From 773fd1a707f5abff63c4fd47b73580faba65d468 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 15:58:05 -0500 Subject: initial commit --- library/compiler-builtins/.gitignore | 3 + library/compiler-builtins/Cargo.toml | 4 + library/compiler-builtins/LICENSE-APACHE | 201 +++++++++++++++++++++++++++++++ library/compiler-builtins/LICENSE-MIT | 25 ++++ library/compiler-builtins/README.md | 23 ++++ library/compiler-builtins/src/arm.rs | 67 +++++++++++ library/compiler-builtins/src/lib.rs | 43 +++++++ library/compiler-builtins/src/test.rs | 25 ++++ library/compiler-builtins/src/x86_64.rs | 9 ++ 9 files changed, 400 insertions(+) create mode 100644 library/compiler-builtins/.gitignore create mode 100644 library/compiler-builtins/Cargo.toml create mode 100644 library/compiler-builtins/LICENSE-APACHE create mode 100644 library/compiler-builtins/LICENSE-MIT create mode 100644 library/compiler-builtins/README.md create mode 100644 library/compiler-builtins/src/arm.rs create mode 100644 library/compiler-builtins/src/lib.rs create mode 100644 library/compiler-builtins/src/test.rs create mode 100644 library/compiler-builtins/src/x86_64.rs diff --git a/library/compiler-builtins/.gitignore b/library/compiler-builtins/.gitignore new file mode 100644 index 00000000000..b203ea61f2a --- /dev/null +++ b/library/compiler-builtins/.gitignore @@ -0,0 +1,3 @@ +*.rs.bk +Cargo.lock +target diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml new file mode 100644 index 00000000000..663d9b109a4 --- /dev/null +++ b/library/compiler-builtins/Cargo.toml @@ -0,0 +1,4 @@ +[package] +authors = ["Jorge Aparicio "] +name = "rustc_builtins" +version = "0.1.0" diff --git a/library/compiler-builtins/LICENSE-APACHE b/library/compiler-builtins/LICENSE-APACHE new file mode 100644 index 00000000000..16fe87b06e8 --- /dev/null +++ b/library/compiler-builtins/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/compiler-builtins/LICENSE-MIT b/library/compiler-builtins/LICENSE-MIT new file mode 100644 index 00000000000..a43445e6cd1 --- /dev/null +++ b/library/compiler-builtins/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Jorge Aparicio + +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/compiler-builtins/README.md b/library/compiler-builtins/README.md new file mode 100644 index 00000000000..f54664faece --- /dev/null +++ b/library/compiler-builtins/README.md @@ -0,0 +1,23 @@ +[![Build Status][status]](https://travis-ci.org/japaric/rustc-builtins) + +[status]: https://travis-ci.org/japaric/rustc-builtins.svg?branch=master + +# `rustc-builtins` + +> [WIP] Porting `compiler-rt` intrinsics to Rust + +## License + +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 the +work 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/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs new file mode 100644 index 00000000000..0be06a4dfbb --- /dev/null +++ b/library/compiler-builtins/src/arm.rs @@ -0,0 +1,67 @@ +use core::intrinsics; + +macro_rules! defer { + ($($symbol:ident),+ -> $routine:ident) => { + $( + #[naked] + #[no_mangle] + pub extern "C" fn $symbol() { + unsafe { + asm!(concat!("b ", stringify!($routine))); + intrinsics::unreachable(); + } + } + )+ + } +} + +// FIXME only `__aeabi_memcmp` should be defined like this. The `*4` and `*8` variants should be +// defined as aliases of `__aeabi_memcmp` +defer!(__aeabi_memcmp, __aeabi_memcmp4, __aeabi_memcmp8 -> memcmp); + +// FIXME same issue as `__aeabi_memcmp*` +defer!(__aeabi_memcpy, __aeabi_memcpy4, __aeabi_memcpy8 -> memcpy); + +// FIXME same issue as `__aeabi_memcmp*` +defer!(__aeabi_memmove, __aeabi_memmove4, __aeabi_memmove8 -> memmove); + +macro_rules! memset { + ($($symbol:ident),+) => { + $( + #[naked] + #[no_mangle] + pub extern "C" fn $symbol() { + unsafe { + asm!("mov r3, r1 + mov r1, r2 + mov r2, r3 + b memset"); + intrinsics::unreachable(); + } + } + )+ + } +} + +// FIXME same issue as `__aeabi_memcmp*` +memset!(__aeabi_memset, __aeabi_memset4, __aeabi_memset8); + +macro_rules! memclr { + ($($symbol:ident),+) => { + $( + #[naked] + #[no_mangle] + pub extern "C" fn $symbol() { + unsafe { + asm!("mov r2, r1 + mov r1, #0 + b memset"); + intrinsics::unreachable(); + } + } + )+ + } +} + +// FIXME same issue as `__aeabi_memcmp*` +memclr!(__aeabi_memclr, __aeabi_memclr4, __aeabi_memclr8); diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs new file mode 100644 index 00000000000..838e62a296b --- /dev/null +++ b/library/compiler-builtins/src/lib.rs @@ -0,0 +1,43 @@ +#![allow(unused_features)] +#![cfg_attr(not(test), no_std)] +#![feature(asm)] +#![feature(core_intrinsics)] +#![feature(naked_functions)] +// TODO(rust-lang/rust#35021) uncomment when that PR lands +// #![feature(rustc_builtins)] + +#[cfg(test)] +extern crate core; + +use core::mem; + +#[cfg(target_arch = "arm")] +pub mod arm; + +#[cfg(target_arch = "x86_64")] +pub mod x86_64; + +#[cfg(test)] +mod test; + +const CHAR_BITS: usize = 8; + +macro_rules! absv_i2 { + ($intrinsic:ident : $ty:ty) => { + #[no_mangle] + pub extern "C" fn $intrinsic(x: $ty) -> $ty { + let n = mem::size_of::<$ty>() * CHAR_BITS; + if x == 1 << (n - 1) { + panic!(); + } + let y = x >> (n - 1); + (x ^ y) - y + } + + } +} + +absv_i2!(__absvsi2: i32); +absv_i2!(__absvdi2: i64); +// TODO(rust-lang/35118)? +// absv_i2!(__absvti2, i128); diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs new file mode 100644 index 00000000000..9abfec7e800 --- /dev/null +++ b/library/compiler-builtins/src/test.rs @@ -0,0 +1,25 @@ +use std::panic; + +macro_rules! absv_i2 { + ($intrinsic:ident: $ty:ident) => { + #[test] + fn $intrinsic() { + assert!(panic::catch_unwind(|| ::$intrinsic(::std::$ty::MIN)).is_err()); + assert_eq!(::$intrinsic(::std::$ty::MIN + 1), ::std::$ty::MAX); + assert_eq!(::$intrinsic(::std::$ty::MIN + 2), ::std::$ty::MAX - 1); + assert_eq!(::$intrinsic(-1), 1); + assert_eq!(::$intrinsic(-2), 2); + assert_eq!(::$intrinsic(0), 0); + assert_eq!(::$intrinsic(1), 1); + assert_eq!(::$intrinsic(2), 2); + assert_eq!(::$intrinsic(2), 2); + assert_eq!(::$intrinsic(::std::$ty::MAX - 1), ::std::$ty::MAX - 1); + assert_eq!(::$intrinsic(::std::$ty::MAX), ::std::$ty::MAX); + } + } +} + +absv_i2!(__absvsi2: i32); +absv_i2!(__absvdi2: i64); +// TODO(rust-lang/35118)? +// absv_i2!(__absvti2: i128); diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs new file mode 100644 index 00000000000..d4ea0f759de --- /dev/null +++ b/library/compiler-builtins/src/x86_64.rs @@ -0,0 +1,9 @@ +#[no_mangle] +pub extern "C" fn __floatdisf(x: i64) -> f32 { + x as f32 +} + +#[no_mangle] +pub extern "C" fn __floatdidf(x: i64) -> f64 { + x as f64 +} -- cgit 1.4.1-3-g733a5 From 51db348a3f640214300026a238131939773bad1c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 16:01:28 -0500 Subject: README: link back to rust-lang/rust issue --- library/compiler-builtins/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index f54664faece..e2fc6a17131 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -6,6 +6,10 @@ > [WIP] Porting `compiler-rt` intrinsics to Rust +See [rust-lang/rust#35437][0]. + +[0]: https://github.com/rust-lang/rust/issues/35437 + ## License Licensed under either of -- cgit 1.4.1-3-g733a5 From 178fa2a806c0e1d12b0df9183505c6c36c14ab58 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 16:55:30 -0500 Subject: travis CI --- library/compiler-builtins/.travis.yml | 61 +++++++++++++++++++++++++++++++++ library/compiler-builtins/ci/env.sh | 23 +++++++++++++ library/compiler-builtins/ci/install.sh | 31 +++++++++++++++++ library/compiler-builtins/ci/script.sh | 48 ++++++++++++++++++++++++++ 4 files changed, 163 insertions(+) create mode 100644 library/compiler-builtins/.travis.yml create mode 100644 library/compiler-builtins/ci/env.sh create mode 100644 library/compiler-builtins/ci/install.sh create mode 100644 library/compiler-builtins/ci/script.sh diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml new file mode 100644 index 00000000000..63faac24cde --- /dev/null +++ b/library/compiler-builtins/.travis.yml @@ -0,0 +1,61 @@ +language: generic + +matrix: + include: + - env: TARGET=aarch64-unknown-linux-gnu + os: linux + dist: trusty + sudo: required + addons: + apt: + packages: + - binfmt-support + - qemu-user-static + - env: TARGET=arm-unknown-linux-gnueabi + os: linux + sudo: required + addons: + apt: + packages: + - binfmt-support + - gcc-arm-linux-gnueabi + - libc6-armel-cross + - qemu-user-static + - env: TARGET=arm-unknown-linux-gnueabihf + os: linux + sudo: required + addons: + apt: + packages: &armhf + - binfmt-support + - gcc-arm-linux-gnueabihf + - libc6-armhf-cross + - qemu-user-static + - env: TARGET=armv7-unknown-linux-gnueabihf + os: linux + sudo: required + addons: + apt: + packages: *armhf + - env: TARGET=i686-apple-darwin + os: osx + - env: TARGET=i686-unknown-linux-gnu + os: linux + addons: + apt: + packages: + - gcc-multilib + - env: TARGET=x86_64-apple-darwin + os: osx + - env: TARGET=x86_64-unknown-linux-gnu + os: linux + +install: + - bash ci/install.sh + +script: + - bash ci/script.sh + +notifications: + email: + on_success: never diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh new file mode 100644 index 00000000000..ad76689789d --- /dev/null +++ b/library/compiler-builtins/ci/env.sh @@ -0,0 +1,23 @@ +case $TRAVIS_OS_NAME in + linux) + export HOST=x86_64-unknown-linux-gnu + ;; + osx) + export HOST=x86_64-apple-darwin + ;; +esac + +case $TARGET in + aarch64-unknown-linux-gnu) + export PREFIX=aarch64-linux-gnu- + export QEMU_LD_PREFIX=/usr/aarch64-linux-gnu + ;; + arm*-unknown-linux-gnueabi) + export PREFIX=arm-linux-gnueabi- + export QEMU_LD_PREFIX=/usr/arm-linux-gnueabi + ;; + arm*-unknown-linux-gnueabihf) + export PREFIX=arm-linux-gnueabihf- + export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf + ;; +esac diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh new file mode 100644 index 00000000000..a66c5d0ee1f --- /dev/null +++ b/library/compiler-builtins/ci/install.sh @@ -0,0 +1,31 @@ +set -ex + +. $(dirname $0)/env.sh + +build() { + cargo build --target $TARGET + cargo build --target $TARGET --release +} + +run_tests() { + if [[ $QEMU_LD_PREFIX ]]; then + export RUST_TEST_THREADS=1 + fi + + cargo test --target $TARGET + cargo test --target $TARGET --release +} + +inspect() { + ${PREFIX}nm -g --defined-only target/**/debug/*.rlib + ${PREFIX}objdump target/**/debug/*.rlib + ${PREFIX}objdump target/**/release/*.rlib +} + +main() { + build + run_tests + inspect +} + +main diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh new file mode 100644 index 00000000000..c2fcdb8078e --- /dev/null +++ b/library/compiler-builtins/ci/script.sh @@ -0,0 +1,48 @@ +set -ex + +. $(dirname $0)/env.sh + +install_c_toolchain() { + case $TARGET in + aarch64-unknown-linux-gnu) + sudo apt-get install -y --no-install-recommends \ + gcc-aarch64-linux-gnu libc6-arm64-cross libc6-dev-arm64-cross + ;; + *) + ;; + esac +} + +install_rust() { + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly + + rustc -V + cargo -V +} + +add_rustup_target() { + if [[ $TARGET != $HOST ]]; then + rustup target add $TARGET + fi +} + +configure_cargo() { + if [[ $PREFIX ]]; then + ${PREFIX}gcc -v + + mkdir -p .cargo + cat >>.cargo/config < Date: Sun, 7 Aug 2016 16:58:44 -0500 Subject: set $PATH --- library/compiler-builtins/.travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 63faac24cde..364e4d940cc 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -50,6 +50,9 @@ matrix: - env: TARGET=x86_64-unknown-linux-gnu os: linux +before_install: + - export PATH="$PATH:$HOME/.cargo/bin" + install: - bash ci/install.sh -- cgit 1.4.1-3-g733a5 From 898869871e8479942d1cc9225a91b415bdc4368a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 16:59:54 -0500 Subject: only test on master --- library/compiler-builtins/.travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 364e4d940cc..27a14135586 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -59,6 +59,10 @@ install: script: - bash ci/script.sh +branches: + only: + - master + notifications: email: on_success: never -- cgit 1.4.1-3-g733a5 From 5dbc8d97298e3e50919382d96146190be3e0fc69 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:03:44 -0500 Subject: swap install.sh and script.sh --- library/compiler-builtins/ci/install.sh | 49 ++++++++++++++++++++++----------- library/compiler-builtins/ci/script.sh | 49 +++++++++++---------------------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index a66c5d0ee1f..c2fcdb8078e 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -2,30 +2,47 @@ set -ex . $(dirname $0)/env.sh -build() { - cargo build --target $TARGET - cargo build --target $TARGET --release +install_c_toolchain() { + case $TARGET in + aarch64-unknown-linux-gnu) + sudo apt-get install -y --no-install-recommends \ + gcc-aarch64-linux-gnu libc6-arm64-cross libc6-dev-arm64-cross + ;; + *) + ;; + esac } -run_tests() { - if [[ $QEMU_LD_PREFIX ]]; then - export RUST_TEST_THREADS=1 - fi +install_rust() { + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly + + rustc -V + cargo -V +} - cargo test --target $TARGET - cargo test --target $TARGET --release +add_rustup_target() { + if [[ $TARGET != $HOST ]]; then + rustup target add $TARGET + fi } -inspect() { - ${PREFIX}nm -g --defined-only target/**/debug/*.rlib - ${PREFIX}objdump target/**/debug/*.rlib - ${PREFIX}objdump target/**/release/*.rlib +configure_cargo() { + if [[ $PREFIX ]]; then + ${PREFIX}gcc -v + + mkdir -p .cargo + cat >>.cargo/config <>.cargo/config < Date: Sun, 7 Aug 2016 17:07:12 -0500 Subject: install libc6-dev for ARM targets --- library/compiler-builtins/.travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 27a14135586..d8ff366262c 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -20,6 +20,7 @@ matrix: - binfmt-support - gcc-arm-linux-gnueabi - libc6-armel-cross + - libc6-dev-armel-cross - qemu-user-static - env: TARGET=arm-unknown-linux-gnueabihf os: linux @@ -30,6 +31,7 @@ matrix: - binfmt-support - gcc-arm-linux-gnueabihf - libc6-armhf-cross + - libc6-dev-armhf-cross - qemu-user-static - env: TARGET=armv7-unknown-linux-gnueabihf os: linux -- cgit 1.4.1-3-g733a5 From 0921a91b267f994ba6a479f76b47de427e272307 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:07:58 -0500 Subject: fix objdump commands --- library/compiler-builtins/ci/script.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index a66c5d0ee1f..5952f7ecbfa 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -18,8 +18,8 @@ run_tests() { inspect() { ${PREFIX}nm -g --defined-only target/**/debug/*.rlib - ${PREFIX}objdump target/**/debug/*.rlib - ${PREFIX}objdump target/**/release/*.rlib + ${PREFIX}objdump -Cd target/**/debug/*.rlib + ${PREFIX}objdump -Cd target/**/release/*.rlib } main() { -- cgit 1.4.1-3-g733a5 From f8099c755e14a9c9d6f65fb8216ef27df7d48d72 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:10:36 -0500 Subject: use container-based infrastructure --- library/compiler-builtins/.travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index d8ff366262c..c09c3bb49bf 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,4 +1,5 @@ language: generic +sudo: false matrix: include: -- cgit 1.4.1-3-g733a5 From 4cbba5979d53b04373061384f87becd16b2a90b6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:13:29 -0500 Subject: ignore objdump exit code --- library/compiler-builtins/ci/script.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 5952f7ecbfa..01f6ff50570 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -18,8 +18,10 @@ run_tests() { inspect() { ${PREFIX}nm -g --defined-only target/**/debug/*.rlib + set +e ${PREFIX}objdump -Cd target/**/debug/*.rlib ${PREFIX}objdump -Cd target/**/release/*.rlib + set -e } main() { -- cgit 1.4.1-3-g733a5 From 48d9ff7e805d9fe0b213145c530af58f6dc4bc60 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:18:37 -0500 Subject: nm: drop --defined-only flag it doesn't work on macOS --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 01f6ff50570..c3e1a65fc29 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -17,7 +17,7 @@ run_tests() { } inspect() { - ${PREFIX}nm -g --defined-only target/**/debug/*.rlib + ${PREFIX}nm -g target/**/debug/*.rlib set +e ${PREFIX}objdump -Cd target/**/debug/*.rlib ${PREFIX}objdump -Cd target/**/release/*.rlib -- cgit 1.4.1-3-g733a5 From a0de8f0bdb898c0559b785c4e4aff2035404cce1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:23:30 -0500 Subject: macOS: install binutils --- library/compiler-builtins/ci/install.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index c2fcdb8078e..595a985cecf 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -13,6 +13,16 @@ install_c_toolchain() { esac } +install_binutils() { + case $TRAVIS_OS_NAME in + osx) + brew install binutils + ;; + *) + ;; + esac +} + install_rust() { curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly -- cgit 1.4.1-3-g733a5 From 3cea133b4c391725f0a7eb33ec8545f99198853f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:29:31 -0500 Subject: macOS: use gnu binutils --- library/compiler-builtins/ci/env.sh | 4 ++++ library/compiler-builtins/ci/script.sh | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index ad76689789d..92f0c3ecabd 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -1,9 +1,13 @@ case $TRAVIS_OS_NAME in linux) export HOST=x86_64-unknown-linux-gnu + export NM=nm + export OBJDUMP=objdump ;; osx) export HOST=x86_64-apple-darwin + export NM=gnm + export OBJDUMP=gobjdump ;; esac diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index c3e1a65fc29..c1748fcd73e 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -17,10 +17,10 @@ run_tests() { } inspect() { - ${PREFIX}nm -g target/**/debug/*.rlib + $PREFIX$NM -g --defined-only target/**/debug/*.rlib set +e - ${PREFIX}objdump -Cd target/**/debug/*.rlib - ${PREFIX}objdump -Cd target/**/release/*.rlib + $PREFIX$OBJDUMP -Cd target/**/debug/*.rlib + $PREFIX$OBJDUMP -Cd target/**/release/*.rlib set -e } -- cgit 1.4.1-3-g733a5 From 3ccdc29e4dc1216bd5cce4055a83c5491ee84045 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:32:53 -0500 Subject: macOS: actually install binutils --- library/compiler-builtins/ci/install.sh | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 595a985cecf..3d11092f8c0 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -2,21 +2,21 @@ set -ex . $(dirname $0)/env.sh -install_c_toolchain() { - case $TARGET in - aarch64-unknown-linux-gnu) - sudo apt-get install -y --no-install-recommends \ - gcc-aarch64-linux-gnu libc6-arm64-cross libc6-dev-arm64-cross +install_binutils() { + case $TRAVIS_OS_NAME in + osx) + brew install binutils ;; *) ;; esac } -install_binutils() { - case $TRAVIS_OS_NAME in - osx) - brew install binutils +install_c_toolchain() { + case $TARGET in + aarch64-unknown-linux-gnu) + sudo apt-get install -y --no-install-recommends \ + gcc-aarch64-linux-gnu libc6-arm64-cross libc6-dev-arm64-cross ;; *) ;; @@ -49,6 +49,7 @@ EOF } main() { + install_binutils install_c_toolchain install_rust add_rustup_target -- cgit 1.4.1-3-g733a5 From c691a4e475a1b5295858e8c0d9cb75516300c153 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 21:05:42 -0500 Subject: README: add Contributing and Progress sections --- library/compiler-builtins/README.md | 306 ++++++++++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index e2fc6a17131..f24f173c2fc 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -10,6 +10,312 @@ See [rust-lang/rust#35437][0]. [0]: https://github.com/rust-lang/rust/issues/35437 +## Contributing + +1. Pick one or more intrinsics from the [pending list][/#progress]. +2. Fork this repository +3. Port the intrinsic(s) and their corresponding [unit tests][1] from their [C implementation][2] to + Rust. +4. Send a Pull Request (PR) +5. Once the PR passes our extensive [testing infrastructure][3], we'll merge it! +6. Celebrate :tada: + +[1]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/test/builtins/Unit +[2]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/lib/builtins +[3]: https://travis-ci.org/japaric/rustc-builtins + +## Progress + +The intrinsics that involve quadruple precision floating point numbers ("`f128`") has been crossed +off because Rust doesn't support them. + +- [ ] absvdi2.c +- [ ] absvsi2.c +- [ ] absvti2.c +- [ ] adddf3.c +- [ ] addsf3.c +- [ ] addtf3.c +- [ ] addvdi3.c +- [ ] addvsi3.c +- [ ] addvti3.c +- [ ] apple_versioning.c +- [ ] arm/adddf3vfp.S +- [ ] arm/addsf3vfp.S +- [ ] arm/aeabi_cdcmp.S +- [ ] arm/aeabi_cdcmpeq_check_nan.c +- [ ] arm/aeabi_cfcmp.S +- [ ] arm/aeabi_cfcmpeq_check_nan.c +- [ ] arm/aeabi_dcmp.S +- [ ] arm/aeabi_div0.c +- [ ] arm/aeabi_drsub.c +- [ ] arm/aeabi_fcmp.S +- [ ] arm/aeabi_frsub.c +- [ ] arm/aeabi_idivmod.S +- [ ] arm/aeabi_ldivmod.S +- [ ] arm/aeabi_uidivmod.S +- [ ] arm/aeabi_uldivmod.S +- [ ] arm/bswapdi2.S +- [ ] arm/bswapsi2.S +- [ ] arm/clzdi2.S +- [ ] arm/clzsi2.S +- [ ] arm/comparesf2.S +- [ ] arm/divdf3vfp.S +- [ ] arm/divmodsi4.S +- [ ] arm/divsf3vfp.S +- [ ] arm/divsi3.S +- [ ] arm/eqdf2vfp.S +- [ ] arm/eqsf2vfp.S +- [ ] arm/extendsfdf2vfp.S +- [ ] arm/fixdfsivfp.S +- [ ] arm/fixsfsivfp.S +- [ ] arm/fixunsdfsivfp.S +- [ ] arm/fixunssfsivfp.S +- [ ] arm/floatsidfvfp.S +- [ ] arm/floatsisfvfp.S +- [ ] arm/floatunssidfvfp.S +- [ ] arm/floatunssisfvfp.S +- [ ] arm/gedf2vfp.S +- [ ] arm/gesf2vfp.S +- [ ] arm/gtdf2vfp.S +- [ ] arm/gtsf2vfp.S +- [ ] arm/ledf2vfp.S +- [ ] arm/lesf2vfp.S +- [ ] arm/ltdf2vfp.S +- [ ] arm/ltsf2vfp.S +- [ ] arm/modsi3.S +- [ ] arm/muldf3vfp.S +- [ ] arm/mulsf3vfp.S +- [ ] arm/nedf2vfp.S +- [ ] arm/negdf2vfp.S +- [ ] arm/negsf2vfp.S +- [ ] arm/nesf2vfp.S +- [ ] arm/restore_vfp_d8_d15_regs.S +- [ ] arm/save_vfp_d8_d15_regs.S +- [ ] arm/softfloat-alias.list +- [ ] arm/subdf3vfp.S +- [ ] arm/subsf3vfp.S +- [ ] arm/switch16.S +- [ ] arm/switch32.S +- [ ] arm/switch8.S +- [ ] arm/switchu8.S +- [ ] arm/sync_fetch_and_add_4.S +- [ ] arm/sync_fetch_and_add_8.S +- [ ] arm/sync_fetch_and_and_4.S +- [ ] arm/sync_fetch_and_and_8.S +- [ ] arm/sync_fetch_and_max_4.S +- [ ] arm/sync_fetch_and_max_8.S +- [ ] arm/sync_fetch_and_min_4.S +- [ ] arm/sync_fetch_and_min_8.S +- [ ] arm/sync_fetch_and_nand_4.S +- [ ] arm/sync_fetch_and_nand_8.S +- [ ] arm/sync_fetch_and_or_4.S +- [ ] arm/sync_fetch_and_or_8.S +- [ ] arm/sync_fetch_and_sub_4.S +- [ ] arm/sync_fetch_and_sub_8.S +- [ ] arm/sync_fetch_and_umax_4.S +- [ ] arm/sync_fetch_and_umax_8.S +- [ ] arm/sync_fetch_and_umin_4.S +- [ ] arm/sync_fetch_and_umin_8.S +- [ ] arm/sync_fetch_and_xor_4.S +- [ ] arm/sync_fetch_and_xor_8.S +- [ ] arm/sync_synchronize.S +- [ ] arm/truncdfsf2vfp.S +- [ ] arm/udivmodsi4.S +- [ ] arm/udivsi3.S +- [ ] arm/umodsi3.S +- [ ] arm/unorddf2vfp.S +- [ ] arm/unordsf2vfp.S +- [ ] ashldi3.c +- [ ] ashlti3.c +- [ ] ashrdi3.c +- [ ] ashrti3.c +- [ ] atomic.c +- [ ] atomic_flag_clear.c +- [ ] atomic_flag_clear_explicit.c +- [ ] atomic_flag_test_and_set.c +- [ ] atomic_flag_test_and_set_explicit.c +- [ ] atomic_signal_fence.c +- [ ] atomic_thread_fence.c +- [ ] clear_cache.c +- [ ] clzdi2.c +- [ ] clzsi2.c +- [ ] clzti2.c +- [ ] cmpdi2.c +- [ ] cmpti2.c +- [ ] comparedf2.c +- [ ] comparesf2.c +- [ ] comparetf2.c +- [ ] cpu_model.c +- [ ] ctzdi2.c +- [ ] ctzsi2.c +- [ ] ctzti2.c +- [ ] divdc3.c +- [ ] divdf3.c +- [ ] divdi3.c +- [ ] divmoddi4.c +- [ ] divmodsi4.c +- [ ] divsc3.c +- [ ] divsf3.c +- [ ] divsi3.c +- [ ] divtc3.c +- [ ] divtf3.c +- [ ] divti3.c +- [ ] divxc3.c +- [ ] emutls.c +- [ ] enable_execute_stack.c +- [ ] eprintf.c +- [ ] extenddftf2.c +- [ ] extendhfsf2.c +- [ ] extendsfdf2.c +- [ ] extendsftf2.c +- [ ] ffsdi2.c +- [ ] ffsti2.c +- [ ] fixdfdi.c +- [ ] fixdfsi.c +- [ ] fixdfti.c +- [ ] fixsfdi.c +- [ ] fixsfsi.c +- [ ] fixsfti.c +- [ ] fixtfdi.c +- [ ] fixtfsi.c +- [ ] fixtfti.c +- [ ] fixunsdfdi.c +- [ ] fixunsdfsi.c +- [ ] fixunsdfti.c +- [ ] fixunssfdi.c +- [ ] fixunssfsi.c +- [ ] fixunssfti.c +- [ ] fixunstfdi.c +- [ ] fixunstfsi.c +- [ ] fixunstfti.c +- [ ] floatdidf.c +- [ ] floatdisf.c +- [ ] floatditf.c +- [ ] floatsidf.c +- [ ] floatsisf.c +- [ ] floatsitf.c +- [ ] floattidf.c +- [ ] floattisf.c +- [ ] floatundidf.c +- [ ] floatundisf.c +- [ ] floatunditf.c +- [ ] floatunsidf.c +- [ ] floatunsisf.c +- [ ] floatunsitf.c +- [ ] floatuntidf.c +- [ ] floatuntisf.c +- [ ] gcc_personality_v0.c +- [ ] i386/ashldi3.S +- [ ] i386/ashrdi3.S +- [ ] i386/chkstk.S +- [ ] i386/chkstk2.S +- [ ] i386/divdi3.S +- [ ] i386/floatdidf.S +- [ ] i386/floatdisf.S +- [ ] i386/floatundidf.S +- [ ] i386/floatundisf.S +- [ ] i386/lshrdi3.S +- [ ] i386/moddi3.S +- [ ] i386/muldi3.S +- [ ] i386/udivdi3.S +- [ ] i386/umoddi3.S +- [ ] int_util.c +- [ ] lshrdi3.c +- [ ] lshrti3.c +- [ ] moddi3.c +- [ ] modsi3.c +- [ ] modti3.c +- [ ] muldc3.c +- [ ] muldf3.c +- [ ] muldi3.c +- [ ] mulodi4.c +- [ ] mulosi4.c +- [ ] muloti4.c +- [ ] mulsc3.c +- [ ] mulsf3.c +- [ ] multc3.c +- [ ] multf3.c +- [ ] multi3.c +- [ ] mulvdi3.c +- [ ] mulvsi3.c +- [ ] mulvti3.c +- [ ] mulxc3.c +- [ ] negdf2.c +- [ ] negdi2.c +- [ ] negsf2.c +- [ ] negti2.c +- [ ] negvdi2.c +- [ ] negvsi2.c +- [ ] negvti2.c +- [ ] paritydi2.c +- [ ] paritysi2.c +- [ ] parityti2.c +- [ ] popcountdi2.c +- [ ] popcountsi2.c +- [ ] popcountti2.c +- [ ] powidf2.c +- [ ] powisf2.c +- [ ] powitf2.c +- [ ] ppc/divtc3.c +- [ ] ppc/fixtfdi.c +- [ ] ppc/fixunstfdi.c +- [ ] ppc/floatditf.c +- [ ] ppc/floatunditf.c +- [ ] ppc/gcc_qadd.c +- [ ] ppc/gcc_qdiv.c +- [ ] ppc/gcc_qmul.c +- [ ] ppc/gcc_qsub.c +- [ ] ppc/multc3.c +- [ ] ppc/restFP.S +- [ ] ppc/saveFP.S +- [ ] subdf3.c +- [ ] subsf3.c +- [ ] subtf3.c +- [ ] subvdi3.c +- [ ] subvsi3.c +- [ ] subvti3.c +- [ ] trampoline_setup.c +- [ ] truncdfhf2.c +- [ ] truncdfsf2.c +- [ ] truncsfhf2.c +- [ ] trunctfdf2.c +- [ ] trunctfsf2.c +- [ ] ucmpdi2.c +- [ ] ucmpti2.c +- [ ] udivdi3.c +- [ ] udivmoddi4.c +- [ ] udivmodsi4.c +- [ ] udivmodti4.c +- [ ] udivsi3.c +- [ ] udivti3.c +- [ ] umoddi3.c +- [ ] umodsi3.c +- [ ] umodti3.c +- [ ] x86_64/chkstk.S +- [ ] x86_64/chkstk2.S +- [ ] x86_64/floatundidf.S +- [ ] x86_64/floatundisf.S +- [x] arm/aeabi_memcmp.S +- [x] arm/aeabi_memcpy.S +- [x] arm/aeabi_memmove.S +- [x] arm/aeabi_memset.S +- [x] x86_64/floatdidf.c +- [x] x86_64/floatdisf.c +- ~~fixunsxfdi.c~~ +- ~~fixunsxfsi.c~~ +- ~~fixunsxfti.c~~ +- ~~fixxfdi.c~~ +- ~~fixxfti.c~~ +- ~~floatdixf.c~~ +- ~~floattixf.c~~ +- ~~floatundixf.c~~ +- ~~floatuntixf.c~~ +- ~~i386/floatdixf.S~~ +- ~~i386/floatundixf.S~~ +- ~~powixf2.c~~ +- ~~x86_64/floatdixf.c~~ +- ~~x86_64/floatundixf.S~~ + ## License Licensed under either of -- cgit 1.4.1-3-g733a5 From f271e63915ac5a3e5d45b7349ae441e33751099e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 21:22:15 -0500 Subject: CI: allow failures for TARGET=armv7-unknown-linux-gnueabihf --- library/compiler-builtins/.travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index c09c3bb49bf..7ede66cce92 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -52,6 +52,10 @@ matrix: os: osx - env: TARGET=x86_64-unknown-linux-gnu os: linux + allow_failures: + # FIXME(#2) + - env: TARGET=armv7-unknown-linux-gnueabihf + os: linux before_install: - export PATH="$PATH:$HOME/.cargo/bin" -- cgit 1.4.1-3-g733a5 From 1b0cfdc47703f01cc565e1258d662c65f0fb0041 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 8 Aug 2016 06:54:00 +0100 Subject: Clean up function list in README --- library/compiler-builtins/README.md | 154 +++++++++++++++++++----------------- 1 file changed, 80 insertions(+), 74 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index f24f173c2fc..de26d893118 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -26,19 +26,14 @@ See [rust-lang/rust#35437][0]. ## Progress -The intrinsics that involve quadruple precision floating point numbers ("`f128`") has been crossed -off because Rust doesn't support them. - - [ ] absvdi2.c - [ ] absvsi2.c - [ ] absvti2.c - [ ] adddf3.c - [ ] addsf3.c -- [ ] addtf3.c - [ ] addvdi3.c - [ ] addvsi3.c - [ ] addvti3.c -- [ ] apple_versioning.c - [ ] arm/adddf3vfp.S - [ ] arm/addsf3vfp.S - [ ] arm/aeabi_cdcmp.S @@ -98,27 +93,6 @@ off because Rust doesn't support them. - [ ] arm/switch32.S - [ ] arm/switch8.S - [ ] arm/switchu8.S -- [ ] arm/sync_fetch_and_add_4.S -- [ ] arm/sync_fetch_and_add_8.S -- [ ] arm/sync_fetch_and_and_4.S -- [ ] arm/sync_fetch_and_and_8.S -- [ ] arm/sync_fetch_and_max_4.S -- [ ] arm/sync_fetch_and_max_8.S -- [ ] arm/sync_fetch_and_min_4.S -- [ ] arm/sync_fetch_and_min_8.S -- [ ] arm/sync_fetch_and_nand_4.S -- [ ] arm/sync_fetch_and_nand_8.S -- [ ] arm/sync_fetch_and_or_4.S -- [ ] arm/sync_fetch_and_or_8.S -- [ ] arm/sync_fetch_and_sub_4.S -- [ ] arm/sync_fetch_and_sub_8.S -- [ ] arm/sync_fetch_and_umax_4.S -- [ ] arm/sync_fetch_and_umax_8.S -- [ ] arm/sync_fetch_and_umin_4.S -- [ ] arm/sync_fetch_and_umin_8.S -- [ ] arm/sync_fetch_and_xor_4.S -- [ ] arm/sync_fetch_and_xor_8.S -- [ ] arm/sync_synchronize.S - [ ] arm/truncdfsf2vfp.S - [ ] arm/udivmodsi4.S - [ ] arm/udivsi3.S @@ -129,14 +103,6 @@ off because Rust doesn't support them. - [ ] ashlti3.c - [ ] ashrdi3.c - [ ] ashrti3.c -- [ ] atomic.c -- [ ] atomic_flag_clear.c -- [ ] atomic_flag_clear_explicit.c -- [ ] atomic_flag_test_and_set.c -- [ ] atomic_flag_test_and_set_explicit.c -- [ ] atomic_signal_fence.c -- [ ] atomic_thread_fence.c -- [ ] clear_cache.c - [ ] clzdi2.c - [ ] clzsi2.c - [ ] clzti2.c @@ -144,30 +110,18 @@ off because Rust doesn't support them. - [ ] cmpti2.c - [ ] comparedf2.c - [ ] comparesf2.c -- [ ] comparetf2.c -- [ ] cpu_model.c - [ ] ctzdi2.c - [ ] ctzsi2.c - [ ] ctzti2.c -- [ ] divdc3.c - [ ] divdf3.c - [ ] divdi3.c - [ ] divmoddi4.c - [ ] divmodsi4.c -- [ ] divsc3.c - [ ] divsf3.c - [ ] divsi3.c -- [ ] divtc3.c -- [ ] divtf3.c - [ ] divti3.c -- [ ] divxc3.c -- [ ] emutls.c -- [ ] enable_execute_stack.c -- [ ] eprintf.c -- [ ] extenddftf2.c - [ ] extendhfsf2.c - [ ] extendsfdf2.c -- [ ] extendsftf2.c - [ ] ffsdi2.c - [ ] ffsti2.c - [ ] fixdfdi.c @@ -176,35 +130,24 @@ off because Rust doesn't support them. - [ ] fixsfdi.c - [ ] fixsfsi.c - [ ] fixsfti.c -- [ ] fixtfdi.c -- [ ] fixtfsi.c -- [ ] fixtfti.c - [ ] fixunsdfdi.c - [ ] fixunsdfsi.c - [ ] fixunsdfti.c - [ ] fixunssfdi.c - [ ] fixunssfsi.c - [ ] fixunssfti.c -- [ ] fixunstfdi.c -- [ ] fixunstfsi.c -- [ ] fixunstfti.c - [ ] floatdidf.c - [ ] floatdisf.c -- [ ] floatditf.c - [ ] floatsidf.c - [ ] floatsisf.c -- [ ] floatsitf.c - [ ] floattidf.c - [ ] floattisf.c - [ ] floatundidf.c - [ ] floatundisf.c -- [ ] floatunditf.c - [ ] floatunsidf.c - [ ] floatunsisf.c -- [ ] floatunsitf.c - [ ] floatuntidf.c - [ ] floatuntisf.c -- [ ] gcc_personality_v0.c - [ ] i386/ashldi3.S - [ ] i386/ashrdi3.S - [ ] i386/chkstk.S @@ -219,27 +162,21 @@ off because Rust doesn't support them. - [ ] i386/muldi3.S - [ ] i386/udivdi3.S - [ ] i386/umoddi3.S -- [ ] int_util.c - [ ] lshrdi3.c - [ ] lshrti3.c - [ ] moddi3.c - [ ] modsi3.c - [ ] modti3.c -- [ ] muldc3.c - [ ] muldf3.c - [ ] muldi3.c - [ ] mulodi4.c - [ ] mulosi4.c - [ ] muloti4.c -- [ ] mulsc3.c - [ ] mulsf3.c -- [ ] multc3.c -- [ ] multf3.c - [ ] multi3.c - [ ] mulvdi3.c - [ ] mulvsi3.c - [ ] mulvti3.c -- [ ] mulxc3.c - [ ] negdf2.c - [ ] negdi2.c - [ ] negsf2.c @@ -255,31 +192,20 @@ off because Rust doesn't support them. - [ ] popcountti2.c - [ ] powidf2.c - [ ] powisf2.c -- [ ] powitf2.c -- [ ] ppc/divtc3.c -- [ ] ppc/fixtfdi.c -- [ ] ppc/fixunstfdi.c -- [ ] ppc/floatditf.c -- [ ] ppc/floatunditf.c - [ ] ppc/gcc_qadd.c - [ ] ppc/gcc_qdiv.c - [ ] ppc/gcc_qmul.c - [ ] ppc/gcc_qsub.c -- [ ] ppc/multc3.c - [ ] ppc/restFP.S - [ ] ppc/saveFP.S - [ ] subdf3.c - [ ] subsf3.c -- [ ] subtf3.c - [ ] subvdi3.c - [ ] subvsi3.c - [ ] subvti3.c -- [ ] trampoline_setup.c - [ ] truncdfhf2.c - [ ] truncdfsf2.c - [ ] truncsfhf2.c -- [ ] trunctfdf2.c -- [ ] trunctfsf2.c - [ ] ucmpdi2.c - [ ] ucmpti2.c - [ ] udivdi3.c @@ -301,21 +227,101 @@ off because Rust doesn't support them. - [x] arm/aeabi_memset.S - [x] x86_64/floatdidf.c - [x] x86_64/floatdisf.c + +## Unimplemented functions + +These builtins involve floating-point types ("`f128`", "`f80`" and complex numbers) that are not supported by Rust. + +- ~~addtf3.c~~ +- ~~comparetf2.c~~ +- ~~divdc3.c~~ +- ~~divsc3.c~~ +- ~~divtc3.c~~ +- ~~divtf3.c~~ +- ~~divxc3.c~~ +- ~~extenddftf2.c~~ +- ~~extendsftf2.c~~ +- ~~fixtfdi.c~~ +- ~~fixtfsi.c~~ +- ~~fixtfti.c~~ +- ~~fixunstfdi.c~~ +- ~~fixunstfsi.c~~ +- ~~fixunstfti.c~~ - ~~fixunsxfdi.c~~ - ~~fixunsxfsi.c~~ - ~~fixunsxfti.c~~ - ~~fixxfdi.c~~ - ~~fixxfti.c~~ +- ~~floatditf.c~~ - ~~floatdixf.c~~ +- ~~floatsitf.c~~ - ~~floattixf.c~~ +- ~~floatunditf.c~~ - ~~floatundixf.c~~ +- ~~floatunsitf.c~~ - ~~floatuntixf.c~~ - ~~i386/floatdixf.S~~ - ~~i386/floatundixf.S~~ +- ~~muldc3.c~~ +- ~~mulsc3.c~~ +- ~~multc3.c~~ +- ~~multf3.c~~ +- ~~mulxc3.c~~ +- ~~powitf2.c~~ - ~~powixf2.c~~ +- ~~ppc/divtc3.c~~ +- ~~ppc/fixtfdi.c~~ +- ~~ppc/fixunstfdi.c~~ +- ~~ppc/floatditf.c~~ +- ~~ppc/floatunditf.c~~ +- ~~ppc/multc3.c~~ +- ~~subtf3.c~~ +- ~~trunctfdf2.c~~ +- ~~trunctfsf2.c~~ - ~~x86_64/floatdixf.c~~ - ~~x86_64/floatundixf.S~~ +Rust only exposes atomic types on platforms that support them, and therefore does not need to fall back to software implementations. + +- ~~arm/sync_fetch_and_add_4.S~~ +- ~~arm/sync_fetch_and_add_8.S~~ +- ~~arm/sync_fetch_and_and_4.S~~ +- ~~arm/sync_fetch_and_and_8.S~~ +- ~~arm/sync_fetch_and_max_4.S~~ +- ~~arm/sync_fetch_and_max_8.S~~ +- ~~arm/sync_fetch_and_min_4.S~~ +- ~~arm/sync_fetch_and_min_8.S~~ +- ~~arm/sync_fetch_and_nand_4.S~~ +- ~~arm/sync_fetch_and_nand_8.S~~ +- ~~arm/sync_fetch_and_or_4.S~~ +- ~~arm/sync_fetch_and_or_8.S~~ +- ~~arm/sync_fetch_and_sub_4.S~~ +- ~~arm/sync_fetch_and_sub_8.S~~ +- ~~arm/sync_fetch_and_umax_4.S~~ +- ~~arm/sync_fetch_and_umax_8.S~~ +- ~~arm/sync_fetch_and_umin_4.S~~ +- ~~arm/sync_fetch_and_umin_8.S~~ +- ~~arm/sync_fetch_and_xor_4.S~~ +- ~~arm/sync_fetch_and_xor_8.S~~ +- ~~arm/sync_synchronize.S~~ +- ~~atomic.c~~ +- ~~atomic_flag_clear.c~~ +- ~~atomic_flag_clear_explicit.c~~ +- ~~atomic_flag_test_and_set.c~~ +- ~~atomic_flag_test_and_set_explicit.c~~ +- ~~atomic_signal_fence.c~~ +- ~~atomic_thread_fence.c~~ + +Miscellaneous functionality that is not used by Rust. + +- ~~apple_versioning.c~~ +- ~~clear_cache.c~~ +- ~~emutls.c~~ +- ~~enable_execute_stack.c~~ +- ~~eprintf.c~~ +- ~~gcc_personality_v0.c~~ +- ~~trampoline_setup.c~~ + ## License Licensed under either of -- cgit 1.4.1-3-g733a5 From 9fbd25b4cd7e8b688efd9e7a12403124146e8fee Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 8 Aug 2016 07:20:39 +0100 Subject: Rewrite the arm mem* builtins without asm and naked functions --- library/compiler-builtins/src/arm.rs | 123 ++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 58 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 0be06a4dfbb..d2544f588d4 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,67 +1,74 @@ -use core::intrinsics; - -macro_rules! defer { - ($($symbol:ident),+ -> $routine:ident) => { - $( - #[naked] - #[no_mangle] - pub extern "C" fn $symbol() { - unsafe { - asm!(concat!("b ", stringify!($routine))); - intrinsics::unreachable(); - } - } - )+ - } +extern "C" { + fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; + fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; + fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; + fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8; } -// FIXME only `__aeabi_memcmp` should be defined like this. The `*4` and `*8` variants should be -// defined as aliases of `__aeabi_memcmp` -defer!(__aeabi_memcmp, __aeabi_memcmp4, __aeabi_memcmp8 -> memcmp); - -// FIXME same issue as `__aeabi_memcmp*` -defer!(__aeabi_memcpy, __aeabi_memcpy4, __aeabi_memcpy8 -> memcpy); +// FIXME: The `*4` and `*8` variants should be defined as aliases. -// FIXME same issue as `__aeabi_memcmp*` -defer!(__aeabi_memmove, __aeabi_memmove4, __aeabi_memmove8 -> memmove); +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + memcmp(s1, s2, n) +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memcmp4(s1: *const u8, s2: *const u8, n: usize) -> i32 { + memcmp(s1, s2, n) +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memcmp8(s1: *const u8, s2: *const u8, n: usize) -> i32 { + memcmp(s1, s2, n) +} -macro_rules! memset { - ($($symbol:ident),+) => { - $( - #[naked] - #[no_mangle] - pub extern "C" fn $symbol() { - unsafe { - asm!("mov r3, r1 - mov r1, r2 - mov r2, r3 - b memset"); - intrinsics::unreachable(); - } - } - )+ - } +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { + memcpy(dest, src, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { + memcpy(dest, src, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { + memcpy(dest, src, n); } -// FIXME same issue as `__aeabi_memcmp*` -memset!(__aeabi_memset, __aeabi_memset4, __aeabi_memset8); +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { + memmove(dest, src, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { + memmove(dest, src, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { + memmove(dest, src, n); +} -macro_rules! memclr { - ($($symbol:ident),+) => { - $( - #[naked] - #[no_mangle] - pub extern "C" fn $symbol() { - unsafe { - asm!("mov r2, r1 - mov r1, #0 - b memset"); - intrinsics::unreachable(); - } - } - )+ - } +// Note the different argument order +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { + memset(dest, c, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { + memset(dest, c, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { + memset(dest, c, n); } -// FIXME same issue as `__aeabi_memcmp*` -memclr!(__aeabi_memclr, __aeabi_memclr4, __aeabi_memclr8); +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { + memset(dest, 0, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { + memset(dest, 0, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { + memset(dest, 0, n); +} -- cgit 1.4.1-3-g733a5 From 1260f145b3e656cc04c2950bd97eb9ac7145d8e1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 01:58:16 -0500 Subject: CI: AppVeyor --- library/compiler-builtins/appveyor.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 library/compiler-builtins/appveyor.yml diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml new file mode 100644 index 00000000000..e7a6a5e4013 --- /dev/null +++ b/library/compiler-builtins/appveyor.yml @@ -0,0 +1,24 @@ +environment: + global: + matrix: + - TARGET=i686-pc-windows-msvc + - TARGET=x86_64-pc-windows-msvc + +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - rustc -Vv + - cargo -V + +build: false + +test_script: + - cargo build + - cargo build --release + - cargo test + - cargo test --release + +branches: + only: + - master -- cgit 1.4.1-3-g733a5 From 74ca884c6da1fef2db211a0e6c16322bb5d54d67 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 01:59:37 -0500 Subject: fix the syntax --- library/compiler-builtins/appveyor.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index e7a6a5e4013..f051e3b567e 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -1,8 +1,7 @@ environment: - global: - matrix: - - TARGET=i686-pc-windows-msvc - - TARGET=x86_64-pc-windows-msvc + matrix: + - TARGET: i686-pc-windows-msvc + - TARGET: x86_64-pc-windows-msvc install: - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" -- cgit 1.4.1-3-g733a5 From e414f9a954419a5194975a0b1a174c2484b19491 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 02:05:24 -0500 Subject: properly call the rust installer to not require user input --- library/compiler-builtins/appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index f051e3b567e..d27883dc901 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -5,7 +5,7 @@ environment: install: - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" - - rust-nightly-%TARGET%.exe + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin - rustc -Vv - cargo -V -- cgit 1.4.1-3-g733a5 From 6f22c85b25b31485328334ca147d82010d038ef6 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 8 Aug 2016 08:16:54 +0100 Subject: Remove builtins that are not called by LLVM --- library/compiler-builtins/README.md | 141 ++++++++++++++++++----------------- library/compiler-builtins/src/arm.rs | 14 ---- 2 files changed, 72 insertions(+), 83 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index de26d893118..a08f4d26208 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -26,34 +26,16 @@ See [rust-lang/rust#35437][0]. ## Progress -- [ ] absvdi2.c -- [ ] absvsi2.c -- [ ] absvti2.c - [ ] adddf3.c - [ ] addsf3.c -- [ ] addvdi3.c -- [ ] addvsi3.c -- [ ] addvti3.c - [ ] arm/adddf3vfp.S - [ ] arm/addsf3vfp.S -- [ ] arm/aeabi_cdcmp.S -- [ ] arm/aeabi_cdcmpeq_check_nan.c -- [ ] arm/aeabi_cfcmp.S -- [ ] arm/aeabi_cfcmpeq_check_nan.c - [ ] arm/aeabi_dcmp.S -- [ ] arm/aeabi_div0.c -- [ ] arm/aeabi_drsub.c - [ ] arm/aeabi_fcmp.S -- [ ] arm/aeabi_frsub.c - [ ] arm/aeabi_idivmod.S - [ ] arm/aeabi_ldivmod.S - [ ] arm/aeabi_uidivmod.S - [ ] arm/aeabi_uldivmod.S -- [ ] arm/bswapdi2.S -- [ ] arm/bswapsi2.S -- [ ] arm/clzdi2.S -- [ ] arm/clzsi2.S -- [ ] arm/comparesf2.S - [ ] arm/divdf3vfp.S - [ ] arm/divmodsi4.S - [ ] arm/divsf3vfp.S @@ -84,15 +66,9 @@ See [rust-lang/rust#35437][0]. - [ ] arm/negdf2vfp.S - [ ] arm/negsf2vfp.S - [ ] arm/nesf2vfp.S -- [ ] arm/restore_vfp_d8_d15_regs.S -- [ ] arm/save_vfp_d8_d15_regs.S - [ ] arm/softfloat-alias.list - [ ] arm/subdf3vfp.S - [ ] arm/subsf3vfp.S -- [ ] arm/switch16.S -- [ ] arm/switch32.S -- [ ] arm/switch8.S -- [ ] arm/switchu8.S - [ ] arm/truncdfsf2vfp.S - [ ] arm/udivmodsi4.S - [ ] arm/udivsi3.S @@ -103,27 +79,13 @@ See [rust-lang/rust#35437][0]. - [ ] ashlti3.c - [ ] ashrdi3.c - [ ] ashrti3.c -- [ ] clzdi2.c -- [ ] clzsi2.c -- [ ] clzti2.c -- [ ] cmpdi2.c -- [ ] cmpti2.c -- [ ] comparedf2.c -- [ ] comparesf2.c -- [ ] ctzdi2.c -- [ ] ctzsi2.c -- [ ] ctzti2.c - [ ] divdf3.c - [ ] divdi3.c -- [ ] divmoddi4.c -- [ ] divmodsi4.c - [ ] divsf3.c - [ ] divsi3.c - [ ] divti3.c - [ ] extendhfsf2.c - [ ] extendsfdf2.c -- [ ] ffsdi2.c -- [ ] ffsti2.c - [ ] fixdfdi.c - [ ] fixdfsi.c - [ ] fixdfti.c @@ -174,44 +136,14 @@ See [rust-lang/rust#35437][0]. - [ ] muloti4.c - [ ] mulsf3.c - [ ] multi3.c -- [ ] mulvdi3.c -- [ ] mulvsi3.c -- [ ] mulvti3.c -- [ ] negdf2.c -- [ ] negdi2.c -- [ ] negsf2.c -- [ ] negti2.c -- [ ] negvdi2.c -- [ ] negvsi2.c -- [ ] negvti2.c -- [ ] paritydi2.c -- [ ] paritysi2.c -- [ ] parityti2.c -- [ ] popcountdi2.c -- [ ] popcountsi2.c -- [ ] popcountti2.c - [ ] powidf2.c - [ ] powisf2.c -- [ ] ppc/gcc_qadd.c -- [ ] ppc/gcc_qdiv.c -- [ ] ppc/gcc_qmul.c -- [ ] ppc/gcc_qsub.c -- [ ] ppc/restFP.S -- [ ] ppc/saveFP.S - [ ] subdf3.c - [ ] subsf3.c -- [ ] subvdi3.c -- [ ] subvsi3.c -- [ ] subvti3.c - [ ] truncdfhf2.c - [ ] truncdfsf2.c - [ ] truncsfhf2.c -- [ ] ucmpdi2.c -- [ ] ucmpti2.c - [ ] udivdi3.c -- [ ] udivmoddi4.c -- [ ] udivmodsi4.c -- [ ] udivmodti4.c - [ ] udivsi3.c - [ ] udivti3.c - [ ] umoddi3.c @@ -221,7 +153,6 @@ See [rust-lang/rust#35437][0]. - [ ] x86_64/chkstk2.S - [ ] x86_64/floatundidf.S - [ ] x86_64/floatundisf.S -- [x] arm/aeabi_memcmp.S - [x] arm/aeabi_memcpy.S - [x] arm/aeabi_memmove.S - [x] arm/aeabi_memset.S @@ -274,6 +205,10 @@ These builtins involve floating-point types ("`f128`", "`f80`" and complex numbe - ~~ppc/fixunstfdi.c~~ - ~~ppc/floatditf.c~~ - ~~ppc/floatunditf.c~~ +- ~~ppc/gcc_qadd.c~~ +- ~~ppc/gcc_qdiv.c~~ +- ~~ppc/gcc_qmul.c~~ +- ~~ppc/gcc_qsub.c~~ - ~~ppc/multc3.c~~ - ~~subtf3.c~~ - ~~trunctfdf2.c~~ @@ -281,6 +216,74 @@ These builtins involve floating-point types ("`f128`", "`f80`" and complex numbe - ~~x86_64/floatdixf.c~~ - ~~x86_64/floatundixf.S~~ +These builtins are never called by LLVM. + +- ~~absvdi2.c~~ +- ~~absvsi2.c~~ +- ~~absvti2.c~~ +- ~~addvdi3.c~~ +- ~~addvsi3.c~~ +- ~~addvti3.c~~ +- ~~arm/aeabi_cdcmp.S~~ +- ~~arm/aeabi_cdcmpeq_check_nan.c~~ +- ~~arm/aeabi_cfcmp.S~~ +- ~~arm/aeabi_cfcmpeq_check_nan.c~~ +- ~~arm/aeabi_div0.c~~ +- ~~arm/aeabi_drsub.c~~ +- ~~arm/aeabi_frsub.c~~ +- ~~arm/aeabi_memcmp.S~~ +- ~~arm/bswapdi2.S~~ +- ~~arm/bswapsi2.S~~ +- ~~arm/clzdi2.S~~ +- ~~arm/clzsi2.S~~ +- ~~arm/comparesf2.S~~ +- ~~arm/restore_vfp_d8_d15_regs.S~~ +- ~~arm/save_vfp_d8_d15_regs.S~~ +- ~~arm/switch16.S~~ +- ~~arm/switch32.S~~ +- ~~arm/switch8.S~~ +- ~~arm/switchu8.S~~ +- ~~clzdi2.c~~ +- ~~clzsi2.c~~ +- ~~clzti2.c~~ +- ~~cmpdi2.c~~ +- ~~cmpti2.c~~ +- ~~comparedf2.c~~ +- ~~comparesf2.c~~ +- ~~ctzdi2.c~~ +- ~~ctzsi2.c~~ +- ~~ctzti2.c~~ +- ~~divmoddi4.c~~ +- ~~divmodsi4.c~~ +- ~~ffsdi2.c~~ +- ~~ffsti2.c~~ +- ~~mulvdi3.c~~ +- ~~mulvsi3.c~~ +- ~~mulvti3.c~~ +- ~~negdf2.c~~ +- ~~negdi2.c~~ +- ~~negsf2.c~~ +- ~~negti2.c~~ +- ~~negvdi2.c~~ +- ~~negvsi2.c~~ +- ~~negvti2.c~~ +- ~~paritydi2.c~~ +- ~~paritysi2.c~~ +- ~~parityti2.c~~ +- ~~popcountdi2.c~~ +- ~~popcountsi2.c~~ +- ~~popcountti2.c~~ +- ~~ppc/restFP.S~~ +- ~~ppc/saveFP.S~~ +- ~~subvdi3.c~~ +- ~~subvsi3.c~~ +- ~~subvti3.c~~ +- ~~ucmpdi2.c~~ +- ~~ucmpti2.c~~ +- ~~udivmoddi4.c~~ +- ~~udivmodsi4.c~~ +- ~~udivmodti4.c~~ + Rust only exposes atomic types on platforms that support them, and therefore does not need to fall back to software implementations. - ~~arm/sync_fetch_and_add_4.S~~ diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index d2544f588d4..7beb91aa958 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,5 +1,4 @@ extern "C" { - fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8; @@ -7,19 +6,6 @@ extern "C" { // FIXME: The `*4` and `*8` variants should be defined as aliases. -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - memcmp(s1, s2, n) -} -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memcmp4(s1: *const u8, s2: *const u8, n: usize) -> i32 { - memcmp(s1, s2, n) -} -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memcmp8(s1: *const u8, s2: *const u8, n: usize) -> i32 { - memcmp(s1, s2, n) -} - #[no_mangle] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); -- cgit 1.4.1-3-g733a5 From 68e0b7657c935e21c9f4b715b02846cc7efeeab2 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 8 Aug 2016 08:27:22 +0100 Subject: Remove the x86-specific floating-point builtins --- library/compiler-builtins/README.md | 25 ++++++++++++++----------- library/compiler-builtins/src/lib.rs | 3 --- library/compiler-builtins/src/x86_64.rs | 9 --------- 3 files changed, 14 insertions(+), 23 deletions(-) delete mode 100644 library/compiler-builtins/src/x86_64.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index a08f4d26208..c68882985aa 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -34,6 +34,9 @@ See [rust-lang/rust#35437][0]. - [ ] arm/aeabi_fcmp.S - [ ] arm/aeabi_idivmod.S - [ ] arm/aeabi_ldivmod.S +- [x] arm/aeabi_memcpy.S +- [x] arm/aeabi_memmove.S +- [x] arm/aeabi_memset.S - [ ] arm/aeabi_uidivmod.S - [ ] arm/aeabi_uldivmod.S - [ ] arm/divdf3vfp.S @@ -115,10 +118,6 @@ See [rust-lang/rust#35437][0]. - [ ] i386/chkstk.S - [ ] i386/chkstk2.S - [ ] i386/divdi3.S -- [ ] i386/floatdidf.S -- [ ] i386/floatdisf.S -- [ ] i386/floatundidf.S -- [ ] i386/floatundisf.S - [ ] i386/lshrdi3.S - [ ] i386/moddi3.S - [ ] i386/muldi3.S @@ -151,13 +150,6 @@ See [rust-lang/rust#35437][0]. - [ ] umodti3.c - [ ] x86_64/chkstk.S - [ ] x86_64/chkstk2.S -- [ ] x86_64/floatundidf.S -- [ ] x86_64/floatundisf.S -- [x] arm/aeabi_memcpy.S -- [x] arm/aeabi_memmove.S -- [x] arm/aeabi_memset.S -- [x] x86_64/floatdidf.c -- [x] x86_64/floatdisf.c ## Unimplemented functions @@ -325,6 +317,17 @@ Miscellaneous functionality that is not used by Rust. - ~~gcc_personality_v0.c~~ - ~~trampoline_setup.c~~ +Floating-point implementations of builtins that are only called from soft-float code. It would be better to simply use the generic soft-float versions in this case. + +- ~~i386/floatdidf.S~~ +- ~~i386/floatdisf.S~~ +- ~~i386/floatundidf.S~~ +- ~~i386/floatundisf.S~~ +- ~~x86_64/floatundidf.S~~ +- ~~x86_64/floatundisf.S~~ +- ~~x86_64/floatdidf.c~~ +- ~~x86_64/floatdisf.c~~ + ## License Licensed under either of diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 838e62a296b..01aca7674c2 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -14,9 +14,6 @@ use core::mem; #[cfg(target_arch = "arm")] pub mod arm; -#[cfg(target_arch = "x86_64")] -pub mod x86_64; - #[cfg(test)] mod test; diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs deleted file mode 100644 index d4ea0f759de..00000000000 --- a/library/compiler-builtins/src/x86_64.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[no_mangle] -pub extern "C" fn __floatdisf(x: i64) -> f32 { - x as f32 -} - -#[no_mangle] -pub extern "C" fn __floatdidf(x: i64) -> f64 { - x as f64 -} -- cgit 1.4.1-3-g733a5 From 2431cd754bc23ec556e15b80f8cf566aa830da82 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 19:31:37 -0500 Subject: CI: test powerpc-unknown-linux-gnu --- library/compiler-builtins/.travis.yml | 11 +++++++++++ library/compiler-builtins/ci/env.sh | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7ede66cce92..7e22c1d4b7d 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -48,6 +48,17 @@ matrix: apt: packages: - gcc-multilib + - env: TARGET=powerpc-unknown-linux-gnu + os: linux + sudo: required + addons: + apt: + packages: + - binfmt-support + - gcc-powerpc-linux-gnu + - libc6-powerpc-cross + - libc6-dev-powerpc-cross + - qemu-user-static - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 92f0c3ecabd..fa1b1f0cdf3 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -24,4 +24,8 @@ case $TARGET in export PREFIX=arm-linux-gnueabihf- export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf ;; + powerpc-unknown-linux-gnu) + export PREFIX=powerpc-linux-gnu- + export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu + ;; esac -- cgit 1.4.1-3-g733a5 From e0be22eb4429c6869ced1f6a0a2444ac3dd20301 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 19:36:20 -0500 Subject: use trusty --- library/compiler-builtins/.travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7e22c1d4b7d..e13bd112f53 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -50,6 +50,7 @@ matrix: - gcc-multilib - env: TARGET=powerpc-unknown-linux-gnu os: linux + dist: trusty sudo: required addons: apt: -- cgit 1.4.1-3-g733a5 From a1b1c8d66a686909ea9d3d935bdf51cb7bf8e0d8 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 19:44:55 -0500 Subject: CI: test powerpc64le-unknown-linux-gnu --- library/compiler-builtins/.travis.yml | 12 ++++++++++++ library/compiler-builtins/ci/env.sh | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index e13bd112f53..8f6a27018a8 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -60,6 +60,18 @@ matrix: - libc6-powerpc-cross - libc6-dev-powerpc-cross - qemu-user-static + - env: TARGET=powerpc64le-unknown-linux-gnu + os: linux + dist: trusty + sudo: required + addons: + apt: + packages: + - binfmt-support + - gcc-powerpc64le-linux-gnu + - libc6-ppc64el-cross + - libc6-dev-ppc64el-cross + - qemu-user-static - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index fa1b1f0cdf3..0bfc810858a 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -28,4 +28,8 @@ case $TARGET in export PREFIX=powerpc-linux-gnu- export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; + powerpc64le-unknown-linux-gnu) + export PREFIX=powerpc64le-linux-gnu- + export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu + ;; esac -- cgit 1.4.1-3-g733a5 From e813daef4b4050c05c5415dea35e38ce2392a9ab Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 20:04:17 -0500 Subject: explicitly use qemu-ppc64le --- library/compiler-builtins/.travis.yml | 2 +- library/compiler-builtins/ci/env.sh | 1 + library/compiler-builtins/ci/script.sh | 11 +++++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 8f6a27018a8..ba1c5369d12 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -71,7 +71,7 @@ matrix: - gcc-powerpc64le-linux-gnu - libc6-ppc64el-cross - libc6-dev-ppc64el-cross - - qemu-user-static + - qemu-user - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 0bfc810858a..29707a4b08c 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -30,6 +30,7 @@ case $TARGET in ;; powerpc64le-unknown-linux-gnu) export PREFIX=powerpc64le-linux-gnu- + export QEMU=qemu-ppc64le export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu ;; esac diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index c1748fcd73e..0249a531cd3 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -12,8 +12,15 @@ run_tests() { export RUST_TEST_THREADS=1 fi - cargo test --target $TARGET - cargo test --target $TARGET --release + if [[ $QEMU ]]; then + cargo test --target $TARGET --no-run + $QEMU target/**/debug/rustc_builtins-* + cargo test --target $TARGET --release --no-run + $QEMU target/**/release/rustc_builtins-* + else + cargo test --target $TARGET + cargo test --target $TARGET --release + fi } inspect() { -- cgit 1.4.1-3-g733a5 From 4c52ab7a895021549ef7e1979066cdaab2dc1fcc Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 20:37:04 -0500 Subject: run in xenial (docker) --- library/compiler-builtins/.travis.yml | 1 + library/compiler-builtins/ci/env.sh | 1 + library/compiler-builtins/ci/install.sh | 22 +++++++++++++++++----- library/compiler-builtins/ci/script.sh | 16 +++++++++++++--- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index ba1c5369d12..aecd54618c0 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -63,6 +63,7 @@ matrix: - env: TARGET=powerpc64le-unknown-linux-gnu os: linux dist: trusty + services: docker sudo: required addons: apt: diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 29707a4b08c..ed4e1b0b651 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -29,6 +29,7 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; powerpc64le-unknown-linux-gnu) + export DOCKER=y export PREFIX=powerpc64le-linux-gnu- export QEMU=qemu-ppc64le export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 3d11092f8c0..79af908946c 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -2,6 +2,15 @@ set -ex . $(dirname $0)/env.sh +install_qemu() { + case $TARGET in + powerpc64-unknown-linux-gnu) + sudo apt-get install -y --no-install-recommends \ + qemu-user + ;; + esac +} + install_binutils() { case $TRAVIS_OS_NAME in osx) @@ -49,11 +58,14 @@ EOF } main() { - install_binutils - install_c_toolchain - install_rust - add_rustup_target - configure_cargo + if [[ -z $DOCKER ]]; then + install_qemu + install_binutils + install_c_toolchain + install_rust + add_rustup_target + configure_cargo + fi } main diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 0249a531cd3..b3f7c17a3e5 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -32,9 +32,19 @@ inspect() { } main() { - build - run_tests - inspect + if [[ $DOCKER ]]; then + docker run \ + -e TARGET=$TARGET \ + -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ + -v $(pwd)/ci:/mnt \ + ubuntu:16.04 \ + sh -c "bash /mnt/install.sh; bash /mnt/script.sh" + else + build + run_tests + inspect + fi + } main -- cgit 1.4.1-3-g733a5 From a2fd9ed440a2aeca262fb17baf17e8e690aed6d7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 20:41:08 -0500 Subject: install toolchain in docker --- library/compiler-builtins/.travis.yml | 9 --------- library/compiler-builtins/ci/install.sh | 6 +++++- library/compiler-builtins/ci/script.sh | 4 ++-- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index aecd54618c0..dee71f7022f 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -62,17 +62,8 @@ matrix: - qemu-user-static - env: TARGET=powerpc64le-unknown-linux-gnu os: linux - dist: trusty services: docker sudo: required - addons: - apt: - packages: - - binfmt-support - - gcc-powerpc64le-linux-gnu - - libc6-ppc64el-cross - - libc6-dev-ppc64el-cross - - qemu-user - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 79af908946c..80a1023b3c3 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -25,7 +25,11 @@ install_c_toolchain() { case $TARGET in aarch64-unknown-linux-gnu) sudo apt-get install -y --no-install-recommends \ - gcc-aarch64-linux-gnu libc6-arm64-cross libc6-dev-arm64-cross + gcc-aarch64-linux-gnu libc6-dev-arm64-cross + ;; + powerpc64-unknown-linux-gnu) + sudo apt-get install -y --no-install-recommends \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64le-cross ;; *) ;; diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index b3f7c17a3e5..1013208bb9d 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -36,9 +36,9 @@ main() { docker run \ -e TARGET=$TARGET \ -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ - -v $(pwd)/ci:/mnt \ + -v $(pwd):/mnt \ ubuntu:16.04 \ - sh -c "bash /mnt/install.sh; bash /mnt/script.sh" + sh -c "cd /mnt; bash ci/install.sh; bash ci/script.sh" else build run_tests -- cgit 1.4.1-3-g733a5 From 3d3248119a505d26432e60c892adba4b56de1616 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 20:45:46 -0500 Subject: enable docker --- library/compiler-builtins/.travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index dee71f7022f..6d3d4311a40 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -62,7 +62,8 @@ matrix: - qemu-user-static - env: TARGET=powerpc64le-unknown-linux-gnu os: linux - services: docker + services: + - docker sudo: required - env: TARGET=x86_64-apple-darwin os: osx -- cgit 1.4.1-3-g733a5 From 87004d454cdef106a7df67054117bae3fd4c100b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 20:53:33 -0500 Subject: don't recursively call docker --- library/compiler-builtins/.travis.yml | 3 +-- library/compiler-builtins/ci/env.sh | 4 +++- library/compiler-builtins/ci/script.sh | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 6d3d4311a40..dee71f7022f 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -62,8 +62,7 @@ matrix: - qemu-user-static - env: TARGET=powerpc64le-unknown-linux-gnu os: linux - services: - - docker + services: docker sudo: required - env: TARGET=x86_64-apple-darwin os: osx diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index ed4e1b0b651..7458372baf8 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -29,7 +29,9 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; powerpc64le-unknown-linux-gnu) - export DOCKER=y + if [[ -z $DOCKER ]]; then + export DOCKER=y + fi export PREFIX=powerpc64le-linux-gnu- export QEMU=qemu-ppc64le export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 1013208bb9d..1e23656791b 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -32,8 +32,9 @@ inspect() { } main() { - if [[ $DOCKER ]]; then + if [[ $DOCKER == "y" ]]; then docker run \ + -e DOCKER=n \ -e TARGET=$TARGET \ -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ -v $(pwd):/mnt \ @@ -44,7 +45,6 @@ main() { run_tests inspect fi - } main -- cgit 1.4.1-3-g733a5 From f31fd01713df99e654a3faf40293dcdbc783b544 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:02:07 -0500 Subject: set PATH inside docker --- library/compiler-builtins/ci/script.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 1e23656791b..56625fafc54 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -39,7 +39,10 @@ main() { -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ -v $(pwd):/mnt \ ubuntu:16.04 \ - sh -c "cd /mnt; bash ci/install.sh; bash ci/script.sh" + sh -c 'cd /mnt; + export PATH="$PATH:$HOME/.cargo/bin"; + bash ci/install.sh; + bash ci/script.sh' else build run_tests -- cgit 1.4.1-3-g733a5 From ed2f8c937ea28ec1ce5f3b249c2ef4643a039426 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:14:04 -0500 Subject: don't skip install phase inside docker --- library/compiler-builtins/ci/install.sh | 2 +- library/compiler-builtins/ci/script.sh | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 80a1023b3c3..69f6ebcf36d 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -62,7 +62,7 @@ EOF } main() { - if [[ -z $DOCKER ]]; then + if [[ ${DOCKER:-n} != "y" ]]; then install_qemu install_binutils install_c_toolchain diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 56625fafc54..4a6dce7a8a9 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -39,7 +39,8 @@ main() { -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ -v $(pwd):/mnt \ ubuntu:16.04 \ - sh -c 'cd /mnt; + sh -c 'set -ex; + cd /mnt; export PATH="$PATH:$HOME/.cargo/bin"; bash ci/install.sh; bash ci/script.sh' -- cgit 1.4.1-3-g733a5 From f9d1455b29959b64c0652e7af6cac326d4e594e0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:20:46 -0500 Subject: install curl inside docker --- library/compiler-builtins/ci/install.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 69f6ebcf36d..3c87ddb6ad3 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -2,6 +2,13 @@ set -ex . $(dirname $0)/env.sh +install_deps() { + if [[ ${DOCKER} == "y" ]]; then + apt-get install -y --no-install-recommends \ + ca-certificates curl + fi +} + install_qemu() { case $TARGET in powerpc64-unknown-linux-gnu) @@ -63,6 +70,7 @@ EOF main() { if [[ ${DOCKER:-n} != "y" ]]; then + install_deps install_qemu install_binutils install_c_toolchain -- cgit 1.4.1-3-g733a5 From eb5a86b261948f4a6e8407203fc69ebce3ce5ae1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:27:08 -0500 Subject: really install curl inside docker --- library/compiler-builtins/ci/env.sh | 1 + library/compiler-builtins/ci/install.sh | 2 +- library/compiler-builtins/ci/script.sh | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 7458372baf8..f1aa4fe2cd2 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -29,6 +29,7 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; powerpc64le-unknown-linux-gnu) + # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) if [[ -z $DOCKER ]]; then export DOCKER=y fi diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 3c87ddb6ad3..c545eedf1a5 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -3,7 +3,7 @@ set -ex . $(dirname $0)/env.sh install_deps() { - if [[ ${DOCKER} == "y" ]]; then + if [[ ${DOCKER} == "i" ]]; then apt-get install -y --no-install-recommends \ ca-certificates curl fi diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 4a6dce7a8a9..65d74a332a2 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -34,7 +34,7 @@ inspect() { main() { if [[ $DOCKER == "y" ]]; then docker run \ - -e DOCKER=n \ + -e DOCKER=i \ -e TARGET=$TARGET \ -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ -v $(pwd):/mnt \ -- cgit 1.4.1-3-g733a5 From ce538c66184576694e2cc0ccfe62aad2b20cc3d2 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:32:12 -0500 Subject: apt-get update --- library/compiler-builtins/ci/install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index c545eedf1a5..d7eac145dfb 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -4,6 +4,7 @@ set -ex install_deps() { if [[ ${DOCKER} == "i" ]]; then + apt-get update apt-get install -y --no-install-recommends \ ca-certificates curl fi -- cgit 1.4.1-3-g733a5 From d24e0e07a32d767495f84645a3747431cecd3614 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:37:48 -0500 Subject: fix installation of c toolchain --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index d7eac145dfb..2635c8984aa 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -35,7 +35,7 @@ install_c_toolchain() { sudo apt-get install -y --no-install-recommends \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross ;; - powerpc64-unknown-linux-gnu) + powerpc64le-unknown-linux-gnu) sudo apt-get install -y --no-install-recommends \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64le-cross ;; -- cgit 1.4.1-3-g733a5 From 5e6dc52747f8aa5d3a6542c51b801a61e325f0fa Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:43:01 -0500 Subject: no sudo --- library/compiler-builtins/ci/install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 2635c8984aa..0000e457562 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -36,8 +36,8 @@ install_c_toolchain() { gcc-aarch64-linux-gnu libc6-dev-arm64-cross ;; powerpc64le-unknown-linux-gnu) - sudo apt-get install -y --no-install-recommends \ - gcc-powerpc64le-linux-gnu libc6-dev-ppc64le-cross + apt-get install -y --no-install-recommends \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64le-cross ;; *) ;; -- cgit 1.4.1-3-g733a5 From 32758212c87a74a15c4774aee11ddebb032b44cd Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:43:13 -0500 Subject: put first in the queue --- library/compiler-builtins/.travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index dee71f7022f..7f90c44ad75 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -3,6 +3,10 @@ sudo: false matrix: include: + - env: TARGET=powerpc64le-unknown-linux-gnu + os: linux + services: docker + sudo: required - env: TARGET=aarch64-unknown-linux-gnu os: linux dist: trusty @@ -60,10 +64,6 @@ matrix: - libc6-powerpc-cross - libc6-dev-powerpc-cross - qemu-user-static - - env: TARGET=powerpc64le-unknown-linux-gnu - os: linux - services: docker - sudo: required - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu -- cgit 1.4.1-3-g733a5 From 378bab2a11f4d6edb74f708b66f568e6914adce4 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:46:24 -0500 Subject: fix package name --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 0000e457562..867ac00e743 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -37,7 +37,7 @@ install_c_toolchain() { ;; powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc-powerpc64le-linux-gnu libc6-dev-ppc64le-cross + gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross ;; *) ;; -- cgit 1.4.1-3-g733a5 From c3a501ec3b84a6927097a4389c1b1ecebeb0ac60 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:49:31 -0500 Subject: fix target name in case --- library/compiler-builtins/ci/install.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 867ac00e743..ae94e949d24 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -12,9 +12,9 @@ install_deps() { install_qemu() { case $TARGET in - powerpc64-unknown-linux-gnu) - sudo apt-get install -y --no-install-recommends \ - qemu-user + powerpc64le-unknown-linux-gnu) + apt-get install -y --no-install-recommends \ + qemu-user ;; esac } -- cgit 1.4.1-3-g733a5 From 808ff7d4696afcebc790f5a18ff67481917b78fc Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:57:18 -0500 Subject: allow failure --- library/compiler-builtins/.travis.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7f90c44ad75..3ae43eba3f8 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -3,10 +3,6 @@ sudo: false matrix: include: - - env: TARGET=powerpc64le-unknown-linux-gnu - os: linux - services: docker - sudo: required - env: TARGET=aarch64-unknown-linux-gnu os: linux dist: trusty @@ -64,6 +60,10 @@ matrix: - libc6-powerpc-cross - libc6-dev-powerpc-cross - qemu-user-static + - env: TARGET=powerpc64le-unknown-linux-gnu + os: linux + services: docker + sudo: required - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu @@ -72,6 +72,9 @@ matrix: # FIXME(#2) - env: TARGET=armv7-unknown-linux-gnueabihf os: linux + # FIXME QEMU blows up + - env: TARGET=powerpc64le-unknown-linux-gnu + os: linux before_install: - export PATH="$PATH:$HOME/.cargo/bin" -- cgit 1.4.1-3-g733a5 From cb83ffc7f740f24052dbc9afff1f26ab48afa772 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 22:03:44 -0500 Subject: CI: test mips-unknown-linux-gnu --- library/compiler-builtins/.travis.yml | 4 ++++ library/compiler-builtins/ci/env.sh | 10 +++++++++- library/compiler-builtins/ci/install.sh | 5 +++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 3ae43eba3f8..e6667a7e4b5 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -48,6 +48,10 @@ matrix: apt: packages: - gcc-multilib + - env: TARGET=mips-unknown-linux-gnu + os: linux + services: docker + sudo: required - env: TARGET=powerpc-unknown-linux-gnu os: linux dist: trusty diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index f1aa4fe2cd2..eadaae478f9 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -24,12 +24,20 @@ case $TARGET in export PREFIX=arm-linux-gnueabihf- export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf ;; + mips-unknown-linux-gnu) + # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) + if [[ -z $DOCKER ]]; then + export DOCKER=y + fi + export PREFIX=mips-linux-gnu- + export QEMU=qemu-mips + export QEMU_LD_PREFIX=/usr/mips-linux-gnu + ;; powerpc-unknown-linux-gnu) export PREFIX=powerpc-linux-gnu- export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; powerpc64le-unknown-linux-gnu) - # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) if [[ -z $DOCKER ]]; then export DOCKER=y fi diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index ae94e949d24..e306cdf1f56 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -12,6 +12,7 @@ install_deps() { install_qemu() { case $TARGET in + mips-unknown-linux-gnu | powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ qemu-user @@ -35,6 +36,10 @@ install_c_toolchain() { sudo apt-get install -y --no-install-recommends \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross ;; + mips-unknown-linux-gnu) + apt-get install -y --no-install-recommends \ + gcc-mips-linux-gnu libc6-dev-mips-cross + ;; powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross -- cgit 1.4.1-3-g733a5 From b458b433979dd5ab1d4a84f5ff0c16dfa7ba77af Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 22:31:14 -0500 Subject: fix case syntax --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index e306cdf1f56..edabee74373 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -12,7 +12,7 @@ install_deps() { install_qemu() { case $TARGET in - mips-unknown-linux-gnu | + mips-unknown-linux-gnu | \ powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ qemu-user -- cgit 1.4.1-3-g733a5 From 04c097a6e399bc8f9a0494a784a5de69a8a218bf Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 22:47:37 -0500 Subject: allow failure --- library/compiler-builtins/.travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index e6667a7e4b5..46cdb6610b0 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -77,6 +77,9 @@ matrix: - env: TARGET=armv7-unknown-linux-gnueabihf os: linux # FIXME QEMU blows up + - env: TARGET=mips-unknown-linux-gnu + os: linux + # FIXME QEMU blows up - env: TARGET=powerpc64le-unknown-linux-gnu os: linux -- cgit 1.4.1-3-g733a5 From e9f11c6f121409213efe6acc6274ac25c6b773d8 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:59:31 -0500 Subject: CI: test powerpc64-unknown-linux-gnu --- library/compiler-builtins/.travis.yml | 7 +++++++ library/compiler-builtins/ci/env.sh | 8 ++++++++ library/compiler-builtins/ci/install.sh | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 46cdb6610b0..008cc3dabc0 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -64,6 +64,10 @@ matrix: - libc6-powerpc-cross - libc6-dev-powerpc-cross - qemu-user-static + - env: TARGET=powerpc64-unknown-linux-gnu + os: linux + services: docker + sudo: required - env: TARGET=powerpc64le-unknown-linux-gnu os: linux services: docker @@ -80,6 +84,9 @@ matrix: - env: TARGET=mips-unknown-linux-gnu os: linux # FIXME QEMU blows up + - env: TARGET=powerpc64-unknown-linux-gnu + os: linux + # FIXME QEMU blows up - env: TARGET=powerpc64le-unknown-linux-gnu os: linux diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index eadaae478f9..81b89014abc 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -37,6 +37,14 @@ case $TARGET in export PREFIX=powerpc-linux-gnu- export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; + powerpc64-unknown-linux-gnu) + if [[ -z $DOCKER ]]; then + export DOCKER=y + fi + export PREFIX=powerpc64-linux-gnu- + export QEMU=qemu-ppc64 + export QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu + ;; powerpc64le-unknown-linux-gnu) if [[ -z $DOCKER ]]; then export DOCKER=y diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index edabee74373..85fcc4d6b5b 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -13,6 +13,7 @@ install_deps() { install_qemu() { case $TARGET in mips-unknown-linux-gnu | \ + powerpc64-unknown-linux-gnu | \ powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ qemu-user @@ -40,6 +41,10 @@ install_c_toolchain() { apt-get install -y --no-install-recommends \ gcc-mips-linux-gnu libc6-dev-mips-cross ;; + powerpc64-unknown-linux-gnu) + apt-get install -y --no-install-recommends \ + gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross + ;; powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross -- cgit 1.4.1-3-g733a5 From 59a8ab6c87df5e730a4ccf4cf9e2d5c3ee503e1e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 23:07:33 -0500 Subject: CI: test mipsel-unknown-linux-gnu --- library/compiler-builtins/.travis.yml | 4 ++++ library/compiler-builtins/ci/env.sh | 9 +++++++++ library/compiler-builtins/ci/install.sh | 5 +++++ 3 files changed, 18 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 008cc3dabc0..dacfd705a50 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -52,6 +52,10 @@ matrix: os: linux services: docker sudo: required + - env: TARGET=mipsel-unknown-linux-gnu + os: linux + services: docker + sudo: required - env: TARGET=powerpc-unknown-linux-gnu os: linux dist: trusty diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 81b89014abc..fb3d1ef26f7 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -33,6 +33,15 @@ case $TARGET in export QEMU=qemu-mips export QEMU_LD_PREFIX=/usr/mips-linux-gnu ;; + mipsel-unknown-linux-gnu) + # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) + if [[ -z $DOCKER ]]; then + export DOCKER=y + fi + export PREFIX=mipsel-linux-gnu- + export QEMU=qemu-mipsel + export QEMU_LD_PREFIX=/usr/mipsel-linux-gnu + ;; powerpc-unknown-linux-gnu) export PREFIX=powerpc-linux-gnu- export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 85fcc4d6b5b..82c4c59b37c 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -13,6 +13,7 @@ install_deps() { install_qemu() { case $TARGET in mips-unknown-linux-gnu | \ + mipsel-unknown-linux-gnu | \ powerpc64-unknown-linux-gnu | \ powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ @@ -41,6 +42,10 @@ install_c_toolchain() { apt-get install -y --no-install-recommends \ gcc-mips-linux-gnu libc6-dev-mips-cross ;; + mipsel-unknown-linux-gnu) + apt-get install -y --no-install-recommends \ + gcc-mipsel-linux-gnu libc6-dev-mipsel-cross + ;; powerpc64-unknown-linux-gnu) apt-get install -y --no-install-recommends \ gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross -- cgit 1.4.1-3-g733a5 From 4d0da42b082460879b7f925d92dd45b1ec42706e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 11:48:51 -0500 Subject: don't run tests on targets that have QEMU issues cc #2 --- library/compiler-builtins/.travis.yml | 13 ------------- library/compiler-builtins/ci/env.sh | 15 +++++++++++++-- library/compiler-builtins/ci/script.sh | 8 ++++++-- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index dacfd705a50..c1b6dd4fbd1 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -80,19 +80,6 @@ matrix: os: osx - env: TARGET=x86_64-unknown-linux-gnu os: linux - allow_failures: - # FIXME(#2) - - env: TARGET=armv7-unknown-linux-gnueabihf - os: linux - # FIXME QEMU blows up - - env: TARGET=mips-unknown-linux-gnu - os: linux - # FIXME QEMU blows up - - env: TARGET=powerpc64-unknown-linux-gnu - os: linux - # FIXME QEMU blows up - - env: TARGET=powerpc64le-unknown-linux-gnu - os: linux before_install: - export PATH="$PATH:$HOME/.cargo/bin" diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index fb3d1ef26f7..ee3bd163e8c 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -20,11 +20,19 @@ case $TARGET in export PREFIX=arm-linux-gnueabi- export QEMU_LD_PREFIX=/usr/arm-linux-gnueabi ;; - arm*-unknown-linux-gnueabihf) + arm-unknown-linux-gnueabihf) + export PREFIX=arm-linux-gnueabihf- + export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf + ;; + armv7-unknown-linux-gnueabihf) + # See #2 + export DONT_RUN_TESTS=y export PREFIX=arm-linux-gnueabihf- export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf ;; mips-unknown-linux-gnu) + # See #2 + export DONT_RUN_TESTS=y # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) if [[ -z $DOCKER ]]; then export DOCKER=y @@ -34,7 +42,6 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/mips-linux-gnu ;; mipsel-unknown-linux-gnu) - # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) if [[ -z $DOCKER ]]; then export DOCKER=y fi @@ -47,6 +54,8 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; powerpc64-unknown-linux-gnu) + # See #2 + export DONT_RUN_TESTS=y if [[ -z $DOCKER ]]; then export DOCKER=y fi @@ -55,6 +64,8 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu ;; powerpc64le-unknown-linux-gnu) + # See #2 + export DONT_RUN_TESTS=y if [[ -z $DOCKER ]]; then export DOCKER=y fi diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 65d74a332a2..16b6e763f03 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -14,9 +14,13 @@ run_tests() { if [[ $QEMU ]]; then cargo test --target $TARGET --no-run - $QEMU target/**/debug/rustc_builtins-* + if [[ -z $DONT_RUN_TESTS ]]; then + $QEMU target/**/debug/rustc_builtins-* + fi cargo test --target $TARGET --release --no-run - $QEMU target/**/release/rustc_builtins-* + if [[ -z $DONT_RUN_TESTS ]]; then + $QEMU target/**/release/rustc_builtins-* + fi else cargo test --target $TARGET cargo test --target $TARGET --release -- cgit 1.4.1-3-g733a5 From b191b89e87cf308ff6ded22a78b76509003f88cb Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 11:53:49 -0500 Subject: fix armv7 --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 16b6e763f03..c0074ec0808 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -21,7 +21,7 @@ run_tests() { if [[ -z $DONT_RUN_TESTS ]]; then $QEMU target/**/release/rustc_builtins-* fi - else + else if [[ -z $DONT_RUN_TESTS ]]; then cargo test --target $TARGET cargo test --target $TARGET --release fi -- cgit 1.4.1-3-g733a5 From d6acb778e485d7c5d779c71963e9d7a34de5a242 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 12:04:24 -0500 Subject: fix bash syntax --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index c0074ec0808..099e42ea3b0 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -21,7 +21,7 @@ run_tests() { if [[ -z $DONT_RUN_TESTS ]]; then $QEMU target/**/release/rustc_builtins-* fi - else if [[ -z $DONT_RUN_TESTS ]]; then + elif [[ -z $DONT_RUN_TESTS ]]; then cargo test --target $TARGET cargo test --target $TARGET --release fi -- cgit 1.4.1-3-g733a5 From 3aa17dec7a41a16582650e1cbc6f541057efe31f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 12:25:49 -0500 Subject: CI: test i586-unknown-linux-gnu --- library/compiler-builtins/.travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index c1b6dd4fbd1..45b3d03fb7e 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -42,6 +42,12 @@ matrix: packages: *armhf - env: TARGET=i686-apple-darwin os: osx + - env: TARGET=i586-unknown-linux-gnu + os: linux + addons: + apt: + packages: + - gcc-multilib - env: TARGET=i686-unknown-linux-gnu os: linux addons: -- cgit 1.4.1-3-g733a5 From a601cae4b4f80569009333f37fec83a136d8b820 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 12:43:37 -0500 Subject: use trusty --- library/compiler-builtins/.travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 45b3d03fb7e..b3fd61d8a81 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -44,6 +44,7 @@ matrix: os: osx - env: TARGET=i586-unknown-linux-gnu os: linux + dist: trusty addons: apt: packages: -- cgit 1.4.1-3-g733a5 From 5e8812c57419c645929c1c8741139391dafd66da Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 15:37:24 -0500 Subject: use docker --- library/compiler-builtins/.travis.yml | 7 ++----- library/compiler-builtins/ci/env.sh | 7 ++++++- library/compiler-builtins/ci/install.sh | 4 ++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index b3fd61d8a81..13e843e4de3 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -44,11 +44,8 @@ matrix: os: osx - env: TARGET=i586-unknown-linux-gnu os: linux - dist: trusty - addons: - apt: - packages: - - gcc-multilib + services: docker + sudo: required - env: TARGET=i686-unknown-linux-gnu os: linux addons: diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index ee3bd163e8c..09b86f2f093 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -30,10 +30,15 @@ case $TARGET in export PREFIX=arm-linux-gnueabihf- export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf ;; + i586-unknown-linux-gnu) + # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) + if [[ -z $DOCKER ]]; then + export DOCKER=y + fi + ;; mips-unknown-linux-gnu) # See #2 export DONT_RUN_TESTS=y - # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) if [[ -z $DOCKER ]]; then export DOCKER=y fi diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 82c4c59b37c..c97a45daef3 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -38,6 +38,10 @@ install_c_toolchain() { sudo apt-get install -y --no-install-recommends \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross ;; + i586-unknown-linux-gnu) + apt-get install -y --no-install-recommends \ + gcc libc6-dev-i386 + ;; mips-unknown-linux-gnu) apt-get install -y --no-install-recommends \ gcc-mips-linux-gnu libc6-dev-mips-cross -- cgit 1.4.1-3-g733a5 From 57c1e1344eac777b415e8bb8931f2abdbe3f92fd Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 15:37:51 -0500 Subject: put the target first --- library/compiler-builtins/.travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 13e843e4de3..dae5b40b2d0 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -3,6 +3,10 @@ sudo: false matrix: include: + - env: TARGET=i586-unknown-linux-gnu + os: linux + services: docker + sudo: required - env: TARGET=aarch64-unknown-linux-gnu os: linux dist: trusty @@ -42,10 +46,6 @@ matrix: packages: *armhf - env: TARGET=i686-apple-darwin os: osx - - env: TARGET=i586-unknown-linux-gnu - os: linux - services: docker - sudo: required - env: TARGET=i686-unknown-linux-gnu os: linux addons: -- cgit 1.4.1-3-g733a5 From 4e6c1b1be3cb0e205e7ac2397706bcb4f65d2fe1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 15:46:57 -0500 Subject: add libgcc --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index c97a45daef3..e34433c894f 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -40,7 +40,7 @@ install_c_toolchain() { ;; i586-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc libc6-dev-i386 + gcc libc6-dev-i386 libgcc1 ;; mips-unknown-linux-gnu) apt-get install -y --no-install-recommends \ -- cgit 1.4.1-3-g733a5 From f484596465376ad861a80f5f351a18ccf4485617 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 15:55:25 -0500 Subject: 32-bit version of libgcc --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index e34433c894f..8226e1784f0 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -40,7 +40,7 @@ install_c_toolchain() { ;; i586-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc libc6-dev-i386 libgcc1 + gcc libc6-dev-i386 lib32gcc1 ;; mips-unknown-linux-gnu) apt-get install -y --no-install-recommends \ -- cgit 1.4.1-3-g733a5 From 3d2573086fcccd9df7121ec57d4c44ef569c88fa Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 16:17:06 -0500 Subject: libgcc_s dev version --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 8226e1784f0..9251f79a37d 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -40,7 +40,7 @@ install_c_toolchain() { ;; i586-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc libc6-dev-i386 lib32gcc1 + gcc libc6-dev-i386 lib32gcc-5-dev ;; mips-unknown-linux-gnu) apt-get install -y --no-install-recommends \ -- cgit 1.4.1-3-g733a5 From 1d924aa047a82ad6b7b9dadffc13fe4d7813c246 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 10 Aug 2016 11:50:41 -0500 Subject: mips: run test on 32-bit QEMU cc #2 --- library/compiler-builtins/ci/env.sh | 2 -- library/compiler-builtins/ci/install.sh | 9 ++++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 09b86f2f093..6ec927d50f7 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -37,8 +37,6 @@ case $TARGET in fi ;; mips-unknown-linux-gnu) - # See #2 - export DONT_RUN_TESTS=y if [[ -z $DOCKER ]]; then export DOCKER=y fi diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 9251f79a37d..074b5eac015 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -12,13 +12,18 @@ install_deps() { install_qemu() { case $TARGET in - mips-unknown-linux-gnu | \ mipsel-unknown-linux-gnu | \ powerpc64-unknown-linux-gnu | \ powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ qemu-user ;; + mips-unknown-linux-gnu) + dpkg --add-architecture i386 + apt-get update + apt-get install -y --no-install-recommends \ + qemu-user:i386 + ;; esac } @@ -58,8 +63,6 @@ install_c_toolchain() { apt-get install -y --no-install-recommends \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross ;; - *) - ;; esac } -- cgit 1.4.1-3-g733a5 From 989cd751cc5ee1850be988e222f7db6ecbed4b58 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 10 Aug 2016 13:01:22 -0500 Subject: ppc64: test on 32-bit QEMU --- library/compiler-builtins/ci/env.sh | 2 -- library/compiler-builtins/ci/install.sh | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 6ec927d50f7..472983ff918 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -57,8 +57,6 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; powerpc64-unknown-linux-gnu) - # See #2 - export DONT_RUN_TESTS=y if [[ -z $DOCKER ]]; then export DOCKER=y fi diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 074b5eac015..d60571db3d0 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -13,12 +13,12 @@ install_deps() { install_qemu() { case $TARGET in mipsel-unknown-linux-gnu | \ - powerpc64-unknown-linux-gnu | \ powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ qemu-user ;; - mips-unknown-linux-gnu) + mips-unknown-linux-gnu | \ + powerpc64-unknown-linux-gnu) dpkg --add-architecture i386 apt-get update apt-get install -y --no-install-recommends \ -- cgit 1.4.1-3-g733a5 From 2880fd70ad0504a56925609c9ffd229a6a7a7617 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 11 Aug 2016 05:28:15 +0100 Subject: Add traits for integer operations --- library/compiler-builtins/src/lib.rs | 63 +++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 01aca7674c2..3ef13549e5a 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -9,21 +9,76 @@ #[cfg(test)] extern crate core; -use core::mem; - #[cfg(target_arch = "arm")] pub mod arm; #[cfg(test)] mod test; -const CHAR_BITS: usize = 8; +/// Trait for some basic operations on integers +trait Int { + fn bits() -> usize; +} + +// TODO: Once i128/u128 support lands, we'll want to add impls for those as well +impl Int for u32 { + fn bits() -> usize { 32 } +} +impl Int for i32 { + fn bits() -> usize { 32 } +} +impl Int for u64 { + fn bits() -> usize { 64 } +} +impl Int for i64 { + fn bits() -> usize { 64 } +} + +/// Trait to convert an integer to/from smaller parts +trait LargeInt { + type LowHalf; + type HighHalf; + + fn low(self) -> Self::LowHalf; + fn high(self) -> Self::HighHalf; + fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; +} + +// TODO: Once i128/u128 support lands, we'll want to add impls for those as well +impl LargeInt for u64 { + type LowHalf = u32; + type HighHalf = u32; + + fn low(self) -> u32 { + self as u32 + } + fn high(self) -> u32 { + (self >> 32) as u32 + } + fn from_parts(low: u32, high: u32) -> u64 { + low as u64 | ((high as u64) << 32) + } +} +impl LargeInt for i64 { + type LowHalf = u32; + type HighHalf = i32; + + fn low(self) -> u32 { + self as u32 + } + fn high(self) -> i32 { + (self >> 32) as i32 + } + fn from_parts(low: u32, high: i32) -> i64 { + low as i64 | ((high as i64) << 32) + } +} macro_rules! absv_i2 { ($intrinsic:ident : $ty:ty) => { #[no_mangle] pub extern "C" fn $intrinsic(x: $ty) -> $ty { - let n = mem::size_of::<$ty>() * CHAR_BITS; + let n = <$ty>::bits(); if x == 1 << (n - 1) { panic!(); } -- cgit 1.4.1-3-g733a5 From 2eb2ac115d217249f543d24ee21a8604488b6074 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 10 Aug 2016 19:12:37 -0500 Subject: port udivmoddi4 and __aeabi_uldivmod --- library/compiler-builtins/Cargo.toml | 3 + library/compiler-builtins/src/arm.rs | 17 +++ library/compiler-builtins/src/lib.rs | 259 ++++++++++++++++++++++++++++++++++ library/compiler-builtins/src/test.rs | 21 ++- 4 files changed, 299 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 663d9b109a4..dfd1fdeeee1 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -2,3 +2,6 @@ authors = ["Jorge Aparicio "] name = "rustc_builtins" version = "0.1.0" + +[dev-dependencies] +quickcheck = "0.3.1" diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 7beb91aa958..55e9bb9faaa 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,3 +1,20 @@ +use core::mem; + +#[repr(C)] +pub struct u64x2 { + a: u64, + b: u64, +} + +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_uldivmod(num: u64, den: u64) -> u64x2 { + + let mut rem = mem::uninitialized(); + let quot = ::__udivmoddi4(num, den, &mut rem); + + u64x2 { a: quot, b: rem } +} + extern "C" { fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3ef13549e5a..e5caa83dcbf 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -8,6 +8,9 @@ #[cfg(test)] extern crate core; +#[cfg(test)] +#[macro_use] +extern crate quickcheck; #[cfg(target_arch = "arm")] pub mod arm; @@ -15,6 +18,8 @@ pub mod arm; #[cfg(test)] mod test; +use core::mem; + /// Trait for some basic operations on integers trait Int { fn bits() -> usize; @@ -93,3 +98,257 @@ absv_i2!(__absvsi2: i32); absv_i2!(__absvdi2: i64); // TODO(rust-lang/35118)? // absv_i2!(__absvti2, i128); + +#[no_mangle] +pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { + #[cfg(target_endian = "little")] + #[repr(C)] + #[derive(Debug)] + struct words { + low: u32, + high: u32, + } + + #[cfg(target_endian = "big")] + #[repr(C)] + #[derive(Debug)] + struct words { + high: u32, + low: u32, + } + + impl words { + fn all(&mut self) -> &mut u64 { + unsafe { mem::transmute(self) } + } + + fn u64(&self) -> u64 { + unsafe { *(self as *const _ as *const u64) } + } + } + + impl From for words { + fn from(x: u64) -> words { + unsafe { mem::transmute(x) } + } + } + + let u32_bits = u32::bits() as u32; + let u64_bits = u64::bits() as u32; + + let n = words::from(a); + let d = words::from(b); + + // NOTE X is unknown, K != 0 + if n.high == 0 { + return if d.high == 0 { + // 0 X + // --- + // 0 X + + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = u64::from(n.low % d.low); + } + u64::from(n.low / d.low) + } else + // d.high != 0 + { + // 0 X + // --- + // K X + + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = u64::from(n.low); + } + 0 + }; + } + + let mut sr; + // NOTE IMO it should be possible to leave these "uninitialized" (just declare them here) + // because these variables get initialized below, but if I do that the compiler complains about + // them being used before being initialized. + let mut q = words { low: 0, high: 0 }; + let mut r = words { low: 0, high: 0 }; + + // n.high != 0 + if d.low == 0 { + if d.high == 0 { + // K X + // --- + // 0 0 + + // NOTE copied verbatim from compiler-rt, but does division by zero even make sense? + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = u64::from(n.high % d.low); + } + return u64::from(n.high / d.low); + } + + // d.high != 0 + if n.low == 0 { + // K 0 + // --- + // K 0 + + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = words { + low: 0, + high: n.high % d.high, + } + .u64(); + } + return u64::from(n.high / d.high); + } + + // n.low != 0 + // K K + // --- + // K 0 + + if d.high.is_power_of_two() { + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = words { + low: n.low, + high: n.high & (d.high - 1), + } + .u64() + } + + return u64::from(n.high >> d.high.trailing_zeros()); + } + + sr = d.high.leading_zeros().wrapping_sub(n.high.leading_zeros()); + + // D > N + if sr > u32_bits - 2 { + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = n.u64(); + } + return 0; + } + + sr = sr + 1; + + // 1 <= sr <= u32_bits - 1 + // *q.all() = n.u64() << (u64_bits - sr); + q.low = 0; + q.high = n.low << (u32_bits - sr); + // *r.all() = n.u64() >> sr + r.high = n.high >> sr; + r.low = (n.high << (u32_bits - sr)) | (n.low >> sr); + } else + // d.low != 0 + { + if d.high == 0 { + // K X + // --- + // 0 K + if d.low.is_power_of_two() { + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = u64::from(n.low & (d.low - 1)); + } + + return if d.low == 1 { + n.u64() + } else { + let sr = d.low.trailing_zeros(); + words { + low: (n.high << (u32_bits - sr)) | (n.low >> sr), + high: n.high >> sr, + } + .u64() + }; + } + + sr = 1 + u32_bits + d.low.leading_zeros() - n.high.leading_zeros(); + + // 2 <= sr <= u64_bits - 1 + // *q.all() = n.u64() << (u64_bits - sr) + // *r.all() = n.u64() >> sr; + if sr == u32_bits { + q.low = 0; + q.high = n.low; + r.high = 0; + r.low = n.high; + } else if sr < u32_bits + // 2 <= sr <= u32_bits - 1 + { + q.low = 0; + q.high = n.low << (u32_bits - sr); + r.high = n.high >> sr; + r.low = (n.high << (u32_bits - sr)) | (n.low >> sr); + } else + // u32_bits + 1 <= sr <= u64_bits - 1 + { + q.low = n.low << (u64_bits - sr); + q.high = (n.high << (u64_bits - sr)) | (n.low >> (sr - u32_bits)); + r.high = 0; + r.low = n.high >> (sr - u32_bits); + } + + } else + // d.high != 0 + { + // K X + // --- + // K K + + sr = d.high.leading_zeros().wrapping_sub(n.high.leading_zeros()); + + // D > N + if sr > u32_bits - 1 { + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = a; + return 0; + } + } + + sr += 1; + + // 1 <= sr <= u32_bits + // *q.all() = n.u64() << (u64_bits - sr) + q.low = 0; + if sr == u32_bits { + q.high = n.low; + r.high = 0; + r.low = n.high; + } else { + q.high = n.low << (u32_bits - sr); + r.high = n.high >> sr; + r.low = (n.high << (u32_bits - sr)) | (n.low >> sr); + } + } + } + + // Not a special case + // q and r are initialized with + // *q.all() = n.u64() << (u64_bits - sr) + // *.r.all() = n.u64() >> sr + // 1 <= sr <= u64_bits - 1 + let mut carry = 0; + + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r.high = (r.high << 1) | (r.low >> (u32_bits - 1)); + r.low = (r.low << 1) | (q.high >> (u32_bits - 1)); + q.high = (q.high << 1) | (q.low >> (u32_bits - 1)); + q.low = (q.low << 1) | carry; + + // carry = 0 + // if r.u64() >= d.u64() { + // *r.all() -= d.u64(); + // carry = 1; + // } + + let s = (d.u64().wrapping_sub(r.u64()).wrapping_sub(1)) as i64 >> (u64_bits - 1); + carry = (s & 1) as u32; + *r.all() -= d.u64() & s as u64; + } + + *q.all() = (q.u64() << 1) | carry as u64; + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = r.u64(); + } + q.u64() +} diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs index 9abfec7e800..8d5a42c9e79 100644 --- a/library/compiler-builtins/src/test.rs +++ b/library/compiler-builtins/src/test.rs @@ -1,4 +1,6 @@ -use std::panic; +use std::{mem, panic}; + +use quickcheck::TestResult; macro_rules! absv_i2 { ($intrinsic:ident: $ty:ident) => { @@ -23,3 +25,20 @@ absv_i2!(__absvsi2: i32); absv_i2!(__absvdi2: i64); // TODO(rust-lang/35118)? // absv_i2!(__absvti2: i128); + +quickcheck! { + fn udivmoddi4(a: (u32, u32), b: (u32, u32)) -> TestResult { + let (a, b) = unsafe { + (mem::transmute(a), mem::transmute(b)) + }; + + if b == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = ::__udivmoddi4(a, b, &mut r); + + TestResult::from_bool(q * b + r == a) + } + } +} -- cgit 1.4.1-3-g733a5 From 003d4d15215f03278f021dba7efbaa936988f354 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 10 Aug 2016 19:51:18 -0500 Subject: some targets need gcc to be installed --- library/compiler-builtins/ci/install.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index d60571db3d0..e1635301d1e 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -49,19 +49,19 @@ install_c_toolchain() { ;; mips-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc-mips-linux-gnu libc6-dev-mips-cross + gcc gcc-mips-linux-gnu libc6-dev-mips-cross ;; mipsel-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc-mipsel-linux-gnu libc6-dev-mipsel-cross + gcc gcc-mipsel-linux-gnu libc6-dev-mipsel-cross ;; powerpc64-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross + gcc gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross ;; powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross + gcc gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross ;; esac } -- cgit 1.4.1-3-g733a5 From 2aaa38504fd3dc9e1a89252e2e797093c825dfda Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 10 Aug 2016 20:00:51 -0500 Subject: and libc6-dev --- library/compiler-builtins/ci/install.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index e1635301d1e..9c971c67a66 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -49,19 +49,19 @@ install_c_toolchain() { ;; mips-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc gcc-mips-linux-gnu libc6-dev-mips-cross + gcc gcc-mips-linux-gnu libc6-dev libc6-dev-mips-cross ;; mipsel-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc gcc-mipsel-linux-gnu libc6-dev-mipsel-cross + gcc gcc-mipsel-linux-gnu libc6-dev libc6-dev-mipsel-cross ;; powerpc64-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross + gcc gcc-powerpc64-linux-gnu libc6-dev libc6-dev-ppc64-cross ;; powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross + gcc gcc-powerpc64le-linux-gnu libc6-dev libc6-dev-ppc64el-cross ;; esac } -- cgit 1.4.1-3-g733a5 From 4c93f051952746b8a830a868f2fcd331ae93c35c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 10 Aug 2016 23:40:35 -0500 Subject: port __udivmodsi4, aeabi_uidivmod and udivsi3 also rewrite these last two new aeabi intrinsics as naked functions --- library/compiler-builtins/src/arm.rs | 37 ++++++++++++++------- library/compiler-builtins/src/lib.rs | 61 +++++++++++++++++++++++++++++++++++ library/compiler-builtins/src/test.rs | 13 ++++++++ 3 files changed, 100 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 55e9bb9faaa..bcfc6c86eb5 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,18 +1,33 @@ -use core::mem; +use core::intrinsics; -#[repr(C)] -pub struct u64x2 { - a: u64, - b: u64, +// TODO use `global_asm!` +#[naked] +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_uidivmod() { + asm!("push { lr } + sub sp, sp, #4 + mov r2, sp + bl __udivmodsi4 + ldr r1, [sp] + add sp, sp, #4 + pop { pc }"); + intrinsics::unreachable(); } +// TODO use `global_asm!` +#[naked] #[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_uldivmod(num: u64, den: u64) -> u64x2 { - - let mut rem = mem::uninitialized(); - let quot = ::__udivmoddi4(num, den, &mut rem); - - u64x2 { a: quot, b: rem } +pub unsafe extern "aapcs" fn __aeabi_uldivmod() { + asm!("push {r11, lr} + sub sp, sp, #16 + add r12, sp, #8 + str r12, [sp] + bl __udivmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r11, pc}"); + intrinsics::unreachable(); } extern "C" { diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index e5caa83dcbf..2c016a73c41 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -352,3 +352,64 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { } q.u64() } + +#[no_mangle] +pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: *mut u32) -> u32 { + let d = __udivsi3(a, b); + if let Some(rem) = unsafe {rem.as_mut()} { + *rem = a - (d*b); + } + return d; +} + +#[no_mangle] +pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { + let u32_bits = u32::bits() as u32; + + // Special cases + if d == 0 { + return 0; // ?! + } + + if n == 0 { + return 0; + } + + let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); + + // d > n + if sr > u32_bits - 1 { + return 0; + } + + // d == 1 + if sr == u32_bits - 1 { + return n; + } + + sr = sr + 1; + + // 1 <= sr <= u32_bits - 1 + let mut q = n << (u32_bits - sr); + let mut r = n >> sr; + + let mut carry = 0; + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (u32_bits - 1)); + q = (q << 1) | carry; + + // carry = 0; + // if r > d { + // r -= d; + // carry = 1; + // } + + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32_bits - 1); + carry = (s & 1) as u32; + r -= d & s as u32; + } + + q = (q << 1) | carry; + q +} diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs index 8d5a42c9e79..40e2885fba7 100644 --- a/library/compiler-builtins/src/test.rs +++ b/library/compiler-builtins/src/test.rs @@ -42,3 +42,16 @@ quickcheck! { } } } + +quickcheck! { + fn udivmodsi4(a: u32, b: u32) -> TestResult { + if b == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = ::__udivmodsi4(a, b, &mut r); + + TestResult::from_bool(q * b + r == a) + } + } +} -- cgit 1.4.1-3-g733a5 From 6d663ebb9ca4e3f5b0e08ba46b3a6f5fb1da783f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 00:31:49 -0500 Subject: *mut T -> Option<&mut T> --- library/compiler-builtins/src/lib.rs | 24 ++++++++++++------------ library/compiler-builtins/src/test.rs | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 2c016a73c41..d2dcbdc2ac1 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -100,7 +100,7 @@ absv_i2!(__absvdi2: i64); // absv_i2!(__absvti2, i128); #[no_mangle] -pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { +pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 { #[cfg(target_endian = "little")] #[repr(C)] #[derive(Debug)] @@ -146,7 +146,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // --- // 0 X - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = u64::from(n.low % d.low); } u64::from(n.low / d.low) @@ -157,7 +157,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // --- // K X - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = u64::from(n.low); } 0 @@ -179,7 +179,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // 0 0 // NOTE copied verbatim from compiler-rt, but does division by zero even make sense? - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = u64::from(n.high % d.low); } return u64::from(n.high / d.low); @@ -191,7 +191,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // --- // K 0 - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = words { low: 0, high: n.high % d.high, @@ -207,7 +207,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // K 0 if d.high.is_power_of_two() { - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = words { low: n.low, high: n.high & (d.high - 1), @@ -222,7 +222,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // D > N if sr > u32_bits - 2 { - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = n.u64(); } return 0; @@ -245,7 +245,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // --- // 0 K if d.low.is_power_of_two() { - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = u64::from(n.low & (d.low - 1)); } @@ -298,7 +298,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // D > N if sr > u32_bits - 1 { - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = a; return 0; } @@ -347,16 +347,16 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { } *q.all() = (q.u64() << 1) | carry as u64; - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = r.u64(); } q.u64() } #[no_mangle] -pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: *mut u32) -> u32 { +pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 { let d = __udivsi3(a, b); - if let Some(rem) = unsafe {rem.as_mut()} { + if let Some(rem) = rem { *rem = a - (d*b); } return d; diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs index 40e2885fba7..62cf59ce5a0 100644 --- a/library/compiler-builtins/src/test.rs +++ b/library/compiler-builtins/src/test.rs @@ -36,7 +36,7 @@ quickcheck! { TestResult::discard() } else { let mut r = 0; - let q = ::__udivmoddi4(a, b, &mut r); + let q = ::__udivmoddi4(a, b, Some(&mut r)); TestResult::from_bool(q * b + r == a) } @@ -49,7 +49,7 @@ quickcheck! { TestResult::discard() } else { let mut r = 0; - let q = ::__udivmodsi4(a, b, &mut r); + let q = ::__udivmodsi4(a, b, Some(&mut r)); TestResult::from_bool(q * b + r == a) } -- cgit 1.4.1-3-g733a5 From 6be47a352480d34266926b7c32c470f2721d3107 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 00:33:27 -0500 Subject: move return into if branches --- library/compiler-builtins/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index d2dcbdc2ac1..581189f3e38 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -141,7 +141,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 { // NOTE X is unknown, K != 0 if n.high == 0 { - return if d.high == 0 { + if d.high == 0 { // 0 X // --- // 0 X @@ -149,7 +149,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 { if let Some(rem) = rem { *rem = u64::from(n.low % d.low); } - u64::from(n.low / d.low) + return u64::from(n.low / d.low); } else // d.high != 0 { @@ -160,7 +160,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 { if let Some(rem) = rem { *rem = u64::from(n.low); } - 0 + return 0; }; } -- cgit 1.4.1-3-g733a5 From d66ff75198290c3a7318f881ab342dfb82b74292 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 00:36:19 -0500 Subject: note about calling convention --- library/compiler-builtins/src/arm.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index bcfc6c86eb5..51206eda47e 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,5 +1,7 @@ use core::intrinsics; +// NOTE This function and the one below are implemented using assembly because they using a custom +// calling convention which can't be implemented using a normal Rust function // TODO use `global_asm!` #[naked] #[no_mangle] -- cgit 1.4.1-3-g733a5 From 24344f1dcae9a7fcd2db9dce323993786e0544f3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 01:15:51 -0500 Subject: refactor: use Int traits, words -> U64, fmt --- library/compiler-builtins/src/lib.rs | 220 +++++++++++++++++------------------ 1 file changed, 109 insertions(+), 111 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 581189f3e38..527f4442446 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -18,8 +18,6 @@ pub mod arm; #[cfg(test)] mod test; -use core::mem; - /// Trait for some basic operations on integers trait Int { fn bits() -> usize; @@ -27,16 +25,24 @@ trait Int { // TODO: Once i128/u128 support lands, we'll want to add impls for those as well impl Int for u32 { - fn bits() -> usize { 32 } + fn bits() -> usize { + 32 + } } impl Int for i32 { - fn bits() -> usize { 32 } + fn bits() -> usize { + 32 + } } impl Int for u64 { - fn bits() -> usize { 64 } + fn bits() -> usize { + 64 + } } impl Int for i64 { - fn bits() -> usize { 64 } + fn bits() -> usize { + 64 + } } /// Trait to convert an integer to/from smaller parts @@ -99,131 +105,124 @@ absv_i2!(__absvdi2: i64); // TODO(rust-lang/35118)? // absv_i2!(__absvti2, i128); +/// Return `n / d` and `*rem = n % d` #[no_mangle] -pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 { +pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { + use core::ops::{Index, IndexMut, RangeFull}; + #[cfg(target_endian = "little")] #[repr(C)] - #[derive(Debug)] - struct words { + struct U64 { low: u32, high: u32, } #[cfg(target_endian = "big")] #[repr(C)] - #[derive(Debug)] - struct words { + struct U64 { high: u32, low: u32, } - impl words { - fn all(&mut self) -> &mut u64 { - unsafe { mem::transmute(self) } - } + impl Index for U64 { + type Output = u64; - fn u64(&self) -> u64 { - unsafe { *(self as *const _ as *const u64) } + fn index(&self, _: RangeFull) -> &u64 { + unsafe { &*(self as *const _ as *const u64) } } } - impl From for words { - fn from(x: u64) -> words { - unsafe { mem::transmute(x) } + impl IndexMut for U64 { + fn index_mut(&mut self, _: RangeFull) -> &mut u64 { + unsafe { &mut *(self as *const _ as *mut u64) } } } let u32_bits = u32::bits() as u32; let u64_bits = u64::bits() as u32; - let n = words::from(a); - let d = words::from(b); - // NOTE X is unknown, K != 0 - if n.high == 0 { - if d.high == 0 { + if n.high() == 0 { + if d.high() == 0 { // 0 X // --- // 0 X if let Some(rem) = rem { - *rem = u64::from(n.low % d.low); + *rem = u64::from(n.low() % d.low()); } - return u64::from(n.low / d.low); + return u64::from(n.low() / d.low()); } else - // d.high != 0 - { + // d.high() != 0 + { // 0 X // --- // K X if let Some(rem) = rem { - *rem = u64::from(n.low); + *rem = u64::from(n.low()); } return 0; }; } let mut sr; - // NOTE IMO it should be possible to leave these "uninitialized" (just declare them here) - // because these variables get initialized below, but if I do that the compiler complains about - // them being used before being initialized. - let mut q = words { low: 0, high: 0 }; - let mut r = words { low: 0, high: 0 }; - - // n.high != 0 - if d.low == 0 { - if d.high == 0 { + let mut q = U64 { low: 0, high: 0 }; + let mut r = U64 { low: 0, high: 0 }; + + // n.high() != 0 + if d.low() == 0 { + if d.high() == 0 { // K X // --- // 0 0 - // NOTE copied verbatim from compiler-rt, but does division by zero even make sense? + // NOTE copied verbatim from compiler-rt. This probably lets the intrinsic decide how to + // handle the division by zero (SIGFPE, 0, etc.). But this part shouldn't be reachable + // from safe code. if let Some(rem) = rem { - *rem = u64::from(n.high % d.low); + *rem = u64::from(n.high() % d.low()); } - return u64::from(n.high / d.low); + return u64::from(n.high() / d.low()); } - // d.high != 0 - if n.low == 0 { + // d.high() != 0 + if n.low() == 0 { // K 0 // --- // K 0 if let Some(rem) = rem { - *rem = words { - low: 0, - high: n.high % d.high, - } - .u64(); + *rem = U64 { + low: 0, + high: n.high() % d.high(), + }[..]; } - return u64::from(n.high / d.high); + return u64::from(n.high() / d.high()); } - // n.low != 0 + // n.low() != 0 // K K // --- // K 0 - if d.high.is_power_of_two() { + if d.high().is_power_of_two() { if let Some(rem) = rem { - *rem = words { - low: n.low, - high: n.high & (d.high - 1), - } - .u64() + *rem = U64 { + low: n.low(), + high: n.high() & (d.high() - 1), + }[..]; } - return u64::from(n.high >> d.high.trailing_zeros()); + return u64::from(n.high() >> d.high().trailing_zeros()); } - sr = d.high.leading_zeros().wrapping_sub(n.high.leading_zeros()); + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); // D > N if sr > u32_bits - 2 { if let Some(rem) = rem { - *rem = n.u64(); + *rem = n; } return 0; } @@ -231,75 +230,74 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 { sr = sr + 1; // 1 <= sr <= u32_bits - 1 - // *q.all() = n.u64() << (u64_bits - sr); + // q = n << (u64_bits - sr); q.low = 0; - q.high = n.low << (u32_bits - sr); - // *r.all() = n.u64() >> sr - r.high = n.high >> sr; - r.low = (n.high << (u32_bits - sr)) | (n.low >> sr); + q.high = n.low() << (u32_bits - sr); + // r = n >> sr + r.high = n.high() >> sr; + r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); } else - // d.low != 0 + // d.low() != 0 { - if d.high == 0 { + if d.high() == 0 { // K X // --- // 0 K - if d.low.is_power_of_two() { + if d.low().is_power_of_two() { if let Some(rem) = rem { - *rem = u64::from(n.low & (d.low - 1)); + *rem = u64::from(n.low() & (d.low() - 1)); } - return if d.low == 1 { - n.u64() + if d.low() == 1 { + return n; } else { - let sr = d.low.trailing_zeros(); - words { - low: (n.high << (u32_bits - sr)) | (n.low >> sr), - high: n.high >> sr, - } - .u64() + let sr = d.low().trailing_zeros(); + return U64 { + low: (n.high() << (u32_bits - sr)) | (n.low() >> sr), + high: n.high() >> sr, + }[..]; }; } - sr = 1 + u32_bits + d.low.leading_zeros() - n.high.leading_zeros(); + sr = 1 + u32_bits + d.low().leading_zeros() - n.high().leading_zeros(); // 2 <= sr <= u64_bits - 1 - // *q.all() = n.u64() << (u64_bits - sr) - // *r.all() = n.u64() >> sr; + // q = n << (u64_bits - sr) + // r = n >> sr; if sr == u32_bits { q.low = 0; - q.high = n.low; + q.high = n.low(); r.high = 0; - r.low = n.high; + r.low = n.high(); } else if sr < u32_bits // 2 <= sr <= u32_bits - 1 { q.low = 0; - q.high = n.low << (u32_bits - sr); - r.high = n.high >> sr; - r.low = (n.high << (u32_bits - sr)) | (n.low >> sr); + q.high = n.low() << (u32_bits - sr); + r.high = n.high() >> sr; + r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); } else // u32_bits + 1 <= sr <= u64_bits - 1 { - q.low = n.low << (u64_bits - sr); - q.high = (n.high << (u64_bits - sr)) | (n.low >> (sr - u32_bits)); + q.low = n.low() << (u64_bits - sr); + q.high = (n.high() << (u64_bits - sr)) | (n.low() >> (sr - u32_bits)); r.high = 0; - r.low = n.high >> (sr - u32_bits); + r.low = n.high() >> (sr - u32_bits); } } else - // d.high != 0 + // d.high() != 0 { // K X // --- // K K - sr = d.high.leading_zeros().wrapping_sub(n.high.leading_zeros()); + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); // D > N if sr > u32_bits - 1 { if let Some(rem) = rem { - *rem = a; + *rem = n; return 0; } } @@ -307,61 +305,61 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 { sr += 1; // 1 <= sr <= u32_bits - // *q.all() = n.u64() << (u64_bits - sr) + // q = n << (u64_bits - sr) q.low = 0; if sr == u32_bits { - q.high = n.low; + q.high = n.low(); r.high = 0; - r.low = n.high; + r.low = n.high(); } else { - q.high = n.low << (u32_bits - sr); - r.high = n.high >> sr; - r.low = (n.high << (u32_bits - sr)) | (n.low >> sr); + q.high = n.low() << (u32_bits - sr); + r.high = n.high() >> sr; + r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); } } } // Not a special case // q and r are initialized with - // *q.all() = n.u64() << (u64_bits - sr) - // *.r.all() = n.u64() >> sr + // q = n << (u64_bits - sr) + // r = n >> sr // 1 <= sr <= u64_bits - 1 let mut carry = 0; for _ in 0..sr { // r:q = ((r:q) << 1) | carry - r.high = (r.high << 1) | (r.low >> (u32_bits - 1)); - r.low = (r.low << 1) | (q.high >> (u32_bits - 1)); - q.high = (q.high << 1) | (q.low >> (u32_bits - 1)); - q.low = (q.low << 1) | carry; + r[..] = (r[..] << 1) | (q[..] >> 63); + q[..] = (q[..] << 1) | carry as u64; // carry = 0 - // if r.u64() >= d.u64() { - // *r.all() -= d.u64(); + // if r >= d { + // r -= d; // carry = 1; // } - let s = (d.u64().wrapping_sub(r.u64()).wrapping_sub(1)) as i64 >> (u64_bits - 1); + let s = (d.wrapping_sub(r[..]).wrapping_sub(1)) as i64 >> (u64_bits - 1); carry = (s & 1) as u32; - *r.all() -= d.u64() & s as u64; + r[..] -= d & s as u64; } - *q.all() = (q.u64() << 1) | carry as u64; + q[..] = (q[..] << 1) | carry as u64; if let Some(rem) = rem { - *rem = r.u64(); + *rem = r[..]; } - q.u64() + q[..] } +/// Return `n / d` and `*rem = n % d` #[no_mangle] pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 { let d = __udivsi3(a, b); if let Some(rem) = rem { - *rem = a - (d*b); + *rem = a - (d * b); } return d; } +/// Return `n / d` #[no_mangle] pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { let u32_bits = u32::bits() as u32; -- cgit 1.4.1-3-g733a5 From bcd525fe6181f4ad1f925a4952be24acf69d0424 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 01:26:27 -0500 Subject: put div intrinsics in their own module + some docs --- library/compiler-builtins/src/div.rs | 278 +++++++++++++++++++++++++++ library/compiler-builtins/src/lib.rs | 341 ++++------------------------------ library/compiler-builtins/src/test.rs | 4 +- 3 files changed, 314 insertions(+), 309 deletions(-) create mode 100644 library/compiler-builtins/src/div.rs diff --git a/library/compiler-builtins/src/div.rs b/library/compiler-builtins/src/div.rs new file mode 100644 index 00000000000..cb6568e9de1 --- /dev/null +++ b/library/compiler-builtins/src/div.rs @@ -0,0 +1,278 @@ +use {Int, LargeInt, U64}; + +/// Returns `n / d` +#[no_mangle] +pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { + let u32_bits = u32::bits() as u32; + + // Special cases + if d == 0 { + return 0; // ?! + } + + if n == 0 { + return 0; + } + + let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); + + // d > n + if sr > u32_bits - 1 { + return 0; + } + + // d == 1 + if sr == u32_bits - 1 { + return n; + } + + sr = sr + 1; + + // 1 <= sr <= u32_bits - 1 + let mut q = n << (u32_bits - sr); + let mut r = n >> sr; + + let mut carry = 0; + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (u32_bits - 1)); + q = (q << 1) | carry; + + // carry = 0; + // if r > d { + // r -= d; + // carry = 1; + // } + + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32_bits - 1); + carry = (s & 1) as u32; + r -= d & s as u32; + } + + q = (q << 1) | carry; + q +} + +/// Returns `n / d` and sets `*rem = n % d` +#[no_mangle] +pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 { + let d = __udivsi3(a, b); + if let Some(rem) = rem { + *rem = a - (d * b); + } + return d; +} + +/// Returns `n / d` and sets `*rem = n % d` +#[no_mangle] +pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { + let u32_bits = u32::bits() as u32; + let u64_bits = u64::bits() as u32; + + // NOTE X is unknown, K != 0 + if n.high() == 0 { + if d.high() == 0 { + // 0 X + // --- + // 0 X + + if let Some(rem) = rem { + *rem = u64::from(n.low() % d.low()); + } + return u64::from(n.low() / d.low()); + } else + // d.high() != 0 + { + // 0 X + // --- + // K X + + if let Some(rem) = rem { + *rem = u64::from(n.low()); + } + return 0; + }; + } + + let mut sr; + let mut q = U64 { low: 0, high: 0 }; + let mut r = U64 { low: 0, high: 0 }; + + // n.high() != 0 + if d.low() == 0 { + if d.high() == 0 { + // K X + // --- + // 0 0 + + // NOTE copied verbatim from compiler-rt. This probably lets the intrinsic decide how to + // handle the division by zero (SIGFPE, 0, etc.). But this part shouldn't be reachable + // from safe code. + if let Some(rem) = rem { + *rem = u64::from(n.high() % d.low()); + } + return u64::from(n.high() / d.low()); + } + + // d.high() != 0 + if n.low() == 0 { + // K 0 + // --- + // K 0 + + if let Some(rem) = rem { + *rem = U64 { + low: 0, + high: n.high() % d.high(), + }[..]; + } + return u64::from(n.high() / d.high()); + } + + // n.low() != 0 + // K K + // --- + // K 0 + + if d.high().is_power_of_two() { + if let Some(rem) = rem { + *rem = U64 { + low: n.low(), + high: n.high() & (d.high() - 1), + }[..]; + } + + return u64::from(n.high() >> d.high().trailing_zeros()); + } + + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > u32_bits - 2 { + if let Some(rem) = rem { + *rem = n; + } + return 0; + } + + sr = sr + 1; + + // 1 <= sr <= u32_bits - 1 + // q = n << (u64_bits - sr); + q.low = 0; + q.high = n.low() << (u32_bits - sr); + // r = n >> sr + r.high = n.high() >> sr; + r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); + } else + // d.low() != 0 + { + if d.high() == 0 { + // K X + // --- + // 0 K + if d.low().is_power_of_two() { + if let Some(rem) = rem { + *rem = u64::from(n.low() & (d.low() - 1)); + } + + if d.low() == 1 { + return n; + } else { + let sr = d.low().trailing_zeros(); + return U64 { + low: (n.high() << (u32_bits - sr)) | (n.low() >> sr), + high: n.high() >> sr, + }[..]; + }; + } + + sr = 1 + u32_bits + d.low().leading_zeros() - n.high().leading_zeros(); + + // 2 <= sr <= u64_bits - 1 + // q = n << (u64_bits - sr) + // r = n >> sr; + if sr == u32_bits { + q.low = 0; + q.high = n.low(); + r.high = 0; + r.low = n.high(); + } else if sr < u32_bits + // 2 <= sr <= u32_bits - 1 + { + q.low = 0; + q.high = n.low() << (u32_bits - sr); + r.high = n.high() >> sr; + r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); + } else + // u32_bits + 1 <= sr <= u64_bits - 1 + { + q.low = n.low() << (u64_bits - sr); + q.high = (n.high() << (u64_bits - sr)) | (n.low() >> (sr - u32_bits)); + r.high = 0; + r.low = n.high() >> (sr - u32_bits); + } + + } else + // d.high() != 0 + { + // K X + // --- + // K K + + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > u32_bits - 1 { + if let Some(rem) = rem { + *rem = n; + return 0; + } + } + + sr += 1; + + // 1 <= sr <= u32_bits + // q = n << (u64_bits - sr) + q.low = 0; + if sr == u32_bits { + q.high = n.low(); + r.high = 0; + r.low = n.high(); + } else { + q.high = n.low() << (u32_bits - sr); + r.high = n.high() >> sr; + r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); + } + } + } + + // Not a special case + // q and r are initialized with + // q = n << (u64_bits - sr) + // r = n >> sr + // 1 <= sr <= u64_bits - 1 + let mut carry = 0; + + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r[..] = (r[..] << 1) | (q[..] >> 63); + q[..] = (q[..] << 1) | carry as u64; + + // carry = 0 + // if r >= d { + // r -= d; + // carry = 1; + // } + + let s = (d.wrapping_sub(r[..]).wrapping_sub(1)) as i64 >> (u64_bits - 1); + carry = (s & 1) as u32; + r[..] -= d & s as u64; + } + + q[..] = (q[..] << 1) | carry as u64; + if let Some(rem) = rem { + *rem = r[..]; + } + q[..] +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 527f4442446..3a24025b67c 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -15,9 +15,13 @@ extern crate quickcheck; #[cfg(target_arch = "arm")] pub mod arm; +pub mod div; + #[cfg(test)] mod test; +use core::ops::{Index, IndexMut, RangeFull}; + /// Trait for some basic operations on integers trait Int { fn bits() -> usize; @@ -85,6 +89,36 @@ impl LargeInt for i64 { } } +/// Union-like access to the 32-bit words that make an `u64`: `x.low` and `x.high`. The whole `u64` +/// can be accessed via the expression `x[..]`, which can be used in lvalue or rvalue position. +#[cfg(target_endian = "little")] +#[repr(C)] +struct U64 { + low: u32, + high: u32, +} + +#[cfg(target_endian = "big")] +#[repr(C)] +struct U64 { + high: u32, + low: u32, +} + +impl Index for U64 { + type Output = u64; + + fn index(&self, _: RangeFull) -> &u64 { + unsafe { &*(self as *const _ as *const u64) } + } +} + +impl IndexMut for U64 { + fn index_mut(&mut self, _: RangeFull) -> &mut u64 { + unsafe { &mut *(self as *const _ as *mut u64) } + } +} + macro_rules! absv_i2 { ($intrinsic:ident : $ty:ty) => { #[no_mangle] @@ -104,310 +138,3 @@ absv_i2!(__absvsi2: i32); absv_i2!(__absvdi2: i64); // TODO(rust-lang/35118)? // absv_i2!(__absvti2, i128); - -/// Return `n / d` and `*rem = n % d` -#[no_mangle] -pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { - use core::ops::{Index, IndexMut, RangeFull}; - - #[cfg(target_endian = "little")] - #[repr(C)] - struct U64 { - low: u32, - high: u32, - } - - #[cfg(target_endian = "big")] - #[repr(C)] - struct U64 { - high: u32, - low: u32, - } - - impl Index for U64 { - type Output = u64; - - fn index(&self, _: RangeFull) -> &u64 { - unsafe { &*(self as *const _ as *const u64) } - } - } - - impl IndexMut for U64 { - fn index_mut(&mut self, _: RangeFull) -> &mut u64 { - unsafe { &mut *(self as *const _ as *mut u64) } - } - } - - let u32_bits = u32::bits() as u32; - let u64_bits = u64::bits() as u32; - - // NOTE X is unknown, K != 0 - if n.high() == 0 { - if d.high() == 0 { - // 0 X - // --- - // 0 X - - if let Some(rem) = rem { - *rem = u64::from(n.low() % d.low()); - } - return u64::from(n.low() / d.low()); - } else - // d.high() != 0 - { - // 0 X - // --- - // K X - - if let Some(rem) = rem { - *rem = u64::from(n.low()); - } - return 0; - }; - } - - let mut sr; - let mut q = U64 { low: 0, high: 0 }; - let mut r = U64 { low: 0, high: 0 }; - - // n.high() != 0 - if d.low() == 0 { - if d.high() == 0 { - // K X - // --- - // 0 0 - - // NOTE copied verbatim from compiler-rt. This probably lets the intrinsic decide how to - // handle the division by zero (SIGFPE, 0, etc.). But this part shouldn't be reachable - // from safe code. - if let Some(rem) = rem { - *rem = u64::from(n.high() % d.low()); - } - return u64::from(n.high() / d.low()); - } - - // d.high() != 0 - if n.low() == 0 { - // K 0 - // --- - // K 0 - - if let Some(rem) = rem { - *rem = U64 { - low: 0, - high: n.high() % d.high(), - }[..]; - } - return u64::from(n.high() / d.high()); - } - - // n.low() != 0 - // K K - // --- - // K 0 - - if d.high().is_power_of_two() { - if let Some(rem) = rem { - *rem = U64 { - low: n.low(), - high: n.high() & (d.high() - 1), - }[..]; - } - - return u64::from(n.high() >> d.high().trailing_zeros()); - } - - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > u32_bits - 2 { - if let Some(rem) = rem { - *rem = n; - } - return 0; - } - - sr = sr + 1; - - // 1 <= sr <= u32_bits - 1 - // q = n << (u64_bits - sr); - q.low = 0; - q.high = n.low() << (u32_bits - sr); - // r = n >> sr - r.high = n.high() >> sr; - r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); - } else - // d.low() != 0 - { - if d.high() == 0 { - // K X - // --- - // 0 K - if d.low().is_power_of_two() { - if let Some(rem) = rem { - *rem = u64::from(n.low() & (d.low() - 1)); - } - - if d.low() == 1 { - return n; - } else { - let sr = d.low().trailing_zeros(); - return U64 { - low: (n.high() << (u32_bits - sr)) | (n.low() >> sr), - high: n.high() >> sr, - }[..]; - }; - } - - sr = 1 + u32_bits + d.low().leading_zeros() - n.high().leading_zeros(); - - // 2 <= sr <= u64_bits - 1 - // q = n << (u64_bits - sr) - // r = n >> sr; - if sr == u32_bits { - q.low = 0; - q.high = n.low(); - r.high = 0; - r.low = n.high(); - } else if sr < u32_bits - // 2 <= sr <= u32_bits - 1 - { - q.low = 0; - q.high = n.low() << (u32_bits - sr); - r.high = n.high() >> sr; - r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); - } else - // u32_bits + 1 <= sr <= u64_bits - 1 - { - q.low = n.low() << (u64_bits - sr); - q.high = (n.high() << (u64_bits - sr)) | (n.low() >> (sr - u32_bits)); - r.high = 0; - r.low = n.high() >> (sr - u32_bits); - } - - } else - // d.high() != 0 - { - // K X - // --- - // K K - - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > u32_bits - 1 { - if let Some(rem) = rem { - *rem = n; - return 0; - } - } - - sr += 1; - - // 1 <= sr <= u32_bits - // q = n << (u64_bits - sr) - q.low = 0; - if sr == u32_bits { - q.high = n.low(); - r.high = 0; - r.low = n.high(); - } else { - q.high = n.low() << (u32_bits - sr); - r.high = n.high() >> sr; - r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); - } - } - } - - // Not a special case - // q and r are initialized with - // q = n << (u64_bits - sr) - // r = n >> sr - // 1 <= sr <= u64_bits - 1 - let mut carry = 0; - - for _ in 0..sr { - // r:q = ((r:q) << 1) | carry - r[..] = (r[..] << 1) | (q[..] >> 63); - q[..] = (q[..] << 1) | carry as u64; - - // carry = 0 - // if r >= d { - // r -= d; - // carry = 1; - // } - - let s = (d.wrapping_sub(r[..]).wrapping_sub(1)) as i64 >> (u64_bits - 1); - carry = (s & 1) as u32; - r[..] -= d & s as u64; - } - - q[..] = (q[..] << 1) | carry as u64; - if let Some(rem) = rem { - *rem = r[..]; - } - q[..] -} - -/// Return `n / d` and `*rem = n % d` -#[no_mangle] -pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 { - let d = __udivsi3(a, b); - if let Some(rem) = rem { - *rem = a - (d * b); - } - return d; -} - -/// Return `n / d` -#[no_mangle] -pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { - let u32_bits = u32::bits() as u32; - - // Special cases - if d == 0 { - return 0; // ?! - } - - if n == 0 { - return 0; - } - - let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); - - // d > n - if sr > u32_bits - 1 { - return 0; - } - - // d == 1 - if sr == u32_bits - 1 { - return n; - } - - sr = sr + 1; - - // 1 <= sr <= u32_bits - 1 - let mut q = n << (u32_bits - sr); - let mut r = n >> sr; - - let mut carry = 0; - for _ in 0..sr { - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (u32_bits - 1)); - q = (q << 1) | carry; - - // carry = 0; - // if r > d { - // r -= d; - // carry = 1; - // } - - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32_bits - 1); - carry = (s & 1) as u32; - r -= d & s as u32; - } - - q = (q << 1) | carry; - q -} diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs index 62cf59ce5a0..f1fa4f331ff 100644 --- a/library/compiler-builtins/src/test.rs +++ b/library/compiler-builtins/src/test.rs @@ -36,7 +36,7 @@ quickcheck! { TestResult::discard() } else { let mut r = 0; - let q = ::__udivmoddi4(a, b, Some(&mut r)); + let q = ::div::__udivmoddi4(a, b, Some(&mut r)); TestResult::from_bool(q * b + r == a) } @@ -49,7 +49,7 @@ quickcheck! { TestResult::discard() } else { let mut r = 0; - let q = ::__udivmodsi4(a, b, Some(&mut r)); + let q = ::div::__udivmodsi4(a, b, Some(&mut r)); TestResult::from_bool(q * b + r == a) } -- cgit 1.4.1-3-g733a5 From 01a8a996b5c477466657ba0ac1bc6ae07eaaca4d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 01:42:34 -0500 Subject: don't transmute in test --- library/compiler-builtins/src/test.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs index f1fa4f331ff..fa8691c8f68 100644 --- a/library/compiler-builtins/src/test.rs +++ b/library/compiler-builtins/src/test.rs @@ -1,4 +1,4 @@ -use std::{mem, panic}; +use std::panic; use quickcheck::TestResult; @@ -27,31 +27,30 @@ absv_i2!(__absvdi2: i64); // absv_i2!(__absvti2: i128); quickcheck! { - fn udivmoddi4(a: (u32, u32), b: (u32, u32)) -> TestResult { - let (a, b) = unsafe { - (mem::transmute(a), mem::transmute(b)) - }; + fn udivmoddi4(n: (u32, u32), d: (u32, u32)) -> TestResult { + let n = ::U64 { low: n.0, high: n.1 }[..]; + let d = ::U64 { low: d.0, high: d.1 }[..]; - if b == 0 { + if d == 0 { TestResult::discard() } else { let mut r = 0; - let q = ::div::__udivmoddi4(a, b, Some(&mut r)); + let q = ::div::__udivmoddi4(n, d, Some(&mut r)); - TestResult::from_bool(q * b + r == a) + TestResult::from_bool(q * d + r == n) } } } quickcheck! { - fn udivmodsi4(a: u32, b: u32) -> TestResult { - if b == 0 { + fn udivmodsi4(n: u32, d: u32) -> TestResult { + if d == 0 { TestResult::discard() } else { let mut r = 0; - let q = ::div::__udivmodsi4(a, b, Some(&mut r)); + let q = ::div::__udivmodsi4(n, d, Some(&mut r)); - TestResult::from_bool(q * b + r == a) + TestResult::from_bool(q * d + r == n) } } } -- cgit 1.4.1-3-g733a5 From 57a3f411dded66bdccfcc9190713167a33f79f80 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 01:45:48 -0500 Subject: address second row of review --- library/compiler-builtins/src/div.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/src/div.rs b/library/compiler-builtins/src/div.rs index cb6568e9de1..44d59b70cf9 100644 --- a/library/compiler-builtins/src/div.rs +++ b/library/compiler-builtins/src/div.rs @@ -7,7 +7,7 @@ pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { // Special cases if d == 0 { - return 0; // ?! + panic!("Division by zero"); } if n == 0 { @@ -49,8 +49,7 @@ pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { r -= d & s as u32; } - q = (q << 1) | carry; - q + (q << 1) | carry } /// Returns `n / d` and sets `*rem = n % d` @@ -105,13 +104,7 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { // --- // 0 0 - // NOTE copied verbatim from compiler-rt. This probably lets the intrinsic decide how to - // handle the division by zero (SIGFPE, 0, etc.). But this part shouldn't be reachable - // from safe code. - if let Some(rem) = rem { - *rem = u64::from(n.high() % d.low()); - } - return u64::from(n.high() / d.low()); + panic!("Division by zero"); } // d.high() != 0 -- cgit 1.4.1-3-g733a5 From 25b25d5e8e044e89fcb661ce445e4292873865b5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 01:52:48 -0500 Subject: appveyor: inspect binaries --- library/compiler-builtins/appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index d27883dc901..06255fa1d43 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -17,6 +17,8 @@ test_script: - cargo build --release - cargo test - cargo test --release + - dumpbin /disasm target/debug/librustc_builtins.rlib + - dumpbin /disasm target/release/librustc_builtins.rlib branches: only: -- cgit 1.4.1-3-g733a5 From f22f7cdd865c6f046c66a466eec438548dc4bb52 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 02:12:01 -0500 Subject: README: cross out a few intrinsics for the TODO list --- library/compiler-builtins/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index c68882985aa..32f85cdb206 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -32,8 +32,8 @@ See [rust-lang/rust#35437][0]. - [ ] arm/addsf3vfp.S - [ ] arm/aeabi_dcmp.S - [ ] arm/aeabi_fcmp.S -- [ ] arm/aeabi_idivmod.S -- [ ] arm/aeabi_ldivmod.S +- [x] arm/aeabi_idivmod.S +- [x] arm/aeabi_ldivmod.S - [x] arm/aeabi_memcpy.S - [x] arm/aeabi_memmove.S - [x] arm/aeabi_memset.S @@ -143,6 +143,8 @@ See [rust-lang/rust#35437][0]. - [ ] truncdfsf2.c - [ ] truncsfhf2.c - [ ] udivdi3.c +- [x] udivmoddi4.c +- [x] udivmodsi4.c - [ ] udivsi3.c - [ ] udivti3.c - [ ] umoddi3.c @@ -272,8 +274,6 @@ These builtins are never called by LLVM. - ~~subvti3.c~~ - ~~ucmpdi2.c~~ - ~~ucmpti2.c~~ -- ~~udivmoddi4.c~~ -- ~~udivmodsi4.c~~ - ~~udivmodti4.c~~ Rust only exposes atomic types on platforms that support them, and therefore does not need to fall back to software implementations. -- cgit 1.4.1-3-g733a5 From 07afa89f10205ea0db16a1752936ba1488b70eca Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 11 Aug 2016 08:18:06 +0100 Subject: Remove the absv implementation, it isn't needed by Rust --- library/compiler-builtins/src/lib.rs | 20 -------------------- library/compiler-builtins/src/test.rs | 24 ------------------------ 2 files changed, 44 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3a24025b67c..196f37c338f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -118,23 +118,3 @@ impl IndexMut for U64 { unsafe { &mut *(self as *const _ as *mut u64) } } } - -macro_rules! absv_i2 { - ($intrinsic:ident : $ty:ty) => { - #[no_mangle] - pub extern "C" fn $intrinsic(x: $ty) -> $ty { - let n = <$ty>::bits(); - if x == 1 << (n - 1) { - panic!(); - } - let y = x >> (n - 1); - (x ^ y) - y - } - - } -} - -absv_i2!(__absvsi2: i32); -absv_i2!(__absvdi2: i64); -// TODO(rust-lang/35118)? -// absv_i2!(__absvti2, i128); diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs index fa8691c8f68..96e0c12738b 100644 --- a/library/compiler-builtins/src/test.rs +++ b/library/compiler-builtins/src/test.rs @@ -2,30 +2,6 @@ use std::panic; use quickcheck::TestResult; -macro_rules! absv_i2 { - ($intrinsic:ident: $ty:ident) => { - #[test] - fn $intrinsic() { - assert!(panic::catch_unwind(|| ::$intrinsic(::std::$ty::MIN)).is_err()); - assert_eq!(::$intrinsic(::std::$ty::MIN + 1), ::std::$ty::MAX); - assert_eq!(::$intrinsic(::std::$ty::MIN + 2), ::std::$ty::MAX - 1); - assert_eq!(::$intrinsic(-1), 1); - assert_eq!(::$intrinsic(-2), 2); - assert_eq!(::$intrinsic(0), 0); - assert_eq!(::$intrinsic(1), 1); - assert_eq!(::$intrinsic(2), 2); - assert_eq!(::$intrinsic(2), 2); - assert_eq!(::$intrinsic(::std::$ty::MAX - 1), ::std::$ty::MAX - 1); - assert_eq!(::$intrinsic(::std::$ty::MAX), ::std::$ty::MAX); - } - } -} - -absv_i2!(__absvsi2: i32); -absv_i2!(__absvdi2: i64); -// TODO(rust-lang/35118)? -// absv_i2!(__absvti2: i128); - quickcheck! { fn udivmoddi4(n: (u32, u32), d: (u32, u32)) -> TestResult { let n = ::U64 { low: n.0, high: n.1 }[..]; -- cgit 1.4.1-3-g733a5 From 1a60c3d52f314f2c984d238c993318005eee12a0 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 13 Aug 2016 09:51:54 +0100 Subject: Various changes --- library/compiler-builtins/README.md | 62 +++---- library/compiler-builtins/src/arm.rs | 87 +++++----- library/compiler-builtins/src/div.rs | 271 ------------------------------ library/compiler-builtins/src/lib.rs | 56 ++----- library/compiler-builtins/src/mul.rs | 99 +++++++++++ library/compiler-builtins/src/shift.rs | 93 +++++++++++ library/compiler-builtins/src/test.rs | 32 ---- library/compiler-builtins/src/udiv.rs | 290 +++++++++++++++++++++++++++++++++ 8 files changed, 568 insertions(+), 422 deletions(-) delete mode 100644 library/compiler-builtins/src/div.rs create mode 100644 library/compiler-builtins/src/mul.rs create mode 100644 library/compiler-builtins/src/shift.rs delete mode 100644 library/compiler-builtins/src/test.rs create mode 100644 library/compiler-builtins/src/udiv.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 32f85cdb206..73a25e9d7dc 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -37,8 +37,8 @@ See [rust-lang/rust#35437][0]. - [x] arm/aeabi_memcpy.S - [x] arm/aeabi_memmove.S - [x] arm/aeabi_memset.S -- [ ] arm/aeabi_uidivmod.S -- [ ] arm/aeabi_uldivmod.S +- [x] arm/aeabi_uidivmod.S +- [x] arm/aeabi_uldivmod.S - [ ] arm/divdf3vfp.S - [ ] arm/divmodsi4.S - [ ] arm/divsf3vfp.S @@ -78,41 +78,30 @@ See [rust-lang/rust#35437][0]. - [ ] arm/umodsi3.S - [ ] arm/unorddf2vfp.S - [ ] arm/unordsf2vfp.S -- [ ] ashldi3.c -- [ ] ashlti3.c -- [ ] ashrdi3.c -- [ ] ashrti3.c +- [x] ashldi3.c +- [x] ashrdi3.c - [ ] divdf3.c - [ ] divdi3.c - [ ] divsf3.c - [ ] divsi3.c -- [ ] divti3.c - [ ] extendhfsf2.c - [ ] extendsfdf2.c - [ ] fixdfdi.c - [ ] fixdfsi.c -- [ ] fixdfti.c - [ ] fixsfdi.c - [ ] fixsfsi.c -- [ ] fixsfti.c - [ ] fixunsdfdi.c - [ ] fixunsdfsi.c -- [ ] fixunsdfti.c - [ ] fixunssfdi.c - [ ] fixunssfsi.c -- [ ] fixunssfti.c - [ ] floatdidf.c - [ ] floatdisf.c - [ ] floatsidf.c - [ ] floatsisf.c -- [ ] floattidf.c -- [ ] floattisf.c - [ ] floatundidf.c - [ ] floatundisf.c - [ ] floatunsidf.c - [ ] floatunsisf.c -- [ ] floatuntidf.c -- [ ] floatuntisf.c - [ ] i386/ashldi3.S - [ ] i386/ashrdi3.S - [ ] i386/chkstk.S @@ -123,18 +112,14 @@ See [rust-lang/rust#35437][0]. - [ ] i386/muldi3.S - [ ] i386/udivdi3.S - [ ] i386/umoddi3.S -- [ ] lshrdi3.c -- [ ] lshrti3.c +- [x] lshrdi3.c - [ ] moddi3.c - [ ] modsi3.c -- [ ] modti3.c - [ ] muldf3.c -- [ ] muldi3.c -- [ ] mulodi4.c -- [ ] mulosi4.c -- [ ] muloti4.c +- [x] muldi3.c +- [x] mulodi4.c +- [x] mulosi4.c - [ ] mulsf3.c -- [ ] multi3.c - [ ] powidf2.c - [ ] powisf2.c - [ ] subdf3.c @@ -142,17 +127,36 @@ See [rust-lang/rust#35437][0]. - [ ] truncdfhf2.c - [ ] truncdfsf2.c - [ ] truncsfhf2.c -- [ ] udivdi3.c +- [x] udivdi3.c - [x] udivmoddi4.c - [x] udivmodsi4.c -- [ ] udivsi3.c -- [ ] udivti3.c -- [ ] umoddi3.c -- [ ] umodsi3.c -- [ ] umodti3.c +- [x] udivsi3.c +- [x] umoddi3.c +- [x] umodsi3.c - [ ] x86_64/chkstk.S - [ ] x86_64/chkstk2.S +These builtins are needed to support 128-bit integers, which are in the process of being added to Rust. + +- [ ] ashlti3.c +- [ ] ashrti3.c +- [ ] divti3.c +- [ ] fixdfti.c +- [ ] fixsfti.c +- [ ] fixunsdfti.c +- [ ] fixunssfti.c +- [ ] floattidf.c +- [ ] floattisf.c +- [ ] floatuntidf.c +- [ ] floatuntisf.c +- [ ] lshrti3.c +- [ ] modti3.c +- [ ] muloti4.c +- [ ] multi3.c +- [ ] udivmodti4.c +- [ ] udivti3.c +- [ ] umodti3.c + ## Unimplemented functions These builtins involve floating-point types ("`f128`", "`f80`" and complex numbers) that are not supported by Rust. diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 51206eda47e..0759b55d4af 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -2,33 +2,28 @@ use core::intrinsics; // NOTE This function and the one below are implemented using assembly because they using a custom // calling convention which can't be implemented using a normal Rust function -// TODO use `global_asm!` #[naked] -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_uidivmod() { - asm!("push { lr } - sub sp, sp, #4 - mov r2, sp - bl __udivmodsi4 - ldr r1, [sp] - add sp, sp, #4 - pop { pc }"); +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn __aeabi_uidivmod() { + asm!("push {lr} + sub sp, sp, #4 + mov r2, sp + bl __udivmodsi4 + ldr r1, [sp], #4 + pop {pc}"); intrinsics::unreachable(); } -// TODO use `global_asm!` #[naked] -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_uldivmod() { - asm!("push {r11, lr} - sub sp, sp, #16 - add r12, sp, #8 - str r12, [sp] - bl __udivmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r11, pc}"); +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn __aeabi_uldivmod() { + asm!("push {lr} + sub r12, sp, #12 + str r12, [sp, #-20]! + bl __udivmoddi4 + ldrd r2, r3, [sp, #8] + add sp, sp, #20 + pop {pc}"); intrinsics::unreachable(); } @@ -40,55 +35,55 @@ extern "C" { // FIXME: The `*4` and `*8` variants should be defined as aliases. -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } // Note the different argument order -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memclr(dest: *mut u8, n: usize) { memset(dest, 0, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memclr4(dest: *mut u8, n: usize) { memset(dest, 0, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memclr8(dest: *mut u8, n: usize) { memset(dest, 0, n); } diff --git a/library/compiler-builtins/src/div.rs b/library/compiler-builtins/src/div.rs deleted file mode 100644 index 44d59b70cf9..00000000000 --- a/library/compiler-builtins/src/div.rs +++ /dev/null @@ -1,271 +0,0 @@ -use {Int, LargeInt, U64}; - -/// Returns `n / d` -#[no_mangle] -pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { - let u32_bits = u32::bits() as u32; - - // Special cases - if d == 0 { - panic!("Division by zero"); - } - - if n == 0 { - return 0; - } - - let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); - - // d > n - if sr > u32_bits - 1 { - return 0; - } - - // d == 1 - if sr == u32_bits - 1 { - return n; - } - - sr = sr + 1; - - // 1 <= sr <= u32_bits - 1 - let mut q = n << (u32_bits - sr); - let mut r = n >> sr; - - let mut carry = 0; - for _ in 0..sr { - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (u32_bits - 1)); - q = (q << 1) | carry; - - // carry = 0; - // if r > d { - // r -= d; - // carry = 1; - // } - - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32_bits - 1); - carry = (s & 1) as u32; - r -= d & s as u32; - } - - (q << 1) | carry -} - -/// Returns `n / d` and sets `*rem = n % d` -#[no_mangle] -pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 { - let d = __udivsi3(a, b); - if let Some(rem) = rem { - *rem = a - (d * b); - } - return d; -} - -/// Returns `n / d` and sets `*rem = n % d` -#[no_mangle] -pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { - let u32_bits = u32::bits() as u32; - let u64_bits = u64::bits() as u32; - - // NOTE X is unknown, K != 0 - if n.high() == 0 { - if d.high() == 0 { - // 0 X - // --- - // 0 X - - if let Some(rem) = rem { - *rem = u64::from(n.low() % d.low()); - } - return u64::from(n.low() / d.low()); - } else - // d.high() != 0 - { - // 0 X - // --- - // K X - - if let Some(rem) = rem { - *rem = u64::from(n.low()); - } - return 0; - }; - } - - let mut sr; - let mut q = U64 { low: 0, high: 0 }; - let mut r = U64 { low: 0, high: 0 }; - - // n.high() != 0 - if d.low() == 0 { - if d.high() == 0 { - // K X - // --- - // 0 0 - - panic!("Division by zero"); - } - - // d.high() != 0 - if n.low() == 0 { - // K 0 - // --- - // K 0 - - if let Some(rem) = rem { - *rem = U64 { - low: 0, - high: n.high() % d.high(), - }[..]; - } - return u64::from(n.high() / d.high()); - } - - // n.low() != 0 - // K K - // --- - // K 0 - - if d.high().is_power_of_two() { - if let Some(rem) = rem { - *rem = U64 { - low: n.low(), - high: n.high() & (d.high() - 1), - }[..]; - } - - return u64::from(n.high() >> d.high().trailing_zeros()); - } - - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > u32_bits - 2 { - if let Some(rem) = rem { - *rem = n; - } - return 0; - } - - sr = sr + 1; - - // 1 <= sr <= u32_bits - 1 - // q = n << (u64_bits - sr); - q.low = 0; - q.high = n.low() << (u32_bits - sr); - // r = n >> sr - r.high = n.high() >> sr; - r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); - } else - // d.low() != 0 - { - if d.high() == 0 { - // K X - // --- - // 0 K - if d.low().is_power_of_two() { - if let Some(rem) = rem { - *rem = u64::from(n.low() & (d.low() - 1)); - } - - if d.low() == 1 { - return n; - } else { - let sr = d.low().trailing_zeros(); - return U64 { - low: (n.high() << (u32_bits - sr)) | (n.low() >> sr), - high: n.high() >> sr, - }[..]; - }; - } - - sr = 1 + u32_bits + d.low().leading_zeros() - n.high().leading_zeros(); - - // 2 <= sr <= u64_bits - 1 - // q = n << (u64_bits - sr) - // r = n >> sr; - if sr == u32_bits { - q.low = 0; - q.high = n.low(); - r.high = 0; - r.low = n.high(); - } else if sr < u32_bits - // 2 <= sr <= u32_bits - 1 - { - q.low = 0; - q.high = n.low() << (u32_bits - sr); - r.high = n.high() >> sr; - r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); - } else - // u32_bits + 1 <= sr <= u64_bits - 1 - { - q.low = n.low() << (u64_bits - sr); - q.high = (n.high() << (u64_bits - sr)) | (n.low() >> (sr - u32_bits)); - r.high = 0; - r.low = n.high() >> (sr - u32_bits); - } - - } else - // d.high() != 0 - { - // K X - // --- - // K K - - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > u32_bits - 1 { - if let Some(rem) = rem { - *rem = n; - return 0; - } - } - - sr += 1; - - // 1 <= sr <= u32_bits - // q = n << (u64_bits - sr) - q.low = 0; - if sr == u32_bits { - q.high = n.low(); - r.high = 0; - r.low = n.high(); - } else { - q.high = n.low() << (u32_bits - sr); - r.high = n.high() >> sr; - r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); - } - } - } - - // Not a special case - // q and r are initialized with - // q = n << (u64_bits - sr) - // r = n >> sr - // 1 <= sr <= u64_bits - 1 - let mut carry = 0; - - for _ in 0..sr { - // r:q = ((r:q) << 1) | carry - r[..] = (r[..] << 1) | (q[..] >> 63); - q[..] = (q[..] << 1) | carry as u64; - - // carry = 0 - // if r >= d { - // r -= d; - // carry = 1; - // } - - let s = (d.wrapping_sub(r[..]).wrapping_sub(1)) as i64 >> (u64_bits - 1); - carry = (s & 1) as u32; - r[..] -= d & s as u64; - } - - q[..] = (q[..] << 1) | carry as u64; - if let Some(rem) = rem { - *rem = r[..]; - } - q[..] -} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 196f37c338f..6d5580b8e18 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,13 +1,14 @@ #![allow(unused_features)] -#![cfg_attr(not(test), no_std)] +#![no_std] #![feature(asm)] #![feature(core_intrinsics)] #![feature(naked_functions)] // TODO(rust-lang/rust#35021) uncomment when that PR lands // #![feature(rustc_builtins)] -#[cfg(test)] -extern crate core; +// We disable #[no_mangle] for tests so that we can verify the test results +// against the native compiler-rt implementations of the builtins. + #[cfg(test)] #[macro_use] extern crate quickcheck; @@ -15,36 +16,33 @@ extern crate quickcheck; #[cfg(target_arch = "arm")] pub mod arm; -pub mod div; - -#[cfg(test)] -mod test; - -use core::ops::{Index, IndexMut, RangeFull}; +pub mod udiv; +pub mod mul; +pub mod shift; /// Trait for some basic operations on integers trait Int { - fn bits() -> usize; + fn bits() -> u32; } // TODO: Once i128/u128 support lands, we'll want to add impls for those as well impl Int for u32 { - fn bits() -> usize { + fn bits() -> u32 { 32 } } impl Int for i32 { - fn bits() -> usize { + fn bits() -> u32 { 32 } } impl Int for u64 { - fn bits() -> usize { + fn bits() -> u32 { 64 } } impl Int for i64 { - fn bits() -> usize { + fn bits() -> u32 { 64 } } @@ -88,33 +86,3 @@ impl LargeInt for i64 { low as i64 | ((high as i64) << 32) } } - -/// Union-like access to the 32-bit words that make an `u64`: `x.low` and `x.high`. The whole `u64` -/// can be accessed via the expression `x[..]`, which can be used in lvalue or rvalue position. -#[cfg(target_endian = "little")] -#[repr(C)] -struct U64 { - low: u32, - high: u32, -} - -#[cfg(target_endian = "big")] -#[repr(C)] -struct U64 { - high: u32, - low: u32, -} - -impl Index for U64 { - type Output = u64; - - fn index(&self, _: RangeFull) -> &u64 { - unsafe { &*(self as *const _ as *const u64) } - } -} - -impl IndexMut for U64 { - fn index_mut(&mut self, _: RangeFull) -> &mut u64 { - unsafe { &mut *(self as *const _ as *mut u64) } - } -} diff --git a/library/compiler-builtins/src/mul.rs b/library/compiler-builtins/src/mul.rs new file mode 100644 index 00000000000..a4350b5f7ff --- /dev/null +++ b/library/compiler-builtins/src/mul.rs @@ -0,0 +1,99 @@ +use {Int, LargeInt}; + +macro_rules! mul { + ($intrinsic:ident: $ty:ty) => { + /// Returns `a * b` + #[cfg_attr(not(test), no_mangle)] + pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { + let half_bits = <$ty>::bits() / 4; + let lower_mask = !0 >> half_bits; + let mut low = (a.low() & lower_mask) * (b.low() & lower_mask); + let mut t = low >> half_bits; + low &= lower_mask; + t += (a.low() >> half_bits) * (b.low() & lower_mask); + low += (t & lower_mask) << half_bits; + let mut high = t >> half_bits; + t = low >> half_bits; + low &= lower_mask; + t += (b.low() >> half_bits) * (a.low() & lower_mask); + low += (t & lower_mask) << half_bits; + high += t >> half_bits; + high += (a.low() >> half_bits) * (b.low() >> half_bits); + high += a.high().wrapping_mul(b.low()) + a.low().wrapping_mul(b.high()); + <$ty>::from_parts(low, high) + } + } +} + +macro_rules! mulo { + ($intrinsic:ident: $ty:ty) => { + /// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows + #[cfg_attr(not(test), no_mangle)] + pub extern fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty { + *overflow = 0; + let result = a.wrapping_mul(b); + if a == <$ty>::min_value() { + if b != 0 && b != 1 { + *overflow = 1; + } + return result; + } + if b == <$ty>::min_value() { + if a != 0 && a != 1 { + *overflow = 1; + } + return result; + } + + let sa = a >> (<$ty>::bits() - 1); + let abs_a = (a ^ sa) - sa; + let sb = b >> (<$ty>::bits() - 1); + let abs_b = (b ^ sb) - sb; + if abs_a < 2 || abs_b < 2 { + return result; + } + if sa == sb { + if abs_a > <$ty>::max_value() / abs_b { + *overflow = 1; + } + } else { + if abs_a > <$ty>::min_value() / -abs_b { + *overflow = 1; + } + } + result + } + } +} + +mul!(__muldi4: u64); +mulo!(__mulosi4: i32); +mulo!(__mulodi4: i64); + +#[cfg(test)] +mod tests { + quickcheck! { + fn muldi(a: u64, b: u64) -> bool { + let r = super::__muldi4(a, b); + r == a.wrapping_mul(b) + } + + fn mulosi(a: i32, b: i32) -> bool { + let mut overflow = 2; + let r = super::__mulosi4(a, b, &mut overflow); + if overflow != 0 && overflow != 1 { + return false; + } + (r, overflow != 0) == a.overflowing_mul(b) + } + + fn mulodi(a: i64, b: i64) -> bool { + let mut overflow = 2; + let r = super::__mulodi4(a, b, &mut overflow); + if overflow != 0 && overflow != 1 { + return false; + } + (r, overflow != 0) == a.overflowing_mul(b) + } + } +} diff --git a/library/compiler-builtins/src/shift.rs b/library/compiler-builtins/src/shift.rs new file mode 100644 index 00000000000..909d6f47f5a --- /dev/null +++ b/library/compiler-builtins/src/shift.rs @@ -0,0 +1,93 @@ +use {Int, LargeInt}; + +macro_rules! ashl { + ($intrinsic:ident: $ty:ty) => { + /// Returns `a << b`, requires `b < $ty::bits()` + #[cfg_attr(not(test), no_mangle)] + pub extern fn $intrinsic(a: $ty, b: u32) -> $ty { + let half_bits = <$ty>::bits() / 2; + if b & half_bits != 0 { + <$ty>::from_parts(0, a.low() << (b - half_bits)) + } else if b == 0 { + a + } else { + <$ty>::from_parts(a.low() << b, (a.high() << b) | (a.low() >> (half_bits - b))) + } + } + } +} + +macro_rules! ashr { + ($intrinsic:ident: $ty:ty) => { + /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` + #[cfg_attr(not(test), no_mangle)] + pub extern fn $intrinsic(a: $ty, b: u32) -> $ty { + let half_bits = <$ty>::bits() / 2; + if b & half_bits != 0 { + <$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf, + a.high() >> (half_bits - 1)) + } else if b == 0 { + a + } else { + let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf; + <$ty>::from_parts((high_unsigned << (half_bits - b)) | (a.low() >> b), + a.high() >> b) + } + } + } +} + +macro_rules! lshr { + ($intrinsic:ident: $ty:ty) => { + /// Returns logical `a >> b`, requires `b < $ty::bits()` + #[cfg_attr(not(test), no_mangle)] + pub extern fn $intrinsic(a: $ty, b: u32) -> $ty { + let half_bits = <$ty>::bits() / 2; + if b & half_bits != 0 { + <$ty>::from_parts(a.high() >> (b - half_bits), 0) + } else if b == 0 { + a + } else { + <$ty>::from_parts((a.high() << (half_bits - b)) | (a.low() >> b), a.high() >> b) + } + } + } +} + +ashl!(__ashldi3: u64); +ashr!(__ashrdi3: i64); +lshr!(__lshrdi3: u64); + +#[cfg(test)] +mod tests { + use quickcheck::TestResult; + + quickcheck! { + fn ashldi(a: u64, b: u32) -> TestResult { + if b >= 64 { + TestResult::discard() + } else { + let r = super::__ashldi3(a, b); + TestResult::from_bool(r == a << b) + } + } + + fn ashrdi(a: i64, b: u32) -> TestResult { + if b >= 64 { + TestResult::discard() + } else { + let r = super::__ashrdi3(a, b); + TestResult::from_bool(r == a >> b) + } + } + + fn lshrdi(a: u64, b: u32) -> TestResult { + if b >= 64 { + TestResult::discard() + } else { + let r = super::__lshrdi3(a, b); + TestResult::from_bool(r == a >> b) + } + } + } +} diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs deleted file mode 100644 index 96e0c12738b..00000000000 --- a/library/compiler-builtins/src/test.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::panic; - -use quickcheck::TestResult; - -quickcheck! { - fn udivmoddi4(n: (u32, u32), d: (u32, u32)) -> TestResult { - let n = ::U64 { low: n.0, high: n.1 }[..]; - let d = ::U64 { low: d.0, high: d.1 }[..]; - - if d == 0 { - TestResult::discard() - } else { - let mut r = 0; - let q = ::div::__udivmoddi4(n, d, Some(&mut r)); - - TestResult::from_bool(q * d + r == n) - } - } -} - -quickcheck! { - fn udivmodsi4(n: u32, d: u32) -> TestResult { - if d == 0 { - TestResult::discard() - } else { - let mut r = 0; - let q = ::div::__udivmodsi4(n, d, Some(&mut r)); - - TestResult::from_bool(q * d + r == n) - } - } -} diff --git a/library/compiler-builtins/src/udiv.rs b/library/compiler-builtins/src/udiv.rs new file mode 100644 index 00000000000..95a550f9b9d --- /dev/null +++ b/library/compiler-builtins/src/udiv.rs @@ -0,0 +1,290 @@ +use core::mem; +use {Int, LargeInt}; + +/// Returns `n / d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { + // Special cases + if d == 0 { + panic!("Division by zero"); + } + + if n == 0 { + return 0; + } + + let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); + + // d > n + if sr > u32::bits() - 1 { + return 0; + } + + // d == 1 + if sr == u32::bits() - 1 { + return n; + } + + sr += 1; + + // 1 <= sr <= u32::bits() - 1 + let mut q = n << (u32::bits() - sr); + let mut r = n >> sr; + + let mut carry = 0; + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (u32::bits() - 1)); + q = (q << 1) | carry; + + // carry = 0; + // if r > d { + // r -= d; + // carry = 1; + // } + + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::bits() - 1); + carry = (s & 1) as u32; + r -= d & s as u32; + } + + (q << 1) | carry +} + +/// Returns `n % d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { + n - __udivsi3(n, d) * d +} + +/// Returns `n / d` and sets `*rem = n % d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { + let q = __udivsi3(n, d); + if let Some(rem) = rem { + *rem = n - (q * d); + } + q +} + +/// Returns `n / d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { + __udivmoddi4(n, d, None) +} + +/// Returns `n % d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 { + let mut rem = unsafe { mem::uninitialized() }; + __udivmoddi4(a, b, Some(&mut rem)); + rem +} + +/// Returns `n / d` and sets `*rem = n % d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { + // NOTE X is unknown, K != 0 + if n.high() == 0 { + if d.high() == 0 { + // 0 X + // --- + // 0 X + if let Some(rem) = rem { + *rem = u64::from(n.low() % d.low()); + } + return u64::from(n.low() / d.low()); + } else { + // 0 X + // --- + // K X + if let Some(rem) = rem { + *rem = n; + } + return 0; + }; + } + + let mut sr; + let mut q; + let mut r; + + if d.low() == 0 { + if d.high() == 0 { + // K X + // --- + // 0 0 + panic!("Division by zero"); + } + + if n.low() == 0 { + // K 0 + // --- + // K 0 + if let Some(rem) = rem { + *rem = u64::from_parts(0, n.high() % d.high()); + } + return u64::from(n.high() / d.high()); + } + + // K K + // --- + // K 0 + + if d.high().is_power_of_two() { + if let Some(rem) = rem { + *rem = u64::from_parts(n.low(), n.high() & (d.high() - 1)); + } + return u64::from(n.high() >> d.high().trailing_zeros()); + } + + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > u32::bits() - 2 { + if let Some(rem) = rem { + *rem = n; + } + return 0; + } + + sr += 1; + + // 1 <= sr <= u32::bits() - 1 + q = n << (u64::bits() - sr); + r = n >> sr; + } else { + if d.high() == 0 { + // K X + // --- + // 0 K + if d.low().is_power_of_two() { + if let Some(rem) = rem { + *rem = u64::from(n.low() & (d.low() - 1)); + } + + if d.low() == 1 { + return n; + } else { + let sr = d.low().trailing_zeros(); + return n >> sr; + }; + } + + sr = 1 + u32::bits() + d.low().leading_zeros() - n.high().leading_zeros(); + + // 2 <= sr <= u64::bits() - 1 + q = n << (u64::bits() - sr); + r = n >> sr; + } else { + // K X + // --- + // K K + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > u32::bits() - 1 { + if let Some(rem) = rem { + *rem = n; + return 0; + } + } + + sr += 1; + + // 1 <= sr <= u32::bits() + q = n << (u64::bits() - sr); + r = n >> sr; + } + } + + // Not a special case + // q and r are initialized with + // q = n << (u64::bits() - sr) + // r = n >> sr + // 1 <= sr <= u64::bits() - 1 + let mut carry = 0; + + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (u64::bits() - 1)); + q = (q << 1) | carry as u64; + + // carry = 0 + // if r >= d { + // r -= d; + // carry = 1; + // } + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i64 >> (u64::bits() - 1); + carry = (s & 1) as u32; + r -= d & s as u64; + } + + if let Some(rem) = rem { + *rem = r; + } + (q << 1) | carry as u64 +} + +#[cfg(test)] +mod tests { + use quickcheck::TestResult; + + quickcheck!{ + fn udivdi3(n: u64, d: u64) -> TestResult { + if d == 0 { + TestResult::discard() + } else { + let q = super::__udivdi3(n, d); + TestResult::from_bool(q == n / d) + } + } + + fn umoddi3(n: u64, d: u64) -> TestResult { + if d == 0 { + TestResult::discard() + } else { + let r = super::__umoddi3(n, d); + TestResult::from_bool(r == n % d) + } + } + + fn udivmoddi4(n: u64, d: u64) -> TestResult { + if d == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = super::__udivmoddi4(n, d, Some(&mut r)); + TestResult::from_bool(q == n / d && r == n % d) + } + } + + fn udivsi3(n: u32, d: u32) -> TestResult { + if d == 0 { + TestResult::discard() + } else { + let q = super::__udivsi3(n, d); + TestResult::from_bool(q == n / d) + } + } + + fn umodsi3(n: u32, d: u32) -> TestResult { + if d == 0 { + TestResult::discard() + } else { + let r = super::__umodsi3(n, d); + TestResult::from_bool(r == n % d) + } + } + + fn udivmodsi4(n: u32, d: u32) -> TestResult { + if d == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = super::__udivmodsi4(n, d, Some(&mut r)); + TestResult::from_bool(q == n / d && r == n % d) + } + } + } +} -- cgit 1.4.1-3-g733a5 From d668c385aca6fc02501bfc78d8561e7e2cdb076f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 13 Aug 2016 17:29:38 +0100 Subject: Fix inline assembly to work on ARMv6-M --- library/compiler-builtins/src/arm.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 0759b55d4af..ad2b39a27f3 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -9,7 +9,8 @@ pub unsafe fn __aeabi_uidivmod() { sub sp, sp, #4 mov r2, sp bl __udivmodsi4 - ldr r1, [sp], #4 + ldr r1, [sp] + add sp, sp, #4 pop {pc}"); intrinsics::unreachable(); } @@ -17,13 +18,15 @@ pub unsafe fn __aeabi_uidivmod() { #[naked] #[cfg_attr(not(test), no_mangle)] pub unsafe fn __aeabi_uldivmod() { - asm!("push {lr} - sub r12, sp, #12 - str r12, [sp, #-20]! + asm!("push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] bl __udivmoddi4 - ldrd r2, r3, [sp, #8] - add sp, sp, #20 - pop {pc}"); + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc}"); intrinsics::unreachable(); } -- cgit 1.4.1-3-g733a5 From 1b757d626d6af7d4d002464557d143cb779320ca Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 11:32:52 -0500 Subject: CI: test ARM Cortex targets closes #32 --- library/compiler-builtins/.travis.yml | 29 ++++++++++++++++++++++ library/compiler-builtins/ci/env.sh | 12 ++++++--- library/compiler-builtins/ci/install.sh | 9 +++++-- library/compiler-builtins/ci/script.sh | 12 ++++----- library/compiler-builtins/thumbv6m-none-eabi.json | 10 ++++++++ library/compiler-builtins/thumbv7em-none-eabi.json | 8 ++++++ library/compiler-builtins/thumbv7m-none-eabi.json | 8 ++++++ 7 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 library/compiler-builtins/thumbv6m-none-eabi.json create mode 100644 library/compiler-builtins/thumbv7em-none-eabi.json create mode 100644 library/compiler-builtins/thumbv7m-none-eabi.json diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index dae5b40b2d0..cb3800665c9 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -3,6 +3,25 @@ sudo: false matrix: include: + - env: TARGET=thumbv6m-none-eabi + os: linux + dist: trusty + addons: + apt: + packages: &cortex + - binutils-arm-none-eabi + - env: TARGET=thumbv7m-none-eabi + os: linux + dist: trusty + addons: + apt: + packages: *cortex + - env: TARGET=thumbv7em-none-eabi + os: linux + dist: trusty + addons: + apt: + packages: *cortex - env: TARGET=i586-unknown-linux-gnu os: linux services: docker @@ -84,6 +103,16 @@ matrix: os: osx - env: TARGET=x86_64-unknown-linux-gnu os: linux + allow_failures: + # Issue #2. Flaky test + - env: TARGET=arm-unknown-linux-gnueabi + os: linux + # Issue #2. Flaky test + - env: TARGET=arm-unknown-linux-gnueabihf + os: linux + # Issue #2. Flaky test + - env: TARGET=armv7-unknown-linux-gnueabihf + os: linux before_install: - export PATH="$PATH:$HOME/.cargo/bin" diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 472983ff918..17f5f9cd267 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -25,8 +25,6 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf ;; armv7-unknown-linux-gnueabihf) - # See #2 - export DONT_RUN_TESTS=y export PREFIX=arm-linux-gnueabihf- export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf ;; @@ -65,13 +63,19 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu ;; powerpc64le-unknown-linux-gnu) - # See #2 - export DONT_RUN_TESTS=y if [[ -z $DOCKER ]]; then export DOCKER=y fi export PREFIX=powerpc64le-linux-gnu- export QEMU=qemu-ppc64le export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu + # Issue #2. QEMU doesn't work + export RUN_TESTS=n + ;; + thumbv*-none-eabi) + export CARGO=xargo + export PREFIX=arm-none-eabi- + # Bare metal targets. No `std` or `test` crates for these targets. + export RUN_TESTS=n ;; esac diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 9c971c67a66..86dfefe375e 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -32,8 +32,6 @@ install_binutils() { osx) brew install binutils ;; - *) - ;; esac } @@ -79,6 +77,12 @@ add_rustup_target() { fi } +install_xargo() { + if [[ $CARGO == "xargo" ]]; then + curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | bash -s -- --from japaric/xargo + fi +} + configure_cargo() { if [[ $PREFIX ]]; then ${PREFIX}gcc -v @@ -99,6 +103,7 @@ main() { install_c_toolchain install_rust add_rustup_target + install_xargo configure_cargo fi } diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 099e42ea3b0..f68b72b7b85 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -3,8 +3,8 @@ set -ex . $(dirname $0)/env.sh build() { - cargo build --target $TARGET - cargo build --target $TARGET --release + ${CARGO:-cargo} build --target $TARGET + ${CARGO:-cargo} build --target $TARGET --release } run_tests() { @@ -14,14 +14,14 @@ run_tests() { if [[ $QEMU ]]; then cargo test --target $TARGET --no-run - if [[ -z $DONT_RUN_TESTS ]]; then + if [[ ${RUN_TESTS:-y} == "y" ]]; then $QEMU target/**/debug/rustc_builtins-* fi cargo test --target $TARGET --release --no-run - if [[ -z $DONT_RUN_TESTS ]]; then + if [[ ${RUN_TESTS:-y} == "y" ]]; then $QEMU target/**/release/rustc_builtins-* fi - elif [[ -z $DONT_RUN_TESTS ]]; then + elif [[ ${RUN_TESTS:-y} == "y" ]]; then cargo test --target $TARGET cargo test --target $TARGET --release fi @@ -50,8 +50,8 @@ main() { bash ci/script.sh' else build - run_tests inspect + run_tests fi } diff --git a/library/compiler-builtins/thumbv6m-none-eabi.json b/library/compiler-builtins/thumbv6m-none-eabi.json new file mode 100644 index 00000000000..9c92d4e3333 --- /dev/null +++ b/library/compiler-builtins/thumbv6m-none-eabi.json @@ -0,0 +1,10 @@ +{ + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "features": "+strict-align", + "llvm-target": "thumbv6m-none-eabi", + "max-atomic-width": 0, + "os": "none", + "target-endian": "little", + "target-pointer-width": "32" +} diff --git a/library/compiler-builtins/thumbv7em-none-eabi.json b/library/compiler-builtins/thumbv7em-none-eabi.json new file mode 100644 index 00000000000..ce49c83ffda --- /dev/null +++ b/library/compiler-builtins/thumbv7em-none-eabi.json @@ -0,0 +1,8 @@ +{ + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "llvm-target": "thumbv7em-none-eabi", + "os": "none", + "target-endian": "little", + "target-pointer-width": "32" +} diff --git a/library/compiler-builtins/thumbv7m-none-eabi.json b/library/compiler-builtins/thumbv7m-none-eabi.json new file mode 100644 index 00000000000..313a5e66f71 --- /dev/null +++ b/library/compiler-builtins/thumbv7m-none-eabi.json @@ -0,0 +1,8 @@ +{ + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "llvm-target": "thumbv7m-none-eabi", + "os": "none", + "target-endian": "little", + "target-pointer-width": "32" +} -- cgit 1.4.1-3-g733a5 From 5e69a93dfb4720428b2fc415586dc13ba10c53b7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:21:33 -0500 Subject: binutils -> gcc? --- library/compiler-builtins/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index cb3800665c9..f71438c87fb 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -9,7 +9,7 @@ matrix: addons: apt: packages: &cortex - - binutils-arm-none-eabi + - gcc-arm-none-eabi - env: TARGET=thumbv7m-none-eabi os: linux dist: trusty -- cgit 1.4.1-3-g733a5 From b5b26a0384f17388cd6985fb14070accae3fbd84 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:41:50 -0500 Subject: install binutils manually --- library/compiler-builtins/.travis.yml | 13 +++---------- library/compiler-builtins/ci/install.sh | 7 +++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index f71438c87fb..4fe9705229a 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -6,22 +6,15 @@ matrix: - env: TARGET=thumbv6m-none-eabi os: linux dist: trusty - addons: - apt: - packages: &cortex - - gcc-arm-none-eabi + sudo: required - env: TARGET=thumbv7m-none-eabi os: linux dist: trusty - addons: - apt: - packages: *cortex + sudo: required - env: TARGET=thumbv7em-none-eabi os: linux dist: trusty - addons: - apt: - packages: *cortex + sudo: required - env: TARGET=i586-unknown-linux-gnu os: linux services: docker diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 86dfefe375e..57131eb94d0 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -33,6 +33,13 @@ install_binutils() { brew install binutils ;; esac + + case $TARGET in + thumbv*-none-eabi) + sudo apt-get install -y --no-install-recommends \ + binutils-arm-none-eabi + ;; + esac } install_c_toolchain() { -- cgit 1.4.1-3-g733a5 From a3a0604b8e8866f09878e26f22d431bc176de3f1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:45:19 -0500 Subject: no rust-std for these targets --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 57131eb94d0..b1e596db88f 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -79,7 +79,7 @@ install_rust() { } add_rustup_target() { - if [[ $TARGET != $HOST ]]; then + if [[ $TARGET != $HOST && ${CARGO:-cargo} == "cargo" ]]; then rustup target add $TARGET fi } -- cgit 1.4.1-3-g733a5 From c135ca31573ff41d00ceda3666590d6c7b3f8e1e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:47:59 -0500 Subject: binutils -> gcc --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index b1e596db88f..8486eb874e7 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -37,7 +37,7 @@ install_binutils() { case $TARGET in thumbv*-none-eabi) sudo apt-get install -y --no-install-recommends \ - binutils-arm-none-eabi + gcc-arm-none-eabi ;; esac } -- cgit 1.4.1-3-g733a5 From 2684ea570cdd4ae82bd550d3f5fb47460a71460e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:55:09 -0500 Subject: change Xargo installation path --- library/compiler-builtins/ci/install.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 8486eb874e7..84441ce393a 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -86,7 +86,8 @@ add_rustup_target() { install_xargo() { if [[ $CARGO == "xargo" ]]; then - curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | bash -s -- --from japaric/xargo + curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ + bash -s -- --from japaric/xargo --at $HOME/.cargo/bin fi } -- cgit 1.4.1-3-g733a5 From da0515756ad0f39856e2684a2a766741cf68f5ab Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:58:44 -0500 Subject: install libssh2 --- library/compiler-builtins/ci/install.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 84441ce393a..3bd806d8714 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -86,6 +86,8 @@ add_rustup_target() { install_xargo() { if [[ $CARGO == "xargo" ]]; then + sudo apt-get install -y --no-install-recommends \ + libssh2-1 curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ bash -s -- --from japaric/xargo --at $HOME/.cargo/bin fi -- cgit 1.4.1-3-g733a5 From 5581cc40af00edb82258f621a28ba6ea5a584d7f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 16:58:44 -0500 Subject: quickcheck: better generation of input arguments closes #31 --- library/compiler-builtins/src/lib.rs | 8 ++- library/compiler-builtins/src/mul.rs | 11 ++- library/compiler-builtins/src/qc.rs | 123 +++++++++++++++++++++++++++++++++ library/compiler-builtins/src/shift.rs | 11 ++- library/compiler-builtins/src/udiv.rs | 19 +++-- 5 files changed, 159 insertions(+), 13 deletions(-) create mode 100644 library/compiler-builtins/src/qc.rs diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 6d5580b8e18..823170a413e 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,8 +1,8 @@ #![allow(unused_features)] -#![no_std] #![feature(asm)] #![feature(core_intrinsics)] #![feature(naked_functions)] +#![cfg_attr(not(test), no_std)] // TODO(rust-lang/rust#35021) uncomment when that PR lands // #![feature(rustc_builtins)] @@ -13,6 +13,9 @@ #[macro_use] extern crate quickcheck; +#[cfg(test)] +extern crate core; + #[cfg(target_arch = "arm")] pub mod arm; @@ -20,6 +23,9 @@ pub mod udiv; pub mod mul; pub mod shift; +#[cfg(test)] +mod qc; + /// Trait for some basic operations on integers trait Int { fn bits() -> u32; diff --git a/library/compiler-builtins/src/mul.rs b/library/compiler-builtins/src/mul.rs index a4350b5f7ff..b93fdb76639 100644 --- a/library/compiler-builtins/src/mul.rs +++ b/library/compiler-builtins/src/mul.rs @@ -72,13 +72,17 @@ mulo!(__mulodi4: i64); #[cfg(test)] mod tests { + use qc::{I32, I64, U64}; + quickcheck! { - fn muldi(a: u64, b: u64) -> bool { + fn muldi(a: U64, b: U64) -> bool { + let (a, b) = (a.0, b.0); let r = super::__muldi4(a, b); r == a.wrapping_mul(b) } - fn mulosi(a: i32, b: i32) -> bool { + fn mulosi(a: I32, b: I32) -> bool { + let (a, b) = (a.0, b.0); let mut overflow = 2; let r = super::__mulosi4(a, b, &mut overflow); if overflow != 0 && overflow != 1 { @@ -87,7 +91,8 @@ mod tests { (r, overflow != 0) == a.overflowing_mul(b) } - fn mulodi(a: i64, b: i64) -> bool { + fn mulodi(a: I64, b: I64) -> bool { + let (a, b) = (a.0, b.0); let mut overflow = 2; let r = super::__mulodi4(a, b, &mut overflow); if overflow != 0 && overflow != 1 { diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs new file mode 100644 index 00000000000..6b37cceb7fd --- /dev/null +++ b/library/compiler-builtins/src/qc.rs @@ -0,0 +1,123 @@ +// When testing functions, QuickCheck (QC) uses small values for integer (`u*`/`i*`) arguments +// (~ `[-100, 100]`), but these values don't stress all the code paths in our intrinsics. Here we +// create newtypes over the primitive integer types with the goal of having full control over the +// random values that will be used to test our intrinsics. + +use std::boxed::Box; +use std::fmt; + +use quickcheck::{Arbitrary, Gen}; + +use LargeInt; + +// Generates values in the full range of the integer type +macro_rules! arbitrary { + ($TY:ident : $ty:ident) => { + #[derive(Clone, Copy)] + pub struct $TY(pub $ty); + + impl Arbitrary for $TY { + fn arbitrary(g: &mut G) -> $TY + where G: Gen + { + $TY(g.gen()) + } + + fn shrink(&self) -> Box> { + struct Shrinker { + x: $ty, + } + + impl Iterator for Shrinker { + type Item = $TY; + + fn next(&mut self) -> Option<$TY> { + self.x /= 2; + if self.x == 0 { + None + } else { + Some($TY(self.x)) + } + } + } + + if self.0 == 0 { + ::quickcheck::empty_shrinker() + } else { + Box::new(Shrinker { x: self.0 }) + } + } + } + + impl fmt::Debug for $TY { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } + } + } +} + +arbitrary!(I32: i32); +arbitrary!(U32: u32); + +// These integers are "too large". If we generate e.g. `u64` values in the full range then there's +// only `1 / 2^32` chance of seeing a value smaller than `2^32` (i.e. whose higher "word" (32-bits) +// is `0`)! But this is an important group of values to tests because we have special code paths for +// them. Instead we'll generate e.g. `u64` integers this way: uniformly pick between (a) setting the +// low word to 0 and generating a random high word, (b) vice versa: high word to 0 and random low +// word or (c) generate both words randomly. This let's cover better the code paths in our +// intrinsics. +macro_rules! arbitrary_large { + ($TY:ident : $ty:ident) => { + #[derive(Clone, Copy)] + pub struct $TY(pub $ty); + + impl Arbitrary for $TY { + fn arbitrary(g: &mut G) -> $TY + where G: Gen + { + if g.gen() { + $TY($ty::from_parts(g.gen(), g.gen())) + } else if g.gen() { + $TY($ty::from_parts(0, g.gen())) + } else { + $TY($ty::from_parts(g.gen(), 0)) + } + } + + fn shrink(&self) -> Box> { + struct Shrinker { + x: $ty, + } + + impl Iterator for Shrinker { + type Item = $TY; + + fn next(&mut self) -> Option<$TY> { + self.x /= 2; + if self.x == 0 { + None + } else { + Some($TY(self.x)) + } + } + } + + if self.0 == 0 { + ::quickcheck::empty_shrinker() + } else { + Box::new(Shrinker { x: self.0 }) + } + } + } + + impl fmt::Debug for $TY { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } + } + } +} + +arbitrary_large!(I64: i64); +arbitrary_large!(U64: u64); diff --git a/library/compiler-builtins/src/shift.rs b/library/compiler-builtins/src/shift.rs index 909d6f47f5a..7fa88abffb2 100644 --- a/library/compiler-builtins/src/shift.rs +++ b/library/compiler-builtins/src/shift.rs @@ -61,9 +61,12 @@ lshr!(__lshrdi3: u64); #[cfg(test)] mod tests { use quickcheck::TestResult; + use qc::{I64, U64}; + // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) quickcheck! { - fn ashldi(a: u64, b: u32) -> TestResult { + fn ashldi(a: U64, b: u32) -> TestResult { + let a = a.0; if b >= 64 { TestResult::discard() } else { @@ -72,7 +75,8 @@ mod tests { } } - fn ashrdi(a: i64, b: u32) -> TestResult { + fn ashrdi(a: I64, b: u32) -> TestResult { + let a = a.0; if b >= 64 { TestResult::discard() } else { @@ -81,7 +85,8 @@ mod tests { } } - fn lshrdi(a: u64, b: u32) -> TestResult { + fn lshrdi(a: U64, b: u32) -> TestResult { + let a = a.0; if b >= 64 { TestResult::discard() } else { diff --git a/library/compiler-builtins/src/udiv.rs b/library/compiler-builtins/src/udiv.rs index 95a550f9b9d..f1037c6df07 100644 --- a/library/compiler-builtins/src/udiv.rs +++ b/library/compiler-builtins/src/udiv.rs @@ -229,9 +229,11 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { #[cfg(test)] mod tests { use quickcheck::TestResult; + use qc::{U32, U64}; quickcheck!{ - fn udivdi3(n: u64, d: u64) -> TestResult { + fn udivdi3(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0, d.0); if d == 0 { TestResult::discard() } else { @@ -240,7 +242,8 @@ mod tests { } } - fn umoddi3(n: u64, d: u64) -> TestResult { + fn umoddi3(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0, d.0); if d == 0 { TestResult::discard() } else { @@ -249,7 +252,8 @@ mod tests { } } - fn udivmoddi4(n: u64, d: u64) -> TestResult { + fn udivmoddi4(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0, d.0); if d == 0 { TestResult::discard() } else { @@ -259,7 +263,8 @@ mod tests { } } - fn udivsi3(n: u32, d: u32) -> TestResult { + fn udivsi3(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0, d.0); if d == 0 { TestResult::discard() } else { @@ -268,7 +273,8 @@ mod tests { } } - fn umodsi3(n: u32, d: u32) -> TestResult { + fn umodsi3(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0, d.0); if d == 0 { TestResult::discard() } else { @@ -277,7 +283,8 @@ mod tests { } } - fn udivmodsi4(n: u32, d: u32) -> TestResult { + fn udivmodsi4(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0, d.0); if d == 0 { TestResult::discard() } else { -- cgit 1.4.1-3-g733a5 From 7b46e31124afceae32263161c317d1cb4aa6492e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:22:12 -0500 Subject: CI: run all Linux targets inside docker --- library/compiler-builtins/.travis.yml | 65 +---------------------- library/compiler-builtins/ci/env.sh | 26 ++------- library/compiler-builtins/ci/install.sh | 93 ++++++--------------------------- library/compiler-builtins/ci/script.sh | 25 +++++---- 4 files changed, 36 insertions(+), 173 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 4fe9705229a..7542351d1cd 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,97 +1,39 @@ language: generic -sudo: false +sudo: required +services: docker matrix: include: - env: TARGET=thumbv6m-none-eabi os: linux - dist: trusty - sudo: required - env: TARGET=thumbv7m-none-eabi os: linux - dist: trusty - sudo: required - env: TARGET=thumbv7em-none-eabi os: linux - dist: trusty - sudo: required - env: TARGET=i586-unknown-linux-gnu os: linux - services: docker - sudo: required - env: TARGET=aarch64-unknown-linux-gnu os: linux - dist: trusty - sudo: required - addons: - apt: - packages: - - binfmt-support - - qemu-user-static - env: TARGET=arm-unknown-linux-gnueabi os: linux - sudo: required - addons: - apt: - packages: - - binfmt-support - - gcc-arm-linux-gnueabi - - libc6-armel-cross - - libc6-dev-armel-cross - - qemu-user-static - env: TARGET=arm-unknown-linux-gnueabihf os: linux - sudo: required - addons: - apt: - packages: &armhf - - binfmt-support - - gcc-arm-linux-gnueabihf - - libc6-armhf-cross - - libc6-dev-armhf-cross - - qemu-user-static - env: TARGET=armv7-unknown-linux-gnueabihf os: linux - sudo: required - addons: - apt: - packages: *armhf - env: TARGET=i686-apple-darwin os: osx - env: TARGET=i686-unknown-linux-gnu os: linux - addons: - apt: - packages: - - gcc-multilib - env: TARGET=mips-unknown-linux-gnu os: linux - services: docker - sudo: required - env: TARGET=mipsel-unknown-linux-gnu os: linux - services: docker - sudo: required - env: TARGET=powerpc-unknown-linux-gnu os: linux - dist: trusty - sudo: required - addons: - apt: - packages: - - binfmt-support - - gcc-powerpc-linux-gnu - - libc6-powerpc-cross - - libc6-dev-powerpc-cross - - qemu-user-static - env: TARGET=powerpc64-unknown-linux-gnu os: linux - services: docker - sudo: required - env: TARGET=powerpc64le-unknown-linux-gnu os: linux - services: docker - sudo: required - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu @@ -107,9 +49,6 @@ matrix: - env: TARGET=armv7-unknown-linux-gnueabihf os: linux -before_install: - - export PATH="$PATH:$HOME/.cargo/bin" - install: - bash ci/install.sh diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 17f5f9cd267..a8c7003394e 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -28,26 +28,14 @@ case $TARGET in export PREFIX=arm-linux-gnueabihf- export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf ;; - i586-unknown-linux-gnu) - # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) - if [[ -z $DOCKER ]]; then - export DOCKER=y - fi - ;; mips-unknown-linux-gnu) - if [[ -z $DOCKER ]]; then - export DOCKER=y - fi export PREFIX=mips-linux-gnu- - export QEMU=qemu-mips + # export QEMU=qemu-mips export QEMU_LD_PREFIX=/usr/mips-linux-gnu ;; mipsel-unknown-linux-gnu) - if [[ -z $DOCKER ]]; then - export DOCKER=y - fi export PREFIX=mipsel-linux-gnu- - export QEMU=qemu-mipsel + # export QEMU=qemu-mipsel export QEMU_LD_PREFIX=/usr/mipsel-linux-gnu ;; powerpc-unknown-linux-gnu) @@ -55,19 +43,13 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; powerpc64-unknown-linux-gnu) - if [[ -z $DOCKER ]]; then - export DOCKER=y - fi export PREFIX=powerpc64-linux-gnu- - export QEMU=qemu-ppc64 + # export QEMU=qemu-ppc64 export QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu ;; powerpc64le-unknown-linux-gnu) - if [[ -z $DOCKER ]]; then - export DOCKER=y - fi export PREFIX=powerpc64le-linux-gnu- - export QEMU=qemu-ppc64le + # export QEMU=qemu-ppc64le export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu # Issue #2. QEMU doesn't work export RUN_TESTS=n diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 3bd806d8714..e3b7ce84fb5 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -2,77 +2,33 @@ set -ex . $(dirname $0)/env.sh -install_deps() { - if [[ ${DOCKER} == "i" ]]; then - apt-get update - apt-get install -y --no-install-recommends \ - ca-certificates curl - fi -} - install_qemu() { - case $TARGET in - mipsel-unknown-linux-gnu | \ - powerpc64le-unknown-linux-gnu) + case ${QEMU_ARCH:-$TRAVIS_OS_NAME} in + i386) + dpkg --add-architecture $QEMU_ARCH apt-get install -y --no-install-recommends \ - qemu-user + binfmt-support qemu-user-static:$QEMU_ARCH ;; - mips-unknown-linux-gnu | \ - powerpc64-unknown-linux-gnu) - dpkg --add-architecture i386 + linux) apt-get update apt-get install -y --no-install-recommends \ - qemu-user:i386 + binfmt-support qemu-user-static ;; esac } install_binutils() { - case $TRAVIS_OS_NAME in - osx) - brew install binutils - ;; - esac - - case $TARGET in - thumbv*-none-eabi) - sudo apt-get install -y --no-install-recommends \ - gcc-arm-none-eabi - ;; - esac -} - -install_c_toolchain() { - case $TARGET in - aarch64-unknown-linux-gnu) - sudo apt-get install -y --no-install-recommends \ - gcc-aarch64-linux-gnu libc6-dev-arm64-cross - ;; - i586-unknown-linux-gnu) - apt-get install -y --no-install-recommends \ - gcc libc6-dev-i386 lib32gcc-5-dev - ;; - mips-unknown-linux-gnu) - apt-get install -y --no-install-recommends \ - gcc gcc-mips-linux-gnu libc6-dev libc6-dev-mips-cross - ;; - mipsel-unknown-linux-gnu) - apt-get install -y --no-install-recommends \ - gcc gcc-mipsel-linux-gnu libc6-dev libc6-dev-mipsel-cross - ;; - powerpc64-unknown-linux-gnu) - apt-get install -y --no-install-recommends \ - gcc gcc-powerpc64-linux-gnu libc6-dev libc6-dev-ppc64-cross - ;; - powerpc64le-unknown-linux-gnu) - apt-get install -y --no-install-recommends \ - gcc gcc-powerpc64le-linux-gnu libc6-dev libc6-dev-ppc64el-cross - ;; - esac + if [[ $TRAVIS_OS_NAME == "osx" ]]; then + brew install binutils + fi } install_rust() { - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly + if [[ $TRAVIS_OS_NAME == "osx" ]]; then + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly + else + rustup default nightly + fi rustc -V cargo -V @@ -86,35 +42,18 @@ add_rustup_target() { install_xargo() { if [[ $CARGO == "xargo" ]]; then - sudo apt-get install -y --no-install-recommends \ - libssh2-1 curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --from japaric/xargo --at $HOME/.cargo/bin - fi -} - -configure_cargo() { - if [[ $PREFIX ]]; then - ${PREFIX}gcc -v - - mkdir -p .cargo - cat >>.cargo/config < Date: Sat, 13 Aug 2016 17:24:52 -0500 Subject: fix bash syntax --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index e3b7ce84fb5..bdb0fa1d77a 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -48,7 +48,7 @@ install_xargo() { } main() { - if [[ $TRAVIS_OS_NAME == "osx" || ${IN_DOCKER_CONTAINER:-n} == "y" ]] + if [[ $TRAVIS_OS_NAME == "osx" || ${IN_DOCKER_CONTAINER:-n} == "y" ]]; then install_qemu install_binutils install_rust -- cgit 1.4.1-3-g733a5 From cc6aab07ea63447f97412b25510bc800d9c90554 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:27:18 -0500 Subject: actually enter docker --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 4243fb02873..e119044b618 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -36,7 +36,7 @@ run_tests() { } main() { - if [[ $DOCKER == "y" ]]; then + if [[ $TRAVIS_OS_NAME == "linux" ]]; then local tag=2016-08-13 docker run \ -- cgit 1.4.1-3-g733a5 From a8f3f4eae63076d7250153cf7b99b53fcf6bac80 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:32:08 -0500 Subject: use trusty --- library/compiler-builtins/.travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7542351d1cd..99a2729aa77 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,6 +1,7 @@ +dist: trusty language: generic -sudo: required services: docker +sudo: required matrix: include: -- cgit 1.4.1-3-g733a5 From c7a48515ac8ac035a9f08f17465f3bf26e97a2a6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:36:00 -0500 Subject: don't call docker inside docker --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index e119044b618..847530a142c 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -36,7 +36,7 @@ run_tests() { } main() { - if [[ $TRAVIS_OS_NAME == "linux" ]]; then + if [[ $TRAVIS_OS_NAME == "linux" && ${IN_DOCKER_CONTAINER:-n} == "n" ]]; then local tag=2016-08-13 docker run \ -- cgit 1.4.1-3-g733a5 From 0433fc0deba61035ecc3c329347afe9b0bf4dadf Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:43:40 -0500 Subject: sort targets --- library/compiler-builtins/.travis.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 99a2729aa77..53b57066560 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -5,14 +5,6 @@ sudo: required matrix: include: - - env: TARGET=thumbv6m-none-eabi - os: linux - - env: TARGET=thumbv7m-none-eabi - os: linux - - env: TARGET=thumbv7em-none-eabi - os: linux - - env: TARGET=i586-unknown-linux-gnu - os: linux - env: TARGET=aarch64-unknown-linux-gnu os: linux - env: TARGET=arm-unknown-linux-gnueabi @@ -21,6 +13,8 @@ matrix: os: linux - env: TARGET=armv7-unknown-linux-gnueabihf os: linux + - env: TARGET=i586-unknown-linux-gnu + os: linux - env: TARGET=i686-apple-darwin os: osx - env: TARGET=i686-unknown-linux-gnu @@ -35,6 +29,12 @@ matrix: os: linux - env: TARGET=powerpc64le-unknown-linux-gnu os: linux + - env: TARGET=thumbv6m-none-eabi + os: linux + - env: TARGET=thumbv7em-none-eabi + os: linux + - env: TARGET=thumbv7m-none-eabi + os: linux - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu -- cgit 1.4.1-3-g733a5 From 54e090113afc22725c1c4aec187952e0134cc0ee Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:45:43 -0500 Subject: no need to explicitly call qemu-$ARCH --- library/compiler-builtins/ci/env.sh | 4 ---- library/compiler-builtins/ci/script.sh | 11 +---------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index a8c7003394e..89660a13e66 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -30,12 +30,10 @@ case $TARGET in ;; mips-unknown-linux-gnu) export PREFIX=mips-linux-gnu- - # export QEMU=qemu-mips export QEMU_LD_PREFIX=/usr/mips-linux-gnu ;; mipsel-unknown-linux-gnu) export PREFIX=mipsel-linux-gnu- - # export QEMU=qemu-mipsel export QEMU_LD_PREFIX=/usr/mipsel-linux-gnu ;; powerpc-unknown-linux-gnu) @@ -44,12 +42,10 @@ case $TARGET in ;; powerpc64-unknown-linux-gnu) export PREFIX=powerpc64-linux-gnu- - # export QEMU=qemu-ppc64 export QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu ;; powerpc64le-unknown-linux-gnu) export PREFIX=powerpc64le-linux-gnu- - # export QEMU=qemu-ppc64le export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu # Issue #2. QEMU doesn't work export RUN_TESTS=n diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 847530a142c..3b00ff62aa1 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -20,16 +20,7 @@ run_tests() { export RUST_TEST_THREADS=1 fi - if [[ $QEMU ]]; then - cargo test --target $TARGET --no-run - if [[ ${RUN_TESTS:-y} == "y" ]]; then - $QEMU target/**/debug/rustc_builtins-* - fi - cargo test --target $TARGET --release --no-run - if [[ ${RUN_TESTS:-y} == "y" ]]; then - $QEMU target/**/release/rustc_builtins-* - fi - elif [[ ${RUN_TESTS:-y} == "y" ]]; then + if [[ ${RUN_TESTS:-y} == "y" ]]; then cargo test --target $TARGET cargo test --target $TARGET --release fi -- cgit 1.4.1-3-g733a5 From b80d5f6912cb8360a0eb9f33468f67bf8b30b718 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:46:12 -0500 Subject: arm targets no longer have flaky tests --- library/compiler-builtins/.travis.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 53b57066560..2b0154aeb2c 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -39,16 +39,6 @@ matrix: os: osx - env: TARGET=x86_64-unknown-linux-gnu os: linux - allow_failures: - # Issue #2. Flaky test - - env: TARGET=arm-unknown-linux-gnueabi - os: linux - # Issue #2. Flaky test - - env: TARGET=arm-unknown-linux-gnueabihf - os: linux - # Issue #2. Flaky test - - env: TARGET=armv7-unknown-linux-gnueabihf - os: linux install: - bash ci/install.sh -- cgit 1.4.1-3-g733a5 From 7a5032317ec28129dace653ad71d62e35914a5f3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:53:26 -0500 Subject: need to set PATH for macos --- library/compiler-builtins/.travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 2b0154aeb2c..e74b68002ff 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -40,6 +40,9 @@ matrix: - env: TARGET=x86_64-unknown-linux-gnu os: linux +before_install: + - export PATH="$PATH:$HOME/.cargo/bin" + install: - bash ci/install.sh -- cgit 1.4.1-3-g733a5 From 2160b520ff00bc04c9d798c114e91de06fed5378 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 18:00:49 -0500 Subject: enable tests for ppc64le --- library/compiler-builtins/ci/env.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 89660a13e66..c3591cbee6e 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -47,8 +47,6 @@ case $TARGET in powerpc64le-unknown-linux-gnu) export PREFIX=powerpc64le-linux-gnu- export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu - # Issue #2. QEMU doesn't work - export RUN_TESTS=n ;; thumbv*-none-eabi) export CARGO=xargo -- cgit 1.4.1-3-g733a5 From b8b7cbeabd94dbc046ae35efa5524a3fac382071 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 18:20:52 -0500 Subject: qemu-ppc64le still doesn't work --- library/compiler-builtins/ci/env.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index c3591cbee6e..50f19b2781f 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -47,6 +47,7 @@ case $TARGET in powerpc64le-unknown-linux-gnu) export PREFIX=powerpc64le-linux-gnu- export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu + export RUN_TESTS=n ;; thumbv*-none-eabi) export CARGO=xargo -- cgit 1.4.1-3-g733a5 From f7864eb3cd29389854555ffaef26e2418ab91ab7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 18:45:00 -0500 Subject: fix a bug in udivmoddi4 --- library/compiler-builtins/src/udiv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/udiv.rs b/library/compiler-builtins/src/udiv.rs index f1037c6df07..82932e31314 100644 --- a/library/compiler-builtins/src/udiv.rs +++ b/library/compiler-builtins/src/udiv.rs @@ -186,8 +186,8 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { if sr > u32::bits() - 1 { if let Some(rem) = rem { *rem = n; - return 0; } + return 0; } sr += 1; -- cgit 1.4.1-3-g733a5 From ebb3175dc0f1c5cefcaf06d8e6761d9b7f3c1304 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 18:47:10 -0500 Subject: use wrapping_add in muldi4 --- library/compiler-builtins/src/mul.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/mul.rs b/library/compiler-builtins/src/mul.rs index b93fdb76639..77dba26ec3c 100644 --- a/library/compiler-builtins/src/mul.rs +++ b/library/compiler-builtins/src/mul.rs @@ -19,7 +19,7 @@ macro_rules! mul { low += (t & lower_mask) << half_bits; high += t >> half_bits; high += (a.low() >> half_bits) * (b.low() >> half_bits); - high += a.high().wrapping_mul(b.low()) + a.low().wrapping_mul(b.high()); + high = high.wrapping_add(a.high().wrapping_mul(b.low()).wrapping_add(a.low().wrapping_mul(b.high()))); <$ty>::from_parts(low, high) } } -- cgit 1.4.1-3-g733a5 From 18265c1061c65001c5b558af604f342b97a986f6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 18:58:41 -0500 Subject: try 32-bit qemu for ppc64le --- library/compiler-builtins/.travis.yml | 4 ++-- library/compiler-builtins/ci/env.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index e74b68002ff..7259cc0b11f 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -5,6 +5,8 @@ sudo: required matrix: include: + - env: TARGET=powerpc64le-unknown-linux-gnu + os: linux - env: TARGET=aarch64-unknown-linux-gnu os: linux - env: TARGET=arm-unknown-linux-gnueabi @@ -27,8 +29,6 @@ matrix: os: linux - env: TARGET=powerpc64-unknown-linux-gnu os: linux - - env: TARGET=powerpc64le-unknown-linux-gnu - os: linux - env: TARGET=thumbv6m-none-eabi os: linux - env: TARGET=thumbv7em-none-eabi diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 50f19b2781f..bb1bd262549 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -46,8 +46,8 @@ case $TARGET in ;; powerpc64le-unknown-linux-gnu) export PREFIX=powerpc64le-linux-gnu- + export QEMU_ARCH=i386 export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu - export RUN_TESTS=n ;; thumbv*-none-eabi) export CARGO=xargo -- cgit 1.4.1-3-g733a5 From 2d84d8acd40d75ccdc12889d3c423b3cec6d1449 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 19:30:30 -0500 Subject: add missing apt-get update --- library/compiler-builtins/ci/install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index bdb0fa1d77a..6e527b5c3cf 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -6,6 +6,7 @@ install_qemu() { case ${QEMU_ARCH:-$TRAVIS_OS_NAME} in i386) dpkg --add-architecture $QEMU_ARCH + apt-get update apt-get install -y --no-install-recommends \ binfmt-support qemu-user-static:$QEMU_ARCH ;; -- cgit 1.4.1-3-g733a5 From 44aa941787d632bf5364300e689716f519386424 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 19:56:34 -0500 Subject: disable tests for ppc64le, drop logic around QEMU_ARCH --- library/compiler-builtins/ci/env.sh | 4 +++- library/compiler-builtins/ci/install.sh | 8 +------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index bb1bd262549..55249950b3c 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -46,8 +46,10 @@ case $TARGET in ;; powerpc64le-unknown-linux-gnu) export PREFIX=powerpc64le-linux-gnu- - export QEMU_ARCH=i386 export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu + # QEMU crashes, even running the simplest cross compiled C program: + # `int main() { return 0; }` + export RUN_TESTS=n ;; thumbv*-none-eabi) export CARGO=xargo diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 6e527b5c3cf..db862cc3349 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -3,13 +3,7 @@ set -ex . $(dirname $0)/env.sh install_qemu() { - case ${QEMU_ARCH:-$TRAVIS_OS_NAME} in - i386) - dpkg --add-architecture $QEMU_ARCH - apt-get update - apt-get install -y --no-install-recommends \ - binfmt-support qemu-user-static:$QEMU_ARCH - ;; + case $TRAVIS_OS_NAME in linux) apt-get update apt-get install -y --no-install-recommends \ -- cgit 1.4.1-3-g733a5 From a87180452ea4b9c198588b29345420ea32644997 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 20:25:16 -0500 Subject: sort targets --- library/compiler-builtins/.travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7259cc0b11f..e74b68002ff 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -5,8 +5,6 @@ sudo: required matrix: include: - - env: TARGET=powerpc64le-unknown-linux-gnu - os: linux - env: TARGET=aarch64-unknown-linux-gnu os: linux - env: TARGET=arm-unknown-linux-gnueabi @@ -29,6 +27,8 @@ matrix: os: linux - env: TARGET=powerpc64-unknown-linux-gnu os: linux + - env: TARGET=powerpc64le-unknown-linux-gnu + os: linux - env: TARGET=thumbv6m-none-eabi os: linux - env: TARGET=thumbv7em-none-eabi -- cgit 1.4.1-3-g733a5 From 657a0cd18aa2c2e6f1925f98eac5e0b7415d27c8 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 12 Aug 2016 21:20:56 -0500 Subject: add weak `memcpy` et al symbols closes #28 --- library/compiler-builtins/src/lib.rs | 3 ++ library/compiler-builtins/src/mem.rs | 60 ++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 library/compiler-builtins/src/mem.rs diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 823170a413e..a802d1b9bf4 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,10 +1,12 @@ #![allow(unused_features)] #![feature(asm)] #![feature(core_intrinsics)] +#![feature(linkage)] #![feature(naked_functions)] #![cfg_attr(not(test), no_std)] // TODO(rust-lang/rust#35021) uncomment when that PR lands // #![feature(rustc_builtins)] +#![no_builtins] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. @@ -20,6 +22,7 @@ extern crate core; pub mod arm; pub mod udiv; +pub mod mem; pub mod mul; pub mod shift; diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs new file mode 100644 index 00000000000..7a9403404f1 --- /dev/null +++ b/library/compiler-builtins/src/mem.rs @@ -0,0 +1,60 @@ +// NOTE Copied verbatim from the rlibc crate +// cf. https://crates.io/crates/rlibc + +#[linkage = "weak"] +#[no_mangle] +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + dest +} + +#[linkage = "weak"] +#[no_mangle] +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + if src < dest as *const u8 { + // copy from end + let mut i = n; + while i != 0 { + i -= 1; + *dest.offset(i as isize) = *src.offset(i as isize); + } + } else { + // copy from beginning + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + } + dest +} + +#[linkage = "weak"] +#[no_mangle] +pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 { + let mut i = 0; + while i < n { + *s.offset(i as isize) = c as u8; + i += 1; + } + s +} + +#[linkage = "weak"] +#[no_mangle] +pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + let mut i = 0; + while i < n { + let a = *s1.offset(i as isize); + let b = *s2.offset(i as isize); + if a != b { + return a as i32 - b as i32; + } + i += 1; + } + 0 +} -- cgit 1.4.1-3-g733a5 From a8c6135b384f0fee0605325fc982991a67f4d5ab Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:16:52 -0500 Subject: exclude windows and macos --- library/compiler-builtins/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index a802d1b9bf4..2d1c8399cfb 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -4,9 +4,9 @@ #![feature(linkage)] #![feature(naked_functions)] #![cfg_attr(not(test), no_std)] +#![no_builtins] // TODO(rust-lang/rust#35021) uncomment when that PR lands // #![feature(rustc_builtins)] -#![no_builtins] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. @@ -22,6 +22,7 @@ extern crate core; pub mod arm; pub mod udiv; +#[cfg(all(not(windows), not(target_os = "macos")))] pub mod mem; pub mod mul; pub mod shift; -- cgit 1.4.1-3-g733a5 From 670f4e32aa8a509384f86e95445c810fa7d118c5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:26:58 -0500 Subject: check presence of weak symbols --- library/compiler-builtins/ci/script.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 3b00ff62aa1..c271456a9dd 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -9,10 +9,21 @@ build() { inspect() { $PREFIX$NM -g --defined-only target/**/debug/*.rlib + set +e $PREFIX$OBJDUMP -Cd target/**/debug/*.rlib $PREFIX$OBJDUMP -Cd target/**/release/*.rlib set -e + + # Check presence of weak symbols + case $TRAVIS_OS_NAME in + linux) + local symbols=( memcmp memcpy memmove memset ) + for symbol in "${symbols[@]}"; do + $PREFIX$NM target/**/debug/*.rlib | grep -q "W $symbol" + done + ;; + esac } run_tests() { -- cgit 1.4.1-3-g733a5 From ae75d02bdd1b0606b8c6c9857d78edb300c473c7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 14 Aug 2016 21:59:48 -0500 Subject: use rlibc crate instead --- library/compiler-builtins/Cargo.toml | 6 ++++ library/compiler-builtins/src/lib.rs | 5 +-- library/compiler-builtins/src/mem.rs | 60 ------------------------------------ 3 files changed, 9 insertions(+), 62 deletions(-) delete mode 100644 library/compiler-builtins/src/mem.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index dfd1fdeeee1..48f6ee0ce3d 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -3,5 +3,11 @@ authors = ["Jorge Aparicio "] name = "rustc_builtins" version = "0.1.0" +[dependencies] +rlibc = { git = "https://github.com/alexcrichton/rlibc", optional = true } + [dev-dependencies] quickcheck = "0.3.1" + +[features] +default = ["rlibc/weak"] diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 2d1c8399cfb..7b621dd3d19 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -18,12 +18,13 @@ extern crate quickcheck; #[cfg(test)] extern crate core; +#[cfg(all(not(windows), not(target_os = "macos")))] +extern crate rlibc; + #[cfg(target_arch = "arm")] pub mod arm; pub mod udiv; -#[cfg(all(not(windows), not(target_os = "macos")))] -pub mod mem; pub mod mul; pub mod shift; diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs deleted file mode 100644 index 7a9403404f1..00000000000 --- a/library/compiler-builtins/src/mem.rs +++ /dev/null @@ -1,60 +0,0 @@ -// NOTE Copied verbatim from the rlibc crate -// cf. https://crates.io/crates/rlibc - -#[linkage = "weak"] -#[no_mangle] -pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); - i += 1; - } - dest -} - -#[linkage = "weak"] -#[no_mangle] -pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - if src < dest as *const u8 { - // copy from end - let mut i = n; - while i != 0 { - i -= 1; - *dest.offset(i as isize) = *src.offset(i as isize); - } - } else { - // copy from beginning - let mut i = 0; - while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); - i += 1; - } - } - dest -} - -#[linkage = "weak"] -#[no_mangle] -pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *s.offset(i as isize) = c as u8; - i += 1; - } - s -} - -#[linkage = "weak"] -#[no_mangle] -pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - let mut i = 0; - while i < n { - let a = *s1.offset(i as isize); - let b = *s2.offset(i as isize); - if a != b { - return a as i32 - b as i32; - } - i += 1; - } - 0 -} -- cgit 1.4.1-3-g733a5 From b193bf698d25f8bf44d1eb6866dcf047fbd0266f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 14 Aug 2016 22:08:36 -0500 Subject: remove unused feature gates --- library/compiler-builtins/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 7b621dd3d19..ed4916f249b 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,4 @@ -#![allow(unused_features)] #![feature(asm)] -#![feature(core_intrinsics)] #![feature(linkage)] #![feature(naked_functions)] #![cfg_attr(not(test), no_std)] -- cgit 1.4.1-3-g733a5 From de150c17015e60f9e863857675bb269559bc4652 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 15 Aug 2016 20:22:58 -0500 Subject: adjust test: weak symbols are now in librlibc.rlib --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index c271456a9dd..75584786943 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -20,7 +20,7 @@ inspect() { linux) local symbols=( memcmp memcpy memmove memset ) for symbol in "${symbols[@]}"; do - $PREFIX$NM target/**/debug/*.rlib | grep -q "W $symbol" + $PREFIX$NM target/**/debug/deps/librlibc*.rlib | grep -q "W $symbol" done ;; esac -- cgit 1.4.1-3-g733a5 From 63a87352d8e73f1e9cd41edd0ee3e1a56dc6e73e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 15 Aug 2016 21:08:04 -0500 Subject: add core_intrinsics feature gate --- library/compiler-builtins/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index ed4916f249b..2263fda0003 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,4 +1,5 @@ #![feature(asm)] +#![feature(core_intrinsics)] #![feature(linkage)] #![feature(naked_functions)] #![cfg_attr(not(test), no_std)] -- cgit 1.4.1-3-g733a5 From f0dbe4c07c16c42e049ee12509e48d04cbe45d74 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Tue, 16 Aug 2016 17:46:46 -0500 Subject: Add x86_64 builtins --- library/compiler-builtins/src/lib.rs | 3 ++ library/compiler-builtins/src/x86_64.rs | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 library/compiler-builtins/src/x86_64.rs diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 2263fda0003..7941b201eb1 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -23,6 +23,9 @@ extern crate rlibc; #[cfg(target_arch = "arm")] pub mod arm; +#[cfg(target_arch = "x86_64")] +pub mod x86_64; + pub mod udiv; pub mod mul; pub mod shift; diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs new file mode 100644 index 00000000000..5df365c5931 --- /dev/null +++ b/library/compiler-builtins/src/x86_64.rs @@ -0,0 +1,67 @@ +use core::intrinsics; + +// NOTE These functions are implemented using assembly because they using a custom +// calling convention which can't be implemented using a normal Rust function +#[cfg(windows)] +#[naked] +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn ___chkstk_ms() { + asm!("push %rcx + push %rax + cmp $$0x1000,%rax + lea 24(%rsp),%rcx + jb 1f + 2: + sub $$0x1000,%rcx + test %rcx,(%rcx) + sub $$0x1000,%rax + cmp $$0x1000,%rax + ja 2b + 1: + sub %rax,%rcx + test %rcx,(%rcx) + pop %rax + pop %rcx + ret"); + intrinsics::unreachable(); +} + +#[cfg(windows)] +#[naked] +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn __alloca() { + asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx"); + // The original behavior had __alloca fall through to ___chkstk here, but + // I don't believe that this behavior is guaranteed, and a program that uses + // only __alloca could have ___chkstk removed by --gc-sections. Call + // ___chkstk here to guarantee that neither of those happen. + ___chkstk(); +} + +#[cfg(windows)] +#[naked] +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn ___chkstk() { + asm!("push %rcx + cmp $$0x1000,%rax + lea 16(%rsp),%rcx // rsp before calling this routine -> rcx + jb 1f + 2: + sub $$0x1000,%rcx + test %rcx,(%rcx) + sub $$0x1000,%rax + cmp $$0x1000,%rax + ja 2b + 1: + sub %rax,%rcx + test %rcx,(%rcx) + + lea 8(%rsp),%rax // load pointer to the return address into rax + mov %rcx,%rsp // install the new top of stack pointer into rsp + mov -8(%rax),%rcx // restore rcx + push (%rax) // push return address onto the stack + sub %rsp,%rax // restore the original value in rax + ret"); + intrinsics::unreachable(); +} + -- cgit 1.4.1-3-g733a5 From 7e238f997391be1ea5baf5e947eb99dcaf496ae2 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 12:11:38 -0500 Subject: Use `jmp` to implement __alloca fallthrough --- library/compiler-builtins/src/x86_64.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 5df365c5931..8368593d665 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -30,12 +30,9 @@ pub unsafe fn ___chkstk_ms() { #[naked] #[cfg_attr(not(test), no_mangle)] pub unsafe fn __alloca() { - asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx"); - // The original behavior had __alloca fall through to ___chkstk here, but - // I don't believe that this behavior is guaranteed, and a program that uses - // only __alloca could have ___chkstk removed by --gc-sections. Call - // ___chkstk here to guarantee that neither of those happen. - ___chkstk(); + asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx + jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); + intrinsics::unreachable(); } #[cfg(windows)] -- cgit 1.4.1-3-g733a5 From 22331947eabea06e12d906a08d6c5afe27b1b3a3 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 12:53:56 -0500 Subject: Disable mangling for msvc stack builtins This prevents linker errors in test builds due to the `jmp` instruction in __alloca --- library/compiler-builtins/src/x86_64.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 8368593d665..8bc33096dfc 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -2,9 +2,13 @@ use core::intrinsics; // NOTE These functions are implemented using assembly because they using a custom // calling convention which can't be implemented using a normal Rust function + +// NOTE These functions are never mangled as they are not tested against compiler-rt +// and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca + #[cfg(windows)] #[naked] -#[cfg_attr(not(test), no_mangle)] +#[no_mangle] pub unsafe fn ___chkstk_ms() { asm!("push %rcx push %rax @@ -28,7 +32,7 @@ pub unsafe fn ___chkstk_ms() { #[cfg(windows)] #[naked] -#[cfg_attr(not(test), no_mangle)] +#[no_mangle] pub unsafe fn __alloca() { asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); @@ -37,7 +41,7 @@ pub unsafe fn __alloca() { #[cfg(windows)] #[naked] -#[cfg_attr(not(test), no_mangle)] +#[no_mangle] pub unsafe fn ___chkstk() { asm!("push %rcx cmp $$0x1000,%rax -- cgit 1.4.1-3-g733a5 From 0ce86ac501cc5fe4ec172385a8cf6bc5ef7a1378 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 13:12:06 -0500 Subject: Appveyor: Source vcvarsall to get dumpbin in path --- library/compiler-builtins/appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 06255fa1d43..77f69590ca7 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -17,6 +17,7 @@ test_script: - cargo build --release - cargo test - cargo test --release + - CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - dumpbin /disasm target/debug/librustc_builtins.rlib - dumpbin /disasm target/release/librustc_builtins.rlib -- cgit 1.4.1-3-g733a5 From 77ffc1f9a0ad15dadd8748d5ab4d452c9a84d8c8 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 13:56:35 -0500 Subject: Appveyor: Ignore errors from dumpbin parsing rlib --- library/compiler-builtins/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 77f69590ca7..4bb03def782 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -18,8 +18,8 @@ test_script: - cargo test - cargo test --release - CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - - dumpbin /disasm target/debug/librustc_builtins.rlib - - dumpbin /disasm target/release/librustc_builtins.rlib + - dumpbin /disasm target/debug/librustc_builtins.rlib || exit 0 + - dumpbin /disasm target/release/librustc_builtins.rlib || exit 0 branches: only: -- cgit 1.4.1-3-g733a5 From f9c8ca854a33a8a95126fea9a601500984419785 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 14:35:48 -0500 Subject: Check off x86_64 builtins in README [ci ignore] --- library/compiler-builtins/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 73a25e9d7dc..4ff8b458651 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -133,8 +133,8 @@ See [rust-lang/rust#35437][0]. - [x] udivsi3.c - [x] umoddi3.c - [x] umodsi3.c -- [ ] x86_64/chkstk.S -- [ ] x86_64/chkstk2.S +- [x] x86_64/chkstk.S +- [x] x86_64/chkstk2.S These builtins are needed to support 128-bit integers, which are in the process of being added to Rust. -- cgit 1.4.1-3-g733a5 From 3fddb6b427bbbfc44254d1c9d151d50f6716f01c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 18 Aug 2016 21:27:16 -0500 Subject: rename muldi4 to muldi3 closes #42 --- library/compiler-builtins/src/mul.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/mul.rs b/library/compiler-builtins/src/mul.rs index 77dba26ec3c..cb313964b8b 100644 --- a/library/compiler-builtins/src/mul.rs +++ b/library/compiler-builtins/src/mul.rs @@ -66,7 +66,7 @@ macro_rules! mulo { } } -mul!(__muldi4: u64); +mul!(__muldi3: u64); mulo!(__mulosi4: i32); mulo!(__mulodi4: i64); @@ -77,7 +77,7 @@ mod tests { quickcheck! { fn muldi(a: U64, b: U64) -> bool { let (a, b) = (a.0, b.0); - let r = super::__muldi4(a, b); + let r = super::__muldi3(a, b); r == a.wrapping_mul(b) } -- cgit 1.4.1-3-g733a5 From 161234b8b30fb443c7a7a6d3be869833ab1803a5 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 18 Aug 2016 17:20:24 +0100 Subject: Add signed division functions --- library/compiler-builtins/README.md | 24 +++---- library/compiler-builtins/src/arm.rs | 40 ++++++++++- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/mul.rs | 4 +- library/compiler-builtins/src/sdiv.rs | 121 +++++++++++++++++++++++++++++++++ library/compiler-builtins/src/shift.rs | 6 +- 6 files changed, 178 insertions(+), 18 deletions(-) create mode 100644 library/compiler-builtins/src/sdiv.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 73a25e9d7dc..9199c963377 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -40,9 +40,9 @@ See [rust-lang/rust#35437][0]. - [x] arm/aeabi_uidivmod.S - [x] arm/aeabi_uldivmod.S - [ ] arm/divdf3vfp.S -- [ ] arm/divmodsi4.S +- [ ] arm/divmodsi4.S (generic version is done) - [ ] arm/divsf3vfp.S -- [ ] arm/divsi3.S +- [ ] arm/divsi3.S (generic version is done) - [ ] arm/eqdf2vfp.S - [ ] arm/eqsf2vfp.S - [ ] arm/extendsfdf2vfp.S @@ -62,7 +62,7 @@ See [rust-lang/rust#35437][0]. - [ ] arm/lesf2vfp.S - [ ] arm/ltdf2vfp.S - [ ] arm/ltsf2vfp.S -- [ ] arm/modsi3.S +- [ ] arm/modsi3.S (generic version is done) - [ ] arm/muldf3vfp.S - [ ] arm/mulsf3vfp.S - [ ] arm/nedf2vfp.S @@ -73,17 +73,19 @@ See [rust-lang/rust#35437][0]. - [ ] arm/subdf3vfp.S - [ ] arm/subsf3vfp.S - [ ] arm/truncdfsf2vfp.S -- [ ] arm/udivmodsi4.S -- [ ] arm/udivsi3.S -- [ ] arm/umodsi3.S +- [ ] arm/udivmodsi4.S (generic version is done) +- [ ] arm/udivsi3.S (generic version is done) +- [ ] arm/umodsi3.S (generic version is done) - [ ] arm/unorddf2vfp.S - [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c - [ ] divdf3.c -- [ ] divdi3.c +- [x] divdi3.c +- [x] divmoddi4.c +- [x] divmodsi4.c - [ ] divsf3.c -- [ ] divsi3.c +- [x] divsi3.c - [ ] extendhfsf2.c - [ ] extendsfdf2.c - [ ] fixdfdi.c @@ -113,8 +115,8 @@ See [rust-lang/rust#35437][0]. - [ ] i386/udivdi3.S - [ ] i386/umoddi3.S - [x] lshrdi3.c -- [ ] moddi3.c -- [ ] modsi3.c +- [x] moddi3.c +- [x] modsi3.c - [ ] muldf3.c - [x] muldi3.c - [x] mulodi4.c @@ -251,8 +253,6 @@ These builtins are never called by LLVM. - ~~ctzdi2.c~~ - ~~ctzsi2.c~~ - ~~ctzti2.c~~ -- ~~divmoddi4.c~~ -- ~~divmodsi4.c~~ - ~~ffsdi2.c~~ - ~~ffsti2.c~~ - ~~mulvdi3.c~~ diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index ad2b39a27f3..285871f15e5 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,6 +1,6 @@ use core::intrinsics; -// NOTE This function and the one below are implemented using assembly because they using a custom +// NOTE This function and the ones below are implemented using assembly because they using a custom // calling convention which can't be implemented using a normal Rust function #[naked] #[cfg_attr(not(test), no_mangle)] @@ -30,6 +30,44 @@ pub unsafe fn __aeabi_uldivmod() { intrinsics::unreachable(); } +#[naked] +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn __aeabi_idivmod() { + asm!("push {r0, r1, r4, lr} + bl __divsi3 + pop {r1, r2} + muls r2, r2, r0 + subs r1, r1, r2 + pop {r4, pc}"); + intrinsics::unreachable(); +} + +#[naked] +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn __aeabi_ldivmod() { + asm!("push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] + bl __divmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc}"); + intrinsics::unreachable(); +} + +// TODO: These two functions should be defined as aliases +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { + ::udiv::__udivsi3(a, b) +} + +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 { + ::sdiv::__divsi3(a, b) +} + extern "C" { fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 2263fda0003..e61a75d88df 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -24,6 +24,7 @@ extern crate rlibc; pub mod arm; pub mod udiv; +pub mod sdiv; pub mod mul; pub mod shift; diff --git a/library/compiler-builtins/src/mul.rs b/library/compiler-builtins/src/mul.rs index 77dba26ec3c..73c1a6f78dd 100644 --- a/library/compiler-builtins/src/mul.rs +++ b/library/compiler-builtins/src/mul.rs @@ -4,7 +4,7 @@ macro_rules! mul { ($intrinsic:ident: $ty:ty) => { /// Returns `a * b` #[cfg_attr(not(test), no_mangle)] - pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { let half_bits = <$ty>::bits() / 4; let lower_mask = !0 >> half_bits; let mut low = (a.low() & lower_mask) * (b.low() & lower_mask); @@ -29,7 +29,7 @@ macro_rules! mulo { ($intrinsic:ident: $ty:ty) => { /// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows #[cfg_attr(not(test), no_mangle)] - pub extern fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty { + pub extern "C" fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty { *overflow = 0; let result = a.wrapping_mul(b); if a == <$ty>::min_value() { diff --git a/library/compiler-builtins/src/sdiv.rs b/library/compiler-builtins/src/sdiv.rs new file mode 100644 index 00000000000..b1231618b79 --- /dev/null +++ b/library/compiler-builtins/src/sdiv.rs @@ -0,0 +1,121 @@ +use Int; + +macro_rules! div { + ($intrinsic:ident: $ty:ty, $uty:ty) => { + /// Returns `a / b` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + let s_a = a >> (<$ty>::bits() - 1); + let s_b = b >> (<$ty>::bits() - 1); + let a = (a ^ s_a) - s_a; + let b = (b ^ s_b) - s_b; + let s = s_a ^ s_b; + let r = (a as $uty) / (b as $uty); + (r as $ty ^ s) - s + } + } +} + +macro_rules! mod_ { + ($intrinsic:ident: $ty:ty, $uty:ty) => { + /// Returns `a % b` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + let s = b >> (<$ty>::bits() - 1); + let b = (b ^ s) - s; + let s = a >> (<$ty>::bits() - 1); + let a = (a ^ s) - s; + let r = (a as $uty) % (b as $uty); + (r as $ty ^ s) - s + } + } +} + +macro_rules! divmod { + ($intrinsic:ident, $div:ident: $ty:ty) => { + /// Returns `a / b` and sets `*rem = n % d` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty { + let r = $div(a, b); + *rem = a - (r * b); + r + } + } +} + +div!(__divsi3: i32, u32); +div!(__divdi3: i64, u64); +mod_!(__modsi3: i32, u32); +mod_!(__moddi3: i64, u64); +divmod!(__divmodsi4, __divsi3: i32); +divmod!(__divmoddi4, __divdi3: i64); + +#[cfg(test)] +mod tests { + use quickcheck::TestResult; + use qc::{U32, U64}; + + quickcheck!{ + fn divdi3(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0 as i64, d.0 as i64); + if d == 0 { + TestResult::discard() + } else { + let q = super::__divdi3(n, d); + TestResult::from_bool(q == n / d) + } + } + + fn moddi3(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0 as i64, d.0 as i64); + if d == 0 { + TestResult::discard() + } else { + let r = super::__moddi3(n, d); + TestResult::from_bool(r == n % d) + } + } + + fn divmoddi4(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0 as i64, d.0 as i64); + if d == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = super::__divmoddi4(n, d, &mut r); + TestResult::from_bool(q == n / d && r == n % d) + } + } + + fn divsi3(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0 as i32, d.0 as i32); + if d == 0 { + TestResult::discard() + } else { + let q = super::__divsi3(n, d); + TestResult::from_bool(q == n / d) + } + } + + fn modsi3(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0 as i32, d.0 as i32); + if d == 0 { + TestResult::discard() + } else { + let r = super::__modsi3(n, d); + TestResult::from_bool(r == n % d) + } + } + + fn divmodsi4(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0 as i32, d.0 as i32); + if d == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = super::__divmodsi4(n, d, &mut r); + TestResult::from_bool(q == n / d && r == n % d) + } + } + } +} diff --git a/library/compiler-builtins/src/shift.rs b/library/compiler-builtins/src/shift.rs index 7fa88abffb2..ccbfe13fae0 100644 --- a/library/compiler-builtins/src/shift.rs +++ b/library/compiler-builtins/src/shift.rs @@ -4,7 +4,7 @@ macro_rules! ashl { ($intrinsic:ident: $ty:ty) => { /// Returns `a << b`, requires `b < $ty::bits()` #[cfg_attr(not(test), no_mangle)] - pub extern fn $intrinsic(a: $ty, b: u32) -> $ty { + pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { let half_bits = <$ty>::bits() / 2; if b & half_bits != 0 { <$ty>::from_parts(0, a.low() << (b - half_bits)) @@ -21,7 +21,7 @@ macro_rules! ashr { ($intrinsic:ident: $ty:ty) => { /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` #[cfg_attr(not(test), no_mangle)] - pub extern fn $intrinsic(a: $ty, b: u32) -> $ty { + pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { let half_bits = <$ty>::bits() / 2; if b & half_bits != 0 { <$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf, @@ -41,7 +41,7 @@ macro_rules! lshr { ($intrinsic:ident: $ty:ty) => { /// Returns logical `a >> b`, requires `b < $ty::bits()` #[cfg_attr(not(test), no_mangle)] - pub extern fn $intrinsic(a: $ty, b: u32) -> $ty { + pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { let half_bits = <$ty>::bits() / 2; if b & half_bits != 0 { <$ty>::from_parts(a.high() >> (b - half_bits), 0) -- cgit 1.4.1-3-g733a5 From 59fe09c493d03174f50ef08d902a355602c8ebd8 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 19 Aug 2016 12:12:07 +0100 Subject: Add tests for ARM division builtins --- library/compiler-builtins/src/arm.rs | 81 ++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 285871f15e5..4555d5b1302 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -128,3 +128,84 @@ pub unsafe extern "C" fn __aeabi_memclr4(dest: *mut u8, n: usize) { pub unsafe extern "C" fn __aeabi_memclr8(dest: *mut u8, n: usize) { memset(dest, 0, n); } + + +#[cfg(test)] +mod tests { + use quickcheck::TestResult; + use qc::{U32, U64}; + + quickcheck!{ + fn uldivmod(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0, d.0); + if d == 0 { + TestResult::discard() + } else { + let q: u64; + let r: u64; + unsafe { + // The inline asm is a bit tricky here, LLVM will allocate + // both r0 and r1 when we specify a 64-bit value for {r0}. + asm!("bl __aeabi_uldivmod" + : "={r0}" (q), "={r2}" (r) + : "{r0}" (n), "{r2}" (d) + : "r12", "lr", "flags"); + } + TestResult::from_bool(q == n / d && r == n % d) + } + } + + fn uidivmod(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0, d.0); + if d == 0 { + TestResult::discard() + } else { + let q: u32; + let r: u32; + unsafe { + asm!("bl __aeabi_uidivmod" + : "={r0}" (q), "={r1}" (r) + : "{r0}" (n), "{r1}" (d) + : "r2", "r3", "r12", "lr", "flags"); + } + TestResult::from_bool(q == n / d && r == n % d) + } + } + + fn ldivmod(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0 as i64, d.0 as i64); + if d == 0 { + TestResult::discard() + } else { + let q: i64; + let r: i64; + unsafe { + // The inline asm is a bit tricky here, LLVM will allocate + // both r0 and r1 when we specify a 64-bit value for {r0}. + asm!("bl __aeabi_ldivmod" + : "={r0}" (q), "={r2}" (r) + : "{r0}" (n), "{r2}" (d) + : "r12", "lr", "flags"); + } + TestResult::from_bool(q == n / d && r == n % d) + } + } + + fn idivmod(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0 as i32, d.0 as i32); + if d == 0 { + TestResult::discard() + } else { + let q: i32; + let r: i32; + unsafe { + asm!("bl __aeabi_idivmod" + : "={r0}" (q), "={r1}" (r) + : "{r0}" (n), "{r1}" (d) + : "r2", "r3", "r12", "lr", "flags"); + } + TestResult::from_bool(q == n / d && r == n % d) + } + } + } +} -- cgit 1.4.1-3-g733a5 From 35d68d8ab23069005002dd2107219f867917f0fc Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 15:50:24 -0500 Subject: Move integer functions to separate module --- library/compiler-builtins/src/arm.rs | 4 +- library/compiler-builtins/src/int/mod.rs | 73 +++++++ library/compiler-builtins/src/int/mul.rs | 104 ++++++++++ library/compiler-builtins/src/int/sdiv.rs | 121 ++++++++++++ library/compiler-builtins/src/int/shift.rs | 98 ++++++++++ library/compiler-builtins/src/int/udiv.rs | 297 +++++++++++++++++++++++++++++ library/compiler-builtins/src/lib.rs | 73 +------ library/compiler-builtins/src/mul.rs | 104 ---------- library/compiler-builtins/src/qc.rs | 2 +- library/compiler-builtins/src/sdiv.rs | 121 ------------ library/compiler-builtins/src/shift.rs | 98 ---------- library/compiler-builtins/src/udiv.rs | 297 ----------------------------- 12 files changed, 698 insertions(+), 694 deletions(-) create mode 100644 library/compiler-builtins/src/int/mod.rs create mode 100644 library/compiler-builtins/src/int/mul.rs create mode 100644 library/compiler-builtins/src/int/sdiv.rs create mode 100644 library/compiler-builtins/src/int/shift.rs create mode 100644 library/compiler-builtins/src/int/udiv.rs delete mode 100644 library/compiler-builtins/src/mul.rs delete mode 100644 library/compiler-builtins/src/sdiv.rs delete mode 100644 library/compiler-builtins/src/shift.rs delete mode 100644 library/compiler-builtins/src/udiv.rs diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 4555d5b1302..b46b0ea77f5 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -60,12 +60,12 @@ pub unsafe fn __aeabi_ldivmod() { // TODO: These two functions should be defined as aliases #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { - ::udiv::__udivsi3(a, b) + ::int::udiv::__udivsi3(a, b) } #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 { - ::sdiv::__divsi3(a, b) + ::int::sdiv::__divsi3(a, b) } extern "C" { diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs new file mode 100644 index 00000000000..37e05377a2e --- /dev/null +++ b/library/compiler-builtins/src/int/mod.rs @@ -0,0 +1,73 @@ + +pub mod mul; +pub mod sdiv; +pub mod shift; +pub mod udiv; + +/// Trait for some basic operations on integers +pub trait Int { + /// Returns the bitwidth of the int type + fn bits() -> u32; +} + +// TODO: Once i128/u128 support lands, we'll want to add impls for those as well +impl Int for u32 { + fn bits() -> u32 { + 32 + } +} +impl Int for i32 { + fn bits() -> u32 { + 32 + } +} +impl Int for u64 { + fn bits() -> u32 { + 64 + } +} +impl Int for i64 { + fn bits() -> u32 { + 64 + } +} + +/// Trait to convert an integer to/from smaller parts +pub trait LargeInt { + type LowHalf; + type HighHalf; + + fn low(self) -> Self::LowHalf; + fn high(self) -> Self::HighHalf; + fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; +} + +// TODO: Once i128/u128 support lands, we'll want to add impls for those as well +impl LargeInt for u64 { + type LowHalf = u32; + type HighHalf = u32; + + fn low(self) -> u32 { + self as u32 + } + fn high(self) -> u32 { + (self >> 32) as u32 + } + fn from_parts(low: u32, high: u32) -> u64 { + low as u64 | ((high as u64) << 32) + } +} +impl LargeInt for i64 { + type LowHalf = u32; + type HighHalf = i32; + + fn low(self) -> u32 { + self as u32 + } + fn high(self) -> i32 { + (self >> 32) as i32 + } + fn from_parts(low: u32, high: i32) -> i64 { + low as i64 | ((high as i64) << 32) + } +} diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs new file mode 100644 index 00000000000..3d6844473b9 --- /dev/null +++ b/library/compiler-builtins/src/int/mul.rs @@ -0,0 +1,104 @@ +use int::{Int, LargeInt}; + +macro_rules! mul { + ($intrinsic:ident: $ty:ty) => { + /// Returns `a * b` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + let half_bits = <$ty>::bits() / 4; + let lower_mask = !0 >> half_bits; + let mut low = (a.low() & lower_mask) * (b.low() & lower_mask); + let mut t = low >> half_bits; + low &= lower_mask; + t += (a.low() >> half_bits) * (b.low() & lower_mask); + low += (t & lower_mask) << half_bits; + let mut high = t >> half_bits; + t = low >> half_bits; + low &= lower_mask; + t += (b.low() >> half_bits) * (a.low() & lower_mask); + low += (t & lower_mask) << half_bits; + high += t >> half_bits; + high += (a.low() >> half_bits) * (b.low() >> half_bits); + high = high.wrapping_add(a.high().wrapping_mul(b.low()).wrapping_add(a.low().wrapping_mul(b.high()))); + <$ty>::from_parts(low, high) + } + } +} + +macro_rules! mulo { + ($intrinsic:ident: $ty:ty) => { + /// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty { + *overflow = 0; + let result = a.wrapping_mul(b); + if a == <$ty>::min_value() { + if b != 0 && b != 1 { + *overflow = 1; + } + return result; + } + if b == <$ty>::min_value() { + if a != 0 && a != 1 { + *overflow = 1; + } + return result; + } + + let sa = a >> (<$ty>::bits() - 1); + let abs_a = (a ^ sa) - sa; + let sb = b >> (<$ty>::bits() - 1); + let abs_b = (b ^ sb) - sb; + if abs_a < 2 || abs_b < 2 { + return result; + } + if sa == sb { + if abs_a > <$ty>::max_value() / abs_b { + *overflow = 1; + } + } else { + if abs_a > <$ty>::min_value() / -abs_b { + *overflow = 1; + } + } + result + } + } +} + +mul!(__muldi3: u64); +mulo!(__mulosi4: i32); +mulo!(__mulodi4: i64); + +#[cfg(test)] +mod tests { + use qc::{I32, I64, U64}; + + quickcheck! { + fn muldi(a: U64, b: U64) -> bool { + let (a, b) = (a.0, b.0); + let r = super::__muldi3(a, b); + r == a.wrapping_mul(b) + } + + fn mulosi(a: I32, b: I32) -> bool { + let (a, b) = (a.0, b.0); + let mut overflow = 2; + let r = super::__mulosi4(a, b, &mut overflow); + if overflow != 0 && overflow != 1 { + return false; + } + (r, overflow != 0) == a.overflowing_mul(b) + } + + fn mulodi(a: I64, b: I64) -> bool { + let (a, b) = (a.0, b.0); + let mut overflow = 2; + let r = super::__mulodi4(a, b, &mut overflow); + if overflow != 0 && overflow != 1 { + return false; + } + (r, overflow != 0) == a.overflowing_mul(b) + } + } +} diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs new file mode 100644 index 00000000000..72ddbca5d5b --- /dev/null +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -0,0 +1,121 @@ +use int::Int; + +macro_rules! div { + ($intrinsic:ident: $ty:ty, $uty:ty) => { + /// Returns `a / b` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + let s_a = a >> (<$ty>::bits() - 1); + let s_b = b >> (<$ty>::bits() - 1); + let a = (a ^ s_a) - s_a; + let b = (b ^ s_b) - s_b; + let s = s_a ^ s_b; + let r = (a as $uty) / (b as $uty); + (r as $ty ^ s) - s + } + } +} + +macro_rules! mod_ { + ($intrinsic:ident: $ty:ty, $uty:ty) => { + /// Returns `a % b` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + let s = b >> (<$ty>::bits() - 1); + let b = (b ^ s) - s; + let s = a >> (<$ty>::bits() - 1); + let a = (a ^ s) - s; + let r = (a as $uty) % (b as $uty); + (r as $ty ^ s) - s + } + } +} + +macro_rules! divmod { + ($intrinsic:ident, $div:ident: $ty:ty) => { + /// Returns `a / b` and sets `*rem = n % d` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty { + let r = $div(a, b); + *rem = a - (r * b); + r + } + } +} + +div!(__divsi3: i32, u32); +div!(__divdi3: i64, u64); +mod_!(__modsi3: i32, u32); +mod_!(__moddi3: i64, u64); +divmod!(__divmodsi4, __divsi3: i32); +divmod!(__divmoddi4, __divdi3: i64); + +#[cfg(test)] +mod tests { + use quickcheck::TestResult; + use qc::{U32, U64}; + + quickcheck!{ + fn divdi3(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0 as i64, d.0 as i64); + if d == 0 { + TestResult::discard() + } else { + let q = super::__divdi3(n, d); + TestResult::from_bool(q == n / d) + } + } + + fn moddi3(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0 as i64, d.0 as i64); + if d == 0 { + TestResult::discard() + } else { + let r = super::__moddi3(n, d); + TestResult::from_bool(r == n % d) + } + } + + fn divmoddi4(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0 as i64, d.0 as i64); + if d == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = super::__divmoddi4(n, d, &mut r); + TestResult::from_bool(q == n / d && r == n % d) + } + } + + fn divsi3(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0 as i32, d.0 as i32); + if d == 0 { + TestResult::discard() + } else { + let q = super::__divsi3(n, d); + TestResult::from_bool(q == n / d) + } + } + + fn modsi3(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0 as i32, d.0 as i32); + if d == 0 { + TestResult::discard() + } else { + let r = super::__modsi3(n, d); + TestResult::from_bool(r == n % d) + } + } + + fn divmodsi4(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0 as i32, d.0 as i32); + if d == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = super::__divmodsi4(n, d, &mut r); + TestResult::from_bool(q == n / d && r == n % d) + } + } + } +} diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs new file mode 100644 index 00000000000..96ae6dbad25 --- /dev/null +++ b/library/compiler-builtins/src/int/shift.rs @@ -0,0 +1,98 @@ +use int::{Int, LargeInt}; + +macro_rules! ashl { + ($intrinsic:ident: $ty:ty) => { + /// Returns `a << b`, requires `b < $ty::bits()` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { + let half_bits = <$ty>::bits() / 2; + if b & half_bits != 0 { + <$ty>::from_parts(0, a.low() << (b - half_bits)) + } else if b == 0 { + a + } else { + <$ty>::from_parts(a.low() << b, (a.high() << b) | (a.low() >> (half_bits - b))) + } + } + } +} + +macro_rules! ashr { + ($intrinsic:ident: $ty:ty) => { + /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { + let half_bits = <$ty>::bits() / 2; + if b & half_bits != 0 { + <$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf, + a.high() >> (half_bits - 1)) + } else if b == 0 { + a + } else { + let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf; + <$ty>::from_parts((high_unsigned << (half_bits - b)) | (a.low() >> b), + a.high() >> b) + } + } + } +} + +macro_rules! lshr { + ($intrinsic:ident: $ty:ty) => { + /// Returns logical `a >> b`, requires `b < $ty::bits()` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { + let half_bits = <$ty>::bits() / 2; + if b & half_bits != 0 { + <$ty>::from_parts(a.high() >> (b - half_bits), 0) + } else if b == 0 { + a + } else { + <$ty>::from_parts((a.high() << (half_bits - b)) | (a.low() >> b), a.high() >> b) + } + } + } +} + +ashl!(__ashldi3: u64); +ashr!(__ashrdi3: i64); +lshr!(__lshrdi3: u64); + +#[cfg(test)] +mod tests { + use quickcheck::TestResult; + use qc::{I64, U64}; + + // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) + quickcheck! { + fn ashldi(a: U64, b: u32) -> TestResult { + let a = a.0; + if b >= 64 { + TestResult::discard() + } else { + let r = super::__ashldi3(a, b); + TestResult::from_bool(r == a << b) + } + } + + fn ashrdi(a: I64, b: u32) -> TestResult { + let a = a.0; + if b >= 64 { + TestResult::discard() + } else { + let r = super::__ashrdi3(a, b); + TestResult::from_bool(r == a >> b) + } + } + + fn lshrdi(a: U64, b: u32) -> TestResult { + let a = a.0; + if b >= 64 { + TestResult::discard() + } else { + let r = super::__lshrdi3(a, b); + TestResult::from_bool(r == a >> b) + } + } + } +} diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs new file mode 100644 index 00000000000..f3ec720c105 --- /dev/null +++ b/library/compiler-builtins/src/int/udiv.rs @@ -0,0 +1,297 @@ +use core::mem; +use int::{Int, LargeInt}; + +/// Returns `n / d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { + // Special cases + if d == 0 { + panic!("Division by zero"); + } + + if n == 0 { + return 0; + } + + let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); + + // d > n + if sr > u32::bits() - 1 { + return 0; + } + + // d == 1 + if sr == u32::bits() - 1 { + return n; + } + + sr += 1; + + // 1 <= sr <= u32::bits() - 1 + let mut q = n << (u32::bits() - sr); + let mut r = n >> sr; + + let mut carry = 0; + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (u32::bits() - 1)); + q = (q << 1) | carry; + + // carry = 0; + // if r > d { + // r -= d; + // carry = 1; + // } + + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::bits() - 1); + carry = (s & 1) as u32; + r -= d & s as u32; + } + + (q << 1) | carry +} + +/// Returns `n % d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { + n - __udivsi3(n, d) * d +} + +/// Returns `n / d` and sets `*rem = n % d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { + let q = __udivsi3(n, d); + if let Some(rem) = rem { + *rem = n - (q * d); + } + q +} + +/// Returns `n / d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { + __udivmoddi4(n, d, None) +} + +/// Returns `n % d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 { + let mut rem = unsafe { mem::uninitialized() }; + __udivmoddi4(a, b, Some(&mut rem)); + rem +} + +/// Returns `n / d` and sets `*rem = n % d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { + // NOTE X is unknown, K != 0 + if n.high() == 0 { + if d.high() == 0 { + // 0 X + // --- + // 0 X + if let Some(rem) = rem { + *rem = u64::from(n.low() % d.low()); + } + return u64::from(n.low() / d.low()); + } else { + // 0 X + // --- + // K X + if let Some(rem) = rem { + *rem = n; + } + return 0; + }; + } + + let mut sr; + let mut q; + let mut r; + + if d.low() == 0 { + if d.high() == 0 { + // K X + // --- + // 0 0 + panic!("Division by zero"); + } + + if n.low() == 0 { + // K 0 + // --- + // K 0 + if let Some(rem) = rem { + *rem = u64::from_parts(0, n.high() % d.high()); + } + return u64::from(n.high() / d.high()); + } + + // K K + // --- + // K 0 + + if d.high().is_power_of_two() { + if let Some(rem) = rem { + *rem = u64::from_parts(n.low(), n.high() & (d.high() - 1)); + } + return u64::from(n.high() >> d.high().trailing_zeros()); + } + + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > u32::bits() - 2 { + if let Some(rem) = rem { + *rem = n; + } + return 0; + } + + sr += 1; + + // 1 <= sr <= u32::bits() - 1 + q = n << (u64::bits() - sr); + r = n >> sr; + } else { + if d.high() == 0 { + // K X + // --- + // 0 K + if d.low().is_power_of_two() { + if let Some(rem) = rem { + *rem = u64::from(n.low() & (d.low() - 1)); + } + + if d.low() == 1 { + return n; + } else { + let sr = d.low().trailing_zeros(); + return n >> sr; + }; + } + + sr = 1 + u32::bits() + d.low().leading_zeros() - n.high().leading_zeros(); + + // 2 <= sr <= u64::bits() - 1 + q = n << (u64::bits() - sr); + r = n >> sr; + } else { + // K X + // --- + // K K + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > u32::bits() - 1 { + if let Some(rem) = rem { + *rem = n; + } + return 0; + } + + sr += 1; + + // 1 <= sr <= u32::bits() + q = n << (u64::bits() - sr); + r = n >> sr; + } + } + + // Not a special case + // q and r are initialized with + // q = n << (u64::bits() - sr) + // r = n >> sr + // 1 <= sr <= u64::bits() - 1 + let mut carry = 0; + + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (u64::bits() - 1)); + q = (q << 1) | carry as u64; + + // carry = 0 + // if r >= d { + // r -= d; + // carry = 1; + // } + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i64 >> (u64::bits() - 1); + carry = (s & 1) as u32; + r -= d & s as u64; + } + + if let Some(rem) = rem { + *rem = r; + } + (q << 1) | carry as u64 +} + +#[cfg(test)] +mod tests { + use quickcheck::TestResult; + use qc::{U32, U64}; + + quickcheck!{ + fn udivdi3(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0, d.0); + if d == 0 { + TestResult::discard() + } else { + let q = super::__udivdi3(n, d); + TestResult::from_bool(q == n / d) + } + } + + fn umoddi3(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0, d.0); + if d == 0 { + TestResult::discard() + } else { + let r = super::__umoddi3(n, d); + TestResult::from_bool(r == n % d) + } + } + + fn udivmoddi4(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0, d.0); + if d == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = super::__udivmoddi4(n, d, Some(&mut r)); + TestResult::from_bool(q == n / d && r == n % d) + } + } + + fn udivsi3(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0, d.0); + if d == 0 { + TestResult::discard() + } else { + let q = super::__udivsi3(n, d); + TestResult::from_bool(q == n / d) + } + } + + fn umodsi3(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0, d.0); + if d == 0 { + TestResult::discard() + } else { + let r = super::__umodsi3(n, d); + TestResult::from_bool(r == n % d) + } + } + + fn udivmodsi4(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0, d.0); + if d == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = super::__udivmodsi4(n, d, Some(&mut r)); + TestResult::from_bool(q == n / d && r == n % d) + } + } + } +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 1351c389685..b817d74fda6 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -20,83 +20,14 @@ extern crate core; #[cfg(all(not(windows), not(target_os = "macos")))] extern crate rlibc; +pub mod int; + #[cfg(target_arch = "arm")] pub mod arm; #[cfg(target_arch = "x86_64")] pub mod x86_64; -pub mod udiv; -pub mod sdiv; -pub mod mul; -pub mod shift; - #[cfg(test)] mod qc; -/// Trait for some basic operations on integers -trait Int { - fn bits() -> u32; -} - -// TODO: Once i128/u128 support lands, we'll want to add impls for those as well -impl Int for u32 { - fn bits() -> u32 { - 32 - } -} -impl Int for i32 { - fn bits() -> u32 { - 32 - } -} -impl Int for u64 { - fn bits() -> u32 { - 64 - } -} -impl Int for i64 { - fn bits() -> u32 { - 64 - } -} - -/// Trait to convert an integer to/from smaller parts -trait LargeInt { - type LowHalf; - type HighHalf; - - fn low(self) -> Self::LowHalf; - fn high(self) -> Self::HighHalf; - fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; -} - -// TODO: Once i128/u128 support lands, we'll want to add impls for those as well -impl LargeInt for u64 { - type LowHalf = u32; - type HighHalf = u32; - - fn low(self) -> u32 { - self as u32 - } - fn high(self) -> u32 { - (self >> 32) as u32 - } - fn from_parts(low: u32, high: u32) -> u64 { - low as u64 | ((high as u64) << 32) - } -} -impl LargeInt for i64 { - type LowHalf = u32; - type HighHalf = i32; - - fn low(self) -> u32 { - self as u32 - } - fn high(self) -> i32 { - (self >> 32) as i32 - } - fn from_parts(low: u32, high: i32) -> i64 { - low as i64 | ((high as i64) << 32) - } -} diff --git a/library/compiler-builtins/src/mul.rs b/library/compiler-builtins/src/mul.rs deleted file mode 100644 index 2c4ce52ed93..00000000000 --- a/library/compiler-builtins/src/mul.rs +++ /dev/null @@ -1,104 +0,0 @@ -use {Int, LargeInt}; - -macro_rules! mul { - ($intrinsic:ident: $ty:ty) => { - /// Returns `a * b` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { - let half_bits = <$ty>::bits() / 4; - let lower_mask = !0 >> half_bits; - let mut low = (a.low() & lower_mask) * (b.low() & lower_mask); - let mut t = low >> half_bits; - low &= lower_mask; - t += (a.low() >> half_bits) * (b.low() & lower_mask); - low += (t & lower_mask) << half_bits; - let mut high = t >> half_bits; - t = low >> half_bits; - low &= lower_mask; - t += (b.low() >> half_bits) * (a.low() & lower_mask); - low += (t & lower_mask) << half_bits; - high += t >> half_bits; - high += (a.low() >> half_bits) * (b.low() >> half_bits); - high = high.wrapping_add(a.high().wrapping_mul(b.low()).wrapping_add(a.low().wrapping_mul(b.high()))); - <$ty>::from_parts(low, high) - } - } -} - -macro_rules! mulo { - ($intrinsic:ident: $ty:ty) => { - /// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty { - *overflow = 0; - let result = a.wrapping_mul(b); - if a == <$ty>::min_value() { - if b != 0 && b != 1 { - *overflow = 1; - } - return result; - } - if b == <$ty>::min_value() { - if a != 0 && a != 1 { - *overflow = 1; - } - return result; - } - - let sa = a >> (<$ty>::bits() - 1); - let abs_a = (a ^ sa) - sa; - let sb = b >> (<$ty>::bits() - 1); - let abs_b = (b ^ sb) - sb; - if abs_a < 2 || abs_b < 2 { - return result; - } - if sa == sb { - if abs_a > <$ty>::max_value() / abs_b { - *overflow = 1; - } - } else { - if abs_a > <$ty>::min_value() / -abs_b { - *overflow = 1; - } - } - result - } - } -} - -mul!(__muldi3: u64); -mulo!(__mulosi4: i32); -mulo!(__mulodi4: i64); - -#[cfg(test)] -mod tests { - use qc::{I32, I64, U64}; - - quickcheck! { - fn muldi(a: U64, b: U64) -> bool { - let (a, b) = (a.0, b.0); - let r = super::__muldi3(a, b); - r == a.wrapping_mul(b) - } - - fn mulosi(a: I32, b: I32) -> bool { - let (a, b) = (a.0, b.0); - let mut overflow = 2; - let r = super::__mulosi4(a, b, &mut overflow); - if overflow != 0 && overflow != 1 { - return false; - } - (r, overflow != 0) == a.overflowing_mul(b) - } - - fn mulodi(a: I64, b: I64) -> bool { - let (a, b) = (a.0, b.0); - let mut overflow = 2; - let r = super::__mulodi4(a, b, &mut overflow); - if overflow != 0 && overflow != 1 { - return false; - } - (r, overflow != 0) == a.overflowing_mul(b) - } - } -} diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 6b37cceb7fd..eccde7650cc 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -8,7 +8,7 @@ use std::fmt; use quickcheck::{Arbitrary, Gen}; -use LargeInt; +use int::LargeInt; // Generates values in the full range of the integer type macro_rules! arbitrary { diff --git a/library/compiler-builtins/src/sdiv.rs b/library/compiler-builtins/src/sdiv.rs deleted file mode 100644 index b1231618b79..00000000000 --- a/library/compiler-builtins/src/sdiv.rs +++ /dev/null @@ -1,121 +0,0 @@ -use Int; - -macro_rules! div { - ($intrinsic:ident: $ty:ty, $uty:ty) => { - /// Returns `a / b` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { - let s_a = a >> (<$ty>::bits() - 1); - let s_b = b >> (<$ty>::bits() - 1); - let a = (a ^ s_a) - s_a; - let b = (b ^ s_b) - s_b; - let s = s_a ^ s_b; - let r = (a as $uty) / (b as $uty); - (r as $ty ^ s) - s - } - } -} - -macro_rules! mod_ { - ($intrinsic:ident: $ty:ty, $uty:ty) => { - /// Returns `a % b` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { - let s = b >> (<$ty>::bits() - 1); - let b = (b ^ s) - s; - let s = a >> (<$ty>::bits() - 1); - let a = (a ^ s) - s; - let r = (a as $uty) % (b as $uty); - (r as $ty ^ s) - s - } - } -} - -macro_rules! divmod { - ($intrinsic:ident, $div:ident: $ty:ty) => { - /// Returns `a / b` and sets `*rem = n % d` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty { - let r = $div(a, b); - *rem = a - (r * b); - r - } - } -} - -div!(__divsi3: i32, u32); -div!(__divdi3: i64, u64); -mod_!(__modsi3: i32, u32); -mod_!(__moddi3: i64, u64); -divmod!(__divmodsi4, __divsi3: i32); -divmod!(__divmoddi4, __divdi3: i64); - -#[cfg(test)] -mod tests { - use quickcheck::TestResult; - use qc::{U32, U64}; - - quickcheck!{ - fn divdi3(n: U64, d: U64) -> TestResult { - let (n, d) = (n.0 as i64, d.0 as i64); - if d == 0 { - TestResult::discard() - } else { - let q = super::__divdi3(n, d); - TestResult::from_bool(q == n / d) - } - } - - fn moddi3(n: U64, d: U64) -> TestResult { - let (n, d) = (n.0 as i64, d.0 as i64); - if d == 0 { - TestResult::discard() - } else { - let r = super::__moddi3(n, d); - TestResult::from_bool(r == n % d) - } - } - - fn divmoddi4(n: U64, d: U64) -> TestResult { - let (n, d) = (n.0 as i64, d.0 as i64); - if d == 0 { - TestResult::discard() - } else { - let mut r = 0; - let q = super::__divmoddi4(n, d, &mut r); - TestResult::from_bool(q == n / d && r == n % d) - } - } - - fn divsi3(n: U32, d: U32) -> TestResult { - let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 { - TestResult::discard() - } else { - let q = super::__divsi3(n, d); - TestResult::from_bool(q == n / d) - } - } - - fn modsi3(n: U32, d: U32) -> TestResult { - let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 { - TestResult::discard() - } else { - let r = super::__modsi3(n, d); - TestResult::from_bool(r == n % d) - } - } - - fn divmodsi4(n: U32, d: U32) -> TestResult { - let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 { - TestResult::discard() - } else { - let mut r = 0; - let q = super::__divmodsi4(n, d, &mut r); - TestResult::from_bool(q == n / d && r == n % d) - } - } - } -} diff --git a/library/compiler-builtins/src/shift.rs b/library/compiler-builtins/src/shift.rs deleted file mode 100644 index ccbfe13fae0..00000000000 --- a/library/compiler-builtins/src/shift.rs +++ /dev/null @@ -1,98 +0,0 @@ -use {Int, LargeInt}; - -macro_rules! ashl { - ($intrinsic:ident: $ty:ty) => { - /// Returns `a << b`, requires `b < $ty::bits()` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { - let half_bits = <$ty>::bits() / 2; - if b & half_bits != 0 { - <$ty>::from_parts(0, a.low() << (b - half_bits)) - } else if b == 0 { - a - } else { - <$ty>::from_parts(a.low() << b, (a.high() << b) | (a.low() >> (half_bits - b))) - } - } - } -} - -macro_rules! ashr { - ($intrinsic:ident: $ty:ty) => { - /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { - let half_bits = <$ty>::bits() / 2; - if b & half_bits != 0 { - <$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf, - a.high() >> (half_bits - 1)) - } else if b == 0 { - a - } else { - let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf; - <$ty>::from_parts((high_unsigned << (half_bits - b)) | (a.low() >> b), - a.high() >> b) - } - } - } -} - -macro_rules! lshr { - ($intrinsic:ident: $ty:ty) => { - /// Returns logical `a >> b`, requires `b < $ty::bits()` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { - let half_bits = <$ty>::bits() / 2; - if b & half_bits != 0 { - <$ty>::from_parts(a.high() >> (b - half_bits), 0) - } else if b == 0 { - a - } else { - <$ty>::from_parts((a.high() << (half_bits - b)) | (a.low() >> b), a.high() >> b) - } - } - } -} - -ashl!(__ashldi3: u64); -ashr!(__ashrdi3: i64); -lshr!(__lshrdi3: u64); - -#[cfg(test)] -mod tests { - use quickcheck::TestResult; - use qc::{I64, U64}; - - // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) - quickcheck! { - fn ashldi(a: U64, b: u32) -> TestResult { - let a = a.0; - if b >= 64 { - TestResult::discard() - } else { - let r = super::__ashldi3(a, b); - TestResult::from_bool(r == a << b) - } - } - - fn ashrdi(a: I64, b: u32) -> TestResult { - let a = a.0; - if b >= 64 { - TestResult::discard() - } else { - let r = super::__ashrdi3(a, b); - TestResult::from_bool(r == a >> b) - } - } - - fn lshrdi(a: U64, b: u32) -> TestResult { - let a = a.0; - if b >= 64 { - TestResult::discard() - } else { - let r = super::__lshrdi3(a, b); - TestResult::from_bool(r == a >> b) - } - } - } -} diff --git a/library/compiler-builtins/src/udiv.rs b/library/compiler-builtins/src/udiv.rs deleted file mode 100644 index 82932e31314..00000000000 --- a/library/compiler-builtins/src/udiv.rs +++ /dev/null @@ -1,297 +0,0 @@ -use core::mem; -use {Int, LargeInt}; - -/// Returns `n / d` -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { - // Special cases - if d == 0 { - panic!("Division by zero"); - } - - if n == 0 { - return 0; - } - - let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); - - // d > n - if sr > u32::bits() - 1 { - return 0; - } - - // d == 1 - if sr == u32::bits() - 1 { - return n; - } - - sr += 1; - - // 1 <= sr <= u32::bits() - 1 - let mut q = n << (u32::bits() - sr); - let mut r = n >> sr; - - let mut carry = 0; - for _ in 0..sr { - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (u32::bits() - 1)); - q = (q << 1) | carry; - - // carry = 0; - // if r > d { - // r -= d; - // carry = 1; - // } - - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::bits() - 1); - carry = (s & 1) as u32; - r -= d & s as u32; - } - - (q << 1) | carry -} - -/// Returns `n % d` -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { - n - __udivsi3(n, d) * d -} - -/// Returns `n / d` and sets `*rem = n % d` -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { - let q = __udivsi3(n, d); - if let Some(rem) = rem { - *rem = n - (q * d); - } - q -} - -/// Returns `n / d` -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { - __udivmoddi4(n, d, None) -} - -/// Returns `n % d` -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 { - let mut rem = unsafe { mem::uninitialized() }; - __udivmoddi4(a, b, Some(&mut rem)); - rem -} - -/// Returns `n / d` and sets `*rem = n % d` -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { - // NOTE X is unknown, K != 0 - if n.high() == 0 { - if d.high() == 0 { - // 0 X - // --- - // 0 X - if let Some(rem) = rem { - *rem = u64::from(n.low() % d.low()); - } - return u64::from(n.low() / d.low()); - } else { - // 0 X - // --- - // K X - if let Some(rem) = rem { - *rem = n; - } - return 0; - }; - } - - let mut sr; - let mut q; - let mut r; - - if d.low() == 0 { - if d.high() == 0 { - // K X - // --- - // 0 0 - panic!("Division by zero"); - } - - if n.low() == 0 { - // K 0 - // --- - // K 0 - if let Some(rem) = rem { - *rem = u64::from_parts(0, n.high() % d.high()); - } - return u64::from(n.high() / d.high()); - } - - // K K - // --- - // K 0 - - if d.high().is_power_of_two() { - if let Some(rem) = rem { - *rem = u64::from_parts(n.low(), n.high() & (d.high() - 1)); - } - return u64::from(n.high() >> d.high().trailing_zeros()); - } - - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > u32::bits() - 2 { - if let Some(rem) = rem { - *rem = n; - } - return 0; - } - - sr += 1; - - // 1 <= sr <= u32::bits() - 1 - q = n << (u64::bits() - sr); - r = n >> sr; - } else { - if d.high() == 0 { - // K X - // --- - // 0 K - if d.low().is_power_of_two() { - if let Some(rem) = rem { - *rem = u64::from(n.low() & (d.low() - 1)); - } - - if d.low() == 1 { - return n; - } else { - let sr = d.low().trailing_zeros(); - return n >> sr; - }; - } - - sr = 1 + u32::bits() + d.low().leading_zeros() - n.high().leading_zeros(); - - // 2 <= sr <= u64::bits() - 1 - q = n << (u64::bits() - sr); - r = n >> sr; - } else { - // K X - // --- - // K K - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > u32::bits() - 1 { - if let Some(rem) = rem { - *rem = n; - } - return 0; - } - - sr += 1; - - // 1 <= sr <= u32::bits() - q = n << (u64::bits() - sr); - r = n >> sr; - } - } - - // Not a special case - // q and r are initialized with - // q = n << (u64::bits() - sr) - // r = n >> sr - // 1 <= sr <= u64::bits() - 1 - let mut carry = 0; - - for _ in 0..sr { - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (u64::bits() - 1)); - q = (q << 1) | carry as u64; - - // carry = 0 - // if r >= d { - // r -= d; - // carry = 1; - // } - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i64 >> (u64::bits() - 1); - carry = (s & 1) as u32; - r -= d & s as u64; - } - - if let Some(rem) = rem { - *rem = r; - } - (q << 1) | carry as u64 -} - -#[cfg(test)] -mod tests { - use quickcheck::TestResult; - use qc::{U32, U64}; - - quickcheck!{ - fn udivdi3(n: U64, d: U64) -> TestResult { - let (n, d) = (n.0, d.0); - if d == 0 { - TestResult::discard() - } else { - let q = super::__udivdi3(n, d); - TestResult::from_bool(q == n / d) - } - } - - fn umoddi3(n: U64, d: U64) -> TestResult { - let (n, d) = (n.0, d.0); - if d == 0 { - TestResult::discard() - } else { - let r = super::__umoddi3(n, d); - TestResult::from_bool(r == n % d) - } - } - - fn udivmoddi4(n: U64, d: U64) -> TestResult { - let (n, d) = (n.0, d.0); - if d == 0 { - TestResult::discard() - } else { - let mut r = 0; - let q = super::__udivmoddi4(n, d, Some(&mut r)); - TestResult::from_bool(q == n / d && r == n % d) - } - } - - fn udivsi3(n: U32, d: U32) -> TestResult { - let (n, d) = (n.0, d.0); - if d == 0 { - TestResult::discard() - } else { - let q = super::__udivsi3(n, d); - TestResult::from_bool(q == n / d) - } - } - - fn umodsi3(n: U32, d: U32) -> TestResult { - let (n, d) = (n.0, d.0); - if d == 0 { - TestResult::discard() - } else { - let r = super::__umodsi3(n, d); - TestResult::from_bool(r == n % d) - } - } - - fn udivmodsi4(n: U32, d: U32) -> TestResult { - let (n, d) = (n.0, d.0); - if d == 0 { - TestResult::discard() - } else { - let mut r = 0; - let q = super::__udivmodsi4(n, d, Some(&mut r)); - TestResult::from_bool(q == n / d && r == n % d) - } - } - } -} -- cgit 1.4.1-3-g733a5 From fe3c35131f7a83e2b2245bd462b77749b9010bfc Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 15:51:37 -0500 Subject: Implement soft float add builtins --- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/src/float/add.rs | 326 +++++++++++++++++++++++++++++ library/compiler-builtins/src/float/mod.rs | 65 ++++++ library/compiler-builtins/src/lib.rs | 1 + 4 files changed, 394 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/src/float/add.rs create mode 100644 library/compiler-builtins/src/float/mod.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 8f229a1370d..67e7b25433e 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -26,8 +26,8 @@ See [rust-lang/rust#35437][0]. ## Progress -- [ ] adddf3.c -- [ ] addsf3.c +- [x] adddf3.c +- [x] addsf3.c - [ ] arm/adddf3vfp.S - [ ] arm/addsf3vfp.S - [ ] arm/aeabi_dcmp.S diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs new file mode 100644 index 00000000000..3fffac35d7b --- /dev/null +++ b/library/compiler-builtins/src/float/add.rs @@ -0,0 +1,326 @@ +use core::num::Wrapping; +use float::Float; + +macro_rules! add { + ($intrinsic:ident: $ty:ty) => { + /// Returns `a + b` + #[allow(unused_parens)] + #[cfg_attr(not(test), no_mangle)] + pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { + let one = Wrapping(1 as <$ty as Float>::Int); + let zero = Wrapping(0 as <$ty as Float>::Int); + + let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); + let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); + let exponent_bits = bits - significand_bits - one; + let max_exponent = (one << exponent_bits.0 as usize) - one; + + let implicit_bit = one << significand_bits.0 as usize; + let significand_mask = implicit_bit - one; + let sign_bit = one << (significand_bits + exponent_bits).0 as usize; + let abs_mask = sign_bit - one; + let exponent_mask = abs_mask ^ significand_mask; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + + let mut a_rep = Wrapping(a.repr()); + let mut b_rep = Wrapping(b.repr()); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // Detect if a or b is zero, infinity, or NaN. + if a_abs - one >= inf_rep - one || + b_abs - one >= inf_rep - one { + // NaN + anything = qNaN + if a_abs > inf_rep { + return (<$ty as Float>::from_repr((a_abs | quiet_bit).0)); + } + // anything + NaN = qNaN + if b_abs > inf_rep { + return (<$ty as Float>::from_repr((b_abs | quiet_bit).0)); + } + + if a_abs == inf_rep { + // +/-infinity + -/+infinity = qNaN + if (a.repr() ^ b.repr()) == sign_bit.0 { + return (<$ty as Float>::from_repr(qnan_rep.0)); + } else { + // +/-infinity + anything remaining = +/- infinity + return a; + } + } + + // anything remaining + +/-infinity = +/-infinity + if b_abs == inf_rep { + return b; + } + + // zero + anything = anything + if a_abs.0 == 0 { + // but we need to get the sign right for zero + zero + if b_abs.0 == 0 { + return (<$ty as Float>::from_repr(a.repr() & b.repr())); + } else { + return b; + } + } + + // anything + zero = anything + if b_abs.0 == 0 { + return a; + } + } + + // Swap a and b if necessary so that a has the larger absolute value. + if b_abs > a_abs { + let temp = a_rep; + a_rep = b_rep; + b_rep = temp; + } + + // Extract the exponent and significand from the (possibly swapped) a and b. + let mut a_exponent = Wrapping((a_rep >> significand_bits.0 as usize & max_exponent).0 as i32); + let mut b_exponent = Wrapping((b_rep >> significand_bits.0 as usize & max_exponent).0 as i32); + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + + // normalize any denormals, and adjust the exponent accordingly. + if a_exponent.0 == 0 { + let (exponent, significand) = <$ty>::normalize(a_significand.0); + a_exponent = Wrapping(exponent); + a_significand = Wrapping(significand); + } + if b_exponent.0 == 0 { + let (exponent, significand) = <$ty>::normalize(b_significand.0); + b_exponent = Wrapping(exponent); + b_significand = Wrapping(significand); + } + + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + let result_sign = a_rep & sign_bit; + let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize(), but setting it twice won't hurt + // anything.) + a_significand = (a_significand | implicit_bit) << 3; + b_significand = (b_significand | implicit_bit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + let align = Wrapping((a_exponent - b_exponent).0 as <$ty as Float>::Int); + if align.0 != 0 { + if align < bits { + let sticky = ((b_significand << (bits - align).0 as usize).0 != 0) as <$ty as Float>::Int; + b_significand = (b_significand >> align.0 as usize) | Wrapping(sticky); + } else { + b_significand = one; // sticky; b is known to be non-zero. + } + } + if subtraction { + a_significand -= b_significand; + // If a == -b, return +zero. + if a_significand.0 == 0 { + return (<$ty as Float>::from_repr(0)); + } + + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if a_significand < implicit_bit << 3 { + let shift = a_significand.0.leading_zeros() as i32 + - (implicit_bit << 3).0.leading_zeros() as i32; + a_significand <<= shift as usize; + a_exponent -= Wrapping(shift); + } + } else /* addition */ { + a_significand += b_significand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if (a_significand & implicit_bit << 4).0 != 0 { + let sticky = ((a_significand & one).0 != 0) as <$ty as Float>::Int; + a_significand = a_significand >> 1 | Wrapping(sticky); + a_exponent += Wrapping(1); + } + } + + // If we have overflowed the type, return +/- infinity: + if a_exponent >= Wrapping(max_exponent.0 as i32) { + return (<$ty>::from_repr((inf_rep | result_sign).0)); + } + + if a_exponent.0 <= 0 { + // Result is denormal before rounding; the exponent is zero and we + // need to shift the significand. + let shift = Wrapping((Wrapping(1) - a_exponent).0 as <$ty as Float>::Int); + let sticky = ((a_significand << (bits - shift).0 as usize).0 != 0) as <$ty as Float>::Int; + a_significand = a_significand >> shift.0 as usize | Wrapping(sticky); + a_exponent = Wrapping(0); + } + + // Low three bits are round, guard, and sticky. + let round_guard_sticky: i32 = (a_significand.0 & 0x7) as i32; + + // Shift the significand into place, and mask off the implicit bit. + let mut result = a_significand >> 3 & significand_mask; + + // Insert the exponent and sign. + result |= Wrapping(a_exponent.0 as <$ty as Float>::Int) << significand_bits.0 as usize; + result |= result_sign; + + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if round_guard_sticky > 0x4 { result += one; } + if round_guard_sticky == 0x4 { result += result & one; } + return (<$ty>::from_repr(result.0)); + } + } +} + +add!(__addsf3: f32); +add!(__adddf3: f64); + +// FIXME: Implement these using aliases +#[cfg(target_arch = "arm")] +#[cfg_attr(not(test), no_mangle)] +pub extern fn __aeabi_dadd(a: f64, b: f64) -> f64 { + __adddf3(a, b) +} + +#[cfg(target_arch = "arm")] +#[cfg_attr(not(test), no_mangle)] +pub extern fn __aeabi_fadd(a: f32, b: f32) -> f32 { + __addsf3(a, b) +} + +#[cfg(test)] +mod tests { + use core::{f32, f64}; + use qc::{U32, U64}; + use float::Float; + + // NOTE The tests below have special handing for NaN values. + // Because NaN != NaN, the floating-point representations must be used + // Because there are many diffferent values of NaN, and the implementation + // doesn't care about calculating the 'correct' one, if both values are NaN + // the values are considered equivalent. + + // TODO: Add F32/F64 to qc so that they print the right values (at the very least) + quickcheck! { + fn addsf3(a: U32, b: U32) -> bool { + let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); + let x = super::__addsf3(a, b); + let y = a + b; + if !(x.is_nan() && y.is_nan()) { + x.repr() == y.repr() + } else { + true + } + } + + fn adddf3(a: U64, b: U64) -> bool { + let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); + let x = super::__adddf3(a, b); + let y = a + b; + if !(x.is_nan() && y.is_nan()) { + x.repr() == y.repr() + } else { + true + } + } + } + + // More tests for special float values + + #[test] + fn test_float_tiny_plus_tiny() { + let tiny = f32::from_repr(1); + let r = super::__addsf3(tiny, tiny); + assert_eq!(r, tiny + tiny); + } + + #[test] + fn test_double_tiny_plus_tiny() { + let tiny = f64::from_repr(1); + let r = super::__adddf3(tiny, tiny); + assert_eq!(r, tiny + tiny); + } + + #[test] + fn test_float_small_plus_small() { + let a = f32::from_repr(327); + let b = f32::from_repr(256); + let r = super::__addsf3(a, b); + assert_eq!(r, a + b); + } + + #[test] + fn test_double_small_plus_small() { + let a = f64::from_repr(327); + let b = f64::from_repr(256); + let r = super::__adddf3(a, b); + assert_eq!(r, a + b); + } + + #[test] + fn test_float_one_plus_one() { + let r = super::__addsf3(1f32, 1f32); + assert_eq!(r, 1f32 + 1f32); + } + + #[test] + fn test_double_one_plus_one() { + let r = super::__adddf3(1f64, 1f64); + assert_eq!(r, 1f64 + 1f64); + } + + #[test] + fn test_float_different_nan() { + let a = f32::from_repr(1); + let b = f32::from_repr(0b11111111100100010001001010101010); + let x = super::__addsf3(a, b); + let y = a + b; + if !(x.is_nan() && y.is_nan()) { + assert_eq!(x.repr(), y.repr()); + } + } + + #[test] + fn test_double_different_nan() { + let a = f64::from_repr(1); + let b = f64::from_repr( + 0b1111111111110010001000100101010101001000101010000110100011101011); + let x = super::__adddf3(a, b); + let y = a + b; + if !(x.is_nan() && y.is_nan()) { + assert_eq!(x.repr(), y.repr()); + } + } + + #[test] + fn test_float_nan() { + let r = super::__addsf3(f32::NAN, 1.23); + assert_eq!(r.repr(), f32::NAN.repr()); + } + + #[test] + fn test_double_nan() { + let r = super::__adddf3(f64::NAN, 1.23); + assert_eq!(r.repr(), f64::NAN.repr()); + } + + #[test] + fn test_float_inf() { + let r = super::__addsf3(f32::INFINITY, -123.4); + assert_eq!(r, f32::INFINITY); + } + + #[test] + fn test_double_inf() { + let r = super::__adddf3(f64::INFINITY, -123.4); + assert_eq!(r, f64::INFINITY); + } +} diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs new file mode 100644 index 00000000000..ceb2155cc9f --- /dev/null +++ b/library/compiler-builtins/src/float/mod.rs @@ -0,0 +1,65 @@ +use core::mem; + +pub mod add; + +/// Trait for some basic operations on floats +pub trait Float: Sized { + /// A uint of the same with as the float + type Int; + + /// Returns the bitwidth of the float type + fn bits() -> u32; + + /// Returns the bitwidth of the significand + fn significand_bits() -> u32; + + /// Returns `self` transmuted to `Self::Int` + fn repr(self) -> Self::Int; + + /// Returns a `Self::Int` transmuted back to `Self` + fn from_repr(a: Self::Int) -> Self; + + /// Returns (normalized exponent, normalized significand) + fn normalize(significand: Self::Int) -> (i32, Self::Int); +} + +impl Float for f32 { + type Int = u32; + fn bits() -> u32 { + 32 + } + fn significand_bits() -> u32 { + 23 + } + fn repr(self) -> Self::Int { + unsafe { mem::transmute(self) } + } + fn from_repr(a: Self::Int) -> Self { + unsafe { mem::transmute(a) } + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand.leading_zeros() + .wrapping_sub((1u32 << Self::significand_bits()).leading_zeros()); + (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) + } +} +impl Float for f64 { + type Int = u64; + fn bits() -> u32 { + 64 + } + fn significand_bits() -> u32 { + 52 + } + fn repr(self) -> Self::Int { + unsafe { mem::transmute(self) } + } + fn from_repr(a: Self::Int) -> Self { + unsafe { mem::transmute(a) } + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand.leading_zeros() + .wrapping_sub((1u64 << Self::significand_bits()).leading_zeros()); + (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) + } +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index b817d74fda6..9efebcd36b2 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -21,6 +21,7 @@ extern crate core; extern crate rlibc; pub mod int; +pub mod float; #[cfg(target_arch = "arm")] pub mod arm; -- cgit 1.4.1-3-g733a5 From e4dabb8c3239ed4699db304dce542eefbcc18182 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 20 Aug 2016 22:17:50 -0500 Subject: qc: bias towards generation of edge cases --- library/compiler-builtins/src/qc.rs | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 6b37cceb7fd..fcb0b0880e5 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -20,7 +20,18 @@ macro_rules! arbitrary { fn arbitrary(g: &mut G) -> $TY where G: Gen { - $TY(g.gen()) + // NOTE Generate edge cases with a 10% chance + let t = if g.gen_weighted_bool(10) { + *g.choose(&[ + $ty::min_value(), + 0, + $ty::max_value(), + ]).unwrap() + } else { + g.gen() + }; + + $TY(t) } fn shrink(&self) -> Box> { @@ -76,13 +87,23 @@ macro_rules! arbitrary_large { fn arbitrary(g: &mut G) -> $TY where G: Gen { - if g.gen() { - $TY($ty::from_parts(g.gen(), g.gen())) - } else if g.gen() { - $TY($ty::from_parts(0, g.gen())) + // NOTE Generate edge cases with a 10% chance + let t = if g.gen_weighted_bool(10) { + *g.choose(&[ + $ty::min_value(), + 0, + $ty::max_value(), + ]).unwrap() } else { - $TY($ty::from_parts(g.gen(), 0)) - } + match g.gen_range(0, 3) { + 0 => $ty::from_parts(g.gen(), g.gen()), + 1 => $ty::from_parts(0, g.gen()), + 2 => $ty::from_parts(g.gen(), 0), + _ => unreachable!(), + } + }; + + $TY(t) } fn shrink(&self) -> Box> { -- cgit 1.4.1-3-g733a5 From 30428ec88f66c3da56f4ad42368ea81da9aebd6a Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sat, 20 Aug 2016 22:30:02 -0500 Subject: Use mem::swap to swap variables --- library/compiler-builtins/src/float/add.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 3fffac35d7b..f36e0c1e3f5 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -74,9 +74,7 @@ macro_rules! add { // Swap a and b if necessary so that a has the larger absolute value. if b_abs > a_abs { - let temp = a_rep; - a_rep = b_rep; - b_rep = temp; + ::core::mem::swap(&mut a_rep, &mut b_rep); } // Extract the exponent and significand from the (possibly swapped) a and b. -- cgit 1.4.1-3-g733a5 From 43ce7db752551bbbdf7408bc6b36436a3000a1a5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 21 Aug 2016 11:09:32 -0500 Subject: only show disassembly of optimized build we can't really compare the disassembly of the debug build to libcompiler-rt.a anyways --- library/compiler-builtins/appveyor.yml | 1 - library/compiler-builtins/ci/script.sh | 1 - 2 files changed, 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 4bb03def782..5cf0b48f1e9 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -18,7 +18,6 @@ test_script: - cargo test - cargo test --release - CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - - dumpbin /disasm target/debug/librustc_builtins.rlib || exit 0 - dumpbin /disasm target/release/librustc_builtins.rlib || exit 0 branches: diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 75584786943..84e7ee7af53 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -11,7 +11,6 @@ inspect() { $PREFIX$NM -g --defined-only target/**/debug/*.rlib set +e - $PREFIX$OBJDUMP -Cd target/**/debug/*.rlib $PREFIX$OBJDUMP -Cd target/**/release/*.rlib set -e -- cgit 1.4.1-3-g733a5 From ae9d29429727c7c018c2d4c7c1a8dea321a3b14a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 21 Aug 2016 11:24:58 -0500 Subject: use utility function to compare the repr of floats follow up of #43 --- library/compiler-builtins/src/float/add.rs | 36 +++++++++++------------------- library/compiler-builtins/src/float/mod.rs | 22 ++++++++++++++++++ 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index f36e0c1e3f5..3ebc92b3237 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,4 +1,6 @@ +use core::mem; use core::num::Wrapping; + use float::Float; macro_rules! add { @@ -74,7 +76,7 @@ macro_rules! add { // Swap a and b if necessary so that a has the larger absolute value. if b_abs > a_abs { - ::core::mem::swap(&mut a_rep, &mut b_rep); + mem::swap(&mut a_rep, &mut b_rep); } // Extract the exponent and significand from the (possibly swapped) a and b. @@ -212,22 +214,14 @@ mod tests { let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); let x = super::__addsf3(a, b); let y = a + b; - if !(x.is_nan() && y.is_nan()) { - x.repr() == y.repr() - } else { - true - } + x.eq_repr(y) } fn adddf3(a: U64, b: U64) -> bool { let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); let x = super::__adddf3(a, b); let y = a + b; - if !(x.is_nan() && y.is_nan()) { - x.repr() == y.repr() - } else { - true - } + x.eq_repr(y) } } @@ -237,14 +231,14 @@ mod tests { fn test_float_tiny_plus_tiny() { let tiny = f32::from_repr(1); let r = super::__addsf3(tiny, tiny); - assert_eq!(r, tiny + tiny); + assert!(r.eq_repr(tiny + tiny)); } #[test] fn test_double_tiny_plus_tiny() { let tiny = f64::from_repr(1); let r = super::__adddf3(tiny, tiny); - assert_eq!(r, tiny + tiny); + assert!(r.eq_repr(tiny + tiny)); } #[test] @@ -252,7 +246,7 @@ mod tests { let a = f32::from_repr(327); let b = f32::from_repr(256); let r = super::__addsf3(a, b); - assert_eq!(r, a + b); + assert!(r.eq_repr(a + b)); } #[test] @@ -260,19 +254,19 @@ mod tests { let a = f64::from_repr(327); let b = f64::from_repr(256); let r = super::__adddf3(a, b); - assert_eq!(r, a + b); + assert!(r.eq_repr(a + b)); } #[test] fn test_float_one_plus_one() { let r = super::__addsf3(1f32, 1f32); - assert_eq!(r, 1f32 + 1f32); + assert!(r.eq_repr(1f32 + 1f32)); } #[test] fn test_double_one_plus_one() { let r = super::__adddf3(1f64, 1f64); - assert_eq!(r, 1f64 + 1f64); + assert!(r.eq_repr(1f64 + 1f64)); } #[test] @@ -281,9 +275,7 @@ mod tests { let b = f32::from_repr(0b11111111100100010001001010101010); let x = super::__addsf3(a, b); let y = a + b; - if !(x.is_nan() && y.is_nan()) { - assert_eq!(x.repr(), y.repr()); - } + assert!(x.eq_repr(y)); } #[test] @@ -293,9 +285,7 @@ mod tests { 0b1111111111110010001000100101010101001000101010000110100011101011); let x = super::__adddf3(a, b); let y = a + b; - if !(x.is_nan() && y.is_nan()) { - assert_eq!(x.repr(), y.repr()); - } + assert!(x.eq_repr(y)); } #[test] diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index ceb2155cc9f..bd9194bfb79 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -16,6 +16,12 @@ pub trait Float: Sized { /// Returns `self` transmuted to `Self::Int` fn repr(self) -> Self::Int; + #[cfg(test)] + /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be + /// represented in multiple different ways. This methods returns `true` if two NaNs are + /// compared. + fn eq_repr(self, rhs: Self) -> bool; + /// Returns a `Self::Int` transmuted back to `Self` fn from_repr(a: Self::Int) -> Self; @@ -34,6 +40,14 @@ impl Float for f32 { fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } + #[cfg(test)] + fn eq_repr(self, rhs: Self) -> bool { + if self.is_nan() && rhs.is_nan() { + true + } else { + self.repr() == rhs.repr() + } + } fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } @@ -54,6 +68,14 @@ impl Float for f64 { fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } + #[cfg(test)] + fn eq_repr(self, rhs: Self) -> bool { + if self.is_nan() && rhs.is_nan() { + true + } else { + self.repr() == rhs.repr() + } + } fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } -- cgit 1.4.1-3-g733a5 From 6a96cf52b6b57810c945447e4474b74cbd972f18 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sun, 21 Aug 2016 13:31:08 -0500 Subject: Add a `Porting Reminders` section to the README --- library/compiler-builtins/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 67e7b25433e..6dae6654f42 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -24,6 +24,20 @@ See [rust-lang/rust#35437][0]. [2]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/lib/builtins [3]: https://travis-ci.org/japaric/rustc-builtins +### Porting Reminders + +1. [Rust][4] and [C][5] have slightly different operator precedence. C evaluates comparisons (`== !=`) before bitwise operations (`& | ^`), while Rust evaluates the other way. +2. C assumes wrapping operations everywhere. Rust panics on overflow when in debug mode. Consider using the [Wrapping][6] type or the explicit [wrapping_*][7] functions where applicable. +3. Note [C implicit casts][8], especially integer promotion. Rust is much more explicit about casting, so be sure that any cast which affects the output is ported to the Rust implementation. +4. Rust has [many functions][9] for integer or floating point manipulation in the standard library. Consider using one of these functions rather than porting a new one. + +[4]: https://doc.rust-lang.org/reference.html#operator-precedence +[5]: http://en.cppreference.com/w/c/language/operator_precedence +[6]: https://doc.rust-lang.org/core/num/struct.Wrapping.html +[7]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_add +[8]: http://en.cppreference.com/w/cpp/language/implicit_conversion +[9]: https://doc.rust-lang.org/std/primitive.i32.html + ## Progress - [x] adddf3.c -- cgit 1.4.1-3-g733a5 From 5e867a2b984b92954f4560011cc7888072dd38a9 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sun, 21 Aug 2016 16:51:50 -0500 Subject: travis: Use wgetpaste to post disassemblies to gist --- library/compiler-builtins/ci/install.sh | 12 ++++++++++++ library/compiler-builtins/ci/script.sh | 7 ++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index db862cc3349..08dce43d36c 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -42,6 +42,17 @@ install_xargo() { fi } +install_wgetpaste() { + if [[ $TRAVIS_OS_NAME == "osx" ]]; then + brew install wgetpaste + else + curl -O http://wgetpaste.zlin.dk/wgetpaste-2.28.tar.bz2 + tar -xvf wgetpaste-2.28.tar.bz2 + sudo mv ./wgetpaste-2.28/wgetpaste /usr/bin + rm -r wgetpaste-2.28* + fi +} + main() { if [[ $TRAVIS_OS_NAME == "osx" || ${IN_DOCKER_CONTAINER:-n} == "y" ]]; then install_qemu @@ -49,6 +60,7 @@ main() { install_rust add_rustup_target install_xargo + install_wgetpaste fi } diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 84e7ee7af53..89c535223e0 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -2,6 +2,11 @@ set -ex . $(dirname $0)/env.sh +gist() { + wgetpaste -s gists -d "'$1' from commit '$TRAVIS_COMMIT' on branch '$TRAVIS_BRANCH'" + echo "Disassembly available at the above URL." +} + build() { ${CARGO:-cargo} build --target $TARGET ${CARGO:-cargo} build --target $TARGET --release @@ -11,7 +16,7 @@ inspect() { $PREFIX$NM -g --defined-only target/**/debug/*.rlib set +e - $PREFIX$OBJDUMP -Cd target/**/release/*.rlib + $PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist "$TARGET/rustc-builtins.rlib" set -e # Check presence of weak symbols -- cgit 1.4.1-3-g733a5 From ed393f32a19386cef17a2ec182844cc6a34e3fa1 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sun, 21 Aug 2016 17:04:48 -0500 Subject: appveyor: Use gist to post disassembly --- library/compiler-builtins/appveyor.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 5cf0b48f1e9..afca023dc98 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -7,6 +7,7 @@ install: - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - gem install gist - rustc -Vv - cargo -V @@ -17,8 +18,12 @@ test_script: - cargo build --release - cargo test - cargo test --release - - CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - - dumpbin /disasm target/release/librustc_builtins.rlib || exit 0 + +on_success: + - cmd: | + CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" + dumpbin /disasm target/release/librustc_builtins.rlib | + gist -d "'%TARGET%/rustc-builtins.rlib' from commit '%APPVEYOR_REPO_COMMIT%' on branch '%APPVEYOR_REPO_branch%'" branches: only: -- cgit 1.4.1-3-g733a5 From 79411ae643aacaed213b796d691624ff6b1732f6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 22 Aug 2016 18:03:21 -0500 Subject: use the gist crate but not on OSX because it doesn't work there closes #53 cc #51 --- library/compiler-builtins/appveyor.yml | 5 ++--- library/compiler-builtins/ci/install.sh | 12 ------------ library/compiler-builtins/ci/script.sh | 30 +++++++++++++++++++----------- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index afca023dc98..ef3194cbe58 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -21,9 +21,8 @@ test_script: on_success: - cmd: | - CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - dumpbin /disasm target/release/librustc_builtins.rlib | - gist -d "'%TARGET%/rustc-builtins.rlib' from commit '%APPVEYOR_REPO_COMMIT%' on branch '%APPVEYOR_REPO_branch%'" + CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" + dumpbin /disasm target/release/librustc_builtins.rlib | gist -d "'%TARGET%/rustc-builtins.rlib' from commit '%APPVEYOR_REPO_COMMIT%' on branch '%APPVEYOR_REPO_branch%'" branches: only: diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 08dce43d36c..db862cc3349 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -42,17 +42,6 @@ install_xargo() { fi } -install_wgetpaste() { - if [[ $TRAVIS_OS_NAME == "osx" ]]; then - brew install wgetpaste - else - curl -O http://wgetpaste.zlin.dk/wgetpaste-2.28.tar.bz2 - tar -xvf wgetpaste-2.28.tar.bz2 - sudo mv ./wgetpaste-2.28/wgetpaste /usr/bin - rm -r wgetpaste-2.28* - fi -} - main() { if [[ $TRAVIS_OS_NAME == "osx" || ${IN_DOCKER_CONTAINER:-n} == "y" ]]; then install_qemu @@ -60,7 +49,6 @@ main() { install_rust add_rustup_target install_xargo - install_wgetpaste fi } diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 89c535223e0..ef6905b28a9 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -2,8 +2,8 @@ set -ex . $(dirname $0)/env.sh -gist() { - wgetpaste -s gists -d "'$1' from commit '$TRAVIS_COMMIT' on branch '$TRAVIS_BRANCH'" +gist_it() { + gist -ap -f "'$1' from commit '$TRAVIS_COMMIT' on branch '$TRAVIS_BRANCH'" echo "Disassembly available at the above URL." } @@ -16,18 +16,24 @@ inspect() { $PREFIX$NM -g --defined-only target/**/debug/*.rlib set +e - $PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist "$TARGET/rustc-builtins.rlib" - set -e - - # Check presence of weak symbols case $TRAVIS_OS_NAME in linux) - local symbols=( memcmp memcpy memmove memset ) - for symbol in "${symbols[@]}"; do - $PREFIX$NM target/**/debug/deps/librlibc*.rlib | grep -q "W $symbol" - done + $PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist_it "$TARGET/rustc-builtins.rlib" + ;; + osx) + $PREFIX$OBJDUMP -Cd target/**/release/*.rlib ;; esac + set -e + + # Check presence of weak symbols + if [[ $TRAVIS_OS_NAME = "linux" ]]; then + local symbols=( memcmp memcpy memmove memset ) + for symbol in "${symbols[@]}"; do + $PREFIX$NM target/**/debug/deps/librlibc*.rlib | grep -q "W $symbol" + done + fi + } run_tests() { @@ -43,12 +49,14 @@ run_tests() { main() { if [[ $TRAVIS_OS_NAME == "linux" && ${IN_DOCKER_CONTAINER:-n} == "n" ]]; then - local tag=2016-08-13 + local tag=2016-08-22 docker run \ --privileged \ -e IN_DOCKER_CONTAINER=y \ -e TARGET=$TARGET \ + -e TRAVIS_BRANCH=$TRAVIS_BRANCH \ + -e TRAVIS_COMMIT=$TRAVIS_COMMIT \ -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ -v $(pwd):/mnt \ japaric/rustc-builtins:$tag \ -- cgit 1.4.1-3-g733a5 From bcf5a641df944a2f5293c999be7d31e19e6a714e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 23 Aug 2016 20:17:39 -0500 Subject: README: fix link --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 6dae6654f42..55f215316a9 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -12,7 +12,7 @@ See [rust-lang/rust#35437][0]. ## Contributing -1. Pick one or more intrinsics from the [pending list][/#progress]. +1. Pick one or more intrinsics from the [pending list][#progress]. 2. Fork this repository 3. Port the intrinsic(s) and their corresponding [unit tests][1] from their [C implementation][2] to Rust. -- cgit 1.4.1-3-g733a5 From 72db6febd0aa0224d8632cb5e443f863792ebf8f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 23 Aug 2016 20:23:28 -0500 Subject: README: add AppVeyor badge --- library/compiler-builtins/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 55f215316a9..4eeadb17ec5 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,6 +1,8 @@ -[![Build Status][status]](https://travis-ci.org/japaric/rustc-builtins) +[![Travis][travis]](https://travis-ci.org/japaric/rustc-builtins) +[![AppVeyor][appveyor]](https://ci.appveyor.com/project/japaric/rustc-builtins) -[status]: https://travis-ci.org/japaric/rustc-builtins.svg?branch=master +[travis]: https://travis-ci.org/japaric/rustc-builtins.svg?branch=master +[appveyor]: https://ci.appveyor.com/api/projects/status/mofi55r3px9pv3o7?svg=true # `rustc-builtins` -- cgit 1.4.1-3-g733a5 From ff17cfaa46812d27ab1858499af1f8d091a4b4e8 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 23 Aug 2016 20:35:30 -0500 Subject: README: when and how to use this crate --- library/compiler-builtins/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 4eeadb17ec5..3d0ded11bfe 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -12,6 +12,27 @@ See [rust-lang/rust#35437][0]. [0]: https://github.com/rust-lang/rust/issues/35437 +## When and how to use this crate? + +If you are working with a target that doesn't have binary releases of std available via rustup (this +probably means you are building the core crate yourself) and need compiler-rt intrinsics (i.e. you +are probably getting linker errors when building an executable: "undefined reference to +__aeabi_memcpy"), you can use this crate to get those intrinsics and solve the linker errors. To do +that, simply add this crate as a Cargo dependency (it doesn't matter where in the dependency graph +this crate ends up, as long as it's there): + +``` toml +[dependencies] +rustc-builtins = { git = "https://github.com/japaric/rustc-builtins" } +``` + +If you still get an "undefined reference to $INTRINSIC" error after that change, that means that we +haven't ported `$INTRINSIC` to Rust yet! Please open [an issue] with the name of the intrinsic and +the LLVM triple (e.g. thumbv7m-none-eabi) of the target you are using. That way we can prioritize +porting that particular intrinsic. + +[an issue]: https://github.com/japaric/rustc-builtins/issues + ## Contributing 1. Pick one or more intrinsics from the [pending list][#progress]. -- cgit 1.4.1-3-g733a5 From 185143e90f6d2636ae8f1c61ced7b05555e46492 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 23 Aug 2016 20:46:36 -0500 Subject: use the gist gem instead of the gist crate hopefully this will work on osx and will make everything more uniform (appveyor is already using the gem instead of the crate) closes #51 --- library/compiler-builtins/.travis.yml | 2 +- library/compiler-builtins/ci/install.sh | 17 ++++++++++------- library/compiler-builtins/ci/script.sh | 13 +++---------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index e74b68002ff..b7a44d99a51 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,5 +1,5 @@ dist: trusty -language: generic +language: ruby services: docker sudo: required diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index db862cc3349..d912771e0fd 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -3,13 +3,15 @@ set -ex . $(dirname $0)/env.sh install_qemu() { - case $TRAVIS_OS_NAME in - linux) - apt-get update - apt-get install -y --no-install-recommends \ - binfmt-support qemu-user-static - ;; - esac + if [[ $TRAVIS_OS_NAME = "linux" ]]; then + apt-get update + apt-get install -y --no-install-recommends \ + binfmt-support qemu-user-static + fi +} + +install_gist() { + gem install gist } install_binutils() { @@ -45,6 +47,7 @@ install_xargo() { main() { if [[ $TRAVIS_OS_NAME == "osx" || ${IN_DOCKER_CONTAINER:-n} == "y" ]]; then install_qemu + install_gist install_binutils install_rust add_rustup_target diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index ef6905b28a9..7f518a79450 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -3,7 +3,7 @@ set -ex . $(dirname $0)/env.sh gist_it() { - gist -ap -f "'$1' from commit '$TRAVIS_COMMIT' on branch '$TRAVIS_BRANCH'" + gist -d "'$TARGET/rustc-builtins.rlib' from commit '$TRAVIS_COMMIT' on branch '$TRAVIS_BRANCH'" echo "Disassembly available at the above URL." } @@ -16,14 +16,7 @@ inspect() { $PREFIX$NM -g --defined-only target/**/debug/*.rlib set +e - case $TRAVIS_OS_NAME in - linux) - $PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist_it "$TARGET/rustc-builtins.rlib" - ;; - osx) - $PREFIX$OBJDUMP -Cd target/**/release/*.rlib - ;; - esac + $PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist_it set -e # Check presence of weak symbols @@ -49,7 +42,7 @@ run_tests() { main() { if [[ $TRAVIS_OS_NAME == "linux" && ${IN_DOCKER_CONTAINER:-n} == "n" ]]; then - local tag=2016-08-22 + local tag=2016-08-13 docker run \ --privileged \ -- cgit 1.4.1-3-g733a5 From 1ae3b2927080f00888cf2cfe82e7d11d654e4f85 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 23 Aug 2016 21:19:18 -0500 Subject: use newer docker image it comes with ruby pre-installed --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 7f518a79450..911f40218b4 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -42,7 +42,7 @@ run_tests() { main() { if [[ $TRAVIS_OS_NAME == "linux" && ${IN_DOCKER_CONTAINER:-n} == "n" ]]; then - local tag=2016-08-13 + local tag=2016-08-24 docker run \ --privileged \ -- cgit 1.4.1-3-g733a5 From 2e516532d1004cf96224d1494aea96e1c1a2517d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 23 Aug 2016 21:20:57 -0500 Subject: set language: ruby on osx only --- library/compiler-builtins/.travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index b7a44d99a51..7a7a9bf5d79 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,5 +1,5 @@ dist: trusty -language: ruby +language: generic services: docker sudo: required @@ -16,6 +16,7 @@ matrix: - env: TARGET=i586-unknown-linux-gnu os: linux - env: TARGET=i686-apple-darwin + language: ruby os: osx - env: TARGET=i686-unknown-linux-gnu os: linux @@ -36,6 +37,7 @@ matrix: - env: TARGET=thumbv7m-none-eabi os: linux - env: TARGET=x86_64-apple-darwin + language: ruby os: osx - env: TARGET=x86_64-unknown-linux-gnu os: linux -- cgit 1.4.1-3-g733a5 From 90d58ada7a7a5402530810cf702935262886ffa5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 27 Aug 2016 11:37:35 -0500 Subject: appveyor: use rustup --- library/compiler-builtins/appveyor.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index ef3194cbe58..669500a38e4 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -4,9 +4,9 @@ environment: - TARGET: x86_64-pc-windows-msvc install: - - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" - - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - curl -sSf -o rustup-init.exe https://win.rustup.rs + - rustup-init.exe --default-host %TARGET% --default-toolchain nightly -y + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - gem install gist - rustc -Vv - cargo -V -- cgit 1.4.1-3-g733a5 From 62d5f589086b07ca3f82bffb04e162430aed0fa3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 27 Aug 2016 12:34:39 -0500 Subject: print rustup version --- library/compiler-builtins/ci/install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index d912771e0fd..50e223cdd6c 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -27,6 +27,7 @@ install_rust() { rustup default nightly fi + rustup -V rustc -V cargo -V } -- cgit 1.4.1-3-g733a5 From a8774eb192291f3b652159803a61fb09ec4c373d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Aug 2016 19:31:49 -0500 Subject: travis: simplify ci scripts --- library/compiler-builtins/.travis.yml | 3 -- library/compiler-builtins/ci/env.sh | 95 +++++++++++++++------------------ library/compiler-builtins/ci/install.sh | 12 ++--- library/compiler-builtins/ci/script.sh | 14 +++-- 4 files changed, 54 insertions(+), 70 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7a7a9bf5d79..6759c4e2864 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -42,9 +42,6 @@ matrix: - env: TARGET=x86_64-unknown-linux-gnu os: linux -before_install: - - export PATH="$PATH:$HOME/.cargo/bin" - install: - bash ci/install.sh diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 55249950b3c..9addf551b77 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -1,60 +1,49 @@ case $TRAVIS_OS_NAME in linux) - export HOST=x86_64-unknown-linux-gnu - export NM=nm - export OBJDUMP=objdump + HOST=x86_64-unknown-linux-gnu + NM=nm + OBJDUMP=objdump + LINUX=y ;; osx) - export HOST=x86_64-apple-darwin - export NM=gnm - export OBJDUMP=gobjdump + HOST=x86_64-apple-darwin + NM=gnm + OBJDUMP=gobjdump + OSX=y ;; esac -case $TARGET in - aarch64-unknown-linux-gnu) - export PREFIX=aarch64-linux-gnu- - export QEMU_LD_PREFIX=/usr/aarch64-linux-gnu - ;; - arm*-unknown-linux-gnueabi) - export PREFIX=arm-linux-gnueabi- - export QEMU_LD_PREFIX=/usr/arm-linux-gnueabi - ;; - arm-unknown-linux-gnueabihf) - export PREFIX=arm-linux-gnueabihf- - export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf - ;; - armv7-unknown-linux-gnueabihf) - export PREFIX=arm-linux-gnueabihf- - export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf - ;; - mips-unknown-linux-gnu) - export PREFIX=mips-linux-gnu- - export QEMU_LD_PREFIX=/usr/mips-linux-gnu - ;; - mipsel-unknown-linux-gnu) - export PREFIX=mipsel-linux-gnu- - export QEMU_LD_PREFIX=/usr/mipsel-linux-gnu - ;; - powerpc-unknown-linux-gnu) - export PREFIX=powerpc-linux-gnu- - export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu - ;; - powerpc64-unknown-linux-gnu) - export PREFIX=powerpc64-linux-gnu- - export QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu - ;; - powerpc64le-unknown-linux-gnu) - export PREFIX=powerpc64le-linux-gnu- - export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu - # QEMU crashes, even running the simplest cross compiled C program: - # `int main() { return 0; }` - export RUN_TESTS=n - ;; - thumbv*-none-eabi) - export CARGO=xargo - export PREFIX=arm-none-eabi- - # Bare metal targets. No `std` or `test` crates for these targets. - export RUN_TESTS=n - ;; -esac +# NOTE For rustup +export PATH="$HOME/.cargo/bin:$PATH" + +CARGO=cargo +RUN_TESTS=y + +# NOTE For the host and its 32-bit variants we don't need prefixed tools or QEMU +if [[ $TARGET != $HOST && ! $TARGET =~ ^i.86- ]]; then + GCC_TRIPLE=${TARGET//unknown-/} + + case $TARGET in + armv7-unknown-linux-gnueabihf) + GCC_TRIPLE=arm-linux-gnueabihf + ;; + powerpc64le-unknown-linux-gnu) + # QEMU crashes even when executing the simplest cross compiled C program: + # `int main() { return 0; }` + RUN_TESTS=n + ;; + thumbv*-none-eabi) + CARGO=xargo + GCC_TRIPLE=arm-none-eabi + # Bare metal targets. No `std` or `test` crates for these targets. + RUN_TESTS=n + ;; + esac + + if [[ $RUN_TESTS == y ]]; then + # NOTE(export) so this can reach the processes that `cargo test` spawns + export QEMU_LD_PREFIX=/usr/$GCC_TRIPLE + fi + + PREFIX=$GCC_TRIPLE- +fi diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 50e223cdd6c..ee01f34944b 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -3,7 +3,7 @@ set -ex . $(dirname $0)/env.sh install_qemu() { - if [[ $TRAVIS_OS_NAME = "linux" ]]; then + if [[ $QEMU_LD_PREFIX ]]; then apt-get update apt-get install -y --no-install-recommends \ binfmt-support qemu-user-static @@ -15,13 +15,13 @@ install_gist() { } install_binutils() { - if [[ $TRAVIS_OS_NAME == "osx" ]]; then + if [[ $OSX ]]; then brew install binutils fi } install_rust() { - if [[ $TRAVIS_OS_NAME == "osx" ]]; then + if [[ $OSX ]]; then curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly else rustup default nightly @@ -33,20 +33,20 @@ install_rust() { } add_rustup_target() { - if [[ $TARGET != $HOST && ${CARGO:-cargo} == "cargo" ]]; then + if [[ $TARGET != $HOST && $CARGO == cargo ]]; then rustup target add $TARGET fi } install_xargo() { - if [[ $CARGO == "xargo" ]]; then + if [[ $CARGO == xargo ]]; then curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ bash -s -- --from japaric/xargo --at /root/.cargo/bin fi } main() { - if [[ $TRAVIS_OS_NAME == "osx" || ${IN_DOCKER_CONTAINER:-n} == "y" ]]; then + if [[ $OSX || ${IN_DOCKER_CONTAINER:-n} == y ]]; then install_qemu install_gist install_binutils diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 911f40218b4..29cad854e88 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -8,8 +8,8 @@ gist_it() { } build() { - ${CARGO:-cargo} build --target $TARGET - ${CARGO:-cargo} build --target $TARGET --release + $CARGO build --tartet $TARGET + $CARGO build --target $TARGET --release } inspect() { @@ -20,7 +20,7 @@ inspect() { set -e # Check presence of weak symbols - if [[ $TRAVIS_OS_NAME = "linux" ]]; then + if [[ $LINUX ]]; then local symbols=( memcmp memcpy memmove memset ) for symbol in "${symbols[@]}"; do $PREFIX$NM target/**/debug/deps/librlibc*.rlib | grep -q "W $symbol" @@ -34,14 +34,14 @@ run_tests() { export RUST_TEST_THREADS=1 fi - if [[ ${RUN_TESTS:-y} == "y" ]]; then + if [[ $RUN_TESTS == y ]]; then cargo test --target $TARGET cargo test --target $TARGET --release fi } main() { - if [[ $TRAVIS_OS_NAME == "linux" && ${IN_DOCKER_CONTAINER:-n} == "n" ]]; then + if [[ $LINUX && ${IN_DOCKER_CONTAINER:-n} == n ]]; then local tag=2016-08-24 docker run \ @@ -53,9 +53,7 @@ main() { -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ -v $(pwd):/mnt \ japaric/rustc-builtins:$tag \ - sh -c 'set -ex; - cd /mnt; - export PATH="$PATH:/root/.cargo/bin"; + sh -c 'cd /mnt; bash ci/install.sh; bash ci/script.sh' else -- cgit 1.4.1-3-g733a5 From 17386437c853e12a300028c4c58fa62917de0f3c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Aug 2016 20:36:52 -0500 Subject: fix typo --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 29cad854e88..20e574166ee 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -8,7 +8,7 @@ gist_it() { } build() { - $CARGO build --tartet $TARGET + $CARGO build --target $TARGET $CARGO build --target $TARGET --release } -- cgit 1.4.1-3-g733a5 From 80f867f306353c15ef73eed94423ddbb7dfbf73e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Aug 2016 20:37:41 -0500 Subject: pin xargo and gist versions --- library/compiler-builtins/ci/install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index ee01f34944b..45ad243fb99 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -11,7 +11,7 @@ install_qemu() { } install_gist() { - gem install gist + gem install gist -v 4.5.0 } install_binutils() { @@ -41,7 +41,7 @@ add_rustup_target() { install_xargo() { if [[ $CARGO == xargo ]]; then curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --from japaric/xargo --at /root/.cargo/bin + bash -s -- --from japaric/xargo --at /root/.cargo/bin --vers 0.1.5 fi } -- cgit 1.4.1-3-g733a5 From d253b6a2e4d6f01230f0f2103e9f7a8e070af732 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Aug 2016 21:21:59 -0500 Subject: travis: use latest docker image --- library/compiler-builtins/ci/script.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 20e574166ee..38c6b32376e 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -42,8 +42,7 @@ run_tests() { main() { if [[ $LINUX && ${IN_DOCKER_CONTAINER:-n} == n ]]; then - local tag=2016-08-24 - + # NOTE The Dockerfile of this image is in the docker branch of this repository docker run \ --privileged \ -e IN_DOCKER_CONTAINER=y \ @@ -52,7 +51,7 @@ main() { -e TRAVIS_COMMIT=$TRAVIS_COMMIT \ -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ -v $(pwd):/mnt \ - japaric/rustc-builtins:$tag \ + japaric/rustc-builtins \ sh -c 'cd /mnt; bash ci/install.sh; bash ci/script.sh' -- cgit 1.4.1-3-g733a5 From a88958c673a4afdc4dfca44af43399c70e2f0538 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Aug 2016 21:25:23 -0500 Subject: install less stuff it's already installed in the docker image --- library/compiler-builtins/ci/install.sh | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 45ad243fb99..86095e33e89 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -11,7 +11,9 @@ install_qemu() { } install_gist() { - gem install gist -v 4.5.0 + if [[ $OSX ]]; then + gem install gist -v 4.5.0 + fi } install_binutils() { @@ -38,13 +40,6 @@ add_rustup_target() { fi } -install_xargo() { - if [[ $CARGO == xargo ]]; then - curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --from japaric/xargo --at /root/.cargo/bin --vers 0.1.5 - fi -} - main() { if [[ $OSX || ${IN_DOCKER_CONTAINER:-n} == y ]]; then install_qemu @@ -52,7 +47,6 @@ main() { install_binutils install_rust add_rustup_target - install_xargo fi } -- cgit 1.4.1-3-g733a5 From e237a46f40da18a841e5add04f517f5b156e491c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Aug 2016 21:35:53 -0500 Subject: tell cargo which linker to use --- library/compiler-builtins/ci/env.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 9addf551b77..feeac221389 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -40,6 +40,8 @@ if [[ $TARGET != $HOST && ! $TARGET =~ ^i.86- ]]; then ;; esac + export CARGO_TARGET_$(echo $TARGET | tr a-z- A-Z_)_LINKER=$GCC_TRIPLE-gcc + if [[ $RUN_TESTS == y ]]; then # NOTE(export) so this can reach the processes that `cargo test` spawns export QEMU_LD_PREFIX=/usr/$GCC_TRIPLE -- cgit 1.4.1-3-g733a5 From becf6eea62817dd8f5ade044afac56af2303674e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 10 Sep 2016 16:49:32 -0500 Subject: homu-ify --- library/compiler-builtins/.travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 6759c4e2864..5496bb29131 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -50,8 +50,10 @@ script: branches: only: - - master + - auto + - try notifications: email: on_success: never + webhooks: https://homu.herokuapp.com/travis -- cgit 1.4.1-3-g733a5 From 4553b1fc764e89ce6f319145f2fd94e2f8aaa28e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 10 Sep 2016 16:54:54 -0500 Subject: appveyor: test on auto and try only --- library/compiler-builtins/appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 669500a38e4..b34efc21e61 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -26,4 +26,5 @@ on_success: branches: only: - - master + - auto + - try -- cgit 1.4.1-3-g733a5 From 74459fdf121c388d52db7edea1fcbbc69b9a9d7b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 10 Sep 2016 18:37:35 -0500 Subject: test for homu --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 3d0ded11bfe..536cec739cd 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,8 +1,8 @@ [![Travis][travis]](https://travis-ci.org/japaric/rustc-builtins) [![AppVeyor][appveyor]](https://ci.appveyor.com/project/japaric/rustc-builtins) -[travis]: https://travis-ci.org/japaric/rustc-builtins.svg?branch=master [appveyor]: https://ci.appveyor.com/api/projects/status/mofi55r3px9pv3o7?svg=true +[travis]: https://travis-ci.org/japaric/rustc-builtins.svg?branch=master # `rustc-builtins` -- cgit 1.4.1-3-g733a5 From 152f5150f66d9122898a9b8e99bc7affa225104c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 10 Sep 2016 19:12:50 -0500 Subject: homu test --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 536cec739cd..edccd301838 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,5 +1,5 @@ -[![Travis][travis]](https://travis-ci.org/japaric/rustc-builtins) [![AppVeyor][appveyor]](https://ci.appveyor.com/project/japaric/rustc-builtins) +[![Travis][travis]](https://travis-ci.org/japaric/rustc-builtins) [appveyor]: https://ci.appveyor.com/api/projects/status/mofi55r3px9pv3o7?svg=true [travis]: https://travis-ci.org/japaric/rustc-builtins.svg?branch=master -- cgit 1.4.1-3-g733a5 From 656cd2b30820022f0189c83988970209c5e6dc18 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 16 Sep 2016 15:53:14 -0500 Subject: test our implementations against gcc_s if it exposes the same intrinsics that we implement -- gcc_s doesn't implement all the intrinsics for all the architectures. closes #65 --- library/compiler-builtins/Cargo.toml | 3 ++ library/compiler-builtins/gcc_s/Cargo.toml | 7 ++++ library/compiler-builtins/gcc_s/src/lib.rs | 51 ++++++++++++++++++++++++++++ library/compiler-builtins/src/float/add.rs | 18 +++++++--- library/compiler-builtins/src/int/mul.rs | 32 ++++++++++++++++-- library/compiler-builtins/src/int/sdiv.rs | 53 ++++++++++++++++++++++++++---- library/compiler-builtins/src/int/shift.rs | 22 +++++++++++-- library/compiler-builtins/src/int/udiv.rs | 53 ++++++++++++++++++++++++++---- library/compiler-builtins/src/lib.rs | 3 ++ 9 files changed, 220 insertions(+), 22 deletions(-) create mode 100644 library/compiler-builtins/gcc_s/Cargo.toml create mode 100644 library/compiler-builtins/gcc_s/src/lib.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 48f6ee0ce3d..229cec74706 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -7,7 +7,10 @@ version = "0.1.0" rlibc = { git = "https://github.com/alexcrichton/rlibc", optional = true } [dev-dependencies] +gcc_s = { path = "gcc_s" } quickcheck = "0.3.1" [features] default = ["rlibc/weak"] + +[workspace] diff --git a/library/compiler-builtins/gcc_s/Cargo.toml b/library/compiler-builtins/gcc_s/Cargo.toml new file mode 100644 index 00000000000..4e3080fa408 --- /dev/null +++ b/library/compiler-builtins/gcc_s/Cargo.toml @@ -0,0 +1,7 @@ +[package] +authors = ["Jorge Aparicio "] +name = "gcc_s" +version = "0.1.0" + +[dependencies] +libloading = "0.3.0" diff --git a/library/compiler-builtins/gcc_s/src/lib.rs b/library/compiler-builtins/gcc_s/src/lib.rs new file mode 100644 index 00000000000..b053a5b8e35 --- /dev/null +++ b/library/compiler-builtins/gcc_s/src/lib.rs @@ -0,0 +1,51 @@ +#![feature(drop_types_in_const)] + +extern crate libloading; + +use std::sync::{Once, ONCE_INIT}; + +use libloading::Library; + +static mut GCC_S: Option = None; + +fn gcc_s() -> &'static Library { + unsafe { + static INIT: Once = ONCE_INIT; + + INIT.call_once(|| { + GCC_S = Some(Library::new("libgcc_s.so.1").unwrap()); + }); + GCC_S.as_ref().unwrap() + } +} + +macro_rules! declare { + ($symbol:ident: fn($($i:ty),+) -> $o:ty) => { + pub fn $symbol() -> Option $o> { + unsafe { + gcc_s().get(concat!("__", stringify!($symbol)).as_bytes()).ok().map(|s| *s) + } + } + } +} + +declare!(ashldi3: fn(u64, u32) -> u64); +declare!(ashrdi3: fn(i64, u32) -> i64); +declare!(divdi3: fn(i64, i64) -> i64); +declare!(divmoddi4: fn(i64, i64, &mut i64) -> i64); +declare!(divmodsi4: fn(i32, i32, &mut i32) -> i32); +declare!(divsi3: fn(i32, i32) -> i32); +declare!(lshrdi3: fn(u64, u32) -> u64); +declare!(moddi3: fn(i64, i64) -> i64); +declare!(modsi3: fn(i32, i32) -> i32); +declare!(muldi3: fn(u64, u64) -> u64); +declare!(mulodi4: fn(i64, i64, &mut i32) -> i64); +declare!(mulosi4: fn(i32, i32, &mut i32) -> i32); +declare!(udivdi3: fn(u64, u64) -> u64); +declare!(udivmoddi4: fn(u64, u64, Option<&mut u64>) -> u64); +declare!(udivmodsi4: fn(u32, u32, Option<&mut u32>) -> u32); +declare!(udivsi3: fn(u32, u32) -> u32); +declare!(umoddi3: fn(u64, u64) -> u64); +declare!(umodsi3: fn(u32, u32) -> u32); +declare!(addsf3: fn(f32, f32) -> f32); +declare!(adddf3: fn(f64, f64) -> f64); diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 3ebc92b3237..13c7aba678b 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -199,6 +199,8 @@ pub extern fn __aeabi_fadd(a: f32, b: f32) -> f32 { #[cfg(test)] mod tests { use core::{f32, f64}; + + use gcc_s; use qc::{U32, U64}; use float::Float; @@ -213,15 +215,23 @@ mod tests { fn addsf3(a: U32, b: U32) -> bool { let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); let x = super::__addsf3(a, b); - let y = a + b; - x.eq_repr(y) + + if let Some(addsf3) = gcc_s::addsf3() { + x.eq_repr(unsafe { addsf3(a, b) }) + } else { + x.eq_repr(a + b) + } } fn adddf3(a: U64, b: U64) -> bool { let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); let x = super::__adddf3(a, b); - let y = a + b; - x.eq_repr(y) + + if let Some(adddf3) = gcc_s::adddf3() { + x.eq_repr(unsafe { adddf3(a, b) }) + } else { + x.eq_repr(a + b) + } } } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 3d6844473b9..4ea65bd28dc 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -72,13 +72,19 @@ mulo!(__mulodi4: i64); #[cfg(test)] mod tests { + use gcc_s; use qc::{I32, I64, U64}; quickcheck! { fn muldi(a: U64, b: U64) -> bool { let (a, b) = (a.0, b.0); let r = super::__muldi3(a, b); - r == a.wrapping_mul(b) + + if let Some(muldi3) = gcc_s::muldi3() { + r == unsafe { muldi3(a, b) } + } else { + r == a.wrapping_mul(b) + } } fn mulosi(a: I32, b: I32) -> bool { @@ -88,7 +94,17 @@ mod tests { if overflow != 0 && overflow != 1 { return false; } - (r, overflow != 0) == a.overflowing_mul(b) + + if let Some(mulosi4) = gcc_s::mulosi4() { + let mut gcc_s_overflow = 2; + let gcc_s_r = unsafe { + mulosi4(a, b, &mut gcc_s_overflow) + }; + + (r, overflow) == (gcc_s_r, gcc_s_overflow) + } else { + (r, overflow != 0) == a.overflowing_mul(b) + } } fn mulodi(a: I64, b: I64) -> bool { @@ -98,7 +114,17 @@ mod tests { if overflow != 0 && overflow != 1 { return false; } - (r, overflow != 0) == a.overflowing_mul(b) + + if let Some(mulodi4) = gcc_s::mulodi4() { + let mut gcc_s_overflow = 2; + let gcc_s_r = unsafe { + mulodi4(a, b, &mut gcc_s_overflow) + }; + + (r, overflow) == (gcc_s_r, gcc_s_overflow) + } else { + (r, overflow != 0) == a.overflowing_mul(b) + } } } } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 72ddbca5d5b..50ad0e0a525 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -52,6 +52,7 @@ divmod!(__divmoddi4, __divdi3: i64); #[cfg(test)] mod tests { + use gcc_s; use quickcheck::TestResult; use qc::{U32, U64}; @@ -62,7 +63,12 @@ mod tests { TestResult::discard() } else { let q = super::__divdi3(n, d); - TestResult::from_bool(q == n / d) + + if let Some(divdi3) = gcc_s::divdi3() { + TestResult::from_bool(q == unsafe { divdi3(n, d) }) + } else { + TestResult::from_bool(q == n / d) + } } } @@ -72,7 +78,12 @@ mod tests { TestResult::discard() } else { let r = super::__moddi3(n, d); - TestResult::from_bool(r == n % d) + + if let Some(moddi3) = gcc_s::moddi3() { + TestResult::from_bool(r == unsafe { moddi3(n, d) }) + } else { + TestResult::from_bool(r == n % d) + } } } @@ -83,7 +94,17 @@ mod tests { } else { let mut r = 0; let q = super::__divmoddi4(n, d, &mut r); - TestResult::from_bool(q == n / d && r == n % d) + + if let Some(divmoddi4) = gcc_s::divmoddi4() { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + divmoddi4(n, d, &mut gcc_s_r) + }; + + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + } else { + TestResult::from_bool(q == n / d && r == n % d) + } } } @@ -93,7 +114,12 @@ mod tests { TestResult::discard() } else { let q = super::__divsi3(n, d); - TestResult::from_bool(q == n / d) + + if let Some(divsi3) = gcc_s::divsi3() { + TestResult::from_bool(q == unsafe { divsi3(n, d)}) + } else { + TestResult::from_bool(q == n / d) + } } } @@ -103,7 +129,12 @@ mod tests { TestResult::discard() } else { let r = super::__modsi3(n, d); - TestResult::from_bool(r == n % d) + + if let Some(modsi3) = gcc_s::modsi3() { + TestResult::from_bool(r == unsafe { modsi3(n, d) }) + } else { + TestResult::from_bool(r == n % d) + } } } @@ -114,7 +145,17 @@ mod tests { } else { let mut r = 0; let q = super::__divmodsi4(n, d, &mut r); - TestResult::from_bool(q == n / d && r == n % d) + + if let Some(divmodsi4) = gcc_s::divmodsi4() { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + divmodsi4(n, d, &mut gcc_s_r) + }; + + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + } else { + TestResult::from_bool(q == n / d && r == n % d) + } } } } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 96ae6dbad25..c7be81171c4 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -60,6 +60,7 @@ lshr!(__lshrdi3: u64); #[cfg(test)] mod tests { + use gcc_s; use quickcheck::TestResult; use qc::{I64, U64}; @@ -71,7 +72,12 @@ mod tests { TestResult::discard() } else { let r = super::__ashldi3(a, b); - TestResult::from_bool(r == a << b) + + if let Some(ashldi3) = gcc_s::ashldi3() { + TestResult::from_bool(r == unsafe { ashldi3(a, b) }) + } else { + TestResult::from_bool(r == a << b) + } } } @@ -81,7 +87,12 @@ mod tests { TestResult::discard() } else { let r = super::__ashrdi3(a, b); - TestResult::from_bool(r == a >> b) + + if let Some(ashrdi3) = gcc_s::ashrdi3() { + TestResult::from_bool(r == unsafe { ashrdi3(a, b) }) + } else { + TestResult::from_bool(r == a >> b) + } } } @@ -91,7 +102,12 @@ mod tests { TestResult::discard() } else { let r = super::__lshrdi3(a, b); - TestResult::from_bool(r == a >> b) + + if let Some(lshrdi3) = gcc_s::lshrdi3() { + TestResult::from_bool(r == unsafe { lshrdi3(a, b) }) + } else { + TestResult::from_bool(r == a >> b) + } } } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index f3ec720c105..8c9d06f21df 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -228,6 +228,7 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { #[cfg(test)] mod tests { + use gcc_s; use quickcheck::TestResult; use qc::{U32, U64}; @@ -238,7 +239,12 @@ mod tests { TestResult::discard() } else { let q = super::__udivdi3(n, d); - TestResult::from_bool(q == n / d) + + if let Some(udivdi3) = gcc_s::udivdi3() { + TestResult::from_bool(q == unsafe { udivdi3(n, d) }) + } else { + TestResult::from_bool(q == n / d) + } } } @@ -248,7 +254,12 @@ mod tests { TestResult::discard() } else { let r = super::__umoddi3(n, d); - TestResult::from_bool(r == n % d) + + if let Some(umoddi3) = gcc_s::umoddi3() { + TestResult::from_bool(r == unsafe { umoddi3(n, d) }) + } else { + TestResult::from_bool(r == n % d) + } } } @@ -259,7 +270,17 @@ mod tests { } else { let mut r = 0; let q = super::__udivmoddi4(n, d, Some(&mut r)); - TestResult::from_bool(q == n / d && r == n % d) + + if let Some(udivmoddi4) = gcc_s::udivmoddi4() { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + udivmoddi4(n, d, Some(&mut gcc_s_r)) + }; + + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + } else { + TestResult::from_bool(q == n / d && r == n % d) + } } } @@ -269,7 +290,12 @@ mod tests { TestResult::discard() } else { let q = super::__udivsi3(n, d); - TestResult::from_bool(q == n / d) + + if let Some(udivsi3) = gcc_s::udivsi3() { + TestResult::from_bool(q == unsafe { udivsi3(n, d) }) + } else { + TestResult::from_bool(q == n / d) + } } } @@ -279,7 +305,12 @@ mod tests { TestResult::discard() } else { let r = super::__umodsi3(n, d); - TestResult::from_bool(r == n % d) + + if let Some(umodsi3) = gcc_s::umodsi3() { + TestResult::from_bool(r == unsafe { umodsi3(n, d) }) + } else { + TestResult::from_bool(r == n % d) + } } } @@ -290,7 +321,17 @@ mod tests { } else { let mut r = 0; let q = super::__udivmodsi4(n, d, Some(&mut r)); - TestResult::from_bool(q == n / d && r == n % d) + + if let Some(udivmodsi4) = gcc_s::udivmodsi4() { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + udivmodsi4(n, d, Some(&mut gcc_s_r)) + }; + + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + } else { + TestResult::from_bool(q == n / d && r == n % d) + } } } } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 9efebcd36b2..cba1604c0e1 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -17,6 +17,9 @@ extern crate quickcheck; #[cfg(test)] extern crate core; +#[cfg(test)] +extern crate gcc_s; + #[cfg(all(not(windows), not(target_os = "macos")))] extern crate rlibc; -- cgit 1.4.1-3-g733a5 From 0ae6c5db880ba919ba58c91134202a0a42c05cb1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 17 Sep 2016 19:54:29 -0500 Subject: osx: link to dylib, windows: always return None --- library/compiler-builtins/gcc_s/src/lib.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/gcc_s/src/lib.rs b/library/compiler-builtins/gcc_s/src/lib.rs index b053a5b8e35..fa034b0b3dd 100644 --- a/library/compiler-builtins/gcc_s/src/lib.rs +++ b/library/compiler-builtins/gcc_s/src/lib.rs @@ -8,17 +8,34 @@ use libloading::Library; static mut GCC_S: Option = None; +#[cfg(not(windows))] fn gcc_s() -> &'static Library { + #[cfg(not(target_os = "macos"))] + const LIBGCC_S: &'static str = "libgcc_s.so.1"; + + #[cfg(target_os = "macos")] + const LIBGCC_S: &'static str = "libgcc_s.1.dylib"; + unsafe { static INIT: Once = ONCE_INIT; INIT.call_once(|| { - GCC_S = Some(Library::new("libgcc_s.so.1").unwrap()); + GCC_S = Some(Library::new(LIBGCC_S).unwrap()); }); GCC_S.as_ref().unwrap() } } +#[cfg(windows)] +macro_rules! declare { + ($symbol:ident: fn($($i:ty),+) -> $o:ty) => { + pub fn $symbol() -> Option $o> { + None + } + } +} + +#[cfg(not(windows))] macro_rules! declare { ($symbol:ident: fn($($i:ty),+) -> $o:ty) => { pub fn $symbol() -> Option $o> { -- cgit 1.4.1-3-g733a5 From 294c6a93d85df4c1808fc05e8bdf072b256befee Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 17 Sep 2016 21:10:41 -0500 Subject: avoid division overflow in idivmod test --- library/compiler-builtins/src/arm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index b46b0ea77f5..903672fc8fc 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -193,7 +193,7 @@ mod tests { fn idivmod(n: U32, d: U32) -> TestResult { let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 { + if d == 0 || (n == i32::min_value() && d == -1) { TestResult::discard() } else { let q: i32; -- cgit 1.4.1-3-g733a5 From 7a56ac6bb420a44fdfaa02ad1a1c8a0f5969b5be Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 21 Sep 2016 21:14:38 -0500 Subject: armhf: don't compare our impls against gcc_s --- library/compiler-builtins/Cargo.toml | 1 + library/compiler-builtins/build.rs | 7 +++++++ library/compiler-builtins/src/float/add.rs | 23 +++++++++++++++-------- 3 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/build.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 229cec74706..d378461802a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,5 +1,6 @@ [package] authors = ["Jorge Aparicio "] +build = "build.rs" name = "rustc_builtins" version = "0.1.0" diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs new file mode 100644 index 00000000000..1ff0c06218f --- /dev/null +++ b/library/compiler-builtins/build.rs @@ -0,0 +1,7 @@ +use std::env; + +fn main() { + if env::var("TARGET").unwrap().ends_with("hf") { + println!("cargo:rustc-cfg=gnueabihf") + } +} diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 13c7aba678b..0943e2e3bbc 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -216,10 +216,15 @@ mod tests { let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); let x = super::__addsf3(a, b); - if let Some(addsf3) = gcc_s::addsf3() { - x.eq_repr(unsafe { addsf3(a, b) }) - } else { - x.eq_repr(a + b) + match gcc_s::addsf3() { + // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't + // match the output of its gcc_s counterpart. Until we investigate further, we'll + // just avoid testing against gcc_s on those targets. Do note that our + // implementation matches the output of the FPU instruction on *hard* float targets + // and matches its gcc_s counterpart on *soft* float targets. + #[cfg(not(gnueabihf))] + Some(addsf3) => x.eq_repr(unsafe { addsf3(a, b) }), + _ => x.eq_repr(a + b), } } @@ -227,10 +232,12 @@ mod tests { let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); let x = super::__adddf3(a, b); - if let Some(adddf3) = gcc_s::adddf3() { - x.eq_repr(unsafe { adddf3(a, b) }) - } else { - x.eq_repr(a + b) + match gcc_s::adddf3() { + // NOTE(cfg) See NOTE above + #[cfg(not(gnueabihf))] + Some(adddf3) => x.eq_repr(unsafe { adddf3(a, b) }), + _ => x.eq_repr(a + b), + } } } -- cgit 1.4.1-3-g733a5 From bc61db2e36cbd7776aaac320b628abee494b50e2 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 21 Sep 2016 21:38:06 -0500 Subject: don't test always against gcc_s instead test half of the time against gcc_s and the other half test against the native operation (\*). (\*) Not all the targets have available a native version of the intrinsics under test. On those targets we'll end up testing our implementation against itself half of the time. This is not much of a problem because we do several quickcheck runs per intrinsic. --- library/compiler-builtins/Cargo.toml | 10 +++- library/compiler-builtins/src/float/add.rs | 10 ++-- library/compiler-builtins/src/int/mul.rs | 45 +++++++++--------- library/compiler-builtins/src/int/sdiv.rs | 74 +++++++++++++++++------------- library/compiler-builtins/src/int/shift.rs | 31 +++++++------ library/compiler-builtins/src/int/udiv.rs | 74 +++++++++++++++++------------- library/compiler-builtins/src/lib.rs | 3 ++ 7 files changed, 141 insertions(+), 106 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d378461802a..e086f7c6ffb 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,11 +5,17 @@ name = "rustc_builtins" version = "0.1.0" [dependencies] -rlibc = { git = "https://github.com/alexcrichton/rlibc", optional = true } + +[dependencies.rlibc] +git = "https://github.com/alexcrichton/rlibc" +optional = true [dev-dependencies] -gcc_s = { path = "gcc_s" } quickcheck = "0.3.1" +rand = "0.3.14" + +[dev-dependencies.gcc_s] +path = "gcc_s" [features] default = ["rlibc/weak"] diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 0943e2e3bbc..14ff2f45e22 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -200,9 +200,11 @@ pub extern fn __aeabi_fadd(a: f32, b: f32) -> f32 { mod tests { use core::{f32, f64}; - use gcc_s; - use qc::{U32, U64}; use float::Float; + use qc::{U32, U64}; + + use gcc_s; + use rand; // NOTE The tests below have special handing for NaN values. // Because NaN != NaN, the floating-point representations must be used @@ -223,7 +225,7 @@ mod tests { // implementation matches the output of the FPU instruction on *hard* float targets // and matches its gcc_s counterpart on *soft* float targets. #[cfg(not(gnueabihf))] - Some(addsf3) => x.eq_repr(unsafe { addsf3(a, b) }), + Some(addsf3) if rand::random() => x.eq_repr(unsafe { addsf3(a, b) }), _ => x.eq_repr(a + b), } } @@ -235,7 +237,7 @@ mod tests { match gcc_s::adddf3() { // NOTE(cfg) See NOTE above #[cfg(not(gnueabihf))] - Some(adddf3) => x.eq_repr(unsafe { adddf3(a, b) }), + Some(adddf3) if rand::random() => x.eq_repr(unsafe { adddf3(a, b) }), _ => x.eq_repr(a + b), } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 4ea65bd28dc..dea3499d4c5 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -72,18 +72,19 @@ mulo!(__mulodi4: i64); #[cfg(test)] mod tests { - use gcc_s; use qc::{I32, I64, U64}; + use gcc_s; + use rand; + quickcheck! { fn muldi(a: U64, b: U64) -> bool { let (a, b) = (a.0, b.0); let r = super::__muldi3(a, b); - if let Some(muldi3) = gcc_s::muldi3() { - r == unsafe { muldi3(a, b) } - } else { - r == a.wrapping_mul(b) + match gcc_s::muldi3() { + Some(muldi3) if rand::random() => r == unsafe { muldi3(a, b) }, + _ => r == a.wrapping_mul(b), } } @@ -95,15 +96,16 @@ mod tests { return false; } - if let Some(mulosi4) = gcc_s::mulosi4() { - let mut gcc_s_overflow = 2; - let gcc_s_r = unsafe { - mulosi4(a, b, &mut gcc_s_overflow) - }; + match gcc_s::mulosi4() { + Some(mulosi4) if rand::random() => { + let mut gcc_s_overflow = 2; + let gcc_s_r = unsafe { + mulosi4(a, b, &mut gcc_s_overflow) + }; - (r, overflow) == (gcc_s_r, gcc_s_overflow) - } else { - (r, overflow != 0) == a.overflowing_mul(b) + (r, overflow) == (gcc_s_r, gcc_s_overflow) + }, + _ => (r, overflow != 0) == a.overflowing_mul(b), } } @@ -115,15 +117,16 @@ mod tests { return false; } - if let Some(mulodi4) = gcc_s::mulodi4() { - let mut gcc_s_overflow = 2; - let gcc_s_r = unsafe { - mulodi4(a, b, &mut gcc_s_overflow) - }; + match gcc_s::mulodi4() { + Some(mulodi4) if rand::random() => { + let mut gcc_s_overflow = 2; + let gcc_s_r = unsafe { + mulodi4(a, b, &mut gcc_s_overflow) + }; - (r, overflow) == (gcc_s_r, gcc_s_overflow) - } else { - (r, overflow != 0) == a.overflowing_mul(b) + (r, overflow) == (gcc_s_r, gcc_s_overflow) + }, + _ => (r, overflow != 0) == a.overflowing_mul(b), } } } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 50ad0e0a525..fcb9ed9d9e8 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -52,9 +52,11 @@ divmod!(__divmoddi4, __divdi3: i64); #[cfg(test)] mod tests { + use qc::{U32, U64}; + use gcc_s; use quickcheck::TestResult; - use qc::{U32, U64}; + use rand; quickcheck!{ fn divdi3(n: U64, d: U64) -> TestResult { @@ -64,10 +66,11 @@ mod tests { } else { let q = super::__divdi3(n, d); - if let Some(divdi3) = gcc_s::divdi3() { - TestResult::from_bool(q == unsafe { divdi3(n, d) }) - } else { - TestResult::from_bool(q == n / d) + match gcc_s::divdi3() { + Some(divdi3) if rand::random() => { + TestResult::from_bool(q == unsafe { divdi3(n, d) }) + }, + _ => TestResult::from_bool(q == n / d), } } } @@ -79,10 +82,11 @@ mod tests { } else { let r = super::__moddi3(n, d); - if let Some(moddi3) = gcc_s::moddi3() { - TestResult::from_bool(r == unsafe { moddi3(n, d) }) - } else { - TestResult::from_bool(r == n % d) + match gcc_s::moddi3() { + Some(moddi3) if rand::random() => { + TestResult::from_bool(r == unsafe { moddi3(n, d) }) + }, + _ => TestResult::from_bool(r == n % d), } } } @@ -95,15 +99,16 @@ mod tests { let mut r = 0; let q = super::__divmoddi4(n, d, &mut r); - if let Some(divmoddi4) = gcc_s::divmoddi4() { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - divmoddi4(n, d, &mut gcc_s_r) - }; + match gcc_s::divmoddi4() { + Some(divmoddi4) if rand::random() => { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + divmoddi4(n, d, &mut gcc_s_r) + }; - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - } else { - TestResult::from_bool(q == n / d && r == n % d) + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + }, + _ => TestResult::from_bool(q == n / d && r == n % d), } } } @@ -115,10 +120,11 @@ mod tests { } else { let q = super::__divsi3(n, d); - if let Some(divsi3) = gcc_s::divsi3() { - TestResult::from_bool(q == unsafe { divsi3(n, d)}) - } else { - TestResult::from_bool(q == n / d) + match gcc_s::divsi3() { + Some(divsi3) if rand::random() => { + TestResult::from_bool(q == unsafe { divsi3(n, d)}) + }, + _ => TestResult::from_bool(q == n / d), } } } @@ -130,10 +136,11 @@ mod tests { } else { let r = super::__modsi3(n, d); - if let Some(modsi3) = gcc_s::modsi3() { - TestResult::from_bool(r == unsafe { modsi3(n, d) }) - } else { - TestResult::from_bool(r == n % d) + match gcc_s::modsi3() { + Some(modsi3) if rand::random() => { + TestResult::from_bool(r == unsafe { modsi3(n, d) }) + }, + _ => TestResult::from_bool(r == n % d), } } } @@ -146,15 +153,16 @@ mod tests { let mut r = 0; let q = super::__divmodsi4(n, d, &mut r); - if let Some(divmodsi4) = gcc_s::divmodsi4() { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - divmodsi4(n, d, &mut gcc_s_r) - }; + match gcc_s::divmodsi4() { + Some(divmodsi4) if rand::random() => { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + divmodsi4(n, d, &mut gcc_s_r) + }; - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - } else { - TestResult::from_bool(q == n / d && r == n % d) + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + }, + _ => TestResult::from_bool(q == n / d && r == n % d), } } } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index c7be81171c4..bafc9dbe0ce 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -60,9 +60,11 @@ lshr!(__lshrdi3: u64); #[cfg(test)] mod tests { + use qc::{I64, U64}; + use gcc_s; use quickcheck::TestResult; - use qc::{I64, U64}; + use rand; // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) quickcheck! { @@ -73,10 +75,11 @@ mod tests { } else { let r = super::__ashldi3(a, b); - if let Some(ashldi3) = gcc_s::ashldi3() { - TestResult::from_bool(r == unsafe { ashldi3(a, b) }) - } else { - TestResult::from_bool(r == a << b) + match gcc_s::ashldi3() { + Some(ashldi3) if rand::random() => { + TestResult::from_bool(r == unsafe { ashldi3(a, b) }) + }, + _ => TestResult::from_bool(r == a << b), } } } @@ -88,10 +91,11 @@ mod tests { } else { let r = super::__ashrdi3(a, b); - if let Some(ashrdi3) = gcc_s::ashrdi3() { - TestResult::from_bool(r == unsafe { ashrdi3(a, b) }) - } else { - TestResult::from_bool(r == a >> b) + match gcc_s::ashrdi3() { + Some(ashrdi3) if rand::random() => { + TestResult::from_bool(r == unsafe { ashrdi3(a, b) }) + }, + _ => TestResult::from_bool(r == a >> b), } } } @@ -103,10 +107,11 @@ mod tests { } else { let r = super::__lshrdi3(a, b); - if let Some(lshrdi3) = gcc_s::lshrdi3() { - TestResult::from_bool(r == unsafe { lshrdi3(a, b) }) - } else { - TestResult::from_bool(r == a >> b) + match gcc_s::lshrdi3() { + Some(lshrdi3) if rand::random() => { + TestResult::from_bool(r == unsafe { lshrdi3(a, b) }) + }, + _ => TestResult::from_bool(r == a >> b), } } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 8c9d06f21df..89793c8a82e 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -228,9 +228,11 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { #[cfg(test)] mod tests { + use qc::{U32, U64}; + use gcc_s; use quickcheck::TestResult; - use qc::{U32, U64}; + use rand; quickcheck!{ fn udivdi3(n: U64, d: U64) -> TestResult { @@ -240,10 +242,11 @@ mod tests { } else { let q = super::__udivdi3(n, d); - if let Some(udivdi3) = gcc_s::udivdi3() { - TestResult::from_bool(q == unsafe { udivdi3(n, d) }) - } else { - TestResult::from_bool(q == n / d) + match gcc_s::udivdi3() { + Some(udivdi3) if rand::random() => { + TestResult::from_bool(q == unsafe { udivdi3(n, d) }) + }, + _ => TestResult::from_bool(q == n / d), } } } @@ -255,10 +258,11 @@ mod tests { } else { let r = super::__umoddi3(n, d); - if let Some(umoddi3) = gcc_s::umoddi3() { - TestResult::from_bool(r == unsafe { umoddi3(n, d) }) - } else { - TestResult::from_bool(r == n % d) + match gcc_s::umoddi3() { + Some(umoddi3) if rand::random() => { + TestResult::from_bool(r == unsafe { umoddi3(n, d) }) + }, + _ => TestResult::from_bool(r == n % d), } } } @@ -271,15 +275,16 @@ mod tests { let mut r = 0; let q = super::__udivmoddi4(n, d, Some(&mut r)); - if let Some(udivmoddi4) = gcc_s::udivmoddi4() { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - udivmoddi4(n, d, Some(&mut gcc_s_r)) - }; + match gcc_s::udivmoddi4() { + Some(udivmoddi4) if rand::random() => { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + udivmoddi4(n, d, Some(&mut gcc_s_r)) + }; - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - } else { - TestResult::from_bool(q == n / d && r == n % d) + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + }, + _ => TestResult::from_bool(q == n / d && r == n % d), } } } @@ -291,10 +296,11 @@ mod tests { } else { let q = super::__udivsi3(n, d); - if let Some(udivsi3) = gcc_s::udivsi3() { - TestResult::from_bool(q == unsafe { udivsi3(n, d) }) - } else { - TestResult::from_bool(q == n / d) + match gcc_s::udivsi3() { + Some(udivsi3) if rand::random() => { + TestResult::from_bool(q == unsafe { udivsi3(n, d) }) + }, + _ => TestResult::from_bool(q == n / d), } } } @@ -306,10 +312,11 @@ mod tests { } else { let r = super::__umodsi3(n, d); - if let Some(umodsi3) = gcc_s::umodsi3() { - TestResult::from_bool(r == unsafe { umodsi3(n, d) }) - } else { - TestResult::from_bool(r == n % d) + match gcc_s::umodsi3() { + Some(umodsi3) if rand::random() => { + TestResult::from_bool(r == unsafe { umodsi3(n, d) }) + }, + _ => TestResult::from_bool(r == n % d), } } } @@ -322,15 +329,16 @@ mod tests { let mut r = 0; let q = super::__udivmodsi4(n, d, Some(&mut r)); - if let Some(udivmodsi4) = gcc_s::udivmodsi4() { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - udivmodsi4(n, d, Some(&mut gcc_s_r)) - }; + match gcc_s::udivmodsi4() { + Some(udivmodsi4) if rand::random() => { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + udivmodsi4(n, d, Some(&mut gcc_s_r)) + }; - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - } else { - TestResult::from_bool(q == n / d && r == n % d) + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + }, + _ => TestResult::from_bool(q == n / d && r == n % d), } } } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index cba1604c0e1..88bbbec3594 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -20,6 +20,9 @@ extern crate core; #[cfg(test)] extern crate gcc_s; +#[cfg(test)] +extern crate rand; + #[cfg(all(not(windows), not(target_os = "macos")))] extern crate rlibc; -- cgit 1.4.1-3-g733a5 From 34f17b2ecf2718868d1c74d188dc461761adab5c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 22 Sep 2016 06:15:05 -0500 Subject: test the thumbv7em-none-eabihf target --- library/compiler-builtins/.travis.yml | 2 ++ library/compiler-builtins/ci/env.sh | 2 +- library/compiler-builtins/thumbv7em-none-eabihf.json | 9 +++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/thumbv7em-none-eabihf.json diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 5496bb29131..d4a1319c7b6 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -34,6 +34,8 @@ matrix: os: linux - env: TARGET=thumbv7em-none-eabi os: linux + - env: TARGET=thumbv7em-none-eabihf + os: linux - env: TARGET=thumbv7m-none-eabi os: linux - env: TARGET=x86_64-apple-darwin diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index feeac221389..6275107b55c 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -32,7 +32,7 @@ if [[ $TARGET != $HOST && ! $TARGET =~ ^i.86- ]]; then # `int main() { return 0; }` RUN_TESTS=n ;; - thumbv*-none-eabi) + thumbv*-none-eabi*) CARGO=xargo GCC_TRIPLE=arm-none-eabi # Bare metal targets. No `std` or `test` crates for these targets. diff --git a/library/compiler-builtins/thumbv7em-none-eabihf.json b/library/compiler-builtins/thumbv7em-none-eabihf.json new file mode 100644 index 00000000000..bb0b87eb41f --- /dev/null +++ b/library/compiler-builtins/thumbv7em-none-eabihf.json @@ -0,0 +1,9 @@ +{ + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "features": "+vfp4", + "llvm-target": "thumbv7em-none-eabihf", + "os": "none", + "target-endian": "little", + "target-pointer-width": "32" +} -- cgit 1.4.1-3-g733a5 From a83c11232ea6d59ea750990834ca94ced5fb315e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 17 Sep 2016 21:10:41 -0500 Subject: avoid division overflow in idivmod test --- library/compiler-builtins/src/arm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index b46b0ea77f5..903672fc8fc 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -193,7 +193,7 @@ mod tests { fn idivmod(n: U32, d: U32) -> TestResult { let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 { + if d == 0 || (n == i32::min_value() && d == -1) { TestResult::discard() } else { let q: i32; -- cgit 1.4.1-3-g733a5 From a5b15eef7106bcf385e07116786d58895fd97fbf Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 22 Sep 2016 11:56:34 -0500 Subject: fix build.rs we don't want to match musleabihf targets --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 1ff0c06218f..298b656a114 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,7 +1,7 @@ use std::env; fn main() { - if env::var("TARGET").unwrap().ends_with("hf") { + if env::var("TARGET").unwrap().ends_with("gnueabihf") { println!("cargo:rustc-cfg=gnueabihf") } } -- cgit 1.4.1-3-g733a5 From 2d630eedfdfe076b71b2562bf14e5aec63028d16 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 22 Sep 2016 12:44:22 -0500 Subject: add missing aeabi aliases --- library/compiler-builtins/src/arm.rs | 36 +++++++++++++++++++++++++++--- library/compiler-builtins/src/float/add.rs | 13 ----------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index b46b0ea77f5..17423cd8fa3 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -57,10 +57,15 @@ pub unsafe fn __aeabi_ldivmod() { intrinsics::unreachable(); } -// TODO: These two functions should be defined as aliases +// TODO: These aeabi_* functions should be defined as aliases #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { - ::int::udiv::__udivsi3(a, b) +pub extern "C" fn __aeabi_dadd(a: f64, b: f64) -> f64 { + ::float::add::__adddf3(a, b) +} + +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_fadd(a: f32, b: f32) -> f32 { + ::float::add::__addsf3(a, b) } #[cfg_attr(not(test), no_mangle)] @@ -68,6 +73,31 @@ pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 { ::int::sdiv::__divsi3(a, b) } +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_lasr(a: i64, b: u32) -> i64 { + ::int::shift::__ashrdi3(a, b) +} + +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_llsl(a: u64, b: u32) -> u64 { + ::int::shift::__ashldi3(a, b) +} + +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_llsr(a: u64, b: u32) -> u64 { + ::int::shift::__lshrdi3(a, b) +} + +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_lmul(a: u64, b: u64) -> u64 { + ::int::mul::__muldi3(a, b) +} + +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { + ::int::udiv::__udivsi3(a, b) +} + extern "C" { fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 3ebc92b3237..076a462862e 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -183,19 +183,6 @@ macro_rules! add { add!(__addsf3: f32); add!(__adddf3: f64); -// FIXME: Implement these using aliases -#[cfg(target_arch = "arm")] -#[cfg_attr(not(test), no_mangle)] -pub extern fn __aeabi_dadd(a: f64, b: f64) -> f64 { - __adddf3(a, b) -} - -#[cfg(target_arch = "arm")] -#[cfg_attr(not(test), no_mangle)] -pub extern fn __aeabi_fadd(a: f32, b: f32) -> f32 { - __addsf3(a, b) -} - #[cfg(test)] mod tests { use core::{f32, f64}; -- cgit 1.4.1-3-g733a5 From 2dc91bd96cbf4fefb38bd025539bc86c3ee59319 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 22 Sep 2016 14:46:05 -0500 Subject: put weak mem* symbols behind an opt-in Cargo feature closes #64 cc #66 --- library/compiler-builtins/.travis.yml | 8 ++++++++ library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/ci/script.sh | 25 ++++++++++++++++++++----- library/compiler-builtins/src/lib.rs | 2 +- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index d4a1319c7b6..74f3a08a045 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -32,12 +32,20 @@ matrix: os: linux - env: TARGET=thumbv6m-none-eabi os: linux + - env: TARGET=thumbv6m-none-eabi WEAK=true + os: linux - env: TARGET=thumbv7em-none-eabi os: linux + - env: TARGET=thumbv7em-none-eabi WEAK=true + os: linux - env: TARGET=thumbv7em-none-eabihf os: linux + - env: TARGET=thumbv7em-none-eabihf WEAK=true + os: linux - env: TARGET=thumbv7m-none-eabi os: linux + - env: TARGET=thumbv7m-none-eabi WEAK=true + os: linux - env: TARGET=x86_64-apple-darwin language: ruby os: osx diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index e086f7c6ffb..ae28057e2a9 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -18,6 +18,6 @@ rand = "0.3.14" path = "gcc_s" [features] -default = ["rlibc/weak"] +weak = ["rlibc/weak"] [workspace] diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 38c6b32376e..9dffac5f16e 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -8,8 +8,13 @@ gist_it() { } build() { - $CARGO build --target $TARGET - $CARGO build --target $TARGET --release + if [[ $WEAK ]]; then + $CARGO build --features weak --target $TARGET + $CARGO build --features weak --target $TARGET --release + else + $CARGO build --target $TARGET + $CARGO build --target $TARGET --release + fi } inspect() { @@ -19,12 +24,21 @@ inspect() { $PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist_it set -e - # Check presence of weak symbols - if [[ $LINUX ]]; then + # Check presence/absence of weak symbols + if [[ $WEAK ]]; then local symbols=( memcmp memcpy memmove memset ) for symbol in "${symbols[@]}"; do - $PREFIX$NM target/**/debug/deps/librlibc*.rlib | grep -q "W $symbol" + $PREFIX$NM target/$TARGET/debug/deps/librlibc-*.rlib | grep -q "W $symbol" done + else + set +e + ls target/$TARGET/debug/deps/librlibc-*.rlib + + if [[ $? == 0 ]]; then + exit 1 + fi + + set -e fi } @@ -50,6 +64,7 @@ main() { -e TRAVIS_BRANCH=$TRAVIS_BRANCH \ -e TRAVIS_COMMIT=$TRAVIS_COMMIT \ -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ + -e WEAK=$WEAK \ -v $(pwd):/mnt \ japaric/rustc-builtins \ sh -c 'cd /mnt; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 88bbbec3594..7f2d39180ff 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -23,7 +23,7 @@ extern crate gcc_s; #[cfg(test)] extern crate rand; -#[cfg(all(not(windows), not(target_os = "macos")))] +#[cfg(feature = "weak")] extern crate rlibc; pub mod int; -- cgit 1.4.1-3-g733a5 From e7c804a9b020c6172273a660e38ed86b6362e22c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 26 Sep 2016 22:22:10 -0700 Subject: Expand and refactor teting infrastructure This commit moves over most of the testing infrastructure to in-tree docker images that are all dispatched to from Travis (no other test configuration). This allows versioning modifications to the test infrastructure as well as the code itself. Additionally separate docker images allows for easy modification of one without worrying about tampering of others as well as easy addition of new targets by simply adding a new `Dockerfile`. Additionally this commit bundles the master version of the `compiler-rt` source repository from `llvm-mirror/compiler-rt` to test against. The compiler-rt library itself is compiled as a `cdylib` which is then dynamically located at runtime and we look for symbols in. There's a few hoops here, but they currently get the job done. All tests now execute against both gcc_s and compiler-rt, and this testing strategy is now all hidden behind a macro as well (refactoring all existing tests along the way). --- library/compiler-builtins/.gitmodules | 3 + library/compiler-builtins/.travis.yml | 65 +++++------ library/compiler-builtins/Cargo.toml | 5 +- library/compiler-builtins/README.md | 6 +- library/compiler-builtins/appveyor.yml | 1 + library/compiler-builtins/build.rs | 1 + .../ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 10 ++ .../ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 10 ++ .../docker/arm-unknown-linux-gnueabihf/Dockerfile | 9 ++ .../armv7-unknown-linux-gnueabihf/Dockerfile | 9 ++ .../ci/docker/i586-unknown-linux-gnu/Dockerfile | 5 + .../ci/docker/i686-unknown-linux-gnu/Dockerfile | 5 + .../ci/docker/mips-unknown-linux-gnu/Dockerfile | 12 ++ .../ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 12 ++ .../ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 12 ++ .../docker/powerpc64-unknown-linux-gnu/Dockerfile | 13 +++ .../powerpc64le-unknown-linux-gnu/Dockerfile | 13 +++ .../ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 6 + library/compiler-builtins/ci/env.sh | 51 --------- library/compiler-builtins/ci/install.sh | 53 --------- library/compiler-builtins/ci/run-docker.sh | 29 +++++ library/compiler-builtins/ci/script.sh | 80 -------------- library/compiler-builtins/compiler-rt/Cargo.toml | 8 ++ .../compiler-rt/compiler-rt-cdylib/Cargo.toml | 11 ++ .../compiler-rt/compiler-rt-cdylib/build.rs | 68 ++++++++++++ .../compiler-rt/compiler-rt-cdylib/compiler-rt | 1 + .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 60 ++++++++++ library/compiler-builtins/compiler-rt/src/lib.rs | 35 ++++++ library/compiler-builtins/gcc_s/src/lib.rs | 39 +------ library/compiler-builtins/src/float/add.rs | 65 ++++++----- library/compiler-builtins/src/float/mod.rs | 6 +- library/compiler-builtins/src/int/mul.rs | 58 +++------- library/compiler-builtins/src/int/sdiv.rs | 104 +++++------------- library/compiler-builtins/src/int/shift.rs | 45 ++------ library/compiler-builtins/src/int/udiv.rs | 100 +++++------------ library/compiler-builtins/src/lib.rs | 11 +- library/compiler-builtins/src/qc.rs | 121 +++++++++++++++++++++ library/compiler-builtins/src/x86_64.rs | 2 + 38 files changed, 621 insertions(+), 523 deletions(-) create mode 100644 library/compiler-builtins/.gitmodules create mode 100644 library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/ci/env.sh delete mode 100644 library/compiler-builtins/ci/install.sh create mode 100644 library/compiler-builtins/ci/run-docker.sh delete mode 100644 library/compiler-builtins/ci/script.sh create mode 100644 library/compiler-builtins/compiler-rt/Cargo.toml create mode 100644 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml create mode 100644 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs create mode 160000 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt create mode 100644 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs create mode 100644 library/compiler-builtins/compiler-rt/src/lib.rs diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules new file mode 100644 index 00000000000..fe501bba965 --- /dev/null +++ b/library/compiler-builtins/.gitmodules @@ -0,0 +1,3 @@ +[submodule "compiler-rt/compiler-rt-cdylib/compiler-rt"] + path = compiler-rt/compiler-rt-cdylib/compiler-rt + url = https://github.com/llvm-mirror/compiler-rt diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 74f3a08a045..47252a41794 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,62 +1,63 @@ dist: trusty -language: generic +language: rust services: docker sudo: required +rust: nightly +cache: cargo matrix: include: - env: TARGET=aarch64-unknown-linux-gnu - os: linux - env: TARGET=arm-unknown-linux-gnueabi - os: linux + # FIXME(rust-lang/rust#36518) + rust: nightly-2016-09-21 - env: TARGET=arm-unknown-linux-gnueabihf - os: linux - env: TARGET=armv7-unknown-linux-gnueabihf - os: linux - env: TARGET=i586-unknown-linux-gnu - os: linux - env: TARGET=i686-apple-darwin - language: ruby + # FIXME(rust-lang/rust#36793) + rust: nightly-2016-09-10 os: osx - env: TARGET=i686-unknown-linux-gnu - os: linux + # FIXME(rust-lang/rust#36793) + rust: nightly-2016-09-10 - env: TARGET=mips-unknown-linux-gnu - os: linux - env: TARGET=mipsel-unknown-linux-gnu - os: linux - env: TARGET=powerpc-unknown-linux-gnu - os: linux - env: TARGET=powerpc64-unknown-linux-gnu - os: linux - - env: TARGET=powerpc64le-unknown-linux-gnu - os: linux + # QEMU crashes even when executing the simplest cross compiled C program: + # `int main() { return 0; }` + - env: TARGET=powerpc64le-unknown-linux-gnu NO_RUN=1 - env: TARGET=thumbv6m-none-eabi - os: linux - - env: TARGET=thumbv6m-none-eabi WEAK=true - os: linux + install: cargo install xargo --debug -f + script: $HOME/.cargo/bin/xargo build --target $TARGET - env: TARGET=thumbv7em-none-eabi - os: linux - - env: TARGET=thumbv7em-none-eabi WEAK=true - os: linux + install: cargo install xargo --debug -f + script: $HOME/.cargo/bin/xargo build --target $TARGET - env: TARGET=thumbv7em-none-eabihf - os: linux - - env: TARGET=thumbv7em-none-eabihf WEAK=true - os: linux - - env: TARGET=thumbv7m-none-eabi - os: linux - - env: TARGET=thumbv7m-none-eabi WEAK=true - os: linux + install: cargo install xargo --debug -f + script: $HOME/.cargo/bin/xargo build --target $TARGET - env: TARGET=x86_64-apple-darwin - language: ruby os: osx - - env: TARGET=x86_64-unknown-linux-gnu - os: linux +env: TARGET=x86_64-unknown-linux-gnu + +before_install: + - test "$TRAVIS_OS_NAME" = "osx" || docker run --rm --privileged multiarch/qemu-user-static:register install: - - bash ci/install.sh + - curl https://static.rust-lang.org/rustup.sh | + sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot` script: - - bash ci/script.sh + - cargo generate-lockfile + - if [[ $TRAVIS_OS_NAME = "linux" ]]; then + sudo apt-get remove -y qemu-user-static && + sudo apt-get install -y qemu-user-static && + sh ci/run-docker.sh $TARGET; + else + cargo test --target $TARGET && + cargo test --target $TARGET --release; + fi branches: only: diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index ae28057e2a9..6e75a116bbf 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -13,9 +13,8 @@ optional = true [dev-dependencies] quickcheck = "0.3.1" rand = "0.3.14" - -[dev-dependencies.gcc_s] -path = "gcc_s" +gcc_s = { path = "gcc_s" } +compiler-rt = { path = "compiler-rt" } [features] weak = ["rlibc/weak"] diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index edccd301838..28d86043ad5 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -16,8 +16,8 @@ See [rust-lang/rust#35437][0]. If you are working with a target that doesn't have binary releases of std available via rustup (this probably means you are building the core crate yourself) and need compiler-rt intrinsics (i.e. you -are probably getting linker errors when building an executable: "undefined reference to -__aeabi_memcpy"), you can use this crate to get those intrinsics and solve the linker errors. To do +are probably getting linker errors when building an executable: `undefined reference to +__aeabi_memcpy`), you can use this crate to get those intrinsics and solve the linker errors. To do that, simply add this crate as a Cargo dependency (it doesn't matter where in the dependency graph this crate ends up, as long as it's there): @@ -52,7 +52,7 @@ porting that particular intrinsic. 1. [Rust][4] and [C][5] have slightly different operator precedence. C evaluates comparisons (`== !=`) before bitwise operations (`& | ^`), while Rust evaluates the other way. 2. C assumes wrapping operations everywhere. Rust panics on overflow when in debug mode. Consider using the [Wrapping][6] type or the explicit [wrapping_*][7] functions where applicable. 3. Note [C implicit casts][8], especially integer promotion. Rust is much more explicit about casting, so be sure that any cast which affects the output is ported to the Rust implementation. -4. Rust has [many functions][9] for integer or floating point manipulation in the standard library. Consider using one of these functions rather than porting a new one. +4. Rust has [many functions][9] for integer or floating point manipulation in the standard library. Consider using one of these functions rather than porting a new one. [4]: https://doc.rust-lang.org/reference.html#operator-precedence [5]: http://en.cppreference.com/w/c/language/operator_precedence diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index b34efc21e61..0e64977c175 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -4,6 +4,7 @@ environment: - TARGET: x86_64-pc-windows-msvc install: + - git submodule update --init - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe --default-host %TARGET% --default-toolchain nightly -y - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 298b656a114..3ef6c289554 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4,4 +4,5 @@ fn main() { if env::var("TARGET").unwrap().ends_with("gnueabihf") { println!("cargo:rustc-cfg=gnueabihf") } + println!("cargo:rerun-if-changed=build.rs"); } diff --git a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..6a68154d192 --- /dev/null +++ b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ + qemu-user-static +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile new file mode 100644 index 00000000000..36efcd73ccc --- /dev/null +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ + RUST_TEST_THREADS=1 + diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile new file mode 100644 index 00000000000..83e7e52e8f2 --- /dev/null +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile new file mode 100644 index 00000000000..adc15a5c5c5 --- /dev/null +++ b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static +ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..63450ff9e0e --- /dev/null +++ b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc-multilib libc6-dev ca-certificates +ENV PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..63450ff9e0e --- /dev/null +++ b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc-multilib libc6-dev ca-certificates +ENV PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..328152471f8 --- /dev/null +++ b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-mips-linux-gnu libc6-dev-mips-cross \ + binfmt-support qemu-user-static qemu-system-mips + +ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/mips-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..088c45f04a8 --- /dev/null +++ b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ + binfmt-support qemu-user-static + +ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..542afa2f4d9 --- /dev/null +++ b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ + qemu-system-ppc + +ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..f4559c7de99 --- /dev/null +++ b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ + binfmt-support qemu-user-static qemu-system-ppc + +ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ + CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..9a777883d24 --- /dev/null +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ + qemu-system-ppc + +ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ + CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..a5704bb64b4 --- /dev/null +++ b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,6 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates +ENV PATH=$PATH:/rust/bin + diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh deleted file mode 100644 index 6275107b55c..00000000000 --- a/library/compiler-builtins/ci/env.sh +++ /dev/null @@ -1,51 +0,0 @@ -case $TRAVIS_OS_NAME in - linux) - HOST=x86_64-unknown-linux-gnu - NM=nm - OBJDUMP=objdump - LINUX=y - ;; - osx) - HOST=x86_64-apple-darwin - NM=gnm - OBJDUMP=gobjdump - OSX=y - ;; -esac - -# NOTE For rustup -export PATH="$HOME/.cargo/bin:$PATH" - -CARGO=cargo -RUN_TESTS=y - -# NOTE For the host and its 32-bit variants we don't need prefixed tools or QEMU -if [[ $TARGET != $HOST && ! $TARGET =~ ^i.86- ]]; then - GCC_TRIPLE=${TARGET//unknown-/} - - case $TARGET in - armv7-unknown-linux-gnueabihf) - GCC_TRIPLE=arm-linux-gnueabihf - ;; - powerpc64le-unknown-linux-gnu) - # QEMU crashes even when executing the simplest cross compiled C program: - # `int main() { return 0; }` - RUN_TESTS=n - ;; - thumbv*-none-eabi*) - CARGO=xargo - GCC_TRIPLE=arm-none-eabi - # Bare metal targets. No `std` or `test` crates for these targets. - RUN_TESTS=n - ;; - esac - - export CARGO_TARGET_$(echo $TARGET | tr a-z- A-Z_)_LINKER=$GCC_TRIPLE-gcc - - if [[ $RUN_TESTS == y ]]; then - # NOTE(export) so this can reach the processes that `cargo test` spawns - export QEMU_LD_PREFIX=/usr/$GCC_TRIPLE - fi - - PREFIX=$GCC_TRIPLE- -fi diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh deleted file mode 100644 index 86095e33e89..00000000000 --- a/library/compiler-builtins/ci/install.sh +++ /dev/null @@ -1,53 +0,0 @@ -set -ex - -. $(dirname $0)/env.sh - -install_qemu() { - if [[ $QEMU_LD_PREFIX ]]; then - apt-get update - apt-get install -y --no-install-recommends \ - binfmt-support qemu-user-static - fi -} - -install_gist() { - if [[ $OSX ]]; then - gem install gist -v 4.5.0 - fi -} - -install_binutils() { - if [[ $OSX ]]; then - brew install binutils - fi -} - -install_rust() { - if [[ $OSX ]]; then - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly - else - rustup default nightly - fi - - rustup -V - rustc -V - cargo -V -} - -add_rustup_target() { - if [[ $TARGET != $HOST && $CARGO == cargo ]]; then - rustup target add $TARGET - fi -} - -main() { - if [[ $OSX || ${IN_DOCKER_CONTAINER:-n} == y ]]; then - install_qemu - install_gist - install_binutils - install_rust - add_rustup_target - fi -} - -main diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh new file mode 100644 index 00000000000..8ef024e8222 --- /dev/null +++ b/library/compiler-builtins/ci/run-docker.sh @@ -0,0 +1,29 @@ +# Small script to run tests for a target (or all targets) inside all the +# respective docker images. + +set -ex + +run() { + echo $1 + CMD="cargo test --target $1" + if [ "$NO_RUN" = "1" ]; then + CMD="$CMD --no-run" + fi + docker build -t libc ci/docker/$1 + docker run \ + -v `rustc --print sysroot`:/rust:ro \ + -v `pwd`:/checkout:ro \ + -e CARGO_TARGET_DIR=/tmp/target \ + -w /checkout \ + --privileged \ + -it libc \ + bash -c "$CMD && $CMD --release" +} + +if [ -z "$1" ]; then + for d in `ls ci/docker/`; do + run $d + done +else + run $1 +fi diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh deleted file mode 100644 index 9dffac5f16e..00000000000 --- a/library/compiler-builtins/ci/script.sh +++ /dev/null @@ -1,80 +0,0 @@ -set -ex - -. $(dirname $0)/env.sh - -gist_it() { - gist -d "'$TARGET/rustc-builtins.rlib' from commit '$TRAVIS_COMMIT' on branch '$TRAVIS_BRANCH'" - echo "Disassembly available at the above URL." -} - -build() { - if [[ $WEAK ]]; then - $CARGO build --features weak --target $TARGET - $CARGO build --features weak --target $TARGET --release - else - $CARGO build --target $TARGET - $CARGO build --target $TARGET --release - fi -} - -inspect() { - $PREFIX$NM -g --defined-only target/**/debug/*.rlib - - set +e - $PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist_it - set -e - - # Check presence/absence of weak symbols - if [[ $WEAK ]]; then - local symbols=( memcmp memcpy memmove memset ) - for symbol in "${symbols[@]}"; do - $PREFIX$NM target/$TARGET/debug/deps/librlibc-*.rlib | grep -q "W $symbol" - done - else - set +e - ls target/$TARGET/debug/deps/librlibc-*.rlib - - if [[ $? == 0 ]]; then - exit 1 - fi - - set -e - fi - -} - -run_tests() { - if [[ $QEMU_LD_PREFIX ]]; then - export RUST_TEST_THREADS=1 - fi - - if [[ $RUN_TESTS == y ]]; then - cargo test --target $TARGET - cargo test --target $TARGET --release - fi -} - -main() { - if [[ $LINUX && ${IN_DOCKER_CONTAINER:-n} == n ]]; then - # NOTE The Dockerfile of this image is in the docker branch of this repository - docker run \ - --privileged \ - -e IN_DOCKER_CONTAINER=y \ - -e TARGET=$TARGET \ - -e TRAVIS_BRANCH=$TRAVIS_BRANCH \ - -e TRAVIS_COMMIT=$TRAVIS_COMMIT \ - -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ - -e WEAK=$WEAK \ - -v $(pwd):/mnt \ - japaric/rustc-builtins \ - sh -c 'cd /mnt; - bash ci/install.sh; - bash ci/script.sh' - else - build - inspect - run_tests - fi -} - -main diff --git a/library/compiler-builtins/compiler-rt/Cargo.toml b/library/compiler-builtins/compiler-rt/Cargo.toml new file mode 100644 index 00000000000..cac87733a62 --- /dev/null +++ b/library/compiler-builtins/compiler-rt/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "compiler-rt" +version = "0.1.0" +authors = ["Alex Crichton "] + +[dependencies] +compiler-rt-cdylib = { path = "compiler-rt-cdylib" } +libloading = "0.3" diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml new file mode 100644 index 00000000000..3c64d23d37e --- /dev/null +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "compiler-rt-cdylib" +version = "0.1.0" +authors = ["Alex Crichton "] +build = "build.rs" + +[lib] +crate-type = ["cdylib"] + +[build-dependencies] +gcc = "0.3" diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs new file mode 100644 index 00000000000..b9b56a627b0 --- /dev/null +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs @@ -0,0 +1,68 @@ +extern crate gcc; + +use std::env; +use std::path::Path; +use std::process::Command; + +struct Sources { + files: Vec<&'static str>, +} + +impl Sources { + fn new() -> Sources { + Sources { files: Vec::new() } + } + + fn extend(&mut self, sources: &[&'static str]) { + self.files.extend(sources); + } +} + +fn main() { + if !Path::new("compiler-rt/.git").exists() { + let _ = Command::new("git").args(&["submodule", "update", "--init"]) + .status(); + } + + let target = env::var("TARGET").expect("TARGET was not set"); + let cfg = &mut gcc::Config::new(); + + if target.contains("msvc") { + cfg.define("__func__", Some("__FUNCTION__")); + } else { + cfg.flag("-fno-builtin"); + cfg.flag("-fomit-frame-pointer"); + cfg.flag("-ffreestanding"); + } + + let mut sources = Sources::new(); + + sources.extend(&[ + "muldi3.c", + "mulosi4.c", + "mulodi4.c", + "divsi3.c", + "divdi3.c", + "modsi3.c", + "moddi3.c", + "divmodsi4.c", + "divmoddi4.c", + "ashldi3.c", + "ashrdi3.c", + "lshrdi3.c", + "udivdi3.c", + "umoddi3.c", + "udivmoddi4.c", + "udivsi3.c", + "umodsi3.c", + "udivmodsi4.c", + "adddf3.c", + "addsf3.c", + ]); + + for src in sources.files.iter() { + cfg.file(Path::new("compiler-rt/lib/builtins").join(src)); + } + + cfg.compile("libcompiler-rt.a"); +} diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt new file mode 160000 index 00000000000..515106ebc07 --- /dev/null +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt @@ -0,0 +1 @@ +Subproject commit 515106ebc07227b85336816ef77bc39506b8fd26 diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs new file mode 100644 index 00000000000..57584832ff8 --- /dev/null +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -0,0 +1,60 @@ +#![feature(lang_items)] +#![no_std] + +extern { + fn __ashldi3(); + fn __ashrdi3(); + fn __divdi3(); + fn __divmoddi4(); + fn __divmodsi4(); + fn __divsi3(); + fn __lshrdi3(); + fn __moddi3(); + fn __modsi3(); + fn __muldi3(); + fn __mulodi4(); + fn __mulosi4(); + fn __udivdi3(); + fn __udivmoddi4(); + fn __udivmodsi4(); + fn __udivsi3(); + fn __umoddi3(); + fn __umodsi3(); + fn __addsf3(); + fn __adddf3(); +} + +macro_rules! declare { + ($func:ident, $sym:ident) => { + #[no_mangle] + pub extern fn $func() -> usize { + $sym as usize + } + } +} + +declare!(___ashldi3, __ashldi3); +declare!(___ashrdi3, __ashrdi3); +declare!(___divdi3, __divdi3); +declare!(___divmoddi4, __divmoddi4); +declare!(___divmodsi4, __divmodsi4); +declare!(___divsi3, __divsi3); +declare!(___lshrdi3, __lshrdi3); +declare!(___moddi3, __moddi3); +declare!(___modsi3, __modsi3); +declare!(___muldi3, __muldi3); +declare!(___mulodi4, __mulodi4); +declare!(___mulosi4, __mulosi4); +declare!(___udivdi3, __udivdi3); +declare!(___udivmoddi4, __udivmoddi4); +declare!(___udivmodsi4, __udivmodsi4); +declare!(___udivsi3, __udivsi3); +declare!(___umoddi3, __umoddi3); +declare!(___umodsi3, __umodsi3); +declare!(___addsf3, __addsf3); +declare!(___adddf3, __adddf3); + +#[lang = "eh_personality"] +fn eh_personality() {} +#[lang = "panic_fmt"] +fn panic_fmt() {} diff --git a/library/compiler-builtins/compiler-rt/src/lib.rs b/library/compiler-builtins/compiler-rt/src/lib.rs new file mode 100644 index 00000000000..ca99f397f55 --- /dev/null +++ b/library/compiler-builtins/compiler-rt/src/lib.rs @@ -0,0 +1,35 @@ +#![feature(drop_types_in_const)] + +extern crate libloading; + +use std::sync::{Once, ONCE_INIT}; +use std::env; + +use libloading::Library; + +fn compiler_rt() -> &'static Library { + let dir = env::current_exe().unwrap(); + let cdylib = dir.parent().unwrap().read_dir().unwrap().map(|c| { + c.unwrap().path() + }).find(|path| { + path.file_name().unwrap().to_str().unwrap().contains("compiler_rt_cdylib") + }).unwrap(); + + unsafe { + static mut COMPILER_RT: Option = None; + static INIT: Once = ONCE_INIT; + + INIT.call_once(|| { + COMPILER_RT = Some(Library::new(&cdylib).unwrap()); + }); + COMPILER_RT.as_ref().unwrap() + } +} + +pub fn get(sym: &str) -> usize { + unsafe { + let sym = format!("_{}", sym); + let f: fn() -> usize = *compiler_rt().get(sym.as_bytes()).unwrap(); + f() + } +} diff --git a/library/compiler-builtins/gcc_s/src/lib.rs b/library/compiler-builtins/gcc_s/src/lib.rs index fa034b0b3dd..e3417ffb591 100644 --- a/library/compiler-builtins/gcc_s/src/lib.rs +++ b/library/compiler-builtins/gcc_s/src/lib.rs @@ -27,42 +27,13 @@ fn gcc_s() -> &'static Library { } #[cfg(windows)] -macro_rules! declare { - ($symbol:ident: fn($($i:ty),+) -> $o:ty) => { - pub fn $symbol() -> Option $o> { - None - } - } +pub fn get(_sym: &str) -> Option { + None } #[cfg(not(windows))] -macro_rules! declare { - ($symbol:ident: fn($($i:ty),+) -> $o:ty) => { - pub fn $symbol() -> Option $o> { - unsafe { - gcc_s().get(concat!("__", stringify!($symbol)).as_bytes()).ok().map(|s| *s) - } - } +pub fn get(sym: &str) -> Option { + unsafe { + gcc_s().get(sym.as_bytes()).ok().map(|s| *s) } } - -declare!(ashldi3: fn(u64, u32) -> u64); -declare!(ashrdi3: fn(i64, u32) -> i64); -declare!(divdi3: fn(i64, i64) -> i64); -declare!(divmoddi4: fn(i64, i64, &mut i64) -> i64); -declare!(divmodsi4: fn(i32, i32, &mut i32) -> i32); -declare!(divsi3: fn(i32, i32) -> i32); -declare!(lshrdi3: fn(u64, u32) -> u64); -declare!(moddi3: fn(i64, i64) -> i64); -declare!(modsi3: fn(i32, i32) -> i32); -declare!(muldi3: fn(u64, u64) -> u64); -declare!(mulodi4: fn(i64, i64, &mut i32) -> i64); -declare!(mulosi4: fn(i32, i32, &mut i32) -> i32); -declare!(udivdi3: fn(u64, u64) -> u64); -declare!(udivmoddi4: fn(u64, u64, Option<&mut u64>) -> u64); -declare!(udivmodsi4: fn(u32, u32, Option<&mut u32>) -> u32); -declare!(udivsi3: fn(u32, u32) -> u32); -declare!(umoddi3: fn(u64, u64) -> u64); -declare!(umodsi3: fn(u32, u32) -> u32); -declare!(addsf3: fn(f32, f32) -> f32); -declare!(adddf3: fn(f64, f64) -> f64); diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 7c3856a0ab3..1e7a651c96c 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -89,12 +89,12 @@ macro_rules! add { if a_exponent.0 == 0 { let (exponent, significand) = <$ty>::normalize(a_significand.0); a_exponent = Wrapping(exponent); - a_significand = Wrapping(significand); + a_significand = Wrapping(significand); } if b_exponent.0 == 0 { let (exponent, significand) = <$ty>::normalize(b_significand.0); b_exponent = Wrapping(exponent); - b_significand = Wrapping(significand); + b_significand = Wrapping(significand); } // The sign of the result is the sign of the larger operand, a. If they @@ -123,8 +123,8 @@ macro_rules! add { if subtraction { a_significand -= b_significand; // If a == -b, return +zero. - if a_significand.0 == 0 { - return (<$ty as Float>::from_repr(0)); + if a_significand.0 == 0 { + return (<$ty as Float>::from_repr(0)); } // If partial cancellation occured, we need to left-shift the result @@ -148,7 +148,7 @@ macro_rules! add { } // If we have overflowed the type, return +/- infinity: - if a_exponent >= Wrapping(max_exponent.0 as i32) { + if a_exponent >= Wrapping(max_exponent.0 as i32) { return (<$ty>::from_repr((inf_rep | result_sign).0)); } @@ -190,47 +190,46 @@ mod tests { use float::Float; use qc::{U32, U64}; - use gcc_s; - use rand; - // NOTE The tests below have special handing for NaN values. // Because NaN != NaN, the floating-point representations must be used // Because there are many diffferent values of NaN, and the implementation // doesn't care about calculating the 'correct' one, if both values are NaN // the values are considered equivalent. + struct FRepr(F); + + impl PartialEq for FRepr { + fn eq(&self, other: &FRepr) -> bool { + // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't + // match the output of its gcc_s counterpart. Until we investigate further, we'll + // just avoid testing against gcc_s on those targets. Do note that our + // implementation matches the output of the FPU instruction on *hard* float targets + // and matches its gcc_s counterpart on *soft* float targets. + if cfg!(gnueabihf) { + return true + } + self.0.eq_repr(other.0) + } + } + // TODO: Add F32/F64 to qc so that they print the right values (at the very least) - quickcheck! { - fn addsf3(a: U32, b: U32) -> bool { + check! { + fn __addsf3(f: extern fn(f32, f32) -> f32, + a: U32, + b: U32) + -> Option > { let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); - let x = super::__addsf3(a, b); - - match gcc_s::addsf3() { - // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't - // match the output of its gcc_s counterpart. Until we investigate further, we'll - // just avoid testing against gcc_s on those targets. Do note that our - // implementation matches the output of the FPU instruction on *hard* float targets - // and matches its gcc_s counterpart on *soft* float targets. - #[cfg(not(gnueabihf))] - Some(addsf3) if rand::random() => x.eq_repr(unsafe { addsf3(a, b) }), - _ => x.eq_repr(a + b), - } + Some(FRepr(f(a, b))) } - fn adddf3(a: U64, b: U64) -> bool { + fn __adddf3(f: extern fn(f64, f64) -> f64, + a: U64, + b: U64) -> Option > { let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); - let x = super::__adddf3(a, b); - - match gcc_s::adddf3() { - // NOTE(cfg) See NOTE above - #[cfg(not(gnueabihf))] - Some(adddf3) if rand::random() => x.eq_repr(unsafe { adddf3(a, b) }), - _ => x.eq_repr(a + b), - - } + Some(FRepr(f(a, b))) } } - + // More tests for special float values #[test] diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index bd9194bfb79..cee2b739873 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -3,10 +3,10 @@ use core::mem; pub mod add; /// Trait for some basic operations on floats -pub trait Float: Sized { +pub trait Float: Sized + Copy { /// A uint of the same with as the float type Int; - + /// Returns the bitwidth of the float type fn bits() -> u32; @@ -22,7 +22,7 @@ pub trait Float: Sized { /// compared. fn eq_repr(self, rhs: Self) -> bool; - /// Returns a `Self::Int` transmuted back to `Self` + /// Returns a `Self::Int` transmuted back to `Self` fn from_repr(a: Self::Int) -> Self; /// Returns (normalized exponent, normalized significand) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index dea3499d4c5..ea48ca9c070 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -74,60 +74,34 @@ mulo!(__mulodi4: i64); mod tests { use qc::{I32, I64, U64}; - use gcc_s; - use rand; - - quickcheck! { - fn muldi(a: U64, b: U64) -> bool { - let (a, b) = (a.0, b.0); - let r = super::__muldi3(a, b); - - match gcc_s::muldi3() { - Some(muldi3) if rand::random() => r == unsafe { muldi3(a, b) }, - _ => r == a.wrapping_mul(b), - } + check! { + fn __muldi3(f: extern fn(u64, u64) -> u64, a: U64, b: U64) + -> Option { + Some(f(a.0, b.0)) } - fn mulosi(a: I32, b: I32) -> bool { + fn __mulosi4(f: extern fn(i32, i32, &mut i32) -> i32, + a: I32, + b: I32) -> Option<(i32, i32)> { let (a, b) = (a.0, b.0); let mut overflow = 2; - let r = super::__mulosi4(a, b, &mut overflow); + let r = f(a, b, &mut overflow); if overflow != 0 && overflow != 1 { - return false; - } - - match gcc_s::mulosi4() { - Some(mulosi4) if rand::random() => { - let mut gcc_s_overflow = 2; - let gcc_s_r = unsafe { - mulosi4(a, b, &mut gcc_s_overflow) - }; - - (r, overflow) == (gcc_s_r, gcc_s_overflow) - }, - _ => (r, overflow != 0) == a.overflowing_mul(b), + return None } + Some((r, overflow)) } - fn mulodi(a: I64, b: I64) -> bool { + fn __mulodi4(f: extern fn(i64, i64, &mut i32) -> i64, + a: I64, + b: I64) -> Option<(i64, i32)> { let (a, b) = (a.0, b.0); let mut overflow = 2; - let r = super::__mulodi4(a, b, &mut overflow); + let r = f(a, b, &mut overflow); if overflow != 0 && overflow != 1 { - return false; - } - - match gcc_s::mulodi4() { - Some(mulodi4) if rand::random() => { - let mut gcc_s_overflow = 2; - let gcc_s_r = unsafe { - mulodi4(a, b, &mut gcc_s_overflow) - }; - - (r, overflow) == (gcc_s_r, gcc_s_overflow) - }, - _ => (r, overflow != 0) == a.overflowing_mul(b), + return None } + Some((r, overflow)) } } } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index fcb9ed9d9e8..7a8e38e5e6d 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -54,116 +54,70 @@ divmod!(__divmoddi4, __divdi3: i64); mod tests { use qc::{U32, U64}; - use gcc_s; - use quickcheck::TestResult; - use rand; - - quickcheck!{ - fn divdi3(n: U64, d: U64) -> TestResult { + check! { + fn __divdi3(f: extern fn(i64, i64) -> i64, n: U64, d: U64) -> Option { let (n, d) = (n.0 as i64, d.0 as i64); if d == 0 { - TestResult::discard() + None } else { - let q = super::__divdi3(n, d); - - match gcc_s::divdi3() { - Some(divdi3) if rand::random() => { - TestResult::from_bool(q == unsafe { divdi3(n, d) }) - }, - _ => TestResult::from_bool(q == n / d), - } + Some(f(n, d)) } } - fn moddi3(n: U64, d: U64) -> TestResult { + fn __moddi3(f: extern fn(i64, i64) -> i64, n: U64, d: U64) -> Option { let (n, d) = (n.0 as i64, d.0 as i64); if d == 0 { - TestResult::discard() + None } else { - let r = super::__moddi3(n, d); - - match gcc_s::moddi3() { - Some(moddi3) if rand::random() => { - TestResult::from_bool(r == unsafe { moddi3(n, d) }) - }, - _ => TestResult::from_bool(r == n % d), - } + Some(f(n, d)) } } - fn divmoddi4(n: U64, d: U64) -> TestResult { + fn __divmoddi4(f: extern fn(i64, i64, &mut i64) -> i64, + n: U64, + d: U64) -> Option<(i64, i64)> { let (n, d) = (n.0 as i64, d.0 as i64); if d == 0 { - TestResult::discard() + None } else { let mut r = 0; - let q = super::__divmoddi4(n, d, &mut r); - - match gcc_s::divmoddi4() { - Some(divmoddi4) if rand::random() => { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - divmoddi4(n, d, &mut gcc_s_r) - }; - - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - }, - _ => TestResult::from_bool(q == n / d && r == n % d), - } + let q = f(n, d, &mut r); + Some((q, r)) } } - fn divsi3(n: U32, d: U32) -> TestResult { + fn __divsi3(f: extern fn(i32, i32) -> i32, + n: U32, + d: U32) -> Option { let (n, d) = (n.0 as i32, d.0 as i32); if d == 0 { - TestResult::discard() + None } else { - let q = super::__divsi3(n, d); - - match gcc_s::divsi3() { - Some(divsi3) if rand::random() => { - TestResult::from_bool(q == unsafe { divsi3(n, d)}) - }, - _ => TestResult::from_bool(q == n / d), - } + Some(f(n, d)) } } - fn modsi3(n: U32, d: U32) -> TestResult { + fn __modsi3(f: extern fn(i32, i32) -> i32, + n: U32, + d: U32) -> Option { let (n, d) = (n.0 as i32, d.0 as i32); if d == 0 { - TestResult::discard() + None } else { - let r = super::__modsi3(n, d); - - match gcc_s::modsi3() { - Some(modsi3) if rand::random() => { - TestResult::from_bool(r == unsafe { modsi3(n, d) }) - }, - _ => TestResult::from_bool(r == n % d), - } + Some(f(n, d)) } } - fn divmodsi4(n: U32, d: U32) -> TestResult { + fn __divmodsi4(f: extern fn(i32, i32, &mut i32) -> i32, + n: U32, + d: U32) -> Option<(i32, i32)> { let (n, d) = (n.0 as i32, d.0 as i32); if d == 0 { - TestResult::discard() + None } else { let mut r = 0; - let q = super::__divmodsi4(n, d, &mut r); - - match gcc_s::divmodsi4() { - Some(divmodsi4) if rand::random() => { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - divmodsi4(n, d, &mut gcc_s_r) - }; - - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - }, - _ => TestResult::from_bool(q == n / d && r == n % d), - } + let q = f(n, d, &mut r); + Some((q, r)) } } } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index bafc9dbe0ce..4fc23918cbf 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -62,57 +62,32 @@ lshr!(__lshrdi3: u64); mod tests { use qc::{I64, U64}; - use gcc_s; - use quickcheck::TestResult; - use rand; - // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) - quickcheck! { - fn ashldi(a: U64, b: u32) -> TestResult { + check! { + fn __ashldi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option { let a = a.0; if b >= 64 { - TestResult::discard() + None } else { - let r = super::__ashldi3(a, b); - - match gcc_s::ashldi3() { - Some(ashldi3) if rand::random() => { - TestResult::from_bool(r == unsafe { ashldi3(a, b) }) - }, - _ => TestResult::from_bool(r == a << b), - } + Some(f(a, b)) } } - fn ashrdi(a: I64, b: u32) -> TestResult { + fn __ashrdi3(f: extern fn(i64, u32) -> i64, a: I64, b: u32) -> Option { let a = a.0; if b >= 64 { - TestResult::discard() + None } else { - let r = super::__ashrdi3(a, b); - - match gcc_s::ashrdi3() { - Some(ashrdi3) if rand::random() => { - TestResult::from_bool(r == unsafe { ashrdi3(a, b) }) - }, - _ => TestResult::from_bool(r == a >> b), - } + Some(f(a, b)) } } - fn lshrdi(a: U64, b: u32) -> TestResult { + fn __lshrdi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option { let a = a.0; if b >= 64 { - TestResult::discard() + None } else { - let r = super::__lshrdi3(a, b); - - match gcc_s::lshrdi3() { - Some(lshrdi3) if rand::random() => { - TestResult::from_bool(r == unsafe { lshrdi3(a, b) }) - }, - _ => TestResult::from_bool(r == a >> b), - } + Some(f(a, b)) } } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 89793c8a82e..2c2089ab71e 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -230,116 +230,66 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { mod tests { use qc::{U32, U64}; - use gcc_s; - use quickcheck::TestResult; - use rand; - - quickcheck!{ - fn udivdi3(n: U64, d: U64) -> TestResult { + check! { + fn __udivdi3(f: extern fn(u64, u64) -> u64, n: U64, d: U64) -> Option { let (n, d) = (n.0, d.0); if d == 0 { - TestResult::discard() + None } else { - let q = super::__udivdi3(n, d); - - match gcc_s::udivdi3() { - Some(udivdi3) if rand::random() => { - TestResult::from_bool(q == unsafe { udivdi3(n, d) }) - }, - _ => TestResult::from_bool(q == n / d), - } + Some(f(n, d)) } } - fn umoddi3(n: U64, d: U64) -> TestResult { + fn __umoddi3(f: extern fn(u64, u64) -> u64, n: U64, d: U64) -> Option { let (n, d) = (n.0, d.0); if d == 0 { - TestResult::discard() + None } else { - let r = super::__umoddi3(n, d); - - match gcc_s::umoddi3() { - Some(umoddi3) if rand::random() => { - TestResult::from_bool(r == unsafe { umoddi3(n, d) }) - }, - _ => TestResult::from_bool(r == n % d), - } + Some(f(n, d)) } } - fn udivmoddi4(n: U64, d: U64) -> TestResult { + fn __udivmoddi4(f: extern fn(u64, u64, Option<&mut u64>) -> u64, + n: U64, + d: U64) -> Option<(u64, u64)> { let (n, d) = (n.0, d.0); if d == 0 { - TestResult::discard() + None } else { let mut r = 0; - let q = super::__udivmoddi4(n, d, Some(&mut r)); - - match gcc_s::udivmoddi4() { - Some(udivmoddi4) if rand::random() => { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - udivmoddi4(n, d, Some(&mut gcc_s_r)) - }; - - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - }, - _ => TestResult::from_bool(q == n / d && r == n % d), - } + let q = f(n, d, Some(&mut r)); + Some((q, r)) } } - fn udivsi3(n: U32, d: U32) -> TestResult { + fn __udivsi3(f: extern fn(u32, u32) -> u32, n: U32, d: U32) -> Option { let (n, d) = (n.0, d.0); if d == 0 { - TestResult::discard() + None } else { - let q = super::__udivsi3(n, d); - - match gcc_s::udivsi3() { - Some(udivsi3) if rand::random() => { - TestResult::from_bool(q == unsafe { udivsi3(n, d) }) - }, - _ => TestResult::from_bool(q == n / d), - } + Some(f(n, d)) } } - fn umodsi3(n: U32, d: U32) -> TestResult { + fn __umodsi3(f: extern fn(u32, u32) -> u32, n: U32, d: U32) -> Option { let (n, d) = (n.0, d.0); if d == 0 { - TestResult::discard() + None } else { - let r = super::__umodsi3(n, d); - - match gcc_s::umodsi3() { - Some(umodsi3) if rand::random() => { - TestResult::from_bool(r == unsafe { umodsi3(n, d) }) - }, - _ => TestResult::from_bool(r == n % d), - } + Some(f(n, d)) } } - fn udivmodsi4(n: U32, d: U32) -> TestResult { + fn __udivmodsi4(f: extern fn(u32, u32, Option<&mut u32>) -> u32, + n: U32, + d: U32) -> Option<(u32, u32)> { let (n, d) = (n.0, d.0); if d == 0 { - TestResult::discard() + None } else { let mut r = 0; - let q = super::__udivmodsi4(n, d, Some(&mut r)); - - match gcc_s::udivmodsi4() { - Some(udivmodsi4) if rand::random() => { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - udivmodsi4(n, d, Some(&mut gcc_s_r)) - }; - - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - }, - _ => TestResult::from_bool(q == n / d && r == n % d), - } + let q = f(n, d, Some(&mut r)); + Some((q, r)) } } } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 7f2d39180ff..bb51e4050c0 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -20,12 +20,19 @@ extern crate core; #[cfg(test)] extern crate gcc_s; +#[cfg(test)] +extern crate compiler_rt; + #[cfg(test)] extern crate rand; #[cfg(feature = "weak")] extern crate rlibc; +#[cfg(test)] +#[macro_use] +mod qc; + pub mod int; pub mod float; @@ -34,7 +41,3 @@ pub mod arm; #[cfg(target_arch = "x86_64")] pub mod x86_64; - -#[cfg(test)] -mod qc; - diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 8f102c01a44..1450a4ec8b3 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -142,3 +142,124 @@ macro_rules! arbitrary_large { arbitrary_large!(I64: i64); arbitrary_large!(U64: u64); + +// Convenience macro to test intrinsics against their reference implementations. +// +// Each intrinsic is tested against both the `gcc_s` library as well as +// `compiler-rt`. These libraries are defined in the `gcc_s` crate as well as +// the `compiler-rt` crate in this repository. Both load a dynamic library and +// lookup symbols through that dynamic library to ensure that we're using the +// right intrinsic. +// +// This macro hopefully allows you to define a bare minimum of how to test an +// intrinsic without worrying about these implementation details. A sample +// invocation looks like: +// +// +// check! { +// // First argument is the function we're testing (either from this lib +// // or a dynamically loaded one. Further arguments are all generated by +// // quickcheck. +// fn __my_intrinsic(f: extern fn(i32) -> i32, +// a: I32) +// -> Option<(i32, i64)> { +// +// // Discard tests by returning Some +// if a.0 == 0 { +// return None +// } +// +// // Return the result via `Some` if the test can run +// let mut other_result = 0; +// let result = f(a.0, &mut other_result); +// Some((result, other_result)) +// } +// } +// +// If anything returns `None` then the test is discarded, otherwise the two +// results are compared for equality and the test fails if this equality check +// fails. +macro_rules! check { + ($( + fn $name:ident($f:ident: extern fn($($farg:ty),*) -> $fret:ty, + $($arg:ident: $t:ty),*) + -> Option<$ret:ty> + { + $($code:tt)* + } + )*) => ( + $( + fn $name($f: extern fn($($farg),*) -> $fret, + $($arg: $t),*) -> Option<$ret> { + $($code)* + } + )* + + mod _compiler_rt { + use qc::*; + use std::mem; + use quickcheck::TestResult; + + $( + #[test] + fn $name() { + fn my_check($($arg:$t),*) -> TestResult { + let my_answer = super::$name(super::super::$name, + $($arg),*); + let compiler_rt_fn = ::compiler_rt::get(stringify!($name)); + unsafe { + let compiler_rt_answer = + super::$name(mem::transmute(compiler_rt_fn), + $($arg),*); + match (my_answer, compiler_rt_answer) { + (None, _) | (_, None) => TestResult::discard(), + (Some(a), Some(b)) => { + TestResult::from_bool(a == b) + } + } + } + } + + ::quickcheck::quickcheck(my_check as fn($($t),*) -> TestResult) + } + )* + } + + mod _gcc_s { + use qc::*; + use std::mem; + use quickcheck::TestResult; + + $( + #[test] + fn $name() { + fn my_check($($arg:$t),*) -> TestResult { + let my_answer = super::$name(super::super::$name, + $($arg),*); + let gcc_s_fn = ::gcc_s::get(stringify!($name)).unwrap(); + unsafe { + let gcc_s_answer = + super::$name(mem::transmute(gcc_s_fn), + $($arg),*); + match (my_answer, gcc_s_answer) { + (None, _) | (_, None) => TestResult::discard(), + (Some(a), Some(b)) => { + TestResult::from_bool(a == b) + } + } + } + } + + // If it's not in libgcc, or we couldn't find libgcc, then + // just ignore this. We should have tests through + // compiler-rt in any case + if ::gcc_s::get(stringify!($name)).is_none() { + return + } + + ::quickcheck::quickcheck(my_check as fn($($t),*) -> TestResult) + } + )* + } + ) +} diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 8bc33096dfc..e38147aaff8 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -1,3 +1,5 @@ +#![allow(unused_imports)] + use core::intrinsics; // NOTE These functions are implemented using assembly because they using a custom -- cgit 1.4.1-3-g733a5 From df0eb9981eba7484e473696c34fc0e89e43c780a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 29 Sep 2016 06:43:25 -0500 Subject: appveyor: stop gisting the disassembly it's flaky in its current form and Travis is not producing gist either. --- library/compiler-builtins/appveyor.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 0e64977c175..52afc97ef5e 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -8,7 +8,6 @@ install: - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe --default-host %TARGET% --default-toolchain nightly -y - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - - gem install gist - rustc -Vv - cargo -V @@ -20,11 +19,6 @@ test_script: - cargo test - cargo test --release -on_success: - - cmd: | - CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - dumpbin /disasm target/release/librustc_builtins.rlib | gist -d "'%TARGET%/rustc-builtins.rlib' from commit '%APPVEYOR_REPO_COMMIT%' on branch '%APPVEYOR_REPO_branch%'" - branches: only: - auto -- cgit 1.4.1-3-g733a5 From cb9b1f82e32ca15e77f22b7132ab57f31138e935 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 26 Sep 2016 15:55:11 -0500 Subject: add an opt-in cargo feature to build intrinsics from compiler-rt source closes #63 cc #66 --- library/compiler-builtins/Cargo.toml | 6 + library/compiler-builtins/build.rs | 426 ++++++++++++++++++++- library/compiler-builtins/src/arm.rs | 2 + library/compiler-builtins/src/bin/intrinsics.rs | 399 +++++++++++++++++++ library/compiler-builtins/src/float/add.rs | 3 +- library/compiler-builtins/src/int/mul.rs | 2 + library/compiler-builtins/src/int/sdiv.rs | 17 +- library/compiler-builtins/src/int/shift.rs | 5 + library/compiler-builtins/src/int/udiv.rs | 19 +- library/compiler-builtins/src/lib.rs | 3 + library/compiler-builtins/src/x86_64.rs | 1 - library/compiler-builtins/thumbv6m-none-eabi.json | 2 + library/compiler-builtins/thumbv7em-none-eabi.json | 2 + .../compiler-builtins/thumbv7em-none-eabihf.json | 2 + library/compiler-builtins/thumbv7m-none-eabi.json | 2 + 15 files changed, 883 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/src/bin/intrinsics.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6e75a116bbf..93f7d197012 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -4,6 +4,10 @@ build = "build.rs" name = "rustc_builtins" version = "0.1.0" +[build-dependencies] +gcc = "0.3.35" +rustc-cfg = "0.1.2" + [dependencies] [dependencies.rlibc] @@ -17,6 +21,8 @@ gcc_s = { path = "gcc_s" } compiler-rt = { path = "compiler-rt" } [features] +# Build the missing intrinsics from compiler-rt C source code +c = [] weak = ["rlibc/weak"] [workspace] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 3ef6c289554..2333bb1cd00 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,8 +1,430 @@ +extern crate gcc; +extern crate rustc_cfg; + +use std::collections::BTreeMap; use std::env; +use std::path::Path; + +use rustc_cfg::Cfg; + +struct Sources { + // SYMBOL -> PATH TO SOURCE + map: BTreeMap<&'static str, &'static str>, +} + +impl Sources { + fn new() -> Sources { + Sources { map: BTreeMap::new() } + } + + fn extend(&mut self, sources: &[&'static str]) { + // NOTE Some intrinsics have both a generic implementation (e.g. + // `floatdidf.c`) and an arch optimized implementation + // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized + // implementation and discard the generic implementation. If we don't + // and keep both implementations, the linker will yell at us about + // duplicate symbols! + for &src in sources { + let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap(); + if src.contains("/") { + // Arch-optimized implementation (preferred) + self.map.insert(symbol, src); + } else { + // Generic implementation + if !self.map.contains_key(symbol) { + self.map.insert(symbol, src); + } + } + } + } + + fn remove(&mut self, symbols: &[&str]) { + for symbol in symbols { + self.map.remove(*symbol).unwrap(); + } + } +} fn main() { - if env::var("TARGET").unwrap().ends_with("gnueabihf") { + println!("cargo:rerun-if-changed=build.rs"); + + let target = env::var("TARGET").unwrap(); + let Cfg { ref target_arch, ref target_os, ref target_env, ref target_vendor, .. } = + Cfg::new(&target).unwrap(); + // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the + // target triple. This is usually correct for our built-in targets but can break in presence of + // custom targets, which can have arbitrary names. + let llvm_target = target.split('-').collect::>(); + let target_vendor = target_vendor.as_ref().unwrap(); + + // Build missing intrinsics from compiler-rt C source code + if env::var_os("CARGO_FEATURE_C").is_some() { + let cfg = &mut gcc::Config::new(); + + if target_env == "msvc" { + // Don't pull in extra libraries on MSVC + cfg.flag("/Zl"); + + // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP + cfg.define("__func__", Some("__FUNCTION__")); + } else { + // Turn off various features of gcc and such, mostly copying + // compiler-rt's build system already + cfg.flag("-fno-builtin"); + cfg.flag("-fvisibility=hidden"); + cfg.flag("-fomit-frame-pointer"); + cfg.flag("-ffreestanding"); + } + + // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to + // target to make sure that the assembly implementations really work for the target. If the + // implementation is not valid for the arch, then gcc will error when compiling it. + if llvm_target[0].starts_with("thumb") { + cfg.flag("-mthumb"); + + if llvm_target.last() == Some(&"eabihf") { + cfg.flag("-mfloat-abi=hard"); + } + } + + if llvm_target[0] == "thumbv6m" { + cfg.flag("-march=armv6-m"); + } + + if llvm_target[0] == "thumbv7m" { + cfg.flag("-march=armv7-m"); + } + + if llvm_target[0] == "thumbv7em" { + cfg.flag("-march=armv7e-m"); + } + + let mut sources = Sources::new(); + sources.extend(&["absvdi2.c", + "absvsi2.c", + "addvdi3.c", + "addvsi3.c", + "apple_versioning.c", + "clear_cache.c", + "clzdi2.c", + "clzsi2.c", + "cmpdi2.c", + "comparedf2.c", + "comparesf2.c", + "ctzdi2.c", + "ctzsi2.c", + "divdc3.c", + "divdf3.c", + "divsc3.c", + "divsf3.c", + "divxc3.c", + "extendsfdf2.c", + "extendhfsf2.c", + "ffsdi2.c", + "fixdfdi.c", + "fixdfsi.c", + "fixsfdi.c", + "fixsfsi.c", + "fixunsdfdi.c", + "fixunsdfsi.c", + "fixunssfdi.c", + "fixunssfsi.c", + "fixunsxfdi.c", + "fixunsxfsi.c", + "fixxfdi.c", + "floatdidf.c", + "floatdisf.c", + "floatdixf.c", + "floatsidf.c", + "floatsisf.c", + "floatundidf.c", + "floatundisf.c", + "floatundixf.c", + "floatunsidf.c", + "floatunsisf.c", + "int_util.c", + "muldc3.c", + "muldf3.c", + "muloti4.c", + "mulsc3.c", + "mulsf3.c", + "mulvdi3.c", + "mulvsi3.c", + "mulxc3.c", + "negdf2.c", + "negdi2.c", + "negsf2.c", + "negvdi2.c", + "negvsi2.c", + "paritydi2.c", + "paritysi2.c", + "popcountdi2.c", + "popcountsi2.c", + "powidf2.c", + "powisf2.c", + "powixf2.c", + "subdf3.c", + "subsf3.c", + "subvdi3.c", + "subvsi3.c", + "truncdfhf2.c", + "truncdfsf2.c", + "truncsfhf2.c", + "ucmpdi2.c"]); + + if target_os != "ios" { + sources.extend(&["absvti2.c", + "addtf3.c", + "addvti3.c", + "ashlti3.c", + "ashrti3.c", + "clzti2.c", + "cmpti2.c", + "ctzti2.c", + "divtf3.c", + "divti3.c", + "ffsti2.c", + "fixdfti.c", + "fixsfti.c", + "fixunsdfti.c", + "fixunssfti.c", + "fixunsxfti.c", + "fixxfti.c", + "floattidf.c", + "floattisf.c", + "floattixf.c", + "floatuntidf.c", + "floatuntisf.c", + "floatuntixf.c", + "lshrti3.c", + "modti3.c", + "multf3.c", + "multi3.c", + "mulvti3.c", + "negti2.c", + "negvti2.c", + "parityti2.c", + "popcountti2.c", + "powitf2.c", + "subtf3.c", + "subvti3.c", + "trampoline_setup.c", + "ucmpti2.c", + "udivmodti4.c", + "udivti3.c", + "umodti3.c"]); + } + + if target_vendor == "apple" { + sources.extend(&["atomic_flag_clear.c", + "atomic_flag_clear_explicit.c", + "atomic_flag_test_and_set.c", + "atomic_flag_test_and_set_explicit.c", + "atomic_signal_fence.c", + "atomic_thread_fence.c"]); + } + + if target_os != "windows" && target_os != "none" { + sources.extend(&["emutls.c"]); + } + + if target_env == "msvc" { + if target_arch == "x86_64" { + sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); + } + } else { + if target_os != "freebsd" { + sources.extend(&["gcc_personality_v0.c"]); + } + + if target_arch == "x86_64" { + sources.extend(&["x86_64/chkstk.S", + "x86_64/chkstk2.S", + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S"]); + } + + if target_arch == "x86" { + sources.extend(&["i386/ashldi3.S", + "i386/ashrdi3.S", + "i386/chkstk.S", + "i386/chkstk2.S", + "i386/divdi3.S", + "i386/floatdidf.S", + "i386/floatdisf.S", + "i386/floatdixf.S", + "i386/floatundidf.S", + "i386/floatundisf.S", + "i386/floatundixf.S", + "i386/lshrdi3.S", + "i386/moddi3.S", + "i386/muldi3.S", + "i386/udivdi3.S", + "i386/umoddi3.S"]); + } + } + + if target_arch == "arm" && target_os != "ios" { + sources.extend(&["arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + "arm/aeabi_dcmp.S", + "arm/aeabi_div0.c", + "arm/aeabi_drsub.c", + "arm/aeabi_fcmp.S", + "arm/aeabi_frsub.c", + "arm/bswapdi2.S", + "arm/bswapsi2.S", + "arm/clzdi2.S", + "arm/clzsi2.S", + "arm/comparesf2.S", + "arm/divmodsi4.S", + "arm/divsi3.S", + "arm/modsi3.S", + "arm/switch16.S", + "arm/switch32.S", + "arm/switch8.S", + "arm/switchu8.S", + "arm/sync_synchronize.S", + "arm/udivmodsi4.S", + "arm/udivsi3.S", + "arm/umodsi3.S"]); + } + + if llvm_target[0] == "armv7" { + sources.extend(&["arm/sync_fetch_and_add_4.S", + "arm/sync_fetch_and_add_8.S", + "arm/sync_fetch_and_and_4.S", + "arm/sync_fetch_and_and_8.S", + "arm/sync_fetch_and_max_4.S", + "arm/sync_fetch_and_max_8.S", + "arm/sync_fetch_and_min_4.S", + "arm/sync_fetch_and_min_8.S", + "arm/sync_fetch_and_nand_4.S", + "arm/sync_fetch_and_nand_8.S", + "arm/sync_fetch_and_or_4.S", + "arm/sync_fetch_and_or_8.S", + "arm/sync_fetch_and_sub_4.S", + "arm/sync_fetch_and_sub_8.S", + "arm/sync_fetch_and_umax_4.S", + "arm/sync_fetch_and_umax_8.S", + "arm/sync_fetch_and_umin_4.S", + "arm/sync_fetch_and_umin_8.S", + "arm/sync_fetch_and_xor_4.S", + "arm/sync_fetch_and_xor_8.S"]); + } + + if llvm_target.last().unwrap().ends_with("eabihf") { + if !llvm_target[0].starts_with("thumbv7em") { + sources.extend(&["arm/adddf3vfp.S", + "arm/addsf3vfp.S", + "arm/divdf3vfp.S", + "arm/divsf3vfp.S", + "arm/eqdf2vfp.S", + "arm/eqsf2vfp.S", + "arm/extendsfdf2vfp.S", + "arm/fixdfsivfp.S", + "arm/fixsfsivfp.S", + "arm/fixunsdfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsidfvfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssidfvfp.S", + "arm/floatunssisfvfp.S", + "arm/gedf2vfp.S", + "arm/gesf2vfp.S", + "arm/gtdf2vfp.S", + "arm/gtsf2vfp.S", + "arm/ledf2vfp.S", + "arm/lesf2vfp.S", + "arm/ltdf2vfp.S", + "arm/ltsf2vfp.S", + "arm/muldf3vfp.S", + "arm/mulsf3vfp.S", + "arm/nedf2vfp.S", + "arm/nesf2vfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/subdf3vfp.S", + "arm/subsf3vfp.S"]); + } + + sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); + + } + + if target_arch == "aarch64" { + sources.extend(&["comparetf2.c", + "extenddftf2.c", + "extendsftf2.c", + "fixtfdi.c", + "fixtfsi.c", + "fixtfti.c", + "fixunstfdi.c", + "fixunstfsi.c", + "fixunstfti.c", + "floatditf.c", + "floatsitf.c", + "floatunditf.c", + "floatunsitf.c", + "multc3.c", + "trunctfdf2.c", + "trunctfsf2.c"]); + } + + // Remove the assembly implementations that won't compile for the target + if llvm_target[0] == "thumbv6m" { + sources.remove(&["aeabi_cdcmp", + "aeabi_cfcmp", + "aeabi_dcmp", + "aeabi_fcmp", + "clzdi2", + "clzsi2", + "comparesf2", + "divmodsi4", + "divsi3", + "modsi3", + "switch16", + "switch32", + "switch8", + "switchu8", + "udivmodsi4", + "udivsi3", + "umodsi3"]); + + // But use some generic implementations where possible + sources.extend(&["clzdi2.c", "clzsi2.c"]) + } + + if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { + sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); + } + + for src in sources.map.values() { + cfg.file(Path::new("compiler-rt/lib/builtins").join(src)); + } + + cfg.compile("libcompiler-rt.a"); + } + + // To filter away some flaky test (see src/float/add.rs for details) + if llvm_target.last() == Some(&"gnueabihf") { println!("cargo:rustc-cfg=gnueabihf") } - println!("cargo:rerun-if-changed=build.rs"); + + // To compile intrinsics.rs for thumb targets, where there is no libc + if llvm_target[0].starts_with("thumb") { + println!("cargo:rustc-cfg=thumb") + } + + // compiler-rt `cfg`s away some intrinsics for thumbv6m because that target doesn't have full + // THUMBv2 support. We have to cfg our code accordingly. + if llvm_target[0] == "thumbv6m" { + println!("cargo:rustc-cfg=thumbv6m") + } } diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 4fe243c68d2..b74458f11a2 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -68,6 +68,7 @@ pub extern "C" fn __aeabi_fadd(a: f32, b: f32) -> f32 { ::float::add::__addsf3(a, b) } +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 { ::int::sdiv::__divsi3(a, b) @@ -93,6 +94,7 @@ pub extern "C" fn __aeabi_lmul(a: u64, b: u64) -> u64 { ::int::mul::__muldi3(a, b) } +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { ::int::udiv::__udivsi3(a, b) diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs new file mode 100644 index 00000000000..5e234855cf1 --- /dev/null +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -0,0 +1,399 @@ +// By compiling this file we check that all the intrinsics we care about continue to be provided by +// the `rustc_builtins` crate regardless of the changes we make to it. If we, by mistake, stop +// compiling a C implementation and forget to implement that intrinsic in Rust, this file will fail +// to link due to the missing intrinsic (symbol). + +#![allow(unused_features)] +#![deny(dead_code)] +#![feature(core_float)] +#![feature(lang_items)] +#![feature(libc)] +#![feature(start)] +#![no_std] +#![cfg_attr(thumb, no_main)] + +#[cfg(not(thumb))] +extern crate libc; +extern crate rustc_builtins; + +// NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even +// compiler-rt provides a C/assembly implementation. + +// Every function in this module maps will be lowered to an intrinsic by LLVM, if the platform +// doesn't have native support for the operation used in the function. ARM has a naming convention +// convention for its intrinsics that's different from other architectures; that's why some function +// have an additional comment: the function name is the ARM name for the intrinsic and the comment +// in the non-ARM name for the intrinsic. +#[cfg(feature = "c")] +mod intrinsics { + use core::num::Float; + + // trunccdfsf2 + pub fn aeabi_d2f(x: f64) -> f32 { + x as f32 + } + + // fixdfsi + pub fn aeabi_d2i(x: f64) -> i32 { + x as i32 + } + + // fixdfdi + #[cfg(not(thumbv6m))] + pub fn aeabi_d2l(x: f64) -> i64 { + x as i64 + } + + #[cfg(thumbv6m)] + pub fn aeabi_d2l(_: f64) -> i64 { + 0 + } + + // fixunsdfsi + pub fn aeabi_d2uiz(x: f64) -> u32 { + x as u32 + } + + // fixunsdfdi + #[cfg(not(thumbv6m))] + pub fn aeabi_d2ulz(x: f64) -> u64 { + x as u64 + } + + #[cfg(thumbv6m)] + pub fn aeabi_d2ulz(_: f64) -> u64 { + 0 + } + + // adddf3 + pub fn aeabi_dadd(a: f64, b: f64) -> f64 { + a + b + } + + // eqdf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_dcmpeq(a: f64, b: f64) -> bool { + a == b + } + + #[cfg(thumbv6m)] + pub fn aeabi_dcmpeq(_: f64, _: f64) -> bool { + true + } + + // gtdf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_dcmpgt(a: f64, b: f64) -> bool { + a > b + } + + #[cfg(thumbv6m)] + pub fn aeabi_dcmpgt(_: f64, _: f64) -> bool { + true + } + + // ltdf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_dcmplt(a: f64, b: f64) -> bool { + a < b + } + + #[cfg(thumbv6m)] + pub fn aeabi_dcmplt(_: f64, _: f64) -> bool { + true + } + + // divdf3 + pub fn aeabi_ddiv(a: f64, b: f64) -> f64 { + a / b + } + + // muldf3 + pub fn aeabi_dmul(a: f64, b: f64) -> f64 { + a * b + } + + // subdf3 + pub fn aeabi_dsub(a: f64, b: f64) -> f64 { + a - b + } + + // extendsfdf2 + pub fn aeabi_f2d(x: f32) -> f64 { + x as f64 + } + + // fixsfsi + pub fn aeabi_f2iz(x: f32) -> i32 { + x as i32 + } + + // fixsfdi + #[cfg(not(thumbv6m))] + pub fn aeabi_f2lz(x: f32) -> i64 { + x as i64 + } + + #[cfg(thumbv6m)] + pub fn aeabi_f2lz(_: f32) -> i64 { + 0 + } + + // fixunssfsi + pub fn aeabi_f2uiz(x: f32) -> u32 { + x as u32 + } + + // fixunssfdi + #[cfg(not(thumbv6m))] + pub fn aeabi_f2ulz(x: f32) -> u64 { + x as u64 + } + + #[cfg(thumbv6m)] + pub fn aeabi_f2ulz(_: f32) -> u64 { + 0 + } + + // addsf3 + pub fn aeabi_fadd(a: f32, b: f32) -> f32 { + a + b + } + + // eqsf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_fcmpeq(a: f32, b: f32) -> bool { + a == b + } + + #[cfg(thumbv6m)] + pub fn aeabi_fcmpeq(_: f32, _: f32) -> bool { + true + } + + // gtsf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_fcmpgt(a: f32, b: f32) -> bool { + a > b + } + + #[cfg(thumbv6m)] + pub fn aeabi_fcmpgt(_: f32, _: f32) -> bool { + true + } + + // ltsf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_fcmplt(a: f32, b: f32) -> bool { + a < b + } + + #[cfg(thumbv6m)] + pub fn aeabi_fcmplt(_: f32, _: f32) -> bool { + true + } + + // divsf3 + pub fn aeabi_fdiv(a: f32, b: f32) -> f32 { + a / b + } + + // mulsf3 + pub fn aeabi_fmul(a: f32, b: f32) -> f32 { + a * b + } + + // subsf3 + pub fn aeabi_fsub(a: f32, b: f32) -> f32 { + a - b + } + + // floatsidf + pub fn aeabi_i2d(x: i32) -> f64 { + x as f64 + } + + // floatsisf + pub fn aeabi_i2f(x: i32) -> f32 { + x as f32 + } + + pub fn aeabi_idiv(a: i32, b: i32) -> i32 { + a.wrapping_div(b) + } + + pub fn aeabi_idivmod(a: i32, b: i32) -> i32 { + a % b + } + + // floatdidf + pub fn aeabi_l2d(x: i64) -> f64 { + x as f64 + } + + // floatdisf + pub fn aeabi_l2f(x: i64) -> f32 { + x as f32 + } + + // divdi3 + pub fn aeabi_ldivmod(a: i64, b: i64) -> i64 { + a / b + } + + // muldi3 + pub fn aeabi_lmul(a: i64, b: i64) -> i64 { + a.wrapping_mul(b) + } + + // floatunsidf + pub fn aeabi_ui2d(x: u32) -> f64 { + x as f64 + } + + // floatunsisf + pub fn aeabi_ui2f(x: u32) -> f32 { + x as f32 + } + + pub fn aeabi_uidiv(a: u32, b: u32) -> u32 { + a / b + } + + pub fn aeabi_uidivmod(a: u32, b: u32) -> u32 { + a % b + } + + // floatundidf + pub fn aeabi_ul2d(x: u64) -> f64 { + x as f64 + } + + // floatundisf + pub fn aeabi_ul2f(x: u64) -> f32 { + x as f32 + } + + // udivdi3 + pub fn aeabi_uldivmod(a: u64, b: u64) -> u64 { + a * b + } + + pub fn moddi3(a: i64, b: i64) -> i64 { + a % b + } + + pub fn mulodi4(a: i64, b: i64) -> i64 { + a * b + } + + pub fn powidf2(a: f64, b: i32) -> f64 { + a.powi(b) + } + + pub fn powisf2(a: f32, b: i32) -> f32 { + a.powi(b) + } + + pub fn umoddi3(a: u64, b: u64) -> u64 { + a % b + } +} + +#[cfg(feature = "c")] +fn run() { + use intrinsics::*; + + aeabi_d2f(2.); + aeabi_d2i(2.); + aeabi_d2l(2.); + aeabi_d2uiz(2.); + aeabi_d2ulz(2.); + aeabi_dadd(2., 3.); + aeabi_dcmpeq(2., 3.); + aeabi_dcmpgt(2., 3.); + aeabi_dcmplt(2., 3.); + aeabi_ddiv(2., 3.); + aeabi_dmul(2., 3.); + aeabi_dsub(2., 3.); + aeabi_f2d(2.); + aeabi_f2iz(2.); + aeabi_f2lz(2.); + aeabi_f2uiz(2.); + aeabi_f2ulz(2.); + aeabi_fadd(2., 3.); + aeabi_fcmpeq(2., 3.); + aeabi_fcmpgt(2., 3.); + aeabi_fcmplt(2., 3.); + aeabi_fdiv(2., 3.); + aeabi_fmul(2., 3.); + aeabi_fsub(2., 3.); + aeabi_i2d(2); + aeabi_i2f(2); + aeabi_idiv(2, 3); + aeabi_idivmod(2, 3); + aeabi_l2d(2); + aeabi_l2f(2); + aeabi_ldivmod(2, 3); + aeabi_lmul(2, 3); + aeabi_ui2d(2); + aeabi_ui2f(2); + aeabi_uidiv(2, 3); + aeabi_uidivmod(2, 3); + aeabi_ul2d(2); + aeabi_ul2f(2); + aeabi_uldivmod(2, 3); + moddi3(2, 3); + mulodi4(2, 3); + powidf2(2., 3); + powisf2(2., 3); + umoddi3(2, 3); +} + +#[cfg(all(feature = "c", not(thumb)))] +#[start] +fn main(_: isize, _: *const *const u8) -> isize { + run(); + + 0 +} + +#[cfg(all(not(feature = "c"), not(thumb)))] +#[start] +fn main(_: isize, _: *const *const u8) -> isize { + 0 +} + +#[cfg(all(feature = "c", thumb))] +#[no_mangle] +pub fn _start() -> ! { + run(); + loop {} +} + +#[cfg(all(not(feature = "c"), thumb))] +#[no_mangle] +pub fn _start() -> ! { + loop {} +} + +// ARM targets need these symbols +#[no_mangle] +pub fn __aeabi_unwind_cpp_pr0() {} + +#[no_mangle] +pub fn __aeabi_unwind_cpp_pr1() {} + +// Avoid "undefined reference to `_Unwind_Resume`" errors +#[allow(non_snake_case)] +#[no_mangle] +pub fn _Unwind_Resume() {} + +// Lang items +#[cfg(not(test))] +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[cfg(not(test))] +#[lang = "panic_fmt"] +extern "C" fn panic_fmt() {} diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 1e7a651c96c..7707850217c 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -286,8 +286,7 @@ mod tests { #[test] fn test_double_different_nan() { let a = f64::from_repr(1); - let b = f64::from_repr( - 0b1111111111110010001000100101010101001000101010000110100011101011); + let b = f64::from_repr(0b1111111111110010001000100101010101001000101010000110100011101011); let x = super::__adddf3(a, b); let y = a + b; assert!(x.eq_repr(y)); diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index ea48ca9c070..e04e86ccb80 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -66,7 +66,9 @@ macro_rules! mulo { } } +#[cfg(not(all(feature = "c", target_arch = "x86")))] mul!(__muldi3: u64); + mulo!(__mulosi4: i32); mulo!(__mulodi4: i64); diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 7a8e38e5e6d..37f5dd7df62 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -36,18 +36,33 @@ macro_rules! divmod { /// Returns `a / b` and sets `*rem = n % d` #[cfg_attr(not(test), no_mangle)] pub extern "C" fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty { - let r = $div(a, b); + #[cfg(all(feature = "c", any(target_arch = "x86")))] + extern { + fn $div(a: $ty, b: $ty) -> $ty; + } + + let r = unsafe { $div(a, b) }; *rem = a - (r * b); r } } } +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] div!(__divsi3: i32, u32); + +#[cfg(not(all(feature = "c", target_arch = "x86")))] div!(__divdi3: i64, u64); + +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] mod_!(__modsi3: i32, u32); + +#[cfg(not(all(feature = "c", target_arch = "x86")))] mod_!(__moddi3: i64, u64); + +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] divmod!(__divmodsi4, __divsi3: i32); + divmod!(__divmoddi4, __divdi3: i64); #[cfg(test)] diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 4fc23918cbf..995f8d60925 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -54,8 +54,13 @@ macro_rules! lshr { } } +#[cfg(not(all(feature = "c", target_arch = "x86")))] ashl!(__ashldi3: u64); + +#[cfg(not(all(feature = "c", target_arch = "x86")))] ashr!(__ashrdi3: i64); + +#[cfg(not(all(feature = "c", target_arch = "x86")))] lshr!(__lshrdi3: u64); #[cfg(test)] diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 2c2089ab71e..3de18b4a0ca 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -2,6 +2,7 @@ use core::mem; use int::{Int, LargeInt}; /// Returns `n / d` +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { // Special cases @@ -52,15 +53,27 @@ pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { } /// Returns `n % d` +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { - n - __udivsi3(n, d) * d + #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] + extern "C" { + fn __udivsi3(n: u32, d: u32) -> u32; + } + + n - unsafe { __udivsi3(n, d) * d } } /// Returns `n / d` and sets `*rem = n % d` +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { - let q = __udivsi3(n, d); + #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] + extern "C" { + fn __udivsi3(n: u32, d: u32) -> u32; + } + + let q = unsafe { __udivsi3(n, d) }; if let Some(rem) = rem { *rem = n - (q * d); } @@ -69,11 +82,13 @@ pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { /// Returns `n / d` #[cfg_attr(not(test), no_mangle)] +#[cfg(not(all(feature = "c", target_arch = "x86")))] pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { __udivmoddi4(n, d, None) } /// Returns `n % d` +#[cfg(not(all(feature = "c", target_arch = "x86")))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 { let mut rem = unsafe { mem::uninitialized() }; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index bb51e4050c0..acc56c98a69 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -10,6 +10,9 @@ // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. +// NOTE cfg(all(feature = "c", ..)) indicate that compiler-rt provides an arch optimized +// implementation of that intrinsic and we'll prefer to use that + #[cfg(test)] #[macro_use] extern crate quickcheck; diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index e38147aaff8..072f964dd70 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -67,4 +67,3 @@ pub unsafe fn ___chkstk() { ret"); intrinsics::unreachable(); } - diff --git a/library/compiler-builtins/thumbv6m-none-eabi.json b/library/compiler-builtins/thumbv6m-none-eabi.json index 9c92d4e3333..4b409cff049 100644 --- a/library/compiler-builtins/thumbv6m-none-eabi.json +++ b/library/compiler-builtins/thumbv6m-none-eabi.json @@ -1,10 +1,12 @@ { "arch": "arm", "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "executables": true, "features": "+strict-align", "llvm-target": "thumbv6m-none-eabi", "max-atomic-width": 0, "os": "none", + "pre-link-args": ["-nostartfiles"], "target-endian": "little", "target-pointer-width": "32" } diff --git a/library/compiler-builtins/thumbv7em-none-eabi.json b/library/compiler-builtins/thumbv7em-none-eabi.json index ce49c83ffda..2ac47c8f829 100644 --- a/library/compiler-builtins/thumbv7em-none-eabi.json +++ b/library/compiler-builtins/thumbv7em-none-eabi.json @@ -1,8 +1,10 @@ { "arch": "arm", "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "executables": true, "llvm-target": "thumbv7em-none-eabi", "os": "none", + "pre-link-args": ["-nostartfiles"], "target-endian": "little", "target-pointer-width": "32" } diff --git a/library/compiler-builtins/thumbv7em-none-eabihf.json b/library/compiler-builtins/thumbv7em-none-eabihf.json index bb0b87eb41f..55ed3fd885d 100644 --- a/library/compiler-builtins/thumbv7em-none-eabihf.json +++ b/library/compiler-builtins/thumbv7em-none-eabihf.json @@ -1,9 +1,11 @@ { "arch": "arm", "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "executables": true, "features": "+vfp4", "llvm-target": "thumbv7em-none-eabihf", "os": "none", + "pre-link-args": ["-nostartfiles"], "target-endian": "little", "target-pointer-width": "32" } diff --git a/library/compiler-builtins/thumbv7m-none-eabi.json b/library/compiler-builtins/thumbv7m-none-eabi.json index 313a5e66f71..9635efa8d78 100644 --- a/library/compiler-builtins/thumbv7m-none-eabi.json +++ b/library/compiler-builtins/thumbv7m-none-eabi.json @@ -1,8 +1,10 @@ { "arch": "arm", "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "executables": true, "llvm-target": "thumbv7m-none-eabi", "os": "none", + "pre-link-args": ["-nostartfiles"], "target-endian": "little", "target-pointer-width": "32" } -- cgit 1.4.1-3-g733a5 From a57a63fe08fcea954284f11981f38f0bfd553ad9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 29 Sep 2016 18:50:04 -0500 Subject: adapt to new testing infrastructure --- library/compiler-builtins/.travis.yml | 18 +++---- library/compiler-builtins/build.rs | 2 +- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 8 +++ .../ci/docker/thumbv7em-none-eabi/Dockerfile | 8 +++ .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 8 +++ .../ci/docker/thumbv7m-none-eabi/Dockerfile | 8 +++ library/compiler-builtins/ci/run-docker.sh | 10 ++-- library/compiler-builtins/ci/run.sh | 63 ++++++++++++++++++++++ 8 files changed, 105 insertions(+), 20 deletions(-) create mode 100644 library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/ci/run.sh diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 47252a41794..5b84ae5fd6f 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -3,7 +3,6 @@ language: rust services: docker sudo: required rust: nightly -cache: cargo matrix: include: @@ -25,18 +24,11 @@ matrix: - env: TARGET=mipsel-unknown-linux-gnu - env: TARGET=powerpc-unknown-linux-gnu - env: TARGET=powerpc64-unknown-linux-gnu - # QEMU crashes even when executing the simplest cross compiled C program: - # `int main() { return 0; }` - - env: TARGET=powerpc64le-unknown-linux-gnu NO_RUN=1 + - env: TARGET=powerpc64le-unknown-linux-gnu - env: TARGET=thumbv6m-none-eabi - install: cargo install xargo --debug -f - script: $HOME/.cargo/bin/xargo build --target $TARGET - env: TARGET=thumbv7em-none-eabi - install: cargo install xargo --debug -f - script: $HOME/.cargo/bin/xargo build --target $TARGET - env: TARGET=thumbv7em-none-eabihf - install: cargo install xargo --debug -f - script: $HOME/.cargo/bin/xargo build --target $TARGET + - env: TARGET=thumbv7m-none-eabi - env: TARGET=x86_64-apple-darwin os: osx env: TARGET=x86_64-unknown-linux-gnu @@ -45,8 +37,10 @@ before_install: - test "$TRAVIS_OS_NAME" = "osx" || docker run --rm --privileged multiarch/qemu-user-static:register install: - - curl https://static.rust-lang.org/rustup.sh | - sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot` + - if case $TARGET in thumb*) false;; *) true;; esac; then + curl https://static.rust-lang.org/rustup.sh | + sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot`; + fi script: - cargo generate-lockfile diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2333bb1cd00..f58ea5bb64f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -406,7 +406,7 @@ fn main() { } for src in sources.map.values() { - cfg.file(Path::new("compiler-rt/lib/builtins").join(src)); + cfg.file(Path::new("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins").join(src)); } cfg.compile("libcompiler-rt.a"); diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile new file mode 100644 index 00000000000..c6f7209f3a3 --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \ + CC_thumbv6m_none_eabi=arm-none-eabi-gcc \ + PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile new file mode 100644 index 00000000000..016097b2eab --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ + CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ + PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile new file mode 100644 index 00000000000..c7188ef5886 --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ + CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ + PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile new file mode 100644 index 00000000000..542cc920187 --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ + CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ + PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 8ef024e8222..69127148546 100644 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -5,19 +5,15 @@ set -ex run() { echo $1 - CMD="cargo test --target $1" - if [ "$NO_RUN" = "1" ]; then - CMD="$CMD --no-run" - fi - docker build -t libc ci/docker/$1 + docker build -t $1 ci/docker/$1 docker run \ -v `rustc --print sysroot`:/rust:ro \ -v `pwd`:/checkout:ro \ -e CARGO_TARGET_DIR=/tmp/target \ -w /checkout \ --privileged \ - -it libc \ - bash -c "$CMD && $CMD --release" + -it $1 \ + sh ci/run.sh $1 } if [ -z "$1" ]; then diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh new file mode 100644 index 00000000000..866ddc20e17 --- /dev/null +++ b/library/compiler-builtins/ci/run.sh @@ -0,0 +1,63 @@ +# Test our implementation +case $1 in + thumb*) + curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ + bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 + xargo build --target $1 + xargo build --target $1 --release + ;; + # QEMU crashes even when executing the simplest cross compiled C program: + # `int main() { return 0; }` + powerpc64le-unknown-linux-gnu) + cargo test --target $1 --no-run + cargo test --target $1 --no-run --release + ;; + *) + cargo test --target $1 + cargo test --target $1 --release + ;; +esac + +# Verify that we haven't drop any intrinsic/symbol +case $1 in + thumb*) + xargo build --features c --target $1 --bin intrinsics + ;; + *) + cargo build --features c --target $1 --bin intrinsics + ;; +esac + +# Look out for duplicated symbols when we include the compiler-rt (C) implementation +PREFIX=$(echo $1 | sed -e 's/unknown-//') +case $1 in + armv7-*) + PREFIX=arm-linux-gnueabihf- + ;; + thumb*) + PREFIX=arm-none-eabi- + ;; + *-unknown-linux-gnu | *-apple-darwin) + PREFIX= + ;; +esac + +case $TRAVIS_OS_NAME in + osx) + NM=gnm + + # NOTE OSx's nm doesn't accept the `--defined-only` or provide an equivalent. + # Use GNU nm instead + brew install binutils + ;; + *) + NM=nm + ;; +esac + +$PREFIX$NM -g --defined-only /tmp/target/${1}/debug/librustc_builtins.rlib | \ + sort | uniq -d | grep 'T __' + +if test $? = 0; then + exit 1 +fi -- cgit 1.4.1-3-g733a5 From 148ac030d482f57b4362f54ea01952cd4039008d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 29 Sep 2016 19:20:34 -0500 Subject: ignore duplicated get_pc_thunk symbols --- library/compiler-builtins/ci/run.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 866ddc20e17..237c5058280 100644 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -55,8 +55,9 @@ case $TRAVIS_OS_NAME in ;; esac +# NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it $PREFIX$NM -g --defined-only /tmp/target/${1}/debug/librustc_builtins.rlib | \ - sort | uniq -d | grep 'T __' + sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' if test $? = 0; then exit 1 -- cgit 1.4.1-3-g733a5 From 9a9f025347c1a36cc448edae964530ff900198e1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 29 Sep 2016 19:45:59 -0500 Subject: build.rs: print rerun-if-change for all the C/asm sources --- library/compiler-builtins/build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index f58ea5bb64f..a05a1a590ad 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -406,7 +406,9 @@ fn main() { } for src in sources.map.values() { - cfg.file(Path::new("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins").join(src)); + let src = Path::new("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins").join(src); + cfg.file(&src); + println!("cargo:rerun-if-changed={}", src.display()); } cfg.compile("libcompiler-rt.a"); -- cgit 1.4.1-3-g733a5 From eeaaebc9ac12dbbaaec36828be3ce38b625530c5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 29 Sep 2016 19:47:44 -0500 Subject: only x86-ish targets can use an unprefixed nm --- library/compiler-builtins/ci/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 237c5058280..c0406e33f23 100644 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -37,7 +37,7 @@ case $1 in thumb*) PREFIX=arm-none-eabi- ;; - *-unknown-linux-gnu | *-apple-darwin) + *86*-*) PREFIX= ;; esac -- cgit 1.4.1-3-g733a5 From fde45da3327835212a51fe38c3de2a45a1db1e1b Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Thu, 29 Sep 2016 20:48:20 -0500 Subject: Add floating point deconstruction helpers --- library/compiler-builtins/src/float/add.rs | 2 +- library/compiler-builtins/src/float/mod.rs | 38 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 7707850217c..a462168b950 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -14,7 +14,7 @@ macro_rules! add { let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); - let exponent_bits = bits - significand_bits - one; + let exponent_bits = Wrapping(<$ty>::exponent_bits() as <$ty as Float>::Int); let max_exponent = (one << exponent_bits.0 as usize) - one; let implicit_bit = one << significand_bits.0 as usize; diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index cee2b739873..a44faade8e1 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -10,6 +10,9 @@ pub trait Float: Sized + Copy { /// Returns the bitwidth of the float type fn bits() -> u32; + /// Returns the bitwidth of the exponent + fn exponent_bits() -> u32; + /// Returns the bitwidth of the significand fn significand_bits() -> u32; @@ -25,6 +28,15 @@ pub trait Float: Sized + Copy { /// Returns a `Self::Int` transmuted back to `Self` fn from_repr(a: Self::Int) -> Self; + /// Returns the sign bit of `self` + fn sign(self) -> bool; + + /// Returns the exponent portion of `self`, shifted to the right + fn exponent(self) -> Self::Int; + + /// Returns the significand portion of `self` + fn significand(self) -> Self::Int; + /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); } @@ -34,6 +46,9 @@ impl Float for f32 { fn bits() -> u32 { 32 } + fn exponent_bits() -> u32 { + 8 + } fn significand_bits() -> u32 { 23 } @@ -51,6 +66,16 @@ impl Float for f32 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } + fn sign(self) -> bool { + (self.repr() & 1 << Self::bits()) != 0 + } + fn exponent(self) -> Self::Int { + self.repr() >> Self::significand_bits() + & ((1 << Self::exponent_bits()) - 1) + } + fn significand(self) -> Self::Int { + self.repr() & ((1 << Self::significand_bits()) - 1) + } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() .wrapping_sub((1u32 << Self::significand_bits()).leading_zeros()); @@ -62,6 +87,9 @@ impl Float for f64 { fn bits() -> u32 { 64 } + fn exponent_bits() -> u32 { + 11 + } fn significand_bits() -> u32 { 52 } @@ -79,6 +107,16 @@ impl Float for f64 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } + fn sign(self) -> bool { + (self.repr() & 1 << Self::bits()) != 0 + } + fn exponent(self) -> Self::Int { + self.repr() >> Self::significand_bits() + & ((1 << Self::exponent_bits()) - 1) + } + fn significand(self) -> Self::Int { + self.repr() & ((1 << Self::significand_bits()) - 1) + } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() .wrapping_sub((1u64 << Self::significand_bits()).leading_zeros()); -- cgit 1.4.1-3-g733a5 From ca01aa45ff1ed89038df3b6cdbaf8e2d237fa157 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Thu, 29 Sep 2016 20:48:28 -0500 Subject: Cleanup add builtin assignments --- library/compiler-builtins/src/float/add.rs | 42 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index a462168b950..395f7e853a1 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -9,27 +9,27 @@ macro_rules! add { #[allow(unused_parens)] #[cfg_attr(not(test), no_mangle)] pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { - let one = Wrapping(1 as <$ty as Float>::Int); - let zero = Wrapping(0 as <$ty as Float>::Int); - - let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); - let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); - let exponent_bits = Wrapping(<$ty>::exponent_bits() as <$ty as Float>::Int); - let max_exponent = (one << exponent_bits.0 as usize) - one; - - let implicit_bit = one << significand_bits.0 as usize; - let significand_mask = implicit_bit - one; - let sign_bit = one << (significand_bits + exponent_bits).0 as usize; - let abs_mask = sign_bit - one; - let exponent_mask = abs_mask ^ significand_mask; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; - - let mut a_rep = Wrapping(a.repr()); - let mut b_rep = Wrapping(b.repr()); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; + let one = Wrapping(1 as <$ty as Float>::Int); + let zero = Wrapping(0 as <$ty as Float>::Int); + + let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); + let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); + let exponent_bits = Wrapping(<$ty>::exponent_bits() as <$ty as Float>::Int); + let max_exponent = (one << exponent_bits.0 as usize) - one; + + let implicit_bit = one << significand_bits.0 as usize; + let significand_mask = implicit_bit - one; + let sign_bit = one << (significand_bits + exponent_bits).0 as usize; + let abs_mask = sign_bit - one; + let exponent_mask = abs_mask ^ significand_mask; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + + let mut a_rep = Wrapping(a.repr()); + let mut b_rep = Wrapping(b.repr()); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; // Detect if a or b is zero, infinity, or NaN. if a_abs - one >= inf_rep - one || -- cgit 1.4.1-3-g733a5 From 43d85fa5cb25faec4109ad471737966d569bd690 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Thu, 29 Sep 2016 20:48:33 -0500 Subject: Add Quickcheck types for float tests --- library/compiler-builtins/src/float/add.rs | 103 ++--------------------------- library/compiler-builtins/src/float/mod.rs | 73 +++++++++++++++----- library/compiler-builtins/src/qc.rs | 55 +++++++++++++++ 3 files changed, 118 insertions(+), 113 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 395f7e853a1..7c9f11a1195 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -188,7 +188,7 @@ mod tests { use core::{f32, f64}; use float::Float; - use qc::{U32, U64}; + use qc::{F32, F64}; // NOTE The tests below have special handing for NaN values. // Because NaN != NaN, the floating-point representations must be used @@ -212,107 +212,18 @@ mod tests { } } - // TODO: Add F32/F64 to qc so that they print the right values (at the very least) check! { fn __addsf3(f: extern fn(f32, f32) -> f32, - a: U32, - b: U32) + a: F32, + b: F32) -> Option > { - let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); - Some(FRepr(f(a, b))) + Some(FRepr(f(a.0, b.0))) } fn __adddf3(f: extern fn(f64, f64) -> f64, - a: U64, - b: U64) -> Option > { - let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); - Some(FRepr(f(a, b))) + a: F64, + b: F64) -> Option > { + Some(FRepr(f(a.0, b.0))) } } - - // More tests for special float values - - #[test] - fn test_float_tiny_plus_tiny() { - let tiny = f32::from_repr(1); - let r = super::__addsf3(tiny, tiny); - assert!(r.eq_repr(tiny + tiny)); - } - - #[test] - fn test_double_tiny_plus_tiny() { - let tiny = f64::from_repr(1); - let r = super::__adddf3(tiny, tiny); - assert!(r.eq_repr(tiny + tiny)); - } - - #[test] - fn test_float_small_plus_small() { - let a = f32::from_repr(327); - let b = f32::from_repr(256); - let r = super::__addsf3(a, b); - assert!(r.eq_repr(a + b)); - } - - #[test] - fn test_double_small_plus_small() { - let a = f64::from_repr(327); - let b = f64::from_repr(256); - let r = super::__adddf3(a, b); - assert!(r.eq_repr(a + b)); - } - - #[test] - fn test_float_one_plus_one() { - let r = super::__addsf3(1f32, 1f32); - assert!(r.eq_repr(1f32 + 1f32)); - } - - #[test] - fn test_double_one_plus_one() { - let r = super::__adddf3(1f64, 1f64); - assert!(r.eq_repr(1f64 + 1f64)); - } - - #[test] - fn test_float_different_nan() { - let a = f32::from_repr(1); - let b = f32::from_repr(0b11111111100100010001001010101010); - let x = super::__addsf3(a, b); - let y = a + b; - assert!(x.eq_repr(y)); - } - - #[test] - fn test_double_different_nan() { - let a = f64::from_repr(1); - let b = f64::from_repr(0b1111111111110010001000100101010101001000101010000110100011101011); - let x = super::__adddf3(a, b); - let y = a + b; - assert!(x.eq_repr(y)); - } - - #[test] - fn test_float_nan() { - let r = super::__addsf3(f32::NAN, 1.23); - assert_eq!(r.repr(), f32::NAN.repr()); - } - - #[test] - fn test_double_nan() { - let r = super::__adddf3(f64::NAN, 1.23); - assert_eq!(r.repr(), f64::NAN.repr()); - } - - #[test] - fn test_float_inf() { - let r = super::__addsf3(f32::INFINITY, -123.4); - assert_eq!(r, f32::INFINITY); - } - - #[test] - fn test_double_inf() { - let r = super::__adddf3(f64::INFINITY, -123.4); - assert_eq!(r, f64::INFINITY); - } } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index a44faade8e1..8aa6328ce06 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -16,17 +16,14 @@ pub trait Float: Sized + Copy { /// Returns the bitwidth of the significand fn significand_bits() -> u32; - /// Returns `self` transmuted to `Self::Int` - fn repr(self) -> Self::Int; + /// Returns a mask for the sign bit of `self` + fn sign_mask() -> Self::Int; - #[cfg(test)] - /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. This methods returns `true` if two NaNs are - /// compared. - fn eq_repr(self, rhs: Self) -> bool; + /// Returns a mask for the exponent portion of `self` + fn exponent_mask() -> Self::Int; - /// Returns a `Self::Int` transmuted back to `Self` - fn from_repr(a: Self::Int) -> Self; + /// Returns a mask for the significand portion of `self` + fn significand_mask() -> Self::Int; /// Returns the sign bit of `self` fn sign(self) -> bool; @@ -37,6 +34,21 @@ pub trait Float: Sized + Copy { /// Returns the significand portion of `self` fn significand(self) -> Self::Int; + /// Returns `self` transmuted to `Self::Int` + fn repr(self) -> Self::Int; + + #[cfg(test)] + /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be + /// represented in multiple different ways. This method returns `true` if two NaNs are + /// compared. + fn eq_repr(self, rhs: Self) -> bool; + + /// Returns a `Self::Int` transmuted back to `Self` + fn from_repr(a: Self::Int) -> Self; + + /// Constructs a `Self` from its parts + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; + /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); } @@ -52,6 +64,15 @@ impl Float for f32 { fn significand_bits() -> u32 { 23 } + fn sign_mask() -> Self::Int { + 1 << (Self::bits() - 1) + } + fn exponent_mask() -> Self::Int { + ((1 << Self::exponent_bits()) - 1) << Self::significand_bits() + } + fn significand_mask() -> Self::Int { + (1 << Self::significand_bits()) - 1 + } fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -66,15 +87,20 @@ impl Float for f32 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } + + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | + exponent & Self::exponent_mask() | + significand & Self::significand_mask()) + } fn sign(self) -> bool { - (self.repr() & 1 << Self::bits()) != 0 + (self.repr() & Self::sign_mask()) != 0 } fn exponent(self) -> Self::Int { - self.repr() >> Self::significand_bits() - & ((1 << Self::exponent_bits()) - 1) + self.repr() >> Self::significand_bits() & Self::exponent_mask() } fn significand(self) -> Self::Int { - self.repr() & ((1 << Self::significand_bits()) - 1) + self.repr() & Self::significand_mask() } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() @@ -93,6 +119,15 @@ impl Float for f64 { fn significand_bits() -> u32 { 52 } + fn sign_mask() -> Self::Int { + 1 << (Self::bits() - 1) + } + fn exponent_mask() -> Self::Int { + ((1 << Self::exponent_bits()) - 1) << Self::significand_bits() + } + fn significand_mask() -> Self::Int { + (1 << Self::significand_bits()) - 1 + } fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -107,15 +142,19 @@ impl Float for f64 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | + exponent & Self::exponent_mask() | + significand & Self::significand_mask()) + } fn sign(self) -> bool { - (self.repr() & 1 << Self::bits()) != 0 + (self.repr() & Self::sign_mask()) != 0 } fn exponent(self) -> Self::Int { - self.repr() >> Self::significand_bits() - & ((1 << Self::exponent_bits()) - 1) + self.repr() >> Self::significand_bits() & Self::exponent_mask() } fn significand(self) -> Self::Int { - self.repr() & ((1 << Self::significand_bits()) - 1) + self.repr() & Self::significand_mask() } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 1450a4ec8b3..9d4fff305f6 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -5,10 +5,12 @@ use std::boxed::Box; use std::fmt; +use core::{f32, f64}; use quickcheck::{Arbitrary, Gen}; use int::LargeInt; +use float::Float; // Generates values in the full range of the integer type macro_rules! arbitrary { @@ -71,6 +73,7 @@ macro_rules! arbitrary { arbitrary!(I32: i32); arbitrary!(U32: u32); + // These integers are "too large". If we generate e.g. `u64` values in the full range then there's // only `1 / 2^32` chance of seeing a value smaller than `2^32` (i.e. whose higher "word" (32-bits) // is `0`)! But this is an important group of values to tests because we have special code paths for @@ -143,6 +146,57 @@ macro_rules! arbitrary_large { arbitrary_large!(I64: i64); arbitrary_large!(U64: u64); + +macro_rules! arbitrary_float { + ($TY:ident : $ty:ident) => { + #[derive(Clone, Copy)] + pub struct $TY(pub $ty); + + impl Arbitrary for $TY { + fn arbitrary(g: &mut G) -> $TY + where G: Gen + { + let special = [ + -0.0, 0.0, $ty::NAN, $ty::INFINITY, -$ty::INFINITY + ]; + + if g.gen_weighted_bool(10) { // Random special case + $TY(*g.choose(&special).unwrap()) + } else if g.gen_weighted_bool(10) { // NaN variants + let sign: bool = g.gen(); + let exponent: <$ty as Float>::Int = g.gen(); + let significand: <$ty as Float>::Int = 0; + $TY($ty::from_parts(sign, exponent, significand)) + } else if g.gen() { // Denormalized + let sign: bool = g.gen(); + let exponent: <$ty as Float>::Int = 0; + let significand: <$ty as Float>::Int = g.gen(); + $TY($ty::from_parts(sign, exponent, significand)) + } else { // Random anything + let sign: bool = g.gen(); + let exponent: <$ty as Float>::Int = g.gen(); + let significand: <$ty as Float>::Int = g.gen(); + $TY($ty::from_parts(sign, exponent, significand)) + } + } + + fn shrink(&self) -> Box> { + ::quickcheck::empty_shrinker() + } + } + + impl fmt::Debug for $TY { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } + } + } +} + +arbitrary_float!(F32: f32); +arbitrary_float!(F64: f64); + + // Convenience macro to test intrinsics against their reference implementations. // // Each intrinsic is tested against both the `gcc_s` library as well as @@ -263,3 +317,4 @@ macro_rules! check { } ) } + -- cgit 1.4.1-3-g733a5 From 92204dce54b277b9f5c4260ecaf5c0ec4eb7d219 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 17:21:54 -0500 Subject: cache Cargo artifacts notable changes in the docker-based testing infrastructure - the docker containers can now modify $CARGO_HOME, to re-use the outer Cargo registry, and the target directory to re-use build artifacts. - the docker containers are removed when their execution finishes because it's no longer necessary to re-start them to inspect them because all the interesting output is in the outer target directory --- library/compiler-builtins/.travis.yml | 7 +++-- .../ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 1 - .../ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 1 - .../docker/arm-unknown-linux-gnueabihf/Dockerfile | 1 - .../armv7-unknown-linux-gnueabihf/Dockerfile | 1 - .../ci/docker/i586-unknown-linux-gnu/Dockerfile | 1 - .../ci/docker/i686-unknown-linux-gnu/Dockerfile | 1 - .../ci/docker/mips-unknown-linux-gnu/Dockerfile | 1 - .../ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 1 - .../ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 1 - .../docker/powerpc64-unknown-linux-gnu/Dockerfile | 1 - .../powerpc64le-unknown-linux-gnu/Dockerfile | 2 -- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 1 - .../ci/docker/thumbv7em-none-eabi/Dockerfile | 1 - .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 1 - .../ci/docker/thumbv7m-none-eabi/Dockerfile | 1 - .../ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 2 -- library/compiler-builtins/ci/run-docker.sh | 32 ++++++++++++++++------ library/compiler-builtins/ci/run.sh | 5 ++-- 19 files changed, 30 insertions(+), 32 deletions(-) mode change 100644 => 100755 library/compiler-builtins/ci/run.sh diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 5b84ae5fd6f..31957119f41 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,3 +1,4 @@ +cache: cargo dist: trusty language: rust services: docker @@ -45,14 +46,16 @@ install: script: - cargo generate-lockfile - if [[ $TRAVIS_OS_NAME = "linux" ]]; then - sudo apt-get remove -y qemu-user-static && - sudo apt-get install -y qemu-user-static && sh ci/run-docker.sh $TARGET; else cargo test --target $TARGET && cargo test --target $TARGET --release; fi +after_success: + # Travis can't cache files that are not readable by "others" + - chmod -R a+r /home/travis/.cargo + branches: only: - auto diff --git a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index 6a68154d192..d9a243fa26c 100644 --- a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -5,6 +5,5 @@ RUN apt-get install -y --no-install-recommends \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ qemu-user-static ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile index 36efcd73ccc..cb4d021bb94 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -4,7 +4,6 @@ RUN apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile index 83e7e52e8f2..985abeceaba 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -4,6 +4,5 @@ RUN apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile index adc15a5c5c5..94cae18ccb9 100644 --- a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -4,6 +4,5 @@ RUN apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile index 63450ff9e0e..3254b1a347a 100644 --- a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -2,4 +2,3 @@ FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y --no-install-recommends \ gcc-multilib libc6-dev ca-certificates -ENV PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile index 63450ff9e0e..3254b1a347a 100644 --- a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -2,4 +2,3 @@ FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y --no-install-recommends \ gcc-multilib libc6-dev ca-certificates -ENV PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile index 328152471f8..e332b540394 100644 --- a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -7,6 +7,5 @@ RUN apt-get install -y --no-install-recommends \ binfmt-support qemu-user-static qemu-system-mips ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/mips-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile index 088c45f04a8..28f77be64d7 100644 --- a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -7,6 +7,5 @@ RUN apt-get install -y --no-install-recommends \ binfmt-support qemu-user-static ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile index 542afa2f4d9..8106728b96e 100644 --- a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -7,6 +7,5 @@ RUN apt-get install -y --no-install-recommends \ qemu-system-ppc ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile index f4559c7de99..3259b4d9244 100644 --- a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -8,6 +8,5 @@ RUN apt-get install -y --no-install-recommends \ ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile index 9a777883d24..bd0a182a886 100644 --- a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -7,7 +7,5 @@ RUN apt-get install -y --no-install-recommends \ qemu-system-ppc ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ - CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index c6f7209f3a3..6f4997546bd 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -5,4 +5,3 @@ RUN apt-get install -y --no-install-recommends \ ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv6m_none_eabi=arm-none-eabi-gcc \ - PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 016097b2eab..5d26c922717 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -5,4 +5,3 @@ RUN apt-get install -y --no-install-recommends \ ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ - PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index c7188ef5886..f223320c2e3 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -5,4 +5,3 @@ RUN apt-get install -y --no-install-recommends \ ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ - PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index 542cc920187..e0121034c8a 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -5,4 +5,3 @@ RUN apt-get install -y --no-install-recommends \ ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ - PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile index a5704bb64b4..2ca8ee99c7c 100644 --- a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -2,5 +2,3 @@ FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates -ENV PATH=$PATH:/rust/bin - diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 69127148546..82eacbac0ab 100644 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -4,16 +4,30 @@ set -ex run() { - echo $1 - docker build -t $1 ci/docker/$1 + local gid=$(id -g) \ + group=$(id -g -n) \ + target=$1 \ + uid=$(id -u) \ + user=$(id -u -n) + + echo $target + docker build -t $target ci/docker/$target docker run \ - -v `rustc --print sysroot`:/rust:ro \ - -v `pwd`:/checkout:ro \ - -e CARGO_TARGET_DIR=/tmp/target \ - -w /checkout \ - --privileged \ - -it $1 \ - sh ci/run.sh $1 + --rm \ + -e CARGO_HOME=/cargo \ + -e CARGO_TARGET_DIR=/target \ + -v $HOME/.cargo:/cargo \ + -v `pwd`/target:/target \ + -v `pwd`:/checkout:ro \ + -v `rustc --print sysroot`:/rust:ro \ + -w /checkout \ + -it $target \ + sh -c " +groupadd -g $gid $group +useradd -m -g $gid -u $uid $user +chown $user /cargo /target +su -c 'PATH=\$PATH:/rust/bin ci/run.sh $target' $user +" } if [ -z "$1" ]; then diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh old mode 100644 new mode 100755 index c0406e33f23..206b2e9ed3c --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -44,10 +44,9 @@ esac case $TRAVIS_OS_NAME in osx) - NM=gnm - # NOTE OSx's nm doesn't accept the `--defined-only` or provide an equivalent. # Use GNU nm instead + NM=gnm brew install binutils ;; *) @@ -56,7 +55,7 @@ case $TRAVIS_OS_NAME in esac # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it -$PREFIX$NM -g --defined-only /tmp/target/${1}/debug/librustc_builtins.rlib | \ +$PREFIX$NM -g --defined-only /target/${1}/debug/librustc_builtins.rlib | \ sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' if test $? = 0; then -- cgit 1.4.1-3-g733a5 From 9e1f8322e5f2d4d81ce3445400154185397c4c38 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 18:09:52 -0500 Subject: do chmod jut before the script phase ends --- library/compiler-builtins/.travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 31957119f41..4ea6ddc416f 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -51,8 +51,6 @@ script: cargo test --target $TARGET && cargo test --target $TARGET --release; fi - -after_success: # Travis can't cache files that are not readable by "others" - chmod -R a+r /home/travis/.cargo -- cgit 1.4.1-3-g733a5 From f707dda057608d56e1e0c6946fe2baa0fa80c3e9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 18:25:40 -0500 Subject: /home/travis -> $HOME --- library/compiler-builtins/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 4ea6ddc416f..7b3efe474a0 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -52,7 +52,7 @@ script: cargo test --target $TARGET --release; fi # Travis can't cache files that are not readable by "others" - - chmod -R a+r /home/travis/.cargo + - chmod -R a+r $HOME/.cargo branches: only: -- cgit 1.4.1-3-g733a5 From d44e127053a93218c1555640c9ebc7f415c84727 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 18:37:41 -0500 Subject: use `docker run --user` instead of manually creating a user --- library/compiler-builtins/ci/run-docker.sh | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 82eacbac0ab..d80e758313d 100644 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -4,16 +4,18 @@ set -ex run() { - local gid=$(id -g) \ - group=$(id -g -n) \ - target=$1 \ - uid=$(id -u) \ - user=$(id -u -n) + local target=$1 echo $target + + # This directory needs to exist before calling docker, otherwise docker will create it but it + # will be owned by root + mkdir -p target + docker build -t $target ci/docker/$target docker run \ --rm \ + --user $(id -u):$(id -g) \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ -v $HOME/.cargo:/cargo \ @@ -22,12 +24,7 @@ run() { -v `rustc --print sysroot`:/rust:ro \ -w /checkout \ -it $target \ - sh -c " -groupadd -g $gid $group -useradd -m -g $gid -u $uid $user -chown $user /cargo /target -su -c 'PATH=\$PATH:/rust/bin ci/run.sh $target' $user -" + sh -c "PATH=\$PATH:/rust/bin ci/run.sh $target" } if [ -z "$1" ]; then -- cgit 1.4.1-3-g733a5 From 0864c9d6a221c69f8644199991e56f5458f63347 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 19:04:48 -0500 Subject: fix nm call the prefix was missing a '-', i.e. arm-linux-gnueabinm was being called. This also sets -e in run.sh to catch this sort of errors. --- library/compiler-builtins/ci/run.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 206b2e9ed3c..e07c82fd0b6 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,3 +1,5 @@ +set -e + # Test our implementation case $1 in thumb*) @@ -29,7 +31,7 @@ case $1 in esac # Look out for duplicated symbols when we include the compiler-rt (C) implementation -PREFIX=$(echo $1 | sed -e 's/unknown-//') +PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in armv7-*) PREFIX=arm-linux-gnueabihf- @@ -55,8 +57,10 @@ case $TRAVIS_OS_NAME in esac # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it -$PREFIX$NM -g --defined-only /target/${1}/debug/librustc_builtins.rlib | \ - sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' +stdout=$($PREFIX$NM -g --defined-only /target/${1}/debug/librustc_builtins.rlib) + +set +e +echo $stdout | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' if test $? = 0; then exit 1 -- cgit 1.4.1-3-g733a5 From 7009fd238d261eb84f353a122cb31cedc30c6899 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 19:12:17 -0500 Subject: Revert "Merge pull request #48 from mattico/add_float_quickcheck" This reverts commit e34a6058df470e5b3d187c947ac41a294994c414, reversing changes made to cab88e6133b0db9c6663ffd8b2f65cb35e8a9dda. --- library/compiler-builtins/src/float/add.rs | 145 +++++++++++++++++++++++------ library/compiler-builtins/src/float/mod.rs | 79 +--------------- library/compiler-builtins/src/qc.rs | 55 ----------- 3 files changed, 118 insertions(+), 161 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 7c9f11a1195..7707850217c 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -9,27 +9,27 @@ macro_rules! add { #[allow(unused_parens)] #[cfg_attr(not(test), no_mangle)] pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { - let one = Wrapping(1 as <$ty as Float>::Int); - let zero = Wrapping(0 as <$ty as Float>::Int); - - let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); - let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); - let exponent_bits = Wrapping(<$ty>::exponent_bits() as <$ty as Float>::Int); - let max_exponent = (one << exponent_bits.0 as usize) - one; - - let implicit_bit = one << significand_bits.0 as usize; - let significand_mask = implicit_bit - one; - let sign_bit = one << (significand_bits + exponent_bits).0 as usize; - let abs_mask = sign_bit - one; - let exponent_mask = abs_mask ^ significand_mask; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; - - let mut a_rep = Wrapping(a.repr()); - let mut b_rep = Wrapping(b.repr()); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; + let one = Wrapping(1 as <$ty as Float>::Int); + let zero = Wrapping(0 as <$ty as Float>::Int); + + let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); + let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); + let exponent_bits = bits - significand_bits - one; + let max_exponent = (one << exponent_bits.0 as usize) - one; + + let implicit_bit = one << significand_bits.0 as usize; + let significand_mask = implicit_bit - one; + let sign_bit = one << (significand_bits + exponent_bits).0 as usize; + let abs_mask = sign_bit - one; + let exponent_mask = abs_mask ^ significand_mask; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + + let mut a_rep = Wrapping(a.repr()); + let mut b_rep = Wrapping(b.repr()); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; // Detect if a or b is zero, infinity, or NaN. if a_abs - one >= inf_rep - one || @@ -188,7 +188,7 @@ mod tests { use core::{f32, f64}; use float::Float; - use qc::{F32, F64}; + use qc::{U32, U64}; // NOTE The tests below have special handing for NaN values. // Because NaN != NaN, the floating-point representations must be used @@ -212,18 +212,107 @@ mod tests { } } + // TODO: Add F32/F64 to qc so that they print the right values (at the very least) check! { fn __addsf3(f: extern fn(f32, f32) -> f32, - a: F32, - b: F32) + a: U32, + b: U32) -> Option > { - Some(FRepr(f(a.0, b.0))) + let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); + Some(FRepr(f(a, b))) } fn __adddf3(f: extern fn(f64, f64) -> f64, - a: F64, - b: F64) -> Option > { - Some(FRepr(f(a.0, b.0))) + a: U64, + b: U64) -> Option > { + let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); + Some(FRepr(f(a, b))) } } + + // More tests for special float values + + #[test] + fn test_float_tiny_plus_tiny() { + let tiny = f32::from_repr(1); + let r = super::__addsf3(tiny, tiny); + assert!(r.eq_repr(tiny + tiny)); + } + + #[test] + fn test_double_tiny_plus_tiny() { + let tiny = f64::from_repr(1); + let r = super::__adddf3(tiny, tiny); + assert!(r.eq_repr(tiny + tiny)); + } + + #[test] + fn test_float_small_plus_small() { + let a = f32::from_repr(327); + let b = f32::from_repr(256); + let r = super::__addsf3(a, b); + assert!(r.eq_repr(a + b)); + } + + #[test] + fn test_double_small_plus_small() { + let a = f64::from_repr(327); + let b = f64::from_repr(256); + let r = super::__adddf3(a, b); + assert!(r.eq_repr(a + b)); + } + + #[test] + fn test_float_one_plus_one() { + let r = super::__addsf3(1f32, 1f32); + assert!(r.eq_repr(1f32 + 1f32)); + } + + #[test] + fn test_double_one_plus_one() { + let r = super::__adddf3(1f64, 1f64); + assert!(r.eq_repr(1f64 + 1f64)); + } + + #[test] + fn test_float_different_nan() { + let a = f32::from_repr(1); + let b = f32::from_repr(0b11111111100100010001001010101010); + let x = super::__addsf3(a, b); + let y = a + b; + assert!(x.eq_repr(y)); + } + + #[test] + fn test_double_different_nan() { + let a = f64::from_repr(1); + let b = f64::from_repr(0b1111111111110010001000100101010101001000101010000110100011101011); + let x = super::__adddf3(a, b); + let y = a + b; + assert!(x.eq_repr(y)); + } + + #[test] + fn test_float_nan() { + let r = super::__addsf3(f32::NAN, 1.23); + assert_eq!(r.repr(), f32::NAN.repr()); + } + + #[test] + fn test_double_nan() { + let r = super::__adddf3(f64::NAN, 1.23); + assert_eq!(r.repr(), f64::NAN.repr()); + } + + #[test] + fn test_float_inf() { + let r = super::__addsf3(f32::INFINITY, -123.4); + assert_eq!(r, f32::INFINITY); + } + + #[test] + fn test_double_inf() { + let r = super::__adddf3(f64::INFINITY, -123.4); + assert_eq!(r, f64::INFINITY); + } } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 8aa6328ce06..cee2b739873 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -10,45 +10,21 @@ pub trait Float: Sized + Copy { /// Returns the bitwidth of the float type fn bits() -> u32; - /// Returns the bitwidth of the exponent - fn exponent_bits() -> u32; - /// Returns the bitwidth of the significand fn significand_bits() -> u32; - /// Returns a mask for the sign bit of `self` - fn sign_mask() -> Self::Int; - - /// Returns a mask for the exponent portion of `self` - fn exponent_mask() -> Self::Int; - - /// Returns a mask for the significand portion of `self` - fn significand_mask() -> Self::Int; - - /// Returns the sign bit of `self` - fn sign(self) -> bool; - - /// Returns the exponent portion of `self`, shifted to the right - fn exponent(self) -> Self::Int; - - /// Returns the significand portion of `self` - fn significand(self) -> Self::Int; - /// Returns `self` transmuted to `Self::Int` fn repr(self) -> Self::Int; #[cfg(test)] /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. This method returns `true` if two NaNs are + /// represented in multiple different ways. This methods returns `true` if two NaNs are /// compared. fn eq_repr(self, rhs: Self) -> bool; /// Returns a `Self::Int` transmuted back to `Self` fn from_repr(a: Self::Int) -> Self; - /// Constructs a `Self` from its parts - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; - /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); } @@ -58,21 +34,9 @@ impl Float for f32 { fn bits() -> u32 { 32 } - fn exponent_bits() -> u32 { - 8 - } fn significand_bits() -> u32 { 23 } - fn sign_mask() -> Self::Int { - 1 << (Self::bits() - 1) - } - fn exponent_mask() -> Self::Int { - ((1 << Self::exponent_bits()) - 1) << Self::significand_bits() - } - fn significand_mask() -> Self::Int { - (1 << Self::significand_bits()) - 1 - } fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -87,21 +51,6 @@ impl Float for f32 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } - - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | - exponent & Self::exponent_mask() | - significand & Self::significand_mask()) - } - fn sign(self) -> bool { - (self.repr() & Self::sign_mask()) != 0 - } - fn exponent(self) -> Self::Int { - self.repr() >> Self::significand_bits() & Self::exponent_mask() - } - fn significand(self) -> Self::Int { - self.repr() & Self::significand_mask() - } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() .wrapping_sub((1u32 << Self::significand_bits()).leading_zeros()); @@ -113,21 +62,9 @@ impl Float for f64 { fn bits() -> u32 { 64 } - fn exponent_bits() -> u32 { - 11 - } fn significand_bits() -> u32 { 52 } - fn sign_mask() -> Self::Int { - 1 << (Self::bits() - 1) - } - fn exponent_mask() -> Self::Int { - ((1 << Self::exponent_bits()) - 1) << Self::significand_bits() - } - fn significand_mask() -> Self::Int { - (1 << Self::significand_bits()) - 1 - } fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -142,20 +79,6 @@ impl Float for f64 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | - exponent & Self::exponent_mask() | - significand & Self::significand_mask()) - } - fn sign(self) -> bool { - (self.repr() & Self::sign_mask()) != 0 - } - fn exponent(self) -> Self::Int { - self.repr() >> Self::significand_bits() & Self::exponent_mask() - } - fn significand(self) -> Self::Int { - self.repr() & Self::significand_mask() - } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() .wrapping_sub((1u64 << Self::significand_bits()).leading_zeros()); diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 9d4fff305f6..1450a4ec8b3 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -5,12 +5,10 @@ use std::boxed::Box; use std::fmt; -use core::{f32, f64}; use quickcheck::{Arbitrary, Gen}; use int::LargeInt; -use float::Float; // Generates values in the full range of the integer type macro_rules! arbitrary { @@ -73,7 +71,6 @@ macro_rules! arbitrary { arbitrary!(I32: i32); arbitrary!(U32: u32); - // These integers are "too large". If we generate e.g. `u64` values in the full range then there's // only `1 / 2^32` chance of seeing a value smaller than `2^32` (i.e. whose higher "word" (32-bits) // is `0`)! But this is an important group of values to tests because we have special code paths for @@ -146,57 +143,6 @@ macro_rules! arbitrary_large { arbitrary_large!(I64: i64); arbitrary_large!(U64: u64); - -macro_rules! arbitrary_float { - ($TY:ident : $ty:ident) => { - #[derive(Clone, Copy)] - pub struct $TY(pub $ty); - - impl Arbitrary for $TY { - fn arbitrary(g: &mut G) -> $TY - where G: Gen - { - let special = [ - -0.0, 0.0, $ty::NAN, $ty::INFINITY, -$ty::INFINITY - ]; - - if g.gen_weighted_bool(10) { // Random special case - $TY(*g.choose(&special).unwrap()) - } else if g.gen_weighted_bool(10) { // NaN variants - let sign: bool = g.gen(); - let exponent: <$ty as Float>::Int = g.gen(); - let significand: <$ty as Float>::Int = 0; - $TY($ty::from_parts(sign, exponent, significand)) - } else if g.gen() { // Denormalized - let sign: bool = g.gen(); - let exponent: <$ty as Float>::Int = 0; - let significand: <$ty as Float>::Int = g.gen(); - $TY($ty::from_parts(sign, exponent, significand)) - } else { // Random anything - let sign: bool = g.gen(); - let exponent: <$ty as Float>::Int = g.gen(); - let significand: <$ty as Float>::Int = g.gen(); - $TY($ty::from_parts(sign, exponent, significand)) - } - } - - fn shrink(&self) -> Box> { - ::quickcheck::empty_shrinker() - } - } - - impl fmt::Debug for $TY { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } - } - } -} - -arbitrary_float!(F32: f32); -arbitrary_float!(F64: f64); - - // Convenience macro to test intrinsics against their reference implementations. // // Each intrinsic is tested against both the `gcc_s` library as well as @@ -317,4 +263,3 @@ macro_rules! check { } ) } - -- cgit 1.4.1-3-g733a5 From cea4ff6d255f7bcffa6f0c26966a6ba7521a5d23 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 20:08:29 -0500 Subject: add back the mysterious apt-get install qemu-user-static --- library/compiler-builtins/.travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7b3efe474a0..e8931afad8d 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -46,6 +46,8 @@ install: script: - cargo generate-lockfile - if [[ $TRAVIS_OS_NAME = "linux" ]]; then + sudo apt-get remove -y qemu-user-static && + sudo apt-get install -y qemu-user-static && sh ci/run-docker.sh $TARGET; else cargo test --target $TARGET && -- cgit 1.4.1-3-g733a5 From 9b1c06948d3ee1d8087b43b995e143b43e705dff Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 20:20:15 -0500 Subject: fix Xargo installation --- library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile | 2 ++ library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile | 2 ++ library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile | 2 ++ library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile | 2 ++ library/compiler-builtins/ci/run.sh | 2 -- 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index 6f4997546bd..52c969342cc 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -2,6 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv6m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 5d26c922717..5825fce9983 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -2,6 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ + bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index f223320c2e3..7b2046ae70c 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -2,6 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ + bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index e0121034c8a..f3dce399714 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -2,6 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ + bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index e07c82fd0b6..eae37deb2ef 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -3,8 +3,6 @@ set -e # Test our implementation case $1 in thumb*) - curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 xargo build --target $1 xargo build --target $1 --release ;; -- cgit 1.4.1-3-g733a5 From 20926bc1fd603ddd44bab16c9a0c94c8a5b75ce0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 20:21:15 -0500 Subject: give Xargo a $HOME --- library/compiler-builtins/ci/run-docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index d80e758313d..5608cedc467 100644 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -24,7 +24,7 @@ run() { -v `rustc --print sysroot`:/rust:ro \ -w /checkout \ -it $target \ - sh -c "PATH=\$PATH:/rust/bin ci/run.sh $target" + sh -c "HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" } if [ -z "$1" ]; then -- cgit 1.4.1-3-g733a5 From dd34b80ea0c629524404392496cafd3ea0ca6f72 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 20:41:59 -0500 Subject: pick target during Xargo installation --- library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile | 2 +- library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile | 2 +- library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 5825fce9983..6f5b478e4ad 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index 7b2046ae70c..3cd8acae9a4 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index f3dce399714..88adb2ddd6e 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ -- cgit 1.4.1-3-g733a5 From ab4e4bfd71e6c4b6c1a7481fff70dc7e2d52c737 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sun, 2 Oct 2016 14:21:09 -0500 Subject: Initial implementation of multitester --- library/compiler-builtins/src/float/add.rs | 15 +++--- library/compiler-builtins/src/qc.rs | 80 ++++++++++++------------------ 2 files changed, 41 insertions(+), 54 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 7707850217c..63baf0068cb 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -186,16 +186,13 @@ add!(__adddf3: f64); #[cfg(test)] mod tests { use core::{f32, f64}; + use core::fmt; use float::Float; use qc::{U32, U64}; - // NOTE The tests below have special handing for NaN values. - // Because NaN != NaN, the floating-point representations must be used - // Because there are many diffferent values of NaN, and the implementation - // doesn't care about calculating the 'correct' one, if both values are NaN - // the values are considered equivalent. - + // TODO: Move this to F32/F64 in qc.rs + #[derive(Copy, Clone)] struct FRepr(F); impl PartialEq for FRepr { @@ -212,6 +209,12 @@ mod tests { } } + impl fmt::Debug for FRepr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } + } + // TODO: Add F32/F64 to qc so that they print the right values (at the very least) check! { fn __addsf3(f: extern fn(f32, f32) -> f32, diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 1450a4ec8b3..f7696b58de5 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -195,7 +195,7 @@ macro_rules! check { } )* - mod _compiler_rt { + mod _test { use qc::*; use std::mem; use quickcheck::TestResult; @@ -207,56 +207,40 @@ macro_rules! check { let my_answer = super::$name(super::super::$name, $($arg),*); let compiler_rt_fn = ::compiler_rt::get(stringify!($name)); - unsafe { - let compiler_rt_answer = - super::$name(mem::transmute(compiler_rt_fn), - $($arg),*); - match (my_answer, compiler_rt_answer) { - (None, _) | (_, None) => TestResult::discard(), - (Some(a), Some(b)) => { - TestResult::from_bool(a == b) - } - } - } - } - - ::quickcheck::quickcheck(my_check as fn($($t),*) -> TestResult) - } - )* - } - - mod _gcc_s { - use qc::*; - use std::mem; - use quickcheck::TestResult; - - $( - #[test] - fn $name() { - fn my_check($($arg:$t),*) -> TestResult { - let my_answer = super::$name(super::super::$name, - $($arg),*); - let gcc_s_fn = ::gcc_s::get(stringify!($name)).unwrap(); - unsafe { - let gcc_s_answer = - super::$name(mem::transmute(gcc_s_fn), - $($arg),*); - match (my_answer, gcc_s_answer) { - (None, _) | (_, None) => TestResult::discard(), - (Some(a), Some(b)) => { - TestResult::from_bool(a == b) - } - } + let compiler_rt_answer = unsafe { + super::$name(mem::transmute(compiler_rt_fn), + $($arg),*) + }; + let gcc_s_answer = + match ::gcc_s::get(stringify!($name)) { + Some(f) => unsafe { + Some(super::$name(mem::transmute(f), + $($arg),*)) + }, + None => None, + }; + + let print_values = || { + print!("{} - Args: ", stringify!($name)); + $(print!("{:?} ", $arg);)* + print!("\n"); + println!(" rustc-builtins: {:?}", my_answer); + println!(" compiler_rt: {:?}", compiler_rt_answer); + println!(" gcc_s: {:?}", gcc_s_answer); + }; + + if my_answer != compiler_rt_answer { + print_values(); + TestResult::from_bool(false) + } else if gcc_s_answer.is_some() && + my_answer != gcc_s_answer.unwrap() { + print_values(); + TestResult::from_bool(false) + } else { + TestResult::from_bool(true) } } - // If it's not in libgcc, or we couldn't find libgcc, then - // just ignore this. We should have tests through - // compiler-rt in any case - if ::gcc_s::get(stringify!($name)).is_none() { - return - } - ::quickcheck::quickcheck(my_check as fn($($t),*) -> TestResult) } )* -- cgit 1.4.1-3-g733a5 From e4997a2026340fd6a63edb79d679dbdb164cb4b3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 2 Oct 2016 19:05:01 -0500 Subject: hide the thumbv* target files due to how Cargo works, the rustc-cfg in build.rs was picking our target specifications rather than the one the user meant to use. Placing our target files in any place other than the root of the Cargo project avoids the issue. --- library/compiler-builtins/ci/run.sh | 2 ++ library/compiler-builtins/targets/thumbv6m-none-eabi.json | 12 ++++++++++++ library/compiler-builtins/targets/thumbv7em-none-eabi.json | 10 ++++++++++ library/compiler-builtins/targets/thumbv7em-none-eabihf.json | 11 +++++++++++ library/compiler-builtins/targets/thumbv7m-none-eabi.json | 10 ++++++++++ library/compiler-builtins/thumbv6m-none-eabi.json | 12 ------------ library/compiler-builtins/thumbv7em-none-eabi.json | 10 ---------- library/compiler-builtins/thumbv7em-none-eabihf.json | 11 ----------- library/compiler-builtins/thumbv7m-none-eabi.json | 10 ---------- 9 files changed, 45 insertions(+), 43 deletions(-) create mode 100644 library/compiler-builtins/targets/thumbv6m-none-eabi.json create mode 100644 library/compiler-builtins/targets/thumbv7em-none-eabi.json create mode 100644 library/compiler-builtins/targets/thumbv7em-none-eabihf.json create mode 100644 library/compiler-builtins/targets/thumbv7m-none-eabi.json delete mode 100644 library/compiler-builtins/thumbv6m-none-eabi.json delete mode 100644 library/compiler-builtins/thumbv7em-none-eabi.json delete mode 100644 library/compiler-builtins/thumbv7em-none-eabihf.json delete mode 100644 library/compiler-builtins/thumbv7m-none-eabi.json diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index eae37deb2ef..e938bc18c74 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -3,6 +3,8 @@ set -e # Test our implementation case $1 in thumb*) + export RUST_TARGET_PATH=/checkout/targets + xargo build --target $1 xargo build --target $1 --release ;; diff --git a/library/compiler-builtins/targets/thumbv6m-none-eabi.json b/library/compiler-builtins/targets/thumbv6m-none-eabi.json new file mode 100644 index 00000000000..4b409cff049 --- /dev/null +++ b/library/compiler-builtins/targets/thumbv6m-none-eabi.json @@ -0,0 +1,12 @@ +{ + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "executables": true, + "features": "+strict-align", + "llvm-target": "thumbv6m-none-eabi", + "max-atomic-width": 0, + "os": "none", + "pre-link-args": ["-nostartfiles"], + "target-endian": "little", + "target-pointer-width": "32" +} diff --git a/library/compiler-builtins/targets/thumbv7em-none-eabi.json b/library/compiler-builtins/targets/thumbv7em-none-eabi.json new file mode 100644 index 00000000000..2ac47c8f829 --- /dev/null +++ b/library/compiler-builtins/targets/thumbv7em-none-eabi.json @@ -0,0 +1,10 @@ +{ + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "executables": true, + "llvm-target": "thumbv7em-none-eabi", + "os": "none", + "pre-link-args": ["-nostartfiles"], + "target-endian": "little", + "target-pointer-width": "32" +} diff --git a/library/compiler-builtins/targets/thumbv7em-none-eabihf.json b/library/compiler-builtins/targets/thumbv7em-none-eabihf.json new file mode 100644 index 00000000000..55ed3fd885d --- /dev/null +++ b/library/compiler-builtins/targets/thumbv7em-none-eabihf.json @@ -0,0 +1,11 @@ +{ + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "executables": true, + "features": "+vfp4", + "llvm-target": "thumbv7em-none-eabihf", + "os": "none", + "pre-link-args": ["-nostartfiles"], + "target-endian": "little", + "target-pointer-width": "32" +} diff --git a/library/compiler-builtins/targets/thumbv7m-none-eabi.json b/library/compiler-builtins/targets/thumbv7m-none-eabi.json new file mode 100644 index 00000000000..9635efa8d78 --- /dev/null +++ b/library/compiler-builtins/targets/thumbv7m-none-eabi.json @@ -0,0 +1,10 @@ +{ + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "executables": true, + "llvm-target": "thumbv7m-none-eabi", + "os": "none", + "pre-link-args": ["-nostartfiles"], + "target-endian": "little", + "target-pointer-width": "32" +} diff --git a/library/compiler-builtins/thumbv6m-none-eabi.json b/library/compiler-builtins/thumbv6m-none-eabi.json deleted file mode 100644 index 4b409cff049..00000000000 --- a/library/compiler-builtins/thumbv6m-none-eabi.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "executables": true, - "features": "+strict-align", - "llvm-target": "thumbv6m-none-eabi", - "max-atomic-width": 0, - "os": "none", - "pre-link-args": ["-nostartfiles"], - "target-endian": "little", - "target-pointer-width": "32" -} diff --git a/library/compiler-builtins/thumbv7em-none-eabi.json b/library/compiler-builtins/thumbv7em-none-eabi.json deleted file mode 100644 index 2ac47c8f829..00000000000 --- a/library/compiler-builtins/thumbv7em-none-eabi.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "executables": true, - "llvm-target": "thumbv7em-none-eabi", - "os": "none", - "pre-link-args": ["-nostartfiles"], - "target-endian": "little", - "target-pointer-width": "32" -} diff --git a/library/compiler-builtins/thumbv7em-none-eabihf.json b/library/compiler-builtins/thumbv7em-none-eabihf.json deleted file mode 100644 index 55ed3fd885d..00000000000 --- a/library/compiler-builtins/thumbv7em-none-eabihf.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "executables": true, - "features": "+vfp4", - "llvm-target": "thumbv7em-none-eabihf", - "os": "none", - "pre-link-args": ["-nostartfiles"], - "target-endian": "little", - "target-pointer-width": "32" -} diff --git a/library/compiler-builtins/thumbv7m-none-eabi.json b/library/compiler-builtins/thumbv7m-none-eabi.json deleted file mode 100644 index 9635efa8d78..00000000000 --- a/library/compiler-builtins/thumbv7m-none-eabi.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "executables": true, - "llvm-target": "thumbv7m-none-eabi", - "os": "none", - "pre-link-args": ["-nostartfiles"], - "target-endian": "little", - "target-pointer-width": "32" -} -- cgit 1.4.1-3-g733a5 From e6bc8007dd49f63d8b0b62ee436aae27ea7893a1 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Fri, 30 Sep 2016 17:15:44 -0500 Subject: Implement powi_f2 --- library/compiler-builtins/README.md | 4 +- .../compiler-rt/compiler-rt-cdylib/build.rs | 2 + .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 4 ++ library/compiler-builtins/src/float/add.rs | 27 +---------- library/compiler-builtins/src/float/mod.rs | 29 ++++++++++++ library/compiler-builtins/src/float/pow.rs | 53 ++++++++++++++++++++++ 6 files changed, 91 insertions(+), 28 deletions(-) create mode 100644 library/compiler-builtins/src/float/pow.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 28d86043ad5..20b153d7dc1 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -159,8 +159,8 @@ porting that particular intrinsic. - [x] mulodi4.c - [x] mulosi4.c - [ ] mulsf3.c -- [ ] powidf2.c -- [ ] powisf2.c +- [x] powidf2.c +- [x] powisf2.c - [ ] subdf3.c - [ ] subsf3.c - [ ] truncdfhf2.c diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs index b9b56a627b0..4eb76389570 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs @@ -58,6 +58,8 @@ fn main() { "udivmodsi4.c", "adddf3.c", "addsf3.c", + "powidf2.c", + "powisf2.c", ]); for src in sources.files.iter() { diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs index 57584832ff8..81affa2421a 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -22,6 +22,8 @@ extern { fn __umodsi3(); fn __addsf3(); fn __adddf3(); + fn __powisf2(); + fn __powidf2(); } macro_rules! declare { @@ -53,6 +55,8 @@ declare!(___umoddi3, __umoddi3); declare!(___umodsi3, __umodsi3); declare!(___addsf3, __addsf3); declare!(___adddf3, __adddf3); +declare!(___powisf2, __powisf2); +declare!(___powidf2, __powidf2); #[lang = "eh_personality"] fn eh_personality() {} diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 63baf0068cb..243c391b565 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -186,35 +186,10 @@ add!(__adddf3: f64); #[cfg(test)] mod tests { use core::{f32, f64}; - use core::fmt; - use float::Float; + use float::{Float, FRepr}; use qc::{U32, U64}; - // TODO: Move this to F32/F64 in qc.rs - #[derive(Copy, Clone)] - struct FRepr(F); - - impl PartialEq for FRepr { - fn eq(&self, other: &FRepr) -> bool { - // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't - // match the output of its gcc_s counterpart. Until we investigate further, we'll - // just avoid testing against gcc_s on those targets. Do note that our - // implementation matches the output of the FPU instruction on *hard* float targets - // and matches its gcc_s counterpart on *soft* float targets. - if cfg!(gnueabihf) { - return true - } - self.0.eq_repr(other.0) - } - } - - impl fmt::Debug for FRepr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } - } - // TODO: Add F32/F64 to qc so that they print the right values (at the very least) check! { fn __addsf3(f: extern fn(f32, f32) -> f32, diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index cee2b739873..8bd574deb17 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,6 +1,8 @@ use core::mem; +use core::fmt; pub mod add; +pub mod pow; /// Trait for some basic operations on floats pub trait Float: Sized + Copy { @@ -85,3 +87,30 @@ impl Float for f64 { (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) } } + +// TODO: Move this to F32/F64 in qc.rs +#[cfg(test)] +#[derive(Copy, Clone)] +pub struct FRepr(F); + +#[cfg(test)] +impl PartialEq for FRepr { + fn eq(&self, other: &FRepr) -> bool { + // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't + // match the output of its gcc_s counterpart. Until we investigate further, we'll + // just avoid testing against gcc_s on those targets. Do note that our + // implementation matches the output of the FPU instruction on *hard* float targets + // and matches its gcc_s counterpart on *soft* float targets. + if cfg!(gnueabihf) { + return true + } + self.0.eq_repr(other.0) + } +} + +#[cfg(test)] +impl fmt::Debug for FRepr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs new file mode 100644 index 00000000000..14b3b9ace6a --- /dev/null +++ b/library/compiler-builtins/src/float/pow.rs @@ -0,0 +1,53 @@ + +macro_rules! pow { + ($intrinsic:ident: $fty:ty, $ity:ty) => { + /// Returns `a` raised to the power `b` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $fty, b: $ity) -> $fty { + let (mut a, mut b) = (a, b); + let recip = b < 0; + let mut r: $fty = 1.0; + loop { + if (b & 1) != 0 { + r *= a; + } + b /= 2; + if b == 0 { + break; + } + a *= a; + } + + if recip { + 1.0 / r + } else { + r + } + } + } +} + +pow!(__powisf2: f32, i32); +pow!(__powidf2: f64, i32); + +#[cfg(test)] +mod tests { + use float::{Float, FRepr}; + use qc::{I32, U32, U64}; + + check! { + fn __powisf2(f: extern fn(f32, i32) -> f32, + a: U32, + b: I32) -> Option > { + let (a, b) = (f32::from_repr(a.0), b.0); + Some(FRepr(f(a, b))) + } + + fn __powidf2(f: extern fn(f64, i32) -> f64, + a: U64, + b: I32) -> Option > { + let (a, b) = (f64::from_repr(a.0), b.0); + Some(FRepr(f(a, b))) + } + } +} -- cgit 1.4.1-3-g733a5 From 4e7d7c7cd832dd7fee4568a0e81c519af53c8769 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 3 Oct 2016 09:12:13 -0500 Subject: bump rustc-cfg version and show a better error message when it fails --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/build.rs | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 93f7d197012..c198d9f3ccb 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" [build-dependencies] gcc = "0.3.35" -rustc-cfg = "0.1.2" +rustc-cfg = "0.2.0" [dependencies] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a05a1a590ad..cf9a24e3b1f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -2,8 +2,9 @@ extern crate gcc; extern crate rustc_cfg; use std::collections::BTreeMap; -use std::env; +use std::io::Write; use std::path::Path; +use std::{env, io, process}; use rustc_cfg::Cfg; @@ -50,7 +51,10 @@ fn main() { let target = env::var("TARGET").unwrap(); let Cfg { ref target_arch, ref target_os, ref target_env, ref target_vendor, .. } = - Cfg::new(&target).unwrap(); + Cfg::new(&target).unwrap_or_else(|e| { + writeln!(io::stderr(), "{}", e).ok(); + process::exit(1) + }); // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the // target triple. This is usually correct for our built-in targets but can break in presence of // custom targets, which can have arbitrary names. -- cgit 1.4.1-3-g733a5 From 27adb57c40706466dbe2ffd4e5bca7b15e01cb92 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 3 Oct 2016 20:19:56 -0500 Subject: fix duplicate symbol test --- library/compiler-builtins/ci/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index e938bc18c74..c3618132b67 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -60,7 +60,7 @@ esac stdout=$($PREFIX$NM -g --defined-only /target/${1}/debug/librustc_builtins.rlib) set +e -echo $stdout | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' +echo "$stdout" | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' if test $? = 0; then exit 1 -- cgit 1.4.1-3-g733a5 From d0c93bef1b3894390c9a02b9a98467d0c0a1ef55 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 3 Oct 2016 20:52:14 -0500 Subject: stop compiling compiler-rt implementations to avoid duplicate symbols --- library/compiler-builtins/build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a05a1a590ad..856a6bcfa33 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -160,8 +160,6 @@ fn main() { "paritysi2.c", "popcountdi2.c", "popcountsi2.c", - "powidf2.c", - "powisf2.c", "powixf2.c", "subdf3.c", "subsf3.c", -- cgit 1.4.1-3-g733a5 From fcc7ca7f80b3672e7c828ae99cd23005c18d3e30 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 3 Oct 2016 23:26:49 -0500 Subject: switch compiler-rt to rust-lang's fork this fork has been patched against the UB in floatsidf and floasisf closes #85 --- library/compiler-builtins/.gitmodules | 2 +- library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index fe501bba965..d86b9fa3414 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ [submodule "compiler-rt/compiler-rt-cdylib/compiler-rt"] path = compiler-rt/compiler-rt-cdylib/compiler-rt - url = https://github.com/llvm-mirror/compiler-rt + url = https://github.com/rust-lang/compiler-rt diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt index 515106ebc07..f03ba5a4e8b 160000 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt @@ -1 +1 @@ -Subproject commit 515106ebc07227b85336816ef77bc39506b8fd26 +Subproject commit f03ba5a4e8bf16dcf42dd742a4ce255c36321356 -- cgit 1.4.1-3-g733a5 From b56315e9a73fcb3e906b9fb4b9b024fe585f5500 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Oct 2016 21:34:16 -0500 Subject: switch to a current nightly --- library/compiler-builtins/.travis.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index e8931afad8d..511e69c5671 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,26 +1,20 @@ cache: cargo dist: trusty language: rust +rust: nightly services: docker sudo: required -rust: nightly matrix: include: - env: TARGET=aarch64-unknown-linux-gnu - env: TARGET=arm-unknown-linux-gnueabi - # FIXME(rust-lang/rust#36518) - rust: nightly-2016-09-21 - env: TARGET=arm-unknown-linux-gnueabihf - env: TARGET=armv7-unknown-linux-gnueabihf - env: TARGET=i586-unknown-linux-gnu - env: TARGET=i686-apple-darwin - # FIXME(rust-lang/rust#36793) - rust: nightly-2016-09-10 os: osx - env: TARGET=i686-unknown-linux-gnu - # FIXME(rust-lang/rust#36793) - rust: nightly-2016-09-10 - env: TARGET=mips-unknown-linux-gnu - env: TARGET=mipsel-unknown-linux-gnu - env: TARGET=powerpc-unknown-linux-gnu -- cgit 1.4.1-3-g733a5 From b2b40931c65dedb9c7552565a06b869ab5199243 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Oct 2016 22:13:55 -0500 Subject: switch back to old nightly for the arm-gnueabi target --- library/compiler-builtins/.travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 511e69c5671..a7bea0f912f 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -9,6 +9,8 @@ matrix: include: - env: TARGET=aarch64-unknown-linux-gnu - env: TARGET=arm-unknown-linux-gnueabi + # FIXME(rust-lang/rust#36518) + rust: nightly-2016-09-21 - env: TARGET=arm-unknown-linux-gnueabihf - env: TARGET=armv7-unknown-linux-gnueabihf - env: TARGET=i586-unknown-linux-gnu -- cgit 1.4.1-3-g733a5 From dbd5f05f31ea467f5519967ab432f362260a27b1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Oct 2016 23:20:09 -0500 Subject: drop the target files --- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 2 +- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 2 +- .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 2 +- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 2 +- library/compiler-builtins/ci/run.sh | 2 -- library/compiler-builtins/targets/thumbv6m-none-eabi.json | 12 ------------ library/compiler-builtins/targets/thumbv7em-none-eabi.json | 10 ---------- library/compiler-builtins/targets/thumbv7em-none-eabihf.json | 11 ----------- library/compiler-builtins/targets/thumbv7m-none-eabi.json | 10 ---------- 9 files changed, 4 insertions(+), 49 deletions(-) delete mode 100644 library/compiler-builtins/targets/thumbv6m-none-eabi.json delete mode 100644 library/compiler-builtins/targets/thumbv7em-none-eabi.json delete mode 100644 library/compiler-builtins/targets/thumbv7em-none-eabihf.json delete mode 100644 library/compiler-builtins/targets/thumbv7m-none-eabi.json diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index 52c969342cc..4a4556673f2 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv6m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 6f5b478e4ad..84cd8d7af07 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index 3cd8acae9a4..62ba1273122 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index 88adb2ddd6e..42baa3c9a19 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index c3618132b67..455bb2e400d 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -3,8 +3,6 @@ set -e # Test our implementation case $1 in thumb*) - export RUST_TARGET_PATH=/checkout/targets - xargo build --target $1 xargo build --target $1 --release ;; diff --git a/library/compiler-builtins/targets/thumbv6m-none-eabi.json b/library/compiler-builtins/targets/thumbv6m-none-eabi.json deleted file mode 100644 index 4b409cff049..00000000000 --- a/library/compiler-builtins/targets/thumbv6m-none-eabi.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "executables": true, - "features": "+strict-align", - "llvm-target": "thumbv6m-none-eabi", - "max-atomic-width": 0, - "os": "none", - "pre-link-args": ["-nostartfiles"], - "target-endian": "little", - "target-pointer-width": "32" -} diff --git a/library/compiler-builtins/targets/thumbv7em-none-eabi.json b/library/compiler-builtins/targets/thumbv7em-none-eabi.json deleted file mode 100644 index 2ac47c8f829..00000000000 --- a/library/compiler-builtins/targets/thumbv7em-none-eabi.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "executables": true, - "llvm-target": "thumbv7em-none-eabi", - "os": "none", - "pre-link-args": ["-nostartfiles"], - "target-endian": "little", - "target-pointer-width": "32" -} diff --git a/library/compiler-builtins/targets/thumbv7em-none-eabihf.json b/library/compiler-builtins/targets/thumbv7em-none-eabihf.json deleted file mode 100644 index 55ed3fd885d..00000000000 --- a/library/compiler-builtins/targets/thumbv7em-none-eabihf.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "executables": true, - "features": "+vfp4", - "llvm-target": "thumbv7em-none-eabihf", - "os": "none", - "pre-link-args": ["-nostartfiles"], - "target-endian": "little", - "target-pointer-width": "32" -} diff --git a/library/compiler-builtins/targets/thumbv7m-none-eabi.json b/library/compiler-builtins/targets/thumbv7m-none-eabi.json deleted file mode 100644 index 9635efa8d78..00000000000 --- a/library/compiler-builtins/targets/thumbv7m-none-eabi.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "executables": true, - "llvm-target": "thumbv7m-none-eabi", - "os": "none", - "pre-link-args": ["-nostartfiles"], - "target-endian": "little", - "target-pointer-width": "32" -} -- cgit 1.4.1-3-g733a5 From 92734e88ff42d1c3cd7599c5e82124ae5c2dba96 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Oct 2016 07:13:55 -0500 Subject: pass -nostartfiles to the linker --- library/compiler-builtins/.cargo/config | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 library/compiler-builtins/.cargo/config diff --git a/library/compiler-builtins/.cargo/config b/library/compiler-builtins/.cargo/config new file mode 100644 index 00000000000..b5389534582 --- /dev/null +++ b/library/compiler-builtins/.cargo/config @@ -0,0 +1,11 @@ +[target.thumbv6m-none-eabi] +rustflags = ["-C", "link-arg=-nostartfiles"] + +[target.thumbv7m-none-eabi] +rustflags = ["-C", "link-arg=-nostartfiles"] + +[target.thumbv7em-none-eabi] +rustflags = ["-C", "link-arg=-nostartfiles"] + +[target.thumbv7em-none-eabihf] +rustflags = ["-C", "link-arg=-nostartfiles"] \ No newline at end of file -- cgit 1.4.1-3-g733a5 From 3911f499902b22b15ccfae5d6a48efb7e25b4f84 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Oct 2016 23:01:58 -0500 Subject: run the full test suite on osx --- library/compiler-builtins/.travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index a7bea0f912f..6e159cc211d 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -46,8 +46,7 @@ script: sudo apt-get install -y qemu-user-static && sh ci/run-docker.sh $TARGET; else - cargo test --target $TARGET && - cargo test --target $TARGET --release; + sh ci/run.sh $TARGET; fi # Travis can't cache files that are not readable by "others" - chmod -R a+r $HOME/.cargo -- cgit 1.4.1-3-g733a5 From b0b7453ea3d2457af456e337df22d6e786270913 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Oct 2016 14:29:34 -0500 Subject: fix path to .rlib on OSX --- library/compiler-builtins/ci/run.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 455bb2e400d..7dc9be178a9 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -55,7 +55,13 @@ case $TRAVIS_OS_NAME in esac # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it -stdout=$($PREFIX$NM -g --defined-only /target/${1}/debug/librustc_builtins.rlib) +if [ $TRAVIS_OS_NAME = osx ]; then + path=target/${1}/debug/librustc_builtins.rlib +else + path=/target/${1}/debug/librustc_builtins.rlib +fi + +stdout=$($PREFIX$NM -g --defined-only $path) set +e echo "$stdout" | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' -- cgit 1.4.1-3-g733a5 From 9f4632c82971f757f17b53b969161b483c8dc46c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 17:30:05 -0500 Subject: panic! -> abort closes #79 --- library/compiler-builtins/src/int/udiv.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 3de18b4a0ca..8a9da9f41bc 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,4 +1,4 @@ -use core::mem; +use core::{intrinsics, mem}; use int::{Int, LargeInt}; /// Returns `n / d` @@ -7,7 +7,11 @@ use int::{Int, LargeInt}; pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { // Special cases if d == 0 { - panic!("Division by zero"); + // NOTE This should be unreachable in safe Rust because the program will panic before + // this intrinsic is called + unsafe { + intrinsics::abort() + } } if n == 0 { @@ -129,7 +133,11 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { // K X // --- // 0 0 - panic!("Division by zero"); + // NOTE This should be unreachable in safe Rust because the program will panic before + // this intrinsic is called + unsafe { + intrinsics::abort() + } } if n.low() == 0 { -- cgit 1.4.1-3-g733a5 From fbf1cc0b75b979d31f65fa1edbadbc3a9bae4562 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 23:10:30 -0500 Subject: check that we don't have any call to panic in our implementations --- library/compiler-builtins/Cargo.toml | 3 + library/compiler-builtins/ci/run.sh | 10 +++ library/compiler-builtins/src/bin/intrinsics.rs | 106 ++++++++++++++---------- 3 files changed, 75 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c198d9f3ccb..b3a5cf4d6b3 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -26,3 +26,6 @@ c = [] weak = ["rlibc/weak"] [workspace] + +[profile.release] +lto = true diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 7dc9be178a9..6a0906b8dfb 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -28,6 +28,16 @@ case $1 in ;; esac +# Verify that there are no undefined symbols to `panic` within our implementations +case $1 in + thumb*) + xargo build --features c --target $1 --bin intrinsics --release + ;; + *) + cargo build --features c --target $1 --bin intrinsics --release + ;; +esac + # Look out for duplicated symbols when we include the compiler-rt (C) implementation PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index 5e234855cf1..591765a477e 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -302,52 +302,70 @@ mod intrinsics { #[cfg(feature = "c")] fn run() { + use core::ptr; use intrinsics::*; - aeabi_d2f(2.); - aeabi_d2i(2.); - aeabi_d2l(2.); - aeabi_d2uiz(2.); - aeabi_d2ulz(2.); - aeabi_dadd(2., 3.); - aeabi_dcmpeq(2., 3.); - aeabi_dcmpgt(2., 3.); - aeabi_dcmplt(2., 3.); - aeabi_ddiv(2., 3.); - aeabi_dmul(2., 3.); - aeabi_dsub(2., 3.); - aeabi_f2d(2.); - aeabi_f2iz(2.); - aeabi_f2lz(2.); - aeabi_f2uiz(2.); - aeabi_f2ulz(2.); - aeabi_fadd(2., 3.); - aeabi_fcmpeq(2., 3.); - aeabi_fcmpgt(2., 3.); - aeabi_fcmplt(2., 3.); - aeabi_fdiv(2., 3.); - aeabi_fmul(2., 3.); - aeabi_fsub(2., 3.); - aeabi_i2d(2); - aeabi_i2f(2); - aeabi_idiv(2, 3); - aeabi_idivmod(2, 3); - aeabi_l2d(2); - aeabi_l2f(2); - aeabi_ldivmod(2, 3); - aeabi_lmul(2, 3); - aeabi_ui2d(2); - aeabi_ui2f(2); - aeabi_uidiv(2, 3); - aeabi_uidivmod(2, 3); - aeabi_ul2d(2); - aeabi_ul2f(2); - aeabi_uldivmod(2, 3); - moddi3(2, 3); - mulodi4(2, 3); - powidf2(2., 3); - powisf2(2., 3); - umoddi3(2, 3); + // We use volatile load/stores to prevent LLVM from optimizing away the intrinsics during LTO + macro_rules! arg { + () => { + unsafe { + ptr::read_volatile(0x0 as *const _) + } + } + } + + macro_rules! ret { + ($e:expr) => { + unsafe { + ptr::write_volatile(0x0 as *mut _, $e) + } + } + } + + ret!(aeabi_d2f(arg!())); + ret!(aeabi_d2i(arg!())); + ret!(aeabi_d2l(arg!())); + ret!(aeabi_d2uiz(arg!())); + ret!(aeabi_d2ulz(arg!())); + ret!(aeabi_dadd(arg!(), arg!())); + ret!(aeabi_dcmpeq(arg!(), arg!())); + ret!(aeabi_dcmpgt(arg!(), arg!())); + ret!(aeabi_dcmplt(arg!(), arg!())); + ret!(aeabi_ddiv(arg!(), arg!())); + ret!(aeabi_dmul(arg!(), arg!())); + ret!(aeabi_dsub(arg!(), arg!())); + ret!(aeabi_f2d(arg!())); + ret!(aeabi_f2iz(arg!())); + ret!(aeabi_f2lz(arg!())); + ret!(aeabi_f2uiz(arg!())); + ret!(aeabi_f2ulz(arg!())); + ret!(aeabi_fadd(arg!(), arg!())); + ret!(aeabi_fcmpeq(arg!(), arg!())); + ret!(aeabi_fcmpgt(arg!(), arg!())); + ret!(aeabi_fcmplt(arg!(), arg!())); + ret!(aeabi_fdiv(arg!(), arg!())); + ret!(aeabi_fmul(arg!(), arg!())); + ret!(aeabi_fsub(arg!(), arg!())); + ret!(aeabi_i2d(arg!())); + ret!(aeabi_i2f(arg!())); + ret!(aeabi_idiv(arg!(), arg!())); + ret!(aeabi_idivmod(arg!(), arg!())); + ret!(aeabi_l2d(arg!())); + ret!(aeabi_l2f(arg!())); + ret!(aeabi_ldivmod(arg!(), arg!())); + ret!(aeabi_lmul(arg!(), arg!())); + ret!(aeabi_ui2d(arg!())); + ret!(aeabi_ui2f(arg!())); + ret!(aeabi_uidiv(arg!(), arg!())); + ret!(aeabi_uidivmod(arg!(), arg!())); + ret!(aeabi_ul2d(arg!())); + ret!(aeabi_ul2f(arg!())); + ret!(aeabi_uldivmod(arg!(), arg!())); + ret!(moddi3(arg!(), arg!())); + ret!(mulodi4(arg!(), arg!())); + ret!(powidf2(arg!(), arg!())); + ret!(powisf2(arg!(), arg!())); + ret!(umoddi3(arg!(), arg!())); } #[cfg(all(feature = "c", not(thumb)))] -- cgit 1.4.1-3-g733a5 From c9e3feb5e30591cca73a7c2fa990e9d21f672f2c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Oct 2016 20:45:40 -0500 Subject: insert more `abort()` calls where division by zero may occur --- library/compiler-builtins/src/int/sdiv.rs | 14 ++++++++++++++ library/compiler-builtins/src/int/udiv.rs | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 37f5dd7df62..d60dda98999 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,3 +1,5 @@ +use core::intrinsics; + use int::Int; macro_rules! div { @@ -10,6 +12,12 @@ macro_rules! div { let a = (a ^ s_a) - s_a; let b = (b ^ s_b) - s_b; let s = s_a ^ s_b; + + if b == 0 { + unsafe { + intrinsics::abort() + } + } let r = (a as $uty) / (b as $uty); (r as $ty ^ s) - s } @@ -25,6 +33,12 @@ macro_rules! mod_ { let b = (b ^ s) - s; let s = a >> (<$ty>::bits() - 1); let a = (a ^ s) - s; + + if b == 0 { + unsafe { + intrinsics::abort() + } + } let r = (a as $uty) % (b as $uty); (r as $ty ^ s) - s } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 8a9da9f41bc..bb1546c3ac3 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -109,6 +109,14 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { // 0 X // --- // 0 X + // NOTE This should be unreachable in safe Rust because the program will panic before + // this intrinsic is called + if d.low() == 0 { + unsafe { + intrinsics::abort() + } + } + if let Some(rem) = rem { *rem = u64::from(n.low() % d.low()); } -- cgit 1.4.1-3-g733a5 From a02ecc8eeff47be8eb6641d558e0121ae5499fa6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Oct 2016 10:17:44 -0500 Subject: get profile.dev (-debug-assertions) + LTO working --- library/compiler-builtins/Cargo.toml | 6 +-- library/compiler-builtins/ci/run.sh | 6 ++- library/compiler-builtins/src/float/pow.rs | 5 ++- library/compiler-builtins/src/int/sdiv.rs | 14 +------ library/compiler-builtins/src/int/udiv.rs | 15 ++------ library/compiler-builtins/src/lib.rs | 60 ++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index b3a5cf4d6b3..eefb0b26663 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -25,7 +25,7 @@ compiler-rt = { path = "compiler-rt" } c = [] weak = ["rlibc/weak"] -[workspace] +[profile.dev] +debug-assertions = false -[profile.release] -lto = true +[workspace] diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 6a0906b8dfb..df27e35626f 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -31,10 +31,12 @@ esac # Verify that there are no undefined symbols to `panic` within our implementations case $1 in thumb*) - xargo build --features c --target $1 --bin intrinsics --release + xargo rustc --features c --target $1 --bin intrinsics -- -C lto + xargo rustc --features c --target $1 --bin intrinsics --release -- -C lto ;; *) - cargo build --features c --target $1 --bin intrinsics --release + cargo rustc --features c --target $1 --bin intrinsics -- -C lto + cargo rustc --features c --target $1 --bin intrinsics --release -- -C lto ;; esac diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 14b3b9ace6a..c02c76f7709 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,6 +1,7 @@ +use core::intrinsics; macro_rules! pow { - ($intrinsic:ident: $fty:ty, $ity:ty) => { + ($intrinsic:ident: $fty:ty, $ity:ident) => { /// Returns `a` raised to the power `b` #[cfg_attr(not(test), no_mangle)] pub extern "C" fn $intrinsic(a: $fty, b: $ity) -> $fty { @@ -11,7 +12,7 @@ macro_rules! pow { if (b & 1) != 0 { r *= a; } - b /= 2; + b = sdiv!($ity, b, 2); if b == 0 { break; } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index d60dda98999..6f96b800bd8 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -13,12 +13,7 @@ macro_rules! div { let b = (b ^ s_b) - s_b; let s = s_a ^ s_b; - if b == 0 { - unsafe { - intrinsics::abort() - } - } - let r = (a as $uty) / (b as $uty); + let r = udiv!((a as $uty), (b as $uty)); (r as $ty ^ s) - s } } @@ -34,12 +29,7 @@ macro_rules! mod_ { let s = a >> (<$ty>::bits() - 1); let a = (a ^ s) - s; - if b == 0 { - unsafe { - intrinsics::abort() - } - } - let r = (a as $uty) % (b as $uty); + let r = urem!((a as $uty), (b as $uty)); (r as $ty ^ s) - s } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index bb1546c3ac3..999dcec0552 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -109,18 +109,11 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { // 0 X // --- // 0 X - // NOTE This should be unreachable in safe Rust because the program will panic before - // this intrinsic is called - if d.low() == 0 { - unsafe { - intrinsics::abort() - } - } if let Some(rem) = rem { - *rem = u64::from(n.low() % d.low()); + *rem = u64::from(urem!(n.low(), d.low())); } - return u64::from(n.low() / d.low()); + return u64::from(udiv!(n.low(), d.low())); } else { // 0 X // --- @@ -153,9 +146,9 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { // --- // K 0 if let Some(rem) = rem { - *rem = u64::from_parts(0, n.high() % d.high()); + *rem = u64::from_parts(0, urem!(n.high(), d.high())); } - return u64::from(n.high() / d.high()); + return u64::from(udiv!(n.high(), d.high())); } // K K diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index acc56c98a69..351be02f78f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -13,6 +13,66 @@ // NOTE cfg(all(feature = "c", ..)) indicate that compiler-rt provides an arch optimized // implementation of that intrinsic and we'll prefer to use that +macro_rules! udiv { + ($a:expr, $b:expr) => { + unsafe { + let a = $a; + let b = $b; + + if b == 0 { + intrinsics::abort() + } else { + intrinsics::unchecked_div(a, b) + } + } + } +} + +macro_rules! sdiv { + ($sty:ident, $a:expr, $b:expr) => { + unsafe { + let a = $a; + let b = $b; + + if b == 0 || (b == -1 && a == $sty::min_value()) { + intrinsics::abort() + } else { + intrinsics::unchecked_div(a, b) + } + } + } +} + +macro_rules! urem { + ($a:expr, $b:expr) => { + unsafe { + let a = $a; + let b = $b; + + if b == 0 { + intrinsics::abort() + } else { + intrinsics::unchecked_rem(a, b) + } + } + } +} + +macro_rules! srem { + ($sty:ty, $a:expr, $b:expr) => { + unsafe { + let a = $a; + let b = $b; + + if b == 0 || (b == -1 && a == $sty::min_value()) { + intrinsics::abort() + } else { + intrinsics::unchecked_rem(a, b) + } + } + } +} + #[cfg(test)] #[macro_use] extern crate quickcheck; -- cgit 1.4.1-3-g733a5 From d05514cb20cef5a7886b33b0ae306e2e15911dfc Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Oct 2016 17:48:37 -0500 Subject: fix unsafe warnings --- library/compiler-builtins/Cargo.toml | 3 --- library/compiler-builtins/ci/run.sh | 5 +++-- library/compiler-builtins/src/bin/intrinsics.rs | 4 +--- library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/src/float/pow.rs | 2 -- library/compiler-builtins/src/int/sdiv.rs | 6 ++---- library/compiler-builtins/src/lib.rs | 17 +++++++++-------- 7 files changed, 16 insertions(+), 22 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index eefb0b26663..c198d9f3ccb 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -25,7 +25,4 @@ compiler-rt = { path = "compiler-rt" } c = [] weak = ["rlibc/weak"] -[profile.dev] -debug-assertions = false - [workspace] diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index df27e35626f..0ac9d683b3f 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -29,13 +29,14 @@ case $1 in esac # Verify that there are no undefined symbols to `panic` within our implementations +# TODO(#79) fix the undefined references problem for debug-assertions+lto case $1 in thumb*) - xargo rustc --features c --target $1 --bin intrinsics -- -C lto + RUSTFLAGS="-C debug-assertions=no" xargo rustc --features c --target $1 --bin intrinsics -- -C lto xargo rustc --features c --target $1 --bin intrinsics --release -- -C lto ;; *) - cargo rustc --features c --target $1 --bin intrinsics -- -C lto + RUSTFLAGS="-C debug-assertions=no" cargo rustc --features c --target $1 --bin intrinsics -- -C lto cargo rustc --features c --target $1 --bin intrinsics --release -- -C lto ;; esac diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index 591765a477e..ca01a9d0d85 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -308,9 +308,7 @@ fn run() { // We use volatile load/stores to prevent LLVM from optimizing away the intrinsics during LTO macro_rules! arg { () => { - unsafe { - ptr::read_volatile(0x0 as *const _) - } + ptr::read_volatile(0x0 as *const _) } } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 8bd574deb17..7dc084d4f79 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,4 +1,5 @@ use core::mem; +#[cfg(test)] use core::fmt; pub mod add; diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index c02c76f7709..838805f9492 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,5 +1,3 @@ -use core::intrinsics; - macro_rules! pow { ($intrinsic:ident: $fty:ty, $ity:ident) => { /// Returns `a` raised to the power `b` diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 6f96b800bd8..a1d119f3b1b 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,5 +1,3 @@ -use core::intrinsics; - use int::Int; macro_rules! div { @@ -13,7 +11,7 @@ macro_rules! div { let b = (b ^ s_b) - s_b; let s = s_a ^ s_b; - let r = udiv!((a as $uty), (b as $uty)); + let r = udiv!(a as $uty, b as $uty); (r as $ty ^ s) - s } } @@ -29,7 +27,7 @@ macro_rules! mod_ { let s = a >> (<$ty>::bits() - 1); let a = (a ^ s) - s; - let r = urem!((a as $uty), (b as $uty)); + let r = urem!(a as $uty, b as $uty); (r as $ty ^ s) - s } } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 351be02f78f..f5a12afd220 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -13,6 +13,7 @@ // NOTE cfg(all(feature = "c", ..)) indicate that compiler-rt provides an arch optimized // implementation of that intrinsic and we'll prefer to use that +// TODO(rust-lang/rust#37029) use e.g. checked_div(_).unwrap_or_else(|| abort()) macro_rules! udiv { ($a:expr, $b:expr) => { unsafe { @@ -20,9 +21,9 @@ macro_rules! udiv { let b = $b; if b == 0 { - intrinsics::abort() + ::core::intrinsics::abort() } else { - intrinsics::unchecked_div(a, b) + ::core::intrinsics::unchecked_div(a, b) } } } @@ -35,9 +36,9 @@ macro_rules! sdiv { let b = $b; if b == 0 || (b == -1 && a == $sty::min_value()) { - intrinsics::abort() + ::core::intrinsics::abort() } else { - intrinsics::unchecked_div(a, b) + ::core::intrinsics::unchecked_div(a, b) } } } @@ -50,9 +51,9 @@ macro_rules! urem { let b = $b; if b == 0 { - intrinsics::abort() + ::core::intrinsics::abort() } else { - intrinsics::unchecked_rem(a, b) + ::core::intrinsics::unchecked_rem(a, b) } } } @@ -65,9 +66,9 @@ macro_rules! srem { let b = $b; if b == 0 || (b == -1 && a == $sty::min_value()) { - intrinsics::abort() + ::core::intrinsics::abort() } else { - intrinsics::unchecked_rem(a, b) + ::core::intrinsics::unchecked_rem(a, b) } } } -- cgit 1.4.1-3-g733a5 From 2056d001cfd666a4fb1c5bd8d24df5d1d04b2c96 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Oct 2016 18:26:21 -0500 Subject: use test::black_box instead of ptr::*_volatile both prevent LLVM from optimizing away the intrinsics but the former doesn't produce an `intrinsics` binary that segfaults --- library/compiler-builtins/ci/run.sh | 2 +- library/compiler-builtins/src/bin/intrinsics.rs | 113 +++++++++++------------- 2 files changed, 53 insertions(+), 62 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 0ac9d683b3f..3846049ea13 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -32,7 +32,7 @@ esac # TODO(#79) fix the undefined references problem for debug-assertions+lto case $1 in thumb*) - RUSTFLAGS="-C debug-assertions=no" xargo rustc --features c --target $1 --bin intrinsics -- -C lto + RUSTFLAGS="-C debug-assertions=no -C link-arg=-nostartfiles" xargo rustc --features c --target $1 --bin intrinsics -- -C lto xargo rustc --features c --target $1 --bin intrinsics --release -- -C lto ;; *) diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index ca01a9d0d85..e11e415cc75 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -4,13 +4,14 @@ // to link due to the missing intrinsic (symbol). #![allow(unused_features)] +#![cfg_attr(thumb, no_main)] #![deny(dead_code)] +#![feature(asm)] #![feature(core_float)] #![feature(lang_items)] #![feature(libc)] #![feature(start)] #![no_std] -#![cfg_attr(thumb, no_main)] #[cfg(not(thumb))] extern crate libc; @@ -302,68 +303,58 @@ mod intrinsics { #[cfg(feature = "c")] fn run() { - use core::ptr; use intrinsics::*; - // We use volatile load/stores to prevent LLVM from optimizing away the intrinsics during LTO - macro_rules! arg { - () => { - ptr::read_volatile(0x0 as *const _) - } - } - - macro_rules! ret { - ($e:expr) => { - unsafe { - ptr::write_volatile(0x0 as *mut _, $e) - } - } - } - - ret!(aeabi_d2f(arg!())); - ret!(aeabi_d2i(arg!())); - ret!(aeabi_d2l(arg!())); - ret!(aeabi_d2uiz(arg!())); - ret!(aeabi_d2ulz(arg!())); - ret!(aeabi_dadd(arg!(), arg!())); - ret!(aeabi_dcmpeq(arg!(), arg!())); - ret!(aeabi_dcmpgt(arg!(), arg!())); - ret!(aeabi_dcmplt(arg!(), arg!())); - ret!(aeabi_ddiv(arg!(), arg!())); - ret!(aeabi_dmul(arg!(), arg!())); - ret!(aeabi_dsub(arg!(), arg!())); - ret!(aeabi_f2d(arg!())); - ret!(aeabi_f2iz(arg!())); - ret!(aeabi_f2lz(arg!())); - ret!(aeabi_f2uiz(arg!())); - ret!(aeabi_f2ulz(arg!())); - ret!(aeabi_fadd(arg!(), arg!())); - ret!(aeabi_fcmpeq(arg!(), arg!())); - ret!(aeabi_fcmpgt(arg!(), arg!())); - ret!(aeabi_fcmplt(arg!(), arg!())); - ret!(aeabi_fdiv(arg!(), arg!())); - ret!(aeabi_fmul(arg!(), arg!())); - ret!(aeabi_fsub(arg!(), arg!())); - ret!(aeabi_i2d(arg!())); - ret!(aeabi_i2f(arg!())); - ret!(aeabi_idiv(arg!(), arg!())); - ret!(aeabi_idivmod(arg!(), arg!())); - ret!(aeabi_l2d(arg!())); - ret!(aeabi_l2f(arg!())); - ret!(aeabi_ldivmod(arg!(), arg!())); - ret!(aeabi_lmul(arg!(), arg!())); - ret!(aeabi_ui2d(arg!())); - ret!(aeabi_ui2f(arg!())); - ret!(aeabi_uidiv(arg!(), arg!())); - ret!(aeabi_uidivmod(arg!(), arg!())); - ret!(aeabi_ul2d(arg!())); - ret!(aeabi_ul2f(arg!())); - ret!(aeabi_uldivmod(arg!(), arg!())); - ret!(moddi3(arg!(), arg!())); - ret!(mulodi4(arg!(), arg!())); - ret!(powidf2(arg!(), arg!())); - ret!(powisf2(arg!(), arg!())); - ret!(umoddi3(arg!(), arg!())); + // A copy of "test::black_box". Used to prevent LLVM from optimizing away the intrinsics during LTO + fn bb(dummy: T) -> T { + unsafe { asm!("" : : "r"(&dummy)) } + dummy + } + + bb(aeabi_d2f(bb(2.))); + bb(aeabi_d2i(bb(2.))); + bb(aeabi_d2l(bb(2.))); + bb(aeabi_d2uiz(bb(2.))); + bb(aeabi_d2ulz(bb(2.))); + bb(aeabi_dadd(bb(2.), bb(3.))); + bb(aeabi_dcmpeq(bb(2.), bb(3.))); + bb(aeabi_dcmpgt(bb(2.), bb(3.))); + bb(aeabi_dcmplt(bb(2.), bb(3.))); + bb(aeabi_ddiv(bb(2.), bb(3.))); + bb(aeabi_dmul(bb(2.), bb(3.))); + bb(aeabi_dsub(bb(2.), bb(3.))); + bb(aeabi_f2d(bb(2.))); + bb(aeabi_f2iz(bb(2.))); + bb(aeabi_f2lz(bb(2.))); + bb(aeabi_f2uiz(bb(2.))); + bb(aeabi_f2ulz(bb(2.))); + bb(aeabi_fadd(bb(2.), bb(3.))); + bb(aeabi_fcmpeq(bb(2.), bb(3.))); + bb(aeabi_fcmpgt(bb(2.), bb(3.))); + bb(aeabi_fcmplt(bb(2.), bb(3.))); + bb(aeabi_fdiv(bb(2.), bb(3.))); + bb(aeabi_fmul(bb(2.), bb(3.))); + bb(aeabi_fsub(bb(2.), bb(3.))); + bb(aeabi_i2d(bb(2))); + bb(aeabi_i2f(bb(2))); + bb(aeabi_idiv(bb(2), bb(3))); + bb(aeabi_idivmod(bb(2), bb(3))); + bb(aeabi_l2d(bb(2))); + bb(aeabi_l2f(bb(2))); + bb(aeabi_ldivmod(bb(2), bb(3))); + bb(aeabi_lmul(bb(2), bb(3))); + bb(aeabi_ui2d(bb(2))); + bb(aeabi_ui2f(bb(2))); + bb(aeabi_uidiv(bb(2), bb(3))); + bb(aeabi_uidivmod(bb(2), bb(3))); + bb(aeabi_ul2d(bb(2))); + bb(aeabi_ul2f(bb(2))); + bb(aeabi_uldivmod(bb(2), bb(3))); + bb(moddi3(bb(2), bb(3))); + bb(mulodi4(bb(2), bb(3))); + bb(powidf2(bb(2.), bb(3))); + bb(powisf2(bb(2.), bb(3))); + bb(umoddi3(bb(2), bb(3))); } #[cfg(all(feature = "c", not(thumb)))] -- cgit 1.4.1-3-g733a5 From 8692e64db9d862e48e8c1b0d4efc76aa256168f6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Oct 2016 16:18:18 -0500 Subject: add a rustbuild cargo feature for integration with rust-lang/rust --- library/compiler-builtins/build.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 046085a9d07..c0fdb52ec8a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -407,8 +407,15 @@ fn main() { sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); } + let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { + Path::new("../../libcompiler_builtins") + } else { + Path::new(".") + }; + + let src_dir = root.join("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins"); for src in sources.map.values() { - let src = Path::new("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins").join(src); + let src = src_dir.join(src); cfg.file(&src); println!("cargo:rerun-if-changed={}", src.display()); } -- cgit 1.4.1-3-g733a5 From 5f5c973cbe7fd642172081a10e12174235535053 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Oct 2016 16:43:38 -0500 Subject: set crate_name and crate_type in src/lib.rs --- library/compiler-builtins/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index f5a12afd220..6eaf2b1e798 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,3 +1,5 @@ +#![crate_name = "compiler_builtins"] +#![crate_type = "rlib"] #![feature(asm)] #![feature(core_intrinsics)] #![feature(linkage)] -- cgit 1.4.1-3-g733a5 From 622a760d91db5f41fe381757d466d2c88c582b8b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Oct 2016 16:45:24 -0500 Subject: add the compiler_builtins feature to src/lib.rs --- library/compiler-builtins/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 6eaf2b1e798..3adddd5cd17 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,13 +1,13 @@ +#![cfg_attr(not(test), no_std)] +#![compiler_builtins] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] #![feature(asm)] +#![feature(compiler_builtins)] #![feature(core_intrinsics)] #![feature(linkage)] #![feature(naked_functions)] -#![cfg_attr(not(test), no_std)] #![no_builtins] -// TODO(rust-lang/rust#35021) uncomment when that PR lands -// #![feature(rustc_builtins)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. -- cgit 1.4.1-3-g733a5 From 14c32a0369d72fb2d52832610b59b1df740e728a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Oct 2016 19:05:21 -0500 Subject: rename to compiler_builtins, add rust-lang/rust-ish crate attributes --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/src/lib.rs | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c198d9f3ccb..6455a6ef3ab 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] build = "build.rs" -name = "rustc_builtins" +name = "compiler_builtins" version = "0.1.0" [build-dependencies] diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3adddd5cd17..bcc56e53584 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,13 +1,23 @@ +#![cfg_attr(not(stage0), deny(warnings))] #![cfg_attr(not(test), no_std)] #![compiler_builtins] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/", + html_playground_url = "https://play.rust-lang.org/", + test(attr(deny(warnings))))] #![feature(asm)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] #![feature(linkage)] #![feature(naked_functions)] +#![feature(staged_api)] #![no_builtins] +#![unstable(feature = "compiler_builtins", + reason = "Compiler builtins. Will never become stable.", + issue = "0")] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. -- cgit 1.4.1-3-g733a5 From 3fe4f1c687afb8d1195124e64caa09ea325f53f0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Oct 2016 19:45:34 -0500 Subject: fix warnings --- library/compiler-builtins/ci/run.sh | 4 +++- library/compiler-builtins/src/bin/intrinsics.rs | 3 ++- library/compiler-builtins/src/int/sdiv.rs | 7 ++++++- library/compiler-builtins/src/int/udiv.rs | 16 ++++++++++++++-- library/compiler-builtins/src/lib.rs | 4 ++-- 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 3846049ea13..90441bdc934 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,4 +1,6 @@ -set -e +set -ex + +export RUST_BACKTRACE=1 # Test our implementation case $1 in diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index e11e415cc75..db6d7d93d64 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -7,6 +7,7 @@ #![cfg_attr(thumb, no_main)] #![deny(dead_code)] #![feature(asm)] +#![feature(compiler_builtins_lib)] #![feature(core_float)] #![feature(lang_items)] #![feature(libc)] @@ -15,7 +16,7 @@ #[cfg(not(thumb))] extern crate libc; -extern crate rustc_builtins; +extern crate compiler_builtins; // NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even // compiler-rt provides a C/assembly implementation. diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index a1d119f3b1b..b54132290af 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -43,7 +43,12 @@ macro_rules! divmod { fn $div(a: $ty, b: $ty) -> $ty; } - let r = unsafe { $div(a, b) }; + let r = match () { + #[cfg(not(all(feature = "c", any(target_arch = "x86"))))] + () => $div(a, b), + #[cfg(all(feature = "c", any(target_arch = "x86")))] + () => unsafe { $div(a, b) }, + }; *rem = a - (r * b); r } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 999dcec0552..4a14d3ce99c 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -65,7 +65,14 @@ pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { fn __udivsi3(n: u32, d: u32) -> u32; } - n - unsafe { __udivsi3(n, d) * d } + let q = match () { + #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] + () => unsafe { __udivsi3(n, d) }, + #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] + () => __udivsi3(n, d), + }; + + n - q * d } /// Returns `n / d` and sets `*rem = n % d` @@ -77,7 +84,12 @@ pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { fn __udivsi3(n: u32, d: u32) -> u32; } - let q = unsafe { __udivsi3(n, d) }; + let q = match () { + #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] + () => unsafe { __udivsi3(n, d) }, + #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] + () => __udivsi3(n, d), + }; if let Some(rem) = rem { *rem = n - (q * d); } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index bcc56e53584..0efb20b5dec 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,6 @@ #![cfg_attr(not(stage0), deny(warnings))] #![cfg_attr(not(test), no_std)] -#![compiler_builtins] +#![cfg_attr(rustbuild, compiler_builtins)] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", @@ -15,7 +15,7 @@ #![feature(naked_functions)] #![feature(staged_api)] #![no_builtins] -#![unstable(feature = "compiler_builtins", +#![unstable(feature = "compiler_builtins_lib", reason = "Compiler builtins. Will never become stable.", issue = "0")] -- cgit 1.4.1-3-g733a5 From 77b5865b0471e175ce60feb15eec22c2f4594b02 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Oct 2016 20:21:11 -0500 Subject: fix more warnings --- library/compiler-builtins/src/int/mul.rs | 4 +++- library/compiler-builtins/src/int/shift.rs | 1 + library/compiler-builtins/src/int/udiv.rs | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index e04e86ccb80..db9f0d9e0c6 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,4 +1,6 @@ -use int::{Int, LargeInt}; +#[cfg(not(all(feature = "c", target_arch = "x86")))] +use int::LargeInt; +use int::Int; macro_rules! mul { ($intrinsic:ident: $ty:ty) => { diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 995f8d60925..9338f07ce7e 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,3 +1,4 @@ +#[cfg(not(all(feature = "c", target_arch = "x86")))] use int::{Int, LargeInt}; macro_rules! ashl { diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 4a14d3ce99c..b60c8751784 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,4 +1,4 @@ -use core::{intrinsics, mem}; +use core::intrinsics; use int::{Int, LargeInt}; /// Returns `n / d` @@ -107,6 +107,8 @@ pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { #[cfg(not(all(feature = "c", target_arch = "x86")))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 { + use core::mem; + let mut rem = unsafe { mem::uninitialized() }; __udivmoddi4(a, b, Some(&mut rem)); rem -- cgit 1.4.1-3-g733a5 From fcb19597cfd266ede3e43bcee1c4f74169f9031e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Oct 2016 20:52:49 -0500 Subject: ci/run.sh: remove debug stuff --- library/compiler-builtins/ci/run.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 90441bdc934..3846049ea13 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,6 +1,4 @@ -set -ex - -export RUST_BACKTRACE=1 +set -e # Test our implementation case $1 in -- cgit 1.4.1-3-g733a5 From 7928431aea83ff9d43d9e8bfaea70c9734b7fbad Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 12 Oct 2016 17:38:14 +0000 Subject: Correct the license to that of upstream compiler-rt As this is a derivative work we must maintain the same license terms. --- library/compiler-builtins/LICENSE-APACHE | 201 ------------------------------- library/compiler-builtins/LICENSE-MIT | 25 ---- library/compiler-builtins/LICENSE.TXT | 91 ++++++++++++++ library/compiler-builtins/README.md | 11 +- 4 files changed, 96 insertions(+), 232 deletions(-) delete mode 100644 library/compiler-builtins/LICENSE-APACHE delete mode 100644 library/compiler-builtins/LICENSE-MIT create mode 100644 library/compiler-builtins/LICENSE.TXT diff --git a/library/compiler-builtins/LICENSE-APACHE b/library/compiler-builtins/LICENSE-APACHE deleted file mode 100644 index 16fe87b06e8..00000000000 --- a/library/compiler-builtins/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/compiler-builtins/LICENSE-MIT b/library/compiler-builtins/LICENSE-MIT deleted file mode 100644 index a43445e6cd1..00000000000 --- a/library/compiler-builtins/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2016 Jorge Aparicio - -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/compiler-builtins/LICENSE.TXT b/library/compiler-builtins/LICENSE.TXT new file mode 100644 index 00000000000..92bbe113ab2 --- /dev/null +++ b/library/compiler-builtins/LICENSE.TXT @@ -0,0 +1,91 @@ +============================================================================== +compiler-builtins License +============================================================================== + +The compiler-builtins crate is dual licensed under both the University of +Illinois "BSD-Like" license and the MIT license. As a user of this code you may +choose to use it under either license. As a contributor, you agree to allow +your code to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +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 +CONTRIBUTORS 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 WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT + +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. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 20b153d7dc1..0a5b33a4a7c 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -371,13 +371,12 @@ Floating-point implementations of builtins that are only called from soft-float ## License -Licensed under either of +The compiler-builtins crate is dual licensed under both the University of +Illinois "BSD-Like" license and the MIT license. As a user of this code you may +choose to use it under either license. As a contributor, you agree to allow +your code to be used under both. -- 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. +Full text of the relevant licenses is in LICENSE.TXT. ### Contribution -- cgit 1.4.1-3-g733a5 From b4f4913e6baa5652d950143c5f716bafc36ce38b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 13 Oct 2016 20:50:30 -0500 Subject: README: remove the Contribution sub-section which still referred to the Apache-2 license and is now deprecated by the updated License section cc @brson --- library/compiler-builtins/README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 0a5b33a4a7c..aab37939b81 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -377,9 +377,3 @@ choose to use it under either license. As a contributor, you agree to allow your code to be used under both. Full text of the relevant licenses is in LICENSE.TXT. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the -work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any -additional terms or conditions. -- cgit 1.4.1-3-g733a5 From ab4d5e62fbc6ed60074918be045d0fba727f5f30 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 14 Oct 2016 09:59:21 -0500 Subject: fix the powerpc64le target by selecting a CPU that's compatible with the instructions that `rustc` generates --- .../ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile | 1 + library/compiler-builtins/ci/run.sh | 10 ++-------- library/compiler-builtins/src/bin/intrinsics.rs | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile index bd0a182a886..ba1b3c287bf 100644 --- a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -7,5 +7,6 @@ RUN apt-get install -y --no-install-recommends \ qemu-system-ppc ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ + QEMU_CPU=POWER8 \ QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 3846049ea13..0159e238913 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -6,12 +6,6 @@ case $1 in xargo build --target $1 xargo build --target $1 --release ;; - # QEMU crashes even when executing the simplest cross compiled C program: - # `int main() { return 0; }` - powerpc64le-unknown-linux-gnu) - cargo test --target $1 --no-run - cargo test --target $1 --no-run --release - ;; *) cargo test --target $1 cargo test --target $1 --release @@ -69,9 +63,9 @@ esac # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it if [ $TRAVIS_OS_NAME = osx ]; then - path=target/${1}/debug/librustc_builtins.rlib + path=target/${1}/debug/libcompiler_builtins.rlib else - path=/target/${1}/debug/librustc_builtins.rlib + path=/target/${1}/debug/libcompiler_builtins.rlib fi stdout=$($PREFIX$NM -g --defined-only $path) diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index db6d7d93d64..5a4a34503cc 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -1,5 +1,5 @@ // By compiling this file we check that all the intrinsics we care about continue to be provided by -// the `rustc_builtins` crate regardless of the changes we make to it. If we, by mistake, stop +// the `compiler_builtins` crate regardless of the changes we make to it. If we, by mistake, stop // compiling a C implementation and forget to implement that intrinsic in Rust, this file will fail // to link due to the missing intrinsic (symbol). -- cgit 1.4.1-3-g733a5 From 8ab8bd78899706af5c97cae2a31f2f12aa0844bf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 14 Oct 2016 11:44:45 -0700 Subject: Update webhook url --- library/compiler-builtins/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 6e159cc211d..96b11376377 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -59,4 +59,4 @@ branches: notifications: email: on_success: never - webhooks: https://homu.herokuapp.com/travis + webhooks: https://buildbot.rust-lang.org/homu/travis -- cgit 1.4.1-3-g733a5 From 7f70040462b7a9c491d21e8911c65d41600dca79 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 14 Oct 2016 11:58:02 -0700 Subject: Update CI configs * Run on the master branch (to get previews) * Pass --target on AppVeyor (oops) * Use the current nightly for arm (I think that bug is fixed) --- library/compiler-builtins/.travis.yml | 7 ------- library/compiler-builtins/appveyor.yml | 13 ++++--------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 6e159cc211d..e53b678fb1e 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -9,8 +9,6 @@ matrix: include: - env: TARGET=aarch64-unknown-linux-gnu - env: TARGET=arm-unknown-linux-gnueabi - # FIXME(rust-lang/rust#36518) - rust: nightly-2016-09-21 - env: TARGET=arm-unknown-linux-gnueabihf - env: TARGET=armv7-unknown-linux-gnueabihf - env: TARGET=i586-unknown-linux-gnu @@ -51,11 +49,6 @@ script: # Travis can't cache files that are not readable by "others" - chmod -R a+r $HOME/.cargo -branches: - only: - - auto - - try - notifications: email: on_success: never diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 52afc97ef5e..f27347c338d 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -14,12 +14,7 @@ install: build: false test_script: - - cargo build - - cargo build --release - - cargo test - - cargo test --release - -branches: - only: - - auto - - try + - cargo build --target %TARGET% + - cargo build --release --target %TARGET% + - cargo test --target %TARGET% + - cargo test --release --target %TARGET% -- cgit 1.4.1-3-g733a5 From b92c6caa068f2862af471dfe8fcb7f8053054ee7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 14 Oct 2016 15:45:25 -0700 Subject: More small updates to the README --- library/compiler-builtins/README.md | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index aab37939b81..1eee9eb0d69 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,11 +1,8 @@ -[![AppVeyor][appveyor]](https://ci.appveyor.com/project/japaric/rustc-builtins) -[![Travis][travis]](https://travis-ci.org/japaric/rustc-builtins) - -[appveyor]: https://ci.appveyor.com/api/projects/status/mofi55r3px9pv3o7?svg=true -[travis]: https://travis-ci.org/japaric/rustc-builtins.svg?branch=master - # `rustc-builtins` +[![Build status](https://ci.appveyor.com/api/projects/status/eusnjps5ui3d305p?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/compiler-builtins) +[![Build Status](https://travis-ci.org/rust-lang-nursery/compiler-builtins.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/compiler-builtins) + > [WIP] Porting `compiler-rt` intrinsics to Rust See [rust-lang/rust#35437][0]. @@ -23,15 +20,26 @@ this crate ends up, as long as it's there): ``` toml [dependencies] -rustc-builtins = { git = "https://github.com/japaric/rustc-builtins" } +compiler-builtins = { git = "https://github.com/rustc-lang-nursery/compiler-builtins" } ``` -If you still get an "undefined reference to $INTRINSIC" error after that change, that means that we -haven't ported `$INTRINSIC` to Rust yet! Please open [an issue] with the name of the intrinsic and -the LLVM triple (e.g. thumbv7m-none-eabi) of the target you are using. That way we can prioritize +If you still get an "undefined reference to $INTRINSIC" error after that change, +that means that we haven't ported `$INTRINSIC` to Rust yet! Please open [an +issue] with the name of the intrinsic and the LLVM triple (e.g. +thumbv7m-none-eabi) of the target you are using. That way we can prioritize porting that particular intrinsic. -[an issue]: https://github.com/japaric/rustc-builtins/issues +If you've got a C compiler available for your target then while we implement +this intrinsic you can temporarily enable a fallback to the actual compiler-rt +implementation as well for unimplemented intrinsics: + +```toml +[dependencies.compiler-builtins] +git = "https://github.com/rustc-lang-nursery/compiler-builtins" +features = ["c"] +``` + +[an issue]: https://github.com/rust-lang-nursery/compiler-builtins/issues ## Contributing @@ -45,7 +53,7 @@ porting that particular intrinsic. [1]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/test/builtins/Unit [2]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/lib/builtins -[3]: https://travis-ci.org/japaric/rustc-builtins +[3]: https://travis-ci.org/rust-lang-nursery/compiler-builtins ### Porting Reminders -- cgit 1.4.1-3-g733a5 From 04639c2f5471ebd8707224eb132defda5e65ee58 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 14 Oct 2016 19:59:00 -0500 Subject: update the title as well --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 1eee9eb0d69..f2b97ed5e3e 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,4 +1,4 @@ -# `rustc-builtins` +# `compiler-builtins` [![Build status](https://ci.appveyor.com/api/projects/status/eusnjps5ui3d305p?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/compiler-builtins) [![Build Status](https://travis-ci.org/rust-lang-nursery/compiler-builtins.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/compiler-builtins) -- cgit 1.4.1-3-g733a5 From 533c78afaf358e7f276ca0991b2529f0d44f905f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 14 Oct 2016 20:26:59 -0500 Subject: test the mips64 targets --- library/compiler-builtins/.travis.yml | 2 ++ .../ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile | 14 ++++++++++++++ .../ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile | 13 +++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 6e159cc211d..776c5269707 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -18,6 +18,8 @@ matrix: os: osx - env: TARGET=i686-unknown-linux-gnu - env: TARGET=mips-unknown-linux-gnu + - env: TARGET=mips64-unknown-linux-gnuabi64 + - env: TARGET=mips64el-unknown-linux-gnuabi64 - env: TARGET=mipsel-unknown-linux-gnu - env: TARGET=powerpc-unknown-linux-gnu - env: TARGET=powerpc64-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile new file mode 100644 index 00000000000..92b1d93b8fd --- /dev/null +++ b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -0,0 +1,14 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + ca-certificates \ + gcc \ + gcc-mips64-linux-gnuabi64 \ + libc6-dev \ + libc6-dev-mips64-cross \ + qemu-user-static +RUN apt-get install -y --no-install-recommends qemu-system-mips +ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ + CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ + QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile new file mode 100644 index 00000000000..adba7783fa0 --- /dev/null +++ b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + ca-certificates \ + gcc \ + gcc-mips64el-linux-gnuabi64 \ + libc6-dev \ + libc6-dev-mips64el-cross \ + qemu-user-static +ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER=mips64el-linux-gnuabi64-gcc \ + CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \ + QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ + RUST_TEST_THREADS=1 -- cgit 1.4.1-3-g733a5 From f511f6775224b09eccd50553c5ae83aa2e2b3cb2 Mon Sep 17 00:00:00 2001 From: Phaiax Date: Sat, 15 Oct 2016 19:18:12 +0200 Subject: Fix url in readme --- library/compiler-builtins/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index f2b97ed5e3e..54e8b618596 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -20,7 +20,7 @@ this crate ends up, as long as it's there): ``` toml [dependencies] -compiler-builtins = { git = "https://github.com/rustc-lang-nursery/compiler-builtins" } +compiler_builtins = { git = "https://github.com/rust-lang-nursery/compiler-builtins" } ``` If you still get an "undefined reference to $INTRINSIC" error after that change, @@ -34,8 +34,8 @@ this intrinsic you can temporarily enable a fallback to the actual compiler-rt implementation as well for unimplemented intrinsics: ```toml -[dependencies.compiler-builtins] -git = "https://github.com/rustc-lang-nursery/compiler-builtins" +[dependencies.compiler_builtins] +git = "https://github.com/rust-lang-nursery/compiler-builtins" features = ["c"] ``` -- cgit 1.4.1-3-g733a5 From 7ecc55fbefac06bea7fe2af37533f73e8bd8a381 Mon Sep 17 00:00:00 2001 From: Phaiax Date: Sat, 15 Oct 2016 20:35:38 +0200 Subject: Update gcc-rs dependency to 0.3.36 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6455a6ef3ab..58ce4513ca5 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,8 +5,8 @@ name = "compiler_builtins" version = "0.1.0" [build-dependencies] -gcc = "0.3.35" rustc-cfg = "0.2.0" +gcc = "0.3.36" [dependencies] diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml index 3c64d23d37e..ec9c6af1831 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml @@ -8,4 +8,5 @@ build = "build.rs" crate-type = ["cdylib"] [build-dependencies] -gcc = "0.3" +gcc = "0.3.36" + -- cgit 1.4.1-3-g733a5 From 53c19053e406a8462b9ecd276d8af18b7d976c5f Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Sun, 16 Oct 2016 13:53:31 +0200 Subject: Fix a few clippy warnings --- library/compiler-builtins/src/float/add.rs | 3 +- library/compiler-builtins/src/int/udiv.rs | 72 +++++++++++++++--------------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 243c391b565..92ba8216fbd 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -175,7 +175,8 @@ macro_rules! add { // correct result in that case. if round_guard_sticky > 0x4 { result += one; } if round_guard_sticky == 0x4 { result += result & one; } - return (<$ty>::from_repr(result.0)); + + <$ty>::from_repr(result.0) } } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index b60c8751784..3c5629e1a51 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -191,49 +191,47 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { // 1 <= sr <= u32::bits() - 1 q = n << (u64::bits() - sr); r = n >> sr; - } else { - if d.high() == 0 { - // K X - // --- - // 0 K - if d.low().is_power_of_two() { - if let Some(rem) = rem { - *rem = u64::from(n.low() & (d.low() - 1)); - } - - if d.low() == 1 { - return n; - } else { - let sr = d.low().trailing_zeros(); - return n >> sr; - }; + } else if d.high() == 0 { + // K X + // --- + // 0 K + if d.low().is_power_of_two() { + if let Some(rem) = rem { + *rem = u64::from(n.low() & (d.low() - 1)); } - sr = 1 + u32::bits() + d.low().leading_zeros() - n.high().leading_zeros(); + if d.low() == 1 { + return n; + } else { + let sr = d.low().trailing_zeros(); + return n >> sr; + }; + } - // 2 <= sr <= u64::bits() - 1 - q = n << (u64::bits() - sr); - r = n >> sr; - } else { - // K X - // --- - // K K - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > u32::bits() - 1 { - if let Some(rem) = rem { - *rem = n; - } - return 0; - } + sr = 1 + u32::bits() + d.low().leading_zeros() - n.high().leading_zeros(); - sr += 1; + // 2 <= sr <= u64::bits() - 1 + q = n << (u64::bits() - sr); + r = n >> sr; + } else { + // K X + // --- + // K K + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - // 1 <= sr <= u32::bits() - q = n << (u64::bits() - sr); - r = n >> sr; + // D > N + if sr > u32::bits() - 1 { + if let Some(rem) = rem { + *rem = n; + } + return 0; } + + sr += 1; + + // 1 <= sr <= u32::bits() + q = n << (u64::bits() - sr); + r = n >> sr; } // Not a special case -- cgit 1.4.1-3-g733a5 From 1074677eb0a3ebb4273d811a199ca66bdb944831 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 19 Oct 2016 11:19:06 -0500 Subject: mention that 'extern crate compiler_builtins' must be used in some crate that's part of the dependency graph of the crate one's building. --- library/compiler-builtins/README.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 54e8b618596..d66d88828bf 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -11,18 +11,26 @@ See [rust-lang/rust#35437][0]. ## When and how to use this crate? -If you are working with a target that doesn't have binary releases of std available via rustup (this -probably means you are building the core crate yourself) and need compiler-rt intrinsics (i.e. you -are probably getting linker errors when building an executable: `undefined reference to -__aeabi_memcpy`), you can use this crate to get those intrinsics and solve the linker errors. To do -that, simply add this crate as a Cargo dependency (it doesn't matter where in the dependency graph -this crate ends up, as long as it's there): +If you are working with a target that doesn't have binary releases of std +available via rustup (this probably means you are building the core crate +yourself) and need compiler-rt intrinsics (i.e. you are probably getting linker +errors when building an executable: `undefined reference to __aeabi_memcpy`), +you can use this crate to get those intrinsics and solve the linker errors. To +do that, add this crate somewhere in the dependency graph of the crate you are +building: ``` toml +# Cargo.toml [dependencies] compiler_builtins = { git = "https://github.com/rust-lang-nursery/compiler-builtins" } ``` +``` rust +extern crate compiler_builtins; + +// ... +``` + If you still get an "undefined reference to $INTRINSIC" error after that change, that means that we haven't ported `$INTRINSIC` to Rust yet! Please open [an issue] with the name of the intrinsic and the LLVM triple (e.g. -- cgit 1.4.1-3-g733a5 From 9b4553de1c2b3091240c39d4f46c669a07f8b38c Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Mon, 3 Oct 2016 11:58:16 -0500 Subject: Add float quickcheck --- library/compiler-builtins/build.rs | 4 +- library/compiler-builtins/src/float/add.rs | 113 ++++------------------------- library/compiler-builtins/src/float/mod.rs | 78 ++++++++++++-------- library/compiler-builtins/src/float/pow.rs | 17 ++--- library/compiler-builtins/src/qc.rs | 57 +++++++++++++++ 5 files changed, 127 insertions(+), 142 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index c0fdb52ec8a..9f7a8fdedb8 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -424,8 +424,8 @@ fn main() { } // To filter away some flaky test (see src/float/add.rs for details) - if llvm_target.last() == Some(&"gnueabihf") { - println!("cargo:rustc-cfg=gnueabihf") + if llvm_target.last().unwrap().contains("gnueabi") { + println!("cargo:rustc-cfg=gnueabi") } // To compile intrinsics.rs for thumb targets, where there is no libc diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 92ba8216fbd..814b99b26c8 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -184,114 +184,27 @@ macro_rules! add { add!(__addsf3: f32); add!(__adddf3: f64); -#[cfg(test)] +// NOTE(cfg) for some reason, on arm-unknown-linux-gnueabi*, our implementation doesn't +// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll +// just avoid testing against them on those targets. Do note that our implementation gives the +// correct answer; gcc_s and compiler-rt are incorrect in this case. +#[cfg(all(test, not(gnueabi)))] mod tests { use core::{f32, f64}; + use qc::{F32, F64}; - use float::{Float, FRepr}; - use qc::{U32, U64}; - - // TODO: Add F32/F64 to qc so that they print the right values (at the very least) check! { fn __addsf3(f: extern fn(f32, f32) -> f32, - a: U32, - b: U32) - -> Option > { - let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); - Some(FRepr(f(a, b))) + a: F32, + b: F32) + -> Option { + Some(F32(f(a.0, b.0))) } fn __adddf3(f: extern fn(f64, f64) -> f64, - a: U64, - b: U64) -> Option > { - let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); - Some(FRepr(f(a, b))) + a: F64, + b: F64) -> Option { + Some(F64(f(a.0, b.0))) } } - - // More tests for special float values - - #[test] - fn test_float_tiny_plus_tiny() { - let tiny = f32::from_repr(1); - let r = super::__addsf3(tiny, tiny); - assert!(r.eq_repr(tiny + tiny)); - } - - #[test] - fn test_double_tiny_plus_tiny() { - let tiny = f64::from_repr(1); - let r = super::__adddf3(tiny, tiny); - assert!(r.eq_repr(tiny + tiny)); - } - - #[test] - fn test_float_small_plus_small() { - let a = f32::from_repr(327); - let b = f32::from_repr(256); - let r = super::__addsf3(a, b); - assert!(r.eq_repr(a + b)); - } - - #[test] - fn test_double_small_plus_small() { - let a = f64::from_repr(327); - let b = f64::from_repr(256); - let r = super::__adddf3(a, b); - assert!(r.eq_repr(a + b)); - } - - #[test] - fn test_float_one_plus_one() { - let r = super::__addsf3(1f32, 1f32); - assert!(r.eq_repr(1f32 + 1f32)); - } - - #[test] - fn test_double_one_plus_one() { - let r = super::__adddf3(1f64, 1f64); - assert!(r.eq_repr(1f64 + 1f64)); - } - - #[test] - fn test_float_different_nan() { - let a = f32::from_repr(1); - let b = f32::from_repr(0b11111111100100010001001010101010); - let x = super::__addsf3(a, b); - let y = a + b; - assert!(x.eq_repr(y)); - } - - #[test] - fn test_double_different_nan() { - let a = f64::from_repr(1); - let b = f64::from_repr(0b1111111111110010001000100101010101001000101010000110100011101011); - let x = super::__adddf3(a, b); - let y = a + b; - assert!(x.eq_repr(y)); - } - - #[test] - fn test_float_nan() { - let r = super::__addsf3(f32::NAN, 1.23); - assert_eq!(r.repr(), f32::NAN.repr()); - } - - #[test] - fn test_double_nan() { - let r = super::__adddf3(f64::NAN, 1.23); - assert_eq!(r.repr(), f64::NAN.repr()); - } - - #[test] - fn test_float_inf() { - let r = super::__addsf3(f32::INFINITY, -123.4); - assert_eq!(r, f32::INFINITY); - } - - #[test] - fn test_double_inf() { - let r = super::__adddf3(f64::INFINITY, -123.4); - assert_eq!(r, f64::INFINITY); - } } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 7dc084d4f79..134c32dc745 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,6 +1,4 @@ use core::mem; -#[cfg(test)] -use core::fmt; pub mod add; pub mod pow; @@ -16,22 +14,41 @@ pub trait Float: Sized + Copy { /// Returns the bitwidth of the significand fn significand_bits() -> u32; + /// Returns the bitwidth of the exponent + fn exponent_bits() -> u32 { + Self::bits() - Self::significand_bits() - 1 + } + + /// Returns a mask for the sign bit + fn sign_mask() -> Self::Int; + + /// Returns a mask for the significand + fn significand_mask() -> Self::Int; + + /// Returns a mask for the exponent + fn exponent_mask() -> Self::Int; + /// Returns `self` transmuted to `Self::Int` fn repr(self) -> Self::Int; #[cfg(test)] /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. This methods returns `true` if two NaNs are + /// represented in multiple different ways. This method returns `true` if two NaNs are /// compared. fn eq_repr(self, rhs: Self) -> bool; /// Returns a `Self::Int` transmuted back to `Self` fn from_repr(a: Self::Int) -> Self; + /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; + /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); } +// FIXME: Some of this can be removed if RFC Issue #1424 is resolved +// https://github.com/rust-lang/rfcs/issues/1424 impl Float for f32 { type Int = u32; fn bits() -> u32 { @@ -40,6 +57,15 @@ impl Float for f32 { fn significand_bits() -> u32 { 23 } + fn sign_mask() -> Self::Int { + 1 << (Self::bits() - 1) + } + fn significand_mask() -> Self::Int { + (1 << Self::significand_bits()) - 1 + } + fn exponent_mask() -> Self::Int { + !(Self::sign_mask() | Self::significand_mask()) + } fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -54,6 +80,11 @@ impl Float for f32 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | + ((exponent << Self::significand_bits()) & Self::exponent_mask()) | + (significand & Self::significand_mask())) + } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() .wrapping_sub((1u32 << Self::significand_bits()).leading_zeros()); @@ -68,6 +99,15 @@ impl Float for f64 { fn significand_bits() -> u32 { 52 } + fn sign_mask() -> Self::Int { + 1 << (Self::bits() - 1) + } + fn significand_mask() -> Self::Int { + (1 << Self::significand_bits()) - 1 + } + fn exponent_mask() -> Self::Int { + !(Self::sign_mask() | Self::significand_mask()) + } fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -82,36 +122,14 @@ impl Float for f64 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | + ((exponent << Self::significand_bits()) & Self::exponent_mask()) | + (significand & Self::significand_mask())) + } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() .wrapping_sub((1u64 << Self::significand_bits()).leading_zeros()); (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) } } - -// TODO: Move this to F32/F64 in qc.rs -#[cfg(test)] -#[derive(Copy, Clone)] -pub struct FRepr(F); - -#[cfg(test)] -impl PartialEq for FRepr { - fn eq(&self, other: &FRepr) -> bool { - // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't - // match the output of its gcc_s counterpart. Until we investigate further, we'll - // just avoid testing against gcc_s on those targets. Do note that our - // implementation matches the output of the FPU instruction on *hard* float targets - // and matches its gcc_s counterpart on *soft* float targets. - if cfg!(gnueabihf) { - return true - } - self.0.eq_repr(other.0) - } -} - -#[cfg(test)] -impl fmt::Debug for FRepr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 838805f9492..290d0f54d95 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -31,22 +31,19 @@ pow!(__powidf2: f64, i32); #[cfg(test)] mod tests { - use float::{Float, FRepr}; - use qc::{I32, U32, U64}; + use qc::{I32, F32, F64}; check! { fn __powisf2(f: extern fn(f32, i32) -> f32, - a: U32, - b: I32) -> Option > { - let (a, b) = (f32::from_repr(a.0), b.0); - Some(FRepr(f(a, b))) + a: F32, + b: I32) -> Option { + Some(F32(f(a.0, b.0))) } fn __powidf2(f: extern fn(f64, i32) -> f64, - a: U64, - b: I32) -> Option > { - let (a, b) = (f64::from_repr(a.0), b.0); - Some(FRepr(f(a, b))) + a: F64, + b: I32) -> Option { + Some(F64(f(a.0, b.0))) } } } diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index f7696b58de5..74fcb42c859 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -5,10 +5,12 @@ use std::boxed::Box; use std::fmt; +use core::{f32, f64}; use quickcheck::{Arbitrary, Gen}; use int::LargeInt; +use float::Float; // Generates values in the full range of the integer type macro_rules! arbitrary { @@ -143,6 +145,61 @@ macro_rules! arbitrary_large { arbitrary_large!(I64: i64); arbitrary_large!(U64: u64); +macro_rules! arbitrary_float { + ($TY:ident : $ty:ident) => { + #[derive(Clone, Copy)] + pub struct $TY(pub $ty); + + impl Arbitrary for $TY { + fn arbitrary(g: &mut G) -> $TY + where G: Gen + { + let special = [ + -0.0, 0.0, $ty::NAN, $ty::INFINITY, -$ty::INFINITY + ]; + + if g.gen_weighted_bool(10) { // Random special case + $TY(*g.choose(&special).unwrap()) + } else if g.gen_weighted_bool(10) { // NaN variants + let sign: bool = g.gen(); + let exponent: <$ty as Float>::Int = g.gen(); + let significand: <$ty as Float>::Int = 0; + $TY($ty::from_parts(sign, exponent, significand)) + } else if g.gen() { // Denormalized + let sign: bool = g.gen(); + let exponent: <$ty as Float>::Int = 0; + let significand: <$ty as Float>::Int = g.gen(); + $TY($ty::from_parts(sign, exponent, significand)) + } else { // Random anything + let sign: bool = g.gen(); + let exponent: <$ty as Float>::Int = g.gen(); + let significand: <$ty as Float>::Int = g.gen(); + $TY($ty::from_parts(sign, exponent, significand)) + } + } + + fn shrink(&self) -> Box> { + ::quickcheck::empty_shrinker() + } + } + + impl fmt::Debug for $TY { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } + } + + impl PartialEq for $TY { + fn eq(&self, other: &$TY) -> bool { + self.0.eq_repr(other.0) + } + } + } +} + +arbitrary_float!(F32: f32); +arbitrary_float!(F64: f64); + // Convenience macro to test intrinsics against their reference implementations. // // Each intrinsic is tested against both the `gcc_s` library as well as -- cgit 1.4.1-3-g733a5 From 94c0d475bc24b132efb08ad1ca1b8b992078b82b Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sat, 12 Nov 2016 15:30:57 -0600 Subject: Use correct lib name in qc test failure --- library/compiler-builtins/src/qc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 74fcb42c859..5dbc56f24a8 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -281,9 +281,9 @@ macro_rules! check { print!("{} - Args: ", stringify!($name)); $(print!("{:?} ", $arg);)* print!("\n"); - println!(" rustc-builtins: {:?}", my_answer); - println!(" compiler_rt: {:?}", compiler_rt_answer); - println!(" gcc_s: {:?}", gcc_s_answer); + println!(" compiler-builtins: {:?}", my_answer); + println!(" compiler_rt: {:?}", compiler_rt_answer); + println!(" gcc_s: {:?}", gcc_s_answer); }; if my_answer != compiler_rt_answer { -- cgit 1.4.1-3-g733a5 From 430c92cc9a0cd6e338bb1327bfaa31df729999a0 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sat, 12 Nov 2016 15:31:19 -0600 Subject: Use better cfg name for arm-linux tests --- library/compiler-builtins/build.rs | 5 +++-- library/compiler-builtins/src/float/add.rs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 9f7a8fdedb8..6e7833013ee 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -424,8 +424,9 @@ fn main() { } // To filter away some flaky test (see src/float/add.rs for details) - if llvm_target.last().unwrap().contains("gnueabi") { - println!("cargo:rustc-cfg=gnueabi") + if llvm_target[0].starts_with("arm") && + llvm_target.last().unwrap().contains("gnueabi") { + println!("cargo:rustc-cfg=arm_linux") } // To compile intrinsics.rs for thumb targets, where there is no libc diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 814b99b26c8..0b2490a8ce9 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -184,11 +184,11 @@ macro_rules! add { add!(__addsf3: f32); add!(__adddf3: f64); -// NOTE(cfg) for some reason, on arm-unknown-linux-gnueabi*, our implementation doesn't +// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabi*, our implementation doesn't // match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll // just avoid testing against them on those targets. Do note that our implementation gives the // correct answer; gcc_s and compiler-rt are incorrect in this case. -#[cfg(all(test, not(gnueabi)))] +#[cfg(all(test, not(arm_linux)))] mod tests { use core::{f32, f64}; use qc::{F32, F64}; -- cgit 1.4.1-3-g733a5 From 2c99644aa793fefd3c5788765bd506fa63336950 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sat, 12 Nov 2016 15:09:47 -0600 Subject: Fix apt 404s in Docker `apt update` and `apt install` should be in the same Docker RUN statement, otherwise `apt update` will be cached and `apt install` will 404 if a package no longer exists. --- .../ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 10 +++++----- .../ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 8 ++++---- .../ci/docker/arm-unknown-linux-gnueabihf/Dockerfile | 8 ++++---- .../ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile | 8 ++++---- .../ci/docker/i586-unknown-linux-gnu/Dockerfile | 6 +++--- .../ci/docker/i686-unknown-linux-gnu/Dockerfile | 6 +++--- .../ci/docker/mips-unknown-linux-gnu/Dockerfile | 10 +++++----- .../ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile | 8 ++++---- .../ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile | 4 ++-- .../ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 10 +++++----- .../ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 10 +++++----- .../ci/docker/powerpc64-unknown-linux-gnu/Dockerfile | 10 +++++----- .../ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile | 10 +++++----- .../compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile | 4 ++-- .../compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile | 4 ++-- .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 4 ++-- .../compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile | 4 ++-- .../ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 6 +++--- 18 files changed, 65 insertions(+), 65 deletions(-) diff --git a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index d9a243fa26c..fe05867e379 100644 --- a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -1,9 +1,9 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ - qemu-user-static +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ + qemu-user-static ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile index cb4d021bb94..8a09c20c43e 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -1,8 +1,8 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile index 985abeceaba..57d830d1cd5 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -1,8 +1,8 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile index 94cae18ccb9..a2f3cf177a2 100644 --- a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -1,8 +1,8 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile index 3254b1a347a..fb32306090b 100644 --- a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc-multilib libc6-dev ca-certificates +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc-multilib libc6-dev ca-certificates diff --git a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile index 3254b1a347a..fb32306090b 100644 --- a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc-multilib libc6-dev ca-certificates +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc-multilib libc6-dev ca-certificates diff --git a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile index e332b540394..9d69f1dfea3 100644 --- a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -1,10 +1,10 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-mips-linux-gnu libc6-dev-mips-cross \ - binfmt-support qemu-user-static qemu-system-mips +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-mips-linux-gnu libc6-dev-mips-cross \ + binfmt-support qemu-user-static qemu-system-mips ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ QEMU_LD_PREFIX=/usr/mips-linux-gnu \ diff --git a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile index 92b1d93b8fd..16b6c878ff0 100644 --- a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -1,13 +1,13 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ ca-certificates \ gcc \ gcc-mips64-linux-gnuabi64 \ libc6-dev \ libc6-dev-mips64-cross \ - qemu-user-static -RUN apt-get install -y --no-install-recommends qemu-system-mips + qemu-user-static \ + apt-get install -y --no-install-recommends qemu-system-mips ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ diff --git a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile index adba7783fa0..13f770fcc53 100644 --- a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ ca-certificates \ gcc \ gcc-mips64el-linux-gnuabi64 \ diff --git a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile index 28f77be64d7..0afd5e7f503 100644 --- a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -1,10 +1,10 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ - binfmt-support qemu-user-static +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ + binfmt-support qemu-user-static ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \ QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ diff --git a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile index 8106728b96e..6e65a04db7c 100644 --- a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -1,10 +1,10 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ - qemu-system-ppc +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ + qemu-system-ppc ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ diff --git a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile index 3259b4d9244..eb86808f648 100644 --- a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -1,10 +1,10 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ - binfmt-support qemu-user-static qemu-system-ppc +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ + binfmt-support qemu-user-static qemu-system-ppc ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ diff --git a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile index ba1b3c287bf..adb4106d3ef 100644 --- a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -1,10 +1,10 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ - qemu-system-ppc +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ + qemu-system-ppc ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ QEMU_CPU=POWER8 \ diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index 4a4556673f2..8e92cc0709d 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 84cd8d7af07..65f95643bdd 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index 62ba1273122..e368168a789 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index 42baa3c9a19..3db646b9a6b 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 diff --git a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile index 2ca8ee99c7c..efc7b26c609 100644 --- a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates -- cgit 1.4.1-3-g733a5 From a5d8d0d9f5ff3cfded51f1f5eeed3a9e46c37a2d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 12 Nov 2016 17:36:59 -0500 Subject: merge apt-get commands --- .../ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile index 16b6c878ff0..ef6eeaad59f 100644 --- a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -7,7 +7,7 @@ RUN apt-get update && \ libc6-dev \ libc6-dev-mips64-cross \ qemu-user-static \ - apt-get install -y --no-install-recommends qemu-system-mips + qemu-system-mips ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ -- cgit 1.4.1-3-g733a5 From 03e9f74fb89c0e723c551b84a29f3f4ea766bcb6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 16 Nov 2016 14:34:26 -0500 Subject: update the compiler-rt submodule to pick up the fixes for rust-lang/rust#37559 and rust-lang/rust#37630 --- library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt index f03ba5a4e8b..3bc0272cab9 160000 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt @@ -1 +1 @@ -Subproject commit f03ba5a4e8bf16dcf42dd742a4ce255c36321356 +Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79 -- cgit 1.4.1-3-g733a5 From 865ed6f133627772d6b02d4a44cd8fae447ef294 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 18 Nov 2016 09:40:20 -0800 Subject: Define VISIBILITY_HIDDEN when compiling objects Apparently compiler-rt passed this and we just forgot to. Fixes visibility of some symbols on 32-bit Linux. --- library/compiler-builtins/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6e7833013ee..e6ad4c6a13b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -78,6 +78,7 @@ fn main() { cfg.flag("-fvisibility=hidden"); cfg.flag("-fomit-frame-pointer"); cfg.flag("-ffreestanding"); + cfg.define("VISIBILITY_HIDDEN", None); } // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to -- cgit 1.4.1-3-g733a5 From 42b4300d36fbe5c30056e6f9f0a55ca0353ff69b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 23 Nov 2016 12:47:42 -0500 Subject: CI: use Xargo 0.2.x this version uses the rust-src component that rustup installs instead of fetching the source tarball from static.r-l.o, which sometimes went wrong due to the fallible logic that Xargo 0.1.x used --- library/compiler-builtins/.travis.yml | 11 +++++++---- .../compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile | 4 ++-- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 4 ++-- .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 4 ++-- .../compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile | 4 ++-- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index f4ccbadeac6..7ca18a91514 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -34,10 +34,13 @@ before_install: - test "$TRAVIS_OS_NAME" = "osx" || docker run --rm --privileged multiarch/qemu-user-static:register install: - - if case $TARGET in thumb*) false;; *) true;; esac; then - curl https://static.rust-lang.org/rustup.sh | - sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot`; - fi + - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION + - source ~/.cargo/env + - case $TARGET in + x86_64-apple-darwin | x86_64-unknown-linux-gnu) ;; + thumbv*-none-eabi*) rustup component add rust-src ;; + *) rustup target add $TARGET;; + esac script: - cargo generate-lockfile diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index 8e92cc0709d..09c3203b480 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -2,8 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev -RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 +RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv6m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 65f95643bdd..73ebf810183 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -2,8 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev -RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 +RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index e368168a789..7ec622b7211 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -2,8 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev -RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 +RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index 3db646b9a6b..f5a49319534 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -2,8 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev -RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 +RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ -- cgit 1.4.1-3-g733a5 From 0abb6e20e6eae6d2ae461644965aa94b379f202e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Dec 2016 11:17:21 -0500 Subject: fix the test suite for the thumb targets --- library/compiler-builtins/.travis.yml | 5 +++++ library/compiler-builtins/ci/run.sh | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7ca18a91514..e5fcf195a80 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -22,10 +22,15 @@ matrix: - env: TARGET=powerpc-unknown-linux-gnu - env: TARGET=powerpc64-unknown-linux-gnu - env: TARGET=powerpc64le-unknown-linux-gnu + # NOTE(nightly-2016-12-05) work around for rust-lang/rust#38281 - env: TARGET=thumbv6m-none-eabi + rust: nightly-2016-12-05 - env: TARGET=thumbv7em-none-eabi + rust: nightly-2016-12-05 - env: TARGET=thumbv7em-none-eabihf + rust: nightly-2016-12-05 - env: TARGET=thumbv7m-none-eabi + rust: nightly-2016-12-05 - env: TARGET=x86_64-apple-darwin os: osx env: TARGET=x86_64-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 0159e238913..221748fd488 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,4 +1,4 @@ -set -e +set -ex # Test our implementation case $1 in -- cgit 1.4.1-3-g733a5 From 8a415ef044345d42e090773861cb7ea30aeee60b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Dec 2016 11:33:21 -0500 Subject: pin all the targets to nightly-2016-12-05 --- library/compiler-builtins/.travis.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index e5fcf195a80..156dbe0c9d8 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,7 +1,8 @@ cache: cargo dist: trusty language: rust -rust: nightly +# NOTE(nightly-2016-12-05) work around for rust-lang/rust#38281 +rust: nightly-2016-12-05 services: docker sudo: required @@ -22,15 +23,10 @@ matrix: - env: TARGET=powerpc-unknown-linux-gnu - env: TARGET=powerpc64-unknown-linux-gnu - env: TARGET=powerpc64le-unknown-linux-gnu - # NOTE(nightly-2016-12-05) work around for rust-lang/rust#38281 - env: TARGET=thumbv6m-none-eabi - rust: nightly-2016-12-05 - env: TARGET=thumbv7em-none-eabi - rust: nightly-2016-12-05 - env: TARGET=thumbv7em-none-eabihf - rust: nightly-2016-12-05 - env: TARGET=thumbv7m-none-eabi - rust: nightly-2016-12-05 - env: TARGET=x86_64-apple-darwin os: osx env: TARGET=x86_64-unknown-linux-gnu -- cgit 1.4.1-3-g733a5 From fc81b547e612afc64a1f9ae6ea2d2fad6dbe1205 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Dec 2016 14:58:05 -0500 Subject: work around rust-lang/cargo#3340 --- library/compiler-builtins/.travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 156dbe0c9d8..61b17134072 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -44,6 +44,8 @@ install: esac script: + # work around rust-lang/cargo#3340 + - export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt - cargo generate-lockfile - if [[ $TRAVIS_OS_NAME = "linux" ]]; then sudo apt-get remove -y qemu-user-static && -- cgit 1.4.1-3-g733a5 From b90b5107a7a8ea66f8ab635b105413c396ea7782 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Dec 2016 15:26:18 -0500 Subject: don't set SSL_CERT_FILE for OSX --- library/compiler-builtins/.travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 61b17134072..82ca5d8222c 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -45,7 +45,8 @@ install: script: # work around rust-lang/cargo#3340 - - export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt + - test "$TRAVIS_OS_NAME" = "osx" || + export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt - cargo generate-lockfile - if [[ $TRAVIS_OS_NAME = "linux" ]]; then sudo apt-get remove -y qemu-user-static && -- cgit 1.4.1-3-g733a5 From 6da988a43a27b0db272c05da50720782c54f5a85 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Dec 2016 16:18:43 -0500 Subject: by default, mark this crate as the #![compiler_builtins] crate as this is how most users will want to use this crate --- library/compiler-builtins/Cargo.toml | 4 ++++ library/compiler-builtins/ci/run.sh | 14 +++++++------- library/compiler-builtins/src/lib.rs | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 58ce4513ca5..95364233e9d 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -23,6 +23,10 @@ compiler-rt = { path = "compiler-rt" } [features] # Build the missing intrinsics from compiler-rt C source code c = [] +# Mark this crate as the #![compiler_builtins] crate +compiler-builtins = [] +default = ["compiler-builtins"] +rustbuild = ["compiler-builtins"] weak = ["rlibc/weak"] [workspace] diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 0159e238913..c9e0736c3d8 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -7,8 +7,8 @@ case $1 in xargo build --target $1 --release ;; *) - cargo test --target $1 - cargo test --target $1 --release + cargo test --no-default-features --target $1 + cargo test --no-default-features --target $1 --release ;; esac @@ -18,7 +18,7 @@ case $1 in xargo build --features c --target $1 --bin intrinsics ;; *) - cargo build --features c --target $1 --bin intrinsics + cargo build --no-default-features --features c --target $1 --bin intrinsics ;; esac @@ -26,12 +26,12 @@ esac # TODO(#79) fix the undefined references problem for debug-assertions+lto case $1 in thumb*) - RUSTFLAGS="-C debug-assertions=no -C link-arg=-nostartfiles" xargo rustc --features c --target $1 --bin intrinsics -- -C lto - xargo rustc --features c --target $1 --bin intrinsics --release -- -C lto + RUSTFLAGS="-C debug-assertions=no -C link-arg=-nostartfiles" xargo rustc --no-default-features --features c --target $1 --bin intrinsics -- -C lto + xargo rustc --no-default-features --features c --target $1 --bin intrinsics --release -- -C lto ;; *) - RUSTFLAGS="-C debug-assertions=no" cargo rustc --features c --target $1 --bin intrinsics -- -C lto - cargo rustc --features c --target $1 --bin intrinsics --release -- -C lto + RUSTFLAGS="-C debug-assertions=no" cargo rustc --no-default-features --features c --target $1 --bin intrinsics -- -C lto + cargo rustc --no-default-features --features c --target $1 --bin intrinsics --release -- -C lto ;; esac diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0efb20b5dec..dc8f4111d89 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,6 @@ #![cfg_attr(not(stage0), deny(warnings))] #![cfg_attr(not(test), no_std)] -#![cfg_attr(rustbuild, compiler_builtins)] +#![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", -- cgit 1.4.1-3-g733a5 From 45ebf21c0b03f0e04b7714a521a71028ffd9cf68 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Dec 2016 16:54:41 -0500 Subject: fix appveyor --- library/compiler-builtins/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index f27347c338d..c05bfdfc2b6 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -16,5 +16,5 @@ build: false test_script: - cargo build --target %TARGET% - cargo build --release --target %TARGET% - - cargo test --target %TARGET% - - cargo test --release --target %TARGET% + - cargo test --no-default-features --target %TARGET% + - cargo test --no-default-features --release --target %TARGET% -- cgit 1.4.1-3-g733a5 From b8d66520352af21a8e53f04363ddd3a040d7dcba Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 17 Dec 2016 23:01:47 -0500 Subject: add implementations of memcpy et al behind the "mem" Cargo feature, which used to be named "weak" fixes #126 --- library/compiler-builtins/Cargo.toml | 9 ++---- library/compiler-builtins/src/arm.rs | 4 +++ library/compiler-builtins/src/lib.rs | 7 ++--- library/compiler-builtins/src/mem.rs | 59 ++++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 library/compiler-builtins/src/mem.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 95364233e9d..83405787a02 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -8,12 +8,6 @@ version = "0.1.0" rustc-cfg = "0.2.0" gcc = "0.3.36" -[dependencies] - -[dependencies.rlibc] -git = "https://github.com/alexcrichton/rlibc" -optional = true - [dev-dependencies] quickcheck = "0.3.1" rand = "0.3.14" @@ -26,7 +20,8 @@ c = [] # Mark this crate as the #![compiler_builtins] crate compiler-builtins = [] default = ["compiler-builtins"] +# Include implementations of memory operations like memcpy +mem = [] rustbuild = ["compiler-builtins"] -weak = ["rlibc/weak"] [workspace] diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index b74458f11a2..345ff241dbe 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,5 +1,8 @@ use core::intrinsics; +#[cfg(feature = "mem")] +use mem::{memcpy, memmove, memset}; + // NOTE This function and the ones below are implemented using assembly because they using a custom // calling convention which can't be implemented using a normal Rust function #[naked] @@ -100,6 +103,7 @@ pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { ::int::udiv::__udivsi3(a, b) } +#[cfg(not(feature = "mem"))] extern "C" { fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index dc8f4111d89..b104def30cc 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -11,7 +11,6 @@ #![feature(asm)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] -#![feature(linkage)] #![feature(naked_functions)] #![feature(staged_api)] #![no_builtins] @@ -102,9 +101,6 @@ extern crate compiler_rt; #[cfg(test)] extern crate rand; -#[cfg(feature = "weak")] -extern crate rlibc; - #[cfg(test)] #[macro_use] mod qc; @@ -112,6 +108,9 @@ mod qc; pub mod int; pub mod float; +#[cfg(feature = "mem")] +pub mod mem; + #[cfg(target_arch = "arm")] pub mod arm; diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs new file mode 100644 index 00000000000..31d6712d0d3 --- /dev/null +++ b/library/compiler-builtins/src/mem.rs @@ -0,0 +1,59 @@ +#[no_mangle] +pub unsafe extern "C" fn memcpy(dest: *mut u8, + src: *const u8, + n: usize) + -> *mut u8 { + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + dest +} + +#[no_mangle] +pub unsafe extern "C" fn memmove(dest: *mut u8, + src: *const u8, + n: usize) + -> *mut u8 { + if src < dest as *const u8 { + // copy from end + let mut i = n; + while i != 0 { + i -= 1; + *dest.offset(i as isize) = *src.offset(i as isize); + } + } else { + // copy from beginning + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + } + dest +} + +#[no_mangle] +pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 { + let mut i = 0; + while i < n { + *s.offset(i as isize) = c as u8; + i += 1; + } + s +} + +#[no_mangle] +pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + let mut i = 0; + while i < n { + let a = *s1.offset(i as isize); + let b = *s2.offset(i as isize); + if a != b { + return a as i32 - b as i32; + } + i += 1; + } + 0 +} -- cgit 1.4.1-3-g733a5 From a2671118ae95417715bacc803661fb2b410b9c32 Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Mon, 19 Dec 2016 05:11:01 +0300 Subject: Fix memset arguments for MSP430 target. On MSP430 second argument to memset has i16 type instead of i32. --- library/compiler-builtins/src/mem.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index 31d6712d0d3..a7d267c5003 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -1,3 +1,10 @@ +#[allow(warnings)] +#[cfg(target_pointer_width = "16")] +type c_int = i16; +#[allow(warnings)] +#[cfg(not(target_pointer_width = "16"))] +type c_int = i32; + #[no_mangle] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, @@ -35,7 +42,7 @@ pub unsafe extern "C" fn memmove(dest: *mut u8, } #[no_mangle] -pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 { +pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { let mut i = 0; while i < n { *s.offset(i as isize) = c as u8; -- cgit 1.4.1-3-g733a5 From af00bd119832a37366f4a67a19f9556d68bd1d74 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Dec 2016 21:56:29 -0500 Subject: bump rustc-cfg dependency to v0.3.0 the older no longer works with recent nightlies as target_family disappeared from `rustc --print cfg`'s output --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 83405787a02..5fb89f462bc 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,7 +5,7 @@ name = "compiler_builtins" version = "0.1.0" [build-dependencies] -rustc-cfg = "0.2.0" +rustc-cfg = "0.3.0" gcc = "0.3.36" [dev-dependencies] -- cgit 1.4.1-3-g733a5 From 3ed64e2b500e9464898bf67ea2ca48b9d09a1f26 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Dec 2016 23:18:17 -0500 Subject: CI: use a recent nightly - add #[no_mangle] to the panic_fmt lang item to adjust to changes in the visibility algorithm - adjust to changes in the layout of Cargo's target directory - use a newer Xargo to reduce the build time of the sysroot (only core is compiled as part of the sysroot now) --- library/compiler-builtins/.travis.yml | 3 +-- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 2 +- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 2 +- .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 2 +- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 2 +- library/compiler-builtins/ci/run.sh | 24 +++++++++++++--------- library/compiler-builtins/src/bin/intrinsics.rs | 1 + 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 82ca5d8222c..96bd24ab2f9 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,8 +1,7 @@ cache: cargo dist: trusty language: rust -# NOTE(nightly-2016-12-05) work around for rust-lang/rust#38281 -rust: nightly-2016-12-05 +rust: nightly services: docker sudo: required diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index 09c3203b480..2a2d127e1d2 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin + sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv6m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 73ebf810183..fda5dcbe6f8 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin + sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index 7ec622b7211..5395e7449a9 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin + sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index f5a49319534..e09c020a223 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin + sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 382d70fe87b..b30fad10fc8 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -26,7 +26,7 @@ esac # TODO(#79) fix the undefined references problem for debug-assertions+lto case $1 in thumb*) - RUSTFLAGS="-C debug-assertions=no -C link-arg=-nostartfiles" xargo rustc --no-default-features --features c --target $1 --bin intrinsics -- -C lto + RUSTFLAGS="-C debug-assertions=no" xargo rustc --no-default-features --features c --target $1 --bin intrinsics -- -C lto -C link-arg=-nostartfiles xargo rustc --no-default-features --features c --target $1 --bin intrinsics --release -- -C lto ;; *) @@ -61,18 +61,22 @@ case $TRAVIS_OS_NAME in ;; esac -# NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it if [ $TRAVIS_OS_NAME = osx ]; then - path=target/${1}/debug/libcompiler_builtins.rlib + path=target/${1}/debug/deps/libcompiler_builtins-*.rlib else - path=/target/${1}/debug/libcompiler_builtins.rlib + path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib fi -stdout=$($PREFIX$NM -g --defined-only $path) +for rlib in $(echo $path); do + stdout=$($PREFIX$NM -g --defined-only $rlib) -set +e -echo "$stdout" | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' + # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it + set +e + echo "$stdout" | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' -if test $? = 0; then - exit 1 -fi + if test $? = 0; then + exit 1 + fi +done + +true diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index 5a4a34503cc..b0de331afd4 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -403,5 +403,6 @@ pub fn _Unwind_Resume() {} extern "C" fn eh_personality() {} #[cfg(not(test))] +#[no_mangle] #[lang = "panic_fmt"] extern "C" fn panic_fmt() {} -- cgit 1.4.1-3-g733a5 From acbca64291e2ad303b732cb0a0cb6097ecd15db5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 31 Dec 2016 10:04:16 -0500 Subject: more #[no_mangle] --- library/compiler-builtins/src/bin/intrinsics.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index b0de331afd4..e0b619f5598 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -400,9 +400,10 @@ pub fn _Unwind_Resume() {} // Lang items #[cfg(not(test))] #[lang = "eh_personality"] +#[no_mangle] extern "C" fn eh_personality() {} #[cfg(not(test))] -#[no_mangle] #[lang = "panic_fmt"] +#[no_mangle] extern "C" fn panic_fmt() {} -- cgit 1.4.1-3-g733a5 From da48de46016c0214bf43aca7e5f6bc41ab731367 Mon Sep 17 00:00:00 2001 From: James Duley Date: Mon, 2 Jan 2017 22:57:38 +1300 Subject: mul.rs: use wrapping_mul not plain rustc in debug mode with a plain multiplication will call @llvm.umul.with.overflow.* which may call the builtin resulting in infinite recursion. --- library/compiler-builtins/src/int/mul.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index db9f0d9e0c6..0403aa90060 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -9,18 +9,18 @@ macro_rules! mul { pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { let half_bits = <$ty>::bits() / 4; let lower_mask = !0 >> half_bits; - let mut low = (a.low() & lower_mask) * (b.low() & lower_mask); + let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask); let mut t = low >> half_bits; low &= lower_mask; - t += (a.low() >> half_bits) * (b.low() & lower_mask); + t += (a.low() >> half_bits).wrapping_mul(b.low() & lower_mask); low += (t & lower_mask) << half_bits; let mut high = t >> half_bits; t = low >> half_bits; low &= lower_mask; - t += (b.low() >> half_bits) * (a.low() & lower_mask); + t += (b.low() >> half_bits).wrapping_mul(a.low() & lower_mask); low += (t & lower_mask) << half_bits; high += t >> half_bits; - high += (a.low() >> half_bits) * (b.low() >> half_bits); + high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits); high = high.wrapping_add(a.high().wrapping_mul(b.low()).wrapping_add(a.low().wrapping_mul(b.high()))); <$ty>::from_parts(low, high) } -- cgit 1.4.1-3-g733a5 From e6bb6db8eb0f83233d57e174e2ea56d9a11aa34b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 26 Jan 2017 16:17:23 -0500 Subject: fix the build the unused macro_use crate lint has tightened; fix the new warnings --- library/compiler-builtins/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index b104def30cc..04bf2d05c95 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -86,7 +86,7 @@ macro_rules! srem { } #[cfg(test)] -#[macro_use] +#[cfg_attr(target_arch = "arm", macro_use)] extern crate quickcheck; #[cfg(test)] -- cgit 1.4.1-3-g733a5 From b6e0dd2bf28f8ff17e4430ddc4bd1cba098e2173 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 4 Jan 2017 01:42:57 +0100 Subject: Add i128 to lib.rs as feature --- library/compiler-builtins/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 04bf2d05c95..21d7902b2c2 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -13,6 +13,7 @@ #![feature(core_intrinsics)] #![feature(naked_functions)] #![feature(staged_api)] +#![feature(i128_type)] #![no_builtins] #![unstable(feature = "compiler_builtins_lib", reason = "Compiler builtins. Will never become stable.", -- cgit 1.4.1-3-g733a5 From 8bb1010d51e65ef9565c3b7ee839ce2d5f7297bf Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 4 Jan 2017 01:52:47 +0100 Subject: int module: macro-ify trait impls and add {u,i}128 support --- library/compiler-builtins/src/int/mod.rs | 79 ++++++++++++++------------------ 1 file changed, 35 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 37e05377a2e..bbe4b7bfd5d 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -10,28 +10,25 @@ pub trait Int { fn bits() -> u32; } -// TODO: Once i128/u128 support lands, we'll want to add impls for those as well -impl Int for u32 { - fn bits() -> u32 { - 32 - } -} -impl Int for i32 { - fn bits() -> u32 { - 32 - } -} -impl Int for u64 { - fn bits() -> u32 { - 64 - } -} -impl Int for i64 { - fn bits() -> u32 { - 64 +macro_rules! int_impl { + ($ity:ty, $sty:ty, $bits:expr) => { + impl Int for $ity { + fn bits() -> u32 { + $bits + } + } + impl Int for $sty { + fn bits() -> u32 { + $bits + } + } } } +int_impl!(i32, u32, 32); +int_impl!(i64, u64, 64); +int_impl!(i128, u128, 128); + /// Trait to convert an integer to/from smaller parts pub trait LargeInt { type LowHalf; @@ -42,32 +39,26 @@ pub trait LargeInt { fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; } -// TODO: Once i128/u128 support lands, we'll want to add impls for those as well -impl LargeInt for u64 { - type LowHalf = u32; - type HighHalf = u32; +macro_rules! large_int { + ($ty:ty, $tylow:ty, $tyhigh:ty, $halfbits:expr) => { + impl LargeInt for $ty { + type LowHalf = $tylow; + type HighHalf = $tyhigh; - fn low(self) -> u32 { - self as u32 - } - fn high(self) -> u32 { - (self >> 32) as u32 - } - fn from_parts(low: u32, high: u32) -> u64 { - low as u64 | ((high as u64) << 32) + fn low(self) -> $tylow { + self as $tylow + } + fn high(self) -> $tyhigh { + (self >> $halfbits) as $tyhigh + } + fn from_parts(low: $tylow, high: $tyhigh) -> $ty { + low as $ty | ((high as $ty) << $halfbits) + } + } } } -impl LargeInt for i64 { - type LowHalf = u32; - type HighHalf = i32; - fn low(self) -> u32 { - self as u32 - } - fn high(self) -> i32 { - (self >> 32) as i32 - } - fn from_parts(low: u32, high: i32) -> i64 { - low as i64 | ((high as i64) << 32) - } -} +large_int!(u64, u32, u32, 32); +large_int!(i64, u32, i32, 32); +large_int!(u128, u64, u64, 64); +large_int!(i128, u64, i64, 64); -- cgit 1.4.1-3-g733a5 From 19700fb03daaa88a11ec99d5a1bc84c8ce658204 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 4 Jan 2017 02:42:03 +0100 Subject: i128 mul intrinsics --- library/compiler-builtins/README.md | 4 ++-- library/compiler-builtins/build.rs | 2 -- library/compiler-builtins/src/int/mul.rs | 27 +++++++++++++++++++-------- library/compiler-builtins/src/lib.rs | 3 +++ 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index d66d88828bf..8e81dde84a5 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -206,8 +206,8 @@ These builtins are needed to support 128-bit integers, which are in the process - [ ] floatuntisf.c - [ ] lshrti3.c - [ ] modti3.c -- [ ] muloti4.c -- [ ] multi3.c +- [x] muloti4.c +- [x] multi3.c - [ ] udivmodti4.c - [ ] udivti3.c - [ ] umodti3.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e6ad4c6a13b..0ecb0d0c60b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -150,7 +150,6 @@ fn main() { "int_util.c", "muldc3.c", "muldf3.c", - "muloti4.c", "mulsc3.c", "mulsf3.c", "mulvdi3.c", @@ -202,7 +201,6 @@ fn main() { "lshrti3.c", "modti3.c", "multf3.c", - "multi3.c", "mulvti3.c", "negti2.c", "negvti2.c", diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 0403aa90060..d46bc90303f 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,9 +1,8 @@ -#[cfg(not(all(feature = "c", target_arch = "x86")))] use int::LargeInt; use int::Int; macro_rules! mul { - ($intrinsic:ident: $ty:ty) => { + ($intrinsic:ident: $ty:ty, $tyh:ty) => { /// Returns `a * b` #[cfg_attr(not(test), no_mangle)] pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { @@ -14,14 +13,15 @@ macro_rules! mul { low &= lower_mask; t += (a.low() >> half_bits).wrapping_mul(b.low() & lower_mask); low += (t & lower_mask) << half_bits; - let mut high = t >> half_bits; + let mut high = (t >> half_bits) as $tyh; t = low >> half_bits; low &= lower_mask; t += (b.low() >> half_bits).wrapping_mul(a.low() & lower_mask); low += (t & lower_mask) << half_bits; - high += t >> half_bits; - high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits); - high = high.wrapping_add(a.high().wrapping_mul(b.low()).wrapping_add(a.low().wrapping_mul(b.high()))); + high += (t >> half_bits) as $tyh; + high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits) as $tyh; + high = high.wrapping_add(a.high().wrapping_mul(b.low() as $tyh)) + .wrapping_add((a.low() as $tyh).wrapping_mul(b.high())); <$ty>::from_parts(low, high) } } @@ -29,9 +29,13 @@ macro_rules! mul { macro_rules! mulo { ($intrinsic:ident: $ty:ty) => { + // Default is "C" ABI + mulo!($intrinsic: $ty, "C"); + }; + ($intrinsic:ident: $ty:ty, $abi:tt) => { /// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty { + pub extern $abi fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty { *overflow = 0; let result = a.wrapping_mul(b); if a == <$ty>::min_value() { @@ -69,11 +73,18 @@ macro_rules! mulo { } #[cfg(not(all(feature = "c", target_arch = "x86")))] -mul!(__muldi3: u64); +mul!(__muldi3: u64, u32); + +mul!(__multi3: i128, i64); mulo!(__mulosi4: i32); mulo!(__mulodi4: i64); +#[cfg(all(windows, target_pointer_width="64"))] +mulo!(__muloti4: i128, "unadjusted"); +#[cfg(not(all(windows, target_pointer_width="64")))] +mulo!(__muloti4: i128); + #[cfg(test)] mod tests { use qc::{I32, I64, U64}; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 21d7902b2c2..f637ff52b96 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -14,6 +14,9 @@ #![feature(naked_functions)] #![feature(staged_api)] #![feature(i128_type)] +#![feature(repr_simd)] +#![feature(abi_unadjusted)] +#![allow(unused_features)] #![no_builtins] #![unstable(feature = "compiler_builtins_lib", reason = "Compiler builtins. Will never become stable.", -- cgit 1.4.1-3-g733a5 From a38eee9ea1bd00395ed97e7898cd1cd772f73d22 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 4 Jan 2017 03:04:27 +0100 Subject: i128 shift intrinsics --- library/compiler-builtins/README.md | 6 +++--- library/compiler-builtins/build.rs | 3 --- library/compiler-builtins/src/int/shift.rs | 7 ++++++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 8e81dde84a5..8a8c2d174f6 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -193,8 +193,8 @@ features = ["c"] These builtins are needed to support 128-bit integers, which are in the process of being added to Rust. -- [ ] ashlti3.c -- [ ] ashrti3.c +- [x] ashlti3.c +- [x] ashrti3.c - [ ] divti3.c - [ ] fixdfti.c - [ ] fixsfti.c @@ -204,7 +204,7 @@ These builtins are needed to support 128-bit integers, which are in the process - [ ] floattisf.c - [ ] floatuntidf.c - [ ] floatuntisf.c -- [ ] lshrti3.c +- [x] lshrti3.c - [ ] modti3.c - [x] muloti4.c - [x] multi3.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0ecb0d0c60b..082592541d0 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -178,8 +178,6 @@ fn main() { sources.extend(&["absvti2.c", "addtf3.c", "addvti3.c", - "ashlti3.c", - "ashrti3.c", "clzti2.c", "cmpti2.c", "ctzti2.c", @@ -198,7 +196,6 @@ fn main() { "floatuntidf.c", "floatuntisf.c", "floatuntixf.c", - "lshrti3.c", "modti3.c", "multf3.c", "mulvti3.c", diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 9338f07ce7e..5c8dd5c6a47 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,4 +1,3 @@ -#[cfg(not(all(feature = "c", target_arch = "x86")))] use int::{Int, LargeInt}; macro_rules! ashl { @@ -58,12 +57,18 @@ macro_rules! lshr { #[cfg(not(all(feature = "c", target_arch = "x86")))] ashl!(__ashldi3: u64); +ashl!(__ashlti3: u128); + #[cfg(not(all(feature = "c", target_arch = "x86")))] ashr!(__ashrdi3: i64); +ashr!(__ashrti3: i128); + #[cfg(not(all(feature = "c", target_arch = "x86")))] lshr!(__lshrdi3: u64); +lshr!(__lshrti3: u128); + #[cfg(test)] mod tests { use qc::{I64, U64}; -- cgit 1.4.1-3-g733a5 From 9fd610d8591f0bca467587ac060cae3d6b05f2ff Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 5 Jan 2017 02:22:44 +0100 Subject: Macro-ify udivmod --- library/compiler-builtins/src/int/mod.rs | 15 ++ library/compiler-builtins/src/int/mul.rs | 16 +- library/compiler-builtins/src/int/udiv.rs | 255 +++++++++++++++--------------- 3 files changed, 154 insertions(+), 132 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index bbe4b7bfd5d..647410ccbf8 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,3 +1,14 @@ +macro_rules! hty { + ($ty:ty) => { + <$ty as LargeInt>::HighHalf + } +} + +macro_rules! os_ty { + ($ty:ty) => { + <$ty as Int>::OtherSign + } +} pub mod mul; pub mod sdiv; @@ -6,6 +17,8 @@ pub mod udiv; /// Trait for some basic operations on integers pub trait Int { + /// Type with the same width but other signedness + type OtherSign; /// Returns the bitwidth of the int type fn bits() -> u32; } @@ -13,11 +26,13 @@ pub trait Int { macro_rules! int_impl { ($ity:ty, $sty:ty, $bits:expr) => { impl Int for $ity { + type OtherSign = $sty; fn bits() -> u32 { $bits } } impl Int for $sty { + type OtherSign = $ity; fn bits() -> u32 { $bits } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index d46bc90303f..45a71283464 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -2,7 +2,7 @@ use int::LargeInt; use int::Int; macro_rules! mul { - ($intrinsic:ident: $ty:ty, $tyh:ty) => { + ($intrinsic:ident: $ty:ty) => { /// Returns `a * b` #[cfg_attr(not(test), no_mangle)] pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { @@ -13,15 +13,15 @@ macro_rules! mul { low &= lower_mask; t += (a.low() >> half_bits).wrapping_mul(b.low() & lower_mask); low += (t & lower_mask) << half_bits; - let mut high = (t >> half_bits) as $tyh; + let mut high = (t >> half_bits) as hty!($ty); t = low >> half_bits; low &= lower_mask; t += (b.low() >> half_bits).wrapping_mul(a.low() & lower_mask); low += (t & lower_mask) << half_bits; - high += (t >> half_bits) as $tyh; - high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits) as $tyh; - high = high.wrapping_add(a.high().wrapping_mul(b.low() as $tyh)) - .wrapping_add((a.low() as $tyh).wrapping_mul(b.high())); + high += (t >> half_bits) as hty!($ty); + high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits) as hty!($ty); + high = high.wrapping_add(a.high().wrapping_mul(b.low() as hty!($ty))) + .wrapping_add((a.low() as hty!($ty)).wrapping_mul(b.high())); <$ty>::from_parts(low, high) } } @@ -73,9 +73,9 @@ macro_rules! mulo { } #[cfg(not(all(feature = "c", target_arch = "x86")))] -mul!(__muldi3: u64, u32); +mul!(__muldi3: u64); -mul!(__multi3: i128, i64); +mul!(__multi3: i128); mulo!(__mulosi4: i32); mulo!(__mulodi4: i64); diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 3c5629e1a51..a1a9503a79e 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -114,152 +114,159 @@ pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 { rem } -/// Returns `n / d` and sets `*rem = n % d` -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { - // NOTE X is unknown, K != 0 - if n.high() == 0 { - if d.high() == 0 { - // 0 X - // --- - // 0 X +macro_rules! udivmod_inner { + ($n:expr, $d:expr, $rem:expr, $ty:ty) => {{ + let (n, d, rem) = ($n, $d, $rem); + // NOTE X is unknown, K != 0 + if n.high() == 0 { + if d.high() == 0 { + // 0 X + // --- + // 0 X + + if let Some(rem) = rem { + *rem = <$ty>::from(urem!(n.low(), d.low())); + } + return <$ty>::from(udiv!(n.low(), d.low())); + } else { + // 0 X + // --- + // K X + if let Some(rem) = rem { + *rem = n; + } + return 0; + }; + } - if let Some(rem) = rem { - *rem = u64::from(urem!(n.low(), d.low())); + let mut sr; + let mut q; + let mut r; + + if d.low() == 0 { + if d.high() == 0 { + // K X + // --- + // 0 0 + // NOTE This should be unreachable in safe Rust because the program will panic before + // this intrinsic is called + unsafe { + intrinsics::abort() + } } - return u64::from(udiv!(n.low(), d.low())); - } else { - // 0 X - // --- - // K X - if let Some(rem) = rem { - *rem = n; - } - return 0; - }; - } - - let mut sr; - let mut q; - let mut r; - if d.low() == 0 { - if d.high() == 0 { - // K X - // --- - // 0 0 - // NOTE This should be unreachable in safe Rust because the program will panic before - // this intrinsic is called - unsafe { - intrinsics::abort() + if n.low() == 0 { + // K 0 + // --- + // K 0 + if let Some(rem) = rem { + *rem = <$ty>::from_parts(0, urem!(n.high(), d.high())); + } + return <$ty>::from(udiv!(n.high(), d.high())); } - } - if n.low() == 0 { - // K 0 + // K K // --- // K 0 - if let Some(rem) = rem { - *rem = u64::from_parts(0, urem!(n.high(), d.high())); + + if d.high().is_power_of_two() { + if let Some(rem) = rem { + *rem = <$ty>::from_parts(n.low(), n.high() & (d.high() - 1)); + } + return <$ty>::from(n.high() >> d.high().trailing_zeros()); } - return u64::from(udiv!(n.high(), d.high())); - } - // K K - // --- - // K 0 + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - if d.high().is_power_of_two() { - if let Some(rem) = rem { - *rem = u64::from_parts(n.low(), n.high() & (d.high() - 1)); + // D > N + if sr > ::bits() - 2 { + if let Some(rem) = rem { + *rem = n; + } + return 0; } - return u64::from(n.high() >> d.high().trailing_zeros()); - } - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + sr += 1; - // D > N - if sr > u32::bits() - 2 { - if let Some(rem) = rem { - *rem = n; + // 1 <= sr <= ::bits() - 1 + q = n << (<$ty>::bits() - sr); + r = n >> sr; + } else if d.high() == 0 { + // K X + // --- + // 0 K + if d.low().is_power_of_two() { + if let Some(rem) = rem { + *rem = <$ty>::from(n.low() & (d.low() - 1)); + } + + if d.low() == 1 { + return n; + } else { + let sr = d.low().trailing_zeros(); + return n >> sr; + }; } - return 0; - } - sr += 1; - - // 1 <= sr <= u32::bits() - 1 - q = n << (u64::bits() - sr); - r = n >> sr; - } else if d.high() == 0 { - // K X - // --- - // 0 K - if d.low().is_power_of_two() { - if let Some(rem) = rem { - *rem = u64::from(n.low() & (d.low() - 1)); - } + sr = 1 + ::bits() + d.low().leading_zeros() - n.high().leading_zeros(); - if d.low() == 1 { - return n; - } else { - let sr = d.low().trailing_zeros(); - return n >> sr; - }; - } - - sr = 1 + u32::bits() + d.low().leading_zeros() - n.high().leading_zeros(); - - // 2 <= sr <= u64::bits() - 1 - q = n << (u64::bits() - sr); - r = n >> sr; - } else { - // K X - // --- - // K K - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > u32::bits() - 1 { - if let Some(rem) = rem { - *rem = n; + // 2 <= sr <= u64::bits() - 1 + q = n << (<$ty>::bits() - sr); + r = n >> sr; + } else { + // K X + // --- + // K K + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > ::bits() - 1 { + if let Some(rem) = rem { + *rem = n; + } + return 0; } - return 0; - } - sr += 1; + sr += 1; - // 1 <= sr <= u32::bits() - q = n << (u64::bits() - sr); - r = n >> sr; - } - - // Not a special case - // q and r are initialized with - // q = n << (u64::bits() - sr) - // r = n >> sr - // 1 <= sr <= u64::bits() - 1 - let mut carry = 0; + // 1 <= sr <= ::bits() + q = n << (<$ty>::bits() - sr); + r = n >> sr; + } - for _ in 0..sr { - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (u64::bits() - 1)); - q = (q << 1) | carry as u64; + // Not a special case + // q and r are initialized with + // q = n << (u64::bits() - sr) + // r = n >> sr + // 1 <= sr <= u64::bits() - 1 + let mut carry = 0; + + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (<$ty>::bits() - 1)); + q = (q << 1) | carry as $ty; + + // carry = 0 + // if r >= d { + // r -= d; + // carry = 1; + // } + let s = (d.wrapping_sub(r).wrapping_sub(1)) as os_ty!($ty) >> (<$ty>::bits() - 1); + carry = (s & 1) as hty!($ty); + r -= d & s as $ty; + } - // carry = 0 - // if r >= d { - // r -= d; - // carry = 1; - // } - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i64 >> (u64::bits() - 1); - carry = (s & 1) as u32; - r -= d & s as u64; - } + if let Some(rem) = rem { + *rem = r; + } + (q << 1) | carry as $ty + }} +} - if let Some(rem) = rem { - *rem = r; - } - (q << 1) | carry as u64 +/// Returns `n / d` and sets `*rem = n % d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { + udivmod_inner!(n, d, rem, u64) } #[cfg(test)] -- cgit 1.4.1-3-g733a5 From 37a62269dce4a8790aaca7623d0aace955fbd773 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 5 Jan 2017 15:08:56 +0100 Subject: u128 udiv intrinsics --- library/compiler-builtins/README.md | 6 +-- library/compiler-builtins/build.rs | 5 +-- library/compiler-builtins/src/int/udiv.rs | 69 +++++++++++++++++++++++++------ library/compiler-builtins/src/lib.rs | 11 +++++ 4 files changed, 71 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 8a8c2d174f6..7397810ceae 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -208,9 +208,9 @@ These builtins are needed to support 128-bit integers, which are in the process - [ ] modti3.c - [x] muloti4.c - [x] multi3.c -- [ ] udivmodti4.c -- [ ] udivti3.c -- [ ] umodti3.c +- [x] udivmodti4.c +- [x] udivti3.c +- [x] umodti3.c ## Unimplemented functions diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 082592541d0..5219a0400b4 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -207,10 +207,7 @@ fn main() { "subtf3.c", "subvti3.c", "trampoline_setup.c", - "ucmpti2.c", - "udivmodti4.c", - "udivti3.c", - "umodti3.c"]); + "ucmpti2.c"]); } if target_vendor == "apple" { diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index a1a9503a79e..44a1149b9b2 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -96,23 +96,44 @@ pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { q } -/// Returns `n / d` -#[cfg_attr(not(test), no_mangle)] -#[cfg(not(all(feature = "c", target_arch = "x86")))] -pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { - __udivmoddi4(n, d, None) +macro_rules! div_mod_intrinsics { + ($udiv_intr:ident, $umod_intr:ident : $ty:ty) => { + div_mod_intrinsics!($udiv_intr, $umod_intr : $ty, + __udivmoddi4); + }; + ($udiv_intr:ident, $umod_intr:ident : $ty:ty, $divmod_intr:expr) => { + div_mod_intrinsics!($udiv_intr, $umod_intr : $ty, + $divmod_intr, $ty, |i|{ i }); + }; + ($udiv_intr:ident, $umod_intr:ident : $ty:ty, $divmod_intr:expr, + $tyret:ty, $conv:expr) => { + /// Returns `n / d` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $udiv_intr(n: $ty, d: $ty) -> $tyret { + let r = $divmod_intr(n, d, None); + ($conv)(r) + } + + /// Returns `n % d` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $umod_intr(a: $ty, b: $ty) -> $tyret { + use core::mem; + + let mut rem = unsafe { mem::uninitialized() }; + $divmod_intr(a, b, Some(&mut rem)); + ($conv)(rem) + } + } } -/// Returns `n % d` #[cfg(not(all(feature = "c", target_arch = "x86")))] -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 { - use core::mem; +div_mod_intrinsics!(__udivdi3, __umoddi3: u64); - let mut rem = unsafe { mem::uninitialized() }; - __udivmoddi4(a, b, Some(&mut rem)); - rem -} +#[cfg(not(all(windows, target_pointer_width="64")))] +div_mod_intrinsics!(__udivti3, __umodti3: u128, u128_div_mod); + +#[cfg(all(windows, target_pointer_width="64"))] +div_mod_intrinsics!(__udivti3, __umodti3: u128, u128_div_mod, ::U64x2, ::conv); macro_rules! udivmod_inner { ($n:expr, $d:expr, $rem:expr, $ty:ty) => {{ @@ -269,6 +290,28 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { udivmod_inner!(n, d, rem, u64) } +macro_rules! udivmodti4 { + ($tyret:ty, $conv:expr) => { + /// Returns `n / d` and sets `*rem = n % d` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> $tyret { + let r = u128_div_mod(n, d, rem); + ($conv)(r) + } + } +} + +/// Returns `n / d` and sets `*rem = n % d` +fn u128_div_mod(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { + udivmod_inner!(n, d, rem, u128) +} + +#[cfg(all(windows, target_pointer_width="64"))] +udivmodti4!(::U64x2, ::conv); + +#[cfg(not(all(windows, target_pointer_width="64")))] +udivmodti4!(u128, |i|{ i }); + #[cfg(test)] mod tests { use qc::{U32, U64}; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index f637ff52b96..559e1a7270c 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -89,6 +89,17 @@ macro_rules! srem { } } +// Hack for LLVM expectations for ABI on windows +#[cfg(all(windows, target_pointer_width="64"))] +#[repr(simd)] +pub struct U64x2(u64, u64); + +#[cfg(all(windows, target_pointer_width="64"))] +fn conv(i: u128) -> U64x2 { + use int::LargeInt; + U64x2(i.low(), i.high()) +} + #[cfg(test)] #[cfg_attr(target_arch = "arm", macro_use)] extern crate quickcheck; -- cgit 1.4.1-3-g733a5 From b1561fc1950c333b6ca36b56412351faa410a562 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 5 Jan 2017 15:23:45 +0100 Subject: u128 sdiv intrinsics --- library/compiler-builtins/README.md | 4 ++-- library/compiler-builtins/build.rs | 2 -- library/compiler-builtins/src/int/sdiv.rs | 26 ++++++++++++++++++++++---- library/compiler-builtins/src/lib.rs | 7 +++++++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 7397810ceae..0810edf5bd1 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -195,7 +195,7 @@ These builtins are needed to support 128-bit integers, which are in the process - [x] ashlti3.c - [x] ashrti3.c -- [ ] divti3.c +- [x] divti3.c - [ ] fixdfti.c - [ ] fixsfti.c - [ ] fixunsdfti.c @@ -205,7 +205,7 @@ These builtins are needed to support 128-bit integers, which are in the process - [ ] floatuntidf.c - [ ] floatuntisf.c - [x] lshrti3.c -- [ ] modti3.c +- [x] modti3.c - [x] muloti4.c - [x] multi3.c - [x] udivmodti4.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 5219a0400b4..ca58b6758b1 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -182,7 +182,6 @@ fn main() { "cmpti2.c", "ctzti2.c", "divtf3.c", - "divti3.c", "ffsti2.c", "fixdfti.c", "fixsfti.c", @@ -196,7 +195,6 @@ fn main() { "floatuntidf.c", "floatuntisf.c", "floatuntixf.c", - "modti3.c", "multf3.c", "mulvti3.c", "negti2.c", diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index b54132290af..84f72f1fdc4 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -2,9 +2,12 @@ use int::Int; macro_rules! div { ($intrinsic:ident: $ty:ty, $uty:ty) => { + div!($intrinsic: $ty, $uty, $ty, |i| {i}); + }; + ($intrinsic:ident: $ty:ty, $uty:ty, $tyret:ty, $conv:expr) => { /// Returns `a / b` #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $tyret { let s_a = a >> (<$ty>::bits() - 1); let s_b = b >> (<$ty>::bits() - 1); let a = (a ^ s_a) - s_a; @@ -12,23 +15,26 @@ macro_rules! div { let s = s_a ^ s_b; let r = udiv!(a as $uty, b as $uty); - (r as $ty ^ s) - s + ($conv)((r as $ty ^ s) - s) } } } macro_rules! mod_ { ($intrinsic:ident: $ty:ty, $uty:ty) => { + mod_!($intrinsic: $ty, $uty, $ty, |i| {i}); + }; + ($intrinsic:ident: $ty:ty, $uty:ty, $tyret:ty, $conv:expr) => { /// Returns `a % b` #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $tyret { let s = b >> (<$ty>::bits() - 1); let b = (b ^ s) - s; let s = a >> (<$ty>::bits() - 1); let a = (a ^ s) - s; let r = urem!(a as $uty, b as $uty); - (r as $ty ^ s) - s + ($conv)((r as $ty ^ s) - s) } } } @@ -61,12 +67,24 @@ div!(__divsi3: i32, u32); #[cfg(not(all(feature = "c", target_arch = "x86")))] div!(__divdi3: i64, u64); +#[cfg(not(all(windows, target_pointer_width="64")))] +div!(__divti3: i128, u128); + +#[cfg(all(windows, target_pointer_width="64"))] +div!(__divti3: i128, u128, ::U64x2, ::sconv); + #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] mod_!(__modsi3: i32, u32); #[cfg(not(all(feature = "c", target_arch = "x86")))] mod_!(__moddi3: i64, u64); +#[cfg(not(all(windows, target_pointer_width="64")))] +mod_!(__modti3: i128, u128); + +#[cfg(all(windows, target_pointer_width="64"))] +mod_!(__modti3: i128, u128, ::U64x2, ::sconv); + #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] divmod!(__divmodsi4, __divsi3: i32); diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 559e1a7270c..0a80ad260c7 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -100,6 +100,13 @@ fn conv(i: u128) -> U64x2 { U64x2(i.low(), i.high()) } +#[cfg(all(windows, target_pointer_width="64"))] +fn sconv(i: i128) -> U64x2 { + use int::LargeInt; + let j = i as u128; + U64x2(j.low(), j.high()) +} + #[cfg(test)] #[cfg_attr(target_arch = "arm", macro_use)] extern crate quickcheck; -- cgit 1.4.1-3-g733a5 From aeda7382d7bf10f16e1ead3184a8ac15696a2a1b Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 6 Jan 2017 06:30:37 +0100 Subject: Add newly implemented intrinsics to test file --- library/compiler-builtins/src/bin/intrinsics.rs | 46 +++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index e0b619f5598..4c5c8842bb9 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -12,6 +12,7 @@ #![feature(lang_items)] #![feature(libc)] #![feature(start)] +#![feature(i128_type)] #![no_std] #[cfg(not(thumb))] @@ -300,6 +301,42 @@ mod intrinsics { pub fn umoddi3(a: u64, b: u64) -> u64 { a % b } + + pub fn muloti4(a: u128, b: u128) -> Option { + a.checked_mul(b) + } + + pub fn multi3(a: u128, b: u128) -> u128 { + a.wrapping_mul(b) + } + + pub fn ashlti3(a: u128, b: usize) -> u128 { + a >> b + } + + pub fn ashrti3(a: u128, b: usize) -> u128 { + a << b + } + + pub fn lshrti3(a: i128, b: usize) -> i128 { + a >> b + } + + pub fn udivti3(a: u128, b: u128) -> u128 { + a / b + } + + pub fn umodti3(a: u128, b: u128) -> u128 { + a % b + } + + pub fn divti3(a: i128, b: i128) -> i128 { + a / b + } + + pub fn modti3(a: i128, b: i128) -> i128 { + a % b + } } #[cfg(feature = "c")] @@ -356,6 +393,15 @@ fn run() { bb(powidf2(bb(2.), bb(3))); bb(powisf2(bb(2.), bb(3))); bb(umoddi3(bb(2), bb(3))); + bb(muloti4(bb(2), bb(2))); + bb(multi3(bb(2), bb(2))); + bb(ashlti3(bb(2), bb(2))); + bb(ashrti3(bb(2), bb(2))); + bb(lshrti3(bb(2), bb(2))); + bb(udivti3(bb(2), bb(2))); + bb(umodti3(bb(2), bb(2))); + bb(divti3(bb(2), bb(2))); + bb(modti3(bb(2), bb(2))); } #[cfg(all(feature = "c", not(thumb)))] -- cgit 1.4.1-3-g733a5 From f15bf972bd1b41fff714eaf2993ddc621f798502 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 3 Feb 2017 22:06:36 +0100 Subject: Add quickcheck tests --- .../compiler-rt/compiler-rt-cdylib/build.rs | 11 ++++++ .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 27 +++++++++++++ library/compiler-builtins/src/int/mul.rs | 24 ++++++++++++ library/compiler-builtins/src/int/sdiv.rs | 26 +++++++++++++ library/compiler-builtins/src/int/shift.rs | 36 +++++++++++++++++ library/compiler-builtins/src/int/udiv.rs | 45 ++++++++++++++++++++++ library/compiler-builtins/src/qc.rs | 2 + 7 files changed, 171 insertions(+) diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs index 4eb76389570..5fc18f1eae9 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs @@ -60,6 +60,17 @@ fn main() { "addsf3.c", "powidf2.c", "powisf2.c", + // 128 bit integers + "lshrti3.c", + "modti3.c", + "muloti4.c", + "multi3.c", + "udivmodti4.c", + "udivti3.c", + "umodti3.c", + "ashlti3.c", + "ashrti3.c", + "divti3.c", ]); for src in sources.files.iter() { diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs index 81affa2421a..268da50d6f1 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -58,6 +58,33 @@ declare!(___adddf3, __adddf3); declare!(___powisf2, __powisf2); declare!(___powidf2, __powidf2); +#[cfg(all(not(windows), target_pointer_width="64"))] +pub mod int_128 { + extern { + fn __lshrti3(); + fn __modti3(); + fn __muloti4(); + fn __multi3(); + fn __udivmodti4(); + fn __udivti3(); + fn __umodti3(); + fn __ashlti3(); + fn __ashrti3(); + fn __divti3(); + } + + declare!(___lshrti3, __lshrti3); + declare!(___modti3, __modti3); + declare!(___muloti4, __muloti4); + declare!(___multi3, __multi3); + declare!(___udivmodti4, __udivmodti4); + declare!(___udivti3, __udivti3); + declare!(___umodti3, __umodti3); + declare!(___ashlti3, __ashlti3); + declare!(___ashrti3, __ashrti3); + declare!(___divti3, __divti3); +} + #[lang = "eh_personality"] fn eh_personality() {} #[lang = "panic_fmt"] diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 45a71283464..c2aece0ea8b 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -120,3 +120,27 @@ mod tests { } } } + +#[cfg(test)] +#[cfg(all(not(windows), target_pointer_width="64"))] +mod tests_i128 { + use qc::I128; + + check! { + fn __multi3(f: extern fn(i128, i128) -> i128, a: I128, b: I128) + -> Option { + Some(f(a.0, b.0)) + } + fn __muloti4(f: extern fn(i128, i128, &mut i32) -> i128, + a: I128, + b: I128) -> Option<(i128, i32)> { + let (a, b) = (a.0, b.0); + let mut overflow = 2; + let r = f(a, b, &mut overflow); + if overflow != 0 && overflow != 1 { + return None + } + Some((r, overflow)) + } + } +} diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 84f72f1fdc4..97e1939919a 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -162,3 +162,29 @@ mod tests { } } } + +#[cfg(test)] +#[cfg(all(not(windows), target_pointer_width="64"))] +mod tests_i128 { + use qc::U128; + + check! { + fn __divti3(f: extern fn(i128, i128) -> i128, n: U128, d: U128) -> Option { + let (n, d) = (n.0 as i128, d.0 as i128); + if d == 0 { + None + } else { + Some(f(n, d)) + } + } + + fn __modti3(f: extern fn(i128, i128) -> i128, n: U128, d: U128) -> Option { + let (n, d) = (n.0 as i128, d.0 as i128); + if d == 0 { + None + } else { + Some(f(n, d)) + } + } + } +} diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 5c8dd5c6a47..2993d9286bc 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -103,3 +103,39 @@ mod tests { } } } + +#[cfg(test)] +#[cfg(all(not(windows), target_pointer_width="64"))] +mod tests_i128 { + use qc::{I128, U128}; + + // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) + check! { + fn __ashlti3(f: extern fn(u128, u32) -> u128, a: U128, b: u32) -> Option { + let a = a.0; + if b >= 64 { + None + } else { + Some(f(a, b)) + } + } + + fn __ashrti3(f: extern fn(i128, u32) -> i128, a: I128, b: u32) -> Option { + let a = a.0; + if b >= 64 { + None + } else { + Some(f(a, b)) + } + } + + fn __lshrti3(f: extern fn(u128, u32) -> u128, a: U128, b: u32) -> Option { + let a = a.0; + if b >= 128 { + None + } else { + Some(f(a, b)) + } + } + } +} diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 44a1149b9b2..735d388c199 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -380,3 +380,48 @@ mod tests { } } } + +#[cfg(test)] +#[cfg(all(not(windows), target_pointer_width="64"))] +mod tests_i128 { + use qc::U128; + + check! { + fn __udivti3(f: extern fn(u128, u128) -> u128, + n: U128, + d: U128) -> Option { + let (n, d) = (n.0, d.0); + if d == 0 { + None + } else { + Some(f(n, d)) + } + } + + fn __umodti3(f: extern fn(u128, u128) -> u128, + n: U128, + d: U128) -> Option { + let (n, d) = (n.0, d.0); + if d == 0 { + None + } else { + Some(f(n, d)) + } + } + + fn __udivmodti4(f: extern fn(u128, u128, Option<&mut u128>) -> u128, + n: U128, + d: U128) -> Option { + let (n, d) = (n.0, d.0); + if d == 0 { + None + } else { + // FIXME fix the segfault when the remainder is requested + /*let mut r = 0; + let q = f(n, d, Some(&mut r)); + Some((q, r))*/ + Some(f(n, d, None)) + } + } + } +} diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 5dbc56f24a8..ea0faaceca5 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -144,6 +144,8 @@ macro_rules! arbitrary_large { arbitrary_large!(I64: i64); arbitrary_large!(U64: u64); +arbitrary_large!(I128: i128); +arbitrary_large!(U128: u128); macro_rules! arbitrary_float { ($TY:ident : $ty:ident) => { -- cgit 1.4.1-3-g733a5 From a01ee168c43131e01816293a6a8cc1ef375767dc Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 4 Feb 2017 01:39:19 +0100 Subject: Panic when invalid overflow value is returned --- library/compiler-builtins/src/int/mul.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index c2aece0ea8b..1ccaf04d634 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -102,7 +102,7 @@ mod tests { let mut overflow = 2; let r = f(a, b, &mut overflow); if overflow != 0 && overflow != 1 { - return None + panic!("Invalid value {} for overflow", overflow); } Some((r, overflow)) } @@ -114,7 +114,7 @@ mod tests { let mut overflow = 2; let r = f(a, b, &mut overflow); if overflow != 0 && overflow != 1 { - return None + panic!("Invalid value {} for overflow", overflow); } Some((r, overflow)) } @@ -138,7 +138,7 @@ mod tests_i128 { let mut overflow = 2; let r = f(a, b, &mut overflow); if overflow != 0 && overflow != 1 { - return None + panic!("Invalid value {} for overflow", overflow); } Some((r, overflow)) } -- cgit 1.4.1-3-g733a5 From 48ef4907b3cc707aa1d0910058e88e93ef883f51 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 3 Feb 2017 20:00:24 -0500 Subject: add rebuild logic to compiler-rt-cdylib fixes #136 --- .../compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs index 4eb76389570..a4d53ccf7ff 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs @@ -62,9 +62,16 @@ fn main() { "powisf2.c", ]); + let builtins_dir = Path::new("compiler-rt/lib/builtins"); for src in sources.files.iter() { - cfg.file(Path::new("compiler-rt/lib/builtins").join(src)); + cfg.file(builtins_dir.join(src)); } cfg.compile("libcompiler-rt.a"); + + println!("cargo:rerun-if-changed=build.rs"); + + for source in sources.files.iter() { + println!("cargo:rerun-if-changed={}", builtins_dir.join(source).display()); + } } -- cgit 1.4.1-3-g733a5 From 70bda6dd1cd5424143f331cedea8f9bea5bd58b9 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 4 Feb 2017 12:17:04 +0100 Subject: Disable quickcheck tests on mips Two reasons: * the C versions __divti3 and __modti3 are apparently broken, at least when used in quickcheck. They change their own arguments. * compiler_rt's support for mips is disabled already on clang [1]. Its desireable to support working "cargo test" on that compiler as well, and not greet the tester with linker errors. [1]: http://llvm.org/viewvc/llvm-project?view=revision&revision=224488 --- .../compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs | 5 ++++- library/compiler-builtins/src/int/mul.rs | 5 ++++- library/compiler-builtins/src/int/sdiv.rs | 7 +++++-- library/compiler-builtins/src/int/shift.rs | 5 ++++- library/compiler-builtins/src/int/udiv.rs | 5 ++++- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs index 268da50d6f1..a7246148321 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -58,7 +58,10 @@ declare!(___adddf3, __adddf3); declare!(___powisf2, __powisf2); declare!(___powidf2, __powidf2); -#[cfg(all(not(windows), target_pointer_width="64"))] +#[cfg(all(not(windows), + not(target_arch = "mips64"), + not(target_arch = "mips64el"), + target_pointer_width="64"))] pub mod int_128 { extern { fn __lshrti3(); diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 1ccaf04d634..27709e52146 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -122,7 +122,10 @@ mod tests { } #[cfg(test)] -#[cfg(all(not(windows), target_pointer_width="64"))] +#[cfg(all(not(windows), + not(target_arch = "mips64"), + not(target_arch = "mips64el"), + target_pointer_width="64"))] mod tests_i128 { use qc::I128; diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 97e1939919a..023fad44d3c 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -164,11 +164,14 @@ mod tests { } #[cfg(test)] -#[cfg(all(not(windows), target_pointer_width="64"))] +#[cfg(all(not(windows), + not(target_arch = "mips64"), + not(target_arch = "mips64el"), + target_pointer_width="64"))] mod tests_i128 { use qc::U128; - check! { + fn __divti3(f: extern fn(i128, i128) -> i128, n: U128, d: U128) -> Option { let (n, d) = (n.0 as i128, d.0 as i128); if d == 0 { diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 2993d9286bc..e5dc38fdac5 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -105,7 +105,10 @@ mod tests { } #[cfg(test)] -#[cfg(all(not(windows), target_pointer_width="64"))] +#[cfg(all(not(windows), + not(target_arch = "mips64"), + not(target_arch = "mips64el"), + target_pointer_width="64"))] mod tests_i128 { use qc::{I128, U128}; diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 735d388c199..57d5fe549d8 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -382,7 +382,10 @@ mod tests { } #[cfg(test)] -#[cfg(all(not(windows), target_pointer_width="64"))] +#[cfg(all(not(windows), + not(target_arch = "mips64"), + not(target_arch = "mips64el"), + target_pointer_width="64"))] mod tests_i128 { use qc::U128; -- cgit 1.4.1-3-g733a5 From a13d0e2b137a568eb74c35acc4f356911dd74cd9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Feb 2017 15:10:02 -0500 Subject: Don't build gcc_personality_v0.c on NetBSD either rust-lang/rust#39425 --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index ca58b6758b1..16c721c6f3a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -226,7 +226,7 @@ fn main() { sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); } } else { - if target_os != "freebsd" { + if target_os != "freebsd" && !target.contains("netbsd") { sources.extend(&["gcc_personality_v0.c"]); } -- cgit 1.4.1-3-g733a5 From 2c7368702bca9037a14ee5225dd87307e2a8c398 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Feb 2017 15:11:09 -0500 Subject: Don't build any native compiler-builtin components for emscripten rust-lang/rust#36339 --- library/compiler-builtins/build.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 16c721c6f3a..6d9801300aa 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -50,6 +50,12 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").unwrap(); + + // Emscripten's runtime includes all the builtins + if target.contains("emscripten") { + return; + } + let Cfg { ref target_arch, ref target_os, ref target_env, ref target_vendor, .. } = Cfg::new(&target).unwrap_or_else(|e| { writeln!(io::stderr(), "{}", e).ok(); -- cgit 1.4.1-3-g733a5 From bdb136a50ea5d086d94fc68e5ca34437b7e7f9da Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Feb 2017 15:11:51 -0500 Subject: libcompiler_builtins: Don't build emutls.c Rather than improving the check, let's ditch emutls.c entirely. rust-lang/rust#38877 --- library/compiler-builtins/build.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6d9801300aa..a0e986dd78f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -223,10 +223,6 @@ fn main() { "atomic_thread_fence.c"]); } - if target_os != "windows" && target_os != "none" { - sources.extend(&["emutls.c"]); - } - if target_env == "msvc" { if target_arch == "x86_64" { sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); -- cgit 1.4.1-3-g733a5 From 263f16a81b6db6d250cc73a66e985e92d5770450 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Feb 2017 15:12:34 -0500 Subject: travis: Expand the `cross` linux image rust-lang/rust#39111 --- library/compiler-builtins/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a0e986dd78f..f29a48322a8 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -116,7 +116,6 @@ fn main() { "addvdi3.c", "addvsi3.c", "apple_versioning.c", - "clear_cache.c", "clzdi2.c", "clzsi2.c", "cmpdi2.c", -- cgit 1.4.1-3-g733a5 From ee172768d27d4dd8ff5b3e4c5f874a580712b55b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Feb 2017 15:13:40 -0500 Subject: std: Remove unused objects from compiler-builtins rust-lang/rust#38623 --- library/compiler-builtins/build.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index f29a48322a8..125813e4659 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -181,12 +181,10 @@ fn main() { if target_os != "ios" { sources.extend(&["absvti2.c", - "addtf3.c", "addvti3.c", "clzti2.c", "cmpti2.c", "ctzti2.c", - "divtf3.c", "ffsti2.c", "fixdfti.c", "fixsfti.c", @@ -200,16 +198,12 @@ fn main() { "floatuntidf.c", "floatuntisf.c", "floatuntixf.c", - "multf3.c", "mulvti3.c", "negti2.c", "negvti2.c", "parityti2.c", "popcountti2.c", - "powitf2.c", - "subtf3.c", "subvti3.c", - "trampoline_setup.c", "ucmpti2.c"]); } -- cgit 1.4.1-3-g733a5 From c261f82cab8bfab1e700dafa2c6019e64d120c17 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Feb 2017 15:16:16 -0500 Subject: target.contains -> target_os == --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 125813e4659..79fbcf3402d 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -221,7 +221,7 @@ fn main() { sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); } } else { - if target_os != "freebsd" && !target.contains("netbsd") { + if target_os != "freebsd" && target_os != "netbsd" { sources.extend(&["gcc_personality_v0.c"]); } -- cgit 1.4.1-3-g733a5 From 3a4e6ce2f413b13797fc5fecfc04150926c662b1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 7 Feb 2017 09:41:26 -0500 Subject: use AAPCS calling convention on all aeabi intrinsics also, on ARM, inline(always) the actual implementation of the intrinsics so we end with code like this: ``` 00000000 <__aeabi_dadd>: (implementation here) ``` instead of "trampolines" like this: ``` 00000000 <__aeabi_dadd>: (shuffle registers) (call __adddf3) 00000000 <__adddf3>: (implementation here) ``` closes #116 --- library/compiler-builtins/src/arm.rs | 40 +++++++++++++++--------------- library/compiler-builtins/src/float/add.rs | 3 ++- library/compiler-builtins/src/int/mul.rs | 3 ++- library/compiler-builtins/src/int/sdiv.rs | 3 ++- library/compiler-builtins/src/int/shift.rs | 4 +++ library/compiler-builtins/src/int/udiv.rs | 3 ++- library/compiler-builtins/src/lib.rs | 4 +++ 7 files changed, 36 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 345ff241dbe..67947a1c8e7 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -62,44 +62,44 @@ pub unsafe fn __aeabi_ldivmod() { // TODO: These aeabi_* functions should be defined as aliases #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_dadd(a: f64, b: f64) -> f64 { +pub extern "aapcs" fn __aeabi_dadd(a: f64, b: f64) -> f64 { ::float::add::__adddf3(a, b) } #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_fadd(a: f32, b: f32) -> f32 { +pub extern "aapcs" fn __aeabi_fadd(a: f32, b: f32) -> f32 { ::float::add::__addsf3(a, b) } #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 { +pub extern "aapcs" fn __aeabi_idiv(a: i32, b: i32) -> i32 { ::int::sdiv::__divsi3(a, b) } #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_lasr(a: i64, b: u32) -> i64 { +pub extern "aapcs" fn __aeabi_lasr(a: i64, b: u32) -> i64 { ::int::shift::__ashrdi3(a, b) } #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_llsl(a: u64, b: u32) -> u64 { +pub extern "aapcs" fn __aeabi_llsl(a: u64, b: u32) -> u64 { ::int::shift::__ashldi3(a, b) } #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_llsr(a: u64, b: u32) -> u64 { +pub extern "aapcs" fn __aeabi_llsr(a: u64, b: u32) -> u64 { ::int::shift::__lshrdi3(a, b) } #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_lmul(a: u64, b: u64) -> u64 { +pub extern "aapcs" fn __aeabi_lmul(a: u64, b: u64) -> u64 { ::int::mul::__muldi3(a, b) } #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { +pub extern "aapcs" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { ::int::udiv::__udivsi3(a, b) } @@ -113,55 +113,55 @@ extern "C" { // FIXME: The `*4` and `*8` variants should be defined as aliases. #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } // Note the different argument order #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { +pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { +pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { +pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memclr(dest: *mut u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { memset(dest, 0, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memclr4(dest: *mut u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { memset(dest, 0, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memclr8(dest: *mut u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { memset(dest, 0, n); } diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 0b2490a8ce9..8bb5b4b39c0 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -7,7 +7,8 @@ macro_rules! add { ($intrinsic:ident: $ty:ty) => { /// Returns `a + b` #[allow(unused_parens)] - #[cfg_attr(not(test), no_mangle)] + #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { let one = Wrapping(1 as <$ty as Float>::Int); let zero = Wrapping(0 as <$ty as Float>::Int); diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 27709e52146..046382ad5b2 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -4,7 +4,8 @@ use int::Int; macro_rules! mul { ($intrinsic:ident: $ty:ty) => { /// Returns `a * b` - #[cfg_attr(not(test), no_mangle)] + #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { let half_bits = <$ty>::bits() / 4; let lower_mask = !0 >> half_bits; diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 023fad44d3c..2676428802b 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -42,7 +42,8 @@ macro_rules! mod_ { macro_rules! divmod { ($intrinsic:ident, $div:ident: $ty:ty) => { /// Returns `a / b` and sets `*rem = n % d` - #[cfg_attr(not(test), no_mangle)] + #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] pub extern "C" fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty { #[cfg(all(feature = "c", any(target_arch = "x86")))] extern { diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index e5dc38fdac5..b93b7bf7afa 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -4,6 +4,8 @@ macro_rules! ashl { ($intrinsic:ident: $ty:ty) => { /// Returns `a << b`, requires `b < $ty::bits()` #[cfg_attr(not(test), no_mangle)] + #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { let half_bits = <$ty>::bits() / 2; if b & half_bits != 0 { @@ -21,6 +23,8 @@ macro_rules! ashr { ($intrinsic:ident: $ty:ty) => { /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` #[cfg_attr(not(test), no_mangle)] + #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { let half_bits = <$ty>::bits() / 2; if b & half_bits != 0 { diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 57d5fe549d8..820c4cfba69 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -3,7 +3,8 @@ use int::{Int, LargeInt}; /// Returns `n / d` #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] +#[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { // Special cases if d == 0 { diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0a80ad260c7..0da336e950b 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -28,6 +28,10 @@ // NOTE cfg(all(feature = "c", ..)) indicate that compiler-rt provides an arch optimized // implementation of that intrinsic and we'll prefer to use that +// NOTE(aapcs, aeabi, arm) ARM targets use intrinsics named __aeabi_* instead of the intrinsics +// that follow "x86 naming convention" (e.g. addsf3). Those aeabi intrinsics must adhere to the +// AAPCS calling convention (`extern "aapcs"`) because that's how LLVM will call them. + // TODO(rust-lang/rust#37029) use e.g. checked_div(_).unwrap_or_else(|| abort()) macro_rules! udiv { ($a:expr, $b:expr) => { -- cgit 1.4.1-3-g733a5 From 57deccf6defa78af40ee413b304d986d8b7dea41 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 7 Feb 2017 12:51:18 -0500 Subject: ARM: keep some non-aeabi symbols around - multi3: there's no aeabi equivalent - divmod{s,d}i4: these are directly called by __aeabi_{l,i}divmod - add{s,d}f3: required by the C sub{s,d}f3 implementation but make sure they also use the AAPCS calling convention --- library/compiler-builtins/src/float/add.rs | 20 ++++++++++++++------ library/compiler-builtins/src/int/mul.rs | 20 ++++++++++++++------ library/compiler-builtins/src/int/sdiv.rs | 15 +++++++++------ library/compiler-builtins/src/int/udiv.rs | 6 +++--- 4 files changed, 40 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 8bb5b4b39c0..65a718634fe 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -4,12 +4,11 @@ use core::num::Wrapping; use float::Float; macro_rules! add { - ($intrinsic:ident: $ty:ty) => { + ($abi:tt, $intrinsic:ident: $ty:ty) => { /// Returns `a + b` #[allow(unused_parens)] - #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { + #[cfg_attr(not(test), no_mangle)] + pub extern $abi fn $intrinsic(a: $ty, b: $ty) -> $ty { let one = Wrapping(1 as <$ty as Float>::Int); let zero = Wrapping(0 as <$ty as Float>::Int); @@ -182,8 +181,17 @@ macro_rules! add { } } -add!(__addsf3: f32); -add!(__adddf3: f64); +#[cfg(target_arch = "arm")] +add!("aapcs", __addsf3: f32); + +#[cfg(not(target_arch = "arm"))] +add!("C", __addsf3: f32); + +#[cfg(target_arch = "arm")] +add!("aapcs", __adddf3: f64); + +#[cfg(not(target_arch = "arm"))] +add!("C", __adddf3: f64); // NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabi*, our implementation doesn't // match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 046382ad5b2..64ceb723124 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -2,11 +2,11 @@ use int::LargeInt; use int::Int; macro_rules! mul { - ($intrinsic:ident: $ty:ty) => { + ($(#[$attr:meta])+ | + $abi:tt, $intrinsic:ident: $ty:ty) => { /// Returns `a * b` - #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + $(#[$attr])+ + pub extern $abi fn $intrinsic(a: $ty, b: $ty) -> $ty { let half_bits = <$ty>::bits() / 4; let lower_mask = !0 >> half_bits; let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask); @@ -74,9 +74,17 @@ macro_rules! mulo { } #[cfg(not(all(feature = "c", target_arch = "x86")))] -mul!(__muldi3: u64); +mul!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] + | "C", __muldi3: u64); + +#[cfg(not(target_arch = "arm"))] +mul!(#[cfg_attr(not(test), no_mangle)] + | "C", __multi3: i128); -mul!(__multi3: i128); +#[cfg(target_arch = "arm")] +mul!(#[cfg_attr(not(test), no_mangle)] + | "aapcs", __multi3: i128); mulo!(__mulosi4: i32); mulo!(__mulodi4: i64); diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 2676428802b..7a3e6e75733 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -40,11 +40,10 @@ macro_rules! mod_ { } macro_rules! divmod { - ($intrinsic:ident, $div:ident: $ty:ty) => { + ($abi:tt, $intrinsic:ident, $div:ident: $ty:ty) => { /// Returns `a / b` and sets `*rem = n % d` - #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - pub extern "C" fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty { + #[cfg_attr(not(test), no_mangle)] + pub extern $abi fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty { #[cfg(all(feature = "c", any(target_arch = "x86")))] extern { fn $div(a: $ty, b: $ty) -> $ty; @@ -87,9 +86,13 @@ mod_!(__modti3: i128, u128); mod_!(__modti3: i128, u128, ::U64x2, ::sconv); #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] -divmod!(__divmodsi4, __divsi3: i32); +divmod!("C", __divmodsi4, __divsi3: i32); + +#[cfg(target_arch = "arm")] +divmod!("aapcs", __divmoddi4, __divdi3: i64); -divmod!(__divmoddi4, __divdi3: i64); +#[cfg(not(target_arch = "arm"))] +divmod!("C", __divmoddi4, __divdi3: i64); #[cfg(test)] mod tests { diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 820c4cfba69..453ab005e0a 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -80,15 +80,15 @@ pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { - #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] + #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] extern "C" { fn __udivsi3(n: u32, d: u32) -> u32; } let q = match () { - #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] + #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] () => unsafe { __udivsi3(n, d) }, - #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] + #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] () => __udivsi3(n, d), }; if let Some(rem) = rem { -- cgit 1.4.1-3-g733a5 From 0dfe91f7cf2f0c6b498aee45c1575ecd726fa6e4 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 7 Feb 2017 23:07:51 -0500 Subject: adjust the check! macro to accept AAPCS intrinsics --- library/compiler-builtins/src/float/add.rs | 4 ++-- library/compiler-builtins/src/float/pow.rs | 4 ++-- library/compiler-builtins/src/int/mul.rs | 10 +++++----- library/compiler-builtins/src/int/sdiv.rs | 31 ++++++++++++++++++++++-------- library/compiler-builtins/src/int/shift.rs | 12 ++++++------ library/compiler-builtins/src/int/udiv.rs | 18 ++++++++--------- library/compiler-builtins/src/qc.rs | 7 +++++-- 7 files changed, 52 insertions(+), 34 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 65a718634fe..992d149f458 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -203,14 +203,14 @@ mod tests { use qc::{F32, F64}; check! { - fn __addsf3(f: extern fn(f32, f32) -> f32, + fn __addsf3(f: extern "C" fn(f32, f32) -> f32, a: F32, b: F32) -> Option { Some(F32(f(a.0, b.0))) } - fn __adddf3(f: extern fn(f64, f64) -> f64, + fn __adddf3(f: extern "C" fn(f64, f64) -> f64, a: F64, b: F64) -> Option { Some(F64(f(a.0, b.0))) diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 290d0f54d95..52aba5df68c 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -34,13 +34,13 @@ mod tests { use qc::{I32, F32, F64}; check! { - fn __powisf2(f: extern fn(f32, i32) -> f32, + fn __powisf2(f: extern "C" fn(f32, i32) -> f32, a: F32, b: I32) -> Option { Some(F32(f(a.0, b.0))) } - fn __powidf2(f: extern fn(f64, i32) -> f64, + fn __powidf2(f: extern "C" fn(f64, i32) -> f64, a: F64, b: I32) -> Option { Some(F64(f(a.0, b.0))) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 64ceb723124..7b0d033b0b4 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -99,12 +99,12 @@ mod tests { use qc::{I32, I64, U64}; check! { - fn __muldi3(f: extern fn(u64, u64) -> u64, a: U64, b: U64) + fn __muldi3(f: extern "C" fn(u64, u64) -> u64, a: U64, b: U64) -> Option { Some(f(a.0, b.0)) } - fn __mulosi4(f: extern fn(i32, i32, &mut i32) -> i32, + fn __mulosi4(f: extern "C" fn(i32, i32, &mut i32) -> i32, a: I32, b: I32) -> Option<(i32, i32)> { let (a, b) = (a.0, b.0); @@ -116,7 +116,7 @@ mod tests { Some((r, overflow)) } - fn __mulodi4(f: extern fn(i64, i64, &mut i32) -> i64, + fn __mulodi4(f: extern "C" fn(i64, i64, &mut i32) -> i64, a: I64, b: I64) -> Option<(i64, i32)> { let (a, b) = (a.0, b.0); @@ -139,11 +139,11 @@ mod tests_i128 { use qc::I128; check! { - fn __multi3(f: extern fn(i128, i128) -> i128, a: I128, b: I128) + fn __multi3(f: extern "C" fn(i128, i128) -> i128, a: I128, b: I128) -> Option { Some(f(a.0, b.0)) } - fn __muloti4(f: extern fn(i128, i128, &mut i32) -> i128, + fn __muloti4(f: extern "C" fn(i128, i128, &mut i32) -> i128, a: I128, b: I128) -> Option<(i128, i32)> { let (a, b) = (a.0, b.0); diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 7a3e6e75733..51d9c376976 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -99,7 +99,7 @@ mod tests { use qc::{U32, U64}; check! { - fn __divdi3(f: extern fn(i64, i64) -> i64, n: U64, d: U64) -> Option { + fn __divdi3(f: extern "C" fn(i64, i64) -> i64, n: U64, d: U64) -> Option { let (n, d) = (n.0 as i64, d.0 as i64); if d == 0 { None @@ -108,7 +108,7 @@ mod tests { } } - fn __moddi3(f: extern fn(i64, i64) -> i64, n: U64, d: U64) -> Option { + fn __moddi3(f: extern "C" fn(i64, i64) -> i64, n: U64, d: U64) -> Option { let (n, d) = (n.0 as i64, d.0 as i64); if d == 0 { None @@ -117,7 +117,8 @@ mod tests { } } - fn __divmoddi4(f: extern fn(i64, i64, &mut i64) -> i64, + #[cfg(target_arch = "arm")] + fn __divmoddi4(f: extern "aapcs" fn(i64, i64, &mut i64) -> i64, n: U64, d: U64) -> Option<(i64, i64)> { let (n, d) = (n.0 as i64, d.0 as i64); @@ -130,7 +131,21 @@ mod tests { } } - fn __divsi3(f: extern fn(i32, i32) -> i32, + #[cfg(not(target_arch = "arm"))] + fn __divmoddi4(f: extern "C" fn(i64, i64, &mut i64) -> i64, + n: U64, + d: U64) -> Option<(i64, i64)> { + let (n, d) = (n.0 as i64, d.0 as i64); + if d == 0 { + None + } else { + let mut r = 0; + let q = f(n, d, &mut r); + Some((q, r)) + } + } + + fn __divsi3(f: extern "C" fn(i32, i32) -> i32, n: U32, d: U32) -> Option { let (n, d) = (n.0 as i32, d.0 as i32); @@ -141,7 +156,7 @@ mod tests { } } - fn __modsi3(f: extern fn(i32, i32) -> i32, + fn __modsi3(f: extern "C" fn(i32, i32) -> i32, n: U32, d: U32) -> Option { let (n, d) = (n.0 as i32, d.0 as i32); @@ -152,7 +167,7 @@ mod tests { } } - fn __divmodsi4(f: extern fn(i32, i32, &mut i32) -> i32, + fn __divmodsi4(f: extern "C" fn(i32, i32, &mut i32) -> i32, n: U32, d: U32) -> Option<(i32, i32)> { let (n, d) = (n.0 as i32, d.0 as i32); @@ -176,7 +191,7 @@ mod tests_i128 { use qc::U128; check! { - fn __divti3(f: extern fn(i128, i128) -> i128, n: U128, d: U128) -> Option { + fn __divti3(f: extern "C" fn(i128, i128) -> i128, n: U128, d: U128) -> Option { let (n, d) = (n.0 as i128, d.0 as i128); if d == 0 { None @@ -185,7 +200,7 @@ mod tests_i128 { } } - fn __modti3(f: extern fn(i128, i128) -> i128, n: U128, d: U128) -> Option { + fn __modti3(f: extern "C" fn(i128, i128) -> i128, n: U128, d: U128) -> Option { let (n, d) = (n.0 as i128, d.0 as i128); if d == 0 { None diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index b93b7bf7afa..fdd2f6ce2b5 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -79,7 +79,7 @@ mod tests { // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) check! { - fn __ashldi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option { + fn __ashldi3(f: extern "C" fn(u64, u32) -> u64, a: U64, b: u32) -> Option { let a = a.0; if b >= 64 { None @@ -88,7 +88,7 @@ mod tests { } } - fn __ashrdi3(f: extern fn(i64, u32) -> i64, a: I64, b: u32) -> Option { + fn __ashrdi3(f: extern "C" fn(i64, u32) -> i64, a: I64, b: u32) -> Option { let a = a.0; if b >= 64 { None @@ -97,7 +97,7 @@ mod tests { } } - fn __lshrdi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option { + fn __lshrdi3(f: extern "C" fn(u64, u32) -> u64, a: U64, b: u32) -> Option { let a = a.0; if b >= 64 { None @@ -118,7 +118,7 @@ mod tests_i128 { // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) check! { - fn __ashlti3(f: extern fn(u128, u32) -> u128, a: U128, b: u32) -> Option { + fn __ashlti3(f: extern "C" fn(u128, u32) -> u128, a: U128, b: u32) -> Option { let a = a.0; if b >= 64 { None @@ -127,7 +127,7 @@ mod tests_i128 { } } - fn __ashrti3(f: extern fn(i128, u32) -> i128, a: I128, b: u32) -> Option { + fn __ashrti3(f: extern "C" fn(i128, u32) -> i128, a: I128, b: u32) -> Option { let a = a.0; if b >= 64 { None @@ -136,7 +136,7 @@ mod tests_i128 { } } - fn __lshrti3(f: extern fn(u128, u32) -> u128, a: U128, b: u32) -> Option { + fn __lshrti3(f: extern "C" fn(u128, u32) -> u128, a: U128, b: u32) -> Option { let a = a.0; if b >= 128 { None diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 453ab005e0a..6c125bb750c 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -318,7 +318,7 @@ mod tests { use qc::{U32, U64}; check! { - fn __udivdi3(f: extern fn(u64, u64) -> u64, n: U64, d: U64) -> Option { + fn __udivdi3(f: extern "C" fn(u64, u64) -> u64, n: U64, d: U64) -> Option { let (n, d) = (n.0, d.0); if d == 0 { None @@ -327,7 +327,7 @@ mod tests { } } - fn __umoddi3(f: extern fn(u64, u64) -> u64, n: U64, d: U64) -> Option { + fn __umoddi3(f: extern "C" fn(u64, u64) -> u64, n: U64, d: U64) -> Option { let (n, d) = (n.0, d.0); if d == 0 { None @@ -336,7 +336,7 @@ mod tests { } } - fn __udivmoddi4(f: extern fn(u64, u64, Option<&mut u64>) -> u64, + fn __udivmoddi4(f: extern "C" fn(u64, u64, Option<&mut u64>) -> u64, n: U64, d: U64) -> Option<(u64, u64)> { let (n, d) = (n.0, d.0); @@ -349,7 +349,7 @@ mod tests { } } - fn __udivsi3(f: extern fn(u32, u32) -> u32, n: U32, d: U32) -> Option { + fn __udivsi3(f: extern "C" fn(u32, u32) -> u32, n: U32, d: U32) -> Option { let (n, d) = (n.0, d.0); if d == 0 { None @@ -358,7 +358,7 @@ mod tests { } } - fn __umodsi3(f: extern fn(u32, u32) -> u32, n: U32, d: U32) -> Option { + fn __umodsi3(f: extern "C" fn(u32, u32) -> u32, n: U32, d: U32) -> Option { let (n, d) = (n.0, d.0); if d == 0 { None @@ -367,7 +367,7 @@ mod tests { } } - fn __udivmodsi4(f: extern fn(u32, u32, Option<&mut u32>) -> u32, + fn __udivmodsi4(f: extern "C" fn(u32, u32, Option<&mut u32>) -> u32, n: U32, d: U32) -> Option<(u32, u32)> { let (n, d) = (n.0, d.0); @@ -391,7 +391,7 @@ mod tests_i128 { use qc::U128; check! { - fn __udivti3(f: extern fn(u128, u128) -> u128, + fn __udivti3(f: extern "C" fn(u128, u128) -> u128, n: U128, d: U128) -> Option { let (n, d) = (n.0, d.0); @@ -402,7 +402,7 @@ mod tests_i128 { } } - fn __umodti3(f: extern fn(u128, u128) -> u128, + fn __umodti3(f: extern "C" fn(u128, u128) -> u128, n: U128, d: U128) -> Option { let (n, d) = (n.0, d.0); @@ -413,7 +413,7 @@ mod tests_i128 { } } - fn __udivmodti4(f: extern fn(u128, u128, Option<&mut u128>) -> u128, + fn __udivmodti4(f: extern "C" fn(u128, u128, Option<&mut u128>) -> u128, n: U128, d: U128) -> Option { let (n, d) = (n.0, d.0); diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index ea0faaceca5..306508f6c48 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -240,7 +240,8 @@ arbitrary_float!(F64: f64); // fails. macro_rules! check { ($( - fn $name:ident($f:ident: extern fn($($farg:ty),*) -> $fret:ty, + $(#[$cfg:meta])* + fn $name:ident($f:ident: extern $abi:tt fn($($farg:ty),*) -> $fret:ty, $($arg:ident: $t:ty),*) -> Option<$ret:ty> { @@ -248,7 +249,8 @@ macro_rules! check { } )*) => ( $( - fn $name($f: extern fn($($farg),*) -> $fret, + $(#[$cfg])* + fn $name($f: extern $abi fn($($farg),*) -> $fret, $($arg: $t),*) -> Option<$ret> { $($code)* } @@ -260,6 +262,7 @@ macro_rules! check { use quickcheck::TestResult; $( + $(#[$cfg])* #[test] fn $name() { fn my_check($($arg:$t),*) -> TestResult { -- cgit 1.4.1-3-g733a5 From 9916fa670c2ec00e3b1085f27d3144fb3d3d5f60 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 8 Feb 2017 10:10:40 -0500 Subject: implement float subtraction as a + (-b) --- library/compiler-builtins/build.rs | 2 - .../compiler-rt/compiler-rt-cdylib/build.rs | 2 + .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 4 ++ library/compiler-builtins/src/arm.rs | 12 +++++- library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/src/float/sub.rs | 45 ++++++++++++++++++++++ 6 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/src/float/sub.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 79fbcf3402d..532e23217ee 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -170,8 +170,6 @@ fn main() { "popcountdi2.c", "popcountsi2.c", "powixf2.c", - "subdf3.c", - "subsf3.c", "subvdi3.c", "subvsi3.c", "truncdfhf2.c", diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs index 269070c4a34..0f36143e2f8 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs @@ -60,6 +60,8 @@ fn main() { "addsf3.c", "powidf2.c", "powisf2.c", + "subdf3.c", + "subsf3.c", // 128 bit integers "lshrti3.c", "modti3.c", diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs index a7246148321..b76e1fd6fa1 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -24,6 +24,8 @@ extern { fn __adddf3(); fn __powisf2(); fn __powidf2(); + fn __subsf3(); + fn __subdf3(); } macro_rules! declare { @@ -57,6 +59,8 @@ declare!(___addsf3, __addsf3); declare!(___adddf3, __adddf3); declare!(___powisf2, __powisf2); declare!(___powidf2, __powidf2); +declare!(___subsf3, __subsf3); +declare!(___subdf3, __subdf3); #[cfg(all(not(windows), not(target_arch = "mips64"), diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 67947a1c8e7..f2027e7b890 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -60,7 +60,6 @@ pub unsafe fn __aeabi_ldivmod() { intrinsics::unreachable(); } -// TODO: These aeabi_* functions should be defined as aliases #[cfg_attr(not(test), no_mangle)] pub extern "aapcs" fn __aeabi_dadd(a: f64, b: f64) -> f64 { ::float::add::__adddf3(a, b) @@ -71,6 +70,16 @@ pub extern "aapcs" fn __aeabi_fadd(a: f32, b: f32) -> f32 { ::float::add::__addsf3(a, b) } +#[cfg_attr(not(test), no_mangle)] +pub extern "aapcs" fn __aeabi_dsub(a: f64, b: f64) -> f64 { + ::float::sub::__subdf3(a, b) +} + +#[cfg_attr(not(test), no_mangle)] +pub extern "aapcs" fn __aeabi_fsub(a: f32, b: f32) -> f32 { + ::float::sub::__subsf3(a, b) +} + #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] pub extern "aapcs" fn __aeabi_idiv(a: i32, b: i32) -> i32 { @@ -103,6 +112,7 @@ pub extern "aapcs" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { ::int::udiv::__udivsi3(a, b) } +// TODO: These aeabi_* functions should be defined as aliases #[cfg(not(feature = "mem"))] extern "C" { fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 134c32dc745..08a1b6d727f 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -2,6 +2,7 @@ use core::mem; pub mod add; pub mod pow; +pub mod sub; /// Trait for some basic operations on floats pub trait Float: Sized + Copy { diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs new file mode 100644 index 00000000000..928d7382103 --- /dev/null +++ b/library/compiler-builtins/src/float/sub.rs @@ -0,0 +1,45 @@ +use float::Float; + +macro_rules! sub { + ($(#[$attr:meta])* + | $intrinsic:ident: $ty:ty) => { + /// Returns `a - b` + $(#[$attr])* + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + a + <$ty>::from_repr(b.repr() ^ <$ty>::sign_mask()) + } + } +} + +sub!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] + | __subsf3: f32); + +sub!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] + | __subdf3: f64); + +// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabi*, our implementation doesn't +// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll +// just avoid testing against them on those targets. Do note that our implementation gives the +// correct answer; gcc_s and compiler-rt are incorrect in this case. +#[cfg(all(test, not(arm_linux)))] +mod tests { + use core::{f32, f64}; + use qc::{F32, F64}; + + check! { + fn __subsf3(f: extern "C" fn(f32, f32) -> f32, + a: F32, + b: F32) + -> Option { + Some(F32(f(a.0, b.0))) + } + + fn __subdf3(f: extern "C" fn(f64, f64) -> f64, + a: F64, + b: F64) -> Option { + Some(F64(f(a.0, b.0))) + } + } +} -- cgit 1.4.1-3-g733a5 From f96c8b825044b4374bdefcc4ed3c2905fbe2862f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 19 Feb 2017 15:49:59 -0500 Subject: make the gcc crate optional it's only required when the "c" feature is enabled --- library/compiler-builtins/Cargo.toml | 7 +- library/compiler-builtins/build.rs | 638 ++++++++++++++++++----------------- 2 files changed, 329 insertions(+), 316 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 5fb89f462bc..a82aad55fe4 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -6,7 +6,10 @@ version = "0.1.0" [build-dependencies] rustc-cfg = "0.3.0" -gcc = "0.3.36" + +[build-dependencies.gcc] +optional = true +version = "0.3.36" [dev-dependencies] quickcheck = "0.3.1" @@ -16,7 +19,7 @@ compiler-rt = { path = "compiler-rt" } [features] # Build the missing intrinsics from compiler-rt C source code -c = [] +c = ["gcc"] # Mark this crate as the #![compiler_builtins] crate compiler-builtins = [] default = ["compiler-builtins"] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 532e23217ee..6c96284731b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,18 +1,23 @@ +#[cfg(feature = "c")] extern crate gcc; extern crate rustc_cfg; +#[cfg(feature = "c")] use std::collections::BTreeMap; use std::io::Write; +#[cfg(feature = "c")] use std::path::Path; use std::{env, io, process}; use rustc_cfg::Cfg; +#[cfg(feature = "c")] struct Sources { // SYMBOL -> PATH TO SOURCE map: BTreeMap<&'static str, &'static str>, } +#[cfg(feature = "c")] impl Sources { fn new() -> Sources { Sources { map: BTreeMap::new() } @@ -65,346 +70,351 @@ fn main() { // target triple. This is usually correct for our built-in targets but can break in presence of // custom targets, which can have arbitrary names. let llvm_target = target.split('-').collect::>(); - let target_vendor = target_vendor.as_ref().unwrap(); // Build missing intrinsics from compiler-rt C source code - if env::var_os("CARGO_FEATURE_C").is_some() { - let cfg = &mut gcc::Config::new(); - - if target_env == "msvc" { - // Don't pull in extra libraries on MSVC - cfg.flag("/Zl"); - - // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP - cfg.define("__func__", Some("__FUNCTION__")); - } else { - // Turn off various features of gcc and such, mostly copying - // compiler-rt's build system already - cfg.flag("-fno-builtin"); - cfg.flag("-fvisibility=hidden"); - cfg.flag("-fomit-frame-pointer"); - cfg.flag("-ffreestanding"); - cfg.define("VISIBILITY_HIDDEN", None); - } + match () { + #[cfg(feature = "c")] + () => { + let target_vendor = target_vendor.as_ref().unwrap(); + let cfg = &mut gcc::Config::new(); + + if target_env == "msvc" { + // Don't pull in extra libraries on MSVC + cfg.flag("/Zl"); + + // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP + cfg.define("__func__", Some("__FUNCTION__")); + } else { + // Turn off various features of gcc and such, mostly copying + // compiler-rt's build system already + cfg.flag("-fno-builtin"); + cfg.flag("-fvisibility=hidden"); + cfg.flag("-fomit-frame-pointer"); + cfg.flag("-ffreestanding"); + cfg.define("VISIBILITY_HIDDEN", None); + } - // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to - // target to make sure that the assembly implementations really work for the target. If the - // implementation is not valid for the arch, then gcc will error when compiling it. - if llvm_target[0].starts_with("thumb") { - cfg.flag("-mthumb"); + // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to + // target to make sure that the assembly implementations really work for the target. If the + // implementation is not valid for the arch, then gcc will error when compiling it. + if llvm_target[0].starts_with("thumb") { + cfg.flag("-mthumb"); - if llvm_target.last() == Some(&"eabihf") { - cfg.flag("-mfloat-abi=hard"); + if llvm_target.last() == Some(&"eabihf") { + cfg.flag("-mfloat-abi=hard"); + } } - } - if llvm_target[0] == "thumbv6m" { - cfg.flag("-march=armv6-m"); - } - - if llvm_target[0] == "thumbv7m" { - cfg.flag("-march=armv7-m"); - } + if llvm_target[0] == "thumbv6m" { + cfg.flag("-march=armv6-m"); + } - if llvm_target[0] == "thumbv7em" { - cfg.flag("-march=armv7e-m"); - } + if llvm_target[0] == "thumbv7m" { + cfg.flag("-march=armv7-m"); + } - let mut sources = Sources::new(); - sources.extend(&["absvdi2.c", - "absvsi2.c", - "addvdi3.c", - "addvsi3.c", - "apple_versioning.c", - "clzdi2.c", - "clzsi2.c", - "cmpdi2.c", - "comparedf2.c", - "comparesf2.c", - "ctzdi2.c", - "ctzsi2.c", - "divdc3.c", - "divdf3.c", - "divsc3.c", - "divsf3.c", - "divxc3.c", - "extendsfdf2.c", - "extendhfsf2.c", - "ffsdi2.c", - "fixdfdi.c", - "fixdfsi.c", - "fixsfdi.c", - "fixsfsi.c", - "fixunsdfdi.c", - "fixunsdfsi.c", - "fixunssfdi.c", - "fixunssfsi.c", - "fixunsxfdi.c", - "fixunsxfsi.c", - "fixxfdi.c", - "floatdidf.c", - "floatdisf.c", - "floatdixf.c", - "floatsidf.c", - "floatsisf.c", - "floatundidf.c", - "floatundisf.c", - "floatundixf.c", - "floatunsidf.c", - "floatunsisf.c", - "int_util.c", - "muldc3.c", - "muldf3.c", - "mulsc3.c", - "mulsf3.c", - "mulvdi3.c", - "mulvsi3.c", - "mulxc3.c", - "negdf2.c", - "negdi2.c", - "negsf2.c", - "negvdi2.c", - "negvsi2.c", - "paritydi2.c", - "paritysi2.c", - "popcountdi2.c", - "popcountsi2.c", - "powixf2.c", - "subvdi3.c", - "subvsi3.c", - "truncdfhf2.c", - "truncdfsf2.c", - "truncsfhf2.c", - "ucmpdi2.c"]); - - if target_os != "ios" { - sources.extend(&["absvti2.c", - "addvti3.c", - "clzti2.c", - "cmpti2.c", - "ctzti2.c", - "ffsti2.c", - "fixdfti.c", - "fixsfti.c", - "fixunsdfti.c", - "fixunssfti.c", - "fixunsxfti.c", - "fixxfti.c", - "floattidf.c", - "floattisf.c", - "floattixf.c", - "floatuntidf.c", - "floatuntisf.c", - "floatuntixf.c", - "mulvti3.c", - "negti2.c", - "negvti2.c", - "parityti2.c", - "popcountti2.c", - "subvti3.c", - "ucmpti2.c"]); - } + if llvm_target[0] == "thumbv7em" { + cfg.flag("-march=armv7e-m"); + } - if target_vendor == "apple" { - sources.extend(&["atomic_flag_clear.c", - "atomic_flag_clear_explicit.c", - "atomic_flag_test_and_set.c", - "atomic_flag_test_and_set_explicit.c", - "atomic_signal_fence.c", - "atomic_thread_fence.c"]); - } + let mut sources = Sources::new(); + sources.extend(&["absvdi2.c", + "absvsi2.c", + "addvdi3.c", + "addvsi3.c", + "apple_versioning.c", + "clzdi2.c", + "clzsi2.c", + "cmpdi2.c", + "comparedf2.c", + "comparesf2.c", + "ctzdi2.c", + "ctzsi2.c", + "divdc3.c", + "divdf3.c", + "divsc3.c", + "divsf3.c", + "divxc3.c", + "extendsfdf2.c", + "extendhfsf2.c", + "ffsdi2.c", + "fixdfdi.c", + "fixdfsi.c", + "fixsfdi.c", + "fixsfsi.c", + "fixunsdfdi.c", + "fixunsdfsi.c", + "fixunssfdi.c", + "fixunssfsi.c", + "fixunsxfdi.c", + "fixunsxfsi.c", + "fixxfdi.c", + "floatdidf.c", + "floatdisf.c", + "floatdixf.c", + "floatsidf.c", + "floatsisf.c", + "floatundidf.c", + "floatundisf.c", + "floatundixf.c", + "floatunsidf.c", + "floatunsisf.c", + "int_util.c", + "muldc3.c", + "muldf3.c", + "mulsc3.c", + "mulsf3.c", + "mulvdi3.c", + "mulvsi3.c", + "mulxc3.c", + "negdf2.c", + "negdi2.c", + "negsf2.c", + "negvdi2.c", + "negvsi2.c", + "paritydi2.c", + "paritysi2.c", + "popcountdi2.c", + "popcountsi2.c", + "powixf2.c", + "subvdi3.c", + "subvsi3.c", + "truncdfhf2.c", + "truncdfsf2.c", + "truncsfhf2.c", + "ucmpdi2.c"]); + + if target_os != "ios" { + sources.extend(&["absvti2.c", + "addvti3.c", + "clzti2.c", + "cmpti2.c", + "ctzti2.c", + "ffsti2.c", + "fixdfti.c", + "fixsfti.c", + "fixunsdfti.c", + "fixunssfti.c", + "fixunsxfti.c", + "fixxfti.c", + "floattidf.c", + "floattisf.c", + "floattixf.c", + "floatuntidf.c", + "floatuntisf.c", + "floatuntixf.c", + "mulvti3.c", + "negti2.c", + "negvti2.c", + "parityti2.c", + "popcountti2.c", + "subvti3.c", + "ucmpti2.c"]); + } - if target_env == "msvc" { - if target_arch == "x86_64" { - sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); + if target_vendor == "apple" { + sources.extend(&["atomic_flag_clear.c", + "atomic_flag_clear_explicit.c", + "atomic_flag_test_and_set.c", + "atomic_flag_test_and_set_explicit.c", + "atomic_signal_fence.c", + "atomic_thread_fence.c"]); } - } else { - if target_os != "freebsd" && target_os != "netbsd" { - sources.extend(&["gcc_personality_v0.c"]); + + if target_env == "msvc" { + if target_arch == "x86_64" { + sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); + } + } else { + if target_os != "freebsd" && target_os != "netbsd" { + sources.extend(&["gcc_personality_v0.c"]); + } + + if target_arch == "x86_64" { + sources.extend(&["x86_64/chkstk.S", + "x86_64/chkstk2.S", + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S"]); + } + + if target_arch == "x86" { + sources.extend(&["i386/ashldi3.S", + "i386/ashrdi3.S", + "i386/chkstk.S", + "i386/chkstk2.S", + "i386/divdi3.S", + "i386/floatdidf.S", + "i386/floatdisf.S", + "i386/floatdixf.S", + "i386/floatundidf.S", + "i386/floatundisf.S", + "i386/floatundixf.S", + "i386/lshrdi3.S", + "i386/moddi3.S", + "i386/muldi3.S", + "i386/udivdi3.S", + "i386/umoddi3.S"]); + } } - if target_arch == "x86_64" { - sources.extend(&["x86_64/chkstk.S", - "x86_64/chkstk2.S", - "x86_64/floatdidf.c", - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S"]); + if target_arch == "arm" && target_os != "ios" { + sources.extend(&["arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + "arm/aeabi_dcmp.S", + "arm/aeabi_div0.c", + "arm/aeabi_drsub.c", + "arm/aeabi_fcmp.S", + "arm/aeabi_frsub.c", + "arm/bswapdi2.S", + "arm/bswapsi2.S", + "arm/clzdi2.S", + "arm/clzsi2.S", + "arm/comparesf2.S", + "arm/divmodsi4.S", + "arm/divsi3.S", + "arm/modsi3.S", + "arm/switch16.S", + "arm/switch32.S", + "arm/switch8.S", + "arm/switchu8.S", + "arm/sync_synchronize.S", + "arm/udivmodsi4.S", + "arm/udivsi3.S", + "arm/umodsi3.S"]); } - if target_arch == "x86" { - sources.extend(&["i386/ashldi3.S", - "i386/ashrdi3.S", - "i386/chkstk.S", - "i386/chkstk2.S", - "i386/divdi3.S", - "i386/floatdidf.S", - "i386/floatdisf.S", - "i386/floatdixf.S", - "i386/floatundidf.S", - "i386/floatundisf.S", - "i386/floatundixf.S", - "i386/lshrdi3.S", - "i386/moddi3.S", - "i386/muldi3.S", - "i386/udivdi3.S", - "i386/umoddi3.S"]); + if llvm_target[0] == "armv7" { + sources.extend(&["arm/sync_fetch_and_add_4.S", + "arm/sync_fetch_and_add_8.S", + "arm/sync_fetch_and_and_4.S", + "arm/sync_fetch_and_and_8.S", + "arm/sync_fetch_and_max_4.S", + "arm/sync_fetch_and_max_8.S", + "arm/sync_fetch_and_min_4.S", + "arm/sync_fetch_and_min_8.S", + "arm/sync_fetch_and_nand_4.S", + "arm/sync_fetch_and_nand_8.S", + "arm/sync_fetch_and_or_4.S", + "arm/sync_fetch_and_or_8.S", + "arm/sync_fetch_and_sub_4.S", + "arm/sync_fetch_and_sub_8.S", + "arm/sync_fetch_and_umax_4.S", + "arm/sync_fetch_and_umax_8.S", + "arm/sync_fetch_and_umin_4.S", + "arm/sync_fetch_and_umin_8.S", + "arm/sync_fetch_and_xor_4.S", + "arm/sync_fetch_and_xor_8.S"]); } - } - if target_arch == "arm" && target_os != "ios" { - sources.extend(&["arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", - "arm/aeabi_dcmp.S", - "arm/aeabi_div0.c", - "arm/aeabi_drsub.c", - "arm/aeabi_fcmp.S", - "arm/aeabi_frsub.c", - "arm/bswapdi2.S", - "arm/bswapsi2.S", - "arm/clzdi2.S", - "arm/clzsi2.S", - "arm/comparesf2.S", - "arm/divmodsi4.S", - "arm/divsi3.S", - "arm/modsi3.S", - "arm/switch16.S", - "arm/switch32.S", - "arm/switch8.S", - "arm/switchu8.S", - "arm/sync_synchronize.S", - "arm/udivmodsi4.S", - "arm/udivsi3.S", - "arm/umodsi3.S"]); - } + if llvm_target.last().unwrap().ends_with("eabihf") { + if !llvm_target[0].starts_with("thumbv7em") { + sources.extend(&["arm/adddf3vfp.S", + "arm/addsf3vfp.S", + "arm/divdf3vfp.S", + "arm/divsf3vfp.S", + "arm/eqdf2vfp.S", + "arm/eqsf2vfp.S", + "arm/extendsfdf2vfp.S", + "arm/fixdfsivfp.S", + "arm/fixsfsivfp.S", + "arm/fixunsdfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsidfvfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssidfvfp.S", + "arm/floatunssisfvfp.S", + "arm/gedf2vfp.S", + "arm/gesf2vfp.S", + "arm/gtdf2vfp.S", + "arm/gtsf2vfp.S", + "arm/ledf2vfp.S", + "arm/lesf2vfp.S", + "arm/ltdf2vfp.S", + "arm/ltsf2vfp.S", + "arm/muldf3vfp.S", + "arm/mulsf3vfp.S", + "arm/nedf2vfp.S", + "arm/nesf2vfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/subdf3vfp.S", + "arm/subsf3vfp.S"]); + } - if llvm_target[0] == "armv7" { - sources.extend(&["arm/sync_fetch_and_add_4.S", - "arm/sync_fetch_and_add_8.S", - "arm/sync_fetch_and_and_4.S", - "arm/sync_fetch_and_and_8.S", - "arm/sync_fetch_and_max_4.S", - "arm/sync_fetch_and_max_8.S", - "arm/sync_fetch_and_min_4.S", - "arm/sync_fetch_and_min_8.S", - "arm/sync_fetch_and_nand_4.S", - "arm/sync_fetch_and_nand_8.S", - "arm/sync_fetch_and_or_4.S", - "arm/sync_fetch_and_or_8.S", - "arm/sync_fetch_and_sub_4.S", - "arm/sync_fetch_and_sub_8.S", - "arm/sync_fetch_and_umax_4.S", - "arm/sync_fetch_and_umax_8.S", - "arm/sync_fetch_and_umin_4.S", - "arm/sync_fetch_and_umin_8.S", - "arm/sync_fetch_and_xor_4.S", - "arm/sync_fetch_and_xor_8.S"]); - } + sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); - if llvm_target.last().unwrap().ends_with("eabihf") { - if !llvm_target[0].starts_with("thumbv7em") { - sources.extend(&["arm/adddf3vfp.S", - "arm/addsf3vfp.S", - "arm/divdf3vfp.S", - "arm/divsf3vfp.S", - "arm/eqdf2vfp.S", - "arm/eqsf2vfp.S", - "arm/extendsfdf2vfp.S", - "arm/fixdfsivfp.S", - "arm/fixsfsivfp.S", - "arm/fixunsdfsivfp.S", - "arm/fixunssfsivfp.S", - "arm/floatsidfvfp.S", - "arm/floatsisfvfp.S", - "arm/floatunssidfvfp.S", - "arm/floatunssisfvfp.S", - "arm/gedf2vfp.S", - "arm/gesf2vfp.S", - "arm/gtdf2vfp.S", - "arm/gtsf2vfp.S", - "arm/ledf2vfp.S", - "arm/lesf2vfp.S", - "arm/ltdf2vfp.S", - "arm/ltsf2vfp.S", - "arm/muldf3vfp.S", - "arm/mulsf3vfp.S", - "arm/nedf2vfp.S", - "arm/nesf2vfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", - "arm/subdf3vfp.S", - "arm/subsf3vfp.S"]); } - sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); - - } + if target_arch == "aarch64" { + sources.extend(&["comparetf2.c", + "extenddftf2.c", + "extendsftf2.c", + "fixtfdi.c", + "fixtfsi.c", + "fixtfti.c", + "fixunstfdi.c", + "fixunstfsi.c", + "fixunstfti.c", + "floatditf.c", + "floatsitf.c", + "floatunditf.c", + "floatunsitf.c", + "multc3.c", + "trunctfdf2.c", + "trunctfsf2.c"]); + } - if target_arch == "aarch64" { - sources.extend(&["comparetf2.c", - "extenddftf2.c", - "extendsftf2.c", - "fixtfdi.c", - "fixtfsi.c", - "fixtfti.c", - "fixunstfdi.c", - "fixunstfsi.c", - "fixunstfti.c", - "floatditf.c", - "floatsitf.c", - "floatunditf.c", - "floatunsitf.c", - "multc3.c", - "trunctfdf2.c", - "trunctfsf2.c"]); - } + // Remove the assembly implementations that won't compile for the target + if llvm_target[0] == "thumbv6m" { + sources.remove(&["aeabi_cdcmp", + "aeabi_cfcmp", + "aeabi_dcmp", + "aeabi_fcmp", + "clzdi2", + "clzsi2", + "comparesf2", + "divmodsi4", + "divsi3", + "modsi3", + "switch16", + "switch32", + "switch8", + "switchu8", + "udivmodsi4", + "udivsi3", + "umodsi3"]); + + // But use some generic implementations where possible + sources.extend(&["clzdi2.c", "clzsi2.c"]) + } - // Remove the assembly implementations that won't compile for the target - if llvm_target[0] == "thumbv6m" { - sources.remove(&["aeabi_cdcmp", - "aeabi_cfcmp", - "aeabi_dcmp", - "aeabi_fcmp", - "clzdi2", - "clzsi2", - "comparesf2", - "divmodsi4", - "divsi3", - "modsi3", - "switch16", - "switch32", - "switch8", - "switchu8", - "udivmodsi4", - "udivsi3", - "umodsi3"]); - - // But use some generic implementations where possible - sources.extend(&["clzdi2.c", "clzsi2.c"]) - } + if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { + sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); + } - if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { - sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); - } + let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { + Path::new("../../libcompiler_builtins") + } else { + Path::new(".") + }; + + let src_dir = root.join("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins"); + for src in sources.map.values() { + let src = src_dir.join(src); + cfg.file(&src); + println!("cargo:rerun-if-changed={}", src.display()); + } - let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { - Path::new("../../libcompiler_builtins") - } else { - Path::new(".") - }; - - let src_dir = root.join("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins"); - for src in sources.map.values() { - let src = src_dir.join(src); - cfg.file(&src); - println!("cargo:rerun-if-changed={}", src.display()); + cfg.compile("libcompiler-rt.a"); } - - cfg.compile("libcompiler-rt.a"); + #[cfg(not(feature = "c"))] + () => {} } // To filter away some flaky test (see src/float/add.rs for details) -- cgit 1.4.1-3-g733a5 From cd96f5305064ef4eb6551c329c4cd4d2f5e6588d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Mar 2017 10:34:27 -0500 Subject: fix infinite recursion in divmoddi4 / mulodi4 on ARMv7-M processors, divmoddi4 was calling mulodi4 and mulodi4 was calling divmoddi4 leading to infinite recursion. This commit breaks the cycle by using wrapping multiplication in divmoddi4. fixes #145 --- library/compiler-builtins/src/int/sdiv.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 51d9c376976..d00f89a2788 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -55,7 +55,9 @@ macro_rules! divmod { #[cfg(all(feature = "c", any(target_arch = "x86")))] () => unsafe { $div(a, b) }, }; - *rem = a - (r * b); + // NOTE won't overflow because it's using the result from the + // previous division + *rem = a - r.wrapping_mul(b); r } } -- cgit 1.4.1-3-g733a5 From b3e33508a057206a5b486ba35c4efd065f2b714c Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 6 Dec 2016 05:16:19 +0100 Subject: impl (unsigned/signed) int to single/double precision float conversion based on llvm algorithms. --- .../compiler-rt/compiler-rt-cdylib/build.rs | 6 + .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 12 ++ library/compiler-builtins/src/arm.rs | 6 + library/compiler-builtins/src/float/conv.rs | 133 +++++++++++++++++++++ library/compiler-builtins/src/float/mod.rs | 10 ++ library/compiler-builtins/src/int/mod.rs | 87 +++++++++++--- 6 files changed, 238 insertions(+), 16 deletions(-) mode change 100644 => 100755 library/compiler-builtins/src/arm.rs create mode 100755 library/compiler-builtins/src/float/conv.rs mode change 100644 => 100755 library/compiler-builtins/src/int/mod.rs diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs index 0f36143e2f8..98c5f884f30 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs @@ -62,6 +62,12 @@ fn main() { "powisf2.c", "subdf3.c", "subsf3.c", + "floatsisf.c", + "floatsidf.c", + "floatdidf.c", + "floatunsisf.c", + "floatunsidf.c", + "floatundidf.c", // 128 bit integers "lshrti3.c", "modti3.c", diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs index b76e1fd6fa1..e72613ad0b1 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -26,6 +26,12 @@ extern { fn __powidf2(); fn __subsf3(); fn __subdf3(); + fn __floatsisf(); + fn __floatsidf(); + fn __floatdidf(); + fn __floatunsisf(); + fn __floatunsidf(); + fn __floatundidf(); } macro_rules! declare { @@ -61,6 +67,12 @@ declare!(___powisf2, __powisf2); declare!(___powidf2, __powidf2); declare!(___subsf3, __subsf3); declare!(___subdf3, __subdf3); +declare!(___floatsisf, __floatsisf); +declare!(___floatsidf, __floatsidf); +declare!(___floatdidf, __floatdidf); +declare!(___floatunsisf, __floatunsisf); +declare!(___floatunsidf, __floatunsidf); +declare!(___floatundidf, __floatundidf); #[cfg(all(not(windows), not(target_arch = "mips64"), diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs old mode 100644 new mode 100755 index f2027e7b890..63f52500d4b --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -112,6 +112,12 @@ pub extern "aapcs" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { ::int::udiv::__udivsi3(a, b) } +#[cfg(not(feature = "c"))] +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_ui2d(a: u32) -> f64 { + ::float::conv::__floatunsidf(a) +} + // TODO: These aeabi_* functions should be defined as aliases #[cfg(not(feature = "mem"))] extern "C" { diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs new file mode 100755 index 00000000000..629af3c6353 --- /dev/null +++ b/library/compiler-builtins/src/float/conv.rs @@ -0,0 +1,133 @@ +use float::Float; +use int::Int; + +macro_rules! fp_overflow { + (infinity, $fty:ty, $sign: expr) => { + return { + <$fty as Float>::from_parts( + $sign, + <$fty as Float>::exponent_max() as <$fty as Float>::Int, + 0 as <$fty as Float>::Int) + } + } +} + +macro_rules! fp_convert { + ($intrinsic:ident: $ity:ty, $fty:ty) => { + + pub extern "C" fn $intrinsic(i: $ity) -> $fty { + if i == 0 { + return 0.0 + } + + let mant_dig = <$fty>::significand_bits() + 1; + let exponent_bias = <$fty>::exponent_bias(); + + let n = <$ity>::bits(); + let (s, a) = i.extract_sign(); + let mut a = a; + + // number of significant digits + let sd = n - a.leading_zeros(); + + // exponent + let mut e = sd - 1; + + if <$ity>::bits() < mant_dig { + return <$fty>::from_parts(s, + (e + exponent_bias) as <$fty as Float>::Int, + (a as <$fty as Float>::Int) << (mant_dig - e - 1)) + } + + a = if sd > mant_dig { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit MANT_DIG-1 bits to the right of 1 + * Q = bit MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + let mant_dig_plus_one = mant_dig + 1; + let mant_dig_plus_two = mant_dig + 2; + a = if sd == mant_dig_plus_one { + a << 1 + } else if sd == mant_dig_plus_two { + a + } else { + (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt | + ((a & <$ity as Int>::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != 0) as <$ity as Int>::UnsignedInt + }; + + /* finish: */ + a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */ + a += 1; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + + /* a is now rounded to mant_dig or mant_dig+1 bits */ + if (a & (1 << mant_dig)) != 0 { + a >>= 1; e += 1; + } + a + /* a is now rounded to mant_dig bits */ + } else { + a.wrapping_shl(mant_dig - sd) + /* a is now rounded to mant_dig bits */ + }; + + <$fty>::from_parts(s, + (e + exponent_bias) as <$fty as Float>::Int, + a as <$fty as Float>::Int) + } + } +} + +fp_convert!(__floatsisf: i32, f32); +fp_convert!(__floatsidf: i32, f64); +fp_convert!(__floatdidf: i64, f64); +fp_convert!(__floatunsisf: u32, f32); +fp_convert!(__floatunsidf: u32, f64); +fp_convert!(__floatundidf: u64, f64); + +// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabihf, our implementation doesn't +// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll +// just avoid testing against them on those targets. Do note that our implementation gives the +// correct answer; gcc_s and compiler-rt are incorrect in this case. +// +#[cfg(all(test, not(arm_linux)))] +mod tests { + use qc::{I32, U32, I64, U64, F32, F64}; + + check! { + fn __floatsisf(f: extern fn(i32) -> f32, + a: I32) + -> Option { + Some(F32(f(a.0))) + } + fn __floatsidf(f: extern fn(i32) -> f64, + a: I32) + -> Option { + Some(F64(f(a.0))) + } + fn __floatdidf(f: extern fn(i64) -> f64, + a: I64) + -> Option { + Some(F64(f(a.0))) + } + fn __floatunsisf(f: extern fn(u32) -> f32, + a: U32) + -> Option { + Some(F32(f(a.0))) + } + fn __floatunsidf(f: extern fn(u32) -> f64, + a: U32) + -> Option { + Some(F64(f(a.0))) + } + fn __floatundidf(f: extern fn(u64) -> f64, + a: U64) + -> Option { + Some(F64(f(a.0))) + } + } +} diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 08a1b6d727f..6176d5ab179 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,5 +1,6 @@ use core::mem; +pub mod conv; pub mod add; pub mod pow; pub mod sub; @@ -19,6 +20,15 @@ pub trait Float: Sized + Copy { fn exponent_bits() -> u32 { Self::bits() - Self::significand_bits() - 1 } + /// Returns the maximum value of the exponent + fn exponent_max() -> u32 { + (1 << Self::exponent_bits()) - 1 + } + + /// Returns the exponent bias value + fn exponent_bias() -> u32 { + Self::exponent_max() >> 1 + } /// Returns a mask for the sign bit fn sign_mask() -> Self::Int; diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs old mode 100644 new mode 100755 index 647410ccbf8..4fc8c19f22c --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -19,30 +19,85 @@ pub mod udiv; pub trait Int { /// Type with the same width but other signedness type OtherSign; + /// Unsigned version of Self + type UnsignedInt; + /// Returns the bitwidth of the int type fn bits() -> u32; + + /// Extracts the sign from self and returns a tuple. + /// + /// # Examples + /// + /// ```rust,ignore + /// let i = -25_i32; + /// let (sign, u) = i.extract_sign(); + /// assert_eq!(sign, true); + /// assert_eq!(u, 25_u32); + /// ``` + fn extract_sign(self) -> (bool, Self::UnsignedInt); } -macro_rules! int_impl { - ($ity:ty, $sty:ty, $bits:expr) => { - impl Int for $ity { - type OtherSign = $sty; - fn bits() -> u32 { - $bits - } - } - impl Int for $sty { - type OtherSign = $ity; - fn bits() -> u32 { - $bits - } +// TODO: Once i128/u128 support lands, we'll want to add impls for those as well +impl Int for u32 { + type OtherSign = i32; + type UnsignedInt = u32; + + fn bits() -> u32 { + 32 + } + + fn extract_sign(self) -> (bool, u32) { + (false, self) + } +} + +impl Int for i32 { + type OtherSign = u32; + type UnsignedInt = u32; + + fn bits() -> u32 { + 32 + } + + fn extract_sign(self) -> (bool, u32) { + if self < 0 { + (true, !(self as u32) + 1) + } else { + (false, self as u32) } } } -int_impl!(i32, u32, 32); -int_impl!(i64, u64, 64); -int_impl!(i128, u128, 128); +impl Int for u64 { + type OtherSign = i64; + type UnsignedInt = u64; + + fn bits() -> u32 { + 64 + } + + fn extract_sign(self) -> (bool, u64) { + (false, self) + } +} + +impl Int for i64 { + type OtherSign = u64; + type UnsignedInt = u64; + + fn bits() -> u32 { + 64 + } + + fn extract_sign(self) -> (bool, u64) { + if self < 0 { + (true, !(self as u64) + 1) + } else { + (false, self as u64) + } + } +} /// Trait to convert an integer to/from smaller parts pub trait LargeInt { -- cgit 1.4.1-3-g733a5 From ef3de28eaff1e1539b4a77a89fd52f675ddb01bb Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Sun, 5 Feb 2017 10:57:36 +0100 Subject: implement float/double to (u)int conversion. --- .../compiler-rt/compiler-rt-cdylib/build.rs | 8 ++ .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 16 +++ library/compiler-builtins/src/float/conv.rs | 109 +++++++++++++++++++++ library/compiler-builtins/src/float/mod.rs | 10 ++ library/compiler-builtins/src/qc.rs | 4 +- 5 files changed, 145 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs index 98c5f884f30..c07ea70cfd9 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs @@ -68,6 +68,14 @@ fn main() { "floatunsisf.c", "floatunsidf.c", "floatundidf.c", + "fixsfsi.c", + "fixsfdi.c", + "fixdfsi.c", + "fixdfdi.c", + "fixunssfsi.c", + "fixunssfdi.c", + "fixunsdfsi.c", + "fixunsdfdi.c", // 128 bit integers "lshrti3.c", "modti3.c", diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs index e72613ad0b1..2f08314bb88 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -32,6 +32,14 @@ extern { fn __floatunsisf(); fn __floatunsidf(); fn __floatundidf(); + fn __fixsfsi(); + fn __fixsfdi(); + fn __fixdfsi(); + fn __fixdfdi(); + fn __fixunssfsi(); + fn __fixunssfdi(); + fn __fixunsdfsi(); + fn __fixunsdfdi(); } macro_rules! declare { @@ -73,6 +81,14 @@ declare!(___floatdidf, __floatdidf); declare!(___floatunsisf, __floatunsisf); declare!(___floatunsidf, __floatunsidf); declare!(___floatundidf, __floatundidf); +declare!(___fixsfsi, __fixsfsi); +declare!(___fixsfdi, __fixsfdi); +declare!(___fixdfsi, __fixdfsi); +declare!(___fixdfdi, __fixdfdi); +declare!(___fixunssfsi, __fixunssfsi); +declare!(___fixunssfdi, __fixunssfdi); +declare!(___fixunsdfsi, __fixunsdfsi); +declare!(___fixunsdfdi, __fixunsdfdi); #[cfg(all(not(windows), not(target_arch = "mips64"), diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 629af3c6353..93437c84057 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -89,6 +89,73 @@ fp_convert!(__floatunsisf: u32, f32); fp_convert!(__floatunsidf: u32, f64); fp_convert!(__floatundidf: u64, f64); +#[derive(PartialEq, Debug)] +enum Sign { + Positive, + Negative +} +macro_rules! fp_fix { + ($intrinsic:ident: $fty:ty, $ity:ty) => { + pub extern "C" fn $intrinsic(f: $fty) -> $ity { + let fixint_min = <$ity>::min_value(); + let fixint_max = <$ity>::max_value(); + let fixint_bits = <$ity>::bits() as usize; + let fixint_unsigned = fixint_min == 0; + + let sign_bit = <$fty>::sign_mask(); + let significand_bits = <$fty>::significand_bits() as usize; + let exponent_bias = <$fty>::exponent_bias() as usize; + //let exponent_max = <$fty>::exponent_max() as usize; + + // Break a into sign, exponent, significand + let a_rep = <$fty>::repr(f); + let a_abs = a_rep & !sign_bit; + + // this is used to work around -1 not being available for unsigned + let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative }; + let mut exponent = (a_abs >> significand_bits) as usize; + let significand = (a_abs & <$fty>::significand_mask()) | <$fty>::implicit_bit(); + + // if < 1 or unsigned & negative + if exponent < exponent_bias || + fixint_unsigned && sign == Sign::Negative { + return 0 + } + exponent -= exponent_bias; + + // If the value is infinity, saturate. + // If the value is too large for the integer type, 0. + if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { + return if sign == Sign::Positive {fixint_max} else {fixint_min} + } + // If 0 <= exponent < significand_bits, right shift to get the result. + // Otherwise, shift left. + // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned + let r = if exponent < significand_bits { + (significand >> (significand_bits - exponent)) as $ity + } else { + (significand as $ity) << (exponent - significand_bits) + }; + + if sign == Sign::Negative { + (!r).wrapping_add(1) + } else { + r + } + } + } +} + +fp_fix!(__fixsfsi: f32, i32); +fp_fix!(__fixsfdi: f32, i64); +fp_fix!(__fixdfsi: f64, i32); +fp_fix!(__fixdfdi: f64, i64); + +fp_fix!(__fixunssfsi: f32, u32); +fp_fix!(__fixunssfdi: f32, u64); +fp_fix!(__fixunsdfsi: f64, u32); +fp_fix!(__fixunsdfdi: f64, u64); + // NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabihf, our implementation doesn't // match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll // just avoid testing against them on those targets. Do note that our implementation gives the @@ -129,5 +196,47 @@ mod tests { -> Option { Some(F64(f(a.0))) } + + fn __fixsfsi(f: extern fn(f32) -> i32, + a: F32) + -> Option { + Some(I32(f(a.0))) + } + fn __fixsfdi(f: extern fn(f32) -> i64, + a: F32) + -> Option { + Some(I64(f(a.0))) + } + fn __fixdfsi(f: extern fn(f64) -> i32, + a: F64) + -> Option { + Some(I32(f(a.0))) + } + fn __fixdfdi(f: extern fn(f64) -> i64, + a: F64) + -> Option { + Some(I64(f(a.0))) + } + + fn __fixunssfsi(f: extern fn(f32) -> u32, + a: F32) + -> Option { + Some(U32(f(a.0))) + } + fn __fixunssfdi(f: extern fn(f32) -> u64, + a: F32) + -> Option { + Some(U64(f(a.0))) + } + fn __fixunsdfsi(f: extern fn(f64) -> u32, + a: F64) + -> Option { + Some(U32(f(a.0))) + } + fn __fixunsdfdi(f: extern fn(f64) -> u64, + a: F64) + -> Option { + Some(U64(f(a.0))) + } } } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 6176d5ab179..46e3e5d9585 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -36,6 +36,9 @@ pub trait Float: Sized + Copy { /// Returns a mask for the significand fn significand_mask() -> Self::Int; + // Returns the implicit bit of the float format + fn implicit_bit() -> Self::Int; + /// Returns a mask for the exponent fn exponent_mask() -> Self::Int; @@ -68,6 +71,9 @@ impl Float for f32 { fn significand_bits() -> u32 { 23 } + fn implicit_bit() -> Self::Int { + 1 << Self::significand_bits() + } fn sign_mask() -> Self::Int { 1 << (Self::bits() - 1) } @@ -110,6 +116,10 @@ impl Float for f64 { fn significand_bits() -> u32 { 52 } + // Returns the implicit bit of the float format + fn implicit_bit() -> Self::Int { + 1 << Self::significand_bits() + } fn sign_mask() -> Self::Int { 1 << (Self::bits() - 1) } diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 306508f6c48..675bcc67702 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -15,7 +15,7 @@ use float::Float; // Generates values in the full range of the integer type macro_rules! arbitrary { ($TY:ident : $ty:ident) => { - #[derive(Clone, Copy)] + #[derive(Clone, Copy, PartialEq)] pub struct $TY(pub $ty); impl Arbitrary for $TY { @@ -82,7 +82,7 @@ arbitrary!(U32: u32); // intrinsics. macro_rules! arbitrary_large { ($TY:ident : $ty:ident) => { - #[derive(Clone, Copy)] + #[derive(Clone, Copy, PartialEq)] pub struct $TY(pub $ty); impl Arbitrary for $TY { -- cgit 1.4.1-3-g733a5 From 77889226f7159a333543aee468361bb707061e84 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Mon, 6 Feb 2017 06:26:55 +0100 Subject: exclude from tests values out of integer range (and NaN). --- library/compiler-builtins/src/float/conv.rs | 40 +++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 93437c84057..00259ecddda 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -200,43 +200,67 @@ mod tests { fn __fixsfsi(f: extern fn(f32) -> i32, a: F32) -> Option { - Some(I32(f(a.0))) + if a.0 > (i32::max_value() as f32) || + a.0 < (i32::min_value() as f32) || a.0.is_nan() { + None + } else { Some(I32(f(a.0))) } } fn __fixsfdi(f: extern fn(f32) -> i64, a: F32) -> Option { - Some(I64(f(a.0))) + if a.0 > (i64::max_value() as f32) || + a.0 < (i64::min_value() as f32) || a.0.is_nan() { + None + } else { Some(I64(f(a.0))) } } fn __fixdfsi(f: extern fn(f64) -> i32, a: F64) -> Option { - Some(I32(f(a.0))) + if a.0 > (i32::max_value() as f64) || + a.0 < (i32::min_value() as f64) || a.0.is_nan() { + None + } else { Some(I32(f(a.0))) } } fn __fixdfdi(f: extern fn(f64) -> i64, a: F64) -> Option { - Some(I64(f(a.0))) + if a.0 > (i64::max_value() as f64) || + a.0 < (i64::min_value() as f64) || a.0.is_nan() { + None + } else { Some(I64(f(a.0))) } } fn __fixunssfsi(f: extern fn(f32) -> u32, a: F32) -> Option { - Some(U32(f(a.0))) + if a.0 > (u32::max_value() as f32) || + a.0 < (u32::min_value() as f32) || a.0.is_nan() { + None + } else { Some(U32(f(a.0))) } } fn __fixunssfdi(f: extern fn(f32) -> u64, a: F32) -> Option { - Some(U64(f(a.0))) + if a.0 > (u64::max_value() as f32) || + a.0 < (u64::min_value() as f32) || a.0.is_nan() { + None + } else { Some(U64(f(a.0))) } } fn __fixunsdfsi(f: extern fn(f64) -> u32, a: F64) -> Option { - Some(U32(f(a.0))) + if a.0 > (u32::max_value() as f64) || + a.0 < (u32::min_value() as f64) || a.0.is_nan() { + None + } else { Some(U32(f(a.0))) } } fn __fixunsdfdi(f: extern fn(f64) -> u64, a: F64) -> Option { - Some(U64(f(a.0))) + if a.0 <= (u64::max_value() as f64) || + a.0 >= (u64::min_value() as f64) || a.0.is_nan() { + None + } else { Some(U64(f(a.0))) } } } } -- cgit 1.4.1-3-g733a5 From 1f26fea5d47b219488c9b792f6d911c1edbe6b76 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Mar 2017 12:17:10 -0500 Subject: refactor 'impl Int' --- library/compiler-builtins/src/int/mod.rs | 81 ++++++++++++-------------------- 1 file changed, 29 insertions(+), 52 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 4fc8c19f22c..a94a070ca06 100755 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -38,67 +38,44 @@ pub trait Int { fn extract_sign(self) -> (bool, Self::UnsignedInt); } -// TODO: Once i128/u128 support lands, we'll want to add impls for those as well -impl Int for u32 { - type OtherSign = i32; - type UnsignedInt = u32; - - fn bits() -> u32 { - 32 - } - - fn extract_sign(self) -> (bool, u32) { - (false, self) - } -} - -impl Int for i32 { - type OtherSign = u32; - type UnsignedInt = u32; - - fn bits() -> u32 { - 32 - } +macro_rules! int_impl { + ($ity:ty, $uty:ty, $bits:expr) => { + impl Int for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + fn bits() -> u32 { + $bits + } - fn extract_sign(self) -> (bool, u32) { - if self < 0 { - (true, !(self as u32) + 1) - } else { - (false, self as u32) + fn extract_sign(self) -> (bool, $uty) { + (false, self) + } } - } -} - -impl Int for u64 { - type OtherSign = i64; - type UnsignedInt = u64; - - fn bits() -> u32 { - 64 - } - fn extract_sign(self) -> (bool, u64) { - (false, self) - } -} + impl Int for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; -impl Int for i64 { - type OtherSign = u64; - type UnsignedInt = u64; - - fn bits() -> u32 { - 64 - } + fn bits() -> u32 { + $bits + } - fn extract_sign(self) -> (bool, u64) { - if self < 0 { - (true, !(self as u64) + 1) - } else { - (false, self as u64) + fn extract_sign(self) -> (bool, $uty) { + if self < 0 { + (true, !(self as $uty) + 1) + } else { + (false, self as $uty) + } + } } } } +int_impl!(i32, u32, 32); +int_impl!(i64, u64, 64); +int_impl!(i128, u128, 128); + /// Trait to convert an integer to/from smaller parts pub trait LargeInt { type LowHalf; -- cgit 1.4.1-3-g733a5 From 0ecfe751b5e26db8fe86316f5af269cce6a11a42 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Mar 2017 12:17:41 -0500 Subject: fix quickcheck tests the check! macro syntax has changed --- library/compiler-builtins/src/float/conv.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 00259ecddda..75a392efce1 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -166,38 +166,38 @@ mod tests { use qc::{I32, U32, I64, U64, F32, F64}; check! { - fn __floatsisf(f: extern fn(i32) -> f32, + fn __floatsisf(f: extern "C" fn(i32) -> f32, a: I32) -> Option { Some(F32(f(a.0))) } - fn __floatsidf(f: extern fn(i32) -> f64, + fn __floatsidf(f: extern "C" fn(i32) -> f64, a: I32) -> Option { Some(F64(f(a.0))) } - fn __floatdidf(f: extern fn(i64) -> f64, + fn __floatdidf(f: extern "C" fn(i64) -> f64, a: I64) -> Option { Some(F64(f(a.0))) } - fn __floatunsisf(f: extern fn(u32) -> f32, + fn __floatunsisf(f: extern "C" fn(u32) -> f32, a: U32) -> Option { Some(F32(f(a.0))) } - fn __floatunsidf(f: extern fn(u32) -> f64, + fn __floatunsidf(f: extern "C" fn(u32) -> f64, a: U32) -> Option { Some(F64(f(a.0))) } - fn __floatundidf(f: extern fn(u64) -> f64, + fn __floatundidf(f: extern "C" fn(u64) -> f64, a: U64) -> Option { Some(F64(f(a.0))) } - fn __fixsfsi(f: extern fn(f32) -> i32, + fn __fixsfsi(f: extern "C" fn(f32) -> i32, a: F32) -> Option { if a.0 > (i32::max_value() as f32) || @@ -205,7 +205,7 @@ mod tests { None } else { Some(I32(f(a.0))) } } - fn __fixsfdi(f: extern fn(f32) -> i64, + fn __fixsfdi(f: extern "C" fn(f32) -> i64, a: F32) -> Option { if a.0 > (i64::max_value() as f32) || @@ -213,7 +213,7 @@ mod tests { None } else { Some(I64(f(a.0))) } } - fn __fixdfsi(f: extern fn(f64) -> i32, + fn __fixdfsi(f: extern "C" fn(f64) -> i32, a: F64) -> Option { if a.0 > (i32::max_value() as f64) || @@ -221,7 +221,7 @@ mod tests { None } else { Some(I32(f(a.0))) } } - fn __fixdfdi(f: extern fn(f64) -> i64, + fn __fixdfdi(f: extern "C" fn(f64) -> i64, a: F64) -> Option { if a.0 > (i64::max_value() as f64) || @@ -230,7 +230,7 @@ mod tests { } else { Some(I64(f(a.0))) } } - fn __fixunssfsi(f: extern fn(f32) -> u32, + fn __fixunssfsi(f: extern "C" fn(f32) -> u32, a: F32) -> Option { if a.0 > (u32::max_value() as f32) || @@ -238,7 +238,7 @@ mod tests { None } else { Some(U32(f(a.0))) } } - fn __fixunssfdi(f: extern fn(f32) -> u64, + fn __fixunssfdi(f: extern "C" fn(f32) -> u64, a: F32) -> Option { if a.0 > (u64::max_value() as f32) || @@ -246,7 +246,7 @@ mod tests { None } else { Some(U64(f(a.0))) } } - fn __fixunsdfsi(f: extern fn(f64) -> u32, + fn __fixunsdfsi(f: extern "C" fn(f64) -> u32, a: F64) -> Option { if a.0 > (u32::max_value() as f64) || @@ -254,7 +254,7 @@ mod tests { None } else { Some(U32(f(a.0))) } } - fn __fixunsdfdi(f: extern fn(f64) -> u64, + fn __fixunsdfdi(f: extern "C" fn(f64) -> u64, a: F64) -> Option { if a.0 <= (u64::max_value() as f64) || -- cgit 1.4.1-3-g733a5 From 74c6b91677c7ea6dcab65da58f304d1c465301dc Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Mar 2017 17:46:11 -0500 Subject: fix debug assertion in divdi3 fixes #148 --- library/compiler-builtins/src/int/sdiv.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 51d9c376976..f9fd4668741 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -10,8 +10,12 @@ macro_rules! div { pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $tyret { let s_a = a >> (<$ty>::bits() - 1); let s_b = b >> (<$ty>::bits() - 1); - let a = (a ^ s_a) - s_a; - let b = (b ^ s_b) - s_b; + // NOTE it's OK to overflow here because of the `as $uty` cast below + // This whole operation is computing the absolute value of the inputs + // So some overflow will happen when dealing with e.g. `i64::MIN` + // where the absolute value is `(-i64::MIN) as u64` + let a = (a ^ s_a).wrapping_sub(s_a); + let b = (b ^ s_b).wrapping_sub(s_b); let s = s_a ^ s_b; let r = udiv!(a as $uty, b as $uty); -- cgit 1.4.1-3-g733a5 From 0ef737f5570124d6478dd4637a1a01bcc484a370 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 13 Mar 2017 20:40:44 -0500 Subject: fix debug assertion in modsi3 / moddi3 fixes #151 this fix is very similar to #149 --- library/compiler-builtins/src/int/sdiv.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 7f30eaf26e8..19065602970 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -33,9 +33,10 @@ macro_rules! mod_ { #[cfg_attr(not(test), no_mangle)] pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $tyret { let s = b >> (<$ty>::bits() - 1); - let b = (b ^ s) - s; + // NOTE(wrapping_sub) see comment in the `div` macro + let b = (b ^ s).wrapping_sub(s); let s = a >> (<$ty>::bits() - 1); - let a = (a ^ s) - s; + let a = (a ^ s).wrapping_sub(s); let r = urem!(a as $uty, b as $uty); ($conv)((r as $ty ^ s) - s) -- cgit 1.4.1-3-g733a5 From 07064c2239af3d9fe83839334d5845f064c4ac97 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 8 Apr 2017 10:18:19 -0500 Subject: test out of range condition using f64 to avoid imprecision due to rounding to f32 --- library/compiler-builtins/src/float/conv.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 75a392efce1..2781ff55621 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -200,16 +200,16 @@ mod tests { fn __fixsfsi(f: extern "C" fn(f32) -> i32, a: F32) -> Option { - if a.0 > (i32::max_value() as f32) || - a.0 < (i32::min_value() as f32) || a.0.is_nan() { + if (a.0 as f64) > (i32::max_value() as f64) || + (a.0 as f64) < (i32::min_value() as f64) || a.0.is_nan() { None } else { Some(I32(f(a.0))) } } fn __fixsfdi(f: extern "C" fn(f32) -> i64, a: F32) -> Option { - if a.0 > (i64::max_value() as f32) || - a.0 < (i64::min_value() as f32) || a.0.is_nan() { + if (a.0 as f64) > (i64::max_value() as f64) || + (a.0 as f64) < (i64::min_value() as f64) || a.0.is_nan() { None } else { Some(I64(f(a.0))) } } @@ -233,16 +233,16 @@ mod tests { fn __fixunssfsi(f: extern "C" fn(f32) -> u32, a: F32) -> Option { - if a.0 > (u32::max_value() as f32) || - a.0 < (u32::min_value() as f32) || a.0.is_nan() { + if (a.0 as f64) > (u32::max_value() as f64) || + (a.0 as f64) < (u32::min_value() as f64) || a.0.is_nan() { None } else { Some(U32(f(a.0))) } } fn __fixunssfdi(f: extern "C" fn(f32) -> u64, a: F32) -> Option { - if a.0 > (u64::max_value() as f32) || - a.0 < (u64::min_value() as f32) || a.0.is_nan() { + if (a.0 as f64) > (u64::max_value() as f64) || + (a.0 as f64) < (u64::min_value() as f64) || a.0.is_nan() { None } else { Some(U64(f(a.0))) } } -- cgit 1.4.1-3-g733a5 From 8316333dc6081cfdbfb62e4b7b31beb7bacdafdb Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 11:11:23 -0500 Subject: move compiler-rt submodule --- library/compiler-builtins/.gitmodules | 2 +- library/compiler-builtins/c/compiler-rt | 1 + library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) create mode 160000 library/compiler-builtins/c/compiler-rt delete mode 160000 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index d86b9fa3414..ed1a78f9fb3 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ [submodule "compiler-rt/compiler-rt-cdylib/compiler-rt"] - path = compiler-rt/compiler-rt-cdylib/compiler-rt + path = c/compiler-rt url = https://github.com/rust-lang/compiler-rt diff --git a/library/compiler-builtins/c/compiler-rt b/library/compiler-builtins/c/compiler-rt new file mode 160000 index 00000000000..3bc0272cab9 --- /dev/null +++ b/library/compiler-builtins/c/compiler-rt @@ -0,0 +1 @@ +Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79 diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt deleted file mode 160000 index 3bc0272cab9..00000000000 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79 -- cgit 1.4.1-3-g733a5 From 05a5f4681fa8bee5cea856c7d6717dda798bb683 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 11:14:05 -0500 Subject: remove the current test suite --- library/compiler-builtins/Cargo.toml | 6 -- library/compiler-builtins/src/float/add.rs | 25 ------ library/compiler-builtins/src/float/conv.rs | 109 -------------------------- library/compiler-builtins/src/float/pow.rs | 19 ----- library/compiler-builtins/src/float/sub.rs | 25 ------ library/compiler-builtins/src/int/mul.rs | 63 --------------- library/compiler-builtins/src/int/sdiv.rs | 117 ---------------------------- library/compiler-builtins/src/int/shift.rs | 74 ------------------ library/compiler-builtins/src/int/udiv.rs | 117 ---------------------------- library/compiler-builtins/src/lib.rs | 17 ---- 10 files changed, 572 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index a82aad55fe4..fdd3b2a7d66 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -11,12 +11,6 @@ rustc-cfg = "0.3.0" optional = true version = "0.3.36" -[dev-dependencies] -quickcheck = "0.3.1" -rand = "0.3.14" -gcc_s = { path = "gcc_s" } -compiler-rt = { path = "compiler-rt" } - [features] # Build the missing intrinsics from compiler-rt C source code c = ["gcc"] diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 992d149f458..5024a728b04 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -192,28 +192,3 @@ add!("aapcs", __adddf3: f64); #[cfg(not(target_arch = "arm"))] add!("C", __adddf3: f64); - -// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabi*, our implementation doesn't -// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll -// just avoid testing against them on those targets. Do note that our implementation gives the -// correct answer; gcc_s and compiler-rt are incorrect in this case. -#[cfg(all(test, not(arm_linux)))] -mod tests { - use core::{f32, f64}; - use qc::{F32, F64}; - - check! { - fn __addsf3(f: extern "C" fn(f32, f32) -> f32, - a: F32, - b: F32) - -> Option { - Some(F32(f(a.0, b.0))) - } - - fn __adddf3(f: extern "C" fn(f64, f64) -> f64, - a: F64, - b: F64) -> Option { - Some(F64(f(a.0, b.0))) - } - } -} diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 2781ff55621..e04b26bf536 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -155,112 +155,3 @@ fp_fix!(__fixunssfsi: f32, u32); fp_fix!(__fixunssfdi: f32, u64); fp_fix!(__fixunsdfsi: f64, u32); fp_fix!(__fixunsdfdi: f64, u64); - -// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabihf, our implementation doesn't -// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll -// just avoid testing against them on those targets. Do note that our implementation gives the -// correct answer; gcc_s and compiler-rt are incorrect in this case. -// -#[cfg(all(test, not(arm_linux)))] -mod tests { - use qc::{I32, U32, I64, U64, F32, F64}; - - check! { - fn __floatsisf(f: extern "C" fn(i32) -> f32, - a: I32) - -> Option { - Some(F32(f(a.0))) - } - fn __floatsidf(f: extern "C" fn(i32) -> f64, - a: I32) - -> Option { - Some(F64(f(a.0))) - } - fn __floatdidf(f: extern "C" fn(i64) -> f64, - a: I64) - -> Option { - Some(F64(f(a.0))) - } - fn __floatunsisf(f: extern "C" fn(u32) -> f32, - a: U32) - -> Option { - Some(F32(f(a.0))) - } - fn __floatunsidf(f: extern "C" fn(u32) -> f64, - a: U32) - -> Option { - Some(F64(f(a.0))) - } - fn __floatundidf(f: extern "C" fn(u64) -> f64, - a: U64) - -> Option { - Some(F64(f(a.0))) - } - - fn __fixsfsi(f: extern "C" fn(f32) -> i32, - a: F32) - -> Option { - if (a.0 as f64) > (i32::max_value() as f64) || - (a.0 as f64) < (i32::min_value() as f64) || a.0.is_nan() { - None - } else { Some(I32(f(a.0))) } - } - fn __fixsfdi(f: extern "C" fn(f32) -> i64, - a: F32) - -> Option { - if (a.0 as f64) > (i64::max_value() as f64) || - (a.0 as f64) < (i64::min_value() as f64) || a.0.is_nan() { - None - } else { Some(I64(f(a.0))) } - } - fn __fixdfsi(f: extern "C" fn(f64) -> i32, - a: F64) - -> Option { - if a.0 > (i32::max_value() as f64) || - a.0 < (i32::min_value() as f64) || a.0.is_nan() { - None - } else { Some(I32(f(a.0))) } - } - fn __fixdfdi(f: extern "C" fn(f64) -> i64, - a: F64) - -> Option { - if a.0 > (i64::max_value() as f64) || - a.0 < (i64::min_value() as f64) || a.0.is_nan() { - None - } else { Some(I64(f(a.0))) } - } - - fn __fixunssfsi(f: extern "C" fn(f32) -> u32, - a: F32) - -> Option { - if (a.0 as f64) > (u32::max_value() as f64) || - (a.0 as f64) < (u32::min_value() as f64) || a.0.is_nan() { - None - } else { Some(U32(f(a.0))) } - } - fn __fixunssfdi(f: extern "C" fn(f32) -> u64, - a: F32) - -> Option { - if (a.0 as f64) > (u64::max_value() as f64) || - (a.0 as f64) < (u64::min_value() as f64) || a.0.is_nan() { - None - } else { Some(U64(f(a.0))) } - } - fn __fixunsdfsi(f: extern "C" fn(f64) -> u32, - a: F64) - -> Option { - if a.0 > (u32::max_value() as f64) || - a.0 < (u32::min_value() as f64) || a.0.is_nan() { - None - } else { Some(U32(f(a.0))) } - } - fn __fixunsdfdi(f: extern "C" fn(f64) -> u64, - a: F64) - -> Option { - if a.0 <= (u64::max_value() as f64) || - a.0 >= (u64::min_value() as f64) || a.0.is_nan() { - None - } else { Some(U64(f(a.0))) } - } - } -} diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 52aba5df68c..5e28d95d8d2 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -28,22 +28,3 @@ macro_rules! pow { pow!(__powisf2: f32, i32); pow!(__powidf2: f64, i32); - -#[cfg(test)] -mod tests { - use qc::{I32, F32, F64}; - - check! { - fn __powisf2(f: extern "C" fn(f32, i32) -> f32, - a: F32, - b: I32) -> Option { - Some(F32(f(a.0, b.0))) - } - - fn __powidf2(f: extern "C" fn(f64, i32) -> f64, - a: F64, - b: I32) -> Option { - Some(F64(f(a.0, b.0))) - } - } -} diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 928d7382103..a4fd8841d17 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -18,28 +18,3 @@ sub!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] sub!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] | __subdf3: f64); - -// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabi*, our implementation doesn't -// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll -// just avoid testing against them on those targets. Do note that our implementation gives the -// correct answer; gcc_s and compiler-rt are incorrect in this case. -#[cfg(all(test, not(arm_linux)))] -mod tests { - use core::{f32, f64}; - use qc::{F32, F64}; - - check! { - fn __subsf3(f: extern "C" fn(f32, f32) -> f32, - a: F32, - b: F32) - -> Option { - Some(F32(f(a.0, b.0))) - } - - fn __subdf3(f: extern "C" fn(f64, f64) -> f64, - a: F64, - b: F64) -> Option { - Some(F64(f(a.0, b.0))) - } - } -} diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 7b0d033b0b4..5381eddea41 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -93,66 +93,3 @@ mulo!(__mulodi4: i64); mulo!(__muloti4: i128, "unadjusted"); #[cfg(not(all(windows, target_pointer_width="64")))] mulo!(__muloti4: i128); - -#[cfg(test)] -mod tests { - use qc::{I32, I64, U64}; - - check! { - fn __muldi3(f: extern "C" fn(u64, u64) -> u64, a: U64, b: U64) - -> Option { - Some(f(a.0, b.0)) - } - - fn __mulosi4(f: extern "C" fn(i32, i32, &mut i32) -> i32, - a: I32, - b: I32) -> Option<(i32, i32)> { - let (a, b) = (a.0, b.0); - let mut overflow = 2; - let r = f(a, b, &mut overflow); - if overflow != 0 && overflow != 1 { - panic!("Invalid value {} for overflow", overflow); - } - Some((r, overflow)) - } - - fn __mulodi4(f: extern "C" fn(i64, i64, &mut i32) -> i64, - a: I64, - b: I64) -> Option<(i64, i32)> { - let (a, b) = (a.0, b.0); - let mut overflow = 2; - let r = f(a, b, &mut overflow); - if overflow != 0 && overflow != 1 { - panic!("Invalid value {} for overflow", overflow); - } - Some((r, overflow)) - } - } -} - -#[cfg(test)] -#[cfg(all(not(windows), - not(target_arch = "mips64"), - not(target_arch = "mips64el"), - target_pointer_width="64"))] -mod tests_i128 { - use qc::I128; - - check! { - fn __multi3(f: extern "C" fn(i128, i128) -> i128, a: I128, b: I128) - -> Option { - Some(f(a.0, b.0)) - } - fn __muloti4(f: extern "C" fn(i128, i128, &mut i32) -> i128, - a: I128, - b: I128) -> Option<(i128, i32)> { - let (a, b) = (a.0, b.0); - let mut overflow = 2; - let r = f(a, b, &mut overflow); - if overflow != 0 && overflow != 1 { - panic!("Invalid value {} for overflow", overflow); - } - Some((r, overflow)) - } - } -} diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 19065602970..557689814f6 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -100,120 +100,3 @@ divmod!("aapcs", __divmoddi4, __divdi3: i64); #[cfg(not(target_arch = "arm"))] divmod!("C", __divmoddi4, __divdi3: i64); - -#[cfg(test)] -mod tests { - use qc::{U32, U64}; - - check! { - fn __divdi3(f: extern "C" fn(i64, i64) -> i64, n: U64, d: U64) -> Option { - let (n, d) = (n.0 as i64, d.0 as i64); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __moddi3(f: extern "C" fn(i64, i64) -> i64, n: U64, d: U64) -> Option { - let (n, d) = (n.0 as i64, d.0 as i64); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - #[cfg(target_arch = "arm")] - fn __divmoddi4(f: extern "aapcs" fn(i64, i64, &mut i64) -> i64, - n: U64, - d: U64) -> Option<(i64, i64)> { - let (n, d) = (n.0 as i64, d.0 as i64); - if d == 0 { - None - } else { - let mut r = 0; - let q = f(n, d, &mut r); - Some((q, r)) - } - } - - #[cfg(not(target_arch = "arm"))] - fn __divmoddi4(f: extern "C" fn(i64, i64, &mut i64) -> i64, - n: U64, - d: U64) -> Option<(i64, i64)> { - let (n, d) = (n.0 as i64, d.0 as i64); - if d == 0 { - None - } else { - let mut r = 0; - let q = f(n, d, &mut r); - Some((q, r)) - } - } - - fn __divsi3(f: extern "C" fn(i32, i32) -> i32, - n: U32, - d: U32) -> Option { - let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __modsi3(f: extern "C" fn(i32, i32) -> i32, - n: U32, - d: U32) -> Option { - let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __divmodsi4(f: extern "C" fn(i32, i32, &mut i32) -> i32, - n: U32, - d: U32) -> Option<(i32, i32)> { - let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 { - None - } else { - let mut r = 0; - let q = f(n, d, &mut r); - Some((q, r)) - } - } - } -} - -#[cfg(test)] -#[cfg(all(not(windows), - not(target_arch = "mips64"), - not(target_arch = "mips64el"), - target_pointer_width="64"))] -mod tests_i128 { - use qc::U128; - check! { - - fn __divti3(f: extern "C" fn(i128, i128) -> i128, n: U128, d: U128) -> Option { - let (n, d) = (n.0 as i128, d.0 as i128); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __modti3(f: extern "C" fn(i128, i128) -> i128, n: U128, d: U128) -> Option { - let (n, d) = (n.0 as i128, d.0 as i128); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - } -} diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index fdd2f6ce2b5..8b5c4a16eaa 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -72,77 +72,3 @@ ashr!(__ashrti3: i128); lshr!(__lshrdi3: u64); lshr!(__lshrti3: u128); - -#[cfg(test)] -mod tests { - use qc::{I64, U64}; - - // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) - check! { - fn __ashldi3(f: extern "C" fn(u64, u32) -> u64, a: U64, b: u32) -> Option { - let a = a.0; - if b >= 64 { - None - } else { - Some(f(a, b)) - } - } - - fn __ashrdi3(f: extern "C" fn(i64, u32) -> i64, a: I64, b: u32) -> Option { - let a = a.0; - if b >= 64 { - None - } else { - Some(f(a, b)) - } - } - - fn __lshrdi3(f: extern "C" fn(u64, u32) -> u64, a: U64, b: u32) -> Option { - let a = a.0; - if b >= 64 { - None - } else { - Some(f(a, b)) - } - } - } -} - -#[cfg(test)] -#[cfg(all(not(windows), - not(target_arch = "mips64"), - not(target_arch = "mips64el"), - target_pointer_width="64"))] -mod tests_i128 { - use qc::{I128, U128}; - - // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) - check! { - fn __ashlti3(f: extern "C" fn(u128, u32) -> u128, a: U128, b: u32) -> Option { - let a = a.0; - if b >= 64 { - None - } else { - Some(f(a, b)) - } - } - - fn __ashrti3(f: extern "C" fn(i128, u32) -> i128, a: I128, b: u32) -> Option { - let a = a.0; - if b >= 64 { - None - } else { - Some(f(a, b)) - } - } - - fn __lshrti3(f: extern "C" fn(u128, u32) -> u128, a: U128, b: u32) -> Option { - let a = a.0; - if b >= 128 { - None - } else { - Some(f(a, b)) - } - } - } -} diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 6c125bb750c..e8db7460125 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -312,120 +312,3 @@ udivmodti4!(::U64x2, ::conv); #[cfg(not(all(windows, target_pointer_width="64")))] udivmodti4!(u128, |i|{ i }); - -#[cfg(test)] -mod tests { - use qc::{U32, U64}; - - check! { - fn __udivdi3(f: extern "C" fn(u64, u64) -> u64, n: U64, d: U64) -> Option { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __umoddi3(f: extern "C" fn(u64, u64) -> u64, n: U64, d: U64) -> Option { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __udivmoddi4(f: extern "C" fn(u64, u64, Option<&mut u64>) -> u64, - n: U64, - d: U64) -> Option<(u64, u64)> { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - let mut r = 0; - let q = f(n, d, Some(&mut r)); - Some((q, r)) - } - } - - fn __udivsi3(f: extern "C" fn(u32, u32) -> u32, n: U32, d: U32) -> Option { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __umodsi3(f: extern "C" fn(u32, u32) -> u32, n: U32, d: U32) -> Option { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __udivmodsi4(f: extern "C" fn(u32, u32, Option<&mut u32>) -> u32, - n: U32, - d: U32) -> Option<(u32, u32)> { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - let mut r = 0; - let q = f(n, d, Some(&mut r)); - Some((q, r)) - } - } - } -} - -#[cfg(test)] -#[cfg(all(not(windows), - not(target_arch = "mips64"), - not(target_arch = "mips64el"), - target_pointer_width="64"))] -mod tests_i128 { - use qc::U128; - - check! { - fn __udivti3(f: extern "C" fn(u128, u128) -> u128, - n: U128, - d: U128) -> Option { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __umodti3(f: extern "C" fn(u128, u128) -> u128, - n: U128, - d: U128) -> Option { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __udivmodti4(f: extern "C" fn(u128, u128, Option<&mut u128>) -> u128, - n: U128, - d: U128) -> Option { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - // FIXME fix the segfault when the remainder is requested - /*let mut r = 0; - let q = f(n, d, Some(&mut r)); - Some((q, r))*/ - Some(f(n, d, None)) - } - } - } -} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0da336e950b..8c7820bf99b 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -111,26 +111,9 @@ fn sconv(i: i128) -> U64x2 { U64x2(j.low(), j.high()) } -#[cfg(test)] -#[cfg_attr(target_arch = "arm", macro_use)] -extern crate quickcheck; - #[cfg(test)] extern crate core; -#[cfg(test)] -extern crate gcc_s; - -#[cfg(test)] -extern crate compiler_rt; - -#[cfg(test)] -extern crate rand; - -#[cfg(test)] -#[macro_use] -mod qc; - pub mod int; pub mod float; -- cgit 1.4.1-3-g733a5 From 199c7a8dcbd06cf409a6ba02a5ad2eb3283365ad Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 11:19:16 -0500 Subject: refactor build.rs to not depend on rustc-cfg it now uses the CARGO_CFG_TARGET variables provided by Cargo --- library/compiler-builtins/Cargo.toml | 3 - library/compiler-builtins/build.rs | 761 +++++++++++++++++------------------ 2 files changed, 375 insertions(+), 389 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index fdd3b2a7d66..aea0c38840f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -4,9 +4,6 @@ build = "build.rs" name = "compiler_builtins" version = "0.1.0" -[build-dependencies] -rustc-cfg = "0.3.0" - [build-dependencies.gcc] optional = true version = "0.3.36" diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6c96284731b..145f71575d2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,55 +1,4 @@ -#[cfg(feature = "c")] -extern crate gcc; -extern crate rustc_cfg; - -#[cfg(feature = "c")] -use std::collections::BTreeMap; -use std::io::Write; -#[cfg(feature = "c")] -use std::path::Path; -use std::{env, io, process}; - -use rustc_cfg::Cfg; - -#[cfg(feature = "c")] -struct Sources { - // SYMBOL -> PATH TO SOURCE - map: BTreeMap<&'static str, &'static str>, -} - -#[cfg(feature = "c")] -impl Sources { - fn new() -> Sources { - Sources { map: BTreeMap::new() } - } - - fn extend(&mut self, sources: &[&'static str]) { - // NOTE Some intrinsics have both a generic implementation (e.g. - // `floatdidf.c`) and an arch optimized implementation - // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized - // implementation and discard the generic implementation. If we don't - // and keep both implementations, the linker will yell at us about - // duplicate symbols! - for &src in sources { - let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap(); - if src.contains("/") { - // Arch-optimized implementation (preferred) - self.map.insert(symbol, src); - } else { - // Generic implementation - if !self.map.contains_key(symbol) { - self.map.insert(symbol, src); - } - } - } - } - - fn remove(&mut self, symbols: &[&str]) { - for symbol in symbols { - self.map.remove(*symbol).unwrap(); - } - } -} +use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); @@ -61,376 +10,416 @@ fn main() { return; } - let Cfg { ref target_arch, ref target_os, ref target_env, ref target_vendor, .. } = - Cfg::new(&target).unwrap_or_else(|e| { - writeln!(io::stderr(), "{}", e).ok(); - process::exit(1) - }); // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the // target triple. This is usually correct for our built-in targets but can break in presence of // custom targets, which can have arbitrary names. let llvm_target = target.split('-').collect::>(); // Build missing intrinsics from compiler-rt C source code - match () { - #[cfg(feature = "c")] - () => { - let target_vendor = target_vendor.as_ref().unwrap(); - let cfg = &mut gcc::Config::new(); - - if target_env == "msvc" { - // Don't pull in extra libraries on MSVC - cfg.flag("/Zl"); - - // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP - cfg.define("__func__", Some("__FUNCTION__")); - } else { - // Turn off various features of gcc and such, mostly copying - // compiler-rt's build system already - cfg.flag("-fno-builtin"); - cfg.flag("-fvisibility=hidden"); - cfg.flag("-fomit-frame-pointer"); - cfg.flag("-ffreestanding"); - cfg.define("VISIBILITY_HIDDEN", None); - } + #[cfg(feature = "c")] + c::compile(&llvm_target); - // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to - // target to make sure that the assembly implementations really work for the target. If the - // implementation is not valid for the arch, then gcc will error when compiling it. - if llvm_target[0].starts_with("thumb") { - cfg.flag("-mthumb"); + // To compile intrinsics.rs for thumb targets, where there is no libc + if llvm_target[0].starts_with("thumb") { + println!("cargo:rustc-cfg=thumb") + } - if llvm_target.last() == Some(&"eabihf") { - cfg.flag("-mfloat-abi=hard"); - } - } + // compiler-rt `cfg`s away some intrinsics for thumbv6m because that target doesn't have full + // THUMBv2 support. We have to cfg our code accordingly. + if llvm_target[0] == "thumbv6m" { + println!("cargo:rustc-cfg=thumbv6m") + } +} - if llvm_target[0] == "thumbv6m" { - cfg.flag("-march=armv6-m"); - } +#[cfg(feature = "c")] +mod c { + extern crate gcc; - if llvm_target[0] == "thumbv7m" { - cfg.flag("-march=armv7-m"); - } + use std::collections::BTreeMap; + use std::env; + use std::io::Write; + use std::path::Path; - if llvm_target[0] == "thumbv7em" { - cfg.flag("-march=armv7e-m"); - } + struct Sources { + // SYMBOL -> PATH TO SOURCE + map: BTreeMap<&'static str, &'static str>, + } - let mut sources = Sources::new(); - sources.extend(&["absvdi2.c", - "absvsi2.c", - "addvdi3.c", - "addvsi3.c", - "apple_versioning.c", - "clzdi2.c", - "clzsi2.c", - "cmpdi2.c", - "comparedf2.c", - "comparesf2.c", - "ctzdi2.c", - "ctzsi2.c", - "divdc3.c", - "divdf3.c", - "divsc3.c", - "divsf3.c", - "divxc3.c", - "extendsfdf2.c", - "extendhfsf2.c", - "ffsdi2.c", - "fixdfdi.c", - "fixdfsi.c", - "fixsfdi.c", - "fixsfsi.c", - "fixunsdfdi.c", - "fixunsdfsi.c", - "fixunssfdi.c", - "fixunssfsi.c", - "fixunsxfdi.c", - "fixunsxfsi.c", - "fixxfdi.c", - "floatdidf.c", - "floatdisf.c", - "floatdixf.c", - "floatsidf.c", - "floatsisf.c", - "floatundidf.c", - "floatundisf.c", - "floatundixf.c", - "floatunsidf.c", - "floatunsisf.c", - "int_util.c", - "muldc3.c", - "muldf3.c", - "mulsc3.c", - "mulsf3.c", - "mulvdi3.c", - "mulvsi3.c", - "mulxc3.c", - "negdf2.c", - "negdi2.c", - "negsf2.c", - "negvdi2.c", - "negvsi2.c", - "paritydi2.c", - "paritysi2.c", - "popcountdi2.c", - "popcountsi2.c", - "powixf2.c", - "subvdi3.c", - "subvsi3.c", - "truncdfhf2.c", - "truncdfsf2.c", - "truncsfhf2.c", - "ucmpdi2.c"]); - - if target_os != "ios" { - sources.extend(&["absvti2.c", - "addvti3.c", - "clzti2.c", - "cmpti2.c", - "ctzti2.c", - "ffsti2.c", - "fixdfti.c", - "fixsfti.c", - "fixunsdfti.c", - "fixunssfti.c", - "fixunsxfti.c", - "fixxfti.c", - "floattidf.c", - "floattisf.c", - "floattixf.c", - "floatuntidf.c", - "floatuntisf.c", - "floatuntixf.c", - "mulvti3.c", - "negti2.c", - "negvti2.c", - "parityti2.c", - "popcountti2.c", - "subvti3.c", - "ucmpti2.c"]); + impl Sources { + fn new() -> Sources { + Sources { map: BTreeMap::new() } + } + + fn extend(&mut self, sources: &[&'static str]) { + // NOTE Some intrinsics have both a generic implementation (e.g. + // `floatdidf.c`) and an arch optimized implementation + // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized + // implementation and discard the generic implementation. If we don't + // and keep both implementations, the linker will yell at us about + // duplicate symbols! + for &src in sources { + let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap(); + if src.contains("/") { + // Arch-optimized implementation (preferred) + self.map.insert(symbol, src); + } else { + // Generic implementation + if !self.map.contains_key(symbol) { + self.map.insert(symbol, src); + } + } } + } - if target_vendor == "apple" { - sources.extend(&["atomic_flag_clear.c", - "atomic_flag_clear_explicit.c", - "atomic_flag_test_and_set.c", - "atomic_flag_test_and_set_explicit.c", - "atomic_signal_fence.c", - "atomic_thread_fence.c"]); + fn remove(&mut self, symbols: &[&str]) { + for symbol in symbols { + self.map.remove(*symbol).unwrap(); } + } + } - if target_env == "msvc" { - if target_arch == "x86_64" { - sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); - } - } else { - if target_os != "freebsd" && target_os != "netbsd" { - sources.extend(&["gcc_personality_v0.c"]); - } + /// Compile intrinsics from the compiler-rt C source code + pub fn compile(llvm_target: &[&str]){ + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); + + let cfg = &mut gcc::Config::new(); + + if target_env == "msvc" { + // Don't pull in extra libraries on MSVC + cfg.flag("/Zl"); + + // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP + cfg.define("__func__", Some("__FUNCTION__")); + } else { + // Turn off various features of gcc and such, mostly copying + // compiler-rt's build system already + cfg.flag("-fno-builtin"); + cfg.flag("-fvisibility=hidden"); + cfg.flag("-fomit-frame-pointer"); + cfg.flag("-ffreestanding"); + cfg.define("VISIBILITY_HIDDEN", None); + } - if target_arch == "x86_64" { - sources.extend(&["x86_64/chkstk.S", - "x86_64/chkstk2.S", - "x86_64/floatdidf.c", - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S"]); - } + // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to + // target to make sure that the assembly implementations really work for the target. If the + // implementation is not valid for the arch, then gcc will error when compiling it. + if llvm_target[0].starts_with("thumb") { + cfg.flag("-mthumb"); - if target_arch == "x86" { - sources.extend(&["i386/ashldi3.S", - "i386/ashrdi3.S", - "i386/chkstk.S", - "i386/chkstk2.S", - "i386/divdi3.S", - "i386/floatdidf.S", - "i386/floatdisf.S", - "i386/floatdixf.S", - "i386/floatundidf.S", - "i386/floatundisf.S", - "i386/floatundixf.S", - "i386/lshrdi3.S", - "i386/moddi3.S", - "i386/muldi3.S", - "i386/udivdi3.S", - "i386/umoddi3.S"]); - } + if llvm_target.last() == Some(&"eabihf") { + cfg.flag("-mfloat-abi=hard"); } + } - if target_arch == "arm" && target_os != "ios" { - sources.extend(&["arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", - "arm/aeabi_dcmp.S", - "arm/aeabi_div0.c", - "arm/aeabi_drsub.c", - "arm/aeabi_fcmp.S", - "arm/aeabi_frsub.c", - "arm/bswapdi2.S", - "arm/bswapsi2.S", - "arm/clzdi2.S", - "arm/clzsi2.S", - "arm/comparesf2.S", - "arm/divmodsi4.S", - "arm/divsi3.S", - "arm/modsi3.S", - "arm/switch16.S", - "arm/switch32.S", - "arm/switch8.S", - "arm/switchu8.S", - "arm/sync_synchronize.S", - "arm/udivmodsi4.S", - "arm/udivsi3.S", - "arm/umodsi3.S"]); - } + if llvm_target[0] == "thumbv6m" { + cfg.flag("-march=armv6-m"); + } - if llvm_target[0] == "armv7" { - sources.extend(&["arm/sync_fetch_and_add_4.S", - "arm/sync_fetch_and_add_8.S", - "arm/sync_fetch_and_and_4.S", - "arm/sync_fetch_and_and_8.S", - "arm/sync_fetch_and_max_4.S", - "arm/sync_fetch_and_max_8.S", - "arm/sync_fetch_and_min_4.S", - "arm/sync_fetch_and_min_8.S", - "arm/sync_fetch_and_nand_4.S", - "arm/sync_fetch_and_nand_8.S", - "arm/sync_fetch_and_or_4.S", - "arm/sync_fetch_and_or_8.S", - "arm/sync_fetch_and_sub_4.S", - "arm/sync_fetch_and_sub_8.S", - "arm/sync_fetch_and_umax_4.S", - "arm/sync_fetch_and_umax_8.S", - "arm/sync_fetch_and_umin_4.S", - "arm/sync_fetch_and_umin_8.S", - "arm/sync_fetch_and_xor_4.S", - "arm/sync_fetch_and_xor_8.S"]); - } + if llvm_target[0] == "thumbv7m" { + cfg.flag("-march=armv7-m"); + } - if llvm_target.last().unwrap().ends_with("eabihf") { - if !llvm_target[0].starts_with("thumbv7em") { - sources.extend(&["arm/adddf3vfp.S", - "arm/addsf3vfp.S", - "arm/divdf3vfp.S", - "arm/divsf3vfp.S", - "arm/eqdf2vfp.S", - "arm/eqsf2vfp.S", - "arm/extendsfdf2vfp.S", - "arm/fixdfsivfp.S", - "arm/fixsfsivfp.S", - "arm/fixunsdfsivfp.S", - "arm/fixunssfsivfp.S", - "arm/floatsidfvfp.S", - "arm/floatsisfvfp.S", - "arm/floatunssidfvfp.S", - "arm/floatunssisfvfp.S", - "arm/gedf2vfp.S", - "arm/gesf2vfp.S", - "arm/gtdf2vfp.S", - "arm/gtsf2vfp.S", - "arm/ledf2vfp.S", - "arm/lesf2vfp.S", - "arm/ltdf2vfp.S", - "arm/ltsf2vfp.S", - "arm/muldf3vfp.S", - "arm/mulsf3vfp.S", - "arm/nedf2vfp.S", - "arm/nesf2vfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", - "arm/subdf3vfp.S", - "arm/subsf3vfp.S"]); - } + if llvm_target[0] == "thumbv7em" { + cfg.flag("-march=armv7e-m"); + } - sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); + let mut sources = Sources::new(); + sources.extend(&["absvdi2.c", + "absvsi2.c", + "addvdi3.c", + "addvsi3.c", + "apple_versioning.c", + "clzdi2.c", + "clzsi2.c", + "cmpdi2.c", + "comparedf2.c", + "comparesf2.c", + "ctzdi2.c", + "ctzsi2.c", + "divdc3.c", + "divdf3.c", + "divsc3.c", + "divsf3.c", + "divxc3.c", + "extendsfdf2.c", + "extendhfsf2.c", + "ffsdi2.c", + "fixdfdi.c", + "fixdfsi.c", + "fixsfdi.c", + "fixsfsi.c", + "fixunsdfdi.c", + "fixunsdfsi.c", + "fixunssfdi.c", + "fixunssfsi.c", + "fixunsxfdi.c", + "fixunsxfsi.c", + "fixxfdi.c", + "floatdidf.c", + "floatdisf.c", + "floatdixf.c", + "floatsidf.c", + "floatsisf.c", + "floatundidf.c", + "floatundisf.c", + "floatundixf.c", + "floatunsidf.c", + "floatunsisf.c", + "int_util.c", + "muldc3.c", + "muldf3.c", + "mulsc3.c", + "mulsf3.c", + "mulvdi3.c", + "mulvsi3.c", + "mulxc3.c", + "negdf2.c", + "negdi2.c", + "negsf2.c", + "negvdi2.c", + "negvsi2.c", + "paritydi2.c", + "paritysi2.c", + "popcountdi2.c", + "popcountsi2.c", + "powixf2.c", + "subvdi3.c", + "subvsi3.c", + "truncdfhf2.c", + "truncdfsf2.c", + "truncsfhf2.c", + "ucmpdi2.c"]); + + if target_os != "ios" { + sources.extend(&["absvti2.c", + "addvti3.c", + "clzti2.c", + "cmpti2.c", + "ctzti2.c", + "ffsti2.c", + "fixdfti.c", + "fixsfti.c", + "fixunsdfti.c", + "fixunssfti.c", + "fixunsxfti.c", + "fixxfti.c", + "floattidf.c", + "floattisf.c", + "floattixf.c", + "floatuntidf.c", + "floatuntisf.c", + "floatuntixf.c", + "mulvti3.c", + "negti2.c", + "negvti2.c", + "parityti2.c", + "popcountti2.c", + "subvti3.c", + "ucmpti2.c"]); + } - } + if target_vendor == "apple" { + sources.extend(&["atomic_flag_clear.c", + "atomic_flag_clear_explicit.c", + "atomic_flag_test_and_set.c", + "atomic_flag_test_and_set_explicit.c", + "atomic_signal_fence.c", + "atomic_thread_fence.c"]); + } - if target_arch == "aarch64" { - sources.extend(&["comparetf2.c", - "extenddftf2.c", - "extendsftf2.c", - "fixtfdi.c", - "fixtfsi.c", - "fixtfti.c", - "fixunstfdi.c", - "fixunstfsi.c", - "fixunstfti.c", - "floatditf.c", - "floatsitf.c", - "floatunditf.c", - "floatunsitf.c", - "multc3.c", - "trunctfdf2.c", - "trunctfsf2.c"]); + if target_env == "msvc" { + if target_arch == "x86_64" { + sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); + } + } else { + if target_os != "freebsd" && target_os != "netbsd" { + sources.extend(&["gcc_personality_v0.c"]); } - // Remove the assembly implementations that won't compile for the target - if llvm_target[0] == "thumbv6m" { - sources.remove(&["aeabi_cdcmp", - "aeabi_cfcmp", - "aeabi_dcmp", - "aeabi_fcmp", - "clzdi2", - "clzsi2", - "comparesf2", - "divmodsi4", - "divsi3", - "modsi3", - "switch16", - "switch32", - "switch8", - "switchu8", - "udivmodsi4", - "udivsi3", - "umodsi3"]); - - // But use some generic implementations where possible - sources.extend(&["clzdi2.c", "clzsi2.c"]) + if target_arch == "x86_64" { + sources.extend(&["x86_64/chkstk.S", + "x86_64/chkstk2.S", + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S"]); } - if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { - sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); + if target_arch == "x86" { + sources.extend(&["i386/ashldi3.S", + "i386/ashrdi3.S", + "i386/chkstk.S", + "i386/chkstk2.S", + "i386/divdi3.S", + "i386/floatdidf.S", + "i386/floatdisf.S", + "i386/floatdixf.S", + "i386/floatundidf.S", + "i386/floatundisf.S", + "i386/floatundixf.S", + "i386/lshrdi3.S", + "i386/moddi3.S", + "i386/muldi3.S", + "i386/udivdi3.S", + "i386/umoddi3.S"]); } + } - let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { - Path::new("../../libcompiler_builtins") - } else { - Path::new(".") - }; - - let src_dir = root.join("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins"); - for src in sources.map.values() { - let src = src_dir.join(src); - cfg.file(&src); - println!("cargo:rerun-if-changed={}", src.display()); + if target_arch == "arm" && target_os != "ios" { + sources.extend(&["arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + "arm/aeabi_dcmp.S", + "arm/aeabi_div0.c", + "arm/aeabi_drsub.c", + "arm/aeabi_fcmp.S", + "arm/aeabi_frsub.c", + "arm/bswapdi2.S", + "arm/bswapsi2.S", + "arm/clzdi2.S", + "arm/clzsi2.S", + "arm/comparesf2.S", + "arm/divmodsi4.S", + "arm/divsi3.S", + "arm/modsi3.S", + "arm/switch16.S", + "arm/switch32.S", + "arm/switch8.S", + "arm/switchu8.S", + "arm/sync_synchronize.S", + "arm/udivmodsi4.S", + "arm/udivsi3.S", + "arm/umodsi3.S"]); + } + + if llvm_target[0] == "armv7" { + sources.extend(&["arm/sync_fetch_and_add_4.S", + "arm/sync_fetch_and_add_8.S", + "arm/sync_fetch_and_and_4.S", + "arm/sync_fetch_and_and_8.S", + "arm/sync_fetch_and_max_4.S", + "arm/sync_fetch_and_max_8.S", + "arm/sync_fetch_and_min_4.S", + "arm/sync_fetch_and_min_8.S", + "arm/sync_fetch_and_nand_4.S", + "arm/sync_fetch_and_nand_8.S", + "arm/sync_fetch_and_or_4.S", + "arm/sync_fetch_and_or_8.S", + "arm/sync_fetch_and_sub_4.S", + "arm/sync_fetch_and_sub_8.S", + "arm/sync_fetch_and_umax_4.S", + "arm/sync_fetch_and_umax_8.S", + "arm/sync_fetch_and_umin_4.S", + "arm/sync_fetch_and_umin_8.S", + "arm/sync_fetch_and_xor_4.S", + "arm/sync_fetch_and_xor_8.S"]); + } + + if llvm_target.last().unwrap().ends_with("eabihf") { + if !llvm_target[0].starts_with("thumbv7em") { + sources.extend(&["arm/adddf3vfp.S", + "arm/addsf3vfp.S", + "arm/divdf3vfp.S", + "arm/divsf3vfp.S", + "arm/eqdf2vfp.S", + "arm/eqsf2vfp.S", + "arm/extendsfdf2vfp.S", + "arm/fixdfsivfp.S", + "arm/fixsfsivfp.S", + "arm/fixunsdfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsidfvfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssidfvfp.S", + "arm/floatunssisfvfp.S", + "arm/gedf2vfp.S", + "arm/gesf2vfp.S", + "arm/gtdf2vfp.S", + "arm/gtsf2vfp.S", + "arm/ledf2vfp.S", + "arm/lesf2vfp.S", + "arm/ltdf2vfp.S", + "arm/ltsf2vfp.S", + "arm/muldf3vfp.S", + "arm/mulsf3vfp.S", + "arm/nedf2vfp.S", + "arm/nesf2vfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/subdf3vfp.S", + "arm/subsf3vfp.S"]); } - cfg.compile("libcompiler-rt.a"); + sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); + } - #[cfg(not(feature = "c"))] - () => {} - } - // To filter away some flaky test (see src/float/add.rs for details) - if llvm_target[0].starts_with("arm") && - llvm_target.last().unwrap().contains("gnueabi") { - println!("cargo:rustc-cfg=arm_linux") - } + if target_arch == "aarch64" { + sources.extend(&["comparetf2.c", + "extenddftf2.c", + "extendsftf2.c", + "fixtfdi.c", + "fixtfsi.c", + "fixtfti.c", + "fixunstfdi.c", + "fixunstfsi.c", + "fixunstfti.c", + "floatditf.c", + "floatsitf.c", + "floatunditf.c", + "floatunsitf.c", + "multc3.c", + "trunctfdf2.c", + "trunctfsf2.c"]); + } - // To compile intrinsics.rs for thumb targets, where there is no libc - if llvm_target[0].starts_with("thumb") { - println!("cargo:rustc-cfg=thumb") - } + // Remove the assembly implementations that won't compile for the target + if llvm_target[0] == "thumbv6m" { + sources.remove(&["aeabi_cdcmp", + "aeabi_cfcmp", + "aeabi_dcmp", + "aeabi_fcmp", + "clzdi2", + "clzsi2", + "comparesf2", + "divmodsi4", + "divsi3", + "modsi3", + "switch16", + "switch32", + "switch8", + "switchu8", + "udivmodsi4", + "udivsi3", + "umodsi3"]); + + // But use some generic implementations where possible + sources.extend(&["clzdi2.c", "clzsi2.c"]) + } - // compiler-rt `cfg`s away some intrinsics for thumbv6m because that target doesn't have full - // THUMBv2 support. We have to cfg our code accordingly. - if llvm_target[0] == "thumbv6m" { - println!("cargo:rustc-cfg=thumbv6m") + if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { + sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); + } + + let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { + Path::new("../../libcompiler_builtins") + } else { + Path::new(".") + }; + + let src_dir = root.join("c/compiler-rt/lib/builtins"); + for src in sources.map.values() { + let src = src_dir.join(src); + cfg.file(&src); + println!("cargo:rerun-if-changed={}", src.display()); + } + + cfg.compile("libcompiler-rt.a"); } } -- cgit 1.4.1-3-g733a5 From 5b2585403daf4187a465a254032864d164dd95c3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 11:22:17 -0500 Subject: remove unused Cargo subprojects --- library/compiler-builtins/compiler-rt/Cargo.toml | 8 -- .../compiler-rt/compiler-rt-cdylib/Cargo.toml | 12 -- .../compiler-rt/compiler-rt-cdylib/build.rs | 104 ----------------- .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 126 --------------------- library/compiler-builtins/compiler-rt/src/lib.rs | 35 ------ library/compiler-builtins/gcc_s/Cargo.toml | 7 -- library/compiler-builtins/gcc_s/src/lib.rs | 39 ------- 7 files changed, 331 deletions(-) delete mode 100644 library/compiler-builtins/compiler-rt/Cargo.toml delete mode 100644 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml delete mode 100644 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs delete mode 100644 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs delete mode 100644 library/compiler-builtins/compiler-rt/src/lib.rs delete mode 100644 library/compiler-builtins/gcc_s/Cargo.toml delete mode 100644 library/compiler-builtins/gcc_s/src/lib.rs diff --git a/library/compiler-builtins/compiler-rt/Cargo.toml b/library/compiler-builtins/compiler-rt/Cargo.toml deleted file mode 100644 index cac87733a62..00000000000 --- a/library/compiler-builtins/compiler-rt/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "compiler-rt" -version = "0.1.0" -authors = ["Alex Crichton "] - -[dependencies] -compiler-rt-cdylib = { path = "compiler-rt-cdylib" } -libloading = "0.3" diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml deleted file mode 100644 index ec9c6af1831..00000000000 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "compiler-rt-cdylib" -version = "0.1.0" -authors = ["Alex Crichton "] -build = "build.rs" - -[lib] -crate-type = ["cdylib"] - -[build-dependencies] -gcc = "0.3.36" - diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs deleted file mode 100644 index c07ea70cfd9..00000000000 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs +++ /dev/null @@ -1,104 +0,0 @@ -extern crate gcc; - -use std::env; -use std::path::Path; -use std::process::Command; - -struct Sources { - files: Vec<&'static str>, -} - -impl Sources { - fn new() -> Sources { - Sources { files: Vec::new() } - } - - fn extend(&mut self, sources: &[&'static str]) { - self.files.extend(sources); - } -} - -fn main() { - if !Path::new("compiler-rt/.git").exists() { - let _ = Command::new("git").args(&["submodule", "update", "--init"]) - .status(); - } - - let target = env::var("TARGET").expect("TARGET was not set"); - let cfg = &mut gcc::Config::new(); - - if target.contains("msvc") { - cfg.define("__func__", Some("__FUNCTION__")); - } else { - cfg.flag("-fno-builtin"); - cfg.flag("-fomit-frame-pointer"); - cfg.flag("-ffreestanding"); - } - - let mut sources = Sources::new(); - - sources.extend(&[ - "muldi3.c", - "mulosi4.c", - "mulodi4.c", - "divsi3.c", - "divdi3.c", - "modsi3.c", - "moddi3.c", - "divmodsi4.c", - "divmoddi4.c", - "ashldi3.c", - "ashrdi3.c", - "lshrdi3.c", - "udivdi3.c", - "umoddi3.c", - "udivmoddi4.c", - "udivsi3.c", - "umodsi3.c", - "udivmodsi4.c", - "adddf3.c", - "addsf3.c", - "powidf2.c", - "powisf2.c", - "subdf3.c", - "subsf3.c", - "floatsisf.c", - "floatsidf.c", - "floatdidf.c", - "floatunsisf.c", - "floatunsidf.c", - "floatundidf.c", - "fixsfsi.c", - "fixsfdi.c", - "fixdfsi.c", - "fixdfdi.c", - "fixunssfsi.c", - "fixunssfdi.c", - "fixunsdfsi.c", - "fixunsdfdi.c", - // 128 bit integers - "lshrti3.c", - "modti3.c", - "muloti4.c", - "multi3.c", - "udivmodti4.c", - "udivti3.c", - "umodti3.c", - "ashlti3.c", - "ashrti3.c", - "divti3.c", - ]); - - let builtins_dir = Path::new("compiler-rt/lib/builtins"); - for src in sources.files.iter() { - cfg.file(builtins_dir.join(src)); - } - - cfg.compile("libcompiler-rt.a"); - - println!("cargo:rerun-if-changed=build.rs"); - - for source in sources.files.iter() { - println!("cargo:rerun-if-changed={}", builtins_dir.join(source).display()); - } -} diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs deleted file mode 100644 index 2f08314bb88..00000000000 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ /dev/null @@ -1,126 +0,0 @@ -#![feature(lang_items)] -#![no_std] - -extern { - fn __ashldi3(); - fn __ashrdi3(); - fn __divdi3(); - fn __divmoddi4(); - fn __divmodsi4(); - fn __divsi3(); - fn __lshrdi3(); - fn __moddi3(); - fn __modsi3(); - fn __muldi3(); - fn __mulodi4(); - fn __mulosi4(); - fn __udivdi3(); - fn __udivmoddi4(); - fn __udivmodsi4(); - fn __udivsi3(); - fn __umoddi3(); - fn __umodsi3(); - fn __addsf3(); - fn __adddf3(); - fn __powisf2(); - fn __powidf2(); - fn __subsf3(); - fn __subdf3(); - fn __floatsisf(); - fn __floatsidf(); - fn __floatdidf(); - fn __floatunsisf(); - fn __floatunsidf(); - fn __floatundidf(); - fn __fixsfsi(); - fn __fixsfdi(); - fn __fixdfsi(); - fn __fixdfdi(); - fn __fixunssfsi(); - fn __fixunssfdi(); - fn __fixunsdfsi(); - fn __fixunsdfdi(); -} - -macro_rules! declare { - ($func:ident, $sym:ident) => { - #[no_mangle] - pub extern fn $func() -> usize { - $sym as usize - } - } -} - -declare!(___ashldi3, __ashldi3); -declare!(___ashrdi3, __ashrdi3); -declare!(___divdi3, __divdi3); -declare!(___divmoddi4, __divmoddi4); -declare!(___divmodsi4, __divmodsi4); -declare!(___divsi3, __divsi3); -declare!(___lshrdi3, __lshrdi3); -declare!(___moddi3, __moddi3); -declare!(___modsi3, __modsi3); -declare!(___muldi3, __muldi3); -declare!(___mulodi4, __mulodi4); -declare!(___mulosi4, __mulosi4); -declare!(___udivdi3, __udivdi3); -declare!(___udivmoddi4, __udivmoddi4); -declare!(___udivmodsi4, __udivmodsi4); -declare!(___udivsi3, __udivsi3); -declare!(___umoddi3, __umoddi3); -declare!(___umodsi3, __umodsi3); -declare!(___addsf3, __addsf3); -declare!(___adddf3, __adddf3); -declare!(___powisf2, __powisf2); -declare!(___powidf2, __powidf2); -declare!(___subsf3, __subsf3); -declare!(___subdf3, __subdf3); -declare!(___floatsisf, __floatsisf); -declare!(___floatsidf, __floatsidf); -declare!(___floatdidf, __floatdidf); -declare!(___floatunsisf, __floatunsisf); -declare!(___floatunsidf, __floatunsidf); -declare!(___floatundidf, __floatundidf); -declare!(___fixsfsi, __fixsfsi); -declare!(___fixsfdi, __fixsfdi); -declare!(___fixdfsi, __fixdfsi); -declare!(___fixdfdi, __fixdfdi); -declare!(___fixunssfsi, __fixunssfsi); -declare!(___fixunssfdi, __fixunssfdi); -declare!(___fixunsdfsi, __fixunsdfsi); -declare!(___fixunsdfdi, __fixunsdfdi); - -#[cfg(all(not(windows), - not(target_arch = "mips64"), - not(target_arch = "mips64el"), - target_pointer_width="64"))] -pub mod int_128 { - extern { - fn __lshrti3(); - fn __modti3(); - fn __muloti4(); - fn __multi3(); - fn __udivmodti4(); - fn __udivti3(); - fn __umodti3(); - fn __ashlti3(); - fn __ashrti3(); - fn __divti3(); - } - - declare!(___lshrti3, __lshrti3); - declare!(___modti3, __modti3); - declare!(___muloti4, __muloti4); - declare!(___multi3, __multi3); - declare!(___udivmodti4, __udivmodti4); - declare!(___udivti3, __udivti3); - declare!(___umodti3, __umodti3); - declare!(___ashlti3, __ashlti3); - declare!(___ashrti3, __ashrti3); - declare!(___divti3, __divti3); -} - -#[lang = "eh_personality"] -fn eh_personality() {} -#[lang = "panic_fmt"] -fn panic_fmt() {} diff --git a/library/compiler-builtins/compiler-rt/src/lib.rs b/library/compiler-builtins/compiler-rt/src/lib.rs deleted file mode 100644 index ca99f397f55..00000000000 --- a/library/compiler-builtins/compiler-rt/src/lib.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![feature(drop_types_in_const)] - -extern crate libloading; - -use std::sync::{Once, ONCE_INIT}; -use std::env; - -use libloading::Library; - -fn compiler_rt() -> &'static Library { - let dir = env::current_exe().unwrap(); - let cdylib = dir.parent().unwrap().read_dir().unwrap().map(|c| { - c.unwrap().path() - }).find(|path| { - path.file_name().unwrap().to_str().unwrap().contains("compiler_rt_cdylib") - }).unwrap(); - - unsafe { - static mut COMPILER_RT: Option = None; - static INIT: Once = ONCE_INIT; - - INIT.call_once(|| { - COMPILER_RT = Some(Library::new(&cdylib).unwrap()); - }); - COMPILER_RT.as_ref().unwrap() - } -} - -pub fn get(sym: &str) -> usize { - unsafe { - let sym = format!("_{}", sym); - let f: fn() -> usize = *compiler_rt().get(sym.as_bytes()).unwrap(); - f() - } -} diff --git a/library/compiler-builtins/gcc_s/Cargo.toml b/library/compiler-builtins/gcc_s/Cargo.toml deleted file mode 100644 index 4e3080fa408..00000000000 --- a/library/compiler-builtins/gcc_s/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -authors = ["Jorge Aparicio "] -name = "gcc_s" -version = "0.1.0" - -[dependencies] -libloading = "0.3.0" diff --git a/library/compiler-builtins/gcc_s/src/lib.rs b/library/compiler-builtins/gcc_s/src/lib.rs deleted file mode 100644 index e3417ffb591..00000000000 --- a/library/compiler-builtins/gcc_s/src/lib.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![feature(drop_types_in_const)] - -extern crate libloading; - -use std::sync::{Once, ONCE_INIT}; - -use libloading::Library; - -static mut GCC_S: Option = None; - -#[cfg(not(windows))] -fn gcc_s() -> &'static Library { - #[cfg(not(target_os = "macos"))] - const LIBGCC_S: &'static str = "libgcc_s.so.1"; - - #[cfg(target_os = "macos")] - const LIBGCC_S: &'static str = "libgcc_s.1.dylib"; - - unsafe { - static INIT: Once = ONCE_INIT; - - INIT.call_once(|| { - GCC_S = Some(Library::new(LIBGCC_S).unwrap()); - }); - GCC_S.as_ref().unwrap() - } -} - -#[cfg(windows)] -pub fn get(_sym: &str) -> Option { - None -} - -#[cfg(not(windows))] -pub fn get(sym: &str) -> Option { - unsafe { - gcc_s().get(sym.as_bytes()).ok().map(|s| *s) - } -} -- cgit 1.4.1-3-g733a5 From dfc1a7d814b323ce032a96431dea1e8b55be2a98 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 11:23:03 -0500 Subject: move the compiler-rt submodule to the root --- library/compiler-builtins/.gitmodules | 2 +- library/compiler-builtins/build.rs | 3 +-- library/compiler-builtins/c/compiler-rt | 1 - library/compiler-builtins/compiler-rt | 1 + 4 files changed, 3 insertions(+), 4 deletions(-) delete mode 160000 library/compiler-builtins/c/compiler-rt create mode 160000 library/compiler-builtins/compiler-rt diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index ed1a78f9fb3..bbdcf701cd6 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ [submodule "compiler-rt/compiler-rt-cdylib/compiler-rt"] - path = c/compiler-rt + path = compiler-rt url = https://github.com/rust-lang/compiler-rt diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 145f71575d2..46aa05e7749 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -37,7 +37,6 @@ mod c { use std::collections::BTreeMap; use std::env; - use std::io::Write; use std::path::Path; struct Sources { @@ -413,7 +412,7 @@ mod c { Path::new(".") }; - let src_dir = root.join("c/compiler-rt/lib/builtins"); + let src_dir = root.join("compiler-rt/lib/builtins"); for src in sources.map.values() { let src = src_dir.join(src); cfg.file(&src); diff --git a/library/compiler-builtins/c/compiler-rt b/library/compiler-builtins/c/compiler-rt deleted file mode 160000 index 3bc0272cab9..00000000000 --- a/library/compiler-builtins/c/compiler-rt +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79 diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt new file mode 160000 index 00000000000..3bc0272cab9 --- /dev/null +++ b/library/compiler-builtins/compiler-rt @@ -0,0 +1 @@ +Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79 -- cgit 1.4.1-3-g733a5 From 447ebe4f915a366e44f6538f1e3b3c2a83251fff Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 11:29:31 -0500 Subject: rustfmt --- library/compiler-builtins/build.rs | 514 ++++++++++++++++++++----------------- 1 file changed, 280 insertions(+), 234 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 46aa05e7749..cc778642b8c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -78,7 +78,7 @@ mod c { } /// Compile intrinsics from the compiler-rt C source code - pub fn compile(llvm_target: &[&str]){ + pub fn compile(llvm_target: &[&str]) { let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); @@ -102,9 +102,9 @@ mod c { cfg.define("VISIBILITY_HIDDEN", None); } - // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to - // target to make sure that the assembly implementations really work for the target. If the - // implementation is not valid for the arch, then gcc will error when compiling it. + // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going + // to target to make sure that the assembly implementations really work for the target. If + // the implementation is not valid for the arch, then gcc will error when compiling it. if llvm_target[0].starts_with("thumb") { cfg.flag("-mthumb"); @@ -126,112 +126,130 @@ mod c { } let mut sources = Sources::new(); - sources.extend(&["absvdi2.c", - "absvsi2.c", - "addvdi3.c", - "addvsi3.c", - "apple_versioning.c", - "clzdi2.c", - "clzsi2.c", - "cmpdi2.c", - "comparedf2.c", - "comparesf2.c", - "ctzdi2.c", - "ctzsi2.c", - "divdc3.c", - "divdf3.c", - "divsc3.c", - "divsf3.c", - "divxc3.c", - "extendsfdf2.c", - "extendhfsf2.c", - "ffsdi2.c", - "fixdfdi.c", - "fixdfsi.c", - "fixsfdi.c", - "fixsfsi.c", - "fixunsdfdi.c", - "fixunsdfsi.c", - "fixunssfdi.c", - "fixunssfsi.c", - "fixunsxfdi.c", - "fixunsxfsi.c", - "fixxfdi.c", - "floatdidf.c", - "floatdisf.c", - "floatdixf.c", - "floatsidf.c", - "floatsisf.c", - "floatundidf.c", - "floatundisf.c", - "floatundixf.c", - "floatunsidf.c", - "floatunsisf.c", - "int_util.c", - "muldc3.c", - "muldf3.c", - "mulsc3.c", - "mulsf3.c", - "mulvdi3.c", - "mulvsi3.c", - "mulxc3.c", - "negdf2.c", - "negdi2.c", - "negsf2.c", - "negvdi2.c", - "negvsi2.c", - "paritydi2.c", - "paritysi2.c", - "popcountdi2.c", - "popcountsi2.c", - "powixf2.c", - "subvdi3.c", - "subvsi3.c", - "truncdfhf2.c", - "truncdfsf2.c", - "truncsfhf2.c", - "ucmpdi2.c"]); + sources.extend( + &[ + "absvdi2.c", + "absvsi2.c", + "addvdi3.c", + "addvsi3.c", + "apple_versioning.c", + "clzdi2.c", + "clzsi2.c", + "cmpdi2.c", + "comparedf2.c", + "comparesf2.c", + "ctzdi2.c", + "ctzsi2.c", + "divdc3.c", + "divdf3.c", + "divsc3.c", + "divsf3.c", + "divxc3.c", + "extendsfdf2.c", + "extendhfsf2.c", + "ffsdi2.c", + "fixdfdi.c", + "fixdfsi.c", + "fixsfdi.c", + "fixsfsi.c", + "fixunsdfdi.c", + "fixunsdfsi.c", + "fixunssfdi.c", + "fixunssfsi.c", + "fixunsxfdi.c", + "fixunsxfsi.c", + "fixxfdi.c", + "floatdidf.c", + "floatdisf.c", + "floatdixf.c", + "floatsidf.c", + "floatsisf.c", + "floatundidf.c", + "floatundisf.c", + "floatundixf.c", + "floatunsidf.c", + "floatunsisf.c", + "int_util.c", + "muldc3.c", + "muldf3.c", + "mulsc3.c", + "mulsf3.c", + "mulvdi3.c", + "mulvsi3.c", + "mulxc3.c", + "negdf2.c", + "negdi2.c", + "negsf2.c", + "negvdi2.c", + "negvsi2.c", + "paritydi2.c", + "paritysi2.c", + "popcountdi2.c", + "popcountsi2.c", + "powixf2.c", + "subvdi3.c", + "subvsi3.c", + "truncdfhf2.c", + "truncdfsf2.c", + "truncsfhf2.c", + "ucmpdi2.c", + ], + ); if target_os != "ios" { - sources.extend(&["absvti2.c", - "addvti3.c", - "clzti2.c", - "cmpti2.c", - "ctzti2.c", - "ffsti2.c", - "fixdfti.c", - "fixsfti.c", - "fixunsdfti.c", - "fixunssfti.c", - "fixunsxfti.c", - "fixxfti.c", - "floattidf.c", - "floattisf.c", - "floattixf.c", - "floatuntidf.c", - "floatuntisf.c", - "floatuntixf.c", - "mulvti3.c", - "negti2.c", - "negvti2.c", - "parityti2.c", - "popcountti2.c", - "subvti3.c", - "ucmpti2.c"]); + sources.extend( + &[ + "absvti2.c", + "addvti3.c", + "clzti2.c", + "cmpti2.c", + "ctzti2.c", + "ffsti2.c", + "fixdfti.c", + "fixsfti.c", + "fixunsdfti.c", + "fixunssfti.c", + "fixunsxfti.c", + "fixxfti.c", + "floattidf.c", + "floattisf.c", + "floattixf.c", + "floatuntidf.c", + "floatuntisf.c", + "floatuntixf.c", + "mulvti3.c", + "negti2.c", + "negvti2.c", + "parityti2.c", + "popcountti2.c", + "subvti3.c", + "ucmpti2.c", + ], + ); } if target_vendor == "apple" { - sources.extend(&["atomic_flag_clear.c", - "atomic_flag_clear_explicit.c", - "atomic_flag_test_and_set.c", - "atomic_flag_test_and_set_explicit.c", - "atomic_signal_fence.c", - "atomic_thread_fence.c"]); + sources.extend( + &[ + "atomic_flag_clear.c", + "atomic_flag_clear_explicit.c", + "atomic_flag_test_and_set.c", + "atomic_flag_test_and_set_explicit.c", + "atomic_signal_fence.c", + "atomic_thread_fence.c", + ], + ); } if target_env == "msvc" { if target_arch == "x86_64" { - sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); + sources.extend( + &[ + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + ], + ); } } else { if target_os != "freebsd" && target_os != "netbsd" { @@ -239,120 +257,140 @@ mod c { } if target_arch == "x86_64" { - sources.extend(&["x86_64/chkstk.S", - "x86_64/chkstk2.S", - "x86_64/floatdidf.c", - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S"]); + sources.extend( + &[ + "x86_64/chkstk.S", + "x86_64/chkstk2.S", + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S", + ], + ); } if target_arch == "x86" { - sources.extend(&["i386/ashldi3.S", - "i386/ashrdi3.S", - "i386/chkstk.S", - "i386/chkstk2.S", - "i386/divdi3.S", - "i386/floatdidf.S", - "i386/floatdisf.S", - "i386/floatdixf.S", - "i386/floatundidf.S", - "i386/floatundisf.S", - "i386/floatundixf.S", - "i386/lshrdi3.S", - "i386/moddi3.S", - "i386/muldi3.S", - "i386/udivdi3.S", - "i386/umoddi3.S"]); + sources.extend( + &[ + "i386/ashldi3.S", + "i386/ashrdi3.S", + "i386/chkstk.S", + "i386/chkstk2.S", + "i386/divdi3.S", + "i386/floatdidf.S", + "i386/floatdisf.S", + "i386/floatdixf.S", + "i386/floatundidf.S", + "i386/floatundisf.S", + "i386/floatundixf.S", + "i386/lshrdi3.S", + "i386/moddi3.S", + "i386/muldi3.S", + "i386/udivdi3.S", + "i386/umoddi3.S", + ], + ); } } if target_arch == "arm" && target_os != "ios" { - sources.extend(&["arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", - "arm/aeabi_dcmp.S", - "arm/aeabi_div0.c", - "arm/aeabi_drsub.c", - "arm/aeabi_fcmp.S", - "arm/aeabi_frsub.c", - "arm/bswapdi2.S", - "arm/bswapsi2.S", - "arm/clzdi2.S", - "arm/clzsi2.S", - "arm/comparesf2.S", - "arm/divmodsi4.S", - "arm/divsi3.S", - "arm/modsi3.S", - "arm/switch16.S", - "arm/switch32.S", - "arm/switch8.S", - "arm/switchu8.S", - "arm/sync_synchronize.S", - "arm/udivmodsi4.S", - "arm/udivsi3.S", - "arm/umodsi3.S"]); + sources.extend( + &[ + "arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + "arm/aeabi_dcmp.S", + "arm/aeabi_div0.c", + "arm/aeabi_drsub.c", + "arm/aeabi_fcmp.S", + "arm/aeabi_frsub.c", + "arm/bswapdi2.S", + "arm/bswapsi2.S", + "arm/clzdi2.S", + "arm/clzsi2.S", + "arm/comparesf2.S", + "arm/divmodsi4.S", + "arm/divsi3.S", + "arm/modsi3.S", + "arm/switch16.S", + "arm/switch32.S", + "arm/switch8.S", + "arm/switchu8.S", + "arm/sync_synchronize.S", + "arm/udivmodsi4.S", + "arm/udivsi3.S", + "arm/umodsi3.S", + ], + ); } if llvm_target[0] == "armv7" { - sources.extend(&["arm/sync_fetch_and_add_4.S", - "arm/sync_fetch_and_add_8.S", - "arm/sync_fetch_and_and_4.S", - "arm/sync_fetch_and_and_8.S", - "arm/sync_fetch_and_max_4.S", - "arm/sync_fetch_and_max_8.S", - "arm/sync_fetch_and_min_4.S", - "arm/sync_fetch_and_min_8.S", - "arm/sync_fetch_and_nand_4.S", - "arm/sync_fetch_and_nand_8.S", - "arm/sync_fetch_and_or_4.S", - "arm/sync_fetch_and_or_8.S", - "arm/sync_fetch_and_sub_4.S", - "arm/sync_fetch_and_sub_8.S", - "arm/sync_fetch_and_umax_4.S", - "arm/sync_fetch_and_umax_8.S", - "arm/sync_fetch_and_umin_4.S", - "arm/sync_fetch_and_umin_8.S", - "arm/sync_fetch_and_xor_4.S", - "arm/sync_fetch_and_xor_8.S"]); + sources.extend( + &[ + "arm/sync_fetch_and_add_4.S", + "arm/sync_fetch_and_add_8.S", + "arm/sync_fetch_and_and_4.S", + "arm/sync_fetch_and_and_8.S", + "arm/sync_fetch_and_max_4.S", + "arm/sync_fetch_and_max_8.S", + "arm/sync_fetch_and_min_4.S", + "arm/sync_fetch_and_min_8.S", + "arm/sync_fetch_and_nand_4.S", + "arm/sync_fetch_and_nand_8.S", + "arm/sync_fetch_and_or_4.S", + "arm/sync_fetch_and_or_8.S", + "arm/sync_fetch_and_sub_4.S", + "arm/sync_fetch_and_sub_8.S", + "arm/sync_fetch_and_umax_4.S", + "arm/sync_fetch_and_umax_8.S", + "arm/sync_fetch_and_umin_4.S", + "arm/sync_fetch_and_umin_8.S", + "arm/sync_fetch_and_xor_4.S", + "arm/sync_fetch_and_xor_8.S", + ], + ); } if llvm_target.last().unwrap().ends_with("eabihf") { if !llvm_target[0].starts_with("thumbv7em") { - sources.extend(&["arm/adddf3vfp.S", - "arm/addsf3vfp.S", - "arm/divdf3vfp.S", - "arm/divsf3vfp.S", - "arm/eqdf2vfp.S", - "arm/eqsf2vfp.S", - "arm/extendsfdf2vfp.S", - "arm/fixdfsivfp.S", - "arm/fixsfsivfp.S", - "arm/fixunsdfsivfp.S", - "arm/fixunssfsivfp.S", - "arm/floatsidfvfp.S", - "arm/floatsisfvfp.S", - "arm/floatunssidfvfp.S", - "arm/floatunssisfvfp.S", - "arm/gedf2vfp.S", - "arm/gesf2vfp.S", - "arm/gtdf2vfp.S", - "arm/gtsf2vfp.S", - "arm/ledf2vfp.S", - "arm/lesf2vfp.S", - "arm/ltdf2vfp.S", - "arm/ltsf2vfp.S", - "arm/muldf3vfp.S", - "arm/mulsf3vfp.S", - "arm/nedf2vfp.S", - "arm/nesf2vfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", - "arm/subdf3vfp.S", - "arm/subsf3vfp.S"]); + sources.extend( + &[ + "arm/adddf3vfp.S", + "arm/addsf3vfp.S", + "arm/divdf3vfp.S", + "arm/divsf3vfp.S", + "arm/eqdf2vfp.S", + "arm/eqsf2vfp.S", + "arm/extendsfdf2vfp.S", + "arm/fixdfsivfp.S", + "arm/fixsfsivfp.S", + "arm/fixunsdfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsidfvfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssidfvfp.S", + "arm/floatunssisfvfp.S", + "arm/gedf2vfp.S", + "arm/gesf2vfp.S", + "arm/gtdf2vfp.S", + "arm/gtsf2vfp.S", + "arm/ledf2vfp.S", + "arm/lesf2vfp.S", + "arm/ltdf2vfp.S", + "arm/ltsf2vfp.S", + "arm/muldf3vfp.S", + "arm/mulsf3vfp.S", + "arm/nedf2vfp.S", + "arm/nesf2vfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/subdf3vfp.S", + "arm/subsf3vfp.S", + ], + ); } sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); @@ -360,43 +398,51 @@ mod c { } if target_arch == "aarch64" { - sources.extend(&["comparetf2.c", - "extenddftf2.c", - "extendsftf2.c", - "fixtfdi.c", - "fixtfsi.c", - "fixtfti.c", - "fixunstfdi.c", - "fixunstfsi.c", - "fixunstfti.c", - "floatditf.c", - "floatsitf.c", - "floatunditf.c", - "floatunsitf.c", - "multc3.c", - "trunctfdf2.c", - "trunctfsf2.c"]); + sources.extend( + &[ + "comparetf2.c", + "extenddftf2.c", + "extendsftf2.c", + "fixtfdi.c", + "fixtfsi.c", + "fixtfti.c", + "fixunstfdi.c", + "fixunstfsi.c", + "fixunstfti.c", + "floatditf.c", + "floatsitf.c", + "floatunditf.c", + "floatunsitf.c", + "multc3.c", + "trunctfdf2.c", + "trunctfsf2.c", + ], + ); } // Remove the assembly implementations that won't compile for the target if llvm_target[0] == "thumbv6m" { - sources.remove(&["aeabi_cdcmp", - "aeabi_cfcmp", - "aeabi_dcmp", - "aeabi_fcmp", - "clzdi2", - "clzsi2", - "comparesf2", - "divmodsi4", - "divsi3", - "modsi3", - "switch16", - "switch32", - "switch8", - "switchu8", - "udivmodsi4", - "udivsi3", - "umodsi3"]); + sources.remove( + &[ + "aeabi_cdcmp", + "aeabi_cfcmp", + "aeabi_dcmp", + "aeabi_fcmp", + "clzdi2", + "clzsi2", + "comparesf2", + "divmodsi4", + "divsi3", + "modsi3", + "switch16", + "switch32", + "switch8", + "switchu8", + "udivmodsi4", + "udivsi3", + "umodsi3", + ], + ); // But use some generic implementations where possible sources.extend(&["clzdi2.c", "clzsi2.c"]) -- cgit 1.4.1-3-g733a5 From af0d6847d704f3e8e2b9574b5688d9ce72b0d67e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 14:38:17 -0500 Subject: no_std compatible tester --- library/compiler-builtins/Cargo.toml | 11 +- library/compiler-builtins/build.rs | 2508 ++++++++++++++++++++ library/compiler-builtins/src/float/conv.rs | 1 + library/compiler-builtins/tests/adddf3.rs | 8 + library/compiler-builtins/tests/addsf3.rs | 8 + library/compiler-builtins/tests/ashldi3.rs | 8 + library/compiler-builtins/tests/ashlti3.rs | 8 + library/compiler-builtins/tests/ashrdi3.rs | 8 + library/compiler-builtins/tests/ashrti3.rs | 8 + library/compiler-builtins/tests/divdi3.rs | 8 + library/compiler-builtins/tests/divmoddi4.rs | 8 + library/compiler-builtins/tests/divmodsi4.rs | 8 + library/compiler-builtins/tests/divsi3.rs | 8 + library/compiler-builtins/tests/divti3.rs | 8 + library/compiler-builtins/tests/lshrdi3.rs | 8 + library/compiler-builtins/tests/lshrti3.rs | 8 + library/compiler-builtins/tests/moddi3.rs | 8 + library/compiler-builtins/tests/modsi3.rs | 8 + library/compiler-builtins/tests/modti3.rs | 8 + library/compiler-builtins/tests/muldi3.rs | 8 + library/compiler-builtins/tests/mulodi4.rs | 8 + library/compiler-builtins/tests/mulosi4.rs | 8 + library/compiler-builtins/tests/muloti4.rs | 8 + library/compiler-builtins/tests/multi3.rs | 8 + library/compiler-builtins/tests/powidf2.rs | 8 + library/compiler-builtins/tests/powisf2.rs | 8 + library/compiler-builtins/tests/subdf3.rs | 8 + library/compiler-builtins/tests/subsf3.rs | 8 + library/compiler-builtins/tests/udivdi3.rs | 8 + library/compiler-builtins/tests/udivmoddi4.rs | 8 + library/compiler-builtins/tests/udivmodsi4.rs | 8 + library/compiler-builtins/tests/udivmodti4.rs | 8 + library/compiler-builtins/tests/udivsi3.rs | 8 + library/compiler-builtins/tests/udivti3.rs | 8 + library/compiler-builtins/tests/umoddi3.rs | 8 + library/compiler-builtins/tests/umodsi3.rs | 8 + library/compiler-builtins/tests/umodti3.rs | 8 + library/compiler-builtins/thumbv6m-linux-eabi.json | 24 + .../compiler-builtins/thumbv7em-linux-eabi.json | 23 + .../compiler-builtins/thumbv7em-linux-eabihf.json | 24 + library/compiler-builtins/thumbv7m-linux-eabi.json | 23 + 41 files changed, 2883 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/tests/adddf3.rs create mode 100644 library/compiler-builtins/tests/addsf3.rs create mode 100644 library/compiler-builtins/tests/ashldi3.rs create mode 100644 library/compiler-builtins/tests/ashlti3.rs create mode 100644 library/compiler-builtins/tests/ashrdi3.rs create mode 100644 library/compiler-builtins/tests/ashrti3.rs create mode 100644 library/compiler-builtins/tests/divdi3.rs create mode 100644 library/compiler-builtins/tests/divmoddi4.rs create mode 100644 library/compiler-builtins/tests/divmodsi4.rs create mode 100644 library/compiler-builtins/tests/divsi3.rs create mode 100644 library/compiler-builtins/tests/divti3.rs create mode 100644 library/compiler-builtins/tests/lshrdi3.rs create mode 100644 library/compiler-builtins/tests/lshrti3.rs create mode 100644 library/compiler-builtins/tests/moddi3.rs create mode 100644 library/compiler-builtins/tests/modsi3.rs create mode 100644 library/compiler-builtins/tests/modti3.rs create mode 100644 library/compiler-builtins/tests/muldi3.rs create mode 100644 library/compiler-builtins/tests/mulodi4.rs create mode 100644 library/compiler-builtins/tests/mulosi4.rs create mode 100644 library/compiler-builtins/tests/muloti4.rs create mode 100644 library/compiler-builtins/tests/multi3.rs create mode 100644 library/compiler-builtins/tests/powidf2.rs create mode 100644 library/compiler-builtins/tests/powisf2.rs create mode 100644 library/compiler-builtins/tests/subdf3.rs create mode 100644 library/compiler-builtins/tests/subsf3.rs create mode 100644 library/compiler-builtins/tests/udivdi3.rs create mode 100644 library/compiler-builtins/tests/udivmoddi4.rs create mode 100644 library/compiler-builtins/tests/udivmodsi4.rs create mode 100644 library/compiler-builtins/tests/udivmodti4.rs create mode 100644 library/compiler-builtins/tests/udivsi3.rs create mode 100644 library/compiler-builtins/tests/udivti3.rs create mode 100644 library/compiler-builtins/tests/umoddi3.rs create mode 100644 library/compiler-builtins/tests/umodsi3.rs create mode 100644 library/compiler-builtins/tests/umodti3.rs create mode 100644 library/compiler-builtins/thumbv6m-linux-eabi.json create mode 100644 library/compiler-builtins/thumbv7em-linux-eabi.json create mode 100644 library/compiler-builtins/thumbv7em-linux-eabihf.json create mode 100644 library/compiler-builtins/thumbv7m-linux-eabi.json diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index aea0c38840f..bc0d105a790 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -4,17 +4,22 @@ build = "build.rs" name = "compiler_builtins" version = "0.1.0" +[build-dependencies] +rand = "0.3.15" + [build-dependencies.gcc] optional = true version = "0.3.36" +[target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] +test = { git = "https://github.com/japaric/utest" } +utest-cortex-m-qemu = { git = "https://github.com/japaric/utest", default-features = false } +utest-macros = { git = "https://github.com/japaric/utest" } + [features] -# Build the missing intrinsics from compiler-rt C source code c = ["gcc"] -# Mark this crate as the #![compiler_builtins] crate compiler-builtins = [] default = ["compiler-builtins"] -# Include implementations of memory operations like memcpy mem = [] rustbuild = ["compiler-builtins"] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index cc778642b8c..a3834290aa2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,3 +1,5 @@ +#![feature(i128_type)] + use std::env; fn main() { @@ -15,6 +17,9 @@ fn main() { // custom targets, which can have arbitrary names. let llvm_target = target.split('-').collect::>(); + // Build test files + tests::generate(); + // Build missing intrinsics from compiler-rt C source code #[cfg(feature = "c")] c::compile(&llvm_target); @@ -31,6 +36,2509 @@ fn main() { } } +mod tests { + extern crate rand; + + use std::collections::HashSet; + use std::fmt::Write; + use std::fs::File; + use std::hash::Hash; + use std::path::PathBuf; + use std::{env, mem}; + + use self::rand::Rng; + + const NTESTS: usize = 10_000; + + macro_rules! test { + ($($intrinsic:ident,)+) => { + $( + mk_file::<$intrinsic>(); + )+ + } + } + + pub fn generate() { + // TODO move to main + test! { + // float/add.rs + Adddf3, + Addsf3, + + // float/conv.rs + // Fixdfdi, + // Fixdfsi, + // Fixsfdi, + // Fixsfsi, + // Fixunsdfdi, + // Fixunsdfsi, + // Fixunssfdi, + // Fixunssfsi, + // Floatdidf, + // Floatsidf, + // Floatsisf, + // Floatundidf, + // Floatunsidf, + // Floatunsisf, + + // float/pow.rs + Powidf2, + Powisf2, + + // float/sub.rs + Subdf3, + Subsf3, + + // int/mul.rs + Muldi3, + Mulodi4, + Mulosi4, + Muloti4, + Multi3, + + // int/sdiv.rs + Divdi3, + Divmoddi4, + Divmodsi4, + Divsi3, + Divti3, + Moddi3, + Modsi3, + Modti3, + + // int/shift.rs + Ashldi3, + Ashlti3, + Ashrdi3, + Ashrti3, + Lshrdi3, + Lshrti3, + + // int/udiv.rs + Udivdi3, + Udivmoddi4, + Udivmodsi4, + Udivmodti4, + Udivsi3, + Udivti3, + Umoddi3, + Umodsi3, + Umodti3, + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Adddf3 { + a: u64, + b: u64, + c: u64, + } + + impl TestCase for Adddf3 { + fn name() -> &'static str { + "adddf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + let b = gen_f64(rng); + let c = a + b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Adddf3 { + a: to_u64(a), + b: to_u64(b), + c: to_u64(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::add::__adddf3; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn adddf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __adddf3(mk_f64(a), mk_f64(b)); + assert_eq!(((a, b), c), ((a, b), to_u64(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Addsf3 { + a: u32, + b: u32, + c: u32, + } + + impl TestCase for Addsf3 { + fn name() -> &'static str { + "addsf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + let b = gen_f32(rng); + let c = a + b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Addsf3 { + a: to_u32(a), + b: to_u32(b), + c: to_u32(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::add::__addsf3; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn addsf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __addsf3(mk_f32(a), mk_f32(b)); + assert_eq!(((a, b), c), ((a, b), to_u32(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Ashldi3 { + a: u64, + b: u32, + c: u64, + } + + impl TestCase for Ashldi3 { + fn name() -> &'static str { + "ashldi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u64(rng); + let b = (rng.gen::() % 64) as u32; + let c = a << b; + + Some(Ashldi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::shift::__ashldi3; + +static TEST_CASES: &[((u64, u32), u64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn ashldi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __ashldi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Ashlti3 { + a: u128, + b: u32, + c: u128, + } + + impl TestCase for Ashlti3 { + fn name() -> &'static str { + "ashlti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = (rng.gen::() % 128) as u32; + let c = a << b; + + Some(Ashlti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::shift::__ashlti3; + +static TEST_CASES: &[((u128, u32), u128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn ashlti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __ashlti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Ashrdi3 { + a: i64, + b: u32, + c: i64, + } + + impl TestCase for Ashrdi3 { + fn name() -> &'static str { + "ashrdi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i64(rng); + let b = (rng.gen::() % 64) as u32; + let c = a >> b; + + Some(Ashrdi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::shift::__ashrdi3; + +static TEST_CASES: &[((i64, u32), i64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn ashrdi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __ashrdi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Ashrti3 { + a: i128, + b: u32, + c: i128, + } + + impl TestCase for Ashrti3 { + fn name() -> &'static str { + "ashrti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = (rng.gen::() % 128) as u32; + let c = a >> b; + + Some(Ashrti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::shift::__ashrti3; + +static TEST_CASES: &[((i128, u32), i128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn ashrti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __ashrti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divmoddi4 { + a: i64, + b: i64, + c: i64, + rem: i64, + } + + impl TestCase for Divmoddi4 { + fn name() -> &'static str { + "divmoddi4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i64(rng); + let b = gen_i64(rng); + if b == 0 { + return None; + } + let c = a / b; + let rem = a % b; + + Some(Divmoddi4 { a, b, c, rem }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {rem})),", + a = self.a, + b = self.b, + c = self.c, + rem = self.rem + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divmoddi4; + +static TEST_CASES: &[((i64, i64), (i64, i64))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divmoddi4() { + for &((a, b), (c, rem)) in TEST_CASES { + let mut rem_ = 0; + let c_ = __divmoddi4(a, b, &mut rem_); + assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divdi3 { + a: i64, + b: i64, + c: i64, + } + + impl TestCase for Divdi3 { + fn name() -> &'static str { + "divdi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i64(rng); + let b = gen_i64(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Divdi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divdi3; + +static TEST_CASES: &[((i64, i64), i64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divdi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divdi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divmodsi4 { + a: i32, + b: i32, + c: i32, + rem: i32, + } + + impl TestCase for Divmodsi4 { + fn name() -> &'static str { + "divmodsi4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i32(rng); + let b = gen_i32(rng); + if b == 0 { + return None; + } + let c = a / b; + let rem = a % b; + + Some(Divmodsi4 { a, b, c, rem }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {rem})),", + a = self.a, + b = self.b, + c = self.c, + rem = self.rem + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divmodsi4; + +static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divmodsi4() { + for &((a, b), (c, rem)) in TEST_CASES { + let mut rem_ = 0; + let c_ = __divmodsi4(a, b, &mut rem_); + assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divsi3 { + a: i32, + b: i32, + c: i32, + } + + impl TestCase for Divsi3 { + fn name() -> &'static str { + "divsi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i32(rng); + let b = gen_i32(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Divsi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divsi3; + +static TEST_CASES: &[((i32, i32), i32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divsi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divsi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divti3 { + a: i128, + b: i128, + c: i128, + } + + impl TestCase for Divti3 { + fn name() -> &'static str { + "divti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Divti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divti3; + +static TEST_CASES: &[((i128, i128), i128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Moddi3 { + a: i64, + b: i64, + c: i64, + } + + impl TestCase for Moddi3 { + fn name() -> &'static str { + "moddi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i64(rng); + let b = gen_i64(rng); + if b == 0 { + return None; + } + let c = a % b; + + Some(Moddi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__moddi3; + +static TEST_CASES: &[((i64, i64), i64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn moddi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __moddi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Modsi3 { + a: i32, + b: i32, + c: i32, + } + + impl TestCase for Modsi3 { + fn name() -> &'static str { + "modsi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i32(rng); + let b = gen_i32(rng); + if b == 0 { + return None; + } + let c = a % b; + + Some(Modsi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__modsi3; + +static TEST_CASES: &[((i32, i32), i32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn modsi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __modsi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Modti3 { + a: i128, + b: i128, + c: i128, + } + + impl TestCase for Modti3 { + fn name() -> &'static str { + "modti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + if b == 0 { + return None; + } + let c = a % b; + + Some(Modti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__modti3; + +static TEST_CASES: &[((i128, i128), i128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn modti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __modti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + struct Muldi3 { + a: u64, + b: u64, + c: u64, + } + + impl TestCase for Muldi3 { + fn name() -> &'static str { + "muldi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u64(rng); + let b = gen_u64(rng); + let c = a.wrapping_mul(b); + + Some(Muldi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::mul::__muldi3; + +static TEST_CASES: &[((u64, u64), u64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn muldi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __muldi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Mulodi4 { + a: i64, + b: i64, + c: i64, + overflow: u32, + } + + impl TestCase for Mulodi4 { + fn name() -> &'static str { + "mulodi4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + { + let a = gen_i64(rng); + let b = gen_i64(rng); + let c = a.wrapping_mul(b); + let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; + + Some(Mulodi4 { a, b, c, overflow }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {overflow})),", + a = self.a, + b = self.b, + c = self.c, + overflow = self.overflow + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::mul::__mulodi4; + +static TEST_CASES: &[((i64, i64), (i64, i32))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn mulodi4() { + let mut overflow_ = 2; + for &((a, b), (c, overflow)) in TEST_CASES { + let c_ = __mulodi4(a, b, &mut overflow_); + assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Mulosi4 { + a: i32, + b: i32, + c: i32, + overflow: u32, + } + + impl TestCase for Mulosi4 { + fn name() -> &'static str { + "mulosi4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + { + let a = gen_i32(rng); + let b = gen_i32(rng); + let c = a.wrapping_mul(b); + let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; + + Some(Mulosi4 { a, b, c, overflow }) + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::mul::__mulosi4; + +static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn mulosi4() { + let mut overflow_ = 2; + for &((a, b), (c, overflow)) in TEST_CASES { + let c_ = __mulosi4(a, b, &mut overflow_); + assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); + } +} +" + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {overflow})),", + a = self.a, + b = self.b, + c = self.c, + overflow = self.overflow + ) + .unwrap(); + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Muloti4 { + a: i128, + b: i128, + c: i128, + overflow: u32, + } + + impl TestCase for Muloti4 { + fn name() -> &'static str { + "muloti4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + let c = a.wrapping_mul(b); + let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; + + Some(Muloti4 { a, b, c, overflow }) + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::mul::__muloti4; + +static TEST_CASES: &[((i128, i128), (i128, i32))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn muloti4() { + let mut overflow_ = 2; + for &((a, b), (c, overflow)) in TEST_CASES { + let c_ = __muloti4(a, b, &mut overflow_); + assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); + } +} +" + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {overflow})),", + a = self.a, + b = self.b, + c = self.c, + overflow = self.overflow + ) + .unwrap(); + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Multi3 { + a: i128, + b: i128, + c: i128, + } + + impl TestCase for Multi3 { + fn name() -> &'static str { + "multi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + let c = a.wrapping_mul(b); + + Some(Multi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::mul::__multi3; + +static TEST_CASES: &[((i128, i128), i128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn multi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __multi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Powidf2 { + a: u64, + b: i32, + c: u64, + } + + impl TestCase for Powidf2 { + fn name() -> &'static str { + "powidf2" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + let b = gen_i32(rng); + let c = a.powi(b); + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets + if a.is_nan() || c.is_nan() { + return None; + } + + Some( + Powidf2 { + a: to_u64(a), + b, + c: to_u64(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::pow::__powidf2; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, i32), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn powidf2() { + for &((a, b), c) in TEST_CASES { + let c_ = __powidf2(mk_f64(a), b); + assert_eq!(((a, b), c), ((a, b), to_u64(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Powisf2 { + a: u32, + b: i32, + c: u32, + } + + impl TestCase for Powisf2 { + fn name() -> &'static str { + "powisf2" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + let b = gen_i32(rng); + let c = a.powi(b); + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets + if a.is_nan() || c.is_nan() { + return None; + } + + Some( + Powisf2 { + a: to_u32(a), + b, + c: to_u32(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::pow::__powisf2; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, i32), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn powisf2() { + for &((a, b), c) in TEST_CASES { + let c_ = __powisf2(mk_f32(a), b); + assert_eq!(((a, b), c), ((a, b), to_u32(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Lshrdi3 { + a: u64, + b: u32, + c: u64, + } + + impl TestCase for Lshrdi3 { + fn name() -> &'static str { + "lshrdi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u64(rng); + let b = (rng.gen::() % 64) as u32; + let c = a >> b; + + Some(Lshrdi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::shift::__lshrdi3; + +static TEST_CASES: &[((u64, u32), u64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn lshrdi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __lshrdi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Lshrti3 { + a: u128, + b: u32, + c: u128, + } + + impl TestCase for Lshrti3 { + fn name() -> &'static str { + "lshrti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = (rng.gen::() % 128) as u32; + let c = a >> b; + + Some(Lshrti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::shift::__lshrti3; + +static TEST_CASES: &[((u128, u32), u128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn lshrti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __lshrti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Subdf3 { + a: u64, + b: u64, + c: u64, + } + + impl TestCase for Subdf3 { + fn name() -> &'static str { + "subdf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + let b = gen_f64(rng); + let c = a - b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Subdf3 { + a: to_u64(a), + b: to_u64(b), + c: to_u64(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::sub::__subdf3; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn subdf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __subdf3(mk_f64(a), mk_f64(b)); + assert_eq!(((a, b), c), ((a, b), to_u64(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Subsf3 { + a: u32, + b: u32, + c: u32, + } + + impl TestCase for Subsf3 { + fn name() -> &'static str { + "subsf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + let b = gen_f32(rng); + let c = a - b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Subsf3 { + a: to_u32(a), + b: to_u32(b), + c: to_u32(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::sub::__subsf3; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn subsf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __subsf3(mk_f32(a), mk_f32(b)); + assert_eq!(((a, b), c), ((a, b), to_u32(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Udivdi3 { + a: u64, + b: u64, + c: u64, + } + + impl TestCase for Udivdi3 { + fn name() -> &'static str { + "udivdi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u64(rng); + let b = gen_u64(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Udivdi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__udivdi3; + +static TEST_CASES: &[((u64, u64), u64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn udivdi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __udivdi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Udivmoddi4 { + a: u64, + b: u64, + c: u64, + rem: u64, + } + + impl TestCase for Udivmoddi4 { + fn name() -> &'static str { + "udivmoddi4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u64(rng); + let b = gen_u64(rng); + if b == 0 { + return None; + } + let c = a / b; + let rem = a % b; + + Some(Udivmoddi4 { a, b, c, rem }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {rem})),", + a = self.a, + b = self.b, + c = self.c, + rem = self.rem + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__udivmoddi4; + +static TEST_CASES: &[((u64, u64), (u64, u64))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn udivmoddi4() { + for &((a, b), (c, rem)) in TEST_CASES { + let mut rem_ = 0; + let c_ = __udivmoddi4(a, b, Some(&mut rem_)); + assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Udivmodsi4 { + a: u32, + b: u32, + c: u32, + rem: u32, + } + + impl TestCase for Udivmodsi4 { + fn name() -> &'static str { + "udivmodsi4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u32(rng); + let b = gen_u32(rng); + if b == 0 { + return None; + } + let c = a / b; + let rem = a % b; + + Some(Udivmodsi4 { a, b, c, rem }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {rem})),", + a = self.a, + b = self.b, + c = self.c, + rem = self.rem + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__udivmodsi4; + +static TEST_CASES: &[((u32, u32), (u32, u32))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn udivmodsi4() { + for &((a, b), (c, rem)) in TEST_CASES { + let mut rem_ = 0; + let c_ = __udivmodsi4(a, b, Some(&mut rem_)); + assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Udivmodti4 { + a: u128, + b: u128, + c: u128, + rem: u128, + } + + impl TestCase for Udivmodti4 { + fn name() -> &'static str { + "udivmodti4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = gen_u128(rng); + if b == 0 { + return None; + } + let c = a / b; + let rem = a % b; + + Some(Udivmodti4 { a, b, c, rem }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {rem})),", + a = self.a, + b = self.b, + c = self.c, + rem = self.rem + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__udivmodti4; + +static TEST_CASES: &[((u128, u128), (u128, u128))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn udivmodti4() { + for &((a, b), (c, rem)) in TEST_CASES { + let mut rem_ = 0; + let c_ = __udivmodti4(a, b, Some(&mut rem_)); + assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Udivsi3 { + a: u32, + b: u32, + c: u32, + } + + impl TestCase for Udivsi3 { + fn name() -> &'static str { + "udivsi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u32(rng); + let b = gen_u32(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Udivsi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__udivsi3; + +static TEST_CASES: &[((u32, u32), u32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn udivsi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __udivsi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Udivti3 { + a: u128, + b: u128, + c: u128, + } + + impl TestCase for Udivti3 { + fn name() -> &'static str { + "udivti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = gen_u128(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Udivti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__udivti3; + +static TEST_CASES: &[((u128, u128), u128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn udivti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __udivti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Umoddi3 { + a: u64, + b: u64, + c: u64, + } + + impl TestCase for Umoddi3 { + fn name() -> &'static str { + "umoddi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u64(rng); + let b = gen_u64(rng); + if b == 0 { + return None; + } + let c = a % b; + + Some(Umoddi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__umoddi3; + +static TEST_CASES: &[((u64, u64), u64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn umoddi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __umoddi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Umodsi3 { + a: u32, + b: u32, + c: u32, + } + + impl TestCase for Umodsi3 { + fn name() -> &'static str { + "umodsi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u32(rng); + let b = gen_u32(rng); + if b == 0 { + return None; + } + let c = a % b; + + Some(Umodsi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__umodsi3; + +static TEST_CASES: &[((u32, u32), u32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn umodsi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __umodsi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Umodti3 { + a: u128, + b: u128, + c: u128, + } + + impl TestCase for Umodti3 { + fn name() -> &'static str { + "umodti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = gen_u128(rng); + if b == 0 { + return None; + } + let c = a % b; + + Some(Umodti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__umodti3; + +static TEST_CASES: &[((u128, u128), u128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn umodti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __umodti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + trait TestCase { + /// Name of the intrinsic to test + fn name() -> &'static str; + /// Generates a valid test case + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized; + /// Stringifies a test case + fn to_string(&self, buffer: &mut String); + /// Prologue of the test file + fn prologue() -> &'static str; + /// Epilogue of the test file + fn epilogue() -> &'static str; + } + + const PROLOGUE: &'static str = r#" +extern crate compiler_builtins; + +// test runner +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +extern crate utest_cortex_m_qemu; + +// overrides `panic!` +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +#[macro_use] +extern crate utest_macros; + +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +macro_rules! panic { + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} +"#; + + macro_rules! gen_int { + ($name:ident, $ity:ident, $hty:ident) => { + fn $name(rng: &mut R) -> $ity + where + R: Rng, + { + let mut mk = || if rng.gen_weighted_bool(10) { + *rng.choose(&[::std::$hty::MAX, 0, ::std::$hty::MIN]).unwrap() + } else { + rng.gen::<$hty>() + }; + unsafe { mem::transmute([mk(), mk()]) } + } + + } + } + + gen_int!(gen_i32, i32, i16); + gen_int!(gen_i64, i64, i32); + gen_int!(gen_i128, i128, i64); + + macro_rules! gen_float { + ($name:ident, + $fty:ident, + $uty:ident, + $bits:expr, + $significand_bits:expr) => { + pub fn $name(rng: &mut R) -> $fty + where + R: Rng, + { + const BITS: u8 = $bits; + const SIGNIFICAND_BITS: u8 = $significand_bits; + + const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; + const SIGN_MASK: $uty = (1 << (BITS - 1)); + const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); + + fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { + unsafe { + mem::transmute(((sign as $uty) << (BITS - 1)) | + ((exponent & EXPONENT_MASK) << + SIGNIFICAND_BITS) | + (significand & SIGNIFICAND_MASK)) + } + } + + if rng.gen_weighted_bool(10) { + // Special values + *rng.choose(&[-0.0, + 0.0, + ::std::$fty::NAN, + ::std::$fty::INFINITY, + -::std::$fty::INFINITY]) + .unwrap() + } else if rng.gen_weighted_bool(10) { + // NaN patterns + mk_f32(rng.gen(), rng.gen(), 0) + } else if rng.gen() { + // Denormalized + mk_f32(rng.gen(), 0, rng.gen()) + } else { + // Random anything + mk_f32(rng.gen(), rng.gen(), rng.gen()) + } + } + } + } + + gen_float!(gen_f32, f32, u32, 32, 23); + gen_float!(gen_f64, f64, u64, 64, 52); + + pub fn gen_u128(rng: &mut R) -> u128 + where + R: Rng, + { + gen_i128(rng) as u128 + } + + pub fn gen_u32(rng: &mut R) -> u32 + where + R: Rng, + { + gen_i32(rng) as u32 + } + + fn gen_u64(rng: &mut R) -> u64 + where + R: Rng, + { + gen_i64(rng) as u64 + } + + pub fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } + } + + pub fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } + } + + fn mk_tests(mut n: usize, rng: &mut R) -> String + where + T: Eq + Hash + TestCase, + R: Rng, + { + let mut buffer = PROLOGUE.to_owned(); + buffer.push_str(T::prologue()); + let mut cases = HashSet::new(); + while n != 0 { + if let Some(case) = T::generate(rng) { + if cases.contains(&case) { + continue; + } + case.to_string(&mut buffer); + n -= 1; + cases.insert(case); + } + } + buffer.push_str(T::epilogue()); + buffer + } + + fn mk_file() + where + T: Eq + Hash + TestCase, + { + use std::io::Write; + + let rng = &mut rand::thread_rng(); + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let out_file = out_dir.join(format!("{}.rs", T::name())); + let contents = mk_tests::(NTESTS, rng); + + File::create(out_file) + .unwrap() + .write_all(contents.as_bytes()) + .unwrap(); + } +} + #[cfg(feature = "c")] mod c { extern crate gcc; diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index e04b26bf536..efe590ab43b 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -94,6 +94,7 @@ enum Sign { Positive, Negative } + macro_rules! fp_fix { ($intrinsic:ident: $fty:ty, $ity:ty) => { pub extern "C" fn $intrinsic(f: $fty) -> $ity { diff --git a/library/compiler-builtins/tests/adddf3.rs b/library/compiler-builtins/tests/adddf3.rs new file mode 100644 index 00000000000..3129330afaf --- /dev/null +++ b/library/compiler-builtins/tests/adddf3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/adddf3.rs")); diff --git a/library/compiler-builtins/tests/addsf3.rs b/library/compiler-builtins/tests/addsf3.rs new file mode 100644 index 00000000000..b5c9c3dfebd --- /dev/null +++ b/library/compiler-builtins/tests/addsf3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/addsf3.rs")); diff --git a/library/compiler-builtins/tests/ashldi3.rs b/library/compiler-builtins/tests/ashldi3.rs new file mode 100644 index 00000000000..1116375d3ef --- /dev/null +++ b/library/compiler-builtins/tests/ashldi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/ashldi3.rs")); diff --git a/library/compiler-builtins/tests/ashlti3.rs b/library/compiler-builtins/tests/ashlti3.rs new file mode 100644 index 00000000000..4c799cf8822 --- /dev/null +++ b/library/compiler-builtins/tests/ashlti3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/ashlti3.rs")); diff --git a/library/compiler-builtins/tests/ashrdi3.rs b/library/compiler-builtins/tests/ashrdi3.rs new file mode 100644 index 00000000000..a0a2b6cb13a --- /dev/null +++ b/library/compiler-builtins/tests/ashrdi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/ashrdi3.rs")); diff --git a/library/compiler-builtins/tests/ashrti3.rs b/library/compiler-builtins/tests/ashrti3.rs new file mode 100644 index 00000000000..b147051c2d9 --- /dev/null +++ b/library/compiler-builtins/tests/ashrti3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/ashrti3.rs")); diff --git a/library/compiler-builtins/tests/divdi3.rs b/library/compiler-builtins/tests/divdi3.rs new file mode 100644 index 00000000000..4bdce54156e --- /dev/null +++ b/library/compiler-builtins/tests/divdi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/divdi3.rs")); diff --git a/library/compiler-builtins/tests/divmoddi4.rs b/library/compiler-builtins/tests/divmoddi4.rs new file mode 100644 index 00000000000..9ddd85a829f --- /dev/null +++ b/library/compiler-builtins/tests/divmoddi4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/divmoddi4.rs")); diff --git a/library/compiler-builtins/tests/divmodsi4.rs b/library/compiler-builtins/tests/divmodsi4.rs new file mode 100644 index 00000000000..6fe80e97569 --- /dev/null +++ b/library/compiler-builtins/tests/divmodsi4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/divmodsi4.rs")); diff --git a/library/compiler-builtins/tests/divsi3.rs b/library/compiler-builtins/tests/divsi3.rs new file mode 100644 index 00000000000..e6440d782c7 --- /dev/null +++ b/library/compiler-builtins/tests/divsi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/divsi3.rs")); diff --git a/library/compiler-builtins/tests/divti3.rs b/library/compiler-builtins/tests/divti3.rs new file mode 100644 index 00000000000..62d9789d0f8 --- /dev/null +++ b/library/compiler-builtins/tests/divti3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/divti3.rs")); diff --git a/library/compiler-builtins/tests/lshrdi3.rs b/library/compiler-builtins/tests/lshrdi3.rs new file mode 100644 index 00000000000..b1a2331b196 --- /dev/null +++ b/library/compiler-builtins/tests/lshrdi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/lshrdi3.rs")); diff --git a/library/compiler-builtins/tests/lshrti3.rs b/library/compiler-builtins/tests/lshrti3.rs new file mode 100644 index 00000000000..2ee32ce71f4 --- /dev/null +++ b/library/compiler-builtins/tests/lshrti3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/lshrti3.rs")); diff --git a/library/compiler-builtins/tests/moddi3.rs b/library/compiler-builtins/tests/moddi3.rs new file mode 100644 index 00000000000..6a58a77ab49 --- /dev/null +++ b/library/compiler-builtins/tests/moddi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/moddi3.rs")); diff --git a/library/compiler-builtins/tests/modsi3.rs b/library/compiler-builtins/tests/modsi3.rs new file mode 100644 index 00000000000..46ad8cd33cd --- /dev/null +++ b/library/compiler-builtins/tests/modsi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/modsi3.rs")); diff --git a/library/compiler-builtins/tests/modti3.rs b/library/compiler-builtins/tests/modti3.rs new file mode 100644 index 00000000000..1a363f7cb41 --- /dev/null +++ b/library/compiler-builtins/tests/modti3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/modti3.rs")); diff --git a/library/compiler-builtins/tests/muldi3.rs b/library/compiler-builtins/tests/muldi3.rs new file mode 100644 index 00000000000..d771e8a6bde --- /dev/null +++ b/library/compiler-builtins/tests/muldi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/muldi3.rs")); diff --git a/library/compiler-builtins/tests/mulodi4.rs b/library/compiler-builtins/tests/mulodi4.rs new file mode 100644 index 00000000000..071a295810f --- /dev/null +++ b/library/compiler-builtins/tests/mulodi4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/mulodi4.rs")); diff --git a/library/compiler-builtins/tests/mulosi4.rs b/library/compiler-builtins/tests/mulosi4.rs new file mode 100644 index 00000000000..3ec4336d118 --- /dev/null +++ b/library/compiler-builtins/tests/mulosi4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/mulosi4.rs")); diff --git a/library/compiler-builtins/tests/muloti4.rs b/library/compiler-builtins/tests/muloti4.rs new file mode 100644 index 00000000000..262b4646592 --- /dev/null +++ b/library/compiler-builtins/tests/muloti4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/muloti4.rs")); diff --git a/library/compiler-builtins/tests/multi3.rs b/library/compiler-builtins/tests/multi3.rs new file mode 100644 index 00000000000..db525387438 --- /dev/null +++ b/library/compiler-builtins/tests/multi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/multi3.rs")); diff --git a/library/compiler-builtins/tests/powidf2.rs b/library/compiler-builtins/tests/powidf2.rs new file mode 100644 index 00000000000..dde5f03eb9c --- /dev/null +++ b/library/compiler-builtins/tests/powidf2.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/powidf2.rs")); diff --git a/library/compiler-builtins/tests/powisf2.rs b/library/compiler-builtins/tests/powisf2.rs new file mode 100644 index 00000000000..3e0baeb73ce --- /dev/null +++ b/library/compiler-builtins/tests/powisf2.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/powisf2.rs")); diff --git a/library/compiler-builtins/tests/subdf3.rs b/library/compiler-builtins/tests/subdf3.rs new file mode 100644 index 00000000000..13f695718e1 --- /dev/null +++ b/library/compiler-builtins/tests/subdf3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/subdf3.rs")); diff --git a/library/compiler-builtins/tests/subsf3.rs b/library/compiler-builtins/tests/subsf3.rs new file mode 100644 index 00000000000..7be426c4531 --- /dev/null +++ b/library/compiler-builtins/tests/subsf3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/subsf3.rs")); diff --git a/library/compiler-builtins/tests/udivdi3.rs b/library/compiler-builtins/tests/udivdi3.rs new file mode 100644 index 00000000000..d87091c7d84 --- /dev/null +++ b/library/compiler-builtins/tests/udivdi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/udivdi3.rs")); diff --git a/library/compiler-builtins/tests/udivmoddi4.rs b/library/compiler-builtins/tests/udivmoddi4.rs new file mode 100644 index 00000000000..a9444c10db3 --- /dev/null +++ b/library/compiler-builtins/tests/udivmoddi4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/udivmoddi4.rs")); diff --git a/library/compiler-builtins/tests/udivmodsi4.rs b/library/compiler-builtins/tests/udivmodsi4.rs new file mode 100644 index 00000000000..e93bfe1e552 --- /dev/null +++ b/library/compiler-builtins/tests/udivmodsi4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/udivmodsi4.rs")); diff --git a/library/compiler-builtins/tests/udivmodti4.rs b/library/compiler-builtins/tests/udivmodti4.rs new file mode 100644 index 00000000000..1f9ed279926 --- /dev/null +++ b/library/compiler-builtins/tests/udivmodti4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/udivmodti4.rs")); diff --git a/library/compiler-builtins/tests/udivsi3.rs b/library/compiler-builtins/tests/udivsi3.rs new file mode 100644 index 00000000000..d6433e7c31d --- /dev/null +++ b/library/compiler-builtins/tests/udivsi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/udivsi3.rs")); diff --git a/library/compiler-builtins/tests/udivti3.rs b/library/compiler-builtins/tests/udivti3.rs new file mode 100644 index 00000000000..fc602fd28af --- /dev/null +++ b/library/compiler-builtins/tests/udivti3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/udivti3.rs")); diff --git a/library/compiler-builtins/tests/umoddi3.rs b/library/compiler-builtins/tests/umoddi3.rs new file mode 100644 index 00000000000..09a114ee6b9 --- /dev/null +++ b/library/compiler-builtins/tests/umoddi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/umoddi3.rs")); diff --git a/library/compiler-builtins/tests/umodsi3.rs b/library/compiler-builtins/tests/umodsi3.rs new file mode 100644 index 00000000000..aa56e819c27 --- /dev/null +++ b/library/compiler-builtins/tests/umodsi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/umodsi3.rs")); diff --git a/library/compiler-builtins/tests/umodti3.rs b/library/compiler-builtins/tests/umodti3.rs new file mode 100644 index 00000000000..63a0bf28f2f --- /dev/null +++ b/library/compiler-builtins/tests/umodti3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/umodti3.rs")); diff --git a/library/compiler-builtins/thumbv6m-linux-eabi.json b/library/compiler-builtins/thumbv6m-linux-eabi.json new file mode 100644 index 00000000000..d3ac24dfc5e --- /dev/null +++ b/library/compiler-builtins/thumbv6m-linux-eabi.json @@ -0,0 +1,24 @@ +{ + "abi-blacklist": [ + "stdcall", + "fastcall", + "vectorcall", + "win64", + "sysv64" + ], + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "env": "", + "executables": true, + "features": "+strict-align", + "linker": "arm-none-eabi-gcc", + "llvm-target": "thumbv6m-none-eabi", + "max-atomic-width": 0, + "os": "linux", + "panic-strategy": "abort", + "pre-link-args": ["-nostartfiles"], + "relocation-model": "static", + "target-endian": "little", + "target-pointer-width": "32", + "vendor": "" +} diff --git a/library/compiler-builtins/thumbv7em-linux-eabi.json b/library/compiler-builtins/thumbv7em-linux-eabi.json new file mode 100644 index 00000000000..af6ea94eebd --- /dev/null +++ b/library/compiler-builtins/thumbv7em-linux-eabi.json @@ -0,0 +1,23 @@ +{ + "abi-blacklist": [ + "stdcall", + "fastcall", + "vectorcall", + "win64", + "sysv64" + ], + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "env": "", + "executables": true, + "linker": "arm-none-eabi-gcc", + "llvm-target": "thumbv7em-none-eabi", + "max-atomic-width": 32, + "os": "linux", + "panic-strategy": "abort", + "pre-link-args": ["-nostartfiles"], + "relocation-model": "static", + "target-endian": "little", + "target-pointer-width": "32", + "vendor": "" +} diff --git a/library/compiler-builtins/thumbv7em-linux-eabihf.json b/library/compiler-builtins/thumbv7em-linux-eabihf.json new file mode 100644 index 00000000000..536d28c951d --- /dev/null +++ b/library/compiler-builtins/thumbv7em-linux-eabihf.json @@ -0,0 +1,24 @@ +{ + "abi-blacklist": [ + "stdcall", + "fastcall", + "vectorcall", + "win64", + "sysv64" + ], + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "env": "", + "executables": true, + "features": "+vfp4,+d16,+fp-only-sp", + "linker": "arm-none-eabi-gcc", + "llvm-target": "thumbv7em-none-eabihf", + "max-atomic-width": 32, + "os": "linux", + "panic-strategy": "abort", + "pre-link-args": ["-nostartfiles"], + "relocation-model": "static", + "target-endian": "little", + "target-pointer-width": "32", + "vendor": "" +} diff --git a/library/compiler-builtins/thumbv7m-linux-eabi.json b/library/compiler-builtins/thumbv7m-linux-eabi.json new file mode 100644 index 00000000000..02ed839cc82 --- /dev/null +++ b/library/compiler-builtins/thumbv7m-linux-eabi.json @@ -0,0 +1,23 @@ +{ + "abi-blacklist": [ + "stdcall", + "fastcall", + "vectorcall", + "win64", + "sysv64" + ], + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "env": "", + "executables": true, + "linker": "arm-none-eabi-gcc", + "llvm-target": "thumbv7m-none-eabi", + "max-atomic-width": 32, + "os": "linux", + "panic-strategy": "abort", + "pre-link-args": ["-nostartfiles"], + "relocation-model": "static", + "target-endian": "little", + "target-pointer-width": "32", + "vendor": "" +} -- cgit 1.4.1-3-g733a5 From 62091bb12492006566e746d30d6cf54552548aa2 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 16:12:49 -0500 Subject: test float/conv.rs --- library/compiler-builtins/Cargo.toml | 22 +- library/compiler-builtins/build.rs | 1230 ++++++++++++++++++++---- library/compiler-builtins/tests/fixdfdi.rs | 8 + library/compiler-builtins/tests/fixdfsi.rs | 8 + library/compiler-builtins/tests/fixsfdi.rs | 8 + library/compiler-builtins/tests/fixsfsi.rs | 8 + library/compiler-builtins/tests/fixunsdfdi.rs | 8 + library/compiler-builtins/tests/fixunsdfsi.rs | 8 + library/compiler-builtins/tests/fixunssfdi.rs | 8 + library/compiler-builtins/tests/fixunssfsi.rs | 8 + library/compiler-builtins/tests/floatdidf.rs | 8 + library/compiler-builtins/tests/floatsidf.rs | 8 + library/compiler-builtins/tests/floatsisf.rs | 8 + library/compiler-builtins/tests/floatundidf.rs | 8 + library/compiler-builtins/tests/floatunsidf.rs | 8 + library/compiler-builtins/tests/floatunsisf.rs | 8 + 16 files changed, 1187 insertions(+), 177 deletions(-) create mode 100644 library/compiler-builtins/tests/fixdfdi.rs create mode 100644 library/compiler-builtins/tests/fixdfsi.rs create mode 100644 library/compiler-builtins/tests/fixsfdi.rs create mode 100644 library/compiler-builtins/tests/fixsfsi.rs create mode 100644 library/compiler-builtins/tests/fixunsdfdi.rs create mode 100644 library/compiler-builtins/tests/fixunsdfsi.rs create mode 100644 library/compiler-builtins/tests/fixunssfdi.rs create mode 100644 library/compiler-builtins/tests/fixunssfsi.rs create mode 100644 library/compiler-builtins/tests/floatdidf.rs create mode 100644 library/compiler-builtins/tests/floatsidf.rs create mode 100644 library/compiler-builtins/tests/floatsisf.rs create mode 100644 library/compiler-builtins/tests/floatundidf.rs create mode 100644 library/compiler-builtins/tests/floatunsidf.rs create mode 100644 library/compiler-builtins/tests/floatunsisf.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index bc0d105a790..2aefba8bc3f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,17 +5,13 @@ name = "compiler_builtins" version = "0.1.0" [build-dependencies] +cast = "0.2.0" rand = "0.3.15" [build-dependencies.gcc] optional = true version = "0.3.36" -[target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] -test = { git = "https://github.com/japaric/utest" } -utest-cortex-m-qemu = { git = "https://github.com/japaric/utest", default-features = false } -utest-macros = { git = "https://github.com/japaric/utest" } - [features] c = ["gcc"] compiler-builtins = [] @@ -23,4 +19,20 @@ default = ["compiler-builtins"] mem = [] rustbuild = ["compiler-builtins"] +[target] + +[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))"] + +[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))".dev-dependencies] + +[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))".dev-dependencies.test] +git = "https://github.com/japaric/utest" + +[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))".dev-dependencies.utest-cortex-m-qemu] +default-features = false +git = "https://github.com/japaric/utest" + +[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))".dev-dependencies.utest-macros] +git = "https://github.com/japaric/utest" + [workspace] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a3834290aa2..d27eb7898e0 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -37,6 +37,7 @@ fn main() { } mod tests { + extern crate cast; extern crate rand; use std::collections::HashSet; @@ -46,6 +47,7 @@ mod tests { use std::path::PathBuf; use std::{env, mem}; + use self::cast::{f32, f64, u32, u64, i32, i64}; use self::rand::Rng; const NTESTS: usize = 10_000; @@ -66,20 +68,20 @@ mod tests { Addsf3, // float/conv.rs - // Fixdfdi, - // Fixdfsi, - // Fixsfdi, - // Fixsfsi, - // Fixunsdfdi, - // Fixunsdfsi, - // Fixunssfdi, - // Fixunssfsi, - // Floatdidf, - // Floatsidf, - // Floatsisf, - // Floatundidf, - // Floatunsidf, - // Floatunsisf, + Fixdfdi, + Fixdfsi, + Fixsfdi, + Fixsfsi, + Fixunsdfdi, + Fixunsdfsi, + Fixunssfdi, + Fixunssfsi, + Floatdidf, + Floatsidf, + Floatsisf, + Floatundidf, + Floatunsidf, + Floatunsisf, // float/pow.rs Powidf2, @@ -129,9 +131,9 @@ mod tests { #[derive(Eq, Hash, PartialEq)] pub struct Adddf3 { - a: u64, - b: u64, - c: u64, + a: u64, // f64 + b: u64, // f64 + c: u64, // f64 } impl TestCase for Adddf3 { @@ -216,9 +218,9 @@ fn adddf3() { #[derive(Eq, Hash, PartialEq)] pub struct Addsf3 { - a: u32, - b: u32, - c: u32, + a: u32, // f32 + b: u32, // f32 + c: u32, // f32 } impl TestCase for Addsf3 { @@ -563,23 +565,892 @@ fn ashrti3() { } fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {rem})),", - a = self.a, - b = self.b, - c = self.c, - rem = self.rem - ) - .unwrap(); + writeln!( + buffer, + "(({a}, {b}), ({c}, {rem})),", + a = self.a, + b = self.b, + c = self.c, + rem = self.rem + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divmoddi4; + +static TEST_CASES: &[((i64, i64), (i64, i64))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divmoddi4() { + for &((a, b), (c, rem)) in TEST_CASES { + let mut rem_ = 0; + let c_ = __divmoddi4(a, b, &mut rem_); + assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divdi3 { + a: i64, + b: i64, + c: i64, + } + + impl TestCase for Divdi3 { + fn name() -> &'static str { + "divdi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i64(rng); + let b = gen_i64(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Divdi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divdi3; + +static TEST_CASES: &[((i64, i64), i64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divdi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divdi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divmodsi4 { + a: i32, + b: i32, + c: i32, + rem: i32, + } + + impl TestCase for Divmodsi4 { + fn name() -> &'static str { + "divmodsi4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i32(rng); + let b = gen_i32(rng); + if b == 0 { + return None; + } + let c = a / b; + let rem = a % b; + + Some(Divmodsi4 { a, b, c, rem }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {rem})),", + a = self.a, + b = self.b, + c = self.c, + rem = self.rem + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divmodsi4; + +static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divmodsi4() { + for &((a, b), (c, rem)) in TEST_CASES { + let mut rem_ = 0; + let c_ = __divmodsi4(a, b, &mut rem_); + assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divsi3 { + a: i32, + b: i32, + c: i32, + } + + impl TestCase for Divsi3 { + fn name() -> &'static str { + "divsi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i32(rng); + let b = gen_i32(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Divsi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divsi3; + +static TEST_CASES: &[((i32, i32), i32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divsi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divsi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divti3 { + a: i128, + b: i128, + c: i128, + } + + impl TestCase for Divti3 { + fn name() -> &'static str { + "divti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Divti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divti3; + +static TEST_CASES: &[((i128, i128), i128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixdfdi { + a: u64, // f64 + b: i64, + } + + impl TestCase for Fixdfdi { + fn name() -> &'static str { + "fixdfdi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + i64(a).ok().map(|b| Fixdfdi { a: to_u64(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixdfdi; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64,), i64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixdfdi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixdfdi(mk_f64(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixdfsi { + a: u64, // f64 + b: i32, + } + + impl TestCase for Fixdfsi { + fn name() -> &'static str { + "fixdfsi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + i32(a).ok().map(|b| Fixdfsi { a: to_u64(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixdfsi; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64,), i32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixdfdi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixdfsi(mk_f64(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixsfdi { + a: u32, // f32 + b: i64, + } + + impl TestCase for Fixsfdi { + fn name() -> &'static str { + "fixsfdi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + i64(a).ok().map(|b| Fixsfdi { a: to_u32(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixsfdi; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), i64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixsfdi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixsfdi(mk_f32(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixsfsi { + a: u32, // f32 + b: i32, + } + + impl TestCase for Fixsfsi { + fn name() -> &'static str { + "fixsfsi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + i32(a).ok().map(|b| Fixsfsi { a: to_u32(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixsfsi; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), i32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixsfdi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixsfsi(mk_f32(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixunsdfdi { + a: u64, // f64 + b: u64, + } + + impl TestCase for Fixunsdfdi { + fn name() -> &'static str { + "fixunsdfdi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + u64(a).ok().map(|b| Fixunsdfdi { a: to_u64(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixunsdfdi; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64,), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixunsdfdi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixunsdfdi(mk_f64(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixunsdfsi { + a: u64, // f64 + b: u32, + } + + impl TestCase for Fixunsdfsi { + fn name() -> &'static str { + "fixunsdfsi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + u32(a).ok().map(|b| Fixunsdfsi { a: to_u64(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixunsdfsi; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64,), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixunsdfdi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixunsdfsi(mk_f64(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixunssfdi { + a: u32, // f32 + b: u64, + } + + impl TestCase for Fixunssfdi { + fn name() -> &'static str { + "fixunssfdi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + u64(a).ok().map(|b| Fixunssfdi { a: to_u32(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixunssfdi; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixunssfdi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixunssfdi(mk_f32(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixunssfsi { + a: u32, // f32 + b: u32, + } + + impl TestCase for Fixunssfsi { + fn name() -> &'static str { + "fixunssfsi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + u32(a).ok().map(|b| Fixunssfsi { a: to_u32(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixunssfsi; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixunssfsi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixunssfsi(mk_f32(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Floatdidf { + a: i64, + b: u64, // f64 + } + + impl TestCase for Floatdidf { + fn name() -> &'static str { + "floatdidf" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i64(rng); + Some( + Floatdidf { + a, + b: to_u64(f64(a)), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatdidf; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((i64,), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn floatdidf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatdidf(a); + assert_eq!(((a,), mk_f64(b)), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Floatsidf { + a: i32, + b: u64, // f64 + } + + impl TestCase for Floatsidf { + fn name() -> &'static str { + "floatsidf" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i32(rng); + Some( + Floatsidf { + a, + b: to_u64(f64(a)), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); } fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divmoddi4; + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatsidf; -static TEST_CASES: &[((i64, i64), (i64, i64))] = &[ -" +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((i32,), u64)] = &[ +"# } fn epilogue() -> &'static str { @@ -587,11 +1458,10 @@ static TEST_CASES: &[((i64, i64), (i64, i64))] = &[ ]; #[test] -fn divmoddi4() { - for &((a, b), (c, rem)) in TEST_CASES { - let mut rem_ = 0; - let c_ = __divmoddi4(a, b, &mut rem_); - assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); +fn floatsidf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatsidf(a); + assert_eq!(((a,), mk_f64(b)), ((a,), b_)); } } " @@ -599,15 +1469,14 @@ fn divmoddi4() { } #[derive(Eq, Hash, PartialEq)] - pub struct Divdi3 { - a: i64, - b: i64, - c: i64, + pub struct Floatsisf { + a: i32, + b: u32, // f32 } - impl TestCase for Divdi3 { + impl TestCase for Floatsisf { fn name() -> &'static str { - "divdi3" + "floatsisf" } fn generate(rng: &mut R) -> Option @@ -615,33 +1484,39 @@ fn divmoddi4() { R: Rng, Self: Sized, { - let a = gen_i64(rng); - let b = gen_i64(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Divdi3 { a, b, c }) + let a = gen_i32(rng); + Some( + Floatsisf { + a, + b: to_u32(f32(a)), + }, + ) } fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); } fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divdi3; + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatsisf; -static TEST_CASES: &[((i64, i64), i64)] = &[ -" +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((i32,), u32)] = &[ +"# } fn epilogue() -> &'static str { @@ -649,10 +1524,10 @@ static TEST_CASES: &[((i64, i64), i64)] = &[ ]; #[test] -fn divdi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divdi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); +fn floatsisf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatsisf(a); + assert_eq!(((a,), mk_f32(b)), ((a,), b_)); } } " @@ -660,16 +1535,14 @@ fn divdi3() { } #[derive(Eq, Hash, PartialEq)] - pub struct Divmodsi4 { - a: i32, - b: i32, - c: i32, - rem: i32, + pub struct Floatundidf { + a: u64, + b: u64, // f64 } - impl TestCase for Divmodsi4 { + impl TestCase for Floatundidf { fn name() -> &'static str { - "divmodsi4" + "floatundidf" } fn generate(rng: &mut R) -> Option @@ -677,35 +1550,39 @@ fn divdi3() { R: Rng, Self: Sized, { - let a = gen_i32(rng); - let b = gen_i32(rng); - if b == 0 { - return None; - } - let c = a / b; - let rem = a % b; - - Some(Divmodsi4 { a, b, c, rem }) + let a = gen_u64(rng); + Some( + Floatundidf { + a, + b: to_u64(f64(a)), + }, + ) } fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {rem})),", - a = self.a, - b = self.b, - c = self.c, - rem = self.rem - ) - .unwrap(); + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); } fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divmodsi4; + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatundidf; -static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ -" +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64,), u64)] = &[ +"# } fn epilogue() -> &'static str { @@ -713,11 +1590,10 @@ static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ ]; #[test] -fn divmodsi4() { - for &((a, b), (c, rem)) in TEST_CASES { - let mut rem_ = 0; - let c_ = __divmodsi4(a, b, &mut rem_); - assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); +fn floatundidf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatundidf(a); + assert_eq!(((a,), mk_f64(b)), ((a,), b_)); } } " @@ -725,15 +1601,14 @@ fn divmodsi4() { } #[derive(Eq, Hash, PartialEq)] - pub struct Divsi3 { - a: i32, - b: i32, - c: i32, + pub struct Floatunsidf { + a: u32, + b: u64, // f64 } - impl TestCase for Divsi3 { + impl TestCase for Floatunsidf { fn name() -> &'static str { - "divsi3" + "floatunsidf" } fn generate(rng: &mut R) -> Option @@ -741,33 +1616,39 @@ fn divmodsi4() { R: Rng, Self: Sized, { - let a = gen_i32(rng); - let b = gen_i32(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Divsi3 { a, b, c }) + let a = gen_u32(rng); + Some( + Floatunsidf { + a, + b: to_u64(f64(a)), + }, + ) } fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); } fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divsi3; + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatunsidf; -static TEST_CASES: &[((i32, i32), i32)] = &[ -" +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), u64)] = &[ +"# } fn epilogue() -> &'static str { @@ -775,10 +1656,10 @@ static TEST_CASES: &[((i32, i32), i32)] = &[ ]; #[test] -fn divsi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divsi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); +fn floatunsidf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatunsidf(a); + assert_eq!(((a,), mk_f64(b)), ((a,), b_)); } } " @@ -786,15 +1667,14 @@ fn divsi3() { } #[derive(Eq, Hash, PartialEq)] - pub struct Divti3 { - a: i128, - b: i128, - c: i128, + pub struct Floatunsisf { + a: u32, + b: u32, // f32 } - impl TestCase for Divti3 { + impl TestCase for Floatunsisf { fn name() -> &'static str { - "divti3" + "floatunsisf" } fn generate(rng: &mut R) -> Option @@ -802,33 +1682,39 @@ fn divsi3() { R: Rng, Self: Sized, { - let a = gen_i128(rng); - let b = gen_i128(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Divti3 { a, b, c }) + let a = gen_u32(rng); + Some( + Floatunsisf { + a, + b: to_u32(f32(a)), + }, + ) } fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); } fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divti3; + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatunsisf; -static TEST_CASES: &[((i128, i128), i128)] = &[ -" +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), u32)] = &[ +"# } fn epilogue() -> &'static str { @@ -836,10 +1722,10 @@ static TEST_CASES: &[((i128, i128), i128)] = &[ ]; #[test] -fn divti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); +fn floatunsisf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatunsisf(a); + assert_eq!(((a,), mk_f32(b)), ((a,), b_)); } } " @@ -1330,9 +2216,9 @@ fn multi3() { #[derive(Eq, Hash, PartialEq)] pub struct Powidf2 { - a: u64, + a: u64, // f64 b: i32, - c: u64, + c: u64, // f64 } impl TestCase for Powidf2 { @@ -1417,9 +2303,9 @@ fn powidf2() { #[derive(Eq, Hash, PartialEq)] pub struct Powisf2 { - a: u32, + a: u32, // f32 b: i32, - c: u32, + c: u32, // f32 } impl TestCase for Powisf2 { @@ -1620,9 +2506,9 @@ fn lshrti3() { #[derive(Eq, Hash, PartialEq)] pub struct Subdf3 { - a: u64, - b: u64, - c: u64, + a: u64, // f64 + b: u64, // f64 + c: u64, // f64 } impl TestCase for Subdf3 { @@ -1707,9 +2593,9 @@ fn subdf3() { #[derive(Eq, Hash, PartialEq)] pub struct Subsf3 { - a: u32, - b: u32, - c: u32, + a: u32, // f32 + b: u32, // f32 + c: u32, // f32 } impl TestCase for Subsf3 { diff --git a/library/compiler-builtins/tests/fixdfdi.rs b/library/compiler-builtins/tests/fixdfdi.rs new file mode 100644 index 00000000000..b66477502bb --- /dev/null +++ b/library/compiler-builtins/tests/fixdfdi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixdfdi.rs")); diff --git a/library/compiler-builtins/tests/fixdfsi.rs b/library/compiler-builtins/tests/fixdfsi.rs new file mode 100644 index 00000000000..2677eec747a --- /dev/null +++ b/library/compiler-builtins/tests/fixdfsi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixdfsi.rs")); diff --git a/library/compiler-builtins/tests/fixsfdi.rs b/library/compiler-builtins/tests/fixsfdi.rs new file mode 100644 index 00000000000..e38952be593 --- /dev/null +++ b/library/compiler-builtins/tests/fixsfdi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixsfdi.rs")); diff --git a/library/compiler-builtins/tests/fixsfsi.rs b/library/compiler-builtins/tests/fixsfsi.rs new file mode 100644 index 00000000000..242b4c16940 --- /dev/null +++ b/library/compiler-builtins/tests/fixsfsi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixsfsi.rs")); diff --git a/library/compiler-builtins/tests/fixunsdfdi.rs b/library/compiler-builtins/tests/fixunsdfdi.rs new file mode 100644 index 00000000000..13b35ba4a17 --- /dev/null +++ b/library/compiler-builtins/tests/fixunsdfdi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixunsdfdi.rs")); diff --git a/library/compiler-builtins/tests/fixunsdfsi.rs b/library/compiler-builtins/tests/fixunsdfsi.rs new file mode 100644 index 00000000000..32faf360c30 --- /dev/null +++ b/library/compiler-builtins/tests/fixunsdfsi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixunsdfsi.rs")); diff --git a/library/compiler-builtins/tests/fixunssfdi.rs b/library/compiler-builtins/tests/fixunssfdi.rs new file mode 100644 index 00000000000..24e6f6e3508 --- /dev/null +++ b/library/compiler-builtins/tests/fixunssfdi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixunssfdi.rs")); diff --git a/library/compiler-builtins/tests/fixunssfsi.rs b/library/compiler-builtins/tests/fixunssfsi.rs new file mode 100644 index 00000000000..da02cd94578 --- /dev/null +++ b/library/compiler-builtins/tests/fixunssfsi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixunssfsi.rs")); diff --git a/library/compiler-builtins/tests/floatdidf.rs b/library/compiler-builtins/tests/floatdidf.rs new file mode 100644 index 00000000000..2b3dcb5928c --- /dev/null +++ b/library/compiler-builtins/tests/floatdidf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatdidf.rs")); diff --git a/library/compiler-builtins/tests/floatsidf.rs b/library/compiler-builtins/tests/floatsidf.rs new file mode 100644 index 00000000000..ffee7e27113 --- /dev/null +++ b/library/compiler-builtins/tests/floatsidf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatsidf.rs")); diff --git a/library/compiler-builtins/tests/floatsisf.rs b/library/compiler-builtins/tests/floatsisf.rs new file mode 100644 index 00000000000..c03ab7f9dd5 --- /dev/null +++ b/library/compiler-builtins/tests/floatsisf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatsisf.rs")); diff --git a/library/compiler-builtins/tests/floatundidf.rs b/library/compiler-builtins/tests/floatundidf.rs new file mode 100644 index 00000000000..0b833851245 --- /dev/null +++ b/library/compiler-builtins/tests/floatundidf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatundidf.rs")); diff --git a/library/compiler-builtins/tests/floatunsidf.rs b/library/compiler-builtins/tests/floatunsidf.rs new file mode 100644 index 00000000000..e25a69f5bea --- /dev/null +++ b/library/compiler-builtins/tests/floatunsidf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatunsidf.rs")); diff --git a/library/compiler-builtins/tests/floatunsisf.rs b/library/compiler-builtins/tests/floatunsisf.rs new file mode 100644 index 00000000000..c0b9fd8b0b9 --- /dev/null +++ b/library/compiler-builtins/tests/floatunsisf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatunsisf.rs")); -- cgit 1.4.1-3-g733a5 From 0869e5b93a9f73167bcb85cf866149da2afac09a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 16:35:08 -0500 Subject: remove arm tests from the old test suite --- library/compiler-builtins/src/arm.rs | 81 ------------------------------------ 1 file changed, 81 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 63f52500d4b..cf960c5aa1a 100755 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -180,84 +180,3 @@ pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { memset(dest, 0, n); } - - -#[cfg(test)] -mod tests { - use quickcheck::TestResult; - use qc::{U32, U64}; - - quickcheck!{ - fn uldivmod(n: U64, d: U64) -> TestResult { - let (n, d) = (n.0, d.0); - if d == 0 { - TestResult::discard() - } else { - let q: u64; - let r: u64; - unsafe { - // The inline asm is a bit tricky here, LLVM will allocate - // both r0 and r1 when we specify a 64-bit value for {r0}. - asm!("bl __aeabi_uldivmod" - : "={r0}" (q), "={r2}" (r) - : "{r0}" (n), "{r2}" (d) - : "r12", "lr", "flags"); - } - TestResult::from_bool(q == n / d && r == n % d) - } - } - - fn uidivmod(n: U32, d: U32) -> TestResult { - let (n, d) = (n.0, d.0); - if d == 0 { - TestResult::discard() - } else { - let q: u32; - let r: u32; - unsafe { - asm!("bl __aeabi_uidivmod" - : "={r0}" (q), "={r1}" (r) - : "{r0}" (n), "{r1}" (d) - : "r2", "r3", "r12", "lr", "flags"); - } - TestResult::from_bool(q == n / d && r == n % d) - } - } - - fn ldivmod(n: U64, d: U64) -> TestResult { - let (n, d) = (n.0 as i64, d.0 as i64); - if d == 0 { - TestResult::discard() - } else { - let q: i64; - let r: i64; - unsafe { - // The inline asm is a bit tricky here, LLVM will allocate - // both r0 and r1 when we specify a 64-bit value for {r0}. - asm!("bl __aeabi_ldivmod" - : "={r0}" (q), "={r2}" (r) - : "{r0}" (n), "{r2}" (d) - : "r12", "lr", "flags"); - } - TestResult::from_bool(q == n / d && r == n % d) - } - } - - fn idivmod(n: U32, d: U32) -> TestResult { - let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 || (n == i32::min_value() && d == -1) { - TestResult::discard() - } else { - let q: i32; - let r: i32; - unsafe { - asm!("bl __aeabi_idivmod" - : "={r0}" (q), "={r1}" (r) - : "{r0}" (n), "{r1}" (d) - : "r2", "r3", "r12", "lr", "flags"); - } - TestResult::from_bool(q == n / d && r == n % d) - } - } - } -} -- cgit 1.4.1-3-g733a5 From 74eedd0f17d4e8383fe987d3f599987e31872711 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 17:13:07 -0500 Subject: make float* intrinsics testable on thumb there are no intrinsics for float equality atm, so transmute to an integer before comparing --- library/compiler-builtins/build.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d27eb7898e0..2c8cff7295c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1379,7 +1379,7 @@ use core::mem; use std::mem; use compiler_builtins::float::conv::__floatdidf; -fn mk_f64(x: u64) -> f64 { +fn to_u64(x: f64) -> u64 { unsafe { mem::transmute(x) } } @@ -1395,7 +1395,7 @@ static TEST_CASES: &[((i64,), u64)] = &[ fn floatdidf() { for &((a,), b) in TEST_CASES { let b_ = __floatdidf(a); - assert_eq!(((a,), mk_f64(b)), ((a,), b_)); + assert_eq!(((a,), b), ((a,), to_u64(b_))); } } " @@ -1445,7 +1445,7 @@ use core::mem; use std::mem; use compiler_builtins::float::conv::__floatsidf; -fn mk_f64(x: u64) -> f64 { +fn to_u64(x: f64) -> u64 { unsafe { mem::transmute(x) } } @@ -1461,7 +1461,7 @@ static TEST_CASES: &[((i32,), u64)] = &[ fn floatsidf() { for &((a,), b) in TEST_CASES { let b_ = __floatsidf(a); - assert_eq!(((a,), mk_f64(b)), ((a,), b_)); + assert_eq!(((a,), b), ((a,), to_u64(b_))); } } " @@ -1511,7 +1511,7 @@ use core::mem; use std::mem; use compiler_builtins::float::conv::__floatsisf; -fn mk_f32(x: u32) -> f32 { +fn to_u32(x: f32) -> u32 { unsafe { mem::transmute(x) } } @@ -1527,7 +1527,7 @@ static TEST_CASES: &[((i32,), u32)] = &[ fn floatsisf() { for &((a,), b) in TEST_CASES { let b_ = __floatsisf(a); - assert_eq!(((a,), mk_f32(b)), ((a,), b_)); + assert_eq!(((a,), b), ((a,), to_u32(b_))); } } " @@ -1577,7 +1577,7 @@ use core::mem; use std::mem; use compiler_builtins::float::conv::__floatundidf; -fn mk_f64(x: u64) -> f64 { +fn to_u64(x: f64) -> u64 { unsafe { mem::transmute(x) } } @@ -1593,7 +1593,7 @@ static TEST_CASES: &[((u64,), u64)] = &[ fn floatundidf() { for &((a,), b) in TEST_CASES { let b_ = __floatundidf(a); - assert_eq!(((a,), mk_f64(b)), ((a,), b_)); + assert_eq!(((a,), b), ((a,), to_u64(b_))); } } " @@ -1643,7 +1643,7 @@ use core::mem; use std::mem; use compiler_builtins::float::conv::__floatunsidf; -fn mk_f64(x: u64) -> f64 { +fn to_u64(x: f64) -> u64 { unsafe { mem::transmute(x) } } @@ -1659,7 +1659,7 @@ static TEST_CASES: &[((u32,), u64)] = &[ fn floatunsidf() { for &((a,), b) in TEST_CASES { let b_ = __floatunsidf(a); - assert_eq!(((a,), mk_f64(b)), ((a,), b_)); + assert_eq!(((a,), b), ((a,), to_u64(b_))); } } " @@ -1709,7 +1709,7 @@ use core::mem; use std::mem; use compiler_builtins::float::conv::__floatunsisf; -fn mk_f32(x: u32) -> f32 { +fn to_u32(x: f32) -> u32 { unsafe { mem::transmute(x) } } @@ -1725,7 +1725,7 @@ static TEST_CASES: &[((u32,), u32)] = &[ fn floatunsisf() { for &((a,), b) in TEST_CASES { let b_ = __floatunsisf(a); - assert_eq!(((a,), mk_f32(b)), ((a,), b_)); + assert_eq!(((a,), b), ((a,), to_u32(b_))); } } " -- cgit 1.4.1-3-g733a5 From d8576a4f8b71882257f81a15c270a86eb98635b1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 17:16:13 -0500 Subject: modify the CI setup to run tests on the thumb targets --- .../ci/docker/thumbv6m-linux-eabi/Dockerfile | 9 +++++++ .../ci/docker/thumbv6m-none-eabi/Dockerfile | 9 ------- .../ci/docker/thumbv7em-linux-eabi/Dockerfile | 9 +++++++ .../ci/docker/thumbv7em-linux-eabihf/Dockerfile | 9 +++++++ .../ci/docker/thumbv7em-none-eabi/Dockerfile | 9 ------- .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 9 ------- .../ci/docker/thumbv7m-linux-eabi/Dockerfile | 9 +++++++ .../ci/docker/thumbv7m-none-eabi/Dockerfile | 9 ------- library/compiler-builtins/ci/run.sh | 30 ++++++++++++++++++++-- 9 files changed, 64 insertions(+), 38 deletions(-) create mode 100644 library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile delete mode 100644 library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile delete mode 100644 library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile delete mode 100644 library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile delete mode 100644 library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile diff --git a/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile new file mode 100644 index 00000000000..d26035618e6 --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:16.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static +RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin +ENV AR_thumbv6m_linux_eabi=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV6M_LINUX_EABI_LINKER=arm-none-eabi-gcc \ + CC_thumbv6m_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile deleted file mode 100644 index 2a2d127e1d2..00000000000 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM ubuntu:16.04 -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev -RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \ - CC_thumbv6m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile new file mode 100644 index 00000000000..d630352a721 --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:16.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static +RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin +ENV AR_thumbv7em_linux_eabi=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV7EM_LINUX_EABI_LINKER=arm-none-eabi-gcc \ + CC_thumbv7em_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile new file mode 100644 index 00000000000..6f30729fa9e --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:16.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static +RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin +ENV AR_thumbv7em_linux_eabihf=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV7EM_LINUX_EABIHF_LINKER=arm-none-eabi-gcc \ + CC_thumbv7em_linux_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile deleted file mode 100644 index fda5dcbe6f8..00000000000 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM ubuntu:16.04 -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev -RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ - CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile deleted file mode 100644 index 5395e7449a9..00000000000 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM ubuntu:16.04 -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev -RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ - CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile new file mode 100644 index 00000000000..a7dbad64724 --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:16.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static +RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin +ENV AR_thumbv7m_linux_eabi=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV7M_LINUX_EABI_LINKER=arm-none-eabi-gcc \ + CC_thumbv7m_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile deleted file mode 100644 index e09c020a223..00000000000 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM ubuntu:16.04 -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev -RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ - CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index b30fad10fc8..17c54ef0427 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -3,8 +3,34 @@ set -ex # Test our implementation case $1 in thumb*) - xargo build --target $1 - xargo build --target $1 --release + for t in $(ls tests); do + t=${t%.rs} + + # TODO(#154) enable these tests when aeabi_*mul are implemented + case $t in + powi*f2) + continue + ;; + esac + + # FIXME(#150) debug assertion in divmoddi4 + case $1 in + thumbv6m-*) + case $t in + divdi3 | divmoddi4 | moddi3 | modsi3 | udivmoddi4 | udivmodsi4 | umoddi3 | \ + umodsi3) + continue + ;; + esac + ;; + esac + + xargo test --test $t --target $1 --features mem --no-run + qemu-arm-static target/${1}/debug/$t-* + + xargo test --test $t --target $1 --features mem --no-run --release + qemu-arm-static target/${1}/release/$t-* + done ;; *) cargo test --no-default-features --target $1 -- cgit 1.4.1-3-g733a5 From 9c0fe5be3daf5102ad857ff81df5e660ae6666bb Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 17:27:25 -0500 Subject: put test generation behind a Cargo feature to reduce build time for the most common case of not running tests --- library/compiler-builtins/Cargo.toml | 23 ++++++++--------------- library/compiler-builtins/build.rs | 2 ++ library/compiler-builtins/ci/run.sh | 8 ++++---- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 2aefba8bc3f..59f6b404abd 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,8 +5,8 @@ name = "compiler_builtins" version = "0.1.0" [build-dependencies] -cast = "0.2.0" -rand = "0.3.15" +cast = { version = "0.2.0", optional = true } +rand = { version = "0.3.15", optional = true } [build-dependencies.gcc] optional = true @@ -18,21 +18,14 @@ compiler-builtins = [] default = ["compiler-builtins"] mem = [] rustbuild = ["compiler-builtins"] +# generate tests +gen-tests = ["cast", "rand"] -[target] +[target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] +test = { git = "https://github.com/japaric/utest" } +utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japaric/utest" } +utest-macros = { git = "https://github.com/japaric/utest" } -[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))"] -[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))".dev-dependencies] - -[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))".dev-dependencies.test] -git = "https://github.com/japaric/utest" - -[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))".dev-dependencies.utest-cortex-m-qemu] -default-features = false -git = "https://github.com/japaric/utest" - -[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))".dev-dependencies.utest-macros] -git = "https://github.com/japaric/utest" [workspace] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2c8cff7295c..ac75e6ede88 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -18,6 +18,7 @@ fn main() { let llvm_target = target.split('-').collect::>(); // Build test files + #[cfg(feature = "gen-tests")] tests::generate(); // Build missing intrinsics from compiler-rt C source code @@ -36,6 +37,7 @@ fn main() { } } +#[cfg(feature = "gen-tests")] mod tests { extern crate cast; extern crate rand; diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 17c54ef0427..771f8812a02 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -25,16 +25,16 @@ case $1 in ;; esac - xargo test --test $t --target $1 --features mem --no-run + xargo test --test $t --target $1 --features 'mem gen-tests' --no-run qemu-arm-static target/${1}/debug/$t-* - xargo test --test $t --target $1 --features mem --no-run --release + xargo test --test $t --target $1 --features 'mem gen-tests' --no-run --release qemu-arm-static target/${1}/release/$t-* done ;; *) - cargo test --no-default-features --target $1 - cargo test --no-default-features --target $1 --release + cargo test --no-default-features --features gen-tests --target $1 + cargo test --no-default-features --features gen-tests --target $1 --release ;; esac -- cgit 1.4.1-3-g733a5 From 750b26267f9c66c41c3f51c6859402e7cf496bed Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 17:46:33 -0500 Subject: appveyor: cargo test requires the gen-tests feature --- library/compiler-builtins/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index c05bfdfc2b6..80d943c4b52 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -16,5 +16,5 @@ build: false test_script: - cargo build --target %TARGET% - cargo build --release --target %TARGET% - - cargo test --no-default-features --target %TARGET% - - cargo test --no-default-features --release --target %TARGET% + - cargo test --no-default-features --feature gen-tests --target %TARGET% + - cargo test --no-default-features --feature gen-tests --release --target %TARGET% -- cgit 1.4.1-3-g733a5 From a606075c9bdcc61f54c6a82499ee244de82a5487 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 17:59:45 -0500 Subject: .travis.yml: thumbs target have been renamed --- library/compiler-builtins/.travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 96bd24ab2f9..3c26d624777 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -22,10 +22,10 @@ matrix: - env: TARGET=powerpc-unknown-linux-gnu - env: TARGET=powerpc64-unknown-linux-gnu - env: TARGET=powerpc64le-unknown-linux-gnu - - env: TARGET=thumbv6m-none-eabi - - env: TARGET=thumbv7em-none-eabi - - env: TARGET=thumbv7em-none-eabihf - - env: TARGET=thumbv7m-none-eabi + - env: TARGET=thumbv6m-linux-eabi + - env: TARGET=thumbv7em-linux-eabi + - env: TARGET=thumbv7em-linux-eabihf + - env: TARGET=thumbv7m-linux-eabi - env: TARGET=x86_64-apple-darwin os: osx env: TARGET=x86_64-unknown-linux-gnu @@ -38,7 +38,7 @@ install: - source ~/.cargo/env - case $TARGET in x86_64-apple-darwin | x86_64-unknown-linux-gnu) ;; - thumbv*-none-eabi*) rustup component add rust-src ;; + thumbv*eabi*) rustup component add rust-src ;; *) rustup target add $TARGET;; esac -- cgit 1.4.1-3-g733a5 From 09f95517b19245357a41edc13998581839bf06d7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 18:00:16 -0500 Subject: travis: don't reinstall rustup travis now installs rust using rustup --- library/compiler-builtins/.travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 3c26d624777..108b12a014f 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -34,8 +34,6 @@ before_install: - test "$TRAVIS_OS_NAME" = "osx" || docker run --rm --privileged multiarch/qemu-user-static:register install: - - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION - - source ~/.cargo/env - case $TARGET in x86_64-apple-darwin | x86_64-unknown-linux-gnu) ;; thumbv*eabi*) rustup component add rust-src ;; -- cgit 1.4.1-3-g733a5 From f80b2c4af2a0c429525f7b739c808fa1f8a69878 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 20:10:45 -0500 Subject: s/feature/features/g --- library/compiler-builtins/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 80d943c4b52..61e5d6ce76f 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -16,5 +16,5 @@ build: false test_script: - cargo build --target %TARGET% - cargo build --release --target %TARGET% - - cargo test --no-default-features --feature gen-tests --target %TARGET% - - cargo test --no-default-features --feature gen-tests --release --target %TARGET% + - cargo test --no-default-features --features gen-tests --target %TARGET% + - cargo test --no-default-features --features gen-tests --release --target %TARGET% -- cgit 1.4.1-3-g733a5 From 2f64ef08701e94aeff9b9407dca4ed1ecb23f482 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 11:24:33 -0500 Subject: ignore i128 div / mul tests on MIPS there's an unfixed bug. See #137 --- library/compiler-builtins/tests/divti3.rs | 2 ++ library/compiler-builtins/tests/modti3.rs | 2 ++ library/compiler-builtins/tests/muloti4.rs | 2 ++ library/compiler-builtins/tests/udivmodti4.rs | 2 ++ library/compiler-builtins/tests/udivti3.rs | 2 ++ library/compiler-builtins/tests/umodti3.rs | 2 ++ 6 files changed, 12 insertions(+) diff --git a/library/compiler-builtins/tests/divti3.rs b/library/compiler-builtins/tests/divti3.rs index 62d9789d0f8..7919f8fe396 100644 --- a/library/compiler-builtins/tests/divti3.rs +++ b/library/compiler-builtins/tests/divti3.rs @@ -5,4 +5,6 @@ target_os = "linux", test), no_std)] +// FIXME(#137) +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/divti3.rs")); diff --git a/library/compiler-builtins/tests/modti3.rs b/library/compiler-builtins/tests/modti3.rs index 1a363f7cb41..62129cd04d3 100644 --- a/library/compiler-builtins/tests/modti3.rs +++ b/library/compiler-builtins/tests/modti3.rs @@ -5,4 +5,6 @@ target_os = "linux", test), no_std)] +// FIXME(#137) +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/modti3.rs")); diff --git a/library/compiler-builtins/tests/muloti4.rs b/library/compiler-builtins/tests/muloti4.rs index 262b4646592..358c57ec528 100644 --- a/library/compiler-builtins/tests/muloti4.rs +++ b/library/compiler-builtins/tests/muloti4.rs @@ -5,4 +5,6 @@ target_os = "linux", test), no_std)] +// FIXME(#137) +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/muloti4.rs")); diff --git a/library/compiler-builtins/tests/udivmodti4.rs b/library/compiler-builtins/tests/udivmodti4.rs index 1f9ed279926..8185ec0e789 100644 --- a/library/compiler-builtins/tests/udivmodti4.rs +++ b/library/compiler-builtins/tests/udivmodti4.rs @@ -5,4 +5,6 @@ target_os = "linux", test), no_std)] +// FIXME(#137) +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/udivmodti4.rs")); diff --git a/library/compiler-builtins/tests/udivti3.rs b/library/compiler-builtins/tests/udivti3.rs index fc602fd28af..cefddda8f86 100644 --- a/library/compiler-builtins/tests/udivti3.rs +++ b/library/compiler-builtins/tests/udivti3.rs @@ -5,4 +5,6 @@ target_os = "linux", test), no_std)] +// FIXME(#137) +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/udivti3.rs")); diff --git a/library/compiler-builtins/tests/umodti3.rs b/library/compiler-builtins/tests/umodti3.rs index 63a0bf28f2f..57e651b2710 100644 --- a/library/compiler-builtins/tests/umodti3.rs +++ b/library/compiler-builtins/tests/umodti3.rs @@ -5,4 +5,6 @@ target_os = "linux", test), no_std)] +// FIXME(#137) +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/umodti3.rs")); -- cgit 1.4.1-3-g733a5 From 692906c58a805b234e404840f14ed9d81a215b3e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 11:32:44 -0500 Subject: adapt the thumb target specs to upstream linker-flavor changes --- library/compiler-builtins/.cargo/config | 11 ----------- library/compiler-builtins/thumbv6m-linux-eabi.json | 5 ++++- library/compiler-builtins/thumbv7em-linux-eabi.json | 5 ++++- library/compiler-builtins/thumbv7em-linux-eabihf.json | 5 ++++- library/compiler-builtins/thumbv7m-linux-eabi.json | 5 ++++- 5 files changed, 16 insertions(+), 15 deletions(-) delete mode 100644 library/compiler-builtins/.cargo/config diff --git a/library/compiler-builtins/.cargo/config b/library/compiler-builtins/.cargo/config deleted file mode 100644 index b5389534582..00000000000 --- a/library/compiler-builtins/.cargo/config +++ /dev/null @@ -1,11 +0,0 @@ -[target.thumbv6m-none-eabi] -rustflags = ["-C", "link-arg=-nostartfiles"] - -[target.thumbv7m-none-eabi] -rustflags = ["-C", "link-arg=-nostartfiles"] - -[target.thumbv7em-none-eabi] -rustflags = ["-C", "link-arg=-nostartfiles"] - -[target.thumbv7em-none-eabihf] -rustflags = ["-C", "link-arg=-nostartfiles"] \ No newline at end of file diff --git a/library/compiler-builtins/thumbv6m-linux-eabi.json b/library/compiler-builtins/thumbv6m-linux-eabi.json index d3ac24dfc5e..dd0cb61bc09 100644 --- a/library/compiler-builtins/thumbv6m-linux-eabi.json +++ b/library/compiler-builtins/thumbv6m-linux-eabi.json @@ -12,11 +12,14 @@ "executables": true, "features": "+strict-align", "linker": "arm-none-eabi-gcc", + "linker-flavor": "gcc", "llvm-target": "thumbv6m-none-eabi", "max-atomic-width": 0, "os": "linux", "panic-strategy": "abort", - "pre-link-args": ["-nostartfiles"], + "pre-link-args": { + "gcc": ["-nostartfiles"] + }, "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", diff --git a/library/compiler-builtins/thumbv7em-linux-eabi.json b/library/compiler-builtins/thumbv7em-linux-eabi.json index af6ea94eebd..eef29f5cc7a 100644 --- a/library/compiler-builtins/thumbv7em-linux-eabi.json +++ b/library/compiler-builtins/thumbv7em-linux-eabi.json @@ -11,11 +11,14 @@ "env": "", "executables": true, "linker": "arm-none-eabi-gcc", + "linker-flavor": "gcc", "llvm-target": "thumbv7em-none-eabi", "max-atomic-width": 32, "os": "linux", "panic-strategy": "abort", - "pre-link-args": ["-nostartfiles"], + "pre-link-args": { + "gcc": ["-nostartfiles"] + }, "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", diff --git a/library/compiler-builtins/thumbv7em-linux-eabihf.json b/library/compiler-builtins/thumbv7em-linux-eabihf.json index 536d28c951d..5d72ec3b478 100644 --- a/library/compiler-builtins/thumbv7em-linux-eabihf.json +++ b/library/compiler-builtins/thumbv7em-linux-eabihf.json @@ -12,11 +12,14 @@ "executables": true, "features": "+vfp4,+d16,+fp-only-sp", "linker": "arm-none-eabi-gcc", + "linker-flavor": "gcc", "llvm-target": "thumbv7em-none-eabihf", "max-atomic-width": 32, "os": "linux", "panic-strategy": "abort", - "pre-link-args": ["-nostartfiles"], + "pre-link-args": { + "gcc": ["-nostartfiles"] + }, "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", diff --git a/library/compiler-builtins/thumbv7m-linux-eabi.json b/library/compiler-builtins/thumbv7m-linux-eabi.json index 02ed839cc82..1e8a7f0086f 100644 --- a/library/compiler-builtins/thumbv7m-linux-eabi.json +++ b/library/compiler-builtins/thumbv7m-linux-eabi.json @@ -11,11 +11,14 @@ "env": "", "executables": true, "linker": "arm-none-eabi-gcc", + "linker-flavor": "gcc", "llvm-target": "thumbv7m-none-eabi", "max-atomic-width": 32, "os": "linux", "panic-strategy": "abort", - "pre-link-args": ["-nostartfiles"], + "pre-link-args": { + "gcc": ["-nostartfiles"] + }, "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", -- cgit 1.4.1-3-g733a5 From 4de2ff7b9d6db673989ebf7388447424e4293ee9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 14:28:31 -0500 Subject: appveyor: make the host x86_64 when testing the i686 target --- library/compiler-builtins/appveyor.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 61e5d6ce76f..7c827268507 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -6,8 +6,12 @@ environment: install: - git submodule update --init - curl -sSf -o rustup-init.exe https://win.rustup.rs - - rustup-init.exe --default-host %TARGET% --default-toolchain nightly -y + - rustup-init.exe --default-host x86_64-pc-windows-msvc --default-toolchain nightly -y - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - ps: >- + If ($Env:TARGET -eq 'i686-pc-windows-msvc') { + rustup target add $Env:TARGET + } - rustc -Vv - cargo -V -- cgit 1.4.1-3-g733a5 From 5b8965c9de461275758a7aef7cbeee619e42537a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 14:47:23 -0500 Subject: i128 test: transmute intrinsic output before comparing on Windows, these intrinsics return a U64x2 type because of ABI requirements --- library/compiler-builtins/build.rs | 86 +++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index ac75e6ede88..5d48ec6ff89 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -189,6 +189,7 @@ use core::mem; target_os = "linux", test)))] use std::mem; + use compiler_builtins::float::add::__adddf3; fn mk_f64(x: u64) -> f64 { @@ -828,11 +829,22 @@ fn divsi3() { } fn prologue() -> &'static str { - " + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; + use compiler_builtins::int::sdiv::__divti3; static TEST_CASES: &[((i128, i128), i128)] = &[ -" +"# } fn epilogue() -> &'static str { @@ -842,7 +854,7 @@ static TEST_CASES: &[((i128, i128), i128)] = &[ #[test] fn divti3() { for &((a, b), c) in TEST_CASES { - let c_ = __divti3(a, b); + let c_: i128 = unsafe { mem::transmute(__divti3(a, b)) }; assert_eq!(((a, b), c), ((a, b), c_)); } } @@ -1895,11 +1907,22 @@ fn modsi3() { } fn prologue() -> &'static str { - " + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; + use compiler_builtins::int::sdiv::__modti3; static TEST_CASES: &[((i128, i128), i128)] = &[ -" +"# } fn epilogue() -> &'static str { @@ -1909,7 +1932,7 @@ static TEST_CASES: &[((i128, i128), i128)] = &[ #[test] fn modti3() { for &((a, b), c) in TEST_CASES { - let c_ = __modti3(a, b); + let c_: i128 = unsafe { mem::transmute(__modti3(a, b)) }; assert_eq!(((a, b), c), ((a, b), c_)); } } @@ -2913,11 +2936,22 @@ fn udivmodsi4() { } fn prologue() -> &'static str { - " + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; + use compiler_builtins::int::udiv::__udivmodti4; static TEST_CASES: &[((u128, u128), (u128, u128))] = &[ -" +"# } fn epilogue() -> &'static str { @@ -2928,7 +2962,7 @@ static TEST_CASES: &[((u128, u128), (u128, u128))] = &[ fn udivmodti4() { for &((a, b), (c, rem)) in TEST_CASES { let mut rem_ = 0; - let c_ = __udivmodti4(a, b, Some(&mut rem_)); + let c_: u128 = unsafe { mem::transmute(__udivmodti4(a, b, Some(&mut rem_))) }; assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); } } @@ -3036,11 +3070,22 @@ fn udivsi3() { } fn prologue() -> &'static str { - " + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; + use compiler_builtins::int::udiv::__udivti3; static TEST_CASES: &[((u128, u128), u128)] = &[ -" +"# } fn epilogue() -> &'static str { @@ -3050,7 +3095,7 @@ static TEST_CASES: &[((u128, u128), u128)] = &[ #[test] fn udivti3() { for &((a, b), c) in TEST_CASES { - let c_ = __udivti3(a, b); + let c_: u128 = unsafe { mem::transmute(__udivti3(a, b)) }; assert_eq!(((a, b), c), ((a, b), c_)); } } @@ -3219,11 +3264,22 @@ fn umodsi3() { } fn prologue() -> &'static str { - " + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; + use compiler_builtins::int::udiv::__umodti3; static TEST_CASES: &[((u128, u128), u128)] = &[ -" +"# } fn epilogue() -> &'static str { @@ -3233,7 +3289,7 @@ static TEST_CASES: &[((u128, u128), u128)] = &[ #[test] fn umodti3() { for &((a, b), c) in TEST_CASES { - let c_ = __umodti3(a, b); + let c_: u128 = unsafe { mem::transmute(__umodti3(a, b)) }; assert_eq!(((a, b), c), ((a, b), c_)); } } -- cgit 1.4.1-3-g733a5 From 3043cf860c4172d2a5eb1b4965dd119950122e88 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 14:53:19 -0500 Subject: powershell -> cmd.exe --- library/compiler-builtins/appveyor.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 7c827268507..f5a4c62f04c 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -8,10 +8,7 @@ install: - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe --default-host x86_64-pc-windows-msvc --default-toolchain nightly -y - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - - ps: >- - If ($Env:TARGET -eq 'i686-pc-windows-msvc') { - rustup target add $Env:TARGET - } + - if "%TARGET%"=="i686-pc-windows-msvc" ( rustup target add %TARGET% ) - rustc -Vv - cargo -V -- cgit 1.4.1-3-g733a5 From 1e48efeaef0c43e2125a4be9328f59e0a79f7a61 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 15:03:21 -0500 Subject: Revert "i128 test: transmute intrinsic output before comparing" This reverts commit 46085a2313ba196e3aab85a3380a07c6bd838fda. --- library/compiler-builtins/build.rs | 86 +++++++------------------------------- 1 file changed, 15 insertions(+), 71 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 5d48ec6ff89..ac75e6ede88 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -189,7 +189,6 @@ use core::mem; target_os = "linux", test)))] use std::mem; - use compiler_builtins::float::add::__adddf3; fn mk_f64(x: u64) -> f64 { @@ -829,22 +828,11 @@ fn divsi3() { } fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; - + " use compiler_builtins::int::sdiv::__divti3; static TEST_CASES: &[((i128, i128), i128)] = &[ -"# +" } fn epilogue() -> &'static str { @@ -854,7 +842,7 @@ static TEST_CASES: &[((i128, i128), i128)] = &[ #[test] fn divti3() { for &((a, b), c) in TEST_CASES { - let c_: i128 = unsafe { mem::transmute(__divti3(a, b)) }; + let c_ = __divti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } @@ -1907,22 +1895,11 @@ fn modsi3() { } fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; - + " use compiler_builtins::int::sdiv::__modti3; static TEST_CASES: &[((i128, i128), i128)] = &[ -"# +" } fn epilogue() -> &'static str { @@ -1932,7 +1909,7 @@ static TEST_CASES: &[((i128, i128), i128)] = &[ #[test] fn modti3() { for &((a, b), c) in TEST_CASES { - let c_: i128 = unsafe { mem::transmute(__modti3(a, b)) }; + let c_ = __modti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } @@ -2936,22 +2913,11 @@ fn udivmodsi4() { } fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; - + " use compiler_builtins::int::udiv::__udivmodti4; static TEST_CASES: &[((u128, u128), (u128, u128))] = &[ -"# +" } fn epilogue() -> &'static str { @@ -2962,7 +2928,7 @@ static TEST_CASES: &[((u128, u128), (u128, u128))] = &[ fn udivmodti4() { for &((a, b), (c, rem)) in TEST_CASES { let mut rem_ = 0; - let c_: u128 = unsafe { mem::transmute(__udivmodti4(a, b, Some(&mut rem_))) }; + let c_ = __udivmodti4(a, b, Some(&mut rem_)); assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); } } @@ -3070,22 +3036,11 @@ fn udivsi3() { } fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; - + " use compiler_builtins::int::udiv::__udivti3; static TEST_CASES: &[((u128, u128), u128)] = &[ -"# +" } fn epilogue() -> &'static str { @@ -3095,7 +3050,7 @@ static TEST_CASES: &[((u128, u128), u128)] = &[ #[test] fn udivti3() { for &((a, b), c) in TEST_CASES { - let c_: u128 = unsafe { mem::transmute(__udivti3(a, b)) }; + let c_ = __udivti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } @@ -3264,22 +3219,11 @@ fn umodsi3() { } fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; - + " use compiler_builtins::int::udiv::__umodti3; static TEST_CASES: &[((u128, u128), u128)] = &[ -"# +" } fn epilogue() -> &'static str { @@ -3289,7 +3233,7 @@ static TEST_CASES: &[((u128, u128), u128)] = &[ #[test] fn umodti3() { for &((a, b), c) in TEST_CASES { - let c_: u128 = unsafe { mem::transmute(__umodti3(a, b)) }; + let c_ = __umodti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } -- cgit 1.4.1-3-g733a5 From 05b6e8fa6c0aaede86dfa6db6ec5f629318e9e42 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 15:08:52 -0500 Subject: ignore i128 tests on windows see #158 --- library/compiler-builtins/tests/divti3.rs | 3 ++- library/compiler-builtins/tests/modti3.rs | 3 ++- library/compiler-builtins/tests/udivmodti4.rs | 3 ++- library/compiler-builtins/tests/udivti3.rs | 3 ++- library/compiler-builtins/tests/umodti3.rs | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/tests/divti3.rs b/library/compiler-builtins/tests/divti3.rs index 7919f8fe396..4c897896e3d 100644 --- a/library/compiler-builtins/tests/divti3.rs +++ b/library/compiler-builtins/tests/divti3.rs @@ -6,5 +6,6 @@ test), no_std)] // FIXME(#137) -#[cfg(not(target_arch = "mips"))] +// FIXME(#158) +#[cfg(not(any(target_arch = "mips"), windows))] include!(concat!(env!("OUT_DIR"), "/divti3.rs")); diff --git a/library/compiler-builtins/tests/modti3.rs b/library/compiler-builtins/tests/modti3.rs index 62129cd04d3..191bd9b6f91 100644 --- a/library/compiler-builtins/tests/modti3.rs +++ b/library/compiler-builtins/tests/modti3.rs @@ -6,5 +6,6 @@ test), no_std)] // FIXME(#137) -#[cfg(not(target_arch = "mips"))] +// FIXME(#158) +#[cfg(not(any(target_arch = "mips"), windows))] include!(concat!(env!("OUT_DIR"), "/modti3.rs")); diff --git a/library/compiler-builtins/tests/udivmodti4.rs b/library/compiler-builtins/tests/udivmodti4.rs index 8185ec0e789..daeb81075d5 100644 --- a/library/compiler-builtins/tests/udivmodti4.rs +++ b/library/compiler-builtins/tests/udivmodti4.rs @@ -6,5 +6,6 @@ test), no_std)] // FIXME(#137) -#[cfg(not(target_arch = "mips"))] +// FIXME(#158) +#[cfg(not(any(target_arch = "mips"), windows))] include!(concat!(env!("OUT_DIR"), "/udivmodti4.rs")); diff --git a/library/compiler-builtins/tests/udivti3.rs b/library/compiler-builtins/tests/udivti3.rs index cefddda8f86..5315f310926 100644 --- a/library/compiler-builtins/tests/udivti3.rs +++ b/library/compiler-builtins/tests/udivti3.rs @@ -6,5 +6,6 @@ test), no_std)] // FIXME(#137) -#[cfg(not(target_arch = "mips"))] +// FIXME(#158) +#[cfg(not(any(target_arch = "mips"), windows))] include!(concat!(env!("OUT_DIR"), "/udivti3.rs")); diff --git a/library/compiler-builtins/tests/umodti3.rs b/library/compiler-builtins/tests/umodti3.rs index 57e651b2710..22a4180b375 100644 --- a/library/compiler-builtins/tests/umodti3.rs +++ b/library/compiler-builtins/tests/umodti3.rs @@ -6,5 +6,6 @@ test), no_std)] // FIXME(#137) -#[cfg(not(target_arch = "mips"))] +// FIXME(#158) +#[cfg(not(any(target_arch = "mips"), windows))] include!(concat!(env!("OUT_DIR"), "/umodti3.rs")); -- cgit 1.4.1-3-g733a5 From 0666ed145ae591c8c195e7f64c4be4f5c082c4db Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 15:17:05 -0500 Subject: fix cfg syntax --- library/compiler-builtins/tests/divti3.rs | 2 +- library/compiler-builtins/tests/modti3.rs | 2 +- library/compiler-builtins/tests/udivmodti4.rs | 2 +- library/compiler-builtins/tests/udivti3.rs | 2 +- library/compiler-builtins/tests/umodti3.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/tests/divti3.rs b/library/compiler-builtins/tests/divti3.rs index 4c897896e3d..c86785fe813 100644 --- a/library/compiler-builtins/tests/divti3.rs +++ b/library/compiler-builtins/tests/divti3.rs @@ -7,5 +7,5 @@ // FIXME(#137) // FIXME(#158) -#[cfg(not(any(target_arch = "mips"), windows))] +#[cfg(not(any(target_arch = "mips", windows)))] include!(concat!(env!("OUT_DIR"), "/divti3.rs")); diff --git a/library/compiler-builtins/tests/modti3.rs b/library/compiler-builtins/tests/modti3.rs index 191bd9b6f91..2ce42ac46f4 100644 --- a/library/compiler-builtins/tests/modti3.rs +++ b/library/compiler-builtins/tests/modti3.rs @@ -7,5 +7,5 @@ // FIXME(#137) // FIXME(#158) -#[cfg(not(any(target_arch = "mips"), windows))] +#[cfg(not(any(target_arch = "mips", windows)))] include!(concat!(env!("OUT_DIR"), "/modti3.rs")); diff --git a/library/compiler-builtins/tests/udivmodti4.rs b/library/compiler-builtins/tests/udivmodti4.rs index daeb81075d5..5629d617bd3 100644 --- a/library/compiler-builtins/tests/udivmodti4.rs +++ b/library/compiler-builtins/tests/udivmodti4.rs @@ -7,5 +7,5 @@ // FIXME(#137) // FIXME(#158) -#[cfg(not(any(target_arch = "mips"), windows))] +#[cfg(not(any(target_arch = "mips", windows)))] include!(concat!(env!("OUT_DIR"), "/udivmodti4.rs")); diff --git a/library/compiler-builtins/tests/udivti3.rs b/library/compiler-builtins/tests/udivti3.rs index 5315f310926..350922563ff 100644 --- a/library/compiler-builtins/tests/udivti3.rs +++ b/library/compiler-builtins/tests/udivti3.rs @@ -7,5 +7,5 @@ // FIXME(#137) // FIXME(#158) -#[cfg(not(any(target_arch = "mips"), windows))] +#[cfg(not(any(target_arch = "mips", windows)))] include!(concat!(env!("OUT_DIR"), "/udivti3.rs")); diff --git a/library/compiler-builtins/tests/umodti3.rs b/library/compiler-builtins/tests/umodti3.rs index 22a4180b375..5807bcff395 100644 --- a/library/compiler-builtins/tests/umodti3.rs +++ b/library/compiler-builtins/tests/umodti3.rs @@ -7,5 +7,5 @@ // FIXME(#137) // FIXME(#158) -#[cfg(not(any(target_arch = "mips"), windows))] +#[cfg(not(any(target_arch = "mips", windows)))] include!(concat!(env!("OUT_DIR"), "/umodti3.rs")); -- cgit 1.4.1-3-g733a5 From 8dad658a6bb796366f0a333b56f8bd7d6b71f1ba Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 17:09:05 -0500 Subject: move intrinsics test from src/bin to examples with this change the libc crate is not required when calling `cargo build -p compiler-builtins` --- library/compiler-builtins/ci/run.sh | 12 +- library/compiler-builtins/examples/intrinsics.rs | 455 +++++++++++++++++++++++ library/compiler-builtins/src/bin/intrinsics.rs | 455 ----------------------- 3 files changed, 461 insertions(+), 461 deletions(-) create mode 100644 library/compiler-builtins/examples/intrinsics.rs delete mode 100644 library/compiler-builtins/src/bin/intrinsics.rs diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 771f8812a02..4a28e8a1894 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -41,10 +41,10 @@ esac # Verify that we haven't drop any intrinsic/symbol case $1 in thumb*) - xargo build --features c --target $1 --bin intrinsics + xargo build --features c --target $1 --example intrinsics ;; *) - cargo build --no-default-features --features c --target $1 --bin intrinsics + cargo build --no-default-features --features c --target $1 --example intrinsics ;; esac @@ -52,12 +52,12 @@ esac # TODO(#79) fix the undefined references problem for debug-assertions+lto case $1 in thumb*) - RUSTFLAGS="-C debug-assertions=no" xargo rustc --no-default-features --features c --target $1 --bin intrinsics -- -C lto -C link-arg=-nostartfiles - xargo rustc --no-default-features --features c --target $1 --bin intrinsics --release -- -C lto + RUSTFLAGS="-C debug-assertions=no" xargo rustc --no-default-features --features c --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles + xargo rustc --no-default-features --features c --target $1 --example intrinsics --release -- -C lto ;; *) - RUSTFLAGS="-C debug-assertions=no" cargo rustc --no-default-features --features c --target $1 --bin intrinsics -- -C lto - cargo rustc --no-default-features --features c --target $1 --bin intrinsics --release -- -C lto + RUSTFLAGS="-C debug-assertions=no" cargo rustc --no-default-features --features c --target $1 --example intrinsics -- -C lto + cargo rustc --no-default-features --features c --target $1 --example intrinsics --release -- -C lto ;; esac diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs new file mode 100644 index 00000000000..4c5c8842bb9 --- /dev/null +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -0,0 +1,455 @@ +// By compiling this file we check that all the intrinsics we care about continue to be provided by +// the `compiler_builtins` crate regardless of the changes we make to it. If we, by mistake, stop +// compiling a C implementation and forget to implement that intrinsic in Rust, this file will fail +// to link due to the missing intrinsic (symbol). + +#![allow(unused_features)] +#![cfg_attr(thumb, no_main)] +#![deny(dead_code)] +#![feature(asm)] +#![feature(compiler_builtins_lib)] +#![feature(core_float)] +#![feature(lang_items)] +#![feature(libc)] +#![feature(start)] +#![feature(i128_type)] +#![no_std] + +#[cfg(not(thumb))] +extern crate libc; +extern crate compiler_builtins; + +// NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even +// compiler-rt provides a C/assembly implementation. + +// Every function in this module maps will be lowered to an intrinsic by LLVM, if the platform +// doesn't have native support for the operation used in the function. ARM has a naming convention +// convention for its intrinsics that's different from other architectures; that's why some function +// have an additional comment: the function name is the ARM name for the intrinsic and the comment +// in the non-ARM name for the intrinsic. +#[cfg(feature = "c")] +mod intrinsics { + use core::num::Float; + + // trunccdfsf2 + pub fn aeabi_d2f(x: f64) -> f32 { + x as f32 + } + + // fixdfsi + pub fn aeabi_d2i(x: f64) -> i32 { + x as i32 + } + + // fixdfdi + #[cfg(not(thumbv6m))] + pub fn aeabi_d2l(x: f64) -> i64 { + x as i64 + } + + #[cfg(thumbv6m)] + pub fn aeabi_d2l(_: f64) -> i64 { + 0 + } + + // fixunsdfsi + pub fn aeabi_d2uiz(x: f64) -> u32 { + x as u32 + } + + // fixunsdfdi + #[cfg(not(thumbv6m))] + pub fn aeabi_d2ulz(x: f64) -> u64 { + x as u64 + } + + #[cfg(thumbv6m)] + pub fn aeabi_d2ulz(_: f64) -> u64 { + 0 + } + + // adddf3 + pub fn aeabi_dadd(a: f64, b: f64) -> f64 { + a + b + } + + // eqdf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_dcmpeq(a: f64, b: f64) -> bool { + a == b + } + + #[cfg(thumbv6m)] + pub fn aeabi_dcmpeq(_: f64, _: f64) -> bool { + true + } + + // gtdf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_dcmpgt(a: f64, b: f64) -> bool { + a > b + } + + #[cfg(thumbv6m)] + pub fn aeabi_dcmpgt(_: f64, _: f64) -> bool { + true + } + + // ltdf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_dcmplt(a: f64, b: f64) -> bool { + a < b + } + + #[cfg(thumbv6m)] + pub fn aeabi_dcmplt(_: f64, _: f64) -> bool { + true + } + + // divdf3 + pub fn aeabi_ddiv(a: f64, b: f64) -> f64 { + a / b + } + + // muldf3 + pub fn aeabi_dmul(a: f64, b: f64) -> f64 { + a * b + } + + // subdf3 + pub fn aeabi_dsub(a: f64, b: f64) -> f64 { + a - b + } + + // extendsfdf2 + pub fn aeabi_f2d(x: f32) -> f64 { + x as f64 + } + + // fixsfsi + pub fn aeabi_f2iz(x: f32) -> i32 { + x as i32 + } + + // fixsfdi + #[cfg(not(thumbv6m))] + pub fn aeabi_f2lz(x: f32) -> i64 { + x as i64 + } + + #[cfg(thumbv6m)] + pub fn aeabi_f2lz(_: f32) -> i64 { + 0 + } + + // fixunssfsi + pub fn aeabi_f2uiz(x: f32) -> u32 { + x as u32 + } + + // fixunssfdi + #[cfg(not(thumbv6m))] + pub fn aeabi_f2ulz(x: f32) -> u64 { + x as u64 + } + + #[cfg(thumbv6m)] + pub fn aeabi_f2ulz(_: f32) -> u64 { + 0 + } + + // addsf3 + pub fn aeabi_fadd(a: f32, b: f32) -> f32 { + a + b + } + + // eqsf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_fcmpeq(a: f32, b: f32) -> bool { + a == b + } + + #[cfg(thumbv6m)] + pub fn aeabi_fcmpeq(_: f32, _: f32) -> bool { + true + } + + // gtsf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_fcmpgt(a: f32, b: f32) -> bool { + a > b + } + + #[cfg(thumbv6m)] + pub fn aeabi_fcmpgt(_: f32, _: f32) -> bool { + true + } + + // ltsf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_fcmplt(a: f32, b: f32) -> bool { + a < b + } + + #[cfg(thumbv6m)] + pub fn aeabi_fcmplt(_: f32, _: f32) -> bool { + true + } + + // divsf3 + pub fn aeabi_fdiv(a: f32, b: f32) -> f32 { + a / b + } + + // mulsf3 + pub fn aeabi_fmul(a: f32, b: f32) -> f32 { + a * b + } + + // subsf3 + pub fn aeabi_fsub(a: f32, b: f32) -> f32 { + a - b + } + + // floatsidf + pub fn aeabi_i2d(x: i32) -> f64 { + x as f64 + } + + // floatsisf + pub fn aeabi_i2f(x: i32) -> f32 { + x as f32 + } + + pub fn aeabi_idiv(a: i32, b: i32) -> i32 { + a.wrapping_div(b) + } + + pub fn aeabi_idivmod(a: i32, b: i32) -> i32 { + a % b + } + + // floatdidf + pub fn aeabi_l2d(x: i64) -> f64 { + x as f64 + } + + // floatdisf + pub fn aeabi_l2f(x: i64) -> f32 { + x as f32 + } + + // divdi3 + pub fn aeabi_ldivmod(a: i64, b: i64) -> i64 { + a / b + } + + // muldi3 + pub fn aeabi_lmul(a: i64, b: i64) -> i64 { + a.wrapping_mul(b) + } + + // floatunsidf + pub fn aeabi_ui2d(x: u32) -> f64 { + x as f64 + } + + // floatunsisf + pub fn aeabi_ui2f(x: u32) -> f32 { + x as f32 + } + + pub fn aeabi_uidiv(a: u32, b: u32) -> u32 { + a / b + } + + pub fn aeabi_uidivmod(a: u32, b: u32) -> u32 { + a % b + } + + // floatundidf + pub fn aeabi_ul2d(x: u64) -> f64 { + x as f64 + } + + // floatundisf + pub fn aeabi_ul2f(x: u64) -> f32 { + x as f32 + } + + // udivdi3 + pub fn aeabi_uldivmod(a: u64, b: u64) -> u64 { + a * b + } + + pub fn moddi3(a: i64, b: i64) -> i64 { + a % b + } + + pub fn mulodi4(a: i64, b: i64) -> i64 { + a * b + } + + pub fn powidf2(a: f64, b: i32) -> f64 { + a.powi(b) + } + + pub fn powisf2(a: f32, b: i32) -> f32 { + a.powi(b) + } + + pub fn umoddi3(a: u64, b: u64) -> u64 { + a % b + } + + pub fn muloti4(a: u128, b: u128) -> Option { + a.checked_mul(b) + } + + pub fn multi3(a: u128, b: u128) -> u128 { + a.wrapping_mul(b) + } + + pub fn ashlti3(a: u128, b: usize) -> u128 { + a >> b + } + + pub fn ashrti3(a: u128, b: usize) -> u128 { + a << b + } + + pub fn lshrti3(a: i128, b: usize) -> i128 { + a >> b + } + + pub fn udivti3(a: u128, b: u128) -> u128 { + a / b + } + + pub fn umodti3(a: u128, b: u128) -> u128 { + a % b + } + + pub fn divti3(a: i128, b: i128) -> i128 { + a / b + } + + pub fn modti3(a: i128, b: i128) -> i128 { + a % b + } +} + +#[cfg(feature = "c")] +fn run() { + use intrinsics::*; + + // A copy of "test::black_box". Used to prevent LLVM from optimizing away the intrinsics during LTO + fn bb(dummy: T) -> T { + unsafe { asm!("" : : "r"(&dummy)) } + dummy + } + + bb(aeabi_d2f(bb(2.))); + bb(aeabi_d2i(bb(2.))); + bb(aeabi_d2l(bb(2.))); + bb(aeabi_d2uiz(bb(2.))); + bb(aeabi_d2ulz(bb(2.))); + bb(aeabi_dadd(bb(2.), bb(3.))); + bb(aeabi_dcmpeq(bb(2.), bb(3.))); + bb(aeabi_dcmpgt(bb(2.), bb(3.))); + bb(aeabi_dcmplt(bb(2.), bb(3.))); + bb(aeabi_ddiv(bb(2.), bb(3.))); + bb(aeabi_dmul(bb(2.), bb(3.))); + bb(aeabi_dsub(bb(2.), bb(3.))); + bb(aeabi_f2d(bb(2.))); + bb(aeabi_f2iz(bb(2.))); + bb(aeabi_f2lz(bb(2.))); + bb(aeabi_f2uiz(bb(2.))); + bb(aeabi_f2ulz(bb(2.))); + bb(aeabi_fadd(bb(2.), bb(3.))); + bb(aeabi_fcmpeq(bb(2.), bb(3.))); + bb(aeabi_fcmpgt(bb(2.), bb(3.))); + bb(aeabi_fcmplt(bb(2.), bb(3.))); + bb(aeabi_fdiv(bb(2.), bb(3.))); + bb(aeabi_fmul(bb(2.), bb(3.))); + bb(aeabi_fsub(bb(2.), bb(3.))); + bb(aeabi_i2d(bb(2))); + bb(aeabi_i2f(bb(2))); + bb(aeabi_idiv(bb(2), bb(3))); + bb(aeabi_idivmod(bb(2), bb(3))); + bb(aeabi_l2d(bb(2))); + bb(aeabi_l2f(bb(2))); + bb(aeabi_ldivmod(bb(2), bb(3))); + bb(aeabi_lmul(bb(2), bb(3))); + bb(aeabi_ui2d(bb(2))); + bb(aeabi_ui2f(bb(2))); + bb(aeabi_uidiv(bb(2), bb(3))); + bb(aeabi_uidivmod(bb(2), bb(3))); + bb(aeabi_ul2d(bb(2))); + bb(aeabi_ul2f(bb(2))); + bb(aeabi_uldivmod(bb(2), bb(3))); + bb(moddi3(bb(2), bb(3))); + bb(mulodi4(bb(2), bb(3))); + bb(powidf2(bb(2.), bb(3))); + bb(powisf2(bb(2.), bb(3))); + bb(umoddi3(bb(2), bb(3))); + bb(muloti4(bb(2), bb(2))); + bb(multi3(bb(2), bb(2))); + bb(ashlti3(bb(2), bb(2))); + bb(ashrti3(bb(2), bb(2))); + bb(lshrti3(bb(2), bb(2))); + bb(udivti3(bb(2), bb(2))); + bb(umodti3(bb(2), bb(2))); + bb(divti3(bb(2), bb(2))); + bb(modti3(bb(2), bb(2))); +} + +#[cfg(all(feature = "c", not(thumb)))] +#[start] +fn main(_: isize, _: *const *const u8) -> isize { + run(); + + 0 +} + +#[cfg(all(not(feature = "c"), not(thumb)))] +#[start] +fn main(_: isize, _: *const *const u8) -> isize { + 0 +} + +#[cfg(all(feature = "c", thumb))] +#[no_mangle] +pub fn _start() -> ! { + run(); + loop {} +} + +#[cfg(all(not(feature = "c"), thumb))] +#[no_mangle] +pub fn _start() -> ! { + loop {} +} + +// ARM targets need these symbols +#[no_mangle] +pub fn __aeabi_unwind_cpp_pr0() {} + +#[no_mangle] +pub fn __aeabi_unwind_cpp_pr1() {} + +// Avoid "undefined reference to `_Unwind_Resume`" errors +#[allow(non_snake_case)] +#[no_mangle] +pub fn _Unwind_Resume() {} + +// Lang items +#[cfg(not(test))] +#[lang = "eh_personality"] +#[no_mangle] +extern "C" fn eh_personality() {} + +#[cfg(not(test))] +#[lang = "panic_fmt"] +#[no_mangle] +extern "C" fn panic_fmt() {} diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs deleted file mode 100644 index 4c5c8842bb9..00000000000 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ /dev/null @@ -1,455 +0,0 @@ -// By compiling this file we check that all the intrinsics we care about continue to be provided by -// the `compiler_builtins` crate regardless of the changes we make to it. If we, by mistake, stop -// compiling a C implementation and forget to implement that intrinsic in Rust, this file will fail -// to link due to the missing intrinsic (symbol). - -#![allow(unused_features)] -#![cfg_attr(thumb, no_main)] -#![deny(dead_code)] -#![feature(asm)] -#![feature(compiler_builtins_lib)] -#![feature(core_float)] -#![feature(lang_items)] -#![feature(libc)] -#![feature(start)] -#![feature(i128_type)] -#![no_std] - -#[cfg(not(thumb))] -extern crate libc; -extern crate compiler_builtins; - -// NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even -// compiler-rt provides a C/assembly implementation. - -// Every function in this module maps will be lowered to an intrinsic by LLVM, if the platform -// doesn't have native support for the operation used in the function. ARM has a naming convention -// convention for its intrinsics that's different from other architectures; that's why some function -// have an additional comment: the function name is the ARM name for the intrinsic and the comment -// in the non-ARM name for the intrinsic. -#[cfg(feature = "c")] -mod intrinsics { - use core::num::Float; - - // trunccdfsf2 - pub fn aeabi_d2f(x: f64) -> f32 { - x as f32 - } - - // fixdfsi - pub fn aeabi_d2i(x: f64) -> i32 { - x as i32 - } - - // fixdfdi - #[cfg(not(thumbv6m))] - pub fn aeabi_d2l(x: f64) -> i64 { - x as i64 - } - - #[cfg(thumbv6m)] - pub fn aeabi_d2l(_: f64) -> i64 { - 0 - } - - // fixunsdfsi - pub fn aeabi_d2uiz(x: f64) -> u32 { - x as u32 - } - - // fixunsdfdi - #[cfg(not(thumbv6m))] - pub fn aeabi_d2ulz(x: f64) -> u64 { - x as u64 - } - - #[cfg(thumbv6m)] - pub fn aeabi_d2ulz(_: f64) -> u64 { - 0 - } - - // adddf3 - pub fn aeabi_dadd(a: f64, b: f64) -> f64 { - a + b - } - - // eqdf2 - #[cfg(not(thumbv6m))] - pub fn aeabi_dcmpeq(a: f64, b: f64) -> bool { - a == b - } - - #[cfg(thumbv6m)] - pub fn aeabi_dcmpeq(_: f64, _: f64) -> bool { - true - } - - // gtdf2 - #[cfg(not(thumbv6m))] - pub fn aeabi_dcmpgt(a: f64, b: f64) -> bool { - a > b - } - - #[cfg(thumbv6m)] - pub fn aeabi_dcmpgt(_: f64, _: f64) -> bool { - true - } - - // ltdf2 - #[cfg(not(thumbv6m))] - pub fn aeabi_dcmplt(a: f64, b: f64) -> bool { - a < b - } - - #[cfg(thumbv6m)] - pub fn aeabi_dcmplt(_: f64, _: f64) -> bool { - true - } - - // divdf3 - pub fn aeabi_ddiv(a: f64, b: f64) -> f64 { - a / b - } - - // muldf3 - pub fn aeabi_dmul(a: f64, b: f64) -> f64 { - a * b - } - - // subdf3 - pub fn aeabi_dsub(a: f64, b: f64) -> f64 { - a - b - } - - // extendsfdf2 - pub fn aeabi_f2d(x: f32) -> f64 { - x as f64 - } - - // fixsfsi - pub fn aeabi_f2iz(x: f32) -> i32 { - x as i32 - } - - // fixsfdi - #[cfg(not(thumbv6m))] - pub fn aeabi_f2lz(x: f32) -> i64 { - x as i64 - } - - #[cfg(thumbv6m)] - pub fn aeabi_f2lz(_: f32) -> i64 { - 0 - } - - // fixunssfsi - pub fn aeabi_f2uiz(x: f32) -> u32 { - x as u32 - } - - // fixunssfdi - #[cfg(not(thumbv6m))] - pub fn aeabi_f2ulz(x: f32) -> u64 { - x as u64 - } - - #[cfg(thumbv6m)] - pub fn aeabi_f2ulz(_: f32) -> u64 { - 0 - } - - // addsf3 - pub fn aeabi_fadd(a: f32, b: f32) -> f32 { - a + b - } - - // eqsf2 - #[cfg(not(thumbv6m))] - pub fn aeabi_fcmpeq(a: f32, b: f32) -> bool { - a == b - } - - #[cfg(thumbv6m)] - pub fn aeabi_fcmpeq(_: f32, _: f32) -> bool { - true - } - - // gtsf2 - #[cfg(not(thumbv6m))] - pub fn aeabi_fcmpgt(a: f32, b: f32) -> bool { - a > b - } - - #[cfg(thumbv6m)] - pub fn aeabi_fcmpgt(_: f32, _: f32) -> bool { - true - } - - // ltsf2 - #[cfg(not(thumbv6m))] - pub fn aeabi_fcmplt(a: f32, b: f32) -> bool { - a < b - } - - #[cfg(thumbv6m)] - pub fn aeabi_fcmplt(_: f32, _: f32) -> bool { - true - } - - // divsf3 - pub fn aeabi_fdiv(a: f32, b: f32) -> f32 { - a / b - } - - // mulsf3 - pub fn aeabi_fmul(a: f32, b: f32) -> f32 { - a * b - } - - // subsf3 - pub fn aeabi_fsub(a: f32, b: f32) -> f32 { - a - b - } - - // floatsidf - pub fn aeabi_i2d(x: i32) -> f64 { - x as f64 - } - - // floatsisf - pub fn aeabi_i2f(x: i32) -> f32 { - x as f32 - } - - pub fn aeabi_idiv(a: i32, b: i32) -> i32 { - a.wrapping_div(b) - } - - pub fn aeabi_idivmod(a: i32, b: i32) -> i32 { - a % b - } - - // floatdidf - pub fn aeabi_l2d(x: i64) -> f64 { - x as f64 - } - - // floatdisf - pub fn aeabi_l2f(x: i64) -> f32 { - x as f32 - } - - // divdi3 - pub fn aeabi_ldivmod(a: i64, b: i64) -> i64 { - a / b - } - - // muldi3 - pub fn aeabi_lmul(a: i64, b: i64) -> i64 { - a.wrapping_mul(b) - } - - // floatunsidf - pub fn aeabi_ui2d(x: u32) -> f64 { - x as f64 - } - - // floatunsisf - pub fn aeabi_ui2f(x: u32) -> f32 { - x as f32 - } - - pub fn aeabi_uidiv(a: u32, b: u32) -> u32 { - a / b - } - - pub fn aeabi_uidivmod(a: u32, b: u32) -> u32 { - a % b - } - - // floatundidf - pub fn aeabi_ul2d(x: u64) -> f64 { - x as f64 - } - - // floatundisf - pub fn aeabi_ul2f(x: u64) -> f32 { - x as f32 - } - - // udivdi3 - pub fn aeabi_uldivmod(a: u64, b: u64) -> u64 { - a * b - } - - pub fn moddi3(a: i64, b: i64) -> i64 { - a % b - } - - pub fn mulodi4(a: i64, b: i64) -> i64 { - a * b - } - - pub fn powidf2(a: f64, b: i32) -> f64 { - a.powi(b) - } - - pub fn powisf2(a: f32, b: i32) -> f32 { - a.powi(b) - } - - pub fn umoddi3(a: u64, b: u64) -> u64 { - a % b - } - - pub fn muloti4(a: u128, b: u128) -> Option { - a.checked_mul(b) - } - - pub fn multi3(a: u128, b: u128) -> u128 { - a.wrapping_mul(b) - } - - pub fn ashlti3(a: u128, b: usize) -> u128 { - a >> b - } - - pub fn ashrti3(a: u128, b: usize) -> u128 { - a << b - } - - pub fn lshrti3(a: i128, b: usize) -> i128 { - a >> b - } - - pub fn udivti3(a: u128, b: u128) -> u128 { - a / b - } - - pub fn umodti3(a: u128, b: u128) -> u128 { - a % b - } - - pub fn divti3(a: i128, b: i128) -> i128 { - a / b - } - - pub fn modti3(a: i128, b: i128) -> i128 { - a % b - } -} - -#[cfg(feature = "c")] -fn run() { - use intrinsics::*; - - // A copy of "test::black_box". Used to prevent LLVM from optimizing away the intrinsics during LTO - fn bb(dummy: T) -> T { - unsafe { asm!("" : : "r"(&dummy)) } - dummy - } - - bb(aeabi_d2f(bb(2.))); - bb(aeabi_d2i(bb(2.))); - bb(aeabi_d2l(bb(2.))); - bb(aeabi_d2uiz(bb(2.))); - bb(aeabi_d2ulz(bb(2.))); - bb(aeabi_dadd(bb(2.), bb(3.))); - bb(aeabi_dcmpeq(bb(2.), bb(3.))); - bb(aeabi_dcmpgt(bb(2.), bb(3.))); - bb(aeabi_dcmplt(bb(2.), bb(3.))); - bb(aeabi_ddiv(bb(2.), bb(3.))); - bb(aeabi_dmul(bb(2.), bb(3.))); - bb(aeabi_dsub(bb(2.), bb(3.))); - bb(aeabi_f2d(bb(2.))); - bb(aeabi_f2iz(bb(2.))); - bb(aeabi_f2lz(bb(2.))); - bb(aeabi_f2uiz(bb(2.))); - bb(aeabi_f2ulz(bb(2.))); - bb(aeabi_fadd(bb(2.), bb(3.))); - bb(aeabi_fcmpeq(bb(2.), bb(3.))); - bb(aeabi_fcmpgt(bb(2.), bb(3.))); - bb(aeabi_fcmplt(bb(2.), bb(3.))); - bb(aeabi_fdiv(bb(2.), bb(3.))); - bb(aeabi_fmul(bb(2.), bb(3.))); - bb(aeabi_fsub(bb(2.), bb(3.))); - bb(aeabi_i2d(bb(2))); - bb(aeabi_i2f(bb(2))); - bb(aeabi_idiv(bb(2), bb(3))); - bb(aeabi_idivmod(bb(2), bb(3))); - bb(aeabi_l2d(bb(2))); - bb(aeabi_l2f(bb(2))); - bb(aeabi_ldivmod(bb(2), bb(3))); - bb(aeabi_lmul(bb(2), bb(3))); - bb(aeabi_ui2d(bb(2))); - bb(aeabi_ui2f(bb(2))); - bb(aeabi_uidiv(bb(2), bb(3))); - bb(aeabi_uidivmod(bb(2), bb(3))); - bb(aeabi_ul2d(bb(2))); - bb(aeabi_ul2f(bb(2))); - bb(aeabi_uldivmod(bb(2), bb(3))); - bb(moddi3(bb(2), bb(3))); - bb(mulodi4(bb(2), bb(3))); - bb(powidf2(bb(2.), bb(3))); - bb(powisf2(bb(2.), bb(3))); - bb(umoddi3(bb(2), bb(3))); - bb(muloti4(bb(2), bb(2))); - bb(multi3(bb(2), bb(2))); - bb(ashlti3(bb(2), bb(2))); - bb(ashrti3(bb(2), bb(2))); - bb(lshrti3(bb(2), bb(2))); - bb(udivti3(bb(2), bb(2))); - bb(umodti3(bb(2), bb(2))); - bb(divti3(bb(2), bb(2))); - bb(modti3(bb(2), bb(2))); -} - -#[cfg(all(feature = "c", not(thumb)))] -#[start] -fn main(_: isize, _: *const *const u8) -> isize { - run(); - - 0 -} - -#[cfg(all(not(feature = "c"), not(thumb)))] -#[start] -fn main(_: isize, _: *const *const u8) -> isize { - 0 -} - -#[cfg(all(feature = "c", thumb))] -#[no_mangle] -pub fn _start() -> ! { - run(); - loop {} -} - -#[cfg(all(not(feature = "c"), thumb))] -#[no_mangle] -pub fn _start() -> ! { - loop {} -} - -// ARM targets need these symbols -#[no_mangle] -pub fn __aeabi_unwind_cpp_pr0() {} - -#[no_mangle] -pub fn __aeabi_unwind_cpp_pr1() {} - -// Avoid "undefined reference to `_Unwind_Resume`" errors -#[allow(non_snake_case)] -#[no_mangle] -pub fn _Unwind_Resume() {} - -// Lang items -#[cfg(not(test))] -#[lang = "eh_personality"] -#[no_mangle] -extern "C" fn eh_personality() {} - -#[cfg(not(test))] -#[lang = "panic_fmt"] -#[no_mangle] -extern "C" fn panic_fmt() {} -- cgit 1.4.1-3-g733a5 From 32540055709d9bd657e07ff92e9087f5bbaf4d3e Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 5 May 2017 23:31:41 +0200 Subject: Rename float conversion macros to something nicer --- library/compiler-builtins/src/float/conv.rs | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index efe590ab43b..37aaa1cdab2 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -12,7 +12,7 @@ macro_rules! fp_overflow { } } -macro_rules! fp_convert { +macro_rules! int_to_float { ($intrinsic:ident: $ity:ty, $fty:ty) => { pub extern "C" fn $intrinsic(i: $ity) -> $fty { @@ -82,12 +82,12 @@ macro_rules! fp_convert { } } -fp_convert!(__floatsisf: i32, f32); -fp_convert!(__floatsidf: i32, f64); -fp_convert!(__floatdidf: i64, f64); -fp_convert!(__floatunsisf: u32, f32); -fp_convert!(__floatunsidf: u32, f64); -fp_convert!(__floatundidf: u64, f64); +int_to_float!(__floatsisf: i32, f32); +int_to_float!(__floatsidf: i32, f64); +int_to_float!(__floatdidf: i64, f64); +int_to_float!(__floatunsisf: u32, f32); +int_to_float!(__floatunsidf: u32, f64); +int_to_float!(__floatundidf: u64, f64); #[derive(PartialEq, Debug)] enum Sign { @@ -95,7 +95,7 @@ enum Sign { Negative } -macro_rules! fp_fix { +macro_rules! float_to_int { ($intrinsic:ident: $fty:ty, $ity:ty) => { pub extern "C" fn $intrinsic(f: $fty) -> $ity { let fixint_min = <$ity>::min_value(); @@ -147,12 +147,12 @@ macro_rules! fp_fix { } } -fp_fix!(__fixsfsi: f32, i32); -fp_fix!(__fixsfdi: f32, i64); -fp_fix!(__fixdfsi: f64, i32); -fp_fix!(__fixdfdi: f64, i64); +float_to_int!(__fixsfsi: f32, i32); +float_to_int!(__fixsfdi: f32, i64); +float_to_int!(__fixdfsi: f64, i32); +float_to_int!(__fixdfdi: f64, i64); -fp_fix!(__fixunssfsi: f32, u32); -fp_fix!(__fixunssfdi: f32, u64); -fp_fix!(__fixunsdfsi: f64, u32); -fp_fix!(__fixunsdfdi: f64, u64); +float_to_int!(__fixunssfsi: f32, u32); +float_to_int!(__fixunssfdi: f32, u64); +float_to_int!(__fixunsdfsi: f64, u32); +float_to_int!(__fixunsdfdi: f64, u64); -- cgit 1.4.1-3-g733a5 From 21db51b3f85280b1085ffff06b98214018258f48 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 00:42:59 +0200 Subject: Mark some float related intrinsics as implemented in README.md They have been implemented since --- library/compiler-builtins/README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 0810edf5bd1..2cd28d495ee 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -141,22 +141,22 @@ features = ["c"] - [x] divsi3.c - [ ] extendhfsf2.c - [ ] extendsfdf2.c -- [ ] fixdfdi.c -- [ ] fixdfsi.c -- [ ] fixsfdi.c -- [ ] fixsfsi.c -- [ ] fixunsdfdi.c -- [ ] fixunsdfsi.c -- [ ] fixunssfdi.c -- [ ] fixunssfsi.c -- [ ] floatdidf.c +- [x] fixdfdi.c +- [x] fixdfsi.c +- [x] fixsfdi.c +- [x] fixsfsi.c +- [x] fixunsdfdi.c +- [x] fixunsdfsi.c +- [x] fixunssfdi.c +- [x] fixunssfsi.c +- [x] floatdidf.c - [ ] floatdisf.c -- [ ] floatsidf.c -- [ ] floatsisf.c -- [ ] floatundidf.c +- [x] floatsidf.c +- [x] floatsisf.c +- [x] floatundidf.c - [ ] floatundisf.c -- [ ] floatunsidf.c -- [ ] floatunsisf.c +- [x] floatunsidf.c +- [x] floatunsisf.c - [ ] i386/ashldi3.S - [ ] i386/ashrdi3.S - [ ] i386/chkstk.S -- cgit 1.4.1-3-g733a5 From 7e5af82760db6ecc28f4ab52b3a8d3952b732c47 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 02:22:54 +0200 Subject: Add i128 <-> float conversion functions --- library/compiler-builtins/src/float/conv.rs | 36 +++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 37aaa1cdab2..3413812a5ac 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -14,8 +14,11 @@ macro_rules! fp_overflow { macro_rules! int_to_float { ($intrinsic:ident: $ity:ty, $fty:ty) => { + int_to_float!($intrinsic: $ity, $fty, "C"); + }; + ($intrinsic:ident: $ity:ty, $fty:ty, $abi:tt) => { - pub extern "C" fn $intrinsic(i: $ity) -> $fty { + pub extern $abi fn $intrinsic(i: $ity) -> $fty { if i == 0 { return 0.0 } @@ -82,12 +85,25 @@ macro_rules! int_to_float { } } +macro_rules! int_to_float_unadj_on_win { + ($intrinsic:ident: $ity:ty, $fty:ty) => { + #[cfg(all(windows, target_pointer_width="64"))] + int_to_float!($intrinsic: $ity, $fty, "unadjusted"); + #[cfg(not(all(windows, target_pointer_width="64")))] + int_to_float!($intrinsic: $ity, $fty, "C"); + }; +} + int_to_float!(__floatsisf: i32, f32); int_to_float!(__floatsidf: i32, f64); int_to_float!(__floatdidf: i64, f64); +int_to_float_unadj_on_win!(__floattisf: i128, f32); +int_to_float_unadj_on_win!(__floattidf: i128, f64); int_to_float!(__floatunsisf: u32, f32); int_to_float!(__floatunsidf: u32, f64); int_to_float!(__floatundidf: u64, f64); +int_to_float_unadj_on_win!(__floatuntisf: u128, f32); +int_to_float_unadj_on_win!(__floatuntidf: u128, f64); #[derive(PartialEq, Debug)] enum Sign { @@ -97,7 +113,10 @@ enum Sign { macro_rules! float_to_int { ($intrinsic:ident: $fty:ty, $ity:ty) => { - pub extern "C" fn $intrinsic(f: $fty) -> $ity { + float_to_int!($intrinsic: $fty, $ity, "C"); + }; + ($intrinsic:ident: $fty:ty, $ity:ty, $abi:tt) => { + pub extern $abi fn $intrinsic(f: $fty) -> $ity { let fixint_min = <$ity>::min_value(); let fixint_max = <$ity>::max_value(); let fixint_bits = <$ity>::bits() as usize; @@ -147,12 +166,25 @@ macro_rules! float_to_int { } } +macro_rules! float_to_int_unadj_on_win { + ($intrinsic:ident: $fty:ty, $ity:ty) => { + #[cfg(all(windows, target_pointer_width="64"))] + float_to_int!($intrinsic: $fty, $ity, "unadjusted"); + #[cfg(not(all(windows, target_pointer_width="64")))] + float_to_int!($intrinsic: $fty, $ity, "C"); + }; +} + float_to_int!(__fixsfsi: f32, i32); float_to_int!(__fixsfdi: f32, i64); +float_to_int_unadj_on_win!(__fixsfti: f32, i128); float_to_int!(__fixdfsi: f64, i32); float_to_int!(__fixdfdi: f64, i64); +float_to_int_unadj_on_win!(__fixdfti: f64, i128); float_to_int!(__fixunssfsi: f32, u32); float_to_int!(__fixunssfdi: f32, u64); +float_to_int_unadj_on_win!(__fixunssfti: f32, u128); float_to_int!(__fixunsdfsi: f64, u32); float_to_int!(__fixunsdfdi: f64, u64); +float_to_int_unadj_on_win!(__fixunsdfti: f64, u128); -- cgit 1.4.1-3-g733a5 From c8b5bb756c10dca567be643e4721dbf607aa2924 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 05:36:40 +0200 Subject: Use cast 0.2.1 for i128 support --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 59f6b404abd..3503438fc4f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,7 +5,7 @@ name = "compiler_builtins" version = "0.1.0" [build-dependencies] -cast = { version = "0.2.0", optional = true } +cast = { version = "0.2.1", features = ["x128"], optional = true } rand = { version = "0.3.15", optional = true } [build-dependencies.gcc] -- cgit 1.4.1-3-g733a5 From 7e072454110395e06fc802cd74e0bd339324f1c9 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 05:20:20 +0200 Subject: Implement tests for floattidf and floattisf --- library/compiler-builtins/build.rs | 136 ++++++++++++++++++++++++++- library/compiler-builtins/tests/floattidf.rs | 8 ++ library/compiler-builtins/tests/floattisf.rs | 8 ++ 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/tests/floattidf.rs create mode 100644 library/compiler-builtins/tests/floattisf.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index ac75e6ede88..bbe9dafa8d8 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -49,7 +49,7 @@ mod tests { use std::path::PathBuf; use std::{env, mem}; - use self::cast::{f32, f64, u32, u64, i32, i64}; + use self::cast::{f32, f64, u32, u64, u128, i32, i64, i128}; use self::rand::Rng; const NTESTS: usize = 10_000; @@ -81,6 +81,8 @@ mod tests { Floatdidf, Floatsidf, Floatsisf, + Floattisf, + Floattidf, Floatundidf, Floatunsidf, Floatunsisf, @@ -1536,6 +1538,138 @@ fn floatsisf() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Floattisf { + a: i128, + b: u32, // f32 + } + + impl TestCase for Floattisf { + fn name() -> &'static str { + "floattisf" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + Some( + Floattisf { + a, + b: to_u32(f32(a)), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floattisf; + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((i128,), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn floattisf() { + for &((a,), b) in TEST_CASES { + let b_ = __floattisf(a); + assert_eq!(((a,), b), ((a,), to_u32(b_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Floattidf { + a: i128, + b: u64, // f64 + } + + impl TestCase for Floattidf { + fn name() -> &'static str { + "floattidf" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + Some( + Floattidf { + a, + b: to_u64(f64(a)), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floattidf; + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((i128,), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn floattidf() { + for &((a,), b) in TEST_CASES { + let b_ = __floattidf(a); + assert_eq!(((a,), b), ((a,), to_u64(b_))); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Floatundidf { a: u64, diff --git a/library/compiler-builtins/tests/floattidf.rs b/library/compiler-builtins/tests/floattidf.rs new file mode 100644 index 00000000000..4e4f84ddb01 --- /dev/null +++ b/library/compiler-builtins/tests/floattidf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floattidf.rs")); diff --git a/library/compiler-builtins/tests/floattisf.rs b/library/compiler-builtins/tests/floattisf.rs new file mode 100644 index 00000000000..2a0657d3d00 --- /dev/null +++ b/library/compiler-builtins/tests/floattisf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floattisf.rs")); -- cgit 1.4.1-3-g733a5 From 390e1e99c9f1ccc19d864b18fd1dd553f6a91bb9 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 05:24:20 +0200 Subject: Implement tests for fixdfti and fixsfti --- library/compiler-builtins/build.rs | 124 +++++++++++++++++++++++++++++ library/compiler-builtins/tests/fixdfti.rs | 8 ++ library/compiler-builtins/tests/fixsfti.rs | 8 ++ 3 files changed, 140 insertions(+) create mode 100644 library/compiler-builtins/tests/fixdfti.rs create mode 100644 library/compiler-builtins/tests/fixsfti.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index bbe9dafa8d8..42f2b477155 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -74,6 +74,8 @@ mod tests { Fixdfsi, Fixsfdi, Fixsfsi, + Fixsfti, + Fixdfti, Fixunsdfdi, Fixunsdfsi, Fixunssfdi, @@ -1096,6 +1098,128 @@ fn fixsfdi() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Fixsfti { + a: u32, // f32 + b: i128, + } + + impl TestCase for Fixsfti { + fn name() -> &'static str { + "fixsfti" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + i128(a).ok().map(|b| Fixsfti { a: to_u32(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixsfti; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), i128)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixsfti() { + for &((a,), b) in TEST_CASES { + let b_ = __fixsfti(mk_f32(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixdfti { + a: u64, // f64 + b: i128, + } + + impl TestCase for Fixdfti { + fn name() -> &'static str { + "fixdfti" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + i128(a).ok().map(|b| Fixdfti { a: to_u64(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixdfti; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64,), i128)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixdfti() { + for &((a,), b) in TEST_CASES { + let b_ = __fixdfti(mk_f64(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Fixunsdfdi { a: u64, // f64 diff --git a/library/compiler-builtins/tests/fixdfti.rs b/library/compiler-builtins/tests/fixdfti.rs new file mode 100644 index 00000000000..5bae55e99f3 --- /dev/null +++ b/library/compiler-builtins/tests/fixdfti.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixdfti.rs")); diff --git a/library/compiler-builtins/tests/fixsfti.rs b/library/compiler-builtins/tests/fixsfti.rs new file mode 100644 index 00000000000..653157df26b --- /dev/null +++ b/library/compiler-builtins/tests/fixsfti.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixsfti.rs")); -- cgit 1.4.1-3-g733a5 From 273211c01b9c7cc912b5ee1f16c06f306ae2a0b6 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 05:28:40 +0200 Subject: Implement tests for fixunsdfti and fixunssfti --- library/compiler-builtins/build.rs | 124 ++++++++++++++++++++++++++ library/compiler-builtins/tests/fixunsdfti.rs | 8 ++ library/compiler-builtins/tests/fixunssfti.rs | 8 ++ 3 files changed, 140 insertions(+) create mode 100644 library/compiler-builtins/tests/fixunsdfti.rs create mode 100644 library/compiler-builtins/tests/fixunssfti.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 42f2b477155..7af47178a4c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -80,6 +80,8 @@ mod tests { Fixunsdfsi, Fixunssfdi, Fixunssfsi, + Fixunssfti, + Fixunsdfti, Floatdidf, Floatsidf, Floatsisf, @@ -1464,6 +1466,128 @@ fn fixunssfsi() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Fixunssfti { + a: u32, // f32 + b: u128, + } + + impl TestCase for Fixunssfti { + fn name() -> &'static str { + "fixunssfti" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + u128(a).ok().map(|b| Fixunssfti { a: to_u32(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixunssfti; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), u128)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixunssfti() { + for &((a,), b) in TEST_CASES { + let b_ = __fixunssfti(mk_f32(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixunsdfti { + a: u64, // f64 + b: u128, + } + + impl TestCase for Fixunsdfti { + fn name() -> &'static str { + "fixunsdfti" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + u128(a).ok().map(|b| Fixunsdfti { a: to_u64(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixunsdfti; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64,), u128)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixunsdfti() { + for &((a,), b) in TEST_CASES { + let b_ = __fixunsdfti(mk_f64(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Floatdidf { a: i64, diff --git a/library/compiler-builtins/tests/fixunsdfti.rs b/library/compiler-builtins/tests/fixunsdfti.rs new file mode 100644 index 00000000000..615e7b33b8d --- /dev/null +++ b/library/compiler-builtins/tests/fixunsdfti.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixunsdfti.rs")); diff --git a/library/compiler-builtins/tests/fixunssfti.rs b/library/compiler-builtins/tests/fixunssfti.rs new file mode 100644 index 00000000000..d67f9e794e0 --- /dev/null +++ b/library/compiler-builtins/tests/fixunssfti.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixunssfti.rs")); -- cgit 1.4.1-3-g733a5 From ee6be10895b00b35fd1f500ffbfd98e78b52cffd Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 05:32:51 +0200 Subject: Implement tests for floatuntidf and floatuntisf --- library/compiler-builtins/build.rs | 134 +++++++++++++++++++++++++ library/compiler-builtins/tests/floatuntidf.rs | 8 ++ library/compiler-builtins/tests/floatuntisf.rs | 8 ++ 3 files changed, 150 insertions(+) create mode 100644 library/compiler-builtins/tests/floatuntidf.rs create mode 100644 library/compiler-builtins/tests/floatuntisf.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 7af47178a4c..bcb7fbe0f30 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -90,6 +90,8 @@ mod tests { Floatundidf, Floatunsidf, Floatunsisf, + Floatuntisf, + Floatuntidf, // float/pow.rs Powidf2, @@ -2116,6 +2118,138 @@ fn floatunsisf() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Floatuntisf { + a: u128, + b: u32, // f32 + } + + impl TestCase for Floatuntisf { + fn name() -> &'static str { + "floatuntisf" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + Some( + Floatuntisf { + a, + b: to_u32(f32(a)), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatuntisf; + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u128,), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn floatuntisf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatuntisf(a); + assert_eq!(((a,), b), ((a,), to_u32(b_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Floatuntidf { + a: u128, + b: u64, // f64 + } + + impl TestCase for Floatuntidf { + fn name() -> &'static str { + "floatuntidf" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + Some( + Floatuntidf { + a, + b: to_u64(f64(a)), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatuntidf; + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u128,), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn floatuntidf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatuntidf(a); + assert_eq!(((a,), b), ((a,), to_u64(b_))); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Moddi3 { a: i64, diff --git a/library/compiler-builtins/tests/floatuntidf.rs b/library/compiler-builtins/tests/floatuntidf.rs new file mode 100644 index 00000000000..4ea272e97d1 --- /dev/null +++ b/library/compiler-builtins/tests/floatuntidf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatuntidf.rs")); diff --git a/library/compiler-builtins/tests/floatuntisf.rs b/library/compiler-builtins/tests/floatuntisf.rs new file mode 100644 index 00000000000..74cd853e49e --- /dev/null +++ b/library/compiler-builtins/tests/floatuntisf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatuntisf.rs")); -- cgit 1.4.1-3-g733a5 From 313d3bb49f794f1ca44dfdc060cc6c832660f9b7 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 15:29:43 +0200 Subject: Adjust for changed cast function --- library/compiler-builtins/build.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index bcb7fbe0f30..7c4135d745a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -2135,12 +2135,13 @@ fn floatunsisf() { Self: Sized, { let a = gen_u128(rng); - Some( + let f_a = f32(a); + f_a.ok().map(|f| { Floatuntisf { a, - b: to_u32(f32(a)), - }, - ) + b: to_u32(f), + } + }) } fn to_string(&self, buffer: &mut String) { -- cgit 1.4.1-3-g733a5 From 2aaaa38e25caf19a93b70f5be6a81b03bf9bfdc1 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 05:33:28 +0200 Subject: Mark the functions just implemented in README.md --- library/compiler-builtins/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 2cd28d495ee..5f59b44b1a8 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -196,14 +196,14 @@ These builtins are needed to support 128-bit integers, which are in the process - [x] ashlti3.c - [x] ashrti3.c - [x] divti3.c -- [ ] fixdfti.c -- [ ] fixsfti.c -- [ ] fixunsdfti.c -- [ ] fixunssfti.c -- [ ] floattidf.c -- [ ] floattisf.c -- [ ] floatuntidf.c -- [ ] floatuntisf.c +- [x] fixdfti.c +- [x] fixsfti.c +- [x] fixunsdfti.c +- [x] fixunssfti.c +- [x] floattidf.c +- [x] floattisf.c +- [x] floatuntidf.c +- [x] floatuntisf.c - [x] lshrti3.c - [x] modti3.c - [x] muloti4.c -- cgit 1.4.1-3-g733a5 From 31048e53b5a24dc690a584c5d3f31c5fe55b1851 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 05:34:50 +0200 Subject: Fix test name gotten wrong --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 7c4135d745a..ba8c5e0de7a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1092,7 +1092,7 @@ static TEST_CASES: &[((u32,), i32)] = &[ ]; #[test] -fn fixsfdi() { +fn fixsfsi() { for &((a,), b) in TEST_CASES { let b_ = __fixsfsi(mk_f32(a)); assert_eq!(((a,), b), ((a,), b_)); -- cgit 1.4.1-3-g733a5 From 197b7e6d97836201690668e794d1dc1f59ff8c67 Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 7 May 2017 03:03:58 +0200 Subject: Print generated files --- library/compiler-builtins/build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index ba8c5e0de7a..1ae8b41eab9 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -3934,7 +3934,9 @@ macro_rules! panic { let rng = &mut rand::thread_rng(); let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let out_file = out_dir.join(format!("{}.rs", T::name())); + let out_file_name = format!("{}.rs", T::name()); + let out_file = out_dir.join(&out_file_name); + println!("Generating {}", out_file_name); let contents = mk_tests::(NTESTS, rng); File::create(out_file) -- cgit 1.4.1-3-g733a5 From ddc95ea11c324c47186cb176674bfe0441b21a7c Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 8 May 2017 00:05:00 +0200 Subject: Update cast to 0.2.2 to fix bug in debug mode --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 3503438fc4f..e23c66605a8 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,7 +5,7 @@ name = "compiler_builtins" version = "0.1.0" [build-dependencies] -cast = { version = "0.2.1", features = ["x128"], optional = true } +cast = { version = "0.2.2", features = ["x128"], optional = true } rand = { version = "0.3.15", optional = true } [build-dependencies.gcc] -- cgit 1.4.1-3-g733a5 From 6eeab2e62f85bbf0f95d89c0c94f785231a19f23 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 8 May 2017 00:49:36 +0200 Subject: floattidf, floatuntidf: ignore differences smaller than 2 in test Its possible that the generated f64 is different from the expected one by one bit. This is legal when both values are equally close to the i128/u128. --- library/compiler-builtins/build.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 1ae8b41eab9..1b2aab149ba 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1913,7 +1913,8 @@ static TEST_CASES: &[((i128,), u64)] = &[ fn floattidf() { for &((a,), b) in TEST_CASES { let b_ = __floattidf(a); - assert_eq!(((a,), b), ((a,), to_u64(b_))); + let diff = if to_u64(b_) > b { to_u64(b_) - b } else { b - to_u64(b_) }; + assert_eq!(((a,), b, true), ((a,), b, diff <= 1)); } } " @@ -2244,7 +2245,8 @@ static TEST_CASES: &[((u128,), u64)] = &[ fn floatuntidf() { for &((a,), b) in TEST_CASES { let b_ = __floatuntidf(a); - assert_eq!(((a,), b), ((a,), to_u64(b_))); + let diff = if to_u64(b_) > b { to_u64(b_) - b } else { b - to_u64(b_) }; + assert_eq!(((a,), b, true), ((a,), b, diff <= 1)); } } " -- cgit 1.4.1-3-g733a5 From 915c2fd0d3abf822db468f7648785503552266c1 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 8 May 2017 04:03:16 +0200 Subject: Fix overflow bug when creating the absolute value Previously, the tests failed on some platforms due to it. --- library/compiler-builtins/src/int/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index a94a070ca06..768b6b4c18f 100755 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -63,7 +63,7 @@ macro_rules! int_impl { fn extract_sign(self) -> (bool, $uty) { if self < 0 { - (true, !(self as $uty) + 1) + (true, (!(self as $uty)).wrapping_add(1)) } else { (false, self as $uty) } -- cgit 1.4.1-3-g733a5 From 4c69bfaff4bb2307e02fe6913f8f8d74b07a5ec1 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 10 May 2017 02:41:29 +0200 Subject: Build.rs: better debug output --- library/compiler-builtins/build.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 1b2aab149ba..c8179fe9eb9 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1913,8 +1913,9 @@ static TEST_CASES: &[((i128,), u64)] = &[ fn floattidf() { for &((a,), b) in TEST_CASES { let b_ = __floattidf(a); - let diff = if to_u64(b_) > b { to_u64(b_) - b } else { b - to_u64(b_) }; - assert_eq!(((a,), b, true), ((a,), b, diff <= 1)); + let g_b = to_u64(b_); + let diff = if g_b > b { g_b - b } else { b - g_b }; + assert_eq!(((a,), b, g_b, true), ((a,), b, g_b, diff <= 1)); } } " @@ -2245,8 +2246,9 @@ static TEST_CASES: &[((u128,), u64)] = &[ fn floatuntidf() { for &((a,), b) in TEST_CASES { let b_ = __floatuntidf(a); - let diff = if to_u64(b_) > b { to_u64(b_) - b } else { b - to_u64(b_) }; - assert_eq!(((a,), b, true), ((a,), b, diff <= 1)); + let g_b = to_u64(b_); + let diff = if g_b > b { g_b - b } else { b - g_b }; + assert_eq!(((a,), b, g_b, true), ((a,), b, g_b, diff <= 1)); } } " -- cgit 1.4.1-3-g733a5 From 1b379a495d49e8bd0bac3f455e2a45dfaf799993 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 1 Jun 2017 07:40:50 -0500 Subject: remove unused macros to fix warnings --- library/compiler-builtins/src/float/conv.rs | 11 ----------- library/compiler-builtins/src/lib.rs | 15 --------------- 2 files changed, 26 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 3413812a5ac..8905f12fafa 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,17 +1,6 @@ use float::Float; use int::Int; -macro_rules! fp_overflow { - (infinity, $fty:ty, $sign: expr) => { - return { - <$fty as Float>::from_parts( - $sign, - <$fty as Float>::exponent_max() as <$fty as Float>::Int, - 0 as <$fty as Float>::Int) - } - } -} - macro_rules! int_to_float { ($intrinsic:ident: $ity:ty, $fty:ty) => { int_to_float!($intrinsic: $ity, $fty, "C"); diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 8c7820bf99b..03f7258d13e 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -78,21 +78,6 @@ macro_rules! urem { } } -macro_rules! srem { - ($sty:ty, $a:expr, $b:expr) => { - unsafe { - let a = $a; - let b = $b; - - if b == 0 || (b == -1 && a == $sty::min_value()) { - ::core::intrinsics::abort() - } else { - ::core::intrinsics::unchecked_rem(a, b) - } - } - } -} - // Hack for LLVM expectations for ABI on windows #[cfg(all(windows, target_pointer_width="64"))] #[repr(simd)] -- cgit 1.4.1-3-g733a5 From 0f2515b715f65f19ba46b5afaa4610e868517a32 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 14:00:31 -0700 Subject: Test with the 'c' feature enabled on CI --- library/compiler-builtins/Cargo.toml | 4 ++++ library/compiler-builtins/appveyor.yml | 4 +++- library/compiler-builtins/ci/run.sh | 2 ++ library/compiler-builtins/examples/intrinsics.rs | 25 ++++++------------------ 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index e23c66605a8..69b9c03c03d 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -27,5 +27,9 @@ utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japa utest-macros = { git = "https://github.com/japaric/utest" } +[[example]] +name = "intrinsics" +required-features = ["c"] + [workspace] diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index f5a4c62f04c..2bef109367c 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -5,7 +5,7 @@ environment: install: - git submodule update --init - - curl -sSf -o rustup-init.exe https://win.rustup.rs + - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init.exe --default-host x86_64-pc-windows-msvc --default-toolchain nightly -y - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - if "%TARGET%"=="i686-pc-windows-msvc" ( rustup target add %TARGET% ) @@ -18,4 +18,6 @@ test_script: - cargo build --target %TARGET% - cargo build --release --target %TARGET% - cargo test --no-default-features --features gen-tests --target %TARGET% + - cargo test --no-default-features --features "gen-tests c" --target %TARGET% - cargo test --no-default-features --features gen-tests --release --target %TARGET% + - cargo test --no-default-features --features "gen-tests c" --release --target %TARGET% diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 4a28e8a1894..02b9bf11248 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -34,7 +34,9 @@ case $1 in ;; *) cargo test --no-default-features --features gen-tests --target $1 + cargo test --no-default-features --features 'gen-tests c' --target $1 cargo test --no-default-features --features gen-tests --target $1 --release + cargo test --no-default-features --features 'gen-tests c' --target $1 --release ;; esac diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 4c5c8842bb9..4015ac318a2 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -6,17 +6,17 @@ #![allow(unused_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] +#![feature(alloc_system)] #![feature(asm)] #![feature(compiler_builtins_lib)] #![feature(core_float)] #![feature(lang_items)] -#![feature(libc)] #![feature(start)] #![feature(i128_type)] #![no_std] #[cfg(not(thumb))] -extern crate libc; +extern crate alloc_system; extern crate compiler_builtins; // NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even @@ -27,7 +27,6 @@ extern crate compiler_builtins; // convention for its intrinsics that's different from other architectures; that's why some function // have an additional comment: the function name is the ARM name for the intrinsic and the comment // in the non-ARM name for the intrinsic. -#[cfg(feature = "c")] mod intrinsics { use core::num::Float; @@ -339,7 +338,6 @@ mod intrinsics { } } -#[cfg(feature = "c")] fn run() { use intrinsics::*; @@ -404,33 +402,20 @@ fn run() { bb(modti3(bb(2), bb(2))); } -#[cfg(all(feature = "c", not(thumb)))] +#[cfg(not(thumb))] #[start] fn main(_: isize, _: *const *const u8) -> isize { run(); - - 0 -} - -#[cfg(all(not(feature = "c"), not(thumb)))] -#[start] -fn main(_: isize, _: *const *const u8) -> isize { 0 } -#[cfg(all(feature = "c", thumb))] +#[cfg(thumb)] #[no_mangle] pub fn _start() -> ! { run(); loop {} } -#[cfg(all(not(feature = "c"), thumb))] -#[no_mangle] -pub fn _start() -> ! { - loop {} -} - // ARM targets need these symbols #[no_mangle] pub fn __aeabi_unwind_cpp_pr0() {} @@ -447,9 +432,11 @@ pub fn _Unwind_Resume() {} #[cfg(not(test))] #[lang = "eh_personality"] #[no_mangle] +#[allow(private_no_mangle_fns)] extern "C" fn eh_personality() {} #[cfg(not(test))] #[lang = "panic_fmt"] #[no_mangle] +#[allow(private_no_mangle_fns)] extern "C" fn panic_fmt() {} -- cgit 1.4.1-3-g733a5 From bd4a416457b75b7d717ac7e3ebe71c39903d41e5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 22:03:07 -0700 Subject: Use traits instead of macros for shift intrinsics This is an attempt to tidy up the definition of intrinsics by making them more rust-like at the definition site and using traits instead of macros for the definition. Additionally the helper macro, `intrinsics!`, now fills in a definition for #[cfg]'d off intrinsics when compiling with C code --- library/compiler-builtins/src/int/mod.rs | 43 ++++++++-- library/compiler-builtins/src/int/shift.rs | 130 +++++++++++++++++------------ library/compiler-builtins/src/lib.rs | 3 + library/compiler-builtins/src/macros.rs | 51 +++++++++++ 4 files changed, 166 insertions(+), 61 deletions(-) create mode 100644 library/compiler-builtins/src/macros.rs diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 768b6b4c18f..11a31acee54 100755 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,3 +1,5 @@ +use core::ops; + macro_rules! hty { ($ty:ty) => { <$ty as LargeInt>::HighHalf @@ -16,15 +18,25 @@ pub mod shift; pub mod udiv; /// Trait for some basic operations on integers -pub trait Int { +pub trait Int: + Copy + + PartialEq + + ops::Shl + + ops::Shr + + ops::BitOr + + // ops::BitAnd + +{ /// Type with the same width but other signedness - type OtherSign; + type OtherSign: Int; /// Unsigned version of Self - type UnsignedInt; + type UnsignedInt: Int; /// Returns the bitwidth of the int type fn bits() -> u32; + /// Returns the zero representation of this number + fn zero() -> Self; + /// Extracts the sign from self and returns a tuple. /// /// # Examples @@ -36,6 +48,9 @@ pub trait Int { /// assert_eq!(u, 25_u32); /// ``` fn extract_sign(self) -> (bool, Self::UnsignedInt); + + /// Convert to a signed representation + fn unsigned(self) -> Self::UnsignedInt; } macro_rules! int_impl { @@ -44,6 +59,10 @@ macro_rules! int_impl { type OtherSign = $ity; type UnsignedInt = $uty; + fn zero() -> Self { + 0 + } + fn bits() -> u32 { $bits } @@ -51,6 +70,10 @@ macro_rules! int_impl { fn extract_sign(self) -> (bool, $uty) { (false, self) } + + fn unsigned(self) -> $uty { + self + } } impl Int for $ity { @@ -61,6 +84,10 @@ macro_rules! int_impl { $bits } + fn zero() -> Self { + 0 + } + fn extract_sign(self) -> (bool, $uty) { if self < 0 { (true, (!(self as $uty)).wrapping_add(1)) @@ -68,6 +95,10 @@ macro_rules! int_impl { (false, self as $uty) } } + + fn unsigned(self) -> $uty { + self as $uty + } } } } @@ -77,9 +108,9 @@ int_impl!(i64, u64, 64); int_impl!(i128, u128, 128); /// Trait to convert an integer to/from smaller parts -pub trait LargeInt { - type LowHalf; - type HighHalf; +pub trait LargeInt: Int { + type LowHalf: Int; + type HighHalf: Int; fn low(self) -> Self::LowHalf; fn high(self) -> Self::HighHalf; diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 8b5c4a16eaa..23a49acb907 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,74 +1,94 @@ use int::{Int, LargeInt}; -macro_rules! ashl { - ($intrinsic:ident: $ty:ty) => { - /// Returns `a << b`, requires `b < $ty::bits()` - #[cfg_attr(not(test), no_mangle)] - #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { - let half_bits = <$ty>::bits() / 2; - if b & half_bits != 0 { - <$ty>::from_parts(0, a.low() << (b - half_bits)) - } else if b == 0 { - a - } else { - <$ty>::from_parts(a.low() << b, (a.high() << b) | (a.low() >> (half_bits - b))) - } +trait Ashl: Int + LargeInt { + /// Returns `a << b`, requires `b < $ty::bits()` + fn ashl(self, offset: u32) -> Self + where Self: LargeInt::LowHalf>, + { + let half_bits = Self::bits() / 2; + if offset & half_bits != 0 { + Self::from_parts(Int::zero(), self.low() << (offset - half_bits)) + } else if offset == 0 { + self + } else { + Self::from_parts(self.low() << offset, + (self.high() << offset) | + (self.low() >> (half_bits - offset))) } } } -macro_rules! ashr { - ($intrinsic:ident: $ty:ty) => { - /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` - #[cfg_attr(not(test), no_mangle)] - #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { - let half_bits = <$ty>::bits() / 2; - if b & half_bits != 0 { - <$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf, - a.high() >> (half_bits - 1)) - } else if b == 0 { - a - } else { - let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf; - <$ty>::from_parts((high_unsigned << (half_bits - b)) | (a.low() >> b), - a.high() >> b) - } +impl Ashl for u64 {} +impl Ashl for u128 {} + +trait Ashr: Int + LargeInt { + /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` + fn ashr(self, offset: u32) -> Self + where Self: LargeInt::HighHalf as Int>::UnsignedInt>, + { + let half_bits = Self::bits() / 2; + if offset & half_bits != 0 { + Self::from_parts((self.high() >> (offset - half_bits)).unsigned(), + self.high() >> (half_bits - 1)) + } else if offset == 0 { + self + } else { + let high_unsigned = self.high().unsigned(); + Self::from_parts((high_unsigned << (half_bits - offset)) | (self.low() >> offset), + self.high() >> offset) } } } -macro_rules! lshr { - ($intrinsic:ident: $ty:ty) => { - /// Returns logical `a >> b`, requires `b < $ty::bits()` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { - let half_bits = <$ty>::bits() / 2; - if b & half_bits != 0 { - <$ty>::from_parts(a.high() >> (b - half_bits), 0) - } else if b == 0 { - a - } else { - <$ty>::from_parts((a.high() << (half_bits - b)) | (a.low() >> b), a.high() >> b) - } +impl Ashr for i64 {} +impl Ashr for i128 {} + +trait Lshr: Int + LargeInt { + /// Returns logical `a >> b`, requires `b < $ty::bits()` + fn lshr(self, offset: u32) -> Self + where Self: LargeInt::LowHalf>, + { + let half_bits = Self::bits() / 2; + if offset & half_bits != 0 { + Self::from_parts(self.high() >> (offset - half_bits), Int::zero()) + } else if offset == 0 { + self + } else { + Self::from_parts((self.high() << (half_bits - offset)) | + (self.low() >> offset), + self.high() >> offset) } } } -#[cfg(not(all(feature = "c", target_arch = "x86")))] -ashl!(__ashldi3: u64); +impl Lshr for u64 {} +impl Lshr for u128 {} -ashl!(__ashlti3: u128); +intrinsics! { + #[cfg(not(all(feature = "c", target_arch = "x86")))] + pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { + a.ashl(b) + } + + pub extern "C" fn __ashlti3(a: u128, b: u32) -> u128 { + a.ashl(b) + } -#[cfg(not(all(feature = "c", target_arch = "x86")))] -ashr!(__ashrdi3: i64); + #[cfg(not(all(feature = "c", target_arch = "x86")))] + pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { + a.ashr(b) + } -ashr!(__ashrti3: i128); + pub extern "C" fn __ashrti3(a: i128, b: u32) -> i128 { + a.ashr(b) + } -#[cfg(not(all(feature = "c", target_arch = "x86")))] -lshr!(__lshrdi3: u64); + #[cfg(not(all(feature = "c", target_arch = "x86")))] + pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { + a.lshr(b) + } -lshr!(__lshrti3: u128); + pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 { + a.lshr(b) + } +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 03f7258d13e..b1e739ffe1e 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -99,6 +99,9 @@ fn sconv(i: i128) -> U64x2 { #[cfg(test)] extern crate core; +#[macro_use] +mod macros; + pub mod int; pub mod float; diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs new file mode 100644 index 00000000000..a5a535bc56c --- /dev/null +++ b/library/compiler-builtins/src/macros.rs @@ -0,0 +1,51 @@ +macro_rules! intrinsics { + () => (); + ( + #[cfg(not(all(feature = "c", $($cfg_clause:tt)*)))] + $(#[$attr:meta])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + + #[cfg(all(feature = "c", not($($cfg_clause)*)))] + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + extern $abi { + fn $name($($argname: $ty),*) -> $ret; + } + unsafe { + $name($($argname),*) + } + } + + #[cfg(not(all(feature = "c", not($($cfg_clause)*))))] + intrinsics! { + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + ( + $(#[$attr:meta])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + $(#[$attr])* + #[cfg_attr(not(test), no_mangle)] + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + + intrinsics!($($rest)*); + ); +} -- cgit 1.4.1-3-g733a5 From 13d1c5ce1835e258c97599ed40e2d3af7eccfc92 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 22:04:40 -0700 Subject: Remove executable bit from mod.rs --- library/compiler-builtins/src/int/mod.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 library/compiler-builtins/src/int/mod.rs diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs old mode 100755 new mode 100644 -- cgit 1.4.1-3-g733a5 From 285a69b29cd4b2f40c954cffcc72c711c3291530 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 22:36:37 -0700 Subject: Port mul intrinsics to traits Also add a few features to the `intrinsics!` macro --- library/compiler-builtins/src/int/mod.rs | 68 +++++++++++++- library/compiler-builtins/src/int/mul.rs | 153 ++++++++++++++++--------------- library/compiler-builtins/src/macros.rs | 66 +++++++++++++ 3 files changed, 208 insertions(+), 79 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 11a31acee54..02e34129612 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -20,11 +20,19 @@ pub mod udiv; /// Trait for some basic operations on integers pub trait Int: Copy + - PartialEq + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::Add + + ops::Sub + + ops::Div + ops::Shl + ops::Shr + ops::BitOr + - // ops::BitAnd + + ops::BitXor + + ops::BitAnd + + ops::BitAndAssign + + ops::Not + { /// Type with the same width but other signedness type OtherSign: Int; @@ -34,8 +42,8 @@ pub trait Int: /// Returns the bitwidth of the int type fn bits() -> u32; - /// Returns the zero representation of this number fn zero() -> Self; + fn one() -> Self; /// Extracts the sign from self and returns a tuple. /// @@ -51,6 +59,12 @@ pub trait Int: /// Convert to a signed representation fn unsigned(self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn max_value() -> Self; + fn min_value() -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; } macro_rules! int_impl { @@ -63,6 +77,10 @@ macro_rules! int_impl { 0 } + fn one() -> Self { + 1 + } + fn bits() -> u32 { $bits } @@ -74,6 +92,22 @@ macro_rules! int_impl { fn unsigned(self) -> $uty { self } + + fn max_value() -> Self { + ::max_value() + } + + fn min_value() -> Self { + ::min_value() + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } } impl Int for $ity { @@ -88,6 +122,10 @@ macro_rules! int_impl { 0 } + fn one() -> Self { + 1 + } + fn extract_sign(self) -> (bool, $uty) { if self < 0 { (true, (!(self as $uty)).wrapping_add(1)) @@ -99,6 +137,22 @@ macro_rules! int_impl { fn unsigned(self) -> $uty { self as $uty } + + fn max_value() -> Self { + ::max_value() + } + + fn min_value() -> Self { + ::min_value() + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } } } } @@ -113,7 +167,9 @@ pub trait LargeInt: Int { type HighHalf: Int; fn low(self) -> Self::LowHalf; + fn low_as_high(low: Self::LowHalf) -> Self::HighHalf; fn high(self) -> Self::HighHalf; + fn high_as_low(low: Self::HighHalf) -> Self::LowHalf; fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; } @@ -126,9 +182,15 @@ macro_rules! large_int { fn low(self) -> $tylow { self as $tylow } + fn low_as_high(low: $tylow) -> $tyhigh { + low as $tyhigh + } fn high(self) -> $tyhigh { (self >> $halfbits) as $tyhigh } + fn high_as_low(high: $tyhigh) -> $tylow { + high as $tylow + } fn from_parts(low: $tylow, high: $tyhigh) -> $ty { low as $ty | ((high as $ty) << $halfbits) } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 5381eddea41..73f95a361da 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,95 +1,96 @@ +use core::ops; + use int::LargeInt; use int::Int; -macro_rules! mul { - ($(#[$attr:meta])+ | - $abi:tt, $intrinsic:ident: $ty:ty) => { - /// Returns `a * b` - $(#[$attr])+ - pub extern $abi fn $intrinsic(a: $ty, b: $ty) -> $ty { - let half_bits = <$ty>::bits() / 4; - let lower_mask = !0 >> half_bits; - let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask); - let mut t = low >> half_bits; - low &= lower_mask; - t += (a.low() >> half_bits).wrapping_mul(b.low() & lower_mask); - low += (t & lower_mask) << half_bits; - let mut high = (t >> half_bits) as hty!($ty); - t = low >> half_bits; - low &= lower_mask; - t += (b.low() >> half_bits).wrapping_mul(a.low() & lower_mask); - low += (t & lower_mask) << half_bits; - high += (t >> half_bits) as hty!($ty); - high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits) as hty!($ty); - high = high.wrapping_add(a.high().wrapping_mul(b.low() as hty!($ty))) - .wrapping_add((a.low() as hty!($ty)).wrapping_mul(b.high())); - <$ty>::from_parts(low, high) - } +trait Mul: LargeInt { + fn mul(self, other: Self) -> Self { + let half_bits = Self::bits() / 4; + let lower_mask = !<::LowHalf>::zero() >> half_bits; + let mut low = (self.low() & lower_mask).wrapping_mul(other.low() & lower_mask); + let mut t = low >> half_bits; + low &= lower_mask; + t += (self.low() >> half_bits).wrapping_mul(other.low() & lower_mask); + low += (t & lower_mask) << half_bits; + let mut high = Self::low_as_high(t >> half_bits); + t = low >> half_bits; + low &= lower_mask; + t += (other.low() >> half_bits).wrapping_mul(self.low() & lower_mask); + low += (t & lower_mask) << half_bits; + high += Self::low_as_high(t >> half_bits); + high += Self::low_as_high((self.low() >> half_bits).wrapping_mul(other.low() >> half_bits)); + high = high.wrapping_add(self.high().wrapping_mul(Self::low_as_high(other.low()))) + .wrapping_add(Self::low_as_high(self.low()).wrapping_mul(other.high())); + Self::from_parts(low, high) } } -macro_rules! mulo { - ($intrinsic:ident: $ty:ty) => { - // Default is "C" ABI - mulo!($intrinsic: $ty, "C"); - }; - ($intrinsic:ident: $ty:ty, $abi:tt) => { - /// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows - #[cfg_attr(not(test), no_mangle)] - pub extern $abi fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty { - *overflow = 0; - let result = a.wrapping_mul(b); - if a == <$ty>::min_value() { - if b != 0 && b != 1 { - *overflow = 1; - } - return result; +impl Mul for u64 {} +impl Mul for i128 {} + +trait Mulo: Int + ops::Neg { + fn mulo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = self.wrapping_mul(other); + if self == Self::min_value() { + if other != Self::zero() && other != Self::one() { + *overflow = 1; } - if b == <$ty>::min_value() { - if a != 0 && a != 1 { - *overflow = 1; - } - return result; + return result; + } + if other == Self::min_value() { + if self != Self::zero() && self != Self::one() { + *overflow = 1; } + return result; + } - let sa = a >> (<$ty>::bits() - 1); - let abs_a = (a ^ sa) - sa; - let sb = b >> (<$ty>::bits() - 1); - let abs_b = (b ^ sb) - sb; - if abs_a < 2 || abs_b < 2 { - return result; + let sa = self >> (Self::bits() - 1); + let abs_a = (self ^ sa) - sa; + let sb = other >> (Self::bits() - 1); + let abs_b = (other ^ sb) - sb; + let two = Self::one() + Self::one(); + if abs_a < two || abs_b < two { + return result; + } + if sa == sb { + if abs_a > Self::max_value() / abs_b { + *overflow = 1; } - if sa == sb { - if abs_a > <$ty>::max_value() / abs_b { - *overflow = 1; - } - } else { - if abs_a > <$ty>::min_value() / -abs_b { - *overflow = 1; - } + } else { + if abs_a > Self::min_value() / -abs_b { + *overflow = 1; } - result } + result } } -#[cfg(not(all(feature = "c", target_arch = "x86")))] -mul!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - | "C", __muldi3: u64); +impl Mulo for i32 {} +impl Mulo for i64 {} +impl Mulo for i128 {} -#[cfg(not(target_arch = "arm"))] -mul!(#[cfg_attr(not(test), no_mangle)] - | "C", __multi3: i128); +intrinsics! { + #[cfg(not(all(feature = "c", target_arch = "x86")))] + pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { + a.mul(b) + } -#[cfg(target_arch = "arm")] -mul!(#[cfg_attr(not(test), no_mangle)] - | "aapcs", __multi3: i128); + #[aapcs_on_arm] + pub extern "C" fn __multi3(a: i128, b: i128) -> i128 { + a.mul(b) + } + + pub extern "C" fn __mulosi4(a: i32, b: i32, oflow: &mut i32) -> i32 { + a.mulo(b, oflow) + } -mulo!(__mulosi4: i32); -mulo!(__mulodi4: i64); + pub extern "C" fn __mulodi4(a: i64, b: i64, oflow: &mut i32) -> i64 { + a.mulo(b, oflow) + } -#[cfg(all(windows, target_pointer_width="64"))] -mulo!(__muloti4: i128, "unadjusted"); -#[cfg(not(all(windows, target_pointer_width="64")))] -mulo!(__muloti4: i128); + #[unadjusted_on_win64] + pub extern "C" fn __muloti4(a: i128, b: i128, oflow: &mut i32) -> i128 { + a.mulo(b, oflow) + } +} diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index a5a535bc56c..c0c94b7db72 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,5 +1,10 @@ macro_rules! intrinsics { () => (); + + // Anything which has a `not(feature = "c")` we'll generate a shim function + // which calls out to the C function if the `c` feature is enabled. + // Otherwise if the `c` feature isn't enabled then we'll just have a normal + // intrinsic. ( #[cfg(not(all(feature = "c", $($cfg_clause:tt)*)))] $(#[$attr:meta])* @@ -32,6 +37,67 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // We recognize the `#[aapcs_only_on_arm]` attribute here and generate the + // same intrinsic but force it to have the `"aapcs"` calling convention on + // ARM and `"C"` elsewhere. + ( + #[aapcs_on_arm] + $(#[$attr:meta])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(target_arch = "arm")] + intrinsics! { + $(#[$attr])* + pub extern "aapcs" fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + #[cfg(not(target_arch = "arm"))] + intrinsics! { + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // Like aapcs above we recognize an attribute for the "unadjusted" abi on + // win64 for some methods. + ( + #[unadjusted_on_win64] + $(#[$attr:meta])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(all(windows, target_pointer_width = "64"))] + intrinsics! { + $(#[$attr])* + pub extern "unadjusted" fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + #[cfg(not(all(windows, target_pointer_width = "64")))] + intrinsics! { + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + ( $(#[$attr:meta])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { -- cgit 1.4.1-3-g733a5 From e80da4a48a8d02541bd2c221810ecfa002aa5626 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 23:09:28 -0700 Subject: Port sdiv to traits + `intrinsics!` Enhance `intrinsics!` along the way! --- library/compiler-builtins/src/int/mod.rs | 37 ++++++- library/compiler-builtins/src/int/mul.rs | 2 +- library/compiler-builtins/src/int/sdiv.rs | 165 ++++++++++++++--------------- library/compiler-builtins/src/int/shift.rs | 6 +- library/compiler-builtins/src/lib.rs | 4 + library/compiler-builtins/src/macros.rs | 59 ++++++++++- 6 files changed, 183 insertions(+), 90 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 02e34129612..9ad3d88852f 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -57,14 +57,17 @@ pub trait Int: /// ``` fn extract_sign(self) -> (bool, Self::UnsignedInt); - /// Convert to a signed representation fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; // copied from primitive integers, but put in a trait fn max_value() -> Self; fn min_value() -> Self; fn wrapping_add(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn checked_div(self, other: Self) -> Option; + fn checked_rem(self, other: Self) -> Option; } macro_rules! int_impl { @@ -93,6 +96,10 @@ macro_rules! int_impl { self } + fn from_unsigned(me: $uty) -> Self { + me + } + fn max_value() -> Self { ::max_value() } @@ -108,6 +115,18 @@ macro_rules! int_impl { fn wrapping_mul(self, other: Self) -> Self { ::wrapping_mul(self, other) } + + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn checked_div(self, other: Self) -> Option { + ::checked_div(self, other) + } + + fn checked_rem(self, other: Self) -> Option { + ::checked_rem(self, other) + } } impl Int for $ity { @@ -138,6 +157,10 @@ macro_rules! int_impl { self as $uty } + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + fn max_value() -> Self { ::max_value() } @@ -153,6 +176,18 @@ macro_rules! int_impl { fn wrapping_mul(self, other: Self) -> Self { ::wrapping_mul(self, other) } + + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn checked_div(self, other: Self) -> Option { + ::checked_div(self, other) + } + + fn checked_rem(self, other: Self) -> Option { + ::checked_rem(self, other) + } } } } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 73f95a361da..4b0831d8ee5 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -71,7 +71,7 @@ impl Mulo for i64 {} impl Mulo for i128 {} intrinsics! { - #[cfg(not(all(feature = "c", target_arch = "x86")))] + #[use_c_shim_if(target_arch = "x86")] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { a.mul(b) } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 557689814f6..310eb9f82fc 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,102 +1,101 @@ use int::Int; -macro_rules! div { - ($intrinsic:ident: $ty:ty, $uty:ty) => { - div!($intrinsic: $ty, $uty, $ty, |i| {i}); - }; - ($intrinsic:ident: $ty:ty, $uty:ty, $tyret:ty, $conv:expr) => { - /// Returns `a / b` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $tyret { - let s_a = a >> (<$ty>::bits() - 1); - let s_b = b >> (<$ty>::bits() - 1); - // NOTE it's OK to overflow here because of the `as $uty` cast below - // This whole operation is computing the absolute value of the inputs - // So some overflow will happen when dealing with e.g. `i64::MIN` - // where the absolute value is `(-i64::MIN) as u64` - let a = (a ^ s_a).wrapping_sub(s_a); - let b = (b ^ s_b).wrapping_sub(s_b); - let s = s_a ^ s_b; - - let r = udiv!(a as $uty, b as $uty); - ($conv)((r as $ty ^ s) - s) - } +trait Div: Int { + /// Returns `a / b` + fn div(self, other: Self) -> Self { + let s_a = self >> (Self::bits() - 1); + let s_b = other >> (Self::bits() - 1); + // NOTE it's OK to overflow here because of the `as $uty` cast below + // This whole operation is computing the absolute value of the inputs + // So some overflow will happen when dealing with e.g. `i64::MIN` + // where the absolute value is `(-i64::MIN) as u64` + let a = (self ^ s_a).wrapping_sub(s_a); + let b = (other ^ s_b).wrapping_sub(s_b); + let s = s_a ^ s_b; + + let r = a.unsigned().checked_div(b.unsigned()) + .unwrap_or_else(|| ::abort()); + (Self::from_unsigned(r) ^ s) - s } } -macro_rules! mod_ { - ($intrinsic:ident: $ty:ty, $uty:ty) => { - mod_!($intrinsic: $ty, $uty, $ty, |i| {i}); - }; - ($intrinsic:ident: $ty:ty, $uty:ty, $tyret:ty, $conv:expr) => { - /// Returns `a % b` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $tyret { - let s = b >> (<$ty>::bits() - 1); - // NOTE(wrapping_sub) see comment in the `div` macro - let b = (b ^ s).wrapping_sub(s); - let s = a >> (<$ty>::bits() - 1); - let a = (a ^ s).wrapping_sub(s); - - let r = urem!(a as $uty, b as $uty); - ($conv)((r as $ty ^ s) - s) - } +impl Div for i32 {} +impl Div for i64 {} +impl Div for i128 {} + +trait Mod: Int { + /// Returns `a % b` + fn mod_(self, other: Self) -> Self { + let s = other >> (Self::bits() - 1); + // NOTE(wrapping_sub) see comment in the `div` + let b = (other ^ s).wrapping_sub(s); + let s = self >> (Self::bits() - 1); + let a = (self ^ s).wrapping_sub(s); + + let r = a.unsigned().checked_rem(b.unsigned()) + .unwrap_or_else(|| ::abort()); + (Self::from_unsigned(r) ^ s) - s } } -macro_rules! divmod { - ($abi:tt, $intrinsic:ident, $div:ident: $ty:ty) => { - /// Returns `a / b` and sets `*rem = n % d` - #[cfg_attr(not(test), no_mangle)] - pub extern $abi fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty { - #[cfg(all(feature = "c", any(target_arch = "x86")))] - extern { - fn $div(a: $ty, b: $ty) -> $ty; - } - - let r = match () { - #[cfg(not(all(feature = "c", any(target_arch = "x86"))))] - () => $div(a, b), - #[cfg(all(feature = "c", any(target_arch = "x86")))] - () => unsafe { $div(a, b) }, - }; - // NOTE won't overflow because it's using the result from the - // previous division - *rem = a - r.wrapping_mul(b); - r - } +impl Mod for i32 {} +impl Mod for i64 {} +impl Mod for i128 {} + +trait Divmod: Int { + /// Returns `a / b` and sets `*rem = n % d` + fn divmod(self, other: Self, rem: &mut Self, div: F) -> Self + where F: Fn(Self, Self) -> Self, + { + let r = div(self, other); + // NOTE won't overflow because it's using the result from the + // previous division + *rem = self - r.wrapping_mul(other); + r } } -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] -div!(__divsi3: i32, u32); +impl Divmod for i32 {} +impl Divmod for i64 {} -#[cfg(not(all(feature = "c", target_arch = "x86")))] -div!(__divdi3: i64, u64); - -#[cfg(not(all(windows, target_pointer_width="64")))] -div!(__divti3: i128, u128); - -#[cfg(all(windows, target_pointer_width="64"))] -div!(__divti3: i128, u128, ::U64x2, ::sconv); +intrinsics! { + #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] + pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { + a.div(b) + } -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] -mod_!(__modsi3: i32, u32); + #[use_c_shim_if(target_arch = "x86")] + pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 { + a.div(b) + } -#[cfg(not(all(feature = "c", target_arch = "x86")))] -mod_!(__moddi3: i64, u64); + #[win64_128bit_abi_hack] + pub extern "C" fn __divti3(a: i128, b: i128) -> i128 { + a.div(b) + } -#[cfg(not(all(windows, target_pointer_width="64")))] -mod_!(__modti3: i128, u128); + #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios")))] + pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { + a.mod_(b) + } -#[cfg(all(windows, target_pointer_width="64"))] -mod_!(__modti3: i128, u128, ::U64x2, ::sconv); + #[use_c_shim_if(target_arch = "x86")] + pub extern "C" fn __moddi3(a: i64, b: i64) -> i64 { + a.mod_(b) + } -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] -divmod!("C", __divmodsi4, __divsi3: i32); + #[win64_128bit_abi_hack] + pub extern "C" fn __modti3(a: i128, b: i128) -> i128 { + a.mod_(b) + } -#[cfg(target_arch = "arm")] -divmod!("aapcs", __divmoddi4, __divdi3: i64); + #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios")))] + pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { + a.divmod(b, rem, |a, b| __divsi3(a, b)) + } -#[cfg(not(target_arch = "arm"))] -divmod!("C", __divmoddi4, __divdi3: i64); + #[aapcs_on_arm] + pub extern "C" fn __divmoddi4(a: i64, b: i64, rem: &mut i64) -> i64 { + a.divmod(b, rem, |a, b| __divdi3(a, b)) + } +} diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 23a49acb907..746d02ded8a 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -65,7 +65,7 @@ impl Lshr for u64 {} impl Lshr for u128 {} intrinsics! { - #[cfg(not(all(feature = "c", target_arch = "x86")))] + #[use_c_shim_if(target_arch = "x86")] pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { a.ashl(b) } @@ -74,7 +74,7 @@ intrinsics! { a.ashl(b) } - #[cfg(not(all(feature = "c", target_arch = "x86")))] + #[use_c_shim_if(target_arch = "x86")] pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { a.ashr(b) } @@ -83,7 +83,7 @@ intrinsics! { a.ashr(b) } - #[cfg(not(all(feature = "c", target_arch = "x86")))] + #[use_c_shim_if(target_arch = "x86")] pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { a.lshr(b) } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index b1e739ffe1e..a55752a68ed 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -99,6 +99,10 @@ fn sconv(i: i128) -> U64x2 { #[cfg(test)] extern crate core; +fn abort() -> ! { + unsafe { core::intrinsics::abort() } +} + #[macro_use] mod macros; diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index c0c94b7db72..5c987740701 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -6,7 +6,7 @@ macro_rules! intrinsics { // Otherwise if the `c` feature isn't enabled then we'll just have a normal // intrinsic. ( - #[cfg(not(all(feature = "c", $($cfg_clause:tt)*)))] + #[use_c_shim_if($($cfg_clause:tt)*)] $(#[$attr:meta])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { $($body:tt)* @@ -37,7 +37,7 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // We recognize the `#[aapcs_only_on_arm]` attribute here and generate the + // We recognize the `#[aapcs_on_arm]` attribute here and generate the // same intrinsic but force it to have the `"aapcs"` calling convention on // ARM and `"C"` elsewhere. ( @@ -98,6 +98,39 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // Another attribute we recognize is an "abi hack" for win64 to get the 128 + // bit calling convention correct. + ( + #[win64_128bit_abi_hack] + $(#[$attr:meta])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(all(windows, target_pointer_width = "64"))] + intrinsics! { + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) + -> ::macros::win64_abi_hack::U64x2 + { + let e: $ret = { $($body)* }; + ::macros::win64_abi_hack::U64x2::from(e) + } + } + + #[cfg(not(all(windows, target_pointer_width = "64")))] + intrinsics! { + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + ( $(#[$attr:meta])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { @@ -115,3 +148,25 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); } + +// Hack for LLVM expectations for ABI on windows +#[cfg(all(windows, target_pointer_width="64"))] +pub mod win64_abi_hack { + #[repr(simd)] + pub struct U64x2(u64, u64); + + impl From for U64x2 { + fn from(i: i128) -> U64x2 { + use int::LargeInt; + let j = i as u128; + U64x2(j.low(), j.high()) + } + } + + impl From for U64x2 { + fn from(i: u128) -> U64x2 { + use int::LargeInt; + U64x2(i.low(), i.high()) + } + } +} -- cgit 1.4.1-3-g733a5 From dd059dd1fc724428c4d75d991f2921875c1d000c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 23:23:36 -0700 Subject: Port udiv to the `intrinsics!` macro --- library/compiler-builtins/src/int/udiv.rs | 268 +++++++++++++----------------- 1 file changed, 112 insertions(+), 156 deletions(-) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index e8db7460125..5ef46dec421 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,140 +1,6 @@ use core::intrinsics; -use int::{Int, LargeInt}; - -/// Returns `n / d` -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] -#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] -#[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] -pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { - // Special cases - if d == 0 { - // NOTE This should be unreachable in safe Rust because the program will panic before - // this intrinsic is called - unsafe { - intrinsics::abort() - } - } - - if n == 0 { - return 0; - } - - let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); - - // d > n - if sr > u32::bits() - 1 { - return 0; - } - - // d == 1 - if sr == u32::bits() - 1 { - return n; - } - - sr += 1; - - // 1 <= sr <= u32::bits() - 1 - let mut q = n << (u32::bits() - sr); - let mut r = n >> sr; - - let mut carry = 0; - for _ in 0..sr { - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (u32::bits() - 1)); - q = (q << 1) | carry; - - // carry = 0; - // if r > d { - // r -= d; - // carry = 1; - // } - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::bits() - 1); - carry = (s & 1) as u32; - r -= d & s as u32; - } - - (q << 1) | carry -} - -/// Returns `n % d` -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { - #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] - extern "C" { - fn __udivsi3(n: u32, d: u32) -> u32; - } - - let q = match () { - #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] - () => unsafe { __udivsi3(n, d) }, - #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] - () => __udivsi3(n, d), - }; - - n - q * d -} - -/// Returns `n / d` and sets `*rem = n % d` -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { - #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] - extern "C" { - fn __udivsi3(n: u32, d: u32) -> u32; - } - - let q = match () { - #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] - () => unsafe { __udivsi3(n, d) }, - #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] - () => __udivsi3(n, d), - }; - if let Some(rem) = rem { - *rem = n - (q * d); - } - q -} - -macro_rules! div_mod_intrinsics { - ($udiv_intr:ident, $umod_intr:ident : $ty:ty) => { - div_mod_intrinsics!($udiv_intr, $umod_intr : $ty, - __udivmoddi4); - }; - ($udiv_intr:ident, $umod_intr:ident : $ty:ty, $divmod_intr:expr) => { - div_mod_intrinsics!($udiv_intr, $umod_intr : $ty, - $divmod_intr, $ty, |i|{ i }); - }; - ($udiv_intr:ident, $umod_intr:ident : $ty:ty, $divmod_intr:expr, - $tyret:ty, $conv:expr) => { - /// Returns `n / d` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $udiv_intr(n: $ty, d: $ty) -> $tyret { - let r = $divmod_intr(n, d, None); - ($conv)(r) - } - - /// Returns `n % d` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $umod_intr(a: $ty, b: $ty) -> $tyret { - use core::mem; - - let mut rem = unsafe { mem::uninitialized() }; - $divmod_intr(a, b, Some(&mut rem)); - ($conv)(rem) - } - } -} - -#[cfg(not(all(feature = "c", target_arch = "x86")))] -div_mod_intrinsics!(__udivdi3, __umoddi3: u64); - -#[cfg(not(all(windows, target_pointer_width="64")))] -div_mod_intrinsics!(__udivti3, __umodti3: u128, u128_div_mod); - -#[cfg(all(windows, target_pointer_width="64"))] -div_mod_intrinsics!(__udivti3, __umodti3: u128, u128_div_mod, ::U64x2, ::conv); +use int::{Int, LargeInt}; macro_rules! udivmod_inner { ($n:expr, $d:expr, $rem:expr, $ty:ty) => {{ @@ -285,30 +151,120 @@ macro_rules! udivmod_inner { }} } -/// Returns `n / d` and sets `*rem = n % d` -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { - udivmod_inner!(n, d, rem, u64) -} +intrinsics! { + #[use_c_shim_if(all(target_arch = "arm", + not(target_os = "ios"), + not(thumbv6m)))] + /// Returns `n / d` + pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { + // Special cases + if d == 0 { + // NOTE This should be unreachable in safe Rust because the program will panic before + // this intrinsic is called + unsafe { + intrinsics::abort() + } + } + + if n == 0 { + return 0; + } + + let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); + + // d > n + if sr > u32::bits() - 1 { + return 0; + } + + // d == 1 + if sr == u32::bits() - 1 { + return n; + } + + sr += 1; + + // 1 <= sr <= u32::bits() - 1 + let mut q = n << (u32::bits() - sr); + let mut r = n >> sr; + + let mut carry = 0; + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (u32::bits() - 1)); + q = (q << 1) | carry; + + // carry = 0; + // if r > d { + // r -= d; + // carry = 1; + // } -macro_rules! udivmodti4 { - ($tyret:ty, $conv:expr) => { - /// Returns `n / d` and sets `*rem = n % d` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> $tyret { - let r = u128_div_mod(n, d, rem); - ($conv)(r) + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::bits() - 1); + carry = (s & 1) as u32; + r -= d & s as u32; } + + (q << 1) | carry } -} -/// Returns `n / d` and sets `*rem = n % d` -fn u128_div_mod(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { - udivmod_inner!(n, d, rem, u128) -} + #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios")))] + /// Returns `n % d` + pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { + let q = __udivsi3(n, d); + n - q * d + } + + #[use_c_shim_if(all(target_arch = "arm", + not(target_os = "ios"), + not(thumbv6m)))] + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { + let q = __udivsi3(n, d); + if let Some(rem) = rem { + *rem = n - (q * d); + } + q + } -#[cfg(all(windows, target_pointer_width="64"))] -udivmodti4!(::U64x2, ::conv); + #[use_c_shim_if(target_arch = "x86")] + /// Returns `n / d` + pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { + __udivmoddi4(n, d, None) + } -#[cfg(not(all(windows, target_pointer_width="64")))] -udivmodti4!(u128, |i|{ i }); + #[use_c_shim_if(target_arch = "x86")] + /// Returns `n % d` + pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { + let mut rem = 0; + __udivmoddi4(n, d, Some(&mut rem)); + rem + } + + #[win64_128bit_abi_hack] + /// Returns `n / d` + pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { + __udivmodti4(n, d, None) + } + + #[win64_128bit_abi_hack] + /// Returns `n % d` + pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { + let mut rem = 0; + __udivmodti4(n, d, Some(&mut rem)); + rem + } + + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { + udivmod_inner!(n, d, rem, u64) + } + + #[win64_128bit_abi_hack] + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __udivmodti4(n: u128, + d: u128, + rem: Option<&mut u128>) -> u128 { + udivmod_inner!(n, d, rem, u128) + } +} -- cgit 1.4.1-3-g733a5 From 0d1138fad343291f4ea2e527904408d8a98a7694 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 23:36:50 -0700 Subject: Fix the abi hack on windows --- library/compiler-builtins/src/lib.rs | 18 ------------------ library/compiler-builtins/src/macros.rs | 22 +++++++++++++++------- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index a55752a68ed..6d44fb1a185 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -78,24 +78,6 @@ macro_rules! urem { } } -// Hack for LLVM expectations for ABI on windows -#[cfg(all(windows, target_pointer_width="64"))] -#[repr(simd)] -pub struct U64x2(u64, u64); - -#[cfg(all(windows, target_pointer_width="64"))] -fn conv(i: u128) -> U64x2 { - use int::LargeInt; - U64x2(i.low(), i.high()) -} - -#[cfg(all(windows, target_pointer_width="64"))] -fn sconv(i: i128) -> U64x2 { - use int::LargeInt; - let j = i as u128; - U64x2(j.low(), j.high()) -} - #[cfg(test)] extern crate core; diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 5c987740701..70e44da59c1 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -110,13 +110,21 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg(all(windows, target_pointer_width = "64"))] - intrinsics! { - $(#[$attr])* - pub extern $abi fn $name( $($argname: $ty),* ) - -> ::macros::win64_abi_hack::U64x2 - { - let e: $ret = { $($body)* }; - ::macros::win64_abi_hack::U64x2::from(e) + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + + #[cfg(all(windows, target_pointer_width = "64"))] + pub mod $name { + + intrinsics! { + pub extern $abi fn $name( $($argname: $ty),* ) + -> ::macros::win64_abi_hack::U64x2 + { + let e: $ret = super::$name($($argname),*); + ::macros::win64_abi_hack::U64x2::from(e) + } } } -- cgit 1.4.1-3-g733a5 From 107cbd36a0c1e074ef69a76272ff8affc68824d9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 23:41:28 -0700 Subject: Try to fix linkage on windows --- library/compiler-builtins/examples/intrinsics.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 4015ac318a2..5336422a39a 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -416,6 +416,10 @@ pub fn _start() -> ! { loop {} } +#[cfg(windows)] +#[link(name = "kernel32")] +extern {} + // ARM targets need these symbols #[no_mangle] pub fn __aeabi_unwind_cpp_pr0() {} -- cgit 1.4.1-3-g733a5 From e892808fddf398d9120aee84d547fd0726acb3d2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 23:44:27 -0700 Subject: Test 64-bit linux --- library/compiler-builtins/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 108b12a014f..fa9a27866af 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -28,7 +28,7 @@ matrix: - env: TARGET=thumbv7m-linux-eabi - env: TARGET=x86_64-apple-darwin os: osx -env: TARGET=x86_64-unknown-linux-gnu + - env: TARGET=x86_64-unknown-linux-gnu before_install: - test "$TRAVIS_OS_NAME" = "osx" || docker run --rm --privileged multiarch/qemu-user-static:register -- cgit 1.4.1-3-g733a5 From 1740b0b0f5701eacb059f533d021aa90f18f9c0a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 06:53:09 -0700 Subject: More windows linkage guesses --- library/compiler-builtins/examples/intrinsics.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 5336422a39a..cabe917641f 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -418,6 +418,7 @@ pub fn _start() -> ! { #[cfg(windows)] #[link(name = "kernel32")] +#[link(name = "msvcrt")] extern {} // ARM targets need these symbols -- cgit 1.4.1-3-g733a5 From 0aead6b3d843d962bf4c57331dc86ea582541fec Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 06:58:05 -0700 Subject: Require the `compiler-builtins` target for the example --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 69b9c03c03d..08bf5fd02f7 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -29,7 +29,7 @@ utest-macros = { git = "https://github.com/japaric/utest" } [[example]] name = "intrinsics" -required-features = ["c"] +required-features = ["c", "compiler-builtins"] [workspace] -- cgit 1.4.1-3-g733a5 From 48c4569e9172d2ad434901287283d5d15bf301c5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 07:01:18 -0700 Subject: Build the intrinsics example separately --- library/compiler-builtins/appveyor.yml | 4 ++-- library/compiler-builtins/ci/run.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 2bef109367c..66cd96e48ea 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -15,8 +15,8 @@ install: build: false test_script: - - cargo build --target %TARGET% - - cargo build --release --target %TARGET% + - cargo build --target %TARGET% --example intrinsics + - cargo build --release --target %TARGET% --example intrinsics - cargo test --no-default-features --features gen-tests --target %TARGET% - cargo test --no-default-features --features "gen-tests c" --target %TARGET% - cargo test --no-default-features --features gen-tests --release --target %TARGET% diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 02b9bf11248..0d52e730712 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -46,7 +46,7 @@ case $1 in xargo build --features c --target $1 --example intrinsics ;; *) - cargo build --no-default-features --features c --target $1 --example intrinsics + cargo build --features c --target $1 --example intrinsics ;; esac -- cgit 1.4.1-3-g733a5 From b6497f5283bbb01a09e1cb36088d20cd2f09be11 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 07:36:08 -0700 Subject: Build tweaks --- library/compiler-builtins/appveyor.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 66cd96e48ea..2dce7ceb6df 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -15,8 +15,10 @@ install: build: false test_script: - - cargo build --target %TARGET% --example intrinsics - - cargo build --release --target %TARGET% --example intrinsics + - cargo build --target %TARGET% + - cargo build --target %TARGET% --features c --example intrinsics + - cargo build --release --target %TARGET% + - cargo build --release --target %TARGET% --features c --example intrinsics - cargo test --no-default-features --features gen-tests --target %TARGET% - cargo test --no-default-features --features "gen-tests c" --target %TARGET% - cargo test --no-default-features --features gen-tests --release --target %TARGET% -- cgit 1.4.1-3-g733a5 From 5a36c4b54bbb6d7a8752ca0a8c14df3bf4e8b369 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 07:52:38 -0700 Subject: Use more intrinsics on msvc --- library/compiler-builtins/src/int/mul.rs | 2 +- library/compiler-builtins/src/int/sdiv.rs | 4 ++-- library/compiler-builtins/src/int/shift.rs | 6 +++--- library/compiler-builtins/src/int/udiv.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 4b0831d8ee5..cb3fbd620bf 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -71,7 +71,7 @@ impl Mulo for i64 {} impl Mulo for i128 {} intrinsics! { - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { a.mul(b) } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 310eb9f82fc..8d856303755 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -64,7 +64,7 @@ intrinsics! { a.div(b) } - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 { a.div(b) } @@ -79,7 +79,7 @@ intrinsics! { a.mod_(b) } - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] pub extern "C" fn __moddi3(a: i64, b: i64) -> i64 { a.mod_(b) } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 746d02ded8a..b0103ceaf20 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -65,7 +65,7 @@ impl Lshr for u64 {} impl Lshr for u128 {} intrinsics! { - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { a.ashl(b) } @@ -74,7 +74,7 @@ intrinsics! { a.ashl(b) } - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { a.ashr(b) } @@ -83,7 +83,7 @@ intrinsics! { a.ashr(b) } - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { a.lshr(b) } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 5ef46dec421..77e9c3f42a6 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -227,13 +227,13 @@ intrinsics! { q } - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] /// Returns `n / d` pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { __udivmoddi4(n, d, None) } - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] /// Returns `n % d` pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { let mut rem = 0; -- cgit 1.4.1-3-g733a5 From 57b8dd1812f6e97844dce891cf696241d3d60322 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 07:54:31 -0700 Subject: Fix use_c_shim_if --- library/compiler-builtins/src/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 70e44da59c1..740eae29385 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -15,7 +15,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(feature = "c", not($($cfg_clause)*)))] + #[cfg(all(feature = "c", $($cfg_clause)*))] $(#[$attr])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { extern $abi { @@ -26,7 +26,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(feature = "c", not($($cfg_clause)*))))] + #[cfg(not(all(feature = "c", $($cfg_clause)*)))] intrinsics! { $(#[$attr])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { -- cgit 1.4.1-3-g733a5 From 43bb211be8467cdf55cbb82116e2db17aaa13799 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 08:19:11 -0700 Subject: Fix travis intrinsics builds --- library/compiler-builtins/ci/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 0d52e730712..0f25a533f5c 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -54,11 +54,11 @@ esac # TODO(#79) fix the undefined references problem for debug-assertions+lto case $1 in thumb*) - RUSTFLAGS="-C debug-assertions=no" xargo rustc --no-default-features --features c --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles + RUSTFLAGS="-C debug-assertions=no" xargo rustc --features c --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles xargo rustc --no-default-features --features c --target $1 --example intrinsics --release -- -C lto ;; *) - RUSTFLAGS="-C debug-assertions=no" cargo rustc --no-default-features --features c --target $1 --example intrinsics -- -C lto + RUSTFLAGS="-C debug-assertions=no" cargo rustc --features c --target $1 --example intrinsics -- -C lto cargo rustc --no-default-features --features c --target $1 --example intrinsics --release -- -C lto ;; esac -- cgit 1.4.1-3-g733a5 From b6a4de6be55a3cfc5b3d13c110dc1079a49f902e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 08:35:24 -0700 Subject: Fix features needed for the intrinsics example --- library/compiler-builtins/ci/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 0f25a533f5c..8ac8845c922 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -55,11 +55,11 @@ esac case $1 in thumb*) RUSTFLAGS="-C debug-assertions=no" xargo rustc --features c --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles - xargo rustc --no-default-features --features c --target $1 --example intrinsics --release -- -C lto + xargo rustc --features c --target $1 --example intrinsics --release -- -C lto ;; *) RUSTFLAGS="-C debug-assertions=no" cargo rustc --features c --target $1 --example intrinsics -- -C lto - cargo rustc --no-default-features --features c --target $1 --example intrinsics --release -- -C lto + cargo rustc --features c --target $1 --example intrinsics --release -- -C lto ;; esac -- cgit 1.4.1-3-g733a5 From e798d1bf8163203ebbd7d4d22816020588a07d93 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 09:59:49 -0700 Subject: Enable `mem` for intrinsics on linux --- library/compiler-builtins/ci/run.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 8ac8845c922..6977455c72b 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -43,10 +43,10 @@ esac # Verify that we haven't drop any intrinsic/symbol case $1 in thumb*) - xargo build --features c --target $1 --example intrinsics + xargo build --features 'c mem' --target $1 --example intrinsics ;; *) - cargo build --features c --target $1 --example intrinsics + cargo build --features 'c mem' --target $1 --example intrinsics ;; esac @@ -54,12 +54,12 @@ esac # TODO(#79) fix the undefined references problem for debug-assertions+lto case $1 in thumb*) - RUSTFLAGS="-C debug-assertions=no" xargo rustc --features c --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles - xargo rustc --features c --target $1 --example intrinsics --release -- -C lto + RUSTFLAGS="-C debug-assertions=no" xargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles + xargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto ;; *) - RUSTFLAGS="-C debug-assertions=no" cargo rustc --features c --target $1 --example intrinsics -- -C lto - cargo rustc --features c --target $1 --example intrinsics --release -- -C lto + RUSTFLAGS="-C debug-assertions=no" cargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto + cargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto ;; esac -- cgit 1.4.1-3-g733a5 From e8d550ee512c06b7abe85d565b57e7d75d8ce182 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 10:44:29 -0700 Subject: Less verbose output on symbol check --- library/compiler-builtins/ci/run.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 6977455c72b..e5c89247dd7 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -77,7 +77,7 @@ case $1 in ;; esac -case $TRAVIS_OS_NAME in +case "$TRAVIS_OS_NAME" in osx) # NOTE OSx's nm doesn't accept the `--defined-only` or provide an equivalent. # Use GNU nm instead @@ -89,14 +89,15 @@ case $TRAVIS_OS_NAME in ;; esac -if [ $TRAVIS_OS_NAME = osx ]; then +if [ "$TRAVIS_OS_NAME" = osx ]; then path=target/${1}/debug/deps/libcompiler_builtins-*.rlib else path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib fi for rlib in $(echo $path); do - stdout=$($PREFIX$NM -g --defined-only $rlib) + set +x + stdout=$($PREFIX$NM -g --defined-only $rlib 2>&1) # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it set +e @@ -105,6 +106,7 @@ for rlib in $(echo $path); do if test $? = 0; then exit 1 fi + set -ex done true -- cgit 1.4.1-3-g733a5 From c53d1c7b7deb7ea430cfe78636e65df6622a0036 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 10:44:59 -0700 Subject: Remove executable bit from conv.rs --- library/compiler-builtins/src/float/conv.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 library/compiler-builtins/src/float/conv.rs diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs old mode 100755 new mode 100644 -- cgit 1.4.1-3-g733a5 From bf2f5b5808f9fc00aec0d7baebf8479851e4dbd9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 11:05:25 -0700 Subject: Convert float intrinsics to the `intrinsics!` macro --- library/compiler-builtins/src/float/add.rs | 324 ++++++++++++++-------------- library/compiler-builtins/src/float/conv.rs | 238 ++++++++++++-------- library/compiler-builtins/src/float/pow.rs | 52 ++--- library/compiler-builtins/src/float/sub.rs | 23 +- library/compiler-builtins/src/int/udiv.rs | 22 +- library/compiler-builtins/src/lib.rs | 46 ---- 6 files changed, 349 insertions(+), 356 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 5024a728b04..1b1ac3f0087 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -3,192 +3,190 @@ use core::num::Wrapping; use float::Float; +/// Returns `a + b` macro_rules! add { - ($abi:tt, $intrinsic:ident: $ty:ty) => { - /// Returns `a + b` - #[allow(unused_parens)] - #[cfg_attr(not(test), no_mangle)] - pub extern $abi fn $intrinsic(a: $ty, b: $ty) -> $ty { - let one = Wrapping(1 as <$ty as Float>::Int); - let zero = Wrapping(0 as <$ty as Float>::Int); - - let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); - let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); - let exponent_bits = bits - significand_bits - one; - let max_exponent = (one << exponent_bits.0 as usize) - one; - - let implicit_bit = one << significand_bits.0 as usize; - let significand_mask = implicit_bit - one; - let sign_bit = one << (significand_bits + exponent_bits).0 as usize; - let abs_mask = sign_bit - one; - let exponent_mask = abs_mask ^ significand_mask; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; - - let mut a_rep = Wrapping(a.repr()); - let mut b_rep = Wrapping(b.repr()); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; - - // Detect if a or b is zero, infinity, or NaN. - if a_abs - one >= inf_rep - one || - b_abs - one >= inf_rep - one { - // NaN + anything = qNaN - if a_abs > inf_rep { - return (<$ty as Float>::from_repr((a_abs | quiet_bit).0)); - } - // anything + NaN = qNaN - if b_abs > inf_rep { - return (<$ty as Float>::from_repr((b_abs | quiet_bit).0)); - } - - if a_abs == inf_rep { - // +/-infinity + -/+infinity = qNaN - if (a.repr() ^ b.repr()) == sign_bit.0 { - return (<$ty as Float>::from_repr(qnan_rep.0)); - } else { - // +/-infinity + anything remaining = +/- infinity - return a; - } - } + ($a:expr, $b:expr, $ty:ty) => ({ + let a = $a; + let b = $b; + let one = Wrapping(1 as <$ty as Float>::Int); + let zero = Wrapping(0 as <$ty as Float>::Int); + + let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); + let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); + let exponent_bits = bits - significand_bits - one; + let max_exponent = (one << exponent_bits.0 as usize) - one; + + let implicit_bit = one << significand_bits.0 as usize; + let significand_mask = implicit_bit - one; + let sign_bit = one << (significand_bits + exponent_bits).0 as usize; + let abs_mask = sign_bit - one; + let exponent_mask = abs_mask ^ significand_mask; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + + let mut a_rep = Wrapping(a.repr()); + let mut b_rep = Wrapping(b.repr()); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // Detect if a or b is zero, infinity, or NaN. + if a_abs - one >= inf_rep - one || + b_abs - one >= inf_rep - one { + // NaN + anything = qNaN + if a_abs > inf_rep { + return <$ty as Float>::from_repr((a_abs | quiet_bit).0); + } + // anything + NaN = qNaN + if b_abs > inf_rep { + return <$ty as Float>::from_repr((b_abs | quiet_bit).0); + } - // anything remaining + +/-infinity = +/-infinity - if b_abs == inf_rep { - return b; + if a_abs == inf_rep { + // +/-infinity + -/+infinity = qNaN + if (a.repr() ^ b.repr()) == sign_bit.0 { + return <$ty as Float>::from_repr(qnan_rep.0); + } else { + // +/-infinity + anything remaining = +/- infinity + return a; } + } - // zero + anything = anything - if a_abs.0 == 0 { - // but we need to get the sign right for zero + zero - if b_abs.0 == 0 { - return (<$ty as Float>::from_repr(a.repr() & b.repr())); - } else { - return b; - } - } + // anything remaining + +/-infinity = +/-infinity + if b_abs == inf_rep { + return b; + } - // anything + zero = anything + // zero + anything = anything + if a_abs.0 == 0 { + // but we need to get the sign right for zero + zero if b_abs.0 == 0 { - return a; + return <$ty as Float>::from_repr(a.repr() & b.repr()); + } else { + return b; } } - // Swap a and b if necessary so that a has the larger absolute value. - if b_abs > a_abs { - mem::swap(&mut a_rep, &mut b_rep); + // anything + zero = anything + if b_abs.0 == 0 { + return a; } + } - // Extract the exponent and significand from the (possibly swapped) a and b. - let mut a_exponent = Wrapping((a_rep >> significand_bits.0 as usize & max_exponent).0 as i32); - let mut b_exponent = Wrapping((b_rep >> significand_bits.0 as usize & max_exponent).0 as i32); - let mut a_significand = a_rep & significand_mask; - let mut b_significand = b_rep & significand_mask; - - // normalize any denormals, and adjust the exponent accordingly. - if a_exponent.0 == 0 { - let (exponent, significand) = <$ty>::normalize(a_significand.0); - a_exponent = Wrapping(exponent); - a_significand = Wrapping(significand); - } - if b_exponent.0 == 0 { - let (exponent, significand) = <$ty>::normalize(b_significand.0); - b_exponent = Wrapping(exponent); - b_significand = Wrapping(significand); - } + // Swap a and b if necessary so that a has the larger absolute value. + if b_abs > a_abs { + mem::swap(&mut a_rep, &mut b_rep); + } - // The sign of the result is the sign of the larger operand, a. If they - // have opposite signs, we are performing a subtraction; otherwise addition. - let result_sign = a_rep & sign_bit; - let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero; - - // Shift the significands to give us round, guard and sticky, and or in the - // implicit significand bit. (If we fell through from the denormal path it - // was already set by normalize(), but setting it twice won't hurt - // anything.) - a_significand = (a_significand | implicit_bit) << 3; - b_significand = (b_significand | implicit_bit) << 3; - - // Shift the significand of b by the difference in exponents, with a sticky - // bottom bit to get rounding correct. - let align = Wrapping((a_exponent - b_exponent).0 as <$ty as Float>::Int); - if align.0 != 0 { - if align < bits { - let sticky = ((b_significand << (bits - align).0 as usize).0 != 0) as <$ty as Float>::Int; - b_significand = (b_significand >> align.0 as usize) | Wrapping(sticky); - } else { - b_significand = one; // sticky; b is known to be non-zero. - } - } - if subtraction { - a_significand -= b_significand; - // If a == -b, return +zero. - if a_significand.0 == 0 { - return (<$ty as Float>::from_repr(0)); - } + // Extract the exponent and significand from the (possibly swapped) a and b. + let mut a_exponent = Wrapping((a_rep >> significand_bits.0 as usize & max_exponent).0 as i32); + let mut b_exponent = Wrapping((b_rep >> significand_bits.0 as usize & max_exponent).0 as i32); + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + + // normalize any denormals, and adjust the exponent accordingly. + if a_exponent.0 == 0 { + let (exponent, significand) = <$ty>::normalize(a_significand.0); + a_exponent = Wrapping(exponent); + a_significand = Wrapping(significand); + } + if b_exponent.0 == 0 { + let (exponent, significand) = <$ty>::normalize(b_significand.0); + b_exponent = Wrapping(exponent); + b_significand = Wrapping(significand); + } - // If partial cancellation occured, we need to left-shift the result - // and adjust the exponent: - if a_significand < implicit_bit << 3 { - let shift = a_significand.0.leading_zeros() as i32 - - (implicit_bit << 3).0.leading_zeros() as i32; - a_significand <<= shift as usize; - a_exponent -= Wrapping(shift); - } - } else /* addition */ { - a_significand += b_significand; - - // If the addition carried up, we need to right-shift the result and - // adjust the exponent: - if (a_significand & implicit_bit << 4).0 != 0 { - let sticky = ((a_significand & one).0 != 0) as <$ty as Float>::Int; - a_significand = a_significand >> 1 | Wrapping(sticky); - a_exponent += Wrapping(1); - } + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + let result_sign = a_rep & sign_bit; + let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize(), but setting it twice won't hurt + // anything.) + a_significand = (a_significand | implicit_bit) << 3; + b_significand = (b_significand | implicit_bit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + let align = Wrapping((a_exponent - b_exponent).0 as <$ty as Float>::Int); + if align.0 != 0 { + if align < bits { + let sticky = ((b_significand << (bits - align).0 as usize).0 != 0) as <$ty as Float>::Int; + b_significand = (b_significand >> align.0 as usize) | Wrapping(sticky); + } else { + b_significand = one; // sticky; b is known to be non-zero. } - - // If we have overflowed the type, return +/- infinity: - if a_exponent >= Wrapping(max_exponent.0 as i32) { - return (<$ty>::from_repr((inf_rep | result_sign).0)); + } + if subtraction { + a_significand -= b_significand; + // If a == -b, return +zero. + if a_significand.0 == 0 { + return <$ty as Float>::from_repr(0); } - if a_exponent.0 <= 0 { - // Result is denormal before rounding; the exponent is zero and we - // need to shift the significand. - let shift = Wrapping((Wrapping(1) - a_exponent).0 as <$ty as Float>::Int); - let sticky = ((a_significand << (bits - shift).0 as usize).0 != 0) as <$ty as Float>::Int; - a_significand = a_significand >> shift.0 as usize | Wrapping(sticky); - a_exponent = Wrapping(0); + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if a_significand < implicit_bit << 3 { + let shift = a_significand.0.leading_zeros() as i32 + - (implicit_bit << 3).0.leading_zeros() as i32; + a_significand <<= shift as usize; + a_exponent -= Wrapping(shift); } + } else /* addition */ { + a_significand += b_significand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if (a_significand & implicit_bit << 4).0 != 0 { + let sticky = ((a_significand & one).0 != 0) as <$ty as Float>::Int; + a_significand = a_significand >> 1 | Wrapping(sticky); + a_exponent += Wrapping(1); + } + } - // Low three bits are round, guard, and sticky. - let round_guard_sticky: i32 = (a_significand.0 & 0x7) as i32; + // If we have overflowed the type, return +/- infinity: + if a_exponent >= Wrapping(max_exponent.0 as i32) { + return <$ty>::from_repr((inf_rep | result_sign).0); + } - // Shift the significand into place, and mask off the implicit bit. - let mut result = a_significand >> 3 & significand_mask; + if a_exponent.0 <= 0 { + // Result is denormal before rounding; the exponent is zero and we + // need to shift the significand. + let shift = Wrapping((Wrapping(1) - a_exponent).0 as <$ty as Float>::Int); + let sticky = ((a_significand << (bits - shift).0 as usize).0 != 0) as <$ty as Float>::Int; + a_significand = a_significand >> shift.0 as usize | Wrapping(sticky); + a_exponent = Wrapping(0); + } - // Insert the exponent and sign. - result |= Wrapping(a_exponent.0 as <$ty as Float>::Int) << significand_bits.0 as usize; - result |= result_sign; + // Low three bits are round, guard, and sticky. + let round_guard_sticky: i32 = (a_significand.0 & 0x7) as i32; - // Final rounding. The result may overflow to infinity, but that is the - // correct result in that case. - if round_guard_sticky > 0x4 { result += one; } - if round_guard_sticky == 0x4 { result += result & one; } + // Shift the significand into place, and mask off the implicit bit. + let mut result = a_significand >> 3 & significand_mask; - <$ty>::from_repr(result.0) - } - } -} + // Insert the exponent and sign. + result |= Wrapping(a_exponent.0 as <$ty as Float>::Int) << significand_bits.0 as usize; + result |= result_sign; -#[cfg(target_arch = "arm")] -add!("aapcs", __addsf3: f32); + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if round_guard_sticky > 0x4 { result += one; } + if round_guard_sticky == 0x4 { result += result & one; } -#[cfg(not(target_arch = "arm"))] -add!("C", __addsf3: f32); + <$ty>::from_repr(result.0) + }) +} -#[cfg(target_arch = "arm")] -add!("aapcs", __adddf3: f64); +intrinsics! { + #[aapcs_on_arm] + pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 { + add!(a, b, f32) + } -#[cfg(not(target_arch = "arm"))] -add!("C", __adddf3: f64); + #[aapcs_on_arm] + pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 { + add!(a, b, f64) + } +} diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 8905f12fafa..edf9ee610fe 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -2,12 +2,8 @@ use float::Float; use int::Int; macro_rules! int_to_float { - ($intrinsic:ident: $ity:ty, $fty:ty) => { - int_to_float!($intrinsic: $ity, $fty, "C"); - }; - ($intrinsic:ident: $ity:ty, $fty:ty, $abi:tt) => { - - pub extern $abi fn $intrinsic(i: $ity) -> $fty { + ($i:expr, $ity:ty, $fty:ty) => ({ + let i = $i; if i == 0 { return 0.0 } @@ -70,29 +66,54 @@ macro_rules! int_to_float { <$fty>::from_parts(s, (e + exponent_bias) as <$fty as Float>::Int, a as <$fty as Float>::Int) + }) +} + +intrinsics! { + pub extern "C" fn __floatsisf(i: i32) -> f32 { + int_to_float!(i, i32, f32) } + + pub extern "C" fn __floatsidf(i: i32) -> f64 { + int_to_float!(i, i32, f64) } -} -macro_rules! int_to_float_unadj_on_win { - ($intrinsic:ident: $ity:ty, $fty:ty) => { - #[cfg(all(windows, target_pointer_width="64"))] - int_to_float!($intrinsic: $ity, $fty, "unadjusted"); - #[cfg(not(all(windows, target_pointer_width="64")))] - int_to_float!($intrinsic: $ity, $fty, "C"); - }; -} + pub extern "C" fn __floatdidf(i: i64) -> f64 { + int_to_float!(i, i64, f64) + } -int_to_float!(__floatsisf: i32, f32); -int_to_float!(__floatsidf: i32, f64); -int_to_float!(__floatdidf: i64, f64); -int_to_float_unadj_on_win!(__floattisf: i128, f32); -int_to_float_unadj_on_win!(__floattidf: i128, f64); -int_to_float!(__floatunsisf: u32, f32); -int_to_float!(__floatunsidf: u32, f64); -int_to_float!(__floatundidf: u64, f64); -int_to_float_unadj_on_win!(__floatuntisf: u128, f32); -int_to_float_unadj_on_win!(__floatuntidf: u128, f64); + #[unadjusted_on_win64] + pub extern "C" fn __floattisf(i: i128) -> f32 { + int_to_float!(i, i128, f32) + } + + #[unadjusted_on_win64] + pub extern "C" fn __floattidf(i: i128) -> f64 { + int_to_float!(i, i128, f64) + } + + pub extern "C" fn __floatunsisf(i: u32) -> f32 { + int_to_float!(i, u32, f32) + } + + pub extern "C" fn __floatunsidf(i: u32) -> f64 { + int_to_float!(i, u32, f64) + } + + pub extern "C" fn __floatundidf(i: u64) -> f64 { + int_to_float!(i, u64, f64) + } + + #[unadjusted_on_win64] + pub extern "C" fn __floatuntisf(i: u128) -> f32 { + int_to_float!(i, u128, f32) + } + + #[unadjusted_on_win64] + pub extern "C" fn __floatuntidf(i: u128) -> f64 { + int_to_float!(i, u128, f64) + } +} #[derive(PartialEq, Debug)] enum Sign { @@ -101,79 +122,106 @@ enum Sign { } macro_rules! float_to_int { - ($intrinsic:ident: $fty:ty, $ity:ty) => { - float_to_int!($intrinsic: $fty, $ity, "C"); - }; - ($intrinsic:ident: $fty:ty, $ity:ty, $abi:tt) => { - pub extern $abi fn $intrinsic(f: $fty) -> $ity { - let fixint_min = <$ity>::min_value(); - let fixint_max = <$ity>::max_value(); - let fixint_bits = <$ity>::bits() as usize; - let fixint_unsigned = fixint_min == 0; - - let sign_bit = <$fty>::sign_mask(); - let significand_bits = <$fty>::significand_bits() as usize; - let exponent_bias = <$fty>::exponent_bias() as usize; - //let exponent_max = <$fty>::exponent_max() as usize; - - // Break a into sign, exponent, significand - let a_rep = <$fty>::repr(f); - let a_abs = a_rep & !sign_bit; - - // this is used to work around -1 not being available for unsigned - let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative }; - let mut exponent = (a_abs >> significand_bits) as usize; - let significand = (a_abs & <$fty>::significand_mask()) | <$fty>::implicit_bit(); - - // if < 1 or unsigned & negative - if exponent < exponent_bias || - fixint_unsigned && sign == Sign::Negative { - return 0 - } - exponent -= exponent_bias; + ($f:expr, $fty:ty, $ity:ty) => ({ + let f = $f; + let fixint_min = <$ity>::min_value(); + let fixint_max = <$ity>::max_value(); + let fixint_bits = <$ity>::bits() as usize; + let fixint_unsigned = fixint_min == 0; + + let sign_bit = <$fty>::sign_mask(); + let significand_bits = <$fty>::significand_bits() as usize; + let exponent_bias = <$fty>::exponent_bias() as usize; + //let exponent_max = <$fty>::exponent_max() as usize; + + // Break a into sign, exponent, significand + let a_rep = <$fty>::repr(f); + let a_abs = a_rep & !sign_bit; + + // this is used to work around -1 not being available for unsigned + let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative }; + let mut exponent = (a_abs >> significand_bits) as usize; + let significand = (a_abs & <$fty>::significand_mask()) | <$fty>::implicit_bit(); + + // if < 1 or unsigned & negative + if exponent < exponent_bias || + fixint_unsigned && sign == Sign::Negative { + return 0 + } + exponent -= exponent_bias; - // If the value is infinity, saturate. - // If the value is too large for the integer type, 0. - if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { - return if sign == Sign::Positive {fixint_max} else {fixint_min} - } - // If 0 <= exponent < significand_bits, right shift to get the result. - // Otherwise, shift left. - // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned - let r = if exponent < significand_bits { - (significand >> (significand_bits - exponent)) as $ity - } else { - (significand as $ity) << (exponent - significand_bits) - }; + // If the value is infinity, saturate. + // If the value is too large for the integer type, 0. + if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { + return if sign == Sign::Positive {fixint_max} else {fixint_min} + } + // If 0 <= exponent < significand_bits, right shift to get the result. + // Otherwise, shift left. + // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned + let r = if exponent < significand_bits { + (significand >> (significand_bits - exponent)) as $ity + } else { + (significand as $ity) << (exponent - significand_bits) + }; - if sign == Sign::Negative { - (!r).wrapping_add(1) - } else { - r - } + if sign == Sign::Negative { + (!r).wrapping_add(1) + } else { + r } - } + }) } -macro_rules! float_to_int_unadj_on_win { - ($intrinsic:ident: $fty:ty, $ity:ty) => { - #[cfg(all(windows, target_pointer_width="64"))] - float_to_int!($intrinsic: $fty, $ity, "unadjusted"); - #[cfg(not(all(windows, target_pointer_width="64")))] - float_to_int!($intrinsic: $fty, $ity, "C"); - }; -} +intrinsics! { + pub extern "C" fn __fixsfsi(f: f32) -> i32 { + float_to_int!(f, f32, i32) + } + + pub extern "C" fn __fixsfdi(f: f32) -> i64 { + float_to_int!(f, f32, i64) + } + + #[unadjusted_on_win64] + pub extern "C" fn __fixsfti(f: f32) -> i128 { + float_to_int!(f, f32, i128) + } + + pub extern "C" fn __fixdfsi(f: f64) -> i32 { + float_to_int!(f, f64, i32) + } + + pub extern "C" fn __fixdfdi(f: f64) -> i64 { + float_to_int!(f, f64, i64) + } -float_to_int!(__fixsfsi: f32, i32); -float_to_int!(__fixsfdi: f32, i64); -float_to_int_unadj_on_win!(__fixsfti: f32, i128); -float_to_int!(__fixdfsi: f64, i32); -float_to_int!(__fixdfdi: f64, i64); -float_to_int_unadj_on_win!(__fixdfti: f64, i128); - -float_to_int!(__fixunssfsi: f32, u32); -float_to_int!(__fixunssfdi: f32, u64); -float_to_int_unadj_on_win!(__fixunssfti: f32, u128); -float_to_int!(__fixunsdfsi: f64, u32); -float_to_int!(__fixunsdfdi: f64, u64); -float_to_int_unadj_on_win!(__fixunsdfti: f64, u128); + #[unadjusted_on_win64] + pub extern "C" fn __fixdfti(f: f64) -> i128 { + float_to_int!(f, f64, i128) + } + + pub extern "C" fn __fixunssfsi(f: f32) -> u32 { + float_to_int!(f, f32, u32) + } + + pub extern "C" fn __fixunssfdi(f: f32) -> u64 { + float_to_int!(f, f32, u64) + } + + #[unadjusted_on_win64] + pub extern "C" fn __fixunssfti(f: f32) -> u128 { + float_to_int!(f, f32, u128) + } + + pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { + float_to_int!(f, f64, u32) + } + + pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { + float_to_int!(f, f64, u64) + } + + #[unadjusted_on_win64] + pub extern "C" fn __fixunsdfti(f: f64) -> u128 { + float_to_int!(f, f64, u128) + } +} diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 5e28d95d8d2..f5c5757d8bc 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,30 +1,34 @@ +/// Returns `a` raised to the power `b` macro_rules! pow { - ($intrinsic:ident: $fty:ty, $ity:ident) => { - /// Returns `a` raised to the power `b` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $fty, b: $ity) -> $fty { - let (mut a, mut b) = (a, b); - let recip = b < 0; - let mut r: $fty = 1.0; - loop { - if (b & 1) != 0 { - r *= a; - } - b = sdiv!($ity, b, 2); - if b == 0 { - break; - } - a *= a; + ($a: expr, $b: expr) => ({ + let (mut a, mut b) = ($a, $b); + let recip = b < 0; + let mut r = 1.0; + loop { + if (b & 1) != 0 { + r *= a; } - - if recip { - 1.0 / r - } else { - r + b = b.checked_div(2).unwrap_or_else(|| ::abort()); + if b == 0 { + break; } + a *= a; } - } + + if recip { + 1.0 / r + } else { + r + } + }) } -pow!(__powisf2: f32, i32); -pow!(__powidf2: f64, i32); +intrinsics! { + pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 { + pow!(a, b) + } + + pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 { + pow!(a, b) + } +} diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index a4fd8841d17..a82a9437e0f 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -1,20 +1,11 @@ use float::Float; -macro_rules! sub { - ($(#[$attr:meta])* - | $intrinsic:ident: $ty:ty) => { - /// Returns `a - b` - $(#[$attr])* - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { - a + <$ty>::from_repr(b.repr() ^ <$ty>::sign_mask()) - } +intrinsics! { + pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { + a + f32::from_repr(b.repr() ^ f32::sign_mask()) } -} - -sub!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - | __subsf3: f32); -sub!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - | __subdf3: f64); + pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { + a + f64::from_repr(b.repr() ^ f64::sign_mask()) + } +} diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 77e9c3f42a6..90ac729bf98 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,5 +1,3 @@ -use core::intrinsics; - use int::{Int, LargeInt}; macro_rules! udivmod_inner { @@ -13,9 +11,11 @@ macro_rules! udivmod_inner { // 0 X if let Some(rem) = rem { - *rem = <$ty>::from(urem!(n.low(), d.low())); + *rem = <$ty>::from(n.low().checked_rem(d.low()) + .unwrap_or_else(|| ::abort())); } - return <$ty>::from(udiv!(n.low(), d.low())); + return <$ty>::from(n.low().checked_div(d.low()) + .unwrap_or_else(|| ::abort())); } else { // 0 X // --- @@ -38,9 +38,7 @@ macro_rules! udivmod_inner { // 0 0 // NOTE This should be unreachable in safe Rust because the program will panic before // this intrinsic is called - unsafe { - intrinsics::abort() - } + ::abort(); } if n.low() == 0 { @@ -48,9 +46,11 @@ macro_rules! udivmod_inner { // --- // K 0 if let Some(rem) = rem { - *rem = <$ty>::from_parts(0, urem!(n.high(), d.high())); + *rem = <$ty>::from_parts(0, n.high().checked_rem(d.high()) + .unwrap_or_else(|| ::abort())); } - return <$ty>::from(udiv!(n.high(), d.high())); + return <$ty>::from(n.high().checked_div(d.high()) + .unwrap_or_else(|| ::abort())); } // K K @@ -161,9 +161,7 @@ intrinsics! { if d == 0 { // NOTE This should be unreachable in safe Rust because the program will panic before // this intrinsic is called - unsafe { - intrinsics::abort() - } + ::abort(); } if n == 0 { diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 6d44fb1a185..3fa7923b447 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -32,52 +32,6 @@ // that follow "x86 naming convention" (e.g. addsf3). Those aeabi intrinsics must adhere to the // AAPCS calling convention (`extern "aapcs"`) because that's how LLVM will call them. -// TODO(rust-lang/rust#37029) use e.g. checked_div(_).unwrap_or_else(|| abort()) -macro_rules! udiv { - ($a:expr, $b:expr) => { - unsafe { - let a = $a; - let b = $b; - - if b == 0 { - ::core::intrinsics::abort() - } else { - ::core::intrinsics::unchecked_div(a, b) - } - } - } -} - -macro_rules! sdiv { - ($sty:ident, $a:expr, $b:expr) => { - unsafe { - let a = $a; - let b = $b; - - if b == 0 || (b == -1 && a == $sty::min_value()) { - ::core::intrinsics::abort() - } else { - ::core::intrinsics::unchecked_div(a, b) - } - } - } -} - -macro_rules! urem { - ($a:expr, $b:expr) => { - unsafe { - let a = $a; - let b = $b; - - if b == 0 { - ::core::intrinsics::abort() - } else { - ::core::intrinsics::unchecked_rem(a, b) - } - } - } -} - #[cfg(test)] extern crate core; -- cgit 1.4.1-3-g733a5 From d20a774a4aeb6a580f272c38bef91618a8c4ac61 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 11:13:31 -0700 Subject: Remove defined intrinsics from build.rs No need to load these from C! --- library/compiler-builtins/build.rs | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index c8179fe9eb9..171622cb0da 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4066,28 +4066,8 @@ mod c { "divxc3.c", "extendsfdf2.c", "extendhfsf2.c", - "ffsdi2.c", - "fixdfdi.c", - "fixdfsi.c", - "fixsfdi.c", - "fixsfsi.c", - "fixunsdfdi.c", - "fixunsdfsi.c", - "fixunssfdi.c", - "fixunssfsi.c", - "fixunsxfdi.c", - "fixunsxfsi.c", - "fixxfdi.c", - "floatdidf.c", "floatdisf.c", - "floatdixf.c", - "floatsidf.c", - "floatsisf.c", - "floatundidf.c", "floatundisf.c", - "floatundixf.c", - "floatunsidf.c", - "floatunsisf.c", "int_util.c", "muldc3.c", "muldf3.c", @@ -4124,18 +4104,6 @@ mod c { "cmpti2.c", "ctzti2.c", "ffsti2.c", - "fixdfti.c", - "fixsfti.c", - "fixunsdfti.c", - "fixunssfti.c", - "fixunsxfti.c", - "fixxfti.c", - "floattidf.c", - "floattisf.c", - "floattixf.c", - "floatuntidf.c", - "floatuntisf.c", - "floatuntixf.c", "mulvti3.c", "negti2.c", "negvti2.c", -- cgit 1.4.1-3-g733a5 From 0e5562c38dabf672e69736d7fa9afbcc3fbece7b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 11:21:15 -0700 Subject: Remove executable bit on arm.rs --- library/compiler-builtins/src/arm.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 library/compiler-builtins/src/arm.rs diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs old mode 100755 new mode 100644 -- cgit 1.4.1-3-g733a5 From 11d3cffd309ba4148a41b5f4c6aab1b56858d44b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 11:21:36 -0700 Subject: Remove unused rust file --- library/compiler-builtins/src/qc.rs | 311 ------------------------------------ 1 file changed, 311 deletions(-) delete mode 100644 library/compiler-builtins/src/qc.rs diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs deleted file mode 100644 index 675bcc67702..00000000000 --- a/library/compiler-builtins/src/qc.rs +++ /dev/null @@ -1,311 +0,0 @@ -// When testing functions, QuickCheck (QC) uses small values for integer (`u*`/`i*`) arguments -// (~ `[-100, 100]`), but these values don't stress all the code paths in our intrinsics. Here we -// create newtypes over the primitive integer types with the goal of having full control over the -// random values that will be used to test our intrinsics. - -use std::boxed::Box; -use std::fmt; -use core::{f32, f64}; - -use quickcheck::{Arbitrary, Gen}; - -use int::LargeInt; -use float::Float; - -// Generates values in the full range of the integer type -macro_rules! arbitrary { - ($TY:ident : $ty:ident) => { - #[derive(Clone, Copy, PartialEq)] - pub struct $TY(pub $ty); - - impl Arbitrary for $TY { - fn arbitrary(g: &mut G) -> $TY - where G: Gen - { - // NOTE Generate edge cases with a 10% chance - let t = if g.gen_weighted_bool(10) { - *g.choose(&[ - $ty::min_value(), - 0, - $ty::max_value(), - ]).unwrap() - } else { - g.gen() - }; - - $TY(t) - } - - fn shrink(&self) -> Box> { - struct Shrinker { - x: $ty, - } - - impl Iterator for Shrinker { - type Item = $TY; - - fn next(&mut self) -> Option<$TY> { - self.x /= 2; - if self.x == 0 { - None - } else { - Some($TY(self.x)) - } - } - } - - if self.0 == 0 { - ::quickcheck::empty_shrinker() - } else { - Box::new(Shrinker { x: self.0 }) - } - } - } - - impl fmt::Debug for $TY { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } - } - } -} - -arbitrary!(I32: i32); -arbitrary!(U32: u32); - -// These integers are "too large". If we generate e.g. `u64` values in the full range then there's -// only `1 / 2^32` chance of seeing a value smaller than `2^32` (i.e. whose higher "word" (32-bits) -// is `0`)! But this is an important group of values to tests because we have special code paths for -// them. Instead we'll generate e.g. `u64` integers this way: uniformly pick between (a) setting the -// low word to 0 and generating a random high word, (b) vice versa: high word to 0 and random low -// word or (c) generate both words randomly. This let's cover better the code paths in our -// intrinsics. -macro_rules! arbitrary_large { - ($TY:ident : $ty:ident) => { - #[derive(Clone, Copy, PartialEq)] - pub struct $TY(pub $ty); - - impl Arbitrary for $TY { - fn arbitrary(g: &mut G) -> $TY - where G: Gen - { - // NOTE Generate edge cases with a 10% chance - let t = if g.gen_weighted_bool(10) { - *g.choose(&[ - $ty::min_value(), - 0, - $ty::max_value(), - ]).unwrap() - } else { - match g.gen_range(0, 3) { - 0 => $ty::from_parts(g.gen(), g.gen()), - 1 => $ty::from_parts(0, g.gen()), - 2 => $ty::from_parts(g.gen(), 0), - _ => unreachable!(), - } - }; - - $TY(t) - } - - fn shrink(&self) -> Box> { - struct Shrinker { - x: $ty, - } - - impl Iterator for Shrinker { - type Item = $TY; - - fn next(&mut self) -> Option<$TY> { - self.x /= 2; - if self.x == 0 { - None - } else { - Some($TY(self.x)) - } - } - } - - if self.0 == 0 { - ::quickcheck::empty_shrinker() - } else { - Box::new(Shrinker { x: self.0 }) - } - } - } - - impl fmt::Debug for $TY { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } - } - } -} - -arbitrary_large!(I64: i64); -arbitrary_large!(U64: u64); -arbitrary_large!(I128: i128); -arbitrary_large!(U128: u128); - -macro_rules! arbitrary_float { - ($TY:ident : $ty:ident) => { - #[derive(Clone, Copy)] - pub struct $TY(pub $ty); - - impl Arbitrary for $TY { - fn arbitrary(g: &mut G) -> $TY - where G: Gen - { - let special = [ - -0.0, 0.0, $ty::NAN, $ty::INFINITY, -$ty::INFINITY - ]; - - if g.gen_weighted_bool(10) { // Random special case - $TY(*g.choose(&special).unwrap()) - } else if g.gen_weighted_bool(10) { // NaN variants - let sign: bool = g.gen(); - let exponent: <$ty as Float>::Int = g.gen(); - let significand: <$ty as Float>::Int = 0; - $TY($ty::from_parts(sign, exponent, significand)) - } else if g.gen() { // Denormalized - let sign: bool = g.gen(); - let exponent: <$ty as Float>::Int = 0; - let significand: <$ty as Float>::Int = g.gen(); - $TY($ty::from_parts(sign, exponent, significand)) - } else { // Random anything - let sign: bool = g.gen(); - let exponent: <$ty as Float>::Int = g.gen(); - let significand: <$ty as Float>::Int = g.gen(); - $TY($ty::from_parts(sign, exponent, significand)) - } - } - - fn shrink(&self) -> Box> { - ::quickcheck::empty_shrinker() - } - } - - impl fmt::Debug for $TY { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } - } - - impl PartialEq for $TY { - fn eq(&self, other: &$TY) -> bool { - self.0.eq_repr(other.0) - } - } - } -} - -arbitrary_float!(F32: f32); -arbitrary_float!(F64: f64); - -// Convenience macro to test intrinsics against their reference implementations. -// -// Each intrinsic is tested against both the `gcc_s` library as well as -// `compiler-rt`. These libraries are defined in the `gcc_s` crate as well as -// the `compiler-rt` crate in this repository. Both load a dynamic library and -// lookup symbols through that dynamic library to ensure that we're using the -// right intrinsic. -// -// This macro hopefully allows you to define a bare minimum of how to test an -// intrinsic without worrying about these implementation details. A sample -// invocation looks like: -// -// -// check! { -// // First argument is the function we're testing (either from this lib -// // or a dynamically loaded one. Further arguments are all generated by -// // quickcheck. -// fn __my_intrinsic(f: extern fn(i32) -> i32, -// a: I32) -// -> Option<(i32, i64)> { -// -// // Discard tests by returning Some -// if a.0 == 0 { -// return None -// } -// -// // Return the result via `Some` if the test can run -// let mut other_result = 0; -// let result = f(a.0, &mut other_result); -// Some((result, other_result)) -// } -// } -// -// If anything returns `None` then the test is discarded, otherwise the two -// results are compared for equality and the test fails if this equality check -// fails. -macro_rules! check { - ($( - $(#[$cfg:meta])* - fn $name:ident($f:ident: extern $abi:tt fn($($farg:ty),*) -> $fret:ty, - $($arg:ident: $t:ty),*) - -> Option<$ret:ty> - { - $($code:tt)* - } - )*) => ( - $( - $(#[$cfg])* - fn $name($f: extern $abi fn($($farg),*) -> $fret, - $($arg: $t),*) -> Option<$ret> { - $($code)* - } - )* - - mod _test { - use qc::*; - use std::mem; - use quickcheck::TestResult; - - $( - $(#[$cfg])* - #[test] - fn $name() { - fn my_check($($arg:$t),*) -> TestResult { - let my_answer = super::$name(super::super::$name, - $($arg),*); - let compiler_rt_fn = ::compiler_rt::get(stringify!($name)); - let compiler_rt_answer = unsafe { - super::$name(mem::transmute(compiler_rt_fn), - $($arg),*) - }; - let gcc_s_answer = - match ::gcc_s::get(stringify!($name)) { - Some(f) => unsafe { - Some(super::$name(mem::transmute(f), - $($arg),*)) - }, - None => None, - }; - - let print_values = || { - print!("{} - Args: ", stringify!($name)); - $(print!("{:?} ", $arg);)* - print!("\n"); - println!(" compiler-builtins: {:?}", my_answer); - println!(" compiler_rt: {:?}", compiler_rt_answer); - println!(" gcc_s: {:?}", gcc_s_answer); - }; - - if my_answer != compiler_rt_answer { - print_values(); - TestResult::from_bool(false) - } else if gcc_s_answer.is_some() && - my_answer != gcc_s_answer.unwrap() { - print_values(); - TestResult::from_bool(false) - } else { - TestResult::from_bool(true) - } - } - - ::quickcheck::quickcheck(my_check as fn($($t),*) -> TestResult) - } - )* - } - ) -} -- cgit 1.4.1-3-g733a5 From 4dbe3aaf2de7a866bb5011cc78874155bf60d3d3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 11:52:22 -0700 Subject: Use `nm` to weed out panics --- library/compiler-builtins/ci/run.sh | 13 ++++++++++++- library/compiler-builtins/src/float/conv.rs | 2 ++ library/compiler-builtins/src/int/mul.rs | 4 ++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index e5c89247dd7..3316a43c61e 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -63,7 +63,6 @@ case $1 in ;; esac -# Look out for duplicated symbols when we include the compiler-rt (C) implementation PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in armv7-*) @@ -95,6 +94,7 @@ else path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib fi +# Look out for duplicated symbols when we include the compiler-rt (C) implementation for rlib in $(echo $path); do set +x stdout=$($PREFIX$NM -g --defined-only $rlib 2>&1) @@ -109,4 +109,15 @@ for rlib in $(echo $path); do set -ex done +# Ensure no references to a panicking function +for rlib in $(echo $path); do + set +x + $PREFIX$NM -u $rlib 2>&1 | grep panicking + + if test $? = 0; then + exit 1 + fi + set -ex +done + true diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index edf9ee610fe..053c6816e5b 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -78,6 +78,7 @@ intrinsics! { int_to_float!(i, i32, f64) } + #[use_c_shim_if(any(target_arch = "x86", target_arch = "x86_64"))] pub extern "C" fn __floatdidf(i: i64) -> f64 { int_to_float!(i, i64, f64) } @@ -100,6 +101,7 @@ intrinsics! { int_to_float!(i, u32, f64) } + #[use_c_shim_if(any(target_arch = "x86", target_arch = "x86_64"))] pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float!(i, u64, f64) } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index cb3fbd620bf..9241ee6a4c0 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -54,11 +54,11 @@ trait Mulo: Int + ops::Neg { return result; } if sa == sb { - if abs_a > Self::max_value() / abs_b { + if abs_a > Self::max_value().checked_div(abs_b).unwrap_or_else(|| ::abort()) { *overflow = 1; } } else { - if abs_a > Self::min_value() / -abs_b { + if abs_a > Self::min_value().checked_div(-abs_b).unwrap_or_else(|| ::abort()) { *overflow = 1; } } -- cgit 1.4.1-3-g733a5 From f091d059040c080c0ff215062aef35cbb48fd2d8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 12:02:28 -0700 Subject: Tweak usage of C shims on MSVC --- library/compiler-builtins/src/float/conv.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 053c6816e5b..ca95b110434 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -78,7 +78,10 @@ intrinsics! { int_to_float!(i, i32, f64) } - #[use_c_shim_if(any(target_arch = "x86", target_arch = "x86_64"))] + #[use_c_shim_if(any( + all(not(target_env = "msvc"), target_arch = "x86", target_arch = "x86_64"), + all(target_env = "msvc", target_arch = "x86_64"), + ))] pub extern "C" fn __floatdidf(i: i64) -> f64 { int_to_float!(i, i64, f64) } @@ -101,7 +104,8 @@ intrinsics! { int_to_float!(i, u32, f64) } - #[use_c_shim_if(any(target_arch = "x86", target_arch = "x86_64"))] + #[use_c_shim_if(all(any(target_arch = "x86", target_arch = "x86_64"), + not(target_env = "msvc")))] pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float!(i, u64, f64) } -- cgit 1.4.1-3-g733a5 From 78b290b61c7a27c0dd6e09397971a2e5de90071d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 13:28:24 -0700 Subject: Deal with floatdidf on x86_64 Apparently LLVM will lower this down to just an instruction --- library/compiler-builtins/build.rs | 2 -- library/compiler-builtins/src/float/conv.rs | 13 ++++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 171622cb0da..e66b3ab3bbe 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4132,7 +4132,6 @@ mod c { if target_arch == "x86_64" { sources.extend( &[ - "x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c", ], @@ -4148,7 +4147,6 @@ mod c { &[ "x86_64/chkstk.S", "x86_64/chkstk2.S", - "x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c", "x86_64/floatundidf.S", diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index ca95b110434..ca05c283060 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -78,12 +78,15 @@ intrinsics! { int_to_float!(i, i32, f64) } - #[use_c_shim_if(any( - all(not(target_env = "msvc"), target_arch = "x86", target_arch = "x86_64"), - all(target_env = "msvc", target_arch = "x86_64"), - ))] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] pub extern "C" fn __floatdidf(i: i64) -> f64 { - int_to_float!(i, i64, f64) + // On x86_64 LLVM will use native instructions for this conversion, we + // can just do it directly + if cfg!(target_arch = "x86_64") { + i as f64 + } else { + int_to_float!(i, i64, f64) + } } #[unadjusted_on_win64] -- cgit 1.4.1-3-g733a5 From 6db18f65366162e2da22091f9a750184eee7979f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 15:16:07 -0700 Subject: Handle aeabi aliasing Objects in compiler-rt may have two symbols, so this makes sure that we don't bring in those objects by accident by defining the aliases ourselves. --- library/compiler-builtins/ci/run.sh | 30 +++++++------ library/compiler-builtins/src/arm.rs | 58 ------------------------ library/compiler-builtins/src/float/add.rs | 2 + library/compiler-builtins/src/float/conv.rs | 14 ++++++ library/compiler-builtins/src/float/sub.rs | 2 + library/compiler-builtins/src/int/mul.rs | 1 + library/compiler-builtins/src/int/sdiv.rs | 1 + library/compiler-builtins/src/int/shift.rs | 3 ++ library/compiler-builtins/src/int/udiv.rs | 1 + library/compiler-builtins/src/macros.rs | 69 +++++++++++++++++++++++------ 10 files changed, 95 insertions(+), 86 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 3316a43c61e..f61b90f8175 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -50,19 +50,6 @@ case $1 in ;; esac -# Verify that there are no undefined symbols to `panic` within our implementations -# TODO(#79) fix the undefined references problem for debug-assertions+lto -case $1 in - thumb*) - RUSTFLAGS="-C debug-assertions=no" xargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles - xargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto - ;; - *) - RUSTFLAGS="-C debug-assertions=no" cargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto - cargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto - ;; -esac - PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in armv7-*) @@ -109,9 +96,24 @@ for rlib in $(echo $path); do set -ex done +rm -f $path + +# Verify that there are no undefined symbols to `panic` within our implementations +# TODO(#79) fix the undefined references problem for debug-assertions+lto +case $1 in + thumb*) + RUSTFLAGS="-C debug-assertions=no" xargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles + xargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto + ;; + *) + RUSTFLAGS="-C debug-assertions=no" cargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto + cargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto + ;; +esac + # Ensure no references to a panicking function for rlib in $(echo $path); do - set +x + set +ex $PREFIX$NM -u $rlib 2>&1 | grep panicking if test $? = 0; then diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index cf960c5aa1a..6e1c8f2b0b2 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -60,64 +60,6 @@ pub unsafe fn __aeabi_ldivmod() { intrinsics::unreachable(); } -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_dadd(a: f64, b: f64) -> f64 { - ::float::add::__adddf3(a, b) -} - -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_fadd(a: f32, b: f32) -> f32 { - ::float::add::__addsf3(a, b) -} - -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_dsub(a: f64, b: f64) -> f64 { - ::float::sub::__subdf3(a, b) -} - -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_fsub(a: f32, b: f32) -> f32 { - ::float::sub::__subsf3(a, b) -} - -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_idiv(a: i32, b: i32) -> i32 { - ::int::sdiv::__divsi3(a, b) -} - -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_lasr(a: i64, b: u32) -> i64 { - ::int::shift::__ashrdi3(a, b) -} - -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_llsl(a: u64, b: u32) -> u64 { - ::int::shift::__ashldi3(a, b) -} - -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_llsr(a: u64, b: u32) -> u64 { - ::int::shift::__lshrdi3(a, b) -} - -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_lmul(a: u64, b: u64) -> u64 { - ::int::mul::__muldi3(a, b) -} - -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { - ::int::udiv::__udivsi3(a, b) -} - -#[cfg(not(feature = "c"))] -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_ui2d(a: u32) -> f64 { - ::float::conv::__floatunsidf(a) -} - // TODO: These aeabi_* functions should be defined as aliases #[cfg(not(feature = "mem"))] extern "C" { diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 1b1ac3f0087..696d886fb69 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -181,11 +181,13 @@ macro_rules! add { intrinsics! { #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_fadd] pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 { add!(a, b, f32) } #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_dadd] pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 { add!(a, b, f64) } diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index ca05c283060..8fc2a2a7951 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -70,15 +70,18 @@ macro_rules! int_to_float { } intrinsics! { + #[arm_aeabi_alias = __aeabi_i2f] pub extern "C" fn __floatsisf(i: i32) -> f32 { int_to_float!(i, i32, f32) } + #[arm_aeabi_alias = __aeabi_i2d] pub extern "C" fn __floatsidf(i: i32) -> f64 { int_to_float!(i, i32, f64) } #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[arm_aeabi_alias = __aeabi_l2d] pub extern "C" fn __floatdidf(i: i64) -> f64 { // On x86_64 LLVM will use native instructions for this conversion, we // can just do it directly @@ -99,16 +102,19 @@ intrinsics! { int_to_float!(i, i128, f64) } + #[arm_aeabi_alias = __aeabi_ui2f] pub extern "C" fn __floatunsisf(i: u32) -> f32 { int_to_float!(i, u32, f32) } + #[arm_aeabi_alias = __aeabi_ui2d] pub extern "C" fn __floatunsidf(i: u32) -> f64 { int_to_float!(i, u32, f64) } #[use_c_shim_if(all(any(target_arch = "x86", target_arch = "x86_64"), not(target_env = "msvc")))] + #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float!(i, u64, f64) } @@ -182,10 +188,12 @@ macro_rules! float_to_int { } intrinsics! { + #[arm_aeabi_alias = __aeabi_f2iz] pub extern "C" fn __fixsfsi(f: f32) -> i32 { float_to_int!(f, f32, i32) } + #[arm_aeabi_alias = __aeabi_f2lz] pub extern "C" fn __fixsfdi(f: f32) -> i64 { float_to_int!(f, f32, i64) } @@ -195,10 +203,12 @@ intrinsics! { float_to_int!(f, f32, i128) } + #[arm_aeabi_alias = __aeabi_d2iz] pub extern "C" fn __fixdfsi(f: f64) -> i32 { float_to_int!(f, f64, i32) } + #[arm_aeabi_alias = __aeabi_d2lz] pub extern "C" fn __fixdfdi(f: f64) -> i64 { float_to_int!(f, f64, i64) } @@ -208,10 +218,12 @@ intrinsics! { float_to_int!(f, f64, i128) } + #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { float_to_int!(f, f32, u32) } + #[arm_aeabi_alias = __aeabi_f2ulz] pub extern "C" fn __fixunssfdi(f: f32) -> u64 { float_to_int!(f, f32, u64) } @@ -221,10 +233,12 @@ intrinsics! { float_to_int!(f, f32, u128) } + #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { float_to_int!(f, f64, u32) } + #[arm_aeabi_alias = __aeabi_d2ulz] pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { float_to_int!(f, f64, u64) } diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index a82a9437e0f..4fa436db613 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -1,10 +1,12 @@ use float::Float; intrinsics! { + #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { a + f32::from_repr(b.repr() ^ f32::sign_mask()) } + #[arm_aeabi_alias = __aeabi_dsub] pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { a + f64::from_repr(b.repr() ^ f64::sign_mask()) } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 9241ee6a4c0..d61a6b474cd 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -72,6 +72,7 @@ impl Mulo for i128 {} intrinsics! { #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[arm_aeabi_alias = __aeabi_lmul] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { a.mul(b) } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 8d856303755..6ce7ffd42ce 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -60,6 +60,7 @@ impl Divmod for i64 {} intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] + #[arm_aeabi_alias = __aeabi_idiv] pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { a.div(b) } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index b0103ceaf20..a9b6c05d3d3 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -66,6 +66,7 @@ impl Lshr for u128 {} intrinsics! { #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[arm_aeabi_alias = __aeabi_llsl] pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { a.ashl(b) } @@ -75,6 +76,7 @@ intrinsics! { } #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[arm_aeabi_alias = __aeabi_lasr] pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { a.ashr(b) } @@ -84,6 +86,7 @@ intrinsics! { } #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[arm_aeabi_alias = __aeabi_llsr] pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { a.lshr(b) } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 90ac729bf98..27baff95775 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -155,6 +155,7 @@ intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] + #[arm_aeabi_alias = __aeabi_uidiv] /// Returns `n / d` pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { // Special cases diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 740eae29385..2e65e9659f4 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -7,7 +7,7 @@ macro_rules! intrinsics { // intrinsic. ( #[use_c_shim_if($($cfg_clause:tt)*)] - $(#[$attr:meta])* + $(#[$($attr:tt)*])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { $($body:tt)* } @@ -16,7 +16,6 @@ macro_rules! intrinsics { ) => ( #[cfg(all(feature = "c", $($cfg_clause)*))] - $(#[$attr])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { extern $abi { fn $name($($argname: $ty),*) -> $ret; @@ -28,7 +27,7 @@ macro_rules! intrinsics { #[cfg(not(all(feature = "c", $($cfg_clause)*)))] intrinsics! { - $(#[$attr])* + $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -42,7 +41,7 @@ macro_rules! intrinsics { // ARM and `"C"` elsewhere. ( #[aapcs_on_arm] - $(#[$attr:meta])* + $(#[$($attr:tt)*])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { $($body:tt)* } @@ -51,7 +50,7 @@ macro_rules! intrinsics { ) => ( #[cfg(target_arch = "arm")] intrinsics! { - $(#[$attr])* + $(#[$($attr)*])* pub extern "aapcs" fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -59,7 +58,7 @@ macro_rules! intrinsics { #[cfg(not(target_arch = "arm"))] intrinsics! { - $(#[$attr])* + $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -72,7 +71,7 @@ macro_rules! intrinsics { // win64 for some methods. ( #[unadjusted_on_win64] - $(#[$attr:meta])* + $(#[$($attr:tt)*])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { $($body:tt)* } @@ -81,7 +80,7 @@ macro_rules! intrinsics { ) => ( #[cfg(all(windows, target_pointer_width = "64"))] intrinsics! { - $(#[$attr])* + $(#[$($attr)*])* pub extern "unadjusted" fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -89,7 +88,7 @@ macro_rules! intrinsics { #[cfg(not(all(windows, target_pointer_width = "64")))] intrinsics! { - $(#[$attr])* + $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -102,7 +101,7 @@ macro_rules! intrinsics { // bit calling convention correct. ( #[win64_128bit_abi_hack] - $(#[$attr:meta])* + $(#[$($attr:tt)*])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { $($body:tt)* } @@ -110,7 +109,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg(all(windows, target_pointer_width = "64"))] - $(#[$attr])* + $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -130,7 +129,7 @@ macro_rules! intrinsics { #[cfg(not(all(windows, target_pointer_width = "64")))] intrinsics! { - $(#[$attr])* + $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -139,15 +138,57 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // A bunch of intrinsics on ARM are aliased in the standard compiler-rt + // build under `__aeabi_*` aliases, and LLVM will call these instead of the + // original function. Handle that here ( - $(#[$attr:meta])* + #[arm_aeabi_alias = $alias:ident] + $(#[$($attr:tt)*])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { $($body:tt)* } $($rest:tt)* ) => ( - $(#[$attr])* + #[cfg(target_arch = "arm")] + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + + #[cfg(target_arch = "arm")] + pub mod $name { + intrinsics! { + pub extern "aapcs" fn $alias( $($argname: $ty),* ) -> $ret { + super::$name($($argname),*) + } + + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + super::$name($($argname),*) + } + } + } + + #[cfg(not(target_arch = "arm"))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + ( + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + $(#[$($attr)*])* #[cfg_attr(not(test), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* -- cgit 1.4.1-3-g733a5 From e8efe11f71c6ca4f04340aa0ac5678a47e789909 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 16:28:50 -0700 Subject: Shore up docs in the macros module --- library/compiler-builtins/src/macros.rs | 89 ++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 2e65e9659f4..6e34066f19f 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,10 +1,63 @@ +//! Macros shared throughout the compiler-builtins implementation + +/// The "main macro" used for defining intrinsics. +/// +/// The compiler-builtins library is super platform-specific with tons of crazy +/// little tweaks for various platforms. As a result it *could* involve a lot fo +/// #[cfg] and macro soup, but the intention is that this macro alleviates a lof +/// of that complexity. Ideally this macro has all the weird ABI things +/// platforms need and elsewhere in this library it just looks like normal Rust +/// code. +/// +/// This macro is structured to be invoked with a bunch of functions that looks +/// like: +/// +/// intrinsics! { +/// pub extern "C" fn foo(a: i32) -> u32 { +/// // ... +/// } +/// +/// #[nonstandard_attribute] +/// pub extern "C" fn bar(a: i32) -> u32 { +/// // ... +/// } +/// } +/// +/// Each function is defined in a manner that looks like a normal Rust function. +/// The macro then accepts a few nonstandard attributes that can decorate +/// various functions. Each of the attributes is documented below with what it +/// can do, and each of them slightly tweaks how further expansion happens. +/// +/// A quick overview of attributes supported right now are: +/// +/// * `use_c_shim_if` - takes a #[cfg] directive and falls back to the +/// C-compiled version if `feature = "c"` is specified. +/// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and +/// the specified ABI everywhere else. +/// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the +/// `"unadjusted"` abi on Win64 and the specified abi elsewhere. +/// * `win64_128bit_abi_hack` - this attribute is used for 128-bit integer +/// intrinsics where the ABI is slightly tweaked on Windows platforms, but +/// it's a normal ABI elsewhere for returning a 128 bit integer. +/// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM +/// their otherwise typical names to other prefixed ones. +/// macro_rules! intrinsics { () => (); - // Anything which has a `not(feature = "c")` we'll generate a shim function - // which calls out to the C function if the `c` feature is enabled. - // Otherwise if the `c` feature isn't enabled then we'll just have a normal - // intrinsic. + // Right now there's a bunch of architecture-optimized intrinsics in the + // stock compiler-rt implementation. Not all of these have been ported over + // to Rust yet so when the `c` feature of this crate is enabled we fall back + // to the architecture-specific versions which should be more optimized. The + // purpose of this macro is to easily allow specifying this. + // + // The argument to `use_c_shim_if` is a `#[cfg]` directive which, when true, + // will cause this crate's exported version of `$name` to just redirect to + // the C implementation. No symbol named `$name` will be in the object file + // for this crate itself. + // + // When the `#[cfg]` directive is false, or when the `c` feature is + // disabled, the provided implementation is used instead. ( #[use_c_shim_if($($cfg_clause:tt)*)] $(#[$($attr:tt)*])* @@ -97,8 +150,13 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // Another attribute we recognize is an "abi hack" for win64 to get the 128 - // bit calling convention correct. + // Some intrinsics on win64 which return a 128-bit integer have an.. unusual + // calling convention. That's managed here with this "abi hack" which alters + // the generated symbol's ABI. + // + // This will still define a function in this crate with the given name and + // signature, but the actual symbol for the intrinsic may have a slightly + // different ABI on win64. ( #[win64_128bit_abi_hack] $(#[$($attr:tt)*])* @@ -119,10 +177,10 @@ macro_rules! intrinsics { intrinsics! { pub extern $abi fn $name( $($argname: $ty),* ) - -> ::macros::win64_abi_hack::U64x2 + -> ::macros::win64_128bit_abi_hack::U64x2 { let e: $ret = super::$name($($argname),*); - ::macros::win64_abi_hack::U64x2::from(e) + ::macros::win64_128bit_abi_hack::U64x2::from(e) } } } @@ -140,7 +198,8 @@ macro_rules! intrinsics { // A bunch of intrinsics on ARM are aliased in the standard compiler-rt // build under `__aeabi_*` aliases, and LLVM will call these instead of the - // original function. Handle that here + // original function. The aliasing here is used to generate these symbols in + // the object file. ( #[arm_aeabi_alias = $alias:ident] $(#[$($attr:tt)*])* @@ -151,7 +210,6 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg(target_arch = "arm")] - $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -180,6 +238,12 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // This is the final catch-all rule. At this point we just generate an + // intrinsic with a conditional `#[no_mangle]` directive to avoid + // interfereing with duplicate symbols and whatnot. + // + // After the intrinsic is defined we just continue with the rest of the + // input we were given. ( $(#[$($attr:tt)*])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { @@ -198,9 +262,10 @@ macro_rules! intrinsics { ); } -// Hack for LLVM expectations for ABI on windows +// Hack for LLVM expectations for ABI on windows. This is used by the +// `#[win64_128bit_abi_hack]` attribute recognized above #[cfg(all(windows, target_pointer_width="64"))] -pub mod win64_abi_hack { +pub mod win64_128bit_abi_hack { #[repr(simd)] pub struct U64x2(u64, u64); -- cgit 1.4.1-3-g733a5 From 4bb783da70e7fa61fd3c01a957d9c85ac497297e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 20:20:42 -0700 Subject: Remove the travis cache --- library/compiler-builtins/.travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index fa9a27866af..8a9d1faa1dc 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,4 +1,3 @@ -cache: cargo dist: trusty language: rust rust: nightly @@ -52,8 +51,6 @@ script: else sh ci/run.sh $TARGET; fi - # Travis can't cache files that are not readable by "others" - - chmod -R a+r $HOME/.cargo notifications: email: -- cgit 1.4.1-3-g733a5 From af944595d07e2a66d1f518096e666d7f7ea0eda9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 20:35:25 -0700 Subject: Try testing MinGW targets --- library/compiler-builtins/appveyor.yml | 21 ++++++++++++++++-- library/compiler-builtins/examples/intrinsics.rs | 28 ++++++++++++++---------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 2dce7ceb6df..70049bf5130 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -3,12 +3,29 @@ environment: - TARGET: i686-pc-windows-msvc - TARGET: x86_64-pc-windows-msvc + # Ensure MinGW works, but we need to download the 32-bit MinGW compiler from a + # custom location. + - TARGET: i686-pc-windows-gnu + MINGW_URL: https://s3.amazonaws.com/rust-lang-ci + MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z + MINGW_DIR: mingw32 + - TARGET: x86_64-pc-windows-gnu + MSYS_BITS: 64 + install: - git submodule update --init - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init.exe --default-host x86_64-pc-windows-msvc --default-toolchain nightly -y - - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - - if "%TARGET%"=="i686-pc-windows-msvc" ( rustup target add %TARGET% ) + - if NOT "%TARGET%" == "x86_64-pc-windows-msvc" rustup target add %TARGET% + + # Use the system msys if we can + - if defined MSYS_BITS set PATH=C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin;%PATH% + + # download a custom compiler otherwise + - if defined MINGW_URL appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE% + - if defined MINGW_URL 7z x -y %MINGW_ARCHIVE% > nul + - if defined MINGW_URL set PATH=C:\Python27;%CD%\%MINGW_DIR%\bin;C:\msys64\usr\bin;%PATH% + - rustc -Vv - cargo -V diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index cabe917641f..7db241eddbb 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -12,12 +12,14 @@ #![feature(core_float)] #![feature(lang_items)] #![feature(start)] +#![feature(panic_unwind)] #![feature(i128_type)] #![no_std] #[cfg(not(thumb))] extern crate alloc_system; extern crate compiler_builtins; +extern crate panic_unwind; // NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even // compiler-rt provides a C/assembly implementation. @@ -400,6 +402,20 @@ fn run() { bb(umodti3(bb(2), bb(2))); bb(divti3(bb(2), bb(2))); bb(modti3(bb(2), bb(2))); + + something_with_a_dtor(&|| assert_eq!(bb(1), 1)); +} + +fn something_with_a_dtor(f: &Fn()) { + struct A<'a>(&'a (Fn() + 'a)); + + impl<'a> Drop for A<'a> { + fn drop(&mut self) { + (self.0)(); + } + } + let _a = A(f); + f(); } #[cfg(not(thumb))] @@ -428,18 +444,6 @@ pub fn __aeabi_unwind_cpp_pr0() {} #[no_mangle] pub fn __aeabi_unwind_cpp_pr1() {} -// Avoid "undefined reference to `_Unwind_Resume`" errors -#[allow(non_snake_case)] -#[no_mangle] -pub fn _Unwind_Resume() {} - -// Lang items -#[cfg(not(test))] -#[lang = "eh_personality"] -#[no_mangle] -#[allow(private_no_mangle_fns)] -extern "C" fn eh_personality() {} - #[cfg(not(test))] #[lang = "panic_fmt"] #[no_mangle] -- cgit 1.4.1-3-g733a5 From bbaf9fd85a9b7b59df028a1963100ba371136ac1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 20:43:51 -0700 Subject: Don't build chkstk on x86_64 --- library/compiler-builtins/build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e66b3ab3bbe..7c09987ad0a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4145,8 +4145,6 @@ mod c { if target_arch == "x86_64" { sources.extend( &[ - "x86_64/chkstk.S", - "x86_64/chkstk2.S", "x86_64/floatdisf.c", "x86_64/floatdixf.c", "x86_64/floatundidf.S", -- cgit 1.4.1-3-g733a5 From d3e78c5f6f338db025b685dab29495fdb84c20d7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 21:09:24 -0700 Subject: Don't compile assembly on x86_64 Windows They've all got the wrong ABI... --- library/compiler-builtins/build.rs | 24 ++++++++++++++---------- library/compiler-builtins/src/float/conv.rs | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 7c09987ad0a..06e1155bae4 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4142,16 +4142,20 @@ mod c { sources.extend(&["gcc_personality_v0.c"]); } - if target_arch == "x86_64" { - sources.extend( - &[ - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S", - ], - ); + // None of these seem to be used on x86_64 windows, and they've all + // got the wrong ABI anyway, so we want to avoid them. + if target_os != "windows" { + if target_arch == "x86_64" { + sources.extend( + &[ + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S", + ], + ); + } } if target_arch == "x86" { diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 8fc2a2a7951..ec77f2bf873 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -113,7 +113,7 @@ intrinsics! { } #[use_c_shim_if(all(any(target_arch = "x86", target_arch = "x86_64"), - not(target_env = "msvc")))] + not(windows)))] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float!(i, u64, f64) -- cgit 1.4.1-3-g733a5 From d5279752b062b1749a93c0b229e82bafb255fe1b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 21:11:31 -0700 Subject: Don't derive Debug for Sign --- library/compiler-builtins/src/float/conv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index ec77f2bf873..e12349cfff9 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -130,7 +130,7 @@ intrinsics! { } } -#[derive(PartialEq, Debug)] +#[derive(PartialEq)] enum Sign { Positive, Negative -- cgit 1.4.1-3-g733a5 From 80112d198d8bc429d91c8984878e858cd832b802 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 21:23:52 -0700 Subject: Use the same CI script on AppVeyor --- library/compiler-builtins/appveyor.yml | 14 +++----------- library/compiler-builtins/ci/run.sh | 6 +++--- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 70049bf5130..6a602132f65 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -10,7 +10,6 @@ environment: MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z MINGW_DIR: mingw32 - TARGET: x86_64-pc-windows-gnu - MSYS_BITS: 64 install: - git submodule update --init @@ -18,8 +17,8 @@ install: - rustup-init.exe --default-host x86_64-pc-windows-msvc --default-toolchain nightly -y - if NOT "%TARGET%" == "x86_64-pc-windows-msvc" rustup target add %TARGET% - # Use the system msys if we can - - if defined MSYS_BITS set PATH=C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin;%PATH% + # Use the system msys + - set PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH% # download a custom compiler otherwise - if defined MINGW_URL appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE% @@ -32,11 +31,4 @@ install: build: false test_script: - - cargo build --target %TARGET% - - cargo build --target %TARGET% --features c --example intrinsics - - cargo build --release --target %TARGET% - - cargo build --release --target %TARGET% --features c --example intrinsics - - cargo test --no-default-features --features gen-tests --target %TARGET% - - cargo test --no-default-features --features "gen-tests c" --target %TARGET% - - cargo test --no-default-features --features gen-tests --release --target %TARGET% - - cargo test --no-default-features --features "gen-tests c" --release --target %TARGET% + - sh ci/run.sh %TARGET% diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index f61b90f8175..c727bdfb969 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -75,10 +75,10 @@ case "$TRAVIS_OS_NAME" in ;; esac -if [ "$TRAVIS_OS_NAME" = osx ]; then - path=target/${1}/debug/deps/libcompiler_builtins-*.rlib -else +if [ -d /target ]; then path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib +else + path=target/${1}/debug/deps/libcompiler_builtins-*.rlib fi # Look out for duplicated symbols when we include the compiler-rt (C) implementation -- cgit 1.4.1-3-g733a5 From c785055bd9bc9f11c6c0ae4d2c76b544575d40f2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 21:31:54 -0700 Subject: Remove usage of unwrap_or_else --- library/compiler-builtins/src/float/pow.rs | 4 +++- library/compiler-builtins/src/int/mod.rs | 27 +++++++++++++++++---------- library/compiler-builtins/src/int/mul.rs | 4 ++-- library/compiler-builtins/src/int/sdiv.rs | 6 ++---- library/compiler-builtins/src/int/udiv.rs | 12 ++++-------- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index f5c5757d8bc..bc15dc08887 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,3 +1,5 @@ +use int::Int; + /// Returns `a` raised to the power `b` macro_rules! pow { ($a: expr, $b: expr) => ({ @@ -8,7 +10,7 @@ macro_rules! pow { if (b & 1) != 0 { r *= a; } - b = b.checked_div(2).unwrap_or_else(|| ::abort()); + b = b.aborting_div(2); if b == 0 { break; } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 9ad3d88852f..0334a4acb8b 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -66,8 +66,15 @@ pub trait Int: fn wrapping_add(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self; fn wrapping_sub(self, other: Self) -> Self; - fn checked_div(self, other: Self) -> Option; - fn checked_rem(self, other: Self) -> Option; + fn aborting_div(self, other: Self) -> Self; + fn aborting_rem(self, other: Self) -> Self; +} + +fn unwrap(t: Option) -> T { + match t { + Some(t) => t, + None => ::abort(), + } } macro_rules! int_impl { @@ -120,12 +127,12 @@ macro_rules! int_impl { ::wrapping_sub(self, other) } - fn checked_div(self, other: Self) -> Option { - ::checked_div(self, other) + fn aborting_div(self, other: Self) -> Self { + unwrap(::checked_div(self, other)) } - fn checked_rem(self, other: Self) -> Option { - ::checked_rem(self, other) + fn aborting_rem(self, other: Self) -> Self { + unwrap(::checked_rem(self, other)) } } @@ -181,12 +188,12 @@ macro_rules! int_impl { ::wrapping_sub(self, other) } - fn checked_div(self, other: Self) -> Option { - ::checked_div(self, other) + fn aborting_div(self, other: Self) -> Self { + unwrap(::checked_div(self, other)) } - fn checked_rem(self, other: Self) -> Option { - ::checked_rem(self, other) + fn aborting_rem(self, other: Self) -> Self { + unwrap(::checked_rem(self, other)) } } } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index d61a6b474cd..98a8987e1d4 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -54,11 +54,11 @@ trait Mulo: Int + ops::Neg { return result; } if sa == sb { - if abs_a > Self::max_value().checked_div(abs_b).unwrap_or_else(|| ::abort()) { + if abs_a > Self::max_value().aborting_div(abs_b) { *overflow = 1; } } else { - if abs_a > Self::min_value().checked_div(-abs_b).unwrap_or_else(|| ::abort()) { + if abs_a > Self::min_value().aborting_div(-abs_b) { *overflow = 1; } } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 6ce7ffd42ce..6dd090f394a 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -13,8 +13,7 @@ trait Div: Int { let b = (other ^ s_b).wrapping_sub(s_b); let s = s_a ^ s_b; - let r = a.unsigned().checked_div(b.unsigned()) - .unwrap_or_else(|| ::abort()); + let r = a.unsigned().aborting_div(b.unsigned()); (Self::from_unsigned(r) ^ s) - s } } @@ -32,8 +31,7 @@ trait Mod: Int { let s = self >> (Self::bits() - 1); let a = (self ^ s).wrapping_sub(s); - let r = a.unsigned().checked_rem(b.unsigned()) - .unwrap_or_else(|| ::abort()); + let r = a.unsigned().aborting_rem(b.unsigned()); (Self::from_unsigned(r) ^ s) - s } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 27baff95775..471f01d078a 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -11,11 +11,9 @@ macro_rules! udivmod_inner { // 0 X if let Some(rem) = rem { - *rem = <$ty>::from(n.low().checked_rem(d.low()) - .unwrap_or_else(|| ::abort())); + *rem = <$ty>::from(n.low().aborting_rem(d.low())); } - return <$ty>::from(n.low().checked_div(d.low()) - .unwrap_or_else(|| ::abort())); + return <$ty>::from(n.low().aborting_div(d.low())) } else { // 0 X // --- @@ -46,11 +44,9 @@ macro_rules! udivmod_inner { // --- // K 0 if let Some(rem) = rem { - *rem = <$ty>::from_parts(0, n.high().checked_rem(d.high()) - .unwrap_or_else(|| ::abort())); + *rem = <$ty>::from_parts(0, n.high().aborting_rem(d.high())); } - return <$ty>::from(n.high().checked_div(d.high()) - .unwrap_or_else(|| ::abort())); + return <$ty>::from(n.high().aborting_div(d.high())) } // K K -- cgit 1.4.1-3-g733a5 From 1614443a6886c5ba2b0ef9adc01635ed5bf70bf6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 21:36:36 -0700 Subject: Try to fix run.sh on AppVeyor --- library/compiler-builtins/appveyor.yml | 2 ++ library/compiler-builtins/ci/run.sh | 38 ++++++++++++++++++---------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 6a602132f65..1eaaf765917 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -1,4 +1,6 @@ environment: + DEBUG_LTO_BUILD_DOESNT_WORK: 1 + INTRINSICS_FAILS_WITH_MEM_FEATURE: 1 matrix: - TARGET: i686-pc-windows-msvc - TARGET: x86_64-pc-windows-msvc diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index c727bdfb969..eb60636af28 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,5 +1,19 @@ set -ex +case $1 in + thumb*) + cargo=xargo + ;; + *) + cargo=cargo + ;; +esac + +INTRINSICS_FEATURES="c" +if [ -z "$INTRINSICS_FAILS_WITH_MEM_FEATURE" ]; then + INTRINSICS_FEATURES="$INTRINSICS_FEATURES mem" +fi + # Test our implementation case $1 in thumb*) @@ -41,14 +55,7 @@ case $1 in esac # Verify that we haven't drop any intrinsic/symbol -case $1 in - thumb*) - xargo build --features 'c mem' --target $1 --example intrinsics - ;; - *) - cargo build --features 'c mem' --target $1 --example intrinsics - ;; -esac +$cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in @@ -100,16 +107,11 @@ rm -f $path # Verify that there are no undefined symbols to `panic` within our implementations # TODO(#79) fix the undefined references problem for debug-assertions+lto -case $1 in - thumb*) - RUSTFLAGS="-C debug-assertions=no" xargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles - xargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto - ;; - *) - RUSTFLAGS="-C debug-assertions=no" cargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto - cargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto - ;; -esac +if [ -z "$DEBUG_LTO_BUILD_DOESNT_WORK" ]; then + RUSTFLAGS="-C debug-assertions=no" \ + $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics -- -C lto +fi +$cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics --release -- -C lto # Ensure no references to a panicking function for rlib in $(echo $path); do -- cgit 1.4.1-3-g733a5 From 4dfb2c5f097c918f624011b401e31abdac593ad4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 21:38:55 -0700 Subject: Fix appveyor PATH --- library/compiler-builtins/appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 1eaaf765917..ebc903560f6 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -17,6 +17,7 @@ install: - git submodule update --init - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init.exe --default-host x86_64-pc-windows-msvc --default-toolchain nightly -y + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - if NOT "%TARGET%" == "x86_64-pc-windows-msvc" rustup target add %TARGET% # Use the system msys -- cgit 1.4.1-3-g733a5 From cec593c2aa1acaad439760387604fb3a1ecc2aa2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 10:04:00 -0700 Subject: Tweak testing and such: * Don't run `intrinsics` tests on thumb * Disable `compiler_builtins` attribute on `feature = "gen-tests"` * Disable mangling on `feature = "gen-tests"` instead of `cfg(test)` --- library/compiler-builtins/Cargo.toml | 7 +++++-- library/compiler-builtins/appveyor.yml | 10 +++++++++- library/compiler-builtins/ci/run.sh | 32 ++++++++++++++++++++++++-------- library/compiler-builtins/src/lib.rs | 3 ++- library/compiler-builtins/src/macros.rs | 4 ++-- 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 08bf5fd02f7..c717311d8fc 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -18,7 +18,12 @@ compiler-builtins = [] default = ["compiler-builtins"] mem = [] rustbuild = ["compiler-builtins"] + # generate tests +# +# Note that this is an internal-only feature used in testing, this should not +# be relied on with crates.io! Enabling this may expose you to breaking +# changes. gen-tests = ["cast", "rand"] [target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] @@ -26,10 +31,8 @@ test = { git = "https://github.com/japaric/utest" } utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japaric/utest" } utest-macros = { git = "https://github.com/japaric/utest" } - [[example]] name = "intrinsics" required-features = ["c", "compiler-builtins"] - [workspace] diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index ebc903560f6..e51ddab740e 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -1,17 +1,25 @@ environment: - DEBUG_LTO_BUILD_DOESNT_WORK: 1 + # It's... a little unclear why the memcpy symbols clash on linux but not on + # other platforms. Would be great to not differ on this though! INTRINSICS_FAILS_WITH_MEM_FEATURE: 1 + matrix: - TARGET: i686-pc-windows-msvc - TARGET: x86_64-pc-windows-msvc # Ensure MinGW works, but we need to download the 32-bit MinGW compiler from a # custom location. + # + # Note that the MinGW builds have tons of references to + # `rust_eh_unwind_resume` in the debug LTO builds that aren't optimized out, + # so we skip that test for now. Would be great to not skip it! - TARGET: i686-pc-windows-gnu MINGW_URL: https://s3.amazonaws.com/rust-lang-ci MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z MINGW_DIR: mingw32 + DEBUG_LTO_BUILD_DOESNT_WORK: 1 - TARGET: x86_64-pc-windows-gnu + DEBUG_LTO_BUILD_DOESNT_WORK: 1 install: - git submodule update --init diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index eb60636af28..f1acaced8e9 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -10,6 +10,10 @@ case $1 in esac INTRINSICS_FEATURES="c" + +# Some architectures like ARM apparently seem to require the `mem` feature +# enabled to successfully compile the `intrinsics` example, and... we're not +# sure why! if [ -z "$INTRINSICS_FAILS_WITH_MEM_FEATURE" ]; then INTRINSICS_FEATURES="$INTRINSICS_FEATURES mem" fi @@ -47,16 +51,13 @@ case $1 in done ;; *) - cargo test --no-default-features --features gen-tests --target $1 - cargo test --no-default-features --features 'gen-tests c' --target $1 - cargo test --no-default-features --features gen-tests --target $1 --release - cargo test --no-default-features --features 'gen-tests c' --target $1 --release + cargo test --features gen-tests --target $1 + cargo test --features 'gen-tests c' --target $1 + cargo test --features gen-tests --target $1 --release + cargo test --features 'gen-tests c' --target $1 --release ;; esac -# Verify that we haven't drop any intrinsic/symbol -$cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics - PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in armv7-*) @@ -105,7 +106,22 @@ done rm -f $path -# Verify that there are no undefined symbols to `panic` within our implementations +# Verification of the `intrinsics` program doesn't work on thumb targets right +# now. +case $1 in + thumb*) + exit 0 + ;; + *) + ;; +esac + +# Verify that we haven't drop any intrinsic/symbol +$cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics + +# Verify that there are no undefined symbols to `panic` within our +# implementations +# # TODO(#79) fix the undefined references problem for debug-assertions+lto if [ -z "$DEBUG_LTO_BUILD_DOESNT_WORK" ]; then RUSTFLAGS="-C debug-assertions=no" \ diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3fa7923b447..3f8a57edfce 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(not(stage0), deny(warnings))] #![cfg_attr(not(test), no_std)] -#![cfg_attr(feature = "compiler-builtins", compiler_builtins)] +#![cfg_attr(all(feature = "compiler-builtins", + not(feature = "gen-tests")), compiler_builtins)] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 6e34066f19f..6bf9d26fc6f 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -240,7 +240,7 @@ macro_rules! intrinsics { // This is the final catch-all rule. At this point we just generate an // intrinsic with a conditional `#[no_mangle]` directive to avoid - // interfereing with duplicate symbols and whatnot. + // interfereing with duplicate symbols and whatnot during testing. // // After the intrinsic is defined we just continue with the rest of the // input we were given. @@ -253,7 +253,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( $(#[$($attr)*])* - #[cfg_attr(not(test), no_mangle)] + #[cfg_attr(not(feature = "gen-tests"), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } -- cgit 1.4.1-3-g733a5 From cf1419e538d81446a52b0d7f00f8731b969676a1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 10:12:17 -0700 Subject: Add a FIXME for Windows --- library/compiler-builtins/ci/run.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index f1acaced8e9..2709617e7e2 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -94,9 +94,17 @@ for rlib in $(echo $path); do set +x stdout=$($PREFIX$NM -g --defined-only $rlib 2>&1) - # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it + # NOTE On i586, It's normal that the get_pc_thunk symbol appears several + # times so ignore it + # + # FIXME(#167) - we shouldn't ignore `__builtin_cl` style symbols here. set +e - echo "$stdout" | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' + echo "$stdout" | \ + sort | \ + uniq -d | \ + grep -v __x86.get_pc_thunk | \ + grep -v __builtin_cl | \ + grep 'T __' if test $? = 0; then exit 1 -- cgit 1.4.1-3-g733a5 From 90dab55cb0c3e7bb7df26167abbd0b18f56e81c0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 10:22:49 -0700 Subject: Don't try to work with `cargo test` --- library/compiler-builtins/ci/run.sh | 8 ++++---- library/compiler-builtins/src/lib.rs | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 2709617e7e2..bda44156402 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -51,10 +51,10 @@ case $1 in done ;; *) - cargo test --features gen-tests --target $1 - cargo test --features 'gen-tests c' --target $1 - cargo test --features gen-tests --target $1 --release - cargo test --features 'gen-tests c' --target $1 --release + cargo test --no-default-features --features gen-tests --target $1 + cargo test --no-default-features --features 'gen-tests c' --target $1 + cargo test --no-default-features --features gen-tests --target $1 --release + cargo test --no-default-features --features 'gen-tests c' --target $1 --release ;; esac diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3f8a57edfce..3fa7923b447 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,7 +1,6 @@ #![cfg_attr(not(stage0), deny(warnings))] #![cfg_attr(not(test), no_std)] -#![cfg_attr(all(feature = "compiler-builtins", - not(feature = "gen-tests")), compiler_builtins)] +#![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", -- cgit 1.4.1-3-g733a5 From 3eff54a4eeca72cfc10911d30eca24a4dff995c1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 11:34:10 -0700 Subject: Don't generate unmangled aeabi with gen-tests The symbols they delgate to also don't exist... --- library/compiler-builtins/src/arm.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 6e1c8f2b0b2..8d5808c82db 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -7,6 +7,7 @@ use mem::{memcpy, memmove, memset}; // calling convention which can't be implemented using a normal Rust function #[naked] #[cfg_attr(not(test), no_mangle)] +#[cfg(not(feature = "gen-tests"))] pub unsafe fn __aeabi_uidivmod() { asm!("push {lr} sub sp, sp, #4 @@ -20,6 +21,7 @@ pub unsafe fn __aeabi_uidivmod() { #[naked] #[cfg_attr(not(test), no_mangle)] +#[cfg(not(feature = "gen-tests"))] pub unsafe fn __aeabi_uldivmod() { asm!("push {r4, lr} sub sp, sp, #16 @@ -35,6 +37,7 @@ pub unsafe fn __aeabi_uldivmod() { #[naked] #[cfg_attr(not(test), no_mangle)] +#[cfg(not(feature = "gen-tests"))] pub unsafe fn __aeabi_idivmod() { asm!("push {r0, r1, r4, lr} bl __divsi3 @@ -47,6 +50,7 @@ pub unsafe fn __aeabi_idivmod() { #[naked] #[cfg_attr(not(test), no_mangle)] +#[cfg(not(feature = "gen-tests"))] pub unsafe fn __aeabi_ldivmod() { asm!("push {r4, lr} sub sp, sp, #16 -- cgit 1.4.1-3-g733a5 From e8964fc7dd5280fb29f5c99c48a1f8484b7dce55 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 11:36:05 -0700 Subject: Don't build gcc_personality_v0 --- library/compiler-builtins/build.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 06e1155bae4..bfb0ad9797d 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4138,10 +4138,6 @@ mod c { ); } } else { - if target_os != "freebsd" && target_os != "netbsd" { - sources.extend(&["gcc_personality_v0.c"]); - } - // None of these seem to be used on x86_64 windows, and they've all // got the wrong ABI anyway, so we want to avoid them. if target_os != "windows" { -- cgit 1.4.1-3-g733a5 From e7008c8609c3f017057a33ddf1e529b8e2407976 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 11:43:57 -0700 Subject: Don't check for references to panics with debug assertions --- library/compiler-builtins/ci/run.sh | 3 ++- library/compiler-builtins/src/arm.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index bda44156402..008d9ca9d44 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -125,7 +125,8 @@ case $1 in esac # Verify that we haven't drop any intrinsic/symbol -$cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics +RUSTFLAGS="-C debug-assertions=no" \ + $cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics # Verify that there are no undefined symbols to `panic` within our # implementations diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 8d5808c82db..1e234b7d885 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,3 +1,4 @@ +#[cfg(not(feature = "gen-tests"))] use core::intrinsics; #[cfg(feature = "mem")] -- cgit 1.4.1-3-g733a5 From 60028c1d9d7f64005dc785263ac7b2d3964ed8ff Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 12:22:31 -0700 Subject: Enable 128-bit integer tests on Windows Closes #158 --- library/compiler-builtins/tests/divti3.rs | 3 +-- library/compiler-builtins/tests/modti3.rs | 3 +-- library/compiler-builtins/tests/udivmodti4.rs | 3 +-- library/compiler-builtins/tests/udivti3.rs | 3 +-- library/compiler-builtins/tests/umodti3.rs | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/tests/divti3.rs b/library/compiler-builtins/tests/divti3.rs index c86785fe813..7919f8fe396 100644 --- a/library/compiler-builtins/tests/divti3.rs +++ b/library/compiler-builtins/tests/divti3.rs @@ -6,6 +6,5 @@ test), no_std)] // FIXME(#137) -// FIXME(#158) -#[cfg(not(any(target_arch = "mips", windows)))] +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/divti3.rs")); diff --git a/library/compiler-builtins/tests/modti3.rs b/library/compiler-builtins/tests/modti3.rs index 2ce42ac46f4..62129cd04d3 100644 --- a/library/compiler-builtins/tests/modti3.rs +++ b/library/compiler-builtins/tests/modti3.rs @@ -6,6 +6,5 @@ test), no_std)] // FIXME(#137) -// FIXME(#158) -#[cfg(not(any(target_arch = "mips", windows)))] +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/modti3.rs")); diff --git a/library/compiler-builtins/tests/udivmodti4.rs b/library/compiler-builtins/tests/udivmodti4.rs index 5629d617bd3..8185ec0e789 100644 --- a/library/compiler-builtins/tests/udivmodti4.rs +++ b/library/compiler-builtins/tests/udivmodti4.rs @@ -6,6 +6,5 @@ test), no_std)] // FIXME(#137) -// FIXME(#158) -#[cfg(not(any(target_arch = "mips", windows)))] +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/udivmodti4.rs")); diff --git a/library/compiler-builtins/tests/udivti3.rs b/library/compiler-builtins/tests/udivti3.rs index 350922563ff..cefddda8f86 100644 --- a/library/compiler-builtins/tests/udivti3.rs +++ b/library/compiler-builtins/tests/udivti3.rs @@ -6,6 +6,5 @@ test), no_std)] // FIXME(#137) -// FIXME(#158) -#[cfg(not(any(target_arch = "mips", windows)))] +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/udivti3.rs")); diff --git a/library/compiler-builtins/tests/umodti3.rs b/library/compiler-builtins/tests/umodti3.rs index 5807bcff395..57e651b2710 100644 --- a/library/compiler-builtins/tests/umodti3.rs +++ b/library/compiler-builtins/tests/umodti3.rs @@ -6,6 +6,5 @@ test), no_std)] // FIXME(#137) -// FIXME(#158) -#[cfg(not(any(target_arch = "mips", windows)))] +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/umodti3.rs")); -- cgit 1.4.1-3-g733a5 From f9db3c5b324beef1dd81bd471c13e51d9168a687 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 12:44:00 -0700 Subject: Don't test mangled names on thumb We are both the "real compiler-rt" and the "to be tested one". --- library/compiler-builtins/Cargo.toml | 1 + library/compiler-builtins/ci/run.sh | 9 ++++---- library/compiler-builtins/src/arm.rs | 37 ++++++++++++++------------------- library/compiler-builtins/src/macros.rs | 2 +- library/compiler-builtins/src/mem.rs | 8 +++---- 5 files changed, 27 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c717311d8fc..070d8f8c7a0 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -18,6 +18,7 @@ compiler-builtins = [] default = ["compiler-builtins"] mem = [] rustbuild = ["compiler-builtins"] +mangled-names = [] # generate tests # diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 008d9ca9d44..d285b366538 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -51,10 +51,11 @@ case $1 in done ;; *) - cargo test --no-default-features --features gen-tests --target $1 - cargo test --no-default-features --features 'gen-tests c' --target $1 - cargo test --no-default-features --features gen-tests --target $1 --release - cargo test --no-default-features --features 'gen-tests c' --target $1 --release + run="cargo test --no-default-features --target $1" + $run --features 'gen-tests mangled-names' + $run --features 'gen-tests mangled-names' --release + $run --features 'gen-tests mangled-names c' + $run --features 'gen-tests mangled-names c' --release ;; esac diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 1e234b7d885..81e0afdd00b 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,4 +1,3 @@ -#[cfg(not(feature = "gen-tests"))] use core::intrinsics; #[cfg(feature = "mem")] @@ -7,8 +6,7 @@ use mem::{memcpy, memmove, memset}; // NOTE This function and the ones below are implemented using assembly because they using a custom // calling convention which can't be implemented using a normal Rust function #[naked] -#[cfg_attr(not(test), no_mangle)] -#[cfg(not(feature = "gen-tests"))] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uidivmod() { asm!("push {lr} sub sp, sp, #4 @@ -21,8 +19,7 @@ pub unsafe fn __aeabi_uidivmod() { } #[naked] -#[cfg_attr(not(test), no_mangle)] -#[cfg(not(feature = "gen-tests"))] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uldivmod() { asm!("push {r4, lr} sub sp, sp, #16 @@ -37,8 +34,7 @@ pub unsafe fn __aeabi_uldivmod() { } #[naked] -#[cfg_attr(not(test), no_mangle)] -#[cfg(not(feature = "gen-tests"))] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_idivmod() { asm!("push {r0, r1, r4, lr} bl __divsi3 @@ -50,8 +46,7 @@ pub unsafe fn __aeabi_idivmod() { } #[naked] -#[cfg_attr(not(test), no_mangle)] -#[cfg(not(feature = "gen-tests"))] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_ldivmod() { asm!("push {r4, lr} sub sp, sp, #16 @@ -75,55 +70,55 @@ extern "C" { // FIXME: The `*4` and `*8` variants should be defined as aliases. -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } // Note the different argument order -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { memset(dest, 0, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { memset(dest, 0, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { memset(dest, 0, n); } diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 6bf9d26fc6f..188508f5cc6 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -253,7 +253,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( $(#[$($attr)*])* - #[cfg_attr(not(feature = "gen-tests"), no_mangle)] + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index a7d267c5003..cb8baec273e 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -5,7 +5,7 @@ type c_int = i16; #[cfg(not(target_pointer_width = "16"))] type c_int = i32; -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) @@ -18,7 +18,7 @@ pub unsafe extern "C" fn memcpy(dest: *mut u8, dest } -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) @@ -41,7 +41,7 @@ pub unsafe extern "C" fn memmove(dest: *mut u8, dest } -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { let mut i = 0; while i < n { @@ -51,7 +51,7 @@ pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { s } -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { let mut i = 0; while i < n { -- cgit 1.4.1-3-g733a5 From 0e404583e82cd044b9561e493b3997609cb0fafa Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 21:51:34 -0700 Subject: Address review comments --- library/compiler-builtins/src/macros.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 188508f5cc6..f6d7db70934 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -3,8 +3,8 @@ /// The "main macro" used for defining intrinsics. /// /// The compiler-builtins library is super platform-specific with tons of crazy -/// little tweaks for various platforms. As a result it *could* involve a lot fo -/// #[cfg] and macro soup, but the intention is that this macro alleviates a lof +/// little tweaks for various platforms. As a result it *could* involve a lot of +/// #[cfg] and macro soup, but the intention is that this macro alleviates a lot /// of that complexity. Ideally this macro has all the weird ABI things /// platforms need and elsewhere in this library it just looks like normal Rust /// code. @@ -220,10 +220,6 @@ macro_rules! intrinsics { pub extern "aapcs" fn $alias( $($argname: $ty),* ) -> $ret { super::$name($($argname),*) } - - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { - super::$name($($argname),*) - } } } -- cgit 1.4.1-3-g733a5 From 6792390e3ef1d6eae76802949a07859d9eaabcb7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 25 Jun 2017 09:25:54 -0700 Subject: Enable the `intrinsics` program on thumb --- library/compiler-builtins/ci/run.sh | 12 +----------- library/compiler-builtins/examples/intrinsics.rs | 14 ++++++++++++-- library/compiler-builtins/src/arm.rs | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index d285b366538..9562b7fd8a9 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -115,19 +115,9 @@ done rm -f $path -# Verification of the `intrinsics` program doesn't work on thumb targets right -# now. -case $1 in - thumb*) - exit 0 - ;; - *) - ;; -esac - # Verify that we haven't drop any intrinsic/symbol RUSTFLAGS="-C debug-assertions=no" \ - $cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics + $cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics -v # Verify that there are no undefined symbols to `panic` within our # implementations diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 7db241eddbb..e7c55e835ed 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -12,13 +12,14 @@ #![feature(core_float)] #![feature(lang_items)] #![feature(start)] -#![feature(panic_unwind)] #![feature(i128_type)] +#![cfg_attr(windows, feature(panic_unwind))] #![no_std] #[cfg(not(thumb))] extern crate alloc_system; extern crate compiler_builtins; +#[cfg(windows)] extern crate panic_unwind; // NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even @@ -444,7 +445,16 @@ pub fn __aeabi_unwind_cpp_pr0() {} #[no_mangle] pub fn __aeabi_unwind_cpp_pr1() {} -#[cfg(not(test))] +#[cfg(not(windows))] +#[allow(non_snake_case)] +#[no_mangle] +pub fn _Unwind_Resume() {} + +#[cfg(not(windows))] +#[lang = "eh_personality"] +#[no_mangle] +pub extern "C" fn eh_personality() {} + #[lang = "panic_fmt"] #[no_mangle] #[allow(private_no_mangle_fns)] diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 81e0afdd00b..389bf9aaa96 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -37,7 +37,7 @@ pub unsafe fn __aeabi_uldivmod() { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_idivmod() { asm!("push {r0, r1, r4, lr} - bl __divsi3 + bl __aeabi_idiv pop {r1, r2} muls r2, r2, r0 subs r1, r1, r2 -- cgit 1.4.1-3-g733a5 From 326c0bb597ddda686ef6e11d446e026eac026b7b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 27 Jun 2017 22:48:57 -0500 Subject: enable tests now that #150 has been fixed --- library/compiler-builtins/ci/run.sh | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 9562b7fd8a9..c37ca489f93 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -31,18 +31,6 @@ case $1 in ;; esac - # FIXME(#150) debug assertion in divmoddi4 - case $1 in - thumbv6m-*) - case $t in - divdi3 | divmoddi4 | moddi3 | modsi3 | udivmoddi4 | udivmodsi4 | umoddi3 | \ - umodsi3) - continue - ;; - esac - ;; - esac - xargo test --test $t --target $1 --features 'mem gen-tests' --no-run qemu-arm-static target/${1}/debug/$t-* -- cgit 1.4.1-3-g733a5 From f096e02f636eeade93dedfd6659ffe16d3e192f0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 29 Jun 2017 22:40:58 -0500 Subject: optimize 32-bit aligned mem{cpy,clr,set} intrinsics for ARM this reduces the execution time of all these routines by 40-70% --- library/compiler-builtins/src/arm.rs | 82 ++++--- library/compiler-builtins/src/lib.rs | 2 +- library/compiler-builtins/src/mem.rs | 8 +- library/compiler-builtins/tests/aeabi_memclr.rs | 58 +++++ library/compiler-builtins/tests/aeabi_memcpy.rs | 69 ++++++ library/compiler-builtins/tests/aeabi_memset.rs | 274 ++++++++++++++++++++++++ 6 files changed, 463 insertions(+), 30 deletions(-) create mode 100644 library/compiler-builtins/tests/aeabi_memclr.rs create mode 100644 library/compiler-builtins/tests/aeabi_memcpy.rs create mode 100644 library/compiler-builtins/tests/aeabi_memset.rs diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 389bf9aaa96..227ab0515f5 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,7 +1,6 @@ -use core::intrinsics; +use core::{intrinsics, ptr}; -#[cfg(feature = "mem")] -use mem::{memcpy, memmove, memset}; +use mem; // NOTE This function and the ones below are implemented using assembly because they using a custom // calling convention which can't be implemented using a normal Rust function @@ -60,65 +59,98 @@ pub unsafe fn __aeabi_ldivmod() { intrinsics::unreachable(); } -// TODO: These aeabi_* functions should be defined as aliases -#[cfg(not(feature = "mem"))] -extern "C" { - fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; - fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; - fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8; -} - // FIXME: The `*4` and `*8` variants should be defined as aliases. #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { - memcpy(dest, src, n); + mem::memcpy(dest, src, n); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { - memcpy(dest, src, n); +#[linkage = "weak"] +pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) { + let mut dest = dest as *mut u32; + let mut src = src as *mut u32; + + while n >= 4 { + ptr::write(dest, ptr::read(src)); + dest = dest.offset(1); + src = src.offset(1); + n -= 4; + } + + __aeabi_memcpy(dest as *mut u8, src as *const u8, n); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { - memcpy(dest, src, n); + __aeabi_memcpy4(dest, src, n); } #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { - memmove(dest, src, n); + mem::memmove(dest, src, n); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { - memmove(dest, src, n); + __aeabi_memmove(dest, src, n); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { - memmove(dest, src, n); + __aeabi_memmove(dest, src, n); } // Note the different argument order #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { - memset(dest, c, n); + mem::memset(dest, c, n); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { - memset(dest, c, n); +#[linkage = "weak"] +pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) { + let mut dest = dest as *mut u32; + + let byte = (c as u32) & 0xff; + let c = (byte << 24) | (byte << 16) | (byte << 8) | byte; + + while n >= 4 { + ptr::write(dest, c); + dest = dest.offset(1); + n -= 4; + } + + __aeabi_memset(dest as *mut u8, n, byte as i32); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { - memset(dest, c, n); + __aeabi_memset4(dest, n, c); } #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { - memset(dest, 0, n); + __aeabi_memset(dest, n, 0); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { - memset(dest, 0, n); + __aeabi_memset4(dest, n, 0); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { - memset(dest, 0, n); + __aeabi_memset4(dest, n, 0); } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3fa7923b447..39bf854d09c 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -16,6 +16,7 @@ #![feature(i128_type)] #![feature(repr_simd)] #![feature(abi_unadjusted)] +#![feature(linkage)] #![allow(unused_features)] #![no_builtins] #![unstable(feature = "compiler_builtins_lib", @@ -45,7 +46,6 @@ mod macros; pub mod int; pub mod float; -#[cfg(feature = "mem")] pub mod mem; #[cfg(target_arch = "arm")] diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index cb8baec273e..c56391c4d3d 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -5,7 +5,7 @@ type c_int = i16; #[cfg(not(target_pointer_width = "16"))] type c_int = i32; -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) @@ -18,7 +18,7 @@ pub unsafe extern "C" fn memcpy(dest: *mut u8, dest } -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) @@ -41,7 +41,7 @@ pub unsafe extern "C" fn memmove(dest: *mut u8, dest } -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { let mut i = 0; while i < n { @@ -51,7 +51,7 @@ pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { s } -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { let mut i = 0; while i < n { diff --git a/library/compiler-builtins/tests/aeabi_memclr.rs b/library/compiler-builtins/tests/aeabi_memclr.rs new file mode 100644 index 00000000000..72e944e4c74 --- /dev/null +++ b/library/compiler-builtins/tests/aeabi_memclr.rs @@ -0,0 +1,58 @@ +#![cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem"))] +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; + +// test runner +extern crate utest_cortex_m_qemu; + +// overrides `panic!` +#[macro_use] +extern crate utest_macros; + +use core::mem; + +macro_rules! panic { + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} + +extern "C" { + fn __aeabi_memclr4(dest: *mut u8, n: usize); + fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); +} + +struct Aligned { + array: [u8; 8], + _alignment: [u32; 0], +} + +impl Aligned { + fn new() -> Self { + Aligned { + array: [0; 8], + _alignment: [], + } + } +} + +#[test] +fn memclr4() { + let mut aligned = Aligned::new();; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + + for n in 0..9 { + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, 0xff); + __aeabi_memclr4(xs.as_mut_ptr(), n); + } + + assert!(xs[0..n].iter().all(|x| *x == 0)); + } +} diff --git a/library/compiler-builtins/tests/aeabi_memcpy.rs b/library/compiler-builtins/tests/aeabi_memcpy.rs new file mode 100644 index 00000000000..2ba942c23c1 --- /dev/null +++ b/library/compiler-builtins/tests/aeabi_memcpy.rs @@ -0,0 +1,69 @@ +#![cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem"))] +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; + +// test runner +extern crate utest_cortex_m_qemu; + +// overrides `panic!` +#[macro_use] +extern crate utest_macros; + +macro_rules! panic { + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} + +extern "C" { + fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize); + fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize); +} + +struct Aligned { + array: [u8; 8], + _alignment: [u32; 0], +} + +impl Aligned { + fn new(array: [u8; 8]) -> Self { + Aligned { + array: array, + _alignment: [], + } + } +} + +#[test] +fn memcpy() { + let mut dest = [0; 4]; + let src = [0xde, 0xad, 0xbe, 0xef]; + + for n in 0..dest.len() { + dest.copy_from_slice(&[0; 4]); + + unsafe { __aeabi_memcpy(dest.as_mut_ptr(), src.as_ptr(), n) } + + assert_eq!(&dest[0..n], &src[0..n]) + } +} + +#[test] +fn memcpy4() { + let mut aligned = Aligned::new([0; 8]); + let dest = &mut aligned.array; + let src = [0xde, 0xad, 0xbe, 0xef, 0xba, 0xad, 0xf0, 0x0d]; + + for n in 0..dest.len() { + dest.copy_from_slice(&[0; 8]); + + unsafe { __aeabi_memcpy4(dest.as_mut_ptr(), src.as_ptr(), n) } + + assert_eq!(&dest[0..n], &src[0..n]) + } +} diff --git a/library/compiler-builtins/tests/aeabi_memset.rs b/library/compiler-builtins/tests/aeabi_memset.rs new file mode 100644 index 00000000000..0919f149124 --- /dev/null +++ b/library/compiler-builtins/tests/aeabi_memset.rs @@ -0,0 +1,274 @@ +#![cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem"))] +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; + +// test runner +extern crate utest_cortex_m_qemu; + +// overrides `panic!` +#[macro_use] +extern crate utest_macros; + +use core::mem; + +macro_rules! panic { + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} + +extern "C" { + fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); +} + +struct Aligned { + array: [u8; 8], + _alignment: [u32; 0], +} + +impl Aligned { + fn new(array: [u8; 8]) -> Self { + Aligned { + array: array, + _alignment: [], + } + } +} + +#[test] +fn zero() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), 0, c) + } + + assert_eq!(*xs, [0; 8]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), 0, c) + } + + assert_eq!(*xs, [1; 8]); +} + +#[test] +fn one() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 1; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0, 0, 0, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 1, 1, 1, 1, 1, 1, 1]); +} + +#[test] +fn two() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 2; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0, 0, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 1, 1, 1, 1, 1, 1]); +} + +#[test] +fn three() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 3; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 1, 1, 1, 1, 1]); +} + +#[test] +fn four() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 4; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 1, 1, 1, 1]); +} + +#[test] +fn five() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 5; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 1, 1, 1]); +} + +#[test] +fn six() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 6; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1, 1]); +} + +#[test] +fn seven() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 7; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1]); +} + +#[test] +fn eight() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 8; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); +} -- cgit 1.4.1-3-g733a5 From b9d62916825a11ebaf06df2598b23404df57a30a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Jun 2017 18:06:25 -0500 Subject: no aeabi_mem* symbols on iOS, weak symbols on thumb, normal symbols elsewhere --- library/compiler-builtins/src/arm.rs | 38 ++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 227ab0515f5..b72ff97ea31 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -61,14 +61,16 @@ pub unsafe fn __aeabi_ldivmod() { // FIXME: The `*4` and `*8` variants should be defined as aliases. +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { mem::memcpy(dest, src, n); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) { let mut dest = dest as *mut u32; let mut src = src as *mut u32; @@ -83,39 +85,45 @@ pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut __aeabi_memcpy(dest as *mut u8, src as *const u8, n); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memcpy4(dest, src, n); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { mem::memmove(dest, src, n); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } -// Note the different argument order +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { + // Note the different argument order mem::memset(dest, c, n); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) { let mut dest = dest as *mut u32; @@ -131,26 +139,30 @@ pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32 __aeabi_memset(dest as *mut u8, n, byte as i32); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { __aeabi_memset4(dest, n, c); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { __aeabi_memset(dest, n, 0); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } -- cgit 1.4.1-3-g733a5 From 37538e8c2a6855595f84fec4e322eaddab775119 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 1 Jul 2017 00:31:45 -0700 Subject: Update compiler-rt submodule Needed to pull in some recent changes with rust-lang/rust --- library/compiler-builtins/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index 3bc0272cab9..c8a8767c56a 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79 +Subproject commit c8a8767c56ad3d3f4eb45c87b95026936fb9aa35 -- cgit 1.4.1-3-g733a5 From e48cd1180be56826f4b53503627c9fabfab8deaf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 3 Jul 2017 08:16:01 -0700 Subject: Use the Rust implementation of udivsi3 on ARM Although compiler-rt presumably has a more optimized implementation written in assembly, it appears buggy for whatever reason, causing #173. For now let's see if integration into rust-lang/rust will work with the Rust-defined implementation! --- library/compiler-builtins/build.rs | 17 +++++++++++++---- library/compiler-builtins/src/int/sdiv.rs | 1 - library/compiler-builtins/src/int/udiv.rs | 3 --- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index bfb0ad9797d..17df4b6435a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4196,7 +4196,6 @@ mod c { "arm/clzsi2.S", "arm/comparesf2.S", "arm/divmodsi4.S", - "arm/divsi3.S", "arm/modsi3.S", "arm/switch16.S", "arm/switch32.S", @@ -4204,8 +4203,20 @@ mod c { "arm/switchu8.S", "arm/sync_synchronize.S", "arm/udivmodsi4.S", - "arm/udivsi3.S", "arm/umodsi3.S", + + // Exclude these two files for now even though we haven't + // translated their implementation into Rust yet (#173). + // They appear... buggy? The `udivsi3` implementation was + // the one that seemed buggy, but the `divsi3` file + // references a symbol from `udivsi3` so we compile them + // both with the Rust versions. + // + // Note that if these are added back they should be removed + // from thumbv6m below. + // + // "arm/divsi3.S", + // "arm/udivsi3.S", ], ); } @@ -4315,14 +4326,12 @@ mod c { "clzsi2", "comparesf2", "divmodsi4", - "divsi3", "modsi3", "switch16", "switch32", "switch8", "switchu8", "udivmodsi4", - "udivsi3", "umodsi3", ], ); diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 6dd090f394a..c949c3394d2 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -57,7 +57,6 @@ impl Divmod for i32 {} impl Divmod for i64 {} intrinsics! { - #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] #[arm_aeabi_alias = __aeabi_idiv] pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { a.div(b) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 471f01d078a..de276147e3d 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -148,9 +148,6 @@ macro_rules! udivmod_inner { } intrinsics! { - #[use_c_shim_if(all(target_arch = "arm", - not(target_os = "ios"), - not(thumbv6m)))] #[arm_aeabi_alias = __aeabi_uidiv] /// Returns `n / d` pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { -- cgit 1.4.1-3-g733a5 From ebcf7fac6a90bb4b5deaf7fda4ad71d3a00a7b2e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 3 Jul 2017 14:57:42 -0700 Subject: Compile ffsdi2 with `rustbuild` feature This is not used by LLVM/Rust, but is apparently used by gcc/C which jemalloc can require at least. --- library/compiler-builtins/README.md | 4 +++- library/compiler-builtins/build.rs | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 5f59b44b1a8..a0e2a29ed15 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -306,7 +306,7 @@ These builtins are never called by LLVM. - ~~ctzdi2.c~~ - ~~ctzsi2.c~~ - ~~ctzti2.c~~ -- ~~ffsdi2.c~~ +- ~~ffsdi2.c~~ - this is [called by gcc][jemalloc-fail] though! - ~~ffsti2.c~~ - ~~mulvdi3.c~~ - ~~mulvsi3.c~~ @@ -333,6 +333,8 @@ These builtins are never called by LLVM. - ~~ucmpti2.c~~ - ~~udivmodti4.c~~ +[jemalloc-fail]: https://travis-ci.org/rust-lang/rust/jobs/249772758 + Rust only exposes atomic types on platforms that support them, and therefore does not need to fall back to software implementations. - ~~arm/sync_fetch_and_add_4.S~~ diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 17df4b6435a..22196455413 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4095,6 +4095,16 @@ mod c { ], ); + // When compiling in rustbuild (the rust-lang/rust repo) this library + // also needs to satisfy intrinsics that jemalloc or C in general may + // need, so include a few more that aren't typically needed by + // LLVM/Rust. + if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { + sources.exend(&[ + "ffsdi2.c", + ]); + } + if target_os != "ios" { sources.extend( &[ -- cgit 1.4.1-3-g733a5 From a32ae6d6b6c660b021663f4def7a6f8419cc8657 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 3 Jul 2017 15:28:03 -0700 Subject: Fix a typo in the build script --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 22196455413..d4c4ad247de 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4100,7 +4100,7 @@ mod c { // need, so include a few more that aren't typically needed by // LLVM/Rust. if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { - sources.exend(&[ + sources.extend(&[ "ffsdi2.c", ]); } -- cgit 1.4.1-3-g733a5 From 79b55c48ca5f657aab2ced4067c07c93cdff96d6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 3 Jul 2017 19:11:34 -0700 Subject: Fix unused imports on iOS --- library/compiler-builtins/src/arm.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index b72ff97ea31..fa86e969146 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,6 +1,4 @@ -use core::{intrinsics, ptr}; - -use mem; +use core::intrinsics; // NOTE This function and the ones below are implemented using assembly because they using a custom // calling convention which can't be implemented using a normal Rust function @@ -65,13 +63,15 @@ pub unsafe fn __aeabi_ldivmod() { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { - mem::memcpy(dest, src, n); + ::mem::memcpy(dest, src, n); } #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) { + use core::ptr; + let mut dest = dest as *mut u32; let mut src = src as *mut u32; @@ -96,7 +96,7 @@ pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: u #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { - mem::memmove(dest, src, n); + ::mem::memmove(dest, src, n); } #[cfg(not(target_os = "ios"))] @@ -118,13 +118,15 @@ pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { // Note the different argument order - mem::memset(dest, c, n); + ::mem::memset(dest, c, n); } #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) { + use core::ptr; + let mut dest = dest as *mut u32; let byte = (c as u32) & 0xff; -- cgit 1.4.1-3-g733a5 From f771aac37a2ca080f86b4731fe702ce7359a22de Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Jul 2017 22:18:19 -0700 Subject: Add `__rust_probestack` intrinsic Will be required for rust-lang/rust#42816 --- library/compiler-builtins/src/lib.rs | 2 + library/compiler-builtins/src/probestack.rs | 112 ++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 library/compiler-builtins/src/probestack.rs diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 39bf854d09c..b8cf83e2125 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -53,3 +53,5 @@ pub mod arm; #[cfg(target_arch = "x86_64")] pub mod x86_64; + +pub mod probestack; diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs new file mode 100644 index 00000000000..e59fe861a7e --- /dev/null +++ b/library/compiler-builtins/src/probestack.rs @@ -0,0 +1,112 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module defines the `__rust_probestack` intrinsic which is used in the +//! implementation of "stack probes" on certain platforms. +//! +//! The purpose of a stack probe is to provide a static guarantee that if a +//! thread has a guard page then a stack overflow is guaranteed to hit that +//! guard page. If a function did not have a stack probe then there's a risk of +//! having a stack frame *larger* than the guard page, so a function call could +//! skip over the guard page entirely and then later hit maybe the heap or +//! another thread, possibly leading to security vulnerabilities such as [The +//! Stack Clash], for example. +//! +//! [The Stack Clash]: https://blog.qualys.com/securitylabs/2017/06/19/the-stack-clash +//! +//! The `__rust_probestack` is called in the prologue of functions whose stack +//! size is larger than the guard page, for example larger than 4096 bytes on +//! x86. This function is then responsible for "touching" all pages relevant to +//! the stack to ensure that that if any of them are the guard page we'll hit +//! them guaranteed. +//! +//! The precise ABI for how this function operates is defined by LLVM. There's +//! no real documentation as to what this is, so you'd basically need to read +//! the LLVM source code for reference. Often though the test cases can be +//! illuminating as to the ABI that's generated, or just looking at the output +//! of `llc`. +//! +//! Note that `#[naked]` is typically used here for the stack probe because the +//! ABI corresponds to no actual ABI. +//! +//! Finally it's worth noting that at the time of this writing LLVM only has +//! support for stack probes on x86 and x86_64. There's no support for stack +//! probes on any other architecture like ARM or PowerPC64. LLVM I'm sure would +//! be more than welcome to accept such a change! + +#![cfg(not(windows))] // Windows already has builtins to do this + +#[naked] +#[no_mangle] +#[cfg(target_arch = "x86_64")] +pub unsafe extern fn __rust_probestack() { + // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, + // ensuring that if any pages are unmapped we'll make a page fault. + // + // The ABI here is that the stack frame size is located in `%eax`. Upon + // return we're not supposed to modify `%esp` or `%eax`. + asm!(" + lea 8(%rsp),%r11 // rsp before calling this routine -> r11 + + // Main loop, taken in one page increments. We're decrementing r11 by + // a page each time until there's less than a page remaining. We're + // guaranteed that this function isn't called unless there's more than a + // page needed + 2: + sub $$0x1000,%r11 + test %r11,(%r11) + sub $$0x1000,%rax + cmp $$0x1000,%rax + ja 2b + + // Finish up the last remaining stack space requested, getting the last + // bits out of rax + sub %rax,%r11 + test %r11,(%r11) + + // We now know that %r11 is (%rsp + 8 - %rax) so to recover rax + // we calculate (%rsp + 8) - %r11 which will give us %rax + lea 8(%rsp),%rax + sub %r11,%rax + + ret + "); + ::core::intrinsics::unreachable(); +} + +#[naked] +#[no_mangle] +#[cfg(target_arch = "x86")] +pub unsafe extern fn __rust_probestack() { + // This is the same as x86_64 above, only translated for 32-bit sizes. Note + // that on Unix we're expected to restore everything as it was, this + // function basically can't tamper with anything. + // + // The ABI here is the same as x86_64, except everything is 32-bits large. + asm!(" + push %ecx + lea 8(%esp),%ecx + 2: + sub $$0x1000,%ecx + test %ecx,(%ecx) + sub $$0x1000,%eax + cmp $$0x1000,%eax + ja 2b + + sub %eax,%ecx + test %ecx,(%ecx) + + lea 8(%esp),%eax + sub %ecx,%eax + pop %ecx + ret + "); + ::core::intrinsics::unreachable(); +} -- cgit 1.4.1-3-g733a5 From f4e92e379c010913b8adda7273b41198e31d4c9a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 7 Jul 2017 10:16:03 -0700 Subject: Tweak definition of probestack functions It looks like the old `__rust_probestack` routine is incompatible with newer linux kernels. My best guess for this is that the kernel's auto-growth logic is failing to trigger, causing what looks like a legitimate segfault to get delivered. My best guess for why *that's* happening is that the faulting address is below `%rsp`, whereas previously all faulting stack addresses were above `%rsp`. The probestack routine does not modify `%rsp` as it's probing the stack, and presumably newer kernels are interpreting this as a legitimate violation. This commit tweaks the probestack routine to instead update `%rsp` incrementally as probing happens. The ABI of the function, however, requires that `%rsp` isn't changed as part of the function so it's restored at the end to the previous value. --- library/compiler-builtins/src/probestack.rs | 46 ++++++++++++++++------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index e59fe861a7e..e1224fe7ace 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -53,28 +53,33 @@ pub unsafe extern fn __rust_probestack() { // The ABI here is that the stack frame size is located in `%eax`. Upon // return we're not supposed to modify `%esp` or `%eax`. asm!(" - lea 8(%rsp),%r11 // rsp before calling this routine -> r11 + mov %rax,%r11 // duplicate %rax as we're clobbering %r11 - // Main loop, taken in one page increments. We're decrementing r11 by + // Main loop, taken in one page increments. We're decrementing rsp by // a page each time until there's less than a page remaining. We're // guaranteed that this function isn't called unless there's more than a - // page needed + // page needed. + // + // Note that we're also testing against `8(%rsp)` to account for the 8 + // bytes pushed on the stack orginally with our return address. Using + // `8(%rsp)` simulates us testing the stack pointer in the caller's + // context. 2: + sub $$0x1000,%rsp + test %rsp,8(%rsp) sub $$0x1000,%r11 - test %r11,(%r11) - sub $$0x1000,%rax - cmp $$0x1000,%rax + cmp $$0x1000,%r11 ja 2b // Finish up the last remaining stack space requested, getting the last - // bits out of rax - sub %rax,%r11 - test %r11,(%r11) + // bits out of r11 + sub %r11,%rsp + test %rsp,8(%rsp) - // We now know that %r11 is (%rsp + 8 - %rax) so to recover rax - // we calculate (%rsp + 8) - %r11 which will give us %rax - lea 8(%rsp),%rax - sub %r11,%rax + // Restore the stack pointer to what it previously was when entering + // this function. The caller will readjust the stack pointer after we + // return. + add %rax,%rsp ret "); @@ -92,19 +97,18 @@ pub unsafe extern fn __rust_probestack() { // The ABI here is the same as x86_64, except everything is 32-bits large. asm!(" push %ecx - lea 8(%esp),%ecx + mov %eax,%ecx 2: + sub $$0x1000,%esp + test %esp,8(%esp) sub $$0x1000,%ecx - test %ecx,(%ecx) - sub $$0x1000,%eax - cmp $$0x1000,%eax + cmp $$0x1000,%ecx ja 2b - sub %eax,%ecx - test %ecx,(%ecx) + sub %ecx,%esp + test %esp,8(%esp) - lea 8(%esp),%eax - sub %ecx,%eax + add %eax,%esp pop %ecx ret "); -- cgit 1.4.1-3-g733a5 From 2fa53c4b67702063258f6464fea6ed50a6b949a7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 7 Jul 2017 11:20:04 -0700 Subject: Don't mangle probes all the time --- library/compiler-builtins/build.rs | 19 +++++++++++-------- library/compiler-builtins/ci/run.sh | 1 + library/compiler-builtins/examples/intrinsics.rs | 6 ++++++ library/compiler-builtins/src/float/conv.rs | 5 +++-- library/compiler-builtins/src/probestack.rs | 4 ++-- library/compiler-builtins/src/x86_64.rs | 6 +++--- 6 files changed, 26 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d4c4ad247de..25cc5204d2e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -21,9 +21,14 @@ fn main() { #[cfg(feature = "gen-tests")] tests::generate(); - // Build missing intrinsics from compiler-rt C source code - #[cfg(feature = "c")] - c::compile(&llvm_target); + // Build missing intrinsics from compiler-rt C source code. If we're + // mangling names though we assume that we're also in test mode so we don't + // build anything and we rely on the upstream implementation of compiler-rt + // functions + if !cfg!(feature = "mangled-names") { + #[cfg(feature = "c")] + c::compile(&llvm_target); + } // To compile intrinsics.rs for thumb targets, where there is no libc if llvm_target[0].starts_with("thumb") { @@ -4099,11 +4104,9 @@ mod c { // also needs to satisfy intrinsics that jemalloc or C in general may // need, so include a few more that aren't typically needed by // LLVM/Rust. - if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { - sources.extend(&[ - "ffsdi2.c", - ]); - } + sources.extend(&[ + "ffsdi2.c", + ]); if target_os != "ios" { sources.extend( diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index c37ca489f93..9a32ee9ea64 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -93,6 +93,7 @@ for rlib in $(echo $path); do uniq -d | \ grep -v __x86.get_pc_thunk | \ grep -v __builtin_cl | \ + grep -v __builtin_ctz | \ grep 'T __' if test $? = 0; then diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index e7c55e835ed..3820887895d 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -13,6 +13,8 @@ #![feature(lang_items)] #![feature(start)] #![feature(i128_type)] +#![feature(global_allocator)] +#![feature(allocator_api)] #![cfg_attr(windows, feature(panic_unwind))] #![no_std] @@ -22,6 +24,10 @@ extern crate compiler_builtins; #[cfg(windows)] extern crate panic_unwind; +#[cfg(not(thumb))] +#[global_allocator] +static A: alloc_system::System = alloc_system::System; + // NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even // compiler-rt provides a C/assembly implementation. diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index e12349cfff9..f2fd01d37b0 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -112,8 +112,9 @@ intrinsics! { int_to_float!(i, u32, f64) } - #[use_c_shim_if(all(any(target_arch = "x86", target_arch = "x86_64"), - not(windows)))] + #[use_c_shim_if(all(not(target_env = "msvc"), + any(target_arch = "x86", + all(not(windows), target_arch = "x86_64"))))] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float!(i, u64, f64) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index e1224fe7ace..329e2726511 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -44,7 +44,7 @@ #![cfg(not(windows))] // Windows already has builtins to do this #[naked] -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg(target_arch = "x86_64")] pub unsafe extern fn __rust_probestack() { // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, @@ -87,7 +87,7 @@ pub unsafe extern fn __rust_probestack() { } #[naked] -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg(target_arch = "x86")] pub unsafe extern fn __rust_probestack() { // This is the same as x86_64 above, only translated for 32-bit sizes. Note diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 072f964dd70..64cc06c9834 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -10,7 +10,7 @@ use core::intrinsics; #[cfg(windows)] #[naked] -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn ___chkstk_ms() { asm!("push %rcx push %rax @@ -34,7 +34,7 @@ pub unsafe fn ___chkstk_ms() { #[cfg(windows)] #[naked] -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __alloca() { asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); @@ -43,7 +43,7 @@ pub unsafe fn __alloca() { #[cfg(windows)] #[naked] -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn ___chkstk() { asm!("push %rcx cmp $$0x1000,%rax -- cgit 1.4.1-3-g733a5 From 45a7693962e75ae0653645328aa2c78e8708cb24 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Wed, 12 Jul 2017 22:40:49 +0100 Subject: Don't include custom chkstk on MSVC MSVC includes its own __chkstk so these aren't used. --- library/compiler-builtins/src/x86_64.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 64cc06c9834..bc3c4ee4c55 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -8,7 +8,7 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca -#[cfg(windows)] +#[cfg(all(windows, target_env = "gnu"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn ___chkstk_ms() { @@ -32,7 +32,7 @@ pub unsafe fn ___chkstk_ms() { intrinsics::unreachable(); } -#[cfg(windows)] +#[cfg(all(windows, target_env = "gnu"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __alloca() { @@ -41,7 +41,7 @@ pub unsafe fn __alloca() { intrinsics::unreachable(); } -#[cfg(windows)] +#[cfg(all(windows, target_env = "gnu"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn ___chkstk() { -- cgit 1.4.1-3-g733a5 From e377364051476d90183aa916b0d375b86a6079a8 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sat, 22 Jul 2017 23:10:30 +0200 Subject: Avoid memcpy references in unoptimized code --- library/compiler-builtins/src/float/add.rs | 6 ++++-- library/compiler-builtins/src/int/udiv.rs | 13 +++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 696d886fb69..a4b763b7e78 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,4 +1,3 @@ -use core::mem; use core::num::Wrapping; use float::Float; @@ -75,7 +74,10 @@ macro_rules! add { // Swap a and b if necessary so that a has the larger absolute value. if b_abs > a_abs { - mem::swap(&mut a_rep, &mut b_rep); + // Don't use mem::swap because it may generate references to memcpy in unoptimized code. + let tmp = a_rep; + a_rep = b_rep; + b_rep = tmp; } // Extract the exponent and significand from the (possibly swapped) a and b. diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index de276147e3d..b8d949128d3 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -125,7 +125,11 @@ macro_rules! udivmod_inner { // 1 <= sr <= u64::bits() - 1 let mut carry = 0; - for _ in 0..sr { + // Don't use a range because they may generate references to memcpy in unoptimized code + let mut i = 0; + while i < sr { + i += 1; + // r:q = ((r:q) << 1) | carry r = (r << 1) | (q >> (<$ty>::bits() - 1)); q = (q << 1) | carry as $ty; @@ -181,7 +185,12 @@ intrinsics! { let mut r = n >> sr; let mut carry = 0; - for _ in 0..sr { + + // Don't use a range because they may generate references to memcpy in unoptimized code + let mut i = 0; + while i < sr { + i += 1; + // r:q = ((r:q) << 1) | carry r = (r << 1) | (q >> (u32::bits() - 1)); q = (q << 1) | carry; -- cgit 1.4.1-3-g733a5 From 21c82e419de2fc9caced36646a706d0bd0bc5995 Mon Sep 17 00:00:00 2001 From: Geoff Yoerger Date: Mon, 21 Aug 2017 16:17:04 -0500 Subject: Fix README relative link. --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index a0e2a29ed15..3571200aa3b 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -51,7 +51,7 @@ features = ["c"] ## Contributing -1. Pick one or more intrinsics from the [pending list][#progress]. +1. Pick one or more intrinsics from the [pending list](#progress). 2. Fork this repository 3. Port the intrinsic(s) and their corresponding [unit tests][1] from their [C implementation][2] to Rust. -- cgit 1.4.1-3-g733a5 From 465ba28996b25e4531b9d1a2e9ec72d68efb4326 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 7 Sep 2017 07:49:34 +0200 Subject: Update the gcc crate to 0.3.53 and disable compilation warnings They are inside the compiler-rt submodule, about which we don't have direct control over. --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/build.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 070d8f8c7a0..d7419902d7a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -10,7 +10,7 @@ rand = { version = "0.3.15", optional = true } [build-dependencies.gcc] optional = true -version = "0.3.36" +version = "0.3.53" [features] c = ["gcc"] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 25cc5204d2e..6d4e274fadc 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4008,7 +4008,9 @@ mod c { let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); - let cfg = &mut gcc::Config::new(); + let cfg = &mut gcc::Build::new(); + + cfg.warnings(false); if target_env == "msvc" { // Don't pull in extra libraries on MSVC -- cgit 1.4.1-3-g733a5 From ffd4e7639f9bc61f68277982dce53c7a7819186b Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sun, 10 Sep 2017 09:30:47 -0400 Subject: Remove unused rustbuild feature I can't tell if this was ever used, but it's not used today. --- library/compiler-builtins/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d7419902d7a..84cefb2d280 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -17,7 +17,6 @@ c = ["gcc"] compiler-builtins = [] default = ["compiler-builtins"] mem = [] -rustbuild = ["compiler-builtins"] mangled-names = [] # generate tests -- cgit 1.4.1-3-g733a5 From 0b2a017b944424f3c318c2d375493233b01a5254 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 12 Sep 2017 19:09:43 -0400 Subject: Update rustbuild commentary Also use `cfg!(feature = "rustbuild")` instead of the environment variable to ease grep-ability. --- library/compiler-builtins/build.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6d4e274fadc..8b5695ba422 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4106,9 +4106,11 @@ mod c { // also needs to satisfy intrinsics that jemalloc or C in general may // need, so include a few more that aren't typically needed by // LLVM/Rust. - sources.extend(&[ - "ffsdi2.c", - ]); + if cfg!(feature = "rustbuild") { + sources.extend(&[ + "ffsdi2.c", + ]); + } if target_os != "ios" { sources.extend( @@ -4359,7 +4361,9 @@ mod c { sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); } - let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { + // When compiling in rustbuild (the rust-lang/rust repo) this build + // script runs from a directory other than this root directory. + let root = if cfg!(feature = "rustbuild") { Path::new("../../libcompiler_builtins") } else { Path::new(".") -- cgit 1.4.1-3-g733a5 From 985e578acdd1225e36b6df2583188f110af48911 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 13 Sep 2017 21:01:40 +0200 Subject: Refactor int builtins to use associated consts --- library/compiler-builtins/src/float/conv.rs | 6 ++--- library/compiler-builtins/src/int/mod.rs | 34 ++++++++------------------ library/compiler-builtins/src/int/mul.rs | 14 +++++------ library/compiler-builtins/src/int/sdiv.rs | 10 ++++---- library/compiler-builtins/src/int/shift.rs | 16 ++++++------ library/compiler-builtins/src/int/udiv.rs | 38 ++++++++++++++--------------- 6 files changed, 52 insertions(+), 66 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index f2fd01d37b0..fdd7fd8ccd1 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -11,7 +11,7 @@ macro_rules! int_to_float { let mant_dig = <$fty>::significand_bits() + 1; let exponent_bias = <$fty>::exponent_bias(); - let n = <$ity>::bits(); + let n = <$ity>::BITS; let (s, a) = i.extract_sign(); let mut a = a; @@ -21,7 +21,7 @@ macro_rules! int_to_float { // exponent let mut e = sd - 1; - if <$ity>::bits() < mant_dig { + if <$ity>::BITS < mant_dig { return <$fty>::from_parts(s, (e + exponent_bias) as <$fty as Float>::Int, (a as <$fty as Float>::Int) << (mant_dig - e - 1)) @@ -142,7 +142,7 @@ macro_rules! float_to_int { let f = $f; let fixint_min = <$ity>::min_value(); let fixint_max = <$ity>::max_value(); - let fixint_bits = <$ity>::bits() as usize; + let fixint_bits = <$ity>::BITS as usize; let fixint_unsigned = fixint_min == 0; let sign_bit = <$fty>::sign_mask(); diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 0334a4acb8b..7f9a85c4193 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -39,11 +39,11 @@ pub trait Int: /// Unsigned version of Self type UnsignedInt: Int; - /// Returns the bitwidth of the int type - fn bits() -> u32; + /// The bitwidth of the int type + const BITS: u32; - fn zero() -> Self; - fn one() -> Self; + const ZERO: Self; + const ONE: Self; /// Extracts the sign from self and returns a tuple. /// @@ -83,17 +83,10 @@ macro_rules! int_impl { type OtherSign = $ity; type UnsignedInt = $uty; - fn zero() -> Self { - 0 - } - - fn one() -> Self { - 1 - } + const BITS: u32 = $bits; - fn bits() -> u32 { - $bits - } + const ZERO: Self = 0; + const ONE: Self = 1; fn extract_sign(self) -> (bool, $uty) { (false, self) @@ -140,17 +133,10 @@ macro_rules! int_impl { type OtherSign = $uty; type UnsignedInt = $uty; - fn bits() -> u32 { - $bits - } - - fn zero() -> Self { - 0 - } + const BITS: u32 = $bits; - fn one() -> Self { - 1 - } + const ZERO: Self = 0; + const ONE: Self = 1; fn extract_sign(self) -> (bool, $uty) { if self < 0 { diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 98a8987e1d4..a4b2ebd7fb7 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -5,8 +5,8 @@ use int::Int; trait Mul: LargeInt { fn mul(self, other: Self) -> Self { - let half_bits = Self::bits() / 4; - let lower_mask = !<::LowHalf>::zero() >> half_bits; + let half_bits = Self::BITS / 4; + let lower_mask = !<::LowHalf>::ZERO >> half_bits; let mut low = (self.low() & lower_mask).wrapping_mul(other.low() & lower_mask); let mut t = low >> half_bits; low &= lower_mask; @@ -33,23 +33,23 @@ trait Mulo: Int + ops::Neg { *overflow = 0; let result = self.wrapping_mul(other); if self == Self::min_value() { - if other != Self::zero() && other != Self::one() { + if other != Self::ZERO && other != Self::ONE { *overflow = 1; } return result; } if other == Self::min_value() { - if self != Self::zero() && self != Self::one() { + if self != Self::ZERO && self != Self::ONE { *overflow = 1; } return result; } - let sa = self >> (Self::bits() - 1); + let sa = self >> (Self::BITS - 1); let abs_a = (self ^ sa) - sa; - let sb = other >> (Self::bits() - 1); + let sb = other >> (Self::BITS - 1); let abs_b = (other ^ sb) - sb; - let two = Self::one() + Self::one(); + let two = Self::ONE + Self::ONE; if abs_a < two || abs_b < two { return result; } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index c949c3394d2..ff8fa61e4b9 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -3,9 +3,9 @@ use int::Int; trait Div: Int { /// Returns `a / b` fn div(self, other: Self) -> Self { - let s_a = self >> (Self::bits() - 1); - let s_b = other >> (Self::bits() - 1); - // NOTE it's OK to overflow here because of the `as $uty` cast below + let s_a = self >> (Self::BITS - 1); + let s_b = other >> (Self::BITS - 1); + // NOTE it's OK to overflow here because of the `.unsigned()` below. // This whole operation is computing the absolute value of the inputs // So some overflow will happen when dealing with e.g. `i64::MIN` // where the absolute value is `(-i64::MIN) as u64` @@ -25,10 +25,10 @@ impl Div for i128 {} trait Mod: Int { /// Returns `a % b` fn mod_(self, other: Self) -> Self { - let s = other >> (Self::bits() - 1); + let s = other >> (Self::BITS - 1); // NOTE(wrapping_sub) see comment in the `div` let b = (other ^ s).wrapping_sub(s); - let s = self >> (Self::bits() - 1); + let s = self >> (Self::BITS - 1); let a = (self ^ s).wrapping_sub(s); let r = a.unsigned().aborting_rem(b.unsigned()); diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index a9b6c05d3d3..805d7059623 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,13 +1,13 @@ use int::{Int, LargeInt}; trait Ashl: Int + LargeInt { - /// Returns `a << b`, requires `b < $ty::bits()` + /// Returns `a << b`, requires `b < Self::BITS` fn ashl(self, offset: u32) -> Self where Self: LargeInt::LowHalf>, { - let half_bits = Self::bits() / 2; + let half_bits = Self::BITS / 2; if offset & half_bits != 0 { - Self::from_parts(Int::zero(), self.low() << (offset - half_bits)) + Self::from_parts(Int::ZERO, self.low() << (offset - half_bits)) } else if offset == 0 { self } else { @@ -22,11 +22,11 @@ impl Ashl for u64 {} impl Ashl for u128 {} trait Ashr: Int + LargeInt { - /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` + /// Returns arithmetic `a >> b`, requires `b < Self::BITS` fn ashr(self, offset: u32) -> Self where Self: LargeInt::HighHalf as Int>::UnsignedInt>, { - let half_bits = Self::bits() / 2; + let half_bits = Self::BITS / 2; if offset & half_bits != 0 { Self::from_parts((self.high() >> (offset - half_bits)).unsigned(), self.high() >> (half_bits - 1)) @@ -44,13 +44,13 @@ impl Ashr for i64 {} impl Ashr for i128 {} trait Lshr: Int + LargeInt { - /// Returns logical `a >> b`, requires `b < $ty::bits()` + /// Returns logical `a >> b`, requires `b < Self::BITS` fn lshr(self, offset: u32) -> Self where Self: LargeInt::LowHalf>, { - let half_bits = Self::bits() / 2; + let half_bits = Self::BITS / 2; if offset & half_bits != 0 { - Self::from_parts(self.high() >> (offset - half_bits), Int::zero()) + Self::from_parts(self.high() >> (offset - half_bits), Int::ZERO) } else if offset == 0 { self } else { diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index b8d949128d3..74a2ac3387d 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -63,7 +63,7 @@ macro_rules! udivmod_inner { sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); // D > N - if sr > ::bits() - 2 { + if sr > ::BITS - 2 { if let Some(rem) = rem { *rem = n; } @@ -72,8 +72,8 @@ macro_rules! udivmod_inner { sr += 1; - // 1 <= sr <= ::bits() - 1 - q = n << (<$ty>::bits() - sr); + // 1 <= sr <= ::BITS - 1 + q = n << (<$ty>::BITS - sr); r = n >> sr; } else if d.high() == 0 { // K X @@ -92,10 +92,10 @@ macro_rules! udivmod_inner { }; } - sr = 1 + ::bits() + d.low().leading_zeros() - n.high().leading_zeros(); + sr = 1 + ::BITS + d.low().leading_zeros() - n.high().leading_zeros(); - // 2 <= sr <= u64::bits() - 1 - q = n << (<$ty>::bits() - sr); + // 2 <= sr <= u64::BITS - 1 + q = n << (<$ty>::BITS - sr); r = n >> sr; } else { // K X @@ -104,7 +104,7 @@ macro_rules! udivmod_inner { sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); // D > N - if sr > ::bits() - 1 { + if sr > ::BITS - 1 { if let Some(rem) = rem { *rem = n; } @@ -113,16 +113,16 @@ macro_rules! udivmod_inner { sr += 1; - // 1 <= sr <= ::bits() - q = n << (<$ty>::bits() - sr); + // 1 <= sr <= ::BITS + q = n << (<$ty>::BITS - sr); r = n >> sr; } // Not a special case // q and r are initialized with - // q = n << (u64::bits() - sr) + // q = n << (u64::BITS - sr) // r = n >> sr - // 1 <= sr <= u64::bits() - 1 + // 1 <= sr <= u64::BITS - 1 let mut carry = 0; // Don't use a range because they may generate references to memcpy in unoptimized code @@ -131,7 +131,7 @@ macro_rules! udivmod_inner { i += 1; // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (<$ty>::bits() - 1)); + r = (r << 1) | (q >> (<$ty>::BITS - 1)); q = (q << 1) | carry as $ty; // carry = 0 @@ -139,7 +139,7 @@ macro_rules! udivmod_inner { // r -= d; // carry = 1; // } - let s = (d.wrapping_sub(r).wrapping_sub(1)) as os_ty!($ty) >> (<$ty>::bits() - 1); + let s = (d.wrapping_sub(r).wrapping_sub(1)) as os_ty!($ty) >> (<$ty>::BITS - 1); carry = (s & 1) as hty!($ty); r -= d & s as $ty; } @@ -169,19 +169,19 @@ intrinsics! { let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); // d > n - if sr > u32::bits() - 1 { + if sr > u32::BITS - 1 { return 0; } // d == 1 - if sr == u32::bits() - 1 { + if sr == u32::BITS - 1 { return n; } sr += 1; - // 1 <= sr <= u32::bits() - 1 - let mut q = n << (u32::bits() - sr); + // 1 <= sr <= u32::BITS - 1 + let mut q = n << (u32::BITS - sr); let mut r = n >> sr; let mut carry = 0; @@ -192,7 +192,7 @@ intrinsics! { i += 1; // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (u32::bits() - 1)); + r = (r << 1) | (q >> (u32::BITS - 1)); q = (q << 1) | carry; // carry = 0; @@ -201,7 +201,7 @@ intrinsics! { // carry = 1; // } - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::bits() - 1); + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::BITS - 1); carry = (s & 1) as u32; r -= d & s as u32; } -- cgit 1.4.1-3-g733a5 From 218eafcc68b40c1a19c306d891c68962b9d157ed Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 13 Sep 2017 22:08:15 +0200 Subject: Refactor float builtins to use associated consts --- library/compiler-builtins/src/float/add.rs | 4 +- library/compiler-builtins/src/float/conv.rs | 12 +-- library/compiler-builtins/src/float/mod.rs | 116 +++++++++++----------------- library/compiler-builtins/src/float/sub.rs | 4 +- 4 files changed, 56 insertions(+), 80 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index a4b763b7e78..2d380c13c26 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -10,8 +10,8 @@ macro_rules! add { let one = Wrapping(1 as <$ty as Float>::Int); let zero = Wrapping(0 as <$ty as Float>::Int); - let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); - let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); + let bits = Wrapping(<$ty>::BITS as <$ty as Float>::Int); + let significand_bits = Wrapping(<$ty>::SIGNIFICAND_BITS as <$ty as Float>::Int); let exponent_bits = bits - significand_bits - one; let max_exponent = (one << exponent_bits.0 as usize) - one; diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index fdd7fd8ccd1..33644ce56aa 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -8,8 +8,8 @@ macro_rules! int_to_float { return 0.0 } - let mant_dig = <$fty>::significand_bits() + 1; - let exponent_bias = <$fty>::exponent_bias(); + let mant_dig = <$fty>::SIGNIFICAND_BITS + 1; + let exponent_bias = <$fty>::EXPONENT_BIAS; let n = <$ity>::BITS; let (s, a) = i.extract_sign(); @@ -145,9 +145,9 @@ macro_rules! float_to_int { let fixint_bits = <$ity>::BITS as usize; let fixint_unsigned = fixint_min == 0; - let sign_bit = <$fty>::sign_mask(); - let significand_bits = <$fty>::significand_bits() as usize; - let exponent_bias = <$fty>::exponent_bias() as usize; + let sign_bit = <$fty>::SIGN_MASK; + let significand_bits = <$fty>::SIGNIFICAND_BITS as usize; + let exponent_bias = <$fty>::EXPONENT_BIAS as usize; //let exponent_max = <$fty>::exponent_max() as usize; // Break a into sign, exponent, significand @@ -157,7 +157,7 @@ macro_rules! float_to_int { // this is used to work around -1 not being available for unsigned let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative }; let mut exponent = (a_abs >> significand_bits) as usize; - let significand = (a_abs & <$fty>::significand_mask()) | <$fty>::implicit_bit(); + let significand = (a_abs & <$fty>::SIGNIFICAND_MASK) | <$fty>::IMPLICIT_BIT; // if < 1 or unsigned & negative if exponent < exponent_bias || diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 46e3e5d9585..078c5110c2f 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,5 +1,7 @@ use core::mem; +use super::int::Int; + pub mod conv; pub mod add; pub mod pow; @@ -8,39 +10,34 @@ pub mod sub; /// Trait for some basic operations on floats pub trait Float: Sized + Copy { /// A uint of the same with as the float - type Int; + type Int: Int; - /// Returns the bitwidth of the float type - fn bits() -> u32; + /// The bitwidth of the float type + const BITS: u32; - /// Returns the bitwidth of the significand - fn significand_bits() -> u32; + /// The bitwidth of the significand + const SIGNIFICAND_BITS: u32; - /// Returns the bitwidth of the exponent - fn exponent_bits() -> u32 { - Self::bits() - Self::significand_bits() - 1 - } - /// Returns the maximum value of the exponent - fn exponent_max() -> u32 { - (1 << Self::exponent_bits()) - 1 - } + /// The bitwidth of the exponent + const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; - /// Returns the exponent bias value - fn exponent_bias() -> u32 { - Self::exponent_max() >> 1 - } + /// The maximum value of the exponent + const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; + + /// The exponent bias value + const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; - /// Returns a mask for the sign bit - fn sign_mask() -> Self::Int; + /// A mask for the sign bit + const SIGN_MASK: Self::Int; - /// Returns a mask for the significand - fn significand_mask() -> Self::Int; + /// A mask for the significand + const SIGNIFICAND_MASK: Self::Int; - // Returns the implicit bit of the float format - fn implicit_bit() -> Self::Int; + // The implicit bit of the float format + const IMPLICIT_BIT: Self::Int; - /// Returns a mask for the exponent - fn exponent_mask() -> Self::Int; + /// A mask for the exponent + const EXPONENT_MASK: Self::Int; /// Returns `self` transmuted to `Self::Int` fn repr(self) -> Self::Int; @@ -65,24 +62,14 @@ pub trait Float: Sized + Copy { // https://github.com/rust-lang/rfcs/issues/1424 impl Float for f32 { type Int = u32; - fn bits() -> u32 { - 32 - } - fn significand_bits() -> u32 { - 23 - } - fn implicit_bit() -> Self::Int { - 1 << Self::significand_bits() - } - fn sign_mask() -> Self::Int { - 1 << (Self::bits() - 1) - } - fn significand_mask() -> Self::Int { - (1 << Self::significand_bits()) - 1 - } - fn exponent_mask() -> Self::Int { - !(Self::sign_mask() | Self::significand_mask()) - } + const BITS: u32 = 32; + const SIGNIFICAND_BITS: u32 = 23; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; + const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -98,37 +85,26 @@ impl Float for f32 { unsafe { mem::transmute(a) } } fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | - ((exponent << Self::significand_bits()) & Self::exponent_mask()) | - (significand & Self::significand_mask())) + Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) | + ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) | + (significand & Self::SIGNIFICAND_MASK)) } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() - .wrapping_sub((1u32 << Self::significand_bits()).leading_zeros()); + .wrapping_sub((1u32 << Self::SIGNIFICAND_BITS).leading_zeros()); (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) } } impl Float for f64 { type Int = u64; - fn bits() -> u32 { - 64 - } - fn significand_bits() -> u32 { - 52 - } - // Returns the implicit bit of the float format - fn implicit_bit() -> Self::Int { - 1 << Self::significand_bits() - } - fn sign_mask() -> Self::Int { - 1 << (Self::bits() - 1) - } - fn significand_mask() -> Self::Int { - (1 << Self::significand_bits()) - 1 - } - fn exponent_mask() -> Self::Int { - !(Self::sign_mask() | Self::significand_mask()) - } + const BITS: u32 = 64; + const SIGNIFICAND_BITS: u32 = 52; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; + const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -144,13 +120,13 @@ impl Float for f64 { unsafe { mem::transmute(a) } } fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | - ((exponent << Self::significand_bits()) & Self::exponent_mask()) | - (significand & Self::significand_mask())) + Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) | + ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) | + (significand & Self::SIGNIFICAND_MASK)) } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() - .wrapping_sub((1u64 << Self::significand_bits()).leading_zeros()); + .wrapping_sub((1u64 << Self::SIGNIFICAND_BITS).leading_zeros()); (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) } } diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 4fa436db613..ed7dd2c0aaa 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -3,11 +3,11 @@ use float::Float; intrinsics! { #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { - a + f32::from_repr(b.repr() ^ f32::sign_mask()) + a + f32::from_repr(b.repr() ^ f32::SIGN_MASK) } #[arm_aeabi_alias = __aeabi_dsub] pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { - a + f64::from_repr(b.repr() ^ f64::sign_mask()) + a + f64::from_repr(b.repr() ^ f64::SIGN_MASK) } } -- cgit 1.4.1-3-g733a5 From cec214f0d7eb60e895254b3951a032438a2773e7 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 13 Sep 2017 22:44:56 +0200 Subject: Introduce a float_impl! macro to avoid duplication --- library/compiler-builtins/src/float/mod.rs | 106 +++++++++++------------------ 1 file changed, 39 insertions(+), 67 deletions(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 078c5110c2f..33e1479a6bf 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -60,73 +60,45 @@ pub trait Float: Sized + Copy { // FIXME: Some of this can be removed if RFC Issue #1424 is resolved // https://github.com/rust-lang/rfcs/issues/1424 -impl Float for f32 { - type Int = u32; - const BITS: u32 = 32; - const SIGNIFICAND_BITS: u32 = 23; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; - const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); - - fn repr(self) -> Self::Int { - unsafe { mem::transmute(self) } - } - #[cfg(test)] - fn eq_repr(self, rhs: Self) -> bool { - if self.is_nan() && rhs.is_nan() { - true - } else { - self.repr() == rhs.repr() - } - } - fn from_repr(a: Self::Int) -> Self { - unsafe { mem::transmute(a) } - } - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) | - ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) | - (significand & Self::SIGNIFICAND_MASK)) - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand.leading_zeros() - .wrapping_sub((1u32 << Self::SIGNIFICAND_BITS).leading_zeros()); - (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) - } -} -impl Float for f64 { - type Int = u64; - const BITS: u32 = 64; - const SIGNIFICAND_BITS: u32 = 52; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; - const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); - - fn repr(self) -> Self::Int { - unsafe { mem::transmute(self) } - } - #[cfg(test)] - fn eq_repr(self, rhs: Self) -> bool { - if self.is_nan() && rhs.is_nan() { - true - } else { - self.repr() == rhs.repr() +macro_rules! float_impl { + ($ty:ident, $ity:ident, $bits:expr, $significand_bits:expr) => { + impl Float for $ty { + type Int = $ity; + const BITS: u32 = $bits; + const SIGNIFICAND_BITS: u32 = $significand_bits; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; + const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + + fn repr(self) -> Self::Int { + unsafe { mem::transmute(self) } + } + #[cfg(test)] + fn eq_repr(self, rhs: Self) -> bool { + if self.is_nan() && rhs.is_nan() { + true + } else { + self.repr() == rhs.repr() + } + } + fn from_repr(a: Self::Int) -> Self { + unsafe { mem::transmute(a) } + } + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) | + ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) | + (significand & Self::SIGNIFICAND_MASK)) + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand.leading_zeros() + .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros()); + (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) + } } } - fn from_repr(a: Self::Int) -> Self { - unsafe { mem::transmute(a) } - } - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) | - ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) | - (significand & Self::SIGNIFICAND_MASK)) - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand.leading_zeros() - .wrapping_sub((1u64 << Self::SIGNIFICAND_BITS).leading_zeros()); - (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) - } } + +float_impl!(f32, u32, 32, 23); +float_impl!(f64, u64, 64, 52); -- cgit 1.4.1-3-g733a5 From 515ea7157a55e5c870e4935f8560c8c3ccdbf9dd Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 00:10:16 +0200 Subject: Use the newly added ONE constant in float addition --- library/compiler-builtins/src/float/add.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 2d380c13c26..e6cb726fd48 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,5 +1,6 @@ use core::num::Wrapping; +use int::Int; use float::Float; /// Returns `a + b` @@ -7,8 +8,8 @@ macro_rules! add { ($a:expr, $b:expr, $ty:ty) => ({ let a = $a; let b = $b; - let one = Wrapping(1 as <$ty as Float>::Int); - let zero = Wrapping(0 as <$ty as Float>::Int); + let one = Wrapping(<$ty as Float>::Int::ONE); + let zero = Wrapping(<$ty as Float>::Int::ZERO); let bits = Wrapping(<$ty>::BITS as <$ty as Float>::Int); let significand_bits = Wrapping(<$ty>::SIGNIFICAND_BITS as <$ty as Float>::Int); -- cgit 1.4.1-3-g733a5 From 3b5d6d7aa9eb563f547067a62704e561eee9e4a5 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 01:57:52 +0200 Subject: Extend the Float trait by some constants and supertraits --- library/compiler-builtins/src/float/mod.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 33e1479a6bf..23aef32e5de 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,4 +1,5 @@ use core::mem; +use core::ops; use super::int::Int; @@ -8,10 +9,23 @@ pub mod pow; pub mod sub; /// Trait for some basic operations on floats -pub trait Float: Sized + Copy { +pub trait Float: + Copy + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::MulAssign + + ops::Add + + ops::Sub + + ops::Div + + ops::Rem + +{ /// A uint of the same with as the float type Int: Int; + const ZERO: Self; + const ONE: Self; + /// The bitwidth of the float type const BITS: u32; @@ -64,6 +78,9 @@ macro_rules! float_impl { ($ty:ident, $ity:ident, $bits:expr, $significand_bits:expr) => { impl Float for $ty { type Int = $ity; + const ZERO: Self = 0.0; + const ONE: Self = 1.0; + const BITS: u32 = $bits; const SIGNIFICAND_BITS: u32 = $significand_bits; -- cgit 1.4.1-3-g733a5 From 57a3b2fe4824aec06a426a84cf98dcb3216e3672 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 01:59:02 +0200 Subject: Don't use a macro for pow calculation --- library/compiler-builtins/src/float/pow.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index bc15dc08887..f879c1a1f81 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,11 +1,12 @@ use int::Int; +use float::Float; -/// Returns `a` raised to the power `b` -macro_rules! pow { - ($a: expr, $b: expr) => ({ - let (mut a, mut b) = ($a, $b); +trait Pow: Float { + /// Returns `a` raised to the power `b` + fn pow(self, mut b: i32) -> Self { + let mut a = self; let recip = b < 0; - let mut r = 1.0; + let mut r = Self::ONE; loop { if (b & 1) != 0 { r *= a; @@ -18,19 +19,22 @@ macro_rules! pow { } if recip { - 1.0 / r + Self::ONE / r } else { r } - }) + } } +impl Pow for f32 {} +impl Pow for f64 {} + intrinsics! { pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 { - pow!(a, b) + a.pow(b) } pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 { - pow!(a, b) + a.pow(b) } } -- cgit 1.4.1-3-g733a5 From 6f19051513b2ebce272a54aa85f205eab1345c23 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 02:08:28 +0200 Subject: Don't use the Wrapping wrapper in float addition Inspired by a patch by mattico. --- library/compiler-builtins/src/float/add.rs | 106 ++++++++++++++--------------- 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index e6cb726fd48..fae14f07c3e 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,5 +1,3 @@ -use core::num::Wrapping; - use int::Int; use float::Float; @@ -8,44 +6,44 @@ macro_rules! add { ($a:expr, $b:expr, $ty:ty) => ({ let a = $a; let b = $b; - let one = Wrapping(<$ty as Float>::Int::ONE); - let zero = Wrapping(<$ty as Float>::Int::ZERO); + let one = <$ty as Float>::Int::ONE; + let zero = <$ty as Float>::Int::ZERO; - let bits = Wrapping(<$ty>::BITS as <$ty as Float>::Int); - let significand_bits = Wrapping(<$ty>::SIGNIFICAND_BITS as <$ty as Float>::Int); - let exponent_bits = bits - significand_bits - one; - let max_exponent = (one << exponent_bits.0 as usize) - one; + let bits = <$ty>::BITS as <$ty as Float>::Int; + let significand_bits = <$ty>::SIGNIFICAND_BITS as <$ty as Float>::Int; + let exponent_bits = <$ty>::EXPONENT_BITS as <$ty as Float>::Int; + let max_exponent = (one << exponent_bits as usize) - one; - let implicit_bit = one << significand_bits.0 as usize; + let implicit_bit = one << significand_bits as usize; let significand_mask = implicit_bit - one; - let sign_bit = one << (significand_bits + exponent_bits).0 as usize; + let sign_bit = <$ty>::SIGN_MASK as <$ty as Float>::Int; let abs_mask = sign_bit - one; let exponent_mask = abs_mask ^ significand_mask; let inf_rep = exponent_mask; let quiet_bit = implicit_bit >> 1; let qnan_rep = exponent_mask | quiet_bit; - let mut a_rep = Wrapping(a.repr()); - let mut b_rep = Wrapping(b.repr()); + let mut a_rep = a.repr(); + let mut b_rep = b.repr(); let a_abs = a_rep & abs_mask; let b_abs = b_rep & abs_mask; // Detect if a or b is zero, infinity, or NaN. - if a_abs - one >= inf_rep - one || - b_abs - one >= inf_rep - one { + if a_abs.wrapping_sub(one) >= inf_rep - one || + b_abs.wrapping_sub(one) >= inf_rep - one { // NaN + anything = qNaN if a_abs > inf_rep { - return <$ty as Float>::from_repr((a_abs | quiet_bit).0); + return <$ty as Float>::from_repr(a_abs | quiet_bit); } // anything + NaN = qNaN if b_abs > inf_rep { - return <$ty as Float>::from_repr((b_abs | quiet_bit).0); + return <$ty as Float>::from_repr(b_abs | quiet_bit); } if a_abs == inf_rep { // +/-infinity + -/+infinity = qNaN - if (a.repr() ^ b.repr()) == sign_bit.0 { - return <$ty as Float>::from_repr(qnan_rep.0); + if (a.repr() ^ b.repr()) == sign_bit { + return <$ty as Float>::from_repr(qnan_rep); } else { // +/-infinity + anything remaining = +/- infinity return a; @@ -58,9 +56,9 @@ macro_rules! add { } // zero + anything = anything - if a_abs.0 == 0 { + if a_abs == 0 { // but we need to get the sign right for zero + zero - if b_abs.0 == 0 { + if b_abs == 0 { return <$ty as Float>::from_repr(a.repr() & b.repr()); } else { return b; @@ -68,7 +66,7 @@ macro_rules! add { } // anything + zero = anything - if b_abs.0 == 0 { + if b_abs == 0 { return a; } } @@ -82,21 +80,21 @@ macro_rules! add { } // Extract the exponent and significand from the (possibly swapped) a and b. - let mut a_exponent = Wrapping((a_rep >> significand_bits.0 as usize & max_exponent).0 as i32); - let mut b_exponent = Wrapping((b_rep >> significand_bits.0 as usize & max_exponent).0 as i32); + let mut a_exponent = ((a_rep >> significand_bits) & max_exponent) as i32; + let mut b_exponent = ((b_rep >> significand_bits) & max_exponent) as i32; let mut a_significand = a_rep & significand_mask; let mut b_significand = b_rep & significand_mask; // normalize any denormals, and adjust the exponent accordingly. - if a_exponent.0 == 0 { - let (exponent, significand) = <$ty>::normalize(a_significand.0); - a_exponent = Wrapping(exponent); - a_significand = Wrapping(significand); + if a_exponent == 0 { + let (exponent, significand) = <$ty>::normalize(a_significand); + a_exponent = exponent; + a_significand = significand; } - if b_exponent.0 == 0 { - let (exponent, significand) = <$ty>::normalize(b_significand.0); - b_exponent = Wrapping(exponent); - b_significand = Wrapping(significand); + if b_exponent == 0 { + let (exponent, significand) = <$ty>::normalize(b_significand); + b_exponent = exponent; + b_significand = significand; } // The sign of the result is the sign of the larger operand, a. If they @@ -113,64 +111,64 @@ macro_rules! add { // Shift the significand of b by the difference in exponents, with a sticky // bottom bit to get rounding correct. - let align = Wrapping((a_exponent - b_exponent).0 as <$ty as Float>::Int); - if align.0 != 0 { + let align = a_exponent.wrapping_sub(b_exponent) as <$ty as Float>::Int; + if align != 0 { if align < bits { - let sticky = ((b_significand << (bits - align).0 as usize).0 != 0) as <$ty as Float>::Int; - b_significand = (b_significand >> align.0 as usize) | Wrapping(sticky); + let sticky = (b_significand << (bits.wrapping_sub(align) as usize) != 0) as <$ty as Float>::Int; + b_significand = (b_significand >> align as usize) | sticky; } else { b_significand = one; // sticky; b is known to be non-zero. } } if subtraction { - a_significand -= b_significand; + a_significand = a_significand.wrapping_sub(b_significand); // If a == -b, return +zero. - if a_significand.0 == 0 { + if a_significand == 0 { return <$ty as Float>::from_repr(0); } // If partial cancellation occured, we need to left-shift the result // and adjust the exponent: if a_significand < implicit_bit << 3 { - let shift = a_significand.0.leading_zeros() as i32 - - (implicit_bit << 3).0.leading_zeros() as i32; + let shift = a_significand.leading_zeros() as i32 + - (implicit_bit << 3).leading_zeros() as i32; a_significand <<= shift as usize; - a_exponent -= Wrapping(shift); + a_exponent -= shift; } } else /* addition */ { a_significand += b_significand; // If the addition carried up, we need to right-shift the result and // adjust the exponent: - if (a_significand & implicit_bit << 4).0 != 0 { - let sticky = ((a_significand & one).0 != 0) as <$ty as Float>::Int; - a_significand = a_significand >> 1 | Wrapping(sticky); - a_exponent += Wrapping(1); + if a_significand & implicit_bit << 4 != 0 { + let sticky = (a_significand & one != 0) as <$ty as Float>::Int; + a_significand = a_significand >> 1 | sticky; + a_exponent += 1; } } // If we have overflowed the type, return +/- infinity: - if a_exponent >= Wrapping(max_exponent.0 as i32) { - return <$ty>::from_repr((inf_rep | result_sign).0); + if a_exponent >= max_exponent as i32 { + return <$ty>::from_repr(inf_rep | result_sign); } - if a_exponent.0 <= 0 { + if a_exponent <= 0 { // Result is denormal before rounding; the exponent is zero and we // need to shift the significand. - let shift = Wrapping((Wrapping(1) - a_exponent).0 as <$ty as Float>::Int); - let sticky = ((a_significand << (bits - shift).0 as usize).0 != 0) as <$ty as Float>::Int; - a_significand = a_significand >> shift.0 as usize | Wrapping(sticky); - a_exponent = Wrapping(0); + let shift = (1 - a_exponent) as <$ty as Float>::Int; + let sticky = ((a_significand << bits.wrapping_sub(shift) as usize) != 0) as <$ty as Float>::Int; + a_significand = a_significand >> shift as usize | sticky; + a_exponent = 0; } // Low three bits are round, guard, and sticky. - let round_guard_sticky: i32 = (a_significand.0 & 0x7) as i32; + let round_guard_sticky: i32 = (a_significand & 0x7) as i32; // Shift the significand into place, and mask off the implicit bit. let mut result = a_significand >> 3 & significand_mask; // Insert the exponent and sign. - result |= Wrapping(a_exponent.0 as <$ty as Float>::Int) << significand_bits.0 as usize; + result |= (a_exponent as <$ty as Float>::Int) << (significand_bits as usize); result |= result_sign; // Final rounding. The result may overflow to infinity, but that is the @@ -178,7 +176,7 @@ macro_rules! add { if round_guard_sticky > 0x4 { result += one; } if round_guard_sticky == 0x4 { result += result & one; } - <$ty>::from_repr(result.0) + <$ty>::from_repr(result) }) } -- cgit 1.4.1-3-g733a5 From f1bab6229dbae2890ed49d227e2c36fe12d9923b Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 14:59:32 +0200 Subject: Convert float_to_int! into a function --- library/compiler-builtins/src/float/conv.rs | 125 ++++++++++++++-------------- library/compiler-builtins/src/int/mod.rs | 25 ++++++ 2 files changed, 88 insertions(+), 62 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 33644ce56aa..52fdf955998 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,5 +1,5 @@ use float::Float; -use int::Int; +use int::{Int, CastInto}; macro_rules! int_to_float { ($i:expr, $ity:ty, $fty:ty) => ({ @@ -137,115 +137,116 @@ enum Sign { Negative } -macro_rules! float_to_int { - ($f:expr, $fty:ty, $ity:ty) => ({ - let f = $f; - let fixint_min = <$ity>::min_value(); - let fixint_max = <$ity>::max_value(); - let fixint_bits = <$ity>::BITS as usize; - let fixint_unsigned = fixint_min == 0; - - let sign_bit = <$fty>::SIGN_MASK; - let significand_bits = <$fty>::SIGNIFICAND_BITS as usize; - let exponent_bias = <$fty>::EXPONENT_BIAS as usize; - //let exponent_max = <$fty>::exponent_max() as usize; - - // Break a into sign, exponent, significand - let a_rep = <$fty>::repr(f); - let a_abs = a_rep & !sign_bit; - - // this is used to work around -1 not being available for unsigned - let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative }; - let mut exponent = (a_abs >> significand_bits) as usize; - let significand = (a_abs & <$fty>::SIGNIFICAND_MASK) | <$fty>::IMPLICIT_BIT; - - // if < 1 or unsigned & negative - if exponent < exponent_bias || - fixint_unsigned && sign == Sign::Negative { - return 0 - } - exponent -= exponent_bias; - - // If the value is infinity, saturate. - // If the value is too large for the integer type, 0. - if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { - return if sign == Sign::Positive {fixint_max} else {fixint_min} - } - // If 0 <= exponent < significand_bits, right shift to get the result. - // Otherwise, shift left. - // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned - let r = if exponent < significand_bits { - (significand >> (significand_bits - exponent)) as $ity - } else { - (significand as $ity) << (exponent - significand_bits) - }; - - if sign == Sign::Negative { - (!r).wrapping_add(1) - } else { - r - } - }) +fn float_to_int(f: F) -> I where + F::Int: CastInto, + F::Int: CastInto, +{ + let f = f; + let fixint_min = I::min_value(); + let fixint_max = I::max_value(); + let fixint_bits = I::BITS; + let fixint_unsigned = fixint_min == I::ZERO; + + let sign_bit = F::SIGN_MASK; + let significand_bits = F::SIGNIFICAND_BITS; + let exponent_bias = F::EXPONENT_BIAS; + //let exponent_max = F::exponent_max() as usize; + + // Break a into sign, exponent, significand + let a_rep = F::repr(f); + let a_abs = a_rep & !sign_bit; + + // this is used to work around -1 not being available for unsigned + let sign = if (a_rep & sign_bit) == F::Int::ZERO { Sign::Positive } else { Sign::Negative }; + let mut exponent: u32 = (a_abs >> significand_bits).cast(); + let significand = (a_abs & F::SIGNIFICAND_MASK) | F::IMPLICIT_BIT; + + // if < 1 or unsigned & negative + if exponent < exponent_bias || + fixint_unsigned && sign == Sign::Negative { + return I::ZERO; + } + exponent -= exponent_bias; + + // If the value is infinity, saturate. + // If the value is too large for the integer type, 0. + if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { + return if sign == Sign::Positive {fixint_max} else {fixint_min} + } + // If 0 <= exponent < significand_bits, right shift to get the result. + // Otherwise, shift left. + // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned + let r: I = if exponent < significand_bits { + (significand >> (significand_bits - exponent)).cast() + } else { + (significand << (exponent - significand_bits)).cast() + }; + + if sign == Sign::Negative { + (!r).wrapping_add(I::ONE) + } else { + r + } } intrinsics! { #[arm_aeabi_alias = __aeabi_f2iz] pub extern "C" fn __fixsfsi(f: f32) -> i32 { - float_to_int!(f, f32, i32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_f2lz] pub extern "C" fn __fixsfdi(f: f32) -> i64 { - float_to_int!(f, f32, i64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixsfti(f: f32) -> i128 { - float_to_int!(f, f32, i128) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2iz] pub extern "C" fn __fixdfsi(f: f64) -> i32 { - float_to_int!(f, f64, i32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2lz] pub extern "C" fn __fixdfdi(f: f64) -> i64 { - float_to_int!(f, f64, i64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixdfti(f: f64) -> i128 { - float_to_int!(f, f64, i128) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { - float_to_int!(f, f32, u32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_f2ulz] pub extern "C" fn __fixunssfdi(f: f32) -> u64 { - float_to_int!(f, f32, u64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixunssfti(f: f32) -> u128 { - float_to_int!(f, f32, u128) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { - float_to_int!(f, f64, u32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2ulz] pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { - float_to_int!(f, f64, u64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { - float_to_int!(f, f64, u128) + float_to_int(f) } } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 7f9a85c4193..f4d5c0a3be8 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -230,3 +230,28 @@ large_int!(u64, u32, u32, 32); large_int!(i64, u32, i32, 32); large_int!(u128, u64, u64, 64); large_int!(i128, u64, i64, 64); + +/// Trait to express (possibly lossy) casting of integers +pub trait CastInto: Copy { + fn cast(self) -> T; +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} + +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); -- cgit 1.4.1-3-g733a5 From 13477e488f5cd49f0bd9cd84556d3a4edfdb0cee Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 16:32:50 +0200 Subject: Convert int_to_float! to a function --- library/compiler-builtins/src/float/conv.rs | 136 ++++++++++++++-------------- library/compiler-builtins/src/int/mod.rs | 32 ++++++- 2 files changed, 101 insertions(+), 67 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 52fdf955998..f358a17bd57 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,83 +1,87 @@ use float::Float; use int::{Int, CastInto}; -macro_rules! int_to_float { - ($i:expr, $ity:ty, $fty:ty) => ({ - let i = $i; - if i == 0 { - return 0.0 - } +fn int_to_float(i: I) -> F where + F::Int: CastInto, + F::Int: CastInto, + I::UnsignedInt: CastInto, + u32: CastInto, +{ + if i == I::ZERO { + return F::ZERO; + } - let mant_dig = <$fty>::SIGNIFICAND_BITS + 1; - let exponent_bias = <$fty>::EXPONENT_BIAS; + let two = I::UnsignedInt::ONE + I::UnsignedInt::ONE; + let four = two + two; + let mant_dig = F::SIGNIFICAND_BITS + 1; + let exponent_bias = F::EXPONENT_BIAS; - let n = <$ity>::BITS; - let (s, a) = i.extract_sign(); - let mut a = a; + let n = I::BITS; + let (s, a) = i.extract_sign(); + let mut a = a; - // number of significant digits - let sd = n - a.leading_zeros(); + // number of significant digits + let sd = n - a.leading_zeros(); - // exponent - let mut e = sd - 1; + // exponent + let mut e = sd - 1; - if <$ity>::BITS < mant_dig { - return <$fty>::from_parts(s, - (e + exponent_bias) as <$fty as Float>::Int, - (a as <$fty as Float>::Int) << (mant_dig - e - 1)) - } + if I::BITS < mant_dig { + return F::from_parts(s, + (e + exponent_bias).cast(), + a.cast() << (mant_dig - e - 1)); + } - a = if sd > mant_dig { - /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx - * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR - * 12345678901234567890123456 - * 1 = msb 1 bit - * P = bit MANT_DIG-1 bits to the right of 1 - * Q = bit MANT_DIG bits to the right of 1 - * R = "or" of all bits to the right of Q - */ - let mant_dig_plus_one = mant_dig + 1; - let mant_dig_plus_two = mant_dig + 2; - a = if sd == mant_dig_plus_one { - a << 1 - } else if sd == mant_dig_plus_two { - a - } else { - (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt | - ((a & <$ity as Int>::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != 0) as <$ity as Int>::UnsignedInt - }; - - /* finish: */ - a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */ - a += 1; /* round - this step may add a significant bit */ - a >>= 2; /* dump Q and R */ - - /* a is now rounded to mant_dig or mant_dig+1 bits */ - if (a & (1 << mant_dig)) != 0 { - a >>= 1; e += 1; - } + a = if sd > mant_dig { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit MANT_DIG-1 bits to the right of 1 + * Q = bit MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + let mant_dig_plus_one = mant_dig + 1; + let mant_dig_plus_two = mant_dig + 2; + a = if sd == mant_dig_plus_one { + a << 1 + } else if sd == mant_dig_plus_two { a - /* a is now rounded to mant_dig bits */ } else { - a.wrapping_shl(mant_dig - sd) - /* a is now rounded to mant_dig bits */ + (a >> (sd - mant_dig_plus_two)) | + Int::from_bool((a & I::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != Int::ZERO) }; - <$fty>::from_parts(s, - (e + exponent_bias) as <$fty as Float>::Int, - a as <$fty as Float>::Int) - }) + /* finish: */ + a |= Int::from_bool((a & four) != I::UnsignedInt::ZERO); /* Or P into R */ + a += Int::ONE; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + + /* a is now rounded to mant_dig or mant_dig+1 bits */ + if (a & (I::UnsignedInt::ONE << mant_dig)) != Int::ZERO { + a >>= 1; e += 1; + } + a + /* a is now rounded to mant_dig bits */ + } else { + a.wrapping_shl(mant_dig - sd) + /* a is now rounded to mant_dig bits */ + }; + + F::from_parts(s, + (e + exponent_bias).cast(), + a.cast()) } intrinsics! { #[arm_aeabi_alias = __aeabi_i2f] pub extern "C" fn __floatsisf(i: i32) -> f32 { - int_to_float!(i, i32, f32) + int_to_float(i) } #[arm_aeabi_alias = __aeabi_i2d] pub extern "C" fn __floatsidf(i: i32) -> f64 { - int_to_float!(i, i32, f64) + int_to_float(i) } #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] @@ -88,28 +92,28 @@ intrinsics! { if cfg!(target_arch = "x86_64") { i as f64 } else { - int_to_float!(i, i64, f64) + int_to_float(i) } } #[unadjusted_on_win64] pub extern "C" fn __floattisf(i: i128) -> f32 { - int_to_float!(i, i128, f32) + int_to_float(i) } #[unadjusted_on_win64] pub extern "C" fn __floattidf(i: i128) -> f64 { - int_to_float!(i, i128, f64) + int_to_float(i) } #[arm_aeabi_alias = __aeabi_ui2f] pub extern "C" fn __floatunsisf(i: u32) -> f32 { - int_to_float!(i, u32, f32) + int_to_float(i) } #[arm_aeabi_alias = __aeabi_ui2d] pub extern "C" fn __floatunsidf(i: u32) -> f64 { - int_to_float!(i, u32, f64) + int_to_float(i) } #[use_c_shim_if(all(not(target_env = "msvc"), @@ -117,17 +121,17 @@ intrinsics! { all(not(windows), target_arch = "x86_64"))))] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { - int_to_float!(i, u64, f64) + int_to_float(i) } #[unadjusted_on_win64] pub extern "C" fn __floatuntisf(i: u128) -> f32 { - int_to_float!(i, u128, f32) + int_to_float(i) } #[unadjusted_on_win64] pub extern "C" fn __floatuntidf(i: u128) -> f64 { - int_to_float!(i, u128, f64) + int_to_float(i) } } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index f4d5c0a3be8..c184301f5e2 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -23,6 +23,9 @@ pub trait Int: PartialEq + PartialOrd + ops::AddAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::ShrAssign + ops::Add + ops::Sub + ops::Div + @@ -31,7 +34,6 @@ pub trait Int: ops::BitOr + ops::BitXor + ops::BitAnd + - ops::BitAndAssign + ops::Not + { /// Type with the same width but other signedness @@ -60,14 +62,18 @@ pub trait Int: fn unsigned(self) -> Self::UnsignedInt; fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + fn from_bool(b: bool) -> Self; + // copied from primitive integers, but put in a trait fn max_value() -> Self; fn min_value() -> Self; fn wrapping_add(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self; fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; fn aborting_div(self, other: Self) -> Self; fn aborting_rem(self, other: Self) -> Self; + fn leading_zeros(self) -> u32; } fn unwrap(t: Option) -> T { @@ -100,6 +106,10 @@ macro_rules! int_impl { me } + fn from_bool(b: bool) -> Self { + b as $uty + } + fn max_value() -> Self { ::max_value() } @@ -120,6 +130,10 @@ macro_rules! int_impl { ::wrapping_sub(self, other) } + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + fn aborting_div(self, other: Self) -> Self { unwrap(::checked_div(self, other)) } @@ -127,6 +141,10 @@ macro_rules! int_impl { fn aborting_rem(self, other: Self) -> Self { unwrap(::checked_rem(self, other)) } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } } impl Int for $ity { @@ -154,6 +172,10 @@ macro_rules! int_impl { me as $ity } + fn from_bool(b: bool) -> Self { + b as $ity + } + fn max_value() -> Self { ::max_value() } @@ -174,6 +196,10 @@ macro_rules! int_impl { ::wrapping_sub(self, other) } + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + fn aborting_div(self, other: Self) -> Self { unwrap(::checked_div(self, other)) } @@ -181,6 +207,10 @@ macro_rules! int_impl { fn aborting_rem(self, other: Self) -> Self { unwrap(::checked_rem(self, other)) } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } } } } -- cgit 1.4.1-3-g733a5 From f2794913f3c324c68306d20acef9c6568fb074ee Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 17:33:44 +0200 Subject: Convert add! to a function --- library/compiler-builtins/src/float/add.rs | 317 +++++++++++++++-------------- library/compiler-builtins/src/int/mod.rs | 1 + 2 files changed, 160 insertions(+), 158 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index fae14f07c3e..d355cb1ff27 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,195 +1,196 @@ -use int::Int; +use int::{Int, CastInto}; use float::Float; /// Returns `a + b` -macro_rules! add { - ($a:expr, $b:expr, $ty:ty) => ({ - let a = $a; - let b = $b; - let one = <$ty as Float>::Int::ONE; - let zero = <$ty as Float>::Int::ZERO; - - let bits = <$ty>::BITS as <$ty as Float>::Int; - let significand_bits = <$ty>::SIGNIFICAND_BITS as <$ty as Float>::Int; - let exponent_bits = <$ty>::EXPONENT_BITS as <$ty as Float>::Int; - let max_exponent = (one << exponent_bits as usize) - one; - - let implicit_bit = one << significand_bits as usize; - let significand_mask = implicit_bit - one; - let sign_bit = <$ty>::SIGN_MASK as <$ty as Float>::Int; - let abs_mask = sign_bit - one; - let exponent_mask = abs_mask ^ significand_mask; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; - - let mut a_rep = a.repr(); - let mut b_rep = b.repr(); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; - - // Detect if a or b is zero, infinity, or NaN. - if a_abs.wrapping_sub(one) >= inf_rep - one || - b_abs.wrapping_sub(one) >= inf_rep - one { - // NaN + anything = qNaN - if a_abs > inf_rep { - return <$ty as Float>::from_repr(a_abs | quiet_bit); - } - // anything + NaN = qNaN - if b_abs > inf_rep { - return <$ty as Float>::from_repr(b_abs | quiet_bit); - } - - if a_abs == inf_rep { - // +/-infinity + -/+infinity = qNaN - if (a.repr() ^ b.repr()) == sign_bit { - return <$ty as Float>::from_repr(qnan_rep); - } else { - // +/-infinity + anything remaining = +/- infinity - return a; - } - } +fn add(a: F, b: F) -> F where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, +{ + let one = F::Int::ONE; + let zero = F::Int::ZERO; + + let bits = F::BITS.cast(); + let significand_bits = F::SIGNIFICAND_BITS; + let max_exponent = F::EXPONENT_MAX; + + let implicit_bit = F::IMPLICIT_BIT; + let significand_mask = F::SIGNIFICAND_MASK; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXPONENT_MASK; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + + let mut a_rep = a.repr(); + let mut b_rep = b.repr(); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // Detect if a or b is zero, infinity, or NaN. + if a_abs.wrapping_sub(one) >= inf_rep - one || + b_abs.wrapping_sub(one) >= inf_rep - one { + // NaN + anything = qNaN + if a_abs > inf_rep { + return F::from_repr(a_abs | quiet_bit); + } + // anything + NaN = qNaN + if b_abs > inf_rep { + return F::from_repr(b_abs | quiet_bit); + } - // anything remaining + +/-infinity = +/-infinity - if b_abs == inf_rep { - return b; + if a_abs == inf_rep { + // +/-infinity + -/+infinity = qNaN + if (a.repr() ^ b.repr()) == sign_bit { + return F::from_repr(qnan_rep); + } else { + // +/-infinity + anything remaining = +/- infinity + return a; } + } - // zero + anything = anything - if a_abs == 0 { - // but we need to get the sign right for zero + zero - if b_abs == 0 { - return <$ty as Float>::from_repr(a.repr() & b.repr()); - } else { - return b; - } - } + // anything remaining + +/-infinity = +/-infinity + if b_abs == inf_rep { + return b; + } - // anything + zero = anything - if b_abs == 0 { - return a; + // zero + anything = anything + if a_abs == Int::ZERO { + // but we need to get the sign right for zero + zero + if b_abs == Int::ZERO { + return F::from_repr(a.repr() & b.repr()); + } else { + return b; } } - // Swap a and b if necessary so that a has the larger absolute value. - if b_abs > a_abs { - // Don't use mem::swap because it may generate references to memcpy in unoptimized code. - let tmp = a_rep; - a_rep = b_rep; - b_rep = tmp; + // anything + zero = anything + if b_abs == Int::ZERO { + return a; } + } + + // Swap a and b if necessary so that a has the larger absolute value. + if b_abs > a_abs { + // Don't use mem::swap because it may generate references to memcpy in unoptimized code. + let tmp = a_rep; + a_rep = b_rep; + b_rep = tmp; + } - // Extract the exponent and significand from the (possibly swapped) a and b. - let mut a_exponent = ((a_rep >> significand_bits) & max_exponent) as i32; - let mut b_exponent = ((b_rep >> significand_bits) & max_exponent) as i32; - let mut a_significand = a_rep & significand_mask; - let mut b_significand = b_rep & significand_mask; - - // normalize any denormals, and adjust the exponent accordingly. - if a_exponent == 0 { - let (exponent, significand) = <$ty>::normalize(a_significand); - a_exponent = exponent; - a_significand = significand; + // Extract the exponent and significand from the (possibly swapped) a and b. + let mut a_exponent: i32 = ((a_rep & exponent_mask) >> significand_bits).cast(); + let mut b_exponent: i32 = ((b_rep & exponent_mask) >> significand_bits).cast(); + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + + // normalize any denormals, and adjust the exponent accordingly. + if a_exponent == 0 { + let (exponent, significand) = F::normalize(a_significand); + a_exponent = exponent; + a_significand = significand; + } + if b_exponent == 0 { + let (exponent, significand) = F::normalize(b_significand); + b_exponent = exponent; + b_significand = significand; + } + + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + let result_sign = a_rep & sign_bit; + let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize(), but setting it twice won't hurt + // anything.) + a_significand = (a_significand | implicit_bit) << 3; + b_significand = (b_significand | implicit_bit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + let align = a_exponent.wrapping_sub(b_exponent).cast(); + if align != Int::ZERO { + if align < bits { + let sticky = F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != Int::ZERO); + b_significand = (b_significand >> align.cast()) | sticky; + } else { + b_significand = one; // sticky; b is known to be non-zero. } - if b_exponent == 0 { - let (exponent, significand) = <$ty>::normalize(b_significand); - b_exponent = exponent; - b_significand = significand; + } + if subtraction { + a_significand = a_significand.wrapping_sub(b_significand); + // If a == -b, return +zero. + if a_significand == Int::ZERO { + return F::from_repr(Int::ZERO); } - // The sign of the result is the sign of the larger operand, a. If they - // have opposite signs, we are performing a subtraction; otherwise addition. - let result_sign = a_rep & sign_bit; - let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero; - - // Shift the significands to give us round, guard and sticky, and or in the - // implicit significand bit. (If we fell through from the denormal path it - // was already set by normalize(), but setting it twice won't hurt - // anything.) - a_significand = (a_significand | implicit_bit) << 3; - b_significand = (b_significand | implicit_bit) << 3; - - // Shift the significand of b by the difference in exponents, with a sticky - // bottom bit to get rounding correct. - let align = a_exponent.wrapping_sub(b_exponent) as <$ty as Float>::Int; - if align != 0 { - if align < bits { - let sticky = (b_significand << (bits.wrapping_sub(align) as usize) != 0) as <$ty as Float>::Int; - b_significand = (b_significand >> align as usize) | sticky; - } else { - b_significand = one; // sticky; b is known to be non-zero. - } + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if a_significand < implicit_bit << 3 { + let shift = a_significand.leading_zeros() as i32 + - (implicit_bit << 3).leading_zeros() as i32; + a_significand <<= shift; + a_exponent -= shift; } - if subtraction { - a_significand = a_significand.wrapping_sub(b_significand); - // If a == -b, return +zero. - if a_significand == 0 { - return <$ty as Float>::from_repr(0); - } - - // If partial cancellation occured, we need to left-shift the result - // and adjust the exponent: - if a_significand < implicit_bit << 3 { - let shift = a_significand.leading_zeros() as i32 - - (implicit_bit << 3).leading_zeros() as i32; - a_significand <<= shift as usize; - a_exponent -= shift; - } - } else /* addition */ { - a_significand += b_significand; - - // If the addition carried up, we need to right-shift the result and - // adjust the exponent: - if a_significand & implicit_bit << 4 != 0 { - let sticky = (a_significand & one != 0) as <$ty as Float>::Int; - a_significand = a_significand >> 1 | sticky; - a_exponent += 1; - } + } else /* addition */ { + a_significand += b_significand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if a_significand & implicit_bit << 4 != Int::ZERO { + let sticky = F::Int::from_bool(a_significand & one != Int::ZERO); + a_significand = a_significand >> 1 | sticky; + a_exponent += 1; } + } - // If we have overflowed the type, return +/- infinity: - if a_exponent >= max_exponent as i32 { - return <$ty>::from_repr(inf_rep | result_sign); - } + // If we have overflowed the type, return +/- infinity: + if a_exponent >= max_exponent as i32 { + return F::from_repr(inf_rep | result_sign); + } - if a_exponent <= 0 { - // Result is denormal before rounding; the exponent is zero and we - // need to shift the significand. - let shift = (1 - a_exponent) as <$ty as Float>::Int; - let sticky = ((a_significand << bits.wrapping_sub(shift) as usize) != 0) as <$ty as Float>::Int; - a_significand = a_significand >> shift as usize | sticky; - a_exponent = 0; - } + if a_exponent <= 0 { + // Result is denormal before rounding; the exponent is zero and we + // need to shift the significand. + let shift = (1 - a_exponent).cast(); + let sticky = F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != Int::ZERO); + a_significand = a_significand >> shift.cast() | sticky; + a_exponent = 0; + } - // Low three bits are round, guard, and sticky. - let round_guard_sticky: i32 = (a_significand & 0x7) as i32; + // Low three bits are round, guard, and sticky. + let a_significand_i32: i32 = a_significand.cast(); + let round_guard_sticky: i32 = a_significand_i32 & 0x7; - // Shift the significand into place, and mask off the implicit bit. - let mut result = a_significand >> 3 & significand_mask; + // Shift the significand into place, and mask off the implicit bit. + let mut result = a_significand >> 3 & significand_mask; - // Insert the exponent and sign. - result |= (a_exponent as <$ty as Float>::Int) << (significand_bits as usize); - result |= result_sign; + // Insert the exponent and sign. + result |= a_exponent.cast() << significand_bits; + result |= result_sign; - // Final rounding. The result may overflow to infinity, but that is the - // correct result in that case. - if round_guard_sticky > 0x4 { result += one; } - if round_guard_sticky == 0x4 { result += result & one; } + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if round_guard_sticky > 0x4 { result += one; } + if round_guard_sticky == 0x4 { result += result & one; } - <$ty>::from_repr(result) - }) + F::from_repr(result) } intrinsics! { #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_fadd] pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 { - add!(a, b, f32) + add(a, b) } #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_dadd] pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 { - add!(a, b, f64) + add(a, b) } } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index c184301f5e2..c8706c33c5b 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -25,6 +25,7 @@ pub trait Int: ops::AddAssign + ops::BitAndAssign + ops::BitOrAssign + + ops::ShlAssign + ops::ShrAssign + ops::Add + ops::Sub + -- cgit 1.4.1-3-g733a5 From 5ce08df93ec0cbf686c2c43009cc5f5b382e4181 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 17:39:25 +0200 Subject: Remove duplication by adding a macro --- library/compiler-builtins/src/int/mod.rs | 89 ++++++++++---------------------- 1 file changed, 26 insertions(+), 63 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index c8706c33c5b..24b27b1faea 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -84,31 +84,15 @@ fn unwrap(t: Option) -> T { } } -macro_rules! int_impl { - ($ity:ty, $uty:ty, $bits:expr) => { - impl Int for $uty { - type OtherSign = $ity; - type UnsignedInt = $uty; - +macro_rules! int_impl_common { + ($ty:ty, $bits:expr) => { const BITS: u32 = $bits; const ZERO: Self = 0; const ONE: Self = 1; - fn extract_sign(self) -> (bool, $uty) { - (false, self) - } - - fn unsigned(self) -> $uty { - self - } - - fn from_unsigned(me: $uty) -> Self { - me - } - fn from_bool(b: bool) -> Self { - b as $uty + b as $ty } fn max_value() -> Self { @@ -146,17 +130,34 @@ macro_rules! int_impl { fn leading_zeros(self) -> u32 { ::leading_zeros(self) } + } +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty, $bits:expr) => { + impl Int for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + fn extract_sign(self) -> (bool, $uty) { + (false, self) + } + + fn unsigned(self) -> $uty { + self + } + + fn from_unsigned(me: $uty) -> Self { + me + } + + int_impl_common!($uty, $bits); } impl Int for $ity { type OtherSign = $uty; type UnsignedInt = $uty; - const BITS: u32 = $bits; - - const ZERO: Self = 0; - const ONE: Self = 1; - fn extract_sign(self) -> (bool, $uty) { if self < 0 { (true, (!(self as $uty)).wrapping_add(1)) @@ -173,45 +174,7 @@ macro_rules! int_impl { me as $ity } - fn from_bool(b: bool) -> Self { - b as $ity - } - - fn max_value() -> Self { - ::max_value() - } - - fn min_value() -> Self { - ::min_value() - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn aborting_div(self, other: Self) -> Self { - unwrap(::checked_div(self, other)) - } - - fn aborting_rem(self, other: Self) -> Self { - unwrap(::checked_rem(self, other)) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } + int_impl_common!($ity, $bits); } } } -- cgit 1.4.1-3-g733a5 From 259327c25be9cf89f93b405339ac2b799b4ca4fb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 15 Sep 2017 15:59:15 -0700 Subject: Update MinGW download location --- library/compiler-builtins/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index e51ddab740e..bb78ad36a2a 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -14,8 +14,8 @@ environment: # `rust_eh_unwind_resume` in the debug LTO builds that aren't optimized out, # so we skip that test for now. Would be great to not skip it! - TARGET: i686-pc-windows-gnu - MINGW_URL: https://s3.amazonaws.com/rust-lang-ci - MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z + MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror + MINGW_ARCHIVE: i686-6.3.0-release-win32-dwarf-rt_v5-rev1.7z MINGW_DIR: mingw32 DEBUG_LTO_BUILD_DOESNT_WORK: 1 - TARGET: x86_64-pc-windows-gnu -- cgit 1.4.1-3-g733a5 From 1f98921e44cbe72fd12b225c1119f5190dda1a06 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Fri, 15 Sep 2017 17:18:54 -0500 Subject: Implement x86 chkstk in "rust" --- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/build.rs | 2 - library/compiler-builtins/src/lib.rs | 3 ++ library/compiler-builtins/src/x86.rs | 71 +++++++++++++++++++++++++++++++ library/compiler-builtins/src/x86_64.rs | 74 +++++++++++++++++---------------- 5 files changed, 114 insertions(+), 40 deletions(-) create mode 100644 library/compiler-builtins/src/x86.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 3571200aa3b..63569964341 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -159,8 +159,8 @@ features = ["c"] - [x] floatunsisf.c - [ ] i386/ashldi3.S - [ ] i386/ashrdi3.S -- [ ] i386/chkstk.S -- [ ] i386/chkstk2.S +- [x] i386/chkstk.S +- [x] i386/chkstk2.S - [ ] i386/divdi3.S - [ ] i386/lshrdi3.S - [ ] i386/moddi3.S diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 8b5695ba422..74e506eff77 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4176,8 +4176,6 @@ mod c { &[ "i386/ashldi3.S", "i386/ashrdi3.S", - "i386/chkstk.S", - "i386/chkstk2.S", "i386/divdi3.S", "i386/floatdidf.S", "i386/floatdisf.S", diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index b8cf83e2125..d30a218e3df 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -51,6 +51,9 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; +#[cfg(target_arch = "x86")] +pub mod x86; + #[cfg(target_arch = "x86_64")] pub mod x86_64; diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs new file mode 100644 index 00000000000..554b08fec0d --- /dev/null +++ b/library/compiler-builtins/src/x86.rs @@ -0,0 +1,71 @@ +#![allow(unused_imports)] + +use core::intrinsics; + +// NOTE These functions are implemented using assembly because they using a custom +// calling convention which can't be implemented using a normal Rust function + +// NOTE These functions are never mangled as they are not tested against compiler-rt +// and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca + +#[cfg(all(windows, target_env = "gnu"))] +#[naked] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe fn ___chkstk_ms() { + asm!(" + push %ecx + push %eax + cmp $$0x1000,%eax + lea 12(%esp),%ecx + jb 1f + 2: + sub $$0x1000,%ecx + test %ecx,(%ecx) + sub $$0x1000,%eax + cmp $$0x1000,%eax + ja 2b + 1: + sub %eax,%ecx + test %ecx,(%ecx) + pop %eax + pop %ecx + ret"); + intrinsics::unreachable(); +} + +// FIXME: __alloca should be an alias to __chkstk +#[cfg(all(windows, target_env = "gnu"))] +#[naked] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe fn __alloca() { + asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); + intrinsics::unreachable(); +} + +#[cfg(all(windows, target_env = "gnu"))] +#[naked] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe fn ___chkstk() { + asm!(" + push %ecx + cmp $$0x1000,%eax + lea 8(%esp),%ecx // esp before calling this routine -> ecx + jb 1f + 2: + sub $$0x1000,%ecx + test %ecx,(%ecx) + sub $$0x1000,%eax + cmp $$0x1000,%eax + ja 2b + 1: + sub %eax,%ecx + test %ecx,(%ecx) + + lea 4(%esp),%eax // load pointer to the return address into eax + mov %ecx,%esp // install the new top of stack pointer into esp + mov -4(%eax),%ecx // restore ecx + push (%eax) // push return address onto the stack + sub %esp,%eax // restore the original value in eax + ret"); + intrinsics::unreachable(); +} diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index bc3c4ee4c55..221161f4ed6 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -12,23 +12,24 @@ use core::intrinsics; #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn ___chkstk_ms() { - asm!("push %rcx - push %rax - cmp $$0x1000,%rax - lea 24(%rsp),%rcx - jb 1f - 2: - sub $$0x1000,%rcx - test %rcx,(%rcx) - sub $$0x1000,%rax - cmp $$0x1000,%rax - ja 2b - 1: - sub %rax,%rcx - test %rcx,(%rcx) - pop %rax - pop %rcx - ret"); + asm!(" + push %rcx + push %rax + cmp $$0x1000,%rax + lea 24(%rsp),%rcx + jb 1f + 2: + sub $$0x1000,%rcx + test %rcx,(%rcx) + sub $$0x1000,%rax + cmp $$0x1000,%rax + ja 2b + 1: + sub %rax,%rcx + test %rcx,(%rcx) + pop %rax + pop %rcx + ret"); intrinsics::unreachable(); } @@ -45,25 +46,26 @@ pub unsafe fn __alloca() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn ___chkstk() { - asm!("push %rcx - cmp $$0x1000,%rax - lea 16(%rsp),%rcx // rsp before calling this routine -> rcx - jb 1f - 2: - sub $$0x1000,%rcx - test %rcx,(%rcx) - sub $$0x1000,%rax - cmp $$0x1000,%rax - ja 2b - 1: - sub %rax,%rcx - test %rcx,(%rcx) + asm!(" + push %rcx + cmp $$0x1000,%rax + lea 16(%rsp),%rcx // rsp before calling this routine -> rcx + jb 1f + 2: + sub $$0x1000,%rcx + test %rcx,(%rcx) + sub $$0x1000,%rax + cmp $$0x1000,%rax + ja 2b + 1: + sub %rax,%rcx + test %rcx,(%rcx) - lea 8(%rsp),%rax // load pointer to the return address into rax - mov %rcx,%rsp // install the new top of stack pointer into rsp - mov -8(%rax),%rcx // restore rcx - push (%rax) // push return address onto the stack - sub %rsp,%rax // restore the original value in rax - ret"); + lea 8(%rsp),%rax // load pointer to the return address into rax + mov %rcx,%rsp // install the new top of stack pointer into rsp + mov -8(%rax),%rcx // restore rcx + push (%rax) // push return address onto the stack + sub %rsp,%rax // restore the original value in rax + ret"); intrinsics::unreachable(); } -- cgit 1.4.1-3-g733a5 From 81fe6a9654f4dbf473cec7217ab3d2e13733dc69 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Fri, 15 Sep 2017 18:04:11 -0500 Subject: Don't compile probestack functions during testing --- library/compiler-builtins/src/probestack.rs | 8 ++++---- library/compiler-builtins/src/x86.rs | 12 ++++++------ library/compiler-builtins/src/x86_64.rs | 12 ++++++------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 329e2726511..13ea5a5f03b 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -44,8 +44,8 @@ #![cfg(not(windows))] // Windows already has builtins to do this #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg(target_arch = "x86_64")] +#[no_mangle] +#[cfg(all(target_arch = "x86_64", not(feature = "mangled-names")))] pub unsafe extern fn __rust_probestack() { // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, // ensuring that if any pages are unmapped we'll make a page fault. @@ -87,8 +87,8 @@ pub unsafe extern fn __rust_probestack() { } #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg(target_arch = "x86")] +#[no_mangle] +#[cfg(all(target_arch = "x86", not(feature = "mangled-names")))] pub unsafe extern fn __rust_probestack() { // This is the same as x86_64 above, only translated for 32-bit sizes. Note // that on Unix we're expected to restore everything as it was, this diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index 554b08fec0d..3e540e21eff 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -8,9 +8,9 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca -#[cfg(all(windows, target_env = "gnu"))] +#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[no_mangle] pub unsafe fn ___chkstk_ms() { asm!(" push %ecx @@ -34,17 +34,17 @@ pub unsafe fn ___chkstk_ms() { } // FIXME: __alloca should be an alias to __chkstk -#[cfg(all(windows, target_env = "gnu"))] +#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[no_mangle] pub unsafe fn __alloca() { asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); intrinsics::unreachable(); } -#[cfg(all(windows, target_env = "gnu"))] +#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[no_mangle] pub unsafe fn ___chkstk() { asm!(" push %ecx diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 221161f4ed6..09b00815265 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -8,9 +8,9 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca -#[cfg(all(windows, target_env = "gnu"))] +#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[no_mangle] pub unsafe fn ___chkstk_ms() { asm!(" push %rcx @@ -33,18 +33,18 @@ pub unsafe fn ___chkstk_ms() { intrinsics::unreachable(); } -#[cfg(all(windows, target_env = "gnu"))] +#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[no_mangle] pub unsafe fn __alloca() { asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); intrinsics::unreachable(); } -#[cfg(all(windows, target_env = "gnu"))] +#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[no_mangle] pub unsafe fn ___chkstk() { asm!(" push %rcx -- cgit 1.4.1-3-g733a5 From 0a260ce265bf7585881a3630ff7b6346a8824e94 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 17 Sep 2017 15:24:36 -0700 Subject: Disable empty intrinsics on i686-apple-darwin These all currently just produce empty object files --- library/compiler-builtins/build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 74e506eff77..18f32ab1cd8 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4112,7 +4112,9 @@ mod c { ]); } - if target_os != "ios" { + // On iOS and 32-bit OSX these are all just empty intrinsics, no need to + // include them. + if target_os != "ios" && (target_vendor != "apple" || target_arch != "x86") { sources.extend( &[ "absvti2.c", -- cgit 1.4.1-3-g733a5 From 46dab7688fe9d85358dc5795cb6549877012824f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 22 Sep 2017 21:30:12 -0700 Subject: Update to the `cc` dependency --- library/compiler-builtins/Cargo.toml | 6 +++--- library/compiler-builtins/build.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 84cefb2d280..b7743c2ce06 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -8,12 +8,12 @@ version = "0.1.0" cast = { version = "0.2.2", features = ["x128"], optional = true } rand = { version = "0.3.15", optional = true } -[build-dependencies.gcc] +[build-dependencies.cc] optional = true -version = "0.3.53" +version = "1.0" [features] -c = ["gcc"] +c = ["cc"] compiler-builtins = [] default = ["compiler-builtins"] mem = [] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 18f32ab1cd8..1895201e8fa 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -3957,7 +3957,7 @@ macro_rules! panic { #[cfg(feature = "c")] mod c { - extern crate gcc; + extern crate cc; use std::collections::BTreeMap; use std::env; @@ -4008,7 +4008,7 @@ mod c { let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); - let cfg = &mut gcc::Build::new(); + let cfg = &mut cc::Build::new(); cfg.warnings(false); -- cgit 1.4.1-3-g733a5 From 832c7758f94146c16a35de55d1ca100ad4762f50 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 22 Sep 2017 21:31:27 -0700 Subject: Ignore failing test on mips --- library/compiler-builtins/tests/floattidf.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/tests/floattidf.rs b/library/compiler-builtins/tests/floattidf.rs index 4e4f84ddb01..c2e798a9963 100644 --- a/library/compiler-builtins/tests/floattidf.rs +++ b/library/compiler-builtins/tests/floattidf.rs @@ -4,5 +4,6 @@ not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test), no_std)] +#![cfg(not(target_arch = "mips"))] // FIXME(#168) include!(concat!(env!("OUT_DIR"), "/floattidf.rs")); -- cgit 1.4.1-3-g733a5 From aef124cc751774aae1ff2f3648a577359c72b459 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 29 Sep 2017 02:19:40 +0200 Subject: Partially revert 482d98318fc1bfd003942c9de4ee1c7e8a0c45f0 This partially reverts "Convert int_to_float! to a function". --- library/compiler-builtins/src/float/conv.rs | 136 ++++++++++++++-------------- 1 file changed, 66 insertions(+), 70 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index f358a17bd57..52fdf955998 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,87 +1,83 @@ use float::Float; use int::{Int, CastInto}; -fn int_to_float(i: I) -> F where - F::Int: CastInto, - F::Int: CastInto, - I::UnsignedInt: CastInto, - u32: CastInto, -{ - if i == I::ZERO { - return F::ZERO; - } +macro_rules! int_to_float { + ($i:expr, $ity:ty, $fty:ty) => ({ + let i = $i; + if i == 0 { + return 0.0 + } - let two = I::UnsignedInt::ONE + I::UnsignedInt::ONE; - let four = two + two; - let mant_dig = F::SIGNIFICAND_BITS + 1; - let exponent_bias = F::EXPONENT_BIAS; + let mant_dig = <$fty>::SIGNIFICAND_BITS + 1; + let exponent_bias = <$fty>::EXPONENT_BIAS; - let n = I::BITS; - let (s, a) = i.extract_sign(); - let mut a = a; + let n = <$ity>::BITS; + let (s, a) = i.extract_sign(); + let mut a = a; - // number of significant digits - let sd = n - a.leading_zeros(); + // number of significant digits + let sd = n - a.leading_zeros(); - // exponent - let mut e = sd - 1; + // exponent + let mut e = sd - 1; - if I::BITS < mant_dig { - return F::from_parts(s, - (e + exponent_bias).cast(), - a.cast() << (mant_dig - e - 1)); - } + if <$ity>::BITS < mant_dig { + return <$fty>::from_parts(s, + (e + exponent_bias) as <$fty as Float>::Int, + (a as <$fty as Float>::Int) << (mant_dig - e - 1)) + } - a = if sd > mant_dig { - /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx - * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR - * 12345678901234567890123456 - * 1 = msb 1 bit - * P = bit MANT_DIG-1 bits to the right of 1 - * Q = bit MANT_DIG bits to the right of 1 - * R = "or" of all bits to the right of Q - */ - let mant_dig_plus_one = mant_dig + 1; - let mant_dig_plus_two = mant_dig + 2; - a = if sd == mant_dig_plus_one { - a << 1 - } else if sd == mant_dig_plus_two { + a = if sd > mant_dig { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit MANT_DIG-1 bits to the right of 1 + * Q = bit MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + let mant_dig_plus_one = mant_dig + 1; + let mant_dig_plus_two = mant_dig + 2; + a = if sd == mant_dig_plus_one { + a << 1 + } else if sd == mant_dig_plus_two { + a + } else { + (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt | + ((a & <$ity as Int>::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != 0) as <$ity as Int>::UnsignedInt + }; + + /* finish: */ + a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */ + a += 1; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + + /* a is now rounded to mant_dig or mant_dig+1 bits */ + if (a & (1 << mant_dig)) != 0 { + a >>= 1; e += 1; + } a + /* a is now rounded to mant_dig bits */ } else { - (a >> (sd - mant_dig_plus_two)) | - Int::from_bool((a & I::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != Int::ZERO) + a.wrapping_shl(mant_dig - sd) + /* a is now rounded to mant_dig bits */ }; - /* finish: */ - a |= Int::from_bool((a & four) != I::UnsignedInt::ZERO); /* Or P into R */ - a += Int::ONE; /* round - this step may add a significant bit */ - a >>= 2; /* dump Q and R */ - - /* a is now rounded to mant_dig or mant_dig+1 bits */ - if (a & (I::UnsignedInt::ONE << mant_dig)) != Int::ZERO { - a >>= 1; e += 1; - } - a - /* a is now rounded to mant_dig bits */ - } else { - a.wrapping_shl(mant_dig - sd) - /* a is now rounded to mant_dig bits */ - }; - - F::from_parts(s, - (e + exponent_bias).cast(), - a.cast()) + <$fty>::from_parts(s, + (e + exponent_bias) as <$fty as Float>::Int, + a as <$fty as Float>::Int) + }) } intrinsics! { #[arm_aeabi_alias = __aeabi_i2f] pub extern "C" fn __floatsisf(i: i32) -> f32 { - int_to_float(i) + int_to_float!(i, i32, f32) } #[arm_aeabi_alias = __aeabi_i2d] pub extern "C" fn __floatsidf(i: i32) -> f64 { - int_to_float(i) + int_to_float!(i, i32, f64) } #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] @@ -92,28 +88,28 @@ intrinsics! { if cfg!(target_arch = "x86_64") { i as f64 } else { - int_to_float(i) + int_to_float!(i, i64, f64) } } #[unadjusted_on_win64] pub extern "C" fn __floattisf(i: i128) -> f32 { - int_to_float(i) + int_to_float!(i, i128, f32) } #[unadjusted_on_win64] pub extern "C" fn __floattidf(i: i128) -> f64 { - int_to_float(i) + int_to_float!(i, i128, f64) } #[arm_aeabi_alias = __aeabi_ui2f] pub extern "C" fn __floatunsisf(i: u32) -> f32 { - int_to_float(i) + int_to_float!(i, u32, f32) } #[arm_aeabi_alias = __aeabi_ui2d] pub extern "C" fn __floatunsidf(i: u32) -> f64 { - int_to_float(i) + int_to_float!(i, u32, f64) } #[use_c_shim_if(all(not(target_env = "msvc"), @@ -121,17 +117,17 @@ intrinsics! { all(not(windows), target_arch = "x86_64"))))] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { - int_to_float(i) + int_to_float!(i, u64, f64) } #[unadjusted_on_win64] pub extern "C" fn __floatuntisf(i: u128) -> f32 { - int_to_float(i) + int_to_float!(i, u128, f32) } #[unadjusted_on_win64] pub extern "C" fn __floatuntidf(i: u128) -> f64 { - int_to_float(i) + int_to_float!(i, u128, f64) } } -- cgit 1.4.1-3-g733a5 From c582a5c1180d93173abe118364d0f8ea58e134b2 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 29 Sep 2017 02:20:27 +0200 Subject: Partially revert a272d753f5c75ab9acb7b282765a3c7517caac25 This partially reverts commit "Convert float_to_int! into a function" --- library/compiler-builtins/src/float/conv.rs | 125 ++++++++++++++-------------- 1 file changed, 62 insertions(+), 63 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 52fdf955998..33644ce56aa 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,5 +1,5 @@ use float::Float; -use int::{Int, CastInto}; +use int::Int; macro_rules! int_to_float { ($i:expr, $ity:ty, $fty:ty) => ({ @@ -137,116 +137,115 @@ enum Sign { Negative } -fn float_to_int(f: F) -> I where - F::Int: CastInto, - F::Int: CastInto, -{ - let f = f; - let fixint_min = I::min_value(); - let fixint_max = I::max_value(); - let fixint_bits = I::BITS; - let fixint_unsigned = fixint_min == I::ZERO; - - let sign_bit = F::SIGN_MASK; - let significand_bits = F::SIGNIFICAND_BITS; - let exponent_bias = F::EXPONENT_BIAS; - //let exponent_max = F::exponent_max() as usize; - - // Break a into sign, exponent, significand - let a_rep = F::repr(f); - let a_abs = a_rep & !sign_bit; - - // this is used to work around -1 not being available for unsigned - let sign = if (a_rep & sign_bit) == F::Int::ZERO { Sign::Positive } else { Sign::Negative }; - let mut exponent: u32 = (a_abs >> significand_bits).cast(); - let significand = (a_abs & F::SIGNIFICAND_MASK) | F::IMPLICIT_BIT; - - // if < 1 or unsigned & negative - if exponent < exponent_bias || - fixint_unsigned && sign == Sign::Negative { - return I::ZERO; - } - exponent -= exponent_bias; - - // If the value is infinity, saturate. - // If the value is too large for the integer type, 0. - if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { - return if sign == Sign::Positive {fixint_max} else {fixint_min} - } - // If 0 <= exponent < significand_bits, right shift to get the result. - // Otherwise, shift left. - // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned - let r: I = if exponent < significand_bits { - (significand >> (significand_bits - exponent)).cast() - } else { - (significand << (exponent - significand_bits)).cast() - }; - - if sign == Sign::Negative { - (!r).wrapping_add(I::ONE) - } else { - r - } +macro_rules! float_to_int { + ($f:expr, $fty:ty, $ity:ty) => ({ + let f = $f; + let fixint_min = <$ity>::min_value(); + let fixint_max = <$ity>::max_value(); + let fixint_bits = <$ity>::BITS as usize; + let fixint_unsigned = fixint_min == 0; + + let sign_bit = <$fty>::SIGN_MASK; + let significand_bits = <$fty>::SIGNIFICAND_BITS as usize; + let exponent_bias = <$fty>::EXPONENT_BIAS as usize; + //let exponent_max = <$fty>::exponent_max() as usize; + + // Break a into sign, exponent, significand + let a_rep = <$fty>::repr(f); + let a_abs = a_rep & !sign_bit; + + // this is used to work around -1 not being available for unsigned + let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative }; + let mut exponent = (a_abs >> significand_bits) as usize; + let significand = (a_abs & <$fty>::SIGNIFICAND_MASK) | <$fty>::IMPLICIT_BIT; + + // if < 1 or unsigned & negative + if exponent < exponent_bias || + fixint_unsigned && sign == Sign::Negative { + return 0 + } + exponent -= exponent_bias; + + // If the value is infinity, saturate. + // If the value is too large for the integer type, 0. + if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { + return if sign == Sign::Positive {fixint_max} else {fixint_min} + } + // If 0 <= exponent < significand_bits, right shift to get the result. + // Otherwise, shift left. + // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned + let r = if exponent < significand_bits { + (significand >> (significand_bits - exponent)) as $ity + } else { + (significand as $ity) << (exponent - significand_bits) + }; + + if sign == Sign::Negative { + (!r).wrapping_add(1) + } else { + r + } + }) } intrinsics! { #[arm_aeabi_alias = __aeabi_f2iz] pub extern "C" fn __fixsfsi(f: f32) -> i32 { - float_to_int(f) + float_to_int!(f, f32, i32) } #[arm_aeabi_alias = __aeabi_f2lz] pub extern "C" fn __fixsfdi(f: f32) -> i64 { - float_to_int(f) + float_to_int!(f, f32, i64) } #[unadjusted_on_win64] pub extern "C" fn __fixsfti(f: f32) -> i128 { - float_to_int(f) + float_to_int!(f, f32, i128) } #[arm_aeabi_alias = __aeabi_d2iz] pub extern "C" fn __fixdfsi(f: f64) -> i32 { - float_to_int(f) + float_to_int!(f, f64, i32) } #[arm_aeabi_alias = __aeabi_d2lz] pub extern "C" fn __fixdfdi(f: f64) -> i64 { - float_to_int(f) + float_to_int!(f, f64, i64) } #[unadjusted_on_win64] pub extern "C" fn __fixdfti(f: f64) -> i128 { - float_to_int(f) + float_to_int!(f, f64, i128) } #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { - float_to_int(f) + float_to_int!(f, f32, u32) } #[arm_aeabi_alias = __aeabi_f2ulz] pub extern "C" fn __fixunssfdi(f: f32) -> u64 { - float_to_int(f) + float_to_int!(f, f32, u64) } #[unadjusted_on_win64] pub extern "C" fn __fixunssfti(f: f32) -> u128 { - float_to_int(f) + float_to_int!(f, f32, u128) } #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { - float_to_int(f) + float_to_int!(f, f64, u32) } #[arm_aeabi_alias = __aeabi_d2ulz] pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { - float_to_int(f) + float_to_int!(f, f64, u64) } #[unadjusted_on_win64] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { - float_to_int(f) + float_to_int!(f, f64, u128) } } -- cgit 1.4.1-3-g733a5 From d43287ac573e5191b5bde493e0a972c1eef01fff Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 3 Oct 2017 02:28:49 -0700 Subject: Update target specs --- library/compiler-builtins/thumbv6m-linux-eabi.json | 1 + library/compiler-builtins/thumbv7em-linux-eabi.json | 1 + library/compiler-builtins/thumbv7em-linux-eabihf.json | 1 + library/compiler-builtins/thumbv7m-linux-eabi.json | 1 + 4 files changed, 4 insertions(+) diff --git a/library/compiler-builtins/thumbv6m-linux-eabi.json b/library/compiler-builtins/thumbv6m-linux-eabi.json index dd0cb61bc09..ac736eae686 100644 --- a/library/compiler-builtins/thumbv6m-linux-eabi.json +++ b/library/compiler-builtins/thumbv6m-linux-eabi.json @@ -23,5 +23,6 @@ "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", + "target-c-int-width": "32", "vendor": "" } diff --git a/library/compiler-builtins/thumbv7em-linux-eabi.json b/library/compiler-builtins/thumbv7em-linux-eabi.json index eef29f5cc7a..b6d4a6bda7b 100644 --- a/library/compiler-builtins/thumbv7em-linux-eabi.json +++ b/library/compiler-builtins/thumbv7em-linux-eabi.json @@ -22,5 +22,6 @@ "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", + "target-c-int-width": "32", "vendor": "" } diff --git a/library/compiler-builtins/thumbv7em-linux-eabihf.json b/library/compiler-builtins/thumbv7em-linux-eabihf.json index 5d72ec3b478..81cfcd48d56 100644 --- a/library/compiler-builtins/thumbv7em-linux-eabihf.json +++ b/library/compiler-builtins/thumbv7em-linux-eabihf.json @@ -23,5 +23,6 @@ "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", + "target-c-int-width": "32", "vendor": "" } diff --git a/library/compiler-builtins/thumbv7m-linux-eabi.json b/library/compiler-builtins/thumbv7m-linux-eabi.json index 1e8a7f0086f..abe037c5bef 100644 --- a/library/compiler-builtins/thumbv7m-linux-eabi.json +++ b/library/compiler-builtins/thumbv7m-linux-eabi.json @@ -22,5 +22,6 @@ "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", + "target-c-int-width": "32", "vendor": "" } -- cgit 1.4.1-3-g733a5 From c95fefa9f65386687f182878bc2e0334ae802dc7 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 31 Oct 2016 16:03:46 +0000 Subject: Add atomic support for pre-ARMv6 on Linux --- library/compiler-builtins/build.rs | 5 + library/compiler-builtins/src/arm_linux.rs | 170 +++++++++++++++++++++++++++++ library/compiler-builtins/src/lib.rs | 3 + 3 files changed, 178 insertions(+) create mode 100644 library/compiler-builtins/src/arm_linux.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 1895201e8fa..71dec1999aa 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -40,6 +40,11 @@ fn main() { if llvm_target[0] == "thumbv6m" { println!("cargo:rustc-cfg=thumbv6m") } + + // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. + if llvm_target[0] == "armv5te" { + println!("cargo:rustc-cfg=armv5te") + } } #[cfg(feature = "gen-tests")] diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs new file mode 100644 index 00000000000..d94996d7399 --- /dev/null +++ b/library/compiler-builtins/src/arm_linux.rs @@ -0,0 +1,170 @@ +use core::intrinsics; +use core::mem; + +// Kernel-provided user-mode helper functions: +// https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt +unsafe fn __kuser_cmpxchg(oldval: u32, newval: u32, ptr: *mut u32) -> bool { + let out: u32; + // FIXME: we can't use BLX on ARMv4 + asm!("blx ${0}" + : "={r0}" (out) + : "r" (0xffff0fc0u32) + "{r0}" (oldval), + "{r1}" (newval), + "{r2}" (ptr) + : "r3", "r12", "lr", "cc", "memory"); + out == 0 +} +unsafe fn __kuser_memory_barrier() { + // FIXME: we can't use BLX on ARMv4 + asm!("blx ${0}" + : + : "r" (0xffff0fa0u32) + : "lr", "memory"); +} + +// Word-align a pointer +fn align_ptr(ptr: *mut T) -> *mut u32 { + // This gives us a mask of 0 when T == u32 since the pointer is already + // supposed to be aligned, which avoids any masking in that case. + let ptr_mask = 3 & (4 - mem::size_of::()); + (ptr as usize & !ptr_mask) as *mut u32 +} + +// Calculate the shift and mask of a value inside an aligned word +fn get_shift_mask(ptr: *mut T) -> (u32, u32) { + // Mask to get the low byte/halfword/word + let mask = match mem::size_of::() { + 1 => 0xff, + 2 => 0xffff, + 4 => 0xffffffff, + _ => unreachable!(), + }; + + // If we are on big-endian then we need to adjust the shift accordingly + let endian_adjust = if cfg!(target_endian = "little") { + 0 + } else { + 4 - mem::size_of::() as u32 + }; + + // Shift to get the desired element in the word + let ptr_mask = 3 & (4 - mem::size_of::()); + let shift = ((ptr as usize & ptr_mask) as u32 ^ endian_adjust) * 8; + + (shift, mask) +} + +// Extract a value from an aligned word +fn extract_aligned(aligned: u32, shift: u32, mask: u32) -> u32 { + (aligned >> shift) & mask +} + +// Insert a value into an aligned word +fn insert_aligned(aligned: u32, val: u32, shift: u32, mask: u32) -> u32 { + (aligned & !(mask << shift)) | ((val & mask) << shift) +} + +// Generic atomic read-modify-write operation +unsafe fn atomic_rmw u32>(ptr: *mut T, f: F) -> u32 { + let aligned_ptr = align_ptr(ptr); + let (shift, mask) = get_shift_mask(ptr); + + loop { + let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr); + let curval = extract_aligned(curval_aligned, shift, mask); + let newval = f(curval); + let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask); + if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) { + return curval; + } + } +} + +// Generic atomic compare-exchange operation +unsafe fn atomic_cmpxchg(oldval: u32, newval: u32, ptr: *mut T) -> u32 { + let aligned_ptr = align_ptr(ptr); + let (shift, mask) = get_shift_mask(ptr); + + loop { + let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr); + let curval = extract_aligned(curval_aligned, shift, mask); + if curval != oldval { + return curval; + } + let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask); + if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) { + return oldval; + } + } +} + +macro_rules! atomic_rmw { + ($name:ident, $ty:ty, $op:expr) => { + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty { + atomic_rmw(ptr, |x| $op(x as $ty, val) as u32) as $ty + } + } +} +macro_rules! atomic_cmpxchg { + ($name:ident, $ty:ty) => { + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub unsafe extern "C" fn $name(oldval: $ty, newval: $ty, ptr: *mut $ty) -> $ty { + atomic_cmpxchg(oldval as u32, newval as u32, ptr) as $ty + } + } +} + +atomic_rmw!(__sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b)); +atomic_rmw!(__sync_fetch_and_add_2, u16, |a: u16, b: u16| a.wrapping_add(b)); +atomic_rmw!(__sync_fetch_and_add_4, u32, |a: u32, b: u32| a.wrapping_add(b)); + +atomic_rmw!(__sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); +atomic_rmw!(__sync_fetch_and_sub_2, u16, |a: u16, b: u16| a.wrapping_sub(b)); +atomic_rmw!(__sync_fetch_and_sub_4, u32, |a: u32, b: u32| a.wrapping_sub(b)); + +atomic_rmw!(__sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b); +atomic_rmw!(__sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b); +atomic_rmw!(__sync_fetch_and_and_4, u32, |a: u32, b: u32| a & b); + +atomic_rmw!(__sync_fetch_and_or_1, u8, |a: u8, b: u8| a | b); +atomic_rmw!(__sync_fetch_and_or_2, u16, |a: u16, b: u16| a | b); +atomic_rmw!(__sync_fetch_and_or_4, u32, |a: u32, b: u32| a | b); + +atomic_rmw!(__sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b); +atomic_rmw!(__sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b); +atomic_rmw!(__sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b); + +atomic_rmw!(__sync_fetch_and_nand_1, u8, |a: u8, b: u8| !a & b); +atomic_rmw!(__sync_fetch_and_nand_2, u16, |a: u16, b: u16| !a & b); +atomic_rmw!(__sync_fetch_and_nand_4, u32, |a: u32, b: u32| !a & b); + +atomic_rmw!(__sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { a } else { b }); +atomic_rmw!(__sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { a } else { b }); +atomic_rmw!(__sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { a } else { b }); + +atomic_rmw!(__sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { a } else { b }); +atomic_rmw!(__sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { a } else { b }); +atomic_rmw!(__sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { a } else { b }); + +atomic_rmw!(__sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { a } else { b }); +atomic_rmw!(__sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { a } else { b }); +atomic_rmw!(__sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { a } else { b }); + +atomic_rmw!(__sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { a } else { b }); +atomic_rmw!(__sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { a } else { b }); +atomic_rmw!(__sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { a } else { b }); + +atomic_rmw!(__sync_lock_test_and_set_1, u8, |_: u8, b: u8| b); +atomic_rmw!(__sync_lock_test_and_set_2, u16, |_: u16, b: u16| b); +atomic_rmw!(__sync_lock_test_and_set_4, u32, |_: u32, b: u32| b); + +atomic_cmpxchg!(__sync_val_compare_and_swap_1, u8); +atomic_cmpxchg!(__sync_val_compare_and_swap_2, u16); +atomic_cmpxchg!(__sync_val_compare_and_swap_4, u32); + +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe extern "C" fn __sync_synchronize() { + __kuser_memory_barrier(); +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index d30a218e3df..8bf3230654a 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -51,6 +51,9 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; +#[cfg(all(armv5te, target_os = "linux", target_arch = "arm"))] +pub mod arm_linux; + #[cfg(target_arch = "x86")] pub mod x86; -- cgit 1.4.1-3-g733a5 From 0601024adf733d6dc2c072bda5984d74e051de13 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 7 Oct 2017 22:19:37 +0200 Subject: drop binfmt_misc dependency Instead use the Cargo runner feature. The binfmt_misc approach requires running a privileged container for setup. Not all docker setups support privileged containers so the test suite should be more accessible with this change as no privileged container is needed. --- library/compiler-builtins/.travis.yml | 3 --- .../compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 1 + .../compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 2 +- .../compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile | 1 + .../ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile | 1 + library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile | 1 + .../ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile | 1 + .../ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile | 1 + .../compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 1 + .../compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 1 + .../compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile | 1 + .../ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile | 1 + library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile | 1 + library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile | 1 + library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile | 1 + library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile | 1 + 16 files changed, 15 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 8a9d1faa1dc..898a600eb41 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -29,9 +29,6 @@ matrix: os: osx - env: TARGET=x86_64-unknown-linux-gnu -before_install: - - test "$TRAVIS_OS_NAME" = "osx" || docker run --rm --privileged multiarch/qemu-user-static:register - install: - case $TARGET in x86_64-apple-darwin | x86_64-unknown-linux-gnu) ;; diff --git a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index fe05867e379..3f6a63fcb0d 100644 --- a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -5,5 +5,6 @@ RUN apt-get update && \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ qemu-user-static ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-aarch64-static \ QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile index 8a09c20c43e..1c31b00b4ea 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -4,6 +4,6 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER=qemu-arm-static \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ RUST_TEST_THREADS=1 - diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile index 57d830d1cd5..c305b1ba546 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -4,5 +4,6 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile index a2f3cf177a2..76f367f142a 100644 --- a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -4,5 +4,6 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile index 9d69f1dfea3..71a9e8032f8 100644 --- a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -7,5 +7,6 @@ RUN apt-get update && \ binfmt-support qemu-user-static qemu-system-mips ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ + CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER=qemu-mips-static \ QEMU_LD_PREFIX=/usr/mips-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile index ef6eeaad59f..22239e46d8a 100644 --- a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -9,6 +9,7 @@ RUN apt-get update && \ qemu-user-static \ qemu-system-mips ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ + CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64-static \ CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile index 13f770fcc53..77f1fd58c47 100644 --- a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -8,6 +8,7 @@ RUN apt-get update && \ libc6-dev-mips64el-cross \ qemu-user-static ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER=mips64el-linux-gnuabi64-gcc \ + CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64el-static \ CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \ QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile index 0afd5e7f503..98257e76806 100644 --- a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -7,5 +7,6 @@ RUN apt-get update && \ binfmt-support qemu-user-static ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \ + CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER=qemu-mipsel-static \ QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile index 6e65a04db7c..b6bee385ec4 100644 --- a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -7,5 +7,6 @@ RUN apt-get update && \ qemu-system-ppc ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ + CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc-static \ QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile index eb86808f648..26dc1dc2726 100644 --- a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -7,6 +7,7 @@ RUN apt-get update && \ binfmt-support qemu-user-static qemu-system-ppc ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ + CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64-static \ CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile index adb4106d3ef..3b280c0bdc6 100644 --- a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -7,6 +7,7 @@ RUN apt-get update && \ qemu-system-ppc ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ + CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64le-static \ QEMU_CPU=POWER8 \ QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile index d26035618e6..ecf90087e1e 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile @@ -6,4 +6,5 @@ RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv6m_linux_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV6M_LINUX_EABI_LINKER=arm-none-eabi-gcc \ + CARGO_TARGET_THUMBV6M_LINUX_EABI_RUNNER=qemu-arm-static \ CC_thumbv6m_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile index d630352a721..029a55d29a0 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile @@ -6,4 +6,5 @@ RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7em_linux_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_LINUX_EABI_LINKER=arm-none-eabi-gcc \ + CARGO_TARGET_THUMBV7EM_LINUX_EABI_RUNNER=qemu-arm-static \ CC_thumbv7em_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile index 6f30729fa9e..5bf0c76e5be 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile @@ -6,4 +6,5 @@ RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7em_linux_eabihf=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_LINUX_EABIHF_LINKER=arm-none-eabi-gcc \ + CARGO_TARGET_THUMBV7EM_LINUX_EABIHF_RUNNER=qemu-arm-static \ CC_thumbv7em_linux_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile index a7dbad64724..1ffac1f3345 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile @@ -6,4 +6,5 @@ RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7m_linux_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7M_LINUX_EABI_LINKER=arm-none-eabi-gcc \ + CARGO_TARGET_THUMBV7M_LINUX_EABI_RUNNER=qemu-arm-static \ CC_thumbv7m_linux_eabi=arm-none-eabi-gcc \ -- cgit 1.4.1-3-g733a5 From 4fc3de624a1c83e0f0bc818f9fd9753834a73d03 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Oct 2017 17:03:39 -0700 Subject: Prepare this crate for more wasm32 compatibility This commit prepares the build script for a wasm32 target that doesn't use Emcripten, notably forcing the `mem` feature to get activated and forcibly ignoring the `c` feature, even if activated, for the wasm32 target. --- library/compiler-builtins/build.rs | 16 +++++++++++++--- library/compiler-builtins/src/macros.rs | 6 +++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 71dec1999aa..e94914b779f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -12,6 +12,12 @@ fn main() { return; } + // Forcibly enable memory intrinsics on wasm32 as we don't have a libc to + // provide them. + if target.contains("wasm32") { + println!("cargo:rustc-cfg=feature=\"mem\""); + } + // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the // target triple. This is usually correct for our built-in targets but can break in presence of // custom targets, which can have arbitrary names. @@ -25,9 +31,13 @@ fn main() { // mangling names though we assume that we're also in test mode so we don't // build anything and we rely on the upstream implementation of compiler-rt // functions - if !cfg!(feature = "mangled-names") { - #[cfg(feature = "c")] - c::compile(&llvm_target); + if !cfg!(feature = "mangled-names") && cfg!(feature = "c") { + // no C compiler for wasm + if !target.contains("wasm32") { + #[cfg(feature = "c")] + c::compile(&llvm_target); + println!("cargo:rustc-cfg=use_c"); + } } // To compile intrinsics.rs for thumb targets, where there is no libc diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index f6d7db70934..652c9111de6 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -31,7 +31,7 @@ /// A quick overview of attributes supported right now are: /// /// * `use_c_shim_if` - takes a #[cfg] directive and falls back to the -/// C-compiled version if `feature = "c"` is specified. +/// C-compiled version if `use_c` is specified. /// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and /// the specified ABI everywhere else. /// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the @@ -68,7 +68,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(feature = "c", $($cfg_clause)*))] + #[cfg(all(use_c, $($cfg_clause)*))] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { extern $abi { fn $name($($argname: $ty),*) -> $ret; @@ -78,7 +78,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(feature = "c", $($cfg_clause)*)))] + #[cfg(not(all(use_c, $($cfg_clause)*)))] intrinsics! { $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { -- cgit 1.4.1-3-g733a5 From a46f33ce48ded88589926e48fee19eca34dcc6ee Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 Nov 2017 11:14:05 -0700 Subject: Work around OSX on Travis --- library/compiler-builtins/ci/run.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 9a32ee9ea64..95dcdfda959 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -65,6 +65,7 @@ case "$TRAVIS_OS_NAME" in # NOTE OSx's nm doesn't accept the `--defined-only` or provide an equivalent. # Use GNU nm instead NM=gnm + brew update brew install binutils ;; *) -- cgit 1.4.1-3-g733a5 From 5923e278c32a8d52a4d9b380c4025ead2a36089b Mon Sep 17 00:00:00 2001 From: Oliver Geller Date: Wed, 8 Nov 2017 17:36:34 -0500 Subject: Implement mulsf3 and muldf3 --- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/build.rs | 230 +++++++++++++++++++++++++++++ library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/src/float/mul.rs | 191 ++++++++++++++++++++++++ library/compiler-builtins/src/int/mod.rs | 45 ++++++ library/compiler-builtins/tests/muldf3.rs | 7 + library/compiler-builtins/tests/mulsf3.rs | 7 + 7 files changed, 483 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/src/float/mul.rs create mode 100644 library/compiler-builtins/tests/muldf3.rs create mode 100644 library/compiler-builtins/tests/mulsf3.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 63569964341..d1c57c74ef4 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -170,11 +170,11 @@ features = ["c"] - [x] lshrdi3.c - [x] moddi3.c - [x] modsi3.c -- [ ] muldf3.c +- [x] muldf3.c - [x] muldi3.c - [x] mulodi4.c - [x] mulosi4.c -- [ ] mulsf3.c +- [x] mulsf3.c - [x] powidf2.c - [x] powisf2.c - [ ] subdf3.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e94914b779f..be0b1366356 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -121,6 +121,10 @@ mod tests { Subdf3, Subsf3, + // float/mul.rs + Mulsf3, + Muldf3, + // int/mul.rs Muldi3, Mulodi4, @@ -3221,6 +3225,181 @@ fn subsf3() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Mulsf3 { + a: u32, // f32 + b: u32, // f32 + c: u32, // f32 + } + + impl TestCase for Mulsf3 { + fn name() -> &'static str { + "mulsf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f32(rng); + let b = gen_large_f32(rng); + let c = a * b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Mulsf3 { + a: to_u32(a), + b: to_u32(b), + c: to_u32(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::mul::__mulsf3; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn mulsf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __mulsf3(mk_f32(a), mk_f32(b)); + assert_eq!(((a, b), c), ((a, b), to_u32(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Muldf3 { + a: u64, // f64 + b: u64, // f64 + c: u64, // f64 + } + + impl TestCase for Muldf3 { + fn name() -> &'static str { + "muldf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f64(rng); + let b = gen_large_f64(rng); + let c = a * b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Muldf3 { + a: to_u64(a), + b: to_u64(b), + c: to_u64(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::mul::__muldf3; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn muldf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __muldf3(mk_f64(a), mk_f64(b)); + assert_eq!(((a, b), c), ((a, b), to_u64(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] pub struct Udivdi3 { a: u64, @@ -3899,6 +4078,57 @@ macro_rules! panic { gen_float!(gen_f32, f32, u32, 32, 23); gen_float!(gen_f64, f64, u64, 64, 52); + macro_rules! gen_large_float { + ($name:ident, + $fty:ident, + $uty:ident, + $bits:expr, + $significand_bits:expr) => { + pub fn $name(rng: &mut R) -> $fty + where + R: Rng, + { + const BITS: u8 = $bits; + const SIGNIFICAND_BITS: u8 = $significand_bits; + + const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; + const SIGN_MASK: $uty = (1 << (BITS - 1)); + const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); + + fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { + unsafe { + mem::transmute(((sign as $uty) << (BITS - 1)) | + ((exponent & EXPONENT_MASK) << + SIGNIFICAND_BITS) | + (significand & SIGNIFICAND_MASK)) + } + } + + if rng.gen_weighted_bool(10) { + // Special values + *rng.choose(&[-0.0, + 0.0, + ::std::$fty::NAN, + ::std::$fty::INFINITY, + -::std::$fty::INFINITY]) + .unwrap() + } else if rng.gen_weighted_bool(10) { + // NaN patterns + mk_f32(rng.gen(), rng.gen(), 0) + } else if rng.gen() { + // Denormalized + mk_f32(rng.gen(), 0, rng.gen()) + } else { + // Random anything + rng.gen::<$fty>() + } + } + } + } + + gen_large_float!(gen_large_f32, f32, u32, 32, 23); + gen_large_float!(gen_large_f64, f64, u64, 64, 52); + pub fn gen_u128(rng: &mut R) -> u128 where R: Rng, diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 23aef32e5de..55dde9a0245 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -7,6 +7,7 @@ pub mod conv; pub mod add; pub mod pow; pub mod sub; +pub mod mul; /// Trait for some basic operations on floats pub trait Float: diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs new file mode 100644 index 00000000000..696adeaecb3 --- /dev/null +++ b/library/compiler-builtins/src/float/mul.rs @@ -0,0 +1,191 @@ +use int::{CastInto, Int, WideInt}; +use float::Float; + +fn mul(a: F, b: F) -> F +where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, + F::Int: WideInt, +{ + let one = F::Int::ONE; + let zero = F::Int::ZERO; + + let bits = F::BITS; + let significand_bits = F::SIGNIFICAND_BITS; + let max_exponent = F::EXPONENT_MAX; + + let exponent_bias = F::EXPONENT_BIAS; + + let implicit_bit = F::IMPLICIT_BIT; + let significand_mask = F::SIGNIFICAND_MASK; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXPONENT_MASK; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + let exponent_bits = F::EXPONENT_BITS; + + let a_rep = a.repr(); + let b_rep = b.repr(); + + let a_exponent = (a_rep >> significand_bits) & max_exponent.cast(); + let b_exponent = (b_rep >> significand_bits) & max_exponent.cast(); + let product_sign = (a_rep ^ b_rep) & sign_bit; + + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + let mut scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if a_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + || b_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + { + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // NaN + anything = qNaN + if a_abs > inf_rep { + return F::from_repr(a_rep | quiet_bit); + } + // anything + NaN = qNaN + if b_abs > inf_rep { + return F::from_repr(b_rep | quiet_bit); + } + + if a_abs == inf_rep { + if b_abs != zero { + // infinity * non-zero = +/- infinity + return F::from_repr(a_abs | product_sign); + } else { + // infinity * zero = NaN + return F::from_repr(qnan_rep); + } + } + + if b_abs == inf_rep { + if a_abs != zero { + // infinity * non-zero = +/- infinity + return F::from_repr(b_abs | product_sign); + } else { + // infinity * zero = NaN + return F::from_repr(qnan_rep); + } + } + + // zero * anything = +/- zero + if a_abs == zero { + return F::from_repr(product_sign); + } + + // anything * zero = +/- zero + if b_abs == zero { + return F::from_repr(product_sign); + } + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if a_abs < implicit_bit { + let (exponent, significand) = F::normalize(a_significand); + scale += exponent; + a_significand = significand; + } + + if b_abs < implicit_bit { + let (exponent, significand) = F::normalize(b_significand); + scale += exponent; + b_significand = significand; + } + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + a_significand |= implicit_bit; + b_significand |= implicit_bit; + + // Get the significand of a*b. Before multiplying the significands, shift + // one of them left to left-align it in the field. Thus, the product will + // have (exponentBits + 2) integral digits, all but two of which must be + // zero. Normalizing this result is just a conditional left-shift by one + // and bumping the exponent accordingly. + let (mut product_high, mut product_low) = + ::wide_mul(a_significand, b_significand << exponent_bits); + + let a_exponent_i32: i32 = a_exponent.cast(); + let b_exponent_i32: i32 = b_exponent.cast(); + let mut product_exponent: i32 = a_exponent_i32 + .wrapping_add(b_exponent_i32) + .wrapping_add(scale) + .wrapping_sub(exponent_bias as i32); + + // Normalize the significand, adjust exponent if needed. + if (product_high & implicit_bit) != zero { + product_exponent = product_exponent.wrapping_add(1); + } else { + ::wide_shift_left(&mut product_high, &mut product_low, 1); + } + + // If we have overflowed the type, return +/- infinity. + if product_exponent >= max_exponent as i32 { + return F::from_repr(inf_rep | product_sign); + } + + if product_exponent <= 0 { + // Result is denormal before rounding + // + // If the result is so small that it just underflows to zero, return + // a zero of the appropriate sign. Mathematically there is no need to + // handle this case separately, but we make it a special case to + // simplify the shift logic. + let shift = one.wrapping_sub(product_exponent.cast()).cast(); + if shift >= bits as i32 { + return F::from_repr(product_sign); + } + + // Otherwise, shift the significand of the result so that the round + // bit is the high bit of productLo. + ::wide_shift_right_with_sticky( + &mut product_high, + &mut product_low, + shift, + ) + } else { + // Result is normal before rounding; insert the exponent. + product_high &= significand_mask; + product_high |= product_exponent.cast() << significand_bits; + } + + // Insert the sign of the result: + product_high |= product_sign; + + // Final rounding. The final result may overflow to infinity, or underflow + // to zero, but those are the correct results in those cases. We use the + // default IEEE-754 round-to-nearest, ties-to-even rounding mode. + if product_low > sign_bit { + product_high += one; + } + + if product_low == sign_bit { + product_high += product_high & one; + } + + return F::from_repr(product_high); +} + +intrinsics! { + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_fmul] + pub extern "C" fn __mulsf3(a: f32, b: f32) -> f32 { + mul(a, b) + } + + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_dmul] + pub extern "C" fn __muldf3(a: f64, b: f64) -> f64 { + mul(a, b) + } +} diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 24b27b1faea..37dac8cab27 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -249,3 +249,48 @@ cast_into!(u64); cast_into!(i64); cast_into!(u128); cast_into!(i128); + +pub trait WideInt: Int { + type Output: Int; + + fn wide_mul(self, other: Self) -> (Self, Self); + fn wide_shift_left(&mut self, low: &mut Self, count: i32); + fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32); +} + +macro_rules! impl_wide_int { + ($ty:ty, $tywide:ty, $bits:expr) => { + impl WideInt for $ty { + type Output = $ty; + + fn wide_mul(self, other: Self) -> (Self, Self) { + let product = (self as $tywide).wrapping_mul(other as $tywide); + ((product >> ($bits as $ty)) as $ty, product as $ty) + } + + fn wide_shift_left(&mut self, low: &mut Self, count: i32) { + *self = (*self << count) | (*low >> ($bits - count)); + *low = *low << count; + } + + fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32) { + if count < $bits { + let sticky = *low << ($bits - count); + *low = *self << ($bits - count) | *low >> count | sticky; + *self = *self >> count; + } else if count < 2*$bits { + let sticky = *self << (2*$bits - count) | *low; + *low = *self >> (count - $bits ) | sticky; + *self = 0; + } else { + let sticky = *self | *low; + *self = sticky; + *self = 0; + } + } + } + } +} + +impl_wide_int!(u32, u64, 32); +impl_wide_int!(u64, u128, 64); diff --git a/library/compiler-builtins/tests/muldf3.rs b/library/compiler-builtins/tests/muldf3.rs new file mode 100644 index 00000000000..82d06d8de36 --- /dev/null +++ b/library/compiler-builtins/tests/muldf3.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/muldf3.rs")); diff --git a/library/compiler-builtins/tests/mulsf3.rs b/library/compiler-builtins/tests/mulsf3.rs new file mode 100644 index 00000000000..fe278d84be2 --- /dev/null +++ b/library/compiler-builtins/tests/mulsf3.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/mulsf3.rs")); -- cgit 1.4.1-3-g733a5 From 99ea83e095d78849827dab71d42c4c29e8c7e8c0 Mon Sep 17 00:00:00 2001 From: Oliver Geller Date: Sun, 12 Nov 2017 14:40:17 -0500 Subject: Implement divsf3 and divdf3 --- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/build.rs | 185 ++++++++++++ library/compiler-builtins/src/float/div.rs | 457 +++++++++++++++++++++++++++++ library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/tests/divdf3.rs | 7 + library/compiler-builtins/tests/divsf3.rs | 7 + 6 files changed, 659 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/src/float/div.rs create mode 100644 library/compiler-builtins/tests/divdf3.rs create mode 100644 library/compiler-builtins/tests/divsf3.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index d1c57c74ef4..5606ef4c846 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -133,11 +133,11 @@ features = ["c"] - [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c -- [ ] divdf3.c +- [x] divdf3.c - [x] divdi3.c - [x] divmoddi4.c - [x] divmodsi4.c -- [ ] divsf3.c +- [x] divsf3.c - [x] divsi3.c - [ ] extendhfsf2.c - [ ] extendsfdf2.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index be0b1366356..2885d9d00c9 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -125,6 +125,10 @@ mod tests { Mulsf3, Muldf3, + // float/div.rs + Divsf3, + Divdf3, + // int/mul.rs Muldi3, Mulodi4, @@ -3399,6 +3403,187 @@ fn muldf3() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Divsf3 { + a: u32, // f32 + b: u32, // f32 + c: u32, // f32 + } + + impl TestCase for Divsf3 { + fn name() -> &'static str { + "divsf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f32(rng); + let b = gen_large_f32(rng); + if b == 0.0 { + return None; + } + let c = a / b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan()|| c.abs() <= unsafe { mem::transmute(16777215u32) } { + return None; + } + + Some( + Divsf3 { + a: to_u32(a), + b: to_u32(b), + c: to_u32(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::div::__divsf3; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divsf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divsf3(mk_f32(a), mk_f32(b)); + assert_eq!(((a, b), c), ((a, b), to_u32(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divdf3 { + a: u64, // f64 + b: u64, // f64 + c: u64, // f64 + } + + impl TestCase for Divdf3 { + fn name() -> &'static str { + "divdf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f64(rng); + let b = gen_large_f64(rng); + if b == 0.0 { + return None; + } + let c = a / b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() + || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } { + return None; + } + + Some( + Divdf3 { + a: to_u64(a), + b: to_u64(b), + c: to_u64(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::div::__divdf3; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divdf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divdf3(mk_f64(a), mk_f64(b)); + assert_eq!(((a, b), c), ((a, b), to_u64(c_))); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Udivdi3 { diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs new file mode 100644 index 00000000000..e0e287a9ea3 --- /dev/null +++ b/library/compiler-builtins/src/float/div.rs @@ -0,0 +1,457 @@ +use int::{CastInto, Int, WideInt}; +use float::Float; + + + +fn div32(a: F, b: F) -> F +where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, + F::Int: WideInt, +{ + let one = F::Int::ONE; + let zero = F::Int::ZERO; + + // let bits = F::BITS; + let significand_bits = F::SIGNIFICAND_BITS; + let max_exponent = F::EXPONENT_MAX; + + let exponent_bias = F::EXPONENT_BIAS; + + let implicit_bit = F::IMPLICIT_BIT; + let significand_mask = F::SIGNIFICAND_MASK; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXPONENT_MASK; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + + #[inline(always)] + fn negate_u32(a: u32) -> u32 { + (::wrapping_neg(a as i32)) as u32 + } + + let a_rep = a.repr(); + let b_rep = b.repr(); + + let a_exponent = (a_rep >> significand_bits) & max_exponent.cast(); + let b_exponent = (b_rep >> significand_bits) & max_exponent.cast(); + let quotient_sign = (a_rep ^ b_rep) & sign_bit; + + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + let mut scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if a_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + || b_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + { + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // NaN / anything = qNaN + if a_abs > inf_rep { + return F::from_repr(a_rep | quiet_bit); + } + // anything / NaN = qNaN + if b_abs > inf_rep { + return F::from_repr(b_rep | quiet_bit); + } + + if a_abs == inf_rep { + if b_abs == inf_rep { + // infinity / infinity = NaN + return F::from_repr(qnan_rep); + } else { + // infinity / anything else = +/- infinity + return F::from_repr(a_abs | quotient_sign); + } + } + + // anything else / infinity = +/- 0 + if b_abs == inf_rep { + return F::from_repr(quotient_sign); + } + + if a_abs == zero { + if b_abs == zero { + // zero / zero = NaN + return F::from_repr(qnan_rep); + } else { + // zero / anything else = +/- zero + return F::from_repr(quotient_sign); + } + } + + // anything else / zero = +/- infinity + if b_abs == zero { + return F::from_repr(inf_rep | quotient_sign); + } + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if a_abs < implicit_bit { + let (exponent, significand) = F::normalize(a_significand); + scale += exponent; + a_significand = significand; + } + + if b_abs < implicit_bit { + let (exponent, significand) = F::normalize(b_significand); + scale -= exponent; + b_significand = significand; + } + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + a_significand |= implicit_bit; + b_significand |= implicit_bit; + let mut quotient_exponent: i32 = CastInto::::cast(a_exponent) + .wrapping_sub(CastInto::::cast(b_exponent)) + .wrapping_add(scale); + + // Align the significand of b as a Q31 fixed-point number in the range + // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax + // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This + // is accurate to about 3.5 binary digits. + let q31b = CastInto::::cast(b_significand << 8.cast()); + let mut reciprocal = (0x7504f333u32).wrapping_sub(q31b); + + // Now refine the reciprocal estimate using a Newton-Raphson iteration: + // + // x1 = x0 * (2 - x0 * b) + // + // This doubles the number of correct binary digits in the approximation + // with each iteration, so after three iterations, we have about 28 binary + // digits of accuracy. + let mut correction: u32; + correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); + reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; + correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); + reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; + correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); + reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; + + // Exhaustive testing shows that the error in reciprocal after three steps + // is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our + // expectations. We bump the reciprocal by a tiny value to force the error + // to be strictly positive (in the range [0x1.4fdfp-37,0x1.287246p-29], to + // be specific). This also causes 1/1 to give a sensible approximation + // instead of zero (due to overflow). + reciprocal = reciprocal.wrapping_sub(2); + + // The numerical reciprocal is accurate to within 2^-28, lies in the + // interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller + // than the true reciprocal of b. Multiplying a by this reciprocal thus + // gives a numerical q = a/b in Q24 with the following properties: + // + // 1. q < a/b + // 2. q is in the interval [0x1.000000eep-1, 0x1.fffffffcp0) + // 3. the error in q is at most 2^-24 + 2^-27 -- the 2^24 term comes + // from the fact that we truncate the product, and the 2^27 term + // is the error in the reciprocal of b scaled by the maximum + // possible value of a. As a consequence of this error bound, + // either q or nextafter(q) is the correctly rounded + let (mut quotient, _) = ::wide_mul(a_significand << 1, reciprocal.cast()); + + // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). + // In either case, we are going to compute a residual of the form + // + // r = a - q*b + // + // We know from the construction of q that r satisfies: + // + // 0 <= r < ulp(q)*b + // + // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we + // already have the correct result. The exact halfway case cannot occur. + // We also take this time to right shift quotient if it falls in the [1,2) + // range and adjust the exponent accordingly. + let residual = if quotient < (implicit_bit << 1) { + quotient_exponent = quotient_exponent.wrapping_sub(1); + (a_significand << (significand_bits + 1)).wrapping_sub(quotient.wrapping_mul(b_significand)) + } else { + quotient >>= 1; + (a_significand << significand_bits).wrapping_sub(quotient.wrapping_mul(b_significand)) + }; + + let written_exponent = quotient_exponent.wrapping_add(exponent_bias as i32); + + if written_exponent >= max_exponent as i32 { + // If we have overflowed the exponent, return infinity. + return F::from_repr(inf_rep | quotient_sign); + } else if written_exponent < 1 { + // Flush denormals to zero. In the future, it would be nice to add + // code to round them correctly. + return F::from_repr(quotient_sign); + } else { + let round = ((residual << 1) > b_significand) as u32; + // Clear the implicit bits + let mut abs_result = quotient & significand_mask; + // Insert the exponent + abs_result |= written_exponent.cast() << significand_bits; + // Round + abs_result = abs_result.wrapping_add(round.cast()); + // Insert the sign and return + return F::from_repr(abs_result | quotient_sign); + } +} + +fn div64(a: F, b: F) -> F +where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, + u64: CastInto, + F::Int: CastInto, + i64: CastInto, + F::Int: CastInto, + F::Int: WideInt, +{ + let one = F::Int::ONE; + let zero = F::Int::ZERO; + + // let bits = F::BITS; + let significand_bits = F::SIGNIFICAND_BITS; + let max_exponent = F::EXPONENT_MAX; + + let exponent_bias = F::EXPONENT_BIAS; + + let implicit_bit = F::IMPLICIT_BIT; + let significand_mask = F::SIGNIFICAND_MASK; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXPONENT_MASK; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + // let exponent_bits = F::EXPONENT_BITS; + + #[inline(always)] + fn negate_u32(a: u32) -> u32 { + (::wrapping_neg(a as i32)) as u32 + } + + #[inline(always)] + fn negate_u64(a: u64) -> u64 { + (::wrapping_neg(a as i64)) as u64 + } + + let a_rep = a.repr(); + let b_rep = b.repr(); + + let a_exponent = (a_rep >> significand_bits) & max_exponent.cast(); + let b_exponent = (b_rep >> significand_bits) & max_exponent.cast(); + let quotient_sign = (a_rep ^ b_rep) & sign_bit; + + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + let mut scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if a_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + || b_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + { + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // NaN / anything = qNaN + if a_abs > inf_rep { + return F::from_repr(a_rep | quiet_bit); + } + // anything / NaN = qNaN + if b_abs > inf_rep { + return F::from_repr(b_rep | quiet_bit); + } + + if a_abs == inf_rep { + if b_abs == inf_rep { + // infinity / infinity = NaN + return F::from_repr(qnan_rep); + } else { + // infinity / anything else = +/- infinity + return F::from_repr(a_abs | quotient_sign); + } + } + + // anything else / infinity = +/- 0 + if b_abs == inf_rep { + return F::from_repr(quotient_sign); + } + + if a_abs == zero { + if b_abs == zero { + // zero / zero = NaN + return F::from_repr(qnan_rep); + } else { + // zero / anything else = +/- zero + return F::from_repr(quotient_sign); + } + } + + // anything else / zero = +/- infinity + if b_abs == zero { + return F::from_repr(inf_rep | quotient_sign); + } + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if a_abs < implicit_bit { + let (exponent, significand) = F::normalize(a_significand); + scale += exponent; + a_significand = significand; + } + + if b_abs < implicit_bit { + let (exponent, significand) = F::normalize(b_significand); + scale -= exponent; + b_significand = significand; + } + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + a_significand |= implicit_bit; + b_significand |= implicit_bit; + let mut quotient_exponent: i32 = CastInto::::cast(a_exponent) + .wrapping_sub(CastInto::::cast(b_exponent)) + .wrapping_add(scale); + + // Align the significand of b as a Q31 fixed-point number in the range + // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax + // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This + // is accurate to about 3.5 binary digits. + let q31b = CastInto::::cast(b_significand >> 21.cast()); + let mut recip32 = (0x7504f333u32).wrapping_sub(q31b); + + // Now refine the reciprocal estimate using a Newton-Raphson iteration: + // + // x1 = x0 * (2 - x0 * b) + // + // This doubles the number of correct binary digits in the approximation + // with each iteration, so after three iterations, we have about 28 binary + // digits of accuracy. + let mut correction32: u32; + correction32 = negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); + recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; + correction32 = negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); + recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; + correction32 = negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); + recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; + + // recip32 might have overflowed to exactly zero in the preceeding + // computation if the high word of b is exactly 1.0. This would sabotage + // the full-width final stage of the computation that follows, so we adjust + // recip32 downward by one bit. + recip32 = recip32.wrapping_sub(1); + + // We need to perform one more iteration to get us to 56 binary digits; + // The last iteration needs to happen with extra precision. + let q63blo = CastInto::::cast(b_significand << 11.cast()); + let correction: u64; + let mut reciprocal: u64; + correction = negate_u64( + (recip32 as u64) + .wrapping_mul(q31b as u64) + .wrapping_add((recip32 as u64).wrapping_mul(q63blo as u64) >> 32), + ); + let c_hi = (correction >> 32) as u32; + let c_lo = correction as u32; + reciprocal = (recip32 as u64) + .wrapping_mul(c_hi as u64) + .wrapping_add((recip32 as u64).wrapping_mul(c_lo as u64) >> 32); + + // We already adjusted the 32-bit estimate, now we need to adjust the final + // 64-bit reciprocal estimate downward to ensure that it is strictly smaller + // than the infinitely precise exact reciprocal. Because the computation + // of the Newton-Raphson step is truncating at every step, this adjustment + // is small; most of the work is already done. + reciprocal = reciprocal.wrapping_sub(2); + + // The numerical reciprocal is accurate to within 2^-56, lies in the + // interval [0.5, 1.0), and is strictly smaller than the true reciprocal + // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b + // in Q53 with the following properties: + // + // 1. q < a/b + // 2. q is in the interval [0.5, 2.0) + // 3. the error in q is bounded away from 2^-53 (actually, we have a + // couple of bits to spare, but this is all we need). + + // We need a 64 x 64 multiply high to compute q, which isn't a basic + // operation in C, so we need to be a little bit fussy. + // let mut quotient: F::Int = ((((reciprocal as u64) + // .wrapping_mul(CastInto::::cast(a_significand << 1) as u64)) + // >> 32) as u32) + // .cast(); + + // We need a 64 x 64 multiply high to compute q, which isn't a basic + // operation in C, so we need to be a little bit fussy. + let (mut quotient, _) = ::wide_mul(a_significand << 2, reciprocal.cast()); + + + // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). + // In either case, we are going to compute a residual of the form + // + // r = a - q*b + // + // We know from the construction of q that r satisfies: + // + // 0 <= r < ulp(q)*b + // + // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we + // already have the correct result. The exact halfway case cannot occur. + // We also take this time to right shift quotient if it falls in the [1,2) + // range and adjust the exponent accordingly. + let residual = if quotient < (implicit_bit << 1) { + quotient_exponent = quotient_exponent.wrapping_sub(1); + (a_significand << (significand_bits + 1)).wrapping_sub(quotient.wrapping_mul(b_significand)) + } else { + quotient >>= 1; + (a_significand << significand_bits).wrapping_sub(quotient.wrapping_mul(b_significand)) + }; + + let written_exponent = quotient_exponent.wrapping_add(exponent_bias as i32); + + if written_exponent >= max_exponent as i32 { + // If we have overflowed the exponent, return infinity. + return F::from_repr(inf_rep | quotient_sign); + } else if written_exponent < 1 { + // Flush denormals to zero. In the future, it would be nice to add + // code to round them correctly. + return F::from_repr(quotient_sign); + } else { + let round = ((residual << 1) > b_significand) as u32; + // Clear the implicit bits + let mut abs_result = quotient & significand_mask; + // Insert the exponent + abs_result |= written_exponent.cast() << significand_bits; + // Round + abs_result = abs_result.wrapping_add(round.cast()); + // Insert the sign and return + return F::from_repr(abs_result | quotient_sign); + } +} + + +intrinsics! { + #[arm_aeabi_alias = __aeabi_fdiv] + pub extern "C" fn __divsf3(a: f32, b: f32) -> f32 { + div32(a, b) + } + + #[arm_aeabi_alias = __aeabi_ddiv] + pub extern "C" fn __divdf3(a: f64, b: f64) -> f64 { + div64(a, b) + } + +} diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 55dde9a0245..6daf7b8f75f 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -8,6 +8,7 @@ pub mod add; pub mod pow; pub mod sub; pub mod mul; +pub mod div; /// Trait for some basic operations on floats pub trait Float: diff --git a/library/compiler-builtins/tests/divdf3.rs b/library/compiler-builtins/tests/divdf3.rs new file mode 100644 index 00000000000..98d32d1b084 --- /dev/null +++ b/library/compiler-builtins/tests/divdf3.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/divdf3.rs")); diff --git a/library/compiler-builtins/tests/divsf3.rs b/library/compiler-builtins/tests/divsf3.rs new file mode 100644 index 00000000000..5cf3e86ca01 --- /dev/null +++ b/library/compiler-builtins/tests/divsf3.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/divsf3.rs")); -- cgit 1.4.1-3-g733a5 From 3bd28c8b6d2ff270ad1e0d9861f4fa8502fd2ba0 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 15 Nov 2017 12:49:10 -0800 Subject: Add "volatile" and "memory" clobber to asm! that doesn't fall through. Use the "volatile" option and the "memory" clobber on inline asm that does things like return directly, to reduce the chances of compilers rearranging the code. --- library/compiler-builtins/src/arm.rs | 8 ++++---- library/compiler-builtins/src/probestack.rs | 4 ++-- library/compiler-builtins/src/x86.rs | 7 ++++--- library/compiler-builtins/src/x86_64.rs | 12 ++++++++---- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index fa86e969146..25fdd52429e 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -11,7 +11,7 @@ pub unsafe fn __aeabi_uidivmod() { bl __udivmodsi4 ldr r1, [sp] add sp, sp, #4 - pop {pc}"); + pop {pc}" ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -26,7 +26,7 @@ pub unsafe fn __aeabi_uldivmod() { ldr r2, [sp, #8] ldr r3, [sp, #12] add sp, sp, #16 - pop {r4, pc}"); + pop {r4, pc}" ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -38,7 +38,7 @@ pub unsafe fn __aeabi_idivmod() { pop {r1, r2} muls r2, r2, r0 subs r1, r1, r2 - pop {r4, pc}"); + pop {r4, pc}" ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -53,7 +53,7 @@ pub unsafe fn __aeabi_ldivmod() { ldr r2, [sp, #8] ldr r3, [sp, #12] add sp, sp, #16 - pop {r4, pc}"); + pop {r4, pc}" ::: "memory" : "volatile"); intrinsics::unreachable(); } diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 13ea5a5f03b..34f466e1e3a 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -82,7 +82,7 @@ pub unsafe extern fn __rust_probestack() { add %rax,%rsp ret - "); + " ::: "memory" : "volatile"); ::core::intrinsics::unreachable(); } @@ -111,6 +111,6 @@ pub unsafe extern fn __rust_probestack() { add %eax,%esp pop %ecx ret - "); + " ::: "memory" : "volatile"); ::core::intrinsics::unreachable(); } diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index 3e540e21eff..035c0a31c41 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -29,7 +29,7 @@ pub unsafe fn ___chkstk_ms() { test %ecx,(%ecx) pop %eax pop %ecx - ret"); + ret" ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -38,7 +38,8 @@ pub unsafe fn ___chkstk_ms() { #[naked] #[no_mangle] pub unsafe fn __alloca() { - asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); + asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" + ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -66,6 +67,6 @@ pub unsafe fn ___chkstk() { mov -4(%eax),%ecx // restore ecx push (%eax) // push return address onto the stack sub %esp,%eax // restore the original value in eax - ret"); + ret" ::: "memory" : "volatile"); intrinsics::unreachable(); } diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 09b00815265..2360ab8a6fa 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -29,7 +29,7 @@ pub unsafe fn ___chkstk_ms() { test %rcx,(%rcx) pop %rax pop %rcx - ret"); + ret" ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -38,7 +38,8 @@ pub unsafe fn ___chkstk_ms() { #[no_mangle] pub unsafe fn __alloca() { asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx - jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); + jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" + ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -46,7 +47,8 @@ pub unsafe fn __alloca() { #[naked] #[no_mangle] pub unsafe fn ___chkstk() { - asm!(" + asm!( + " push %rcx cmp $$0x1000,%rax lea 16(%rsp),%rcx // rsp before calling this routine -> rcx @@ -66,6 +68,8 @@ pub unsafe fn ___chkstk() { mov -8(%rax),%rcx // restore rcx push (%rax) // push return address onto the stack sub %rsp,%rax // restore the original value in rax - ret"); + ret" + ::: "memory" : "volatile" + ); intrinsics::unreachable(); } -- cgit 1.4.1-3-g733a5 From 7115a910c8905095bee677ee0ba29793482b132e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 19 Nov 2017 09:07:11 -0800 Subject: Remove divsf3.c from compiler-rt We implement this now! --- library/compiler-builtins/build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2885d9d00c9..e2a63a6cf97 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4497,9 +4497,7 @@ mod c { "ctzdi2.c", "ctzsi2.c", "divdc3.c", - "divdf3.c", "divsc3.c", - "divsf3.c", "divxc3.c", "extendsfdf2.c", "extendhfsf2.c", -- cgit 1.4.1-3-g733a5 From ff97668431754e6ca892356da88e838bc5e52bd5 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 25 Nov 2017 04:21:05 -0800 Subject: Implement all the 128-bit operator lang items from rust PR 46093 --- library/compiler-builtins/src/int/add.rs | 111 +++++++++++++++++++++++++++++ library/compiler-builtins/src/int/mod.rs | 7 ++ library/compiler-builtins/src/int/mul.rs | 37 ++++++++++ library/compiler-builtins/src/int/sdiv.rs | 11 +++ library/compiler-builtins/src/int/shift.rs | 42 +++++++++++ library/compiler-builtins/src/int/sub.rs | 109 ++++++++++++++++++++++++++++ library/compiler-builtins/src/int/udiv.rs | 11 +++ library/compiler-builtins/src/lib.rs | 1 + 8 files changed, 329 insertions(+) create mode 100644 library/compiler-builtins/src/int/add.rs create mode 100644 library/compiler-builtins/src/int/sub.rs diff --git a/library/compiler-builtins/src/int/add.rs b/library/compiler-builtins/src/int/add.rs new file mode 100644 index 00000000000..639d14ac309 --- /dev/null +++ b/library/compiler-builtins/src/int/add.rs @@ -0,0 +1,111 @@ +use int::LargeInt; +use int::Int; + +trait Add: LargeInt { + fn add(self, other: Self) -> Self { + let (low, carry) = self.low().overflowing_add(other.low()); + let high = self.high().wrapping_add(other.high()); + let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; + Self::from_parts(low, high.wrapping_add(carry)) + } +} + +impl Add for u128 {} + +trait Addo: Int { + fn addo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = self.wrapping_add(other); + if other >= Self::ZERO { + if result < self { + *overflow = 1; + } + } else { + if result >= self { + *overflow = 1; + } + } + result + } +} + +impl Addo for i128 {} +impl Addo for u128 {} + +#[cfg_attr(not(stage0), lang = "i128_add")] +#[allow(dead_code)] +fn rust_i128_add(a: i128, b: i128) -> i128 { + rust_u128_add(a as _, b as _) as _ +} +#[cfg_attr(not(stage0), lang = "i128_addo")] +#[allow(dead_code)] +fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = a.addo(b, &mut oflow); + (r, oflow != 0) +} +#[cfg_attr(not(stage0), lang = "u128_add")] +#[allow(dead_code)] +fn rust_u128_add(a: u128, b: u128) -> u128 { + a.add(b) +} +#[cfg_attr(not(stage0), lang = "u128_addo")] +#[allow(dead_code)] +fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.addo(b, &mut oflow); + (r, oflow != 0) +} + +#[test] +fn test_add() { + assert_eq!(rust_u128_add(1, 2), 3); + assert_eq!(rust_u128_add(!0, 3), 2); + assert_eq!(rust_u128_add(1 << 63, 1 << 63), 1 << 64); + assert_eq!(rust_u128_add( + 0x54009B79B43145A0_B781BF1FD491296E_u128, + 0x6019CEECA5354210_839AB51D155FF7F3_u128), + 0xB41A6A66596687B1_3B1C743CE9F12161_u128); + assert_eq!(rust_u128_add( + 0x3AE89C3AACEE47CD_8721275248B38DDB_u128, + 0xEFDD73C41D344744_B0842900C3352A63_u128), + 0x2AC60FFECA228F12_37A550530BE8B83E_u128); + + assert_eq!(rust_i128_add(1, 2), 3); + assert_eq!(rust_i128_add(-1, 3), 2); +} + +#[test] +fn test_addo() { + assert_eq!(rust_u128_addo(1, 2), (3, false)); + assert_eq!(rust_u128_addo(!0, 3), (2, true)); + assert_eq!(rust_u128_addo(1 << 63, 1 << 63), (1 << 64, false)); + assert_eq!(rust_u128_addo( + 0x54009B79B43145A0_B781BF1FD491296E_u128, + 0x6019CEECA5354210_839AB51D155FF7F3_u128), + (0xB41A6A66596687B1_3B1C743CE9F12161_u128, false)); + assert_eq!(rust_u128_addo( + 0x3AE89C3AACEE47CD_8721275248B38DDB_u128, + 0xEFDD73C41D344744_B0842900C3352A63_u128), + (0x2AC60FFECA228F12_37A550530BE8B83E_u128, true)); + + assert_eq!(rust_i128_addo(1, 2), (3, false)); + assert_eq!(rust_i128_addo(-1, 3), (2, false)); + assert_eq!(rust_i128_addo(1 << 63, 1 << 63), (1 << 64, false)); + assert_eq!(rust_i128_addo( + 0x54009B79B43145A0_B781BF1FD491296E_i128, + 0x6019CEECA5354210_839AB51D155FF7F3_i128), + (-0x4BE59599A699784E_C4E38BC3160EDE9F_i128, true)); + assert_eq!(rust_i128_addo( + 0x3AE89C3AACEE47CD_8721275248B38DDB_i128, + -0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), + (0x2AC60FFECA228F12_37A550530BE8B83E_i128, false)); + assert_eq!(rust_i128_addo( + -0x54009B79B43145A0_B781BF1FD491296E_i128, + -0x6019CEECA5354210_839AB51D155FF7F3_i128), + (0x4BE59599A699784E_C4E38BC3160EDE9F_i128, true)); + assert_eq!(rust_i128_addo( + -0x3AE89C3AACEE47CD_8721275248B38DDB_i128, + 0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), + (-0x2AC60FFECA228F12_37A550530BE8B83E_i128, false)); +} \ No newline at end of file diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 37dac8cab27..c5490cba796 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -12,9 +12,11 @@ macro_rules! os_ty { } } +pub mod add; pub mod mul; pub mod sdiv; pub mod shift; +pub mod sub; pub mod udiv; /// Trait for some basic operations on integers @@ -72,6 +74,7 @@ pub trait Int: fn wrapping_mul(self, other: Self) -> Self; fn wrapping_sub(self, other: Self) -> Self; fn wrapping_shl(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); fn aborting_div(self, other: Self) -> Self; fn aborting_rem(self, other: Self) -> Self; fn leading_zeros(self) -> u32; @@ -119,6 +122,10 @@ macro_rules! int_impl_common { ::wrapping_shl(self, other) } + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + fn aborting_div(self, other: Self) -> Self { unwrap(::checked_div(self, other)) } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index a4b2ebd7fb7..9d45fa54b8b 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -70,6 +70,18 @@ impl Mulo for i32 {} impl Mulo for i64 {} impl Mulo for i128 {} +trait UMulo : Int { + fn mulo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = self.wrapping_mul(other); + if self > Self::max_value().aborting_div(other) { + *overflow = 1; + } + result + } +} +impl UMulo for u128 {} + intrinsics! { #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] #[arm_aeabi_alias = __aeabi_lmul] @@ -95,3 +107,28 @@ intrinsics! { a.mulo(b, oflow) } } + +#[cfg_attr(not(stage0), lang = "i128_mul")] +#[allow(dead_code)] +fn rust_i128_mul(a: i128, b: i128) -> i128 { + __multi3(a, b) +} +#[cfg_attr(not(stage0), lang = "i128_mulo")] +#[allow(dead_code)] +fn rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = __muloti4(a, b, &mut oflow); + (r, oflow != 0) +} +#[cfg_attr(not(stage0), lang = "u128_mul")] +#[allow(dead_code)] +fn rust_u128_mul(a: u128, b: u128) -> u128 { + __multi3(a as _, b as _) as _ +} +#[cfg_attr(not(stage0), lang = "u128_mulo")] +#[allow(dead_code)] +fn rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.mulo(b, &mut oflow); + (r, oflow != 0) +} diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index ff8fa61e4b9..6fef631c624 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -97,3 +97,14 @@ intrinsics! { a.divmod(b, rem, |a, b| __divdi3(a, b)) } } + +#[cfg_attr(not(stage0), lang = "i128_div")] +#[allow(dead_code)] +fn rust_i128_div(a: i128, b: i128) -> i128 { + __divti3(a, b) +} +#[cfg_attr(not(stage0), lang = "i128_rem")] +#[allow(dead_code)] +fn rust_i128_rem(a: i128, b: i128) -> i128 { + __modti3(a, b) +} diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 805d7059623..de6d06b6c68 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -95,3 +95,45 @@ intrinsics! { a.lshr(b) } } + +#[cfg_attr(not(stage0), lang = "i128_shl")] +#[allow(dead_code)] +fn rust_i128_shl(a: i128, b: u32) -> i128 { + __ashlti3(a as _, b) as _ +} +#[cfg_attr(not(stage0), lang = "i128_shlo")] +#[allow(dead_code)] +fn rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { + (rust_i128_shl(a, b as _), b >= 128) +} +#[cfg_attr(not(stage0), lang = "u128_shl")] +#[allow(dead_code)] +fn rust_u128_shl(a: u128, b: u32) -> u128 { + __ashlti3(a, b) +} +#[cfg_attr(not(stage0), lang = "u128_shlo")] +#[allow(dead_code)] +fn rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { + (rust_u128_shl(a, b as _), b >= 128) +} + +#[cfg_attr(not(stage0), lang = "i128_shr")] +#[allow(dead_code)] +fn rust_i128_shr(a: i128, b: u32) -> i128 { + __ashrti3(a, b) +} +#[cfg_attr(not(stage0), lang = "i128_shro")] +#[allow(dead_code)] +fn rust_i128_shro(a: i128, b: u128) -> (i128, bool) { + (rust_i128_shr(a, b as _), b >= 128) +} +#[cfg_attr(not(stage0), lang = "u128_shr")] +#[allow(dead_code)] +fn rust_u128_shr(a: u128, b: u32) -> u128 { + __lshrti3(a, b) +} +#[cfg_attr(not(stage0), lang = "u128_shro")] +#[allow(dead_code)] +fn rust_u128_shro(a: u128, b: u128) -> (u128, bool) { + (rust_u128_shr(a, b as _), b >= 128) +} diff --git a/library/compiler-builtins/src/int/sub.rs b/library/compiler-builtins/src/int/sub.rs new file mode 100644 index 00000000000..4d3dfeb9ff0 --- /dev/null +++ b/library/compiler-builtins/src/int/sub.rs @@ -0,0 +1,109 @@ +use int::LargeInt; +use int::Int; + +trait Sub: LargeInt { + fn sub(self, other: Self) -> Self { + let neg_other = (!other).wrapping_add(Self::ONE); + self.wrapping_add(neg_other) + } +} + +impl Sub for u128 {} + +trait Subo: Int { + fn subo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = self.wrapping_sub(other); + if other >= Self::ZERO { + if result > self { + *overflow = 1; + } + } else { + if result <= self { + *overflow = 1; + } + } + result + } +} + +impl Subo for i128 {} +impl Subo for u128 {} + +#[cfg_attr(not(stage0), lang = "i128_sub")] +#[allow(dead_code)] +fn rust_i128_sub(a: i128, b: i128) -> i128 { + rust_u128_sub(a as _, b as _) as _ +} +#[cfg_attr(not(stage0), lang = "i128_subo")] +#[allow(dead_code)] +fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = a.subo(b, &mut oflow); + (r, oflow != 0) +} +#[cfg_attr(not(stage0), lang = "u128_sub")] +#[allow(dead_code)] +fn rust_u128_sub(a: u128, b: u128) -> u128 { + a.sub(b) +} +#[cfg_attr(not(stage0), lang = "u128_subo")] +#[allow(dead_code)] +fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.subo(b, &mut oflow); + (r, oflow != 0) +} + +#[test] +fn test_sub() { + assert_eq!(rust_u128_sub(3, 2), 1); + assert_eq!(rust_u128_sub(2, 3), !0); + assert_eq!(rust_u128_sub(1 << 64, 1 << 63), 1 << 63); + assert_eq!(rust_u128_sub( + 0xB41A6A66596687B1_3B1C743CE9F12161_u128, + 0x6019CEECA5354210_839AB51D155FF7F3_u128), + 0x54009B79B43145A0_B781BF1FD491296E_u128); + assert_eq!(rust_u128_sub( + 0x2AC60FFECA228F12_37A550530BE8B83E_u128, + 0xEFDD73C41D344744_B0842900C3352A63_u128), + 0x3AE89C3AACEE47CD_8721275248B38DDB_u128); + + assert_eq!(rust_i128_sub(3, 2), 1); + assert_eq!(rust_i128_sub(2, 3), -1); +} + +#[test] +fn test_subo() { + assert_eq!(rust_u128_subo(3, 2), (1, false)); + assert_eq!(rust_u128_subo(2, 3), (!0, true)); + assert_eq!(rust_u128_subo(1 << 64, 1 << 63), (1 << 63, false)); + assert_eq!(rust_u128_subo( + 0xB41A6A66596687B1_3B1C743CE9F12161_u128, + 0x6019CEECA5354210_839AB51D155FF7F3_u128), + (0x54009B79B43145A0_B781BF1FD491296E_u128, false)); + assert_eq!(rust_u128_subo( + 0x2AC60FFECA228F12_37A550530BE8B83E_u128, + 0xEFDD73C41D344744_B0842900C3352A63_u128), + (0x3AE89C3AACEE47CD_8721275248B38DDB_u128, true)); + + assert_eq!(rust_i128_subo(3, 2), (1, false)); + assert_eq!(rust_i128_subo(2, 3), (-1, false)); + assert_eq!(rust_i128_subo(1 << 64, 1 << 63), (1 << 63, false)); + assert_eq!(rust_i128_subo( + -0x4BE59599A699784E_C4E38BC3160EDE9F_i128, + 0x6019CEECA5354210_839AB51D155FF7F3_i128), + (0x54009B79B43145A0_B781BF1FD491296E_i128, true)); + assert_eq!(rust_i128_subo( + 0x2AC60FFECA228F12_37A550530BE8B83E_i128, + -0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), + (0x3AE89C3AACEE47CD_8721275248B38DDB_i128, false)); + assert_eq!(rust_i128_subo( + 0x4BE59599A699784E_C4E38BC3160EDE9F_i128, + -0x6019CEECA5354210_839AB51D155FF7F3_i128), + (-0x54009B79B43145A0_B781BF1FD491296E_i128, true)); + assert_eq!(rust_i128_subo( + -0x2AC60FFECA228F12_37A550530BE8B83E_i128, + 0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), + (-0x3AE89C3AACEE47CD_8721275248B38DDB_i128, false)); +} \ No newline at end of file diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 74a2ac3387d..0442a8c4a0e 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -269,3 +269,14 @@ intrinsics! { udivmod_inner!(n, d, rem, u128) } } + +#[cfg_attr(not(stage0), lang = "u128_div")] +#[allow(dead_code)] +fn rust_u128_div(a: u128, b: u128) -> u128 { + __udivti3(a, b) +} +#[cfg_attr(not(stage0), lang = "u128_rem")] +#[allow(dead_code)] +fn rust_u128_rem(a: u128, b: u128) -> u128 { + __umodti3(a, b) +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 8bf3230654a..ff7885bb3f6 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -17,6 +17,7 @@ #![feature(repr_simd)] #![feature(abi_unadjusted)] #![feature(linkage)] +#![feature(lang_items)] #![allow(unused_features)] #![no_builtins] #![unstable(feature = "compiler_builtins_lib", -- cgit 1.4.1-3-g733a5 From a35d63583f58a733ebd9b86e1848729ab3f044db Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 25 Nov 2017 05:26:24 -0800 Subject: Tweak addo & subo to try and fix MIPS --- library/compiler-builtins/src/int/add.rs | 21 +++++++++++++++++---- library/compiler-builtins/src/int/sub.rs | 6 +++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/src/int/add.rs b/library/compiler-builtins/src/int/add.rs index 639d14ac309..4253b64f7ba 100644 --- a/library/compiler-builtins/src/int/add.rs +++ b/library/compiler-builtins/src/int/add.rs @@ -1,8 +1,8 @@ use int::LargeInt; use int::Int; -trait Add: LargeInt { - fn add(self, other: Self) -> Self { +trait UAdd: LargeInt { + fn uadd(self, other: Self) -> Self { let (low, carry) = self.low().overflowing_add(other.low()); let high = self.high().wrapping_add(other.high()); let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; @@ -10,12 +10,25 @@ trait Add: LargeInt { } } +impl UAdd for u128 {} + +trait Add: Int + where ::UnsignedInt: UAdd +{ + fn add(self, other: Self) -> Self { + Self::from_unsigned(self.unsigned().uadd(other.unsigned())) + } +} + impl Add for u128 {} +impl Add for i128 {} -trait Addo: Int { +trait Addo: Add + where ::UnsignedInt: UAdd +{ fn addo(self, other: Self, overflow: &mut i32) -> Self { *overflow = 0; - let result = self.wrapping_add(other); + let result = Add::add(self, other); if other >= Self::ZERO { if result < self { *overflow = 1; diff --git a/library/compiler-builtins/src/int/sub.rs b/library/compiler-builtins/src/int/sub.rs index 4d3dfeb9ff0..ba29c102157 100644 --- a/library/compiler-builtins/src/int/sub.rs +++ b/library/compiler-builtins/src/int/sub.rs @@ -1,5 +1,4 @@ use int::LargeInt; -use int::Int; trait Sub: LargeInt { fn sub(self, other: Self) -> Self { @@ -8,12 +7,13 @@ trait Sub: LargeInt { } } +impl Sub for i128 {} impl Sub for u128 {} -trait Subo: Int { +trait Subo: Sub { fn subo(self, other: Self, overflow: &mut i32) -> Self { *overflow = 0; - let result = self.wrapping_sub(other); + let result = Sub::sub(self, other); if other >= Self::ZERO { if result > self { *overflow = 1; -- cgit 1.4.1-3-g733a5 From 51a0396d2a208fd5cd06b3d9350ddcd298edd2fb Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 25 Nov 2017 05:53:53 -0800 Subject: Make them all `pub` --- library/compiler-builtins/src/int/add.rs | 12 ++++-------- library/compiler-builtins/src/int/mul.rs | 12 ++++-------- library/compiler-builtins/src/int/sdiv.rs | 6 ++---- library/compiler-builtins/src/int/shift.rs | 24 ++++++++---------------- library/compiler-builtins/src/int/sub.rs | 12 ++++-------- library/compiler-builtins/src/int/udiv.rs | 6 ++---- 6 files changed, 24 insertions(+), 48 deletions(-) diff --git a/library/compiler-builtins/src/int/add.rs b/library/compiler-builtins/src/int/add.rs index 4253b64f7ba..b0f7ab6214a 100644 --- a/library/compiler-builtins/src/int/add.rs +++ b/library/compiler-builtins/src/int/add.rs @@ -46,25 +46,21 @@ impl Addo for i128 {} impl Addo for u128 {} #[cfg_attr(not(stage0), lang = "i128_add")] -#[allow(dead_code)] -fn rust_i128_add(a: i128, b: i128) -> i128 { +pub fn rust_i128_add(a: i128, b: i128) -> i128 { rust_u128_add(a as _, b as _) as _ } #[cfg_attr(not(stage0), lang = "i128_addo")] -#[allow(dead_code)] -fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { +pub fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { let mut oflow = 0; let r = a.addo(b, &mut oflow); (r, oflow != 0) } #[cfg_attr(not(stage0), lang = "u128_add")] -#[allow(dead_code)] -fn rust_u128_add(a: u128, b: u128) -> u128 { +pub fn rust_u128_add(a: u128, b: u128) -> u128 { a.add(b) } #[cfg_attr(not(stage0), lang = "u128_addo")] -#[allow(dead_code)] -fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { +pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { let mut oflow = 0; let r = a.addo(b, &mut oflow); (r, oflow != 0) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 9d45fa54b8b..61c379c7b68 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -109,25 +109,21 @@ intrinsics! { } #[cfg_attr(not(stage0), lang = "i128_mul")] -#[allow(dead_code)] -fn rust_i128_mul(a: i128, b: i128) -> i128 { +pub fn rust_i128_mul(a: i128, b: i128) -> i128 { __multi3(a, b) } #[cfg_attr(not(stage0), lang = "i128_mulo")] -#[allow(dead_code)] -fn rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { +pub fn rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { let mut oflow = 0; let r = __muloti4(a, b, &mut oflow); (r, oflow != 0) } #[cfg_attr(not(stage0), lang = "u128_mul")] -#[allow(dead_code)] -fn rust_u128_mul(a: u128, b: u128) -> u128 { +pub fn rust_u128_mul(a: u128, b: u128) -> u128 { __multi3(a as _, b as _) as _ } #[cfg_attr(not(stage0), lang = "u128_mulo")] -#[allow(dead_code)] -fn rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { +pub fn rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { let mut oflow = 0; let r = a.mulo(b, &mut oflow); (r, oflow != 0) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 6fef631c624..03086646695 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -99,12 +99,10 @@ intrinsics! { } #[cfg_attr(not(stage0), lang = "i128_div")] -#[allow(dead_code)] -fn rust_i128_div(a: i128, b: i128) -> i128 { +pub fn rust_i128_div(a: i128, b: i128) -> i128 { __divti3(a, b) } #[cfg_attr(not(stage0), lang = "i128_rem")] -#[allow(dead_code)] -fn rust_i128_rem(a: i128, b: i128) -> i128 { +pub fn rust_i128_rem(a: i128, b: i128) -> i128 { __modti3(a, b) } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index de6d06b6c68..f8faad829a9 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -97,43 +97,35 @@ intrinsics! { } #[cfg_attr(not(stage0), lang = "i128_shl")] -#[allow(dead_code)] -fn rust_i128_shl(a: i128, b: u32) -> i128 { +pub fn rust_i128_shl(a: i128, b: u32) -> i128 { __ashlti3(a as _, b) as _ } #[cfg_attr(not(stage0), lang = "i128_shlo")] -#[allow(dead_code)] -fn rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { +pub fn rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { (rust_i128_shl(a, b as _), b >= 128) } #[cfg_attr(not(stage0), lang = "u128_shl")] -#[allow(dead_code)] -fn rust_u128_shl(a: u128, b: u32) -> u128 { +pub fn rust_u128_shl(a: u128, b: u32) -> u128 { __ashlti3(a, b) } #[cfg_attr(not(stage0), lang = "u128_shlo")] -#[allow(dead_code)] -fn rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { +pub fn rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { (rust_u128_shl(a, b as _), b >= 128) } #[cfg_attr(not(stage0), lang = "i128_shr")] -#[allow(dead_code)] -fn rust_i128_shr(a: i128, b: u32) -> i128 { +pub fn rust_i128_shr(a: i128, b: u32) -> i128 { __ashrti3(a, b) } #[cfg_attr(not(stage0), lang = "i128_shro")] -#[allow(dead_code)] -fn rust_i128_shro(a: i128, b: u128) -> (i128, bool) { +pub fn rust_i128_shro(a: i128, b: u128) -> (i128, bool) { (rust_i128_shr(a, b as _), b >= 128) } #[cfg_attr(not(stage0), lang = "u128_shr")] -#[allow(dead_code)] -fn rust_u128_shr(a: u128, b: u32) -> u128 { +pub fn rust_u128_shr(a: u128, b: u32) -> u128 { __lshrti3(a, b) } #[cfg_attr(not(stage0), lang = "u128_shro")] -#[allow(dead_code)] -fn rust_u128_shro(a: u128, b: u128) -> (u128, bool) { +pub fn rust_u128_shro(a: u128, b: u128) -> (u128, bool) { (rust_u128_shr(a, b as _), b >= 128) } diff --git a/library/compiler-builtins/src/int/sub.rs b/library/compiler-builtins/src/int/sub.rs index ba29c102157..0b0cbf2479f 100644 --- a/library/compiler-builtins/src/int/sub.rs +++ b/library/compiler-builtins/src/int/sub.rs @@ -31,25 +31,21 @@ impl Subo for i128 {} impl Subo for u128 {} #[cfg_attr(not(stage0), lang = "i128_sub")] -#[allow(dead_code)] -fn rust_i128_sub(a: i128, b: i128) -> i128 { +pub fn rust_i128_sub(a: i128, b: i128) -> i128 { rust_u128_sub(a as _, b as _) as _ } #[cfg_attr(not(stage0), lang = "i128_subo")] -#[allow(dead_code)] -fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { +pub fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { let mut oflow = 0; let r = a.subo(b, &mut oflow); (r, oflow != 0) } #[cfg_attr(not(stage0), lang = "u128_sub")] -#[allow(dead_code)] -fn rust_u128_sub(a: u128, b: u128) -> u128 { +pub fn rust_u128_sub(a: u128, b: u128) -> u128 { a.sub(b) } #[cfg_attr(not(stage0), lang = "u128_subo")] -#[allow(dead_code)] -fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { +pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { let mut oflow = 0; let r = a.subo(b, &mut oflow); (r, oflow != 0) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 0442a8c4a0e..6c100f3f86d 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -271,12 +271,10 @@ intrinsics! { } #[cfg_attr(not(stage0), lang = "u128_div")] -#[allow(dead_code)] -fn rust_u128_div(a: u128, b: u128) -> u128 { +pub fn rust_u128_div(a: u128, b: u128) -> u128 { __udivti3(a, b) } #[cfg_attr(not(stage0), lang = "u128_rem")] -#[allow(dead_code)] -fn rust_u128_rem(a: u128, b: u128) -> u128 { +pub fn rust_u128_rem(a: u128, b: u128) -> u128 { __umodti3(a, b) } -- cgit 1.4.1-3-g733a5 From ba376a39125d3890c618450ea5ec960781fda1d8 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 25 Nov 2017 06:24:07 -0800 Subject: Autogenerate the add/sub tests --- library/compiler-builtins/build.rs | 484 +++++++++++++++++++++++++++ library/compiler-builtins/src/int/add.rs | 53 --- library/compiler-builtins/src/int/sub.rs | 53 --- library/compiler-builtins/tests/i128_add.rs | 8 + library/compiler-builtins/tests/i128_addo.rs | 8 + library/compiler-builtins/tests/i128_sub.rs | 8 + library/compiler-builtins/tests/i128_subo.rs | 8 + library/compiler-builtins/tests/u128_add.rs | 8 + library/compiler-builtins/tests/u128_addo.rs | 8 + library/compiler-builtins/tests/u128_sub.rs | 8 + library/compiler-builtins/tests/u128_subo.rs | 8 + 11 files changed, 548 insertions(+), 106 deletions(-) create mode 100644 library/compiler-builtins/tests/i128_add.rs create mode 100644 library/compiler-builtins/tests/i128_addo.rs create mode 100644 library/compiler-builtins/tests/i128_sub.rs create mode 100644 library/compiler-builtins/tests/i128_subo.rs create mode 100644 library/compiler-builtins/tests/u128_add.rs create mode 100644 library/compiler-builtins/tests/u128_addo.rs create mode 100644 library/compiler-builtins/tests/u128_sub.rs create mode 100644 library/compiler-builtins/tests/u128_subo.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e2a63a6cf97..d7f6c01becf 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -129,6 +129,12 @@ mod tests { Divsf3, Divdf3, + // int/add.rs + AddU128, + AddI128, + AddoU128, + AddoI128, + // int/mul.rs Muldi3, Mulodi4, @@ -154,6 +160,12 @@ mod tests { Lshrdi3, Lshrti3, + // int/sub.rs + SubU128, + SubI128, + SuboU128, + SuboI128, + // int/udiv.rs Udivdi3, Udivmoddi4, @@ -341,6 +353,242 @@ fn addsf3() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct AddU128 { + a: u128, + b: u128, + c: u128, + } + + impl TestCase for AddU128 { + fn name() -> &'static str { + "u128_add" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = gen_u128(rng); + let c = a.wrapping_add(b); + + Some(AddU128 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::add::rust_u128_add; + +static TEST_CASES: &[((u128, u128), u128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn u128_add() { + for &((a, b), c) in TEST_CASES { + let c_ = rust_u128_add(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct AddI128 { + a: i128, + b: i128, + c: i128, + } + + impl TestCase for AddI128 { + fn name() -> &'static str { + "i128_add" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + let c = a.wrapping_add(b); + + Some(AddI128 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::add::rust_i128_add; + +static TEST_CASES: &[((i128, i128), i128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn i128_add() { + for &((a, b), c) in TEST_CASES { + let c_ = rust_i128_add(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct AddoU128 { + a: u128, + b: u128, + c: u128, + d: bool, + } + + impl TestCase for AddoU128 { + fn name() -> &'static str { + "u128_addo" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = gen_u128(rng); + let (c, d) = a.overflowing_add(b); + + Some(AddoU128 { a, b, c, d }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {d})),", + a = self.a, + b = self.b, + c = self.c, + d = self.d + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::add::rust_u128_addo; + +static TEST_CASES: &[((u128, u128), (u128, bool))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn u128_addo() { + for &((a, b), (c, d)) in TEST_CASES { + let (c_, d_) = rust_u128_addo(a, b); + assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct AddoI128 { + a: i128, + b: i128, + c: i128, + d: bool, + } + + impl TestCase for AddoI128 { + fn name() -> &'static str { + "i128_addo" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + let (c, d) = a.overflowing_add(b); + + Some(AddoI128 { a, b, c, d }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {d})),", + a = self.a, + b = self.b, + c = self.c, + d = self.d + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::add::rust_i128_addo; + +static TEST_CASES: &[((i128, i128), (i128, bool))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn i128_addo() { + for &((a, b), (c, d)) in TEST_CASES { + let (c_, d_) = rust_i128_addo(a, b); + assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Ashldi3 { a: u64, @@ -3229,6 +3477,242 @@ fn subsf3() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct SubU128 { + a: u128, + b: u128, + c: u128, + } + + impl TestCase for SubU128 { + fn name() -> &'static str { + "u128_sub" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = gen_u128(rng); + let c = a.wrapping_sub(b); + + Some(SubU128 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sub::rust_u128_sub; + +static TEST_CASES: &[((u128, u128), u128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn u128_sub() { + for &((a, b), c) in TEST_CASES { + let c_ = rust_u128_sub(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct SubI128 { + a: i128, + b: i128, + c: i128, + } + + impl TestCase for SubI128 { + fn name() -> &'static str { + "i128_sub" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + let c = a.wrapping_sub(b); + + Some(SubI128 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sub::rust_i128_sub; + +static TEST_CASES: &[((i128, i128), i128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn i128_sub() { + for &((a, b), c) in TEST_CASES { + let c_ = rust_i128_sub(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct SuboU128 { + a: u128, + b: u128, + c: u128, + d: bool, + } + + impl TestCase for SuboU128 { + fn name() -> &'static str { + "u128_subo" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = gen_u128(rng); + let (c, d) = a.overflowing_sub(b); + + Some(SuboU128 { a, b, c, d }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {d})),", + a = self.a, + b = self.b, + c = self.c, + d = self.d + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sub::rust_u128_subo; + +static TEST_CASES: &[((u128, u128), (u128, bool))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn u128_subo() { + for &((a, b), (c, d)) in TEST_CASES { + let (c_, d_) = rust_u128_subo(a, b); + assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct SuboI128 { + a: i128, + b: i128, + c: i128, + d: bool, + } + + impl TestCase for SuboI128 { + fn name() -> &'static str { + "i128_subo" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + let (c, d) = a.overflowing_sub(b); + + Some(SuboI128 { a, b, c, d }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {d})),", + a = self.a, + b = self.b, + c = self.c, + d = self.d + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sub::rust_i128_subo; + +static TEST_CASES: &[((i128, i128), (i128, bool))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn i128_subo() { + for &((a, b), (c, d)) in TEST_CASES { + let (c_, d_) = rust_i128_subo(a, b); + assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Mulsf3 { a: u32, // f32 diff --git a/library/compiler-builtins/src/int/add.rs b/library/compiler-builtins/src/int/add.rs index b0f7ab6214a..5c746c233dd 100644 --- a/library/compiler-builtins/src/int/add.rs +++ b/library/compiler-builtins/src/int/add.rs @@ -65,56 +65,3 @@ pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { let r = a.addo(b, &mut oflow); (r, oflow != 0) } - -#[test] -fn test_add() { - assert_eq!(rust_u128_add(1, 2), 3); - assert_eq!(rust_u128_add(!0, 3), 2); - assert_eq!(rust_u128_add(1 << 63, 1 << 63), 1 << 64); - assert_eq!(rust_u128_add( - 0x54009B79B43145A0_B781BF1FD491296E_u128, - 0x6019CEECA5354210_839AB51D155FF7F3_u128), - 0xB41A6A66596687B1_3B1C743CE9F12161_u128); - assert_eq!(rust_u128_add( - 0x3AE89C3AACEE47CD_8721275248B38DDB_u128, - 0xEFDD73C41D344744_B0842900C3352A63_u128), - 0x2AC60FFECA228F12_37A550530BE8B83E_u128); - - assert_eq!(rust_i128_add(1, 2), 3); - assert_eq!(rust_i128_add(-1, 3), 2); -} - -#[test] -fn test_addo() { - assert_eq!(rust_u128_addo(1, 2), (3, false)); - assert_eq!(rust_u128_addo(!0, 3), (2, true)); - assert_eq!(rust_u128_addo(1 << 63, 1 << 63), (1 << 64, false)); - assert_eq!(rust_u128_addo( - 0x54009B79B43145A0_B781BF1FD491296E_u128, - 0x6019CEECA5354210_839AB51D155FF7F3_u128), - (0xB41A6A66596687B1_3B1C743CE9F12161_u128, false)); - assert_eq!(rust_u128_addo( - 0x3AE89C3AACEE47CD_8721275248B38DDB_u128, - 0xEFDD73C41D344744_B0842900C3352A63_u128), - (0x2AC60FFECA228F12_37A550530BE8B83E_u128, true)); - - assert_eq!(rust_i128_addo(1, 2), (3, false)); - assert_eq!(rust_i128_addo(-1, 3), (2, false)); - assert_eq!(rust_i128_addo(1 << 63, 1 << 63), (1 << 64, false)); - assert_eq!(rust_i128_addo( - 0x54009B79B43145A0_B781BF1FD491296E_i128, - 0x6019CEECA5354210_839AB51D155FF7F3_i128), - (-0x4BE59599A699784E_C4E38BC3160EDE9F_i128, true)); - assert_eq!(rust_i128_addo( - 0x3AE89C3AACEE47CD_8721275248B38DDB_i128, - -0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), - (0x2AC60FFECA228F12_37A550530BE8B83E_i128, false)); - assert_eq!(rust_i128_addo( - -0x54009B79B43145A0_B781BF1FD491296E_i128, - -0x6019CEECA5354210_839AB51D155FF7F3_i128), - (0x4BE59599A699784E_C4E38BC3160EDE9F_i128, true)); - assert_eq!(rust_i128_addo( - -0x3AE89C3AACEE47CD_8721275248B38DDB_i128, - 0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), - (-0x2AC60FFECA228F12_37A550530BE8B83E_i128, false)); -} \ No newline at end of file diff --git a/library/compiler-builtins/src/int/sub.rs b/library/compiler-builtins/src/int/sub.rs index 0b0cbf2479f..abcb45a80ee 100644 --- a/library/compiler-builtins/src/int/sub.rs +++ b/library/compiler-builtins/src/int/sub.rs @@ -50,56 +50,3 @@ pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { let r = a.subo(b, &mut oflow); (r, oflow != 0) } - -#[test] -fn test_sub() { - assert_eq!(rust_u128_sub(3, 2), 1); - assert_eq!(rust_u128_sub(2, 3), !0); - assert_eq!(rust_u128_sub(1 << 64, 1 << 63), 1 << 63); - assert_eq!(rust_u128_sub( - 0xB41A6A66596687B1_3B1C743CE9F12161_u128, - 0x6019CEECA5354210_839AB51D155FF7F3_u128), - 0x54009B79B43145A0_B781BF1FD491296E_u128); - assert_eq!(rust_u128_sub( - 0x2AC60FFECA228F12_37A550530BE8B83E_u128, - 0xEFDD73C41D344744_B0842900C3352A63_u128), - 0x3AE89C3AACEE47CD_8721275248B38DDB_u128); - - assert_eq!(rust_i128_sub(3, 2), 1); - assert_eq!(rust_i128_sub(2, 3), -1); -} - -#[test] -fn test_subo() { - assert_eq!(rust_u128_subo(3, 2), (1, false)); - assert_eq!(rust_u128_subo(2, 3), (!0, true)); - assert_eq!(rust_u128_subo(1 << 64, 1 << 63), (1 << 63, false)); - assert_eq!(rust_u128_subo( - 0xB41A6A66596687B1_3B1C743CE9F12161_u128, - 0x6019CEECA5354210_839AB51D155FF7F3_u128), - (0x54009B79B43145A0_B781BF1FD491296E_u128, false)); - assert_eq!(rust_u128_subo( - 0x2AC60FFECA228F12_37A550530BE8B83E_u128, - 0xEFDD73C41D344744_B0842900C3352A63_u128), - (0x3AE89C3AACEE47CD_8721275248B38DDB_u128, true)); - - assert_eq!(rust_i128_subo(3, 2), (1, false)); - assert_eq!(rust_i128_subo(2, 3), (-1, false)); - assert_eq!(rust_i128_subo(1 << 64, 1 << 63), (1 << 63, false)); - assert_eq!(rust_i128_subo( - -0x4BE59599A699784E_C4E38BC3160EDE9F_i128, - 0x6019CEECA5354210_839AB51D155FF7F3_i128), - (0x54009B79B43145A0_B781BF1FD491296E_i128, true)); - assert_eq!(rust_i128_subo( - 0x2AC60FFECA228F12_37A550530BE8B83E_i128, - -0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), - (0x3AE89C3AACEE47CD_8721275248B38DDB_i128, false)); - assert_eq!(rust_i128_subo( - 0x4BE59599A699784E_C4E38BC3160EDE9F_i128, - -0x6019CEECA5354210_839AB51D155FF7F3_i128), - (-0x54009B79B43145A0_B781BF1FD491296E_i128, true)); - assert_eq!(rust_i128_subo( - -0x2AC60FFECA228F12_37A550530BE8B83E_i128, - 0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), - (-0x3AE89C3AACEE47CD_8721275248B38DDB_i128, false)); -} \ No newline at end of file diff --git a/library/compiler-builtins/tests/i128_add.rs b/library/compiler-builtins/tests/i128_add.rs new file mode 100644 index 00000000000..13af0500cb8 --- /dev/null +++ b/library/compiler-builtins/tests/i128_add.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/i128_add.rs")); diff --git a/library/compiler-builtins/tests/i128_addo.rs b/library/compiler-builtins/tests/i128_addo.rs new file mode 100644 index 00000000000..306ffac169e --- /dev/null +++ b/library/compiler-builtins/tests/i128_addo.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/i128_addo.rs")); diff --git a/library/compiler-builtins/tests/i128_sub.rs b/library/compiler-builtins/tests/i128_sub.rs new file mode 100644 index 00000000000..933fe4f5661 --- /dev/null +++ b/library/compiler-builtins/tests/i128_sub.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/i128_sub.rs")); diff --git a/library/compiler-builtins/tests/i128_subo.rs b/library/compiler-builtins/tests/i128_subo.rs new file mode 100644 index 00000000000..0c2b67cbbdc --- /dev/null +++ b/library/compiler-builtins/tests/i128_subo.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/i128_subo.rs")); diff --git a/library/compiler-builtins/tests/u128_add.rs b/library/compiler-builtins/tests/u128_add.rs new file mode 100644 index 00000000000..d4b8f2ccb24 --- /dev/null +++ b/library/compiler-builtins/tests/u128_add.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/u128_add.rs")); diff --git a/library/compiler-builtins/tests/u128_addo.rs b/library/compiler-builtins/tests/u128_addo.rs new file mode 100644 index 00000000000..caff682e8a0 --- /dev/null +++ b/library/compiler-builtins/tests/u128_addo.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/u128_addo.rs")); diff --git a/library/compiler-builtins/tests/u128_sub.rs b/library/compiler-builtins/tests/u128_sub.rs new file mode 100644 index 00000000000..024266b9263 --- /dev/null +++ b/library/compiler-builtins/tests/u128_sub.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/u128_sub.rs")); diff --git a/library/compiler-builtins/tests/u128_subo.rs b/library/compiler-builtins/tests/u128_subo.rs new file mode 100644 index 00000000000..b3fb4b854e2 --- /dev/null +++ b/library/compiler-builtins/tests/u128_subo.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/u128_subo.rs")); -- cgit 1.4.1-3-g733a5 From f468c28f74321ca970d58d75ad7d481b7651f667 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 25 Nov 2017 07:00:26 -0800 Subject: Another attempt at making MIPS happy (I really don't understand how arithmetic makes it segfault...) --- library/compiler-builtins/build.rs | 28 +++---- library/compiler-builtins/src/int/add.rs | 67 --------------- library/compiler-builtins/src/int/addsub.rs | 122 ++++++++++++++++++++++++++++ library/compiler-builtins/src/int/mod.rs | 3 +- library/compiler-builtins/src/int/sub.rs | 52 ------------ 5 files changed, 136 insertions(+), 136 deletions(-) delete mode 100644 library/compiler-builtins/src/int/add.rs create mode 100644 library/compiler-builtins/src/int/addsub.rs delete mode 100644 library/compiler-builtins/src/int/sub.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d7f6c01becf..753978d234c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -129,11 +129,15 @@ mod tests { Divsf3, Divdf3, - // int/add.rs + // int/addsub.rs AddU128, AddI128, AddoU128, AddoI128, + SubU128, + SubI128, + SuboU128, + SuboI128, // int/mul.rs Muldi3, @@ -160,12 +164,6 @@ mod tests { Lshrdi3, Lshrti3, - // int/sub.rs - SubU128, - SubI128, - SuboU128, - SuboI128, - // int/udiv.rs Udivdi3, Udivmoddi4, @@ -390,7 +388,7 @@ fn addsf3() { fn prologue() -> &'static str { " -use compiler_builtins::int::add::rust_u128_add; +use compiler_builtins::int::addsub::rust_u128_add; static TEST_CASES: &[((u128, u128), u128)] = &[ " @@ -448,7 +446,7 @@ fn u128_add() { fn prologue() -> &'static str { " -use compiler_builtins::int::add::rust_i128_add; +use compiler_builtins::int::addsub::rust_i128_add; static TEST_CASES: &[((i128, i128), i128)] = &[ " @@ -508,7 +506,7 @@ fn i128_add() { fn prologue() -> &'static str { " -use compiler_builtins::int::add::rust_u128_addo; +use compiler_builtins::int::addsub::rust_u128_addo; static TEST_CASES: &[((u128, u128), (u128, bool))] = &[ " @@ -568,7 +566,7 @@ fn u128_addo() { fn prologue() -> &'static str { " -use compiler_builtins::int::add::rust_i128_addo; +use compiler_builtins::int::addsub::rust_i128_addo; static TEST_CASES: &[((i128, i128), (i128, bool))] = &[ " @@ -3514,7 +3512,7 @@ fn subsf3() { fn prologue() -> &'static str { " -use compiler_builtins::int::sub::rust_u128_sub; +use compiler_builtins::int::addsub::rust_u128_sub; static TEST_CASES: &[((u128, u128), u128)] = &[ " @@ -3572,7 +3570,7 @@ fn u128_sub() { fn prologue() -> &'static str { " -use compiler_builtins::int::sub::rust_i128_sub; +use compiler_builtins::int::addsub::rust_i128_sub; static TEST_CASES: &[((i128, i128), i128)] = &[ " @@ -3632,7 +3630,7 @@ fn i128_sub() { fn prologue() -> &'static str { " -use compiler_builtins::int::sub::rust_u128_subo; +use compiler_builtins::int::addsub::rust_u128_subo; static TEST_CASES: &[((u128, u128), (u128, bool))] = &[ " @@ -3692,7 +3690,7 @@ fn u128_subo() { fn prologue() -> &'static str { " -use compiler_builtins::int::sub::rust_i128_subo; +use compiler_builtins::int::addsub::rust_i128_subo; static TEST_CASES: &[((i128, i128), (i128, bool))] = &[ " diff --git a/library/compiler-builtins/src/int/add.rs b/library/compiler-builtins/src/int/add.rs deleted file mode 100644 index 5c746c233dd..00000000000 --- a/library/compiler-builtins/src/int/add.rs +++ /dev/null @@ -1,67 +0,0 @@ -use int::LargeInt; -use int::Int; - -trait UAdd: LargeInt { - fn uadd(self, other: Self) -> Self { - let (low, carry) = self.low().overflowing_add(other.low()); - let high = self.high().wrapping_add(other.high()); - let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; - Self::from_parts(low, high.wrapping_add(carry)) - } -} - -impl UAdd for u128 {} - -trait Add: Int - where ::UnsignedInt: UAdd -{ - fn add(self, other: Self) -> Self { - Self::from_unsigned(self.unsigned().uadd(other.unsigned())) - } -} - -impl Add for u128 {} -impl Add for i128 {} - -trait Addo: Add - where ::UnsignedInt: UAdd -{ - fn addo(self, other: Self, overflow: &mut i32) -> Self { - *overflow = 0; - let result = Add::add(self, other); - if other >= Self::ZERO { - if result < self { - *overflow = 1; - } - } else { - if result >= self { - *overflow = 1; - } - } - result - } -} - -impl Addo for i128 {} -impl Addo for u128 {} - -#[cfg_attr(not(stage0), lang = "i128_add")] -pub fn rust_i128_add(a: i128, b: i128) -> i128 { - rust_u128_add(a as _, b as _) as _ -} -#[cfg_attr(not(stage0), lang = "i128_addo")] -pub fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = a.addo(b, &mut oflow); - (r, oflow != 0) -} -#[cfg_attr(not(stage0), lang = "u128_add")] -pub fn rust_u128_add(a: u128, b: u128) -> u128 { - a.add(b) -} -#[cfg_attr(not(stage0), lang = "u128_addo")] -pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.addo(b, &mut oflow); - (r, oflow != 0) -} diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs new file mode 100644 index 00000000000..7564d896df2 --- /dev/null +++ b/library/compiler-builtins/src/int/addsub.rs @@ -0,0 +1,122 @@ +use int::LargeInt; +use int::Int; + +trait UAddSub: LargeInt { + fn uadd(self, other: Self) -> Self { + let (low, carry) = self.low().overflowing_add(other.low()); + let high = self.high().wrapping_add(other.high()); + let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; + Self::from_parts(low, high.wrapping_add(carry)) + } + fn uadd_one(self) -> Self { + let (low, carry) = self.low().overflowing_add(Self::LowHalf::ONE); + let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; + Self::from_parts(low, self.high().wrapping_add(carry)) + } + fn usub(self, other: Self) -> Self { + let uneg = (!other).uadd_one(); + self.uadd(uneg) + } +} + +impl UAddSub for u128 {} + +trait AddSub: Int + where ::UnsignedInt: UAddSub +{ + fn add(self, other: Self) -> Self { + Self::from_unsigned(self.unsigned().uadd(other.unsigned())) + } + fn sub(self, other: Self) -> Self { + Self::from_unsigned(self.unsigned().usub(other.unsigned())) + } +} + +impl AddSub for u128 {} +impl AddSub for i128 {} + +trait Addo: AddSub + where ::UnsignedInt: UAddSub +{ + fn addo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = AddSub::add(self, other); + if other >= Self::ZERO { + if result < self { + *overflow = 1; + } + } else { + if result >= self { + *overflow = 1; + } + } + result + } +} + +impl Addo for i128 {} +impl Addo for u128 {} + +trait Subo: AddSub + where ::UnsignedInt: UAddSub +{ + fn subo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = AddSub::sub(self, other); + if other >= Self::ZERO { + if result > self { + *overflow = 1; + } + } else { + if result <= self { + *overflow = 1; + } + } + result + } +} + +impl Subo for i128 {} +impl Subo for u128 {} + +#[cfg_attr(not(stage0), lang = "i128_add")] +pub fn rust_i128_add(a: i128, b: i128) -> i128 { + rust_u128_add(a as _, b as _) as _ +} +#[cfg_attr(not(stage0), lang = "i128_addo")] +pub fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = a.addo(b, &mut oflow); + (r, oflow != 0) +} +#[cfg_attr(not(stage0), lang = "u128_add")] +pub fn rust_u128_add(a: u128, b: u128) -> u128 { + a.add(b) +} +#[cfg_attr(not(stage0), lang = "u128_addo")] +pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.addo(b, &mut oflow); + (r, oflow != 0) +} + +#[cfg_attr(not(stage0), lang = "i128_sub")] +pub fn rust_i128_sub(a: i128, b: i128) -> i128 { + rust_u128_sub(a as _, b as _) as _ +} +#[cfg_attr(not(stage0), lang = "i128_subo")] +pub fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = a.subo(b, &mut oflow); + (r, oflow != 0) +} +#[cfg_attr(not(stage0), lang = "u128_sub")] +pub fn rust_u128_sub(a: u128, b: u128) -> u128 { + a.sub(b) +} +#[cfg_attr(not(stage0), lang = "u128_subo")] +pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.subo(b, &mut oflow); + (r, oflow != 0) +} diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index c5490cba796..b645b214540 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -12,11 +12,10 @@ macro_rules! os_ty { } } -pub mod add; +pub mod addsub; pub mod mul; pub mod sdiv; pub mod shift; -pub mod sub; pub mod udiv; /// Trait for some basic operations on integers diff --git a/library/compiler-builtins/src/int/sub.rs b/library/compiler-builtins/src/int/sub.rs deleted file mode 100644 index abcb45a80ee..00000000000 --- a/library/compiler-builtins/src/int/sub.rs +++ /dev/null @@ -1,52 +0,0 @@ -use int::LargeInt; - -trait Sub: LargeInt { - fn sub(self, other: Self) -> Self { - let neg_other = (!other).wrapping_add(Self::ONE); - self.wrapping_add(neg_other) - } -} - -impl Sub for i128 {} -impl Sub for u128 {} - -trait Subo: Sub { - fn subo(self, other: Self, overflow: &mut i32) -> Self { - *overflow = 0; - let result = Sub::sub(self, other); - if other >= Self::ZERO { - if result > self { - *overflow = 1; - } - } else { - if result <= self { - *overflow = 1; - } - } - result - } -} - -impl Subo for i128 {} -impl Subo for u128 {} - -#[cfg_attr(not(stage0), lang = "i128_sub")] -pub fn rust_i128_sub(a: i128, b: i128) -> i128 { - rust_u128_sub(a as _, b as _) as _ -} -#[cfg_attr(not(stage0), lang = "i128_subo")] -pub fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = a.subo(b, &mut oflow); - (r, oflow != 0) -} -#[cfg_attr(not(stage0), lang = "u128_sub")] -pub fn rust_u128_sub(a: u128, b: u128) -> u128 { - a.sub(b) -} -#[cfg_attr(not(stage0), lang = "u128_subo")] -pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.subo(b, &mut oflow); - (r, oflow != 0) -} -- cgit 1.4.1-3-g733a5 From dd0be676655a3df8654fb94361a568110e52f048 Mon Sep 17 00:00:00 2001 From: Jan Teske Date: Sun, 26 Nov 2017 21:53:57 +0100 Subject: Remove mulsf3.c and muldf3.c from compiler-rt. mulsf3 and muldf3 have Rust implementations since 8970485. Remove the C implementations to avoid conflicts. --- library/compiler-builtins/build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 753978d234c..4f8db808c1a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4987,9 +4987,7 @@ mod c { "floatundisf.c", "int_util.c", "muldc3.c", - "muldf3.c", "mulsc3.c", - "mulsf3.c", "mulvdi3.c", "mulvsi3.c", "mulxc3.c", -- cgit 1.4.1-3-g733a5 From fe9bd52cc15f4ea8414d39bd6583bceb3ec0908c Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 27 Nov 2017 16:13:22 -0500 Subject: Avoid warning spew ...when the compiler doesn't support '-fomit-frame-pointer' on the target architecture. --- library/compiler-builtins/build.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e2a63a6cf97..5a721261756 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4453,8 +4453,16 @@ mod c { // compiler-rt's build system already cfg.flag("-fno-builtin"); cfg.flag("-fvisibility=hidden"); - cfg.flag("-fomit-frame-pointer"); cfg.flag("-ffreestanding"); + // Avoid the following warning appearing once **per file**: + // clang: warning: optimization flag '-fomit-frame-pointer' is not supported for target 'armv7' [-Wignored-optimization-argument] + // + // Note that compiler-rt's build system also checks + // + // `check_cxx_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG)` + // + // in https://github.com/rust-lang/compiler-rt/blob/c8fbcb3/cmake/config-ix.cmake#L19. + cfg.flag_if_supported("-fomit-frame-pointer"); cfg.define("VISIBILITY_HIDDEN", None); } -- cgit 1.4.1-3-g733a5 From 19a725d772e24a69590513d5f4f3aa93db47ba06 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 8 Dec 2017 08:19:28 -0800 Subject: Fix nightly CI Currently we're getting lots of errors about duplicate lang items so deal with this by `#[cfg_attr]`'ing off the lang item attribute in tests. --- library/compiler-builtins/src/int/addsub.rs | 80 +++++++++++++++-------------- library/compiler-builtins/src/int/mul.rs | 40 ++++++++------- library/compiler-builtins/src/int/sdiv.rs | 16 +++--- library/compiler-builtins/src/int/shift.rs | 64 ++++++++++++----------- library/compiler-builtins/src/int/udiv.rs | 16 +++--- library/compiler-builtins/src/macros.rs | 14 +++++ 6 files changed, 127 insertions(+), 103 deletions(-) diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs index 7564d896df2..50b5d10d259 100644 --- a/library/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/src/int/addsub.rs @@ -79,44 +79,46 @@ trait Subo: AddSub impl Subo for i128 {} impl Subo for u128 {} -#[cfg_attr(not(stage0), lang = "i128_add")] -pub fn rust_i128_add(a: i128, b: i128) -> i128 { - rust_u128_add(a as _, b as _) as _ -} -#[cfg_attr(not(stage0), lang = "i128_addo")] -pub fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = a.addo(b, &mut oflow); - (r, oflow != 0) -} -#[cfg_attr(not(stage0), lang = "u128_add")] -pub fn rust_u128_add(a: u128, b: u128) -> u128 { - a.add(b) -} -#[cfg_attr(not(stage0), lang = "u128_addo")] -pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.addo(b, &mut oflow); - (r, oflow != 0) -} +u128_lang_items! { + #[lang = "i128_add"] + pub fn rust_i128_add(a: i128, b: i128) -> i128 { + rust_u128_add(a as _, b as _) as _ + } + #[lang = "i128_addo"] + pub fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = a.addo(b, &mut oflow); + (r, oflow != 0) + } + #[lang = "u128_add"] + pub fn rust_u128_add(a: u128, b: u128) -> u128 { + a.add(b) + } + #[lang = "u128_addo"] + pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.addo(b, &mut oflow); + (r, oflow != 0) + } -#[cfg_attr(not(stage0), lang = "i128_sub")] -pub fn rust_i128_sub(a: i128, b: i128) -> i128 { - rust_u128_sub(a as _, b as _) as _ -} -#[cfg_attr(not(stage0), lang = "i128_subo")] -pub fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = a.subo(b, &mut oflow); - (r, oflow != 0) -} -#[cfg_attr(not(stage0), lang = "u128_sub")] -pub fn rust_u128_sub(a: u128, b: u128) -> u128 { - a.sub(b) -} -#[cfg_attr(not(stage0), lang = "u128_subo")] -pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.subo(b, &mut oflow); - (r, oflow != 0) + #[lang = "i128_sub"] + pub fn rust_i128_sub(a: i128, b: i128) -> i128 { + rust_u128_sub(a as _, b as _) as _ + } + #[lang = "i128_subo"] + pub fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = a.subo(b, &mut oflow); + (r, oflow != 0) + } + #[lang = "u128_sub"] + pub fn rust_u128_sub(a: u128, b: u128) -> u128 { + a.sub(b) + } + #[lang = "u128_subo"] + pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.subo(b, &mut oflow); + (r, oflow != 0) + } } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 61c379c7b68..58ca461b085 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -108,23 +108,25 @@ intrinsics! { } } -#[cfg_attr(not(stage0), lang = "i128_mul")] -pub fn rust_i128_mul(a: i128, b: i128) -> i128 { - __multi3(a, b) -} -#[cfg_attr(not(stage0), lang = "i128_mulo")] -pub fn rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = __muloti4(a, b, &mut oflow); - (r, oflow != 0) -} -#[cfg_attr(not(stage0), lang = "u128_mul")] -pub fn rust_u128_mul(a: u128, b: u128) -> u128 { - __multi3(a as _, b as _) as _ -} -#[cfg_attr(not(stage0), lang = "u128_mulo")] -pub fn rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.mulo(b, &mut oflow); - (r, oflow != 0) +u128_lang_items! { + #[lang = "i128_mul"] + pub fn rust_i128_mul(a: i128, b: i128) -> i128 { + __multi3(a, b) + } + #[lang = "i128_mulo"] + pub fn rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = __muloti4(a, b, &mut oflow); + (r, oflow != 0) + } + #[lang = "u128_mul"] + pub fn rust_u128_mul(a: u128, b: u128) -> u128 { + __multi3(a as _, b as _) as _ + } + #[lang = "u128_mulo"] + pub fn rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.mulo(b, &mut oflow); + (r, oflow != 0) + } } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 03086646695..2f09bd51d91 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -98,11 +98,13 @@ intrinsics! { } } -#[cfg_attr(not(stage0), lang = "i128_div")] -pub fn rust_i128_div(a: i128, b: i128) -> i128 { - __divti3(a, b) -} -#[cfg_attr(not(stage0), lang = "i128_rem")] -pub fn rust_i128_rem(a: i128, b: i128) -> i128 { - __modti3(a, b) +u128_lang_items! { + #[lang = "i128_div"] + pub fn rust_i128_div(a: i128, b: i128) -> i128 { + __divti3(a, b) + } + #[lang = "i128_rem"] + pub fn rust_i128_rem(a: i128, b: i128) -> i128 { + __modti3(a, b) + } } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index f8faad829a9..959fcb0880f 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -96,36 +96,38 @@ intrinsics! { } } -#[cfg_attr(not(stage0), lang = "i128_shl")] -pub fn rust_i128_shl(a: i128, b: u32) -> i128 { - __ashlti3(a as _, b) as _ -} -#[cfg_attr(not(stage0), lang = "i128_shlo")] -pub fn rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { - (rust_i128_shl(a, b as _), b >= 128) -} -#[cfg_attr(not(stage0), lang = "u128_shl")] -pub fn rust_u128_shl(a: u128, b: u32) -> u128 { - __ashlti3(a, b) -} -#[cfg_attr(not(stage0), lang = "u128_shlo")] -pub fn rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { - (rust_u128_shl(a, b as _), b >= 128) -} +u128_lang_items! { + #[lang = "i128_shl"] + pub fn rust_i128_shl(a: i128, b: u32) -> i128 { + __ashlti3(a as _, b) as _ + } + #[lang = "i128_shlo"] + pub fn rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { + (rust_i128_shl(a, b as _), b >= 128) + } + #[lang = "u128_shl"] + pub fn rust_u128_shl(a: u128, b: u32) -> u128 { + __ashlti3(a, b) + } + #[lang = "u128_shlo"] + pub fn rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { + (rust_u128_shl(a, b as _), b >= 128) + } -#[cfg_attr(not(stage0), lang = "i128_shr")] -pub fn rust_i128_shr(a: i128, b: u32) -> i128 { - __ashrti3(a, b) -} -#[cfg_attr(not(stage0), lang = "i128_shro")] -pub fn rust_i128_shro(a: i128, b: u128) -> (i128, bool) { - (rust_i128_shr(a, b as _), b >= 128) -} -#[cfg_attr(not(stage0), lang = "u128_shr")] -pub fn rust_u128_shr(a: u128, b: u32) -> u128 { - __lshrti3(a, b) -} -#[cfg_attr(not(stage0), lang = "u128_shro")] -pub fn rust_u128_shro(a: u128, b: u128) -> (u128, bool) { - (rust_u128_shr(a, b as _), b >= 128) + #[lang = "i128_shr"] + pub fn rust_i128_shr(a: i128, b: u32) -> i128 { + __ashrti3(a, b) + } + #[lang = "i128_shro"] + pub fn rust_i128_shro(a: i128, b: u128) -> (i128, bool) { + (rust_i128_shr(a, b as _), b >= 128) + } + #[lang = "u128_shr"] + pub fn rust_u128_shr(a: u128, b: u32) -> u128 { + __lshrti3(a, b) + } + #[lang = "u128_shro"] + pub fn rust_u128_shro(a: u128, b: u128) -> (u128, bool) { + (rust_u128_shr(a, b as _), b >= 128) + } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 6c100f3f86d..1d93e177b5b 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -270,11 +270,13 @@ intrinsics! { } } -#[cfg_attr(not(stage0), lang = "u128_div")] -pub fn rust_u128_div(a: u128, b: u128) -> u128 { - __udivti3(a, b) -} -#[cfg_attr(not(stage0), lang = "u128_rem")] -pub fn rust_u128_rem(a: u128, b: u128) -> u128 { - __umodti3(a, b) +u128_lang_items! { + #[lang = "u128_div"] + pub fn rust_u128_div(a: u128, b: u128) -> u128 { + __udivti3(a, b) + } + #[lang = "u128_rem"] + pub fn rust_u128_rem(a: u128, b: u128) -> u128 { + __umodti3(a, b) + } } diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 652c9111de6..033f14121a8 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -280,3 +280,17 @@ pub mod win64_128bit_abi_hack { } } } + +macro_rules! u128_lang_items { + ($( + #[lang = $lang:tt] + pub fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + )*) => ($( + #[cfg_attr(not(any(stage0, feature = "gen-tests")), lang = $lang)] + pub fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + )*) +} -- cgit 1.4.1-3-g733a5 From dd2e94ae5bfc178e2379d80afc0fd24cd4254f5e Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 20 Dec 2017 01:44:48 +0000 Subject: Replace inline asm with function calls in __kuser_cmpxchg and __kuser_memory_barrier --- library/compiler-builtins/src/arm_linux.rs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs index d94996d7399..a48a9698f37 100644 --- a/library/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/src/arm_linux.rs @@ -4,23 +4,12 @@ use core::mem; // Kernel-provided user-mode helper functions: // https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt unsafe fn __kuser_cmpxchg(oldval: u32, newval: u32, ptr: *mut u32) -> bool { - let out: u32; - // FIXME: we can't use BLX on ARMv4 - asm!("blx ${0}" - : "={r0}" (out) - : "r" (0xffff0fc0u32) - "{r0}" (oldval), - "{r1}" (newval), - "{r2}" (ptr) - : "r3", "r12", "lr", "cc", "memory"); - out == 0 + let f: extern "C" fn (u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0u32); + f(oldval, newval, ptr) == 0 } unsafe fn __kuser_memory_barrier() { - // FIXME: we can't use BLX on ARMv4 - asm!("blx ${0}" - : - : "r" (0xffff0fa0u32) - : "lr", "memory"); + let f: extern "C" fn () = mem::transmute(0xffff0fa0u32); + f(); } // Word-align a pointer -- cgit 1.4.1-3-g733a5 From af91189aa7e0631e1d86bbbb15b2f32cc66d9618 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 23 Dec 2017 08:45:25 +0100 Subject: Fix argument order for __sync_val_compare_and_swap --- library/compiler-builtins/src/arm_linux.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs index a48a9698f37..2291edf9f14 100644 --- a/library/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/src/arm_linux.rs @@ -71,7 +71,7 @@ unsafe fn atomic_rmw u32>(ptr: *mut T, f: F) -> u32 { } // Generic atomic compare-exchange operation -unsafe fn atomic_cmpxchg(oldval: u32, newval: u32, ptr: *mut T) -> u32 { +unsafe fn atomic_cmpxchg(ptr: *mut T, oldval: u32, newval: u32) -> u32 { let aligned_ptr = align_ptr(ptr); let (shift, mask) = get_shift_mask(ptr); @@ -99,8 +99,8 @@ macro_rules! atomic_rmw { macro_rules! atomic_cmpxchg { ($name:ident, $ty:ty) => { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - pub unsafe extern "C" fn $name(oldval: $ty, newval: $ty, ptr: *mut $ty) -> $ty { - atomic_cmpxchg(oldval as u32, newval as u32, ptr) as $ty + pub unsafe extern "C" fn $name(ptr: *mut $ty, oldval: $ty, newval: $ty) -> $ty { + atomic_cmpxchg(ptr, oldval as u32, newval as u32) as $ty } } } -- cgit 1.4.1-3-g733a5 From 90bd768b2013b095beacc3e813fa0f7d0d43f05c Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Tue, 26 Dec 2017 13:01:02 -0200 Subject: Use kernel user helpers for armv4t Rename armv5te cfg to kernel_user_helpers and enable it for armv4t --- library/compiler-builtins/build.rs | 4 ++-- library/compiler-builtins/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 9c23c20c965..996a7c04b05 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -52,8 +52,8 @@ fn main() { } // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. - if llvm_target[0] == "armv5te" { - println!("cargo:rustc-cfg=armv5te") + if llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" { + println!("cargo:rustc-cfg=kernel_user_helpers") } } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index ff7885bb3f6..f815a9cf393 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -52,7 +52,7 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; -#[cfg(all(armv5te, target_os = "linux", target_arch = "arm"))] +#[cfg(all(kernel_user_helpers, target_os = "linux", target_arch = "arm"))] pub mod arm_linux; #[cfg(target_arch = "x86")] -- cgit 1.4.1-3-g733a5 From 4481a6c4ab4019762eaafbfe549ab3d395e66b35 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 26 Dec 2017 10:14:11 -0800 Subject: Disable incremental + LTO This causes errors in more recent versions of rustc --- library/compiler-builtins/ci/run.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 95dcdfda959..0bc12816ac9 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -115,6 +115,7 @@ RUSTFLAGS="-C debug-assertions=no" \ # TODO(#79) fix the undefined references problem for debug-assertions+lto if [ -z "$DEBUG_LTO_BUILD_DOESNT_WORK" ]; then RUSTFLAGS="-C debug-assertions=no" \ + CARGO_INCREMENTAL=0 \ $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics -- -C lto fi $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics --release -- -C lto -- cgit 1.4.1-3-g733a5 From dbaa47027e6bb67f57ba4fe40400e39ffadfa097 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 26 Dec 2017 12:20:17 -0800 Subject: Work around japaric/xargo#186 temporarily --- library/compiler-builtins/ci/run.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 0bc12816ac9..50413cf9f62 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,5 +1,8 @@ set -ex +# FIXME(japarix/xargo#186) this shouldn't be necessary +export RUST_TARGET_PATH=`pwd` + case $1 in thumb*) cargo=xargo -- cgit 1.4.1-3-g733a5 From c329f6ef75005926f862333bdb0c185768810501 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 02:57:42 +0000 Subject: comparesf2/comparedf2 are called on soft-float targets. E.g. take a look at the assembly output for: pub fn comparesf2(a: f32, b: f32) -> bool { a > b } pub fn comparedf2(a: f64, b: f64) -> bool { a > b } which will include calls to __gtsf2 and __gtdf2. --- library/compiler-builtins/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 5606ef4c846..533850bb700 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -133,6 +133,8 @@ features = ["c"] - [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c +- [ ] comparedf2.c +- [ ] comparesf2.c - [x] divdf3.c - [x] divdi3.c - [x] divmoddi4.c @@ -301,8 +303,6 @@ These builtins are never called by LLVM. - ~~clzti2.c~~ - ~~cmpdi2.c~~ - ~~cmpti2.c~~ -- ~~comparedf2.c~~ -- ~~comparesf2.c~~ - ~~ctzdi2.c~~ - ~~ctzsi2.c~~ - ~~ctzti2.c~~ -- cgit 1.4.1-3-g733a5 From 24175dd6cae41821aac6f3c6a2fbe32a4bba160a Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 03:41:14 +0000 Subject: Implement comparesf2/comparedf2 intrinsics. --- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/src/float/cmp.rs | 166 +++++++++++++++++++++++++++++ library/compiler-builtins/src/float/mod.rs | 1 + 3 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/src/float/cmp.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 533850bb700..6123fe40b7c 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -133,8 +133,8 @@ features = ["c"] - [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c -- [ ] comparedf2.c -- [ ] comparesf2.c +- [x] comparedf2.c +- [x] comparesf2.c - [x] divdf3.c - [x] divdi3.c - [x] divmoddi4.c diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs new file mode 100644 index 00000000000..f10860c3b82 --- /dev/null +++ b/library/compiler-builtins/src/float/cmp.rs @@ -0,0 +1,166 @@ +use int::{Int, CastInto}; +use float::Float; + +#[derive(Clone, Copy)] +enum Result { + Less, + Equal, + Greater, + Unordered +} + +impl Result { + fn to_le_abi(self) -> i32 { + match self { + Result::Less => -1, + Result::Equal => 0, + Result::Greater => 1, + Result::Unordered => 1 + } + } + + fn to_ge_abi(self) -> i32 { + match self { + Result::Less => -1, + Result::Equal => 0, + Result::Greater => 1, + Result::Unordered => -1 + } + } +} + +fn cmp(a: F, b: F) -> Result where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, +{ + let one = F::Int::ONE; + let zero = F::Int::ZERO; + + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXPONENT_MASK; + let inf_rep = exponent_mask; + + let a_rep = a.repr(); + let b_rep = b.repr(); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // If either a or b is NaN, they are unordered. + if a_abs > inf_rep || b_abs > inf_rep { + return Result::Unordered + } + + // If a and b are both zeros, they are equal. + if a_abs | b_abs == zero { + return Result::Equal + } + + // If at least one of a and b is positive, we get the same result comparing + // a and b as signed integers as we would with a fp_ting-point compare. + if a_rep & b_rep >= zero { + if a_rep < b_rep { + return Result::Less + } else if a_rep == b_rep { + return Result::Equal + } else { + return Result::Greater + } + } + + // Otherwise, both are negative, so we need to flip the sense of the + // comparison to get the correct result. (This assumes a twos- or ones- + // complement integer representation; if integers are represented in a + // sign-magnitude representation, then this flip is incorrect). + else { + if a_rep > b_rep { + return Result::Less + } else if a_rep == b_rep { + return Result::Equal + } else { + return Result::Greater + } + } +} +fn unord(a: F, b: F) -> bool where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, +{ + let one = F::Int::ONE; + + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXPONENT_MASK; + let inf_rep = exponent_mask; + + let a_rep = a.repr(); + let b_rep = b.repr(); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + a_abs > inf_rep || b_abs > inf_rep +} + +intrinsics! { + pub extern "C" fn __lesf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_le_abi() + } + + pub extern "C" fn __gesf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_ge_abi() + } + + #[arm_aeabi_alias = fcmpun] + pub extern "C" fn __unordsf2(a: f32, b: f32) -> bool { + unord(a, b) + } + + pub extern "C" fn __eqsf2(a: f32, b: f32) -> bool { + cmp(a, b).to_le_abi() != 0 + } + + pub extern "C" fn __ltsf2(a: f32, b: f32) -> bool { + cmp(a, b).to_le_abi() != 0 + } + + pub extern "C" fn __nesf2(a: f32, b: f32) -> bool { + cmp(a, b).to_le_abi() != 0 + } + + pub extern "C" fn __gtsf2(a: f32, b: f32) -> bool { + cmp(a, b).to_ge_abi() != 0 + } + + pub extern "C" fn __ledf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_le_abi() + } + + pub extern "C" fn __gedf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_ge_abi() + } + + #[arm_aeabi_alias = dcmpun] + pub extern "C" fn __unorddf2(a: f64, b: f64) -> bool { + unord(a, b) + } + + pub extern "C" fn __eqdf2(a: f64, b: f64) -> bool { + cmp(a, b).to_le_abi() != 0 + } + + pub extern "C" fn __ltdf2(a: f64, b: f64) -> bool { + cmp(a, b).to_le_abi() != 0 + } + + pub extern "C" fn __nedf2(a: f64, b: f64) -> bool { + cmp(a, b).to_le_abi() != 0 + } + + pub extern "C" fn __gtdf2(a: f32, b: f32) -> bool { + cmp(a, b).to_ge_abi() != 0 + } +} diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 6daf7b8f75f..f13256da4b4 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -4,6 +4,7 @@ use core::ops; use super::int::Int; pub mod conv; +pub mod cmp; pub mod add; pub mod pow; pub mod sub; -- cgit 1.4.1-3-g733a5 From fee371a365e98279d6008e83b838f0ebff7ac75e Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 29 Dec 2017 06:14:51 +0000 Subject: comparesf2/comparedf2: use i32 instead of bool for return type. Note that this changes semantics: pub extern "C" fn __eqsf2(a: f32, b: f32) -> bool { cmp(a, b).to_le_abi() != 0 } is not the same as pub extern "C" fn __eqsf2(a: f32, b: f32) -> i32 { cmp(a, b).to_le_abi() } However, compiler-rt does the latter, so this is actually an improvement. --- library/compiler-builtins/src/float/cmp.rs | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index f10860c3b82..2434deb895c 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -115,24 +115,24 @@ intrinsics! { } #[arm_aeabi_alias = fcmpun] - pub extern "C" fn __unordsf2(a: f32, b: f32) -> bool { - unord(a, b) + pub extern "C" fn __unordsf2(a: f32, b: f32) -> i32 { + unord(a, b) as i32 } - pub extern "C" fn __eqsf2(a: f32, b: f32) -> bool { - cmp(a, b).to_le_abi() != 0 + pub extern "C" fn __eqsf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_le_abi() } - pub extern "C" fn __ltsf2(a: f32, b: f32) -> bool { - cmp(a, b).to_le_abi() != 0 + pub extern "C" fn __ltsf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_le_abi() } - pub extern "C" fn __nesf2(a: f32, b: f32) -> bool { - cmp(a, b).to_le_abi() != 0 + pub extern "C" fn __nesf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_le_abi() } - pub extern "C" fn __gtsf2(a: f32, b: f32) -> bool { - cmp(a, b).to_ge_abi() != 0 + pub extern "C" fn __gtsf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_ge_abi() } pub extern "C" fn __ledf2(a: f64, b: f64) -> i32 { @@ -144,23 +144,23 @@ intrinsics! { } #[arm_aeabi_alias = dcmpun] - pub extern "C" fn __unorddf2(a: f64, b: f64) -> bool { - unord(a, b) + pub extern "C" fn __unorddf2(a: f64, b: f64) -> i32 { + unord(a, b) as i32 } - pub extern "C" fn __eqdf2(a: f64, b: f64) -> bool { - cmp(a, b).to_le_abi() != 0 + pub extern "C" fn __eqdf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_le_abi() } - pub extern "C" fn __ltdf2(a: f64, b: f64) -> bool { - cmp(a, b).to_le_abi() != 0 + pub extern "C" fn __ltdf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_le_abi() } - pub extern "C" fn __nedf2(a: f64, b: f64) -> bool { - cmp(a, b).to_le_abi() != 0 + pub extern "C" fn __nedf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_le_abi() } - pub extern "C" fn __gtdf2(a: f32, b: f32) -> bool { - cmp(a, b).to_ge_abi() != 0 + pub extern "C" fn __gtdf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_ge_abi() } } -- cgit 1.4.1-3-g733a5 From a0777758df7bd63040d9f8f4937368c69fd24760 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 29 Dec 2017 06:16:35 +0000 Subject: comparesf2/comparedf2: do not build the C versions of intrinsics. --- library/compiler-builtins/build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 996a7c04b05..a71139208f7 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4982,8 +4982,6 @@ mod c { "clzdi2.c", "clzsi2.c", "cmpdi2.c", - "comparedf2.c", - "comparesf2.c", "ctzdi2.c", "ctzsi2.c", "divdc3.c", -- cgit 1.4.1-3-g733a5 From 45112fc65f00b0d12b4cd5e6c842a3b44caca089 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 29 Dec 2017 06:36:09 +0000 Subject: README: update to explain how to run quickcheck-style tests. --- library/compiler-builtins/README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 6123fe40b7c..a7dabe7b5a7 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -52,16 +52,20 @@ features = ["c"] ## Contributing 1. Pick one or more intrinsics from the [pending list](#progress). -2. Fork this repository -3. Port the intrinsic(s) and their corresponding [unit tests][1] from their [C implementation][2] to - Rust. -4. Send a Pull Request (PR) -5. Once the PR passes our extensive [testing infrastructure][3], we'll merge it! +2. Fork this repository. +3. Port the intrinsic(s) and their corresponding [unit tests][1] from their + [C implementation][2] to Rust. +4. Implement a [test generator][3] to compare the behavior of the ported intrinsic(s) + with their implementation on the testing host. Note that randomized compiler-builtin tests + should be run using `cargo test --features gen-tests`. +4. Send a Pull Request (PR). +5. Once the PR passes our extensive [testing infrastructure][4], we'll merge it! 6. Celebrate :tada: [1]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/test/builtins/Unit [2]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/lib/builtins -[3]: https://travis-ci.org/rust-lang-nursery/compiler-builtins +[3]: https://github.com/rust-lang-nursery/compiler-builtins/blob/0ba07e49264a54cb5bbd4856fcea083bb3fbec15/build.rs#L180-L265 +[4]: https://travis-ci.org/rust-lang-nursery/compiler-builtins ### Porting Reminders -- cgit 1.4.1-3-g733a5 From 566e7ede907e6ca84a858aab9e8bce4c6d67d9a6 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 29 Dec 2017 07:49:45 +0000 Subject: comparesf2/comparedf2: fix a signedness bug and add tests. --- library/compiler-builtins/build.rs | 318 +++++++++++++++++++++++++++++ library/compiler-builtins/src/float/cmp.rs | 28 ++- library/compiler-builtins/src/float/mod.rs | 16 +- library/compiler-builtins/tests/gedf2.rs | 7 + library/compiler-builtins/tests/gesf2.rs | 7 + library/compiler-builtins/tests/ledf2.rs | 7 + library/compiler-builtins/tests/lesf2.rs | 7 + 7 files changed, 376 insertions(+), 14 deletions(-) create mode 100644 library/compiler-builtins/tests/gedf2.rs create mode 100644 library/compiler-builtins/tests/gesf2.rs create mode 100644 library/compiler-builtins/tests/ledf2.rs create mode 100644 library/compiler-builtins/tests/lesf2.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a71139208f7..0a12a757d61 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -89,6 +89,12 @@ mod tests { Adddf3, Addsf3, + // float/cmp.rs + Gedf2, + Gesf2, + Ledf2, + Lesf2, + // float/conv.rs Fixdfdi, Fixdfsi, @@ -2529,6 +2535,318 @@ fn floatuntidf() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Gedf2 { + a: u64, + b: u64, + c: i32, + } + + impl TestCase for Gedf2 { + fn name() -> &'static str { + "gedf2" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + let b = gen_f64(rng); + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() { + return None; + } + + let c; + if a.is_nan() || b.is_nan() { + c = -1; + } else if a < b { + c = -1; + } else if a > b { + c = 1; + } else { + c = 0; + } + + Some(Gedf2 { a: to_u64(a), b: to_u64(b), c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use std::mem; +use compiler_builtins::float::cmp::__gedf2; + +fn to_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), i32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn gedf2() { + for &((a, b), c) in TEST_CASES { + let c_ = __gedf2(to_f64(a), to_f64(b)); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Gesf2 { + a: u32, + b: u32, + c: i32, + } + + impl TestCase for Gesf2 { + fn name() -> &'static str { + "gesf2" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + let b = gen_f32(rng); + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() { + return None; + } + + let c; + if a.is_nan() || b.is_nan() { + c = -1; + } else if a < b { + c = -1; + } else if a > b { + c = 1; + } else { + c = 0; + } + + Some(Gesf2 { a: to_u32(a), b: to_u32(b), c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use std::mem; +use compiler_builtins::float::cmp::__gesf2; + +fn to_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), i32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn gesf2() { + for &((a, b), c) in TEST_CASES { + let c_ = __gesf2(to_f32(a), to_f32(b)); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Ledf2 { + a: u64, + b: u64, + c: i32, + } + + impl TestCase for Ledf2 { + fn name() -> &'static str { + "ledf2" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + let b = gen_f64(rng); + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() { + return None; + } + + let c; + if a.is_nan() || b.is_nan() { + c = 1; + } else if a < b { + c = -1; + } else if a > b { + c = 1; + } else { + c = 0; + } + + Some(Ledf2 { a: to_u64(a), b: to_u64(b), c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use std::mem; +use compiler_builtins::float::cmp::__ledf2; + +fn to_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), i32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn ledf2() { + for &((a, b), c) in TEST_CASES { + let c_ = __ledf2(to_f64(a), to_f64(b)); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Lesf2 { + a: u32, + b: u32, + c: i32, + } + + impl TestCase for Lesf2 { + fn name() -> &'static str { + "lesf2" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + let b = gen_f32(rng); + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() { + return None; + } + + let c; + if a.is_nan() || b.is_nan() { + c = 1; + } else if a < b { + c = -1; + } else if a > b { + c = 1; + } else { + c = 0; + } + + Some(Lesf2 { a: to_u32(a), b: to_u32(b), c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use std::mem; +use compiler_builtins::float::cmp::__lesf2; + +fn to_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), i32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn lesf2() { + for &((a, b), c) in TEST_CASES { + let c_ = __lesf2(to_f32(a), to_f32(b)); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Moddi3 { a: i64, diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 2434deb895c..e884872f1d4 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -1,3 +1,5 @@ +#![allow(unreachable_code)] + use int::{Int, CastInto}; use float::Float; @@ -35,18 +37,19 @@ fn cmp(a: F, b: F) -> Result where i32: CastInto, F::Int: CastInto, { - let one = F::Int::ONE; - let zero = F::Int::ZERO; + let one = F::Int::ONE; + let zero = F::Int::ZERO; + let szero = F::SignedInt::ZERO; let sign_bit = F::SIGN_MASK as F::Int; let abs_mask = sign_bit - one; let exponent_mask = F::EXPONENT_MASK; let inf_rep = exponent_mask; - let a_rep = a.repr(); - let b_rep = b.repr(); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; + let a_rep = a.repr(); + let b_rep = b.repr(); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; // If either a or b is NaN, they are unordered. if a_abs > inf_rep || b_abs > inf_rep { @@ -58,12 +61,15 @@ fn cmp(a: F, b: F) -> Result where return Result::Equal } + let a_srep = a.signed_repr(); + let b_srep = b.signed_repr(); + // If at least one of a and b is positive, we get the same result comparing // a and b as signed integers as we would with a fp_ting-point compare. - if a_rep & b_rep >= zero { - if a_rep < b_rep { + if a_srep & b_srep >= szero { + if a_srep < b_srep { return Result::Less - } else if a_rep == b_rep { + } else if a_srep == b_srep { return Result::Equal } else { return Result::Greater @@ -75,9 +81,9 @@ fn cmp(a: F, b: F) -> Result where // complement integer representation; if integers are represented in a // sign-magnitude representation, then this flip is incorrect). else { - if a_rep > b_rep { + if a_srep > b_srep { return Result::Less - } else if a_rep == b_rep { + } else if a_srep == b_srep { return Result::Equal } else { return Result::Greater diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index f13256da4b4..51ed6674d1d 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -26,6 +26,9 @@ pub trait Float: /// A uint of the same with as the float type Int: Int; + /// A int of the same with as the float + type SignedInt: Int; + const ZERO: Self; const ONE: Self; @@ -59,6 +62,9 @@ pub trait Float: /// Returns `self` transmuted to `Self::Int` fn repr(self) -> Self::Int; + /// Returns `self` transmuted to `Self::SignedInt` + fn signed_repr(self) -> Self::SignedInt; + #[cfg(test)] /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be /// represented in multiple different ways. This method returns `true` if two NaNs are @@ -78,9 +84,10 @@ pub trait Float: // FIXME: Some of this can be removed if RFC Issue #1424 is resolved // https://github.com/rust-lang/rfcs/issues/1424 macro_rules! float_impl { - ($ty:ident, $ity:ident, $bits:expr, $significand_bits:expr) => { + ($ty:ident, $ity:ident, $sity:ident, $bits:expr, $significand_bits:expr) => { impl Float for $ty { type Int = $ity; + type SignedInt = $sity; const ZERO: Self = 0.0; const ONE: Self = 1.0; @@ -95,6 +102,9 @@ macro_rules! float_impl { fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } + fn signed_repr(self) -> Self::SignedInt { + unsafe { mem::transmute(self) } + } #[cfg(test)] fn eq_repr(self, rhs: Self) -> bool { if self.is_nan() && rhs.is_nan() { @@ -120,5 +130,5 @@ macro_rules! float_impl { } } -float_impl!(f32, u32, 32, 23); -float_impl!(f64, u64, 64, 52); +float_impl!(f32, u32, i32, 32, 23); +float_impl!(f64, u64, i64, 64, 52); diff --git a/library/compiler-builtins/tests/gedf2.rs b/library/compiler-builtins/tests/gedf2.rs new file mode 100644 index 00000000000..e1bea595395 --- /dev/null +++ b/library/compiler-builtins/tests/gedf2.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/gedf2.rs")); diff --git a/library/compiler-builtins/tests/gesf2.rs b/library/compiler-builtins/tests/gesf2.rs new file mode 100644 index 00000000000..760f5a8f5ad --- /dev/null +++ b/library/compiler-builtins/tests/gesf2.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/gesf2.rs")); diff --git a/library/compiler-builtins/tests/ledf2.rs b/library/compiler-builtins/tests/ledf2.rs new file mode 100644 index 00000000000..3fac17b0f36 --- /dev/null +++ b/library/compiler-builtins/tests/ledf2.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/ledf2.rs")); diff --git a/library/compiler-builtins/tests/lesf2.rs b/library/compiler-builtins/tests/lesf2.rs new file mode 100644 index 00000000000..878861fec1c --- /dev/null +++ b/library/compiler-builtins/tests/lesf2.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/lesf2.rs")); -- cgit 1.4.1-3-g733a5 From 746c4717e15db62a09b5f405a2340ced24d4b862 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 29 Dec 2017 18:07:40 +0000 Subject: comparesf2: do not build the assembly versions of intrinsics on ARM. --- library/compiler-builtins/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0a12a757d61..cc3121eea45 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -5443,7 +5443,6 @@ mod c { "arm/bswapsi2.S", "arm/clzdi2.S", "arm/clzsi2.S", - "arm/comparesf2.S", "arm/divmodsi4.S", "arm/modsi3.S", "arm/switch16.S", -- cgit 1.4.1-3-g733a5 From 2754f64c1883d48d09bcc202f507f0cca7b2513f Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Fri, 19 Jan 2018 09:04:57 +0100 Subject: Skip aeabi_cdcmp and aeabi_cfcmp on big-endian targets First of all aeabi_cdcmp and aeabi_cfcmp are never called LLVM. Second are little-endian only, so build fail on big-endian targets. Temporally workaround: exclude these files for big-endian targets. --- library/compiler-builtins/build.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index cc3121eea45..0b27598bfe0 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -5430,10 +5430,6 @@ mod c { if target_arch == "arm" && target_os != "ios" { sources.extend( &[ - "arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", "arm/aeabi_dcmp.S", "arm/aeabi_div0.c", "arm/aeabi_drsub.c", @@ -5467,6 +5463,20 @@ mod c { // "arm/udivsi3.S", ], ); + + // First of all aeabi_cdcmp and aeabi_cfcmp are never called LLVM. + // Second are little-endian only, so build fail on big-endian targets. + // Temporally workaround: exclude these files for big-endian targets. + if !llvm_target[0].starts_with("thumbeb") && + !llvm_target[0].starts_with("armeb") { + sources.extend( + &[ + "arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + ], + ); } if llvm_target[0] == "armv7" { -- cgit 1.4.1-3-g733a5 From c68621f444fbf9687d590ee9987d22687dc13cc2 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Fri, 19 Jan 2018 19:27:25 +0100 Subject: Fix build issue and comments Fix an unclosed if block --- library/compiler-builtins/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0b27598bfe0..cb8f810fee3 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -5464,7 +5464,7 @@ mod c { ], ); - // First of all aeabi_cdcmp and aeabi_cfcmp are never called LLVM. + // First of all aeabi_cdcmp and aeabi_cfcmp are never called by LLVM. // Second are little-endian only, so build fail on big-endian targets. // Temporally workaround: exclude these files for big-endian targets. if !llvm_target[0].starts_with("thumbeb") && @@ -5477,6 +5477,7 @@ mod c { "arm/aeabi_cfcmpeq_check_nan.c", ], ); + } } if llvm_target[0] == "armv7" { -- cgit 1.4.1-3-g733a5 From b75149347268413ec2fe4c4131b7e2f5680af3cd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 24 Jan 2018 15:20:48 -0800 Subject: Fix some typos/bugs with float comparison intrinsics * I believe `__gtdf2` erroneously used `f32` instead of `f64` * Most of these needed `#[arm_aeabi_alias]` to ensure they're correctly called through the alias * Some existing aliases were corrected with the right names --- library/compiler-builtins/build.rs | 2 -- library/compiler-builtins/src/float/cmp.rs | 49 ++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index cb8f810fee3..a7351cc990e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -5430,10 +5430,8 @@ mod c { if target_arch == "arm" && target_os != "ios" { sources.extend( &[ - "arm/aeabi_dcmp.S", "arm/aeabi_div0.c", "arm/aeabi_drsub.c", - "arm/aeabi_fcmp.S", "arm/aeabi_frsub.c", "arm/bswapdi2.S", "arm/bswapsi2.S", diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index e884872f1d4..e3c584084ad 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -120,7 +120,7 @@ intrinsics! { cmp(a, b).to_ge_abi() } - #[arm_aeabi_alias = fcmpun] + #[arm_aeabi_alias = __aeabi_fcmpun] pub extern "C" fn __unordsf2(a: f32, b: f32) -> i32 { unord(a, b) as i32 } @@ -149,7 +149,7 @@ intrinsics! { cmp(a, b).to_ge_abi() } - #[arm_aeabi_alias = dcmpun] + #[arm_aeabi_alias = __aeabi_dcmpun] pub extern "C" fn __unorddf2(a: f64, b: f64) -> i32 { unord(a, b) as i32 } @@ -166,7 +166,50 @@ intrinsics! { cmp(a, b).to_le_abi() } - pub extern "C" fn __gtdf2(a: f32, b: f32) -> i32 { + pub extern "C" fn __gtdf2(a: f64, b: f64) -> i32 { cmp(a, b).to_ge_abi() } } + +#[cfg(target_arch = "arm")] +intrinsics! { + pub extern "aapcs" fn __aeabi_fcmple(a: f32, b: f32) -> i32 { + (__lesf2(a, b) < 0) as i32 + } + + pub extern "aapcs" fn __aeabi_fcmpge(a: f32, b: f32) -> i32 { + (__gesf2(a, b) >= 0) as i32 + } + + pub extern "aapcs" fn __aeabi_fcmpeq(a: f32, b: f32) -> i32 { + (__eqsf2(a, b) == 0) as i32 + } + + pub extern "aapcs" fn __aeabi_fcmplt(a: f32, b: f32) -> i32 { + (__ltsf2(a, b) < 0) as i32 + } + + pub extern "aapcs" fn __aeabi_fcmpgt(a: f32, b: f32) -> i32 { + (__gtsf2(a, b) > 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmple(a: f64, b: f64) -> i32 { + (__ledf2(a, b) <= 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmpge(a: f64, b: f64) -> i32 { + (__gedf2(a, b) >= 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmpeq(a: f64, b: f64) -> i32 { + (__eqdf2(a, b) == 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmplt(a: f64, b: f64) -> i32 { + (__ltdf2(a, b) < 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmpgt(a: f64, b: f64) -> i32 { + (__gtdf2(a, b) > 0) as i32 + } +} -- cgit 1.4.1-3-g733a5 From ffd4f4d43d25a79267ee011ae249e328257d076a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 23 Jan 2018 15:23:21 -0800 Subject: Update to release_60 of LLVM's compiler-rt --- library/compiler-builtins/.gitmodules | 2 +- library/compiler-builtins/compiler-rt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index bbdcf701cd6..3ff1154f3e7 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ -[submodule "compiler-rt/compiler-rt-cdylib/compiler-rt"] +[submodule "compiler-rt"] path = compiler-rt url = https://github.com/rust-lang/compiler-rt diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index c8a8767c56a..dfd960b5f1a 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit c8a8767c56ad3d3f4eb45c87b95026936fb9aa35 +Subproject commit dfd960b5f1a1751b22738fa34fd27b583f4618db -- cgit 1.4.1-3-g733a5 From 9a4e458b488af6992353e81acb87baaf05481f81 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Mon, 29 Jan 2018 19:52:55 +0100 Subject: Add support for mul[s/d]f3vfp and div[s/d]f3vfp Here using `"C"` the compiler will use `"aapcs"` or `"aapcs-vfp"` depending on target configuration. Of course this translates in a call to `__aeabi_fdiv` / `__aeabi_fmul` on non-HF targets. On `eabi` targets with +vfpv2/vfpv3 LLVM generate: vmov s0, r1 vmov s2, r0 vdiv.f32 s0, s2, s0 vmov r0, s0 bx lr On `eabihf` targets with +vfpv3-d16/d32/f32 +fp-only-sp LLVM generate: vdiv.f32 s0, s0, s1 bx lr That's exactly what We need for [div/mul][s/d]f3vfp.S --- library/compiler-builtins/README.md | 8 ++++---- library/compiler-builtins/build.rs | 4 ---- library/compiler-builtins/src/float/div.rs | 7 +++++++ library/compiler-builtins/src/float/mul.rs | 8 ++++++++ 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index a7dabe7b5a7..cc4852a446a 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -96,9 +96,9 @@ features = ["c"] - [x] arm/aeabi_memset.S - [x] arm/aeabi_uidivmod.S - [x] arm/aeabi_uldivmod.S -- [ ] arm/divdf3vfp.S +- [x] arm/divdf3vfp.S - [ ] arm/divmodsi4.S (generic version is done) -- [ ] arm/divsf3vfp.S +- [x] arm/divsf3vfp.S - [ ] arm/divsi3.S (generic version is done) - [ ] arm/eqdf2vfp.S - [ ] arm/eqsf2vfp.S @@ -120,8 +120,8 @@ features = ["c"] - [ ] arm/ltdf2vfp.S - [ ] arm/ltsf2vfp.S - [ ] arm/modsi3.S (generic version is done) -- [ ] arm/muldf3vfp.S -- [ ] arm/mulsf3vfp.S +- [x] arm/muldf3vfp.S +- [x] arm/mulsf3vfp.S - [ ] arm/nedf2vfp.S - [ ] arm/negdf2vfp.S - [ ] arm/negsf2vfp.S diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a7351cc990e..1bb2b0ffc7b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -5511,8 +5511,6 @@ mod c { &[ "arm/adddf3vfp.S", "arm/addsf3vfp.S", - "arm/divdf3vfp.S", - "arm/divsf3vfp.S", "arm/eqdf2vfp.S", "arm/eqsf2vfp.S", "arm/extendsfdf2vfp.S", @@ -5532,8 +5530,6 @@ mod c { "arm/lesf2vfp.S", "arm/ltdf2vfp.S", "arm/ltsf2vfp.S", - "arm/muldf3vfp.S", - "arm/mulsf3vfp.S", "arm/nedf2vfp.S", "arm/nesf2vfp.S", "arm/restore_vfp_d8_d15_regs.S", diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index e0e287a9ea3..94be4f2a5c9 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -454,4 +454,11 @@ intrinsics! { div64(a, b) } + pub extern "C" fn __divsf3vfp(a: f32, b: f32) -> f32 { + a / b + } + + pub extern "C" fn __divdf3vfp(a: f64, b: f64) -> f64 { + a / b + } } diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 696adeaecb3..c5c5403521d 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -188,4 +188,12 @@ intrinsics! { pub extern "C" fn __muldf3(a: f64, b: f64) -> f64 { mul(a, b) } + + pub extern "C" fn __mulsf3vfp(a: f32, b: f32) -> f32 { + a * b + } + + pub extern "C" fn __muldf3vfp(a: f64, b: f64) -> f64 { + a * b + } } -- cgit 1.4.1-3-g733a5 From 298629196536e43006d828af5b2a8e6d0e52dbb9 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Tue, 30 Jan 2018 18:48:20 +0100 Subject: __[mul/div]sf3vfp and __[mul/div]df3vfp only on ARM --- library/compiler-builtins/src/float/div.rs | 2 ++ library/compiler-builtins/src/float/mul.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 94be4f2a5c9..ae12bb32140 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -454,10 +454,12 @@ intrinsics! { div64(a, b) } + #[cfg(target_arch = "arm")] pub extern "C" fn __divsf3vfp(a: f32, b: f32) -> f32 { a / b } + #[cfg(target_arch = "arm")] pub extern "C" fn __divdf3vfp(a: f64, b: f64) -> f64 { a / b } diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index c5c5403521d..d014bbc90c0 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -189,10 +189,12 @@ intrinsics! { mul(a, b) } + #[cfg(target_arch = "arm")] pub extern "C" fn __mulsf3vfp(a: f32, b: f32) -> f32 { a * b } + #[cfg(target_arch = "arm")] pub extern "C" fn __muldf3vfp(a: f64, b: f64) -> f64 { a * b } -- cgit 1.4.1-3-g733a5 From cc3ea0ab935e00d09e11b72a746c113d7d7799f4 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Tue, 30 Jan 2018 20:15:37 +0100 Subject: Add test cases for Mul[s/d]f3vfp and Div[s/d]f3vfp for ARM targets only --- library/compiler-builtins/build.rs | 339 +++++++++++++++++++++++++++ library/compiler-builtins/tests/divdf3vfp.rs | 8 + library/compiler-builtins/tests/divsf3vfp.rs | 8 + library/compiler-builtins/tests/muldf3vfp.rs | 8 + library/compiler-builtins/tests/mulsf3vfp.rs | 8 + 5 files changed, 371 insertions(+) create mode 100644 library/compiler-builtins/tests/divdf3vfp.rs create mode 100644 library/compiler-builtins/tests/divsf3vfp.rs create mode 100644 library/compiler-builtins/tests/muldf3vfp.rs create mode 100644 library/compiler-builtins/tests/mulsf3vfp.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 1bb2b0ffc7b..a8407b268d2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -130,10 +130,14 @@ mod tests { // float/mul.rs Mulsf3, Muldf3, + Mulsf3vfp, + Muldf3vfp, // float/div.rs Divsf3, Divdf3, + Divsf3vfp, + Divdf3vfp, // int/addsub.rs AddU128, @@ -4203,6 +4207,171 @@ fn muldf3() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Mulsf3vfp { + a: u32, // f32 + b: u32, // f32 + c: u32, // f32 + } + + impl TestCase for Mulsf3vfp { + fn name() -> &'static str { + "mulsf3vfp" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f32(rng); + let b = gen_large_f32(rng); + let c = a * b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Mulsf3vfp { + a: to_u32(a), + b: to_u32(b), + c: to_u32(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +use compiler_builtins::float::mul::__mulsf3vfp; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn mulsf3vfp() { + for &((a, b), c) in TEST_CASES { + let c_ = __mulsf3vfp(mk_f32(a), mk_f32(b)); + assert_eq!(((a, b), c), ((a, b), to_u32(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Muldf3vfp { + a: u64, // f64 + b: u64, // f64 + c: u64, // f64 + } + + impl TestCase for Muldf3vfp { + fn name() -> &'static str { + "muldf3vfp" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f64(rng); + let b = gen_large_f64(rng); + let c = a * b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Muldf3vfp { + a: to_u64(a), + b: to_u64(b), + c: to_u64(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +use compiler_builtins::float::mul::__muldf3vfp; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn muldf3vfp() { + for &((a, b), c) in TEST_CASES { + let c_ = __muldf3vfp(mk_f64(a), mk_f64(b)); + assert_eq!(((a, b), c), ((a, b), to_u64(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] pub struct Divsf3 { a: u32, // f32 @@ -4384,6 +4553,176 @@ fn divdf3() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Divsf3vfp { + a: u32, // f32 + b: u32, // f32 + c: u32, // f32 + } + + impl TestCase for Divsf3vfp { + fn name() -> &'static str { + "divsf3vfp" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f32(rng); + let b = gen_large_f32(rng); + if b == 0.0 { + return None; + } + let c = a / b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan()|| c.abs() <= unsafe { mem::transmute(16777215u32) } { + return None; + } + + Some( + Divsf3vfp { + a: to_u32(a), + b: to_u32(b), + c: to_u32(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +use compiler_builtins::float::div::__divsf3vfp; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divsf3vfp() { + for &((a, b), c) in TEST_CASES { + let c_ = __divsf3vfp(mk_f32(a), mk_f32(b)); + assert_eq!(((a, b), c), ((a, b), to_u32(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divdf3vfp { + a: u64, // f64 + b: u64, // f64 + c: u64, // f64 + } + + impl TestCase for Divdf3vfp { + fn name() -> &'static str { + "divdf3vfp" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f64(rng); + let b = gen_large_f64(rng); + if b == 0.0 { + return None; + } + let c = a / b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() + || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } { + return None; + } + + Some( + Divdf3vfp { + a: to_u64(a), + b: to_u64(b), + c: to_u64(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +use compiler_builtins::float::div::__divdf3vfp; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divdf3vfp() { + for &((a, b), c) in TEST_CASES { + let c_ = __divdf3vfp(mk_f64(a), mk_f64(b)); + assert_eq!(((a, b), c), ((a, b), to_u64(c_))); + } +} +" + } + } #[derive(Eq, Hash, PartialEq)] pub struct Udivdi3 { diff --git a/library/compiler-builtins/tests/divdf3vfp.rs b/library/compiler-builtins/tests/divdf3vfp.rs new file mode 100644 index 00000000000..9225a5c30a1 --- /dev/null +++ b/library/compiler-builtins/tests/divdf3vfp.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +#[cfg(target_arch = "arm")] +include!(concat!(env!("OUT_DIR"), "/divdf3vfp.rs")); diff --git a/library/compiler-builtins/tests/divsf3vfp.rs b/library/compiler-builtins/tests/divsf3vfp.rs new file mode 100644 index 00000000000..0ecc8fe0c8b --- /dev/null +++ b/library/compiler-builtins/tests/divsf3vfp.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +#[cfg(target_arch = "arm")] +include!(concat!(env!("OUT_DIR"), "/divsf3vfp.rs")); diff --git a/library/compiler-builtins/tests/muldf3vfp.rs b/library/compiler-builtins/tests/muldf3vfp.rs new file mode 100644 index 00000000000..8a717157fb0 --- /dev/null +++ b/library/compiler-builtins/tests/muldf3vfp.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +#[cfg(target_arch = "arm")] +include!(concat!(env!("OUT_DIR"), "/muldf3vfp.rs")); diff --git a/library/compiler-builtins/tests/mulsf3vfp.rs b/library/compiler-builtins/tests/mulsf3vfp.rs new file mode 100644 index 00000000000..4d7f288970a --- /dev/null +++ b/library/compiler-builtins/tests/mulsf3vfp.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +#[cfg(target_arch = "arm")] +include!(concat!(env!("OUT_DIR"), "/mulsf3vfp.rs")); -- cgit 1.4.1-3-g733a5 From 4c7de1e315e82e6891156b9ce067188a0f374149 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Tue, 30 Jan 2018 23:10:56 +0100 Subject: Fix build errors on arm*-linux-gnueabi I removed std::mem, but We need it. --- library/compiler-builtins/build.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a8407b268d2..12ed31f5d74 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4260,6 +4260,11 @@ fn muldf3() { target_os = "linux", test))] use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; use compiler_builtins::float::mul::__mulsf3vfp; fn mk_f32(x: u32) -> f32 { @@ -4342,6 +4347,11 @@ fn mulsf3vfp() { target_os = "linux", test))] use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; use compiler_builtins::float::mul::__muldf3vfp; fn mk_f64(x: u64) -> f64 { @@ -4609,6 +4619,11 @@ fn divdf3() { target_os = "linux", test))] use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; use compiler_builtins::float::div::__divsf3vfp; fn mk_f32(x: u32) -> f32 { @@ -4695,6 +4710,11 @@ fn divsf3vfp() { target_os = "linux", test))] use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; use compiler_builtins::float::div::__divdf3vfp; fn mk_f64(x: u64) -> f64 { -- cgit 1.4.1-3-g733a5 From 4d0ea26a26a22da8f8f49350ffb4a78813a47eb1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 31 Jan 2018 07:26:44 -0800 Subject: Allow thumb failures They've been broken for some time anyway --- library/compiler-builtins/.travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 898a600eb41..efd0b1738e3 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -28,6 +28,11 @@ matrix: - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu + allow_failures: + - env: TARGET=thumbv6m-linux-eabi + - env: TARGET=thumbv7em-linux-eabi + - env: TARGET=thumbv7em-linux-eabihf + - env: TARGET=thumbv7m-linux-eabi install: - case $TARGET in -- cgit 1.4.1-3-g733a5 From 41290fe7282f7f89893df59e72fb0867e1598df7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 31 Jan 2018 10:04:01 -0800 Subject: Simplify how testing is done All tests are moved to a separate crate in this repository to enable features by default. Additionally the test generation is moved to a seprate build script and simplified to reduce the amount of boilerplate needed per test. Overall this should still be testing everything, just in a different location! --- library/compiler-builtins/Cargo.toml | 37 +- library/compiler-builtins/build.rs | 5493 -------------------- library/compiler-builtins/ci/run.sh | 10 +- library/compiler-builtins/src/lib.rs | 9 +- library/compiler-builtins/src/macros.rs | 2 +- library/compiler-builtins/testcrate/Cargo.toml | 25 + library/compiler-builtins/testcrate/build.rs | 914 ++++ library/compiler-builtins/testcrate/src/lib.rs | 7 + .../testcrate/tests/aeabi_memclr.rs | 58 + .../testcrate/tests/aeabi_memcpy.rs | 69 + .../testcrate/tests/aeabi_memset.rs | 274 + .../compiler-builtins/testcrate/tests/generated.rs | 6 + library/compiler-builtins/tests/adddf3.rs | 8 - library/compiler-builtins/tests/addsf3.rs | 8 - library/compiler-builtins/tests/aeabi_memclr.rs | 58 - library/compiler-builtins/tests/aeabi_memcpy.rs | 69 - library/compiler-builtins/tests/aeabi_memset.rs | 274 - library/compiler-builtins/tests/ashldi3.rs | 8 - library/compiler-builtins/tests/ashlti3.rs | 8 - library/compiler-builtins/tests/ashrdi3.rs | 8 - library/compiler-builtins/tests/ashrti3.rs | 8 - library/compiler-builtins/tests/divdf3.rs | 7 - library/compiler-builtins/tests/divdf3vfp.rs | 8 - library/compiler-builtins/tests/divdi3.rs | 8 - library/compiler-builtins/tests/divmoddi4.rs | 8 - library/compiler-builtins/tests/divmodsi4.rs | 8 - library/compiler-builtins/tests/divsf3.rs | 7 - library/compiler-builtins/tests/divsf3vfp.rs | 8 - library/compiler-builtins/tests/divsi3.rs | 8 - library/compiler-builtins/tests/divti3.rs | 10 - library/compiler-builtins/tests/fixdfdi.rs | 8 - library/compiler-builtins/tests/fixdfsi.rs | 8 - library/compiler-builtins/tests/fixdfti.rs | 8 - library/compiler-builtins/tests/fixsfdi.rs | 8 - library/compiler-builtins/tests/fixsfsi.rs | 8 - library/compiler-builtins/tests/fixsfti.rs | 8 - library/compiler-builtins/tests/fixunsdfdi.rs | 8 - library/compiler-builtins/tests/fixunsdfsi.rs | 8 - library/compiler-builtins/tests/fixunsdfti.rs | 8 - library/compiler-builtins/tests/fixunssfdi.rs | 8 - library/compiler-builtins/tests/fixunssfsi.rs | 8 - library/compiler-builtins/tests/fixunssfti.rs | 8 - library/compiler-builtins/tests/floatdidf.rs | 8 - library/compiler-builtins/tests/floatsidf.rs | 8 - library/compiler-builtins/tests/floatsisf.rs | 8 - library/compiler-builtins/tests/floattidf.rs | 9 - library/compiler-builtins/tests/floattisf.rs | 8 - library/compiler-builtins/tests/floatundidf.rs | 8 - library/compiler-builtins/tests/floatunsidf.rs | 8 - library/compiler-builtins/tests/floatunsisf.rs | 8 - library/compiler-builtins/tests/floatuntidf.rs | 8 - library/compiler-builtins/tests/floatuntisf.rs | 8 - library/compiler-builtins/tests/gedf2.rs | 7 - library/compiler-builtins/tests/gesf2.rs | 7 - library/compiler-builtins/tests/i128_add.rs | 8 - library/compiler-builtins/tests/i128_addo.rs | 8 - library/compiler-builtins/tests/i128_sub.rs | 8 - library/compiler-builtins/tests/i128_subo.rs | 8 - library/compiler-builtins/tests/ledf2.rs | 7 - library/compiler-builtins/tests/lesf2.rs | 7 - library/compiler-builtins/tests/lshrdi3.rs | 8 - library/compiler-builtins/tests/lshrti3.rs | 8 - library/compiler-builtins/tests/moddi3.rs | 8 - library/compiler-builtins/tests/modsi3.rs | 8 - library/compiler-builtins/tests/modti3.rs | 10 - library/compiler-builtins/tests/muldf3.rs | 7 - library/compiler-builtins/tests/muldf3vfp.rs | 8 - library/compiler-builtins/tests/muldi3.rs | 8 - library/compiler-builtins/tests/mulodi4.rs | 8 - library/compiler-builtins/tests/mulosi4.rs | 8 - library/compiler-builtins/tests/muloti4.rs | 10 - library/compiler-builtins/tests/mulsf3.rs | 7 - library/compiler-builtins/tests/mulsf3vfp.rs | 8 - library/compiler-builtins/tests/multi3.rs | 8 - library/compiler-builtins/tests/powidf2.rs | 8 - library/compiler-builtins/tests/powisf2.rs | 8 - library/compiler-builtins/tests/subdf3.rs | 8 - library/compiler-builtins/tests/subsf3.rs | 8 - library/compiler-builtins/tests/u128_add.rs | 8 - library/compiler-builtins/tests/u128_addo.rs | 8 - library/compiler-builtins/tests/u128_sub.rs | 8 - library/compiler-builtins/tests/u128_subo.rs | 8 - library/compiler-builtins/tests/udivdi3.rs | 8 - library/compiler-builtins/tests/udivmoddi4.rs | 8 - library/compiler-builtins/tests/udivmodsi4.rs | 8 - library/compiler-builtins/tests/udivmodti4.rs | 10 - library/compiler-builtins/tests/udivsi3.rs | 8 - library/compiler-builtins/tests/udivti3.rs | 10 - library/compiler-builtins/tests/umoddi3.rs | 8 - library/compiler-builtins/tests/umodsi3.rs | 8 - library/compiler-builtins/tests/umodti3.rs | 10 - 91 files changed, 1382 insertions(+), 6536 deletions(-) create mode 100644 library/compiler-builtins/testcrate/Cargo.toml create mode 100644 library/compiler-builtins/testcrate/build.rs create mode 100644 library/compiler-builtins/testcrate/src/lib.rs create mode 100644 library/compiler-builtins/testcrate/tests/aeabi_memclr.rs create mode 100644 library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs create mode 100644 library/compiler-builtins/testcrate/tests/aeabi_memset.rs create mode 100644 library/compiler-builtins/testcrate/tests/generated.rs delete mode 100644 library/compiler-builtins/tests/adddf3.rs delete mode 100644 library/compiler-builtins/tests/addsf3.rs delete mode 100644 library/compiler-builtins/tests/aeabi_memclr.rs delete mode 100644 library/compiler-builtins/tests/aeabi_memcpy.rs delete mode 100644 library/compiler-builtins/tests/aeabi_memset.rs delete mode 100644 library/compiler-builtins/tests/ashldi3.rs delete mode 100644 library/compiler-builtins/tests/ashlti3.rs delete mode 100644 library/compiler-builtins/tests/ashrdi3.rs delete mode 100644 library/compiler-builtins/tests/ashrti3.rs delete mode 100644 library/compiler-builtins/tests/divdf3.rs delete mode 100644 library/compiler-builtins/tests/divdf3vfp.rs delete mode 100644 library/compiler-builtins/tests/divdi3.rs delete mode 100644 library/compiler-builtins/tests/divmoddi4.rs delete mode 100644 library/compiler-builtins/tests/divmodsi4.rs delete mode 100644 library/compiler-builtins/tests/divsf3.rs delete mode 100644 library/compiler-builtins/tests/divsf3vfp.rs delete mode 100644 library/compiler-builtins/tests/divsi3.rs delete mode 100644 library/compiler-builtins/tests/divti3.rs delete mode 100644 library/compiler-builtins/tests/fixdfdi.rs delete mode 100644 library/compiler-builtins/tests/fixdfsi.rs delete mode 100644 library/compiler-builtins/tests/fixdfti.rs delete mode 100644 library/compiler-builtins/tests/fixsfdi.rs delete mode 100644 library/compiler-builtins/tests/fixsfsi.rs delete mode 100644 library/compiler-builtins/tests/fixsfti.rs delete mode 100644 library/compiler-builtins/tests/fixunsdfdi.rs delete mode 100644 library/compiler-builtins/tests/fixunsdfsi.rs delete mode 100644 library/compiler-builtins/tests/fixunsdfti.rs delete mode 100644 library/compiler-builtins/tests/fixunssfdi.rs delete mode 100644 library/compiler-builtins/tests/fixunssfsi.rs delete mode 100644 library/compiler-builtins/tests/fixunssfti.rs delete mode 100644 library/compiler-builtins/tests/floatdidf.rs delete mode 100644 library/compiler-builtins/tests/floatsidf.rs delete mode 100644 library/compiler-builtins/tests/floatsisf.rs delete mode 100644 library/compiler-builtins/tests/floattidf.rs delete mode 100644 library/compiler-builtins/tests/floattisf.rs delete mode 100644 library/compiler-builtins/tests/floatundidf.rs delete mode 100644 library/compiler-builtins/tests/floatunsidf.rs delete mode 100644 library/compiler-builtins/tests/floatunsisf.rs delete mode 100644 library/compiler-builtins/tests/floatuntidf.rs delete mode 100644 library/compiler-builtins/tests/floatuntisf.rs delete mode 100644 library/compiler-builtins/tests/gedf2.rs delete mode 100644 library/compiler-builtins/tests/gesf2.rs delete mode 100644 library/compiler-builtins/tests/i128_add.rs delete mode 100644 library/compiler-builtins/tests/i128_addo.rs delete mode 100644 library/compiler-builtins/tests/i128_sub.rs delete mode 100644 library/compiler-builtins/tests/i128_subo.rs delete mode 100644 library/compiler-builtins/tests/ledf2.rs delete mode 100644 library/compiler-builtins/tests/lesf2.rs delete mode 100644 library/compiler-builtins/tests/lshrdi3.rs delete mode 100644 library/compiler-builtins/tests/lshrti3.rs delete mode 100644 library/compiler-builtins/tests/moddi3.rs delete mode 100644 library/compiler-builtins/tests/modsi3.rs delete mode 100644 library/compiler-builtins/tests/modti3.rs delete mode 100644 library/compiler-builtins/tests/muldf3.rs delete mode 100644 library/compiler-builtins/tests/muldf3vfp.rs delete mode 100644 library/compiler-builtins/tests/muldi3.rs delete mode 100644 library/compiler-builtins/tests/mulodi4.rs delete mode 100644 library/compiler-builtins/tests/mulosi4.rs delete mode 100644 library/compiler-builtins/tests/muloti4.rs delete mode 100644 library/compiler-builtins/tests/mulsf3.rs delete mode 100644 library/compiler-builtins/tests/mulsf3vfp.rs delete mode 100644 library/compiler-builtins/tests/multi3.rs delete mode 100644 library/compiler-builtins/tests/powidf2.rs delete mode 100644 library/compiler-builtins/tests/powisf2.rs delete mode 100644 library/compiler-builtins/tests/subdf3.rs delete mode 100644 library/compiler-builtins/tests/subsf3.rs delete mode 100644 library/compiler-builtins/tests/u128_add.rs delete mode 100644 library/compiler-builtins/tests/u128_addo.rs delete mode 100644 library/compiler-builtins/tests/u128_sub.rs delete mode 100644 library/compiler-builtins/tests/u128_subo.rs delete mode 100644 library/compiler-builtins/tests/udivdi3.rs delete mode 100644 library/compiler-builtins/tests/udivmoddi4.rs delete mode 100644 library/compiler-builtins/tests/udivmodsi4.rs delete mode 100644 library/compiler-builtins/tests/udivmodti4.rs delete mode 100644 library/compiler-builtins/tests/udivsi3.rs delete mode 100644 library/compiler-builtins/tests/udivti3.rs delete mode 100644 library/compiler-builtins/tests/umoddi3.rs delete mode 100644 library/compiler-builtins/tests/umodsi3.rs delete mode 100644 library/compiler-builtins/tests/umodti3.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index b7743c2ce06..0ebeb17f326 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,38 +1,37 @@ [package] authors = ["Jorge Aparicio "] -build = "build.rs" name = "compiler_builtins" version = "0.1.0" -[build-dependencies] -cast = { version = "0.2.2", features = ["x128"], optional = true } -rand = { version = "0.3.15", optional = true } +[lib] +test = false -[build-dependencies.cc] -optional = true -version = "1.0" +[build-dependencies] +cc = { optional = true, version = "1.0" } [features] +default = ["compiler-builtins"] + +# Enable compilation of C code in compiler-rt, filling in some more optimized +# implementations and also filling in unimplemented intrinsics c = ["cc"] + +# Flag this library as the unstable compiler-builtins lib compiler-builtins = [] -default = ["compiler-builtins"] + +# Generate memory-related intrinsics like memcpy mem = [] -mangled-names = [] -# generate tests -# -# Note that this is an internal-only feature used in testing, this should not -# be relied on with crates.io! Enabling this may expose you to breaking -# changes. -gen-tests = ["cast", "rand"] +# Mangle all names so this can be linked in with other versions or other +# compiler-rt implementations. Also used for testing +mangled-names = [] -[target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] -test = { git = "https://github.com/japaric/utest" } -utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japaric/utest" } -utest-macros = { git = "https://github.com/japaric/utest" } +# Don't generate lang items for i128 intrisnics and such +no-lang-items = [] [[example]] name = "intrinsics" required-features = ["c", "compiler-builtins"] [workspace] +members = ["testcrate"] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 12ed31f5d74..8beb1288116 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,5 +1,3 @@ -#![feature(i128_type)] - use std::env; fn main() { @@ -23,10 +21,6 @@ fn main() { // custom targets, which can have arbitrary names. let llvm_target = target.split('-').collect::>(); - // Build test files - #[cfg(feature = "gen-tests")] - tests::generate(); - // Build missing intrinsics from compiler-rt C source code. If we're // mangling names though we assume that we're also in test mode so we don't // build anything and we rely on the upstream implementation of compiler-rt @@ -57,5493 +51,6 @@ fn main() { } } -#[cfg(feature = "gen-tests")] -mod tests { - extern crate cast; - extern crate rand; - - use std::collections::HashSet; - use std::fmt::Write; - use std::fs::File; - use std::hash::Hash; - use std::path::PathBuf; - use std::{env, mem}; - - use self::cast::{f32, f64, u32, u64, u128, i32, i64, i128}; - use self::rand::Rng; - - const NTESTS: usize = 10_000; - - macro_rules! test { - ($($intrinsic:ident,)+) => { - $( - mk_file::<$intrinsic>(); - )+ - } - } - - pub fn generate() { - // TODO move to main - test! { - // float/add.rs - Adddf3, - Addsf3, - - // float/cmp.rs - Gedf2, - Gesf2, - Ledf2, - Lesf2, - - // float/conv.rs - Fixdfdi, - Fixdfsi, - Fixsfdi, - Fixsfsi, - Fixsfti, - Fixdfti, - Fixunsdfdi, - Fixunsdfsi, - Fixunssfdi, - Fixunssfsi, - Fixunssfti, - Fixunsdfti, - Floatdidf, - Floatsidf, - Floatsisf, - Floattisf, - Floattidf, - Floatundidf, - Floatunsidf, - Floatunsisf, - Floatuntisf, - Floatuntidf, - - // float/pow.rs - Powidf2, - Powisf2, - - // float/sub.rs - Subdf3, - Subsf3, - - // float/mul.rs - Mulsf3, - Muldf3, - Mulsf3vfp, - Muldf3vfp, - - // float/div.rs - Divsf3, - Divdf3, - Divsf3vfp, - Divdf3vfp, - - // int/addsub.rs - AddU128, - AddI128, - AddoU128, - AddoI128, - SubU128, - SubI128, - SuboU128, - SuboI128, - - // int/mul.rs - Muldi3, - Mulodi4, - Mulosi4, - Muloti4, - Multi3, - - // int/sdiv.rs - Divdi3, - Divmoddi4, - Divmodsi4, - Divsi3, - Divti3, - Moddi3, - Modsi3, - Modti3, - - // int/shift.rs - Ashldi3, - Ashlti3, - Ashrdi3, - Ashrti3, - Lshrdi3, - Lshrti3, - - // int/udiv.rs - Udivdi3, - Udivmoddi4, - Udivmodsi4, - Udivmodti4, - Udivsi3, - Udivti3, - Umoddi3, - Umodsi3, - Umodti3, - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Adddf3 { - a: u64, // f64 - b: u64, // f64 - c: u64, // f64 - } - - impl TestCase for Adddf3 { - fn name() -> &'static str { - "adddf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - let b = gen_f64(rng); - let c = a + b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Adddf3 { - a: to_u64(a), - b: to_u64(b), - c: to_u64(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::add::__adddf3; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn adddf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __adddf3(mk_f64(a), mk_f64(b)); - assert_eq!(((a, b), c), ((a, b), to_u64(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Addsf3 { - a: u32, // f32 - b: u32, // f32 - c: u32, // f32 - } - - impl TestCase for Addsf3 { - fn name() -> &'static str { - "addsf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - let b = gen_f32(rng); - let c = a + b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Addsf3 { - a: to_u32(a), - b: to_u32(b), - c: to_u32(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::add::__addsf3; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn addsf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __addsf3(mk_f32(a), mk_f32(b)); - assert_eq!(((a, b), c), ((a, b), to_u32(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct AddU128 { - a: u128, - b: u128, - c: u128, - } - - impl TestCase for AddU128 { - fn name() -> &'static str { - "u128_add" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = gen_u128(rng); - let c = a.wrapping_add(b); - - Some(AddU128 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_u128_add; - -static TEST_CASES: &[((u128, u128), u128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn u128_add() { - for &((a, b), c) in TEST_CASES { - let c_ = rust_u128_add(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct AddI128 { - a: i128, - b: i128, - c: i128, - } - - impl TestCase for AddI128 { - fn name() -> &'static str { - "i128_add" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - let c = a.wrapping_add(b); - - Some(AddI128 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_i128_add; - -static TEST_CASES: &[((i128, i128), i128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn i128_add() { - for &((a, b), c) in TEST_CASES { - let c_ = rust_i128_add(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct AddoU128 { - a: u128, - b: u128, - c: u128, - d: bool, - } - - impl TestCase for AddoU128 { - fn name() -> &'static str { - "u128_addo" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = gen_u128(rng); - let (c, d) = a.overflowing_add(b); - - Some(AddoU128 { a, b, c, d }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {d})),", - a = self.a, - b = self.b, - c = self.c, - d = self.d - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_u128_addo; - -static TEST_CASES: &[((u128, u128), (u128, bool))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn u128_addo() { - for &((a, b), (c, d)) in TEST_CASES { - let (c_, d_) = rust_u128_addo(a, b); - assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct AddoI128 { - a: i128, - b: i128, - c: i128, - d: bool, - } - - impl TestCase for AddoI128 { - fn name() -> &'static str { - "i128_addo" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - let (c, d) = a.overflowing_add(b); - - Some(AddoI128 { a, b, c, d }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {d})),", - a = self.a, - b = self.b, - c = self.c, - d = self.d - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_i128_addo; - -static TEST_CASES: &[((i128, i128), (i128, bool))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn i128_addo() { - for &((a, b), (c, d)) in TEST_CASES { - let (c_, d_) = rust_i128_addo(a, b); - assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Ashldi3 { - a: u64, - b: u32, - c: u64, - } - - impl TestCase for Ashldi3 { - fn name() -> &'static str { - "ashldi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u64(rng); - let b = (rng.gen::() % 64) as u32; - let c = a << b; - - Some(Ashldi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::shift::__ashldi3; - -static TEST_CASES: &[((u64, u32), u64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn ashldi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __ashldi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Ashlti3 { - a: u128, - b: u32, - c: u128, - } - - impl TestCase for Ashlti3 { - fn name() -> &'static str { - "ashlti3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = (rng.gen::() % 128) as u32; - let c = a << b; - - Some(Ashlti3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::shift::__ashlti3; - -static TEST_CASES: &[((u128, u32), u128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn ashlti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __ashlti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Ashrdi3 { - a: i64, - b: u32, - c: i64, - } - - impl TestCase for Ashrdi3 { - fn name() -> &'static str { - "ashrdi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i64(rng); - let b = (rng.gen::() % 64) as u32; - let c = a >> b; - - Some(Ashrdi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::shift::__ashrdi3; - -static TEST_CASES: &[((i64, u32), i64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn ashrdi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __ashrdi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Ashrti3 { - a: i128, - b: u32, - c: i128, - } - - impl TestCase for Ashrti3 { - fn name() -> &'static str { - "ashrti3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = (rng.gen::() % 128) as u32; - let c = a >> b; - - Some(Ashrti3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::shift::__ashrti3; - -static TEST_CASES: &[((i128, u32), i128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn ashrti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __ashrti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divmoddi4 { - a: i64, - b: i64, - c: i64, - rem: i64, - } - - impl TestCase for Divmoddi4 { - fn name() -> &'static str { - "divmoddi4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i64(rng); - let b = gen_i64(rng); - if b == 0 { - return None; - } - let c = a / b; - let rem = a % b; - - Some(Divmoddi4 { a, b, c, rem }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {rem})),", - a = self.a, - b = self.b, - c = self.c, - rem = self.rem - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divmoddi4; - -static TEST_CASES: &[((i64, i64), (i64, i64))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divmoddi4() { - for &((a, b), (c, rem)) in TEST_CASES { - let mut rem_ = 0; - let c_ = __divmoddi4(a, b, &mut rem_); - assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divdi3 { - a: i64, - b: i64, - c: i64, - } - - impl TestCase for Divdi3 { - fn name() -> &'static str { - "divdi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i64(rng); - let b = gen_i64(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Divdi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divdi3; - -static TEST_CASES: &[((i64, i64), i64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divdi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divdi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divmodsi4 { - a: i32, - b: i32, - c: i32, - rem: i32, - } - - impl TestCase for Divmodsi4 { - fn name() -> &'static str { - "divmodsi4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i32(rng); - let b = gen_i32(rng); - if b == 0 { - return None; - } - let c = a / b; - let rem = a % b; - - Some(Divmodsi4 { a, b, c, rem }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {rem})),", - a = self.a, - b = self.b, - c = self.c, - rem = self.rem - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divmodsi4; - -static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divmodsi4() { - for &((a, b), (c, rem)) in TEST_CASES { - let mut rem_ = 0; - let c_ = __divmodsi4(a, b, &mut rem_); - assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divsi3 { - a: i32, - b: i32, - c: i32, - } - - impl TestCase for Divsi3 { - fn name() -> &'static str { - "divsi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i32(rng); - let b = gen_i32(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Divsi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divsi3; - -static TEST_CASES: &[((i32, i32), i32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divsi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divsi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divti3 { - a: i128, - b: i128, - c: i128, - } - - impl TestCase for Divti3 { - fn name() -> &'static str { - "divti3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Divti3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divti3; - -static TEST_CASES: &[((i128, i128), i128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixdfdi { - a: u64, // f64 - b: i64, - } - - impl TestCase for Fixdfdi { - fn name() -> &'static str { - "fixdfdi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - i64(a).ok().map(|b| Fixdfdi { a: to_u64(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixdfdi; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64,), i64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixdfdi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixdfdi(mk_f64(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixdfsi { - a: u64, // f64 - b: i32, - } - - impl TestCase for Fixdfsi { - fn name() -> &'static str { - "fixdfsi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - i32(a).ok().map(|b| Fixdfsi { a: to_u64(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixdfsi; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64,), i32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixdfdi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixdfsi(mk_f64(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixsfdi { - a: u32, // f32 - b: i64, - } - - impl TestCase for Fixsfdi { - fn name() -> &'static str { - "fixsfdi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - i64(a).ok().map(|b| Fixsfdi { a: to_u32(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixsfdi; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), i64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixsfdi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixsfdi(mk_f32(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixsfsi { - a: u32, // f32 - b: i32, - } - - impl TestCase for Fixsfsi { - fn name() -> &'static str { - "fixsfsi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - i32(a).ok().map(|b| Fixsfsi { a: to_u32(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixsfsi; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), i32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixsfsi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixsfsi(mk_f32(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixsfti { - a: u32, // f32 - b: i128, - } - - impl TestCase for Fixsfti { - fn name() -> &'static str { - "fixsfti" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - i128(a).ok().map(|b| Fixsfti { a: to_u32(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixsfti; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), i128)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixsfti() { - for &((a,), b) in TEST_CASES { - let b_ = __fixsfti(mk_f32(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixdfti { - a: u64, // f64 - b: i128, - } - - impl TestCase for Fixdfti { - fn name() -> &'static str { - "fixdfti" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - i128(a).ok().map(|b| Fixdfti { a: to_u64(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixdfti; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64,), i128)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixdfti() { - for &((a,), b) in TEST_CASES { - let b_ = __fixdfti(mk_f64(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixunsdfdi { - a: u64, // f64 - b: u64, - } - - impl TestCase for Fixunsdfdi { - fn name() -> &'static str { - "fixunsdfdi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - u64(a).ok().map(|b| Fixunsdfdi { a: to_u64(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixunsdfdi; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixunsdfdi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixunsdfdi(mk_f64(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixunsdfsi { - a: u64, // f64 - b: u32, - } - - impl TestCase for Fixunsdfsi { - fn name() -> &'static str { - "fixunsdfsi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - u32(a).ok().map(|b| Fixunsdfsi { a: to_u64(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixunsdfsi; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64,), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixunsdfdi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixunsdfsi(mk_f64(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixunssfdi { - a: u32, // f32 - b: u64, - } - - impl TestCase for Fixunssfdi { - fn name() -> &'static str { - "fixunssfdi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - u64(a).ok().map(|b| Fixunssfdi { a: to_u32(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixunssfdi; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixunssfdi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixunssfdi(mk_f32(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixunssfsi { - a: u32, // f32 - b: u32, - } - - impl TestCase for Fixunssfsi { - fn name() -> &'static str { - "fixunssfsi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - u32(a).ok().map(|b| Fixunssfsi { a: to_u32(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixunssfsi; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixunssfsi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixunssfsi(mk_f32(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixunssfti { - a: u32, // f32 - b: u128, - } - - impl TestCase for Fixunssfti { - fn name() -> &'static str { - "fixunssfti" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - u128(a).ok().map(|b| Fixunssfti { a: to_u32(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixunssfti; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), u128)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixunssfti() { - for &((a,), b) in TEST_CASES { - let b_ = __fixunssfti(mk_f32(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixunsdfti { - a: u64, // f64 - b: u128, - } - - impl TestCase for Fixunsdfti { - fn name() -> &'static str { - "fixunsdfti" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - u128(a).ok().map(|b| Fixunsdfti { a: to_u64(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixunsdfti; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64,), u128)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixunsdfti() { - for &((a,), b) in TEST_CASES { - let b_ = __fixunsdfti(mk_f64(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatdidf { - a: i64, - b: u64, // f64 - } - - impl TestCase for Floatdidf { - fn name() -> &'static str { - "floatdidf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i64(rng); - Some( - Floatdidf { - a, - b: to_u64(f64(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatdidf; - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((i64,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatdidf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatdidf(a); - assert_eq!(((a,), b), ((a,), to_u64(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatsidf { - a: i32, - b: u64, // f64 - } - - impl TestCase for Floatsidf { - fn name() -> &'static str { - "floatsidf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i32(rng); - Some( - Floatsidf { - a, - b: to_u64(f64(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatsidf; - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((i32,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatsidf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatsidf(a); - assert_eq!(((a,), b), ((a,), to_u64(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatsisf { - a: i32, - b: u32, // f32 - } - - impl TestCase for Floatsisf { - fn name() -> &'static str { - "floatsisf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i32(rng); - Some( - Floatsisf { - a, - b: to_u32(f32(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatsisf; - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((i32,), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatsisf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatsisf(a); - assert_eq!(((a,), b), ((a,), to_u32(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floattisf { - a: i128, - b: u32, // f32 - } - - impl TestCase for Floattisf { - fn name() -> &'static str { - "floattisf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - Some( - Floattisf { - a, - b: to_u32(f32(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floattisf; - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((i128,), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floattisf() { - for &((a,), b) in TEST_CASES { - let b_ = __floattisf(a); - assert_eq!(((a,), b), ((a,), to_u32(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floattidf { - a: i128, - b: u64, // f64 - } - - impl TestCase for Floattidf { - fn name() -> &'static str { - "floattidf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - Some( - Floattidf { - a, - b: to_u64(f64(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floattidf; - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((i128,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floattidf() { - for &((a,), b) in TEST_CASES { - let b_ = __floattidf(a); - let g_b = to_u64(b_); - let diff = if g_b > b { g_b - b } else { b - g_b }; - assert_eq!(((a,), b, g_b, true), ((a,), b, g_b, diff <= 1)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatundidf { - a: u64, - b: u64, // f64 - } - - impl TestCase for Floatundidf { - fn name() -> &'static str { - "floatundidf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u64(rng); - Some( - Floatundidf { - a, - b: to_u64(f64(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatundidf; - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatundidf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatundidf(a); - assert_eq!(((a,), b), ((a,), to_u64(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatunsidf { - a: u32, - b: u64, // f64 - } - - impl TestCase for Floatunsidf { - fn name() -> &'static str { - "floatunsidf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u32(rng); - Some( - Floatunsidf { - a, - b: to_u64(f64(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatunsidf; - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatunsidf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatunsidf(a); - assert_eq!(((a,), b), ((a,), to_u64(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatunsisf { - a: u32, - b: u32, // f32 - } - - impl TestCase for Floatunsisf { - fn name() -> &'static str { - "floatunsisf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u32(rng); - Some( - Floatunsisf { - a, - b: to_u32(f32(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatunsisf; - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatunsisf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatunsisf(a); - assert_eq!(((a,), b), ((a,), to_u32(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatuntisf { - a: u128, - b: u32, // f32 - } - - impl TestCase for Floatuntisf { - fn name() -> &'static str { - "floatuntisf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let f_a = f32(a); - f_a.ok().map(|f| { - Floatuntisf { - a, - b: to_u32(f), - } - }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatuntisf; - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u128,), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatuntisf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatuntisf(a); - assert_eq!(((a,), b), ((a,), to_u32(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatuntidf { - a: u128, - b: u64, // f64 - } - - impl TestCase for Floatuntidf { - fn name() -> &'static str { - "floatuntidf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - Some( - Floatuntidf { - a, - b: to_u64(f64(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatuntidf; - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u128,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatuntidf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatuntidf(a); - let g_b = to_u64(b_); - let diff = if g_b > b { g_b - b } else { b - g_b }; - assert_eq!(((a,), b, g_b, true), ((a,), b, g_b, diff <= 1)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Gedf2 { - a: u64, - b: u64, - c: i32, - } - - impl TestCase for Gedf2 { - fn name() -> &'static str { - "gedf2" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - let b = gen_f64(rng); - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() { - return None; - } - - let c; - if a.is_nan() || b.is_nan() { - c = -1; - } else if a < b { - c = -1; - } else if a > b { - c = 1; - } else { - c = 0; - } - - Some(Gedf2 { a: to_u64(a), b: to_u64(b), c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use std::mem; -use compiler_builtins::float::cmp::__gedf2; - -fn to_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), i32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn gedf2() { - for &((a, b), c) in TEST_CASES { - let c_ = __gedf2(to_f64(a), to_f64(b)); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Gesf2 { - a: u32, - b: u32, - c: i32, - } - - impl TestCase for Gesf2 { - fn name() -> &'static str { - "gesf2" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - let b = gen_f32(rng); - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() { - return None; - } - - let c; - if a.is_nan() || b.is_nan() { - c = -1; - } else if a < b { - c = -1; - } else if a > b { - c = 1; - } else { - c = 0; - } - - Some(Gesf2 { a: to_u32(a), b: to_u32(b), c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use std::mem; -use compiler_builtins::float::cmp::__gesf2; - -fn to_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), i32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn gesf2() { - for &((a, b), c) in TEST_CASES { - let c_ = __gesf2(to_f32(a), to_f32(b)); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Ledf2 { - a: u64, - b: u64, - c: i32, - } - - impl TestCase for Ledf2 { - fn name() -> &'static str { - "ledf2" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - let b = gen_f64(rng); - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() { - return None; - } - - let c; - if a.is_nan() || b.is_nan() { - c = 1; - } else if a < b { - c = -1; - } else if a > b { - c = 1; - } else { - c = 0; - } - - Some(Ledf2 { a: to_u64(a), b: to_u64(b), c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use std::mem; -use compiler_builtins::float::cmp::__ledf2; - -fn to_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), i32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn ledf2() { - for &((a, b), c) in TEST_CASES { - let c_ = __ledf2(to_f64(a), to_f64(b)); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Lesf2 { - a: u32, - b: u32, - c: i32, - } - - impl TestCase for Lesf2 { - fn name() -> &'static str { - "lesf2" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - let b = gen_f32(rng); - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() { - return None; - } - - let c; - if a.is_nan() || b.is_nan() { - c = 1; - } else if a < b { - c = -1; - } else if a > b { - c = 1; - } else { - c = 0; - } - - Some(Lesf2 { a: to_u32(a), b: to_u32(b), c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use std::mem; -use compiler_builtins::float::cmp::__lesf2; - -fn to_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), i32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn lesf2() { - for &((a, b), c) in TEST_CASES { - let c_ = __lesf2(to_f32(a), to_f32(b)); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Moddi3 { - a: i64, - b: i64, - c: i64, - } - - impl TestCase for Moddi3 { - fn name() -> &'static str { - "moddi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i64(rng); - let b = gen_i64(rng); - if b == 0 { - return None; - } - let c = a % b; - - Some(Moddi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__moddi3; - -static TEST_CASES: &[((i64, i64), i64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn moddi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __moddi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Modsi3 { - a: i32, - b: i32, - c: i32, - } - - impl TestCase for Modsi3 { - fn name() -> &'static str { - "modsi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i32(rng); - let b = gen_i32(rng); - if b == 0 { - return None; - } - let c = a % b; - - Some(Modsi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__modsi3; - -static TEST_CASES: &[((i32, i32), i32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn modsi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __modsi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Modti3 { - a: i128, - b: i128, - c: i128, - } - - impl TestCase for Modti3 { - fn name() -> &'static str { - "modti3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - if b == 0 { - return None; - } - let c = a % b; - - Some(Modti3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__modti3; - -static TEST_CASES: &[((i128, i128), i128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn modti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __modti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - struct Muldi3 { - a: u64, - b: u64, - c: u64, - } - - impl TestCase for Muldi3 { - fn name() -> &'static str { - "muldi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u64(rng); - let b = gen_u64(rng); - let c = a.wrapping_mul(b); - - Some(Muldi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::mul::__muldi3; - -static TEST_CASES: &[((u64, u64), u64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn muldi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __muldi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Mulodi4 { - a: i64, - b: i64, - c: i64, - overflow: u32, - } - - impl TestCase for Mulodi4 { - fn name() -> &'static str { - "mulodi4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - { - let a = gen_i64(rng); - let b = gen_i64(rng); - let c = a.wrapping_mul(b); - let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; - - Some(Mulodi4 { a, b, c, overflow }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {overflow})),", - a = self.a, - b = self.b, - c = self.c, - overflow = self.overflow - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::mul::__mulodi4; - -static TEST_CASES: &[((i64, i64), (i64, i32))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn mulodi4() { - let mut overflow_ = 2; - for &((a, b), (c, overflow)) in TEST_CASES { - let c_ = __mulodi4(a, b, &mut overflow_); - assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Mulosi4 { - a: i32, - b: i32, - c: i32, - overflow: u32, - } - - impl TestCase for Mulosi4 { - fn name() -> &'static str { - "mulosi4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - { - let a = gen_i32(rng); - let b = gen_i32(rng); - let c = a.wrapping_mul(b); - let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; - - Some(Mulosi4 { a, b, c, overflow }) - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::mul::__mulosi4; - -static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn mulosi4() { - let mut overflow_ = 2; - for &((a, b), (c, overflow)) in TEST_CASES { - let c_ = __mulosi4(a, b, &mut overflow_); - assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); - } -} -" - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {overflow})),", - a = self.a, - b = self.b, - c = self.c, - overflow = self.overflow - ) - .unwrap(); - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Muloti4 { - a: i128, - b: i128, - c: i128, - overflow: u32, - } - - impl TestCase for Muloti4 { - fn name() -> &'static str { - "muloti4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - let c = a.wrapping_mul(b); - let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; - - Some(Muloti4 { a, b, c, overflow }) - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::mul::__muloti4; - -static TEST_CASES: &[((i128, i128), (i128, i32))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn muloti4() { - let mut overflow_ = 2; - for &((a, b), (c, overflow)) in TEST_CASES { - let c_ = __muloti4(a, b, &mut overflow_); - assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); - } -} -" - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {overflow})),", - a = self.a, - b = self.b, - c = self.c, - overflow = self.overflow - ) - .unwrap(); - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Multi3 { - a: i128, - b: i128, - c: i128, - } - - impl TestCase for Multi3 { - fn name() -> &'static str { - "multi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - let c = a.wrapping_mul(b); - - Some(Multi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::mul::__multi3; - -static TEST_CASES: &[((i128, i128), i128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn multi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __multi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Powidf2 { - a: u64, // f64 - b: i32, - c: u64, // f64 - } - - impl TestCase for Powidf2 { - fn name() -> &'static str { - "powidf2" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - let b = gen_i32(rng); - let c = a.powi(b); - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets - if a.is_nan() || c.is_nan() { - return None; - } - - Some( - Powidf2 { - a: to_u64(a), - b, - c: to_u64(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::pow::__powidf2; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, i32), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn powidf2() { - for &((a, b), c) in TEST_CASES { - let c_ = __powidf2(mk_f64(a), b); - assert_eq!(((a, b), c), ((a, b), to_u64(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Powisf2 { - a: u32, // f32 - b: i32, - c: u32, // f32 - } - - impl TestCase for Powisf2 { - fn name() -> &'static str { - "powisf2" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - let b = gen_i32(rng); - let c = a.powi(b); - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets - if a.is_nan() || c.is_nan() { - return None; - } - - Some( - Powisf2 { - a: to_u32(a), - b, - c: to_u32(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::pow::__powisf2; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, i32), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn powisf2() { - for &((a, b), c) in TEST_CASES { - let c_ = __powisf2(mk_f32(a), b); - assert_eq!(((a, b), c), ((a, b), to_u32(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Lshrdi3 { - a: u64, - b: u32, - c: u64, - } - - impl TestCase for Lshrdi3 { - fn name() -> &'static str { - "lshrdi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u64(rng); - let b = (rng.gen::() % 64) as u32; - let c = a >> b; - - Some(Lshrdi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::shift::__lshrdi3; - -static TEST_CASES: &[((u64, u32), u64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn lshrdi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __lshrdi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Lshrti3 { - a: u128, - b: u32, - c: u128, - } - - impl TestCase for Lshrti3 { - fn name() -> &'static str { - "lshrti3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = (rng.gen::() % 128) as u32; - let c = a >> b; - - Some(Lshrti3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::shift::__lshrti3; - -static TEST_CASES: &[((u128, u32), u128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn lshrti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __lshrti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Subdf3 { - a: u64, // f64 - b: u64, // f64 - c: u64, // f64 - } - - impl TestCase for Subdf3 { - fn name() -> &'static str { - "subdf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - let b = gen_f64(rng); - let c = a - b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Subdf3 { - a: to_u64(a), - b: to_u64(b), - c: to_u64(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::sub::__subdf3; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn subdf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __subdf3(mk_f64(a), mk_f64(b)); - assert_eq!(((a, b), c), ((a, b), to_u64(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Subsf3 { - a: u32, // f32 - b: u32, // f32 - c: u32, // f32 - } - - impl TestCase for Subsf3 { - fn name() -> &'static str { - "subsf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - let b = gen_f32(rng); - let c = a - b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Subsf3 { - a: to_u32(a), - b: to_u32(b), - c: to_u32(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::sub::__subsf3; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn subsf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __subsf3(mk_f32(a), mk_f32(b)); - assert_eq!(((a, b), c), ((a, b), to_u32(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct SubU128 { - a: u128, - b: u128, - c: u128, - } - - impl TestCase for SubU128 { - fn name() -> &'static str { - "u128_sub" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = gen_u128(rng); - let c = a.wrapping_sub(b); - - Some(SubU128 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_u128_sub; - -static TEST_CASES: &[((u128, u128), u128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn u128_sub() { - for &((a, b), c) in TEST_CASES { - let c_ = rust_u128_sub(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct SubI128 { - a: i128, - b: i128, - c: i128, - } - - impl TestCase for SubI128 { - fn name() -> &'static str { - "i128_sub" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - let c = a.wrapping_sub(b); - - Some(SubI128 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_i128_sub; - -static TEST_CASES: &[((i128, i128), i128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn i128_sub() { - for &((a, b), c) in TEST_CASES { - let c_ = rust_i128_sub(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct SuboU128 { - a: u128, - b: u128, - c: u128, - d: bool, - } - - impl TestCase for SuboU128 { - fn name() -> &'static str { - "u128_subo" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = gen_u128(rng); - let (c, d) = a.overflowing_sub(b); - - Some(SuboU128 { a, b, c, d }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {d})),", - a = self.a, - b = self.b, - c = self.c, - d = self.d - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_u128_subo; - -static TEST_CASES: &[((u128, u128), (u128, bool))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn u128_subo() { - for &((a, b), (c, d)) in TEST_CASES { - let (c_, d_) = rust_u128_subo(a, b); - assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct SuboI128 { - a: i128, - b: i128, - c: i128, - d: bool, - } - - impl TestCase for SuboI128 { - fn name() -> &'static str { - "i128_subo" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - let (c, d) = a.overflowing_sub(b); - - Some(SuboI128 { a, b, c, d }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {d})),", - a = self.a, - b = self.b, - c = self.c, - d = self.d - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_i128_subo; - -static TEST_CASES: &[((i128, i128), (i128, bool))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn i128_subo() { - for &((a, b), (c, d)) in TEST_CASES { - let (c_, d_) = rust_i128_subo(a, b); - assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Mulsf3 { - a: u32, // f32 - b: u32, // f32 - c: u32, // f32 - } - - impl TestCase for Mulsf3 { - fn name() -> &'static str { - "mulsf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f32(rng); - let b = gen_large_f32(rng); - let c = a * b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Mulsf3 { - a: to_u32(a), - b: to_u32(b), - c: to_u32(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::mul::__mulsf3; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn mulsf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __mulsf3(mk_f32(a), mk_f32(b)); - assert_eq!(((a, b), c), ((a, b), to_u32(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Muldf3 { - a: u64, // f64 - b: u64, // f64 - c: u64, // f64 - } - - impl TestCase for Muldf3 { - fn name() -> &'static str { - "muldf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f64(rng); - let b = gen_large_f64(rng); - let c = a * b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Muldf3 { - a: to_u64(a), - b: to_u64(b), - c: to_u64(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::mul::__muldf3; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn muldf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __muldf3(mk_f64(a), mk_f64(b)); - assert_eq!(((a, b), c), ((a, b), to_u64(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Mulsf3vfp { - a: u32, // f32 - b: u32, // f32 - c: u32, // f32 - } - - impl TestCase for Mulsf3vfp { - fn name() -> &'static str { - "mulsf3vfp" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f32(rng); - let b = gen_large_f32(rng); - let c = a * b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Mulsf3vfp { - a: to_u32(a), - b: to_u32(b), - c: to_u32(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::mul::__mulsf3vfp; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn mulsf3vfp() { - for &((a, b), c) in TEST_CASES { - let c_ = __mulsf3vfp(mk_f32(a), mk_f32(b)); - assert_eq!(((a, b), c), ((a, b), to_u32(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Muldf3vfp { - a: u64, // f64 - b: u64, // f64 - c: u64, // f64 - } - - impl TestCase for Muldf3vfp { - fn name() -> &'static str { - "muldf3vfp" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f64(rng); - let b = gen_large_f64(rng); - let c = a * b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Muldf3vfp { - a: to_u64(a), - b: to_u64(b), - c: to_u64(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::mul::__muldf3vfp; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn muldf3vfp() { - for &((a, b), c) in TEST_CASES { - let c_ = __muldf3vfp(mk_f64(a), mk_f64(b)); - assert_eq!(((a, b), c), ((a, b), to_u64(c_))); - } -} -" - } - } - - - #[derive(Eq, Hash, PartialEq)] - pub struct Divsf3 { - a: u32, // f32 - b: u32, // f32 - c: u32, // f32 - } - - impl TestCase for Divsf3 { - fn name() -> &'static str { - "divsf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f32(rng); - let b = gen_large_f32(rng); - if b == 0.0 { - return None; - } - let c = a / b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan()|| c.abs() <= unsafe { mem::transmute(16777215u32) } { - return None; - } - - Some( - Divsf3 { - a: to_u32(a), - b: to_u32(b), - c: to_u32(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::div::__divsf3; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divsf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divsf3(mk_f32(a), mk_f32(b)); - assert_eq!(((a, b), c), ((a, b), to_u32(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divdf3 { - a: u64, // f64 - b: u64, // f64 - c: u64, // f64 - } - - impl TestCase for Divdf3 { - fn name() -> &'static str { - "divdf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f64(rng); - let b = gen_large_f64(rng); - if b == 0.0 { - return None; - } - let c = a / b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() - || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } { - return None; - } - - Some( - Divdf3 { - a: to_u64(a), - b: to_u64(b), - c: to_u64(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::div::__divdf3; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divdf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divdf3(mk_f64(a), mk_f64(b)); - assert_eq!(((a, b), c), ((a, b), to_u64(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divsf3vfp { - a: u32, // f32 - b: u32, // f32 - c: u32, // f32 - } - - impl TestCase for Divsf3vfp { - fn name() -> &'static str { - "divsf3vfp" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f32(rng); - let b = gen_large_f32(rng); - if b == 0.0 { - return None; - } - let c = a / b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan()|| c.abs() <= unsafe { mem::transmute(16777215u32) } { - return None; - } - - Some( - Divsf3vfp { - a: to_u32(a), - b: to_u32(b), - c: to_u32(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::div::__divsf3vfp; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divsf3vfp() { - for &((a, b), c) in TEST_CASES { - let c_ = __divsf3vfp(mk_f32(a), mk_f32(b)); - assert_eq!(((a, b), c), ((a, b), to_u32(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divdf3vfp { - a: u64, // f64 - b: u64, // f64 - c: u64, // f64 - } - - impl TestCase for Divdf3vfp { - fn name() -> &'static str { - "divdf3vfp" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f64(rng); - let b = gen_large_f64(rng); - if b == 0.0 { - return None; - } - let c = a / b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() - || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } { - return None; - } - - Some( - Divdf3vfp { - a: to_u64(a), - b: to_u64(b), - c: to_u64(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::div::__divdf3vfp; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divdf3vfp() { - for &((a, b), c) in TEST_CASES { - let c_ = __divdf3vfp(mk_f64(a), mk_f64(b)); - assert_eq!(((a, b), c), ((a, b), to_u64(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Udivdi3 { - a: u64, - b: u64, - c: u64, - } - - impl TestCase for Udivdi3 { - fn name() -> &'static str { - "udivdi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u64(rng); - let b = gen_u64(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Udivdi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__udivdi3; - -static TEST_CASES: &[((u64, u64), u64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn udivdi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __udivdi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Udivmoddi4 { - a: u64, - b: u64, - c: u64, - rem: u64, - } - - impl TestCase for Udivmoddi4 { - fn name() -> &'static str { - "udivmoddi4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u64(rng); - let b = gen_u64(rng); - if b == 0 { - return None; - } - let c = a / b; - let rem = a % b; - - Some(Udivmoddi4 { a, b, c, rem }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {rem})),", - a = self.a, - b = self.b, - c = self.c, - rem = self.rem - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__udivmoddi4; - -static TEST_CASES: &[((u64, u64), (u64, u64))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn udivmoddi4() { - for &((a, b), (c, rem)) in TEST_CASES { - let mut rem_ = 0; - let c_ = __udivmoddi4(a, b, Some(&mut rem_)); - assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Udivmodsi4 { - a: u32, - b: u32, - c: u32, - rem: u32, - } - - impl TestCase for Udivmodsi4 { - fn name() -> &'static str { - "udivmodsi4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u32(rng); - let b = gen_u32(rng); - if b == 0 { - return None; - } - let c = a / b; - let rem = a % b; - - Some(Udivmodsi4 { a, b, c, rem }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {rem})),", - a = self.a, - b = self.b, - c = self.c, - rem = self.rem - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__udivmodsi4; - -static TEST_CASES: &[((u32, u32), (u32, u32))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn udivmodsi4() { - for &((a, b), (c, rem)) in TEST_CASES { - let mut rem_ = 0; - let c_ = __udivmodsi4(a, b, Some(&mut rem_)); - assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Udivmodti4 { - a: u128, - b: u128, - c: u128, - rem: u128, - } - - impl TestCase for Udivmodti4 { - fn name() -> &'static str { - "udivmodti4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = gen_u128(rng); - if b == 0 { - return None; - } - let c = a / b; - let rem = a % b; - - Some(Udivmodti4 { a, b, c, rem }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {rem})),", - a = self.a, - b = self.b, - c = self.c, - rem = self.rem - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__udivmodti4; - -static TEST_CASES: &[((u128, u128), (u128, u128))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn udivmodti4() { - for &((a, b), (c, rem)) in TEST_CASES { - let mut rem_ = 0; - let c_ = __udivmodti4(a, b, Some(&mut rem_)); - assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Udivsi3 { - a: u32, - b: u32, - c: u32, - } - - impl TestCase for Udivsi3 { - fn name() -> &'static str { - "udivsi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u32(rng); - let b = gen_u32(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Udivsi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__udivsi3; - -static TEST_CASES: &[((u32, u32), u32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn udivsi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __udivsi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Udivti3 { - a: u128, - b: u128, - c: u128, - } - - impl TestCase for Udivti3 { - fn name() -> &'static str { - "udivti3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = gen_u128(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Udivti3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__udivti3; - -static TEST_CASES: &[((u128, u128), u128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn udivti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __udivti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Umoddi3 { - a: u64, - b: u64, - c: u64, - } - - impl TestCase for Umoddi3 { - fn name() -> &'static str { - "umoddi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u64(rng); - let b = gen_u64(rng); - if b == 0 { - return None; - } - let c = a % b; - - Some(Umoddi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__umoddi3; - -static TEST_CASES: &[((u64, u64), u64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn umoddi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __umoddi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Umodsi3 { - a: u32, - b: u32, - c: u32, - } - - impl TestCase for Umodsi3 { - fn name() -> &'static str { - "umodsi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u32(rng); - let b = gen_u32(rng); - if b == 0 { - return None; - } - let c = a % b; - - Some(Umodsi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__umodsi3; - -static TEST_CASES: &[((u32, u32), u32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn umodsi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __umodsi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Umodti3 { - a: u128, - b: u128, - c: u128, - } - - impl TestCase for Umodti3 { - fn name() -> &'static str { - "umodti3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = gen_u128(rng); - if b == 0 { - return None; - } - let c = a % b; - - Some(Umodti3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__umodti3; - -static TEST_CASES: &[((u128, u128), u128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn umodti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __umodti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - trait TestCase { - /// Name of the intrinsic to test - fn name() -> &'static str; - /// Generates a valid test case - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized; - /// Stringifies a test case - fn to_string(&self, buffer: &mut String); - /// Prologue of the test file - fn prologue() -> &'static str; - /// Epilogue of the test file - fn epilogue() -> &'static str; - } - - const PROLOGUE: &'static str = r#" -extern crate compiler_builtins; - -// test runner -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -extern crate utest_cortex_m_qemu; - -// overrides `panic!` -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -#[macro_use] -extern crate utest_macros; - -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -macro_rules! panic { - ($($tt:tt)*) => { - upanic!($($tt)*); - }; -} -"#; - - macro_rules! gen_int { - ($name:ident, $ity:ident, $hty:ident) => { - fn $name(rng: &mut R) -> $ity - where - R: Rng, - { - let mut mk = || if rng.gen_weighted_bool(10) { - *rng.choose(&[::std::$hty::MAX, 0, ::std::$hty::MIN]).unwrap() - } else { - rng.gen::<$hty>() - }; - unsafe { mem::transmute([mk(), mk()]) } - } - - } - } - - gen_int!(gen_i32, i32, i16); - gen_int!(gen_i64, i64, i32); - gen_int!(gen_i128, i128, i64); - - macro_rules! gen_float { - ($name:ident, - $fty:ident, - $uty:ident, - $bits:expr, - $significand_bits:expr) => { - pub fn $name(rng: &mut R) -> $fty - where - R: Rng, - { - const BITS: u8 = $bits; - const SIGNIFICAND_BITS: u8 = $significand_bits; - - const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; - const SIGN_MASK: $uty = (1 << (BITS - 1)); - const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); - - fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { - unsafe { - mem::transmute(((sign as $uty) << (BITS - 1)) | - ((exponent & EXPONENT_MASK) << - SIGNIFICAND_BITS) | - (significand & SIGNIFICAND_MASK)) - } - } - - if rng.gen_weighted_bool(10) { - // Special values - *rng.choose(&[-0.0, - 0.0, - ::std::$fty::NAN, - ::std::$fty::INFINITY, - -::std::$fty::INFINITY]) - .unwrap() - } else if rng.gen_weighted_bool(10) { - // NaN patterns - mk_f32(rng.gen(), rng.gen(), 0) - } else if rng.gen() { - // Denormalized - mk_f32(rng.gen(), 0, rng.gen()) - } else { - // Random anything - mk_f32(rng.gen(), rng.gen(), rng.gen()) - } - } - } - } - - gen_float!(gen_f32, f32, u32, 32, 23); - gen_float!(gen_f64, f64, u64, 64, 52); - - macro_rules! gen_large_float { - ($name:ident, - $fty:ident, - $uty:ident, - $bits:expr, - $significand_bits:expr) => { - pub fn $name(rng: &mut R) -> $fty - where - R: Rng, - { - const BITS: u8 = $bits; - const SIGNIFICAND_BITS: u8 = $significand_bits; - - const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; - const SIGN_MASK: $uty = (1 << (BITS - 1)); - const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); - - fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { - unsafe { - mem::transmute(((sign as $uty) << (BITS - 1)) | - ((exponent & EXPONENT_MASK) << - SIGNIFICAND_BITS) | - (significand & SIGNIFICAND_MASK)) - } - } - - if rng.gen_weighted_bool(10) { - // Special values - *rng.choose(&[-0.0, - 0.0, - ::std::$fty::NAN, - ::std::$fty::INFINITY, - -::std::$fty::INFINITY]) - .unwrap() - } else if rng.gen_weighted_bool(10) { - // NaN patterns - mk_f32(rng.gen(), rng.gen(), 0) - } else if rng.gen() { - // Denormalized - mk_f32(rng.gen(), 0, rng.gen()) - } else { - // Random anything - rng.gen::<$fty>() - } - } - } - } - - gen_large_float!(gen_large_f32, f32, u32, 32, 23); - gen_large_float!(gen_large_f64, f64, u64, 64, 52); - - pub fn gen_u128(rng: &mut R) -> u128 - where - R: Rng, - { - gen_i128(rng) as u128 - } - - pub fn gen_u32(rng: &mut R) -> u32 - where - R: Rng, - { - gen_i32(rng) as u32 - } - - fn gen_u64(rng: &mut R) -> u64 - where - R: Rng, - { - gen_i64(rng) as u64 - } - - pub fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } - } - - pub fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } - } - - fn mk_tests(mut n: usize, rng: &mut R) -> String - where - T: Eq + Hash + TestCase, - R: Rng, - { - let mut buffer = PROLOGUE.to_owned(); - buffer.push_str(T::prologue()); - let mut cases = HashSet::new(); - while n != 0 { - if let Some(case) = T::generate(rng) { - if cases.contains(&case) { - continue; - } - case.to_string(&mut buffer); - n -= 1; - cases.insert(case); - } - } - buffer.push_str(T::epilogue()); - buffer - } - - fn mk_file() - where - T: Eq + Hash + TestCase, - { - use std::io::Write; - - let rng = &mut rand::thread_rng(); - let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let out_file_name = format!("{}.rs", T::name()); - let out_file = out_dir.join(&out_file_name); - println!("Generating {}", out_file_name); - let contents = mk_tests::(NTESTS, rng); - - File::create(out_file) - .unwrap() - .write_all(contents.as_bytes()) - .unwrap(); - } -} - #[cfg(feature = "c")] mod c { extern crate cc; diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 50413cf9f62..bc40e2d603c 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -42,11 +42,11 @@ case $1 in done ;; *) - run="cargo test --no-default-features --target $1" - $run --features 'gen-tests mangled-names' - $run --features 'gen-tests mangled-names' --release - $run --features 'gen-tests mangled-names c' - $run --features 'gen-tests mangled-names c' --release + run="cargo test --manifest-path testcrate/Cargo.toml --target $1" + $run + $run --release + $run --features c + $run --features c --release ;; esac diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index f815a9cf393..8d8d4a2fee0 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -12,7 +12,6 @@ #![feature(compiler_builtins)] #![feature(core_intrinsics)] #![feature(naked_functions)] -#![feature(staged_api)] #![feature(i128_type)] #![feature(repr_simd)] #![feature(abi_unadjusted)] @@ -20,9 +19,11 @@ #![feature(lang_items)] #![allow(unused_features)] #![no_builtins] -#![unstable(feature = "compiler_builtins_lib", - reason = "Compiler builtins. Will never become stable.", - issue = "0")] +#![cfg_attr(feature = "compiler-builtins", feature(staged_api))] +#![cfg_attr(feature = "compiler-builtins", + unstable(feature = "compiler_builtins_lib", + reason = "Compiler builtins. Will never become stable.", + issue = "0"))] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 033f14121a8..58d94958a43 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -288,7 +288,7 @@ macro_rules! u128_lang_items { $($body:tt)* } )*) => ($( - #[cfg_attr(not(any(stage0, feature = "gen-tests")), lang = $lang)] + #[cfg_attr(not(any(stage0, feature = "no-lang-items")), lang = $lang)] pub fn $name( $($argname: $ty),* ) -> $ret { $($body)* } diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml new file mode 100644 index 00000000000..834df68775b --- /dev/null +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "testcrate" +version = "0.1.0" +authors = ["Alex Crichton "] + +[lib] +test = false +doctest = false + +[build-dependencies] +cast = { version = "0.2.2", features = ["x128"] } +rand = { version = "0.4", features = ["i128_support"] } + +[dependencies.compiler_builtins] +path = ".." +default-features = false +features = ["mangled-names", "no-lang-items"] + +[target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] +test = { git = "https://github.com/japaric/utest" } +utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japaric/utest" } +utest-macros = { git = "https://github.com/japaric/utest" } + +[features] +c = ["compiler_builtins/c"] diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs new file mode 100644 index 00000000000..98a0934c0d9 --- /dev/null +++ b/library/compiler-builtins/testcrate/build.rs @@ -0,0 +1,914 @@ +#![feature(i128_type, i128)] + +extern crate cast; +extern crate rand; + +use std::collections::HashMap; +use std::fmt::Write as FmtWrite; +use std::fs::{self, OpenOptions}; +use std::io::Write; +use std::hash::{Hash, Hasher}; +use std::path::PathBuf; +use std::{env, mem}; +use std::fmt; + +use self::cast::{f32, f64, u32, u64, u128, i32, i64, i128}; +use self::rand::Rng; + +const NTESTS: usize = 1_000; + +fn main() { + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let out_file = out_dir.join("generated.rs"); + drop(fs::remove_file(&out_file)); + + let target = env::var("TARGET").unwrap(); + let target_arch_arm = + target.contains("arm") || + target.contains("thumb"); + let target_arch_mips = target.contains("mips"); + + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + + // float/add.rs + gen(|(a, b): (MyF64, MyF64)| { + let c = a.0 + b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::add::__adddf3(a, b)"); + gen(|(a, b): (MyF32, MyF32)| { + let c = a.0 + b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::add::__addsf3(a, b)"); + + // float/cmp.rs + gen(|(a, b): (MyF64, MyF64)| { + let (a, b) = (a.0, b.0); + if a.is_nan() || b.is_nan() { + return None; + } + + if a.is_nan() || b.is_nan() { + Some(-1) + } else if a < b { + Some(-1) + } else if a > b { + Some(1) + } else { + Some(0) + } + }, + "compiler_builtins::float::cmp::__gedf2(a, b)"); + gen(|(a, b): (MyF32, MyF32)| { + let (a, b) = (a.0, b.0); + if a.is_nan() || b.is_nan() { + return None; + } + + if a.is_nan() || b.is_nan() { + Some(-1) + } else if a < b { + Some(-1) + } else if a > b { + Some(1) + } else { + Some(0) + } + }, + "compiler_builtins::float::cmp::__gesf2(a, b)"); + gen(|(a, b): (MyF64, MyF64)| { + let (a, b) = (a.0, b.0); + if a.is_nan() || b.is_nan() { + return None; + } + + if a.is_nan() || b.is_nan() { + Some(1) + } else if a < b { + Some(-1) + } else if a > b { + Some(1) + } else { + Some(0) + } + }, + "compiler_builtins::float::cmp::__ledf2(a, b)"); + gen(|(a, b): (MyF32, MyF32)| { + let (a, b) = (a.0, b.0); + if a.is_nan() || b.is_nan() { + return None; + } + + if a.is_nan() || b.is_nan() { + Some(1) + } else if a < b { + Some(-1) + } else if a > b { + Some(1) + } else { + Some(0) + } + }, + "compiler_builtins::float::cmp::__lesf2(a, b)"); + + // float/conv.rs + gen(|a: MyF64| i64(a.0).ok(), + "compiler_builtins::float::conv::__fixdfdi(a)"); + gen(|a: MyF64| i32(a.0).ok(), + "compiler_builtins::float::conv::__fixdfsi(a)"); + gen(|a: MyF32| i64(a.0).ok(), + "compiler_builtins::float::conv::__fixsfdi(a)"); + gen(|a: MyF32| i32(a.0).ok(), + "compiler_builtins::float::conv::__fixsfsi(a)"); + gen(|a: MyF32| i128(a.0).ok(), + "compiler_builtins::float::conv::__fixsfti(a)"); + gen(|a: MyF64| i128(a.0).ok(), + "compiler_builtins::float::conv::__fixdfti(a)"); + gen(|a: MyF64| u64(a.0).ok(), + "compiler_builtins::float::conv::__fixunsdfdi(a)"); + gen(|a: MyF64| u32(a.0).ok(), + "compiler_builtins::float::conv::__fixunsdfsi(a)"); + gen(|a: MyF32| u64(a.0).ok(), + "compiler_builtins::float::conv::__fixunssfdi(a)"); + gen(|a: MyF32| u32(a.0).ok(), + "compiler_builtins::float::conv::__fixunssfsi(a)"); + gen(|a: MyF32| u128(a.0).ok(), + "compiler_builtins::float::conv::__fixunssfti(a)"); + gen(|a: MyF64| u128(a.0).ok(), + "compiler_builtins::float::conv::__fixunsdfti(a)"); + gen(|a: MyI64| Some(f64(a.0)), + "compiler_builtins::float::conv::__floatdidf(a)"); + gen(|a: MyI32| Some(f64(a.0)), + "compiler_builtins::float::conv::__floatsidf(a)"); + gen(|a: MyI32| Some(f32(a.0)), + "compiler_builtins::float::conv::__floatsisf(a)"); + gen(|a: MyU64| Some(f64(a.0)), + "compiler_builtins::float::conv::__floatundidf(a)"); + gen(|a: MyU32| Some(f64(a.0)), + "compiler_builtins::float::conv::__floatunsidf(a)"); + gen(|a: MyU32| Some(f32(a.0)), + "compiler_builtins::float::conv::__floatunsisf(a)"); + gen(|a: MyU128| f32(a.0).ok(), + "compiler_builtins::float::conv::__floatuntisf(a)"); + if !target_arch_mips { + gen(|a: MyI128| Some(f32(a.0)), + "compiler_builtins::float::conv::__floattisf(a)"); + gen(|a: MyI128| Some(f64(a.0)), + "compiler_builtins::float::conv::__floattidf(a)"); + gen(|a: MyU128| Some(f64(a.0)), + "compiler_builtins::float::conv::__floatuntidf(a)"); + } + + // float/pow.rs + gen(|(a, b): (MyF64, MyI32)| { + let c = a.0.powi(b.0); + if a.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::pow::__powidf2(a, b)"); + gen(|(a, b): (MyF32, MyI32)| { + let c = a.0.powi(b.0); + if a.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::pow::__powisf2(a, b)"); + + // float/sub.rs + gen(|(a, b): (MyF64, MyF64)| { + let c = a.0 - b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::sub::__subdf3(a, b)"); + gen(|(a, b): (MyF32, MyF32)| { + let c = a.0 - b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::sub::__subsf3(a, b)"); + + // float/mul.rs + gen(|(a, b): (MyF64, MyF64)| { + let c = a.0 * b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::mul::__muldf3(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + let c = a.0 * b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::mul::__mulsf3(a, b)"); + + if target_arch_arm { + gen(|(a, b): (MyF64, MyF64)| { + let c = a.0 * b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::mul::__muldf3vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + let c = a.0 * b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::mul::__mulsf3vfp(a, b)"); + } + + // float/div.rs + gen(|(a, b): (MyF64, MyF64)| { + if b.0 == 0.0 { + return None + } + let c = a.0 / b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() || + c.abs() <= unsafe { mem::transmute(4503599627370495u64) } + { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::div::__divdf3(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + if b.0 == 0.0 { + return None + } + let c = a.0 / b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() || + c.abs() <= unsafe { mem::transmute(16777215u32) } + { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::div::__divsf3(a, b)"); + + if target_arch_arm { + gen(|(a, b): (MyF64, MyF64)| { + if b.0 == 0.0 { + return None + } + let c = a.0 / b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() || + c.abs() <= unsafe { mem::transmute(4503599627370495u64) } + { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::div::__divdf3vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + if b.0 == 0.0 { + return None + } + let c = a.0 / b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() || + c.abs() <= unsafe { mem::transmute(16777215u32) } + { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::div::__divsf3vfp(a, b)"); + } + + // int/addsub.rs + gen(|(a, b): (MyU128, MyU128)| Some(a.0.wrapping_add(b.0)), + "compiler_builtins::int::addsub::rust_u128_add(a, b)"); + gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_add(b.0)), + "compiler_builtins::int::addsub::rust_i128_add(a, b)"); + gen(|(a, b): (MyU128, MyU128)| Some(a.0.overflowing_add(b.0)), + "compiler_builtins::int::addsub::rust_u128_addo(a, b)"); + gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_add(b.0)), + "compiler_builtins::int::addsub::rust_i128_addo(a, b)"); + gen(|(a, b): (MyU128, MyU128)| Some(a.0.wrapping_sub(b.0)), + "compiler_builtins::int::addsub::rust_u128_sub(a, b)"); + gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_sub(b.0)), + "compiler_builtins::int::addsub::rust_i128_sub(a, b)"); + gen(|(a, b): (MyU128, MyU128)| Some(a.0.overflowing_sub(b.0)), + "compiler_builtins::int::addsub::rust_u128_subo(a, b)"); + gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_sub(b.0)), + "compiler_builtins::int::addsub::rust_i128_subo(a, b)"); + + // int/mul.rs + gen(|(a, b): (MyU64, MyU64)| Some(a.0.wrapping_mul(b.0)), + "compiler_builtins::int::mul::__muldi3(a, b)"); + gen(|(a, b): (MyI64, MyI64)| Some(a.0.overflowing_mul(b.0)), + "{ + let mut o = 2; + let c = compiler_builtins::int::mul::__mulodi4(a, b, &mut o); + (c, match o { 0 => false, 1 => true, _ => panic!() }) + }"); + gen(|(a, b): (MyI32, MyI32)| Some(a.0.overflowing_mul(b.0)), + "{ + let mut o = 2; + let c = compiler_builtins::int::mul::__mulosi4(a, b, &mut o); + (c, match o { 0 => false, 1 => true, _ => panic!() }) + }"); + gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_mul(b.0)), + "compiler_builtins::int::mul::__multi3(a, b)"); + if !target_arch_mips { // FIXME(#137) + gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_mul(b.0)), + "{ + let mut o = 2; + let c = compiler_builtins::int::mul::__muloti4(a, b, &mut o); + (c, match o { 0 => false, 1 => true, _ => panic!() }) + }"); + } + + // int/sdiv.rs + gen(|(a, b): (MyI64, MyI64)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "compiler_builtins::int::sdiv::__divdi3(a, b)"); + gen(|(a, b): (MyI64, MyI64)| { + if b.0 == 0 { + None + } else { + Some((a.0 / b.0, a.0 % b.0)) + } + }, + "{ + let mut r = 0; + (compiler_builtins::int::sdiv::__divmoddi4(a, b, &mut r), r) + }"); + gen(|(a, b): (MyI32, MyI32)| { + if b.0 == 0 { + None + } else { + Some((a.0 / b.0, a.0 % b.0)) + } + }, + "{ + let mut r = 0; + (compiler_builtins::int::sdiv::__divmodsi4(a, b, &mut r), r) + }"); + gen(|(a, b): (MyI32, MyI32)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "compiler_builtins::int::sdiv::__divsi3(a, b)"); + gen(|(a, b): (MyI32, MyI32)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "compiler_builtins::int::sdiv::__modsi3(a, b)"); + gen(|(a, b): (MyI64, MyI64)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "compiler_builtins::int::sdiv::__moddi3(a, b)"); + if !target_arch_mips { // FIXME(#137) + gen(|(a, b): (MyI128, MyI128)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "compiler_builtins::int::sdiv::__divti3(a, b)"); + gen(|(a, b): (MyI128, MyI128)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "compiler_builtins::int::sdiv::__modti3(a, b)"); + } + + // int/shift.rs + gen(|(a, b): (MyU64, MyU32)| Some(a.0 << (b.0 % 64)), + "compiler_builtins::int::shift::__ashldi3(a, b % 64)"); + gen(|(a, b): (MyU128, MyU32)| Some(a.0 << (b.0 % 128)), + "compiler_builtins::int::shift::__ashlti3(a, b % 128)"); + gen(|(a, b): (MyI64, MyU32)| Some(a.0 >> (b.0 % 64)), + "compiler_builtins::int::shift::__ashrdi3(a, b % 64)"); + gen(|(a, b): (MyI128, MyU32)| Some(a.0 >> (b.0 % 128)), + "compiler_builtins::int::shift::__ashrti3(a, b % 128)"); + gen(|(a, b): (MyU64, MyU32)| Some(a.0 >> (b.0 % 64)), + "compiler_builtins::int::shift::__lshrdi3(a, b % 64)"); + gen(|(a, b): (MyU128, MyU32)| Some(a.0 >> (b.0 % 128)), + "compiler_builtins::int::shift::__lshrti3(a, b % 128)"); + + // int/udiv.rs + gen(|(a, b): (MyU64, MyU64)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "compiler_builtins::int::udiv::__udivdi3(a, b)"); + gen(|(a, b): (MyU64, MyU64)| { + if b.0 == 0 { + None + } else { + Some((a.0 / b.0, a.0 % b.0)) + } + }, + "{ + let mut r = 0; + (compiler_builtins::int::udiv::__udivmoddi4(a, b, Some(&mut r)), r) + }"); + gen(|(a, b): (MyU32, MyU32)| { + if b.0 == 0 { + None + } else { + Some((a.0 / b.0, a.0 % b.0)) + } + }, + "{ + let mut r = 0; + (compiler_builtins::int::udiv::__udivmodsi4(a, b, Some(&mut r)), r) + }"); + gen(|(a, b): (MyU32, MyU32)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "compiler_builtins::int::udiv::__udivsi3(a, b)"); + gen(|(a, b): (MyU32, MyU32)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "compiler_builtins::int::udiv::__umodsi3(a, b)"); + gen(|(a, b): (MyU64, MyU64)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "compiler_builtins::int::udiv::__umoddi3(a, b)"); + if !target_arch_mips { // FIXME(#137) + gen(|(a, b): (MyU128, MyU128)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "compiler_builtins::int::udiv::__udivti3(a, b)"); + gen(|(a, b): (MyU128, MyU128)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "compiler_builtins::int::udiv::__umodti3(a, b)"); + gen(|(a, b): (MyU128, MyU128)| { + if b.0 == 0 { + None + } else { + Some((a.0 / b.0, a.0 % b.0)) + } + }, + "{ + let mut r = 0; + (compiler_builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) + }"); + } +} + +macro_rules! gen_float { + ($name:ident, + $fty:ident, + $uty:ident, + $bits:expr, + $significand_bits:expr) => { + pub fn $name(rng: &mut R) -> $fty + where + R: Rng, + { + const BITS: u8 = $bits; + const SIGNIFICAND_BITS: u8 = $significand_bits; + + const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; + const SIGN_MASK: $uty = (1 << (BITS - 1)); + const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); + + fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { + unsafe { + mem::transmute(((sign as $uty) << (BITS - 1)) | + ((exponent & EXPONENT_MASK) << + SIGNIFICAND_BITS) | + (significand & SIGNIFICAND_MASK)) + } + } + + if rng.gen_weighted_bool(10) { + // Special values + *rng.choose(&[-0.0, + 0.0, + ::std::$fty::NAN, + ::std::$fty::INFINITY, + -::std::$fty::INFINITY]) + .unwrap() + } else if rng.gen_weighted_bool(10) { + // NaN patterns + mk_f32(rng.gen(), rng.gen(), 0) + } else if rng.gen() { + // Denormalized + mk_f32(rng.gen(), 0, rng.gen()) + } else { + // Random anything + mk_f32(rng.gen(), rng.gen(), rng.gen()) + } + } + } +} + +gen_float!(gen_f32, f32, u32, 32, 23); +gen_float!(gen_f64, f64, u64, 64, 52); + +macro_rules! gen_large_float { + ($name:ident, + $fty:ident, + $uty:ident, + $bits:expr, + $significand_bits:expr) => { + pub fn $name(rng: &mut R) -> $fty + where + R: Rng, + { + const BITS: u8 = $bits; + const SIGNIFICAND_BITS: u8 = $significand_bits; + + const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; + const SIGN_MASK: $uty = (1 << (BITS - 1)); + const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); + + fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { + unsafe { + mem::transmute(((sign as $uty) << (BITS - 1)) | + ((exponent & EXPONENT_MASK) << + SIGNIFICAND_BITS) | + (significand & SIGNIFICAND_MASK)) + } + } + + if rng.gen_weighted_bool(10) { + // Special values + *rng.choose(&[-0.0, + 0.0, + ::std::$fty::NAN, + ::std::$fty::INFINITY, + -::std::$fty::INFINITY]) + .unwrap() + } else if rng.gen_weighted_bool(10) { + // NaN patterns + mk_f32(rng.gen(), rng.gen(), 0) + } else if rng.gen() { + // Denormalized + mk_f32(rng.gen(), 0, rng.gen()) + } else { + // Random anything + rng.gen::<$fty>() + } + } + } +} + +gen_large_float!(gen_large_f32, f32, u32, 32, 23); +gen_large_float!(gen_large_f64, f64, u64, 64, 52); + +trait TestInput: rand::Rand + Hash + Eq + fmt::Debug { + fn ty_name() -> String; + fn generate_lets(container: &str, cnt: &mut u8) -> String; + fn generate_static(&self, dst: &mut String); +} + +trait TestOutput { + fn ty_name() -> String; + fn generate_static(&self, dst: &mut String); + fn generate_expr(container: &str) -> String; +} + +fn gen(mut generate: F, test: &str) + where F: FnMut(A) -> Option, + A: TestInput + Copy, + R: TestOutput, +{ + let rng = &mut rand::thread_rng(); + let testname = test.split("::") + .last() + .unwrap() + .split("(") + .next() + .unwrap(); + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let out_file = out_dir.join("generated.rs"); + + let mut testcases = HashMap::new(); + let mut n = NTESTS; + while n > 0 { + let input: A = rng.gen(); + if testcases.contains_key(&input) { + continue + } + let output = match generate(input) { + Some(o) => o, + None => continue, + }; + testcases.insert(input, output); + n -= 1; + } + + let mut contents = String::new(); + contents.push_str(&format!("mod {} {{\nuse super::*;\n", testname)); + contents.push_str("#[test]\n"); + contents.push_str("fn test() {\n"); + contents.push_str(&format!("static TESTS: [({}, {}); {}] = [\n", + A::ty_name(), + R::ty_name(), + NTESTS)); + for (input, output) in testcases { + contents.push_str(" ("); + input.generate_static(&mut contents); + contents.push_str(", "); + output.generate_static(&mut contents); + contents.push_str("),\n"); + } + contents.push_str("];\n"); + + contents.push_str(&format!(r#" + for &(inputs, output) in TESTS.iter() {{ + {} + assert_eq!({}, {}, "inputs {{:?}}", inputs) + }} + "#, + A::generate_lets("inputs", &mut 0), + R::generate_expr("output"), + test, + )); + contents.push_str("\n}\n"); + contents.push_str("\n}\n"); + + OpenOptions::new() + .write(true) + .append(true) + .create(true) + .open(out_file) + .unwrap() + .write_all(contents.as_bytes()) + .unwrap(); +} + +macro_rules! my_float { + ($(struct $name:ident($inner:ident) = $gen:ident;)*) => ($( + #[derive(Debug, Clone, Copy)] + struct $name($inner); + + impl TestInput for $name { + fn ty_name() -> String { + format!("u{}", &stringify!($inner)[1..]) + } + + fn generate_lets(container: &str, cnt: &mut u8) -> String { + let me = *cnt; + *cnt += 1; + format!("let {} = {}::from_bits({});\n", + (b'a' + me) as char, + stringify!($inner), + container) + } + + fn generate_static(&self, dst: &mut String) { + write!(dst, "{}", self.0.to_bits()).unwrap(); + } + } + + impl rand::Rand for $name { + fn rand(r: &mut R) -> $name { + $name($gen(r)) + } + } + + impl Hash for $name { + fn hash(&self, h: &mut H) { + self.0.to_bits().hash(h) + } + } + + impl PartialEq for $name { + fn eq(&self, other: &$name) -> bool { + self.0.to_bits() == other.0.to_bits() + } + } + + impl Eq for $name {} + + )*) +} + +my_float! { + struct MyF64(f64) = gen_f64; + struct LargeF64(f64) = gen_large_f64; + struct MyF32(f32) = gen_f32; + struct LargeF32(f32) = gen_large_f32; +} + +macro_rules! my_integer { + ($(struct $name:ident($inner:ident);)*) => ($( + #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] + struct $name($inner); + + impl TestInput for $name { + fn ty_name() -> String { + stringify!($inner).to_string() + } + + fn generate_lets(container: &str, cnt: &mut u8) -> String { + let me = *cnt; + *cnt += 1; + format!("let {} = {};\n", + (b'a' + me) as char, + container) + } + + fn generate_static(&self, dst: &mut String) { + write!(dst, "{}", self.0).unwrap(); + } + } + + impl rand::Rand for $name { + fn rand(rng: &mut R) -> $name { + let bits = (0 as $inner).count_zeros(); + let mut mk = || { + if rng.gen_weighted_bool(10) { + *rng.choose(&[ + ::std::$inner::MAX >> (bits / 2), + 0, + ::std::$inner::MIN >> (bits / 2), + ]).unwrap() + } else { + rng.gen::<$inner>() + } + }; + let a = mk(); + let b = mk(); + $name((a << (bits / 2)) | (b & (!0 << (bits / 2)))) + } + } + )*) +} + +my_integer! { + struct MyI32(i32); + struct MyI64(i64); + struct MyI128(i128); + struct MyU32(u32); + struct MyU64(u64); + struct MyU128(u128); +} + +impl TestInput for (A, B) + where A: TestInput, + B: TestInput, +{ + fn ty_name() -> String { + format!("({}, {})", A::ty_name(), B::ty_name()) + } + + fn generate_lets(container: &str, cnt: &mut u8) -> String { + format!("{}{}", + A::generate_lets(&format!("{}.0", container), cnt), + B::generate_lets(&format!("{}.1", container), cnt)) + } + + fn generate_static(&self, dst: &mut String) { + dst.push_str("("); + self.0.generate_static(dst); + dst.push_str(", "); + self.1.generate_static(dst); + dst.push_str(")"); + } +} + +impl TestOutput for f64 { + fn ty_name() -> String { + "u64".to_string() + } + + fn generate_static(&self, dst: &mut String) { + write!(dst, "{}", self.to_bits()).unwrap(); + } + + fn generate_expr(container: &str) -> String { + format!("f64::from_bits({})", container) + } +} + +impl TestOutput for f32 { + fn ty_name() -> String { + "u32".to_string() + } + + fn generate_static(&self, dst: &mut String) { + write!(dst, "{}", self.to_bits()).unwrap(); + } + + fn generate_expr(container: &str) -> String { + format!("f32::from_bits({})", container) + } +} + +macro_rules! plain_test_output { + ($($i:tt)*) => ($( + impl TestOutput for $i { + fn ty_name() -> String { + stringify!($i).to_string() + } + + fn generate_static(&self, dst: &mut String) { + write!(dst, "{}", self).unwrap(); + } + + fn generate_expr(container: &str) -> String { + container.to_string() + } + } + )*) +} + +plain_test_output!(i32 i64 i128 u32 u64 u128 bool); + +impl TestOutput for (A, B) + where A: TestOutput, + B: TestOutput, +{ + fn ty_name() -> String { + format!("({}, {})", A::ty_name(), B::ty_name()) + } + + fn generate_static(&self, dst: &mut String) { + dst.push_str("("); + self.0.generate_static(dst); + dst.push_str(", "); + self.1.generate_static(dst); + dst.push_str(")"); + } + + fn generate_expr(container: &str) -> String { + container.to_string() + } +} diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs new file mode 100644 index 00000000000..31e1bb209f9 --- /dev/null +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs new file mode 100644 index 00000000000..72e944e4c74 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs @@ -0,0 +1,58 @@ +#![cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem"))] +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; + +// test runner +extern crate utest_cortex_m_qemu; + +// overrides `panic!` +#[macro_use] +extern crate utest_macros; + +use core::mem; + +macro_rules! panic { + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} + +extern "C" { + fn __aeabi_memclr4(dest: *mut u8, n: usize); + fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); +} + +struct Aligned { + array: [u8; 8], + _alignment: [u32; 0], +} + +impl Aligned { + fn new() -> Self { + Aligned { + array: [0; 8], + _alignment: [], + } + } +} + +#[test] +fn memclr4() { + let mut aligned = Aligned::new();; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + + for n in 0..9 { + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, 0xff); + __aeabi_memclr4(xs.as_mut_ptr(), n); + } + + assert!(xs[0..n].iter().all(|x| *x == 0)); + } +} diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs new file mode 100644 index 00000000000..2ba942c23c1 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs @@ -0,0 +1,69 @@ +#![cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem"))] +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; + +// test runner +extern crate utest_cortex_m_qemu; + +// overrides `panic!` +#[macro_use] +extern crate utest_macros; + +macro_rules! panic { + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} + +extern "C" { + fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize); + fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize); +} + +struct Aligned { + array: [u8; 8], + _alignment: [u32; 0], +} + +impl Aligned { + fn new(array: [u8; 8]) -> Self { + Aligned { + array: array, + _alignment: [], + } + } +} + +#[test] +fn memcpy() { + let mut dest = [0; 4]; + let src = [0xde, 0xad, 0xbe, 0xef]; + + for n in 0..dest.len() { + dest.copy_from_slice(&[0; 4]); + + unsafe { __aeabi_memcpy(dest.as_mut_ptr(), src.as_ptr(), n) } + + assert_eq!(&dest[0..n], &src[0..n]) + } +} + +#[test] +fn memcpy4() { + let mut aligned = Aligned::new([0; 8]); + let dest = &mut aligned.array; + let src = [0xde, 0xad, 0xbe, 0xef, 0xba, 0xad, 0xf0, 0x0d]; + + for n in 0..dest.len() { + dest.copy_from_slice(&[0; 8]); + + unsafe { __aeabi_memcpy4(dest.as_mut_ptr(), src.as_ptr(), n) } + + assert_eq!(&dest[0..n], &src[0..n]) + } +} diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs new file mode 100644 index 00000000000..0919f149124 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs @@ -0,0 +1,274 @@ +#![cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem"))] +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; + +// test runner +extern crate utest_cortex_m_qemu; + +// overrides `panic!` +#[macro_use] +extern crate utest_macros; + +use core::mem; + +macro_rules! panic { + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} + +extern "C" { + fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); +} + +struct Aligned { + array: [u8; 8], + _alignment: [u32; 0], +} + +impl Aligned { + fn new(array: [u8; 8]) -> Self { + Aligned { + array: array, + _alignment: [], + } + } +} + +#[test] +fn zero() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), 0, c) + } + + assert_eq!(*xs, [0; 8]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), 0, c) + } + + assert_eq!(*xs, [1; 8]); +} + +#[test] +fn one() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 1; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0, 0, 0, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 1, 1, 1, 1, 1, 1, 1]); +} + +#[test] +fn two() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 2; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0, 0, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 1, 1, 1, 1, 1, 1]); +} + +#[test] +fn three() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 3; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 1, 1, 1, 1, 1]); +} + +#[test] +fn four() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 4; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 1, 1, 1, 1]); +} + +#[test] +fn five() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 5; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 1, 1, 1]); +} + +#[test] +fn six() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 6; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1, 1]); +} + +#[test] +fn seven() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 7; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1]); +} + +#[test] +fn eight() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 8; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); +} diff --git a/library/compiler-builtins/testcrate/tests/generated.rs b/library/compiler-builtins/testcrate/tests/generated.rs new file mode 100644 index 00000000000..1a43f436e0b --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/generated.rs @@ -0,0 +1,6 @@ +#![feature(i128_type)] +#![allow(bad_style)] + +extern crate compiler_builtins; + +include!(concat!(env!("OUT_DIR"), "/generated.rs")); diff --git a/library/compiler-builtins/tests/adddf3.rs b/library/compiler-builtins/tests/adddf3.rs deleted file mode 100644 index 3129330afaf..00000000000 --- a/library/compiler-builtins/tests/adddf3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/adddf3.rs")); diff --git a/library/compiler-builtins/tests/addsf3.rs b/library/compiler-builtins/tests/addsf3.rs deleted file mode 100644 index b5c9c3dfebd..00000000000 --- a/library/compiler-builtins/tests/addsf3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/addsf3.rs")); diff --git a/library/compiler-builtins/tests/aeabi_memclr.rs b/library/compiler-builtins/tests/aeabi_memclr.rs deleted file mode 100644 index 72e944e4c74..00000000000 --- a/library/compiler-builtins/tests/aeabi_memclr.rs +++ /dev/null @@ -1,58 +0,0 @@ -#![cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - feature = "mem"))] -#![feature(compiler_builtins_lib)] -#![no_std] - -extern crate compiler_builtins; - -// test runner -extern crate utest_cortex_m_qemu; - -// overrides `panic!` -#[macro_use] -extern crate utest_macros; - -use core::mem; - -macro_rules! panic { - ($($tt:tt)*) => { - upanic!($($tt)*); - }; -} - -extern "C" { - fn __aeabi_memclr4(dest: *mut u8, n: usize); - fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); -} - -struct Aligned { - array: [u8; 8], - _alignment: [u32; 0], -} - -impl Aligned { - fn new() -> Self { - Aligned { - array: [0; 8], - _alignment: [], - } - } -} - -#[test] -fn memclr4() { - let mut aligned = Aligned::new();; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - - for n in 0..9 { - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, 0xff); - __aeabi_memclr4(xs.as_mut_ptr(), n); - } - - assert!(xs[0..n].iter().all(|x| *x == 0)); - } -} diff --git a/library/compiler-builtins/tests/aeabi_memcpy.rs b/library/compiler-builtins/tests/aeabi_memcpy.rs deleted file mode 100644 index 2ba942c23c1..00000000000 --- a/library/compiler-builtins/tests/aeabi_memcpy.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - feature = "mem"))] -#![feature(compiler_builtins_lib)] -#![no_std] - -extern crate compiler_builtins; - -// test runner -extern crate utest_cortex_m_qemu; - -// overrides `panic!` -#[macro_use] -extern crate utest_macros; - -macro_rules! panic { - ($($tt:tt)*) => { - upanic!($($tt)*); - }; -} - -extern "C" { - fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize); - fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize); -} - -struct Aligned { - array: [u8; 8], - _alignment: [u32; 0], -} - -impl Aligned { - fn new(array: [u8; 8]) -> Self { - Aligned { - array: array, - _alignment: [], - } - } -} - -#[test] -fn memcpy() { - let mut dest = [0; 4]; - let src = [0xde, 0xad, 0xbe, 0xef]; - - for n in 0..dest.len() { - dest.copy_from_slice(&[0; 4]); - - unsafe { __aeabi_memcpy(dest.as_mut_ptr(), src.as_ptr(), n) } - - assert_eq!(&dest[0..n], &src[0..n]) - } -} - -#[test] -fn memcpy4() { - let mut aligned = Aligned::new([0; 8]); - let dest = &mut aligned.array; - let src = [0xde, 0xad, 0xbe, 0xef, 0xba, 0xad, 0xf0, 0x0d]; - - for n in 0..dest.len() { - dest.copy_from_slice(&[0; 8]); - - unsafe { __aeabi_memcpy4(dest.as_mut_ptr(), src.as_ptr(), n) } - - assert_eq!(&dest[0..n], &src[0..n]) - } -} diff --git a/library/compiler-builtins/tests/aeabi_memset.rs b/library/compiler-builtins/tests/aeabi_memset.rs deleted file mode 100644 index 0919f149124..00000000000 --- a/library/compiler-builtins/tests/aeabi_memset.rs +++ /dev/null @@ -1,274 +0,0 @@ -#![cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - feature = "mem"))] -#![feature(compiler_builtins_lib)] -#![no_std] - -extern crate compiler_builtins; - -// test runner -extern crate utest_cortex_m_qemu; - -// overrides `panic!` -#[macro_use] -extern crate utest_macros; - -use core::mem; - -macro_rules! panic { - ($($tt:tt)*) => { - upanic!($($tt)*); - }; -} - -extern "C" { - fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); -} - -struct Aligned { - array: [u8; 8], - _alignment: [u32; 0], -} - -impl Aligned { - fn new(array: [u8; 8]) -> Self { - Aligned { - array: array, - _alignment: [], - } - } -} - -#[test] -fn zero() { - let mut aligned = Aligned::new([0u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), 0, c) - } - - assert_eq!(*xs, [0; 8]); - - let mut aligned = Aligned::new([1u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), 0, c) - } - - assert_eq!(*xs, [1; 8]); -} - -#[test] -fn one() { - let mut aligned = Aligned::new([0u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 1; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0, 0, 0, 0, 0, 0, 0]); - - let mut aligned = Aligned::new([1u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 1, 1, 1, 1, 1, 1, 1]); -} - -#[test] -fn two() { - let mut aligned = Aligned::new([0u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 2; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0xef, 0, 0, 0, 0, 0, 0]); - - let mut aligned = Aligned::new([1u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0xef, 1, 1, 1, 1, 1, 1]); -} - -#[test] -fn three() { - let mut aligned = Aligned::new([0u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 3; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0, 0, 0, 0, 0]); - - let mut aligned = Aligned::new([1u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 1, 1, 1, 1, 1]); -} - -#[test] -fn four() { - let mut aligned = Aligned::new([0u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 4; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0, 0, 0, 0]); - - let mut aligned = Aligned::new([1u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 1, 1, 1, 1]); -} - -#[test] -fn five() { - let mut aligned = Aligned::new([0u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 5; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0, 0, 0]); - - let mut aligned = Aligned::new([1u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 1, 1, 1]); -} - -#[test] -fn six() { - let mut aligned = Aligned::new([0u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 6; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0, 0]); - - let mut aligned = Aligned::new([1u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1, 1]); -} - -#[test] -fn seven() { - let mut aligned = Aligned::new([0u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 7; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0]); - - let mut aligned = Aligned::new([1u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1]); -} - -#[test] -fn eight() { - let mut aligned = Aligned::new([0u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 8; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); - - let mut aligned = Aligned::new([1u8; 8]);; - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); -} diff --git a/library/compiler-builtins/tests/ashldi3.rs b/library/compiler-builtins/tests/ashldi3.rs deleted file mode 100644 index 1116375d3ef..00000000000 --- a/library/compiler-builtins/tests/ashldi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/ashldi3.rs")); diff --git a/library/compiler-builtins/tests/ashlti3.rs b/library/compiler-builtins/tests/ashlti3.rs deleted file mode 100644 index 4c799cf8822..00000000000 --- a/library/compiler-builtins/tests/ashlti3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/ashlti3.rs")); diff --git a/library/compiler-builtins/tests/ashrdi3.rs b/library/compiler-builtins/tests/ashrdi3.rs deleted file mode 100644 index a0a2b6cb13a..00000000000 --- a/library/compiler-builtins/tests/ashrdi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/ashrdi3.rs")); diff --git a/library/compiler-builtins/tests/ashrti3.rs b/library/compiler-builtins/tests/ashrti3.rs deleted file mode 100644 index b147051c2d9..00000000000 --- a/library/compiler-builtins/tests/ashrti3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/ashrti3.rs")); diff --git a/library/compiler-builtins/tests/divdf3.rs b/library/compiler-builtins/tests/divdf3.rs deleted file mode 100644 index 98d32d1b084..00000000000 --- a/library/compiler-builtins/tests/divdf3.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/divdf3.rs")); diff --git a/library/compiler-builtins/tests/divdf3vfp.rs b/library/compiler-builtins/tests/divdf3vfp.rs deleted file mode 100644 index 9225a5c30a1..00000000000 --- a/library/compiler-builtins/tests/divdf3vfp.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -#[cfg(target_arch = "arm")] -include!(concat!(env!("OUT_DIR"), "/divdf3vfp.rs")); diff --git a/library/compiler-builtins/tests/divdi3.rs b/library/compiler-builtins/tests/divdi3.rs deleted file mode 100644 index 4bdce54156e..00000000000 --- a/library/compiler-builtins/tests/divdi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/divdi3.rs")); diff --git a/library/compiler-builtins/tests/divmoddi4.rs b/library/compiler-builtins/tests/divmoddi4.rs deleted file mode 100644 index 9ddd85a829f..00000000000 --- a/library/compiler-builtins/tests/divmoddi4.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/divmoddi4.rs")); diff --git a/library/compiler-builtins/tests/divmodsi4.rs b/library/compiler-builtins/tests/divmodsi4.rs deleted file mode 100644 index 6fe80e97569..00000000000 --- a/library/compiler-builtins/tests/divmodsi4.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/divmodsi4.rs")); diff --git a/library/compiler-builtins/tests/divsf3.rs b/library/compiler-builtins/tests/divsf3.rs deleted file mode 100644 index 5cf3e86ca01..00000000000 --- a/library/compiler-builtins/tests/divsf3.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/divsf3.rs")); diff --git a/library/compiler-builtins/tests/divsf3vfp.rs b/library/compiler-builtins/tests/divsf3vfp.rs deleted file mode 100644 index 0ecc8fe0c8b..00000000000 --- a/library/compiler-builtins/tests/divsf3vfp.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -#[cfg(target_arch = "arm")] -include!(concat!(env!("OUT_DIR"), "/divsf3vfp.rs")); diff --git a/library/compiler-builtins/tests/divsi3.rs b/library/compiler-builtins/tests/divsi3.rs deleted file mode 100644 index e6440d782c7..00000000000 --- a/library/compiler-builtins/tests/divsi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/divsi3.rs")); diff --git a/library/compiler-builtins/tests/divti3.rs b/library/compiler-builtins/tests/divti3.rs deleted file mode 100644 index 7919f8fe396..00000000000 --- a/library/compiler-builtins/tests/divti3.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -// FIXME(#137) -#[cfg(not(target_arch = "mips"))] -include!(concat!(env!("OUT_DIR"), "/divti3.rs")); diff --git a/library/compiler-builtins/tests/fixdfdi.rs b/library/compiler-builtins/tests/fixdfdi.rs deleted file mode 100644 index b66477502bb..00000000000 --- a/library/compiler-builtins/tests/fixdfdi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixdfdi.rs")); diff --git a/library/compiler-builtins/tests/fixdfsi.rs b/library/compiler-builtins/tests/fixdfsi.rs deleted file mode 100644 index 2677eec747a..00000000000 --- a/library/compiler-builtins/tests/fixdfsi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixdfsi.rs")); diff --git a/library/compiler-builtins/tests/fixdfti.rs b/library/compiler-builtins/tests/fixdfti.rs deleted file mode 100644 index 5bae55e99f3..00000000000 --- a/library/compiler-builtins/tests/fixdfti.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixdfti.rs")); diff --git a/library/compiler-builtins/tests/fixsfdi.rs b/library/compiler-builtins/tests/fixsfdi.rs deleted file mode 100644 index e38952be593..00000000000 --- a/library/compiler-builtins/tests/fixsfdi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixsfdi.rs")); diff --git a/library/compiler-builtins/tests/fixsfsi.rs b/library/compiler-builtins/tests/fixsfsi.rs deleted file mode 100644 index 242b4c16940..00000000000 --- a/library/compiler-builtins/tests/fixsfsi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixsfsi.rs")); diff --git a/library/compiler-builtins/tests/fixsfti.rs b/library/compiler-builtins/tests/fixsfti.rs deleted file mode 100644 index 653157df26b..00000000000 --- a/library/compiler-builtins/tests/fixsfti.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixsfti.rs")); diff --git a/library/compiler-builtins/tests/fixunsdfdi.rs b/library/compiler-builtins/tests/fixunsdfdi.rs deleted file mode 100644 index 13b35ba4a17..00000000000 --- a/library/compiler-builtins/tests/fixunsdfdi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixunsdfdi.rs")); diff --git a/library/compiler-builtins/tests/fixunsdfsi.rs b/library/compiler-builtins/tests/fixunsdfsi.rs deleted file mode 100644 index 32faf360c30..00000000000 --- a/library/compiler-builtins/tests/fixunsdfsi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixunsdfsi.rs")); diff --git a/library/compiler-builtins/tests/fixunsdfti.rs b/library/compiler-builtins/tests/fixunsdfti.rs deleted file mode 100644 index 615e7b33b8d..00000000000 --- a/library/compiler-builtins/tests/fixunsdfti.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixunsdfti.rs")); diff --git a/library/compiler-builtins/tests/fixunssfdi.rs b/library/compiler-builtins/tests/fixunssfdi.rs deleted file mode 100644 index 24e6f6e3508..00000000000 --- a/library/compiler-builtins/tests/fixunssfdi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixunssfdi.rs")); diff --git a/library/compiler-builtins/tests/fixunssfsi.rs b/library/compiler-builtins/tests/fixunssfsi.rs deleted file mode 100644 index da02cd94578..00000000000 --- a/library/compiler-builtins/tests/fixunssfsi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixunssfsi.rs")); diff --git a/library/compiler-builtins/tests/fixunssfti.rs b/library/compiler-builtins/tests/fixunssfti.rs deleted file mode 100644 index d67f9e794e0..00000000000 --- a/library/compiler-builtins/tests/fixunssfti.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixunssfti.rs")); diff --git a/library/compiler-builtins/tests/floatdidf.rs b/library/compiler-builtins/tests/floatdidf.rs deleted file mode 100644 index 2b3dcb5928c..00000000000 --- a/library/compiler-builtins/tests/floatdidf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatdidf.rs")); diff --git a/library/compiler-builtins/tests/floatsidf.rs b/library/compiler-builtins/tests/floatsidf.rs deleted file mode 100644 index ffee7e27113..00000000000 --- a/library/compiler-builtins/tests/floatsidf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatsidf.rs")); diff --git a/library/compiler-builtins/tests/floatsisf.rs b/library/compiler-builtins/tests/floatsisf.rs deleted file mode 100644 index c03ab7f9dd5..00000000000 --- a/library/compiler-builtins/tests/floatsisf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatsisf.rs")); diff --git a/library/compiler-builtins/tests/floattidf.rs b/library/compiler-builtins/tests/floattidf.rs deleted file mode 100644 index c2e798a9963..00000000000 --- a/library/compiler-builtins/tests/floattidf.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] -#![cfg(not(target_arch = "mips"))] // FIXME(#168) - -include!(concat!(env!("OUT_DIR"), "/floattidf.rs")); diff --git a/library/compiler-builtins/tests/floattisf.rs b/library/compiler-builtins/tests/floattisf.rs deleted file mode 100644 index 2a0657d3d00..00000000000 --- a/library/compiler-builtins/tests/floattisf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floattisf.rs")); diff --git a/library/compiler-builtins/tests/floatundidf.rs b/library/compiler-builtins/tests/floatundidf.rs deleted file mode 100644 index 0b833851245..00000000000 --- a/library/compiler-builtins/tests/floatundidf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatundidf.rs")); diff --git a/library/compiler-builtins/tests/floatunsidf.rs b/library/compiler-builtins/tests/floatunsidf.rs deleted file mode 100644 index e25a69f5bea..00000000000 --- a/library/compiler-builtins/tests/floatunsidf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatunsidf.rs")); diff --git a/library/compiler-builtins/tests/floatunsisf.rs b/library/compiler-builtins/tests/floatunsisf.rs deleted file mode 100644 index c0b9fd8b0b9..00000000000 --- a/library/compiler-builtins/tests/floatunsisf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatunsisf.rs")); diff --git a/library/compiler-builtins/tests/floatuntidf.rs b/library/compiler-builtins/tests/floatuntidf.rs deleted file mode 100644 index 4ea272e97d1..00000000000 --- a/library/compiler-builtins/tests/floatuntidf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatuntidf.rs")); diff --git a/library/compiler-builtins/tests/floatuntisf.rs b/library/compiler-builtins/tests/floatuntisf.rs deleted file mode 100644 index 74cd853e49e..00000000000 --- a/library/compiler-builtins/tests/floatuntisf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatuntisf.rs")); diff --git a/library/compiler-builtins/tests/gedf2.rs b/library/compiler-builtins/tests/gedf2.rs deleted file mode 100644 index e1bea595395..00000000000 --- a/library/compiler-builtins/tests/gedf2.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/gedf2.rs")); diff --git a/library/compiler-builtins/tests/gesf2.rs b/library/compiler-builtins/tests/gesf2.rs deleted file mode 100644 index 760f5a8f5ad..00000000000 --- a/library/compiler-builtins/tests/gesf2.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/gesf2.rs")); diff --git a/library/compiler-builtins/tests/i128_add.rs b/library/compiler-builtins/tests/i128_add.rs deleted file mode 100644 index 13af0500cb8..00000000000 --- a/library/compiler-builtins/tests/i128_add.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/i128_add.rs")); diff --git a/library/compiler-builtins/tests/i128_addo.rs b/library/compiler-builtins/tests/i128_addo.rs deleted file mode 100644 index 306ffac169e..00000000000 --- a/library/compiler-builtins/tests/i128_addo.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/i128_addo.rs")); diff --git a/library/compiler-builtins/tests/i128_sub.rs b/library/compiler-builtins/tests/i128_sub.rs deleted file mode 100644 index 933fe4f5661..00000000000 --- a/library/compiler-builtins/tests/i128_sub.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/i128_sub.rs")); diff --git a/library/compiler-builtins/tests/i128_subo.rs b/library/compiler-builtins/tests/i128_subo.rs deleted file mode 100644 index 0c2b67cbbdc..00000000000 --- a/library/compiler-builtins/tests/i128_subo.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/i128_subo.rs")); diff --git a/library/compiler-builtins/tests/ledf2.rs b/library/compiler-builtins/tests/ledf2.rs deleted file mode 100644 index 3fac17b0f36..00000000000 --- a/library/compiler-builtins/tests/ledf2.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/ledf2.rs")); diff --git a/library/compiler-builtins/tests/lesf2.rs b/library/compiler-builtins/tests/lesf2.rs deleted file mode 100644 index 878861fec1c..00000000000 --- a/library/compiler-builtins/tests/lesf2.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/lesf2.rs")); diff --git a/library/compiler-builtins/tests/lshrdi3.rs b/library/compiler-builtins/tests/lshrdi3.rs deleted file mode 100644 index b1a2331b196..00000000000 --- a/library/compiler-builtins/tests/lshrdi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/lshrdi3.rs")); diff --git a/library/compiler-builtins/tests/lshrti3.rs b/library/compiler-builtins/tests/lshrti3.rs deleted file mode 100644 index 2ee32ce71f4..00000000000 --- a/library/compiler-builtins/tests/lshrti3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/lshrti3.rs")); diff --git a/library/compiler-builtins/tests/moddi3.rs b/library/compiler-builtins/tests/moddi3.rs deleted file mode 100644 index 6a58a77ab49..00000000000 --- a/library/compiler-builtins/tests/moddi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/moddi3.rs")); diff --git a/library/compiler-builtins/tests/modsi3.rs b/library/compiler-builtins/tests/modsi3.rs deleted file mode 100644 index 46ad8cd33cd..00000000000 --- a/library/compiler-builtins/tests/modsi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/modsi3.rs")); diff --git a/library/compiler-builtins/tests/modti3.rs b/library/compiler-builtins/tests/modti3.rs deleted file mode 100644 index 62129cd04d3..00000000000 --- a/library/compiler-builtins/tests/modti3.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -// FIXME(#137) -#[cfg(not(target_arch = "mips"))] -include!(concat!(env!("OUT_DIR"), "/modti3.rs")); diff --git a/library/compiler-builtins/tests/muldf3.rs b/library/compiler-builtins/tests/muldf3.rs deleted file mode 100644 index 82d06d8de36..00000000000 --- a/library/compiler-builtins/tests/muldf3.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/muldf3.rs")); diff --git a/library/compiler-builtins/tests/muldf3vfp.rs b/library/compiler-builtins/tests/muldf3vfp.rs deleted file mode 100644 index 8a717157fb0..00000000000 --- a/library/compiler-builtins/tests/muldf3vfp.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -#[cfg(target_arch = "arm")] -include!(concat!(env!("OUT_DIR"), "/muldf3vfp.rs")); diff --git a/library/compiler-builtins/tests/muldi3.rs b/library/compiler-builtins/tests/muldi3.rs deleted file mode 100644 index d771e8a6bde..00000000000 --- a/library/compiler-builtins/tests/muldi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/muldi3.rs")); diff --git a/library/compiler-builtins/tests/mulodi4.rs b/library/compiler-builtins/tests/mulodi4.rs deleted file mode 100644 index 071a295810f..00000000000 --- a/library/compiler-builtins/tests/mulodi4.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/mulodi4.rs")); diff --git a/library/compiler-builtins/tests/mulosi4.rs b/library/compiler-builtins/tests/mulosi4.rs deleted file mode 100644 index 3ec4336d118..00000000000 --- a/library/compiler-builtins/tests/mulosi4.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/mulosi4.rs")); diff --git a/library/compiler-builtins/tests/muloti4.rs b/library/compiler-builtins/tests/muloti4.rs deleted file mode 100644 index 358c57ec528..00000000000 --- a/library/compiler-builtins/tests/muloti4.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -// FIXME(#137) -#[cfg(not(target_arch = "mips"))] -include!(concat!(env!("OUT_DIR"), "/muloti4.rs")); diff --git a/library/compiler-builtins/tests/mulsf3.rs b/library/compiler-builtins/tests/mulsf3.rs deleted file mode 100644 index fe278d84be2..00000000000 --- a/library/compiler-builtins/tests/mulsf3.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/mulsf3.rs")); diff --git a/library/compiler-builtins/tests/mulsf3vfp.rs b/library/compiler-builtins/tests/mulsf3vfp.rs deleted file mode 100644 index 4d7f288970a..00000000000 --- a/library/compiler-builtins/tests/mulsf3vfp.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -#[cfg(target_arch = "arm")] -include!(concat!(env!("OUT_DIR"), "/mulsf3vfp.rs")); diff --git a/library/compiler-builtins/tests/multi3.rs b/library/compiler-builtins/tests/multi3.rs deleted file mode 100644 index db525387438..00000000000 --- a/library/compiler-builtins/tests/multi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/multi3.rs")); diff --git a/library/compiler-builtins/tests/powidf2.rs b/library/compiler-builtins/tests/powidf2.rs deleted file mode 100644 index dde5f03eb9c..00000000000 --- a/library/compiler-builtins/tests/powidf2.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/powidf2.rs")); diff --git a/library/compiler-builtins/tests/powisf2.rs b/library/compiler-builtins/tests/powisf2.rs deleted file mode 100644 index 3e0baeb73ce..00000000000 --- a/library/compiler-builtins/tests/powisf2.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/powisf2.rs")); diff --git a/library/compiler-builtins/tests/subdf3.rs b/library/compiler-builtins/tests/subdf3.rs deleted file mode 100644 index 13f695718e1..00000000000 --- a/library/compiler-builtins/tests/subdf3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/subdf3.rs")); diff --git a/library/compiler-builtins/tests/subsf3.rs b/library/compiler-builtins/tests/subsf3.rs deleted file mode 100644 index 7be426c4531..00000000000 --- a/library/compiler-builtins/tests/subsf3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/subsf3.rs")); diff --git a/library/compiler-builtins/tests/u128_add.rs b/library/compiler-builtins/tests/u128_add.rs deleted file mode 100644 index d4b8f2ccb24..00000000000 --- a/library/compiler-builtins/tests/u128_add.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/u128_add.rs")); diff --git a/library/compiler-builtins/tests/u128_addo.rs b/library/compiler-builtins/tests/u128_addo.rs deleted file mode 100644 index caff682e8a0..00000000000 --- a/library/compiler-builtins/tests/u128_addo.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/u128_addo.rs")); diff --git a/library/compiler-builtins/tests/u128_sub.rs b/library/compiler-builtins/tests/u128_sub.rs deleted file mode 100644 index 024266b9263..00000000000 --- a/library/compiler-builtins/tests/u128_sub.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/u128_sub.rs")); diff --git a/library/compiler-builtins/tests/u128_subo.rs b/library/compiler-builtins/tests/u128_subo.rs deleted file mode 100644 index b3fb4b854e2..00000000000 --- a/library/compiler-builtins/tests/u128_subo.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/u128_subo.rs")); diff --git a/library/compiler-builtins/tests/udivdi3.rs b/library/compiler-builtins/tests/udivdi3.rs deleted file mode 100644 index d87091c7d84..00000000000 --- a/library/compiler-builtins/tests/udivdi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/udivdi3.rs")); diff --git a/library/compiler-builtins/tests/udivmoddi4.rs b/library/compiler-builtins/tests/udivmoddi4.rs deleted file mode 100644 index a9444c10db3..00000000000 --- a/library/compiler-builtins/tests/udivmoddi4.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/udivmoddi4.rs")); diff --git a/library/compiler-builtins/tests/udivmodsi4.rs b/library/compiler-builtins/tests/udivmodsi4.rs deleted file mode 100644 index e93bfe1e552..00000000000 --- a/library/compiler-builtins/tests/udivmodsi4.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/udivmodsi4.rs")); diff --git a/library/compiler-builtins/tests/udivmodti4.rs b/library/compiler-builtins/tests/udivmodti4.rs deleted file mode 100644 index 8185ec0e789..00000000000 --- a/library/compiler-builtins/tests/udivmodti4.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -// FIXME(#137) -#[cfg(not(target_arch = "mips"))] -include!(concat!(env!("OUT_DIR"), "/udivmodti4.rs")); diff --git a/library/compiler-builtins/tests/udivsi3.rs b/library/compiler-builtins/tests/udivsi3.rs deleted file mode 100644 index d6433e7c31d..00000000000 --- a/library/compiler-builtins/tests/udivsi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/udivsi3.rs")); diff --git a/library/compiler-builtins/tests/udivti3.rs b/library/compiler-builtins/tests/udivti3.rs deleted file mode 100644 index cefddda8f86..00000000000 --- a/library/compiler-builtins/tests/udivti3.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -// FIXME(#137) -#[cfg(not(target_arch = "mips"))] -include!(concat!(env!("OUT_DIR"), "/udivti3.rs")); diff --git a/library/compiler-builtins/tests/umoddi3.rs b/library/compiler-builtins/tests/umoddi3.rs deleted file mode 100644 index 09a114ee6b9..00000000000 --- a/library/compiler-builtins/tests/umoddi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/umoddi3.rs")); diff --git a/library/compiler-builtins/tests/umodsi3.rs b/library/compiler-builtins/tests/umodsi3.rs deleted file mode 100644 index aa56e819c27..00000000000 --- a/library/compiler-builtins/tests/umodsi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/umodsi3.rs")); diff --git a/library/compiler-builtins/tests/umodti3.rs b/library/compiler-builtins/tests/umodti3.rs deleted file mode 100644 index 57e651b2710..00000000000 --- a/library/compiler-builtins/tests/umodti3.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -// FIXME(#137) -#[cfg(not(target_arch = "mips"))] -include!(concat!(env!("OUT_DIR"), "/umodti3.rs")); -- cgit 1.4.1-3-g733a5 From 07c82d220028bb89c9977e59fc0f0e26f2a517b0 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 4 Feb 2018 09:48:06 +0100 Subject: Fix __aeabi_fcmple and add test cases `le` in __aeabi_fcmple means `less or equal` --- library/compiler-builtins/src/float/cmp.rs | 2 +- library/compiler-builtins/testcrate/build.rs | 92 ++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index e3c584084ad..4986d056052 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -174,7 +174,7 @@ intrinsics! { #[cfg(target_arch = "arm")] intrinsics! { pub extern "aapcs" fn __aeabi_fcmple(a: f32, b: f32) -> i32 { - (__lesf2(a, b) < 0) as i32 + (__lesf2(a, b) <= 0) as i32 } pub extern "aapcs" fn __aeabi_fcmpge(a: f32, b: f32) -> i32 { diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 98a0934c0d9..a32dc741b35 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -121,6 +121,98 @@ fn main() { }, "compiler_builtins::float::cmp::__lesf2(a, b)"); + if target_arch_arm { + gen(|(a, b): (MyF32, MyF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 <= b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_fcmple(a, b)"); + + gen(|(a, b): (MyF32, MyF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 >= b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_fcmpge(a, b)"); + + gen(|(a, b): (MyF32, MyF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 == b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_fcmpeq(a, b)"); + + gen(|(a, b): (MyF32, MyF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 < b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_fcmplt(a, b)"); + + gen(|(a, b): (MyF32, MyF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 > b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_fcmpgt(a, b)"); + + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 <= b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_dcmple(a, b)"); + + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 >= b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_dcmpge(a, b)"); + + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 == b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_dcmpeq(a, b)"); + + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 < b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_dcmplt(a, b)"); + + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 > b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_dcmpgt(a, b)"); + } + // float/conv.rs gen(|a: MyF64| i64(a.0).ok(), "compiler_builtins::float::conv::__fixdfdi(a)"); -- cgit 1.4.1-3-g733a5 From 97e6b3712af601e9f6a450f2d9653e6315596208 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 4 Feb 2018 18:34:31 +0100 Subject: Add support for sub*f3vfp and add*f3vfp As done before for mul and div let's use extern "C" to generate `"aapcs"` or `"aapcs-vfp"` depending on target configuration. --- library/compiler-builtins/README.md | 8 +++--- library/compiler-builtins/build.rs | 4 --- library/compiler-builtins/src/float/add.rs | 10 +++++++ library/compiler-builtins/src/float/sub.rs | 10 +++++++ library/compiler-builtins/testcrate/build.rs | 43 ++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index cc4852a446a..97ef340f9e5 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -85,8 +85,8 @@ features = ["c"] - [x] adddf3.c - [x] addsf3.c -- [ ] arm/adddf3vfp.S -- [ ] arm/addsf3vfp.S +- [x] arm/adddf3vfp.S +- [x] arm/addsf3vfp.S - [ ] arm/aeabi_dcmp.S - [ ] arm/aeabi_fcmp.S - [x] arm/aeabi_idivmod.S @@ -127,8 +127,8 @@ features = ["c"] - [ ] arm/negsf2vfp.S - [ ] arm/nesf2vfp.S - [ ] arm/softfloat-alias.list -- [ ] arm/subdf3vfp.S -- [ ] arm/subsf3vfp.S +- [x] arm/subdf3vfp.S +- [x] arm/subsf3vfp.S - [ ] arm/truncdfsf2vfp.S - [ ] arm/udivmodsi4.S (generic version is done) - [ ] arm/udivsi3.S (generic version is done) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 8beb1288116..89a4a83e424 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -375,8 +375,6 @@ mod c { if !llvm_target[0].starts_with("thumbv7em") { sources.extend( &[ - "arm/adddf3vfp.S", - "arm/addsf3vfp.S", "arm/eqdf2vfp.S", "arm/eqsf2vfp.S", "arm/extendsfdf2vfp.S", @@ -400,8 +398,6 @@ mod c { "arm/nesf2vfp.S", "arm/restore_vfp_d8_d15_regs.S", "arm/save_vfp_d8_d15_regs.S", - "arm/subdf3vfp.S", - "arm/subsf3vfp.S", ], ); } diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index d355cb1ff27..2b6ada81ddc 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -193,4 +193,14 @@ intrinsics! { pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 { add(a, b) } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __addsf3vfp(a: f32, b: f32) -> f32 { + a + b + } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __adddf3vfp(a: f64, b: f64) -> f64 { + a + b + } } diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index ed7dd2c0aaa..c2791bf9291 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -10,4 +10,14 @@ intrinsics! { pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { a + f64::from_repr(b.repr() ^ f64::SIGN_MASK) } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __subsf3vfp(a: f32, b: f32) -> f32 { + a - b + } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __subdf3vfp(a: f64, b: f64) -> f64 { + a - b + } } diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index a32dc741b35..a300e280360 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -51,6 +51,28 @@ fn main() { }, "compiler_builtins::float::add::__addsf3(a, b)"); + if target_arch_arm { + gen(|(a, b): (MyF64, MyF64)| { + let c = a.0 + b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::add::__adddf3vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + let c = a.0 + b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::add::__addsf3vfp(a, b)"); + } + + // float/cmp.rs gen(|(a, b): (MyF64, MyF64)| { let (a, b) = (a.0, b.0); @@ -301,6 +323,27 @@ fn main() { }, "compiler_builtins::float::sub::__subsf3(a, b)"); + if target_arch_arm { + gen(|(a, b): (MyF64, MyF64)| { + let c = a.0 - b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::sub::__subdf3vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + let c = a.0 - b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::sub::__subsf3vfp(a, b)"); + } + // float/mul.rs gen(|(a, b): (MyF64, MyF64)| { let c = a.0 * b.0; -- cgit 1.4.1-3-g733a5 From 0af69177f94b6e34c9e05b2e4543566f295a4d6d Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Thu, 8 Feb 2018 18:20:45 +0100 Subject: Add generic conversion from a narrower to a wider FP type Add `extend` module to implement conversion from a narrower to a wider floating-point type. This implementation is only intended to support *widening* operations. Module to convert a *narrower* floating-point will be added in the future. --- library/compiler-builtins/README.md | 2 +- library/compiler-builtins/build.rs | 1 - library/compiler-builtins/src/float/extend.rs | 77 +++++++++++++++++++++++++++ library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/testcrate/build.rs | 9 ++++ 5 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/src/float/extend.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 97ef340f9e5..30abd928e02 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -146,7 +146,7 @@ features = ["c"] - [x] divsf3.c - [x] divsi3.c - [ ] extendhfsf2.c -- [ ] extendsfdf2.c +- [x] extendsfdf2.c - [x] fixdfdi.c - [x] fixdfsi.c - [x] fixsfdi.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 89a4a83e424..0d32e976258 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -171,7 +171,6 @@ mod c { "divdc3.c", "divsc3.c", "divxc3.c", - "extendsfdf2.c", "extendhfsf2.c", "floatdisf.c", "floatundisf.c", diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs new file mode 100644 index 00000000000..1abb23c3f92 --- /dev/null +++ b/library/compiler-builtins/src/float/extend.rs @@ -0,0 +1,77 @@ +use int::{CastInto, Int}; +use float::Float; + +/// Generic conversion from a narrower to a wider IEEE-754 floating-point type +fn extend(a: F) -> R where + F::Int: CastInto, + u64: CastInto, + u32: CastInto, + R::Int: CastInto, + R::Int: CastInto, + u64: CastInto, + F::Int: CastInto, +{ + let src_zero = F::Int::ZERO; + let src_one = F::Int::ONE; + let src_bits = F::BITS; + let src_sign_bits = F::SIGNIFICAND_BITS; + let src_exp_bias = F::EXPONENT_BIAS; + let src_min_normal = F::IMPLICIT_BIT; + let src_infinity = F::EXPONENT_MASK; + let src_sign_mask = F::SIGN_MASK as F::Int; + let src_abs_mask = src_sign_mask - src_one; + let src_qnan = F::SIGNIFICAND_MASK; + let src_nan_code = src_qnan - src_one; + + let dst_bits = R::BITS; + let dst_sign_bits = R::SIGNIFICAND_BITS; + let dst_inf_exp = R::EXPONENT_MAX; + let dst_exp_bias = R::EXPONENT_BIAS; + let dst_min_normal = R::IMPLICIT_BIT; + + let sign_bits_delta = dst_sign_bits - src_sign_bits; + let exp_bias_delta = dst_exp_bias - src_exp_bias; + let a_abs = a.repr() & src_abs_mask; + let mut abs_result = R::Int::ZERO; + + if a_abs.wrapping_sub(src_min_normal) < src_infinity.wrapping_sub(src_min_normal) { + // a is a normal number. + // Extend to the destination type by shifting the significand and + // exponent into the proper position and rebiasing the exponent. + let abs_dst: R::Int = a_abs.cast(); + let bias_dst: R::Int = exp_bias_delta.cast(); + abs_result = abs_dst.wrapping_shl(sign_bits_delta); + abs_result |= bias_dst.wrapping_shl(dst_sign_bits); + } else if a_abs >= src_infinity { + // a is NaN or infinity. + // Conjure the result by beginning with infinity, then setting the qNaN + // bit (if needed) and right-aligning the rest of the trailing NaN + // payload field. + let qnan_dst: R::Int = (a_abs & src_qnan).cast(); + let nan_code_dst: R::Int = (a_abs & src_nan_code).cast(); + let inf_exp_dst: R::Int = dst_inf_exp.cast(); + abs_result = inf_exp_dst.wrapping_shl(dst_sign_bits); + abs_result |= qnan_dst.wrapping_shl(sign_bits_delta); + abs_result |= nan_code_dst.wrapping_shl(sign_bits_delta); + } else if a_abs != src_zero { + // a is denormal. + // Renormalize the significand and clear the leading bit, then insert + // the correct adjusted exponent in the destination type. + let scale = a_abs.leading_zeros() - src_min_normal.leading_zeros(); + let abs_dst: R::Int = a_abs.cast(); + let bias_dst: R::Int = (exp_bias_delta - scale + 1).cast(); + abs_result = abs_dst.wrapping_shl(sign_bits_delta + scale); + abs_result = (abs_result ^ dst_min_normal) | (bias_dst.wrapping_shl(dst_sign_bits)); + } + + let sign_result: R::Int = (a.repr() & src_sign_mask).cast(); + R::from_repr(abs_result | (sign_result.wrapping_shl(dst_bits - src_bits))) +} + +intrinsics! { + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_f2d] + pub extern "C" fn __extendsfdf2(a: f32) -> f64 { + extend(a) + } +} \ No newline at end of file diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 51ed6674d1d..3bb13abbc5c 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -10,6 +10,7 @@ pub mod pow; pub mod sub; pub mod mul; pub mod div; +pub mod extend; /// Trait for some basic operations on floats pub trait Float: diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index a300e280360..9269983c7b7 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -235,6 +235,15 @@ fn main() { "compiler_builtins::float::cmp::__aeabi_dcmpgt(a, b)"); } + // float/extend.rs + gen(|a: MyF32| { + if a.0.is_nan() { + return None; + } + Some(f64(a.0)) + }, + "compiler_builtins::float::extend::__extendsfdf2(a)"); + // float/conv.rs gen(|a: MyF64| i64(a.0).ok(), "compiler_builtins::float::conv::__fixdfdi(a)"); -- cgit 1.4.1-3-g733a5 From 178b78b92491b723ae3914e62674118ad756762e Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Fri, 9 Feb 2018 17:13:45 +0100 Subject: Fix issue extending f32::MIN/MAX to f64 and improve testcrate. I was able to trigger an issue extending f32::MAX or f32::MIN to a f64. Issue was not triggered by `testcrate` mainly because f32::MAX/MIN are not in the list of special values to generate. This PR fix the issue and improve `testcrate` adding MAX/MIN/MIN_POSITIVE in the list of special values. --- library/compiler-builtins/src/float/extend.rs | 2 +- library/compiler-builtins/testcrate/build.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 1abb23c3f92..a71b7a12c8a 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -41,7 +41,7 @@ fn extend(a: F) -> R where let abs_dst: R::Int = a_abs.cast(); let bias_dst: R::Int = exp_bias_delta.cast(); abs_result = abs_dst.wrapping_shl(sign_bits_delta); - abs_result |= bias_dst.wrapping_shl(dst_sign_bits); + abs_result += bias_dst.wrapping_shl(dst_sign_bits); } else if a_abs >= src_infinity { // a is NaN or infinity. // Conjure the result by beginning with infinity, then setting the qNaN diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 9269983c7b7..40cc1db350c 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -703,6 +703,9 @@ macro_rules! gen_float { // Special values *rng.choose(&[-0.0, 0.0, + ::std::$fty::MIN, + ::std::$fty::MIN_POSITIVE, + ::std::$fty::MAX, ::std::$fty::NAN, ::std::$fty::INFINITY, -::std::$fty::INFINITY]) @@ -754,6 +757,9 @@ macro_rules! gen_large_float { // Special values *rng.choose(&[-0.0, 0.0, + ::std::$fty::MIN, + ::std::$fty::MIN_POSITIVE, + ::std::$fty::MAX, ::std::$fty::NAN, ::std::$fty::INFINITY, -::std::$fty::INFINITY]) -- cgit 1.4.1-3-g733a5 From f70ccac08e4229480bc2c55bdfef8dd632fa0d7d Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Fri, 9 Feb 2018 20:35:55 +0100 Subject: Fix __subsf3 and __subdf3 on x86 Be sure to do not mix hard-float and soft-float calls. Disassembled code show exactly this. So replace add with an explicit call to __addsf3/__adddf3 This seems the root cause of some sporadic failures. --- library/compiler-builtins/src/float/sub.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index c2791bf9291..2afb1409b32 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -1,14 +1,16 @@ use float::Float; +use float::add::__addsf3; +use float::add::__adddf3; intrinsics! { #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { - a + f32::from_repr(b.repr() ^ f32::SIGN_MASK) + __addsf3(a, f32::from_repr(b.repr() ^ f32::SIGN_MASK)) } #[arm_aeabi_alias = __aeabi_dsub] pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { - a + f64::from_repr(b.repr() ^ f64::SIGN_MASK) + __adddf3(a, f64::from_repr(b.repr() ^ f64::SIGN_MASK)) } #[cfg(target_arch = "arm")] -- cgit 1.4.1-3-g733a5 From 4e1ff92946650486828250957fc27a56780036c3 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 11 Feb 2018 21:17:42 +0100 Subject: Set -mfloat-abi=hard not only for thumb targets --- library/compiler-builtins/build.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0d32e976258..6a057270e5c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -103,7 +103,9 @@ mod c { let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); - + let target_arch_arm = + target_arch.contains("arm") || + target_arch.contains("thumb"); let cfg = &mut cc::Build::new(); cfg.warnings(false); @@ -137,10 +139,10 @@ mod c { // the implementation is not valid for the arch, then gcc will error when compiling it. if llvm_target[0].starts_with("thumb") { cfg.flag("-mthumb"); + } - if llvm_target.last() == Some(&"eabihf") { - cfg.flag("-mfloat-abi=hard"); - } + if target_arch_arm && llvm_target.last() == Some(&"eabihf") { + cfg.flag("-mfloat-abi=hard"); } if llvm_target[0] == "thumbv6m" { -- cgit 1.4.1-3-g733a5 From b2aea631feb69ca6cbff38d6dc6fea9801d78bcd Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 11 Feb 2018 23:46:56 +0100 Subject: Collection of VFP intrinsics Nothing really exciting here. LLVM on hard-float target use native instructions for all listed VFP intrinsics and so resulting implementation is really trivial. Implemented intrinsics: __gesf2vfp __gedf2vfp __gtsf2vfp __gtdf2vfp __ltsf2vfp __ltdf2vfp __nesf2vfp __nedf2vfp __eqsf2vfp __eqdf2vfp __extendsfdf2vfp --- library/compiler-builtins/README.md | 24 ++++---- library/compiler-builtins/build.rs | 11 ---- library/compiler-builtins/src/float/cmp.rs | 43 ++++++++++++++ library/compiler-builtins/src/float/extend.rs | 5 ++ library/compiler-builtins/testcrate/build.rs | 80 +++++++++++++++++++++++++++ 5 files changed, 140 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 30abd928e02..8d59594e06e 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -100,9 +100,9 @@ features = ["c"] - [ ] arm/divmodsi4.S (generic version is done) - [x] arm/divsf3vfp.S - [ ] arm/divsi3.S (generic version is done) -- [ ] arm/eqdf2vfp.S -- [ ] arm/eqsf2vfp.S -- [ ] arm/extendsfdf2vfp.S +- [x] arm/eqdf2vfp.S +- [x] arm/eqsf2vfp.S +- [x] arm/extendsfdf2vfp.S - [ ] arm/fixdfsivfp.S - [ ] arm/fixsfsivfp.S - [ ] arm/fixunsdfsivfp.S @@ -111,22 +111,22 @@ features = ["c"] - [ ] arm/floatsisfvfp.S - [ ] arm/floatunssidfvfp.S - [ ] arm/floatunssisfvfp.S -- [ ] arm/gedf2vfp.S -- [ ] arm/gesf2vfp.S -- [ ] arm/gtdf2vfp.S -- [ ] arm/gtsf2vfp.S +- [x] arm/gedf2vfp.S +- [x] arm/gesf2vfp.S +- [x] arm/gtdf2vfp.S +- [x] arm/gtsf2vfp.S - [ ] arm/ledf2vfp.S - [ ] arm/lesf2vfp.S -- [ ] arm/ltdf2vfp.S -- [ ] arm/ltsf2vfp.S +- [x] arm/ltdf2vfp.S +- [x] arm/ltsf2vfp.S - [ ] arm/modsi3.S (generic version is done) - [x] arm/muldf3vfp.S - [x] arm/mulsf3vfp.S -- [ ] arm/nedf2vfp.S +- [x] arm/nedf2vfp.S - [ ] arm/negdf2vfp.S - [ ] arm/negsf2vfp.S -- [ ] arm/nesf2vfp.S -- [ ] arm/softfloat-alias.list +- [x] arm/nesf2vfp.S +- [x] arm/softfloat-alias.list - [x] arm/subdf3vfp.S - [x] arm/subsf3vfp.S - [ ] arm/truncdfsf2vfp.S diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6a057270e5c..594afbded81 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -376,9 +376,6 @@ mod c { if !llvm_target[0].starts_with("thumbv7em") { sources.extend( &[ - "arm/eqdf2vfp.S", - "arm/eqsf2vfp.S", - "arm/extendsfdf2vfp.S", "arm/fixdfsivfp.S", "arm/fixsfsivfp.S", "arm/fixunsdfsivfp.S", @@ -387,16 +384,8 @@ mod c { "arm/floatsisfvfp.S", "arm/floatunssidfvfp.S", "arm/floatunssisfvfp.S", - "arm/gedf2vfp.S", - "arm/gesf2vfp.S", - "arm/gtdf2vfp.S", - "arm/gtsf2vfp.S", "arm/ledf2vfp.S", "arm/lesf2vfp.S", - "arm/ltdf2vfp.S", - "arm/ltsf2vfp.S", - "arm/nedf2vfp.S", - "arm/nesf2vfp.S", "arm/restore_vfp_d8_d15_regs.S", "arm/save_vfp_d8_d15_regs.S", ], diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 4986d056052..16b059e157d 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -212,4 +212,47 @@ intrinsics! { pub extern "aapcs" fn __aeabi_dcmpgt(a: f64, b: f64) -> i32 { (__gtdf2(a, b) > 0) as i32 } + + // On hard-float targets LLVM will use native instructions + // for all VFP intrinsics below + + pub extern "C" fn __gesf2vfp(a: f32, b: f32) -> i32 { + (a >= b) as i32 + } + + pub extern "C" fn __gedf2vfp(a: f64, b: f64) -> i32 { + (a >= b) as i32 + } + + pub extern "C" fn __gtsf2vfp(a: f32, b: f32) -> i32 { + (a > b) as i32 + } + + pub extern "C" fn __gtdf2vfp(a: f64, b: f64) -> i32 { + (a > b) as i32 + } + + pub extern "C" fn __ltsf2vfp(a: f32, b: f32) -> i32 { + (a < b) as i32 + } + + pub extern "C" fn __ltdf2vfp(a: f64, b: f64) -> i32 { + (a < b) as i32 + } + + pub extern "C" fn __nesf2vfp(a: f32, b: f32) -> i32 { + (a != b) as i32 + } + + pub extern "C" fn __nedf2vfp(a: f64, b: f64) -> i32 { + (a != b) as i32 + } + + pub extern "C" fn __eqsf2vfp(a: f32, b: f32) -> i32 { + (a == b) as i32 + } + + pub extern "C" fn __eqdf2vfp(a: f64, b: f64) -> i32 { + (a == b) as i32 + } } diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index a71b7a12c8a..0ca9cf57a58 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -74,4 +74,9 @@ intrinsics! { pub extern "C" fn __extendsfdf2(a: f32) -> f64 { extend(a) } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __extendsfdf2vfp(a: f32) -> f64 { + a as f64 // LLVM generate 'fcvtds' + } } \ No newline at end of file diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 40cc1db350c..d3850cc5cb5 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -233,6 +233,77 @@ fn main() { Some(c) }, "compiler_builtins::float::cmp::__aeabi_dcmpgt(a, b)"); + + gen(|(a, b): (LargeF32, LargeF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 >= b.0) as i32) + }, + "compiler_builtins::float::cmp::__gesf2vfp(a, b)"); + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 >= b.0) as i32) + }, + "compiler_builtins::float::cmp::__gedf2vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 > b.0) as i32) + }, + "compiler_builtins::float::cmp::__gtsf2vfp(a, b)"); + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 > b.0) as i32) + }, + "compiler_builtins::float::cmp::__gtdf2vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 < b.0) as i32) + }, + "compiler_builtins::float::cmp::__ltsf2vfp(a, b)"); + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 < b.0) as i32) + }, + "compiler_builtins::float::cmp::__ltdf2vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 != b.0) as i32) + }, + "compiler_builtins::float::cmp::__nesf2vfp(a, b)"); + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 != b.0) as i32) + }, + "compiler_builtins::float::cmp::__nedf2vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 == b.0) as i32) + }, + "compiler_builtins::float::cmp::__eqsf2vfp(a, b)"); + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 == b.0) as i32) + }, + "compiler_builtins::float::cmp::__eqdf2vfp(a, b)"); } // float/extend.rs @@ -243,6 +314,15 @@ fn main() { Some(f64(a.0)) }, "compiler_builtins::float::extend::__extendsfdf2(a)"); + if target_arch_arm { + gen(|a: LargeF32| { + if a.0.is_nan() { + return None; + } + Some(f64(a.0)) + }, + "compiler_builtins::float::extend::__extendsfdf2vfp(a)"); + } // float/conv.rs gen(|a: MyF64| i64(a.0).ok(), -- cgit 1.4.1-3-g733a5 From 347871f7ecbf2b4ad3101d3292c43e4174dcd460 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Mon, 12 Feb 2018 18:23:55 +0100 Subject: Update Progress list Already implemented, but not marked as done. --- library/compiler-builtins/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 8d59594e06e..823877b8f5d 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -87,8 +87,8 @@ features = ["c"] - [x] addsf3.c - [x] arm/adddf3vfp.S - [x] arm/addsf3vfp.S -- [ ] arm/aeabi_dcmp.S -- [ ] arm/aeabi_fcmp.S +- [x] arm/aeabi_dcmp.S +- [x] arm/aeabi_fcmp.S - [x] arm/aeabi_idivmod.S - [x] arm/aeabi_ldivmod.S - [x] arm/aeabi_memcpy.S @@ -183,8 +183,8 @@ features = ["c"] - [x] mulsf3.c - [x] powidf2.c - [x] powisf2.c -- [ ] subdf3.c -- [ ] subsf3.c +- [x] subdf3.c +- [x] subsf3.c - [ ] truncdfhf2.c - [ ] truncdfsf2.c - [ ] truncsfhf2.c -- cgit 1.4.1-3-g733a5 From 63b78c86d93484a3721c53faf9bd60311063b64f Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Fri, 16 Feb 2018 17:31:25 +0100 Subject: Fix thumbv6m build (feature=c) 1. Avoid undefined references as: undefined reference to `__modsi3' undefined reference to `__umodsi3' 2. We can't remove assembly implementations that are not in the list --- library/compiler-builtins/build.rs | 5 ----- library/compiler-builtins/src/int/sdiv.rs | 7 +++++-- library/compiler-builtins/src/int/udiv.rs | 4 +++- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 594afbded81..9eca26c1dd9 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -423,13 +423,8 @@ mod c { if llvm_target[0] == "thumbv6m" { sources.remove( &[ - "aeabi_cdcmp", - "aeabi_cfcmp", - "aeabi_dcmp", - "aeabi_fcmp", "clzdi2", "clzsi2", - "comparesf2", "divmodsi4", "modsi3", "switch16", diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 2f09bd51d91..2de73b0eab7 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -72,7 +72,9 @@ intrinsics! { a.div(b) } - #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios")))] + #[use_c_shim_if(all(target_arch = "arm", + not(target_os = "ios")), + not(thumbv6m))] pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { a.mod_(b) } @@ -87,7 +89,8 @@ intrinsics! { a.mod_(b) } - #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios")))] + #[use_c_shim_if(all(target_arch = "arm", + not(target_os = "ios"), not(thumbv6m)))] pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { a.divmod(b, rem, |a, b| __divsi3(a, b)) } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 1d93e177b5b..4382460e782 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -209,7 +209,9 @@ intrinsics! { (q << 1) | carry } - #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios")))] + #[use_c_shim_if(all(target_arch = "arm", + not(target_os = "ios"), + not(thumbv6m)))] /// Returns `n % d` pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { let q = __udivsi3(n, d); -- cgit 1.4.1-3-g733a5 From 64ea229988b28445007e7c15a0d4ebcbbdb4024a Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 18 Feb 2018 18:15:57 +0100 Subject: Fix CI for thumb* targets Main fix is inside 'utest' all the rest are minor fixes due to the new 'testcrate'. Still allow failures on TravisCI for a while. --- library/compiler-builtins/ci/run.sh | 29 +++++++++++----------- library/compiler-builtins/testcrate/Cargo.toml | 11 +++++--- library/compiler-builtins/testcrate/src/lib.rs | 2 ++ .../testcrate/tests/aeabi_memclr.rs | 1 + .../testcrate/tests/aeabi_memcpy.rs | 1 + .../testcrate/tests/aeabi_memset.rs | 1 + .../compiler-builtins/testcrate/tests/generated.rs | 29 ++++++++++++++++++++++ 7 files changed, 56 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index bc40e2d603c..3196400f153 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -24,29 +24,30 @@ fi # Test our implementation case $1 in thumb*) - for t in $(ls tests); do + run="xargo test --manifest-path testcrate/Cargo.toml --target $1" + for t in $(ls testcrate/tests); do t=${t%.rs} - # TODO(#154) enable these tests when aeabi_*mul are implemented - case $t in - powi*f2) - continue - ;; - esac - - xargo test --test $t --target $1 --features 'mem gen-tests' --no-run + RUSTFLAGS="-C debug-assertions=no -C lto" \ + CARGO_INCREMENTAL=0 \ + $run --test $t --features 'no_std mem c' --no-run qemu-arm-static target/${1}/debug/$t-* + done - xargo test --test $t --target $1 --features 'mem gen-tests' --no-run --release + for t in $(ls testcrate/tests); do + t=${t%.rs} + RUSTFLAGS="-C lto" \ + CARGO_INCREMENTAL=0 \ + $run --test $t --features 'no_std mem c' --no-run --release qemu-arm-static target/${1}/release/$t-* done ;; *) run="cargo test --manifest-path testcrate/Cargo.toml --target $1" - $run - $run --release - $run --features c - $run --features c --release + $run --features mangled-names + $run --features mangled-names --release + $run --features 'mangled-names c' + $run --features 'mangled-names c' --release ;; esac diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 834df68775b..d88acda365d 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -14,12 +14,15 @@ rand = { version = "0.4", features = ["i128_support"] } [dependencies.compiler_builtins] path = ".." default-features = false -features = ["mangled-names", "no-lang-items"] +features = ["no-lang-items"] [target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] -test = { git = "https://github.com/japaric/utest" } -utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japaric/utest" } -utest-macros = { git = "https://github.com/japaric/utest" } +test = { git = "https://github.com/paoloteti/utest", branch = "ci" } +utest-cortex-m-qemu = { default-features = false, git = "https://github.com/paoloteti/utest", branch = "ci" } +utest-macros = { git = "https://github.com/paoloteti/utest", branch = "ci" } [features] c = ["compiler_builtins/c"] +mem = ["compiler_builtins/mem"] +mangled-names = ["compiler_builtins/mangled-names"] +no_std = [] diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 31e1bb209f9..ae9e4e2f5c5 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(feature = "no_std", no_std)] + #[cfg(test)] mod tests { #[test] diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs index 72e944e4c74..08fbd4fa9f2 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs @@ -3,6 +3,7 @@ target_os = "linux", feature = "mem"))] #![feature(compiler_builtins_lib)] +#![feature(lang_items)] #![no_std] extern crate compiler_builtins; diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs index 2ba942c23c1..76dad899263 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs @@ -3,6 +3,7 @@ target_os = "linux", feature = "mem"))] #![feature(compiler_builtins_lib)] +#![feature(lang_items)] #![no_std] extern crate compiler_builtins; diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs index 0919f149124..71fe37e3582 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs @@ -3,6 +3,7 @@ target_os = "linux", feature = "mem"))] #![feature(compiler_builtins_lib)] +#![feature(lang_items)] #![no_std] extern crate compiler_builtins; diff --git a/library/compiler-builtins/testcrate/tests/generated.rs b/library/compiler-builtins/testcrate/tests/generated.rs index 1a43f436e0b..1263dc261d6 100644 --- a/library/compiler-builtins/testcrate/tests/generated.rs +++ b/library/compiler-builtins/testcrate/tests/generated.rs @@ -1,6 +1,35 @@ +#![feature(compiler_builtins_lib)] #![feature(i128_type)] +#![feature(lang_items, core_float, core_float_bits)] #![allow(bad_style)] +#![allow(unused_imports)] +#![no_std] + +use core::num::Float; extern crate compiler_builtins; +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +extern crate utest_cortex_m_qemu; + +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +#[macro_use] +extern crate utest_macros; + +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +macro_rules! panic { // overrides `panic!` + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} + include!(concat!(env!("OUT_DIR"), "/generated.rs")); -- cgit 1.4.1-3-g733a5 From e319f042fd12e536db438f15d85f49ceeee3ffbe Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sat, 24 Feb 2018 22:48:27 +0100 Subject: Use upstream for utest Fix has been merged into upstream. --- library/compiler-builtins/testcrate/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index d88acda365d..7544d94fe3d 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -17,9 +17,9 @@ default-features = false features = ["no-lang-items"] [target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] -test = { git = "https://github.com/paoloteti/utest", branch = "ci" } -utest-cortex-m-qemu = { default-features = false, git = "https://github.com/paoloteti/utest", branch = "ci" } -utest-macros = { git = "https://github.com/paoloteti/utest", branch = "ci" } +test = { git = "https://github.com/japaric/utest" } +utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japaric/utest" } +utest-macros = { git = "https://github.com/japaric/utest" } [features] c = ["compiler_builtins/c"] -- cgit 1.4.1-3-g733a5 From ef48c1984b78a2b65c593d6fca20dcc77615c454 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 25 Feb 2018 00:22:39 +0100 Subject: testcrate/lib.rs: use #![no_std] unconditionally --- library/compiler-builtins/testcrate/src/lib.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index ae9e4e2f5c5..2e7f0d4d752 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -1,9 +1 @@ -#![cfg_attr(feature = "no_std", no_std)] - -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} +#![no_std] \ No newline at end of file -- cgit 1.4.1-3-g733a5 From 81356ccde422207be4921bc72fc5cd5f61bec5ec Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 25 Feb 2018 01:11:49 +0100 Subject: Keep mangled-names as a default feature --- library/compiler-builtins/ci/run.sh | 14 ++++++++------ library/compiler-builtins/testcrate/Cargo.toml | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 3196400f153..8ce706c2815 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -30,7 +30,8 @@ case $1 in RUSTFLAGS="-C debug-assertions=no -C lto" \ CARGO_INCREMENTAL=0 \ - $run --test $t --features 'no_std mem c' --no-run + $run --test $t --no-default-features \ + --features 'no_std mem c' --no-run qemu-arm-static target/${1}/debug/$t-* done @@ -38,16 +39,17 @@ case $1 in t=${t%.rs} RUSTFLAGS="-C lto" \ CARGO_INCREMENTAL=0 \ - $run --test $t --features 'no_std mem c' --no-run --release + $run --test $t --no-default-features \ + --features 'no_std mem c' --no-run --release qemu-arm-static target/${1}/release/$t-* done ;; *) run="cargo test --manifest-path testcrate/Cargo.toml --target $1" - $run --features mangled-names - $run --features mangled-names --release - $run --features 'mangled-names c' - $run --features 'mangled-names c' --release + $run + $run --release + $run --features c + $run --features c --release ;; esac diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 7544d94fe3d..eae66ce2e19 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -25,4 +25,5 @@ utest-macros = { git = "https://github.com/japaric/utest" } c = ["compiler_builtins/c"] mem = ["compiler_builtins/mem"] mangled-names = ["compiler_builtins/mangled-names"] +default = ["mangled-names"] no_std = [] -- cgit 1.4.1-3-g733a5 From d7799358e41ad35be3b9708e36dc7f047808a059 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 25 Feb 2018 09:19:34 +0100 Subject: Remove no_std features Everything default unconditionally to #![no_std]. --- library/compiler-builtins/ci/run.sh | 6 ++---- library/compiler-builtins/testcrate/Cargo.toml | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 8ce706c2815..8c85038f97a 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -30,8 +30,7 @@ case $1 in RUSTFLAGS="-C debug-assertions=no -C lto" \ CARGO_INCREMENTAL=0 \ - $run --test $t --no-default-features \ - --features 'no_std mem c' --no-run + $run --test $t --no-default-features --features 'mem c' --no-run qemu-arm-static target/${1}/debug/$t-* done @@ -39,8 +38,7 @@ case $1 in t=${t%.rs} RUSTFLAGS="-C lto" \ CARGO_INCREMENTAL=0 \ - $run --test $t --no-default-features \ - --features 'no_std mem c' --no-run --release + $run --test $t --no-default-features --features 'mem c' --no-run --release qemu-arm-static target/${1}/release/$t-* done ;; diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index eae66ce2e19..2a102660b2f 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -26,4 +26,3 @@ c = ["compiler_builtins/c"] mem = ["compiler_builtins/mem"] mangled-names = ["compiler_builtins/mangled-names"] default = ["mangled-names"] -no_std = [] -- cgit 1.4.1-3-g733a5 From 20de84d127eeb07fa4bae34960dcaa35a6124aac Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 25 Feb 2018 17:50:56 +0100 Subject: Add __ledf2vfp and __lesf2vfp Now that `73884ae` is in some nightly release We can add ledf2vfp/leds2vfp and so these two functions be aliased to aeabi_fcmple/aeabi_dcmple on soft-float targets. --- library/compiler-builtins/README.md | 4 ++-- library/compiler-builtins/src/float/cmp.rs | 8 ++++++++ library/compiler-builtins/testcrate/build.rs | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 823877b8f5d..cef2fb0974a 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -115,8 +115,8 @@ features = ["c"] - [x] arm/gesf2vfp.S - [x] arm/gtdf2vfp.S - [x] arm/gtsf2vfp.S -- [ ] arm/ledf2vfp.S -- [ ] arm/lesf2vfp.S +- [x] arm/ledf2vfp.S +- [x] arm/lesf2vfp.S - [x] arm/ltdf2vfp.S - [x] arm/ltsf2vfp.S - [ ] arm/modsi3.S (generic version is done) diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 16b059e157d..01dd890550b 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -240,6 +240,14 @@ intrinsics! { (a < b) as i32 } + pub extern "C" fn __lesf2vfp(a: f32, b: f32) -> i32 { + (a <= b) as i32 + } + + pub extern "C" fn __ledf2vfp(a: f64, b: f64) -> i32 { + (a <= b) as i32 + } + pub extern "C" fn __nesf2vfp(a: f32, b: f32) -> i32 { (a != b) as i32 } diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index d3850cc5cb5..92e0b5d4c01 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -276,6 +276,20 @@ fn main() { Some((a.0 < b.0) as i32) }, "compiler_builtins::float::cmp::__ltdf2vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 <= b.0) as i32) + }, + "compiler_builtins::float::cmp::__lesf2vfp(a, b)"); + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 <= b.0) as i32) + }, + "compiler_builtins::float::cmp::__ledf2vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; -- cgit 1.4.1-3-g733a5 From 6fedebb1661bdc027e360ac935020d28c969e349 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 25 Feb 2018 18:35:36 +0100 Subject: Add missing test cases for __unordsf2/__unorddf2 --- library/compiler-builtins/testcrate/build.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 92e0b5d4c01..d50dc5623f5 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -143,6 +143,18 @@ fn main() { }, "compiler_builtins::float::cmp::__lesf2(a, b)"); + gen(|(a, b): (MyF32, MyF32)| { + let c = a.0.is_nan() || b.0.is_nan(); + Some(c as i32) + }, + "compiler_builtins::float::cmp::__unordsf2(a, b)"); + + gen(|(a, b): (MyF64, MyF64)| { + let c = a.0.is_nan() || b.0.is_nan(); + Some(c as i32) + }, + "compiler_builtins::float::cmp::__unorddf2(a, b)"); + if target_arch_arm { gen(|(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { -- cgit 1.4.1-3-g733a5 From 9fbdac0e38b7caedbbcf56a60dd977ea915216c0 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 25 Feb 2018 19:23:30 +0100 Subject: TravisCI: remove allow_failures for thumb* targets --- library/compiler-builtins/.travis.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index efd0b1738e3..898a600eb41 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -28,11 +28,6 @@ matrix: - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu - allow_failures: - - env: TARGET=thumbv6m-linux-eabi - - env: TARGET=thumbv7em-linux-eabi - - env: TARGET=thumbv7em-linux-eabihf - - env: TARGET=thumbv7m-linux-eabi install: - case $TARGET in -- cgit 1.4.1-3-g733a5 From ad3a5b682613b106c706b28ad1bf34444a419e17 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 25 Feb 2018 19:49:31 +0100 Subject: Remove ledf2vfp.S and lesf2vfp.S from build list --- library/compiler-builtins/build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 9eca26c1dd9..789311051de 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -384,8 +384,6 @@ mod c { "arm/floatsisfvfp.S", "arm/floatunssidfvfp.S", "arm/floatunssisfvfp.S", - "arm/ledf2vfp.S", - "arm/lesf2vfp.S", "arm/restore_vfp_d8_d15_regs.S", "arm/save_vfp_d8_d15_regs.S", ], -- cgit 1.4.1-3-g733a5 From 09d201db355a208952ba8b03587fa953c8b13302 Mon Sep 17 00:00:00 2001 From: Thomas Winwood Date: Sat, 9 Dec 2017 18:40:36 +0000 Subject: Add __floatdisf and __floatundisf intrinsics --- library/compiler-builtins/README.md | 4 ++-- library/compiler-builtins/src/float/conv.rs | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 5606ef4c846..cee6679e16c 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -150,11 +150,11 @@ features = ["c"] - [x] fixunssfdi.c - [x] fixunssfsi.c - [x] floatdidf.c -- [ ] floatdisf.c +- [x] floatdisf.c - [x] floatsidf.c - [x] floatsisf.c - [x] floatundidf.c -- [ ] floatundisf.c +- [x] floatundisf.c - [x] floatunsidf.c - [x] floatunsisf.c - [ ] i386/ashldi3.S diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 33644ce56aa..53844c17b49 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -80,6 +80,18 @@ intrinsics! { int_to_float!(i, i32, f64) } + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[arm_aeabi_alias = __aeabi_l2f] + pub extern "C" fn __floatdisf(i: i64) -> f32 { + // On x86_64 LLVM will use native instructions for this conversion, we + // can just do it directly + if cfg!(target_arch = "x86_64") { + i as f32 + } else { + int_to_float!(i, i64, f32) + } + } + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] #[arm_aeabi_alias = __aeabi_l2d] pub extern "C" fn __floatdidf(i: i64) -> f64 { @@ -112,6 +124,14 @@ intrinsics! { int_to_float!(i, u32, f64) } + #[use_c_shim_if(all(not(target_env = "msvc"), + any(target_arch = "x86", + all(not(windows), target_arch = "x86_64"))))] + #[arm_aeabi_alias = __aeabi_ul2f] + pub extern "C" fn __floatundisf(i: u64) -> f32 { + int_to_float!(i, u64, f32) + } + #[use_c_shim_if(all(not(target_env = "msvc"), any(target_arch = "x86", all(not(windows), target_arch = "x86_64"))))] -- cgit 1.4.1-3-g733a5 From f0f2db7490da3bec0c669a31dc8db4cdcb6c0549 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sat, 17 Mar 2018 21:37:35 -0500 Subject: i128 is being stabilized --- library/compiler-builtins/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 8d8d4a2fee0..619b6ac7afb 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -12,7 +12,6 @@ #![feature(compiler_builtins)] #![feature(core_intrinsics)] #![feature(naked_functions)] -#![feature(i128_type)] #![feature(repr_simd)] #![feature(abi_unadjusted)] #![feature(linkage)] -- cgit 1.4.1-3-g733a5 From b90fa1e14fa86fe402c6d1c1e08384947c19a668 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sun, 18 Mar 2018 14:07:01 -0500 Subject: Put back feature --- library/compiler-builtins/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 619b6ac7afb..f10ba757228 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -17,6 +17,7 @@ #![feature(linkage)] #![feature(lang_items)] #![allow(unused_features)] +#![feature(i128_type)] #![no_builtins] #![cfg_attr(feature = "compiler-builtins", feature(staged_api))] #![cfg_attr(feature = "compiler-builtins", -- cgit 1.4.1-3-g733a5 From 635855abdd31a066f6bdb6d65da5f29c3f53bb99 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Tue, 20 Mar 2018 19:16:13 -0500 Subject: stable_features allowed temporarily --- library/compiler-builtins/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index f10ba757228..819967be4aa 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -17,6 +17,7 @@ #![feature(linkage)] #![feature(lang_items)] #![allow(unused_features)] +#![allow(stable_features)] // FIXME(mark-i-m): remove after i128 stabilizes #![feature(i128_type)] #![no_builtins] #![cfg_attr(feature = "compiler-builtins", feature(staged_api))] -- cgit 1.4.1-3-g733a5 From f83c8529e7216b44b1dbbabc92bf313d8c57f5e3 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Tue, 27 Mar 2018 11:33:57 +0200 Subject: Fix incorrect names used / generated on ARM --- library/compiler-builtins/src/arm.rs | 67 ++++++++++++++++++++++++++++++++- library/compiler-builtins/src/macros.rs | 1 + 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 25fdd52429e..dbd6f87ca52 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,7 +1,10 @@ use core::intrinsics; // NOTE This function and the ones below are implemented using assembly because they using a custom -// calling convention which can't be implemented using a normal Rust function +// calling convention which can't be implemented using a normal Rust function. +// NOTE The only difference between the iOS and non-iOS versions of those functions is that the iOS +// versions use 3 leading underscores in the names of called functions instead of 2. +#[cfg(not(target_os = "ios"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uidivmod() { @@ -15,6 +18,21 @@ pub unsafe fn __aeabi_uidivmod() { intrinsics::unreachable(); } +#[cfg(target_os = "ios")] +#[naked] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe fn __aeabi_uidivmod() { + asm!("push {lr} + sub sp, sp, #4 + mov r2, sp + bl ___udivmodsi4 + ldr r1, [sp] + add sp, sp, #4 + pop {pc}" ::: "memory" : "volatile"); + intrinsics::unreachable(); +} + +#[cfg(not(target_os = "ios"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uldivmod() { @@ -30,6 +48,23 @@ pub unsafe fn __aeabi_uldivmod() { intrinsics::unreachable(); } +#[cfg(target_os = "ios")] +#[naked] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe fn __aeabi_uldivmod() { + asm!("push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] + bl ___udivmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc}" ::: "memory" : "volatile"); + intrinsics::unreachable(); +} + +#[cfg(not(target_os = "ios"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_idivmod() { @@ -42,6 +77,20 @@ pub unsafe fn __aeabi_idivmod() { intrinsics::unreachable(); } +#[cfg(target_os = "ios")] +#[naked] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe fn __aeabi_idivmod() { + asm!("push {r0, r1, r4, lr} + bl ___aeabi_idiv + pop {r1, r2} + muls r2, r2, r0 + subs r1, r1, r2 + pop {r4, pc}" ::: "memory" : "volatile"); + intrinsics::unreachable(); +} + +#[cfg(not(target_os = "ios"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_ldivmod() { @@ -57,6 +106,22 @@ pub unsafe fn __aeabi_ldivmod() { intrinsics::unreachable(); } +#[cfg(target_os = "ios")] +#[naked] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe fn __aeabi_ldivmod() { + asm!("push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] + bl ___divmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc}" ::: "memory" : "volatile"); + intrinsics::unreachable(); +} + // FIXME: The `*4` and `*8` variants should be defined as aliases. #[cfg(not(target_os = "ios"))] diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 58d94958a43..5f1ab469a02 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -210,6 +210,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg(target_arch = "arm")] + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } -- cgit 1.4.1-3-g733a5 From ed6d12ecea3707d22328818efe9aadfcf0612e19 Mon Sep 17 00:00:00 2001 From: Thomas Winwood Date: Thu, 5 Apr 2018 15:03:44 +0100 Subject: Remove reference to C impl of float[un]disf --- library/compiler-builtins/build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 9c23c20c965..ab1cc4b2735 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4991,8 +4991,6 @@ mod c { "divxc3.c", "extendsfdf2.c", "extendhfsf2.c", - "floatdisf.c", - "floatundisf.c", "int_util.c", "muldc3.c", "mulsc3.c", -- cgit 1.4.1-3-g733a5 From 99d7dde58d76f72a400d22d5ba27d640ab67992f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 11 May 2018 16:45:30 -0700 Subject: Attempt to fix tests on latest nightly --- library/compiler-builtins/testcrate/build.rs | 214 ++++++++++----------- .../compiler-builtins/testcrate/tests/generated.rs | 7 +- 2 files changed, 108 insertions(+), 113 deletions(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index d50dc5623f5..d862e0d0ffb 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -1,5 +1,3 @@ -#![feature(i128_type, i128)] - extern crate cast; extern crate rand; @@ -40,7 +38,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::add::__adddf3(a, b)"); + "builtins::float::add::__adddf3(a, b)"); gen(|(a, b): (MyF32, MyF32)| { let c = a.0 + b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { @@ -49,7 +47,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::add::__addsf3(a, b)"); + "builtins::float::add::__addsf3(a, b)"); if target_arch_arm { gen(|(a, b): (MyF64, MyF64)| { @@ -60,7 +58,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::add::__adddf3vfp(a, b)"); + "builtins::float::add::__adddf3vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { let c = a.0 + b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { @@ -69,7 +67,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::add::__addsf3vfp(a, b)"); + "builtins::float::add::__addsf3vfp(a, b)"); } @@ -90,7 +88,7 @@ fn main() { Some(0) } }, - "compiler_builtins::float::cmp::__gedf2(a, b)"); + "builtins::float::cmp::__gedf2(a, b)"); gen(|(a, b): (MyF32, MyF32)| { let (a, b) = (a.0, b.0); if a.is_nan() || b.is_nan() { @@ -107,7 +105,7 @@ fn main() { Some(0) } }, - "compiler_builtins::float::cmp::__gesf2(a, b)"); + "builtins::float::cmp::__gesf2(a, b)"); gen(|(a, b): (MyF64, MyF64)| { let (a, b) = (a.0, b.0); if a.is_nan() || b.is_nan() { @@ -124,7 +122,7 @@ fn main() { Some(0) } }, - "compiler_builtins::float::cmp::__ledf2(a, b)"); + "builtins::float::cmp::__ledf2(a, b)"); gen(|(a, b): (MyF32, MyF32)| { let (a, b) = (a.0, b.0); if a.is_nan() || b.is_nan() { @@ -141,19 +139,19 @@ fn main() { Some(0) } }, - "compiler_builtins::float::cmp::__lesf2(a, b)"); + "builtins::float::cmp::__lesf2(a, b)"); gen(|(a, b): (MyF32, MyF32)| { let c = a.0.is_nan() || b.0.is_nan(); Some(c as i32) }, - "compiler_builtins::float::cmp::__unordsf2(a, b)"); + "builtins::float::cmp::__unordsf2(a, b)"); gen(|(a, b): (MyF64, MyF64)| { let c = a.0.is_nan() || b.0.is_nan(); Some(c as i32) }, - "compiler_builtins::float::cmp::__unorddf2(a, b)"); + "builtins::float::cmp::__unorddf2(a, b)"); if target_arch_arm { gen(|(a, b): (MyF32, MyF32)| { @@ -163,7 +161,7 @@ fn main() { let c = (a.0 <= b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_fcmple(a, b)"); + "builtins::float::cmp::__aeabi_fcmple(a, b)"); gen(|(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { @@ -172,7 +170,7 @@ fn main() { let c = (a.0 >= b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_fcmpge(a, b)"); + "builtins::float::cmp::__aeabi_fcmpge(a, b)"); gen(|(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { @@ -181,7 +179,7 @@ fn main() { let c = (a.0 == b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_fcmpeq(a, b)"); + "builtins::float::cmp::__aeabi_fcmpeq(a, b)"); gen(|(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { @@ -190,7 +188,7 @@ fn main() { let c = (a.0 < b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_fcmplt(a, b)"); + "builtins::float::cmp::__aeabi_fcmplt(a, b)"); gen(|(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { @@ -199,7 +197,7 @@ fn main() { let c = (a.0 > b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_fcmpgt(a, b)"); + "builtins::float::cmp::__aeabi_fcmpgt(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { @@ -208,7 +206,7 @@ fn main() { let c = (a.0 <= b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_dcmple(a, b)"); + "builtins::float::cmp::__aeabi_dcmple(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { @@ -217,7 +215,7 @@ fn main() { let c = (a.0 >= b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_dcmpge(a, b)"); + "builtins::float::cmp::__aeabi_dcmpge(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { @@ -226,7 +224,7 @@ fn main() { let c = (a.0 == b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_dcmpeq(a, b)"); + "builtins::float::cmp::__aeabi_dcmpeq(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { @@ -235,7 +233,7 @@ fn main() { let c = (a.0 < b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_dcmplt(a, b)"); + "builtins::float::cmp::__aeabi_dcmplt(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { @@ -244,7 +242,7 @@ fn main() { let c = (a.0 > b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_dcmpgt(a, b)"); + "builtins::float::cmp::__aeabi_dcmpgt(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { @@ -252,84 +250,84 @@ fn main() { } Some((a.0 >= b.0) as i32) }, - "compiler_builtins::float::cmp::__gesf2vfp(a, b)"); + "builtins::float::cmp::__gesf2vfp(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 >= b.0) as i32) }, - "compiler_builtins::float::cmp::__gedf2vfp(a, b)"); + "builtins::float::cmp::__gedf2vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 > b.0) as i32) }, - "compiler_builtins::float::cmp::__gtsf2vfp(a, b)"); + "builtins::float::cmp::__gtsf2vfp(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 > b.0) as i32) }, - "compiler_builtins::float::cmp::__gtdf2vfp(a, b)"); + "builtins::float::cmp::__gtdf2vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 < b.0) as i32) }, - "compiler_builtins::float::cmp::__ltsf2vfp(a, b)"); + "builtins::float::cmp::__ltsf2vfp(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 < b.0) as i32) }, - "compiler_builtins::float::cmp::__ltdf2vfp(a, b)"); + "builtins::float::cmp::__ltdf2vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 <= b.0) as i32) }, - "compiler_builtins::float::cmp::__lesf2vfp(a, b)"); + "builtins::float::cmp::__lesf2vfp(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 <= b.0) as i32) }, - "compiler_builtins::float::cmp::__ledf2vfp(a, b)"); + "builtins::float::cmp::__ledf2vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 != b.0) as i32) }, - "compiler_builtins::float::cmp::__nesf2vfp(a, b)"); + "builtins::float::cmp::__nesf2vfp(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 != b.0) as i32) }, - "compiler_builtins::float::cmp::__nedf2vfp(a, b)"); + "builtins::float::cmp::__nedf2vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 == b.0) as i32) }, - "compiler_builtins::float::cmp::__eqsf2vfp(a, b)"); + "builtins::float::cmp::__eqsf2vfp(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 == b.0) as i32) }, - "compiler_builtins::float::cmp::__eqdf2vfp(a, b)"); + "builtins::float::cmp::__eqdf2vfp(a, b)"); } // float/extend.rs @@ -339,7 +337,7 @@ fn main() { } Some(f64(a.0)) }, - "compiler_builtins::float::extend::__extendsfdf2(a)"); + "builtins::float::extend::__extendsfdf2(a)"); if target_arch_arm { gen(|a: LargeF32| { if a.0.is_nan() { @@ -347,55 +345,55 @@ fn main() { } Some(f64(a.0)) }, - "compiler_builtins::float::extend::__extendsfdf2vfp(a)"); + "builtins::float::extend::__extendsfdf2vfp(a)"); } // float/conv.rs gen(|a: MyF64| i64(a.0).ok(), - "compiler_builtins::float::conv::__fixdfdi(a)"); + "builtins::float::conv::__fixdfdi(a)"); gen(|a: MyF64| i32(a.0).ok(), - "compiler_builtins::float::conv::__fixdfsi(a)"); + "builtins::float::conv::__fixdfsi(a)"); gen(|a: MyF32| i64(a.0).ok(), - "compiler_builtins::float::conv::__fixsfdi(a)"); + "builtins::float::conv::__fixsfdi(a)"); gen(|a: MyF32| i32(a.0).ok(), - "compiler_builtins::float::conv::__fixsfsi(a)"); + "builtins::float::conv::__fixsfsi(a)"); gen(|a: MyF32| i128(a.0).ok(), - "compiler_builtins::float::conv::__fixsfti(a)"); + "builtins::float::conv::__fixsfti(a)"); gen(|a: MyF64| i128(a.0).ok(), - "compiler_builtins::float::conv::__fixdfti(a)"); + "builtins::float::conv::__fixdfti(a)"); gen(|a: MyF64| u64(a.0).ok(), - "compiler_builtins::float::conv::__fixunsdfdi(a)"); + "builtins::float::conv::__fixunsdfdi(a)"); gen(|a: MyF64| u32(a.0).ok(), - "compiler_builtins::float::conv::__fixunsdfsi(a)"); + "builtins::float::conv::__fixunsdfsi(a)"); gen(|a: MyF32| u64(a.0).ok(), - "compiler_builtins::float::conv::__fixunssfdi(a)"); + "builtins::float::conv::__fixunssfdi(a)"); gen(|a: MyF32| u32(a.0).ok(), - "compiler_builtins::float::conv::__fixunssfsi(a)"); + "builtins::float::conv::__fixunssfsi(a)"); gen(|a: MyF32| u128(a.0).ok(), - "compiler_builtins::float::conv::__fixunssfti(a)"); + "builtins::float::conv::__fixunssfti(a)"); gen(|a: MyF64| u128(a.0).ok(), - "compiler_builtins::float::conv::__fixunsdfti(a)"); + "builtins::float::conv::__fixunsdfti(a)"); gen(|a: MyI64| Some(f64(a.0)), - "compiler_builtins::float::conv::__floatdidf(a)"); + "builtins::float::conv::__floatdidf(a)"); gen(|a: MyI32| Some(f64(a.0)), - "compiler_builtins::float::conv::__floatsidf(a)"); + "builtins::float::conv::__floatsidf(a)"); gen(|a: MyI32| Some(f32(a.0)), - "compiler_builtins::float::conv::__floatsisf(a)"); + "builtins::float::conv::__floatsisf(a)"); gen(|a: MyU64| Some(f64(a.0)), - "compiler_builtins::float::conv::__floatundidf(a)"); + "builtins::float::conv::__floatundidf(a)"); gen(|a: MyU32| Some(f64(a.0)), - "compiler_builtins::float::conv::__floatunsidf(a)"); + "builtins::float::conv::__floatunsidf(a)"); gen(|a: MyU32| Some(f32(a.0)), - "compiler_builtins::float::conv::__floatunsisf(a)"); + "builtins::float::conv::__floatunsisf(a)"); gen(|a: MyU128| f32(a.0).ok(), - "compiler_builtins::float::conv::__floatuntisf(a)"); + "builtins::float::conv::__floatuntisf(a)"); if !target_arch_mips { gen(|a: MyI128| Some(f32(a.0)), - "compiler_builtins::float::conv::__floattisf(a)"); + "builtins::float::conv::__floattisf(a)"); gen(|a: MyI128| Some(f64(a.0)), - "compiler_builtins::float::conv::__floattidf(a)"); + "builtins::float::conv::__floattidf(a)"); gen(|a: MyU128| Some(f64(a.0)), - "compiler_builtins::float::conv::__floatuntidf(a)"); + "builtins::float::conv::__floatuntidf(a)"); } // float/pow.rs @@ -407,7 +405,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::pow::__powidf2(a, b)"); + "builtins::float::pow::__powidf2(a, b)"); gen(|(a, b): (MyF32, MyI32)| { let c = a.0.powi(b.0); if a.0.is_nan() || c.is_nan() { @@ -416,7 +414,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::pow::__powisf2(a, b)"); + "builtins::float::pow::__powisf2(a, b)"); // float/sub.rs gen(|(a, b): (MyF64, MyF64)| { @@ -427,7 +425,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::sub::__subdf3(a, b)"); + "builtins::float::sub::__subdf3(a, b)"); gen(|(a, b): (MyF32, MyF32)| { let c = a.0 - b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { @@ -436,7 +434,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::sub::__subsf3(a, b)"); + "builtins::float::sub::__subsf3(a, b)"); if target_arch_arm { gen(|(a, b): (MyF64, MyF64)| { @@ -447,7 +445,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::sub::__subdf3vfp(a, b)"); + "builtins::float::sub::__subdf3vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { let c = a.0 - b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { @@ -456,7 +454,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::sub::__subsf3vfp(a, b)"); + "builtins::float::sub::__subsf3vfp(a, b)"); } // float/mul.rs @@ -468,7 +466,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::mul::__muldf3(a, b)"); + "builtins::float::mul::__muldf3(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { let c = a.0 * b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { @@ -477,7 +475,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::mul::__mulsf3(a, b)"); + "builtins::float::mul::__mulsf3(a, b)"); if target_arch_arm { gen(|(a, b): (MyF64, MyF64)| { @@ -488,7 +486,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::mul::__muldf3vfp(a, b)"); + "builtins::float::mul::__muldf3vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { let c = a.0 * b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { @@ -497,7 +495,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::mul::__mulsf3vfp(a, b)"); + "builtins::float::mul::__mulsf3vfp(a, b)"); } // float/div.rs @@ -514,7 +512,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::div::__divdf3(a, b)"); + "builtins::float::div::__divdf3(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if b.0 == 0.0 { return None @@ -528,7 +526,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::div::__divsf3(a, b)"); + "builtins::float::div::__divsf3(a, b)"); if target_arch_arm { gen(|(a, b): (MyF64, MyF64)| { @@ -544,7 +542,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::div::__divdf3vfp(a, b)"); + "builtins::float::div::__divdf3vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if b.0 == 0.0 { return None @@ -558,49 +556,49 @@ fn main() { Some(c) } }, - "compiler_builtins::float::div::__divsf3vfp(a, b)"); + "builtins::float::div::__divsf3vfp(a, b)"); } // int/addsub.rs gen(|(a, b): (MyU128, MyU128)| Some(a.0.wrapping_add(b.0)), - "compiler_builtins::int::addsub::rust_u128_add(a, b)"); + "builtins::int::addsub::rust_u128_add(a, b)"); gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_add(b.0)), - "compiler_builtins::int::addsub::rust_i128_add(a, b)"); + "builtins::int::addsub::rust_i128_add(a, b)"); gen(|(a, b): (MyU128, MyU128)| Some(a.0.overflowing_add(b.0)), - "compiler_builtins::int::addsub::rust_u128_addo(a, b)"); + "builtins::int::addsub::rust_u128_addo(a, b)"); gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_add(b.0)), - "compiler_builtins::int::addsub::rust_i128_addo(a, b)"); + "builtins::int::addsub::rust_i128_addo(a, b)"); gen(|(a, b): (MyU128, MyU128)| Some(a.0.wrapping_sub(b.0)), - "compiler_builtins::int::addsub::rust_u128_sub(a, b)"); + "builtins::int::addsub::rust_u128_sub(a, b)"); gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_sub(b.0)), - "compiler_builtins::int::addsub::rust_i128_sub(a, b)"); + "builtins::int::addsub::rust_i128_sub(a, b)"); gen(|(a, b): (MyU128, MyU128)| Some(a.0.overflowing_sub(b.0)), - "compiler_builtins::int::addsub::rust_u128_subo(a, b)"); + "builtins::int::addsub::rust_u128_subo(a, b)"); gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_sub(b.0)), - "compiler_builtins::int::addsub::rust_i128_subo(a, b)"); + "builtins::int::addsub::rust_i128_subo(a, b)"); // int/mul.rs gen(|(a, b): (MyU64, MyU64)| Some(a.0.wrapping_mul(b.0)), - "compiler_builtins::int::mul::__muldi3(a, b)"); + "builtins::int::mul::__muldi3(a, b)"); gen(|(a, b): (MyI64, MyI64)| Some(a.0.overflowing_mul(b.0)), "{ let mut o = 2; - let c = compiler_builtins::int::mul::__mulodi4(a, b, &mut o); + let c = builtins::int::mul::__mulodi4(a, b, &mut o); (c, match o { 0 => false, 1 => true, _ => panic!() }) }"); gen(|(a, b): (MyI32, MyI32)| Some(a.0.overflowing_mul(b.0)), "{ let mut o = 2; - let c = compiler_builtins::int::mul::__mulosi4(a, b, &mut o); + let c = builtins::int::mul::__mulosi4(a, b, &mut o); (c, match o { 0 => false, 1 => true, _ => panic!() }) }"); gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_mul(b.0)), - "compiler_builtins::int::mul::__multi3(a, b)"); + "builtins::int::mul::__multi3(a, b)"); if !target_arch_mips { // FIXME(#137) gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_mul(b.0)), "{ let mut o = 2; - let c = compiler_builtins::int::mul::__muloti4(a, b, &mut o); + let c = builtins::int::mul::__muloti4(a, b, &mut o); (c, match o { 0 => false, 1 => true, _ => panic!() }) }"); } @@ -613,7 +611,7 @@ fn main() { Some(a.0 / b.0) } }, - "compiler_builtins::int::sdiv::__divdi3(a, b)"); + "builtins::int::sdiv::__divdi3(a, b)"); gen(|(a, b): (MyI64, MyI64)| { if b.0 == 0 { None @@ -623,7 +621,7 @@ fn main() { }, "{ let mut r = 0; - (compiler_builtins::int::sdiv::__divmoddi4(a, b, &mut r), r) + (builtins::int::sdiv::__divmoddi4(a, b, &mut r), r) }"); gen(|(a, b): (MyI32, MyI32)| { if b.0 == 0 { @@ -634,7 +632,7 @@ fn main() { }, "{ let mut r = 0; - (compiler_builtins::int::sdiv::__divmodsi4(a, b, &mut r), r) + (builtins::int::sdiv::__divmodsi4(a, b, &mut r), r) }"); gen(|(a, b): (MyI32, MyI32)| { if b.0 == 0 { @@ -643,7 +641,7 @@ fn main() { Some(a.0 / b.0) } }, - "compiler_builtins::int::sdiv::__divsi3(a, b)"); + "builtins::int::sdiv::__divsi3(a, b)"); gen(|(a, b): (MyI32, MyI32)| { if b.0 == 0 { None @@ -651,7 +649,7 @@ fn main() { Some(a.0 % b.0) } }, - "compiler_builtins::int::sdiv::__modsi3(a, b)"); + "builtins::int::sdiv::__modsi3(a, b)"); gen(|(a, b): (MyI64, MyI64)| { if b.0 == 0 { None @@ -659,7 +657,7 @@ fn main() { Some(a.0 % b.0) } }, - "compiler_builtins::int::sdiv::__moddi3(a, b)"); + "builtins::int::sdiv::__moddi3(a, b)"); if !target_arch_mips { // FIXME(#137) gen(|(a, b): (MyI128, MyI128)| { if b.0 == 0 { @@ -668,7 +666,7 @@ fn main() { Some(a.0 / b.0) } }, - "compiler_builtins::int::sdiv::__divti3(a, b)"); + "builtins::int::sdiv::__divti3(a, b)"); gen(|(a, b): (MyI128, MyI128)| { if b.0 == 0 { None @@ -676,22 +674,22 @@ fn main() { Some(a.0 % b.0) } }, - "compiler_builtins::int::sdiv::__modti3(a, b)"); + "builtins::int::sdiv::__modti3(a, b)"); } // int/shift.rs gen(|(a, b): (MyU64, MyU32)| Some(a.0 << (b.0 % 64)), - "compiler_builtins::int::shift::__ashldi3(a, b % 64)"); + "builtins::int::shift::__ashldi3(a, b % 64)"); gen(|(a, b): (MyU128, MyU32)| Some(a.0 << (b.0 % 128)), - "compiler_builtins::int::shift::__ashlti3(a, b % 128)"); + "builtins::int::shift::__ashlti3(a, b % 128)"); gen(|(a, b): (MyI64, MyU32)| Some(a.0 >> (b.0 % 64)), - "compiler_builtins::int::shift::__ashrdi3(a, b % 64)"); + "builtins::int::shift::__ashrdi3(a, b % 64)"); gen(|(a, b): (MyI128, MyU32)| Some(a.0 >> (b.0 % 128)), - "compiler_builtins::int::shift::__ashrti3(a, b % 128)"); + "builtins::int::shift::__ashrti3(a, b % 128)"); gen(|(a, b): (MyU64, MyU32)| Some(a.0 >> (b.0 % 64)), - "compiler_builtins::int::shift::__lshrdi3(a, b % 64)"); + "builtins::int::shift::__lshrdi3(a, b % 64)"); gen(|(a, b): (MyU128, MyU32)| Some(a.0 >> (b.0 % 128)), - "compiler_builtins::int::shift::__lshrti3(a, b % 128)"); + "builtins::int::shift::__lshrti3(a, b % 128)"); // int/udiv.rs gen(|(a, b): (MyU64, MyU64)| { @@ -701,7 +699,7 @@ fn main() { Some(a.0 / b.0) } }, - "compiler_builtins::int::udiv::__udivdi3(a, b)"); + "builtins::int::udiv::__udivdi3(a, b)"); gen(|(a, b): (MyU64, MyU64)| { if b.0 == 0 { None @@ -711,7 +709,7 @@ fn main() { }, "{ let mut r = 0; - (compiler_builtins::int::udiv::__udivmoddi4(a, b, Some(&mut r)), r) + (builtins::int::udiv::__udivmoddi4(a, b, Some(&mut r)), r) }"); gen(|(a, b): (MyU32, MyU32)| { if b.0 == 0 { @@ -722,7 +720,7 @@ fn main() { }, "{ let mut r = 0; - (compiler_builtins::int::udiv::__udivmodsi4(a, b, Some(&mut r)), r) + (builtins::int::udiv::__udivmodsi4(a, b, Some(&mut r)), r) }"); gen(|(a, b): (MyU32, MyU32)| { if b.0 == 0 { @@ -731,7 +729,7 @@ fn main() { Some(a.0 / b.0) } }, - "compiler_builtins::int::udiv::__udivsi3(a, b)"); + "builtins::int::udiv::__udivsi3(a, b)"); gen(|(a, b): (MyU32, MyU32)| { if b.0 == 0 { None @@ -739,7 +737,7 @@ fn main() { Some(a.0 % b.0) } }, - "compiler_builtins::int::udiv::__umodsi3(a, b)"); + "builtins::int::udiv::__umodsi3(a, b)"); gen(|(a, b): (MyU64, MyU64)| { if b.0 == 0 { None @@ -747,7 +745,7 @@ fn main() { Some(a.0 % b.0) } }, - "compiler_builtins::int::udiv::__umoddi3(a, b)"); + "builtins::int::udiv::__umoddi3(a, b)"); if !target_arch_mips { // FIXME(#137) gen(|(a, b): (MyU128, MyU128)| { if b.0 == 0 { @@ -756,7 +754,7 @@ fn main() { Some(a.0 / b.0) } }, - "compiler_builtins::int::udiv::__udivti3(a, b)"); + "builtins::int::udiv::__udivti3(a, b)"); gen(|(a, b): (MyU128, MyU128)| { if b.0 == 0 { None @@ -764,7 +762,7 @@ fn main() { Some(a.0 % b.0) } }, - "compiler_builtins::int::udiv::__umodti3(a, b)"); + "builtins::int::udiv::__umodti3(a, b)"); gen(|(a, b): (MyU128, MyU128)| { if b.0 == 0 { None @@ -774,7 +772,7 @@ fn main() { }, "{ let mut r = 0; - (compiler_builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) + (builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) }"); } } diff --git a/library/compiler-builtins/testcrate/tests/generated.rs b/library/compiler-builtins/testcrate/tests/generated.rs index 1263dc261d6..28fe4be59e3 100644 --- a/library/compiler-builtins/testcrate/tests/generated.rs +++ b/library/compiler-builtins/testcrate/tests/generated.rs @@ -1,13 +1,10 @@ #![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![feature(lang_items, core_float, core_float_bits)] +#![feature(lang_items)] #![allow(bad_style)] #![allow(unused_imports)] #![no_std] -use core::num::Float; - -extern crate compiler_builtins; +extern crate compiler_builtins as builtins; #[cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), -- cgit 1.4.1-3-g733a5 From f58152286aeb8282df4d75e1f55cc9720c558e50 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 11 May 2018 16:52:34 -0700 Subject: More CI fixes --- library/compiler-builtins/examples/intrinsics.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 3820887895d..57aa95947ed 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -12,11 +12,12 @@ #![feature(core_float)] #![feature(lang_items)] #![feature(start)] -#![feature(i128_type)] #![feature(global_allocator)] #![feature(allocator_api)] #![cfg_attr(windows, feature(panic_unwind))] -#![no_std] +#![no_core] + +extern crate core; #[cfg(not(thumb))] extern crate alloc_system; -- cgit 1.4.1-3-g733a5 From c207fd3869e9b95add4816a64ce5870d385725ce Mon Sep 17 00:00:00 2001 From: Sébastien Marie Date: Sat, 12 May 2018 09:19:28 +0200 Subject: use system library on openbsd compiler_rt is provided by default on OpenBSD, so use it instead of rebuilding it from source. --- library/compiler-builtins/build.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index c625abbfc5b..271b010bc4a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -10,6 +10,13 @@ fn main() { return; } + // OpenBSD provides compiler_rt by default, use it instead of rebuilding it from source + if target.contains("openbsd") { + println!("cargo:rustc-link-search=native=/usr/lib"); + println!("cargo:rustc-link-lib=static=compiler_rt"); + return; + } + // Forcibly enable memory intrinsics on wasm32 as we don't have a libc to // provide them. if target.contains("wasm32") { -- cgit 1.4.1-3-g733a5 From 5f184b9b567f9e01d940b2d47ec0a7a1ff793f0f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 12 May 2018 07:21:36 -0700 Subject: More attempts for intrinsics example --- library/compiler-builtins/examples/intrinsics.rs | 26 +++--------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 57aa95947ed..ddcb1ab8636 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -15,19 +15,11 @@ #![feature(global_allocator)] #![feature(allocator_api)] #![cfg_attr(windows, feature(panic_unwind))] -#![no_core] - -extern crate core; +#![no_std] #[cfg(not(thumb))] -extern crate alloc_system; -extern crate compiler_builtins; -#[cfg(windows)] -extern crate panic_unwind; - -#[cfg(not(thumb))] -#[global_allocator] -static A: alloc_system::System = alloc_system::System; +#[link(name = "c")] +extern {} // NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even // compiler-rt provides a C/assembly implementation. @@ -38,8 +30,6 @@ static A: alloc_system::System = alloc_system::System; // have an additional comment: the function name is the ARM name for the intrinsic and the comment // in the non-ARM name for the intrinsic. mod intrinsics { - use core::num::Float; - // trunccdfsf2 pub fn aeabi_d2f(x: f64) -> f32 { x as f32 @@ -299,14 +289,6 @@ mod intrinsics { a * b } - pub fn powidf2(a: f64, b: i32) -> f64 { - a.powi(b) - } - - pub fn powisf2(a: f32, b: i32) -> f32 { - a.powi(b) - } - pub fn umoddi3(a: u64, b: u64) -> u64 { a % b } @@ -398,8 +380,6 @@ fn run() { bb(aeabi_uldivmod(bb(2), bb(3))); bb(moddi3(bb(2), bb(3))); bb(mulodi4(bb(2), bb(3))); - bb(powidf2(bb(2.), bb(3))); - bb(powisf2(bb(2.), bb(3))); bb(umoddi3(bb(2), bb(3))); bb(muloti4(bb(2), bb(2))); bb(multi3(bb(2), bb(2))); -- cgit 1.4.1-3-g733a5 From 87fad11100ffa43297928758074a86414cf2dd19 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 May 2018 06:55:34 -0700 Subject: Update compiler-rt Pick up a PR we forgot to backport --- library/compiler-builtins/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index dfd960b5f1a..54d95ca0bd6 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit dfd960b5f1a1751b22738fa34fd27b583f4618db +Subproject commit 54d95ca0bd603c322601a61255898e2b8d2a3cae -- cgit 1.4.1-3-g733a5 From 3f8bdca10d2f890b603b412988395ca494a144ea Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 May 2018 06:56:42 -0700 Subject: Allow failures on thumb for now --- library/compiler-builtins/.travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 898a600eb41..efd0b1738e3 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -28,6 +28,11 @@ matrix: - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu + allow_failures: + - env: TARGET=thumbv6m-linux-eabi + - env: TARGET=thumbv7em-linux-eabi + - env: TARGET=thumbv7em-linux-eabihf + - env: TARGET=thumbv7m-linux-eabi install: - case $TARGET in -- cgit 1.4.1-3-g733a5 From 247819f3a0f7e96b5f9e5f0a6b530c649b54d74a Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Sun, 27 May 2018 23:28:17 +0900 Subject: Fix segfault on probestack with dynamic alloca. --- library/compiler-builtins/src/probestack.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 34f466e1e3a..c8883e2f825 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -64,6 +64,8 @@ pub unsafe extern fn __rust_probestack() { // bytes pushed on the stack orginally with our return address. Using // `8(%rsp)` simulates us testing the stack pointer in the caller's // context. + cmp $$0x1000,%r11 + jna 3f 2: sub $$0x1000,%rsp test %rsp,8(%rsp) @@ -71,6 +73,7 @@ pub unsafe extern fn __rust_probestack() { cmp $$0x1000,%r11 ja 2b + 3: // Finish up the last remaining stack space requested, getting the last // bits out of r11 sub %r11,%rsp @@ -98,6 +101,9 @@ pub unsafe extern fn __rust_probestack() { asm!(" push %ecx mov %eax,%ecx + + cmp $$0x1000,%ecx + jna 3f 2: sub $$0x1000,%esp test %esp,8(%esp) @@ -105,6 +111,7 @@ pub unsafe extern fn __rust_probestack() { cmp $$0x1000,%ecx ja 2b + 3: sub %ecx,%esp test %esp,8(%esp) -- cgit 1.4.1-3-g733a5 From bf7b7b9109d62487511ff3acecb01e80a51e822a Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 28 May 2018 13:29:35 +0900 Subject: Explain why we need extra check in probestack. --- library/compiler-builtins/src/probestack.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index c8883e2f825..52a0414a18f 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -64,6 +64,11 @@ pub unsafe extern fn __rust_probestack() { // bytes pushed on the stack orginally with our return address. Using // `8(%rsp)` simulates us testing the stack pointer in the caller's // context. + + // It's usually called when %rax >= 0x1000, but that's not always true. + // Dynamic stack allocation, which is needed to implement unsized + // rvalues, triggers stackprobe even if %rax < 0x1000. + // Thus we have to check %r11 first to avoid segfault. cmp $$0x1000,%r11 jna 3f 2: -- cgit 1.4.1-3-g733a5 From b3ffa4f2ebd9a000667563f574d4b28120b7a30d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 Jun 2018 09:53:58 -0700 Subject: Upgrade compiler-rt submodule, mostly for sanitizers --- library/compiler-builtins/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index 54d95ca0bd6..40151c4c1cf 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit 54d95ca0bd603c322601a61255898e2b8d2a3cae +Subproject commit 40151c4c1cf77e593e3654e66e25ea423116aaae -- cgit 1.4.1-3-g733a5 From 8e271704ef5f758ceaf505af3a7da69b2666f819 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 00:44:28 -0500 Subject: initial commit --- library/compiler-builtins/libm/.gitignore | 5 + library/compiler-builtins/libm/Cargo.toml | 7 + library/compiler-builtins/libm/LICENSE-APACHE | 201 +++++++++++++ library/compiler-builtins/libm/LICENSE-MIT | 25 ++ library/compiler-builtins/libm/README.md | 111 +++++++ library/compiler-builtins/libm/ci/script.sh | 12 + library/compiler-builtins/libm/src/fabsf.rs | 3 + library/compiler-builtins/libm/src/lib.rs | 12 + library/compiler-builtins/libm/src/powf.rs | 326 +++++++++++++++++++++ library/compiler-builtins/libm/src/scalbnf.rs | 34 +++ library/compiler-builtins/libm/src/sqrtf.rs | 83 ++++++ .../libm/test-generator/Cargo.toml | 8 + .../libm/test-generator/README.md | 8 + .../libm/test-generator/src/main.rs | 234 +++++++++++++++ 14 files changed, 1069 insertions(+) create mode 100644 library/compiler-builtins/libm/.gitignore create mode 100644 library/compiler-builtins/libm/Cargo.toml create mode 100644 library/compiler-builtins/libm/LICENSE-APACHE create mode 100644 library/compiler-builtins/libm/LICENSE-MIT create mode 100644 library/compiler-builtins/libm/README.md create mode 100644 library/compiler-builtins/libm/ci/script.sh create mode 100644 library/compiler-builtins/libm/src/fabsf.rs create mode 100644 library/compiler-builtins/libm/src/lib.rs create mode 100644 library/compiler-builtins/libm/src/powf.rs create mode 100644 library/compiler-builtins/libm/src/scalbnf.rs create mode 100644 library/compiler-builtins/libm/src/sqrtf.rs create mode 100644 library/compiler-builtins/libm/test-generator/Cargo.toml create mode 100644 library/compiler-builtins/libm/test-generator/README.md create mode 100644 library/compiler-builtins/libm/test-generator/src/main.rs diff --git a/library/compiler-builtins/libm/.gitignore b/library/compiler-builtins/libm/.gitignore new file mode 100644 index 00000000000..6db0ab6effc --- /dev/null +++ b/library/compiler-builtins/libm/.gitignore @@ -0,0 +1,5 @@ +**/*.rs.bk +.#* +/target +/tests +Cargo.lock diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml new file mode 100644 index 00000000000..96bc290fb32 --- /dev/null +++ b/library/compiler-builtins/libm/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "libm" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[workspace] +members = ["test-generator"] \ No newline at end of file diff --git a/library/compiler-builtins/libm/LICENSE-APACHE b/library/compiler-builtins/libm/LICENSE-APACHE new file mode 100644 index 00000000000..16fe87b06e8 --- /dev/null +++ b/library/compiler-builtins/libm/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/compiler-builtins/libm/LICENSE-MIT b/library/compiler-builtins/libm/LICENSE-MIT new file mode 100644 index 00000000000..432fbea04d3 --- /dev/null +++ b/library/compiler-builtins/libm/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2018 Jorge Aparicio + +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/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md new file mode 100644 index 00000000000..fe384e118e9 --- /dev/null +++ b/library/compiler-builtins/libm/README.md @@ -0,0 +1,111 @@ +# `libm` + +A port of [MUSL]'s libm to Rust. + +[MUSL]: https://www.musl-libc.org/ + +## Testing + +The test suite of this crate can only be run on x86_64 Linux systems. + +``` +$ # The test suite depends on the `cross` tool so install it if you don't have it +$ cargo install cross + +$ # and the `cross` tool requires docker to be running +$ systemctl start docker + +$ # execute the test suite for the x86_64 target +$ TARGET=x86_64-unknown-linux-gnu bash ci/script.sh + +$ # execute the test suite for the ARMv7 target +$ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh +``` + +## Contributing + +- Pick your favorite math function from the list below. +- Look for the C implementation of the function in the [MUSL source code][src]. +- Copy paste the C code into a Rust file in the `src` directory and adjust `src/lib.rs` accordingly. +- Run `cargo watch check` and fix the compiler errors. +- If you can, run the test suite locally. If you can't, no problem! Your PR will be tested + automatically. +- Send us a pull request! +- :tada: + +### Notes + +- To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the + `GET_FLOAT_WORD` macro, or a union, to do this operation. + +- To reinterpret an integer as a float use the `f32::from_bits` constructor. The MUSL code uses the + `SET_FLOAT_WORD` macro, or a union, to do this operation. + +- Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`] + newtype to avoid this problem. + +[src]: https://git.musl-libc.org/cgit/musl/tree/src/math +[`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html + +## Progress + +### Functions wanted by the wasm WG + +cf. [rustwasm/team#84](https://github.com/rustwasm/team/issues/84). + +- [ ] acos +- [ ] asin +- [ ] atan +- [ ] atan2 +- [ ] cbrt +- [ ] cos +- [ ] cosf +- [ ] cosh +- [ ] exp +- [ ] exp2 +- [ ] exp2f +- [ ] expf +- [ ] expm1 +- [ ] fma +- [ ] fmaf +- [ ] fmod +- [ ] fmodf +- [ ] hypot +- [ ] log +- [ ] log10 +- [ ] log10f +- [ ] log1p +- [ ] log2 +- [ ] log2f +- [ ] logf +- [ ] pow +- [x] powf +- [ ] round +- [ ] roundf +- [ ] sin +- [ ] sinf +- [ ] sinh +- [ ] tan +- [ ] tanh + +### Other functions + +- [x] fabsf +- [x] scalbnf +- [x] sqrtf + +## License + +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 the +work 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/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh new file mode 100644 index 00000000000..64550573c0e --- /dev/null +++ b/library/compiler-builtins/libm/ci/script.sh @@ -0,0 +1,12 @@ +set -euxo pipefail + +main() { + cargo run --package test-generator --target x86_64-unknown-linux-musl + if hash cargo-fmt; then + # nicer syntax error messages (if any) + cargo fmt + fi + cross test --target $TARGET --release +} + +main diff --git a/library/compiler-builtins/libm/src/fabsf.rs b/library/compiler-builtins/libm/src/fabsf.rs new file mode 100644 index 00000000000..be60d06cc8d --- /dev/null +++ b/library/compiler-builtins/libm/src/fabsf.rs @@ -0,0 +1,3 @@ +pub fn fabsf(x: f32) -> f32 { + f32::from_bits(x.to_bits() & 0x7fffffff) +} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs new file mode 100644 index 00000000000..3d4062f3d4a --- /dev/null +++ b/library/compiler-builtins/libm/src/lib.rs @@ -0,0 +1,12 @@ +#![deny(warnings)] +#![no_std] + +mod fabsf; +mod powf; +mod scalbnf; +mod sqrtf; + +pub use fabsf::fabsf; +pub use powf::powf; +pub use scalbnf::scalbnf; +pub use sqrtf::sqrtf; diff --git a/library/compiler-builtins/libm/src/powf.rs b/library/compiler-builtins/libm/src/powf.rs new file mode 100644 index 00000000000..770987c2a09 --- /dev/null +++ b/library/compiler-builtins/libm/src/powf.rs @@ -0,0 +1,326 @@ +use {scalbnf, sqrtf}; + +const BP: [f32; 2] = [1.0, 1.5]; +const DP_H: [f32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ +const DP_L: [f32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ +const TWO24: f32 = 16777216.0; /* 0x4b800000 */ +const HUGE: f32 = 1.0e30; +const TINY: f32 = 1.0e-30; +const L1: f32 = 6.0000002384e-01; /* 0x3f19999a */ +const L2: f32 = 4.2857143283e-01; /* 0x3edb6db7 */ +const L3: f32 = 3.3333334327e-01; /* 0x3eaaaaab */ +const L4: f32 = 2.7272811532e-01; /* 0x3e8ba305 */ +const L5: f32 = 2.3066075146e-01; /* 0x3e6c3255 */ +const L6: f32 = 2.0697501302e-01; /* 0x3e53f142 */ +const P1: f32 = 1.6666667163e-01; /* 0x3e2aaaab */ +const P2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const P3: f32 = 6.6137559770e-05; /* 0x388ab355 */ +const P4: f32 = -1.6533901999e-06; /* 0xb5ddea0e */ +const P5: f32 = 4.1381369442e-08; /* 0x3331bb4c */ +const LG2: f32 = 6.9314718246e-01; /* 0x3f317218 */ +const LG2_H: f32 = 6.93145752e-01; /* 0x3f317200 */ +const LG2_L: f32 = 1.42860654e-06; /* 0x35bfbe8c */ +const OVT: f32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ +const CP: f32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ +const CP_H: f32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ +const CP_L: f32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ +const IVLN2: f32 = 1.4426950216e+00; +const IVLN2_H: f32 = 1.4426879883e+00; +const IVLN2_L: f32 = 7.0526075433e-06; + +pub fn powf(x: f32, y: f32) -> f32 { + let mut z: f32; + let mut ax: f32; + let z_h: f32; + let z_l: f32; + let mut p_h: f32; + let mut p_l: f32; + let y1: f32; + let mut t1: f32; + let t2: f32; + let mut r: f32; + let s: f32; + let mut sn: f32; + let mut t: f32; + let mut u: f32; + let mut v: f32; + let mut w: f32; + let i: i32; + let mut j: i32; + let mut k: i32; + let mut yisint: i32; + let mut n: i32; + let hx: i32; + let hy: i32; + let mut ix: i32; + let iy: i32; + let mut is: i32; + + hx = x.to_bits() as i32; + hy = y.to_bits() as i32; + + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if iy == 0 { + return 1.0; + } + + /* 1**y = 1, even if y is NaN */ + if hx == 0x3f800000 { + return 1.0; + } + + /* NaN if either arg is NaN */ + if ix > 0x7f800000 || iy > 0x7f800000 { + return x + y; + } + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if hx < 0 { + if iy >= 0x4b800000 { + yisint = 2; /* even integer y */ + } else if iy >= 0x3f800000 { + k = (iy >> 23) - 0x7f; /* exponent */ + j = iy >> (23 - k); + if (j << (23 - k)) == iy { + yisint = 2 - (j & 1); + } + } + } + + /* special value of y */ + if iy == 0x7f800000 { + /* y is +-inf */ + if ix == 0x3f800000 { + /* (-1)**+-inf is 1 */ + return 1.0; + } else if ix > 0x3f800000 { + /* (|x|>1)**+-inf = inf,0 */ + return if hy >= 0 { y } else { 0.0 }; + } else { + /* (|x|<1)**+-inf = 0,inf */ + return if hy >= 0 { 0.0 } else { -y }; + } + } + if iy == 0x3f800000 { + /* y is +-1 */ + return if hy >= 0 { x } else { 1.0 / x }; + } + + if hy == 0x40000000 { + /* y is 2 */ + return x * x; + } + + if hy == 0x3f000000 { + /* y is 0.5 */ + if hx >= 0 { + /* x >= +0 */ + return sqrtf(x); + } + } + + ax = ::fabsf(x); + /* special value of x */ + if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 { + /* x is +-0,+-inf,+-1 */ + z = ax; + if hy < 0 { + /* z = (1/|x|) */ + z = 1.0 / z; + } + + if hx < 0 { + if ((ix - 0x3f800000) | yisint) == 0 { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } else if yisint == 1 { + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + } + return z; + } + + sn = 1.0; /* sign of result */ + if hx < 0 { + if yisint == 0 { + /* (x<0)**(non-int) is NaN */ + return (x - x) / (x - x); + } + + if yisint == 1 { + /* (x<0)**(odd int) */ + sn = -1.0; + } + } + + /* |y| is HUGE */ + if iy > 0x4d000000 { + /* if |y| > 2**27 */ + /* over/underflow if x is not close to one */ + if ix < 0x3f7ffff8 { + return if hy < 0 { + sn * HUGE * HUGE + } else { + sn * TINY * TINY + }; + } + + if ix > 0x3f800007 { + return if hy > 0 { + sn * HUGE * HUGE + } else { + sn * TINY * TINY + }; + } + + /* now |1-x| is TINY <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1.; /* t has 20 trailing zeros */ + w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); + u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ + v = t * IVLN2_L - w * IVLN2; + t1 = u + v; + is = t1.to_bits() as i32; + t1 = f32::from_bits(is as u32 & 0xfffff000); + t2 = v - (t1 - u); + } else { + let mut s2: f32; + let mut s_h: f32; + let s_l: f32; + let mut t_h: f32; + let mut t_l: f32; + + n = 0; + /* take care subnormal number */ + if ix < 0x00800000 { + ax *= TWO24; + n -= 24; + ix = ax.to_bits() as i32; + } + n += ((ix) >> 23) - 0x7f; + j = ix & 0x007fffff; + /* determine interval */ + ix = j | 0x3f800000; /* normalize ix */ + if j <= 0x1cc471 { + /* |x|> 1) & 0xfffff000) | 0x20000000) as i32; + t_h = f32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); + t_l = ax - (t_h - BP[k as usize]); + s_l = v * ((u - s_h * t_h) - s_h * t_l); + /* compute log(ax) */ + s2 = s * s; + r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); + r += s_l * (s_h + s); + s2 = s_h * s_h; + t_h = 3.0 + s2 + r; + is = t_h.to_bits() as i32; + t_h = f32::from_bits(is as u32 & 0xfffff000); + t_l = r - ((t_h - 3.0) - s2); + /* u+v = s*(1+...) */ + u = s_h * t_h; + v = s_l * t_h + t_l * s; + /* 2/(3log2)*(s+...) */ + p_h = u + v; + is = p_h.to_bits() as i32; + p_h = f32::from_bits(is as u32 & 0xfffff000); + p_l = v - (p_h - u); + z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = CP_L * p_h + p_l * CP + DP_L[k as usize]; + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = n as f32; + t1 = ((z_h + z_l) + DP_H[k as usize]) + t; + is = t1.to_bits() as i32; + t1 = f32::from_bits(is as u32 & 0xfffff000); + t2 = z_l - (((t1 - t) - DP_H[k as usize]) - z_h); + }; + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + is = y.to_bits() as i32; + y1 = f32::from_bits(is as u32 & 0xfffff000); + p_l = (y - y1) * t1 + y * t2; + p_h = y1 * t1; + z = p_l + p_h; + j = z.to_bits() as i32; + if j > 0x43000000 { + /* if z > 128 */ + return sn * HUGE * HUGE; /* overflow */ + } else if j == 0x43000000 { + /* if z == 128 */ + if p_l + OVT > z - p_h { + return sn * HUGE * HUGE; /* overflow */ + } + } else if (j & 0x7fffffff) > 0x43160000 { + /* z < -150 */ + // FIXME: check should be (uint32_t)j > 0xc3160000 + return sn * TINY * TINY; /* underflow */ + } else if j as u32 == 0xc3160000 { + /* z == -150 */ + if p_l <= z - p_h { + return sn * TINY * TINY; /* underflow */ + } + } + + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i >> 23) - 0x7f; + n = 0; + if i > 0x3f000000 { + /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00800000 >> (k + 1)); + k = ((n & 0x7fffffff) >> 23) - 0x7f; /* new k for n */ + t = f32::from_bits(n as u32 & !(0x007fffff >> k)); + n = ((n & 0x007fffff) | 0x00800000) >> (23 - k); + if j < 0 { + n = -n; + } + p_h -= t; + } + t = p_l + p_h; + is = t.to_bits() as i32; + t = f32::from_bits(is as u32 & 0xffff8000); + u = t * LG2_H; + v = (p_l - (t - p_h)) * LG2 + t * LG2_L; + z = u + v; + w = v - (z - u); + t = z * z; + t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + r = (z * t1) / (t1 - 2.0) - (w + z * w); + z = 1.0 - (r - z); + j = z.to_bits() as i32; + j += n << 23; + if (j >> 23) <= 0 { + /* subnormal output */ + z = scalbnf(z, n); + } else { + z = f32::from_bits(j as u32); + } + return sn * z; +} diff --git a/library/compiler-builtins/libm/src/scalbnf.rs b/library/compiler-builtins/libm/src/scalbnf.rs new file mode 100644 index 00000000000..2c057ebc57d --- /dev/null +++ b/library/compiler-builtins/libm/src/scalbnf.rs @@ -0,0 +1,34 @@ +pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 + let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 + + let mut y: f32 = x; + + if n > 127 { + y *= x1p127; + n -= 127; + if n > 127 { + y *= x1p127; + n -= 127; + if n > 127 { + n = 127; + } + } + } else if n < -126 { + y *= x1p_126; + y *= x1p24; + n += 126 - 24; + if n < -126 { + y *= x1p_126; + y *= x1p24; + n += 126 - 24; + if n < -126 { + n = -126; + } + } + } + + x = y * f32::from_bits((0x7f + n as u32) << 23); + x +} diff --git a/library/compiler-builtins/libm/src/sqrtf.rs b/library/compiler-builtins/libm/src/sqrtf.rs new file mode 100644 index 00000000000..6e92f67d4ab --- /dev/null +++ b/library/compiler-builtins/libm/src/sqrtf.rs @@ -0,0 +1,83 @@ +const TINY: f32 = 1.0e-30; + +pub fn sqrtf(x: f32) -> f32 { + let mut z: f32; + let sign: i32 = 0x80000000u32 as i32; + let mut ix: i32; + let mut s: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: u32; + + ix = x.to_bits() as i32; + + /* take care of Inf and NaN */ + if (ix as u32 & 0x7f800000) == 0x7f800000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + + /* take care of zero */ + if ix <= 0 { + if (ix & !sign) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } + + /* normalize x */ + m = ix >> 23; + if m == 0 { + /* subnormal x */ + i = 0; + while ix & 0x00800000 == 0 { + ix <<= 1; + i = i + 1; + } + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if m & 1 == 1 { + /* odd m, double x to make it even */ + ix += ix; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = 0; + s = 0; + r = 0x01000000; /* r = moving bit from right to left */ + + while r != 0 { + t = s + r as i32; + if t <= ix { + s = t + r as i32; + ix -= t; + q += r as i32; + } + ix += ix; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if ix != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if z > 1.0 { + q += 2; + } else { + q += q & 1; + } + } + } + + ix = (q >> 1) + 0x3f000000; + ix += m << 23; + f32::from_bits(ix as u32) +} diff --git a/library/compiler-builtins/libm/test-generator/Cargo.toml b/library/compiler-builtins/libm/test-generator/Cargo.toml new file mode 100644 index 00000000000..f45d173b451 --- /dev/null +++ b/library/compiler-builtins/libm/test-generator/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "test-generator" +version = "0.1.0" +authors = ["Jorge Aparicio "] +publish = false + +[dependencies] +rand = "0.5.3" diff --git a/library/compiler-builtins/libm/test-generator/README.md b/library/compiler-builtins/libm/test-generator/README.md new file mode 100644 index 00000000000..cbacd88f14d --- /dev/null +++ b/library/compiler-builtins/libm/test-generator/README.md @@ -0,0 +1,8 @@ +# `test-generator` + +This is a tool to generate test cases for the `libm` crate. + +The generator randomly creates inputs for each math function, then proceeds to compute the +expected output for the given function by running the MUSL *C implementation* of the function and +finally it packs the test cases as a Cargo test file. For this reason, this generator **must** +always be compiled for the `x86_64-unknown-linux-musl` target. diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs new file mode 100644 index 00000000000..7ee956f730f --- /dev/null +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -0,0 +1,234 @@ +// NOTE we intentionally avoid using the `quote` crate here because it doesn't work with the +// `x86_64-unknown-linux-musl` target. + +// NOTE usually the only thing you need to do to test a new math function is to add it to one of the +// macro invocations found in the bottom of this file. + +extern crate rand; + +use std::error::Error; +use std::fmt::Write as _0; +use std::fs::{self, File}; +use std::io::Write as _1; +use std::{i16, u32, u8}; + +use rand::{Rng, SeedableRng, XorShiftRng}; + +// Number of test cases to generate +const NTESTS: usize = 10_000; + +// TODO tweak this function to generate edge cases (zero, infinity, NaN) more often +fn f32(rng: &mut XorShiftRng) -> f32 { + let sign = if rng.gen_bool(0.5) { 1 << 31 } else { 0 }; + let exponent = (rng.gen_range(0, u8::MAX) as u32) << 23; + let mantissa = rng.gen_range(0, u32::MAX) & ((1 << 23) - 1); + + f32::from_bits(sign + exponent + mantissa) +} + +// fn(f32) -> f32 +macro_rules! f32_f32 { + ($($intr:ident,)+) => { + fn f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { + // MUSL C implementation of the function to test + extern "C" { + $(fn $intr(_: f32) -> f32;)+ + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let inp = f32(rng); + let out = unsafe { $intr(inp) }; + + let inp = inp.to_bits(); + let out = out.to_bits(); + + write!(cases, "({}, {})", inp, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[(u32, u32)] = &[ + {1} + ]; + + for case in CASES {{ + let (inp, expected) = *case; + + let outf = libm::{0}(f32::from_bits(inp)); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || + outi == expected) {{ + panic!( + \"input: {{}}, output: {{}}, expected: {{}}\", + inp, + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )+ + + Ok(()) + } + } +} + +macro_rules! f32f32_f32 { + ($($intr:ident,)+) => { + fn f32f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { + extern "C" { + $(fn $intr(_: f32, _: f32) -> f32;)+ + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let i1 = f32(rng); + let i2 = f32(rng); + let out = unsafe { $intr(i1, i2) }; + + let i1 = i1.to_bits(); + let i2 = i2.to_bits(); + let out = out.to_bits(); + + write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[((u32, u32), u32)] = &[ + {1} + ]; + + for case in CASES {{ + let ((i1, i2), expected) = *case; + + let outf = libm::{0}(f32::from_bits(i1), f32::from_bits(i2)); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || + outi == expected) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )+ + + Ok(()) + } + }; +} + +macro_rules! f32i32_f32 { + ($($intr:ident,)+) => { + fn f32i32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { + extern "C" { + $(fn $intr(_: f32, _: i32) -> f32;)+ + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let i1 = f32(rng); + let i2 = rng.gen_range(i16::MIN, i16::MAX); + let out = unsafe { $intr(i1, i2 as i32) }; + + let i1 = i1.to_bits(); + let out = out.to_bits(); + + write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[((u32, i16), u32)] = &[ + {1} + ]; + + for case in CASES {{ + let ((i1, i2), expected) = *case; + + let outf = libm::{0}(f32::from_bits(i1), i2 as i32); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || + outi == expected) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )+ + + Ok(()) + } + }; +} + +fn main() -> Result<(), Box> { + fs::remove_dir_all("tests").ok(); + fs::create_dir("tests")?; + + let mut rng = XorShiftRng::from_rng(&mut rand::thread_rng())?; + + f32_f32(&mut rng)?; + f32f32_f32(&mut rng)?; + f32i32_f32(&mut rng)?; + + Ok(()) +} + +/* Functions to test */ + +// With signature `fn(f32) -> f32` +f32_f32! { + fabsf, + sqrtf, +} + +// With signature `fn(f32, f32) -> f32` +f32f32_f32! { + powf, +} + +// With signature `fn(f32, i32) -> f32` +f32i32_f32! { + scalbnf, +} -- cgit 1.4.1-3-g733a5 From 27c88ea01bdea389b1c8656b269d4cfe9448059f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 00:53:44 -0500 Subject: add CI --- library/compiler-builtins/libm/.travis.yml | 32 ++++++++++++++++++++++++++++ library/compiler-builtins/libm/ci/install.sh | 15 +++++++++++++ library/compiler-builtins/libm/ci/script.sh | 2 +- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/.travis.yml create mode 100644 library/compiler-builtins/libm/ci/install.sh diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml new file mode 100644 index 00000000000..4d8ccc784c6 --- /dev/null +++ b/library/compiler-builtins/libm/.travis.yml @@ -0,0 +1,32 @@ +language: rust +services: docker +sudo: required + +matrix: + include: + - env: TARGET=aarch64-unknown-linux-gnu + - env: TARGET=armv7-unknown-linux-gnueabihf + - env: TARGET=i686-unknown-linux-gnu + - env: TARGET=mips-unknown-linux-gnu + - env: TARGET=mips64-unknown-linux-gnuabi64 + - env: TARGET=mips64el-unknown-linux-gnuabi64 + - env: TARGET=mipsel-unknown-linux-gnu + - env: TARGET=powerpc-unknown-linux-gnu + - env: TARGET=powerpc64-unknown-linux-gnu + - env: TARGET=powerpc64le-unknown-linux-gnu + - env: TARGET=x86_64-unknown-linux-gnu + +before_install: set -e + +install: + - bash ci/install.sh + +script: + - bash ci/script.sh + +after_script: set +e + +cache: cargo + +before_cache: + - chmod -R a+r $HOME/.cargo; diff --git a/library/compiler-builtins/libm/ci/install.sh b/library/compiler-builtins/libm/ci/install.sh new file mode 100644 index 00000000000..efdbb06c206 --- /dev/null +++ b/library/compiler-builtins/libm/ci/install.sh @@ -0,0 +1,15 @@ +set -euxo pipefail + +main() { + if ! hash cross >/dev/null 2>&1; then + cargo install cross + fi + + rustup target add x86_64-unknown-linux-musl + + if [ $TARGET != x86_64-unknown-linux-gnu ]; then + rustup target add $TARGET + fi +} + +main diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index 64550573c0e..caba616edd1 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -2,7 +2,7 @@ set -euxo pipefail main() { cargo run --package test-generator --target x86_64-unknown-linux-musl - if hash cargo-fmt; then + if cargo fmt --version >/dev/null 2>&1; then # nicer syntax error messages (if any) cargo fmt fi -- cgit 1.4.1-3-g733a5 From 806431c94788b90c1357705e7223210beefcba1e Mon Sep 17 00:00:00 2001 From: ljedrz Date: Thu, 12 Jul 2018 14:40:56 +0200 Subject: Remove #![feature(i128_type)] as i128 is stable --- library/compiler-builtins/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 819967be4aa..619b6ac7afb 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -17,8 +17,6 @@ #![feature(linkage)] #![feature(lang_items)] #![allow(unused_features)] -#![allow(stable_features)] // FIXME(mark-i-m): remove after i128 stabilizes -#![feature(i128_type)] #![no_builtins] #![cfg_attr(feature = "compiler-builtins", feature(staged_api))] #![cfg_attr(feature = "compiler-builtins", -- cgit 1.4.1-3-g733a5 From 4f50a214f793500891006cafb3477b2b9d05a6d8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 12 Jul 2018 08:32:39 -0700 Subject: Try to fix example's compile on nightly --- library/compiler-builtins/examples/intrinsics.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index ddcb1ab8636..6468a831681 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -14,6 +14,7 @@ #![feature(start)] #![feature(global_allocator)] #![feature(allocator_api)] +#![feature(panic_implementation)] #![cfg_attr(windows, feature(panic_unwind))] #![no_std] @@ -442,7 +443,7 @@ pub fn _Unwind_Resume() {} #[no_mangle] pub extern "C" fn eh_personality() {} -#[lang = "panic_fmt"] -#[no_mangle] -#[allow(private_no_mangle_fns)] -extern "C" fn panic_fmt() {} +#[panic_implementation] +fn panic(x: &core::panic::PanicInfo) -> ! { + loop {} +} -- cgit 1.4.1-3-g733a5 From 3ae27657a1501dfad3ea33f586ad4298f35f1027 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 12 Jul 2018 09:29:32 -0700 Subject: Try to fix intrinsics example on nightly --- library/compiler-builtins/Cargo.toml | 3 +++ .../crates/panic-implementation/Cargo.toml | 6 ++++++ .../crates/panic-implementation/src/lib.rs | 11 +++++++++++ library/compiler-builtins/examples/intrinsics.rs | 15 +++++++++------ 4 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/crates/panic-implementation/Cargo.toml create mode 100644 library/compiler-builtins/crates/panic-implementation/src/lib.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0ebeb17f326..31126626919 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -9,6 +9,9 @@ test = false [build-dependencies] cc = { optional = true, version = "1.0" } +[dev-dependencies] +panic-implementation = { path = 'crates/panic-implementation' } + [features] default = ["compiler-builtins"] diff --git a/library/compiler-builtins/crates/panic-implementation/Cargo.toml b/library/compiler-builtins/crates/panic-implementation/Cargo.toml new file mode 100644 index 00000000000..a076cbc3cb8 --- /dev/null +++ b/library/compiler-builtins/crates/panic-implementation/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "panic-implementation" +version = "0.1.0" +authors = ["Alex Crichton "] + +[dependencies] diff --git a/library/compiler-builtins/crates/panic-implementation/src/lib.rs b/library/compiler-builtins/crates/panic-implementation/src/lib.rs new file mode 100644 index 00000000000..1bb23970f7d --- /dev/null +++ b/library/compiler-builtins/crates/panic-implementation/src/lib.rs @@ -0,0 +1,11 @@ +// Hack of a crate until rust-lang/rust#51647 is fixed + +#![feature(no_core, panic_implementation)] +#![no_core] + +extern crate core; + +#[panic_implementation] +fn panic(_: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 6468a831681..c165fcccaff 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -12,12 +12,13 @@ #![feature(core_float)] #![feature(lang_items)] #![feature(start)] -#![feature(global_allocator)] #![feature(allocator_api)] #![feature(panic_implementation)] #![cfg_attr(windows, feature(panic_unwind))] #![no_std] +extern crate panic_implementation; + #[cfg(not(thumb))] #[link(name = "c")] extern {} @@ -393,6 +394,13 @@ fn run() { bb(modti3(bb(2), bb(2))); something_with_a_dtor(&|| assert_eq!(bb(1), 1)); + + extern { + fn rust_begin_unwind(); + } + // if bb(false) { + unsafe { rust_begin_unwind(); } + // } } fn something_with_a_dtor(f: &Fn()) { @@ -442,8 +450,3 @@ pub fn _Unwind_Resume() {} #[lang = "eh_personality"] #[no_mangle] pub extern "C" fn eh_personality() {} - -#[panic_implementation] -fn panic(x: &core::panic::PanicInfo) -> ! { - loop {} -} -- cgit 1.4.1-3-g733a5 From 5b950eaea2bb38d4974ecc5a96231df6dc42fc99 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 12:20:55 -0500 Subject: use approximate equality with 1 ULP of tolerance --- library/compiler-builtins/libm/src/lib.rs | 6 ++++++ library/compiler-builtins/libm/test-generator/src/main.rs | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 3d4062f3d4a..cb2110f1fb7 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -10,3 +10,9 @@ pub use fabsf::fabsf; pub use powf::powf; pub use scalbnf::scalbnf; pub use sqrtf::sqrtf; + +/// Approximate equality with 1 ULP of tolerance +#[doc(hidden)] +pub fn _eqf(a: u32, b: u32) -> bool { + (a as i32).wrapping_sub(b as i32).abs() <= 1 +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 7ee956f730f..c406cf340ed 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -65,7 +65,7 @@ macro_rules! f32_f32 { let outi = outf.to_bits(); if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || - outi == expected) {{ + libm::_eqf(outi, expected)) {{ panic!( \"input: {{}}, output: {{}}, expected: {{}}\", inp, @@ -124,7 +124,7 @@ macro_rules! f32f32_f32 { let outi = outf.to_bits(); if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || - outi == expected) {{ + libm::_eqf(outi, expected)) {{ panic!( \"input: {{:?}}, output: {{}}, expected: {{}}\", (i1, i2), @@ -182,7 +182,7 @@ macro_rules! f32i32_f32 { let outi = outf.to_bits(); if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || - outi == expected) {{ + libm::_eqf(outi, expected)) {{ panic!( \"input: {{:?}}, output: {{}}, expected: {{}}\", (i1, i2), -- cgit 1.4.1-3-g733a5 From 69f61b414906005e7e1e4486781f0cf98d683821 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 03:07:28 -0500 Subject: implement fmodf --- library/compiler-builtins/libm/src/fmodf.rs | 89 ++++++++++++++++++++++ library/compiler-builtins/libm/src/lib.rs | 6 ++ .../libm/test-generator/src/main.rs | 1 + 3 files changed, 96 insertions(+) create mode 100644 library/compiler-builtins/libm/src/fmodf.rs diff --git a/library/compiler-builtins/libm/src/fmodf.rs b/library/compiler-builtins/libm/src/fmodf.rs new file mode 100644 index 00000000000..a184411a182 --- /dev/null +++ b/library/compiler-builtins/libm/src/fmodf.rs @@ -0,0 +1,89 @@ +use core::u32; + +use isnanf; + +pub fn fmodf(x: f32, y: f32) -> f32 { + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let mut ex = (uxi >> 23 & 0xff) as i32; + let mut ey = (uyi >> 23 & 0xff) as i32; + let sx = uxi & 0x80000000; + let mut i; + + if uyi << 1 == 0 || isnanf(y) || ex == 0xff { + return (x * y) / (x * y); + } + + if uxi << 1 <= uyi << 1 { + if uxi << 1 == uyi << 1 { + return 0.0 * x; + } + + return x; + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 9; + while i >> 31 == 0 { + ex -= 1; + i <<= 1; + } + + uxi <<= -ex + 1; + } else { + uxi &= u32::MAX >> 9; + uxi |= 1 << 23; + } + + if ey == 0 { + i = uyi << 9; + while i >> 31 == 0 { + ey -= 1; + i <<= 1; + } + + uyi <<= -ey + 1; + } else { + uyi &= u32::MAX >> 9; + uyi |= 1 << 23; + } + + /* x mod y */ + while ex > ey { + i = uxi - uyi; + if i >> 31 == 0 { + if i == 0 { + return 0.0 * x; + } + uxi = i; + } + uxi <<= 1; + + ex -= 1; + } + + i = uxi - uyi; + if i >> 31 == 0 { + if i == 0 { + return 0.0 * x; + } + uxi = i; + } + + while uxi >> 23 == 0 { + uxi <<= 1; + ex -= 1; + } + + /* scale result up */ + if ex > 0 { + uxi -= 1 << 23; + uxi |= (ex as u32) << 23; + } else { + uxi >>= -ex + 1; + } + uxi |= sx; + + f32::from_bits(uxi) +} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index cb2110f1fb7..41c20b2dae5 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -2,11 +2,13 @@ #![no_std] mod fabsf; +mod fmodf; mod powf; mod scalbnf; mod sqrtf; pub use fabsf::fabsf; +pub use fmodf::fmodf; pub use powf::powf; pub use scalbnf::scalbnf; pub use sqrtf::sqrtf; @@ -16,3 +18,7 @@ pub use sqrtf::sqrtf; pub fn _eqf(a: u32, b: u32) -> bool { (a as i32).wrapping_sub(b as i32).abs() <= 1 } + +fn isnanf(x: f32) -> bool { + x.to_bits() & 0x7fffffff > 0x7f800000 +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index c406cf340ed..3e58f7e1a08 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -225,6 +225,7 @@ f32_f32! { // With signature `fn(f32, f32) -> f32` f32f32_f32! { + fmodf, powf, } -- cgit 1.4.1-3-g733a5 From ec5784c1e80717407fe9d79eb7b3d4e6ed812233 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 12:43:25 -0500 Subject: update the README --- library/compiler-builtins/libm/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index fe384e118e9..ba82123460c 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -28,11 +28,18 @@ $ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh - Look for the C implementation of the function in the [MUSL source code][src]. - Copy paste the C code into a Rust file in the `src` directory and adjust `src/lib.rs` accordingly. - Run `cargo watch check` and fix the compiler errors. +- Tweak the bottom of `test-generator/src/main.rs` to add your function to the test suite. - If you can, run the test suite locally. If you can't, no problem! Your PR will be tested automatically. - Send us a pull request! - :tada: +[src]: https://git.musl-libc.org/cgit/musl/tree/src/math + +Check [PR #2] for an example. + +[PR #2]: https://github.com/japaric/libm/pull/2 + ### Notes - To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the @@ -44,7 +51,6 @@ $ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh - Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`] newtype to avoid this problem. -[src]: https://git.musl-libc.org/cgit/musl/tree/src/math [`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html ## Progress -- cgit 1.4.1-3-g733a5 From c044991ee3533505954ad2ddf0b0c713f8cc89f9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 13:23:40 -0500 Subject: fmodf is done --- library/compiler-builtins/libm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index ba82123460c..17c4ee94df5 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -75,7 +75,7 @@ cf. [rustwasm/team#84](https://github.com/rustwasm/team/issues/84). - [ ] fma - [ ] fmaf - [ ] fmod -- [ ] fmodf +- [x] fmodf - [ ] hypot - [ ] log - [ ] log10 -- cgit 1.4.1-3-g733a5 From b30af240ad49ec25e1799205c20ea5dd3e2d78c4 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 13:34:19 -0500 Subject: add comment about issue rust-lang/libm#4 --- library/compiler-builtins/libm/ci/script.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index caba616edd1..ee2e458cc03 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -7,6 +7,9 @@ main() { cargo fmt fi cross test --target $TARGET --release + + # TODO need to fix overflow issues (cf. issue #4) + # cross test --target $TARGET } main -- cgit 1.4.1-3-g733a5 From fdfc13afb9c52dca7fa67d93a5206b112d87f0d0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 14:24:02 -0500 Subject: add test infrastructure for f64 functions --- library/compiler-builtins/libm/README.md | 1 + library/compiler-builtins/libm/src/fabs.rs | 5 + library/compiler-builtins/libm/src/lib.rs | 7 + .../libm/test-generator/src/main.rs | 228 ++++++++++++++++++++- 4 files changed, 230 insertions(+), 11 deletions(-) create mode 100644 library/compiler-builtins/libm/src/fabs.rs diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 17c4ee94df5..a0b131733d2 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -96,6 +96,7 @@ cf. [rustwasm/team#84](https://github.com/rustwasm/team/issues/84). ### Other functions +- [x] fabs - [x] fabsf - [x] scalbnf - [x] sqrtf diff --git a/library/compiler-builtins/libm/src/fabs.rs b/library/compiler-builtins/libm/src/fabs.rs new file mode 100644 index 00000000000..993918efcfb --- /dev/null +++ b/library/compiler-builtins/libm/src/fabs.rs @@ -0,0 +1,5 @@ +use core::u64; + +pub fn fabs(x: f64) -> f64 { + f64::from_bits(x.to_bits() & (u64::MAX / 2)) +} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 41c20b2dae5..3f71fe876c6 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,12 +1,14 @@ #![deny(warnings)] #![no_std] +mod fabs; mod fabsf; mod fmodf; mod powf; mod scalbnf; mod sqrtf; +pub use fabs::fabs; pub use fabsf::fabsf; pub use fmodf::fmodf; pub use powf::powf; @@ -19,6 +21,11 @@ pub fn _eqf(a: u32, b: u32) -> bool { (a as i32).wrapping_sub(b as i32).abs() <= 1 } +#[doc(hidden)] +pub fn _eq(a: u64, b: u64) -> bool { + (a as i64).wrapping_sub(b as i64).abs() <= 1 +} + fn isnanf(x: f32) -> bool { x.to_bits() & 0x7fffffff > 0x7f800000 } diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 3e58f7e1a08..fb9154aecc6 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -10,14 +10,14 @@ use std::error::Error; use std::fmt::Write as _0; use std::fs::{self, File}; use std::io::Write as _1; -use std::{i16, u32, u8}; +use std::{i16, u16, u32, u64, u8}; use rand::{Rng, SeedableRng, XorShiftRng}; // Number of test cases to generate const NTESTS: usize = 10_000; -// TODO tweak this function to generate edge cases (zero, infinity, NaN) more often +// TODO tweak these functions to generate edge cases (zero, infinity, NaN) more often fn f32(rng: &mut XorShiftRng) -> f32 { let sign = if rng.gen_bool(0.5) { 1 << 31 } else { 0 }; let exponent = (rng.gen_range(0, u8::MAX) as u32) << 23; @@ -26,13 +26,21 @@ fn f32(rng: &mut XorShiftRng) -> f32 { f32::from_bits(sign + exponent + mantissa) } +fn f64(rng: &mut XorShiftRng) -> f64 { + let sign = if rng.gen_bool(0.5) { 1 << 63 } else { 0 }; + let exponent = (rng.gen_range(0, u16::MAX) as u64 & ((1 << 11) - 1)) << 52; + let mantissa = rng.gen_range(0, u64::MAX) & ((1 << 52) - 1); + + f64::from_bits(sign + exponent + mantissa) +} + // fn(f32) -> f32 macro_rules! f32_f32 { - ($($intr:ident,)+) => { + ($($intr:ident,)*) => { fn f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { // MUSL C implementation of the function to test extern "C" { - $(fn $intr(_: f32) -> f32;)+ + $(fn $intr(_: f32) -> f32;)* } $( @@ -78,18 +86,19 @@ macro_rules! f32_f32 { ", stringify!($intr), cases)?; - )+ + )* Ok(()) } } } +// fn(f32, f32) -> f32 macro_rules! f32f32_f32 { - ($($intr:ident,)+) => { + ($($intr:ident,)*) => { fn f32f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { extern "C" { - $(fn $intr(_: f32, _: f32) -> f32;)+ + $(fn $intr(_: f32, _: f32) -> f32;)* } $( @@ -137,18 +146,19 @@ macro_rules! f32f32_f32 { ", stringify!($intr), cases)?; - )+ + )* Ok(()) } }; } +// fn(f32, i32) -> f32 macro_rules! f32i32_f32 { - ($($intr:ident,)+) => { + ($($intr:ident,)*) => { fn f32i32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { extern "C" { - $(fn $intr(_: f32, _: i32) -> f32;)+ + $(fn $intr(_: f32, _: i32) -> f32;)* } $( @@ -195,7 +205,185 @@ macro_rules! f32i32_f32 { ", stringify!($intr), cases)?; - )+ + )* + + Ok(()) + } + }; +} + +// fn(f64) -> f64 +macro_rules! f64_f64 { + ($($intr:ident,)*) => { + fn f64_f64(rng: &mut XorShiftRng) -> Result<(), Box> { + // MUSL C implementation of the function to test + extern "C" { + $(fn $intr(_: f64) -> f64;)* + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let inp = f64(rng); + let out = unsafe { $intr(inp) }; + + let inp = inp.to_bits(); + let out = out.to_bits(); + + write!(cases, "({}, {})", inp, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[(u64, u64)] = &[ + {1} + ]; + + for case in CASES {{ + let (inp, expected) = *case; + + let outf = libm::{0}(f64::from_bits(inp)); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || + libm::_eq(outi, expected)) {{ + panic!( + \"input: {{}}, output: {{}}, expected: {{}}\", + inp, + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )* + + Ok(()) + } + } +} + +// fn(f64, f64) -> f64 +macro_rules! f64f64_f64 { + ($($intr:ident,)*) => { + fn f64f64_f64(rng: &mut XorShiftRng) -> Result<(), Box> { + extern "C" { + $(fn $intr(_: f64, _: f64) -> f64;)* + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let i1 = f64(rng); + let i2 = f64(rng); + let out = unsafe { $intr(i1, i2) }; + + let i1 = i1.to_bits(); + let i2 = i2.to_bits(); + let out = out.to_bits(); + + write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[((u64, u64), u64)] = &[ + {1} + ]; + + for case in CASES {{ + let ((i1, i2), expected) = *case; + + let outf = libm::{0}(f64::from_bits(i1), f64::from_bits(i2)); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || + libm::_eq(outi, expected)) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )* + + Ok(()) + } + }; +} + +// fn(f64, i32) -> f64 +macro_rules! f64i32_f64 { + ($($intr:ident,)*) => { + fn f64i32_f64(rng: &mut XorShiftRng) -> Result<(), Box> { + extern "C" { + $(fn $intr(_: f64, _: i32) -> f64;)* + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let i1 = f64(rng); + let i2 = rng.gen_range(i16::MIN, i16::MAX); + let out = unsafe { $intr(i1, i2 as i32) }; + + let i1 = i1.to_bits(); + let out = out.to_bits(); + + write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[((u64, i16), u64)] = &[ + {1} + ]; + + for case in CASES {{ + let ((i1, i2), expected) = *case; + + let outf = libm::{0}(f64::from_bits(i1), i2 as i32); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || + libm::_eq(outi, expected)) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )* Ok(()) } @@ -211,6 +399,9 @@ fn main() -> Result<(), Box> { f32_f32(&mut rng)?; f32f32_f32(&mut rng)?; f32i32_f32(&mut rng)?; + f64_f64(&mut rng)?; + f64f64_f64(&mut rng)?; + f64i32_f64(&mut rng)?; Ok(()) } @@ -233,3 +424,18 @@ f32f32_f32! { f32i32_f32! { scalbnf, } + +// With signature `fn(f64) -> f64` +f64_f64! { + fabs, +} + +// With signature `fn(f64, f64) -> f64` +f64f64_f64! { + // fmod, +} + +// With signature `fn(f64, i32) -> f64` +f64i32_f64! { + // scalbn, +} -- cgit 1.4.1-3-g733a5 From 3073bdd29a56b6866d1f1aff9cf5457ac860386a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 15:30:32 -0500 Subject: add more testing infrastructure --- .../libm/test-generator/src/main.rs | 188 +++++++++++++++++++++ 1 file changed, 188 insertions(+) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index fb9154aecc6..f933b34dcd0 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -58,6 +58,8 @@ macro_rules! f32_f32 { let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; write!(f, " + #![deny(warnings)] + extern crate libm; #[test] @@ -118,6 +120,8 @@ macro_rules! f32f32_f32 { let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; write!(f, " + #![deny(warnings)] + extern crate libm; #[test] @@ -153,6 +157,74 @@ macro_rules! f32f32_f32 { }; } +// fn(f32, f32, f32) -> f32 +macro_rules! f32f32f32_f32 { + ($($intr:ident,)*) => { + fn f32f32f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { + extern "C" { + $(fn $intr(_: f32, _: f32, _: f32) -> f32;)* + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let i1 = f32(rng); + let i2 = f32(rng); + let i3 = f32(rng); + let out = unsafe { $intr(i1, i2, i3) }; + + let i1 = i1.to_bits(); + let i2 = i2.to_bits(); + let i3 = i3.to_bits(); + let out = out.to_bits(); + + write!(cases, "(({}, {}, {}), {})", i1, i2, i3, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + #![deny(warnings)] + + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[((u32, u32, u32), u32)] = &[ + {1} + ]; + + for case in CASES {{ + let ((i1, i2, i3), expected) = *case; + + let outf = libm::{0}( + f32::from_bits(i1), + f32::from_bits(i2), + f32::from_bits(i3), + ); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || + libm::_eqf(outi, expected)) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2, i3), + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )* + + Ok(()) + } + }; +} + // fn(f32, i32) -> f32 macro_rules! f32i32_f32 { ($($intr:ident,)*) => { @@ -177,6 +249,8 @@ macro_rules! f32i32_f32 { let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; write!(f, " + #![deny(warnings)] + extern crate libm; #[test] @@ -236,6 +310,8 @@ macro_rules! f64_f64 { let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; write!(f, " + #![deny(warnings)] + extern crate libm; #[test] @@ -296,6 +372,8 @@ macro_rules! f64f64_f64 { let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; write!(f, " + #![deny(warnings)] + extern crate libm; #[test] @@ -331,6 +409,74 @@ macro_rules! f64f64_f64 { }; } +// fn(f64, f64, f64) -> f64 +macro_rules! f64f64f64_f64 { + ($($intr:ident,)*) => { + fn f64f64f64_f64(rng: &mut XorShiftRng) -> Result<(), Box> { + extern "C" { + $(fn $intr(_: f64, _: f64, _: f64) -> f64;)* + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let i1 = f64(rng); + let i2 = f64(rng); + let i3 = f64(rng); + let out = unsafe { $intr(i1, i2, i3) }; + + let i1 = i1.to_bits(); + let i2 = i2.to_bits(); + let i3 = i3.to_bits(); + let out = out.to_bits(); + + write!(cases, "(({}, {}, {}), {})", i1, i2, i3, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + #![deny(warnings)] + + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[((u64, u64, u64), u64)] = &[ + {1} + ]; + + for case in CASES {{ + let ((i1, i2, i3), expected) = *case; + + let outf = libm::{0}( + f64::from_bits(i1), + f64::from_bits(i2), + f64::from_bits(i3), + ); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || + libm::_eq(outi, expected)) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2, i3), + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )* + + Ok(()) + } + }; +} + // fn(f64, i32) -> f64 macro_rules! f64i32_f64 { ($($intr:ident,)*) => { @@ -355,6 +501,8 @@ macro_rules! f64i32_f64 { let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; write!(f, " + #![deny(warnings)] + extern crate libm; #[test] @@ -398,9 +546,11 @@ fn main() -> Result<(), Box> { f32_f32(&mut rng)?; f32f32_f32(&mut rng)?; + f32f32f32_f32(&mut rng)?; f32i32_f32(&mut rng)?; f64_f64(&mut rng)?; f64f64_f64(&mut rng)?; + f64f64f64_f64(&mut rng)?; f64i32_f64(&mut rng)?; Ok(()) @@ -410,6 +560,13 @@ fn main() -> Result<(), Box> { // With signature `fn(f32) -> f32` f32_f32! { + // cosf, + // exp2f, + // expf, + // log10f, + // log2f, + // roundf, + // sinf, fabsf, sqrtf, } @@ -420,6 +577,11 @@ f32f32_f32! { powf, } +// With signature `fn(f32, f32, f32) -> f32` +f32f32f32_f32! { + // fmaf, +} + // With signature `fn(f32, i32) -> f32` f32i32_f32! { scalbnf, @@ -427,12 +589,38 @@ f32i32_f32! { // With signature `fn(f64) -> f64` f64_f64! { + // acos, + // asin, + // atan, + // cbrt, + // cos, + // cosh, + // exp, + // exp2, + // expm1, + // log, + // log10, + // log1p, + // log2, + // round, + // sin, + // sinh, + // tan, + // tanh, fabs, } // With signature `fn(f64, f64) -> f64` f64f64_f64! { + // atan2, // fmod, + // hypot, + // pow, +} + +// With signature `fn(f64, f64, f64) -> f64` +f64f64f64_f64! { + // fma, } // With signature `fn(f64, i32) -> f64` -- cgit 1.4.1-3-g733a5 From 8440b96c93c017541c14a3a661aa87d9f9dd6d43 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 15:50:06 -0500 Subject: bors-ng support --- library/compiler-builtins/libm/.travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index 4d8ccc784c6..0c083279347 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -30,3 +30,9 @@ cache: cargo before_cache: - chmod -R a+r $HOME/.cargo; + +branches: + only: + - master + - staging + - trying -- cgit 1.4.1-3-g733a5 From 333d27ab6ac14b315ff826f381596c50b49b97c3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 18:26:39 -0500 Subject: add more commented out tests --- .../compiler-builtins/libm/test-generator/src/main.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index f933b34dcd0..a13aa4ef705 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -560,19 +560,33 @@ fn main() -> Result<(), Box> { // With signature `fn(f32) -> f32` f32_f32! { + // acosf, + // floorf, + // truncf + // asinf, + // atanf, + // cbrtf, + // ceilf, // cosf, + // coshf, // exp2f, // expf, + // fdimf, // log10f, // log2f, // roundf, // sinf, + // sinhf, + // tanf, + // tanhf, fabsf, sqrtf, } // With signature `fn(f32, f32) -> f32` f32f32_f32! { + // atan2f, + // hypotf, fmodf, powf, } @@ -593,11 +607,13 @@ f64_f64! { // asin, // atan, // cbrt, + // ceil, // cos, // cosh, // exp, // exp2, // expm1, + // floor, // log, // log10, // log1p, @@ -605,14 +621,17 @@ f64_f64! { // round, // sin, // sinh, + // sqrt, // tan, // tanh, + // trunc, fabs, } // With signature `fn(f64, f64) -> f64` f64f64_f64! { // atan2, + // fdim, // fmod, // hypot, // pow, -- cgit 1.4.1-3-g733a5 From f31abe2da16d9529d35a8d335998b1e35e2f853b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 18:43:59 -0500 Subject: update the README --- library/compiler-builtins/libm/README.md | 56 ++++---------------------------- 1 file changed, 7 insertions(+), 49 deletions(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index a0b131733d2..841199a9f03 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -4,6 +4,11 @@ A port of [MUSL]'s libm to Rust. [MUSL]: https://www.musl-libc.org/ +## Goals + +The short term goal of this library is to enable math support (e.g. `sin`, `atan2`) for the +`wasm32-unknown-unknown` target. The longer term goal is to enable math support in the `core` crate. + ## Testing The test suite of this crate can only be run on x86_64 Linux systems. @@ -24,7 +29,7 @@ $ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh ## Contributing -- Pick your favorite math function from the list below. +- Pick your favorite math function from the [issue tracker]. - Look for the C implementation of the function in the [MUSL source code][src]. - Copy paste the C code into a Rust file in the `src` directory and adjust `src/lib.rs` accordingly. - Run `cargo watch check` and fix the compiler errors. @@ -34,6 +39,7 @@ $ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh - Send us a pull request! - :tada: +[issue tracker]: https://github.com/japaric/libm/issues [src]: https://git.musl-libc.org/cgit/musl/tree/src/math Check [PR #2] for an example. @@ -53,54 +59,6 @@ Check [PR #2] for an example. [`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html -## Progress - -### Functions wanted by the wasm WG - -cf. [rustwasm/team#84](https://github.com/rustwasm/team/issues/84). - -- [ ] acos -- [ ] asin -- [ ] atan -- [ ] atan2 -- [ ] cbrt -- [ ] cos -- [ ] cosf -- [ ] cosh -- [ ] exp -- [ ] exp2 -- [ ] exp2f -- [ ] expf -- [ ] expm1 -- [ ] fma -- [ ] fmaf -- [ ] fmod -- [x] fmodf -- [ ] hypot -- [ ] log -- [ ] log10 -- [ ] log10f -- [ ] log1p -- [ ] log2 -- [ ] log2f -- [ ] logf -- [ ] pow -- [x] powf -- [ ] round -- [ ] roundf -- [ ] sin -- [ ] sinf -- [ ] sinh -- [ ] tan -- [ ] tanh - -### Other functions - -- [x] fabs -- [x] fabsf -- [x] scalbnf -- [x] sqrtf - ## License Licensed under either of -- cgit 1.4.1-3-g733a5 From a9e77402601377fa9e9e37924956cf70061eaf7d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 19:16:50 -0500 Subject: re-structure for compiler-builtins integration --- library/compiler-builtins/libm/README.md | 3 +- library/compiler-builtins/libm/src/fabs.rs | 5 - library/compiler-builtins/libm/src/fabsf.rs | 3 - library/compiler-builtins/libm/src/fmodf.rs | 89 ------ library/compiler-builtins/libm/src/lib.rs | 18 +- library/compiler-builtins/libm/src/math/fabs.rs | 6 + library/compiler-builtins/libm/src/math/fabsf.rs | 4 + library/compiler-builtins/libm/src/math/fmodf.rs | 90 ++++++ library/compiler-builtins/libm/src/math/mod.rs | 17 ++ library/compiler-builtins/libm/src/math/powf.rs | 327 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/scalbnf.rs | 35 +++ library/compiler-builtins/libm/src/math/sqrtf.rs | 84 ++++++ library/compiler-builtins/libm/src/powf.rs | 326 -------------------- library/compiler-builtins/libm/src/scalbnf.rs | 34 --- library/compiler-builtins/libm/src/sqrtf.rs | 83 ------ 15 files changed, 567 insertions(+), 557 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/fabs.rs delete mode 100644 library/compiler-builtins/libm/src/fabsf.rs delete mode 100644 library/compiler-builtins/libm/src/fmodf.rs create mode 100644 library/compiler-builtins/libm/src/math/fabs.rs create mode 100644 library/compiler-builtins/libm/src/math/fabsf.rs create mode 100644 library/compiler-builtins/libm/src/math/fmodf.rs create mode 100644 library/compiler-builtins/libm/src/math/mod.rs create mode 100644 library/compiler-builtins/libm/src/math/powf.rs create mode 100644 library/compiler-builtins/libm/src/math/scalbnf.rs create mode 100644 library/compiler-builtins/libm/src/math/sqrtf.rs delete mode 100644 library/compiler-builtins/libm/src/powf.rs delete mode 100644 library/compiler-builtins/libm/src/scalbnf.rs delete mode 100644 library/compiler-builtins/libm/src/sqrtf.rs diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 841199a9f03..55f4654346e 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -31,7 +31,8 @@ $ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh - Pick your favorite math function from the [issue tracker]. - Look for the C implementation of the function in the [MUSL source code][src]. -- Copy paste the C code into a Rust file in the `src` directory and adjust `src/lib.rs` accordingly. +- Copy paste the C code into a Rust file in the `src/math` directory and adjust `src/math/mod.rs` + accordingly. - Run `cargo watch check` and fix the compiler errors. - Tweak the bottom of `test-generator/src/main.rs` to add your function to the test suite. - If you can, run the test suite locally. If you can't, no problem! Your PR will be tested diff --git a/library/compiler-builtins/libm/src/fabs.rs b/library/compiler-builtins/libm/src/fabs.rs deleted file mode 100644 index 993918efcfb..00000000000 --- a/library/compiler-builtins/libm/src/fabs.rs +++ /dev/null @@ -1,5 +0,0 @@ -use core::u64; - -pub fn fabs(x: f64) -> f64 { - f64::from_bits(x.to_bits() & (u64::MAX / 2)) -} diff --git a/library/compiler-builtins/libm/src/fabsf.rs b/library/compiler-builtins/libm/src/fabsf.rs deleted file mode 100644 index be60d06cc8d..00000000000 --- a/library/compiler-builtins/libm/src/fabsf.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub fn fabsf(x: f32) -> f32 { - f32::from_bits(x.to_bits() & 0x7fffffff) -} diff --git a/library/compiler-builtins/libm/src/fmodf.rs b/library/compiler-builtins/libm/src/fmodf.rs deleted file mode 100644 index a184411a182..00000000000 --- a/library/compiler-builtins/libm/src/fmodf.rs +++ /dev/null @@ -1,89 +0,0 @@ -use core::u32; - -use isnanf; - -pub fn fmodf(x: f32, y: f32) -> f32 { - let mut uxi = x.to_bits(); - let mut uyi = y.to_bits(); - let mut ex = (uxi >> 23 & 0xff) as i32; - let mut ey = (uyi >> 23 & 0xff) as i32; - let sx = uxi & 0x80000000; - let mut i; - - if uyi << 1 == 0 || isnanf(y) || ex == 0xff { - return (x * y) / (x * y); - } - - if uxi << 1 <= uyi << 1 { - if uxi << 1 == uyi << 1 { - return 0.0 * x; - } - - return x; - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 9; - while i >> 31 == 0 { - ex -= 1; - i <<= 1; - } - - uxi <<= -ex + 1; - } else { - uxi &= u32::MAX >> 9; - uxi |= 1 << 23; - } - - if ey == 0 { - i = uyi << 9; - while i >> 31 == 0 { - ey -= 1; - i <<= 1; - } - - uyi <<= -ey + 1; - } else { - uyi &= u32::MAX >> 9; - uyi |= 1 << 23; - } - - /* x mod y */ - while ex > ey { - i = uxi - uyi; - if i >> 31 == 0 { - if i == 0 { - return 0.0 * x; - } - uxi = i; - } - uxi <<= 1; - - ex -= 1; - } - - i = uxi - uyi; - if i >> 31 == 0 { - if i == 0 { - return 0.0 * x; - } - uxi = i; - } - - while uxi >> 23 == 0 { - uxi <<= 1; - ex -= 1; - } - - /* scale result up */ - if ex > 0 { - uxi -= 1 << 23; - uxi |= (ex as u32) << 23; - } else { - uxi >>= -ex + 1; - } - uxi |= sx; - - f32::from_bits(uxi) -} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 3f71fe876c6..4d7cec56f9d 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,19 +1,9 @@ #![deny(warnings)] #![no_std] -mod fabs; -mod fabsf; -mod fmodf; -mod powf; -mod scalbnf; -mod sqrtf; +mod math; -pub use fabs::fabs; -pub use fabsf::fabsf; -pub use fmodf::fmodf; -pub use powf::powf; -pub use scalbnf::scalbnf; -pub use sqrtf::sqrtf; +pub use math::*; /// Approximate equality with 1 ULP of tolerance #[doc(hidden)] @@ -25,7 +15,3 @@ pub fn _eqf(a: u32, b: u32) -> bool { pub fn _eq(a: u64, b: u64) -> bool { (a as i64).wrapping_sub(b as i64).abs() <= 1 } - -fn isnanf(x: f32) -> bool { - x.to_bits() & 0x7fffffff > 0x7f800000 -} diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs new file mode 100644 index 00000000000..9e081f3f9f6 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -0,0 +1,6 @@ +use core::u64; + +#[inline] +pub fn fabs(x: f64) -> f64 { + f64::from_bits(x.to_bits() & (u64::MAX / 2)) +} diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs new file mode 100644 index 00000000000..4cc9411169a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -0,0 +1,4 @@ +#[inline] +pub fn fabsf(x: f32) -> f32 { + f32::from_bits(x.to_bits() & 0x7fffffff) +} diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs new file mode 100644 index 00000000000..90977524908 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -0,0 +1,90 @@ +use core::u32; + +use super::isnanf; + +#[inline] +pub fn fmodf(x: f32, y: f32) -> f32 { + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let mut ex = (uxi >> 23 & 0xff) as i32; + let mut ey = (uyi >> 23 & 0xff) as i32; + let sx = uxi & 0x80000000; + let mut i; + + if uyi << 1 == 0 || isnanf(y) || ex == 0xff { + return (x * y) / (x * y); + } + + if uxi << 1 <= uyi << 1 { + if uxi << 1 == uyi << 1 { + return 0.0 * x; + } + + return x; + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 9; + while i >> 31 == 0 { + ex -= 1; + i <<= 1; + } + + uxi <<= -ex + 1; + } else { + uxi &= u32::MAX >> 9; + uxi |= 1 << 23; + } + + if ey == 0 { + i = uyi << 9; + while i >> 31 == 0 { + ey -= 1; + i <<= 1; + } + + uyi <<= -ey + 1; + } else { + uyi &= u32::MAX >> 9; + uyi |= 1 << 23; + } + + /* x mod y */ + while ex > ey { + i = uxi - uyi; + if i >> 31 == 0 { + if i == 0 { + return 0.0 * x; + } + uxi = i; + } + uxi <<= 1; + + ex -= 1; + } + + i = uxi - uyi; + if i >> 31 == 0 { + if i == 0 { + return 0.0 * x; + } + uxi = i; + } + + while uxi >> 23 == 0 { + uxi <<= 1; + ex -= 1; + } + + /* scale result up */ + if ex > 0 { + uxi -= 1 << 23; + uxi |= (ex as u32) << 23; + } else { + uxi >>= -ex + 1; + } + uxi |= sx; + + f32::from_bits(uxi) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs new file mode 100644 index 00000000000..09d81944c27 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -0,0 +1,17 @@ +mod fabs; +mod fabsf; +mod fmodf; +mod powf; +mod scalbnf; +mod sqrtf; + +pub use self::fabs::fabs; +pub use self::fabsf::fabsf; +pub use self::fmodf::fmodf; +pub use self::powf::powf; +pub use self::scalbnf::scalbnf; +pub use self::sqrtf::sqrtf; + +fn isnanf(x: f32) -> bool { + x.to_bits() & 0x7fffffff > 0x7f800000 +} diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs new file mode 100644 index 00000000000..f1dc3a5b867 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -0,0 +1,327 @@ +use super::{fabsf, scalbnf, sqrtf}; + +const BP: [f32; 2] = [1.0, 1.5]; +const DP_H: [f32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ +const DP_L: [f32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ +const TWO24: f32 = 16777216.0; /* 0x4b800000 */ +const HUGE: f32 = 1.0e30; +const TINY: f32 = 1.0e-30; +const L1: f32 = 6.0000002384e-01; /* 0x3f19999a */ +const L2: f32 = 4.2857143283e-01; /* 0x3edb6db7 */ +const L3: f32 = 3.3333334327e-01; /* 0x3eaaaaab */ +const L4: f32 = 2.7272811532e-01; /* 0x3e8ba305 */ +const L5: f32 = 2.3066075146e-01; /* 0x3e6c3255 */ +const L6: f32 = 2.0697501302e-01; /* 0x3e53f142 */ +const P1: f32 = 1.6666667163e-01; /* 0x3e2aaaab */ +const P2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const P3: f32 = 6.6137559770e-05; /* 0x388ab355 */ +const P4: f32 = -1.6533901999e-06; /* 0xb5ddea0e */ +const P5: f32 = 4.1381369442e-08; /* 0x3331bb4c */ +const LG2: f32 = 6.9314718246e-01; /* 0x3f317218 */ +const LG2_H: f32 = 6.93145752e-01; /* 0x3f317200 */ +const LG2_L: f32 = 1.42860654e-06; /* 0x35bfbe8c */ +const OVT: f32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ +const CP: f32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ +const CP_H: f32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ +const CP_L: f32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ +const IVLN2: f32 = 1.4426950216e+00; +const IVLN2_H: f32 = 1.4426879883e+00; +const IVLN2_L: f32 = 7.0526075433e-06; + +#[inline] +pub fn powf(x: f32, y: f32) -> f32 { + let mut z: f32; + let mut ax: f32; + let z_h: f32; + let z_l: f32; + let mut p_h: f32; + let mut p_l: f32; + let y1: f32; + let mut t1: f32; + let t2: f32; + let mut r: f32; + let s: f32; + let mut sn: f32; + let mut t: f32; + let mut u: f32; + let mut v: f32; + let mut w: f32; + let i: i32; + let mut j: i32; + let mut k: i32; + let mut yisint: i32; + let mut n: i32; + let hx: i32; + let hy: i32; + let mut ix: i32; + let iy: i32; + let mut is: i32; + + hx = x.to_bits() as i32; + hy = y.to_bits() as i32; + + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if iy == 0 { + return 1.0; + } + + /* 1**y = 1, even if y is NaN */ + if hx == 0x3f800000 { + return 1.0; + } + + /* NaN if either arg is NaN */ + if ix > 0x7f800000 || iy > 0x7f800000 { + return x + y; + } + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if hx < 0 { + if iy >= 0x4b800000 { + yisint = 2; /* even integer y */ + } else if iy >= 0x3f800000 { + k = (iy >> 23) - 0x7f; /* exponent */ + j = iy >> (23 - k); + if (j << (23 - k)) == iy { + yisint = 2 - (j & 1); + } + } + } + + /* special value of y */ + if iy == 0x7f800000 { + /* y is +-inf */ + if ix == 0x3f800000 { + /* (-1)**+-inf is 1 */ + return 1.0; + } else if ix > 0x3f800000 { + /* (|x|>1)**+-inf = inf,0 */ + return if hy >= 0 { y } else { 0.0 }; + } else { + /* (|x|<1)**+-inf = 0,inf */ + return if hy >= 0 { 0.0 } else { -y }; + } + } + if iy == 0x3f800000 { + /* y is +-1 */ + return if hy >= 0 { x } else { 1.0 / x }; + } + + if hy == 0x40000000 { + /* y is 2 */ + return x * x; + } + + if hy == 0x3f000000 { + /* y is 0.5 */ + if hx >= 0 { + /* x >= +0 */ + return sqrtf(x); + } + } + + ax = fabsf(x); + /* special value of x */ + if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 { + /* x is +-0,+-inf,+-1 */ + z = ax; + if hy < 0 { + /* z = (1/|x|) */ + z = 1.0 / z; + } + + if hx < 0 { + if ((ix - 0x3f800000) | yisint) == 0 { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } else if yisint == 1 { + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + } + return z; + } + + sn = 1.0; /* sign of result */ + if hx < 0 { + if yisint == 0 { + /* (x<0)**(non-int) is NaN */ + return (x - x) / (x - x); + } + + if yisint == 1 { + /* (x<0)**(odd int) */ + sn = -1.0; + } + } + + /* |y| is HUGE */ + if iy > 0x4d000000 { + /* if |y| > 2**27 */ + /* over/underflow if x is not close to one */ + if ix < 0x3f7ffff8 { + return if hy < 0 { + sn * HUGE * HUGE + } else { + sn * TINY * TINY + }; + } + + if ix > 0x3f800007 { + return if hy > 0 { + sn * HUGE * HUGE + } else { + sn * TINY * TINY + }; + } + + /* now |1-x| is TINY <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1.; /* t has 20 trailing zeros */ + w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); + u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ + v = t * IVLN2_L - w * IVLN2; + t1 = u + v; + is = t1.to_bits() as i32; + t1 = f32::from_bits(is as u32 & 0xfffff000); + t2 = v - (t1 - u); + } else { + let mut s2: f32; + let mut s_h: f32; + let s_l: f32; + let mut t_h: f32; + let mut t_l: f32; + + n = 0; + /* take care subnormal number */ + if ix < 0x00800000 { + ax *= TWO24; + n -= 24; + ix = ax.to_bits() as i32; + } + n += ((ix) >> 23) - 0x7f; + j = ix & 0x007fffff; + /* determine interval */ + ix = j | 0x3f800000; /* normalize ix */ + if j <= 0x1cc471 { + /* |x|> 1) & 0xfffff000) | 0x20000000) as i32; + t_h = f32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); + t_l = ax - (t_h - BP[k as usize]); + s_l = v * ((u - s_h * t_h) - s_h * t_l); + /* compute log(ax) */ + s2 = s * s; + r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); + r += s_l * (s_h + s); + s2 = s_h * s_h; + t_h = 3.0 + s2 + r; + is = t_h.to_bits() as i32; + t_h = f32::from_bits(is as u32 & 0xfffff000); + t_l = r - ((t_h - 3.0) - s2); + /* u+v = s*(1+...) */ + u = s_h * t_h; + v = s_l * t_h + t_l * s; + /* 2/(3log2)*(s+...) */ + p_h = u + v; + is = p_h.to_bits() as i32; + p_h = f32::from_bits(is as u32 & 0xfffff000); + p_l = v - (p_h - u); + z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = CP_L * p_h + p_l * CP + DP_L[k as usize]; + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = n as f32; + t1 = ((z_h + z_l) + DP_H[k as usize]) + t; + is = t1.to_bits() as i32; + t1 = f32::from_bits(is as u32 & 0xfffff000); + t2 = z_l - (((t1 - t) - DP_H[k as usize]) - z_h); + }; + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + is = y.to_bits() as i32; + y1 = f32::from_bits(is as u32 & 0xfffff000); + p_l = (y - y1) * t1 + y * t2; + p_h = y1 * t1; + z = p_l + p_h; + j = z.to_bits() as i32; + if j > 0x43000000 { + /* if z > 128 */ + return sn * HUGE * HUGE; /* overflow */ + } else if j == 0x43000000 { + /* if z == 128 */ + if p_l + OVT > z - p_h { + return sn * HUGE * HUGE; /* overflow */ + } + } else if (j & 0x7fffffff) > 0x43160000 { + /* z < -150 */ + // FIXME: check should be (uint32_t)j > 0xc3160000 + return sn * TINY * TINY; /* underflow */ + } else if j as u32 == 0xc3160000 { + /* z == -150 */ + if p_l <= z - p_h { + return sn * TINY * TINY; /* underflow */ + } + } + + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i >> 23) - 0x7f; + n = 0; + if i > 0x3f000000 { + /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00800000 >> (k + 1)); + k = ((n & 0x7fffffff) >> 23) - 0x7f; /* new k for n */ + t = f32::from_bits(n as u32 & !(0x007fffff >> k)); + n = ((n & 0x007fffff) | 0x00800000) >> (23 - k); + if j < 0 { + n = -n; + } + p_h -= t; + } + t = p_l + p_h; + is = t.to_bits() as i32; + t = f32::from_bits(is as u32 & 0xffff8000); + u = t * LG2_H; + v = (p_l - (t - p_h)) * LG2 + t * LG2_L; + z = u + v; + w = v - (z - u); + t = z * z; + t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + r = (z * t1) / (t1 - 2.0) - (w + z * w); + z = 1.0 - (r - z); + j = z.to_bits() as i32; + j += n << 23; + if (j >> 23) <= 0 { + /* subnormal output */ + z = scalbnf(z, n); + } else { + z = f32::from_bits(j as u32); + } + return sn * z; +} diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs new file mode 100644 index 00000000000..2ae8bf31b77 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/scalbnf.rs @@ -0,0 +1,35 @@ +#[inline] +pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 + let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 + + let mut y: f32 = x; + + if n > 127 { + y *= x1p127; + n -= 127; + if n > 127 { + y *= x1p127; + n -= 127; + if n > 127 { + n = 127; + } + } + } else if n < -126 { + y *= x1p_126; + y *= x1p24; + n += 126 - 24; + if n < -126 { + y *= x1p_126; + y *= x1p24; + n += 126 - 24; + if n < -126 { + n = -126; + } + } + } + + x = y * f32::from_bits((0x7f + n as u32) << 23); + x +} diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs new file mode 100644 index 00000000000..a265bef48eb --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -0,0 +1,84 @@ +const TINY: f32 = 1.0e-30; + +#[inline] +pub fn sqrtf(x: f32) -> f32 { + let mut z: f32; + let sign: i32 = 0x80000000u32 as i32; + let mut ix: i32; + let mut s: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: u32; + + ix = x.to_bits() as i32; + + /* take care of Inf and NaN */ + if (ix as u32 & 0x7f800000) == 0x7f800000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + + /* take care of zero */ + if ix <= 0 { + if (ix & !sign) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } + + /* normalize x */ + m = ix >> 23; + if m == 0 { + /* subnormal x */ + i = 0; + while ix & 0x00800000 == 0 { + ix <<= 1; + i = i + 1; + } + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if m & 1 == 1 { + /* odd m, double x to make it even */ + ix += ix; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = 0; + s = 0; + r = 0x01000000; /* r = moving bit from right to left */ + + while r != 0 { + t = s + r as i32; + if t <= ix { + s = t + r as i32; + ix -= t; + q += r as i32; + } + ix += ix; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if ix != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if z > 1.0 { + q += 2; + } else { + q += q & 1; + } + } + } + + ix = (q >> 1) + 0x3f000000; + ix += m << 23; + f32::from_bits(ix as u32) +} diff --git a/library/compiler-builtins/libm/src/powf.rs b/library/compiler-builtins/libm/src/powf.rs deleted file mode 100644 index 770987c2a09..00000000000 --- a/library/compiler-builtins/libm/src/powf.rs +++ /dev/null @@ -1,326 +0,0 @@ -use {scalbnf, sqrtf}; - -const BP: [f32; 2] = [1.0, 1.5]; -const DP_H: [f32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ -const DP_L: [f32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ -const TWO24: f32 = 16777216.0; /* 0x4b800000 */ -const HUGE: f32 = 1.0e30; -const TINY: f32 = 1.0e-30; -const L1: f32 = 6.0000002384e-01; /* 0x3f19999a */ -const L2: f32 = 4.2857143283e-01; /* 0x3edb6db7 */ -const L3: f32 = 3.3333334327e-01; /* 0x3eaaaaab */ -const L4: f32 = 2.7272811532e-01; /* 0x3e8ba305 */ -const L5: f32 = 2.3066075146e-01; /* 0x3e6c3255 */ -const L6: f32 = 2.0697501302e-01; /* 0x3e53f142 */ -const P1: f32 = 1.6666667163e-01; /* 0x3e2aaaab */ -const P2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ -const P3: f32 = 6.6137559770e-05; /* 0x388ab355 */ -const P4: f32 = -1.6533901999e-06; /* 0xb5ddea0e */ -const P5: f32 = 4.1381369442e-08; /* 0x3331bb4c */ -const LG2: f32 = 6.9314718246e-01; /* 0x3f317218 */ -const LG2_H: f32 = 6.93145752e-01; /* 0x3f317200 */ -const LG2_L: f32 = 1.42860654e-06; /* 0x35bfbe8c */ -const OVT: f32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ -const CP: f32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ -const CP_H: f32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ -const CP_L: f32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ -const IVLN2: f32 = 1.4426950216e+00; -const IVLN2_H: f32 = 1.4426879883e+00; -const IVLN2_L: f32 = 7.0526075433e-06; - -pub fn powf(x: f32, y: f32) -> f32 { - let mut z: f32; - let mut ax: f32; - let z_h: f32; - let z_l: f32; - let mut p_h: f32; - let mut p_l: f32; - let y1: f32; - let mut t1: f32; - let t2: f32; - let mut r: f32; - let s: f32; - let mut sn: f32; - let mut t: f32; - let mut u: f32; - let mut v: f32; - let mut w: f32; - let i: i32; - let mut j: i32; - let mut k: i32; - let mut yisint: i32; - let mut n: i32; - let hx: i32; - let hy: i32; - let mut ix: i32; - let iy: i32; - let mut is: i32; - - hx = x.to_bits() as i32; - hy = y.to_bits() as i32; - - ix = hx & 0x7fffffff; - iy = hy & 0x7fffffff; - - /* x**0 = 1, even if x is NaN */ - if iy == 0 { - return 1.0; - } - - /* 1**y = 1, even if y is NaN */ - if hx == 0x3f800000 { - return 1.0; - } - - /* NaN if either arg is NaN */ - if ix > 0x7f800000 || iy > 0x7f800000 { - return x + y; - } - - /* determine if y is an odd int when x < 0 - * yisint = 0 ... y is not an integer - * yisint = 1 ... y is an odd int - * yisint = 2 ... y is an even int - */ - yisint = 0; - if hx < 0 { - if iy >= 0x4b800000 { - yisint = 2; /* even integer y */ - } else if iy >= 0x3f800000 { - k = (iy >> 23) - 0x7f; /* exponent */ - j = iy >> (23 - k); - if (j << (23 - k)) == iy { - yisint = 2 - (j & 1); - } - } - } - - /* special value of y */ - if iy == 0x7f800000 { - /* y is +-inf */ - if ix == 0x3f800000 { - /* (-1)**+-inf is 1 */ - return 1.0; - } else if ix > 0x3f800000 { - /* (|x|>1)**+-inf = inf,0 */ - return if hy >= 0 { y } else { 0.0 }; - } else { - /* (|x|<1)**+-inf = 0,inf */ - return if hy >= 0 { 0.0 } else { -y }; - } - } - if iy == 0x3f800000 { - /* y is +-1 */ - return if hy >= 0 { x } else { 1.0 / x }; - } - - if hy == 0x40000000 { - /* y is 2 */ - return x * x; - } - - if hy == 0x3f000000 { - /* y is 0.5 */ - if hx >= 0 { - /* x >= +0 */ - return sqrtf(x); - } - } - - ax = ::fabsf(x); - /* special value of x */ - if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 { - /* x is +-0,+-inf,+-1 */ - z = ax; - if hy < 0 { - /* z = (1/|x|) */ - z = 1.0 / z; - } - - if hx < 0 { - if ((ix - 0x3f800000) | yisint) == 0 { - z = (z - z) / (z - z); /* (-1)**non-int is NaN */ - } else if yisint == 1 { - z = -z; /* (x<0)**odd = -(|x|**odd) */ - } - } - return z; - } - - sn = 1.0; /* sign of result */ - if hx < 0 { - if yisint == 0 { - /* (x<0)**(non-int) is NaN */ - return (x - x) / (x - x); - } - - if yisint == 1 { - /* (x<0)**(odd int) */ - sn = -1.0; - } - } - - /* |y| is HUGE */ - if iy > 0x4d000000 { - /* if |y| > 2**27 */ - /* over/underflow if x is not close to one */ - if ix < 0x3f7ffff8 { - return if hy < 0 { - sn * HUGE * HUGE - } else { - sn * TINY * TINY - }; - } - - if ix > 0x3f800007 { - return if hy > 0 { - sn * HUGE * HUGE - } else { - sn * TINY * TINY - }; - } - - /* now |1-x| is TINY <= 2**-20, suffice to compute - log(x) by x-x^2/2+x^3/3-x^4/4 */ - t = ax - 1.; /* t has 20 trailing zeros */ - w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); - u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ - v = t * IVLN2_L - w * IVLN2; - t1 = u + v; - is = t1.to_bits() as i32; - t1 = f32::from_bits(is as u32 & 0xfffff000); - t2 = v - (t1 - u); - } else { - let mut s2: f32; - let mut s_h: f32; - let s_l: f32; - let mut t_h: f32; - let mut t_l: f32; - - n = 0; - /* take care subnormal number */ - if ix < 0x00800000 { - ax *= TWO24; - n -= 24; - ix = ax.to_bits() as i32; - } - n += ((ix) >> 23) - 0x7f; - j = ix & 0x007fffff; - /* determine interval */ - ix = j | 0x3f800000; /* normalize ix */ - if j <= 0x1cc471 { - /* |x|> 1) & 0xfffff000) | 0x20000000) as i32; - t_h = f32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); - t_l = ax - (t_h - BP[k as usize]); - s_l = v * ((u - s_h * t_h) - s_h * t_l); - /* compute log(ax) */ - s2 = s * s; - r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); - r += s_l * (s_h + s); - s2 = s_h * s_h; - t_h = 3.0 + s2 + r; - is = t_h.to_bits() as i32; - t_h = f32::from_bits(is as u32 & 0xfffff000); - t_l = r - ((t_h - 3.0) - s2); - /* u+v = s*(1+...) */ - u = s_h * t_h; - v = s_l * t_h + t_l * s; - /* 2/(3log2)*(s+...) */ - p_h = u + v; - is = p_h.to_bits() as i32; - p_h = f32::from_bits(is as u32 & 0xfffff000); - p_l = v - (p_h - u); - z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ - z_l = CP_L * p_h + p_l * CP + DP_L[k as usize]; - /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ - t = n as f32; - t1 = ((z_h + z_l) + DP_H[k as usize]) + t; - is = t1.to_bits() as i32; - t1 = f32::from_bits(is as u32 & 0xfffff000); - t2 = z_l - (((t1 - t) - DP_H[k as usize]) - z_h); - }; - - /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ - is = y.to_bits() as i32; - y1 = f32::from_bits(is as u32 & 0xfffff000); - p_l = (y - y1) * t1 + y * t2; - p_h = y1 * t1; - z = p_l + p_h; - j = z.to_bits() as i32; - if j > 0x43000000 { - /* if z > 128 */ - return sn * HUGE * HUGE; /* overflow */ - } else if j == 0x43000000 { - /* if z == 128 */ - if p_l + OVT > z - p_h { - return sn * HUGE * HUGE; /* overflow */ - } - } else if (j & 0x7fffffff) > 0x43160000 { - /* z < -150 */ - // FIXME: check should be (uint32_t)j > 0xc3160000 - return sn * TINY * TINY; /* underflow */ - } else if j as u32 == 0xc3160000 { - /* z == -150 */ - if p_l <= z - p_h { - return sn * TINY * TINY; /* underflow */ - } - } - - /* - * compute 2**(p_h+p_l) - */ - i = j & 0x7fffffff; - k = (i >> 23) - 0x7f; - n = 0; - if i > 0x3f000000 { - /* if |z| > 0.5, set n = [z+0.5] */ - n = j + (0x00800000 >> (k + 1)); - k = ((n & 0x7fffffff) >> 23) - 0x7f; /* new k for n */ - t = f32::from_bits(n as u32 & !(0x007fffff >> k)); - n = ((n & 0x007fffff) | 0x00800000) >> (23 - k); - if j < 0 { - n = -n; - } - p_h -= t; - } - t = p_l + p_h; - is = t.to_bits() as i32; - t = f32::from_bits(is as u32 & 0xffff8000); - u = t * LG2_H; - v = (p_l - (t - p_h)) * LG2 + t * LG2_L; - z = u + v; - w = v - (z - u); - t = z * z; - t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); - r = (z * t1) / (t1 - 2.0) - (w + z * w); - z = 1.0 - (r - z); - j = z.to_bits() as i32; - j += n << 23; - if (j >> 23) <= 0 { - /* subnormal output */ - z = scalbnf(z, n); - } else { - z = f32::from_bits(j as u32); - } - return sn * z; -} diff --git a/library/compiler-builtins/libm/src/scalbnf.rs b/library/compiler-builtins/libm/src/scalbnf.rs deleted file mode 100644 index 2c057ebc57d..00000000000 --- a/library/compiler-builtins/libm/src/scalbnf.rs +++ /dev/null @@ -1,34 +0,0 @@ -pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 - let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 - - let mut y: f32 = x; - - if n > 127 { - y *= x1p127; - n -= 127; - if n > 127 { - y *= x1p127; - n -= 127; - if n > 127 { - n = 127; - } - } - } else if n < -126 { - y *= x1p_126; - y *= x1p24; - n += 126 - 24; - if n < -126 { - y *= x1p_126; - y *= x1p24; - n += 126 - 24; - if n < -126 { - n = -126; - } - } - } - - x = y * f32::from_bits((0x7f + n as u32) << 23); - x -} diff --git a/library/compiler-builtins/libm/src/sqrtf.rs b/library/compiler-builtins/libm/src/sqrtf.rs deleted file mode 100644 index 6e92f67d4ab..00000000000 --- a/library/compiler-builtins/libm/src/sqrtf.rs +++ /dev/null @@ -1,83 +0,0 @@ -const TINY: f32 = 1.0e-30; - -pub fn sqrtf(x: f32) -> f32 { - let mut z: f32; - let sign: i32 = 0x80000000u32 as i32; - let mut ix: i32; - let mut s: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: u32; - - ix = x.to_bits() as i32; - - /* take care of Inf and NaN */ - if (ix as u32 & 0x7f800000) == 0x7f800000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } - - /* take care of zero */ - if ix <= 0 { - if (ix & !sign) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } - - /* normalize x */ - m = ix >> 23; - if m == 0 { - /* subnormal x */ - i = 0; - while ix & 0x00800000 == 0 { - ix <<= 1; - i = i + 1; - } - m -= i - 1; - } - m -= 127; /* unbias exponent */ - ix = (ix & 0x007fffff) | 0x00800000; - if m & 1 == 1 { - /* odd m, double x to make it even */ - ix += ix; - } - m >>= 1; /* m = [m/2] */ - - /* generate sqrt(x) bit by bit */ - ix += ix; - q = 0; - s = 0; - r = 0x01000000; /* r = moving bit from right to left */ - - while r != 0 { - t = s + r as i32; - if t <= ix { - s = t + r as i32; - ix -= t; - q += r as i32; - } - ix += ix; - r >>= 1; - } - - /* use floating add to find out rounding direction */ - if ix != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if z > 1.0 { - q += 2; - } else { - q += q & 1; - } - } - } - - ix = (q >> 1) + 0x3f000000; - ix += m << 23; - f32::from_bits(ix as u32) -} -- cgit 1.4.1-3-g733a5 From 7aafbaa6042f38635f437762b0a4078cea4a72b9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 19:57:44 -0500 Subject: add extension traits --- library/compiler-builtins/libm/src/lib.rs | 690 ++++++++++++++++++++++++++++++ 1 file changed, 690 insertions(+) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 4d7cec56f9d..fc9628d919f 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,8 +1,22 @@ +//! Port of MUSL's libm to Rust +//! +//! # Usage +//! +//! You can use this crate in two ways: +//! +//! - By directly using its free functions, e.g. `libm::powf`. +//! +//! - By importing the `F32Ext` and / or `F64Ext` extension traits to add methods like `powf` to the +//! `f32` and `f64` types. Then you'll be able to invoke math functions as methods, e.g. `x.sqrt()`. + #![deny(warnings)] #![no_std] mod math; +#[cfg(todo)] +use core::{f32, f64}; + pub use math::*; /// Approximate equality with 1 ULP of tolerance @@ -15,3 +29,679 @@ pub fn _eqf(a: u32, b: u32) -> bool { pub fn _eq(a: u64, b: u64) -> bool { (a as i64).wrapping_sub(b as i64).abs() <= 1 } + +/// Math support for `f32` +/// +/// NOTE this meant to be a closed extension trait. The only stable way to use this trait is to +/// import it to access its methods. +pub trait F32Ext { + #[cfg(todo)] + fn floor(self) -> Self; + + #[cfg(todo)] + fn ceil(self) -> Self; + + #[cfg(todo)] + fn round(self) -> Self; + + #[cfg(todo)] + fn trunc(self) -> Self; + + #[cfg(todo)] + fn fract(self) -> Self; + + fn abs(self) -> Self; + + #[cfg(todo)] + fn signum(self) -> Self; + + #[cfg(todo)] + fn mul_add(self, a: Self, b: Self) -> Self; + + #[cfg(todo)] + fn div_euc(self, rhs: Self) -> Self; + + #[cfg(todo)] + fn mod_euc(self, rhs: Self) -> Self; + + // NOTE depends on unstable intrinsics::powif32 + // fn powi(self, n: i32) -> Self; + + fn powf(self, n: Self) -> Self; + + fn sqrt(self) -> Self; + + #[cfg(todo)] + fn exp(self) -> Self; + + #[cfg(todo)] + fn exp2(self) -> Self; + + #[cfg(todo)] + fn ln(self) -> Self; + + #[cfg(todo)] + fn log(self, base: Self) -> Self; + + #[cfg(todo)] + fn log2(self) -> Self; + + #[cfg(todo)] + fn log10(self) -> Self; + + #[cfg(todo)] + fn cbrt(self) -> Self; + + #[cfg(todo)] + fn hypot(self, other: Self) -> Self; + + #[cfg(todo)] + fn sin(self) -> Self; + + #[cfg(todo)] + fn cos(self) -> Self; + + #[cfg(todo)] + fn tan(self) -> Self; + + #[cfg(todo)] + fn asin(self) -> Self; + + #[cfg(todo)] + fn acos(self) -> Self; + + #[cfg(todo)] + fn atan(self) -> Self; + + #[cfg(todo)] + fn atan2(self, other: Self) -> Self; + + #[cfg(todo)] + #[inline] + fn sin_cos(self) -> (Self, Self) { + (self.sin(), self.cos()) + } + + #[cfg(todo)] + fn exp_m1(self) -> Self; + + #[cfg(todo)] + fn ln_1p(self) -> Self; + + #[cfg(todo)] + fn sinh(self) -> Self; + + #[cfg(todo)] + fn cosh(self) -> Self; + + #[cfg(todo)] + fn tanh(self) -> Self; + + #[cfg(todo)] + fn asinh(self) -> Self; + + #[cfg(todo)] + fn acosh(self) -> Self; + + #[cfg(todo)] + fn atanh(self) -> Self; +} + +impl F32Ext for f32 { + #[cfg(todo)] + #[inline] + fn floor(self) -> Self { + floorf(self) + } + + #[cfg(todo)] + #[inline] + fn ceil(self) -> Self { + ceilf(self) + } + + #[cfg(todo)] + #[inline] + fn round(self) -> Self { + roundf(self) + } + + #[cfg(todo)] + #[inline] + fn trunc(self) -> Self { + truncf(self) + } + + #[cfg(todo)] + #[inline] + fn fract(self) -> Self { + self - self.trunc() + } + + #[inline] + fn abs(self) -> Self { + fabsf(self) + } + + #[cfg(todo)] + #[inline] + fn mul_add(self, a: Self, b: Self) -> Self { + fmaf(self, a, b) + } + + #[cfg(todo)] + #[inline] + fn div_euc(self, rhs: Self) -> Self { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q + } + + #[cfg(todo)] + #[inline] + fn mod_euc(self, rhs: f32) -> f32 { + let r = self % rhs; + if r < 0.0 { + r + rhs.abs() + } else { + r + } + } + + #[inline] + fn powf(self, n: Self) -> Self { + powf(self, n) + } + + #[inline] + fn sqrt(self) -> Self { + sqrtf(self) + } + + #[cfg(todo)] + #[inline] + fn exp(self) -> Self { + expf(self) + } + + #[cfg(todo)] + #[inline] + fn exp2(self) -> Self { + exp2f(self) + } + + #[cfg(todo)] + #[inline] + fn ln(self) -> Self { + logf(self) + } + + #[cfg(todo)] + #[inline] + fn log(self, base: Self) -> Self { + self.ln() / base.ln() + } + + #[cfg(todo)] + #[inline] + fn log2(self) -> Self { + log2f(self) + } + + #[cfg(todo)] + #[inline] + fn log10(self) -> Self { + log10f(self) + } + + #[cfg(todo)] + #[inline] + fn cbrt(self) -> Self { + cbrtf(self) + } + + #[cfg(todo)] + #[inline] + fn hypot(self, other: Self) -> Self { + hypotf(self, other) + } + + #[cfg(todo)] + #[inline] + fn sin(self) -> Self { + sinf(self) + } + + #[cfg(todo)] + #[inline] + fn cos(self) -> Self { + cosf(self) + } + + #[cfg(todo)] + #[inline] + fn tan(self) -> Self { + tanf(self) + } + + #[cfg(todo)] + #[inline] + fn asin(self) -> Self { + asinf(self) + } + + #[cfg(todo)] + #[inline] + fn acos(self) -> Self { + acosf(self) + } + + #[cfg(todo)] + #[inline] + fn atan(self) -> Self { + atanf(self) + } + + #[cfg(todo)] + #[inline] + fn atan2(self, other: Self) -> Self { + atan2f(self, other) + } + + #[cfg(todo)] + #[inline] + fn exp_m1(self) -> Self { + expm1f(self) + } + + #[cfg(todo)] + #[inline] + fn ln_1p(self) -> Self { + log1pf(self) + } + + #[cfg(todo)] + #[inline] + fn sinh(self) -> Self { + sinhf(self) + } + + #[cfg(todo)] + #[inline] + fn cosh(self) -> Self { + coshf(self) + } + + #[cfg(todo)] + #[inline] + fn tanh(self) -> Self { + tanhf(self) + } + + #[cfg(todo)] + #[inline] + fn asinh(self) -> Self { + if self == f32::NEG_INFINITY { + f32::NEG_INFINITY + } else { + (self + ((self * self) + 1.0).sqrt()).ln() + } + } + + #[cfg(todo)] + #[inline] + fn acosh(self) -> Self { + match self { + x if x < 1.0 => f32::NAN, + x => (x + ((x * x) - 1.0).sqrt()).ln(), + } + } + + #[cfg(todo)] + #[inline] + fn atanh(self) -> Self { + 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() + } +} + +/// Math support for `f32` +/// +/// NOTE this meant to be a closed extension trait. The only stable way to use this trait is to +/// import it to access its methods. +pub trait F64Ext { + #[cfg(todo)] + fn floor(self) -> Self; + + #[cfg(todo)] + fn ceil(self) -> Self; + + #[cfg(todo)] + fn round(self) -> Self; + + #[cfg(todo)] + fn trunc(self) -> Self; + + #[cfg(todo)] + fn fract(self) -> Self; + + fn abs(self) -> Self; + + #[cfg(todo)] + fn signum(self) -> Self; + + #[cfg(todo)] + fn mul_add(self, a: Self, b: Self) -> Self; + + #[cfg(todo)] + fn div_euc(self, rhs: Self) -> Self; + + #[cfg(todo)] + fn mod_euc(self, rhs: Self) -> Self; + + // NOTE depends on unstable intrinsics::powif64 + // fn powi(self, n: i32) -> Self; + + #[cfg(todo)] + fn powf(self, n: Self) -> Self; + + #[cfg(todo)] + fn sqrt(self) -> Self; + + #[cfg(todo)] + fn exp(self) -> Self; + + #[cfg(todo)] + fn exp2(self) -> Self; + + #[cfg(todo)] + fn ln(self) -> Self; + + #[cfg(todo)] + fn log(self, base: Self) -> Self; + + #[cfg(todo)] + fn log2(self) -> Self; + + #[cfg(todo)] + fn log10(self) -> Self; + + #[cfg(todo)] + fn cbrt(self) -> Self; + + #[cfg(todo)] + fn hypot(self, other: Self) -> Self; + + #[cfg(todo)] + fn sin(self) -> Self; + + #[cfg(todo)] + fn cos(self) -> Self; + + #[cfg(todo)] + fn tan(self) -> Self; + + #[cfg(todo)] + fn asin(self) -> Self; + + #[cfg(todo)] + fn acos(self) -> Self; + + #[cfg(todo)] + fn atan(self) -> Self; + + #[cfg(todo)] + fn atan2(self, other: Self) -> Self; + + #[cfg(todo)] + #[inline] + fn sin_cos(self) -> (Self, Self) { + (self.sin(), self.cos()) + } + + #[cfg(todo)] + fn exp_m1(self) -> Self; + + #[cfg(todo)] + fn ln_1p(self) -> Self; + + #[cfg(todo)] + fn sinh(self) -> Self; + + #[cfg(todo)] + fn cosh(self) -> Self; + + #[cfg(todo)] + fn tanh(self) -> Self; + + #[cfg(todo)] + fn asinh(self) -> Self; + + #[cfg(todo)] + fn acosh(self) -> Self; + + #[cfg(todo)] + fn atanh(self) -> Self; +} + +impl F64Ext for f64 { + #[cfg(todo)] + #[inline] + fn floor(self) -> Self { + floor(self) + } + + #[cfg(todo)] + #[inline] + fn ceil(self) -> Self { + ceil(self) + } + + #[cfg(todo)] + #[inline] + fn round(self) -> Self { + round(self) + } + + #[cfg(todo)] + #[inline] + fn trunc(self) -> Self { + trunc(self) + } + + #[cfg(todo)] + #[inline] + fn fract(self) -> Self { + self - self.trunc() + } + + #[inline] + fn abs(self) -> Self { + fabs(self) + } + + #[cfg(todo)] + #[inline] + fn mul_add(self, a: Self, b: Self) -> Self { + fma(self, a, b) + } + + #[cfg(todo)] + #[inline] + fn div_euc(self, rhs: Self) -> Self { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q + } + + #[cfg(todo)] + #[inline] + fn mod_euc(self, rhs: f32) -> f32 { + let r = self % rhs; + if r < 0.0 { + r + rhs.abs() + } else { + r + } + } + + #[cfg(todo)] + #[inline] + fn powf(self, n: Self) -> Self { + pow(self, n) + } + + #[cfg(todo)] + #[inline] + fn sqrt(self) -> Self { + sqrt(self) + } + + #[cfg(todo)] + #[inline] + fn exp(self) -> Self { + exp(self) + } + + #[cfg(todo)] + #[inline] + fn exp2(self) -> Self { + exp2(self) + } + + #[cfg(todo)] + #[inline] + fn ln(self) -> Self { + log(self) + } + + #[cfg(todo)] + #[inline] + fn log(self, base: Self) -> Self { + self.ln() / base.ln() + } + + #[cfg(todo)] + #[inline] + fn log2(self) -> Self { + log2(self) + } + + #[cfg(todo)] + #[inline] + fn log10(self) -> Self { + log10(self) + } + + #[cfg(todo)] + #[inline] + fn cbrt(self) -> Self { + cbrt(self) + } + + #[cfg(todo)] + #[inline] + fn hypot(self, other: Self) -> Self { + hypot(self, other) + } + + #[cfg(todo)] + #[inline] + fn sin(self) -> Self { + sin(self) + } + + #[cfg(todo)] + #[inline] + fn cos(self) -> Self { + cos(self) + } + + #[cfg(todo)] + #[inline] + fn tan(self) -> Self { + tan(self) + } + + #[cfg(todo)] + #[inline] + fn asin(self) -> Self { + asin(self) + } + + #[cfg(todo)] + #[inline] + fn acos(self) -> Self { + acos(self) + } + + #[cfg(todo)] + #[inline] + fn atan(self) -> Self { + atan(self) + } + + #[cfg(todo)] + #[inline] + fn atan2(self, other: Self) -> Self { + atan2(self, other) + } + + #[cfg(todo)] + #[inline] + fn exp_m1(self) -> Self { + expm1(self) + } + + #[cfg(todo)] + #[inline] + fn ln_1p(self) -> Self { + log1p(self) + } + + #[cfg(todo)] + #[inline] + fn sinh(self) -> Self { + sinh(self) + } + + #[cfg(todo)] + #[inline] + fn cosh(self) -> Self { + cosh(self) + } + + #[cfg(todo)] + #[inline] + fn tanh(self) -> Self { + tanh(self) + } + + #[cfg(todo)] + #[inline] + fn asinh(self) -> Self { + if self == f64::NEG_INFINITY { + f64::NEG_INFINITY + } else { + (self + ((self * self) + 1.0).sqrt()).ln() + } + } + + #[cfg(todo)] + #[inline] + fn acosh(self) -> Self { + match self { + x if x < 1.0 => f64::NAN, + x => (x + ((x * x) - 1.0).sqrt()).ln(), + } + } + + #[cfg(todo)] + #[inline] + fn atanh(self) -> Self { + 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() + } +} -- cgit 1.4.1-3-g733a5 From f556a9bbb422e86c76334fe3fe0a3c0382707946 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 20:19:42 -0500 Subject: test source importing this crate --- library/compiler-builtins/libm/Cargo.toml | 2 +- library/compiler-builtins/libm/README.md | 5 ++++- library/compiler-builtins/libm/cb/Cargo.toml | 6 ++++++ library/compiler-builtins/libm/cb/src/lib.rs | 9 +++++++++ library/compiler-builtins/libm/ci/script.sh | 10 ++++++++++ 5 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/cb/Cargo.toml create mode 100644 library/compiler-builtins/libm/cb/src/lib.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 96bc290fb32..e3498eed038 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" authors = ["Jorge Aparicio "] [workspace] -members = ["test-generator"] \ No newline at end of file +members = ["cb", "test-generator"] \ No newline at end of file diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 55f4654346e..cb29baf63a7 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -32,7 +32,7 @@ $ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh - Pick your favorite math function from the [issue tracker]. - Look for the C implementation of the function in the [MUSL source code][src]. - Copy paste the C code into a Rust file in the `src/math` directory and adjust `src/math/mod.rs` - accordingly. + accordingly. Also, uncomment the corresponding trait method in `src/lib.rs`. - Run `cargo watch check` and fix the compiler errors. - Tweak the bottom of `test-generator/src/main.rs` to add your function to the test suite. - If you can, run the test suite locally. If you can't, no problem! Your PR will be tested @@ -49,6 +49,9 @@ Check [PR #2] for an example. ### Notes +- Only use relative imports within the `math` directory / module, e.g. `use self::fabs::fabs` or +`use super::isnanf`. Absolute imports from core are OK, e.g. `use core::u64`. + - To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the `GET_FLOAT_WORD` macro, or a union, to do this operation. diff --git a/library/compiler-builtins/libm/cb/Cargo.toml b/library/compiler-builtins/libm/cb/Cargo.toml new file mode 100644 index 00000000000..40e75dd22fd --- /dev/null +++ b/library/compiler-builtins/libm/cb/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "cb" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[dependencies] diff --git a/library/compiler-builtins/libm/cb/src/lib.rs b/library/compiler-builtins/libm/cb/src/lib.rs new file mode 100644 index 00000000000..439ba7dc4e6 --- /dev/null +++ b/library/compiler-builtins/libm/cb/src/lib.rs @@ -0,0 +1,9 @@ +//! Fake compiler-builtins crate +//! +//! This is used to test that we can source import `libm` into the compiler-builtins crate. + +#![allow(dead_code)] +#![no_std] + +#[path = "../../src/math/mod.rs"] +mod libm; diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index ee2e458cc03..3db6bfeb12d 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -1,11 +1,21 @@ set -euxo pipefail main() { + # quick check + cargo check + + # check that we can source import libm into compiler-builtins + cargo check --package cb + + # generate tests cargo run --package test-generator --target x86_64-unknown-linux-musl + if cargo fmt --version >/dev/null 2>&1; then # nicer syntax error messages (if any) cargo fmt fi + + # run tests cross test --target $TARGET --release # TODO need to fix overflow issues (cf. issue #4) -- cgit 1.4.1-3-g733a5 From 50f9ad97a58576c4c8aecdf392242736fc11efd8 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 13 Jul 2018 00:40:05 +0000 Subject: Implement `round` --- library/compiler-builtins/libm/src/lib.rs | 6 ++++ library/compiler-builtins/libm/src/math/mod.rs | 2 ++ library/compiler-builtins/libm/src/math/round.rs | 35 ++++++++++++++++++++++ .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/src/math/round.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index fc9628d919f..f54366b95ae 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -12,6 +12,12 @@ #![deny(warnings)] #![no_std] +macro_rules! force_eval { + ($e:expr) => { + unsafe { ::core::ptr::read_volatile(&$e); } + } +} + mod math; #[cfg(todo)] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 09d81944c27..c150a629516 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -2,6 +2,7 @@ mod fabs; mod fabsf; mod fmodf; mod powf; +mod round; mod scalbnf; mod sqrtf; @@ -9,6 +10,7 @@ pub use self::fabs::fabs; pub use self::fabsf::fabsf; pub use self::fmodf::fmodf; pub use self::powf::powf; +pub use self::round::round; pub use self::scalbnf::scalbnf; pub use self::sqrtf::sqrtf; diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs new file mode 100644 index 00000000000..2a9f67c1d0f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -0,0 +1,35 @@ +use core::f64; + +const TOINT: f64 = 1.0 / f64::EPSILON; + +pub fn round(mut x: f64) -> f64 { + let (f, i) = (x, x.to_bits()); + let e: u64 = i >> 52 & 0x7ff; + let mut y: f64; + + if e >= 0x3ff + 52 { + return x; + } + if i >> 63 != 0 { + x = -x; + } + if e < 0x3ff - 1 { + // raise inexact if x!=0 + force_eval!(x + TOINT); + return 0.0 * f; + } + y = x + TOINT - TOINT - x; + if y > 0.5 { + y = y + x - 1.0; + } else if y <= -0.5 { + y = y + x + 1.0; + } else { + y = y + x; + } + + if i >> 63 != 0 { + -y + } else { + y + } +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index a13aa4ef705..5ff78ffc8b3 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -618,7 +618,7 @@ f64_f64! { // log10, // log1p, // log2, - // round, + round, // sin, // sinh, // sqrt, -- cgit 1.4.1-3-g733a5 From 3accabd018c1645817d0b0cd234be6c5eae4d73a Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 13 Jul 2018 01:25:46 +0000 Subject: Enable f64::round --- library/compiler-builtins/libm/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index f54366b95ae..06ef4592dce 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -383,7 +383,6 @@ pub trait F64Ext { #[cfg(todo)] fn ceil(self) -> Self; - #[cfg(todo)] fn round(self) -> Self; #[cfg(todo)] @@ -504,7 +503,6 @@ impl F64Ext for f64 { ceil(self) } - #[cfg(todo)] #[inline] fn round(self) -> Self { round(self) -- cgit 1.4.1-3-g733a5 From 9395c8002c0bacb90a2a0008ddf709c775ce5a90 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 13 Jul 2018 01:38:04 +0000 Subject: Move the `force_eval!` macro into the math module This fixes the cross-inclusion into the compiler builtins --- library/compiler-builtins/libm/src/lib.rs | 6 ------ library/compiler-builtins/libm/src/math/mod.rs | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 06ef4592dce..0d13590c7ec 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -12,12 +12,6 @@ #![deny(warnings)] #![no_std] -macro_rules! force_eval { - ($e:expr) => { - unsafe { ::core::ptr::read_volatile(&$e); } - } -} - mod math; #[cfg(todo)] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c150a629516..41359bf8c05 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -1,3 +1,9 @@ +macro_rules! force_eval { + ($e:expr) => { + unsafe { ::core::ptr::read_volatile(&$e); } + } +} + mod fabs; mod fabsf; mod fmodf; -- cgit 1.4.1-3-g733a5 From 505e4ce81c019550d6e90986dc5b328fbc6fd7cc Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 13 Jul 2018 11:10:41 +0300 Subject: add exp and log/ln functions for f32 --- library/compiler-builtins/libm/src/lib.rs | 6 -- library/compiler-builtins/libm/src/math/expf.rs | 76 +++++++++++++++++++++++++ library/compiler-builtins/libm/src/math/logf.rs | 49 ++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 4 ++ 4 files changed, 129 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/expf.rs create mode 100644 library/compiler-builtins/libm/src/math/logf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0d13590c7ec..bb00149dfd2 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -71,16 +71,13 @@ pub trait F32Ext { fn sqrt(self) -> Self; - #[cfg(todo)] fn exp(self) -> Self; #[cfg(todo)] fn exp2(self) -> Self; - #[cfg(todo)] fn ln(self) -> Self; - #[cfg(todo)] fn log(self, base: Self) -> Self; #[cfg(todo)] @@ -220,7 +217,6 @@ impl F32Ext for f32 { sqrtf(self) } - #[cfg(todo)] #[inline] fn exp(self) -> Self { expf(self) @@ -232,13 +228,11 @@ impl F32Ext for f32 { exp2f(self) } - #[cfg(todo)] #[inline] fn ln(self) -> Self { logf(self) } - #[cfg(todo)] #[inline] fn log(self, base: Self) -> Self { self.ln() / base.ln() diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs new file mode 100644 index 00000000000..c26ff8e6412 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -0,0 +1,76 @@ +use super::scalbnf; + +const HALF : [f32; 2] = [0.5,-0.5]; +const LN2_HI : f32 = 6.9314575195e-01; /* 0x3f317200 */ +const LN2_LO : f32 = 1.4286067653e-06; /* 0x35bfbe8e */ +const INV_LN2 : f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: + * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 + */ +const P1 : f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ +const P2 : f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ + +#[inline] +pub fn expf(mut x: f32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ + + let mut hx = x.to_bits() as i32; + let sign = (hx >> 31) as i32; /* sign bit of x */ + let signb : bool = sign != 0; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if hx >= 0x42aeac50 { /* if |x| >= -87.33655f or NaN */ + if hx > 0x7f800000 {/* NaN */ + return x; + } + if (hx >= 0x42b17218) && (!signb) { /* x >= 88.722839f */ + /* overflow */ + x *= x1p127; + return x; + } + if signb { + /* underflow */ + force_eval!(-x1p_126/x); + if hx >= 0x42cff1b5 { /* x <= -103.972084f */ + return 0. + } + } + } + + /* argument reduction */ + let k : i32; + let hi : f32; + let lo : f32; + if hx > 0x3eb17218 { /* if |x| > 0.5 ln2 */ + if hx > 0x3f851592 { /* if |x| > 1.5 ln2 */ + k = (INV_LN2*x + HALF[sign as usize]) as i32; + } else { + k = 1 - sign - sign; + } + let kf = k as f32; + hi = x - kf*LN2_HI; /* k*ln2hi is exact here */ + lo = kf*LN2_LO; + x = hi - lo; + } else if hx > 0x39000000 { /* |x| > 2**-14 */ + k = 0; + hi = x; + lo = 0.; + } else { + /* raise inexact */ + force_eval!(x1p127 + x); + return 1. + x; + } + + /* x is now in primary range */ + let xx = x*x; + let c = x - xx*(P1+xx*P2); + let y = 1. + (x*c/(2.-c) - lo + hi); + if k == 0 { + y + } else { + scalbnf(y, k) + } +} diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs new file mode 100644 index 00000000000..f8bbe733aa8 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -0,0 +1,49 @@ +const LN2_HI : f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO : f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1 : f32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ +const LG2 : f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3 : f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4 : f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +#[inline] +pub fn logf(mut x: f32) -> f32 { + let x1p25 = f32::from_bits(0x4c000000); // 0x1p24f === 2 ^ 25 + + let mut ix = x.to_bits(); + let mut k = 0i32; + + if (ix < 0x00800000) || ((ix>>31) != 0) { /* x < 2**-126 */ + if ix<<1 == 0 { + return -1./(x*x); /* log(+-0)=-inf */ + } + if (ix>>31) != 0 { + return (x-x)/0.; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25; + ix = x.to_bits(); + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += ((ix>>23) as i32) - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + x = f32::from_bits(ix); + + let f = x - 1.; + let s = f/(2. + f); + let z = s*s; + let w = z*z; + let t1 = w*(LG2+w*LG4); + let t2 = z*(LG1+w*LG3); + let r = t2 + t1; + let hfsq = 0.5*f*f; + let dk = k as f32; + s*(hfsq+r) + dk*LN2_LO - hfsq + f + dk*LN2_HI +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 41359bf8c05..5edf6fd740d 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -11,6 +11,8 @@ mod powf; mod round; mod scalbnf; mod sqrtf; +mod logf; +mod expf; pub use self::fabs::fabs; pub use self::fabsf::fabsf; @@ -19,6 +21,8 @@ pub use self::powf::powf; pub use self::round::round; pub use self::scalbnf::scalbnf; pub use self::sqrtf::sqrtf; +pub use self::logf::logf; +pub use self::expf::expf; fn isnanf(x: f32) -> bool { x.to_bits() & 0x7fffffff > 0x7f800000 -- cgit 1.4.1-3-g733a5 From b8aae8ef23d18bcd03f75252a2164d87da833b9a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 11:16:43 -0500 Subject: enable tests for expf and logf --- library/compiler-builtins/libm/test-generator/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 5ff78ffc8b3..d324c4f09f6 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -570,10 +570,11 @@ f32_f32! { // cosf, // coshf, // exp2f, - // expf, + expf, // fdimf, // log10f, // log2f, + logf, // roundf, // sinf, // sinhf, -- cgit 1.4.1-3-g733a5 From 7e419befa1bf59fde2ac4fdd3fd44464e9e1b3c6 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 13 Jul 2018 21:02:11 +0300 Subject: add floor, scalbn; fixes in expf, scalbnf --- library/compiler-builtins/libm/src/lib.rs | 2 -- library/compiler-builtins/libm/src/math/expf.rs | 8 +++--- library/compiler-builtins/libm/src/math/floor.rs | 29 +++++++++++++++++++ library/compiler-builtins/libm/src/math/logf.rs | 2 +- library/compiler-builtins/libm/src/math/mod.rs | 26 +++++++++++------ library/compiler-builtins/libm/src/math/scalbn.rs | 33 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/scalbnf.rs | 26 +++++++---------- 7 files changed, 94 insertions(+), 32 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/floor.rs create mode 100644 library/compiler-builtins/libm/src/math/scalbn.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index bb00149dfd2..ed163ff98c7 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -365,7 +365,6 @@ impl F32Ext for f32 { /// NOTE this meant to be a closed extension trait. The only stable way to use this trait is to /// import it to access its methods. pub trait F64Ext { - #[cfg(todo)] fn floor(self) -> Self; #[cfg(todo)] @@ -479,7 +478,6 @@ pub trait F64Ext { } impl F64Ext for f64 { - #[cfg(todo)] #[inline] fn floor(self) -> Self { floor(self) diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index c26ff8e6412..1b645654e36 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -13,16 +13,16 @@ const P2 : f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ #[inline] pub fn expf(mut x: f32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ - let mut hx = x.to_bits() as i32; + let mut hx = x.to_bits(); let sign = (hx >> 31) as i32; /* sign bit of x */ let signb : bool = sign != 0; hx &= 0x7fffffff; /* high word of |x| */ /* special cases */ - if hx >= 0x42aeac50 { /* if |x| >= -87.33655f or NaN */ + if hx >= 0x42aeac50 { /* if |x| >= -87.33655f or NaN */ if hx > 0x7f800000 {/* NaN */ return x; } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs new file mode 100644 index 00000000000..a5fb1757413 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -0,0 +1,29 @@ +use core::f64; + +const TOINT : f64 = 1. / f64::EPSILON; + +#[inline] +pub fn floor(x : f64) -> f64 { + let ui = x.to_bits(); + let e = ((ui >> 52) & 0x7ff) as i32; + + if (e >= 0x3ff+52) || (x == 0.) { + return x; + } + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + let y = if (ui >> 63) != 0 { + x - TOINT + TOINT - x + } else { + x + TOINT - TOINT - x + }; + /* special case because of non-nearest rounding modes */ + if e <= 0x3ff-1 { + force_eval!(y); + return if (ui >> 63) != 0 { -1. } else { 0. }; + } + if y > 0. { + x + y - 1. + } else { + x + y + } +} diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs index f8bbe733aa8..76b4ede1951 100644 --- a/library/compiler-builtins/libm/src/math/logf.rs +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -8,7 +8,7 @@ const LG4 : f32 = 0.24279078841; /* 0xf89e26.0p-26 */ #[inline] pub fn logf(mut x: f32) -> f32 { - let x1p25 = f32::from_bits(0x4c000000); // 0x1p24f === 2 ^ 25 + let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 let mut ix = x.to_bits(); let mut k = 0i32; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 5edf6fd740d..e400badd129 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -9,20 +9,28 @@ mod fabsf; mod fmodf; mod powf; mod round; +mod scalbn; mod scalbnf; mod sqrtf; mod logf; mod expf; +mod floor; -pub use self::fabs::fabs; -pub use self::fabsf::fabsf; -pub use self::fmodf::fmodf; -pub use self::powf::powf; -pub use self::round::round; -pub use self::scalbnf::scalbnf; -pub use self::sqrtf::sqrtf; -pub use self::logf::logf; -pub use self::expf::expf; +//mod service; + +pub use self::{ + fabs::fabs, + fabsf::fabsf, + fmodf::fmodf, + powf::powf, + round::round, + scalbn::scalbn, + scalbnf::scalbnf, + sqrtf::sqrtf, + logf::logf, + expf::expf, + floor::floor, +}; fn isnanf(x: f32) -> bool { x.to_bits() & 0x7fffffff > 0x7f800000 diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs new file mode 100644 index 00000000000..76e06f03ece --- /dev/null +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -0,0 +1,33 @@ +#[inline] +pub fn scalbn(x : f64, mut n: i32) -> f64 { + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 + let x1p53 = f64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53 + let x1p_1022 = f64::from_bits(0x0010000000000000); // 0x1p-1022 === 2 ^ (-1022) + + let mut y = x; + + if n > 1023 { + y *= x1p1023; + n -= 1023; + if n > 1023 { + y *= x1p1023; + n -= 1023; + if n > 1023 { + n = 1023; + } + } + } else if n < -1022 { + /* make sure final n < -53 to avoid double + rounding in the subnormal range */ + y *= x1p_1022 * x1p53; + n += 1022 - 53; + if n < -1022 { + y *= x1p_1022 * x1p53; + n += 1022 - 53; + if n < -1022 { + n = -1022; + } + } + } + y*f64::from_bits(((0x3ff+n) as u64)<<52) +} diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs index 2ae8bf31b77..31f93d323c5 100644 --- a/library/compiler-builtins/libm/src/math/scalbnf.rs +++ b/library/compiler-builtins/libm/src/math/scalbnf.rs @@ -1,35 +1,29 @@ #[inline] -pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 - let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 - - let mut y: f32 = x; - +pub fn scalbnf(mut x: f32, mut n : i32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 + let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 + if n > 127 { - y *= x1p127; + x *= x1p127; n -= 127; if n > 127 { - y *= x1p127; + x *= x1p127; n -= 127; if n > 127 { n = 127; } } } else if n < -126 { - y *= x1p_126; - y *= x1p24; + x *= x1p_126 * x1p24; n += 126 - 24; if n < -126 { - y *= x1p_126; - y *= x1p24; + x *= x1p_126 * x1p24; n += 126 - 24; if n < -126 { n = -126; } } } - - x = y * f32::from_bits((0x7f + n as u32) << 23); - x + x * f32::from_bits(((0x7f+n) as u32)<<23) } -- cgit 1.4.1-3-g733a5 From 47afc3992ff0df14d89b65f1d8834c62930201a7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 13:36:59 -0500 Subject: enable tests for floor and scalbn --- library/compiler-builtins/libm/test-generator/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index d324c4f09f6..42e157ad876 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -614,7 +614,7 @@ f64_f64! { // exp, // exp2, // expm1, - // floor, + floor, // log, // log10, // log1p, @@ -645,5 +645,5 @@ f64f64f64_f64! { // With signature `fn(f64, i32) -> f64` f64i32_f64! { - // scalbn, + scalbn, } -- cgit 1.4.1-3-g733a5 From 8cdd2678306ce916daa42ac6d9f49cd5a7e0473b Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 13 Jul 2018 16:04:30 -0400 Subject: implement trunc and truncf --- library/compiler-builtins/libm/src/lib.rs | 4 ---- library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ library/compiler-builtins/libm/src/math/trunc.rs | 24 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/truncf.rs | 24 ++++++++++++++++++++++ .../libm/test-generator/src/main.rs | 4 ++-- 5 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/trunc.rs create mode 100644 library/compiler-builtins/libm/src/math/truncf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index ed163ff98c7..fa709ad754a 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -44,7 +44,6 @@ pub trait F32Ext { #[cfg(todo)] fn round(self) -> Self; - #[cfg(todo)] fn trunc(self) -> Self; #[cfg(todo)] @@ -163,7 +162,6 @@ impl F32Ext for f32 { roundf(self) } - #[cfg(todo)] #[inline] fn trunc(self) -> Self { truncf(self) @@ -372,7 +370,6 @@ pub trait F64Ext { fn round(self) -> Self; - #[cfg(todo)] fn trunc(self) -> Self; #[cfg(todo)] @@ -494,7 +491,6 @@ impl F64Ext for f64 { round(self) } - #[cfg(todo)] #[inline] fn trunc(self) -> Self { trunc(self) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e400badd129..71b58dda883 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -15,6 +15,8 @@ mod sqrtf; mod logf; mod expf; mod floor; +mod trunc; +mod truncf; //mod service; @@ -30,6 +32,8 @@ pub use self::{ logf::logf, expf::expf, floor::floor, + trunc::trunc, + truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs new file mode 100644 index 00000000000..b50ffd77156 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -0,0 +1,24 @@ +use core::f64; + +#[inline] +pub fn trunc(x: f64) -> f64 { + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 + + let mut i: u64 = x.to_bits(); + let mut e: i64 = (i >> 52 & 0x7ff) as i64 - 0x3ff + 12; + let m: u64; + + if e >= 52 + 12 { + return x; + } + if e < 12 { + e = 1; + } + m = -1i64 as u64 >> e; + if (i & m) == 0 { + return x; + } + force_eval!(x + x1p120); + i &= !m; + f64::from_bits(i) +} diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs new file mode 100644 index 00000000000..f7d7249e351 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -0,0 +1,24 @@ +use core::f32; + +#[inline] +pub fn truncf(x: f32) -> f32 { + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut i: u32 = x.to_bits(); + let mut e: i32 = (i >> 23 & 0xff) as i32 - 0x7f + 9; + let m: u32; + + if e >= 23 + 9 { + return x; + } + if e < 9 { + e = 1; + } + m = -1i32 as u32 >> e; + if (i & m) == 0 { + return x; + } + force_eval!(x + x1p120); + i &= !m; + f32::from_bits(i) +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 42e157ad876..6353b257dce 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -562,7 +562,7 @@ fn main() -> Result<(), Box> { f32_f32! { // acosf, // floorf, - // truncf + truncf, // asinf, // atanf, // cbrtf, @@ -625,7 +625,7 @@ f64_f64! { // sqrt, // tan, // tanh, - // trunc, + trunc, fabs, } -- cgit 1.4.1-3-g733a5 From ece6cc8044835342c0a53b81be56c4029d002089 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 13 Jul 2018 23:23:14 +0300 Subject: add cosf with dependencies --- library/compiler-builtins/libm/src/lib.rs | 2 - library/compiler-builtins/libm/src/math/cosf.rs | 65 +++ library/compiler-builtins/libm/src/math/mod.rs | 4 +- .../libm/src/math/service/cosdf.rs | 13 + .../compiler-builtins/libm/src/math/service/mod.rs | 11 + .../libm/src/math/service/rem_pio2_large.rs | 489 +++++++++++++++++++++ .../libm/src/math/service/rem_pio2f.rs | 44 ++ .../libm/src/math/service/sindf.rs | 14 + 8 files changed, 639 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/cosf.rs create mode 100644 library/compiler-builtins/libm/src/math/service/cosdf.rs create mode 100644 library/compiler-builtins/libm/src/math/service/mod.rs create mode 100644 library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs create mode 100644 library/compiler-builtins/libm/src/math/service/rem_pio2f.rs create mode 100644 library/compiler-builtins/libm/src/math/service/sindf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index ed163ff98c7..e51a7c2dc48 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -95,7 +95,6 @@ pub trait F32Ext { #[cfg(todo)] fn sin(self) -> Self; - #[cfg(todo)] fn cos(self) -> Self; #[cfg(todo)] @@ -268,7 +267,6 @@ impl F32Ext for f32 { sinf(self) } - #[cfg(todo)] #[inline] fn cos(self) -> Self { cosf(self) diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs new file mode 100644 index 00000000000..b1aefd5e32b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -0,0 +1,65 @@ +use super::service::{cosdf, sindf, rem_pio2f}; + +use core::f64::consts::FRAC_PI_2; + +/* Small multiples of pi/2 rounded to double precision. */ +const C1_PIO2 : f64 = 1.*FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const C2_PIO2 : f64 = 2.*FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const C3_PIO2 : f64 = 3.*FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const C4_PIO2 : f64 = 4.*FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +#[inline] +pub fn cosf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { /* |x| ~<= pi/4 */ + if ix < 0x39800000 { /* |x| < 2**-12 */ + /* raise inexact if x != 0 */ + force_eval!(x + x1p120); + return 1.; + } + return cosdf(x64); + } + if ix <= 0x407b53d1 { /* |x| ~<= 5*pi/4 */ + if ix > 0x4016cbe3 { /* |x| ~> 3*pi/4 */ + return -cosdf(if sign { x64+C2_PIO2 } else { x64-C2_PIO2 }); + } else { + if sign { + return sindf(x64 + C1_PIO2); + } else { + return sindf(C1_PIO2 - x64); + } + } + } + if ix <= 0x40e231d5 { /* |x| ~<= 9*pi/4 */ + if ix > 0x40afeddf { /* |x| ~> 7*pi/4 */ + return cosdf(if sign { x64+C4_PIO2 } else { x64-C4_PIO2 }); + } else { + if sign { + return sindf(-x64 - C3_PIO2); + } else { + return sindf(x64 - C3_PIO2); + } + } + } + + /* cos(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x-x; + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + match n&3 { + 0 => { cosdf( y) }, + 1 => { sindf(-y) }, + 2 => { -cosdf( y) }, + _ => { sindf( y) }, + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e400badd129..bc69aca0f61 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -15,8 +15,9 @@ mod sqrtf; mod logf; mod expf; mod floor; +mod cosf; -//mod service; +mod service; pub use self::{ fabs::fabs, @@ -30,6 +31,7 @@ pub use self::{ logf::logf, expf::expf, floor::floor, + cosf::cosf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/src/math/service/cosdf.rs b/library/compiler-builtins/libm/src/math/service/cosdf.rs new file mode 100644 index 00000000000..6c5e9d3495a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/service/cosdf.rs @@ -0,0 +1,13 @@ +/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +const C0 : f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ +const C1 : f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ +const C2 : f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ +const C3 : f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ + +#[inline] +pub(crate) fn cosdf(x : f64) -> f32 { + let z = x*x; + let w = z*z; + let r = C2+z*C3; + (((1.0+z*C0) + w*C1) + (w*z)*r) as f32 +} diff --git a/library/compiler-builtins/libm/src/math/service/mod.rs b/library/compiler-builtins/libm/src/math/service/mod.rs new file mode 100644 index 00000000000..96bb09431ba --- /dev/null +++ b/library/compiler-builtins/libm/src/math/service/mod.rs @@ -0,0 +1,11 @@ +mod sindf; +mod cosdf; +mod rem_pio2f; +mod rem_pio2_large; + +pub(crate) use self::{ + cosdf::cosdf, + sindf::sindf, + rem_pio2f::rem_pio2f, + rem_pio2_large::rem_pio2_large, +}; diff --git a/library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs new file mode 100644 index 00000000000..017fc88bae2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs @@ -0,0 +1,489 @@ +use ::scalbn; +use ::F64Ext; + +/// double x[],y[]; int e0,nx,prec; +/// +/// __rem_pio2_large return the last three digits of N with +/// y = x - N*pi/2 +/// so that |y| < pi/2. +/// +/// The method is to compute the integer (mod 8) and fraction parts of +/// (2/pi)*x without doing the full multiplication. In general we +/// skip the part of the product that are known to be a huge integer ( +/// more accurately, = 0 mod 8 ). Thus the number of operations are +/// independent of the exponent of the input. +/// +/// (2/pi) is represented by an array of 24-bit integers in ipio2[]. +/// +/// Input parameters: +/// x[] The input value (must be positive) is broken into nx +/// pieces of 24-bit integers in double precision format. +/// x[i] will be the i-th 24 bit of x. The scaled exponent +/// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 +/// match x's up to 24 bits. +/// +/// Example of breaking a double positive z into x[0]+x[1]+x[2]: +/// e0 = ilogb(z)-23 +/// z = scalbn(z,-e0) +/// for i = 0,1,2 +/// x[i] = floor(z) +/// z = (z-x[i])*2**24 +/// +/// y[] ouput result in an array of double precision numbers. +/// The dimension of y[] is: +/// 24-bit precision 1 +/// 53-bit precision 2 +/// 64-bit precision 2 +/// 113-bit precision 3 +/// The actual value is the sum of them. Thus for 113-bit +/// precison, one may have to do something like: +/// +/// long double t,w,r_head, r_tail; +/// t = (long double)y[2] + (long double)y[1]; +/// w = (long double)y[0]; +/// r_head = t+w; +/// r_tail = w - (r_head - t); +/// +/// e0 The exponent of x[0]. Must be <= 16360 or you need to +/// expand the ipio2 table. +/// +/// prec an integer indicating the precision: +/// 0 24 bits (single) +/// 1 53 bits (double) +/// 2 64 bits (extended) +/// 3 113 bits (quad) +/// External function: +/// double scalbn(), floor(); +/// +/// +/// Here is the description of some local variables: +/// +/// jk jk+1 is the initial number of terms of ipio2[] needed +/// in the computation. The minimum and recommended value +/// for jk is 3,4,4,6 for single, double, extended, and quad. +/// jk+1 must be 2 larger than you might expect so that our +/// recomputation test works. (Up to 24 bits in the integer +/// part (the 24 bits of it that we compute) and 23 bits in +/// the fraction part may be lost to cancelation before we +/// recompute.) +/// +/// jz local integer variable indicating the number of +/// terms of ipio2[] used. +/// +/// jx nx - 1 +/// +/// jv index for pointing to the suitable ipio2[] for the +/// computation. In general, we want +/// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 +/// is an integer. Thus +/// e0-3-24*jv >= 0 or (e0-3)/24 >= jv +/// Hence jv = max(0,(e0-3)/24). +/// +/// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. +/// +/// q[] double array with integral value, representing the +/// 24-bits chunk of the product of x and 2/pi. +/// +/// q0 the corresponding exponent of q[0]. Note that the +/// exponent for q[i] would be q0-24*i. +/// +/// PIo2[] double precision array, obtained by cutting pi/2 +/// into 24 bits chunks. +/// +/// f[] ipio2[] in floating point +/// +/// iq[] integer array by breaking up q[] in 24-bits chunk. +/// +/// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] +/// +/// ih integer. If >0 it indicates q[] is >= 0.5, hence +/// it also indicates the *sign* of the result. + +const INIT_JK : [usize; 4] = [3,4,4,6]; /* initial value for jk */ + +/// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi +/// +/// integer array, contains the (24*i)-th to (24*i+23)-th +/// bit of 2/pi after binary point. The corresponding +/// floating value is +/// +/// ipio2[i] * 2^(-24(i+1)). +/// +/// NB: This table must have at least (e0-3)/24 + jk terms. +/// For quad precision (e0 <= 16360, jk = 6), this is 686. +#[cfg(not(ldbl_max_exp_more1024))] +const IPIO2 : [i32; 66] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, + 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, + 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, + 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, + 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, + 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, + 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, + 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, +]; + +#[cfg(ldbl_max_exp_more1024)] +const IPIO2 : [i32; 690] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, + 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, + 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, + 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, + 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, + 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, + 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, + 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, + 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, + 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, + 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, + 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, + 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, + 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, + 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, + 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, + 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, + 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, + 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, + 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, + 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, + 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, + 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, + 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, + 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, + 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, + 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, + 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, + 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, + 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, + 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, + 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, + 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, + 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, + 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, + 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, + 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, + 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, + 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, + 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, + 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, + 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, + 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, + 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, + 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, + 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, + 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, + 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, + 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, + 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, + 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, + 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, + 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, + 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, + 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, + 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, + 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, + 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, + 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, + 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, + 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, + 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, + 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, + 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, + 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, + 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, + 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, + 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, + 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, + 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, + 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, + 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, + 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, + 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, + 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, + 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, + 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, + 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, + 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, + 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, + 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, + 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, + 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, + 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, + 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, + 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, + 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, + 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, + 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, + 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, + 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, + 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, + 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, + 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, + 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, + 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, + 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, + 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, + 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, + 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, + 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, + 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, + 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, + 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, + 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, + 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, + 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, + 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, + 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, + 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, + 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, + 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, +]; + +const PIO2 : [f64; 8] = [ + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +]; + +#[inline] +pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 { + let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 + let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) + + #[cfg(not(ldbl_max_exp_more1024))] + assert!(e0 <= 16360); + + let nx = x.len(); + + let mut fw : f64; + let mut n : i32; + let mut ih : i32; + let mut z = 0f64; + let mut f : [f64;20] = [0.;20]; + let mut fq : [f64;20] = [0.;20]; + let mut q : [f64;20] = [0.;20]; + let mut iq : [i32;20] = [0;20]; + + /* initialize jk*/ + let jk = INIT_JK[prec]; + let jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + let jx = nx-1; + let mut jv = (e0-3)/24; + if jv < 0 { + jv=0; + } + let mut q0 = e0-24*(jv+1); + let jv = jv as usize; + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + let mut j = (jv-jx) as i32; + let m = jx+jk; + for i in 0..=m { + f[i] = if j<0 { + 0. + } else { + IPIO2[j as usize] as f64 + }; + j += 1 + } + + /* compute q[0],q[1],...q[jk] */ + for i in 0..=jk { + fw = 0f64; + for j in 0..=jx { + fw += x[j]*f[jx+i-j]; + } + q[i] = fw; + } + + let mut jz = jk; + + 'recompute: loop { + /* distill q[] into iq[] reversingly */ + let mut i = 0i32; + let mut z = q[jz]; + for j in (1..=jz).rev() { + fw = (x1p_24*z) as i32 as f64; + iq[i as usize] = (z - x1p24*fw) as i32; + z = q[j-1]+fw; + i += 1; + } + + /* compute n */ + z = scalbn(z, q0); /* actual value of z */ + z -= 8.0*(z*0.125).floor(); /* trim off integer >= 8 */ + n = z as i32; + z -= n as f64; + ih = 0; + if q0 > 0 { /* need iq[jz-1] to determine n */ + i = iq[jz-1] >> (24-q0); + n += i; + iq[jz-1] -= i << (24-q0); + ih = iq[jz-1] >> (23-q0); + } else if q0 == 0 { + ih = iq[jz-1]>>23; + } else if z >= 0.5 { + ih = 2; + } + + if ih > 0 { /* q > 0.5 */ + n += 1; + let mut carry = 0i32; + for i in 0..jz { /* compute 1-q */ + let j = iq[i]; + if carry == 0 { + if j != 0 { + carry = 1; + iq[i] = 0x1000000 - j; + } + } else { + iq[i] = 0xffffff - j; + } + } + if q0 > 0 { /* rare case: chance is 1 in 12 */ + match q0 { + 1 => { iq[jz-1] &= 0x7fffff; }, + 2 => { iq[jz-1] &= 0x3fffff; }, + _ => {} + } + } + if ih == 2 { + z = 1. - z; + if carry != 0 { + z -= scalbn(1., q0); + } + } + } + + /* check if recomputation is needed */ + if z == 0. { + let mut j = 0; + for i in (jk..=jz-1).rev() { + j |= iq[i]; + } + if j == 0 { /* need recomputation */ + let mut k = 1; + while iq[jk-k]==0 { + k += 1; /* k = no. of terms needed */ + } + + for i in (jz+1)..=(jz+k) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = IPIO2[jv+i] as f64; + fw = 0f64; + for j in 0..=jx { + fw += x[j]*f[jx+i-j]; + } + q[i] = fw; + } + jz += k; + continue 'recompute; + } + } + + break; + } + + /* chop off zero terms */ + if z == 0. { + jz -= 1; + q0 -= 24; + while iq[jz] == 0 { + jz -= 1; + q0 -= 24; + } + } else { /* break z into 24-bit if necessary */ + z = scalbn(z, -q0); + if z >= x1p24 { + fw = (x1p_24*z) as i32 as f64; + iq[jz] = (z - x1p24*fw) as i32; + jz += 1; + q0 += 24; + iq[jz] = fw as i32; + } else { + iq[jz] = z as i32; + } + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(1., q0); + for i in (0..=jz).rev() { + q[i] = fw*(iq[i] as f64); + fw *= x1p_24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for i in (0..=jz).rev() { + fw = 0f64; + let mut k = 0; + while (k <= jp) && (k <= jz-i) { + fw += PIO2[k]*q[i+k]; + k += 1; + } + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + match prec { + 0 => { + fw = 0f64; + for i in (0..=jz).rev() { + fw += fq[i]; + } + y[0] = if ih == 0 { fw } else { -fw }; + }, + 1 | 2 => { + fw = 0f64; + for i in (0..=jz).rev() { + fw += fq[i]; + } + // TODO: drop excess precision here once double_t is used + fw = fw as f64; + y[0] = if ih == 0 { fw } else { -fw }; + fw = fq[0]-fw; + for i in 1..=jz { + fw += fq[i]; + } + y[1] = if ih == 0 { fw } else { -fw }; + }, + 3 => { /* painful */ + for i in (1..=jz).rev() { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for i in (2..=jz).rev() { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + fw = 0f64; + for i in (2..=jz).rev() { + fw += fq[i]; + } + if ih==0 { + y[0] = fq[0]; + y[1] = fq[1]; + y[2] = fw; + } else { + y[0] = -fq[0]; + y[1] = -fq[1]; + y[2] = -fw; + } + }, + _ => { unreachable!() } + } + n & 7 +} diff --git a/library/compiler-builtins/libm/src/math/service/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/service/rem_pio2f.rs new file mode 100644 index 00000000000..a908ccd9f75 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/service/rem_pio2f.rs @@ -0,0 +1,44 @@ +use super::rem_pio2_large; + +use core::f64; + +const TOINT : f64 = 1.5 / f64::EPSILON; + +/// 53 bits of 2/pi +const INV_PIO2 : f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +/// first 25 bits of pi/2 +const PIO2_1 : f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ +/// pi/2 - pio2_1 +const PIO2_1T : f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + +/// Return the remainder of x rem pi/2 in *y +/// +/// use double precision for everything except passing x +/// use __rem_pio2_large() for large x +#[inline] +pub(crate) fn rem_pio2f(x : f32) -> (i32, f64) { + let x64 = x as f64; + + let mut tx : [f64; 1] = [0.,]; + let mut ty : [f64; 1] = [0.,]; + + let ix = x.to_bits() & 0x7fffffff; + /* 25+53 bit pi is good enough for medium size */ + if ix < 0x4dc90fdb { /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + let f_n = x64*INV_PIO2 + TOINT - TOINT; + return (f_n as i32, x64 - f_n*PIO2_1 - f_n*PIO2_1T); + } + if ix>=0x7f800000 { /* x is inf or NaN */ + return (0, x64-x64); + } + /* scale x into [2^23, 2^24-1] */ + let sign = (x.to_bits() >> 31) != 0; + let e0 = ((ix>>23) - (0x7f+23)) as i32; /* e0 = ilogb(|x|)-23, positive */ + tx[0] = f32::from_bits(ix - (e0<<23) as u32) as f64; + let n = rem_pio2_large(&tx, &mut ty, e0, 0); + if sign { + return (-n, -ty[0]); + } + (n, ty[0]) +} diff --git a/library/compiler-builtins/libm/src/math/service/sindf.rs b/library/compiler-builtins/libm/src/math/service/sindf.rs new file mode 100644 index 00000000000..a633545ba80 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/service/sindf.rs @@ -0,0 +1,14 @@ +/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +const S1 : f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ +const S2 : f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ +const S3 : f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ +const S4 : f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ + +#[inline] +pub(crate) fn sindf(x : f64) -> f32 { + let z = x*x; + let w = z*z; + let r = S3 + z*S4; + let s = z*x; + ((x + s*(S1 + z*S2)) + s*w*r) as f32 +} -- cgit 1.4.1-3-g733a5 From ac1b398b4db6d1bdc60d6da8e809487254d17a87 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 13 Jul 2018 15:31:57 -0400 Subject: seal extension traits to prevent external implementation --- library/compiler-builtins/libm/src/lib.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index fa709ad754a..4deb2e21eee 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -32,9 +32,8 @@ pub fn _eq(a: u64, b: u64) -> bool { /// Math support for `f32` /// -/// NOTE this meant to be a closed extension trait. The only stable way to use this trait is to -/// import it to access its methods. -pub trait F32Ext { +/// This trait is sealed and cannot be implemented outside of `libm`. +pub trait F32Ext: private::Sealed { #[cfg(todo)] fn floor(self) -> Self; @@ -360,9 +359,8 @@ impl F32Ext for f32 { /// Math support for `f32` /// -/// NOTE this meant to be a closed extension trait. The only stable way to use this trait is to -/// import it to access its methods. -pub trait F64Ext { +/// This trait is sealed and cannot be implemented outside of `libm`. +pub trait F64Ext: private::Sealed { fn floor(self) -> Self; #[cfg(todo)] @@ -691,3 +689,10 @@ impl F64Ext for f64 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } } + +mod private { + pub trait Sealed {} + + impl Sealed for f32 {} + impl Sealed for f64 {} +} -- cgit 1.4.1-3-g733a5 From d8cc25edd3c39a4c9c4add84e9657e7e656c1121 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 13 Jul 2018 23:58:41 +0300 Subject: cosf review --- library/compiler-builtins/libm/src/math/cosdf.rs | 13 + library/compiler-builtins/libm/src/math/cosf.rs | 2 +- library/compiler-builtins/libm/src/math/mod.rs | 14 +- .../libm/src/math/rem_pio2_large.rs | 489 +++++++++++++++++++++ .../compiler-builtins/libm/src/math/rem_pio2f.rs | 44 ++ .../libm/src/math/service/cosdf.rs | 13 - .../compiler-builtins/libm/src/math/service/mod.rs | 11 - .../libm/src/math/service/rem_pio2_large.rs | 489 --------------------- .../libm/src/math/service/rem_pio2f.rs | 44 -- .../libm/src/math/service/sindf.rs | 14 - library/compiler-builtins/libm/src/math/sindf.rs | 14 + 11 files changed, 573 insertions(+), 574 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/cosdf.rs create mode 100644 library/compiler-builtins/libm/src/math/rem_pio2_large.rs create mode 100644 library/compiler-builtins/libm/src/math/rem_pio2f.rs delete mode 100644 library/compiler-builtins/libm/src/math/service/cosdf.rs delete mode 100644 library/compiler-builtins/libm/src/math/service/mod.rs delete mode 100644 library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs delete mode 100644 library/compiler-builtins/libm/src/math/service/rem_pio2f.rs delete mode 100644 library/compiler-builtins/libm/src/math/service/sindf.rs create mode 100644 library/compiler-builtins/libm/src/math/sindf.rs diff --git a/library/compiler-builtins/libm/src/math/cosdf.rs b/library/compiler-builtins/libm/src/math/cosdf.rs new file mode 100644 index 00000000000..6c5e9d3495a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cosdf.rs @@ -0,0 +1,13 @@ +/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +const C0 : f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ +const C1 : f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ +const C2 : f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ +const C3 : f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ + +#[inline] +pub(crate) fn cosdf(x : f64) -> f32 { + let z = x*x; + let w = z*z; + let r = C2+z*C3; + (((1.0+z*C0) + w*C1) + (w*z)*r) as f32 +} diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index b1aefd5e32b..f63724e791e 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -1,4 +1,4 @@ -use super::service::{cosdf, sindf, rem_pio2f}; +use super::{cosdf, sindf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index bc69aca0f61..b8de3c73333 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -17,8 +17,6 @@ mod expf; mod floor; mod cosf; -mod service; - pub use self::{ fabs::fabs, fabsf::fabsf, @@ -34,6 +32,18 @@ pub use self::{ cosf::cosf, }; +mod sindf; +mod cosdf; +mod rem_pio2f; +mod rem_pio2_large; + +use self::{ + sindf::sindf, + cosdf::cosdf, + rem_pio2f::rem_pio2f, + rem_pio2_large::rem_pio2_large, +}; + fn isnanf(x: f32) -> bool { x.to_bits() & 0x7fffffff > 0x7f800000 } diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs new file mode 100644 index 00000000000..deb985f1d1c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -0,0 +1,489 @@ +use super::scalbn; +use super::floor; + +/// double x[],y[]; int e0,nx,prec; +/// +/// __rem_pio2_large return the last three digits of N with +/// y = x - N*pi/2 +/// so that |y| < pi/2. +/// +/// The method is to compute the integer (mod 8) and fraction parts of +/// (2/pi)*x without doing the full multiplication. In general we +/// skip the part of the product that are known to be a huge integer ( +/// more accurately, = 0 mod 8 ). Thus the number of operations are +/// independent of the exponent of the input. +/// +/// (2/pi) is represented by an array of 24-bit integers in ipio2[]. +/// +/// Input parameters: +/// x[] The input value (must be positive) is broken into nx +/// pieces of 24-bit integers in double precision format. +/// x[i] will be the i-th 24 bit of x. The scaled exponent +/// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 +/// match x's up to 24 bits. +/// +/// Example of breaking a double positive z into x[0]+x[1]+x[2]: +/// e0 = ilogb(z)-23 +/// z = scalbn(z,-e0) +/// for i = 0,1,2 +/// x[i] = floor(z) +/// z = (z-x[i])*2**24 +/// +/// y[] ouput result in an array of double precision numbers. +/// The dimension of y[] is: +/// 24-bit precision 1 +/// 53-bit precision 2 +/// 64-bit precision 2 +/// 113-bit precision 3 +/// The actual value is the sum of them. Thus for 113-bit +/// precison, one may have to do something like: +/// +/// long double t,w,r_head, r_tail; +/// t = (long double)y[2] + (long double)y[1]; +/// w = (long double)y[0]; +/// r_head = t+w; +/// r_tail = w - (r_head - t); +/// +/// e0 The exponent of x[0]. Must be <= 16360 or you need to +/// expand the ipio2 table. +/// +/// prec an integer indicating the precision: +/// 0 24 bits (single) +/// 1 53 bits (double) +/// 2 64 bits (extended) +/// 3 113 bits (quad) +/// External function: +/// double scalbn(), floor(); +/// +/// +/// Here is the description of some local variables: +/// +/// jk jk+1 is the initial number of terms of ipio2[] needed +/// in the computation. The minimum and recommended value +/// for jk is 3,4,4,6 for single, double, extended, and quad. +/// jk+1 must be 2 larger than you might expect so that our +/// recomputation test works. (Up to 24 bits in the integer +/// part (the 24 bits of it that we compute) and 23 bits in +/// the fraction part may be lost to cancelation before we +/// recompute.) +/// +/// jz local integer variable indicating the number of +/// terms of ipio2[] used. +/// +/// jx nx - 1 +/// +/// jv index for pointing to the suitable ipio2[] for the +/// computation. In general, we want +/// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 +/// is an integer. Thus +/// e0-3-24*jv >= 0 or (e0-3)/24 >= jv +/// Hence jv = max(0,(e0-3)/24). +/// +/// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. +/// +/// q[] double array with integral value, representing the +/// 24-bits chunk of the product of x and 2/pi. +/// +/// q0 the corresponding exponent of q[0]. Note that the +/// exponent for q[i] would be q0-24*i. +/// +/// PIo2[] double precision array, obtained by cutting pi/2 +/// into 24 bits chunks. +/// +/// f[] ipio2[] in floating point +/// +/// iq[] integer array by breaking up q[] in 24-bits chunk. +/// +/// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] +/// +/// ih integer. If >0 it indicates q[] is >= 0.5, hence +/// it also indicates the *sign* of the result. + +const INIT_JK : [usize; 4] = [3,4,4,6]; /* initial value for jk */ + +/// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi +/// +/// integer array, contains the (24*i)-th to (24*i+23)-th +/// bit of 2/pi after binary point. The corresponding +/// floating value is +/// +/// ipio2[i] * 2^(-24(i+1)). +/// +/// NB: This table must have at least (e0-3)/24 + jk terms. +/// For quad precision (e0 <= 16360, jk = 6), this is 686. +#[cfg(not(ldbl_max_exp_more1024))] +const IPIO2 : [i32; 66] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, + 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, + 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, + 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, + 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, + 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, + 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, + 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, +]; + +#[cfg(ldbl_max_exp_more1024)] +const IPIO2 : [i32; 690] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, + 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, + 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, + 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, + 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, + 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, + 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, + 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, + 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, + 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, + 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, + 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, + 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, + 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, + 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, + 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, + 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, + 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, + 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, + 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, + 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, + 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, + 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, + 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, + 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, + 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, + 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, + 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, + 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, + 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, + 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, + 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, + 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, + 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, + 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, + 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, + 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, + 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, + 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, + 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, + 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, + 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, + 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, + 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, + 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, + 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, + 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, + 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, + 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, + 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, + 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, + 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, + 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, + 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, + 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, + 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, + 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, + 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, + 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, + 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, + 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, + 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, + 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, + 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, + 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, + 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, + 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, + 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, + 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, + 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, + 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, + 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, + 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, + 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, + 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, + 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, + 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, + 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, + 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, + 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, + 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, + 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, + 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, + 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, + 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, + 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, + 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, + 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, + 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, + 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, + 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, + 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, + 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, + 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, + 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, + 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, + 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, + 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, + 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, + 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, + 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, + 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, + 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, + 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, + 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, + 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, + 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, + 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, + 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, + 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, + 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, + 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, +]; + +const PIO2 : [f64; 8] = [ + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +]; + +#[inline] +pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 { + let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 + let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) + + #[cfg(not(ldbl_max_exp_more1024))] + assert!(e0 <= 16360); + + let nx = x.len(); + + let mut fw : f64; + let mut n : i32; + let mut ih : i32; + let mut z = 0f64; + let mut f : [f64;20] = [0.;20]; + let mut fq : [f64;20] = [0.;20]; + let mut q : [f64;20] = [0.;20]; + let mut iq : [i32;20] = [0;20]; + + /* initialize jk*/ + let jk = INIT_JK[prec]; + let jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + let jx = nx-1; + let mut jv = (e0-3)/24; + if jv < 0 { + jv=0; + } + let mut q0 = e0-24*(jv+1); + let jv = jv as usize; + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + let mut j = (jv-jx) as i32; + let m = jx+jk; + for i in 0..=m { + f[i] = if j<0 { + 0. + } else { + IPIO2[j as usize] as f64 + }; + j += 1 + } + + /* compute q[0],q[1],...q[jk] */ + for i in 0..=jk { + fw = 0f64; + for j in 0..=jx { + fw += x[j]*f[jx+i-j]; + } + q[i] = fw; + } + + let mut jz = jk; + + 'recompute: loop { + /* distill q[] into iq[] reversingly */ + let mut i = 0i32; + let mut z = q[jz]; + for j in (1..=jz).rev() { + fw = (x1p_24*z) as i32 as f64; + iq[i as usize] = (z - x1p24*fw) as i32; + z = q[j-1]+fw; + i += 1; + } + + /* compute n */ + z = scalbn(z, q0); /* actual value of z */ + z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ + n = z as i32; + z -= n as f64; + ih = 0; + if q0 > 0 { /* need iq[jz-1] to determine n */ + i = iq[jz-1] >> (24-q0); + n += i; + iq[jz-1] -= i << (24-q0); + ih = iq[jz-1] >> (23-q0); + } else if q0 == 0 { + ih = iq[jz-1]>>23; + } else if z >= 0.5 { + ih = 2; + } + + if ih > 0 { /* q > 0.5 */ + n += 1; + let mut carry = 0i32; + for i in 0..jz { /* compute 1-q */ + let j = iq[i]; + if carry == 0 { + if j != 0 { + carry = 1; + iq[i] = 0x1000000 - j; + } + } else { + iq[i] = 0xffffff - j; + } + } + if q0 > 0 { /* rare case: chance is 1 in 12 */ + match q0 { + 1 => { iq[jz-1] &= 0x7fffff; }, + 2 => { iq[jz-1] &= 0x3fffff; }, + _ => {} + } + } + if ih == 2 { + z = 1. - z; + if carry != 0 { + z -= scalbn(1., q0); + } + } + } + + /* check if recomputation is needed */ + if z == 0. { + let mut j = 0; + for i in (jk..=jz-1).rev() { + j |= iq[i]; + } + if j == 0 { /* need recomputation */ + let mut k = 1; + while iq[jk-k]==0 { + k += 1; /* k = no. of terms needed */ + } + + for i in (jz+1)..=(jz+k) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = IPIO2[jv+i] as f64; + fw = 0f64; + for j in 0..=jx { + fw += x[j]*f[jx+i-j]; + } + q[i] = fw; + } + jz += k; + continue 'recompute; + } + } + + break; + } + + /* chop off zero terms */ + if z == 0. { + jz -= 1; + q0 -= 24; + while iq[jz] == 0 { + jz -= 1; + q0 -= 24; + } + } else { /* break z into 24-bit if necessary */ + z = scalbn(z, -q0); + if z >= x1p24 { + fw = (x1p_24*z) as i32 as f64; + iq[jz] = (z - x1p24*fw) as i32; + jz += 1; + q0 += 24; + iq[jz] = fw as i32; + } else { + iq[jz] = z as i32; + } + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(1., q0); + for i in (0..=jz).rev() { + q[i] = fw*(iq[i] as f64); + fw *= x1p_24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for i in (0..=jz).rev() { + fw = 0f64; + let mut k = 0; + while (k <= jp) && (k <= jz-i) { + fw += PIO2[k]*q[i+k]; + k += 1; + } + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + match prec { + 0 => { + fw = 0f64; + for i in (0..=jz).rev() { + fw += fq[i]; + } + y[0] = if ih == 0 { fw } else { -fw }; + }, + 1 | 2 => { + fw = 0f64; + for i in (0..=jz).rev() { + fw += fq[i]; + } + // TODO: drop excess precision here once double_t is used + fw = fw as f64; + y[0] = if ih == 0 { fw } else { -fw }; + fw = fq[0]-fw; + for i in 1..=jz { + fw += fq[i]; + } + y[1] = if ih == 0 { fw } else { -fw }; + }, + 3 => { /* painful */ + for i in (1..=jz).rev() { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for i in (2..=jz).rev() { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + fw = 0f64; + for i in (2..=jz).rev() { + fw += fq[i]; + } + if ih==0 { + y[0] = fq[0]; + y[1] = fq[1]; + y[2] = fw; + } else { + y[0] = -fq[0]; + y[1] = -fq[1]; + y[2] = -fw; + } + }, + _ => { unreachable!() } + } + n & 7 +} diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs new file mode 100644 index 00000000000..a908ccd9f75 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -0,0 +1,44 @@ +use super::rem_pio2_large; + +use core::f64; + +const TOINT : f64 = 1.5 / f64::EPSILON; + +/// 53 bits of 2/pi +const INV_PIO2 : f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +/// first 25 bits of pi/2 +const PIO2_1 : f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ +/// pi/2 - pio2_1 +const PIO2_1T : f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + +/// Return the remainder of x rem pi/2 in *y +/// +/// use double precision for everything except passing x +/// use __rem_pio2_large() for large x +#[inline] +pub(crate) fn rem_pio2f(x : f32) -> (i32, f64) { + let x64 = x as f64; + + let mut tx : [f64; 1] = [0.,]; + let mut ty : [f64; 1] = [0.,]; + + let ix = x.to_bits() & 0x7fffffff; + /* 25+53 bit pi is good enough for medium size */ + if ix < 0x4dc90fdb { /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + let f_n = x64*INV_PIO2 + TOINT - TOINT; + return (f_n as i32, x64 - f_n*PIO2_1 - f_n*PIO2_1T); + } + if ix>=0x7f800000 { /* x is inf or NaN */ + return (0, x64-x64); + } + /* scale x into [2^23, 2^24-1] */ + let sign = (x.to_bits() >> 31) != 0; + let e0 = ((ix>>23) - (0x7f+23)) as i32; /* e0 = ilogb(|x|)-23, positive */ + tx[0] = f32::from_bits(ix - (e0<<23) as u32) as f64; + let n = rem_pio2_large(&tx, &mut ty, e0, 0); + if sign { + return (-n, -ty[0]); + } + (n, ty[0]) +} diff --git a/library/compiler-builtins/libm/src/math/service/cosdf.rs b/library/compiler-builtins/libm/src/math/service/cosdf.rs deleted file mode 100644 index 6c5e9d3495a..00000000000 --- a/library/compiler-builtins/libm/src/math/service/cosdf.rs +++ /dev/null @@ -1,13 +0,0 @@ -/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ -const C0 : f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ -const C1 : f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ -const C2 : f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ -const C3 : f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ - -#[inline] -pub(crate) fn cosdf(x : f64) -> f32 { - let z = x*x; - let w = z*z; - let r = C2+z*C3; - (((1.0+z*C0) + w*C1) + (w*z)*r) as f32 -} diff --git a/library/compiler-builtins/libm/src/math/service/mod.rs b/library/compiler-builtins/libm/src/math/service/mod.rs deleted file mode 100644 index 96bb09431ba..00000000000 --- a/library/compiler-builtins/libm/src/math/service/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -mod sindf; -mod cosdf; -mod rem_pio2f; -mod rem_pio2_large; - -pub(crate) use self::{ - cosdf::cosdf, - sindf::sindf, - rem_pio2f::rem_pio2f, - rem_pio2_large::rem_pio2_large, -}; diff --git a/library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs deleted file mode 100644 index 017fc88bae2..00000000000 --- a/library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs +++ /dev/null @@ -1,489 +0,0 @@ -use ::scalbn; -use ::F64Ext; - -/// double x[],y[]; int e0,nx,prec; -/// -/// __rem_pio2_large return the last three digits of N with -/// y = x - N*pi/2 -/// so that |y| < pi/2. -/// -/// The method is to compute the integer (mod 8) and fraction parts of -/// (2/pi)*x without doing the full multiplication. In general we -/// skip the part of the product that are known to be a huge integer ( -/// more accurately, = 0 mod 8 ). Thus the number of operations are -/// independent of the exponent of the input. -/// -/// (2/pi) is represented by an array of 24-bit integers in ipio2[]. -/// -/// Input parameters: -/// x[] The input value (must be positive) is broken into nx -/// pieces of 24-bit integers in double precision format. -/// x[i] will be the i-th 24 bit of x. The scaled exponent -/// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 -/// match x's up to 24 bits. -/// -/// Example of breaking a double positive z into x[0]+x[1]+x[2]: -/// e0 = ilogb(z)-23 -/// z = scalbn(z,-e0) -/// for i = 0,1,2 -/// x[i] = floor(z) -/// z = (z-x[i])*2**24 -/// -/// y[] ouput result in an array of double precision numbers. -/// The dimension of y[] is: -/// 24-bit precision 1 -/// 53-bit precision 2 -/// 64-bit precision 2 -/// 113-bit precision 3 -/// The actual value is the sum of them. Thus for 113-bit -/// precison, one may have to do something like: -/// -/// long double t,w,r_head, r_tail; -/// t = (long double)y[2] + (long double)y[1]; -/// w = (long double)y[0]; -/// r_head = t+w; -/// r_tail = w - (r_head - t); -/// -/// e0 The exponent of x[0]. Must be <= 16360 or you need to -/// expand the ipio2 table. -/// -/// prec an integer indicating the precision: -/// 0 24 bits (single) -/// 1 53 bits (double) -/// 2 64 bits (extended) -/// 3 113 bits (quad) -/// External function: -/// double scalbn(), floor(); -/// -/// -/// Here is the description of some local variables: -/// -/// jk jk+1 is the initial number of terms of ipio2[] needed -/// in the computation. The minimum and recommended value -/// for jk is 3,4,4,6 for single, double, extended, and quad. -/// jk+1 must be 2 larger than you might expect so that our -/// recomputation test works. (Up to 24 bits in the integer -/// part (the 24 bits of it that we compute) and 23 bits in -/// the fraction part may be lost to cancelation before we -/// recompute.) -/// -/// jz local integer variable indicating the number of -/// terms of ipio2[] used. -/// -/// jx nx - 1 -/// -/// jv index for pointing to the suitable ipio2[] for the -/// computation. In general, we want -/// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 -/// is an integer. Thus -/// e0-3-24*jv >= 0 or (e0-3)/24 >= jv -/// Hence jv = max(0,(e0-3)/24). -/// -/// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. -/// -/// q[] double array with integral value, representing the -/// 24-bits chunk of the product of x and 2/pi. -/// -/// q0 the corresponding exponent of q[0]. Note that the -/// exponent for q[i] would be q0-24*i. -/// -/// PIo2[] double precision array, obtained by cutting pi/2 -/// into 24 bits chunks. -/// -/// f[] ipio2[] in floating point -/// -/// iq[] integer array by breaking up q[] in 24-bits chunk. -/// -/// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] -/// -/// ih integer. If >0 it indicates q[] is >= 0.5, hence -/// it also indicates the *sign* of the result. - -const INIT_JK : [usize; 4] = [3,4,4,6]; /* initial value for jk */ - -/// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi -/// -/// integer array, contains the (24*i)-th to (24*i+23)-th -/// bit of 2/pi after binary point. The corresponding -/// floating value is -/// -/// ipio2[i] * 2^(-24(i+1)). -/// -/// NB: This table must have at least (e0-3)/24 + jk terms. -/// For quad precision (e0 <= 16360, jk = 6), this is 686. -#[cfg(not(ldbl_max_exp_more1024))] -const IPIO2 : [i32; 66] = [ - 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, - 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, - 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, - 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, - 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, - 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, - 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, - 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, - 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, - 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, - 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, -]; - -#[cfg(ldbl_max_exp_more1024)] -const IPIO2 : [i32; 690] = [ - 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, - 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, - 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, - 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, - 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, - 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, - 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, - 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, - 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, - 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, - 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, - 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, - 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, - 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, - 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, - 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, - 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, - 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, - 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, - 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, - 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, - 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, - 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, - 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, - 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, - 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, - 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, - 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, - 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, - 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, - 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, - 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, - 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, - 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, - 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, - 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, - 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, - 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, - 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, - 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, - 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, - 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, - 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, - 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, - 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, - 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, - 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, - 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, - 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, - 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, - 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, - 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, - 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, - 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, - 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, - 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, - 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, - 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, - 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, - 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, - 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, - 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, - 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, - 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, - 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, - 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, - 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, - 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, - 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, - 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, - 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, - 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, - 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, - 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, - 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, - 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, - 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, - 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, - 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, - 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, - 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, - 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, - 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, - 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, - 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, - 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, - 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, - 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, - 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, - 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, - 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, - 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, - 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, - 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, - 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, - 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, - 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, - 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, - 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, - 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, - 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, - 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, - 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, - 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, - 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, - 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, - 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, - 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, - 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, - 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, - 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, - 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, - 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, - 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, - 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, -]; - -const PIO2 : [f64; 8] = [ - 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ - 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ - 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ - 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ - 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ - 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ - 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ - 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ -]; - -#[inline] -pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 { - let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 - let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) - - #[cfg(not(ldbl_max_exp_more1024))] - assert!(e0 <= 16360); - - let nx = x.len(); - - let mut fw : f64; - let mut n : i32; - let mut ih : i32; - let mut z = 0f64; - let mut f : [f64;20] = [0.;20]; - let mut fq : [f64;20] = [0.;20]; - let mut q : [f64;20] = [0.;20]; - let mut iq : [i32;20] = [0;20]; - - /* initialize jk*/ - let jk = INIT_JK[prec]; - let jp = jk; - - /* determine jx,jv,q0, note that 3>q0 */ - let jx = nx-1; - let mut jv = (e0-3)/24; - if jv < 0 { - jv=0; - } - let mut q0 = e0-24*(jv+1); - let jv = jv as usize; - - /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ - let mut j = (jv-jx) as i32; - let m = jx+jk; - for i in 0..=m { - f[i] = if j<0 { - 0. - } else { - IPIO2[j as usize] as f64 - }; - j += 1 - } - - /* compute q[0],q[1],...q[jk] */ - for i in 0..=jk { - fw = 0f64; - for j in 0..=jx { - fw += x[j]*f[jx+i-j]; - } - q[i] = fw; - } - - let mut jz = jk; - - 'recompute: loop { - /* distill q[] into iq[] reversingly */ - let mut i = 0i32; - let mut z = q[jz]; - for j in (1..=jz).rev() { - fw = (x1p_24*z) as i32 as f64; - iq[i as usize] = (z - x1p24*fw) as i32; - z = q[j-1]+fw; - i += 1; - } - - /* compute n */ - z = scalbn(z, q0); /* actual value of z */ - z -= 8.0*(z*0.125).floor(); /* trim off integer >= 8 */ - n = z as i32; - z -= n as f64; - ih = 0; - if q0 > 0 { /* need iq[jz-1] to determine n */ - i = iq[jz-1] >> (24-q0); - n += i; - iq[jz-1] -= i << (24-q0); - ih = iq[jz-1] >> (23-q0); - } else if q0 == 0 { - ih = iq[jz-1]>>23; - } else if z >= 0.5 { - ih = 2; - } - - if ih > 0 { /* q > 0.5 */ - n += 1; - let mut carry = 0i32; - for i in 0..jz { /* compute 1-q */ - let j = iq[i]; - if carry == 0 { - if j != 0 { - carry = 1; - iq[i] = 0x1000000 - j; - } - } else { - iq[i] = 0xffffff - j; - } - } - if q0 > 0 { /* rare case: chance is 1 in 12 */ - match q0 { - 1 => { iq[jz-1] &= 0x7fffff; }, - 2 => { iq[jz-1] &= 0x3fffff; }, - _ => {} - } - } - if ih == 2 { - z = 1. - z; - if carry != 0 { - z -= scalbn(1., q0); - } - } - } - - /* check if recomputation is needed */ - if z == 0. { - let mut j = 0; - for i in (jk..=jz-1).rev() { - j |= iq[i]; - } - if j == 0 { /* need recomputation */ - let mut k = 1; - while iq[jk-k]==0 { - k += 1; /* k = no. of terms needed */ - } - - for i in (jz+1)..=(jz+k) { /* add q[jz+1] to q[jz+k] */ - f[jx+i] = IPIO2[jv+i] as f64; - fw = 0f64; - for j in 0..=jx { - fw += x[j]*f[jx+i-j]; - } - q[i] = fw; - } - jz += k; - continue 'recompute; - } - } - - break; - } - - /* chop off zero terms */ - if z == 0. { - jz -= 1; - q0 -= 24; - while iq[jz] == 0 { - jz -= 1; - q0 -= 24; - } - } else { /* break z into 24-bit if necessary */ - z = scalbn(z, -q0); - if z >= x1p24 { - fw = (x1p_24*z) as i32 as f64; - iq[jz] = (z - x1p24*fw) as i32; - jz += 1; - q0 += 24; - iq[jz] = fw as i32; - } else { - iq[jz] = z as i32; - } - } - - /* convert integer "bit" chunk to floating-point value */ - fw = scalbn(1., q0); - for i in (0..=jz).rev() { - q[i] = fw*(iq[i] as f64); - fw *= x1p_24; - } - - /* compute PIo2[0,...,jp]*q[jz,...,0] */ - for i in (0..=jz).rev() { - fw = 0f64; - let mut k = 0; - while (k <= jp) && (k <= jz-i) { - fw += PIO2[k]*q[i+k]; - k += 1; - } - fq[jz-i] = fw; - } - - /* compress fq[] into y[] */ - match prec { - 0 => { - fw = 0f64; - for i in (0..=jz).rev() { - fw += fq[i]; - } - y[0] = if ih == 0 { fw } else { -fw }; - }, - 1 | 2 => { - fw = 0f64; - for i in (0..=jz).rev() { - fw += fq[i]; - } - // TODO: drop excess precision here once double_t is used - fw = fw as f64; - y[0] = if ih == 0 { fw } else { -fw }; - fw = fq[0]-fw; - for i in 1..=jz { - fw += fq[i]; - } - y[1] = if ih == 0 { fw } else { -fw }; - }, - 3 => { /* painful */ - for i in (1..=jz).rev() { - fw = fq[i-1]+fq[i]; - fq[i] += fq[i-1]-fw; - fq[i-1] = fw; - } - for i in (2..=jz).rev() { - fw = fq[i-1]+fq[i]; - fq[i] += fq[i-1]-fw; - fq[i-1] = fw; - } - fw = 0f64; - for i in (2..=jz).rev() { - fw += fq[i]; - } - if ih==0 { - y[0] = fq[0]; - y[1] = fq[1]; - y[2] = fw; - } else { - y[0] = -fq[0]; - y[1] = -fq[1]; - y[2] = -fw; - } - }, - _ => { unreachable!() } - } - n & 7 -} diff --git a/library/compiler-builtins/libm/src/math/service/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/service/rem_pio2f.rs deleted file mode 100644 index a908ccd9f75..00000000000 --- a/library/compiler-builtins/libm/src/math/service/rem_pio2f.rs +++ /dev/null @@ -1,44 +0,0 @@ -use super::rem_pio2_large; - -use core::f64; - -const TOINT : f64 = 1.5 / f64::EPSILON; - -/// 53 bits of 2/pi -const INV_PIO2 : f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ -/// first 25 bits of pi/2 -const PIO2_1 : f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ -/// pi/2 - pio2_1 -const PIO2_1T : f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ - -/// Return the remainder of x rem pi/2 in *y -/// -/// use double precision for everything except passing x -/// use __rem_pio2_large() for large x -#[inline] -pub(crate) fn rem_pio2f(x : f32) -> (i32, f64) { - let x64 = x as f64; - - let mut tx : [f64; 1] = [0.,]; - let mut ty : [f64; 1] = [0.,]; - - let ix = x.to_bits() & 0x7fffffff; - /* 25+53 bit pi is good enough for medium size */ - if ix < 0x4dc90fdb { /* |x| ~< 2^28*(pi/2), medium size */ - /* Use a specialized rint() to get fn. Assume round-to-nearest. */ - let f_n = x64*INV_PIO2 + TOINT - TOINT; - return (f_n as i32, x64 - f_n*PIO2_1 - f_n*PIO2_1T); - } - if ix>=0x7f800000 { /* x is inf or NaN */ - return (0, x64-x64); - } - /* scale x into [2^23, 2^24-1] */ - let sign = (x.to_bits() >> 31) != 0; - let e0 = ((ix>>23) - (0x7f+23)) as i32; /* e0 = ilogb(|x|)-23, positive */ - tx[0] = f32::from_bits(ix - (e0<<23) as u32) as f64; - let n = rem_pio2_large(&tx, &mut ty, e0, 0); - if sign { - return (-n, -ty[0]); - } - (n, ty[0]) -} diff --git a/library/compiler-builtins/libm/src/math/service/sindf.rs b/library/compiler-builtins/libm/src/math/service/sindf.rs deleted file mode 100644 index a633545ba80..00000000000 --- a/library/compiler-builtins/libm/src/math/service/sindf.rs +++ /dev/null @@ -1,14 +0,0 @@ -/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ -const S1 : f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ -const S2 : f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ -const S3 : f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ -const S4 : f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ - -#[inline] -pub(crate) fn sindf(x : f64) -> f32 { - let z = x*x; - let w = z*z; - let r = S3 + z*S4; - let s = z*x; - ((x + s*(S1 + z*S2)) + s*w*r) as f32 -} diff --git a/library/compiler-builtins/libm/src/math/sindf.rs b/library/compiler-builtins/libm/src/math/sindf.rs new file mode 100644 index 00000000000..a633545ba80 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sindf.rs @@ -0,0 +1,14 @@ +/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +const S1 : f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ +const S2 : f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ +const S3 : f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ +const S4 : f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ + +#[inline] +pub(crate) fn sindf(x : f64) -> f32 { + let z = x*x; + let w = z*z; + let r = S3 + z*S4; + let s = z*x; + ((x + s*(S1 + z*S2)) + s*w*r) as f32 +} -- cgit 1.4.1-3-g733a5 From 1ba1301250f58ada230ff0211c383e59eb884f6a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 16:32:57 -0500 Subject: catch panics in tests so we can print the inputs that triggered the panic --- .../libm/test-generator/src/main.rs | 223 +++++++++++++++------ 1 file changed, 157 insertions(+), 66 deletions(-) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 6353b257dce..ca49179f187 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -62,6 +62,8 @@ macro_rules! f32_f32 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[(u32, u32)] = &[ @@ -71,16 +73,23 @@ macro_rules! f32_f32 { for case in CASES {{ let (inp, expected) = *case; - let outf = libm::{0}(f32::from_bits(inp)); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || - libm::_eqf(outi, expected)) {{ + if let Ok(outf) = + panic::catch_unwind(|| libm::{0}(f32::from_bits(inp))) + {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) + || libm::_eqf(outi, expected)) + {{ + panic!( + \"input: {{}}, output: {{}}, expected: {{}}\", + inp, outi, expected, + ); + }} + }} else {{ panic!( - \"input: {{}}, output: {{}}, expected: {{}}\", - inp, - outi, - expected, + \"input: {{}}, output: PANIC, expected: {{}}\", + inp, expected, ); }} }} @@ -124,6 +133,8 @@ macro_rules! f32f32_f32 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[((u32, u32), u32)] = &[ @@ -133,15 +144,25 @@ macro_rules! f32f32_f32 { for case in CASES {{ let ((i1, i2), expected) = *case; - let outf = libm::{0}(f32::from_bits(i1), f32::from_bits(i2)); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || - libm::_eqf(outi, expected)) {{ + if let Ok(outf) = panic::catch_unwind(|| {{ + libm::{0}(f32::from_bits(i1), f32::from_bits(i2)) + }}) {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) + || libm::_eqf(outi, expected)) + {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} else {{ panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", + \"input: {{:?}}, output: PANIC, expected: {{}}\", (i1, i2), - outi, expected, ); }} @@ -188,6 +209,8 @@ macro_rules! f32f32f32_f32 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[((u32, u32, u32), u32)] = &[ @@ -197,19 +220,29 @@ macro_rules! f32f32f32_f32 { for case in CASES {{ let ((i1, i2, i3), expected) = *case; - let outf = libm::{0}( - f32::from_bits(i1), - f32::from_bits(i2), - f32::from_bits(i3), - ); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || - libm::_eqf(outi, expected)) {{ + if let Ok(outf) = panic::catch_unwind(|| {{ + libm::{0}( + f32::from_bits(i1), + f32::from_bits(i2), + f32::from_bits(i3), + ) + }}) {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) + || libm::_eqf(outi, expected)) + {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2, i3), + outi, + expected, + ); + }} + }} else {{ panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", + \"input: {{:?}}, output: PANIC, expected: {{}}\", (i1, i2, i3), - outi, expected, ); }} @@ -253,6 +286,8 @@ macro_rules! f32i32_f32 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[((u32, i16), u32)] = &[ @@ -262,15 +297,25 @@ macro_rules! f32i32_f32 { for case in CASES {{ let ((i1, i2), expected) = *case; - let outf = libm::{0}(f32::from_bits(i1), i2 as i32); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || - libm::_eqf(outi, expected)) {{ + if let Ok(outf) = panic::catch_unwind(|| {{ + libm::{0}(f32::from_bits(i1), i2 as i32) + }}) {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) + || libm::_eqf(outi, expected)) + {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} else {{ panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", + \"input: {{:?}}, output: PANIC, expected: {{}}\", (i1, i2), - outi, expected, ); }} @@ -314,6 +359,8 @@ macro_rules! f64_f64 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[(u64, u64)] = &[ @@ -323,15 +370,25 @@ macro_rules! f64_f64 { for case in CASES {{ let (inp, expected) = *case; - let outf = libm::{0}(f64::from_bits(inp)); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || - libm::_eq(outi, expected)) {{ + if let Ok(outf) = panic::catch_unwind(|| {{ + libm::{0}(f64::from_bits(inp)) + }}) {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) + || libm::_eq(outi, expected)) + {{ + panic!( + \"input: {{}}, output: {{}}, expected: {{}}\", + inp, + outi, + expected, + ); + }} + }} else {{ panic!( - \"input: {{}}, output: {{}}, expected: {{}}\", + \"input: {{}}, output: PANIC, expected: {{}}\", inp, - outi, expected, ); }} @@ -376,6 +433,8 @@ macro_rules! f64f64_f64 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[((u64, u64), u64)] = &[ @@ -385,15 +444,24 @@ macro_rules! f64f64_f64 { for case in CASES {{ let ((i1, i2), expected) = *case; - let outf = libm::{0}(f64::from_bits(i1), f64::from_bits(i2)); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || - libm::_eq(outi, expected)) {{ + if let Ok(outf) = panic::catch_unwind(|| {{ + libm::{0}(f64::from_bits(i1), f64::from_bits(i2)) + }}) {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || + libm::_eq(outi, expected)) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} else {{ panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", + \"input: {{:?}}, output: PANIC, expected: {{}}\", (i1, i2), - outi, expected, ); }} @@ -440,6 +508,8 @@ macro_rules! f64f64f64_f64 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[((u64, u64, u64), u64)] = &[ @@ -449,19 +519,29 @@ macro_rules! f64f64f64_f64 { for case in CASES {{ let ((i1, i2, i3), expected) = *case; - let outf = libm::{0}( - f64::from_bits(i1), - f64::from_bits(i2), - f64::from_bits(i3), - ); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || - libm::_eq(outi, expected)) {{ + if let Ok(outf) = panic::catch_unwind(|| {{ + libm::{0}( + f64::from_bits(i1), + f64::from_bits(i2), + f64::from_bits(i3), + ) + }}) {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) + || libm::_eq(outi, expected)) + {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2, i3), + outi, + expected, + ); + }} + }} else {{ panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", + \"input: {{:?}}, output: PANIC, expected: {{}}\", (i1, i2, i3), - outi, expected, ); }} @@ -505,6 +585,8 @@ macro_rules! f64i32_f64 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[((u64, i16), u64)] = &[ @@ -514,15 +596,24 @@ macro_rules! f64i32_f64 { for case in CASES {{ let ((i1, i2), expected) = *case; - let outf = libm::{0}(f64::from_bits(i1), i2 as i32); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || - libm::_eq(outi, expected)) {{ + if let Ok(outf) = panic::catch_unwind(|| {{ + libm::{0}(f64::from_bits(i1), i2 as i32) + }}) {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || + libm::_eq(outi, expected)) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} else {{ panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", + \"input: {{:?}}, output: PANIC, expected: {{}}\", (i1, i2), - outi, expected, ); }} -- cgit 1.4.1-3-g733a5 From 6dbd8b33035d2f40eb7f4def4f340081d4234ed5 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 13 Jul 2018 17:41:54 -0400 Subject: implement hypotf --- library/compiler-builtins/libm/src/lib.rs | 2 - library/compiler-builtins/libm/src/math/hypotf.rs | 43 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/hypotf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index fa709ad754a..a6702c4a72b 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -88,7 +88,6 @@ pub trait F32Ext { #[cfg(todo)] fn cbrt(self) -> Self; - #[cfg(todo)] fn hypot(self, other: Self) -> Self; #[cfg(todo)] @@ -254,7 +253,6 @@ impl F32Ext for f32 { cbrtf(self) } - #[cfg(todo)] #[inline] fn hypot(self, other: Self) -> Self { hypotf(self, other) diff --git a/library/compiler-builtins/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/src/math/hypotf.rs new file mode 100644 index 00000000000..146aab4e446 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/hypotf.rs @@ -0,0 +1,43 @@ +use core::f32; + +use super::sqrtf; + +#[inline] +pub fn hypotf(mut x: f32, mut y: f32) -> f32 { + let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90 + let x1p_90 = f32::from_bits(0x12800000); // 0x1p-90f === 2 ^ -90 + + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let uti; + let mut z: f32; + + uxi &= -1i32 as u32 >> 1; + uyi &= -1i32 as u32 >> 1; + if uxi < uyi { + uti = uxi; + uxi = uyi; + uyi = uti; + } + + x = f32::from_bits(uxi); + y = f32::from_bits(uyi); + if uyi == 0xff<<23 { + return y; + } + if uxi >= 0xff<<23 || uyi == 0 || uxi - uyi >= 25<<23 { + return x + y; + } + + z = 1.; + if uxi >= (0x7f+60)<<23 { + z = x1p90; + x *= x1p_90; + y *= x1p_90; + } else if uyi < (0x7f-60)<<23 { + z = x1p_90; + x *= x1p90; + y *= x1p90; + } + z*sqrtf((x as f64 * x as f64 + y as f64 * y as f64) as f32) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 71b58dda883..a34ebd767e5 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -17,6 +17,7 @@ mod expf; mod floor; mod trunc; mod truncf; +mod hypotf; //mod service; @@ -34,6 +35,7 @@ pub use self::{ floor::floor, trunc::trunc, truncf::truncf, + hypotf::hypotf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 6353b257dce..290952bbd18 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -587,7 +587,7 @@ f32_f32! { // With signature `fn(f32, f32) -> f32` f32f32_f32! { // atan2f, - // hypotf, + hypotf, fmodf, powf, } -- cgit 1.4.1-3-g733a5 From 52dba9843b4f9d2ec2da3f8509ed6c8e48e091e6 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 00:52:28 +0300 Subject: rem_pio2_large comments --- .../libm/src/math/rem_pio2_large.rs | 216 ++++++++++----------- 1 file changed, 105 insertions(+), 111 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index deb985f1d1c..809724df419 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -1,117 +1,20 @@ use super::scalbn; use super::floor; -/// double x[],y[]; int e0,nx,prec; -/// -/// __rem_pio2_large return the last three digits of N with -/// y = x - N*pi/2 -/// so that |y| < pi/2. -/// -/// The method is to compute the integer (mod 8) and fraction parts of -/// (2/pi)*x without doing the full multiplication. In general we -/// skip the part of the product that are known to be a huge integer ( -/// more accurately, = 0 mod 8 ). Thus the number of operations are -/// independent of the exponent of the input. -/// -/// (2/pi) is represented by an array of 24-bit integers in ipio2[]. -/// -/// Input parameters: -/// x[] The input value (must be positive) is broken into nx -/// pieces of 24-bit integers in double precision format. -/// x[i] will be the i-th 24 bit of x. The scaled exponent -/// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 -/// match x's up to 24 bits. -/// -/// Example of breaking a double positive z into x[0]+x[1]+x[2]: -/// e0 = ilogb(z)-23 -/// z = scalbn(z,-e0) -/// for i = 0,1,2 -/// x[i] = floor(z) -/// z = (z-x[i])*2**24 -/// -/// y[] ouput result in an array of double precision numbers. -/// The dimension of y[] is: -/// 24-bit precision 1 -/// 53-bit precision 2 -/// 64-bit precision 2 -/// 113-bit precision 3 -/// The actual value is the sum of them. Thus for 113-bit -/// precison, one may have to do something like: -/// -/// long double t,w,r_head, r_tail; -/// t = (long double)y[2] + (long double)y[1]; -/// w = (long double)y[0]; -/// r_head = t+w; -/// r_tail = w - (r_head - t); -/// -/// e0 The exponent of x[0]. Must be <= 16360 or you need to -/// expand the ipio2 table. -/// -/// prec an integer indicating the precision: -/// 0 24 bits (single) -/// 1 53 bits (double) -/// 2 64 bits (extended) -/// 3 113 bits (quad) -/// External function: -/// double scalbn(), floor(); -/// -/// -/// Here is the description of some local variables: -/// -/// jk jk+1 is the initial number of terms of ipio2[] needed -/// in the computation. The minimum and recommended value -/// for jk is 3,4,4,6 for single, double, extended, and quad. -/// jk+1 must be 2 larger than you might expect so that our -/// recomputation test works. (Up to 24 bits in the integer -/// part (the 24 bits of it that we compute) and 23 bits in -/// the fraction part may be lost to cancelation before we -/// recompute.) -/// -/// jz local integer variable indicating the number of -/// terms of ipio2[] used. -/// -/// jx nx - 1 -/// -/// jv index for pointing to the suitable ipio2[] for the -/// computation. In general, we want -/// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 -/// is an integer. Thus -/// e0-3-24*jv >= 0 or (e0-3)/24 >= jv -/// Hence jv = max(0,(e0-3)/24). -/// -/// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. -/// -/// q[] double array with integral value, representing the -/// 24-bits chunk of the product of x and 2/pi. -/// -/// q0 the corresponding exponent of q[0]. Note that the -/// exponent for q[i] would be q0-24*i. -/// -/// PIo2[] double precision array, obtained by cutting pi/2 -/// into 24 bits chunks. -/// -/// f[] ipio2[] in floating point -/// -/// iq[] integer array by breaking up q[] in 24-bits chunk. -/// -/// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] -/// -/// ih integer. If >0 it indicates q[] is >= 0.5, hence -/// it also indicates the *sign* of the result. +// initial value for jk +const INIT_JK : [usize; 4] = [3,4,4,6]; -const INIT_JK : [usize; 4] = [3,4,4,6]; /* initial value for jk */ - -/// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi -/// -/// integer array, contains the (24*i)-th to (24*i+23)-th -/// bit of 2/pi after binary point. The corresponding -/// floating value is -/// -/// ipio2[i] * 2^(-24(i+1)). -/// -/// NB: This table must have at least (e0-3)/24 + jk terms. -/// For quad precision (e0 <= 16360, jk = 6), this is 686. -#[cfg(not(ldbl_max_exp_more1024))] +// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi +// +// integer array, contains the (24*i)-th to (24*i+23)-th +// bit of 2/pi after binary point. The corresponding +// floating value is +// +// ipio2[i] * 2^(-24(i+1)). +// +// NB: This table must have at least (e0-3)/24 + jk terms. +// For quad precision (e0 <= 16360, jk = 6), this is 686. +#[cfg(target_pointer_width = "32")] const IPIO2 : [i32; 66] = [ 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, @@ -126,7 +29,7 @@ const IPIO2 : [i32; 66] = [ 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, ]; -#[cfg(ldbl_max_exp_more1024)] +#[cfg(target_pointer_width = "64")] const IPIO2 : [i32; 690] = [ 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, @@ -256,6 +159,97 @@ const PIO2 : [f64; 8] = [ 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ ]; +// fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 +// +// Input parameters: +// x[] The input value (must be positive) is broken into nx +// pieces of 24-bit integers in double precision format. +// x[i] will be the i-th 24 bit of x. The scaled exponent +// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 +// match x's up to 24 bits. +// +// Example of breaking a double positive z into x[0]+x[1]+x[2]: +// e0 = ilogb(z)-23 +// z = scalbn(z,-e0) +// for i = 0,1,2 +// x[i] = floor(z) +// z = (z-x[i])*2**24 +// +// y[] ouput result in an array of double precision numbers. +// The dimension of y[] is: +// 24-bit precision 1 +// 53-bit precision 2 +// 64-bit precision 2 +// 113-bit precision 3 +// The actual value is the sum of them. Thus for 113-bit +// precison, one may have to do something like: +// +// long double t,w,r_head, r_tail; +// t = (long double)y[2] + (long double)y[1]; +// w = (long double)y[0]; +// r_head = t+w; +// r_tail = w - (r_head - t); +// +// e0 The exponent of x[0]. Must be <= 16360 or you need to +// expand the ipio2 table. +// +// prec an integer indicating the precision: +// 0 24 bits (single) +// 1 53 bits (double) +// 2 64 bits (extended) +// 3 113 bits (quad) +// +// Here is the description of some local variables: +// +// jk jk+1 is the initial number of terms of ipio2[] needed +// in the computation. The minimum and recommended value +// for jk is 3,4,4,6 for single, double, extended, and quad. +// jk+1 must be 2 larger than you might expect so that our +// recomputation test works. (Up to 24 bits in the integer +// part (the 24 bits of it that we compute) and 23 bits in +// the fraction part may be lost to cancelation before we +// recompute.) +// +// jz local integer variable indicating the number of +// terms of ipio2[] used. +// +// jx nx - 1 +// +// jv index for pointing to the suitable ipio2[] for the +// computation. In general, we want +// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 +// is an integer. Thus +// e0-3-24*jv >= 0 or (e0-3)/24 >= jv +// Hence jv = max(0,(e0-3)/24). +// +// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. +// +// q[] double array with integral value, representing the +// 24-bits chunk of the product of x and 2/pi. +// +// q0 the corresponding exponent of q[0]. Note that the +// exponent for q[i] would be q0-24*i. +// +// PIo2[] double precision array, obtained by cutting pi/2 +// into 24 bits chunks. +// +// f[] ipio2[] in floating point +// +// iq[] integer array by breaking up q[] in 24-bits chunk. +// +// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] +// +// ih integer. If >0 it indicates q[] is >= 0.5, hence +// it also indicates the *sign* of the result. + +/// Return the last three digits of N with y = x - N*pi/2 +/// so that |y| < pi/2. +/// +/// The method is to compute the integer (mod 8) and fraction parts of +/// (2/pi)*x without doing the full multiplication. In general we +/// skip the part of the product that are known to be a huge integer ( +/// more accurately, = 0 mod 8 ). Thus the number of operations are +/// independent of the exponent of the input. #[inline] pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 { let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 -- cgit 1.4.1-3-g733a5 From a372fff7facd658e395ce833ff5de8ac3603a698 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 00:58:02 +0300 Subject: cfg fix --- library/compiler-builtins/libm/src/math/rem_pio2_large.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 809724df419..18dc721c651 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -255,7 +255,7 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) - #[cfg(not(ldbl_max_exp_more1024))] + #[cfg(target_pointer_width = "64")] assert!(e0 <= 16360); let nx = x.len(); -- cgit 1.4.1-3-g733a5 From 892cd4f5b83761f2abf96e27c109ad3a6d87bceb Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 13 Jul 2018 18:31:01 -0400 Subject: implement sqrt and hypot --- library/compiler-builtins/libm/src/lib.rs | 4 - library/compiler-builtins/libm/src/math/hypot.rs | 74 ++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 4 + library/compiler-builtins/libm/src/math/sqrt.rs | 129 +++++++++++++++++++++ .../libm/test-generator/src/main.rs | 4 +- 5 files changed, 209 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/hypot.rs create mode 100644 library/compiler-builtins/libm/src/math/sqrt.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0fb555a7b49..3e25c16db29 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -391,7 +391,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn powf(self, n: Self) -> Self; - #[cfg(todo)] fn sqrt(self) -> Self; #[cfg(todo)] @@ -415,7 +414,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn cbrt(self) -> Self; - #[cfg(todo)] fn hypot(self, other: Self) -> Self; #[cfg(todo)] @@ -536,7 +534,6 @@ impl F64Ext for f64 { pow(self, n) } - #[cfg(todo)] #[inline] fn sqrt(self) -> Self { sqrt(self) @@ -584,7 +581,6 @@ impl F64Ext for f64 { cbrt(self) } - #[cfg(todo)] #[inline] fn hypot(self, other: Self) -> Self { hypot(self, other) diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs new file mode 100644 index 00000000000..dcc17d914fb --- /dev/null +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -0,0 +1,74 @@ +use core::f64; + +use super::sqrt; + +const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 + +fn sq(x: f64) -> (f64, f64) { + let xh: f64; + let xl: f64; + let xc: f64; + + xc = x * SPLIT; + xh = x - xc + xc; + xl = x - xh; + let hi = x*x; + let lo = xh*xh - hi + 2.*xh*xl + xl*xl; + (hi, lo) +} + +#[inline] +pub fn hypot(mut x: f64, mut y: f64) -> f64 { + let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700 + let x1p_700 = f64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700 + + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let uti; + let ex: i64; + let ey: i64; + let mut z: f64; + + /* arrange |x| >= |y| */ + uxi &= -1i64 as u64 >> 1; + uyi &= -1i64 as u64 >> 1; + if uxi < uyi { + uti = uxi; + uxi = uyi; + uyi = uti; + } + + /* special cases */ + ex = (uxi>>52) as i64; + ey = (uyi>>52) as i64; + x = f64::from_bits(uxi); + y = f64::from_bits(uyi); + /* note: hypot(inf,nan) == inf */ + if ey == 0x7ff { + return y; + } + if ex == 0x7ff || uyi == 0 { + return x; + } + /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ + /* 64 difference is enough for ld80 double_t */ + if ex - ey > 64 { + return x + y; + } + + /* precise sqrt argument in nearest rounding mode without overflow */ + /* xh*xh must not overflow and xl*xl must not underflow in sq */ + z = 1.; + if ex > 0x3ff+510 { + z = x1p700; + x *= x1p_700; + y *= x1p_700; + } else if ey < 0x3ff-450 { + z = x1p_700; + x *= x1p700; + y *= x1p700; + } + let (hx, lx) = sq(x); + let (hy, ly) = sq(y); + return z*sqrt(ly+lx+hy+hx); +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index a34ebd767e5..444652e81ef 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -11,12 +11,14 @@ mod powf; mod round; mod scalbn; mod scalbnf; +mod sqrt; mod sqrtf; mod logf; mod expf; mod floor; mod trunc; mod truncf; +mod hypot; mod hypotf; //mod service; @@ -29,12 +31,14 @@ pub use self::{ round::round, scalbn::scalbn, scalbnf::scalbnf, + sqrt::sqrt, sqrtf::sqrtf, logf::logf, expf::expf, floor::floor, trunc::trunc, truncf::truncf, + hypot::hypot, hypotf::hypotf, }; diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs new file mode 100644 index 00000000000..49fc58fff03 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -0,0 +1,129 @@ +use core::f64; + +const TINY: f64 = 1.0e-300; + +#[inline] +pub fn sqrt(x: f64) -> f64 { + let mut z: f64; + let sign: u32 = 0x80000000; + let mut ix0: i32; + let mut s0: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: u32; + let mut t1: u32; + let mut s1: u32; + let mut ix1: u32; + let mut q1: u32; + + ix0 = (x.to_bits() >> 32) as i32; + ix1 = x.to_bits() as u32; + + /* take care of Inf and NaN */ + if (ix0&0x7ff00000) == 0x7ff00000 { + return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if ix0 <= 0 { + if ((ix0&!(sign as i32))|ix1 as i32) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix0 < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } + /* normalize x */ + m = ix0>>20; + if m == 0 { /* subnormal x */ + while ix0 == 0 { + m -= 21; + ix0 |= (ix1>>11) as i32; + ix1 <<= 21; + } + i=0; + while (ix0&0x00100000) == 0 { + i += 1; + ix0 <<= 1; + } + m -= i - 1; + ix0 |= (ix1>>(32-i)) as i32; + ix1 <<= i; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0&0x000fffff)|0x00100000; + if (m & 1) == 1 { /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1&sign)>>31) as i32; + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1&sign)>>31) as i32; + ix1 += ix1; + q = 0; /* [q,q1] = sqrt(x) */ + q1 = 0; + s0 = 0; + s1 = 0; + r = 0x00200000; /* r = moving bit from right to left */ + + while r != 0 { + t = s0 + r as i32; + if t <= ix0 { + s0 = t + r as i32; + ix0 -= t; + q += r as i32; + } + ix0 += ix0 + ((ix1&sign)>>31) as i32; + ix1 += ix1; + r >>= 1; + } + + r = sign; + while r != 0 { + t1 = s1 + r; + t = s0; + if t < ix0 || (t == ix0 && t1 <= ix1) { + s1 = t1 + r; + if (t1&sign) == sign && (s1&sign) == 0 { + s0 += 1; + } + ix0 -= t; + if ix1 < t1 { + ix0 -= 1; + } + ix1 -= t1; + q1 += r; + } + ix0 += ix0 + ((ix1&sign)>>31) as i32; + ix1 += ix1; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if (ix0 as u32|ix1) != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if q1 == 0xffffffff { + q1 = 0; + q+=1; + } else if z > 1.0 { + if q1 == 0xfffffffe { + q += 1; + } + q1 += 2; + } else { + q1 += q1 & 1; + } + } + } + ix0 = (q>>1) + 0x3fe00000; + ix1 = q1>>1; + if (q&1) == 1 { + ix1 |= sign; + } + ix0 += m << 20; + f64::from_bits((ix0 as u64) << 32 | ix1 as u64) +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 8da1a920eef..ce20e80d195 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -713,7 +713,7 @@ f64_f64! { round, // sin, // sinh, - // sqrt, + sqrt, // tan, // tanh, trunc, @@ -725,7 +725,7 @@ f64f64_f64! { // atan2, // fdim, // fmod, - // hypot, + hypot, // pow, } -- cgit 1.4.1-3-g733a5 From aaa56fba356a4961baf98ccb8d8ff85c589ea19c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 17:52:58 -0500 Subject: move a chunk of the README into CONTRIBUTING.md --- library/compiler-builtins/libm/CONTRIBUTING.md | 87 +++++++++++++++++++++++ library/compiler-builtins/libm/README.md | 52 +------------- library/compiler-builtins/libm/src/lib.rs | 2 +- library/compiler-builtins/libm/src/math/trunc.rs | 8 +++ library/compiler-builtins/libm/src/math/truncf.rs | 8 +++ 5 files changed, 105 insertions(+), 52 deletions(-) create mode 100644 library/compiler-builtins/libm/CONTRIBUTING.md diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md new file mode 100644 index 00000000000..1f0a05a3f8d --- /dev/null +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -0,0 +1,87 @@ +# How to contribute + +- Pick your favorite math function from the [issue tracker]. +- Look for the C implementation of the function in the [MUSL source code][src]. +- Copy paste the C code into a Rust file in the `src/math` directory and adjust `src/math/mod.rs` + accordingly. Also, uncomment the corresponding trait method in `src/lib.rs`. +- Run `cargo watch check` and fix the compiler errors. +- Tweak the bottom of `test-generator/src/main.rs` to add your function to the test suite. +- If you can, run the full test suite locally (see the [testing](#testing) section below). If you + can't, no problem! Your PR will be fully tested automatically. Though you may still want to add + and run some unit tests. See the bottom of [`src/math/truncf.rs`] for an example of such tests; + you can run unit tests with the `cargo test --lib` command. +- Send us a pull request! +- :tada: + +[issue tracker]: https://github.com/japaric/libm/issues +[src]: https://git.musl-libc.org/cgit/musl/tree/src/math +[`src/math/truncf.rs`]: https://github.com/japaric/libm/blob/master/src/math/truncf.rs + +Check [PR #65] for an example. + +[PR #65]: https://github.com/japaric/libm/pull/65 + +## Tips and tricks + +- *IMPORTANT* The code in this crate will end up being used in the `core` crate so it can **not** + have any external dependencies (other than `core` itself). + +- Only use relative imports within the `math` directory / module, e.g. `use self::fabs::fabs` or +`use super::isnanf`. Absolute imports from core are OK, e.g. `use core::u64`. + +- To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the + `GET_FLOAT_WORD` macro, or a union, to do this operation. + +- To reinterpret an integer as a float use the `f32::from_bits` constructor. The MUSL code uses the + `SET_FLOAT_WORD` macro, or a union, to do this operation. + +- You may encounter weird literals like `0x1p127f` in the MUSL code. These are hexadecimal floating + point literals. Rust (the language) doesn't support these kind of literals. The best way I have + found to deal with these literals is to turn them into their integer representation using the + [`hexf!`] macro and then turn them back into floats. See below: + +[`hexf!`]: https://crates.io/crates/hexf + +``` rust +// Step 1: write a program to convert the float into its integer representation +#[macro_use] +extern crate hexf; + +fn main() { + println!("{:#x}", hexf32!("0x1.0p127").to_bits()); +} +``` + +``` console +$ # Step 2: run the program +$ cargo run +0x7f000000 +``` + +``` rust +// Step 3: copy paste the output into libm +let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 12 +``` + +- Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`] + newtype to avoid this problem. + +[`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html + +## Testing + +The test suite of this crate can only be run on x86_64 Linux systems using the following commands: + +``` console +$ # The test suite depends on the `cross` tool so install it if you don't have it +$ cargo install cross + +$ # and the `cross` tool requires docker to be running +$ systemctl start docker + +$ # execute the test suite for the x86_64 target +$ TARGET=x86_64-unknown-linux-gnu bash ci/script.sh + +$ # execute the test suite for the ARMv7 target +$ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh +``` diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index cb29baf63a7..ce731a203d6 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -9,59 +9,9 @@ A port of [MUSL]'s libm to Rust. The short term goal of this library is to enable math support (e.g. `sin`, `atan2`) for the `wasm32-unknown-unknown` target. The longer term goal is to enable math support in the `core` crate. -## Testing - -The test suite of this crate can only be run on x86_64 Linux systems. - -``` -$ # The test suite depends on the `cross` tool so install it if you don't have it -$ cargo install cross - -$ # and the `cross` tool requires docker to be running -$ systemctl start docker - -$ # execute the test suite for the x86_64 target -$ TARGET=x86_64-unknown-linux-gnu bash ci/script.sh - -$ # execute the test suite for the ARMv7 target -$ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh -``` - ## Contributing -- Pick your favorite math function from the [issue tracker]. -- Look for the C implementation of the function in the [MUSL source code][src]. -- Copy paste the C code into a Rust file in the `src/math` directory and adjust `src/math/mod.rs` - accordingly. Also, uncomment the corresponding trait method in `src/lib.rs`. -- Run `cargo watch check` and fix the compiler errors. -- Tweak the bottom of `test-generator/src/main.rs` to add your function to the test suite. -- If you can, run the test suite locally. If you can't, no problem! Your PR will be tested - automatically. -- Send us a pull request! -- :tada: - -[issue tracker]: https://github.com/japaric/libm/issues -[src]: https://git.musl-libc.org/cgit/musl/tree/src/math - -Check [PR #2] for an example. - -[PR #2]: https://github.com/japaric/libm/pull/2 - -### Notes - -- Only use relative imports within the `math` directory / module, e.g. `use self::fabs::fabs` or -`use super::isnanf`. Absolute imports from core are OK, e.g. `use core::u64`. - -- To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the - `GET_FLOAT_WORD` macro, or a union, to do this operation. - -- To reinterpret an integer as a float use the `f32::from_bits` constructor. The MUSL code uses the - `SET_FLOAT_WORD` macro, or a union, to do this operation. - -- Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`] - newtype to avoid this problem. - -[`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html +Please check [CONTRIBUTING.md](CONTRIBUTING.md) ## License diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0fb555a7b49..32735f7ed6b 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -355,7 +355,7 @@ impl F32Ext for f32 { } } -/// Math support for `f32` +/// Math support for `f64` /// /// This trait is sealed and cannot be implemented outside of `libm`. pub trait F64Ext: private::Sealed { diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index b50ffd77156..6bea67cbc16 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -22,3 +22,11 @@ pub fn trunc(x: f64) -> f64 { i &= !m; f64::from_bits(i) } + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::trunc(1.1), 1.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index f7d7249e351..9d42620d966 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -22,3 +22,11 @@ pub fn truncf(x: f32) -> f32 { i &= !m; f32::from_bits(i) } + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::truncf(1.1), 1.0); + } +} -- cgit 1.4.1-3-g733a5 From e6576930ef34b5617c0c46faa0937922fed9095d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 19:38:51 -0500 Subject: v0.1.0 --- library/compiler-builtins/libm/CHANGELOG.md | 12 ++++++++++++ library/compiler-builtins/libm/Cargo.toml | 8 +++++++- library/compiler-builtins/libm/README.md | 9 +++++++-- 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/CHANGELOG.md diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md new file mode 100644 index 00000000000..c3e74a81433 --- /dev/null +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -0,0 +1,12 @@ +# Change Log + +All notable changes to this project will be documented in this file. +This project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +## v0.1.0 - 2018-07-13 + +- Initial release + +[Unreleased]: https://github.com/japaric/libm/compare/v0.1.0...HEAD diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index e3498eed038..5a1ae4a6c92 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -1,7 +1,13 @@ [package] +authors = ["Jorge Aparicio "] +categories = ["no-std"] +description = "libm in pure Rust" +documentation = "https://docs.rs/libm" +keywords = ["libm", "math"] +license = "MIT OR Apache-2.0" name = "libm" +repository = "https://github.com/japaric/libm" version = "0.1.0" -authors = ["Jorge Aparicio "] [workspace] members = ["cb", "test-generator"] \ No newline at end of file diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index ce731a203d6..6d8f9c49cc3 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -6,8 +6,13 @@ A port of [MUSL]'s libm to Rust. ## Goals -The short term goal of this library is to enable math support (e.g. `sin`, `atan2`) for the -`wasm32-unknown-unknown` target. The longer term goal is to enable math support in the `core` crate. +The short term goal of this library is to [enable math support (e.g. `sin`, `atan2`) for the +`wasm32-unknown-unknown` target][wasm] (cf. [rust-lang-nursery/compiler-builtins][pr]). The longer +term goal is to enable [math support in the `core` crate][core]. + +[wasm]: https://github.com/japaric/libm/milestone/1 +[pr]: https://github.com/rust-lang-nursery/compiler-builtins/pull/248 +[core]: https://github.com/japaric/libm/milestone/2 ## Contributing -- cgit 1.4.1-3-g733a5 From 9a9522cf4795a9aaf49458a914c964f98733a8b2 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 20:25:27 -0500 Subject: README: note that this crate is on crates.io and already usable --- library/compiler-builtins/libm/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 6d8f9c49cc3..02de9765a50 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -14,6 +14,30 @@ term goal is to enable [math support in the `core` crate][core]. [pr]: https://github.com/rust-lang-nursery/compiler-builtins/pull/248 [core]: https://github.com/japaric/libm/milestone/2 +## Already usable + +This crate is [on crates.io] and can be used today in stable `#![no_std]` programs like this: + +[on crates.io]: https://crates.io/crates/libm + +``` rust +#![no_std] + +extern crate libm; + +use libm::F32Ext; // adds methods to `f32` + +fn foo(x: f32) { + let y = x.sqrt(); + let z = libm::truncf(x); +} +``` + +Not all the math functions are available at the moment. Check the [API docs] to learn what's +currently supported. + +[API docs]: https://docs.rs/libm + ## Contributing Please check [CONTRIBUTING.md](CONTRIBUTING.md) -- cgit 1.4.1-3-g733a5 From bc94c70687c467d7fa4c655b90033de99d27211c Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Fri, 13 Jul 2018 20:46:09 -0500 Subject: implement roundf --- library/compiler-builtins/libm/src/lib.rs | 2 -- library/compiler-builtins/libm/src/math/mod.rs | 8 ++++-- library/compiler-builtins/libm/src/math/roundf.rs | 33 ++++++++++++++++++++++ .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/roundf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0d13590c7ec..b87e82b2ac6 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -41,7 +41,6 @@ pub trait F32Ext { #[cfg(todo)] fn ceil(self) -> Self; - #[cfg(todo)] fn round(self) -> Self; #[cfg(todo)] @@ -160,7 +159,6 @@ impl F32Ext for f32 { ceilf(self) } - #[cfg(todo)] #[inline] fn round(self) -> Self { roundf(self) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 41359bf8c05..8032bdabf9a 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -1,7 +1,9 @@ macro_rules! force_eval { ($e:expr) => { - unsafe { ::core::ptr::read_volatile(&$e); } - } + unsafe { + ::core::ptr::read_volatile(&$e); + } + }; } mod fabs; @@ -9,6 +11,7 @@ mod fabsf; mod fmodf; mod powf; mod round; +mod roundf; mod scalbnf; mod sqrtf; @@ -17,6 +20,7 @@ pub use self::fabsf::fabsf; pub use self::fmodf::fmodf; pub use self::powf::powf; pub use self::round::round; +pub use self::roundf::roundf; pub use self::scalbnf::scalbnf; pub use self::sqrtf::sqrtf; diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs new file mode 100644 index 00000000000..bd2488fa99c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -0,0 +1,33 @@ +use core::f32; + +const TOINT: f32 = 1.0 / f32::EPSILON; + +pub fn roundf(mut x: f32) -> f32 { + let i = x.to_bits(); + let e: u32 = i >> 23 & 0xff; + let mut y: f32; + + if e >= 0x7f + 23 { + return x; + } + if i >> 31 != 0 { + x = -x; + } + if e < 0x7f - 1 { + force_eval!(x + TOINT); + return 0.0 * x; + } + y = x + TOINT - TOINT - x; + if y > 0.5f32 { + y = y + x - 1.0; + } else if y <= -0.5f32 { + y = y + x + 1.0; + } else { + y = y + x; + } + if i >> 31 != 0 { + -y + } else { + y + } +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 5ff78ffc8b3..2f78a8ed38d 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -574,7 +574,7 @@ f32_f32! { // fdimf, // log10f, // log2f, - // roundf, + roundf, // sinf, // sinhf, // tanf, -- cgit 1.4.1-3-g733a5 From f40b8096aa272135bb3d869e9b1a29535d674b40 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 05:20:09 +0300 Subject: add cosf test --- library/compiler-builtins/libm/test-generator/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 6353b257dce..40eac207c15 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -567,7 +567,7 @@ f32_f32! { // atanf, // cbrtf, // ceilf, - // cosf, + cosf, // coshf, // exp2f, expf, -- cgit 1.4.1-3-g733a5 From 6237ba289068254c34fca5ad014a1cf8ba9ccbee Mon Sep 17 00:00:00 2001 From: Jack Mott Date: Fri, 13 Jul 2018 21:32:59 -0500 Subject: adding ceilf and floorf for issues rust-lang/libm#56 and rust-lang/libm#54 --- library/compiler-builtins/libm/src/lib.rs | 4 --- library/compiler-builtins/libm/src/math/ceilf.rs | 29 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/floorf.rs | 30 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 4 +++ .../libm/test-generator/src/main.rs | 4 +-- 5 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/ceilf.rs create mode 100644 library/compiler-builtins/libm/src/math/floorf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 13e038bfc3b..783cc9e1818 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -34,10 +34,8 @@ pub fn _eq(a: u64, b: u64) -> bool { /// /// This trait is sealed and cannot be implemented outside of `libm`. pub trait F32Ext: private::Sealed { - #[cfg(todo)] fn floor(self) -> Self; - #[cfg(todo)] fn ceil(self) -> Self; #[cfg(todo)] @@ -142,13 +140,11 @@ pub trait F32Ext: private::Sealed { } impl F32Ext for f32 { - #[cfg(todo)] #[inline] fn floor(self) -> Self { floorf(self) } - #[cfg(todo)] #[inline] fn ceil(self) -> Self { ceilf(self) diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs new file mode 100644 index 00000000000..b4f58bfb86f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -0,0 +1,29 @@ +use core::f32; + +pub fn ceilf(x: f32) -> f32 { + let mut ui = x.to_bits(); + let e = (((ui >> 23) & 0xff) - 0x7f) as i32; + + if e >= 23 { + return x; + } + if e >= 0 { + let m = 0x007fffff >> e; + if (ui & m) == 0 { + return x; + } + force_eval!(x + f32::from_bits(0x7b800000)); + if ui >> 31 == 0 { + ui += m; + } + ui &= !m; + } else { + force_eval!(x + f32::from_bits(0x7b800000)); + if ui >> 31 != 0 { + return -0.0; + } else if ui << 1 != 0 { + return 1.0; + } + } + return f32::from_bits(ui); +} diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs new file mode 100644 index 00000000000..9c263b51828 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -0,0 +1,30 @@ +use core::f32; + +#[inline] +pub fn floorf(x: f32) -> f32 { + let mut ui = x.to_bits(); + let e = (((ui >> 23) & 0xff) - 0x7f) as i32; + + if e >= 23 { + return x; + } + if e >= 0 { + let m: u32 = 0x007fffff >> e; + if (ui & m) == 0 { + return x; + } + force_eval!(x + f32::from_bits(0x7b800000)); + if ui >> 31 != 0 { + ui += m; + } + ui &= !m; + } else { + force_eval!(x + f32::from_bits(0x7b800000)); + if ui >> 31 == 0 { + ui = 0; + } else if ui << 1 != 0 { + return -1.0; + } + } + return f32::from_bits(ui); +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 444652e81ef..2ddaa272835 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -4,8 +4,10 @@ macro_rules! force_eval { } } +mod ceilf; mod fabs; mod fabsf; +mod floorf; mod fmodf; mod powf; mod round; @@ -24,8 +26,10 @@ mod hypotf; //mod service; pub use self::{ + ceilf::ceilf, fabs::fabs, fabsf::fabsf, + floorf::floorf, fmodf::fmodf, powf::powf, round::round, diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index ce20e80d195..1d6168e4bc2 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -652,12 +652,12 @@ fn main() -> Result<(), Box> { // With signature `fn(f32) -> f32` f32_f32! { // acosf, - // floorf, + floorf, truncf, // asinf, // atanf, // cbrtf, - // ceilf, + ceilf, // cosf, // coshf, // exp2f, -- cgit 1.4.1-3-g733a5 From 8bdbe460728b1de630b96a3164bb448b5083a007 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 21:51:07 -0500 Subject: run cargo-fmt --- library/compiler-builtins/libm/src/math/expf.rs | 73 ++++++++++++---------- library/compiler-builtins/libm/src/math/floor.rs | 32 +++++----- library/compiler-builtins/libm/src/math/hypot.rs | 14 ++--- library/compiler-builtins/libm/src/math/hypotf.rs | 10 +-- library/compiler-builtins/libm/src/math/logf.rs | 45 ++++++------- library/compiler-builtins/libm/src/math/mod.rs | 32 +++------- library/compiler-builtins/libm/src/math/round.rs | 2 +- library/compiler-builtins/libm/src/math/scalbn.rs | 12 ++-- library/compiler-builtins/libm/src/math/scalbnf.rs | 12 ++-- library/compiler-builtins/libm/src/math/sqrt.rs | 60 +++++++++--------- 10 files changed, 143 insertions(+), 149 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index 1b645654e36..cffb557719f 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -1,60 +1,67 @@ use super::scalbnf; -const HALF : [f32; 2] = [0.5,-0.5]; -const LN2_HI : f32 = 6.9314575195e-01; /* 0x3f317200 */ -const LN2_LO : f32 = 1.4286067653e-06; /* 0x35bfbe8e */ -const INV_LN2 : f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ +const HALF: [f32; 2] = [0.5, -0.5]; +const LN2_HI: f32 = 6.9314575195e-01; /* 0x3f317200 */ +const LN2_LO: f32 = 1.4286067653e-06; /* 0x35bfbe8e */ +const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ /* * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 */ -const P1 : f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ -const P2 : f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ +const P1: f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ +const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ #[inline] pub fn expf(mut x: f32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ - + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ + let mut hx = x.to_bits(); - let sign = (hx >> 31) as i32; /* sign bit of x */ - let signb : bool = sign != 0; - hx &= 0x7fffffff; /* high word of |x| */ - + let sign = (hx >> 31) as i32; /* sign bit of x */ + let signb: bool = sign != 0; + hx &= 0x7fffffff; /* high word of |x| */ + /* special cases */ - if hx >= 0x42aeac50 { /* if |x| >= -87.33655f or NaN */ - if hx > 0x7f800000 {/* NaN */ + if hx >= 0x42aeac50 { + /* if |x| >= -87.33655f or NaN */ + if hx > 0x7f800000 { + /* NaN */ return x; } - if (hx >= 0x42b17218) && (!signb) { /* x >= 88.722839f */ + if (hx >= 0x42b17218) && (!signb) { + /* x >= 88.722839f */ /* overflow */ x *= x1p127; return x; } if signb { /* underflow */ - force_eval!(-x1p_126/x); - if hx >= 0x42cff1b5 { /* x <= -103.972084f */ - return 0. + force_eval!(-x1p_126 / x); + if hx >= 0x42cff1b5 { + /* x <= -103.972084f */ + return 0.; } } } - + /* argument reduction */ - let k : i32; - let hi : f32; - let lo : f32; - if hx > 0x3eb17218 { /* if |x| > 0.5 ln2 */ - if hx > 0x3f851592 { /* if |x| > 1.5 ln2 */ - k = (INV_LN2*x + HALF[sign as usize]) as i32; + let k: i32; + let hi: f32; + let lo: f32; + if hx > 0x3eb17218 { + /* if |x| > 0.5 ln2 */ + if hx > 0x3f851592 { + /* if |x| > 1.5 ln2 */ + k = (INV_LN2 * x + HALF[sign as usize]) as i32; } else { k = 1 - sign - sign; } let kf = k as f32; - hi = x - kf*LN2_HI; /* k*ln2hi is exact here */ - lo = kf*LN2_LO; + hi = x - kf * LN2_HI; /* k*ln2hi is exact here */ + lo = kf * LN2_LO; x = hi - lo; - } else if hx > 0x39000000 { /* |x| > 2**-14 */ + } else if hx > 0x39000000 { + /* |x| > 2**-14 */ k = 0; hi = x; lo = 0.; @@ -63,11 +70,11 @@ pub fn expf(mut x: f32) -> f32 { force_eval!(x1p127 + x); return 1. + x; } - + /* x is now in primary range */ - let xx = x*x; - let c = x - xx*(P1+xx*P2); - let y = 1. + (x*c/(2.-c) - lo + hi); + let xx = x * x; + let c = x - xx * (P1 + xx * P2); + let y = 1. + (x * c / (2. - c) - lo + hi); if k == 0 { y } else { diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index a5fb1757413..997865d39e9 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -1,27 +1,27 @@ use core::f64; -const TOINT : f64 = 1. / f64::EPSILON; +const TOINT: f64 = 1. / f64::EPSILON; #[inline] -pub fn floor(x : f64) -> f64 { +pub fn floor(x: f64) -> f64 { let ui = x.to_bits(); - let e = ((ui >> 52) & 0x7ff) as i32; + let e = ((ui >> 52) & 0x7ff) as i32; - if (e >= 0x3ff+52) || (x == 0.) { - return x; + if (e >= 0x3ff + 52) || (x == 0.) { + return x; } - /* y = int(x) - x, where int(x) is an integer neighbor of x */ - let y = if (ui >> 63) != 0 { - x - TOINT + TOINT - x - } else { - x + TOINT - TOINT - x + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + let y = if (ui >> 63) != 0 { + x - TOINT + TOINT - x + } else { + x + TOINT - TOINT - x }; - /* special case because of non-nearest rounding modes */ - if e <= 0x3ff-1 { - force_eval!(y); - return if (ui >> 63) != 0 { -1. } else { 0. }; - } - if y > 0. { + /* special case because of non-nearest rounding modes */ + if e <= 0x3ff - 1 { + force_eval!(y); + return if (ui >> 63) != 0 { -1. } else { 0. }; + } + if y > 0. { x + y - 1. } else { x + y diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs index dcc17d914fb..7ad1baf796c 100644 --- a/library/compiler-builtins/libm/src/math/hypot.rs +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -12,8 +12,8 @@ fn sq(x: f64) -> (f64, f64) { xc = x * SPLIT; xh = x - xc + xc; xl = x - xh; - let hi = x*x; - let lo = xh*xh - hi + 2.*xh*xl + xl*xl; + let hi = x * x; + let lo = xh * xh - hi + 2. * xh * xl + xl * xl; (hi, lo) } @@ -39,8 +39,8 @@ pub fn hypot(mut x: f64, mut y: f64) -> f64 { } /* special cases */ - ex = (uxi>>52) as i64; - ey = (uyi>>52) as i64; + ex = (uxi >> 52) as i64; + ey = (uyi >> 52) as i64; x = f64::from_bits(uxi); y = f64::from_bits(uyi); /* note: hypot(inf,nan) == inf */ @@ -59,16 +59,16 @@ pub fn hypot(mut x: f64, mut y: f64) -> f64 { /* precise sqrt argument in nearest rounding mode without overflow */ /* xh*xh must not overflow and xl*xl must not underflow in sq */ z = 1.; - if ex > 0x3ff+510 { + if ex > 0x3ff + 510 { z = x1p700; x *= x1p_700; y *= x1p_700; - } else if ey < 0x3ff-450 { + } else if ey < 0x3ff - 450 { z = x1p_700; x *= x1p700; y *= x1p700; } let (hx, lx) = sq(x); let (hy, ly) = sq(y); - return z*sqrt(ly+lx+hy+hx); + return z * sqrt(ly + lx + hy + hx); } diff --git a/library/compiler-builtins/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/src/math/hypotf.rs index 146aab4e446..d59710ada39 100644 --- a/library/compiler-builtins/libm/src/math/hypotf.rs +++ b/library/compiler-builtins/libm/src/math/hypotf.rs @@ -22,22 +22,22 @@ pub fn hypotf(mut x: f32, mut y: f32) -> f32 { x = f32::from_bits(uxi); y = f32::from_bits(uyi); - if uyi == 0xff<<23 { + if uyi == 0xff << 23 { return y; } - if uxi >= 0xff<<23 || uyi == 0 || uxi - uyi >= 25<<23 { + if uxi >= 0xff << 23 || uyi == 0 || uxi - uyi >= 25 << 23 { return x + y; } z = 1.; - if uxi >= (0x7f+60)<<23 { + if uxi >= (0x7f + 60) << 23 { z = x1p90; x *= x1p_90; y *= x1p_90; - } else if uyi < (0x7f-60)<<23 { + } else if uyi < (0x7f - 60) << 23 { z = x1p_90; x *= x1p90; y *= x1p90; } - z*sqrtf((x as f64 * x as f64 + y as f64 * y as f64) as f32) + z * sqrtf((x as f64 * x as f64 + y as f64 * y as f64) as f32) } diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs index 76b4ede1951..78c5e94ad92 100644 --- a/library/compiler-builtins/libm/src/math/logf.rs +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -1,24 +1,25 @@ -const LN2_HI : f32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO : f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1 : f32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ -const LG2 : f32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3 : f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4 : f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ #[inline] pub fn logf(mut x: f32) -> f32 { let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 - + let mut ix = x.to_bits(); let mut k = 0i32; - - if (ix < 0x00800000) || ((ix>>31) != 0) { /* x < 2**-126 */ - if ix<<1 == 0 { - return -1./(x*x); /* log(+-0)=-inf */ + + if (ix < 0x00800000) || ((ix >> 31) != 0) { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ } - if (ix>>31) != 0 { - return (x-x)/0.; /* log(-#) = NaN */ + if (ix >> 31) != 0 { + return (x - x) / 0.; /* log(-#) = NaN */ } /* subnormal number, scale up x */ k -= 25; @@ -32,18 +33,18 @@ pub fn logf(mut x: f32) -> f32 { /* reduce x into [sqrt(2)/2, sqrt(2)] */ ix += 0x3f800000 - 0x3f3504f3; - k += ((ix>>23) as i32) - 0x7f; + k += ((ix >> 23) as i32) - 0x7f; ix = (ix & 0x007fffff) + 0x3f3504f3; - x = f32::from_bits(ix); + x = f32::from_bits(ix); let f = x - 1.; - let s = f/(2. + f); - let z = s*s; - let w = z*z; - let t1 = w*(LG2+w*LG4); - let t2 = z*(LG1+w*LG3); + let s = f / (2. + f); + let z = s * s; + let w = z * z; + let t1 = w * (LG2 + w * LG4); + let t2 = z * (LG1 + w * LG3); let r = t2 + t1; - let hfsq = 0.5*f*f; + let hfsq = 0.5 * f * f; let dk = k as f32; - s*(hfsq+r) + dk*LN2_LO - hfsq + f + dk*LN2_HI + s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index d0121048d96..c43199f825c 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -7,10 +7,15 @@ macro_rules! force_eval { } mod ceilf; +mod expf; mod fabs; mod fabsf; +mod floor; mod floorf; mod fmodf; +mod hypot; +mod hypotf; +mod logf; mod powf; mod round; mod roundf; @@ -18,36 +23,15 @@ mod scalbn; mod scalbnf; mod sqrt; mod sqrtf; -mod logf; -mod expf; -mod floor; mod trunc; mod truncf; -mod hypot; -mod hypotf; //mod service; pub use self::{ - ceilf::ceilf, - fabs::fabs, - fabsf::fabsf, - floorf::floorf, - fmodf::fmodf, - powf::powf, - round::round, - roundf::roundf, - scalbn::scalbn, - scalbnf::scalbnf, - sqrt::sqrt, - sqrtf::sqrtf, - logf::logf, - expf::expf, - floor::floor, - trunc::trunc, - truncf::truncf, - hypot::hypot, - hypotf::hypotf, + ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, + hypot::hypot, hypotf::hypotf, logf::logf, powf::powf, round::round, roundf::roundf, + scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 2a9f67c1d0f..73d431c5183 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -26,7 +26,7 @@ pub fn round(mut x: f64) -> f64 { } else { y = y + x; } - + if i >> 63 != 0 { -y } else { diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs index 76e06f03ece..ad81072ddc9 100644 --- a/library/compiler-builtins/libm/src/math/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -1,11 +1,11 @@ #[inline] -pub fn scalbn(x : f64, mut n: i32) -> f64 { - let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 - let x1p53 = f64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53 +pub fn scalbn(x: f64, mut n: i32) -> f64 { + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 + let x1p53 = f64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53 let x1p_1022 = f64::from_bits(0x0010000000000000); // 0x1p-1022 === 2 ^ (-1022) - + let mut y = x; - + if n > 1023 { y *= x1p1023; n -= 1023; @@ -29,5 +29,5 @@ pub fn scalbn(x : f64, mut n: i32) -> f64 { } } } - y*f64::from_bits(((0x3ff+n) as u64)<<52) + y * f64::from_bits(((0x3ff + n) as u64) << 52) } diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs index 31f93d323c5..901497e5e51 100644 --- a/library/compiler-builtins/libm/src/math/scalbnf.rs +++ b/library/compiler-builtins/libm/src/math/scalbnf.rs @@ -1,9 +1,9 @@ #[inline] -pub fn scalbnf(mut x: f32, mut n : i32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 - let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 - +pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 + let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 + if n > 127 { x *= x1p127; n -= 127; @@ -25,5 +25,5 @@ pub fn scalbnf(mut x: f32, mut n : i32) -> f32 { } } } - x * f32::from_bits(((0x7f+n) as u32)<<23) + x * f32::from_bits(((0x7f + n) as u32) << 23) } diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 49fc58fff03..17de5a2e030 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -22,60 +22,62 @@ pub fn sqrt(x: f64) -> f64 { ix1 = x.to_bits() as u32; /* take care of Inf and NaN */ - if (ix0&0x7ff00000) == 0x7ff00000 { - return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + if (ix0 & 0x7ff00000) == 0x7ff00000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ } /* take care of zero */ if ix0 <= 0 { - if ((ix0&!(sign as i32))|ix1 as i32) == 0 { - return x; /* sqrt(+-0) = +-0 */ + if ((ix0 & !(sign as i32)) | ix1 as i32) == 0 { + return x; /* sqrt(+-0) = +-0 */ } if ix0 < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ } } /* normalize x */ - m = ix0>>20; - if m == 0 { /* subnormal x */ + m = ix0 >> 20; + if m == 0 { + /* subnormal x */ while ix0 == 0 { m -= 21; - ix0 |= (ix1>>11) as i32; + ix0 |= (ix1 >> 11) as i32; ix1 <<= 21; } - i=0; - while (ix0&0x00100000) == 0 { + i = 0; + while (ix0 & 0x00100000) == 0 { i += 1; ix0 <<= 1; } m -= i - 1; - ix0 |= (ix1>>(32-i)) as i32; + ix0 |= (ix1 >> (32 - i)) as i32; ix1 <<= i; } - m -= 1023; /* unbias exponent */ - ix0 = (ix0&0x000fffff)|0x00100000; - if (m & 1) == 1 { /* odd m, double x to make it even */ - ix0 += ix0 + ((ix1&sign)>>31) as i32; + m -= 1023; /* unbias exponent */ + ix0 = (ix0 & 0x000fffff) | 0x00100000; + if (m & 1) == 1 { + /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1 & sign) >> 31) as i32; ix1 += ix1; } - m >>= 1; /* m = [m/2] */ + m >>= 1; /* m = [m/2] */ /* generate sqrt(x) bit by bit */ - ix0 += ix0 + ((ix1&sign)>>31) as i32; + ix0 += ix0 + ((ix1 & sign) >> 31) as i32; ix1 += ix1; q = 0; /* [q,q1] = sqrt(x) */ q1 = 0; s0 = 0; s1 = 0; - r = 0x00200000; /* r = moving bit from right to left */ + r = 0x00200000; /* r = moving bit from right to left */ while r != 0 { t = s0 + r as i32; if t <= ix0 { - s0 = t + r as i32; + s0 = t + r as i32; ix0 -= t; - q += r as i32; + q += r as i32; } - ix0 += ix0 + ((ix1&sign)>>31) as i32; + ix0 += ix0 + ((ix1 & sign) >> 31) as i32; ix1 += ix1; r >>= 1; } @@ -83,10 +85,10 @@ pub fn sqrt(x: f64) -> f64 { r = sign; while r != 0 { t1 = s1 + r; - t = s0; + t = s0; if t < ix0 || (t == ix0 && t1 <= ix1) { s1 = t1 + r; - if (t1&sign) == sign && (s1&sign) == 0 { + if (t1 & sign) == sign && (s1 & sign) == 0 { s0 += 1; } ix0 -= t; @@ -96,19 +98,19 @@ pub fn sqrt(x: f64) -> f64 { ix1 -= t1; q1 += r; } - ix0 += ix0 + ((ix1&sign)>>31) as i32; + ix0 += ix0 + ((ix1 & sign) >> 31) as i32; ix1 += ix1; r >>= 1; } /* use floating add to find out rounding direction */ - if (ix0 as u32|ix1) != 0 { + if (ix0 as u32 | ix1) != 0 { z = 1.0 - TINY; /* raise inexact flag */ if z >= 1.0 { z = 1.0 + TINY; if q1 == 0xffffffff { q1 = 0; - q+=1; + q += 1; } else if z > 1.0 { if q1 == 0xfffffffe { q += 1; @@ -119,9 +121,9 @@ pub fn sqrt(x: f64) -> f64 { } } } - ix0 = (q>>1) + 0x3fe00000; - ix1 = q1>>1; - if (q&1) == 1 { + ix0 = (q >> 1) + 0x3fe00000; + ix1 = q1 >> 1; + if (q & 1) == 1 { ix1 |= sign; } ix0 += m << 20; -- cgit 1.4.1-3-g733a5 From 6e6642b48ca0e66625266e4b106eeec364297f9b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 21:53:01 -0500 Subject: force PR code to be formatted --- library/compiler-builtins/libm/.travis.yml | 2 ++ library/compiler-builtins/libm/ci/install.sh | 2 ++ library/compiler-builtins/libm/ci/script.sh | 6 ++---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index 0c083279347..ae03b660197 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -22,6 +22,8 @@ install: - bash ci/install.sh script: + # code must be already formatted + - cargo fmt -- --check - bash ci/script.sh after_script: set +e diff --git a/library/compiler-builtins/libm/ci/install.sh b/library/compiler-builtins/libm/ci/install.sh index efdbb06c206..68dd0f337ac 100644 --- a/library/compiler-builtins/libm/ci/install.sh +++ b/library/compiler-builtins/libm/ci/install.sh @@ -5,6 +5,8 @@ main() { cargo install cross fi + rustup component add rustfmt-preview + rustup target add x86_64-unknown-linux-musl if [ $TARGET != x86_64-unknown-linux-gnu ]; then diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index 3db6bfeb12d..d2900305250 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -10,10 +10,8 @@ main() { # generate tests cargo run --package test-generator --target x86_64-unknown-linux-musl - if cargo fmt --version >/dev/null 2>&1; then - # nicer syntax error messages (if any) - cargo fmt - fi + # nicer syntax error messages (if any) + cargo fmt # run tests cross test --target $TARGET --release -- cgit 1.4.1-3-g733a5 From 131cc1ac449a64d81ca371ae183f3fa2eeec1cf8 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 22:10:08 -0500 Subject: run cargo fmt -- --check on beta --- library/compiler-builtins/libm/.travis.yml | 4 ++-- library/compiler-builtins/libm/ci/install.sh | 7 +++++-- library/compiler-builtins/libm/ci/script.sh | 5 +++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index ae03b660197..2bbb60fc64d 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -15,6 +15,8 @@ matrix: - env: TARGET=powerpc64-unknown-linux-gnu - env: TARGET=powerpc64le-unknown-linux-gnu - env: TARGET=x86_64-unknown-linux-gnu + - env: TARGET=cargo-fmt + rust: beta before_install: set -e @@ -22,8 +24,6 @@ install: - bash ci/install.sh script: - # code must be already formatted - - cargo fmt -- --check - bash ci/script.sh after_script: set +e diff --git a/library/compiler-builtins/libm/ci/install.sh b/library/compiler-builtins/libm/ci/install.sh index 68dd0f337ac..4d9552d231b 100644 --- a/library/compiler-builtins/libm/ci/install.sh +++ b/library/compiler-builtins/libm/ci/install.sh @@ -1,12 +1,15 @@ set -euxo pipefail main() { + if [ $TARGET = cargo-fmt ]; then + rustup component add rustfmt-preview + return + fi + if ! hash cross >/dev/null 2>&1; then cargo install cross fi - rustup component add rustfmt-preview - rustup target add x86_64-unknown-linux-musl if [ $TARGET != x86_64-unknown-linux-gnu ]; then diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index d2900305250..a4f1b324d66 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -1,6 +1,11 @@ set -euxo pipefail main() { + if [ $TARGET = cargo-fmt ]; then + cargo fmt -- --check + return + fi + # quick check cargo check -- cgit 1.4.1-3-g733a5 From ea8d02ae0f0eee219144fe2aa96679e384b6d110 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 22:15:21 -0500 Subject: make cargo fmt in ci/script.sh optional --- library/compiler-builtins/libm/ci/script.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index a4f1b324d66..f2a294b488f 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -15,8 +15,10 @@ main() { # generate tests cargo run --package test-generator --target x86_64-unknown-linux-musl - # nicer syntax error messages (if any) - cargo fmt + if cargo fmt --version >/dev/null 2>&1; then + # nicer syntax error messages (if any) + cargo fmt + fi # run tests cross test --target $TARGET --release -- cgit 1.4.1-3-g733a5 From 30c31d32d337c69d1f7ce5142e3ec8dcfaa50d47 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 13 Jul 2018 23:40:57 -0400 Subject: implement log2 and log2f --- library/compiler-builtins/libm/src/lib.rs | 4 - library/compiler-builtins/libm/src/math/log2.rs | 86 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/log2f.rs | 71 ++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 7 +- .../libm/test-generator/src/main.rs | 4 +- 5 files changed, 164 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/log2.rs create mode 100644 library/compiler-builtins/libm/src/math/log2f.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 571cf365c8c..0194722af66 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -75,7 +75,6 @@ pub trait F32Ext: private::Sealed { fn log(self, base: Self) -> Self; - #[cfg(todo)] fn log2(self) -> Self; #[cfg(todo)] @@ -228,7 +227,6 @@ impl F32Ext for f32 { self.ln() / base.ln() } - #[cfg(todo)] #[inline] fn log2(self) -> Self { log2f(self) @@ -399,7 +397,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn log(self, base: Self) -> Self; - #[cfg(todo)] fn log2(self) -> Self; #[cfg(todo)] @@ -557,7 +554,6 @@ impl F64Ext for f64 { self.ln() / base.ln() } - #[cfg(todo)] #[inline] fn log2(self) -> Self { log2(self) diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs new file mode 100644 index 00000000000..c0d3263e3b4 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -0,0 +1,86 @@ +use core::f64; + +const IVLN2HI: f64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ +const IVLN2LO: f64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +pub fn log2(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let f: f64; + let s: f64; + let z: f64; + let r: f64; + let mut w: f64; + let t1: f64; + let t2: f64; + let y: f64; + let mut hi: f64; + let lo: f64; + let mut val_hi: f64; + let mut val_lo: f64; + let mut hx: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 0; + if hx < 0x00100000 || (hx >> 31) > 0 { + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (hx >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (hx >> 20) as i32 - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = (hx as u64) << 32 | (ui & 0xffffffff); + x = f64::from_bits(ui); + + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + ui = hi.to_bits(); + ui &= (-1i64 as u64) << 32; + hi = f64::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + + val_hi = hi * IVLN2HI; + val_lo = (lo + hi) * IVLN2LO + lo * IVLN2HI; + + /* spadd(val_hi, val_lo, y), except for not using double_t: */ + y = k.into(); + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs new file mode 100644 index 00000000000..47a917bdb8d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -0,0 +1,71 @@ +use core::f32; + +const IVLN2HI: f32 = 1.4428710938e+00; /* 0x3fb8b000 */ +const IVLN2LO: f32 = -1.7605285393e-04; /* 0xb9389ad4 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +pub fn log2f(mut x: f32) -> f32 { + let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 + + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let f: f32; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let mut hi: f32; + let lo: f32; + let mut ix: u32; + let mut k: i32; + + ix = ui; + k = 0; + if ix < 0x00800000 || (ix >> 31) > 0 { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (ix >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25f; + ui = x.to_bits(); + ix = ui; + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (ix >> 23) as i32 - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + ui = ix; + x = f32::from_bits(ui); + + f = x - 1.0; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + + hi = f - hfsq; + ui = hi.to_bits(); + ui &= 0xfffff000; + hi = f32::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + return (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as f32; +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c43199f825c..a82c1ba7e59 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -15,6 +15,8 @@ mod floorf; mod fmodf; mod hypot; mod hypotf; +mod log2; +mod log2f; mod logf; mod powf; mod round; @@ -30,8 +32,9 @@ mod truncf; pub use self::{ ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, logf::logf, powf::powf, round::round, roundf::roundf, - scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, + hypot::hypot, hypotf::hypotf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, + roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, + truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 257232ca694..7ec2292c349 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -664,7 +664,7 @@ f32_f32! { expf, // fdimf, // log10f, - // log2f, + log2f, logf, roundf, // sinf, @@ -709,7 +709,7 @@ f64_f64! { // log, // log10, // log1p, - // log2, + log2, round, // sin, // sinh, -- cgit 1.4.1-3-g733a5 From a749e176b170c4527813a5d3191b6f203458870d Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Fri, 13 Jul 2018 23:15:36 -0500 Subject: Implement fmod and tweak fmodf --- library/compiler-builtins/libm/src/math/fmod.rs | 80 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/fmodf.rs | 4 +- library/compiler-builtins/libm/src/math/mod.rs | 36 +++------- .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 91 insertions(+), 31 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fmod.rs diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs new file mode 100644 index 00000000000..23f0c4846c4 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -0,0 +1,80 @@ +use core::u64; + +#[inline] +pub fn fmod(x: f64, y: f64) -> f64 { + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let mut ex = (uxi >> 52 & 0x7ff) as i64; + let mut ey = (uyi >> 52 & 0x7ff) as i64; + let sx = uxi >> 63; + let mut i; + + if uyi << 1 == 0 || y.is_nan() || ex == 0x7ff { + return (x * y) / (x * y); + } + if uxi << 1 <= uyi << 1 { + if uxi << 1 == uyi << 1 { + return 0.0 * x; + } + return x; + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 12; + while i >> 63 == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= u64::MAX >> 12; + uxi |= 1 << 52; + } + if ey == 0 { + i = uyi << 12; + while i >> 63 == 0 { + ey -= 1; + i <<= 1; + } + uyi <<= -ey + 1; + } else { + uyi &= u64::MAX >> 12; + uyi |= 1 << 52; + } + + /* x mod y */ + while ex > ey { + i = uxi - uyi; + if i >> 63 == 0 { + if i == 0 { + return 0.0 * x; + } + uxi = i; + } + uxi <<= 1; + ex -= 1; + } + i = uxi - uyi; + if i >> 63 == 0 { + if i == 0 { + return 0.0 * x; + } + uxi = i; + } + while uxi >> 52 == 0 { + uxi <<= 1; + ex -= 1; + } + + /* scale result */ + if ex > 0 { + uxi -= 1 << 52; + uxi |= (ex as u64) << 52; + } else { + uxi >>= -ex + 1; + } + uxi |= (sx as u64) << 63; + + f64::from_bits(uxi) +} diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index 90977524908..8d0c2d5c82c 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -1,7 +1,5 @@ use core::u32; -use super::isnanf; - #[inline] pub fn fmodf(x: f32, y: f32) -> f32 { let mut uxi = x.to_bits(); @@ -11,7 +9,7 @@ pub fn fmodf(x: f32, y: f32) -> f32 { let sx = uxi & 0x80000000; let mut i; - if uyi << 1 == 0 || isnanf(y) || ex == 0xff { + if uyi << 1 == 0 || y.is_nan() || ex == 0xff { return (x * y) / (x * y); } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index d0121048d96..a81fc174bcb 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -7,10 +7,16 @@ macro_rules! force_eval { } mod ceilf; +mod expf; mod fabs; mod fabsf; +mod floor; mod floorf; +mod fmod; mod fmodf; +mod hypot; +mod hypotf; +mod logf; mod powf; mod round; mod roundf; @@ -18,38 +24,14 @@ mod scalbn; mod scalbnf; mod sqrt; mod sqrtf; -mod logf; -mod expf; -mod floor; mod trunc; mod truncf; -mod hypot; -mod hypotf; //mod service; pub use self::{ - ceilf::ceilf, - fabs::fabs, - fabsf::fabsf, - floorf::floorf, - fmodf::fmodf, - powf::powf, - round::round, - roundf::roundf, - scalbn::scalbn, - scalbnf::scalbnf, - sqrt::sqrt, - sqrtf::sqrtf, - logf::logf, - expf::expf, - floor::floor, - trunc::trunc, + ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmod::fmod, + fmodf::fmodf, hypot::hypot, hypotf::hypotf, logf::logf, powf::powf, round::round, + roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, - hypot::hypot, - hypotf::hypotf, }; - -fn isnanf(x: f32) -> bool { - x.to_bits() & 0x7fffffff > 0x7f800000 -} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 257232ca694..ee291027d21 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -724,7 +724,7 @@ f64_f64! { f64f64_f64! { // atan2, // fdim, - // fmod, + fmod, hypot, // pow, } -- cgit 1.4.1-3-g733a5 From 65368071063a2b4a7d117301d67b6f3b66c70d1a Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 00:24:22 -0400 Subject: implement log10 and log10f --- library/compiler-builtins/libm/src/lib.rs | 4 - library/compiler-builtins/libm/src/math/log10.rs | 98 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/log10f.rs | 76 +++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 8 +- .../libm/test-generator/src/main.rs | 4 +- 5 files changed, 181 insertions(+), 9 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/log10.rs create mode 100644 library/compiler-builtins/libm/src/math/log10f.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0194722af66..3ed89f72950 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -77,7 +77,6 @@ pub trait F32Ext: private::Sealed { fn log2(self) -> Self; - #[cfg(todo)] fn log10(self) -> Self; #[cfg(todo)] @@ -232,7 +231,6 @@ impl F32Ext for f32 { log2f(self) } - #[cfg(todo)] #[inline] fn log10(self) -> Self { log10f(self) @@ -399,7 +397,6 @@ pub trait F64Ext: private::Sealed { fn log2(self) -> Self; - #[cfg(todo)] fn log10(self) -> Self; #[cfg(todo)] @@ -559,7 +556,6 @@ impl F64Ext for f64 { log2(self) } - #[cfg(todo)] #[inline] fn log10(self) -> Self { log10(self) diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs new file mode 100644 index 00000000000..137d8966f52 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -0,0 +1,98 @@ +use core::f64; + +const IVLN10HI: f64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ +const IVLN10LO: f64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ +const LOG10_2HI: f64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ +const LOG10_2LO: f64 = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +#[inline] +pub fn log10(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let f: f64; + let s: f64; + let z: f64; + let r: f64; + let mut w: f64; + let t1: f64; + let t2: f64; + let dk: f64; + let y: f64; + let mut hi: f64; + let lo: f64; + let mut val_hi: f64; + let mut val_lo: f64; + let mut hx: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 0; + if hx < 0x00100000 || (hx >> 31) > 0 { + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (hx >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (hx >> 20) as i32 - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = (hx as u64) << 32 | (ui & 0xffffffff); + x = f64::from_bits(ui); + + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + + /* See log2.c for details. */ + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + ui = hi.to_bits(); + ui &= (-1i64 as u64) << 32; + hi = f64::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + + /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ + val_hi = hi * IVLN10HI; + dk = k as f64; + y = dk * LOG10_2HI; + val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI; + + /* + * Extra precision in for adding y is not strictly needed + * since there is no very large cancellation near x = sqrt(2) or + * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs + * with some parallelism and it reduces the error for many args. + */ + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs new file mode 100644 index 00000000000..58db093441f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log10f.rs @@ -0,0 +1,76 @@ +use core::f32; + +const IVLN10HI: f32 = 4.3432617188e-01; /* 0x3ede6000 */ +const IVLN10LO: f32 = -3.1689971365e-05; /* 0xb804ead9 */ +const LOG10_2HI: f32 = 3.0102920532e-01; /* 0x3e9a2080 */ +const LOG10_2LO: f32 = 7.9034151668e-07; /* 0x355427db */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +#[inline] +pub fn log10f(mut x: f32) -> f32 { + let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 + + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let f: f32; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let dk: f32; + let mut hi: f32; + let lo: f32; + let mut ix: u32; + let mut k: i32; + + ix = ui; + k = 0; + if ix < 0x00800000 || (ix >> 31) > 0 { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (ix >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25f; + ui = x.to_bits(); + ix = ui; + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (ix >> 23) as i32 - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + ui = ix; + x = f32::from_bits(ui); + + f = x - 1.0; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + + hi = f - hfsq; + ui = hi.to_bits(); + ui &= 0xfffff000; + hi = f32::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + dk = k as f32; + return dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI; +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index a82c1ba7e59..828eef85908 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -15,6 +15,8 @@ mod floorf; mod fmodf; mod hypot; mod hypotf; +mod log10; +mod log10f; mod log2; mod log2f; mod logf; @@ -32,9 +34,9 @@ mod truncf; pub use self::{ ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, - roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, - truncf::truncf, + hypot::hypot, hypotf::hypotf, log10::log10, log10f::log10f, log2::log2, log2f::log2f, + logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, + sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 7ec2292c349..799a354a90a 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -663,7 +663,7 @@ f32_f32! { // exp2f, expf, // fdimf, - // log10f, + log10f, log2f, logf, roundf, @@ -707,7 +707,7 @@ f64_f64! { // expm1, floor, // log, - // log10, + log10, // log1p, log2, round, -- cgit 1.4.1-3-g733a5 From bcafb03f6cdb51d14978de6117180af99829c746 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 23:34:37 -0500 Subject: update CONTRIBUTING --- library/compiler-builtins/libm/CONTRIBUTING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index 1f0a05a3f8d..6f8e984f300 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -10,7 +10,8 @@ can't, no problem! Your PR will be fully tested automatically. Though you may still want to add and run some unit tests. See the bottom of [`src/math/truncf.rs`] for an example of such tests; you can run unit tests with the `cargo test --lib` command. -- Send us a pull request! +- Send us a pull request! Make sure to run `cargo fmt` on your code before sending the PR. Also + include "closes #42" in the PR description to close the corresponding issue. - :tada: [issue tracker]: https://github.com/japaric/libm/issues -- cgit 1.4.1-3-g733a5 From e9575059748b90eba751e31883b4b0b733e6253b Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Fri, 13 Jul 2018 23:56:00 -0500 Subject: Fix log2 --- library/compiler-builtins/libm/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0194722af66..735f8162e5a 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -229,7 +229,7 @@ impl F32Ext for f32 { #[inline] fn log2(self) -> Self { - log2f(self) + self.log2f(self) } #[cfg(todo)] @@ -556,7 +556,7 @@ impl F64Ext for f64 { #[inline] fn log2(self) -> Self { - log2(self) + self.log2(self) } #[cfg(todo)] -- cgit 1.4.1-3-g733a5 From 45d9d8caa60dd8555f27834f0d854f0c9fcf5bba Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 08:13:35 +0300 Subject: fix bug in rem_pio2_large --- library/compiler-builtins/libm/src/math/cosdf.rs | 13 ---- library/compiler-builtins/libm/src/math/cosf.rs | 80 +++++++++++----------- library/compiler-builtins/libm/src/math/k_cosf.rs | 13 ++++ library/compiler-builtins/libm/src/math/k_sinf.rs | 14 ++++ library/compiler-builtins/libm/src/math/mod.rs | 8 +-- .../libm/src/math/rem_pio2_large.rs | 8 +-- library/compiler-builtins/libm/src/math/sindf.rs | 14 ---- 7 files changed, 75 insertions(+), 75 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/cosdf.rs create mode 100644 library/compiler-builtins/libm/src/math/k_cosf.rs create mode 100644 library/compiler-builtins/libm/src/math/k_sinf.rs delete mode 100644 library/compiler-builtins/libm/src/math/sindf.rs diff --git a/library/compiler-builtins/libm/src/math/cosdf.rs b/library/compiler-builtins/libm/src/math/cosdf.rs deleted file mode 100644 index 6c5e9d3495a..00000000000 --- a/library/compiler-builtins/libm/src/math/cosdf.rs +++ /dev/null @@ -1,13 +0,0 @@ -/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ -const C0 : f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ -const C1 : f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ -const C2 : f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ -const C3 : f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ - -#[inline] -pub(crate) fn cosdf(x : f64) -> f32 { - let z = x*x; - let w = z*z; - let r = C2+z*C3; - (((1.0+z*C0) + w*C1) + (w*z)*r) as f32 -} diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index f63724e791e..ef46d4a15f2 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -1,4 +1,4 @@ -use super::{cosdf, sindf, rem_pio2f}; +use super::{k_cosf, k_sinf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; @@ -14,52 +14,52 @@ pub fn cosf(x: f32) -> f32 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; - if ix <= 0x3f490fda { /* |x| ~<= pi/4 */ - if ix < 0x39800000 { /* |x| < 2**-12 */ - /* raise inexact if x != 0 */ - force_eval!(x + x1p120); - return 1.; - } - return cosdf(x64); - } - if ix <= 0x407b53d1 { /* |x| ~<= 5*pi/4 */ - if ix > 0x4016cbe3 { /* |x| ~> 3*pi/4 */ - return -cosdf(if sign { x64+C2_PIO2 } else { x64-C2_PIO2 }); + if ix <= 0x3f490fda { /* |x| ~<= pi/4 */ + if ix < 0x39800000 { /* |x| < 2**-12 */ + /* raise inexact if x != 0 */ + force_eval!(x + x1p120); + return 1.; + } + return k_cosf(x64); + } + if ix <= 0x407b53d1 { /* |x| ~<= 5*pi/4 */ + if ix > 0x4016cbe3 { /* |x| ~> 3*pi/4 */ + return -k_cosf(if sign { x64+C2_PIO2 } else { x64-C2_PIO2 }); } else { - if sign { - return sindf(x64 + C1_PIO2); - } else { - return sindf(C1_PIO2 - x64); + if sign { + return k_sinf(x64 + C1_PIO2); + } else { + return k_sinf(C1_PIO2 - x64); } - } - } - if ix <= 0x40e231d5 { /* |x| ~<= 9*pi/4 */ - if ix > 0x40afeddf { /* |x| ~> 7*pi/4 */ - return cosdf(if sign { x64+C4_PIO2 } else { x64-C4_PIO2 }); - } else { - if sign { - return sindf(-x64 - C3_PIO2); - } else { - return sindf(x64 - C3_PIO2); + } + } + if ix <= 0x40e231d5 { /* |x| ~<= 9*pi/4 */ + if ix > 0x40afeddf { /* |x| ~> 7*pi/4 */ + return k_cosf(if sign { x64+C4_PIO2 } else { x64-C4_PIO2 }); + } else { + if sign { + return k_sinf(-x64 - C3_PIO2); + } else { + return k_sinf(x64 - C3_PIO2); } - } - } + } + } - /* cos(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - return x-x; + /* cos(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x-x; } - /* general argument reduction needed */ - let (n, y) = rem_pio2f(x); + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); match n&3 { - 0 => { cosdf( y) }, - 1 => { sindf(-y) }, - 2 => { -cosdf( y) }, - _ => { sindf( y) }, + 0 => { k_cosf( y) }, + 1 => { k_sinf(-y) }, + 2 => { -k_cosf( y) }, + _ => { k_sinf( y) }, } } diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs new file mode 100644 index 00000000000..5d1ede7af92 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -0,0 +1,13 @@ +/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +const C0 : f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ +const C1 : f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ +const C2 : f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ +const C3 : f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ + +#[inline] +pub(crate) fn k_cosf(x : f64) -> f32 { + let z = x*x; + let w = z*z; + let r = C2+z*C3; + (((1.0+z*C0) + w*C1) + (w*z)*r) as f32 +} diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs new file mode 100644 index 00000000000..5eedab3aa64 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -0,0 +1,14 @@ +/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +const S1 : f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ +const S2 : f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ +const S3 : f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ +const S4 : f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ + +#[inline] +pub(crate) fn k_sinf(x : f64) -> f32 { + let z = x*x; + let w = z*z; + let r = S3 + z*S4; + let s = z*x; + ((x + s*(S1 + z*S2)) + s*w*r) as f32 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 4900bf94c53..d844ee153d6 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -36,14 +36,14 @@ pub use self::{ truncf::truncf, }; -mod sindf; -mod cosdf; +mod k_cosf; +mod k_sinf; mod rem_pio2f; mod rem_pio2_large; use self::{ - sindf::sindf, - cosdf::cosdf, + k_cosf::k_cosf, + k_sinf::k_sinf, rem_pio2f::rem_pio2f, rem_pio2_large::rem_pio2_large, }; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 18dc721c651..b5fa7e0af6b 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -1,5 +1,5 @@ -use super::scalbn; -use super::floor; +use math::scalbn; +use math::floor; // initial value for jk const INIT_JK : [usize; 4] = [3,4,4,6]; @@ -263,7 +263,7 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) let mut fw : f64; let mut n : i32; let mut ih : i32; - let mut z = 0f64; + let mut z : f64; let mut f : [f64;20] = [0.;20]; let mut fq : [f64;20] = [0.;20]; let mut q : [f64;20] = [0.;20]; @@ -308,7 +308,7 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) 'recompute: loop { /* distill q[] into iq[] reversingly */ let mut i = 0i32; - let mut z = q[jz]; + z = q[jz]; for j in (1..=jz).rev() { fw = (x1p_24*z) as i32 as f64; iq[i as usize] = (z - x1p24*fw) as i32; diff --git a/library/compiler-builtins/libm/src/math/sindf.rs b/library/compiler-builtins/libm/src/math/sindf.rs deleted file mode 100644 index a633545ba80..00000000000 --- a/library/compiler-builtins/libm/src/math/sindf.rs +++ /dev/null @@ -1,14 +0,0 @@ -/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ -const S1 : f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ -const S2 : f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ -const S3 : f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ -const S4 : f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ - -#[inline] -pub(crate) fn sindf(x : f64) -> f32 { - let z = x*x; - let w = z*z; - let r = S3 + z*S4; - let s = z*x; - ((x + s*(S1 + z*S2)) + s*w*r) as f32 -} -- cgit 1.4.1-3-g733a5 From 119bb9bd248aca933b27d8dc50892fcf2cca5402 Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Sat, 14 Jul 2018 00:15:24 -0500 Subject: Revert log2 breakage --- library/compiler-builtins/libm/src/lib.rs | 4 ++-- library/compiler-builtins/libm/src/math/mod.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 735f8162e5a..0194722af66 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -229,7 +229,7 @@ impl F32Ext for f32 { #[inline] fn log2(self) -> Self { - self.log2f(self) + log2f(self) } #[cfg(todo)] @@ -556,7 +556,7 @@ impl F64Ext for f64 { #[inline] fn log2(self) -> Self { - self.log2(self) + log2(self) } #[cfg(todo)] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e75429df59c..56488c43806 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -33,7 +33,7 @@ mod truncf; pub use self::{ ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmod::fmod, - fmodf::fmodf, hypot::hypot, hypotf::hypotf, logf::logf, powf::powf, round::round, - roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, - truncf::truncf, + fmodf::fmodf, hypot::hypot, hypotf::hypotf, log2::log2, log2f::log2f, logf::logf, powf::powf, + round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, + trunc::trunc, truncf::truncf, }; -- cgit 1.4.1-3-g733a5 From 83673acaa42c10f13f2792798ca8528058d09fb7 Mon Sep 17 00:00:00 2001 From: Opal Date: Sat, 14 Jul 2018 16:59:27 +1200 Subject: Add log implementation. Fixes rust-lang/libm#23 --- library/compiler-builtins/libm/src/lib.rs | 4 - library/compiler-builtins/libm/src/math/log.rs | 117 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 3 +- .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/log.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 3ed89f72950..39eb71e99c9 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -389,10 +389,8 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn exp2(self) -> Self; - #[cfg(todo)] fn ln(self) -> Self; - #[cfg(todo)] fn log(self, base: Self) -> Self; fn log2(self) -> Self; @@ -539,13 +537,11 @@ impl F64Ext for f64 { exp2(self) } - #[cfg(todo)] #[inline] fn ln(self) -> Self { log(self) } - #[cfg(todo)] #[inline] fn log(self, base: Self) -> Self { self.ln() / base.ln() diff --git a/library/compiler-builtins/libm/src/math/log.rs b/library/compiler-builtins/libm/src/math/log.rs new file mode 100644 index 00000000000..48e9fa79a46 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log.rs @@ -0,0 +1,117 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* log(x) + * Return the logarithm of x + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Remez algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +#[inline] +pub fn log(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui = x.to_bits(); + let mut hx: u32 = (ui >> 32) as u32; + let mut k: i32 = 0; + + if (hx < 0x00100000) || ((hx >> 31) != 0) { + /* x < 2**-126 */ + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if hx >> 31 != 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += ((hx >> 20) as i32) - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = ((hx as u64) << 32) | (ui & 0xffffffff); + x = f64::from_bits(ui); + + let f: f64 = x - 1.0; + let hfsq: f64 = 0.5 * f * f; + let s: f64 = f / (2.0 + f); + let z: f64 = s * s; + let w: f64 = z * z; + let t1: f64 = w * (LG2 + w * (LG4 + w * LG6)); + let t2: f64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + let r: f64 = t2 + t1; + let dk: f64 = k as f64; + return s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI; +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 828eef85908..6e514f86f9c 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -15,6 +15,7 @@ mod floorf; mod fmodf; mod hypot; mod hypotf; +mod log; mod log10; mod log10f; mod log2; @@ -34,7 +35,7 @@ mod truncf; pub use self::{ ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log10::log10, log10f::log10f, log2::log2, log2f::log2f, + hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, }; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 799a354a90a..6f8d3c68a32 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -706,7 +706,7 @@ f64_f64! { // exp2, // expm1, floor, - // log, + log, log10, // log1p, log2, -- cgit 1.4.1-3-g733a5 From 88faf19ca55c94eebff3a113e40158f4413dbb16 Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Sat, 14 Jul 2018 00:44:36 -0500 Subject: Run rustfmt --- library/compiler-builtins/libm/src/math/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 85592908147..afa8cd8ef23 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -35,7 +35,7 @@ mod truncf; pub use self::{ ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmod::fmod, - fmodf::fmodf, hypot::hypot, hypotf::hypotf, log10::log10, log10f::log10f, log2::log2, - log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, + fmodf::fmodf, hypot::hypot, hypotf::hypotf, log10::log10, log10f::log10f, log2::log2, + log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, }; -- cgit 1.4.1-3-g733a5 From ead2d02710a69bb83819a837fd5b9edcad2159a7 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 08:50:53 +0300 Subject: clean duplicates --- library/compiler-builtins/libm/src/math/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 30e7a2c592d..00945b258c8 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -27,9 +27,6 @@ mod scalbn; mod scalbnf; mod sqrt; mod sqrtf; -mod logf; -mod expf; -mod floor; mod cosf; mod trunc; mod truncf; -- cgit 1.4.1-3-g733a5 From f73c61b76230cbbb8061118ccd228411b7b84031 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 01:28:00 -0400 Subject: implement log1p and log1pf --- library/compiler-builtins/libm/src/lib.rs | 4 - library/compiler-builtins/libm/src/math/log1p.rs | 142 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/log1pf.rs | 97 ++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 8 +- .../libm/test-generator/src/main.rs | 3 +- 5 files changed, 246 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/log1p.rs create mode 100644 library/compiler-builtins/libm/src/math/log1pf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 39eb71e99c9..30f879769d0 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -114,7 +114,6 @@ pub trait F32Ext: private::Sealed { #[cfg(todo)] fn exp_m1(self) -> Self; - #[cfg(todo)] fn ln_1p(self) -> Self; #[cfg(todo)] @@ -295,7 +294,6 @@ impl F32Ext for f32 { expm1f(self) } - #[cfg(todo)] #[inline] fn ln_1p(self) -> Self { log1pf(self) @@ -432,7 +430,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn exp_m1(self) -> Self; - #[cfg(todo)] fn ln_1p(self) -> Self; #[cfg(todo)] @@ -616,7 +613,6 @@ impl F64Ext for f64 { expm1(self) } - #[cfg(todo)] #[inline] fn ln_1p(self) -> Self { log1p(self) diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs new file mode 100644 index 00000000000..7f7a5125bbb --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -0,0 +1,142 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double log1p(double x) + * Return the natural logarithm of 1+x. + * + * Method : + * 1. Argument Reduction: find k and f such that + * 1+x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * Note. If k=0, then f=x is exact. However, if k!=0, then f + * may not be representable exactly. In that case, a correction + * term is need. Let u=1+x rounded. Let c = (1+x)-u, then + * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), + * and add back the correction term c/u. + * (Note: when x > 2**53, one can simply return log(x)) + * + * 2. Approximation of log(1+f): See log.c + * + * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c + * + * Special cases: + * log1p(x) is NaN with signal if x < -1 (including -INF) ; + * log1p(+INF) is +INF; log1p(-1) is -INF with signal; + * log1p(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + * + * Note: Assuming log() return accurate answer, the following + * algorithm can be used to compute log1p(x) to within a few ULP: + * + * u = 1+x; + * if(u==1.0) return x ; else + * return log(u)*(x/(u-1.0)); + * + * See HP-15C Advanced Functions Handbook, p.193. + */ + +use core::f64; + +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +pub fn log1p(x: f64) -> f64 { + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let mut f: f64 = 0.; + let mut c: f64 = 0.; + let s: f64; + let z: f64; + let r: f64; + let w: f64; + let t1: f64; + let t2: f64; + let dk: f64; + let hx: u32; + let mut hu: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 1; + if hx < 0x3fda827a || (hx >> 31) > 0 { + /* 1+x < sqrt(2)+ */ + if hx >= 0xbff00000 { + /* x <= -1.0 */ + if x == -1. { + return x / 0.0; /* log1p(-1) = -inf */ + } + return (x - x) / 0.0; /* log1p(x<-1) = NaN */ + } + if hx << 1 < 0x3ca00000 << 1 { + /* |x| < 2**-53 */ + /* underflow if subnormal */ + if (hx & 0x7ff00000) == 0 { + force_eval!(x as f32); + } + return x; + } + if hx <= 0xbfd2bec4 { + /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0.; + f = x; + } + } else if hx >= 0x7ff00000 { + return x; + } + if k > 0 { + ui = (1. + x).to_bits(); + hu = (ui >> 32) as u32; + hu += 0x3ff00000 - 0x3fe6a09e; + k = (hu >> 20) as i32 - 0x3ff; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if k < 54 { + c = if k >= 2 { + 1. - (f64::from_bits(ui) - x) + } else { + x - (f64::from_bits(ui) - 1.) + }; + c /= f64::from_bits(ui); + } else { + c = 0.; + } + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + hu = (hu & 0x000fffff) + 0x3fe6a09e; + ui = (hu as u64) << 32 | (ui & 0xffffffff); + f = f64::from_bits(ui) - 1.; + } + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + dk = k as f64; + return s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI; +} diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs new file mode 100644 index 00000000000..c8e24225933 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -0,0 +1,97 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f32; + +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +pub fn log1pf(x: f32) -> f32 { + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let mut f: f32 = 0.; + let mut c: f32 = 0.; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let dk: f32; + let ix: u32; + let mut iu: u32; + let mut k: i32; + + ix = ui; + k = 1; + if ix < 0x3ed413d0 || (ix >> 31) > 0 { + /* 1+x < sqrt(2)+ */ + if ix >= 0xbf800000 { + /* x <= -1.0 */ + if x == -1. { + return x / 0.0; /* log1p(-1)=+inf */ + } + return (x - x) / 0.0; /* log1p(x<-1)=NaN */ + } + if ix << 1 < 0x33800000 << 1 { + /* |x| < 2**-24 */ + /* underflow if subnormal */ + if (ix & 0x7f800000) == 0 { + force_eval!(x * x); + } + return x; + } + if ix <= 0xbe95f619 { + /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0.; + f = x; + } + } else if ix >= 0x7f800000 { + return x; + } + if k > 0 { + ui = (1. + x).to_bits(); + iu = ui; + iu += 0x3f800000 - 0x3f3504f3; + k = (iu >> 23) as i32 - 0x7f; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if k < 25 { + c = if k >= 2 { + 1. - (f32::from_bits(ui) - x) + } else { + x - (f32::from_bits(ui) - 1.) + }; + c /= f32::from_bits(ui); + } else { + c = 0.; + } + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + iu = (iu & 0x007fffff) + 0x3f3504f3; + ui = iu; + f = f32::from_bits(ui) - 1.; + } + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + dk = k as f32; + return s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI; +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 6e514f86f9c..fb5e3df9090 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -18,6 +18,8 @@ mod hypotf; mod log; mod log10; mod log10f; +mod log1p; +mod log1pf; mod log2; mod log2f; mod logf; @@ -35,9 +37,9 @@ mod truncf; pub use self::{ ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log2::log2, log2f::log2f, - logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, - sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, + hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log1p::log1p, + log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, + scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 6f8d3c68a32..be5ed0784f8 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -664,6 +664,7 @@ f32_f32! { expf, // fdimf, log10f, + log1pf, log2f, logf, roundf, @@ -708,7 +709,7 @@ f64_f64! { floor, log, log10, - // log1p, + log1p, log2, round, // sin, -- cgit 1.4.1-3-g733a5 From d03ec1472b73bab2a33ea798bfba689ae86b57c2 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 09:17:41 +0300 Subject: revert changes --- library/compiler-builtins/libm/src/math/rem_pio2_large.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index b5fa7e0af6b..e1f5d133390 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -1,5 +1,5 @@ -use math::scalbn; -use math::floor; +use super::scalbn; +use super::floor; // initial value for jk const INIT_JK : [usize; 4] = [3,4,4,6]; -- cgit 1.4.1-3-g733a5 From 6548a83edfe2e3835a14fe636a6be1d086d345bf Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 02:26:19 -0400 Subject: add license and other comments to existing files --- library/compiler-builtins/libm/src/math/expf.rs | 15 +++++ library/compiler-builtins/libm/src/math/log10.rs | 19 ++++++ library/compiler-builtins/libm/src/math/log10f.rs | 15 +++++ library/compiler-builtins/libm/src/math/log2.rs | 19 ++++++ library/compiler-builtins/libm/src/math/log2f.rs | 15 +++++ library/compiler-builtins/libm/src/math/logf.rs | 15 +++++ library/compiler-builtins/libm/src/math/powf.rs | 15 +++++ library/compiler-builtins/libm/src/math/sqrt.rs | 78 +++++++++++++++++++++++ library/compiler-builtins/libm/src/math/sqrtf.rs | 15 +++++ 9 files changed, 206 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index cffb557719f..8ecc3b6abd6 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + use super::scalbnf; const HALF: [f32; 2] = [0.5, -0.5]; diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs index 137d8966f52..7c7afefa345 100644 --- a/library/compiler-builtins/libm/src/math/log10.rs +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -1,3 +1,22 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 10 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) + */ + use core::f64; const IVLN10HI: f64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs index 58db093441f..82b87c044b2 100644 --- a/library/compiler-builtins/libm/src/math/log10f.rs +++ b/library/compiler-builtins/libm/src/math/log10f.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log10.c. + */ + use core::f32; const IVLN10HI: f32 = 4.3432617188e-01; /* 0x3ede6000 */ diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index c0d3263e3b4..f6640d296c3 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -1,3 +1,22 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 2 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log2(x) = (f - f*f/2 + r)/log(2) + k + */ + use core::f64; const IVLN2HI: f64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs index 47a917bdb8d..c007ff9b097 100644 --- a/library/compiler-builtins/libm/src/math/log2f.rs +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log2.c. + */ + use core::f32; const IVLN2HI: f32 = 1.4428710938e+00; /* 0x3fb8b000 */ diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs index 78c5e94ad92..09519104174 100644 --- a/library/compiler-builtins/libm/src/math/logf.rs +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index f1dc3a5b867..8d0afe6693c 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + use super::{fabsf, scalbnf, sqrtf}; const BP: [f32; 2] = [1.0, 1.5]; diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 17de5a2e030..cbadb49bba0 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -1,3 +1,81 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* sqrt(x) + * Return correctly rounded sqrt. + * ------------------------------------------ + * | Use the hardware sqrt if you have one | + * ------------------------------------------ + * Method: + * Bit by bit method using integer arithmetic. (Slow, but portable) + * 1. Normalization + * Scale x to y in [1,4) with even powers of 2: + * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then + * sqrt(x) = 2^k * sqrt(y) + * 2. Bit by bit computation + * Let q = sqrt(y) truncated to i bit after binary point (q = 1), + * i 0 + * i+1 2 + * s = 2*q , and y = 2 * ( y - q ). (1) + * i i i i + * + * To compute q from q , one checks whether + * i+1 i + * + * -(i+1) 2 + * (q + 2 ) <= y. (2) + * i + * -(i+1) + * If (2) is false, then q = q ; otherwise q = q + 2 . + * i+1 i i+1 i + * + * With some algebric manipulation, it is not difficult to see + * that (2) is equivalent to + * -(i+1) + * s + 2 <= y (3) + * i i + * + * The advantage of (3) is that s and y can be computed by + * i i + * the following recurrence formula: + * if (3) is false + * + * s = s , y = y ; (4) + * i+1 i i+1 i + * + * otherwise, + * -i -(i+1) + * s = s + 2 , y = y - s - 2 (5) + * i+1 i i+1 i i + * + * One may easily use induction to prove (4) and (5). + * Note. Since the left hand side of (3) contain only i+2 bits, + * it does not necessary to do a full (53-bit) comparison + * in (3). + * 3. Final rounding + * After generating the 53 bits result, we compute one more bit. + * Together with the remainder, we can decide whether the + * result is exact, bigger than 1/2ulp, or less than 1/2ulp + * (it will never equal to 1/2ulp). + * The rounding mode can be detected by checking whether + * huge + tiny is equal to huge, and whether huge - tiny is + * equal to huge for some floating point number "huge" and "tiny". + * + * Special cases: + * sqrt(+-0) = +-0 ... exact + * sqrt(inf) = inf + * sqrt(-ve) = NaN ... with invalid signal + * sqrt(NaN) = NaN ... with invalid signal for signaling NaN + */ + use core::f64; const TINY: f64 = 1.0e-300; diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index a265bef48eb..49984689efc 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + const TINY: f32 = 1.0e-30; #[inline] -- cgit 1.4.1-3-g733a5 From d67c2c391b86738246d90ba902b96b79c021a2bd Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 09:33:46 +0300 Subject: cargo fmt --- library/compiler-builtins/libm/src/math/cosf.rs | 46 +-- library/compiler-builtins/libm/src/math/k_cosf.rs | 18 +- library/compiler-builtins/libm/src/math/k_sinf.rs | 20 +- library/compiler-builtins/libm/src/math/mod.rs | 19 +- .../libm/src/math/rem_pio2_large.rs | 393 ++++++++++----------- .../compiler-builtins/libm/src/math/rem_pio2f.rs | 32 +- 6 files changed, 249 insertions(+), 279 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index ef46d4a15f2..79df97e354a 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -3,32 +3,36 @@ use super::{k_cosf, k_sinf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; /* Small multiples of pi/2 rounded to double precision. */ -const C1_PIO2 : f64 = 1.*FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const C2_PIO2 : f64 = 2.*FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ -const C3_PIO2 : f64 = 3.*FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const C4_PIO2 : f64 = 4.*FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ +const C1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ #[inline] pub fn cosf(x: f32) -> f32 { let x64 = x as f64; - + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - + let mut ix = x.to_bits(); let sign = (ix >> 31) != 0; ix &= 0x7fffffff; - if ix <= 0x3f490fda { /* |x| ~<= pi/4 */ - if ix < 0x39800000 { /* |x| < 2**-12 */ + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ /* raise inexact if x != 0 */ force_eval!(x + x1p120); return 1.; } return k_cosf(x64); } - if ix <= 0x407b53d1 { /* |x| ~<= 5*pi/4 */ - if ix > 0x4016cbe3 { /* |x| ~> 3*pi/4 */ - return -k_cosf(if sign { x64+C2_PIO2 } else { x64-C2_PIO2 }); + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix > 0x4016cbe3 { + /* |x| ~> 3*pi/4 */ + return -k_cosf(if sign { x64 + C2_PIO2 } else { x64 - C2_PIO2 }); } else { if sign { return k_sinf(x64 + C1_PIO2); @@ -37,9 +41,11 @@ pub fn cosf(x: f32) -> f32 { } } } - if ix <= 0x40e231d5 { /* |x| ~<= 9*pi/4 */ - if ix > 0x40afeddf { /* |x| ~> 7*pi/4 */ - return k_cosf(if sign { x64+C4_PIO2 } else { x64-C4_PIO2 }); + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix > 0x40afeddf { + /* |x| ~> 7*pi/4 */ + return k_cosf(if sign { x64 + C4_PIO2 } else { x64 - C4_PIO2 }); } else { if sign { return k_sinf(-x64 - C3_PIO2); @@ -51,15 +57,15 @@ pub fn cosf(x: f32) -> f32 { /* cos(Inf or NaN) is NaN */ if ix >= 0x7f800000 { - return x-x; + return x - x; } /* general argument reduction needed */ let (n, y) = rem_pio2f(x); - match n&3 { - 0 => { k_cosf( y) }, - 1 => { k_sinf(-y) }, - 2 => { -k_cosf( y) }, - _ => { k_sinf( y) }, + match n & 3 { + 0 => k_cosf(y), + 1 => k_sinf(-y), + 2 => -k_cosf(y), + _ => k_sinf(y), } } diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs index 5d1ede7af92..83d13b2e998 100644 --- a/library/compiler-builtins/libm/src/math/k_cosf.rs +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -1,13 +1,13 @@ /* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ -const C0 : f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ -const C1 : f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ -const C2 : f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ -const C3 : f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ +const C0: f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ +const C1: f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ +const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ +const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ #[inline] -pub(crate) fn k_cosf(x : f64) -> f32 { - let z = x*x; - let w = z*z; - let r = C2+z*C3; - (((1.0+z*C0) + w*C1) + (w*z)*r) as f32 +pub(crate) fn k_cosf(x: f64) -> f32 { + let z = x * x; + let w = z * z; + let r = C2 + z * C3; + (((1.0 + z * C0) + w * C1) + (w * z) * r) as f32 } diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs index 5eedab3aa64..bb2183afc7c 100644 --- a/library/compiler-builtins/libm/src/math/k_sinf.rs +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -1,14 +1,14 @@ /* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ -const S1 : f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ -const S2 : f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ -const S3 : f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ -const S4 : f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ +const S1: f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ +const S2: f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ +const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ +const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ #[inline] -pub(crate) fn k_sinf(x : f64) -> f32 { - let z = x*x; - let w = z*z; - let r = S3 + z*S4; - let s = z*x; - ((x + s*(S1 + z*S2)) + s*w*r) as f32 +pub(crate) fn k_sinf(x: f64) -> f32 { + let z = x * x; + let w = z * z; + let r = S3 + z * S4; + let s = z * x; + ((x + s * (S1 + z * S2)) + s * w * r) as f32 } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 00945b258c8..013e70870bb 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -7,6 +7,7 @@ macro_rules! force_eval { } mod ceilf; +mod cosf; mod expf; mod fabs; mod fabsf; @@ -27,28 +28,22 @@ mod scalbn; mod scalbnf; mod sqrt; mod sqrtf; -mod cosf; mod trunc; mod truncf; pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log10::log10, log10f::log10f, log2::log2, log2f::log2f, - logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, - sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, cosf::cosf, + ceilf::ceilf, cosf::cosf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, + fmodf::fmodf, hypot::hypot, hypotf::hypotf, log10::log10, log10f::log10f, log2::log2, + log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, + scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, }; mod k_cosf; mod k_sinf; -mod rem_pio2f; mod rem_pio2_large; +mod rem_pio2f; -use self::{ - k_cosf::k_cosf, - k_sinf::k_sinf, - rem_pio2f::rem_pio2f, - rem_pio2_large::rem_pio2_large, -}; +use self::{k_cosf::k_cosf, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f}; fn isnanf(x: f32) -> bool { x.to_bits() & 0x7fffffff > 0x7f800000 diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index e1f5d133390..52b47279cd9 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -1,8 +1,8 @@ -use super::scalbn; use super::floor; +use super::scalbn; // initial value for jk -const INIT_JK : [usize; 4] = [3,4,4,6]; +const INIT_JK: [usize; 4] = [3, 4, 4, 6]; // Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi // @@ -15,140 +15,99 @@ const INIT_JK : [usize; 4] = [3,4,4,6]; // NB: This table must have at least (e0-3)/24 + jk terms. // For quad precision (e0 <= 16360, jk = 6), this is 686. #[cfg(target_pointer_width = "32")] -const IPIO2 : [i32; 66] = [ - 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, - 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, - 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, - 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, - 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, - 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, - 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, - 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, - 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, - 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, - 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, +const IPIO2: [i32; 66] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, + 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, + 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, + 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, + 0x73A8C9, 0x60E27B, 0xC08C6B, ]; #[cfg(target_pointer_width = "64")] -const IPIO2 : [i32; 690] = [ - 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, - 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, - 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, - 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, - 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, - 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, - 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, - 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, - 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, - 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, - 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, - 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, - 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, - 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, - 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, - 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, - 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, - 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, - 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, - 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, - 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, - 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, - 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, - 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, - 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, - 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, - 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, - 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, - 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, - 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, - 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, - 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, - 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, - 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, - 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, - 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, - 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, - 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, - 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, - 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, - 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, - 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, - 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, - 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, - 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, - 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, - 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, - 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, - 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, - 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, - 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, - 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, - 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, - 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, - 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, - 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, - 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, - 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, - 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, - 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, - 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, - 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, - 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, - 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, - 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, - 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, - 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, - 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, - 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, - 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, - 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, - 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, - 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, - 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, - 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, - 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, - 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, - 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, - 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, - 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, - 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, - 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, - 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, - 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, - 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, - 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, - 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, - 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, - 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, - 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, - 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, - 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, - 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, - 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, - 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, - 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, - 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, - 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, - 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, - 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, - 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, - 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, - 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, - 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, - 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, - 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, - 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, - 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, - 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, - 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, - 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, - 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, - 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, - 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, +const IPIO2: [i32; 690] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, + 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, + 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, + 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, + 0x73A8C9, 0x60E27B, 0xC08C6B, 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, + 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, 0xDE4F98, 0x327DBB, 0xC33D26, + 0xEF6B1E, 0x5EF89F, 0x3A1F35, 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, + 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, 0x467D86, 0x2D71E3, 0x9AC69B, + 0x006233, 0x7CD2B4, 0x97A7B4, 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, + 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, 0xCB2324, 0x778AD6, 0x23545A, + 0xB91F00, 0x1B0AF1, 0xDFCE19, 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, + 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, 0xDE3B58, 0x929BDE, 0x2822D2, + 0xE88628, 0x4D58E2, 0x32CAC6, 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, + 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, 0xD36710, 0xD8DDAA, 0x425FAE, + 0xCE616A, 0xA4280A, 0xB499D3, 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, + 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, 0x36D9CA, 0xD2A828, 0x8D61C2, + 0x77C912, 0x142604, 0x9B4612, 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, + 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, 0xC3E7B3, 0x28F8C7, 0x940593, + 0x3E71C1, 0xB3092E, 0xF3450B, 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, + 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, 0x9794E8, 0x84E6E2, 0x973199, + 0x6BED88, 0x365F5F, 0x0EFDBB, 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, + 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, 0x90AA47, 0x02E774, 0x24D6BD, + 0xA67DF7, 0x72486E, 0xEF169F, 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, + 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, 0x10D86D, 0x324832, 0x754C5B, + 0xD4714E, 0x6E5445, 0xC1090B, 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, + 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, 0x6AE290, 0x89D988, 0x50722C, + 0xBEA404, 0x940777, 0x7030F3, 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, + 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, 0x3BDF08, 0x2B3715, 0xA0805C, + 0x93805A, 0x921110, 0xD8E80F, 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, + 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, 0xAA140A, 0x2F2689, 0x768364, + 0x333B09, 0x1A940E, 0xAA3A51, 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, + 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, 0x5BC3D8, 0xC492F5, 0x4BADC6, + 0xA5CA4E, 0xCD37A7, 0x36A9E6, 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, + 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, 0x306529, 0xBF5657, 0x3AFF47, + 0xB9F96A, 0xF3BE75, 0xDF9328, 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, + 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, 0xA8654F, 0xA5C1D2, 0x0F3F0B, + 0xCD785B, 0x76F923, 0x048B7B, 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, + 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, 0xDA4886, 0xA05DF7, 0xF480C6, + 0x2FF0AC, 0x9AECDD, 0xBC5C3F, 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, + 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, 0x2A1216, 0x2DB7DC, 0xFDE5FA, + 0xFEDB89, 0xFDBE89, 0x6C76E4, 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, + 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, 0x48D784, 0x16DF30, 0x432DC7, + 0x356125, 0xCE70C9, 0xB8CB30, 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, + 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, 0xC4F133, 0x5F6E13, 0xE4305D, + 0xA92E85, 0xC3B21D, 0x3632A1, 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, + 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, 0xCBDA11, 0xD0BE7D, 0xC1DB9B, + 0xBD17AB, 0x81A2CA, 0x5C6A08, 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, + 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, 0x4F6A68, 0xA82A4A, 0x5AC44F, + 0xBCF82D, 0x985AD7, 0x95C7F4, 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, + 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, 0xD0C0B2, 0x485551, 0x0EFB1E, + 0xC37295, 0x3B06A3, 0x3540C0, 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, + 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, 0x3C3ABA, 0x461846, 0x5F7555, + 0xF5BDD2, 0xC6926E, 0x5D2EAC, 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, + 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, 0x745D7C, 0xB2AD6B, 0x9D6ECD, + 0x7B723E, 0x6A11C6, 0xA9CFF7, 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, + 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, 0xBEFDFD, 0xEF4556, 0x367ED9, + 0x13D9EC, 0xB9BA8B, 0xFC97C4, 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, + 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, 0x9C2A3E, 0xCC5F11, 0x4A0BFD, + 0xFBF4E1, 0x6D3B8E, 0x2C86E2, 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, + 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, 0xCC2254, 0xDC552A, 0xD6C6C0, + 0x96190B, 0xB8701A, 0x649569, 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, + 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, 0x9B5861, 0xBC57E1, 0xC68351, + 0x103ED8, 0x4871DD, 0xDD1C2D, 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, + 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, 0x382682, 0x9BE7CA, 0xA40D51, + 0xB13399, 0x0ED7A9, 0x480569, 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, + 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, 0x5FD45E, 0xA4677B, 0x7AACBA, + 0xA2F655, 0x23882B, 0x55BA41, 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, + 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, 0xAE5ADB, 0x86C547, 0x624385, + 0x3B8621, 0x94792C, 0x876110, 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, + 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, 0xB1933D, 0x0B7CBD, 0xDC51A4, + 0x63DD27, 0xDDE169, 0x19949A, 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, + 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, 0x4D7E6F, 0x5119A5, 0xABF9B5, + 0xD6DF82, 0x61DD96, 0x023616, 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, ]; -const PIO2 : [f64; 8] = [ +const PIO2: [f64; 8] = [ 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ @@ -251,92 +210,91 @@ const PIO2 : [f64; 8] = [ /// more accurately, = 0 mod 8 ). Thus the number of operations are /// independent of the exponent of the input. #[inline] -pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 { - let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 +pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { + let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) - + #[cfg(target_pointer_width = "64")] assert!(e0 <= 16360); - + let nx = x.len(); - - let mut fw : f64; - let mut n : i32; - let mut ih : i32; - let mut z : f64; - let mut f : [f64;20] = [0.;20]; - let mut fq : [f64;20] = [0.;20]; - let mut q : [f64;20] = [0.;20]; - let mut iq : [i32;20] = [0;20]; - + + let mut fw: f64; + let mut n: i32; + let mut ih: i32; + let mut z: f64; + let mut f: [f64; 20] = [0.; 20]; + let mut fq: [f64; 20] = [0.; 20]; + let mut q: [f64; 20] = [0.; 20]; + let mut iq: [i32; 20] = [0; 20]; + /* initialize jk*/ let jk = INIT_JK[prec]; let jp = jk; /* determine jx,jv,q0, note that 3>q0 */ - let jx = nx-1; - let mut jv = (e0-3)/24; + let jx = nx - 1; + let mut jv = (e0 - 3) / 24; if jv < 0 { - jv=0; + jv = 0; } - let mut q0 = e0-24*(jv+1); + let mut q0 = e0 - 24 * (jv + 1); let jv = jv as usize; /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ - let mut j = (jv-jx) as i32; - let m = jx+jk; + let mut j = (jv - jx) as i32; + let m = jx + jk; for i in 0..=m { - f[i] = if j<0 { - 0. - } else { - IPIO2[j as usize] as f64 - }; + f[i] = if j < 0 { 0. } else { IPIO2[j as usize] as f64 }; j += 1 } - + /* compute q[0],q[1],...q[jk] */ for i in 0..=jk { fw = 0f64; for j in 0..=jx { - fw += x[j]*f[jx+i-j]; + fw += x[j] * f[jx + i - j]; } q[i] = fw; } - + let mut jz = jk; - + 'recompute: loop { /* distill q[] into iq[] reversingly */ let mut i = 0i32; z = q[jz]; for j in (1..=jz).rev() { - fw = (x1p_24*z) as i32 as f64; - iq[i as usize] = (z - x1p24*fw) as i32; - z = q[j-1]+fw; + fw = (x1p_24 * z) as i32 as f64; + iq[i as usize] = (z - x1p24 * fw) as i32; + z = q[j - 1] + fw; i += 1; } - + /* compute n */ - z = scalbn(z, q0); /* actual value of z */ - z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ - n = z as i32; + z = scalbn(z, q0); /* actual value of z */ + z -= 8.0 * floor(z * 0.125); /* trim off integer >= 8 */ + n = z as i32; z -= n as f64; ih = 0; - if q0 > 0 { /* need iq[jz-1] to determine n */ - i = iq[jz-1] >> (24-q0); + if q0 > 0 { + /* need iq[jz-1] to determine n */ + i = iq[jz - 1] >> (24 - q0); n += i; - iq[jz-1] -= i << (24-q0); - ih = iq[jz-1] >> (23-q0); + iq[jz - 1] -= i << (24 - q0); + ih = iq[jz - 1] >> (23 - q0); } else if q0 == 0 { - ih = iq[jz-1]>>23; + ih = iq[jz - 1] >> 23; } else if z >= 0.5 { ih = 2; } - - if ih > 0 { /* q > 0.5 */ + + if ih > 0 { + /* q > 0.5 */ n += 1; let mut carry = 0i32; - for i in 0..jz { /* compute 1-q */ + for i in 0..jz { + /* compute 1-q */ let j = iq[i]; if carry == 0 { if j != 0 { @@ -347,10 +305,15 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) iq[i] = 0xffffff - j; } } - if q0 > 0 { /* rare case: chance is 1 in 12 */ + if q0 > 0 { + /* rare case: chance is 1 in 12 */ match q0 { - 1 => { iq[jz-1] &= 0x7fffff; }, - 2 => { iq[jz-1] &= 0x3fffff; }, + 1 => { + iq[jz - 1] &= 0x7fffff; + } + 2 => { + iq[jz - 1] &= 0x3fffff; + } _ => {} } } @@ -361,24 +324,26 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) } } } - + /* check if recomputation is needed */ if z == 0. { let mut j = 0; - for i in (jk..=jz-1).rev() { + for i in (jk..=jz - 1).rev() { j |= iq[i]; } - if j == 0 { /* need recomputation */ + if j == 0 { + /* need recomputation */ let mut k = 1; - while iq[jk-k]==0 { - k += 1; /* k = no. of terms needed */ + while iq[jk - k] == 0 { + k += 1; /* k = no. of terms needed */ } - - for i in (jz+1)..=(jz+k) { /* add q[jz+1] to q[jz+k] */ - f[jx+i] = IPIO2[jv+i] as f64; + + for i in (jz + 1)..=(jz + k) { + /* add q[jz+1] to q[jz+k] */ + f[jx + i] = IPIO2[jv + i] as f64; fw = 0f64; for j in 0..=jx { - fw += x[j]*f[jx+i-j]; + fw += x[j] * f[jx + i - j]; } q[i] = fw; } @@ -389,7 +354,7 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) break; } - + /* chop off zero terms */ if z == 0. { jz -= 1; @@ -398,11 +363,12 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) jz -= 1; q0 -= 24; } - } else { /* break z into 24-bit if necessary */ + } else { + /* break z into 24-bit if necessary */ z = scalbn(z, -q0); if z >= x1p24 { - fw = (x1p_24*z) as i32 as f64; - iq[jz] = (z - x1p24*fw) as i32; + fw = (x1p_24 * z) as i32 as f64; + iq[jz] = (z - x1p24 * fw) as i32; jz += 1; q0 += 24; iq[jz] = fw as i32; @@ -410,25 +376,25 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) iq[jz] = z as i32; } } - + /* convert integer "bit" chunk to floating-point value */ fw = scalbn(1., q0); for i in (0..=jz).rev() { - q[i] = fw*(iq[i] as f64); + q[i] = fw * (iq[i] as f64); fw *= x1p_24; } - + /* compute PIo2[0,...,jp]*q[jz,...,0] */ for i in (0..=jz).rev() { fw = 0f64; let mut k = 0; - while (k <= jp) && (k <= jz-i) { - fw += PIO2[k]*q[i+k]; + while (k <= jp) && (k <= jz - i) { + fw += PIO2[k] * q[i + k]; k += 1; } - fq[jz-i] = fw; + fq[jz - i] = fw; } - + /* compress fq[] into y[] */ match prec { 0 => { @@ -437,7 +403,7 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) fw += fq[i]; } y[0] = if ih == 0 { fw } else { -fw }; - }, + } 1 | 2 => { fw = 0f64; for i in (0..=jz).rev() { @@ -446,38 +412,39 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) // TODO: drop excess precision here once double_t is used fw = fw as f64; y[0] = if ih == 0 { fw } else { -fw }; - fw = fq[0]-fw; + fw = fq[0] - fw; for i in 1..=jz { fw += fq[i]; } y[1] = if ih == 0 { fw } else { -fw }; - }, - 3 => { /* painful */ + } + 3 => { + /* painful */ for i in (1..=jz).rev() { - fw = fq[i-1]+fq[i]; - fq[i] += fq[i-1]-fw; - fq[i-1] = fw; + fw = fq[i - 1] + fq[i]; + fq[i] += fq[i - 1] - fw; + fq[i - 1] = fw; } for i in (2..=jz).rev() { - fw = fq[i-1]+fq[i]; - fq[i] += fq[i-1]-fw; - fq[i-1] = fw; + fw = fq[i - 1] + fq[i]; + fq[i] += fq[i - 1] - fw; + fq[i - 1] = fw; } fw = 0f64; for i in (2..=jz).rev() { fw += fq[i]; } - if ih==0 { - y[0] = fq[0]; - y[1] = fq[1]; - y[2] = fw; + if ih == 0 { + y[0] = fq[0]; + y[1] = fq[1]; + y[2] = fw; } else { y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; } - }, - _ => { unreachable!() } + } + _ => unreachable!(), } n & 7 } diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index a908ccd9f75..73ec3775d3d 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -2,40 +2,42 @@ use super::rem_pio2_large; use core::f64; -const TOINT : f64 = 1.5 / f64::EPSILON; +const TOINT: f64 = 1.5 / f64::EPSILON; /// 53 bits of 2/pi -const INV_PIO2 : f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ /// first 25 bits of pi/2 -const PIO2_1 : f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ +const PIO2_1: f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ /// pi/2 - pio2_1 -const PIO2_1T : f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ +const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ /// Return the remainder of x rem pi/2 in *y /// /// use double precision for everything except passing x /// use __rem_pio2_large() for large x #[inline] -pub(crate) fn rem_pio2f(x : f32) -> (i32, f64) { +pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { let x64 = x as f64; - - let mut tx : [f64; 1] = [0.,]; - let mut ty : [f64; 1] = [0.,]; + + let mut tx: [f64; 1] = [0.]; + let mut ty: [f64; 1] = [0.]; let ix = x.to_bits() & 0x7fffffff; /* 25+53 bit pi is good enough for medium size */ - if ix < 0x4dc90fdb { /* |x| ~< 2^28*(pi/2), medium size */ + if ix < 0x4dc90fdb { + /* |x| ~< 2^28*(pi/2), medium size */ /* Use a specialized rint() to get fn. Assume round-to-nearest. */ - let f_n = x64*INV_PIO2 + TOINT - TOINT; - return (f_n as i32, x64 - f_n*PIO2_1 - f_n*PIO2_1T); + let f_n = x64 * INV_PIO2 + TOINT - TOINT; + return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); } - if ix>=0x7f800000 { /* x is inf or NaN */ - return (0, x64-x64); + if ix >= 0x7f800000 { + /* x is inf or NaN */ + return (0, x64 - x64); } /* scale x into [2^23, 2^24-1] */ let sign = (x.to_bits() >> 31) != 0; - let e0 = ((ix>>23) - (0x7f+23)) as i32; /* e0 = ilogb(|x|)-23, positive */ - tx[0] = f32::from_bits(ix - (e0<<23) as u32) as f64; + let e0 = ((ix >> 23) - (0x7f + 23)) as i32; /* e0 = ilogb(|x|)-23, positive */ + tx[0] = f32::from_bits(ix - (e0 << 23) as u32) as f64; let n = rem_pio2_large(&tx, &mut ty, e0, 0); if sign { return (-n, -ty[0]); -- cgit 1.4.1-3-g733a5 From 137d99d55b781f49680de8993f1498bbb7cd5f1f Mon Sep 17 00:00:00 2001 From: Opal Date: Sat, 14 Jul 2018 18:28:11 +1200 Subject: Adding acos implementation --- library/compiler-builtins/libm/src/lib.rs | 2 - library/compiler-builtins/libm/src/math/acos.rs | 108 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 10 +- .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/acos.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 30f879769d0..9b3a6457f4a 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -412,7 +412,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn asin(self) -> Self; - #[cfg(todo)] fn acos(self) -> Self; #[cfg(todo)] @@ -589,7 +588,6 @@ impl F64Ext for f64 { asin(self) } - #[cfg(todo)] #[inline] fn acos(self) -> Self { acos(self) diff --git a/library/compiler-builtins/libm/src/math/acos.rs b/library/compiler-builtins/libm/src/math/acos.rs new file mode 100644 index 00000000000..276e361f3d5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/acos.rs @@ -0,0 +1,108 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* acos(x) + * Method : + * acos(x) = pi/2 - asin(x) + * acos(-x) = pi/2 + asin(x) + * For |x|<=0.5 + * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) + * For x>0.5 + * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) + * = 2asin(sqrt((1-x)/2)) + * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) + * = 2f + (2c + 2s*z*R(z)) + * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term + * for f so that f+c ~ sqrt(z). + * For x<-0.5 + * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) + * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + * Function needed: sqrt + */ + +use super::sqrt; + +const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ +const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ +const PS0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ +const PS1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ +const PS2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ +const PS3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ +const PS4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ +const PS5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ +const QS1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ +const QS2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ +const QS3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ +const QS4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +#[inline] +fn r(z: f64) -> f64 { + let p: f64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); + let q: f64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); + return p / q; +} + +#[inline] +pub fn acos(x: f64) -> f64 { + let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120 + let z: f64; + let w: f64; + let s: f64; + let c: f64; + let df: f64; + let hx: u32; + let ix: u32; + + hx = (x.to_bits() >> 32) as u32; + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3ff00000 { + let lx: u32 = x.to_bits() as u32; + + if (ix - 0x3ff00000 | lx) == 0 { + /* acos(1)=0, acos(-1)=pi */ + if (hx >> 31) != 0 { + return 2. * PIO2_HI + x1p_120f; + } + return 0.; + } + return 0. / (x - x); + } + /* |x| < 0.5 */ + if ix < 0x3fe00000 { + if ix <= 0x3c600000 { + /* |x| < 2**-57 */ + return PIO2_HI + x1p_120f; + } + return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); + } + /* x < -0.5 */ + if (hx >> 31) != 0 { + z = (1.0 + x) * 0.5; + s = sqrt(z); + w = r(z) * s - PIO2_LO; + return 2. * (PIO2_HI - (s + w)); + } + /* x > 0.5 */ + z = (1.0 - x) * 0.5; + s = sqrt(z); + // Set the low 4 bytes to zero + df = f64::from_bits(s.to_bits() & 0xff_ff_ff_ff_00_00_00_00); + + c = (z - df * df) / (s + df); + w = r(z) * s + c; + return 2. * (df + w); +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index fb5e3df9090..f70555e9cc2 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -6,6 +6,7 @@ macro_rules! force_eval { }; } +mod acos; mod ceilf; mod expf; mod fabs; @@ -36,10 +37,11 @@ mod truncf; //mod service; pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log1p::log1p, - log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, - scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, + acos::acos, ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, + fmodf::fmodf, hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, + log1p::log1p, log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, + roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, + truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index be5ed0784f8..d48851a9e63 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -696,7 +696,7 @@ f32i32_f32! { // With signature `fn(f64) -> f64` f64_f64! { - // acos, + acos, // asin, // atan, // cbrt, -- cgit 1.4.1-3-g733a5 From a7c456363394954ef27cd3db80e476e7349518c0 Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 05:48:39 -0400 Subject: Use separate imports instead of {}-grouped imports for better merges Previously every merge would cause conflicts because the {}-group would re-flow, which the merge algorithm can't handle. This will hopefully make rebases and merges go more smoothly while everyone is still adding new modules. --- library/compiler-builtins/libm/src/math/mod.rs | 33 +++++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index fb5e3df9090..78f8991413b 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -35,12 +35,33 @@ mod truncf; //mod service; -pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log1p::log1p, - log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, - scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, -}; +// Use separated imports instead of {}-grouped imports for easier merging. +pub use self::ceilf::ceilf; +pub use self::expf::expf; +pub use self::fabs::fabs; +pub use self::fabsf::fabsf; +pub use self::floor::floor; +pub use self::floorf::floorf; +pub use self::fmodf::fmodf; +pub use self::hypot::hypot; +pub use self::hypotf::hypotf; +pub use self::log::log; +pub use self::log10::log10; +pub use self::log10f::log10f; +pub use self::log1p::log1p; +pub use self::log1pf::log1pf; +pub use self::log2::log2; +pub use self::log2f::log2f; +pub use self::logf::logf; +pub use self::powf::powf; +pub use self::round::round; +pub use self::roundf::roundf; +pub use self::scalbn::scalbn; +pub use self::scalbnf::scalbnf; +pub use self::sqrt::sqrt; +pub use self::sqrtf::sqrtf; +pub use self::trunc::trunc; +pub use self::truncf::truncf; fn isnanf(x: f32) -> bool { x.to_bits() & 0x7fffffff > 0x7f800000 -- cgit 1.4.1-3-g733a5 From 480531461c0ea0eb04cb66d83696323a25d0925a Mon Sep 17 00:00:00 2001 From: Jack Mott Date: Sat, 14 Jul 2018 05:35:07 -0500 Subject: fdimf --- library/compiler-builtins/libm/src/lib.rs | 7 +++++++ library/compiler-builtins/libm/src/math/fdimf.rs | 15 +++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 10 ++++++---- library/compiler-builtins/libm/test-generator/src/main.rs | 2 +- 4 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fdimf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 30f879769d0..7d8ae903a12 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -42,6 +42,8 @@ pub trait F32Ext: private::Sealed { fn trunc(self) -> Self; + fn fdim(self, rhs: Self) -> Self; + #[cfg(todo)] fn fract(self) -> Self; @@ -156,6 +158,11 @@ impl F32Ext for f32 { truncf(self) } + #[inline] + fn fdim(self, rhs: Self) -> Self { + fdimf(self, rhs) + } + #[cfg(todo)] #[inline] fn fract(self) -> Self { diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs new file mode 100644 index 00000000000..3cf65d9beee --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -0,0 +1,15 @@ +use super::isnanf; + +pub fn fdimf(x: f32, y: f32) -> f32 { + if isnanf(x) { + x + } else if isnanf(y) { + y + } else { + if x > y { + x - y + } else { + 0.0 + } + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index fb5e3df9090..a9ba87aa2ce 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -10,6 +10,7 @@ mod ceilf; mod expf; mod fabs; mod fabsf; +mod fdimf; mod floor; mod floorf; mod fmodf; @@ -36,10 +37,11 @@ mod truncf; //mod service; pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log1p::log1p, - log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, - scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, + ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, fdimf::fdimf, floor::floor, floorf::floorf, + fmodf::fmodf, hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, + log1p::log1p, log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, + roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, + truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index be5ed0784f8..29529356247 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -662,7 +662,6 @@ f32_f32! { // coshf, // exp2f, expf, - // fdimf, log10f, log1pf, log2f, @@ -679,6 +678,7 @@ f32_f32! { // With signature `fn(f32, f32) -> f32` f32f32_f32! { // atan2f, + fdimf, hypotf, fmodf, powf, -- cgit 1.4.1-3-g733a5 From 643287e1f15268cfa481e0cbd56e57b3f6772117 Mon Sep 17 00:00:00 2001 From: Jack Mott Date: Sat, 14 Jul 2018 06:20:13 -0500 Subject: fdim --- library/compiler-builtins/libm/src/lib.rs | 6 ++++++ library/compiler-builtins/libm/src/math/fdim.rs | 15 +++++++++++++++ library/compiler-builtins/libm/src/math/fdimf.rs | 6 +++--- library/compiler-builtins/libm/src/math/fmodf.rs | 5 ++--- library/compiler-builtins/libm/src/math/mod.rs | 15 ++++++--------- library/compiler-builtins/libm/test-generator/src/main.rs | 2 +- 6 files changed, 33 insertions(+), 16 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fdim.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 7d8ae903a12..df96aadc725 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -363,6 +363,8 @@ pub trait F64Ext: private::Sealed { fn trunc(self) -> Self; + fn fdim(self, rhs: Self) -> Self; + #[cfg(todo)] fn fract(self) -> Self; @@ -480,6 +482,10 @@ impl F64Ext for f64 { trunc(self) } + #[inline] + fn fdim(self, rhs: Self) -> Self { + fdim(self, rhs) + } #[cfg(todo)] #[inline] fn fract(self) -> Self { diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs new file mode 100644 index 00000000000..2b277eab03e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -0,0 +1,15 @@ +use core::f64; + +pub fn fdim(x: f64, y: f64) -> f64 { + if x.is_nan() { + x + } else if y.is_nan() { + y + } else { + if x > y { + x - y + } else { + 0.0 + } + } +} diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index 3cf65d9beee..44bf2d6806e 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -1,9 +1,9 @@ -use super::isnanf; +use core::f32; pub fn fdimf(x: f32, y: f32) -> f32 { - if isnanf(x) { + if x.is_nan() { x - } else if isnanf(y) { + } else if y.is_nan() { y } else { if x > y { diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index 90977524908..d84cfeb01b8 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -1,7 +1,6 @@ +use core::f32; use core::u32; -use super::isnanf; - #[inline] pub fn fmodf(x: f32, y: f32) -> f32 { let mut uxi = x.to_bits(); @@ -11,7 +10,7 @@ pub fn fmodf(x: f32, y: f32) -> f32 { let sx = uxi & 0x80000000; let mut i; - if uyi << 1 == 0 || isnanf(y) || ex == 0xff { + if uyi << 1 == 0 || y.is_nan() || ex == 0xff { return (x * y) / (x * y); } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index a9ba87aa2ce..e526314a667 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -10,6 +10,7 @@ mod ceilf; mod expf; mod fabs; mod fabsf; +mod fdim; mod fdimf; mod floor; mod floorf; @@ -37,13 +38,9 @@ mod truncf; //mod service; pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, fdimf::fdimf, floor::floor, floorf::floorf, - fmodf::fmodf, hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, - log1p::log1p, log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, - roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, - truncf::truncf, + ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, fdim::fdim, fdimf::fdimf, floor::floor, + floorf::floorf, fmodf::fmodf, hypot::hypot, hypotf::hypotf, log::log, log10::log10, + log10f::log10f, log1p::log1p, log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, + round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, + trunc::trunc, truncf::truncf, }; - -fn isnanf(x: f32) -> bool { - x.to_bits() & 0x7fffffff > 0x7f800000 -} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 29529356247..bf679ca6419 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -724,7 +724,7 @@ f64_f64! { // With signature `fn(f64, f64) -> f64` f64f64_f64! { // atan2, - // fdim, + fdim, // fmod, hypot, // pow, -- cgit 1.4.1-3-g733a5 From 5c2409fcca9e91f862b7f061e253e72270d8505c Mon Sep 17 00:00:00 2001 From: Lucas Marques Date: Sat, 14 Jul 2018 00:23:58 -0300 Subject: implement ceil --- library/compiler-builtins/libm/src/lib.rs | 2 -- library/compiler-builtins/libm/src/math/ceil.rs | 39 +++++++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 10 ++++--- 3 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/ceil.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 30f879769d0..5af219fccf9 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -349,7 +349,6 @@ impl F32Ext for f32 { pub trait F64Ext: private::Sealed { fn floor(self) -> Self; - #[cfg(todo)] fn ceil(self) -> Self; fn round(self) -> Self; @@ -457,7 +456,6 @@ impl F64Ext for f64 { floor(self) } - #[cfg(todo)] #[inline] fn ceil(self) -> Self { ceil(self) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs new file mode 100644 index 00000000000..4db2ca84036 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -0,0 +1,39 @@ +use core::f64; + +const TOINT: f64 = 1. / f64::EPSILON; + +#[inline] +pub fn ceil(x: f64) -> f64 { + let u: u64 = x.to_bits(); + let e: i64 = (u >> 52 & 0x7ff) as i64; + let y: f64; + + if e >= 0x3ff + 52 || x == 0. { + return x; + } + // y = int(x) - x, where int(x) is an integer neighbor of x + y = if (u >> 63) != 0 { + x - TOINT + TOINT - x + } else { + x + TOINT - TOINT - x + }; + // special case because of non-nearest rounding modes + if e <= 0x3ff - 1 { + force_eval!(y); + return if (u >> 63) != 0 { -0. } else { 1. }; + } + if y < 0. { + x + y + 1. + } else { + x + y + } +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::ceil(1.1), 2.0); + assert_eq!(super::ceil(2.9), 3.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index fb5e3df9090..7c676095dc9 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -6,6 +6,7 @@ macro_rules! force_eval { }; } +mod ceil; mod ceilf; mod expf; mod fabs; @@ -36,10 +37,11 @@ mod truncf; //mod service; pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log1p::log1p, - log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, - scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, + ceil::ceil, ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, + fmodf::fmodf, hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, + log1p::log1p, log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, + roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, + truncf::truncf, }; fn isnanf(x: f32) -> bool { -- cgit 1.4.1-3-g733a5 From 42e52da01052183a7c8f09e13e7d209bdd7e09c9 Mon Sep 17 00:00:00 2001 From: Lucas Marques Date: Sat, 14 Jul 2018 00:41:03 -0300 Subject: enable test generation for ceil --- library/compiler-builtins/libm/test-generator/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index be5ed0784f8..d386da9f650 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -700,7 +700,7 @@ f64_f64! { // asin, // atan, // cbrt, - // ceil, + ceil, // cos, // cosh, // exp, -- cgit 1.4.1-3-g733a5 From 3a15b30d164cbc5d85d3b4f90c69cae06d2ebdc2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jul 2018 18:31:28 +0200 Subject: Implement cosh, exp and expm1 --- library/compiler-builtins/libm/src/math/cosh.rs | 54 +++++++++ library/compiler-builtins/libm/src/math/exp.rs | 84 ++++++++++++++ library/compiler-builtins/libm/src/math/expm1.rs | 124 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 12 +- .../libm/test-generator/src/main.rs | 6 +- 5 files changed, 273 insertions(+), 7 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/cosh.rs create mode 100644 library/compiler-builtins/libm/src/math/exp.rs create mode 100644 library/compiler-builtins/libm/src/math/expm1.rs diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs new file mode 100644 index 00000000000..ce541ce1489 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -0,0 +1,54 @@ +use core::f64; + +use super::exp; +use super::expm1; + +pub fn cosh(mut x: f64) -> f64 { + let t: f64; + /* |x| */ + let mut ui = x.to_bits(); + ui &= !0u64; + x = f64::from_bits(ui); + let w = (ui >> 32) as u32; + + /* |x| < log(2) */ + if w < 0x3fe62e42 { + if w < 0x3ff00000 - (26 << 20) { + /* raise inexact if x!=0 */ + force_eval!(x + f64::from_bits(0x4770000000000000)); + return 1.0; + } + let t = expm1(x); + return 1.0 + t * t / (2.0 * (1.0 + t)); + } + + /* |x| < log(DBL_MAX) */ + if w < 0x40862e42 { + t = exp(x); + /* note: if x>log(0x1p26) then the 1/t is not needed */ + return 0.5 * (t + 1.0 / t); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = __expo2(x); + return t; +} + +const K: u32 = 2043; + +pub fn __expo2(x: f64) -> f64 { + let kln2 = f64::from_bits(0x40962066151add8b); + /* note that k is odd and scale*scale overflows */ + let scale = f64::from_bits(((0x3ff + K / 2) << 20) as u64); + /* exp(x - k ln2) * 2**(k-1) */ + return exp(x - kln2) * scale * scale; +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::cosh(1.1), 1.6685185538222564); + } +} diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs new file mode 100644 index 00000000000..870bf60853f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -0,0 +1,84 @@ +use super::scalbn; + +const HALF: [f64; 2] = [0.5, -0.5]; +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ +const INV_LN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ +const P1: f64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */ +const P2: f64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ +const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ +const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ +const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +#[inline] +pub fn exp(mut x: f64) -> f64 { + let mut hx: u32 = (x.to_bits() >> 32) as u32; + let sign = (hx >> 31) as i32; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if hx >= 0x4086232b { + /* if |x| >= 708.39... */ + if x.is_nan() { + return x; + } + if x > 709.782712893383973096 { + /* overflow if x!=inf */ + x *= f64::from_bits(0x7fe0000000000000); + return x; + } + if x < -708.39641853226410622 { + /* underflow if x!=-inf */ + force_eval!((f64::from_bits(0xb6a0000000000000) / x) as f32); + if x < -745.13321910194110842 { + return 0.0; + } + } + } + + /* argument reduction */ + let k: i32; + let hi: f64; + let lo: f64; + if hx > 0x3fd62e42 { + /* if |x| > 0.5 ln2 */ + /* if |x| > 0.5 ln2 */ + if hx > 0x3ff0a2b2 { + /* if |x| > 1.5 ln2 */ + k = (INV_LN2 * x + HALF[sign as usize]) as i32; + } else { + k = 1 - sign - sign; + } + let kf = k as f64; + hi = x - kf * LN2_HI; /* k*ln2hi is exact here */ + lo = kf * LN2_LO; + x = hi - lo; + } else if hx > 0x3e300000 { + /* |x| > 2**-14 */ + k = 0; + hi = x; + lo = 0.0; + } else { + /* raise inexact */ + force_eval!(f64::from_bits(0x7fe0000000000000) + x); + return 1.0 + x; + } + + /* x is now in primary range */ + let xx = x * x; + let c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); + let y = 1.0 + (x * c / (2.0 - c) - lo + hi); + if k == 0 { + y + } else { + scalbn(y, k) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::exp(1.1), 3.0041660239464334); + } +} diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs new file mode 100644 index 00000000000..2fc230b05f9 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -0,0 +1,124 @@ +use core::f64; + +const O_THRESHOLD: f64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ +const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ +/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ +const Q1: f64 = -3.33333333333331316428e-02; /* BFA11111 111110F4 */ +const Q2: f64 = 1.58730158725481460165e-03; /* 3F5A01A0 19FE5585 */ +const Q3: f64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ +const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ +const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ + +pub fn expm1(mut x: f64) -> f64 { + let hi: f64; + let lo: f64; + let k: i32; + let c: f64; + let mut t: f64; + let mut y: f64; + + let mut ui = x.to_bits() >> 32; + let hx = ui & 0x7fffffff; + let sign = (ui >> 63) as i32; + + /* filter out huge and non-finite argument */ + if hx >= 0x4043687A { + /* if |x|>=56*ln2 */ + if x.is_nan() { + return x; + } + if sign != 0 { + return -1.0; + } + if x > O_THRESHOLD { + x *= f64::from_bits(0x7fe0000000000000); + return x; + } + } + + /* argument reduction */ + if hx > 0x3fd62e42 { + /* if |x| > 0.5 ln2 */ + if hx < 0x3FF0A2B2 { + /* and |x| < 1.5 ln2 */ + if sign == 0 { + hi = x - LN2_HI; + lo = LN2_LO; + k = 1; + } else { + hi = x + LN2_HI; + lo = -LN2_LO; + k = -1; + } + } else { + k = (INVLN2 * x + if sign != 0 { -0.5 } else { 0.5 }) as i32; + t = k as f64; + hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ + lo = t * LN2_LO; + } + x = hi - lo; + c = (hi - x) - lo; + } else if hx < 0x3c900000 { + /* |x| < 2**-54, return x */ + if hx < 0x00100000 { + force_eval!(x as f32); + } + return x; + } else { + c = 0.0; + k = 0; + } + + /* x is now in primary range */ + let hfx = 0.5 * x; + let hxs = x * hfx; + let r1 = 1.0 + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5)))); + t = 3.0 - r1 * hfx; + let mut e = hxs * ((r1 - t) / (6.0 - x * t)); + if k == 0 { + /* c is 0 */ + return x - (x * e - hxs); + } + e = x * (e - c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if k == -1 { + return 0.5 * (x - e) - 0.5; + } + if k == 1 { + if x < -0.25 { + return -2.0 * (e - (x + 0.5)); + } + return 1.0 + 2.0 * (x - e); + } + ui = ((0x3ff + k) as u64) << 52; /* 2^k */ + let twopk = f64::from_bits(ui); + if k < 0 || k > 56 { + /* suffice to return exp(x)-1 */ + y = x - e + 1.0; + if k == 1024 { + y = y * 2.0 * f64::from_bits(0x7fe0000000000000); + } else { + y = y * twopk; + } + return y - 1.0; + } + ui = ((0x3ff - k) as u64) << 52; /* 2^-k */ + let uf = f64::from_bits(ui); + if k < 20 { + y = (x - e + (1.0 - uf)) * twopk; + } else { + y = (x - (e + uf) + 1.0) * twopk; + } + y +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::expm1(1.1), 2.0041660239464334); + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index fb5e3df9090..b4f12b67df8 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -7,7 +7,10 @@ macro_rules! force_eval { } mod ceilf; +mod cosh; +mod exp; mod expf; +mod expm1; mod fabs; mod fabsf; mod floor; @@ -36,10 +39,11 @@ mod truncf; //mod service; pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log1p::log1p, - log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, - scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, + ceilf::ceilf, cosh::cosh, exp::exp, expf::expf, expm1::expm1, fabs::fabs, fabsf::fabsf, + floor::floor, floorf::floorf, fmodf::fmodf, hypot::hypot, hypotf::hypotf, log::log, + log10::log10, log10f::log10f, log1p::log1p, log1pf::log1pf, log2::log2, log2f::log2f, + logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, + sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index be5ed0784f8..b4f11dc1c8b 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -702,10 +702,10 @@ f64_f64! { // cbrt, // ceil, // cos, - // cosh, - // exp, + cosh, + exp, // exp2, - // expm1, + expm1, floor, log, log10, -- cgit 1.4.1-3-g733a5 From 8f93f401810f5f8c3d67d59ca5558b4573006380 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jul 2018 18:45:54 +0200 Subject: add lib.rs changes --- library/compiler-builtins/libm/src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 30f879769d0..2ef2092e7cf 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -381,7 +381,6 @@ pub trait F64Ext: private::Sealed { fn sqrt(self) -> Self; - #[cfg(todo)] fn exp(self) -> Self; #[cfg(todo)] @@ -427,7 +426,6 @@ pub trait F64Ext: private::Sealed { (self.sin(), self.cos()) } - #[cfg(todo)] fn exp_m1(self) -> Self; fn ln_1p(self) -> Self; @@ -435,7 +433,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn sinh(self) -> Self; - #[cfg(todo)] fn cosh(self) -> Self; #[cfg(todo)] @@ -522,7 +519,6 @@ impl F64Ext for f64 { sqrt(self) } - #[cfg(todo)] #[inline] fn exp(self) -> Self { exp(self) @@ -607,7 +603,6 @@ impl F64Ext for f64 { atan2(self, other) } - #[cfg(todo)] #[inline] fn exp_m1(self) -> Self { expm1(self) @@ -624,7 +619,6 @@ impl F64Ext for f64 { sinh(self) } - #[cfg(todo)] #[inline] fn cosh(self) -> Self { cosh(self) -- cgit 1.4.1-3-g733a5 From 6d5a9699c2c069d324072c90c8b7aa4ccb62ff24 Mon Sep 17 00:00:00 2001 From: Jack Mott Date: Sat, 14 Jul 2018 11:51:46 -0500 Subject: fix rebase merge --- library/compiler-builtins/libm/src/math/mod.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 21bd7a480b5..324220a3598 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -42,6 +42,8 @@ pub use self::cosf::cosf; pub use self::expf::expf; pub use self::fabs::fabs; pub use self::fabsf::fabsf; +pub use self::fdim::fdim; +pub use self::fdimf::fdimf; pub use self::floor::floor; pub use self::floorf::floorf; pub use self::fmodf::fmodf; @@ -65,20 +67,9 @@ pub use self::sqrtf::sqrtf; pub use self::trunc::trunc; pub use self::truncf::truncf; -pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, fdim::fdim, fdimf::fdimf, floor::floor, - floorf::floorf, fmodf::fmodf, hypot::hypot, hypotf::hypotf, log::log, log10::log10, - log10f::log10f, log1p::log1p, log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, - round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, - trunc::trunc, truncf::truncf, -}; mod k_cosf; mod k_sinf; mod rem_pio2_large; mod rem_pio2f; use self::{k_cosf::k_cosf, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f}; - -fn isnanf(x: f32) -> bool { - x.to_bits() & 0x7fffffff > 0x7f800000 -} -- cgit 1.4.1-3-g733a5 From 92b7592ba28569f3cd64063e174e83cc97fa1194 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jul 2018 19:14:56 +0200 Subject: add missing bitshift for __expo2 and move it into its own module --- library/compiler-builtins/libm/src/math/cosh.rs | 13 ++----------- library/compiler-builtins/libm/src/math/k_expo2.rs | 12 ++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 8 ++++++-- 3 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/k_expo2.rs diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs index ce541ce1489..e76edca0379 100644 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -2,6 +2,7 @@ use core::f64; use super::exp; use super::expm1; +use super::k_expo2; pub fn cosh(mut x: f64) -> f64 { let t: f64; @@ -31,20 +32,10 @@ pub fn cosh(mut x: f64) -> f64 { /* |x| > log(DBL_MAX) or nan */ /* note: the result is stored to handle overflow */ - t = __expo2(x); + t = k_expo2(x); return t; } -const K: u32 = 2043; - -pub fn __expo2(x: f64) -> f64 { - let kln2 = f64::from_bits(0x40962066151add8b); - /* note that k is odd and scale*scale overflows */ - let scale = f64::from_bits(((0x3ff + K / 2) << 20) as u64); - /* exp(x - k ln2) * 2**(k-1) */ - return exp(x - kln2) * scale * scale; -} - #[cfg(test)] mod tests { #[test] diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs new file mode 100644 index 00000000000..c67a86550e6 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_expo2.rs @@ -0,0 +1,12 @@ +use super::exp; + +const K: u32 = 2043; +const KLN2: f64 = 1416.0996898839683; + +#[inline] +pub(crate) fn k_expo2(x: f64) -> f64 { + /* note that k is odd and scale*scale overflows */ + let scale = f64::from_bits((((0x3ff + K / 2) << 20) as u64) << 32); + /* exp(x - k ln2) * 2**(k-1) */ + return exp(x - KLN2) * scale * scale; +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 67f482a6f56..d9e37ee3a6d 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -43,8 +43,8 @@ pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; pub use self::cosh::cosh; -pub use self::expf::expf; pub use self::exp::exp; +pub use self::expf::expf; pub use self::expm1::expm1; pub use self::fabs::fabs; pub use self::fabsf::fabsf; @@ -72,11 +72,15 @@ pub use self::trunc::trunc; pub use self::truncf::truncf; mod k_cosf; +mod k_expo2; mod k_sinf; mod rem_pio2_large; mod rem_pio2f; -use self::{k_cosf::k_cosf, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f}; +use self::{ + k_cosf::k_cosf, k_expo2::k_expo2, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, + rem_pio2f::rem_pio2f, +}; fn isnanf(x: f32) -> bool { x.to_bits() & 0x7fffffff > 0x7f800000 -- cgit 1.4.1-3-g733a5 From 722e2e32cce55d857432e823a62fb46652f01b4c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 14 Jul 2018 12:20:10 -0500 Subject: ci: don't test the master master --- library/compiler-builtins/libm/.travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index 2bbb60fc64d..223b586ea6d 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -35,6 +35,5 @@ before_cache: branches: only: - - master - staging - trying -- cgit 1.4.1-3-g733a5 From 08dabf5dca8a182de50c74f39a237b05d8b4a4f7 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 02:50:23 -0400 Subject: implement exp --- library/compiler-builtins/libm/src/lib.rs | 2 - library/compiler-builtins/libm/src/math/exp.rs | 150 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/exp.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 9095fd892a6..f112aaaca6b 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -378,7 +378,6 @@ pub trait F64Ext: private::Sealed { fn sqrt(self) -> Self; - #[cfg(todo)] fn exp(self) -> Self; #[cfg(todo)] @@ -518,7 +517,6 @@ impl F64Ext for f64 { sqrt(self) } - #[cfg(todo)] #[inline] fn exp(self) -> Self { exp(self) diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs new file mode 100644 index 00000000000..cd63b8fb3f1 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -0,0 +1,150 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* exp(x) + * Returns the exponential of x. + * + * Method + * 1. Argument reduction: + * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2. + * + * Here r will be represented as r = hi-lo for better + * accuracy. + * + * 2. Approximation of exp(r) by a special rational function on + * the interval [0,0.34658]: + * Write + * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... + * We use a special Remez algorithm on [0,0.34658] to generate + * a polynomial of degree 5 to approximate R. The maximum error + * of this polynomial approximation is bounded by 2**-59. In + * other words, + * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 + * (where z=r*r, and the values of P1 to P5 are listed below) + * and + * | 5 | -59 + * | 2.0+P1*z+...+P5*z - R(z) | <= 2 + * | | + * The computation of exp(r) thus becomes + * 2*r + * exp(r) = 1 + ---------- + * R(r) - r + * r*c(r) + * = 1 + r + ----------- (for better accuracy) + * 2 - c(r) + * where + * 2 4 10 + * c(r) = r - (P1*r + P2*r + ... + P5*r ). + * + * 3. Scale back to obtain exp(x): + * From step 1, we have + * exp(x) = 2^k * exp(r) + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF) is 0, and + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 709.782712893383973096 then exp(x) overflows + * if x < -745.133219101941108420 then exp(x) underflows + */ + +use super::scalbn; + +const HALF: [f64; 2] = [0.5, -0.5]; +const LN2HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ +const LN2LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ +const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ +const P1: f64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */ +const P2: f64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ +const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ +const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ +const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +#[inline] +pub fn exp(mut x: f64) -> f64 { + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 + let x1p_149 = f64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149 + + let hi: f64; + let lo: f64; + let c: f64; + let xx: f64; + let y: f64; + let k: i32; + let sign: i32; + let mut hx: u32; + + hx = (x.to_bits() >> 32) as u32; + sign = (hx >> 31) as i32; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if hx >= 0x4086232b { + /* if |x| >= 708.39... */ + if x.is_nan() { + return x; + } + if x > 709.782712893383973096 { + /* overflow if x!=inf */ + x *= x1p1023; + return x; + } + if x < -708.39641853226410622 { + /* underflow if x!=-inf */ + force_eval!((-x1p_149 / x) as f32); + if x < -745.13321910194110842 { + return 0.; + } + } + } + + /* argument reduction */ + if hx > 0x3fd62e42 { + /* if |x| > 0.5 ln2 */ + if hx >= 0x3ff0a2b2 { + /* if |x| >= 1.5 ln2 */ + k = (INVLN2 * x + HALF[sign as usize]) as i32; + } else { + k = 1 - sign - sign; + } + hi = x - k as f64 * LN2HI; /* k*ln2hi is exact here */ + lo = k as f64 * LN2LO; + x = hi - lo; + } else if hx > 0x3e300000 { + /* if |x| > 2**-28 */ + k = 0; + hi = x; + lo = 0.; + } else { + /* inexact if x!=0 */ + force_eval!(x1p1023 + x); + return 1. + x; + } + + /* x is now in primary range */ + xx = x * x; + c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); + y = 1. + (x * c / (2. - c) - lo + hi); + if k == 0 { + y + } else { + scalbn(y, k) + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index ee846ebb9cc..2a84b463d9f 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -9,6 +9,7 @@ macro_rules! force_eval { mod ceil; mod ceilf; mod cosf; +mod exp; mod expf; mod fabs; mod fabsf; @@ -39,6 +40,7 @@ mod truncf; pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; +pub use self::exp::exp; pub use self::expf::expf; pub use self::fabs::fabs; pub use self::fabsf::fabsf; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 291c30f6394..a54d8b2710f 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -703,7 +703,7 @@ f64_f64! { ceil, // cos, // cosh, - // exp, + exp, // exp2, // expm1, floor, -- cgit 1.4.1-3-g733a5 From e22803605379ea10989050707a6a30d02ab8a141 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 14:07:14 -0400 Subject: implement cbrt and cbrtf --- library/compiler-builtins/libm/src/lib.rs | 4 - library/compiler-builtins/libm/src/math/cbrt.rs | 110 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/cbrtf.rs | 72 ++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 4 + .../libm/test-generator/src/main.rs | 4 +- 5 files changed, 188 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/cbrt.rs create mode 100644 library/compiler-builtins/libm/src/math/cbrtf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index f112aaaca6b..b175f686411 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -79,7 +79,6 @@ pub trait F32Ext: private::Sealed { fn log10(self) -> Self; - #[cfg(todo)] fn cbrt(self) -> Self; fn hypot(self, other: Self) -> Self; @@ -234,7 +233,6 @@ impl F32Ext for f32 { log10f(self) } - #[cfg(todo)] #[inline] fn cbrt(self) -> Self { cbrtf(self) @@ -391,7 +389,6 @@ pub trait F64Ext: private::Sealed { fn log10(self) -> Self; - #[cfg(todo)] fn cbrt(self) -> Self; fn hypot(self, other: Self) -> Self; @@ -548,7 +545,6 @@ impl F64Ext for f64 { log10(self) } - #[cfg(todo)] #[inline] fn cbrt(self) -> Self { cbrt(self) diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs new file mode 100644 index 00000000000..8c37f0b266b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -0,0 +1,110 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrt.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +/* cbrt(x) + * Return cube root of x + */ + +use core::f64; + +const B1: u32 = 715094163; /* B1 = (1023-1023/3-0.03306235651)*2**20 */ +const B2: u32 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */ + +/* |1/cbrt(x) - p(x)| < 2**-23.5 (~[-7.93e-8, 7.929e-8]). */ +const P0: f64 = 1.87595182427177009643; /* 0x3ffe03e6, 0x0f61e692 */ +const P1: f64 = -1.88497979543377169875; /* 0xbffe28e0, 0x92f02420 */ +const P2: f64 = 1.621429720105354466140; /* 0x3ff9f160, 0x4a49d6c2 */ +const P3: f64 = -0.758397934778766047437; /* 0xbfe844cb, 0xbee751d9 */ +const P4: f64 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ + +#[inline] +pub fn cbrt(x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui: u64 = x.to_bits(); + let mut r: f64; + let s: f64; + let mut t: f64; + let w: f64; + let mut hx: u32 = (ui >> 32) as u32 & 0x7fffffff; + + if hx >= 0x7ff00000 { + /* cbrt(NaN,INF) is itself */ + return x + x; + } + + /* + * Rough cbrt to 5 bits: + * cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3) + * where e is integral and >= 0, m is real and in [0, 1), and "/" and + * "%" are integer division and modulus with rounding towards minus + * infinity. The RHS is always >= the LHS and has a maximum relative + * error of about 1 in 16. Adding a bias of -0.03306235651 to the + * (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE + * floating point representation, for finite positive normal values, + * ordinary integer divison of the value in bits magically gives + * almost exactly the RHS of the above provided we first subtract the + * exponent bias (1023 for doubles) and later add it back. We do the + * subtraction virtually to keep e >= 0 so that ordinary integer + * division rounds towards minus infinity; this is also efficient. + */ + if hx < 0x00100000 { + /* zero or subnormal? */ + ui = (x * x1p54).to_bits(); + hx = (ui >> 32) as u32 & 0x7fffffff; + if hx == 0 { + return x; /* cbrt(0) is itself */ + } + hx = hx / 3 + B2; + } else { + hx = hx / 3 + B1; + } + ui &= 1 << 63; + ui |= (hx as u64) << 32; + t = f64::from_bits(ui); + + /* + * New cbrt to 23 bits: + * cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x) + * where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r) + * to within 2**-23.5 when |r - 1| < 1/10. The rough approximation + * has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this + * gives us bounds for r = t**3/x. + * + * Try to optimize for parallel evaluation as in __tanf.c. + */ + r = (t * t) * (t / x); + t = t * ((P0 + r * (P1 + r * P2)) + ((r * r) * r) * (P3 + r * P4)); + + /* + * Round t away from zero to 23 bits (sloppily except for ensuring that + * the result is larger in magnitude than cbrt(x) but not much more than + * 2 23-bit ulps larger). With rounding towards zero, the error bound + * would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps + * in the rounded t, the infinite-precision error in the Newton + * approximation barely affects third digit in the final error + * 0.667; the error in the rounded t can be up to about 3 23-bit ulps + * before the final error is larger than 0.667 ulps. + */ + ui = t.to_bits(); + ui = (ui + 0x80000000) & 0xffffffffc0000000; + t = f64::from_bits(ui); + + /* one step Newton iteration to 53 bits with error < 0.667 ulps */ + s = t * t; /* t*t is exact */ + r = x / s; /* error <= 0.5 ulps; |r| < |t| */ + w = t + t; /* t+t is exact */ + r = (r - t) / (w + r); /* r-t is exact; w+r ~= 3*t */ + t = t + t * r; /* error <= 0.5 + 0.5/3 + epsilon */ + t +} diff --git a/library/compiler-builtins/libm/src/math/cbrtf.rs b/library/compiler-builtins/libm/src/math/cbrtf.rs new file mode 100644 index 00000000000..878372eefbf --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cbrtf.rs @@ -0,0 +1,72 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* cbrtf(x) + * Return cube root of x + */ + +use core::f32; + +const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ +const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ + +#[inline] +pub fn cbrtf(x: f32) -> f32 { + let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 + + let mut r: f64; + let mut t: f64; + let mut ui: u32 = x.to_bits(); + let mut hx: u32 = ui & 0x7fffffff; + + if hx >= 0x7f800000 { + /* cbrt(NaN,INF) is itself */ + return x + x; + } + + /* rough cbrt to 5 bits */ + if hx < 0x00800000 { + /* zero or subnormal? */ + if hx == 0 { + return x; /* cbrt(+-0) is itself */ + } + ui = (x * x1p24).to_bits(); + hx = ui & 0x7fffffff; + hx = hx / 3 + B2; + } else { + hx = hx / 3 + B1; + } + ui &= 0x80000000; + ui |= hx; + + /* + * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In + * double precision so that its terms can be arranged for efficiency + * without causing overflow or underflow. + */ + t = f32::from_bits(ui) as f64; + r = t * t * t; + t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); + + /* + * Second step Newton iteration to 47 bits. In double precision for + * efficiency and accuracy. + */ + r = t * t * t; + t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); + + /* rounding to 24 bits is perfect in round-to-nearest mode */ + t as f32 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 2a84b463d9f..0f112a0cbbe 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -6,6 +6,8 @@ macro_rules! force_eval { }; } +mod cbrt; +mod cbrtf; mod ceil; mod ceilf; mod cosf; @@ -37,6 +39,8 @@ mod trunc; mod truncf; // Use separated imports instead of {}-grouped imports for easier merging. +pub use self::cbrt::cbrt; +pub use self::cbrtf::cbrtf; pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index a54d8b2710f..0521538deff 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -656,7 +656,7 @@ f32_f32! { truncf, // asinf, // atanf, - // cbrtf, + cbrtf, cosf, ceilf, // coshf, @@ -699,7 +699,7 @@ f64_f64! { // acos, // asin, // atan, - // cbrt, + cbrt, ceil, // cos, // cosh, -- cgit 1.4.1-3-g733a5 From de0682bf64e0bc753b0bb82bffc8f66cad7faa31 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jul 2018 20:36:28 +0200 Subject: remove exp --- library/compiler-builtins/libm/src/lib.rs | 2 + library/compiler-builtins/libm/src/math/exp.rs | 84 ---------------------- library/compiler-builtins/libm/src/math/mod.rs | 2 - .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 3 insertions(+), 87 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/exp.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index e8869fca9ab..c53fefb2f29 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -378,6 +378,7 @@ pub trait F64Ext: private::Sealed { fn sqrt(self) -> Self; + #[cfg(todo)] fn exp(self) -> Self; #[cfg(todo)] @@ -515,6 +516,7 @@ impl F64Ext for f64 { sqrt(self) } + #[cfg(todo)] #[inline] fn exp(self) -> Self { exp(self) diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs deleted file mode 100644 index 870bf60853f..00000000000 --- a/library/compiler-builtins/libm/src/math/exp.rs +++ /dev/null @@ -1,84 +0,0 @@ -use super::scalbn; - -const HALF: [f64; 2] = [0.5, -0.5]; -const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ -const LN2_LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ -const INV_LN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ -const P1: f64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */ -const P2: f64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ -const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ -const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ -const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ - -#[inline] -pub fn exp(mut x: f64) -> f64 { - let mut hx: u32 = (x.to_bits() >> 32) as u32; - let sign = (hx >> 31) as i32; /* sign bit of x */ - hx &= 0x7fffffff; /* high word of |x| */ - - /* special cases */ - if hx >= 0x4086232b { - /* if |x| >= 708.39... */ - if x.is_nan() { - return x; - } - if x > 709.782712893383973096 { - /* overflow if x!=inf */ - x *= f64::from_bits(0x7fe0000000000000); - return x; - } - if x < -708.39641853226410622 { - /* underflow if x!=-inf */ - force_eval!((f64::from_bits(0xb6a0000000000000) / x) as f32); - if x < -745.13321910194110842 { - return 0.0; - } - } - } - - /* argument reduction */ - let k: i32; - let hi: f64; - let lo: f64; - if hx > 0x3fd62e42 { - /* if |x| > 0.5 ln2 */ - /* if |x| > 0.5 ln2 */ - if hx > 0x3ff0a2b2 { - /* if |x| > 1.5 ln2 */ - k = (INV_LN2 * x + HALF[sign as usize]) as i32; - } else { - k = 1 - sign - sign; - } - let kf = k as f64; - hi = x - kf * LN2_HI; /* k*ln2hi is exact here */ - lo = kf * LN2_LO; - x = hi - lo; - } else if hx > 0x3e300000 { - /* |x| > 2**-14 */ - k = 0; - hi = x; - lo = 0.0; - } else { - /* raise inexact */ - force_eval!(f64::from_bits(0x7fe0000000000000) + x); - return 1.0 + x; - } - - /* x is now in primary range */ - let xx = x * x; - let c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); - let y = 1.0 + (x * c / (2.0 - c) - lo + hi); - if k == 0 { - y - } else { - scalbn(y, k) - } -} - -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::exp(1.1), 3.0041660239464334); - } -} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index d9e37ee3a6d..be17295659a 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -10,7 +10,6 @@ mod ceil; mod ceilf; mod cosf; mod cosh; -mod exp; mod expf; mod expm1; mod fabs; @@ -43,7 +42,6 @@ pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; pub use self::cosh::cosh; -pub use self::exp::exp; pub use self::expf::expf; pub use self::expm1::expm1; pub use self::fabs::fabs; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 8689870c2f5..fc2842b0b81 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -703,7 +703,7 @@ f64_f64! { ceil, // cos, cosh, - exp, + // exp, // exp2, expm1, floor, -- cgit 1.4.1-3-g733a5 From c6aad03ae4f922a8cd453627944669306cb850b6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jul 2018 20:51:39 +0200 Subject: remove faulty cosh implementation --- library/compiler-builtins/libm/src/math/cosh.rs | 45 ---------------------- library/compiler-builtins/libm/src/math/k_expo2.rs | 12 ------ 2 files changed, 57 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/cosh.rs delete mode 100644 library/compiler-builtins/libm/src/math/k_expo2.rs diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs deleted file mode 100644 index e76edca0379..00000000000 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ /dev/null @@ -1,45 +0,0 @@ -use core::f64; - -use super::exp; -use super::expm1; -use super::k_expo2; - -pub fn cosh(mut x: f64) -> f64 { - let t: f64; - /* |x| */ - let mut ui = x.to_bits(); - ui &= !0u64; - x = f64::from_bits(ui); - let w = (ui >> 32) as u32; - - /* |x| < log(2) */ - if w < 0x3fe62e42 { - if w < 0x3ff00000 - (26 << 20) { - /* raise inexact if x!=0 */ - force_eval!(x + f64::from_bits(0x4770000000000000)); - return 1.0; - } - let t = expm1(x); - return 1.0 + t * t / (2.0 * (1.0 + t)); - } - - /* |x| < log(DBL_MAX) */ - if w < 0x40862e42 { - t = exp(x); - /* note: if x>log(0x1p26) then the 1/t is not needed */ - return 0.5 * (t + 1.0 / t); - } - - /* |x| > log(DBL_MAX) or nan */ - /* note: the result is stored to handle overflow */ - t = k_expo2(x); - return t; -} - -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::cosh(1.1), 1.6685185538222564); - } -} diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs deleted file mode 100644 index c67a86550e6..00000000000 --- a/library/compiler-builtins/libm/src/math/k_expo2.rs +++ /dev/null @@ -1,12 +0,0 @@ -use super::exp; - -const K: u32 = 2043; -const KLN2: f64 = 1416.0996898839683; - -#[inline] -pub(crate) fn k_expo2(x: f64) -> f64 { - /* note that k is odd and scale*scale overflows */ - let scale = f64::from_bits((((0x3ff + K / 2) << 20) as u64) << 32); - /* exp(x - k ln2) * 2**(k-1) */ - return exp(x - KLN2) * scale * scale; -} -- cgit 1.4.1-3-g733a5 From b544bc360f8edc38fb6d64b1d1527d86cf6be95b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jul 2018 20:59:41 +0200 Subject: fix missing changes --- library/compiler-builtins/libm/src/lib.rs | 2 ++ library/compiler-builtins/libm/src/math/mod.rs | 6 +----- library/compiler-builtins/libm/test-generator/src/main.rs | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 8091079a624..3a772881188 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -439,6 +439,7 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn sinh(self) -> Self; + #[cfg(todo)] fn cosh(self) -> Self; #[cfg(todo)] @@ -628,6 +629,7 @@ impl F64Ext for f64 { sinh(self) } + #[cfg(todo)] #[inline] fn cosh(self) -> Self { cosh(self) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 86c181d1323..65bfb96d08f 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -9,7 +9,6 @@ macro_rules! force_eval { mod ceil; mod ceilf; mod cosf; -mod cosh; mod exp; mod expf; mod expm1; @@ -44,7 +43,6 @@ mod truncf; pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; -pub use self::cosh::cosh; pub use self::exp::exp; pub use self::expf::expf; pub use self::expm1::expm1; @@ -76,12 +74,10 @@ pub use self::trunc::trunc; pub use self::truncf::truncf; mod k_cosf; -mod k_expo2; mod k_sinf; mod rem_pio2_large; mod rem_pio2f; use self::{ - k_cosf::k_cosf, k_expo2::k_expo2, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, - rem_pio2f::rem_pio2f, + k_cosf::k_cosf, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f, }; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index dff949459a2..6010695cb1d 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -702,7 +702,7 @@ f64_f64! { // cbrt, ceil, // cos, - cosh, + // cosh, exp, // exp2, expm1, -- cgit 1.4.1-3-g733a5 From 353409ada712abee04099d2a640f2c6ddf1d20e6 Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 05:04:46 -0400 Subject: Add exp2f --- library/compiler-builtins/libm/src/lib.rs | 2 - library/compiler-builtins/libm/src/math/exp2f.rs | 130 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/exp2f.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index fddb8ca70fb..c6e01df415e 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -70,7 +70,6 @@ pub trait F32Ext: private::Sealed { fn exp(self) -> Self; - #[cfg(todo)] fn exp2(self) -> Self; fn ln(self) -> Self; @@ -214,7 +213,6 @@ impl F32Ext for f32 { expf(self) } - #[cfg(todo)] #[inline] fn exp2(self) -> Self { exp2f(self) diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs new file mode 100644 index 00000000000..947679a8389 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -0,0 +1,130 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c +//- +// Copyright (c) 2005 David Schultz +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +const TBLSIZE: usize = 16; + +// exp2f(x): compute the base 2 exponential of x +// +// Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. +// +// Method: (equally-spaced tables) +// +// Reduce x: +// x = k + y, for integer k and |y| <= 1/2. +// Thus we have exp2f(x) = 2**k * exp2(y). +// +// Reduce y: +// y = i/TBLSIZE + z for integer i near y * TBLSIZE. +// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), +// with |z| <= 2**-(TBLSIZE+1). +// +// We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a +// degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. +// Using double precision for everything except the reduction makes +// roundoff error insignificant and simplifies the scaling step. +// +// This method is due to Tang, but I do not use his suggested parameters: +// +// Tang, P. Table-driven Implementation of the Exponential Function +// in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). +pub fn exp2f(mut x: f32) -> f32 { + let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; + let p1 = f32::from_bits(0x3f317218); + let p2 = f32::from_bits(0x3e75fdf0); + let p3 = f32::from_bits(0x3d6359a4); + let p4 = f32::from_bits(0x3c1d964e); + + let exp2ft: [f64; TBLSIZE] = [ + f64::from_bits(0x3fe6a09e667f3bcd), + f64::from_bits(0x3fe7a11473eb0187), + f64::from_bits(0x3fe8ace5422aa0db), + f64::from_bits(0x3fe9c49182a3f090), + f64::from_bits(0x3feae89f995ad3ad), + f64::from_bits(0x3fec199bdd85529c), + f64::from_bits(0x3fed5818dcfba487), + f64::from_bits(0x3feea4afa2a490da), + f64::from_bits(0x3ff0000000000000), + f64::from_bits(0x3ff0b5586cf9890f), + f64::from_bits(0x3ff172b83c7d517b), + f64::from_bits(0x3ff2387a6e756238), + f64::from_bits(0x3ff306fe0a31b715), + f64::from_bits(0x3ff3dea64c123422), + f64::from_bits(0x3ff4bfdad5362a27), + f64::from_bits(0x3ff5ab07dd485429), + ]; + + // double_t t, r, z; + // uint32_t ix, i0, k; + + let x1p127 = f32::from_bits(0x7f000000); + + /* Filter out exceptional cases. */ + let ui = f32::to_bits(x); + let ix = ui & 0x7fffffff; + if ix > 0x42fc0000 { + /* |x| > 126 */ + if ix > 0x7f800000 { + /* NaN */ + return x; + } + if ui >= 0x43000000 && ui < 0x80000000 { + /* x >= 128 */ + x *= x1p127; + return x; + } + if ui >= 0x80000000 { + /* x < -126 */ + if ui >= 0xc3160000 || (ui & 0x0000ffff != 0) { + force_eval!(f32::from_bits(0x80000001) / x); + } + if ui >= 0xc3160000 { + /* x <= -150 */ + return 0.0; + } + } + } else if ix <= 0x33000000 { + /* |x| <= 0x1p-25 */ + return 1.0 + x; + } + + /* Reduce x, computing z, i0, and k. */ + let ui = f32::to_bits(x + redux); + let mut i0 = ui; + i0 += TBLSIZE as u32 / 2; + let k = i0 / TBLSIZE as u32; + let ukf = f64::from_bits(((0x3ff + k) as u64) << 52); + i0 &= TBLSIZE as u32 - 1; + let mut uf = f32::from_bits(ui); + uf -= redux; + let z: f64 = (x - uf) as f64; + /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ + let r: f64 = exp2ft[i0 as usize]; + let t: f64 = r as f64 * z; + let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64); + + /* Scale by 2**k */ + (r * ukf) as f32 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 59d669ab6a9..5540ba83825 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -12,6 +12,7 @@ mod ceil; mod ceilf; mod cosf; mod exp; +mod exp2f; mod expf; mod fabs; mod fabsf; @@ -48,6 +49,7 @@ pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; pub use self::exp::exp; +pub use self::exp2f::exp2f; pub use self::expf::expf; pub use self::fabs::fabs; pub use self::fabsf::fabsf; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index bce4284b3d0..dfe912a508b 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -660,7 +660,7 @@ f32_f32! { cosf, ceilf, // coshf, - // exp2f, + exp2f, expf, log10f, log1pf, -- cgit 1.4.1-3-g733a5 From 62b9897c29deb29345598987b07ab0f4be8d335a Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 05:29:43 -0400 Subject: Implement exp2 --- library/compiler-builtins/libm/src/lib.rs | 2 - library/compiler-builtins/libm/src/math/exp2.rs | 383 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 386 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/exp2.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index c6e01df415e..3f9a65bccd1 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -385,7 +385,6 @@ pub trait F64Ext: private::Sealed { fn exp(self) -> Self; - #[cfg(todo)] fn exp2(self) -> Self; fn ln(self) -> Self; @@ -530,7 +529,6 @@ impl F64Ext for f64 { exp(self) } - #[cfg(todo)] #[inline] fn exp2(self) -> Self { exp2(self) diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs new file mode 100644 index 00000000000..c5bd3608a43 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -0,0 +1,383 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */ +//- +// Copyright (c) 2005 David Schultz +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +use super::scalbn::scalbn; + +const TBLSIZE: usize = 256; + +// exp2(x): compute the base 2 exponential of x +// +// Accuracy: Peak error < 0.503 ulp for normalized results. +// +// Method: (accurate tables) +// +// Reduce x: +// x = k + y, for integer k and |y| <= 1/2. +// Thus we have exp2(x) = 2**k * exp2(y). +// +// Reduce y: +// y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. +// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), +// with |z - eps[i]| <= 2**-9 + 2**-39 for the table used. +// +// We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via +// a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61. +// The values in exp2t[] and eps[] are chosen such that +// exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such +// that exp2t[i] is accurate to 2**-64. +// +// Note that the range of i is +-TBLSIZE/2, so we actually index the tables +// by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are +// virtual tables, interleaved in the real table tbl[]. +// +// This method is due to Gal, with many details due to Gal and Bachelis: +// +// Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library +// for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). +pub fn exp2(mut x: f64) -> f64 { + let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64; + let p1 = f64::from_bits(0x3fe62e42fefa39ef); + let p2 = f64::from_bits(0x3fcebfbdff82c575); + let p3 = f64::from_bits(0x3fac6b08d704a0a6); + let p4 = f64::from_bits(0x3f83b2ab88f70400); + let p5 = f64::from_bits(0x3f55d88003875c74); + + #[cfg_attr(rustfmt, rustfmt_skip)] + let tbl = [ + // exp2(z + eps) eps + f64::from_bits(0x3fe6a09e667f3d5d), f64::from_bits(0x3d39880000000000), + f64::from_bits(0x3fe6b052fa751744), f64::from_bits(0x3cd8000000000000), + f64::from_bits(0x3fe6c012750bd9fe), f64::from_bits(0xbd28780000000000), + f64::from_bits(0x3fe6cfdcddd476bf), f64::from_bits(0x3d1ec00000000000), + f64::from_bits(0x3fe6dfb23c651a29), f64::from_bits(0xbcd8000000000000), + f64::from_bits(0x3fe6ef9298593ae3), f64::from_bits(0xbcbc000000000000), + f64::from_bits(0x3fe6ff7df9519386), f64::from_bits(0xbd2fd80000000000), + f64::from_bits(0x3fe70f7466f42da3), f64::from_bits(0xbd2c880000000000), + f64::from_bits(0x3fe71f75e8ec5fc3), f64::from_bits(0x3d13c00000000000), + f64::from_bits(0x3fe72f8286eacf05), f64::from_bits(0xbd38300000000000), + f64::from_bits(0x3fe73f9a48a58152), f64::from_bits(0xbd00c00000000000), + f64::from_bits(0x3fe74fbd35d7ccfc), f64::from_bits(0x3d2f880000000000), + f64::from_bits(0x3fe75feb564267f1), f64::from_bits(0x3d03e00000000000), + f64::from_bits(0x3fe77024b1ab6d48), f64::from_bits(0xbd27d00000000000), + f64::from_bits(0x3fe780694fde5d38), f64::from_bits(0xbcdd000000000000), + f64::from_bits(0x3fe790b938ac1d00), f64::from_bits(0x3ce3000000000000), + f64::from_bits(0x3fe7a11473eb0178), f64::from_bits(0xbced000000000000), + f64::from_bits(0x3fe7b17b0976d060), f64::from_bits(0x3d20400000000000), + f64::from_bits(0x3fe7c1ed0130c133), f64::from_bits(0x3ca0000000000000), + f64::from_bits(0x3fe7d26a62ff8636), f64::from_bits(0xbd26900000000000), + f64::from_bits(0x3fe7e2f336cf4e3b), f64::from_bits(0xbd02e00000000000), + f64::from_bits(0x3fe7f3878491c3e8), f64::from_bits(0xbd24580000000000), + f64::from_bits(0x3fe80427543e1b4e), f64::from_bits(0x3d33000000000000), + f64::from_bits(0x3fe814d2add1071a), f64::from_bits(0x3d0f000000000000), + f64::from_bits(0x3fe82589994ccd7e), f64::from_bits(0xbd21c00000000000), + f64::from_bits(0x3fe8364c1eb942d0), f64::from_bits(0x3d29d00000000000), + f64::from_bits(0x3fe8471a4623cab5), f64::from_bits(0x3d47100000000000), + f64::from_bits(0x3fe857f4179f5bbc), f64::from_bits(0x3d22600000000000), + f64::from_bits(0x3fe868d99b4491af), f64::from_bits(0xbd32c40000000000), + f64::from_bits(0x3fe879cad931a395), f64::from_bits(0xbd23000000000000), + f64::from_bits(0x3fe88ac7d98a65b8), f64::from_bits(0xbd2a800000000000), + f64::from_bits(0x3fe89bd0a4785800), f64::from_bits(0xbced000000000000), + f64::from_bits(0x3fe8ace5422aa223), f64::from_bits(0x3d33280000000000), + f64::from_bits(0x3fe8be05bad619fa), f64::from_bits(0x3d42b40000000000), + f64::from_bits(0x3fe8cf3216b54383), f64::from_bits(0xbd2ed00000000000), + f64::from_bits(0x3fe8e06a5e08664c), f64::from_bits(0xbd20500000000000), + f64::from_bits(0x3fe8f1ae99157807), f64::from_bits(0x3d28280000000000), + f64::from_bits(0x3fe902fed0282c0e), f64::from_bits(0xbd1cb00000000000), + f64::from_bits(0x3fe9145b0b91ff96), f64::from_bits(0xbd05e00000000000), + f64::from_bits(0x3fe925c353aa2ff9), f64::from_bits(0x3cf5400000000000), + f64::from_bits(0x3fe93737b0cdc64a), f64::from_bits(0x3d17200000000000), + f64::from_bits(0x3fe948b82b5f98ae), f64::from_bits(0xbd09000000000000), + f64::from_bits(0x3fe95a44cbc852cb), f64::from_bits(0x3d25680000000000), + f64::from_bits(0x3fe96bdd9a766f21), f64::from_bits(0xbd36d00000000000), + f64::from_bits(0x3fe97d829fde4e2a), f64::from_bits(0xbd01000000000000), + f64::from_bits(0x3fe98f33e47a23a3), f64::from_bits(0x3d2d000000000000), + f64::from_bits(0x3fe9a0f170ca0604), f64::from_bits(0xbd38a40000000000), + f64::from_bits(0x3fe9b2bb4d53ff89), f64::from_bits(0x3d355c0000000000), + f64::from_bits(0x3fe9c49182a3f15b), f64::from_bits(0x3d26b80000000000), + f64::from_bits(0x3fe9d674194bb8c5), f64::from_bits(0xbcec000000000000), + f64::from_bits(0x3fe9e86319e3238e), f64::from_bits(0x3d17d00000000000), + f64::from_bits(0x3fe9fa5e8d07f302), f64::from_bits(0x3d16400000000000), + f64::from_bits(0x3fea0c667b5de54d), f64::from_bits(0xbcf5000000000000), + f64::from_bits(0x3fea1e7aed8eb8f6), f64::from_bits(0x3d09e00000000000), + f64::from_bits(0x3fea309bec4a2e27), f64::from_bits(0x3d2ad80000000000), + f64::from_bits(0x3fea42c980460a5d), f64::from_bits(0xbd1af00000000000), + f64::from_bits(0x3fea5503b23e259b), f64::from_bits(0x3d0b600000000000), + f64::from_bits(0x3fea674a8af46213), f64::from_bits(0x3d38880000000000), + f64::from_bits(0x3fea799e1330b3a7), f64::from_bits(0x3d11200000000000), + f64::from_bits(0x3fea8bfe53c12e8d), f64::from_bits(0x3d06c00000000000), + f64::from_bits(0x3fea9e6b5579fcd2), f64::from_bits(0xbd29b80000000000), + f64::from_bits(0x3feab0e521356fb8), f64::from_bits(0x3d2b700000000000), + f64::from_bits(0x3feac36bbfd3f381), f64::from_bits(0x3cd9000000000000), + f64::from_bits(0x3fead5ff3a3c2780), f64::from_bits(0x3ce4000000000000), + f64::from_bits(0x3feae89f995ad2a3), f64::from_bits(0xbd2c900000000000), + f64::from_bits(0x3feafb4ce622f367), f64::from_bits(0x3d16500000000000), + f64::from_bits(0x3feb0e07298db790), f64::from_bits(0x3d2fd40000000000), + f64::from_bits(0x3feb20ce6c9a89a9), f64::from_bits(0x3d12700000000000), + f64::from_bits(0x3feb33a2b84f1a4b), f64::from_bits(0x3d4d470000000000), + f64::from_bits(0x3feb468415b747e7), f64::from_bits(0xbd38380000000000), + f64::from_bits(0x3feb59728de5593a), f64::from_bits(0x3c98000000000000), + f64::from_bits(0x3feb6c6e29f1c56a), f64::from_bits(0x3d0ad00000000000), + f64::from_bits(0x3feb7f76f2fb5e50), f64::from_bits(0x3cde800000000000), + f64::from_bits(0x3feb928cf22749b2), f64::from_bits(0xbd04c00000000000), + f64::from_bits(0x3feba5b030a10603), f64::from_bits(0xbd0d700000000000), + f64::from_bits(0x3febb8e0b79a6f66), f64::from_bits(0x3d0d900000000000), + f64::from_bits(0x3febcc1e904bc1ff), f64::from_bits(0x3d02a00000000000), + f64::from_bits(0x3febdf69c3f3a16f), f64::from_bits(0xbd1f780000000000), + f64::from_bits(0x3febf2c25bd71db8), f64::from_bits(0xbd10a00000000000), + f64::from_bits(0x3fec06286141b2e9), f64::from_bits(0xbd11400000000000), + f64::from_bits(0x3fec199bdd8552e0), f64::from_bits(0x3d0be00000000000), + f64::from_bits(0x3fec2d1cd9fa64ee), f64::from_bits(0xbd09400000000000), + f64::from_bits(0x3fec40ab5fffd02f), f64::from_bits(0xbd0ed00000000000), + f64::from_bits(0x3fec544778fafd15), f64::from_bits(0x3d39660000000000), + f64::from_bits(0x3fec67f12e57d0cb), f64::from_bits(0xbd1a100000000000), + f64::from_bits(0x3fec7ba88988c1b6), f64::from_bits(0xbd58458000000000), + f64::from_bits(0x3fec8f6d9406e733), f64::from_bits(0xbd1a480000000000), + f64::from_bits(0x3feca3405751c4df), f64::from_bits(0x3ccb000000000000), + f64::from_bits(0x3fecb720dcef9094), f64::from_bits(0x3d01400000000000), + f64::from_bits(0x3feccb0f2e6d1689), f64::from_bits(0x3cf0200000000000), + f64::from_bits(0x3fecdf0b555dc412), f64::from_bits(0x3cf3600000000000), + f64::from_bits(0x3fecf3155b5bab3b), f64::from_bits(0xbd06900000000000), + f64::from_bits(0x3fed072d4a0789bc), f64::from_bits(0x3d09a00000000000), + f64::from_bits(0x3fed1b532b08c8fa), f64::from_bits(0xbd15e00000000000), + f64::from_bits(0x3fed2f87080d8a85), f64::from_bits(0x3d1d280000000000), + f64::from_bits(0x3fed43c8eacaa203), f64::from_bits(0x3d01a00000000000), + f64::from_bits(0x3fed5818dcfba491), f64::from_bits(0x3cdf000000000000), + f64::from_bits(0x3fed6c76e862e6a1), f64::from_bits(0xbd03a00000000000), + f64::from_bits(0x3fed80e316c9834e), f64::from_bits(0xbd0cd80000000000), + f64::from_bits(0x3fed955d71ff6090), f64::from_bits(0x3cf4c00000000000), + f64::from_bits(0x3feda9e603db32ae), f64::from_bits(0x3cff900000000000), + f64::from_bits(0x3fedbe7cd63a8325), f64::from_bits(0x3ce9800000000000), + f64::from_bits(0x3fedd321f301b445), f64::from_bits(0xbcf5200000000000), + f64::from_bits(0x3fede7d5641c05bf), f64::from_bits(0xbd1d700000000000), + f64::from_bits(0x3fedfc97337b9aec), f64::from_bits(0xbd16140000000000), + f64::from_bits(0x3fee11676b197d5e), f64::from_bits(0x3d0b480000000000), + f64::from_bits(0x3fee264614f5a3e7), f64::from_bits(0x3d40ce0000000000), + f64::from_bits(0x3fee3b333b16ee5c), f64::from_bits(0x3d0c680000000000), + f64::from_bits(0x3fee502ee78b3fb4), f64::from_bits(0xbd09300000000000), + f64::from_bits(0x3fee653924676d68), f64::from_bits(0xbce5000000000000), + f64::from_bits(0x3fee7a51fbc74c44), f64::from_bits(0xbd07f80000000000), + f64::from_bits(0x3fee8f7977cdb726), f64::from_bits(0xbcf3700000000000), + f64::from_bits(0x3feea4afa2a490e8), f64::from_bits(0x3ce5d00000000000), + f64::from_bits(0x3feeb9f4867ccae4), f64::from_bits(0x3d161a0000000000), + f64::from_bits(0x3feecf482d8e680d), f64::from_bits(0x3cf5500000000000), + f64::from_bits(0x3feee4aaa2188514), f64::from_bits(0x3cc6400000000000), + f64::from_bits(0x3feefa1bee615a13), f64::from_bits(0xbcee800000000000), + f64::from_bits(0x3fef0f9c1cb64106), f64::from_bits(0xbcfa880000000000), + f64::from_bits(0x3fef252b376bb963), f64::from_bits(0xbd2c900000000000), + f64::from_bits(0x3fef3ac948dd7275), f64::from_bits(0x3caa000000000000), + f64::from_bits(0x3fef50765b6e4524), f64::from_bits(0xbcf4f00000000000), + f64::from_bits(0x3fef6632798844fd), f64::from_bits(0x3cca800000000000), + f64::from_bits(0x3fef7bfdad9cbe38), f64::from_bits(0x3cfabc0000000000), + f64::from_bits(0x3fef91d802243c82), f64::from_bits(0xbcd4600000000000), + f64::from_bits(0x3fefa7c1819e908e), f64::from_bits(0xbd0b0c0000000000), + f64::from_bits(0x3fefbdba3692d511), f64::from_bits(0xbcc0e00000000000), + f64::from_bits(0x3fefd3c22b8f7194), f64::from_bits(0xbd10de8000000000), + f64::from_bits(0x3fefe9d96b2a23ee), f64::from_bits(0x3cee430000000000), + f64::from_bits(0x3ff0000000000000), f64::from_bits(0x0), + f64::from_bits(0x3ff00b1afa5abcbe), f64::from_bits(0xbcb3400000000000), + f64::from_bits(0x3ff0163da9fb3303), f64::from_bits(0xbd12170000000000), + f64::from_bits(0x3ff02168143b0282), f64::from_bits(0x3cba400000000000), + f64::from_bits(0x3ff02c9a3e77806c), f64::from_bits(0x3cef980000000000), + f64::from_bits(0x3ff037d42e11bbca), f64::from_bits(0xbcc7400000000000), + f64::from_bits(0x3ff04315e86e7f89), f64::from_bits(0x3cd8300000000000), + f64::from_bits(0x3ff04e5f72f65467), f64::from_bits(0xbd1a3f0000000000), + f64::from_bits(0x3ff059b0d315855a), f64::from_bits(0xbd02840000000000), + f64::from_bits(0x3ff0650a0e3c1f95), f64::from_bits(0x3cf1600000000000), + f64::from_bits(0x3ff0706b29ddf71a), f64::from_bits(0x3d15240000000000), + f64::from_bits(0x3ff07bd42b72a82d), f64::from_bits(0xbce9a00000000000), + f64::from_bits(0x3ff0874518759bd0), f64::from_bits(0x3ce6400000000000), + f64::from_bits(0x3ff092bdf66607c8), f64::from_bits(0xbd00780000000000), + f64::from_bits(0x3ff09e3ecac6f383), f64::from_bits(0xbc98000000000000), + f64::from_bits(0x3ff0a9c79b1f3930), f64::from_bits(0x3cffa00000000000), + f64::from_bits(0x3ff0b5586cf988fc), f64::from_bits(0xbcfac80000000000), + f64::from_bits(0x3ff0c0f145e46c8a), f64::from_bits(0x3cd9c00000000000), + f64::from_bits(0x3ff0cc922b724816), f64::from_bits(0x3d05200000000000), + f64::from_bits(0x3ff0d83b23395dd8), f64::from_bits(0xbcfad00000000000), + f64::from_bits(0x3ff0e3ec32d3d1f3), f64::from_bits(0x3d1bac0000000000), + f64::from_bits(0x3ff0efa55fdfa9a6), f64::from_bits(0xbd04e80000000000), + f64::from_bits(0x3ff0fb66affed2f0), f64::from_bits(0xbd0d300000000000), + f64::from_bits(0x3ff1073028d7234b), f64::from_bits(0x3cf1500000000000), + f64::from_bits(0x3ff11301d0125b5b), f64::from_bits(0x3cec000000000000), + f64::from_bits(0x3ff11edbab5e2af9), f64::from_bits(0x3d16bc0000000000), + f64::from_bits(0x3ff12abdc06c31d5), f64::from_bits(0x3ce8400000000000), + f64::from_bits(0x3ff136a814f2047d), f64::from_bits(0xbd0ed00000000000), + f64::from_bits(0x3ff1429aaea92de9), f64::from_bits(0x3ce8e00000000000), + f64::from_bits(0x3ff14e95934f3138), f64::from_bits(0x3ceb400000000000), + f64::from_bits(0x3ff15a98c8a58e71), f64::from_bits(0x3d05300000000000), + f64::from_bits(0x3ff166a45471c3df), f64::from_bits(0x3d03380000000000), + f64::from_bits(0x3ff172b83c7d5211), f64::from_bits(0x3d28d40000000000), + f64::from_bits(0x3ff17ed48695bb9f), f64::from_bits(0xbd05d00000000000), + f64::from_bits(0x3ff18af9388c8d93), f64::from_bits(0xbd1c880000000000), + f64::from_bits(0x3ff1972658375d66), f64::from_bits(0x3d11f00000000000), + f64::from_bits(0x3ff1a35beb6fcba7), f64::from_bits(0x3d10480000000000), + f64::from_bits(0x3ff1af99f81387e3), f64::from_bits(0xbd47390000000000), + f64::from_bits(0x3ff1bbe084045d54), f64::from_bits(0x3d24e40000000000), + f64::from_bits(0x3ff1c82f95281c43), f64::from_bits(0xbd0a200000000000), + f64::from_bits(0x3ff1d4873168b9b2), f64::from_bits(0x3ce3800000000000), + f64::from_bits(0x3ff1e0e75eb44031), f64::from_bits(0x3ceac00000000000), + f64::from_bits(0x3ff1ed5022fcd938), f64::from_bits(0x3d01900000000000), + f64::from_bits(0x3ff1f9c18438cdf7), f64::from_bits(0xbd1b780000000000), + f64::from_bits(0x3ff2063b88628d8f), f64::from_bits(0x3d2d940000000000), + f64::from_bits(0x3ff212be3578a81e), f64::from_bits(0x3cd8000000000000), + f64::from_bits(0x3ff21f49917ddd41), f64::from_bits(0x3d2b340000000000), + f64::from_bits(0x3ff22bdda2791323), f64::from_bits(0x3d19f80000000000), + f64::from_bits(0x3ff2387a6e7561e7), f64::from_bits(0xbd19c80000000000), + f64::from_bits(0x3ff2451ffb821427), f64::from_bits(0x3d02300000000000), + f64::from_bits(0x3ff251ce4fb2a602), f64::from_bits(0xbd13480000000000), + f64::from_bits(0x3ff25e85711eceb0), f64::from_bits(0x3d12700000000000), + f64::from_bits(0x3ff26b4565e27d16), f64::from_bits(0x3d11d00000000000), + f64::from_bits(0x3ff2780e341de00f), f64::from_bits(0x3d31ee0000000000), + f64::from_bits(0x3ff284dfe1f5633e), f64::from_bits(0xbd14c00000000000), + f64::from_bits(0x3ff291ba7591bb30), f64::from_bits(0xbd13d80000000000), + f64::from_bits(0x3ff29e9df51fdf09), f64::from_bits(0x3d08b00000000000), + f64::from_bits(0x3ff2ab8a66d10e9b), f64::from_bits(0xbd227c0000000000), + f64::from_bits(0x3ff2b87fd0dada3a), f64::from_bits(0x3d2a340000000000), + f64::from_bits(0x3ff2c57e39771af9), f64::from_bits(0xbd10800000000000), + f64::from_bits(0x3ff2d285a6e402d9), f64::from_bits(0xbd0ed00000000000), + f64::from_bits(0x3ff2df961f641579), f64::from_bits(0xbcf4200000000000), + f64::from_bits(0x3ff2ecafa93e2ecf), f64::from_bits(0xbd24980000000000), + f64::from_bits(0x3ff2f9d24abd8822), f64::from_bits(0xbd16300000000000), + f64::from_bits(0x3ff306fe0a31b625), f64::from_bits(0xbd32360000000000), + f64::from_bits(0x3ff31432edeea50b), f64::from_bits(0xbd70df8000000000), + f64::from_bits(0x3ff32170fc4cd7b8), f64::from_bits(0xbd22480000000000), + f64::from_bits(0x3ff32eb83ba8e9a2), f64::from_bits(0xbd25980000000000), + f64::from_bits(0x3ff33c08b2641766), f64::from_bits(0x3d1ed00000000000), + f64::from_bits(0x3ff3496266e3fa27), f64::from_bits(0xbcdc000000000000), + f64::from_bits(0x3ff356c55f929f0f), f64::from_bits(0xbd30d80000000000), + f64::from_bits(0x3ff36431a2de88b9), f64::from_bits(0x3d22c80000000000), + f64::from_bits(0x3ff371a7373aaa39), f64::from_bits(0x3d20600000000000), + f64::from_bits(0x3ff37f26231e74fe), f64::from_bits(0xbd16600000000000), + f64::from_bits(0x3ff38cae6d05d838), f64::from_bits(0xbd0ae00000000000), + f64::from_bits(0x3ff39a401b713ec3), f64::from_bits(0xbd44720000000000), + f64::from_bits(0x3ff3a7db34e5a020), f64::from_bits(0x3d08200000000000), + f64::from_bits(0x3ff3b57fbfec6e95), f64::from_bits(0x3d3e800000000000), + f64::from_bits(0x3ff3c32dc313a8f2), f64::from_bits(0x3cef800000000000), + f64::from_bits(0x3ff3d0e544ede122), f64::from_bits(0xbd17a00000000000), + f64::from_bits(0x3ff3dea64c1234bb), f64::from_bits(0x3d26300000000000), + f64::from_bits(0x3ff3ec70df1c4ecc), f64::from_bits(0xbd48a60000000000), + f64::from_bits(0x3ff3fa4504ac7e8c), f64::from_bits(0xbd3cdc0000000000), + f64::from_bits(0x3ff40822c367a0bb), f64::from_bits(0x3d25b80000000000), + f64::from_bits(0x3ff4160a21f72e95), f64::from_bits(0x3d1ec00000000000), + f64::from_bits(0x3ff423fb27094646), f64::from_bits(0xbd13600000000000), + f64::from_bits(0x3ff431f5d950a920), f64::from_bits(0x3d23980000000000), + f64::from_bits(0x3ff43ffa3f84b9eb), f64::from_bits(0x3cfa000000000000), + f64::from_bits(0x3ff44e0860618919), f64::from_bits(0xbcf6c00000000000), + f64::from_bits(0x3ff45c2042a7d201), f64::from_bits(0xbd0bc00000000000), + f64::from_bits(0x3ff46a41ed1d0016), f64::from_bits(0xbd12800000000000), + f64::from_bits(0x3ff4786d668b3326), f64::from_bits(0x3d30e00000000000), + f64::from_bits(0x3ff486a2b5c13c00), f64::from_bits(0xbd2d400000000000), + f64::from_bits(0x3ff494e1e192af04), f64::from_bits(0x3d0c200000000000), + f64::from_bits(0x3ff4a32af0d7d372), f64::from_bits(0xbd1e500000000000), + f64::from_bits(0x3ff4b17dea6db801), f64::from_bits(0x3d07800000000000), + f64::from_bits(0x3ff4bfdad53629e1), f64::from_bits(0xbd13800000000000), + f64::from_bits(0x3ff4ce41b817c132), f64::from_bits(0x3d00800000000000), + f64::from_bits(0x3ff4dcb299fddddb), f64::from_bits(0x3d2c700000000000), + f64::from_bits(0x3ff4eb2d81d8ab96), f64::from_bits(0xbd1ce00000000000), + f64::from_bits(0x3ff4f9b2769d2d02), f64::from_bits(0x3d19200000000000), + f64::from_bits(0x3ff508417f4531c1), f64::from_bits(0xbd08c00000000000), + f64::from_bits(0x3ff516daa2cf662a), f64::from_bits(0xbcfa000000000000), + f64::from_bits(0x3ff5257de83f51ea), f64::from_bits(0x3d4a080000000000), + f64::from_bits(0x3ff5342b569d4eda), f64::from_bits(0xbd26d80000000000), + f64::from_bits(0x3ff542e2f4f6ac1a), f64::from_bits(0xbd32440000000000), + f64::from_bits(0x3ff551a4ca5d94db), f64::from_bits(0x3d483c0000000000), + f64::from_bits(0x3ff56070dde9116b), f64::from_bits(0x3d24b00000000000), + f64::from_bits(0x3ff56f4736b529de), f64::from_bits(0x3d415a0000000000), + f64::from_bits(0x3ff57e27dbe2c40e), f64::from_bits(0xbd29e00000000000), + f64::from_bits(0x3ff58d12d497c76f), f64::from_bits(0xbd23080000000000), + f64::from_bits(0x3ff59c0827ff0b4c), f64::from_bits(0x3d4dec0000000000), + f64::from_bits(0x3ff5ab07dd485427), f64::from_bits(0xbcc4000000000000), + f64::from_bits(0x3ff5ba11fba87af4), f64::from_bits(0x3d30080000000000), + f64::from_bits(0x3ff5c9268a59460b), f64::from_bits(0xbd26c80000000000), + f64::from_bits(0x3ff5d84590998e3f), f64::from_bits(0x3d469a0000000000), + f64::from_bits(0x3ff5e76f15ad20e1), f64::from_bits(0xbd1b400000000000), + f64::from_bits(0x3ff5f6a320dcebca), f64::from_bits(0x3d17700000000000), + f64::from_bits(0x3ff605e1b976dcb8), f64::from_bits(0x3d26f80000000000), + f64::from_bits(0x3ff6152ae6cdf715), f64::from_bits(0x3d01000000000000), + f64::from_bits(0x3ff6247eb03a5531), f64::from_bits(0xbd15d00000000000), + f64::from_bits(0x3ff633dd1d1929b5), f64::from_bits(0xbd12d00000000000), + f64::from_bits(0x3ff6434634ccc313), f64::from_bits(0xbcea800000000000), + f64::from_bits(0x3ff652b9febc8efa), f64::from_bits(0xbd28600000000000), + f64::from_bits(0x3ff6623882553397), f64::from_bits(0x3d71fe0000000000), + f64::from_bits(0x3ff671c1c708328e), f64::from_bits(0xbd37200000000000), + f64::from_bits(0x3ff68155d44ca97e), f64::from_bits(0x3ce6800000000000), + f64::from_bits(0x3ff690f4b19e9471), f64::from_bits(0xbd29780000000000), + ]; + + // double_t r, t, z; + // uint32_t ix, i0; + // union {double f; uint64_t i;} u = {x}; + // union {uint32_t u; int32_t i;} k; + let x1p1023 = f64::from_bits(0x7fe0000000000000); + let x1p52 = f64::from_bits(0x4330000000000000); + let _0x1p_149 = f64::from_bits(0xb6a0000000000000); + + /* Filter out exceptional cases. */ + let ui = f64::to_bits(x); + let ix = ui >> 32 & 0x7fffffff; + if ix >= 0x408ff000 { + /* |x| >= 1022 or nan */ + if ix >= 0x40900000 && ui >> 63 == 0 { + /* x >= 1024 or nan */ + /* overflow */ + x *= x1p1023; + return x; + } + if ix >= 0x7ff00000 { + /* -inf or -nan */ + return -1.0 / x; + } + if ui >> 63 != 0 { + /* x <= -1022 */ + /* underflow */ + if x <= -1075.0 || x - x1p52 + x1p52 != x { + force_eval!((_0x1p_149 / x) as f32); + } + if x <= -1075.0 { + return 0.0; + } + } + } else if ix < 0x3c900000 { + /* |x| < 0x1p-54 */ + return 1.0 + x; + } + + /* Reduce x, computing z, i0, and k. */ + let ui = f64::to_bits(x + redux); + let mut i0 = ui as u32; + i0 += TBLSIZE as u32 / 2; + let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32; + let ki = ku as i32 / TBLSIZE as i32; + i0 %= TBLSIZE as u32; + let uf = f64::from_bits(ui) - redux; + let mut z = x - uf; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + let t = tbl[2 * i0 as usize]; /* exp2t[i0] */ + z -= tbl[2 * i0 as usize + 1]; /* eps[i0] */ + let r = t + t * z * (p1 + z * (p2 + z * (p3 + z * (p4 + z * p5)))); + + scalbn(r, ki) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 5540ba83825..a15c4e60bdf 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -12,6 +12,7 @@ mod ceil; mod ceilf; mod cosf; mod exp; +mod exp2; mod exp2f; mod expf; mod fabs; @@ -49,6 +50,7 @@ pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; pub use self::exp::exp; +pub use self::exp2::exp2; pub use self::exp2f::exp2f; pub use self::expf::expf; pub use self::fabs::fabs; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index dfe912a508b..e33f120a712 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -704,7 +704,7 @@ f64_f64! { // cos, // cosh, exp, - // exp2, + exp2, // expm1, floor, log, -- cgit 1.4.1-3-g733a5 From c3d29246bbc6c6ac1017c4992d14ffc64146a4d0 Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 15:04:16 -0400 Subject: DRY up the exp2 and exp2f data tables --- library/compiler-builtins/libm/src/math/exp2.rs | 526 +++++++++++------------ library/compiler-builtins/libm/src/math/exp2f.rs | 40 +- 2 files changed, 283 insertions(+), 283 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index c5bd3608a43..61bfd1015d2 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -28,6 +28,267 @@ use super::scalbn::scalbn; const TBLSIZE: usize = 256; +#[cfg_attr(rustfmt, rustfmt_skip)] +static TBL: [u64; TBLSIZE * 2] = [ + // exp2(z + eps) eps + 0x3fe6a09e667f3d5d, 0x3d39880000000000, + 0x3fe6b052fa751744, 0x3cd8000000000000, + 0x3fe6c012750bd9fe, 0xbd28780000000000, + 0x3fe6cfdcddd476bf, 0x3d1ec00000000000, + 0x3fe6dfb23c651a29, 0xbcd8000000000000, + 0x3fe6ef9298593ae3, 0xbcbc000000000000, + 0x3fe6ff7df9519386, 0xbd2fd80000000000, + 0x3fe70f7466f42da3, 0xbd2c880000000000, + 0x3fe71f75e8ec5fc3, 0x3d13c00000000000, + 0x3fe72f8286eacf05, 0xbd38300000000000, + 0x3fe73f9a48a58152, 0xbd00c00000000000, + 0x3fe74fbd35d7ccfc, 0x3d2f880000000000, + 0x3fe75feb564267f1, 0x3d03e00000000000, + 0x3fe77024b1ab6d48, 0xbd27d00000000000, + 0x3fe780694fde5d38, 0xbcdd000000000000, + 0x3fe790b938ac1d00, 0x3ce3000000000000, + 0x3fe7a11473eb0178, 0xbced000000000000, + 0x3fe7b17b0976d060, 0x3d20400000000000, + 0x3fe7c1ed0130c133, 0x3ca0000000000000, + 0x3fe7d26a62ff8636, 0xbd26900000000000, + 0x3fe7e2f336cf4e3b, 0xbd02e00000000000, + 0x3fe7f3878491c3e8, 0xbd24580000000000, + 0x3fe80427543e1b4e, 0x3d33000000000000, + 0x3fe814d2add1071a, 0x3d0f000000000000, + 0x3fe82589994ccd7e, 0xbd21c00000000000, + 0x3fe8364c1eb942d0, 0x3d29d00000000000, + 0x3fe8471a4623cab5, 0x3d47100000000000, + 0x3fe857f4179f5bbc, 0x3d22600000000000, + 0x3fe868d99b4491af, 0xbd32c40000000000, + 0x3fe879cad931a395, 0xbd23000000000000, + 0x3fe88ac7d98a65b8, 0xbd2a800000000000, + 0x3fe89bd0a4785800, 0xbced000000000000, + 0x3fe8ace5422aa223, 0x3d33280000000000, + 0x3fe8be05bad619fa, 0x3d42b40000000000, + 0x3fe8cf3216b54383, 0xbd2ed00000000000, + 0x3fe8e06a5e08664c, 0xbd20500000000000, + 0x3fe8f1ae99157807, 0x3d28280000000000, + 0x3fe902fed0282c0e, 0xbd1cb00000000000, + 0x3fe9145b0b91ff96, 0xbd05e00000000000, + 0x3fe925c353aa2ff9, 0x3cf5400000000000, + 0x3fe93737b0cdc64a, 0x3d17200000000000, + 0x3fe948b82b5f98ae, 0xbd09000000000000, + 0x3fe95a44cbc852cb, 0x3d25680000000000, + 0x3fe96bdd9a766f21, 0xbd36d00000000000, + 0x3fe97d829fde4e2a, 0xbd01000000000000, + 0x3fe98f33e47a23a3, 0x3d2d000000000000, + 0x3fe9a0f170ca0604, 0xbd38a40000000000, + 0x3fe9b2bb4d53ff89, 0x3d355c0000000000, + 0x3fe9c49182a3f15b, 0x3d26b80000000000, + 0x3fe9d674194bb8c5, 0xbcec000000000000, + 0x3fe9e86319e3238e, 0x3d17d00000000000, + 0x3fe9fa5e8d07f302, 0x3d16400000000000, + 0x3fea0c667b5de54d, 0xbcf5000000000000, + 0x3fea1e7aed8eb8f6, 0x3d09e00000000000, + 0x3fea309bec4a2e27, 0x3d2ad80000000000, + 0x3fea42c980460a5d, 0xbd1af00000000000, + 0x3fea5503b23e259b, 0x3d0b600000000000, + 0x3fea674a8af46213, 0x3d38880000000000, + 0x3fea799e1330b3a7, 0x3d11200000000000, + 0x3fea8bfe53c12e8d, 0x3d06c00000000000, + 0x3fea9e6b5579fcd2, 0xbd29b80000000000, + 0x3feab0e521356fb8, 0x3d2b700000000000, + 0x3feac36bbfd3f381, 0x3cd9000000000000, + 0x3fead5ff3a3c2780, 0x3ce4000000000000, + 0x3feae89f995ad2a3, 0xbd2c900000000000, + 0x3feafb4ce622f367, 0x3d16500000000000, + 0x3feb0e07298db790, 0x3d2fd40000000000, + 0x3feb20ce6c9a89a9, 0x3d12700000000000, + 0x3feb33a2b84f1a4b, 0x3d4d470000000000, + 0x3feb468415b747e7, 0xbd38380000000000, + 0x3feb59728de5593a, 0x3c98000000000000, + 0x3feb6c6e29f1c56a, 0x3d0ad00000000000, + 0x3feb7f76f2fb5e50, 0x3cde800000000000, + 0x3feb928cf22749b2, 0xbd04c00000000000, + 0x3feba5b030a10603, 0xbd0d700000000000, + 0x3febb8e0b79a6f66, 0x3d0d900000000000, + 0x3febcc1e904bc1ff, 0x3d02a00000000000, + 0x3febdf69c3f3a16f, 0xbd1f780000000000, + 0x3febf2c25bd71db8, 0xbd10a00000000000, + 0x3fec06286141b2e9, 0xbd11400000000000, + 0x3fec199bdd8552e0, 0x3d0be00000000000, + 0x3fec2d1cd9fa64ee, 0xbd09400000000000, + 0x3fec40ab5fffd02f, 0xbd0ed00000000000, + 0x3fec544778fafd15, 0x3d39660000000000, + 0x3fec67f12e57d0cb, 0xbd1a100000000000, + 0x3fec7ba88988c1b6, 0xbd58458000000000, + 0x3fec8f6d9406e733, 0xbd1a480000000000, + 0x3feca3405751c4df, 0x3ccb000000000000, + 0x3fecb720dcef9094, 0x3d01400000000000, + 0x3feccb0f2e6d1689, 0x3cf0200000000000, + 0x3fecdf0b555dc412, 0x3cf3600000000000, + 0x3fecf3155b5bab3b, 0xbd06900000000000, + 0x3fed072d4a0789bc, 0x3d09a00000000000, + 0x3fed1b532b08c8fa, 0xbd15e00000000000, + 0x3fed2f87080d8a85, 0x3d1d280000000000, + 0x3fed43c8eacaa203, 0x3d01a00000000000, + 0x3fed5818dcfba491, 0x3cdf000000000000, + 0x3fed6c76e862e6a1, 0xbd03a00000000000, + 0x3fed80e316c9834e, 0xbd0cd80000000000, + 0x3fed955d71ff6090, 0x3cf4c00000000000, + 0x3feda9e603db32ae, 0x3cff900000000000, + 0x3fedbe7cd63a8325, 0x3ce9800000000000, + 0x3fedd321f301b445, 0xbcf5200000000000, + 0x3fede7d5641c05bf, 0xbd1d700000000000, + 0x3fedfc97337b9aec, 0xbd16140000000000, + 0x3fee11676b197d5e, 0x3d0b480000000000, + 0x3fee264614f5a3e7, 0x3d40ce0000000000, + 0x3fee3b333b16ee5c, 0x3d0c680000000000, + 0x3fee502ee78b3fb4, 0xbd09300000000000, + 0x3fee653924676d68, 0xbce5000000000000, + 0x3fee7a51fbc74c44, 0xbd07f80000000000, + 0x3fee8f7977cdb726, 0xbcf3700000000000, + 0x3feea4afa2a490e8, 0x3ce5d00000000000, + 0x3feeb9f4867ccae4, 0x3d161a0000000000, + 0x3feecf482d8e680d, 0x3cf5500000000000, + 0x3feee4aaa2188514, 0x3cc6400000000000, + 0x3feefa1bee615a13, 0xbcee800000000000, + 0x3fef0f9c1cb64106, 0xbcfa880000000000, + 0x3fef252b376bb963, 0xbd2c900000000000, + 0x3fef3ac948dd7275, 0x3caa000000000000, + 0x3fef50765b6e4524, 0xbcf4f00000000000, + 0x3fef6632798844fd, 0x3cca800000000000, + 0x3fef7bfdad9cbe38, 0x3cfabc0000000000, + 0x3fef91d802243c82, 0xbcd4600000000000, + 0x3fefa7c1819e908e, 0xbd0b0c0000000000, + 0x3fefbdba3692d511, 0xbcc0e00000000000, + 0x3fefd3c22b8f7194, 0xbd10de8000000000, + 0x3fefe9d96b2a23ee, 0x3cee430000000000, + 0x3ff0000000000000, 0x0, + 0x3ff00b1afa5abcbe, 0xbcb3400000000000, + 0x3ff0163da9fb3303, 0xbd12170000000000, + 0x3ff02168143b0282, 0x3cba400000000000, + 0x3ff02c9a3e77806c, 0x3cef980000000000, + 0x3ff037d42e11bbca, 0xbcc7400000000000, + 0x3ff04315e86e7f89, 0x3cd8300000000000, + 0x3ff04e5f72f65467, 0xbd1a3f0000000000, + 0x3ff059b0d315855a, 0xbd02840000000000, + 0x3ff0650a0e3c1f95, 0x3cf1600000000000, + 0x3ff0706b29ddf71a, 0x3d15240000000000, + 0x3ff07bd42b72a82d, 0xbce9a00000000000, + 0x3ff0874518759bd0, 0x3ce6400000000000, + 0x3ff092bdf66607c8, 0xbd00780000000000, + 0x3ff09e3ecac6f383, 0xbc98000000000000, + 0x3ff0a9c79b1f3930, 0x3cffa00000000000, + 0x3ff0b5586cf988fc, 0xbcfac80000000000, + 0x3ff0c0f145e46c8a, 0x3cd9c00000000000, + 0x3ff0cc922b724816, 0x3d05200000000000, + 0x3ff0d83b23395dd8, 0xbcfad00000000000, + 0x3ff0e3ec32d3d1f3, 0x3d1bac0000000000, + 0x3ff0efa55fdfa9a6, 0xbd04e80000000000, + 0x3ff0fb66affed2f0, 0xbd0d300000000000, + 0x3ff1073028d7234b, 0x3cf1500000000000, + 0x3ff11301d0125b5b, 0x3cec000000000000, + 0x3ff11edbab5e2af9, 0x3d16bc0000000000, + 0x3ff12abdc06c31d5, 0x3ce8400000000000, + 0x3ff136a814f2047d, 0xbd0ed00000000000, + 0x3ff1429aaea92de9, 0x3ce8e00000000000, + 0x3ff14e95934f3138, 0x3ceb400000000000, + 0x3ff15a98c8a58e71, 0x3d05300000000000, + 0x3ff166a45471c3df, 0x3d03380000000000, + 0x3ff172b83c7d5211, 0x3d28d40000000000, + 0x3ff17ed48695bb9f, 0xbd05d00000000000, + 0x3ff18af9388c8d93, 0xbd1c880000000000, + 0x3ff1972658375d66, 0x3d11f00000000000, + 0x3ff1a35beb6fcba7, 0x3d10480000000000, + 0x3ff1af99f81387e3, 0xbd47390000000000, + 0x3ff1bbe084045d54, 0x3d24e40000000000, + 0x3ff1c82f95281c43, 0xbd0a200000000000, + 0x3ff1d4873168b9b2, 0x3ce3800000000000, + 0x3ff1e0e75eb44031, 0x3ceac00000000000, + 0x3ff1ed5022fcd938, 0x3d01900000000000, + 0x3ff1f9c18438cdf7, 0xbd1b780000000000, + 0x3ff2063b88628d8f, 0x3d2d940000000000, + 0x3ff212be3578a81e, 0x3cd8000000000000, + 0x3ff21f49917ddd41, 0x3d2b340000000000, + 0x3ff22bdda2791323, 0x3d19f80000000000, + 0x3ff2387a6e7561e7, 0xbd19c80000000000, + 0x3ff2451ffb821427, 0x3d02300000000000, + 0x3ff251ce4fb2a602, 0xbd13480000000000, + 0x3ff25e85711eceb0, 0x3d12700000000000, + 0x3ff26b4565e27d16, 0x3d11d00000000000, + 0x3ff2780e341de00f, 0x3d31ee0000000000, + 0x3ff284dfe1f5633e, 0xbd14c00000000000, + 0x3ff291ba7591bb30, 0xbd13d80000000000, + 0x3ff29e9df51fdf09, 0x3d08b00000000000, + 0x3ff2ab8a66d10e9b, 0xbd227c0000000000, + 0x3ff2b87fd0dada3a, 0x3d2a340000000000, + 0x3ff2c57e39771af9, 0xbd10800000000000, + 0x3ff2d285a6e402d9, 0xbd0ed00000000000, + 0x3ff2df961f641579, 0xbcf4200000000000, + 0x3ff2ecafa93e2ecf, 0xbd24980000000000, + 0x3ff2f9d24abd8822, 0xbd16300000000000, + 0x3ff306fe0a31b625, 0xbd32360000000000, + 0x3ff31432edeea50b, 0xbd70df8000000000, + 0x3ff32170fc4cd7b8, 0xbd22480000000000, + 0x3ff32eb83ba8e9a2, 0xbd25980000000000, + 0x3ff33c08b2641766, 0x3d1ed00000000000, + 0x3ff3496266e3fa27, 0xbcdc000000000000, + 0x3ff356c55f929f0f, 0xbd30d80000000000, + 0x3ff36431a2de88b9, 0x3d22c80000000000, + 0x3ff371a7373aaa39, 0x3d20600000000000, + 0x3ff37f26231e74fe, 0xbd16600000000000, + 0x3ff38cae6d05d838, 0xbd0ae00000000000, + 0x3ff39a401b713ec3, 0xbd44720000000000, + 0x3ff3a7db34e5a020, 0x3d08200000000000, + 0x3ff3b57fbfec6e95, 0x3d3e800000000000, + 0x3ff3c32dc313a8f2, 0x3cef800000000000, + 0x3ff3d0e544ede122, 0xbd17a00000000000, + 0x3ff3dea64c1234bb, 0x3d26300000000000, + 0x3ff3ec70df1c4ecc, 0xbd48a60000000000, + 0x3ff3fa4504ac7e8c, 0xbd3cdc0000000000, + 0x3ff40822c367a0bb, 0x3d25b80000000000, + 0x3ff4160a21f72e95, 0x3d1ec00000000000, + 0x3ff423fb27094646, 0xbd13600000000000, + 0x3ff431f5d950a920, 0x3d23980000000000, + 0x3ff43ffa3f84b9eb, 0x3cfa000000000000, + 0x3ff44e0860618919, 0xbcf6c00000000000, + 0x3ff45c2042a7d201, 0xbd0bc00000000000, + 0x3ff46a41ed1d0016, 0xbd12800000000000, + 0x3ff4786d668b3326, 0x3d30e00000000000, + 0x3ff486a2b5c13c00, 0xbd2d400000000000, + 0x3ff494e1e192af04, 0x3d0c200000000000, + 0x3ff4a32af0d7d372, 0xbd1e500000000000, + 0x3ff4b17dea6db801, 0x3d07800000000000, + 0x3ff4bfdad53629e1, 0xbd13800000000000, + 0x3ff4ce41b817c132, 0x3d00800000000000, + 0x3ff4dcb299fddddb, 0x3d2c700000000000, + 0x3ff4eb2d81d8ab96, 0xbd1ce00000000000, + 0x3ff4f9b2769d2d02, 0x3d19200000000000, + 0x3ff508417f4531c1, 0xbd08c00000000000, + 0x3ff516daa2cf662a, 0xbcfa000000000000, + 0x3ff5257de83f51ea, 0x3d4a080000000000, + 0x3ff5342b569d4eda, 0xbd26d80000000000, + 0x3ff542e2f4f6ac1a, 0xbd32440000000000, + 0x3ff551a4ca5d94db, 0x3d483c0000000000, + 0x3ff56070dde9116b, 0x3d24b00000000000, + 0x3ff56f4736b529de, 0x3d415a0000000000, + 0x3ff57e27dbe2c40e, 0xbd29e00000000000, + 0x3ff58d12d497c76f, 0xbd23080000000000, + 0x3ff59c0827ff0b4c, 0x3d4dec0000000000, + 0x3ff5ab07dd485427, 0xbcc4000000000000, + 0x3ff5ba11fba87af4, 0x3d30080000000000, + 0x3ff5c9268a59460b, 0xbd26c80000000000, + 0x3ff5d84590998e3f, 0x3d469a0000000000, + 0x3ff5e76f15ad20e1, 0xbd1b400000000000, + 0x3ff5f6a320dcebca, 0x3d17700000000000, + 0x3ff605e1b976dcb8, 0x3d26f80000000000, + 0x3ff6152ae6cdf715, 0x3d01000000000000, + 0x3ff6247eb03a5531, 0xbd15d00000000000, + 0x3ff633dd1d1929b5, 0xbd12d00000000000, + 0x3ff6434634ccc313, 0xbcea800000000000, + 0x3ff652b9febc8efa, 0xbd28600000000000, + 0x3ff6623882553397, 0x3d71fe0000000000, + 0x3ff671c1c708328e, 0xbd37200000000000, + 0x3ff68155d44ca97e, 0x3ce6800000000000, + 0x3ff690f4b19e9471, 0xbd29780000000000, +]; + // exp2(x): compute the base 2 exponential of x // // Accuracy: Peak error < 0.503 ulp for normalized results. @@ -65,267 +326,6 @@ pub fn exp2(mut x: f64) -> f64 { let p4 = f64::from_bits(0x3f83b2ab88f70400); let p5 = f64::from_bits(0x3f55d88003875c74); - #[cfg_attr(rustfmt, rustfmt_skip)] - let tbl = [ - // exp2(z + eps) eps - f64::from_bits(0x3fe6a09e667f3d5d), f64::from_bits(0x3d39880000000000), - f64::from_bits(0x3fe6b052fa751744), f64::from_bits(0x3cd8000000000000), - f64::from_bits(0x3fe6c012750bd9fe), f64::from_bits(0xbd28780000000000), - f64::from_bits(0x3fe6cfdcddd476bf), f64::from_bits(0x3d1ec00000000000), - f64::from_bits(0x3fe6dfb23c651a29), f64::from_bits(0xbcd8000000000000), - f64::from_bits(0x3fe6ef9298593ae3), f64::from_bits(0xbcbc000000000000), - f64::from_bits(0x3fe6ff7df9519386), f64::from_bits(0xbd2fd80000000000), - f64::from_bits(0x3fe70f7466f42da3), f64::from_bits(0xbd2c880000000000), - f64::from_bits(0x3fe71f75e8ec5fc3), f64::from_bits(0x3d13c00000000000), - f64::from_bits(0x3fe72f8286eacf05), f64::from_bits(0xbd38300000000000), - f64::from_bits(0x3fe73f9a48a58152), f64::from_bits(0xbd00c00000000000), - f64::from_bits(0x3fe74fbd35d7ccfc), f64::from_bits(0x3d2f880000000000), - f64::from_bits(0x3fe75feb564267f1), f64::from_bits(0x3d03e00000000000), - f64::from_bits(0x3fe77024b1ab6d48), f64::from_bits(0xbd27d00000000000), - f64::from_bits(0x3fe780694fde5d38), f64::from_bits(0xbcdd000000000000), - f64::from_bits(0x3fe790b938ac1d00), f64::from_bits(0x3ce3000000000000), - f64::from_bits(0x3fe7a11473eb0178), f64::from_bits(0xbced000000000000), - f64::from_bits(0x3fe7b17b0976d060), f64::from_bits(0x3d20400000000000), - f64::from_bits(0x3fe7c1ed0130c133), f64::from_bits(0x3ca0000000000000), - f64::from_bits(0x3fe7d26a62ff8636), f64::from_bits(0xbd26900000000000), - f64::from_bits(0x3fe7e2f336cf4e3b), f64::from_bits(0xbd02e00000000000), - f64::from_bits(0x3fe7f3878491c3e8), f64::from_bits(0xbd24580000000000), - f64::from_bits(0x3fe80427543e1b4e), f64::from_bits(0x3d33000000000000), - f64::from_bits(0x3fe814d2add1071a), f64::from_bits(0x3d0f000000000000), - f64::from_bits(0x3fe82589994ccd7e), f64::from_bits(0xbd21c00000000000), - f64::from_bits(0x3fe8364c1eb942d0), f64::from_bits(0x3d29d00000000000), - f64::from_bits(0x3fe8471a4623cab5), f64::from_bits(0x3d47100000000000), - f64::from_bits(0x3fe857f4179f5bbc), f64::from_bits(0x3d22600000000000), - f64::from_bits(0x3fe868d99b4491af), f64::from_bits(0xbd32c40000000000), - f64::from_bits(0x3fe879cad931a395), f64::from_bits(0xbd23000000000000), - f64::from_bits(0x3fe88ac7d98a65b8), f64::from_bits(0xbd2a800000000000), - f64::from_bits(0x3fe89bd0a4785800), f64::from_bits(0xbced000000000000), - f64::from_bits(0x3fe8ace5422aa223), f64::from_bits(0x3d33280000000000), - f64::from_bits(0x3fe8be05bad619fa), f64::from_bits(0x3d42b40000000000), - f64::from_bits(0x3fe8cf3216b54383), f64::from_bits(0xbd2ed00000000000), - f64::from_bits(0x3fe8e06a5e08664c), f64::from_bits(0xbd20500000000000), - f64::from_bits(0x3fe8f1ae99157807), f64::from_bits(0x3d28280000000000), - f64::from_bits(0x3fe902fed0282c0e), f64::from_bits(0xbd1cb00000000000), - f64::from_bits(0x3fe9145b0b91ff96), f64::from_bits(0xbd05e00000000000), - f64::from_bits(0x3fe925c353aa2ff9), f64::from_bits(0x3cf5400000000000), - f64::from_bits(0x3fe93737b0cdc64a), f64::from_bits(0x3d17200000000000), - f64::from_bits(0x3fe948b82b5f98ae), f64::from_bits(0xbd09000000000000), - f64::from_bits(0x3fe95a44cbc852cb), f64::from_bits(0x3d25680000000000), - f64::from_bits(0x3fe96bdd9a766f21), f64::from_bits(0xbd36d00000000000), - f64::from_bits(0x3fe97d829fde4e2a), f64::from_bits(0xbd01000000000000), - f64::from_bits(0x3fe98f33e47a23a3), f64::from_bits(0x3d2d000000000000), - f64::from_bits(0x3fe9a0f170ca0604), f64::from_bits(0xbd38a40000000000), - f64::from_bits(0x3fe9b2bb4d53ff89), f64::from_bits(0x3d355c0000000000), - f64::from_bits(0x3fe9c49182a3f15b), f64::from_bits(0x3d26b80000000000), - f64::from_bits(0x3fe9d674194bb8c5), f64::from_bits(0xbcec000000000000), - f64::from_bits(0x3fe9e86319e3238e), f64::from_bits(0x3d17d00000000000), - f64::from_bits(0x3fe9fa5e8d07f302), f64::from_bits(0x3d16400000000000), - f64::from_bits(0x3fea0c667b5de54d), f64::from_bits(0xbcf5000000000000), - f64::from_bits(0x3fea1e7aed8eb8f6), f64::from_bits(0x3d09e00000000000), - f64::from_bits(0x3fea309bec4a2e27), f64::from_bits(0x3d2ad80000000000), - f64::from_bits(0x3fea42c980460a5d), f64::from_bits(0xbd1af00000000000), - f64::from_bits(0x3fea5503b23e259b), f64::from_bits(0x3d0b600000000000), - f64::from_bits(0x3fea674a8af46213), f64::from_bits(0x3d38880000000000), - f64::from_bits(0x3fea799e1330b3a7), f64::from_bits(0x3d11200000000000), - f64::from_bits(0x3fea8bfe53c12e8d), f64::from_bits(0x3d06c00000000000), - f64::from_bits(0x3fea9e6b5579fcd2), f64::from_bits(0xbd29b80000000000), - f64::from_bits(0x3feab0e521356fb8), f64::from_bits(0x3d2b700000000000), - f64::from_bits(0x3feac36bbfd3f381), f64::from_bits(0x3cd9000000000000), - f64::from_bits(0x3fead5ff3a3c2780), f64::from_bits(0x3ce4000000000000), - f64::from_bits(0x3feae89f995ad2a3), f64::from_bits(0xbd2c900000000000), - f64::from_bits(0x3feafb4ce622f367), f64::from_bits(0x3d16500000000000), - f64::from_bits(0x3feb0e07298db790), f64::from_bits(0x3d2fd40000000000), - f64::from_bits(0x3feb20ce6c9a89a9), f64::from_bits(0x3d12700000000000), - f64::from_bits(0x3feb33a2b84f1a4b), f64::from_bits(0x3d4d470000000000), - f64::from_bits(0x3feb468415b747e7), f64::from_bits(0xbd38380000000000), - f64::from_bits(0x3feb59728de5593a), f64::from_bits(0x3c98000000000000), - f64::from_bits(0x3feb6c6e29f1c56a), f64::from_bits(0x3d0ad00000000000), - f64::from_bits(0x3feb7f76f2fb5e50), f64::from_bits(0x3cde800000000000), - f64::from_bits(0x3feb928cf22749b2), f64::from_bits(0xbd04c00000000000), - f64::from_bits(0x3feba5b030a10603), f64::from_bits(0xbd0d700000000000), - f64::from_bits(0x3febb8e0b79a6f66), f64::from_bits(0x3d0d900000000000), - f64::from_bits(0x3febcc1e904bc1ff), f64::from_bits(0x3d02a00000000000), - f64::from_bits(0x3febdf69c3f3a16f), f64::from_bits(0xbd1f780000000000), - f64::from_bits(0x3febf2c25bd71db8), f64::from_bits(0xbd10a00000000000), - f64::from_bits(0x3fec06286141b2e9), f64::from_bits(0xbd11400000000000), - f64::from_bits(0x3fec199bdd8552e0), f64::from_bits(0x3d0be00000000000), - f64::from_bits(0x3fec2d1cd9fa64ee), f64::from_bits(0xbd09400000000000), - f64::from_bits(0x3fec40ab5fffd02f), f64::from_bits(0xbd0ed00000000000), - f64::from_bits(0x3fec544778fafd15), f64::from_bits(0x3d39660000000000), - f64::from_bits(0x3fec67f12e57d0cb), f64::from_bits(0xbd1a100000000000), - f64::from_bits(0x3fec7ba88988c1b6), f64::from_bits(0xbd58458000000000), - f64::from_bits(0x3fec8f6d9406e733), f64::from_bits(0xbd1a480000000000), - f64::from_bits(0x3feca3405751c4df), f64::from_bits(0x3ccb000000000000), - f64::from_bits(0x3fecb720dcef9094), f64::from_bits(0x3d01400000000000), - f64::from_bits(0x3feccb0f2e6d1689), f64::from_bits(0x3cf0200000000000), - f64::from_bits(0x3fecdf0b555dc412), f64::from_bits(0x3cf3600000000000), - f64::from_bits(0x3fecf3155b5bab3b), f64::from_bits(0xbd06900000000000), - f64::from_bits(0x3fed072d4a0789bc), f64::from_bits(0x3d09a00000000000), - f64::from_bits(0x3fed1b532b08c8fa), f64::from_bits(0xbd15e00000000000), - f64::from_bits(0x3fed2f87080d8a85), f64::from_bits(0x3d1d280000000000), - f64::from_bits(0x3fed43c8eacaa203), f64::from_bits(0x3d01a00000000000), - f64::from_bits(0x3fed5818dcfba491), f64::from_bits(0x3cdf000000000000), - f64::from_bits(0x3fed6c76e862e6a1), f64::from_bits(0xbd03a00000000000), - f64::from_bits(0x3fed80e316c9834e), f64::from_bits(0xbd0cd80000000000), - f64::from_bits(0x3fed955d71ff6090), f64::from_bits(0x3cf4c00000000000), - f64::from_bits(0x3feda9e603db32ae), f64::from_bits(0x3cff900000000000), - f64::from_bits(0x3fedbe7cd63a8325), f64::from_bits(0x3ce9800000000000), - f64::from_bits(0x3fedd321f301b445), f64::from_bits(0xbcf5200000000000), - f64::from_bits(0x3fede7d5641c05bf), f64::from_bits(0xbd1d700000000000), - f64::from_bits(0x3fedfc97337b9aec), f64::from_bits(0xbd16140000000000), - f64::from_bits(0x3fee11676b197d5e), f64::from_bits(0x3d0b480000000000), - f64::from_bits(0x3fee264614f5a3e7), f64::from_bits(0x3d40ce0000000000), - f64::from_bits(0x3fee3b333b16ee5c), f64::from_bits(0x3d0c680000000000), - f64::from_bits(0x3fee502ee78b3fb4), f64::from_bits(0xbd09300000000000), - f64::from_bits(0x3fee653924676d68), f64::from_bits(0xbce5000000000000), - f64::from_bits(0x3fee7a51fbc74c44), f64::from_bits(0xbd07f80000000000), - f64::from_bits(0x3fee8f7977cdb726), f64::from_bits(0xbcf3700000000000), - f64::from_bits(0x3feea4afa2a490e8), f64::from_bits(0x3ce5d00000000000), - f64::from_bits(0x3feeb9f4867ccae4), f64::from_bits(0x3d161a0000000000), - f64::from_bits(0x3feecf482d8e680d), f64::from_bits(0x3cf5500000000000), - f64::from_bits(0x3feee4aaa2188514), f64::from_bits(0x3cc6400000000000), - f64::from_bits(0x3feefa1bee615a13), f64::from_bits(0xbcee800000000000), - f64::from_bits(0x3fef0f9c1cb64106), f64::from_bits(0xbcfa880000000000), - f64::from_bits(0x3fef252b376bb963), f64::from_bits(0xbd2c900000000000), - f64::from_bits(0x3fef3ac948dd7275), f64::from_bits(0x3caa000000000000), - f64::from_bits(0x3fef50765b6e4524), f64::from_bits(0xbcf4f00000000000), - f64::from_bits(0x3fef6632798844fd), f64::from_bits(0x3cca800000000000), - f64::from_bits(0x3fef7bfdad9cbe38), f64::from_bits(0x3cfabc0000000000), - f64::from_bits(0x3fef91d802243c82), f64::from_bits(0xbcd4600000000000), - f64::from_bits(0x3fefa7c1819e908e), f64::from_bits(0xbd0b0c0000000000), - f64::from_bits(0x3fefbdba3692d511), f64::from_bits(0xbcc0e00000000000), - f64::from_bits(0x3fefd3c22b8f7194), f64::from_bits(0xbd10de8000000000), - f64::from_bits(0x3fefe9d96b2a23ee), f64::from_bits(0x3cee430000000000), - f64::from_bits(0x3ff0000000000000), f64::from_bits(0x0), - f64::from_bits(0x3ff00b1afa5abcbe), f64::from_bits(0xbcb3400000000000), - f64::from_bits(0x3ff0163da9fb3303), f64::from_bits(0xbd12170000000000), - f64::from_bits(0x3ff02168143b0282), f64::from_bits(0x3cba400000000000), - f64::from_bits(0x3ff02c9a3e77806c), f64::from_bits(0x3cef980000000000), - f64::from_bits(0x3ff037d42e11bbca), f64::from_bits(0xbcc7400000000000), - f64::from_bits(0x3ff04315e86e7f89), f64::from_bits(0x3cd8300000000000), - f64::from_bits(0x3ff04e5f72f65467), f64::from_bits(0xbd1a3f0000000000), - f64::from_bits(0x3ff059b0d315855a), f64::from_bits(0xbd02840000000000), - f64::from_bits(0x3ff0650a0e3c1f95), f64::from_bits(0x3cf1600000000000), - f64::from_bits(0x3ff0706b29ddf71a), f64::from_bits(0x3d15240000000000), - f64::from_bits(0x3ff07bd42b72a82d), f64::from_bits(0xbce9a00000000000), - f64::from_bits(0x3ff0874518759bd0), f64::from_bits(0x3ce6400000000000), - f64::from_bits(0x3ff092bdf66607c8), f64::from_bits(0xbd00780000000000), - f64::from_bits(0x3ff09e3ecac6f383), f64::from_bits(0xbc98000000000000), - f64::from_bits(0x3ff0a9c79b1f3930), f64::from_bits(0x3cffa00000000000), - f64::from_bits(0x3ff0b5586cf988fc), f64::from_bits(0xbcfac80000000000), - f64::from_bits(0x3ff0c0f145e46c8a), f64::from_bits(0x3cd9c00000000000), - f64::from_bits(0x3ff0cc922b724816), f64::from_bits(0x3d05200000000000), - f64::from_bits(0x3ff0d83b23395dd8), f64::from_bits(0xbcfad00000000000), - f64::from_bits(0x3ff0e3ec32d3d1f3), f64::from_bits(0x3d1bac0000000000), - f64::from_bits(0x3ff0efa55fdfa9a6), f64::from_bits(0xbd04e80000000000), - f64::from_bits(0x3ff0fb66affed2f0), f64::from_bits(0xbd0d300000000000), - f64::from_bits(0x3ff1073028d7234b), f64::from_bits(0x3cf1500000000000), - f64::from_bits(0x3ff11301d0125b5b), f64::from_bits(0x3cec000000000000), - f64::from_bits(0x3ff11edbab5e2af9), f64::from_bits(0x3d16bc0000000000), - f64::from_bits(0x3ff12abdc06c31d5), f64::from_bits(0x3ce8400000000000), - f64::from_bits(0x3ff136a814f2047d), f64::from_bits(0xbd0ed00000000000), - f64::from_bits(0x3ff1429aaea92de9), f64::from_bits(0x3ce8e00000000000), - f64::from_bits(0x3ff14e95934f3138), f64::from_bits(0x3ceb400000000000), - f64::from_bits(0x3ff15a98c8a58e71), f64::from_bits(0x3d05300000000000), - f64::from_bits(0x3ff166a45471c3df), f64::from_bits(0x3d03380000000000), - f64::from_bits(0x3ff172b83c7d5211), f64::from_bits(0x3d28d40000000000), - f64::from_bits(0x3ff17ed48695bb9f), f64::from_bits(0xbd05d00000000000), - f64::from_bits(0x3ff18af9388c8d93), f64::from_bits(0xbd1c880000000000), - f64::from_bits(0x3ff1972658375d66), f64::from_bits(0x3d11f00000000000), - f64::from_bits(0x3ff1a35beb6fcba7), f64::from_bits(0x3d10480000000000), - f64::from_bits(0x3ff1af99f81387e3), f64::from_bits(0xbd47390000000000), - f64::from_bits(0x3ff1bbe084045d54), f64::from_bits(0x3d24e40000000000), - f64::from_bits(0x3ff1c82f95281c43), f64::from_bits(0xbd0a200000000000), - f64::from_bits(0x3ff1d4873168b9b2), f64::from_bits(0x3ce3800000000000), - f64::from_bits(0x3ff1e0e75eb44031), f64::from_bits(0x3ceac00000000000), - f64::from_bits(0x3ff1ed5022fcd938), f64::from_bits(0x3d01900000000000), - f64::from_bits(0x3ff1f9c18438cdf7), f64::from_bits(0xbd1b780000000000), - f64::from_bits(0x3ff2063b88628d8f), f64::from_bits(0x3d2d940000000000), - f64::from_bits(0x3ff212be3578a81e), f64::from_bits(0x3cd8000000000000), - f64::from_bits(0x3ff21f49917ddd41), f64::from_bits(0x3d2b340000000000), - f64::from_bits(0x3ff22bdda2791323), f64::from_bits(0x3d19f80000000000), - f64::from_bits(0x3ff2387a6e7561e7), f64::from_bits(0xbd19c80000000000), - f64::from_bits(0x3ff2451ffb821427), f64::from_bits(0x3d02300000000000), - f64::from_bits(0x3ff251ce4fb2a602), f64::from_bits(0xbd13480000000000), - f64::from_bits(0x3ff25e85711eceb0), f64::from_bits(0x3d12700000000000), - f64::from_bits(0x3ff26b4565e27d16), f64::from_bits(0x3d11d00000000000), - f64::from_bits(0x3ff2780e341de00f), f64::from_bits(0x3d31ee0000000000), - f64::from_bits(0x3ff284dfe1f5633e), f64::from_bits(0xbd14c00000000000), - f64::from_bits(0x3ff291ba7591bb30), f64::from_bits(0xbd13d80000000000), - f64::from_bits(0x3ff29e9df51fdf09), f64::from_bits(0x3d08b00000000000), - f64::from_bits(0x3ff2ab8a66d10e9b), f64::from_bits(0xbd227c0000000000), - f64::from_bits(0x3ff2b87fd0dada3a), f64::from_bits(0x3d2a340000000000), - f64::from_bits(0x3ff2c57e39771af9), f64::from_bits(0xbd10800000000000), - f64::from_bits(0x3ff2d285a6e402d9), f64::from_bits(0xbd0ed00000000000), - f64::from_bits(0x3ff2df961f641579), f64::from_bits(0xbcf4200000000000), - f64::from_bits(0x3ff2ecafa93e2ecf), f64::from_bits(0xbd24980000000000), - f64::from_bits(0x3ff2f9d24abd8822), f64::from_bits(0xbd16300000000000), - f64::from_bits(0x3ff306fe0a31b625), f64::from_bits(0xbd32360000000000), - f64::from_bits(0x3ff31432edeea50b), f64::from_bits(0xbd70df8000000000), - f64::from_bits(0x3ff32170fc4cd7b8), f64::from_bits(0xbd22480000000000), - f64::from_bits(0x3ff32eb83ba8e9a2), f64::from_bits(0xbd25980000000000), - f64::from_bits(0x3ff33c08b2641766), f64::from_bits(0x3d1ed00000000000), - f64::from_bits(0x3ff3496266e3fa27), f64::from_bits(0xbcdc000000000000), - f64::from_bits(0x3ff356c55f929f0f), f64::from_bits(0xbd30d80000000000), - f64::from_bits(0x3ff36431a2de88b9), f64::from_bits(0x3d22c80000000000), - f64::from_bits(0x3ff371a7373aaa39), f64::from_bits(0x3d20600000000000), - f64::from_bits(0x3ff37f26231e74fe), f64::from_bits(0xbd16600000000000), - f64::from_bits(0x3ff38cae6d05d838), f64::from_bits(0xbd0ae00000000000), - f64::from_bits(0x3ff39a401b713ec3), f64::from_bits(0xbd44720000000000), - f64::from_bits(0x3ff3a7db34e5a020), f64::from_bits(0x3d08200000000000), - f64::from_bits(0x3ff3b57fbfec6e95), f64::from_bits(0x3d3e800000000000), - f64::from_bits(0x3ff3c32dc313a8f2), f64::from_bits(0x3cef800000000000), - f64::from_bits(0x3ff3d0e544ede122), f64::from_bits(0xbd17a00000000000), - f64::from_bits(0x3ff3dea64c1234bb), f64::from_bits(0x3d26300000000000), - f64::from_bits(0x3ff3ec70df1c4ecc), f64::from_bits(0xbd48a60000000000), - f64::from_bits(0x3ff3fa4504ac7e8c), f64::from_bits(0xbd3cdc0000000000), - f64::from_bits(0x3ff40822c367a0bb), f64::from_bits(0x3d25b80000000000), - f64::from_bits(0x3ff4160a21f72e95), f64::from_bits(0x3d1ec00000000000), - f64::from_bits(0x3ff423fb27094646), f64::from_bits(0xbd13600000000000), - f64::from_bits(0x3ff431f5d950a920), f64::from_bits(0x3d23980000000000), - f64::from_bits(0x3ff43ffa3f84b9eb), f64::from_bits(0x3cfa000000000000), - f64::from_bits(0x3ff44e0860618919), f64::from_bits(0xbcf6c00000000000), - f64::from_bits(0x3ff45c2042a7d201), f64::from_bits(0xbd0bc00000000000), - f64::from_bits(0x3ff46a41ed1d0016), f64::from_bits(0xbd12800000000000), - f64::from_bits(0x3ff4786d668b3326), f64::from_bits(0x3d30e00000000000), - f64::from_bits(0x3ff486a2b5c13c00), f64::from_bits(0xbd2d400000000000), - f64::from_bits(0x3ff494e1e192af04), f64::from_bits(0x3d0c200000000000), - f64::from_bits(0x3ff4a32af0d7d372), f64::from_bits(0xbd1e500000000000), - f64::from_bits(0x3ff4b17dea6db801), f64::from_bits(0x3d07800000000000), - f64::from_bits(0x3ff4bfdad53629e1), f64::from_bits(0xbd13800000000000), - f64::from_bits(0x3ff4ce41b817c132), f64::from_bits(0x3d00800000000000), - f64::from_bits(0x3ff4dcb299fddddb), f64::from_bits(0x3d2c700000000000), - f64::from_bits(0x3ff4eb2d81d8ab96), f64::from_bits(0xbd1ce00000000000), - f64::from_bits(0x3ff4f9b2769d2d02), f64::from_bits(0x3d19200000000000), - f64::from_bits(0x3ff508417f4531c1), f64::from_bits(0xbd08c00000000000), - f64::from_bits(0x3ff516daa2cf662a), f64::from_bits(0xbcfa000000000000), - f64::from_bits(0x3ff5257de83f51ea), f64::from_bits(0x3d4a080000000000), - f64::from_bits(0x3ff5342b569d4eda), f64::from_bits(0xbd26d80000000000), - f64::from_bits(0x3ff542e2f4f6ac1a), f64::from_bits(0xbd32440000000000), - f64::from_bits(0x3ff551a4ca5d94db), f64::from_bits(0x3d483c0000000000), - f64::from_bits(0x3ff56070dde9116b), f64::from_bits(0x3d24b00000000000), - f64::from_bits(0x3ff56f4736b529de), f64::from_bits(0x3d415a0000000000), - f64::from_bits(0x3ff57e27dbe2c40e), f64::from_bits(0xbd29e00000000000), - f64::from_bits(0x3ff58d12d497c76f), f64::from_bits(0xbd23080000000000), - f64::from_bits(0x3ff59c0827ff0b4c), f64::from_bits(0x3d4dec0000000000), - f64::from_bits(0x3ff5ab07dd485427), f64::from_bits(0xbcc4000000000000), - f64::from_bits(0x3ff5ba11fba87af4), f64::from_bits(0x3d30080000000000), - f64::from_bits(0x3ff5c9268a59460b), f64::from_bits(0xbd26c80000000000), - f64::from_bits(0x3ff5d84590998e3f), f64::from_bits(0x3d469a0000000000), - f64::from_bits(0x3ff5e76f15ad20e1), f64::from_bits(0xbd1b400000000000), - f64::from_bits(0x3ff5f6a320dcebca), f64::from_bits(0x3d17700000000000), - f64::from_bits(0x3ff605e1b976dcb8), f64::from_bits(0x3d26f80000000000), - f64::from_bits(0x3ff6152ae6cdf715), f64::from_bits(0x3d01000000000000), - f64::from_bits(0x3ff6247eb03a5531), f64::from_bits(0xbd15d00000000000), - f64::from_bits(0x3ff633dd1d1929b5), f64::from_bits(0xbd12d00000000000), - f64::from_bits(0x3ff6434634ccc313), f64::from_bits(0xbcea800000000000), - f64::from_bits(0x3ff652b9febc8efa), f64::from_bits(0xbd28600000000000), - f64::from_bits(0x3ff6623882553397), f64::from_bits(0x3d71fe0000000000), - f64::from_bits(0x3ff671c1c708328e), f64::from_bits(0xbd37200000000000), - f64::from_bits(0x3ff68155d44ca97e), f64::from_bits(0x3ce6800000000000), - f64::from_bits(0x3ff690f4b19e9471), f64::from_bits(0xbd29780000000000), - ]; - // double_t r, t, z; // uint32_t ix, i0; // union {double f; uint64_t i;} u = {x}; @@ -375,8 +375,8 @@ pub fn exp2(mut x: f64) -> f64 { let mut z = x - uf; /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ - let t = tbl[2 * i0 as usize]; /* exp2t[i0] */ - z -= tbl[2 * i0 as usize + 1]; /* eps[i0] */ + let t = f64::from_bits(TBL[2 * i0 as usize]); /* exp2t[i0] */ + z -= f64::from_bits(TBL[2 * i0 as usize + 1]); /* eps[i0] */ let r = t + t * z * (p1 + z * (p2 + z * (p3 + z * (p4 + z * p5)))); scalbn(r, ki) diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index 947679a8389..79929ce90e0 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -26,6 +26,25 @@ const TBLSIZE: usize = 16; +static EXP2FT: [u64; TBLSIZE] = [ + 0x3fe6a09e667f3bcd, + 0x3fe7a11473eb0187, + 0x3fe8ace5422aa0db, + 0x3fe9c49182a3f090, + 0x3feae89f995ad3ad, + 0x3fec199bdd85529c, + 0x3fed5818dcfba487, + 0x3feea4afa2a490da, + 0x3ff0000000000000, + 0x3ff0b5586cf9890f, + 0x3ff172b83c7d517b, + 0x3ff2387a6e756238, + 0x3ff306fe0a31b715, + 0x3ff3dea64c123422, + 0x3ff4bfdad5362a27, + 0x3ff5ab07dd485429, +]; + // exp2f(x): compute the base 2 exponential of x // // Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. @@ -57,25 +76,6 @@ pub fn exp2f(mut x: f32) -> f32 { let p3 = f32::from_bits(0x3d6359a4); let p4 = f32::from_bits(0x3c1d964e); - let exp2ft: [f64; TBLSIZE] = [ - f64::from_bits(0x3fe6a09e667f3bcd), - f64::from_bits(0x3fe7a11473eb0187), - f64::from_bits(0x3fe8ace5422aa0db), - f64::from_bits(0x3fe9c49182a3f090), - f64::from_bits(0x3feae89f995ad3ad), - f64::from_bits(0x3fec199bdd85529c), - f64::from_bits(0x3fed5818dcfba487), - f64::from_bits(0x3feea4afa2a490da), - f64::from_bits(0x3ff0000000000000), - f64::from_bits(0x3ff0b5586cf9890f), - f64::from_bits(0x3ff172b83c7d517b), - f64::from_bits(0x3ff2387a6e756238), - f64::from_bits(0x3ff306fe0a31b715), - f64::from_bits(0x3ff3dea64c123422), - f64::from_bits(0x3ff4bfdad5362a27), - f64::from_bits(0x3ff5ab07dd485429), - ]; - // double_t t, r, z; // uint32_t ix, i0, k; @@ -121,7 +121,7 @@ pub fn exp2f(mut x: f32) -> f32 { uf -= redux; let z: f64 = (x - uf) as f64; /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ - let r: f64 = exp2ft[i0 as usize]; + let r: f64 = f64::from_bits(EXP2FT[i0 as usize]); let t: f64 = r as f64 * z; let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64); -- cgit 1.4.1-3-g733a5 From a60a31ab9017209b8359dc5c97649faecb7b99f6 Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 15:25:09 -0400 Subject: Add some extra notes to CONTRIBUTING --- library/compiler-builtins/libm/CONTRIBUTING.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index 6f8e984f300..680c40e80e7 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -28,7 +28,7 @@ Check [PR #65] for an example. have any external dependencies (other than `core` itself). - Only use relative imports within the `math` directory / module, e.g. `use self::fabs::fabs` or -`use super::isnanf`. Absolute imports from core are OK, e.g. `use core::u64`. +`use super::k_cos`. Absolute imports from core are OK, e.g. `use core::u64`. - To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the `GET_FLOAT_WORD` macro, or a union, to do this operation. @@ -36,6 +36,13 @@ Check [PR #65] for an example. - To reinterpret an integer as a float use the `f32::from_bits` constructor. The MUSL code uses the `SET_FLOAT_WORD` macro, or a union, to do this operation. +- You may use other methods from core like `f64::is_nan`, etc. as appropriate. + +- If you're implementing one of the private double-underscore functions, take a look at the + "source" name in the comment at the top for an idea for alternate naming. For example, `__sin` + was renamed to `k_sin` after the FreeBSD source code naming. Do `use` these private functions in + `mod.rs`. + - You may encounter weird literals like `0x1p127f` in the MUSL code. These are hexadecimal floating point literals. Rust (the language) doesn't support these kind of literals. The best way I have found to deal with these literals is to turn them into their integer representation using the -- cgit 1.4.1-3-g733a5 From 65b49bb7a0fa37ff6fd9481844fc0af56e2a613f Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 15:21:23 -0400 Subject: implement fma --- library/compiler-builtins/libm/src/lib.rs | 2 - library/compiler-builtins/libm/src/math/fma.rs | 201 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fma.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index bef4667875a..c3a20059330 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -366,7 +366,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn signum(self) -> Self; - #[cfg(todo)] fn mul_add(self, a: Self, b: Self) -> Self; #[cfg(todo)] @@ -485,7 +484,6 @@ impl F64Ext for f64 { fabs(self) } - #[cfg(todo)] #[inline] fn mul_add(self, a: Self, b: Self) -> Self { fma(self, a, b) diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs new file mode 100644 index 00000000000..99a27164a81 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -0,0 +1,201 @@ +use core::{f32, f64}; + +use super::scalbn; + +const ZEROINFNAN: i32 = 0x7ff - 0x3ff - 52 - 1; + +struct Num { + m: u64, + e: i32, + sign: i32, +} + +#[inline] +fn normalize(x: f64) -> Num { + let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 + + let mut ix: u64 = x.to_bits(); + let mut e: i32 = (ix >> 52) as i32; + let sign: i32 = e & 0x800; + e &= 0x7ff; + if e == 0 { + ix = (x * x1p63).to_bits(); + e = (ix >> 52) as i32 & 0x7ff; + e = if e != 0 { e - 63 } else { 0x800 }; + } + ix &= (1 << 52) - 1; + ix |= 1 << 52; + ix <<= 1; + e -= 0x3ff + 52 + 1; + Num { m: ix, e, sign } +} + +#[inline] +fn mul(x: u64, y: u64) -> (u64, u64) { + let t1: u64; + let t2: u64; + let t3: u64; + let xlo: u64 = x as u32 as u64; + let xhi: u64 = x >> 32; + let ylo: u64 = y as u32 as u64; + let yhi: u64 = y >> 32; + + t1 = xlo * ylo; + t2 = xlo * yhi + xhi * ylo; + t3 = xhi * yhi; + let lo = t1 + (t2 << 32); + let hi = t3 + (t2 >> 32) + (t1 > lo) as u64; + (hi, lo) +} + +#[inline] +pub fn fma(x: f64, y: f64, z: f64) -> f64 { + let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 + let x0_ffffff8p_63 = f64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63 + + /* normalize so top 10bits and last bit are 0 */ + let nx = normalize(x); + let ny = normalize(y); + let nz = normalize(z); + + if nx.e >= ZEROINFNAN || ny.e >= ZEROINFNAN { + return x * y + z; + } + if nz.e >= ZEROINFNAN { + if nz.e > ZEROINFNAN { + /* z==0 */ + return x * y + z; + } + return z; + } + + /* mul: r = x*y */ + let zhi: u64; + let zlo: u64; + let (mut rhi, mut rlo) = mul(nx.m, ny.m); + /* either top 20 or 21 bits of rhi and last 2 bits of rlo are 0 */ + + /* align exponents */ + let mut e: i32 = nx.e + ny.e; + let mut d: i32 = nz.e - e; + /* shift bits z<<=kz, r>>=kr, so kz+kr == d, set e = e+kr (== ez-kz) */ + if d > 0 { + if d < 64 { + zlo = nz.m << d; + zhi = nz.m >> 64 - d; + } else { + zlo = 0; + zhi = nz.m; + e = nz.e - 64; + d -= 64; + if d == 0 { + } else if d < 64 { + rlo = rhi << 64 - d | rlo >> d | ((rlo << 64 - d) != 0) as u64; + rhi = rhi >> d; + } else { + rlo = 1; + rhi = 0; + } + } + } else { + zhi = 0; + d = -d; + if d == 0 { + zlo = nz.m; + } else if d < 64 { + zlo = nz.m >> d | ((nz.m << 64 - d) != 0) as u64; + } else { + zlo = 1; + } + } + + /* add */ + let mut sign: i32 = nx.sign ^ ny.sign; + let samesign: bool = (sign ^ nz.sign) == 0; + let mut nonzero: i32 = 1; + if samesign { + /* r += z */ + rlo += zlo; + rhi += zhi + (rlo < zlo) as u64; + } else { + /* r -= z */ + let t = rlo; + rlo -= zlo; + rhi = rhi - zhi - (t < rlo) as u64; + if (rhi >> 63) != 0 { + rlo = (-(rlo as i64)) as u64; + rhi = (-(rhi as i64)) as u64 - (rlo != 0) as u64; + sign = (sign == 0) as i32; + } + nonzero = (rhi != 0) as i32; + } + + /* set rhi to top 63bit of the result (last bit is sticky) */ + if nonzero != 0 { + e += 64; + d = rhi.leading_zeros() as i32 - 1; + /* note: d > 0 */ + rhi = rhi << d | rlo >> 64 - d | ((rlo << d) != 0) as u64; + } else if rlo != 0 { + d = rlo.leading_zeros() as i32 - 1; + if d < 0 { + rhi = rlo >> 1 | (rlo & 1); + } else { + rhi = rlo << d; + } + } else { + /* exact +-0 */ + return x * y + z; + } + e -= d; + + /* convert to double */ + let mut i: i64 = rhi as i64; /* i is in [1<<62,(1<<63)-1] */ + if sign != 0 { + i = -i; + } + let mut r: f64 = i as f64; /* |r| is in [0x1p62,0x1p63] */ + + if e < -1022 - 62 { + /* result is subnormal before rounding */ + if e == -1022 - 63 { + let mut c: f64 = x1p63; + if sign != 0 { + c = -c; + } + if r == c { + /* min normal after rounding, underflow depends + on arch behaviour which can be imitated by + a double to float conversion */ + let fltmin: f32 = (x0_ffffff8p_63 * f32::MIN_POSITIVE as f64 * r) as f32; + return f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64; + } + /* one bit is lost when scaled, add another top bit to + only round once at conversion if it is inexact */ + if (rhi << 53) != 0 { + i = (rhi >> 1 | (rhi & 1) | 1 << 62) as i64; + if sign != 0 { + i = -i; + } + r = i as f64; + r = 2. * r - c; /* remove top bit */ + + /* raise underflow portably, such that it + cannot be optimized away */ + { + let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * r; + r += (tiny * tiny) * (r - r); + } + } + } else { + /* only round once when scaled */ + d = 10; + i = ((rhi >> d | ((rhi << 64 - d) != 0) as u64) << d) as i64; + if sign != 0 { + i = -i; + } + r = i as f64; + } + } + scalbn(r, e) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 828e3cb1a7e..c9a34fae42b 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -22,6 +22,7 @@ mod fdim; mod fdimf; mod floor; mod floorf; +mod fma; mod fmod; mod fmodf; mod hypot; @@ -61,6 +62,7 @@ pub use self::fdim::fdim; pub use self::fdimf::fdimf; pub use self::floor::floor; pub use self::floorf::floorf; +pub use self::fma::fma; pub use self::fmod::fmod; pub use self::fmodf::fmodf; pub use self::hypot::hypot; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index e5b8fdc1d4f..f4b7cd7cafb 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -732,7 +732,7 @@ f64f64_f64! { // With signature `fn(f64, f64, f64) -> f64` f64f64f64_f64! { - // fma, + fma, } // With signature `fn(f64, i32) -> f64` -- cgit 1.4.1-3-g733a5 From a377d0d79b16bbcff76bbed4f0fa7d79ba0da621 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 14:49:22 -0400 Subject: allow some functions to be inlined --- library/compiler-builtins/libm/src/math/ceilf.rs | 1 + library/compiler-builtins/libm/src/math/exp2.rs | 1 + library/compiler-builtins/libm/src/math/exp2f.rs | 1 + library/compiler-builtins/libm/src/math/fdim.rs | 1 + library/compiler-builtins/libm/src/math/fdimf.rs | 1 + library/compiler-builtins/libm/src/math/hypot.rs | 1 + library/compiler-builtins/libm/src/math/log1p.rs | 1 + library/compiler-builtins/libm/src/math/log1pf.rs | 1 + library/compiler-builtins/libm/src/math/log2.rs | 1 + library/compiler-builtins/libm/src/math/log2f.rs | 1 + library/compiler-builtins/libm/src/math/round.rs | 1 + library/compiler-builtins/libm/src/math/roundf.rs | 1 + 12 files changed, 12 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index b4f58bfb86f..16bffb3002e 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -1,5 +1,6 @@ use core::f32; +#[inline] pub fn ceilf(x: f32) -> f32 { let mut ui = x.to_bits(); let e = (((ui >> 23) & 0xff) - 0x7f) as i32; diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index 61bfd1015d2..0ab11989679 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -318,6 +318,7 @@ static TBL: [u64; TBLSIZE * 2] = [ // // Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library // for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). +#[inline] pub fn exp2(mut x: f64) -> f64 { let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64; let p1 = f64::from_bits(0x3fe62e42fefa39ef); diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index 79929ce90e0..a3f6db8c5b3 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -69,6 +69,7 @@ static EXP2FT: [u64; TBLSIZE] = [ // // Tang, P. Table-driven Implementation of the Exponential Function // in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). +#[inline] pub fn exp2f(mut x: f32) -> f32 { let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; let p1 = f32::from_bits(0x3f317218); diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index 2b277eab03e..1daae4ebc22 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -1,5 +1,6 @@ use core::f64; +#[inline] pub fn fdim(x: f64, y: f64) -> f64 { if x.is_nan() { x diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index 44bf2d6806e..953e0c8dfaf 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -1,5 +1,6 @@ use core::f32; +#[inline] pub fn fdimf(x: f32, y: f32) -> f32 { if x.is_nan() { x diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs index 7ad1baf796c..f011415fdc6 100644 --- a/library/compiler-builtins/libm/src/math/hypot.rs +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -4,6 +4,7 @@ use super::sqrt; const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 +#[inline] fn sq(x: f64) -> (f64, f64) { let xh: f64; let xl: f64; diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index 7f7a5125bbb..f42669deeae 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -65,6 +65,7 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +#[inline] pub fn log1p(x: f64) -> f64 { let mut ui: u64 = x.to_bits(); let hfsq: f64; diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index c8e24225933..e6e1c14c8c5 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -20,6 +20,7 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +#[inline] pub fn log1pf(x: f32) -> f32 { let mut ui: u32 = x.to_bits(); let hfsq: f32; diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index f6640d296c3..35eb9bf72b2 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -29,6 +29,7 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +#[inline] pub fn log2(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs index c007ff9b097..8684b142f8b 100644 --- a/library/compiler-builtins/libm/src/math/log2f.rs +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -23,6 +23,7 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +#[inline] pub fn log2f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 73d431c5183..1a6e754489c 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -2,6 +2,7 @@ use core::f64; const TOINT: f64 = 1.0 / f64::EPSILON; +#[inline] pub fn round(mut x: f64) -> f64 { let (f, i) = (x, x.to_bits()); let e: u64 = i >> 52 & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index bd2488fa99c..7dd79557a9d 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -2,6 +2,7 @@ use core::f32; const TOINT: f32 = 1.0 / f32::EPSILON; +#[inline] pub fn roundf(mut x: f32) -> f32 { let i = x.to_bits(); let e: u32 = i >> 23 & 0xff; -- cgit 1.4.1-3-g733a5 From f03a65b37279890082fcdeaebdc90409eab7fc6b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jul 2018 22:41:48 +0200 Subject: rustfmt --- library/compiler-builtins/libm/src/math/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index b2c01f6514f..d5f4e0d54bc 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -90,6 +90,4 @@ mod k_sinf; mod rem_pio2_large; mod rem_pio2f; -use self::{ - k_cosf::k_cosf, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f, -}; +use self::{k_cosf::k_cosf, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f}; -- cgit 1.4.1-3-g733a5 From ccde9e02e7573c05c4add6653f93ba483da42d6f Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 18:57:12 +0300 Subject: acosf asinf atanf expm1f sinf tanf --- library/compiler-builtins/libm/src/lib.rs | 12 --- library/compiler-builtins/libm/src/math/acosf.rs | 59 +++++++++++ library/compiler-builtins/libm/src/math/asinf.rs | 52 ++++++++++ library/compiler-builtins/libm/src/math/atanf.rs | 95 +++++++++++++++++ library/compiler-builtins/libm/src/math/expm1f.rs | 112 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/k_tanf.rs | 35 +++++++ library/compiler-builtins/libm/src/math/mod.rs | 18 +++- library/compiler-builtins/libm/src/math/sinf.rs | 77 ++++++++++++++ library/compiler-builtins/libm/src/math/tanf.rs | 62 ++++++++++++ .../libm/test-generator/src/main.rs | 11 +- 10 files changed, 515 insertions(+), 18 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/acosf.rs create mode 100644 library/compiler-builtins/libm/src/math/asinf.rs create mode 100644 library/compiler-builtins/libm/src/math/atanf.rs create mode 100644 library/compiler-builtins/libm/src/math/expm1f.rs create mode 100644 library/compiler-builtins/libm/src/math/k_tanf.rs create mode 100644 library/compiler-builtins/libm/src/math/sinf.rs create mode 100644 library/compiler-builtins/libm/src/math/tanf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 27925e806c0..df7ee813fba 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -84,21 +84,16 @@ pub trait F32Ext: private::Sealed { fn hypot(self, other: Self) -> Self; - #[cfg(todo)] fn sin(self) -> Self; fn cos(self) -> Self; - #[cfg(todo)] fn tan(self) -> Self; - #[cfg(todo)] fn asin(self) -> Self; - #[cfg(todo)] fn acos(self) -> Self; - #[cfg(todo)] fn atan(self) -> Self; #[cfg(todo)] @@ -110,7 +105,6 @@ pub trait F32Ext: private::Sealed { (self.sin(), self.cos()) } - #[cfg(todo)] fn exp_m1(self) -> Self; fn ln_1p(self) -> Self; @@ -248,7 +242,6 @@ impl F32Ext for f32 { hypotf(self, other) } - #[cfg(todo)] #[inline] fn sin(self) -> Self { sinf(self) @@ -259,25 +252,21 @@ impl F32Ext for f32 { cosf(self) } - #[cfg(todo)] #[inline] fn tan(self) -> Self { tanf(self) } - #[cfg(todo)] #[inline] fn asin(self) -> Self { asinf(self) } - #[cfg(todo)] #[inline] fn acos(self) -> Self { acosf(self) } - #[cfg(todo)] #[inline] fn atan(self) -> Self { atanf(self) @@ -289,7 +278,6 @@ impl F32Ext for f32 { atan2f(self, other) } - #[cfg(todo)] #[inline] fn exp_m1(self) -> Self { expm1f(self) diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs new file mode 100644 index 00000000000..bbe29c17c13 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -0,0 +1,59 @@ +use super::sqrtf::sqrtf; + +const PIO2_HI: f32 = 1.5707962513e+00; /* 0x3fc90fda */ +const PIO2_LO: f32 = 7.5497894159e-08; /* 0x33a22168 */ +const P_S0: f32 = 1.6666586697e-01; +const P_S1: f32 = -4.2743422091e-02; +const P_S2: f32 = -8.6563630030e-03; +const Q_S1: f32 = -7.0662963390e-01; + +fn r(z: f32) -> f32 { + let p = z * (P_S0 + z * (P_S1 + z * P_S2)); + let q = 1. + z * Q_S1; + p / q +} + +#[inline] +pub fn acosf(x: f32) -> f32 { + let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) + + let z: f32; + let w: f32; + let s: f32; + + let mut hx = x.to_bits(); + let ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3f800000 { + if ix == 0x3f800000 { + if (hx >> 31) != 0 { + return 2. * PIO2_HI + x1p_120; + } + return 0.; + } + return 0. / (x - x); + } + /* |x| < 0.5 */ + if ix < 0x3f000000 { + if ix <= 0x32800000 { + /* |x| < 2**-26 */ + return PIO2_HI + x1p_120; + } + return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); + } + /* x < -0.5 */ + if (hx >> 31) != 0 { + z = (1. + x) * 0.5; + s = sqrtf(z); + w = r(z) * s - PIO2_LO; + return 2. * (PIO2_HI - (s + w)); + } + /* x > 0.5 */ + z = (1. - x) * 0.5; + s = sqrtf(z); + hx = s.to_bits(); + let df = f32::from_bits(hx & 0xfffff000); + let c = (z - df * df) / (s + df); + w = r(z) * s + c; + 2. * (df + w) +} diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs new file mode 100644 index 00000000000..597be4cb7f9 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -0,0 +1,52 @@ +use super::fabsf::fabsf; +use super::sqrt::sqrt; + +const PIO2: f64 = 1.570796326794896558e+00; + +/* coefficients for R(x^2) */ +const P_S0: f32 = 1.6666586697e-01; +const P_S1: f32 = -4.2743422091e-02; +const P_S2: f32 = -8.6563630030e-03; +const Q_S1: f32 = -7.0662963390e-01; + +fn r(z: f32) -> f32 { + let p = z * (P_S0 + z * (P_S1 + z * P_S2)); + let q = 1. + z * Q_S1; + p / q +} + +#[inline] +pub fn asinf(mut x: f32) -> f32 { + let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120) + + let hx = x.to_bits(); + let ix = hx & 0x7fffffff; + + if ix >= 0x3f800000 { + /* |x| >= 1 */ + if ix == 0x3f800000 { + /* |x| == 1 */ + return ((x as f64) * PIO2 + x1p_120) as f32; /* asin(+-1) = +-pi/2 with inexact */ + } + return 0. / (x - x); /* asin(|x|>1) is NaN */ + } + + if ix < 0x3f000000 { + /* |x| < 0.5 */ + /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ + if (ix < 0x39800000) && (ix >= 0x00800000) { + return x; + } + return x + x * r(x * x); + } + + /* 1 > |x| >= 0.5 */ + let z = (1. - fabsf(x)) * 0.5; + let s = sqrt(z as f64); + x = (PIO2 - 2. * (s + s * (r(z) as f64))) as f32; + if (hx >> 31) != 0 { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs new file mode 100644 index 00000000000..01c41f4ce17 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -0,0 +1,95 @@ +use super::fabsf; + +const ATAN_HI: [f32; 4] = [ + 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ + 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ + 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ + 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ +]; + +const ATAN_LO: [f32; 4] = [ + 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ + 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ + 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ + 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ +]; + +const A_T: [f32; 5] = [ + 3.3333328366e-01, + -1.9999158382e-01, + 1.4253635705e-01, + -1.0648017377e-01, + 6.1687607318e-02, +]; + +#[inline] +pub fn atanf(mut x: f32) -> f32 { + let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) + + let z: f32; + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix >= 0x4c800000 { + /* if |x| >= 2**26 */ + if x.is_nan() { + return x; + } + z = ATAN_HI[3] + x1p_120; + return if sign { -z } else { z }; + } + let id = if ix < 0x3ee00000 { + /* |x| < 0.4375 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + if ix < 0x00800000 { + /* raise underflow for subnormal x */ + force_eval!(x * x); + } + return x; + } + -1 + } else { + x = fabsf(x); + if ix < 0x3f980000 { + /* |x| < 1.1875 */ + if ix < 0x3f300000 { + /* 7/16 <= |x| < 11/16 */ + x = (2. * x - 1.) / (2. + x); + 0 + } else { + /* 11/16 <= |x| < 19/16 */ + x = (x - 1.) / (x + 1.); + 1 + } + } else { + if ix < 0x401c0000 { + /* |x| < 2.4375 */ + x = (x - 1.5) / (1. + 1.5 * x); + 2 + } else { + /* 2.4375 <= |x| < 2**26 */ + x = -1. / x; + 3 + } + } + }; + /* end of argument reduction */ + z = x * x; + let w = z * z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + let s1 = z * (A_T[0] + w * (A_T[2] + w * A_T[4])); + let s2 = w * (A_T[1] + w * A_T[3]); + if id < 0 { + return x - x * (s1 + s2); + } + let id = id as usize; + let z = ATAN_HI[id] - ((x * (s1 + s2) - ATAN_LO[id]) - x); + if sign { + -z + } else { + z + } +} diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs new file mode 100644 index 00000000000..011e09b693d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -0,0 +1,112 @@ +const O_THRESHOLD: f32 = 8.8721679688e+01; /* 0x42b17180 */ +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: + * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 + * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): + */ +const Q1: f32 = -3.3333212137e-2; /* -0x888868.0p-28 */ +const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ + +#[inline] +pub fn expm1f(mut x: f32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + + let mut hx = x.to_bits(); + let sign = (hx >> 31) != 0; + hx &= 0x7fffffff; + + /* filter out huge and non-finite argument */ + if hx >= 0x4195b844 { + /* if |x|>=27*ln2 */ + if hx > 0x7f800000 { + /* NaN */ + return x; + } + if sign { + return -1.; + } + if x > O_THRESHOLD { + x *= x1p127; + return x; + } + } + + let k: i32; + let hi: f32; + let lo: f32; + let mut c = 0f32; + /* argument reduction */ + if hx > 0x3eb17218 { + /* if |x| > 0.5 ln2 */ + if hx < 0x3F851592 { + /* and |x| < 1.5 ln2 */ + if !sign { + hi = x - LN2_HI; + lo = LN2_LO; + k = 1; + } else { + hi = x + LN2_HI; + lo = -LN2_LO; + k = -1; + } + } else { + k = (INV_LN2 * x + (if sign { -0.5 } else { 0.5 })) as i32; + let t = k as f32; + hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ + lo = t * LN2_LO; + } + x = hi - lo; + c = (hi - x) - lo; + } else if hx < 0x33000000 { + /* when |x|<2**-25, return x */ + if hx < 0x00800000 { + force_eval!(x * x); + } + return x; + } else { + k = 0; + } + + /* x is now in primary range */ + let hfx = 0.5 * x; + let hxs = x * hfx; + let r1 = 1. + hxs * (Q1 + hxs * Q2); + let t = 3. - r1 * hfx; + let mut e = hxs * ((r1 - t) / (6. - x * t)); + if k == 0 { + /* c is 0 */ + return x - (x * e - hxs); + } + e = x * (e - c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if k == -1 { + return 0.5 * (x - e) - 0.5; + } + if k == 1 { + if x < -0.25 { + return -2. * (e - (x + 0.5)); + } + return 1. + 2. * (x - e); + } + let twopk = f32::from_bits(((0x7f + k) << 23) as u32); /* 2^k */ + if (k < 0) || (k > 56) { + /* suffice to return exp(x)-1 */ + let mut y = x - e + 1.; + if k == 128 { + y = y * 2. * x1p127; + } else { + y = y * twopk; + } + return y - 1.; + } + let uf = f32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */ + if k < 23 { + (x - e + (1. - uf)) * twopk + } else { + (x - (e + uf) + 1.) * twopk + } +} diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs new file mode 100644 index 00000000000..db2e0caa7a5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_tanf.rs @@ -0,0 +1,35 @@ +/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ +const T: [f64; 6] = [ + 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ + 0.133392002712976742718, /* 0x1112fd38999f72.0p-55 */ + 0.0533812378445670393523, /* 0x1b54c91d865afe.0p-57 */ + 0.0245283181166547278873, /* 0x191df3908c33ce.0p-58 */ + 0.00297435743359967304927, /* 0x185dadfcecf44e.0p-61 */ + 0.00946564784943673166728, /* 0x1362b9bf971bcd.0p-59 */ +]; + +#[inline] +pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { + let z = x * x; + /* + * Split up the polynomial into small independent terms to give + * opportunities for parallel evaluation. The chosen splitting is + * micro-optimized for Athlons (XP, X64). It costs 2 multiplications + * relative to Horner's method on sequential machines. + * + * We add the small terms from lowest degree up for efficiency on + * non-sequential machines (the lowest degree terms tend to be ready + * earlier). Apart from this, we don't care about order of + * operations, and don't need to to care since we have precision to + * spare. However, the chosen splitting is good for accuracy too, + * and would give results as accurate as Horner's method if the + * small terms were added from highest degree down. + */ + let mut r = T[4] + z * T[5]; + let t = T[2] + z * T[3]; + let w = z * z; + let s = z * x; + let u = T[0] + z * T[1]; + r = (x + s * u) + (s * w) * (t + w * r); + (if odd { -1. / r } else { r }) as f32 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c903d378762..792d05623f3 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -7,6 +7,9 @@ macro_rules! force_eval { } mod acos; +mod acosf; +mod asinf; +mod atanf; mod cbrt; mod cbrtf; mod ceil; @@ -17,6 +20,7 @@ mod exp2; mod exp2f; mod expf; mod expm1; +mod expm1f; mod fabs; mod fabsf; mod fdim; @@ -41,13 +45,18 @@ mod round; mod roundf; mod scalbn; mod scalbnf; +mod sinf; mod sqrt; mod sqrtf; +mod tanf; mod trunc; mod truncf; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; +pub use self::acosf::acosf; +pub use self::asinf::asinf; +pub use self::atanf::atanf; pub use self::cbrt::cbrt; pub use self::cbrtf::cbrtf; pub use self::ceil::ceil; @@ -58,6 +67,7 @@ pub use self::exp2::exp2; pub use self::exp2f::exp2f; pub use self::expf::expf; pub use self::expm1::expm1; +pub use self::expm1f::expm1f; pub use self::fabs::fabs; pub use self::fabsf::fabsf; pub use self::fdim::fdim; @@ -82,14 +92,20 @@ pub use self::round::round; pub use self::roundf::roundf; pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; +pub use self::sinf::sinf; pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; +pub use self::tanf::tanf; pub use self::trunc::trunc; pub use self::truncf::truncf; mod k_cosf; mod k_sinf; +mod k_tanf; mod rem_pio2_large; mod rem_pio2f; -use self::{k_cosf::k_cosf, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f}; +use self::{ + k_cosf::k_cosf, k_sinf::k_sinf, k_tanf::k_tanf, rem_pio2_large::rem_pio2_large, + rem_pio2f::rem_pio2f, +}; diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs new file mode 100644 index 00000000000..09f62cddcae --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -0,0 +1,77 @@ +use super::{k_cosf, k_sinf, rem_pio2f}; + +use core::f64::consts::FRAC_PI_2; + +/* Small multiples of pi/2 rounded to double precision. */ +const S1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +#[inline] +pub fn sinf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00800000 { + x / x1p120 + } else { + x + x1p120 + }); + return x; + } + return k_sinf(x64); + } + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + if sign { + return -k_cosf(x64 + S1_PIO2); + } else { + return k_cosf(x64 - S1_PIO2); + } + } + return k_sinf(if sign { + -(x64 + S2_PIO2) + } else { + -(x64 - S2_PIO2) + }); + } + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + if sign { + return k_cosf(x64 + S3_PIO2); + } else { + return -k_cosf(x64 - S3_PIO2); + } + } + return k_sinf(if sign { x64 + S4_PIO2 } else { x64 - S4_PIO2 }); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x - x; + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + match n & 3 { + 0 => k_sinf(y), + 1 => k_cosf(y), + 2 => return k_sinf(-y), + _ => -k_cosf(y), + } +} diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs new file mode 100644 index 00000000000..6bfbe06c1b4 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -0,0 +1,62 @@ +use super::{k_tanf, rem_pio2f}; + +use core::f64::consts::FRAC_PI_2; + +/* Small multiples of pi/2 rounded to double precision. */ +const T1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +#[inline] +pub fn tanf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00800000 { + x / x1p120 + } else { + x + x1p120 + }); + return x; + } + return k_tanf(x64, false); + } + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + return k_tanf(if sign { x64 + T1_PIO2 } else { x64 - T1_PIO2 }, true); + } else { + return k_tanf(if sign { x64 + T2_PIO2 } else { x64 - T2_PIO2 }, false); + } + } + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + return k_tanf(if sign { x64 + T3_PIO2 } else { x64 - T3_PIO2 }, true); + } else { + return k_tanf(if sign { x64 + T4_PIO2 } else { x64 - T4_PIO2 }, false); + } + } + + /* tan(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x - x; + } + + /* argument reduction */ + let (n, y) = rem_pio2f(x); + k_tanf(y, n & 1 != 0) +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index aa50f57cdb7..0f93606500f 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -651,25 +651,26 @@ fn main() -> Result<(), Box> { // With signature `fn(f32) -> f32` f32_f32! { - // acosf, + acosf, floorf, truncf, - // asinf, - // atanf, + asinf, + atanf, cbrtf, cosf, ceilf, // coshf, exp2f, expf, + expm1f, log10f, log1pf, log2f, logf, roundf, - // sinf, + sinf, // sinhf, - // tanf, + tanf, // tanhf, fabsf, sqrtf, -- cgit 1.4.1-3-g733a5 From 1d39d059e5eb25a84191245af804b68db954d032 Mon Sep 17 00:00:00 2001 From: vjackson725 Date: Sat, 14 Jul 2018 23:10:26 +1000 Subject: add an implemetation of asin Fixes rust-lang/libm#7 Additonally adds inline functions for macros dealing with low and high words of f64s to the root module. Also, the muslc code used a hexdecimal float. This shouldn't be needed because Rust implements floating point parsing well. --- library/compiler-builtins/libm/src/math/asin.rs | 113 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 28 +++++ .../libm/test-generator/src/main.rs | 2 +- 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/src/math/asin.rs diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs new file mode 100644 index 00000000000..720169bdcf0 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -0,0 +1,113 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* asin(x) + * Method : + * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... + * we approximate asin(x) on [0,0.5] by + * asin(x) = x + x*x^2*R(x^2) + * where + * R(x^2) is a rational approximation of (asin(x)-x)/x^3 + * and its remez error is bounded by + * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) + * + * For x in [0.5,1] + * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) + * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; + * then for x>0.98 + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) + * For x<=0.98, let pio4_hi = pio2_hi/2, then + * f = hi part of s; + * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) + * and + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) + * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + */ + +use super::{fabs, get_high_word, get_low_word, sqrt, with_set_low_word}; + +const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ +const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ +/* coefficients for R(x^2) */ +const P_S0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ +const P_S1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ +const P_S2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ +const P_S3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ +const P_S4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ +const P_S5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ +const Q_S1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ +const Q_S2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ +const Q_S3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ +const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +fn comp_r(z: f64) -> f64 { + let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); + let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); + return p / q; +} + +pub fn asin(mut x: f64) -> f64 { + let z: f64; + let r: f64; + let s: f64; + let hx: u32; + let ix: u32; + + hx = get_high_word(x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3ff00000 { + let lx: u32; + lx = get_low_word(x); + if (ix - 0x3ff00000 | lx) == 0 { + /* asin(1) = +-pi/2 with inexact */ + return x * PIO2_HI + f64::from_bits(0x3870000000000000); + } else { + return 0.0 / (x - x); + } + } + /* |x| < 0.5 */ + if ix < 0x3fe00000 { + /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ + if ix < 0x3e500000 && ix >= 0x00100000 { + return x; + } else { + return x + x * comp_r(x * x); + } + } + /* 1 > |x| >= 0.5 */ + z = (1.0 - fabs(x)) * 0.5; + s = sqrt(z); + r = comp_r(z); + if ix >= 0x3fef3333 { + /* if |x| > 0.975 */ + x = PIO2_HI - (2. * (s + s * r) - PIO2_LO); + } else { + let f: f64; + let c: f64; + /* f+c = sqrt(z) */ + f = with_set_low_word(s, 0); + c = (z - f * f) / (s + f); + x = 0.5 * PIO2_HI - (2.0 * s * r - (PIO2_LO - 2.0 * c) - (0.5 * PIO2_HI - 2.0 * f)); + } + if hx >> 31 != 0 { + return -x; + } else { + return x; + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 792d05623f3..42c596857d7 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -8,6 +8,7 @@ macro_rules! force_eval { mod acos; mod acosf; +mod asin; mod asinf; mod atanf; mod cbrt; @@ -55,6 +56,7 @@ mod truncf; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; pub use self::acosf::acosf; +pub use self::asin::asin; pub use self::asinf::asinf; pub use self::atanf::atanf; pub use self::cbrt::cbrt; @@ -109,3 +111,29 @@ use self::{ k_cosf::k_cosf, k_sinf::k_sinf, k_tanf::k_tanf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f, }; + +#[inline] +pub fn get_high_word(x: f64) -> u32 { + (x.to_bits() >> 32) as u32 +} + +#[inline] +pub fn get_low_word(x: f64) -> u32 { + x.to_bits() as u32 +} + +#[inline] +pub fn with_set_high_word(f: f64, hi: u32) -> f64 { + let mut tmp = f.to_bits(); + tmp &= 0x00000000_ffffffff; + tmp |= (hi as u64) << 32; + f64::from_bits(tmp) +} + +#[inline] +pub fn with_set_low_word(f: f64, lo: u32) -> f64 { + let mut tmp = f.to_bits(); + tmp &= 0xffffffff_00000000; + tmp |= lo as u64; + f64::from_bits(tmp) +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 0f93606500f..b639cf11b19 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -698,7 +698,7 @@ f32i32_f32! { // With signature `fn(f64) -> f64` f64_f64! { acos, - // asin, + asin, // atan, cbrt, ceil, -- cgit 1.4.1-3-g733a5 From 802f6a2b46689fed5a37fbea4c0aa7a64a8522db Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 14 Jul 2018 16:58:24 -0500 Subject: v0.1.1 --- library/compiler-builtins/libm/CHANGELOG.md | 38 ++++++++++++++++++++++++++++- library/compiler-builtins/libm/Cargo.toml | 2 +- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index c3e74a81433..3a496527bc0 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -5,8 +5,44 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.1.1] - 2018-07-14 + +### Added + +- acos +- acosf +- asin +- asinf +- atanf +- cbrt +- cbrtf +- ceil +- ceilf +- cosf +- exp +- exp2 +- exp2f +- expm1 +- expm1f +- fdim +- fdimf +- floorf +- fma +- fmod +- log +- log2 +- log10 +- log10f +- log1p +- log1pf +- log2f +- roundf +- sinf +- tanf + ## v0.1.0 - 2018-07-13 - Initial release -[Unreleased]: https://github.com/japaric/libm/compare/v0.1.0...HEAD +[Unreleased]: https://github.com/japaric/libm/compare/v0.1.1...HEAD +[v0.1.1]: https://github.com/japaric/libm/compare/v0.1.0...v0.1.1 diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 5a1ae4a6c92..a82fc99a7e7 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" repository = "https://github.com/japaric/libm" -version = "0.1.0" +version = "0.1.1" [workspace] members = ["cb", "test-generator"] \ No newline at end of file -- cgit 1.4.1-3-g733a5 From 440a1b7273e663ce0c7680aba62efe744d2ab556 Mon Sep 17 00:00:00 2001 From: C Jones Date: Fri, 13 Jul 2018 22:10:30 -0400 Subject: Implement part of sin/cos with quadrant selection unimplemented --- library/compiler-builtins/libm/src/lib.rs | 4 - library/compiler-builtins/libm/src/math/cos.rs | 73 ++++++ library/compiler-builtins/libm/src/math/mod.rs | 14 +- library/compiler-builtins/libm/src/math/sin.rs | 80 ++++++ .../compiler-builtins/libm/src/math/trig_common.rs | 289 +++++++++++++++++++++ 5 files changed, 452 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/cos.rs create mode 100644 library/compiler-builtins/libm/src/math/sin.rs create mode 100644 library/compiler-builtins/libm/src/math/trig_common.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index df7ee813fba..0b9efeeb338 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -386,10 +386,8 @@ pub trait F64Ext: private::Sealed { fn hypot(self, other: Self) -> Self; - #[cfg(todo)] fn sin(self) -> Self; - #[cfg(todo)] fn cos(self) -> Self; #[cfg(todo)] @@ -548,13 +546,11 @@ impl F64Ext for f64 { hypot(self, other) } - #[cfg(todo)] #[inline] fn sin(self) -> Self { sin(self) } - #[cfg(todo)] #[inline] fn cos(self) -> Self { cos(self) diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs new file mode 100644 index 00000000000..91412c6489a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cos.rs @@ -0,0 +1,73 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use math::trig_common::{_cos, _sin, rem_pio2}; + +// cos(x) +// Return cosine function of x. +// +// kernel function: +// __sin ... sine function on [-pi/4,pi/4] +// __cos ... cosine function on [-pi/4,pi/4] +// __rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded +// +pub fn cos(x: f64) -> f64 { + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e46a09e { + /* if x < 2**-27 * sqrt(2) */ + /* raise inexact if x != 0 */ + if x as i32 == 0 { + return 1.0; + } + } + return _cos(x, 0.0); + } + + /* cos(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + match n & 3 { + 0 => _cos(y0, y1), + 1 => -_sin(y0, y1, 1), + 2 => -_cos(y0, y1), + _ => _sin(y0, y1, 1), + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 42c596857d7..a657da810e3 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -15,6 +15,7 @@ mod cbrt; mod cbrtf; mod ceil; mod ceilf; +mod cos; mod cosf; mod exp; mod exp2; @@ -46,6 +47,7 @@ mod round; mod roundf; mod scalbn; mod scalbnf; +mod sin; mod sinf; mod sqrt; mod sqrtf; @@ -63,6 +65,7 @@ pub use self::cbrt::cbrt; pub use self::cbrtf::cbrtf; pub use self::ceil::ceil; pub use self::ceilf::ceilf; +pub use self::cos::cos; pub use self::cosf::cosf; pub use self::exp::exp; pub use self::exp2::exp2; @@ -94,6 +97,7 @@ pub use self::round::round; pub use self::roundf::roundf; pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; +pub use self::sin::sin; pub use self::sinf::sinf; pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; @@ -106,11 +110,13 @@ mod k_sinf; mod k_tanf; mod rem_pio2_large; mod rem_pio2f; +mod trig_common; -use self::{ - k_cosf::k_cosf, k_sinf::k_sinf, k_tanf::k_tanf, rem_pio2_large::rem_pio2_large, - rem_pio2f::rem_pio2f, -}; +use self::k_cosf::k_cosf; +use self::k_sinf::k_sinf; +use self::k_tanf::k_tanf; +use self::rem_pio2_large::rem_pio2_large; +use self::rem_pio2f::rem_pio2f; #[inline] pub fn get_high_word(x: f64) -> u32 { diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs new file mode 100644 index 00000000000..0717c1ae3ed --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -0,0 +1,80 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f64; + +use math::trig_common::{_cos, _sin, rem_pio2}; + +// sin(x) +// Return sine function of x. +// +// kernel function: +// __sin ... sine function on [-pi/4,pi/4] +// __cos ... cose function on [-pi/4,pi/4] +// __rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded +pub fn sin(x: f64) -> f64 { + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 + + /* High word of x. */ + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e500000 { + /* |x| < 2**-26 */ + /* raise inexact if x != 0 and underflow if subnormal*/ + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return x; + } + return _sin(x, 0.0, 0); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + match n & 3 { + 0 => _sin(y0, y1, 1), + 1 => _cos(y0, y1), + 2 => -_sin(y0, y1, 1), + _ => -_cos(y0, y1), + } +} diff --git a/library/compiler-builtins/libm/src/math/trig_common.rs b/library/compiler-builtins/libm/src/math/trig_common.rs new file mode 100644 index 00000000000..59e75e2dd6b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/trig_common.rs @@ -0,0 +1,289 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */ + +const S1: f64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ +const S2: f64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ +const S3: f64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ +const S4: f64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ +const S5: f64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ +const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// Input iy indicates whether y is 0. (if iy=0, y assume to be 0). +// +// Algorithm +// 1. Since sin(-x) = -sin(x), we need only to consider positive x. +// 2. Callers must return sin(-0) = -0 without calling here since our +// odd polynomial is not evaluated in a way that preserves -0. +// Callers may do the optimization sin(x) ~ x for tiny x. +// 3. sin(x) is approximated by a polynomial of degree 13 on +// [0,pi/4] +// 3 13 +// sin(x) ~ x + S1*x + ... + S6*x +// where +// +// |sin(x) 2 4 6 8 10 12 | -58 +// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 +// | x | +// +// 4. sin(x+y) = sin(x) + sin'(x')*y +// ~ sin(x) + (1-x*x/2)*y +// For better accuracy, let +// 3 2 2 2 2 +// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) +// then 3 2 +// sin(x) = x + (S1*x + (x *(r-y/2)+y)) +pub fn _sin(x: f64, y: f64, iy: i32) -> f64 { + let z = x * x; + let w = z * z; + let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); + let v = z * x; + if iy == 0 { + x + v * (S1 + z * r) + } else { + x - ((z * (0.5 * y - v * r) - y) - v * S1) + } +} + +/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */ +const C1: f64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ +const C2: f64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ +const C3: f64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ +const C4: f64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ +const C5: f64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ +const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// +// Algorithm +// 1. Since cos(-x) = cos(x), we need only to consider positive x. +// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. +// 3. cos(x) is approximated by a polynomial of degree 14 on +// [0,pi/4] +// 4 14 +// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x +// where the remez error is +// +// | 2 4 6 8 10 12 14 | -58 +// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 +// | | +// +// 4 6 8 10 12 14 +// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then +// cos(x) ~ 1 - x*x/2 + r +// since cos(x+y) ~ cos(x) - sin(x)*y +// ~ cos(x) - x*y, +// a correction term is necessary in cos(x) and hence +// cos(x+y) = 1 - (x*x/2 - (r - x*y)) +// For better accuracy, rearrange to +// cos(x+y) ~ w + (tmp + (r-x*y)) +// where w = 1 - x*x/2 and tmp is a tiny correction term +// (1 - x*x/2 == w + tmp exactly in infinite precision). +// The exactness of w + tmp in infinite precision depends on w +// and tmp having the same precision as x. If they have extra +// precision due to compiler bugs, then the extra precision is +// only good provided it is retained in all terms of the final +// expression for cos(). Retention happens in all cases tested +// under FreeBSD, so don't pessimize things by forcibly clipping +// any extra precision in w. +pub fn _cos(x: f64, y: f64) -> f64 { + let z = x * x; + let w = z * z; + let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); + let hz = 0.5 * z; + let w = 1.0 - hz; + w + (((1.0 - w) - hz) + (z * r - x * y)) +} + +// origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c +// Optimized by Bruce D. Evans. */ + +// #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +// #define EPS DBL_EPSILON +const EPS: f64 = 2.2204460492503131e-16; +// #elif FLT_EVAL_METHOD==2 +// #define EPS LDBL_EPSILON +// #endif + +// TODO: Support FLT_EVAL_METHOD? + +#[allow(unused, non_upper_case_globals)] +const toint: f64 = 1.5 / EPS; +/// 53 bits of 2/pi +#[allow(unused, non_upper_case_globals)] +const invpio2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +/// first 33 bits of pi/2 +#[allow(unused, non_upper_case_globals)] +const pio2_1: f64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ +/// pi/2 - pio2_1 +#[allow(unused, non_upper_case_globals)] +const pio2_1t: f64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ +/// second 33 bits of pi/2 +#[allow(unused, non_upper_case_globals)] +const pio2_2: f64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ +/// pi/2 - (pio2_1+pio2_2) +#[allow(unused, non_upper_case_globals)] +const pio2_2t: f64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ +/// third 33 bits of pi/2 +#[allow(unused, non_upper_case_globals)] +const pio2_3: f64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ +/// pi/2 - (pio2_1+pio2_2+pio2_3) +#[allow(unused, non_upper_case_globals)] +const pio2_3t: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +/* __rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __rem_pio2_large() for large x + */ + +/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +/* +{ + union {double f; uint64_t i;} u = {x}; + double_t z,w,t,r,fn; + double tx[3],ty[2]; + uint32_t ix; + int sign, n, ex, ey, i; + + sign = u.i>>63; + ix = u.i>>32 & 0x7fffffff; + if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */ + if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */ + goto medium; /* cancellation -- use medium case */ + if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */ + if (!sign) { + z = x - pio2_1; /* one round good to 85 bits */ + y[0] = z - pio2_1t; + y[1] = (z-y[0]) - pio2_1t; + return 1; + } else { + z = x + pio2_1; + y[0] = z + pio2_1t; + y[1] = (z-y[0]) + pio2_1t; + return -1; + } + } else { + if (!sign) { + z = x - 2*pio2_1; + y[0] = z - 2*pio2_1t; + y[1] = (z-y[0]) - 2*pio2_1t; + return 2; + } else { + z = x + 2*pio2_1; + y[0] = z + 2*pio2_1t; + y[1] = (z-y[0]) + 2*pio2_1t; + return -2; + } + } + } + if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */ + if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */ + if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */ + goto medium; + if (!sign) { + z = x - 3*pio2_1; + y[0] = z - 3*pio2_1t; + y[1] = (z-y[0]) - 3*pio2_1t; + return 3; + } else { + z = x + 3*pio2_1; + y[0] = z + 3*pio2_1t; + y[1] = (z-y[0]) + 3*pio2_1t; + return -3; + } + } else { + if (ix == 0x401921fb) /* |x| ~= 4pi/2 */ + goto medium; + if (!sign) { + z = x - 4*pio2_1; + y[0] = z - 4*pio2_1t; + y[1] = (z-y[0]) - 4*pio2_1t; + return 4; + } else { + z = x + 4*pio2_1; + y[0] = z + 4*pio2_1t; + y[1] = (z-y[0]) + 4*pio2_1t; + return -4; + } + } + } + if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ +medium: + /* rint(x/(pi/2)), Assume round-to-nearest. */ + fn = (double_t)x*invpio2 + toint - toint; + n = (int32_t)fn; + r = x - fn*pio2_1; + w = fn*pio2_1t; /* 1st round, good to 85 bits */ + y[0] = r - w; + u.f = y[0]; + ey = u.i>>52 & 0x7ff; + ex = ix>>20; + if (ex - ey > 16) { /* 2nd round, good to 118 bits */ + t = r; + w = fn*pio2_2; + r = t - w; + w = fn*pio2_2t - ((t-r)-w); + y[0] = r - w; + u.f = y[0]; + ey = u.i>>52 & 0x7ff; + if (ex - ey > 49) { /* 3rd round, good to 151 bits, covers all cases */ + t = r; + w = fn*pio2_3; + r = t - w; + w = fn*pio2_3t - ((t-r)-w); + y[0] = r - w; + } + } + y[1] = (r - y[0]) - w; + return n; + } + /* + * all other (large) arguments + */ + if (ix >= 0x7ff00000) { /* x is inf or NaN */ + y[0] = y[1] = x - x; + return 0; + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + u.f = x; + u.i &= (uint64_t)-1>>12; + u.i |= (uint64_t)(0x3ff + 23)<<52; + z = u.f; + for (i=0; i < 2; i++) { + tx[i] = (double)(int32_t)z; + z = (z-tx[i])*0x1p24; + } + tx[i] = z; + /* skip zero terms, first term is non-zero */ + while (tx[i] == 0.0) + i--; + n = __rem_pio2_large(tx,ty,(int)(ix>>20)-(0x3ff+23),i+1,1); + if (sign) { + y[0] = -ty[0]; + y[1] = -ty[1]; + return -n; + } + y[0] = ty[0]; + y[1] = ty[1]; + return n; +} +*/ + +pub fn rem_pio2(_x: f64) -> (i32, f64, f64) { + unimplemented!() +} -- cgit 1.4.1-3-g733a5 From b2751897d2fde5c7aa0ec30b7d45b714011cd0dd Mon Sep 17 00:00:00 2001 From: C Jones Date: Fri, 13 Jul 2018 23:03:21 -0400 Subject: Convert rem_pio2 code, split up modules --- library/compiler-builtins/libm/src/math/cos.rs | 39 ++- library/compiler-builtins/libm/src/math/exp2.rs | 2 +- library/compiler-builtins/libm/src/math/k_cos.rs | 62 +++++ library/compiler-builtins/libm/src/math/k_sin.rs | 57 ++++ library/compiler-builtins/libm/src/math/mod.rs | 10 +- .../compiler-builtins/libm/src/math/rem_pio2.rs | 187 +++++++++++++ library/compiler-builtins/libm/src/math/sin.rs | 41 ++- .../compiler-builtins/libm/src/math/trig_common.rs | 289 --------------------- .../libm/test-generator/src/main.rs | 4 +- 9 files changed, 356 insertions(+), 335 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/k_cos.rs create mode 100644 library/compiler-builtins/libm/src/math/k_sin.rs create mode 100644 library/compiler-builtins/libm/src/math/rem_pio2.rs delete mode 100644 library/compiler-builtins/libm/src/math/trig_common.rs diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs index 91412c6489a..e6e9b373674 100644 --- a/library/compiler-builtins/libm/src/math/cos.rs +++ b/library/compiler-builtins/libm/src/math/cos.rs @@ -1,24 +1,23 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ +// origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */ +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== -use math::trig_common::{_cos, _sin, rem_pio2}; +use super::{k_cos, k_sin, rem_pio2}; // cos(x) // Return cosine function of x. // // kernel function: -// __sin ... sine function on [-pi/4,pi/4] -// __cos ... cosine function on [-pi/4,pi/4] -// __rem_pio2 ... argument reduction routine +// k_sin ... sine function on [-pi/4,pi/4] +// k_cos ... cosine function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine // // Method. // Let S,C and T denote the sin, cos and tan respectively on @@ -54,7 +53,7 @@ pub fn cos(x: f64) -> f64 { return 1.0; } } - return _cos(x, 0.0); + return k_cos(x, 0.0); } /* cos(Inf or NaN) is NaN */ @@ -65,9 +64,9 @@ pub fn cos(x: f64) -> f64 { /* argument reduction needed */ let (n, y0, y1) = rem_pio2(x); match n & 3 { - 0 => _cos(y0, y1), - 1 => -_sin(y0, y1, 1), - 2 => -_cos(y0, y1), - _ => _sin(y0, y1, 1), + 0 => k_cos(y0, y1), + 1 => -k_sin(y0, y1, 1), + 2 => -k_cos(y0, y1), + _ => k_sin(y0, y1, 1), } } diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index 0ab11989679..3952e93007e 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -24,7 +24,7 @@ // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. -use super::scalbn::scalbn; +use super::scalbn; const TBLSIZE: usize = 256; diff --git a/library/compiler-builtins/libm/src/math/k_cos.rs b/library/compiler-builtins/libm/src/math/k_cos.rs new file mode 100644 index 00000000000..693950d1d41 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_cos.rs @@ -0,0 +1,62 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_cos.c +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunSoft, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +const C1: f64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ +const C2: f64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ +const C3: f64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ +const C4: f64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ +const C5: f64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ +const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// +// Algorithm +// 1. Since cos(-x) = cos(x), we need only to consider positive x. +// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. +// 3. cos(x) is approximated by a polynomial of degree 14 on +// [0,pi/4] +// 4 14 +// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x +// where the remez error is +// +// | 2 4 6 8 10 12 14 | -58 +// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 +// | | +// +// 4 6 8 10 12 14 +// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then +// cos(x) ~ 1 - x*x/2 + r +// since cos(x+y) ~ cos(x) - sin(x)*y +// ~ cos(x) - x*y, +// a correction term is necessary in cos(x) and hence +// cos(x+y) = 1 - (x*x/2 - (r - x*y)) +// For better accuracy, rearrange to +// cos(x+y) ~ w + (tmp + (r-x*y)) +// where w = 1 - x*x/2 and tmp is a tiny correction term +// (1 - x*x/2 == w + tmp exactly in infinite precision). +// The exactness of w + tmp in infinite precision depends on w +// and tmp having the same precision as x. If they have extra +// precision due to compiler bugs, then the extra precision is +// only good provided it is retained in all terms of the final +// expression for cos(). Retention happens in all cases tested +// under FreeBSD, so don't pessimize things by forcibly clipping +// any extra precision in w. +#[inline] +pub fn k_cos(x: f64, y: f64) -> f64 { + let z = x * x; + let w = z * z; + let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); + let hz = 0.5 * z; + let w = 1.0 - hz; + w + (((1.0 - w) - hz) + (z * r - x * y)) +} diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs new file mode 100644 index 00000000000..3e07c359447 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_sin.rs @@ -0,0 +1,57 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_sin.c +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunSoft, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +const S1: f64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ +const S2: f64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ +const S3: f64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ +const S4: f64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ +const S5: f64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ +const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// Input iy indicates whether y is 0. (if iy=0, y assume to be 0). +// +// Algorithm +// 1. Since sin(-x) = -sin(x), we need only to consider positive x. +// 2. Callers must return sin(-0) = -0 without calling here since our +// odd polynomial is not evaluated in a way that preserves -0. +// Callers may do the optimization sin(x) ~ x for tiny x. +// 3. sin(x) is approximated by a polynomial of degree 13 on +// [0,pi/4] +// 3 13 +// sin(x) ~ x + S1*x + ... + S6*x +// where +// +// |sin(x) 2 4 6 8 10 12 | -58 +// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 +// | x | +// +// 4. sin(x+y) = sin(x) + sin'(x')*y +// ~ sin(x) + (1-x*x/2)*y +// For better accuracy, let +// 3 2 2 2 2 +// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) +// then 3 2 +// sin(x) = x + (S1*x + (x *(r-y/2)+y)) +#[inline] +pub fn k_sin(x: f64, y: f64, iy: i32) -> f64 { + let z = x * x; + let w = z * z; + let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); + let v = z * x; + if iy == 0 { + x + v * (S1 + z * r) + } else { + x - ((z * (0.5 * y - v * r) - y) - v * S1) + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index a657da810e3..7b3d9abee69 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -6,6 +6,7 @@ macro_rules! force_eval { }; } +// Public modules mod acos; mod acosf; mod asin; @@ -105,16 +106,23 @@ pub use self::tanf::tanf; pub use self::trunc::trunc; pub use self::truncf::truncf; +// Private modules +mod k_cos; mod k_cosf; +mod k_sin; mod k_sinf; mod k_tanf; +mod rem_pio2; mod rem_pio2_large; mod rem_pio2f; -mod trig_common; +// Private re-imports +use self::k_cos::k_cos; use self::k_cosf::k_cosf; +use self::k_sin::k_sin; use self::k_sinf::k_sinf; use self::k_tanf::k_tanf; +use self::rem_pio2::rem_pio2; use self::rem_pio2_large::rem_pio2_large; use self::rem_pio2f::rem_pio2f; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs new file mode 100644 index 00000000000..68db7056b63 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -0,0 +1,187 @@ +// origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== +// +// Optimized by Bruce D. Evans. */ + +use super::rem_pio2_large; + +// #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +// #define EPS DBL_EPSILON +const EPS: f64 = 2.2204460492503131e-16; +// #elif FLT_EVAL_METHOD==2 +// #define EPS LDBL_EPSILON +// #endif + +// TODO: Support FLT_EVAL_METHOD? + +const TO_INT: f64 = 1.5 / EPS; +/// 53 bits of 2/pi +const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +/// first 33 bits of pi/2 +const PIO2_1: f64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ +/// pi/2 - PIO2_1 +const PIO2_1T: f64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ +/// second 33 bits of pi/2 +const PIO2_2: f64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ +/// pi/2 - (PIO2_1+PIO2_2) +const PIO2_2T: f64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ +/// third 33 bits of pi/2 +const PIO2_3: f64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ +/// pi/2 - (PIO2_1+PIO2_2+PIO2_3) +const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +// return the remainder of x rem pi/2 in y[0]+y[1] +// use rem_pio2_large() for large x +// +// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +pub fn rem_pio2(x: f64) -> (i32, f64, f64) { + let x1p24 = f64::from_bits(0x7041); + + let sign = (f64::to_bits(x) >> 63) as i32; + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + fn medium(x: f64, ix: u32) -> (i32, f64, f64) { + /* rint(x/(pi/2)), Assume round-to-nearest. */ + let f_n = x as f64 * INV_PIO2 + TO_INT - TO_INT; + let n = f_n as i32; + let mut r = x - f_n * PIO2_1; + let mut w = f_n * PIO2_1T; /* 1st round, good to 85 bits */ + let mut y0 = r - w; + let ui = f64::to_bits(y0); + let ey = (ui >> 52) as i32 & 0x7ff; + let ex = (ix >> 20) as i32; + if ex - ey > 16 { + /* 2nd round, good to 118 bits */ + let t = r; + w = f_n * PIO2_2; + r = t - w; + w = f_n * PIO2_2T - ((t - r) - w); + y0 = r - w; + let ey = (f64::to_bits(y0) >> 52) as i32 & 0x7ff; + if ex - ey > 49 { + /* 3rd round, good to 151 bits, covers all cases */ + let t = r; + w = f_n * PIO2_3; + r = t - w; + w = f_n * PIO2_3T - ((t - r) - w); + y0 = r - w; + } + } + let y1 = (r - y0) - w; + return (n, y0, y1); + } + + if ix <= 0x400f6a7a { + /* |x| ~<= 5pi/4 */ + if (ix & 0xfffff) == 0x921fb { + /* |x| ~= pi/2 or 2pi/2 */ + medium(x, ix); /* cancellation -- use medium case */ + } + if ix <= 0x4002d97c { + /* |x| ~<= 3pi/4 */ + if sign == 0 { + let z = x - PIO2_1; /* one round good to 85 bits */ + let y0 = z - PIO2_1T; + let y1 = (z - y0) - PIO2_1T; + return (1, y0, y1); + } else { + let z = x + PIO2_1; + let y0 = z + PIO2_1T; + let y1 = (z - y0) + PIO2_1T; + return (-1, y0, y1); + } + } else { + if sign == 0 { + let z = x - 2.0 * PIO2_1; + let y0 = z - 2.0 * PIO2_1T; + let y1 = (z - y0) - 2.0 * PIO2_1T; + return (2, y0, y1); + } else { + let z = x + 2.0 * PIO2_1; + let y0 = z + 2.0 * PIO2_1T; + let y1 = (z - y0) + 2.0 * PIO2_1T; + return (-2, y0, y1); + } + } + } + if ix <= 0x401c463b { + /* |x| ~<= 9pi/4 */ + if ix <= 0x4015fdbc { + /* |x| ~<= 7pi/4 */ + if ix == 0x4012d97c { + /* |x| ~= 3pi/2 */ + return medium(x, ix); + } + if sign == 0 { + let z = x - 3.0 * PIO2_1; + let y0 = z - 3.0 * PIO2_1T; + let y1 = (z - y0) - 3.0 * PIO2_1T; + return (3, y0, y1); + } else { + let z = x + 3.0 * PIO2_1; + let y0 = z + 3.0 * PIO2_1T; + let y1 = (z - y0) + 3.0 * PIO2_1T; + return (-3, y0, y1); + } + } else { + if ix == 0x401921fb { + /* |x| ~= 4pi/2 */ + return medium(x, ix); + } + if sign == 0 { + let z = x - 4.0 * PIO2_1; + let y0 = z - 4.0 * PIO2_1T; + let y1 = (z - y0) - 4.0 * PIO2_1T; + return (4, y0, y1); + } else { + let z = x + 4.0 * PIO2_1; + let y0 = z + 4.0 * PIO2_1T; + let y1 = (z - y0) + 4.0 * PIO2_1T; + return (-4, y0, y1); + } + } + } + if ix < 0x413921fb { + /* |x| ~< 2^20*(pi/2), medium size */ + return medium(x, ix); + } + /* + * all other (large) arguments + */ + if ix >= 0x7ff00000 { + /* x is inf or NaN */ + let y0 = x - x; + let y1 = y0; + return (0, y0, y1); + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + let mut ui = f64::to_bits(x); + ui &= (!1) >> 12; + ui |= (0x3ff + 23) << 52; + let mut z = f64::from_bits(ui); + let mut tx = [0.0; 3]; + for i in 0..2 { + tx[i] = z as i32 as f64; + z = (z - tx[i]) * x1p24; + } + tx[2] = z; + /* skip zero terms, first term is non-zero */ + let mut i = 2; + while tx[i] == 0.0 { + i -= 1; + } + let mut ty = [0.0; 3]; + let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix >> 20) - (0x3ff + 23)) as i32, 1); + if sign != 0 { + return (-n, -ty[0], -ty[1]); + } + return (n, ty[0], ty[1]); +} diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index 0717c1ae3ed..13eb30248ab 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -1,26 +1,23 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::f64; +// origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== -use math::trig_common::{_cos, _sin, rem_pio2}; +use super::{k_cos, k_sin, rem_pio2}; // sin(x) // Return sine function of x. // // kernel function: -// __sin ... sine function on [-pi/4,pi/4] -// __cos ... cose function on [-pi/4,pi/4] -// __rem_pio2 ... argument reduction routine +// k_sin ... sine function on [-pi/4,pi/4] +// k_cos ... cose function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine // // Method. // Let S,C and T denote the sin, cos and tan respectively on @@ -61,7 +58,7 @@ pub fn sin(x: f64) -> f64 { } return x; } - return _sin(x, 0.0, 0); + return k_sin(x, 0.0, 0); } /* sin(Inf or NaN) is NaN */ @@ -72,9 +69,9 @@ pub fn sin(x: f64) -> f64 { /* argument reduction needed */ let (n, y0, y1) = rem_pio2(x); match n & 3 { - 0 => _sin(y0, y1, 1), - 1 => _cos(y0, y1), - 2 => -_sin(y0, y1, 1), - _ => -_cos(y0, y1), + 0 => k_sin(y0, y1, 1), + 1 => k_cos(y0, y1), + 2 => -k_sin(y0, y1, 1), + _ => -k_cos(y0, y1), } } diff --git a/library/compiler-builtins/libm/src/math/trig_common.rs b/library/compiler-builtins/libm/src/math/trig_common.rs deleted file mode 100644 index 59e75e2dd6b..00000000000 --- a/library/compiler-builtins/libm/src/math/trig_common.rs +++ /dev/null @@ -1,289 +0,0 @@ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */ - -const S1: f64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ -const S2: f64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ -const S3: f64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ -const S4: f64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ -const S5: f64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ -const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ - -// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 -// Input x is assumed to be bounded by ~pi/4 in magnitude. -// Input y is the tail of x. -// Input iy indicates whether y is 0. (if iy=0, y assume to be 0). -// -// Algorithm -// 1. Since sin(-x) = -sin(x), we need only to consider positive x. -// 2. Callers must return sin(-0) = -0 without calling here since our -// odd polynomial is not evaluated in a way that preserves -0. -// Callers may do the optimization sin(x) ~ x for tiny x. -// 3. sin(x) is approximated by a polynomial of degree 13 on -// [0,pi/4] -// 3 13 -// sin(x) ~ x + S1*x + ... + S6*x -// where -// -// |sin(x) 2 4 6 8 10 12 | -58 -// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 -// | x | -// -// 4. sin(x+y) = sin(x) + sin'(x')*y -// ~ sin(x) + (1-x*x/2)*y -// For better accuracy, let -// 3 2 2 2 2 -// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) -// then 3 2 -// sin(x) = x + (S1*x + (x *(r-y/2)+y)) -pub fn _sin(x: f64, y: f64, iy: i32) -> f64 { - let z = x * x; - let w = z * z; - let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); - let v = z * x; - if iy == 0 { - x + v * (S1 + z * r) - } else { - x - ((z * (0.5 * y - v * r) - y) - v * S1) - } -} - -/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */ -const C1: f64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ -const C2: f64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ -const C3: f64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ -const C4: f64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ -const C5: f64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ -const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ - -// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 -// Input x is assumed to be bounded by ~pi/4 in magnitude. -// Input y is the tail of x. -// -// Algorithm -// 1. Since cos(-x) = cos(x), we need only to consider positive x. -// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. -// 3. cos(x) is approximated by a polynomial of degree 14 on -// [0,pi/4] -// 4 14 -// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x -// where the remez error is -// -// | 2 4 6 8 10 12 14 | -58 -// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 -// | | -// -// 4 6 8 10 12 14 -// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then -// cos(x) ~ 1 - x*x/2 + r -// since cos(x+y) ~ cos(x) - sin(x)*y -// ~ cos(x) - x*y, -// a correction term is necessary in cos(x) and hence -// cos(x+y) = 1 - (x*x/2 - (r - x*y)) -// For better accuracy, rearrange to -// cos(x+y) ~ w + (tmp + (r-x*y)) -// where w = 1 - x*x/2 and tmp is a tiny correction term -// (1 - x*x/2 == w + tmp exactly in infinite precision). -// The exactness of w + tmp in infinite precision depends on w -// and tmp having the same precision as x. If they have extra -// precision due to compiler bugs, then the extra precision is -// only good provided it is retained in all terms of the final -// expression for cos(). Retention happens in all cases tested -// under FreeBSD, so don't pessimize things by forcibly clipping -// any extra precision in w. -pub fn _cos(x: f64, y: f64) -> f64 { - let z = x * x; - let w = z * z; - let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); - let hz = 0.5 * z; - let w = 1.0 - hz; - w + (((1.0 - w) - hz) + (z * r - x * y)) -} - -// origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c -// Optimized by Bruce D. Evans. */ - -// #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 -// #define EPS DBL_EPSILON -const EPS: f64 = 2.2204460492503131e-16; -// #elif FLT_EVAL_METHOD==2 -// #define EPS LDBL_EPSILON -// #endif - -// TODO: Support FLT_EVAL_METHOD? - -#[allow(unused, non_upper_case_globals)] -const toint: f64 = 1.5 / EPS; -/// 53 bits of 2/pi -#[allow(unused, non_upper_case_globals)] -const invpio2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ -/// first 33 bits of pi/2 -#[allow(unused, non_upper_case_globals)] -const pio2_1: f64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ -/// pi/2 - pio2_1 -#[allow(unused, non_upper_case_globals)] -const pio2_1t: f64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ -/// second 33 bits of pi/2 -#[allow(unused, non_upper_case_globals)] -const pio2_2: f64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ -/// pi/2 - (pio2_1+pio2_2) -#[allow(unused, non_upper_case_globals)] -const pio2_2t: f64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ -/// third 33 bits of pi/2 -#[allow(unused, non_upper_case_globals)] -const pio2_3: f64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ -/// pi/2 - (pio2_1+pio2_2+pio2_3) -#[allow(unused, non_upper_case_globals)] -const pio2_3t: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ - -/* __rem_pio2(x,y) - * - * return the remainder of x rem pi/2 in y[0]+y[1] - * use __rem_pio2_large() for large x - */ - -/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ -/* -{ - union {double f; uint64_t i;} u = {x}; - double_t z,w,t,r,fn; - double tx[3],ty[2]; - uint32_t ix; - int sign, n, ex, ey, i; - - sign = u.i>>63; - ix = u.i>>32 & 0x7fffffff; - if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */ - if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */ - goto medium; /* cancellation -- use medium case */ - if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */ - if (!sign) { - z = x - pio2_1; /* one round good to 85 bits */ - y[0] = z - pio2_1t; - y[1] = (z-y[0]) - pio2_1t; - return 1; - } else { - z = x + pio2_1; - y[0] = z + pio2_1t; - y[1] = (z-y[0]) + pio2_1t; - return -1; - } - } else { - if (!sign) { - z = x - 2*pio2_1; - y[0] = z - 2*pio2_1t; - y[1] = (z-y[0]) - 2*pio2_1t; - return 2; - } else { - z = x + 2*pio2_1; - y[0] = z + 2*pio2_1t; - y[1] = (z-y[0]) + 2*pio2_1t; - return -2; - } - } - } - if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */ - if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */ - if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */ - goto medium; - if (!sign) { - z = x - 3*pio2_1; - y[0] = z - 3*pio2_1t; - y[1] = (z-y[0]) - 3*pio2_1t; - return 3; - } else { - z = x + 3*pio2_1; - y[0] = z + 3*pio2_1t; - y[1] = (z-y[0]) + 3*pio2_1t; - return -3; - } - } else { - if (ix == 0x401921fb) /* |x| ~= 4pi/2 */ - goto medium; - if (!sign) { - z = x - 4*pio2_1; - y[0] = z - 4*pio2_1t; - y[1] = (z-y[0]) - 4*pio2_1t; - return 4; - } else { - z = x + 4*pio2_1; - y[0] = z + 4*pio2_1t; - y[1] = (z-y[0]) + 4*pio2_1t; - return -4; - } - } - } - if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ -medium: - /* rint(x/(pi/2)), Assume round-to-nearest. */ - fn = (double_t)x*invpio2 + toint - toint; - n = (int32_t)fn; - r = x - fn*pio2_1; - w = fn*pio2_1t; /* 1st round, good to 85 bits */ - y[0] = r - w; - u.f = y[0]; - ey = u.i>>52 & 0x7ff; - ex = ix>>20; - if (ex - ey > 16) { /* 2nd round, good to 118 bits */ - t = r; - w = fn*pio2_2; - r = t - w; - w = fn*pio2_2t - ((t-r)-w); - y[0] = r - w; - u.f = y[0]; - ey = u.i>>52 & 0x7ff; - if (ex - ey > 49) { /* 3rd round, good to 151 bits, covers all cases */ - t = r; - w = fn*pio2_3; - r = t - w; - w = fn*pio2_3t - ((t-r)-w); - y[0] = r - w; - } - } - y[1] = (r - y[0]) - w; - return n; - } - /* - * all other (large) arguments - */ - if (ix >= 0x7ff00000) { /* x is inf or NaN */ - y[0] = y[1] = x - x; - return 0; - } - /* set z = scalbn(|x|,-ilogb(x)+23) */ - u.f = x; - u.i &= (uint64_t)-1>>12; - u.i |= (uint64_t)(0x3ff + 23)<<52; - z = u.f; - for (i=0; i < 2; i++) { - tx[i] = (double)(int32_t)z; - z = (z-tx[i])*0x1p24; - } - tx[i] = z; - /* skip zero terms, first term is non-zero */ - while (tx[i] == 0.0) - i--; - n = __rem_pio2_large(tx,ty,(int)(ix>>20)-(0x3ff+23),i+1,1); - if (sign) { - y[0] = -ty[0]; - y[1] = -ty[1]; - return -n; - } - y[0] = ty[0]; - y[1] = ty[1]; - return n; -} -*/ - -pub fn rem_pio2(_x: f64) -> (i32, f64, f64) { - unimplemented!() -} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index b639cf11b19..c8e35cea7b0 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -702,7 +702,7 @@ f64_f64! { // atan, cbrt, ceil, - // cos, + cos, // cosh, exp, exp2, @@ -713,7 +713,7 @@ f64_f64! { log1p, log2, round, - // sin, + sin, // sinh, sqrt, // tan, -- cgit 1.4.1-3-g733a5 From 75428a13cf93a710deabaa2ab475984e1f26e18c Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 18:40:52 -0400 Subject: Fix x1p24 constant --- library/compiler-builtins/libm/src/math/rem_pio2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 68db7056b63..47bab6e65f1 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -43,7 +43,7 @@ const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ // // caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ pub fn rem_pio2(x: f64) -> (i32, f64, f64) { - let x1p24 = f64::from_bits(0x7041); + let x1p24 = f64::from_bits(0x4170000000000000); let sign = (f64::to_bits(x) >> 63) as i32; let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; -- cgit 1.4.1-3-g733a5 From b61b0046c0dbc98cca990131adee22cfc599c4ec Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 15 Jul 2018 02:06:20 +0300 Subject: coshf tanhf and atan2f --- library/compiler-builtins/libm/src/lib.rs | 6 -- library/compiler-builtins/libm/src/math/atan2f.rs | 71 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/coshf.rs | 33 ++++++++++ .../compiler-builtins/libm/src/math/k_expo2f.rs | 14 +++++ library/compiler-builtins/libm/src/math/mod.rs | 11 +++- library/compiler-builtins/libm/src/math/tanhf.rs | 39 ++++++++++++ .../libm/test-generator/src/main.rs | 6 +- 7 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/atan2f.rs create mode 100644 library/compiler-builtins/libm/src/math/coshf.rs create mode 100644 library/compiler-builtins/libm/src/math/k_expo2f.rs create mode 100644 library/compiler-builtins/libm/src/math/tanhf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index df7ee813fba..969e7c45b5e 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -96,7 +96,6 @@ pub trait F32Ext: private::Sealed { fn atan(self) -> Self; - #[cfg(todo)] fn atan2(self, other: Self) -> Self; #[cfg(todo)] @@ -112,10 +111,8 @@ pub trait F32Ext: private::Sealed { #[cfg(todo)] fn sinh(self) -> Self; - #[cfg(todo)] fn cosh(self) -> Self; - #[cfg(todo)] fn tanh(self) -> Self; #[cfg(todo)] @@ -272,7 +269,6 @@ impl F32Ext for f32 { atanf(self) } - #[cfg(todo)] #[inline] fn atan2(self, other: Self) -> Self { atan2f(self, other) @@ -294,13 +290,11 @@ impl F32Ext for f32 { sinhf(self) } - #[cfg(todo)] #[inline] fn cosh(self) -> Self { coshf(self) } - #[cfg(todo)] #[inline] fn tanh(self) -> Self { tanhf(self) diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs new file mode 100644 index 00000000000..a232ffdd61d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -0,0 +1,71 @@ +use super::atanf; +use super::fabsf; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ + +#[inline] +pub fn atan2f(y: f32, x: f32) -> f32 { + if x.is_nan() || y.is_nan() { + return x + y; + } + let mut ix = x.to_bits(); + let mut iy = y.to_bits(); + + if ix == 0x3f800000 { + /* x=1.0 */ + return atanf(y); + } + let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if iy == 0 { + return match m { + 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ + 2 => PI, /* atan(+0,-anything) = pi */ + 3 | _ => -PI, /* atan(-0,-anything) =-pi */ + }; + } + /* when x = 0 */ + if ix == 0 { + return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; + } + /* when x is INF */ + if ix == 0x7f800000 { + return if iy == 0x7f800000 { + match m { + 0 => PI / 4., /* atan(+INF,+INF) */ + 1 => -PI / 4., /* atan(-INF,+INF) */ + 2 => 3. * PI / 4., /* atan(+INF,-INF)*/ + 3 | _ => -3. * PI / 4., /* atan(-INF,-INF)*/ + } + } else { + match m { + 0 => 0., /* atan(+...,+INF) */ + 1 => -0., /* atan(-...,+INF) */ + 2 => PI, /* atan(+...,-INF) */ + 3 | _ => -PI, /* atan(-...,-INF) */ + } + }; + } + /* |y/x| > 0x1p26 */ + if (ix + (26 << 23) < iy) || (iy == 0x7f800000) { + return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; + } + + /* z = atan(|y/x|) with correct underflow */ + let z = if (m & 2 != 0) && (iy + (26 << 23) < ix) { + /*|y/x| < 0x1p-26, x < 0 */ + 0. + } else { + atanf(fabsf(y / x)) + }; + match m { + 0 => z, /* atan(+,+) */ + 1 => -z, /* atan(-,+) */ + 2 => PI - (z - PI_LO), /* atan(+,-) */ + _ => (z - PI_LO) - PI, /* case 3 */ /* atan(-,-) */ + } +} diff --git a/library/compiler-builtins/libm/src/math/coshf.rs b/library/compiler-builtins/libm/src/math/coshf.rs new file mode 100644 index 00000000000..bd468f5da71 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/coshf.rs @@ -0,0 +1,33 @@ +use super::expf; +use super::expm1f; +use super::k_expo2f; + +#[inline] +pub fn coshf(mut x: f32) -> f32 { + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + /* |x| */ + let mut ix = x.to_bits(); + ix &= 0x7fffffff; + x = f32::from_bits(ix); + let w = ix; + + /* |x| < log(2) */ + if w < 0x3f317217 { + if w < (0x3f800000 - (12 << 23)) { + force_eval!(x + x1p120); + return 1.; + } + let t = expm1f(x); + return 1. + t * t / (2. * (1. + t)); + } + + /* |x| < log(FLT_MAX) */ + if w < 0x42b17217 { + let t = expf(x); + return 0.5 * (t + 1. / t); + } + + /* |x| > log(FLT_MAX) or nan */ + k_expo2f(x) +} diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs new file mode 100644 index 00000000000..031a0bdd036 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -0,0 +1,14 @@ +use super::expf; + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +const K: i32 = 235; +const K_LN2: f32 = 162.89; /* 0x1.45c778p+7f */ + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +#[inline] +pub(crate) fn k_expo2f(x: f32) -> f32 { + /* note that k is odd and scale*scale overflows */ + let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); + /* exp(x - k ln2) * 2**(k-1) */ + expf(x - K_LN2) * scale * scale +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 42c596857d7..1ac5472576b 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -10,12 +10,14 @@ mod acos; mod acosf; mod asin; mod asinf; +mod atan2f; mod atanf; mod cbrt; mod cbrtf; mod ceil; mod ceilf; mod cosf; +mod coshf; mod exp; mod exp2; mod exp2f; @@ -50,6 +52,7 @@ mod sinf; mod sqrt; mod sqrtf; mod tanf; +mod tanhf; mod trunc; mod truncf; @@ -58,12 +61,14 @@ pub use self::acos::acos; pub use self::acosf::acosf; pub use self::asin::asin; pub use self::asinf::asinf; +pub use self::atan2f::atan2f; pub use self::atanf::atanf; pub use self::cbrt::cbrt; pub use self::cbrtf::cbrtf; pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; +pub use self::coshf::coshf; pub use self::exp::exp; pub use self::exp2::exp2; pub use self::exp2f::exp2f; @@ -98,18 +103,20 @@ pub use self::sinf::sinf; pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; pub use self::tanf::tanf; +pub use self::tanhf::tanhf; pub use self::trunc::trunc; pub use self::truncf::truncf; mod k_cosf; +mod k_expo2f; mod k_sinf; mod k_tanf; mod rem_pio2_large; mod rem_pio2f; use self::{ - k_cosf::k_cosf, k_sinf::k_sinf, k_tanf::k_tanf, rem_pio2_large::rem_pio2_large, - rem_pio2f::rem_pio2f, + k_cosf::k_cosf, k_expo2f::k_expo2f, k_sinf::k_sinf, k_tanf::k_tanf, + rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f, }; #[inline] diff --git a/library/compiler-builtins/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/src/math/tanhf.rs new file mode 100644 index 00000000000..98a1b60c29b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tanhf.rs @@ -0,0 +1,39 @@ +use super::expm1f; + +#[inline] +pub fn tanhf(mut x: f32) -> f32 { + /* x = |x| */ + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + x = f32::from_bits(ix); + let w = ix; + + let tt = if w > 0x3f0c9f54 { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if w > 0x41200000 { + /* |x| > 10 */ + 1. + 0. / x + } else { + let t = expm1f(2. * x); + 1. - 2. / (t + 2.) + } + } else if w > 0x3e82c578 { + /* |x| > log(5/3)/2 ~= 0.2554 */ + let t = expm1f(2. * x); + t / (t + 2.) + } else if w >= 0x00800000 { + /* |x| >= 0x1p-126 */ + let t = expm1f(-2. * x); + -t / (t + 2.) + } else { + /* |x| is subnormal */ + force_eval!(x * x); + x + }; + if sign { + -tt + } else { + tt + } +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index b639cf11b19..1c261b2ebaf 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -659,7 +659,7 @@ f32_f32! { cbrtf, cosf, ceilf, - // coshf, + coshf, exp2f, expf, expm1f, @@ -671,14 +671,14 @@ f32_f32! { sinf, // sinhf, tanf, - // tanhf, + tanhf, fabsf, sqrtf, } // With signature `fn(f32, f32) -> f32` f32f32_f32! { - // atan2f, + atan2f, fdimf, hypotf, fmodf, -- cgit 1.4.1-3-g733a5 From dde8131c1e8ecb9c55d1b5f6888ce70d55119cd3 Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 19:23:01 -0400 Subject: Implement sinh This also adds expo2 for the __expo2 function, and combine_words() to replace the INSERT_WORDS macro. Closes rust-lang/libm#35 --- library/compiler-builtins/libm/src/lib.rs | 2 - library/compiler-builtins/libm/src/math/expo2.rs | 13 ++++++ library/compiler-builtins/libm/src/math/mod.rs | 9 ++++ library/compiler-builtins/libm/src/math/sinh.rs | 48 ++++++++++++++++++++++ .../libm/test-generator/src/main.rs | 2 +- 5 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/expo2.rs create mode 100644 library/compiler-builtins/libm/src/math/sinh.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0b9efeeb338..ee864a36cf2 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -414,7 +414,6 @@ pub trait F64Ext: private::Sealed { fn ln_1p(self) -> Self; - #[cfg(todo)] fn sinh(self) -> Self; #[cfg(todo)] @@ -595,7 +594,6 @@ impl F64Ext for f64 { log1p(self) } - #[cfg(todo)] #[inline] fn sinh(self) -> Self { sinh(self) diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs new file mode 100644 index 00000000000..8a121b0a287 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/expo2.rs @@ -0,0 +1,13 @@ +use super::{combine_words, exp}; + +/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ +pub(crate) fn expo2(x: f64) -> f64 { + /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ + const K: i32 = 2043; + let kln2 = f64::from_bits(0x40962066151add8b); + + /* note that k is odd and scale*scale overflows */ + let scale = combine_words(((0x3ff + K / 2) as u32) << 20, 0); + /* exp(x - k ln2) * 2**(k-1) */ + return exp(x - kln2) * scale * scale; +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 7b3d9abee69..19d8ad58d86 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -50,6 +50,7 @@ mod scalbn; mod scalbnf; mod sin; mod sinf; +mod sinh; mod sqrt; mod sqrtf; mod tanf; @@ -100,6 +101,7 @@ pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; pub use self::sin::sin; pub use self::sinf::sinf; +pub use self::sinh::sinh; pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; pub use self::tanf::tanf; @@ -107,6 +109,7 @@ pub use self::trunc::trunc; pub use self::truncf::truncf; // Private modules +mod expo2; mod k_cos; mod k_cosf; mod k_sin; @@ -117,6 +120,7 @@ mod rem_pio2_large; mod rem_pio2f; // Private re-imports +use self::expo2::expo2; use self::k_cos::k_cos; use self::k_cosf::k_cosf; use self::k_sin::k_sin; @@ -151,3 +155,8 @@ pub fn with_set_low_word(f: f64, lo: u32) -> f64 { tmp |= lo as u64; f64::from_bits(tmp) } + +#[inline] +fn combine_words(hi: u32, lo: u32) -> f64 { + f64::from_bits((hi as u64) << 32 | lo as u64) +} diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs new file mode 100644 index 00000000000..0579871719a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sinh.rs @@ -0,0 +1,48 @@ +use super::{expm1, expo2}; + +// sinh(x) = (exp(x) - 1/exp(x))/2 +// = (exp(x)-1 + (exp(x)-1)/exp(x))/2 +// = x + x^3/6 + o(x^5) +// +pub fn sinh(x: f64) -> f64 { + // union {double f; uint64_t i;} u = {.f = x}; + // uint32_t w; + // double t, h, absx; + + let mut uf: f64 = x; + let mut ui: u64 = f64::to_bits(uf); + let w: u32; + let t: f64; + let mut h: f64; + let absx: f64; + + h = 0.5; + if ui >> 63 != 0 { + h = -h; + } + /* |x| */ + ui &= !1 / 2; + uf = f64::from_bits(ui); + absx = uf; + w = (ui >> 32) as u32; + + /* |x| < log(DBL_MAX) */ + if w < 0x40862e42 { + t = expm1(absx); + if w < 0x3ff00000 { + if w < 0x3ff00000 - (26 << 20) { + /* note: inexact and underflow are raised by expm1 */ + /* note: this branch avoids spurious underflow */ + return x; + } + return h * (2.0 * t - t * t / (t + 1.0)); + } + /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ + return h * (t + t / (t + 1.0)); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = 2.0 * h * expo2(absx); + return t; +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index c8e35cea7b0..758db9f527f 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -714,7 +714,7 @@ f64_f64! { log2, round, sin, - // sinh, + sinh, sqrt, // tan, // tanh, -- cgit 1.4.1-3-g733a5 From 0be652de3a29a7dcb5817c17f746543616980c1f Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 16:08:41 -0400 Subject: Implement tan Also includes implementing the private k_tan function. Closes rust-lang/libm#36 --- library/compiler-builtins/libm/src/lib.rs | 2 - library/compiler-builtins/libm/src/math/k_tan.rs | 105 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 4 + library/compiler-builtins/libm/src/math/tan.rs | 69 ++++++++++++++ .../libm/test-generator/src/main.rs | 2 +- 5 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/k_tan.rs create mode 100644 library/compiler-builtins/libm/src/math/tan.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0b9efeeb338..e6f286a9edc 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -390,7 +390,6 @@ pub trait F64Ext: private::Sealed { fn cos(self) -> Self; - #[cfg(todo)] fn tan(self) -> Self; #[cfg(todo)] @@ -556,7 +555,6 @@ impl F64Ext for f64 { cos(self) } - #[cfg(todo)] #[inline] fn tan(self) -> Self { tan(self) diff --git a/library/compiler-builtins/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/src/math/k_tan.rs new file mode 100644 index 00000000000..b0dd317a2e7 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_tan.rs @@ -0,0 +1,105 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ +// +// ==================================================== +// Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. +// +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +// kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. +// +// Algorithm +// 1. Since tan(-x) = -tan(x), we need only to consider positive x. +// 2. Callers must return tan(-0) = -0 without calling here since our +// odd polynomial is not evaluated in a way that preserves -0. +// Callers may do the optimization tan(x) ~ x for tiny x. +// 3. tan(x) is approximated by a odd polynomial of degree 27 on +// [0,0.67434] +// 3 27 +// tan(x) ~ x + T1*x + ... + T13*x +// where +// +// |tan(x) 2 4 26 | -59.2 +// |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 +// | x | +// +// Note: tan(x+y) = tan(x) + tan'(x)*y +// ~ tan(x) + (1+x*x)*y +// Therefore, for better accuracy in computing tan(x+y), let +// 3 2 2 2 2 +// r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) +// then +// 3 2 +// tan(x+y) = x + (T1*x + (x *(r+y)+y)) +// +// 4. For x in [0.67434,pi/4], let y = pi/4 - x, then +// tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) +// = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) +static T: [f64; 13] = [ + 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ + 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ + 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ + 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ + 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ + 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ + 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ + 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ + 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ + 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ + 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ + -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ + 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ +]; +const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ +const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ + +pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { + let hx = (f64::to_bits(x) >> 32) as u32; + let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ + if big { + let sign = hx >> 31; + if sign != 0 { + x = -x; + y = -y; + } + x = (PIO4 - x) + (PIO4_LO - y); + y = 0.0; + } + let z = x * x; + let w = z * z; + /* + * Break x^5*(T[1]+x^2*T[2]+...) into + * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + + * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) + */ + let r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11])))); + let v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12]))))); + let s = z * x; + let r = y + z * (s * (r + v) + y) + s * T[0]; + let w = x + r; + if big { + let sign = hx >> 31; + let s = 1.0 - 2.0 * odd as f64; + let v = s - 2.0 * (x + (r - w * w / (w + s))); + return if sign != 0 { -v } else { v }; + } + if odd == 0 { + return w; + } + /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */ + let w0 = zero_low_word(w); + let v = r - (w0 - x); /* w0+v = r+x */ + let a = -1.0 / w; + let a0 = zero_low_word(a); + a0 + a * (1.0 + a0 * w0 + a0 * v) +} + +#[inline] +fn zero_low_word(x: f64) -> f64 { + f64::from_bits(f64::to_bits(x) & 0xFFFF_FFFF_0000_0000) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 7b3d9abee69..a6ce52394cf 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -52,6 +52,7 @@ mod sin; mod sinf; mod sqrt; mod sqrtf; +mod tan; mod tanf; mod trunc; mod truncf; @@ -102,6 +103,7 @@ pub use self::sin::sin; pub use self::sinf::sinf; pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; +pub use self::tan::tan; pub use self::tanf::tanf; pub use self::trunc::trunc; pub use self::truncf::truncf; @@ -111,6 +113,7 @@ mod k_cos; mod k_cosf; mod k_sin; mod k_sinf; +mod k_tan; mod k_tanf; mod rem_pio2; mod rem_pio2_large; @@ -121,6 +124,7 @@ use self::k_cos::k_cos; use self::k_cosf::k_cosf; use self::k_sin::k_sin; use self::k_sinf::k_sinf; +use self::k_tan::k_tan; use self::k_tanf::k_tanf; use self::rem_pio2::rem_pio2; use self::rem_pio2_large::rem_pio2_large; diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs new file mode 100644 index 00000000000..92bbb622122 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -0,0 +1,69 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */ +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +use super::{k_tan, rem_pio2}; + +// tan(x) +// Return tangent function of x. +// +// kernel function: +// k_tan ... tangent function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded +pub fn tan(x: f64) -> f64 { + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e400000 { + /* |x| < 2**-27 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00100000 { + x / x1p120 as f64 + } else { + x + x1p120 as f64 + }); + return x; + } + return k_tan(x, 0.0, 0); + } + + /* tan(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction */ + let (n, y0, y1) = rem_pio2(x); + k_tan(y0, y1, n & 1) +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index c8e35cea7b0..5d47cb2a45b 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -716,7 +716,7 @@ f64_f64! { sin, // sinh, sqrt, - // tan, + tan, // tanh, trunc, fabs, -- cgit 1.4.1-3-g733a5 From f8e937fa466f721925073225a1a2177eee8b8e81 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 15 Jul 2018 07:01:26 +0300 Subject: sinf, fix constant in k_expo2f --- library/compiler-builtins/libm/src/lib.rs | 2 -- .../compiler-builtins/libm/src/math/k_expo2f.rs | 4 +-- library/compiler-builtins/libm/src/math/mod.rs | 2 ++ library/compiler-builtins/libm/src/math/sinhf.rs | 30 ++++++++++++++++++++++ .../libm/test-generator/src/main.rs | 2 +- 5 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/sinhf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 1ed07873421..45213a25f7a 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -108,7 +108,6 @@ pub trait F32Ext: private::Sealed { fn ln_1p(self) -> Self; - #[cfg(todo)] fn sinh(self) -> Self; fn cosh(self) -> Self; @@ -284,7 +283,6 @@ impl F32Ext for f32 { log1pf(self) } - #[cfg(todo)] #[inline] fn sinh(self) -> Self { sinhf(self) diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs index 031a0bdd036..e2eaa4e6bb0 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2f.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -2,13 +2,13 @@ use super::expf; /* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ const K: i32 = 235; -const K_LN2: f32 = 162.89; /* 0x1.45c778p+7f */ /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[inline] pub(crate) fn k_expo2f(x: f32) -> f32 { + let k_ln2 = f32::from_bits(0x4322e3bc); /* note that k is odd and scale*scale overflows */ let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); /* exp(x - k ln2) * 2**(k-1) */ - expf(x - K_LN2) * scale * scale + expf(x - k_ln2) * scale * scale } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index a29f2fb0ab4..eda6b5b7293 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -53,6 +53,7 @@ mod scalbnf; mod sin; mod sinf; mod sinh; +mod sinhf; mod sqrt; mod sqrtf; mod tan; @@ -108,6 +109,7 @@ pub use self::scalbnf::scalbnf; pub use self::sin::sin; pub use self::sinf::sinf; pub use self::sinh::sinh; +pub use self::sinhf::sinhf; pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; pub use self::tan::tan; diff --git a/library/compiler-builtins/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/src/math/sinhf.rs new file mode 100644 index 00000000000..90c4b931281 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sinhf.rs @@ -0,0 +1,30 @@ +use super::expm1f; +use super::k_expo2f; + +#[inline] +pub fn sinhf(x: f32) -> f32 { + let mut h = 0.5f32; + let mut ix = x.to_bits(); + if (ix >> 31) != 0 { + h = -h; + } + /* |x| */ + ix &= 0x7fffffff; + let absx = f32::from_bits(ix); + let w = ix; + + /* |x| < log(FLT_MAX) */ + if w < 0x42b17217 { + let t = expm1f(absx); + if w < 0x3f800000 { + if w < (0x3f800000 - (12 << 23)) { + return x; + } + return h * (2. * t - t * t / (t + 1.)); + } + return h * (t + t / (t + 1.)); + } + + /* |x| > logf(FLT_MAX) or nan */ + 2. * h * k_expo2f(absx) +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 6708891f3ed..7caada4ef3e 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -669,7 +669,7 @@ f32_f32! { logf, roundf, sinf, - // sinhf, + sinhf, tanf, tanhf, fabsf, -- cgit 1.4.1-3-g733a5 From 76b675c202bd964d1c3e86c9a806f6aeffc4c0f2 Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Sun, 15 Jul 2018 01:17:46 -0500 Subject: implement atan2 --- library/compiler-builtins/libm/src/lib.rs | 2 - library/compiler-builtins/libm/src/math/atan2.rs | 72 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/atan2.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 45213a25f7a..e7abce540af 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -392,7 +392,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn atan(self) -> Self; - #[cfg(todo)] fn atan2(self, other: Self) -> Self; #[cfg(todo)] @@ -568,7 +567,6 @@ impl F64Ext for f64 { atan(self) } - #[cfg(todo)] #[inline] fn atan2(self, other: Self) -> Self { atan2(self, other) diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs new file mode 100644 index 00000000000..324b1e937f9 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -0,0 +1,72 @@ +use super::atan; +use super::fabs; + +const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ +const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +#[inline] +pub fn atan2(y: f64, x: f64) -> f64 { + if x.is_nan() || y.is_nan() { + return x + y; + } + let mut ix = (x.to_bits() >> 32) as u32; + let lx = x.to_bits() as u32; + let mut iy = (y.to_bits() >> 32) as u32; + let ly = y.to_bits() as u32; + if (ix - 0x3ff00000 | lx) == 0 { + /* x = 1.0 */ + return atan(y); + } + let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if (iy | ly) == 0 { + return match m { + 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ + 2 => PI, /* atan(+0,-anything) = PI */ + _ => -PI, /* atan(-0,-anything) =-PI */ + }; + } + /* when x = 0 */ + if (ix | lx) == 0 { + return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; + } + /* when x is INF */ + if ix == 0x7ff00000 { + if iy == 0x7ff00000 { + return match m { + 0 => PI / 4.0, /* atan(+INF,+INF) */ + 1 => -PI / 4.0, /* atan(-INF,+INF) */ + 2 => 3.0 * PI / 4.0, /* atan(+INF,-INF) */ + _ => -3.0 * PI / 4.0, /* atan(-INF,-INF) */ + }; + } else { + return match m { + 0 => 0.0, /* atan(+...,+INF) */ + 1 => -0.0, /* atan(-...,+INF) */ + 2 => PI, /* atan(+...,-INF) */ + _ => -PI, /* atan(-...,-INF) */ + }; + } + } + /* |y/x| > 0x1p64 */ + if ix + (64 << 20) < iy || iy == 0x7ff00000 { + return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; + } + + /* z = atan(|y/x|) without spurious underflow */ + let z = if (m & 2 != 0) && iy + (64 << 20) < ix { + /* |y/x| < 0x1p-64, x<0 */ + 0.0 + } else { + atan(fabs(y / x)) + }; + match m { + 0 => z, /* atan(+,+) */ + 1 => -z, /* atan(-,+) */ + 2 => PI - (z - PI_LO), /* atan(+,-) */ + _ => (z - PI_LO) - PI, /* atan(-,-) */ + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index eda6b5b7293..07032dcfbca 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -11,6 +11,7 @@ mod acos; mod acosf; mod asin; mod asinf; +mod atan2; mod atan2f; mod atanf; mod cbrt; @@ -67,6 +68,7 @@ pub use self::acos::acos; pub use self::acosf::acosf; pub use self::asin::asin; pub use self::asinf::asinf; +pub use self::atan2::atan2; pub use self::atan2f::atan2f; pub use self::atanf::atanf; pub use self::cbrt::cbrt; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 7caada4ef3e..e65f0f69bb0 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -724,7 +724,7 @@ f64_f64! { // With signature `fn(f64, f64) -> f64` f64f64_f64! { - // atan2, + atan2, fdim, fmod, hypot, -- cgit 1.4.1-3-g733a5 From 14c3113694d81ed7e4c2dbe7877c2c73e32864f3 Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 19:42:47 -0400 Subject: Implement tanh Closes rust-lang/libm#37 --- library/compiler-builtins/libm/src/lib.rs | 2 - library/compiler-builtins/libm/src/math/mod.rs | 2 + library/compiler-builtins/libm/src/math/tanh.rs | 52 ++++++++++++++++++++++ .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/tanh.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 45213a25f7a..1eea30667bd 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -410,7 +410,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn cosh(self) -> Self; - #[cfg(todo)] fn tanh(self) -> Self; #[cfg(todo)] @@ -595,7 +594,6 @@ impl F64Ext for f64 { cosh(self) } - #[cfg(todo)] #[inline] fn tanh(self) -> Self { tanh(self) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index eda6b5b7293..5fc787c8217 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -58,6 +58,7 @@ mod sqrt; mod sqrtf; mod tan; mod tanf; +mod tanh; mod tanhf; mod trunc; mod truncf; @@ -114,6 +115,7 @@ pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; pub use self::tan::tan; pub use self::tanf::tanf; +pub use self::tanh::tanh; pub use self::tanhf::tanhf; pub use self::trunc::trunc; pub use self::truncf::truncf; diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs new file mode 100644 index 00000000000..657d7e0e276 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tanh.rs @@ -0,0 +1,52 @@ +use super::expm1; + +/* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) + * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) + * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) + */ +pub fn tanh(mut x: f64) -> f64 { + let mut uf: f64 = x; + let mut ui: u64 = f64::to_bits(uf); + + let w: u32; + let sign: bool; + let mut t: f64; + + /* x = |x| */ + sign = ui >> 63 != 0; + ui &= !1 / 2; + uf = f64::from_bits(ui); + x = uf; + w = (ui >> 32) as u32; + + if w > 0x3fe193ea { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if w > 0x40340000 { + /* |x| > 20 or nan */ + /* note: this branch avoids raising overflow */ + t = 1.0 - 0.0 / x; + } else { + t = expm1(2.0 * x); + t = 1.0 - 2.0 / (t + 2.0); + } + } else if w > 0x3fd058ae { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1(2.0 * x); + t = t / (t + 2.0); + } else if w >= 0x00100000 { + /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ + t = expm1(-2.0 * x); + t = -t / (t + 2.0); + } else { + /* |x| is subnormal */ + /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ + force_eval!(x as f32); + t = x; + } + + if sign { + -t + } else { + t + } +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 7caada4ef3e..1d619cd9292 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -717,7 +717,7 @@ f64_f64! { sinh, sqrt, tan, - // tanh, + tanh, trunc, fabs, } -- cgit 1.4.1-3-g733a5 From 865fedeac63f00c180c62b279f01eade7dee0761 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 15:22:41 -0400 Subject: implement fmaf --- library/compiler-builtins/libm/src/lib.rs | 2 - library/compiler-builtins/libm/src/math/fmaf.rs | 94 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fmaf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 45213a25f7a..f0fdd464c64 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -52,7 +52,6 @@ pub trait F32Ext: private::Sealed { #[cfg(todo)] fn signum(self) -> Self; - #[cfg(todo)] fn mul_add(self, a: Self, b: Self) -> Self; #[cfg(todo)] @@ -161,7 +160,6 @@ impl F32Ext for f32 { fabsf(self) } - #[cfg(todo)] #[inline] fn mul_add(self, a: Self, b: Self) -> Self { fmaf(self, a, b) diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs new file mode 100644 index 00000000000..70d2c54a27e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -0,0 +1,94 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_fmaf.c */ +/*- + * Copyright (c) 2005-2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +use core::f32; +use core::ptr::read_volatile; + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * A double has more than twice as much precision than a float, so + * direct double-precision arithmetic suffices, except where double + * rounding occurs. + */ +#[inline] +pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { + let xy: f64; + let mut result: f64; + let mut ui: u64; + let e: i32; + + xy = x as f64 * y as f64; + result = xy + z as f64; + ui = result.to_bits(); + e = (ui >> 52) as i32 & 0x7ff; + /* Common case: The double precision result is fine. */ + if ( + /* not a halfway case */ + ui & 0x1fffffff) != 0x10000000 || + /* NaN */ + e == 0x7ff || + /* exact */ + (result - xy == z as f64 && result - z as f64 == xy) || + /* not round-to-nearest */ + fegetround() != FE_TONEAREST + { + /* + underflow may not be raised correctly, example: + fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) + */ + if e < 0x3ff - 126 && e >= 0x3ff - 149 && fetestexcept(FE_INEXACT) { + feclearexcept(FE_INEXACT); + /* TODO: gcc and clang bug workaround */ + let vz: f32 = unsafe { read_volatile(&z) }; + result = xy + vz as f64; + if fetestexcept(FE_INEXACT) { + feraiseexcept(FE_UNDERFLOW); + } else { + feraiseexcept(FE_INEXACT); + } + } + z = result as f32; + return z; + } + + /* + * If result is inexact, and exactly halfway between two float values, + * we need to adjust the low-order bit in the direction of the error. + */ + fesetround(FE_TOWARDZERO); + let vxy: f64 = unsafe { read_volatile(&xy) }; /* XXX work around gcc CSE bug */ + let mut adjusted_result: f64 = vxy + z as f64; + fesetround(FE_TONEAREST); + if result == adjusted_result { + ui = adjusted_result.to_bits(); + ui += 1; + adjusted_result = f64::from_bits(ui); + } + z = adjusted_result as f32; + z +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index eda6b5b7293..ad9aead7c38 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -33,6 +33,7 @@ mod fdimf; mod floor; mod floorf; mod fma; +mod fmaf; mod fmod; mod fmodf; mod hypot; @@ -89,6 +90,7 @@ pub use self::fdimf::fdimf; pub use self::floor::floor; pub use self::floorf::floorf; pub use self::fma::fma; +pub use self::fmaf::fmaf; pub use self::fmod::fmod; pub use self::fmodf::fmodf; pub use self::hypot::hypot; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 7caada4ef3e..a2a301d133c 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -687,7 +687,7 @@ f32f32_f32! { // With signature `fn(f32, f32, f32) -> f32` f32f32f32_f32! { - // fmaf, + fmaf, } // With signature `fn(f32, i32) -> f32` -- cgit 1.4.1-3-g733a5 From 7084ce52b709905a823b6f371487eab6bbf57148 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 15 Jul 2018 13:14:29 -0400 Subject: add dummy fenv implementation --- library/compiler-builtins/libm/src/math/fenv.rs | 33 +++++++++++++++++++++++++ library/compiler-builtins/libm/src/math/fmaf.rs | 14 ++++++++--- library/compiler-builtins/libm/src/math/mod.rs | 1 + 3 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fenv.rs diff --git a/library/compiler-builtins/libm/src/math/fenv.rs b/library/compiler-builtins/libm/src/math/fenv.rs new file mode 100644 index 00000000000..652e6032452 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fenv.rs @@ -0,0 +1,33 @@ +// src: musl/src/fenv/fenv.c +/* Dummy functions for archs lacking fenv implementation */ + +pub(crate) const FE_UNDERFLOW: i32 = 0; +pub(crate) const FE_INEXACT: i32 = 0; + +pub(crate) const FE_TONEAREST: i32 = 0; +pub(crate) const FE_TOWARDZERO: i32 = 0; + +#[inline] +pub(crate) fn feclearexcept(_mask: i32) -> i32 { + 0 +} + +#[inline] +pub(crate) fn feraiseexcept(_mask: i32) -> i32 { + 0 +} + +#[inline] +pub(crate) fn fetestexcept(_mask: i32) -> i32 { + 0 +} + +#[inline] +pub(crate) fn fegetround() -> i32 { + FE_TONEAREST +} + +#[inline] +pub(crate) fn fesetround(_r: i32) -> i32 { + 0 +} diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index 70d2c54a27e..25b04fc2396 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -28,6 +28,11 @@ use core::f32; use core::ptr::read_volatile; +use super::fenv::{ + feclearexcept, fegetround, feraiseexcept, fesetround, fetestexcept, FE_INEXACT, FE_TONEAREST, + FE_TOWARDZERO, FE_UNDERFLOW, +}; + /* * Fused multiply-add: Compute x * y + z with a single rounding error. * @@ -61,12 +66,12 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { underflow may not be raised correctly, example: fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) */ - if e < 0x3ff - 126 && e >= 0x3ff - 149 && fetestexcept(FE_INEXACT) { + if e < 0x3ff - 126 && e >= 0x3ff - 149 && fetestexcept(FE_INEXACT) != 0 { feclearexcept(FE_INEXACT); - /* TODO: gcc and clang bug workaround */ + // prevent `xy + vz` from being CSE'd with `xy + z` above let vz: f32 = unsafe { read_volatile(&z) }; result = xy + vz as f64; - if fetestexcept(FE_INEXACT) { + if fetestexcept(FE_INEXACT) != 0 { feraiseexcept(FE_UNDERFLOW); } else { feraiseexcept(FE_INEXACT); @@ -81,7 +86,8 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { * we need to adjust the low-order bit in the direction of the error. */ fesetround(FE_TOWARDZERO); - let vxy: f64 = unsafe { read_volatile(&xy) }; /* XXX work around gcc CSE bug */ + // prevent `vxy + z` from being CSE'd with `xy + z` above + let vxy: f64 = unsafe { read_volatile(&xy) }; let mut adjusted_result: f64 = vxy + z as f64; fesetround(FE_TONEAREST); if result == adjusted_result { diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index ad9aead7c38..92db426bf21 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -122,6 +122,7 @@ pub use self::truncf::truncf; // Private modules mod expo2; +mod fenv; mod k_cos; mod k_cosf; mod k_expo2f; -- cgit 1.4.1-3-g733a5 From ee33990f46cd2c1c8039a00e0f486f0afe8dcfdc Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 15 Jul 2018 13:24:09 -0500 Subject: update CHANGELOG; make utility functions private --- library/compiler-builtins/libm/CHANGELOG.md | 13 +++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 9 +++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 3a496527bc0..107813b0813 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -5,6 +5,19 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added + +- atan2f +- cos +- coshf +- fmaf +- sin +- sinh +- sinhf +- tan +- tanh +- tanhf + ## [v0.1.1] - 2018-07-14 ### Added diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c6a3424d8ad..7fa4252077d 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -150,17 +150,18 @@ use self::rem_pio2_large::rem_pio2_large; use self::rem_pio2f::rem_pio2f; #[inline] -pub fn get_high_word(x: f64) -> u32 { +fn get_high_word(x: f64) -> u32 { (x.to_bits() >> 32) as u32 } #[inline] -pub fn get_low_word(x: f64) -> u32 { +fn get_low_word(x: f64) -> u32 { x.to_bits() as u32 } +#[allow(dead_code)] #[inline] -pub fn with_set_high_word(f: f64, hi: u32) -> f64 { +fn with_set_high_word(f: f64, hi: u32) -> f64 { let mut tmp = f.to_bits(); tmp &= 0x00000000_ffffffff; tmp |= (hi as u64) << 32; @@ -168,7 +169,7 @@ pub fn with_set_high_word(f: f64, hi: u32) -> f64 { } #[inline] -pub fn with_set_low_word(f: f64, lo: u32) -> f64 { +fn with_set_low_word(f: f64, lo: u32) -> f64 { let mut tmp = f.to_bits(); tmp &= 0xffffffff_00000000; tmp |= lo as u64; -- cgit 1.4.1-3-g733a5 From 60db814b549b8d28d88f4898bc085e48bdd3146a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 15 Jul 2018 14:50:00 -0500 Subject: add more copyright notices --- library/compiler-builtins/libm/src/math/acosf.rs | 15 +++++++++++++++ library/compiler-builtins/libm/src/math/asinf.rs | 15 +++++++++++++++ library/compiler-builtins/libm/src/math/atanf.rs | 15 +++++++++++++++ library/compiler-builtins/libm/src/math/cosf.rs | 16 ++++++++++++++++ library/compiler-builtins/libm/src/math/expm1.rs | 12 ++++++++++++ library/compiler-builtins/libm/src/math/expm1f.rs | 15 +++++++++++++++ library/compiler-builtins/libm/src/math/k_cosf.rs | 16 ++++++++++++++++ library/compiler-builtins/libm/src/math/k_sinf.rs | 16 ++++++++++++++++ library/compiler-builtins/libm/src/math/k_tanf.rs | 11 +++++++++++ .../compiler-builtins/libm/src/math/rem_pio2_large.rs | 12 ++++++++++++ library/compiler-builtins/libm/src/math/rem_pio2f.rs | 16 ++++++++++++++++ library/compiler-builtins/libm/src/math/sinf.rs | 16 ++++++++++++++++ library/compiler-builtins/libm/src/math/tanf.rs | 16 ++++++++++++++++ 13 files changed, 191 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index bbe29c17c13..ff07fe93501 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + use super::sqrtf::sqrtf; const PIO2_HI: f32 = 1.5707962513e+00; /* 0x3fc90fda */ diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index 597be4cb7f9..86944bb0057 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + use super::fabsf::fabsf; use super::sqrt::sqrt; diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index 01c41f4ce17..b05152e2bc3 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + use super::fabsf; const ATAN_HI: [f32; 4] = [ diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index 79df97e354a..23faacdc26c 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -1,3 +1,19 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + use super::{k_cosf, k_sinf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs index 48082cd745c..a00396524e8 100644 --- a/library/compiler-builtins/libm/src/math/expm1.rs +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -1,3 +1,15 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + use core::f64; const O_THRESHOLD: f64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs index 011e09b693d..8f581733acd 100644 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + const O_THRESHOLD: f32 = 8.8721679688e+01; /* 0x42b17180 */ const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs index 83d13b2e998..75579ef9bf4 100644 --- a/library/compiler-builtins/libm/src/math/k_cosf.rs +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -1,3 +1,19 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + /* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ const C0: f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ const C1: f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs index bb2183afc7c..bb519c9c09e 100644 --- a/library/compiler-builtins/libm/src/math/k_sinf.rs +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -1,3 +1,19 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + /* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ const S1: f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ const S2: f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs index db2e0caa7a5..6d3da1dcc80 100644 --- a/library/compiler-builtins/libm/src/math/k_tanf.rs +++ b/library/compiler-builtins/libm/src/math/k_tanf.rs @@ -1,3 +1,14 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + /* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ const T: [f64; 6] = [ 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 52b47279cd9..462eb034515 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -1,3 +1,15 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + use super::floor; use super::scalbn; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 73ec3775d3d..e2368d93db6 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -1,3 +1,19 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + use super::rem_pio2_large; use core::f64; diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs index 09f62cddcae..c9b02bcdc51 100644 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -1,3 +1,19 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + use super::{k_cosf, k_sinf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs index 6bfbe06c1b4..15a462d4e19 100644 --- a/library/compiler-builtins/libm/src/math/tanf.rs +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -1,3 +1,19 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_tanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + use super::{k_tanf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; -- cgit 1.4.1-3-g733a5 From 57848a73097269a3beaab1c20613953d37c68f99 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 15 Jul 2018 16:00:09 -0500 Subject: inline more functions; add more methods to F{32,64}Ext --- library/compiler-builtins/libm/src/lib.rs | 56 +++++++--------------- library/compiler-builtins/libm/src/math/acosf.rs | 1 + library/compiler-builtins/libm/src/math/asin.rs | 2 + library/compiler-builtins/libm/src/math/asinf.rs | 1 + library/compiler-builtins/libm/src/math/cos.rs | 1 + library/compiler-builtins/libm/src/math/expm1.rs | 2 +- library/compiler-builtins/libm/src/math/expo2.rs | 3 +- library/compiler-builtins/libm/src/math/fenv.rs | 18 +++---- library/compiler-builtins/libm/src/math/k_cosf.rs | 2 +- .../compiler-builtins/libm/src/math/k_expo2f.rs | 2 +- library/compiler-builtins/libm/src/math/k_sinf.rs | 2 +- library/compiler-builtins/libm/src/math/k_tan.rs | 3 +- library/compiler-builtins/libm/src/math/k_tanf.rs | 2 +- .../compiler-builtins/libm/src/math/rem_pio2.rs | 2 + .../libm/src/math/rem_pio2_large.rs | 2 +- .../compiler-builtins/libm/src/math/rem_pio2f.rs | 2 +- library/compiler-builtins/libm/src/math/sin.rs | 1 + library/compiler-builtins/libm/src/math/sinh.rs | 1 + library/compiler-builtins/libm/src/math/tan.rs | 1 + library/compiler-builtins/libm/src/math/tanh.rs | 1 + 20 files changed, 49 insertions(+), 56 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 644091bb74d..bd4bff98db7 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -14,18 +14,19 @@ mod math; -#[cfg(todo)] use core::{f32, f64}; pub use math::*; /// Approximate equality with 1 ULP of tolerance #[doc(hidden)] +#[inline] pub fn _eqf(a: u32, b: u32) -> bool { (a as i32).wrapping_sub(b as i32).abs() <= 1 } #[doc(hidden)] +#[inline] pub fn _eq(a: u64, b: u64) -> bool { (a as i64).wrapping_sub(b as i64).abs() <= 1 } @@ -33,7 +34,7 @@ pub fn _eq(a: u64, b: u64) -> bool { /// Math support for `f32` /// /// This trait is sealed and cannot be implemented outside of `libm`. -pub trait F32Ext: private::Sealed { +pub trait F32Ext: private::Sealed + Sized { fn floor(self) -> Self; fn ceil(self) -> Self; @@ -44,20 +45,17 @@ pub trait F32Ext: private::Sealed { fn fdim(self, rhs: Self) -> Self; - #[cfg(todo)] fn fract(self) -> Self; fn abs(self) -> Self; - #[cfg(todo)] - fn signum(self) -> Self; + // NOTE depends on unstable intrinsics::copysignf32 + // fn signum(self) -> Self; fn mul_add(self, a: Self, b: Self) -> Self; - #[cfg(todo)] fn div_euc(self, rhs: Self) -> Self; - #[cfg(todo)] fn mod_euc(self, rhs: Self) -> Self; // NOTE depends on unstable intrinsics::powif32 @@ -97,9 +95,11 @@ pub trait F32Ext: private::Sealed { fn atan2(self, other: Self) -> Self; - #[cfg(todo)] #[inline] - fn sin_cos(self) -> (Self, Self) { + fn sin_cos(self) -> (Self, Self) + where + Self: Copy, + { (self.sin(), self.cos()) } @@ -113,13 +113,10 @@ pub trait F32Ext: private::Sealed { fn tanh(self) -> Self; - #[cfg(todo)] fn asinh(self) -> Self; - #[cfg(todo)] fn acosh(self) -> Self; - #[cfg(todo)] fn atanh(self) -> Self; } @@ -149,7 +146,6 @@ impl F32Ext for f32 { fdimf(self, rhs) } - #[cfg(todo)] #[inline] fn fract(self) -> Self { self - self.trunc() @@ -165,7 +161,6 @@ impl F32Ext for f32 { fmaf(self, a, b) } - #[cfg(todo)] #[inline] fn div_euc(self, rhs: Self) -> Self { let q = (self / rhs).trunc(); @@ -175,7 +170,6 @@ impl F32Ext for f32 { q } - #[cfg(todo)] #[inline] fn mod_euc(self, rhs: f32) -> f32 { let r = self % rhs; @@ -296,7 +290,6 @@ impl F32Ext for f32 { tanhf(self) } - #[cfg(todo)] #[inline] fn asinh(self) -> Self { if self == f32::NEG_INFINITY { @@ -306,7 +299,6 @@ impl F32Ext for f32 { } } - #[cfg(todo)] #[inline] fn acosh(self) -> Self { match self { @@ -315,7 +307,6 @@ impl F32Ext for f32 { } } - #[cfg(todo)] #[inline] fn atanh(self) -> Self { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() @@ -325,7 +316,7 @@ impl F32Ext for f32 { /// Math support for `f64` /// /// This trait is sealed and cannot be implemented outside of `libm`. -pub trait F64Ext: private::Sealed { +pub trait F64Ext: private::Sealed + Sized { fn floor(self) -> Self; fn ceil(self) -> Self; @@ -336,20 +327,17 @@ pub trait F64Ext: private::Sealed { fn fdim(self, rhs: Self) -> Self; - #[cfg(todo)] fn fract(self) -> Self; fn abs(self) -> Self; - #[cfg(todo)] - fn signum(self) -> Self; + // NOTE depends on unstable intrinsics::copysignf64 + // fn signum(self) -> Self; fn mul_add(self, a: Self, b: Self) -> Self; - #[cfg(todo)] fn div_euc(self, rhs: Self) -> Self; - #[cfg(todo)] fn mod_euc(self, rhs: Self) -> Self; // NOTE depends on unstable intrinsics::powif64 @@ -382,7 +370,6 @@ pub trait F64Ext: private::Sealed { fn tan(self) -> Self; - #[cfg(todo)] fn asin(self) -> Self; fn acos(self) -> Self; @@ -393,9 +380,11 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn atan2(self, other: Self) -> Self; - #[cfg(todo)] #[inline] - fn sin_cos(self) -> (Self, Self) { + fn sin_cos(self) -> (Self, Self) + where + Self: Copy, + { (self.sin(), self.cos()) } @@ -410,13 +399,10 @@ pub trait F64Ext: private::Sealed { fn tanh(self) -> Self; - #[cfg(todo)] fn asinh(self) -> Self; - #[cfg(todo)] fn acosh(self) -> Self; - #[cfg(todo)] fn atanh(self) -> Self; } @@ -445,7 +431,7 @@ impl F64Ext for f64 { fn fdim(self, rhs: Self) -> Self { fdim(self, rhs) } - #[cfg(todo)] + #[inline] fn fract(self) -> Self { self - self.trunc() @@ -461,7 +447,6 @@ impl F64Ext for f64 { fma(self, a, b) } - #[cfg(todo)] #[inline] fn div_euc(self, rhs: Self) -> Self { let q = (self / rhs).trunc(); @@ -471,9 +456,8 @@ impl F64Ext for f64 { q } - #[cfg(todo)] #[inline] - fn mod_euc(self, rhs: f32) -> f32 { + fn mod_euc(self, rhs: f64) -> f64 { let r = self % rhs; if r < 0.0 { r + rhs.abs() @@ -548,7 +532,6 @@ impl F64Ext for f64 { tan(self) } - #[cfg(todo)] #[inline] fn asin(self) -> Self { asin(self) @@ -597,7 +580,6 @@ impl F64Ext for f64 { tanh(self) } - #[cfg(todo)] #[inline] fn asinh(self) -> Self { if self == f64::NEG_INFINITY { @@ -607,7 +589,6 @@ impl F64Ext for f64 { } } - #[cfg(todo)] #[inline] fn acosh(self) -> Self { match self { @@ -616,7 +597,6 @@ impl F64Ext for f64 { } } - #[cfg(todo)] #[inline] fn atanh(self) -> Self { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index ff07fe93501..469601caba4 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -22,6 +22,7 @@ const P_S1: f32 = -4.2743422091e-02; const P_S2: f32 = -8.6563630030e-03; const Q_S1: f32 = -7.0662963390e-01; +#[inline] fn r(z: f32) -> f32 { let p = z * (P_S0 + z * (P_S1 + z * P_S2)); let q = 1. + z * Q_S1; diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs index 720169bdcf0..a0bb4918c5a 100644 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -55,12 +55,14 @@ const Q_S2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ const Q_S3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ +#[inline] fn comp_r(z: f64) -> f64 { let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); return p / q; } +#[inline] pub fn asin(mut x: f64) -> f64 { let z: f64; let r: f64; diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index 86944bb0057..79c85d81d00 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -24,6 +24,7 @@ const P_S1: f32 = -4.2743422091e-02; const P_S2: f32 = -8.6563630030e-03; const Q_S1: f32 = -7.0662963390e-01; +#[inline] fn r(z: f32) -> f32 { let p = z * (P_S0 + z * (P_S1 + z * P_S2)); let q = 1. + z * Q_S1; diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs index e6e9b373674..df16b5c36a8 100644 --- a/library/compiler-builtins/libm/src/math/cos.rs +++ b/library/compiler-builtins/libm/src/math/cos.rs @@ -41,6 +41,7 @@ use super::{k_cos, k_sin, rem_pio2}; // Accuracy: // TRIG(x) returns trig(x) nearly rounded // +#[inline] pub fn cos(x: f64) -> f64 { let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs index a00396524e8..9da064ee773 100644 --- a/library/compiler-builtins/libm/src/math/expm1.rs +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -23,7 +23,7 @@ const Q3: f64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ -#[allow(warnings)] +#[inline] pub fn expm1(mut x: f64) -> f64 { let hi: f64; let lo: f64; diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs index 8a121b0a287..39f9815c404 100644 --- a/library/compiler-builtins/libm/src/math/expo2.rs +++ b/library/compiler-builtins/libm/src/math/expo2.rs @@ -1,7 +1,8 @@ use super::{combine_words, exp}; /* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ -pub(crate) fn expo2(x: f64) -> f64 { +#[inline] +pub fn expo2(x: f64) -> f64 { /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ const K: i32 = 2043; let kln2 = f64::from_bits(0x40962066151add8b); diff --git a/library/compiler-builtins/libm/src/math/fenv.rs b/library/compiler-builtins/libm/src/math/fenv.rs index 652e6032452..63bb2036820 100644 --- a/library/compiler-builtins/libm/src/math/fenv.rs +++ b/library/compiler-builtins/libm/src/math/fenv.rs @@ -1,33 +1,33 @@ // src: musl/src/fenv/fenv.c /* Dummy functions for archs lacking fenv implementation */ -pub(crate) const FE_UNDERFLOW: i32 = 0; -pub(crate) const FE_INEXACT: i32 = 0; +pub const FE_UNDERFLOW: i32 = 0; +pub const FE_INEXACT: i32 = 0; -pub(crate) const FE_TONEAREST: i32 = 0; -pub(crate) const FE_TOWARDZERO: i32 = 0; +pub const FE_TONEAREST: i32 = 0; +pub const FE_TOWARDZERO: i32 = 0; #[inline] -pub(crate) fn feclearexcept(_mask: i32) -> i32 { +pub fn feclearexcept(_mask: i32) -> i32 { 0 } #[inline] -pub(crate) fn feraiseexcept(_mask: i32) -> i32 { +pub fn feraiseexcept(_mask: i32) -> i32 { 0 } #[inline] -pub(crate) fn fetestexcept(_mask: i32) -> i32 { +pub fn fetestexcept(_mask: i32) -> i32 { 0 } #[inline] -pub(crate) fn fegetround() -> i32 { +pub fn fegetround() -> i32 { FE_TONEAREST } #[inline] -pub(crate) fn fesetround(_r: i32) -> i32 { +pub fn fesetround(_r: i32) -> i32 { 0 } diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs index 75579ef9bf4..4aa10c0f089 100644 --- a/library/compiler-builtins/libm/src/math/k_cosf.rs +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -21,7 +21,7 @@ const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ #[inline] -pub(crate) fn k_cosf(x: f64) -> f32 { +pub fn k_cosf(x: f64) -> f32 { let z = x * x; let w = z * z; let r = C2 + z * C3; diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs index e2eaa4e6bb0..ec2a2c5e2b8 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2f.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -5,7 +5,7 @@ const K: i32 = 235; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[inline] -pub(crate) fn k_expo2f(x: f32) -> f32 { +pub fn k_expo2f(x: f32) -> f32 { let k_ln2 = f32::from_bits(0x4322e3bc); /* note that k is odd and scale*scale overflows */ let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs index bb519c9c09e..1c5f5f98a48 100644 --- a/library/compiler-builtins/libm/src/math/k_sinf.rs +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -21,7 +21,7 @@ const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ #[inline] -pub(crate) fn k_sinf(x: f64) -> f32 { +pub fn k_sinf(x: f64) -> f32 { let z = x * x; let w = z * z; let r = S3 + z * S4; diff --git a/library/compiler-builtins/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/src/math/k_tan.rs index b0dd317a2e7..e9ba21499d0 100644 --- a/library/compiler-builtins/libm/src/math/k_tan.rs +++ b/library/compiler-builtins/libm/src/math/k_tan.rs @@ -58,7 +58,8 @@ static T: [f64; 13] = [ const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ -pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { +#[inline] +pub fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { let hx = (f64::to_bits(x) >> 32) as u32; let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ if big { diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs index 6d3da1dcc80..b9ccf2570f3 100644 --- a/library/compiler-builtins/libm/src/math/k_tanf.rs +++ b/library/compiler-builtins/libm/src/math/k_tanf.rs @@ -20,7 +20,7 @@ const T: [f64; 6] = [ ]; #[inline] -pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { +pub fn k_tanf(x: f64, odd: bool) -> f32 { let z = x * x; /* * Split up the polynomial into small independent terms to give diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 47bab6e65f1..6e655e7d419 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -42,12 +42,14 @@ const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ // use rem_pio2_large() for large x // // caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +#[inline] pub fn rem_pio2(x: f64) -> (i32, f64, f64) { let x1p24 = f64::from_bits(0x4170000000000000); let sign = (f64::to_bits(x) >> 63) as i32; let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + #[inline] fn medium(x: f64, ix: u32) -> (i32, f64, f64) { /* rint(x/(pi/2)), Assume round-to-nearest. */ let f_n = x as f64 * INV_PIO2 + TO_INT - TO_INT; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 462eb034515..745b700a5eb 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -222,7 +222,7 @@ const PIO2: [f64; 8] = [ /// more accurately, = 0 mod 8 ). Thus the number of operations are /// independent of the exponent of the input. #[inline] -pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { +pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index e2368d93db6..5e7a7d43904 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -32,7 +32,7 @@ const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ /// use double precision for everything except passing x /// use __rem_pio2_large() for large x #[inline] -pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { +pub fn rem_pio2f(x: f32) -> (i32, f64) { let x64 = x as f64; let mut tx: [f64; 1] = [0.]; diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index 13eb30248ab..e749094e668 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -40,6 +40,7 @@ use super::{k_cos, k_sin, rem_pio2}; // // Accuracy: // TRIG(x) returns trig(x) nearly rounded +#[inline] pub fn sin(x: f64) -> f64 { let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs index 0579871719a..684e8e30984 100644 --- a/library/compiler-builtins/libm/src/math/sinh.rs +++ b/library/compiler-builtins/libm/src/math/sinh.rs @@ -4,6 +4,7 @@ use super::{expm1, expo2}; // = (exp(x)-1 + (exp(x)-1)/exp(x))/2 // = x + x^3/6 + o(x^5) // +#[inline] pub fn sinh(x: f64) -> f64 { // union {double f; uint64_t i;} u = {.f = x}; // uint32_t w; diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs index 92bbb622122..5a5f178a51c 100644 --- a/library/compiler-builtins/libm/src/math/tan.rs +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -39,6 +39,7 @@ use super::{k_tan, rem_pio2}; // // Accuracy: // TRIG(x) returns trig(x) nearly rounded +#[inline] pub fn tan(x: f64) -> f64 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs index 657d7e0e276..1c3dd0be438 100644 --- a/library/compiler-builtins/libm/src/math/tanh.rs +++ b/library/compiler-builtins/libm/src/math/tanh.rs @@ -4,6 +4,7 @@ use super::expm1; * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) */ +#[inline] pub fn tanh(mut x: f64) -> f64 { let mut uf: f64 = x; let mut ui: u64 = f64::to_bits(uf); -- cgit 1.4.1-3-g733a5 From 06aba076817ff1b01287e136e0aea8941baa93bf Mon Sep 17 00:00:00 2001 From: Cássio Kirch Date: Sun, 15 Jul 2018 19:49:12 -0300 Subject: implement cosh --- library/compiler-builtins/libm/src/lib.rs | 2 -- library/compiler-builtins/libm/src/math/cosh.rs | 34 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/k_expo2.rs | 14 +++++++++ library/compiler-builtins/libm/src/math/mod.rs | 4 +++ 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/cosh.rs create mode 100644 library/compiler-builtins/libm/src/math/k_expo2.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 45213a25f7a..3a1785357bf 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -407,7 +407,6 @@ pub trait F64Ext: private::Sealed { fn sinh(self) -> Self; - #[cfg(todo)] fn cosh(self) -> Self; #[cfg(todo)] @@ -589,7 +588,6 @@ impl F64Ext for f64 { sinh(self) } - #[cfg(todo)] #[inline] fn cosh(self) -> Self { cosh(self) diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs new file mode 100644 index 00000000000..54c0a61dc05 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -0,0 +1,34 @@ +use super::exp; +use super::expm1; +use super::k_expo2; + +#[inline] +pub fn cosh(mut x: f64) -> f64 { + /* |x| */ + let mut ix = x.to_bits(); + ix &= 0x7fffffffffffffff; + x = f64::from_bits(ix); + let w = ix >> 32; + let w = w as u32; + + /* |x| < log(2) */ + if w < 0x3fe62e42 { + if w < 0x3ff00000 - (26 << 20) { + let x1p120 = f64::from_bits(0x4770000000000000); + force_eval!(x + x1p120); + return 1.; + } + let t = expm1(x); // exponential minus 1 + return 1. + t * t / (2. * (1. + t)); + } + + /* |x| < log(DBL_MAX) */ + if w < 0x40862e42 { + let t = exp(x); + /* note: if x>log(0x1p26) then the 1/t is not needed */ + return 0.5 * (t + 1. / t); + } + + /* |x| > log(DBL_MAX) or nan */ + k_expo2(x) +} diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs new file mode 100644 index 00000000000..7a4045dfc7b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_expo2.rs @@ -0,0 +1,14 @@ +use super::exp; + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +const K: i64 = 2043; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +#[inline] +pub(crate) fn k_expo2(x: f64) -> f64 { + let k_ln2 = f64::from_bits(0x40962066151add8b); + /* note that k is odd and scale*scale overflows */ + let scale = f64::from_bits(((0x3ff + K / 2) as u64) << 20); + /* exp(x - k ln2) * 2**(k-1) */ + exp(x - k_ln2) * scale * scale +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index eda6b5b7293..3b3822711d6 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -19,6 +19,7 @@ mod ceil; mod ceilf; mod cos; mod cosf; +mod cosh; mod coshf; mod exp; mod exp2; @@ -75,6 +76,7 @@ pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cos::cos; pub use self::cosf::cosf; +pub use self::cosh::cosh; pub use self::coshf::coshf; pub use self::exp::exp; pub use self::exp2::exp2; @@ -122,6 +124,7 @@ pub use self::truncf::truncf; mod expo2; mod k_cos; mod k_cosf; +mod k_expo2; mod k_expo2f; mod k_sin; mod k_sinf; @@ -135,6 +138,7 @@ mod rem_pio2f; use self::expo2::expo2; use self::k_cos::k_cos; use self::k_cosf::k_cosf; +use self::k_expo2::k_expo2; use self::k_expo2f::k_expo2f; use self::k_sin::k_sin; use self::k_sinf::k_sinf; -- cgit 1.4.1-3-g733a5 From bbf1c5432a76f59ab1771bf92a4e46a5afe99693 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 15 Jul 2018 18:13:09 -0500 Subject: enable tests for cosh --- library/compiler-builtins/libm/test-generator/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 7caada4ef3e..897f16d6c91 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -703,7 +703,7 @@ f64_f64! { cbrt, ceil, cos, - // cosh, + cosh, exp, exp2, expm1, -- cgit 1.4.1-3-g733a5 From 1e617876949964277328a2dde5914128f0fb9d33 Mon Sep 17 00:00:00 2001 From: Cássio Kirch Date: Sun, 15 Jul 2018 21:35:08 -0300 Subject: unused cast removed --- library/compiler-builtins/libm/src/math/cosh.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs index 54c0a61dc05..f3f7fbfbeb1 100644 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -9,7 +9,6 @@ pub fn cosh(mut x: f64) -> f64 { ix &= 0x7fffffffffffffff; x = f64::from_bits(ix); let w = ix >> 32; - let w = w as u32; /* |x| < log(2) */ if w < 0x3fe62e42 { -- cgit 1.4.1-3-g733a5 From e8e11976299cb5e58a0b2bbdbd0fd9537f23afff Mon Sep 17 00:00:00 2001 From: Cássio Kirch Date: Sun, 15 Jul 2018 21:36:22 -0300 Subject: words insertion on k_expo2 --- library/compiler-builtins/libm/src/math/k_expo2.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs index 7a4045dfc7b..e295c7a5346 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2.rs @@ -1,14 +1,14 @@ use super::exp; /* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ -const K: i64 = 2043; +const K: i32 = 2043; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[inline] pub(crate) fn k_expo2(x: f64) -> f64 { let k_ln2 = f64::from_bits(0x40962066151add8b); /* note that k is odd and scale*scale overflows */ - let scale = f64::from_bits(((0x3ff + K / 2) as u64) << 20); + let scale = f64::from_bits(((((0x3ff + K / 2) as u32) << 20) as u64) << 32); /* exp(x - k ln2) * 2**(k-1) */ exp(x - k_ln2) * scale * scale } -- cgit 1.4.1-3-g733a5 From b1b06f583a9b4b7627311b71aeac77da8f7cd95f Mon Sep 17 00:00:00 2001 From: Sébastien Marie Date: Mon, 16 Jul 2018 06:17:38 +0200 Subject: openbsd: doesn't use `static` as it could result duplicated symbols --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 271b010bc4a..a7091d541f4 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -13,7 +13,7 @@ fn main() { // OpenBSD provides compiler_rt by default, use it instead of rebuilding it from source if target.contains("openbsd") { println!("cargo:rustc-link-search=native=/usr/lib"); - println!("cargo:rustc-link-lib=static=compiler_rt"); + println!("cargo:rustc-link-lib=compiler_rt"); return; } -- cgit 1.4.1-3-g733a5 From 99830bac40414e37df5663cda2b46a81a086a1d0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 16 Jul 2018 13:03:40 -0500 Subject: test edge cases --- library/compiler-builtins/libm/ci/script.sh | 5 -- .../libm/test-generator/Cargo.toml | 1 + .../libm/test-generator/src/main.rs | 92 ++++++++++++++++------ 3 files changed, 70 insertions(+), 28 deletions(-) diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index f2a294b488f..cf37ac1ca64 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -15,11 +15,6 @@ main() { # generate tests cargo run --package test-generator --target x86_64-unknown-linux-musl - if cargo fmt --version >/dev/null 2>&1; then - # nicer syntax error messages (if any) - cargo fmt - fi - # run tests cross test --target $TARGET --release diff --git a/library/compiler-builtins/libm/test-generator/Cargo.toml b/library/compiler-builtins/libm/test-generator/Cargo.toml index f45d173b451..b810d9daf63 100644 --- a/library/compiler-builtins/libm/test-generator/Cargo.toml +++ b/library/compiler-builtins/libm/test-generator/Cargo.toml @@ -6,3 +6,4 @@ publish = false [dependencies] rand = "0.5.3" +itertools = "0.7.8" diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 7c48031c174..e22e2018640 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -4,13 +4,15 @@ // NOTE usually the only thing you need to do to test a new math function is to add it to one of the // macro invocations found in the bottom of this file. +#[macro_use] +extern crate itertools; extern crate rand; use std::error::Error; use std::fmt::Write as _0; use std::fs::{self, File}; use std::io::Write as _1; -use std::{i16, u16, u32, u64, u8}; +use std::{f32, f64, i16, u16, u32, u64, u8}; use rand::{Rng, SeedableRng, XorShiftRng}; @@ -34,6 +36,30 @@ fn f64(rng: &mut XorShiftRng) -> f64 { f64::from_bits(sign + exponent + mantissa) } +const EDGE_CASES32: &[f32] = &[ + -0., + 0., + f32::EPSILON, + f32::INFINITY, + f32::MAX, + f32::MIN, + f32::MIN_POSITIVE, + f32::NAN, + f32::NEG_INFINITY, +]; + +const EDGE_CASES64: &[f64] = &[ + -0., + 0., + f64::EPSILON, + f64::INFINITY, + f64::MAX, + f64::MIN, + f64::MIN_POSITIVE, + f64::NAN, + f64::NEG_INFINITY, +]; + // fn(f32) -> f32 macro_rules! f32_f32 { ($($intr:ident,)*) => { @@ -45,8 +71,9 @@ macro_rules! f32_f32 { $( let mut cases = String::new(); - for _ in 0..NTESTS { - let inp = f32(rng); + + // random inputs + for inp in EDGE_CASES32.iter().cloned().chain((0..NTESTS).map(|_| f32(rng))) { let out = unsafe { $intr(inp) }; let inp = inp.to_bits(); @@ -112,11 +139,17 @@ macro_rules! f32f32_f32 { $(fn $intr(_: f32, _: f32) -> f32;)* } + let mut rng2 = rng.clone(); + let mut rng3 = rng.clone(); $( let mut cases = String::new(); - for _ in 0..NTESTS { - let i1 = f32(rng); - let i2 = f32(rng); + for (i1, i2) in iproduct!( + EDGE_CASES32.iter().cloned(), + EDGE_CASES32.iter().cloned() + ).chain(EDGE_CASES32.iter().map(|i1| (*i1, f32(rng)))) + .chain(EDGE_CASES32.iter().map(|i2| (f32(&mut rng2), *i2))) + .chain((0..NTESTS).map(|_| (f32(&mut rng3), f32(&mut rng3)))) + { let out = unsafe { $intr(i1, i2) }; let i1 = i1.to_bits(); @@ -186,12 +219,16 @@ macro_rules! f32f32f32_f32 { $(fn $intr(_: f32, _: f32, _: f32) -> f32;)* } + let mut rng2 = rng.clone(); $( let mut cases = String::new(); - for _ in 0..NTESTS { - let i1 = f32(rng); - let i2 = f32(rng); - let i3 = f32(rng); + for (i1, i2, i3) in iproduct!( + EDGE_CASES32.iter().cloned(), + EDGE_CASES32.iter().cloned(), + EDGE_CASES32.iter().cloned() + ).chain(EDGE_CASES32.iter().map(|i1| (*i1, f32(rng), f32(rng)))) + .chain((0..NTESTS).map(|_| (f32(&mut rng2), f32(&mut rng2), f32(&mut rng2)))) + { let out = unsafe { $intr(i1, i2, i3) }; let i1 = i1.to_bits(); @@ -266,10 +303,10 @@ macro_rules! f32i32_f32 { $(fn $intr(_: f32, _: i32) -> f32;)* } + let mut rng2 = rng.clone(); $( let mut cases = String::new(); - for _ in 0..NTESTS { - let i1 = f32(rng); + for i1 in EDGE_CASES32.iter().cloned().chain((0..NTESTS).map(|_| f32(&mut rng2))) { let i2 = rng.gen_range(i16::MIN, i16::MAX); let out = unsafe { $intr(i1, i2 as i32) }; @@ -342,8 +379,7 @@ macro_rules! f64_f64 { $( let mut cases = String::new(); - for _ in 0..NTESTS { - let inp = f64(rng); + for inp in EDGE_CASES64.iter().cloned().chain((0..NTESTS).map(|_| f64(rng))) { let out = unsafe { $intr(inp) }; let inp = inp.to_bits(); @@ -412,11 +448,17 @@ macro_rules! f64f64_f64 { $(fn $intr(_: f64, _: f64) -> f64;)* } + let mut rng2 = rng.clone(); + let mut rng3 = rng.clone(); $( let mut cases = String::new(); - for _ in 0..NTESTS { - let i1 = f64(rng); - let i2 = f64(rng); + for (i1, i2) in iproduct!( + EDGE_CASES64.iter().cloned(), + EDGE_CASES64.iter().cloned() + ).chain(EDGE_CASES64.iter().map(|i1| (*i1, f64(rng)))) + .chain(EDGE_CASES64.iter().map(|i2| (f64(&mut rng2), *i2))) + .chain((0..NTESTS).map(|_| (f64(&mut rng3), f64(&mut rng3)))) + { let out = unsafe { $intr(i1, i2) }; let i1 = i1.to_bits(); @@ -485,12 +527,16 @@ macro_rules! f64f64f64_f64 { $(fn $intr(_: f64, _: f64, _: f64) -> f64;)* } + let mut rng2 = rng.clone(); $( let mut cases = String::new(); - for _ in 0..NTESTS { - let i1 = f64(rng); - let i2 = f64(rng); - let i3 = f64(rng); + for (i1, i2, i3) in iproduct!( + EDGE_CASES64.iter().cloned(), + EDGE_CASES64.iter().cloned(), + EDGE_CASES64.iter().cloned() + ).chain(EDGE_CASES64.iter().map(|i1| (*i1, f64(rng), f64(rng)))) + .chain((0..NTESTS).map(|_| (f64(&mut rng2), f64(&mut rng2), f64(&mut rng2)))) + { let out = unsafe { $intr(i1, i2, i3) }; let i1 = i1.to_bits(); @@ -565,10 +611,10 @@ macro_rules! f64i32_f64 { $(fn $intr(_: f64, _: i32) -> f64;)* } + let mut rng2 = rng.clone(); $( let mut cases = String::new(); - for _ in 0..NTESTS { - let i1 = f64(rng); + for i1 in EDGE_CASES64.iter().cloned().chain((0..NTESTS).map(|_| f64(&mut rng2))) { let i2 = rng.gen_range(i16::MIN, i16::MAX); let out = unsafe { $intr(i1, i2 as i32) }; -- cgit 1.4.1-3-g733a5 From e6f9e770064d7c86d80c9bb311726085dae91aaa Mon Sep 17 00:00:00 2001 From: Richard Dodd Date: Mon, 16 Jul 2018 17:56:14 +0100 Subject: Implement atan --- library/compiler-builtins/libm/src/lib.rs | 2 - library/compiler-builtins/libm/src/math/atan.rs | 170 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/atan.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 38ebeac413b..0e1ed61d277 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -374,7 +374,6 @@ pub trait F64Ext: private::Sealed + Sized { fn acos(self) -> Self; - #[cfg(todo)] fn atan(self) -> Self; #[cfg(todo)] @@ -541,7 +540,6 @@ impl F64Ext for f64 { acos(self) } - #[cfg(todo)] #[inline] fn atan(self) -> Self { atan(self) diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs new file mode 100644 index 00000000000..d057af6d663 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -0,0 +1,170 @@ +/* atan(x) + * Method + * 1. Reduce x to positive by atan(x) = -atan(-x). + * 2. According to the integer k=4t+0.25 chopped, t=x, the argument + * is further reduced to one of the following intervals and the + * arctangent of t is evaluated by the corresponding formula: + * + * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) + * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) + * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) + * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) + * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +use super::fabs; +use core::f64; + +const ATANHI: [f64; 4] = [ + 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ + 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ + 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ + 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ +]; + +const ATANLO: [f64; 4] = [ + 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ + 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ + 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ + 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ +]; + +const AT: [f64; 11] = [ + 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ + -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ + 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ + -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ + 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ + -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ + 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ + -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ + 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ + -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ + 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ +]; + +#[inline] +pub fn atan(x: f64) -> f64 { + let mut x = x; + let mut ix = (x.to_bits() >> 32) as u32; + let sign = ix >> 31; + ix &= 0x7fff_ffff; + if ix >= 0x4410_0000 { + if x.is_nan() { + return x; + } + + let z = ATANHI[3] + f64::from_bits(0x0380_0000); // 0x1p-120f + return if sign != 0 { -z } else { z }; + } + + let id = if ix < 0x3fdc_0000 { + /* |x| < 0.4375 */ + if ix < 0x3e40_0000 { + /* |x| < 2^-27 */ + if ix < 0x0010_0000 { + /* raise underflow for subnormal x */ + force_eval!(x as f32); + } + + return x; + } + + -1 + } else { + x = fabs(x); + if ix < 0x3ff30000 { + /* |x| < 1.1875 */ + if ix < 0x3fe60000 { + /* 7/16 <= |x| < 11/16 */ + x = (2. * x - 1.) / (2. + x); + 0 + } else { + /* 11/16 <= |x| < 19/16 */ + x = (x - 1.) / (x + 1.); + 1 + } + } else { + if ix < 0x40038000 { + /* |x| < 2.4375 */ + x = (x - 1.5) / (1. + 1.5 * x); + 2 + } else { + /* 2.4375 <= |x| < 2^66 */ + x = -1. / x; + 3 + } + } + }; + + let z = x * x; + let w = z * z; + /* break sum from i=0 to 10 AT[i]z**(i+1) into odd and even poly */ + let s1 = z * (AT[0] + w * (AT[2] + w * (AT[4] + w * (AT[6] + w * (AT[8] + w * AT[10]))))); + let s2 = w * (AT[1] + w * (AT[3] + w * (AT[5] + w * (AT[7] + w * AT[9])))); + + if id < 0 { + return x - x * (s1 + s2); + } + + let z = ATANHI[id as usize] - (x * (s1 + s2) - ATANLO[id as usize] - x); + + if sign != 0 { + -z + } else { + z + } +} + +#[cfg(test)] +mod tests { + use super::atan; + use core::f64; + + #[test] + fn sanity_check() { + for (input, answer) in [ + (3.0_f64.sqrt() / 3.0, f64::consts::FRAC_PI_6), + (1.0, f64::consts::FRAC_PI_4), + (3.0_f64.sqrt(), f64::consts::FRAC_PI_3), + (-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6), + (-1.0, -f64::consts::FRAC_PI_4), + (-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3), + ].iter() + { + assert!( + (atan(*input) - answer) / answer < 1e-5, + "\natan({:.4}/16) = {:.4}, actual: {}", + input * 16.0, + answer, + atan(*input) + ); + } + } + + #[test] + fn zero() { + assert_eq!(atan(0.0), 0.0); + } + + #[test] + fn infinity() { + assert_eq!(atan(f64::INFINITY), f64::consts::FRAC_PI_2); + } + + #[test] + fn minus_infinity() { + assert_eq!(atan(f64::NEG_INFINITY), -f64::consts::FRAC_PI_2); + } + + #[test] + fn nan() { + assert!(atan(f64::NAN).is_nan()); + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 352e1d37b6c..64ab3faa703 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -11,6 +11,7 @@ mod acos; mod acosf; mod asin; mod asinf; +mod atan; mod atan2f; mod atanf; mod cbrt; @@ -70,6 +71,7 @@ pub use self::acos::acos; pub use self::acosf::acosf; pub use self::asin::asin; pub use self::asinf::asinf; +pub use self::atan::atan; pub use self::atan2f::atan2f; pub use self::atanf::atanf; pub use self::cbrt::cbrt; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index e22e2018640..a3efd076962 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -745,7 +745,7 @@ f32i32_f32! { f64_f64! { acos, asin, - // atan, + atan, cbrt, ceil, cos, -- cgit 1.4.1-3-g733a5 From 33086672fa30ef627cbb69896b79ad6c936c2f2f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 16 Jul 2018 16:37:35 -0700 Subject: Don't build multc3 on AArch64 MSVC Apparently it doesn't compile due to an odd compiler error! This intrinsic has to do with complex arithmetic anyway and we shouldn't need it. --- library/compiler-builtins/build.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a7091d541f4..cdcbfe24cd7 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -415,11 +415,14 @@ mod c { "floatsitf.c", "floatunditf.c", "floatunsitf.c", - "multc3.c", "trunctfdf2.c", "trunctfsf2.c", ], ); + + if target_os != "windows" { + sources.extend(&["multc3.c"]); + } } // Remove the assembly implementations that won't compile for the target -- cgit 1.4.1-3-g733a5 From 579a0ad4fd1dab5ac84aecaf711a79b51f3ed2c6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 16 Jul 2018 18:46:59 -0500 Subject: fix rebase error --- library/compiler-builtins/libm/src/math/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 3f6fa321149..f3f533ddd21 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -10,6 +10,7 @@ macro_rules! force_eval { mod acos; mod acosf; mod asin; +mod asinf; mod atan2; mod atan2f; mod atanf; -- cgit 1.4.1-3-g733a5 From addfefd63f24c4caeed01326b4f91e029d450b97 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 16 Jul 2018 18:54:19 -0500 Subject: fix another rebase error --- library/compiler-builtins/libm/src/math/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index f3f533ddd21..49f5059dcb0 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -11,6 +11,7 @@ mod acos; mod acosf; mod asin; mod asinf; +mod atan; mod atan2; mod atan2f; mod atanf; -- cgit 1.4.1-3-g733a5 From 29c1188f1f7626d0552b781fc97a62d11f2e6a03 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 16 Jul 2018 20:03:30 -0500 Subject: cargo fmt --- library/compiler-builtins/libm/src/math/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 49f5059dcb0..754efa9f6da 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -72,8 +72,8 @@ pub use self::acos::acos; pub use self::acosf::acosf; pub use self::asin::asin; pub use self::asinf::asinf; -pub use self::atan2::atan2; pub use self::atan::atan; +pub use self::atan2::atan2; pub use self::atan2f::atan2f; pub use self::atanf::atanf; pub use self::cbrt::cbrt; -- cgit 1.4.1-3-g733a5 From fe84c2050e917466b67866b76b7155f383524cf4 Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Mon, 16 Jul 2018 21:18:38 -0500 Subject: Add unit tests for atan2 --- library/compiler-builtins/libm/src/math/atan2.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index 324b1e937f9..1816bca5c50 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -70,3 +70,14 @@ pub fn atan2(y: f64, x: f64) -> f64 { _ => (z - PI_LO) - PI, /* atan(-,-) */ } } + +#[test] +fn sanity_check() { + assert_eq!(atan2(0.0, 1.0), 0.0); + assert_eq!(atan2(0.0, -1.0), PI); + assert_eq!(atan2(-0.0, -1.0), -PI); + assert_eq!(atan2(3.0, 2.0), atan(3.0/2.0)); + assert_eq!(atan2(2.0, -1.0), atan(2.0/-1.0) + PI); + assert_eq!(atan2(-2.0, -1.0), atan(-2.0/-1.0) - PI); +} + -- cgit 1.4.1-3-g733a5 From 203a8aea86c1e20af051d63d64f375364671f4ed Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Mon, 16 Jul 2018 21:22:35 -0500 Subject: rustfmt --- library/compiler-builtins/libm/src/math/atan2.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index 1816bca5c50..a719b6d632c 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -76,8 +76,7 @@ fn sanity_check() { assert_eq!(atan2(0.0, 1.0), 0.0); assert_eq!(atan2(0.0, -1.0), PI); assert_eq!(atan2(-0.0, -1.0), -PI); - assert_eq!(atan2(3.0, 2.0), atan(3.0/2.0)); - assert_eq!(atan2(2.0, -1.0), atan(2.0/-1.0) + PI); - assert_eq!(atan2(-2.0, -1.0), atan(-2.0/-1.0) - PI); + assert_eq!(atan2(3.0, 2.0), atan(3.0 / 2.0)); + assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI); + assert_eq!(atan2(-2.0, -1.0), atan(-2.0 / -1.0) - PI); } - -- cgit 1.4.1-3-g733a5 From f12ba75f67ede8582bfdf20e75eafbf423112e50 Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Tue, 17 Jul 2018 14:56:11 -0500 Subject: pow! --- library/compiler-builtins/libm/src/math/pow.rs | 395 +++++++++++++++++++++++++ 1 file changed, 395 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/pow.rs diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs new file mode 100644 index 00000000000..3d0769b3440 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -0,0 +1,395 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* pow(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 53-24 = 29 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. 1 ** (anything) is 1 + * 3. (anything except 1) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. -1 ** +-INF is 1 + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero + * 14. -0 ** (+odd integer) is -0 + * 15. -0 ** (-odd integer) is -INF, raise divbyzero + * 16. +INF ** (+anything except 0,NAN) is +INF + * 17. +INF ** (-anything except 0,NAN) is +0 + * 18. -INF ** (+odd integer) is -INF + * 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) + * 20. (anything) ** 1 is (anything) + * 21. (anything) ** -1 is 1/(anything) + * 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 23. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + * pow(x,y) returns x**y nearly rounded. In particular + * pow(integer,integer) + * always returns the correct integer provided it is + * representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +// #include "libm.h" + +/* Concerns: + * - Some constants are shared; DRY? + * - FLT_EVAL_METHOD: the others sidestep this (epsilon or just always true in the case of hypot (#71)) + */ + +use super::{fabs, scalbn, sqrt, with_set_low_word, with_set_high_word, get_high_word}; + +const BP: [f64; 2] = [1.0, 1.5]; +const DP_H: [f64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ +const DP_L: [f64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ +const TWO53: f64 = 9007199254740992.0; /* 0x43400000_00000000 */ +const HUGE: f64 = 1.0e300; +const TINY: f64 = 1.0e-300; + +// poly coefs for (3/2)*(log(x)-2s-2/3*s**3: +const L1: f64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ +const L2: f64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ +const L3: f64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ +const L4: f64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ +const L5: f64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ +const L6: f64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ +const P1: f64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ +const P2: f64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ +const P3: f64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ +const P4: f64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ +const P5: f64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ +const LG2: f64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ +const LG2_H: f64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ +const LG2_L: f64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ +const OVT: f64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ +const CP: f64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ +const CP_H: f64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ +const CP_L: f64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ +const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ +const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ +const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ + +#[inline] +pub fn pow(x: f64, y: f64) -> f64 { + let t1: f64; + let t2: f64; + + let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); + let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); + + let mut ix: i32 = (hx & 0x7fffffff) as i32; + let iy: i32 = (hy & 0x7fffffff) as i32; + + /* x**0 = 1, even if x is NaN */ + if ((iy as u32) | ly) == 0 { + return 1.0; + } + + /* 1**y = 1, even if y is NaN */ + if hx == 0x3ff00000 && lx == 0 { + return 1.0; + } + + /* NaN if either arg is NaN */ + if ix > 0x7ff00000 || (ix == 0x7ff00000 && lx != 0) || + iy > 0x7ff00000 || (iy == 0x7ff00000 && ly != 0) { + return x + y; + } + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + let mut yisint: i32 = 0; + let mut k: i32; + let mut j: i32; + if hx < 0 { + if iy >= 0x43400000 { + yisint = 2; /* even integer y */ + } else if iy >= 0x3ff00000 { + k = (iy >> 20) - 0x3ff; /* exponent */ + + if k > 20 { + j = (ly >> (52 - k)) as i32; + + if (j << (52 - k)) == (ly as i32) { + yisint = 2 - (j & 1); + } + } else if ly == 0 { + j = iy >> (20 - k); + + if (j << (20 - k)) == iy { + yisint = 2 - (j & 1); + } + } + } + } + + if ly == 0 { + /* special value of y */ + if iy == 0x7ff00000 { + /* y is +-inf */ + return if ((ix - 0x3ff00000) | (lx as i32)) == 0 { + /* (-1)**+-inf is 1 */ + 1.0 + } else if ix >= 0x3ff00000 { + /* (|x|>1)**+-inf = inf,0 */ + if hy >= 0 { y } else { 0.0 } + } else { + /* (|x|<1)**+-inf = 0,inf */ + if hy >= 0 { 0.0 } else { -y } + }; + } + + if iy == 0x3ff00000 { + /* y is +-1 */ + return if hy >= 0 { x } else { 1.0 / x }; + } + + if hy == 0x40000000 { + /* y is 2 */ + return x * x; + } + + if hy == 0x3fe00000 { + /* y is 0.5 */ + if hx >= 0 { + /* x >= +0 */ + return sqrt(x); + } + } + } + + let mut ax: f64 = fabs(x); + if lx == 0 { + /* special value of x */ + if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { + /* x is +-0,+-inf,+-1 */ + let mut z: f64 = ax; + + if hy < 0 { + /* z = (1/|x|) */ + z = 1.0 / z; + } + + if hx < 0 { + if ((ix-0x3ff00000)|yisint) == 0 { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } else if yisint == 1 { + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + } + + return z; + } + } + + let mut s: f64 = 1.0; /* sign of result */ + if hx < 0 { + if yisint == 0 { + /* (x<0)**(non-int) is NaN */ + return (x - x) / (x - x); + } + + if yisint == 1 { + /* (x<0)**(odd int) */ + s = -1.0; + } + } + + /* |y| is HUGE */ + if iy > 0x41e00000 { + /* if |y| > 2**31 */ + if iy > 0x43f00000 { + /* if |y| > 2**64, must o/uflow */ + if ix <= 0x3fefffff { + return if hy < 0 { HUGE * HUGE } else { TINY * TINY }; + } + + if ix >= 0x3ff00000 { + return if hy > 0 { HUGE * HUGE } else { TINY * TINY }; + } + } + + /* over/underflow if x is not close to one */ + if ix < 0x3fefffff { + return if hy < 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + } + if ix > 0x3ff00000 { + return if hy > 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + } + + /* now |1-x| is TINY <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ + let w: f64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); + let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ + let v: f64 = t * IVLN2_L - w * IVLN2; + t1 = with_set_low_word(u + v, 0); + t2 = v - (t1 - u); + } else { + // double ss,s2,s_h,s_l,t_h,t_l; + let mut n: i32 = 0; + + if ix < 0x00100000 { + /* take care subnormal number */ + ax *= TWO53; + n -= 53; + ix = get_high_word(ax) as i32; + } + + n += (ix >> 20) - 0x3ff; + j = ix & 0x000fffff; + + /* determine interval */ + let k: i32; + ix = j | 0x3ff00000; /* normalize ix */ + if j <= 0x3988E { + /* |x|> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18)); + let t_l: f64 = ax - (t_h - BP[k as usize]); + let s_l: f64 = v * ((u - s_h * t_h) - s_h * t_l); + + /* compute log(ax) */ + let s2: f64 = ss * ss; + let mut r: f64 = s2 * s2 * (L1 + s2 * (L2 + s2 *(L3 + s2 *(L4 + s2 *(L5 + s2 * L6))))); + r += s_l * (s_h + ss); + let s2: f64 = s_h * s_h; + let t_h: f64 = with_set_low_word(3.0 + s2 + r, 0); + let t_l: f64 = r - ((t_h - 3.0) - s2); + + /* u+v = ss*(1+...) */ + let u: f64 = s_h * t_h; + let v: f64 = s_l * t_h + t_l * ss; + + /* 2/(3log2)*(ss+...) */ + let p_h: f64 = with_set_low_word(u + v, 0); + let p_l = v - (p_h-u); + let z_h: f64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ + let z_l: f64 = CP_L * p_h + p_l * CP + DP_L[k as usize]; + + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + let t: f64 = n as f64; + t1 = with_set_low_word(((z_h + z_l) + DP_H[k as usize]) + t, 0); + t2 = z_l - (((t1 - t) - DP_H[k as usize]) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + let y1: f64 = with_set_low_word(y, 0); + let p_l: f64 = (y - y1) * t1 + y * t2; + let mut p_h: f64 = y1 * t1; + let z: f64 = p_l + p_h; + let mut j: i32 = (z.to_bits() >> 32) as i32; + let i: i32 = z.to_bits() as i32; + // let (j, i): (i32, i32) = ((z.to_bits() >> 32) as i32, z.to_bits() as i32); + + if j >= 0x40900000 { + /* z >= 1024 */ + if (j - 0x40900000) | i != 0 { + /* if z > 1024 */ + return s * HUGE * HUGE; /* overflow */ + } + + if p_l + OVT > z - p_h { + return s * HUGE * HUGE; /* overflow */ + } + } else if (j & 0x7fffffff) >= 0x4090cc00 { + /* z <= -1075 */ + // FIXME: instead of abs(j) use unsigned j + + if (((j as u32) - 0xc090cc00) | (i as u32)) != 0 { + /* z < -1075 */ + return s * TINY * TINY; /* underflow */ + } + + if p_l <= z - p_h { + return s * TINY * TINY; /* underflow */ + } + } + + /* compute 2**(p_h+p_l) */ + let i: i32 = j & (0x7fffffff as i32); + k = (i >> 20) - 0x3ff; + let mut n: i32 = 0; + + if i > 0x3fe00000 { + /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00100000 >> (k + 1)); + k = ((n&0x7fffffff) >> 20) - 0x3ff; /* new k for n */ + let t: f64 = with_set_high_word(0.0, (n & !(0x000fffff >> k)) as u32); + n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); + if j < 0 { + n = -n; + } + p_h -= t; + } + + let t: f64 = with_set_low_word(p_l + p_h, 0); + let u: f64 = t * LG2_H; + let v: f64 = (p_l - (t - p_h)) * LG2 + t * LG2_L; + let mut z: f64 = u + v; + let w: f64 = v - (z - u); + let t: f64 = z * z; + let t1: f64 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + let r: f64 = (z * t1) / (t1 - 2.0) - (w + z*w); + z = 1.0 - (r - z); + j = get_high_word(z) as i32; + j += n << 20; + + if (j >> 20) <= 0 { + /* subnormal output */ + z = scalbn(z,n); + } else { + z = with_set_high_word(z, j as u32); + } + + return s*z; +} -- cgit 1.4.1-3-g733a5 From 440e835967dd4bac67a7b20ea8b063dfa347891e Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Tue, 17 Jul 2018 15:03:39 -0500 Subject: Enable tests and expose --- library/compiler-builtins/libm/src/lib.rs | 2 -- library/compiler-builtins/libm/src/math/mod.rs | 3 ++- library/compiler-builtins/libm/test-generator/src/main.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 1837b9c1f9e..06991effe1d 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -343,7 +343,6 @@ pub trait F64Ext: private::Sealed + Sized { // NOTE depends on unstable intrinsics::powif64 // fn powi(self, n: i32) -> Self; - #[cfg(todo)] fn powf(self, n: Self) -> Self; fn sqrt(self) -> Self; @@ -463,7 +462,6 @@ impl F64Ext for f64 { } } - #[cfg(todo)] #[inline] fn powf(self, n: Self) -> Self { pow(self, n) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 754efa9f6da..6dd362d0094 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -50,6 +50,7 @@ mod log2; mod log2f; mod logf; mod powf; +mod pow; mod round; mod roundf; mod scalbn; @@ -111,6 +112,7 @@ pub use self::log2::log2; pub use self::log2f::log2f; pub use self::logf::logf; pub use self::powf::powf; +pub use self::pow::pow; pub use self::round::round; pub use self::roundf::roundf; pub use self::scalbn::scalbn; @@ -167,7 +169,6 @@ fn get_low_word(x: f64) -> u32 { x.to_bits() as u32 } -#[allow(dead_code)] #[inline] fn with_set_high_word(f: f64, hi: u32) -> f64 { let mut tmp = f.to_bits(); diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 09a9cb8f588..4c4e420a285 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -774,7 +774,7 @@ f64f64_f64! { fdim, fmod, hypot, - // pow, + pow, } // With signature `fn(f64, f64, f64) -> f64` -- cgit 1.4.1-3-g733a5 From 1c555103ae48c2c452739d9b9b77e4267738965f Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Tue, 17 Jul 2018 15:06:50 -0500 Subject: rustfmt'ed + some clean up --- library/compiler-builtins/libm/src/math/mod.rs | 4 +- library/compiler-builtins/libm/src/math/pow.rs | 239 +++++++++++++------------ 2 files changed, 129 insertions(+), 114 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 6dd362d0094..752a5991aea 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -49,8 +49,8 @@ mod log1pf; mod log2; mod log2f; mod logf; -mod powf; mod pow; +mod powf; mod round; mod roundf; mod scalbn; @@ -111,8 +111,8 @@ pub use self::log1pf::log1pf; pub use self::log2::log2; pub use self::log2f::log2f; pub use self::logf::logf; -pub use self::powf::powf; pub use self::pow::pow; +pub use self::powf::powf; pub use self::round::round; pub use self::roundf::roundf; pub use self::scalbn::scalbn; diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 3d0769b3440..69c086b0f24 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -8,93 +8,87 @@ * is preserved. * ==================================================== */ -/* pow(x,y) return x**y - * - * n - * Method: Let x = 2 * (1+f) - * 1. Compute and return log2(x) in two pieces: - * log2(x) = w1 + w2, - * where w1 has 53-24 = 29 bit trailing zeros. - * 2. Perform y*log2(x) = n+y' by simulating muti-precision - * arithmetic, where |y'|<=0.5. - * 3. Return x**y = 2**n*exp(y'*log2) - * - * Special cases: - * 1. (anything) ** 0 is 1 - * 2. 1 ** (anything) is 1 - * 3. (anything except 1) ** NAN is NAN - * 4. NAN ** (anything except 0) is NAN - * 5. +-(|x| > 1) ** +INF is +INF - * 6. +-(|x| > 1) ** -INF is +0 - * 7. +-(|x| < 1) ** +INF is +0 - * 8. +-(|x| < 1) ** -INF is +INF - * 9. -1 ** +-INF is 1 - * 10. +0 ** (+anything except 0, NAN) is +0 - * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 - * 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero - * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero - * 14. -0 ** (+odd integer) is -0 - * 15. -0 ** (-odd integer) is -INF, raise divbyzero - * 16. +INF ** (+anything except 0,NAN) is +INF - * 17. +INF ** (-anything except 0,NAN) is +0 - * 18. -INF ** (+odd integer) is -INF - * 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) - * 20. (anything) ** 1 is (anything) - * 21. (anything) ** -1 is 1/(anything) - * 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) - * 23. (-anything except 0 and inf) ** (non-integer) is NAN - * - * Accuracy: - * pow(x,y) returns x**y nearly rounded. In particular - * pow(integer,integer) - * always returns the correct integer provided it is - * representable. - * - * Constants : - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. - */ - -// #include "libm.h" -/* Concerns: - * - Some constants are shared; DRY? - * - FLT_EVAL_METHOD: the others sidestep this (epsilon or just always true in the case of hypot (#71)) - */ - -use super::{fabs, scalbn, sqrt, with_set_low_word, with_set_high_word, get_high_word}; - -const BP: [f64; 2] = [1.0, 1.5]; +/// pow(x,y) return x**y +/// +/// n +/// Method: Let x = 2 * (1+f) +/// 1. Compute and return log2(x) in two pieces: +/// log2(x) = w1 + w2, +/// where w1 has 53-24 = 29 bit trailing zeros. +/// 2. Perform y*log2(x) = n+y' by simulating muti-precision +/// arithmetic, where |y'|<=0.5. +/// 3. Return x**y = 2**n*exp(y'*log2) +/// +/// Special cases: +/// 1. (anything) ** 0 is 1 +/// 2. 1 ** (anything) is 1 +/// 3. (anything except 1) ** NAN is NAN +/// 4. NAN ** (anything except 0) is NAN +/// 5. +-(|x| > 1) ** +INF is +INF +/// 6. +-(|x| > 1) ** -INF is +0 +/// 7. +-(|x| < 1) ** +INF is +0 +/// 8. +-(|x| < 1) ** -INF is +INF +/// 9. -1 ** +-INF is 1 +/// 10. +0 ** (+anything except 0, NAN) is +0 +/// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 +/// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero +/// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero +/// 14. -0 ** (+odd integer) is -0 +/// 15. -0 ** (-odd integer) is -INF, raise divbyzero +/// 16. +INF ** (+anything except 0,NAN) is +INF +/// 17. +INF ** (-anything except 0,NAN) is +0 +/// 18. -INF ** (+odd integer) is -INF +/// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) +/// 20. (anything) ** 1 is (anything) +/// 21. (anything) ** -1 is 1/(anything) +/// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) +/// 23. (-anything except 0 and inf) ** (non-integer) is NAN +/// +/// Accuracy: +/// pow(x,y) returns x**y nearly rounded. In particular +/// pow(integer,integer) +/// always returns the correct integer provided it is +/// representable. +/// +/// Constants : +/// The hexadecimal values are the intended ones for the following +/// constants. The decimal values may be used, provided that the +/// compiler will convert from decimal to binary accurately enough +/// to produce the hexadecimal values shown. +/// + +use super::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; + +const BP: [f64; 2] = [1.0, 1.5]; const DP_H: [f64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ const DP_L: [f64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ -const TWO53: f64 = 9007199254740992.0; /* 0x43400000_00000000 */ -const HUGE: f64 = 1.0e300; -const TINY: f64 = 1.0e-300; +const TWO53: f64 = 9007199254740992.0; /* 0x43400000_00000000 */ +const HUGE: f64 = 1.0e300; +const TINY: f64 = 1.0e-300; // poly coefs for (3/2)*(log(x)-2s-2/3*s**3: -const L1: f64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ -const L2: f64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ -const L3: f64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ -const L4: f64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ -const L5: f64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ -const L6: f64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ -const P1: f64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ +const L1: f64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ +const L2: f64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ +const L3: f64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ +const L4: f64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ +const L5: f64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ +const L6: f64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ +const P1: f64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ const P2: f64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ -const P3: f64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ +const P3: f64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ const P4: f64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ -const P5: f64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ -const LG2: f64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ -const LG2_H: f64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ -const LG2_L: f64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ -const OVT: f64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ -const CP: f64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ -const CP_H: f64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ -const CP_L: f64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ -const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ -const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ -const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ +const P5: f64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ +const LG2: f64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ +const LG2_H: f64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ +const LG2_L: f64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ +const OVT: f64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ +const CP: f64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ +const CP_H: f64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ +const CP_L: f64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ +const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ +const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ +const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ #[inline] pub fn pow(x: f64, y: f64) -> f64 { @@ -103,7 +97,7 @@ pub fn pow(x: f64, y: f64) -> f64 { let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); - + let mut ix: i32 = (hx & 0x7fffffff) as i32; let iy: i32 = (hy & 0x7fffffff) as i32; @@ -118,9 +112,12 @@ pub fn pow(x: f64, y: f64) -> f64 { } /* NaN if either arg is NaN */ - if ix > 0x7ff00000 || (ix == 0x7ff00000 && lx != 0) || - iy > 0x7ff00000 || (iy == 0x7ff00000 && ly != 0) { - return x + y; + if ix > 0x7ff00000 + || (ix == 0x7ff00000 && lx != 0) + || iy > 0x7ff00000 + || (iy == 0x7ff00000 && ly != 0) + { + return x + y; } /* determine if y is an odd int when x < 0 @@ -136,16 +133,16 @@ pub fn pow(x: f64, y: f64) -> f64 { yisint = 2; /* even integer y */ } else if iy >= 0x3ff00000 { k = (iy >> 20) - 0x3ff; /* exponent */ - + if k > 20 { j = (ly >> (52 - k)) as i32; - + if (j << (52 - k)) == (ly as i32) { yisint = 2 - (j & 1); } } else if ly == 0 { j = iy >> (20 - k); - + if (j << (20 - k)) == iy { yisint = 2 - (j & 1); } @@ -156,16 +153,25 @@ pub fn pow(x: f64, y: f64) -> f64 { if ly == 0 { /* special value of y */ if iy == 0x7ff00000 { - /* y is +-inf */ + /* y is +-inf */ + return if ((ix - 0x3ff00000) | (lx as i32)) == 0 { /* (-1)**+-inf is 1 */ 1.0 } else if ix >= 0x3ff00000 { /* (|x|>1)**+-inf = inf,0 */ - if hy >= 0 { y } else { 0.0 } + if hy >= 0 { + y + } else { + 0.0 + } } else { /* (|x|<1)**+-inf = 0,inf */ - if hy >= 0 { 0.0 } else { -y } + if hy >= 0 { + 0.0 + } else { + -y + } }; } @@ -194,14 +200,14 @@ pub fn pow(x: f64, y: f64) -> f64 { if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { /* x is +-0,+-inf,+-1 */ let mut z: f64 = ax; - + if hy < 0 { /* z = (1/|x|) */ z = 1.0 / z; } if hx < 0 { - if ((ix-0x3ff00000)|yisint) == 0 { + if ((ix - 0x3ff00000) | yisint) == 0 { z = (z - z) / (z - z); /* (-1)**non-int is NaN */ } else if yisint == 1 { z = -z; /* (x<0)**odd = -(|x|**odd) */ @@ -241,17 +247,25 @@ pub fn pow(x: f64, y: f64) -> f64 { /* over/underflow if x is not close to one */ if ix < 0x3fefffff { - return if hy < 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + return if hy < 0 { + s * HUGE * HUGE + } else { + s * TINY * TINY + }; } if ix > 0x3ff00000 { - return if hy > 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + return if hy > 0 { + s * HUGE * HUGE + } else { + s * TINY * TINY + }; } /* now |1-x| is TINY <= 2**-20, suffice to compute log(x) by x-x^2/2+x^3/3-x^4/4 */ - let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ + let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ let w: f64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); - let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ + let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ let v: f64 = t * IVLN2_L - w * IVLN2; t1 = with_set_low_word(u + v, 0); t2 = v - (t1 - u); @@ -262,8 +276,8 @@ pub fn pow(x: f64, y: f64) -> f64 { if ix < 0x00100000 { /* take care subnormal number */ ax *= TWO53; - n -= 53; - ix = get_high_word(ax) as i32; + n -= 53; + ix = get_high_word(ax) as i32; } n += (ix >> 20) - 0x3ff; @@ -271,12 +285,11 @@ pub fn pow(x: f64, y: f64) -> f64 { /* determine interval */ let k: i32; - ix = j | 0x3ff00000; /* normalize ix */ + ix = j | 0x3ff00000; /* normalize ix */ if j <= 0x3988E { /* |x| f64 { /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ let u: f64 = ax - BP[k as usize]; /* bp[0]=1.0, bp[1]=1.5 */ let v: f64 = 1.0 / (ax + BP[k as usize]); - let ss: f64 = u * v; + let ss: f64 = u * v; let s_h = with_set_low_word(ss, 0); /* t_h=ax+bp[k] High */ - let t_h: f64 = with_set_high_word(0.0, - ((ix as u32 >> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18)); + let t_h: f64 = with_set_high_word( + 0.0, + ((ix as u32 >> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18), + ); let t_l: f64 = ax - (t_h - BP[k as usize]); let s_l: f64 = v * ((u - s_h * t_h) - s_h * t_l); /* compute log(ax) */ let s2: f64 = ss * ss; - let mut r: f64 = s2 * s2 * (L1 + s2 * (L2 + s2 *(L3 + s2 *(L4 + s2 *(L5 + s2 * L6))))); + let mut r: f64 = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); r += s_l * (s_h + ss); let s2: f64 = s_h * s_h; let t_h: f64 = with_set_low_word(3.0 + s2 + r, 0); @@ -312,7 +327,7 @@ pub fn pow(x: f64, y: f64) -> f64 { /* 2/(3log2)*(ss+...) */ let p_h: f64 = with_set_low_word(u + v, 0); - let p_l = v - (p_h-u); + let p_l = v - (p_h - u); let z_h: f64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ let z_l: f64 = CP_L * p_h + p_l * CP + DP_L[k as usize]; @@ -323,10 +338,10 @@ pub fn pow(x: f64, y: f64) -> f64 { } /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ - let y1: f64 = with_set_low_word(y, 0); + let y1: f64 = with_set_low_word(y, 0); let p_l: f64 = (y - y1) * t1 + y * t2; let mut p_h: f64 = y1 * t1; - let z: f64 = p_l + p_h; + let z: f64 = p_l + p_h; let mut j: i32 = (z.to_bits() >> 32) as i32; let i: i32 = z.to_bits() as i32; // let (j, i): (i32, i32) = ((z.to_bits() >> 32) as i32, z.to_bits() as i32); @@ -363,7 +378,7 @@ pub fn pow(x: f64, y: f64) -> f64 { if i > 0x3fe00000 { /* if |z| > 0.5, set n = [z+0.5] */ n = j + (0x00100000 >> (k + 1)); - k = ((n&0x7fffffff) >> 20) - 0x3ff; /* new k for n */ + k = ((n & 0x7fffffff) >> 20) - 0x3ff; /* new k for n */ let t: f64 = with_set_high_word(0.0, (n & !(0x000fffff >> k)) as u32); n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); if j < 0 { @@ -379,17 +394,17 @@ pub fn pow(x: f64, y: f64) -> f64 { let w: f64 = v - (z - u); let t: f64 = z * z; let t1: f64 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); - let r: f64 = (z * t1) / (t1 - 2.0) - (w + z*w); + let r: f64 = (z * t1) / (t1 - 2.0) - (w + z * w); z = 1.0 - (r - z); j = get_high_word(z) as i32; j += n << 20; if (j >> 20) <= 0 { /* subnormal output */ - z = scalbn(z,n); + z = scalbn(z, n); } else { z = with_set_high_word(z, j as u32); } - return s*z; + return s * z; } -- cgit 1.4.1-3-g733a5 From 9f920e739a0765f31b77223186dfd16c48b45936 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 17 Jul 2018 19:46:12 -0500 Subject: cargo fmt --- library/compiler-builtins/libm/src/math/pow.rs | 97 +++++++++++++------------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 69c086b0f24..329b3955d88 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -9,55 +9,54 @@ * ==================================================== */ -/// pow(x,y) return x**y -/// -/// n -/// Method: Let x = 2 * (1+f) -/// 1. Compute and return log2(x) in two pieces: -/// log2(x) = w1 + w2, -/// where w1 has 53-24 = 29 bit trailing zeros. -/// 2. Perform y*log2(x) = n+y' by simulating muti-precision -/// arithmetic, where |y'|<=0.5. -/// 3. Return x**y = 2**n*exp(y'*log2) -/// -/// Special cases: -/// 1. (anything) ** 0 is 1 -/// 2. 1 ** (anything) is 1 -/// 3. (anything except 1) ** NAN is NAN -/// 4. NAN ** (anything except 0) is NAN -/// 5. +-(|x| > 1) ** +INF is +INF -/// 6. +-(|x| > 1) ** -INF is +0 -/// 7. +-(|x| < 1) ** +INF is +0 -/// 8. +-(|x| < 1) ** -INF is +INF -/// 9. -1 ** +-INF is 1 -/// 10. +0 ** (+anything except 0, NAN) is +0 -/// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 -/// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero -/// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero -/// 14. -0 ** (+odd integer) is -0 -/// 15. -0 ** (-odd integer) is -INF, raise divbyzero -/// 16. +INF ** (+anything except 0,NAN) is +INF -/// 17. +INF ** (-anything except 0,NAN) is +0 -/// 18. -INF ** (+odd integer) is -INF -/// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) -/// 20. (anything) ** 1 is (anything) -/// 21. (anything) ** -1 is 1/(anything) -/// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) -/// 23. (-anything except 0 and inf) ** (non-integer) is NAN -/// -/// Accuracy: -/// pow(x,y) returns x**y nearly rounded. In particular -/// pow(integer,integer) -/// always returns the correct integer provided it is -/// representable. -/// -/// Constants : -/// The hexadecimal values are the intended ones for the following -/// constants. The decimal values may be used, provided that the -/// compiler will convert from decimal to binary accurately enough -/// to produce the hexadecimal values shown. -/// - +// pow(x,y) return x**y +// +// n +// Method: Let x = 2 * (1+f) +// 1. Compute and return log2(x) in two pieces: +// log2(x) = w1 + w2, +// where w1 has 53-24 = 29 bit trailing zeros. +// 2. Perform y*log2(x) = n+y' by simulating muti-precision +// arithmetic, where |y'|<=0.5. +// 3. Return x**y = 2**n*exp(y'*log2) +// +// Special cases: +// 1. (anything) ** 0 is 1 +// 2. 1 ** (anything) is 1 +// 3. (anything except 1) ** NAN is NAN +// 4. NAN ** (anything except 0) is NAN +// 5. +-(|x| > 1) ** +INF is +INF +// 6. +-(|x| > 1) ** -INF is +0 +// 7. +-(|x| < 1) ** +INF is +0 +// 8. +-(|x| < 1) ** -INF is +INF +// 9. -1 ** +-INF is 1 +// 10. +0 ** (+anything except 0, NAN) is +0 +// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 +// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero +// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero +// 14. -0 ** (+odd integer) is -0 +// 15. -0 ** (-odd integer) is -INF, raise divbyzero +// 16. +INF ** (+anything except 0,NAN) is +INF +// 17. +INF ** (-anything except 0,NAN) is +0 +// 18. -INF ** (+odd integer) is -INF +// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) +// 20. (anything) ** 1 is (anything) +// 21. (anything) ** -1 is 1/(anything) +// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) +// 23. (-anything except 0 and inf) ** (non-integer) is NAN +// +// Accuracy: +// pow(x,y) returns x**y nearly rounded. In particular +// pow(integer,integer) +// always returns the correct integer provided it is +// representable. +// +// Constants : +// The hexadecimal values are the intended ones for the following +// constants. The decimal values may be used, provided that the +// compiler will convert from decimal to binary accurately enough +// to produce the hexadecimal values shown. +// use super::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; const BP: [f64; 2] = [1.0, 1.5]; -- cgit 1.4.1-3-g733a5 From a8cce5bda19ea62439fd167370dcd15c8abecb73 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 17 Jul 2018 20:04:33 -0500 Subject: update changelog; add more copyright notices --- library/compiler-builtins/libm/CHANGELOG.md | 15 +++++++++ library/compiler-builtins/libm/src/math/atan.rs | 11 +++++++ library/compiler-builtins/libm/src/math/atan2.rs | 39 +++++++++++++++++++++++ library/compiler-builtins/libm/src/math/atan2f.rs | 15 +++++++++ 4 files changed, 80 insertions(+) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 107813b0813..d37468685a9 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -7,14 +7,29 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added +- acosf +- asin +- asinf +- atan +- atan2 - atan2f +- atanf - cos +- cosf +- cosh - coshf +- exp2 +- expm1 +- expm1f +- expo2 - fmaf +- pow - sin +- sinf - sinh - sinhf - tan +- tanf - tanh - tanhf diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index d057af6d663..47a2951c6f4 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -1,3 +1,14 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ /* atan(x) * Method * 1. Reduce x to positive by atan(x) = -atan(-x). diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index a719b6d632c..a91ddd84d0d 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -1,3 +1,42 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* atan2(y,x) + * Method : + * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). + * 2. Reduce x to positive by (if x and y are unexceptional): + * ARG (x+iy) = arctan(y/x) ... if x > 0, + * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, + * + * Special cases: + * + * ATAN2((anything), NaN ) is NaN; + * ATAN2(NAN , (anything) ) is NaN; + * ATAN2(+-0, +(anything but NaN)) is +-0 ; + * ATAN2(+-0, -(anything but NaN)) is +-pi ; + * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; + * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; + * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; + * ATAN2(+-INF,+INF ) is +-pi/4 ; + * ATAN2(+-INF,-INF ) is +-3pi/4; + * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + use super::atan; use super::fabs; diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs index a232ffdd61d..211a992a065 100644 --- a/library/compiler-builtins/libm/src/math/atan2f.rs +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + use super::atanf; use super::fabsf; -- cgit 1.4.1-3-g733a5 From 1dbcef117c2c16a4cafbb0160e3383db64bd1d91 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 20:40:30 -0500 Subject: expose math symbol on wasm32-unknown-unknown --- library/compiler-builtins/.gitmodules | 3 +++ library/compiler-builtins/.travis.yml | 3 +++ library/compiler-builtins/libm | 1 + library/compiler-builtins/src/lib.rs | 3 +++ library/compiler-builtins/src/math.rs | 51 +++++++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+) create mode 160000 library/compiler-builtins/libm create mode 100644 library/compiler-builtins/src/math.rs diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index 3ff1154f3e7..7162b2c4d5b 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,6 @@ [submodule "compiler-rt"] path = compiler-rt url = https://github.com/rust-lang/compiler-rt +[submodule "libm"] + path = libm + url = https://github.com/japaric/libm diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index efd0b1738e3..7b7ed7e6bca 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -25,6 +25,9 @@ matrix: - env: TARGET=thumbv7em-linux-eabi - env: TARGET=thumbv7em-linux-eabihf - env: TARGET=thumbv7m-linux-eabi + - env: TARGET=wasm32-unknown-unknown + install: rustup target add $TARGET + script: cargo build --target $TARGET - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm new file mode 160000 index 00000000000..d65f60f2428 --- /dev/null +++ b/library/compiler-builtins/libm @@ -0,0 +1 @@ +Subproject commit d65f60f24289ba212f5d47792f7236857efb2339 diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 619b6ac7afb..3e665a88d49 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -48,6 +48,9 @@ pub mod int; pub mod float; pub mod mem; +// only for the wasm32-unknown-unknown target +#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] +pub mod math; #[cfg(target_arch = "arm")] pub mod arm; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs new file mode 100644 index 00000000000..f9ee36f0e72 --- /dev/null +++ b/library/compiler-builtins/src/math.rs @@ -0,0 +1,51 @@ +#[allow(dead_code)] +#[path = "../../libm/src/math/mod.rs"] +mod libm; + +macro_rules! no_mangle { + ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { + $( + #[no_mangle] + pub fn $fun($($iid: $ity),+) -> $oty { + self::libm::$fun($($iid),+) + } + )+ + } +} + +no_mangle! { + fn acos(x: f64) -> f64; + fn asin(x: f64) -> f64; + fn atan(x: f64) -> f64; + fn atan2(x: f64, y: f64) -> f64; + fn cbrt(x: f64) -> f64; + fn cosh(x: f64) -> f64; + fn expm1(x: f64) -> f64; + fn hypot(x: f64, y: f64) -> f64; + fn log1p(x: f64) -> f64; + fn sinh(x: f64) -> f64; + fn tan(x: f64) -> f64; + fn tanh(x: f64) -> f64; + fn cos(x: f64) -> f64; + fn cosf(x: f32) -> f32; + fn exp(x: f64) -> f64; + fn expf(x: f32) -> f32; + fn log2(x: f64) -> f64; + fn log2f(x: f32) -> f32; + fn log10(x: f64) -> f64; + fn log10f(x: f32) -> f32; + fn log(x: f64) -> f64; + fn logf(x: f32) -> f32; + fn round(x: f64) -> f64; + fn roundf(x: f32) -> f32; + fn sin(x: f64) -> f64; + fn sinf(x: f32) -> f32; + fn pow(x: f64, y: f64) -> f64; + fn powf(x: f32, y: f32) -> f32; + fn exp2(x: f64) -> f64; + fn exp2f(x: f32) -> f32; + fn fmod(x: f64, y: f64) -> f64; + fn fmodf(x: f32, y: f32) -> f32; + fn fma(x: f64, y: f64, z: f64) -> f64; + fn fmaf(x: f32, y: f32, z: f32) -> f32; +} -- cgit 1.4.1-3-g733a5 From f43deaa6a483cb8fadc87c61eaa765fe9f781cf7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 18 Jul 2018 11:36:24 -0500 Subject: fix path --- library/compiler-builtins/src/math.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index f9ee36f0e72..76bb7267993 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -1,5 +1,5 @@ #[allow(dead_code)] -#[path = "../../libm/src/math/mod.rs"] +#[path = "../libm/src/math/mod.rs"] mod libm; macro_rules! no_mangle { -- cgit 1.4.1-3-g733a5 From ddd9a3c5ba32460e3b506f10a780076bfade39f7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 18 Jul 2018 11:48:47 -0500 Subject: v0.1.2 --- library/compiler-builtins/libm/CHANGELOG.md | 5 ++++- library/compiler-builtins/libm/Cargo.toml | 2 +- library/compiler-builtins/libm/src/lib.rs | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index d37468685a9..1cc396455f3 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.1.2] - 2018-07-18 + ### Added - acosf @@ -72,5 +74,6 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Initial release -[Unreleased]: https://github.com/japaric/libm/compare/v0.1.1...HEAD +[Unreleased]: https://github.com/japaric/libm/compare/v0.1.2...HEAD +[v0.1.2]: https://github.com/japaric/libm/compare/v0.1.1...v0.1.2 [v0.1.1]: https://github.com/japaric/libm/compare/v0.1.0...v0.1.1 diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index a82fc99a7e7..11c59a2dbdb 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" repository = "https://github.com/japaric/libm" -version = "0.1.1" +version = "0.1.2" [workspace] members = ["cb", "test-generator"] \ No newline at end of file diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 06991effe1d..5121cbfbacf 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,4 +1,4 @@ -//! Port of MUSL's libm to Rust +//! libm in pure Rust //! //! # Usage //! -- cgit 1.4.1-3-g733a5 From bb88e27e3c6658273d634aeaf95bb172adfb748e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 18 Jul 2018 10:04:33 -0700 Subject: Use `intrinsics!` macro for math intrinsics Make sure they respect the `mangled-names` feature as well as have the `"C"` ABI. --- library/compiler-builtins/src/math.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 76bb7267993..f1eaaa5fa41 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -4,12 +4,13 @@ mod libm; macro_rules! no_mangle { ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { - $( - #[no_mangle] - pub fn $fun($($iid: $ity),+) -> $oty { - self::libm::$fun($($iid),+) - } - )+ + intrinsics! { + $( + pub extern "C" fn $fun($($iid: $ity),+) -> $oty { + self::libm::$fun($($iid),+) + } + )+ + } } } -- cgit 1.4.1-3-g733a5 From 7774eac9625362e9433209dc22b356058d5b63a0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 21 Jul 2018 12:01:49 -0500 Subject: README: all the math functions we needed are now supported --- library/compiler-builtins/libm/README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 02de9765a50..24b816c351b 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -33,10 +33,7 @@ fn foo(x: f32) { } ``` -Not all the math functions are available at the moment. Check the [API docs] to learn what's -currently supported. - -[API docs]: https://docs.rs/libm +The API documentation can be found [here](https://docs.rs/libm). ## Contributing -- cgit 1.4.1-3-g733a5 From 8b1e42bf2ae50dab91837e5d6d8da386b945c460 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 24 Jul 2018 13:26:50 -0500 Subject: expose fmod{,f} symbols on thumb these symbols are required for the built-in operation `f32 % f32` --- library/compiler-builtins/src/lib.rs | 4 +--- library/compiler-builtins/src/math.rs | 11 +++++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3e665a88d49..5c87e90a5ac 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -47,10 +47,8 @@ mod macros; pub mod int; pub mod float; -pub mod mem; -// only for the wasm32-unknown-unknown target -#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] pub mod math; +pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index f1eaaa5fa41..6eddc3d78ab 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -14,6 +14,8 @@ macro_rules! no_mangle { } } +// only for the wasm32-unknown-unknown target +#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; @@ -50,3 +52,12 @@ no_mangle! { fn fma(x: f64, y: f64, z: f64) -> f64; fn fmaf(x: f32, y: f32, z: f32) -> f32; } + +// only for the thumb*-none-eabi* targets +#[cfg(all(target_arch = "arm", target_os = "none"))] +no_mangle! { + // `f64 % f64` + fn fmod(x: f64, y: f64) -> f64; + // `f32 % f32` + fn fmodf(x: f32, y: f32) -> f32; +} -- cgit 1.4.1-3-g733a5 From cfa1690e6918de6ee8bbe92e2cfb69817b26d636 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 24 Jul 2018 16:57:22 -0500 Subject: fix warnings --- library/compiler-builtins/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 5c87e90a5ac..02b6c7db953 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -47,6 +47,8 @@ mod macros; pub mod int; pub mod float; +#[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), + all(target_arch = "arm", target_os = "none")))] pub mod math; pub mod mem; -- cgit 1.4.1-3-g733a5 From 645468713446cabed74c9de55cf8df98e13ebe49 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 25 Jul 2018 13:16:10 -0500 Subject: omit bounds check in release mode this eliminates panicking branches in the optimized version of the functions. We keep the bounds checks when running the test suite to check that we never do an out of bounds access. This commit also adds a "must link" test that ensures that future changes in our implementation won't add panicking branches. closes rust-lang/libm#129 --- library/compiler-builtins/libm/Cargo.toml | 4 + library/compiler-builtins/libm/ci/script.sh | 14 ++- .../compiler-builtins/libm/examples/no-panic.rs | 115 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/atan.rs | 2 +- library/compiler-builtins/libm/src/math/mod.rs | 44 ++++++++ .../compiler-builtins/libm/src/math/rem_pio2.rs | 2 +- .../libm/src/math/rem_pio2_large.rs | 104 ++++++++++--------- 7 files changed, 233 insertions(+), 52 deletions(-) create mode 100644 library/compiler-builtins/libm/examples/no-panic.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 11c59a2dbdb..8a2ba7447ab 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -9,5 +9,9 @@ name = "libm" repository = "https://github.com/japaric/libm" version = "0.1.2" +[features] +# only used to run our test suite +checked = [] + [workspace] members = ["cb", "test-generator"] \ No newline at end of file diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index cf37ac1ca64..71d9e088212 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -12,11 +12,21 @@ main() { # check that we can source import libm into compiler-builtins cargo check --package cb + # test that the functions don't contain invocations of `panic!` + case $TARGET in + armv7-unknown-linux-gnueabihf) + cross build --release --target $TARGET --example no-panic + ;; + esac + + # run unit tests + cross test --lib --features checked --target $TARGET --release + # generate tests cargo run --package test-generator --target x86_64-unknown-linux-musl - # run tests - cross test --target $TARGET --release + # run generated tests + cross test --tests --features checked --target $TARGET --release # TODO need to fix overflow issues (cf. issue #4) # cross test --target $TARGET diff --git a/library/compiler-builtins/libm/examples/no-panic.rs b/library/compiler-builtins/libm/examples/no-panic.rs new file mode 100644 index 00000000000..fb79f99afa1 --- /dev/null +++ b/library/compiler-builtins/libm/examples/no-panic.rs @@ -0,0 +1,115 @@ +#![feature(lang_items)] +#![feature(panic_implementation)] +#![no_main] +#![no_std] + +extern crate libm; + +use core::panic::PanicInfo; +use core::ptr; + +macro_rules! force_eval { + ($e:expr) => { + unsafe { + core::ptr::read_volatile(&$e); + } + }; +} + +#[no_mangle] +pub fn main() { + force_eval!(libm::acos(random())); + force_eval!(libm::acosf(random())); + force_eval!(libm::asin(random())); + force_eval!(libm::asinf(random())); + force_eval!(libm::atan(random())); + force_eval!(libm::atan2(random(), random())); + force_eval!(libm::atan2f(random(), random())); + force_eval!(libm::atanf(random())); + force_eval!(libm::cbrt(random())); + force_eval!(libm::cbrtf(random())); + force_eval!(libm::ceil(random())); + force_eval!(libm::ceilf(random())); + force_eval!(libm::cos(random())); + force_eval!(libm::cosf(random())); + force_eval!(libm::cosh(random())); + force_eval!(libm::coshf(random())); + force_eval!(libm::exp(random())); + force_eval!(libm::exp2(random())); + force_eval!(libm::exp2f(random())); + force_eval!(libm::expf(random())); + force_eval!(libm::expm1(random())); + force_eval!(libm::expm1f(random())); + force_eval!(libm::fabs(random())); + force_eval!(libm::fabsf(random())); + force_eval!(libm::fdim(random(), random())); + force_eval!(libm::fdimf(random(), random())); + force_eval!(libm::floor(random())); + force_eval!(libm::floorf(random())); + force_eval!(libm::fma(random(), random(), random())); + force_eval!(libm::fmaf(random(), random(), random())); + force_eval!(libm::fmod(random(), random())); + force_eval!(libm::fmodf(random(), random())); + force_eval!(libm::hypot(random(), random())); + force_eval!(libm::hypotf(random(), random())); + force_eval!(libm::log(random())); + force_eval!(libm::log2(random())); + force_eval!(libm::log10(random())); + force_eval!(libm::log10f(random())); + force_eval!(libm::log1p(random())); + force_eval!(libm::log1pf(random())); + force_eval!(libm::log2f(random())); + force_eval!(libm::logf(random())); + force_eval!(libm::pow(random(), random())); + force_eval!(libm::powf(random(), random())); + force_eval!(libm::round(random())); + force_eval!(libm::roundf(random())); + force_eval!(libm::scalbn(random(), random())); + force_eval!(libm::scalbnf(random(), random())); + force_eval!(libm::sin(random())); + force_eval!(libm::sinf(random())); + force_eval!(libm::sinh(random())); + force_eval!(libm::sinhf(random())); + force_eval!(libm::sqrt(random())); + force_eval!(libm::sqrtf(random())); + force_eval!(libm::tan(random())); + force_eval!(libm::tanf(random())); + force_eval!(libm::tanh(random())); + force_eval!(libm::tanhf(random())); + force_eval!(libm::trunc(random())); + force_eval!(libm::truncf(random())); +} + +fn random() -> T +where + T: Copy, +{ + unsafe { + static mut X: usize = 0; + X += 8; + ptr::read_volatile(X as *const T) + } +} + +#[panic_implementation] +#[no_mangle] +pub fn panic(_info: &PanicInfo) -> ! { + // loop {} + extern "C" { + fn thou_shalt_not_panic() -> !; + } + + unsafe { thou_shalt_not_panic() } +} + +#[link(name = "c")] +extern "C" {} + +#[lang = "eh_personality"] +fn eh() {} + +#[no_mangle] +pub extern "C" fn __aeabi_unwind_cpp_pr0() {} + +#[no_mangle] +pub extern "C" fn __aeabi_unwind_cpp_pr1() {} diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index 47a2951c6f4..cf6a62a5459 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -124,7 +124,7 @@ pub fn atan(x: f64) -> f64 { return x - x * (s1 + s2); } - let z = ATANHI[id as usize] - (x * (s1 + s2) - ATANLO[id as usize] - x); + let z = i!(ATANHI, id as usize) - (x * (s1 + s2) - i!(ATANLO, id as usize) - x); if sign != 0 { -z diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 752a5991aea..f663ae674f9 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -6,6 +6,50 @@ macro_rules! force_eval { }; } +#[cfg(not(feature = "checked"))] +macro_rules! i { + ($array:expr, $index:expr) => { + unsafe { *$array.get_unchecked($index) } + }; + ($array:expr, $index:expr, =, $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) = $rhs; } + }; + ($array:expr, $index:expr, +=, $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) += $rhs; } + }; + ($array:expr, $index:expr, -=, $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) -= $rhs; } + }; + ($array:expr, $index:expr, &=, $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) &= $rhs; } + }; + ($array:expr, $index:expr, ==, $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) == $rhs } + }; +} + +#[cfg(feature = "checked")] +macro_rules! i { + ($array:expr, $index:expr) => { + *$array.get($index).unwrap() + }; + ($array:expr, $index:expr, =, $rhs:expr) => { + *$array.get_mut($index).unwrap() = $rhs; + }; + ($array:expr, $index:expr, -=, $rhs:expr) => { + *$array.get_mut($index).unwrap() -= $rhs; + }; + ($array:expr, $index:expr, +=, $rhs:expr) => { + *$array.get_mut($index).unwrap() += $rhs; + }; + ($array:expr, $index:expr, &=, $rhs:expr) => { + *$array.get_mut($index).unwrap() &= $rhs; + }; + ($array:expr, $index:expr, ==, $rhs:expr) => { + *$array.get_mut($index).unwrap() == $rhs + }; +} + // Public modules mod acos; mod acosf; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 6e655e7d419..5c1685877b6 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -177,7 +177,7 @@ pub fn rem_pio2(x: f64) -> (i32, f64, f64) { tx[2] = z; /* skip zero terms, first term is non-zero */ let mut i = 2; - while tx[i] == 0.0 { + while i != 0 && tx[i] == 0.0 { i -= 1; } let mut ty = [0.0; 3]; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 745b700a5eb..f44520931f8 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -1,3 +1,4 @@ +#![allow(unused_unsafe)] /* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ /* * ==================================================== @@ -257,17 +258,21 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { let mut j = (jv - jx) as i32; let m = jx + jk; for i in 0..=m { - f[i] = if j < 0 { 0. } else { IPIO2[j as usize] as f64 }; - j += 1 + i!(f, i, =, if j < 0 { + 0. + } else { + i!(IPIO2, j as usize) as f64 + }); + j += 1; } /* compute q[0],q[1],...q[jk] */ for i in 0..=jk { fw = 0f64; for j in 0..=jx { - fw += x[j] * f[jx + i - j]; + fw += i!(x, j) * i!(f, jx + i - j); } - q[i] = fw; + i!(q, i, =, fw); } let mut jz = jk; @@ -275,11 +280,11 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { 'recompute: loop { /* distill q[] into iq[] reversingly */ let mut i = 0i32; - z = q[jz]; + z = i!(q, jz); for j in (1..=jz).rev() { fw = (x1p_24 * z) as i32 as f64; - iq[i as usize] = (z - x1p24 * fw) as i32; - z = q[j - 1] + fw; + i!(iq, i as usize, =, (z - x1p24 * fw) as i32); + z = i!(q, j - 1) + fw; i += 1; } @@ -291,12 +296,12 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { ih = 0; if q0 > 0 { /* need iq[jz-1] to determine n */ - i = iq[jz - 1] >> (24 - q0); + i = i!(iq, jz - 1) >> (24 - q0); n += i; - iq[jz - 1] -= i << (24 - q0); - ih = iq[jz - 1] >> (23 - q0); + i!(iq, jz - 1, -=, i << (24 - q0)); + ih = i!(iq, jz - 1) >> (23 - q0); } else if q0 == 0 { - ih = iq[jz - 1] >> 23; + ih = i!(iq, jz - 1) >> 23; } else if z >= 0.5 { ih = 2; } @@ -307,24 +312,24 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { let mut carry = 0i32; for i in 0..jz { /* compute 1-q */ - let j = iq[i]; + let j = i!(iq, i); if carry == 0 { if j != 0 { carry = 1; - iq[i] = 0x1000000 - j; + i!(iq, i, =, 0x1000000 - j); } } else { - iq[i] = 0xffffff - j; + i!(iq, i, =, 0xffffff - j); } } if q0 > 0 { /* rare case: chance is 1 in 12 */ match q0 { 1 => { - iq[jz - 1] &= 0x7fffff; + i!(iq, jz - 1, &=, 0x7fffff); } 2 => { - iq[jz - 1] &= 0x3fffff; + i!(iq, jz - 1, &=, 0x3fffff); } _ => {} } @@ -341,23 +346,23 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { if z == 0. { let mut j = 0; for i in (jk..=jz - 1).rev() { - j |= iq[i]; + j |= i!(iq, i); } if j == 0 { /* need recomputation */ let mut k = 1; - while iq[jk - k] == 0 { + while i!(iq, jk - k, ==, 0) { k += 1; /* k = no. of terms needed */ } for i in (jz + 1)..=(jz + k) { /* add q[jz+1] to q[jz+k] */ - f[jx + i] = IPIO2[jv + i] as f64; + i!(f, jx + i, =, i!(IPIO2, jv + i) as f64); fw = 0f64; for j in 0..=jx { - fw += x[j] * f[jx + i - j]; + fw += i!(x, j) * i!(f, jx + i - j); } - q[i] = fw; + i!(q, i, =, fw); } jz += k; continue 'recompute; @@ -371,7 +376,7 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { if z == 0. { jz -= 1; q0 -= 24; - while iq[jz] == 0 { + while i!(iq, jz) == 0 { jz -= 1; q0 -= 24; } @@ -380,19 +385,19 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { z = scalbn(z, -q0); if z >= x1p24 { fw = (x1p_24 * z) as i32 as f64; - iq[jz] = (z - x1p24 * fw) as i32; + i!(iq, jz, =, (z - x1p24 * fw) as i32); jz += 1; q0 += 24; - iq[jz] = fw as i32; + i!(iq, jz, =, fw as i32); } else { - iq[jz] = z as i32; + i!(iq, jz, =, z as i32); } } /* convert integer "bit" chunk to floating-point value */ fw = scalbn(1., q0); for i in (0..=jz).rev() { - q[i] = fw * (iq[i] as f64); + i!(q, i, =, fw * (i!(iq, i) as f64)); fw *= x1p_24; } @@ -401,10 +406,10 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { fw = 0f64; let mut k = 0; while (k <= jp) && (k <= jz - i) { - fw += PIO2[k] * q[i + k]; + fw += i!(PIO2, k) * i!(q, i + k); k += 1; } - fq[jz - i] = fw; + i!(fq, jz - i, =, fw); } /* compress fq[] into y[] */ @@ -412,51 +417,54 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { 0 => { fw = 0f64; for i in (0..=jz).rev() { - fw += fq[i]; + fw += i!(fq, i); } - y[0] = if ih == 0 { fw } else { -fw }; + i!(y, 0, =, if ih == 0 { fw } else { -fw }); } 1 | 2 => { fw = 0f64; for i in (0..=jz).rev() { - fw += fq[i]; + fw += i!(fq, i); } // TODO: drop excess precision here once double_t is used fw = fw as f64; - y[0] = if ih == 0 { fw } else { -fw }; - fw = fq[0] - fw; + i!(y, 0, =, if ih == 0 { fw } else { -fw }); + fw = i!(fq, 0) - fw; for i in 1..=jz { - fw += fq[i]; + fw += i!(fq, i); } - y[1] = if ih == 0 { fw } else { -fw }; + i!(y, 1, =, if ih == 0 { fw } else { -fw }); } 3 => { /* painful */ for i in (1..=jz).rev() { - fw = fq[i - 1] + fq[i]; - fq[i] += fq[i - 1] - fw; - fq[i - 1] = fw; + fw = i!(fq, i - 1) + i!(fq, i); + i!(fq, i, +=, i!(fq, i - 1) - fw); + i!(fq, i - 1, =, fw); } for i in (2..=jz).rev() { - fw = fq[i - 1] + fq[i]; - fq[i] += fq[i - 1] - fw; - fq[i - 1] = fw; + fw = i!(fq, i - 1) + i!(fq, i); + i!(fq, i, +=, i!(fq, i - 1) - fw); + i!(fq, i - 1, =, fw); } fw = 0f64; for i in (2..=jz).rev() { - fw += fq[i]; + fw += i!(fq, i); } if ih == 0 { - y[0] = fq[0]; - y[1] = fq[1]; - y[2] = fw; + i!(y, 0, =, i!(fq, 0)); + i!(y, 1, =, i!(fq, 1)); + i!(y, 2, =, fw); } else { - y[0] = -fq[0]; - y[1] = -fq[1]; - y[2] = -fw; + i!(y, 0, =, -i!(fq, 0)); + i!(y, 1, =, -i!(fq, 1)); + i!(y, 2, =, -fw); } } + #[cfg(feature = "checked")] _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => {}, } n & 7 } -- cgit 1.4.1-3-g733a5 From 657906b30c5fcf3810f31a3e5967112b917750df Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 25 Jul 2018 14:48:49 -0500 Subject: ci: add nightly build job to rnu the no-panic test --- library/compiler-builtins/libm/.travis.yml | 3 +++ library/compiler-builtins/libm/ci/script.sh | 13 ++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index 223b586ea6d..922273e0936 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -17,6 +17,9 @@ matrix: - env: TARGET=x86_64-unknown-linux-gnu - env: TARGET=cargo-fmt rust: beta + # no-panic link test + - env: TARGET=armv7-unknown-linux-gnueabihf + rust: nightly before_install: set -e diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index 71d9e088212..5156047df58 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -6,19 +6,18 @@ main() { return fi + # test that the functions don't contain invocations of `panic!` + if [ $TRAVIS_RUST_VERSION ]; then + cross build --release --target $TARGET --example no-panic + return + fi + # quick check cargo check # check that we can source import libm into compiler-builtins cargo check --package cb - # test that the functions don't contain invocations of `panic!` - case $TARGET in - armv7-unknown-linux-gnueabihf) - cross build --release --target $TARGET --example no-panic - ;; - esac - # run unit tests cross test --lib --features checked --target $TARGET --release -- cgit 1.4.1-3-g733a5 From a4197d1cdefcf87463c5a6be4163fa8ab5e390d1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 25 Jul 2018 14:49:14 -0500 Subject: cargo fmt --- library/compiler-builtins/libm/src/math/mod.rs | 36 +++++++++++++--------- .../libm/src/math/rem_pio2_large.rs | 2 +- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index f663ae674f9..da34fb4cecd 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -11,19 +11,27 @@ macro_rules! i { ($array:expr, $index:expr) => { unsafe { *$array.get_unchecked($index) } }; - ($array:expr, $index:expr, =, $rhs:expr) => { - unsafe { *$array.get_unchecked_mut($index) = $rhs; } + ($array:expr, $index:expr, = , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) = $rhs; + } }; - ($array:expr, $index:expr, +=, $rhs:expr) => { - unsafe { *$array.get_unchecked_mut($index) += $rhs; } + ($array:expr, $index:expr, += , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) += $rhs; + } }; - ($array:expr, $index:expr, -=, $rhs:expr) => { - unsafe { *$array.get_unchecked_mut($index) -= $rhs; } + ($array:expr, $index:expr, -= , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) -= $rhs; + } }; - ($array:expr, $index:expr, &=, $rhs:expr) => { - unsafe { *$array.get_unchecked_mut($index) &= $rhs; } + ($array:expr, $index:expr, &= , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) &= $rhs; + } }; - ($array:expr, $index:expr, ==, $rhs:expr) => { + ($array:expr, $index:expr, == , $rhs:expr) => { unsafe { *$array.get_unchecked_mut($index) == $rhs } }; } @@ -33,19 +41,19 @@ macro_rules! i { ($array:expr, $index:expr) => { *$array.get($index).unwrap() }; - ($array:expr, $index:expr, =, $rhs:expr) => { + ($array:expr, $index:expr, = , $rhs:expr) => { *$array.get_mut($index).unwrap() = $rhs; }; - ($array:expr, $index:expr, -=, $rhs:expr) => { + ($array:expr, $index:expr, -= , $rhs:expr) => { *$array.get_mut($index).unwrap() -= $rhs; }; - ($array:expr, $index:expr, +=, $rhs:expr) => { + ($array:expr, $index:expr, += , $rhs:expr) => { *$array.get_mut($index).unwrap() += $rhs; }; - ($array:expr, $index:expr, &=, $rhs:expr) => { + ($array:expr, $index:expr, &= , $rhs:expr) => { *$array.get_mut($index).unwrap() &= $rhs; }; - ($array:expr, $index:expr, ==, $rhs:expr) => { + ($array:expr, $index:expr, == , $rhs:expr) => { *$array.get_mut($index).unwrap() == $rhs }; } diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index f44520931f8..4d9146af9d6 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -464,7 +464,7 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { #[cfg(feature = "checked")] _ => unreachable!(), #[cfg(not(feature = "checked"))] - _ => {}, + _ => {} } n & 7 } -- cgit 1.4.1-3-g733a5 From 47e65384f254e5d0328fee59f40acddc000a4b7c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 25 Jul 2018 15:02:10 -0500 Subject: ci: fix if condition --- library/compiler-builtins/libm/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index 5156047df58..bb19e23d84e 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -7,7 +7,7 @@ main() { fi # test that the functions don't contain invocations of `panic!` - if [ $TRAVIS_RUST_VERSION ]; then + if [ $TRAVIS_RUST_VERSION = nightly ]; then cross build --release --target $TARGET --example no-panic return fi -- cgit 1.4.1-3-g733a5 From be2f980cf6ae19da23a1ac8684f0b426be5ee6ff Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Jul 2018 18:11:47 -0700 Subject: Update libm to elide bounds checks --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index d65f60f2428..96e36ea2620 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit d65f60f24289ba212f5d47792f7236857efb2339 +Subproject commit 96e36ea2620f9fbbaa46a01694a2fa3ef6c2fb7e -- cgit 1.4.1-3-g733a5 From c626608e414820d87a2c81f0701ded45b1fb4597 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 27 Jul 2018 00:11:06 -0500 Subject: add newlib support to the test generator --- library/compiler-builtins/libm/.gitignore | 3 + library/compiler-builtins/libm/.travis.yml | 35 +- library/compiler-builtins/libm/Cargo.toml | 11 +- library/compiler-builtins/libm/ci/install.sh | 3 + library/compiler-builtins/libm/ci/script.sh | 17 +- .../libm/input-generator/Cargo.toml | 7 + .../libm/input-generator/src/main.rs | 189 +++++ library/compiler-builtins/libm/math/.cargo/config | 11 + library/compiler-builtins/libm/math/Cargo.toml | 8 + library/compiler-builtins/libm/math/Cross.toml | 2 + .../libm/musl-generator/Cargo.toml | 9 + .../libm/musl-generator/src/macros.rs | 191 +++++ .../libm/musl-generator/src/main.rs | 97 +++ .../libm/newlib-generator/Cargo.toml | 7 + .../libm/newlib-generator/src/macros.rs | 245 +++++++ .../libm/newlib-generator/src/main.rs | 32 + library/compiler-builtins/libm/shared/Cargo.toml | 7 + library/compiler-builtins/libm/shared/src/lib.rs | 471 ++++++++++++ library/compiler-builtins/libm/src/lib.rs | 28 +- .../libm/test-generator/Cargo.toml | 9 - .../libm/test-generator/README.md | 8 - .../libm/test-generator/src/main.rs | 788 --------------------- 22 files changed, 1348 insertions(+), 830 deletions(-) create mode 100644 library/compiler-builtins/libm/input-generator/Cargo.toml create mode 100644 library/compiler-builtins/libm/input-generator/src/main.rs create mode 100644 library/compiler-builtins/libm/math/.cargo/config create mode 100644 library/compiler-builtins/libm/math/Cargo.toml create mode 100644 library/compiler-builtins/libm/math/Cross.toml create mode 100644 library/compiler-builtins/libm/musl-generator/Cargo.toml create mode 100644 library/compiler-builtins/libm/musl-generator/src/macros.rs create mode 100644 library/compiler-builtins/libm/musl-generator/src/main.rs create mode 100644 library/compiler-builtins/libm/newlib-generator/Cargo.toml create mode 100644 library/compiler-builtins/libm/newlib-generator/src/macros.rs create mode 100644 library/compiler-builtins/libm/newlib-generator/src/main.rs create mode 100644 library/compiler-builtins/libm/shared/Cargo.toml create mode 100644 library/compiler-builtins/libm/shared/src/lib.rs delete mode 100644 library/compiler-builtins/libm/test-generator/Cargo.toml delete mode 100644 library/compiler-builtins/libm/test-generator/README.md delete mode 100644 library/compiler-builtins/libm/test-generator/src/main.rs diff --git a/library/compiler-builtins/libm/.gitignore b/library/compiler-builtins/libm/.gitignore index 6db0ab6effc..39950911a62 100644 --- a/library/compiler-builtins/libm/.gitignore +++ b/library/compiler-builtins/libm/.gitignore @@ -1,5 +1,8 @@ **/*.rs.bk .#* +/bin +/math/src +/math/target /target /tests Cargo.lock diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index 922273e0936..b3beecb0920 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -5,21 +5,29 @@ sudo: required matrix: include: - env: TARGET=aarch64-unknown-linux-gnu - - env: TARGET=armv7-unknown-linux-gnueabihf - - env: TARGET=i686-unknown-linux-gnu - - env: TARGET=mips-unknown-linux-gnu - - env: TARGET=mips64-unknown-linux-gnuabi64 - - env: TARGET=mips64el-unknown-linux-gnuabi64 - - env: TARGET=mipsel-unknown-linux-gnu - - env: TARGET=powerpc-unknown-linux-gnu - - env: TARGET=powerpc64-unknown-linux-gnu - - env: TARGET=powerpc64le-unknown-linux-gnu + rust: nightly + # - env: TARGET=armv7-unknown-linux-gnueabihf + # rust: nightly + # - env: TARGET=i686-unknown-linux-gnu + # rust: nightly + # - env: TARGET=mips-unknown-linux-gnu + # rust: nightly + # - env: TARGET=mips64-unknown-linux-gnuabi64 + # rust: nightly + # - env: TARGET=mips64el-unknown-linux-gnuabi64 + # rust: nightly + # - env: TARGET=mipsel-unknown-linux-gnu + # rust: nightly + # - env: TARGET=powerpc-unknown-linux-gnu + # rust: nightly + # - env: TARGET=powerpc64-unknown-linux-gnu + # rust: nightly + # - env: TARGET=powerpc64le-unknown-linux-gnu + # rust: nightly - env: TARGET=x86_64-unknown-linux-gnu - - env: TARGET=cargo-fmt - rust: beta - # no-panic link test - - env: TARGET=armv7-unknown-linux-gnueabihf rust: nightly + # - env: TARGET=cargo-fmt + # rust: beta before_install: set -e @@ -27,6 +35,7 @@ install: - bash ci/install.sh script: + - export PATH=$HOME/.local/bin:$PATH - bash ci/script.sh after_script: set +e diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 8a2ba7447ab..cedf8d267db 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -14,4 +14,13 @@ version = "0.1.2" checked = [] [workspace] -members = ["cb", "test-generator"] \ No newline at end of file +members = [ + "cb", + "input-generator", + "musl-generator", + "newlib-generator", + "shared", +] + +[dev-dependencies] +shared = { path = "shared" } diff --git a/library/compiler-builtins/libm/ci/install.sh b/library/compiler-builtins/libm/ci/install.sh index 4d9552d231b..7f73c5feaf3 100644 --- a/library/compiler-builtins/libm/ci/install.sh +++ b/library/compiler-builtins/libm/ci/install.sh @@ -15,6 +15,9 @@ main() { if [ $TARGET != x86_64-unknown-linux-gnu ]; then rustup target add $TARGET fi + + mkdir -p ~/.local/bin + curl -L https://github.com/japaric/qemu-bin/raw/master/14.04/qemu-arm-2.12.0 > ~/.local/bin/qemu-arm } main diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index bb19e23d84e..59e5a5f37de 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -7,10 +7,11 @@ main() { fi # test that the functions don't contain invocations of `panic!` - if [ $TRAVIS_RUST_VERSION = nightly ]; then - cross build --release --target $TARGET --example no-panic - return - fi + case $TARGET in + armv7-unknown-linux-gnueabihf) + cross build --release --target $TARGET --example no-panic + ;; + esac # quick check cargo check @@ -18,12 +19,14 @@ main() { # check that we can source import libm into compiler-builtins cargo check --package cb + # generate tests + cargo run -p input-generator --target x86_64-unknown-linux-musl + cargo run -p musl-generator --target x86_64-unknown-linux-musl + cargo run -p newlib-generator + # run unit tests cross test --lib --features checked --target $TARGET --release - # generate tests - cargo run --package test-generator --target x86_64-unknown-linux-musl - # run generated tests cross test --tests --features checked --target $TARGET --release diff --git a/library/compiler-builtins/libm/input-generator/Cargo.toml b/library/compiler-builtins/libm/input-generator/Cargo.toml new file mode 100644 index 00000000000..fef2558a8b0 --- /dev/null +++ b/library/compiler-builtins/libm/input-generator/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "input-generator" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[dependencies] +rand = "0.5.4" diff --git a/library/compiler-builtins/libm/input-generator/src/main.rs b/library/compiler-builtins/libm/input-generator/src/main.rs new file mode 100644 index 00000000000..b4a6ad14225 --- /dev/null +++ b/library/compiler-builtins/libm/input-generator/src/main.rs @@ -0,0 +1,189 @@ +extern crate rand; + +use std::collections::BTreeSet; +use std::error::Error; +use std::fs::{self, File}; +use std::io::Write; + +use rand::{RngCore, SeedableRng, XorShiftRng}; + +const NTESTS: usize = 10_000; + +fn main() -> Result<(), Box> { + let mut rng = XorShiftRng::from_rng(&mut rand::thread_rng())?; + + fs::remove_dir_all("bin").ok(); + fs::create_dir_all("bin/input")?; + fs::create_dir_all("bin/output")?; + + f32(&mut rng)?; + f32f32(&mut rng)?; + f32f32f32(&mut rng)?; + f32i16(&mut rng)?; + f64(&mut rng)?; + f64f64(&mut rng)?; + f64f64f64(&mut rng)?; + f64i16(&mut rng)?; + + Ok(()) +} + +fn f32(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut set = BTreeSet::new(); + + while set.len() < NTESTS { + let f = f32::from_bits(rng.next_u32()); + + if f.is_nan() { + continue; + } + + set.insert(f.to_bits()); + } + + let mut f = File::create("bin/input/f32")?; + for i in set { + f.write_all(&i.to_bytes())?; + } + + Ok(()) +} + +fn f32f32(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f32f32")?; + let mut i = 0; + while i < NTESTS { + let x0 = f32::from_bits(rng.next_u32()); + let x1 = f32::from_bits(rng.next_u32()); + + if x0.is_nan() || x1.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_bytes())?; + f.write_all(&x1.to_bits().to_bytes())?; + } + + Ok(()) +} + +fn f32i16(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f32i16")?; + let mut i = 0; + while i < NTESTS { + let x0 = f32::from_bits(rng.next_u32()); + let x1 = rng.next_u32() as i16; + + if x0.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_bytes())?; + f.write_all(&x1.to_bytes())?; + } + + Ok(()) +} + +fn f32f32f32(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f32f32f32")?; + let mut i = 0; + while i < NTESTS { + let x0 = f32::from_bits(rng.next_u32()); + let x1 = f32::from_bits(rng.next_u32()); + let x2 = f32::from_bits(rng.next_u32()); + + if x0.is_nan() || x1.is_nan() || x2.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_bytes())?; + f.write_all(&x1.to_bits().to_bytes())?; + f.write_all(&x2.to_bits().to_bytes())?; + } + + Ok(()) +} + +fn f64(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut set = BTreeSet::new(); + + while set.len() < NTESTS { + let f = f64::from_bits(rng.next_u64()); + + if f.is_nan() { + continue; + } + + set.insert(f.to_bits()); + } + + let mut f = File::create("bin/input/f64")?; + for i in set { + f.write_all(&i.to_bytes())?; + } + + Ok(()) +} + +fn f64f64(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f64f64")?; + let mut i = 0; + while i < NTESTS { + let x0 = f64::from_bits(rng.next_u64()); + let x1 = f64::from_bits(rng.next_u64()); + + if x0.is_nan() || x1.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_bytes())?; + f.write_all(&x1.to_bits().to_bytes())?; + } + + Ok(()) +} + +fn f64f64f64(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f64f64f64")?; + let mut i = 0; + while i < NTESTS { + let x0 = f64::from_bits(rng.next_u64()); + let x1 = f64::from_bits(rng.next_u64()); + let x2 = f64::from_bits(rng.next_u64()); + + if x0.is_nan() || x1.is_nan() || x2.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_bytes())?; + f.write_all(&x1.to_bits().to_bytes())?; + f.write_all(&x2.to_bits().to_bytes())?; + } + + Ok(()) +} + +fn f64i16(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f64i16")?; + let mut i = 0; + while i < NTESTS { + let x0 = f64::from_bits(rng.next_u64()); + let x1 = rng.next_u32() as i16; + + if x0.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_bytes())?; + f.write_all(&x1.to_bytes())?; + } + + Ok(()) +} diff --git a/library/compiler-builtins/libm/math/.cargo/config b/library/compiler-builtins/libm/math/.cargo/config new file mode 100644 index 00000000000..be79c453ad6 --- /dev/null +++ b/library/compiler-builtins/libm/math/.cargo/config @@ -0,0 +1,11 @@ +[target.thumbv7em-none-eabi] +rustflags = [ + "-C", "link-arg=-Wl,-Tlink.x", + "-C", "link-arg=-nostartfiles", + "-C", "link-arg=-mthumb", + "-C", "link-arg=-march=armv7e-m", + "-C", "link-arg=-mfloat-abi=soft", +] + +[build] +target = "thumbv7em-none-eabi" \ No newline at end of file diff --git a/library/compiler-builtins/libm/math/Cargo.toml b/library/compiler-builtins/libm/math/Cargo.toml new file mode 100644 index 00000000000..5bca038a9c3 --- /dev/null +++ b/library/compiler-builtins/libm/math/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "math" +version = "0.0.0" + +[dependencies] +qemu-arm-rt = { git = "https://github.com/japaric/qemu-arm-rt" } + +[workspace] \ No newline at end of file diff --git a/library/compiler-builtins/libm/math/Cross.toml b/library/compiler-builtins/libm/math/Cross.toml new file mode 100644 index 00000000000..471770b528b --- /dev/null +++ b/library/compiler-builtins/libm/math/Cross.toml @@ -0,0 +1,2 @@ +[target.thumbv7em-none-eabi] +xargo = false \ No newline at end of file diff --git a/library/compiler-builtins/libm/musl-generator/Cargo.toml b/library/compiler-builtins/libm/musl-generator/Cargo.toml new file mode 100644 index 00000000000..0564f353611 --- /dev/null +++ b/library/compiler-builtins/libm/musl-generator/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "musl-generator" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[dependencies] +lazy_static = "1.0.2" +shared = { path = "../shared" } +libm = { path = ".." } diff --git a/library/compiler-builtins/libm/musl-generator/src/macros.rs b/library/compiler-builtins/libm/musl-generator/src/macros.rs new file mode 100644 index 00000000000..16ba99d640c --- /dev/null +++ b/library/compiler-builtins/libm/musl-generator/src/macros.rs @@ -0,0 +1,191 @@ +macro_rules! f32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f32) -> f32 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for x in shared::F32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f32) -> f32; + } + + $fun(*x) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} + +macro_rules! f32f32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f32, f32) -> f32 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1) in shared::F32F32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f32, _: f32) -> f32; + } + + $fun(*x0, *x1) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} + +macro_rules! f32f32f32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f32, f32, f32) -> f32 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1, x2) in shared::F32F32F32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f32, _: f32, _: f32) -> f32; + } + + $fun(*x0, *x1, *x2) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} + +macro_rules! f32i32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f32, i32) -> f32 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1) in shared::F32I32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f32, _: i32) -> f32; + } + + $fun(*x0, *x1 as i32) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} + +macro_rules! f64 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f64) -> f64 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for x in shared::F64.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f64) -> f64; + } + + $fun(*x) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} + +macro_rules! f64f64 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f64, f64) -> f64 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1) in shared::F64F64.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f64, _: f64) -> f64; + } + + $fun(*x0, *x1) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} + +macro_rules! f64f64f64 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f64, f64, f64) -> f64 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1, x2) in shared::F64F64F64.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f64, _: f64, _: f64) -> f64; + } + + $fun(*x0, *x1, *x2) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} + +macro_rules! f64i32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f64, i32) -> f64 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1) in shared::F64I32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f64, _: i32) -> f64; + } + + $fun(*x0, *x1 as i32) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} diff --git a/library/compiler-builtins/libm/musl-generator/src/main.rs b/library/compiler-builtins/libm/musl-generator/src/main.rs new file mode 100644 index 00000000000..6e57e856dc6 --- /dev/null +++ b/library/compiler-builtins/libm/musl-generator/src/main.rs @@ -0,0 +1,97 @@ +extern crate libm; +extern crate shared; + +use std::error::Error; +use std::fs::File; +use std::io::Write; + +#[macro_use] +mod macros; + +fn main() -> Result<(), Box> { + f32! { + acosf, + asinf, + atanf, + cbrtf, + ceilf, + cosf, + coshf, + exp2f, + expf, + expm1f, + fabsf, + floorf, + log10f, + log1pf, + log2f, + logf, + roundf, + sinf, + sinhf, + sqrtf, + tanf, + tanhf, + truncf, + } + + f32f32! { + atan2f, + fdimf, + fmodf, + hypotf, + powf, + } + + f32i32! { + scalbnf, + } + + f32f32f32! { + fmaf, + } + + f64! { + acos, + asin, + atan, + cbrt, + ceil, + cos, + cosh, + exp, + exp2, + expm1, + fabs, + floor, + log, + log10, + log1p, + log2, + round, + sin, + sinh, + sqrt, + tan, + tanh, + trunc, + } + + f64f64! { + atan2, + fdim, + fmod, + hypot, + pow, + } + + f64i32! { + scalbn, + } + + f64f64f64! { + fma, + } + + Ok(()) +} diff --git a/library/compiler-builtins/libm/newlib-generator/Cargo.toml b/library/compiler-builtins/libm/newlib-generator/Cargo.toml new file mode 100644 index 00000000000..5766cb4b7a0 --- /dev/null +++ b/library/compiler-builtins/libm/newlib-generator/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "newlib-generator" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[dependencies] +shared = { path = "../shared" } diff --git a/library/compiler-builtins/libm/newlib-generator/src/macros.rs b/library/compiler-builtins/libm/newlib-generator/src/macros.rs new file mode 100644 index 00000000000..84315a777bd --- /dev/null +++ b/library/compiler-builtins/libm/newlib-generator/src/macros.rs @@ -0,0 +1,245 @@ +macro_rules! f32 { + ($($fun:ident,)+) => { + $( + let fun = stringify!($fun); + + fs::create_dir_all("math/src")?; + + let main = format!(" +#![no_main] +#![no_std] + +#[macro_use] +extern crate qemu_arm_rt as rt; + +use core::u32; + +use rt::{{io, process}}; + +entry!(main); + +fn main() {{ + run().unwrap_or_else(|e| {{ + eprintln!(\"error: {{}}\", e); + process::exit(1); + }}) +}} + +fn run() -> Result<(), usize> {{ + #[link(name = \"m\")] + extern \"C\" {{ + fn {0}(_: f32) -> f32; + }} + + let mut buf = [0; 4]; + while let Ok(()) = io::Stdin.read_exact(&mut buf) {{ + let x = f32::from_bits(u32::from_bytes(buf)); + let y = unsafe {{ {0}(x) }}; + + io::Stdout.write_all(&y.to_bits().to_bytes())?; + }} + + Ok(()) +}} + +#[no_mangle] +pub fn __errno() -> *mut i32 {{ + static mut ERRNO: i32 = 0; + unsafe {{ &mut ERRNO }} +}} +", fun); + + File::create("math/src/main.rs")?.write_all(main.as_bytes())?; + + assert!( + Command::new("cross") + .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) + .current_dir("math") + .status()? + .success() + ); + + let mut qemu = Command::new("qemu-arm") + .arg("math/target/thumbv7em-none-eabi/release/math") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + + qemu.stdin.as_mut().take().unwrap().write_all(F32)?; + + let output = qemu.wait_with_output()?; + + File::create(concat!("bin/output/newlib.", stringify!($fun)))? + .write_all(&output.stdout)?; + )+ + } +} + +macro_rules! f32f32 { + ($($fun:ident,)+) => { + $( + let fun = stringify!($fun); + + fs::create_dir_all("math/src")?; + + let main = format!(" +#![no_main] +#![no_std] + +#[macro_use] +extern crate qemu_arm_rt as rt; + +use core::u32; + +use rt::{{io, process}}; + +entry!(main); + +fn main() {{ + run().unwrap_or_else(|e| {{ + eprintln!(\"error: {{}}\", e); + process::exit(1); + }}) +}} + +fn run() -> Result<(), usize> {{ + #[link(name = \"m\")] + extern \"C\" {{ + fn {0}(_: f32, _: f32) -> f32; + }} + + let mut chunk = [0; 8]; + while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{ + let mut buf = [0; 4]; + buf.copy_from_slice(&chunk[..4]); + let x0 = f32::from_bits(u32::from_bytes(buf)); + + buf.copy_from_slice(&chunk[4..]); + let x1 = f32::from_bits(u32::from_bytes(buf)); + + let y = unsafe {{ {0}(x0, x1) }}; + + io::Stdout.write_all(&y.to_bits().to_bytes())?; + }} + + Ok(()) +}} + +#[no_mangle] +pub fn __errno() -> *mut i32 {{ + static mut ERRNO: i32 = 0; + unsafe {{ &mut ERRNO }} +}} +", fun); + + File::create("math/src/main.rs")?.write_all(main.as_bytes())?; + + assert!( + Command::new("cross") + .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) + .current_dir("math") + .status()? + .success() + ); + + let mut qemu = Command::new("qemu-arm") + .arg("math/target/thumbv7em-none-eabi/release/math") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + + qemu.stdin.as_mut().take().unwrap().write_all(F32)?; + + let output = qemu.wait_with_output()?; + + File::create(concat!("bin/output/newlib.", stringify!($fun)))? + .write_all(&output.stdout)?; + )+ + } +} + +macro_rules! f32f32f32 { + ($($fun:ident,)+) => { + $( + let fun = stringify!($fun); + + fs::create_dir_all("math/src")?; + + let main = format!(" +#![no_main] +#![no_std] + +#[macro_use] +extern crate qemu_arm_rt as rt; + +use core::u32; + +use rt::{{io, process}}; + +entry!(main); + +fn main() {{ + run().unwrap_or_else(|e| {{ + eprintln!(\"error: {{}}\", e); + process::exit(1); + }}) +}} + +fn run() -> Result<(), usize> {{ + #[link(name = \"m\")] + extern \"C\" {{ + fn {0}(_: f32, _: f32, _: f32) -> f32; + }} + + let mut chunk = [0; 12]; + while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{ + let mut buf = [0; 4]; + buf.copy_from_slice(&chunk[..4]); + let x0 = f32::from_bits(u32::from_bytes(buf)); + + buf.copy_from_slice(&chunk[4..8]); + let x1 = f32::from_bits(u32::from_bytes(buf)); + + buf.copy_from_slice(&chunk[8..]); + let x2 = f32::from_bits(u32::from_bytes(buf)); + + let y = unsafe {{ {0}(x0, x1, x2) }}; + + io::Stdout.write_all(&y.to_bits().to_bytes())?; + }} + + Ok(()) +}} + +#[no_mangle] +pub fn __errno() -> *mut i32 {{ + static mut ERRNO: i32 = 0; + unsafe {{ &mut ERRNO }} +}} +", fun); + + File::create("math/src/main.rs")?.write_all(main.as_bytes())?; + + assert!( + Command::new("cross") + .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) + .current_dir("math") + .status()? + .success() + ); + + let mut qemu = Command::new("qemu-arm") + .arg("math/target/thumbv7em-none-eabi/release/math") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + + qemu.stdin.as_mut().take().unwrap().write_all(F32)?; + + let output = qemu.wait_with_output()?; + + File::create(concat!("bin/output/newlib.", stringify!($fun)))? + .write_all(&output.stdout)?; + )+ + } +} diff --git a/library/compiler-builtins/libm/newlib-generator/src/main.rs b/library/compiler-builtins/libm/newlib-generator/src/main.rs new file mode 100644 index 00000000000..52a97cabbfd --- /dev/null +++ b/library/compiler-builtins/libm/newlib-generator/src/main.rs @@ -0,0 +1,32 @@ +extern crate shared; + +use std::error::Error; +use std::fs::{self, File}; +use std::io::Write; +use std::process::{Command, Stdio}; + +#[macro_use] +mod macros; + +fn main() -> Result<(), Box> { + const F32: &[u8] = include_bytes!("../../bin/input/f32"); + + f32! { + asinf, + cbrtf, + cosf, + exp2f, + sinf, + tanf, + } + + f32f32! { + hypotf, + } + + f32f32f32! { + fmaf, + } + + Ok(()) +} diff --git a/library/compiler-builtins/libm/shared/Cargo.toml b/library/compiler-builtins/libm/shared/Cargo.toml new file mode 100644 index 00000000000..d7782378101 --- /dev/null +++ b/library/compiler-builtins/libm/shared/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "shared" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[dependencies] +lazy_static = "1.0.2" diff --git a/library/compiler-builtins/libm/shared/src/lib.rs b/library/compiler-builtins/libm/shared/src/lib.rs new file mode 100644 index 00000000000..84676f94f74 --- /dev/null +++ b/library/compiler-builtins/libm/shared/src/lib.rs @@ -0,0 +1,471 @@ +#![feature(exact_chunks)] + +#[macro_use] +extern crate lazy_static; + +lazy_static! { + pub static ref F32: Vec = { + let bytes = include_bytes!("../../bin/input/f32"); + + bytes + .exact_chunks(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_bytes(buf))) + }) + .collect() + }; + pub static ref F32F32: Vec<(f32, f32)> = { + let bytes = include_bytes!("../../bin/input/f32f32"); + + bytes + .exact_chunks(8) + .map(|chunk| { + let mut x0 = [0; 4]; + let mut x1 = [0; 4]; + x0.copy_from_slice(&chunk[..4]); + x1.copy_from_slice(&chunk[4..]); + + ( + f32::from_bits(u32::from_le(u32::from_bytes(x0))), + f32::from_bits(u32::from_le(u32::from_bytes(x1))), + ) + }) + .collect() + }; + pub static ref F32F32F32: Vec<(f32, f32, f32)> = { + let bytes = include_bytes!("../../bin/input/f32f32f32"); + + bytes + .exact_chunks(12) + .map(|chunk| { + let mut x0 = [0; 4]; + let mut x1 = [0; 4]; + let mut x2 = [0; 4]; + x0.copy_from_slice(&chunk[..4]); + x1.copy_from_slice(&chunk[4..8]); + x2.copy_from_slice(&chunk[8..]); + + ( + f32::from_bits(u32::from_le(u32::from_bytes(x0))), + f32::from_bits(u32::from_le(u32::from_bytes(x1))), + f32::from_bits(u32::from_le(u32::from_bytes(x2))), + ) + }) + .collect() + }; + pub static ref F32I32: Vec<(f32, i32)> = { + let bytes = include_bytes!("../../bin/input/f32i16"); + + bytes + .exact_chunks(6) + .map(|chunk| { + let mut x0 = [0; 4]; + let mut x1 = [0; 2]; + x0.copy_from_slice(&chunk[..4]); + x1.copy_from_slice(&chunk[4..]); + + ( + f32::from_bits(u32::from_le(u32::from_bytes(x0))), + i16::from_le(i16::from_bytes(x1)) as i32, + ) + }) + .collect() + }; + pub static ref F64: Vec = { + let bytes = include_bytes!("../../bin/input/f64"); + + bytes + .exact_chunks(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_bytes(buf))) + }) + .collect() + }; + pub static ref F64F64: Vec<(f64, f64)> = { + let bytes = include_bytes!("../../bin/input/f64f64"); + + bytes + .exact_chunks(16) + .map(|chunk| { + let mut x0 = [0; 8]; + let mut x1 = [0; 8]; + x0.copy_from_slice(&chunk[..8]); + x1.copy_from_slice(&chunk[8..]); + + ( + f64::from_bits(u64::from_le(u64::from_bytes(x0))), + f64::from_bits(u64::from_le(u64::from_bytes(x1))), + ) + }) + .collect() + }; + pub static ref F64F64F64: Vec<(f64, f64, f64)> = { + let bytes = include_bytes!("../../bin/input/f64f64f64"); + + bytes + .exact_chunks(24) + .map(|chunk| { + let mut x0 = [0; 8]; + let mut x1 = [0; 8]; + let mut x2 = [0; 8]; + x0.copy_from_slice(&chunk[..8]); + x1.copy_from_slice(&chunk[8..16]); + x2.copy_from_slice(&chunk[16..]); + + ( + f64::from_bits(u64::from_le(u64::from_bytes(x0))), + f64::from_bits(u64::from_le(u64::from_bytes(x1))), + f64::from_bits(u64::from_le(u64::from_bytes(x2))), + ) + }) + .collect() + }; + pub static ref F64I32: Vec<(f64, i32)> = { + let bytes = include_bytes!("../../bin/input/f64i16"); + + bytes + .exact_chunks(10) + .map(|chunk| { + let mut x0 = [0; 8]; + let mut x1 = [0; 2]; + x0.copy_from_slice(&chunk[..8]); + x1.copy_from_slice(&chunk[8..]); + + ( + f64::from_bits(u64::from_le(u64::from_bytes(x0))), + i16::from_le(i16::from_bytes(x1)) as i32, + ) + }) + .collect() + }; +} + +#[macro_export] +macro_rules! f32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_bytes(buf))) + }) + .collect::>(); + + for (input, expected) in $crate::F32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) { + if let Err(error) = libm::_eqf(output, *expected) { + panic!( + "INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + input.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}", + input.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f32f32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1), expected) in $crate::F32F32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { + if let Err(error) = libm::_eqf(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f32f32f32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1, i2), expected) in $crate::F32F32F32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) { + if let Err(error) = libm::_eqf(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1.to_bits(), + i2.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f32i32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1), expected) in $crate::F32I32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { + if let Err(error) = libm::_eqf(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1, + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1, + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f64 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_bytes(buf))) + }) + .collect::>(); + + for (input, expected) in shared::F64.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) { + if let Err(error) = libm::_eq(output, *expected) { + panic!( + "INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + input.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}", + input.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f64f64 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1), expected) in shared::F64F64.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { + if let Err(error) = libm::_eq(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f64f64f64 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1, i2), expected) in shared::F64F64F64.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) { + if let Err(error) = libm::_eq(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1.to_bits(), + i2.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f64i32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1), expected) in shared::F64I32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { + if let Err(error) = libm::_eq(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1, + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1, + expected.to_bits() + ); + } + } + } + )+ + } +} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 5121cbfbacf..627c6443e3d 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -21,14 +21,34 @@ pub use math::*; /// Approximate equality with 1 ULP of tolerance #[doc(hidden)] #[inline] -pub fn _eqf(a: u32, b: u32) -> bool { - (a as i32).wrapping_sub(b as i32).abs() <= 1 +pub fn _eqf(a: f32, b: f32) -> Result<(), u32> { + if a.is_nan() && b.is_nan() { + Ok(()) + } else { + let err = (a.to_bits() as i32).wrapping_sub(b.to_bits() as i32).abs(); + + if err <= 1 { + Ok(()) + } else { + Err(err as u32) + } + } } #[doc(hidden)] #[inline] -pub fn _eq(a: u64, b: u64) -> bool { - (a as i64).wrapping_sub(b as i64).abs() <= 1 +pub fn _eq(a: f64, b: f64) -> Result<(), u64> { + if a.is_nan() && b.is_nan() { + Ok(()) + } else { + let err = (a.to_bits() as i64).wrapping_sub(b.to_bits() as i64).abs(); + + if err <= 1 { + Ok(()) + } else { + Err(err as u64) + } + } } /// Math support for `f32` diff --git a/library/compiler-builtins/libm/test-generator/Cargo.toml b/library/compiler-builtins/libm/test-generator/Cargo.toml deleted file mode 100644 index b810d9daf63..00000000000 --- a/library/compiler-builtins/libm/test-generator/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "test-generator" -version = "0.1.0" -authors = ["Jorge Aparicio "] -publish = false - -[dependencies] -rand = "0.5.3" -itertools = "0.7.8" diff --git a/library/compiler-builtins/libm/test-generator/README.md b/library/compiler-builtins/libm/test-generator/README.md deleted file mode 100644 index cbacd88f14d..00000000000 --- a/library/compiler-builtins/libm/test-generator/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# `test-generator` - -This is a tool to generate test cases for the `libm` crate. - -The generator randomly creates inputs for each math function, then proceeds to compute the -expected output for the given function by running the MUSL *C implementation* of the function and -finally it packs the test cases as a Cargo test file. For this reason, this generator **must** -always be compiled for the `x86_64-unknown-linux-musl` target. diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs deleted file mode 100644 index 4c4e420a285..00000000000 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ /dev/null @@ -1,788 +0,0 @@ -// NOTE we intentionally avoid using the `quote` crate here because it doesn't work with the -// `x86_64-unknown-linux-musl` target. - -// NOTE usually the only thing you need to do to test a new math function is to add it to one of the -// macro invocations found in the bottom of this file. - -#[macro_use] -extern crate itertools; -extern crate rand; - -use std::error::Error; -use std::fmt::Write as _0; -use std::fs::{self, File}; -use std::io::Write as _1; -use std::{f32, f64, i16, u16, u32, u64, u8}; - -use rand::{Rng, SeedableRng, XorShiftRng}; - -// Number of test cases to generate -const NTESTS: usize = 10_000; - -// TODO tweak these functions to generate edge cases (zero, infinity, NaN) more often -fn f32(rng: &mut XorShiftRng) -> f32 { - let sign = if rng.gen_bool(0.5) { 1 << 31 } else { 0 }; - let exponent = (rng.gen_range(0, u8::MAX) as u32) << 23; - let mantissa = rng.gen_range(0, u32::MAX) & ((1 << 23) - 1); - - f32::from_bits(sign + exponent + mantissa) -} - -fn f64(rng: &mut XorShiftRng) -> f64 { - let sign = if rng.gen_bool(0.5) { 1 << 63 } else { 0 }; - let exponent = (rng.gen_range(0, u16::MAX) as u64 & ((1 << 11) - 1)) << 52; - let mantissa = rng.gen_range(0, u64::MAX) & ((1 << 52) - 1); - - f64::from_bits(sign + exponent + mantissa) -} - -const EDGE_CASES32: &[f32] = &[ - -0., - 0., - f32::EPSILON, - f32::INFINITY, - f32::MAX, - f32::MIN, - f32::MIN_POSITIVE, - f32::NAN, - f32::NEG_INFINITY, -]; - -const EDGE_CASES64: &[f64] = &[ - -0., - 0., - f64::EPSILON, - f64::INFINITY, - f64::MAX, - f64::MIN, - f64::MIN_POSITIVE, - f64::NAN, - f64::NEG_INFINITY, -]; - -// fn(f32) -> f32 -macro_rules! f32_f32 { - ($($intr:ident,)*) => { - fn f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { - // MUSL C implementation of the function to test - extern "C" { - $(fn $intr(_: f32) -> f32;)* - } - - $( - let mut cases = String::new(); - - // random inputs - for inp in EDGE_CASES32.iter().cloned().chain((0..NTESTS).map(|_| f32(rng))) { - let out = unsafe { $intr(inp) }; - - let inp = inp.to_bits(); - let out = out.to_bits(); - - write!(cases, "({}, {})", inp, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[(u32, u32)] = &[ - {1} - ]; - - for case in CASES {{ - let (inp, expected) = *case; - - if let Ok(outf) = - panic::catch_unwind(|| libm::{0}(f32::from_bits(inp))) - {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) - || libm::_eqf(outi, expected)) - {{ - panic!( - \"input: {{}}, output: {{}}, expected: {{}}\", - inp, outi, expected, - ); - }} - }} else {{ - panic!( - \"input: {{}}, output: PANIC, expected: {{}}\", - inp, expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - } -} - -// fn(f32, f32) -> f32 -macro_rules! f32f32_f32 { - ($($intr:ident,)*) => { - fn f32f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { - extern "C" { - $(fn $intr(_: f32, _: f32) -> f32;)* - } - - let mut rng2 = rng.clone(); - let mut rng3 = rng.clone(); - $( - let mut cases = String::new(); - for (i1, i2) in iproduct!( - EDGE_CASES32.iter().cloned(), - EDGE_CASES32.iter().cloned() - ).chain(EDGE_CASES32.iter().map(|i1| (*i1, f32(rng)))) - .chain(EDGE_CASES32.iter().map(|i2| (f32(&mut rng2), *i2))) - .chain((0..NTESTS).map(|_| (f32(&mut rng3), f32(&mut rng3)))) - { - let out = unsafe { $intr(i1, i2) }; - - let i1 = i1.to_bits(); - let i2 = i2.to_bits(); - let out = out.to_bits(); - - write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[((u32, u32), u32)] = &[ - {1} - ]; - - for case in CASES {{ - let ((i1, i2), expected) = *case; - - if let Ok(outf) = panic::catch_unwind(|| {{ - libm::{0}(f32::from_bits(i1), f32::from_bits(i2)) - }}) {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) - || libm::_eqf(outi, expected)) - {{ - panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", - (i1, i2), - outi, - expected, - ); - }} - }} else {{ - panic!( - \"input: {{:?}}, output: PANIC, expected: {{}}\", - (i1, i2), - expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - }; -} - -// fn(f32, f32, f32) -> f32 -macro_rules! f32f32f32_f32 { - ($($intr:ident,)*) => { - fn f32f32f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { - extern "C" { - $(fn $intr(_: f32, _: f32, _: f32) -> f32;)* - } - - let mut rng2 = rng.clone(); - $( - let mut cases = String::new(); - for (i1, i2, i3) in iproduct!( - EDGE_CASES32.iter().cloned(), - EDGE_CASES32.iter().cloned(), - EDGE_CASES32.iter().cloned() - ).chain(EDGE_CASES32.iter().map(|i1| (*i1, f32(rng), f32(rng)))) - .chain((0..NTESTS).map(|_| (f32(&mut rng2), f32(&mut rng2), f32(&mut rng2)))) - { - let out = unsafe { $intr(i1, i2, i3) }; - - let i1 = i1.to_bits(); - let i2 = i2.to_bits(); - let i3 = i3.to_bits(); - let out = out.to_bits(); - - write!(cases, "(({}, {}, {}), {})", i1, i2, i3, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[((u32, u32, u32), u32)] = &[ - {1} - ]; - - for case in CASES {{ - let ((i1, i2, i3), expected) = *case; - - if let Ok(outf) = panic::catch_unwind(|| {{ - libm::{0}( - f32::from_bits(i1), - f32::from_bits(i2), - f32::from_bits(i3), - ) - }}) {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) - || libm::_eqf(outi, expected)) - {{ - panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", - (i1, i2, i3), - outi, - expected, - ); - }} - }} else {{ - panic!( - \"input: {{:?}}, output: PANIC, expected: {{}}\", - (i1, i2, i3), - expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - }; -} - -// fn(f32, i32) -> f32 -macro_rules! f32i32_f32 { - ($($intr:ident,)*) => { - fn f32i32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { - extern "C" { - $(fn $intr(_: f32, _: i32) -> f32;)* - } - - let mut rng2 = rng.clone(); - $( - let mut cases = String::new(); - for i1 in EDGE_CASES32.iter().cloned().chain((0..NTESTS).map(|_| f32(&mut rng2))) { - let i2 = rng.gen_range(i16::MIN, i16::MAX); - let out = unsafe { $intr(i1, i2 as i32) }; - - let i1 = i1.to_bits(); - let out = out.to_bits(); - - write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[((u32, i16), u32)] = &[ - {1} - ]; - - for case in CASES {{ - let ((i1, i2), expected) = *case; - - if let Ok(outf) = panic::catch_unwind(|| {{ - libm::{0}(f32::from_bits(i1), i2 as i32) - }}) {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) - || libm::_eqf(outi, expected)) - {{ - panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", - (i1, i2), - outi, - expected, - ); - }} - }} else {{ - panic!( - \"input: {{:?}}, output: PANIC, expected: {{}}\", - (i1, i2), - expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - }; -} - -// fn(f64) -> f64 -macro_rules! f64_f64 { - ($($intr:ident,)*) => { - fn f64_f64(rng: &mut XorShiftRng) -> Result<(), Box> { - // MUSL C implementation of the function to test - extern "C" { - $(fn $intr(_: f64) -> f64;)* - } - - $( - let mut cases = String::new(); - for inp in EDGE_CASES64.iter().cloned().chain((0..NTESTS).map(|_| f64(rng))) { - let out = unsafe { $intr(inp) }; - - let inp = inp.to_bits(); - let out = out.to_bits(); - - write!(cases, "({}, {})", inp, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[(u64, u64)] = &[ - {1} - ]; - - for case in CASES {{ - let (inp, expected) = *case; - - if let Ok(outf) = panic::catch_unwind(|| {{ - libm::{0}(f64::from_bits(inp)) - }}) {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) - || libm::_eq(outi, expected)) - {{ - panic!( - \"input: {{}}, output: {{}}, expected: {{}}\", - inp, - outi, - expected, - ); - }} - }} else {{ - panic!( - \"input: {{}}, output: PANIC, expected: {{}}\", - inp, - expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - } -} - -// fn(f64, f64) -> f64 -macro_rules! f64f64_f64 { - ($($intr:ident,)*) => { - fn f64f64_f64(rng: &mut XorShiftRng) -> Result<(), Box> { - extern "C" { - $(fn $intr(_: f64, _: f64) -> f64;)* - } - - let mut rng2 = rng.clone(); - let mut rng3 = rng.clone(); - $( - let mut cases = String::new(); - for (i1, i2) in iproduct!( - EDGE_CASES64.iter().cloned(), - EDGE_CASES64.iter().cloned() - ).chain(EDGE_CASES64.iter().map(|i1| (*i1, f64(rng)))) - .chain(EDGE_CASES64.iter().map(|i2| (f64(&mut rng2), *i2))) - .chain((0..NTESTS).map(|_| (f64(&mut rng3), f64(&mut rng3)))) - { - let out = unsafe { $intr(i1, i2) }; - - let i1 = i1.to_bits(); - let i2 = i2.to_bits(); - let out = out.to_bits(); - - write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[((u64, u64), u64)] = &[ - {1} - ]; - - for case in CASES {{ - let ((i1, i2), expected) = *case; - - if let Ok(outf) = panic::catch_unwind(|| {{ - libm::{0}(f64::from_bits(i1), f64::from_bits(i2)) - }}) {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || - libm::_eq(outi, expected)) {{ - panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", - (i1, i2), - outi, - expected, - ); - }} - }} else {{ - panic!( - \"input: {{:?}}, output: PANIC, expected: {{}}\", - (i1, i2), - expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - }; -} - -// fn(f64, f64, f64) -> f64 -macro_rules! f64f64f64_f64 { - ($($intr:ident,)*) => { - fn f64f64f64_f64(rng: &mut XorShiftRng) -> Result<(), Box> { - extern "C" { - $(fn $intr(_: f64, _: f64, _: f64) -> f64;)* - } - - let mut rng2 = rng.clone(); - $( - let mut cases = String::new(); - for (i1, i2, i3) in iproduct!( - EDGE_CASES64.iter().cloned(), - EDGE_CASES64.iter().cloned(), - EDGE_CASES64.iter().cloned() - ).chain(EDGE_CASES64.iter().map(|i1| (*i1, f64(rng), f64(rng)))) - .chain((0..NTESTS).map(|_| (f64(&mut rng2), f64(&mut rng2), f64(&mut rng2)))) - { - let out = unsafe { $intr(i1, i2, i3) }; - - let i1 = i1.to_bits(); - let i2 = i2.to_bits(); - let i3 = i3.to_bits(); - let out = out.to_bits(); - - write!(cases, "(({}, {}, {}), {})", i1, i2, i3, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[((u64, u64, u64), u64)] = &[ - {1} - ]; - - for case in CASES {{ - let ((i1, i2, i3), expected) = *case; - - if let Ok(outf) = panic::catch_unwind(|| {{ - libm::{0}( - f64::from_bits(i1), - f64::from_bits(i2), - f64::from_bits(i3), - ) - }}) {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) - || libm::_eq(outi, expected)) - {{ - panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", - (i1, i2, i3), - outi, - expected, - ); - }} - }} else {{ - panic!( - \"input: {{:?}}, output: PANIC, expected: {{}}\", - (i1, i2, i3), - expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - }; -} - -// fn(f64, i32) -> f64 -macro_rules! f64i32_f64 { - ($($intr:ident,)*) => { - fn f64i32_f64(rng: &mut XorShiftRng) -> Result<(), Box> { - extern "C" { - $(fn $intr(_: f64, _: i32) -> f64;)* - } - - let mut rng2 = rng.clone(); - $( - let mut cases = String::new(); - for i1 in EDGE_CASES64.iter().cloned().chain((0..NTESTS).map(|_| f64(&mut rng2))) { - let i2 = rng.gen_range(i16::MIN, i16::MAX); - let out = unsafe { $intr(i1, i2 as i32) }; - - let i1 = i1.to_bits(); - let out = out.to_bits(); - - write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[((u64, i16), u64)] = &[ - {1} - ]; - - for case in CASES {{ - let ((i1, i2), expected) = *case; - - if let Ok(outf) = panic::catch_unwind(|| {{ - libm::{0}(f64::from_bits(i1), i2 as i32) - }}) {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || - libm::_eq(outi, expected)) {{ - panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", - (i1, i2), - outi, - expected, - ); - }} - }} else {{ - panic!( - \"input: {{:?}}, output: PANIC, expected: {{}}\", - (i1, i2), - expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - }; -} - -fn main() -> Result<(), Box> { - fs::remove_dir_all("tests").ok(); - fs::create_dir("tests")?; - - let mut rng = XorShiftRng::from_rng(&mut rand::thread_rng())?; - - f32_f32(&mut rng)?; - f32f32_f32(&mut rng)?; - f32f32f32_f32(&mut rng)?; - f32i32_f32(&mut rng)?; - f64_f64(&mut rng)?; - f64f64_f64(&mut rng)?; - f64f64f64_f64(&mut rng)?; - f64i32_f64(&mut rng)?; - - Ok(()) -} - -/* Functions to test */ - -// With signature `fn(f32) -> f32` -f32_f32! { - acosf, - floorf, - truncf, - asinf, - atanf, - cbrtf, - cosf, - ceilf, - coshf, - exp2f, - expf, - expm1f, - log10f, - log1pf, - log2f, - logf, - roundf, - sinf, - sinhf, - tanf, - tanhf, - fabsf, - sqrtf, -} - -// With signature `fn(f32, f32) -> f32` -f32f32_f32! { - atan2f, - fdimf, - hypotf, - fmodf, - powf, -} - -// With signature `fn(f32, f32, f32) -> f32` -f32f32f32_f32! { - fmaf, -} - -// With signature `fn(f32, i32) -> f32` -f32i32_f32! { - scalbnf, -} - -// With signature `fn(f64) -> f64` -f64_f64! { - acos, - asin, - atan, - cbrt, - ceil, - cos, - cosh, - exp, - exp2, - expm1, - floor, - log, - log10, - log1p, - log2, - round, - sin, - sinh, - sqrt, - tan, - tanh, - trunc, - fabs, -} - -// With signature `fn(f64, f64) -> f64` -f64f64_f64! { - atan2, - fdim, - fmod, - hypot, - pow, -} - -// With signature `fn(f64, f64, f64) -> f64` -f64f64f64_f64! { - fma, -} - -// With signature `fn(f64, i32) -> f64` -f64i32_f64! { - scalbn, -} -- cgit 1.4.1-3-g733a5 From 99da9ff292e475172c42d5cea073354af47972fa Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 27 Jul 2018 00:21:54 -0500 Subject: make qemu-arm executable --- library/compiler-builtins/libm/ci/install.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/ci/install.sh b/library/compiler-builtins/libm/ci/install.sh index 7f73c5feaf3..af26e2d4c30 100644 --- a/library/compiler-builtins/libm/ci/install.sh +++ b/library/compiler-builtins/libm/ci/install.sh @@ -18,6 +18,8 @@ main() { mkdir -p ~/.local/bin curl -L https://github.com/japaric/qemu-bin/raw/master/14.04/qemu-arm-2.12.0 > ~/.local/bin/qemu-arm + chmod +x ~/.local/bin/qemu-arm + qemu-arm --version } main -- cgit 1.4.1-3-g733a5 From 28b3fff3c5ec7aafe467ce2b0e34d1678f8fdc5a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 27 Jul 2018 00:27:25 -0500 Subject: uncomment the other build jobs --- library/compiler-builtins/libm/.travis.yml | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index b3beecb0920..47f2b2f205d 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -6,28 +6,28 @@ matrix: include: - env: TARGET=aarch64-unknown-linux-gnu rust: nightly - # - env: TARGET=armv7-unknown-linux-gnueabihf - # rust: nightly - # - env: TARGET=i686-unknown-linux-gnu - # rust: nightly - # - env: TARGET=mips-unknown-linux-gnu - # rust: nightly - # - env: TARGET=mips64-unknown-linux-gnuabi64 - # rust: nightly - # - env: TARGET=mips64el-unknown-linux-gnuabi64 - # rust: nightly - # - env: TARGET=mipsel-unknown-linux-gnu - # rust: nightly - # - env: TARGET=powerpc-unknown-linux-gnu - # rust: nightly - # - env: TARGET=powerpc64-unknown-linux-gnu - # rust: nightly - # - env: TARGET=powerpc64le-unknown-linux-gnu - # rust: nightly + - env: TARGET=armv7-unknown-linux-gnueabihf + rust: nightly + - env: TARGET=i686-unknown-linux-gnu + rust: nightly + - env: TARGET=mips-unknown-linux-gnu + rust: nightly + - env: TARGET=mips64-unknown-linux-gnuabi64 + rust: nightly + - env: TARGET=mips64el-unknown-linux-gnuabi64 + rust: nightly + - env: TARGET=mipsel-unknown-linux-gnu + rust: nightly + - env: TARGET=powerpc-unknown-linux-gnu + rust: nightly + - env: TARGET=powerpc64-unknown-linux-gnu + rust: nightly + - env: TARGET=powerpc64le-unknown-linux-gnu + rust: nightly - env: TARGET=x86_64-unknown-linux-gnu rust: nightly - # - env: TARGET=cargo-fmt - # rust: beta + - env: TARGET=cargo-fmt + rust: beta before_install: set -e -- cgit 1.4.1-3-g733a5 From 527eefef9c11396cff6bc9cb0b939c053ebf8b95 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 27 Jul 2018 00:38:56 -0500 Subject: tweak the order of the tests --- library/compiler-builtins/libm/ci/script.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index 59e5a5f37de..c3b6faa6cac 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -6,13 +6,6 @@ main() { return fi - # test that the functions don't contain invocations of `panic!` - case $TARGET in - armv7-unknown-linux-gnueabihf) - cross build --release --target $TARGET --example no-panic - ;; - esac - # quick check cargo check @@ -24,6 +17,13 @@ main() { cargo run -p musl-generator --target x86_64-unknown-linux-musl cargo run -p newlib-generator + # test that the functions don't contain invocations of `panic!` + case $TARGET in + armv7-unknown-linux-gnueabihf) + cross build --release --target $TARGET --example no-panic + ;; + esac + # run unit tests cross test --lib --features checked --target $TARGET --release -- cgit 1.4.1-3-g733a5 From 831af41ae4ea718e255b7f857df7a49e4fb2eb06 Mon Sep 17 00:00:00 2001 From: David Craven Date: Thu, 26 Jul 2018 19:30:26 +0200 Subject: Implement __mulsi3. --- library/compiler-builtins/src/lib.rs | 3 +++ library/compiler-builtins/src/riscv32.rs | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 library/compiler-builtins/src/riscv32.rs diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 02b6c7db953..9f1dd15120c 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -58,6 +58,9 @@ pub mod arm; #[cfg(all(kernel_user_helpers, target_os = "linux", target_arch = "arm"))] pub mod arm_linux; +#[cfg(any(target_arch = "riscv32"))] +pub mod riscv32; + #[cfg(target_arch = "x86")] pub mod x86; diff --git a/library/compiler-builtins/src/riscv32.rs b/library/compiler-builtins/src/riscv32.rs new file mode 100644 index 00000000000..ebaa354a4b3 --- /dev/null +++ b/library/compiler-builtins/src/riscv32.rs @@ -0,0 +1,17 @@ +intrinsics! { + // Implementation from gcc + // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c + pub extern "C" fn __mulsi3(mut a: u32, mut b: u32) -> u32 { + let mut r: usize = 0; + + while a > 0 { + if a & 1 > 0 { + r += b; + } + a >>= 1; + b <<= 1; + } + + r + } +} -- cgit 1.4.1-3-g733a5 From b0b04fc04394d0c6b47a688e29f9df717899d3bb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 Aug 2018 07:07:43 -0700 Subject: Upgrade to LLVM 7 branch point --- library/compiler-builtins/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index 40151c4c1cf..8964c7a0c4d 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit 40151c4c1cf77e593e3654e66e25ea423116aaae +Subproject commit 8964c7a0c4d1dc8c45b5adee6fe5ae3db057ab98 -- cgit 1.4.1-3-g733a5 From e3ac57b2343b56389d6f6eb8be1767f30b883f03 Mon Sep 17 00:00:00 2001 From: Yu Ding Date: Mon, 6 Aug 2018 20:54:48 -0700 Subject: Fix symbol collision caused by floatdisf [PR #234](https://github.com/rust-lang-nursery/compiler-builtins/pull/234) added floatdisf implementation in rust and removed floatdisf.c from build.rs. However the removal is in-complete. In x86_64+!msvc environment, the symbol floatdisf would be generated twice. Bugs found in Redox OS issue [#1195](https://gitlab.redox-os.org/redox-os/redox/issues/1195) and Mesalink travis [log](https://travis-ci.org/mesalock-linux/mesalink/jobs/412928048) at line 738. This patch fixes it by removing floatdisf.c from this environment. Signed-off-by: Yu Ding --- library/compiler-builtins/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index cdcbfe24cd7..d06c1191f3e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -267,7 +267,6 @@ mod c { if target_arch == "x86_64" { sources.extend( &[ - "x86_64/floatdisf.c", "x86_64/floatdixf.c", "x86_64/floatundidf.S", "x86_64/floatundisf.S", -- cgit 1.4.1-3-g733a5 From 0e67871a430062619951e72c92b9d2735c3449cc Mon Sep 17 00:00:00 2001 From: Yu Ding Date: Mon, 6 Aug 2018 23:03:37 -0700 Subject: Follow up on PR #252 --- library/compiler-builtins/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d06c1191f3e..fba4091124a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -269,7 +269,6 @@ mod c { &[ "x86_64/floatdixf.c", "x86_64/floatundidf.S", - "x86_64/floatundisf.S", "x86_64/floatundixf.S", ], ); -- cgit 1.4.1-3-g733a5 From 2095fdab378c80ba64bd1aeacd01f772743f21f0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 17 Aug 2018 11:21:08 -0700 Subject: Remove unused features --- library/compiler-builtins/examples/intrinsics.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index c165fcccaff..7f502bba34b 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -6,10 +6,8 @@ #![allow(unused_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] -#![feature(alloc_system)] #![feature(asm)] #![feature(compiler_builtins_lib)] -#![feature(core_float)] #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] -- cgit 1.4.1-3-g733a5 From c9b4a8423c388246fb29c49cda44717cb671bdd6 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 18 Aug 2018 12:29:01 +0300 Subject: Fix __sync_fetch_and_nand_* for pre-v6 ARM gcc changed semantics for __sync_fetch_and_nand_* in gcc 4.4, and this was implementing the old semantics: https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/_005f_005fsync-Builtins.html --- library/compiler-builtins/src/arm_linux.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs index 2291edf9f14..5ed379fa1e2 100644 --- a/library/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/src/arm_linux.rs @@ -125,9 +125,9 @@ atomic_rmw!(__sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b); atomic_rmw!(__sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b); atomic_rmw!(__sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b); -atomic_rmw!(__sync_fetch_and_nand_1, u8, |a: u8, b: u8| !a & b); -atomic_rmw!(__sync_fetch_and_nand_2, u16, |a: u16, b: u16| !a & b); -atomic_rmw!(__sync_fetch_and_nand_4, u32, |a: u32, b: u32| !a & b); +atomic_rmw!(__sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b)); +atomic_rmw!(__sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b)); +atomic_rmw!(__sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b)); atomic_rmw!(__sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { a } else { b }); atomic_rmw!(__sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { a } else { b }); -- cgit 1.4.1-3-g733a5 From ff82848c8e07b85bb1717bd5f657132dd3cdadfe Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 22 Aug 2018 11:19:18 -0700 Subject: Update LLVM's compiler-rt submodule --- library/compiler-builtins/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index 8964c7a0c4d..7e387f0f90b 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit 8964c7a0c4d1dc8c45b5adee6fe5ae3db057ab98 +Subproject commit 7e387f0f90b493ae72930c787c381a80055a7ec9 -- cgit 1.4.1-3-g733a5 From 4f1f71a8d623a9189ce979614f7f72d4629c35ec Mon Sep 17 00:00:00 2001 From: Igor null Date: Sun, 26 Aug 2018 16:36:59 +0300 Subject: Ported several remaining math functions from musl Please note that these aren't tested yet. --- library/compiler-builtins/libm/src/math/acosh.rs | 22 ++ library/compiler-builtins/libm/src/math/acoshf.rs | 21 ++ library/compiler-builtins/libm/src/math/asinef.rs | 95 +++++ library/compiler-builtins/libm/src/math/asinh.rs | 35 ++ library/compiler-builtins/libm/src/math/asinhf.rs | 34 ++ library/compiler-builtins/libm/src/math/atanh.rs | 33 ++ library/compiler-builtins/libm/src/math/atanhf.rs | 32 ++ .../compiler-builtins/libm/src/math/copysign.rs | 7 + .../compiler-builtins/libm/src/math/copysignf.rs | 7 + library/compiler-builtins/libm/src/math/erf.rs | 297 ++++++++++++++++ library/compiler-builtins/libm/src/math/erff.rs | 210 +++++++++++ library/compiler-builtins/libm/src/math/exp10.rs | 24 ++ library/compiler-builtins/libm/src/math/exp10f.rs | 22 ++ library/compiler-builtins/libm/src/math/frexp.rs | 20 ++ library/compiler-builtins/libm/src/math/frexpf.rs | 21 ++ library/compiler-builtins/libm/src/math/ilogb.rs | 31 ++ library/compiler-builtins/libm/src/math/ilogbf.rs | 31 ++ library/compiler-builtins/libm/src/math/j0.rs | 392 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/j0f.rs | 330 +++++++++++++++++ library/compiler-builtins/libm/src/math/j1.rs | 387 ++++++++++++++++++++ library/compiler-builtins/libm/src/math/j1f.rs | 331 +++++++++++++++++ library/compiler-builtins/libm/src/math/jn.rs | 338 ++++++++++++++++++ library/compiler-builtins/libm/src/math/jnf.rs | 255 ++++++++++++++ library/compiler-builtins/libm/src/math/lgamma.rs | 309 ++++++++++++++++ library/compiler-builtins/libm/src/math/lgammaf.rs | 244 +++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 74 ++++ library/compiler-builtins/libm/src/math/modf.rs | 33 ++ library/compiler-builtins/libm/src/math/modff.rs | 32 ++ library/compiler-builtins/libm/src/math/remquo.rs | 98 ++++++ library/compiler-builtins/libm/src/math/remquof.rs | 97 +++++ library/compiler-builtins/libm/src/math/sincos.rs | 60 ++++ library/compiler-builtins/libm/src/math/sincosf.rs | 122 +++++++ library/compiler-builtins/libm/src/math/tgamma.rs | 179 ++++++++++ library/compiler-builtins/libm/src/math/tgammaf.rs | 5 + 34 files changed, 4228 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/acosh.rs create mode 100644 library/compiler-builtins/libm/src/math/acoshf.rs create mode 100644 library/compiler-builtins/libm/src/math/asinef.rs create mode 100644 library/compiler-builtins/libm/src/math/asinh.rs create mode 100644 library/compiler-builtins/libm/src/math/asinhf.rs create mode 100644 library/compiler-builtins/libm/src/math/atanh.rs create mode 100644 library/compiler-builtins/libm/src/math/atanhf.rs create mode 100644 library/compiler-builtins/libm/src/math/copysign.rs create mode 100644 library/compiler-builtins/libm/src/math/copysignf.rs create mode 100644 library/compiler-builtins/libm/src/math/erf.rs create mode 100644 library/compiler-builtins/libm/src/math/erff.rs create mode 100644 library/compiler-builtins/libm/src/math/exp10.rs create mode 100644 library/compiler-builtins/libm/src/math/exp10f.rs create mode 100644 library/compiler-builtins/libm/src/math/frexp.rs create mode 100644 library/compiler-builtins/libm/src/math/frexpf.rs create mode 100644 library/compiler-builtins/libm/src/math/ilogb.rs create mode 100644 library/compiler-builtins/libm/src/math/ilogbf.rs create mode 100644 library/compiler-builtins/libm/src/math/j0.rs create mode 100644 library/compiler-builtins/libm/src/math/j0f.rs create mode 100644 library/compiler-builtins/libm/src/math/j1.rs create mode 100644 library/compiler-builtins/libm/src/math/j1f.rs create mode 100644 library/compiler-builtins/libm/src/math/jn.rs create mode 100644 library/compiler-builtins/libm/src/math/jnf.rs create mode 100644 library/compiler-builtins/libm/src/math/lgamma.rs create mode 100644 library/compiler-builtins/libm/src/math/lgammaf.rs create mode 100644 library/compiler-builtins/libm/src/math/modf.rs create mode 100644 library/compiler-builtins/libm/src/math/modff.rs create mode 100644 library/compiler-builtins/libm/src/math/remquo.rs create mode 100644 library/compiler-builtins/libm/src/math/remquof.rs create mode 100644 library/compiler-builtins/libm/src/math/sincos.rs create mode 100644 library/compiler-builtins/libm/src/math/sincosf.rs create mode 100644 library/compiler-builtins/libm/src/math/tgamma.rs create mode 100644 library/compiler-builtins/libm/src/math/tgammaf.rs diff --git a/library/compiler-builtins/libm/src/math/acosh.rs b/library/compiler-builtins/libm/src/math/acosh.rs new file mode 100644 index 00000000000..3494e3405e7 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/acosh.rs @@ -0,0 +1,22 @@ +use super::{log, log1p, sqrt}; + +const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +pub fn acosh(x: f64) -> f64 { + let u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + + /* x < 1 domain error is handled in the called functions */ + + if e < 0x3ff + 1 { + /* |x| < 2, up to 2ulp error in [1,1.125] */ + return log1p(x-1.0+sqrt((x-1.0)*(x-1.0)+2.0*(x-1.0))); + } + if e < 0x3ff + 26 { + /* |x| < 0x1p26 */ + return log(2.0*x-1.0/(x+sqrt(x*x-1.0))); + } + /* |x| >= 0x1p26 or nan */ + return log(x) + LN2; +} diff --git a/library/compiler-builtins/libm/src/math/acoshf.rs b/library/compiler-builtins/libm/src/math/acoshf.rs new file mode 100644 index 00000000000..1e298a9b3d5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/acoshf.rs @@ -0,0 +1,21 @@ +use super::{log1pf, logf, sqrtf}; + +const LN2: f32 = 0.693147180559945309417232121458176568; + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +pub fn acoshf(x: f32) -> f32 { + let u = x.to_bits(); + let a = u & 0x7fffffff; + + if a < 0x3f800000+(1<<23) { + /* |x| < 2, invalid if x < 1 or nan */ + /* up to 2ulp error in [1,1.125] */ + return log1pf(x-1.0 + sqrtf((x-1.0)*(x-1.0)+2.0*(x-1.0))); + } + if a < 0x3f800000+(12<<23) { + /* |x| < 0x1p12 */ + return logf(2.0*x - 1.0/(x+sqrtf(x*x-1.0))); + } + /* x >= 0x1p12 */ + return logf(x) + LN2; +} diff --git a/library/compiler-builtins/libm/src/math/asinef.rs b/library/compiler-builtins/libm/src/math/asinef.rs new file mode 100644 index 00000000000..d2cd826999d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/asinef.rs @@ -0,0 +1,95 @@ +/* @(#)z_asinef.c 1.0 98/08/13 */ +/****************************************************************** + * The following routines are coded directly from the algorithms + * and coefficients given in "Software Manual for the Elementary + * Functions" by William J. Cody, Jr. and William Waite, Prentice + * Hall, 1980. + ******************************************************************/ +/****************************************************************** + * Arcsine + * + * Input: + * x - floating point value + * acosine - indicates acos calculation + * + * Output: + * Arcsine of x. + * + * Description: + * This routine calculates arcsine / arccosine. + * + *****************************************************************/ + +use super::{fabsf, sqrtf}; + +const P: [f32; 2] = [ 0.933935835, -0.504400557 ]; +const Q: [f32; 2] = [ 0.560363004e+1, -0.554846723e+1 ]; +const A: [f32; 2] = [ 0.0, 0.785398163 ]; +const B: [f32; 2] = [ 1.570796326, 0.785398163 ]; +const Z_ROOTEPS_F: f32 = 1.7263349182589107e-4; + +pub fn asinef(x: f32, acosine: usize) -> f32 +{ + let flag: usize; + let i: usize; + let mut branch: bool = false; + let g: f32; + let mut res: f32 = 0.0; + let mut y: f32; + + /* Check for special values. */ + //i = numtestf (x); + if x.is_nan() || x.is_infinite() { + force_eval!(x); + return x; + } + + y = fabsf(x); + flag = acosine; + + if y > 0.5 { + i = 1 - flag; + + /* Check for range error. */ + if y > 1.0 { + return 0.0 / 0.0; + } + + g = (1.0 - y) / 2.0; + y = -2.0 * sqrtf(g); + branch = true; + } else { + i = flag; + if y < Z_ROOTEPS_F { + res = y; + g = 0.0; // pleasing the uninitialized variable + } else { + g = y * y; + } + } + + if y >= Z_ROOTEPS_F || branch { + /* Calculate the Taylor series. */ + let p = (P[1] * g + P[0]) * g; + let q = (g + Q[1]) * g + Q[0]; + let r = p / q; + + res = y + y * r; + } + + /* Calculate asine or acose. */ + if flag == 0 { + res = (A[i] + res) + A[i]; + if x < 0.0 { + res = -res; + } + } else { + if x < 0.0 { + res = (B[i] + res) + B[i]; + } else { + res = (A[i] - res) + A[i]; + } + } + + return res; +} diff --git a/library/compiler-builtins/libm/src/math/asinh.rs b/library/compiler-builtins/libm/src/math/asinh.rs new file mode 100644 index 00000000000..09e894551f6 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/asinh.rs @@ -0,0 +1,35 @@ +use super::{log, log1p, sqrt}; + +const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +pub fn asinh(mut x: f64) -> f64 { + let mut u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + let sign = (u >> 63) != 0; + + /* |x| */ + u &= (!0) >> 1; + x = f64::from_bits(u); + + if e >= 0x3ff + 26 { + /* |x| >= 0x1p26 or inf or nan */ + x = log(x) + LN2; + } else if e >= 0x3ff + 1 { + /* |x| >= 2 */ + x = log(2.0*x + 1.0/(sqrt(x*x+1.0)+x)); + } else if e >= 0x3ff - 26 { + /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ + x = log1p(x + x*x/(sqrt(x*x+1.0)+1.0)); + } else { + /* |x| < 0x1p-26, raise inexact if x != 0 */ + let x1p120 = f64::from_bits(0x4770000000000000); + force_eval!(x + x1p120); + } + + if sign { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/src/math/asinhf.rs new file mode 100644 index 00000000000..236916d83e8 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/asinhf.rs @@ -0,0 +1,34 @@ +use super::{logf, log1pf, sqrtf}; + +const LN2: f32 = 0.693147180559945309417232121458176568; + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +pub fn asinhf(mut x: f32) -> f32 { + let u = x.to_bits(); + let i = u & 0x7fffffff; + let sign = (u >> 31) != 0; + + /* |x| */ + x = f32::from_bits(i); + + if i >= 0x3f800000 + (12<<23) { + /* |x| >= 0x1p12 or inf or nan */ + x = logf(x) + LN2; + } else if i >= 0x3f800000 + (1<<23) { + /* |x| >= 2 */ + x = logf(2.0*x + 1.0/(sqrtf(x*x+1.0)+x)); + } else if i >= 0x3f800000 - (12<<23) { + /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ + x = log1pf(x + x*x/(sqrtf(x*x+1.0)+1.0)); + } else { + /* |x| < 0x1p-12, raise inexact if x!=0 */ + let x1p120 = f32::from_bits(0x7b800000); + force_eval!(x + x1p120); + } + + if sign { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/atanh.rs b/library/compiler-builtins/libm/src/math/atanh.rs new file mode 100644 index 00000000000..ea444809c7d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atanh.rs @@ -0,0 +1,33 @@ +use super::{log1p}; + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +pub fn atanh(mut x: f64) -> f64 { + let mut u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + let sign = (u >> 63) != 0; + + /* |x| */ + u &= 0x7fffffff; + x = f64::from_bits(u); + + if e < 0x3ff - 1 { + if e < 0x3ff - 32 { + /* handle underflow */ + if e == 0 { + force_eval!(x as f32); + } + } else { + /* |x| < 0.5, up to 1.7ulp error */ + x = 0.5*log1p(2.0*x + 2.0*x*x/(1.0-x)); + } + } else { + /* avoid overflow */ + x = 0.5*log1p(2.0*(x/(1.0-x))); + } + + if sign { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs new file mode 100644 index 00000000000..77d451bf27e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atanhf.rs @@ -0,0 +1,32 @@ +use super::{log1pf}; + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +pub fn atanhf(mut x: f32) -> f32 { + let mut u = x.to_bits(); + let sign = (u >> 31) != 0; + + /* |x| */ + u &= 0x7fffffff; + x = f32::from_bits(u); + + if u < 0x3f800000 - (1<<23) { + if u < 0x3f800000 - (32<<23) { + /* handle underflow */ + if u < (1<<23) { + force_eval!((x*x) as f32); + } + } else { + /* |x| < 0.5, up to 1.7ulp error */ + x = 0.5*log1pf(2.0*x + 2.0*x*x/(1.0-x)); + } + } else { + /* avoid overflow */ + x = 0.5*log1pf(2.0*(x/(1.0-x))); + } + + if sign { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs new file mode 100644 index 00000000000..74b761e7468 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -0,0 +1,7 @@ +pub fn copysign(x: f64, y: f64) -> f64 { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= (!0) >> 1; + ux |= uy & (1<<63); + f64::from_bits(ux) +} diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs new file mode 100644 index 00000000000..a0a814bf6a1 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/copysignf.rs @@ -0,0 +1,7 @@ +pub fn copysignf(x: f32, y: f32) -> f32 { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= 0x7fffffff; + ux |= uy & 0x80000000; + f32::from_bits(ux) +} diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs new file mode 100644 index 00000000000..b3ad2ce058f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -0,0 +1,297 @@ +use super::{exp, fabs, get_high_word, with_set_low_word}; +/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * where R = P/Q where P is an odd poly of degree 8 and + * Q is an odd poly of degree 10. + * -57.90 + * | R - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + * erf(x) = 1 - erfc(x) + * where + * R1(z) = degree 7 poly in z, (z=1/x^2) + * S1(z) = degree 8 poly in z + * + * 4. For x in [1/0.35,28] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +const ERX: f64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +const EFX8: f64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ +const PP0: f64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ +const PP1: f64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ +const PP2: f64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */ +const PP3: f64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */ +const PP4: f64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */ +const QQ1: f64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */ +const QQ2: f64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ +const QQ3: f64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ +const QQ4: f64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ +const QQ5: f64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +const PA0: f64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ +const PA1: f64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ +const PA2: f64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ +const PA3: f64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */ +const PA4: f64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */ +const PA5: f64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */ +const PA6: f64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */ +const QA1: f64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */ +const QA2: f64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */ +const QA3: f64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ +const QA4: f64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ +const QA5: f64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ +const QA6: f64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +const RA0: f64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ +const RA1: f64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ +const RA2: f64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ +const RA3: f64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */ +const RA4: f64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */ +const RA5: f64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */ +const RA6: f64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */ +const RA7: f64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */ +const SA1: f64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */ +const SA2: f64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */ +const SA3: f64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */ +const SA4: f64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */ +const SA5: f64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ +const SA6: f64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ +const SA7: f64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ +const SA8: f64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +const RB0: f64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ +const RB1: f64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ +const RB2: f64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ +const RB3: f64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */ +const RB4: f64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */ +const RB5: f64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */ +const RB6: f64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */ +const SB1: f64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */ +const SB2: f64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */ +const SB3: f64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */ +const SB4: f64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ +const SB5: f64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ +const SB6: f64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ +const SB7: f64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +fn erfc1(x: f64) -> f64 { + let s: f64; + let p: f64; + let q: f64; + + s = fabs(x) - 1.0; + p = PA0+s*(PA1+s*(PA2+s*(PA3+s*(PA4+s*(PA5+s*PA6))))); + q = 1.0+s*(QA1+s*(QA2+s*(QA3+s*(QA4+s*(QA5+s*QA6))))); + + 1.0 - ERX - p/q +} + +fn erfc2(ix: u32, mut x: f64) -> f64 { + let s: f64; + let r: f64; + let big_s: f64; + let z: f64; + + if ix < 0x3ff40000 { /* |x| < 1.25 */ + return erfc1(x); + } + + x = fabs(x); + s = 1.0/(x*x); + if ix < 0x4006db6d { /* |x| < 1/.35 ~ 2.85714 */ + r = RA0+s*(RA1+s*(RA2+s*(RA3+s*(RA4+s*( + RA5+s*(RA6+s*RA7)))))); + big_s = 1.0+s*(SA1+s*(SA2+s*(SA3+s*(SA4+s*( + SA5+s*(SA6+s*(SA7+s*SA8))))))); + } else { /* |x| > 1/.35 */ + r = RB0+s*(RB1+s*(RB2+s*(RB3+s*(RB4+s*( + RB5+s*RB6))))); + big_s = 1.0+s*(SB1+s*(SB2+s*(SB3+s*(SB4+s*( + SB5+s*(SB6+s*SB7)))))); + } + z = with_set_low_word(x, 0); + + exp(-z*z-0.5625)*exp((z-x)*(z+x)+r/big_s)/x +} + +pub fn erf(x: f64) -> f64 { + let r: f64; + let s: f64; + let z: f64; + let y: f64; + let mut ix: u32; + let sign: usize; + + ix = get_high_word(x); + sign = (ix>>31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1.0-2.0*(sign as f64) + 1.0/x; + } + if ix < 0x3feb0000 { /* |x| < 0.84375 */ + if ix < 0x3e300000 { /* |x| < 2**-28 */ + /* avoid underflow */ + return 0.125*(8.0*x + EFX8*x); + } + z = x*x; + r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); + s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); + y = r/s; + return x + x*y; + } + if ix < 0x40180000 { /* 0.84375 <= |x| < 6 */ + y = 1.0 - erfc2(ix,x); + } else { + let x1p_1022 = f64::from_bits(0x0010000000000000); + y = 1.0 - x1p_1022; + } + + if sign != 0 { + -y + } else { + y + } +} + +pub fn erfc(x: f64) -> f64 { + let r: f64; + let s: f64; + let z: f64; + let y: f64; + let mut ix: u32; + let sign: usize; + + ix = get_high_word(x); + sign = (ix>>31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2.0*(sign as f64) + 1.0/x; + } + if ix < 0x3feb0000 { /* |x| < 0.84375 */ + if ix < 0x3c700000 { /* |x| < 2**-56 */ + return 1.0 - x; + } + z = x*x; + r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); + s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); + y = r/s; + if sign != 0 || ix < 0x3fd00000 { /* x < 1/4 */ + return 1.0 - (x+x*y); + } + return 0.5 - (x - 0.5 + x*y); + } + if ix < 0x403c0000 { /* 0.84375 <= |x| < 28 */ + if sign != 0 { + return 2.0 - erfc2(ix,x); + } else { + return erfc2(ix,x); + } + } + + let x1p_1022 = f64::from_bits(0x0010000000000000); + if sign != 0 { + 2.0 - x1p_1022 + } else { + x1p_1022*x1p_1022 + } +} diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs new file mode 100644 index 00000000000..0aaa89767ab --- /dev/null +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -0,0 +1,210 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{expf, fabsf}; + +const ERX: f32 = 8.4506291151e-01; /* 0x3f58560b */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +const EFX8: f32 = 1.0270333290e+00; /* 0x3f8375d4 */ +const PP0: f32 = 1.2837916613e-01; /* 0x3e0375d4 */ +const PP1: f32 = -3.2504209876e-01; /* 0xbea66beb */ +const PP2: f32 = -2.8481749818e-02; /* 0xbce9528f */ +const PP3: f32 = -5.7702702470e-03; /* 0xbbbd1489 */ +const PP4: f32 = -2.3763017452e-05; /* 0xb7c756b1 */ +const QQ1: f32 = 3.9791721106e-01; /* 0x3ecbbbce */ +const QQ2: f32 = 6.5022252500e-02; /* 0x3d852a63 */ +const QQ3: f32 = 5.0813062117e-03; /* 0x3ba68116 */ +const QQ4: f32 = 1.3249473704e-04; /* 0x390aee49 */ +const QQ5: f32 = -3.9602282413e-06; /* 0xb684e21a */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +const PA0: f32 = -2.3621185683e-03; /* 0xbb1acdc6 */ +const PA1: f32 = 4.1485610604e-01; /* 0x3ed46805 */ +const PA2: f32 = -3.7220788002e-01; /* 0xbebe9208 */ +const PA3: f32 = 3.1834661961e-01; /* 0x3ea2fe54 */ +const PA4: f32 = -1.1089469492e-01; /* 0xbde31cc2 */ +const PA5: f32 = 3.5478305072e-02; /* 0x3d1151b3 */ +const PA6: f32 = -2.1663755178e-03; /* 0xbb0df9c0 */ +const QA1: f32 = 1.0642088205e-01; /* 0x3dd9f331 */ +const QA2: f32 = 5.4039794207e-01; /* 0x3f0a5785 */ +const QA3: f32 = 7.1828655899e-02; /* 0x3d931ae7 */ +const QA4: f32 = 1.2617121637e-01; /* 0x3e013307 */ +const QA5: f32 = 1.3637083583e-02; /* 0x3c5f6e13 */ +const QA6: f32 = 1.1984500103e-02; /* 0x3c445aa3 */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +const RA0: f32 = -9.8649440333e-03; /* 0xbc21a093 */ +const RA1: f32 = -6.9385856390e-01; /* 0xbf31a0b7 */ +const RA2: f32 = -1.0558626175e+01; /* 0xc128f022 */ +const RA3: f32 = -6.2375331879e+01; /* 0xc2798057 */ +const RA4: f32 = -1.6239666748e+02; /* 0xc322658c */ +const RA5: f32 = -1.8460508728e+02; /* 0xc3389ae7 */ +const RA6: f32 = -8.1287437439e+01; /* 0xc2a2932b */ +const RA7: f32 = -9.8143291473e+00; /* 0xc11d077e */ +const SA1: f32 = 1.9651271820e+01; /* 0x419d35ce */ +const SA2: f32 = 1.3765776062e+02; /* 0x4309a863 */ +const SA3: f32 = 4.3456588745e+02; /* 0x43d9486f */ +const SA4: f32 = 6.4538726807e+02; /* 0x442158c9 */ +const SA5: f32 = 4.2900814819e+02; /* 0x43d6810b */ +const SA6: f32 = 1.0863500214e+02; /* 0x42d9451f */ +const SA7: f32 = 6.5702495575e+00; /* 0x40d23f7c */ +const SA8: f32 = -6.0424413532e-02; /* 0xbd777f97 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +const RB0: f32 = -9.8649431020e-03; /* 0xbc21a092 */ +const RB1: f32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ +const RB2: f32 = -1.7757955551e+01; /* 0xc18e104b */ +const RB3: f32 = -1.6063638306e+02; /* 0xc320a2ea */ +const RB4: f32 = -6.3756646729e+02; /* 0xc41f6441 */ +const RB5: f32 = -1.0250950928e+03; /* 0xc480230b */ +const RB6: f32 = -4.8351919556e+02; /* 0xc3f1c275 */ +const SB1: f32 = 3.0338060379e+01; /* 0x41f2b459 */ +const SB2: f32 = 3.2579251099e+02; /* 0x43a2e571 */ +const SB3: f32 = 1.5367296143e+03; /* 0x44c01759 */ +const SB4: f32 = 3.1998581543e+03; /* 0x4547fdbb */ +const SB5: f32 = 2.5530502930e+03; /* 0x451f90ce */ +const SB6: f32 = 4.7452853394e+02; /* 0x43ed43a7 */ +const SB7: f32 = -2.2440952301e+01; /* 0xc1b38712 */ + +fn erfc1(x: f32) -> f32 { + let s: f32; + let p: f32; + let q: f32; + + s = fabsf(x) - 1.0; + p = PA0+s*(PA1+s*(PA2+s*(PA3+s*(PA4+s*(PA5+s*PA6))))); + q = 1.0+s*(QA1+s*(QA2+s*(QA3+s*(QA4+s*(QA5+s*QA6))))); + return 1.0 - ERX - p/q; +} + +fn erfc2(mut ix: u32, mut x: f32) -> f32 { + let s: f32; + let r: f32; + let big_s: f32; + let z: f32; + + if ix < 0x3fa00000 { /* |x| < 1.25 */ + return erfc1(x); + } + + x = fabsf(x); + s = 1.0/(x*x); + if ix < 0x4036db6d { /* |x| < 1/0.35 */ + r = RA0+s*(RA1+s*(RA2+s*(RA3+s*(RA4+s*( + RA5+s*(RA6+s*RA7)))))); + big_s = 1.0+s*(SA1+s*(SA2+s*(SA3+s*(SA4+s*( + SA5+s*(SA6+s*(SA7+s*SA8))))))); + } else { /* |x| >= 1/0.35 */ + r = RB0+s*(RB1+s*(RB2+s*(RB3+s*(RB4+s*( + RB5+s*RB6))))); + big_s = 1.0+s*(SB1+s*(SB2+s*(SB3+s*(SB4+s*( + SB5+s*(SB6+s*SB7)))))); + } + ix = x.to_bits(); + z = f32::from_bits(ix&0xffffe000); + + expf(-z*z - 0.5625) * expf((z-x)*(z+x) + r/big_s)/x +} + +pub fn erff(x: f32) -> f32 +{ + let r: f32; + let s: f32; + let z: f32; + let y: f32; + let mut ix: u32; + let sign: usize; + + ix = x.to_bits(); + sign = (ix>>31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1.0-2.0*(sign as f32) + 1.0/x; + } + if ix < 0x3f580000 { /* |x| < 0.84375 */ + if ix < 0x31800000 { /* |x| < 2**-28 */ + /*avoid underflow */ + return 0.125*(8.0*x + EFX8*x); + } + z = x*x; + r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); + s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); + y = r/s; + return x + x*y; + } + if ix < 0x40c00000 { /* |x| < 6 */ + y = 1.0 - erfc2(ix,x); + } else { + let x1p_120 = f32::from_bits(0x03800000); + y = 1.0 - x1p_120; + } + + if sign != 0 { + -y + } else { + y + } +} + +pub fn erfcf(x: f32) -> f32 { + let r: f32; + let s: f32; + let z: f32; + let y: f32; + let mut ix: u32; + let sign: usize; + + ix = x.to_bits(); + sign = (ix>>31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2.0*(sign as f32) + 1.0/x; + } + + if ix < 0x3f580000 { /* |x| < 0.84375 */ + if ix < 0x23800000 { /* |x| < 2**-56 */ + return 1.0 - x; + } + z = x*x; + r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); + s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); + y = r/s; + if sign != 0 || ix < 0x3e800000 { /* x < 1/4 */ + return 1.0 - (x+x*y); + } + return 0.5 - (x - 0.5 + x*y); + } + if ix < 0x41e00000 { /* |x| < 28 */ + if sign != 0 { + return 2.0 - erfc2(ix, x); + } else { + return erfc2(ix, x); + } + } + + let x1p_120 = f32::from_bits(0x03800000); + if sign != 0 { + 2.0 - x1p_120 + } else { + x1p_120*x1p_120 + } +} diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs new file mode 100644 index 00000000000..d12fa0be31e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp10.rs @@ -0,0 +1,24 @@ +use super::{exp2, modf, pow}; + +const LN10: f64 = 3.32192809488736234787031942948939; +const P10: &[f64] = &[ + 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, + 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15 +]; + +pub fn exp10(x: f64) -> f64 +{ + let (mut y, n) = modf(x); + let u: u64 = n.to_bits(); + /* fabs(n) < 16 without raising invalid on nan */ + if (u>>52 & 0x7ff) < 0x3ff+4 { + if y == 0.0 { + return P10[((n as isize) + 15) as usize]; + } + y = exp2(LN10 * y); + return y * P10[((n as isize) + 15) as usize]; + } + return pow(10.0, x); +} diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs new file mode 100644 index 00000000000..8fb88a52c01 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -0,0 +1,22 @@ +use super::{exp2, exp2f, modff}; + +const LN10_F32: f32 = 3.32192809488736234787031942948939; +const LN10_F64: f64 = 3.32192809488736234787031942948939; +const P10: &[f32] = &[ + 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 +]; + +pub fn exp10f(x: f32) -> f32 { + let (mut y, n) = modff(x); + let u = n.to_bits(); + /* fabsf(n) < 8 without raising invalid on nan */ + if (u>>23 & 0xff) < 0x7f+3 { + if y == 0.0 { + return P10[((n as isize) + 7) as usize] + } + y = exp2f(LN10_F32 * y); + return y * P10[((n as isize) + 7) as usize]; + } + return exp2(LN10_F64 * (x as f64)) as f32; +} diff --git a/library/compiler-builtins/libm/src/math/frexp.rs b/library/compiler-builtins/libm/src/math/frexp.rs new file mode 100644 index 00000000000..45733a3aaa3 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/frexp.rs @@ -0,0 +1,20 @@ +pub fn frexp(x: f64) -> (f64, isize) { + let mut y = x.to_bits(); + let ee = ((y>>52) & 0x7ff) as isize; + + if ee == 0 { + if x != 0.0 { + let x1p64 = f64::from_bits(0x43f0000000000000); + let (x, e) = frexp(x*x1p64); + return (x, e - 64); + } + return (x, 0); + } else if ee == 0x7ff { + return (x, 0); + } + + let e = ee - 0x3fe; + y &= 0x800fffffffffffff; + y |= 0x3fe0000000000000; + return (f64::from_bits(y), e); +} diff --git a/library/compiler-builtins/libm/src/math/frexpf.rs b/library/compiler-builtins/libm/src/math/frexpf.rs new file mode 100644 index 00000000000..1c9dae0bb98 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/frexpf.rs @@ -0,0 +1,21 @@ +pub fn frexpf(x: f32) -> (f32, isize) { + let mut y = x.to_bits(); + let ee: isize = ((y>>23) & 0xff) as isize; + + if ee == 0 { + if x != 0.0 { + let x1p64 = f32::from_bits(0x5f800000); + let (x, e) = frexpf(x*x1p64); + return (x, e - 64); + } else { + return (x, 0); + } + } else if ee == 0xff { + return (x, 0); + } + + let e = ee - 0x7e; + y &= 0x807fffff; + y |= 0x3f000000; + return (f32::from_bits(y), e); +} diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs new file mode 100644 index 00000000000..78fe030a1cc --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -0,0 +1,31 @@ +const FP_ILOGBNAN: isize = -1 - (((!0) >> 1)); +const FP_ILOGB0: isize = FP_ILOGBNAN; + +pub fn ilogb(x: f64) -> isize { + let mut i: u64 = x.to_bits(); + let e = ((i>>52) & 0x7ff) as isize; + + if e == 0 { + i <<= 12; + if i == 0 { + force_eval!(0.0/0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -0x3ff; + while (i>>63) == 0 { + e -= 1; + i <<= 1; + } + return e; + } + if e == 0x7ff { + force_eval!(0.0/0.0); + if (i<<12) != 0 { + return FP_ILOGBNAN; + } else { + return isize::max_value(); + } + } + return e - 0x3ff; +} diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs new file mode 100644 index 00000000000..9ca1c360665 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ilogbf.rs @@ -0,0 +1,31 @@ +const FP_ILOGBNAN: isize = -1 - (((!0) >> 1)); +const FP_ILOGB0: isize = FP_ILOGBNAN; + +pub fn ilogbf(x: f32) -> isize { + let mut i = x.to_bits(); + let e = ((i>>23) & 0xff) as isize; + + if e == 0 { + i <<= 9; + if i == 0 { + force_eval!(0.0/0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -0x7f; + while (i>>31) == 0 { + e -= 1; + i <<= 1; + } + return e; + } + if e == 0xff { + force_eval!(0.0/0.0); + if (i<<9) != 0 { + return FP_ILOGBNAN; + } else { + return isize::max_value(); + } + } + return e - 0x7f; +} diff --git a/library/compiler-builtins/libm/src/math/j0.rs b/library/compiler-builtins/libm/src/math/j0.rs new file mode 100644 index 00000000000..02625b086db --- /dev/null +++ b/library/compiler-builtins/libm/src/math/j0.rs @@ -0,0 +1,392 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j0(x), y0(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j0(x): + * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... + * 2. Reduce x to |x| since j0(x)=j0(-x), and + * for x in (0,2) + * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; + * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) + * for x in (2,inf) + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * as follow: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (cos(x) + sin(x)) + * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j0(nan)= nan + * j0(0) = 1 + * j0(inf) = 0 + * + * Method -- y0(x): + * 1. For x<2. + * Since + * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) + * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. + * We use the following function to approximate y0, + * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 + * where + * U(z) = u00 + u01*z + ... + u06*z^6 + * V(z) = 1 + v01*z + ... + v04*z^4 + * with absolute approximation error bounded by 2**-72. + * Note: For tiny x, U/V = u0 and j0(x)~1, hence + * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) + * 2. For x>=2. + * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * by the method mentioned above. + * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. + */ + +use super::{cos, get_low_word, get_high_word, fabs, log, sin, sqrt}; +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +/* common method when |x|>=2 */ +fn common(ix: u32, x: f64, y0: bool) -> f64 { + let s: f64; + let mut c: f64; + let mut ss: f64; + let mut cc: f64; + let z: f64; + + /* + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) + * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) + * + * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) + * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + c = cos(x); + if y0 { + c = -c; + } + cc = s+c; + /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ + if ix < 0x7fe00000 { + ss = s-c; + z = -cos(2.0*x); + if s*c < 0.0 { + cc = z/ss; + } else { + ss = z/cc; + } + if ix < 0x48000000 { + if y0 { + ss = -ss; + } + cc = pzero(x)*cc-qzero(x)*ss; + } + } + return INVSQRTPI*cc/sqrt(x); +} + +/* R0/S0 on [0, 2.00] */ +const R02: f64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ +const R03: f64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ +const R04: f64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ +const R05: f64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */ +const S01: f64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ +const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ +const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ +const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ + +pub fn j0(mut x: f64) -> f64 +{ + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + + /* j0(+-inf)=0, j0(nan)=nan */ + if ix >= 0x7ff00000 { + return 1.0/(x*x); + } + x = fabs(x); + + if ix >= 0x40000000 { /* |x| >= 2 */ + /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ + return common(ix,x,false); + } + + /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ + if ix >= 0x3f200000 { /* |x| >= 2**-13 */ + /* up to 4ulp error close to 2 */ + z = x*x; + r = z*(R02+z*(R03+z*(R04+z*R05))); + s = 1.0+z*(S01+z*(S02+z*(S03+z*S04))); + return (1.0+x/2.0)*(1.0-x/2.0) + z*(r/s); + } + + /* 1 - x*x/4 */ + /* prevent underflow */ + /* inexact should be raised when x!=0, this is not done correctly */ + if ix >= 0x38000000 { /* |x| >= 2**-127 */ + x = 0.25*x*x; + } + return 1.0 - x; +} + +const U00: f64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ +const U01: f64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ +const U02: f64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ +const U03: f64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */ +const U04: f64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */ +const U05: f64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */ +const U06: f64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */ +const V01: f64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ +const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ +const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ +const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ + +pub fn y0(x: f64) -> f64 +{ + let z: f64; + let u: f64; + let v: f64; + let ix: u32; + let lx: u32; + + ix = get_high_word(x); + lx = get_low_word(x); + + /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ + if ((ix<<1) | lx) == 0 { + return -1.0/0.0; + } + if (ix>>31) != 0 { + return 0.0/0.0; + } + if ix >= 0x7ff00000 { + return 1.0/x; + } + + if ix >= 0x40000000 { /* x >= 2 */ + /* large ulp errors near zeros: 3.958, 7.086,.. */ + return common(ix,x,true); + } + + /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ + if ix >= 0x3e400000 { /* x >= 2**-27 */ + /* large ulp error near the first zero, x ~= 0.89 */ + z = x*x; + u = U00+z*(U01+z*(U02+z*(U03+z*(U04+z*(U05+z*U06))))); + v = 1.0+z*(V01+z*(V02+z*(V03+z*V04))); + return u/v + TPI*(j0(x)*log(x)); + } + return U00 + TPI*log(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +const PR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ + -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ + -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ + -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ + -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ +]; +const PS8: [f64; 5] = [ + 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ + 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ + 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ + 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ + 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ +]; + +const PR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ + -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ + -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ + -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ + -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ + -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ +]; +const PS5: [f64; 5] = [ + 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ + 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ + 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ + 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ + 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ +]; + +const PR3: [f64; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ + -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ + -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ + -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ + -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ + -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ +]; +const PS3: [f64; 5] = [ + 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ + 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ + 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ + 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ + 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ +]; + +const PR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ + -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ + -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ + -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ + -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ + -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ +]; +const PS2: [f64; 5] = [ + 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ + 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ + 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ + 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ + 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ +]; + +fn pzero(x: f64) -> f64 +{ + let p: &[f64; 6]; + let q: &[f64; 5]; + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 {p = &PR8; q = &PS8;} + else if ix >= 0x40122E8B {p = &PR5; q = &PS5;} + else if ix >= 0x4006DB6D {p = &PR3; q = &PS3;} + else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0 + r/s; +} + + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +const QR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ + 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ + 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ + 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ + 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ +]; +const QS8: [f64; 6] = [ + 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ + 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ + 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ + 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ + 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ + -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ +]; + +const QR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ + 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ + 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ + 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ + 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ + 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ +]; +const QS5: [f64; 6] = [ + 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ + 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ + 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ + 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ + 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ + -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ +]; + +const QR3: [f64; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ + 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ + 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ + 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ + 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ + 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ +]; +const QS3: [f64; 6] = [ + 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ + 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ + 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ + 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ + 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ + -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ +]; + +const QR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ + 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ + 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ + 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ + 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ + 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ +]; +const QS2: [f64; 6] = [ + 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ + 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ + 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ + 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ + 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ + -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ +]; + +fn qzero(x: f64) -> f64 +{ + let p: &[f64; 6]; + let q: &[f64; 6]; + let s: f64; + let r: f64; + let z: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 {p = &QR8; q = &QS8;} + else if ix >= 0x40122E8B {p = &QR5; q = &QS5;} + else if ix >= 0x4006DB6D {p = &QR3; q = &QS3;} + else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (-0.125 + r/s)/x; +} diff --git a/library/compiler-builtins/libm/src/math/j0f.rs b/library/compiler-builtins/libm/src/math/j0f.rs new file mode 100644 index 00000000000..e2faed0b256 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/j0f.rs @@ -0,0 +1,330 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{cosf, fabsf, logf, sinf, sqrtf}; + +const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ + +fn common(ix: u32, x: f32, y0: bool) -> f32 +{ + let z: f32; + let s: f32; + let mut c: f32; + let mut ss: f32; + let mut cc: f32; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + s = sinf(x); + c = cosf(x); + if y0 { + c = -c; + } + cc = s+c; + if ix < 0x7f000000 { + ss = s-c; + z = -cosf(2.0*x); + if s*c < 0.0 { + cc = z/ss; + } else { + ss = z/cc; + } + if ix < 0x58800000 { + if y0 { + ss = -ss; + } + cc = pzerof(x)*cc-qzerof(x)*ss; + } + } + return INVSQRTPI*cc/sqrtf(x); +} + +/* R0/S0 on [0, 2.00] */ +const R02: f32 = 1.5625000000e-02; /* 0x3c800000 */ +const R03: f32 = -1.8997929874e-04; /* 0xb947352e */ +const R04: f32 = 1.8295404516e-06; /* 0x35f58e88 */ +const R05: f32 = -4.6183270541e-09; /* 0xb19eaf3c */ +const S01: f32 = 1.5619102865e-02; /* 0x3c7fe744 */ +const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ +const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ +const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ + +pub fn j0f(mut x: f32) -> f32 +{ + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + return 1.0/(x*x); + } + x = fabsf(x); + + if ix >= 0x40000000 { /* |x| >= 2 */ + /* large ulp error near zeros */ + return common(ix, x, false); + } + if ix >= 0x3a000000 { /* |x| >= 2**-11 */ + /* up to 4ulp error near 2 */ + z = x*x; + r = z*(R02+z*(R03+z*(R04+z*R05))); + s = 1.0+z*(S01+z*(S02+z*(S03+z*S04))); + return (1.0+x/2.0)*(1.0-x/2.0) + z*(r/s); + } + if ix >= 0x21800000 { /* |x| >= 2**-60 */ + x = 0.25*x*x; + } + return 1.0 - x; +} + +const U00: f32 = -7.3804296553e-02; /* 0xbd9726b5 */ +const U01: f32 = 1.7666645348e-01; /* 0x3e34e80d */ +const U02: f32 = -1.3818567619e-02; /* 0xbc626746 */ +const U03: f32 = 3.4745343146e-04; /* 0x39b62a69 */ +const U04: f32 = -3.8140706238e-06; /* 0xb67ff53c */ +const U05: f32 = 1.9559013964e-08; /* 0x32a802ba */ +const U06: f32 = -3.9820518410e-11; /* 0xae2f21eb */ +const V01: f32 = 1.2730483897e-02; /* 0x3c509385 */ +const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ +const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ +const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ + +pub fn y0f(x: f32) -> f32 +{ + let z: f32; + let u: f32; + let v: f32; + let ix: u32; + + ix = x.to_bits(); + if (ix & 0x7fffffff) == 0 { + return -1.0/0.0; + } + if (ix>>31) !=0 { + return 0.0/0.0; + } + if ix >= 0x7f800000 { + return 1.0/x; + } + if ix >= 0x40000000 { /* |x| >= 2.0 */ + /* large ulp error near zeros */ + return common(ix,x,true); + } + if ix >= 0x39000000 { /* x >= 2**-13 */ + /* large ulp error at x ~= 0.89 */ + z = x*x; + u = U00+z*(U01+z*(U02+z*(U03+z*(U04+z*(U05+z*U06))))); + v = 1.0+z*(V01+z*(V02+z*(V03+z*V04))); + return u/v + TPI*(j0f(x)*logf(x)); + } + return U00 + TPI*logf(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +const PR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -7.0312500000e-02, /* 0xbd900000 */ + -8.0816707611e+00, /* 0xc1014e86 */ + -2.5706311035e+02, /* 0xc3808814 */ + -2.4852163086e+03, /* 0xc51b5376 */ + -5.2530439453e+03, /* 0xc5a4285a */ +]; +const PS8: [f32; 5] = [ + 1.1653436279e+02, /* 0x42e91198 */ + 3.8337448730e+03, /* 0x456f9beb */ + 4.0597855469e+04, /* 0x471e95db */ + 1.1675296875e+05, /* 0x47e4087c */ + 4.7627726562e+04, /* 0x473a0bba */ +]; +const PR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.1412546255e-11, /* 0xad48c58a */ + -7.0312492549e-02, /* 0xbd8fffff */ + -4.1596107483e+00, /* 0xc0851b88 */ + -6.7674766541e+01, /* 0xc287597b */ + -3.3123129272e+02, /* 0xc3a59d9b */ + -3.4643338013e+02, /* 0xc3ad3779 */ +]; +const PS5: [f32; 5] = [ + 6.0753936768e+01, /* 0x42730408 */ + 1.0512523193e+03, /* 0x44836813 */ + 5.9789707031e+03, /* 0x45bad7c4 */ + 9.6254453125e+03, /* 0x461665c8 */ + 2.4060581055e+03, /* 0x451660ee */ +]; + +const PR3: [f32; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.5470459075e-09, /* 0xb12f081b */ + -7.0311963558e-02, /* 0xbd8fffb8 */ + -2.4090321064e+00, /* 0xc01a2d95 */ + -2.1965976715e+01, /* 0xc1afba52 */ + -5.8079170227e+01, /* 0xc2685112 */ + -3.1447946548e+01, /* 0xc1fb9565 */ +]; +const PS3: [f32; 5] = [ + 3.5856033325e+01, /* 0x420f6c94 */ + 3.6151397705e+02, /* 0x43b4c1ca */ + 1.1936077881e+03, /* 0x44953373 */ + 1.1279968262e+03, /* 0x448cffe6 */ + 1.7358093262e+02, /* 0x432d94b8 */ +]; + +const PR2: [f32; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.8753431271e-08, /* 0xb3be98b7 */ + -7.0303097367e-02, /* 0xbd8ffb12 */ + -1.4507384300e+00, /* 0xbfb9b1cc */ + -7.6356959343e+00, /* 0xc0f4579f */ + -1.1193166733e+01, /* 0xc1331736 */ + -3.2336456776e+00, /* 0xc04ef40d */ +]; +const PS2: [f32; 5] = [ + 2.2220300674e+01, /* 0x41b1c32d */ + 1.3620678711e+02, /* 0x430834f0 */ + 2.7047027588e+02, /* 0x43873c32 */ + 1.5387539673e+02, /* 0x4319e01a */ + 1.4657617569e+01, /* 0x416a859a */ +]; + +fn pzerof(x: f32) -> f32 +{ + let p: &[f32; 6]; + let q: &[f32; 5]; + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 {p = &PR8; q = &PS8;} + else if ix >= 0x409173eb {p = &PR5; q = &PS5;} + else if ix >= 0x4036d917 {p = &PR3; q = &PS3;} + else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0 + r/s; +} + + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +const QR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 7.3242187500e-02, /* 0x3d960000 */ + 1.1768206596e+01, /* 0x413c4a93 */ + 5.5767340088e+02, /* 0x440b6b19 */ + 8.8591972656e+03, /* 0x460a6cca */ + 3.7014625000e+04, /* 0x471096a0 */ +]; +const QS8: [f32; 6] = [ + 1.6377603149e+02, /* 0x4323c6aa */ + 8.0983447266e+03, /* 0x45fd12c2 */ + 1.4253829688e+05, /* 0x480b3293 */ + 8.0330925000e+05, /* 0x49441ed4 */ + 8.4050156250e+05, /* 0x494d3359 */ + -3.4389928125e+05, /* 0xc8a7eb69 */ +]; + +const QR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.8408595828e-11, /* 0x2da1ec79 */ + 7.3242180049e-02, /* 0x3d95ffff */ + 5.8356351852e+00, /* 0x40babd86 */ + 1.3511157227e+02, /* 0x43071c90 */ + 1.0272437744e+03, /* 0x448067cd */ + 1.9899779053e+03, /* 0x44f8bf4b */ +]; +const QS5: [f32; 6] = [ + 8.2776611328e+01, /* 0x42a58da0 */ + 2.0778142090e+03, /* 0x4501dd07 */ + 1.8847289062e+04, /* 0x46933e94 */ + 5.6751113281e+04, /* 0x475daf1d */ + 3.5976753906e+04, /* 0x470c88c1 */ + -5.3543427734e+03, /* 0xc5a752be */ +]; + +const QR3: [f32; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.3774099900e-09, /* 0x3196681b */ + 7.3241114616e-02, /* 0x3d95ff70 */ + 3.3442313671e+00, /* 0x405607e3 */ + 4.2621845245e+01, /* 0x422a7cc5 */ + 1.7080809021e+02, /* 0x432acedf */ + 1.6673394775e+02, /* 0x4326bbe4 */ +]; +const QS3: [f32; 6] = [ + 4.8758872986e+01, /* 0x42430916 */ + 7.0968920898e+02, /* 0x44316c1c */ + 3.7041481934e+03, /* 0x4567825f */ + 6.4604252930e+03, /* 0x45c9e367 */ + 2.5163337402e+03, /* 0x451d4557 */ + -1.4924745178e+02, /* 0xc3153f59 */ +]; + +const QR2: [f32; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.5044444979e-07, /* 0x342189db */ + 7.3223426938e-02, /* 0x3d95f62a */ + 1.9981917143e+00, /* 0x3fffc4bf */ + 1.4495602608e+01, /* 0x4167edfd */ + 3.1666231155e+01, /* 0x41fd5471 */ + 1.6252708435e+01, /* 0x4182058c */ +]; +const QS2: [f32; 6] = [ + 3.0365585327e+01, /* 0x41f2ecb8 */ + 2.6934811401e+02, /* 0x4386ac8f */ + 8.4478375244e+02, /* 0x44533229 */ + 8.8293585205e+02, /* 0x445cbbe5 */ + 2.1266638184e+02, /* 0x4354aa98 */ + -5.3109550476e+00, /* 0xc0a9f358 */ +]; + +fn qzerof(x: f32) -> f32 +{ + let p: &[f32; 6]; + let q: &[f32; 6]; + let s: f32; + let r: f32; + let z: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 {p = &QR8; q = &QS8;} + else if ix >= 0x409173eb {p = &QR5; q = &QS5;} + else if ix >= 0x4036d917 {p = &QR3; q = &QS3;} + else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (-0.125 + r/s)/x; +} diff --git a/library/compiler-builtins/libm/src/math/j1.rs b/library/compiler-builtins/libm/src/math/j1.rs new file mode 100644 index 00000000000..92289a61320 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/j1.rs @@ -0,0 +1,387 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j1(x), y1(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j1(x): + * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... + * 2. Reduce x to |x| since j1(x)=-j1(-x), and + * for x in (0,2) + * j1(x) = x/2 + x*z*R0/S0, where z = x*x; + * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) + * for x in (2,inf) + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * as follow: + * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (sin(x) + cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j1(nan)= nan + * j1(0) = 0 + * j1(inf) = 0 + * + * Method -- y1(x): + * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN + * 2. For x<2. + * Since + * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) + * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. + * We use the following function to approximate y1, + * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 + * where for x in [0,2] (abs err less than 2**-65.89) + * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 + * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 + * Note: For tiny x, 1/x dominate y1 and hence + * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) + * 3. For x>=2. + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * by method mentioned above. + */ + +use super::{cos, get_high_word, get_low_word, fabs, log, sin, sqrt}; + +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +fn common(ix: u32, x: f64, y1: bool, sign: bool) -> f64 +{ + let z: f64; + let mut s: f64; + let c: f64; + let mut ss: f64; + let mut cc: f64; + + /* + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) + * + * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) + * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + if y1 { + s = -s; + } + c = cos(x); + cc = s-c; + if ix < 0x7fe00000 { + /* avoid overflow in 2*x */ + ss = -s-c; + z = cos(2.0*x); + if s*c > 0.0 { + cc = z/ss; + } else { + ss = z/cc; + } + if ix < 0x48000000 { + if y1 { + ss = -ss; + } + cc = pone(x)*cc-qone(x)*ss; + } + } + if sign { + cc = -cc; + } + return INVSQRTPI*cc/sqrt(x); +} + +/* R0/S0 on [0,2] */ +const R00: f64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ +const R01: f64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ +const R02: f64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ +const R03: f64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ +const S01: f64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ +const S02: f64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ +const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ +const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ +const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ + +pub fn j1(x: f64) -> f64 +{ + let mut z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + let sign: bool; + + ix = get_high_word(x); + sign = (ix>>31) != 0; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + return 1.0/(x*x); + } + if ix >= 0x40000000 { /* |x| >= 2 */ + return common(ix, fabs(x), false, sign); + } + if ix >= 0x38000000 { /* |x| >= 2**-127 */ + z = x*x; + r = z*(R00+z*(R01+z*(R02+z*R03))); + s = 1.0+z*(S01+z*(S02+z*(S03+z*(S04+z*S05)))); + z = r/s; + } else { + /* avoid underflow, raise inexact if x!=0 */ + z = x; + } + return (0.5 + z)*x; +} + +const U0: [f64; 5] = [ + -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ + 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ + 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ +]; +const V0: [f64; 5] = [ + 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ + 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ +]; + +pub fn y1(x: f64) -> f64 +{ + let z: f64; + let u: f64; + let v: f64; + let ix: u32; + let lx: u32; + + ix = get_high_word(x); + lx = get_low_word(x); + + /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ + if (ix<<1 | lx) == 0 { + return -1.0/0.0; + } + if (ix>>31) != 0 { + return 0.0/0.0; + } + if ix >= 0x7ff00000 { + return 1.0/x; + } + + if ix >= 0x40000000 { /* x >= 2 */ + return common(ix, x, true, false); + } + if ix < 0x3c900000 { /* x < 2**-54 */ + return -TPI/x; + } + z = x*x; + u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); + v = 1.0+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); + return x*(u/v) + TPI*(j1(x)*log(x)-1.0/x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +const PR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ + 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ + 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ + 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ +]; +const PS8: [f64; 5] = [ + 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ + 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ + 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ + 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ + 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ +]; + +const PR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ + 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ + 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ + 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ +]; +const PS5: [f64; 5] = [ + 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ + 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ + 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ + 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ +]; + +const PR3: [f64; 6] = [ + 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ + 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ + 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ + 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ +]; +const PS3: [f64; 5] = [ + 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ + 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ + 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ + 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ + 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ +]; + +const PR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ + 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ + 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ + 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ +]; +const PS2: [f64; 5] = [ + 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ + 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ + 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ + 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ +]; + +fn pone(x: f64) -> f64 +{ + let p: &[f64; 6]; + let q: &[f64; 5]; + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 {p = &PR8; q = &PS8;} + else if ix >= 0x40122E8B {p = &PR5; q = &PS5;} + else if ix >= 0x4006DB6D {p = &PR3; q = &PS3;} + else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0+ r/s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +const QR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ + -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ + -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ + -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ + -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ +]; +const QS8: [f64; 6] = [ + 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ + 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ + 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ + 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ + 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ + -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ +]; + +const QR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ + -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ + -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ + -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ + -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ + -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ +]; +const QS5: [f64; 6] = [ + 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ + 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ + 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ + 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ + 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ + -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ +]; + +const QR3: [f64; 6] = [ + -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ + -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ + -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ + -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ + -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ + -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ +]; +const QS3: [f64; 6] = [ + 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ + 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ + 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ + 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ + 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ + -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ +]; + +const QR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ + -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ + -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ + -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ + -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ + -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ +]; +const QS2: [f64; 6] = [ + 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ + 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ + 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ + 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ + 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ + -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ +]; + +fn qone(x: f64) -> f64 +{ + let p: &[f64; 6]; + let q: &[f64; 6]; + let s: f64; + let r: f64; + let z: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 {p = &QR8; q = &QS8;} + else if ix >= 0x40122E8B {p = &QR5; q = &QS5;} + else if ix >= 0x4006DB6D {p = &QR3; q = &QS3;} + else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (0.375 + r/s)/x; +} diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs new file mode 100644 index 00000000000..7cf9c45b98e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -0,0 +1,331 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{cosf, fabsf, logf, sinf, sqrtf}; + +const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ + +fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 +{ + let z: f64; + let mut s: f64; + let c: f64; + let mut ss: f64; + let mut cc: f64; + + s = sinf(x) as f64; + if y1 { + s = -s; + } + c = cosf(x) as f64; + cc = s-c; + if ix < 0x7f000000 { + ss = -s-c; + z = cosf(2.0*x) as f64; + if s*c > 0.0 { + cc = z/ss; + } else { + ss = z/cc; + } + if ix < 0x58800000 { + if y1 { + ss = -ss; + } + cc = (ponef(x) as f64)*cc-(qonef(x) as f64)*ss; + } + } + if sign { + cc = -cc; + } + return INVSQRTPI*(cc as f32)/sqrtf(x); +} + +/* R0/S0 on [0,2] */ +const R00: f32 = -6.2500000000e-02; /* 0xbd800000 */ +const R01: f32 = 1.4070566976e-03; /* 0x3ab86cfd */ +const R02: f32 = -1.5995563444e-05; /* 0xb7862e36 */ +const R03: f32 = 4.9672799207e-08; /* 0x335557d2 */ +const S01: f32 = 1.9153760746e-02; /* 0x3c9ce859 */ +const S02: f32 = 1.8594678841e-04; /* 0x3942fab6 */ +const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ +const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ +const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ + +pub fn j1f(x: f32) -> f32 +{ + let mut z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + let sign: bool; + + ix = x.to_bits(); + sign = (ix>>31) != 0; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + return 1.0/(x*x); + } + if ix >= 0x40000000 { /* |x| >= 2 */ + return common(ix, fabsf(x), false, sign); + } + if ix >= 0x39000000 { /* |x| >= 2**-13 */ + z = x*x; + r = z*(R00+z*(R01+z*(R02+z*R03))); + s = 1.0+z*(S01+z*(S02+z*(S03+z*(S04+z*S05)))); + z = 0.5 + r/s; + } else { + z = 0.5; + } + return z*x; +} + +const U0: [f32; 5] = [ + -1.9605709612e-01, /* 0xbe48c331 */ + 5.0443872809e-02, /* 0x3d4e9e3c */ + -1.9125689287e-03, /* 0xbafaaf2a */ + 2.3525259166e-05, /* 0x37c5581c */ + -9.1909917899e-08, /* 0xb3c56003 */ +]; +const V0: [f32; 5] = [ + 1.9916731864e-02, /* 0x3ca3286a */ + 2.0255257550e-04, /* 0x3954644b */ + 1.3560879779e-06, /* 0x35b602d4 */ + 6.2274145840e-09, /* 0x31d5f8eb */ + 1.6655924903e-11, /* 0x2d9281cf */ +]; + +pub fn y1f(x: f32) -> f32 +{ + let z: f32; + let u: f32; + let v: f32; + let ix: u32; + + ix = x.to_bits(); + if (ix & 0x7fffffff) == 0 { + return -1.0/0.0; + } + if (ix>>31) != 0{ + return 0.0/0.0; + } + if ix >= 0x7f800000 { + return 1.0/x; + } + if ix >= 0x40000000 { /* |x| >= 2.0 */ + return common(ix,x,true,false); + } + if ix < 0x33000000 { /* x < 2**-25 */ + return -TPI/x; + } + z = x*x; + u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); + v = 1.0+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); + return x*(u/v) + TPI*(j1f(x)*logf(x)-1.0/x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +const PR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 1.1718750000e-01, /* 0x3df00000 */ + 1.3239480972e+01, /* 0x4153d4ea */ + 4.1205184937e+02, /* 0x43ce06a3 */ + 3.8747453613e+03, /* 0x45722bed */ + 7.9144794922e+03, /* 0x45f753d6 */ +]; +const PS8: [f32; 5] = [ + 1.1420736694e+02, /* 0x42e46a2c */ + 3.6509309082e+03, /* 0x45642ee5 */ + 3.6956207031e+04, /* 0x47105c35 */ + 9.7602796875e+04, /* 0x47bea166 */ + 3.0804271484e+04, /* 0x46f0a88b */ +]; + +const PR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.3199052094e-11, /* 0x2d68333f */ + 1.1718749255e-01, /* 0x3defffff */ + 6.8027510643e+00, /* 0x40d9b023 */ + 1.0830818176e+02, /* 0x42d89dca */ + 5.1763616943e+02, /* 0x440168b7 */ + 5.2871520996e+02, /* 0x44042dc6 */ +]; +const PS5: [f32; 5] = [ + 5.9280597687e+01, /* 0x426d1f55 */ + 9.9140142822e+02, /* 0x4477d9b1 */ + 5.3532670898e+03, /* 0x45a74a23 */ + 7.8446904297e+03, /* 0x45f52586 */ + 1.5040468750e+03, /* 0x44bc0180 */ +]; + +const PR3: [f32; 6] = [ + 3.0250391081e-09, /* 0x314fe10d */ + 1.1718686670e-01, /* 0x3defffab */ + 3.9329774380e+00, /* 0x407bb5e7 */ + 3.5119403839e+01, /* 0x420c7a45 */ + 9.1055007935e+01, /* 0x42b61c2a */ + 4.8559066772e+01, /* 0x42423c7c */ +]; +const PS3: [f32; 5] = [ + 3.4791309357e+01, /* 0x420b2a4d */ + 3.3676245117e+02, /* 0x43a86198 */ + 1.0468714600e+03, /* 0x4482dbe3 */ + 8.9081134033e+02, /* 0x445eb3ed */ + 1.0378793335e+02, /* 0x42cf936c */ +]; + +const PR2: [f32; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.0771083225e-07, /* 0x33e74ea8 */ + 1.1717621982e-01, /* 0x3deffa16 */ + 2.3685150146e+00, /* 0x401795c0 */ + 1.2242610931e+01, /* 0x4143e1bc */ + 1.7693971634e+01, /* 0x418d8d41 */ + 5.0735230446e+00, /* 0x40a25a4d */ +]; +const PS2: [f32; 5] = [ + 2.1436485291e+01, /* 0x41ab7dec */ + 1.2529022980e+02, /* 0x42fa9499 */ + 2.3227647400e+02, /* 0x436846c7 */ + 1.1767937469e+02, /* 0x42eb5bd7 */ + 8.3646392822e+00, /* 0x4105d590 */ +]; + +fn ponef(x: f32) -> f32 +{ + let p: &[f32; 6]; + let q: &[f32; 5]; + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 {p = &PR8; q = &PS8;} + else if ix >= 0x409173eb {p = &PR5; q = &PS5;} + else if ix >= 0x4036d917 {p = &PR3; q = &PS3;} + else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0 + r/s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +const QR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -1.0253906250e-01, /* 0xbdd20000 */ + -1.6271753311e+01, /* 0xc1822c8d */ + -7.5960174561e+02, /* 0xc43de683 */ + -1.1849806641e+04, /* 0xc639273a */ + -4.8438511719e+04, /* 0xc73d3683 */ +]; +const QS8: [f32; 6] = [ + 1.6139537048e+02, /* 0x43216537 */ + 7.8253862305e+03, /* 0x45f48b17 */ + 1.3387534375e+05, /* 0x4802bcd6 */ + 7.1965775000e+05, /* 0x492fb29c */ + 6.6660125000e+05, /* 0x4922be94 */ + -2.9449025000e+05, /* 0xc88fcb48 */ +]; + +const QR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.0897993405e-11, /* 0xadb7d219 */ + -1.0253904760e-01, /* 0xbdd1fffe */ + -8.0564479828e+00, /* 0xc100e736 */ + -1.8366960144e+02, /* 0xc337ab6b */ + -1.3731937256e+03, /* 0xc4aba633 */ + -2.6124443359e+03, /* 0xc523471c */ +]; +const QS5: [f32; 6] = [ + 8.1276550293e+01, /* 0x42a28d98 */ + 1.9917987061e+03, /* 0x44f8f98f */ + 1.7468484375e+04, /* 0x468878f8 */ + 4.9851425781e+04, /* 0x4742bb6d */ + 2.7948074219e+04, /* 0x46da5826 */ + -4.7191835938e+03, /* 0xc5937978 */ +]; + +const QR3: [f32; 6] = [ + -5.0783124372e-09, /* 0xb1ae7d4f */ + -1.0253783315e-01, /* 0xbdd1ff5b */ + -4.6101160049e+00, /* 0xc0938612 */ + -5.7847221375e+01, /* 0xc267638e */ + -2.2824453735e+02, /* 0xc3643e9a */ + -2.1921012878e+02, /* 0xc35b35cb */ +]; +const QS3: [f32; 6] = [ + 4.7665153503e+01, /* 0x423ea91e */ + 6.7386511230e+02, /* 0x4428775e */ + 3.3801528320e+03, /* 0x45534272 */ + 5.5477290039e+03, /* 0x45ad5dd5 */ + 1.9031191406e+03, /* 0x44ede3d0 */ + -1.3520118713e+02, /* 0xc3073381 */ +]; + +const QR2: [f32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.7838172539e-07, /* 0xb43f8932 */ + -1.0251704603e-01, /* 0xbdd1f475 */ + -2.7522056103e+00, /* 0xc0302423 */ + -1.9663616180e+01, /* 0xc19d4f16 */ + -4.2325313568e+01, /* 0xc2294d1f */ + -2.1371921539e+01, /* 0xc1aaf9b2 */ +]; +const QS2: [f32; 6] = [ + 2.9533363342e+01, /* 0x41ec4454 */ + 2.5298155212e+02, /* 0x437cfb47 */ + 7.5750280762e+02, /* 0x443d602e */ + 7.3939318848e+02, /* 0x4438d92a */ + 1.5594900513e+02, /* 0x431bf2f2 */ + -4.9594988823e+00, /* 0xc09eb437 */ +]; + +fn qonef(x: f32) -> f32 +{ + let p: &[f32; 6]; + let q: &[f32; 6]; + let s: f32; + let r: f32; + let z: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 {p = &QR8; q = &QS8;} + else if ix >= 0x409173eb {p = &QR5; q = &QS5;} + else if ix >= 0x4036d917 {p = &QR3; q = &QS3;} + else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (0.375 + r/s)/x; +} diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs new file mode 100644 index 00000000000..7f7c06feed2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -0,0 +1,338 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * jn(n, x), yn(n, x) + * floating point Bessel's function of the 1st and 2nd kind + * of order n + * + * Special cases: + * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; + * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. + * Note 2. About jn(n,x), yn(n,x) + * For n=0, j0(x) is called, + * for n=1, j1(x) is called, + * for n<=x, forward recursion is used starting + * from values of j0(x) and j1(x). + * for n>x, a continued fraction approximation to + * j(n,x)/j(n-1,x) is evaluated and then backward + * recursion is used starting from a supposed value + * for j(n,x). The resulting value of j(0,x) is + * compared with the actual value to correct the + * supposed value of j(n,x). + * + * yn(n,x) is similar in all respects, except + * that forward recursion is used for all + * values of n>1. + */ + +use super::{cos, fabs, get_high_word, get_low_word, log, j0, j1, sin, sqrt, y0, y1}; + +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ + +pub fn jn(n: isize, mut x: f64) -> f64 +{ + let mut ix: u32; + let lx: u32; + let nm1: isize; + let mut i: isize; + let mut sign: bool; + let mut a: f64; + let mut b: f64; + let mut temp: f64; + + ix = get_high_word(x); + lx = get_low_word(x); + sign = (ix>>31) != 0; + ix &= 0x7fffffff; + + // -lx == !lx + 1 + if (ix | (lx|(!lx+1))>>31) > 0x7ff00000 { /* nan */ + return x; + } + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ + if n == 0 { + return j0(x); + } + if n < 0 { + nm1 = -(n+1); + x = -x; + sign = !sign; + } else { + nm1 = n-1; + } + if nm1 == 0 { + return j1(x); + } + + sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabs(x); + if (ix|lx) == 0 || ix == 0x7ff00000 { /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as f64) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + if ix >= 0x52d00000 { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + temp = match nm1&3 { + 0 => -cos(x)+sin(x), + 1 => -cos(x)-sin(x), + 2 => cos(x)-sin(x), + 3 | _ => cos(x)+sin(x), + }; + b = INVSQRTPI*temp/sqrt(x); + } else { + a = j0(x); + b = j1(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b*(2.0*(i as f64)/x) - a; /* avoid underflow */ + a = temp; + } + } + } else { + if ix < 0x3e100000 { /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 32 { /* underflow */ + b = 0.0; + } else { + temp = x*0.5; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f64; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b/a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f64; + let mut q0: f64; + let mut q1: f64; + let mut w: f64; + let h: f64; + let mut z: f64; + let mut tmp: f64; + let nf: f64; + + let mut k: isize; + + nf = (nm1 as f64) + 1.0; + w = 2.0*nf/x; + h = 2.0/x; + z = w+h; + q0 = w; + q1 = w*z - 1.0; + k = 1; + while q1 < 1.0e9 { + k += 1; + z += h; + tmp = z*q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0/(2.0*((i as f64)+nf)/x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf*log(fabs(w)); + if tmp < 7.09782712893383973096e+02 { + i = nm1; + while i > 0 { + temp = b; + b = b*(2.0*(i as f64))/x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = b*(2.0*(i as f64))/x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 + if b > x1p500 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0(x); + w = j1(x); + if fabs(z) >= fabs(w) { + b = t*z/b; + } else { + b = t*w/a; + } + } + } + + if sign { + -b + } else { + b + } +} + + +pub fn yn(n: isize, x: f64) -> f64 +{ + let mut ix: u32; + let lx: u32; + let mut ib: u32; + let nm1: isize; + let mut sign: bool; + let mut i: isize; + let mut a: f64; + let mut b: f64; + let mut temp: f64; + + ix = get_high_word(x); + lx = get_low_word(x); + sign = (ix>>31) != 0; + ix &= 0x7fffffff; + + // -lx == !lx + 1 + if (ix | (lx|(!lx+1))>>31) > 0x7ff00000 { /* nan */ + return x; + } + if sign && (ix|lx) != 0 { /* x < 0 */ + return 0.0/0.0; + } + if ix == 0x7ff00000 { + return 0.0; + } + + if n == 0 { + return y0(x); + } + if n < 0 { + nm1 = -(n+1); + sign = (n&1) != 0; + } else { + nm1 = n-1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1(x); + } else { + return y1(x); + } + } + + if ix >= 0x52d00000 { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + temp = match nm1&3 { + 0 => -sin(x)-cos(x), + 1 => -sin(x)+cos(x), + 2 => sin(x)+cos(x), + 3 | _ => sin(x)-cos(x), + }; + b = INVSQRTPI*temp/sqrt(x); + } else { + a = y0(x); + b = y1(x); + /* quit if b is -inf */ + ib = get_high_word(b); + i = 0; + while i < nm1 && ib != 0xfff00000 { + i += 1; + temp = b; + b = (2.0*(i as f64)/x)*b - a; + ib = get_high_word(b); + a = temp; + } + } + + if sign { + -b + } else { + b + } +} diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs new file mode 100644 index 00000000000..4cd848a03b0 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/jnf.rs @@ -0,0 +1,255 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{fabsf, j0f, j1f, logf, y0f, y1f}; + +pub fn jnf(n: isize, mut x: f32) -> f32 +{ + let mut ix: u32; + let mut nm1: isize; + let mut sign: bool; + let mut i: isize; + let mut a: f32; + let mut b: f32; + let mut temp: f32; + + ix = x.to_bits(); + sign = (ix>>31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { /* nan */ + return x; + } + + /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ + if n == 0 { + return j0f(x); + } + if n < 0 { + nm1 = -(n+1); + x = -x; + sign = !sign; + } else { + nm1 = n-1; + } + if nm1 == 0 { + return j1f(x); + } + + sign &= (n&1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabsf(x); + if ix == 0 || ix == 0x7f800000 { /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as f32) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + a = j0f(x); + b = j1f(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b*(2.0*(i as f32)/x) - a; + a = temp; + } + } else { + if ix < 0x35800000 { /* x < 2**-20 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 8 { /* underflow */ + nm1 = 8; + } + temp = 0.5 * x; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f32; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b/a; + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f32; + let mut q0: f32; + let mut q1: f32; + let mut w: f32; + let h: f32; + let mut z: f32; + let mut tmp: f32; + let nf: f32; + let mut k: isize; + + nf = (nm1 as f32)+1.0; + w = 2.0*(nf as f32)/x; + h = 2.0/x; + z = w+h; + q0 = w; + q1 = w*z - 1.0; + k = 1; + while q1 < 1.0e4 { + k += 1; + z += h; + tmp = z*q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0/(2.0*((i as f32)+nf)/x-t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf*logf(fabsf(w)); + if tmp < 88.721679688 { + i = nm1; + while i > 0 { + temp = b; + b = 2.0*(i as f32)*b/x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = 2.0*(i as f32)*b/x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 + if b > x1p60 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0f(x); + w = j1f(x); + if fabsf(z) >= fabsf(w) { + b = t*z/b; + } else { + b = t*w/a; + } + } + } + + if sign { + -b + } else { + b + } +} + +pub fn ynf(n: isize, x: f32) -> f32 +{ + let mut ix: u32; + let mut ib: u32; + let nm1: isize; + let mut sign: bool; + let mut i: isize; + let mut a: f32; + let mut b: f32; + let mut temp: f32; + + ix = x.to_bits(); + sign = (ix>>31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { /* nan */ + return x; + } + if sign && ix != 0 { /* x < 0 */ + return 0.0/0.0; + } + if ix == 0x7f800000 { + return 0.0; + } + + if n == 0 { + return y0f(x); + } + if n < 0 { + nm1 = -(n+1); + sign = (n&1) != 0; + } else { + nm1 = n-1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1f(x); + } else { + return y1f(x); + } + } + + a = y0f(x); + b = y1f(x); + /* quit if b is -inf */ + ib = b.to_bits(); + i = 0; + while i < nm1 && ib != 0xff800000 { + i += 1; + temp = b; + b = (2.0*(i as f32)/x)*b - a; + ib = b.to_bits(); + a = temp; + } + + if sign { + -b + } else { + b + } +} diff --git a/library/compiler-builtins/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/src/math/lgamma.rs new file mode 100644 index 00000000000..35b25265214 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/lgamma.rs @@ -0,0 +1,309 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = PI/sin(PI*x), + * we have + * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(PI*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); + * Note: one should avoid compute PI*(-x) directly in the + * computation of sin(PI*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +use super::{floor, k_cos, k_sin, log}; + +const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ +const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ +const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ +const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ +const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ +const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ +const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ +const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ +const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ +const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ +const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ +const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ +const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ +const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ +const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of TF) */ +const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ +const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ +const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ +const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ +const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ +const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ +const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ +const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ +const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ +const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ +const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ +const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ +const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ +const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ +const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ +const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ +const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ +const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ +const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ +const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ +const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ +const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ +const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ +const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ +const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ +const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ +const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ +const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ +const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ +const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ +const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ +const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ +const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ +const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ +const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ +const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ +const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ +const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ +const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ +const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ +const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ +const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ +const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ +const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ +const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f64) -> f64 +{ + let mut n: isize; + + /* spurious inexact if odd int */ + x = 2.0*(x*0.5 - floor(x*0.5)); /* x mod 2.0 */ + + n = (x*4.0) as isize; + n = (n+1)/2; + x -= (n as f64)*0.5; + x *= PI; + + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + 0|_ => k_sin(x, 0.0, 0), + } +} + +pub fn lgamma(x: f64) -> f64 { + lgamma_r(x).0 +} + +pub fn lgamma_r(mut x: f64) -> (f64, isize) +{ + let u: u64 = x.to_bits(); + let mut t: f64; + let y: f64; + let mut z: f64; + let nadj: f64; + let p: f64; + let p1: f64; + let p2: f64; + let p3: f64; + let q: f64; + let mut r: f64; + let w: f64; + let ix: u32; + let sign: bool; + let i: isize; + let mut signgam: isize; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u>>63) != 0; + ix = ((u>>32) as u32) & 0x7fffffff; + if ix >= 0x7ff00000 { + return (x*x, signgam); + } + if ix < (0x3ff-70)<<20 { /* |x|<2**-70, return -log(|x|) */ + if sign { + x = -x; + signgam = -1; + } + return (-log(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { /* -integer */ + return (1.0/(x-x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = log(PI/(t*x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3feccccc { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -log(x); + if ix >= 0x3FE76944 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3FCDA661 { + y = x - (TC-1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3FFBB4C3 { /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3FF3B4C4 { /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y*y; + p1 = A0+z*(A2+z*(A4+z*(A6+z*(A8+z*A10)))); + p2 = z*(A1+z*(A3+z*(A5+z*(A7+z*(A9+z*A11))))); + p = y*p1+p2; + r += p-0.5*y; + } + 1 => { + z = y*y; + w = z*y; + p1 = T0+w*(T3+w*(T6+w*(T9 +w*T12))); /* parallel comp */ + p2 = T1+w*(T4+w*(T7+w*(T10+w*T13))); + p3 = T2+w*(T5+w*(T8+w*(T11+w*T14))); + p = z*p1-(TT-w*(p2+y*p3)); + r += TF + p; + } + 2 => { + p1 = y*(U0+y*(U1+y*(U2+y*(U3+y*(U4+y*U5))))); + p2 = 1.0+y*(V1+y*(V2+y*(V3+y*(V4+y*V5)))); + r += -0.5*y + p1/p2; + } + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => {} + } + } else if ix < 0x40200000 { /* x < 8.0 */ + i = x as isize; + y = x - (i as f64); + p = y*(S0+y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6)))))); + q = 1.0+y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6))))); + r = 0.5*y+p/q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { z *= y + 6.0; } + if i >= 6 { z *= y + 5.0; } + if i >= 5 { z *= y + 4.0; } + if i >= 4 { z *= y + 3.0; } + if i >= 3 { + z *= y + 2.0; + r += log(z); + } + } else if ix < 0x43900000 { /* 8.0 <= x < 2**58 */ + t = log(x); + z = 1.0/x; + y = z*z; + w = W0+z*(W1+y*(W2+y*(W3+y*(W4+y*(W5+y*W6))))); + r = (x-0.5)*(t-1.0)+w; + } else { /* 2**58 <= x <= inf */ + r = x*(log(x)-1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/src/math/lgammaf.rs new file mode 100644 index 00000000000..60effa31674 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/lgammaf.rs @@ -0,0 +1,244 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{floorf, k_cosf, k_sinf, logf}; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ +const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ +const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ +const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ +const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ +const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ +const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ +const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ +const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ +const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ +const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ +const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ +const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ +const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ +/* TT = -(tail of TF) */ +const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ +const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ +const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ +const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ +const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ +const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ +const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ +const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ +const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ +const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ +const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ +const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ +const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ +const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ +const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ +const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ +const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ +const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ +const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ +const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ +const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ +const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ +const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ +const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ +const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ +const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ +const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ +const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ +const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ +const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ +const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ +const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ +const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ +const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ +const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ +const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ +const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ +const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ +const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ +const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ +const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ +const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ +const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ +const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f32) -> f32 +{ + let mut y: f64; + let mut n: isize; + + /* spurious inexact if odd int */ + x = 2.0*(x*0.5 - floorf(x*0.5)); /* x mod 2.0 */ + + n = (x*4.0) as isize; + n = (n+1)/2; + y = (x as f64) - (n as f64)*0.5; + y *= 3.14159265358979323846; + match n { + 1 => k_cosf(y), + 2 => k_sinf(-y), + 3 => -k_cosf(y), + 0|_ => k_sinf(y), + } +} + +pub fn lgammaf(x: f32) -> f32 { + lgammaf_r(x).0 +} + +pub fn lgammaf_r(mut x: f32) -> (f32, isize) +{ + let u = x.to_bits(); + let mut t: f32; + let y: f32; + let mut z: f32; + let nadj: f32; + let p: f32; + let p1: f32; + let p2: f32; + let p3: f32; + let q: f32; + let mut r: f32; + let w: f32; + let ix: u32; + let i: isize; + let sign: bool; + let mut signgam: isize; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u>>31) != 0; + ix = u & 0x7fffffff; + if ix >= 0x7f800000 { + return (x*x, signgam); + } + if ix < 0x35000000 { /* |x| < 2**-21, return -log(|x|) */ + if sign { + signgam = -1; + x = -x; + } + return (-logf(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { /* -integer */ + return (1.0/(x-x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = logf(PI/(t*x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if ix == 0x3f800000 || ix == 0x40000000 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3f666666 { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -logf(x); + if ix >= 0x3f3b4a20 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3e6d3308 { + y = x - (TC-1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3fdda618 { /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3F9da620 { /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y*y; + p1 = A0+z*(A2+z*(A4+z*(A6+z*(A8+z*A10)))); + p2 = z*(A1+z*(A3+z*(A5+z*(A7+z*(A9+z*A11))))); + p = y*p1+p2; + r += p - 0.5*y; + } + 1 => { + z = y*y; + w = z*y; + p1 = T0+w*(T3+w*(T6+w*(T9 +w*T12))); /* parallel comp */ + p2 = T1+w*(T4+w*(T7+w*(T10+w*T13))); + p3 = T2+w*(T5+w*(T8+w*(T11+w*T14))); + p = z*p1-(TT-w*(p2+y*p3)); + r += TF + p; + } + 2 => { + p1 = y*(U0+y*(U1+y*(U2+y*(U3+y*(U4+y*U5))))); + p2 = 1.0+y*(V1+y*(V2+y*(V3+y*(V4+y*V5)))); + r += -0.5*y + p1/p2; + } + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => {} + } + } else if ix < 0x41000000 { /* x < 8.0 */ + i = x as isize; + y = x - (i as f32); + p = y*(S0+y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6)))))); + q = 1.0+y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6))))); + r = 0.5*y+p/q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { z *= y + 6.0; } + if i >= 6 { z *= y + 5.0; } + if i >= 5 { z *= y + 4.0; } + if i >= 4 { z *= y + 3.0; } + if i >= 3 { + z *= y + 2.0; + r += logf(z); + } + } else if ix < 0x5c800000 { /* 8.0 <= x < 2**58 */ + t = logf(x); + z = 1.0/x; + y = z*z; + w = W0+z*(W1+y*(W2+y*(W3+y*(W4+y*(W5+y*W6))))); + r = (x-0.5)*(t-1.0)+w; + } else { /* 2**58 <= x <= inf */ + r = x*(logf(x)-1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index da34fb4cecd..53842b38e99 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -61,21 +61,33 @@ macro_rules! i { // Public modules mod acos; mod acosf; +mod acosh; +mod acoshf; mod asin; mod asinf; +mod asinh; +mod asinhf; mod atan; mod atan2; mod atan2f; mod atanf; +mod atanh; +mod atanhf; mod cbrt; mod cbrtf; mod ceil; mod ceilf; +mod copysign; +mod copysignf; mod cos; mod cosf; mod cosh; mod coshf; +mod erf; +mod erff; mod exp; +mod exp10; +mod exp10f; mod exp2; mod exp2f; mod expf; @@ -91,8 +103,20 @@ mod fma; mod fmaf; mod fmod; mod fmodf; +mod frexp; +mod frexpf; mod hypot; mod hypotf; +mod ilogb; +mod ilogbf; +mod j0; +mod j0f; +mod j1; +mod j1f; +mod jn; +mod jnf; +mod lgamma; +mod lgammaf; mod log; mod log10; mod log10f; @@ -101,13 +125,19 @@ mod log1pf; mod log2; mod log2f; mod logf; +mod modf; +mod modff; mod pow; mod powf; +mod remquo; +mod remquof; mod round; mod roundf; mod scalbn; mod scalbnf; mod sin; +mod sincos; +mod sincosf; mod sinf; mod sinh; mod sinhf; @@ -117,27 +147,43 @@ mod tan; mod tanf; mod tanh; mod tanhf; +mod tgamma; +mod tgammaf; mod trunc; mod truncf; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; pub use self::acosf::acosf; +pub use self::acosh::acosh; +pub use self::acoshf::acoshf; pub use self::asin::asin; pub use self::asinf::asinf; +pub use self::asinh::asinh; +pub use self::asinhf::asinhf; pub use self::atan::atan; pub use self::atan2::atan2; pub use self::atan2f::atan2f; pub use self::atanf::atanf; +pub use self::atanh::atanh; +pub use self::atanhf::atanhf; pub use self::cbrt::cbrt; pub use self::cbrtf::cbrtf; pub use self::ceil::ceil; pub use self::ceilf::ceilf; +pub use self::copysign::copysign; +pub use self::copysignf::copysignf; pub use self::cos::cos; pub use self::cosf::cosf; pub use self::cosh::cosh; pub use self::coshf::coshf; +pub use self::erf::erf; +pub use self::erf::erfc; +pub use self::erff::erff; +pub use self::erff::erfcf; pub use self::exp::exp; +pub use self::exp10::exp10; +pub use self::exp10f::exp10f; pub use self::exp2::exp2; pub use self::exp2f::exp2f; pub use self::expf::expf; @@ -153,8 +199,28 @@ pub use self::fma::fma; pub use self::fmaf::fmaf; pub use self::fmod::fmod; pub use self::fmodf::fmodf; +pub use self::frexp::frexp; +pub use self::frexpf::frexpf; pub use self::hypot::hypot; pub use self::hypotf::hypotf; +pub use self::ilogb::ilogb; +pub use self::ilogbf::ilogbf; +pub use self::j0::j0; +pub use self::j0::y0; +pub use self::j0f::j0f; +pub use self::j0f::y0f; +pub use self::j1::j1; +pub use self::j1::y1; +pub use self::j1f::j1f; +pub use self::j1f::y1f; +pub use self::jn::jn; +pub use self::jn::yn; +pub use self::jnf::jnf; +pub use self::jnf::ynf; +pub use self::lgamma::lgamma; +pub use self::lgamma::lgamma_r; +pub use self::lgammaf::lgammaf; +pub use self::lgammaf::lgammaf_r; pub use self::log::log; pub use self::log10::log10; pub use self::log10f::log10f; @@ -163,13 +229,19 @@ pub use self::log1pf::log1pf; pub use self::log2::log2; pub use self::log2f::log2f; pub use self::logf::logf; +pub use self::modf::modf; +pub use self::modff::modff; pub use self::pow::pow; pub use self::powf::powf; +pub use self::remquo::remquo; +pub use self::remquof::remquof; pub use self::round::round; pub use self::roundf::roundf; pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; pub use self::sin::sin; +pub use self::sincos::sincos; +pub use self::sincosf::sincosf; pub use self::sinf::sinf; pub use self::sinh::sinh; pub use self::sinhf::sinhf; @@ -179,6 +251,8 @@ pub use self::tan::tan; pub use self::tanf::tanf; pub use self::tanh::tanh; pub use self::tanhf::tanhf; +pub use self::tgamma::tgamma; +pub use self::tgammaf::tgammaf; pub use self::trunc::trunc; pub use self::truncf::truncf; diff --git a/library/compiler-builtins/libm/src/math/modf.rs b/library/compiler-builtins/libm/src/math/modf.rs new file mode 100644 index 00000000000..1ff8ee116d0 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/modf.rs @@ -0,0 +1,33 @@ +pub fn modf(x: f64) -> (f64, f64) { + let rv2: f64; + let mut u = x.to_bits(); + let mask: u64; + let e = ((u>>52 & 0x7ff) as isize) - 0x3ff; + + /* no fractional part */ + if e >= 52 { + rv2 = x; + if e == 0x400 && (u<<12) != 0 { /* nan */ + return (x, rv2); + } + u &= 1<<63; + return (f64::from_bits(u), rv2); + } + + /* no integral part*/ + if e < 0 { + u &= 1<<63; + rv2 = f64::from_bits(u); + return (x, rv2); + } + + mask = ((!0)>>12)>>e; + if (u & mask) == 0 { + rv2 = x; + u &= 1<<63; + return (f64::from_bits(u), rv2); + } + u &= !mask; + rv2 = f64::from_bits(u); + return (x - rv2, rv2); +} diff --git a/library/compiler-builtins/libm/src/math/modff.rs b/library/compiler-builtins/libm/src/math/modff.rs new file mode 100644 index 00000000000..5250e8d3801 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/modff.rs @@ -0,0 +1,32 @@ +pub fn modff(x: f32) -> (f32, f32) { + let rv2: f32; + let mut u: u32 = x.to_bits(); + let mask: u32; + let e = ((u>>23 & 0xff) as isize) - 0x7f; + + /* no fractional part */ + if e >= 23 { + rv2 = x; + if e == 0x80 && (u<<9) != 0 { /* nan */ + return (x, rv2); + } + u &= 0x80000000; + return (f32::from_bits(u), rv2); + } + /* no integral part */ + if e < 0 { + u &= 0x80000000; + rv2 = f32::from_bits(u); + return (x, rv2); + } + + mask = 0x007fffff>>e; + if (u & mask) == 0 { + rv2 = x; + u &= 0x80000000; + return (f32::from_bits(u), rv2); + } + u &= !mask; + rv2 = f32::from_bits(u); + return (x - rv2, rv2); +} diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs new file mode 100644 index 00000000000..98f4b38581a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -0,0 +1,98 @@ +pub fn remquo(mut x: f64, mut y: f64) -> (f64, isize) +{ + let ux: u64 = x.to_bits(); + let mut uy: u64 = y.to_bits(); + let mut ex = ((ux>>52) & 0x7ff) as isize; + let mut ey = ((uy>>52) & 0x7ff) as isize; + let sx = (ux>>63) != 0; + let sy = (uy>>63) != 0; + let mut q: u32; + let mut i: u64; + let mut uxi: u64 = ux; + + if (uy<<1) == 0 || y.is_nan() || ex == 0x7ff { + return ((x*y)/(x*y), 0); + } + if (ux<<1) == 0 { + return (x, 0); + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 12; + while (i>>63) == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= (!0) >> 12; + uxi |= 1 << 52; + } + if ey == 0 { + i = uy<<12; + while (i>>63) == 0 { + ey -= 1; + i <<= 1; + } + uy <<= -ey + 1; + } else { + uy &= (!0) >> 12; + uy |= 1 << 52; + } + + q = 0; + + if ex+1 != ey { + if ex < ey { + return (x, 0); + } + /* x mod y */ + while ex > ey { + i = uxi - uy; + if (i>>63) == 0 { + uxi = i; + q += 1; + } + uxi <<= 1; + q <<= 1; + ex -= 1; + } + i = uxi - uy; + if (i>>63) == 0 { + uxi = i; + q += 1; + } + if uxi == 0 { + ex = -60; + } else { + while (uxi>>52) == 0 { + uxi <<= 1; + ex -= 1; + } + } + } + + /* scale result and decide between |x| and |x|-|y| */ + if ex > 0 { + uxi -= 1 << 52; + uxi |= (ex as u64) << 52; + } else { + uxi >>= -ex + 1; + } + x = f64::from_bits(uxi); + if sy { + y = -y; + } + if ex == ey || (ex+1 == ey && (2.0*x > y || (2.0*x == y && (q%2) != 0))) { + x -= y; + q += 1; + } + q &= 0x7fffffff; + let quo = if sx ^ sy { -(q as isize) } else { q as isize }; + if sx { + (-x, quo) + } else { + (x, quo) + } +} diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs new file mode 100644 index 00000000000..4307e190665 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/remquof.rs @@ -0,0 +1,97 @@ +pub fn remquof(mut x: f32, mut y: f32) -> (f32, isize) +{ + let ux: u32 = x.to_bits(); + let mut uy: u32 = y.to_bits(); + let mut ex = ((ux>>23) & 0xff) as isize; + let mut ey = ((uy>>23) & 0xff) as isize; + let sx = (ux>>31) != 0; + let sy = (uy>>31) != 0; + let mut q: u32; + let mut i: u32; + let mut uxi: u32 = ux; + + if (uy<<1) == 0 || y.is_nan() || ex == 0xff { + return ((x*y)/(x*y), 0); + } + if (ux<<1) == 0 { + return (x, 0); + } + + /* normalize x and y */ + if ex == 0 { + i = uxi<<9; + while (i>>31) == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= (!0) >> 9; + uxi |= 1 << 23; + } + if ey == 0 { + i = uy<<9; + while (i>>31) == 0 { + ey -= 1; + i <<= 1; + } + uy <<= -ey + 1; + } else { + uy &= (!0) >> 9; + uy |= 1 << 23; + } + + q = 0; + if ex+1 != ey { + if ex < ey { + return (x, 0); + } + /* x mod y */ + while ex > ey { + i = uxi - uy; + if (i>>31) == 0 { + uxi = i; + q += 1; + } + uxi <<= 1; + q <<= 1; + ex -= 1; + } + i = uxi - uy; + if (i>>31) == 0 { + uxi = i; + q += 1; + } + if uxi == 0 { + ex = -30; + } else { + while (uxi>>23) == 0 { + uxi <<= 1; + ex -= 1; + } + } + } + + /* scale result and decide between |x| and |x|-|y| */ + if ex > 0 { + uxi -= 1 << 23; + uxi |= (ex as u32) << 23; + } else { + uxi >>= -ex + 1; + } + x = f32::from_bits(uxi); + if sy { + y = -y; + } + if ex == ey || (ex+1 == ey && (2.0*x > y || (2.0*x == y && (q%2) != 0))) { + x -= y; + q += 1; + } + q &= 0x7fffffff; + let quo = if sx^sy { -(q as isize) } else { q as isize }; + if sx { + (-x, quo) + } else { + (x, quo) + } +} diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs new file mode 100644 index 00000000000..c15ee4661f6 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -0,0 +1,60 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{get_high_word, k_cos, k_sin, rem_pio2}; + +pub fn sincos(x: f64) -> (f64, f64) +{ + let s: f64; + let c: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + /* if |x| < 2**-27 * sqrt(2) */ + if ix < 0x3e46a09e { + /* raise inexact if x!=0 and underflow if subnormal */ + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 + if ix < 0x00100000 { + force_eval!(x/x1p120); + } else { + force_eval!(x+x1p120); + } + return (x, 1.0); + } + return (k_sin(x, 0.0, 0), k_cos(x, 0.0)); + } + + /* sincos(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + let rv = x - x; + return (rv, rv); + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + s = k_sin(y0, y1, 1); + c = k_cos(y0, y1); + match n&3 { + 0 => (s, c), + 1 => (c, -s), + 2 => (-s, -c), + 3 => (-c, s), + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => (0.0, 1.0), + } +} diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs new file mode 100644 index 00000000000..911421d63d4 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -0,0 +1,122 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{k_cosf, k_sinf, rem_pio2f}; + +/* Small multiples of pi/2 rounded to double precision. */ +const PI_2: f32 = 0.5 * 3.1415926535897931160E+00; +const S1PIO2: f32 = 1.0*PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2PIO2: f32 = 2.0*PI_2; /* 0x400921FB, 0x54442D18 */ +const S3PIO2: f32 = 3.0*PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4PIO2: f32 = 4.0*PI_2; /* 0x401921FB, 0x54442D18 */ + +pub fn sincosf(x: f32) -> (f32, f32) +{ + let s: f32; + let c: f32; + let mut ix: u32; + let sign: bool; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + /* |x| ~<= pi/4 */ + if ix <= 0x3f490fda { + /* |x| < 2**-12 */ + if ix < 0x39800000 { + /* raise inexact if x!=0 and underflow if subnormal */ + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120 == 2^120 + if ix < 0x00100000 { + force_eval!(x/x1p120); + } else { + force_eval!(x+x1p120); + } + return (x, 1.0); + } + return (k_sinf(x as f64), k_cosf(x as f64)); + } + + /* |x| ~<= 5*pi/4 */ + if ix <= 0x407b53d1 { + if ix <= 0x4016cbe3 { /* |x| ~<= 3pi/4 */ + if sign { + s = -k_cosf((x + S1PIO2) as f64); + c = k_sinf((x + S1PIO2) as f64); + } else { + s = k_cosf((S1PIO2 - x) as f64); + c = k_sinf((S1PIO2 - x) as f64); + } + } + /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ + else { + if sign { + s = k_sinf((x + S2PIO2) as f64); + c = k_cosf((x + S2PIO2) as f64); + } else { + s = k_sinf((x - S2PIO2) as f64); + c = k_cosf((x - S2PIO2) as f64); + } + } + + return (s, c); + } + + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40e231d5 { + if ix <= 0x40afeddf { /* |x| ~<= 7*pi/4 */ + if sign { + s = k_cosf((x + S3PIO2) as f64); + c = -k_sinf((x + S3PIO2) as f64); + } else { + s = -k_cosf((x - S3PIO2) as f64); + c = k_sinf((x - S3PIO2) as f64); + } + } else { + if sign { + s = k_cosf((x + S4PIO2) as f64); + c = k_sinf((x + S4PIO2) as f64); + } else { + s = k_cosf((x - S4PIO2) as f64); + c = k_sinf((x - S4PIO2) as f64); + } + } + + return (s, c); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + let rv = x - x; + return (rv, rv); + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + s = k_sinf(y); + c = k_cosf(y); + match n&3 { + 0 => (s, c), + 1 => (c, -s), + 2 => (-s, -c), + 3 => (-c, s), + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => (0.0, 1.0), + } +} diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs new file mode 100644 index 00000000000..598f46f1c3e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tgamma.rs @@ -0,0 +1,179 @@ +/* +"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) +"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) +"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) + +approximation method: + + (x - 0.5) S(x) +Gamma(x) = (x + g - 0.5) * ---------------- + exp(x + g - 0.5) + +with + a1 a2 a3 aN +S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] + x + 1 x + 2 x + 3 x + N + +with a0, a1, a2, a3,.. aN constants which depend on g. + +for x < 0 the following reflection formula is used: + +Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) + +most ideas and constants are from boost and python +*/ +extern crate core; +use super::{exp, floor, k_cos, k_sin, pow}; + +const PI: f64 = 3.141592653589793238462643383279502884; + +/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ +fn sinpi(mut x: f64) -> f64 +{ + let mut n: isize; + + /* argument reduction: x = |x| mod 2 */ + /* spurious inexact when x is odd int */ + x = x * 0.5; + x = 2.0 * (x - floor(x)); + + /* reduce x into [-.25,.25] */ + n = (4.0 * x) as isize; + n = (n+1)/2; + x -= (n as f64) * 0.5; + + x *= PI; + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + 0|_ => k_sin(x, 0.0, 0), + } +} + +const N: usize = 12; +//static const double g = 6.024680040776729583740234375; +const GMHALF: f64 = 5.524680040776729583740234375; +const SNUM: [f64; N+1] = [ + 23531376880.410759688572007674451636754734846804940, + 42919803642.649098768957899047001988850926355848959, + 35711959237.355668049440185451547166705960488635843, + 17921034426.037209699919755754458931112671403265390, + 6039542586.3520280050642916443072979210699388420708, + 1439720407.3117216736632230727949123939715485786772, + 248874557.86205415651146038641322942321632125127801, + 31426415.585400194380614231628318205362874684987640, + 2876370.6289353724412254090516208496135991145378768, + 186056.26539522349504029498971604569928220784236328, + 8071.6720023658162106380029022722506138218516325024, + 210.82427775157934587250973392071336271166969580291, + 2.5066282746310002701649081771338373386264310793408, +]; +const SDEN: [f64; N+1] = [ + 0.0, 39916800.0, 120543840.0, 150917976.0, 105258076.0, + 45995730.0, 13339535.0, 2637558.0, 357423.0, 32670.0, 1925.0, 66.0, 1.0, +]; +/* n! for small integer n */ +const FACT: [f64; 23] = [ + 1.0, 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, 40320.0, 362880.0, 3628800.0, + 39916800.0, 479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0, + 20922789888000.0, 355687428096000.0, 6402373705728000.0, 121645100408832000.0, + 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0, +]; + +/* S(x) rational function for positive x */ +fn s(x: f64) -> f64 +{ + let mut num: f64 = 0.0; + let mut den: f64 = 0.0; + + /* to avoid overflow handle large x differently */ + if x < 8.0 { + for i in (0..=N).rev() { + num = num * x + SNUM[i]; + den = den * x + SDEN[i]; + } + } else { + for i in 0..=N { + num = num / x + SNUM[i]; + den = den / x + SDEN[i]; + } + } + return num/den; +} + +pub fn tgamma(mut x: f64) -> f64 +{ + let u: u64 = x.to_bits(); + let absx: f64; + let mut y: f64; + let mut dy: f64; + let mut z: f64; + let mut r: f64; + let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; + let sign: bool = (u>>64) != 0; + + /* special cases */ + if ix >= 0x7ff00000 { + /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ + return x + core::f64::INFINITY; + } + if ix < ((0x3ff-54)<<20) { + /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ + return 1.0/x; + } + + /* integer arguments */ + /* raise inexact when non-integer */ + if x == floor(x) { + if sign { + return 0.0/0.0; + } + if x <= FACT.len() as f64 { + return FACT[(x as usize) - 1]; + } + } + + /* x >= 172: tgamma(x)=inf with overflow */ + /* x =< -184: tgamma(x)=+-0 with underflow */ + if ix >= 0x40670000 { /* |x| >= 184 */ + if sign { + let x1p_126 = f64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 + force_eval!((x1p_126/x) as f32); + if floor(x) * 0.5 == floor(x * 0.5) { + return 0.0; + } else { + return -0.0; + } + } + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 + x *= x1p1023; + return x; + } + + absx = if sign { -x } else { x }; + + /* handle the error of x + g - 0.5 */ + y = absx + GMHALF; + if absx > GMHALF { + dy = y - absx; + dy -= GMHALF; + } else { + dy = y - GMHALF; + dy -= absx; + } + + z = absx - 0.5; + r = s(absx) * exp(-y); + if x < 0.0 { + /* reflection formula for negative x */ + /* sinpi(absx) is not 0, integers are already handled */ + r = -PI / (sinpi(absx) * absx * r); + dy = -dy; + z = -z; + } + r += dy * (GMHALF+0.5) * r / y; + z = pow(y, 0.5*z); + y = r * z * z; + return y; +} diff --git a/library/compiler-builtins/libm/src/math/tgammaf.rs b/library/compiler-builtins/libm/src/math/tgammaf.rs new file mode 100644 index 00000000000..b9c799ce76c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tgammaf.rs @@ -0,0 +1,5 @@ +use super::{tgamma}; + +pub fn tgammaf(x: f32) -> f32 { + tgamma(x as f64) as f32 +} -- cgit 1.4.1-3-g733a5 From cbff8302355717eb3f73457f19538972443e36af Mon Sep 17 00:00:00 2001 From: Charles Samborski Date: Tue, 28 Aug 2018 15:48:58 +0200 Subject: Fix link in README.md (Rust operator precedence) --- library/compiler-builtins/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index d10b44f8f78..cae885279ad 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -69,13 +69,13 @@ features = ["c"] ### Porting Reminders -1. [Rust][4] and [C][5] have slightly different operator precedence. C evaluates comparisons (`== !=`) before bitwise operations (`& | ^`), while Rust evaluates the other way. +1. [Rust][5a] and [C][5b] have slightly different operator precedence. C evaluates comparisons (`== !=`) before bitwise operations (`& | ^`), while Rust evaluates the other way. 2. C assumes wrapping operations everywhere. Rust panics on overflow when in debug mode. Consider using the [Wrapping][6] type or the explicit [wrapping_*][7] functions where applicable. 3. Note [C implicit casts][8], especially integer promotion. Rust is much more explicit about casting, so be sure that any cast which affects the output is ported to the Rust implementation. 4. Rust has [many functions][9] for integer or floating point manipulation in the standard library. Consider using one of these functions rather than porting a new one. -[4]: https://doc.rust-lang.org/reference.html#operator-precedence -[5]: http://en.cppreference.com/w/c/language/operator_precedence +[5a]: https://doc.rust-lang.org/reference/expressions.html#expression-precedence +[5b]: http://en.cppreference.com/w/c/language/operator_precedence [6]: https://doc.rust-lang.org/core/num/struct.Wrapping.html [7]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_add [8]: http://en.cppreference.com/w/cpp/language/implicit_conversion -- cgit 1.4.1-3-g733a5 From 1b4201f90d4c796c5776c1fb7ef077fb73af7f43 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 30 Aug 2018 14:13:15 -0700 Subject: Fix compilation on riscv32 --- library/compiler-builtins/src/riscv32.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/riscv32.rs b/library/compiler-builtins/src/riscv32.rs index ebaa354a4b3..9161a11ccec 100644 --- a/library/compiler-builtins/src/riscv32.rs +++ b/library/compiler-builtins/src/riscv32.rs @@ -1,7 +1,8 @@ intrinsics! { // Implementation from gcc // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c - pub extern "C" fn __mulsi3(mut a: u32, mut b: u32) -> u32 { + pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { + let (mut a, mut b) = (a, b); let mut r: usize = 0; while a > 0 { -- cgit 1.4.1-3-g733a5 From 091b21da578911d46e1c95b2e37413737473e374 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 31 Aug 2018 16:00:12 -0700 Subject: Fix compile on riscv again --- library/compiler-builtins/src/riscv32.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/riscv32.rs b/library/compiler-builtins/src/riscv32.rs index 9161a11ccec..9a3c1714c1f 100644 --- a/library/compiler-builtins/src/riscv32.rs +++ b/library/compiler-builtins/src/riscv32.rs @@ -3,7 +3,7 @@ intrinsics! { // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { let (mut a, mut b) = (a, b); - let mut r: usize = 0; + let mut r = 0; while a > 0 { if a & 1 > 0 { -- cgit 1.4.1-3-g733a5 From 8a4148f60b5b27e35df5c5ed9dd42cb537b86a55 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sat, 1 Sep 2018 20:12:41 +0200 Subject: Rename panic_implementation -> panic_handler panic_implementation has been deprecated/renamed. New name is panic_handler --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/crates/panic-handler/Cargo.toml | 6 ++++++ library/compiler-builtins/crates/panic-handler/src/lib.rs | 11 +++++++++++ .../compiler-builtins/crates/panic-implementation/Cargo.toml | 6 ------ .../compiler-builtins/crates/panic-implementation/src/lib.rs | 11 ----------- library/compiler-builtins/examples/intrinsics.rs | 4 ++-- 6 files changed, 20 insertions(+), 20 deletions(-) create mode 100644 library/compiler-builtins/crates/panic-handler/Cargo.toml create mode 100644 library/compiler-builtins/crates/panic-handler/src/lib.rs delete mode 100644 library/compiler-builtins/crates/panic-implementation/Cargo.toml delete mode 100644 library/compiler-builtins/crates/panic-implementation/src/lib.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 31126626919..7eae2dc1f28 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -10,7 +10,7 @@ test = false cc = { optional = true, version = "1.0" } [dev-dependencies] -panic-implementation = { path = 'crates/panic-implementation' } +panic-handler = { path = 'crates/panic-handler' } [features] default = ["compiler-builtins"] diff --git a/library/compiler-builtins/crates/panic-handler/Cargo.toml b/library/compiler-builtins/crates/panic-handler/Cargo.toml new file mode 100644 index 00000000000..1dea613d192 --- /dev/null +++ b/library/compiler-builtins/crates/panic-handler/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "panic-handler" +version = "0.1.0" +authors = ["Alex Crichton "] + +[dependencies] diff --git a/library/compiler-builtins/crates/panic-handler/src/lib.rs b/library/compiler-builtins/crates/panic-handler/src/lib.rs new file mode 100644 index 00000000000..e9706108737 --- /dev/null +++ b/library/compiler-builtins/crates/panic-handler/src/lib.rs @@ -0,0 +1,11 @@ +// Hack of a crate until rust-lang/rust#51647 is fixed + +#![feature(no_core, panic_handler)] +#![no_core] + +extern crate core; + +#[panic_handler] +fn panic(_: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/library/compiler-builtins/crates/panic-implementation/Cargo.toml b/library/compiler-builtins/crates/panic-implementation/Cargo.toml deleted file mode 100644 index a076cbc3cb8..00000000000 --- a/library/compiler-builtins/crates/panic-implementation/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "panic-implementation" -version = "0.1.0" -authors = ["Alex Crichton "] - -[dependencies] diff --git a/library/compiler-builtins/crates/panic-implementation/src/lib.rs b/library/compiler-builtins/crates/panic-implementation/src/lib.rs deleted file mode 100644 index 1bb23970f7d..00000000000 --- a/library/compiler-builtins/crates/panic-implementation/src/lib.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Hack of a crate until rust-lang/rust#51647 is fixed - -#![feature(no_core, panic_implementation)] -#![no_core] - -extern crate core; - -#[panic_implementation] -fn panic(_: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 7f502bba34b..a5be5739443 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -11,11 +11,11 @@ #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] -#![feature(panic_implementation)] +#![feature(panic_handler)] #![cfg_attr(windows, feature(panic_unwind))] #![no_std] -extern crate panic_implementation; +extern crate panic_handler; #[cfg(not(thumb))] #[link(name = "c")] -- cgit 1.4.1-3-g733a5 From 38d5777d984c1e4eb35bbaf3e932c2b90a038dc9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 4 Sep 2018 10:19:55 -0700 Subject: Fix some `use_c_shim_if` directives This was an accidental regression introduced in #252 by removing compilation of C files without adjusting the `#[use_c_shim_if]` directives. This restores the compilation of the assembly files and updates the `#[use_c_shim_if]` directives. --- library/compiler-builtins/build.rs | 2 ++ library/compiler-builtins/src/float/conv.rs | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index fba4091124a..cdcbfe24cd7 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -267,8 +267,10 @@ mod c { if target_arch == "x86_64" { sources.extend( &[ + "x86_64/floatdisf.c", "x86_64/floatdixf.c", "x86_64/floatundidf.S", + "x86_64/floatundisf.S", "x86_64/floatundixf.S", ], ); diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 53844c17b49..3171e45096c 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -80,7 +80,10 @@ intrinsics! { int_to_float!(i, i32, f64) } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[use_c_shim_if(any( + all(target_arch = "x86", not(target_env = "msvc")), + all(target_arch = "x86_64", not(windows)), + ))] #[arm_aeabi_alias = __aeabi_l2f] pub extern "C" fn __floatdisf(i: i64) -> f32 { // On x86_64 LLVM will use native instructions for this conversion, we @@ -124,17 +127,19 @@ intrinsics! { int_to_float!(i, u32, f64) } - #[use_c_shim_if(all(not(target_env = "msvc"), - any(target_arch = "x86", - all(not(windows), target_arch = "x86_64"))))] + #[use_c_shim_if(any( + all(target_arch = "x86", not(target_env = "msvc")), + all(target_arch = "x86_64", not(windows)), + ))] #[arm_aeabi_alias = __aeabi_ul2f] pub extern "C" fn __floatundisf(i: u64) -> f32 { int_to_float!(i, u64, f32) } - #[use_c_shim_if(all(not(target_env = "msvc"), - any(target_arch = "x86", - all(not(windows), target_arch = "x86_64"))))] + #[use_c_shim_if(any( + all(target_arch = "x86", not(target_env = "msvc")), + all(target_arch = "x86_64", not(windows)), + ))] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float!(i, u64, f64) -- cgit 1.4.1-3-g733a5 From 6310b74d854eb354b344afbde6ea62be7fead78d Mon Sep 17 00:00:00 2001 From: Jordan Rhee Date: Thu, 5 Jul 2018 11:20:34 -0700 Subject: Support windows/arm target --- library/compiler-builtins/build.rs | 4 ++-- library/compiler-builtins/src/arm.rs | 2 +- library/compiler-builtins/src/int/sdiv.rs | 5 +++-- library/compiler-builtins/src/int/udiv.rs | 2 ++ 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index fba4091124a..111a38b5e6b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -297,7 +297,7 @@ mod c { } } - if target_arch == "arm" && target_os != "ios" { + if target_arch == "arm" && target_os != "ios" && target_env != "msvc" { sources.extend( &[ "arm/aeabi_div0.c", @@ -348,7 +348,7 @@ mod c { } } - if llvm_target[0] == "armv7" { + if llvm_target[0] == "armv7" && target_env != "msvc" { sources.extend( &[ "arm/sync_fetch_and_add_4.S", diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index dbd6f87ca52..9e43aec7d34 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -4,7 +4,7 @@ use core::intrinsics; // calling convention which can't be implemented using a normal Rust function. // NOTE The only difference between the iOS and non-iOS versions of those functions is that the iOS // versions use 3 leading underscores in the names of called functions instead of 2. -#[cfg(not(target_os = "ios"))] +#[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uidivmod() { diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 2de73b0eab7..89bb51a47b3 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -73,7 +73,8 @@ intrinsics! { } #[use_c_shim_if(all(target_arch = "arm", - not(target_os = "ios")), + not(target_os = "ios"), + not(target_env = "msvc")), not(thumbv6m))] pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { a.mod_(b) @@ -89,7 +90,7 @@ intrinsics! { a.mod_(b) } - #[use_c_shim_if(all(target_arch = "arm", + #[use_c_shim_if(all(target_arch = "arm", not(target_env = "msvc"), not(target_os = "ios"), not(thumbv6m)))] pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { a.divmod(b, rem, |a, b| __divsi3(a, b)) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 4382460e782..a2572227f97 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -211,6 +211,7 @@ intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), + not(target_env = "msvc"), not(thumbv6m)))] /// Returns `n % d` pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { @@ -220,6 +221,7 @@ intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), + not(target_env = "msvc"), not(thumbv6m)))] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { -- cgit 1.4.1-3-g733a5 From 19a7eedbf3143f77a67e177ff9e2c7670f3e9bf5 Mon Sep 17 00:00:00 2001 From: Jordan Rhee Date: Thu, 6 Sep 2018 09:24:52 -0700 Subject: Try undoing unnecessary change --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 111a38b5e6b..45060a4e6e3 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -348,7 +348,7 @@ mod c { } } - if llvm_target[0] == "armv7" && target_env != "msvc" { + if llvm_target[0] == "armv7" /* XXX && target_env != "msvc" */ { sources.extend( &[ "arm/sync_fetch_and_add_4.S", -- cgit 1.4.1-3-g733a5 From 71c5701c58f8744699690b450ca62ad53f1fc8ad Mon Sep 17 00:00:00 2001 From: Jordan Rhee Date: Fri, 7 Sep 2018 08:27:38 -0700 Subject: Remove unnecessary check --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 45060a4e6e3..87b5e049063 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -348,7 +348,7 @@ mod c { } } - if llvm_target[0] == "armv7" /* XXX && target_env != "msvc" */ { + if llvm_target[0] == "armv7" { sources.extend( &[ "arm/sync_fetch_and_add_4.S", -- cgit 1.4.1-3-g733a5 From 66d52cf01d671ad1616f067702a585d2fa9e5f1a Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sat, 8 Sep 2018 17:41:26 +0200 Subject: Remove superfluous cc flags Latest `cc-rs` already manage all arm/thumb flags, so We can safely remove this piece of code. --- library/compiler-builtins/build.rs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index fba4091124a..48d11db7cce 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -141,29 +141,6 @@ mod c { cfg.define("VISIBILITY_HIDDEN", None); } - // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going - // to target to make sure that the assembly implementations really work for the target. If - // the implementation is not valid for the arch, then gcc will error when compiling it. - if llvm_target[0].starts_with("thumb") { - cfg.flag("-mthumb"); - } - - if target_arch_arm && llvm_target.last() == Some(&"eabihf") { - cfg.flag("-mfloat-abi=hard"); - } - - if llvm_target[0] == "thumbv6m" { - cfg.flag("-march=armv6-m"); - } - - if llvm_target[0] == "thumbv7m" { - cfg.flag("-march=armv7-m"); - } - - if llvm_target[0] == "thumbv7em" { - cfg.flag("-march=armv7e-m"); - } - let mut sources = Sources::new(); sources.extend( &[ -- cgit 1.4.1-3-g733a5 From 296f04fe6342430ff44207e149ac32e93b1f62d4 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sat, 8 Sep 2018 19:04:09 +0200 Subject: Remove unused variable target_arch_arm Previous commit makes this variable unused --- library/compiler-builtins/build.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 48d11db7cce..1ace622bef4 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -110,9 +110,6 @@ mod c { let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); - let target_arch_arm = - target_arch.contains("arm") || - target_arch.contains("thumb"); let cfg = &mut cc::Build::new(); cfg.warnings(false); -- cgit 1.4.1-3-g733a5 From c03769a47e91aadf34d616d68f8a3ddfcf983d93 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Thu, 13 Sep 2018 10:10:52 +0200 Subject: `panic_handler` is now stable Fixes the following warning: "warning: the feature `panic_handler` has been stable since 1.30.0 and no longer requires an attribute to enable" --- library/compiler-builtins/crates/panic-handler/src/lib.rs | 2 +- library/compiler-builtins/examples/intrinsics.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/crates/panic-handler/src/lib.rs b/library/compiler-builtins/crates/panic-handler/src/lib.rs index e9706108737..a75999a4b60 100644 --- a/library/compiler-builtins/crates/panic-handler/src/lib.rs +++ b/library/compiler-builtins/crates/panic-handler/src/lib.rs @@ -1,6 +1,6 @@ // Hack of a crate until rust-lang/rust#51647 is fixed -#![feature(no_core, panic_handler)] +#![feature(no_core)] #![no_core] extern crate core; diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index a5be5739443..1c498176c13 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -11,7 +11,6 @@ #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] -#![feature(panic_handler)] #![cfg_attr(windows, feature(panic_unwind))] #![no_std] -- cgit 1.4.1-3-g733a5 From 620a8d4272dbb511dcbc75eeffaefaae4700a253 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Thu, 13 Sep 2018 10:31:36 +0200 Subject: Apple-darwin: set DEBUG_LTO_BUILD_DOESNT_WORK Temporary workaround for the well known "undefined references problem for debug-assertions+lto" (#79) --- library/compiler-builtins/.travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7b7ed7e6bca..9b4c28419f8 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -11,7 +11,7 @@ matrix: - env: TARGET=arm-unknown-linux-gnueabihf - env: TARGET=armv7-unknown-linux-gnueabihf - env: TARGET=i586-unknown-linux-gnu - - env: TARGET=i686-apple-darwin + - env: TARGET=i686-apple-darwin DEBUG_LTO_BUILD_DOESNT_WORK=1 os: osx - env: TARGET=i686-unknown-linux-gnu - env: TARGET=mips-unknown-linux-gnu @@ -28,7 +28,7 @@ matrix: - env: TARGET=wasm32-unknown-unknown install: rustup target add $TARGET script: cargo build --target $TARGET - - env: TARGET=x86_64-apple-darwin + - env: TARGET=x86_64-apple-darwin DEBUG_LTO_BUILD_DOESNT_WORK=1 os: osx - env: TARGET=x86_64-unknown-linux-gnu allow_failures: -- cgit 1.4.1-3-g733a5 From 45a42b5b890f2c894bff2980e1bbb03522267c23 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Mon, 17 Sep 2018 19:37:18 +0200 Subject: Conversion from a wider to a narrower IEEE-754 floating-point type Adds generic conversion from a wider to a narrower IEEE-754 floating-point type. Implement `__truncdfsf2` and `__truncdfsf2vfp` and associated test-cases. --- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/build.rs | 1 - library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/src/float/truncate.rs | 116 ++++++++++++++++++++++++ library/compiler-builtins/testcrate/build.rs | 18 ++++ 5 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/src/float/truncate.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index cae885279ad..fceaa631d55 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -129,7 +129,7 @@ features = ["c"] - [x] arm/softfloat-alias.list - [x] arm/subdf3vfp.S - [x] arm/subsf3vfp.S -- [ ] arm/truncdfsf2vfp.S +- [x] arm/truncdfsf2vfp.S - [ ] arm/udivmodsi4.S (generic version is done) - [ ] arm/udivsi3.S (generic version is done) - [ ] arm/umodsi3.S (generic version is done) @@ -186,7 +186,7 @@ features = ["c"] - [x] subdf3.c - [x] subsf3.c - [ ] truncdfhf2.c -- [ ] truncdfsf2.c +- [x] truncdfsf2.c - [ ] truncsfhf2.c - [x] udivdi3.c - [x] udivmoddi4.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6f2cc76a961..917dd963d0f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -174,7 +174,6 @@ mod c { "subvdi3.c", "subvsi3.c", "truncdfhf2.c", - "truncdfsf2.c", "truncsfhf2.c", "ucmpdi2.c", ], diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 3bb13abbc5c..2b8ddb94132 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -11,6 +11,7 @@ pub mod sub; pub mod mul; pub mod div; pub mod extend; +pub mod truncate; /// Trait for some basic operations on floats pub trait Float: diff --git a/library/compiler-builtins/src/float/truncate.rs b/library/compiler-builtins/src/float/truncate.rs new file mode 100644 index 00000000000..99d4807da8a --- /dev/null +++ b/library/compiler-builtins/src/float/truncate.rs @@ -0,0 +1,116 @@ +use float::Float; +use int::{CastInto, Int}; + +/// Generic conversion from a wider to a narrower IEEE-754 floating-point type +fn truncate(a: F) -> R +where + F::Int: CastInto, + u64: CastInto, + F::Int: CastInto, + u32: CastInto, + u32: CastInto, + R::Int: CastInto, + F::Int: CastInto, +{ + let src_one = F::Int::ONE; + let src_bits = F::BITS; + let src_sign_bits = F::SIGNIFICAND_BITS; + let src_exp_bias = F::EXPONENT_BIAS; + let src_min_normal = F::IMPLICIT_BIT; + let src_infinity = F::EXPONENT_MASK; + let src_sign_mask = F::SIGN_MASK as F::Int; + let src_abs_mask = src_sign_mask - src_one; + let src_qnan = F::SIGNIFICAND_MASK; + let src_nan_code = src_qnan - src_one; + + let dst_bits = R::BITS; + let dst_sign_bits = R::SIGNIFICAND_BITS; + let dst_inf_exp = R::EXPONENT_MAX; + let dst_exp_bias = R::EXPONENT_BIAS; + + let dst_zero = R::Int::ZERO; + let dst_one = R::Int::ONE; + let dst_qnan = R::SIGNIFICAND_MASK; + let dst_nan_code = dst_qnan - dst_one; + + let round_mask = (src_one << src_sign_bits - dst_sign_bits) - src_one; + let half = src_one << src_sign_bits - dst_sign_bits - 1; + let underflow_exp = src_exp_bias + 1 - dst_exp_bias; + let overflow_exp = src_exp_bias + dst_inf_exp - dst_exp_bias; + let underflow: F::Int = underflow_exp.cast(); // << src_sign_bits; + let overflow: F::Int = overflow_exp.cast(); //<< src_sign_bits; + + let a_abs = a.repr() & src_abs_mask; + let sign = a.repr() & src_sign_mask; + let mut abs_result: R::Int; + + let src_underflow = underflow << src_sign_bits; + let src_overflow = overflow << src_sign_bits; + + if a_abs.wrapping_sub(src_underflow) < a_abs.wrapping_sub(src_overflow) { + // The exponent of a is within the range of normal numbers + let bias_delta: R::Int = (src_exp_bias - dst_exp_bias).cast(); + abs_result = a_abs.cast(); + abs_result = abs_result >> src_sign_bits - dst_sign_bits; + abs_result = abs_result - bias_delta.wrapping_shl(dst_sign_bits); + let round_bits: F::Int = a_abs & round_mask; + abs_result += if round_bits > half { + dst_one + } else { + abs_result & dst_one + }; + } else if a_abs > src_infinity { + // a is NaN. + // Conjure the result by beginning with infinity, setting the qNaN + // bit and inserting the (truncated) trailing NaN field + let nan_result: R::Int = (a_abs & src_nan_code).cast(); + abs_result = dst_inf_exp.cast(); + abs_result = abs_result.wrapping_shl(dst_sign_bits); + abs_result |= dst_qnan; + abs_result |= (nan_result >> (src_sign_bits - dst_sign_bits)) & dst_nan_code; + } else if a_abs >= src_overflow { + // a overflows to infinity. + abs_result = dst_inf_exp.cast(); + abs_result = abs_result.wrapping_shl(dst_sign_bits); + } else { + // a underflows on conversion to the destination type or is an exact + // zero. The result may be a denormal or zero. Extract the exponent + // to get the shift amount for the denormalization. + let a_exp = a_abs >> src_sign_bits; + let mut shift: u32 = a_exp.cast(); + shift = src_exp_bias - dst_exp_bias - shift + 1; + + let significand = (a.repr() & src_sign_mask) | src_min_normal; + if shift > src_sign_bits { + abs_result = dst_zero; + } else { + let sticky = significand << src_bits - shift; + let mut denormalized_significand: R::Int = significand.cast(); + let sticky_shift: u32 = sticky.cast(); + denormalized_significand = denormalized_significand >> (shift | sticky_shift); + abs_result = denormalized_significand >> src_sign_bits - dst_sign_bits; + let round_bits = denormalized_significand & round_mask.cast(); + if round_bits > half.cast() { + abs_result += dst_one; // Round to nearest + } else if round_bits == half.cast() { + abs_result += abs_result & dst_one; // Ties to even + } + } + } + // Finally apply the sign bit + let s = sign >> src_bits - dst_bits; + R::from_repr(abs_result | s.cast()) +} + +intrinsics! { + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_d2f] + pub extern "C" fn __truncdfsf2(a: f64) -> f32 { + truncate(a) + } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __truncdfsf2vfp(a: f64) -> f32 { + a as f32 + } +} diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index d862e0d0ffb..f02a67cc32a 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -348,6 +348,24 @@ fn main() { "builtins::float::extend::__extendsfdf2vfp(a)"); } + // float/truncate.rs + gen(|a: MyF64| { + if a.0.is_nan() { + return None; + } + Some(a.0 as f32) + }, + "builtins::float::truncate::__truncdfsf2(a)"); + if target_arch_arm { + gen(|a: LargeF64| { + if a.0.is_nan() { + return None; + } + Some(a.0 as f32) + }, + "builtins::float::truncate::__truncdfsf2vfp(a)"); + } + // float/conv.rs gen(|a: MyF64| i64(a.0).ok(), "builtins::float::conv::__fixdfdi(a)"); -- cgit 1.4.1-3-g733a5 From 9b03920fe17ddb1e61a179a7a83fcb00ce740e98 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 11 Oct 2018 14:43:19 -0700 Subject: Optimize intrinsics on wasm32 Profiling a recent demo I was playing with on `wasm32-unknown-unknown` pointed me to the surprising result that 15% of the execution time was in the `sqrt` intrinsic (there's a lot of math here). Upon investigation I remembered that wasm (unconditionally) has a native `f32.sqrt` instruction! I was then subsequently confused that a simple `f.sqrt()` actually codegens to use `f32.sqrt` in Rust, but I later realized that the implementations of intrinsics in this library often use other intrinsics to implement them. That means that the real intrinsic here, `acos`, internally called `sqrt` at some point but wasn't using the optimized implementation! To help fix this situation this PR is intended on providing the infrastructure for optimized implementations (via code generation) to be used for each intrinsic. I've gone thorugh the various math instructions that wasm has available and updated each of the intrinsic implementations in this crate to optionally use the LLVM intrinsic versions, which are known to unconditionally compile down to a single instruction (unlike the arbitrary platform, where we don't know what it will compile down to!). To do this I created a new macro to wrap the invocation of LLVM intrinsics. Invoking LLVM intrinsics is turned off by default (through a new and on-by-default feature, `stable`). When the `stable` feature is disabled, however, then the wasm-target specifically will enable usage of the LLVM intrinsics. I've additionally added a CI builder which should verify that these continue to build on Travis. After this I intended to update the submodule in the `compiler-builtins` repository so we can pull in the optimized implementation there, and `compiler-builtins` naturally won't set `feature = "stable"` when compiling so all the intrinsics should get compiled in by default. After a further update of `the libcompiler_builtins` submodule in rust-lang/rust we should be good to go! --- library/compiler-builtins/libm/.travis.yml | 7 +++++++ library/compiler-builtins/libm/Cargo.toml | 4 ++++ library/compiler-builtins/libm/src/lib.rs | 4 ++++ library/compiler-builtins/libm/src/math/ceil.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/ceilf.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/fabs.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/fabsf.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/floor.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/floorf.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/mod.rs | 11 +++++++++++ library/compiler-builtins/libm/src/math/sqrt.rs | 12 ++++++++++++ library/compiler-builtins/libm/src/math/sqrtf.rs | 12 ++++++++++++ library/compiler-builtins/libm/src/math/trunc.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/truncf.rs | 8 ++++++++ 14 files changed, 114 insertions(+) diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index 47f2b2f205d..75831617819 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -29,6 +29,13 @@ matrix: - env: TARGET=cargo-fmt rust: beta + - env: TARGET=wasm32-unknown-unknown + rust: nightly + install: rustup target add $TARGET + script: + - cargo build --target $TARGET + - cargo build --no-default-features --target $TARGET + before_install: set -e install: diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index cedf8d267db..f7a52833424 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -24,3 +24,7 @@ members = [ [dev-dependencies] shared = { path = "shared" } + +[features] +default = ['stable'] +stable = [] diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 627c6443e3d..6be45872819 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -11,6 +11,10 @@ #![deny(warnings)] #![no_std] +#![cfg_attr( + all(target_arch = "wasm32", not(feature = "stable")), + feature(core_intrinsics) +)] mod math; diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 4db2ca84036..5dbfa6a2c0a 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -4,6 +4,14 @@ const TOINT: f64 = 1. / f64::EPSILON; #[inline] pub fn ceil(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.ceil` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::ceilf64(x) } + } + } let u: u64 = x.to_bits(); let e: i64 = (u >> 52 & 0x7ff) as i64; let y: f64; diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 16bffb3002e..c8cd4b5aa5b 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -2,6 +2,14 @@ use core::f32; #[inline] pub fn ceilf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.ceil` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::ceilf32(x) } + } + } let mut ui = x.to_bits(); let e = (((ui >> 23) & 0xff) - 0x7f) as i32; diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 9e081f3f9f6..7c804653c99 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -2,5 +2,13 @@ use core::u64; #[inline] pub fn fabs(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.abs` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::fabsf64(x) } + } + } f64::from_bits(x.to_bits() & (u64::MAX / 2)) } diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 4cc9411169a..884c20f6c41 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -1,4 +1,12 @@ #[inline] pub fn fabsf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.abs` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::fabsf32(x) } + } + } f32::from_bits(x.to_bits() & 0x7fffffff) } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index 997865d39e9..b14a48d55bc 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -4,6 +4,14 @@ const TOINT: f64 = 1. / f64::EPSILON; #[inline] pub fn floor(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.floor` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::floorf64(x) } + } + } let ui = x.to_bits(); let e = ((ui >> 52) & 0x7ff) as i32; diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 9c263b51828..71b5953df3e 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -2,6 +2,14 @@ use core::f32; #[inline] pub fn floorf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.floor` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::floorf32(x) } + } + } let mut ui = x.to_bits(); let e = (((ui >> 23) & 0xff) - 0x7f) as i32; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index da34fb4cecd..e51b1511dfc 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -58,6 +58,17 @@ macro_rules! i { }; } +macro_rules! llvm_intrinsically_optimized { + (#[cfg($($clause:tt)*)] $e:expr) => { + #[cfg(all(not(feature = "stable"), $($clause)*))] + { + if true { // thwart the dead code lint + $e + } + } + }; +} + // Public modules mod acos; mod acosf; diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index cbadb49bba0..b2387a26e75 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -82,6 +82,18 @@ const TINY: f64 = 1.0e-300; #[inline] pub fn sqrt(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.sqrt` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return if x < 0.0 { + f64::NAN + } else { + unsafe { ::core::intrinsics::sqrtf64(x) } + } + } + } let mut z: f64; let sign: u32 = 0x80000000; let mut ix0: i32; diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 49984689efc..33cafbcbda3 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -17,6 +17,18 @@ const TINY: f32 = 1.0e-30; #[inline] pub fn sqrtf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.sqrt` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return if x < 0.0 { + ::core::f32::NAN + } else { + unsafe { ::core::intrinsics::sqrtf32(x) } + } + } + } let mut z: f32; let sign: i32 = 0x80000000u32 as i32; let mut ix: i32; diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 6bea67cbc16..8eecfcf538e 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -2,6 +2,14 @@ use core::f64; #[inline] pub fn trunc(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.trunc` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::truncf64(x) } + } + } let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 let mut i: u64 = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index 9d42620d966..0d74fea9c9e 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -2,6 +2,14 @@ use core::f32; #[inline] pub fn truncf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.trunc` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::truncf32(x) } + } + } let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 let mut i: u32 = x.to_bits(); -- cgit 1.4.1-3-g733a5 From 5c6fd41b3deab08ab7cbbfec15bc8ce5af593a1c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 24 Oct 2018 00:18:30 +0200 Subject: merge [features] tables --- library/compiler-builtins/libm/Cargo.toml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index f7a52833424..f28024d041c 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -12,6 +12,8 @@ version = "0.1.2" [features] # only used to run our test suite checked = [] +default = ['stable'] +stable = [] [workspace] members = [ @@ -24,7 +26,3 @@ members = [ [dev-dependencies] shared = { path = "shared" } - -[features] -default = ['stable'] -stable = [] -- cgit 1.4.1-3-g733a5 From b387ac07b1bc26f829bb686868e2cce4d2cd9751 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 24 Oct 2018 01:01:14 -0700 Subject: Update libm submodule --- library/compiler-builtins/.gitmodules | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index 7162b2c4d5b..50ed51e937b 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -3,4 +3,4 @@ url = https://github.com/rust-lang/compiler-rt [submodule "libm"] path = libm - url = https://github.com/japaric/libm + url = https://github.com/rust-lang-nursery/libm diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 96e36ea2620..3559e703795 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 96e36ea2620f9fbbaa46a01694a2fa3ef6c2fb7e +Subproject commit 3559e703795d33e84a91da2a35f2f3baac47e872 -- cgit 1.4.1-3-g733a5 From dbdcd66e3579a187dba001dca5102ea0a7996a81 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 30 Oct 2018 10:51:11 -0700 Subject: Revert "Conversion from a wider to a narrower IEEE-754 floating-point type" This reverts commit baab4fd89cdd945e46fed31166e5dcad7224ed87. --- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/build.rs | 1 + library/compiler-builtins/src/float/mod.rs | 1 - library/compiler-builtins/src/float/truncate.rs | 116 ------------------------ library/compiler-builtins/testcrate/build.rs | 18 ---- 5 files changed, 3 insertions(+), 137 deletions(-) delete mode 100644 library/compiler-builtins/src/float/truncate.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index fceaa631d55..cae885279ad 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -129,7 +129,7 @@ features = ["c"] - [x] arm/softfloat-alias.list - [x] arm/subdf3vfp.S - [x] arm/subsf3vfp.S -- [x] arm/truncdfsf2vfp.S +- [ ] arm/truncdfsf2vfp.S - [ ] arm/udivmodsi4.S (generic version is done) - [ ] arm/udivsi3.S (generic version is done) - [ ] arm/umodsi3.S (generic version is done) @@ -186,7 +186,7 @@ features = ["c"] - [x] subdf3.c - [x] subsf3.c - [ ] truncdfhf2.c -- [x] truncdfsf2.c +- [ ] truncdfsf2.c - [ ] truncsfhf2.c - [x] udivdi3.c - [x] udivmoddi4.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 917dd963d0f..6f2cc76a961 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -174,6 +174,7 @@ mod c { "subvdi3.c", "subvsi3.c", "truncdfhf2.c", + "truncdfsf2.c", "truncsfhf2.c", "ucmpdi2.c", ], diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 2b8ddb94132..3bb13abbc5c 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -11,7 +11,6 @@ pub mod sub; pub mod mul; pub mod div; pub mod extend; -pub mod truncate; /// Trait for some basic operations on floats pub trait Float: diff --git a/library/compiler-builtins/src/float/truncate.rs b/library/compiler-builtins/src/float/truncate.rs deleted file mode 100644 index 99d4807da8a..00000000000 --- a/library/compiler-builtins/src/float/truncate.rs +++ /dev/null @@ -1,116 +0,0 @@ -use float::Float; -use int::{CastInto, Int}; - -/// Generic conversion from a wider to a narrower IEEE-754 floating-point type -fn truncate(a: F) -> R -where - F::Int: CastInto, - u64: CastInto, - F::Int: CastInto, - u32: CastInto, - u32: CastInto, - R::Int: CastInto, - F::Int: CastInto, -{ - let src_one = F::Int::ONE; - let src_bits = F::BITS; - let src_sign_bits = F::SIGNIFICAND_BITS; - let src_exp_bias = F::EXPONENT_BIAS; - let src_min_normal = F::IMPLICIT_BIT; - let src_infinity = F::EXPONENT_MASK; - let src_sign_mask = F::SIGN_MASK as F::Int; - let src_abs_mask = src_sign_mask - src_one; - let src_qnan = F::SIGNIFICAND_MASK; - let src_nan_code = src_qnan - src_one; - - let dst_bits = R::BITS; - let dst_sign_bits = R::SIGNIFICAND_BITS; - let dst_inf_exp = R::EXPONENT_MAX; - let dst_exp_bias = R::EXPONENT_BIAS; - - let dst_zero = R::Int::ZERO; - let dst_one = R::Int::ONE; - let dst_qnan = R::SIGNIFICAND_MASK; - let dst_nan_code = dst_qnan - dst_one; - - let round_mask = (src_one << src_sign_bits - dst_sign_bits) - src_one; - let half = src_one << src_sign_bits - dst_sign_bits - 1; - let underflow_exp = src_exp_bias + 1 - dst_exp_bias; - let overflow_exp = src_exp_bias + dst_inf_exp - dst_exp_bias; - let underflow: F::Int = underflow_exp.cast(); // << src_sign_bits; - let overflow: F::Int = overflow_exp.cast(); //<< src_sign_bits; - - let a_abs = a.repr() & src_abs_mask; - let sign = a.repr() & src_sign_mask; - let mut abs_result: R::Int; - - let src_underflow = underflow << src_sign_bits; - let src_overflow = overflow << src_sign_bits; - - if a_abs.wrapping_sub(src_underflow) < a_abs.wrapping_sub(src_overflow) { - // The exponent of a is within the range of normal numbers - let bias_delta: R::Int = (src_exp_bias - dst_exp_bias).cast(); - abs_result = a_abs.cast(); - abs_result = abs_result >> src_sign_bits - dst_sign_bits; - abs_result = abs_result - bias_delta.wrapping_shl(dst_sign_bits); - let round_bits: F::Int = a_abs & round_mask; - abs_result += if round_bits > half { - dst_one - } else { - abs_result & dst_one - }; - } else if a_abs > src_infinity { - // a is NaN. - // Conjure the result by beginning with infinity, setting the qNaN - // bit and inserting the (truncated) trailing NaN field - let nan_result: R::Int = (a_abs & src_nan_code).cast(); - abs_result = dst_inf_exp.cast(); - abs_result = abs_result.wrapping_shl(dst_sign_bits); - abs_result |= dst_qnan; - abs_result |= (nan_result >> (src_sign_bits - dst_sign_bits)) & dst_nan_code; - } else if a_abs >= src_overflow { - // a overflows to infinity. - abs_result = dst_inf_exp.cast(); - abs_result = abs_result.wrapping_shl(dst_sign_bits); - } else { - // a underflows on conversion to the destination type or is an exact - // zero. The result may be a denormal or zero. Extract the exponent - // to get the shift amount for the denormalization. - let a_exp = a_abs >> src_sign_bits; - let mut shift: u32 = a_exp.cast(); - shift = src_exp_bias - dst_exp_bias - shift + 1; - - let significand = (a.repr() & src_sign_mask) | src_min_normal; - if shift > src_sign_bits { - abs_result = dst_zero; - } else { - let sticky = significand << src_bits - shift; - let mut denormalized_significand: R::Int = significand.cast(); - let sticky_shift: u32 = sticky.cast(); - denormalized_significand = denormalized_significand >> (shift | sticky_shift); - abs_result = denormalized_significand >> src_sign_bits - dst_sign_bits; - let round_bits = denormalized_significand & round_mask.cast(); - if round_bits > half.cast() { - abs_result += dst_one; // Round to nearest - } else if round_bits == half.cast() { - abs_result += abs_result & dst_one; // Ties to even - } - } - } - // Finally apply the sign bit - let s = sign >> src_bits - dst_bits; - R::from_repr(abs_result | s.cast()) -} - -intrinsics! { - #[aapcs_on_arm] - #[arm_aeabi_alias = __aeabi_d2f] - pub extern "C" fn __truncdfsf2(a: f64) -> f32 { - truncate(a) - } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __truncdfsf2vfp(a: f64) -> f32 { - a as f32 - } -} diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index f02a67cc32a..d862e0d0ffb 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -348,24 +348,6 @@ fn main() { "builtins::float::extend::__extendsfdf2vfp(a)"); } - // float/truncate.rs - gen(|a: MyF64| { - if a.0.is_nan() { - return None; - } - Some(a.0 as f32) - }, - "builtins::float::truncate::__truncdfsf2(a)"); - if target_arch_arm { - gen(|a: LargeF64| { - if a.0.is_nan() { - return None; - } - Some(a.0 as f32) - }, - "builtins::float::truncate::__truncdfsf2vfp(a)"); - } - // float/conv.rs gen(|a: MyF64| i64(a.0).ok(), "builtins::float::conv::__fixdfdi(a)"); -- cgit 1.4.1-3-g733a5 From 330bb3a744de533597d18cded2373c71bd781c41 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 9 Nov 2018 12:52:21 -0800 Subject: Update for next LLVM 8 version --- library/compiler-builtins/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index 7e387f0f90b..84c0bd0158c 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit 7e387f0f90b493ae72930c787c381a80055a7ec9 +Subproject commit 84c0bd0158c3ff86052be1b07a3ddc3c4f5ba52a -- cgit 1.4.1-3-g733a5 From 6582b145b8404d4b61ff60123014e9158931c344 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Wed, 21 Nov 2018 14:07:03 +0530 Subject: Add f32 versions of WebAssembly math functions --- library/compiler-builtins/src/math.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 6eddc3d78ab..9db7a0aa3d6 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -51,6 +51,19 @@ no_mangle! { fn fmodf(x: f32, y: f32) -> f32; fn fma(x: f64, y: f64, z: f64) -> f64; fn fmaf(x: f32, y: f32, z: f32) -> f32; + fn acosf(n: f32) -> f32; + fn asinf(n: f32) -> f32; + fn atan2f(a: f32, b: f32) -> f32; + fn atanf(n: f32) -> f32; + fn cbrtf(n: f32) -> f32; + fn coshf(n: f32) -> f32; + fn expm1f(n: f32) -> f32; + fn fdimf(a: f32, b: f32) -> f32; + fn hypotf(x: f32, y: f32) -> f32; + fn log1pf(n: f32) -> f32; + fn sinhf(n: f32) -> f32; + fn tanf(n: f32) -> f32; + fn tanhf(n: f32) -> f32; } // only for the thumb*-none-eabi* targets -- cgit 1.4.1-3-g733a5 From 3880e404a8b53ed9312a4272bc2ae7653e05dc23 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Wed, 21 Nov 2018 14:07:57 +0530 Subject: Add SGX target --- library/compiler-builtins/build.rs | 4 ++-- library/compiler-builtins/src/lib.rs | 3 ++- library/compiler-builtins/src/math.rs | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6f2cc76a961..f5ada024f41 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -17,9 +17,9 @@ fn main() { return; } - // Forcibly enable memory intrinsics on wasm32 as we don't have a libc to + // Forcibly enable memory intrinsics on wasm32 & SGX as we don't have a libc to // provide them. - if target.contains("wasm32") { + if target.contains("wasm32") || target.contains("sgx") { println!("cargo:rustc-cfg=feature=\"mem\""); } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 9f1dd15120c..9bb38f39aa2 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -48,7 +48,8 @@ pub mod int; pub mod float; #[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), - all(target_arch = "arm", target_os = "none")))] + all(target_arch = "arm", target_os = "none"), + target_env = "sgx"))] pub mod math; pub mod mem; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 9db7a0aa3d6..c37243504b1 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -15,7 +15,7 @@ macro_rules! no_mangle { } // only for the wasm32-unknown-unknown target -#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] +#[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), target_env = "sgx"))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; -- cgit 1.4.1-3-g733a5 From 59fb3fd69c2e0b97890fa4a707bd57bd267ba5f8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 19 Nov 2018 22:02:13 -0800 Subject: Prepare for publication to crates.io This commit prepares to publish the compiler-builtins crate to crates.io in order for the standard library to directly depend on it from crates.io in rust-lang/rust#56092 --- library/compiler-builtins/Cargo.toml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7eae2dc1f28..0bbd22e463a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -6,6 +6,11 @@ version = "0.1.0" [lib] test = false +[dependencies] +# For more information on this dependency see rust-lang/rust's +# `src/tools/rustc-std-workspace` folder +core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } + [build-dependencies] cc = { optional = true, version = "1.0" } @@ -32,6 +37,9 @@ mangled-names = [] # Don't generate lang items for i128 intrisnics and such no-lang-items = [] +# Only used in the compiler's build system +rustc-dep-of-std = ['c', 'compiler-builtins', 'core'] + [[example]] name = "intrinsics" required-features = ["c", "compiler-builtins"] -- cgit 1.4.1-3-g733a5 From 9fdc957019b94922c303071945fac62c4ee50079 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 10:19:31 -0800 Subject: Use panic=abort for tests Try to fix issues with undefined `rust_eh_personality` symbols --- library/compiler-builtins/Cargo.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0bbd22e463a..a7f34c007a6 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -46,3 +46,9 @@ required-features = ["c", "compiler-builtins"] [workspace] members = ["testcrate"] + +[profile.release] +panic = 'abort' + +[profile.dev] +panic = 'abort' -- cgit 1.4.1-3-g733a5 From 1af471e00b32a849703b366962a594faf5e5d2b1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 10:48:58 -0800 Subject: Use `nm` on OSX Looks like it may be fixed now? --- library/compiler-builtins/ci/run.sh | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 8c85038f97a..b77752288d9 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -64,18 +64,7 @@ case $1 in ;; esac -case "$TRAVIS_OS_NAME" in - osx) - # NOTE OSx's nm doesn't accept the `--defined-only` or provide an equivalent. - # Use GNU nm instead - NM=gnm - brew update - brew install binutils - ;; - *) - NM=nm - ;; -esac +NM=nm if [ -d /target ]; then path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib -- cgit 1.4.1-3-g733a5 From e367858b0e627ff824428c906094b47cc9dfbfee Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 11:07:07 -0800 Subject: Remove unknown feature --- library/compiler-builtins/examples/intrinsics.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 1c498176c13..c1a781415ed 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -11,7 +11,6 @@ #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] -#![cfg_attr(windows, feature(panic_unwind))] #![no_std] extern crate panic_handler; -- cgit 1.4.1-3-g733a5 From d90aa8c244a9de892d93735f1123cab2e3bb5640 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 11:09:24 -0800 Subject: Add some crate metadata --- library/compiler-builtins/Cargo.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index a7f34c007a6..97cad699cb9 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -2,6 +2,15 @@ authors = ["Jorge Aparicio "] name = "compiler_builtins" version = "0.1.0" +license = "MIT/Apache-2.0" +readme = "README.md" +repository = "https://github.com/rust-lang-nursery/compiler-builtins" +homepage = "https://github.com/rust-lang-nursery/compiler-builtins" +documentation = "https://docs.rs/compiler_builtins" +description = """ +Compiler intrinsics used by the Rust compiler. Also available for other targets +if necessary! +""" [lib] test = false -- cgit 1.4.1-3-g733a5 From 9690d3a17ecfd0548b60157a83d5c29352a483da Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 11:56:04 -0800 Subject: Try to fix Windows build issue --- library/compiler-builtins/examples/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index c1a781415ed..c52b4f0d768 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -15,7 +15,7 @@ extern crate panic_handler; -#[cfg(not(thumb))] +#[cfg(all(not(thumb), not(windows)))] #[link(name = "c")] extern {} -- cgit 1.4.1-3-g733a5 From 08db8f31d38ce77e0562cf2a9a07ba6cf4949408 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 12:55:06 -0800 Subject: Add metadata for where compiler-rt is located Compiler crates will need to use this! --- library/compiler-builtins/Cargo.toml | 1 + library/compiler-builtins/build.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 97cad699cb9..5b9469b3d2b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -11,6 +11,7 @@ description = """ Compiler intrinsics used by the Rust compiler. Also available for other targets if necessary! """ +links = 'compiler-rt' [lib] test = false diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index f5ada024f41..752bba1343f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4,6 +4,9 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").unwrap(); + let cwd = env::current_dir().unwrap(); + + println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); // Emscripten's runtime includes all the builtins if target.contains("emscripten") { -- cgit 1.4.1-3-g733a5 From 018fa133fd41781426a7f096e9766ec7a97ac124 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 12:57:14 -0800 Subject: Add a whitelist of included files in packaging --- library/compiler-builtins/Cargo.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 5b9469b3d2b..13d0b18e35b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -11,6 +11,16 @@ description = """ Compiler intrinsics used by the Rust compiler. Also available for other targets if necessary! """ +include = [ + '/Cargo.toml', + '/build.rs', + '/src/*', + '/examples/*', + '/LICENSE.txt', + '/README.md', + '/compiler-rt/*', + '/libm/src/math/*', +] links = 'compiler-rt' [lib] -- cgit 1.4.1-3-g733a5 From 693a2636607c8fce4d6a7922722d092aaed58621 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 12:57:54 -0800 Subject: Bump to 0.1.1 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 13d0b18e35b..cf996ef2f44 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.0" +version = "0.1.1" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From b29ccbb6e9e25565b18be8716de504b128c43fdd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 26 Nov 2018 12:09:10 -0800 Subject: Bump to 0.1.2 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index cf996ef2f44..07afd304686 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.1" +version = "0.1.2" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 1a1dd89a320a55e1f0927088aa8fb194feef3118 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 20 Dec 2018 17:47:57 -0700 Subject: start of __clzsi2 --- library/compiler-builtins/src/arm.rs | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 9e43aec7d34..111e6974f34 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -233,3 +233,61 @@ pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } + +#[no_mangle] +#[cfg(any(target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64"))] +pub extern "C" fn __clzsi2(mut x: usize) -> usize { + // TODO: const this? Requires const if + let mut y: usize; + let mut n: usize = { + #[cfg(target_pointer_width = "64")] + { + 64 + } + #[cfg(target_pointer_width = "32")] + { + 32 + } + #[cfg(target_pointer_width = "16")] + { + 16 + } + }; + #[cfg(target_pointer_width = "64")] + { + y = x >> 32; + if y != 0 { + n -= 32; + x = y; + } + } + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + y = x >> 16; + if y != 0 { + n -= 16; + x = y; + } + } + y = x >> 8; + if y != 0 { + n -= 8; + x = y; + } + y = x >> 4; + if y != 0 { + n -= 4; + x = y; + } + y = x >> 2; + if y != 0 { + n -= 2; + x = y; + } + y = x >> 1; + if y != 0 { + n - 2 + } else { + n - x + } +} -- cgit 1.4.1-3-g733a5 From 9e1de34b4e36078c0f12c1e11c6981c5aadf7f7d Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 20 Dec 2018 17:53:10 -0700 Subject: modify to fit into standard rustfmt output --- library/compiler-builtins/src/arm.rs | 92 +++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 111e6974f34..009b1ff69f5 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -235,59 +235,63 @@ pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { } #[no_mangle] -#[cfg(any(target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64"))] +#[cfg(any( + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64" +))] pub extern "C" fn __clzsi2(mut x: usize) -> usize { - // TODO: const this? Requires const if - let mut y: usize; - let mut n: usize = { + // TODO: const this? Requires const if + let mut y: usize; + let mut n: usize = { + #[cfg(target_pointer_width = "64")] + { + 64 + } + #[cfg(target_pointer_width = "32")] + { + 32 + } + #[cfg(target_pointer_width = "16")] + { + 16 + } + }; #[cfg(target_pointer_width = "64")] { - 64 + y = x >> 32; + if y != 0 { + n -= 32; + x = y; + } } - #[cfg(target_pointer_width = "32")] + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] { - 32 + y = x >> 16; + if y != 0 { + n -= 16; + x = y; + } } - #[cfg(target_pointer_width = "16")] - { - 16 + y = x >> 8; + if y != 0 { + n -= 8; + x = y; + } + y = x >> 4; + if y != 0 { + n -= 4; + x = y; } - }; - #[cfg(target_pointer_width = "64")] - { - y = x >> 32; + y = x >> 2; if y != 0 { - n -= 32; - x = y; + n -= 2; + x = y; } - } - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { - y = x >> 16; + y = x >> 1; if y != 0 { - n -= 16; - x = y; + n - 2 + } else { + n - x } - } - y = x >> 8; - if y != 0 { - n -= 8; - x = y; - } - y = x >> 4; - if y != 0 { - n -= 4; - x = y; - } - y = x >> 2; - if y != 0 { - n -= 2; - x = y; - } - y = x >> 1; - if y != 0 { - n - 2 - } else { - n - x - } } -- cgit 1.4.1-3-g733a5 From 86de7413562fffb54e69a1d6c855b6d9f336d5c2 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 21 Dec 2018 18:02:12 -0700 Subject: Move clzi2 into the int module --- library/compiler-builtins/src/arm.rs | 62 -------------------------------- library/compiler-builtins/src/int/mod.rs | 62 ++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 009b1ff69f5..9e43aec7d34 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -233,65 +233,3 @@ pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } - -#[no_mangle] -#[cfg(any( - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64" -))] -pub extern "C" fn __clzsi2(mut x: usize) -> usize { - // TODO: const this? Requires const if - let mut y: usize; - let mut n: usize = { - #[cfg(target_pointer_width = "64")] - { - 64 - } - #[cfg(target_pointer_width = "32")] - { - 32 - } - #[cfg(target_pointer_width = "16")] - { - 16 - } - }; - #[cfg(target_pointer_width = "64")] - { - y = x >> 32; - if y != 0 { - n -= 32; - x = y; - } - } - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { - y = x >> 16; - if y != 0 { - n -= 16; - x = y; - } - } - y = x >> 8; - if y != 0 { - n -= 8; - x = y; - } - y = x >> 4; - if y != 0 { - n -= 4; - x = y; - } - y = x >> 2; - if y != 0 { - n -= 2; - x = y; - } - y = x >> 1; - if y != 0 { - n - 2 - } else { - n - x - } -} diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index b645b214540..11fd49bbc88 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -300,3 +300,65 @@ macro_rules! impl_wide_int { impl_wide_int!(u32, u64, 32); impl_wide_int!(u64, u128, 64); + +#[no_mangle] +#[cfg(any( + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64" +))] +pub extern "C" fn __clzsi2(mut x: usize) -> usize { + // TODO: const this? Would require const-if + let mut y: usize; + let mut n: usize = { + #[cfg(target_pointer_width = "64")] + { + 64 + } + #[cfg(target_pointer_width = "32")] + { + 32 + } + #[cfg(target_pointer_width = "16")] + { + 16 + } + }; + #[cfg(target_pointer_width = "64")] + { + y = x >> 32; + if y != 0 { + n -= 32; + x = y; + } + } + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + y = x >> 16; + if y != 0 { + n -= 16; + x = y; + } + } + y = x >> 8; + if y != 0 { + n -= 8; + x = y; + } + y = x >> 4; + if y != 0 { + n -= 4; + x = y; + } + y = x >> 2; + if y != 0 { + n -= 2; + x = y; + } + y = x >> 1; + if y != 0 { + n - 2 + } else { + n - x + } +} -- cgit 1.4.1-3-g733a5 From a57c899eb118da796e045f6ea43d7c941081760e Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 21 Dec 2018 18:10:45 -0700 Subject: trying a test case for clzsi2 --- library/compiler-builtins/testcrate/build.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index d862e0d0ffb..08c14fda533 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -775,6 +775,12 @@ fn main() { (builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) }"); } + + // count leading zeros + gen(|(a): (usize)| { + Some(a.leading_zeros()) + }, + "builtins::int::__clzsi2(a)"); } macro_rules! gen_float { -- cgit 1.4.1-3-g733a5 From 734b5c261ac295a266bcdd8424a2a3072f2aeef5 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 21 Dec 2018 18:20:59 -0700 Subject: We can't accept usize directly, i guess accept `MyU64`? --- library/compiler-builtins/testcrate/build.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 08c14fda533..0fa2f5631b9 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -777,10 +777,12 @@ fn main() { } // count leading zeros - gen(|(a): (usize)| { - Some(a.leading_zeros()) + gen(|a: MyU128| { + Some((a as usize).leading_zeros()) }, - "builtins::int::__clzsi2(a)"); + "{ + builtins::int::__clzsi2(a as usize) + }"); } macro_rules! gen_float { -- cgit 1.4.1-3-g733a5 From e495054f893683f3a2f48dbd2d65ba8a7eaf1733 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 21 Dec 2018 18:21:47 -0700 Subject: 64, not 128! --- library/compiler-builtins/testcrate/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 0fa2f5631b9..292d36a77ac 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -777,7 +777,7 @@ fn main() { } // count leading zeros - gen(|a: MyU128| { + gen(|a: MyU64| { Some((a as usize).leading_zeros()) }, "{ -- cgit 1.4.1-3-g733a5 From e5123b4625094408749422dfc262a0a32bdaa348 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 21 Dec 2018 18:36:26 -0700 Subject: forgot the little `.0` part --- library/compiler-builtins/testcrate/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 292d36a77ac..1a5105407e4 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -778,7 +778,7 @@ fn main() { // count leading zeros gen(|a: MyU64| { - Some((a as usize).leading_zeros()) + Some((a.0 as usize).leading_zeros()) }, "{ builtins::int::__clzsi2(a as usize) -- cgit 1.4.1-3-g733a5 From fe9b17acec9b1e0d2028ab997ca5768708bd2867 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 21 Dec 2018 18:47:03 -0700 Subject: Rust and LLVM don't spec the same output types --- library/compiler-builtins/testcrate/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 1a5105407e4..4f10adcf029 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -778,7 +778,7 @@ fn main() { // count leading zeros gen(|a: MyU64| { - Some((a.0 as usize).leading_zeros()) + Some((a.0 as usize).leading_zeros() as usize) }, "{ builtins::int::__clzsi2(a as usize) -- cgit 1.4.1-3-g733a5 From d422c9a587d1ebd051f45dd1b6fd6d003ee0856c Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 21 Dec 2018 18:55:01 -0700 Subject: Okay we'll process outputs as all u32 --- library/compiler-builtins/testcrate/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 4f10adcf029..c18daca2458 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -778,10 +778,10 @@ fn main() { // count leading zeros gen(|a: MyU64| { - Some((a.0 as usize).leading_zeros() as usize) + Some((a.0 as usize).leading_zeros()) }, "{ - builtins::int::__clzsi2(a as usize) + builtins::int::__clzsi2(a as usize) as u32 }"); } -- cgit 1.4.1-3-g733a5 From f1971b5b710a35c758e5662af904b4e28f7426ff Mon Sep 17 00:00:00 2001 From: akashfortanix Date: Thu, 27 Dec 2018 19:13:50 +0530 Subject: expose ceil, floor and trunc on sgx-target --- library/compiler-builtins/src/math.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index c37243504b1..e2b15c6a7b5 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -66,6 +66,16 @@ no_mangle! { fn tanhf(n: f32) -> f32; } +#[cfg(target_env = "sgx")] +no_mangle! { + fn ceil(x: f64) -> f64; + fn ceilf(x: f32) -> f32; + fn floor(x: f64) -> f64; + fn floorf(x: f32) -> f32; + fn trunc(x: f64) -> f64; + fn truncf(x: f32) -> f32; +} + // only for the thumb*-none-eabi* targets #[cfg(all(target_arch = "arm", target_os = "none"))] no_mangle! { -- cgit 1.4.1-3-g733a5 From b549e21009f1341fee325938a2a1f7df66b5671c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 2 Jan 2019 10:21:41 -0800 Subject: Bump to 0.1.3 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 07afd304686..32cc2681d7a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.2" +version = "0.1.3" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From a68950646f9ff08e7dce7e5b110a2a3d2f7fc01f Mon Sep 17 00:00:00 2001 From: Lokathor Date: Wed, 2 Jan 2019 18:50:11 -0700 Subject: Move the test to be a standard test. --- library/compiler-builtins/testcrate/build.rs | 8 ------- .../testcrate/tests/count_leading_zeros.rs | 25 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/testcrate/tests/count_leading_zeros.rs diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index c18daca2458..d862e0d0ffb 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -775,14 +775,6 @@ fn main() { (builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) }"); } - - // count leading zeros - gen(|a: MyU64| { - Some((a.0 as usize).leading_zeros()) - }, - "{ - builtins::int::__clzsi2(a as usize) as u32 - }"); } macro_rules! gen_float { diff --git a/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs b/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs new file mode 100644 index 00000000000..55965017454 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs @@ -0,0 +1,25 @@ +#![feature(compiler_builtins_lib)] + +extern crate compiler_builtins; + +use compiler_builtins::int::__clzsi2; + +#[test] +fn __clzsi2_test() { + let mut i: usize = core::usize::MAX; + // Check all values above 0 + while i > 0 { + assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); + i >>= 1; + } + // check 0 also + i = 0; + assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); + // double check for bit patterns that aren't just solid 1s + i = 1; + for _ in 0..63 { + assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); + i <<= 2; + i += 1; + } +} -- cgit 1.4.1-3-g733a5 From c5dc23d75d36f414a47034d9510fec56d84ae2b0 Mon Sep 17 00:00:00 2001 From: Yu Ding Date: Thu, 3 Jan 2019 12:53:08 -0800 Subject: Fix SGX target_env collision Signed-off-by: Yu Ding --- library/compiler-builtins/build.rs | 2 +- library/compiler-builtins/src/lib.rs | 3 ++- library/compiler-builtins/src/math.rs | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 752bba1343f..78a4ce2fb11 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -22,7 +22,7 @@ fn main() { // Forcibly enable memory intrinsics on wasm32 & SGX as we don't have a libc to // provide them. - if target.contains("wasm32") || target.contains("sgx") { + if target.contains("wasm32") || (target.contains("sgx") && target.contains("fortanix")) { println!("cargo:rustc-cfg=feature=\"mem\""); } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 9bb38f39aa2..0acb00698d2 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -16,6 +16,7 @@ #![feature(abi_unadjusted)] #![feature(linkage)] #![feature(lang_items)] +#![feature(cfg_target_vendor)] #![allow(unused_features)] #![no_builtins] #![cfg_attr(feature = "compiler-builtins", feature(staged_api))] @@ -49,7 +50,7 @@ pub mod float; #[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), all(target_arch = "arm", target_os = "none"), - target_env = "sgx"))] + all(target_vendor = "fortanix", target_env = "sgx")))] pub mod math; pub mod mem; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index e2b15c6a7b5..18def0e86c7 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -15,7 +15,8 @@ macro_rules! no_mangle { } // only for the wasm32-unknown-unknown target -#[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), target_env = "sgx"))] +#[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), + all(target_vendor = "fortanix", target_env = "sgx")))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; @@ -66,7 +67,7 @@ no_mangle! { fn tanhf(n: f32) -> f32; } -#[cfg(target_env = "sgx")] +#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] no_mangle! { fn ceil(x: f64) -> f64; fn ceilf(x: f32) -> f32; -- cgit 1.4.1-3-g733a5 From 905869e4d5b229a12d43f706e59efc300ba7aa1b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 3 Jan 2019 13:55:02 -0800 Subject: Bump to 0.1.4 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 32cc2681d7a..7dce4b07b02 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.3" +version = "0.1.4" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 8b002dcd525fbda817d802f2e8f624dde3ae4ee8 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 4 Jan 2019 19:17:02 -0700 Subject: Attempt to use `intrinsics!` --- library/compiler-builtins/src/int/mod.rs | 97 ++++++++++++++++---------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 11fd49bbc88..52a4227a09b 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -301,64 +301,67 @@ macro_rules! impl_wide_int { impl_wide_int!(u32, u64, 32); impl_wide_int!(u64, u128, 64); -#[no_mangle] -#[cfg(any( - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64" -))] -pub extern "C" fn __clzsi2(mut x: usize) -> usize { - // TODO: const this? Would require const-if - let mut y: usize; - let mut n: usize = { +intrinsics! { + #[cfg(any( + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64" + ))] + pub extern "C" fn __clzsi2(x: usize) -> usize { + // TODO: const this? Would require const-if + // Note(Lokathor): the `intrinsics!` macro can't process mut inputs + let mut x = x; + let mut y: usize; + let mut n: usize = { + #[cfg(target_pointer_width = "64")] + { + 64 + } + #[cfg(target_pointer_width = "32")] + { + 32 + } + #[cfg(target_pointer_width = "16")] + { + 16 + } + }; #[cfg(target_pointer_width = "64")] { - 64 + y = x >> 32; + if y != 0 { + n -= 32; + x = y; + } } - #[cfg(target_pointer_width = "32")] + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] { - 32 + y = x >> 16; + if y != 0 { + n -= 16; + x = y; + } } - #[cfg(target_pointer_width = "16")] - { - 16 + y = x >> 8; + if y != 0 { + n -= 8; + x = y; } - }; - #[cfg(target_pointer_width = "64")] - { - y = x >> 32; + y = x >> 4; if y != 0 { - n -= 32; + n -= 4; x = y; } - } - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { - y = x >> 16; + y = x >> 2; if y != 0 { - n -= 16; + n -= 2; x = y; } - } - y = x >> 8; - if y != 0 { - n -= 8; - x = y; - } - y = x >> 4; - if y != 0 { - n -= 4; - x = y; - } - y = x >> 2; - if y != 0 { - n -= 2; - x = y; - } - y = x >> 1; - if y != 0 { - n - 2 - } else { - n - x + y = x >> 1; + if y != 0 { + n - 2 + } else { + n - x + } } } -- cgit 1.4.1-3-g733a5 From deb1cb51d13642a1c6390f2b593ddba74c88dd38 Mon Sep 17 00:00:00 2001 From: Denys Zariaiev Date: Sun, 6 Jan 2019 16:28:46 +0100 Subject: Don't build compiler-rt for NVPTX --- library/compiler-builtins/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 752bba1343f..b094734539e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -36,8 +36,8 @@ fn main() { // build anything and we rely on the upstream implementation of compiler-rt // functions if !cfg!(feature = "mangled-names") && cfg!(feature = "c") { - // no C compiler for wasm - if !target.contains("wasm32") { + // Don't use C compiler for bitcode-only wasm and nvptx + if !target.contains("wasm32") && !target.contains("nvptx") { #[cfg(feature = "c")] c::compile(&llvm_target); println!("cargo:rustc-cfg=use_c"); -- cgit 1.4.1-3-g733a5 From 5b18b6471dab40d72a2cfc405972e1b7a50f664f Mon Sep 17 00:00:00 2001 From: Lokathor Date: Mon, 7 Jan 2019 11:52:30 -0700 Subject: Version Bump for count leading zeros --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 07afd304686..32cc2681d7a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.2" +version = "0.1.3" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From c48d0c3d999aebba85af9dd59d97f3e2a76b3898 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Mon, 7 Jan 2019 12:08:18 -0700 Subject: Perform the correct version bump --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7dce4b07b02..de2996b215d 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.4" +version = "0.1.5" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 2b8e3f6029a4710f30d023808285b8ebbd1ebd26 Mon Sep 17 00:00:00 2001 From: Cyryl Płotnicki Date: Sun, 20 Jan 2019 09:33:55 +0000 Subject: Fix compilation on new nightly. Compilation on rustc 1.33.0-nightly (c76f3c374 2019-01-18) failed with ``` error: the feature `cfg_target_vendor` has been stable since 1.33.0 and no longer requires an attribute to enable --> src/lib.rs:19:12 | 19 | #![feature(cfg_target_vendor)] | ^^^^^^^^^^^^^^^^^ | ``` Removed the attribute to make it compile. --- library/compiler-builtins/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0acb00698d2..fddfa67aa8e 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -16,7 +16,6 @@ #![feature(abi_unadjusted)] #![feature(linkage)] #![feature(lang_items)] -#![feature(cfg_target_vendor)] #![allow(unused_features)] #![no_builtins] #![cfg_attr(feature = "compiler-builtins", feature(staged_api))] -- cgit 1.4.1-3-g733a5 From 55f0ab112a4cec08681aae2b0ab4d0a39bdba8a8 Mon Sep 17 00:00:00 2001 From: MikaelUrankar Date: Sat, 2 Feb 2019 19:52:41 +0100 Subject: FreeBSD arm needs clear_cache.c --- library/compiler-builtins/build.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 057f5d9d82e..9a7c05eb0a7 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -311,6 +311,10 @@ mod c { ], ); + if target_os == "freebsd" { + sources.extend(&["clear_cache.c"]); + } + // First of all aeabi_cdcmp and aeabi_cfcmp are never called by LLVM. // Second are little-endian only, so build fail on big-endian targets. // Temporally workaround: exclude these files for big-endian targets. -- cgit 1.4.1-3-g733a5 From cab813bf74205cbe49431f98e49fc6427a14ca87 Mon Sep 17 00:00:00 2001 From: Jordan Rhee Date: Wed, 27 Feb 2019 11:39:49 -0800 Subject: Fix undefined symbol errors on windows/arm Fix undefined symbol linker errors when building rust for windows/arm by excluding unneeded symbols. The errors are: = note: lib.def : error LNK2001: unresolved external symbol __aeabi_memclr4 lib.def : error LNK2001: unresolved external symbol __aeabi_memclr8 lib.def : error LNK2001: unresolved external symbol __aeabi_memmove4 lib.def : error LNK2001: unresolved external symbol __aeabi_memmove8 --- library/compiler-builtins/src/arm.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 9e43aec7d34..9bfffb74fc9 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -164,14 +164,14 @@ pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: u ::mem::memmove(dest, src, n); } -#[cfg(not(target_os = "ios"))] +#[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } -#[cfg(not(target_os = "ios"))] +#[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { @@ -220,14 +220,14 @@ pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { __aeabi_memset(dest, n, 0); } -#[cfg(not(target_os = "ios"))] +#[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } -#[cfg(not(target_os = "ios"))] +#[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { -- cgit 1.4.1-3-g733a5 From 648db7498b471619870e295f8f8e3eab55be50fe Mon Sep 17 00:00:00 2001 From: Jordan Rhee Date: Wed, 27 Feb 2019 11:45:14 -0800 Subject: Bump version to 0.1.6 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index de2996b215d..44dabada166 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.5" +version = "0.1.6" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From b94478025096c875b396ba98de745b8655fe8035 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 27 Feb 2019 12:39:34 -0800 Subject: Bump to 0.1.7 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 44dabada166..62900bff6e6 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.6" +version = "0.1.7" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 8d0fdce9ca55b5d8f7732a35a452e0dcfbb364c2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 13 Mar 2019 08:19:30 -0700 Subject: Don't compile memory intrinsics on wasi --- library/compiler-builtins/build.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 9a7c05eb0a7..5d555d60828 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -22,7 +22,8 @@ fn main() { // Forcibly enable memory intrinsics on wasm32 & SGX as we don't have a libc to // provide them. - if target.contains("wasm32") || (target.contains("sgx") && target.contains("fortanix")) { + if (target.contains("wasm32") && !target.contains("wasi")) || + (target.contains("sgx") && target.contains("fortanix")) { println!("cargo:rustc-cfg=feature=\"mem\""); } @@ -314,7 +315,7 @@ mod c { if target_os == "freebsd" { sources.extend(&["clear_cache.c"]); } - + // First of all aeabi_cdcmp and aeabi_cfcmp are never called by LLVM. // Second are little-endian only, so build fail on big-endian targets. // Temporally workaround: exclude these files for big-endian targets. -- cgit 1.4.1-3-g733a5 From e7c41f4a8418b27525ebbb989c78a8fc74d999aa Mon Sep 17 00:00:00 2001 From: Hugues de Valon Date: Thu, 7 Mar 2019 19:24:15 +0000 Subject: Fix Armv8-M Baseline compilation Armv8-M Baseline, ie thumbv8m.base-none-eabi, is a superset of the Armv6-M architecture profile. As it shares almost the same instruction set, this commit copies the configuration for thumbv6m-none-eabi to enable it. --- library/compiler-builtins/build.rs | 11 ++++++----- library/compiler-builtins/src/int/sdiv.rs | 6 +++--- library/compiler-builtins/src/int/udiv.rs | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 9a7c05eb0a7..6cef4be3940 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -49,10 +49,11 @@ fn main() { println!("cargo:rustc-cfg=thumb") } - // compiler-rt `cfg`s away some intrinsics for thumbv6m because that target doesn't have full - // THUMBv2 support. We have to cfg our code accordingly. - if llvm_target[0] == "thumbv6m" { - println!("cargo:rustc-cfg=thumbv6m") + // compiler-rt `cfg`s away some intrinsics for thumbv6m and thumbv8m.base because + // these targets do not have full Thumb-2 support but only original Thumb-1. + // We have to cfg our code accordingly. + if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { + println!("cargo:rustc-cfg=thumb_1") } // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. @@ -407,7 +408,7 @@ mod c { } // Remove the assembly implementations that won't compile for the target - if llvm_target[0] == "thumbv6m" { + if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { sources.remove( &[ "clzdi2", diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 89bb51a47b3..a2e8aa96f90 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -74,8 +74,8 @@ intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), - not(target_env = "msvc")), - not(thumbv6m))] + not(target_env = "msvc"), + not(thumb_1)))] pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { a.mod_(b) } @@ -91,7 +91,7 @@ intrinsics! { } #[use_c_shim_if(all(target_arch = "arm", not(target_env = "msvc"), - not(target_os = "ios"), not(thumbv6m)))] + not(target_os = "ios"), not(thumb_1)))] pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { a.divmod(b, rem, |a, b| __divsi3(a, b)) } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index a2572227f97..d873559bdd8 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -212,7 +212,7 @@ intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(target_env = "msvc"), - not(thumbv6m)))] + not(thumb_1)))] /// Returns `n % d` pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { let q = __udivsi3(n, d); @@ -222,7 +222,7 @@ intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(target_env = "msvc"), - not(thumbv6m)))] + not(thumb_1)))] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { let q = __udivsi3(n, d); -- cgit 1.4.1-3-g733a5 From ae7b057cdb913b64a08498b816c30e2691a74118 Mon Sep 17 00:00:00 2001 From: Hugues de Valon Date: Thu, 7 Mar 2019 19:30:39 +0000 Subject: Fix compilation for thumbv8m.main-none-eabihf Some files were not assembling for the Armv8-M Mainline architecture profile with FPU extension. Reason being the same as for Armv7-M: the conversion intrinsics including double precision floating point variables do not work with single precision FPUs. Also removes from exclusion files that are assembling without errors for Armv7-M and Armv8-M Mainline. --- library/compiler-builtins/build.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6cef4be3940..ccd908caa36 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -360,24 +360,36 @@ mod c { } if llvm_target.last().unwrap().ends_with("eabihf") { - if !llvm_target[0].starts_with("thumbv7em") { + if !llvm_target[0].starts_with("thumbv7em") && + !llvm_target[0].starts_with("thumbv8m.main") { + // The FPU option chosen for these architectures in cc-rs, ie: + // -mfpu=fpv4-sp-d16 for thumbv7em + // -mfpu=fpv5-sp-d16 for thumbv8m.main + // do not support double precision floating points conversions so the files + // that include such instructions are not included for these targets. sources.extend( &[ "arm/fixdfsivfp.S", - "arm/fixsfsivfp.S", "arm/fixunsdfsivfp.S", - "arm/fixunssfsivfp.S", "arm/floatsidfvfp.S", - "arm/floatsisfvfp.S", "arm/floatunssidfvfp.S", - "arm/floatunssisfvfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", ], ); } - sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); + sources.extend( + &[ + "arm/fixsfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssisfvfp.S", + "arm/floatunssisfvfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/negdf2vfp.S", + "arm/negsf2vfp.S", + ] + ); } -- cgit 1.4.1-3-g733a5 From b8413ddc326efe629f6fd307f113fa0fc46cdd77 Mon Sep 17 00:00:00 2001 From: Hugues de Valon Date: Thu, 7 Mar 2019 19:34:53 +0000 Subject: Remove thumbv6m configuration of intrinsic example It seems that the intrinsics that were generated for the functions in example/intrinsics.rs where different implementations were given for thumb6m-none-eabi target, have now been implemented in Rust so configuration is not needed anymore. --- library/compiler-builtins/examples/intrinsics.rs | 63 ------------------------ 1 file changed, 63 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index c52b4f0d768..89c2c23dbfc 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -19,9 +19,6 @@ extern crate panic_handler; #[link(name = "c")] extern {} -// NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even -// compiler-rt provides a C/assembly implementation. - // Every function in this module maps will be lowered to an intrinsic by LLVM, if the platform // doesn't have native support for the operation used in the function. ARM has a naming convention // convention for its intrinsics that's different from other architectures; that's why some function @@ -39,70 +36,40 @@ mod intrinsics { } // fixdfdi - #[cfg(not(thumbv6m))] pub fn aeabi_d2l(x: f64) -> i64 { x as i64 } - #[cfg(thumbv6m)] - pub fn aeabi_d2l(_: f64) -> i64 { - 0 - } - // fixunsdfsi pub fn aeabi_d2uiz(x: f64) -> u32 { x as u32 } // fixunsdfdi - #[cfg(not(thumbv6m))] pub fn aeabi_d2ulz(x: f64) -> u64 { x as u64 } - #[cfg(thumbv6m)] - pub fn aeabi_d2ulz(_: f64) -> u64 { - 0 - } - // adddf3 pub fn aeabi_dadd(a: f64, b: f64) -> f64 { a + b } // eqdf2 - #[cfg(not(thumbv6m))] pub fn aeabi_dcmpeq(a: f64, b: f64) -> bool { a == b } - #[cfg(thumbv6m)] - pub fn aeabi_dcmpeq(_: f64, _: f64) -> bool { - true - } - // gtdf2 - #[cfg(not(thumbv6m))] pub fn aeabi_dcmpgt(a: f64, b: f64) -> bool { a > b } - #[cfg(thumbv6m)] - pub fn aeabi_dcmpgt(_: f64, _: f64) -> bool { - true - } - // ltdf2 - #[cfg(not(thumbv6m))] pub fn aeabi_dcmplt(a: f64, b: f64) -> bool { a < b } - #[cfg(thumbv6m)] - pub fn aeabi_dcmplt(_: f64, _: f64) -> bool { - true - } - // divdf3 pub fn aeabi_ddiv(a: f64, b: f64) -> f64 { a / b @@ -129,70 +96,40 @@ mod intrinsics { } // fixsfdi - #[cfg(not(thumbv6m))] pub fn aeabi_f2lz(x: f32) -> i64 { x as i64 } - #[cfg(thumbv6m)] - pub fn aeabi_f2lz(_: f32) -> i64 { - 0 - } - // fixunssfsi pub fn aeabi_f2uiz(x: f32) -> u32 { x as u32 } // fixunssfdi - #[cfg(not(thumbv6m))] pub fn aeabi_f2ulz(x: f32) -> u64 { x as u64 } - #[cfg(thumbv6m)] - pub fn aeabi_f2ulz(_: f32) -> u64 { - 0 - } - // addsf3 pub fn aeabi_fadd(a: f32, b: f32) -> f32 { a + b } // eqsf2 - #[cfg(not(thumbv6m))] pub fn aeabi_fcmpeq(a: f32, b: f32) -> bool { a == b } - #[cfg(thumbv6m)] - pub fn aeabi_fcmpeq(_: f32, _: f32) -> bool { - true - } - // gtsf2 - #[cfg(not(thumbv6m))] pub fn aeabi_fcmpgt(a: f32, b: f32) -> bool { a > b } - #[cfg(thumbv6m)] - pub fn aeabi_fcmpgt(_: f32, _: f32) -> bool { - true - } - // ltsf2 - #[cfg(not(thumbv6m))] pub fn aeabi_fcmplt(a: f32, b: f32) -> bool { a < b } - #[cfg(thumbv6m)] - pub fn aeabi_fcmplt(_: f32, _: f32) -> bool { - true - } - // divsf3 pub fn aeabi_fdiv(a: f32, b: f32) -> f32 { a / b -- cgit 1.4.1-3-g733a5 From a634eff2801f0ddaf22ce36e9010f5e5f6b59f60 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 21 Mar 2019 07:52:59 -0700 Subject: Bump to 0.1.8 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 62900bff6e6..d30af40511d 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.7" +version = "0.1.8" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From a806c53b2cfb1d17c6825691cf1f1a5731755df3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 07:46:06 -0700 Subject: Don't compile math symbols on wasm32-unknown-wasi These are already provided by the C sysroot, so no need for us to duplicate them! --- library/compiler-builtins/src/math.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 18def0e86c7..dfdd99cdf93 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -14,9 +14,14 @@ macro_rules! no_mangle { } } -// only for the wasm32-unknown-unknown target -#[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), - all(target_vendor = "fortanix", target_env = "sgx")))] +#[cfg(any( + all( + target_arch = "wasm32", + target_os = "unknown", + not(target_env = "wasi") + ), + all(target_vendor = "fortanix", target_env = "sgx") +))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; -- cgit 1.4.1-3-g733a5 From d3d3cc21260527eb24b46bbf64eb96de7ea7650e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 07:57:02 -0700 Subject: Add sample azure pipelines configuration --- library/compiler-builtins/azure-pipelines.yml | 33 ++++++++++++++++++++++ .../compiler-builtins/ci/azure-install-rust.yml | 25 ++++++++++++++++ library/compiler-builtins/ci/azure-steps.yml | 10 +++++++ 3 files changed, 68 insertions(+) create mode 100644 library/compiler-builtins/azure-pipelines.yml create mode 100644 library/compiler-builtins/ci/azure-install-rust.yml create mode 100644 library/compiler-builtins/ci/azure-steps.yml diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml new file mode 100644 index 00000000000..f7a25ae00aa --- /dev/null +++ b/library/compiler-builtins/azure-pipelines.yml @@ -0,0 +1,33 @@ +trigger: + - master + +jobs: + - job: Linux + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + aarch64-unknown-linux-gnu: + TARGET: aarch64-unknown-linux-gnu + + - job: macOS + pool: + vmImage: macos-10.13 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + x86_64-apple-darwin: + TARGET: x86_64-apple-darwin + + - job: Windows + pool: + vmImage: 'vs2017-win2016' + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + i686-pc-windows-msvc: + TARGET: i686-pc-windows-msvc diff --git a/library/compiler-builtins/ci/azure-install-rust.yml b/library/compiler-builtins/ci/azure-install-rust.yml new file mode 100644 index 00000000000..25e48f99157 --- /dev/null +++ b/library/compiler-builtins/ci/azure-install-rust.yml @@ -0,0 +1,25 @@ +parameters: + toolchain: 'nightly' + +steps: + - bash: | + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TOOLCHAIN + echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + displayName: Install rust + condition: ne( variables['Agent.OS'], 'Windows_NT' ) + env: + TOOLCHAIN: ${{ parameters.toolchain }} + + - script: | + curl -sSf -o rustup-init.exe https://win.rustup.rs + rustup-init.exe -y --default-toolchain %TOOLCHAIN% + echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin" + displayName: Install rust + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + env: + TOOLCHAIN: ${{ parameters.toolchain }} + + - script: | + rustc -Vv + cargo -V + displayName: Query rust and cargo versions diff --git a/library/compiler-builtins/ci/azure-steps.yml b/library/compiler-builtins/ci/azure-steps.yml new file mode 100644 index 00000000000..a6acba48069 --- /dev/null +++ b/library/compiler-builtins/ci/azure-steps.yml @@ -0,0 +1,10 @@ +steps: + - template: azure-install-rust.yml + + - bash: ./ci/run.sh $TARGET + condition: ne( variables['Agent.OS'], 'Linux' ) + displayName: Run test script + + - bash: ./ci/run-docker.sh $TARGET + condition: eq( variables['Agent.OS'], 'Linux' ) + displayName: Run docker test script -- cgit 1.4.1-3-g733a5 From b51f3d18a32e443bd254df81ac4df17be941c03c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 07:58:12 -0700 Subject: Configure Azure Pipelines --- library/compiler-builtins/.travis.yml | 63 ---------------------- library/compiler-builtins/README.md | 5 +- library/compiler-builtins/appveyor.yml | 45 ---------------- library/compiler-builtins/azure-pipelines.yml | 3 +- .../compiler-builtins/ci/azure-install-rust.yml | 5 +- library/compiler-builtins/ci/azure-steps.yml | 2 + 6 files changed, 9 insertions(+), 114 deletions(-) delete mode 100644 library/compiler-builtins/.travis.yml delete mode 100644 library/compiler-builtins/appveyor.yml diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml deleted file mode 100644 index 9b4c28419f8..00000000000 --- a/library/compiler-builtins/.travis.yml +++ /dev/null @@ -1,63 +0,0 @@ -dist: trusty -language: rust -rust: nightly -services: docker -sudo: required - -matrix: - include: - - env: TARGET=aarch64-unknown-linux-gnu - - env: TARGET=arm-unknown-linux-gnueabi - - env: TARGET=arm-unknown-linux-gnueabihf - - env: TARGET=armv7-unknown-linux-gnueabihf - - env: TARGET=i586-unknown-linux-gnu - - env: TARGET=i686-apple-darwin DEBUG_LTO_BUILD_DOESNT_WORK=1 - os: osx - - env: TARGET=i686-unknown-linux-gnu - - env: TARGET=mips-unknown-linux-gnu - - env: TARGET=mips64-unknown-linux-gnuabi64 - - env: TARGET=mips64el-unknown-linux-gnuabi64 - - env: TARGET=mipsel-unknown-linux-gnu - - env: TARGET=powerpc-unknown-linux-gnu - - env: TARGET=powerpc64-unknown-linux-gnu - - env: TARGET=powerpc64le-unknown-linux-gnu - - env: TARGET=thumbv6m-linux-eabi - - env: TARGET=thumbv7em-linux-eabi - - env: TARGET=thumbv7em-linux-eabihf - - env: TARGET=thumbv7m-linux-eabi - - env: TARGET=wasm32-unknown-unknown - install: rustup target add $TARGET - script: cargo build --target $TARGET - - env: TARGET=x86_64-apple-darwin DEBUG_LTO_BUILD_DOESNT_WORK=1 - os: osx - - env: TARGET=x86_64-unknown-linux-gnu - allow_failures: - - env: TARGET=thumbv6m-linux-eabi - - env: TARGET=thumbv7em-linux-eabi - - env: TARGET=thumbv7em-linux-eabihf - - env: TARGET=thumbv7m-linux-eabi - -install: - - case $TARGET in - x86_64-apple-darwin | x86_64-unknown-linux-gnu) ;; - thumbv*eabi*) rustup component add rust-src ;; - *) rustup target add $TARGET;; - esac - -script: - # work around rust-lang/cargo#3340 - - test "$TRAVIS_OS_NAME" = "osx" || - export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt - - cargo generate-lockfile - - if [[ $TRAVIS_OS_NAME = "linux" ]]; then - sudo apt-get remove -y qemu-user-static && - sudo apt-get install -y qemu-user-static && - sh ci/run-docker.sh $TARGET; - else - sh ci/run.sh $TARGET; - fi - -notifications: - email: - on_success: never - webhooks: https://buildbot.rust-lang.org/homu/travis diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index cae885279ad..b290cbff889 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,9 +1,8 @@ # `compiler-builtins` -[![Build status](https://ci.appveyor.com/api/projects/status/eusnjps5ui3d305p?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/compiler-builtins) -[![Build Status](https://travis-ci.org/rust-lang-nursery/compiler-builtins.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/compiler-builtins) +[![Build Status](https://dev.azure.com/rust-lang/compiler-builtins/_apis/build/status/compiler-builtins-CI?branchName=master)](https://dev.azure.com/rust-lang/compiler-builtins/_build/latest?definitionId=2&branchName=master) -> [WIP] Porting `compiler-rt` intrinsics to Rust +> Porting `compiler-rt` intrinsics to Rust See [rust-lang/rust#35437][0]. diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml deleted file mode 100644 index bb78ad36a2a..00000000000 --- a/library/compiler-builtins/appveyor.yml +++ /dev/null @@ -1,45 +0,0 @@ -environment: - # It's... a little unclear why the memcpy symbols clash on linux but not on - # other platforms. Would be great to not differ on this though! - INTRINSICS_FAILS_WITH_MEM_FEATURE: 1 - - matrix: - - TARGET: i686-pc-windows-msvc - - TARGET: x86_64-pc-windows-msvc - - # Ensure MinGW works, but we need to download the 32-bit MinGW compiler from a - # custom location. - # - # Note that the MinGW builds have tons of references to - # `rust_eh_unwind_resume` in the debug LTO builds that aren't optimized out, - # so we skip that test for now. Would be great to not skip it! - - TARGET: i686-pc-windows-gnu - MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror - MINGW_ARCHIVE: i686-6.3.0-release-win32-dwarf-rt_v5-rev1.7z - MINGW_DIR: mingw32 - DEBUG_LTO_BUILD_DOESNT_WORK: 1 - - TARGET: x86_64-pc-windows-gnu - DEBUG_LTO_BUILD_DOESNT_WORK: 1 - -install: - - git submodule update --init - - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - - rustup-init.exe --default-host x86_64-pc-windows-msvc --default-toolchain nightly -y - - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - - if NOT "%TARGET%" == "x86_64-pc-windows-msvc" rustup target add %TARGET% - - # Use the system msys - - set PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH% - - # download a custom compiler otherwise - - if defined MINGW_URL appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE% - - if defined MINGW_URL 7z x -y %MINGW_ARCHIVE% > nul - - if defined MINGW_URL set PATH=C:\Python27;%CD%\%MINGW_DIR%\bin;C:\msys64\usr\bin;%PATH% - - - rustc -Vv - - cargo -V - -build: false - -test_script: - - sh ci/run.sh %TARGET% diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml index f7a25ae00aa..b4b7ef81caf 100644 --- a/library/compiler-builtins/azure-pipelines.yml +++ b/library/compiler-builtins/azure-pipelines.yml @@ -1,6 +1,7 @@ trigger: - master - +pr: + - master jobs: - job: Linux pool: diff --git a/library/compiler-builtins/ci/azure-install-rust.yml b/library/compiler-builtins/ci/azure-install-rust.yml index 25e48f99157..d74946e3dfd 100644 --- a/library/compiler-builtins/ci/azure-install-rust.yml +++ b/library/compiler-builtins/ci/azure-install-rust.yml @@ -3,8 +3,9 @@ parameters: steps: - bash: | + set -e curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TOOLCHAIN - echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + echo "##vso[task.prependpath]$HOME/.cargo/bin" displayName: Install rust condition: ne( variables['Agent.OS'], 'Windows_NT' ) env: @@ -13,7 +14,7 @@ steps: - script: | curl -sSf -o rustup-init.exe https://win.rustup.rs rustup-init.exe -y --default-toolchain %TOOLCHAIN% - echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin" + echo ##vso[task.prependpath]%USERPROFILE%\.cargo\bin displayName: Install rust condition: eq( variables['Agent.OS'], 'Windows_NT' ) env: diff --git a/library/compiler-builtins/ci/azure-steps.yml b/library/compiler-builtins/ci/azure-steps.yml index a6acba48069..c769941d4c6 100644 --- a/library/compiler-builtins/ci/azure-steps.yml +++ b/library/compiler-builtins/ci/azure-steps.yml @@ -1,4 +1,6 @@ steps: + - checkout: self + submodules: true - template: azure-install-rust.yml - bash: ./ci/run.sh $TARGET -- cgit 1.4.1-3-g733a5 From cede5bc161d1cef9f13c707d1545765d7760a9f8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 08:27:38 -0700 Subject: Expand Azure Pipelines configuration --- library/compiler-builtins/azure-pipelines.yml | 51 ++++++++++++++++++++++++--- library/compiler-builtins/ci/azure-steps.yml | 4 +++ library/compiler-builtins/ci/run-docker.sh | 0 3 files changed, 50 insertions(+), 5 deletions(-) mode change 100644 => 100755 library/compiler-builtins/ci/run-docker.sh diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml index b4b7ef81caf..c32262b1c7e 100644 --- a/library/compiler-builtins/azure-pipelines.yml +++ b/library/compiler-builtins/azure-pipelines.yml @@ -1,7 +1,6 @@ trigger: - master -pr: - - master + jobs: - job: Linux pool: @@ -10,8 +9,42 @@ jobs: - template: ci/azure-steps.yml strategy: matrix: - aarch64-unknown-linux-gnu: + aarch64: TARGET: aarch64-unknown-linux-gnu + arm: + TARGET: arm-unknown-linux-gnueabi + armhf: + TARGET: arm-unknown-linux-gnueabihf + i586: + TARGET: i586-unknown-linux-gnu + i686: + TARGET: i686-unknown-linux-gnu + mips: + TARGET: mips-unknown-linux-gnu + mips64: + TARGET: mips64-unknown-linux-gnuabi64 + mips64el: + TARGET: mips64el-unknown-linux-gnuabi64 + mipsel: + TARGET: mipsel-unknown-linux-gnu + powerpc: + TARGET: powerpc-unknown-linux-gnu + powerpc64: + TARGET: powerpc64-unknown-linux-gnu + powerpc64le: + TARGET: powerpc64le-unknown-linux-gnu + thumbv6m: + TARGET: thumbv6m-linux-eabi + thumbv7em: + TARGET: thumbv7em-linux-eabi + thumbv7emhf: + TARGET: thumbv7em-linux-eabihf + thumbv7m: + TARGET: thumbv7m-linux-eabi + wasm32: + TARGET: wasm32-unknown-unknown + x86_64: + TARGET: x86_64-unknown-linux-gnu - job: macOS pool: @@ -20,8 +53,10 @@ jobs: - template: ci/azure-steps.yml strategy: matrix: - x86_64-apple-darwin: + x86_64: TARGET: x86_64-apple-darwin + i686: + TARGET: i686-apple-darwin - job: Windows pool: @@ -30,5 +65,11 @@ jobs: - template: ci/azure-steps.yml strategy: matrix: - i686-pc-windows-msvc: + i686-msvc: TARGET: i686-pc-windows-msvc + x86_64-msvc: + TARGET: x86_64-pc-windows-msvc + i686-gnu: + TARGET: i686-pc-windows-gnu + x86_64-gnu: + TARGET: x86_64-pc-windows-gnu diff --git a/library/compiler-builtins/ci/azure-steps.yml b/library/compiler-builtins/ci/azure-steps.yml index c769941d4c6..251b2d58443 100644 --- a/library/compiler-builtins/ci/azure-steps.yml +++ b/library/compiler-builtins/ci/azure-steps.yml @@ -1,8 +1,12 @@ steps: - checkout: self submodules: true + - template: azure-install-rust.yml + - bash: rustup target add $TARGET + displayName: Install compilation target + - bash: ./ci/run.sh $TARGET condition: ne( variables['Agent.OS'], 'Linux' ) displayName: Run test script diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh old mode 100644 new mode 100755 -- cgit 1.4.1-3-g733a5 From 95f4f0cd4eb1eee145a4d56344c314e57d8cfc4b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 08:39:19 -0700 Subject: Upgrade all docker containers to 18.04 --- .../compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 2 +- .../compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 2 +- .../compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile | 2 +- .../ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile | 2 +- library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile | 2 +- library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile | 2 +- library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile | 2 +- .../ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile | 2 +- .../ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile | 2 +- library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 2 +- .../compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 2 +- .../compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile | 2 +- .../ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile | 2 +- library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile | 2 +- library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile | 2 +- library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile | 2 +- library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile | 2 +- library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index 3f6a63fcb0d..9e2559f4ab3 100644 --- a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile index 1c31b00b4ea..afab874bc28 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile index c305b1ba546..3ed3602b0dc 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile index 76f367f142a..6617af1558c 100644 --- a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile index fb32306090b..5783e28e122 100644 --- a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc-multilib libc6-dev ca-certificates diff --git a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile index fb32306090b..5783e28e122 100644 --- a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc-multilib libc6-dev ca-certificates diff --git a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile index 71a9e8032f8..f47e8f5227b 100644 --- a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile index 22239e46d8a..8fa77c7bd07 100644 --- a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile index 77f1fd58c47..c6611d9ac89 100644 --- a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile index 98257e76806..0bc69562462 100644 --- a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile index b6bee385ec4..2d39fef6142 100644 --- a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile index 26dc1dc2726..653cd351156 100644 --- a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile index 3b280c0bdc6..63ea9af9d20 100644 --- a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile index ecf90087e1e..789bdf4e46c 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static diff --git a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile index 029a55d29a0..c6ce273c875 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static diff --git a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile index 5bf0c76e5be..c7518aaca84 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static diff --git a/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile index 1ffac1f3345..c9071094139 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static diff --git a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile index efc7b26c609..98000f4eb81 100644 --- a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates -- cgit 1.4.1-3-g733a5 From 7567d9ceb4d79e2ac500620316e02718a5560504 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 09:35:47 -0700 Subject: Don't pass `-it` to docker --- library/compiler-builtins/ci/run-docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 5608cedc467..6b3066e53e6 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -23,7 +23,7 @@ run() { -v `pwd`:/checkout:ro \ -v `rustc --print sysroot`:/rust:ro \ -w /checkout \ - -it $target \ + $target \ sh -c "HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" } -- cgit 1.4.1-3-g733a5 From a2b87a1a7fdba9c76f4c4d1b6ee273fb1b1ecfe4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 09:53:05 -0700 Subject: Generate a lock file before using Docker Can't do it in the readonly filesystem inside! --- library/compiler-builtins/ci/azure-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/azure-steps.yml b/library/compiler-builtins/ci/azure-steps.yml index 251b2d58443..19972a7c0a3 100644 --- a/library/compiler-builtins/ci/azure-steps.yml +++ b/library/compiler-builtins/ci/azure-steps.yml @@ -11,6 +11,6 @@ steps: condition: ne( variables['Agent.OS'], 'Linux' ) displayName: Run test script - - bash: ./ci/run-docker.sh $TARGET + - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET condition: eq( variables['Agent.OS'], 'Linux' ) displayName: Run docker test script -- cgit 1.4.1-3-g733a5 From 742b0330c55f70ba4bc5075a656f62ca881b4898 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 11:44:28 -0700 Subject: Try to handle thumb targets and xargo --- library/compiler-builtins/azure-pipelines.yml | 61 +++++++++++++------------ library/compiler-builtins/ci/azure-steps.yml | 14 +++++- library/compiler-builtins/ci/run-docker.sh | 1 + library/compiler-builtins/ci/run.sh | 65 ++++++++++++--------------- 4 files changed, 75 insertions(+), 66 deletions(-) diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml index c32262b1c7e..ca02a515399 100644 --- a/library/compiler-builtins/azure-pipelines.yml +++ b/library/compiler-builtins/azure-pipelines.yml @@ -11,38 +11,43 @@ jobs: matrix: aarch64: TARGET: aarch64-unknown-linux-gnu - arm: - TARGET: arm-unknown-linux-gnueabi - armhf: - TARGET: arm-unknown-linux-gnueabihf - i586: - TARGET: i586-unknown-linux-gnu - i686: - TARGET: i686-unknown-linux-gnu - mips: - TARGET: mips-unknown-linux-gnu - mips64: - TARGET: mips64-unknown-linux-gnuabi64 - mips64el: - TARGET: mips64el-unknown-linux-gnuabi64 - mipsel: - TARGET: mipsel-unknown-linux-gnu - powerpc: - TARGET: powerpc-unknown-linux-gnu - powerpc64: - TARGET: powerpc64-unknown-linux-gnu - powerpc64le: - TARGET: powerpc64le-unknown-linux-gnu + # arm: + # TARGET: arm-unknown-linux-gnueabi + # armhf: + # TARGET: arm-unknown-linux-gnueabihf + # i586: + # TARGET: i586-unknown-linux-gnu + # i686: + # TARGET: i686-unknown-linux-gnu + # mips: + # TARGET: mips-unknown-linux-gnu + # mips64: + # TARGET: mips64-unknown-linux-gnuabi64 + # mips64el: + # TARGET: mips64el-unknown-linux-gnuabi64 + # mipsel: + # TARGET: mipsel-unknown-linux-gnu + # powerpc: + # TARGET: powerpc-unknown-linux-gnu + # powerpc64: + # TARGET: powerpc64-unknown-linux-gnu + # powerpc64le: + # TARGET: powerpc64le-unknown-linux-gnu thumbv6m: TARGET: thumbv6m-linux-eabi + XARGO: 1 thumbv7em: TARGET: thumbv7em-linux-eabi + XARGO: 1 thumbv7emhf: TARGET: thumbv7em-linux-eabihf + XARGO: 1 thumbv7m: TARGET: thumbv7m-linux-eabi + XARGO: 1 wasm32: TARGET: wasm32-unknown-unknown + ONLY_BUILD: 1 x86_64: TARGET: x86_64-unknown-linux-gnu @@ -55,8 +60,8 @@ jobs: matrix: x86_64: TARGET: x86_64-apple-darwin - i686: - TARGET: i686-apple-darwin + # i686: + # TARGET: i686-apple-darwin - job: Windows pool: @@ -67,9 +72,9 @@ jobs: matrix: i686-msvc: TARGET: i686-pc-windows-msvc - x86_64-msvc: - TARGET: x86_64-pc-windows-msvc - i686-gnu: - TARGET: i686-pc-windows-gnu + # x86_64-msvc: + # TARGET: x86_64-pc-windows-msvc + # i686-gnu: + # TARGET: i686-pc-windows-gnu x86_64-gnu: TARGET: x86_64-pc-windows-gnu diff --git a/library/compiler-builtins/ci/azure-steps.yml b/library/compiler-builtins/ci/azure-steps.yml index 19972a7c0a3..c8a954024da 100644 --- a/library/compiler-builtins/ci/azure-steps.yml +++ b/library/compiler-builtins/ci/azure-steps.yml @@ -4,13 +4,23 @@ steps: - template: azure-install-rust.yml + - script: rustup component add rust-src + displayName: Install Rust sources + condition: eq( variables['XARGO'], '1' ) + - bash: rustup target add $TARGET - displayName: Install compilation target + displayName: Install Rust target + condition: ne( variables['XARGO'], '1' ) - bash: ./ci/run.sh $TARGET condition: ne( variables['Agent.OS'], 'Linux' ) displayName: Run test script - - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET + - bash: | + if [ "$ONLY_BUILD" = "1" ]; then + cargo build --target $TARGET + else + cargo generate-lockfile && ./ci/run-docker.sh $TARGET + fi condition: eq( variables['Agent.OS'], 'Linux' ) displayName: Run docker test script diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 6b3066e53e6..5c2e065ccef 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -18,6 +18,7 @@ run() { --user $(id -u):$(id -g) \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ + -e XARGO \ -v $HOME/.cargo:/cargo \ -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index b77752288d9..589553adbf2 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -3,14 +3,10 @@ set -ex # FIXME(japarix/xargo#186) this shouldn't be necessary export RUST_TARGET_PATH=`pwd` -case $1 in - thumb*) - cargo=xargo - ;; - *) - cargo=cargo - ;; -esac +cargo=cargo +if [ "$XARGO" = "1" ]; then + cargo=xargo +fi INTRINSICS_FEATURES="c" @@ -22,34 +18,31 @@ if [ -z "$INTRINSICS_FAILS_WITH_MEM_FEATURE" ]; then fi # Test our implementation -case $1 in - thumb*) - run="xargo test --manifest-path testcrate/Cargo.toml --target $1" - for t in $(ls testcrate/tests); do - t=${t%.rs} - - RUSTFLAGS="-C debug-assertions=no -C lto" \ - CARGO_INCREMENTAL=0 \ - $run --test $t --no-default-features --features 'mem c' --no-run - qemu-arm-static target/${1}/debug/$t-* - done - - for t in $(ls testcrate/tests); do - t=${t%.rs} - RUSTFLAGS="-C lto" \ - CARGO_INCREMENTAL=0 \ - $run --test $t --no-default-features --features 'mem c' --no-run --release - qemu-arm-static target/${1}/release/$t-* - done - ;; - *) - run="cargo test --manifest-path testcrate/Cargo.toml --target $1" - $run - $run --release - $run --features c - $run --features c --release - ;; -esac +if [ "$XARGO" = "1" ]; then + run="xargo test --manifest-path testcrate/Cargo.toml --target $1" + for t in $(ls testcrate/tests); do + t=${t%.rs} + + RUSTFLAGS="-C debug-assertions=no -C lto" \ + CARGO_INCREMENTAL=0 \ + $run --test $t --no-default-features --features 'mem c' --no-run + qemu-arm-static target/${1}/debug/$t-* + done + + for t in $(ls testcrate/tests); do + t=${t%.rs} + RUSTFLAGS="-C lto" \ + CARGO_INCREMENTAL=0 \ + $run --test $t --no-default-features --features 'mem c' --no-run --release + qemu-arm-static target/${1}/release/$t-* + done +else + run="cargo test --manifest-path testcrate/Cargo.toml --target $1" + $run + $run --release + $run --features c + $run --features c --release +fi PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in -- cgit 1.4.1-3-g733a5 From b73fa4b764991ea7f87827cdd5e8a850bacab269 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 12:12:19 -0700 Subject: Try to fix Windows --- library/compiler-builtins/azure-pipelines.yml | 130 ++++++++++----------- .../compiler-builtins/ci/azure-install-rust.yml | 2 +- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml index ca02a515399..36732f1320d 100644 --- a/library/compiler-builtins/azure-pipelines.yml +++ b/library/compiler-builtins/azure-pipelines.yml @@ -2,67 +2,67 @@ trigger: - master jobs: - - job: Linux - pool: - vmImage: ubuntu-16.04 - steps: - - template: ci/azure-steps.yml - strategy: - matrix: - aarch64: - TARGET: aarch64-unknown-linux-gnu - # arm: - # TARGET: arm-unknown-linux-gnueabi - # armhf: - # TARGET: arm-unknown-linux-gnueabihf - # i586: - # TARGET: i586-unknown-linux-gnu - # i686: - # TARGET: i686-unknown-linux-gnu - # mips: - # TARGET: mips-unknown-linux-gnu - # mips64: - # TARGET: mips64-unknown-linux-gnuabi64 - # mips64el: - # TARGET: mips64el-unknown-linux-gnuabi64 - # mipsel: - # TARGET: mipsel-unknown-linux-gnu - # powerpc: - # TARGET: powerpc-unknown-linux-gnu - # powerpc64: - # TARGET: powerpc64-unknown-linux-gnu - # powerpc64le: - # TARGET: powerpc64le-unknown-linux-gnu - thumbv6m: - TARGET: thumbv6m-linux-eabi - XARGO: 1 - thumbv7em: - TARGET: thumbv7em-linux-eabi - XARGO: 1 - thumbv7emhf: - TARGET: thumbv7em-linux-eabihf - XARGO: 1 - thumbv7m: - TARGET: thumbv7m-linux-eabi - XARGO: 1 - wasm32: - TARGET: wasm32-unknown-unknown - ONLY_BUILD: 1 - x86_64: - TARGET: x86_64-unknown-linux-gnu - - - job: macOS - pool: - vmImage: macos-10.13 - steps: - - template: ci/azure-steps.yml - strategy: - matrix: - x86_64: - TARGET: x86_64-apple-darwin - # i686: - # TARGET: i686-apple-darwin - + # - job: Linux + # pool: + # vmImage: ubuntu-16.04 + # steps: + # - template: ci/azure-steps.yml + # strategy: + # matrix: + # aarch64: + # TARGET: aarch64-unknown-linux-gnu + # arm: + # TARGET: arm-unknown-linux-gnueabi + # armhf: + # TARGET: arm-unknown-linux-gnueabihf + # i586: + # TARGET: i586-unknown-linux-gnu + # i686: + # TARGET: i686-unknown-linux-gnu + # mips: + # TARGET: mips-unknown-linux-gnu + # mips64: + # TARGET: mips64-unknown-linux-gnuabi64 + # mips64el: + # TARGET: mips64el-unknown-linux-gnuabi64 + # mipsel: + # TARGET: mipsel-unknown-linux-gnu + # powerpc: + # TARGET: powerpc-unknown-linux-gnu + # powerpc64: + # TARGET: powerpc64-unknown-linux-gnu + # powerpc64le: + # TARGET: powerpc64le-unknown-linux-gnu + # thumbv6m: + # TARGET: thumbv6m-linux-eabi + # XARGO: 1 + # thumbv7em: + # TARGET: thumbv7em-linux-eabi + # XARGO: 1 + # thumbv7emhf: + # TARGET: thumbv7em-linux-eabihf + # XARGO: 1 + # thumbv7m: + # TARGET: thumbv7m-linux-eabi + # XARGO: 1 + # wasm32: + # TARGET: wasm32-unknown-unknown + # ONLY_BUILD: 1 + # x86_64: + # TARGET: x86_64-unknown-linux-gnu + # + # - job: macOS + # pool: + # vmImage: macos-10.13 + # steps: + # - template: ci/azure-steps.yml + # strategy: + # matrix: + # x86_64: + # TARGET: x86_64-apple-darwin + # i686: + # TARGET: i686-apple-darwin + # - job: Windows pool: vmImage: 'vs2017-win2016' @@ -72,9 +72,9 @@ jobs: matrix: i686-msvc: TARGET: i686-pc-windows-msvc - # x86_64-msvc: - # TARGET: x86_64-pc-windows-msvc - # i686-gnu: - # TARGET: i686-pc-windows-gnu + x86_64-msvc: + TARGET: x86_64-pc-windows-msvc + i686-gnu: + TARGET: i686-pc-windows-gnu x86_64-gnu: TARGET: x86_64-pc-windows-gnu diff --git a/library/compiler-builtins/ci/azure-install-rust.yml b/library/compiler-builtins/ci/azure-install-rust.yml index d74946e3dfd..f44f8c59dc6 100644 --- a/library/compiler-builtins/ci/azure-install-rust.yml +++ b/library/compiler-builtins/ci/azure-install-rust.yml @@ -13,7 +13,7 @@ steps: - script: | curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe -y --default-toolchain %TOOLCHAIN% + rustup-init.exe -y --default-toolchain %TOOLCHAIN%-%TARGET% echo ##vso[task.prependpath]%USERPROFILE%\.cargo\bin displayName: Install rust condition: eq( variables['Agent.OS'], 'Windows_NT' ) -- cgit 1.4.1-3-g733a5 From 9772acb3cd954061c01e5bc6f5a5b7f9ba0bc8ff Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 12:16:59 -0700 Subject: Re-enable all targets --- library/compiler-builtins/azure-pipelines.yml | 122 +++++++++++++------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml index 36732f1320d..8df6e64c5e2 100644 --- a/library/compiler-builtins/azure-pipelines.yml +++ b/library/compiler-builtins/azure-pipelines.yml @@ -2,67 +2,67 @@ trigger: - master jobs: - # - job: Linux - # pool: - # vmImage: ubuntu-16.04 - # steps: - # - template: ci/azure-steps.yml - # strategy: - # matrix: - # aarch64: - # TARGET: aarch64-unknown-linux-gnu - # arm: - # TARGET: arm-unknown-linux-gnueabi - # armhf: - # TARGET: arm-unknown-linux-gnueabihf - # i586: - # TARGET: i586-unknown-linux-gnu - # i686: - # TARGET: i686-unknown-linux-gnu - # mips: - # TARGET: mips-unknown-linux-gnu - # mips64: - # TARGET: mips64-unknown-linux-gnuabi64 - # mips64el: - # TARGET: mips64el-unknown-linux-gnuabi64 - # mipsel: - # TARGET: mipsel-unknown-linux-gnu - # powerpc: - # TARGET: powerpc-unknown-linux-gnu - # powerpc64: - # TARGET: powerpc64-unknown-linux-gnu - # powerpc64le: - # TARGET: powerpc64le-unknown-linux-gnu - # thumbv6m: - # TARGET: thumbv6m-linux-eabi - # XARGO: 1 - # thumbv7em: - # TARGET: thumbv7em-linux-eabi - # XARGO: 1 - # thumbv7emhf: - # TARGET: thumbv7em-linux-eabihf - # XARGO: 1 - # thumbv7m: - # TARGET: thumbv7m-linux-eabi - # XARGO: 1 - # wasm32: - # TARGET: wasm32-unknown-unknown - # ONLY_BUILD: 1 - # x86_64: - # TARGET: x86_64-unknown-linux-gnu - # - # - job: macOS - # pool: - # vmImage: macos-10.13 - # steps: - # - template: ci/azure-steps.yml - # strategy: - # matrix: - # x86_64: - # TARGET: x86_64-apple-darwin - # i686: - # TARGET: i686-apple-darwin - # + - job: Linux + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + aarch64: + TARGET: aarch64-unknown-linux-gnu + arm: + TARGET: arm-unknown-linux-gnueabi + armhf: + TARGET: arm-unknown-linux-gnueabihf + i586: + TARGET: i586-unknown-linux-gnu + i686: + TARGET: i686-unknown-linux-gnu + mips: + TARGET: mips-unknown-linux-gnu + mips64: + TARGET: mips64-unknown-linux-gnuabi64 + mips64el: + TARGET: mips64el-unknown-linux-gnuabi64 + mipsel: + TARGET: mipsel-unknown-linux-gnu + powerpc: + TARGET: powerpc-unknown-linux-gnu + powerpc64: + TARGET: powerpc64-unknown-linux-gnu + powerpc64le: + TARGET: powerpc64le-unknown-linux-gnu + # thumbv6m: + # TARGET: thumbv6m-linux-eabi + # XARGO: 1 + # thumbv7em: + # TARGET: thumbv7em-linux-eabi + # XARGO: 1 + # thumbv7emhf: + # TARGET: thumbv7em-linux-eabihf + # XARGO: 1 + # thumbv7m: + # TARGET: thumbv7m-linux-eabi + # XARGO: 1 + wasm32: + TARGET: wasm32-unknown-unknown + ONLY_BUILD: 1 + x86_64: + TARGET: x86_64-unknown-linux-gnu + + - job: macOS + pool: + vmImage: macos-10.13 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + x86_64: + TARGET: x86_64-apple-darwin + i686: + TARGET: i686-apple-darwin + - job: Windows pool: vmImage: 'vs2017-win2016' -- cgit 1.4.1-3-g733a5 From 44181b42f4dba4062bb6d974f62d3223d84a4d23 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 12:51:36 -0700 Subject: Attempt to fix MinGW targets --- library/compiler-builtins/azure-pipelines.yml | 4 ++++ library/compiler-builtins/examples/intrinsics.rs | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml index 8df6e64c5e2..da3a1bb1d39 100644 --- a/library/compiler-builtins/azure-pipelines.yml +++ b/library/compiler-builtins/azure-pipelines.yml @@ -76,5 +76,9 @@ jobs: TARGET: x86_64-pc-windows-msvc i686-gnu: TARGET: i686-pc-windows-gnu + INTRINSICS_FAILS_WITH_MEM_FEATURE: 1 + DEBUG_LTO_BUILD_DOESNT_WORK: 1 x86_64-gnu: TARGET: x86_64-pc-windows-gnu + INTRINSICS_FAILS_WITH_MEM_FEATURE: 1 + DEBUG_LTO_BUILD_DOESNT_WORK: 1 diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 89c2c23dbfc..7766687c8b5 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -383,3 +383,11 @@ pub fn _Unwind_Resume() {} #[lang = "eh_personality"] #[no_mangle] pub extern "C" fn eh_personality() {} + +#[cfg(all(windows, target_env = "gnu"))] +mod mingw_unwidning { + #[no_mangle] + pub fn rust_eh_personality() {} + #[no_mangle] + pub fn rust_eh_unwind_resume() {} +} -- cgit 1.4.1-3-g733a5 From a6034d0b7be09158e287df7e49460cf7dc845296 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 13:02:22 -0700 Subject: More fixes for i686-mingw --- library/compiler-builtins/examples/intrinsics.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 7766687c8b5..ccd701569d9 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -390,4 +390,8 @@ mod mingw_unwidning { pub fn rust_eh_personality() {} #[no_mangle] pub fn rust_eh_unwind_resume() {} + #[no_mangle] + pub fn rust_eh_register_frames() {} + #[no_mangle] + pub fn rust_eh_unregister_frames() {} } -- cgit 1.4.1-3-g733a5 From 26a01f97a8bbe482599e98d3aa852c7513ff8b60 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 13:05:56 -0700 Subject: Bump to 0.1.9 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d30af40511d..7c0cf0d74bc 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.8" +version = "0.1.9" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 78d40ed30c560a2deda73c34637a09f3ee285c9f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 15:41:20 -0500 Subject: Update azure pipelines badge --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index b290cbff889..f0724bffe1d 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,6 +1,6 @@ # `compiler-builtins` -[![Build Status](https://dev.azure.com/rust-lang/compiler-builtins/_apis/build/status/compiler-builtins-CI?branchName=master)](https://dev.azure.com/rust-lang/compiler-builtins/_build/latest?definitionId=2&branchName=master) +[![Build Status](https://dev.azure.com/rust-lang/compiler-builtins/_apis/build/status/rust-lang-nursery.compiler-builtins?branchName=master)](https://dev.azure.com/rust-lang/compiler-builtins/_build/latest?definitionId=6&branchName=master) > Porting `compiler-rt` intrinsics to Rust -- cgit 1.4.1-3-g733a5 From 36e4db03641d734815d799731c8016a0f7f68749 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Mon, 8 Apr 2019 16:30:33 +0200 Subject: Update submodule for VS 2019 support --- library/compiler-builtins/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index 84c0bd0158c..03fc28f9273 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit 84c0bd0158c3ff86052be1b07a3ddc3c4f5ba52a +Subproject commit 03fc28f9273eeab16f1005f982dfde5900bddb29 -- cgit 1.4.1-3-g733a5 From c2e263422329e2daeb81d82f3a3bd98e66be844c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 8 Apr 2019 07:52:05 -0700 Subject: Bump to 0.1.10 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7c0cf0d74bc..1dfe6c73f16 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.9" +version = "0.1.10" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 76184c21e0791c99855ac30ea0e1d5f15766a796 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 8 Apr 2019 07:55:09 -0700 Subject: Add instructions for publishing --- library/compiler-builtins/PUBLISHING.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 library/compiler-builtins/PUBLISHING.md diff --git a/library/compiler-builtins/PUBLISHING.md b/library/compiler-builtins/PUBLISHING.md new file mode 100644 index 00000000000..ad100dee08f --- /dev/null +++ b/library/compiler-builtins/PUBLISHING.md @@ -0,0 +1,17 @@ +# Publishing to crates.io + +Publishing `compiler-builtins` to crates.io takes a few steps unfortunately. +It's not great, but it works for now. PRs to improve this process would be +greatly appreciated! + +1. Make sure you've got a clean working tree and it's updated with the latest + changes on `master` +2. Edit `Cargo.toml` to bump the version number +3. Commit this change +4. Run `git tag` to create a tag for this version +5. Delete the `libm/Cargo.toml` file +6. Comment out the `[dev-dependencies]` section of `Cargo.toml` +7. Run `cargo +nightly publish --allow-dirty` +8. Push the tag +9. Push the commit +10. Undo changes to `Cargo.toml` and the `libm` submodule -- cgit 1.4.1-3-g733a5 From 63c0bd2522d7f1cc897c3467346f713eaad7fda5 Mon Sep 17 00:00:00 2001 From: Goirad Date: Mon, 29 Apr 2019 14:42:14 -0700 Subject: Added missing fdim signature --- library/compiler-builtins/src/math.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index dfdd99cdf93..b6195553916 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -64,6 +64,7 @@ no_mangle! { fn cbrtf(n: f32) -> f32; fn coshf(n: f32) -> f32; fn expm1f(n: f32) -> f32; + fn fdim(a: f64, b: f64) -> f64; fn fdimf(a: f32, b: f32) -> f32; fn hypotf(x: f32, y: f32) -> f32; fn log1pf(n: f32) -> f32; -- cgit 1.4.1-3-g733a5 From 3789bb1a981a7f2dc8e9374d87961633078f59a8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 30 Apr 2019 10:08:23 -0700 Subject: Bump to 0.1.11 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 1dfe6c73f16..fdca20143b9 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.10" +version = "0.1.11" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From fa6d92bb415938c532e60dc3536e27b4b7146c24 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 09:15:01 -0500 Subject: Set up CI with Azure Pipelines [skip ci] --- library/compiler-builtins/libm/azure-pipelines.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 library/compiler-builtins/libm/azure-pipelines.yml diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml new file mode 100644 index 00000000000..c23ced43ca0 --- /dev/null +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -0,0 +1,19 @@ +# Starter pipeline +# Start with a minimal pipeline that you can customize to build and deploy your code. +# Add steps that build, run tests, deploy, and more: +# https://aka.ms/yaml + +trigger: +- master + +pool: + vmImage: 'Ubuntu-16.04' + +steps: +- script: echo Hello, world! + displayName: 'Run a one-line script' + +- script: | + echo Add other tasks to build, test, and deploy your project. + echo See https://aka.ms/yaml + displayName: 'Run a multi-line script' -- cgit 1.4.1-3-g733a5 From ae69253dc7b6f33de149fa5b09679bc2c603a702 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 08:12:00 -0700 Subject: Move crates to `crates` folder --- library/compiler-builtins/libm/Cargo.toml | 10 +- library/compiler-builtins/libm/azure-pipelines.yml | 156 ++++++- library/compiler-builtins/libm/cb/Cargo.toml | 6 - library/compiler-builtins/libm/cb/src/lib.rs | 9 - .../libm/ci/azure-install-rust.yml | 23 + .../compiler-builtins/libm/ci/azure-test-all.yml | 41 ++ .../crates/compiler-builtins-smoke-test/Cargo.toml | 6 + .../crates/compiler-builtins-smoke-test/src/lib.rs | 9 + .../libm/crates/input-generator/Cargo.toml | 7 + .../libm/crates/input-generator/src/main.rs | 189 +++++++++ .../libm/crates/musl-generator/Cargo.toml | 9 + .../libm/crates/musl-generator/src/macros.rs | 191 +++++++++ .../libm/crates/musl-generator/src/main.rs | 97 +++++ .../libm/crates/newlib-generator/Cargo.toml | 7 + .../libm/crates/newlib-generator/src/macros.rs | 245 +++++++++++ .../libm/crates/newlib-generator/src/main.rs | 32 ++ .../libm/crates/shared/Cargo.toml | 7 + .../libm/crates/shared/src/lib.rs | 469 ++++++++++++++++++++ .../libm/input-generator/Cargo.toml | 7 - .../libm/input-generator/src/main.rs | 189 --------- library/compiler-builtins/libm/math/.cargo/config | 11 - library/compiler-builtins/libm/math/Cargo.toml | 8 - library/compiler-builtins/libm/math/Cross.toml | 2 - .../libm/musl-generator/Cargo.toml | 9 - .../libm/musl-generator/src/macros.rs | 191 --------- .../libm/musl-generator/src/main.rs | 97 ----- .../libm/newlib-generator/Cargo.toml | 7 - .../libm/newlib-generator/src/macros.rs | 245 ----------- .../libm/newlib-generator/src/main.rs | 32 -- library/compiler-builtins/libm/shared/Cargo.toml | 7 - library/compiler-builtins/libm/shared/src/lib.rs | 471 --------------------- library/compiler-builtins/libm/src/math/acosf.rs | 14 + 32 files changed, 1491 insertions(+), 1312 deletions(-) delete mode 100644 library/compiler-builtins/libm/cb/Cargo.toml delete mode 100644 library/compiler-builtins/libm/cb/src/lib.rs create mode 100644 library/compiler-builtins/libm/ci/azure-install-rust.yml create mode 100644 library/compiler-builtins/libm/ci/azure-test-all.yml create mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml create mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs create mode 100644 library/compiler-builtins/libm/crates/input-generator/Cargo.toml create mode 100644 library/compiler-builtins/libm/crates/input-generator/src/main.rs create mode 100644 library/compiler-builtins/libm/crates/musl-generator/Cargo.toml create mode 100644 library/compiler-builtins/libm/crates/musl-generator/src/macros.rs create mode 100644 library/compiler-builtins/libm/crates/musl-generator/src/main.rs create mode 100644 library/compiler-builtins/libm/crates/newlib-generator/Cargo.toml create mode 100644 library/compiler-builtins/libm/crates/newlib-generator/src/macros.rs create mode 100644 library/compiler-builtins/libm/crates/newlib-generator/src/main.rs create mode 100644 library/compiler-builtins/libm/crates/shared/Cargo.toml create mode 100644 library/compiler-builtins/libm/crates/shared/src/lib.rs delete mode 100644 library/compiler-builtins/libm/input-generator/Cargo.toml delete mode 100644 library/compiler-builtins/libm/input-generator/src/main.rs delete mode 100644 library/compiler-builtins/libm/math/.cargo/config delete mode 100644 library/compiler-builtins/libm/math/Cargo.toml delete mode 100644 library/compiler-builtins/libm/math/Cross.toml delete mode 100644 library/compiler-builtins/libm/musl-generator/Cargo.toml delete mode 100644 library/compiler-builtins/libm/musl-generator/src/macros.rs delete mode 100644 library/compiler-builtins/libm/musl-generator/src/main.rs delete mode 100644 library/compiler-builtins/libm/newlib-generator/Cargo.toml delete mode 100644 library/compiler-builtins/libm/newlib-generator/src/macros.rs delete mode 100644 library/compiler-builtins/libm/newlib-generator/src/main.rs delete mode 100644 library/compiler-builtins/libm/shared/Cargo.toml delete mode 100644 library/compiler-builtins/libm/shared/src/lib.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index f28024d041c..b4f07eeeed2 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -17,11 +17,11 @@ stable = [] [workspace] members = [ - "cb", - "input-generator", - "musl-generator", - "newlib-generator", - "shared", + "crates/compiler-builtins-smoke-test", + "crates/input-generator", + "crates/musl-generator", + "crates/newlib-generator", + "crates/shared", ] [dev-dependencies] diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml index c23ced43ca0..36271ec1bea 100644 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -1,19 +1,143 @@ -# Starter pipeline -# Start with a minimal pipeline that you can customize to build and deploy your code. -# Add steps that build, run tests, deploy, and more: -# https://aka.ms/yaml - trigger: -- master - -pool: - vmImage: 'Ubuntu-16.04' + - master -steps: -- script: echo Hello, world! - displayName: 'Run a one-line script' +jobs: + - job: Docker + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-install-rust.yml + env: + TOOLCHAIN: nightly + - bash: rustup target add $TARGET + displayName: "Install rust cross target" + - bash: | + set -e + mkdir cross + curl -L https://github.com/rust-embedded/cross/releases/download/v0.1.14/cross-v0.1.14-x86_64-unknown-linux-musl.tar.gz | tar xzf - -C $HOME/.cargo/bin + displayName: "Install cross" + - bash: cross test --lib --features checked --target $TARGET --release + displayName: "Run lib tests" + - bash: cross test --tests --features checked --target $TARGET --release + displayName: "Run integration tests" + strategy: + matrix: + aarch64: + TARGET: aarch64-unknown-linux-gnu + armhv: + TARGET: arm-unknown-linux-gnueabihf + armv7: + TARGET: armv7-unknown-linux-gnueabihf + i586: + TARGET: i586-unknown-linux-gnu + i686: + TARGET: i686-unknown-linux-gnu + mips: + TARGET: mips-unknown-linux-gnu + mips64: + TARGET: mips64-unknown-linux-gnuabi64 + mips64el: + TARGET: mips64el-unknown-linux-gnuabi64 + powerpc: + TARGET: powerpc-unknown-linux-gnu + powerpc64: + TARGET: powerpc64-unknown-linux-gnu + powerpc64le: + TARGET: powerpc64le-unknown-linux-gnu + x86_64: + TARGET: x86_64-unknown-linux-gnu -- script: | - echo Add other tasks to build, test, and deploy your project. - echo See https://aka.ms/yaml - displayName: 'Run a multi-line script' + # - job: Linux + # pool: + # vmImage: ubuntu-16.04 + # steps: + # - template: ci/azure-test-all.yml + # strategy: + # matrix: + # stable: + # TOOLCHAIN: stable + # beta: + # TOOLCHAIN: beta + # nightly: + # TOOLCHAIN: nightly + # + # - job: macOS + # pool: + # vmImage: macos-10.13 + # steps: + # - template: ci/azure-test-all.yml + # strategy: + # matrix: + # x86_64: + # TARGET: x86_64-apple-darwin + # + # - job: iOS + # pool: + # vmImage: macos-10.13 + # steps: + # - checkout: self + # submodules: true + # - template: ci/azure-install-rust.yml + # - script: rustup target add $TARGET + # displayName: "Install rust cross target" + # - bash: | + # set -e + # export SDK_PATH=`xcrun --show-sdk-path --sdk $SDK` + # export RUSTFLAGS="-C link-arg=-isysroot -C link-arg=$SDK_PATH" + # cargo test --no-run --target $TARGET + # displayName: "Build for iOS" + # strategy: + # matrix: + # aarch64: + # TARGET: aarch64-apple-ios + # SDK: iphoneos + # armv7: + # TARGET: armv7-apple-ios + # SDK: iphoneos + # armv7s: + # TARGET: armv7s-apple-ios + # SDK: iphoneos + # i386: + # TARGET: i386-apple-ios + # SDK: iphonesimulator + # x86_64: + # TARGET: x86_64-apple-ios + # SDK: iphonesimulator + # + # - job: wasm + # pool: + # vmImage: ubuntu-16.04 + # steps: + # - checkout: self + # submodules: true + # - template: ci/azure-install-rust.yml + # - script: rustup target add wasm32-unknown-unknown + # displayName: "Install rust cross target" + # - script: cargo build --target wasm32-unknown-unknown + # displayName: "Build for wasm" + # + # - job: Windows + # pool: + # vmImage: vs2017-win2016 + # steps: + # - template: ci/azure-test-all.yml + # strategy: + # matrix: + # x86_64-msvc: + # TARGET: x86_64-pc-windows-msvc + # i686-msvc: + # TARGET: i686-pc-windows-msvc + # x86_64-gnu: + # TARGET: x86_64-pc-windows-gnu + # i686-gnu: + # TARGET: i686-pc-windows-gnu + # + # - job: Windows_arm64 + # pool: + # vmImage: windows-2019 + # steps: + # - template: ci/azure-install-rust.yml + # - script: rustup target add aarch64-pc-windows-msvc + # displayName: "Install rust cross target" + # - script: cargo test --no-run --target aarch64-pc-windows-msvc + # displayName: "Build for arm64" diff --git a/library/compiler-builtins/libm/cb/Cargo.toml b/library/compiler-builtins/libm/cb/Cargo.toml deleted file mode 100644 index 40e75dd22fd..00000000000 --- a/library/compiler-builtins/libm/cb/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "cb" -version = "0.1.0" -authors = ["Jorge Aparicio "] - -[dependencies] diff --git a/library/compiler-builtins/libm/cb/src/lib.rs b/library/compiler-builtins/libm/cb/src/lib.rs deleted file mode 100644 index 439ba7dc4e6..00000000000 --- a/library/compiler-builtins/libm/cb/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Fake compiler-builtins crate -//! -//! This is used to test that we can source import `libm` into the compiler-builtins crate. - -#![allow(dead_code)] -#![no_std] - -#[path = "../../src/math/mod.rs"] -mod libm; diff --git a/library/compiler-builtins/libm/ci/azure-install-rust.yml b/library/compiler-builtins/libm/ci/azure-install-rust.yml new file mode 100644 index 00000000000..fa7eae459b7 --- /dev/null +++ b/library/compiler-builtins/libm/ci/azure-install-rust.yml @@ -0,0 +1,23 @@ +steps: + - bash: | + set -e + toolchain=$TOOLCHAIN + if [ "$toolchain" = "" ]; then + toolchain=stable + fi + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain + echo "##vso[task.prependpath]$HOME/.cargo/bin" + displayName: Install rust (unix) + condition: ne( variables['Agent.OS'], 'Windows_NT' ) + + - script: | + curl -sSf -o rustup-init.exe https://win.rustup.rs + rustup-init.exe -y --default-toolchain stable-%TARGET% + echo ##vso[task.prependpath]%USERPROFILE%\.cargo\bin + displayName: Install rust (windows) + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + + - script: | + rustc -Vv + cargo -V + displayName: Query rust and cargo versions diff --git a/library/compiler-builtins/libm/ci/azure-test-all.yml b/library/compiler-builtins/libm/ci/azure-test-all.yml new file mode 100644 index 00000000000..b2b7124d3ff --- /dev/null +++ b/library/compiler-builtins/libm/ci/azure-test-all.yml @@ -0,0 +1,41 @@ +steps: + - checkout: self + submodules: true + - template: azure-install-rust.yml + + - bash: cargo build --manifest-path backtrace-sys/Cargo.toml + displayName: "Build backtrace-sys" + - bash: cargo build + displayName: "Build backtrace" + - bash: cargo test + displayName: "Test backtrace" + - bash: cargo test --no-default-features + displayName: "Test backtrace (-default)" + - bash: cargo test --no-default-features --features 'std' + displayName: "Test backtrace (-default + std)" + - bash: cargo test --no-default-features --features 'libunwind std' + displayName: "Test backtrace (-default + libunwind)" + - bash: cargo test --no-default-features --features 'libunwind dladdr std' + displayName: "Test backtrace (-default + libunwind + dladdr)" + - bash: cargo test --no-default-features --features 'libunwind libbacktrace std' + displayName: "Test backtrace (-default + libunwind + libbacktrace)" + - bash: cargo test --no-default-features --features 'unix-backtrace std' + displayName: "Test backtrace (-default + unix-backtrace)" + - bash: cargo test --no-default-features --features 'unix-backtrace dladdr std' + displayName: "Test backtrace (-default + unix-backtrace + dladdr)" + - bash: cargo test --no-default-features --features 'unix-backtrace libbacktrace std' + displayName: "Test backtrace (-default + unix-backtrace + libbacktrace)" + - bash: cargo test --no-default-features --features 'serialize-serde std' + displayName: "Test backtrace (-default + serialize-serde + std)" + - bash: cargo test --no-default-features --features 'serialize-rustc std' + displayName: "Test backtrace (-default + serialize-rustc + std)" + - bash: cargo test --no-default-features --features 'serialize-rustc serialize-serde std' + displayName: "Test backtrace (-default + serialize-rustc + serialize-serde + std)" + - bash: cargo test --no-default-features --features 'cpp_demangle std' + displayName: "Test backtrace (-default + cpp_demangle + std)" + - bash: cargo test --no-default-features --features 'gimli-symbolize std' + displayName: "Test backtrace (-default + gimli-symbolize + std)" + - bash: cargo test --no-default-features --features 'dbghelp std' + displayName: "Test backtrace (-default + dbghelp + std)" + - bash: cd ./cpp_smoke_test && cargo test + displayName: "Test cpp_smoke_test" diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml new file mode 100644 index 00000000000..40e75dd22fd --- /dev/null +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "cb" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[dependencies] diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs new file mode 100644 index 00000000000..7fad301b983 --- /dev/null +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -0,0 +1,9 @@ +//! Fake compiler-builtins crate +//! +//! This is used to test that we can source import `libm` into the compiler-builtins crate. + +#![allow(dead_code)] +#![no_std] + +#[path = "../../../src/math/mod.rs"] +mod libm; diff --git a/library/compiler-builtins/libm/crates/input-generator/Cargo.toml b/library/compiler-builtins/libm/crates/input-generator/Cargo.toml new file mode 100644 index 00000000000..fef2558a8b0 --- /dev/null +++ b/library/compiler-builtins/libm/crates/input-generator/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "input-generator" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[dependencies] +rand = "0.5.4" diff --git a/library/compiler-builtins/libm/crates/input-generator/src/main.rs b/library/compiler-builtins/libm/crates/input-generator/src/main.rs new file mode 100644 index 00000000000..0746ea477e8 --- /dev/null +++ b/library/compiler-builtins/libm/crates/input-generator/src/main.rs @@ -0,0 +1,189 @@ +extern crate rand; + +use std::collections::BTreeSet; +use std::error::Error; +use std::fs::{self, File}; +use std::io::Write; + +use rand::{RngCore, SeedableRng, XorShiftRng}; + +const NTESTS: usize = 10_000; + +fn main() -> Result<(), Box> { + let mut rng = XorShiftRng::from_rng(&mut rand::thread_rng())?; + + fs::remove_dir_all("bin").ok(); + fs::create_dir_all("bin/input")?; + fs::create_dir_all("bin/output")?; + + f32(&mut rng)?; + f32f32(&mut rng)?; + f32f32f32(&mut rng)?; + f32i16(&mut rng)?; + f64(&mut rng)?; + f64f64(&mut rng)?; + f64f64f64(&mut rng)?; + f64i16(&mut rng)?; + + Ok(()) +} + +fn f32(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut set = BTreeSet::new(); + + while set.len() < NTESTS { + let f = f32::from_bits(rng.next_u32()); + + if f.is_nan() { + continue; + } + + set.insert(f.to_bits()); + } + + let mut f = File::create("bin/input/f32")?; + for i in set { + f.write_all(&i.to_le_bytes())?; + } + + Ok(()) +} + +fn f32f32(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f32f32")?; + let mut i = 0; + while i < NTESTS { + let x0 = f32::from_bits(rng.next_u32()); + let x1 = f32::from_bits(rng.next_u32()); + + if x0.is_nan() || x1.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_le_bytes())?; + f.write_all(&x1.to_bits().to_le_bytes())?; + } + + Ok(()) +} + +fn f32i16(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f32i16")?; + let mut i = 0; + while i < NTESTS { + let x0 = f32::from_bits(rng.next_u32()); + let x1 = rng.next_u32() as i16; + + if x0.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_le_bytes())?; + f.write_all(&x1.to_le_bytes())?; + } + + Ok(()) +} + +fn f32f32f32(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f32f32f32")?; + let mut i = 0; + while i < NTESTS { + let x0 = f32::from_bits(rng.next_u32()); + let x1 = f32::from_bits(rng.next_u32()); + let x2 = f32::from_bits(rng.next_u32()); + + if x0.is_nan() || x1.is_nan() || x2.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_le_bytes())?; + f.write_all(&x1.to_bits().to_le_bytes())?; + f.write_all(&x2.to_bits().to_le_bytes())?; + } + + Ok(()) +} + +fn f64(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut set = BTreeSet::new(); + + while set.len() < NTESTS { + let f = f64::from_bits(rng.next_u64()); + + if f.is_nan() { + continue; + } + + set.insert(f.to_bits()); + } + + let mut f = File::create("bin/input/f64")?; + for i in set { + f.write_all(&i.to_le_bytes())?; + } + + Ok(()) +} + +fn f64f64(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f64f64")?; + let mut i = 0; + while i < NTESTS { + let x0 = f64::from_bits(rng.next_u64()); + let x1 = f64::from_bits(rng.next_u64()); + + if x0.is_nan() || x1.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_le_bytes())?; + f.write_all(&x1.to_bits().to_le_bytes())?; + } + + Ok(()) +} + +fn f64f64f64(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f64f64f64")?; + let mut i = 0; + while i < NTESTS { + let x0 = f64::from_bits(rng.next_u64()); + let x1 = f64::from_bits(rng.next_u64()); + let x2 = f64::from_bits(rng.next_u64()); + + if x0.is_nan() || x1.is_nan() || x2.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_le_bytes())?; + f.write_all(&x1.to_bits().to_le_bytes())?; + f.write_all(&x2.to_bits().to_le_bytes())?; + } + + Ok(()) +} + +fn f64i16(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f64i16")?; + let mut i = 0; + while i < NTESTS { + let x0 = f64::from_bits(rng.next_u64()); + let x1 = rng.next_u32() as i16; + + if x0.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_le_bytes())?; + f.write_all(&x1.to_le_bytes())?; + } + + Ok(()) +} diff --git a/library/compiler-builtins/libm/crates/musl-generator/Cargo.toml b/library/compiler-builtins/libm/crates/musl-generator/Cargo.toml new file mode 100644 index 00000000000..0564f353611 --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-generator/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "musl-generator" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[dependencies] +lazy_static = "1.0.2" +shared = { path = "../shared" } +libm = { path = ".." } diff --git a/library/compiler-builtins/libm/crates/musl-generator/src/macros.rs b/library/compiler-builtins/libm/crates/musl-generator/src/macros.rs new file mode 100644 index 00000000000..e47c0ab6f96 --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-generator/src/macros.rs @@ -0,0 +1,191 @@ +macro_rules! f32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f32) -> f32 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for x in shared::F32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f32) -> f32; + } + + $fun(*x) + }; + + $fun.write_all(&y.to_bits().to_le_bytes())?; + )+ + } + }}; +} + +macro_rules! f32f32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f32, f32) -> f32 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1) in shared::F32F32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f32, _: f32) -> f32; + } + + $fun(*x0, *x1) + }; + + $fun.write_all(&y.to_bits().to_le_bytes())?; + )+ + } + }}; +} + +macro_rules! f32f32f32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f32, f32, f32) -> f32 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1, x2) in shared::F32F32F32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f32, _: f32, _: f32) -> f32; + } + + $fun(*x0, *x1, *x2) + }; + + $fun.write_all(&y.to_bits().to_le_bytes())?; + )+ + } + }}; +} + +macro_rules! f32i32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f32, i32) -> f32 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1) in shared::F32I32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f32, _: i32) -> f32; + } + + $fun(*x0, *x1 as i32) + }; + + $fun.write_all(&y.to_bits().to_le_bytes())?; + )+ + } + }}; +} + +macro_rules! f64 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f64) -> f64 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for x in shared::F64.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f64) -> f64; + } + + $fun(*x) + }; + + $fun.write_all(&y.to_bits().to_le_bytes())?; + )+ + } + }}; +} + +macro_rules! f64f64 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f64, f64) -> f64 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1) in shared::F64F64.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f64, _: f64) -> f64; + } + + $fun(*x0, *x1) + }; + + $fun.write_all(&y.to_bits().to_le_bytes())?; + )+ + } + }}; +} + +macro_rules! f64f64f64 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f64, f64, f64) -> f64 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1, x2) in shared::F64F64F64.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f64, _: f64, _: f64) -> f64; + } + + $fun(*x0, *x1, *x2) + }; + + $fun.write_all(&y.to_bits().to_le_bytes())?; + )+ + } + }}; +} + +macro_rules! f64i32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f64, i32) -> f64 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1) in shared::F64I32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f64, _: i32) -> f64; + } + + $fun(*x0, *x1 as i32) + }; + + $fun.write_all(&y.to_bits().to_le_bytes())?; + )+ + } + }}; +} diff --git a/library/compiler-builtins/libm/crates/musl-generator/src/main.rs b/library/compiler-builtins/libm/crates/musl-generator/src/main.rs new file mode 100644 index 00000000000..6e57e856dc6 --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-generator/src/main.rs @@ -0,0 +1,97 @@ +extern crate libm; +extern crate shared; + +use std::error::Error; +use std::fs::File; +use std::io::Write; + +#[macro_use] +mod macros; + +fn main() -> Result<(), Box> { + f32! { + acosf, + asinf, + atanf, + cbrtf, + ceilf, + cosf, + coshf, + exp2f, + expf, + expm1f, + fabsf, + floorf, + log10f, + log1pf, + log2f, + logf, + roundf, + sinf, + sinhf, + sqrtf, + tanf, + tanhf, + truncf, + } + + f32f32! { + atan2f, + fdimf, + fmodf, + hypotf, + powf, + } + + f32i32! { + scalbnf, + } + + f32f32f32! { + fmaf, + } + + f64! { + acos, + asin, + atan, + cbrt, + ceil, + cos, + cosh, + exp, + exp2, + expm1, + fabs, + floor, + log, + log10, + log1p, + log2, + round, + sin, + sinh, + sqrt, + tan, + tanh, + trunc, + } + + f64f64! { + atan2, + fdim, + fmod, + hypot, + pow, + } + + f64i32! { + scalbn, + } + + f64f64f64! { + fma, + } + + Ok(()) +} diff --git a/library/compiler-builtins/libm/crates/newlib-generator/Cargo.toml b/library/compiler-builtins/libm/crates/newlib-generator/Cargo.toml new file mode 100644 index 00000000000..5766cb4b7a0 --- /dev/null +++ b/library/compiler-builtins/libm/crates/newlib-generator/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "newlib-generator" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[dependencies] +shared = { path = "../shared" } diff --git a/library/compiler-builtins/libm/crates/newlib-generator/src/macros.rs b/library/compiler-builtins/libm/crates/newlib-generator/src/macros.rs new file mode 100644 index 00000000000..84315a777bd --- /dev/null +++ b/library/compiler-builtins/libm/crates/newlib-generator/src/macros.rs @@ -0,0 +1,245 @@ +macro_rules! f32 { + ($($fun:ident,)+) => { + $( + let fun = stringify!($fun); + + fs::create_dir_all("math/src")?; + + let main = format!(" +#![no_main] +#![no_std] + +#[macro_use] +extern crate qemu_arm_rt as rt; + +use core::u32; + +use rt::{{io, process}}; + +entry!(main); + +fn main() {{ + run().unwrap_or_else(|e| {{ + eprintln!(\"error: {{}}\", e); + process::exit(1); + }}) +}} + +fn run() -> Result<(), usize> {{ + #[link(name = \"m\")] + extern \"C\" {{ + fn {0}(_: f32) -> f32; + }} + + let mut buf = [0; 4]; + while let Ok(()) = io::Stdin.read_exact(&mut buf) {{ + let x = f32::from_bits(u32::from_bytes(buf)); + let y = unsafe {{ {0}(x) }}; + + io::Stdout.write_all(&y.to_bits().to_bytes())?; + }} + + Ok(()) +}} + +#[no_mangle] +pub fn __errno() -> *mut i32 {{ + static mut ERRNO: i32 = 0; + unsafe {{ &mut ERRNO }} +}} +", fun); + + File::create("math/src/main.rs")?.write_all(main.as_bytes())?; + + assert!( + Command::new("cross") + .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) + .current_dir("math") + .status()? + .success() + ); + + let mut qemu = Command::new("qemu-arm") + .arg("math/target/thumbv7em-none-eabi/release/math") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + + qemu.stdin.as_mut().take().unwrap().write_all(F32)?; + + let output = qemu.wait_with_output()?; + + File::create(concat!("bin/output/newlib.", stringify!($fun)))? + .write_all(&output.stdout)?; + )+ + } +} + +macro_rules! f32f32 { + ($($fun:ident,)+) => { + $( + let fun = stringify!($fun); + + fs::create_dir_all("math/src")?; + + let main = format!(" +#![no_main] +#![no_std] + +#[macro_use] +extern crate qemu_arm_rt as rt; + +use core::u32; + +use rt::{{io, process}}; + +entry!(main); + +fn main() {{ + run().unwrap_or_else(|e| {{ + eprintln!(\"error: {{}}\", e); + process::exit(1); + }}) +}} + +fn run() -> Result<(), usize> {{ + #[link(name = \"m\")] + extern \"C\" {{ + fn {0}(_: f32, _: f32) -> f32; + }} + + let mut chunk = [0; 8]; + while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{ + let mut buf = [0; 4]; + buf.copy_from_slice(&chunk[..4]); + let x0 = f32::from_bits(u32::from_bytes(buf)); + + buf.copy_from_slice(&chunk[4..]); + let x1 = f32::from_bits(u32::from_bytes(buf)); + + let y = unsafe {{ {0}(x0, x1) }}; + + io::Stdout.write_all(&y.to_bits().to_bytes())?; + }} + + Ok(()) +}} + +#[no_mangle] +pub fn __errno() -> *mut i32 {{ + static mut ERRNO: i32 = 0; + unsafe {{ &mut ERRNO }} +}} +", fun); + + File::create("math/src/main.rs")?.write_all(main.as_bytes())?; + + assert!( + Command::new("cross") + .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) + .current_dir("math") + .status()? + .success() + ); + + let mut qemu = Command::new("qemu-arm") + .arg("math/target/thumbv7em-none-eabi/release/math") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + + qemu.stdin.as_mut().take().unwrap().write_all(F32)?; + + let output = qemu.wait_with_output()?; + + File::create(concat!("bin/output/newlib.", stringify!($fun)))? + .write_all(&output.stdout)?; + )+ + } +} + +macro_rules! f32f32f32 { + ($($fun:ident,)+) => { + $( + let fun = stringify!($fun); + + fs::create_dir_all("math/src")?; + + let main = format!(" +#![no_main] +#![no_std] + +#[macro_use] +extern crate qemu_arm_rt as rt; + +use core::u32; + +use rt::{{io, process}}; + +entry!(main); + +fn main() {{ + run().unwrap_or_else(|e| {{ + eprintln!(\"error: {{}}\", e); + process::exit(1); + }}) +}} + +fn run() -> Result<(), usize> {{ + #[link(name = \"m\")] + extern \"C\" {{ + fn {0}(_: f32, _: f32, _: f32) -> f32; + }} + + let mut chunk = [0; 12]; + while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{ + let mut buf = [0; 4]; + buf.copy_from_slice(&chunk[..4]); + let x0 = f32::from_bits(u32::from_bytes(buf)); + + buf.copy_from_slice(&chunk[4..8]); + let x1 = f32::from_bits(u32::from_bytes(buf)); + + buf.copy_from_slice(&chunk[8..]); + let x2 = f32::from_bits(u32::from_bytes(buf)); + + let y = unsafe {{ {0}(x0, x1, x2) }}; + + io::Stdout.write_all(&y.to_bits().to_bytes())?; + }} + + Ok(()) +}} + +#[no_mangle] +pub fn __errno() -> *mut i32 {{ + static mut ERRNO: i32 = 0; + unsafe {{ &mut ERRNO }} +}} +", fun); + + File::create("math/src/main.rs")?.write_all(main.as_bytes())?; + + assert!( + Command::new("cross") + .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) + .current_dir("math") + .status()? + .success() + ); + + let mut qemu = Command::new("qemu-arm") + .arg("math/target/thumbv7em-none-eabi/release/math") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + + qemu.stdin.as_mut().take().unwrap().write_all(F32)?; + + let output = qemu.wait_with_output()?; + + File::create(concat!("bin/output/newlib.", stringify!($fun)))? + .write_all(&output.stdout)?; + )+ + } +} diff --git a/library/compiler-builtins/libm/crates/newlib-generator/src/main.rs b/library/compiler-builtins/libm/crates/newlib-generator/src/main.rs new file mode 100644 index 00000000000..52a97cabbfd --- /dev/null +++ b/library/compiler-builtins/libm/crates/newlib-generator/src/main.rs @@ -0,0 +1,32 @@ +extern crate shared; + +use std::error::Error; +use std::fs::{self, File}; +use std::io::Write; +use std::process::{Command, Stdio}; + +#[macro_use] +mod macros; + +fn main() -> Result<(), Box> { + const F32: &[u8] = include_bytes!("../../bin/input/f32"); + + f32! { + asinf, + cbrtf, + cosf, + exp2f, + sinf, + tanf, + } + + f32f32! { + hypotf, + } + + f32f32f32! { + fmaf, + } + + Ok(()) +} diff --git a/library/compiler-builtins/libm/crates/shared/Cargo.toml b/library/compiler-builtins/libm/crates/shared/Cargo.toml new file mode 100644 index 00000000000..d7782378101 --- /dev/null +++ b/library/compiler-builtins/libm/crates/shared/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "shared" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[dependencies] +lazy_static = "1.0.2" diff --git a/library/compiler-builtins/libm/crates/shared/src/lib.rs b/library/compiler-builtins/libm/crates/shared/src/lib.rs new file mode 100644 index 00000000000..17c20a332e5 --- /dev/null +++ b/library/compiler-builtins/libm/crates/shared/src/lib.rs @@ -0,0 +1,469 @@ +#[macro_use] +extern crate lazy_static; + +lazy_static! { + pub static ref F32: Vec = { + let bytes = include_bytes!("../../bin/input/f32"); + + bytes + .chunks_exact(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) + }) + .collect() + }; + pub static ref F32F32: Vec<(f32, f32)> = { + let bytes = include_bytes!("../../bin/input/f32f32"); + + bytes + .chunks_exact(8) + .map(|chunk| { + let mut x0 = [0; 4]; + let mut x1 = [0; 4]; + x0.copy_from_slice(&chunk[..4]); + x1.copy_from_slice(&chunk[4..]); + + ( + f32::from_bits(u32::from_le(u32::from_le_bytes(x0))), + f32::from_bits(u32::from_le(u32::from_le_bytes(x1))), + ) + }) + .collect() + }; + pub static ref F32F32F32: Vec<(f32, f32, f32)> = { + let bytes = include_bytes!("../../bin/input/f32f32f32"); + + bytes + .chunks_exact(12) + .map(|chunk| { + let mut x0 = [0; 4]; + let mut x1 = [0; 4]; + let mut x2 = [0; 4]; + x0.copy_from_slice(&chunk[..4]); + x1.copy_from_slice(&chunk[4..8]); + x2.copy_from_slice(&chunk[8..]); + + ( + f32::from_bits(u32::from_le(u32::from_le_bytes(x0))), + f32::from_bits(u32::from_le(u32::from_le_bytes(x1))), + f32::from_bits(u32::from_le(u32::from_le_bytes(x2))), + ) + }) + .collect() + }; + pub static ref F32I32: Vec<(f32, i32)> = { + let bytes = include_bytes!("../../bin/input/f32i16"); + + bytes + .chunks_exact(6) + .map(|chunk| { + let mut x0 = [0; 4]; + let mut x1 = [0; 2]; + x0.copy_from_slice(&chunk[..4]); + x1.copy_from_slice(&chunk[4..]); + + ( + f32::from_bits(u32::from_le(u32::from_le_bytes(x0))), + i16::from_le(i16::from_le_bytes(x1)) as i32, + ) + }) + .collect() + }; + pub static ref F64: Vec = { + let bytes = include_bytes!("../../bin/input/f64"); + + bytes + .chunks_exact(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) + }) + .collect() + }; + pub static ref F64F64: Vec<(f64, f64)> = { + let bytes = include_bytes!("../../bin/input/f64f64"); + + bytes + .chunks_exact(16) + .map(|chunk| { + let mut x0 = [0; 8]; + let mut x1 = [0; 8]; + x0.copy_from_slice(&chunk[..8]); + x1.copy_from_slice(&chunk[8..]); + + ( + f64::from_bits(u64::from_le(u64::from_le_bytes(x0))), + f64::from_bits(u64::from_le(u64::from_le_bytes(x1))), + ) + }) + .collect() + }; + pub static ref F64F64F64: Vec<(f64, f64, f64)> = { + let bytes = include_bytes!("../../bin/input/f64f64f64"); + + bytes + .chunks_exact(24) + .map(|chunk| { + let mut x0 = [0; 8]; + let mut x1 = [0; 8]; + let mut x2 = [0; 8]; + x0.copy_from_slice(&chunk[..8]); + x1.copy_from_slice(&chunk[8..16]); + x2.copy_from_slice(&chunk[16..]); + + ( + f64::from_bits(u64::from_le(u64::from_le_bytes(x0))), + f64::from_bits(u64::from_le(u64::from_le_bytes(x1))), + f64::from_bits(u64::from_le(u64::from_le_bytes(x2))), + ) + }) + .collect() + }; + pub static ref F64I32: Vec<(f64, i32)> = { + let bytes = include_bytes!("../../bin/input/f64i16"); + + bytes + .chunks_exact(10) + .map(|chunk| { + let mut x0 = [0; 8]; + let mut x1 = [0; 2]; + x0.copy_from_slice(&chunk[..8]); + x1.copy_from_slice(&chunk[8..]); + + ( + f64::from_bits(u64::from_le(u64::from_le_bytes(x0))), + i16::from_le(i16::from_le_bytes(x1)) as i32, + ) + }) + .collect() + }; +} + +#[macro_export] +macro_rules! f32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .chunks_exact(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) + }) + .collect::>(); + + for (input, expected) in $crate::F32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) { + if let Err(error) = libm::_eqf(output, *expected) { + panic!( + "INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + input.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}", + input.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f32f32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .chunks_exact(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1), expected) in $crate::F32F32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { + if let Err(error) = libm::_eqf(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f32f32f32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .chunks_exact(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1, i2), expected) in $crate::F32F32F32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) { + if let Err(error) = libm::_eqf(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1.to_bits(), + i2.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f32i32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .chunks_exact(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1), expected) in $crate::F32I32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { + if let Err(error) = libm::_eqf(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1, + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1, + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f64 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .chunks_exact(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) + }) + .collect::>(); + + for (input, expected) in shared::F64.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) { + if let Err(error) = libm::_eq(output, *expected) { + panic!( + "INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + input.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}", + input.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f64f64 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .chunks_exact(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1), expected) in shared::F64F64.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { + if let Err(error) = libm::_eq(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f64f64f64 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .chunks_exact(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1, i2), expected) in shared::F64F64F64.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) { + if let Err(error) = libm::_eq(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1.to_bits(), + i2.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f64i32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .chunks_exact(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1), expected) in shared::F64I32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { + if let Err(error) = libm::_eq(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1, + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1, + expected.to_bits() + ); + } + } + } + )+ + } +} diff --git a/library/compiler-builtins/libm/input-generator/Cargo.toml b/library/compiler-builtins/libm/input-generator/Cargo.toml deleted file mode 100644 index fef2558a8b0..00000000000 --- a/library/compiler-builtins/libm/input-generator/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "input-generator" -version = "0.1.0" -authors = ["Jorge Aparicio "] - -[dependencies] -rand = "0.5.4" diff --git a/library/compiler-builtins/libm/input-generator/src/main.rs b/library/compiler-builtins/libm/input-generator/src/main.rs deleted file mode 100644 index b4a6ad14225..00000000000 --- a/library/compiler-builtins/libm/input-generator/src/main.rs +++ /dev/null @@ -1,189 +0,0 @@ -extern crate rand; - -use std::collections::BTreeSet; -use std::error::Error; -use std::fs::{self, File}; -use std::io::Write; - -use rand::{RngCore, SeedableRng, XorShiftRng}; - -const NTESTS: usize = 10_000; - -fn main() -> Result<(), Box> { - let mut rng = XorShiftRng::from_rng(&mut rand::thread_rng())?; - - fs::remove_dir_all("bin").ok(); - fs::create_dir_all("bin/input")?; - fs::create_dir_all("bin/output")?; - - f32(&mut rng)?; - f32f32(&mut rng)?; - f32f32f32(&mut rng)?; - f32i16(&mut rng)?; - f64(&mut rng)?; - f64f64(&mut rng)?; - f64f64f64(&mut rng)?; - f64i16(&mut rng)?; - - Ok(()) -} - -fn f32(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut set = BTreeSet::new(); - - while set.len() < NTESTS { - let f = f32::from_bits(rng.next_u32()); - - if f.is_nan() { - continue; - } - - set.insert(f.to_bits()); - } - - let mut f = File::create("bin/input/f32")?; - for i in set { - f.write_all(&i.to_bytes())?; - } - - Ok(()) -} - -fn f32f32(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f32f32")?; - let mut i = 0; - while i < NTESTS { - let x0 = f32::from_bits(rng.next_u32()); - let x1 = f32::from_bits(rng.next_u32()); - - if x0.is_nan() || x1.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_bytes())?; - f.write_all(&x1.to_bits().to_bytes())?; - } - - Ok(()) -} - -fn f32i16(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f32i16")?; - let mut i = 0; - while i < NTESTS { - let x0 = f32::from_bits(rng.next_u32()); - let x1 = rng.next_u32() as i16; - - if x0.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_bytes())?; - f.write_all(&x1.to_bytes())?; - } - - Ok(()) -} - -fn f32f32f32(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f32f32f32")?; - let mut i = 0; - while i < NTESTS { - let x0 = f32::from_bits(rng.next_u32()); - let x1 = f32::from_bits(rng.next_u32()); - let x2 = f32::from_bits(rng.next_u32()); - - if x0.is_nan() || x1.is_nan() || x2.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_bytes())?; - f.write_all(&x1.to_bits().to_bytes())?; - f.write_all(&x2.to_bits().to_bytes())?; - } - - Ok(()) -} - -fn f64(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut set = BTreeSet::new(); - - while set.len() < NTESTS { - let f = f64::from_bits(rng.next_u64()); - - if f.is_nan() { - continue; - } - - set.insert(f.to_bits()); - } - - let mut f = File::create("bin/input/f64")?; - for i in set { - f.write_all(&i.to_bytes())?; - } - - Ok(()) -} - -fn f64f64(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f64f64")?; - let mut i = 0; - while i < NTESTS { - let x0 = f64::from_bits(rng.next_u64()); - let x1 = f64::from_bits(rng.next_u64()); - - if x0.is_nan() || x1.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_bytes())?; - f.write_all(&x1.to_bits().to_bytes())?; - } - - Ok(()) -} - -fn f64f64f64(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f64f64f64")?; - let mut i = 0; - while i < NTESTS { - let x0 = f64::from_bits(rng.next_u64()); - let x1 = f64::from_bits(rng.next_u64()); - let x2 = f64::from_bits(rng.next_u64()); - - if x0.is_nan() || x1.is_nan() || x2.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_bytes())?; - f.write_all(&x1.to_bits().to_bytes())?; - f.write_all(&x2.to_bits().to_bytes())?; - } - - Ok(()) -} - -fn f64i16(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f64i16")?; - let mut i = 0; - while i < NTESTS { - let x0 = f64::from_bits(rng.next_u64()); - let x1 = rng.next_u32() as i16; - - if x0.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_bytes())?; - f.write_all(&x1.to_bytes())?; - } - - Ok(()) -} diff --git a/library/compiler-builtins/libm/math/.cargo/config b/library/compiler-builtins/libm/math/.cargo/config deleted file mode 100644 index be79c453ad6..00000000000 --- a/library/compiler-builtins/libm/math/.cargo/config +++ /dev/null @@ -1,11 +0,0 @@ -[target.thumbv7em-none-eabi] -rustflags = [ - "-C", "link-arg=-Wl,-Tlink.x", - "-C", "link-arg=-nostartfiles", - "-C", "link-arg=-mthumb", - "-C", "link-arg=-march=armv7e-m", - "-C", "link-arg=-mfloat-abi=soft", -] - -[build] -target = "thumbv7em-none-eabi" \ No newline at end of file diff --git a/library/compiler-builtins/libm/math/Cargo.toml b/library/compiler-builtins/libm/math/Cargo.toml deleted file mode 100644 index 5bca038a9c3..00000000000 --- a/library/compiler-builtins/libm/math/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "math" -version = "0.0.0" - -[dependencies] -qemu-arm-rt = { git = "https://github.com/japaric/qemu-arm-rt" } - -[workspace] \ No newline at end of file diff --git a/library/compiler-builtins/libm/math/Cross.toml b/library/compiler-builtins/libm/math/Cross.toml deleted file mode 100644 index 471770b528b..00000000000 --- a/library/compiler-builtins/libm/math/Cross.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.thumbv7em-none-eabi] -xargo = false \ No newline at end of file diff --git a/library/compiler-builtins/libm/musl-generator/Cargo.toml b/library/compiler-builtins/libm/musl-generator/Cargo.toml deleted file mode 100644 index 0564f353611..00000000000 --- a/library/compiler-builtins/libm/musl-generator/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "musl-generator" -version = "0.1.0" -authors = ["Jorge Aparicio "] - -[dependencies] -lazy_static = "1.0.2" -shared = { path = "../shared" } -libm = { path = ".." } diff --git a/library/compiler-builtins/libm/musl-generator/src/macros.rs b/library/compiler-builtins/libm/musl-generator/src/macros.rs deleted file mode 100644 index 16ba99d640c..00000000000 --- a/library/compiler-builtins/libm/musl-generator/src/macros.rs +++ /dev/null @@ -1,191 +0,0 @@ -macro_rules! f32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f32) -> f32 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for x in shared::F32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f32) -> f32; - } - - $fun(*x) - }; - - $fun.write_all(&y.to_bits().to_bytes())?; - )+ - } - }}; -} - -macro_rules! f32f32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f32, f32) -> f32 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1) in shared::F32F32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f32, _: f32) -> f32; - } - - $fun(*x0, *x1) - }; - - $fun.write_all(&y.to_bits().to_bytes())?; - )+ - } - }}; -} - -macro_rules! f32f32f32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f32, f32, f32) -> f32 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1, x2) in shared::F32F32F32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f32, _: f32, _: f32) -> f32; - } - - $fun(*x0, *x1, *x2) - }; - - $fun.write_all(&y.to_bits().to_bytes())?; - )+ - } - }}; -} - -macro_rules! f32i32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f32, i32) -> f32 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1) in shared::F32I32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f32, _: i32) -> f32; - } - - $fun(*x0, *x1 as i32) - }; - - $fun.write_all(&y.to_bits().to_bytes())?; - )+ - } - }}; -} - -macro_rules! f64 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f64) -> f64 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for x in shared::F64.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f64) -> f64; - } - - $fun(*x) - }; - - $fun.write_all(&y.to_bits().to_bytes())?; - )+ - } - }}; -} - -macro_rules! f64f64 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f64, f64) -> f64 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1) in shared::F64F64.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f64, _: f64) -> f64; - } - - $fun(*x0, *x1) - }; - - $fun.write_all(&y.to_bits().to_bytes())?; - )+ - } - }}; -} - -macro_rules! f64f64f64 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f64, f64, f64) -> f64 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1, x2) in shared::F64F64F64.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f64, _: f64, _: f64) -> f64; - } - - $fun(*x0, *x1, *x2) - }; - - $fun.write_all(&y.to_bits().to_bytes())?; - )+ - } - }}; -} - -macro_rules! f64i32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f64, i32) -> f64 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1) in shared::F64I32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f64, _: i32) -> f64; - } - - $fun(*x0, *x1 as i32) - }; - - $fun.write_all(&y.to_bits().to_bytes())?; - )+ - } - }}; -} diff --git a/library/compiler-builtins/libm/musl-generator/src/main.rs b/library/compiler-builtins/libm/musl-generator/src/main.rs deleted file mode 100644 index 6e57e856dc6..00000000000 --- a/library/compiler-builtins/libm/musl-generator/src/main.rs +++ /dev/null @@ -1,97 +0,0 @@ -extern crate libm; -extern crate shared; - -use std::error::Error; -use std::fs::File; -use std::io::Write; - -#[macro_use] -mod macros; - -fn main() -> Result<(), Box> { - f32! { - acosf, - asinf, - atanf, - cbrtf, - ceilf, - cosf, - coshf, - exp2f, - expf, - expm1f, - fabsf, - floorf, - log10f, - log1pf, - log2f, - logf, - roundf, - sinf, - sinhf, - sqrtf, - tanf, - tanhf, - truncf, - } - - f32f32! { - atan2f, - fdimf, - fmodf, - hypotf, - powf, - } - - f32i32! { - scalbnf, - } - - f32f32f32! { - fmaf, - } - - f64! { - acos, - asin, - atan, - cbrt, - ceil, - cos, - cosh, - exp, - exp2, - expm1, - fabs, - floor, - log, - log10, - log1p, - log2, - round, - sin, - sinh, - sqrt, - tan, - tanh, - trunc, - } - - f64f64! { - atan2, - fdim, - fmod, - hypot, - pow, - } - - f64i32! { - scalbn, - } - - f64f64f64! { - fma, - } - - Ok(()) -} diff --git a/library/compiler-builtins/libm/newlib-generator/Cargo.toml b/library/compiler-builtins/libm/newlib-generator/Cargo.toml deleted file mode 100644 index 5766cb4b7a0..00000000000 --- a/library/compiler-builtins/libm/newlib-generator/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "newlib-generator" -version = "0.1.0" -authors = ["Jorge Aparicio "] - -[dependencies] -shared = { path = "../shared" } diff --git a/library/compiler-builtins/libm/newlib-generator/src/macros.rs b/library/compiler-builtins/libm/newlib-generator/src/macros.rs deleted file mode 100644 index 84315a777bd..00000000000 --- a/library/compiler-builtins/libm/newlib-generator/src/macros.rs +++ /dev/null @@ -1,245 +0,0 @@ -macro_rules! f32 { - ($($fun:ident,)+) => { - $( - let fun = stringify!($fun); - - fs::create_dir_all("math/src")?; - - let main = format!(" -#![no_main] -#![no_std] - -#[macro_use] -extern crate qemu_arm_rt as rt; - -use core::u32; - -use rt::{{io, process}}; - -entry!(main); - -fn main() {{ - run().unwrap_or_else(|e| {{ - eprintln!(\"error: {{}}\", e); - process::exit(1); - }}) -}} - -fn run() -> Result<(), usize> {{ - #[link(name = \"m\")] - extern \"C\" {{ - fn {0}(_: f32) -> f32; - }} - - let mut buf = [0; 4]; - while let Ok(()) = io::Stdin.read_exact(&mut buf) {{ - let x = f32::from_bits(u32::from_bytes(buf)); - let y = unsafe {{ {0}(x) }}; - - io::Stdout.write_all(&y.to_bits().to_bytes())?; - }} - - Ok(()) -}} - -#[no_mangle] -pub fn __errno() -> *mut i32 {{ - static mut ERRNO: i32 = 0; - unsafe {{ &mut ERRNO }} -}} -", fun); - - File::create("math/src/main.rs")?.write_all(main.as_bytes())?; - - assert!( - Command::new("cross") - .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) - .current_dir("math") - .status()? - .success() - ); - - let mut qemu = Command::new("qemu-arm") - .arg("math/target/thumbv7em-none-eabi/release/math") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn()?; - - qemu.stdin.as_mut().take().unwrap().write_all(F32)?; - - let output = qemu.wait_with_output()?; - - File::create(concat!("bin/output/newlib.", stringify!($fun)))? - .write_all(&output.stdout)?; - )+ - } -} - -macro_rules! f32f32 { - ($($fun:ident,)+) => { - $( - let fun = stringify!($fun); - - fs::create_dir_all("math/src")?; - - let main = format!(" -#![no_main] -#![no_std] - -#[macro_use] -extern crate qemu_arm_rt as rt; - -use core::u32; - -use rt::{{io, process}}; - -entry!(main); - -fn main() {{ - run().unwrap_or_else(|e| {{ - eprintln!(\"error: {{}}\", e); - process::exit(1); - }}) -}} - -fn run() -> Result<(), usize> {{ - #[link(name = \"m\")] - extern \"C\" {{ - fn {0}(_: f32, _: f32) -> f32; - }} - - let mut chunk = [0; 8]; - while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{ - let mut buf = [0; 4]; - buf.copy_from_slice(&chunk[..4]); - let x0 = f32::from_bits(u32::from_bytes(buf)); - - buf.copy_from_slice(&chunk[4..]); - let x1 = f32::from_bits(u32::from_bytes(buf)); - - let y = unsafe {{ {0}(x0, x1) }}; - - io::Stdout.write_all(&y.to_bits().to_bytes())?; - }} - - Ok(()) -}} - -#[no_mangle] -pub fn __errno() -> *mut i32 {{ - static mut ERRNO: i32 = 0; - unsafe {{ &mut ERRNO }} -}} -", fun); - - File::create("math/src/main.rs")?.write_all(main.as_bytes())?; - - assert!( - Command::new("cross") - .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) - .current_dir("math") - .status()? - .success() - ); - - let mut qemu = Command::new("qemu-arm") - .arg("math/target/thumbv7em-none-eabi/release/math") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn()?; - - qemu.stdin.as_mut().take().unwrap().write_all(F32)?; - - let output = qemu.wait_with_output()?; - - File::create(concat!("bin/output/newlib.", stringify!($fun)))? - .write_all(&output.stdout)?; - )+ - } -} - -macro_rules! f32f32f32 { - ($($fun:ident,)+) => { - $( - let fun = stringify!($fun); - - fs::create_dir_all("math/src")?; - - let main = format!(" -#![no_main] -#![no_std] - -#[macro_use] -extern crate qemu_arm_rt as rt; - -use core::u32; - -use rt::{{io, process}}; - -entry!(main); - -fn main() {{ - run().unwrap_or_else(|e| {{ - eprintln!(\"error: {{}}\", e); - process::exit(1); - }}) -}} - -fn run() -> Result<(), usize> {{ - #[link(name = \"m\")] - extern \"C\" {{ - fn {0}(_: f32, _: f32, _: f32) -> f32; - }} - - let mut chunk = [0; 12]; - while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{ - let mut buf = [0; 4]; - buf.copy_from_slice(&chunk[..4]); - let x0 = f32::from_bits(u32::from_bytes(buf)); - - buf.copy_from_slice(&chunk[4..8]); - let x1 = f32::from_bits(u32::from_bytes(buf)); - - buf.copy_from_slice(&chunk[8..]); - let x2 = f32::from_bits(u32::from_bytes(buf)); - - let y = unsafe {{ {0}(x0, x1, x2) }}; - - io::Stdout.write_all(&y.to_bits().to_bytes())?; - }} - - Ok(()) -}} - -#[no_mangle] -pub fn __errno() -> *mut i32 {{ - static mut ERRNO: i32 = 0; - unsafe {{ &mut ERRNO }} -}} -", fun); - - File::create("math/src/main.rs")?.write_all(main.as_bytes())?; - - assert!( - Command::new("cross") - .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) - .current_dir("math") - .status()? - .success() - ); - - let mut qemu = Command::new("qemu-arm") - .arg("math/target/thumbv7em-none-eabi/release/math") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn()?; - - qemu.stdin.as_mut().take().unwrap().write_all(F32)?; - - let output = qemu.wait_with_output()?; - - File::create(concat!("bin/output/newlib.", stringify!($fun)))? - .write_all(&output.stdout)?; - )+ - } -} diff --git a/library/compiler-builtins/libm/newlib-generator/src/main.rs b/library/compiler-builtins/libm/newlib-generator/src/main.rs deleted file mode 100644 index 52a97cabbfd..00000000000 --- a/library/compiler-builtins/libm/newlib-generator/src/main.rs +++ /dev/null @@ -1,32 +0,0 @@ -extern crate shared; - -use std::error::Error; -use std::fs::{self, File}; -use std::io::Write; -use std::process::{Command, Stdio}; - -#[macro_use] -mod macros; - -fn main() -> Result<(), Box> { - const F32: &[u8] = include_bytes!("../../bin/input/f32"); - - f32! { - asinf, - cbrtf, - cosf, - exp2f, - sinf, - tanf, - } - - f32f32! { - hypotf, - } - - f32f32f32! { - fmaf, - } - - Ok(()) -} diff --git a/library/compiler-builtins/libm/shared/Cargo.toml b/library/compiler-builtins/libm/shared/Cargo.toml deleted file mode 100644 index d7782378101..00000000000 --- a/library/compiler-builtins/libm/shared/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "shared" -version = "0.1.0" -authors = ["Jorge Aparicio "] - -[dependencies] -lazy_static = "1.0.2" diff --git a/library/compiler-builtins/libm/shared/src/lib.rs b/library/compiler-builtins/libm/shared/src/lib.rs deleted file mode 100644 index 84676f94f74..00000000000 --- a/library/compiler-builtins/libm/shared/src/lib.rs +++ /dev/null @@ -1,471 +0,0 @@ -#![feature(exact_chunks)] - -#[macro_use] -extern crate lazy_static; - -lazy_static! { - pub static ref F32: Vec = { - let bytes = include_bytes!("../../bin/input/f32"); - - bytes - .exact_chunks(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_bytes(buf))) - }) - .collect() - }; - pub static ref F32F32: Vec<(f32, f32)> = { - let bytes = include_bytes!("../../bin/input/f32f32"); - - bytes - .exact_chunks(8) - .map(|chunk| { - let mut x0 = [0; 4]; - let mut x1 = [0; 4]; - x0.copy_from_slice(&chunk[..4]); - x1.copy_from_slice(&chunk[4..]); - - ( - f32::from_bits(u32::from_le(u32::from_bytes(x0))), - f32::from_bits(u32::from_le(u32::from_bytes(x1))), - ) - }) - .collect() - }; - pub static ref F32F32F32: Vec<(f32, f32, f32)> = { - let bytes = include_bytes!("../../bin/input/f32f32f32"); - - bytes - .exact_chunks(12) - .map(|chunk| { - let mut x0 = [0; 4]; - let mut x1 = [0; 4]; - let mut x2 = [0; 4]; - x0.copy_from_slice(&chunk[..4]); - x1.copy_from_slice(&chunk[4..8]); - x2.copy_from_slice(&chunk[8..]); - - ( - f32::from_bits(u32::from_le(u32::from_bytes(x0))), - f32::from_bits(u32::from_le(u32::from_bytes(x1))), - f32::from_bits(u32::from_le(u32::from_bytes(x2))), - ) - }) - .collect() - }; - pub static ref F32I32: Vec<(f32, i32)> = { - let bytes = include_bytes!("../../bin/input/f32i16"); - - bytes - .exact_chunks(6) - .map(|chunk| { - let mut x0 = [0; 4]; - let mut x1 = [0; 2]; - x0.copy_from_slice(&chunk[..4]); - x1.copy_from_slice(&chunk[4..]); - - ( - f32::from_bits(u32::from_le(u32::from_bytes(x0))), - i16::from_le(i16::from_bytes(x1)) as i32, - ) - }) - .collect() - }; - pub static ref F64: Vec = { - let bytes = include_bytes!("../../bin/input/f64"); - - bytes - .exact_chunks(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_bytes(buf))) - }) - .collect() - }; - pub static ref F64F64: Vec<(f64, f64)> = { - let bytes = include_bytes!("../../bin/input/f64f64"); - - bytes - .exact_chunks(16) - .map(|chunk| { - let mut x0 = [0; 8]; - let mut x1 = [0; 8]; - x0.copy_from_slice(&chunk[..8]); - x1.copy_from_slice(&chunk[8..]); - - ( - f64::from_bits(u64::from_le(u64::from_bytes(x0))), - f64::from_bits(u64::from_le(u64::from_bytes(x1))), - ) - }) - .collect() - }; - pub static ref F64F64F64: Vec<(f64, f64, f64)> = { - let bytes = include_bytes!("../../bin/input/f64f64f64"); - - bytes - .exact_chunks(24) - .map(|chunk| { - let mut x0 = [0; 8]; - let mut x1 = [0; 8]; - let mut x2 = [0; 8]; - x0.copy_from_slice(&chunk[..8]); - x1.copy_from_slice(&chunk[8..16]); - x2.copy_from_slice(&chunk[16..]); - - ( - f64::from_bits(u64::from_le(u64::from_bytes(x0))), - f64::from_bits(u64::from_le(u64::from_bytes(x1))), - f64::from_bits(u64::from_le(u64::from_bytes(x2))), - ) - }) - .collect() - }; - pub static ref F64I32: Vec<(f64, i32)> = { - let bytes = include_bytes!("../../bin/input/f64i16"); - - bytes - .exact_chunks(10) - .map(|chunk| { - let mut x0 = [0; 8]; - let mut x1 = [0; 2]; - x0.copy_from_slice(&chunk[..8]); - x1.copy_from_slice(&chunk[8..]); - - ( - f64::from_bits(u64::from_le(u64::from_bytes(x0))), - i16::from_le(i16::from_bytes(x1)) as i32, - ) - }) - .collect() - }; -} - -#[macro_export] -macro_rules! f32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_bytes(buf))) - }) - .collect::>(); - - for (input, expected) in $crate::F32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) { - if let Err(error) = libm::_eqf(output, *expected) { - panic!( - "INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - input.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}", - input.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f32f32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1), expected) in $crate::F32F32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { - if let Err(error) = libm::_eqf(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f32f32f32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1, i2), expected) in $crate::F32F32F32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) { - if let Err(error) = libm::_eqf(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1.to_bits(), - i2.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f32i32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1), expected) in $crate::F32I32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { - if let Err(error) = libm::_eqf(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1, - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1, - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f64 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_bytes(buf))) - }) - .collect::>(); - - for (input, expected) in shared::F64.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) { - if let Err(error) = libm::_eq(output, *expected) { - panic!( - "INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - input.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}", - input.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f64f64 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1), expected) in shared::F64F64.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { - if let Err(error) = libm::_eq(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f64f64f64 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1, i2), expected) in shared::F64F64F64.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) { - if let Err(error) = libm::_eq(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1.to_bits(), - i2.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f64i32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1), expected) in shared::F64I32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { - if let Err(error) = libm::_eq(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1, - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1, - expected.to_bits() - ); - } - } - } - )+ - } -} diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index 469601caba4..b12ed531ae2 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -73,3 +73,17 @@ pub fn acosf(x: f32) -> f32 { w = r(z) * s + c; 2. * (df + w) } + +#[cfg(test)] +mod tests { + #[test] + fn acosf() { + extern { + fn acosf(x: f32) -> f32; + } + unsafe { + crate::_eqf(super::acosf(1.0), acosf(1.0)).unwrap(); + } + } + // shared::f32!("musl", acosf); +} -- cgit 1.4.1-3-g733a5 From 8560077059df4b5ecfebead0fb3667253b0592c2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 08:12:23 -0700 Subject: Remove newlib generator It's broken and we can try to add it back later if necessary --- library/compiler-builtins/libm/Cargo.toml | 1 - .../libm/crates/newlib-generator/Cargo.toml | 7 - .../libm/crates/newlib-generator/src/macros.rs | 245 --------------------- .../libm/crates/newlib-generator/src/main.rs | 32 --- 4 files changed, 285 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/newlib-generator/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/newlib-generator/src/macros.rs delete mode 100644 library/compiler-builtins/libm/crates/newlib-generator/src/main.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index b4f07eeeed2..c2ac902d991 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -20,7 +20,6 @@ members = [ "crates/compiler-builtins-smoke-test", "crates/input-generator", "crates/musl-generator", - "crates/newlib-generator", "crates/shared", ] diff --git a/library/compiler-builtins/libm/crates/newlib-generator/Cargo.toml b/library/compiler-builtins/libm/crates/newlib-generator/Cargo.toml deleted file mode 100644 index 5766cb4b7a0..00000000000 --- a/library/compiler-builtins/libm/crates/newlib-generator/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "newlib-generator" -version = "0.1.0" -authors = ["Jorge Aparicio "] - -[dependencies] -shared = { path = "../shared" } diff --git a/library/compiler-builtins/libm/crates/newlib-generator/src/macros.rs b/library/compiler-builtins/libm/crates/newlib-generator/src/macros.rs deleted file mode 100644 index 84315a777bd..00000000000 --- a/library/compiler-builtins/libm/crates/newlib-generator/src/macros.rs +++ /dev/null @@ -1,245 +0,0 @@ -macro_rules! f32 { - ($($fun:ident,)+) => { - $( - let fun = stringify!($fun); - - fs::create_dir_all("math/src")?; - - let main = format!(" -#![no_main] -#![no_std] - -#[macro_use] -extern crate qemu_arm_rt as rt; - -use core::u32; - -use rt::{{io, process}}; - -entry!(main); - -fn main() {{ - run().unwrap_or_else(|e| {{ - eprintln!(\"error: {{}}\", e); - process::exit(1); - }}) -}} - -fn run() -> Result<(), usize> {{ - #[link(name = \"m\")] - extern \"C\" {{ - fn {0}(_: f32) -> f32; - }} - - let mut buf = [0; 4]; - while let Ok(()) = io::Stdin.read_exact(&mut buf) {{ - let x = f32::from_bits(u32::from_bytes(buf)); - let y = unsafe {{ {0}(x) }}; - - io::Stdout.write_all(&y.to_bits().to_bytes())?; - }} - - Ok(()) -}} - -#[no_mangle] -pub fn __errno() -> *mut i32 {{ - static mut ERRNO: i32 = 0; - unsafe {{ &mut ERRNO }} -}} -", fun); - - File::create("math/src/main.rs")?.write_all(main.as_bytes())?; - - assert!( - Command::new("cross") - .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) - .current_dir("math") - .status()? - .success() - ); - - let mut qemu = Command::new("qemu-arm") - .arg("math/target/thumbv7em-none-eabi/release/math") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn()?; - - qemu.stdin.as_mut().take().unwrap().write_all(F32)?; - - let output = qemu.wait_with_output()?; - - File::create(concat!("bin/output/newlib.", stringify!($fun)))? - .write_all(&output.stdout)?; - )+ - } -} - -macro_rules! f32f32 { - ($($fun:ident,)+) => { - $( - let fun = stringify!($fun); - - fs::create_dir_all("math/src")?; - - let main = format!(" -#![no_main] -#![no_std] - -#[macro_use] -extern crate qemu_arm_rt as rt; - -use core::u32; - -use rt::{{io, process}}; - -entry!(main); - -fn main() {{ - run().unwrap_or_else(|e| {{ - eprintln!(\"error: {{}}\", e); - process::exit(1); - }}) -}} - -fn run() -> Result<(), usize> {{ - #[link(name = \"m\")] - extern \"C\" {{ - fn {0}(_: f32, _: f32) -> f32; - }} - - let mut chunk = [0; 8]; - while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{ - let mut buf = [0; 4]; - buf.copy_from_slice(&chunk[..4]); - let x0 = f32::from_bits(u32::from_bytes(buf)); - - buf.copy_from_slice(&chunk[4..]); - let x1 = f32::from_bits(u32::from_bytes(buf)); - - let y = unsafe {{ {0}(x0, x1) }}; - - io::Stdout.write_all(&y.to_bits().to_bytes())?; - }} - - Ok(()) -}} - -#[no_mangle] -pub fn __errno() -> *mut i32 {{ - static mut ERRNO: i32 = 0; - unsafe {{ &mut ERRNO }} -}} -", fun); - - File::create("math/src/main.rs")?.write_all(main.as_bytes())?; - - assert!( - Command::new("cross") - .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) - .current_dir("math") - .status()? - .success() - ); - - let mut qemu = Command::new("qemu-arm") - .arg("math/target/thumbv7em-none-eabi/release/math") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn()?; - - qemu.stdin.as_mut().take().unwrap().write_all(F32)?; - - let output = qemu.wait_with_output()?; - - File::create(concat!("bin/output/newlib.", stringify!($fun)))? - .write_all(&output.stdout)?; - )+ - } -} - -macro_rules! f32f32f32 { - ($($fun:ident,)+) => { - $( - let fun = stringify!($fun); - - fs::create_dir_all("math/src")?; - - let main = format!(" -#![no_main] -#![no_std] - -#[macro_use] -extern crate qemu_arm_rt as rt; - -use core::u32; - -use rt::{{io, process}}; - -entry!(main); - -fn main() {{ - run().unwrap_or_else(|e| {{ - eprintln!(\"error: {{}}\", e); - process::exit(1); - }}) -}} - -fn run() -> Result<(), usize> {{ - #[link(name = \"m\")] - extern \"C\" {{ - fn {0}(_: f32, _: f32, _: f32) -> f32; - }} - - let mut chunk = [0; 12]; - while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{ - let mut buf = [0; 4]; - buf.copy_from_slice(&chunk[..4]); - let x0 = f32::from_bits(u32::from_bytes(buf)); - - buf.copy_from_slice(&chunk[4..8]); - let x1 = f32::from_bits(u32::from_bytes(buf)); - - buf.copy_from_slice(&chunk[8..]); - let x2 = f32::from_bits(u32::from_bytes(buf)); - - let y = unsafe {{ {0}(x0, x1, x2) }}; - - io::Stdout.write_all(&y.to_bits().to_bytes())?; - }} - - Ok(()) -}} - -#[no_mangle] -pub fn __errno() -> *mut i32 {{ - static mut ERRNO: i32 = 0; - unsafe {{ &mut ERRNO }} -}} -", fun); - - File::create("math/src/main.rs")?.write_all(main.as_bytes())?; - - assert!( - Command::new("cross") - .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) - .current_dir("math") - .status()? - .success() - ); - - let mut qemu = Command::new("qemu-arm") - .arg("math/target/thumbv7em-none-eabi/release/math") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn()?; - - qemu.stdin.as_mut().take().unwrap().write_all(F32)?; - - let output = qemu.wait_with_output()?; - - File::create(concat!("bin/output/newlib.", stringify!($fun)))? - .write_all(&output.stdout)?; - )+ - } -} diff --git a/library/compiler-builtins/libm/crates/newlib-generator/src/main.rs b/library/compiler-builtins/libm/crates/newlib-generator/src/main.rs deleted file mode 100644 index 52a97cabbfd..00000000000 --- a/library/compiler-builtins/libm/crates/newlib-generator/src/main.rs +++ /dev/null @@ -1,32 +0,0 @@ -extern crate shared; - -use std::error::Error; -use std::fs::{self, File}; -use std::io::Write; -use std::process::{Command, Stdio}; - -#[macro_use] -mod macros; - -fn main() -> Result<(), Box> { - const F32: &[u8] = include_bytes!("../../bin/input/f32"); - - f32! { - asinf, - cbrtf, - cosf, - exp2f, - sinf, - tanf, - } - - f32f32! { - hypotf, - } - - f32f32f32! { - fmaf, - } - - Ok(()) -} -- cgit 1.4.1-3-g733a5 From 7cb4a204a2d6019a14430ad67fd060f59f2d5934 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 10:48:55 -0700 Subject: Rework how testing is done Use a build script to generate musl reference outputs and then ensure that everything gets hooked up to actually run reference tests. --- library/compiler-builtins/libm/Cargo.toml | 9 +- library/compiler-builtins/libm/build.rs | 344 +++++++++++++++ .../libm/crates/input-generator/Cargo.toml | 7 - .../libm/crates/input-generator/src/main.rs | 189 --------- .../libm/crates/musl-generator/Cargo.toml | 9 - .../libm/crates/musl-generator/src/macros.rs | 191 --------- .../libm/crates/musl-generator/src/main.rs | 97 ----- .../libm/crates/shared/Cargo.toml | 7 - .../libm/crates/shared/src/lib.rs | 469 --------------------- library/compiler-builtins/libm/src/lib.rs | 3 + 10 files changed, 351 insertions(+), 974 deletions(-) create mode 100644 library/compiler-builtins/libm/build.rs delete mode 100644 library/compiler-builtins/libm/crates/input-generator/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/input-generator/src/main.rs delete mode 100644 library/compiler-builtins/libm/crates/musl-generator/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/musl-generator/src/macros.rs delete mode 100644 library/compiler-builtins/libm/crates/musl-generator/src/main.rs delete mode 100644 library/compiler-builtins/libm/crates/shared/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/shared/src/lib.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index c2ac902d991..7d9890e3e30 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,20 +8,19 @@ license = "MIT OR Apache-2.0" name = "libm" repository = "https://github.com/japaric/libm" version = "0.1.2" +edition = "2018" [features] # only used to run our test suite checked = [] default = ['stable'] stable = [] +musl-reference-tests = ['rand'] [workspace] members = [ "crates/compiler-builtins-smoke-test", - "crates/input-generator", - "crates/musl-generator", - "crates/shared", ] -[dev-dependencies] -shared = { path = "shared" } +[build-dependencies] +rand = { version = "0.6.5", optional = true } diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs new file mode 100644 index 00000000000..31b1bbea947 --- /dev/null +++ b/library/compiler-builtins/libm/build.rs @@ -0,0 +1,344 @@ +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + #[cfg(feature = "musl-reference-tests")] + musl_reference_tests::generate(); +} + +#[cfg(feature = "musl-reference-tests")] +mod musl_reference_tests { + use rand::seq::SliceRandom; + use rand::Rng; + use std::fs; + use std::process::Command; + + // Number of tests to generate for each function + const NTESTS: usize = 500; + + // These files are all internal functions or otherwise miscellaneous, not + // defining a function we want to test. + const IGNORED_FILES: &[&str] = &[ + "expo2.rs", + "fenv.rs", + "k_cos.rs", + "k_cosf.rs", + "k_expo2.rs", + "k_expo2f.rs", + "k_sin.rs", + "k_sinf.rs", + "k_tan.rs", + "k_tanf.rs", + "mod.rs", + "rem_pio2.rs", + "rem_pio2_large.rs", + "rem_pio2f.rs", + ]; + + struct Function { + name: String, + args: Vec, + ret: Ty, + tests: Vec, + } + + enum Ty { + F32, + F64, + I32, + Bool, + } + + struct Test { + inputs: Vec, + output: i64, + } + + pub fn generate() { + let files = fs::read_dir("src/math") + .unwrap() + .map(|f| f.unwrap().path()) + .collect::>(); + + let mut math = Vec::new(); + for file in files { + if IGNORED_FILES.iter().any(|f| file.ends_with(f)) { + continue; + } + + println!("generating musl reference tests in {:?}", file); + + let contents = fs::read_to_string(file).unwrap(); + let mut functions = contents.lines().filter(|f| f.starts_with("pub fn")); + let function_to_test = functions.next().unwrap(); + if functions.next().is_some() { + panic!("more than one function in"); + } + + math.push(parse(function_to_test)); + } + + // Generate a bunch of random inputs for each function. This will + // attempt to generate a good set of uniform test cases for exercising + // all the various functionality. + generate_random_tests(&mut math, &mut rand::thread_rng()); + + // After we have all our inputs, use the x86_64-unknown-linux-musl + // target to generate the expected output. + generate_test_outputs(&mut math); + + // ... and now that we have both inputs and expected outputs, do a bunch + // of codegen to create the unit tests which we'll actually execute. + generate_unit_tests(&math); + } + + /// A "poor man's" parser for the signature of a function + fn parse(s: &str) -> Function { + let s = eat(s, "pub fn "); + let pos = s.find('(').unwrap(); + let name = &s[..pos]; + let s = &s[pos + 1..]; + let end = s.find(')').unwrap(); + let args = s[..end] + .split(',') + .map(|arg| { + let colon = arg.find(':').unwrap(); + parse_ty(arg[colon + 1..].trim()) + }) + .collect::>(); + let tail = &s[end + 1..]; + let tail = eat(tail, " -> "); + let ret = parse_ty(tail.trim().split(' ').next().unwrap()); + + return Function { + name: name.to_string(), + args, + ret, + tests: Vec::new(), + }; + + fn parse_ty(s: &str) -> Ty { + match s { + "f32" => Ty::F32, + "f64" => Ty::F64, + "i32" => Ty::I32, + "bool" => Ty::Bool, + other => panic!("unknown type `{}`", other), + } + } + + fn eat<'a>(s: &'a str, prefix: &str) -> &'a str { + if s.starts_with(prefix) { + &s[prefix.len()..] + } else { + panic!("{:?} didn't start with {:?}", s, prefix) + } + } + } + + fn generate_random_tests(functions: &mut [Function], rng: &mut R) { + for function in functions { + for _ in 0..NTESTS { + function.tests.push(generate_test(&function.args, rng)); + } + } + + fn generate_test(args: &[Ty], rng: &mut R) -> Test { + let inputs = args.iter().map(|ty| ty.gen_i64(rng)).collect(); + // zero output for now since we'll generate it later + Test { inputs, output: 0 } + } + } + + impl Ty { + fn gen_i64(&self, r: &mut R) -> i64 { + match self { + Ty::F32 => r.gen::().to_bits().into(), + Ty::F64 => r.gen::().to_bits() as i64, + Ty::I32 => { + if r.gen_range(0, 10) < 1 { + let i = *[i32::max_value(), 0, i32::min_value()].choose(r).unwrap(); + i.into() + } else { + r.gen::().into() + } + } + Ty::Bool => r.gen::() as i64, + } + } + + fn libc_ty(&self) -> &'static str { + match self { + Ty::F32 => "f32", + Ty::F64 => "f64", + Ty::I32 => "i32", + Ty::Bool => "i32", + } + } + } + + fn generate_test_outputs(functions: &mut [Function]) { + let mut src = String::new(); + let dst = std::env::var("OUT_DIR").unwrap(); + + // Generate a program which will run all tests with all inputs in + // `functions`. This program will write all outputs to stdout (in a + // binary format). + src.push_str("use std::io::Write;"); + src.push_str("fn main() {"); + src.push_str("let mut result = Vec::new();"); + for function in functions.iter_mut() { + src.push_str("unsafe {"); + src.push_str("extern { fn "); + src.push_str(&function.name); + src.push_str("("); + for (i, arg) in function.args.iter().enumerate() { + src.push_str(&format!("arg{}: {},", i, arg.libc_ty())); + } + src.push_str(") -> "); + src.push_str(function.ret.libc_ty()); + src.push_str("; }"); + + src.push_str(&format!("static TESTS: &[[i64; {}]]", function.args.len())); + src.push_str(" = &["); + for test in function.tests.iter() { + src.push_str("["); + for val in test.inputs.iter() { + src.push_str(&val.to_string()); + src.push_str(","); + } + src.push_str("],"); + } + src.push_str("];"); + + src.push_str("for test in TESTS {"); + src.push_str("let output = "); + src.push_str(&function.name); + src.push_str("("); + for (i, arg) in function.args.iter().enumerate() { + src.push_str(&match arg { + Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), + Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), + Ty::I32 => format!("test[{}] as i32", i), + Ty::Bool => format!("test[{}] as i32", i), + }); + src.push_str(","); + } + src.push_str(");"); + src.push_str("let output = "); + src.push_str(match function.ret { + Ty::F32 => "output.to_bits() as i64", + Ty::F64 => "output.to_bits() as i64", + Ty::I32 => "output as i64", + Ty::Bool => "output as i64", + }); + src.push_str(";"); + src.push_str("result.extend_from_slice(&output.to_le_bytes());"); + + src.push_str("}"); + + src.push_str("}"); + } + + src.push_str("std::io::stdout().write_all(&result).unwrap();"); + + src.push_str("}"); + + let path = format!("{}/gen.rs", dst); + fs::write(&path, src).unwrap(); + + // Make it somewhat pretty if something goes wrong + drop(Command::new("rustfmt").arg(&path).status()); + + // Compile and execute this tests for the musl target, assuming we're an + // x86_64 host effectively. + let status = Command::new("rustc") + .current_dir(&dst) + .arg(&path) + .arg("--target=x86_64-unknown-linux-musl") + .status() + .unwrap(); + assert!(status.success()); + let output = Command::new("./gen") + .current_dir(&dst) + .output() + .unwrap(); + assert!(output.status.success()); + assert!(output.stderr.is_empty()); + + // Map all the output bytes back to an `i64` and then shove it all into + // the expected results. + let mut results = + output.stdout.chunks_exact(8) + .map(|buf| { + let mut exact = [0; 8]; + exact.copy_from_slice(buf); + i64::from_le_bytes(exact) + }); + + for test in functions.iter_mut().flat_map(|f| f.tests.iter_mut()) { + test.output = results.next().unwrap(); + } + assert!(results.next().is_none()); + } + + /// Codegens a file which has a ton of `#[test]` annotations for all the + /// tests that we generated above. + fn generate_unit_tests(functions: &[Function]) { + let mut src = String::new(); + let dst = std::env::var("OUT_DIR").unwrap(); + + for function in functions { + src.push_str("#[test]"); + src.push_str("fn "); + src.push_str(&function.name); + src.push_str("_matches_musl() {"); + src.push_str(&format!("static TESTS: &[([i64; {}], i64)]", function.args.len())); + src.push_str(" = &["); + for test in function.tests.iter() { + src.push_str("(["); + for val in test.inputs.iter() { + src.push_str(&val.to_string()); + src.push_str(","); + } + src.push_str("],"); + src.push_str(&test.output.to_string()); + src.push_str("),"); + } + src.push_str("];"); + + src.push_str("for (test, expected) in TESTS {"); + src.push_str("let output = "); + src.push_str(&function.name); + src.push_str("("); + for (i, arg) in function.args.iter().enumerate() { + src.push_str(&match arg { + Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), + Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), + Ty::I32 => format!("test[{}] as i32", i), + Ty::Bool => format!("test[{}] as i32", i), + }); + src.push_str(","); + } + src.push_str(");"); + src.push_str(match function.ret { + Ty::F32 => "if _eqf(output, f32::from_bits(*expected as u32)).is_ok() { continue }", + Ty::F64 => "if _eq(output, f64::from_bits(*expected as u64)).is_ok() { continue }", + Ty::I32 => "if output as i64 == expected { continue }", + Ty::Bool => unreachable!(), + }); + + src.push_str(r#" + panic!("INPUT: {:?} EXPECTED: {:?} ACTUAL {:?}", test, expected, output); + "#); + src.push_str("}"); + + src.push_str("}"); + } + + let path = format!("{}/tests.rs", dst); + fs::write(&path, src).unwrap(); + + // Try to make it somewhat pretty + drop(Command::new("rustfmt").arg(&path).status()); + } +} diff --git a/library/compiler-builtins/libm/crates/input-generator/Cargo.toml b/library/compiler-builtins/libm/crates/input-generator/Cargo.toml deleted file mode 100644 index fef2558a8b0..00000000000 --- a/library/compiler-builtins/libm/crates/input-generator/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "input-generator" -version = "0.1.0" -authors = ["Jorge Aparicio "] - -[dependencies] -rand = "0.5.4" diff --git a/library/compiler-builtins/libm/crates/input-generator/src/main.rs b/library/compiler-builtins/libm/crates/input-generator/src/main.rs deleted file mode 100644 index 0746ea477e8..00000000000 --- a/library/compiler-builtins/libm/crates/input-generator/src/main.rs +++ /dev/null @@ -1,189 +0,0 @@ -extern crate rand; - -use std::collections::BTreeSet; -use std::error::Error; -use std::fs::{self, File}; -use std::io::Write; - -use rand::{RngCore, SeedableRng, XorShiftRng}; - -const NTESTS: usize = 10_000; - -fn main() -> Result<(), Box> { - let mut rng = XorShiftRng::from_rng(&mut rand::thread_rng())?; - - fs::remove_dir_all("bin").ok(); - fs::create_dir_all("bin/input")?; - fs::create_dir_all("bin/output")?; - - f32(&mut rng)?; - f32f32(&mut rng)?; - f32f32f32(&mut rng)?; - f32i16(&mut rng)?; - f64(&mut rng)?; - f64f64(&mut rng)?; - f64f64f64(&mut rng)?; - f64i16(&mut rng)?; - - Ok(()) -} - -fn f32(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut set = BTreeSet::new(); - - while set.len() < NTESTS { - let f = f32::from_bits(rng.next_u32()); - - if f.is_nan() { - continue; - } - - set.insert(f.to_bits()); - } - - let mut f = File::create("bin/input/f32")?; - for i in set { - f.write_all(&i.to_le_bytes())?; - } - - Ok(()) -} - -fn f32f32(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f32f32")?; - let mut i = 0; - while i < NTESTS { - let x0 = f32::from_bits(rng.next_u32()); - let x1 = f32::from_bits(rng.next_u32()); - - if x0.is_nan() || x1.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_le_bytes())?; - f.write_all(&x1.to_bits().to_le_bytes())?; - } - - Ok(()) -} - -fn f32i16(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f32i16")?; - let mut i = 0; - while i < NTESTS { - let x0 = f32::from_bits(rng.next_u32()); - let x1 = rng.next_u32() as i16; - - if x0.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_le_bytes())?; - f.write_all(&x1.to_le_bytes())?; - } - - Ok(()) -} - -fn f32f32f32(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f32f32f32")?; - let mut i = 0; - while i < NTESTS { - let x0 = f32::from_bits(rng.next_u32()); - let x1 = f32::from_bits(rng.next_u32()); - let x2 = f32::from_bits(rng.next_u32()); - - if x0.is_nan() || x1.is_nan() || x2.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_le_bytes())?; - f.write_all(&x1.to_bits().to_le_bytes())?; - f.write_all(&x2.to_bits().to_le_bytes())?; - } - - Ok(()) -} - -fn f64(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut set = BTreeSet::new(); - - while set.len() < NTESTS { - let f = f64::from_bits(rng.next_u64()); - - if f.is_nan() { - continue; - } - - set.insert(f.to_bits()); - } - - let mut f = File::create("bin/input/f64")?; - for i in set { - f.write_all(&i.to_le_bytes())?; - } - - Ok(()) -} - -fn f64f64(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f64f64")?; - let mut i = 0; - while i < NTESTS { - let x0 = f64::from_bits(rng.next_u64()); - let x1 = f64::from_bits(rng.next_u64()); - - if x0.is_nan() || x1.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_le_bytes())?; - f.write_all(&x1.to_bits().to_le_bytes())?; - } - - Ok(()) -} - -fn f64f64f64(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f64f64f64")?; - let mut i = 0; - while i < NTESTS { - let x0 = f64::from_bits(rng.next_u64()); - let x1 = f64::from_bits(rng.next_u64()); - let x2 = f64::from_bits(rng.next_u64()); - - if x0.is_nan() || x1.is_nan() || x2.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_le_bytes())?; - f.write_all(&x1.to_bits().to_le_bytes())?; - f.write_all(&x2.to_bits().to_le_bytes())?; - } - - Ok(()) -} - -fn f64i16(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f64i16")?; - let mut i = 0; - while i < NTESTS { - let x0 = f64::from_bits(rng.next_u64()); - let x1 = rng.next_u32() as i16; - - if x0.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_le_bytes())?; - f.write_all(&x1.to_le_bytes())?; - } - - Ok(()) -} diff --git a/library/compiler-builtins/libm/crates/musl-generator/Cargo.toml b/library/compiler-builtins/libm/crates/musl-generator/Cargo.toml deleted file mode 100644 index 0564f353611..00000000000 --- a/library/compiler-builtins/libm/crates/musl-generator/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "musl-generator" -version = "0.1.0" -authors = ["Jorge Aparicio "] - -[dependencies] -lazy_static = "1.0.2" -shared = { path = "../shared" } -libm = { path = ".." } diff --git a/library/compiler-builtins/libm/crates/musl-generator/src/macros.rs b/library/compiler-builtins/libm/crates/musl-generator/src/macros.rs deleted file mode 100644 index e47c0ab6f96..00000000000 --- a/library/compiler-builtins/libm/crates/musl-generator/src/macros.rs +++ /dev/null @@ -1,191 +0,0 @@ -macro_rules! f32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f32) -> f32 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for x in shared::F32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f32) -> f32; - } - - $fun(*x) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} - -macro_rules! f32f32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f32, f32) -> f32 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1) in shared::F32F32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f32, _: f32) -> f32; - } - - $fun(*x0, *x1) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} - -macro_rules! f32f32f32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f32, f32, f32) -> f32 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1, x2) in shared::F32F32F32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f32, _: f32, _: f32) -> f32; - } - - $fun(*x0, *x1, *x2) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} - -macro_rules! f32i32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f32, i32) -> f32 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1) in shared::F32I32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f32, _: i32) -> f32; - } - - $fun(*x0, *x1 as i32) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} - -macro_rules! f64 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f64) -> f64 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for x in shared::F64.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f64) -> f64; - } - - $fun(*x) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} - -macro_rules! f64f64 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f64, f64) -> f64 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1) in shared::F64F64.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f64, _: f64) -> f64; - } - - $fun(*x0, *x1) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} - -macro_rules! f64f64f64 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f64, f64, f64) -> f64 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1, x2) in shared::F64F64F64.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f64, _: f64, _: f64) -> f64; - } - - $fun(*x0, *x1, *x2) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} - -macro_rules! f64i32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f64, i32) -> f64 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1) in shared::F64I32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f64, _: i32) -> f64; - } - - $fun(*x0, *x1 as i32) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} diff --git a/library/compiler-builtins/libm/crates/musl-generator/src/main.rs b/library/compiler-builtins/libm/crates/musl-generator/src/main.rs deleted file mode 100644 index 6e57e856dc6..00000000000 --- a/library/compiler-builtins/libm/crates/musl-generator/src/main.rs +++ /dev/null @@ -1,97 +0,0 @@ -extern crate libm; -extern crate shared; - -use std::error::Error; -use std::fs::File; -use std::io::Write; - -#[macro_use] -mod macros; - -fn main() -> Result<(), Box> { - f32! { - acosf, - asinf, - atanf, - cbrtf, - ceilf, - cosf, - coshf, - exp2f, - expf, - expm1f, - fabsf, - floorf, - log10f, - log1pf, - log2f, - logf, - roundf, - sinf, - sinhf, - sqrtf, - tanf, - tanhf, - truncf, - } - - f32f32! { - atan2f, - fdimf, - fmodf, - hypotf, - powf, - } - - f32i32! { - scalbnf, - } - - f32f32f32! { - fmaf, - } - - f64! { - acos, - asin, - atan, - cbrt, - ceil, - cos, - cosh, - exp, - exp2, - expm1, - fabs, - floor, - log, - log10, - log1p, - log2, - round, - sin, - sinh, - sqrt, - tan, - tanh, - trunc, - } - - f64f64! { - atan2, - fdim, - fmod, - hypot, - pow, - } - - f64i32! { - scalbn, - } - - f64f64f64! { - fma, - } - - Ok(()) -} diff --git a/library/compiler-builtins/libm/crates/shared/Cargo.toml b/library/compiler-builtins/libm/crates/shared/Cargo.toml deleted file mode 100644 index d7782378101..00000000000 --- a/library/compiler-builtins/libm/crates/shared/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "shared" -version = "0.1.0" -authors = ["Jorge Aparicio "] - -[dependencies] -lazy_static = "1.0.2" diff --git a/library/compiler-builtins/libm/crates/shared/src/lib.rs b/library/compiler-builtins/libm/crates/shared/src/lib.rs deleted file mode 100644 index 17c20a332e5..00000000000 --- a/library/compiler-builtins/libm/crates/shared/src/lib.rs +++ /dev/null @@ -1,469 +0,0 @@ -#[macro_use] -extern crate lazy_static; - -lazy_static! { - pub static ref F32: Vec = { - let bytes = include_bytes!("../../bin/input/f32"); - - bytes - .chunks_exact(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) - }) - .collect() - }; - pub static ref F32F32: Vec<(f32, f32)> = { - let bytes = include_bytes!("../../bin/input/f32f32"); - - bytes - .chunks_exact(8) - .map(|chunk| { - let mut x0 = [0; 4]; - let mut x1 = [0; 4]; - x0.copy_from_slice(&chunk[..4]); - x1.copy_from_slice(&chunk[4..]); - - ( - f32::from_bits(u32::from_le(u32::from_le_bytes(x0))), - f32::from_bits(u32::from_le(u32::from_le_bytes(x1))), - ) - }) - .collect() - }; - pub static ref F32F32F32: Vec<(f32, f32, f32)> = { - let bytes = include_bytes!("../../bin/input/f32f32f32"); - - bytes - .chunks_exact(12) - .map(|chunk| { - let mut x0 = [0; 4]; - let mut x1 = [0; 4]; - let mut x2 = [0; 4]; - x0.copy_from_slice(&chunk[..4]); - x1.copy_from_slice(&chunk[4..8]); - x2.copy_from_slice(&chunk[8..]); - - ( - f32::from_bits(u32::from_le(u32::from_le_bytes(x0))), - f32::from_bits(u32::from_le(u32::from_le_bytes(x1))), - f32::from_bits(u32::from_le(u32::from_le_bytes(x2))), - ) - }) - .collect() - }; - pub static ref F32I32: Vec<(f32, i32)> = { - let bytes = include_bytes!("../../bin/input/f32i16"); - - bytes - .chunks_exact(6) - .map(|chunk| { - let mut x0 = [0; 4]; - let mut x1 = [0; 2]; - x0.copy_from_slice(&chunk[..4]); - x1.copy_from_slice(&chunk[4..]); - - ( - f32::from_bits(u32::from_le(u32::from_le_bytes(x0))), - i16::from_le(i16::from_le_bytes(x1)) as i32, - ) - }) - .collect() - }; - pub static ref F64: Vec = { - let bytes = include_bytes!("../../bin/input/f64"); - - bytes - .chunks_exact(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) - }) - .collect() - }; - pub static ref F64F64: Vec<(f64, f64)> = { - let bytes = include_bytes!("../../bin/input/f64f64"); - - bytes - .chunks_exact(16) - .map(|chunk| { - let mut x0 = [0; 8]; - let mut x1 = [0; 8]; - x0.copy_from_slice(&chunk[..8]); - x1.copy_from_slice(&chunk[8..]); - - ( - f64::from_bits(u64::from_le(u64::from_le_bytes(x0))), - f64::from_bits(u64::from_le(u64::from_le_bytes(x1))), - ) - }) - .collect() - }; - pub static ref F64F64F64: Vec<(f64, f64, f64)> = { - let bytes = include_bytes!("../../bin/input/f64f64f64"); - - bytes - .chunks_exact(24) - .map(|chunk| { - let mut x0 = [0; 8]; - let mut x1 = [0; 8]; - let mut x2 = [0; 8]; - x0.copy_from_slice(&chunk[..8]); - x1.copy_from_slice(&chunk[8..16]); - x2.copy_from_slice(&chunk[16..]); - - ( - f64::from_bits(u64::from_le(u64::from_le_bytes(x0))), - f64::from_bits(u64::from_le(u64::from_le_bytes(x1))), - f64::from_bits(u64::from_le(u64::from_le_bytes(x2))), - ) - }) - .collect() - }; - pub static ref F64I32: Vec<(f64, i32)> = { - let bytes = include_bytes!("../../bin/input/f64i16"); - - bytes - .chunks_exact(10) - .map(|chunk| { - let mut x0 = [0; 8]; - let mut x1 = [0; 2]; - x0.copy_from_slice(&chunk[..8]); - x1.copy_from_slice(&chunk[8..]); - - ( - f64::from_bits(u64::from_le(u64::from_le_bytes(x0))), - i16::from_le(i16::from_le_bytes(x1)) as i32, - ) - }) - .collect() - }; -} - -#[macro_export] -macro_rules! f32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) - }) - .collect::>(); - - for (input, expected) in $crate::F32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) { - if let Err(error) = libm::_eqf(output, *expected) { - panic!( - "INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - input.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}", - input.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f32f32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1), expected) in $crate::F32F32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { - if let Err(error) = libm::_eqf(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f32f32f32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1, i2), expected) in $crate::F32F32F32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) { - if let Err(error) = libm::_eqf(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1.to_bits(), - i2.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f32i32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1), expected) in $crate::F32I32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { - if let Err(error) = libm::_eqf(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1, - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1, - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f64 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) - }) - .collect::>(); - - for (input, expected) in shared::F64.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) { - if let Err(error) = libm::_eq(output, *expected) { - panic!( - "INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - input.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}", - input.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f64f64 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1), expected) in shared::F64F64.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { - if let Err(error) = libm::_eq(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f64f64f64 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1, i2), expected) in shared::F64F64F64.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) { - if let Err(error) = libm::_eq(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1.to_bits(), - i2.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f64i32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1), expected) in shared::F64I32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { - if let Err(error) = libm::_eq(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1, - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1, - expected.to_bits() - ); - } - } - } - )+ - } -} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 6be45872819..e705dde0f91 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -625,3 +625,6 @@ mod private { impl Sealed for f32 {} impl Sealed for f64 {} } + +#[cfg(test)] +include!(concat!(env!("OUT_DIR"), "/tests.rs")); -- cgit 1.4.1-3-g733a5 From 8d79795d70f7dd30d26720462c39ca0990c8a777 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 11:37:21 -0700 Subject: Overhaul tests * Move everything to azure pipelines * Inline docker configuration in this repo (no `cross`) * Delete `no-panic` example, use `#[no_panic]` instead. --- library/compiler-builtins/libm/.travis.yml | 58 --------- library/compiler-builtins/libm/Cargo.toml | 13 +- library/compiler-builtins/libm/azure-pipelines.yml | 140 +++++---------------- library/compiler-builtins/libm/build.rs | 11 +- .../compiler-builtins/libm/ci/azure-test-all.yml | 39 +----- .../ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 10 ++ .../ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 9 ++ .../docker/arm-unknown-linux-gnueabihf/Dockerfile | 9 ++ .../armv7-unknown-linux-gnueabihf/Dockerfile | 9 ++ .../ci/docker/i686-unknown-linux-gnu/Dockerfile | 4 + .../ci/docker/mips-unknown-linux-gnu/Dockerfile | 12 ++ .../mips64-unknown-linux-gnuabi64/Dockerfile | 15 +++ .../mips64el-unknown-linux-gnuabi64/Dockerfile | 14 +++ .../ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 12 ++ .../ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 12 ++ .../docker/powerpc64-unknown-linux-gnu/Dockerfile | 13 ++ .../powerpc64le-unknown-linux-gnu/Dockerfile | 13 ++ .../ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 4 + library/compiler-builtins/libm/ci/install.sh | 25 ---- library/compiler-builtins/libm/ci/run-docker.sh | 36 ++++++ library/compiler-builtins/libm/ci/run.sh | 12 ++ library/compiler-builtins/libm/ci/script.sh | 37 ------ .../compiler-builtins/libm/examples/no-panic.rs | 115 ----------------- library/compiler-builtins/libm/src/lib.rs | 4 +- library/compiler-builtins/libm/src/math/acos.rs | 1 + library/compiler-builtins/libm/src/math/acosf.rs | 1 + library/compiler-builtins/libm/src/math/asin.rs | 1 + library/compiler-builtins/libm/src/math/asinf.rs | 1 + library/compiler-builtins/libm/src/math/atan.rs | 1 + library/compiler-builtins/libm/src/math/atan2.rs | 1 + library/compiler-builtins/libm/src/math/atan2f.rs | 1 + library/compiler-builtins/libm/src/math/atanf.rs | 1 + library/compiler-builtins/libm/src/math/cbrt.rs | 1 + library/compiler-builtins/libm/src/math/cbrtf.rs | 1 + library/compiler-builtins/libm/src/math/ceil.rs | 1 + library/compiler-builtins/libm/src/math/ceilf.rs | 1 + library/compiler-builtins/libm/src/math/cos.rs | 1 + library/compiler-builtins/libm/src/math/cosf.rs | 1 + library/compiler-builtins/libm/src/math/cosh.rs | 1 + library/compiler-builtins/libm/src/math/coshf.rs | 1 + library/compiler-builtins/libm/src/math/exp.rs | 1 + library/compiler-builtins/libm/src/math/exp2.rs | 1 + library/compiler-builtins/libm/src/math/exp2f.rs | 1 + library/compiler-builtins/libm/src/math/expf.rs | 1 + library/compiler-builtins/libm/src/math/expm1.rs | 1 + library/compiler-builtins/libm/src/math/expm1f.rs | 1 + library/compiler-builtins/libm/src/math/expo2.rs | 1 + library/compiler-builtins/libm/src/math/fabs.rs | 1 + library/compiler-builtins/libm/src/math/fabsf.rs | 1 + library/compiler-builtins/libm/src/math/fdim.rs | 1 + library/compiler-builtins/libm/src/math/fdimf.rs | 1 + library/compiler-builtins/libm/src/math/floor.rs | 1 + library/compiler-builtins/libm/src/math/floorf.rs | 1 + library/compiler-builtins/libm/src/math/fma.rs | 1 + library/compiler-builtins/libm/src/math/fmaf.rs | 1 + library/compiler-builtins/libm/src/math/fmod.rs | 1 + library/compiler-builtins/libm/src/math/fmodf.rs | 1 + library/compiler-builtins/libm/src/math/hypot.rs | 1 + library/compiler-builtins/libm/src/math/hypotf.rs | 1 + library/compiler-builtins/libm/src/math/k_cos.rs | 1 + library/compiler-builtins/libm/src/math/k_cosf.rs | 1 + library/compiler-builtins/libm/src/math/k_expo2.rs | 1 + .../compiler-builtins/libm/src/math/k_expo2f.rs | 1 + library/compiler-builtins/libm/src/math/k_sin.rs | 1 + library/compiler-builtins/libm/src/math/k_sinf.rs | 1 + library/compiler-builtins/libm/src/math/k_tan.rs | 1 + library/compiler-builtins/libm/src/math/k_tanf.rs | 1 + library/compiler-builtins/libm/src/math/log.rs | 1 + library/compiler-builtins/libm/src/math/log10.rs | 1 + library/compiler-builtins/libm/src/math/log10f.rs | 1 + library/compiler-builtins/libm/src/math/log1p.rs | 1 + library/compiler-builtins/libm/src/math/log1pf.rs | 1 + library/compiler-builtins/libm/src/math/log2.rs | 1 + library/compiler-builtins/libm/src/math/log2f.rs | 1 + library/compiler-builtins/libm/src/math/logf.rs | 1 + library/compiler-builtins/libm/src/math/pow.rs | 1 + library/compiler-builtins/libm/src/math/powf.rs | 1 + .../compiler-builtins/libm/src/math/rem_pio2.rs | 1 + .../libm/src/math/rem_pio2_large.rs | 1 + .../compiler-builtins/libm/src/math/rem_pio2f.rs | 1 + library/compiler-builtins/libm/src/math/round.rs | 1 + library/compiler-builtins/libm/src/math/roundf.rs | 1 + library/compiler-builtins/libm/src/math/scalbn.rs | 1 + library/compiler-builtins/libm/src/math/scalbnf.rs | 1 + library/compiler-builtins/libm/src/math/sin.rs | 1 + library/compiler-builtins/libm/src/math/sinf.rs | 1 + library/compiler-builtins/libm/src/math/sinh.rs | 1 + library/compiler-builtins/libm/src/math/sinhf.rs | 1 + library/compiler-builtins/libm/src/math/sqrt.rs | 1 + library/compiler-builtins/libm/src/math/sqrtf.rs | 1 + library/compiler-builtins/libm/src/math/tan.rs | 1 + library/compiler-builtins/libm/src/math/tanf.rs | 1 + library/compiler-builtins/libm/src/math/tanh.rs | 1 + library/compiler-builtins/libm/src/math/tanhf.rs | 1 + library/compiler-builtins/libm/src/math/trunc.rs | 1 + library/compiler-builtins/libm/src/math/truncf.rs | 1 + 96 files changed, 313 insertions(+), 385 deletions(-) delete mode 100644 library/compiler-builtins/libm/.travis.yml create mode 100644 library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/install.sh create mode 100755 library/compiler-builtins/libm/ci/run-docker.sh create mode 100755 library/compiler-builtins/libm/ci/run.sh delete mode 100644 library/compiler-builtins/libm/ci/script.sh delete mode 100644 library/compiler-builtins/libm/examples/no-panic.rs diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml deleted file mode 100644 index 75831617819..00000000000 --- a/library/compiler-builtins/libm/.travis.yml +++ /dev/null @@ -1,58 +0,0 @@ -language: rust -services: docker -sudo: required - -matrix: - include: - - env: TARGET=aarch64-unknown-linux-gnu - rust: nightly - - env: TARGET=armv7-unknown-linux-gnueabihf - rust: nightly - - env: TARGET=i686-unknown-linux-gnu - rust: nightly - - env: TARGET=mips-unknown-linux-gnu - rust: nightly - - env: TARGET=mips64-unknown-linux-gnuabi64 - rust: nightly - - env: TARGET=mips64el-unknown-linux-gnuabi64 - rust: nightly - - env: TARGET=mipsel-unknown-linux-gnu - rust: nightly - - env: TARGET=powerpc-unknown-linux-gnu - rust: nightly - - env: TARGET=powerpc64-unknown-linux-gnu - rust: nightly - - env: TARGET=powerpc64le-unknown-linux-gnu - rust: nightly - - env: TARGET=x86_64-unknown-linux-gnu - rust: nightly - - env: TARGET=cargo-fmt - rust: beta - - - env: TARGET=wasm32-unknown-unknown - rust: nightly - install: rustup target add $TARGET - script: - - cargo build --target $TARGET - - cargo build --no-default-features --target $TARGET - -before_install: set -e - -install: - - bash ci/install.sh - -script: - - export PATH=$HOME/.local/bin:$PATH - - bash ci/script.sh - -after_script: set +e - -cache: cargo - -before_cache: - - chmod -R a+r $HOME/.cargo; - -branches: - only: - - staging - - trying diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 7d9890e3e30..45fad8230a0 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -6,21 +6,30 @@ documentation = "https://docs.rs/libm" keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" -repository = "https://github.com/japaric/libm" +repository = "https://github.com/rust-lang-nursery/libm" version = "0.1.2" edition = "2018" [features] # only used to run our test suite -checked = [] default = ['stable'] stable = [] + +# Generate tests which are random inputs and the outputs are calculated with +# musl libc. musl-reference-tests = ['rand'] +# Used checked array indexing instead of unchecked array indexing in this +# library. +checked = [] + [workspace] members = [ "crates/compiler-builtins-smoke-test", ] +[dev-dependencies] +no-panic = "0.1.8" + [build-dependencies] rand = { version = "0.6.5", optional = true } diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml index 36271ec1bea..82a74452a0f 100644 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -10,26 +10,18 @@ jobs: env: TOOLCHAIN: nightly - bash: rustup target add $TARGET - displayName: "Install rust cross target" - - bash: | - set -e - mkdir cross - curl -L https://github.com/rust-embedded/cross/releases/download/v0.1.14/cross-v0.1.14-x86_64-unknown-linux-musl.tar.gz | tar xzf - -C $HOME/.cargo/bin - displayName: "Install cross" - - bash: cross test --lib --features checked --target $TARGET --release - displayName: "Run lib tests" - - bash: cross test --tests --features checked --target $TARGET --release - displayName: "Run integration tests" + - template: ci/azure-install-rust.yml + - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET strategy: matrix: aarch64: TARGET: aarch64-unknown-linux-gnu - armhv: + arm: + TARGET: arm-unknown-linux-gnueabi + armhf: TARGET: arm-unknown-linux-gnueabihf armv7: TARGET: armv7-unknown-linux-gnueabihf - i586: - TARGET: i586-unknown-linux-gnu i686: TARGET: i686-unknown-linux-gnu mips: @@ -47,97 +39,31 @@ jobs: x86_64: TARGET: x86_64-unknown-linux-gnu - # - job: Linux - # pool: - # vmImage: ubuntu-16.04 - # steps: - # - template: ci/azure-test-all.yml - # strategy: - # matrix: - # stable: - # TOOLCHAIN: stable - # beta: - # TOOLCHAIN: beta - # nightly: - # TOOLCHAIN: nightly - # - # - job: macOS - # pool: - # vmImage: macos-10.13 - # steps: - # - template: ci/azure-test-all.yml - # strategy: - # matrix: - # x86_64: - # TARGET: x86_64-apple-darwin - # - # - job: iOS - # pool: - # vmImage: macos-10.13 - # steps: - # - checkout: self - # submodules: true - # - template: ci/azure-install-rust.yml - # - script: rustup target add $TARGET - # displayName: "Install rust cross target" - # - bash: | - # set -e - # export SDK_PATH=`xcrun --show-sdk-path --sdk $SDK` - # export RUSTFLAGS="-C link-arg=-isysroot -C link-arg=$SDK_PATH" - # cargo test --no-run --target $TARGET - # displayName: "Build for iOS" - # strategy: - # matrix: - # aarch64: - # TARGET: aarch64-apple-ios - # SDK: iphoneos - # armv7: - # TARGET: armv7-apple-ios - # SDK: iphoneos - # armv7s: - # TARGET: armv7s-apple-ios - # SDK: iphoneos - # i386: - # TARGET: i386-apple-ios - # SDK: iphonesimulator - # x86_64: - # TARGET: x86_64-apple-ios - # SDK: iphonesimulator - # - # - job: wasm - # pool: - # vmImage: ubuntu-16.04 - # steps: - # - checkout: self - # submodules: true - # - template: ci/azure-install-rust.yml - # - script: rustup target add wasm32-unknown-unknown - # displayName: "Install rust cross target" - # - script: cargo build --target wasm32-unknown-unknown - # displayName: "Build for wasm" - # - # - job: Windows - # pool: - # vmImage: vs2017-win2016 - # steps: - # - template: ci/azure-test-all.yml - # strategy: - # matrix: - # x86_64-msvc: - # TARGET: x86_64-pc-windows-msvc - # i686-msvc: - # TARGET: i686-pc-windows-msvc - # x86_64-gnu: - # TARGET: x86_64-pc-windows-gnu - # i686-gnu: - # TARGET: i686-pc-windows-gnu - # - # - job: Windows_arm64 - # pool: - # vmImage: windows-2019 - # steps: - # - template: ci/azure-install-rust.yml - # - script: rustup target add aarch64-pc-windows-msvc - # displayName: "Install rust cross target" - # - script: cargo test --no-run --target aarch64-pc-windows-msvc - # displayName: "Build for arm64" + - job: wasm + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-install-rust.yml + env: + TOOLCHAIN: nightly + - script: rustup target add wasm32-unknown-unknown + displayName: "Install rust wasm target" + - script: cargo build --target wasm32-unknown-unknown + displayName: "Build for wasm" + - script: cargo build --target wasm32-unknown-unknown --no-default-features + displayName: "Build for wasm (no default features)" + + - job: rustfmt + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-install-rust.yml + - bash: rustup component add rustfmt + - bash: cargo fmt --all -- --check + + - job: compiler_builtins_works + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-install-rust.yml + - bash: cargo build -p cb diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 31b1bbea947..41dc920e9f7 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -1,8 +1,17 @@ +use std::env; + fn main() { println!("cargo:rerun-if-changed=build.rs"); #[cfg(feature = "musl-reference-tests")] musl_reference_tests::generate(); + + if !cfg!(feature = "checked") { + let lvl = env::var("OPT_LEVEL").unwrap(); + if lvl != "0" { + println!("cargo:rustc-cfg=assert_no_panic"); + } + } } #[cfg(feature = "musl-reference-tests")] @@ -335,7 +344,7 @@ mod musl_reference_tests { src.push_str("}"); } - let path = format!("{}/tests.rs", dst); + let path = format!("{}/musl-tests.rs", dst); fs::write(&path, src).unwrap(); // Try to make it somewhat pretty diff --git a/library/compiler-builtins/libm/ci/azure-test-all.yml b/library/compiler-builtins/libm/ci/azure-test-all.yml index b2b7124d3ff..36831bd5401 100644 --- a/library/compiler-builtins/libm/ci/azure-test-all.yml +++ b/library/compiler-builtins/libm/ci/azure-test-all.yml @@ -1,41 +1,4 @@ steps: - - checkout: self - submodules: true - template: azure-install-rust.yml - - bash: cargo build --manifest-path backtrace-sys/Cargo.toml - displayName: "Build backtrace-sys" - - bash: cargo build - displayName: "Build backtrace" - - bash: cargo test - displayName: "Test backtrace" - - bash: cargo test --no-default-features - displayName: "Test backtrace (-default)" - - bash: cargo test --no-default-features --features 'std' - displayName: "Test backtrace (-default + std)" - - bash: cargo test --no-default-features --features 'libunwind std' - displayName: "Test backtrace (-default + libunwind)" - - bash: cargo test --no-default-features --features 'libunwind dladdr std' - displayName: "Test backtrace (-default + libunwind + dladdr)" - - bash: cargo test --no-default-features --features 'libunwind libbacktrace std' - displayName: "Test backtrace (-default + libunwind + libbacktrace)" - - bash: cargo test --no-default-features --features 'unix-backtrace std' - displayName: "Test backtrace (-default + unix-backtrace)" - - bash: cargo test --no-default-features --features 'unix-backtrace dladdr std' - displayName: "Test backtrace (-default + unix-backtrace + dladdr)" - - bash: cargo test --no-default-features --features 'unix-backtrace libbacktrace std' - displayName: "Test backtrace (-default + unix-backtrace + libbacktrace)" - - bash: cargo test --no-default-features --features 'serialize-serde std' - displayName: "Test backtrace (-default + serialize-serde + std)" - - bash: cargo test --no-default-features --features 'serialize-rustc std' - displayName: "Test backtrace (-default + serialize-rustc + std)" - - bash: cargo test --no-default-features --features 'serialize-rustc serialize-serde std' - displayName: "Test backtrace (-default + serialize-rustc + serialize-serde + std)" - - bash: cargo test --no-default-features --features 'cpp_demangle std' - displayName: "Test backtrace (-default + cpp_demangle + std)" - - bash: cargo test --no-default-features --features 'gimli-symbolize std' - displayName: "Test backtrace (-default + gimli-symbolize + std)" - - bash: cargo test --no-default-features --features 'dbghelp std' - displayName: "Test backtrace (-default + dbghelp + std)" - - bash: cd ./cpp_smoke_test && cargo test - displayName: "Test cpp_smoke_test" + - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET diff --git a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..9e2559f4ab3 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ + qemu-user-static +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-aarch64-static \ + QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile new file mode 100644 index 00000000000..afab874bc28 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER=qemu-arm-static \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile new file mode 100644 index 00000000000..3ed3602b0dc --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile new file mode 100644 index 00000000000..6617af1558c --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static +ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..5783e28e122 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -0,0 +1,4 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc-multilib libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..f47e8f5227b --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:18.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-mips-linux-gnu libc6-dev-mips-cross \ + binfmt-support qemu-user-static qemu-system-mips + +ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ + CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER=qemu-mips-static \ + QEMU_LD_PREFIX=/usr/mips-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile new file mode 100644 index 00000000000..8fa77c7bd07 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + gcc \ + gcc-mips64-linux-gnuabi64 \ + libc6-dev \ + libc6-dev-mips64-cross \ + qemu-user-static \ + qemu-system-mips +ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ + CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64-static \ + CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ + QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile new file mode 100644 index 00000000000..c6611d9ac89 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -0,0 +1,14 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + gcc \ + gcc-mips64el-linux-gnuabi64 \ + libc6-dev \ + libc6-dev-mips64el-cross \ + qemu-user-static +ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER=mips64el-linux-gnuabi64-gcc \ + CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64el-static \ + CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \ + QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..0bc69562462 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:18.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ + binfmt-support qemu-user-static + +ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \ + CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER=qemu-mipsel-static \ + QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..2d39fef6142 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:18.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ + qemu-system-ppc + +ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ + CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc-static \ + QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..653cd351156 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:18.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ + binfmt-support qemu-user-static qemu-system-ppc + +ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ + CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64-static \ + CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ + QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..63ea9af9d20 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:18.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ + qemu-system-ppc + +ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ + CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64le-static \ + QEMU_CPU=POWER8 \ + QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..98000f4eb81 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,4 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/install.sh b/library/compiler-builtins/libm/ci/install.sh deleted file mode 100644 index af26e2d4c30..00000000000 --- a/library/compiler-builtins/libm/ci/install.sh +++ /dev/null @@ -1,25 +0,0 @@ -set -euxo pipefail - -main() { - if [ $TARGET = cargo-fmt ]; then - rustup component add rustfmt-preview - return - fi - - if ! hash cross >/dev/null 2>&1; then - cargo install cross - fi - - rustup target add x86_64-unknown-linux-musl - - if [ $TARGET != x86_64-unknown-linux-gnu ]; then - rustup target add $TARGET - fi - - mkdir -p ~/.local/bin - curl -L https://github.com/japaric/qemu-bin/raw/master/14.04/qemu-arm-2.12.0 > ~/.local/bin/qemu-arm - chmod +x ~/.local/bin/qemu-arm - qemu-arm --version -} - -main diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh new file mode 100755 index 00000000000..6b3066e53e6 --- /dev/null +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -0,0 +1,36 @@ +# Small script to run tests for a target (or all targets) inside all the +# respective docker images. + +set -ex + +run() { + local target=$1 + + echo $target + + # This directory needs to exist before calling docker, otherwise docker will create it but it + # will be owned by root + mkdir -p target + + docker build -t $target ci/docker/$target + docker run \ + --rm \ + --user $(id -u):$(id -g) \ + -e CARGO_HOME=/cargo \ + -e CARGO_TARGET_DIR=/target \ + -v $HOME/.cargo:/cargo \ + -v `pwd`/target:/target \ + -v `pwd`:/checkout:ro \ + -v `rustc --print sysroot`:/rust:ro \ + -w /checkout \ + $target \ + sh -c "HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" +} + +if [ -z "$1" ]; then + for d in `ls ci/docker/`; do + run $d + done +else + run $1 +fi diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh new file mode 100755 index 00000000000..fabfd0ecb96 --- /dev/null +++ b/library/compiler-builtins/libm/ci/run.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +set -ex +TARGET=$1 + +cargo build --target $TARGET +cargo test --target $TARGET +cargo build --target $TARGET --release +cargo test --target $TARGET --release + +cargo test --features 'checked musl-reference-tests' --target $TARGET +cargo test --features 'checked musl-reference-tests' --target $TARGET --release diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh deleted file mode 100644 index c3b6faa6cac..00000000000 --- a/library/compiler-builtins/libm/ci/script.sh +++ /dev/null @@ -1,37 +0,0 @@ -set -euxo pipefail - -main() { - if [ $TARGET = cargo-fmt ]; then - cargo fmt -- --check - return - fi - - # quick check - cargo check - - # check that we can source import libm into compiler-builtins - cargo check --package cb - - # generate tests - cargo run -p input-generator --target x86_64-unknown-linux-musl - cargo run -p musl-generator --target x86_64-unknown-linux-musl - cargo run -p newlib-generator - - # test that the functions don't contain invocations of `panic!` - case $TARGET in - armv7-unknown-linux-gnueabihf) - cross build --release --target $TARGET --example no-panic - ;; - esac - - # run unit tests - cross test --lib --features checked --target $TARGET --release - - # run generated tests - cross test --tests --features checked --target $TARGET --release - - # TODO need to fix overflow issues (cf. issue #4) - # cross test --target $TARGET -} - -main diff --git a/library/compiler-builtins/libm/examples/no-panic.rs b/library/compiler-builtins/libm/examples/no-panic.rs deleted file mode 100644 index fb79f99afa1..00000000000 --- a/library/compiler-builtins/libm/examples/no-panic.rs +++ /dev/null @@ -1,115 +0,0 @@ -#![feature(lang_items)] -#![feature(panic_implementation)] -#![no_main] -#![no_std] - -extern crate libm; - -use core::panic::PanicInfo; -use core::ptr; - -macro_rules! force_eval { - ($e:expr) => { - unsafe { - core::ptr::read_volatile(&$e); - } - }; -} - -#[no_mangle] -pub fn main() { - force_eval!(libm::acos(random())); - force_eval!(libm::acosf(random())); - force_eval!(libm::asin(random())); - force_eval!(libm::asinf(random())); - force_eval!(libm::atan(random())); - force_eval!(libm::atan2(random(), random())); - force_eval!(libm::atan2f(random(), random())); - force_eval!(libm::atanf(random())); - force_eval!(libm::cbrt(random())); - force_eval!(libm::cbrtf(random())); - force_eval!(libm::ceil(random())); - force_eval!(libm::ceilf(random())); - force_eval!(libm::cos(random())); - force_eval!(libm::cosf(random())); - force_eval!(libm::cosh(random())); - force_eval!(libm::coshf(random())); - force_eval!(libm::exp(random())); - force_eval!(libm::exp2(random())); - force_eval!(libm::exp2f(random())); - force_eval!(libm::expf(random())); - force_eval!(libm::expm1(random())); - force_eval!(libm::expm1f(random())); - force_eval!(libm::fabs(random())); - force_eval!(libm::fabsf(random())); - force_eval!(libm::fdim(random(), random())); - force_eval!(libm::fdimf(random(), random())); - force_eval!(libm::floor(random())); - force_eval!(libm::floorf(random())); - force_eval!(libm::fma(random(), random(), random())); - force_eval!(libm::fmaf(random(), random(), random())); - force_eval!(libm::fmod(random(), random())); - force_eval!(libm::fmodf(random(), random())); - force_eval!(libm::hypot(random(), random())); - force_eval!(libm::hypotf(random(), random())); - force_eval!(libm::log(random())); - force_eval!(libm::log2(random())); - force_eval!(libm::log10(random())); - force_eval!(libm::log10f(random())); - force_eval!(libm::log1p(random())); - force_eval!(libm::log1pf(random())); - force_eval!(libm::log2f(random())); - force_eval!(libm::logf(random())); - force_eval!(libm::pow(random(), random())); - force_eval!(libm::powf(random(), random())); - force_eval!(libm::round(random())); - force_eval!(libm::roundf(random())); - force_eval!(libm::scalbn(random(), random())); - force_eval!(libm::scalbnf(random(), random())); - force_eval!(libm::sin(random())); - force_eval!(libm::sinf(random())); - force_eval!(libm::sinh(random())); - force_eval!(libm::sinhf(random())); - force_eval!(libm::sqrt(random())); - force_eval!(libm::sqrtf(random())); - force_eval!(libm::tan(random())); - force_eval!(libm::tanf(random())); - force_eval!(libm::tanh(random())); - force_eval!(libm::tanhf(random())); - force_eval!(libm::trunc(random())); - force_eval!(libm::truncf(random())); -} - -fn random() -> T -where - T: Copy, -{ - unsafe { - static mut X: usize = 0; - X += 8; - ptr::read_volatile(X as *const T) - } -} - -#[panic_implementation] -#[no_mangle] -pub fn panic(_info: &PanicInfo) -> ! { - // loop {} - extern "C" { - fn thou_shalt_not_panic() -> !; - } - - unsafe { thou_shalt_not_panic() } -} - -#[link(name = "c")] -extern "C" {} - -#[lang = "eh_personality"] -fn eh() {} - -#[no_mangle] -pub extern "C" fn __aeabi_unwind_cpp_pr0() {} - -#[no_mangle] -pub extern "C" fn __aeabi_unwind_cpp_pr1() {} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index e705dde0f91..5e94541ab1a 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -626,5 +626,5 @@ mod private { impl Sealed for f64 {} } -#[cfg(test)] -include!(concat!(env!("OUT_DIR"), "/tests.rs")); +#[cfg(all(test, feature = "musl-reference-tests"))] +include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); diff --git a/library/compiler-builtins/libm/src/math/acos.rs b/library/compiler-builtins/libm/src/math/acos.rs index 276e361f3d5..a0d1450e3a8 100644 --- a/library/compiler-builtins/libm/src/math/acos.rs +++ b/library/compiler-builtins/libm/src/math/acos.rs @@ -56,6 +56,7 @@ fn r(z: f64) -> f64 { } #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acos(x: f64) -> f64 { let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120 let z: f64; diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index b12ed531ae2..d635ee8a6c0 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -30,6 +30,7 @@ fn r(z: f32) -> f32 { } #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acosf(x: f32) -> f32 { let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs index a0bb4918c5a..85530083726 100644 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -63,6 +63,7 @@ fn comp_r(z: f64) -> f64 { } #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asin(mut x: f64) -> f64 { let z: f64; let r: f64; diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index 79c85d81d00..979f1a6548f 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -32,6 +32,7 @@ fn r(z: f32) -> f32 { } #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asinf(mut x: f32) -> f32 { let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120) diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index cf6a62a5459..a9cdc29333d 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -61,6 +61,7 @@ const AT: [f64; 11] = [ ]; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan(x: f64) -> f64 { let mut x = x; let mut ix = (x.to_bits() >> 32) as u32; diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index a91ddd84d0d..a702ec39fe6 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -44,6 +44,7 @@ const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan2(y: f64, x: f64) -> f64 { if x.is_nan() || y.is_nan() { return x + y; diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs index 211a992a065..94e3c771867 100644 --- a/library/compiler-builtins/libm/src/math/atan2f.rs +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -20,6 +20,7 @@ const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan2f(y: f32, x: f32) -> f32 { if x.is_nan() || y.is_nan() { return x + y; diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index b05152e2bc3..5d9024022b9 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -38,6 +38,7 @@ const A_T: [f32; 5] = [ ]; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atanf(mut x: f32) -> f32 { let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index 8c37f0b266b..ab11c497e12 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -28,6 +28,7 @@ const P3: f64 = -0.758397934778766047437; /* 0xbfe844cb, 0xbee751d9 */ const P4: f64 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrt(x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/cbrtf.rs b/library/compiler-builtins/libm/src/math/cbrtf.rs index 878372eefbf..19215b8587b 100644 --- a/library/compiler-builtins/libm/src/math/cbrtf.rs +++ b/library/compiler-builtins/libm/src/math/cbrtf.rs @@ -23,6 +23,7 @@ const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrtf(x: f32) -> f32 { let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 5dbfa6a2c0a..c2b11e4e74d 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -3,6 +3,7 @@ use core::f64; const TOINT: f64 = 1. / f64::EPSILON; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceil(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f64.ceil` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index c8cd4b5aa5b..5eb6a35a6ec 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -1,6 +1,7 @@ use core::f32; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceilf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f32.ceil` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs index df16b5c36a8..fe5a89919b2 100644 --- a/library/compiler-builtins/libm/src/math/cos.rs +++ b/library/compiler-builtins/libm/src/math/cos.rs @@ -42,6 +42,7 @@ use super::{k_cos, k_sin, rem_pio2}; // TRIG(x) returns trig(x) nearly rounded // #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cos(x: f64) -> f64 { let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index 23faacdc26c..615746a31f7 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -25,6 +25,7 @@ const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cosf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs index f3f7fbfbeb1..b6ba338b55f 100644 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -3,6 +3,7 @@ use super::expm1; use super::k_expo2; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cosh(mut x: f64) -> f64 { /* |x| */ let mut ix = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/coshf.rs b/library/compiler-builtins/libm/src/math/coshf.rs index bd468f5da71..b37ee1f3271 100644 --- a/library/compiler-builtins/libm/src/math/coshf.rs +++ b/library/compiler-builtins/libm/src/math/coshf.rs @@ -3,6 +3,7 @@ use super::expm1f; use super::k_expo2f; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn coshf(mut x: f32) -> f32 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs index cd63b8fb3f1..c3277318679 100644 --- a/library/compiler-builtins/libm/src/math/exp.rs +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -78,6 +78,7 @@ const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp(mut x: f64) -> f64 { let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 let x1p_149 = f64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149 diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index 3952e93007e..be6a003c6ee 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -319,6 +319,7 @@ static TBL: [u64; TBLSIZE * 2] = [ // Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library // for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp2(mut x: f64) -> f64 { let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64; let p1 = f64::from_bits(0x3fe62e42fefa39ef); diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index a3f6db8c5b3..32816104b5c 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -70,6 +70,7 @@ static EXP2FT: [u64; TBLSIZE] = [ // Tang, P. Table-driven Implementation of the Exponential Function // in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp2f(mut x: f32) -> f32 { let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; let p1 = f32::from_bits(0x3f317218); diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index 8ecc3b6abd6..e33425665eb 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -27,6 +27,7 @@ const P1: f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expf(mut x: f32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs index 9da064ee773..42616399066 100644 --- a/library/compiler-builtins/libm/src/math/expm1.rs +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -24,6 +24,7 @@ const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expm1(mut x: f64) -> f64 { let hi: f64; let lo: f64; diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs index 8f581733acd..4daa83c8565 100644 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -26,6 +26,7 @@ const Q1: f32 = -3.3333212137e-2; /* -0x888868.0p-28 */ const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expm1f(mut x: f32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs index 39f9815c404..b5369fbbe56 100644 --- a/library/compiler-builtins/libm/src/math/expo2.rs +++ b/library/compiler-builtins/libm/src/math/expo2.rs @@ -2,6 +2,7 @@ use super::{combine_words, exp}; /* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expo2(x: f64) -> f64 { /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ const K: i32 = 2043; diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 7c804653c99..0824bd59358 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -1,6 +1,7 @@ use core::u64; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabs(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f64.abs` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 884c20f6c41..859508f9b53 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -1,4 +1,5 @@ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabsf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f32.abs` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index 1daae4ebc22..32ae306e2ef 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -1,6 +1,7 @@ use core::f64; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdim(x: f64, y: f64) -> f64 { if x.is_nan() { x diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index 953e0c8dfaf..7db01932626 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -1,6 +1,7 @@ use core::f32; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdimf(x: f32, y: f32) -> f32 { if x.is_nan() { x diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index b14a48d55bc..f5ac8006f0e 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -3,6 +3,7 @@ use core::f64; const TOINT: f64 = 1. / f64::EPSILON; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floor(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f64.floor` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 71b5953df3e..8699be06026 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -1,6 +1,7 @@ use core::f32; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floorf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f32.floor` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 99a27164a81..38468ae755f 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -49,6 +49,7 @@ fn mul(x: u64, y: u64) -> (u64, u64) { } #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fma(x: f64, y: f64, z: f64) -> f64 { let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 let x0_ffffff8p_63 = f64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63 diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index 25b04fc2396..9e5a55f44b6 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -41,6 +41,7 @@ use super::fenv::{ * rounding occurs. */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { let xy: f64; let mut result: f64; diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs index 23f0c4846c4..ecc9b39a5c1 100644 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -1,6 +1,7 @@ use core::u64; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmod(x: f64, y: f64) -> f64 { let mut uxi = x.to_bits(); let mut uyi = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index d84cfeb01b8..98f51f455b8 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -2,6 +2,7 @@ use core::f32; use core::u32; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmodf(x: f32, y: f32) -> f32 { let mut uxi = x.to_bits(); let mut uyi = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs index f011415fdc6..dee9bbf4240 100644 --- a/library/compiler-builtins/libm/src/math/hypot.rs +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -19,6 +19,7 @@ fn sq(x: f64) -> (f64, f64) { } #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn hypot(mut x: f64, mut y: f64) -> f64 { let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700 let x1p_700 = f64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700 diff --git a/library/compiler-builtins/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/src/math/hypotf.rs index d59710ada39..4636b8f1d8b 100644 --- a/library/compiler-builtins/libm/src/math/hypotf.rs +++ b/library/compiler-builtins/libm/src/math/hypotf.rs @@ -3,6 +3,7 @@ use core::f32; use super::sqrtf; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn hypotf(mut x: f32, mut y: f32) -> f32 { let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90 let x1p_90 = f32::from_bits(0x12800000); // 0x1p-90f === 2 ^ -90 diff --git a/library/compiler-builtins/libm/src/math/k_cos.rs b/library/compiler-builtins/libm/src/math/k_cos.rs index 693950d1d41..8876fac2143 100644 --- a/library/compiler-builtins/libm/src/math/k_cos.rs +++ b/library/compiler-builtins/libm/src/math/k_cos.rs @@ -52,6 +52,7 @@ const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ // under FreeBSD, so don't pessimize things by forcibly clipping // any extra precision in w. #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn k_cos(x: f64, y: f64) -> f64 { let z = x * x; let w = z * z; diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs index 4aa10c0f089..9b48e190ddd 100644 --- a/library/compiler-builtins/libm/src/math/k_cosf.rs +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -21,6 +21,7 @@ const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn k_cosf(x: f64) -> f32 { let z = x * x; let w = z * z; diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs index e295c7a5346..0a9562eaeaa 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2.rs @@ -5,6 +5,7 @@ const K: i32 = 2043; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_expo2(x: f64) -> f64 { let k_ln2 = f64::from_bits(0x40962066151add8b); /* note that k is odd and scale*scale overflows */ diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs index ec2a2c5e2b8..68a7a50325c 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2f.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -5,6 +5,7 @@ const K: i32 = 235; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn k_expo2f(x: f32) -> f32 { let k_ln2 = f32::from_bits(0x4322e3bc); /* note that k is odd and scale*scale overflows */ diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs index 3e07c359447..15718c4c926 100644 --- a/library/compiler-builtins/libm/src/math/k_sin.rs +++ b/library/compiler-builtins/libm/src/math/k_sin.rs @@ -44,6 +44,7 @@ const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ // then 3 2 // sin(x) = x + (S1*x + (x *(r-y/2)+y)) #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn k_sin(x: f64, y: f64, iy: i32) -> f64 { let z = x * x; let w = z * z; diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs index 1c5f5f98a48..157fc104cc7 100644 --- a/library/compiler-builtins/libm/src/math/k_sinf.rs +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -21,6 +21,7 @@ const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn k_sinf(x: f64) -> f32 { let z = x * x; let w = z * z; diff --git a/library/compiler-builtins/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/src/math/k_tan.rs index e9ba21499d0..684e937b93c 100644 --- a/library/compiler-builtins/libm/src/math/k_tan.rs +++ b/library/compiler-builtins/libm/src/math/k_tan.rs @@ -59,6 +59,7 @@ const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { let hx = (f64::to_bits(x) >> 32) as u32; let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs index b9ccf2570f3..96a59100708 100644 --- a/library/compiler-builtins/libm/src/math/k_tanf.rs +++ b/library/compiler-builtins/libm/src/math/k_tanf.rs @@ -20,6 +20,7 @@ const T: [f64; 6] = [ ]; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn k_tanf(x: f64, odd: bool) -> f32 { let z = x * x; /* diff --git a/library/compiler-builtins/libm/src/math/log.rs b/library/compiler-builtins/libm/src/math/log.rs index 48e9fa79a46..948065abf3b 100644 --- a/library/compiler-builtins/libm/src/math/log.rs +++ b/library/compiler-builtins/libm/src/math/log.rs @@ -71,6 +71,7 @@ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs index 7c7afefa345..100618a0281 100644 --- a/library/compiler-builtins/libm/src/math/log10.rs +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -32,6 +32,7 @@ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs index 82b87c044b2..9cf89deb957 100644 --- a/library/compiler-builtins/libm/src/math/log10f.rs +++ b/library/compiler-builtins/libm/src/math/log10f.rs @@ -26,6 +26,7 @@ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index f42669deeae..fb35e90db14 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -66,6 +66,7 @@ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1p(x: f64) -> f64 { let mut ui: u64 = x.to_bits(); let hfsq: f64; diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index e6e1c14c8c5..9fc399d956e 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -21,6 +21,7 @@ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1pf(x: f32) -> f32 { let mut ui: u32 = x.to_bits(); let hfsq: f32; diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index 35eb9bf72b2..b513928ccb1 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -30,6 +30,7 @@ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs index 8684b142f8b..07a00dc3dae 100644 --- a/library/compiler-builtins/libm/src/math/log2f.rs +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -24,6 +24,7 @@ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs index 09519104174..95195601c2d 100644 --- a/library/compiler-builtins/libm/src/math/logf.rs +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -22,6 +22,7 @@ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn logf(mut x: f32) -> f32 { let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 329b3955d88..3b789dd9fb3 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -90,6 +90,7 @@ const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/l const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn pow(x: f64, y: f64) -> f64 { let t1: f64; let t2: f64; diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index 8d0afe6693c..5bc5c08e972 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -44,6 +44,7 @@ const IVLN2_H: f32 = 1.4426879883e+00; const IVLN2_L: f32 = 7.0526075433e-06; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn powf(x: f32, y: f32) -> f32 { let mut z: f32; let mut ax: f32; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 5c1685877b6..98d6b37beb5 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -43,6 +43,7 @@ const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ // // caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rem_pio2(x: f64) -> (i32, f64, f64) { let x1p24 = f64::from_bits(0x4170000000000000); diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 4d9146af9d6..8bab485695e 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -223,6 +223,7 @@ const PIO2: [f64; 8] = [ /// more accurately, = 0 mod 8 ). Thus the number of operations are /// independent of the exponent of the input. #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 5e7a7d43904..054c311841f 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -32,6 +32,7 @@ const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ /// use double precision for everything except passing x /// use __rem_pio2_large() for large x #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rem_pio2f(x: f32) -> (i32, f64) { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 1a6e754489c..9a9723cfbb6 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -3,6 +3,7 @@ use core::f64; const TOINT: f64 = 1.0 / f64::EPSILON; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn round(mut x: f64) -> f64 { let (f, i) = (x, x.to_bits()); let e: u64 = i >> 52 & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index 7dd79557a9d..839d9469a49 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -3,6 +3,7 @@ use core::f32; const TOINT: f32 = 1.0 / f32::EPSILON; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundf(mut x: f32) -> f32 { let i = x.to_bits(); let e: u32 = i >> 23 & 0xff; diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs index ad81072ddc9..2c4ab366084 100644 --- a/library/compiler-builtins/libm/src/math/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -1,4 +1,5 @@ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbn(x: f64, mut n: i32) -> f64 { let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 let x1p53 = f64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53 diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs index 901497e5e51..4e9771175d2 100644 --- a/library/compiler-builtins/libm/src/math/scalbnf.rs +++ b/library/compiler-builtins/libm/src/math/scalbnf.rs @@ -1,4 +1,5 @@ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index e749094e668..b7307441646 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -41,6 +41,7 @@ use super::{k_cos, k_sin, rem_pio2}; // Accuracy: // TRIG(x) returns trig(x) nearly rounded #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sin(x: f64) -> f64 { let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs index c9b02bcdc51..b8fc8d6f4be 100644 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -25,6 +25,7 @@ const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs index 684e8e30984..25ff3daaccb 100644 --- a/library/compiler-builtins/libm/src/math/sinh.rs +++ b/library/compiler-builtins/libm/src/math/sinh.rs @@ -5,6 +5,7 @@ use super::{expm1, expo2}; // = x + x^3/6 + o(x^5) // #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinh(x: f64) -> f64 { // union {double f; uint64_t i;} u = {.f = x}; // uint32_t w; diff --git a/library/compiler-builtins/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/src/math/sinhf.rs index 90c4b931281..fd0b2bfc894 100644 --- a/library/compiler-builtins/libm/src/math/sinhf.rs +++ b/library/compiler-builtins/libm/src/math/sinhf.rs @@ -2,6 +2,7 @@ use super::expm1f; use super::k_expo2f; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinhf(x: f32) -> f32 { let mut h = 0.5f32; let mut ix = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index b2387a26e75..a05a521fb4b 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -81,6 +81,7 @@ use core::f64; const TINY: f64 = 1.0e-300; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f64.sqrt` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 33cafbcbda3..b9365c61716 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -16,6 +16,7 @@ const TINY: f32 = 1.0e-30; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f32.sqrt` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs index 5a5f178a51c..e5c94cbb156 100644 --- a/library/compiler-builtins/libm/src/math/tan.rs +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -40,6 +40,7 @@ use super::{k_tan, rem_pio2}; // Accuracy: // TRIG(x) returns trig(x) nearly rounded #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tan(x: f64) -> f64 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs index 15a462d4e19..c286cdeb419 100644 --- a/library/compiler-builtins/libm/src/math/tanf.rs +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -25,6 +25,7 @@ const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs index 1c3dd0be438..75d695cf7e9 100644 --- a/library/compiler-builtins/libm/src/math/tanh.rs +++ b/library/compiler-builtins/libm/src/math/tanh.rs @@ -5,6 +5,7 @@ use super::expm1; * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanh(mut x: f64) -> f64 { let mut uf: f64 = x; let mut ui: u64 = f64::to_bits(uf); diff --git a/library/compiler-builtins/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/src/math/tanhf.rs index 98a1b60c29b..ac4657b5abd 100644 --- a/library/compiler-builtins/libm/src/math/tanhf.rs +++ b/library/compiler-builtins/libm/src/math/tanhf.rs @@ -1,6 +1,7 @@ use super::expm1f; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanhf(mut x: f32) -> f32 { /* x = |x| */ let mut ix = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 8eecfcf538e..1ee46fc7dae 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -1,6 +1,7 @@ use core::f64; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn trunc(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f64.trunc` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index 0d74fea9c9e..f9338326905 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -1,6 +1,7 @@ use core::f32; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn truncf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f32.trunc` native instruction, so we can leverage this for both code size -- cgit 1.4.1-3-g733a5 From 0656dec45610f13c8b56c30f89f0987a1954622c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 11:38:26 -0700 Subject: Delete stray test --- library/compiler-builtins/libm/src/math/acosf.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index d635ee8a6c0..a6061ae8027 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -74,17 +74,3 @@ pub fn acosf(x: f32) -> f32 { w = r(z) * s + c; 2. * (df + w) } - -#[cfg(test)] -mod tests { - #[test] - fn acosf() { - extern { - fn acosf(x: f32) -> f32; - } - unsafe { - crate::_eqf(super::acosf(1.0), acosf(1.0)).unwrap(); - } - } - // shared::f32!("musl", acosf); -} -- cgit 1.4.1-3-g733a5 From 9cf8475f2f5970f21086b40116d266b746f11c8b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 11:40:01 -0700 Subject: Fix azure config --- library/compiler-builtins/libm/azure-pipelines.yml | 5 ----- library/compiler-builtins/libm/ci/azure-test-all.yml | 4 ---- 2 files changed, 9 deletions(-) delete mode 100644 library/compiler-builtins/libm/ci/azure-test-all.yml diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml index 82a74452a0f..9f4e3672d28 100644 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -7,10 +7,7 @@ jobs: vmImage: ubuntu-16.04 steps: - template: ci/azure-install-rust.yml - env: - TOOLCHAIN: nightly - bash: rustup target add $TARGET - - template: ci/azure-install-rust.yml - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET strategy: matrix: @@ -44,8 +41,6 @@ jobs: vmImage: ubuntu-16.04 steps: - template: ci/azure-install-rust.yml - env: - TOOLCHAIN: nightly - script: rustup target add wasm32-unknown-unknown displayName: "Install rust wasm target" - script: cargo build --target wasm32-unknown-unknown diff --git a/library/compiler-builtins/libm/ci/azure-test-all.yml b/library/compiler-builtins/libm/ci/azure-test-all.yml deleted file mode 100644 index 36831bd5401..00000000000 --- a/library/compiler-builtins/libm/ci/azure-test-all.yml +++ /dev/null @@ -1,4 +0,0 @@ -steps: - - template: azure-install-rust.yml - - - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET -- cgit 1.4.1-3-g733a5 From 47a543171c1ed4c55b6744cff9a65bbcdcf19d95 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 11:44:58 -0700 Subject: Run rustfmt --- library/compiler-builtins/libm/build.rs | 28 +++++++++++----------- library/compiler-builtins/libm/src/math/atan.rs | 3 ++- library/compiler-builtins/libm/src/math/expf.rs | 1 - library/compiler-builtins/libm/src/math/fma.rs | 8 +++---- library/compiler-builtins/libm/src/math/pow.rs | 2 +- library/compiler-builtins/libm/src/math/powf.rs | 2 +- .../compiler-builtins/libm/src/math/rem_pio2.rs | 1 - library/compiler-builtins/libm/src/math/scalbn.rs | 2 +- 8 files changed, 23 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 41dc920e9f7..23e1178e360 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -267,22 +267,17 @@ mod musl_reference_tests { .status() .unwrap(); assert!(status.success()); - let output = Command::new("./gen") - .current_dir(&dst) - .output() - .unwrap(); + let output = Command::new("./gen").current_dir(&dst).output().unwrap(); assert!(output.status.success()); assert!(output.stderr.is_empty()); // Map all the output bytes back to an `i64` and then shove it all into // the expected results. - let mut results = - output.stdout.chunks_exact(8) - .map(|buf| { - let mut exact = [0; 8]; - exact.copy_from_slice(buf); - i64::from_le_bytes(exact) - }); + let mut results = output.stdout.chunks_exact(8).map(|buf| { + let mut exact = [0; 8]; + exact.copy_from_slice(buf); + i64::from_le_bytes(exact) + }); for test in functions.iter_mut().flat_map(|f| f.tests.iter_mut()) { test.output = results.next().unwrap(); @@ -301,7 +296,10 @@ mod musl_reference_tests { src.push_str("fn "); src.push_str(&function.name); src.push_str("_matches_musl() {"); - src.push_str(&format!("static TESTS: &[([i64; {}], i64)]", function.args.len())); + src.push_str(&format!( + "static TESTS: &[([i64; {}], i64)]", + function.args.len() + )); src.push_str(" = &["); for test in function.tests.iter() { src.push_str("(["); @@ -336,9 +334,11 @@ mod musl_reference_tests { Ty::Bool => unreachable!(), }); - src.push_str(r#" + src.push_str( + r#" panic!("INPUT: {:?} EXPECTED: {:?} ACTUAL {:?}", test, expected, output); - "#); + "#, + ); src.push_str("}"); src.push_str("}"); diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index a9cdc29333d..ad1d57c1fe7 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -148,7 +148,8 @@ mod tests { (-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6), (-1.0, -f64::consts::FRAC_PI_4), (-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3), - ].iter() + ] + .iter() { assert!( (atan(*input) - answer) / answer < 1e-5, diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index e33425665eb..baade2552e1 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -31,7 +31,6 @@ const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ pub fn expf(mut x: f32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ - let mut hx = x.to_bits(); let sign = (hx >> 31) as i32; /* sign bit of x */ let signb: bool = sign != 0; diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 38468ae755f..acf99a5d4e2 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -166,13 +166,13 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { } if r == c { /* min normal after rounding, underflow depends - on arch behaviour which can be imitated by - a double to float conversion */ + on arch behaviour which can be imitated by + a double to float conversion */ let fltmin: f32 = (x0_ffffff8p_63 * f32::MIN_POSITIVE as f64 * r) as f32; return f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64; } /* one bit is lost when scaled, add another top bit to - only round once at conversion if it is inexact */ + only round once at conversion if it is inexact */ if (rhi << 53) != 0 { i = (rhi >> 1 | (rhi & 1) | 1 << 62) as i64; if sign != 0 { @@ -182,7 +182,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { r = 2. * r - c; /* remove top bit */ /* raise underflow portably, such that it - cannot be optimized away */ + cannot be optimized away */ { let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * r; r += (tiny * tiny) * (r - r); diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 3b789dd9fb3..b5b0407efa1 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -262,7 +262,7 @@ pub fn pow(x: f64, y: f64) -> f64 { } /* now |1-x| is TINY <= 2**-20, suffice to compute - log(x) by x-x^2/2+x^3/3-x^4/4 */ + log(x) by x-x^2/2+x^3/3-x^4/4 */ let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ let w: f64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index 5bc5c08e972..0a26573a3d1 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -198,7 +198,7 @@ pub fn powf(x: f32, y: f32) -> f32 { } /* now |1-x| is TINY <= 2**-20, suffice to compute - log(x) by x-x^2/2+x^3/3-x^4/4 */ + log(x) by x-x^2/2+x^3/3-x^4/4 */ t = ax - 1.; /* t has 20 trailing zeros */ w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 98d6b37beb5..82faf5da97a 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -10,7 +10,6 @@ // ==================================================== // // Optimized by Bruce D. Evans. */ - use super::rem_pio2_large; // #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs index 2c4ab366084..d8c8409ac10 100644 --- a/library/compiler-builtins/libm/src/math/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -19,7 +19,7 @@ pub fn scalbn(x: f64, mut n: i32) -> f64 { } } else if n < -1022 { /* make sure final n < -53 to avoid double - rounding in the subnormal range */ + rounding in the subnormal range */ y *= x1p_1022 * x1p53; n += 1022 - 53; if n < -1022 { -- cgit 1.4.1-3-g733a5 From c4468281d48438de363314270f023d7d34e52421 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 11:47:46 -0700 Subject: More azure config fixes --- library/compiler-builtins/libm/README.md | 2 ++ library/compiler-builtins/libm/azure-pipelines.yml | 9 +++++++++ library/compiler-builtins/libm/ci/run-docker.sh | 3 ++- library/compiler-builtins/libm/ci/run.sh | 6 +++--- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 24b816c351b..568a049f0c5 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -1,5 +1,7 @@ # `libm` +[![Build Status](https://dev.azure.com/rust-lang/libm/_apis/build/status/rust-lang-nursery.libm?branchName=master)](https://dev.azure.com/rust-lang/libm/_build/latest?definitionId=7&branchName=master) + A port of [MUSL]'s libm to Rust. [MUSL]: https://www.musl-libc.org/ diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml index 9f4e3672d28..d8068e023b4 100644 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -8,7 +8,11 @@ jobs: steps: - template: ci/azure-install-rust.yml - bash: rustup target add $TARGET + displayName: "add cross target" + - bash: rustup target add x86_64-unknown-linux-musl + displayName: "add musl target" - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET + displayName: "run tests" strategy: matrix: aarch64: @@ -47,6 +51,8 @@ jobs: displayName: "Build for wasm" - script: cargo build --target wasm32-unknown-unknown --no-default-features displayName: "Build for wasm (no default features)" + variables: + TOOLCHAIN: nightly - job: rustfmt pool: @@ -54,7 +60,9 @@ jobs: steps: - template: ci/azure-install-rust.yml - bash: rustup component add rustfmt + displayName: "install rustfmt" - bash: cargo fmt --all -- --check + displayName: "check formatting" - job: compiler_builtins_works pool: @@ -62,3 +70,4 @@ jobs: steps: - template: ci/azure-install-rust.yml - bash: cargo build -p cb + displayName: "Check compiler-builtins still probably builds" diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index 6b3066e53e6..95bd3db4836 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -22,9 +22,10 @@ run() { -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ -v `rustc --print sysroot`:/rust:ro \ + --init \ -w /checkout \ $target \ - sh -c "HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" + sh -c "HOME=/tmp PATH=\$PATH:/rust/bin exec ci/run.sh $target" } if [ -z "$1" ]; then diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index fabfd0ecb96..d2881130039 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -3,10 +3,10 @@ set -ex TARGET=$1 -cargo build --target $TARGET cargo test --target $TARGET -cargo build --target $TARGET --release cargo test --target $TARGET --release -cargo test --features 'checked musl-reference-tests' --target $TARGET +# FIXME(#4) overflow checks in non-release currently cause issues +#cargo test --features 'checked musl-reference-tests' --target $TARGET + cargo test --features 'checked musl-reference-tests' --target $TARGET --release -- cgit 1.4.1-3-g733a5 From 272f92def5be4051303711684599800b9466e462 Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Mon, 23 Jul 2018 01:13:23 -0500 Subject: Add some tests for pow These probably aren't comprehensive but they cover all the edge cases identified in the original musl source. --- library/compiler-builtins/libm/src/math/pow.rs | 189 +++++++++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index b5b0407efa1..288e403c688 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -408,3 +408,192 @@ pub fn pow(x: f64, y: f64) -> f64 { return s * z; } + +/// Special cases: + +/// 20. (anything) ** 1 is (anything) +/// 21. (anything) ** -1 is 1/(anything) +/// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) +/// 23. (-anything except 0 and inf) ** (non-integer) is NAN + +#[cfg(test)] +mod tests { + // #[macro_use] + extern crate std; + + use self::std::f64::consts::{E, PI}; + use self::std::f64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; + use super::pow; + + // const TESTCASES: &[f64] = &[1.0, 0.0, PI, -PI, E, -E, MIN, MAX, MIN_POSITIVE, NAN, INFINITY, NEG_INFINITY]; + + const POS_ZERO: &[f64] = &[0.0]; + const NEG_ZERO: &[f64] = &[-0.0]; + const POS_ONE: &[f64] = &[1.0]; + const NEG_ONE: &[f64] = &[-1.0]; + const POS_FLOATS: &[f64] = &[E, PI, MAX]; + const NEG_FLOATS: &[f64] = &[-E, -PI, MIN]; + const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), MIN_POSITIVE, EPSILON]; + const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -MIN_POSITIVE, -EPSILON]; + const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0]; + const NEG_EVENS: &[f64] = &[-8.0, -2.0]; + const POS_ODDS: &[f64] = &[3.0, 7.0]; + const NEG_ODDS: &[f64] = &[-7.0, -3.0]; + const NANS: &[f64] = &[NAN]; + // const EDGES: &[f64] = &[MIN, MAX, MIN_POSITIVE, EPSILON]; + const POS_INF: &[f64] = &[INFINITY]; + const NEG_INF: &[f64] = &[NEG_INFINITY]; + + const ALL: &[&[f64]] = &[ + POS_ZERO, NEG_ZERO, NANS, NEG_SMALL_FLOATS, POS_SMALL_FLOATS, NEG_FLOATS, POS_FLOATS, NEG_EVENS, POS_EVENS, NEG_ODDS, POS_ODDS, + NEG_INF, POS_INF, NEG_ONE, POS_ONE, + ]; + const POS: &[&[f64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF]; + const NEG: &[&[f64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF]; + + fn pow_test(base: f64, exponent: f64, expected: f64) { + let res = pow(base, exponent); + assert!(if expected.is_nan() {res.is_nan()} else {pow(base, exponent) == expected}, + "{} ** {} was {} instead of {}", base, exponent, res, expected); + } + + fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { + sets.iter() + .for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); + } + + fn test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) { + sets.iter() + .for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); + } + + fn test_sets(sets: &[&[f64]], computed: &Fn(f64) -> f64, expected: &Fn(f64) -> f64) { + sets.iter() + .for_each(|s| s.iter().for_each(|val| { + let exp = expected(*val); + let res = computed(*val); + + assert!(if exp.is_nan() {res.is_nan()} else {exp == res}, + "test for {} was {} instead of {}", val, res, exp); + })); + } + + /// 1. (anything) ** 0 is 1 + #[test] + fn zero_as_exponent() { + test_sets_as_base(ALL, 0.0, 1.0); + test_sets_as_base(ALL, -0.0, 1.0); + } + + /// 2. 1 ** (anything) is 1 + #[test] + fn one_as_base() { + test_sets_as_exponent(1.0, ALL, 1.0); + } + + /// 3. (anything except 1) ** NAN is NAN + /// 4. NAN ** (anything except 0) is NAN + #[test] + fn nan_inputs() { + // NAN as the base: + // (NAN ^ anything *but 0* should be NAN) + test_sets_as_exponent(NAN, &ALL[2..], NAN); + + // NAN as the exponent: + // (anything *but 1* ^ NAN should be NAN) + test_sets_as_base(&ALL[..(ALL.len() - 2)], NAN, NAN); + } + + /// 16. +INF ** (+anything except 0,NAN) is +INF + /// 17. +INF ** (-anything except 0,NAN) is +0 + /// 18. -INF ** (+odd integer) is -INF + /// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) + #[test] + fn infinity_as_base() { + // Positive Infinity as the base: + // (+Infinity ^ positive anything but 0 and NAN should be +Infinity) + test_sets_as_exponent(INFINITY, &POS[1..], INFINITY); + + // (+Infinity ^ negative anything except 0 and NAN should be 0.0) + test_sets_as_exponent(INFINITY, &NEG[1..], 0.0); + + // Negative Infinity as the base: + // (-Infinity ^ positive odd ints should be -Infinity) + test_sets_as_exponent(NEG_INFINITY, &[POS_ODDS], NEG_INFINITY); + + // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) + // We can lump in pos/neg odd ints here because they don't seem to + // cause panics (div by zero) in release mode (I think). + test_sets(ALL, &|v: f64| pow(NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); + } + + /// 5. +-(|x| > 1) ** +INF is +INF + /// 6. +-(|x| > 1) ** -INF is +0 + /// 7. +-(|x| < 1) ** +INF is +0 + /// 8. +-(|x| < 1) ** -INF is +INF + /// 9. -1 ** +-INF is 1 + #[test] + fn infinity_as_exponent() { + // Positive/Negative base greater than 1: + // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes NAN as the base) + test_sets_as_base(&ALL[5..(ALL.len() - 2)], INFINITY, INFINITY); + + // (pos/neg > 1 ^ -Infinity should be 0.0) + test_sets_as_base(&ALL[5..(ALL.len() - 2)], NEG_INFINITY, 0.0); + + // Positive/Negative base less than 1: + let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS]; + + // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes NAN as the base) + test_sets_as_base(base_below_one, INFINITY, 0.0); + + // (pos/neg < 1 ^ -Infinity should be Infinity) + test_sets_as_base(base_below_one, NEG_INFINITY, INFINITY); + + // Positive/Negative 1 as the base: + // (pos/neg 1 ^ Infinity should be 1) + test_sets_as_base(&[NEG_ONE, POS_ONE], INFINITY, 1.0); + + // (pos/neg 1 ^ -Infinity should be 1) + test_sets_as_base(&[NEG_ONE, POS_ONE], NEG_INFINITY, 1.0); + } + + /// 10. +0 ** (+anything except 0, NAN) is +0 + /// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + /// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero + /// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero + /// 14. -0 ** (+odd integer) is -0 + /// 15. -0 ** (-odd integer) is -INF, raise divbyzero + #[test] + fn zero_as_base() { + // Positive Zero as the base: + // (+0 ^ anything positive but 0 and NAN should be +0) + test_sets_as_exponent(0.0, &POS[1..], 0.0); + + // (+0 ^ anything negative but 0 and NAN should be Infinity) + // (this should panic because we're dividing by zero but won't because release mode, I think) + test_sets_as_exponent(0.0, &NEG[1..], INFINITY); + + // Negative Zero as the base: + // (-0 ^ anything positive but 0, NAN, and odd ints should be +0) + test_sets_as_exponent(-0.0, &POS[3..], 0.0); + + // (-0 ^ anything negative but 0, NAN, and odd ints should be Infinity) + // (should panic because of divide by zero) + test_sets_as_exponent(-0.0, &NEG[3..], INFINITY); + + // (-0 ^ positive odd ints should be -0) + test_sets_as_exponent(-0.0, &[POS_ODDS], -0.0); + + // (-0 ^ negative odd ints should be -Infinity) + // (should panic because of divide by zero) + test_sets_as_exponent(-0.0, &[NEG_ODDS], NEG_INFINITY); + } + + #[test] + fn normal_cases() { + assert_eq!(pow(2.0, 20.0), (1 << 20) as f64); + assert_eq!(pow(-1.0, 9.0), -1.0); + assert!(pow(-1.0, 2.2).is_nan()); + } +} -- cgit 1.4.1-3-g733a5 From 399b9acdd2ba0cc55955c3efba35ca50f9b59181 Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Mon, 23 Jul 2018 02:54:53 -0500 Subject: Cleaned up + rustfmt'ed --- library/compiler-builtins/libm/src/math/pow.rs | 85 +++++++++++++------------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 288e403c688..47505dc9a0c 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -409,24 +409,14 @@ pub fn pow(x: f64, y: f64) -> f64 { return s * z; } -/// Special cases: - -/// 20. (anything) ** 1 is (anything) -/// 21. (anything) ** -1 is 1/(anything) -/// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) -/// 23. (-anything except 0 and inf) ** (non-integer) is NAN - #[cfg(test)] mod tests { - // #[macro_use] extern crate std; use self::std::f64::consts::{E, PI}; use self::std::f64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; use super::pow; - // const TESTCASES: &[f64] = &[1.0, 0.0, PI, -PI, E, -E, MIN, MAX, MIN_POSITIVE, NAN, INFINITY, NEG_INFINITY]; - const POS_ZERO: &[f64] = &[0.0]; const NEG_ZERO: &[f64] = &[-0.0]; const POS_ONE: &[f64] = &[1.0]; @@ -440,21 +430,43 @@ mod tests { const POS_ODDS: &[f64] = &[3.0, 7.0]; const NEG_ODDS: &[f64] = &[-7.0, -3.0]; const NANS: &[f64] = &[NAN]; - // const EDGES: &[f64] = &[MIN, MAX, MIN_POSITIVE, EPSILON]; const POS_INF: &[f64] = &[INFINITY]; const NEG_INF: &[f64] = &[NEG_INFINITY]; const ALL: &[&[f64]] = &[ - POS_ZERO, NEG_ZERO, NANS, NEG_SMALL_FLOATS, POS_SMALL_FLOATS, NEG_FLOATS, POS_FLOATS, NEG_EVENS, POS_EVENS, NEG_ODDS, POS_ODDS, - NEG_INF, POS_INF, NEG_ONE, POS_ONE, + POS_ZERO, + NEG_ZERO, + NANS, + NEG_SMALL_FLOATS, + POS_SMALL_FLOATS, + NEG_FLOATS, + POS_FLOATS, + NEG_EVENS, + POS_EVENS, + NEG_ODDS, + POS_ODDS, + NEG_INF, + POS_INF, + NEG_ONE, + POS_ONE, ]; const POS: &[&[f64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF]; const NEG: &[&[f64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF]; fn pow_test(base: f64, exponent: f64, expected: f64) { let res = pow(base, exponent); - assert!(if expected.is_nan() {res.is_nan()} else {pow(base, exponent) == expected}, - "{} ** {} was {} instead of {}", base, exponent, res, expected); + assert!( + if expected.is_nan() { + res.is_nan() + } else { + pow(base, exponent) == expected + }, + "{} ** {} was {} instead of {}", + base, + exponent, + res, + expected + ); } fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { @@ -468,31 +480,37 @@ mod tests { } fn test_sets(sets: &[&[f64]], computed: &Fn(f64) -> f64, expected: &Fn(f64) -> f64) { - sets.iter() - .for_each(|s| s.iter().for_each(|val| { + sets.iter().for_each(|s| { + s.iter().for_each(|val| { let exp = expected(*val); let res = computed(*val); - assert!(if exp.is_nan() {res.is_nan()} else {exp == res}, - "test for {} was {} instead of {}", val, res, exp); - })); + assert!( + if exp.is_nan() { + res.is_nan() + } else { + exp == res + }, + "test for {} was {} instead of {}", + val, + res, + exp + ); + }) + }); } - /// 1. (anything) ** 0 is 1 #[test] fn zero_as_exponent() { test_sets_as_base(ALL, 0.0, 1.0); test_sets_as_base(ALL, -0.0, 1.0); } - /// 2. 1 ** (anything) is 1 #[test] fn one_as_base() { test_sets_as_exponent(1.0, ALL, 1.0); } - /// 3. (anything except 1) ** NAN is NAN - /// 4. NAN ** (anything except 0) is NAN #[test] fn nan_inputs() { // NAN as the base: @@ -504,10 +522,6 @@ mod tests { test_sets_as_base(&ALL[..(ALL.len() - 2)], NAN, NAN); } - /// 16. +INF ** (+anything except 0,NAN) is +INF - /// 17. +INF ** (-anything except 0,NAN) is +0 - /// 18. -INF ** (+odd integer) is -INF - /// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) #[test] fn infinity_as_base() { // Positive Infinity as the base: @@ -527,11 +541,6 @@ mod tests { test_sets(ALL, &|v: f64| pow(NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); } - /// 5. +-(|x| > 1) ** +INF is +INF - /// 6. +-(|x| > 1) ** -INF is +0 - /// 7. +-(|x| < 1) ** +INF is +0 - /// 8. +-(|x| < 1) ** -INF is +INF - /// 9. -1 ** +-INF is 1 #[test] fn infinity_as_exponent() { // Positive/Negative base greater than 1: @@ -539,7 +548,7 @@ mod tests { test_sets_as_base(&ALL[5..(ALL.len() - 2)], INFINITY, INFINITY); // (pos/neg > 1 ^ -Infinity should be 0.0) - test_sets_as_base(&ALL[5..(ALL.len() - 2)], NEG_INFINITY, 0.0); + test_sets_as_base(&ALL[5..ALL.len() - 2], NEG_INFINITY, 0.0); // Positive/Negative base less than 1: let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS]; @@ -558,12 +567,6 @@ mod tests { test_sets_as_base(&[NEG_ONE, POS_ONE], NEG_INFINITY, 1.0); } - /// 10. +0 ** (+anything except 0, NAN) is +0 - /// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 - /// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero - /// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero - /// 14. -0 ** (+odd integer) is -0 - /// 15. -0 ** (-odd integer) is -INF, raise divbyzero #[test] fn zero_as_base() { // Positive Zero as the base: @@ -576,7 +579,7 @@ mod tests { // Negative Zero as the base: // (-0 ^ anything positive but 0, NAN, and odd ints should be +0) - test_sets_as_exponent(-0.0, &POS[3..], 0.0); + test_sets_as_exponent(-0.0, &POS[3..], 0.0); // (-0 ^ anything negative but 0, NAN, and odd ints should be Infinity) // (should panic because of divide by zero) -- cgit 1.4.1-3-g733a5 From 770e0edb7087f346554392545feef3bfbec77041 Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Mon, 23 Jul 2018 09:45:22 -0500 Subject: Some additional tests --- library/compiler-builtins/libm/src/math/pow.rs | 39 ++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 47505dc9a0c..c908c8461f2 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -421,12 +421,12 @@ mod tests { const NEG_ZERO: &[f64] = &[-0.0]; const POS_ONE: &[f64] = &[1.0]; const NEG_ONE: &[f64] = &[-1.0]; - const POS_FLOATS: &[f64] = &[E, PI, MAX]; - const NEG_FLOATS: &[f64] = &[-E, -PI, MIN]; + const POS_FLOATS: &[f64] = &[99.0 / 70.0, E, PI]; + const NEG_FLOATS: &[f64] = &[-99.0 / 70.0, -E, -PI]; const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), MIN_POSITIVE, EPSILON]; const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -MIN_POSITIVE, -EPSILON]; - const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0]; - const NEG_EVENS: &[f64] = &[-8.0, -2.0]; + const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, MAX]; + const NEG_EVENS: &[f64] = &[MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; const POS_ODDS: &[f64] = &[3.0, 7.0]; const NEG_ODDS: &[f64] = &[-7.0, -3.0]; const NANS: &[f64] = &[NAN]; @@ -574,7 +574,7 @@ mod tests { test_sets_as_exponent(0.0, &POS[1..], 0.0); // (+0 ^ anything negative but 0 and NAN should be Infinity) - // (this should panic because we're dividing by zero but won't because release mode, I think) + // (this should panic because we're dividing by zero) test_sets_as_exponent(0.0, &NEG[1..], INFINITY); // Negative Zero as the base: @@ -593,10 +593,39 @@ mod tests { test_sets_as_exponent(-0.0, &[NEG_ODDS], NEG_INFINITY); } + #[test] + fn special_cases() { + // / 20. (anything) ** 1 is (anything) + // One as the exponent: + // (anything ^ 1 should be anything - i.e. the base) + test_sets(ALL, &|v: f64| pow(v, 1.0), &|v: f64| v); + + // / 21. (anything) ** -1 is 1/(anything) + // Negative One as the exponent: + // (anything ^ -1 should be 1/anything) + test_sets(ALL, &|v: f64| pow(v, -1.0), &|v: f64| 1.0 / v); + + // / 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + // Factoring -1 out: + // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) + &[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| int_set.iter().for_each(|int| { + test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| pow(-1.0, *int) * pow(v, *int)); + })); + + // / 23. (-anything except 0 and inf) ** (non-integer) is NAN + // Negative base (imaginary results): + // (-anything except 0 and Infinity ^ non-integer should be NAN) + &NEG[1..(NEG.len()-1)].iter().for_each(|set| set.iter().for_each(|val| { + test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| NAN); + })); + + } + #[test] fn normal_cases() { assert_eq!(pow(2.0, 20.0), (1 << 20) as f64); assert_eq!(pow(-1.0, 9.0), -1.0); assert!(pow(-1.0, 2.2).is_nan()); + assert!(pow(-1.0, -1.14).is_nan()); } } -- cgit 1.4.1-3-g733a5 From f52b7ea8f5dc173766c8435f482cde0e85c981b1 Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Mon, 23 Jul 2018 09:48:47 -0500 Subject: rustfmt'ed --- library/compiler-builtins/libm/src/math/pow.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index c908c8461f2..7aaec787401 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -595,30 +595,33 @@ mod tests { #[test] fn special_cases() { - // / 20. (anything) ** 1 is (anything) // One as the exponent: // (anything ^ 1 should be anything - i.e. the base) test_sets(ALL, &|v: f64| pow(v, 1.0), &|v: f64| v); - // / 21. (anything) ** -1 is 1/(anything) // Negative One as the exponent: // (anything ^ -1 should be 1/anything) test_sets(ALL, &|v: f64| pow(v, -1.0), &|v: f64| 1.0 / v); - // / 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - &[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| int_set.iter().for_each(|int| { - test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| pow(-1.0, *int) * pow(v, *int)); - })); + &[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS] + .iter() + .for_each(|int_set| { + int_set.iter().for_each(|int| { + test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| { + pow(-1.0, *int) * pow(v, *int) + }); + }) + }); - // / 23. (-anything except 0 and inf) ** (non-integer) is NAN // Negative base (imaginary results): // (-anything except 0 and Infinity ^ non-integer should be NAN) - &NEG[1..(NEG.len()-1)].iter().for_each(|set| set.iter().for_each(|val| { - test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| NAN); - })); - + &NEG[1..(NEG.len() - 1)].iter().for_each(|set| { + set.iter().for_each(|val| { + test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| NAN); + }) + }); } #[test] -- cgit 1.4.1-3-g733a5 From 7f76eda7b51fe698a04c7dfda1bf49507a887ac0 Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Mon, 23 Jul 2018 11:14:41 -0500 Subject: Use core for constants instead of std (thanks @vks) --- library/compiler-builtins/libm/src/math/pow.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 7aaec787401..a1889bb6bb6 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -411,10 +411,10 @@ pub fn pow(x: f64, y: f64) -> f64 { #[cfg(test)] mod tests { - extern crate std; + extern crate core; - use self::std::f64::consts::{E, PI}; - use self::std::f64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; + use self::core::f64::consts::{E, PI}; + use self::core::f64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; use super::pow; const POS_ZERO: &[f64] = &[0.0]; -- cgit 1.4.1-3-g733a5 From d8cc6337f6e7606a54bd1b70cb9778555829753b Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Tue, 31 Jul 2018 20:56:46 -0400 Subject: Change sqrt to use wrapping operations --- library/compiler-builtins/libm/src/math/sqrt.rs | 63 +++++++++++++------------ 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index a05a521fb4b..14404d4eb18 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -77,6 +77,7 @@ */ use core::f64; +use core::num::Wrapping; const TINY: f64 = 1.0e-300; @@ -96,21 +97,21 @@ pub fn sqrt(x: f64) -> f64 { } } let mut z: f64; - let sign: u32 = 0x80000000; + let sign: Wrapping = Wrapping(0x80000000); let mut ix0: i32; let mut s0: i32; let mut q: i32; let mut m: i32; let mut t: i32; let mut i: i32; - let mut r: u32; - let mut t1: u32; - let mut s1: u32; - let mut ix1: u32; - let mut q1: u32; + let mut r: Wrapping; + let mut t1: Wrapping; + let mut s1: Wrapping; + let mut ix1: Wrapping; + let mut q1: Wrapping; ix0 = (x.to_bits() >> 32) as i32; - ix1 = x.to_bits() as u32; + ix1 = Wrapping(x.to_bits() as u32); /* take care of Inf and NaN */ if (ix0 & 0x7ff00000) == 0x7ff00000 { @@ -118,7 +119,7 @@ pub fn sqrt(x: f64) -> f64 { } /* take care of zero */ if ix0 <= 0 { - if ((ix0 & !(sign as i32)) | ix1 as i32) == 0 { + if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { return x; /* sqrt(+-0) = +-0 */ } if ix0 < 0 { @@ -131,7 +132,7 @@ pub fn sqrt(x: f64) -> f64 { /* subnormal x */ while ix0 == 0 { m -= 21; - ix0 |= (ix1 >> 11) as i32; + ix0 |= (ix1 >> 11).0 as i32; ix1 <<= 21; } i = 0; @@ -140,46 +141,46 @@ pub fn sqrt(x: f64) -> f64 { ix0 <<= 1; } m -= i - 1; - ix0 |= (ix1 >> (32 - i)) as i32; - ix1 <<= i; + ix0 |= (ix1 >> (32 - i) as usize).0 as i32; + ix1 = ix1 << i as usize; } m -= 1023; /* unbias exponent */ ix0 = (ix0 & 0x000fffff) | 0x00100000; if (m & 1) == 1 { /* odd m, double x to make it even */ - ix0 += ix0 + ((ix1 & sign) >> 31) as i32; + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; } m >>= 1; /* m = [m/2] */ /* generate sqrt(x) bit by bit */ - ix0 += ix0 + ((ix1 & sign) >> 31) as i32; + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; q = 0; /* [q,q1] = sqrt(x) */ - q1 = 0; + q1 = Wrapping(0); s0 = 0; - s1 = 0; - r = 0x00200000; /* r = moving bit from right to left */ + s1 = Wrapping(0); + r = Wrapping(0x00200000); /* r = moving bit from right to left */ - while r != 0 { - t = s0 + r as i32; + while r != Wrapping(0) { + t = s0 + r.0 as i32; if t <= ix0 { - s0 = t + r as i32; + s0 = t + r.0 as i32; ix0 -= t; - q += r as i32; + q += r.0 as i32; } - ix0 += ix0 + ((ix1 & sign) >> 31) as i32; + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; r >>= 1; } r = sign; - while r != 0 { + while r != Wrapping(0) { t1 = s1 + r; t = s0; if t < ix0 || (t == ix0 && t1 <= ix1) { s1 = t1 + r; - if (t1 & sign) == sign && (s1 & sign) == 0 { + if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { s0 += 1; } ix0 -= t; @@ -189,26 +190,26 @@ pub fn sqrt(x: f64) -> f64 { ix1 -= t1; q1 += r; } - ix0 += ix0 + ((ix1 & sign) >> 31) as i32; + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; r >>= 1; } /* use floating add to find out rounding direction */ - if (ix0 as u32 | ix1) != 0 { + if (ix0 as u32 | ix1.0) != 0 { z = 1.0 - TINY; /* raise inexact flag */ if z >= 1.0 { z = 1.0 + TINY; - if q1 == 0xffffffff { - q1 = 0; + if q1.0 == 0xffffffff { + q1 = Wrapping(0); q += 1; } else if z > 1.0 { - if q1 == 0xfffffffe { + if q1.0 == 0xfffffffe { q += 1; } - q1 += 2; + q1 += Wrapping(2); } else { - q1 += q1 & 1; + q1 += q1 & Wrapping(1); } } } @@ -218,5 +219,5 @@ pub fn sqrt(x: f64) -> f64 { ix1 |= sign; } ix0 += m << 20; - f64::from_bits((ix0 as u64) << 32 | ix1 as u64) + f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } -- cgit 1.4.1-3-g733a5 From 1cbbb87c89c91f5b6cb3acb694c405cd6f83fb32 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 12:12:47 -0700 Subject: Update contributing docs --- library/compiler-builtins/libm/CONTRIBUTING.md | 48 +++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index 680c40e80e7..a7e817e13ed 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -2,25 +2,25 @@ - Pick your favorite math function from the [issue tracker]. - Look for the C implementation of the function in the [MUSL source code][src]. -- Copy paste the C code into a Rust file in the `src/math` directory and adjust `src/math/mod.rs` - accordingly. Also, uncomment the corresponding trait method in `src/lib.rs`. -- Run `cargo watch check` and fix the compiler errors. -- Tweak the bottom of `test-generator/src/main.rs` to add your function to the test suite. -- If you can, run the full test suite locally (see the [testing](#testing) section below). If you - can't, no problem! Your PR will be fully tested automatically. Though you may still want to add - and run some unit tests. See the bottom of [`src/math/truncf.rs`] for an example of such tests; - you can run unit tests with the `cargo test --lib` command. -- Send us a pull request! Make sure to run `cargo fmt` on your code before sending the PR. Also - include "closes #42" in the PR description to close the corresponding issue. +- Copy paste the C code into a Rust file in the `src/math` directory and adjust + `src/math/mod.rs` accordingly. Also, uncomment the corresponding trait method + in `src/lib.rs`. +- Write some simple tests in your module (using `#[test]`) +- Run `cargo test` to make sure it works +- Run `cargo test --features musl-reference-tests` to compare your + implementation against musl's +- Send us a pull request! Make sure to run `cargo fmt` on your code before + sending the PR. Also include "closes #42" in the PR description to close the + corresponding issue. - :tada: -[issue tracker]: https://github.com/japaric/libm/issues +[issue tracker]: https://github.com/rust-lang-nursery/libm/issues [src]: https://git.musl-libc.org/cgit/musl/tree/src/math -[`src/math/truncf.rs`]: https://github.com/japaric/libm/blob/master/src/math/truncf.rs +[`src/math/truncf.rs`]: https://github.com/rust-lang-nursery/libm/blob/master/src/math/truncf.rs Check [PR #65] for an example. -[PR #65]: https://github.com/japaric/libm/pull/65 +[PR #65]: https://github.com/rust-lang-nursery/libm/pull/65 ## Tips and tricks @@ -78,18 +78,18 @@ let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 12 ## Testing -The test suite of this crate can only be run on x86_64 Linux systems using the following commands: +Normal tests can be executed with: -``` console -$ # The test suite depends on the `cross` tool so install it if you don't have it -$ cargo install cross - -$ # and the `cross` tool requires docker to be running -$ systemctl start docker +``` +cargo test +``` -$ # execute the test suite for the x86_64 target -$ TARGET=x86_64-unknown-linux-gnu bash ci/script.sh +If you'd like to run tests with randomized inputs that get compared against musl +itself, you'll need to be on a Linux system and then you can execute: -$ # execute the test suite for the ARMv7 target -$ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh ``` +cargo test --features musl-reference-tests +``` + +Note that you may need to pass `--release` to Cargo if there are errors related +to integer overflow. -- cgit 1.4.1-3-g733a5 From c981490c7565102a52a580cd20535c311cac7a85 Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Wed, 1 Aug 2018 12:59:20 -0400 Subject: Modify atan2 to use `wrapping_` ops --- library/compiler-builtins/libm/src/math/atan2.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index a702ec39fe6..37dad35e1a4 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -92,12 +92,12 @@ pub fn atan2(y: f64, x: f64) -> f64 { } } /* |y/x| > 0x1p64 */ - if ix + (64 << 20) < iy || iy == 0x7ff00000 { + if ix.wrapping_add(64 << 20) < iy || iy == 0x7ff00000 { return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; } /* z = atan(|y/x|) without spurious underflow */ - let z = if (m & 2 != 0) && iy + (64 << 20) < ix { + let z = if (m & 2 != 0) && iy.wrapping_add(64 << 20) < ix { /* |y/x| < 0x1p-64, x<0 */ 0.0 } else { -- cgit 1.4.1-3-g733a5 From f4c572727a3c4ac47709a25c5aef53832e06850a Mon Sep 17 00:00:00 2001 From: Igor null Date: Tue, 16 Oct 2018 10:26:39 +0300 Subject: fixed uint underflow in floorf for negative exponents --- library/compiler-builtins/libm/src/math/floorf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 8699be06026..7d631df02b3 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -12,7 +12,7 @@ pub fn floorf(x: f32) -> f32 { } } let mut ui = x.to_bits(); - let e = (((ui >> 23) & 0xff) - 0x7f) as i32; + let e = (((ui >> 23) as i32) & 0xff) - 0x7f; if e >= 23 { return x; -- cgit 1.4.1-3-g733a5 From 6ab6ca024e37b5f2dc446c78834d84e2b05732d4 Mon Sep 17 00:00:00 2001 From: Anna Bogus Date: Fri, 5 Oct 2018 07:37:23 +0200 Subject: fixed some clippy warnings --- library/compiler-builtins/libm/src/math/acos.rs | 6 +++--- library/compiler-builtins/libm/src/math/asin.rs | 8 ++++---- library/compiler-builtins/libm/src/math/atan.rs | 16 +++++++-------- library/compiler-builtins/libm/src/math/atan2.rs | 2 +- library/compiler-builtins/libm/src/math/atanf.rs | 16 +++++++-------- library/compiler-builtins/libm/src/math/ceil.rs | 2 +- library/compiler-builtins/libm/src/math/ceilf.rs | 2 +- library/compiler-builtins/libm/src/math/cosf.rs | 16 ++++++--------- library/compiler-builtins/libm/src/math/expo2.rs | 2 +- library/compiler-builtins/libm/src/math/fdim.rs | 8 +++----- library/compiler-builtins/libm/src/math/fdimf.rs | 8 +++----- library/compiler-builtins/libm/src/math/floor.rs | 2 +- library/compiler-builtins/libm/src/math/floorf.rs | 2 +- library/compiler-builtins/libm/src/math/fma.rs | 10 ++++----- library/compiler-builtins/libm/src/math/hypot.rs | 2 +- library/compiler-builtins/libm/src/math/log.rs | 2 +- library/compiler-builtins/libm/src/math/log10.rs | 2 +- library/compiler-builtins/libm/src/math/log10f.rs | 2 +- library/compiler-builtins/libm/src/math/log1p.rs | 2 +- library/compiler-builtins/libm/src/math/log1pf.rs | 2 +- library/compiler-builtins/libm/src/math/log2.rs | 2 +- library/compiler-builtins/libm/src/math/log2f.rs | 2 +- library/compiler-builtins/libm/src/math/pow.rs | 2 +- library/compiler-builtins/libm/src/math/powf.rs | 22 +++++++++----------- .../compiler-builtins/libm/src/math/rem_pio2.rs | 24 ++++++++++------------ library/compiler-builtins/libm/src/math/sinf.rs | 2 +- library/compiler-builtins/libm/src/math/sinh.rs | 2 +- 27 files changed, 76 insertions(+), 92 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/acos.rs b/library/compiler-builtins/libm/src/math/acos.rs index a0d1450e3a8..055888ffa61 100644 --- a/library/compiler-builtins/libm/src/math/acos.rs +++ b/library/compiler-builtins/libm/src/math/acos.rs @@ -52,7 +52,7 @@ const QS4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ fn r(z: f64) -> f64 { let p: f64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); let q: f64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); - return p / q; + p / q } #[inline] @@ -73,7 +73,7 @@ pub fn acos(x: f64) -> f64 { if ix >= 0x3ff00000 { let lx: u32 = x.to_bits() as u32; - if (ix - 0x3ff00000 | lx) == 0 { + if ((ix - 0x3ff00000) | lx) == 0 { /* acos(1)=0, acos(-1)=pi */ if (hx >> 31) != 0 { return 2. * PIO2_HI + x1p_120f; @@ -105,5 +105,5 @@ pub fn acos(x: f64) -> f64 { c = (z - df * df) / (s + df); w = r(z) * s + c; - return 2. * (df + w); + 2. * (df + w) } diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs index 85530083726..2aee72b2861 100644 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -59,7 +59,7 @@ const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ fn comp_r(z: f64) -> f64 { let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); - return p / q; + p / q } #[inline] @@ -77,7 +77,7 @@ pub fn asin(mut x: f64) -> f64 { if ix >= 0x3ff00000 { let lx: u32; lx = get_low_word(x); - if (ix - 0x3ff00000 | lx) == 0 { + if ((ix - 0x3ff00000) | lx) == 0 { /* asin(1) = +-pi/2 with inexact */ return x * PIO2_HI + f64::from_bits(0x3870000000000000); } else { @@ -109,8 +109,8 @@ pub fn asin(mut x: f64) -> f64 { x = 0.5 * PIO2_HI - (2.0 * s * r - (PIO2_LO - 2.0 * c) - (0.5 * PIO2_HI - 2.0 * f)); } if hx >> 31 != 0 { - return -x; + -x } else { - return x; + x } } diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index ad1d57c1fe7..94594080cb8 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -102,16 +102,14 @@ pub fn atan(x: f64) -> f64 { x = (x - 1.) / (x + 1.); 1 } + } else if ix < 0x40038000 { + /* |x| < 2.4375 */ + x = (x - 1.5) / (1. + 1.5 * x); + 2 } else { - if ix < 0x40038000 { - /* |x| < 2.4375 */ - x = (x - 1.5) / (1. + 1.5 * x); - 2 - } else { - /* 2.4375 <= |x| < 2^66 */ - x = -1. / x; - 3 - } + /* 2.4375 <= |x| < 2^66 */ + x = -1. / x; + 3 } }; diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index a702ec39fe6..5dc38099de5 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -53,7 +53,7 @@ pub fn atan2(y: f64, x: f64) -> f64 { let lx = x.to_bits() as u32; let mut iy = (y.to_bits() >> 32) as u32; let ly = y.to_bits() as u32; - if (ix - 0x3ff00000 | lx) == 0 { + if ((ix - 0x3ff00000) | lx) == 0 { /* x = 1.0 */ return atan(y); } diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index 5d9024022b9..89b0afd6fb0 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -80,16 +80,14 @@ pub fn atanf(mut x: f32) -> f32 { x = (x - 1.) / (x + 1.); 1 } + } else if ix < 0x401c0000 { + /* |x| < 2.4375 */ + x = (x - 1.5) / (1. + 1.5 * x); + 2 } else { - if ix < 0x401c0000 { - /* |x| < 2.4375 */ - x = (x - 1.5) / (1. + 1.5 * x); - 2 - } else { - /* 2.4375 <= |x| < 2**26 */ - x = -1. / x; - 3 - } + /* 2.4375 <= |x| < 2**26 */ + x = -1. / x; + 3 } }; /* end of argument reduction */ diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index c2b11e4e74d..d337db200bf 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -27,7 +27,7 @@ pub fn ceil(x: f64) -> f64 { x + TOINT - TOINT - x }; // special case because of non-nearest rounding modes - if e <= 0x3ff - 1 { + if e < 0x3ff { force_eval!(y); return if (u >> 63) != 0 { -0. } else { 1. }; } diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 5eb6a35a6ec..88f9ecc4434 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -35,5 +35,5 @@ pub fn ceilf(x: f32) -> f32 { return 1.0; } } - return f32::from_bits(ui); + f32::from_bits(ui) } diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index 615746a31f7..48d76c8ee0d 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -50,12 +50,10 @@ pub fn cosf(x: f32) -> f32 { if ix > 0x4016cbe3 { /* |x| ~> 3*pi/4 */ return -k_cosf(if sign { x64 + C2_PIO2 } else { x64 - C2_PIO2 }); + } else if sign { + return k_sinf(x64 + C1_PIO2); } else { - if sign { - return k_sinf(x64 + C1_PIO2); - } else { - return k_sinf(C1_PIO2 - x64); - } + return k_sinf(C1_PIO2 - x64); } } if ix <= 0x40e231d5 { @@ -63,12 +61,10 @@ pub fn cosf(x: f32) -> f32 { if ix > 0x40afeddf { /* |x| ~> 7*pi/4 */ return k_cosf(if sign { x64 + C4_PIO2 } else { x64 - C4_PIO2 }); + } else if sign { + return k_sinf(-x64 - C3_PIO2); } else { - if sign { - return k_sinf(-x64 - C3_PIO2); - } else { - return k_sinf(x64 - C3_PIO2); - } + return k_sinf(x64 - C3_PIO2); } } diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs index b5369fbbe56..9e60ca99422 100644 --- a/library/compiler-builtins/libm/src/math/expo2.rs +++ b/library/compiler-builtins/libm/src/math/expo2.rs @@ -11,5 +11,5 @@ pub fn expo2(x: f64) -> f64 { /* note that k is odd and scale*scale overflows */ let scale = combine_words(((0x3ff + K / 2) as u32) << 20, 0); /* exp(x - k ln2) * 2**(k-1) */ - return exp(x - kln2) * scale * scale; + exp(x - kln2) * scale * scale } diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index 32ae306e2ef..d9aca861158 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -7,11 +7,9 @@ pub fn fdim(x: f64, y: f64) -> f64 { x } else if y.is_nan() { y + } else if x > y { + x - y } else { - if x > y { - x - y - } else { - 0.0 - } + 0.0 } } diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index 7db01932626..bcda8ee94f9 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -7,11 +7,9 @@ pub fn fdimf(x: f32, y: f32) -> f32 { x } else if y.is_nan() { y + } else if x > y { + x - y } else { - if x > y { - x - y - } else { - 0.0 - } + 0.0 } } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index f5ac8006f0e..c705ae501a9 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -26,7 +26,7 @@ pub fn floor(x: f64) -> f64 { x + TOINT - TOINT - x }; /* special case because of non-nearest rounding modes */ - if e <= 0x3ff - 1 { + if e < 0x3ff { force_eval!(y); return if (ui >> 63) != 0 { -1. } else { 0. }; } diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 8699be06026..b02bae5962b 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -35,5 +35,5 @@ pub fn floorf(x: f32) -> f32 { return -1.0; } } - return f32::from_bits(ui); + f32::from_bits(ui) } diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index acf99a5d4e2..21c854cd00f 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -83,7 +83,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { if d > 0 { if d < 64 { zlo = nz.m << d; - zhi = nz.m >> 64 - d; + zhi = nz.m >> (64 - d); } else { zlo = 0; zhi = nz.m; @@ -91,7 +91,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { d -= 64; if d == 0 { } else if d < 64 { - rlo = rhi << 64 - d | rlo >> d | ((rlo << 64 - d) != 0) as u64; + rlo = rhi << (64 - d) | rlo >> d | ((rlo << (64 - d)) != 0) as u64; rhi = rhi >> d; } else { rlo = 1; @@ -104,7 +104,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { if d == 0 { zlo = nz.m; } else if d < 64 { - zlo = nz.m >> d | ((nz.m << 64 - d) != 0) as u64; + zlo = nz.m >> d | ((nz.m << (64 - d)) != 0) as u64; } else { zlo = 1; } @@ -136,7 +136,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { e += 64; d = rhi.leading_zeros() as i32 - 1; /* note: d > 0 */ - rhi = rhi << d | rlo >> 64 - d | ((rlo << d) != 0) as u64; + rhi = rhi << d | rlo >> (64 - d) | ((rlo << d) != 0) as u64; } else if rlo != 0 { d = rlo.leading_zeros() as i32 - 1; if d < 0 { @@ -191,7 +191,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { } else { /* only round once when scaled */ d = 10; - i = ((rhi >> d | ((rhi << 64 - d) != 0) as u64) << d) as i64; + i = ((rhi >> d | ((rhi << (64 - d)) != 0) as u64) << d) as i64; if sign != 0 { i = -i; } diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs index dee9bbf4240..e53baf53994 100644 --- a/library/compiler-builtins/libm/src/math/hypot.rs +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -72,5 +72,5 @@ pub fn hypot(mut x: f64, mut y: f64) -> f64 { } let (hx, lx) = sq(x); let (hy, ly) = sq(y); - return z * sqrt(ly + lx + hy + hx); + z * sqrt(ly + lx + hy + hx) } diff --git a/library/compiler-builtins/libm/src/math/log.rs b/library/compiler-builtins/libm/src/math/log.rs index 948065abf3b..4126e413b77 100644 --- a/library/compiler-builtins/libm/src/math/log.rs +++ b/library/compiler-builtins/libm/src/math/log.rs @@ -114,5 +114,5 @@ pub fn log(mut x: f64) -> f64 { let t2: f64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); let r: f64 = t2 + t1; let dk: f64 = k as f64; - return s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI; + s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI } diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs index 100618a0281..c99696040ab 100644 --- a/library/compiler-builtins/libm/src/math/log10.rs +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -114,5 +114,5 @@ pub fn log10(mut x: f64) -> f64 { val_lo += (y - w) + val_hi; val_hi = w; - return val_lo + val_hi; + val_lo + val_hi } diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs index 9cf89deb957..9845cda5d95 100644 --- a/library/compiler-builtins/libm/src/math/log10f.rs +++ b/library/compiler-builtins/libm/src/math/log10f.rs @@ -88,5 +88,5 @@ pub fn log10f(mut x: f32) -> f32 { hi = f32::from_bits(ui); lo = f - hi - hfsq + s * (hfsq + r); dk = k as f32; - return dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI; + dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI } diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index fb35e90db14..cd7045ac97e 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -140,5 +140,5 @@ pub fn log1p(x: f64) -> f64 { t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); r = t2 + t1; dk = k as f64; - return s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI; + s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI } diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index 9fc399d956e..8e9651357d1 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -95,5 +95,5 @@ pub fn log1pf(x: f32) -> f32 { r = t2 + t1; hfsq = 0.5 * f * f; dk = k as f32; - return s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI; + s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI } diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index b513928ccb1..a3d43e55c2b 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -103,5 +103,5 @@ pub fn log2(mut x: f64) -> f64 { val_lo += (y - w) + val_hi; val_hi = w; - return val_lo + val_hi; + val_lo + val_hi } diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs index 07a00dc3dae..53a37e50337 100644 --- a/library/compiler-builtins/libm/src/math/log2f.rs +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -84,5 +84,5 @@ pub fn log2f(mut x: f32) -> f32 { ui &= 0xfffff000; hi = f32::from_bits(ui); lo = f - hi - hfsq + s * (hfsq + r); - return (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as f32; + (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as f32 } diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index b5b0407efa1..dca70f99b61 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -406,5 +406,5 @@ pub fn pow(x: f64, y: f64) -> f64 { z = with_set_high_word(z, j as u32); } - return s * z; + s * z } diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index 0a26573a3d1..befbf44db77 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -136,12 +136,11 @@ pub fn powf(x: f32, y: f32) -> f32 { return x * x; } - if hy == 0x3f000000 { - /* y is 0.5 */ - if hx >= 0 { - /* x >= +0 */ - return sqrtf(x); - } + if hy == 0x3f000000 + /* y is 0.5 */ + && hx >= 0 { + /* x >= +0 */ + return sqrtf(x); } ax = fabsf(x); @@ -296,11 +295,10 @@ pub fn powf(x: f32, y: f32) -> f32 { /* z < -150 */ // FIXME: check should be (uint32_t)j > 0xc3160000 return sn * TINY * TINY; /* underflow */ - } else if j as u32 == 0xc3160000 { - /* z == -150 */ - if p_l <= z - p_h { - return sn * TINY * TINY; /* underflow */ - } + } else if j as u32 == 0xc3160000 + /* z == -150 */ + && p_l <= z - p_h { + return sn * TINY * TINY; /* underflow */ } /* @@ -339,5 +337,5 @@ pub fn powf(x: f32, y: f32) -> f32 { } else { z = f32::from_bits(j as u32); } - return sn * z; + sn * z } diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 82faf5da97a..951dd08b429 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -78,7 +78,7 @@ pub fn rem_pio2(x: f64) -> (i32, f64, f64) { } } let y1 = (r - y0) - w; - return (n, y0, y1); + (n, y0, y1) } if ix <= 0x400f6a7a { @@ -100,18 +100,16 @@ pub fn rem_pio2(x: f64) -> (i32, f64, f64) { let y1 = (z - y0) + PIO2_1T; return (-1, y0, y1); } + } else if sign == 0 { + let z = x - 2.0 * PIO2_1; + let y0 = z - 2.0 * PIO2_1T; + let y1 = (z - y0) - 2.0 * PIO2_1T; + return (2, y0, y1); } else { - if sign == 0 { - let z = x - 2.0 * PIO2_1; - let y0 = z - 2.0 * PIO2_1T; - let y1 = (z - y0) - 2.0 * PIO2_1T; - return (2, y0, y1); - } else { - let z = x + 2.0 * PIO2_1; - let y0 = z + 2.0 * PIO2_1T; - let y1 = (z - y0) + 2.0 * PIO2_1T; - return (-2, y0, y1); - } + let z = x + 2.0 * PIO2_1; + let y0 = z + 2.0 * PIO2_1T; + let y1 = (z - y0) + 2.0 * PIO2_1T; + return (-2, y0, y1); } } if ix <= 0x401c463b { @@ -185,5 +183,5 @@ pub fn rem_pio2(x: f64) -> (i32, f64, f64) { if sign != 0 { return (-n, -ty[0], -ty[1]); } - return (n, ty[0], ty[1]); + (n, ty[0], ty[1]) } diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs index b8fc8d6f4be..0c31099edd2 100644 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -88,7 +88,7 @@ pub fn sinf(x: f32) -> f32 { match n & 3 { 0 => k_sinf(y), 1 => k_cosf(y), - 2 => return k_sinf(-y), + 2 => k_sinf(-y), _ => -k_cosf(y), } } diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs index 25ff3daaccb..d36de66c1c0 100644 --- a/library/compiler-builtins/libm/src/math/sinh.rs +++ b/library/compiler-builtins/libm/src/math/sinh.rs @@ -46,5 +46,5 @@ pub fn sinh(x: f64) -> f64 { /* |x| > log(DBL_MAX) or nan */ /* note: the result is stored to handle overflow */ t = 2.0 * h * expo2(absx); - return t; + t } -- cgit 1.4.1-3-g733a5 From a7ca98487e32cc83fb78baed6539475a3a0379a6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 12:21:55 -0700 Subject: Add bindings for ldexp/ldexpf Should help in fixing wasmerio/wasmer#407 --- library/compiler-builtins/libm/src/math/ldexp.rs | 5 +++++ library/compiler-builtins/libm/src/math/ldexpf.rs | 5 +++++ library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ 3 files changed, 14 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/ldexp.rs create mode 100644 library/compiler-builtins/libm/src/math/ldexpf.rs diff --git a/library/compiler-builtins/libm/src/math/ldexp.rs b/library/compiler-builtins/libm/src/math/ldexp.rs new file mode 100644 index 00000000000..780ddfc1165 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ldexp.rs @@ -0,0 +1,5 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexp(x: f64, n: i32) -> f64 { + super::scalbn(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/ldexpf.rs b/library/compiler-builtins/libm/src/math/ldexpf.rs new file mode 100644 index 00000000000..70935a0024e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ldexpf.rs @@ -0,0 +1,5 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf(x: f32, n: i32) -> f32 { + super::scalbnf(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e51b1511dfc..be0918ffdfa 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -104,6 +104,8 @@ mod fmod; mod fmodf; mod hypot; mod hypotf; +mod ldexp; +mod ldexpf; mod log; mod log10; mod log10f; @@ -166,6 +168,8 @@ pub use self::fmod::fmod; pub use self::fmodf::fmodf; pub use self::hypot::hypot; pub use self::hypotf::hypotf; +pub use self::ldexp::ldexp; +pub use self::ldexpf::ldexpf; pub use self::log::log; pub use self::log10::log10; pub use self::log10f::log10f; -- cgit 1.4.1-3-g733a5 From ef597e0e8f999f278ae939368bb8e7dc91da3f0d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 12:27:57 -0700 Subject: Update some URLs --- library/compiler-builtins/libm/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 568a049f0c5..3df5b65ea38 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -12,9 +12,9 @@ The short term goal of this library is to [enable math support (e.g. `sin`, `ata `wasm32-unknown-unknown` target][wasm] (cf. [rust-lang-nursery/compiler-builtins][pr]). The longer term goal is to enable [math support in the `core` crate][core]. -[wasm]: https://github.com/japaric/libm/milestone/1 +[wasm]: https://github.com/rust-lang-nursery/libm/milestone/1 [pr]: https://github.com/rust-lang-nursery/compiler-builtins/pull/248 -[core]: https://github.com/japaric/libm/milestone/2 +[core]: https://github.com/rust-lang-nursery/libm/milestone/2 ## Already usable -- cgit 1.4.1-3-g733a5 From dc3eebd0b7e04a73d7f255db7daa1918d717c249 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 12:34:05 -0700 Subject: Add a test that overflow does not happen --- library/compiler-builtins/libm/src/math/floorf.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 7d631df02b3..8a63874ebd1 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -37,3 +37,11 @@ pub fn floorf(x: f32) -> f32 { } return f32::from_bits(ui); } + +#[cfg(test)] +mod tests { + #[test] + fn no_overflow() { + assert_eq!(super::floorf(0.5), 0.0); + } +} -- cgit 1.4.1-3-g733a5 From 01d0e3eed8caadef805fd15d9dceb0d44039b712 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 12:36:37 -0700 Subject: Run `cargo fmt` --- library/compiler-builtins/libm/src/math/powf.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index befbf44db77..015bade86c9 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -136,9 +136,10 @@ pub fn powf(x: f32, y: f32) -> f32 { return x * x; } - if hy == 0x3f000000 + if hy == 0x3f000000 /* y is 0.5 */ - && hx >= 0 { + && hx >= 0 + { /* x >= +0 */ return sqrtf(x); } @@ -295,9 +296,10 @@ pub fn powf(x: f32, y: f32) -> f32 { /* z < -150 */ // FIXME: check should be (uint32_t)j > 0xc3160000 return sn * TINY * TINY; /* underflow */ - } else if j as u32 == 0xc3160000 + } else if j as u32 == 0xc3160000 /* z == -150 */ - && p_l <= z - p_h { + && p_l <= z - p_h + { return sn * TINY * TINY; /* underflow */ } -- cgit 1.4.1-3-g733a5 From 1701e71ed63312e72f15c04b42b152b242b0d1e6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 12:40:39 -0700 Subject: Include `ldexp*` intrinsics on the wasm target Looks like LLVM optimizes programs like: fn foo(a: u8) -> f32 { 2.0f32.powf(a as f32) } to actually invoking `ldexpf`, so let's be sure to include bindings so there's not undefined symbols. --- library/compiler-builtins/libm | 2 +- library/compiler-builtins/src/math.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 3559e703795..0ae442888c7 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 3559e703795d33e84a91da2a35f2f3baac47e872 +Subproject commit 0ae442888c7af72c0a335edd43dbbd74c751f119 diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index b6195553916..1893f1c166b 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -71,6 +71,8 @@ no_mangle! { fn sinhf(n: f32) -> f32; fn tanf(n: f32) -> f32; fn tanhf(n: f32) -> f32; + fn ldexp(f: f64, n: i32) -> f64; + fn ldexpf(f: f32, n: i32) -> f32; } #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] -- cgit 1.4.1-3-g733a5 From 98f4618c9ad71df908472b2f34fa567ef17353da Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 12:47:51 -0700 Subject: Revert "Use the Rust implementation of udivsi3 on ARM" This reverts commit 681aaa914dea7cae8252c33023604ce6c91808bd. --- library/compiler-builtins/build.rs | 17 ++++------------- library/compiler-builtins/ci/run-docker.sh | 1 + library/compiler-builtins/src/int/sdiv.rs | 1 + library/compiler-builtins/src/int/udiv.rs | 3 +++ 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 835b423cd79..27dac602647 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -289,6 +289,7 @@ mod c { "arm/clzdi2.S", "arm/clzsi2.S", "arm/divmodsi4.S", + "arm/divsi3.S", "arm/modsi3.S", "arm/switch16.S", "arm/switch32.S", @@ -296,20 +297,8 @@ mod c { "arm/switchu8.S", "arm/sync_synchronize.S", "arm/udivmodsi4.S", + "arm/udivsi3.S", "arm/umodsi3.S", - - // Exclude these two files for now even though we haven't - // translated their implementation into Rust yet (#173). - // They appear... buggy? The `udivsi3` implementation was - // the one that seemed buggy, but the `divsi3` file - // references a symbol from `udivsi3` so we compile them - // both with the Rust versions. - // - // Note that if these are added back they should be removed - // from thumbv6m below. - // - // "arm/divsi3.S", - // "arm/udivsi3.S", ], ); @@ -427,12 +416,14 @@ mod c { "clzdi2", "clzsi2", "divmodsi4", + "divsi3", "modsi3", "switch16", "switch32", "switch8", "switchu8", "udivmodsi4", + "udivsi3", "umodsi3", ], ); diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 5c2e065ccef..bed84ed81f6 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -24,6 +24,7 @@ run() { -v `pwd`:/checkout:ro \ -v `rustc --print sysroot`:/rust:ro \ -w /checkout \ + --init \ $target \ sh -c "HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index a2e8aa96f90..d7ae71ab293 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -57,6 +57,7 @@ impl Divmod for i32 {} impl Divmod for i64 {} intrinsics! { + #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] #[arm_aeabi_alias = __aeabi_idiv] pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { a.div(b) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index d873559bdd8..7b7f5b44dfa 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -152,6 +152,9 @@ macro_rules! udivmod_inner { } intrinsics! { + #[use_c_shim_if(all(target_arch = "arm", + not(target_os = "ios"), + not(thumbv6m)))] #[arm_aeabi_alias = __aeabi_uidiv] /// Returns `n / d` pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { -- cgit 1.4.1-3-g733a5 From 0899a164edf8aa04295c9c6002bdf9e394c4e412 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 13:35:50 -0700 Subject: Fix duplicate symbol __clzsi2 Looks like our tests weren't quite testing compiler-builtins when it was compiled with unmangled symbols, so update the tests to catch this and then fix the compilation of the `__clzsi2` intrinsic to use the C version if it's compiled. --- library/compiler-builtins/ci/run.sh | 9 +++++++++ library/compiler-builtins/src/int/mod.rs | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 589553adbf2..27e2de22f70 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -42,6 +42,10 @@ else $run --release $run --features c $run --features c --release + cargo build --target $1 + cargo build --target $1 --release + cargo build --target $1 --features c + cargo build --target $1 --release --features c fi PREFIX=$(echo $1 | sed -e 's/unknown-//')- @@ -68,6 +72,10 @@ fi # Look out for duplicated symbols when we include the compiler-rt (C) implementation for rlib in $(echo $path); do set +x + echo "================================================================" + echo checking $rlib for duplicate symbols + echo "================================================================" + stdout=$($PREFIX$NM -g --defined-only $rlib 2>&1) # NOTE On i586, It's normal that the get_pc_thunk symbol appears several @@ -86,6 +94,7 @@ for rlib in $(echo $path); do if test $? = 0; then exit 1 fi + set -ex done diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 52a4227a09b..07f72f84e71 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -302,6 +302,7 @@ impl_wide_int!(u32, u64, 32); impl_wide_int!(u64, u128, 64); intrinsics! { + #[use_c_shim_if(/* always if C compilation is enabled */)] #[cfg(any( target_pointer_width = "16", target_pointer_width = "32", @@ -310,7 +311,7 @@ intrinsics! { pub extern "C" fn __clzsi2(x: usize) -> usize { // TODO: const this? Would require const-if // Note(Lokathor): the `intrinsics!` macro can't process mut inputs - let mut x = x; + let mut x = x; let mut y: usize; let mut n: usize = { #[cfg(target_pointer_width = "64")] -- cgit 1.4.1-3-g733a5 From 21513cdcc238f6e66cc83606057116dbcbc61a46 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 13:44:20 -0700 Subject: Enable historically segfaulting tests on MIPS They seem to be passing locally so let's see what CI has to say. Closes #137 --- library/compiler-builtins/testcrate/build.rs | 104 +++++++++++++-------------- 1 file changed, 49 insertions(+), 55 deletions(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index d862e0d0ffb..17ae3ef1819 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -594,14 +594,12 @@ fn main() { }"); gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_mul(b.0)), "builtins::int::mul::__multi3(a, b)"); - if !target_arch_mips { // FIXME(#137) - gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_mul(b.0)), - "{ - let mut o = 2; - let c = builtins::int::mul::__muloti4(a, b, &mut o); - (c, match o { 0 => false, 1 => true, _ => panic!() }) - }"); - } + gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_mul(b.0)), + "{ + let mut o = 2; + let c = builtins::int::mul::__muloti4(a, b, &mut o); + (c, match o { 0 => false, 1 => true, _ => panic!() }) + }"); // int/sdiv.rs gen(|(a, b): (MyI64, MyI64)| { @@ -658,24 +656,22 @@ fn main() { } }, "builtins::int::sdiv::__moddi3(a, b)"); - if !target_arch_mips { // FIXME(#137) - gen(|(a, b): (MyI128, MyI128)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::sdiv::__divti3(a, b)"); - gen(|(a, b): (MyI128, MyI128)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::sdiv::__modti3(a, b)"); - } + gen(|(a, b): (MyI128, MyI128)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "builtins::int::sdiv::__divti3(a, b)"); + gen(|(a, b): (MyI128, MyI128)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "builtins::int::sdiv::__modti3(a, b)"); // int/shift.rs gen(|(a, b): (MyU64, MyU32)| Some(a.0 << (b.0 % 64)), @@ -746,35 +742,33 @@ fn main() { } }, "builtins::int::udiv::__umoddi3(a, b)"); - if !target_arch_mips { // FIXME(#137) - gen(|(a, b): (MyU128, MyU128)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::udiv::__udivti3(a, b)"); - gen(|(a, b): (MyU128, MyU128)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::udiv::__umodti3(a, b)"); - gen(|(a, b): (MyU128, MyU128)| { - if b.0 == 0 { - None - } else { - Some((a.0 / b.0, a.0 % b.0)) - } - }, - "{ - let mut r = 0; - (builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) - }"); - } + gen(|(a, b): (MyU128, MyU128)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "builtins::int::udiv::__udivti3(a, b)"); + gen(|(a, b): (MyU128, MyU128)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "builtins::int::udiv::__umodti3(a, b)"); + gen(|(a, b): (MyU128, MyU128)| { + if b.0 == 0 { + None + } else { + Some((a.0 / b.0, a.0 % b.0)) + } + }, + "{ + let mut r = 0; + (builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) + }"); } macro_rules! gen_float { -- cgit 1.4.1-3-g733a5 From de566fec8cdd22d9ab8c0c36e26bd31d6c8fd146 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 14:22:19 -0700 Subject: Fix duplicate floatdisf symbol on Windows MSVC --- library/compiler-builtins/src/float/conv.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 3171e45096c..8d3e5fc6de2 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -83,6 +83,7 @@ intrinsics! { #[use_c_shim_if(any( all(target_arch = "x86", not(target_env = "msvc")), all(target_arch = "x86_64", not(windows)), + all(target_arch = "x86_64", target_env = "msvc"), ))] #[arm_aeabi_alias = __aeabi_l2f] pub extern "C" fn __floatdisf(i: i64) -> f32 { -- cgit 1.4.1-3-g733a5 From 3a8b5e0244d71bf80da2f824b0ab4349fb232d2e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 15:18:37 -0700 Subject: Bump to 0.1.12 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index fdca20143b9..a05825a6122 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.11" +version = "0.1.12" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From fcdb5a8c13ffd7ca19953ca0de0816d90db27510 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 7 May 2019 07:16:24 +0300 Subject: tests, fixes, format --- library/compiler-builtins/libm/build.rs | 22 +- library/compiler-builtins/libm/ci/run-docker.sh | 0 library/compiler-builtins/libm/ci/run.sh | 0 library/compiler-builtins/libm/src/math/acosh.rs | 44 +- library/compiler-builtins/libm/src/math/acoshf.rs | 42 +- library/compiler-builtins/libm/src/math/asinef.rs | 188 +++-- library/compiler-builtins/libm/src/math/asinh.rs | 70 +- library/compiler-builtins/libm/src/math/asinhf.rs | 68 +- library/compiler-builtins/libm/src/math/atan2.rs | 2 +- library/compiler-builtins/libm/src/math/atanh.rs | 65 +- library/compiler-builtins/libm/src/math/atanhf.rs | 64 +- library/compiler-builtins/libm/src/math/ceilf.rs | 2 +- .../compiler-builtins/libm/src/math/copysign.rs | 14 +- .../compiler-builtins/libm/src/math/copysignf.rs | 14 +- library/compiler-builtins/libm/src/math/erf.rs | 603 +++++++-------- library/compiler-builtins/libm/src/math/erff.rs | 428 +++++------ library/compiler-builtins/libm/src/math/exp10.rs | 45 +- library/compiler-builtins/libm/src/math/exp10f.rs | 43 +- library/compiler-builtins/libm/src/math/fma.rs | 4 +- library/compiler-builtins/libm/src/math/fmod.rs | 4 +- library/compiler-builtins/libm/src/math/fmodf.rs | 4 +- library/compiler-builtins/libm/src/math/frexp.rs | 40 +- library/compiler-builtins/libm/src/math/frexpf.rs | 42 +- library/compiler-builtins/libm/src/math/ilogb.rs | 62 +- library/compiler-builtins/libm/src/math/ilogbf.rs | 62 +- library/compiler-builtins/libm/src/math/j0.rs | 814 +++++++++++---------- library/compiler-builtins/libm/src/math/j0f.rs | 689 ++++++++--------- library/compiler-builtins/libm/src/math/j1.rs | 801 ++++++++++---------- library/compiler-builtins/libm/src/math/j1f.rs | 689 ++++++++--------- library/compiler-builtins/libm/src/math/jn.rs | 681 ++++++++--------- library/compiler-builtins/libm/src/math/jnf.rs | 514 ++++++------- library/compiler-builtins/libm/src/math/lgamma.rs | 632 ++++++++-------- library/compiler-builtins/libm/src/math/lgammaf.rs | 502 +++++++------ library/compiler-builtins/libm/src/math/mod.rs | 10 +- library/compiler-builtins/libm/src/math/modf.rs | 67 +- library/compiler-builtins/libm/src/math/modff.rs | 65 +- library/compiler-builtins/libm/src/math/remquo.rs | 195 +++-- library/compiler-builtins/libm/src/math/remquof.rs | 193 +++-- library/compiler-builtins/libm/src/math/sincos.rs | 119 ++- library/compiler-builtins/libm/src/math/sincosf.rs | 245 ++++--- library/compiler-builtins/libm/src/math/tgamma.rs | 386 +++++----- library/compiler-builtins/libm/src/math/tgammaf.rs | 10 +- 42 files changed, 4371 insertions(+), 4173 deletions(-) mode change 100755 => 100644 library/compiler-builtins/libm/ci/run-docker.sh mode change 100755 => 100644 library/compiler-builtins/libm/ci/run.sh diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 23e1178e360..29521ab193c 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -41,6 +41,19 @@ mod musl_reference_tests { "rem_pio2.rs", "rem_pio2_large.rs", "rem_pio2f.rs", + "remquo.rs", + "remquof.rs", + "lgamma.rs", // lgamma passed, lgamma_r has more than 1 result + "lgammaf.rs", // lgammaf passed, lgammaf_r has more than 1 result + "frexp.rs", // more than 1 result + "frexpf.rs", // more than 1 result + "sincos.rs", // more than 1 result + "sincosf.rs", // more than 1 result + "modf.rs", // more than 1 result + "modff.rs", // more than 1 result + "asinef.rs", // not exists + "jn.rs", // passed, but very slow + "jnf.rs", // passed, but very slow ]; struct Function { @@ -78,12 +91,9 @@ mod musl_reference_tests { let contents = fs::read_to_string(file).unwrap(); let mut functions = contents.lines().filter(|f| f.starts_with("pub fn")); - let function_to_test = functions.next().unwrap(); - if functions.next().is_some() { - panic!("more than one function in"); + while let Some(function_to_test) = functions.next() { + math.push(parse(function_to_test)); } - - math.push(parse(function_to_test)); } // Generate a bunch of random inputs for each function. This will @@ -330,7 +340,7 @@ mod musl_reference_tests { src.push_str(match function.ret { Ty::F32 => "if _eqf(output, f32::from_bits(*expected as u32)).is_ok() { continue }", Ty::F64 => "if _eq(output, f64::from_bits(*expected as u64)).is_ok() { continue }", - Ty::I32 => "if output as i64 == expected { continue }", + Ty::I32 => "if output as i64 == *expected { continue }", Ty::Bool => unreachable!(), }); diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh old mode 100755 new mode 100644 diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh old mode 100755 new mode 100644 diff --git a/library/compiler-builtins/libm/src/math/acosh.rs b/library/compiler-builtins/libm/src/math/acosh.rs index 3494e3405e7..95dc57d811c 100644 --- a/library/compiler-builtins/libm/src/math/acosh.rs +++ b/library/compiler-builtins/libm/src/math/acosh.rs @@ -1,22 +1,22 @@ -use super::{log, log1p, sqrt}; - -const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ - -/* acosh(x) = log(x + sqrt(x*x-1)) */ -pub fn acosh(x: f64) -> f64 { - let u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - - /* x < 1 domain error is handled in the called functions */ - - if e < 0x3ff + 1 { - /* |x| < 2, up to 2ulp error in [1,1.125] */ - return log1p(x-1.0+sqrt((x-1.0)*(x-1.0)+2.0*(x-1.0))); - } - if e < 0x3ff + 26 { - /* |x| < 0x1p26 */ - return log(2.0*x-1.0/(x+sqrt(x*x-1.0))); - } - /* |x| >= 0x1p26 or nan */ - return log(x) + LN2; -} +use super::{log, log1p, sqrt}; + +const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +pub fn acosh(x: f64) -> f64 { + let u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + + /* x < 1 domain error is handled in the called functions */ + + if e < 0x3ff + 1 { + /* |x| < 2, up to 2ulp error in [1,1.125] */ + return log1p(x - 1.0 + sqrt((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); + } + if e < 0x3ff + 26 { + /* |x| < 0x1p26 */ + return log(2.0 * x - 1.0 / (x + sqrt(x * x - 1.0))); + } + /* |x| >= 0x1p26 or nan */ + return log(x) + LN2; +} diff --git a/library/compiler-builtins/libm/src/math/acoshf.rs b/library/compiler-builtins/libm/src/math/acoshf.rs index 1e298a9b3d5..f50a00324b1 100644 --- a/library/compiler-builtins/libm/src/math/acoshf.rs +++ b/library/compiler-builtins/libm/src/math/acoshf.rs @@ -1,21 +1,21 @@ -use super::{log1pf, logf, sqrtf}; - -const LN2: f32 = 0.693147180559945309417232121458176568; - -/* acosh(x) = log(x + sqrt(x*x-1)) */ -pub fn acoshf(x: f32) -> f32 { - let u = x.to_bits(); - let a = u & 0x7fffffff; - - if a < 0x3f800000+(1<<23) { - /* |x| < 2, invalid if x < 1 or nan */ - /* up to 2ulp error in [1,1.125] */ - return log1pf(x-1.0 + sqrtf((x-1.0)*(x-1.0)+2.0*(x-1.0))); - } - if a < 0x3f800000+(12<<23) { - /* |x| < 0x1p12 */ - return logf(2.0*x - 1.0/(x+sqrtf(x*x-1.0))); - } - /* x >= 0x1p12 */ - return logf(x) + LN2; -} +use super::{log1pf, logf, sqrtf}; + +const LN2: f32 = 0.693147180559945309417232121458176568; + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +pub fn acoshf(x: f32) -> f32 { + let u = x.to_bits(); + let a = u & 0x7fffffff; + + if a < 0x3f800000 + (1 << 23) { + /* |x| < 2, invalid if x < 1 or nan */ + /* up to 2ulp error in [1,1.125] */ + return log1pf(x - 1.0 + sqrtf((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); + } + if a < 0x3f800000 + (12 << 23) { + /* |x| < 0x1p12 */ + return logf(2.0 * x - 1.0 / (x + sqrtf(x * x - 1.0))); + } + /* x >= 0x1p12 */ + return logf(x) + LN2; +} diff --git a/library/compiler-builtins/libm/src/math/asinef.rs b/library/compiler-builtins/libm/src/math/asinef.rs index d2cd826999d..cd1428bc232 100644 --- a/library/compiler-builtins/libm/src/math/asinef.rs +++ b/library/compiler-builtins/libm/src/math/asinef.rs @@ -1,95 +1,93 @@ -/* @(#)z_asinef.c 1.0 98/08/13 */ -/****************************************************************** - * The following routines are coded directly from the algorithms - * and coefficients given in "Software Manual for the Elementary - * Functions" by William J. Cody, Jr. and William Waite, Prentice - * Hall, 1980. - ******************************************************************/ -/****************************************************************** - * Arcsine - * - * Input: - * x - floating point value - * acosine - indicates acos calculation - * - * Output: - * Arcsine of x. - * - * Description: - * This routine calculates arcsine / arccosine. - * - *****************************************************************/ - -use super::{fabsf, sqrtf}; - -const P: [f32; 2] = [ 0.933935835, -0.504400557 ]; -const Q: [f32; 2] = [ 0.560363004e+1, -0.554846723e+1 ]; -const A: [f32; 2] = [ 0.0, 0.785398163 ]; -const B: [f32; 2] = [ 1.570796326, 0.785398163 ]; -const Z_ROOTEPS_F: f32 = 1.7263349182589107e-4; - -pub fn asinef(x: f32, acosine: usize) -> f32 -{ - let flag: usize; - let i: usize; - let mut branch: bool = false; - let g: f32; - let mut res: f32 = 0.0; - let mut y: f32; - - /* Check for special values. */ - //i = numtestf (x); - if x.is_nan() || x.is_infinite() { - force_eval!(x); - return x; - } - - y = fabsf(x); - flag = acosine; - - if y > 0.5 { - i = 1 - flag; - - /* Check for range error. */ - if y > 1.0 { - return 0.0 / 0.0; - } - - g = (1.0 - y) / 2.0; - y = -2.0 * sqrtf(g); - branch = true; - } else { - i = flag; - if y < Z_ROOTEPS_F { - res = y; - g = 0.0; // pleasing the uninitialized variable - } else { - g = y * y; - } - } - - if y >= Z_ROOTEPS_F || branch { - /* Calculate the Taylor series. */ - let p = (P[1] * g + P[0]) * g; - let q = (g + Q[1]) * g + Q[0]; - let r = p / q; - - res = y + y * r; - } - - /* Calculate asine or acose. */ - if flag == 0 { - res = (A[i] + res) + A[i]; - if x < 0.0 { - res = -res; - } - } else { - if x < 0.0 { - res = (B[i] + res) + B[i]; - } else { - res = (A[i] - res) + A[i]; - } - } - - return res; -} +/* @(#)z_asinef.c 1.0 98/08/13 */ +/****************************************************************** + * The following routines are coded directly from the algorithms + * and coefficients given in "Software Manual for the Elementary + * Functions" by William J. Cody, Jr. and William Waite, Prentice + * Hall, 1980. + ******************************************************************/ +/****************************************************************** + * Arcsine + * + * Input: + * x - floating point value + * acosine - indicates acos calculation + * + * Output: + * Arcsine of x. + * + * Description: + * This routine calculates arcsine / arccosine. + * + *****************************************************************/ + +use super::{fabsf, sqrtf}; + +const P: [f32; 2] = [ 0.933935835, -0.504400557 ]; +const Q: [f32; 2] = [ 0.560363004e+1, -0.554846723e+1 ]; +const A: [f32; 2] = [ 0.0, 0.785398163 ]; +const B: [f32; 2] = [ 1.570796326, 0.785398163 ]; +const Z_ROOTEPS_F: f32 = 1.7263349182589107e-4; + +pub fn asinef(x: f32, acosine: bool) -> f32 { + let i: usize; + let mut branch: bool = false; + let g: f32; + let mut res: f32 = 0.0; + let mut y: f32; + + /* Check for special values. */ + //i = numtestf (x); + if x.is_nan() || x.is_infinite() { + force_eval!(x); + return x; + } + + y = fabsf(x); + let flag = acosine; + + if y > 0.5 { + i = (!flag) as usize; + + /* Check for range error. */ + if y > 1.0 { + return 0.0 / 0.0; + } + + g = (1.0 - y) / 2.0; + y = -2.0 * sqrtf(g); + branch = true; + } else { + i = flag; + if y < Z_ROOTEPS_F { + res = y; + g = 0.0; // pleasing the uninitialized variable + } else { + g = y * y; + } + } + + if y >= Z_ROOTEPS_F || branch { + /* Calculate the Taylor series. */ + let p = (P[1] * g + P[0]) * g; + let q = (g + Q[1]) * g + Q[0]; + let r = p / q; + + res = y + y * r; + } + + /* Calculate asine or acose. */ + if flag == 0 { + res = (A[i] + res) + A[i]; + if x < 0.0 { + res = -res; + } + } else { + if x < 0.0 { + res = (B[i] + res) + B[i]; + } else { + res = (A[i] - res) + A[i]; + } + } + + return res; +} diff --git a/library/compiler-builtins/libm/src/math/asinh.rs b/library/compiler-builtins/libm/src/math/asinh.rs index 09e894551f6..b29093b2347 100644 --- a/library/compiler-builtins/libm/src/math/asinh.rs +++ b/library/compiler-builtins/libm/src/math/asinh.rs @@ -1,35 +1,35 @@ -use super::{log, log1p, sqrt}; - -const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ - -/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ -pub fn asinh(mut x: f64) -> f64 { - let mut u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - let sign = (u >> 63) != 0; - - /* |x| */ - u &= (!0) >> 1; - x = f64::from_bits(u); - - if e >= 0x3ff + 26 { - /* |x| >= 0x1p26 or inf or nan */ - x = log(x) + LN2; - } else if e >= 0x3ff + 1 { - /* |x| >= 2 */ - x = log(2.0*x + 1.0/(sqrt(x*x+1.0)+x)); - } else if e >= 0x3ff - 26 { - /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ - x = log1p(x + x*x/(sqrt(x*x+1.0)+1.0)); - } else { - /* |x| < 0x1p-26, raise inexact if x != 0 */ - let x1p120 = f64::from_bits(0x4770000000000000); - force_eval!(x + x1p120); - } - - if sign { - -x - } else { - x - } -} +use super::{log, log1p, sqrt}; + +const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +pub fn asinh(mut x: f64) -> f64 { + let mut u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + let sign = (u >> 63) != 0; + + /* |x| */ + u &= (!0) >> 1; + x = f64::from_bits(u); + + if e >= 0x3ff + 26 { + /* |x| >= 0x1p26 or inf or nan */ + x = log(x) + LN2; + } else if e >= 0x3ff + 1 { + /* |x| >= 2 */ + x = log(2.0 * x + 1.0 / (sqrt(x * x + 1.0) + x)); + } else if e >= 0x3ff - 26 { + /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ + x = log1p(x + x * x / (sqrt(x * x + 1.0) + 1.0)); + } else { + /* |x| < 0x1p-26, raise inexact if x != 0 */ + let x1p120 = f64::from_bits(0x4770000000000000); + force_eval!(x + x1p120); + } + + if sign { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/src/math/asinhf.rs index 236916d83e8..9812433032b 100644 --- a/library/compiler-builtins/libm/src/math/asinhf.rs +++ b/library/compiler-builtins/libm/src/math/asinhf.rs @@ -1,34 +1,34 @@ -use super::{logf, log1pf, sqrtf}; - -const LN2: f32 = 0.693147180559945309417232121458176568; - -/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ -pub fn asinhf(mut x: f32) -> f32 { - let u = x.to_bits(); - let i = u & 0x7fffffff; - let sign = (u >> 31) != 0; - - /* |x| */ - x = f32::from_bits(i); - - if i >= 0x3f800000 + (12<<23) { - /* |x| >= 0x1p12 or inf or nan */ - x = logf(x) + LN2; - } else if i >= 0x3f800000 + (1<<23) { - /* |x| >= 2 */ - x = logf(2.0*x + 1.0/(sqrtf(x*x+1.0)+x)); - } else if i >= 0x3f800000 - (12<<23) { - /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ - x = log1pf(x + x*x/(sqrtf(x*x+1.0)+1.0)); - } else { - /* |x| < 0x1p-12, raise inexact if x!=0 */ - let x1p120 = f32::from_bits(0x7b800000); - force_eval!(x + x1p120); - } - - if sign { - -x - } else { - x - } -} +use super::{log1pf, logf, sqrtf}; + +const LN2: f32 = 0.693147180559945309417232121458176568; + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +pub fn asinhf(mut x: f32) -> f32 { + let u = x.to_bits(); + let i = u & 0x7fffffff; + let sign = (u >> 31) != 0; + + /* |x| */ + x = f32::from_bits(i); + + if i >= 0x3f800000 + (12 << 23) { + /* |x| >= 0x1p12 or inf or nan */ + x = logf(x) + LN2; + } else if i >= 0x3f800000 + (1 << 23) { + /* |x| >= 2 */ + x = logf(2.0 * x + 1.0 / (sqrtf(x * x + 1.0) + x)); + } else if i >= 0x3f800000 - (12 << 23) { + /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ + x = log1pf(x + x * x / (sqrtf(x * x + 1.0) + 1.0)); + } else { + /* |x| < 0x1p-12, raise inexact if x!=0 */ + let x1p120 = f32::from_bits(0x7b800000); + force_eval!(x + x1p120); + } + + if sign { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index 7ab636050f9..313bec4b907 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -53,7 +53,7 @@ pub fn atan2(y: f64, x: f64) -> f64 { let lx = x.to_bits() as u32; let mut iy = (y.to_bits() >> 32) as u32; let ly = y.to_bits() as u32; - if ((ix - 0x3ff00000) | lx) == 0 { + if ((ix.wrapping_sub(0x3ff00000)) | lx) == 0 { /* x = 1.0 */ return atan(y); } diff --git a/library/compiler-builtins/libm/src/math/atanh.rs b/library/compiler-builtins/libm/src/math/atanh.rs index ea444809c7d..2833715ab92 100644 --- a/library/compiler-builtins/libm/src/math/atanh.rs +++ b/library/compiler-builtins/libm/src/math/atanh.rs @@ -1,33 +1,32 @@ -use super::{log1p}; - -/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ -pub fn atanh(mut x: f64) -> f64 { - let mut u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - let sign = (u >> 63) != 0; - - /* |x| */ - u &= 0x7fffffff; - x = f64::from_bits(u); - - if e < 0x3ff - 1 { - if e < 0x3ff - 32 { - /* handle underflow */ - if e == 0 { - force_eval!(x as f32); - } - } else { - /* |x| < 0.5, up to 1.7ulp error */ - x = 0.5*log1p(2.0*x + 2.0*x*x/(1.0-x)); - } - } else { - /* avoid overflow */ - x = 0.5*log1p(2.0*(x/(1.0-x))); - } - - if sign { - -x - } else { - x - } -} +use super::log1p; + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +pub fn atanh(x: f64) -> f64 { + let u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + let sign = (u >> 63) != 0; + + /* |x| */ + let mut y = f64::from_bits(u & 0x7fff_ffff_ffff_ffff); + + if e < 0x3ff - 1 { + if e < 0x3ff - 32 { + /* handle underflow */ + if e == 0 { + force_eval!(y as f32); + } + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5 * log1p(2.0 * y + 2.0 * y * y / (1.0 - y)); + } + } else { + /* avoid overflow */ + y = 0.5 * log1p(2.0 * (y / (1.0 - y))); + } + + if sign { + -y + } else { + y + } +} diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs index 77d451bf27e..709a9555182 100644 --- a/library/compiler-builtins/libm/src/math/atanhf.rs +++ b/library/compiler-builtins/libm/src/math/atanhf.rs @@ -1,32 +1,32 @@ -use super::{log1pf}; - -/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ -pub fn atanhf(mut x: f32) -> f32 { - let mut u = x.to_bits(); - let sign = (u >> 31) != 0; - - /* |x| */ - u &= 0x7fffffff; - x = f32::from_bits(u); - - if u < 0x3f800000 - (1<<23) { - if u < 0x3f800000 - (32<<23) { - /* handle underflow */ - if u < (1<<23) { - force_eval!((x*x) as f32); - } - } else { - /* |x| < 0.5, up to 1.7ulp error */ - x = 0.5*log1pf(2.0*x + 2.0*x*x/(1.0-x)); - } - } else { - /* avoid overflow */ - x = 0.5*log1pf(2.0*(x/(1.0-x))); - } - - if sign { - -x - } else { - x - } -} +use super::log1pf; + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +pub fn atanhf(mut x: f32) -> f32 { + let mut u = x.to_bits(); + let sign = (u >> 31) != 0; + + /* |x| */ + u &= 0x7fffffff; + x = f32::from_bits(u); + + if u < 0x3f800000 - (1 << 23) { + if u < 0x3f800000 - (32 << 23) { + /* handle underflow */ + if u < (1 << 23) { + force_eval!((x * x) as f32); + } + } else { + /* |x| < 0.5, up to 1.7ulp error */ + x = 0.5 * log1pf(2.0 * x + 2.0 * x * x / (1.0 - x)); + } + } else { + /* avoid overflow */ + x = 0.5 * log1pf(2.0 * (x / (1.0 - x))); + } + + if sign { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 88f9ecc4434..0be53c5cf3c 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -12,7 +12,7 @@ pub fn ceilf(x: f32) -> f32 { } } let mut ui = x.to_bits(); - let e = (((ui >> 23) & 0xff) - 0x7f) as i32; + let e = (((ui >> 23) & 0xff).wrapping_sub(0x7f)) as i32; if e >= 23 { return x; diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs index 74b761e7468..9c5362a5a47 100644 --- a/library/compiler-builtins/libm/src/math/copysign.rs +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -1,7 +1,7 @@ -pub fn copysign(x: f64, y: f64) -> f64 { - let mut ux = x.to_bits(); - let uy = y.to_bits(); - ux &= (!0) >> 1; - ux |= uy & (1<<63); - f64::from_bits(ux) -} +pub fn copysign(x: f64, y: f64) -> f64 { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= (!0) >> 1; + ux |= uy & (1 << 63); + f64::from_bits(ux) +} diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs index a0a814bf6a1..b42fd39ad55 100644 --- a/library/compiler-builtins/libm/src/math/copysignf.rs +++ b/library/compiler-builtins/libm/src/math/copysignf.rs @@ -1,7 +1,7 @@ -pub fn copysignf(x: f32, y: f32) -> f32 { - let mut ux = x.to_bits(); - let uy = y.to_bits(); - ux &= 0x7fffffff; - ux |= uy & 0x80000000; - f32::from_bits(ux) -} +pub fn copysignf(x: f32, y: f32) -> f32 { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= 0x7fffffff; + ux |= uy & 0x80000000; + f32::from_bits(ux) +} diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs index b3ad2ce058f..d53a4c83cd5 100644 --- a/library/compiler-builtins/libm/src/math/erf.rs +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -1,297 +1,306 @@ -use super::{exp, fabs, get_high_word, with_set_low_word}; -/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* double erf(double x) - * double erfc(double x) - * x - * 2 |\ - * erf(x) = --------- | exp(-t*t)dt - * sqrt(pi) \| - * 0 - * - * erfc(x) = 1-erf(x) - * Note that - * erf(-x) = -erf(x) - * erfc(-x) = 2 - erfc(x) - * - * Method: - * 1. For |x| in [0, 0.84375] - * erf(x) = x + x*R(x^2) - * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] - * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] - * where R = P/Q where P is an odd poly of degree 8 and - * Q is an odd poly of degree 10. - * -57.90 - * | R - (erf(x)-x)/x | <= 2 - * - * - * Remark. The formula is derived by noting - * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) - * and that - * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 - * is close to one. The interval is chosen because the fix - * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is - * near 0.6174), and by some experiment, 0.84375 is chosen to - * guarantee the error is less than one ulp for erf. - * - * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and - * c = 0.84506291151 rounded to single (24 bits) - * erf(x) = sign(x) * (c + P1(s)/Q1(s)) - * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 - * 1+(c+P1(s)/Q1(s)) if x < 0 - * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 - * Remark: here we use the taylor series expansion at x=1. - * erf(1+s) = erf(1) + s*Poly(s) - * = 0.845.. + P1(s)/Q1(s) - * That is, we use rational approximation to approximate - * erf(1+s) - (c = (single)0.84506291151) - * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] - * where - * P1(s) = degree 6 poly in s - * Q1(s) = degree 6 poly in s - * - * 3. For x in [1.25,1/0.35(~2.857143)], - * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) - * erf(x) = 1 - erfc(x) - * where - * R1(z) = degree 7 poly in z, (z=1/x^2) - * S1(z) = degree 8 poly in z - * - * 4. For x in [1/0.35,28] - * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 - * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 - * erf(x) = sign(x) *(1 - tiny) (raise inexact) - * erfc(x) = tiny*tiny (raise underflow) if x > 0 - * = 2 - tiny if x<0 - * - * 7. Special case: - * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, - * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, - * erfc/erf(NaN) is NaN - */ - -const ERX: f64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ -/* - * Coefficients for approximation to erf on [0,0.84375] - */ -const EFX8: f64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ -const PP0: f64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ -const PP1: f64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ -const PP2: f64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */ -const PP3: f64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */ -const PP4: f64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */ -const QQ1: f64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */ -const QQ2: f64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ -const QQ3: f64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ -const QQ4: f64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ -const QQ5: f64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ -/* - * Coefficients for approximation to erf in [0.84375,1.25] - */ -const PA0: f64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ -const PA1: f64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ -const PA2: f64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ -const PA3: f64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */ -const PA4: f64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */ -const PA5: f64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */ -const PA6: f64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */ -const QA1: f64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */ -const QA2: f64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */ -const QA3: f64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ -const QA4: f64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ -const QA5: f64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ -const QA6: f64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ -/* - * Coefficients for approximation to erfc in [1.25,1/0.35] - */ -const RA0: f64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ -const RA1: f64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ -const RA2: f64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ -const RA3: f64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */ -const RA4: f64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */ -const RA5: f64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */ -const RA6: f64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */ -const RA7: f64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */ -const SA1: f64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */ -const SA2: f64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */ -const SA3: f64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */ -const SA4: f64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */ -const SA5: f64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ -const SA6: f64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ -const SA7: f64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ -const SA8: f64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ -/* - * Coefficients for approximation to erfc in [1/.35,28] - */ -const RB0: f64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ -const RB1: f64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ -const RB2: f64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ -const RB3: f64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */ -const RB4: f64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */ -const RB5: f64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */ -const RB6: f64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */ -const SB1: f64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */ -const SB2: f64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */ -const SB3: f64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */ -const SB4: f64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ -const SB5: f64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ -const SB6: f64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ -const SB7: f64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ - -fn erfc1(x: f64) -> f64 { - let s: f64; - let p: f64; - let q: f64; - - s = fabs(x) - 1.0; - p = PA0+s*(PA1+s*(PA2+s*(PA3+s*(PA4+s*(PA5+s*PA6))))); - q = 1.0+s*(QA1+s*(QA2+s*(QA3+s*(QA4+s*(QA5+s*QA6))))); - - 1.0 - ERX - p/q -} - -fn erfc2(ix: u32, mut x: f64) -> f64 { - let s: f64; - let r: f64; - let big_s: f64; - let z: f64; - - if ix < 0x3ff40000 { /* |x| < 1.25 */ - return erfc1(x); - } - - x = fabs(x); - s = 1.0/(x*x); - if ix < 0x4006db6d { /* |x| < 1/.35 ~ 2.85714 */ - r = RA0+s*(RA1+s*(RA2+s*(RA3+s*(RA4+s*( - RA5+s*(RA6+s*RA7)))))); - big_s = 1.0+s*(SA1+s*(SA2+s*(SA3+s*(SA4+s*( - SA5+s*(SA6+s*(SA7+s*SA8))))))); - } else { /* |x| > 1/.35 */ - r = RB0+s*(RB1+s*(RB2+s*(RB3+s*(RB4+s*( - RB5+s*RB6))))); - big_s = 1.0+s*(SB1+s*(SB2+s*(SB3+s*(SB4+s*( - SB5+s*(SB6+s*SB7)))))); - } - z = with_set_low_word(x, 0); - - exp(-z*z-0.5625)*exp((z-x)*(z+x)+r/big_s)/x -} - -pub fn erf(x: f64) -> f64 { - let r: f64; - let s: f64; - let z: f64; - let y: f64; - let mut ix: u32; - let sign: usize; - - ix = get_high_word(x); - sign = (ix>>31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - /* erf(nan)=nan, erf(+-inf)=+-1 */ - return 1.0-2.0*(sign as f64) + 1.0/x; - } - if ix < 0x3feb0000 { /* |x| < 0.84375 */ - if ix < 0x3e300000 { /* |x| < 2**-28 */ - /* avoid underflow */ - return 0.125*(8.0*x + EFX8*x); - } - z = x*x; - r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); - s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); - y = r/s; - return x + x*y; - } - if ix < 0x40180000 { /* 0.84375 <= |x| < 6 */ - y = 1.0 - erfc2(ix,x); - } else { - let x1p_1022 = f64::from_bits(0x0010000000000000); - y = 1.0 - x1p_1022; - } - - if sign != 0 { - -y - } else { - y - } -} - -pub fn erfc(x: f64) -> f64 { - let r: f64; - let s: f64; - let z: f64; - let y: f64; - let mut ix: u32; - let sign: usize; - - ix = get_high_word(x); - sign = (ix>>31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - /* erfc(nan)=nan, erfc(+-inf)=0,2 */ - return 2.0*(sign as f64) + 1.0/x; - } - if ix < 0x3feb0000 { /* |x| < 0.84375 */ - if ix < 0x3c700000 { /* |x| < 2**-56 */ - return 1.0 - x; - } - z = x*x; - r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); - s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); - y = r/s; - if sign != 0 || ix < 0x3fd00000 { /* x < 1/4 */ - return 1.0 - (x+x*y); - } - return 0.5 - (x - 0.5 + x*y); - } - if ix < 0x403c0000 { /* 0.84375 <= |x| < 28 */ - if sign != 0 { - return 2.0 - erfc2(ix,x); - } else { - return erfc2(ix,x); - } - } - - let x1p_1022 = f64::from_bits(0x0010000000000000); - if sign != 0 { - 2.0 - x1p_1022 - } else { - x1p_1022*x1p_1022 - } -} +use super::{exp, fabs, get_high_word, with_set_low_word}; +/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * where R = P/Q where P is an odd poly of degree 8 and + * Q is an odd poly of degree 10. + * -57.90 + * | R - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + * erf(x) = 1 - erfc(x) + * where + * R1(z) = degree 7 poly in z, (z=1/x^2) + * S1(z) = degree 8 poly in z + * + * 4. For x in [1/0.35,28] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +const ERX: f64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +const EFX8: f64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ +const PP0: f64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ +const PP1: f64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ +const PP2: f64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */ +const PP3: f64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */ +const PP4: f64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */ +const QQ1: f64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */ +const QQ2: f64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ +const QQ3: f64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ +const QQ4: f64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ +const QQ5: f64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +const PA0: f64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ +const PA1: f64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ +const PA2: f64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ +const PA3: f64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */ +const PA4: f64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */ +const PA5: f64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */ +const PA6: f64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */ +const QA1: f64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */ +const QA2: f64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */ +const QA3: f64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ +const QA4: f64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ +const QA5: f64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ +const QA6: f64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +const RA0: f64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ +const RA1: f64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ +const RA2: f64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ +const RA3: f64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */ +const RA4: f64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */ +const RA5: f64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */ +const RA6: f64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */ +const RA7: f64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */ +const SA1: f64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */ +const SA2: f64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */ +const SA3: f64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */ +const SA4: f64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */ +const SA5: f64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ +const SA6: f64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ +const SA7: f64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ +const SA8: f64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +const RB0: f64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ +const RB1: f64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ +const RB2: f64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ +const RB3: f64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */ +const RB4: f64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */ +const RB5: f64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */ +const RB6: f64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */ +const SB1: f64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */ +const SB2: f64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */ +const SB3: f64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */ +const SB4: f64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ +const SB5: f64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ +const SB6: f64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ +const SB7: f64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +fn erfc1(x: f64) -> f64 { + let s: f64; + let p: f64; + let q: f64; + + s = fabs(x) - 1.0; + p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); + q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); + + 1.0 - ERX - p / q +} + +fn erfc2(ix: u32, mut x: f64) -> f64 { + let s: f64; + let r: f64; + let big_s: f64; + let z: f64; + + if ix < 0x3ff40000 { + /* |x| < 1.25 */ + return erfc1(x); + } + + x = fabs(x); + s = 1.0 / (x * x); + if ix < 0x4006db6d { + /* |x| < 1/.35 ~ 2.85714 */ + r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); + big_s = 1.0 + + s * (SA1 + + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); + } else { + /* |x| > 1/.35 */ + r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); + big_s = + 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); + } + z = with_set_low_word(x, 0); + + exp(-z * z - 0.5625) * exp((z - x) * (z + x) + r / big_s) / x +} + +pub fn erf(x: f64) -> f64 { + let r: f64; + let s: f64; + let z: f64; + let y: f64; + let mut ix: u32; + let sign: usize; + + ix = get_high_word(x); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1.0 - 2.0 * (sign as f64) + 1.0 / x; + } + if ix < 0x3feb0000 { + /* |x| < 0.84375 */ + if ix < 0x3e300000 { + /* |x| < 2**-28 */ + /* avoid underflow */ + return 0.125 * (8.0 * x + EFX8 * x); + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + return x + x * y; + } + if ix < 0x40180000 { + /* 0.84375 <= |x| < 6 */ + y = 1.0 - erfc2(ix, x); + } else { + let x1p_1022 = f64::from_bits(0x0010000000000000); + y = 1.0 - x1p_1022; + } + + if sign != 0 { + -y + } else { + y + } +} + +pub fn erfc(x: f64) -> f64 { + let r: f64; + let s: f64; + let z: f64; + let y: f64; + let mut ix: u32; + let sign: usize; + + ix = get_high_word(x); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2.0 * (sign as f64) + 1.0 / x; + } + if ix < 0x3feb0000 { + /* |x| < 0.84375 */ + if ix < 0x3c700000 { + /* |x| < 2**-56 */ + return 1.0 - x; + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + if sign != 0 || ix < 0x3fd00000 { + /* x < 1/4 */ + return 1.0 - (x + x * y); + } + return 0.5 - (x - 0.5 + x * y); + } + if ix < 0x403c0000 { + /* 0.84375 <= |x| < 28 */ + if sign != 0 { + return 2.0 - erfc2(ix, x); + } else { + return erfc2(ix, x); + } + } + + let x1p_1022 = f64::from_bits(0x0010000000000000); + if sign != 0 { + 2.0 - x1p_1022 + } else { + x1p_1022 * x1p_1022 + } +} diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs index 0aaa89767ab..ef67c335b0c 100644 --- a/library/compiler-builtins/libm/src/math/erff.rs +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -1,210 +1,218 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{expf, fabsf}; - -const ERX: f32 = 8.4506291151e-01; /* 0x3f58560b */ -/* - * Coefficients for approximation to erf on [0,0.84375] - */ -const EFX8: f32 = 1.0270333290e+00; /* 0x3f8375d4 */ -const PP0: f32 = 1.2837916613e-01; /* 0x3e0375d4 */ -const PP1: f32 = -3.2504209876e-01; /* 0xbea66beb */ -const PP2: f32 = -2.8481749818e-02; /* 0xbce9528f */ -const PP3: f32 = -5.7702702470e-03; /* 0xbbbd1489 */ -const PP4: f32 = -2.3763017452e-05; /* 0xb7c756b1 */ -const QQ1: f32 = 3.9791721106e-01; /* 0x3ecbbbce */ -const QQ2: f32 = 6.5022252500e-02; /* 0x3d852a63 */ -const QQ3: f32 = 5.0813062117e-03; /* 0x3ba68116 */ -const QQ4: f32 = 1.3249473704e-04; /* 0x390aee49 */ -const QQ5: f32 = -3.9602282413e-06; /* 0xb684e21a */ -/* - * Coefficients for approximation to erf in [0.84375,1.25] - */ -const PA0: f32 = -2.3621185683e-03; /* 0xbb1acdc6 */ -const PA1: f32 = 4.1485610604e-01; /* 0x3ed46805 */ -const PA2: f32 = -3.7220788002e-01; /* 0xbebe9208 */ -const PA3: f32 = 3.1834661961e-01; /* 0x3ea2fe54 */ -const PA4: f32 = -1.1089469492e-01; /* 0xbde31cc2 */ -const PA5: f32 = 3.5478305072e-02; /* 0x3d1151b3 */ -const PA6: f32 = -2.1663755178e-03; /* 0xbb0df9c0 */ -const QA1: f32 = 1.0642088205e-01; /* 0x3dd9f331 */ -const QA2: f32 = 5.4039794207e-01; /* 0x3f0a5785 */ -const QA3: f32 = 7.1828655899e-02; /* 0x3d931ae7 */ -const QA4: f32 = 1.2617121637e-01; /* 0x3e013307 */ -const QA5: f32 = 1.3637083583e-02; /* 0x3c5f6e13 */ -const QA6: f32 = 1.1984500103e-02; /* 0x3c445aa3 */ -/* - * Coefficients for approximation to erfc in [1.25,1/0.35] - */ -const RA0: f32 = -9.8649440333e-03; /* 0xbc21a093 */ -const RA1: f32 = -6.9385856390e-01; /* 0xbf31a0b7 */ -const RA2: f32 = -1.0558626175e+01; /* 0xc128f022 */ -const RA3: f32 = -6.2375331879e+01; /* 0xc2798057 */ -const RA4: f32 = -1.6239666748e+02; /* 0xc322658c */ -const RA5: f32 = -1.8460508728e+02; /* 0xc3389ae7 */ -const RA6: f32 = -8.1287437439e+01; /* 0xc2a2932b */ -const RA7: f32 = -9.8143291473e+00; /* 0xc11d077e */ -const SA1: f32 = 1.9651271820e+01; /* 0x419d35ce */ -const SA2: f32 = 1.3765776062e+02; /* 0x4309a863 */ -const SA3: f32 = 4.3456588745e+02; /* 0x43d9486f */ -const SA4: f32 = 6.4538726807e+02; /* 0x442158c9 */ -const SA5: f32 = 4.2900814819e+02; /* 0x43d6810b */ -const SA6: f32 = 1.0863500214e+02; /* 0x42d9451f */ -const SA7: f32 = 6.5702495575e+00; /* 0x40d23f7c */ -const SA8: f32 = -6.0424413532e-02; /* 0xbd777f97 */ -/* - * Coefficients for approximation to erfc in [1/.35,28] - */ -const RB0: f32 = -9.8649431020e-03; /* 0xbc21a092 */ -const RB1: f32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ -const RB2: f32 = -1.7757955551e+01; /* 0xc18e104b */ -const RB3: f32 = -1.6063638306e+02; /* 0xc320a2ea */ -const RB4: f32 = -6.3756646729e+02; /* 0xc41f6441 */ -const RB5: f32 = -1.0250950928e+03; /* 0xc480230b */ -const RB6: f32 = -4.8351919556e+02; /* 0xc3f1c275 */ -const SB1: f32 = 3.0338060379e+01; /* 0x41f2b459 */ -const SB2: f32 = 3.2579251099e+02; /* 0x43a2e571 */ -const SB3: f32 = 1.5367296143e+03; /* 0x44c01759 */ -const SB4: f32 = 3.1998581543e+03; /* 0x4547fdbb */ -const SB5: f32 = 2.5530502930e+03; /* 0x451f90ce */ -const SB6: f32 = 4.7452853394e+02; /* 0x43ed43a7 */ -const SB7: f32 = -2.2440952301e+01; /* 0xc1b38712 */ - -fn erfc1(x: f32) -> f32 { - let s: f32; - let p: f32; - let q: f32; - - s = fabsf(x) - 1.0; - p = PA0+s*(PA1+s*(PA2+s*(PA3+s*(PA4+s*(PA5+s*PA6))))); - q = 1.0+s*(QA1+s*(QA2+s*(QA3+s*(QA4+s*(QA5+s*QA6))))); - return 1.0 - ERX - p/q; -} - -fn erfc2(mut ix: u32, mut x: f32) -> f32 { - let s: f32; - let r: f32; - let big_s: f32; - let z: f32; - - if ix < 0x3fa00000 { /* |x| < 1.25 */ - return erfc1(x); - } - - x = fabsf(x); - s = 1.0/(x*x); - if ix < 0x4036db6d { /* |x| < 1/0.35 */ - r = RA0+s*(RA1+s*(RA2+s*(RA3+s*(RA4+s*( - RA5+s*(RA6+s*RA7)))))); - big_s = 1.0+s*(SA1+s*(SA2+s*(SA3+s*(SA4+s*( - SA5+s*(SA6+s*(SA7+s*SA8))))))); - } else { /* |x| >= 1/0.35 */ - r = RB0+s*(RB1+s*(RB2+s*(RB3+s*(RB4+s*( - RB5+s*RB6))))); - big_s = 1.0+s*(SB1+s*(SB2+s*(SB3+s*(SB4+s*( - SB5+s*(SB6+s*SB7)))))); - } - ix = x.to_bits(); - z = f32::from_bits(ix&0xffffe000); - - expf(-z*z - 0.5625) * expf((z-x)*(z+x) + r/big_s)/x -} - -pub fn erff(x: f32) -> f32 -{ - let r: f32; - let s: f32; - let z: f32; - let y: f32; - let mut ix: u32; - let sign: usize; - - ix = x.to_bits(); - sign = (ix>>31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - /* erf(nan)=nan, erf(+-inf)=+-1 */ - return 1.0-2.0*(sign as f32) + 1.0/x; - } - if ix < 0x3f580000 { /* |x| < 0.84375 */ - if ix < 0x31800000 { /* |x| < 2**-28 */ - /*avoid underflow */ - return 0.125*(8.0*x + EFX8*x); - } - z = x*x; - r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); - s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); - y = r/s; - return x + x*y; - } - if ix < 0x40c00000 { /* |x| < 6 */ - y = 1.0 - erfc2(ix,x); - } else { - let x1p_120 = f32::from_bits(0x03800000); - y = 1.0 - x1p_120; - } - - if sign != 0 { - -y - } else { - y - } -} - -pub fn erfcf(x: f32) -> f32 { - let r: f32; - let s: f32; - let z: f32; - let y: f32; - let mut ix: u32; - let sign: usize; - - ix = x.to_bits(); - sign = (ix>>31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - /* erfc(nan)=nan, erfc(+-inf)=0,2 */ - return 2.0*(sign as f32) + 1.0/x; - } - - if ix < 0x3f580000 { /* |x| < 0.84375 */ - if ix < 0x23800000 { /* |x| < 2**-56 */ - return 1.0 - x; - } - z = x*x; - r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); - s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); - y = r/s; - if sign != 0 || ix < 0x3e800000 { /* x < 1/4 */ - return 1.0 - (x+x*y); - } - return 0.5 - (x - 0.5 + x*y); - } - if ix < 0x41e00000 { /* |x| < 28 */ - if sign != 0 { - return 2.0 - erfc2(ix, x); - } else { - return erfc2(ix, x); - } - } - - let x1p_120 = f32::from_bits(0x03800000); - if sign != 0 { - 2.0 - x1p_120 - } else { - x1p_120*x1p_120 - } -} +/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{expf, fabsf}; + +const ERX: f32 = 8.4506291151e-01; /* 0x3f58560b */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +const EFX8: f32 = 1.0270333290e+00; /* 0x3f8375d4 */ +const PP0: f32 = 1.2837916613e-01; /* 0x3e0375d4 */ +const PP1: f32 = -3.2504209876e-01; /* 0xbea66beb */ +const PP2: f32 = -2.8481749818e-02; /* 0xbce9528f */ +const PP3: f32 = -5.7702702470e-03; /* 0xbbbd1489 */ +const PP4: f32 = -2.3763017452e-05; /* 0xb7c756b1 */ +const QQ1: f32 = 3.9791721106e-01; /* 0x3ecbbbce */ +const QQ2: f32 = 6.5022252500e-02; /* 0x3d852a63 */ +const QQ3: f32 = 5.0813062117e-03; /* 0x3ba68116 */ +const QQ4: f32 = 1.3249473704e-04; /* 0x390aee49 */ +const QQ5: f32 = -3.9602282413e-06; /* 0xb684e21a */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +const PA0: f32 = -2.3621185683e-03; /* 0xbb1acdc6 */ +const PA1: f32 = 4.1485610604e-01; /* 0x3ed46805 */ +const PA2: f32 = -3.7220788002e-01; /* 0xbebe9208 */ +const PA3: f32 = 3.1834661961e-01; /* 0x3ea2fe54 */ +const PA4: f32 = -1.1089469492e-01; /* 0xbde31cc2 */ +const PA5: f32 = 3.5478305072e-02; /* 0x3d1151b3 */ +const PA6: f32 = -2.1663755178e-03; /* 0xbb0df9c0 */ +const QA1: f32 = 1.0642088205e-01; /* 0x3dd9f331 */ +const QA2: f32 = 5.4039794207e-01; /* 0x3f0a5785 */ +const QA3: f32 = 7.1828655899e-02; /* 0x3d931ae7 */ +const QA4: f32 = 1.2617121637e-01; /* 0x3e013307 */ +const QA5: f32 = 1.3637083583e-02; /* 0x3c5f6e13 */ +const QA6: f32 = 1.1984500103e-02; /* 0x3c445aa3 */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +const RA0: f32 = -9.8649440333e-03; /* 0xbc21a093 */ +const RA1: f32 = -6.9385856390e-01; /* 0xbf31a0b7 */ +const RA2: f32 = -1.0558626175e+01; /* 0xc128f022 */ +const RA3: f32 = -6.2375331879e+01; /* 0xc2798057 */ +const RA4: f32 = -1.6239666748e+02; /* 0xc322658c */ +const RA5: f32 = -1.8460508728e+02; /* 0xc3389ae7 */ +const RA6: f32 = -8.1287437439e+01; /* 0xc2a2932b */ +const RA7: f32 = -9.8143291473e+00; /* 0xc11d077e */ +const SA1: f32 = 1.9651271820e+01; /* 0x419d35ce */ +const SA2: f32 = 1.3765776062e+02; /* 0x4309a863 */ +const SA3: f32 = 4.3456588745e+02; /* 0x43d9486f */ +const SA4: f32 = 6.4538726807e+02; /* 0x442158c9 */ +const SA5: f32 = 4.2900814819e+02; /* 0x43d6810b */ +const SA6: f32 = 1.0863500214e+02; /* 0x42d9451f */ +const SA7: f32 = 6.5702495575e+00; /* 0x40d23f7c */ +const SA8: f32 = -6.0424413532e-02; /* 0xbd777f97 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +const RB0: f32 = -9.8649431020e-03; /* 0xbc21a092 */ +const RB1: f32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ +const RB2: f32 = -1.7757955551e+01; /* 0xc18e104b */ +const RB3: f32 = -1.6063638306e+02; /* 0xc320a2ea */ +const RB4: f32 = -6.3756646729e+02; /* 0xc41f6441 */ +const RB5: f32 = -1.0250950928e+03; /* 0xc480230b */ +const RB6: f32 = -4.8351919556e+02; /* 0xc3f1c275 */ +const SB1: f32 = 3.0338060379e+01; /* 0x41f2b459 */ +const SB2: f32 = 3.2579251099e+02; /* 0x43a2e571 */ +const SB3: f32 = 1.5367296143e+03; /* 0x44c01759 */ +const SB4: f32 = 3.1998581543e+03; /* 0x4547fdbb */ +const SB5: f32 = 2.5530502930e+03; /* 0x451f90ce */ +const SB6: f32 = 4.7452853394e+02; /* 0x43ed43a7 */ +const SB7: f32 = -2.2440952301e+01; /* 0xc1b38712 */ + +fn erfc1(x: f32) -> f32 { + let s: f32; + let p: f32; + let q: f32; + + s = fabsf(x) - 1.0; + p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); + q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); + return 1.0 - ERX - p / q; +} + +fn erfc2(mut ix: u32, mut x: f32) -> f32 { + let s: f32; + let r: f32; + let big_s: f32; + let z: f32; + + if ix < 0x3fa00000 { + /* |x| < 1.25 */ + return erfc1(x); + } + + x = fabsf(x); + s = 1.0 / (x * x); + if ix < 0x4036db6d { + /* |x| < 1/0.35 */ + r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); + big_s = 1.0 + + s * (SA1 + + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); + } else { + /* |x| >= 1/0.35 */ + r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); + big_s = + 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); + } + ix = x.to_bits(); + z = f32::from_bits(ix & 0xffffe000); + + expf(-z * z - 0.5625) * expf((z - x) * (z + x) + r / big_s) / x +} + +pub fn erff(x: f32) -> f32 { + let r: f32; + let s: f32; + let z: f32; + let y: f32; + let mut ix: u32; + let sign: usize; + + ix = x.to_bits(); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1.0 - 2.0 * (sign as f32) + 1.0 / x; + } + if ix < 0x3f580000 { + /* |x| < 0.84375 */ + if ix < 0x31800000 { + /* |x| < 2**-28 */ + /*avoid underflow */ + return 0.125 * (8.0 * x + EFX8 * x); + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + return x + x * y; + } + if ix < 0x40c00000 { + /* |x| < 6 */ + y = 1.0 - erfc2(ix, x); + } else { + let x1p_120 = f32::from_bits(0x03800000); + y = 1.0 - x1p_120; + } + + if sign != 0 { + -y + } else { + y + } +} + +pub fn erfcf(x: f32) -> f32 { + let r: f32; + let s: f32; + let z: f32; + let y: f32; + let mut ix: u32; + let sign: usize; + + ix = x.to_bits(); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2.0 * (sign as f32) + 1.0 / x; + } + + if ix < 0x3f580000 { + /* |x| < 0.84375 */ + if ix < 0x23800000 { + /* |x| < 2**-56 */ + return 1.0 - x; + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + if sign != 0 || ix < 0x3e800000 { + /* x < 1/4 */ + return 1.0 - (x + x * y); + } + return 0.5 - (x - 0.5 + x * y); + } + if ix < 0x41e00000 { + /* |x| < 28 */ + if sign != 0 { + return 2.0 - erfc2(ix, x); + } else { + return erfc2(ix, x); + } + } + + let x1p_120 = f32::from_bits(0x03800000); + if sign != 0 { + 2.0 - x1p_120 + } else { + x1p_120 * x1p_120 + } +} diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs index d12fa0be31e..9537f76f136 100644 --- a/library/compiler-builtins/libm/src/math/exp10.rs +++ b/library/compiler-builtins/libm/src/math/exp10.rs @@ -1,24 +1,21 @@ -use super::{exp2, modf, pow}; - -const LN10: f64 = 3.32192809488736234787031942948939; -const P10: &[f64] = &[ - 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, - 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15 -]; - -pub fn exp10(x: f64) -> f64 -{ - let (mut y, n) = modf(x); - let u: u64 = n.to_bits(); - /* fabs(n) < 16 without raising invalid on nan */ - if (u>>52 & 0x7ff) < 0x3ff+4 { - if y == 0.0 { - return P10[((n as isize) + 15) as usize]; - } - y = exp2(LN10 * y); - return y * P10[((n as isize) + 15) as usize]; - } - return pow(10.0, x); -} +use super::{exp2, modf, pow}; + +const LN10: f64 = 3.32192809488736234787031942948939; +const P10: &[f64] = &[ + 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, +]; + +pub fn exp10(x: f64) -> f64 { + let (mut y, n) = modf(x); + let u: u64 = n.to_bits(); + /* fabs(n) < 16 without raising invalid on nan */ + if (u >> 52 & 0x7ff) < 0x3ff + 4 { + if y == 0.0 { + return P10[((n as isize) + 15) as usize]; + } + y = exp2(LN10 * y); + return y * P10[((n as isize) + 15) as usize]; + } + return pow(10.0, x); +} diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs index 8fb88a52c01..d45fff36ea3 100644 --- a/library/compiler-builtins/libm/src/math/exp10f.rs +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -1,22 +1,21 @@ -use super::{exp2, exp2f, modff}; - -const LN10_F32: f32 = 3.32192809488736234787031942948939; -const LN10_F64: f64 = 3.32192809488736234787031942948939; -const P10: &[f32] = &[ - 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 -]; - -pub fn exp10f(x: f32) -> f32 { - let (mut y, n) = modff(x); - let u = n.to_bits(); - /* fabsf(n) < 8 without raising invalid on nan */ - if (u>>23 & 0xff) < 0x7f+3 { - if y == 0.0 { - return P10[((n as isize) + 7) as usize] - } - y = exp2f(LN10_F32 * y); - return y * P10[((n as isize) + 7) as usize]; - } - return exp2(LN10_F64 * (x as f64)) as f32; -} +use super::{exp2, exp2f, modff}; + +const LN10_F32: f32 = 3.32192809488736234787031942948939; +const LN10_F64: f64 = 3.32192809488736234787031942948939; +const P10: &[f32] = &[ + 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, +]; + +pub fn exp10f(x: f32) -> f32 { + let (mut y, n) = modff(x); + let u = n.to_bits(); + /* fabsf(n) < 8 without raising invalid on nan */ + if (u >> 23 & 0xff) < 0x7f + 3 { + if y == 0.0 { + return P10[((n as isize) + 7) as usize]; + } + y = exp2f(LN10_F32 * y); + return y * P10[((n as isize) + 7) as usize]; + } + return exp2(LN10_F64 * (x as f64)) as f32; +} diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 21c854cd00f..6b062481dca 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -43,7 +43,7 @@ fn mul(x: u64, y: u64) -> (u64, u64) { t1 = xlo * ylo; t2 = xlo * yhi + xhi * ylo; t3 = xhi * yhi; - let lo = t1 + (t2 << 32); + let lo = t1.wrapping_add(t2 << 32); let hi = t3 + (t2 >> 32) + (t1 > lo) as u64; (hi, lo) } @@ -116,7 +116,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { let mut nonzero: i32 = 1; if samesign { /* r += z */ - rlo += zlo; + rlo = rlo.wrapping_add(zlo); rhi += zhi + (rlo < zlo) as u64; } else { /* r -= z */ diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs index ecc9b39a5c1..2cdd8a9ba3f 100644 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -46,7 +46,7 @@ pub fn fmod(x: f64, y: f64) -> f64 { /* x mod y */ while ex > ey { - i = uxi - uyi; + i = uxi.wrapping_sub(uyi); if i >> 63 == 0 { if i == 0 { return 0.0 * x; @@ -56,7 +56,7 @@ pub fn fmod(x: f64, y: f64) -> f64 { uxi <<= 1; ex -= 1; } - i = uxi - uyi; + i = uxi.wrapping_sub(uyi); if i >> 63 == 0 { if i == 0 { return 0.0 * x; diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index 98f51f455b8..3e6779a9304 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -52,7 +52,7 @@ pub fn fmodf(x: f32, y: f32) -> f32 { /* x mod y */ while ex > ey { - i = uxi - uyi; + i = uxi.wrapping_sub(uyi); if i >> 31 == 0 { if i == 0 { return 0.0 * x; @@ -64,7 +64,7 @@ pub fn fmodf(x: f32, y: f32) -> f32 { ex -= 1; } - i = uxi - uyi; + i = uxi.wrapping_sub(uyi); if i >> 31 == 0 { if i == 0 { return 0.0 * x; diff --git a/library/compiler-builtins/libm/src/math/frexp.rs b/library/compiler-builtins/libm/src/math/frexp.rs index 45733a3aaa3..badad786aa3 100644 --- a/library/compiler-builtins/libm/src/math/frexp.rs +++ b/library/compiler-builtins/libm/src/math/frexp.rs @@ -1,20 +1,20 @@ -pub fn frexp(x: f64) -> (f64, isize) { - let mut y = x.to_bits(); - let ee = ((y>>52) & 0x7ff) as isize; - - if ee == 0 { - if x != 0.0 { - let x1p64 = f64::from_bits(0x43f0000000000000); - let (x, e) = frexp(x*x1p64); - return (x, e - 64); - } - return (x, 0); - } else if ee == 0x7ff { - return (x, 0); - } - - let e = ee - 0x3fe; - y &= 0x800fffffffffffff; - y |= 0x3fe0000000000000; - return (f64::from_bits(y), e); -} +pub fn frexp(x: f64) -> (f64, i32) { + let mut y = x.to_bits(); + let ee = ((y >> 52) & 0x7ff) as i32; + + if ee == 0 { + if x != 0.0 { + let x1p64 = f64::from_bits(0x43f0000000000000); + let (x, e) = frexp(x * x1p64); + return (x, e - 64); + } + return (x, 0); + } else if ee == 0x7ff { + return (x, 0); + } + + let e = ee - 0x3fe; + y &= 0x800fffffffffffff; + y |= 0x3fe0000000000000; + return (f64::from_bits(y), e); +} diff --git a/library/compiler-builtins/libm/src/math/frexpf.rs b/library/compiler-builtins/libm/src/math/frexpf.rs index 1c9dae0bb98..2919c0ab022 100644 --- a/library/compiler-builtins/libm/src/math/frexpf.rs +++ b/library/compiler-builtins/libm/src/math/frexpf.rs @@ -1,21 +1,21 @@ -pub fn frexpf(x: f32) -> (f32, isize) { - let mut y = x.to_bits(); - let ee: isize = ((y>>23) & 0xff) as isize; - - if ee == 0 { - if x != 0.0 { - let x1p64 = f32::from_bits(0x5f800000); - let (x, e) = frexpf(x*x1p64); - return (x, e - 64); - } else { - return (x, 0); - } - } else if ee == 0xff { - return (x, 0); - } - - let e = ee - 0x7e; - y &= 0x807fffff; - y |= 0x3f000000; - return (f32::from_bits(y), e); -} +pub fn frexpf(x: f32) -> (f32, i32) { + let mut y = x.to_bits(); + let ee: i32 = ((y >> 23) & 0xff) as i32; + + if ee == 0 { + if x != 0.0 { + let x1p64 = f32::from_bits(0x5f800000); + let (x, e) = frexpf(x * x1p64); + return (x, e - 64); + } else { + return (x, 0); + } + } else if ee == 0xff { + return (x, 0); + } + + let e = ee - 0x7e; + y &= 0x807fffff; + y |= 0x3f000000; + (f32::from_bits(y), e) +} diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs index 78fe030a1cc..8a1289ca444 100644 --- a/library/compiler-builtins/libm/src/math/ilogb.rs +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -1,31 +1,31 @@ -const FP_ILOGBNAN: isize = -1 - (((!0) >> 1)); -const FP_ILOGB0: isize = FP_ILOGBNAN; - -pub fn ilogb(x: f64) -> isize { - let mut i: u64 = x.to_bits(); - let e = ((i>>52) & 0x7ff) as isize; - - if e == 0 { - i <<= 12; - if i == 0 { - force_eval!(0.0/0.0); - return FP_ILOGB0; - } - /* subnormal x */ - let mut e = -0x3ff; - while (i>>63) == 0 { - e -= 1; - i <<= 1; - } - return e; - } - if e == 0x7ff { - force_eval!(0.0/0.0); - if (i<<12) != 0 { - return FP_ILOGBNAN; - } else { - return isize::max_value(); - } - } - return e - 0x3ff; -} +const FP_ILOGBNAN: i32 = -1 - ((!0) >> 1); +const FP_ILOGB0: i32 = FP_ILOGBNAN; + +pub fn ilogb(x: f64) -> i32 { + let mut i: u64 = x.to_bits(); + let e = ((i >> 52) & 0x7ff) as i32; + + if e == 0 { + i <<= 12; + if i == 0 { + force_eval!(0.0 / 0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -0x3ff; + while (i >> 63) == 0 { + e -= 1; + i <<= 1; + } + return e; + } + if e == 0x7ff { + force_eval!(0.0 / 0.0); + if (i << 12) != 0 { + return FP_ILOGBNAN; + } else { + return i32::max_value(); + } + } + return e - 0x3ff; +} diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs index 9ca1c360665..1bf4670a812 100644 --- a/library/compiler-builtins/libm/src/math/ilogbf.rs +++ b/library/compiler-builtins/libm/src/math/ilogbf.rs @@ -1,31 +1,31 @@ -const FP_ILOGBNAN: isize = -1 - (((!0) >> 1)); -const FP_ILOGB0: isize = FP_ILOGBNAN; - -pub fn ilogbf(x: f32) -> isize { - let mut i = x.to_bits(); - let e = ((i>>23) & 0xff) as isize; - - if e == 0 { - i <<= 9; - if i == 0 { - force_eval!(0.0/0.0); - return FP_ILOGB0; - } - /* subnormal x */ - let mut e = -0x7f; - while (i>>31) == 0 { - e -= 1; - i <<= 1; - } - return e; - } - if e == 0xff { - force_eval!(0.0/0.0); - if (i<<9) != 0 { - return FP_ILOGBNAN; - } else { - return isize::max_value(); - } - } - return e - 0x7f; -} +const FP_ILOGBNAN: i32 = -1 - ((!0) >> 1); +const FP_ILOGB0: i32 = FP_ILOGBNAN; + +pub fn ilogbf(x: f32) -> i32 { + let mut i = x.to_bits(); + let e = ((i >> 23) & 0xff) as i32; + + if e == 0 { + i <<= 9; + if i == 0 { + force_eval!(0.0 / 0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -0x7f; + while (i >> 31) == 0 { + e -= 1; + i <<= 1; + } + return e; + } + if e == 0xff { + force_eval!(0.0 / 0.0); + if (i << 9) != 0 { + return FP_ILOGBNAN; + } else { + return i32::max_value(); + } + } + return e - 0x7f; +} diff --git a/library/compiler-builtins/libm/src/math/j0.rs b/library/compiler-builtins/libm/src/math/j0.rs index 02625b086db..c4258ccca16 100644 --- a/library/compiler-builtins/libm/src/math/j0.rs +++ b/library/compiler-builtins/libm/src/math/j0.rs @@ -1,392 +1,422 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* j0(x), y0(x) - * Bessel function of the first and second kinds of order zero. - * Method -- j0(x): - * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... - * 2. Reduce x to |x| since j0(x)=j0(-x), and - * for x in (0,2) - * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; - * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) - * for x in (2,inf) - * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) - * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) - * as follow: - * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) - * = 1/sqrt(2) * (cos(x) + sin(x)) - * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) - * = 1/sqrt(2) * (sin(x) - cos(x)) - * (To avoid cancellation, use - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - * to compute the worse one.) - * - * 3 Special cases - * j0(nan)= nan - * j0(0) = 1 - * j0(inf) = 0 - * - * Method -- y0(x): - * 1. For x<2. - * Since - * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) - * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. - * We use the following function to approximate y0, - * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 - * where - * U(z) = u00 + u01*z + ... + u06*z^6 - * V(z) = 1 + v01*z + ... + v04*z^4 - * with absolute approximation error bounded by 2**-72. - * Note: For tiny x, U/V = u0 and j0(x)~1, hence - * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) - * 2. For x>=2. - * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) - * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) - * by the method mentioned above. - * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. - */ - -use super::{cos, get_low_word, get_high_word, fabs, log, sin, sqrt}; -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ -const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ - -/* common method when |x|>=2 */ -fn common(ix: u32, x: f64, y0: bool) -> f64 { - let s: f64; - let mut c: f64; - let mut ss: f64; - let mut cc: f64; - let z: f64; - - /* - * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) - * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) - * - * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) - * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - */ - s = sin(x); - c = cos(x); - if y0 { - c = -c; - } - cc = s+c; - /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ - if ix < 0x7fe00000 { - ss = s-c; - z = -cos(2.0*x); - if s*c < 0.0 { - cc = z/ss; - } else { - ss = z/cc; - } - if ix < 0x48000000 { - if y0 { - ss = -ss; - } - cc = pzero(x)*cc-qzero(x)*ss; - } - } - return INVSQRTPI*cc/sqrt(x); -} - -/* R0/S0 on [0, 2.00] */ -const R02: f64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ -const R03: f64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ -const R04: f64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ -const R05: f64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */ -const S01: f64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ -const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ -const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ -const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ - -pub fn j0(mut x: f64) -> f64 -{ - let z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - - /* j0(+-inf)=0, j0(nan)=nan */ - if ix >= 0x7ff00000 { - return 1.0/(x*x); - } - x = fabs(x); - - if ix >= 0x40000000 { /* |x| >= 2 */ - /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ - return common(ix,x,false); - } - - /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ - if ix >= 0x3f200000 { /* |x| >= 2**-13 */ - /* up to 4ulp error close to 2 */ - z = x*x; - r = z*(R02+z*(R03+z*(R04+z*R05))); - s = 1.0+z*(S01+z*(S02+z*(S03+z*S04))); - return (1.0+x/2.0)*(1.0-x/2.0) + z*(r/s); - } - - /* 1 - x*x/4 */ - /* prevent underflow */ - /* inexact should be raised when x!=0, this is not done correctly */ - if ix >= 0x38000000 { /* |x| >= 2**-127 */ - x = 0.25*x*x; - } - return 1.0 - x; -} - -const U00: f64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ -const U01: f64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ -const U02: f64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ -const U03: f64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */ -const U04: f64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */ -const U05: f64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */ -const U06: f64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */ -const V01: f64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ -const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ -const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ -const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ - -pub fn y0(x: f64) -> f64 -{ - let z: f64; - let u: f64; - let v: f64; - let ix: u32; - let lx: u32; - - ix = get_high_word(x); - lx = get_low_word(x); - - /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ - if ((ix<<1) | lx) == 0 { - return -1.0/0.0; - } - if (ix>>31) != 0 { - return 0.0/0.0; - } - if ix >= 0x7ff00000 { - return 1.0/x; - } - - if ix >= 0x40000000 { /* x >= 2 */ - /* large ulp errors near zeros: 3.958, 7.086,.. */ - return common(ix,x,true); - } - - /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ - if ix >= 0x3e400000 { /* x >= 2**-27 */ - /* large ulp error near the first zero, x ~= 0.89 */ - z = x*x; - u = U00+z*(U01+z*(U02+z*(U03+z*(U04+z*(U05+z*U06))))); - v = 1.0+z*(V01+z*(V02+z*(V03+z*V04))); - return u/v + TPI*(j0(x)*log(x)); - } - return U00 + TPI*log(x); -} - -/* The asymptotic expansions of pzero is - * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. - * For x >= 2, We approximate pzero by - * pzero(x) = 1 + (R/S) - * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 - * S = 1 + pS0*s^2 + ... + pS4*s^10 - * and - * | pzero(x)-1-R/S | <= 2 ** ( -60.26) - */ -const PR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ - -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ - -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ - -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ - -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ -]; -const PS8: [f64; 5] = [ - 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ - 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ - 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ - 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ - 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ -]; - -const PR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ - -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ - -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ - -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ - -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ - -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ -]; -const PS5: [f64; 5] = [ - 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ - 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ - 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ - 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ - 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ -]; - -const PR3: [f64; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ - -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ - -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ - -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ - -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ - -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ -]; -const PS3: [f64; 5] = [ - 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ - 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ - 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ - 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ - 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ -]; - -const PR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ - -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ - -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ - -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ - -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ - -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ - -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ -]; -const PS2: [f64; 5] = [ - 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ - 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ - 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ - 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ - 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ -]; - -fn pzero(x: f64) -> f64 -{ - let p: &[f64; 6]; - let q: &[f64; 5]; - let z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 {p = &PR8; q = &PS8;} - else if ix >= 0x40122E8B {p = &PR5; q = &PS5;} - else if ix >= 0x4006DB6D {p = &PR3; q = &PS3;} - else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); - return 1.0 + r/s; -} - - -/* For x >= 8, the asymptotic expansions of qzero is - * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. - * We approximate pzero by - * qzero(x) = s*(-1.25 + (R/S)) - * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 - * S = 1 + qS0*s^2 + ... + qS5*s^12 - * and - * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) - */ -const QR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ - 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ - 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ - 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ - 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ -]; -const QS8: [f64; 6] = [ - 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ - 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ - 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ - 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ - 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ - -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ -]; - -const QR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ - 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ - 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ - 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ - 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ - 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ -]; -const QS5: [f64; 6] = [ - 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ - 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ - 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ - 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ - 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ - -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ -]; - -const QR3: [f64; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ - 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ - 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ - 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ - 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ - 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ -]; -const QS3: [f64; 6] = [ - 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ - 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ - 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ - 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ - 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ - -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ -]; - -const QR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ - 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ - 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ - 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ - 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ - 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ -]; -const QS2: [f64; 6] = [ - 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ - 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ - 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ - 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ - 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ - -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ -]; - -fn qzero(x: f64) -> f64 -{ - let p: &[f64; 6]; - let q: &[f64; 6]; - let s: f64; - let r: f64; - let z: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 {p = &QR8; q = &QS8;} - else if ix >= 0x40122E8B {p = &QR5; q = &QS5;} - else if ix >= 0x4006DB6D {p = &QR3; q = &QS3;} - else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); - return (-0.125 + r/s)/x; -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j0(x), y0(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j0(x): + * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... + * 2. Reduce x to |x| since j0(x)=j0(-x), and + * for x in (0,2) + * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; + * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) + * for x in (2,inf) + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * as follow: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (cos(x) + sin(x)) + * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j0(nan)= nan + * j0(0) = 1 + * j0(inf) = 0 + * + * Method -- y0(x): + * 1. For x<2. + * Since + * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) + * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. + * We use the following function to approximate y0, + * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 + * where + * U(z) = u00 + u01*z + ... + u06*z^6 + * V(z) = 1 + v01*z + ... + v04*z^4 + * with absolute approximation error bounded by 2**-72. + * Note: For tiny x, U/V = u0 and j0(x)~1, hence + * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) + * 2. For x>=2. + * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * by the method mentioned above. + * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. + */ + +use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +/* common method when |x|>=2 */ +fn common(ix: u32, x: f64, y0: bool) -> f64 { + let s: f64; + let mut c: f64; + let mut ss: f64; + let mut cc: f64; + let z: f64; + + /* + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) + * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) + * + * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) + * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + c = cos(x); + if y0 { + c = -c; + } + cc = s + c; + /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ + if ix < 0x7fe00000 { + ss = s - c; + z = -cos(2.0 * x); + if s * c < 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x48000000 { + if y0 { + ss = -ss; + } + cc = pzero(x) * cc - qzero(x) * ss; + } + } + return INVSQRTPI * cc / sqrt(x); +} + +/* R0/S0 on [0, 2.00] */ +const R02: f64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ +const R03: f64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ +const R04: f64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ +const R05: f64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */ +const S01: f64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ +const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ +const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ +const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ + +pub fn j0(mut x: f64) -> f64 { + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + + /* j0(+-inf)=0, j0(nan)=nan */ + if ix >= 0x7ff00000 { + return 1.0 / (x * x); + } + x = fabs(x); + + if ix >= 0x40000000 { + /* |x| >= 2 */ + /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ + return common(ix, x, false); + } + + /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ + if ix >= 0x3f200000 { + /* |x| >= 2**-13 */ + /* up to 4ulp error close to 2 */ + z = x * x; + r = z * (R02 + z * (R03 + z * (R04 + z * R05))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); + return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); + } + + /* 1 - x*x/4 */ + /* prevent underflow */ + /* inexact should be raised when x!=0, this is not done correctly */ + if ix >= 0x38000000 { + /* |x| >= 2**-127 */ + x = 0.25 * x * x; + } + return 1.0 - x; +} + +const U00: f64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ +const U01: f64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ +const U02: f64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ +const U03: f64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */ +const U04: f64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */ +const U05: f64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */ +const U06: f64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */ +const V01: f64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ +const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ +const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ +const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ + +pub fn y0(x: f64) -> f64 { + let z: f64; + let u: f64; + let v: f64; + let ix: u32; + let lx: u32; + + ix = get_high_word(x); + lx = get_low_word(x); + + /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ + if ((ix << 1) | lx) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7ff00000 { + return 1.0 / x; + } + + if ix >= 0x40000000 { + /* x >= 2 */ + /* large ulp errors near zeros: 3.958, 7.086,.. */ + return common(ix, x, true); + } + + /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ + if ix >= 0x3e400000 { + /* x >= 2**-27 */ + /* large ulp error near the first zero, x ~= 0.89 */ + z = x * x; + u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); + v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); + return u / v + TPI * (j0(x) * log(x)); + } + return U00 + TPI * log(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +const PR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ + -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ + -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ + -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ + -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ +]; +const PS8: [f64; 5] = [ + 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ + 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ + 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ + 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ + 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ +]; + +const PR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ + -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ + -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ + -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ + -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ + -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ +]; +const PS5: [f64; 5] = [ + 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ + 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ + 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ + 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ + 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ +]; + +const PR3: [f64; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ + -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ + -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ + -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ + -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ + -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ +]; +const PS3: [f64; 5] = [ + 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ + 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ + 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ + 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ + 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ +]; + +const PR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ + -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ + -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ + -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ + -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ + -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ +]; +const PS2: [f64; 5] = [ + 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ + 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ + 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ + 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ + 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ +]; + +fn pzero(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 5]; + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x40122E8B { + p = &PR5; + q = &PS5; + } else if ix >= 0x4006DB6D { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +const QR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ + 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ + 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ + 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ + 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ +]; +const QS8: [f64; 6] = [ + 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ + 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ + 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ + 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ + 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ + -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ +]; + +const QR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ + 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ + 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ + 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ + 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ + 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ +]; +const QS5: [f64; 6] = [ + 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ + 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ + 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ + 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ + 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ + -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ +]; + +const QR3: [f64; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ + 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ + 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ + 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ + 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ + 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ +]; +const QS3: [f64; 6] = [ + 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ + 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ + 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ + 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ + 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ + -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ +]; + +const QR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ + 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ + 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ + 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ + 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ + 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ +]; +const QS2: [f64; 6] = [ + 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ + 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ + 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ + 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ + 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ + -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ +]; + +fn qzero(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 6]; + let s: f64; + let r: f64; + let z: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x40122E8B { + p = &QR5; + q = &QS5; + } else if ix >= 0x4006DB6D { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (-0.125 + r / s) / x; +} diff --git a/library/compiler-builtins/libm/src/math/j0f.rs b/library/compiler-builtins/libm/src/math/j0f.rs index e2faed0b256..91c03dbbcdd 100644 --- a/library/compiler-builtins/libm/src/math/j0f.rs +++ b/library/compiler-builtins/libm/src/math/j0f.rs @@ -1,330 +1,359 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{cosf, fabsf, logf, sinf, sqrtf}; - -const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ -const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ - -fn common(ix: u32, x: f32, y0: bool) -> f32 -{ - let z: f32; - let s: f32; - let mut c: f32; - let mut ss: f32; - let mut cc: f32; - /* - * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) - * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) - */ - s = sinf(x); - c = cosf(x); - if y0 { - c = -c; - } - cc = s+c; - if ix < 0x7f000000 { - ss = s-c; - z = -cosf(2.0*x); - if s*c < 0.0 { - cc = z/ss; - } else { - ss = z/cc; - } - if ix < 0x58800000 { - if y0 { - ss = -ss; - } - cc = pzerof(x)*cc-qzerof(x)*ss; - } - } - return INVSQRTPI*cc/sqrtf(x); -} - -/* R0/S0 on [0, 2.00] */ -const R02: f32 = 1.5625000000e-02; /* 0x3c800000 */ -const R03: f32 = -1.8997929874e-04; /* 0xb947352e */ -const R04: f32 = 1.8295404516e-06; /* 0x35f58e88 */ -const R05: f32 = -4.6183270541e-09; /* 0xb19eaf3c */ -const S01: f32 = 1.5619102865e-02; /* 0x3c7fe744 */ -const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ -const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ -const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ - -pub fn j0f(mut x: f32) -> f32 -{ - let z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - return 1.0/(x*x); - } - x = fabsf(x); - - if ix >= 0x40000000 { /* |x| >= 2 */ - /* large ulp error near zeros */ - return common(ix, x, false); - } - if ix >= 0x3a000000 { /* |x| >= 2**-11 */ - /* up to 4ulp error near 2 */ - z = x*x; - r = z*(R02+z*(R03+z*(R04+z*R05))); - s = 1.0+z*(S01+z*(S02+z*(S03+z*S04))); - return (1.0+x/2.0)*(1.0-x/2.0) + z*(r/s); - } - if ix >= 0x21800000 { /* |x| >= 2**-60 */ - x = 0.25*x*x; - } - return 1.0 - x; -} - -const U00: f32 = -7.3804296553e-02; /* 0xbd9726b5 */ -const U01: f32 = 1.7666645348e-01; /* 0x3e34e80d */ -const U02: f32 = -1.3818567619e-02; /* 0xbc626746 */ -const U03: f32 = 3.4745343146e-04; /* 0x39b62a69 */ -const U04: f32 = -3.8140706238e-06; /* 0xb67ff53c */ -const U05: f32 = 1.9559013964e-08; /* 0x32a802ba */ -const U06: f32 = -3.9820518410e-11; /* 0xae2f21eb */ -const V01: f32 = 1.2730483897e-02; /* 0x3c509385 */ -const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ -const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ -const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ - -pub fn y0f(x: f32) -> f32 -{ - let z: f32; - let u: f32; - let v: f32; - let ix: u32; - - ix = x.to_bits(); - if (ix & 0x7fffffff) == 0 { - return -1.0/0.0; - } - if (ix>>31) !=0 { - return 0.0/0.0; - } - if ix >= 0x7f800000 { - return 1.0/x; - } - if ix >= 0x40000000 { /* |x| >= 2.0 */ - /* large ulp error near zeros */ - return common(ix,x,true); - } - if ix >= 0x39000000 { /* x >= 2**-13 */ - /* large ulp error at x ~= 0.89 */ - z = x*x; - u = U00+z*(U01+z*(U02+z*(U03+z*(U04+z*(U05+z*U06))))); - v = 1.0+z*(V01+z*(V02+z*(V03+z*V04))); - return u/v + TPI*(j0f(x)*logf(x)); - } - return U00 + TPI*logf(x); -} - -/* The asymptotic expansions of pzero is - * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. - * For x >= 2, We approximate pzero by - * pzero(x) = 1 + (R/S) - * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 - * S = 1 + pS0*s^2 + ... + pS4*s^10 - * and - * | pzero(x)-1-R/S | <= 2 ** ( -60.26) - */ -const PR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - -7.0312500000e-02, /* 0xbd900000 */ - -8.0816707611e+00, /* 0xc1014e86 */ - -2.5706311035e+02, /* 0xc3808814 */ - -2.4852163086e+03, /* 0xc51b5376 */ - -5.2530439453e+03, /* 0xc5a4285a */ -]; -const PS8: [f32; 5] = [ - 1.1653436279e+02, /* 0x42e91198 */ - 3.8337448730e+03, /* 0x456f9beb */ - 4.0597855469e+04, /* 0x471e95db */ - 1.1675296875e+05, /* 0x47e4087c */ - 4.7627726562e+04, /* 0x473a0bba */ -]; -const PR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -1.1412546255e-11, /* 0xad48c58a */ - -7.0312492549e-02, /* 0xbd8fffff */ - -4.1596107483e+00, /* 0xc0851b88 */ - -6.7674766541e+01, /* 0xc287597b */ - -3.3123129272e+02, /* 0xc3a59d9b */ - -3.4643338013e+02, /* 0xc3ad3779 */ -]; -const PS5: [f32; 5] = [ - 6.0753936768e+01, /* 0x42730408 */ - 1.0512523193e+03, /* 0x44836813 */ - 5.9789707031e+03, /* 0x45bad7c4 */ - 9.6254453125e+03, /* 0x461665c8 */ - 2.4060581055e+03, /* 0x451660ee */ -]; - -const PR3: [f32; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - -2.5470459075e-09, /* 0xb12f081b */ - -7.0311963558e-02, /* 0xbd8fffb8 */ - -2.4090321064e+00, /* 0xc01a2d95 */ - -2.1965976715e+01, /* 0xc1afba52 */ - -5.8079170227e+01, /* 0xc2685112 */ - -3.1447946548e+01, /* 0xc1fb9565 */ -]; -const PS3: [f32; 5] = [ - 3.5856033325e+01, /* 0x420f6c94 */ - 3.6151397705e+02, /* 0x43b4c1ca */ - 1.1936077881e+03, /* 0x44953373 */ - 1.1279968262e+03, /* 0x448cffe6 */ - 1.7358093262e+02, /* 0x432d94b8 */ -]; - -const PR2: [f32; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ - -8.8753431271e-08, /* 0xb3be98b7 */ - -7.0303097367e-02, /* 0xbd8ffb12 */ - -1.4507384300e+00, /* 0xbfb9b1cc */ - -7.6356959343e+00, /* 0xc0f4579f */ - -1.1193166733e+01, /* 0xc1331736 */ - -3.2336456776e+00, /* 0xc04ef40d */ -]; -const PS2: [f32; 5] = [ - 2.2220300674e+01, /* 0x41b1c32d */ - 1.3620678711e+02, /* 0x430834f0 */ - 2.7047027588e+02, /* 0x43873c32 */ - 1.5387539673e+02, /* 0x4319e01a */ - 1.4657617569e+01, /* 0x416a859a */ -]; - -fn pzerof(x: f32) -> f32 -{ - let p: &[f32; 6]; - let q: &[f32; 5]; - let z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 {p = &PR8; q = &PS8;} - else if ix >= 0x409173eb {p = &PR5; q = &PS5;} - else if ix >= 0x4036d917 {p = &PR3; q = &PS3;} - else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); - return 1.0 + r/s; -} - - -/* For x >= 8, the asymptotic expansions of qzero is - * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. - * We approximate pzero by - * qzero(x) = s*(-1.25 + (R/S)) - * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 - * S = 1 + qS0*s^2 + ... + qS5*s^12 - * and - * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) - */ -const QR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - 7.3242187500e-02, /* 0x3d960000 */ - 1.1768206596e+01, /* 0x413c4a93 */ - 5.5767340088e+02, /* 0x440b6b19 */ - 8.8591972656e+03, /* 0x460a6cca */ - 3.7014625000e+04, /* 0x471096a0 */ -]; -const QS8: [f32; 6] = [ - 1.6377603149e+02, /* 0x4323c6aa */ - 8.0983447266e+03, /* 0x45fd12c2 */ - 1.4253829688e+05, /* 0x480b3293 */ - 8.0330925000e+05, /* 0x49441ed4 */ - 8.4050156250e+05, /* 0x494d3359 */ - -3.4389928125e+05, /* 0xc8a7eb69 */ -]; - -const QR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.8408595828e-11, /* 0x2da1ec79 */ - 7.3242180049e-02, /* 0x3d95ffff */ - 5.8356351852e+00, /* 0x40babd86 */ - 1.3511157227e+02, /* 0x43071c90 */ - 1.0272437744e+03, /* 0x448067cd */ - 1.9899779053e+03, /* 0x44f8bf4b */ -]; -const QS5: [f32; 6] = [ - 8.2776611328e+01, /* 0x42a58da0 */ - 2.0778142090e+03, /* 0x4501dd07 */ - 1.8847289062e+04, /* 0x46933e94 */ - 5.6751113281e+04, /* 0x475daf1d */ - 3.5976753906e+04, /* 0x470c88c1 */ - -5.3543427734e+03, /* 0xc5a752be */ -]; - -const QR3: [f32; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - 4.3774099900e-09, /* 0x3196681b */ - 7.3241114616e-02, /* 0x3d95ff70 */ - 3.3442313671e+00, /* 0x405607e3 */ - 4.2621845245e+01, /* 0x422a7cc5 */ - 1.7080809021e+02, /* 0x432acedf */ - 1.6673394775e+02, /* 0x4326bbe4 */ -]; -const QS3: [f32; 6] = [ - 4.8758872986e+01, /* 0x42430916 */ - 7.0968920898e+02, /* 0x44316c1c */ - 3.7041481934e+03, /* 0x4567825f */ - 6.4604252930e+03, /* 0x45c9e367 */ - 2.5163337402e+03, /* 0x451d4557 */ - -1.4924745178e+02, /* 0xc3153f59 */ -]; - -const QR2: [f32; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.5044444979e-07, /* 0x342189db */ - 7.3223426938e-02, /* 0x3d95f62a */ - 1.9981917143e+00, /* 0x3fffc4bf */ - 1.4495602608e+01, /* 0x4167edfd */ - 3.1666231155e+01, /* 0x41fd5471 */ - 1.6252708435e+01, /* 0x4182058c */ -]; -const QS2: [f32; 6] = [ - 3.0365585327e+01, /* 0x41f2ecb8 */ - 2.6934811401e+02, /* 0x4386ac8f */ - 8.4478375244e+02, /* 0x44533229 */ - 8.8293585205e+02, /* 0x445cbbe5 */ - 2.1266638184e+02, /* 0x4354aa98 */ - -5.3109550476e+00, /* 0xc0a9f358 */ -]; - -fn qzerof(x: f32) -> f32 -{ - let p: &[f32; 6]; - let q: &[f32; 6]; - let s: f32; - let r: f32; - let z: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 {p = &QR8; q = &QS8;} - else if ix >= 0x409173eb {p = &QR5; q = &QS5;} - else if ix >= 0x4036d917 {p = &QR3; q = &QS3;} - else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); - return (-0.125 + r/s)/x; -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{cosf, fabsf, logf, sinf, sqrtf}; + +const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ + +fn common(ix: u32, x: f32, y0: bool) -> f32 { + let z: f32; + let s: f32; + let mut c: f32; + let mut ss: f32; + let mut cc: f32; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + s = sinf(x); + c = cosf(x); + if y0 { + c = -c; + } + cc = s + c; + if ix < 0x7f000000 { + ss = s - c; + z = -cosf(2.0 * x); + if s * c < 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x58800000 { + if y0 { + ss = -ss; + } + cc = pzerof(x) * cc - qzerof(x) * ss; + } + } + return INVSQRTPI * cc / sqrtf(x); +} + +/* R0/S0 on [0, 2.00] */ +const R02: f32 = 1.5625000000e-02; /* 0x3c800000 */ +const R03: f32 = -1.8997929874e-04; /* 0xb947352e */ +const R04: f32 = 1.8295404516e-06; /* 0x35f58e88 */ +const R05: f32 = -4.6183270541e-09; /* 0xb19eaf3c */ +const S01: f32 = 1.5619102865e-02; /* 0x3c7fe744 */ +const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ +const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ +const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ + +pub fn j0f(mut x: f32) -> f32 { + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + return 1.0 / (x * x); + } + x = fabsf(x); + + if ix >= 0x40000000 { + /* |x| >= 2 */ + /* large ulp error near zeros */ + return common(ix, x, false); + } + if ix >= 0x3a000000 { + /* |x| >= 2**-11 */ + /* up to 4ulp error near 2 */ + z = x * x; + r = z * (R02 + z * (R03 + z * (R04 + z * R05))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); + return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); + } + if ix >= 0x21800000 { + /* |x| >= 2**-60 */ + x = 0.25 * x * x; + } + return 1.0 - x; +} + +const U00: f32 = -7.3804296553e-02; /* 0xbd9726b5 */ +const U01: f32 = 1.7666645348e-01; /* 0x3e34e80d */ +const U02: f32 = -1.3818567619e-02; /* 0xbc626746 */ +const U03: f32 = 3.4745343146e-04; /* 0x39b62a69 */ +const U04: f32 = -3.8140706238e-06; /* 0xb67ff53c */ +const U05: f32 = 1.9559013964e-08; /* 0x32a802ba */ +const U06: f32 = -3.9820518410e-11; /* 0xae2f21eb */ +const V01: f32 = 1.2730483897e-02; /* 0x3c509385 */ +const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ +const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ +const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ + +pub fn y0f(x: f32) -> f32 { + let z: f32; + let u: f32; + let v: f32; + let ix: u32; + + ix = x.to_bits(); + if (ix & 0x7fffffff) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7f800000 { + return 1.0 / x; + } + if ix >= 0x40000000 { + /* |x| >= 2.0 */ + /* large ulp error near zeros */ + return common(ix, x, true); + } + if ix >= 0x39000000 { + /* x >= 2**-13 */ + /* large ulp error at x ~= 0.89 */ + z = x * x; + u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); + v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); + return u / v + TPI * (j0f(x) * logf(x)); + } + return U00 + TPI * logf(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +const PR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -7.0312500000e-02, /* 0xbd900000 */ + -8.0816707611e+00, /* 0xc1014e86 */ + -2.5706311035e+02, /* 0xc3808814 */ + -2.4852163086e+03, /* 0xc51b5376 */ + -5.2530439453e+03, /* 0xc5a4285a */ +]; +const PS8: [f32; 5] = [ + 1.1653436279e+02, /* 0x42e91198 */ + 3.8337448730e+03, /* 0x456f9beb */ + 4.0597855469e+04, /* 0x471e95db */ + 1.1675296875e+05, /* 0x47e4087c */ + 4.7627726562e+04, /* 0x473a0bba */ +]; +const PR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.1412546255e-11, /* 0xad48c58a */ + -7.0312492549e-02, /* 0xbd8fffff */ + -4.1596107483e+00, /* 0xc0851b88 */ + -6.7674766541e+01, /* 0xc287597b */ + -3.3123129272e+02, /* 0xc3a59d9b */ + -3.4643338013e+02, /* 0xc3ad3779 */ +]; +const PS5: [f32; 5] = [ + 6.0753936768e+01, /* 0x42730408 */ + 1.0512523193e+03, /* 0x44836813 */ + 5.9789707031e+03, /* 0x45bad7c4 */ + 9.6254453125e+03, /* 0x461665c8 */ + 2.4060581055e+03, /* 0x451660ee */ +]; + +const PR3: [f32; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.5470459075e-09, /* 0xb12f081b */ + -7.0311963558e-02, /* 0xbd8fffb8 */ + -2.4090321064e+00, /* 0xc01a2d95 */ + -2.1965976715e+01, /* 0xc1afba52 */ + -5.8079170227e+01, /* 0xc2685112 */ + -3.1447946548e+01, /* 0xc1fb9565 */ +]; +const PS3: [f32; 5] = [ + 3.5856033325e+01, /* 0x420f6c94 */ + 3.6151397705e+02, /* 0x43b4c1ca */ + 1.1936077881e+03, /* 0x44953373 */ + 1.1279968262e+03, /* 0x448cffe6 */ + 1.7358093262e+02, /* 0x432d94b8 */ +]; + +const PR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.8753431271e-08, /* 0xb3be98b7 */ + -7.0303097367e-02, /* 0xbd8ffb12 */ + -1.4507384300e+00, /* 0xbfb9b1cc */ + -7.6356959343e+00, /* 0xc0f4579f */ + -1.1193166733e+01, /* 0xc1331736 */ + -3.2336456776e+00, /* 0xc04ef40d */ +]; +const PS2: [f32; 5] = [ + 2.2220300674e+01, /* 0x41b1c32d */ + 1.3620678711e+02, /* 0x430834f0 */ + 2.7047027588e+02, /* 0x43873c32 */ + 1.5387539673e+02, /* 0x4319e01a */ + 1.4657617569e+01, /* 0x416a859a */ +]; + +fn pzerof(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 5]; + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x409173eb { + p = &PR5; + q = &PS5; + } else if ix >= 0x4036d917 { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +const QR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 7.3242187500e-02, /* 0x3d960000 */ + 1.1768206596e+01, /* 0x413c4a93 */ + 5.5767340088e+02, /* 0x440b6b19 */ + 8.8591972656e+03, /* 0x460a6cca */ + 3.7014625000e+04, /* 0x471096a0 */ +]; +const QS8: [f32; 6] = [ + 1.6377603149e+02, /* 0x4323c6aa */ + 8.0983447266e+03, /* 0x45fd12c2 */ + 1.4253829688e+05, /* 0x480b3293 */ + 8.0330925000e+05, /* 0x49441ed4 */ + 8.4050156250e+05, /* 0x494d3359 */ + -3.4389928125e+05, /* 0xc8a7eb69 */ +]; + +const QR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.8408595828e-11, /* 0x2da1ec79 */ + 7.3242180049e-02, /* 0x3d95ffff */ + 5.8356351852e+00, /* 0x40babd86 */ + 1.3511157227e+02, /* 0x43071c90 */ + 1.0272437744e+03, /* 0x448067cd */ + 1.9899779053e+03, /* 0x44f8bf4b */ +]; +const QS5: [f32; 6] = [ + 8.2776611328e+01, /* 0x42a58da0 */ + 2.0778142090e+03, /* 0x4501dd07 */ + 1.8847289062e+04, /* 0x46933e94 */ + 5.6751113281e+04, /* 0x475daf1d */ + 3.5976753906e+04, /* 0x470c88c1 */ + -5.3543427734e+03, /* 0xc5a752be */ +]; + +const QR3: [f32; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.3774099900e-09, /* 0x3196681b */ + 7.3241114616e-02, /* 0x3d95ff70 */ + 3.3442313671e+00, /* 0x405607e3 */ + 4.2621845245e+01, /* 0x422a7cc5 */ + 1.7080809021e+02, /* 0x432acedf */ + 1.6673394775e+02, /* 0x4326bbe4 */ +]; +const QS3: [f32; 6] = [ + 4.8758872986e+01, /* 0x42430916 */ + 7.0968920898e+02, /* 0x44316c1c */ + 3.7041481934e+03, /* 0x4567825f */ + 6.4604252930e+03, /* 0x45c9e367 */ + 2.5163337402e+03, /* 0x451d4557 */ + -1.4924745178e+02, /* 0xc3153f59 */ +]; + +const QR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.5044444979e-07, /* 0x342189db */ + 7.3223426938e-02, /* 0x3d95f62a */ + 1.9981917143e+00, /* 0x3fffc4bf */ + 1.4495602608e+01, /* 0x4167edfd */ + 3.1666231155e+01, /* 0x41fd5471 */ + 1.6252708435e+01, /* 0x4182058c */ +]; +const QS2: [f32; 6] = [ + 3.0365585327e+01, /* 0x41f2ecb8 */ + 2.6934811401e+02, /* 0x4386ac8f */ + 8.4478375244e+02, /* 0x44533229 */ + 8.8293585205e+02, /* 0x445cbbe5 */ + 2.1266638184e+02, /* 0x4354aa98 */ + -5.3109550476e+00, /* 0xc0a9f358 */ +]; + +fn qzerof(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 6]; + let s: f32; + let r: f32; + let z: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x409173eb { + p = &QR5; + q = &QS5; + } else if ix >= 0x4036d917 { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (-0.125 + r / s) / x; +} diff --git a/library/compiler-builtins/libm/src/math/j1.rs b/library/compiler-builtins/libm/src/math/j1.rs index 92289a61320..02a65ca5a29 100644 --- a/library/compiler-builtins/libm/src/math/j1.rs +++ b/library/compiler-builtins/libm/src/math/j1.rs @@ -1,387 +1,414 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* j1(x), y1(x) - * Bessel function of the first and second kinds of order zero. - * Method -- j1(x): - * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... - * 2. Reduce x to |x| since j1(x)=-j1(-x), and - * for x in (0,2) - * j1(x) = x/2 + x*z*R0/S0, where z = x*x; - * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) - * for x in (2,inf) - * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) - * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) - * as follow: - * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) - * = 1/sqrt(2) * (sin(x) - cos(x)) - * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) - * = -1/sqrt(2) * (sin(x) + cos(x)) - * (To avoid cancellation, use - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - * to compute the worse one.) - * - * 3 Special cases - * j1(nan)= nan - * j1(0) = 0 - * j1(inf) = 0 - * - * Method -- y1(x): - * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN - * 2. For x<2. - * Since - * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) - * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. - * We use the following function to approximate y1, - * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 - * where for x in [0,2] (abs err less than 2**-65.89) - * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 - * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 - * Note: For tiny x, 1/x dominate y1 and hence - * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) - * 3. For x>=2. - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) - * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) - * by method mentioned above. - */ - -use super::{cos, get_high_word, get_low_word, fabs, log, sin, sqrt}; - -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ -const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ - -fn common(ix: u32, x: f64, y1: bool, sign: bool) -> f64 -{ - let z: f64; - let mut s: f64; - let c: f64; - let mut ss: f64; - let mut cc: f64; - - /* - * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) - * - * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) - * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - */ - s = sin(x); - if y1 { - s = -s; - } - c = cos(x); - cc = s-c; - if ix < 0x7fe00000 { - /* avoid overflow in 2*x */ - ss = -s-c; - z = cos(2.0*x); - if s*c > 0.0 { - cc = z/ss; - } else { - ss = z/cc; - } - if ix < 0x48000000 { - if y1 { - ss = -ss; - } - cc = pone(x)*cc-qone(x)*ss; - } - } - if sign { - cc = -cc; - } - return INVSQRTPI*cc/sqrt(x); -} - -/* R0/S0 on [0,2] */ -const R00: f64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ -const R01: f64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ -const R02: f64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ -const R03: f64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ -const S01: f64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ -const S02: f64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ -const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ -const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ -const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ - -pub fn j1(x: f64) -> f64 -{ - let mut z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - let sign: bool; - - ix = get_high_word(x); - sign = (ix>>31) != 0; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - return 1.0/(x*x); - } - if ix >= 0x40000000 { /* |x| >= 2 */ - return common(ix, fabs(x), false, sign); - } - if ix >= 0x38000000 { /* |x| >= 2**-127 */ - z = x*x; - r = z*(R00+z*(R01+z*(R02+z*R03))); - s = 1.0+z*(S01+z*(S02+z*(S03+z*(S04+z*S05)))); - z = r/s; - } else { - /* avoid underflow, raise inexact if x!=0 */ - z = x; - } - return (0.5 + z)*x; -} - -const U0: [f64; 5] = [ - -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ - 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ - -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ - 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ - -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ -]; -const V0: [f64; 5] = [ - 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ - 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ - 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ - 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ - 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ -]; - -pub fn y1(x: f64) -> f64 -{ - let z: f64; - let u: f64; - let v: f64; - let ix: u32; - let lx: u32; - - ix = get_high_word(x); - lx = get_low_word(x); - - /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ - if (ix<<1 | lx) == 0 { - return -1.0/0.0; - } - if (ix>>31) != 0 { - return 0.0/0.0; - } - if ix >= 0x7ff00000 { - return 1.0/x; - } - - if ix >= 0x40000000 { /* x >= 2 */ - return common(ix, x, true, false); - } - if ix < 0x3c900000 { /* x < 2**-54 */ - return -TPI/x; - } - z = x*x; - u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); - v = 1.0+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); - return x*(u/v) + TPI*(j1(x)*log(x)-1.0/x); -} - -/* For x >= 8, the asymptotic expansions of pone is - * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. - * We approximate pone by - * pone(x) = 1 + (R/S) - * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 - * S = 1 + ps0*s^2 + ... + ps4*s^10 - * and - * | pone(x)-1-R/S | <= 2 ** ( -60.06) - */ - -const PR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ - 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ - 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ - 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ - 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ -]; -const PS8: [f64; 5] = [ - 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ - 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ - 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ - 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ - 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ -]; - -const PR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ - 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ - 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ - 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ - 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ - 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ -]; -const PS5: [f64; 5] = [ - 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ - 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ - 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ - 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ - 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ -]; - -const PR3: [f64; 6] = [ - 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ - 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ - 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ - 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ - 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ - 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ -]; -const PS3: [f64; 5] = [ - 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ - 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ - 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ - 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ - 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ -]; - -const PR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ - 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ - 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ - 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ - 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ - 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ -]; -const PS2: [f64; 5] = [ - 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ - 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ - 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ - 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ - 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ -]; - -fn pone(x: f64) -> f64 -{ - let p: &[f64; 6]; - let q: &[f64; 5]; - let z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 {p = &PR8; q = &PS8;} - else if ix >= 0x40122E8B {p = &PR5; q = &PS5;} - else if ix >= 0x4006DB6D {p = &PR3; q = &PS3;} - else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); - return 1.0+ r/s; -} - -/* For x >= 8, the asymptotic expansions of qone is - * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. - * We approximate pone by - * qone(x) = s*(0.375 + (R/S)) - * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 - * S = 1 + qs1*s^2 + ... + qs6*s^12 - * and - * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) - */ - -const QR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ - -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ - -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ - -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ - -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ -]; -const QS8: [f64; 6] = [ - 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ - 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ - 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ - 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ - 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ - -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ -]; - -const QR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ - -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ - -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ - -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ - -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ - -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ -]; -const QS5: [f64; 6] = [ - 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ - 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ - 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ - 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ - 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ - -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ -]; - -const QR3: [f64; 6] = [ - -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ - -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ - -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ - -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ - -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ - -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ -]; -const QS3: [f64; 6] = [ - 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ - 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ - 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ - 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ - 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ - -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ -]; - -const QR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ - -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ - -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ - -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ - -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ - -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ - -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ -]; -const QS2: [f64; 6] = [ - 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ - 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ - 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ - 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ - 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ - -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ -]; - -fn qone(x: f64) -> f64 -{ - let p: &[f64; 6]; - let q: &[f64; 6]; - let s: f64; - let r: f64; - let z: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 {p = &QR8; q = &QS8;} - else if ix >= 0x40122E8B {p = &QR5; q = &QS5;} - else if ix >= 0x4006DB6D {p = &QR3; q = &QS3;} - else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); - return (0.375 + r/s)/x; -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j1(x), y1(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j1(x): + * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... + * 2. Reduce x to |x| since j1(x)=-j1(-x), and + * for x in (0,2) + * j1(x) = x/2 + x*z*R0/S0, where z = x*x; + * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) + * for x in (2,inf) + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * as follow: + * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (sin(x) + cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j1(nan)= nan + * j1(0) = 0 + * j1(inf) = 0 + * + * Method -- y1(x): + * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN + * 2. For x<2. + * Since + * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) + * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. + * We use the following function to approximate y1, + * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 + * where for x in [0,2] (abs err less than 2**-65.89) + * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 + * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 + * Note: For tiny x, 1/x dominate y1 and hence + * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) + * 3. For x>=2. + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * by method mentioned above. + */ + +use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; + +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +fn common(ix: u32, x: f64, y1: bool, sign: bool) -> f64 { + let z: f64; + let mut s: f64; + let c: f64; + let mut ss: f64; + let mut cc: f64; + + /* + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) + * + * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) + * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + if y1 { + s = -s; + } + c = cos(x); + cc = s - c; + if ix < 0x7fe00000 { + /* avoid overflow in 2*x */ + ss = -s - c; + z = cos(2.0 * x); + if s * c > 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x48000000 { + if y1 { + ss = -ss; + } + cc = pone(x) * cc - qone(x) * ss; + } + } + if sign { + cc = -cc; + } + return INVSQRTPI * cc / sqrt(x); +} + +/* R0/S0 on [0,2] */ +const R00: f64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ +const R01: f64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ +const R02: f64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ +const R03: f64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ +const S01: f64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ +const S02: f64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ +const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ +const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ +const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ + +pub fn j1(x: f64) -> f64 { + let mut z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + let sign: bool; + + ix = get_high_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + return 1.0 / (x * x); + } + if ix >= 0x40000000 { + /* |x| >= 2 */ + return common(ix, fabs(x), false, sign); + } + if ix >= 0x38000000 { + /* |x| >= 2**-127 */ + z = x * x; + r = z * (R00 + z * (R01 + z * (R02 + z * R03))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); + z = r / s; + } else { + /* avoid underflow, raise inexact if x!=0 */ + z = x; + } + return (0.5 + z) * x; +} + +const U0: [f64; 5] = [ + -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ + 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ + 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ +]; +const V0: [f64; 5] = [ + 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ + 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ +]; + +pub fn y1(x: f64) -> f64 { + let z: f64; + let u: f64; + let v: f64; + let ix: u32; + let lx: u32; + + ix = get_high_word(x); + lx = get_low_word(x); + + /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ + if (ix << 1 | lx) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7ff00000 { + return 1.0 / x; + } + + if ix >= 0x40000000 { + /* x >= 2 */ + return common(ix, x, true, false); + } + if ix < 0x3c900000 { + /* x < 2**-54 */ + return -TPI / x; + } + z = x * x; + u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + return x * (u / v) + TPI * (j1(x) * log(x) - 1.0 / x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +const PR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ + 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ + 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ + 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ +]; +const PS8: [f64; 5] = [ + 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ + 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ + 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ + 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ + 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ +]; + +const PR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ + 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ + 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ + 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ +]; +const PS5: [f64; 5] = [ + 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ + 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ + 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ + 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ +]; + +const PR3: [f64; 6] = [ + 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ + 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ + 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ + 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ +]; +const PS3: [f64; 5] = [ + 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ + 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ + 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ + 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ + 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ +]; + +const PR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ + 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ + 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ + 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ +]; +const PS2: [f64; 5] = [ + 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ + 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ + 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ + 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ +]; + +fn pone(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 5]; + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x40122E8B { + p = &PR5; + q = &PS5; + } else if ix >= 0x4006DB6D { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +const QR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ + -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ + -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ + -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ + -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ +]; +const QS8: [f64; 6] = [ + 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ + 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ + 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ + 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ + 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ + -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ +]; + +const QR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ + -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ + -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ + -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ + -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ + -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ +]; +const QS5: [f64; 6] = [ + 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ + 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ + 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ + 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ + 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ + -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ +]; + +const QR3: [f64; 6] = [ + -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ + -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ + -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ + -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ + -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ + -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ +]; +const QS3: [f64; 6] = [ + 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ + 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ + 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ + 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ + 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ + -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ +]; + +const QR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ + -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ + -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ + -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ + -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ + -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ +]; +const QS2: [f64; 6] = [ + 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ + 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ + 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ + 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ + 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ + -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ +]; + +fn qone(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 6]; + let s: f64; + let r: f64; + let z: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x40122E8B { + p = &QR5; + q = &QS5; + } else if ix >= 0x4006DB6D { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (0.375 + r / s) / x; +} diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 7cf9c45b98e..83ac1acffdc 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -1,331 +1,358 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{cosf, fabsf, logf, sinf, sqrtf}; - -const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ -const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ - -fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 -{ - let z: f64; - let mut s: f64; - let c: f64; - let mut ss: f64; - let mut cc: f64; - - s = sinf(x) as f64; - if y1 { - s = -s; - } - c = cosf(x) as f64; - cc = s-c; - if ix < 0x7f000000 { - ss = -s-c; - z = cosf(2.0*x) as f64; - if s*c > 0.0 { - cc = z/ss; - } else { - ss = z/cc; - } - if ix < 0x58800000 { - if y1 { - ss = -ss; - } - cc = (ponef(x) as f64)*cc-(qonef(x) as f64)*ss; - } - } - if sign { - cc = -cc; - } - return INVSQRTPI*(cc as f32)/sqrtf(x); -} - -/* R0/S0 on [0,2] */ -const R00: f32 = -6.2500000000e-02; /* 0xbd800000 */ -const R01: f32 = 1.4070566976e-03; /* 0x3ab86cfd */ -const R02: f32 = -1.5995563444e-05; /* 0xb7862e36 */ -const R03: f32 = 4.9672799207e-08; /* 0x335557d2 */ -const S01: f32 = 1.9153760746e-02; /* 0x3c9ce859 */ -const S02: f32 = 1.8594678841e-04; /* 0x3942fab6 */ -const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ -const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ -const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ - -pub fn j1f(x: f32) -> f32 -{ - let mut z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - let sign: bool; - - ix = x.to_bits(); - sign = (ix>>31) != 0; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - return 1.0/(x*x); - } - if ix >= 0x40000000 { /* |x| >= 2 */ - return common(ix, fabsf(x), false, sign); - } - if ix >= 0x39000000 { /* |x| >= 2**-13 */ - z = x*x; - r = z*(R00+z*(R01+z*(R02+z*R03))); - s = 1.0+z*(S01+z*(S02+z*(S03+z*(S04+z*S05)))); - z = 0.5 + r/s; - } else { - z = 0.5; - } - return z*x; -} - -const U0: [f32; 5] = [ - -1.9605709612e-01, /* 0xbe48c331 */ - 5.0443872809e-02, /* 0x3d4e9e3c */ - -1.9125689287e-03, /* 0xbafaaf2a */ - 2.3525259166e-05, /* 0x37c5581c */ - -9.1909917899e-08, /* 0xb3c56003 */ -]; -const V0: [f32; 5] = [ - 1.9916731864e-02, /* 0x3ca3286a */ - 2.0255257550e-04, /* 0x3954644b */ - 1.3560879779e-06, /* 0x35b602d4 */ - 6.2274145840e-09, /* 0x31d5f8eb */ - 1.6655924903e-11, /* 0x2d9281cf */ -]; - -pub fn y1f(x: f32) -> f32 -{ - let z: f32; - let u: f32; - let v: f32; - let ix: u32; - - ix = x.to_bits(); - if (ix & 0x7fffffff) == 0 { - return -1.0/0.0; - } - if (ix>>31) != 0{ - return 0.0/0.0; - } - if ix >= 0x7f800000 { - return 1.0/x; - } - if ix >= 0x40000000 { /* |x| >= 2.0 */ - return common(ix,x,true,false); - } - if ix < 0x33000000 { /* x < 2**-25 */ - return -TPI/x; - } - z = x*x; - u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); - v = 1.0+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); - return x*(u/v) + TPI*(j1f(x)*logf(x)-1.0/x); -} - -/* For x >= 8, the asymptotic expansions of pone is - * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. - * We approximate pone by - * pone(x) = 1 + (R/S) - * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 - * S = 1 + ps0*s^2 + ... + ps4*s^10 - * and - * | pone(x)-1-R/S | <= 2 ** ( -60.06) - */ - -const PR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - 1.1718750000e-01, /* 0x3df00000 */ - 1.3239480972e+01, /* 0x4153d4ea */ - 4.1205184937e+02, /* 0x43ce06a3 */ - 3.8747453613e+03, /* 0x45722bed */ - 7.9144794922e+03, /* 0x45f753d6 */ -]; -const PS8: [f32; 5] = [ - 1.1420736694e+02, /* 0x42e46a2c */ - 3.6509309082e+03, /* 0x45642ee5 */ - 3.6956207031e+04, /* 0x47105c35 */ - 9.7602796875e+04, /* 0x47bea166 */ - 3.0804271484e+04, /* 0x46f0a88b */ -]; - -const PR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.3199052094e-11, /* 0x2d68333f */ - 1.1718749255e-01, /* 0x3defffff */ - 6.8027510643e+00, /* 0x40d9b023 */ - 1.0830818176e+02, /* 0x42d89dca */ - 5.1763616943e+02, /* 0x440168b7 */ - 5.2871520996e+02, /* 0x44042dc6 */ -]; -const PS5: [f32; 5] = [ - 5.9280597687e+01, /* 0x426d1f55 */ - 9.9140142822e+02, /* 0x4477d9b1 */ - 5.3532670898e+03, /* 0x45a74a23 */ - 7.8446904297e+03, /* 0x45f52586 */ - 1.5040468750e+03, /* 0x44bc0180 */ -]; - -const PR3: [f32; 6] = [ - 3.0250391081e-09, /* 0x314fe10d */ - 1.1718686670e-01, /* 0x3defffab */ - 3.9329774380e+00, /* 0x407bb5e7 */ - 3.5119403839e+01, /* 0x420c7a45 */ - 9.1055007935e+01, /* 0x42b61c2a */ - 4.8559066772e+01, /* 0x42423c7c */ -]; -const PS3: [f32; 5] = [ - 3.4791309357e+01, /* 0x420b2a4d */ - 3.3676245117e+02, /* 0x43a86198 */ - 1.0468714600e+03, /* 0x4482dbe3 */ - 8.9081134033e+02, /* 0x445eb3ed */ - 1.0378793335e+02, /* 0x42cf936c */ -]; - -const PR2: [f32; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.0771083225e-07, /* 0x33e74ea8 */ - 1.1717621982e-01, /* 0x3deffa16 */ - 2.3685150146e+00, /* 0x401795c0 */ - 1.2242610931e+01, /* 0x4143e1bc */ - 1.7693971634e+01, /* 0x418d8d41 */ - 5.0735230446e+00, /* 0x40a25a4d */ -]; -const PS2: [f32; 5] = [ - 2.1436485291e+01, /* 0x41ab7dec */ - 1.2529022980e+02, /* 0x42fa9499 */ - 2.3227647400e+02, /* 0x436846c7 */ - 1.1767937469e+02, /* 0x42eb5bd7 */ - 8.3646392822e+00, /* 0x4105d590 */ -]; - -fn ponef(x: f32) -> f32 -{ - let p: &[f32; 6]; - let q: &[f32; 5]; - let z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 {p = &PR8; q = &PS8;} - else if ix >= 0x409173eb {p = &PR5; q = &PS5;} - else if ix >= 0x4036d917 {p = &PR3; q = &PS3;} - else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); - return 1.0 + r/s; -} - -/* For x >= 8, the asymptotic expansions of qone is - * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. - * We approximate pone by - * qone(x) = s*(0.375 + (R/S)) - * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 - * S = 1 + qs1*s^2 + ... + qs6*s^12 - * and - * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) - */ - -const QR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - -1.0253906250e-01, /* 0xbdd20000 */ - -1.6271753311e+01, /* 0xc1822c8d */ - -7.5960174561e+02, /* 0xc43de683 */ - -1.1849806641e+04, /* 0xc639273a */ - -4.8438511719e+04, /* 0xc73d3683 */ -]; -const QS8: [f32; 6] = [ - 1.6139537048e+02, /* 0x43216537 */ - 7.8253862305e+03, /* 0x45f48b17 */ - 1.3387534375e+05, /* 0x4802bcd6 */ - 7.1965775000e+05, /* 0x492fb29c */ - 6.6660125000e+05, /* 0x4922be94 */ - -2.9449025000e+05, /* 0xc88fcb48 */ -]; - -const QR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -2.0897993405e-11, /* 0xadb7d219 */ - -1.0253904760e-01, /* 0xbdd1fffe */ - -8.0564479828e+00, /* 0xc100e736 */ - -1.8366960144e+02, /* 0xc337ab6b */ - -1.3731937256e+03, /* 0xc4aba633 */ - -2.6124443359e+03, /* 0xc523471c */ -]; -const QS5: [f32; 6] = [ - 8.1276550293e+01, /* 0x42a28d98 */ - 1.9917987061e+03, /* 0x44f8f98f */ - 1.7468484375e+04, /* 0x468878f8 */ - 4.9851425781e+04, /* 0x4742bb6d */ - 2.7948074219e+04, /* 0x46da5826 */ - -4.7191835938e+03, /* 0xc5937978 */ -]; - -const QR3: [f32; 6] = [ - -5.0783124372e-09, /* 0xb1ae7d4f */ - -1.0253783315e-01, /* 0xbdd1ff5b */ - -4.6101160049e+00, /* 0xc0938612 */ - -5.7847221375e+01, /* 0xc267638e */ - -2.2824453735e+02, /* 0xc3643e9a */ - -2.1921012878e+02, /* 0xc35b35cb */ -]; -const QS3: [f32; 6] = [ - 4.7665153503e+01, /* 0x423ea91e */ - 6.7386511230e+02, /* 0x4428775e */ - 3.3801528320e+03, /* 0x45534272 */ - 5.5477290039e+03, /* 0x45ad5dd5 */ - 1.9031191406e+03, /* 0x44ede3d0 */ - -1.3520118713e+02, /* 0xc3073381 */ -]; - -const QR2: [f32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -1.7838172539e-07, /* 0xb43f8932 */ - -1.0251704603e-01, /* 0xbdd1f475 */ - -2.7522056103e+00, /* 0xc0302423 */ - -1.9663616180e+01, /* 0xc19d4f16 */ - -4.2325313568e+01, /* 0xc2294d1f */ - -2.1371921539e+01, /* 0xc1aaf9b2 */ -]; -const QS2: [f32; 6] = [ - 2.9533363342e+01, /* 0x41ec4454 */ - 2.5298155212e+02, /* 0x437cfb47 */ - 7.5750280762e+02, /* 0x443d602e */ - 7.3939318848e+02, /* 0x4438d92a */ - 1.5594900513e+02, /* 0x431bf2f2 */ - -4.9594988823e+00, /* 0xc09eb437 */ -]; - -fn qonef(x: f32) -> f32 -{ - let p: &[f32; 6]; - let q: &[f32; 6]; - let s: f32; - let r: f32; - let z: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 {p = &QR8; q = &QS8;} - else if ix >= 0x409173eb {p = &QR5; q = &QS5;} - else if ix >= 0x4036d917 {p = &QR3; q = &QS3;} - else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); - return (0.375 + r/s)/x; -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{cosf, fabsf, logf, sinf, sqrtf}; + +const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ + +fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 { + let z: f64; + let mut s: f64; + let c: f64; + let mut ss: f64; + let mut cc: f64; + + s = sinf(x) as f64; + if y1 { + s = -s; + } + c = cosf(x) as f64; + cc = s - c; + if ix < 0x7f000000 { + ss = -s - c; + z = cosf(2.0 * x) as f64; + if s * c > 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x58800000 { + if y1 { + ss = -ss; + } + cc = (ponef(x) as f64) * cc - (qonef(x) as f64) * ss; + } + } + if sign { + cc = -cc; + } + return INVSQRTPI * (cc as f32) / sqrtf(x); +} + +/* R0/S0 on [0,2] */ +const R00: f32 = -6.2500000000e-02; /* 0xbd800000 */ +const R01: f32 = 1.4070566976e-03; /* 0x3ab86cfd */ +const R02: f32 = -1.5995563444e-05; /* 0xb7862e36 */ +const R03: f32 = 4.9672799207e-08; /* 0x335557d2 */ +const S01: f32 = 1.9153760746e-02; /* 0x3c9ce859 */ +const S02: f32 = 1.8594678841e-04; /* 0x3942fab6 */ +const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ +const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ +const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ + +pub fn j1f(x: f32) -> f32 { + let mut z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + let sign: bool; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + return 1.0 / (x * x); + } + if ix >= 0x40000000 { + /* |x| >= 2 */ + return common(ix, fabsf(x), false, sign); + } + if ix >= 0x39000000 { + /* |x| >= 2**-13 */ + z = x * x; + r = z * (R00 + z * (R01 + z * (R02 + z * R03))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); + z = 0.5 + r / s; + } else { + z = 0.5; + } + return z * x; +} + +const U0: [f32; 5] = [ + -1.9605709612e-01, /* 0xbe48c331 */ + 5.0443872809e-02, /* 0x3d4e9e3c */ + -1.9125689287e-03, /* 0xbafaaf2a */ + 2.3525259166e-05, /* 0x37c5581c */ + -9.1909917899e-08, /* 0xb3c56003 */ +]; +const V0: [f32; 5] = [ + 1.9916731864e-02, /* 0x3ca3286a */ + 2.0255257550e-04, /* 0x3954644b */ + 1.3560879779e-06, /* 0x35b602d4 */ + 6.2274145840e-09, /* 0x31d5f8eb */ + 1.6655924903e-11, /* 0x2d9281cf */ +]; + +pub fn y1f(x: f32) -> f32 { + let z: f32; + let u: f32; + let v: f32; + let ix: u32; + + ix = x.to_bits(); + if (ix & 0x7fffffff) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7f800000 { + return 1.0 / x; + } + if ix >= 0x40000000 { + /* |x| >= 2.0 */ + return common(ix, x, true, false); + } + if ix < 0x33000000 { + /* x < 2**-25 */ + return -TPI / x; + } + z = x * x; + u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + return x * (u / v) + TPI * (j1f(x) * logf(x) - 1.0 / x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +const PR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 1.1718750000e-01, /* 0x3df00000 */ + 1.3239480972e+01, /* 0x4153d4ea */ + 4.1205184937e+02, /* 0x43ce06a3 */ + 3.8747453613e+03, /* 0x45722bed */ + 7.9144794922e+03, /* 0x45f753d6 */ +]; +const PS8: [f32; 5] = [ + 1.1420736694e+02, /* 0x42e46a2c */ + 3.6509309082e+03, /* 0x45642ee5 */ + 3.6956207031e+04, /* 0x47105c35 */ + 9.7602796875e+04, /* 0x47bea166 */ + 3.0804271484e+04, /* 0x46f0a88b */ +]; + +const PR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.3199052094e-11, /* 0x2d68333f */ + 1.1718749255e-01, /* 0x3defffff */ + 6.8027510643e+00, /* 0x40d9b023 */ + 1.0830818176e+02, /* 0x42d89dca */ + 5.1763616943e+02, /* 0x440168b7 */ + 5.2871520996e+02, /* 0x44042dc6 */ +]; +const PS5: [f32; 5] = [ + 5.9280597687e+01, /* 0x426d1f55 */ + 9.9140142822e+02, /* 0x4477d9b1 */ + 5.3532670898e+03, /* 0x45a74a23 */ + 7.8446904297e+03, /* 0x45f52586 */ + 1.5040468750e+03, /* 0x44bc0180 */ +]; + +const PR3: [f32; 6] = [ + 3.0250391081e-09, /* 0x314fe10d */ + 1.1718686670e-01, /* 0x3defffab */ + 3.9329774380e+00, /* 0x407bb5e7 */ + 3.5119403839e+01, /* 0x420c7a45 */ + 9.1055007935e+01, /* 0x42b61c2a */ + 4.8559066772e+01, /* 0x42423c7c */ +]; +const PS3: [f32; 5] = [ + 3.4791309357e+01, /* 0x420b2a4d */ + 3.3676245117e+02, /* 0x43a86198 */ + 1.0468714600e+03, /* 0x4482dbe3 */ + 8.9081134033e+02, /* 0x445eb3ed */ + 1.0378793335e+02, /* 0x42cf936c */ +]; + +const PR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.0771083225e-07, /* 0x33e74ea8 */ + 1.1717621982e-01, /* 0x3deffa16 */ + 2.3685150146e+00, /* 0x401795c0 */ + 1.2242610931e+01, /* 0x4143e1bc */ + 1.7693971634e+01, /* 0x418d8d41 */ + 5.0735230446e+00, /* 0x40a25a4d */ +]; +const PS2: [f32; 5] = [ + 2.1436485291e+01, /* 0x41ab7dec */ + 1.2529022980e+02, /* 0x42fa9499 */ + 2.3227647400e+02, /* 0x436846c7 */ + 1.1767937469e+02, /* 0x42eb5bd7 */ + 8.3646392822e+00, /* 0x4105d590 */ +]; + +fn ponef(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 5]; + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x409173eb { + p = &PR5; + q = &PS5; + } else if ix >= 0x4036d917 { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +const QR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -1.0253906250e-01, /* 0xbdd20000 */ + -1.6271753311e+01, /* 0xc1822c8d */ + -7.5960174561e+02, /* 0xc43de683 */ + -1.1849806641e+04, /* 0xc639273a */ + -4.8438511719e+04, /* 0xc73d3683 */ +]; +const QS8: [f32; 6] = [ + 1.6139537048e+02, /* 0x43216537 */ + 7.8253862305e+03, /* 0x45f48b17 */ + 1.3387534375e+05, /* 0x4802bcd6 */ + 7.1965775000e+05, /* 0x492fb29c */ + 6.6660125000e+05, /* 0x4922be94 */ + -2.9449025000e+05, /* 0xc88fcb48 */ +]; + +const QR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.0897993405e-11, /* 0xadb7d219 */ + -1.0253904760e-01, /* 0xbdd1fffe */ + -8.0564479828e+00, /* 0xc100e736 */ + -1.8366960144e+02, /* 0xc337ab6b */ + -1.3731937256e+03, /* 0xc4aba633 */ + -2.6124443359e+03, /* 0xc523471c */ +]; +const QS5: [f32; 6] = [ + 8.1276550293e+01, /* 0x42a28d98 */ + 1.9917987061e+03, /* 0x44f8f98f */ + 1.7468484375e+04, /* 0x468878f8 */ + 4.9851425781e+04, /* 0x4742bb6d */ + 2.7948074219e+04, /* 0x46da5826 */ + -4.7191835938e+03, /* 0xc5937978 */ +]; + +const QR3: [f32; 6] = [ + -5.0783124372e-09, /* 0xb1ae7d4f */ + -1.0253783315e-01, /* 0xbdd1ff5b */ + -4.6101160049e+00, /* 0xc0938612 */ + -5.7847221375e+01, /* 0xc267638e */ + -2.2824453735e+02, /* 0xc3643e9a */ + -2.1921012878e+02, /* 0xc35b35cb */ +]; +const QS3: [f32; 6] = [ + 4.7665153503e+01, /* 0x423ea91e */ + 6.7386511230e+02, /* 0x4428775e */ + 3.3801528320e+03, /* 0x45534272 */ + 5.5477290039e+03, /* 0x45ad5dd5 */ + 1.9031191406e+03, /* 0x44ede3d0 */ + -1.3520118713e+02, /* 0xc3073381 */ +]; + +const QR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.7838172539e-07, /* 0xb43f8932 */ + -1.0251704603e-01, /* 0xbdd1f475 */ + -2.7522056103e+00, /* 0xc0302423 */ + -1.9663616180e+01, /* 0xc19d4f16 */ + -4.2325313568e+01, /* 0xc2294d1f */ + -2.1371921539e+01, /* 0xc1aaf9b2 */ +]; +const QS2: [f32; 6] = [ + 2.9533363342e+01, /* 0x41ec4454 */ + 2.5298155212e+02, /* 0x437cfb47 */ + 7.5750280762e+02, /* 0x443d602e */ + 7.3939318848e+02, /* 0x4438d92a */ + 1.5594900513e+02, /* 0x431bf2f2 */ + -4.9594988823e+00, /* 0xc09eb437 */ +]; + +fn qonef(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 6]; + let s: f32; + let r: f32; + let z: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x409173eb { + p = &QR5; + q = &QS5; + } else if ix >= 0x4036d917 { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (0.375 + r / s) / x; +} diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs index 7f7c06feed2..70c98026685 100644 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -1,338 +1,343 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* - * jn(n, x), yn(n, x) - * floating point Bessel's function of the 1st and 2nd kind - * of order n - * - * Special cases: - * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; - * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. - * Note 2. About jn(n,x), yn(n,x) - * For n=0, j0(x) is called, - * for n=1, j1(x) is called, - * for n<=x, forward recursion is used starting - * from values of j0(x) and j1(x). - * for n>x, a continued fraction approximation to - * j(n,x)/j(n-1,x) is evaluated and then backward - * recursion is used starting from a supposed value - * for j(n,x). The resulting value of j(0,x) is - * compared with the actual value to correct the - * supposed value of j(n,x). - * - * yn(n,x) is similar in all respects, except - * that forward recursion is used for all - * values of n>1. - */ - -use super::{cos, fabs, get_high_word, get_low_word, log, j0, j1, sin, sqrt, y0, y1}; - -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ - -pub fn jn(n: isize, mut x: f64) -> f64 -{ - let mut ix: u32; - let lx: u32; - let nm1: isize; - let mut i: isize; - let mut sign: bool; - let mut a: f64; - let mut b: f64; - let mut temp: f64; - - ix = get_high_word(x); - lx = get_low_word(x); - sign = (ix>>31) != 0; - ix &= 0x7fffffff; - - // -lx == !lx + 1 - if (ix | (lx|(!lx+1))>>31) > 0x7ff00000 { /* nan */ - return x; - } - - /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) - * Thus, J(-n,x) = J(n,-x) - */ - /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ - if n == 0 { - return j0(x); - } - if n < 0 { - nm1 = -(n+1); - x = -x; - sign = !sign; - } else { - nm1 = n-1; - } - if nm1 == 0 { - return j1(x); - } - - sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ - x = fabs(x); - if (ix|lx) == 0 || ix == 0x7ff00000 { /* if x is 0 or inf */ - b = 0.0; - } else if (nm1 as f64) < x { - /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ - if ix >= 0x52d00000 { /* x > 2**302 */ - /* (x >> n**2) - * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Let s=sin(x), c=cos(x), - * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then - * - * n sin(xn)*sqt2 cos(xn)*sqt2 - * ---------------------------------- - * 0 s-c c+s - * 1 -s-c -c+s - * 2 -s+c -c-s - * 3 s+c c-s - */ - temp = match nm1&3 { - 0 => -cos(x)+sin(x), - 1 => -cos(x)-sin(x), - 2 => cos(x)-sin(x), - 3 | _ => cos(x)+sin(x), - }; - b = INVSQRTPI*temp/sqrt(x); - } else { - a = j0(x); - b = j1(x); - i = 0; - while i < nm1 { - i += 1; - temp = b; - b = b*(2.0*(i as f64)/x) - a; /* avoid underflow */ - a = temp; - } - } - } else { - if ix < 0x3e100000 { /* x < 2**-29 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 32 { /* underflow */ - b = 0.0; - } else { - temp = x*0.5; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as f64; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b/a; - } - } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: f64; - let mut q0: f64; - let mut q1: f64; - let mut w: f64; - let h: f64; - let mut z: f64; - let mut tmp: f64; - let nf: f64; - - let mut k: isize; - - nf = (nm1 as f64) + 1.0; - w = 2.0*nf/x; - h = 2.0/x; - z = w+h; - q0 = w; - q1 = w*z - 1.0; - k = 1; - while q1 < 1.0e9 { - k += 1; - z += h; - tmp = z*q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0/(2.0*((i as f64)+nf)/x - t); - i -= 1; - } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf*log(fabs(w)); - if tmp < 7.09782712893383973096e+02 { - i = nm1; - while i > 0 { - temp = b; - b = b*(2.0*(i as f64))/x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = b*(2.0*(i as f64))/x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 - if b > x1p500 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; - } - } - z = j0(x); - w = j1(x); - if fabs(z) >= fabs(w) { - b = t*z/b; - } else { - b = t*w/a; - } - } - } - - if sign { - -b - } else { - b - } -} - - -pub fn yn(n: isize, x: f64) -> f64 -{ - let mut ix: u32; - let lx: u32; - let mut ib: u32; - let nm1: isize; - let mut sign: bool; - let mut i: isize; - let mut a: f64; - let mut b: f64; - let mut temp: f64; - - ix = get_high_word(x); - lx = get_low_word(x); - sign = (ix>>31) != 0; - ix &= 0x7fffffff; - - // -lx == !lx + 1 - if (ix | (lx|(!lx+1))>>31) > 0x7ff00000 { /* nan */ - return x; - } - if sign && (ix|lx) != 0 { /* x < 0 */ - return 0.0/0.0; - } - if ix == 0x7ff00000 { - return 0.0; - } - - if n == 0 { - return y0(x); - } - if n < 0 { - nm1 = -(n+1); - sign = (n&1) != 0; - } else { - nm1 = n-1; - sign = false; - } - if nm1 == 0 { - if sign { - return -y1(x); - } else { - return y1(x); - } - } - - if ix >= 0x52d00000 { /* x > 2**302 */ - /* (x >> n**2) - * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Let s=sin(x), c=cos(x), - * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then - * - * n sin(xn)*sqt2 cos(xn)*sqt2 - * ---------------------------------- - * 0 s-c c+s - * 1 -s-c -c+s - * 2 -s+c -c-s - * 3 s+c c-s - */ - temp = match nm1&3 { - 0 => -sin(x)-cos(x), - 1 => -sin(x)+cos(x), - 2 => sin(x)+cos(x), - 3 | _ => sin(x)-cos(x), - }; - b = INVSQRTPI*temp/sqrt(x); - } else { - a = y0(x); - b = y1(x); - /* quit if b is -inf */ - ib = get_high_word(b); - i = 0; - while i < nm1 && ib != 0xfff00000 { - i += 1; - temp = b; - b = (2.0*(i as f64)/x)*b - a; - ib = get_high_word(b); - a = temp; - } - } - - if sign { - -b - } else { - b - } -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * jn(n, x), yn(n, x) + * floating point Bessel's function of the 1st and 2nd kind + * of order n + * + * Special cases: + * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; + * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. + * Note 2. About jn(n,x), yn(n,x) + * For n=0, j0(x) is called, + * for n=1, j1(x) is called, + * for n<=x, forward recursion is used starting + * from values of j0(x) and j1(x). + * for n>x, a continued fraction approximation to + * j(n,x)/j(n-1,x) is evaluated and then backward + * recursion is used starting from a supposed value + * for j(n,x). The resulting value of j(0,x) is + * compared with the actual value to correct the + * supposed value of j(n,x). + * + * yn(n,x) is similar in all respects, except + * that forward recursion is used for all + * values of n>1. + */ + +use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, y1}; + +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ + +pub fn jn(n: i32, mut x: f64) -> f64 { + let mut ix: u32; + let lx: u32; + let nm1: i32; + let mut i: i32; + let mut sign: bool; + let mut a: f64; + let mut b: f64; + let mut temp: f64; + + ix = get_high_word(x); + lx = get_low_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + // -lx == !lx + 1 + if (ix | (lx | (!lx + 1)) >> 31) > 0x7ff00000 { + /* nan */ + return x; + } + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ + if n == 0 { + return j0(x); + } + if n < 0 { + nm1 = -(n + 1); + x = -x; + sign = !sign; + } else { + nm1 = n - 1; + } + if nm1 == 0 { + return j1(x); + } + + sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabs(x); + if (ix | lx) == 0 || ix == 0x7ff00000 { + /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as f64) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + if ix >= 0x52d00000 { + /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + temp = match nm1 & 3 { + 0 => -cos(x) + sin(x), + 1 => -cos(x) - sin(x), + 2 => cos(x) - sin(x), + 3 | _ => cos(x) + sin(x), + }; + b = INVSQRTPI * temp / sqrt(x); + } else { + a = j0(x); + b = j1(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b * (2.0 * (i as f64) / x) - a; /* avoid underflow */ + a = temp; + } + } + } else { + if ix < 0x3e100000 { + /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 32 { + /* underflow */ + b = 0.0; + } else { + temp = x * 0.5; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f64; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f64; + let mut q0: f64; + let mut q1: f64; + let mut w: f64; + let h: f64; + let mut z: f64; + let mut tmp: f64; + let nf: f64; + + let mut k: i32; + + nf = (nm1 as f64) + 1.0; + w = 2.0 * nf / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e9 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as f64) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * log(fabs(w)); + if tmp < 7.09782712893383973096e+02 { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as f64)) / x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as f64)) / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 + if b > x1p500 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0(x); + w = j1(x); + if fabs(z) >= fabs(w) { + b = t * z / b; + } else { + b = t * w / a; + } + } + } + + if sign { + -b + } else { + b + } +} + +pub fn yn(n: i32, x: f64) -> f64 { + let mut ix: u32; + let lx: u32; + let mut ib: u32; + let nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f64; + let mut b: f64; + let mut temp: f64; + + ix = get_high_word(x); + lx = get_low_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + // -lx == !lx + 1 + if (ix | (lx | (!lx + 1)) >> 31) > 0x7ff00000 { + /* nan */ + return x; + } + if sign && (ix | lx) != 0 { + /* x < 0 */ + return 0.0 / 0.0; + } + if ix == 0x7ff00000 { + return 0.0; + } + + if n == 0 { + return y0(x); + } + if n < 0 { + nm1 = -(n + 1); + sign = (n & 1) != 0; + } else { + nm1 = n - 1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1(x); + } else { + return y1(x); + } + } + + if ix >= 0x52d00000 { + /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + temp = match nm1 & 3 { + 0 => -sin(x) - cos(x), + 1 => -sin(x) + cos(x), + 2 => sin(x) + cos(x), + 3 | _ => sin(x) - cos(x), + }; + b = INVSQRTPI * temp / sqrt(x); + } else { + a = y0(x); + b = y1(x); + /* quit if b is -inf */ + ib = get_high_word(b); + i = 0; + while i < nm1 && ib != 0xfff00000 { + i += 1; + temp = b; + b = (2.0 * (i as f64) / x) * b - a; + ib = get_high_word(b); + a = temp; + } + } + + if sign { + -b + } else { + b + } +} diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs index 4cd848a03b0..360f62e201d 100644 --- a/library/compiler-builtins/libm/src/math/jnf.rs +++ b/library/compiler-builtins/libm/src/math/jnf.rs @@ -1,255 +1,259 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{fabsf, j0f, j1f, logf, y0f, y1f}; - -pub fn jnf(n: isize, mut x: f32) -> f32 -{ - let mut ix: u32; - let mut nm1: isize; - let mut sign: bool; - let mut i: isize; - let mut a: f32; - let mut b: f32; - let mut temp: f32; - - ix = x.to_bits(); - sign = (ix>>31) != 0; - ix &= 0x7fffffff; - if ix > 0x7f800000 { /* nan */ - return x; - } - - /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ - if n == 0 { - return j0f(x); - } - if n < 0 { - nm1 = -(n+1); - x = -x; - sign = !sign; - } else { - nm1 = n-1; - } - if nm1 == 0 { - return j1f(x); - } - - sign &= (n&1) != 0; /* even n: 0, odd n: signbit(x) */ - x = fabsf(x); - if ix == 0 || ix == 0x7f800000 { /* if x is 0 or inf */ - b = 0.0; - } else if (nm1 as f32) < x { - /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ - a = j0f(x); - b = j1f(x); - i = 0; - while i < nm1 { - i += 1; - temp = b; - b = b*(2.0*(i as f32)/x) - a; - a = temp; - } - } else { - if ix < 0x35800000 { /* x < 2**-20 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 8 { /* underflow */ - nm1 = 8; - } - temp = 0.5 * x; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as f32; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b/a; - } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: f32; - let mut q0: f32; - let mut q1: f32; - let mut w: f32; - let h: f32; - let mut z: f32; - let mut tmp: f32; - let nf: f32; - let mut k: isize; - - nf = (nm1 as f32)+1.0; - w = 2.0*(nf as f32)/x; - h = 2.0/x; - z = w+h; - q0 = w; - q1 = w*z - 1.0; - k = 1; - while q1 < 1.0e4 { - k += 1; - z += h; - tmp = z*q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0/(2.0*((i as f32)+nf)/x-t); - i -= 1; - } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf*logf(fabsf(w)); - if tmp < 88.721679688 { - i = nm1; - while i > 0 { - temp = b; - b = 2.0*(i as f32)*b/x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = 2.0*(i as f32)*b/x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 - if b > x1p60 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; - } - } - z = j0f(x); - w = j1f(x); - if fabsf(z) >= fabsf(w) { - b = t*z/b; - } else { - b = t*w/a; - } - } - } - - if sign { - -b - } else { - b - } -} - -pub fn ynf(n: isize, x: f32) -> f32 -{ - let mut ix: u32; - let mut ib: u32; - let nm1: isize; - let mut sign: bool; - let mut i: isize; - let mut a: f32; - let mut b: f32; - let mut temp: f32; - - ix = x.to_bits(); - sign = (ix>>31) != 0; - ix &= 0x7fffffff; - if ix > 0x7f800000 { /* nan */ - return x; - } - if sign && ix != 0 { /* x < 0 */ - return 0.0/0.0; - } - if ix == 0x7f800000 { - return 0.0; - } - - if n == 0 { - return y0f(x); - } - if n < 0 { - nm1 = -(n+1); - sign = (n&1) != 0; - } else { - nm1 = n-1; - sign = false; - } - if nm1 == 0 { - if sign { - return -y1f(x); - } else { - return y1f(x); - } - } - - a = y0f(x); - b = y1f(x); - /* quit if b is -inf */ - ib = b.to_bits(); - i = 0; - while i < nm1 && ib != 0xff800000 { - i += 1; - temp = b; - b = (2.0*(i as f32)/x)*b - a; - ib = b.to_bits(); - a = temp; - } - - if sign { - -b - } else { - b - } -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{fabsf, j0f, j1f, logf, y0f, y1f}; + +pub fn jnf(n: i32, mut x: f32) -> f32 { + let mut ix: u32; + let mut nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f32; + let mut b: f32; + let mut temp: f32; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { + /* nan */ + return x; + } + + /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ + if n == 0 { + return j0f(x); + } + if n < 0 { + nm1 = -(n + 1); + x = -x; + sign = !sign; + } else { + nm1 = n - 1; + } + if nm1 == 0 { + return j1f(x); + } + + sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabsf(x); + if ix == 0 || ix == 0x7f800000 { + /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as f32) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + a = j0f(x); + b = j1f(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b * (2.0 * (i as f32) / x) - a; + a = temp; + } + } else { + if ix < 0x35800000 { + /* x < 2**-20 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 8 { + /* underflow */ + nm1 = 8; + } + temp = 0.5 * x; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f32; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f32; + let mut q0: f32; + let mut q1: f32; + let mut w: f32; + let h: f32; + let mut z: f32; + let mut tmp: f32; + let nf: f32; + let mut k: i32; + + nf = (nm1 as f32) + 1.0; + w = 2.0 * (nf as f32) / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e4 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as f32) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * logf(fabsf(w)); + if tmp < 88.721679688 { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as f32) * b / x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as f32) * b / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 + if b > x1p60 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0f(x); + w = j1f(x); + if fabsf(z) >= fabsf(w) { + b = t * z / b; + } else { + b = t * w / a; + } + } + } + + if sign { + -b + } else { + b + } +} + +pub fn ynf(n: i32, x: f32) -> f32 { + let mut ix: u32; + let mut ib: u32; + let nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f32; + let mut b: f32; + let mut temp: f32; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { + /* nan */ + return x; + } + if sign && ix != 0 { + /* x < 0 */ + return 0.0 / 0.0; + } + if ix == 0x7f800000 { + return 0.0; + } + + if n == 0 { + return y0f(x); + } + if n < 0 { + nm1 = -(n + 1); + sign = (n & 1) != 0; + } else { + nm1 = n - 1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1f(x); + } else { + return y1f(x); + } + } + + a = y0f(x); + b = y1f(x); + /* quit if b is -inf */ + ib = b.to_bits(); + i = 0; + while i < nm1 && ib != 0xff800000 { + i += 1; + temp = b; + b = (2.0 * (i as f32) / x) * b - a; + ib = b.to_bits(); + a = temp; + } + + if sign { + -b + } else { + b + } +} diff --git a/library/compiler-builtins/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/src/math/lgamma.rs index 35b25265214..b1a321e308c 100644 --- a/library/compiler-builtins/libm/src/math/lgamma.rs +++ b/library/compiler-builtins/libm/src/math/lgamma.rs @@ -1,309 +1,323 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - * - */ -/* lgamma_r(x, signgamp) - * Reentrant version of the logarithm of the Gamma function - * with user provide pointer for the sign of Gamma(x). - * - * Method: - * 1. Argument Reduction for 0 < x <= 8 - * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may - * reduce x to a number in [1.5,2.5] by - * lgamma(1+s) = log(s) + lgamma(s) - * for example, - * lgamma(7.3) = log(6.3) + lgamma(6.3) - * = log(6.3*5.3) + lgamma(5.3) - * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) - * 2. Polynomial approximation of lgamma around its - * minimun ymin=1.461632144968362245 to maintain monotonicity. - * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use - * Let z = x-ymin; - * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) - * where - * poly(z) is a 14 degree polynomial. - * 2. Rational approximation in the primary interval [2,3] - * We use the following approximation: - * s = x-2.0; - * lgamma(x) = 0.5*s + s*P(s)/Q(s) - * with accuracy - * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 - * Our algorithms are based on the following observation - * - * zeta(2)-1 2 zeta(3)-1 3 - * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... - * 2 3 - * - * where Euler = 0.5771... is the Euler constant, which is very - * close to 0.5. - * - * 3. For x>=8, we have - * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... - * (better formula: - * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) - * Let z = 1/x, then we approximation - * f(z) = lgamma(x) - (x-0.5)(log(x)-1) - * by - * 3 5 11 - * w = w0 + w1*z + w2*z + w3*z + ... + w6*z - * where - * |w - f(z)| < 2**-58.74 - * - * 4. For negative x, since (G is gamma function) - * -x*G(-x)*G(x) = PI/sin(PI*x), - * we have - * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) - * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 - * Hence, for x<0, signgam = sign(sin(PI*x)) and - * lgamma(x) = log(|Gamma(x)|) - * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); - * Note: one should avoid compute PI*(-x) directly in the - * computation of sin(PI*(-x)). - * - * 5. Special Cases - * lgamma(2+s) ~ s*(1-Euler) for tiny s - * lgamma(1) = lgamma(2) = 0 - * lgamma(x) ~ -log(|x|) for tiny x - * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero - * lgamma(inf) = inf - * lgamma(-inf) = inf (bug for bug compatible with C99!?) - * - */ - -use super::{floor, k_cos, k_sin, log}; - -const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ -const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ -const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ -const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ -const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ -const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ -const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ -const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ -const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ -const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ -const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ -const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ -const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ -const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ -const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ -/* tt = -(tail of TF) */ -const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ -const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ -const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ -const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ -const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ -const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ -const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ -const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ -const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ -const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ -const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ -const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ -const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ -const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ -const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ -const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ -const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ -const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ -const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ -const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ -const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ -const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ -const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ -const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ -const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ -const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ -const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ -const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ -const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ -const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ -const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ -const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ -const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ -const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ -const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ -const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ -const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ -const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ -const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ -const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ -const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ -const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ -const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ -const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ -const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ - -/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: f64) -> f64 -{ - let mut n: isize; - - /* spurious inexact if odd int */ - x = 2.0*(x*0.5 - floor(x*0.5)); /* x mod 2.0 */ - - n = (x*4.0) as isize; - n = (n+1)/2; - x -= (n as f64)*0.5; - x *= PI; - - match n { - 1 => k_cos(x, 0.0), - 2 => k_sin(-x, 0.0, 0), - 3 => -k_cos(x, 0.0), - 0|_ => k_sin(x, 0.0, 0), - } -} - -pub fn lgamma(x: f64) -> f64 { - lgamma_r(x).0 -} - -pub fn lgamma_r(mut x: f64) -> (f64, isize) -{ - let u: u64 = x.to_bits(); - let mut t: f64; - let y: f64; - let mut z: f64; - let nadj: f64; - let p: f64; - let p1: f64; - let p2: f64; - let p3: f64; - let q: f64; - let mut r: f64; - let w: f64; - let ix: u32; - let sign: bool; - let i: isize; - let mut signgam: isize; - - /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - signgam = 1; - sign = (u>>63) != 0; - ix = ((u>>32) as u32) & 0x7fffffff; - if ix >= 0x7ff00000 { - return (x*x, signgam); - } - if ix < (0x3ff-70)<<20 { /* |x|<2**-70, return -log(|x|) */ - if sign { - x = -x; - signgam = -1; - } - return (-log(x), signgam); - } - if sign { - x = -x; - t = sin_pi(x); - if t == 0.0 { /* -integer */ - return (1.0/(x-x), signgam); - } - if t > 0.0 { - signgam = -1; - } else { - t = -t; - } - nadj = log(PI/(t*x)); - } else { - nadj = 0.0; - } - - /* purge off 1 and 2 */ - if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { - r = 0.0; - } - /* for x < 2.0 */ - else if ix < 0x40000000 { - if ix <= 0x3feccccc { /* lgamma(x) = lgamma(x+1)-log(x) */ - r = -log(x); - if ix >= 0x3FE76944 { - y = 1.0 - x; - i = 0; - } else if ix >= 0x3FCDA661 { - y = x - (TC-1.0); - i = 1; - } else { - y = x; - i = 2; - } - } else { - r = 0.0; - if ix >= 0x3FFBB4C3 { /* [1.7316,2] */ - y = 2.0 - x; - i = 0; - } else if ix >= 0x3FF3B4C4 { /* [1.23,1.73] */ - y = x - TC; - i = 1; - } else { - y = x - 1.0; - i = 2; - } - } - match i { - 0 => { - z = y*y; - p1 = A0+z*(A2+z*(A4+z*(A6+z*(A8+z*A10)))); - p2 = z*(A1+z*(A3+z*(A5+z*(A7+z*(A9+z*A11))))); - p = y*p1+p2; - r += p-0.5*y; - } - 1 => { - z = y*y; - w = z*y; - p1 = T0+w*(T3+w*(T6+w*(T9 +w*T12))); /* parallel comp */ - p2 = T1+w*(T4+w*(T7+w*(T10+w*T13))); - p3 = T2+w*(T5+w*(T8+w*(T11+w*T14))); - p = z*p1-(TT-w*(p2+y*p3)); - r += TF + p; - } - 2 => { - p1 = y*(U0+y*(U1+y*(U2+y*(U3+y*(U4+y*U5))))); - p2 = 1.0+y*(V1+y*(V2+y*(V3+y*(V4+y*V5)))); - r += -0.5*y + p1/p2; - } - #[cfg(feature = "checked")] - _ => unreachable!(), - #[cfg(not(feature = "checked"))] - _ => {} - } - } else if ix < 0x40200000 { /* x < 8.0 */ - i = x as isize; - y = x - (i as f64); - p = y*(S0+y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6)))))); - q = 1.0+y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6))))); - r = 0.5*y+p/q; - z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ - // TODO: In C, this was implemented using switch jumps with fallthrough. - // Does this implementation have performance problems? - if i >= 7 { z *= y + 6.0; } - if i >= 6 { z *= y + 5.0; } - if i >= 5 { z *= y + 4.0; } - if i >= 4 { z *= y + 3.0; } - if i >= 3 { - z *= y + 2.0; - r += log(z); - } - } else if ix < 0x43900000 { /* 8.0 <= x < 2**58 */ - t = log(x); - z = 1.0/x; - y = z*z; - w = W0+z*(W1+y*(W2+y*(W3+y*(W4+y*(W5+y*W6))))); - r = (x-0.5)*(t-1.0)+w; - } else { /* 2**58 <= x <= inf */ - r = x*(log(x)-1.0); - } - if sign { - r = nadj - r; - } - return (r, signgam); -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = PI/sin(PI*x), + * we have + * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(PI*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); + * Note: one should avoid compute PI*(-x) directly in the + * computation of sin(PI*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +use super::{floor, k_cos, k_sin, log}; + +const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ +const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ +const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ +const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ +const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ +const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ +const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ +const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ +const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ +const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ +const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ +const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ +const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ +const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ +const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of TF) */ +const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ +const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ +const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ +const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ +const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ +const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ +const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ +const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ +const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ +const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ +const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ +const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ +const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ +const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ +const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ +const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ +const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ +const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ +const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ +const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ +const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ +const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ +const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ +const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ +const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ +const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ +const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ +const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ +const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ +const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ +const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ +const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ +const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ +const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ +const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ +const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ +const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ +const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ +const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ +const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ +const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ +const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ +const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ +const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ +const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f64) -> f64 { + let mut n: i32; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ + + n = (x * 4.0) as i32; + n = (n + 1) / 2; + x -= (n as f64) * 0.5; + x *= PI; + + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + 0 | _ => k_sin(x, 0.0, 0), + } +} + +pub fn lgamma(x: f64) -> f64 { + lgamma_r(x).0 +} + +pub fn lgamma_r(mut x: f64) -> (f64, i32) { + let u: u64 = x.to_bits(); + let mut t: f64; + let y: f64; + let mut z: f64; + let nadj: f64; + let p: f64; + let p1: f64; + let p2: f64; + let p3: f64; + let q: f64; + let mut r: f64; + let w: f64; + let ix: u32; + let sign: bool; + let i: i32; + let mut signgam: i32; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u >> 63) != 0; + ix = ((u >> 32) as u32) & 0x7fffffff; + if ix >= 0x7ff00000 { + return (x * x, signgam); + } + if ix < (0x3ff - 70) << 20 { + /* |x|<2**-70, return -log(|x|) */ + if sign { + x = -x; + signgam = -1; + } + return (-log(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { + /* -integer */ + return (1.0 / (x - x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = log(PI / (t * x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3feccccc { + /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -log(x); + if ix >= 0x3FE76944 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3FCDA661 { + y = x - (TC - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3FFBB4C3 { + /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3FF3B4C4 { + /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y * y; + p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); + p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); + p = y * p1 + p2; + r += p - 0.5 * y; + } + 1 => { + z = y * y; + w = z * y; + p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ + p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); + p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); + p = z * p1 - (TT - w * (p2 + y * p3)); + r += TF + p; + } + 2 => { + p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); + p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); + r += -0.5 * y + p1 / p2; + } + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => {} + } + } else if ix < 0x40200000 { + /* x < 8.0 */ + i = x as i32; + y = x - (i as f64); + p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); + q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { + z *= y + 6.0; + } + if i >= 6 { + z *= y + 5.0; + } + if i >= 5 { + z *= y + 4.0; + } + if i >= 4 { + z *= y + 3.0; + } + if i >= 3 { + z *= y + 2.0; + r += log(z); + } + } else if ix < 0x43900000 { + /* 8.0 <= x < 2**58 */ + t = log(x); + z = 1.0 / x; + y = z * z; + w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else { + /* 2**58 <= x <= inf */ + r = x * (log(x) - 1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/src/math/lgammaf.rs index 60effa31674..8fe8060b5ec 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf.rs @@ -1,244 +1,258 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{floorf, k_cosf, k_sinf, logf}; - -const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ -const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ -const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ -const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ -const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ -const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ -const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ -const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ -const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ -const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ -const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ -const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ -const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ -const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ -const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ -/* TT = -(tail of TF) */ -const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ -const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ -const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ -const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ -const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ -const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ -const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ -const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ -const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ -const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ -const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ -const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ -const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ -const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ -const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ -const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ -const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ -const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ -const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ -const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ -const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ -const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ -const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ -const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ -const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ -const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ -const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ -const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ -const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ -const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ -const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ -const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ -const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ -const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ -const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ -const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ -const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ -const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ -const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ -const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ -const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ -const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ -const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ -const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ -const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ -const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ -const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ - -/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: f32) -> f32 -{ - let mut y: f64; - let mut n: isize; - - /* spurious inexact if odd int */ - x = 2.0*(x*0.5 - floorf(x*0.5)); /* x mod 2.0 */ - - n = (x*4.0) as isize; - n = (n+1)/2; - y = (x as f64) - (n as f64)*0.5; - y *= 3.14159265358979323846; - match n { - 1 => k_cosf(y), - 2 => k_sinf(-y), - 3 => -k_cosf(y), - 0|_ => k_sinf(y), - } -} - -pub fn lgammaf(x: f32) -> f32 { - lgammaf_r(x).0 -} - -pub fn lgammaf_r(mut x: f32) -> (f32, isize) -{ - let u = x.to_bits(); - let mut t: f32; - let y: f32; - let mut z: f32; - let nadj: f32; - let p: f32; - let p1: f32; - let p2: f32; - let p3: f32; - let q: f32; - let mut r: f32; - let w: f32; - let ix: u32; - let i: isize; - let sign: bool; - let mut signgam: isize; - - /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - signgam = 1; - sign = (u>>31) != 0; - ix = u & 0x7fffffff; - if ix >= 0x7f800000 { - return (x*x, signgam); - } - if ix < 0x35000000 { /* |x| < 2**-21, return -log(|x|) */ - if sign { - signgam = -1; - x = -x; - } - return (-logf(x), signgam); - } - if sign { - x = -x; - t = sin_pi(x); - if t == 0.0 { /* -integer */ - return (1.0/(x-x), signgam); - } - if t > 0.0 { - signgam = -1; - } else { - t = -t; - } - nadj = logf(PI/(t*x)); - } else { - nadj = 0.0; - } - - /* purge off 1 and 2 */ - if ix == 0x3f800000 || ix == 0x40000000 { - r = 0.0; - } - /* for x < 2.0 */ - else if ix < 0x40000000 { - if ix <= 0x3f666666 { /* lgamma(x) = lgamma(x+1)-log(x) */ - r = -logf(x); - if ix >= 0x3f3b4a20 { - y = 1.0 - x; - i = 0; - } else if ix >= 0x3e6d3308 { - y = x - (TC-1.0); - i = 1; - } else { - y = x; - i = 2; - } - } else { - r = 0.0; - if ix >= 0x3fdda618 { /* [1.7316,2] */ - y = 2.0 - x; - i = 0; - } else if ix >= 0x3F9da620 { /* [1.23,1.73] */ - y = x - TC; - i = 1; - } else { - y = x - 1.0; - i = 2; - } - } - match i { - 0 => { - z = y*y; - p1 = A0+z*(A2+z*(A4+z*(A6+z*(A8+z*A10)))); - p2 = z*(A1+z*(A3+z*(A5+z*(A7+z*(A9+z*A11))))); - p = y*p1+p2; - r += p - 0.5*y; - } - 1 => { - z = y*y; - w = z*y; - p1 = T0+w*(T3+w*(T6+w*(T9 +w*T12))); /* parallel comp */ - p2 = T1+w*(T4+w*(T7+w*(T10+w*T13))); - p3 = T2+w*(T5+w*(T8+w*(T11+w*T14))); - p = z*p1-(TT-w*(p2+y*p3)); - r += TF + p; - } - 2 => { - p1 = y*(U0+y*(U1+y*(U2+y*(U3+y*(U4+y*U5))))); - p2 = 1.0+y*(V1+y*(V2+y*(V3+y*(V4+y*V5)))); - r += -0.5*y + p1/p2; - } - #[cfg(feature = "checked")] - _ => unreachable!(), - #[cfg(not(feature = "checked"))] - _ => {} - } - } else if ix < 0x41000000 { /* x < 8.0 */ - i = x as isize; - y = x - (i as f32); - p = y*(S0+y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6)))))); - q = 1.0+y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6))))); - r = 0.5*y+p/q; - z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ - // TODO: In C, this was implemented using switch jumps with fallthrough. - // Does this implementation have performance problems? - if i >= 7 { z *= y + 6.0; } - if i >= 6 { z *= y + 5.0; } - if i >= 5 { z *= y + 4.0; } - if i >= 4 { z *= y + 3.0; } - if i >= 3 { - z *= y + 2.0; - r += logf(z); - } - } else if ix < 0x5c800000 { /* 8.0 <= x < 2**58 */ - t = logf(x); - z = 1.0/x; - y = z*z; - w = W0+z*(W1+y*(W2+y*(W3+y*(W4+y*(W5+y*W6))))); - r = (x-0.5)*(t-1.0)+w; - } else { /* 2**58 <= x <= inf */ - r = x*(logf(x)-1.0); - } - if sign { - r = nadj - r; - } - return (r, signgam); -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{floorf, k_cosf, k_sinf, logf}; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ +const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ +const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ +const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ +const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ +const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ +const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ +const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ +const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ +const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ +const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ +const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ +const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ +const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ +/* TT = -(tail of TF) */ +const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ +const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ +const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ +const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ +const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ +const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ +const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ +const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ +const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ +const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ +const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ +const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ +const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ +const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ +const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ +const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ +const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ +const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ +const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ +const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ +const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ +const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ +const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ +const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ +const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ +const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ +const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ +const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ +const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ +const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ +const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ +const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ +const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ +const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ +const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ +const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ +const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ +const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ +const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ +const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ +const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ +const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ +const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ +const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f32) -> f32 { + let mut y: f64; + let mut n: isize; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ + + n = (x * 4.0) as isize; + n = (n + 1) / 2; + y = (x as f64) - (n as f64) * 0.5; + y *= 3.14159265358979323846; + match n { + 1 => k_cosf(y), + 2 => k_sinf(-y), + 3 => -k_cosf(y), + 0 | _ => k_sinf(y), + } +} + +pub fn lgammaf(x: f32) -> f32 { + lgammaf_r(x).0 +} + +pub fn lgammaf_r(mut x: f32) -> (f32, isize) { + let u = x.to_bits(); + let mut t: f32; + let y: f32; + let mut z: f32; + let nadj: f32; + let p: f32; + let p1: f32; + let p2: f32; + let p3: f32; + let q: f32; + let mut r: f32; + let w: f32; + let ix: u32; + let i: isize; + let sign: bool; + let mut signgam: isize; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u >> 31) != 0; + ix = u & 0x7fffffff; + if ix >= 0x7f800000 { + return (x * x, signgam); + } + if ix < 0x35000000 { + /* |x| < 2**-21, return -log(|x|) */ + if sign { + signgam = -1; + x = -x; + } + return (-logf(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { + /* -integer */ + return (1.0 / (x - x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = logf(PI / (t * x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if ix == 0x3f800000 || ix == 0x40000000 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3f666666 { + /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -logf(x); + if ix >= 0x3f3b4a20 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3e6d3308 { + y = x - (TC - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3fdda618 { + /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3F9da620 { + /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y * y; + p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); + p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); + p = y * p1 + p2; + r += p - 0.5 * y; + } + 1 => { + z = y * y; + w = z * y; + p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ + p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); + p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); + p = z * p1 - (TT - w * (p2 + y * p3)); + r += TF + p; + } + 2 => { + p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); + p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); + r += -0.5 * y + p1 / p2; + } + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => {} + } + } else if ix < 0x41000000 { + /* x < 8.0 */ + i = x as isize; + y = x - (i as f32); + p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); + q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { + z *= y + 6.0; + } + if i >= 6 { + z *= y + 5.0; + } + if i >= 5 { + z *= y + 4.0; + } + if i >= 4 { + z *= y + 3.0; + } + if i >= 3 { + z *= y + 2.0; + r += logf(z); + } + } else if ix < 0x5c800000 { + /* 8.0 <= x < 2**58 */ + t = logf(x); + z = 1.0 / x; + y = z * z; + w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else { + /* 2**58 <= x <= inf */ + r = x * (logf(x) - 1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 6e53b020c4b..b70b0cd6b32 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -118,8 +118,6 @@ mod frexp; mod frexpf; mod hypot; mod hypotf; -mod ldexp; -mod ldexpf; mod ilogb; mod ilogbf; mod j0; @@ -128,6 +126,8 @@ mod j1; mod j1f; mod jn; mod jnf; +mod ldexp; +mod ldexpf; mod lgamma; mod lgammaf; mod log; @@ -192,8 +192,8 @@ pub use self::cosh::cosh; pub use self::coshf::coshf; pub use self::erf::erf; pub use self::erf::erfc; -pub use self::erff::erff; pub use self::erff::erfcf; +pub use self::erff::erff; pub use self::exp::exp; pub use self::exp10::exp10; pub use self::exp10f::exp10f; @@ -216,8 +216,6 @@ pub use self::frexp::frexp; pub use self::frexpf::frexpf; pub use self::hypot::hypot; pub use self::hypotf::hypotf; -pub use self::ldexp::ldexp; -pub use self::ldexpf::ldexpf; pub use self::ilogb::ilogb; pub use self::ilogbf::ilogbf; pub use self::j0::j0; @@ -232,6 +230,8 @@ pub use self::jn::jn; pub use self::jn::yn; pub use self::jnf::jnf; pub use self::jnf::ynf; +pub use self::ldexp::ldexp; +pub use self::ldexpf::ldexpf; pub use self::lgamma::lgamma; pub use self::lgamma::lgamma_r; pub use self::lgammaf::lgammaf; diff --git a/library/compiler-builtins/libm/src/math/modf.rs b/library/compiler-builtins/libm/src/math/modf.rs index 1ff8ee116d0..a37f8b918a3 100644 --- a/library/compiler-builtins/libm/src/math/modf.rs +++ b/library/compiler-builtins/libm/src/math/modf.rs @@ -1,33 +1,34 @@ -pub fn modf(x: f64) -> (f64, f64) { - let rv2: f64; - let mut u = x.to_bits(); - let mask: u64; - let e = ((u>>52 & 0x7ff) as isize) - 0x3ff; - - /* no fractional part */ - if e >= 52 { - rv2 = x; - if e == 0x400 && (u<<12) != 0 { /* nan */ - return (x, rv2); - } - u &= 1<<63; - return (f64::from_bits(u), rv2); - } - - /* no integral part*/ - if e < 0 { - u &= 1<<63; - rv2 = f64::from_bits(u); - return (x, rv2); - } - - mask = ((!0)>>12)>>e; - if (u & mask) == 0 { - rv2 = x; - u &= 1<<63; - return (f64::from_bits(u), rv2); - } - u &= !mask; - rv2 = f64::from_bits(u); - return (x - rv2, rv2); -} +pub fn modf(x: f64) -> (f64, f64) { + let rv2: f64; + let mut u = x.to_bits(); + let mask: u64; + let e = ((u >> 52 & 0x7ff) as isize) - 0x3ff; + + /* no fractional part */ + if e >= 52 { + rv2 = x; + if e == 0x400 && (u << 12) != 0 { + /* nan */ + return (x, rv2); + } + u &= 1 << 63; + return (f64::from_bits(u), rv2); + } + + /* no integral part*/ + if e < 0 { + u &= 1 << 63; + rv2 = f64::from_bits(u); + return (x, rv2); + } + + mask = ((!0) >> 12) >> e; + if (u & mask) == 0 { + rv2 = x; + u &= 1 << 63; + return (f64::from_bits(u), rv2); + } + u &= !mask; + rv2 = f64::from_bits(u); + return (x - rv2, rv2); +} diff --git a/library/compiler-builtins/libm/src/math/modff.rs b/library/compiler-builtins/libm/src/math/modff.rs index 5250e8d3801..4ce9052e7ea 100644 --- a/library/compiler-builtins/libm/src/math/modff.rs +++ b/library/compiler-builtins/libm/src/math/modff.rs @@ -1,32 +1,33 @@ -pub fn modff(x: f32) -> (f32, f32) { - let rv2: f32; - let mut u: u32 = x.to_bits(); - let mask: u32; - let e = ((u>>23 & 0xff) as isize) - 0x7f; - - /* no fractional part */ - if e >= 23 { - rv2 = x; - if e == 0x80 && (u<<9) != 0 { /* nan */ - return (x, rv2); - } - u &= 0x80000000; - return (f32::from_bits(u), rv2); - } - /* no integral part */ - if e < 0 { - u &= 0x80000000; - rv2 = f32::from_bits(u); - return (x, rv2); - } - - mask = 0x007fffff>>e; - if (u & mask) == 0 { - rv2 = x; - u &= 0x80000000; - return (f32::from_bits(u), rv2); - } - u &= !mask; - rv2 = f32::from_bits(u); - return (x - rv2, rv2); -} +pub fn modff(x: f32) -> (f32, f32) { + let rv2: f32; + let mut u: u32 = x.to_bits(); + let mask: u32; + let e = ((u >> 23 & 0xff) as isize) - 0x7f; + + /* no fractional part */ + if e >= 23 { + rv2 = x; + if e == 0x80 && (u << 9) != 0 { + /* nan */ + return (x, rv2); + } + u &= 0x80000000; + return (f32::from_bits(u), rv2); + } + /* no integral part */ + if e < 0 { + u &= 0x80000000; + rv2 = f32::from_bits(u); + return (x, rv2); + } + + mask = 0x007fffff >> e; + if (u & mask) == 0 { + rv2 = x; + u &= 0x80000000; + return (f32::from_bits(u), rv2); + } + u &= !mask; + rv2 = f32::from_bits(u); + return (x - rv2, rv2); +} diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs index 98f4b38581a..3681b947cc2 100644 --- a/library/compiler-builtins/libm/src/math/remquo.rs +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -1,98 +1,97 @@ -pub fn remquo(mut x: f64, mut y: f64) -> (f64, isize) -{ - let ux: u64 = x.to_bits(); - let mut uy: u64 = y.to_bits(); - let mut ex = ((ux>>52) & 0x7ff) as isize; - let mut ey = ((uy>>52) & 0x7ff) as isize; - let sx = (ux>>63) != 0; - let sy = (uy>>63) != 0; - let mut q: u32; - let mut i: u64; - let mut uxi: u64 = ux; - - if (uy<<1) == 0 || y.is_nan() || ex == 0x7ff { - return ((x*y)/(x*y), 0); - } - if (ux<<1) == 0 { - return (x, 0); - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 12; - while (i>>63) == 0 { - ex -= 1; - i <<= 1; - } - uxi <<= -ex + 1; - } else { - uxi &= (!0) >> 12; - uxi |= 1 << 52; - } - if ey == 0 { - i = uy<<12; - while (i>>63) == 0 { - ey -= 1; - i <<= 1; - } - uy <<= -ey + 1; - } else { - uy &= (!0) >> 12; - uy |= 1 << 52; - } - - q = 0; - - if ex+1 != ey { - if ex < ey { - return (x, 0); - } - /* x mod y */ - while ex > ey { - i = uxi - uy; - if (i>>63) == 0 { - uxi = i; - q += 1; - } - uxi <<= 1; - q <<= 1; - ex -= 1; - } - i = uxi - uy; - if (i>>63) == 0 { - uxi = i; - q += 1; - } - if uxi == 0 { - ex = -60; - } else { - while (uxi>>52) == 0 { - uxi <<= 1; - ex -= 1; - } - } - } - - /* scale result and decide between |x| and |x|-|y| */ - if ex > 0 { - uxi -= 1 << 52; - uxi |= (ex as u64) << 52; - } else { - uxi >>= -ex + 1; - } - x = f64::from_bits(uxi); - if sy { - y = -y; - } - if ex == ey || (ex+1 == ey && (2.0*x > y || (2.0*x == y && (q%2) != 0))) { - x -= y; - q += 1; - } - q &= 0x7fffffff; - let quo = if sx ^ sy { -(q as isize) } else { q as isize }; - if sx { - (-x, quo) - } else { - (x, quo) - } -} +pub fn remquo(mut x: f64, mut y: f64) -> (f64, isize) { + let ux: u64 = x.to_bits(); + let mut uy: u64 = y.to_bits(); + let mut ex = ((ux >> 52) & 0x7ff) as isize; + let mut ey = ((uy >> 52) & 0x7ff) as isize; + let sx = (ux >> 63) != 0; + let sy = (uy >> 63) != 0; + let mut q: u32; + let mut i: u64; + let mut uxi: u64 = ux; + + if (uy << 1) == 0 || y.is_nan() || ex == 0x7ff { + return ((x * y) / (x * y), 0); + } + if (ux << 1) == 0 { + return (x, 0); + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 12; + while (i >> 63) == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= (!0) >> 12; + uxi |= 1 << 52; + } + if ey == 0 { + i = uy << 12; + while (i >> 63) == 0 { + ey -= 1; + i <<= 1; + } + uy <<= -ey + 1; + } else { + uy &= (!0) >> 12; + uy |= 1 << 52; + } + + q = 0; + + if ex + 1 != ey { + if ex < ey { + return (x, 0); + } + /* x mod y */ + while ex > ey { + i = uxi - uy; + if (i >> 63) == 0 { + uxi = i; + q += 1; + } + uxi <<= 1; + q <<= 1; + ex -= 1; + } + i = uxi - uy; + if (i >> 63) == 0 { + uxi = i; + q += 1; + } + if uxi == 0 { + ex = -60; + } else { + while (uxi >> 52) == 0 { + uxi <<= 1; + ex -= 1; + } + } + } + + /* scale result and decide between |x| and |x|-|y| */ + if ex > 0 { + uxi -= 1 << 52; + uxi |= (ex as u64) << 52; + } else { + uxi >>= -ex + 1; + } + x = f64::from_bits(uxi); + if sy { + y = -y; + } + if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { + x -= y; + q += 1; + } + q &= 0x7fffffff; + let quo = if sx ^ sy { -(q as isize) } else { q as isize }; + if sx { + (-x, quo) + } else { + (x, quo) + } +} diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs index 4307e190665..40ded5d6976 100644 --- a/library/compiler-builtins/libm/src/math/remquof.rs +++ b/library/compiler-builtins/libm/src/math/remquof.rs @@ -1,97 +1,96 @@ -pub fn remquof(mut x: f32, mut y: f32) -> (f32, isize) -{ - let ux: u32 = x.to_bits(); - let mut uy: u32 = y.to_bits(); - let mut ex = ((ux>>23) & 0xff) as isize; - let mut ey = ((uy>>23) & 0xff) as isize; - let sx = (ux>>31) != 0; - let sy = (uy>>31) != 0; - let mut q: u32; - let mut i: u32; - let mut uxi: u32 = ux; - - if (uy<<1) == 0 || y.is_nan() || ex == 0xff { - return ((x*y)/(x*y), 0); - } - if (ux<<1) == 0 { - return (x, 0); - } - - /* normalize x and y */ - if ex == 0 { - i = uxi<<9; - while (i>>31) == 0 { - ex -= 1; - i <<= 1; - } - uxi <<= -ex + 1; - } else { - uxi &= (!0) >> 9; - uxi |= 1 << 23; - } - if ey == 0 { - i = uy<<9; - while (i>>31) == 0 { - ey -= 1; - i <<= 1; - } - uy <<= -ey + 1; - } else { - uy &= (!0) >> 9; - uy |= 1 << 23; - } - - q = 0; - if ex+1 != ey { - if ex < ey { - return (x, 0); - } - /* x mod y */ - while ex > ey { - i = uxi - uy; - if (i>>31) == 0 { - uxi = i; - q += 1; - } - uxi <<= 1; - q <<= 1; - ex -= 1; - } - i = uxi - uy; - if (i>>31) == 0 { - uxi = i; - q += 1; - } - if uxi == 0 { - ex = -30; - } else { - while (uxi>>23) == 0 { - uxi <<= 1; - ex -= 1; - } - } - } - - /* scale result and decide between |x| and |x|-|y| */ - if ex > 0 { - uxi -= 1 << 23; - uxi |= (ex as u32) << 23; - } else { - uxi >>= -ex + 1; - } - x = f32::from_bits(uxi); - if sy { - y = -y; - } - if ex == ey || (ex+1 == ey && (2.0*x > y || (2.0*x == y && (q%2) != 0))) { - x -= y; - q += 1; - } - q &= 0x7fffffff; - let quo = if sx^sy { -(q as isize) } else { q as isize }; - if sx { - (-x, quo) - } else { - (x, quo) - } -} +pub fn remquof(mut x: f32, mut y: f32) -> (f32, isize) { + let ux: u32 = x.to_bits(); + let mut uy: u32 = y.to_bits(); + let mut ex = ((ux >> 23) & 0xff) as isize; + let mut ey = ((uy >> 23) & 0xff) as isize; + let sx = (ux >> 31) != 0; + let sy = (uy >> 31) != 0; + let mut q: u32; + let mut i: u32; + let mut uxi: u32 = ux; + + if (uy << 1) == 0 || y.is_nan() || ex == 0xff { + return ((x * y) / (x * y), 0); + } + if (ux << 1) == 0 { + return (x, 0); + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 9; + while (i >> 31) == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= (!0) >> 9; + uxi |= 1 << 23; + } + if ey == 0 { + i = uy << 9; + while (i >> 31) == 0 { + ey -= 1; + i <<= 1; + } + uy <<= -ey + 1; + } else { + uy &= (!0) >> 9; + uy |= 1 << 23; + } + + q = 0; + if ex + 1 != ey { + if ex < ey { + return (x, 0); + } + /* x mod y */ + while ex > ey { + i = uxi - uy; + if (i >> 31) == 0 { + uxi = i; + q += 1; + } + uxi <<= 1; + q <<= 1; + ex -= 1; + } + i = uxi - uy; + if (i >> 31) == 0 { + uxi = i; + q += 1; + } + if uxi == 0 { + ex = -30; + } else { + while (uxi >> 23) == 0 { + uxi <<= 1; + ex -= 1; + } + } + } + + /* scale result and decide between |x| and |x|-|y| */ + if ex > 0 { + uxi -= 1 << 23; + uxi |= (ex as u32) << 23; + } else { + uxi >>= -ex + 1; + } + x = f32::from_bits(uxi); + if sy { + y = -y; + } + if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { + x -= y; + q += 1; + } + q &= 0x7fffffff; + let quo = if sx ^ sy { -(q as isize) } else { q as isize }; + if sx { + (-x, quo) + } else { + (x, quo) + } +} diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs index c15ee4661f6..750908df4f7 100644 --- a/library/compiler-builtins/libm/src/math/sincos.rs +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -1,60 +1,59 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{get_high_word, k_cos, k_sin, rem_pio2}; - -pub fn sincos(x: f64) -> (f64, f64) -{ - let s: f64; - let c: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - - /* |x| ~< pi/4 */ - if ix <= 0x3fe921fb { - /* if |x| < 2**-27 * sqrt(2) */ - if ix < 0x3e46a09e { - /* raise inexact if x!=0 and underflow if subnormal */ - let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 - if ix < 0x00100000 { - force_eval!(x/x1p120); - } else { - force_eval!(x+x1p120); - } - return (x, 1.0); - } - return (k_sin(x, 0.0, 0), k_cos(x, 0.0)); - } - - /* sincos(Inf or NaN) is NaN */ - if ix >= 0x7ff00000 { - let rv = x - x; - return (rv, rv); - } - - /* argument reduction needed */ - let (n, y0, y1) = rem_pio2(x); - s = k_sin(y0, y1, 1); - c = k_cos(y0, y1); - match n&3 { - 0 => (s, c), - 1 => (c, -s), - 2 => (-s, -c), - 3 => (-c, s), - #[cfg(feature = "checked")] - _ => unreachable!(), - #[cfg(not(feature = "checked"))] - _ => (0.0, 1.0), - } -} +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{get_high_word, k_cos, k_sin, rem_pio2}; + +pub fn sincos(x: f64) -> (f64, f64) { + let s: f64; + let c: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + /* if |x| < 2**-27 * sqrt(2) */ + if ix < 0x3e46a09e { + /* raise inexact if x!=0 and underflow if subnormal */ + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return (x, 1.0); + } + return (k_sin(x, 0.0, 0), k_cos(x, 0.0)); + } + + /* sincos(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + let rv = x - x; + return (rv, rv); + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + s = k_sin(y0, y1, 1); + c = k_cos(y0, y1); + match n & 3 { + 0 => (s, c), + 1 => (c, -s), + 2 => (-s, -c), + 3 => (-c, s), + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => (0.0, 1.0), + } +} diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index 911421d63d4..bb9a0039201 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -1,122 +1,123 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{k_cosf, k_sinf, rem_pio2f}; - -/* Small multiples of pi/2 rounded to double precision. */ -const PI_2: f32 = 0.5 * 3.1415926535897931160E+00; -const S1PIO2: f32 = 1.0*PI_2; /* 0x3FF921FB, 0x54442D18 */ -const S2PIO2: f32 = 2.0*PI_2; /* 0x400921FB, 0x54442D18 */ -const S3PIO2: f32 = 3.0*PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const S4PIO2: f32 = 4.0*PI_2; /* 0x401921FB, 0x54442D18 */ - -pub fn sincosf(x: f32) -> (f32, f32) -{ - let s: f32; - let c: f32; - let mut ix: u32; - let sign: bool; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - /* |x| ~<= pi/4 */ - if ix <= 0x3f490fda { - /* |x| < 2**-12 */ - if ix < 0x39800000 { - /* raise inexact if x!=0 and underflow if subnormal */ - - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120 == 2^120 - if ix < 0x00100000 { - force_eval!(x/x1p120); - } else { - force_eval!(x+x1p120); - } - return (x, 1.0); - } - return (k_sinf(x as f64), k_cosf(x as f64)); - } - - /* |x| ~<= 5*pi/4 */ - if ix <= 0x407b53d1 { - if ix <= 0x4016cbe3 { /* |x| ~<= 3pi/4 */ - if sign { - s = -k_cosf((x + S1PIO2) as f64); - c = k_sinf((x + S1PIO2) as f64); - } else { - s = k_cosf((S1PIO2 - x) as f64); - c = k_sinf((S1PIO2 - x) as f64); - } - } - /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ - else { - if sign { - s = k_sinf((x + S2PIO2) as f64); - c = k_cosf((x + S2PIO2) as f64); - } else { - s = k_sinf((x - S2PIO2) as f64); - c = k_cosf((x - S2PIO2) as f64); - } - } - - return (s, c); - } - - /* |x| ~<= 9*pi/4 */ - if ix <= 0x40e231d5 { - if ix <= 0x40afeddf { /* |x| ~<= 7*pi/4 */ - if sign { - s = k_cosf((x + S3PIO2) as f64); - c = -k_sinf((x + S3PIO2) as f64); - } else { - s = -k_cosf((x - S3PIO2) as f64); - c = k_sinf((x - S3PIO2) as f64); - } - } else { - if sign { - s = k_cosf((x + S4PIO2) as f64); - c = k_sinf((x + S4PIO2) as f64); - } else { - s = k_cosf((x - S4PIO2) as f64); - c = k_sinf((x - S4PIO2) as f64); - } - } - - return (s, c); - } - - /* sin(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - let rv = x - x; - return (rv, rv); - } - - /* general argument reduction needed */ - let (n, y) = rem_pio2f(x); - s = k_sinf(y); - c = k_cosf(y); - match n&3 { - 0 => (s, c), - 1 => (c, -s), - 2 => (-s, -c), - 3 => (-c, s), - #[cfg(feature = "checked")] - _ => unreachable!(), - #[cfg(not(feature = "checked"))] - _ => (0.0, 1.0), - } -} +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{k_cosf, k_sinf, rem_pio2f}; + +/* Small multiples of pi/2 rounded to double precision. */ +const PI_2: f32 = 0.5 * 3.1415926535897931160E+00; +const S1PIO2: f32 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2PIO2: f32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ +const S3PIO2: f32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4PIO2: f32 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ + +pub fn sincosf(x: f32) -> (f32, f32) { + let s: f32; + let c: f32; + let mut ix: u32; + let sign: bool; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + /* |x| ~<= pi/4 */ + if ix <= 0x3f490fda { + /* |x| < 2**-12 */ + if ix < 0x39800000 { + /* raise inexact if x!=0 and underflow if subnormal */ + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120 == 2^120 + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return (x, 1.0); + } + return (k_sinf(x as f64), k_cosf(x as f64)); + } + + /* |x| ~<= 5*pi/4 */ + if ix <= 0x407b53d1 { + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + if sign { + s = -k_cosf((x + S1PIO2) as f64); + c = k_sinf((x + S1PIO2) as f64); + } else { + s = k_cosf((S1PIO2 - x) as f64); + c = k_sinf((S1PIO2 - x) as f64); + } + } + /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ + else { + if sign { + s = k_sinf((x + S2PIO2) as f64); + c = k_cosf((x + S2PIO2) as f64); + } else { + s = k_sinf((x - S2PIO2) as f64); + c = k_cosf((x - S2PIO2) as f64); + } + } + + return (s, c); + } + + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40e231d5 { + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + if sign { + s = k_cosf((x + S3PIO2) as f64); + c = -k_sinf((x + S3PIO2) as f64); + } else { + s = -k_cosf((x - S3PIO2) as f64); + c = k_sinf((x - S3PIO2) as f64); + } + } else { + if sign { + s = k_cosf((x + S4PIO2) as f64); + c = k_sinf((x + S4PIO2) as f64); + } else { + s = k_cosf((x - S4PIO2) as f64); + c = k_sinf((x - S4PIO2) as f64); + } + } + + return (s, c); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + let rv = x - x; + return (rv, rv); + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + s = k_sinf(y); + c = k_cosf(y); + match n & 3 { + 0 => (s, c), + 1 => (c, -s), + 2 => (-s, -c), + 3 => (-c, s), + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => (0.0, 1.0), + } +} diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs index 598f46f1c3e..f8ccf669a25 100644 --- a/library/compiler-builtins/libm/src/math/tgamma.rs +++ b/library/compiler-builtins/libm/src/math/tgamma.rs @@ -1,179 +1,207 @@ -/* -"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) -"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) -"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) - -approximation method: - - (x - 0.5) S(x) -Gamma(x) = (x + g - 0.5) * ---------------- - exp(x + g - 0.5) - -with - a1 a2 a3 aN -S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] - x + 1 x + 2 x + 3 x + N - -with a0, a1, a2, a3,.. aN constants which depend on g. - -for x < 0 the following reflection formula is used: - -Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) - -most ideas and constants are from boost and python -*/ -extern crate core; -use super::{exp, floor, k_cos, k_sin, pow}; - -const PI: f64 = 3.141592653589793238462643383279502884; - -/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ -fn sinpi(mut x: f64) -> f64 -{ - let mut n: isize; - - /* argument reduction: x = |x| mod 2 */ - /* spurious inexact when x is odd int */ - x = x * 0.5; - x = 2.0 * (x - floor(x)); - - /* reduce x into [-.25,.25] */ - n = (4.0 * x) as isize; - n = (n+1)/2; - x -= (n as f64) * 0.5; - - x *= PI; - match n { - 1 => k_cos(x, 0.0), - 2 => k_sin(-x, 0.0, 0), - 3 => -k_cos(x, 0.0), - 0|_ => k_sin(x, 0.0, 0), - } -} - -const N: usize = 12; -//static const double g = 6.024680040776729583740234375; -const GMHALF: f64 = 5.524680040776729583740234375; -const SNUM: [f64; N+1] = [ - 23531376880.410759688572007674451636754734846804940, - 42919803642.649098768957899047001988850926355848959, - 35711959237.355668049440185451547166705960488635843, - 17921034426.037209699919755754458931112671403265390, - 6039542586.3520280050642916443072979210699388420708, - 1439720407.3117216736632230727949123939715485786772, - 248874557.86205415651146038641322942321632125127801, - 31426415.585400194380614231628318205362874684987640, - 2876370.6289353724412254090516208496135991145378768, - 186056.26539522349504029498971604569928220784236328, - 8071.6720023658162106380029022722506138218516325024, - 210.82427775157934587250973392071336271166969580291, - 2.5066282746310002701649081771338373386264310793408, -]; -const SDEN: [f64; N+1] = [ - 0.0, 39916800.0, 120543840.0, 150917976.0, 105258076.0, - 45995730.0, 13339535.0, 2637558.0, 357423.0, 32670.0, 1925.0, 66.0, 1.0, -]; -/* n! for small integer n */ -const FACT: [f64; 23] = [ - 1.0, 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, 40320.0, 362880.0, 3628800.0, - 39916800.0, 479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0, - 20922789888000.0, 355687428096000.0, 6402373705728000.0, 121645100408832000.0, - 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0, -]; - -/* S(x) rational function for positive x */ -fn s(x: f64) -> f64 -{ - let mut num: f64 = 0.0; - let mut den: f64 = 0.0; - - /* to avoid overflow handle large x differently */ - if x < 8.0 { - for i in (0..=N).rev() { - num = num * x + SNUM[i]; - den = den * x + SDEN[i]; - } - } else { - for i in 0..=N { - num = num / x + SNUM[i]; - den = den / x + SDEN[i]; - } - } - return num/den; -} - -pub fn tgamma(mut x: f64) -> f64 -{ - let u: u64 = x.to_bits(); - let absx: f64; - let mut y: f64; - let mut dy: f64; - let mut z: f64; - let mut r: f64; - let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; - let sign: bool = (u>>64) != 0; - - /* special cases */ - if ix >= 0x7ff00000 { - /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ - return x + core::f64::INFINITY; - } - if ix < ((0x3ff-54)<<20) { - /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ - return 1.0/x; - } - - /* integer arguments */ - /* raise inexact when non-integer */ - if x == floor(x) { - if sign { - return 0.0/0.0; - } - if x <= FACT.len() as f64 { - return FACT[(x as usize) - 1]; - } - } - - /* x >= 172: tgamma(x)=inf with overflow */ - /* x =< -184: tgamma(x)=+-0 with underflow */ - if ix >= 0x40670000 { /* |x| >= 184 */ - if sign { - let x1p_126 = f64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 - force_eval!((x1p_126/x) as f32); - if floor(x) * 0.5 == floor(x * 0.5) { - return 0.0; - } else { - return -0.0; - } - } - let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 - x *= x1p1023; - return x; - } - - absx = if sign { -x } else { x }; - - /* handle the error of x + g - 0.5 */ - y = absx + GMHALF; - if absx > GMHALF { - dy = y - absx; - dy -= GMHALF; - } else { - dy = y - GMHALF; - dy -= absx; - } - - z = absx - 0.5; - r = s(absx) * exp(-y); - if x < 0.0 { - /* reflection formula for negative x */ - /* sinpi(absx) is not 0, integers are already handled */ - r = -PI / (sinpi(absx) * absx * r); - dy = -dy; - z = -z; - } - r += dy * (GMHALF+0.5) * r / y; - z = pow(y, 0.5*z); - y = r * z * z; - return y; -} +/* +"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) +"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) +"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) + +approximation method: + + (x - 0.5) S(x) +Gamma(x) = (x + g - 0.5) * ---------------- + exp(x + g - 0.5) + +with + a1 a2 a3 aN +S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] + x + 1 x + 2 x + 3 x + N + +with a0, a1, a2, a3,.. aN constants which depend on g. + +for x < 0 the following reflection formula is used: + +Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) + +most ideas and constants are from boost and python +*/ +extern crate core; +use super::{exp, floor, k_cos, k_sin, pow}; + +const PI: f64 = 3.141592653589793238462643383279502884; + +/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ +fn sinpi(mut x: f64) -> f64 { + let mut n: isize; + + /* argument reduction: x = |x| mod 2 */ + /* spurious inexact when x is odd int */ + x = x * 0.5; + x = 2.0 * (x - floor(x)); + + /* reduce x into [-.25,.25] */ + n = (4.0 * x) as isize; + n = (n + 1) / 2; + x -= (n as f64) * 0.5; + + x *= PI; + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + 0 | _ => k_sin(x, 0.0, 0), + } +} + +const N: usize = 12; +//static const double g = 6.024680040776729583740234375; +const GMHALF: f64 = 5.524680040776729583740234375; +const SNUM: [f64; N + 1] = [ + 23531376880.410759688572007674451636754734846804940, + 42919803642.649098768957899047001988850926355848959, + 35711959237.355668049440185451547166705960488635843, + 17921034426.037209699919755754458931112671403265390, + 6039542586.3520280050642916443072979210699388420708, + 1439720407.3117216736632230727949123939715485786772, + 248874557.86205415651146038641322942321632125127801, + 31426415.585400194380614231628318205362874684987640, + 2876370.6289353724412254090516208496135991145378768, + 186056.26539522349504029498971604569928220784236328, + 8071.6720023658162106380029022722506138218516325024, + 210.82427775157934587250973392071336271166969580291, + 2.5066282746310002701649081771338373386264310793408, +]; +const SDEN: [f64; N + 1] = [ + 0.0, + 39916800.0, + 120543840.0, + 150917976.0, + 105258076.0, + 45995730.0, + 13339535.0, + 2637558.0, + 357423.0, + 32670.0, + 1925.0, + 66.0, + 1.0, +]; +/* n! for small integer n */ +const FACT: [f64; 23] = [ + 1.0, + 1.0, + 2.0, + 6.0, + 24.0, + 120.0, + 720.0, + 5040.0, + 40320.0, + 362880.0, + 3628800.0, + 39916800.0, + 479001600.0, + 6227020800.0, + 87178291200.0, + 1307674368000.0, + 20922789888000.0, + 355687428096000.0, + 6402373705728000.0, + 121645100408832000.0, + 2432902008176640000.0, + 51090942171709440000.0, + 1124000727777607680000.0, +]; + +/* S(x) rational function for positive x */ +fn s(x: f64) -> f64 { + let mut num: f64 = 0.0; + let mut den: f64 = 0.0; + + /* to avoid overflow handle large x differently */ + if x < 8.0 { + for i in (0..=N).rev() { + num = num * x + SNUM[i]; + den = den * x + SDEN[i]; + } + } else { + for i in 0..=N { + num = num / x + SNUM[i]; + den = den / x + SDEN[i]; + } + } + return num / den; +} + +pub fn tgamma(mut x: f64) -> f64 { + let u: u64 = x.to_bits(); + let absx: f64; + let mut y: f64; + let mut dy: f64; + let mut z: f64; + let mut r: f64; + let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; + let sign: bool = (u >> 63) != 0; + + /* special cases */ + if ix >= 0x7ff00000 { + /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ + return x + core::f64::INFINITY; + } + if ix < ((0x3ff - 54) << 20) { + /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ + return 1.0 / x; + } + + /* integer arguments */ + /* raise inexact when non-integer */ + if x == floor(x) { + if sign { + return 0.0 / 0.0; + } + if x <= FACT.len() as f64 { + return FACT[(x as usize) - 1]; + } + } + + /* x >= 172: tgamma(x)=inf with overflow */ + /* x =< -184: tgamma(x)=+-0 with underflow */ + if ix >= 0x40670000 { + /* |x| >= 184 */ + if sign { + let x1p_126 = f64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 + force_eval!((x1p_126 / x) as f32); + if floor(x) * 0.5 == floor(x * 0.5) { + return 0.0; + } else { + return -0.0; + } + } + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 + x *= x1p1023; + return x; + } + + absx = if sign { -x } else { x }; + + /* handle the error of x + g - 0.5 */ + y = absx + GMHALF; + if absx > GMHALF { + dy = y - absx; + dy -= GMHALF; + } else { + dy = y - GMHALF; + dy -= absx; + } + + z = absx - 0.5; + r = s(absx) * exp(-y); + if x < 0.0 { + /* reflection formula for negative x */ + /* sinpi(absx) is not 0, integers are already handled */ + r = -PI / (sinpi(absx) * absx * r); + dy = -dy; + z = -z; + } + r += dy * (GMHALF + 0.5) * r / y; + z = pow(y, 0.5 * z); + y = r * z * z; + return y; +} diff --git a/library/compiler-builtins/libm/src/math/tgammaf.rs b/library/compiler-builtins/libm/src/math/tgammaf.rs index b9c799ce76c..a8f161f0c1c 100644 --- a/library/compiler-builtins/libm/src/math/tgammaf.rs +++ b/library/compiler-builtins/libm/src/math/tgammaf.rs @@ -1,5 +1,5 @@ -use super::{tgamma}; - -pub fn tgammaf(x: f32) -> f32 { - tgamma(x as f64) as f32 -} +use super::tgamma; + +pub fn tgammaf(x: f32) -> f32 { + tgamma(x as f64) as f32 +} -- cgit 1.4.1-3-g733a5 From 92db6e9c1bfae23b91be38ff05c9f0cc212881bb Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 7 May 2019 09:07:26 +0300 Subject: sh +x --- library/compiler-builtins/libm/ci/run-docker.sh | 0 library/compiler-builtins/libm/ci/run.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 library/compiler-builtins/libm/ci/run-docker.sh mode change 100644 => 100755 library/compiler-builtins/libm/ci/run.sh diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh old mode 100644 new mode 100755 diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh old mode 100644 new mode 100755 -- cgit 1.4.1-3-g733a5 From 5c5ba6fe82e415b949671e66239d8067e6f5cfca Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Thu, 9 May 2019 06:58:58 +0300 Subject: rm asine, mv lgamma --- library/compiler-builtins/libm/build.rs | 9 +- library/compiler-builtins/libm/src/math/asinef.rs | 93 ------ library/compiler-builtins/libm/src/math/lgamma.rs | 320 +-------------------- .../compiler-builtins/libm/src/math/lgamma_r.rs | 319 ++++++++++++++++++++ library/compiler-builtins/libm/src/math/lgammaf.rs | 255 +--------------- .../compiler-builtins/libm/src/math/lgammaf_r.rs | 254 ++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 6 +- library/compiler-builtins/libm/src/math/modf.rs | 2 +- library/compiler-builtins/libm/src/math/modff.rs | 2 +- library/compiler-builtins/libm/src/math/remquo.rs | 8 +- library/compiler-builtins/libm/src/math/remquof.rs | 8 +- 11 files changed, 593 insertions(+), 683 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/asinef.rs create mode 100644 library/compiler-builtins/libm/src/math/lgamma_r.rs create mode 100644 library/compiler-builtins/libm/src/math/lgammaf_r.rs diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 29521ab193c..4d739a12112 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -41,17 +41,16 @@ mod musl_reference_tests { "rem_pio2.rs", "rem_pio2_large.rs", "rem_pio2f.rs", - "remquo.rs", - "remquof.rs", - "lgamma.rs", // lgamma passed, lgamma_r has more than 1 result - "lgammaf.rs", // lgammaf passed, lgammaf_r has more than 1 result + "remquo.rs", // more than 1 result + "remquof.rs", // more than 1 result + "lgamma_r.rs", // more than 1 result + "lgammaf_r.rs", // more than 1 result "frexp.rs", // more than 1 result "frexpf.rs", // more than 1 result "sincos.rs", // more than 1 result "sincosf.rs", // more than 1 result "modf.rs", // more than 1 result "modff.rs", // more than 1 result - "asinef.rs", // not exists "jn.rs", // passed, but very slow "jnf.rs", // passed, but very slow ]; diff --git a/library/compiler-builtins/libm/src/math/asinef.rs b/library/compiler-builtins/libm/src/math/asinef.rs deleted file mode 100644 index cd1428bc232..00000000000 --- a/library/compiler-builtins/libm/src/math/asinef.rs +++ /dev/null @@ -1,93 +0,0 @@ -/* @(#)z_asinef.c 1.0 98/08/13 */ -/****************************************************************** - * The following routines are coded directly from the algorithms - * and coefficients given in "Software Manual for the Elementary - * Functions" by William J. Cody, Jr. and William Waite, Prentice - * Hall, 1980. - ******************************************************************/ -/****************************************************************** - * Arcsine - * - * Input: - * x - floating point value - * acosine - indicates acos calculation - * - * Output: - * Arcsine of x. - * - * Description: - * This routine calculates arcsine / arccosine. - * - *****************************************************************/ - -use super::{fabsf, sqrtf}; - -const P: [f32; 2] = [ 0.933935835, -0.504400557 ]; -const Q: [f32; 2] = [ 0.560363004e+1, -0.554846723e+1 ]; -const A: [f32; 2] = [ 0.0, 0.785398163 ]; -const B: [f32; 2] = [ 1.570796326, 0.785398163 ]; -const Z_ROOTEPS_F: f32 = 1.7263349182589107e-4; - -pub fn asinef(x: f32, acosine: bool) -> f32 { - let i: usize; - let mut branch: bool = false; - let g: f32; - let mut res: f32 = 0.0; - let mut y: f32; - - /* Check for special values. */ - //i = numtestf (x); - if x.is_nan() || x.is_infinite() { - force_eval!(x); - return x; - } - - y = fabsf(x); - let flag = acosine; - - if y > 0.5 { - i = (!flag) as usize; - - /* Check for range error. */ - if y > 1.0 { - return 0.0 / 0.0; - } - - g = (1.0 - y) / 2.0; - y = -2.0 * sqrtf(g); - branch = true; - } else { - i = flag; - if y < Z_ROOTEPS_F { - res = y; - g = 0.0; // pleasing the uninitialized variable - } else { - g = y * y; - } - } - - if y >= Z_ROOTEPS_F || branch { - /* Calculate the Taylor series. */ - let p = (P[1] * g + P[0]) * g; - let q = (g + Q[1]) * g + Q[0]; - let r = p / q; - - res = y + y * r; - } - - /* Calculate asine or acose. */ - if flag == 0 { - res = (A[i] + res) + A[i]; - if x < 0.0 { - res = -res; - } - } else { - if x < 0.0 { - res = (B[i] + res) + B[i]; - } else { - res = (A[i] - res) + A[i]; - } - } - - return res; -} diff --git a/library/compiler-builtins/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/src/math/lgamma.rs index b1a321e308c..5bc87e85e8c 100644 --- a/library/compiler-builtins/libm/src/math/lgamma.rs +++ b/library/compiler-builtins/libm/src/math/lgamma.rs @@ -1,323 +1,5 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - * - */ -/* lgamma_r(x, signgamp) - * Reentrant version of the logarithm of the Gamma function - * with user provide pointer for the sign of Gamma(x). - * - * Method: - * 1. Argument Reduction for 0 < x <= 8 - * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may - * reduce x to a number in [1.5,2.5] by - * lgamma(1+s) = log(s) + lgamma(s) - * for example, - * lgamma(7.3) = log(6.3) + lgamma(6.3) - * = log(6.3*5.3) + lgamma(5.3) - * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) - * 2. Polynomial approximation of lgamma around its - * minimun ymin=1.461632144968362245 to maintain monotonicity. - * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use - * Let z = x-ymin; - * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) - * where - * poly(z) is a 14 degree polynomial. - * 2. Rational approximation in the primary interval [2,3] - * We use the following approximation: - * s = x-2.0; - * lgamma(x) = 0.5*s + s*P(s)/Q(s) - * with accuracy - * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 - * Our algorithms are based on the following observation - * - * zeta(2)-1 2 zeta(3)-1 3 - * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... - * 2 3 - * - * where Euler = 0.5771... is the Euler constant, which is very - * close to 0.5. - * - * 3. For x>=8, we have - * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... - * (better formula: - * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) - * Let z = 1/x, then we approximation - * f(z) = lgamma(x) - (x-0.5)(log(x)-1) - * by - * 3 5 11 - * w = w0 + w1*z + w2*z + w3*z + ... + w6*z - * where - * |w - f(z)| < 2**-58.74 - * - * 4. For negative x, since (G is gamma function) - * -x*G(-x)*G(x) = PI/sin(PI*x), - * we have - * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) - * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 - * Hence, for x<0, signgam = sign(sin(PI*x)) and - * lgamma(x) = log(|Gamma(x)|) - * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); - * Note: one should avoid compute PI*(-x) directly in the - * computation of sin(PI*(-x)). - * - * 5. Special Cases - * lgamma(2+s) ~ s*(1-Euler) for tiny s - * lgamma(1) = lgamma(2) = 0 - * lgamma(x) ~ -log(|x|) for tiny x - * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero - * lgamma(inf) = inf - * lgamma(-inf) = inf (bug for bug compatible with C99!?) - * - */ - -use super::{floor, k_cos, k_sin, log}; - -const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ -const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ -const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ -const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ -const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ -const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ -const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ -const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ -const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ -const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ -const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ -const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ -const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ -const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ -const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ -/* tt = -(tail of TF) */ -const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ -const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ -const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ -const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ -const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ -const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ -const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ -const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ -const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ -const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ -const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ -const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ -const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ -const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ -const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ -const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ -const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ -const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ -const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ -const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ -const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ -const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ -const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ -const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ -const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ -const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ -const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ -const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ -const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ -const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ -const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ -const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ -const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ -const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ -const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ -const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ -const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ -const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ -const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ -const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ -const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ -const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ -const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ -const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ -const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ - -/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: f64) -> f64 { - let mut n: i32; - - /* spurious inexact if odd int */ - x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ - - n = (x * 4.0) as i32; - n = (n + 1) / 2; - x -= (n as f64) * 0.5; - x *= PI; - - match n { - 1 => k_cos(x, 0.0), - 2 => k_sin(-x, 0.0, 0), - 3 => -k_cos(x, 0.0), - 0 | _ => k_sin(x, 0.0, 0), - } -} +use super::lgamma_r; pub fn lgamma(x: f64) -> f64 { lgamma_r(x).0 } - -pub fn lgamma_r(mut x: f64) -> (f64, i32) { - let u: u64 = x.to_bits(); - let mut t: f64; - let y: f64; - let mut z: f64; - let nadj: f64; - let p: f64; - let p1: f64; - let p2: f64; - let p3: f64; - let q: f64; - let mut r: f64; - let w: f64; - let ix: u32; - let sign: bool; - let i: i32; - let mut signgam: i32; - - /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - signgam = 1; - sign = (u >> 63) != 0; - ix = ((u >> 32) as u32) & 0x7fffffff; - if ix >= 0x7ff00000 { - return (x * x, signgam); - } - if ix < (0x3ff - 70) << 20 { - /* |x|<2**-70, return -log(|x|) */ - if sign { - x = -x; - signgam = -1; - } - return (-log(x), signgam); - } - if sign { - x = -x; - t = sin_pi(x); - if t == 0.0 { - /* -integer */ - return (1.0 / (x - x), signgam); - } - if t > 0.0 { - signgam = -1; - } else { - t = -t; - } - nadj = log(PI / (t * x)); - } else { - nadj = 0.0; - } - - /* purge off 1 and 2 */ - if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { - r = 0.0; - } - /* for x < 2.0 */ - else if ix < 0x40000000 { - if ix <= 0x3feccccc { - /* lgamma(x) = lgamma(x+1)-log(x) */ - r = -log(x); - if ix >= 0x3FE76944 { - y = 1.0 - x; - i = 0; - } else if ix >= 0x3FCDA661 { - y = x - (TC - 1.0); - i = 1; - } else { - y = x; - i = 2; - } - } else { - r = 0.0; - if ix >= 0x3FFBB4C3 { - /* [1.7316,2] */ - y = 2.0 - x; - i = 0; - } else if ix >= 0x3FF3B4C4 { - /* [1.23,1.73] */ - y = x - TC; - i = 1; - } else { - y = x - 1.0; - i = 2; - } - } - match i { - 0 => { - z = y * y; - p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); - p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); - p = y * p1 + p2; - r += p - 0.5 * y; - } - 1 => { - z = y * y; - w = z * y; - p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ - p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); - p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); - p = z * p1 - (TT - w * (p2 + y * p3)); - r += TF + p; - } - 2 => { - p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); - p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); - r += -0.5 * y + p1 / p2; - } - #[cfg(feature = "checked")] - _ => unreachable!(), - #[cfg(not(feature = "checked"))] - _ => {} - } - } else if ix < 0x40200000 { - /* x < 8.0 */ - i = x as i32; - y = x - (i as f64); - p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); - q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); - r = 0.5 * y + p / q; - z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ - // TODO: In C, this was implemented using switch jumps with fallthrough. - // Does this implementation have performance problems? - if i >= 7 { - z *= y + 6.0; - } - if i >= 6 { - z *= y + 5.0; - } - if i >= 5 { - z *= y + 4.0; - } - if i >= 4 { - z *= y + 3.0; - } - if i >= 3 { - z *= y + 2.0; - r += log(z); - } - } else if ix < 0x43900000 { - /* 8.0 <= x < 2**58 */ - t = log(x); - z = 1.0 / x; - y = z * z; - w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); - r = (x - 0.5) * (t - 1.0) + w; - } else { - /* 2**58 <= x <= inf */ - r = x * (log(x) - 1.0); - } - if sign { - r = nadj - r; - } - return (r, signgam); -} diff --git a/library/compiler-builtins/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/src/math/lgamma_r.rs new file mode 100644 index 00000000000..382a501fc3d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/lgamma_r.rs @@ -0,0 +1,319 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = PI/sin(PI*x), + * we have + * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(PI*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); + * Note: one should avoid compute PI*(-x) directly in the + * computation of sin(PI*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +use super::{floor, k_cos, k_sin, log}; + +const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ +const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ +const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ +const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ +const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ +const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ +const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ +const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ +const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ +const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ +const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ +const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ +const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ +const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ +const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of TF) */ +const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ +const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ +const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ +const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ +const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ +const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ +const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ +const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ +const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ +const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ +const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ +const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ +const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ +const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ +const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ +const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ +const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ +const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ +const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ +const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ +const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ +const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ +const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ +const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ +const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ +const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ +const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ +const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ +const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ +const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ +const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ +const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ +const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ +const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ +const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ +const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ +const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ +const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ +const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ +const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ +const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ +const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ +const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ +const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ +const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f64) -> f64 { + let mut n: i32; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ + + n = (x * 4.0) as i32; + n = (n + 1) / 2; + x -= (n as f64) * 0.5; + x *= PI; + + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + 0 | _ => k_sin(x, 0.0, 0), + } +} + +pub fn lgamma_r(mut x: f64) -> (f64, i32) { + let u: u64 = x.to_bits(); + let mut t: f64; + let y: f64; + let mut z: f64; + let nadj: f64; + let p: f64; + let p1: f64; + let p2: f64; + let p3: f64; + let q: f64; + let mut r: f64; + let w: f64; + let ix: u32; + let sign: bool; + let i: i32; + let mut signgam: i32; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u >> 63) != 0; + ix = ((u >> 32) as u32) & 0x7fffffff; + if ix >= 0x7ff00000 { + return (x * x, signgam); + } + if ix < (0x3ff - 70) << 20 { + /* |x|<2**-70, return -log(|x|) */ + if sign { + x = -x; + signgam = -1; + } + return (-log(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { + /* -integer */ + return (1.0 / (x - x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = log(PI / (t * x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3feccccc { + /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -log(x); + if ix >= 0x3FE76944 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3FCDA661 { + y = x - (TC - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3FFBB4C3 { + /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3FF3B4C4 { + /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y * y; + p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); + p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); + p = y * p1 + p2; + r += p - 0.5 * y; + } + 1 => { + z = y * y; + w = z * y; + p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ + p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); + p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); + p = z * p1 - (TT - w * (p2 + y * p3)); + r += TF + p; + } + 2 => { + p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); + p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); + r += -0.5 * y + p1 / p2; + } + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => {} + } + } else if ix < 0x40200000 { + /* x < 8.0 */ + i = x as i32; + y = x - (i as f64); + p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); + q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { + z *= y + 6.0; + } + if i >= 6 { + z *= y + 5.0; + } + if i >= 5 { + z *= y + 4.0; + } + if i >= 4 { + z *= y + 3.0; + } + if i >= 3 { + z *= y + 2.0; + r += log(z); + } + } else if ix < 0x43900000 { + /* 8.0 <= x < 2**58 */ + t = log(x); + z = 1.0 / x; + y = z * z; + w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else { + /* 2**58 <= x <= inf */ + r = x * (log(x) - 1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/src/math/lgammaf.rs index 8fe8060b5ec..dfdc87f9622 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf.rs @@ -1,258 +1,5 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{floorf, k_cosf, k_sinf, logf}; - -const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ -const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ -const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ -const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ -const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ -const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ -const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ -const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ -const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ -const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ -const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ -const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ -const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ -const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ -const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ -/* TT = -(tail of TF) */ -const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ -const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ -const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ -const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ -const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ -const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ -const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ -const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ -const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ -const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ -const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ -const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ -const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ -const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ -const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ -const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ -const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ -const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ -const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ -const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ -const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ -const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ -const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ -const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ -const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ -const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ -const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ -const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ -const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ -const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ -const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ -const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ -const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ -const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ -const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ -const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ -const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ -const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ -const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ -const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ -const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ -const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ -const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ -const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ -const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ -const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ -const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ - -/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: f32) -> f32 { - let mut y: f64; - let mut n: isize; - - /* spurious inexact if odd int */ - x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ - - n = (x * 4.0) as isize; - n = (n + 1) / 2; - y = (x as f64) - (n as f64) * 0.5; - y *= 3.14159265358979323846; - match n { - 1 => k_cosf(y), - 2 => k_sinf(-y), - 3 => -k_cosf(y), - 0 | _ => k_sinf(y), - } -} +use super::lgammaf_r; pub fn lgammaf(x: f32) -> f32 { lgammaf_r(x).0 } - -pub fn lgammaf_r(mut x: f32) -> (f32, isize) { - let u = x.to_bits(); - let mut t: f32; - let y: f32; - let mut z: f32; - let nadj: f32; - let p: f32; - let p1: f32; - let p2: f32; - let p3: f32; - let q: f32; - let mut r: f32; - let w: f32; - let ix: u32; - let i: isize; - let sign: bool; - let mut signgam: isize; - - /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - signgam = 1; - sign = (u >> 31) != 0; - ix = u & 0x7fffffff; - if ix >= 0x7f800000 { - return (x * x, signgam); - } - if ix < 0x35000000 { - /* |x| < 2**-21, return -log(|x|) */ - if sign { - signgam = -1; - x = -x; - } - return (-logf(x), signgam); - } - if sign { - x = -x; - t = sin_pi(x); - if t == 0.0 { - /* -integer */ - return (1.0 / (x - x), signgam); - } - if t > 0.0 { - signgam = -1; - } else { - t = -t; - } - nadj = logf(PI / (t * x)); - } else { - nadj = 0.0; - } - - /* purge off 1 and 2 */ - if ix == 0x3f800000 || ix == 0x40000000 { - r = 0.0; - } - /* for x < 2.0 */ - else if ix < 0x40000000 { - if ix <= 0x3f666666 { - /* lgamma(x) = lgamma(x+1)-log(x) */ - r = -logf(x); - if ix >= 0x3f3b4a20 { - y = 1.0 - x; - i = 0; - } else if ix >= 0x3e6d3308 { - y = x - (TC - 1.0); - i = 1; - } else { - y = x; - i = 2; - } - } else { - r = 0.0; - if ix >= 0x3fdda618 { - /* [1.7316,2] */ - y = 2.0 - x; - i = 0; - } else if ix >= 0x3F9da620 { - /* [1.23,1.73] */ - y = x - TC; - i = 1; - } else { - y = x - 1.0; - i = 2; - } - } - match i { - 0 => { - z = y * y; - p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); - p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); - p = y * p1 + p2; - r += p - 0.5 * y; - } - 1 => { - z = y * y; - w = z * y; - p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ - p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); - p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); - p = z * p1 - (TT - w * (p2 + y * p3)); - r += TF + p; - } - 2 => { - p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); - p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); - r += -0.5 * y + p1 / p2; - } - #[cfg(feature = "checked")] - _ => unreachable!(), - #[cfg(not(feature = "checked"))] - _ => {} - } - } else if ix < 0x41000000 { - /* x < 8.0 */ - i = x as isize; - y = x - (i as f32); - p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); - q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); - r = 0.5 * y + p / q; - z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ - // TODO: In C, this was implemented using switch jumps with fallthrough. - // Does this implementation have performance problems? - if i >= 7 { - z *= y + 6.0; - } - if i >= 6 { - z *= y + 5.0; - } - if i >= 5 { - z *= y + 4.0; - } - if i >= 4 { - z *= y + 3.0; - } - if i >= 3 { - z *= y + 2.0; - r += logf(z); - } - } else if ix < 0x5c800000 { - /* 8.0 <= x < 2**58 */ - t = logf(x); - z = 1.0 / x; - y = z * z; - w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); - r = (x - 0.5) * (t - 1.0) + w; - } else { - /* 2**58 <= x <= inf */ - r = x * (logf(x) - 1.0); - } - if sign { - r = nadj - r; - } - return (r, signgam); -} diff --git a/library/compiler-builtins/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/src/math/lgammaf_r.rs new file mode 100644 index 00000000000..0745359a257 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/lgammaf_r.rs @@ -0,0 +1,254 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{floorf, k_cosf, k_sinf, logf}; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ +const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ +const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ +const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ +const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ +const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ +const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ +const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ +const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ +const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ +const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ +const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ +const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ +const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ +/* TT = -(tail of TF) */ +const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ +const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ +const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ +const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ +const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ +const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ +const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ +const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ +const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ +const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ +const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ +const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ +const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ +const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ +const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ +const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ +const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ +const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ +const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ +const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ +const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ +const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ +const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ +const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ +const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ +const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ +const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ +const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ +const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ +const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ +const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ +const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ +const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ +const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ +const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ +const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ +const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ +const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ +const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ +const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ +const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ +const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ +const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ +const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f32) -> f32 { + let mut y: f64; + let mut n: isize; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ + + n = (x * 4.0) as isize; + n = (n + 1) / 2; + y = (x as f64) - (n as f64) * 0.5; + y *= 3.14159265358979323846; + match n { + 1 => k_cosf(y), + 2 => k_sinf(-y), + 3 => -k_cosf(y), + 0 | _ => k_sinf(y), + } +} + +pub fn lgammaf_r(mut x: f32) -> (f32, i32) { + let u = x.to_bits(); + let mut t: f32; + let y: f32; + let mut z: f32; + let nadj: f32; + let p: f32; + let p1: f32; + let p2: f32; + let p3: f32; + let q: f32; + let mut r: f32; + let w: f32; + let ix: u32; + let i: i32; + let sign: bool; + let mut signgam: i32; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u >> 31) != 0; + ix = u & 0x7fffffff; + if ix >= 0x7f800000 { + return (x * x, signgam); + } + if ix < 0x35000000 { + /* |x| < 2**-21, return -log(|x|) */ + if sign { + signgam = -1; + x = -x; + } + return (-logf(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { + /* -integer */ + return (1.0 / (x - x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = logf(PI / (t * x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if ix == 0x3f800000 || ix == 0x40000000 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3f666666 { + /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -logf(x); + if ix >= 0x3f3b4a20 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3e6d3308 { + y = x - (TC - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3fdda618 { + /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3F9da620 { + /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y * y; + p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); + p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); + p = y * p1 + p2; + r += p - 0.5 * y; + } + 1 => { + z = y * y; + w = z * y; + p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ + p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); + p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); + p = z * p1 - (TT - w * (p2 + y * p3)); + r += TF + p; + } + 2 => { + p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); + p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); + r += -0.5 * y + p1 / p2; + } + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => {} + } + } else if ix < 0x41000000 { + /* x < 8.0 */ + i = x as i32; + y = x - (i as f32); + p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); + q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { + z *= y + 6.0; + } + if i >= 6 { + z *= y + 5.0; + } + if i >= 5 { + z *= y + 4.0; + } + if i >= 4 { + z *= y + 3.0; + } + if i >= 3 { + z *= y + 2.0; + r += logf(z); + } + } else if ix < 0x5c800000 { + /* 8.0 <= x < 2**58 */ + t = logf(x); + z = 1.0 / x; + y = z * z; + w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else { + /* 2**58 <= x <= inf */ + r = x * (logf(x) - 1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index b70b0cd6b32..c4d24741469 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -129,7 +129,9 @@ mod jnf; mod ldexp; mod ldexpf; mod lgamma; +mod lgamma_r; mod lgammaf; +mod lgammaf_r; mod log; mod log10; mod log10f; @@ -233,9 +235,9 @@ pub use self::jnf::ynf; pub use self::ldexp::ldexp; pub use self::ldexpf::ldexpf; pub use self::lgamma::lgamma; -pub use self::lgamma::lgamma_r; +pub use self::lgamma_r::lgamma_r; pub use self::lgammaf::lgammaf; -pub use self::lgammaf::lgammaf_r; +pub use self::lgammaf_r::lgammaf_r; pub use self::log::log; pub use self::log10::log10; pub use self::log10f::log10f; diff --git a/library/compiler-builtins/libm/src/math/modf.rs b/library/compiler-builtins/libm/src/math/modf.rs index a37f8b918a3..bcab33a810d 100644 --- a/library/compiler-builtins/libm/src/math/modf.rs +++ b/library/compiler-builtins/libm/src/math/modf.rs @@ -2,7 +2,7 @@ pub fn modf(x: f64) -> (f64, f64) { let rv2: f64; let mut u = x.to_bits(); let mask: u64; - let e = ((u >> 52 & 0x7ff) as isize) - 0x3ff; + let e = ((u >> 52 & 0x7ff) as i32) - 0x3ff; /* no fractional part */ if e >= 52 { diff --git a/library/compiler-builtins/libm/src/math/modff.rs b/library/compiler-builtins/libm/src/math/modff.rs index 4ce9052e7ea..56ece12e3c0 100644 --- a/library/compiler-builtins/libm/src/math/modff.rs +++ b/library/compiler-builtins/libm/src/math/modff.rs @@ -2,7 +2,7 @@ pub fn modff(x: f32) -> (f32, f32) { let rv2: f32; let mut u: u32 = x.to_bits(); let mask: u32; - let e = ((u >> 23 & 0xff) as isize) - 0x7f; + let e = ((u >> 23 & 0xff) as i32) - 0x7f; /* no fractional part */ if e >= 23 { diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs index 3681b947cc2..507f8db347a 100644 --- a/library/compiler-builtins/libm/src/math/remquo.rs +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -1,8 +1,8 @@ -pub fn remquo(mut x: f64, mut y: f64) -> (f64, isize) { +pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { let ux: u64 = x.to_bits(); let mut uy: u64 = y.to_bits(); - let mut ex = ((ux >> 52) & 0x7ff) as isize; - let mut ey = ((uy >> 52) & 0x7ff) as isize; + let mut ex = ((ux >> 52) & 0x7ff) as i32; + let mut ey = ((uy >> 52) & 0x7ff) as i32; let sx = (ux >> 63) != 0; let sy = (uy >> 63) != 0; let mut q: u32; @@ -88,7 +88,7 @@ pub fn remquo(mut x: f64, mut y: f64) -> (f64, isize) { q += 1; } q &= 0x7fffffff; - let quo = if sx ^ sy { -(q as isize) } else { q as isize }; + let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; if sx { (-x, quo) } else { diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs index 40ded5d6976..6aa4974ed3e 100644 --- a/library/compiler-builtins/libm/src/math/remquof.rs +++ b/library/compiler-builtins/libm/src/math/remquof.rs @@ -1,8 +1,8 @@ -pub fn remquof(mut x: f32, mut y: f32) -> (f32, isize) { +pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { let ux: u32 = x.to_bits(); let mut uy: u32 = y.to_bits(); - let mut ex = ((ux >> 23) & 0xff) as isize; - let mut ey = ((uy >> 23) & 0xff) as isize; + let mut ex = ((ux >> 23) & 0xff) as i32; + let mut ey = ((uy >> 23) & 0xff) as i32; let sx = (ux >> 31) != 0; let sy = (uy >> 31) != 0; let mut q: u32; @@ -87,7 +87,7 @@ pub fn remquof(mut x: f32, mut y: f32) -> (f32, isize) { q += 1; } q &= 0x7fffffff; - let quo = if sx ^ sy { -(q as isize) } else { q as isize }; + let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; if sx { (-x, quo) } else { -- cgit 1.4.1-3-g733a5 From 7c1e4dbf117e761c567b8ecdfb62053dc54b3712 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Thu, 9 May 2019 07:36:52 +0300 Subject: fix traits --- library/compiler-builtins/libm/build.rs | 20 ++++++------ library/compiler-builtins/libm/src/lib.rs | 52 +++++++++++-------------------- 2 files changed, 28 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 4d739a12112..4da50a885d9 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -41,18 +41,18 @@ mod musl_reference_tests { "rem_pio2.rs", "rem_pio2_large.rs", "rem_pio2f.rs", - "remquo.rs", // more than 1 result - "remquof.rs", // more than 1 result + "remquo.rs", // more than 1 result + "remquof.rs", // more than 1 result "lgamma_r.rs", // more than 1 result "lgammaf_r.rs", // more than 1 result - "frexp.rs", // more than 1 result - "frexpf.rs", // more than 1 result - "sincos.rs", // more than 1 result - "sincosf.rs", // more than 1 result - "modf.rs", // more than 1 result - "modff.rs", // more than 1 result - "jn.rs", // passed, but very slow - "jnf.rs", // passed, but very slow + "frexp.rs", // more than 1 result + "frexpf.rs", // more than 1 result + "sincos.rs", // more than 1 result + "sincosf.rs", // more than 1 result + "modf.rs", // more than 1 result + "modff.rs", // more than 1 result + "jn.rs", // passed, but very slow + "jnf.rs", // passed, but very slow ]; struct Function { diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 5e94541ab1a..0d0f6155abe 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -119,13 +119,7 @@ pub trait F32Ext: private::Sealed + Sized { fn atan2(self, other: Self) -> Self; - #[inline] - fn sin_cos(self) -> (Self, Self) - where - Self: Copy, - { - (self.sin(), self.cos()) - } + fn sin_cos(self) -> (Self, Self); fn exp_m1(self) -> Self; @@ -289,6 +283,11 @@ impl F32Ext for f32 { atan2f(self, other) } + #[inline] + fn sin_cos(self) -> (Self, Self) { + sincosf(self) + } + #[inline] fn exp_m1(self) -> Self { expm1f(self) @@ -316,24 +315,17 @@ impl F32Ext for f32 { #[inline] fn asinh(self) -> Self { - if self == f32::NEG_INFINITY { - f32::NEG_INFINITY - } else { - (self + ((self * self) + 1.0).sqrt()).ln() - } + asinhf(self) } #[inline] fn acosh(self) -> Self { - match self { - x if x < 1.0 => f32::NAN, - x => (x + ((x * x) - 1.0).sqrt()).ln(), - } + acoshf(self) } #[inline] fn atanh(self) -> Self { - 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() + atanhf(self) } } @@ -401,13 +393,7 @@ pub trait F64Ext: private::Sealed + Sized { fn atan2(self, other: Self) -> Self; - #[inline] - fn sin_cos(self) -> (Self, Self) - where - Self: Copy, - { - (self.sin(), self.cos()) - } + fn sin_cos(self) -> (Self, Self); fn exp_m1(self) -> Self; @@ -571,6 +557,11 @@ impl F64Ext for f64 { atan2(self, other) } + #[inline] + fn sin_cos(self) -> (Self, Self) { + sincos(self) + } + #[inline] fn exp_m1(self) -> Self { expm1(self) @@ -598,24 +589,17 @@ impl F64Ext for f64 { #[inline] fn asinh(self) -> Self { - if self == f64::NEG_INFINITY { - f64::NEG_INFINITY - } else { - (self + ((self * self) + 1.0).sqrt()).ln() - } + asinh(self) } #[inline] fn acosh(self) -> Self { - match self { - x if x < 1.0 => f64::NAN, - x => (x + ((x * x) - 1.0).sqrt()).ln(), - } + acosh(self) } #[inline] fn atanh(self) -> Self { - 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() + atanh(self) } } -- cgit 1.4.1-3-g733a5 From bb88bad22298777c908ea6fdc91049c0e9bb942c Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Thu, 9 May 2019 12:10:11 +0300 Subject: test several outputs --- library/compiler-builtins/libm/build.rs | 170 +++++++++++++++------ library/compiler-builtins/libm/src/math/remquo.rs | 4 +- library/compiler-builtins/libm/src/math/remquof.rs | 4 +- 3 files changed, 125 insertions(+), 53 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 4da50a885d9..642e929ce5d 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -27,38 +27,30 @@ mod musl_reference_tests { // These files are all internal functions or otherwise miscellaneous, not // defining a function we want to test. const IGNORED_FILES: &[&str] = &[ - "expo2.rs", + "expo2.rs", // kernel, private "fenv.rs", - "k_cos.rs", - "k_cosf.rs", - "k_expo2.rs", - "k_expo2f.rs", - "k_sin.rs", - "k_sinf.rs", - "k_tan.rs", - "k_tanf.rs", + "k_cos.rs", // kernel, private + "k_cosf.rs", // kernel, private + "k_expo2.rs", // kernel, private + "k_expo2f.rs", // kernel, private + "k_sin.rs", // kernel, private + "k_sinf.rs", // kernel, private + "k_tan.rs", // kernel, private + "k_tanf.rs", // kernel, private "mod.rs", - "rem_pio2.rs", - "rem_pio2_large.rs", - "rem_pio2f.rs", - "remquo.rs", // more than 1 result - "remquof.rs", // more than 1 result - "lgamma_r.rs", // more than 1 result - "lgammaf_r.rs", // more than 1 result - "frexp.rs", // more than 1 result - "frexpf.rs", // more than 1 result - "sincos.rs", // more than 1 result - "sincosf.rs", // more than 1 result - "modf.rs", // more than 1 result - "modff.rs", // more than 1 result - "jn.rs", // passed, but very slow - "jnf.rs", // passed, but very slow + "rem_pio2.rs", // kernel, private + "rem_pio2_large.rs", // kernel, private + "rem_pio2f.rs", // kernel, private + "sincos.rs", // more than 1 result + "sincosf.rs", // more than 1 result + "jn.rs", // passed, but very slow + "jnf.rs", // passed, but very slow ]; struct Function { name: String, args: Vec, - ret: Ty, + ret: Vec, tests: Vec, } @@ -71,7 +63,7 @@ mod musl_reference_tests { struct Test { inputs: Vec, - output: i64, + outputs: Vec, } pub fn generate() { @@ -103,7 +95,7 @@ mod musl_reference_tests { // After we have all our inputs, use the x86_64-unknown-linux-musl // target to generate the expected output. generate_test_outputs(&mut math); - + //panic!("Boo"); // ... and now that we have both inputs and expected outputs, do a bunch // of codegen to create the unit tests which we'll actually execute. generate_unit_tests(&math); @@ -125,7 +117,7 @@ mod musl_reference_tests { .collect::>(); let tail = &s[end + 1..]; let tail = eat(tail, " -> "); - let ret = parse_ty(tail.trim().split(' ').next().unwrap()); + let ret = parse_retty(tail.replace("{", "").trim()); return Function { name: name.to_string(), @@ -144,6 +136,16 @@ mod musl_reference_tests { } } + fn parse_retty(s: &str) -> Vec { + match s { + "(f32, f32)" => vec![Ty::F32, Ty::F32], + "(f32, i32)" => vec![Ty::F32, Ty::I32], + "(f64, f64)" => vec![Ty::F64, Ty::F64], + "(f64, i32)" => vec![Ty::F64, Ty::I32], + other => vec![parse_ty(other)], + } + } + fn eat<'a>(s: &'a str, prefix: &str) -> &'a str { if s.starts_with(prefix) { &s[prefix.len()..] @@ -163,7 +165,10 @@ mod musl_reference_tests { fn generate_test(args: &[Ty], rng: &mut R) -> Test { let inputs = args.iter().map(|ty| ty.gen_i64(rng)).collect(); // zero output for now since we'll generate it later - Test { inputs, output: 0 } + Test { + inputs, + outputs: vec![], + } } } @@ -192,6 +197,33 @@ mod musl_reference_tests { Ty::Bool => "i32", } } + + fn libc_pty(&self) -> &'static str { + match self { + Ty::F32 => "*mut f32", + Ty::F64 => "*mut f64", + Ty::I32 => "*mut i32", + Ty::Bool => "*mut i32", + } + } + + fn default(&self) -> &'static str { + match self { + Ty::F32 => "0_f32", + Ty::F64 => "0_f64", + Ty::I32 => "0_i32", + Ty::Bool => "false", + } + } + + fn to_i64(&self) -> &'static str { + match self { + Ty::F32 => ".to_bits() as i64", + Ty::F64 => ".to_bits() as i64", + Ty::I32 => " as i64", + Ty::Bool => " as i64", + } + } } fn generate_test_outputs(functions: &mut [Function]) { @@ -212,8 +244,11 @@ mod musl_reference_tests { for (i, arg) in function.args.iter().enumerate() { src.push_str(&format!("arg{}: {},", i, arg.libc_ty())); } + for (i, ret) in function.ret.iter().skip(1).enumerate() { + src.push_str(&format!("argret{}: {},", i, ret.libc_pty())); + } src.push_str(") -> "); - src.push_str(function.ret.libc_ty()); + src.push_str(function.ret[0].libc_ty()); src.push_str("; }"); src.push_str(&format!("static TESTS: &[[i64; {}]]", function.args.len())); @@ -229,6 +264,14 @@ mod musl_reference_tests { src.push_str("];"); src.push_str("for test in TESTS {"); + for (i, arg) in function.ret.iter().skip(1).enumerate() { + src.push_str(&format!("let mut argret{} = {};", i, arg.default())); + src.push_str(&format!( + "let argret_ptr{0} = &mut argret{0} as *mut {1};", + i, + arg.libc_ty() + )); + } src.push_str("let output = "); src.push_str(&function.name); src.push_str("("); @@ -241,17 +284,20 @@ mod musl_reference_tests { }); src.push_str(","); } + for (i, _) in function.ret.iter().skip(1).enumerate() { + src.push_str(&format!("argret_ptr{},", i)); + } src.push_str(");"); - src.push_str("let output = "); - src.push_str(match function.ret { - Ty::F32 => "output.to_bits() as i64", - Ty::F64 => "output.to_bits() as i64", - Ty::I32 => "output as i64", - Ty::Bool => "output as i64", - }); - src.push_str(";"); + src.push_str(&format!("let output = output{};", function.ret[0].to_i64())); src.push_str("result.extend_from_slice(&output.to_le_bytes());"); + for (i, ret) in function.ret.iter().skip(1).enumerate() { + src.push_str(&format!("let output{0} = argret{0}{1};", i, ret.to_i64())); + src.push_str(&format!( + "result.extend_from_slice(&output{}.to_le_bytes());", + i + )); + } src.push_str("}"); src.push_str("}"); @@ -288,8 +334,13 @@ mod musl_reference_tests { i64::from_le_bytes(exact) }); - for test in functions.iter_mut().flat_map(|f| f.tests.iter_mut()) { - test.output = results.next().unwrap(); + for f in functions.iter_mut() { + for test in f.tests.iter_mut() { + test.outputs = vec![results.next().unwrap()]; + for _ in f.ret.iter().skip(1) { + test.outputs.push(results.next().unwrap()); + } + } } assert!(results.next().is_none()); } @@ -306,8 +357,9 @@ mod musl_reference_tests { src.push_str(&function.name); src.push_str("_matches_musl() {"); src.push_str(&format!( - "static TESTS: &[([i64; {}], i64)]", - function.args.len() + "static TESTS: &[([i64; {}], [i64; {}])]", + function.args.len(), + function.ret.len(), )); src.push_str(" = &["); for test in function.tests.iter() { @@ -317,7 +369,12 @@ mod musl_reference_tests { src.push_str(","); } src.push_str("],"); - src.push_str(&test.output.to_string()); + src.push_str("["); + for val in test.outputs.iter() { + src.push_str(&val.to_string()); + src.push_str(","); + } + src.push_str("],"); src.push_str("),"); } src.push_str("];"); @@ -336,12 +393,27 @@ mod musl_reference_tests { src.push_str(","); } src.push_str(");"); - src.push_str(match function.ret { - Ty::F32 => "if _eqf(output, f32::from_bits(*expected as u32)).is_ok() { continue }", - Ty::F64 => "if _eq(output, f64::from_bits(*expected as u64)).is_ok() { continue }", - Ty::I32 => "if output as i64 == *expected { continue }", - Ty::Bool => unreachable!(), - }); + if function.ret.len() > 1 { + for (i, ret) in function.ret.iter().enumerate() { + src.push_str(&(match ret { + Ty::F32 => format!("if _eqf(output.{0}, f32::from_bits(expected[{0}] as u32)).is_ok() {{ continue }}", i), + Ty::F64 => format!("if _eq(output.{0}, f64::from_bits(expected[{0}] as u64)).is_ok() {{ continue }}", i), + Ty::I32 => format!("if output.{0} as i64 == expected[{0}] {{ continue }}", i), + Ty::Bool => unreachable!(), + })); + } + } else { + src.push_str(match function.ret[0] { + Ty::F32 => { + "if _eqf(output, f32::from_bits(expected[0] as u32)).is_ok() { continue }" + } + Ty::F64 => { + "if _eq(output, f64::from_bits(expected[0] as u64)).is_ok() { continue }" + } + Ty::I32 => "if output as i64 == expected[0] { continue }", + Ty::Bool => unreachable!(), + }); + } src.push_str( r#" diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs index 507f8db347a..1c2ba8918cb 100644 --- a/library/compiler-builtins/libm/src/math/remquo.rs +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -48,7 +48,7 @@ pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { } /* x mod y */ while ex > ey { - i = uxi - uy; + i = uxi.wrapping_sub(uy); if (i >> 63) == 0 { uxi = i; q += 1; @@ -57,7 +57,7 @@ pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { q <<= 1; ex -= 1; } - i = uxi - uy; + i = uxi.wrapping_sub(uy); if (i >> 63) == 0 { uxi = i; q += 1; diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs index 6aa4974ed3e..871d0c7d696 100644 --- a/library/compiler-builtins/libm/src/math/remquof.rs +++ b/library/compiler-builtins/libm/src/math/remquof.rs @@ -47,7 +47,7 @@ pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { } /* x mod y */ while ex > ey { - i = uxi - uy; + i = uxi.wrapping_sub(uy); if (i >> 31) == 0 { uxi = i; q += 1; @@ -56,7 +56,7 @@ pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { q <<= 1; ex -= 1; } - i = uxi - uy; + i = uxi.wrapping_sub(uy); if (i >> 31) == 0 { uxi = i; q += 1; -- cgit 1.4.1-3-g733a5 From 13981db1e106deb18a1a8ad5dafd47e56b471b2c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 9 May 2019 07:27:10 -0700 Subject: Move non-public functions to `pub(crate)` Remove exceptions from the test list after doing so --- library/compiler-builtins/libm/build.rs | 13 ------------- library/compiler-builtins/libm/src/math/expo2.rs | 2 +- library/compiler-builtins/libm/src/math/k_cos.rs | 2 +- library/compiler-builtins/libm/src/math/k_cosf.rs | 2 +- library/compiler-builtins/libm/src/math/k_expo2f.rs | 2 +- library/compiler-builtins/libm/src/math/k_sin.rs | 2 +- library/compiler-builtins/libm/src/math/k_sinf.rs | 2 +- library/compiler-builtins/libm/src/math/k_tan.rs | 2 +- library/compiler-builtins/libm/src/math/k_tanf.rs | 2 +- library/compiler-builtins/libm/src/math/rem_pio2.rs | 2 +- library/compiler-builtins/libm/src/math/rem_pio2_large.rs | 4 ++-- library/compiler-builtins/libm/src/math/rem_pio2f.rs | 2 +- 12 files changed, 12 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 642e929ce5d..896b41326a3 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -27,20 +27,7 @@ mod musl_reference_tests { // These files are all internal functions or otherwise miscellaneous, not // defining a function we want to test. const IGNORED_FILES: &[&str] = &[ - "expo2.rs", // kernel, private "fenv.rs", - "k_cos.rs", // kernel, private - "k_cosf.rs", // kernel, private - "k_expo2.rs", // kernel, private - "k_expo2f.rs", // kernel, private - "k_sin.rs", // kernel, private - "k_sinf.rs", // kernel, private - "k_tan.rs", // kernel, private - "k_tanf.rs", // kernel, private - "mod.rs", - "rem_pio2.rs", // kernel, private - "rem_pio2_large.rs", // kernel, private - "rem_pio2f.rs", // kernel, private "sincos.rs", // more than 1 result "sincosf.rs", // more than 1 result "jn.rs", // passed, but very slow diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs index 9e60ca99422..ae6cc8121e0 100644 --- a/library/compiler-builtins/libm/src/math/expo2.rs +++ b/library/compiler-builtins/libm/src/math/expo2.rs @@ -3,7 +3,7 @@ use super::{combine_words, exp}; /* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn expo2(x: f64) -> f64 { +pub(crate) fn expo2(x: f64) -> f64 { /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ const K: i32 = 2043; let kln2 = f64::from_bits(0x40962066151add8b); diff --git a/library/compiler-builtins/libm/src/math/k_cos.rs b/library/compiler-builtins/libm/src/math/k_cos.rs index 8876fac2143..4687b369a61 100644 --- a/library/compiler-builtins/libm/src/math/k_cos.rs +++ b/library/compiler-builtins/libm/src/math/k_cos.rs @@ -53,7 +53,7 @@ const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ // any extra precision in w. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn k_cos(x: f64, y: f64) -> f64 { +pub(crate) fn k_cos(x: f64, y: f64) -> f64 { let z = x * x; let w = z * z; let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs index 9b48e190ddd..79d0f238fce 100644 --- a/library/compiler-builtins/libm/src/math/k_cosf.rs +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -22,7 +22,7 @@ const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn k_cosf(x: f64) -> f32 { +pub(crate) fn k_cosf(x: f64) -> f32 { let z = x * x; let w = z * z; let r = C2 + z * C3; diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs index 68a7a50325c..de850777259 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2f.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -6,7 +6,7 @@ const K: i32 = 235; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn k_expo2f(x: f32) -> f32 { +pub(crate) fn k_expo2f(x: f32) -> f32 { let k_ln2 = f32::from_bits(0x4322e3bc); /* note that k is odd and scale*scale overflows */ let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs index 15718c4c926..5d2bd68aa95 100644 --- a/library/compiler-builtins/libm/src/math/k_sin.rs +++ b/library/compiler-builtins/libm/src/math/k_sin.rs @@ -45,7 +45,7 @@ const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ // sin(x) = x + (S1*x + (x *(r-y/2)+y)) #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn k_sin(x: f64, y: f64, iy: i32) -> f64 { +pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { let z = x * x; let w = z * z; let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs index 157fc104cc7..68fe926c217 100644 --- a/library/compiler-builtins/libm/src/math/k_sinf.rs +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -22,7 +22,7 @@ const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn k_sinf(x: f64) -> f32 { +pub(crate) fn k_sinf(x: f64) -> f32 { let z = x * x; let w = z * z; let r = S3 + z * S4; diff --git a/library/compiler-builtins/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/src/math/k_tan.rs index 684e937b93c..ea3c386b002 100644 --- a/library/compiler-builtins/libm/src/math/k_tan.rs +++ b/library/compiler-builtins/libm/src/math/k_tan.rs @@ -60,7 +60,7 @@ const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { +pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { let hx = (f64::to_bits(x) >> 32) as u32; let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ if big { diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs index 96a59100708..52651378db5 100644 --- a/library/compiler-builtins/libm/src/math/k_tanf.rs +++ b/library/compiler-builtins/libm/src/math/k_tanf.rs @@ -21,7 +21,7 @@ const T: [f64; 6] = [ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn k_tanf(x: f64, odd: bool) -> f32 { +pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { let z = x * x; /* * Split up the polynomial into small independent terms to give diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 951dd08b429..285663ea2c0 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -43,7 +43,7 @@ const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ // caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rem_pio2(x: f64) -> (i32, f64, f64) { +pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { let x1p24 = f64::from_bits(0x4170000000000000); let sign = (f64::to_bits(x) >> 63) as i32; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 8bab485695e..006d3e153db 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -224,11 +224,11 @@ const PIO2: [f64; 8] = [ /// independent of the exponent of the input. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { +pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) - #[cfg(target_pointer_width = "64")] + #[cfg(all(target_pointer_width = "64", feature = "checked"))] assert!(e0 <= 16360); let nx = x.len(); diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 054c311841f..af2745d1be9 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -33,7 +33,7 @@ const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ /// use __rem_pio2_large() for large x #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rem_pio2f(x: f32) -> (i32, f64) { +pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { let x64 = x as f64; let mut tx: [f64; 1] = [0.]; -- cgit 1.4.1-3-g733a5 From f3e2ed67f917820906e5b1438b1e8ce9b7a706ae Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 9 May 2019 07:52:52 -0700 Subject: Test sincos and sincosf --- library/compiler-builtins/libm/build.rs | 81 +++++++++++++++------------------ 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 896b41326a3..b913a3e3105 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -28,10 +28,8 @@ mod musl_reference_tests { // defining a function we want to test. const IGNORED_FILES: &[&str] = &[ "fenv.rs", - "sincos.rs", // more than 1 result - "sincosf.rs", // more than 1 result - "jn.rs", // passed, but very slow - "jnf.rs", // passed, but very slow + "jn.rs", // passed, but very slow + "jnf.rs", // passed, but very slow ]; struct Function { @@ -228,14 +226,22 @@ mod musl_reference_tests { src.push_str("extern { fn "); src.push_str(&function.name); src.push_str("("); + + let (ret, retptr) = match function.name.as_str() { + "sincos" | "sincosf" => (None, &function.ret[..]), + _ => (Some(&function.ret[0]), &function.ret[1..]), + }; for (i, arg) in function.args.iter().enumerate() { src.push_str(&format!("arg{}: {},", i, arg.libc_ty())); } - for (i, ret) in function.ret.iter().skip(1).enumerate() { + for (i, ret) in retptr.iter().enumerate() { src.push_str(&format!("argret{}: {},", i, ret.libc_pty())); } - src.push_str(") -> "); - src.push_str(function.ret[0].libc_ty()); + src.push_str(")"); + if let Some(ty) = ret { + src.push_str(" -> "); + src.push_str(ty.libc_ty()); + } src.push_str("; }"); src.push_str(&format!("static TESTS: &[[i64; {}]]", function.args.len())); @@ -251,13 +257,8 @@ mod musl_reference_tests { src.push_str("];"); src.push_str("for test in TESTS {"); - for (i, arg) in function.ret.iter().skip(1).enumerate() { + for (i, arg) in retptr.iter().enumerate() { src.push_str(&format!("let mut argret{} = {};", i, arg.default())); - src.push_str(&format!( - "let argret_ptr{0} = &mut argret{0} as *mut {1};", - i, - arg.libc_ty() - )); } src.push_str("let output = "); src.push_str(&function.name); @@ -271,18 +272,20 @@ mod musl_reference_tests { }); src.push_str(","); } - for (i, _) in function.ret.iter().skip(1).enumerate() { - src.push_str(&format!("argret_ptr{},", i)); + for (i, _) in retptr.iter().enumerate() { + src.push_str(&format!("&mut argret{},", i)); } src.push_str(");"); - src.push_str(&format!("let output = output{};", function.ret[0].to_i64())); - src.push_str("result.extend_from_slice(&output.to_le_bytes());"); + if let Some(ty) = &ret { + src.push_str(&format!("let output = output{};", ty.to_i64())); + src.push_str("result.extend_from_slice(&output.to_le_bytes());"); + } - for (i, ret) in function.ret.iter().skip(1).enumerate() { - src.push_str(&format!("let output{0} = argret{0}{1};", i, ret.to_i64())); + for (i, ret) in retptr.iter().enumerate() { src.push_str(&format!( - "result.extend_from_slice(&output{}.to_le_bytes());", - i + "result.extend_from_slice(&(argret{}{}).to_le_bytes());", + i, + ret.to_i64(), )); } src.push_str("}"); @@ -323,10 +326,7 @@ mod musl_reference_tests { for f in functions.iter_mut() { for test in f.tests.iter_mut() { - test.outputs = vec![results.next().unwrap()]; - for _ in f.ret.iter().skip(1) { - test.outputs.push(results.next().unwrap()); - } + test.outputs = (0..f.ret.len()).map(|_| results.next().unwrap()).collect(); } } assert!(results.next().is_none()); @@ -380,26 +380,19 @@ mod musl_reference_tests { src.push_str(","); } src.push_str(");"); - if function.ret.len() > 1 { - for (i, ret) in function.ret.iter().enumerate() { - src.push_str(&(match ret { - Ty::F32 => format!("if _eqf(output.{0}, f32::from_bits(expected[{0}] as u32)).is_ok() {{ continue }}", i), - Ty::F64 => format!("if _eq(output.{0}, f64::from_bits(expected[{0}] as u64)).is_ok() {{ continue }}", i), - Ty::I32 => format!("if output.{0} as i64 == expected[{0}] {{ continue }}", i), - Ty::Bool => unreachable!(), - })); - } - } else { - src.push_str(match function.ret[0] { - Ty::F32 => { - "if _eqf(output, f32::from_bits(expected[0] as u32)).is_ok() { continue }" - } - Ty::F64 => { - "if _eq(output, f64::from_bits(expected[0] as u64)).is_ok() { continue }" - } - Ty::I32 => "if output as i64 == expected[0] { continue }", + + for (i, ret) in function.ret.iter().enumerate() { + let get = if function.ret.len() == 1 { + String::new() + } else { + format!(".{}", i) + }; + src.push_str(&(match ret { + Ty::F32 => format!("if _eqf(output{}, f32::from_bits(expected[{}] as u32)).is_ok() {{ continue }}", get, i), + Ty::F64 => format!("if _eq(output{}, f64::from_bits(expected[{}] as u64)).is_ok() {{ continue }}", get, i), + Ty::I32 => format!("if output{} as i64 == expected[{}] {{ continue }}", get, i), Ty::Bool => unreachable!(), - }); + })); } src.push_str( -- cgit 1.4.1-3-g733a5 From fba10c51e62555d58857f15f96c2a96aa5c0d299 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 9 May 2019 07:53:21 -0700 Subject: Generate NaN and Infinity more often Make sure they come up in RNG generation of floats --- library/compiler-builtins/libm/build.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index b913a3e3105..decb91692be 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -159,9 +159,26 @@ mod musl_reference_tests { impl Ty { fn gen_i64(&self, r: &mut R) -> i64 { - match self { - Ty::F32 => r.gen::().to_bits().into(), - Ty::F64 => r.gen::().to_bits() as i64, + use std::f32; + use std::f64; + + return match self { + Ty::F32 => { + if r.gen_range(0, 20) < 1 { + let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY].choose(r).unwrap(); + i.to_bits().into() + } else { + r.gen::().to_bits().into() + } + } + Ty::F64 => { + if r.gen_range(0, 20) < 1 { + let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY].choose(r).unwrap(); + i.to_bits() as i64 + } else { + r.gen::().to_bits() as i64 + } + } Ty::I32 => { if r.gen_range(0, 10) < 1 { let i = *[i32::max_value(), 0, i32::min_value()].choose(r).unwrap(); @@ -171,7 +188,7 @@ mod musl_reference_tests { } } Ty::Bool => r.gen::() as i64, - } + }; } fn libc_ty(&self) -> &'static str { -- cgit 1.4.1-3-g733a5 From 8a74ccde217846a56b8c17419e92767730ca0631 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 9 May 2019 07:58:57 -0700 Subject: Test jn and jnf --- library/compiler-builtins/libm/build.rs | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index decb91692be..bf28fe23c1f 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -28,8 +28,6 @@ mod musl_reference_tests { // defining a function we want to test. const IGNORED_FILES: &[&str] = &[ "fenv.rs", - "jn.rs", // passed, but very slow - "jnf.rs", // passed, but very slow ]; struct Function { @@ -143,15 +141,28 @@ mod musl_reference_tests { fn generate_random_tests(functions: &mut [Function], rng: &mut R) { for function in functions { for _ in 0..NTESTS { - function.tests.push(generate_test(&function.args, rng)); + function.tests.push(generate_test(function, rng)); } } - fn generate_test(args: &[Ty], rng: &mut R) -> Test { - let inputs = args.iter().map(|ty| ty.gen_i64(rng)).collect(); - // zero output for now since we'll generate it later + fn generate_test(function: &Function, rng: &mut R) -> Test { + let mut inputs = function + .args + .iter() + .map(|ty| ty.gen_i64(rng)) + .collect::>(); + + // First argument to this function appears to be a number of + // iterations, so passing in massive random numbers causes it to + // take forever to execute, so make sure we're not running random + // math code until the heat death of the universe. + if function.name == "jn" || function.name == "jnf" { + inputs[0] &= 0xffff; + } + Test { inputs, + // zero output for now since we'll generate it later outputs: vec![], } } @@ -165,7 +176,9 @@ mod musl_reference_tests { return match self { Ty::F32 => { if r.gen_range(0, 20) < 1 { - let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY].choose(r).unwrap(); + let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY] + .choose(r) + .unwrap(); i.to_bits().into() } else { r.gen::().to_bits().into() @@ -173,7 +186,9 @@ mod musl_reference_tests { } Ty::F64 => { if r.gen_range(0, 20) < 1 { - let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY].choose(r).unwrap(); + let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY] + .choose(r) + .unwrap(); i.to_bits() as i64 } else { r.gen::().to_bits() as i64 -- cgit 1.4.1-3-g733a5 From 0dff1621e025503ad5b7c3f01472f10c68efb98a Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Thu, 9 May 2019 18:40:19 +0300 Subject: fix jn, ilogb --- library/compiler-builtins/libm/build.rs | 4 +--- library/compiler-builtins/libm/src/math/ilogb.rs | 14 +++++++------- library/compiler-builtins/libm/src/math/ilogbf.rs | 14 +++++++------- library/compiler-builtins/libm/src/math/jn.rs | 4 ++-- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index bf28fe23c1f..9af6dec938b 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -26,9 +26,7 @@ mod musl_reference_tests { // These files are all internal functions or otherwise miscellaneous, not // defining a function we want to test. - const IGNORED_FILES: &[&str] = &[ - "fenv.rs", - ]; + const IGNORED_FILES: &[&str] = &["fenv.rs"]; struct Function { name: String, diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs index 8a1289ca444..0a380b7efd3 100644 --- a/library/compiler-builtins/libm/src/math/ilogb.rs +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -1,4 +1,4 @@ -const FP_ILOGBNAN: i32 = -1 - ((!0) >> 1); +const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; const FP_ILOGB0: i32 = FP_ILOGBNAN; pub fn ilogb(x: f64) -> i32 { @@ -17,15 +17,15 @@ pub fn ilogb(x: f64) -> i32 { e -= 1; i <<= 1; } - return e; - } - if e == 0x7ff { + e + } else if e == 0x7ff { force_eval!(0.0 / 0.0); if (i << 12) != 0 { - return FP_ILOGBNAN; + FP_ILOGBNAN } else { - return i32::max_value(); + i32::max_value() } + } else { + e - 0x3ff } - return e - 0x3ff; } diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs index 1bf4670a812..b384fa4b20d 100644 --- a/library/compiler-builtins/libm/src/math/ilogbf.rs +++ b/library/compiler-builtins/libm/src/math/ilogbf.rs @@ -1,4 +1,4 @@ -const FP_ILOGBNAN: i32 = -1 - ((!0) >> 1); +const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; const FP_ILOGB0: i32 = FP_ILOGBNAN; pub fn ilogbf(x: f32) -> i32 { @@ -17,15 +17,15 @@ pub fn ilogbf(x: f32) -> i32 { e -= 1; i <<= 1; } - return e; - } - if e == 0xff { + e + } else if e == 0xff { force_eval!(0.0 / 0.0); if (i << 9) != 0 { - return FP_ILOGBNAN; + FP_ILOGBNAN } else { - return i32::max_value(); + i32::max_value() } + } else { + e - 0x7f } - return e - 0x7f; } diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs index 70c98026685..1be167f8461 100644 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -54,7 +54,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { ix &= 0x7fffffff; // -lx == !lx + 1 - if (ix | (lx | (!lx + 1)) >> 31) > 0x7ff00000 { + if (ix | (lx | ((!lx).wrapping_add(1))) >> 31) > 0x7ff00000 { /* nan */ return x; } @@ -268,7 +268,7 @@ pub fn yn(n: i32, x: f64) -> f64 { ix &= 0x7fffffff; // -lx == !lx + 1 - if (ix | (lx | (!lx + 1)) >> 31) > 0x7ff00000 { + if (ix | (lx | ((!lx).wrapping_add(1))) >> 31) > 0x7ff00000 { /* nan */ return x; } -- cgit 1.4.1-3-g733a5 From f8e5ff50c53f3bb15fb3ea4d1e8e8ecc21436b48 Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 13 May 2019 12:14:03 +0300 Subject: rem_pio2: actually return medium value for x ~<= 5pi/4 --- library/compiler-builtins/libm/src/math/rem_pio2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 285663ea2c0..186333e570d 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -85,7 +85,7 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { /* |x| ~<= 5pi/4 */ if (ix & 0xfffff) == 0x921fb { /* |x| ~= pi/2 or 2pi/2 */ - medium(x, ix); /* cancellation -- use medium case */ + return medium(x, ix); /* cancellation -- use medium case */ } if ix <= 0x4002d97c { /* |x| ~<= 3pi/4 */ -- cgit 1.4.1-3-g733a5 From d58376453078ccb67e602a69eaa33724bcd9b434 Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 13 May 2019 17:42:18 +0300 Subject: added tests near pi for rem_pio2 --- library/compiler-builtins/libm/src/math/rem_pio2.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/sin.rs | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 186333e570d..e46e6623e44 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -185,3 +185,11 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { } (n, ty[0], ty[1]) } + +#[test] +fn test_near_pi() { + assert_eq!(rem_pio2(3.141592025756836), (2, -6.278329573009626e-7, -2.1125998133974653e-23)); + assert_eq!(rem_pio2(3.141592033207416), (2, -6.20382377148128e-7, -2.1125998133974653e-23)); + assert_eq!(rem_pio2(3.141592144966125), (2, -5.086236681942706e-7, -2.1125998133974653e-23)); + assert_eq!(rem_pio2(3.141592979431152), (2, 3.2584135866119817e-7, -2.1125998133974653e-23)); +} diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index b7307441646..51aed88a8db 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -77,3 +77,10 @@ pub fn sin(x: f64) -> f64 { _ => -k_cos(y0, y1), } } + +#[test] +fn test_near_pi() { + let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 + let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 + assert_eq!(sin(x), sx); +} -- cgit 1.4.1-3-g733a5 From 03f6b3194e50104a6bb4a50de16dd9e21d86dc99 Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 13 May 2019 18:05:38 +0300 Subject: formatted rem_pio2 tests --- library/compiler-builtins/libm/src/math/rem_pio2.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index e46e6623e44..536dfac3c42 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -188,8 +188,20 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { #[test] fn test_near_pi() { - assert_eq!(rem_pio2(3.141592025756836), (2, -6.278329573009626e-7, -2.1125998133974653e-23)); - assert_eq!(rem_pio2(3.141592033207416), (2, -6.20382377148128e-7, -2.1125998133974653e-23)); - assert_eq!(rem_pio2(3.141592144966125), (2, -5.086236681942706e-7, -2.1125998133974653e-23)); - assert_eq!(rem_pio2(3.141592979431152), (2, 3.2584135866119817e-7, -2.1125998133974653e-23)); + assert_eq!( + rem_pio2(3.141592025756836), + (2, -6.278329573009626e-7, -2.1125998133974653e-23) + ); + assert_eq!( + rem_pio2(3.141592033207416), + (2, -6.20382377148128e-7, -2.1125998133974653e-23) + ); + assert_eq!( + rem_pio2(3.141592144966125), + (2, -5.086236681942706e-7, -2.1125998133974653e-23) + ); + assert_eq!( + rem_pio2(3.141592979431152), + (2, 3.2584135866119817e-7, -2.1125998133974653e-23) + ); } -- cgit 1.4.1-3-g733a5 From 546492b69a3e6c8302b51cdc30724a1632396dcf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 May 2019 17:57:42 +0200 Subject: don't force-on c feature when working in rustc workspace --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index a05825a6122..ec9fc13f203 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -58,7 +58,7 @@ mangled-names = [] no-lang-items = [] # Only used in the compiler's build system -rustc-dep-of-std = ['c', 'compiler-builtins', 'core'] +rustc-dep-of-std = ['compiler-builtins', 'core'] [[example]] name = "intrinsics" -- cgit 1.4.1-3-g733a5 From 7448d0fac3b7cbc208192222524936c7a1fec8dc Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 14 May 2019 09:06:43 -0700 Subject: Bump to 0.1.3 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 45fad8230a0..a61db5ebaf8 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" repository = "https://github.com/rust-lang-nursery/libm" -version = "0.1.2" +version = "0.1.3" edition = "2018" [features] -- cgit 1.4.1-3-g733a5 From 6ddcff1475851b9f5adbfc91709937fe4b7cc8cf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 14 May 2019 12:26:09 -0700 Subject: Fix __divsi3 and __udivsi3 on thumbv6m targets This commit fixes a bug accidentally introduced in #285 where some lingering references remained to `#[cfg(thumbv6m)]` but this, since the historical revert, was renamed to `#[cfg(thumb_1)]`. This caused on the thumbv6m platform for the intrinsics to be accidentally omitted because the build script didn't actually compile them but the Rust code thought the C code was in use. After correcting the `#[cfg]` statements the CI configuration for the `thumb*` family of targets was all updated. The support for xargo testing was removed from `run.sh` since it had long since bitrotted, and the script was updated to simply build the intrinsics example to attempt to link for each of these targets. This in turn exposed the bug locally and allowed to confirm a fix once the `#[cfg]` statements were corrected. cc rust-lang/rust#60782 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/azure-pipelines.yml | 20 ++++----- .../ci/docker/thumbv6m-linux-eabi/Dockerfile | 10 ----- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 7 +++ .../ci/docker/thumbv7em-linux-eabi/Dockerfile | 10 ----- .../ci/docker/thumbv7em-linux-eabihf/Dockerfile | 10 ----- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 7 +++ .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 7 +++ .../ci/docker/thumbv7m-linux-eabi/Dockerfile | 10 ----- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 7 +++ library/compiler-builtins/ci/run-docker.sh | 1 - library/compiler-builtins/ci/run.sh | 50 ++++++---------------- library/compiler-builtins/examples/intrinsics.rs | 14 +++++- library/compiler-builtins/src/int/sdiv.rs | 2 +- library/compiler-builtins/src/int/udiv.rs | 2 +- 15 files changed, 64 insertions(+), 95 deletions(-) delete mode 100644 library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile delete mode 100644 library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile delete mode 100644 library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile delete mode 100644 library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index a05825a6122..e7995915bd4 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -62,7 +62,7 @@ rustc-dep-of-std = ['c', 'compiler-builtins', 'core'] [[example]] name = "intrinsics" -required-features = ["c", "compiler-builtins"] +required-features = ["compiler-builtins"] [workspace] members = ["testcrate"] diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml index da3a1bb1d39..eac3fb5e486 100644 --- a/library/compiler-builtins/azure-pipelines.yml +++ b/library/compiler-builtins/azure-pipelines.yml @@ -33,18 +33,14 @@ jobs: TARGET: powerpc64-unknown-linux-gnu powerpc64le: TARGET: powerpc64le-unknown-linux-gnu - # thumbv6m: - # TARGET: thumbv6m-linux-eabi - # XARGO: 1 - # thumbv7em: - # TARGET: thumbv7em-linux-eabi - # XARGO: 1 - # thumbv7emhf: - # TARGET: thumbv7em-linux-eabihf - # XARGO: 1 - # thumbv7m: - # TARGET: thumbv7m-linux-eabi - # XARGO: 1 + thumbv6m: + TARGET: thumbv6m-none-eabi + thumbv7em: + TARGET: thumbv7em-none-eabi + thumbv7emhf: + TARGET: thumbv7em-none-eabihf + thumbv7m: + TARGET: thumbv7m-none-eabi wasm32: TARGET: wasm32-unknown-unknown ONLY_BUILD: 1 diff --git a/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile deleted file mode 100644 index 789bdf4e46c..00000000000 --- a/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static -RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv6m_linux_eabi=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV6M_LINUX_EABI_LINKER=arm-none-eabi-gcc \ - CARGO_TARGET_THUMBV6M_LINUX_EABI_RUNNER=qemu-arm-static \ - CC_thumbv6m_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile new file mode 100644 index 00000000000..04d4f442905 --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV XARGO=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile deleted file mode 100644 index c6ce273c875..00000000000 --- a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static -RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv7em_linux_eabi=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV7EM_LINUX_EABI_LINKER=arm-none-eabi-gcc \ - CARGO_TARGET_THUMBV7EM_LINUX_EABI_RUNNER=qemu-arm-static \ - CC_thumbv7em_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile deleted file mode 100644 index c7518aaca84..00000000000 --- a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static -RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv7em_linux_eabihf=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV7EM_LINUX_EABIHF_LINKER=arm-none-eabi-gcc \ - CARGO_TARGET_THUMBV7EM_LINUX_EABIHF_RUNNER=qemu-arm-static \ - CC_thumbv7em_linux_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile new file mode 100644 index 00000000000..04d4f442905 --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV XARGO=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile new file mode 100644 index 00000000000..04d4f442905 --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV XARGO=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile deleted file mode 100644 index c9071094139..00000000000 --- a/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static -RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv7m_linux_eabi=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV7M_LINUX_EABI_LINKER=arm-none-eabi-gcc \ - CARGO_TARGET_THUMBV7M_LINUX_EABI_RUNNER=qemu-arm-static \ - CC_thumbv7m_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile new file mode 100644 index 00000000000..04d4f442905 --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV XARGO=1 diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index bed84ed81f6..ddb970c1b4a 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -18,7 +18,6 @@ run() { --user $(id -u):$(id -g) \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ - -e XARGO \ -v $HOME/.cargo:/cargo \ -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 27e2de22f70..ae32806ece8 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,53 +1,24 @@ set -ex -# FIXME(japarix/xargo#186) this shouldn't be necessary -export RUST_TARGET_PATH=`pwd` - cargo=cargo -if [ "$XARGO" = "1" ]; then - cargo=xargo -fi - -INTRINSICS_FEATURES="c" - -# Some architectures like ARM apparently seem to require the `mem` feature -# enabled to successfully compile the `intrinsics` example, and... we're not -# sure why! -if [ -z "$INTRINSICS_FAILS_WITH_MEM_FEATURE" ]; then - INTRINSICS_FEATURES="$INTRINSICS_FEATURES mem" -fi # Test our implementation if [ "$XARGO" = "1" ]; then - run="xargo test --manifest-path testcrate/Cargo.toml --target $1" - for t in $(ls testcrate/tests); do - t=${t%.rs} - - RUSTFLAGS="-C debug-assertions=no -C lto" \ - CARGO_INCREMENTAL=0 \ - $run --test $t --no-default-features --features 'mem c' --no-run - qemu-arm-static target/${1}/debug/$t-* - done - - for t in $(ls testcrate/tests); do - t=${t%.rs} - RUSTFLAGS="-C lto" \ - CARGO_INCREMENTAL=0 \ - $run --test $t --no-default-features --features 'mem c' --no-run --release - qemu-arm-static target/${1}/release/$t-* - done + # FIXME: currently these tests don't work... + echo nothing to do else run="cargo test --manifest-path testcrate/Cargo.toml --target $1" $run $run --release $run --features c $run --features c --release - cargo build --target $1 - cargo build --target $1 --release - cargo build --target $1 --features c - cargo build --target $1 --release --features c fi +cargo build --target $1 +cargo build --target $1 --release +cargo build --target $1 --features c +cargo build --target $1 --release --features c + PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in armv7-*) @@ -101,8 +72,11 @@ done rm -f $path # Verify that we haven't drop any intrinsic/symbol -RUSTFLAGS="-C debug-assertions=no" \ - $cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics -v +build_intrinsics="$cargo build --target $1 -v --example intrinsics" +RUSTFLAGS="-C debug-assertions=no" $build_intrinsics +RUSTFLAGS="-C debug-assertions=no" $build_intrinsics --release +RUSTFLAGS="-C debug-assertions=no" $build_intrinsics --features c +RUSTFLAGS="-C debug-assertions=no" $build_intrinsics --features c --release # Verify that there are no undefined symbols to `panic` within our # implementations diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index ccd701569d9..8de108d99b4 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -27,7 +27,14 @@ extern {} mod intrinsics { // trunccdfsf2 pub fn aeabi_d2f(x: f64) -> f32 { - x as f32 + // This is only implemented in C currently, so only test it there. + #[cfg(feature = "c")] + return x as f32; + #[cfg(not(feature = "c"))] + { + drop(x); + 0.0 + } } // fixdfsi @@ -263,6 +270,10 @@ mod intrinsics { pub fn modti3(a: i128, b: i128) -> i128 { a % b } + + pub fn udivsi3(a: u32, b: u32) -> u32 { + a / b + } } fn run() { @@ -325,6 +336,7 @@ fn run() { bb(umodti3(bb(2), bb(2))); bb(divti3(bb(2), bb(2))); bb(modti3(bb(2), bb(2))); + bb(udivsi3(bb(2), bb(2))); something_with_a_dtor(&|| assert_eq!(bb(1), 1)); diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index d7ae71ab293..82262a4412d 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -57,7 +57,7 @@ impl Divmod for i32 {} impl Divmod for i64 {} intrinsics! { - #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] + #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumb_1)))] #[arm_aeabi_alias = __aeabi_idiv] pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { a.div(b) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 7b7f5b44dfa..8837126deef 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -154,7 +154,7 @@ macro_rules! udivmod_inner { intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), - not(thumbv6m)))] + not(thumb_1)))] #[arm_aeabi_alias = __aeabi_uidiv] /// Returns `n / d` pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { -- cgit 1.4.1-3-g733a5 From 9886a163b3d49e5523eed904d6803465ad3fecc1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 14 May 2019 14:29:29 -0700 Subject: Don't compile C code on riscv targets This fixes a longstanding bug in compiler-builtins where C code was compiled for the riscv targets but when distributed in rust-lang/rust all the C code was actually compiled for x86_64 since there is no configured C compiler for riscv. This was exposed by #286 by accident but the underlying cause was somewhat unrelated. For now we forcibly disable C code for riscv targets, and when the C compiler story is sorted out in rust-lang/rust and with `cc-rs` we can reenable. For now just use all the Rust definitions. cc rust-lang/rust#60747 --- library/compiler-builtins/build.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 27dac602647..4fc0adbeda6 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -37,8 +37,15 @@ fn main() { // build anything and we rely on the upstream implementation of compiler-rt // functions if !cfg!(feature = "mangled-names") && cfg!(feature = "c") { - // Don't use C compiler for bitcode-only wasm and nvptx - if !target.contains("wasm32") && !target.contains("nvptx") { + // Don't use a C compiler for these targets: + // + // * wasm32 - clang 8 for wasm is somewhat hard to come by and it's + // unlikely that the C is really that much better than our own Rust. + // * nvptx - everything is bitcode, not compatible with mixed C/Rust + // * riscv - the rust-lang/rust distribution container doesn't have a C + // compiler nor is cc-rs ready for compilation to riscv (at this + // time). This can probably be removed in the future + if !target.contains("wasm32") && !target.contains("nvptx") && !target.starts_with("riscv") { #[cfg(feature = "c")] c::compile(&llvm_target); println!("cargo:rustc-cfg=use_c"); -- cgit 1.4.1-3-g733a5 From b2cfc3a4f111d3b944e9c1884d7324bef3607e6b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 14 May 2019 14:33:08 -0700 Subject: Run rustfmt over everything --- library/compiler-builtins/build.rs | 413 +++++------ library/compiler-builtins/examples/intrinsics.rs | 10 +- library/compiler-builtins/src/arm_linux.rs | 98 ++- library/compiler-builtins/src/float/add.rs | 50 +- library/compiler-builtins/src/float/cmp.rs | 67 +- library/compiler-builtins/src/float/conv.rs | 74 +- library/compiler-builtins/src/float/div.rs | 6 +- library/compiler-builtins/src/float/extend.rs | 7 +- library/compiler-builtins/src/float/mod.rs | 46 +- library/compiler-builtins/src/float/mul.rs | 2 +- library/compiler-builtins/src/float/pow.rs | 2 +- library/compiler-builtins/src/float/sub.rs | 4 +- library/compiler-builtins/src/int/addsub.rs | 23 +- library/compiler-builtins/src/int/mod.rs | 50 +- library/compiler-builtins/src/int/mul.rs | 9 +- library/compiler-builtins/src/int/sdiv.rs | 3 +- library/compiler-builtins/src/int/shift.rs | 35 +- library/compiler-builtins/src/lib.rs | 34 +- library/compiler-builtins/src/macros.rs | 2 +- library/compiler-builtins/src/mem.rs | 10 +- library/compiler-builtins/src/probestack.rs | 4 +- library/compiler-builtins/testcrate/build.rs | 814 +++++++++++++-------- library/compiler-builtins/testcrate/src/lib.rs | 2 +- .../testcrate/tests/aeabi_memclr.rs | 10 +- .../testcrate/tests/aeabi_memcpy.rs | 10 +- .../testcrate/tests/aeabi_memset.rs | 82 +-- .../testcrate/tests/count_leading_zeros.rs | 30 +- .../compiler-builtins/testcrate/tests/generated.rs | 30 +- 28 files changed, 1105 insertions(+), 822 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 4fc0adbeda6..a8301afa95f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -22,8 +22,9 @@ fn main() { // Forcibly enable memory intrinsics on wasm32 & SGX as we don't have a libc to // provide them. - if (target.contains("wasm32") && !target.contains("wasi")) || - (target.contains("sgx") && target.contains("fortanix")) { + if (target.contains("wasm32") && !target.contains("wasi")) + || (target.contains("sgx") && target.contains("fortanix")) + { println!("cargo:rustc-cfg=feature=\"mem\""); } @@ -85,7 +86,9 @@ mod c { impl Sources { fn new() -> Sources { - Sources { map: BTreeMap::new() } + Sources { + map: BTreeMap::new(), + } } fn extend(&mut self, sources: &[&'static str]) { @@ -151,163 +154,144 @@ mod c { } let mut sources = Sources::new(); - sources.extend( - &[ - "absvdi2.c", - "absvsi2.c", - "addvdi3.c", - "addvsi3.c", - "apple_versioning.c", - "clzdi2.c", - "clzsi2.c", - "cmpdi2.c", - "ctzdi2.c", - "ctzsi2.c", - "divdc3.c", - "divsc3.c", - "divxc3.c", - "extendhfsf2.c", - "int_util.c", - "muldc3.c", - "mulsc3.c", - "mulvdi3.c", - "mulvsi3.c", - "mulxc3.c", - "negdf2.c", - "negdi2.c", - "negsf2.c", - "negvdi2.c", - "negvsi2.c", - "paritydi2.c", - "paritysi2.c", - "popcountdi2.c", - "popcountsi2.c", - "powixf2.c", - "subvdi3.c", - "subvsi3.c", - "truncdfhf2.c", - "truncdfsf2.c", - "truncsfhf2.c", - "ucmpdi2.c", - ], - ); + sources.extend(&[ + "absvdi2.c", + "absvsi2.c", + "addvdi3.c", + "addvsi3.c", + "apple_versioning.c", + "clzdi2.c", + "clzsi2.c", + "cmpdi2.c", + "ctzdi2.c", + "ctzsi2.c", + "divdc3.c", + "divsc3.c", + "divxc3.c", + "extendhfsf2.c", + "int_util.c", + "muldc3.c", + "mulsc3.c", + "mulvdi3.c", + "mulvsi3.c", + "mulxc3.c", + "negdf2.c", + "negdi2.c", + "negsf2.c", + "negvdi2.c", + "negvsi2.c", + "paritydi2.c", + "paritysi2.c", + "popcountdi2.c", + "popcountsi2.c", + "powixf2.c", + "subvdi3.c", + "subvsi3.c", + "truncdfhf2.c", + "truncdfsf2.c", + "truncsfhf2.c", + "ucmpdi2.c", + ]); // When compiling in rustbuild (the rust-lang/rust repo) this library // also needs to satisfy intrinsics that jemalloc or C in general may // need, so include a few more that aren't typically needed by // LLVM/Rust. if cfg!(feature = "rustbuild") { - sources.extend(&[ - "ffsdi2.c", - ]); + sources.extend(&["ffsdi2.c"]); } // On iOS and 32-bit OSX these are all just empty intrinsics, no need to // include them. if target_os != "ios" && (target_vendor != "apple" || target_arch != "x86") { - sources.extend( - &[ - "absvti2.c", - "addvti3.c", - "clzti2.c", - "cmpti2.c", - "ctzti2.c", - "ffsti2.c", - "mulvti3.c", - "negti2.c", - "negvti2.c", - "parityti2.c", - "popcountti2.c", - "subvti3.c", - "ucmpti2.c", - ], - ); + sources.extend(&[ + "absvti2.c", + "addvti3.c", + "clzti2.c", + "cmpti2.c", + "ctzti2.c", + "ffsti2.c", + "mulvti3.c", + "negti2.c", + "negvti2.c", + "parityti2.c", + "popcountti2.c", + "subvti3.c", + "ucmpti2.c", + ]); } if target_vendor == "apple" { - sources.extend( - &[ - "atomic_flag_clear.c", - "atomic_flag_clear_explicit.c", - "atomic_flag_test_and_set.c", - "atomic_flag_test_and_set_explicit.c", - "atomic_signal_fence.c", - "atomic_thread_fence.c", - ], - ); + sources.extend(&[ + "atomic_flag_clear.c", + "atomic_flag_clear_explicit.c", + "atomic_flag_test_and_set.c", + "atomic_flag_test_and_set_explicit.c", + "atomic_signal_fence.c", + "atomic_thread_fence.c", + ]); } if target_env == "msvc" { if target_arch == "x86_64" { - sources.extend( - &[ - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - ], - ); + sources.extend(&["x86_64/floatdisf.c", "x86_64/floatdixf.c"]); } } else { // None of these seem to be used on x86_64 windows, and they've all // got the wrong ABI anyway, so we want to avoid them. if target_os != "windows" { if target_arch == "x86_64" { - sources.extend( - &[ - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S", - ], - ); + sources.extend(&[ + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S", + ]); } } if target_arch == "x86" { - sources.extend( - &[ - "i386/ashldi3.S", - "i386/ashrdi3.S", - "i386/divdi3.S", - "i386/floatdidf.S", - "i386/floatdisf.S", - "i386/floatdixf.S", - "i386/floatundidf.S", - "i386/floatundisf.S", - "i386/floatundixf.S", - "i386/lshrdi3.S", - "i386/moddi3.S", - "i386/muldi3.S", - "i386/udivdi3.S", - "i386/umoddi3.S", - ], - ); + sources.extend(&[ + "i386/ashldi3.S", + "i386/ashrdi3.S", + "i386/divdi3.S", + "i386/floatdidf.S", + "i386/floatdisf.S", + "i386/floatdixf.S", + "i386/floatundidf.S", + "i386/floatundisf.S", + "i386/floatundixf.S", + "i386/lshrdi3.S", + "i386/moddi3.S", + "i386/muldi3.S", + "i386/udivdi3.S", + "i386/umoddi3.S", + ]); } } if target_arch == "arm" && target_os != "ios" && target_env != "msvc" { - sources.extend( - &[ - "arm/aeabi_div0.c", - "arm/aeabi_drsub.c", - "arm/aeabi_frsub.c", - "arm/bswapdi2.S", - "arm/bswapsi2.S", - "arm/clzdi2.S", - "arm/clzsi2.S", - "arm/divmodsi4.S", - "arm/divsi3.S", - "arm/modsi3.S", - "arm/switch16.S", - "arm/switch32.S", - "arm/switch8.S", - "arm/switchu8.S", - "arm/sync_synchronize.S", - "arm/udivmodsi4.S", - "arm/udivsi3.S", - "arm/umodsi3.S", - ], - ); + sources.extend(&[ + "arm/aeabi_div0.c", + "arm/aeabi_drsub.c", + "arm/aeabi_frsub.c", + "arm/bswapdi2.S", + "arm/bswapsi2.S", + "arm/clzdi2.S", + "arm/clzsi2.S", + "arm/divmodsi4.S", + "arm/divsi3.S", + "arm/modsi3.S", + "arm/switch16.S", + "arm/switch32.S", + "arm/switch8.S", + "arm/switchu8.S", + "arm/sync_synchronize.S", + "arm/udivmodsi4.S", + "arm/udivsi3.S", + "arm/umodsi3.S", + ]); if target_os == "freebsd" { sources.extend(&["clear_cache.c"]); @@ -316,100 +300,89 @@ mod c { // First of all aeabi_cdcmp and aeabi_cfcmp are never called by LLVM. // Second are little-endian only, so build fail on big-endian targets. // Temporally workaround: exclude these files for big-endian targets. - if !llvm_target[0].starts_with("thumbeb") && - !llvm_target[0].starts_with("armeb") { - sources.extend( - &[ - "arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", - ], - ); + if !llvm_target[0].starts_with("thumbeb") && !llvm_target[0].starts_with("armeb") { + sources.extend(&[ + "arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + ]); } } if llvm_target[0] == "armv7" { - sources.extend( - &[ - "arm/sync_fetch_and_add_4.S", - "arm/sync_fetch_and_add_8.S", - "arm/sync_fetch_and_and_4.S", - "arm/sync_fetch_and_and_8.S", - "arm/sync_fetch_and_max_4.S", - "arm/sync_fetch_and_max_8.S", - "arm/sync_fetch_and_min_4.S", - "arm/sync_fetch_and_min_8.S", - "arm/sync_fetch_and_nand_4.S", - "arm/sync_fetch_and_nand_8.S", - "arm/sync_fetch_and_or_4.S", - "arm/sync_fetch_and_or_8.S", - "arm/sync_fetch_and_sub_4.S", - "arm/sync_fetch_and_sub_8.S", - "arm/sync_fetch_and_umax_4.S", - "arm/sync_fetch_and_umax_8.S", - "arm/sync_fetch_and_umin_4.S", - "arm/sync_fetch_and_umin_8.S", - "arm/sync_fetch_and_xor_4.S", - "arm/sync_fetch_and_xor_8.S", - ], - ); + sources.extend(&[ + "arm/sync_fetch_and_add_4.S", + "arm/sync_fetch_and_add_8.S", + "arm/sync_fetch_and_and_4.S", + "arm/sync_fetch_and_and_8.S", + "arm/sync_fetch_and_max_4.S", + "arm/sync_fetch_and_max_8.S", + "arm/sync_fetch_and_min_4.S", + "arm/sync_fetch_and_min_8.S", + "arm/sync_fetch_and_nand_4.S", + "arm/sync_fetch_and_nand_8.S", + "arm/sync_fetch_and_or_4.S", + "arm/sync_fetch_and_or_8.S", + "arm/sync_fetch_and_sub_4.S", + "arm/sync_fetch_and_sub_8.S", + "arm/sync_fetch_and_umax_4.S", + "arm/sync_fetch_and_umax_8.S", + "arm/sync_fetch_and_umin_4.S", + "arm/sync_fetch_and_umin_8.S", + "arm/sync_fetch_and_xor_4.S", + "arm/sync_fetch_and_xor_8.S", + ]); } if llvm_target.last().unwrap().ends_with("eabihf") { - if !llvm_target[0].starts_with("thumbv7em") && - !llvm_target[0].starts_with("thumbv8m.main") { + if !llvm_target[0].starts_with("thumbv7em") + && !llvm_target[0].starts_with("thumbv8m.main") + { // The FPU option chosen for these architectures in cc-rs, ie: // -mfpu=fpv4-sp-d16 for thumbv7em // -mfpu=fpv5-sp-d16 for thumbv8m.main // do not support double precision floating points conversions so the files // that include such instructions are not included for these targets. - sources.extend( - &[ - "arm/fixdfsivfp.S", - "arm/fixunsdfsivfp.S", - "arm/floatsidfvfp.S", - "arm/floatunssidfvfp.S", - ], - ); + sources.extend(&[ + "arm/fixdfsivfp.S", + "arm/fixunsdfsivfp.S", + "arm/floatsidfvfp.S", + "arm/floatunssidfvfp.S", + ]); } - sources.extend( - &[ - "arm/fixsfsivfp.S", - "arm/fixunssfsivfp.S", - "arm/floatsisfvfp.S", - "arm/floatunssisfvfp.S", - "arm/floatunssisfvfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", - "arm/negdf2vfp.S", - "arm/negsf2vfp.S", - ] - ); - + sources.extend(&[ + "arm/fixsfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssisfvfp.S", + "arm/floatunssisfvfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/negdf2vfp.S", + "arm/negsf2vfp.S", + ]); } if target_arch == "aarch64" { - sources.extend( - &[ - "comparetf2.c", - "extenddftf2.c", - "extendsftf2.c", - "fixtfdi.c", - "fixtfsi.c", - "fixtfti.c", - "fixunstfdi.c", - "fixunstfsi.c", - "fixunstfti.c", - "floatditf.c", - "floatsitf.c", - "floatunditf.c", - "floatunsitf.c", - "trunctfdf2.c", - "trunctfsf2.c", - ], - ); + sources.extend(&[ + "comparetf2.c", + "extenddftf2.c", + "extendsftf2.c", + "fixtfdi.c", + "fixtfsi.c", + "fixtfti.c", + "fixunstfdi.c", + "fixunstfsi.c", + "fixunstfti.c", + "floatditf.c", + "floatsitf.c", + "floatunditf.c", + "floatunsitf.c", + "trunctfdf2.c", + "trunctfsf2.c", + ]); if target_os != "windows" { sources.extend(&["multc3.c"]); @@ -418,22 +391,20 @@ mod c { // Remove the assembly implementations that won't compile for the target if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { - sources.remove( - &[ - "clzdi2", - "clzsi2", - "divmodsi4", - "divsi3", - "modsi3", - "switch16", - "switch32", - "switch8", - "switchu8", - "udivmodsi4", - "udivsi3", - "umodsi3", - ], - ); + sources.remove(&[ + "clzdi2", + "clzsi2", + "divmodsi4", + "divsi3", + "modsi3", + "switch16", + "switch32", + "switch8", + "switchu8", + "udivmodsi4", + "udivsi3", + "umodsi3", + ]); // But use some generic implementations where possible sources.extend(&["clzdi2.c", "clzsi2.c"]) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 8de108d99b4..3debffa450a 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -17,7 +17,7 @@ extern crate panic_handler; #[cfg(all(not(thumb), not(windows)))] #[link(name = "c")] -extern {} +extern "C" {} // Every function in this module maps will be lowered to an intrinsic by LLVM, if the platform // doesn't have native support for the operation used in the function. ARM has a naming convention @@ -340,11 +340,13 @@ fn run() { something_with_a_dtor(&|| assert_eq!(bb(1), 1)); - extern { + extern "C" { fn rust_begin_unwind(); } // if bb(false) { - unsafe { rust_begin_unwind(); } + unsafe { + rust_begin_unwind(); + } // } } @@ -377,7 +379,7 @@ pub fn _start() -> ! { #[cfg(windows)] #[link(name = "kernel32")] #[link(name = "msvcrt")] -extern {} +extern "C" {} // ARM targets need these symbols #[no_mangle] diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs index 5ed379fa1e2..e710c1ab98a 100644 --- a/library/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/src/arm_linux.rs @@ -4,11 +4,11 @@ use core::mem; // Kernel-provided user-mode helper functions: // https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt unsafe fn __kuser_cmpxchg(oldval: u32, newval: u32, ptr: *mut u32) -> bool { - let f: extern "C" fn (u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0u32); + let f: extern "C" fn(u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0u32); f(oldval, newval, ptr) == 0 } unsafe fn __kuser_memory_barrier() { - let f: extern "C" fn () = mem::transmute(0xffff0fa0u32); + let f: extern "C" fn() = mem::transmute(0xffff0fa0u32); f(); } @@ -94,7 +94,7 @@ macro_rules! atomic_rmw { pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty { atomic_rmw(ptr, |x| $op(x as $ty, val) as u32) as $ty } - } + }; } macro_rules! atomic_cmpxchg { ($name:ident, $ty:ty) => { @@ -102,16 +102,20 @@ macro_rules! atomic_cmpxchg { pub unsafe extern "C" fn $name(ptr: *mut $ty, oldval: $ty, newval: $ty) -> $ty { atomic_cmpxchg(ptr, oldval as u32, newval as u32) as $ty } - } + }; } atomic_rmw!(__sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b)); -atomic_rmw!(__sync_fetch_and_add_2, u16, |a: u16, b: u16| a.wrapping_add(b)); -atomic_rmw!(__sync_fetch_and_add_4, u32, |a: u32, b: u32| a.wrapping_add(b)); +atomic_rmw!(__sync_fetch_and_add_2, u16, |a: u16, b: u16| a + .wrapping_add(b)); +atomic_rmw!(__sync_fetch_and_add_4, u32, |a: u32, b: u32| a + .wrapping_add(b)); atomic_rmw!(__sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); -atomic_rmw!(__sync_fetch_and_sub_2, u16, |a: u16, b: u16| a.wrapping_sub(b)); -atomic_rmw!(__sync_fetch_and_sub_4, u32, |a: u32, b: u32| a.wrapping_sub(b)); +atomic_rmw!(__sync_fetch_and_sub_2, u16, |a: u16, b: u16| a + .wrapping_sub(b)); +atomic_rmw!(__sync_fetch_and_sub_4, u32, |a: u32, b: u32| a + .wrapping_sub(b)); atomic_rmw!(__sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b); atomic_rmw!(__sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b); @@ -129,21 +133,69 @@ atomic_rmw!(__sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b)); atomic_rmw!(__sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b)); atomic_rmw!(__sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b)); -atomic_rmw!(__sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { a } else { b }); - -atomic_rmw!(__sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { a } else { b }); - -atomic_rmw!(__sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { a } else { b }); - -atomic_rmw!(__sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { a } else { b }); +atomic_rmw!(__sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { + a +} else { + b +}); + +atomic_rmw!(__sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { + a +} else { + b +}); + +atomic_rmw!(__sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { + a +} else { + b +}); + +atomic_rmw!(__sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { + a +} else { + b +}); atomic_rmw!(__sync_lock_test_and_set_1, u8, |_: u8, b: u8| b); atomic_rmw!(__sync_lock_test_and_set_2, u16, |_: u16, b: u16| b); diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 2b6ada81ddc..e8b9f9e7742 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,8 +1,9 @@ -use int::{Int, CastInto}; use float::Float; +use int::{CastInto, Int}; /// Returns `a + b` -fn add(a: F, b: F) -> F where +fn add(a: F, b: F) -> F +where u32: CastInto, F::Int: CastInto, i32: CastInto, @@ -11,18 +12,18 @@ fn add(a: F, b: F) -> F where let one = F::Int::ONE; let zero = F::Int::ZERO; - let bits = F::BITS.cast(); + let bits = F::BITS.cast(); let significand_bits = F::SIGNIFICAND_BITS; - let max_exponent = F::EXPONENT_MAX; + let max_exponent = F::EXPONENT_MAX; - let implicit_bit = F::IMPLICIT_BIT; + let implicit_bit = F::IMPLICIT_BIT; let significand_mask = F::SIGNIFICAND_MASK; - let sign_bit = F::SIGN_MASK as F::Int; - let abs_mask = sign_bit - one; - let exponent_mask = F::EXPONENT_MASK; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXPONENT_MASK; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; let mut a_rep = a.repr(); let mut b_rep = b.repr(); @@ -30,8 +31,7 @@ fn add(a: F, b: F) -> F where let b_abs = b_rep & abs_mask; // Detect if a or b is zero, infinity, or NaN. - if a_abs.wrapping_sub(one) >= inf_rep - one || - b_abs.wrapping_sub(one) >= inf_rep - one { + if a_abs.wrapping_sub(one) >= inf_rep - one || b_abs.wrapping_sub(one) >= inf_rep - one { // NaN + anything = qNaN if a_abs > inf_rep { return F::from_repr(a_abs | quiet_bit); @@ -68,7 +68,7 @@ fn add(a: F, b: F) -> F where // anything + zero = anything if b_abs == Int::ZERO { - return a; + return a; } } @@ -115,7 +115,8 @@ fn add(a: F, b: F) -> F where let align = a_exponent.wrapping_sub(b_exponent).cast(); if align != Int::ZERO { if align < bits { - let sticky = F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != Int::ZERO); + let sticky = + F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != Int::ZERO); b_significand = (b_significand >> align.cast()) | sticky; } else { b_significand = one; // sticky; b is known to be non-zero. @@ -131,12 +132,14 @@ fn add(a: F, b: F) -> F where // If partial cancellation occured, we need to left-shift the result // and adjust the exponent: if a_significand < implicit_bit << 3 { - let shift = a_significand.leading_zeros() as i32 - - (implicit_bit << 3).leading_zeros() as i32; + let shift = + a_significand.leading_zeros() as i32 - (implicit_bit << 3).leading_zeros() as i32; a_significand <<= shift; a_exponent -= shift; } - } else /* addition */ { + } else + /* addition */ + { a_significand += b_significand; // If the addition carried up, we need to right-shift the result and @@ -157,7 +160,8 @@ fn add(a: F, b: F) -> F where // Result is denormal before rounding; the exponent is zero and we // need to shift the significand. let shift = (1 - a_exponent).cast(); - let sticky = F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != Int::ZERO); + let sticky = + F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != Int::ZERO); a_significand = a_significand >> shift.cast() | sticky; a_exponent = 0; } @@ -175,8 +179,12 @@ fn add(a: F, b: F) -> F where // Final rounding. The result may overflow to infinity, but that is the // correct result in that case. - if round_guard_sticky > 0x4 { result += one; } - if round_guard_sticky == 0x4 { result += result & one; } + if round_guard_sticky > 0x4 { + result += one; + } + if round_guard_sticky == 0x4 { + result += result & one; + } F::from_repr(result) } diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 01dd890550b..20ab92e4b9a 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -1,64 +1,65 @@ #![allow(unreachable_code)] -use int::{Int, CastInto}; use float::Float; +use int::{CastInto, Int}; #[derive(Clone, Copy)] enum Result { Less, Equal, Greater, - Unordered + Unordered, } impl Result { fn to_le_abi(self) -> i32 { match self { - Result::Less => -1, - Result::Equal => 0, - Result::Greater => 1, - Result::Unordered => 1 + Result::Less => -1, + Result::Equal => 0, + Result::Greater => 1, + Result::Unordered => 1, } } fn to_ge_abi(self) -> i32 { match self { - Result::Less => -1, - Result::Equal => 0, - Result::Greater => 1, - Result::Unordered => -1 + Result::Less => -1, + Result::Equal => 0, + Result::Greater => 1, + Result::Unordered => -1, } } } -fn cmp(a: F, b: F) -> Result where +fn cmp(a: F, b: F) -> Result +where u32: CastInto, F::Int: CastInto, i32: CastInto, F::Int: CastInto, { - let one = F::Int::ONE; - let zero = F::Int::ZERO; + let one = F::Int::ONE; + let zero = F::Int::ZERO; let szero = F::SignedInt::ZERO; - let sign_bit = F::SIGN_MASK as F::Int; - let abs_mask = sign_bit - one; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; let exponent_mask = F::EXPONENT_MASK; - let inf_rep = exponent_mask; + let inf_rep = exponent_mask; - let a_rep = a.repr(); - let b_rep = b.repr(); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; + let a_rep = a.repr(); + let b_rep = b.repr(); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; // If either a or b is NaN, they are unordered. if a_abs > inf_rep || b_abs > inf_rep { - return Result::Unordered + return Result::Unordered; } // If a and b are both zeros, they are equal. if a_abs | b_abs == zero { - return Result::Equal + return Result::Equal; } let a_srep = a.signed_repr(); @@ -68,29 +69,29 @@ fn cmp(a: F, b: F) -> Result where // a and b as signed integers as we would with a fp_ting-point compare. if a_srep & b_srep >= szero { if a_srep < b_srep { - return Result::Less + return Result::Less; } else if a_srep == b_srep { - return Result::Equal + return Result::Equal; } else { - return Result::Greater + return Result::Greater; } } - // Otherwise, both are negative, so we need to flip the sense of the // comparison to get the correct result. (This assumes a twos- or ones- // complement integer representation; if integers are represented in a // sign-magnitude representation, then this flip is incorrect). else { if a_srep > b_srep { - return Result::Less + return Result::Less; } else if a_srep == b_srep { - return Result::Equal + return Result::Equal; } else { - return Result::Greater + return Result::Greater; } } } -fn unord(a: F, b: F) -> bool where +fn unord(a: F, b: F) -> bool +where u32: CastInto, F::Int: CastInto, i32: CastInto, @@ -98,10 +99,10 @@ fn unord(a: F, b: F) -> bool where { let one = F::Int::ONE; - let sign_bit = F::SIGN_MASK as F::Int; - let abs_mask = sign_bit - one; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; let exponent_mask = F::EXPONENT_MASK; - let inf_rep = exponent_mask; + let inf_rep = exponent_mask; let a_rep = a.repr(); let b_rep = b.repr(); diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 8d3e5fc6de2..21aac15c167 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -2,10 +2,10 @@ use float::Float; use int::Int; macro_rules! int_to_float { - ($i:expr, $ity:ty, $fty:ty) => ({ + ($i:expr, $ity:ty, $fty:ty) => {{ let i = $i; if i == 0 { - return 0.0 + return 0.0; } let mant_dig = <$fty>::SIGNIFICAND_BITS + 1; @@ -22,20 +22,22 @@ macro_rules! int_to_float { let mut e = sd - 1; if <$ity>::BITS < mant_dig { - return <$fty>::from_parts(s, + return <$fty>::from_parts( + s, (e + exponent_bias) as <$fty as Float>::Int, - (a as <$fty as Float>::Int) << (mant_dig - e - 1)) + (a as <$fty as Float>::Int) << (mant_dig - e - 1), + ); } a = if sd > mant_dig { /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx - * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR - * 12345678901234567890123456 - * 1 = msb 1 bit - * P = bit MANT_DIG-1 bits to the right of 1 - * Q = bit MANT_DIG bits to the right of 1 - * R = "or" of all bits to the right of Q - */ + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit MANT_DIG-1 bits to the right of 1 + * Q = bit MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ let mant_dig_plus_one = mant_dig + 1; let mant_dig_plus_two = mant_dig + 2; a = if sd == mant_dig_plus_one { @@ -43,8 +45,10 @@ macro_rules! int_to_float { } else if sd == mant_dig_plus_two { a } else { - (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt | - ((a & <$ity as Int>::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != 0) as <$ity as Int>::UnsignedInt + (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt + | ((a & <$ity as Int>::UnsignedInt::max_value()) + .wrapping_shl((n + mant_dig_plus_two) - sd) + != 0) as <$ity as Int>::UnsignedInt }; /* finish: */ @@ -54,19 +58,22 @@ macro_rules! int_to_float { /* a is now rounded to mant_dig or mant_dig+1 bits */ if (a & (1 << mant_dig)) != 0 { - a >>= 1; e += 1; + a >>= 1; + e += 1; } a - /* a is now rounded to mant_dig bits */ + /* a is now rounded to mant_dig bits */ } else { a.wrapping_shl(mant_dig - sd) /* a is now rounded to mant_dig bits */ }; - <$fty>::from_parts(s, + <$fty>::from_parts( + s, (e + exponent_bias) as <$fty as Float>::Int, - a as <$fty as Float>::Int) - }) + a as <$fty as Float>::Int, + ) + }}; } intrinsics! { @@ -160,11 +167,11 @@ intrinsics! { #[derive(PartialEq)] enum Sign { Positive, - Negative + Negative, } macro_rules! float_to_int { - ($f:expr, $fty:ty, $ity:ty) => ({ + ($f:expr, $fty:ty, $ity:ty) => {{ let f = $f; let fixint_min = <$ity>::min_value(); let fixint_max = <$ity>::max_value(); @@ -181,21 +188,34 @@ macro_rules! float_to_int { let a_abs = a_rep & !sign_bit; // this is used to work around -1 not being available for unsigned - let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative }; + let sign = if (a_rep & sign_bit) == 0 { + Sign::Positive + } else { + Sign::Negative + }; let mut exponent = (a_abs >> significand_bits) as usize; let significand = (a_abs & <$fty>::SIGNIFICAND_MASK) | <$fty>::IMPLICIT_BIT; // if < 1 or unsigned & negative - if exponent < exponent_bias || - fixint_unsigned && sign == Sign::Negative { - return 0 + if exponent < exponent_bias || fixint_unsigned && sign == Sign::Negative { + return 0; } exponent -= exponent_bias; // If the value is infinity, saturate. // If the value is too large for the integer type, 0. - if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { - return if sign == Sign::Positive {fixint_max} else {fixint_min} + if exponent + >= (if fixint_unsigned { + fixint_bits + } else { + fixint_bits - 1 + }) + { + return if sign == Sign::Positive { + fixint_max + } else { + fixint_min + }; } // If 0 <= exponent < significand_bits, right shift to get the result. // Otherwise, shift left. @@ -211,7 +231,7 @@ macro_rules! float_to_int { } else { r } - }) + }}; } intrinsics! { diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index ae12bb32140..7c582a4408d 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -1,7 +1,5 @@ -use int::{CastInto, Int, WideInt}; use float::Float; - - +use int::{CastInto, Int, WideInt}; fn div32(a: F, b: F) -> F where @@ -398,7 +396,6 @@ where // operation in C, so we need to be a little bit fussy. let (mut quotient, _) = ::wide_mul(a_significand << 2, reciprocal.cast()); - // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). // In either case, we are going to compute a residual of the form // @@ -442,7 +439,6 @@ where } } - intrinsics! { #[arm_aeabi_alias = __aeabi_fdiv] pub extern "C" fn __divsf3(a: f32, b: f32) -> f32 { diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 0ca9cf57a58..39633773b25 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -1,8 +1,9 @@ -use int::{CastInto, Int}; use float::Float; +use int::{CastInto, Int}; /// Generic conversion from a narrower to a wider IEEE-754 floating-point type -fn extend(a: F) -> R where +fn extend(a: F) -> R +where F::Int: CastInto, u64: CastInto, u32: CastInto, @@ -79,4 +80,4 @@ intrinsics! { pub extern "C" fn __extendsfdf2vfp(a: f32) -> f64 { a as f64 // LLVM generate 'fcvtds' } -} \ No newline at end of file +} diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 3bb13abbc5c..8b8039452a7 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -3,26 +3,26 @@ use core::ops; use super::int::Int; -pub mod conv; -pub mod cmp; pub mod add; -pub mod pow; -pub mod sub; -pub mod mul; +pub mod cmp; +pub mod conv; pub mod div; pub mod extend; +pub mod mul; +pub mod pow; +pub mod sub; /// Trait for some basic operations on floats pub trait Float: - Copy + - PartialEq + - PartialOrd + - ops::AddAssign + - ops::MulAssign + - ops::Add + - ops::Sub + - ops::Div + - ops::Rem + + Copy + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::MulAssign + + ops::Add + + ops::Sub + + ops::Div + + ops::Rem { /// A uint of the same with as the float type Int: Int; @@ -118,17 +118,23 @@ macro_rules! float_impl { unsafe { mem::transmute(a) } } fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) | - ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) | - (significand & Self::SIGNIFICAND_MASK)) + Self::from_repr( + ((sign as Self::Int) << (Self::BITS - 1)) + | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) + | (significand & Self::SIGNIFICAND_MASK), + ) } fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand.leading_zeros() + let shift = significand + .leading_zeros() .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros()); - (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) + ( + 1i32.wrapping_sub(shift as i32), + significand << shift as Self::Int, + ) } } - } + }; } float_impl!(f32, u32, i32, 32, 23); diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index d014bbc90c0..7b28793c8e7 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -1,5 +1,5 @@ -use int::{CastInto, Int, WideInt}; use float::Float; +use int::{CastInto, Int, WideInt}; fn mul(a: F, b: F) -> F where diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index f879c1a1f81..2eedf67584e 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,5 +1,5 @@ -use int::Int; use float::Float; +use int::Int; trait Pow: Float { /// Returns `a` raised to the power `b` diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 2afb1409b32..8d300e9d248 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -1,6 +1,6 @@ -use float::Float; -use float::add::__addsf3; use float::add::__adddf3; +use float::add::__addsf3; +use float::Float; intrinsics! { #[arm_aeabi_alias = __aeabi_fsub] diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs index 50b5d10d259..e2d5bcbd435 100644 --- a/library/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/src/int/addsub.rs @@ -1,16 +1,24 @@ -use int::LargeInt; use int::Int; +use int::LargeInt; trait UAddSub: LargeInt { fn uadd(self, other: Self) -> Self { let (low, carry) = self.low().overflowing_add(other.low()); let high = self.high().wrapping_add(other.high()); - let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; + let carry = if carry { + Self::HighHalf::ONE + } else { + Self::HighHalf::ZERO + }; Self::from_parts(low, high.wrapping_add(carry)) } fn uadd_one(self) -> Self { let (low, carry) = self.low().overflowing_add(Self::LowHalf::ONE); - let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; + let carry = if carry { + Self::HighHalf::ONE + } else { + Self::HighHalf::ZERO + }; Self::from_parts(low, self.high().wrapping_add(carry)) } fn usub(self, other: Self) -> Self { @@ -22,7 +30,8 @@ trait UAddSub: LargeInt { impl UAddSub for u128 {} trait AddSub: Int - where ::UnsignedInt: UAddSub +where + ::UnsignedInt: UAddSub, { fn add(self, other: Self) -> Self { Self::from_unsigned(self.unsigned().uadd(other.unsigned())) @@ -36,7 +45,8 @@ impl AddSub for u128 {} impl AddSub for i128 {} trait Addo: AddSub - where ::UnsignedInt: UAddSub +where + ::UnsignedInt: UAddSub, { fn addo(self, other: Self, overflow: &mut i32) -> Self { *overflow = 0; @@ -58,7 +68,8 @@ impl Addo for i128 {} impl Addo for u128 {} trait Subo: AddSub - where ::UnsignedInt: UAddSub +where + ::UnsignedInt: UAddSub, { fn subo(self, other: Self, overflow: &mut i32) -> Self { *overflow = 0; diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 07f72f84e71..fd1f0c3c881 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -3,13 +3,13 @@ use core::ops; macro_rules! hty { ($ty:ty) => { <$ty as LargeInt>::HighHalf - } + }; } macro_rules! os_ty { ($ty:ty) => { <$ty as Int>::OtherSign - } + }; } pub mod addsub; @@ -20,23 +20,23 @@ pub mod udiv; /// Trait for some basic operations on integers pub trait Int: - Copy + - PartialEq + - PartialOrd + - ops::AddAssign + - ops::BitAndAssign + - ops::BitOrAssign + - ops::ShlAssign + - ops::ShrAssign + - ops::Add + - ops::Sub + - ops::Div + - ops::Shl + - ops::Shr + - ops::BitOr + - ops::BitXor + - ops::BitAnd + - ops::Not + + Copy + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Div + + ops::Shl + + ops::Shr + + ops::BitOr + + ops::BitXor + + ops::BitAnd + + ops::Not { /// Type with the same width but other signedness type OtherSign: Int; @@ -182,7 +182,7 @@ macro_rules! int_impl { int_impl_common!($ity, $bits); } - } + }; } int_impl!(i32, u32, 32); @@ -223,7 +223,7 @@ macro_rules! large_int { low as $ty | ((high as $ty) << $halfbits) } } - } + }; } large_int!(u64, u32, u32, 32); @@ -284,9 +284,9 @@ macro_rules! impl_wide_int { let sticky = *low << ($bits - count); *low = *self << ($bits - count) | *low >> count | sticky; *self = *self >> count; - } else if count < 2*$bits { - let sticky = *self << (2*$bits - count) | *low; - *low = *self >> (count - $bits ) | sticky; + } else if count < 2 * $bits { + let sticky = *self << (2 * $bits - count) | *low; + *low = *self >> (count - $bits) | sticky; *self = 0; } else { let sticky = *self | *low; @@ -295,7 +295,7 @@ macro_rules! impl_wide_int { } } } - } + }; } impl_wide_int!(u32, u64, 32); diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 58ca461b085..376395ac04c 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,7 +1,7 @@ use core::ops; -use int::LargeInt; use int::Int; +use int::LargeInt; trait Mul: LargeInt { fn mul(self, other: Self) -> Self { @@ -19,8 +19,9 @@ trait Mul: LargeInt { low += (t & lower_mask) << half_bits; high += Self::low_as_high(t >> half_bits); high += Self::low_as_high((self.low() >> half_bits).wrapping_mul(other.low() >> half_bits)); - high = high.wrapping_add(self.high().wrapping_mul(Self::low_as_high(other.low()))) - .wrapping_add(Self::low_as_high(self.low()).wrapping_mul(other.high())); + high = high + .wrapping_add(self.high().wrapping_mul(Self::low_as_high(other.low()))) + .wrapping_add(Self::low_as_high(self.low()).wrapping_mul(other.high())); Self::from_parts(low, high) } } @@ -70,7 +71,7 @@ impl Mulo for i32 {} impl Mulo for i64 {} impl Mulo for i128 {} -trait UMulo : Int { +trait UMulo: Int { fn mulo(self, other: Self, overflow: &mut i32) -> Self { *overflow = 0; let result = self.wrapping_mul(other); diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 82262a4412d..4b63697b425 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -43,7 +43,8 @@ impl Mod for i128 {} trait Divmod: Int { /// Returns `a / b` and sets `*rem = n % d` fn divmod(self, other: Self, rem: &mut Self, div: F) -> Self - where F: Fn(Self, Self) -> Self, + where + F: Fn(Self, Self) -> Self, { let r = div(self, other); // NOTE won't overflow because it's using the result from the diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 959fcb0880f..4be588f161d 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -3,7 +3,8 @@ use int::{Int, LargeInt}; trait Ashl: Int + LargeInt { /// Returns `a << b`, requires `b < Self::BITS` fn ashl(self, offset: u32) -> Self - where Self: LargeInt::LowHalf>, + where + Self: LargeInt::LowHalf>, { let half_bits = Self::BITS / 2; if offset & half_bits != 0 { @@ -11,9 +12,10 @@ trait Ashl: Int + LargeInt { } else if offset == 0 { self } else { - Self::from_parts(self.low() << offset, - (self.high() << offset) | - (self.low() >> (half_bits - offset))) + Self::from_parts( + self.low() << offset, + (self.high() << offset) | (self.low() >> (half_bits - offset)), + ) } } } @@ -24,18 +26,23 @@ impl Ashl for u128 {} trait Ashr: Int + LargeInt { /// Returns arithmetic `a >> b`, requires `b < Self::BITS` fn ashr(self, offset: u32) -> Self - where Self: LargeInt::HighHalf as Int>::UnsignedInt>, + where + Self: LargeInt::HighHalf as Int>::UnsignedInt>, { let half_bits = Self::BITS / 2; if offset & half_bits != 0 { - Self::from_parts((self.high() >> (offset - half_bits)).unsigned(), - self.high() >> (half_bits - 1)) + Self::from_parts( + (self.high() >> (offset - half_bits)).unsigned(), + self.high() >> (half_bits - 1), + ) } else if offset == 0 { self } else { let high_unsigned = self.high().unsigned(); - Self::from_parts((high_unsigned << (half_bits - offset)) | (self.low() >> offset), - self.high() >> offset) + Self::from_parts( + (high_unsigned << (half_bits - offset)) | (self.low() >> offset), + self.high() >> offset, + ) } } } @@ -46,7 +53,8 @@ impl Ashr for i128 {} trait Lshr: Int + LargeInt { /// Returns logical `a >> b`, requires `b < Self::BITS` fn lshr(self, offset: u32) -> Self - where Self: LargeInt::LowHalf>, + where + Self: LargeInt::LowHalf>, { let half_bits = Self::BITS / 2; if offset & half_bits != 0 { @@ -54,9 +62,10 @@ trait Lshr: Int + LargeInt { } else if offset == 0 { self } else { - Self::from_parts((self.high() << (half_bits - offset)) | - (self.low() >> offset), - self.high() >> offset) + Self::from_parts( + (self.high() << (half_bits - offset)) | (self.low() >> offset), + self.high() >> offset, + ) } } } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index fddfa67aa8e..ef5353a7040 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -3,11 +3,13 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", - html_playground_url = "https://play.rust-lang.org/", - test(attr(deny(warnings))))] +#![doc( + html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/", + html_playground_url = "https://play.rust-lang.org/", + test(attr(deny(warnings))) +)] #![feature(asm)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] @@ -19,10 +21,14 @@ #![allow(unused_features)] #![no_builtins] #![cfg_attr(feature = "compiler-builtins", feature(staged_api))] -#![cfg_attr(feature = "compiler-builtins", - unstable(feature = "compiler_builtins_lib", - reason = "Compiler builtins. Will never become stable.", - issue = "0"))] +#![cfg_attr( + feature = "compiler-builtins", + unstable( + feature = "compiler_builtins_lib", + reason = "Compiler builtins. Will never become stable.", + issue = "0" + ) +)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. @@ -44,12 +50,14 @@ fn abort() -> ! { #[macro_use] mod macros; -pub mod int; pub mod float; +pub mod int; -#[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), - all(target_arch = "arm", target_os = "none"), - all(target_vendor = "fortanix", target_env = "sgx")))] +#[cfg(any( + all(target_arch = "wasm32", target_os = "unknown"), + all(target_arch = "arm", target_os = "none"), + all(target_vendor = "fortanix", target_env = "sgx") +))] pub mod math; pub mod mem; diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 5f1ab469a02..e84338fae39 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -261,7 +261,7 @@ macro_rules! intrinsics { // Hack for LLVM expectations for ABI on windows. This is used by the // `#[win64_128bit_abi_hack]` attribute recognized above -#[cfg(all(windows, target_pointer_width="64"))] +#[cfg(all(windows, target_pointer_width = "64"))] pub mod win64_128bit_abi_hack { #[repr(simd)] pub struct U64x2(u64, u64); diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index c56391c4d3d..c863bb72941 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -6,10 +6,7 @@ type c_int = i16; type c_int = i32; #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memcpy(dest: *mut u8, - src: *const u8, - n: usize) - -> *mut u8 { +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { let mut i = 0; while i < n { *dest.offset(i as isize) = *src.offset(i as isize); @@ -19,10 +16,7 @@ pub unsafe extern "C" fn memcpy(dest: *mut u8, } #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memmove(dest: *mut u8, - src: *const u8, - n: usize) - -> *mut u8 { +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { if src < dest as *const u8 { // copy from end let mut i = n; diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 52a0414a18f..f9284e81405 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -46,7 +46,7 @@ #[naked] #[no_mangle] #[cfg(all(target_arch = "x86_64", not(feature = "mangled-names")))] -pub unsafe extern fn __rust_probestack() { +pub unsafe extern "C" fn __rust_probestack() { // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, // ensuring that if any pages are unmapped we'll make a page fault. // @@ -97,7 +97,7 @@ pub unsafe extern fn __rust_probestack() { #[naked] #[no_mangle] #[cfg(all(target_arch = "x86", not(feature = "mangled-names")))] -pub unsafe extern fn __rust_probestack() { +pub unsafe extern "C" fn __rust_probestack() { // This is the same as x86_64 above, only translated for 32-bit sizes. Note // that on Unix we're expected to restore everything as it was, this // function basically can't tamper with anything. diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 17ae3ef1819..e43fdb77b88 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -2,15 +2,15 @@ extern crate cast; extern crate rand; use std::collections::HashMap; +use std::fmt; use std::fmt::Write as FmtWrite; use std::fs::{self, OpenOptions}; -use std::io::Write; use std::hash::{Hash, Hasher}; +use std::io::Write; use std::path::PathBuf; use std::{env, mem}; -use std::fmt; -use self::cast::{f32, f64, u32, u64, u128, i32, i64, i128}; +use self::cast::{f32, f64, i128, i32, i64, u128, u32, u64}; use self::rand::Rng; const NTESTS: usize = 1_000; @@ -21,16 +21,15 @@ fn main() { drop(fs::remove_file(&out_file)); let target = env::var("TARGET").unwrap(); - let target_arch_arm = - target.contains("arm") || - target.contains("thumb"); + let target_arch_arm = target.contains("arm") || target.contains("thumb"); let target_arch_mips = target.contains("mips"); // TODO accept NaNs. We don't do that right now because we can't check // for NaN-ness on the thumb targets (due to missing intrinsics) // float/add.rs - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let c = a.0 + b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -38,8 +37,10 @@ fn main() { Some(c) } }, - "builtins::float::add::__adddf3(a, b)"); - gen(|(a, b): (MyF32, MyF32)| { + "builtins::float::add::__adddf3(a, b)", + ); + gen( + |(a, b): (MyF32, MyF32)| { let c = a.0 + b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -47,10 +48,12 @@ fn main() { Some(c) } }, - "builtins::float::add::__addsf3(a, b)"); + "builtins::float::add::__addsf3(a, b)", + ); if target_arch_arm { - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let c = a.0 + b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -58,8 +61,10 @@ fn main() { Some(c) } }, - "builtins::float::add::__adddf3vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::add::__adddf3vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { let c = a.0 + b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -67,12 +72,13 @@ fn main() { Some(c) } }, - "builtins::float::add::__addsf3vfp(a, b)"); + "builtins::float::add::__addsf3vfp(a, b)", + ); } - // float/cmp.rs - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let (a, b) = (a.0, b.0); if a.is_nan() || b.is_nan() { return None; @@ -88,8 +94,10 @@ fn main() { Some(0) } }, - "builtins::float::cmp::__gedf2(a, b)"); - gen(|(a, b): (MyF32, MyF32)| { + "builtins::float::cmp::__gedf2(a, b)", + ); + gen( + |(a, b): (MyF32, MyF32)| { let (a, b) = (a.0, b.0); if a.is_nan() || b.is_nan() { return None; @@ -105,8 +113,10 @@ fn main() { Some(0) } }, - "builtins::float::cmp::__gesf2(a, b)"); - gen(|(a, b): (MyF64, MyF64)| { + "builtins::float::cmp::__gesf2(a, b)", + ); + gen( + |(a, b): (MyF64, MyF64)| { let (a, b) = (a.0, b.0); if a.is_nan() || b.is_nan() { return None; @@ -122,8 +132,10 @@ fn main() { Some(0) } }, - "builtins::float::cmp::__ledf2(a, b)"); - gen(|(a, b): (MyF32, MyF32)| { + "builtins::float::cmp::__ledf2(a, b)", + ); + gen( + |(a, b): (MyF32, MyF32)| { let (a, b) = (a.0, b.0); if a.is_nan() || b.is_nan() { return None; @@ -139,285 +151,387 @@ fn main() { Some(0) } }, - "builtins::float::cmp::__lesf2(a, b)"); + "builtins::float::cmp::__lesf2(a, b)", + ); - gen(|(a, b): (MyF32, MyF32)| { + gen( + |(a, b): (MyF32, MyF32)| { let c = a.0.is_nan() || b.0.is_nan(); Some(c as i32) }, - "builtins::float::cmp::__unordsf2(a, b)"); + "builtins::float::cmp::__unordsf2(a, b)", + ); - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let c = a.0.is_nan() || b.0.is_nan(); Some(c as i32) }, - "builtins::float::cmp::__unorddf2(a, b)"); + "builtins::float::cmp::__unorddf2(a, b)", + ); if target_arch_arm { - gen(|(a, b): (MyF32, MyF32)| { + gen( + |(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 <= b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_fcmple(a, b)"); + "builtins::float::cmp::__aeabi_fcmple(a, b)", + ); - gen(|(a, b): (MyF32, MyF32)| { + gen( + |(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 >= b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_fcmpge(a, b)"); + "builtins::float::cmp::__aeabi_fcmpge(a, b)", + ); - gen(|(a, b): (MyF32, MyF32)| { + gen( + |(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 == b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_fcmpeq(a, b)"); + "builtins::float::cmp::__aeabi_fcmpeq(a, b)", + ); - gen(|(a, b): (MyF32, MyF32)| { + gen( + |(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 < b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_fcmplt(a, b)"); + "builtins::float::cmp::__aeabi_fcmplt(a, b)", + ); - gen(|(a, b): (MyF32, MyF32)| { + gen( + |(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 > b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_fcmpgt(a, b)"); + "builtins::float::cmp::__aeabi_fcmpgt(a, b)", + ); - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 <= b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_dcmple(a, b)"); + "builtins::float::cmp::__aeabi_dcmple(a, b)", + ); - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 >= b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_dcmpge(a, b)"); + "builtins::float::cmp::__aeabi_dcmpge(a, b)", + ); - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 == b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_dcmpeq(a, b)"); + "builtins::float::cmp::__aeabi_dcmpeq(a, b)", + ); - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 < b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_dcmplt(a, b)"); + "builtins::float::cmp::__aeabi_dcmplt(a, b)", + ); - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 > b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_dcmpgt(a, b)"); + "builtins::float::cmp::__aeabi_dcmpgt(a, b)", + ); - gen(|(a, b): (LargeF32, LargeF32)| { + gen( + |(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 >= b.0) as i32) }, - "builtins::float::cmp::__gesf2vfp(a, b)"); - gen(|(a, b): (MyF64, MyF64)| { + "builtins::float::cmp::__gesf2vfp(a, b)", + ); + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 >= b.0) as i32) }, - "builtins::float::cmp::__gedf2vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::cmp::__gedf2vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 > b.0) as i32) }, - "builtins::float::cmp::__gtsf2vfp(a, b)"); - gen(|(a, b): (MyF64, MyF64)| { + "builtins::float::cmp::__gtsf2vfp(a, b)", + ); + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 > b.0) as i32) }, - "builtins::float::cmp::__gtdf2vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::cmp::__gtdf2vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 < b.0) as i32) }, - "builtins::float::cmp::__ltsf2vfp(a, b)"); - gen(|(a, b): (MyF64, MyF64)| { + "builtins::float::cmp::__ltsf2vfp(a, b)", + ); + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 < b.0) as i32) }, - "builtins::float::cmp::__ltdf2vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::cmp::__ltdf2vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 <= b.0) as i32) }, - "builtins::float::cmp::__lesf2vfp(a, b)"); - gen(|(a, b): (MyF64, MyF64)| { + "builtins::float::cmp::__lesf2vfp(a, b)", + ); + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 <= b.0) as i32) }, - "builtins::float::cmp::__ledf2vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::cmp::__ledf2vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 != b.0) as i32) }, - "builtins::float::cmp::__nesf2vfp(a, b)"); - gen(|(a, b): (MyF64, MyF64)| { + "builtins::float::cmp::__nesf2vfp(a, b)", + ); + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 != b.0) as i32) }, - "builtins::float::cmp::__nedf2vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::cmp::__nedf2vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 == b.0) as i32) }, - "builtins::float::cmp::__eqsf2vfp(a, b)"); - gen(|(a, b): (MyF64, MyF64)| { + "builtins::float::cmp::__eqsf2vfp(a, b)", + ); + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 == b.0) as i32) }, - "builtins::float::cmp::__eqdf2vfp(a, b)"); + "builtins::float::cmp::__eqdf2vfp(a, b)", + ); } // float/extend.rs - gen(|a: MyF32| { + gen( + |a: MyF32| { if a.0.is_nan() { return None; } Some(f64(a.0)) }, - "builtins::float::extend::__extendsfdf2(a)"); + "builtins::float::extend::__extendsfdf2(a)", + ); if target_arch_arm { - gen(|a: LargeF32| { - if a.0.is_nan() { - return None; - } - Some(f64(a.0)) - }, - "builtins::float::extend::__extendsfdf2vfp(a)"); + gen( + |a: LargeF32| { + if a.0.is_nan() { + return None; + } + Some(f64(a.0)) + }, + "builtins::float::extend::__extendsfdf2vfp(a)", + ); } // float/conv.rs - gen(|a: MyF64| i64(a.0).ok(), - "builtins::float::conv::__fixdfdi(a)"); - gen(|a: MyF64| i32(a.0).ok(), - "builtins::float::conv::__fixdfsi(a)"); - gen(|a: MyF32| i64(a.0).ok(), - "builtins::float::conv::__fixsfdi(a)"); - gen(|a: MyF32| i32(a.0).ok(), - "builtins::float::conv::__fixsfsi(a)"); - gen(|a: MyF32| i128(a.0).ok(), - "builtins::float::conv::__fixsfti(a)"); - gen(|a: MyF64| i128(a.0).ok(), - "builtins::float::conv::__fixdfti(a)"); - gen(|a: MyF64| u64(a.0).ok(), - "builtins::float::conv::__fixunsdfdi(a)"); - gen(|a: MyF64| u32(a.0).ok(), - "builtins::float::conv::__fixunsdfsi(a)"); - gen(|a: MyF32| u64(a.0).ok(), - "builtins::float::conv::__fixunssfdi(a)"); - gen(|a: MyF32| u32(a.0).ok(), - "builtins::float::conv::__fixunssfsi(a)"); - gen(|a: MyF32| u128(a.0).ok(), - "builtins::float::conv::__fixunssfti(a)"); - gen(|a: MyF64| u128(a.0).ok(), - "builtins::float::conv::__fixunsdfti(a)"); - gen(|a: MyI64| Some(f64(a.0)), - "builtins::float::conv::__floatdidf(a)"); - gen(|a: MyI32| Some(f64(a.0)), - "builtins::float::conv::__floatsidf(a)"); - gen(|a: MyI32| Some(f32(a.0)), - "builtins::float::conv::__floatsisf(a)"); - gen(|a: MyU64| Some(f64(a.0)), - "builtins::float::conv::__floatundidf(a)"); - gen(|a: MyU32| Some(f64(a.0)), - "builtins::float::conv::__floatunsidf(a)"); - gen(|a: MyU32| Some(f32(a.0)), - "builtins::float::conv::__floatunsisf(a)"); - gen(|a: MyU128| f32(a.0).ok(), - "builtins::float::conv::__floatuntisf(a)"); + gen( + |a: MyF64| i64(a.0).ok(), + "builtins::float::conv::__fixdfdi(a)", + ); + gen( + |a: MyF64| i32(a.0).ok(), + "builtins::float::conv::__fixdfsi(a)", + ); + gen( + |a: MyF32| i64(a.0).ok(), + "builtins::float::conv::__fixsfdi(a)", + ); + gen( + |a: MyF32| i32(a.0).ok(), + "builtins::float::conv::__fixsfsi(a)", + ); + gen( + |a: MyF32| i128(a.0).ok(), + "builtins::float::conv::__fixsfti(a)", + ); + gen( + |a: MyF64| i128(a.0).ok(), + "builtins::float::conv::__fixdfti(a)", + ); + gen( + |a: MyF64| u64(a.0).ok(), + "builtins::float::conv::__fixunsdfdi(a)", + ); + gen( + |a: MyF64| u32(a.0).ok(), + "builtins::float::conv::__fixunsdfsi(a)", + ); + gen( + |a: MyF32| u64(a.0).ok(), + "builtins::float::conv::__fixunssfdi(a)", + ); + gen( + |a: MyF32| u32(a.0).ok(), + "builtins::float::conv::__fixunssfsi(a)", + ); + gen( + |a: MyF32| u128(a.0).ok(), + "builtins::float::conv::__fixunssfti(a)", + ); + gen( + |a: MyF64| u128(a.0).ok(), + "builtins::float::conv::__fixunsdfti(a)", + ); + gen( + |a: MyI64| Some(f64(a.0)), + "builtins::float::conv::__floatdidf(a)", + ); + gen( + |a: MyI32| Some(f64(a.0)), + "builtins::float::conv::__floatsidf(a)", + ); + gen( + |a: MyI32| Some(f32(a.0)), + "builtins::float::conv::__floatsisf(a)", + ); + gen( + |a: MyU64| Some(f64(a.0)), + "builtins::float::conv::__floatundidf(a)", + ); + gen( + |a: MyU32| Some(f64(a.0)), + "builtins::float::conv::__floatunsidf(a)", + ); + gen( + |a: MyU32| Some(f32(a.0)), + "builtins::float::conv::__floatunsisf(a)", + ); + gen( + |a: MyU128| f32(a.0).ok(), + "builtins::float::conv::__floatuntisf(a)", + ); if !target_arch_mips { - gen(|a: MyI128| Some(f32(a.0)), - "builtins::float::conv::__floattisf(a)"); - gen(|a: MyI128| Some(f64(a.0)), - "builtins::float::conv::__floattidf(a)"); - gen(|a: MyU128| Some(f64(a.0)), - "builtins::float::conv::__floatuntidf(a)"); + gen( + |a: MyI128| Some(f32(a.0)), + "builtins::float::conv::__floattisf(a)", + ); + gen( + |a: MyI128| Some(f64(a.0)), + "builtins::float::conv::__floattidf(a)", + ); + gen( + |a: MyU128| Some(f64(a.0)), + "builtins::float::conv::__floatuntidf(a)", + ); } // float/pow.rs - gen(|(a, b): (MyF64, MyI32)| { - let c = a.0.powi(b.0); - if a.0.is_nan() || c.is_nan() { - None - } else { + gen( + |(a, b): (MyF64, MyI32)| { + let c = a.0.powi(b.0); + if a.0.is_nan() || c.is_nan() { + None + } else { Some(c) } }, - "builtins::float::pow::__powidf2(a, b)"); - gen(|(a, b): (MyF32, MyI32)| { - let c = a.0.powi(b.0); - if a.0.is_nan() || c.is_nan() { - None - } else { + "builtins::float::pow::__powidf2(a, b)", + ); + gen( + |(a, b): (MyF32, MyI32)| { + let c = a.0.powi(b.0); + if a.0.is_nan() || c.is_nan() { + None + } else { Some(c) } }, - "builtins::float::pow::__powisf2(a, b)"); + "builtins::float::pow::__powisf2(a, b)", + ); // float/sub.rs - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let c = a.0 - b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -425,8 +539,10 @@ fn main() { Some(c) } }, - "builtins::float::sub::__subdf3(a, b)"); - gen(|(a, b): (MyF32, MyF32)| { + "builtins::float::sub::__subdf3(a, b)", + ); + gen( + |(a, b): (MyF32, MyF32)| { let c = a.0 - b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -434,10 +550,12 @@ fn main() { Some(c) } }, - "builtins::float::sub::__subsf3(a, b)"); + "builtins::float::sub::__subsf3(a, b)", + ); if target_arch_arm { - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let c = a.0 - b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -445,8 +563,10 @@ fn main() { Some(c) } }, - "builtins::float::sub::__subdf3vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::sub::__subdf3vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { let c = a.0 - b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -454,11 +574,13 @@ fn main() { Some(c) } }, - "builtins::float::sub::__subsf3vfp(a, b)"); + "builtins::float::sub::__subsf3vfp(a, b)", + ); } // float/mul.rs - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let c = a.0 * b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -466,8 +588,10 @@ fn main() { Some(c) } }, - "builtins::float::mul::__muldf3(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::mul::__muldf3(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { let c = a.0 * b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -475,10 +599,12 @@ fn main() { Some(c) } }, - "builtins::float::mul::__mulsf3(a, b)"); + "builtins::float::mul::__mulsf3(a, b)", + ); if target_arch_arm { - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let c = a.0 * b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -486,8 +612,10 @@ fn main() { Some(c) } }, - "builtins::float::mul::__muldf3vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::mul::__muldf3vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { let c = a.0 * b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -495,122 +623,168 @@ fn main() { Some(c) } }, - "builtins::float::mul::__mulsf3vfp(a, b)"); + "builtins::float::mul::__mulsf3vfp(a, b)", + ); } // float/div.rs - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { if b.0 == 0.0 { - return None + return None; } let c = a.0 / b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() || - c.abs() <= unsafe { mem::transmute(4503599627370495u64) } + if a.0.is_nan() + || b.0.is_nan() + || c.is_nan() + || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } { None } else { Some(c) } }, - "builtins::float::div::__divdf3(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::div::__divdf3(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { if b.0 == 0.0 { - return None + return None; } let c = a.0 / b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() || - c.abs() <= unsafe { mem::transmute(16777215u32) } + if a.0.is_nan() + || b.0.is_nan() + || c.is_nan() + || c.abs() <= unsafe { mem::transmute(16777215u32) } { None } else { Some(c) } }, - "builtins::float::div::__divsf3(a, b)"); + "builtins::float::div::__divsf3(a, b)", + ); if target_arch_arm { - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { if b.0 == 0.0 { - return None + return None; } let c = a.0 / b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() || - c.abs() <= unsafe { mem::transmute(4503599627370495u64) } + if a.0.is_nan() + || b.0.is_nan() + || c.is_nan() + || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } { None } else { Some(c) } }, - "builtins::float::div::__divdf3vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::div::__divdf3vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { if b.0 == 0.0 { - return None + return None; } let c = a.0 / b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() || - c.abs() <= unsafe { mem::transmute(16777215u32) } + if a.0.is_nan() + || b.0.is_nan() + || c.is_nan() + || c.abs() <= unsafe { mem::transmute(16777215u32) } { None } else { Some(c) } }, - "builtins::float::div::__divsf3vfp(a, b)"); + "builtins::float::div::__divsf3vfp(a, b)", + ); } // int/addsub.rs - gen(|(a, b): (MyU128, MyU128)| Some(a.0.wrapping_add(b.0)), - "builtins::int::addsub::rust_u128_add(a, b)"); - gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_add(b.0)), - "builtins::int::addsub::rust_i128_add(a, b)"); - gen(|(a, b): (MyU128, MyU128)| Some(a.0.overflowing_add(b.0)), - "builtins::int::addsub::rust_u128_addo(a, b)"); - gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_add(b.0)), - "builtins::int::addsub::rust_i128_addo(a, b)"); - gen(|(a, b): (MyU128, MyU128)| Some(a.0.wrapping_sub(b.0)), - "builtins::int::addsub::rust_u128_sub(a, b)"); - gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_sub(b.0)), - "builtins::int::addsub::rust_i128_sub(a, b)"); - gen(|(a, b): (MyU128, MyU128)| Some(a.0.overflowing_sub(b.0)), - "builtins::int::addsub::rust_u128_subo(a, b)"); - gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_sub(b.0)), - "builtins::int::addsub::rust_i128_subo(a, b)"); + gen( + |(a, b): (MyU128, MyU128)| Some(a.0.wrapping_add(b.0)), + "builtins::int::addsub::rust_u128_add(a, b)", + ); + gen( + |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_add(b.0)), + "builtins::int::addsub::rust_i128_add(a, b)", + ); + gen( + |(a, b): (MyU128, MyU128)| Some(a.0.overflowing_add(b.0)), + "builtins::int::addsub::rust_u128_addo(a, b)", + ); + gen( + |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_add(b.0)), + "builtins::int::addsub::rust_i128_addo(a, b)", + ); + gen( + |(a, b): (MyU128, MyU128)| Some(a.0.wrapping_sub(b.0)), + "builtins::int::addsub::rust_u128_sub(a, b)", + ); + gen( + |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_sub(b.0)), + "builtins::int::addsub::rust_i128_sub(a, b)", + ); + gen( + |(a, b): (MyU128, MyU128)| Some(a.0.overflowing_sub(b.0)), + "builtins::int::addsub::rust_u128_subo(a, b)", + ); + gen( + |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_sub(b.0)), + "builtins::int::addsub::rust_i128_subo(a, b)", + ); // int/mul.rs - gen(|(a, b): (MyU64, MyU64)| Some(a.0.wrapping_mul(b.0)), - "builtins::int::mul::__muldi3(a, b)"); - gen(|(a, b): (MyI64, MyI64)| Some(a.0.overflowing_mul(b.0)), + gen( + |(a, b): (MyU64, MyU64)| Some(a.0.wrapping_mul(b.0)), + "builtins::int::mul::__muldi3(a, b)", + ); + gen( + |(a, b): (MyI64, MyI64)| Some(a.0.overflowing_mul(b.0)), "{ let mut o = 2; let c = builtins::int::mul::__mulodi4(a, b, &mut o); (c, match o { 0 => false, 1 => true, _ => panic!() }) - }"); - gen(|(a, b): (MyI32, MyI32)| Some(a.0.overflowing_mul(b.0)), + }", + ); + gen( + |(a, b): (MyI32, MyI32)| Some(a.0.overflowing_mul(b.0)), "{ let mut o = 2; let c = builtins::int::mul::__mulosi4(a, b, &mut o); (c, match o { 0 => false, 1 => true, _ => panic!() }) - }"); - gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_mul(b.0)), - "builtins::int::mul::__multi3(a, b)"); - gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_mul(b.0)), + }", + ); + gen( + |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_mul(b.0)), + "builtins::int::mul::__multi3(a, b)", + ); + gen( + |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_mul(b.0)), "{ let mut o = 2; let c = builtins::int::mul::__muloti4(a, b, &mut o); (c, match o { 0 => false, 1 => true, _ => panic!() }) - }"); + }", + ); // int/sdiv.rs - gen(|(a, b): (MyI64, MyI64)| { + gen( + |(a, b): (MyI64, MyI64)| { if b.0 == 0 { None } else { Some(a.0 / b.0) } }, - "builtins::int::sdiv::__divdi3(a, b)"); - gen(|(a, b): (MyI64, MyI64)| { + "builtins::int::sdiv::__divdi3(a, b)", + ); + gen( + |(a, b): (MyI64, MyI64)| { if b.0 == 0 { None } else { @@ -620,8 +794,10 @@ fn main() { "{ let mut r = 0; (builtins::int::sdiv::__divmoddi4(a, b, &mut r), r) - }"); - gen(|(a, b): (MyI32, MyI32)| { + }", + ); + gen( + |(a, b): (MyI32, MyI32)| { if b.0 == 0 { None } else { @@ -631,72 +807,98 @@ fn main() { "{ let mut r = 0; (builtins::int::sdiv::__divmodsi4(a, b, &mut r), r) - }"); - gen(|(a, b): (MyI32, MyI32)| { + }", + ); + gen( + |(a, b): (MyI32, MyI32)| { if b.0 == 0 { None } else { Some(a.0 / b.0) } }, - "builtins::int::sdiv::__divsi3(a, b)"); - gen(|(a, b): (MyI32, MyI32)| { + "builtins::int::sdiv::__divsi3(a, b)", + ); + gen( + |(a, b): (MyI32, MyI32)| { if b.0 == 0 { None } else { Some(a.0 % b.0) } }, - "builtins::int::sdiv::__modsi3(a, b)"); - gen(|(a, b): (MyI64, MyI64)| { + "builtins::int::sdiv::__modsi3(a, b)", + ); + gen( + |(a, b): (MyI64, MyI64)| { if b.0 == 0 { None } else { Some(a.0 % b.0) } }, - "builtins::int::sdiv::__moddi3(a, b)"); - gen(|(a, b): (MyI128, MyI128)| { + "builtins::int::sdiv::__moddi3(a, b)", + ); + gen( + |(a, b): (MyI128, MyI128)| { if b.0 == 0 { None } else { Some(a.0 / b.0) } }, - "builtins::int::sdiv::__divti3(a, b)"); - gen(|(a, b): (MyI128, MyI128)| { + "builtins::int::sdiv::__divti3(a, b)", + ); + gen( + |(a, b): (MyI128, MyI128)| { if b.0 == 0 { None } else { Some(a.0 % b.0) } }, - "builtins::int::sdiv::__modti3(a, b)"); + "builtins::int::sdiv::__modti3(a, b)", + ); // int/shift.rs - gen(|(a, b): (MyU64, MyU32)| Some(a.0 << (b.0 % 64)), - "builtins::int::shift::__ashldi3(a, b % 64)"); - gen(|(a, b): (MyU128, MyU32)| Some(a.0 << (b.0 % 128)), - "builtins::int::shift::__ashlti3(a, b % 128)"); - gen(|(a, b): (MyI64, MyU32)| Some(a.0 >> (b.0 % 64)), - "builtins::int::shift::__ashrdi3(a, b % 64)"); - gen(|(a, b): (MyI128, MyU32)| Some(a.0 >> (b.0 % 128)), - "builtins::int::shift::__ashrti3(a, b % 128)"); - gen(|(a, b): (MyU64, MyU32)| Some(a.0 >> (b.0 % 64)), - "builtins::int::shift::__lshrdi3(a, b % 64)"); - gen(|(a, b): (MyU128, MyU32)| Some(a.0 >> (b.0 % 128)), - "builtins::int::shift::__lshrti3(a, b % 128)"); + gen( + |(a, b): (MyU64, MyU32)| Some(a.0 << (b.0 % 64)), + "builtins::int::shift::__ashldi3(a, b % 64)", + ); + gen( + |(a, b): (MyU128, MyU32)| Some(a.0 << (b.0 % 128)), + "builtins::int::shift::__ashlti3(a, b % 128)", + ); + gen( + |(a, b): (MyI64, MyU32)| Some(a.0 >> (b.0 % 64)), + "builtins::int::shift::__ashrdi3(a, b % 64)", + ); + gen( + |(a, b): (MyI128, MyU32)| Some(a.0 >> (b.0 % 128)), + "builtins::int::shift::__ashrti3(a, b % 128)", + ); + gen( + |(a, b): (MyU64, MyU32)| Some(a.0 >> (b.0 % 64)), + "builtins::int::shift::__lshrdi3(a, b % 64)", + ); + gen( + |(a, b): (MyU128, MyU32)| Some(a.0 >> (b.0 % 128)), + "builtins::int::shift::__lshrti3(a, b % 128)", + ); // int/udiv.rs - gen(|(a, b): (MyU64, MyU64)| { + gen( + |(a, b): (MyU64, MyU64)| { if b.0 == 0 { None } else { Some(a.0 / b.0) } }, - "builtins::int::udiv::__udivdi3(a, b)"); - gen(|(a, b): (MyU64, MyU64)| { + "builtins::int::udiv::__udivdi3(a, b)", + ); + gen( + |(a, b): (MyU64, MyU64)| { if b.0 == 0 { None } else { @@ -706,8 +908,10 @@ fn main() { "{ let mut r = 0; (builtins::int::udiv::__udivmoddi4(a, b, Some(&mut r)), r) - }"); - gen(|(a, b): (MyU32, MyU32)| { + }", + ); + gen( + |(a, b): (MyU32, MyU32)| { if b.0 == 0 { None } else { @@ -717,48 +921,60 @@ fn main() { "{ let mut r = 0; (builtins::int::udiv::__udivmodsi4(a, b, Some(&mut r)), r) - }"); - gen(|(a, b): (MyU32, MyU32)| { + }", + ); + gen( + |(a, b): (MyU32, MyU32)| { if b.0 == 0 { None } else { Some(a.0 / b.0) } }, - "builtins::int::udiv::__udivsi3(a, b)"); - gen(|(a, b): (MyU32, MyU32)| { + "builtins::int::udiv::__udivsi3(a, b)", + ); + gen( + |(a, b): (MyU32, MyU32)| { if b.0 == 0 { None } else { Some(a.0 % b.0) } }, - "builtins::int::udiv::__umodsi3(a, b)"); - gen(|(a, b): (MyU64, MyU64)| { + "builtins::int::udiv::__umodsi3(a, b)", + ); + gen( + |(a, b): (MyU64, MyU64)| { if b.0 == 0 { None } else { Some(a.0 % b.0) } }, - "builtins::int::udiv::__umoddi3(a, b)"); - gen(|(a, b): (MyU128, MyU128)| { + "builtins::int::udiv::__umoddi3(a, b)", + ); + gen( + |(a, b): (MyU128, MyU128)| { if b.0 == 0 { None } else { Some(a.0 / b.0) } }, - "builtins::int::udiv::__udivti3(a, b)"); - gen(|(a, b): (MyU128, MyU128)| { + "builtins::int::udiv::__udivti3(a, b)", + ); + gen( + |(a, b): (MyU128, MyU128)| { if b.0 == 0 { None } else { Some(a.0 % b.0) } }, - "builtins::int::udiv::__umodti3(a, b)"); - gen(|(a, b): (MyU128, MyU128)| { + "builtins::int::udiv::__umodti3(a, b)", + ); + gen( + |(a, b): (MyU128, MyU128)| { if b.0 == 0 { None } else { @@ -768,7 +984,8 @@ fn main() { "{ let mut r = 0; (builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) - }"); + }", + ); } macro_rules! gen_float { @@ -790,24 +1007,27 @@ macro_rules! gen_float { fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { unsafe { - mem::transmute(((sign as $uty) << (BITS - 1)) | - ((exponent & EXPONENT_MASK) << - SIGNIFICAND_BITS) | - (significand & SIGNIFICAND_MASK)) + mem::transmute( + ((sign as $uty) << (BITS - 1)) + | ((exponent & EXPONENT_MASK) << SIGNIFICAND_BITS) + | (significand & SIGNIFICAND_MASK), + ) } } if rng.gen_weighted_bool(10) { // Special values - *rng.choose(&[-0.0, - 0.0, - ::std::$fty::MIN, - ::std::$fty::MIN_POSITIVE, - ::std::$fty::MAX, - ::std::$fty::NAN, - ::std::$fty::INFINITY, - -::std::$fty::INFINITY]) - .unwrap() + *rng.choose(&[ + -0.0, + 0.0, + ::std::$fty::MIN, + ::std::$fty::MIN_POSITIVE, + ::std::$fty::MAX, + ::std::$fty::NAN, + ::std::$fty::INFINITY, + -::std::$fty::INFINITY, + ]) + .unwrap() } else if rng.gen_weighted_bool(10) { // NaN patterns mk_f32(rng.gen(), rng.gen(), 0) @@ -819,7 +1039,7 @@ macro_rules! gen_float { mk_f32(rng.gen(), rng.gen(), rng.gen()) } } - } + }; } gen_float!(gen_f32, f32, u32, 32, 23); @@ -844,24 +1064,27 @@ macro_rules! gen_large_float { fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { unsafe { - mem::transmute(((sign as $uty) << (BITS - 1)) | - ((exponent & EXPONENT_MASK) << - SIGNIFICAND_BITS) | - (significand & SIGNIFICAND_MASK)) + mem::transmute( + ((sign as $uty) << (BITS - 1)) + | ((exponent & EXPONENT_MASK) << SIGNIFICAND_BITS) + | (significand & SIGNIFICAND_MASK), + ) } } if rng.gen_weighted_bool(10) { // Special values - *rng.choose(&[-0.0, - 0.0, - ::std::$fty::MIN, - ::std::$fty::MIN_POSITIVE, - ::std::$fty::MAX, - ::std::$fty::NAN, - ::std::$fty::INFINITY, - -::std::$fty::INFINITY]) - .unwrap() + *rng.choose(&[ + -0.0, + 0.0, + ::std::$fty::MIN, + ::std::$fty::MIN_POSITIVE, + ::std::$fty::MAX, + ::std::$fty::NAN, + ::std::$fty::INFINITY, + -::std::$fty::INFINITY, + ]) + .unwrap() } else if rng.gen_weighted_bool(10) { // NaN patterns mk_f32(rng.gen(), rng.gen(), 0) @@ -873,7 +1096,7 @@ macro_rules! gen_large_float { rng.gen::<$fty>() } } - } + }; } gen_large_float!(gen_large_f32, f32, u32, 32, 23); @@ -892,17 +1115,13 @@ trait TestOutput { } fn gen(mut generate: F, test: &str) - where F: FnMut(A) -> Option, - A: TestInput + Copy, - R: TestOutput, +where + F: FnMut(A) -> Option, + A: TestInput + Copy, + R: TestOutput, { let rng = &mut rand::thread_rng(); - let testname = test.split("::") - .last() - .unwrap() - .split("(") - .next() - .unwrap(); + let testname = test.split("::").last().unwrap().split("(").next().unwrap(); let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let out_file = out_dir.join("generated.rs"); @@ -911,7 +1130,7 @@ fn gen(mut generate: F, test: &str) while n > 0 { let input: A = rng.gen(); if testcases.contains_key(&input) { - continue + continue; } let output = match generate(input) { Some(o) => o, @@ -925,10 +1144,12 @@ fn gen(mut generate: F, test: &str) contents.push_str(&format!("mod {} {{\nuse super::*;\n", testname)); contents.push_str("#[test]\n"); contents.push_str("fn test() {\n"); - contents.push_str(&format!("static TESTS: [({}, {}); {}] = [\n", - A::ty_name(), - R::ty_name(), - NTESTS)); + contents.push_str(&format!( + "static TESTS: [({}, {}); {}] = [\n", + A::ty_name(), + R::ty_name(), + NTESTS + )); for (input, output) in testcases { contents.push_str(" ("); input.generate_static(&mut contents); @@ -938,7 +1159,8 @@ fn gen(mut generate: F, test: &str) } contents.push_str("];\n"); - contents.push_str(&format!(r#" + contents.push_str(&format!( + r#" for &(inputs, output) in TESTS.iter() {{ {} assert_eq!({}, {}, "inputs {{:?}}", inputs) @@ -1070,17 +1292,20 @@ my_integer! { } impl TestInput for (A, B) - where A: TestInput, - B: TestInput, +where + A: TestInput, + B: TestInput, { fn ty_name() -> String { format!("({}, {})", A::ty_name(), B::ty_name()) } fn generate_lets(container: &str, cnt: &mut u8) -> String { - format!("{}{}", - A::generate_lets(&format!("{}.0", container), cnt), - B::generate_lets(&format!("{}.1", container), cnt)) + format!( + "{}{}", + A::generate_lets(&format!("{}.0", container), cnt), + B::generate_lets(&format!("{}.1", container), cnt) + ) } fn generate_static(&self, dst: &mut String) { @@ -1141,8 +1366,9 @@ macro_rules! plain_test_output { plain_test_output!(i32 i64 i128 u32 u64 u128 bool); impl TestOutput for (A, B) - where A: TestOutput, - B: TestOutput, +where + A: TestOutput, + B: TestOutput, { fn ty_name() -> String { format!("({}, {})", A::ty_name(), B::ty_name()) diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 2e7f0d4d752..0c9ac1ac8e4 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -1 +1 @@ -#![no_std] \ No newline at end of file +#![no_std] diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs index 08fbd4fa9f2..326435c298d 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs @@ -1,7 +1,9 @@ -#![cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - feature = "mem"))] +#![cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem" +))] #![feature(compiler_builtins_lib)] #![feature(lang_items)] #![no_std] diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs index 76dad899263..2d72dfbbaa6 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs @@ -1,7 +1,9 @@ -#![cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - feature = "mem"))] +#![cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem" +))] #![feature(compiler_builtins_lib)] #![feature(lang_items)] #![no_std] diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs index 71fe37e3582..3cfbfe5b011 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs @@ -1,7 +1,9 @@ -#![cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - feature = "mem"))] +#![cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem" +))] #![feature(compiler_builtins_lib)] #![feature(lang_items)] #![no_std] @@ -48,9 +50,7 @@ fn zero() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), 0, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), 0, c) } assert_eq!(*xs, [0; 8]); @@ -59,9 +59,7 @@ fn zero() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), 0, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), 0, c) } assert_eq!(*xs, [1; 8]); } @@ -74,9 +72,7 @@ fn one() { let n = 1; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0, 0, 0, 0, 0, 0, 0]); @@ -85,9 +81,7 @@ fn one() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 1, 1, 1, 1, 1, 1, 1]); } @@ -100,9 +94,7 @@ fn two() { let n = 2; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0, 0, 0, 0, 0, 0]); @@ -111,9 +103,7 @@ fn two() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 1, 1, 1, 1, 1, 1]); } @@ -126,9 +116,7 @@ fn three() { let n = 3; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0, 0, 0, 0, 0]); @@ -137,9 +125,7 @@ fn three() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 1, 1, 1, 1, 1]); } @@ -152,9 +138,7 @@ fn four() { let n = 4; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0, 0, 0, 0]); @@ -163,9 +147,7 @@ fn four() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 1, 1, 1, 1]); } @@ -178,9 +160,7 @@ fn five() { let n = 5; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0, 0, 0]); @@ -189,9 +169,7 @@ fn five() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 1, 1, 1]); } @@ -204,9 +182,7 @@ fn six() { let n = 6; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0, 0]); @@ -215,9 +191,7 @@ fn six() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1, 1]); } @@ -230,9 +204,7 @@ fn seven() { let n = 7; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0]); @@ -241,9 +213,7 @@ fn seven() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1]); } @@ -256,9 +226,7 @@ fn eight() { let n = 8; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); @@ -267,9 +235,7 @@ fn eight() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); } diff --git a/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs b/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs index 55965017454..b50a7ce8430 100644 --- a/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs +++ b/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs @@ -6,20 +6,20 @@ use compiler_builtins::int::__clzsi2; #[test] fn __clzsi2_test() { - let mut i: usize = core::usize::MAX; - // Check all values above 0 - while i > 0 { + let mut i: usize = core::usize::MAX; + // Check all values above 0 + while i > 0 { + assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); + i >>= 1; + } + // check 0 also + i = 0; assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); - i >>= 1; - } - // check 0 also - i = 0; - assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); - // double check for bit patterns that aren't just solid 1s - i = 1; - for _ in 0..63 { - assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); - i <<= 2; - i += 1; - } + // double check for bit patterns that aren't just solid 1s + i = 1; + for _ in 0..63 { + assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); + i <<= 2; + i += 1; + } } diff --git a/library/compiler-builtins/testcrate/tests/generated.rs b/library/compiler-builtins/testcrate/tests/generated.rs index 28fe4be59e3..ee575cba87e 100644 --- a/library/compiler-builtins/testcrate/tests/generated.rs +++ b/library/compiler-builtins/testcrate/tests/generated.rs @@ -6,23 +6,29 @@ extern crate compiler_builtins as builtins; -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] +#[cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test +))] extern crate utest_cortex_m_qemu; -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] +#[cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test +))] #[macro_use] extern crate utest_macros; -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] +#[cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test +))] macro_rules! panic { // overrides `panic!` ($($tt:tt)*) => { upanic!($($tt)*); -- cgit 1.4.1-3-g733a5 From 02aaab7026122b28b4d4dcca833a7e99c91b55a0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 14 May 2019 14:41:07 -0700 Subject: Bump to 0.1.13 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 4d0350de5dd..f0803743284 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.12" +version = "0.1.13" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From f567dbb36ba82779e2aab06d12b68930c3db277f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 May 2019 12:57:36 -0700 Subject: Remove the need for #[cfg] in #[use_c_shim_if] This commit tweaks the implementation of the synthetic `#[use_c_shim_if]` attribute, renaming it to `#[maybe_use_optimized_c_shim]` in the process. This no longer requires specifying a `#[cfg]` clause indicating when the optimized intrinsic should be used, but rather this is inferred and printed from the build script. The build script will now print out appropriate `#[cfg]` directives for rustc to indicate what intrinsics it's compiling. This should remove the need for us to keep the build script and the source in sync, but rather the build script can simply take care of everything. --- library/compiler-builtins/build.rs | 336 ++++++++++++++-------------- library/compiler-builtins/ci/run.sh | 1 + library/compiler-builtins/src/float/conv.rs | 18 +- library/compiler-builtins/src/int/mod.rs | 2 +- library/compiler-builtins/src/int/mul.rs | 2 +- library/compiler-builtins/src/int/sdiv.rs | 14 +- library/compiler-builtins/src/int/shift.rs | 6 +- library/compiler-builtins/src/int/udiv.rs | 18 +- library/compiler-builtins/src/macros.rs | 23 +- 9 files changed, 198 insertions(+), 222 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a8301afa95f..be5d42bb76d 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -49,7 +49,6 @@ fn main() { if !target.contains("wasm32") && !target.contains("nvptx") && !target.starts_with("riscv") { #[cfg(feature = "c")] c::compile(&llvm_target); - println!("cargo:rustc-cfg=use_c"); } } @@ -91,15 +90,14 @@ mod c { } } - fn extend(&mut self, sources: &[&'static str]) { + fn extend(&mut self, sources: &[(&'static str, &'static str)]) { // NOTE Some intrinsics have both a generic implementation (e.g. // `floatdidf.c`) and an arch optimized implementation // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized // implementation and discard the generic implementation. If we don't // and keep both implementations, the linker will yell at us about // duplicate symbols! - for &src in sources { - let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap(); + for (symbol, src) in sources { if src.contains("/") { // Arch-optimized implementation (preferred) self.map.insert(symbol, src); @@ -155,42 +153,42 @@ mod c { let mut sources = Sources::new(); sources.extend(&[ - "absvdi2.c", - "absvsi2.c", - "addvdi3.c", - "addvsi3.c", - "apple_versioning.c", - "clzdi2.c", - "clzsi2.c", - "cmpdi2.c", - "ctzdi2.c", - "ctzsi2.c", - "divdc3.c", - "divsc3.c", - "divxc3.c", - "extendhfsf2.c", - "int_util.c", - "muldc3.c", - "mulsc3.c", - "mulvdi3.c", - "mulvsi3.c", - "mulxc3.c", - "negdf2.c", - "negdi2.c", - "negsf2.c", - "negvdi2.c", - "negvsi2.c", - "paritydi2.c", - "paritysi2.c", - "popcountdi2.c", - "popcountsi2.c", - "powixf2.c", - "subvdi3.c", - "subvsi3.c", - "truncdfhf2.c", - "truncdfsf2.c", - "truncsfhf2.c", - "ucmpdi2.c", + ("__absvdi2", "absvdi2.c"), + ("__absvsi2", "absvsi2.c"), + ("__addvdi3", "addvdi3.c"), + ("__addvsi3", "addvsi3.c"), + ("apple_versioning", "apple_versioning.c"), + ("__clzdi2", "clzdi2.c"), + ("__clzsi2", "clzsi2.c"), + ("__cmpdi2", "cmpdi2.c"), + ("__ctzdi2", "ctzdi2.c"), + ("__ctzsi2", "ctzsi2.c"), + ("__divdc3", "divdc3.c"), + ("__divsc3", "divsc3.c"), + ("__divxc3", "divxc3.c"), + ("__extendhfsf2", "extendhfsf2.c"), + ("__int_util", "int_util.c"), + ("__muldc3", "muldc3.c"), + ("__mulsc3", "mulsc3.c"), + ("__mulvdi3", "mulvdi3.c"), + ("__mulvsi3", "mulvsi3.c"), + ("__mulxc3", "mulxc3.c"), + ("__negdf2", "negdf2.c"), + ("__negdi2", "negdi2.c"), + ("__negsf2", "negsf2.c"), + ("__negvdi2", "negvdi2.c"), + ("__negvsi2", "negvsi2.c"), + ("__paritydi2", "paritydi2.c"), + ("__paritysi2", "paritysi2.c"), + ("__popcountdi2", "popcountdi2.c"), + ("__popcountsi2", "popcountsi2.c"), + ("__powixf2", "powixf2.c"), + ("__subvdi3", "subvdi3.c"), + ("__subvsi3", "subvsi3.c"), + ("__truncdfhf2", "truncdfhf2.c"), + ("__truncdfsf2", "truncdfsf2.c"), + ("__truncsfhf2", "truncsfhf2.c"), + ("__ucmpdi2", "ucmpdi2.c"), ]); // When compiling in rustbuild (the rust-lang/rust repo) this library @@ -198,43 +196,49 @@ mod c { // need, so include a few more that aren't typically needed by // LLVM/Rust. if cfg!(feature = "rustbuild") { - sources.extend(&["ffsdi2.c"]); + sources.extend(&[("__ffsdi2", "ffsdi2.c")]); } // On iOS and 32-bit OSX these are all just empty intrinsics, no need to // include them. if target_os != "ios" && (target_vendor != "apple" || target_arch != "x86") { sources.extend(&[ - "absvti2.c", - "addvti3.c", - "clzti2.c", - "cmpti2.c", - "ctzti2.c", - "ffsti2.c", - "mulvti3.c", - "negti2.c", - "negvti2.c", - "parityti2.c", - "popcountti2.c", - "subvti3.c", - "ucmpti2.c", + ("__absvti2", "absvti2.c"), + ("__addvti3", "addvti3.c"), + ("__clzti2", "clzti2.c"), + ("__cmpti2", "cmpti2.c"), + ("__ctzti2", "ctzti2.c"), + ("__ffsti2", "ffsti2.c"), + ("__mulvti3", "mulvti3.c"), + ("__negti2", "negti2.c"), + ("__negvti2", "negvti2.c"), + ("__parityti2", "parityti2.c"), + ("__popcountti2", "popcountti2.c"), + ("__subvti3", "subvti3.c"), + ("__ucmpti2", "ucmpti2.c"), ]); } if target_vendor == "apple" { sources.extend(&[ - "atomic_flag_clear.c", - "atomic_flag_clear_explicit.c", - "atomic_flag_test_and_set.c", - "atomic_flag_test_and_set_explicit.c", - "atomic_signal_fence.c", - "atomic_thread_fence.c", + ("atomic_flag_clear", "atomic_flag_clear.c"), + ("atomic_flag_clear_explicit", "atomic_flag_clear_explicit.c"), + ("atomic_flag_test_and_set", "atomic_flag_test_and_set.c"), + ( + "atomic_flag_test_and_set_explicit", + "atomic_flag_test_and_set_explicit.c", + ), + ("atomic_signal_fence", "atomic_signal_fence.c"), + ("atomic_thread_fence", "atomic_thread_fence.c"), ]); } if target_env == "msvc" { if target_arch == "x86_64" { - sources.extend(&["x86_64/floatdisf.c", "x86_64/floatdixf.c"]); + sources.extend(&[ + ("__floatdisf", "x86_64/floatdisf.c"), + ("__floatdixf", "x86_64/floatdixf.c"), + ]); } } else { // None of these seem to be used on x86_64 windows, and they've all @@ -242,59 +246,59 @@ mod c { if target_os != "windows" { if target_arch == "x86_64" { sources.extend(&[ - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S", + ("__floatdisf", "x86_64/floatdisf.c"), + ("__floatdixf", "x86_64/floatdixf.c"), + ("__floatundidf", "x86_64/floatundidf.S"), + ("__floatundisf", "x86_64/floatundisf.S"), + ("__floatundixf", "x86_64/floatundixf.S"), ]); } } if target_arch == "x86" { sources.extend(&[ - "i386/ashldi3.S", - "i386/ashrdi3.S", - "i386/divdi3.S", - "i386/floatdidf.S", - "i386/floatdisf.S", - "i386/floatdixf.S", - "i386/floatundidf.S", - "i386/floatundisf.S", - "i386/floatundixf.S", - "i386/lshrdi3.S", - "i386/moddi3.S", - "i386/muldi3.S", - "i386/udivdi3.S", - "i386/umoddi3.S", + ("__ashldi3", "i386/ashldi3.S"), + ("__ashrdi3", "i386/ashrdi3.S"), + ("__divdi3", "i386/divdi3.S"), + ("__floatdidf", "i386/floatdidf.S"), + ("__floatdisf", "i386/floatdisf.S"), + ("__floatdixf", "i386/floatdixf.S"), + ("__floatundidf", "i386/floatundidf.S"), + ("__floatundisf", "i386/floatundisf.S"), + ("__floatundixf", "i386/floatundixf.S"), + ("__lshrdi3", "i386/lshrdi3.S"), + ("__moddi3", "i386/moddi3.S"), + ("__muldi3", "i386/muldi3.S"), + ("__udivdi3", "i386/udivdi3.S"), + ("__umoddi3", "i386/umoddi3.S"), ]); } } if target_arch == "arm" && target_os != "ios" && target_env != "msvc" { sources.extend(&[ - "arm/aeabi_div0.c", - "arm/aeabi_drsub.c", - "arm/aeabi_frsub.c", - "arm/bswapdi2.S", - "arm/bswapsi2.S", - "arm/clzdi2.S", - "arm/clzsi2.S", - "arm/divmodsi4.S", - "arm/divsi3.S", - "arm/modsi3.S", - "arm/switch16.S", - "arm/switch32.S", - "arm/switch8.S", - "arm/switchu8.S", - "arm/sync_synchronize.S", - "arm/udivmodsi4.S", - "arm/udivsi3.S", - "arm/umodsi3.S", + ("__aeabi_div0", "arm/aeabi_div0.c"), + ("__aeabi_drsub", "arm/aeabi_drsub.c"), + ("__aeabi_frsub", "arm/aeabi_frsub.c"), + ("__bswapdi2", "arm/bswapdi2.S"), + ("__bswapsi2", "arm/bswapsi2.S"), + ("__clzdi2", "arm/clzdi2.S"), + ("__clzsi2", "arm/clzsi2.S"), + ("__divmodsi4", "arm/divmodsi4.S"), + ("__divsi3", "arm/divsi3.S"), + ("__modsi3", "arm/modsi3.S"), + ("__switch16", "arm/switch16.S"), + ("__switch32", "arm/switch32.S"), + ("__switch8", "arm/switch8.S"), + ("__switchu8", "arm/switchu8.S"), + ("__sync_synchronize", "arm/sync_synchronize.S"), + ("__udivmodsi4", "arm/udivmodsi4.S"), + ("__udivsi3", "arm/udivsi3.S"), + ("__umodsi3", "arm/umodsi3.S"), ]); if target_os == "freebsd" { - sources.extend(&["clear_cache.c"]); + sources.extend(&[("__clear_cache", "clear_cache.c")]); } // First of all aeabi_cdcmp and aeabi_cfcmp are never called by LLVM. @@ -302,36 +306,36 @@ mod c { // Temporally workaround: exclude these files for big-endian targets. if !llvm_target[0].starts_with("thumbeb") && !llvm_target[0].starts_with("armeb") { sources.extend(&[ - "arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", + ("__aeabi_cdcmp", "arm/aeabi_cdcmp.S"), + ("__aeabi_cdcmpeq_check_nan", "arm/aeabi_cdcmpeq_check_nan.c"), + ("__aeabi_cfcmp", "arm/aeabi_cfcmp.S"), + ("__aeabi_cfcmpeq_check_nan", "arm/aeabi_cfcmpeq_check_nan.c"), ]); } } if llvm_target[0] == "armv7" { sources.extend(&[ - "arm/sync_fetch_and_add_4.S", - "arm/sync_fetch_and_add_8.S", - "arm/sync_fetch_and_and_4.S", - "arm/sync_fetch_and_and_8.S", - "arm/sync_fetch_and_max_4.S", - "arm/sync_fetch_and_max_8.S", - "arm/sync_fetch_and_min_4.S", - "arm/sync_fetch_and_min_8.S", - "arm/sync_fetch_and_nand_4.S", - "arm/sync_fetch_and_nand_8.S", - "arm/sync_fetch_and_or_4.S", - "arm/sync_fetch_and_or_8.S", - "arm/sync_fetch_and_sub_4.S", - "arm/sync_fetch_and_sub_8.S", - "arm/sync_fetch_and_umax_4.S", - "arm/sync_fetch_and_umax_8.S", - "arm/sync_fetch_and_umin_4.S", - "arm/sync_fetch_and_umin_8.S", - "arm/sync_fetch_and_xor_4.S", - "arm/sync_fetch_and_xor_8.S", + ("__sync_fetch_and_add_4", "arm/sync_fetch_and_add_4.S"), + ("__sync_fetch_and_add_8", "arm/sync_fetch_and_add_8.S"), + ("__sync_fetch_and_and_4", "arm/sync_fetch_and_and_4.S"), + ("__sync_fetch_and_and_8", "arm/sync_fetch_and_and_8.S"), + ("__sync_fetch_and_max_4", "arm/sync_fetch_and_max_4.S"), + ("__sync_fetch_and_max_8", "arm/sync_fetch_and_max_8.S"), + ("__sync_fetch_and_min_4", "arm/sync_fetch_and_min_4.S"), + ("__sync_fetch_and_min_8", "arm/sync_fetch_and_min_8.S"), + ("__sync_fetch_and_nand_4", "arm/sync_fetch_and_nand_4.S"), + ("__sync_fetch_and_nand_8", "arm/sync_fetch_and_nand_8.S"), + ("__sync_fetch_and_or_4", "arm/sync_fetch_and_or_4.S"), + ("__sync_fetch_and_or_8", "arm/sync_fetch_and_or_8.S"), + ("__sync_fetch_and_sub_4", "arm/sync_fetch_and_sub_4.S"), + ("__sync_fetch_and_sub_8", "arm/sync_fetch_and_sub_8.S"), + ("__sync_fetch_and_umax_4", "arm/sync_fetch_and_umax_4.S"), + ("__sync_fetch_and_umax_8", "arm/sync_fetch_and_umax_8.S"), + ("__sync_fetch_and_umin_4", "arm/sync_fetch_and_umin_4.S"), + ("__sync_fetch_and_umin_8", "arm/sync_fetch_and_umin_8.S"), + ("__sync_fetch_and_xor_4", "arm/sync_fetch_and_xor_4.S"), + ("__sync_fetch_and_xor_8", "arm/sync_fetch_and_xor_8.S"), ]); } @@ -345,73 +349,66 @@ mod c { // do not support double precision floating points conversions so the files // that include such instructions are not included for these targets. sources.extend(&[ - "arm/fixdfsivfp.S", - "arm/fixunsdfsivfp.S", - "arm/floatsidfvfp.S", - "arm/floatunssidfvfp.S", + ("__fixdfsivfp", "arm/fixdfsivfp.S"), + ("__fixunsdfsivfp", "arm/fixunsdfsivfp.S"), + ("__floatsidfvfp", "arm/floatsidfvfp.S"), + ("__floatunssidfvfp", "arm/floatunssidfvfp.S"), ]); } sources.extend(&[ - "arm/fixsfsivfp.S", - "arm/fixunssfsivfp.S", - "arm/floatsisfvfp.S", - "arm/floatunssisfvfp.S", - "arm/floatunssisfvfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", - "arm/negdf2vfp.S", - "arm/negsf2vfp.S", + ("__fixsfsivfp", "arm/fixsfsivfp.S"), + ("__fixunssfsivfp", "arm/fixunssfsivfp.S"), + ("__floatsisfvfp", "arm/floatsisfvfp.S"), + ("__floatunssisfvfp", "arm/floatunssisfvfp.S"), + ("__floatunssisfvfp", "arm/floatunssisfvfp.S"), + ("__restore_vfp_d8_d15_regs", "arm/restore_vfp_d8_d15_regs.S"), + ("__save_vfp_d8_d15_regs", "arm/save_vfp_d8_d15_regs.S"), + ("__negdf2vfp", "arm/negdf2vfp.S"), + ("__negsf2vfp", "arm/negsf2vfp.S"), ]); } if target_arch == "aarch64" { sources.extend(&[ - "comparetf2.c", - "extenddftf2.c", - "extendsftf2.c", - "fixtfdi.c", - "fixtfsi.c", - "fixtfti.c", - "fixunstfdi.c", - "fixunstfsi.c", - "fixunstfti.c", - "floatditf.c", - "floatsitf.c", - "floatunditf.c", - "floatunsitf.c", - "trunctfdf2.c", - "trunctfsf2.c", + ("__comparetf2", "comparetf2.c"), + ("__extenddftf2", "extenddftf2.c"), + ("__extendsftf2", "extendsftf2.c"), + ("__fixtfdi", "fixtfdi.c"), + ("__fixtfsi", "fixtfsi.c"), + ("__fixtfti", "fixtfti.c"), + ("__fixunstfdi", "fixunstfdi.c"), + ("__fixunstfsi", "fixunstfsi.c"), + ("__fixunstfti", "fixunstfti.c"), + ("__floatditf", "floatditf.c"), + ("__floatsitf", "floatsitf.c"), + ("__floatunditf", "floatunditf.c"), + ("__floatunsitf", "floatunsitf.c"), + ("__trunctfdf2", "trunctfdf2.c"), + ("__trunctfsf2", "trunctfsf2.c"), ]); if target_os != "windows" { - sources.extend(&["multc3.c"]); + sources.extend(&[("__multc3", "multc3.c")]); } } // Remove the assembly implementations that won't compile for the target if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { - sources.remove(&[ - "clzdi2", - "clzsi2", - "divmodsi4", - "divsi3", - "modsi3", - "switch16", - "switch32", - "switch8", - "switchu8", - "udivmodsi4", - "udivsi3", - "umodsi3", - ]); + let mut to_remove = Vec::new(); + for (k, v) in sources.map.iter() { + if v.ends_with(".S") { + to_remove.push(*k); + } + } + sources.remove(&to_remove); // But use some generic implementations where possible - sources.extend(&["clzdi2.c", "clzsi2.c"]) + sources.extend(&[("__clzdi2", "clzdi2.c"), ("__clzsi2", "clzsi2.c")]) } if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { - sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); + sources.remove(&["__aeabi_cdcmp", "__aeabi_cfcmp"]); } // When compiling in rustbuild (the rust-lang/rust repo) this build @@ -423,10 +420,11 @@ mod c { }; let src_dir = root.join("compiler-rt/lib/builtins"); - for src in sources.map.values() { + for (sym, src) in sources.map.iter() { let src = src_dir.join(src); cfg.file(&src); println!("cargo:rerun-if-changed={}", src.display()); + println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); } cfg.compile("libcompiler-rt.a"); diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index ae32806ece8..4d6d6c68f1f 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,5 +1,6 @@ set -ex +export CARGO_INCREMENTAL=0 cargo=cargo # Test our implementation diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 21aac15c167..8a0fc6cb424 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -87,11 +87,7 @@ intrinsics! { int_to_float!(i, i32, f64) } - #[use_c_shim_if(any( - all(target_arch = "x86", not(target_env = "msvc")), - all(target_arch = "x86_64", not(windows)), - all(target_arch = "x86_64", target_env = "msvc"), - ))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_l2f] pub extern "C" fn __floatdisf(i: i64) -> f32 { // On x86_64 LLVM will use native instructions for this conversion, we @@ -103,7 +99,7 @@ intrinsics! { } } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_l2d] pub extern "C" fn __floatdidf(i: i64) -> f64 { // On x86_64 LLVM will use native instructions for this conversion, we @@ -135,19 +131,13 @@ intrinsics! { int_to_float!(i, u32, f64) } - #[use_c_shim_if(any( - all(target_arch = "x86", not(target_env = "msvc")), - all(target_arch = "x86_64", not(windows)), - ))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_ul2f] pub extern "C" fn __floatundisf(i: u64) -> f32 { int_to_float!(i, u64, f32) } - #[use_c_shim_if(any( - all(target_arch = "x86", not(target_env = "msvc")), - all(target_arch = "x86_64", not(windows)), - ))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float!(i, u64, f64) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index fd1f0c3c881..7587bc69e76 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -302,7 +302,7 @@ impl_wide_int!(u32, u64, 32); impl_wide_int!(u64, u128, 64); intrinsics! { - #[use_c_shim_if(/* always if C compilation is enabled */)] + #[maybe_use_optimized_c_shim] #[cfg(any( target_pointer_width = "16", target_pointer_width = "32", diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 376395ac04c..8df58a27b6a 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -84,7 +84,7 @@ trait UMulo: Int { impl UMulo for u128 {} intrinsics! { - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lmul] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { a.mul(b) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 4b63697b425..ad7f67b1b4c 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -58,13 +58,13 @@ impl Divmod for i32 {} impl Divmod for i64 {} intrinsics! { - #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumb_1)))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_idiv] pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { a.div(b) } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 { a.div(b) } @@ -74,15 +74,12 @@ intrinsics! { a.div(b) } - #[use_c_shim_if(all(target_arch = "arm", - not(target_os = "ios"), - not(target_env = "msvc"), - not(thumb_1)))] + #[maybe_use_optimized_c_shim] pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { a.mod_(b) } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] pub extern "C" fn __moddi3(a: i64, b: i64) -> i64 { a.mod_(b) } @@ -92,8 +89,7 @@ intrinsics! { a.mod_(b) } - #[use_c_shim_if(all(target_arch = "arm", not(target_env = "msvc"), - not(target_os = "ios"), not(thumb_1)))] + #[maybe_use_optimized_c_shim] pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { a.divmod(b, rem, |a, b| __divsi3(a, b)) } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 4be588f161d..d98622279e7 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -74,7 +74,7 @@ impl Lshr for u64 {} impl Lshr for u128 {} intrinsics! { - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsl] pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { a.ashl(b) @@ -84,7 +84,7 @@ intrinsics! { a.ashl(b) } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lasr] pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { a.ashr(b) @@ -94,7 +94,7 @@ intrinsics! { a.ashr(b) } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsr] pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { a.lshr(b) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 8837126deef..cdec11d2f16 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -152,9 +152,7 @@ macro_rules! udivmod_inner { } intrinsics! { - #[use_c_shim_if(all(target_arch = "arm", - not(target_os = "ios"), - not(thumb_1)))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_uidiv] /// Returns `n / d` pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { @@ -212,20 +210,14 @@ intrinsics! { (q << 1) | carry } - #[use_c_shim_if(all(target_arch = "arm", - not(target_os = "ios"), - not(target_env = "msvc"), - not(thumb_1)))] + #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { let q = __udivsi3(n, d); n - q * d } - #[use_c_shim_if(all(target_arch = "arm", - not(target_os = "ios"), - not(target_env = "msvc"), - not(thumb_1)))] + #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { let q = __udivsi3(n, d); @@ -235,13 +227,13 @@ intrinsics! { q } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] /// Returns `n / d` pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { __udivmoddi4(n, d, None) } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { let mut rem = 0; diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index e84338fae39..4abdae6eee0 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -30,8 +30,8 @@ /// /// A quick overview of attributes supported right now are: /// -/// * `use_c_shim_if` - takes a #[cfg] directive and falls back to the -/// C-compiled version if `use_c` is specified. +/// * `maybe_use_optimized_c_shim` - indicates that the Rust implementation is +/// ignored if an optimized C version was compiled. /// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and /// the specified ABI everywhere else. /// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the @@ -51,15 +51,14 @@ macro_rules! intrinsics { // to the architecture-specific versions which should be more optimized. The // purpose of this macro is to easily allow specifying this. // - // The argument to `use_c_shim_if` is a `#[cfg]` directive which, when true, - // will cause this crate's exported version of `$name` to just redirect to - // the C implementation. No symbol named `$name` will be in the object file - // for this crate itself. - // - // When the `#[cfg]` directive is false, or when the `c` feature is - // disabled, the provided implementation is used instead. + // The `#[maybe_use_optimized_c_shim]` attribute indicates that this + // intrinsic may have an optimized C version. In these situations the build + // script, if the C code is enabled and compiled, will emit a cfg directive + // to get passed to rustc for our compilation. If that cfg is set we skip + // the Rust implementation, but if the attribute is not enabled then we + // compile in the Rust implementation. ( - #[use_c_shim_if($($cfg_clause:tt)*)] + #[maybe_use_optimized_c_shim] $(#[$($attr:tt)*])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { $($body:tt)* @@ -68,7 +67,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(use_c, $($cfg_clause)*))] + #[cfg($name = "optimized-c")] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { extern $abi { fn $name($($argname: $ty),*) -> $ret; @@ -78,7 +77,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(use_c, $($cfg_clause)*)))] + #[cfg(not($name = "optimized-c"))] intrinsics! { $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { -- cgit 1.4.1-3-g733a5 From e6503aeea766eb94d603bd9f1360f570a833510c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 May 2019 14:47:58 -0700 Subject: Bump to 0.1.14 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f0803743284..5cea06e35ea 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.13" +version = "0.1.14" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From b84b7143e8523e9c3285ee91639b24a0b34bfd17 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 16 May 2019 07:30:36 -0700 Subject: Remove `compiler-rt` submodule from this repository This commit removes the `compiler-rt` submodule from this repository. The goal here is to align the `compiler-rt` used for compiling C intrinsics with the upstream rust-lang/rust's usage of `llvm-project`. Currently we have both an `llvm-project` repository as well as `compiler-rt`, but they can naturally get out of sync and it's just one more submodule to manage. The thinking here is that the feature `c` for this crate, when activated, will require the user to configure where the source code for `compiler-rt` is present. This places the onus on the builder of `compiler-builtins` to check-out and arrange for the appropriate `compiler-rt` source code to be placed somewhere. For rust-lang/rust this is already done with the `llvm-project` submodule, and we can arrange for it to happen on this crate's CI anyway. For users of this crate this is a bit of a bummer, but `c` is disabled by default anyway and it seems unlikely that `c` is explicitly opted in to all that much. (given the purpose of this crate) This should allow us to archive the `compiler-rt` repository and simply use `llvm-project` in the rust-lang/rust repository. --- library/compiler-builtins/.gitmodules | 3 --- library/compiler-builtins/build.rs | 20 ++++++++++++-------- library/compiler-builtins/ci/azure-steps.yml | 12 +++++++----- library/compiler-builtins/ci/run-docker.sh | 1 + library/compiler-builtins/ci/run.sh | 1 - library/compiler-builtins/compiler-rt | 1 - 6 files changed, 20 insertions(+), 18 deletions(-) delete mode 160000 library/compiler-builtins/compiler-rt diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index 50ed51e937b..a71118ff93e 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,6 +1,3 @@ -[submodule "compiler-rt"] - path = compiler-rt - url = https://github.com/rust-lang/compiler-rt [submodule "libm"] path = libm url = https://github.com/rust-lang-nursery/libm diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index be5d42bb76d..c714bc15de3 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -76,7 +76,7 @@ mod c { use std::collections::BTreeMap; use std::env; - use std::path::Path; + use std::path::PathBuf; struct Sources { // SYMBOL -> PATH TO SOURCE @@ -411,15 +411,19 @@ mod c { sources.remove(&["__aeabi_cdcmp", "__aeabi_cfcmp"]); } - // When compiling in rustbuild (the rust-lang/rust repo) this build - // script runs from a directory other than this root directory. - let root = if cfg!(feature = "rustbuild") { - Path::new("../../libcompiler_builtins") - } else { - Path::new(".") + // When compiling the C code we require the user to tell us where the + // source code is, and this is largely done so when we're compiling as + // part of rust-lang/rust we can use the same llvm-project repository as + // rust-lang/rust. + let root = match env::var_os("RUST_COMPILER_RT_ROOT") { + Some(s) => PathBuf::from(s), + None => panic!("RUST_COMPILER_RT_ROOT is not set"), }; + if !root.exists() { + panic!("RUST_COMPILER_RT_ROOT={} does not exist", root.display()); + } - let src_dir = root.join("compiler-rt/lib/builtins"); + let src_dir = root.join("lib/builtins"); for (sym, src) in sources.map.iter() { let src = src_dir.join(src); cfg.file(&src); diff --git a/library/compiler-builtins/ci/azure-steps.yml b/library/compiler-builtins/ci/azure-steps.yml index c8a954024da..f08beca05bf 100644 --- a/library/compiler-builtins/ci/azure-steps.yml +++ b/library/compiler-builtins/ci/azure-steps.yml @@ -4,13 +4,15 @@ steps: - template: azure-install-rust.yml - - script: rustup component add rust-src - displayName: Install Rust sources - condition: eq( variables['XARGO'], '1' ) - - bash: rustup target add $TARGET displayName: Install Rust target - condition: ne( variables['XARGO'], '1' ) + + - bash: | + set -e + curl -L https://github.com/rust-lang/llvm-project/archive/rustc/8.0-2019-03-18.tar.gz | \ + tar xzf - --strip-components 1 llvm-project-rustc-8.0-2019-03-18/compiler-rt + echo '##vso[task.setvariable variable=RUST_COMPILER_RT_ROOT]./compiler-rt' + displayName: "Download compiler-rt reference sources" - bash: ./ci/run.sh $TARGET condition: ne( variables['Agent.OS'], 'Linux' ) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index ddb970c1b4a..dbc86ca54d7 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -18,6 +18,7 @@ run() { --user $(id -u):$(id -g) \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ + -e RUST_COMPILER_RT_ROOT \ -v $HOME/.cargo:/cargo \ -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 4d6d6c68f1f..ae32806ece8 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,6 +1,5 @@ set -ex -export CARGO_INCREMENTAL=0 cargo=cargo # Test our implementation diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt deleted file mode 160000 index 03fc28f9273..00000000000 --- a/library/compiler-builtins/compiler-rt +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 03fc28f9273eeab16f1005f982dfde5900bddb29 -- cgit 1.4.1-3-g733a5 From 9c469738d6ad916f627a29e028f0fc37ff777206 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 16 May 2019 08:12:14 -0700 Subject: Bump to 0.1.15 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 5cea06e35ea..755dcf5e353 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.14" +version = "0.1.15" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From c6b403f5a9db23cae323aa40358d2099de7d0dd1 Mon Sep 17 00:00:00 2001 From: Benjamin Schultzer Date: Thu, 16 May 2019 17:09:33 -0700 Subject: Run musl test in debug mode --- library/compiler-builtins/libm/ci/run.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index d2881130039..42c2416455d 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -6,7 +6,6 @@ TARGET=$1 cargo test --target $TARGET cargo test --target $TARGET --release -# FIXME(#4) overflow checks in non-release currently cause issues -#cargo test --features 'checked musl-reference-tests' --target $TARGET +cargo test --features 'checked musl-reference-tests' --target $TARGET cargo test --features 'checked musl-reference-tests' --target $TARGET --release -- cgit 1.4.1-3-g733a5 From 332d8fd21c071529c89d953511488136ebb93113 Mon Sep 17 00:00:00 2001 From: Benjamin Schultzer Date: Thu, 16 May 2019 23:06:43 -0700 Subject: Add docs --- library/compiler-builtins/libm/src/math/acos.rs | 5 +++++ library/compiler-builtins/libm/src/math/acosf.rs | 5 +++++ library/compiler-builtins/libm/src/math/acosh.rs | 6 +++++- library/compiler-builtins/libm/src/math/acoshf.rs | 6 +++++- library/compiler-builtins/libm/src/math/asin.rs | 5 +++++ library/compiler-builtins/libm/src/math/asinf.rs | 5 +++++ library/compiler-builtins/libm/src/math/asinh.rs | 4 ++++ library/compiler-builtins/libm/src/math/asinhf.rs | 4 ++++ library/compiler-builtins/libm/src/math/atan.rs | 4 ++++ library/compiler-builtins/libm/src/math/atan2.rs | 5 +++++ library/compiler-builtins/libm/src/math/atan2f.rs | 5 +++++ library/compiler-builtins/libm/src/math/atanf.rs | 4 ++++ library/compiler-builtins/libm/src/math/atanh.rs | 4 ++++ library/compiler-builtins/libm/src/math/atanhf.rs | 4 ++++ library/compiler-builtins/libm/src/math/cbrt.rs | 3 +++ library/compiler-builtins/libm/src/math/cbrtf.rs | 3 +++ library/compiler-builtins/libm/src/math/ceil.rs | 3 +++ library/compiler-builtins/libm/src/math/ceilf.rs | 3 +++ library/compiler-builtins/libm/src/math/copysign.rs | 4 ++++ library/compiler-builtins/libm/src/math/copysignf.rs | 4 ++++ library/compiler-builtins/libm/src/math/cosh.rs | 5 +++++ library/compiler-builtins/libm/src/math/coshf.rs | 5 +++++ library/compiler-builtins/libm/src/math/erf.rs | 11 +++++++++++ library/compiler-builtins/libm/src/math/erff.rs | 11 +++++++++++ library/compiler-builtins/libm/src/math/exp.rs | 4 ++++ library/compiler-builtins/libm/src/math/exp2.rs | 4 ++++ library/compiler-builtins/libm/src/math/exp2f.rs | 4 ++++ library/compiler-builtins/libm/src/math/expf.rs | 4 ++++ library/compiler-builtins/libm/src/math/expm1.rs | 7 +++++++ library/compiler-builtins/libm/src/math/expm1f.rs | 7 +++++++ library/compiler-builtins/libm/src/math/fabs.rs | 3 +++ library/compiler-builtins/libm/src/math/fabsf.rs | 3 +++ library/compiler-builtins/libm/src/math/fdim.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/fdimf.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/floor.rs | 3 +++ library/compiler-builtins/libm/src/math/floorf.rs | 3 +++ library/compiler-builtins/libm/src/math/fma.rs | 5 +++++ library/compiler-builtins/libm/src/math/fmaf.rs | 6 ++++++ 38 files changed, 185 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/acos.rs b/library/compiler-builtins/libm/src/math/acos.rs index 055888ffa61..d5e1f6865ad 100644 --- a/library/compiler-builtins/libm/src/math/acos.rs +++ b/library/compiler-builtins/libm/src/math/acos.rs @@ -55,6 +55,11 @@ fn r(z: f64) -> f64 { p / q } +/// Arccosine (f64) +/// +/// Computes the inverse cosine (arc cosine) of the input value. +/// Arguments must be in the range -1 to 1. +/// Returns values in radians, in the range of 0 to pi. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acos(x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index a6061ae8027..d0598e81190 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -29,6 +29,11 @@ fn r(z: f32) -> f32 { p / q } +/// Arccosine (f32) +/// +/// Computes the inverse cosine (arc cosine) of the input value. +/// Arguments must be in the range -1 to 1. +/// Returns values in radians, in the range of 0 to pi. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acosf(x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/acosh.rs b/library/compiler-builtins/libm/src/math/acosh.rs index 95dc57d811c..ac7a5f1c623 100644 --- a/library/compiler-builtins/libm/src/math/acosh.rs +++ b/library/compiler-builtins/libm/src/math/acosh.rs @@ -2,7 +2,11 @@ use super::{log, log1p, sqrt}; const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ -/* acosh(x) = log(x + sqrt(x*x-1)) */ +/// Inverse hyperbolic cosine (f64) +/// +/// Calculates the inverse hyperbolic cosine of `x`. +/// Is defined as `log(x + sqrt(x*x-1))`. +/// `x` must be a number greater than or equal to 1. pub fn acosh(x: f64) -> f64 { let u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/acoshf.rs b/library/compiler-builtins/libm/src/math/acoshf.rs index f50a00324b1..0879e1edb0a 100644 --- a/library/compiler-builtins/libm/src/math/acoshf.rs +++ b/library/compiler-builtins/libm/src/math/acoshf.rs @@ -2,7 +2,11 @@ use super::{log1pf, logf, sqrtf}; const LN2: f32 = 0.693147180559945309417232121458176568; -/* acosh(x) = log(x + sqrt(x*x-1)) */ +/// Inverse hyperbolic cosine (f32) +/// +/// Calculates the inverse hyperbolic cosine of `x`. +/// Is defined as `log(x + sqrt(x*x-1))`. +/// `x` must be a number greater than or equal to 1. pub fn acoshf(x: f32) -> f32 { let u = x.to_bits(); let a = u & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs index 2aee72b2861..774475e5195 100644 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -62,6 +62,11 @@ fn comp_r(z: f64) -> f64 { p / q } +/// Arcsine (f64) +/// +/// Computes the inverse sine (arc sine) of the argument `x`. +/// Arguments to asin must be in the range -1 to 1. +/// Returns values in radians, in the range of -pi/2 to pi/2. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asin(mut x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index 979f1a6548f..ce0f4a997e7 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -31,6 +31,11 @@ fn r(z: f32) -> f32 { p / q } +/// Arcsine (f32) +/// +/// Computes the inverse sine (arc sine) of the argument `x`. +/// Arguments to asin must be in the range -1 to 1. +/// Returns values in radians, in the range of -pi/2 to pi/2. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asinf(mut x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/asinh.rs b/library/compiler-builtins/libm/src/math/asinh.rs index b29093b2347..14295357a55 100644 --- a/library/compiler-builtins/libm/src/math/asinh.rs +++ b/library/compiler-builtins/libm/src/math/asinh.rs @@ -3,6 +3,10 @@ use super::{log, log1p, sqrt}; const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ /* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +/// Inverse hyperbolic sine (f64) +/// +/// Calculates the inverse hyperbolic sine of `x`. +/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. pub fn asinh(mut x: f64) -> f64 { let mut u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/src/math/asinhf.rs index 9812433032b..e22a291323f 100644 --- a/library/compiler-builtins/libm/src/math/asinhf.rs +++ b/library/compiler-builtins/libm/src/math/asinhf.rs @@ -3,6 +3,10 @@ use super::{log1pf, logf, sqrtf}; const LN2: f32 = 0.693147180559945309417232121458176568; /* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +/// Inverse hyperbolic sine (f32) +/// +/// Calculates the inverse hyperbolic sine of `x`. +/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. pub fn asinhf(mut x: f32) -> f32 { let u = x.to_bits(); let i = u & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index 94594080cb8..d2684ece8e9 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -60,6 +60,10 @@ const AT: [f64; 11] = [ 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ ]; +/// Arctangent (f64) +/// +/// Computes the inverse tangent (arc tangent) of the input value. +/// Returns a value in radians, in the range of -pi/2 to pi/2. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan(x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index 313bec4b907..08385cd100e 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -43,6 +43,11 @@ use super::fabs; const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ +/// Arctangent of y/x (f64) +/// +/// Computes the inverse tangent (arc tangent) of `y/x`. +/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). +/// Returns a value in radians, in the range of -pi to pi. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan2(y: f64, x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs index 94e3c771867..7bbe5f1d47a 100644 --- a/library/compiler-builtins/libm/src/math/atan2f.rs +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -19,6 +19,11 @@ use super::fabsf; const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ +/// Arctangent of y/x (f32) +/// +/// Computes the inverse tangent (arc tangent) of `y/x`. +/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). +/// Returns a value in radians, in the range of -pi to pi. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan2f(y: f32, x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index 89b0afd6fb0..363e11d647d 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -37,6 +37,10 @@ const A_T: [f32; 5] = [ 6.1687607318e-02, ]; +/// Arctangent (f32) +/// +/// Computes the inverse tangent (arc tangent) of the input value. +/// Returns a value in radians, in the range of -pi/2 to pi/2. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atanf(mut x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/atanh.rs b/library/compiler-builtins/libm/src/math/atanh.rs index 2833715ab92..79a989c42d1 100644 --- a/library/compiler-builtins/libm/src/math/atanh.rs +++ b/library/compiler-builtins/libm/src/math/atanh.rs @@ -1,6 +1,10 @@ use super::log1p; /* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +/// Inverse hyperbolic tangent (f64) +/// +/// Calculates the inverse hyperbolic tangent of `x`. +/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. pub fn atanh(x: f64) -> f64 { let u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs index 709a9555182..7b2f34d97d4 100644 --- a/library/compiler-builtins/libm/src/math/atanhf.rs +++ b/library/compiler-builtins/libm/src/math/atanhf.rs @@ -1,6 +1,10 @@ use super::log1pf; /* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +/// Inverse hyperbolic tangent (f32) +/// +/// Calculates the inverse hyperbolic tangent of `x`. +/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. pub fn atanhf(mut x: f32) -> f32 { let mut u = x.to_bits(); let sign = (u >> 31) != 0; diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index ab11c497e12..04469b1598f 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -27,6 +27,9 @@ const P2: f64 = 1.621429720105354466140; /* 0x3ff9f160, 0x4a49d6c2 */ const P3: f64 = -0.758397934778766047437; /* 0xbfe844cb, 0xbee751d9 */ const P4: f64 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ +// Cube root (f64) +/// +/// Computes the cube root of the argument. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrt(x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/cbrtf.rs b/library/compiler-builtins/libm/src/math/cbrtf.rs index 19215b8587b..6e589c0994d 100644 --- a/library/compiler-builtins/libm/src/math/cbrtf.rs +++ b/library/compiler-builtins/libm/src/math/cbrtf.rs @@ -22,6 +22,9 @@ use core::f32; const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ +/// Cube root (f32) +/// +/// Computes the cube root of the argument. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrtf(x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index d337db200bf..59883a8a7b9 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -2,6 +2,9 @@ use core::f64; const TOINT: f64 = 1. / f64::EPSILON; +/// Ceil (f64) +/// +/// Finds the nearest integer greater than or equal to `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceil(x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 0be53c5cf3c..151a4f21042 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -1,5 +1,8 @@ use core::f32; +/// Ceil (f32) +/// +/// Finds the nearest integer greater than or equal to `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceilf(x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs index 9c5362a5a47..1527fb6ea8b 100644 --- a/library/compiler-builtins/libm/src/math/copysign.rs +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -1,3 +1,7 @@ +/// Sign of Y, magnitude of X (f64) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. pub fn copysign(x: f64, y: f64) -> f64 { let mut ux = x.to_bits(); let uy = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs index b42fd39ad55..35148561a86 100644 --- a/library/compiler-builtins/libm/src/math/copysignf.rs +++ b/library/compiler-builtins/libm/src/math/copysignf.rs @@ -1,3 +1,7 @@ +/// Sign of Y, magnitude of X (f32) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. pub fn copysignf(x: f32, y: f32) -> f32 { let mut ux = x.to_bits(); let uy = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs index b6ba338b55f..bac87556685 100644 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -2,6 +2,11 @@ use super::exp; use super::expm1; use super::k_expo2; +/// Hyperbolic cosine (f64) +/// +/// Computes the hyperbolic cosine of the argument x. +/// Is defined as `(exp(x) + exp(-x))/2` +/// Angles are specified in radians. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cosh(mut x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/coshf.rs b/library/compiler-builtins/libm/src/math/coshf.rs index b37ee1f3271..bf99e42f09b 100644 --- a/library/compiler-builtins/libm/src/math/coshf.rs +++ b/library/compiler-builtins/libm/src/math/coshf.rs @@ -2,6 +2,11 @@ use super::expf; use super::expm1f; use super::k_expo2f; +/// Hyperbolic cosine (f64) +/// +/// Computes the hyperbolic cosine of the argument x. +/// Is defined as `(exp(x) + exp(-x))/2` +/// Angles are specified in radians. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn coshf(mut x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs index d53a4c83cd5..a2c617d341d 100644 --- a/library/compiler-builtins/libm/src/math/erf.rs +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -214,6 +214,11 @@ fn erfc2(ix: u32, mut x: f64) -> f64 { exp(-z * z - 0.5625) * exp((z - x) * (z + x) + r / big_s) / x } +/// Error function (f64) +/// +/// Calculates an approximation to the “error function”, which estimates +/// the probability that an observation will fall within x standard +/// deviations of the mean (assuming a normal distribution). pub fn erf(x: f64) -> f64 { let r: f64; let s: f64; @@ -257,6 +262,12 @@ pub fn erf(x: f64) -> f64 { } } +/// Error function (f64) +/// +/// Calculates the complementary probability. +/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid +/// the loss of precision that would result from subtracting +/// large probabilities (on large `x`) from 1. pub fn erfc(x: f64) -> f64 { let r: f64; let s: f64; diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs index ef67c335b0c..384052293fe 100644 --- a/library/compiler-builtins/libm/src/math/erff.rs +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -125,6 +125,11 @@ fn erfc2(mut ix: u32, mut x: f32) -> f32 { expf(-z * z - 0.5625) * expf((z - x) * (z + x) + r / big_s) / x } +/// Error function (f32) +/// +/// Calculates an approximation to the “error function”, which estimates +/// the probability that an observation will fall within x standard +/// deviations of the mean (assuming a normal distribution). pub fn erff(x: f32) -> f32 { let r: f32; let s: f32; @@ -168,6 +173,12 @@ pub fn erff(x: f32) -> f32 { } } +/// Error function (f32) +/// +/// Calculates the complementary probability. +/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid +/// the loss of precision that would result from subtracting +/// large probabilities (on large `x`) from 1. pub fn erfcf(x: f32) -> f32 { let r: f32; let s: f32; diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs index c3277318679..5465b569346 100644 --- a/library/compiler-builtins/libm/src/math/exp.rs +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -77,6 +77,10 @@ const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ +/// Exponential, base *e* (f64) +/// +/// Calculate the exponential of `x`, that is, *e* raised to the power `x` +/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp(mut x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index be6a003c6ee..570ca315b09 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -318,6 +318,10 @@ static TBL: [u64; TBLSIZE * 2] = [ // // Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library // for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + +/// Exponential, base 2 (f64) +/// +/// Calculate `2^x`, that is, 2 raised to the power `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp2(mut x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index 32816104b5c..12c9e76a4c7 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -69,6 +69,10 @@ static EXP2FT: [u64; TBLSIZE] = [ // // Tang, P. Table-driven Implementation of the Exponential Function // in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). + +/// Exponential, base 2 (f32) +/// +/// Calculate `2^x`, that is, 2 raised to the power `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp2f(mut x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index baade2552e1..09323ec8de2 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -26,6 +26,10 @@ const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ const P1: f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ +/// Exponential, base *e* (f32) +/// +/// Calculate the exponential of `x`, that is, *e* raised to the power `x` +/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expf(mut x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs index 42616399066..0d43b4e103d 100644 --- a/library/compiler-builtins/libm/src/math/expm1.rs +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -23,6 +23,13 @@ const Q3: f64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ +/// Exponential, base *e*, of x-1 (f64) +/// +/// Calculates the exponential of `x` and subtract 1, that is, *e* raised +/// to the power `x` minus 1 (where *e* is the base of the natural +/// system of logarithms, approximately 2.71828). +/// The result is accurate even for small values of `x`, +/// where using `exp(x)-1` would lose many significant digits. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expm1(mut x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs index 4daa83c8565..9bb22344889 100644 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -25,6 +25,13 @@ const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ const Q1: f32 = -3.3333212137e-2; /* -0x888868.0p-28 */ const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ +/// Exponential, base *e*, of x-1 (f32) +/// +/// Calculates the exponential of `x` and subtract 1, that is, *e* raised +/// to the power `x` minus 1 (where *e* is the base of the natural +/// system of logarithms, approximately 2.71828). +/// The result is accurate even for small values of `x`, +/// where using `exp(x)-1` would lose many significant digits. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expm1f(mut x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 0824bd59358..52a9adcbff1 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -1,5 +1,8 @@ use core::u64; +/// Absolute value (magnitude) (f64) +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabs(x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 859508f9b53..5942d983a4b 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -1,3 +1,6 @@ +/// Absolute value (magnitude) (f32) +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabsf(x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index d9aca861158..06edc996035 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -1,5 +1,13 @@ use core::f64; +/// Positive difference (f64) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdim(x: f64, y: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index bcda8ee94f9..f1ad5896bf9 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -1,5 +1,13 @@ use core::f32; +/// Positive difference (f32) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdimf(x: f32, y: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index c705ae501a9..f6068c697ac 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -2,6 +2,9 @@ use core::f64; const TOINT: f64 = 1. / f64::EPSILON; +/// Floor (f64) +/// +/// Finds the nearest integer less than or equal to `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floor(x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 899dcf5a512..ae605e1918f 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -1,5 +1,8 @@ use core::f32; +/// Floor (f64) +/// +/// Finds the nearest integer less than or equal to `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floorf(x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 6b062481dca..07d90f8b727 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -48,6 +48,11 @@ fn mul(x: u64, y: u64) -> (u64, u64) { (hi, lo) } +/// Floating multiply add (f64) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation: +/// Computes the value (as if) to infinite precision and rounds once to the result format, +/// according to the rounding mode characterized by the value of FLT_ROUNDS. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fma(x: f64, y: f64, z: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index 9e5a55f44b6..e77e0fa4a25 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -40,6 +40,12 @@ use super::fenv::{ * direct double-precision arithmetic suffices, except where double * rounding occurs. */ + +/// Floating multiply add (f32) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation: +/// Computes the value (as if) to infinite precision and rounds once to the result format, +/// according to the rounding mode characterized by the value of FLT_ROUNDS. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { -- cgit 1.4.1-3-g733a5 From 3b18638b987b82221c5c6d6a466caa09883aefd1 Mon Sep 17 00:00:00 2001 From: Sean Leather Date: Tue, 21 May 2019 08:43:50 +0200 Subject: Fix typo: mingw_unwinding --- library/compiler-builtins/examples/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 3debffa450a..f6980fcb566 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -399,7 +399,7 @@ pub fn _Unwind_Resume() {} pub extern "C" fn eh_personality() {} #[cfg(all(windows, target_env = "gnu"))] -mod mingw_unwidning { +mod mingw_unwinding { #[no_mangle] pub fn rust_eh_personality() {} #[no_mangle] -- cgit 1.4.1-3-g733a5 From 5c48fccd6c2533772c88fb33564aebc6df35031e Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 3 Jun 2019 13:16:03 +0300 Subject: fixed add overflow in exp2 --- library/compiler-builtins/libm/src/math/exp2.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index 570ca315b09..c2192fde5a0 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -373,7 +373,7 @@ pub fn exp2(mut x: f64) -> f64 { /* Reduce x, computing z, i0, and k. */ let ui = f64::to_bits(x + redux); let mut i0 = ui as u32; - i0 += TBLSIZE as u32 / 2; + i0 = i0.wrapping_add(TBLSIZE as u32 / 2); let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32; let ki = ku as i32 / TBLSIZE as i32; i0 %= TBLSIZE as u32; @@ -387,3 +387,9 @@ pub fn exp2(mut x: f64) -> f64 { scalbn(r, ki) } + +#[test] +fn i0_wrap_test() { + let x = -3.0 / 256.0; + assert_eq!(exp2(x), f64::from_bits(0x3fefbdba3692d514)); +} -- cgit 1.4.1-3-g733a5 From 13a350ca5df471f717107a0fe500ea547a471636 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Jun 2019 12:14:53 -0700 Subject: Attempt to fix CI --- library/compiler-builtins/libm/ci/azure-install-rust.yml | 14 ++++++++------ library/compiler-builtins/libm/ci/run-docker.sh | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/ci/azure-install-rust.yml b/library/compiler-builtins/libm/ci/azure-install-rust.yml index fa7eae459b7..c5a53122f8e 100644 --- a/library/compiler-builtins/libm/ci/azure-install-rust.yml +++ b/library/compiler-builtins/libm/ci/azure-install-rust.yml @@ -5,15 +5,17 @@ steps: if [ "$toolchain" = "" ]; then toolchain=stable fi - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain - echo "##vso[task.prependpath]$HOME/.cargo/bin" + if command -v rustup; then + rustup update $toolchain + rustup default $toolchain + else + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain + echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + fi displayName: Install rust (unix) condition: ne( variables['Agent.OS'], 'Windows_NT' ) - - script: | - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe -y --default-toolchain stable-%TARGET% - echo ##vso[task.prependpath]%USERPROFILE%\.cargo\bin + - bash: rustup update stable-$TOOLCHAIN && rustup default stable-$TOOLCHAIN displayName: Install rust (windows) condition: eq( variables['Agent.OS'], 'Windows_NT' ) diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index 95bd3db4836..e7b80c719e5 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -18,7 +18,7 @@ run() { --user $(id -u):$(id -g) \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ - -v $HOME/.cargo:/cargo \ + -v $(dirname $(dirname `which cargo`)):/cargo \ -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ -v `rustc --print sysroot`:/rust:ro \ -- cgit 1.4.1-3-g733a5 From f1c957e83237864e1f9c21c9fbebedd24ad54845 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 5 Jun 2019 17:43:46 +0100 Subject: Add minf --- library/compiler-builtins/libm/CHANGELOG.md | 4 ++++ library/compiler-builtins/libm/src/lib.rs | 7 +++++++ library/compiler-builtins/libm/src/math/minf.rs | 13 +++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 ++ 4 files changed, 26 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/minf.rs diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 1cc396455f3..f8d4e98f043 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added + +- minf + ## [v0.1.2] - 2018-07-18 ### Added diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0d0f6155abe..763920cc543 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -136,6 +136,8 @@ pub trait F32Ext: private::Sealed + Sized { fn acosh(self) -> Self; fn atanh(self) -> Self; + + fn min(self, other: Self) -> Self; } impl F32Ext for f32 { @@ -327,6 +329,11 @@ impl F32Ext for f32 { fn atanh(self) -> Self { atanhf(self) } + + #[inline] + fn min(self, other: Self) -> Self { + minf(self, other) + } } /// Math support for `f64` diff --git a/library/compiler-builtins/libm/src/math/minf.rs b/library/compiler-builtins/libm/src/math/minf.rs new file mode 100644 index 00000000000..2098a2d75c0 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/minf.rs @@ -0,0 +1,13 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn minf(x: f32, y: f32) -> f32 { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if y.is_nan() || x < y { x } else { y }) * 1.0 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c4d24741469..90c5fd311a7 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -166,6 +166,7 @@ mod tgamma; mod tgammaf; mod trunc; mod truncf; +mod minf; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; @@ -272,6 +273,7 @@ pub use self::tgamma::tgamma; pub use self::tgammaf::tgammaf; pub use self::trunc::trunc; pub use self::truncf::truncf; +pub use self::minf::minf; // Private modules mod expo2; -- cgit 1.4.1-3-g733a5 From 193e7960f9fc9c76690fe0cb536fe67758e48e67 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 5 Jun 2019 17:44:06 +0100 Subject: Add min --- library/compiler-builtins/libm/CHANGELOG.md | 1 + library/compiler-builtins/libm/src/lib.rs | 7 +++++++ library/compiler-builtins/libm/src/math/min.rs | 13 +++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 ++ 4 files changed, 23 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/min.rs diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index f8d4e98f043..4ecd8c8ab76 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - minf +- min ## [v0.1.2] - 2018-07-18 diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 763920cc543..b72b58c1f44 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -417,6 +417,8 @@ pub trait F64Ext: private::Sealed + Sized { fn acosh(self) -> Self; fn atanh(self) -> Self; + + fn min(self, other: Self) -> Self; } impl F64Ext for f64 { @@ -608,6 +610,11 @@ impl F64Ext for f64 { fn atanh(self) -> Self { atanh(self) } + + #[inline] + fn min(self, other: Self) -> Self { + min(self, other) + } } mod private { diff --git a/library/compiler-builtins/libm/src/math/min.rs b/library/compiler-builtins/libm/src/math/min.rs new file mode 100644 index 00000000000..d0345cf8d4d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/min.rs @@ -0,0 +1,13 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn min(x: f64, y: f64) -> f64 { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if y.is_nan() || x < y { x } else { y }) * 1.0 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 90c5fd311a7..e2d706201d9 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -166,6 +166,7 @@ mod tgamma; mod tgammaf; mod trunc; mod truncf; +mod min; mod minf; // Use separated imports instead of {}-grouped imports for easier merging. @@ -273,6 +274,7 @@ pub use self::tgamma::tgamma; pub use self::tgammaf::tgammaf; pub use self::trunc::trunc; pub use self::truncf::truncf; +pub use self::min::min; pub use self::minf::minf; // Private modules -- cgit 1.4.1-3-g733a5 From a3c8111c5f895f8dc09884edaea915430792a346 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 5 Jun 2019 17:44:20 +0100 Subject: Add maxf --- library/compiler-builtins/libm/CHANGELOG.md | 1 + library/compiler-builtins/libm/src/lib.rs | 7 +++++++ library/compiler-builtins/libm/src/math/maxf.rs | 13 +++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 ++ 4 files changed, 23 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/maxf.rs diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 4ecd8c8ab76..7fb17cc9fbf 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - minf - min +- maxf ## [v0.1.2] - 2018-07-18 diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index b72b58c1f44..368e25c8cfa 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -138,6 +138,8 @@ pub trait F32Ext: private::Sealed + Sized { fn atanh(self) -> Self; fn min(self, other: Self) -> Self; + + fn max(self, other: Self) -> Self; } impl F32Ext for f32 { @@ -334,6 +336,11 @@ impl F32Ext for f32 { fn min(self, other: Self) -> Self { minf(self, other) } + + #[inline] + fn max(self, other: Self) -> Self { + maxf(self, other) + } } /// Math support for `f64` diff --git a/library/compiler-builtins/libm/src/math/maxf.rs b/library/compiler-builtins/libm/src/math/maxf.rs new file mode 100644 index 00000000000..ac0d22aa5f9 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/maxf.rs @@ -0,0 +1,13 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn maxf(x: f32, y: f32) -> f32 { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x.is_nan() || x < y { y } else { x }) * 1.0 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e2d706201d9..9feadce7d1a 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -168,6 +168,7 @@ mod trunc; mod truncf; mod min; mod minf; +mod maxf; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; @@ -276,6 +277,7 @@ pub use self::trunc::trunc; pub use self::truncf::truncf; pub use self::min::min; pub use self::minf::minf; +pub use self::maxf::maxf; // Private modules mod expo2; -- cgit 1.4.1-3-g733a5 From 2db94e02d8571adb956af807e4eae2e6b54f0963 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 5 Jun 2019 17:44:24 +0100 Subject: Add max --- library/compiler-builtins/libm/CHANGELOG.md | 1 + library/compiler-builtins/libm/src/lib.rs | 7 +++++++ library/compiler-builtins/libm/src/math/max.rs | 13 +++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 ++ 4 files changed, 23 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/max.rs diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 7fb17cc9fbf..d7667c0a116 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - minf - min - maxf +- max ## [v0.1.2] - 2018-07-18 diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 368e25c8cfa..f77cda94bdf 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -426,6 +426,8 @@ pub trait F64Ext: private::Sealed + Sized { fn atanh(self) -> Self; fn min(self, other: Self) -> Self; + + fn max(self, other: Self) -> Self; } impl F64Ext for f64 { @@ -622,6 +624,11 @@ impl F64Ext for f64 { fn min(self, other: Self) -> Self { min(self, other) } + + #[inline] + fn max(self, other: Self) -> Self { + max(self, other) + } } mod private { diff --git a/library/compiler-builtins/libm/src/math/max.rs b/library/compiler-builtins/libm/src/math/max.rs new file mode 100644 index 00000000000..3fbb480249a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/max.rs @@ -0,0 +1,13 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn max(x: f64, y: f64) -> f64 { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x.is_nan() || x < y { y } else { x }) * 1.0 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 9feadce7d1a..c2bc9a4750f 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -168,6 +168,7 @@ mod trunc; mod truncf; mod min; mod minf; +mod max; mod maxf; // Use separated imports instead of {}-grouped imports for easier merging. @@ -277,6 +278,7 @@ pub use self::trunc::trunc; pub use self::truncf::truncf; pub use self::min::min; pub use self::minf::minf; +pub use self::max::max; pub use self::maxf::maxf; // Private modules -- cgit 1.4.1-3-g733a5 From 1613fbc4121bd4a19914089f779010e0795917bf Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 5 Jun 2019 20:59:05 +0100 Subject: Alphabetise --- library/compiler-builtins/libm/src/math/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c2bc9a4750f..bedc3a69e5b 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -140,6 +140,10 @@ mod log1pf; mod log2; mod log2f; mod logf; +mod max; +mod maxf; +mod min; +mod minf; mod modf; mod modff; mod pow; @@ -166,10 +170,6 @@ mod tgamma; mod tgammaf; mod trunc; mod truncf; -mod min; -mod minf; -mod max; -mod maxf; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; @@ -250,6 +250,10 @@ pub use self::log1pf::log1pf; pub use self::log2::log2; pub use self::log2f::log2f; pub use self::logf::logf; +pub use self::max::max; +pub use self::maxf::maxf; +pub use self::min::min; +pub use self::minf::minf; pub use self::modf::modf; pub use self::modff::modff; pub use self::pow::pow; @@ -276,10 +280,6 @@ pub use self::tgamma::tgamma; pub use self::tgammaf::tgammaf; pub use self::trunc::trunc; pub use self::truncf::truncf; -pub use self::min::min; -pub use self::minf::minf; -pub use self::max::max; -pub use self::maxf::maxf; // Private modules mod expo2; -- cgit 1.4.1-3-g733a5 From 727722531e56206b1804937480bef563482d6c55 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 5 Jun 2019 21:13:25 +0100 Subject: Correct libm names --- library/compiler-builtins/libm/CHANGELOG.md | 6 +++--- library/compiler-builtins/libm/src/lib.rs | 8 ++++---- library/compiler-builtins/libm/src/math/fmax.rs | 13 +++++++++++++ library/compiler-builtins/libm/src/math/fmaxf.rs | 13 +++++++++++++ library/compiler-builtins/libm/src/math/fmin.rs | 13 +++++++++++++ library/compiler-builtins/libm/src/math/fminf.rs | 13 +++++++++++++ library/compiler-builtins/libm/src/math/max.rs | 13 ------------- library/compiler-builtins/libm/src/math/maxf.rs | 13 ------------- library/compiler-builtins/libm/src/math/min.rs | 13 ------------- library/compiler-builtins/libm/src/math/minf.rs | 13 ------------- library/compiler-builtins/libm/src/math/mod.rs | 16 ++++++++-------- 11 files changed, 67 insertions(+), 67 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fmax.rs create mode 100644 library/compiler-builtins/libm/src/math/fmaxf.rs create mode 100644 library/compiler-builtins/libm/src/math/fmin.rs create mode 100644 library/compiler-builtins/libm/src/math/fminf.rs delete mode 100644 library/compiler-builtins/libm/src/math/max.rs delete mode 100644 library/compiler-builtins/libm/src/math/maxf.rs delete mode 100644 library/compiler-builtins/libm/src/math/min.rs delete mode 100644 library/compiler-builtins/libm/src/math/minf.rs diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index d7667c0a116..62bfd0d5b94 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -8,9 +8,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - minf -- min -- maxf -- max +- fmin +- fmaxf +- fmax ## [v0.1.2] - 2018-07-18 diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index f77cda94bdf..df3c8cf601a 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -334,12 +334,12 @@ impl F32Ext for f32 { #[inline] fn min(self, other: Self) -> Self { - minf(self, other) + fminf(self, other) } #[inline] fn max(self, other: Self) -> Self { - maxf(self, other) + fmaxf(self, other) } } @@ -622,12 +622,12 @@ impl F64Ext for f64 { #[inline] fn min(self, other: Self) -> Self { - min(self, other) + fmin(self, other) } #[inline] fn max(self, other: Self) -> Self { - max(self, other) + fmax(self, other) } } diff --git a/library/compiler-builtins/libm/src/math/fmax.rs b/library/compiler-builtins/libm/src/math/fmax.rs new file mode 100644 index 00000000000..22016d11cc6 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmax.rs @@ -0,0 +1,13 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmax(x: f64, y: f64) -> f64 { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x.is_nan() || x < y { y } else { x }) * 1.0 +} diff --git a/library/compiler-builtins/libm/src/math/fmaxf.rs b/library/compiler-builtins/libm/src/math/fmaxf.rs new file mode 100644 index 00000000000..a883fdaef5b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmaxf.rs @@ -0,0 +1,13 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf(x: f32, y: f32) -> f32 { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x.is_nan() || x < y { y } else { x }) * 1.0 +} diff --git a/library/compiler-builtins/libm/src/math/fmin.rs b/library/compiler-builtins/libm/src/math/fmin.rs new file mode 100644 index 00000000000..d1ccc3a4680 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmin.rs @@ -0,0 +1,13 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmin(x: f64, y: f64) -> f64 { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if y.is_nan() || x < y { x } else { y }) * 1.0 +} diff --git a/library/compiler-builtins/libm/src/math/fminf.rs b/library/compiler-builtins/libm/src/math/fminf.rs new file mode 100644 index 00000000000..43ec97cb5b5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fminf.rs @@ -0,0 +1,13 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf(x: f32, y: f32) -> f32 { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if y.is_nan() || x < y { x } else { y }) * 1.0 +} diff --git a/library/compiler-builtins/libm/src/math/max.rs b/library/compiler-builtins/libm/src/math/max.rs deleted file mode 100644 index 3fbb480249a..00000000000 --- a/library/compiler-builtins/libm/src/math/max.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[inline] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn max(x: f64, y: f64) -> f64 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if x.is_nan() || x < y { y } else { x }) * 1.0 -} diff --git a/library/compiler-builtins/libm/src/math/maxf.rs b/library/compiler-builtins/libm/src/math/maxf.rs deleted file mode 100644 index ac0d22aa5f9..00000000000 --- a/library/compiler-builtins/libm/src/math/maxf.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[inline] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn maxf(x: f32, y: f32) -> f32 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if x.is_nan() || x < y { y } else { x }) * 1.0 -} diff --git a/library/compiler-builtins/libm/src/math/min.rs b/library/compiler-builtins/libm/src/math/min.rs deleted file mode 100644 index d0345cf8d4d..00000000000 --- a/library/compiler-builtins/libm/src/math/min.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[inline] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn min(x: f64, y: f64) -> f64 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if y.is_nan() || x < y { x } else { y }) * 1.0 -} diff --git a/library/compiler-builtins/libm/src/math/minf.rs b/library/compiler-builtins/libm/src/math/minf.rs deleted file mode 100644 index 2098a2d75c0..00000000000 --- a/library/compiler-builtins/libm/src/math/minf.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[inline] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn minf(x: f32, y: f32) -> f32 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if y.is_nan() || x < y { x } else { y }) * 1.0 -} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index bedc3a69e5b..35ffe1a2cb2 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -112,6 +112,10 @@ mod floor; mod floorf; mod fma; mod fmaf; +mod fmax; +mod fmaxf; +mod fmin; +mod fminf; mod fmod; mod fmodf; mod frexp; @@ -140,10 +144,6 @@ mod log1pf; mod log2; mod log2f; mod logf; -mod max; -mod maxf; -mod min; -mod minf; mod modf; mod modff; mod pow; @@ -216,6 +216,10 @@ pub use self::floor::floor; pub use self::floorf::floorf; pub use self::fma::fma; pub use self::fmaf::fmaf; +pub use self::fmax::fmax; +pub use self::fmaxf::fmaxf; +pub use self::fmin::fmin; +pub use self::fminf::fminf; pub use self::fmod::fmod; pub use self::fmodf::fmodf; pub use self::frexp::frexp; @@ -250,10 +254,6 @@ pub use self::log1pf::log1pf; pub use self::log2::log2; pub use self::log2f::log2f; pub use self::logf::logf; -pub use self::max::max; -pub use self::maxf::maxf; -pub use self::min::min; -pub use self::minf::minf; pub use self::modf::modf; pub use self::modff::modff; pub use self::pow::pow; -- cgit 1.4.1-3-g733a5 From 3fe09ab411fafd90ef5b2e1504c4bf33742d7874 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 5 Jun 2019 21:32:31 +0100 Subject: Update libm for fmin/fmax/fminf/fmaxf --- library/compiler-builtins/libm | 2 +- library/compiler-builtins/src/math.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 0ae442888c7..01bee72a93e 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 0ae442888c7af72c0a335edd43dbbd74c751f119 +Subproject commit 01bee72a93ebaeea2883d0f963174c2b00d4fe68 diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 1893f1c166b..4b27cb80f68 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -45,6 +45,10 @@ no_mangle! { fn log10f(x: f32) -> f32; fn log(x: f64) -> f64; fn logf(x: f32) -> f32; + fn fmin(x: f64, y: f64) -> f64; + fn fminf(x: f32, y: f32) -> f32; + fn fmax(x: f64, y: f64) -> f64; + fn fmaxf(x: f32, y: f32) -> f32; fn round(x: f64) -> f64; fn roundf(x: f32) -> f32; fn sin(x: f64) -> f64; -- cgit 1.4.1-3-g733a5 From 0d83008f7ac55d854d9ff2fac8a03c7bd42915d0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Jun 2019 16:09:27 -0700 Subject: Attempt to fix CI --- library/compiler-builtins/ci/azure-install-rust.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/ci/azure-install-rust.yml b/library/compiler-builtins/ci/azure-install-rust.yml index f44f8c59dc6..d0255f85b27 100644 --- a/library/compiler-builtins/ci/azure-install-rust.yml +++ b/library/compiler-builtins/ci/azure-install-rust.yml @@ -4,17 +4,21 @@ parameters: steps: - bash: | set -e - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TOOLCHAIN - echo "##vso[task.prependpath]$HOME/.cargo/bin" + if command -v rustup; then + rustup update $TOOLCHAIN + rustup default $TOOLCHAIN + else + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TOOLCHAIN + echo "##vso[task.prependpath]$HOME/.cargo/bin" + fi displayName: Install rust condition: ne( variables['Agent.OS'], 'Windows_NT' ) env: TOOLCHAIN: ${{ parameters.toolchain }} - script: | - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe -y --default-toolchain %TOOLCHAIN%-%TARGET% - echo ##vso[task.prependpath]%USERPROFILE%\.cargo\bin + rustup update --no-self-update %TOOLCHAIN%-%TARGET% + rustup default %TOOLCHAIN%-%TARGET% displayName: Install rust condition: eq( variables['Agent.OS'], 'Windows_NT' ) env: -- cgit 1.4.1-3-g733a5 From 22030968eb31afd7acf0a3916d38e66b73577420 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Jun 2019 16:19:26 -0700 Subject: More fixes for CI --- library/compiler-builtins/ci/run-docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index dbc86ca54d7..4bb2a78d934 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -19,7 +19,7 @@ run() { -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ -e RUST_COMPILER_RT_ROOT \ - -v $HOME/.cargo:/cargo \ + -v $(dirname $(dirname `which cargo`)):/cargo \ -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ -v `rustc --print sysroot`:/rust:ro \ -- cgit 1.4.1-3-g733a5 From 319ae3ab428c0e6920ecd45315450385354ba549 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 6 Jun 2019 01:09:47 +0100 Subject: Bump to 0.1.16 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 755dcf5e353..e0bb22d218a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.15" +version = "0.1.16" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From c955dbe5d03779eddaa127a3d64d123587957d01 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Fri, 7 Jun 2019 18:23:43 +0200 Subject: Make module path compatible with Rust 1.31.0 --- library/compiler-builtins/libm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index df3c8cf601a..a47883d81bb 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -20,7 +20,7 @@ mod math; use core::{f32, f64}; -pub use math::*; +pub use self::math::*; /// Approximate equality with 1 ULP of tolerance #[doc(hidden)] -- cgit 1.4.1-3-g733a5 From 9df2e2151ce8c956109d4a8bd54891bbe245bf7d Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 12 Jun 2019 18:43:12 +0200 Subject: Add 0.1.3 changelog entry --- library/compiler-builtins/libm/CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 62bfd0d5b94..aef65cfb3c8 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +... + +## [v0.1.3] - 2019-05-14 + ### Added - minf @@ -81,6 +85,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Initial release -[Unreleased]: https://github.com/japaric/libm/compare/v0.1.2...HEAD +[Unreleased]: https://github.com/japaric/libm/compare/0.1.3...HEAD +[v0.1.3]: https://github.com/japaric/libm/compare/v0.1.2...0.1.3 [v0.1.2]: https://github.com/japaric/libm/compare/v0.1.1...v0.1.2 [v0.1.1]: https://github.com/japaric/libm/compare/v0.1.0...v0.1.1 -- cgit 1.4.1-3-g733a5 From 1319dfac2cae4b4ae7de4b681faa7b1b8d5e0786 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 12 Jun 2019 18:45:42 +0200 Subject: Add changelog entry for v0.1.4 release --- library/compiler-builtins/libm/CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index aef65cfb3c8..28e27055dfd 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -7,6 +7,11 @@ This project adheres to [Semantic Versioning](http://semver.org/). ... +## [v0.1.4] - 2019-06-12 + +### Fixed +- Restored compatibility with Rust 1.31.0 + ## [v0.1.3] - 2019-05-14 ### Added @@ -85,7 +90,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Initial release -[Unreleased]: https://github.com/japaric/libm/compare/0.1.3...HEAD +[Unreleased]: https://github.com/japaric/libm/compare/v0.1.4...HEAD +[v0.1.4]: https://github.com/japaric/libm/compare/0.1.3...v0.1.4 [v0.1.3]: https://github.com/japaric/libm/compare/v0.1.2...0.1.3 [v0.1.2]: https://github.com/japaric/libm/compare/v0.1.1...v0.1.2 [v0.1.1]: https://github.com/japaric/libm/compare/v0.1.0...v0.1.1 -- cgit 1.4.1-3-g733a5 From e19b1f013d7913359b3d4b72b9f4e83553b06c4e Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 12 Jun 2019 18:46:01 +0200 Subject: Bump version --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index a61db5ebaf8..8b272d29479 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" repository = "https://github.com/rust-lang-nursery/libm" -version = "0.1.3" +version = "0.1.4" edition = "2018" [features] -- cgit 1.4.1-3-g733a5 From f9b32471651d42dd9529b8a7e55164e23c488975 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 13 Jun 2019 09:21:50 -0700 Subject: Update Rust install task --- library/compiler-builtins/libm/ci/azure-install-rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/ci/azure-install-rust.yml b/library/compiler-builtins/libm/ci/azure-install-rust.yml index c5a53122f8e..f1cd87bcc5c 100644 --- a/library/compiler-builtins/libm/ci/azure-install-rust.yml +++ b/library/compiler-builtins/libm/ci/azure-install-rust.yml @@ -10,7 +10,7 @@ steps: rustup default $toolchain else curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain - echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + echo "##vso[task.prependpath]$HOME/.cargo/bin" fi displayName: Install rust (unix) condition: ne( variables['Agent.OS'], 'Windows_NT' ) -- cgit 1.4.1-3-g733a5 From b31fdb1a70d1cc0da89e8fa6e5e66f60a71a3e38 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 25 Jun 2019 20:39:09 +0200 Subject: Fix doc for floorf --- library/compiler-builtins/libm/src/math/floorf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index ae605e1918f..c04f18aeeea 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -1,6 +1,6 @@ use core::f32; -/// Floor (f64) +/// Floor (f32) /// /// Finds the nearest integer less than or equal to `x`. #[inline] -- cgit 1.4.1-3-g733a5 From 1011d29c556d8abc41748c66f19ce8b22be7a6ca Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 1 Jul 2019 17:05:46 +0300 Subject: Fixed rounding to negative zero --- library/compiler-builtins/libm/src/math/round.rs | 15 ++++++++++----- library/compiler-builtins/libm/src/math/roundf.rs | 11 ++++++++--- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 9a9723cfbb6..efbe68ae4b9 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -5,20 +5,20 @@ const TOINT: f64 = 1.0 / f64::EPSILON; #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn round(mut x: f64) -> f64 { - let (f, i) = (x, x.to_bits()); + let i = x.to_bits(); let e: u64 = i >> 52 & 0x7ff; let mut y: f64; if e >= 0x3ff + 52 { return x; } - if i >> 63 != 0 { - x = -x; - } if e < 0x3ff - 1 { // raise inexact if x!=0 force_eval!(x + TOINT); - return 0.0 * f; + return 0.0 * x; + } + if i >> 63 != 0 { + x = -x; } y = x + TOINT - TOINT - x; if y > 0.5 { @@ -35,3 +35,8 @@ pub fn round(mut x: f64) -> f64 { y } } + +#[test] +fn negative_zero() { + assert_eq!(round(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); +} diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index 839d9469a49..559d3a92680 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -12,13 +12,13 @@ pub fn roundf(mut x: f32) -> f32 { if e >= 0x7f + 23 { return x; } - if i >> 31 != 0 { - x = -x; - } if e < 0x7f - 1 { force_eval!(x + TOINT); return 0.0 * x; } + if i >> 31 != 0 { + x = -x; + } y = x + TOINT - TOINT - x; if y > 0.5f32 { y = y + x - 1.0; @@ -33,3 +33,8 @@ pub fn roundf(mut x: f32) -> f32 { y } } + +#[test] +fn negative_zero() { + assert_eq!(roundf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); +} -- cgit 1.4.1-3-g733a5 From a1286b4f24db30531c46faa542ea3f8e1f9b09c8 Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 1 Jul 2019 17:10:44 +0300 Subject: Fix incorrect f32<->f64 casting in j1f/y1f --- library/compiler-builtins/libm/src/math/j1f.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 83ac1acffdc..14e4ef5bf5b 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -49,7 +49,7 @@ fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 { if sign { cc = -cc; } - return INVSQRTPI * (cc as f32) / sqrtf(x); + return (((INVSQRTPI as f64) * cc) / (sqrtf(x) as f64)) as f32; } /* R0/S0 on [0,2] */ @@ -356,3 +356,17 @@ fn qonef(x: f32) -> f32 { s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); return (0.375 + r / s) / x; } + +#[test] +fn test_j1f_2488() { + // 0x401F3E49 + assert_eq!( + j1f(2.4881766_f32), + 0.49999475_f32); +} +#[test] +fn test_y1f_2002() { + assert_eq!( + y1f(2.0000002_f32), + -0.10703229_f32); +} -- cgit 1.4.1-3-g733a5 From 217b9a34f8339b72838a97aaf7ad24a92ecad89d Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 1 Jul 2019 17:18:59 +0300 Subject: fixed formatting in tests --- library/compiler-builtins/libm/src/math/j1f.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 14e4ef5bf5b..d165ce36985 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -360,13 +360,9 @@ fn qonef(x: f32) -> f32 { #[test] fn test_j1f_2488() { // 0x401F3E49 - assert_eq!( - j1f(2.4881766_f32), - 0.49999475_f32); + assert_eq!(j1f(2.4881766_f32), 0.49999475_f32); } #[test] fn test_y1f_2002() { - assert_eq!( - y1f(2.0000002_f32), - -0.10703229_f32); + assert_eq!(y1f(2.0000002_f32), -0.10703229_f32); } -- cgit 1.4.1-3-g733a5 From 2c05001264d5b57a193776e7e31259e5f6114f8d Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 1 Jul 2019 17:21:43 +0300 Subject: separate tests into #[cfg(test)] mod --- library/compiler-builtins/libm/src/math/j1f.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index d165ce36985..5095894d7a1 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -357,12 +357,16 @@ fn qonef(x: f32) -> f32 { return (0.375 + r / s) / x; } -#[test] -fn test_j1f_2488() { - // 0x401F3E49 - assert_eq!(j1f(2.4881766_f32), 0.49999475_f32); -} -#[test] -fn test_y1f_2002() { - assert_eq!(y1f(2.0000002_f32), -0.10703229_f32); +#[cfg(test)] +mod tests { + use super::{j1f, y1f}; + #[test] + fn test_j1f_2488() { + // 0x401F3E49 + assert_eq!(j1f(2.4881766_f32), 0.49999475_f32); + } + #[test] + fn test_y1f_2002() { + assert_eq!(y1f(2.0000002_f32), -0.10703229_f32); + } } -- cgit 1.4.1-3-g733a5 From b0c846bfd1b15c55e99bad8fdc5c45e626f00db2 Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 1 Jul 2019 17:23:52 +0300 Subject: move tests to separate #[cfg(test)] mod --- library/compiler-builtins/libm/src/math/round.rs | 11 ++++++++--- library/compiler-builtins/libm/src/math/roundf.rs | 11 ++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index efbe68ae4b9..67590d2c19b 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -36,7 +36,12 @@ pub fn round(mut x: f64) -> f64 { } } -#[test] -fn negative_zero() { - assert_eq!(round(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); +#[cfg(test)] +mod tests { + use super::round; + + #[test] + fn negative_zero() { + assert_eq!(round(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); + } } diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index 559d3a92680..85114be4ba1 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -34,7 +34,12 @@ pub fn roundf(mut x: f32) -> f32 { } } -#[test] -fn negative_zero() { - assert_eq!(roundf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); +#[cfg(test)] +mod tests { + use super::roundf; + + #[test] + fn negative_zero() { + assert_eq!(roundf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); + } } -- cgit 1.4.1-3-g733a5 From 2cd88e96b1f87ffcd73e2df62d42f53d1f2ebb63 Mon Sep 17 00:00:00 2001 From: Benjamin Schultzer Date: Tue, 18 Jun 2019 17:56:58 -0700 Subject: Add benchmark suite Signed-off-by: Benjamin Schultzer --- library/compiler-builtins/libm/Cargo.toml | 2 + library/compiler-builtins/libm/README.md | 6 ++ library/compiler-builtins/libm/azure-pipelines.yml | 11 ++ library/compiler-builtins/libm/benches/bench.rs | 118 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/pow.rs | 2 +- 5 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/benches/bench.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 8b272d29479..2f68ecc011b 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -30,6 +30,8 @@ members = [ [dev-dependencies] no-panic = "0.1.8" +rand = "0.6.5" +paste = "0.1.5" [build-dependencies] rand = { version = "0.6.5", optional = true } diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 3df5b65ea38..edd54d41874 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -37,6 +37,12 @@ fn foo(x: f32) { The API documentation can be found [here](https://docs.rs/libm). +## Benchmark +[benchmark]: #benchmark +Run `cargo +nightly bench` + +NOTE: remember to have nightly installed `rustup install nightly` + ## Contributing Please check [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml index d8068e023b4..e9cb916dbed 100644 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -71,3 +71,14 @@ jobs: - template: ci/azure-install-rust.yml - bash: cargo build -p cb displayName: "Check compiler-builtins still probably builds" + + - job: benchmarks + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-install-rust.yml + - bash: cargo bench + displayName: "Benchmarks" + variables: + TOOLCHAIN: nightly + diff --git a/library/compiler-builtins/libm/benches/bench.rs b/library/compiler-builtins/libm/benches/bench.rs new file mode 100644 index 00000000000..522ac4e3bf3 --- /dev/null +++ b/library/compiler-builtins/libm/benches/bench.rs @@ -0,0 +1,118 @@ +#![feature(test)] + +extern crate paste; +extern crate rand; +extern crate test; + +use rand::Rng; +use test::Bencher; + +macro_rules! unary { + ($($func:ident),*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](x))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](x))) + } + } + )*); +} +macro_rules! binary { + ($($func:ident),*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let y = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](x, y))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let y = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](x, y))) + } + } + )*); + ($($func:ident);*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let n = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](x, n))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let n = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](x, n))) + } + } + )*); +} +macro_rules! trinary { + ($($func:ident),*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let y = rng.gen::(); + let z = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](x, y, z))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let y = rng.gen::(); + let z = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](x, y, z))) + } + } + )*); +} +macro_rules! bessel { + ($($func:ident),*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let mut n = rng.gen::(); + n &= 0xffff; + let x = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](n, x))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let mut n = rng.gen::(); + n &= 0xffff; + let x = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](n, x))) + } + } + )*); +} + +unary!( + acos, acosh, asin, atan, cbrt, ceil, cos, cosh, erf, exp, exp2, exp10, expm1, fabs, floor, j0, + j1, lgamma, log, log1p, log2, log10, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc, y0, y1 +); +binary!(atan2, copysign, fdim, fmax, fmin, fmod, hypot, pow); +trinary!(fma); +bessel!(jn, yn); +binary!(ldexp; scalbn); diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 111d712ffc8..068a4ec47d4 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -479,7 +479,7 @@ mod tests { .for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); } - fn test_sets(sets: &[&[f64]], computed: &Fn(f64) -> f64, expected: &Fn(f64) -> f64) { + fn test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) { sets.iter().for_each(|s| { s.iter().for_each(|val| { let exp = expected(*val); -- cgit 1.4.1-3-g733a5 From 53c6687ef53383c6c6b387908c1a1f9893e371dc Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 2 Jul 2019 08:22:03 +0200 Subject: Move benchmarks into its own crate --- library/compiler-builtins/libm/Cargo.toml | 3 +- library/compiler-builtins/libm/README.md | 6 +- library/compiler-builtins/libm/benches/bench.rs | 118 --------------------- library/compiler-builtins/libm/ci/run.sh | 14 ++- .../libm/crates/libm-bench/Cargo.toml | 11 ++ .../libm/crates/libm-bench/benches/bench.rs | 115 ++++++++++++++++++++ 6 files changed, 140 insertions(+), 127 deletions(-) delete mode 100644 library/compiler-builtins/libm/benches/bench.rs create mode 100644 library/compiler-builtins/libm/crates/libm-bench/Cargo.toml create mode 100644 library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 2f68ecc011b..bd1bb80ce45 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -26,12 +26,11 @@ checked = [] [workspace] members = [ "crates/compiler-builtins-smoke-test", + "crates/libm-bench", ] [dev-dependencies] no-panic = "0.1.8" -rand = "0.6.5" -paste = "0.1.5" [build-dependencies] rand = { version = "0.6.5", optional = true } diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index edd54d41874..8b93f260373 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -39,9 +39,11 @@ The API documentation can be found [here](https://docs.rs/libm). ## Benchmark [benchmark]: #benchmark -Run `cargo +nightly bench` -NOTE: remember to have nightly installed `rustup install nightly` +The benchmarks are located in `crates/libm-bench` and require a nightly Rust toolchain. +To run all benchmarks: + +> cargo +nightly bench --all ## Contributing diff --git a/library/compiler-builtins/libm/benches/bench.rs b/library/compiler-builtins/libm/benches/bench.rs deleted file mode 100644 index 522ac4e3bf3..00000000000 --- a/library/compiler-builtins/libm/benches/bench.rs +++ /dev/null @@ -1,118 +0,0 @@ -#![feature(test)] - -extern crate paste; -extern crate rand; -extern crate test; - -use rand::Rng; -use test::Bencher; - -macro_rules! unary { - ($($func:ident),*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](x))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](x))) - } - } - )*); -} -macro_rules! binary { - ($($func:ident),*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let y = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](x, y))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let y = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](x, y))) - } - } - )*); - ($($func:ident);*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let n = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](x, n))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let n = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](x, n))) - } - } - )*); -} -macro_rules! trinary { - ($($func:ident),*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let y = rng.gen::(); - let z = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](x, y, z))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let y = rng.gen::(); - let z = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](x, y, z))) - } - } - )*); -} -macro_rules! bessel { - ($($func:ident),*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let mut n = rng.gen::(); - n &= 0xffff; - let x = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](n, x))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let mut n = rng.gen::(); - n &= 0xffff; - let x = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](n, x))) - } - } - )*); -} - -unary!( - acos, acosh, asin, atan, cbrt, ceil, cos, cosh, erf, exp, exp2, exp10, expm1, fabs, floor, j0, - j1, lgamma, log, log1p, log2, log10, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc, y0, y1 -); -binary!(atan2, copysign, fdim, fmax, fmin, fmod, hypot, pow); -trinary!(fma); -bessel!(jn, yn); -binary!(ldexp; scalbn); diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 42c2416455d..37ffb8793cc 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -1,11 +1,15 @@ -#!/bin/sh +#!/usr/bin/env sh set -ex TARGET=$1 -cargo test --target $TARGET -cargo test --target $TARGET --release +CMD="cargo test --all --no-default-features --target $TARGET" -cargo test --features 'checked musl-reference-tests' --target $TARGET +$CMD +$CMD --release -cargo test --features 'checked musl-reference-tests' --target $TARGET --release +$CMD --features 'stable' +$CMD --release --features 'stable' + +$CMD --features 'stable checked musl-reference-tests' +$CMD --release --features 'stable checked musl-reference-tests' diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml new file mode 100644 index 00000000000..8e06e0fb5c8 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "libm-bench" +version = "0.1.0" +authors = ["Gonzalo Brito Gadeschi "] +edition = "2018" +license = "MIT OR Apache-2.0" + +[dependencies] +libm = { path = "../.." } +rand = "0.6.5" +paste = "0.1.5" diff --git a/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs b/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs new file mode 100644 index 00000000000..b6d8741531f --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs @@ -0,0 +1,115 @@ +#![feature(test)] +extern crate test; + +use rand::Rng; +use test::Bencher; + +macro_rules! unary { + ($($func:ident),*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](x))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](x))) + } + } + )*); +} +macro_rules! binary { + ($($func:ident),*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let y = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](x, y))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let y = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](x, y))) + } + } + )*); + ($($func:ident);*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let n = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](x, n))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let n = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](x, n))) + } + } + )*); +} +macro_rules! trinary { + ($($func:ident),*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let y = rng.gen::(); + let z = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](x, y, z))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let y = rng.gen::(); + let z = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](x, y, z))) + } + } + )*); +} +macro_rules! bessel { + ($($func:ident),*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let mut n = rng.gen::(); + n &= 0xffff; + let x = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](n, x))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let mut n = rng.gen::(); + n &= 0xffff; + let x = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](n, x))) + } + } + )*); +} + +unary!( + acos, acosh, asin, atan, cbrt, ceil, cos, cosh, erf, exp, exp2, exp10, expm1, fabs, floor, j0, + j1, lgamma, log, log1p, log2, log10, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc, y0, y1 +); +binary!(atan2, copysign, fdim, fmax, fmin, fmod, hypot, pow); +trinary!(fma); +bessel!(jn, yn); +binary!(ldexp; scalbn); -- cgit 1.4.1-3-g733a5 From cc1671fc576eb3ca390e3f9979bac4afae063193 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 2 Jul 2019 08:32:31 +0200 Subject: Do not enable default features in benchmarks --- library/compiler-builtins/libm/crates/libm-bench/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml index 8e06e0fb5c8..d28dd861fe4 100644 --- a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml @@ -6,6 +6,6 @@ edition = "2018" license = "MIT OR Apache-2.0" [dependencies] -libm = { path = "../.." } +libm = { path = "../..", default-features = false } rand = "0.6.5" paste = "0.1.5" -- cgit 1.4.1-3-g733a5 From f6e48dd17d39fc95bec7a98f638378b68165a6a1 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 2 Jul 2019 08:33:11 +0200 Subject: Re-export the stable libm feature --- library/compiler-builtins/libm/crates/libm-bench/Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml index d28dd861fe4..ba65dbd5fe6 100644 --- a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml @@ -9,3 +9,7 @@ license = "MIT OR Apache-2.0" libm = { path = "../..", default-features = false } rand = "0.6.5" paste = "0.1.5" + +[features] +default = [] +stable = [ "libm/stable" ] -- cgit 1.4.1-3-g733a5 From eb08eb0d433cfb38f7ba857b7496b69e68aa8d8c Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 2 Jul 2019 09:07:10 +0200 Subject: Run benchmarks on CI --- library/compiler-builtins/libm/azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml index e9cb916dbed..c89346c73d8 100644 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -77,7 +77,7 @@ jobs: vmImage: ubuntu-16.04 steps: - template: ci/azure-install-rust.yml - - bash: cargo bench + - bash: cargo bench --all displayName: "Benchmarks" variables: TOOLCHAIN: nightly -- cgit 1.4.1-3-g733a5 From 5e711e630e77c5c9c111f2833b778bff99f22af6 Mon Sep 17 00:00:00 2001 From: Igor null Date: Tue, 2 Jul 2019 16:48:59 +0300 Subject: Fixed a few int overflows rem_pio2 had incorrect u32/i32 operations remquo has a straight int overflow --- .../compiler-builtins/libm/src/math/rem_pio2.rs | 53 ++++++++++++++-------- .../libm/src/math/rem_pio2_large.rs | 2 +- library/compiler-builtins/libm/src/math/remquo.rs | 14 +++++- 3 files changed, 48 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 536dfac3c42..dc6b3297d93 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -179,29 +179,44 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { i -= 1; } let mut ty = [0.0; 3]; - let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix >> 20) - (0x3ff + 23)) as i32, 1); + let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix as i32) >> 20) - (0x3ff + 23), 1); if sign != 0 { return (-n, -ty[0], -ty[1]); } (n, ty[0], ty[1]) } -#[test] -fn test_near_pi() { - assert_eq!( - rem_pio2(3.141592025756836), - (2, -6.278329573009626e-7, -2.1125998133974653e-23) - ); - assert_eq!( - rem_pio2(3.141592033207416), - (2, -6.20382377148128e-7, -2.1125998133974653e-23) - ); - assert_eq!( - rem_pio2(3.141592144966125), - (2, -5.086236681942706e-7, -2.1125998133974653e-23) - ); - assert_eq!( - rem_pio2(3.141592979431152), - (2, 3.2584135866119817e-7, -2.1125998133974653e-23) - ); +#[cfg(test)] +mod tests { + use super::rem_pio2; + + #[test] + fn test_near_pi() { + assert_eq!( + rem_pio2(3.141592025756836), + (2, -6.278329573009626e-7, -2.1125998133974653e-23) + ); + assert_eq!( + rem_pio2(3.141592033207416), + (2, -6.20382377148128e-7, -2.1125998133974653e-23) + ); + assert_eq!( + rem_pio2(3.141592144966125), + (2, -5.086236681942706e-7, -2.1125998133974653e-23) + ); + assert_eq!( + rem_pio2(3.141592979431152), + (2, 3.2584135866119817e-7, -2.1125998133974653e-23) + ); + } + + #[test] + fn test_overflow_b9b847() { + let _ = rem_pio2(-3054214.5490637687); + } + + #[test] + fn test_overflow_4747b9() { + let _ = rem_pio2(917340800458.2274); + } } diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 006d3e153db..5336a976719 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -256,7 +256,7 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> let jv = jv as usize; /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ - let mut j = (jv - jx) as i32; + let mut j = (jv as i32) - (jx as i32); let m = jx + jk; for i in 0..=m { i!(f, i, =, if j < 0 { diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs index 1c2ba8918cb..c72c8f1878e 100644 --- a/library/compiler-builtins/libm/src/math/remquo.rs +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -85,7 +85,8 @@ pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { } if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { x -= y; - q += 1; + // TODO: this matches musl behavior, but it is incorrect + q = q.wrapping_add(1); } q &= 0x7fffffff; let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; @@ -95,3 +96,14 @@ pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { (x, quo) } } + +#[cfg(test)] +mod tests { + use super::remquo; + + #[test] + fn test_q_overflow() { + // 0xc000000000000001, 0x04c0000000000004 + let _ = remquo(-2.0000000000000004, 8.406091369059082e-286); + } +} -- cgit 1.4.1-3-g733a5 From 4f5e28166f8794cc8a1847fa7bf948aab98ced62 Mon Sep 17 00:00:00 2001 From: Benjamin Schultzer Date: Tue, 2 Jul 2019 11:56:38 -0700 Subject: Add signum Signed-off-by: Benjamin Schultzer --- library/compiler-builtins/libm/src/lib.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index a47883d81bb..81b76f87b44 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -73,8 +73,7 @@ pub trait F32Ext: private::Sealed + Sized { fn abs(self) -> Self; - // NOTE depends on unstable intrinsics::copysignf32 - // fn signum(self) -> Self; + fn signum(self) -> Self; fn mul_add(self, a: Self, b: Self) -> Self; @@ -178,6 +177,15 @@ impl F32Ext for f32 { fabsf(self) } + #[inline] + fn signum(self) -> Self { + if self.is_nan() { + f32::NAN + } else { + copysignf(1., self) + } + } + #[inline] fn mul_add(self, a: Self, b: Self) -> Self { fmaf(self, a, b) @@ -361,8 +369,7 @@ pub trait F64Ext: private::Sealed + Sized { fn abs(self) -> Self; - // NOTE depends on unstable intrinsics::copysignf64 - // fn signum(self) -> Self; + fn signum(self) -> Self; fn mul_add(self, a: Self, b: Self) -> Self; @@ -466,6 +473,15 @@ impl F64Ext for f64 { fabs(self) } + #[inline] + fn signum(self) -> Self { + if self.is_nan() { + f64::NAN + } else { + copysign(1., self) + } + } + #[inline] fn mul_add(self, a: Self, b: Self) -> Self { fma(self, a, b) -- cgit 1.4.1-3-g733a5 From 1d159b527896d7776a0a7982e45324145452f85b Mon Sep 17 00:00:00 2001 From: Benjamin Schultzer Date: Wed, 3 Jul 2019 11:57:54 -0700 Subject: Add remainder This PR adds the missing `remainder` and `remainderf` found in musl libm respectly https://git.musl-libc.org/cgit/musl/tree/src/math/remainder.c and https://git.musl-libc.org/cgit/musl/tree/src/math/remainderf.c Signed-off-by: Benjamin Schultzer --- library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ library/compiler-builtins/libm/src/math/remainder.rs | 5 +++++ library/compiler-builtins/libm/src/math/remainderf.rs | 5 +++++ 3 files changed, 14 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/remainder.rs create mode 100644 library/compiler-builtins/libm/src/math/remainderf.rs diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 35ffe1a2cb2..48b400a9207 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -148,6 +148,8 @@ mod modf; mod modff; mod pow; mod powf; +mod remainder; +mod remainderf; mod remquo; mod remquof; mod round; @@ -258,6 +260,8 @@ pub use self::modf::modf; pub use self::modff::modff; pub use self::pow::pow; pub use self::powf::powf; +pub use self::remainder::remainder; +pub use self::remainderf::remainderf; pub use self::remquo::remquo; pub use self::remquof::remquof; pub use self::round::round; diff --git a/library/compiler-builtins/libm/src/math/remainder.rs b/library/compiler-builtins/libm/src/math/remainder.rs new file mode 100644 index 00000000000..e0f56da2014 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/remainder.rs @@ -0,0 +1,5 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remainder(x: f64, y: f64) -> (f64, i32) { + super::remquo(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/remainderf.rs b/library/compiler-builtins/libm/src/math/remainderf.rs new file mode 100644 index 00000000000..72fd0e20587 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/remainderf.rs @@ -0,0 +1,5 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remainderf(x: f32, y: f32) -> (f32, i32) { + super::remquof(x, y) +} -- cgit 1.4.1-3-g733a5 From 05762eb876f40c192a3c497b8634b668d280b033 Mon Sep 17 00:00:00 2001 From: Benjamin Schultzer Date: Wed, 3 Jul 2019 14:15:29 -0700 Subject: Only return the fp value. Signed-off-by: Benjamin Schultzer --- library/compiler-builtins/libm/src/math/remainder.rs | 5 +++-- library/compiler-builtins/libm/src/math/remainderf.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/remainder.rs b/library/compiler-builtins/libm/src/math/remainder.rs index e0f56da2014..7ce895004b8 100644 --- a/library/compiler-builtins/libm/src/math/remainder.rs +++ b/library/compiler-builtins/libm/src/math/remainder.rs @@ -1,5 +1,6 @@ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remainder(x: f64, y: f64) -> (f64, i32) { - super::remquo(x, y) +pub fn remainder(x: f64, y: f64) -> f64 { + let (result, _) = super::remquo(x, y); + result } diff --git a/library/compiler-builtins/libm/src/math/remainderf.rs b/library/compiler-builtins/libm/src/math/remainderf.rs index 72fd0e20587..8b2aa5aabbc 100644 --- a/library/compiler-builtins/libm/src/math/remainderf.rs +++ b/library/compiler-builtins/libm/src/math/remainderf.rs @@ -1,5 +1,6 @@ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remainderf(x: f32, y: f32) -> (f32, i32) { - super::remquof(x, y) +pub fn remainderf(x: f32, y: f32) -> f32 { + let (result, _) = super::remquof(x, y); + result } -- cgit 1.4.1-3-g733a5 From 0e871e58b4b024b0d2eb0456f2c2aaab5d3a299b Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 3 Jul 2019 23:35:07 +0200 Subject: Remove F32Ext and F64Ext --- library/compiler-builtins/libm/src/lib.rs | 599 ------------------------------ 1 file changed, 599 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 81b76f87b44..b37248ffba4 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -55,604 +55,5 @@ pub fn _eq(a: f64, b: f64) -> Result<(), u64> { } } -/// Math support for `f32` -/// -/// This trait is sealed and cannot be implemented outside of `libm`. -pub trait F32Ext: private::Sealed + Sized { - fn floor(self) -> Self; - - fn ceil(self) -> Self; - - fn round(self) -> Self; - - fn trunc(self) -> Self; - - fn fdim(self, rhs: Self) -> Self; - - fn fract(self) -> Self; - - fn abs(self) -> Self; - - fn signum(self) -> Self; - - fn mul_add(self, a: Self, b: Self) -> Self; - - fn div_euc(self, rhs: Self) -> Self; - - fn mod_euc(self, rhs: Self) -> Self; - - // NOTE depends on unstable intrinsics::powif32 - // fn powi(self, n: i32) -> Self; - - fn powf(self, n: Self) -> Self; - - fn sqrt(self) -> Self; - - fn exp(self) -> Self; - - fn exp2(self) -> Self; - - fn ln(self) -> Self; - - fn log(self, base: Self) -> Self; - - fn log2(self) -> Self; - - fn log10(self) -> Self; - - fn cbrt(self) -> Self; - - fn hypot(self, other: Self) -> Self; - - fn sin(self) -> Self; - - fn cos(self) -> Self; - - fn tan(self) -> Self; - - fn asin(self) -> Self; - - fn acos(self) -> Self; - - fn atan(self) -> Self; - - fn atan2(self, other: Self) -> Self; - - fn sin_cos(self) -> (Self, Self); - - fn exp_m1(self) -> Self; - - fn ln_1p(self) -> Self; - - fn sinh(self) -> Self; - - fn cosh(self) -> Self; - - fn tanh(self) -> Self; - - fn asinh(self) -> Self; - - fn acosh(self) -> Self; - - fn atanh(self) -> Self; - - fn min(self, other: Self) -> Self; - - fn max(self, other: Self) -> Self; -} - -impl F32Ext for f32 { - #[inline] - fn floor(self) -> Self { - floorf(self) - } - - #[inline] - fn ceil(self) -> Self { - ceilf(self) - } - - #[inline] - fn round(self) -> Self { - roundf(self) - } - - #[inline] - fn trunc(self) -> Self { - truncf(self) - } - - #[inline] - fn fdim(self, rhs: Self) -> Self { - fdimf(self, rhs) - } - - #[inline] - fn fract(self) -> Self { - self - self.trunc() - } - - #[inline] - fn abs(self) -> Self { - fabsf(self) - } - - #[inline] - fn signum(self) -> Self { - if self.is_nan() { - f32::NAN - } else { - copysignf(1., self) - } - } - - #[inline] - fn mul_add(self, a: Self, b: Self) -> Self { - fmaf(self, a, b) - } - - #[inline] - fn div_euc(self, rhs: Self) -> Self { - let q = (self / rhs).trunc(); - if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; - } - q - } - - #[inline] - fn mod_euc(self, rhs: f32) -> f32 { - let r = self % rhs; - if r < 0.0 { - r + rhs.abs() - } else { - r - } - } - - #[inline] - fn powf(self, n: Self) -> Self { - powf(self, n) - } - - #[inline] - fn sqrt(self) -> Self { - sqrtf(self) - } - - #[inline] - fn exp(self) -> Self { - expf(self) - } - - #[inline] - fn exp2(self) -> Self { - exp2f(self) - } - - #[inline] - fn ln(self) -> Self { - logf(self) - } - - #[inline] - fn log(self, base: Self) -> Self { - self.ln() / base.ln() - } - - #[inline] - fn log2(self) -> Self { - log2f(self) - } - - #[inline] - fn log10(self) -> Self { - log10f(self) - } - - #[inline] - fn cbrt(self) -> Self { - cbrtf(self) - } - - #[inline] - fn hypot(self, other: Self) -> Self { - hypotf(self, other) - } - - #[inline] - fn sin(self) -> Self { - sinf(self) - } - - #[inline] - fn cos(self) -> Self { - cosf(self) - } - - #[inline] - fn tan(self) -> Self { - tanf(self) - } - - #[inline] - fn asin(self) -> Self { - asinf(self) - } - - #[inline] - fn acos(self) -> Self { - acosf(self) - } - - #[inline] - fn atan(self) -> Self { - atanf(self) - } - - #[inline] - fn atan2(self, other: Self) -> Self { - atan2f(self, other) - } - - #[inline] - fn sin_cos(self) -> (Self, Self) { - sincosf(self) - } - - #[inline] - fn exp_m1(self) -> Self { - expm1f(self) - } - - #[inline] - fn ln_1p(self) -> Self { - log1pf(self) - } - - #[inline] - fn sinh(self) -> Self { - sinhf(self) - } - - #[inline] - fn cosh(self) -> Self { - coshf(self) - } - - #[inline] - fn tanh(self) -> Self { - tanhf(self) - } - - #[inline] - fn asinh(self) -> Self { - asinhf(self) - } - - #[inline] - fn acosh(self) -> Self { - acoshf(self) - } - - #[inline] - fn atanh(self) -> Self { - atanhf(self) - } - - #[inline] - fn min(self, other: Self) -> Self { - fminf(self, other) - } - - #[inline] - fn max(self, other: Self) -> Self { - fmaxf(self, other) - } -} - -/// Math support for `f64` -/// -/// This trait is sealed and cannot be implemented outside of `libm`. -pub trait F64Ext: private::Sealed + Sized { - fn floor(self) -> Self; - - fn ceil(self) -> Self; - - fn round(self) -> Self; - - fn trunc(self) -> Self; - - fn fdim(self, rhs: Self) -> Self; - - fn fract(self) -> Self; - - fn abs(self) -> Self; - - fn signum(self) -> Self; - - fn mul_add(self, a: Self, b: Self) -> Self; - - fn div_euc(self, rhs: Self) -> Self; - - fn mod_euc(self, rhs: Self) -> Self; - - // NOTE depends on unstable intrinsics::powif64 - // fn powi(self, n: i32) -> Self; - - fn powf(self, n: Self) -> Self; - - fn sqrt(self) -> Self; - - fn exp(self) -> Self; - - fn exp2(self) -> Self; - - fn ln(self) -> Self; - - fn log(self, base: Self) -> Self; - - fn log2(self) -> Self; - - fn log10(self) -> Self; - - fn cbrt(self) -> Self; - - fn hypot(self, other: Self) -> Self; - - fn sin(self) -> Self; - - fn cos(self) -> Self; - - fn tan(self) -> Self; - - fn asin(self) -> Self; - - fn acos(self) -> Self; - - fn atan(self) -> Self; - - fn atan2(self, other: Self) -> Self; - - fn sin_cos(self) -> (Self, Self); - - fn exp_m1(self) -> Self; - - fn ln_1p(self) -> Self; - - fn sinh(self) -> Self; - - fn cosh(self) -> Self; - - fn tanh(self) -> Self; - - fn asinh(self) -> Self; - - fn acosh(self) -> Self; - - fn atanh(self) -> Self; - - fn min(self, other: Self) -> Self; - - fn max(self, other: Self) -> Self; -} - -impl F64Ext for f64 { - #[inline] - fn floor(self) -> Self { - floor(self) - } - - #[inline] - fn ceil(self) -> Self { - ceil(self) - } - - #[inline] - fn round(self) -> Self { - round(self) - } - - #[inline] - fn trunc(self) -> Self { - trunc(self) - } - - #[inline] - fn fdim(self, rhs: Self) -> Self { - fdim(self, rhs) - } - - #[inline] - fn fract(self) -> Self { - self - self.trunc() - } - - #[inline] - fn abs(self) -> Self { - fabs(self) - } - - #[inline] - fn signum(self) -> Self { - if self.is_nan() { - f64::NAN - } else { - copysign(1., self) - } - } - - #[inline] - fn mul_add(self, a: Self, b: Self) -> Self { - fma(self, a, b) - } - - #[inline] - fn div_euc(self, rhs: Self) -> Self { - let q = (self / rhs).trunc(); - if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; - } - q - } - - #[inline] - fn mod_euc(self, rhs: f64) -> f64 { - let r = self % rhs; - if r < 0.0 { - r + rhs.abs() - } else { - r - } - } - - #[inline] - fn powf(self, n: Self) -> Self { - pow(self, n) - } - - #[inline] - fn sqrt(self) -> Self { - sqrt(self) - } - - #[inline] - fn exp(self) -> Self { - exp(self) - } - - #[inline] - fn exp2(self) -> Self { - exp2(self) - } - - #[inline] - fn ln(self) -> Self { - log(self) - } - - #[inline] - fn log(self, base: Self) -> Self { - self.ln() / base.ln() - } - - #[inline] - fn log2(self) -> Self { - log2(self) - } - - #[inline] - fn log10(self) -> Self { - log10(self) - } - - #[inline] - fn cbrt(self) -> Self { - cbrt(self) - } - - #[inline] - fn hypot(self, other: Self) -> Self { - hypot(self, other) - } - - #[inline] - fn sin(self) -> Self { - sin(self) - } - - #[inline] - fn cos(self) -> Self { - cos(self) - } - - #[inline] - fn tan(self) -> Self { - tan(self) - } - - #[inline] - fn asin(self) -> Self { - asin(self) - } - - #[inline] - fn acos(self) -> Self { - acos(self) - } - - #[inline] - fn atan(self) -> Self { - atan(self) - } - - #[inline] - fn atan2(self, other: Self) -> Self { - atan2(self, other) - } - - #[inline] - fn sin_cos(self) -> (Self, Self) { - sincos(self) - } - - #[inline] - fn exp_m1(self) -> Self { - expm1(self) - } - - #[inline] - fn ln_1p(self) -> Self { - log1p(self) - } - - #[inline] - fn sinh(self) -> Self { - sinh(self) - } - - #[inline] - fn cosh(self) -> Self { - cosh(self) - } - - #[inline] - fn tanh(self) -> Self { - tanh(self) - } - - #[inline] - fn asinh(self) -> Self { - asinh(self) - } - - #[inline] - fn acosh(self) -> Self { - acosh(self) - } - - #[inline] - fn atanh(self) -> Self { - atanh(self) - } - - #[inline] - fn min(self, other: Self) -> Self { - fmin(self, other) - } - - #[inline] - fn max(self, other: Self) -> Self { - fmax(self, other) - } -} - -mod private { - pub trait Sealed {} - - impl Sealed for f32 {} - impl Sealed for f64 {} -} - #[cfg(all(test, feature = "musl-reference-tests"))] include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); -- cgit 1.4.1-3-g733a5 From dc9fa00222b4204545000f6404d87fef0cd1eb9c Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 3 Jul 2019 23:35:24 +0200 Subject: Bump minor version to 0.2.0 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index bd1bb80ce45..3e6817851ba 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" repository = "https://github.com/rust-lang-nursery/libm" -version = "0.1.4" +version = "0.2.0" edition = "2018" [features] -- cgit 1.4.1-3-g733a5 From e8ad478f6fb33bb95fd7cc215323e0f2a4d7c778 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 3 Jul 2019 23:53:35 +0200 Subject: Remove traits from README --- library/compiler-builtins/libm/README.md | 17 +---------------- library/compiler-builtins/libm/src/lib.rs | 10 ---------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 8b93f260373..e10904f8cf0 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -18,22 +18,7 @@ term goal is to enable [math support in the `core` crate][core]. ## Already usable -This crate is [on crates.io] and can be used today in stable `#![no_std]` programs like this: - -[on crates.io]: https://crates.io/crates/libm - -``` rust -#![no_std] - -extern crate libm; - -use libm::F32Ext; // adds methods to `f32` - -fn foo(x: f32) { - let y = x.sqrt(); - let z = libm::truncf(x); -} -``` +This crate is [on crates.io] and can be used today in stable `#![no_std]` programs. The API documentation can be found [here](https://docs.rs/libm). diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index b37248ffba4..b15857dbe6f 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,14 +1,4 @@ //! libm in pure Rust -//! -//! # Usage -//! -//! You can use this crate in two ways: -//! -//! - By directly using its free functions, e.g. `libm::powf`. -//! -//! - By importing the `F32Ext` and / or `F64Ext` extension traits to add methods like `powf` to the -//! `f32` and `f64` types. Then you'll be able to invoke math functions as methods, e.g. `x.sqrt()`. - #![deny(warnings)] #![no_std] #![cfg_attr( -- cgit 1.4.1-3-g733a5 From 2da2f8dce485370556bec2d6851ec650ef3c79e2 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 9 Jul 2019 17:17:08 +0200 Subject: Add nextafter and nextafterf from musl --- library/compiler-builtins/libm/src/math/mod.rs | 4 +++ .../compiler-builtins/libm/src/math/nextafter.rs | 38 ++++++++++++++++++++++ .../compiler-builtins/libm/src/math/nextafterf.rs | 38 ++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/nextafter.rs create mode 100644 library/compiler-builtins/libm/src/math/nextafterf.rs diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 48b400a9207..fcf4e649cde 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -146,6 +146,8 @@ mod log2f; mod logf; mod modf; mod modff; +mod nextafter; +mod nextafterf; mod pow; mod powf; mod remainder; @@ -258,6 +260,8 @@ pub use self::log2f::log2f; pub use self::logf::logf; pub use self::modf::modf; pub use self::modff::modff; +pub use self::nextafter::nextafter; +pub use self::nextafterf::nextafterf; pub use self::pow::pow; pub use self::powf::powf; pub use self::remainder::remainder; diff --git a/library/compiler-builtins/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/src/math/nextafter.rs new file mode 100644 index 00000000000..4c1257e0027 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/nextafter.rs @@ -0,0 +1,38 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn nextafter(x: f64, y: f64) -> f64 { + if x.is_nan() || y.is_nan() { + return x + y; + } + + let mut ux_i = x.to_bits(); + let uy_i = y.to_bits(); + if ux_i == uy_i { + return y; + } + + let ax = ux_i & !1_u64 / 2; + let ay = uy_i & !1_u64 / 2; + if ax == 0 { + if ay == 0 { + return y; + } + ux_i = (uy_i & 1_u64 << 63) | 1; + } else if ax > ay || ((ux_i ^ uy_i) & 1_u64 << 63) != 0 { + ux_i -= 1; + } else { + ux_i += 1; + } + + let e = ux_i.wrapping_shr(52 & 0x7ff); + // raise overflow if ux.f is infinite and x is finite + if e == 0x7ff { + force_eval!(x + x); + } + let ux_f = f64::from_bits(ux_i); + // raise underflow if ux.f is subnormal or zero + if e == 0 { + force_eval!(x * x + ux_f * ux_f); + } + ux_f +} diff --git a/library/compiler-builtins/libm/src/math/nextafterf.rs b/library/compiler-builtins/libm/src/math/nextafterf.rs new file mode 100644 index 00000000000..a48bce9f742 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/nextafterf.rs @@ -0,0 +1,38 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn nextafterf(x: f32, y: f32) -> f32 { + if x.is_nan() || y.is_nan() { + return x + y; + } + + let mut ux_i = x.to_bits(); + let uy_i = y.to_bits(); + if ux_i == uy_i { + return y; + } + + let ax = ux_i & 0x7fff_ffff_u32; + let ay = uy_i & 0x7fff_ffff_u32; + if ax == 0 { + if ay == 0 { + return y; + } + ux_i = (uy_i & 0x8000_0000_u32) | 1; + } else if ax > ay || ((ux_i ^ uy_i) & 0x8000_0000_u32) != 0 { + ux_i -= 1; + } else { + ux_i += 1; + } + + let e = ux_i.wrapping_shr(0x7f80_0000_u32); + // raise overflow if ux_f is infinite and x is finite + if e == 0x7f80_0000_u32 { + force_eval!(x + x); + } + let ux_f = f32::from_bits(ux_i); + // raise underflow if ux_f is subnormal or zero + if e == 0 { + force_eval!(x * x + ux_f * ux_f); + } + ux_f +} -- cgit 1.4.1-3-g733a5 From e46b4a82995f7a01bbb12385ae27ed476aa89379 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 9 Jul 2019 17:33:01 +0200 Subject: Floating-point environment APIs are private --- library/compiler-builtins/libm/src/math/fenv.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fenv.rs b/library/compiler-builtins/libm/src/math/fenv.rs index 63bb2036820..652e6032452 100644 --- a/library/compiler-builtins/libm/src/math/fenv.rs +++ b/library/compiler-builtins/libm/src/math/fenv.rs @@ -1,33 +1,33 @@ // src: musl/src/fenv/fenv.c /* Dummy functions for archs lacking fenv implementation */ -pub const FE_UNDERFLOW: i32 = 0; -pub const FE_INEXACT: i32 = 0; +pub(crate) const FE_UNDERFLOW: i32 = 0; +pub(crate) const FE_INEXACT: i32 = 0; -pub const FE_TONEAREST: i32 = 0; -pub const FE_TOWARDZERO: i32 = 0; +pub(crate) const FE_TONEAREST: i32 = 0; +pub(crate) const FE_TOWARDZERO: i32 = 0; #[inline] -pub fn feclearexcept(_mask: i32) -> i32 { +pub(crate) fn feclearexcept(_mask: i32) -> i32 { 0 } #[inline] -pub fn feraiseexcept(_mask: i32) -> i32 { +pub(crate) fn feraiseexcept(_mask: i32) -> i32 { 0 } #[inline] -pub fn fetestexcept(_mask: i32) -> i32 { +pub(crate) fn fetestexcept(_mask: i32) -> i32 { 0 } #[inline] -pub fn fegetround() -> i32 { +pub(crate) fn fegetround() -> i32 { FE_TONEAREST } #[inline] -pub fn fesetround(_r: i32) -> i32 { +pub(crate) fn fesetround(_r: i32) -> i32 { 0 } -- cgit 1.4.1-3-g733a5 From 42e0c8c0a1cabb24b48f56470aea1656a47f9cc7 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 10 Jul 2019 12:59:36 +0200 Subject: Add FMA tests that cause it to segfault --- library/compiler-builtins/libm/src/math/fma.rs | 19 +++++++++++++++++++ library/compiler-builtins/libm/tests/unit.rs | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 library/compiler-builtins/libm/tests/unit.rs diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 07d90f8b727..6d4471a9a04 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -205,3 +205,22 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { } scalbn(r, e) } + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn fma_segfault() { + // These two inputs cause fma to segfault on release due to overflow: + assert_eq!( + fma( + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313 + ), + -0.00000000000000022204460492503126, + ); + + assert_eq!(fma(-0.992, -0.992, -0.992), -0.00793599999988632,); + } +} diff --git a/library/compiler-builtins/libm/tests/unit.rs b/library/compiler-builtins/libm/tests/unit.rs new file mode 100644 index 00000000000..4e7002817a6 --- /dev/null +++ b/library/compiler-builtins/libm/tests/unit.rs @@ -0,0 +1,19 @@ +use libm::*; + +#[test] +fn fma_segfault() { + // These two inputs cause fma to segfault on release due to overflow: + assert_eq!( + fma( + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313 + ), + -0.00000000000000022204460492503126, + ); + + assert_eq!( + fma(-0.992, -0.992, -0.992), + -0.00793599999988632, + ); +} -- cgit 1.4.1-3-g733a5 From f783ff454b69a50f37aa37f41a36b7e7b90d67c8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 10 Jul 2019 08:42:28 -0700 Subject: Remove most `#[inline]` annotations These annotations fall into a few categories * Some simply aren't needed since functions will always be in the same CGU anyway and are already candidates for inlining. * Many are on massive functions which shouldn't be inlined across crates due to code size concerns. * Others aren't necessary since calls to this crate are rarely inlined anyway (since it's lowered through LLVM). If this crate is called directly and inlining is needed then LTO can always be turned on, otherwise this will benefit downstream consumers by avoiding re-codegen'ing so many functions. --- library/compiler-builtins/libm/src/math/acos.rs | 2 -- library/compiler-builtins/libm/src/math/acosf.rs | 2 -- library/compiler-builtins/libm/src/math/asin.rs | 2 -- library/compiler-builtins/libm/src/math/asinf.rs | 2 -- library/compiler-builtins/libm/src/math/atan.rs | 1 - library/compiler-builtins/libm/src/math/atan2.rs | 1 - library/compiler-builtins/libm/src/math/atan2f.rs | 1 - library/compiler-builtins/libm/src/math/atanf.rs | 1 - library/compiler-builtins/libm/src/math/cbrt.rs | 1 - library/compiler-builtins/libm/src/math/cbrtf.rs | 1 - library/compiler-builtins/libm/src/math/ceil.rs | 1 - library/compiler-builtins/libm/src/math/ceilf.rs | 1 - library/compiler-builtins/libm/src/math/cos.rs | 1 - library/compiler-builtins/libm/src/math/cosf.rs | 1 - library/compiler-builtins/libm/src/math/cosh.rs | 1 - library/compiler-builtins/libm/src/math/coshf.rs | 1 - library/compiler-builtins/libm/src/math/exp.rs | 1 - library/compiler-builtins/libm/src/math/exp2.rs | 1 - library/compiler-builtins/libm/src/math/exp2f.rs | 1 - library/compiler-builtins/libm/src/math/expf.rs | 1 - library/compiler-builtins/libm/src/math/expm1.rs | 1 - library/compiler-builtins/libm/src/math/expm1f.rs | 1 - library/compiler-builtins/libm/src/math/expo2.rs | 1 - library/compiler-builtins/libm/src/math/fabs.rs | 1 - library/compiler-builtins/libm/src/math/fabsf.rs | 1 - library/compiler-builtins/libm/src/math/fdim.rs | 1 - library/compiler-builtins/libm/src/math/fdimf.rs | 1 - library/compiler-builtins/libm/src/math/floor.rs | 1 - library/compiler-builtins/libm/src/math/floorf.rs | 1 - library/compiler-builtins/libm/src/math/fma.rs | 3 --- library/compiler-builtins/libm/src/math/fmaf.rs | 1 - library/compiler-builtins/libm/src/math/fmax.rs | 1 - library/compiler-builtins/libm/src/math/fmaxf.rs | 1 - library/compiler-builtins/libm/src/math/fmin.rs | 1 - library/compiler-builtins/libm/src/math/fminf.rs | 1 - library/compiler-builtins/libm/src/math/fmod.rs | 1 - library/compiler-builtins/libm/src/math/fmodf.rs | 1 - library/compiler-builtins/libm/src/math/hypot.rs | 2 -- library/compiler-builtins/libm/src/math/hypotf.rs | 1 - library/compiler-builtins/libm/src/math/k_cos.rs | 1 - library/compiler-builtins/libm/src/math/k_cosf.rs | 1 - library/compiler-builtins/libm/src/math/k_expo2.rs | 1 - library/compiler-builtins/libm/src/math/k_expo2f.rs | 1 - library/compiler-builtins/libm/src/math/k_sin.rs | 1 - library/compiler-builtins/libm/src/math/k_sinf.rs | 1 - library/compiler-builtins/libm/src/math/k_tan.rs | 2 -- library/compiler-builtins/libm/src/math/k_tanf.rs | 1 - library/compiler-builtins/libm/src/math/ldexp.rs | 1 - library/compiler-builtins/libm/src/math/ldexpf.rs | 1 - library/compiler-builtins/libm/src/math/log.rs | 1 - library/compiler-builtins/libm/src/math/log10.rs | 1 - library/compiler-builtins/libm/src/math/log10f.rs | 1 - library/compiler-builtins/libm/src/math/log1p.rs | 1 - library/compiler-builtins/libm/src/math/log1pf.rs | 1 - library/compiler-builtins/libm/src/math/log2.rs | 1 - library/compiler-builtins/libm/src/math/log2f.rs | 1 - library/compiler-builtins/libm/src/math/logf.rs | 1 - library/compiler-builtins/libm/src/math/nextafter.rs | 1 - library/compiler-builtins/libm/src/math/nextafterf.rs | 1 - library/compiler-builtins/libm/src/math/pow.rs | 1 - library/compiler-builtins/libm/src/math/powf.rs | 1 - library/compiler-builtins/libm/src/math/rem_pio2.rs | 2 -- library/compiler-builtins/libm/src/math/rem_pio2_large.rs | 1 - library/compiler-builtins/libm/src/math/rem_pio2f.rs | 1 - library/compiler-builtins/libm/src/math/remainder.rs | 1 - library/compiler-builtins/libm/src/math/remainderf.rs | 1 - library/compiler-builtins/libm/src/math/remquo.rs | 1 + library/compiler-builtins/libm/src/math/remquof.rs | 1 + library/compiler-builtins/libm/src/math/round.rs | 1 - library/compiler-builtins/libm/src/math/roundf.rs | 1 - library/compiler-builtins/libm/src/math/scalbn.rs | 1 - library/compiler-builtins/libm/src/math/scalbnf.rs | 1 - library/compiler-builtins/libm/src/math/sin.rs | 1 - library/compiler-builtins/libm/src/math/sinf.rs | 1 - library/compiler-builtins/libm/src/math/sinh.rs | 1 - library/compiler-builtins/libm/src/math/sinhf.rs | 1 - library/compiler-builtins/libm/src/math/sqrt.rs | 1 - library/compiler-builtins/libm/src/math/sqrtf.rs | 1 - library/compiler-builtins/libm/src/math/tan.rs | 1 - library/compiler-builtins/libm/src/math/tanf.rs | 1 - library/compiler-builtins/libm/src/math/tanh.rs | 1 - library/compiler-builtins/libm/src/math/tanhf.rs | 1 - library/compiler-builtins/libm/src/math/trunc.rs | 1 - library/compiler-builtins/libm/src/math/truncf.rs | 1 - 84 files changed, 2 insertions(+), 91 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/acos.rs b/library/compiler-builtins/libm/src/math/acos.rs index d5e1f6865ad..23b13251ee2 100644 --- a/library/compiler-builtins/libm/src/math/acos.rs +++ b/library/compiler-builtins/libm/src/math/acos.rs @@ -48,7 +48,6 @@ const QS2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ const QS3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ const QS4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ -#[inline] fn r(z: f64) -> f64 { let p: f64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); let q: f64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); @@ -60,7 +59,6 @@ fn r(z: f64) -> f64 { /// Computes the inverse cosine (arc cosine) of the input value. /// Arguments must be in the range -1 to 1. /// Returns values in radians, in the range of 0 to pi. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acos(x: f64) -> f64 { let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120 diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index d0598e81190..1a60479e32a 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -22,7 +22,6 @@ const P_S1: f32 = -4.2743422091e-02; const P_S2: f32 = -8.6563630030e-03; const Q_S1: f32 = -7.0662963390e-01; -#[inline] fn r(z: f32) -> f32 { let p = z * (P_S0 + z * (P_S1 + z * P_S2)); let q = 1. + z * Q_S1; @@ -34,7 +33,6 @@ fn r(z: f32) -> f32 { /// Computes the inverse cosine (arc cosine) of the input value. /// Arguments must be in the range -1 to 1. /// Returns values in radians, in the range of 0 to pi. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acosf(x: f32) -> f32 { let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs index 774475e5195..3e4b7c56eba 100644 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -55,7 +55,6 @@ const Q_S2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ const Q_S3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ -#[inline] fn comp_r(z: f64) -> f64 { let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); @@ -67,7 +66,6 @@ fn comp_r(z: f64) -> f64 { /// Computes the inverse sine (arc sine) of the argument `x`. /// Arguments to asin must be in the range -1 to 1. /// Returns values in radians, in the range of -pi/2 to pi/2. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asin(mut x: f64) -> f64 { let z: f64; diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index ce0f4a997e7..6ec61b62978 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -24,7 +24,6 @@ const P_S1: f32 = -4.2743422091e-02; const P_S2: f32 = -8.6563630030e-03; const Q_S1: f32 = -7.0662963390e-01; -#[inline] fn r(z: f32) -> f32 { let p = z * (P_S0 + z * (P_S1 + z * P_S2)); let q = 1. + z * Q_S1; @@ -36,7 +35,6 @@ fn r(z: f32) -> f32 { /// Computes the inverse sine (arc sine) of the argument `x`. /// Arguments to asin must be in the range -1 to 1. /// Returns values in radians, in the range of -pi/2 to pi/2. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asinf(mut x: f32) -> f32 { let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120) diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index d2684ece8e9..4259dc71aab 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -64,7 +64,6 @@ const AT: [f64; 11] = [ /// /// Computes the inverse tangent (arc tangent) of the input value. /// Returns a value in radians, in the range of -pi/2 to pi/2. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan(x: f64) -> f64 { let mut x = x; diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index 08385cd100e..fb2ea4edaf5 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -48,7 +48,6 @@ const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ /// Computes the inverse tangent (arc tangent) of `y/x`. /// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). /// Returns a value in radians, in the range of -pi to pi. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan2(y: f64, x: f64) -> f64 { if x.is_nan() || y.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs index 7bbe5f1d47a..eae3b002dae 100644 --- a/library/compiler-builtins/libm/src/math/atan2f.rs +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -24,7 +24,6 @@ const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ /// Computes the inverse tangent (arc tangent) of `y/x`. /// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). /// Returns a value in radians, in the range of -pi to pi. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan2f(y: f32, x: f32) -> f32 { if x.is_nan() || y.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index 363e11d647d..73f3352e9ec 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -41,7 +41,6 @@ const A_T: [f32; 5] = [ /// /// Computes the inverse tangent (arc tangent) of the input value. /// Returns a value in radians, in the range of -pi/2 to pi/2. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atanf(mut x: f32) -> f32 { let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index 04469b1598f..b4e77eaa27c 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -30,7 +30,6 @@ const P4: f64 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ // Cube root (f64) /// /// Computes the cube root of the argument. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrt(x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/cbrtf.rs b/library/compiler-builtins/libm/src/math/cbrtf.rs index 6e589c0994d..9d70305c647 100644 --- a/library/compiler-builtins/libm/src/math/cbrtf.rs +++ b/library/compiler-builtins/libm/src/math/cbrtf.rs @@ -25,7 +25,6 @@ const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ /// Cube root (f32) /// /// Computes the cube root of the argument. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrtf(x: f32) -> f32 { let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 59883a8a7b9..63c1121c6d3 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -5,7 +5,6 @@ const TOINT: f64 = 1. / f64::EPSILON; /// Ceil (f64) /// /// Finds the nearest integer greater than or equal to `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceil(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 151a4f21042..87d96982aab 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -3,7 +3,6 @@ use core::f32; /// Ceil (f32) /// /// Finds the nearest integer greater than or equal to `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceilf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs index fe5a89919b2..db8bc498926 100644 --- a/library/compiler-builtins/libm/src/math/cos.rs +++ b/library/compiler-builtins/libm/src/math/cos.rs @@ -41,7 +41,6 @@ use super::{k_cos, k_sin, rem_pio2}; // Accuracy: // TRIG(x) returns trig(x) nearly rounded // -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cos(x: f64) -> f64 { let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index 48d76c8ee0d..424fa42eda6 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -24,7 +24,6 @@ const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cosf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs index bac87556685..2fb568ab314 100644 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -7,7 +7,6 @@ use super::k_expo2; /// Computes the hyperbolic cosine of the argument x. /// Is defined as `(exp(x) + exp(-x))/2` /// Angles are specified in radians. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cosh(mut x: f64) -> f64 { /* |x| */ diff --git a/library/compiler-builtins/libm/src/math/coshf.rs b/library/compiler-builtins/libm/src/math/coshf.rs index bf99e42f09b..e7b68458788 100644 --- a/library/compiler-builtins/libm/src/math/coshf.rs +++ b/library/compiler-builtins/libm/src/math/coshf.rs @@ -7,7 +7,6 @@ use super::k_expo2f; /// Computes the hyperbolic cosine of the argument x. /// Is defined as `(exp(x) + exp(-x))/2` /// Angles are specified in radians. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn coshf(mut x: f32) -> f32 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs index 5465b569346..5b163f95427 100644 --- a/library/compiler-builtins/libm/src/math/exp.rs +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -81,7 +81,6 @@ const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ /// /// Calculate the exponential of `x`, that is, *e* raised to the power `x` /// (where *e* is the base of the natural system of logarithms, approximately 2.71828). -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp(mut x: f64) -> f64 { let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index c2192fde5a0..8ea434dcadb 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -322,7 +322,6 @@ static TBL: [u64; TBLSIZE * 2] = [ /// Exponential, base 2 (f64) /// /// Calculate `2^x`, that is, 2 raised to the power `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp2(mut x: f64) -> f64 { let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64; diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index 12c9e76a4c7..8a890b832e9 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -73,7 +73,6 @@ static EXP2FT: [u64; TBLSIZE] = [ /// Exponential, base 2 (f32) /// /// Calculate `2^x`, that is, 2 raised to the power `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp2f(mut x: f32) -> f32 { let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index 09323ec8de2..47c1b2c467e 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -30,7 +30,6 @@ const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ /// /// Calculate the exponential of `x`, that is, *e* raised to the power `x` /// (where *e* is the base of the natural system of logarithms, approximately 2.71828). -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expf(mut x: f32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs index 0d43b4e103d..42608509a40 100644 --- a/library/compiler-builtins/libm/src/math/expm1.rs +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -30,7 +30,6 @@ const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ /// system of logarithms, approximately 2.71828). /// The result is accurate even for small values of `x`, /// where using `exp(x)-1` would lose many significant digits. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expm1(mut x: f64) -> f64 { let hi: f64; diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs index 9bb22344889..3fc2a247b5b 100644 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -32,7 +32,6 @@ const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ /// system of logarithms, approximately 2.71828). /// The result is accurate even for small values of `x`, /// where using `exp(x)-1` would lose many significant digits. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expm1f(mut x: f32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs index ae6cc8121e0..82e9b360a76 100644 --- a/library/compiler-builtins/libm/src/math/expo2.rs +++ b/library/compiler-builtins/libm/src/math/expo2.rs @@ -1,7 +1,6 @@ use super::{combine_words, exp}; /* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn expo2(x: f64) -> f64 { /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 52a9adcbff1..5a7f795f6a3 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -3,7 +3,6 @@ use core::u64; /// Absolute value (magnitude) (f64) /// Calculates the absolute value (magnitude) of the argument `x`, /// by direct manipulation of the bit representation of `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabs(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 5942d983a4b..495512584d2 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -1,7 +1,6 @@ /// Absolute value (magnitude) (f32) /// Calculates the absolute value (magnitude) of the argument `x`, /// by direct manipulation of the bit representation of `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabsf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index 06edc996035..014930097a0 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -8,7 +8,6 @@ use core::f64; /// * NAN if either argument is NAN. /// /// A range error may occur. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdim(x: f64, y: f64) -> f64 { if x.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index f1ad5896bf9..ea0b592d7ab 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -8,7 +8,6 @@ use core::f32; /// * NAN if either argument is NAN. /// /// A range error may occur. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdimf(x: f32, y: f32) -> f32 { if x.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index f6068c697ac..91825e3c88f 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -5,7 +5,6 @@ const TOINT: f64 = 1. / f64::EPSILON; /// Floor (f64) /// /// Finds the nearest integer less than or equal to `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floor(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index c04f18aeeea..6d751b077ef 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -3,7 +3,6 @@ use core::f32; /// Floor (f32) /// /// Finds the nearest integer less than or equal to `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floorf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 07d90f8b727..5ea0d09ea9f 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -10,7 +10,6 @@ struct Num { sign: i32, } -#[inline] fn normalize(x: f64) -> Num { let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 @@ -30,7 +29,6 @@ fn normalize(x: f64) -> Num { Num { m: ix, e, sign } } -#[inline] fn mul(x: u64, y: u64) -> (u64, u64) { let t1: u64; let t2: u64; @@ -53,7 +51,6 @@ fn mul(x: u64, y: u64) -> (u64, u64) { /// Computes `(x*y)+z`, rounded as one ternary operation: /// Computes the value (as if) to infinite precision and rounds once to the result format, /// according to the rounding mode characterized by the value of FLT_ROUNDS. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fma(x: f64, y: f64, z: f64) -> f64 { let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index e77e0fa4a25..03d371c55f2 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -46,7 +46,6 @@ use super::fenv::{ /// Computes `(x*y)+z`, rounded as one ternary operation: /// Computes the value (as if) to infinite precision and rounds once to the result format, /// according to the rounding mode characterized by the value of FLT_ROUNDS. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { let xy: f64; diff --git a/library/compiler-builtins/libm/src/math/fmax.rs b/library/compiler-builtins/libm/src/math/fmax.rs index 22016d11cc6..93c97bc611c 100644 --- a/library/compiler-builtins/libm/src/math/fmax.rs +++ b/library/compiler-builtins/libm/src/math/fmax.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmax(x: f64, y: f64) -> f64 { // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the diff --git a/library/compiler-builtins/libm/src/math/fmaxf.rs b/library/compiler-builtins/libm/src/math/fmaxf.rs index a883fdaef5b..60774664752 100644 --- a/library/compiler-builtins/libm/src/math/fmaxf.rs +++ b/library/compiler-builtins/libm/src/math/fmaxf.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaxf(x: f32, y: f32) -> f32 { // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the diff --git a/library/compiler-builtins/libm/src/math/fmin.rs b/library/compiler-builtins/libm/src/math/fmin.rs index d1ccc3a4680..ab1509f34a6 100644 --- a/library/compiler-builtins/libm/src/math/fmin.rs +++ b/library/compiler-builtins/libm/src/math/fmin.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmin(x: f64, y: f64) -> f64 { // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the diff --git a/library/compiler-builtins/libm/src/math/fminf.rs b/library/compiler-builtins/libm/src/math/fminf.rs index 43ec97cb5b5..0049e7117ae 100644 --- a/library/compiler-builtins/libm/src/math/fminf.rs +++ b/library/compiler-builtins/libm/src/math/fminf.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fminf(x: f32, y: f32) -> f32 { // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs index 2cdd8a9ba3f..d892ffd8b72 100644 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -1,6 +1,5 @@ use core::u64; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmod(x: f64, y: f64) -> f64 { let mut uxi = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index 3e6779a9304..c53dc186aeb 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -1,7 +1,6 @@ use core::f32; use core::u32; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmodf(x: f32, y: f32) -> f32 { let mut uxi = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs index e53baf53994..da458ea1d05 100644 --- a/library/compiler-builtins/libm/src/math/hypot.rs +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -4,7 +4,6 @@ use super::sqrt; const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 -#[inline] fn sq(x: f64) -> (f64, f64) { let xh: f64; let xl: f64; @@ -18,7 +17,6 @@ fn sq(x: f64) -> (f64, f64) { (hi, lo) } -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn hypot(mut x: f64, mut y: f64) -> f64 { let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700 diff --git a/library/compiler-builtins/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/src/math/hypotf.rs index 4636b8f1d8b..576eebb3343 100644 --- a/library/compiler-builtins/libm/src/math/hypotf.rs +++ b/library/compiler-builtins/libm/src/math/hypotf.rs @@ -2,7 +2,6 @@ use core::f32; use super::sqrtf; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn hypotf(mut x: f32, mut y: f32) -> f32 { let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90 diff --git a/library/compiler-builtins/libm/src/math/k_cos.rs b/library/compiler-builtins/libm/src/math/k_cos.rs index 4687b369a61..49b2fc64d86 100644 --- a/library/compiler-builtins/libm/src/math/k_cos.rs +++ b/library/compiler-builtins/libm/src/math/k_cos.rs @@ -51,7 +51,6 @@ const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ // expression for cos(). Retention happens in all cases tested // under FreeBSD, so don't pessimize things by forcibly clipping // any extra precision in w. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_cos(x: f64, y: f64) -> f64 { let z = x * x; diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs index 79d0f238fce..e99f2348c00 100644 --- a/library/compiler-builtins/libm/src/math/k_cosf.rs +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -20,7 +20,6 @@ const C1: f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_cosf(x: f64) -> f32 { let z = x * x; diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs index 0a9562eaeaa..7345075f376 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2.rs @@ -4,7 +4,6 @@ use super::exp; const K: i32 = 2043; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_expo2(x: f64) -> f64 { let k_ln2 = f64::from_bits(0x40962066151add8b); diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs index de850777259..fbd7b27d583 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2f.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -4,7 +4,6 @@ use super::expf; const K: i32 = 235; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_expo2f(x: f32) -> f32 { let k_ln2 = f32::from_bits(0x4322e3bc); diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs index 5d2bd68aa95..9dd96c94474 100644 --- a/library/compiler-builtins/libm/src/math/k_sin.rs +++ b/library/compiler-builtins/libm/src/math/k_sin.rs @@ -43,7 +43,6 @@ const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ // r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) // then 3 2 // sin(x) = x + (S1*x + (x *(r-y/2)+y)) -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { let z = x * x; diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs index 68fe926c217..88d10cababc 100644 --- a/library/compiler-builtins/libm/src/math/k_sinf.rs +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -20,7 +20,6 @@ const S2: f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_sinf(x: f64) -> f32 { let z = x * x; diff --git a/library/compiler-builtins/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/src/math/k_tan.rs index ea3c386b002..d177010bb0a 100644 --- a/library/compiler-builtins/libm/src/math/k_tan.rs +++ b/library/compiler-builtins/libm/src/math/k_tan.rs @@ -58,7 +58,6 @@ static T: [f64; 13] = [ const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { let hx = (f64::to_bits(x) >> 32) as u32; @@ -101,7 +100,6 @@ pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { a0 + a * (1.0 + a0 * w0 + a0 * v) } -#[inline] fn zero_low_word(x: f64) -> f64 { f64::from_bits(f64::to_bits(x) & 0xFFFF_FFFF_0000_0000) } diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs index 52651378db5..af8db539dad 100644 --- a/library/compiler-builtins/libm/src/math/k_tanf.rs +++ b/library/compiler-builtins/libm/src/math/k_tanf.rs @@ -19,7 +19,6 @@ const T: [f64; 6] = [ 0.00946564784943673166728, /* 0x1362b9bf971bcd.0p-59 */ ]; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { let z = x * x; diff --git a/library/compiler-builtins/libm/src/math/ldexp.rs b/library/compiler-builtins/libm/src/math/ldexp.rs index 780ddfc1165..e46242e55b2 100644 --- a/library/compiler-builtins/libm/src/math/ldexp.rs +++ b/library/compiler-builtins/libm/src/math/ldexp.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ldexp(x: f64, n: i32) -> f64 { super::scalbn(x, n) diff --git a/library/compiler-builtins/libm/src/math/ldexpf.rs b/library/compiler-builtins/libm/src/math/ldexpf.rs index 70935a0024e..95b27fc49d2 100644 --- a/library/compiler-builtins/libm/src/math/ldexpf.rs +++ b/library/compiler-builtins/libm/src/math/ldexpf.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ldexpf(x: f32, n: i32) -> f32 { super::scalbnf(x, n) diff --git a/library/compiler-builtins/libm/src/math/log.rs b/library/compiler-builtins/libm/src/math/log.rs index 4126e413b77..27a26da60a9 100644 --- a/library/compiler-builtins/libm/src/math/log.rs +++ b/library/compiler-builtins/libm/src/math/log.rs @@ -70,7 +70,6 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs index c99696040ab..40dacf2c916 100644 --- a/library/compiler-builtins/libm/src/math/log10.rs +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -31,7 +31,6 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs index 9845cda5d95..108dfa8b508 100644 --- a/library/compiler-builtins/libm/src/math/log10f.rs +++ b/library/compiler-builtins/libm/src/math/log10f.rs @@ -25,7 +25,6 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index cd7045ac97e..4fd1c73eb81 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -65,7 +65,6 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1p(x: f64) -> f64 { let mut ui: u64 = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index 8e9651357d1..500e8eeaa85 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -20,7 +20,6 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1pf(x: f32) -> f32 { let mut ui: u32 = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index a3d43e55c2b..83da3a19366 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -29,7 +29,6 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs index 53a37e50337..3a20fb15bd6 100644 --- a/library/compiler-builtins/libm/src/math/log2f.rs +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -23,7 +23,6 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs index 95195601c2d..2b57b934fb9 100644 --- a/library/compiler-builtins/libm/src/math/logf.rs +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -21,7 +21,6 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn logf(mut x: f32) -> f32 { let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/src/math/nextafter.rs index 4c1257e0027..13094a17c34 100644 --- a/library/compiler-builtins/libm/src/math/nextafter.rs +++ b/library/compiler-builtins/libm/src/math/nextafter.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn nextafter(x: f64, y: f64) -> f64 { if x.is_nan() || y.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/nextafterf.rs b/library/compiler-builtins/libm/src/math/nextafterf.rs index a48bce9f742..df9b1082978 100644 --- a/library/compiler-builtins/libm/src/math/nextafterf.rs +++ b/library/compiler-builtins/libm/src/math/nextafterf.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn nextafterf(x: f32, y: f32) -> f32 { if x.is_nan() || y.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 068a4ec47d4..ce8e83ee6f8 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -89,7 +89,6 @@ const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn pow(x: f64, y: f64) -> f64 { let t1: f64; diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index 015bade86c9..f3cf76f9aa6 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -43,7 +43,6 @@ const IVLN2: f32 = 1.4426950216e+00; const IVLN2_H: f32 = 1.4426879883e+00; const IVLN2_L: f32 = 7.0526075433e-06; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn powf(x: f32, y: f32) -> f32 { let mut z: f32; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index dc6b3297d93..6b7dbd348c6 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -41,7 +41,6 @@ const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ // use rem_pio2_large() for large x // // caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { let x1p24 = f64::from_bits(0x4170000000000000); @@ -49,7 +48,6 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { let sign = (f64::to_bits(x) >> 63) as i32; let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; - #[inline] fn medium(x: f64, ix: u32) -> (i32, f64, f64) { /* rint(x/(pi/2)), Assume round-to-nearest. */ let f_n = x as f64 * INV_PIO2 + TO_INT - TO_INT; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 5336a976719..8533dc28948 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -222,7 +222,6 @@ const PIO2: [f64; 8] = [ /// skip the part of the product that are known to be a huge integer ( /// more accurately, = 0 mod 8 ). Thus the number of operations are /// independent of the exponent of the input. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index af2745d1be9..5d392ba2d7f 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -31,7 +31,6 @@ const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ /// /// use double precision for everything except passing x /// use __rem_pio2_large() for large x -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/remainder.rs b/library/compiler-builtins/libm/src/math/remainder.rs index 7ce895004b8..9e966c9ed7f 100644 --- a/library/compiler-builtins/libm/src/math/remainder.rs +++ b/library/compiler-builtins/libm/src/math/remainder.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn remainder(x: f64, y: f64) -> f64 { let (result, _) = super::remquo(x, y); diff --git a/library/compiler-builtins/libm/src/math/remainderf.rs b/library/compiler-builtins/libm/src/math/remainderf.rs index 8b2aa5aabbc..b1407cf2ace 100644 --- a/library/compiler-builtins/libm/src/math/remainderf.rs +++ b/library/compiler-builtins/libm/src/math/remainderf.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn remainderf(x: f32, y: f32) -> f32 { let (result, _) = super::remquof(x, y); diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs index c72c8f1878e..0afd1f7f5f2 100644 --- a/library/compiler-builtins/libm/src/math/remquo.rs +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -1,3 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { let ux: u64 = x.to_bits(); let mut uy: u64 = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs index 871d0c7d696..d71bd38e3dd 100644 --- a/library/compiler-builtins/libm/src/math/remquof.rs +++ b/library/compiler-builtins/libm/src/math/remquof.rs @@ -1,3 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { let ux: u32 = x.to_bits(); let mut uy: u32 = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 67590d2c19b..bf72f5b941d 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -2,7 +2,6 @@ use core::f64; const TOINT: f64 = 1.0 / f64::EPSILON; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn round(mut x: f64) -> f64 { let i = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index 85114be4ba1..497e88d6254 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -2,7 +2,6 @@ use core::f32; const TOINT: f32 = 1.0 / f32::EPSILON; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundf(mut x: f32) -> f32 { let i = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs index d8c8409ac10..00c455a1065 100644 --- a/library/compiler-builtins/libm/src/math/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbn(x: f64, mut n: i32) -> f64 { let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs index 4e9771175d2..73f4bb57aaf 100644 --- a/library/compiler-builtins/libm/src/math/scalbnf.rs +++ b/library/compiler-builtins/libm/src/math/scalbnf.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index 51aed88a8db..1329b41a9d6 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -40,7 +40,6 @@ use super::{k_cos, k_sin, rem_pio2}; // // Accuracy: // TRIG(x) returns trig(x) nearly rounded -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sin(x: f64) -> f64 { let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs index 0c31099edd2..6e20be2aeee 100644 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -24,7 +24,6 @@ const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs index d36de66c1c0..fd24fd20cf7 100644 --- a/library/compiler-builtins/libm/src/math/sinh.rs +++ b/library/compiler-builtins/libm/src/math/sinh.rs @@ -4,7 +4,6 @@ use super::{expm1, expo2}; // = (exp(x)-1 + (exp(x)-1)/exp(x))/2 // = x + x^3/6 + o(x^5) // -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinh(x: f64) -> f64 { // union {double f; uint64_t i;} u = {.f = x}; diff --git a/library/compiler-builtins/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/src/math/sinhf.rs index fd0b2bfc894..24f863c4465 100644 --- a/library/compiler-builtins/libm/src/math/sinhf.rs +++ b/library/compiler-builtins/libm/src/math/sinhf.rs @@ -1,7 +1,6 @@ use super::expm1f; use super::k_expo2f; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinhf(x: f32) -> f32 { let mut h = 0.5f32; diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 14404d4eb18..58cf00ed888 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -81,7 +81,6 @@ use core::num::Wrapping; const TINY: f64 = 1.0e-300; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index b9365c61716..889b5258122 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -15,7 +15,6 @@ const TINY: f32 = 1.0e-30; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs index e5c94cbb156..5a72f68014a 100644 --- a/library/compiler-builtins/libm/src/math/tan.rs +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -39,7 +39,6 @@ use super::{k_tan, rem_pio2}; // // Accuracy: // TRIG(x) returns trig(x) nearly rounded -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tan(x: f64) -> f64 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs index c286cdeb419..10de59c3917 100644 --- a/library/compiler-builtins/libm/src/math/tanf.rs +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -24,7 +24,6 @@ const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs index 75d695cf7e9..980c68554fd 100644 --- a/library/compiler-builtins/libm/src/math/tanh.rs +++ b/library/compiler-builtins/libm/src/math/tanh.rs @@ -4,7 +4,6 @@ use super::expm1; * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanh(mut x: f64) -> f64 { let mut uf: f64 = x; diff --git a/library/compiler-builtins/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/src/math/tanhf.rs index ac4657b5abd..fc94e3ddd58 100644 --- a/library/compiler-builtins/libm/src/math/tanhf.rs +++ b/library/compiler-builtins/libm/src/math/tanhf.rs @@ -1,6 +1,5 @@ use super::expm1f; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanhf(mut x: f32) -> f32 { /* x = |x| */ diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 1ee46fc7dae..f7892a2c553 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -1,6 +1,5 @@ use core::f64; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn trunc(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index f9338326905..a4c001629a2 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -1,6 +1,5 @@ use core::f32; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn truncf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized -- cgit 1.4.1-3-g733a5 From c2b0bbb814544d8c8ccc662b6294948629f0ceb6 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 10 Jul 2019 13:01:02 +0200 Subject: Fix overflow bug in fma --- library/compiler-builtins/libm/src/math/fma.rs | 4 ++-- library/compiler-builtins/libm/tests/unit.rs | 19 ------------------- 2 files changed, 2 insertions(+), 21 deletions(-) delete mode 100644 library/compiler-builtins/libm/tests/unit.rs diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 6d4471a9a04..99f77bc7967 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -126,8 +126,8 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { } else { /* r -= z */ let t = rlo; - rlo -= zlo; - rhi = rhi - zhi - (t < rlo) as u64; + rlo = rlo.wrapping_sub(zlo); + rhi = rhi.wrapping_sub(zhi.wrapping_sub((t < rlo) as u64)); if (rhi >> 63) != 0 { rlo = (-(rlo as i64)) as u64; rhi = (-(rhi as i64)) as u64 - (rlo != 0) as u64; diff --git a/library/compiler-builtins/libm/tests/unit.rs b/library/compiler-builtins/libm/tests/unit.rs deleted file mode 100644 index 4e7002817a6..00000000000 --- a/library/compiler-builtins/libm/tests/unit.rs +++ /dev/null @@ -1,19 +0,0 @@ -use libm::*; - -#[test] -fn fma_segfault() { - // These two inputs cause fma to segfault on release due to overflow: - assert_eq!( - fma( - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313 - ), - -0.00000000000000022204460492503126, - ); - - assert_eq!( - fma(-0.992, -0.992, -0.992), - -0.00793599999988632, - ); -} -- cgit 1.4.1-3-g733a5 From f4bc012b26ead3e50d25e1f878b7447a058d447c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jul 2019 10:55:54 +0200 Subject: avoid ptr::write which might panic in debug mode --- library/compiler-builtins/src/arm.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 9bfffb74fc9..ab35ec92b24 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -137,11 +137,12 @@ pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: us pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) { use core::ptr; + // We are guaranteed 4-alignment, so accessing at u32 is okay. let mut dest = dest as *mut u32; let mut src = src as *mut u32; while n >= 4 { - ptr::write(dest, ptr::read(src)); + *dest = *src; dest = dest.offset(1); src = src.offset(1); n -= 4; @@ -198,7 +199,7 @@ pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32 let c = (byte << 24) | (byte << 16) | (byte << 8) | byte; while n >= 4 { - ptr::write(dest, c); + *dest = c; dest = dest.offset(1); n -= 4; } -- cgit 1.4.1-3-g733a5 From 29ea38c623296267d568ad18a4818c6808dcd93c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jul 2019 11:00:15 +0200 Subject: remove unused imports --- library/compiler-builtins/src/arm.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index ab35ec92b24..4cf73ef37ac 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -135,8 +135,6 @@ pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: us #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) { - use core::ptr; - // We are guaranteed 4-alignment, so accessing at u32 is okay. let mut dest = dest as *mut u32; let mut src = src as *mut u32; @@ -191,8 +189,6 @@ pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) { - use core::ptr; - let mut dest = dest as *mut u32; let byte = (c as u32) & 0xff; -- cgit 1.4.1-3-g733a5 From 8ae096b54455b84e6a36ecef05215163b5fd1f08 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jul 2019 11:07:43 +0200 Subject: avoid bare trait objects --- library/compiler-builtins/examples/intrinsics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index f6980fcb566..8b0ffa3a8d6 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -350,8 +350,8 @@ fn run() { // } } -fn something_with_a_dtor(f: &Fn()) { - struct A<'a>(&'a (Fn() + 'a)); +fn something_with_a_dtor(f: &dyn Fn()) { + struct A<'a>(&'a (dyn Fn() + 'a)); impl<'a> Drop for A<'a> { fn drop(&mut self) { -- cgit 1.4.1-3-g733a5 From 8bd3e4d5a18facf044f0c740db44605dd2bdc69f Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 13 Jul 2019 11:38:35 +0200 Subject: Replace {u,i}128_* lang items with __rust_{u,i}128_* unmangled functions The -Zlower-128bit-ops feature is completely broken, as libcore needs those lang items to compile with this feature, but they are only provided by compiler_builtins, which itself depends on libcore. According to rust-lang/rust#58969 the feature never got finished. This commit removes the associated lang items and replaces them with normal unmangled functions, when there is no existing intrinsic. This makes it easier for alternative codegen backends to implement 128bit integer support. --- library/compiler-builtins/src/int/addsub.rs | 37 +++++++++++++------------- library/compiler-builtins/src/int/mul.rs | 17 +++--------- library/compiler-builtins/src/int/sdiv.rs | 11 -------- library/compiler-builtins/src/int/shift.rs | 40 ++++++++--------------------- library/compiler-builtins/src/int/udiv.rs | 11 -------- library/compiler-builtins/src/macros.rs | 14 ---------- 6 files changed, 31 insertions(+), 99 deletions(-) diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs index e2d5bcbd435..0a88e2fc8f1 100644 --- a/library/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/src/int/addsub.rs @@ -90,44 +90,43 @@ where impl Subo for i128 {} impl Subo for u128 {} -u128_lang_items! { - #[lang = "i128_add"] - pub fn rust_i128_add(a: i128, b: i128) -> i128 { - rust_u128_add(a as _, b as _) as _ +intrinsics! { + pub extern "C" fn __rust_i128_add(a: i128, b: i128) -> i128 { + __rust_u128_add(a as _, b as _) as _ } - #[lang = "i128_addo"] - pub fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { + + pub extern "C" fn __rust_i128_addo(a: i128, b: i128) -> (i128, bool) { let mut oflow = 0; let r = a.addo(b, &mut oflow); (r, oflow != 0) } - #[lang = "u128_add"] - pub fn rust_u128_add(a: u128, b: u128) -> u128 { + + pub extern "C" fn __rust_u128_add(a: u128, b: u128) -> u128 { a.add(b) } - #[lang = "u128_addo"] - pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { + + pub extern "C" fn __rust_u128_addo(a: u128, b: u128) -> (u128, bool) { let mut oflow = 0; let r = a.addo(b, &mut oflow); (r, oflow != 0) } - #[lang = "i128_sub"] - pub fn rust_i128_sub(a: i128, b: i128) -> i128 { - rust_u128_sub(a as _, b as _) as _ + + pub extern "C" fn __rust_i128_sub(a: i128, b: i128) -> i128 { + __rust_u128_sub(a as _, b as _) as _ } - #[lang = "i128_subo"] - pub fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { + + pub extern "C" fn __rust_i128_subo(a: i128, b: i128) -> (i128, bool) { let mut oflow = 0; let r = a.subo(b, &mut oflow); (r, oflow != 0) } - #[lang = "u128_sub"] - pub fn rust_u128_sub(a: u128, b: u128) -> u128 { + + pub extern "C" fn __rust_u128_sub(a: u128, b: u128) -> u128 { a.sub(b) } - #[lang = "u128_subo"] - pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { + + pub extern "C" fn __rust_u128_subo(a: u128, b: u128) -> (u128, bool) { let mut oflow = 0; let r = a.subo(b, &mut oflow); (r, oflow != 0) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 8df58a27b6a..42f13913e3e 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -107,25 +107,14 @@ intrinsics! { pub extern "C" fn __muloti4(a: i128, b: i128, oflow: &mut i32) -> i128 { a.mulo(b, oflow) } -} -u128_lang_items! { - #[lang = "i128_mul"] - pub fn rust_i128_mul(a: i128, b: i128) -> i128 { - __multi3(a, b) - } - #[lang = "i128_mulo"] - pub fn rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { + pub extern "C" fn __rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { let mut oflow = 0; let r = __muloti4(a, b, &mut oflow); (r, oflow != 0) } - #[lang = "u128_mul"] - pub fn rust_u128_mul(a: u128, b: u128) -> u128 { - __multi3(a as _, b as _) as _ - } - #[lang = "u128_mulo"] - pub fn rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { + + pub extern "C" fn __rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { let mut oflow = 0; let r = a.mulo(b, &mut oflow); (r, oflow != 0) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index ad7f67b1b4c..c9e252cc3b0 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -99,14 +99,3 @@ intrinsics! { a.divmod(b, rem, |a, b| __divdi3(a, b)) } } - -u128_lang_items! { - #[lang = "i128_div"] - pub fn rust_i128_div(a: i128, b: i128) -> i128 { - __divti3(a, b) - } - #[lang = "i128_rem"] - pub fn rust_i128_rem(a: i128, b: i128) -> i128 { - __modti3(a, b) - } -} diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index d98622279e7..408f8f3ccbb 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -103,40 +103,20 @@ intrinsics! { pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 { a.lshr(b) } -} -u128_lang_items! { - #[lang = "i128_shl"] - pub fn rust_i128_shl(a: i128, b: u32) -> i128 { - __ashlti3(a as _, b) as _ - } - #[lang = "i128_shlo"] - pub fn rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { - (rust_i128_shl(a, b as _), b >= 128) - } - #[lang = "u128_shl"] - pub fn rust_u128_shl(a: u128, b: u32) -> u128 { - __ashlti3(a, b) - } - #[lang = "u128_shlo"] - pub fn rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { - (rust_u128_shl(a, b as _), b >= 128) + pub extern "C" fn __rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { + (__ashlti3(a as _, b as _) as _, b >= 128) } - #[lang = "i128_shr"] - pub fn rust_i128_shr(a: i128, b: u32) -> i128 { - __ashrti3(a, b) + pub extern "C" fn __rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { + (__ashlti3(a, b as _), b >= 128) } - #[lang = "i128_shro"] - pub fn rust_i128_shro(a: i128, b: u128) -> (i128, bool) { - (rust_i128_shr(a, b as _), b >= 128) - } - #[lang = "u128_shr"] - pub fn rust_u128_shr(a: u128, b: u32) -> u128 { - __lshrti3(a, b) + + pub extern "C" fn __rust_i128_shro(a: i128, b: u128) -> (i128, bool) { + (__ashrti3(a, b as _), b >= 128) } - #[lang = "u128_shro"] - pub fn rust_u128_shro(a: u128, b: u128) -> (u128, bool) { - (rust_u128_shr(a, b as _), b >= 128) + + pub extern "C" fn __rust_u128_shro(a: u128, b: u128) -> (u128, bool) { + (__lshrti3(a, b as _), b >= 128) } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index cdec11d2f16..b393ac6db12 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -268,14 +268,3 @@ intrinsics! { udivmod_inner!(n, d, rem, u128) } } - -u128_lang_items! { - #[lang = "u128_div"] - pub fn rust_u128_div(a: u128, b: u128) -> u128 { - __udivti3(a, b) - } - #[lang = "u128_rem"] - pub fn rust_u128_rem(a: u128, b: u128) -> u128 { - __umodti3(a, b) - } -} diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 4abdae6eee0..2d11ba622b8 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -280,17 +280,3 @@ pub mod win64_128bit_abi_hack { } } } - -macro_rules! u128_lang_items { - ($( - #[lang = $lang:tt] - pub fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { - $($body:tt)* - } - )*) => ($( - #[cfg_attr(not(any(stage0, feature = "no-lang-items")), lang = $lang)] - pub fn $name( $($argname: $ty),* ) -> $ret { - $($body)* - } - )*) -} -- cgit 1.4.1-3-g733a5 From 4ca09454a8603715d51a4ff4c3ea40e020a9949d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 13 Jul 2019 12:27:58 +0200 Subject: Fix tests --- library/compiler-builtins/testcrate/build.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index e43fdb77b88..4bd4005b705 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -707,35 +707,35 @@ fn main() { // int/addsub.rs gen( |(a, b): (MyU128, MyU128)| Some(a.0.wrapping_add(b.0)), - "builtins::int::addsub::rust_u128_add(a, b)", + "builtins::int::addsub::__rust_u128_add(a, b)", ); gen( |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_add(b.0)), - "builtins::int::addsub::rust_i128_add(a, b)", + "builtins::int::addsub::__rust_i128_add(a, b)", ); gen( |(a, b): (MyU128, MyU128)| Some(a.0.overflowing_add(b.0)), - "builtins::int::addsub::rust_u128_addo(a, b)", + "builtins::int::addsub::__rust_u128_addo(a, b)", ); gen( |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_add(b.0)), - "builtins::int::addsub::rust_i128_addo(a, b)", + "builtins::int::addsub::__rust_i128_addo(a, b)", ); gen( |(a, b): (MyU128, MyU128)| Some(a.0.wrapping_sub(b.0)), - "builtins::int::addsub::rust_u128_sub(a, b)", + "builtins::int::addsub::__rust_u128_sub(a, b)", ); gen( |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_sub(b.0)), - "builtins::int::addsub::rust_i128_sub(a, b)", + "builtins::int::addsub::__rust_i128_sub(a, b)", ); gen( |(a, b): (MyU128, MyU128)| Some(a.0.overflowing_sub(b.0)), - "builtins::int::addsub::rust_u128_subo(a, b)", + "builtins::int::addsub::__rust_u128_subo(a, b)", ); gen( |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_sub(b.0)), - "builtins::int::addsub::rust_i128_subo(a, b)", + "builtins::int::addsub::__rust_i128_subo(a, b)", ); // int/mul.rs -- cgit 1.4.1-3-g733a5 From 7773dafe014c407b6e01fb342e2af282ddaf9422 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 15 Jul 2019 07:26:49 -0700 Subject: Bump to 0.1.17 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index e0bb22d218a..fed7beead7f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.16" +version = "0.1.17" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From fb3519099873118e14312d8fb469c464e10558fc Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 19 Jul 2019 07:44:17 -0700 Subject: Bump to 0.1.18 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index fed7beead7f..1436d9b4def 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.17" +version = "0.1.18" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 84e8cc74c57190a1c4321a3db7b6a9a5c9a626a1 Mon Sep 17 00:00:00 2001 From: Dan Aloni Date: Wed, 24 Jul 2019 08:59:54 +0300 Subject: probestack: add frame pointers for easier traceback This turns the following backtrace, ``` >> bt #0 0x0000555555576f73 in __rust_probestack () at /cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.14/src/probestack.rs:55 Backtrace stopped: Cannot access memory at address 0x7fffff7fedf0 ``` To this: ``` >>> bt #0 0x0000555555574e47 in __rust_probestack () #1 0x00005555555595ba in test::main () #2 0x00005555555594f3 in std::rt::lang_start::{{closure}} () #3 0x0000555555561ae3 in std::panicking::try::do_call () #4 0x000055555556595a in __rust_maybe_catch_panic () #5 0x000055555555af9b in std::rt::lang_start_internal () #6 0x00005555555594d5 in std::rt::lang_start () #7 0x000055555555977b in main () ``` --- library/compiler-builtins/src/probestack.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index f9284e81405..9bcaf4fd13d 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -53,6 +53,9 @@ pub unsafe extern "C" fn __rust_probestack() { // The ABI here is that the stack frame size is located in `%eax`. Upon // return we're not supposed to modify `%esp` or `%eax`. asm!(" + pushq %rbp + movq %rsp, %rbp + mov %rax,%r11 // duplicate %rax as we're clobbering %r11 // Main loop, taken in one page increments. We're decrementing rsp by @@ -89,6 +92,7 @@ pub unsafe extern "C" fn __rust_probestack() { // return. add %rax,%rsp + leave ret " ::: "memory" : "volatile"); ::core::intrinsics::unreachable(); @@ -104,6 +108,8 @@ pub unsafe extern "C" fn __rust_probestack() { // // The ABI here is the same as x86_64, except everything is 32-bits large. asm!(" + push %ebp + mov %esp, %ebp push %ecx mov %eax,%ecx @@ -122,6 +128,7 @@ pub unsafe extern "C" fn __rust_probestack() { add %eax,%esp pop %ecx + leave ret " ::: "memory" : "volatile"); ::core::intrinsics::unreachable(); -- cgit 1.4.1-3-g733a5 From 8b76d4463610c07f2018fc8c22ef4be29df678d5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 24 Jul 2019 07:05:29 -0700 Subject: Bump to 0.1.19 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 1436d9b4def..0705dbd9c32 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.18" +version = "0.1.19" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" -- cgit 1.4.1-3-g733a5 From d19e47014ac1aa1e6f0d1b60753caef7dfd8db3c Mon Sep 17 00:00:00 2001 From: Lokathor Date: Wed, 7 Aug 2019 14:06:12 -0600 Subject: Improve sqrt/sqrtf if stable intrinsics allow --- library/compiler-builtins/libm/src/math/sqrt.rs | 252 ++++++++++++----------- library/compiler-builtins/libm/src/math/sqrtf.rs | 160 +++++++------- 2 files changed, 224 insertions(+), 188 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 58cf00ed888..f01267da727 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -95,128 +95,146 @@ pub fn sqrt(x: f64) -> f64 { } } } - let mut z: f64; - let sign: Wrapping = Wrapping(0x80000000); - let mut ix0: i32; - let mut s0: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: Wrapping; - let mut t1: Wrapping; - let mut s1: Wrapping; - let mut ix1: Wrapping; - let mut q1: Wrapping; + #[cfg(target_feature="sse2")] + { + // Note(Lokathor): If compile time settings allow, we just use SSE2, since + // the sqrt in `std` on these platforms also compiles down to an SSE2 + // instruction. + #[cfg(target_arch="x86")] + use core::arch::x86::*; + #[cfg(target_arch="x86_64")] + use core::arch::x86_64::*; + unsafe { + let m = _mm_set_sd(x); + let m_sqrt = _mm_sqrt_pd(m); + _mm_cvtsd_f64(m_sqrt) + } + } + #[cfg(not(target_feature="sse2"))] + { + let mut z: f64; + let sign: Wrapping = Wrapping(0x80000000); + let mut ix0: i32; + let mut s0: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: Wrapping; + let mut t1: Wrapping; + let mut s1: Wrapping; + let mut ix1: Wrapping; + let mut q1: Wrapping; - ix0 = (x.to_bits() >> 32) as i32; - ix1 = Wrapping(x.to_bits() as u32); + ix0 = (x.to_bits() >> 32) as i32; + ix1 = Wrapping(x.to_bits() as u32); - /* take care of Inf and NaN */ - if (ix0 & 0x7ff00000) == 0x7ff00000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } - /* take care of zero */ - if ix0 <= 0 { - if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix0 < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } - /* normalize x */ - m = ix0 >> 20; - if m == 0 { - /* subnormal x */ - while ix0 == 0 { - m -= 21; - ix0 |= (ix1 >> 11).0 as i32; - ix1 <<= 21; - } - i = 0; - while (ix0 & 0x00100000) == 0 { - i += 1; - ix0 <<= 1; - } - m -= i - 1; - ix0 |= (ix1 >> (32 - i) as usize).0 as i32; - ix1 = ix1 << i as usize; - } - m -= 1023; /* unbias exponent */ - ix0 = (ix0 & 0x000fffff) | 0x00100000; - if (m & 1) == 1 { - /* odd m, double x to make it even */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - } - m >>= 1; /* m = [m/2] */ + /* take care of Inf and NaN */ + if (ix0 & 0x7ff00000) == 0x7ff00000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if ix0 <= 0 { + if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix0 < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } + /* normalize x */ + m = ix0 >> 20; + if m == 0 { + /* subnormal x */ + while ix0 == 0 { + m -= 21; + ix0 |= (ix1 >> 11).0 as i32; + ix1 <<= 21; + } + i = 0; + while (ix0 & 0x00100000) == 0 { + i += 1; + ix0 <<= 1; + } + m -= i - 1; + ix0 |= (ix1 >> (32 - i) as usize).0 as i32; + ix1 = ix1 << i as usize; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0 & 0x000fffff) | 0x00100000; + if (m & 1) == 1 { + /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ - /* generate sqrt(x) bit by bit */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - q = 0; /* [q,q1] = sqrt(x) */ - q1 = Wrapping(0); - s0 = 0; - s1 = Wrapping(0); - r = Wrapping(0x00200000); /* r = moving bit from right to left */ + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + q = 0; /* [q,q1] = sqrt(x) */ + q1 = Wrapping(0); + s0 = 0; + s1 = Wrapping(0); + r = Wrapping(0x00200000); /* r = moving bit from right to left */ - while r != Wrapping(0) { - t = s0 + r.0 as i32; - if t <= ix0 { - s0 = t + r.0 as i32; - ix0 -= t; - q += r.0 as i32; - } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; - } + while r != Wrapping(0) { + t = s0 + r.0 as i32; + if t <= ix0 { + s0 = t + r.0 as i32; + ix0 -= t; + q += r.0 as i32; + } + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + r >>= 1; + } - r = sign; - while r != Wrapping(0) { - t1 = s1 + r; - t = s0; - if t < ix0 || (t == ix0 && t1 <= ix1) { - s1 = t1 + r; - if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { - s0 += 1; - } - ix0 -= t; - if ix1 < t1 { - ix0 -= 1; - } - ix1 -= t1; - q1 += r; - } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; - } + r = sign; + while r != Wrapping(0) { + t1 = s1 + r; + t = s0; + if t < ix0 || (t == ix0 && t1 <= ix1) { + s1 = t1 + r; + if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { + s0 += 1; + } + ix0 -= t; + if ix1 < t1 { + ix0 -= 1; + } + ix1 -= t1; + q1 += r; + } + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + r >>= 1; + } - /* use floating add to find out rounding direction */ - if (ix0 as u32 | ix1.0) != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if q1.0 == 0xffffffff { - q1 = Wrapping(0); - q += 1; - } else if z > 1.0 { - if q1.0 == 0xfffffffe { - q += 1; - } - q1 += Wrapping(2); - } else { - q1 += q1 & Wrapping(1); - } - } - } - ix0 = (q >> 1) + 0x3fe00000; - ix1 = q1 >> 1; - if (q & 1) == 1 { - ix1 |= sign; + /* use floating add to find out rounding direction */ + if (ix0 as u32 | ix1.0) != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if q1.0 == 0xffffffff { + q1 = Wrapping(0); + q += 1; + } else if z > 1.0 { + if q1.0 == 0xfffffffe { + q += 1; + } + q1 += Wrapping(2); + } else { + q1 += q1 & Wrapping(1); + } + } + } + ix0 = (q >> 1) + 0x3fe00000; + ix1 = q1 >> 1; + if (q & 1) == 1 { + ix1 |= sign; + } + ix0 += m << 20; + f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } - ix0 += m << 20; - f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 889b5258122..a4d9ab53deb 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -29,83 +29,101 @@ pub fn sqrtf(x: f32) -> f32 { } } } - let mut z: f32; - let sign: i32 = 0x80000000u32 as i32; - let mut ix: i32; - let mut s: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: u32; + #[cfg(target_feature="sse")] + { + // Note(Lokathor): If compile time settings allow, we just use SSE, since + // the sqrt in `std` on these platforms also compiles down to an SSE + // instruction. + #[cfg(target_arch="x86")] + use core::arch::x86::*; + #[cfg(target_arch="x86_64")] + use core::arch::x86_64::*; + unsafe { + let m = _mm_set_ss(x); + let m_sqrt = _mm_sqrt_ss(m); + _mm_cvtss_f32(m_sqrt) + } + } + #[cfg(not(target_feature="sse"))] + { + let mut z: f32; + let sign: i32 = 0x80000000u32 as i32; + let mut ix: i32; + let mut s: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: u32; - ix = x.to_bits() as i32; + ix = x.to_bits() as i32; - /* take care of Inf and NaN */ - if (ix as u32 & 0x7f800000) == 0x7f800000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } + /* take care of Inf and NaN */ + if (ix as u32 & 0x7f800000) == 0x7f800000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } - /* take care of zero */ - if ix <= 0 { - if (ix & !sign) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } + /* take care of zero */ + if ix <= 0 { + if (ix & !sign) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } - /* normalize x */ - m = ix >> 23; - if m == 0 { - /* subnormal x */ - i = 0; - while ix & 0x00800000 == 0 { - ix <<= 1; - i = i + 1; - } - m -= i - 1; - } - m -= 127; /* unbias exponent */ - ix = (ix & 0x007fffff) | 0x00800000; - if m & 1 == 1 { - /* odd m, double x to make it even */ - ix += ix; - } - m >>= 1; /* m = [m/2] */ + /* normalize x */ + m = ix >> 23; + if m == 0 { + /* subnormal x */ + i = 0; + while ix & 0x00800000 == 0 { + ix <<= 1; + i = i + 1; + } + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if m & 1 == 1 { + /* odd m, double x to make it even */ + ix += ix; + } + m >>= 1; /* m = [m/2] */ - /* generate sqrt(x) bit by bit */ - ix += ix; - q = 0; - s = 0; - r = 0x01000000; /* r = moving bit from right to left */ + /* generate sqrt(x) bit by bit */ + ix += ix; + q = 0; + s = 0; + r = 0x01000000; /* r = moving bit from right to left */ - while r != 0 { - t = s + r as i32; - if t <= ix { - s = t + r as i32; - ix -= t; - q += r as i32; - } - ix += ix; - r >>= 1; - } + while r != 0 { + t = s + r as i32; + if t <= ix { + s = t + r as i32; + ix -= t; + q += r as i32; + } + ix += ix; + r >>= 1; + } - /* use floating add to find out rounding direction */ - if ix != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if z > 1.0 { - q += 2; - } else { - q += q & 1; - } - } - } + /* use floating add to find out rounding direction */ + if ix != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if z > 1.0 { + q += 2; + } else { + q += q & 1; + } + } + } - ix = (q >> 1) + 0x3f000000; - ix += m << 23; - f32::from_bits(ix as u32) + ix = (q >> 1) + 0x3f000000; + ix += m << 23; + f32::from_bits(ix as u32) + } } -- cgit 1.4.1-3-g733a5 From 47d6a214d44591208201bb5cd8e3f458ef00c695 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Wed, 7 Aug 2019 14:10:34 -0600 Subject: apply rustfmt --- library/compiler-builtins/libm/src/math/sqrt.rs | 264 +++++++++++------------ library/compiler-builtins/libm/src/math/sqrtf.rs | 170 +++++++-------- 2 files changed, 217 insertions(+), 217 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index f01267da727..2fb1b24b7da 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -95,146 +95,146 @@ pub fn sqrt(x: f64) -> f64 { } } } - #[cfg(target_feature="sse2")] + #[cfg(target_feature = "sse2")] { - // Note(Lokathor): If compile time settings allow, we just use SSE2, since - // the sqrt in `std` on these platforms also compiles down to an SSE2 - // instruction. - #[cfg(target_arch="x86")] - use core::arch::x86::*; - #[cfg(target_arch="x86_64")] - use core::arch::x86_64::*; - unsafe { - let m = _mm_set_sd(x); - let m_sqrt = _mm_sqrt_pd(m); - _mm_cvtsd_f64(m_sqrt) - } + // Note(Lokathor): If compile time settings allow, we just use SSE2, since + // the sqrt in `std` on these platforms also compiles down to an SSE2 + // instruction. + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + unsafe { + let m = _mm_set_sd(x); + let m_sqrt = _mm_sqrt_pd(m); + _mm_cvtsd_f64(m_sqrt) + } } - #[cfg(not(target_feature="sse2"))] + #[cfg(not(target_feature = "sse2"))] { - let mut z: f64; - let sign: Wrapping = Wrapping(0x80000000); - let mut ix0: i32; - let mut s0: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: Wrapping; - let mut t1: Wrapping; - let mut s1: Wrapping; - let mut ix1: Wrapping; - let mut q1: Wrapping; + let mut z: f64; + let sign: Wrapping = Wrapping(0x80000000); + let mut ix0: i32; + let mut s0: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: Wrapping; + let mut t1: Wrapping; + let mut s1: Wrapping; + let mut ix1: Wrapping; + let mut q1: Wrapping; - ix0 = (x.to_bits() >> 32) as i32; - ix1 = Wrapping(x.to_bits() as u32); + ix0 = (x.to_bits() >> 32) as i32; + ix1 = Wrapping(x.to_bits() as u32); - /* take care of Inf and NaN */ - if (ix0 & 0x7ff00000) == 0x7ff00000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } - /* take care of zero */ - if ix0 <= 0 { - if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix0 < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } - /* normalize x */ - m = ix0 >> 20; - if m == 0 { - /* subnormal x */ - while ix0 == 0 { - m -= 21; - ix0 |= (ix1 >> 11).0 as i32; - ix1 <<= 21; - } - i = 0; - while (ix0 & 0x00100000) == 0 { - i += 1; - ix0 <<= 1; - } - m -= i - 1; - ix0 |= (ix1 >> (32 - i) as usize).0 as i32; - ix1 = ix1 << i as usize; - } - m -= 1023; /* unbias exponent */ - ix0 = (ix0 & 0x000fffff) | 0x00100000; - if (m & 1) == 1 { - /* odd m, double x to make it even */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - } - m >>= 1; /* m = [m/2] */ + /* take care of Inf and NaN */ + if (ix0 & 0x7ff00000) == 0x7ff00000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if ix0 <= 0 { + if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix0 < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } + /* normalize x */ + m = ix0 >> 20; + if m == 0 { + /* subnormal x */ + while ix0 == 0 { + m -= 21; + ix0 |= (ix1 >> 11).0 as i32; + ix1 <<= 21; + } + i = 0; + while (ix0 & 0x00100000) == 0 { + i += 1; + ix0 <<= 1; + } + m -= i - 1; + ix0 |= (ix1 >> (32 - i) as usize).0 as i32; + ix1 = ix1 << i as usize; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0 & 0x000fffff) | 0x00100000; + if (m & 1) == 1 { + /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ - /* generate sqrt(x) bit by bit */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - q = 0; /* [q,q1] = sqrt(x) */ - q1 = Wrapping(0); - s0 = 0; - s1 = Wrapping(0); - r = Wrapping(0x00200000); /* r = moving bit from right to left */ + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + q = 0; /* [q,q1] = sqrt(x) */ + q1 = Wrapping(0); + s0 = 0; + s1 = Wrapping(0); + r = Wrapping(0x00200000); /* r = moving bit from right to left */ - while r != Wrapping(0) { - t = s0 + r.0 as i32; - if t <= ix0 { - s0 = t + r.0 as i32; - ix0 -= t; - q += r.0 as i32; - } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; - } + while r != Wrapping(0) { + t = s0 + r.0 as i32; + if t <= ix0 { + s0 = t + r.0 as i32; + ix0 -= t; + q += r.0 as i32; + } + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + r >>= 1; + } - r = sign; - while r != Wrapping(0) { - t1 = s1 + r; - t = s0; - if t < ix0 || (t == ix0 && t1 <= ix1) { - s1 = t1 + r; - if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { - s0 += 1; - } - ix0 -= t; - if ix1 < t1 { - ix0 -= 1; - } - ix1 -= t1; - q1 += r; - } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; - } + r = sign; + while r != Wrapping(0) { + t1 = s1 + r; + t = s0; + if t < ix0 || (t == ix0 && t1 <= ix1) { + s1 = t1 + r; + if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { + s0 += 1; + } + ix0 -= t; + if ix1 < t1 { + ix0 -= 1; + } + ix1 -= t1; + q1 += r; + } + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + r >>= 1; + } - /* use floating add to find out rounding direction */ - if (ix0 as u32 | ix1.0) != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if q1.0 == 0xffffffff { - q1 = Wrapping(0); - q += 1; - } else if z > 1.0 { - if q1.0 == 0xfffffffe { - q += 1; - } - q1 += Wrapping(2); - } else { - q1 += q1 & Wrapping(1); - } - } - } - ix0 = (q >> 1) + 0x3fe00000; - ix1 = q1 >> 1; - if (q & 1) == 1 { - ix1 |= sign; - } - ix0 += m << 20; - f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) + /* use floating add to find out rounding direction */ + if (ix0 as u32 | ix1.0) != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if q1.0 == 0xffffffff { + q1 = Wrapping(0); + q += 1; + } else if z > 1.0 { + if q1.0 == 0xfffffffe { + q += 1; + } + q1 += Wrapping(2); + } else { + q1 += q1 & Wrapping(1); + } + } + } + ix0 = (q >> 1) + 0x3fe00000; + ix1 = q1 >> 1; + if (q & 1) == 1 { + ix1 |= sign; + } + ix0 += m << 20; + f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } } diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index a4d9ab53deb..5fe0a774491 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -29,101 +29,101 @@ pub fn sqrtf(x: f32) -> f32 { } } } - #[cfg(target_feature="sse")] + #[cfg(target_feature = "sse")] { - // Note(Lokathor): If compile time settings allow, we just use SSE, since - // the sqrt in `std` on these platforms also compiles down to an SSE - // instruction. - #[cfg(target_arch="x86")] - use core::arch::x86::*; - #[cfg(target_arch="x86_64")] - use core::arch::x86_64::*; - unsafe { - let m = _mm_set_ss(x); - let m_sqrt = _mm_sqrt_ss(m); - _mm_cvtss_f32(m_sqrt) - } + // Note(Lokathor): If compile time settings allow, we just use SSE, since + // the sqrt in `std` on these platforms also compiles down to an SSE + // instruction. + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + unsafe { + let m = _mm_set_ss(x); + let m_sqrt = _mm_sqrt_ss(m); + _mm_cvtss_f32(m_sqrt) + } } - #[cfg(not(target_feature="sse"))] + #[cfg(not(target_feature = "sse"))] { - let mut z: f32; - let sign: i32 = 0x80000000u32 as i32; - let mut ix: i32; - let mut s: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: u32; + let mut z: f32; + let sign: i32 = 0x80000000u32 as i32; + let mut ix: i32; + let mut s: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: u32; - ix = x.to_bits() as i32; + ix = x.to_bits() as i32; - /* take care of Inf and NaN */ - if (ix as u32 & 0x7f800000) == 0x7f800000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } + /* take care of Inf and NaN */ + if (ix as u32 & 0x7f800000) == 0x7f800000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } - /* take care of zero */ - if ix <= 0 { - if (ix & !sign) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } + /* take care of zero */ + if ix <= 0 { + if (ix & !sign) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } - /* normalize x */ - m = ix >> 23; - if m == 0 { - /* subnormal x */ - i = 0; - while ix & 0x00800000 == 0 { - ix <<= 1; - i = i + 1; - } - m -= i - 1; - } - m -= 127; /* unbias exponent */ - ix = (ix & 0x007fffff) | 0x00800000; - if m & 1 == 1 { - /* odd m, double x to make it even */ - ix += ix; - } - m >>= 1; /* m = [m/2] */ + /* normalize x */ + m = ix >> 23; + if m == 0 { + /* subnormal x */ + i = 0; + while ix & 0x00800000 == 0 { + ix <<= 1; + i = i + 1; + } + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if m & 1 == 1 { + /* odd m, double x to make it even */ + ix += ix; + } + m >>= 1; /* m = [m/2] */ - /* generate sqrt(x) bit by bit */ - ix += ix; - q = 0; - s = 0; - r = 0x01000000; /* r = moving bit from right to left */ + /* generate sqrt(x) bit by bit */ + ix += ix; + q = 0; + s = 0; + r = 0x01000000; /* r = moving bit from right to left */ - while r != 0 { - t = s + r as i32; - if t <= ix { - s = t + r as i32; - ix -= t; - q += r as i32; - } - ix += ix; - r >>= 1; - } + while r != 0 { + t = s + r as i32; + if t <= ix { + s = t + r as i32; + ix -= t; + q += r as i32; + } + ix += ix; + r >>= 1; + } - /* use floating add to find out rounding direction */ - if ix != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if z > 1.0 { - q += 2; - } else { - q += q & 1; - } - } - } + /* use floating add to find out rounding direction */ + if ix != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if z > 1.0 { + q += 2; + } else { + q += q & 1; + } + } + } - ix = (q >> 1) + 0x3f000000; - ix += m << 23; - f32::from_bits(ix as u32) + ix = (q >> 1) + 0x3f000000; + ix += m << 23; + f32::from_bits(ix as u32) } } -- cgit 1.4.1-3-g733a5 From 887fca89c259844a50d5e7cca60cbf186f36ef33 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Wed, 7 Aug 2019 14:16:10 -0600 Subject: move use/const statements to a limited scope --- library/compiler-builtins/libm/src/math/sqrt.rs | 7 ++++--- library/compiler-builtins/libm/src/math/sqrtf.rs | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 2fb1b24b7da..8a67cb18b7c 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -77,9 +77,6 @@ */ use core::f64; -use core::num::Wrapping; - -const TINY: f64 = 1.0e-300; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { @@ -112,6 +109,10 @@ pub fn sqrt(x: f64) -> f64 { } #[cfg(not(target_feature = "sse2"))] { + use core::num::Wrapping; + + const TINY: f64 = 1.0e-300; + let mut z: f64; let sign: Wrapping = Wrapping(0x80000000); let mut ix0: i32; diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 5fe0a774491..cb3c1672e92 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -13,8 +13,6 @@ * ==================================================== */ -const TINY: f32 = 1.0e-30; - #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized @@ -46,6 +44,8 @@ pub fn sqrtf(x: f32) -> f32 { } #[cfg(not(target_feature = "sse"))] { + const TINY: f32 = 1.0e-30; + let mut z: f32; let sign: i32 = 0x80000000u32 as i32; let mut ix: i32; -- cgit 1.4.1-3-g733a5 From e247c599cc53c52eb9cec8a7a3648d0c5858d27c Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 8 Aug 2019 18:21:10 -0600 Subject: update comments --- library/compiler-builtins/libm/src/math/sqrtf.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index cb3c1672e92..1d5b78e84c6 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -29,9 +29,9 @@ pub fn sqrtf(x: f32) -> f32 { } #[cfg(target_feature = "sse")] { - // Note(Lokathor): If compile time settings allow, we just use SSE, since - // the sqrt in `std` on these platforms also compiles down to an SSE - // instruction. + // Note: This path is unlikely since LLVM will usually have already + // optimized sqrt calls into hardware instructions if sse is available, + // but if someone does end up here they'll apprected the speed increase. #[cfg(target_arch = "x86")] use core::arch::x86::*; #[cfg(target_arch = "x86_64")] -- cgit 1.4.1-3-g733a5 From 0b8c514c8f6ca18025872868af2c6e3e335fc6d9 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 8 Aug 2019 18:21:18 -0600 Subject: update comments --- library/compiler-builtins/libm/src/math/sqrt.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 8a67cb18b7c..31afe33566b 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -94,9 +94,9 @@ pub fn sqrt(x: f64) -> f64 { } #[cfg(target_feature = "sse2")] { - // Note(Lokathor): If compile time settings allow, we just use SSE2, since - // the sqrt in `std` on these platforms also compiles down to an SSE2 - // instruction. + // Note: This path is unlikely since LLVM will usually have already + // optimized sqrt calls into hardware instructions if sse2 is available, + // but if someone does end up here they'll apprected the speed increase. #[cfg(target_arch = "x86")] use core::arch::x86::*; #[cfg(target_arch = "x86_64")] -- cgit 1.4.1-3-g733a5 From f004acd69119d43426d93b8d0db5d2efe562b07e Mon Sep 17 00:00:00 2001 From: Roman Proskuryakov Date: Sat, 10 Aug 2019 15:30:43 +0300 Subject: Fix broken link in README --- library/compiler-builtins/libm/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index e10904f8cf0..e90b42d740c 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -22,6 +22,8 @@ This crate is [on crates.io] and can be used today in stable `#![no_std]` progra The API documentation can be found [here](https://docs.rs/libm). +[on crates.io]: https://crates.io/crates/libm + ## Benchmark [benchmark]: #benchmark -- cgit 1.4.1-3-g733a5 From ff3dd206d1eaf63ca3c7bb627ecdbceac827f8a7 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Tue, 13 Aug 2019 23:40:54 -0600 Subject: slightly improve spec and sanity check coverage --- library/compiler-builtins/libm/src/math/ceil.rs | 17 +++++++++++++-- library/compiler-builtins/libm/src/math/ceilf.rs | 22 ++++++++++++++++++++ library/compiler-builtins/libm/src/math/fabs.rs | 24 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/fabsf.rs | 24 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/floor.rs | 22 ++++++++++++++++++++ library/compiler-builtins/libm/src/math/floorf.rs | 19 +++++++++++++++-- library/compiler-builtins/libm/src/math/sqrt.rs | 25 ++++++++++++++++++++++- library/compiler-builtins/libm/src/math/sqrtf.rs | 23 +++++++++++++++++++++ 8 files changed, 171 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 63c1121c6d3..eda28b9a0f2 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -42,9 +42,22 @@ pub fn ceil(x: f64) -> f64 { #[cfg(test)] mod tests { + use super::*; + use core::f64::*; + #[test] fn sanity_check() { - assert_eq!(super::ceil(1.1), 2.0); - assert_eq!(super::ceil(2.9), 3.0); + assert_eq!(ceil(1.1), 2.0); + assert_eq!(ceil(2.9), 3.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil + #[test] + fn spec_tests() { + // Not Asserted: that the current rounding mode has no effect. + assert!(ceil(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(ceil(f), f); + } } } diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 87d96982aab..f1edbd061bf 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -39,3 +39,25 @@ pub fn ceilf(x: f32) -> f32 { } f32::from_bits(ui) } + +#[cfg(test)] +mod tests { + use super::*; + use core::f32::*; + + #[test] + fn sanity_check() { + assert_eq!(ceilf(1.1), 2.0); + assert_eq!(ceilf(2.9), 3.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil + #[test] + fn spec_tests() { + // Not Asserted: that the current rounding mode has no effect. + assert!(ceilf(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(ceilf(f), f); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 5a7f795f6a3..4b292acc6cd 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -15,3 +15,27 @@ pub fn fabs(x: f64) -> f64 { } f64::from_bits(x.to_bits() & (u64::MAX / 2)) } + +#[cfg(test)] +mod tests { + use super::*; + use core::f64::*; + + #[test] + fn sanity_check() { + assert_eq!(fabs(-1.0), 1.0); + assert_eq!(fabs(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabs(NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabs(f), 0.0); + } + for f in [INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(fabs(f), INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 495512584d2..21dda8d6a3c 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -13,3 +13,27 @@ pub fn fabsf(x: f32) -> f32 { } f32::from_bits(x.to_bits() & 0x7fffffff) } + +#[cfg(test)] +mod tests { + use super::*; + use core::f32::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf(-1.0), 1.0); + assert_eq!(fabsf(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf(NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf(f), 0.0); + } + for f in [INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(fabsf(f), INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index 91825e3c88f..b2b760570de 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -38,3 +38,25 @@ pub fn floor(x: f64) -> f64 { x + y } } + +#[cfg(test)] +mod tests { + use super::*; + use core::f64::*; + + #[test] + fn sanity_check() { + assert_eq!(floor(1.1), 1.0); + assert_eq!(floor(2.9), 2.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor + #[test] + fn spec_tests() { + // Not Asserted: that the current rounding mode has no effect. + assert!(floor(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(floor(f), f); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 6d751b077ef..287f0864277 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -42,8 +42,23 @@ pub fn floorf(x: f32) -> f32 { #[cfg(test)] mod tests { + use super::*; + use core::f32::*; + #[test] - fn no_overflow() { - assert_eq!(super::floorf(0.5), 0.0); + fn sanity_check() { + assert_eq!(floorf(0.5), 0.0); + assert_eq!(floorf(1.1), 1.0); + assert_eq!(floorf(2.9), 2.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor + #[test] + fn spec_tests() { + // Not Asserted: that the current rounding mode has no effect. + assert!(floorf(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(floorf(f), f); + } } } diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 31afe33566b..addecba2352 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -37,7 +37,7 @@ * If (2) is false, then q = q ; otherwise q = q + 2 . * i+1 i i+1 i * - * With some algebric manipulation, it is not difficult to see + * With some algebraic manipulation, it is not difficult to see * that (2) is equivalent to * -(i+1) * s + 2 <= y (3) @@ -239,3 +239,26 @@ pub fn sqrt(x: f64) -> f64 { f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } } + +#[cfg(test)] +mod tests { + use super::*; + use core::f64::*; + + #[test] + fn sanity_check() { + assert_eq!(sqrt(100.0), 10.0); + assert_eq!(sqrt(4.0), 2.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt + #[test] + fn spec_tests() { + // Not Asserted: FE_INVALID exception is raised if argument is negative. + assert!(sqrt(-1.0).is_nan()); + assert!(sqrt(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY].iter().copied() { + assert_eq!(sqrt(f), f); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 1d5b78e84c6..0bee0286990 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -127,3 +127,26 @@ pub fn sqrtf(x: f32) -> f32 { f32::from_bits(ix as u32) } } + +#[cfg(test)] +mod tests { + use super::*; + use core::f32::*; + + #[test] + fn sanity_check() { + assert_eq!(sqrtf(100.0), 10.0); + assert_eq!(sqrtf(4.0), 2.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt + #[test] + fn spec_tests() { + // Not Asserted: FE_INVALID exception is raised if argument is negative. + assert!(sqrtf(-1.0).is_nan()); + assert!(sqrtf(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY].iter().copied() { + assert_eq!(sqrtf(f), f); + } + } +} -- cgit 1.4.1-3-g733a5 From 3dd4991eab8456dee638bcc9fb935c4d6978eea9 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Tue, 13 Aug 2019 23:45:50 -0600 Subject: rustfmt fixes --- library/compiler-builtins/libm/src/math/fabs.rs | 4 ++-- library/compiler-builtins/libm/src/math/fabsf.rs | 4 ++-- library/compiler-builtins/libm/src/math/sqrt.rs | 4 ++-- library/compiler-builtins/libm/src/math/sqrtf.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 4b292acc6cd..b2255ad32cf 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -23,8 +23,8 @@ mod tests { #[test] fn sanity_check() { - assert_eq!(fabs(-1.0), 1.0); - assert_eq!(fabs(2.8), 2.8); + assert_eq!(fabs(-1.0), 1.0); + assert_eq!(fabs(2.8), 2.8); } /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 21dda8d6a3c..6655c4c3ccc 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -21,8 +21,8 @@ mod tests { #[test] fn sanity_check() { - assert_eq!(fabsf(-1.0), 1.0); - assert_eq!(fabsf(2.8), 2.8); + assert_eq!(fabsf(-1.0), 1.0); + assert_eq!(fabsf(2.8), 2.8); } /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index addecba2352..f06b209a49f 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -247,8 +247,8 @@ mod tests { #[test] fn sanity_check() { - assert_eq!(sqrt(100.0), 10.0); - assert_eq!(sqrt(4.0), 2.0); + assert_eq!(sqrt(100.0), 10.0); + assert_eq!(sqrt(4.0), 2.0); } /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 0bee0286990..ee868c8c811 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -135,8 +135,8 @@ mod tests { #[test] fn sanity_check() { - assert_eq!(sqrtf(100.0), 10.0); - assert_eq!(sqrtf(4.0), 2.0); + assert_eq!(sqrtf(100.0), 10.0); + assert_eq!(sqrtf(4.0), 2.0); } /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt -- cgit 1.4.1-3-g733a5 From cefd832d8957ad369bfb3923e4ebfd7a4c985973 Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Mon, 19 Aug 2019 09:30:45 -0700 Subject: Support deterministic builds by remapping the __FILE__ prefix if the compiler supports it. --- library/compiler-builtins/build.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index c714bc15de3..feb7fc6ecda 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -423,6 +423,10 @@ mod c { panic!("RUST_COMPILER_RT_ROOT={} does not exist", root.display()); } + // Support deterministic builds by remapping the __FILE__ prefix if the + // compiler supports it. + cfg.flag_if_supported(&format!("-ffile-prefix-map={}=.", root.display())); + let src_dir = root.join("lib/builtins"); for (sym, src) in sources.map.iter() { let src = src_dir.join(src); -- cgit 1.4.1-3-g733a5 From a292bd9cb52cc1c6c26d20e1226d4b94ef7866d5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 19 Aug 2019 14:02:08 -0700 Subject: Modernize the `testcrate` slighty * Update `rand` dependency * Drop `cast` in favor of explicit casting or crate-defined * Move build script to 2018 edition --- library/compiler-builtins/testcrate/Cargo.toml | 4 +- library/compiler-builtins/testcrate/build.rs | 130 +++++++++++++++---------- 2 files changed, 83 insertions(+), 51 deletions(-) diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 2a102660b2f..3b99b574ef2 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -2,14 +2,14 @@ name = "testcrate" version = "0.1.0" authors = ["Alex Crichton "] +edition = "2018" [lib] test = false doctest = false [build-dependencies] -cast = { version = "0.2.2", features = ["x128"] } -rand = { version = "0.4", features = ["i128_support"] } +rand = "0.7" [dependencies.compiler_builtins] path = ".." diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 4bd4005b705..e1d4cf9e818 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -1,6 +1,5 @@ -extern crate cast; -extern crate rand; - +use rand::seq::SliceRandom; +use rand::Rng; use std::collections::HashMap; use std::fmt; use std::fmt::Write as FmtWrite; @@ -10,9 +9,6 @@ use std::io::Write; use std::path::PathBuf; use std::{env, mem}; -use self::cast::{f32, f64, i128, i32, i64, u128, u32, u64}; -use self::rand::Rng; - const NTESTS: usize = 1_000; fn main() { @@ -397,7 +393,7 @@ fn main() { if a.0.is_nan() { return None; } - Some(f64(a.0)) + Some(f64::from(a.0)) }, "builtins::float::extend::__extendsfdf2(a)", ); @@ -407,7 +403,7 @@ fn main() { if a.0.is_nan() { return None; } - Some(f64(a.0)) + Some(f64::from(a.0)) }, "builtins::float::extend::__extendsfdf2vfp(a)", ); @@ -415,92 +411,92 @@ fn main() { // float/conv.rs gen( - |a: MyF64| i64(a.0).ok(), + |a: MyF64| i64::cast(a.0), "builtins::float::conv::__fixdfdi(a)", ); gen( - |a: MyF64| i32(a.0).ok(), + |a: MyF64| i32::cast(a.0), "builtins::float::conv::__fixdfsi(a)", ); gen( - |a: MyF32| i64(a.0).ok(), + |a: MyF32| i64::cast(a.0), "builtins::float::conv::__fixsfdi(a)", ); gen( - |a: MyF32| i32(a.0).ok(), + |a: MyF32| i32::cast(a.0), "builtins::float::conv::__fixsfsi(a)", ); gen( - |a: MyF32| i128(a.0).ok(), + |a: MyF32| i128::cast(a.0), "builtins::float::conv::__fixsfti(a)", ); gen( - |a: MyF64| i128(a.0).ok(), + |a: MyF64| i128::cast(a.0), "builtins::float::conv::__fixdfti(a)", ); gen( - |a: MyF64| u64(a.0).ok(), + |a: MyF64| u64::cast(a.0), "builtins::float::conv::__fixunsdfdi(a)", ); gen( - |a: MyF64| u32(a.0).ok(), + |a: MyF64| u32::cast(a.0), "builtins::float::conv::__fixunsdfsi(a)", ); gen( - |a: MyF32| u64(a.0).ok(), + |a: MyF32| u64::cast(a.0), "builtins::float::conv::__fixunssfdi(a)", ); gen( - |a: MyF32| u32(a.0).ok(), + |a: MyF32| u32::cast(a.0), "builtins::float::conv::__fixunssfsi(a)", ); gen( - |a: MyF32| u128(a.0).ok(), + |a: MyF32| u128::cast(a.0), "builtins::float::conv::__fixunssfti(a)", ); gen( - |a: MyF64| u128(a.0).ok(), + |a: MyF64| u128::cast(a.0), "builtins::float::conv::__fixunsdfti(a)", ); gen( - |a: MyI64| Some(f64(a.0)), + |a: MyI64| Some(a.0 as f64), "builtins::float::conv::__floatdidf(a)", ); gen( - |a: MyI32| Some(f64(a.0)), + |a: MyI32| Some(a.0 as f64), "builtins::float::conv::__floatsidf(a)", ); gen( - |a: MyI32| Some(f32(a.0)), + |a: MyI32| Some(a.0 as f32), "builtins::float::conv::__floatsisf(a)", ); gen( - |a: MyU64| Some(f64(a.0)), + |a: MyU64| Some(a.0 as f64), "builtins::float::conv::__floatundidf(a)", ); gen( - |a: MyU32| Some(f64(a.0)), + |a: MyU32| Some(a.0 as f64), "builtins::float::conv::__floatunsidf(a)", ); gen( - |a: MyU32| Some(f32(a.0)), + |a: MyU32| Some(a.0 as f32), "builtins::float::conv::__floatunsisf(a)", ); gen( - |a: MyU128| f32(a.0).ok(), + |a: MyU128| Some(a.0 as f32), "builtins::float::conv::__floatuntisf(a)", ); if !target_arch_mips { gen( - |a: MyI128| Some(f32(a.0)), + |a: MyI128| Some(a.0 as f32), "builtins::float::conv::__floattisf(a)", ); gen( - |a: MyI128| Some(f64(a.0)), + |a: MyI128| Some(a.0 as f64), "builtins::float::conv::__floattidf(a)", ); gen( - |a: MyU128| Some(f64(a.0)), + |a: MyU128| Some(a.0 as f64), "builtins::float::conv::__floatuntidf(a)", ); } @@ -996,7 +992,7 @@ macro_rules! gen_float { $significand_bits:expr) => { pub fn $name(rng: &mut R) -> $fty where - R: Rng, + R: Rng + ?Sized, { const BITS: u8 = $bits; const SIGNIFICAND_BITS: u8 = $significand_bits; @@ -1015,9 +1011,9 @@ macro_rules! gen_float { } } - if rng.gen_weighted_bool(10) { + if rng.gen_range(0, 10) == 1 { // Special values - *rng.choose(&[ + *[ -0.0, 0.0, ::std::$fty::MIN, @@ -1026,9 +1022,10 @@ macro_rules! gen_float { ::std::$fty::NAN, ::std::$fty::INFINITY, -::std::$fty::INFINITY, - ]) + ] + .choose(rng) .unwrap() - } else if rng.gen_weighted_bool(10) { + } else if rng.gen_range(0, 10) == 1 { // NaN patterns mk_f32(rng.gen(), rng.gen(), 0) } else if rng.gen() { @@ -1053,7 +1050,7 @@ macro_rules! gen_large_float { $significand_bits:expr) => { pub fn $name(rng: &mut R) -> $fty where - R: Rng, + R: Rng + ?Sized, { const BITS: u8 = $bits; const SIGNIFICAND_BITS: u8 = $significand_bits; @@ -1072,9 +1069,9 @@ macro_rules! gen_large_float { } } - if rng.gen_weighted_bool(10) { + if rng.gen_range(0, 10) == 1 { // Special values - *rng.choose(&[ + *[ -0.0, 0.0, ::std::$fty::MIN, @@ -1083,9 +1080,10 @@ macro_rules! gen_large_float { ::std::$fty::NAN, ::std::$fty::INFINITY, -::std::$fty::INFINITY, - ]) + ] + .choose(rng) .unwrap() - } else if rng.gen_weighted_bool(10) { + } else if rng.gen_range(0, 10) == 1 { // NaN patterns mk_f32(rng.gen(), rng.gen(), 0) } else if rng.gen() { @@ -1102,7 +1100,7 @@ macro_rules! gen_large_float { gen_large_float!(gen_large_f32, f32, u32, 32, 23); gen_large_float!(gen_large_f64, f64, u64, 64, 52); -trait TestInput: rand::Rand + Hash + Eq + fmt::Debug { +trait TestInput: Hash + Eq + fmt::Debug { fn ty_name() -> String; fn generate_lets(container: &str, cnt: &mut u8) -> String; fn generate_static(&self, dst: &mut String); @@ -1119,6 +1117,7 @@ where F: FnMut(A) -> Option, A: TestInput + Copy, R: TestOutput, + rand::distributions::Standard: rand::distributions::Distribution, { let rng = &mut rand::thread_rng(); let testname = test.split("::").last().unwrap().split("(").next().unwrap(); @@ -1207,8 +1206,8 @@ macro_rules! my_float { } } - impl rand::Rand for $name { - fn rand(r: &mut R) -> $name { + impl rand::distributions::Distribution<$name> for rand::distributions::Standard { + fn sample(&self, r: &mut R) -> $name { $name($gen(r)) } } @@ -1260,18 +1259,18 @@ macro_rules! my_integer { } } - impl rand::Rand for $name { - fn rand(rng: &mut R) -> $name { + impl rand::distributions::Distribution<$name> for rand::distributions::Standard { + fn sample(&self, r: &mut R) -> $name { let bits = (0 as $inner).count_zeros(); let mut mk = || { - if rng.gen_weighted_bool(10) { - *rng.choose(&[ + if r.gen_range(0, 10) == 1 { + *[ ::std::$inner::MAX >> (bits / 2), 0, ::std::$inner::MIN >> (bits / 2), - ]).unwrap() + ].choose(r).unwrap() } else { - rng.gen::<$inner>() + r.gen::<$inner>() } }; let a = mk(); @@ -1386,3 +1385,36 @@ where container.to_string() } } + +trait FromFloat: Sized { + fn cast(src: T) -> Option; +} + +macro_rules! from_float { + ($($src:ident => $($dst:ident),+);+;) => { + $( + $( + impl FromFloat<$src> for $dst { + fn cast(src: $src) -> Option<$dst> { + use std::{$dst, $src}; + + if src.is_nan() || + src.is_infinite() || + src < std::$dst::MIN as $src || + src > std::$dst::MAX as $src + { + None + } else { + Some(src as $dst) + } + } + } + )+ + )+ + } +} + +from_float! { + f32 => i32, i64, i128, u32, u64, u128; + f64 => i32, i64, i128, u32, u64, u128; +} -- cgit 1.4.1-3-g733a5 From a80233948f6321a6fa5995e7c2590e4596ed6a1f Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Mon, 19 Aug 2019 15:12:07 -0700 Subject: Update comment to mention where the __FILE__ macro is used. --- library/compiler-builtins/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index feb7fc6ecda..490b6391d08 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -424,7 +424,8 @@ mod c { } // Support deterministic builds by remapping the __FILE__ prefix if the - // compiler supports it. + // compiler supports it. This fixes the nondeterminism caused by the + // use of that macro in lib/builtins/int_util.h in compiler-rt. cfg.flag_if_supported(&format!("-ffile-prefix-map={}=.", root.display())); let src_dir = root.join("lib/builtins"); -- cgit 1.4.1-3-g733a5 From 1cc3d328747b1a15913d50644213fd6924b03888 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Tue, 20 Aug 2019 14:10:38 -0700 Subject: Implement LLVM's elementwise unordered atomic memory intrinsics Allows uses of intrinsics of the form llvm.(memcpy|memmove|memset).element.unordered.atomic.* to be linked. --- library/compiler-builtins/src/mem.rs | 106 +++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index c863bb72941..be7849ff39d 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -5,6 +5,10 @@ type c_int = i16; #[cfg(not(target_pointer_width = "16"))] type c_int = i32; +use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, unchecked_div}; +use core::mem; +use core::ops::{BitOr, Shl}; + #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { let mut i = 0; @@ -58,3 +62,105 @@ pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { } 0 } + +fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { + unsafe { + let n = unchecked_div(bytes, mem::size_of::()); + let mut i = 0; + while i < n { + atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); + i += 1; + } + } +} + +fn memmove_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { + unsafe { + let n = unchecked_div(bytes, mem::size_of::()); + if src < dest as *const T { + // copy from end + let mut i = n; + while i != 0 { + i -= 1; + atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); + } + } else { + // copy from beginning + let mut i = 0; + while i < n { + atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); + i += 1; + } + } + } +} + +fn memset_element_unordered_atomic(s: *mut T, c: u8, bytes: usize) +where + T: Copy + From + Shl + BitOr, +{ + unsafe { + let n = unchecked_div(bytes, mem::size_of::()); + let mut x = T::from(c); + let mut i = 1; + while i < mem::size_of::() { + x = x << 8 | T::from(c); + i += 1; + } + let mut i = 0; + while i < n { + atomic_store_unordered(s.add(i), x); + i += 1; + } + } +} + +intrinsics! { + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + + pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memmove_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memmove_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + + pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } + pub extern "C" fn __llvm_memset_element_unordered_atomic_2(s: *mut u16, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } + pub extern "C" fn __llvm_memset_element_unordered_atomic_4(s: *mut u32, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } + pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } + pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } +} -- cgit 1.4.1-3-g733a5 From 01a0524d8c3d5c81adc49934474b00b06d193054 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Fri, 23 Aug 2019 10:18:36 -0700 Subject: Tidy up unordered elementwise atomic memory intrinsics --- library/compiler-builtins/src/mem.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index be7849ff39d..76372d9bc81 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -5,7 +5,7 @@ type c_int = i16; #[cfg(not(target_pointer_width = "16"))] type c_int = i32; -use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, unchecked_div}; +use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, exact_div}; use core::mem; use core::ops::{BitOr, Shl}; @@ -63,9 +63,10 @@ pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { 0 } +// `bytes` must be a multiple of `mem::size_of::()` fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { unsafe { - let n = unchecked_div(bytes, mem::size_of::()); + let n = exact_div(bytes, mem::size_of::()); let mut i = 0; while i < n { atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); @@ -74,9 +75,10 @@ fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: } } +// `bytes` must be a multiple of `mem::size_of::()` fn memmove_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { unsafe { - let n = unchecked_div(bytes, mem::size_of::()); + let n = exact_div(bytes, mem::size_of::()); if src < dest as *const T { // copy from end let mut i = n; @@ -95,18 +97,24 @@ fn memmove_element_unordered_atomic(dest: *mut T, src: *const T, bytes: } } +// `T` must be a primitive integer type, and `bytes` must be a multiple of `mem::size_of::()` fn memset_element_unordered_atomic(s: *mut T, c: u8, bytes: usize) where T: Copy + From + Shl + BitOr, { unsafe { - let n = unchecked_div(bytes, mem::size_of::()); + let n = exact_div(bytes, mem::size_of::()); + + // Construct a value of type `T` consisting of repeated `c` + // bytes, to let us ensure we write each `T` atomically. let mut x = T::from(c); let mut i = 1; while i < mem::size_of::() { x = x << 8 | T::from(c); i += 1; } + + // Write it to `s` let mut i = 0; while i < n { atomic_store_unordered(s.add(i), x); -- cgit 1.4.1-3-g733a5 From 2e3ba17f9d32d68a8c01c36f748487aa0730ac82 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:32:05 -0600 Subject: there are no longer any default features --- library/compiler-builtins/libm/azure-pipelines.yml | 2 -- library/compiler-builtins/libm/ci/run.sh | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml index c89346c73d8..0d723c56dd2 100644 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -49,8 +49,6 @@ jobs: displayName: "Install rust wasm target" - script: cargo build --target wasm32-unknown-unknown displayName: "Build for wasm" - - script: cargo build --target wasm32-unknown-unknown --no-default-features - displayName: "Build for wasm (no default features)" variables: TOOLCHAIN: nightly diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 37ffb8793cc..59930b23879 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -3,7 +3,7 @@ set -ex TARGET=$1 -CMD="cargo test --all --no-default-features --target $TARGET" +CMD="cargo test --all --target $TARGET" $CMD $CMD --release -- cgit 1.4.1-3-g733a5 From de80131c2672868fb24761b2f7e6778940d70ebb Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:32:26 -0600 Subject: swap stable to be unstable, checked is now debug_assertions --- library/compiler-builtins/libm/Cargo.toml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 3e6817851ba..37aff9a765b 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -11,18 +11,16 @@ version = "0.2.0" edition = "2018" [features] -# only used to run our test suite -default = ['stable'] -stable = [] +default = [] + +# This tells the compiler to assume that a Nightly toolchain is being used and +# that it should activate any useful Nightly things accordingly. +unstable = [] # Generate tests which are random inputs and the outputs are calculated with # musl libc. musl-reference-tests = ['rand'] -# Used checked array indexing instead of unchecked array indexing in this -# library. -checked = [] - [workspace] members = [ "crates/compiler-builtins-smoke-test", -- cgit 1.4.1-3-g733a5 From 9811b57af2d08308187de34b00d9051e3de4e923 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:32:38 -0600 Subject: swap stable to be unstable --- library/compiler-builtins/libm/crates/libm-bench/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml index ba65dbd5fe6..b09db339b5b 100644 --- a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml @@ -12,4 +12,4 @@ paste = "0.1.5" [features] default = [] -stable = [ "libm/stable" ] +unstable = [ "libm/unstable" ] -- cgit 1.4.1-3-g733a5 From c6fbe72886291c8201334adcbfc8c0f6cf58dac2 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:33:03 -0600 Subject: swap stable to be unstable --- library/compiler-builtins/libm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index b15857dbe6f..e9def494051 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -2,7 +2,7 @@ #![deny(warnings)] #![no_std] #![cfg_attr( - all(target_arch = "wasm32", not(feature = "stable")), + all(target_arch = "wasm32", feature = "unstable"), feature(core_intrinsics) )] -- cgit 1.4.1-3-g733a5 From c847d46c6409d9986d5964f093f3821838ce990d Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:33:23 -0600 Subject: swap stable to be unstable, use debug_assertions --- library/compiler-builtins/libm/src/math/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index fcf4e649cde..c8d7bd8194d 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -6,7 +6,7 @@ macro_rules! force_eval { }; } -#[cfg(not(feature = "checked"))] +#[cfg(not(debug_assertions))] macro_rules! i { ($array:expr, $index:expr) => { unsafe { *$array.get_unchecked($index) } @@ -36,7 +36,7 @@ macro_rules! i { }; } -#[cfg(feature = "checked")] +#[cfg(debug_assertions)] macro_rules! i { ($array:expr, $index:expr) => { *$array.get($index).unwrap() @@ -60,7 +60,7 @@ macro_rules! i { macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all(not(feature = "stable"), $($clause)*))] + #[cfg(all(feature = "unstable", $($clause)*))] { if true { // thwart the dead code lint $e -- cgit 1.4.1-3-g733a5 From 06184b8d1052f716b9f46a86ed5bac5a942cc160 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:33:34 -0600 Subject: use sebug_assertions --- library/compiler-builtins/libm/src/math/lgamma_r.rs | 4 ++-- library/compiler-builtins/libm/src/math/lgammaf_r.rs | 4 ++-- library/compiler-builtins/libm/src/math/rem_pio2_large.rs | 4 ++-- library/compiler-builtins/libm/src/math/sincos.rs | 4 ++-- library/compiler-builtins/libm/src/math/sincosf.rs | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/src/math/lgamma_r.rs index 382a501fc3d..9533e882cc9 100644 --- a/library/compiler-builtins/libm/src/math/lgamma_r.rs +++ b/library/compiler-builtins/libm/src/math/lgamma_r.rs @@ -270,9 +270,9 @@ pub fn lgamma_r(mut x: f64) -> (f64, i32) { p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); r += -0.5 * y + p1 / p2; } - #[cfg(feature = "checked")] + #[cfg(debug_assertions)] _ => unreachable!(), - #[cfg(not(feature = "checked"))] + #[cfg(not(debug_assertions))] _ => {} } } else if ix < 0x40200000 { diff --git a/library/compiler-builtins/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/src/math/lgammaf_r.rs index 0745359a257..c5e559f4652 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf_r.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf_r.rs @@ -205,9 +205,9 @@ pub fn lgammaf_r(mut x: f32) -> (f32, i32) { p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); r += -0.5 * y + p1 / p2; } - #[cfg(feature = "checked")] + #[cfg(debug_assertions)] _ => unreachable!(), - #[cfg(not(feature = "checked"))] + #[cfg(not(debug_assertions))] _ => {} } } else if ix < 0x41000000 { diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 8533dc28948..002ce2e211f 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -461,9 +461,9 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i!(y, 2, =, -fw); } } - #[cfg(feature = "checked")] + #[cfg(debug_assertions)] _ => unreachable!(), - #[cfg(not(feature = "checked"))] + #[cfg(not(debug_assertions))] _ => {} } n & 7 diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs index 750908df4f7..d49f65c9707 100644 --- a/library/compiler-builtins/libm/src/math/sincos.rs +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -51,9 +51,9 @@ pub fn sincos(x: f64) -> (f64, f64) { 1 => (c, -s), 2 => (-s, -c), 3 => (-c, s), - #[cfg(feature = "checked")] + #[cfg(debug_assertions)] _ => unreachable!(), - #[cfg(not(feature = "checked"))] + #[cfg(not(debug_assertions))] _ => (0.0, 1.0), } } diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index bb9a0039201..d4e0772d5b1 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -115,9 +115,9 @@ pub fn sincosf(x: f32) -> (f32, f32) { 1 => (c, -s), 2 => (-s, -c), 3 => (-c, s), - #[cfg(feature = "checked")] + #[cfg(debug_assertions)] _ => unreachable!(), - #[cfg(not(feature = "checked"))] + #[cfg(not(debug_assertions))] _ => (0.0, 1.0), } } -- cgit 1.4.1-3-g733a5 From de3480c3c29126e36d23a535299e1069979f0c4a Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:36:08 -0600 Subject: Update run.sh --- library/compiler-builtins/libm/ci/run.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 59930b23879..ed253ab0d10 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -5,11 +5,14 @@ TARGET=$1 CMD="cargo test --all --target $TARGET" +# stable by default $CMD $CMD --release -$CMD --features 'stable' -$CMD --release --features 'stable' +# unstable with a feature +$CMD --features 'unstable' +$CMD --release --features 'unstable' -$CMD --features 'stable checked musl-reference-tests' -$CMD --release --features 'stable checked musl-reference-tests' +# also run the reference tests +$CMD --features 'unstable musl-reference-tests' +$CMD --release --features 'unstable musl-reference-tests' -- cgit 1.4.1-3-g733a5 From 0960b00b10f231a317e125cf454a54a5758670e3 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:57:15 -0600 Subject: suppress useless clippy warnings --- library/compiler-builtins/libm/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index e9def494051..e228af9b333 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -5,6 +5,15 @@ all(target_arch = "wasm32", feature = "unstable"), feature(core_intrinsics) )] +#![allow(clippy::unreadable_literal)] +#![allow(clippy::many_single_char_names)] +#![allow(clippy::needless_return)] +#![allow(clippy::int_plus_one)] +#![allow(clippy::deprecated_cfg_attr)] +#![allow(clippy::mixed_case_hex_literals)] +#![allow(clippy::float_cmp)] +#![allow(clippy::eq_op)] +#![allow(clippy::assign_op_pattern)] mod math; -- cgit 1.4.1-3-g733a5 From e9a2b2ca11b57e7a051087c5c14b3d89cb942e1e Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 6 Sep 2019 11:37:00 -0600 Subject: i was told to change this path to my repo and reset things --- library/compiler-builtins/.gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index a71118ff93e..23d29e11b4d 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ [submodule "libm"] path = libm - url = https://github.com/rust-lang-nursery/libm + url = https://github.com/Lokathor/libm -- cgit 1.4.1-3-g733a5 From 3ab350613b44869e1f3e5c7a594609f9fb7e1f1b Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 6 Sep 2019 13:48:15 -0600 Subject: Update the libm submodule --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 01bee72a93e..52983bee338 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 01bee72a93ebaeea2883d0f963174c2b00d4fe68 +Subproject commit 52983bee338ac439bc0f1146d6053955e3b4c33a -- cgit 1.4.1-3-g733a5 From e079f2d70d5813775bff2e23ed942f76474c1e0e Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 6 Sep 2019 15:20:05 -0600 Subject: Update build.rs --- library/compiler-builtins/build.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 490b6391d08..5cdabf95987 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -8,6 +8,9 @@ fn main() { println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); + // Activate libm's unstable features to make full use of Nightly. + println!("rustc-cfg=libm/unstable"); + // Emscripten's runtime includes all the builtins if target.contains("emscripten") { return; -- cgit 1.4.1-3-g733a5 From e796054f9ee7722a9b473de8de737a443bbd1112 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 6 Sep 2019 18:02:11 -0600 Subject: Update build.rs --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 5cdabf95987..b520b62477e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -9,7 +9,7 @@ fn main() { println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); // Activate libm's unstable features to make full use of Nightly. - println!("rustc-cfg=libm/unstable"); + println!("cargo:rustc-cfg=feature=\"unstable\""); // Emscripten's runtime includes all the builtins if target.contains("emscripten") { -- cgit 1.4.1-3-g733a5 From b86b2d59bc2f9141bbb71ec029677c5f9af321e0 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Mon, 9 Sep 2019 19:43:37 -0600 Subject: update the libm submodule, again --- library/compiler-builtins/.gitmodules | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index 23d29e11b4d..a71118ff93e 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ [submodule "libm"] path = libm - url = https://github.com/Lokathor/libm + url = https://github.com/rust-lang-nursery/libm diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 52983bee338..8eedc247053 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 52983bee338ac439bc0f1146d6053955e3b4c33a +Subproject commit 8eedc2470531f51b978e4c873ee78a33c90e0fbd -- cgit 1.4.1-3-g733a5 From fda4a8992f627723a7ffc7f2c801aa4c8148944e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 10 Sep 2019 10:07:17 -0500 Subject: Migrate from azure pipelines to Github actions (#226) Should make user management easier and also helps follow the repository when it's renamed. --- .../libm/.github/workflows/main.yml | 67 ++++++++++++++++++ library/compiler-builtins/libm/README.md | 4 +- library/compiler-builtins/libm/azure-pipelines.yml | 82 ---------------------- .../libm/ci/azure-install-rust.yml | 25 ------- 4 files changed, 68 insertions(+), 110 deletions(-) create mode 100644 library/compiler-builtins/libm/.github/workflows/main.yml delete mode 100644 library/compiler-builtins/libm/azure-pipelines.yml delete mode 100644 library/compiler-builtins/libm/ci/azure-install-rust.yml diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml new file mode 100644 index 00000000000..80ce4ebd5a6 --- /dev/null +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -0,0 +1,67 @@ +name: CI +on: [push, pull_request] + +jobs: + docker: + name: Docker + runs-on: ubuntu-latest + strategy: + matrix: + target: + - aarch64-unknown-linux-gnu + - arm-unknown-linux-gnueabi + - arm-unknown-linux-gnueabihf + - armv7-unknown-linux-gnueabihf + - i686-unknown-linux-gnu + - mips-unknown-linux-gnu + - mips64-unknown-linux-gnuabi64 + - mips64el-unknown-linux-gnuabi64 + - powerpc-unknown-linux-gnu + - powerpc64-unknown-linux-gnu + - powerpc64le-unknown-linux-gnu + - x86_64-unknown-linux-gnu + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update nightly && rustup default nightly + - run: rustup target add ${{ matrix.target }} + - run: rustup target add x86_64-unknown-linux-musl + - run: cargo generate-lockfile + - run: ./ci/run-docker.sh ${{ matrix.target }} + + rustfmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update stable && rustup default stable && rustup component add rustfmt + - run: cargo fmt -- --check + + wasm: + name: WebAssembly + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update nightly && rustup default nightly + - run: rustup target add wasm32-unknown-unknown + - run: cargo build --target wasm32-unknown-unknown + + cb: + name: "The compiler-builtins crate works" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update nightly && rustup default nightly + - run: cargo build -p cb + + benchmarks: + name: Benchmarks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update nightly && rustup default nightly + - run: cargo bench --all diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index e90b42d740c..61a6ebfb382 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -1,7 +1,5 @@ # `libm` -[![Build Status](https://dev.azure.com/rust-lang/libm/_apis/build/status/rust-lang-nursery.libm?branchName=master)](https://dev.azure.com/rust-lang/libm/_build/latest?definitionId=7&branchName=master) - A port of [MUSL]'s libm to Rust. [MUSL]: https://www.musl-libc.org/ @@ -27,7 +25,7 @@ The API documentation can be found [here](https://docs.rs/libm). ## Benchmark [benchmark]: #benchmark -The benchmarks are located in `crates/libm-bench` and require a nightly Rust toolchain. +The benchmarks are located in `crates/libm-bench` and require a nightly Rust toolchain. To run all benchmarks: > cargo +nightly bench --all diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml deleted file mode 100644 index 0d723c56dd2..00000000000 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ /dev/null @@ -1,82 +0,0 @@ -trigger: - - master - -jobs: - - job: Docker - pool: - vmImage: ubuntu-16.04 - steps: - - template: ci/azure-install-rust.yml - - bash: rustup target add $TARGET - displayName: "add cross target" - - bash: rustup target add x86_64-unknown-linux-musl - displayName: "add musl target" - - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET - displayName: "run tests" - strategy: - matrix: - aarch64: - TARGET: aarch64-unknown-linux-gnu - arm: - TARGET: arm-unknown-linux-gnueabi - armhf: - TARGET: arm-unknown-linux-gnueabihf - armv7: - TARGET: armv7-unknown-linux-gnueabihf - i686: - TARGET: i686-unknown-linux-gnu - mips: - TARGET: mips-unknown-linux-gnu - mips64: - TARGET: mips64-unknown-linux-gnuabi64 - mips64el: - TARGET: mips64el-unknown-linux-gnuabi64 - powerpc: - TARGET: powerpc-unknown-linux-gnu - powerpc64: - TARGET: powerpc64-unknown-linux-gnu - powerpc64le: - TARGET: powerpc64le-unknown-linux-gnu - x86_64: - TARGET: x86_64-unknown-linux-gnu - - - job: wasm - pool: - vmImage: ubuntu-16.04 - steps: - - template: ci/azure-install-rust.yml - - script: rustup target add wasm32-unknown-unknown - displayName: "Install rust wasm target" - - script: cargo build --target wasm32-unknown-unknown - displayName: "Build for wasm" - variables: - TOOLCHAIN: nightly - - - job: rustfmt - pool: - vmImage: ubuntu-16.04 - steps: - - template: ci/azure-install-rust.yml - - bash: rustup component add rustfmt - displayName: "install rustfmt" - - bash: cargo fmt --all -- --check - displayName: "check formatting" - - - job: compiler_builtins_works - pool: - vmImage: ubuntu-16.04 - steps: - - template: ci/azure-install-rust.yml - - bash: cargo build -p cb - displayName: "Check compiler-builtins still probably builds" - - - job: benchmarks - pool: - vmImage: ubuntu-16.04 - steps: - - template: ci/azure-install-rust.yml - - bash: cargo bench --all - displayName: "Benchmarks" - variables: - TOOLCHAIN: nightly - diff --git a/library/compiler-builtins/libm/ci/azure-install-rust.yml b/library/compiler-builtins/libm/ci/azure-install-rust.yml deleted file mode 100644 index f1cd87bcc5c..00000000000 --- a/library/compiler-builtins/libm/ci/azure-install-rust.yml +++ /dev/null @@ -1,25 +0,0 @@ -steps: - - bash: | - set -e - toolchain=$TOOLCHAIN - if [ "$toolchain" = "" ]; then - toolchain=stable - fi - if command -v rustup; then - rustup update $toolchain - rustup default $toolchain - else - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain - echo "##vso[task.prependpath]$HOME/.cargo/bin" - fi - displayName: Install rust (unix) - condition: ne( variables['Agent.OS'], 'Windows_NT' ) - - - bash: rustup update stable-$TOOLCHAIN && rustup default stable-$TOOLCHAIN - displayName: Install rust (windows) - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - - - script: | - rustc -Vv - cargo -V - displayName: Query rust and cargo versions -- cgit 1.4.1-3-g733a5 From 0198311a4b56a1fac90cdbd8dccaa587d4bd35be Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 10 Sep 2019 18:16:26 -0700 Subject: Migrate to github actions from Azure Pipelines Less need to manage users, more concurrency, and interface is all in one! --- .../compiler-builtins/.github/workflows/main.yml | 146 +++++++++++++++++++++ library/compiler-builtins/README.md | 2 - library/compiler-builtins/azure-pipelines.yml | 80 ----------- .../compiler-builtins/ci/azure-install-rust.yml | 30 ----- library/compiler-builtins/ci/azure-steps.yml | 28 ---- 5 files changed, 146 insertions(+), 140 deletions(-) create mode 100644 library/compiler-builtins/.github/workflows/main.yml delete mode 100644 library/compiler-builtins/azure-pipelines.yml delete mode 100644 library/compiler-builtins/ci/azure-install-rust.yml delete mode 100644 library/compiler-builtins/ci/azure-steps.yml diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml new file mode 100644 index 00000000000..f9fb844a98e --- /dev/null +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -0,0 +1,146 @@ +name: CI +on: [push, pull_request] + +jobs: + test: + name: Test + runs-on: ${{ matrix.os }} + strategy: + matrix: + target: + - aarch64-unknown-linux-gnu + - arm-unknown-linux-gnueabi + - arm-unknown-linux-gnueabihf + - i586-unknown-linux-gnu + - i686-unknown-linux-gnu + - mips-unknown-linux-gnu + - mips64-unknown-linux-gnuabi64 + - mips64el-unknown-linux-gnuabi64 + - mipsel-unknown-linux-gnu + - powerpc-unknown-linux-gnu + - powerpc64-unknown-linux-gnu + - powerpc64le-unknown-linux-gnu + - thumbv6m-none-eabi + - thumbv7em-none-eabi + - thumbv7em-none-eabihf + - thumbv7m-none-eabi + - wasm32-unknown-unknown + - x86_64-unknown-linux-gnu + - x86_64-apple-darwin + - i686-pc-windows-msvc + - x86_64-pc-windows-msvc + - i686-pc-windows-gnu + - x86_64-pc-windows-gnu + include: + - target: aarch64-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: arm-unknown-linux-gnueabi + os: ubuntu-latest + rust: nightly + - target: arm-unknown-linux-gnueabihf + os: ubuntu-latest + rust: nightly + - target: i586-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: i686-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: mips-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: mips64-unknown-linux-gnuabi64 + os: ubuntu-latest + rust: nightly + - target: mips64el-unknown-linux-gnuabi64 + os: ubuntu-latest + rust: nightly + - target: mipsel-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: powerpc-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: powerpc64-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: powerpc64le-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: thumbv6m-none-eabi + os: ubuntu-latest + rust: nightly + - target: thumbv7em-none-eabi + os: ubuntu-latest + rust: nightly + - target: thumbv7em-none-eabihf + os: ubuntu-latest + rust: nightly + - target: thumbv7m-none-eabi + os: ubuntu-latest + rust: nightly + - target: wasm32-unknown-unknown + os: ubuntu-latest + rust: nightly + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: x86_64-apple-darwin + os: macos-latest + rust: nightly + - target: i686-pc-windows-msvc + os: windows-latest + rust: nightly + - target: x86_64-pc-windows-msvc + os: windows-latest + rust: nightly + - target: i686-pc-windows-gnu + os: windows-latest + rust: nightly-i686-gnu + - target: x86_64-pc-windows-gnu + os: windows-latest + rust: nightly-x86_64-gnu + steps: + - uses: actions/checkout@master + with: + submodules: true + - name: Install Rust (rustup) + run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} + if: matrix.os != 'macos-latest' + - name: Install Rust (macos) + run: | + curl https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly + echo "##[add-path]$HOME/.cargo/bin" + if: matrix.os == 'macos-latest' + - run: rustup target add ${{ matrix.target }} + - name: Download compiler-rt reference sources + run: | + curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/8.0-2019-03-18.tar.gz + tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-8.0-2019-03-18/compiler-rt + echo "##[set-env name=RUST_COMPILER_RT_ROOT]./compiler-rt" + shell: bash + + # Non-linux tests just use our raw script + - run: ./ci/run.sh ${{ matrix.target }} + if: matrix.os != 'ubuntu-latest' + shell: bash + + # Wasm is special and is just build as a smoke test + - run: cargo build --target ${{ matrix.target }} + if: matrix.target == 'wasm32-unknown-unknown' + + # Otherwise we use our docker containers to run builds + - run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} + if: matrix.target != 'wasm32-unknown-unknown' && matrix.os == 'ubuntu-latest' + + rustfmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + with: + submodules: true + - name: Install Rust + run: rustup update stable && rustup default stable && rustup component add rustfmt + - run: cargo fmt -- --check diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index f0724bffe1d..262e9843d77 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,7 +1,5 @@ # `compiler-builtins` -[![Build Status](https://dev.azure.com/rust-lang/compiler-builtins/_apis/build/status/rust-lang-nursery.compiler-builtins?branchName=master)](https://dev.azure.com/rust-lang/compiler-builtins/_build/latest?definitionId=6&branchName=master) - > Porting `compiler-rt` intrinsics to Rust See [rust-lang/rust#35437][0]. diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml deleted file mode 100644 index eac3fb5e486..00000000000 --- a/library/compiler-builtins/azure-pipelines.yml +++ /dev/null @@ -1,80 +0,0 @@ -trigger: - - master - -jobs: - - job: Linux - pool: - vmImage: ubuntu-16.04 - steps: - - template: ci/azure-steps.yml - strategy: - matrix: - aarch64: - TARGET: aarch64-unknown-linux-gnu - arm: - TARGET: arm-unknown-linux-gnueabi - armhf: - TARGET: arm-unknown-linux-gnueabihf - i586: - TARGET: i586-unknown-linux-gnu - i686: - TARGET: i686-unknown-linux-gnu - mips: - TARGET: mips-unknown-linux-gnu - mips64: - TARGET: mips64-unknown-linux-gnuabi64 - mips64el: - TARGET: mips64el-unknown-linux-gnuabi64 - mipsel: - TARGET: mipsel-unknown-linux-gnu - powerpc: - TARGET: powerpc-unknown-linux-gnu - powerpc64: - TARGET: powerpc64-unknown-linux-gnu - powerpc64le: - TARGET: powerpc64le-unknown-linux-gnu - thumbv6m: - TARGET: thumbv6m-none-eabi - thumbv7em: - TARGET: thumbv7em-none-eabi - thumbv7emhf: - TARGET: thumbv7em-none-eabihf - thumbv7m: - TARGET: thumbv7m-none-eabi - wasm32: - TARGET: wasm32-unknown-unknown - ONLY_BUILD: 1 - x86_64: - TARGET: x86_64-unknown-linux-gnu - - - job: macOS - pool: - vmImage: macos-10.13 - steps: - - template: ci/azure-steps.yml - strategy: - matrix: - x86_64: - TARGET: x86_64-apple-darwin - i686: - TARGET: i686-apple-darwin - - - job: Windows - pool: - vmImage: 'vs2017-win2016' - steps: - - template: ci/azure-steps.yml - strategy: - matrix: - i686-msvc: - TARGET: i686-pc-windows-msvc - x86_64-msvc: - TARGET: x86_64-pc-windows-msvc - i686-gnu: - TARGET: i686-pc-windows-gnu - INTRINSICS_FAILS_WITH_MEM_FEATURE: 1 - DEBUG_LTO_BUILD_DOESNT_WORK: 1 - x86_64-gnu: - TARGET: x86_64-pc-windows-gnu - INTRINSICS_FAILS_WITH_MEM_FEATURE: 1 - DEBUG_LTO_BUILD_DOESNT_WORK: 1 diff --git a/library/compiler-builtins/ci/azure-install-rust.yml b/library/compiler-builtins/ci/azure-install-rust.yml deleted file mode 100644 index d0255f85b27..00000000000 --- a/library/compiler-builtins/ci/azure-install-rust.yml +++ /dev/null @@ -1,30 +0,0 @@ -parameters: - toolchain: 'nightly' - -steps: - - bash: | - set -e - if command -v rustup; then - rustup update $TOOLCHAIN - rustup default $TOOLCHAIN - else - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TOOLCHAIN - echo "##vso[task.prependpath]$HOME/.cargo/bin" - fi - displayName: Install rust - condition: ne( variables['Agent.OS'], 'Windows_NT' ) - env: - TOOLCHAIN: ${{ parameters.toolchain }} - - - script: | - rustup update --no-self-update %TOOLCHAIN%-%TARGET% - rustup default %TOOLCHAIN%-%TARGET% - displayName: Install rust - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - env: - TOOLCHAIN: ${{ parameters.toolchain }} - - - script: | - rustc -Vv - cargo -V - displayName: Query rust and cargo versions diff --git a/library/compiler-builtins/ci/azure-steps.yml b/library/compiler-builtins/ci/azure-steps.yml deleted file mode 100644 index f08beca05bf..00000000000 --- a/library/compiler-builtins/ci/azure-steps.yml +++ /dev/null @@ -1,28 +0,0 @@ -steps: - - checkout: self - submodules: true - - - template: azure-install-rust.yml - - - bash: rustup target add $TARGET - displayName: Install Rust target - - - bash: | - set -e - curl -L https://github.com/rust-lang/llvm-project/archive/rustc/8.0-2019-03-18.tar.gz | \ - tar xzf - --strip-components 1 llvm-project-rustc-8.0-2019-03-18/compiler-rt - echo '##vso[task.setvariable variable=RUST_COMPILER_RT_ROOT]./compiler-rt' - displayName: "Download compiler-rt reference sources" - - - bash: ./ci/run.sh $TARGET - condition: ne( variables['Agent.OS'], 'Linux' ) - displayName: Run test script - - - bash: | - if [ "$ONLY_BUILD" = "1" ]; then - cargo build --target $TARGET - else - cargo generate-lockfile && ./ci/run-docker.sh $TARGET - fi - condition: eq( variables['Agent.OS'], 'Linux' ) - displayName: Run docker test script -- cgit 1.4.1-3-g733a5 From d7adb275eb03ead501e772795049d7e8dd321ad1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Sep 2019 11:19:35 -0700 Subject: Update the gitmodule url for `libm` --- library/compiler-builtins/.gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index a71118ff93e..726b1c5c67c 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ [submodule "libm"] path = libm - url = https://github.com/rust-lang-nursery/libm + url = https://github.com/rust-lang/libm.git -- cgit 1.4.1-3-g733a5 From 30bf61039f4777bfd927c3fec8b8a7cc0f8ae5eb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Sep 2019 11:20:14 -0700 Subject: Remove `-nursery` from urls --- library/compiler-builtins/Cargo.toml | 4 ++-- library/compiler-builtins/README.md | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0705dbd9c32..2e3c7038e66 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -4,8 +4,8 @@ name = "compiler_builtins" version = "0.1.19" license = "MIT/Apache-2.0" readme = "README.md" -repository = "https://github.com/rust-lang-nursery/compiler-builtins" -homepage = "https://github.com/rust-lang-nursery/compiler-builtins" +repository = "https://github.com/rust-lang/compiler-builtins" +homepage = "https://github.com/rust-lang/compiler-builtins" documentation = "https://docs.rs/compiler_builtins" description = """ Compiler intrinsics used by the Rust compiler. Also available for other targets diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 262e9843d77..a20d038f8e9 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -19,7 +19,7 @@ building: ``` toml # Cargo.toml [dependencies] -compiler_builtins = { git = "https://github.com/rust-lang-nursery/compiler-builtins" } +compiler_builtins = { git = "https://github.com/rust-lang/compiler-builtins" } ``` ``` rust @@ -40,11 +40,11 @@ implementation as well for unimplemented intrinsics: ```toml [dependencies.compiler_builtins] -git = "https://github.com/rust-lang-nursery/compiler-builtins" +git = "https://github.com/rust-lang/compiler-builtins" features = ["c"] ``` -[an issue]: https://github.com/rust-lang-nursery/compiler-builtins/issues +[an issue]: https://github.com/rust-lang/compiler-builtins/issues ## Contributing @@ -61,8 +61,8 @@ features = ["c"] [1]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/test/builtins/Unit [2]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/lib/builtins -[3]: https://github.com/rust-lang-nursery/compiler-builtins/blob/0ba07e49264a54cb5bbd4856fcea083bb3fbec15/build.rs#L180-L265 -[4]: https://travis-ci.org/rust-lang-nursery/compiler-builtins +[3]: https://github.com/rust-lang/compiler-builtins/blob/0ba07e49264a54cb5bbd4856fcea083bb3fbec15/build.rs#L180-L265 +[4]: https://travis-ci.org/rust-lang/compiler-builtins ### Porting Reminders -- cgit 1.4.1-3-g733a5 From 52ecbdd9c011e8c472de0f25feb968896f6a355f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Sep 2019 11:20:49 -0700 Subject: Remove `-nursery` from urls --- library/compiler-builtins/libm/CONTRIBUTING.md | 6 +++--- library/compiler-builtins/libm/Cargo.toml | 2 +- library/compiler-builtins/libm/README.md | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index a7e817e13ed..59c37a6f959 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -14,13 +14,13 @@ corresponding issue. - :tada: -[issue tracker]: https://github.com/rust-lang-nursery/libm/issues +[issue tracker]: https://github.com/rust-lang/libm/issues [src]: https://git.musl-libc.org/cgit/musl/tree/src/math -[`src/math/truncf.rs`]: https://github.com/rust-lang-nursery/libm/blob/master/src/math/truncf.rs +[`src/math/truncf.rs`]: https://github.com/rust-lang/libm/blob/master/src/math/truncf.rs Check [PR #65] for an example. -[PR #65]: https://github.com/rust-lang-nursery/libm/pull/65 +[PR #65]: https://github.com/rust-lang/libm/pull/65 ## Tips and tricks diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 37aff9a765b..1d7d9714662 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -6,7 +6,7 @@ documentation = "https://docs.rs/libm" keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" -repository = "https://github.com/rust-lang-nursery/libm" +repository = "https://github.com/rust-lang/libm" version = "0.2.0" edition = "2018" diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 61a6ebfb382..5d9e9bddbf8 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -7,12 +7,12 @@ A port of [MUSL]'s libm to Rust. ## Goals The short term goal of this library is to [enable math support (e.g. `sin`, `atan2`) for the -`wasm32-unknown-unknown` target][wasm] (cf. [rust-lang-nursery/compiler-builtins][pr]). The longer +`wasm32-unknown-unknown` target][wasm] (cf. [rust-lang/compiler-builtins][pr]). The longer term goal is to enable [math support in the `core` crate][core]. -[wasm]: https://github.com/rust-lang-nursery/libm/milestone/1 -[pr]: https://github.com/rust-lang-nursery/compiler-builtins/pull/248 -[core]: https://github.com/rust-lang-nursery/libm/milestone/2 +[wasm]: https://github.com/rust-lang/libm/milestone/1 +[pr]: https://github.com/rust-lang/compiler-builtins/pull/248 +[core]: https://github.com/rust-lang/libm/milestone/2 ## Already usable -- cgit 1.4.1-3-g733a5 From af3d2e0a3c8d2992b458b84c209036d2d0317b6c Mon Sep 17 00:00:00 2001 From: Ian Kronquist Date: Mon, 30 Sep 2019 09:02:47 -0700 Subject: Implement bcmp (#315) As of LLVM 9.0, certain calls to memcmp may be converted to bcmp, which I guess could save a single subtraction on some architectures. [1] bcmp is just like memcmp except instead of returning the difference between the two differing bytes, it returns non-zero instead. As such, memcmp is a valid implementation of bcmp. If we care about size, bcmp should just call memcmp. If we care about speed, we can change bcmp to look like this instead: ```rust pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { let mut i = 0; while i < n { let a = *s1.offset(i as isize); let b = *s2.offset(i as isize); if a != b { return 1; } i += 1; } 0 } ``` In this PR I do not address any changes which may or may not be needed for arm aebi as I lack proper test hardware. [1]: https://releases.llvm.org/9.0.0/docs/ReleaseNotes.html#noteworthy-optimizations --- library/compiler-builtins/src/mem.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index 76372d9bc81..7b8a37fde7b 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -63,6 +63,11 @@ pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { 0 } +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + memcmp(s1, s2, n) +} + // `bytes` must be a multiple of `mem::size_of::()` fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { unsafe { -- cgit 1.4.1-3-g733a5 From 3b3f3e977cdbdf57a70fb3565dc59806df75f81b Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Fri, 18 Oct 2019 15:23:57 +0200 Subject: Fix sincosf(PI) (#229) Looks like the implementation was not ported correctly. Some negations were forgotten in a certain branch. Here is the original code in musl that has the negations: https://github.com/bpowers/musl/blob/94cb2ec2a0ffcb47d24dbf7a30e462505396cf54/src/math/sincosf.c#L66-L67 Resolves rust-lang/libm#228 --- library/compiler-builtins/libm/src/math/sincosf.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index d4e0772d5b1..df644f3b5e3 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -65,11 +65,11 @@ pub fn sincosf(x: f32) -> (f32, f32) { /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ else { if sign { - s = k_sinf((x + S2PIO2) as f64); - c = k_cosf((x + S2PIO2) as f64); + s = -k_sinf((x + S2PIO2) as f64); + c = -k_cosf((x + S2PIO2) as f64); } else { - s = k_sinf((x - S2PIO2) as f64); - c = k_cosf((x - S2PIO2) as f64); + s = -k_sinf((x - S2PIO2) as f64); + c = -k_cosf((x - S2PIO2) as f64); } } @@ -121,3 +121,16 @@ pub fn sincosf(x: f32) -> (f32, f32) { _ => (0.0, 1.0), } } + +#[cfg(test)] +mod tests { + use super::sincosf; + use crate::_eqf; + + #[test] + fn with_pi() { + let (s, c) = sincosf(core::f32::consts::PI); + _eqf(s.abs(), 0.0).unwrap(); + _eqf(c, -1.0).unwrap(); + } +} -- cgit 1.4.1-3-g733a5 From 12283c7acad3dbf62556f8a72d5eedeeba4fbe2e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 28 Oct 2019 07:39:04 -0700 Subject: Fix Github Actions for recent system changes --- library/compiler-builtins/.github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index f9fb844a98e..92ce9ca2174 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -108,6 +108,7 @@ jobs: - name: Install Rust (rustup) run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} if: matrix.os != 'macos-latest' + shell: bash - name: Install Rust (macos) run: | curl https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly -- cgit 1.4.1-3-g733a5 From bff186bef3532240249f4b637966a17db2379c96 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 7 Nov 2019 20:04:11 +0100 Subject: Emit `_fltused` on `uefi` targets as a short-term workaround (#317) * Emit `_fltused` on `uefi` targets as a short-term workaround * Remove stray docker container --- library/compiler-builtins/src/x86_64.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 2360ab8a6fa..6940f8d9d29 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -73,3 +73,10 @@ pub unsafe fn ___chkstk() { ); intrinsics::unreachable(); } + +// HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM +// support unless we emit the _fltused +#[no_mangle] +#[used] +#[cfg(target_os = "uefi")] +static _fltused: i32 = 0; -- cgit 1.4.1-3-g733a5 From 5067dce07477fbf264c1ec4f09a17e22a0e1d8e2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 7 Nov 2019 11:04:36 -0800 Subject: Bump to 0.1.20 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 2e3c7038e66..b667894abdc 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.19" +version = "0.1.20" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 3f473cd3f38eba3aa275a5ffb8991314baa49a87 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Nov 2019 12:19:10 -0600 Subject: Allow FFI-unsafe warnings for u128/i128 (#323) * Allow FFI-unsafe warnings for u128/i128 Handle new warnings on nightly, and we shouldn't need to worry about these with compiler-builtins since this is tied to a particular compiler. * Clean up crate attributes * No need for stability marker * Rustdoc docs not used for this crate * Remove old build-system related cruft from rustc itself. * Run `cargo fmt` --- library/compiler-builtins/examples/intrinsics.rs | 1 - library/compiler-builtins/src/lib.rs | 33 ++++++-------------- .../testcrate/tests/aeabi_memclr.rs | 2 +- .../testcrate/tests/aeabi_memset.rs | 36 +++++++++++----------- 4 files changed, 28 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 8b0ffa3a8d6..5ceebe13216 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -7,7 +7,6 @@ #![cfg_attr(thumb, no_main)] #![deny(dead_code)] #![feature(asm)] -#![feature(compiler_builtins_lib)] #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index ef5353a7040..d90927aae1f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,34 +1,19 @@ -#![cfg_attr(not(stage0), deny(warnings))] -#![cfg_attr(not(test), no_std)] #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] -#![crate_name = "compiler_builtins"] -#![crate_type = "rlib"] -#![doc( - html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", - html_playground_url = "https://play.rust-lang.org/", - test(attr(deny(warnings))) -)] +#![feature(abi_unadjusted)] #![feature(asm)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] +#![feature(lang_items)] +#![feature(linkage)] #![feature(naked_functions)] #![feature(repr_simd)] -#![feature(abi_unadjusted)] -#![feature(linkage)] -#![feature(lang_items)] -#![allow(unused_features)] #![no_builtins] -#![cfg_attr(feature = "compiler-builtins", feature(staged_api))] -#![cfg_attr( - feature = "compiler-builtins", - unstable( - feature = "compiler_builtins_lib", - reason = "Compiler builtins. Will never become stable.", - issue = "0" - ) -)] +#![no_std] +#![allow(unused_features)] +// We use `u128` in a whole bunch of places which we currently agree with the +// compiler on ABIs and such, so we should be "good enough" for now and changes +// to the `u128` ABI will be reflected here. +#![allow(improper_ctypes)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs index 326435c298d..59507693988 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs @@ -46,7 +46,7 @@ impl Aligned { #[test] fn memclr4() { - let mut aligned = Aligned::new();; + let mut aligned = Aligned::new(); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs index 3cfbfe5b011..f03729bed35 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs @@ -45,7 +45,7 @@ impl Aligned { #[test] fn zero() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -54,7 +54,7 @@ fn zero() { assert_eq!(*xs, [0; 8]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -66,7 +66,7 @@ fn zero() { #[test] fn one() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 1; @@ -76,7 +76,7 @@ fn one() { assert_eq!(*xs, [0xef, 0, 0, 0, 0, 0, 0, 0]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -88,7 +88,7 @@ fn one() { #[test] fn two() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 2; @@ -98,7 +98,7 @@ fn two() { assert_eq!(*xs, [0xef, 0xef, 0, 0, 0, 0, 0, 0]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -110,7 +110,7 @@ fn two() { #[test] fn three() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 3; @@ -120,7 +120,7 @@ fn three() { assert_eq!(*xs, [0xef, 0xef, 0xef, 0, 0, 0, 0, 0]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -132,7 +132,7 @@ fn three() { #[test] fn four() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 4; @@ -142,7 +142,7 @@ fn four() { assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0, 0, 0, 0]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -154,7 +154,7 @@ fn four() { #[test] fn five() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 5; @@ -164,7 +164,7 @@ fn five() { assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0, 0, 0]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -176,7 +176,7 @@ fn five() { #[test] fn six() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 6; @@ -186,7 +186,7 @@ fn six() { assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0, 0]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -198,7 +198,7 @@ fn six() { #[test] fn seven() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 7; @@ -208,7 +208,7 @@ fn seven() { assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -220,7 +220,7 @@ fn seven() { #[test] fn eight() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 8; @@ -230,7 +230,7 @@ fn eight() { assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; -- cgit 1.4.1-3-g733a5 From eb58e12abf74654faaa04e5e36d270fff8943fae Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Nov 2019 12:38:50 -0600 Subject: Gate atomic intrinsics on presence of instructions (#324) Don't emit the intrinsics for platforms which don't actually have the instructions to do atomic loads/stores. Closes #322 --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/mem.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index d90927aae1f..0e1a435370f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![feature(abi_unadjusted)] #![feature(asm)] +#![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] #![feature(lang_items)] diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index 7b8a37fde7b..24552ed8510 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -129,50 +129,65 @@ where } intrinsics! { + #[cfg(target_has_atomic_load_store = "8")] pub extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "16")] pub extern "C" fn __llvm_memcpy_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "32")] pub extern "C" fn __llvm_memcpy_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "64")] pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "128")] pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "8")] pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "16")] pub extern "C" fn __llvm_memmove_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "32")] pub extern "C" fn __llvm_memmove_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "64")] pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "128")] pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "8")] pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } + #[cfg(target_has_atomic_load_store = "16")] pub extern "C" fn __llvm_memset_element_unordered_atomic_2(s: *mut u16, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } + #[cfg(target_has_atomic_load_store = "32")] pub extern "C" fn __llvm_memset_element_unordered_atomic_4(s: *mut u32, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } + #[cfg(target_has_atomic_load_store = "64")] pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } + #[cfg(target_has_atomic_load_store = "128")] pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } -- cgit 1.4.1-3-g733a5 From 4729d8bf39f2edc599ba11c22ab2dfb329d75ba6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Nov 2019 10:39:08 -0800 Subject: Bump to 0.1.21 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index b667894abdc..200c41bf83f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.20" +version = "0.1.21" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 62c025e9a85a65f5e8b88a1232720d464d80eb1f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Nov 2019 10:40:09 -0800 Subject: Update publishing instructions --- library/compiler-builtins/PUBLISHING.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/PUBLISHING.md b/library/compiler-builtins/PUBLISHING.md index ad100dee08f..3df682ab04a 100644 --- a/library/compiler-builtins/PUBLISHING.md +++ b/library/compiler-builtins/PUBLISHING.md @@ -10,8 +10,7 @@ greatly appreciated! 3. Commit this change 4. Run `git tag` to create a tag for this version 5. Delete the `libm/Cargo.toml` file -6. Comment out the `[dev-dependencies]` section of `Cargo.toml` -7. Run `cargo +nightly publish --allow-dirty` -8. Push the tag -9. Push the commit -10. Undo changes to `Cargo.toml` and the `libm` submodule +6. Run `cargo +nightly publish` +7. Push the tag +8. Push the commit +9. Undo changes to `Cargo.toml` and the `libm` submodule -- cgit 1.4.1-3-g733a5 From a8d9eb7521122bf58cbe1bd8d313b37aede07bdb Mon Sep 17 00:00:00 2001 From: AJ Frantz Date: Fri, 22 Nov 2019 14:16:00 -0500 Subject: Fix sincosf for interval (7*pi/4, 9*pi/4) (#233) A mistake was made in porting musl's implementation which caused the sin and cos components to be reversed. closes rust-lang/libm#232 --- library/compiler-builtins/libm/src/math/sincosf.rs | 26 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index df644f3b5e3..2725caad63c 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -89,11 +89,11 @@ pub fn sincosf(x: f32) -> (f32, f32) { } } else { if sign { - s = k_cosf((x + S4PIO2) as f64); - c = k_sinf((x + S4PIO2) as f64); + s = k_sinf((x + S4PIO2) as f64); + c = k_cosf((x + S4PIO2) as f64); } else { - s = k_cosf((x - S4PIO2) as f64); - c = k_sinf((x - S4PIO2) as f64); + s = k_sinf((x - S4PIO2) as f64); + c = k_cosf((x - S4PIO2) as f64); } } @@ -133,4 +133,22 @@ mod tests { _eqf(s.abs(), 0.0).unwrap(); _eqf(c, -1.0).unwrap(); } + + #[test] + fn rotational_symmetry() { + use core::f32::consts::PI; + const N: usize = 24; + for n in 0..N { + let theta = 2. * PI * (n as f32) / (N as f32); + let (s, c) = sincosf(theta); + let (s_plus, c_plus) = sincosf(theta + 2. * PI); + let (s_minus, c_minus) = sincosf(theta - 2. * PI); + + const TOLERANCE: f32 = 1e-6; + assert!((s - s_plus).abs() < TOLERANCE); + assert!((s - s_minus).abs() < TOLERANCE); + assert!((c - c_plus).abs() < TOLERANCE); + assert!((c - c_minus).abs() < TOLERANCE); + } + } } -- cgit 1.4.1-3-g733a5 From d6d215b97c6300ce15a8a0338520b82ac53b4fa4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 22 Nov 2019 11:16:36 -0800 Subject: Bump to 0.2.1 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 1d7d9714662..d9d6680409e 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" repository = "https://github.com/rust-lang/libm" -version = "0.2.0" +version = "0.2.1" edition = "2018" [features] -- cgit 1.4.1-3-g733a5 From ca69fcbf1277d31dbcfd2136a460a8209d4ef129 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 3 Dec 2019 09:11:29 -0800 Subject: Update checkout action reference --- library/compiler-builtins/.github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 92ce9ca2174..1e1666ab50d 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -102,7 +102,7 @@ jobs: os: windows-latest rust: nightly-x86_64-gnu steps: - - uses: actions/checkout@master + - uses: actions/checkout@v1 with: submodules: true - name: Install Rust (rustup) @@ -139,7 +139,7 @@ jobs: name: Rustfmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v1 with: submodules: true - name: Install Rust -- cgit 1.4.1-3-g733a5 From d511d48b973cc5f8015ab2e1fbbb2b66d2eefab3 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 6 Dec 2019 06:51:42 -0800 Subject: Add control flow information to __rust_probestack (#328) --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/probestack.rs | 232 +++++++++++++++++----------- 2 files changed, 144 insertions(+), 89 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0e1a435370f..e57a5ef3f87 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![feature(abi_unadjusted)] #![feature(asm)] +#![feature(global_asm)] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 9bcaf4fd13d..933a60dd985 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -41,95 +41,149 @@ //! probes on any other architecture like ARM or PowerPC64. LLVM I'm sure would //! be more than welcome to accept such a change! -#![cfg(not(windows))] // Windows already has builtins to do this - -#[naked] -#[no_mangle] -#[cfg(all(target_arch = "x86_64", not(feature = "mangled-names")))] -pub unsafe extern "C" fn __rust_probestack() { - // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, - // ensuring that if any pages are unmapped we'll make a page fault. - // - // The ABI here is that the stack frame size is located in `%eax`. Upon - // return we're not supposed to modify `%esp` or `%eax`. - asm!(" - pushq %rbp - movq %rsp, %rbp - - mov %rax,%r11 // duplicate %rax as we're clobbering %r11 - - // Main loop, taken in one page increments. We're decrementing rsp by - // a page each time until there's less than a page remaining. We're - // guaranteed that this function isn't called unless there's more than a - // page needed. - // - // Note that we're also testing against `8(%rsp)` to account for the 8 - // bytes pushed on the stack orginally with our return address. Using - // `8(%rsp)` simulates us testing the stack pointer in the caller's - // context. - - // It's usually called when %rax >= 0x1000, but that's not always true. - // Dynamic stack allocation, which is needed to implement unsized - // rvalues, triggers stackprobe even if %rax < 0x1000. - // Thus we have to check %r11 first to avoid segfault. - cmp $$0x1000,%r11 - jna 3f - 2: - sub $$0x1000,%rsp - test %rsp,8(%rsp) - sub $$0x1000,%r11 - cmp $$0x1000,%r11 - ja 2b - - 3: - // Finish up the last remaining stack space requested, getting the last - // bits out of r11 - sub %r11,%rsp - test %rsp,8(%rsp) - - // Restore the stack pointer to what it previously was when entering - // this function. The caller will readjust the stack pointer after we - // return. - add %rax,%rsp - - leave - ret - " ::: "memory" : "volatile"); - ::core::intrinsics::unreachable(); +#![cfg(not(feature = "mangled-names"))] +// Windows already has builtins to do this. +#![cfg(not(windows))] +// We only define stack probing for these architectures today. +#![cfg(any(target_arch = "x86_64", target_arch = "x86"))] + +extern "C" { + pub fn __rust_probestack(); } -#[naked] -#[no_mangle] -#[cfg(all(target_arch = "x86", not(feature = "mangled-names")))] -pub unsafe extern "C" fn __rust_probestack() { - // This is the same as x86_64 above, only translated for 32-bit sizes. Note - // that on Unix we're expected to restore everything as it was, this - // function basically can't tamper with anything. - // - // The ABI here is the same as x86_64, except everything is 32-bits large. - asm!(" - push %ebp - mov %esp, %ebp - push %ecx - mov %eax,%ecx - - cmp $$0x1000,%ecx - jna 3f - 2: - sub $$0x1000,%esp - test %esp,8(%esp) - sub $$0x1000,%ecx - cmp $$0x1000,%ecx - ja 2b - - 3: - sub %ecx,%esp - test %esp,8(%esp) - - add %eax,%esp - pop %ecx - leave - ret - " ::: "memory" : "volatile"); - ::core::intrinsics::unreachable(); +// A wrapper for our implementation of __rust_probestack, which allows us to +// keep the assembly inline while controlling all CFI directives in the assembly +// emitted for the function. +// +// This is the ELF version. +#[cfg(not(target_vendor = "apple"))] +macro_rules! define_rust_probestack { + ($body: expr) => { + concat!( + " + .pushsection .text.__rust_probestack + .globl __rust_probestack + .type __rust_probestack, @function + __rust_probestack: + ", + $body, + " + .size __rust_probestack, . - __rust_probestack + .popsection + " + ) + }; +} + +// Same as above, but for Mach-O. +#[cfg(target_vendor = "apple")] +macro_rules! define_rust_probestack { + ($body: expr) => { + concat!( + " + .globl ___rust_probestack + ___rust_probestack: + ", + $body + ) + }; } + +// Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, +// ensuring that if any pages are unmapped we'll make a page fault. +// +// The ABI here is that the stack frame size is located in `%rax`. Upon +// return we're not supposed to modify `%rsp` or `%rax`. +#[cfg(target_arch = "x86_64")] +global_asm!(define_rust_probestack!( + " + .cfi_startproc + pushq %rbp + .cfi_adjust_cfa_offset 8 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + + mov %rax,%r11 // duplicate %rax as we're clobbering %r11 + + // Main loop, taken in one page increments. We're decrementing rsp by + // a page each time until there's less than a page remaining. We're + // guaranteed that this function isn't called unless there's more than a + // page needed. + // + // Note that we're also testing against `8(%rsp)` to account for the 8 + // bytes pushed on the stack orginally with our return address. Using + // `8(%rsp)` simulates us testing the stack pointer in the caller's + // context. + + // It's usually called when %rax >= 0x1000, but that's not always true. + // Dynamic stack allocation, which is needed to implement unsized + // rvalues, triggers stackprobe even if %rax < 0x1000. + // Thus we have to check %r11 first to avoid segfault. + cmp $0x1000,%r11 + jna 3f +2: + sub $0x1000,%rsp + test %rsp,8(%rsp) + sub $0x1000,%r11 + cmp $0x1000,%r11 + ja 2b + +3: + // Finish up the last remaining stack space requested, getting the last + // bits out of r11 + sub %r11,%rsp + test %rsp,8(%rsp) + + // Restore the stack pointer to what it previously was when entering + // this function. The caller will readjust the stack pointer after we + // return. + add %rax,%rsp + + leave + .cfi_def_cfa_register %rsp + .cfi_adjust_cfa_offset -8 + ret + .cfi_endproc + " +)); + +#[cfg(target_arch = "x86")] +// This is the same as x86_64 above, only translated for 32-bit sizes. Note +// that on Unix we're expected to restore everything as it was, this +// function basically can't tamper with anything. +// +// The ABI here is the same as x86_64, except everything is 32-bits large. +global_asm!(define_rust_probestack!( + " + .cfi_startproc + push %ebp + .cfi_adjust_cfa_offset 4 + .cfi_offset %ebp, -8 + mov %esp, %ebp + .cfi_def_cfa_register %ebp + push %ecx + mov %eax,%ecx + + cmp $0x1000,%ecx + jna 3f +2: + sub $0x1000,%esp + test %esp,8(%esp) + sub $0x1000,%ecx + cmp $0x1000,%ecx + ja 2b + +3: + sub %ecx,%esp + test %esp,8(%esp) + + add %eax,%esp + pop %ecx + leave + .cfi_def_cfa_register %esp + .cfi_adjust_cfa_offset -4 + ret + .cfi_endproc + " +)); -- cgit 1.4.1-3-g733a5 From c056e295e23c17d89a27eb62b165a03ab5c46696 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 6 Dec 2019 06:54:50 -0800 Subject: Bump to 1.0.22 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 200c41bf83f..4d5ffa712a7 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.21" +version = "0.1.22" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 304028b2ed215dddbd141cfcd2ab37f9da479914 Mon Sep 17 00:00:00 2001 From: Runji Wang Date: Wed, 11 Dec 2019 01:02:14 +0800 Subject: Fix compile error on x86_64-unknown-uefi target (#331) * fix compile error on x86_64-unknown-uefi target * Fix tests on nightly --- library/compiler-builtins/src/probestack.rs | 4 ++-- library/compiler-builtins/testcrate/tests/count_leading_zeros.rs | 2 -- library/compiler-builtins/testcrate/tests/generated.rs | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 933a60dd985..70b33b8be2d 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -56,7 +56,7 @@ extern "C" { // emitted for the function. // // This is the ELF version. -#[cfg(not(target_vendor = "apple"))] +#[cfg(not(any(target_vendor = "apple", target_os = "uefi")))] macro_rules! define_rust_probestack { ($body: expr) => { concat!( @@ -76,7 +76,7 @@ macro_rules! define_rust_probestack { } // Same as above, but for Mach-O. -#[cfg(target_vendor = "apple")] +#[cfg(any(target_vendor = "apple", target_os = "uefi"))] macro_rules! define_rust_probestack { ($body: expr) => { concat!( diff --git a/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs b/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs index b50a7ce8430..022b2d85293 100644 --- a/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs +++ b/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs @@ -1,5 +1,3 @@ -#![feature(compiler_builtins_lib)] - extern crate compiler_builtins; use compiler_builtins::int::__clzsi2; diff --git a/library/compiler-builtins/testcrate/tests/generated.rs b/library/compiler-builtins/testcrate/tests/generated.rs index ee575cba87e..a296db22da6 100644 --- a/library/compiler-builtins/testcrate/tests/generated.rs +++ b/library/compiler-builtins/testcrate/tests/generated.rs @@ -1,4 +1,3 @@ -#![feature(compiler_builtins_lib)] #![feature(lang_items)] #![allow(bad_style)] #![allow(unused_imports)] -- cgit 1.4.1-3-g733a5 From 643306f30836e0d0de45e6f4d6d858a427c642ee Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 10 Dec 2019 09:02:40 -0800 Subject: Bump to 0.1.23 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 4d5ffa712a7..39c4553fe1e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.22" +version = "0.1.23" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 328332003d2399c179a4488c393fb8d77ddd6a78 Mon Sep 17 00:00:00 2001 From: Adam Schwalm Date: Mon, 6 Jan 2020 10:22:30 -0600 Subject: Add separate rust_probestack definition for uefi (#335) This is necessary because the Mach-O definition must have the triple underscore, but the UEFI one must not. --- library/compiler-builtins/src/probestack.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 70b33b8be2d..3797df0d56b 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -75,8 +75,22 @@ macro_rules! define_rust_probestack { }; } -// Same as above, but for Mach-O. -#[cfg(any(target_vendor = "apple", target_os = "uefi"))] +#[cfg(target_os = "uefi")] +macro_rules! define_rust_probestack { + ($body: expr) => { + concat!( + " + .globl __rust_probestack + __rust_probestack: + ", + $body + ) + }; +} + +// Same as above, but for Mach-O. Note that the triple underscore +// is deliberate +#[cfg(target_vendor = "apple")] macro_rules! define_rust_probestack { ($body: expr) => { concat!( -- cgit 1.4.1-3-g733a5 From 8647190d6c57211c6ddec677e9a0821cea30a4e6 Mon Sep 17 00:00:00 2001 From: Daniel Frampton Date: Tue, 14 Jan 2020 13:28:10 -0800 Subject: Don't modify the intrinsic abi for aarch64 windows (#337) --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/src/macros.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 39c4553fe1e..3203f1c6c02 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.23" +version = "0.1.24" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 2d11ba622b8..a86794072c2 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -165,13 +165,13 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(windows, target_pointer_width = "64"))] + #[cfg(all(windows, target_arch = "x86_64"))] $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } - #[cfg(all(windows, target_pointer_width = "64"))] + #[cfg(all(windows, target_arch = "x86_64"))] pub mod $name { intrinsics! { @@ -184,7 +184,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(windows, target_pointer_width = "64")))] + #[cfg(not(all(windows, target_arch = "x86_64")))] intrinsics! { $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { -- cgit 1.4.1-3-g733a5 From b2227dc5594895d8ee410b03b1aa4d64eab60c54 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 28 Jan 2020 00:39:52 -0800 Subject: Update CI installation of Rust on macos --- library/compiler-builtins/.github/workflows/main.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 1e1666ab50d..46915499764 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -107,13 +107,7 @@ jobs: submodules: true - name: Install Rust (rustup) run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} - if: matrix.os != 'macos-latest' shell: bash - - name: Install Rust (macos) - run: | - curl https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly - echo "##[add-path]$HOME/.cargo/bin" - if: matrix.os == 'macos-latest' - run: rustup target add ${{ matrix.target }} - name: Download compiler-rt reference sources run: | -- cgit 1.4.1-3-g733a5 From 6677b55fcbbe11b8a9387144e4a0cd17dc15cc6c Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 11 Feb 2020 22:21:12 -0800 Subject: Set probestack visibility to hidden on ELF targets (#340) --- library/compiler-builtins/src/probestack.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 3797df0d56b..19307df4e93 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -64,6 +64,7 @@ macro_rules! define_rust_probestack { .pushsection .text.__rust_probestack .globl __rust_probestack .type __rust_probestack, @function + .hidden __rust_probestack __rust_probestack: ", $body, -- cgit 1.4.1-3-g733a5 From 8e87d8a3b50479b9b04b74aba3d6604d41756ebd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 11 Feb 2020 22:21:38 -0800 Subject: Bump to 0.1.25 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 3203f1c6c02..d7518970997 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.24" +version = "0.1.25" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From d370d2728bfbf5ea1fcc1437b32a48eb4f0d2855 Mon Sep 17 00:00:00 2001 From: Yuxiang Zhu Date: Wed, 12 Feb 2020 10:44:10 +0800 Subject: add mips/mips64 compiler-rt fallbacks so that libgcc is not required This adds compiler-rt fallbacks for mips and mips64 arches. Solves linking issues like https://github.com/rust-lang/rust/issues/57820. Signed-off-by: Yuxiang Zhu --- library/compiler-builtins/.github/workflows/main.yml | 4 ++-- library/compiler-builtins/build.rs | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 46915499764..750f288cf40 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -111,8 +111,8 @@ jobs: - run: rustup target add ${{ matrix.target }} - name: Download compiler-rt reference sources run: | - curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/8.0-2019-03-18.tar.gz - tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-8.0-2019-03-18/compiler-rt + curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/10.0-2020-02-05.tar.gz + tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-10.0-2020-02-05/compiler-rt echo "##[set-env name=RUST_COMPILER_RT_ROOT]./compiler-rt" shell: bash diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index b520b62477e..b3c65d5b9c6 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -396,6 +396,25 @@ mod c { } } + if target_arch == "mips" { + sources.extend(&[("__bswapsi2", "bswapsi2.c")]); + } + + if target_arch == "mips64" { + sources.extend(&[ + ("__extenddftf2", "extenddftf2.c"), + ("__netf2", "comparetf2.c"), + ("__addtf3", "addtf3.c"), + ("__multf3", "multf3.c"), + ("__subtf3", "subtf3.c"), + ("__fixtfsi", "fixtfsi.c"), + ("__floatsitf", "floatsitf.c"), + ("__fixunstfsi", "fixunstfsi.c"), + ("__floatunsitf", "floatunsitf.c"), + ("__fe_getround", "fp_mode.c"), + ]); + } + // Remove the assembly implementations that won't compile for the target if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { let mut to_remove = Vec::new(); -- cgit 1.4.1-3-g733a5 From c82ad6a29419c9178410d9f51d565725998f11cd Mon Sep 17 00:00:00 2001 From: Wolfgang Silbermayr Date: Fri, 21 Feb 2020 11:01:50 +0100 Subject: Use lower-case file extension for LICENSE.txt The `LICENSE.txt` file should be distributed to crates.io, but it wasn't due to the `Cargo.toml` entry in the `includes` field being `LICENSE.txt` with lower-case file extension while the file itself had an upper-case extension. --- library/compiler-builtins/LICENSE.TXT | 91 ----------------------------------- library/compiler-builtins/LICENSE.txt | 91 +++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 91 deletions(-) delete mode 100644 library/compiler-builtins/LICENSE.TXT create mode 100644 library/compiler-builtins/LICENSE.txt diff --git a/library/compiler-builtins/LICENSE.TXT b/library/compiler-builtins/LICENSE.TXT deleted file mode 100644 index 92bbe113ab2..00000000000 --- a/library/compiler-builtins/LICENSE.TXT +++ /dev/null @@ -1,91 +0,0 @@ -============================================================================== -compiler-builtins License -============================================================================== - -The compiler-builtins crate is dual licensed under both the University of -Illinois "BSD-Like" license and the MIT license. As a user of this code you may -choose to use it under either license. As a contributor, you agree to allow -your code to be used under both. - -Full text of the relevant licenses is included below. - -============================================================================== - -University of Illinois/NCSA -Open Source License - -Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT - -All rights reserved. - -Developed by: - - LLVM Team - - University of Illinois at Urbana-Champaign - - http://llvm.org - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal with -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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimers. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimers in the - documentation and/or other materials provided with the distribution. - - * Neither the names of the LLVM Team, University of Illinois at - Urbana-Champaign, nor the names of its contributors may be used to - endorse or promote products derived from this Software without specific - prior written permission. - -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 -CONTRIBUTORS 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 WITH THE -SOFTWARE. - -============================================================================== - -Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT - -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. - -============================================================================== -Copyrights and Licenses for Third Party Software Distributed with LLVM: -============================================================================== -The LLVM software contains code written by third parties. Such software will -have its own individual LICENSE.TXT file in the directory in which it appears. -This file will describe the copyrights, license, and restrictions which apply -to that code. - -The disclaimer of warranty in the University of Illinois Open Source License -applies to all code in the LLVM Distribution, and nothing in any of the -other licenses gives permission to use the names of the LLVM Team or the -University of Illinois to endorse or promote products derived from this -Software. - diff --git a/library/compiler-builtins/LICENSE.txt b/library/compiler-builtins/LICENSE.txt new file mode 100644 index 00000000000..92bbe113ab2 --- /dev/null +++ b/library/compiler-builtins/LICENSE.txt @@ -0,0 +1,91 @@ +============================================================================== +compiler-builtins License +============================================================================== + +The compiler-builtins crate is dual licensed under both the University of +Illinois "BSD-Like" license and the MIT license. As a user of this code you may +choose to use it under either license. As a contributor, you agree to allow +your code to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +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 +CONTRIBUTORS 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 WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT + +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. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + -- cgit 1.4.1-3-g733a5 From 569b87d602110e3f620cbeed053cb537420049e6 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Fri, 28 Feb 2020 20:01:22 +0100 Subject: aarch64: Exclude FP intrinsics on +nofp or +nosimd (#344) `AArch64` GCCs exit with an error condition when they encounter any kind of floating point code if the `nofp` and/or `nosimd` compiler flags have been set. Therefore, evaluate if those flags are present and set a boolean that causes any compiler-rt intrinsics that contain floating point source to be excluded for this target. This patch prepares https://github.com/rust-lang/rust/pull/68334 --- library/compiler-builtins/build.rs | 57 ++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index b520b62477e..c4a80223b47 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -51,7 +51,7 @@ fn main() { // time). This can probably be removed in the future if !target.contains("wasm32") && !target.contains("nvptx") && !target.starts_with("riscv") { #[cfg(feature = "c")] - c::compile(&llvm_target); + c::compile(&llvm_target, &target); } } @@ -121,13 +121,28 @@ mod c { } /// Compile intrinsics from the compiler-rt C source code - pub fn compile(llvm_target: &[&str]) { + pub fn compile(llvm_target: &[&str], target: &String) { let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); + let mut consider_float_intrinsics = true; let cfg = &mut cc::Build::new(); + // AArch64 GCCs exit with an error condition when they encounter any kind of floating point + // code if the `nofp` and/or `nosimd` compiler flags have been set. + // + // Therefore, evaluate if those flags are present and set a boolean that causes any + // compiler-rt intrinsics that contain floating point source to be excluded for this target. + if target_arch == "aarch64" { + let cflags_key = String::from("CFLAGS_") + &(target.to_owned().replace("-", "_")); + if let Ok(cflags_value) = env::var(cflags_key) { + if cflags_value.contains("+nofp") || cflags_value.contains("+nosimd") { + consider_float_intrinsics = false; + } + } + } + cfg.warnings(false); if target_env == "msvc" { @@ -166,34 +181,39 @@ mod c { ("__cmpdi2", "cmpdi2.c"), ("__ctzdi2", "ctzdi2.c"), ("__ctzsi2", "ctzsi2.c"), - ("__divdc3", "divdc3.c"), - ("__divsc3", "divsc3.c"), - ("__divxc3", "divxc3.c"), - ("__extendhfsf2", "extendhfsf2.c"), ("__int_util", "int_util.c"), - ("__muldc3", "muldc3.c"), - ("__mulsc3", "mulsc3.c"), ("__mulvdi3", "mulvdi3.c"), ("__mulvsi3", "mulvsi3.c"), - ("__mulxc3", "mulxc3.c"), - ("__negdf2", "negdf2.c"), ("__negdi2", "negdi2.c"), - ("__negsf2", "negsf2.c"), ("__negvdi2", "negvdi2.c"), ("__negvsi2", "negvsi2.c"), ("__paritydi2", "paritydi2.c"), ("__paritysi2", "paritysi2.c"), ("__popcountdi2", "popcountdi2.c"), ("__popcountsi2", "popcountsi2.c"), - ("__powixf2", "powixf2.c"), ("__subvdi3", "subvdi3.c"), ("__subvsi3", "subvsi3.c"), - ("__truncdfhf2", "truncdfhf2.c"), - ("__truncdfsf2", "truncdfsf2.c"), - ("__truncsfhf2", "truncsfhf2.c"), ("__ucmpdi2", "ucmpdi2.c"), ]); + if consider_float_intrinsics { + sources.extend(&[ + ("__divdc3", "divdc3.c"), + ("__divsc3", "divsc3.c"), + ("__divxc3", "divxc3.c"), + ("__extendhfsf2", "extendhfsf2.c"), + ("__muldc3", "muldc3.c"), + ("__mulsc3", "mulsc3.c"), + ("__mulxc3", "mulxc3.c"), + ("__negdf2", "negdf2.c"), + ("__negsf2", "negsf2.c"), + ("__powixf2", "powixf2.c"), + ("__truncdfhf2", "truncdfhf2.c"), + ("__truncdfsf2", "truncdfsf2.c"), + ("__truncsfhf2", "truncsfhf2.c"), + ]); + } + // When compiling in rustbuild (the rust-lang/rust repo) this library // also needs to satisfy intrinsics that jemalloc or C in general may // need, so include a few more that aren't typically needed by @@ -214,12 +234,15 @@ mod c { ("__ffsti2", "ffsti2.c"), ("__mulvti3", "mulvti3.c"), ("__negti2", "negti2.c"), - ("__negvti2", "negvti2.c"), ("__parityti2", "parityti2.c"), ("__popcountti2", "popcountti2.c"), ("__subvti3", "subvti3.c"), ("__ucmpti2", "ucmpti2.c"), ]); + + if consider_float_intrinsics { + sources.extend(&[("__negvti2", "negvti2.c")]); + } } if target_vendor == "apple" { @@ -372,7 +395,7 @@ mod c { ]); } - if target_arch == "aarch64" { + if target_arch == "aarch64" && consider_float_intrinsics { sources.extend(&[ ("__comparetf2", "comparetf2.c"), ("__extenddftf2", "extenddftf2.c"), -- cgit 1.4.1-3-g733a5 From fd781d567f9168c2ca2e3c131b4fe446b7a4f31b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 28 Feb 2020 11:01:42 -0800 Subject: Bump to 0.1.26 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d7518970997..f24093fdfaa 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.25" +version = "0.1.26" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From ef99c37aae973bbd7d554429ff55552aa69f3d17 Mon Sep 17 00:00:00 2001 From: Tomasz Miąsko Date: Sat, 11 Apr 2020 00:00:50 +0200 Subject: Place intrinsics in individual object files (#349) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tomasz Miąsko --- library/compiler-builtins/src/macros.rs | 49 ++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index a86794072c2..b02f3ea5ced 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -173,14 +173,12 @@ macro_rules! intrinsics { #[cfg(all(windows, target_arch = "x86_64"))] pub mod $name { - - intrinsics! { - pub extern $abi fn $name( $($argname: $ty),* ) - -> ::macros::win64_128bit_abi_hack::U64x2 - { - let e: $ret = super::$name($($argname),*); - ::macros::win64_128bit_abi_hack::U64x2::from(e) - } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub extern $abi fn $name( $($argname: $ty),* ) + -> ::macros::win64_128bit_abi_hack::U64x2 + { + let e: $ret = super::$name($($argname),*); + ::macros::win64_128bit_abi_hack::U64x2::from(e) } } @@ -209,17 +207,23 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg(target_arch = "arm")] - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } #[cfg(target_arch = "arm")] pub mod $name { - intrinsics! { - pub extern "aapcs" fn $alias( $($argname: $ty),* ) -> $ret { - super::$name($($argname),*) - } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + super::$name($($argname),*) + } + } + + #[cfg(target_arch = "arm")] + pub mod $alias { + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub extern "aapcs" fn $alias( $($argname: $ty),* ) -> $ret { + super::$name($($argname),*) } } @@ -234,9 +238,15 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // This is the final catch-all rule. At this point we just generate an + // This is the final catch-all rule. At this point we generate an // intrinsic with a conditional `#[no_mangle]` directive to avoid - // interfereing with duplicate symbols and whatnot during testing. + // interfering with duplicate symbols and whatnot during testing. + // + // The implementation is placed in a separate module, to take advantage + // of the fact that rustc partitions functions into code generation + // units based on module they are defined in. As a result we will have + // a separate object file for each intrinsic. For further details see + // corresponding PR in rustc https://github.com/rust-lang/rust/pull/70846 // // After the intrinsic is defined we just continue with the rest of the // input we were given. @@ -249,11 +259,18 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( $(#[$($attr)*])* - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } + pub mod $name { + $(#[$($attr)*])* + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + super::$name($($argname),*) + } + } + intrinsics!($($rest)*); ); } -- cgit 1.4.1-3-g733a5 From 67ec7e4ccf5b3d04d31a01a95f8e4ca9c5f87733 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 13 Apr 2020 07:17:28 -0700 Subject: Bump to 0.1.27 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f24093fdfaa..41b33bf4775 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.26" +version = "0.1.27" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 0e69cc88170728c053a9845730eec6eaaf89531d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 29 Apr 2020 15:30:10 -0500 Subject: Switch to using `llvm_asm!` instead of `asm!` (#351) * Switch to using `llvm_asm!` instead of `asm!` * Run rustfmt * Fix how LTO is specified on nightly --- library/compiler-builtins/ci/run.sh | 6 +- library/compiler-builtins/examples/intrinsics.rs | 4 +- library/compiler-builtins/src/arm.rs | 140 +++++++++++++---------- library/compiler-builtins/src/int/mod.rs | 74 ++++++------ library/compiler-builtins/src/lib.rs | 2 +- library/compiler-builtins/src/x86.rs | 6 +- library/compiler-builtins/src/x86_64.rs | 6 +- 7 files changed, 128 insertions(+), 110 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index ae32806ece8..c4cc6813d59 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -85,9 +85,11 @@ RUSTFLAGS="-C debug-assertions=no" $build_intrinsics --features c --release if [ -z "$DEBUG_LTO_BUILD_DOESNT_WORK" ]; then RUSTFLAGS="-C debug-assertions=no" \ CARGO_INCREMENTAL=0 \ - $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics -- -C lto + CARGO_PROFILE_DEV_LTO=true \ + $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics fi -$cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics --release -- -C lto +CARGO_PROFILE_RELEASE_LTO=true \ + $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics --release # Ensure no references to a panicking function for rlib in $(echo $path); do diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 5ceebe13216..82762e076b1 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -6,7 +6,7 @@ #![allow(unused_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] -#![feature(asm)] +#![feature(llvm_asm)] #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] @@ -280,7 +280,7 @@ fn run() { // A copy of "test::black_box". Used to prevent LLVM from optimizing away the intrinsics during LTO fn bb(dummy: T) -> T { - unsafe { asm!("" : : "r"(&dummy)) } + unsafe { llvm_asm!("" : : "r"(&dummy)) } dummy } diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 4cf73ef37ac..190bba72620 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -8,13 +8,15 @@ use core::intrinsics; #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uidivmod() { - asm!("push {lr} - sub sp, sp, #4 - mov r2, sp - bl __udivmodsi4 - ldr r1, [sp] - add sp, sp, #4 - pop {pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {lr} + sub sp, sp, #4 + mov r2, sp + bl __udivmodsi4 + ldr r1, [sp] + add sp, sp, #4 + pop {pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -22,13 +24,15 @@ pub unsafe fn __aeabi_uidivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uidivmod() { - asm!("push {lr} - sub sp, sp, #4 - mov r2, sp - bl ___udivmodsi4 - ldr r1, [sp] - add sp, sp, #4 - pop {pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {lr} + sub sp, sp, #4 + mov r2, sp + bl ___udivmodsi4 + ldr r1, [sp] + add sp, sp, #4 + pop {pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -36,15 +40,17 @@ pub unsafe fn __aeabi_uidivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uldivmod() { - asm!("push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl __udivmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] + bl __udivmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -52,15 +58,17 @@ pub unsafe fn __aeabi_uldivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uldivmod() { - asm!("push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl ___udivmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] + bl ___udivmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -68,12 +76,14 @@ pub unsafe fn __aeabi_uldivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_idivmod() { - asm!("push {r0, r1, r4, lr} - bl __aeabi_idiv - pop {r1, r2} - muls r2, r2, r0 - subs r1, r1, r2 - pop {r4, pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {r0, r1, r4, lr} + bl __aeabi_idiv + pop {r1, r2} + muls r2, r2, r0 + subs r1, r1, r2 + pop {r4, pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -81,12 +91,14 @@ pub unsafe fn __aeabi_idivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_idivmod() { - asm!("push {r0, r1, r4, lr} - bl ___aeabi_idiv - pop {r1, r2} - muls r2, r2, r0 - subs r1, r1, r2 - pop {r4, pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {r0, r1, r4, lr} + bl ___aeabi_idiv + pop {r1, r2} + muls r2, r2, r0 + subs r1, r1, r2 + pop {r4, pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -94,15 +106,17 @@ pub unsafe fn __aeabi_idivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_ldivmod() { - asm!("push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl __divmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] + bl __divmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -110,15 +124,17 @@ pub unsafe fn __aeabi_ldivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_ldivmod() { - asm!("push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl ___divmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] + bl ___divmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 7587bc69e76..80ac4f9faae 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -88,55 +88,55 @@ fn unwrap(t: Option) -> T { macro_rules! int_impl_common { ($ty:ty, $bits:expr) => { - const BITS: u32 = $bits; + const BITS: u32 = $bits; - const ZERO: Self = 0; - const ONE: Self = 1; + const ZERO: Self = 0; + const ONE: Self = 1; - fn from_bool(b: bool) -> Self { - b as $ty - } + fn from_bool(b: bool) -> Self { + b as $ty + } - fn max_value() -> Self { - ::max_value() - } + fn max_value() -> Self { + ::max_value() + } - fn min_value() -> Self { - ::min_value() - } + fn min_value() -> Self { + ::min_value() + } - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } - fn aborting_div(self, other: Self) -> Self { - unwrap(::checked_div(self, other)) - } + fn aborting_div(self, other: Self) -> Self { + unwrap(::checked_div(self, other)) + } - fn aborting_rem(self, other: Self) -> Self { - unwrap(::checked_rem(self, other)) - } + fn aborting_rem(self, other: Self) -> Self { + unwrap(::checked_rem(self, other)) + } - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - } + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + }; } macro_rules! int_impl { diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index e57a5ef3f87..0ca770b1e78 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,6 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![feature(abi_unadjusted)] -#![feature(asm)] +#![feature(llvm_asm)] #![feature(global_asm)] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index 035c0a31c41..5511c4572e5 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -12,7 +12,7 @@ use core::intrinsics; #[naked] #[no_mangle] pub unsafe fn ___chkstk_ms() { - asm!(" + llvm_asm!(" push %ecx push %eax cmp $$0x1000,%eax @@ -38,7 +38,7 @@ pub unsafe fn ___chkstk_ms() { #[naked] #[no_mangle] pub unsafe fn __alloca() { - asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" + llvm_asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -47,7 +47,7 @@ pub unsafe fn __alloca() { #[naked] #[no_mangle] pub unsafe fn ___chkstk() { - asm!(" + llvm_asm!(" push %ecx cmp $$0x1000,%eax lea 8(%esp),%ecx // esp before calling this routine -> ecx diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 6940f8d9d29..6a0cd566873 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -12,7 +12,7 @@ use core::intrinsics; #[naked] #[no_mangle] pub unsafe fn ___chkstk_ms() { - asm!(" + llvm_asm!(" push %rcx push %rax cmp $$0x1000,%rax @@ -37,7 +37,7 @@ pub unsafe fn ___chkstk_ms() { #[naked] #[no_mangle] pub unsafe fn __alloca() { - asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx + llvm_asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" ::: "memory" : "volatile"); intrinsics::unreachable(); @@ -47,7 +47,7 @@ pub unsafe fn __alloca() { #[naked] #[no_mangle] pub unsafe fn ___chkstk() { - asm!( + llvm_asm!( " push %rcx cmp $$0x1000,%rax -- cgit 1.4.1-3-g733a5 From 5c41a11e62acf7b1687f8d237546c7e0a0bee3bf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 May 2020 22:29:49 -0700 Subject: Bump to 0.1.28 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 41b33bf4775..75a7e1e93ae 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.27" +version = "0.1.28" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From a2840567da837b1a9ff24befa13cf33f8d31fc85 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 22 May 2020 14:12:06 -0700 Subject: Add more targets to automatically select `mem` feature. (#357) --- library/compiler-builtins/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index c4a80223b47..abeac9bf1ec 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -27,6 +27,8 @@ fn main() { // provide them. if (target.contains("wasm32") && !target.contains("wasi")) || (target.contains("sgx") && target.contains("fortanix")) + || target.contains("-none") + || target.contains("nvptx") { println!("cargo:rustc-cfg=feature=\"mem\""); } -- cgit 1.4.1-3-g733a5 From ca827eb2348cb83ccb26fa9403a6f11cb3d668ce Mon Sep 17 00:00:00 2001 From: Tomasz Miąsko Date: Tue, 26 May 2020 22:12:10 +0200 Subject: Use crate visibility for traits (#358) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tomasz Miąsko --- library/compiler-builtins/src/float/mod.rs | 2 +- library/compiler-builtins/src/int/mod.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 8b8039452a7..06e9aad4b42 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -13,7 +13,7 @@ pub mod pow; pub mod sub; /// Trait for some basic operations on floats -pub trait Float: +pub(crate) trait Float: Copy + PartialEq + PartialOrd diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 80ac4f9faae..d73bf6db995 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -19,7 +19,7 @@ pub mod shift; pub mod udiv; /// Trait for some basic operations on integers -pub trait Int: +pub(crate) trait Int: Copy + PartialEq + PartialOrd @@ -190,7 +190,7 @@ int_impl!(i64, u64, 64); int_impl!(i128, u128, 128); /// Trait to convert an integer to/from smaller parts -pub trait LargeInt: Int { +pub(crate) trait LargeInt: Int { type LowHalf: Int; type HighHalf: Int; @@ -232,7 +232,7 @@ large_int!(u128, u64, u64, 64); large_int!(i128, u64, i64, 64); /// Trait to express (possibly lossy) casting of integers -pub trait CastInto: Copy { +pub(crate) trait CastInto: Copy { fn cast(self) -> T; } @@ -256,7 +256,7 @@ cast_into!(i64); cast_into!(u128); cast_into!(i128); -pub trait WideInt: Int { +pub(crate) trait WideInt: Int { type Output: Int; fn wide_mul(self, other: Self) -> (Self, Self); -- cgit 1.4.1-3-g733a5 From a0f9847f1d202313068846c68936c772bbfd74c4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 26 May 2020 13:12:24 -0700 Subject: Bump to 0.1.29 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 75a7e1e93ae..7c6f4bdb704 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.28" +version = "0.1.29" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 72b440075ea3abee81d2ce0682386e65ab98a6bd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 May 2020 14:16:51 -0500 Subject: Use macros for more division/array checks (#244) * Use macros for more division/array checks This commit moves over more array accesses to the `i!` macro to avoid bounds checks when debug assertions are disabled. This is surfaced from rust-lang/compiler-builtins#360 where recent changes in codegen units has caused some bounds checks to not get elided in release mode. This also adds a `div!` macro to work around rust-lang/rust#72751. * Don't test/bench our shim crate It's not intended to run all our tests --- .../crates/compiler-builtins-smoke-test/Cargo.toml | 5 ++++- library/compiler-builtins/libm/src/lib.rs | 5 +---- library/compiler-builtins/libm/src/math/atanf.rs | 8 ++++---- library/compiler-builtins/libm/src/math/exp.rs | 2 +- library/compiler-builtins/libm/src/math/exp2.rs | 6 +++--- library/compiler-builtins/libm/src/math/exp2f.rs | 2 +- library/compiler-builtins/libm/src/math/expf.rs | 2 +- library/compiler-builtins/libm/src/math/mod.rs | 18 ++++++++++++++++++ library/compiler-builtins/libm/src/math/pow.rs | 12 ++++++------ library/compiler-builtins/libm/src/math/powf.rs | 12 ++++++------ library/compiler-builtins/libm/src/math/rem_pio2.rs | 12 ++++++------ .../compiler-builtins/libm/src/math/rem_pio2_large.rs | 4 ++-- 12 files changed, 53 insertions(+), 35 deletions(-) diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 40e75dd22fd..ac192a9132f 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -3,4 +3,7 @@ name = "cb" version = "0.1.0" authors = ["Jorge Aparicio "] -[dependencies] +[lib] +test = false +bench = false + diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index e228af9b333..bbc79ecad56 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,10 +1,7 @@ //! libm in pure Rust #![deny(warnings)] #![no_std] -#![cfg_attr( - all(target_arch = "wasm32", feature = "unstable"), - feature(core_intrinsics) -)] +#![cfg_attr(all(feature = "unstable"), feature(core_intrinsics))] #![allow(clippy::unreadable_literal)] #![allow(clippy::many_single_char_names)] #![allow(clippy::needless_return)] diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index 73f3352e9ec..d042b3bc0fd 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -56,7 +56,7 @@ pub fn atanf(mut x: f32) -> f32 { if x.is_nan() { return x; } - z = ATAN_HI[3] + x1p_120; + z = i!(ATAN_HI, 3) + x1p_120; return if sign { -z } else { z }; } let id = if ix < 0x3ee00000 { @@ -97,13 +97,13 @@ pub fn atanf(mut x: f32) -> f32 { z = x * x; let w = z * z; /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ - let s1 = z * (A_T[0] + w * (A_T[2] + w * A_T[4])); - let s2 = w * (A_T[1] + w * A_T[3]); + let s1 = z * (i!(A_T, 0) + w * (i!(A_T, 2) + w * i!(A_T, 4))); + let s2 = w * (i!(A_T, 1) + w * i!(A_T, 3)); if id < 0 { return x - x * (s1 + s2); } let id = id as usize; - let z = ATAN_HI[id] - ((x * (s1 + s2) - ATAN_LO[id]) - x); + let z = i!(ATAN_HI, id) - ((x * (s1 + s2) - i!(ATAN_LO, id)) - x); if sign { -z } else { diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs index 5b163f95427..d4994277f89 100644 --- a/library/compiler-builtins/libm/src/math/exp.rs +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -124,7 +124,7 @@ pub fn exp(mut x: f64) -> f64 { /* if |x| > 0.5 ln2 */ if hx >= 0x3ff0a2b2 { /* if |x| >= 1.5 ln2 */ - k = (INVLN2 * x + HALF[sign as usize]) as i32; + k = (INVLN2 * x + i!(HALF, sign as usize)) as i32; } else { k = 1 - sign - sign; } diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index 8ea434dcadb..e0e385df2e7 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -374,14 +374,14 @@ pub fn exp2(mut x: f64) -> f64 { let mut i0 = ui as u32; i0 = i0.wrapping_add(TBLSIZE as u32 / 2); let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32; - let ki = ku as i32 / TBLSIZE as i32; + let ki = div!(ku as i32, TBLSIZE as i32); i0 %= TBLSIZE as u32; let uf = f64::from_bits(ui) - redux; let mut z = x - uf; /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ - let t = f64::from_bits(TBL[2 * i0 as usize]); /* exp2t[i0] */ - z -= f64::from_bits(TBL[2 * i0 as usize + 1]); /* eps[i0] */ + let t = f64::from_bits(i!(TBL, 2 * i0 as usize)); /* exp2t[i0] */ + z -= f64::from_bits(i!(TBL, 2 * i0 as usize + 1)); /* eps[i0] */ let r = t + t * z * (p1 + z * (p2 + z * (p3 + z * (p4 + z * p5)))); scalbn(r, ki) diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index 8a890b832e9..f4867b80eed 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -126,7 +126,7 @@ pub fn exp2f(mut x: f32) -> f32 { uf -= redux; let z: f64 = (x - uf) as f64; /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ - let r: f64 = f64::from_bits(EXP2FT[i0 as usize]); + let r: f64 = f64::from_bits(i!(EXP2FT, i0 as usize)); let t: f64 = r as f64 * z; let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64); diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index 47c1b2c467e..a53aa90a646 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -70,7 +70,7 @@ pub fn expf(mut x: f32) -> f32 { /* if |x| > 0.5 ln2 */ if hx > 0x3f851592 { /* if |x| > 1.5 ln2 */ - k = (INV_LN2 * x + HALF[sign as usize]) as i32; + k = (INV_LN2 * x + i!(HALF, sign as usize)) as i32; } else { k = 1 - sign - sign; } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c8d7bd8194d..ceeee0b31fb 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -58,6 +58,24 @@ macro_rules! i { }; } +// Temporary macro to avoid panic codegen for division (in debug mode too). At +// the time of this writing this is only used in a few places, and once +// rust-lang/rust#72751 is fixed then this macro will no longer be necessary and +// the native `/` operator can be used and panics won't be codegen'd. +#[cfg(any(debug_assertions, not(feature = "unstable")))] +macro_rules! div { + ($a:expr, $b:expr) => { + $a / $b + }; +} + +#[cfg(all(not(debug_assertions), feature = "unstable"))] +macro_rules! div { + ($a:expr, $b:expr) => { + unsafe { core::intrinsics::unchecked_div($a, $b) } + }; +} + macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { #[cfg(all(feature = "unstable", $($clause)*))] diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index ce8e83ee6f8..c7fd0dfa117 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -299,8 +299,8 @@ pub fn pow(x: f64, y: f64) -> f64 { ax = with_set_high_word(ax, ix as u32); /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ - let u: f64 = ax - BP[k as usize]; /* bp[0]=1.0, bp[1]=1.5 */ - let v: f64 = 1.0 / (ax + BP[k as usize]); + let u: f64 = ax - i!(BP, k as usize); /* bp[0]=1.0, bp[1]=1.5 */ + let v: f64 = 1.0 / (ax + i!(BP, k as usize)); let ss: f64 = u * v; let s_h = with_set_low_word(ss, 0); @@ -309,7 +309,7 @@ pub fn pow(x: f64, y: f64) -> f64 { 0.0, ((ix as u32 >> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18), ); - let t_l: f64 = ax - (t_h - BP[k as usize]); + let t_l: f64 = ax - (t_h - i!(BP, k as usize)); let s_l: f64 = v * ((u - s_h * t_h) - s_h * t_l); /* compute log(ax) */ @@ -328,12 +328,12 @@ pub fn pow(x: f64, y: f64) -> f64 { let p_h: f64 = with_set_low_word(u + v, 0); let p_l = v - (p_h - u); let z_h: f64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ - let z_l: f64 = CP_L * p_h + p_l * CP + DP_L[k as usize]; + let z_l: f64 = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ let t: f64 = n as f64; - t1 = with_set_low_word(((z_h + z_l) + DP_H[k as usize]) + t, 0); - t2 = z_l - (((t1 - t) - DP_H[k as usize]) - z_h); + t1 = with_set_low_word(((z_h + z_l) + i!(DP_H, k as usize)) + t, 0); + t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); } /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index f3cf76f9aa6..68d2083bbdd 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -238,8 +238,8 @@ pub fn powf(x: f32, y: f32) -> f32 { ax = f32::from_bits(ix as u32); /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ - u = ax - BP[k as usize]; /* bp[0]=1.0, bp[1]=1.5 */ - v = 1.0 / (ax + BP[k as usize]); + u = ax - i!(BP, k as usize); /* bp[0]=1.0, bp[1]=1.5 */ + v = 1.0 / (ax + i!(BP, k as usize)); s = u * v; s_h = s; is = s_h.to_bits() as i32; @@ -247,7 +247,7 @@ pub fn powf(x: f32, y: f32) -> f32 { /* t_h=ax+bp[k] High */ is = (((ix as u32 >> 1) & 0xfffff000) | 0x20000000) as i32; t_h = f32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); - t_l = ax - (t_h - BP[k as usize]); + t_l = ax - (t_h - i!(BP, k as usize)); s_l = v * ((u - s_h * t_h) - s_h * t_l); /* compute log(ax) */ s2 = s * s; @@ -267,13 +267,13 @@ pub fn powf(x: f32, y: f32) -> f32 { p_h = f32::from_bits(is as u32 & 0xfffff000); p_l = v - (p_h - u); z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ - z_l = CP_L * p_h + p_l * CP + DP_L[k as usize]; + z_l = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ t = n as f32; - t1 = ((z_h + z_l) + DP_H[k as usize]) + t; + t1 = ((z_h + z_l) + i!(DP_H, k as usize)) + t; is = t1.to_bits() as i32; t1 = f32::from_bits(is as u32 & 0xfffff000); - t2 = z_l - (((t1 - t) - DP_H[k as usize]) - z_h); + t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); }; /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 6b7dbd348c6..46f7c38ffed 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -167,21 +167,21 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { let mut z = f64::from_bits(ui); let mut tx = [0.0; 3]; for i in 0..2 { - tx[i] = z as i32 as f64; - z = (z - tx[i]) * x1p24; + i!(tx,i, =, z as i32 as f64); + z = (z - i!(tx, i)) * x1p24; } - tx[2] = z; + i!(tx,2, =, z); /* skip zero terms, first term is non-zero */ let mut i = 2; - while i != 0 && tx[i] == 0.0 { + while i != 0 && i!(tx, i) == 0.0 { i -= 1; } let mut ty = [0.0; 3]; let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix as i32) >> 20) - (0x3ff + 23), 1); if sign != 0 { - return (-n, -ty[0], -ty[1]); + return (-n, -i!(ty, 0), -i!(ty, 1)); } - (n, ty[0], ty[1]) + (n, i!(ty, 0), i!(ty, 1)) } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 002ce2e211f..65473f0abda 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -242,12 +242,12 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> let mut iq: [i32; 20] = [0; 20]; /* initialize jk*/ - let jk = INIT_JK[prec]; + let jk = i!(INIT_JK, prec); let jp = jk; /* determine jx,jv,q0, note that 3>q0 */ let jx = nx - 1; - let mut jv = (e0 - 3) / 24; + let mut jv = div!(e0 - 3, 24); if jv < 0 { jv = 0; } -- cgit 1.4.1-3-g733a5 From 63982a3b9e3d8844d98447a474ca94eb1d9f0b0f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 May 2020 14:38:29 -0500 Subject: Expand wasm32 testing on CI (#360) * Expand wasm32 testing on CI Run the full `run.sh` test script to get full assertions, including that nothing in the wasm compiler-builtins is panicking. Unfortunately it's currently panicking, so this is good to weed out! * Update libm --- .../compiler-builtins/.github/workflows/main.yml | 31 ++-------------------- .../ci/docker/wasm32-unknown-unknown/Dockerfile | 6 +++++ library/compiler-builtins/ci/run.sh | 10 ++++--- library/compiler-builtins/examples/intrinsics.rs | 6 ++--- library/compiler-builtins/libm | 2 +- library/compiler-builtins/src/lib.rs | 2 +- 6 files changed, 19 insertions(+), 38 deletions(-) create mode 100644 library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 46915499764..25ab1b30a7e 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -7,30 +7,6 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - target: - - aarch64-unknown-linux-gnu - - arm-unknown-linux-gnueabi - - arm-unknown-linux-gnueabihf - - i586-unknown-linux-gnu - - i686-unknown-linux-gnu - - mips-unknown-linux-gnu - - mips64-unknown-linux-gnuabi64 - - mips64el-unknown-linux-gnuabi64 - - mipsel-unknown-linux-gnu - - powerpc-unknown-linux-gnu - - powerpc64-unknown-linux-gnu - - powerpc64le-unknown-linux-gnu - - thumbv6m-none-eabi - - thumbv7em-none-eabi - - thumbv7em-none-eabihf - - thumbv7m-none-eabi - - wasm32-unknown-unknown - - x86_64-unknown-linux-gnu - - x86_64-apple-darwin - - i686-pc-windows-msvc - - x86_64-pc-windows-msvc - - i686-pc-windows-gnu - - x86_64-pc-windows-gnu include: - target: aarch64-unknown-linux-gnu os: ubuntu-latest @@ -109,6 +85,7 @@ jobs: run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} shell: bash - run: rustup target add ${{ matrix.target }} + - run: rustup component add llvm-tools-preview - name: Download compiler-rt reference sources run: | curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/8.0-2019-03-18.tar.gz @@ -121,13 +98,9 @@ jobs: if: matrix.os != 'ubuntu-latest' shell: bash - # Wasm is special and is just build as a smoke test - - run: cargo build --target ${{ matrix.target }} - if: matrix.target == 'wasm32-unknown-unknown' - # Otherwise we use our docker containers to run builds - run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} - if: matrix.target != 'wasm32-unknown-unknown' && matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-latest' rustfmt: name: Rustfmt diff --git a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile new file mode 100644 index 00000000000..758d94d5013 --- /dev/null +++ b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile @@ -0,0 +1,6 @@ +FROM ubuntu:20.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates + +ENV CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER=true diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index c4cc6813d59..3c9dc0247e6 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -32,7 +32,10 @@ case $1 in ;; esac -NM=nm +NM=$(find $(rustc --print sysroot) -name llvm-nm) +if [ "$NM" = "" ]; then + NM=${PREFIX}nm +fi if [ -d /target ]; then path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib @@ -47,8 +50,7 @@ for rlib in $(echo $path); do echo checking $rlib for duplicate symbols echo "================================================================" - stdout=$($PREFIX$NM -g --defined-only $rlib 2>&1) - + stdout=$($NM -g --defined-only $rlib 2>&1) # NOTE On i586, It's normal that the get_pc_thunk symbol appears several # times so ignore it # @@ -94,7 +96,7 @@ CARGO_PROFILE_RELEASE_LTO=true \ # Ensure no references to a panicking function for rlib in $(echo $path); do set +ex - $PREFIX$NM -u $rlib 2>&1 | grep panicking + $NM -u $rlib 2>&1 | grep panicking if test $? = 0; then exit 1 diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 82762e076b1..519cea2ae0e 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -14,7 +14,7 @@ extern crate panic_handler; -#[cfg(all(not(thumb), not(windows)))] +#[cfg(all(not(thumb), not(windows), not(target_arch = "wasm32")))] #[link(name = "c")] extern "C" {} @@ -340,11 +340,11 @@ fn run() { something_with_a_dtor(&|| assert_eq!(bb(1), 1)); extern "C" { - fn rust_begin_unwind(); + fn rust_begin_unwind(x: usize); } // if bb(false) { unsafe { - rust_begin_unwind(); + rust_begin_unwind(0); } // } } diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 8eedc247053..fe396e00b7e 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 8eedc2470531f51b978e4c873ee78a33c90e0fbd +Subproject commit fe396e00b7e47821a81c4c87a481ddc6af1d2cdf diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0ca770b1e78..564988654f7 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -31,7 +31,7 @@ extern crate core; fn abort() -> ! { - unsafe { core::intrinsics::abort() } + core::intrinsics::abort() } #[macro_use] -- cgit 1.4.1-3-g733a5 From 843c2261a9f918e59b5e14874a62a89473534cc1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 May 2020 13:41:09 -0700 Subject: Bump to 0.1.30 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7c6f4bdb704..0e9778e4090 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.29" +version = "0.1.30" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From e4293adbe151dad5264844c9cc3ef1c808e0c5ce Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 May 2020 13:43:21 -0700 Subject: Add back in unsafe for bootstrapping And add an `#[allow]` for now to appease stage0 --- library/compiler-builtins/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 564988654f7..db05af5de34 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -30,8 +30,9 @@ #[cfg(test)] extern crate core; +#[allow(unused_unsafe)] fn abort() -> ! { - core::intrinsics::abort() + unsafe { core::intrinsics::abort() } } #[macro_use] -- cgit 1.4.1-3-g733a5 From d1e1f04686c88ce03d0ed297d5ed6bca4f2f6a6a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 May 2020 13:43:57 -0700 Subject: Bump to 0.1.31 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0e9778e4090..9a5f9984d4e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.30" +version = "0.1.31" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 96e3a08719d3da905aa4307b09b9cd82910b7a3a Mon Sep 17 00:00:00 2001 From: jethrogb Date: Mon, 1 Jun 2020 17:55:42 +0200 Subject: Manually patch ret instruction for LVI (#359) Co-authored-by: Jethro Beekman --- library/compiler-builtins/src/probestack.rs | 70 ++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 19307df4e93..9c78faa1d23 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -109,7 +109,12 @@ macro_rules! define_rust_probestack { // // The ABI here is that the stack frame size is located in `%rax`. Upon // return we're not supposed to modify `%rsp` or `%rax`. -#[cfg(target_arch = "x86_64")] +// +// Any changes to this function should be replicated to the SGX version below. +#[cfg(all( + target_arch = "x86_64", + not(all(target_env = "sgx", target_vendor = "fortanix")) +))] global_asm!(define_rust_probestack!( " .cfi_startproc @@ -163,6 +168,69 @@ global_asm!(define_rust_probestack!( " )); +// This function is the same as above, except that some instructions are +// [manually patched for LVI]. +// +// [manually patched for LVI]: https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions +#[cfg(all( + target_arch = "x86_64", + all(target_env = "sgx", target_vendor = "fortanix") +))] +global_asm!(define_rust_probestack!( + " + .cfi_startproc + pushq %rbp + .cfi_adjust_cfa_offset 8 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + + mov %rax,%r11 // duplicate %rax as we're clobbering %r11 + + // Main loop, taken in one page increments. We're decrementing rsp by + // a page each time until there's less than a page remaining. We're + // guaranteed that this function isn't called unless there's more than a + // page needed. + // + // Note that we're also testing against `8(%rsp)` to account for the 8 + // bytes pushed on the stack orginally with our return address. Using + // `8(%rsp)` simulates us testing the stack pointer in the caller's + // context. + + // It's usually called when %rax >= 0x1000, but that's not always true. + // Dynamic stack allocation, which is needed to implement unsized + // rvalues, triggers stackprobe even if %rax < 0x1000. + // Thus we have to check %r11 first to avoid segfault. + cmp $0x1000,%r11 + jna 3f +2: + sub $0x1000,%rsp + test %rsp,8(%rsp) + sub $0x1000,%r11 + cmp $0x1000,%r11 + ja 2b + +3: + // Finish up the last remaining stack space requested, getting the last + // bits out of r11 + sub %r11,%rsp + test %rsp,8(%rsp) + + // Restore the stack pointer to what it previously was when entering + // this function. The caller will readjust the stack pointer after we + // return. + add %rax,%rsp + + leave + .cfi_def_cfa_register %rsp + .cfi_adjust_cfa_offset -8 + pop %r11 + lfence + jmp *%r11 + .cfi_endproc + " +)); + #[cfg(target_arch = "x86")] // This is the same as x86_64 above, only translated for 32-bit sizes. Note // that on Unix we're expected to restore everything as it was, this -- cgit 1.4.1-3-g733a5 From 4e71b65530f084cc5041b16fdb6f03e863444bbf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 1 Jun 2020 08:56:11 -0700 Subject: Bump to 0.1.32 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 9a5f9984d4e..d4d1ad67d38 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.31" +version = "0.1.32" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 2b0d14c89ef923287e900843746c9f5f3242e4bf Mon Sep 17 00:00:00 2001 From: kellda <59569234+kellda@users.noreply.github.com> Date: Mon, 8 Jun 2020 16:11:11 +0200 Subject: Update CHANGELOG.md (#245) --- library/compiler-builtins/libm/CHANGELOG.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 28e27055dfd..e8e9acf9b5c 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -7,6 +7,30 @@ This project adheres to [Semantic Versioning](http://semver.org/). ... +## [v0.2.1] - 2019-11-22 + +### Fixed +- sincosf + +## [v0.2.0] - 2019-10-18 + +### Added +- Benchmarks +- signum +- remainder +- remainderf +- nextafter +- nextafterf + +### Fixed +- Rounding to negative zero +- Overflows in rem_pio2 and remquo +- Overflows in fma +- sincosf + +### Removed +- F32Ext and F64Ext traits + ## [v0.1.4] - 2019-06-12 ### Fixed @@ -90,7 +114,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Initial release -[Unreleased]: https://github.com/japaric/libm/compare/v0.1.4...HEAD +[Unreleased]: https://github.com/japaric/libm/compare/v0.2.1...HEAD +[v0.2.1]: https://github.com/japaric/libm/compare/0.2.0...v0.2.1 +[v0.2.0]: https://github.com/japaric/libm/compare/0.1.4...v0.2.0 [v0.1.4]: https://github.com/japaric/libm/compare/0.1.3...v0.1.4 [v0.1.3]: https://github.com/japaric/libm/compare/v0.1.2...0.1.3 [v0.1.2]: https://github.com/japaric/libm/compare/v0.1.1...v0.1.2 -- cgit 1.4.1-3-g733a5 From d59b2875b57f406c3152b45c6f0abb3c794f0949 Mon Sep 17 00:00:00 2001 From: Joseph Richey Date: Wed, 8 Jul 2020 07:07:19 -0700 Subject: lint: Allow improper_ctypes_definitions (#364) https://github.com/rust-lang/rust/pull/72700 caused the existing `allow(improper_ctypes)` guard to stop working, we now need `allow(improper_ctypes_definitions)` instead. We keep the old one to avoid any issues with older nightlies. Signed-off-by: Joe Richey --- library/compiler-builtins/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index db05af5de34..34397e0d256 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -15,7 +15,7 @@ // We use `u128` in a whole bunch of places which we currently agree with the // compiler on ABIs and such, so we should be "good enough" for now and changes // to the `u128` ABI will be reflected here. -#![allow(improper_ctypes)] +#![allow(improper_ctypes, improper_ctypes_definitions)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. -- cgit 1.4.1-3-g733a5 From 7652f288d3a14ca5f5f4940387b48fb802dd614e Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Tue, 28 Jul 2020 13:09:18 -0500 Subject: Improve `__clzsi2` performance (#366) --- library/compiler-builtins/src/int/leading_zeros.rs | 143 +++++++++++++++++++++ library/compiler-builtins/src/int/mod.rs | 69 +--------- library/compiler-builtins/testcrate/Cargo.toml | 6 + .../testcrate/tests/count_leading_zeros.rs | 23 ---- .../testcrate/tests/leading_zeros.rs | 54 ++++++++ 5 files changed, 206 insertions(+), 89 deletions(-) create mode 100644 library/compiler-builtins/src/int/leading_zeros.rs delete mode 100644 library/compiler-builtins/testcrate/tests/count_leading_zeros.rs create mode 100644 library/compiler-builtins/testcrate/tests/leading_zeros.rs diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs new file mode 100644 index 00000000000..78556f0bcf6 --- /dev/null +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -0,0 +1,143 @@ +// Note: these functions happen to produce the correct `usize::leading_zeros(0)` value +// without a explicit zero check. Zero is probably common enough that it could warrant +// adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. +// Compilers will insert the check for zero in cases where it is needed. + +/// Returns the number of leading binary zeros in `x`. +pub fn usize_leading_zeros_default(x: usize) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = usize::MAX.count_ones() as usize; + // a temporary + let mut t: usize; + #[cfg(target_pointer_width = "64")] + { + t = x >> 32; + if t != 0 { + z -= 32; + x = t; + } + } + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + t = x >> 16; + if t != 0 { + z -= 16; + x = t; + } + } + t = x >> 8; + if t != 0 { + z -= 8; + x = t; + } + t = x >> 4; + if t != 0 { + z -= 4; + x = t; + } + t = x >> 2; + if t != 0 { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != 0 { + z - 2 + } else { + z - x + } + + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/ + // fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. +} + +// The above method does not compile well on RISC-V (because of the lack of predicated +// instructions), producing code with many branches or using an excessively long +// branchless solution. This method takes advantage of the set-if-less-than instruction on +// RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + +/// Returns the number of leading binary zeros in `x`. +pub fn usize_leading_zeros_riscv(x: usize) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = usize::MAX.count_ones() as usize; + // a temporary + let mut t: usize; + + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + #[cfg(target_pointer_width = "64")] + { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (1 << 32)) as usize) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. + x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros + z -= t; + } + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + t = ((x >= (1 << 16)) as usize) << 4; + x >>= t; + z -= t; + } + t = ((x >= (1 << 8)) as usize) << 3; + x >>= t; + z -= t; + t = ((x >= (1 << 4)) as usize) << 2; + x >>= t; + z -= t; + t = ((x >= (1 << 2)) as usize) << 1; + x >>= t; + z -= t; + t = (x >= (1 << 1)) as usize; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z - x +} + +intrinsics! { + #[maybe_use_optimized_c_shim] + #[cfg(any( + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64" + ))] + /// Returns the number of leading binary zeros in `x`. + pub extern "C" fn __clzsi2(x: usize) -> usize { + if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { + usize_leading_zeros_riscv(x) + } else { + usize_leading_zeros_default(x) + } + } +} diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index d73bf6db995..8a469d90147 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -13,11 +13,14 @@ macro_rules! os_ty { } pub mod addsub; +pub mod leading_zeros; pub mod mul; pub mod sdiv; pub mod shift; pub mod udiv; +pub use self::leading_zeros::__clzsi2; + /// Trait for some basic operations on integers pub(crate) trait Int: Copy @@ -300,69 +303,3 @@ macro_rules! impl_wide_int { impl_wide_int!(u32, u64, 32); impl_wide_int!(u64, u128, 64); - -intrinsics! { - #[maybe_use_optimized_c_shim] - #[cfg(any( - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64" - ))] - pub extern "C" fn __clzsi2(x: usize) -> usize { - // TODO: const this? Would require const-if - // Note(Lokathor): the `intrinsics!` macro can't process mut inputs - let mut x = x; - let mut y: usize; - let mut n: usize = { - #[cfg(target_pointer_width = "64")] - { - 64 - } - #[cfg(target_pointer_width = "32")] - { - 32 - } - #[cfg(target_pointer_width = "16")] - { - 16 - } - }; - #[cfg(target_pointer_width = "64")] - { - y = x >> 32; - if y != 0 { - n -= 32; - x = y; - } - } - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { - y = x >> 16; - if y != 0 { - n -= 16; - x = y; - } - } - y = x >> 8; - if y != 0 { - n -= 8; - x = y; - } - y = x >> 4; - if y != 0 { - n -= 4; - x = y; - } - y = x >> 2; - if y != 0 { - n -= 2; - x = y; - } - y = x >> 1; - if y != 0 { - n - 2 - } else { - n - x - } - } -} diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 3b99b574ef2..61282af0bf5 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -11,6 +11,12 @@ doctest = false [build-dependencies] rand = "0.7" +[dev-dependencies] +# For fuzzing tests we want a deterministic seedable RNG. We also eliminate potential +# problems with system RNGs on the variety of platforms this crate is tested on. +# `xoshiro128**` is used for its quality, size, and speed at generating `u32` shift amounts. +rand_xoshiro = "0.4" + [dependencies.compiler_builtins] path = ".." default-features = false diff --git a/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs b/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs deleted file mode 100644 index 022b2d85293..00000000000 --- a/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs +++ /dev/null @@ -1,23 +0,0 @@ -extern crate compiler_builtins; - -use compiler_builtins::int::__clzsi2; - -#[test] -fn __clzsi2_test() { - let mut i: usize = core::usize::MAX; - // Check all values above 0 - while i > 0 { - assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); - i >>= 1; - } - // check 0 also - i = 0; - assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); - // double check for bit patterns that aren't just solid 1s - i = 1; - for _ in 0..63 { - assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); - i <<= 2; - i += 1; - } -} diff --git a/library/compiler-builtins/testcrate/tests/leading_zeros.rs b/library/compiler-builtins/testcrate/tests/leading_zeros.rs new file mode 100644 index 00000000000..b857d9e0c31 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/leading_zeros.rs @@ -0,0 +1,54 @@ +use rand_xoshiro::rand_core::{RngCore, SeedableRng}; +use rand_xoshiro::Xoshiro128StarStar; + +use compiler_builtins::int::__clzsi2; +use compiler_builtins::int::leading_zeros::{ + usize_leading_zeros_default, usize_leading_zeros_riscv, +}; + +#[test] +fn __clzsi2_test() { + // Binary fuzzer. We cannot just send a random number directly to `__clzsi2()`, because we need + // large sequences of zeros to test. This XORs, ANDs, and ORs random length strings of 1s to + // `x`. ORs insure sequences of ones, ANDs insures sequences of zeros, and XORs are not often + // destructive but add entropy. + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x = 0usize; + // creates a mask for indexing the bits of the type + let bit_indexing_mask = usize::MAX.count_ones() - 1; + // 10000 iterations is enough to make sure edge cases like single set bits are tested and to go + // through many paths. + for _ in 0..10_000 { + let r0 = bit_indexing_mask & rng.next_u32(); + // random length of ones + let ones: usize = !0 >> r0; + let r1 = bit_indexing_mask & rng.next_u32(); + // random circular shift + let mask = ones.rotate_left(r1); + match rng.next_u32() % 4 { + 0 => x |= mask, + 1 => x &= mask, + // both 2 and 3 to make XORs as common as ORs and ANDs combined + _ => x ^= mask, + } + let lz = x.leading_zeros() as usize; + let lz0 = __clzsi2(x); + let lz1 = usize_leading_zeros_default(x); + let lz2 = usize_leading_zeros_riscv(x); + if lz0 != lz { + panic!("__clzsi2({}): expected: {}, found: {}", x, lz, lz0); + } + if lz1 != lz { + panic!( + "usize_leading_zeros_default({}): expected: {}, found: {}", + x, lz, lz1 + ); + } + if lz2 != lz { + panic!( + "usize_leading_zeros_riscv({}): expected: {}, found: {}", + x, lz, lz2 + ); + } + } +} -- cgit 1.4.1-3-g733a5 From 981e803acd1ef2f54bdc0e431e47f9b5f4b66cd1 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Sun, 3 May 2020 22:38:04 -0500 Subject: regularize the location and documentation of division functions --- library/compiler-builtins/src/int/sdiv.rs | 44 +++++++++++++++++++------------ library/compiler-builtins/src/int/udiv.rs | 14 +++++----- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index c9e252cc3b0..854ea00bbd8 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -60,42 +60,52 @@ impl Divmod for i64 {} intrinsics! { #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_idiv] + /// Returns `n / d` pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { a.div(b) } #[maybe_use_optimized_c_shim] - pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 { - a.div(b) + /// Returns `n % d` + pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { + a.mod_(b) } - - #[win64_128bit_abi_hack] - pub extern "C" fn __divti3(a: i128, b: i128) -> i128 { - a.div(b) + + #[maybe_use_optimized_c_shim] + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { + a.divmod(b, rem, |a, b| __divsi3(a, b)) } #[maybe_use_optimized_c_shim] - pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { - a.mod_(b) + /// Returns `n / d` + pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 { + a.div(b) } #[maybe_use_optimized_c_shim] + /// Returns `n % d` pub extern "C" fn __moddi3(a: i64, b: i64) -> i64 { a.mod_(b) } - #[win64_128bit_abi_hack] - pub extern "C" fn __modti3(a: i128, b: i128) -> i128 { - a.mod_(b) + #[aapcs_on_arm] + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __divmoddi4(a: i64, b: i64, rem: &mut i64) -> i64 { + a.divmod(b, rem, |a, b| __divdi3(a, b)) } - #[maybe_use_optimized_c_shim] - pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { - a.divmod(b, rem, |a, b| __divsi3(a, b)) + #[win64_128bit_abi_hack] + /// Returns `n / d` + pub extern "C" fn __divti3(a: i128, b: i128) -> i128 { + a.div(b) } - #[aapcs_on_arm] - pub extern "C" fn __divmoddi4(a: i64, b: i64, rem: &mut i64) -> i64 { - a.divmod(b, rem, |a, b| __divdi3(a, b)) + #[win64_128bit_abi_hack] + /// Returns `n % d` + pub extern "C" fn __modti3(a: i128, b: i128) -> i128 { + a.mod_(b) } + + // LLVM does not currently have a `__divmodti4` function } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index b393ac6db12..1ee670c72ab 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -241,6 +241,11 @@ intrinsics! { rem } + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { + udivmod_inner!(n, d, rem, u64) + } + #[win64_128bit_abi_hack] /// Returns `n / d` pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { @@ -255,16 +260,9 @@ intrinsics! { rem } - /// Returns `n / d` and sets `*rem = n % d` - pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { - udivmod_inner!(n, d, rem, u64) - } - #[win64_128bit_abi_hack] /// Returns `n / d` and sets `*rem = n % d` - pub extern "C" fn __udivmodti4(n: u128, - d: u128, - rem: Option<&mut u128>) -> u128 { + pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { udivmod_inner!(n, d, rem, u128) } } -- cgit 1.4.1-3-g733a5 From 3fda53a90d048fe9b2220817e502f2ccb02b5d98 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Sun, 3 May 2020 22:40:54 -0500 Subject: replace old soft division code with new functions --- library/compiler-builtins/src/int/sdiv.rs | 23 +++++---- library/compiler-builtins/src/int/udiv.rs | 86 +++++++------------------------ 2 files changed, 33 insertions(+), 76 deletions(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 854ea00bbd8..983c34cf36d 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -57,54 +57,59 @@ trait Divmod: Int { impl Divmod for i32 {} impl Divmod for i64 {} + intrinsics! { #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_idiv] /// Returns `n / d` pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { - a.div(b) + i32_div_rem(a, b).0 } #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { - a.mod_(b) + i32_div_rem(a, b).1 } - + #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { - a.divmod(b, rem, |a, b| __divsi3(a, b)) + let quo_rem = i32_div_rem(a, b); + *rem = quo_rem.1; + quo_rem.0 } #[maybe_use_optimized_c_shim] /// Returns `n / d` pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 { - a.div(b) + i64_div_rem(a, b).0 } #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __moddi3(a: i64, b: i64) -> i64 { - a.mod_(b) + i64_div_rem(a, b).1 } #[aapcs_on_arm] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __divmoddi4(a: i64, b: i64, rem: &mut i64) -> i64 { - a.divmod(b, rem, |a, b| __divdi3(a, b)) + let quo_rem = i64_div_rem(a, b); + *rem = quo_rem.1; + quo_rem.0 } #[win64_128bit_abi_hack] /// Returns `n / d` pub extern "C" fn __divti3(a: i128, b: i128) -> i128 { - a.div(b) + i128_div_rem(a, b).0 } #[win64_128bit_abi_hack] /// Returns `n % d` pub extern "C" fn __modti3(a: i128, b: i128) -> i128 { - a.mod_(b) + i128_div_rem(a, b).1 } // LLVM does not currently have a `__divmodti4` function diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 1ee670c72ab..b312ca48b04 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -156,113 +156,65 @@ intrinsics! { #[arm_aeabi_alias = __aeabi_uidiv] /// Returns `n / d` pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { - // Special cases - if d == 0 { - // NOTE This should be unreachable in safe Rust because the program will panic before - // this intrinsic is called - ::abort(); - } - - if n == 0 { - return 0; - } - - let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); - - // d > n - if sr > u32::BITS - 1 { - return 0; - } - - // d == 1 - if sr == u32::BITS - 1 { - return n; - } - - sr += 1; - - // 1 <= sr <= u32::BITS - 1 - let mut q = n << (u32::BITS - sr); - let mut r = n >> sr; - - let mut carry = 0; - - // Don't use a range because they may generate references to memcpy in unoptimized code - let mut i = 0; - while i < sr { - i += 1; - - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (u32::BITS - 1)); - q = (q << 1) | carry; - - // carry = 0; - // if r > d { - // r -= d; - // carry = 1; - // } - - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::BITS - 1); - carry = (s & 1) as u32; - r -= d & s as u32; - } - - (q << 1) | carry + u32_div_rem(n, d).0 } #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { - let q = __udivsi3(n, d); - n - q * d + u32_div_rem(n, d).1 } #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { - let q = __udivsi3(n, d); + let quo_rem = u32_div_rem(n, d); if let Some(rem) = rem { - *rem = n - (q * d); + *rem = quo_rem.1; } - q + quo_rem.0 } #[maybe_use_optimized_c_shim] /// Returns `n / d` pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { - __udivmoddi4(n, d, None) + u64_div_rem(n, d).0 } #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { - let mut rem = 0; - __udivmoddi4(n, d, Some(&mut rem)); - rem + u64_div_rem(n, d).1 } /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { - udivmod_inner!(n, d, rem, u64) + let quo_rem = u64_div_rem(n, d); + if let Some(rem) = rem { + *rem = quo_rem.1; + } + quo_rem.0 } #[win64_128bit_abi_hack] /// Returns `n / d` pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { - __udivmodti4(n, d, None) + u128_div_rem(n, d).0 } #[win64_128bit_abi_hack] /// Returns `n % d` pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { - let mut rem = 0; - __udivmodti4(n, d, Some(&mut rem)); - rem + u128_div_rem(n, d).1 } #[win64_128bit_abi_hack] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { - udivmod_inner!(n, d, rem, u128) + let quo_rem = u128_div_rem(n, d); + if let Some(rem) = rem { + *rem = quo_rem.1; + } + quo_rem.0 } } -- cgit 1.4.1-3-g733a5 From adbc0b24c55f75c53289ebc6b2fe641f28b2b202 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Sun, 19 Jul 2020 17:15:50 -0500 Subject: Remove erroneous `aapcs_on_arm` and add `maybe_use_optimized_c_shim` --- library/compiler-builtins/src/int/sdiv.rs | 2 +- library/compiler-builtins/src/int/udiv.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 983c34cf36d..682ebeda21c 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -92,7 +92,7 @@ intrinsics! { i64_div_rem(a, b).1 } - #[aapcs_on_arm] + #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __divmoddi4(a: i64, b: i64, rem: &mut i64) -> i64 { let quo_rem = i64_div_rem(a, b); diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index b312ca48b04..e517ca862d0 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -187,6 +187,7 @@ intrinsics! { u64_div_rem(n, d).1 } + #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { let quo_rem = u64_div_rem(n, d); -- cgit 1.4.1-3-g733a5 From 5386117b974ccd468aa13b87acea7b6a0f2b9c46 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 17 Jul 2020 15:17:40 -0500 Subject: Remove unused code --- library/compiler-builtins/src/int/mod.rs | 12 --- library/compiler-builtins/src/int/sdiv.rs | 58 ------------ library/compiler-builtins/src/int/udiv.rs | 151 ------------------------------ 3 files changed, 221 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 8a469d90147..7bafb82f884 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,17 +1,5 @@ use core::ops; -macro_rules! hty { - ($ty:ty) => { - <$ty as LargeInt>::HighHalf - }; -} - -macro_rules! os_ty { - ($ty:ty) => { - <$ty as Int>::OtherSign - }; -} - pub mod addsub; pub mod leading_zeros; pub mod mul; diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 682ebeda21c..d8bb9c0939c 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,63 +1,5 @@ use int::Int; -trait Div: Int { - /// Returns `a / b` - fn div(self, other: Self) -> Self { - let s_a = self >> (Self::BITS - 1); - let s_b = other >> (Self::BITS - 1); - // NOTE it's OK to overflow here because of the `.unsigned()` below. - // This whole operation is computing the absolute value of the inputs - // So some overflow will happen when dealing with e.g. `i64::MIN` - // where the absolute value is `(-i64::MIN) as u64` - let a = (self ^ s_a).wrapping_sub(s_a); - let b = (other ^ s_b).wrapping_sub(s_b); - let s = s_a ^ s_b; - - let r = a.unsigned().aborting_div(b.unsigned()); - (Self::from_unsigned(r) ^ s) - s - } -} - -impl Div for i32 {} -impl Div for i64 {} -impl Div for i128 {} - -trait Mod: Int { - /// Returns `a % b` - fn mod_(self, other: Self) -> Self { - let s = other >> (Self::BITS - 1); - // NOTE(wrapping_sub) see comment in the `div` - let b = (other ^ s).wrapping_sub(s); - let s = self >> (Self::BITS - 1); - let a = (self ^ s).wrapping_sub(s); - - let r = a.unsigned().aborting_rem(b.unsigned()); - (Self::from_unsigned(r) ^ s) - s - } -} - -impl Mod for i32 {} -impl Mod for i64 {} -impl Mod for i128 {} - -trait Divmod: Int { - /// Returns `a / b` and sets `*rem = n % d` - fn divmod(self, other: Self, rem: &mut Self, div: F) -> Self - where - F: Fn(Self, Self) -> Self, - { - let r = div(self, other); - // NOTE won't overflow because it's using the result from the - // previous division - *rem = self - r.wrapping_mul(other); - r - } -} - -impl Divmod for i32 {} -impl Divmod for i64 {} - - intrinsics! { #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_idiv] diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index e517ca862d0..49151594964 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,156 +1,5 @@ use int::{Int, LargeInt}; -macro_rules! udivmod_inner { - ($n:expr, $d:expr, $rem:expr, $ty:ty) => {{ - let (n, d, rem) = ($n, $d, $rem); - // NOTE X is unknown, K != 0 - if n.high() == 0 { - if d.high() == 0 { - // 0 X - // --- - // 0 X - - if let Some(rem) = rem { - *rem = <$ty>::from(n.low().aborting_rem(d.low())); - } - return <$ty>::from(n.low().aborting_div(d.low())) - } else { - // 0 X - // --- - // K X - if let Some(rem) = rem { - *rem = n; - } - return 0; - }; - } - - let mut sr; - let mut q; - let mut r; - - if d.low() == 0 { - if d.high() == 0 { - // K X - // --- - // 0 0 - // NOTE This should be unreachable in safe Rust because the program will panic before - // this intrinsic is called - ::abort(); - } - - if n.low() == 0 { - // K 0 - // --- - // K 0 - if let Some(rem) = rem { - *rem = <$ty>::from_parts(0, n.high().aborting_rem(d.high())); - } - return <$ty>::from(n.high().aborting_div(d.high())) - } - - // K K - // --- - // K 0 - - if d.high().is_power_of_two() { - if let Some(rem) = rem { - *rem = <$ty>::from_parts(n.low(), n.high() & (d.high() - 1)); - } - return <$ty>::from(n.high() >> d.high().trailing_zeros()); - } - - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > ::BITS - 2 { - if let Some(rem) = rem { - *rem = n; - } - return 0; - } - - sr += 1; - - // 1 <= sr <= ::BITS - 1 - q = n << (<$ty>::BITS - sr); - r = n >> sr; - } else if d.high() == 0 { - // K X - // --- - // 0 K - if d.low().is_power_of_two() { - if let Some(rem) = rem { - *rem = <$ty>::from(n.low() & (d.low() - 1)); - } - - if d.low() == 1 { - return n; - } else { - let sr = d.low().trailing_zeros(); - return n >> sr; - }; - } - - sr = 1 + ::BITS + d.low().leading_zeros() - n.high().leading_zeros(); - - // 2 <= sr <= u64::BITS - 1 - q = n << (<$ty>::BITS - sr); - r = n >> sr; - } else { - // K X - // --- - // K K - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > ::BITS - 1 { - if let Some(rem) = rem { - *rem = n; - } - return 0; - } - - sr += 1; - - // 1 <= sr <= ::BITS - q = n << (<$ty>::BITS - sr); - r = n >> sr; - } - - // Not a special case - // q and r are initialized with - // q = n << (u64::BITS - sr) - // r = n >> sr - // 1 <= sr <= u64::BITS - 1 - let mut carry = 0; - - // Don't use a range because they may generate references to memcpy in unoptimized code - let mut i = 0; - while i < sr { - i += 1; - - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (<$ty>::BITS - 1)); - q = (q << 1) | carry as $ty; - - // carry = 0 - // if r >= d { - // r -= d; - // carry = 1; - // } - let s = (d.wrapping_sub(r).wrapping_sub(1)) as os_ty!($ty) >> (<$ty>::BITS - 1); - carry = (s & 1) as hty!($ty); - r -= d & s as $ty; - } - - if let Some(rem) = rem { - *rem = r; - } - (q << 1) | carry as $ty - }} -} - intrinsics! { #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_uidiv] -- cgit 1.4.1-3-g733a5 From 66f5688d608274e5ea266c754ef4c660974498ad Mon Sep 17 00:00:00 2001 From: Max Audron Date: Thu, 13 Aug 2020 12:46:28 +0200 Subject: add 32 bit shift instructions * add 32 bit shift instructions to src/int/shift.rs __ashlsi3 __ashrsi3 __lshrsi3 * add int_impl! for 16 bit numbers and large_int! for i32 and u32 * add tests in testcrate/build.rs --- library/compiler-builtins/src/int/mod.rs | 3 +++ library/compiler-builtins/src/int/shift.rs | 18 ++++++++++++++++++ library/compiler-builtins/testcrate/build.rs | 13 +++++++++++++ 3 files changed, 34 insertions(+) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 8a469d90147..128fdfdc563 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -188,6 +188,7 @@ macro_rules! int_impl { }; } +int_impl!(i16, u16, 16); int_impl!(i32, u32, 32); int_impl!(i64, u64, 64); int_impl!(i128, u128, 128); @@ -229,6 +230,8 @@ macro_rules! large_int { }; } +large_int!(u32, u16, u16, 16); +large_int!(i32, u16, i16, 16); large_int!(u64, u32, u32, 32); large_int!(i64, u32, i32, 32); large_int!(u128, u64, u64, 64); diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 408f8f3ccbb..674c3ee8ca7 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -20,6 +20,7 @@ trait Ashl: Int + LargeInt { } } +impl Ashl for u32 {} impl Ashl for u64 {} impl Ashl for u128 {} @@ -47,6 +48,7 @@ trait Ashr: Int + LargeInt { } } +impl Ashr for i32 {} impl Ashr for i64 {} impl Ashr for i128 {} @@ -70,10 +72,16 @@ trait Lshr: Int + LargeInt { } } +impl Lshr for u32 {} impl Lshr for u64 {} impl Lshr for u128 {} intrinsics! { + #[maybe_use_optimized_c_shim] + pub extern "C" fn __ashlsi3(a: u32, b: u32) -> u32 { + a.ashl(b) + } + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsl] pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { @@ -84,6 +92,11 @@ intrinsics! { a.ashl(b) } + #[maybe_use_optimized_c_shim] + pub extern "C" fn __ashrsi3(a: i32, b: u32) -> i32 { + a.ashr(b) + } + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lasr] pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { @@ -94,6 +107,11 @@ intrinsics! { a.ashr(b) } + #[maybe_use_optimized_c_shim] + pub extern "C" fn __lshrsi3(a: u32, b: u32) -> u32 { + a.lshr(b) + } + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsr] pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index e1d4cf9e818..5a91a120ab8 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -857,6 +857,10 @@ fn main() { ); // int/shift.rs + gen( + |(a, b): (MyU32, MyU32)| Some(a.0 << (b.0 % 32)), + "builtins::int::shift::__ashlsi3(a, b % 32)", + ); gen( |(a, b): (MyU64, MyU32)| Some(a.0 << (b.0 % 64)), "builtins::int::shift::__ashldi3(a, b % 64)", @@ -865,6 +869,10 @@ fn main() { |(a, b): (MyU128, MyU32)| Some(a.0 << (b.0 % 128)), "builtins::int::shift::__ashlti3(a, b % 128)", ); + gen( + |(a, b): (MyI32, MyU32)| Some(a.0 >> (b.0 % 32)), + "builtins::int::shift::__ashrsi3(a, b % 32)", + ); gen( |(a, b): (MyI64, MyU32)| Some(a.0 >> (b.0 % 64)), "builtins::int::shift::__ashrdi3(a, b % 64)", @@ -873,6 +881,10 @@ fn main() { |(a, b): (MyI128, MyU32)| Some(a.0 >> (b.0 % 128)), "builtins::int::shift::__ashrti3(a, b % 128)", ); + gen( + |(a, b): (MyU32, MyU32)| Some(a.0 >> (b.0 % 32)), + "builtins::int::shift::__lshrsi3(a, b % 32)", + ); gen( |(a, b): (MyU64, MyU32)| Some(a.0 >> (b.0 % 64)), "builtins::int::shift::__lshrdi3(a, b % 64)", @@ -1285,6 +1297,7 @@ my_integer! { struct MyI32(i32); struct MyI64(i64); struct MyI128(i128); + struct MyU16(u16); struct MyU32(u32); struct MyU64(u64); struct MyU128(u128); -- cgit 1.4.1-3-g733a5 From 0a957ae73a50eeb135688d0574b064d6f5abf883 Mon Sep 17 00:00:00 2001 From: Xiaoyu Lu Date: Fri, 14 Aug 2020 10:28:15 +0800 Subject: Add uefi arch x86 probestack support 1. In UEFI x86 arch, probestack need triple underscore. 2. In UEFI, probestack function do things like _chkstk(in MSVC). MSVC x32's _chkstk and cygwin/mingw's _alloca adjust %esp themselves MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp themselves. But current probestack doesn't adjust esp. And LLVM doesn't generate sub %eax, %esp after probestack. So we adjust esp in probestack like MSVC x32's _chkstk. --- library/compiler-builtins/src/probestack.rs | 68 ++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 9c78faa1d23..2f37a104ece 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -76,7 +76,7 @@ macro_rules! define_rust_probestack { }; } -#[cfg(target_os = "uefi")] +#[cfg(all(target_os = "uefi", target_arch = "x86_64"))] macro_rules! define_rust_probestack { ($body: expr) => { concat!( @@ -104,6 +104,20 @@ macro_rules! define_rust_probestack { }; } +// In UEFI x86 arch, triple underscore is deliberate. +#[cfg(all(target_os = "uefi", target_arch = "x86"))] +macro_rules! define_rust_probestack { + ($body: expr) => { + concat!( + " + .globl ___rust_probestack + ___rust_probestack: + ", + $body + ) + }; +} + // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, // ensuring that if any pages are unmapped we'll make a page fault. // @@ -231,7 +245,7 @@ global_asm!(define_rust_probestack!( " )); -#[cfg(target_arch = "x86")] +#[cfg(all(target_arch = "x86", not(target_os = "uefi")))] // This is the same as x86_64 above, only translated for 32-bit sizes. Note // that on Unix we're expected to restore everything as it was, this // function basically can't tamper with anything. @@ -270,3 +284,53 @@ global_asm!(define_rust_probestack!( .cfi_endproc " )); + +#[cfg(all(target_arch = "x86", target_os = "uefi"))] +// UEFI target is windows like target. LLVM will do _chkstk things like windows. +// probestack function will also do things like _chkstk in MSVC. +// So we need to sub %ax %sp in probestack when arch is x86. +// +// REF: Rust commit(74e80468347) +// rust\src\llvm-project\llvm\lib\Target\X86\X86FrameLowering.cpp: 805 +// Comments in LLVM: +// MSVC x32's _chkstk and cygwin/mingw's _alloca adjust %esp themselves. +// MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp +// themselves. +global_asm!(define_rust_probestack!( + " + .cfi_startproc + push %ebp + .cfi_adjust_cfa_offset 4 + .cfi_offset %ebp, -8 + mov %esp, %ebp + .cfi_def_cfa_register %ebp + push %ecx + push %edx + mov %eax,%ecx + + cmp $0x1000,%ecx + jna 3f +2: + sub $0x1000,%esp + test %esp,8(%esp) + sub $0x1000,%ecx + cmp $0x1000,%ecx + ja 2b + +3: + sub %ecx,%esp + test %esp,8(%esp) + mov 4(%ebp),%edx + mov %edx, 12(%esp) + add %eax,%esp + pop %edx + pop %ecx + leave + + sub %eax, %esp + .cfi_def_cfa_register %esp + .cfi_adjust_cfa_offset -4 + ret + .cfi_endproc + " +)); -- cgit 1.4.1-3-g733a5 From d1c867333293af83237afd547bde2ead334cb5e0 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Sat, 11 Jul 2020 12:15:10 -0500 Subject: Use `specialized-div-rem` 1.0.0 for division algorithms --- library/compiler-builtins/Cargo.toml | 4 + library/compiler-builtins/src/int/mod.rs | 2 + library/compiler-builtins/src/int/sdiv.rs | 2 +- .../src/int/specialized_div_rem/asymmetric.rs | 169 ++++++ .../src/int/specialized_div_rem/binary_long.rs | 596 +++++++++++++++++++++ .../src/int/specialized_div_rem/delegate.rs | 226 ++++++++ .../src/int/specialized_div_rem/mod.rs | 295 ++++++++++ .../src/int/specialized_div_rem/norm_shift.rs | 106 ++++ .../src/int/specialized_div_rem/trifecta.rs | 441 +++++++++++++++ library/compiler-builtins/src/int/udiv.rs | 2 +- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/testcrate/Cargo.toml | 3 +- .../compiler-builtins/testcrate/tests/div_rem.rs | 143 +++++ 13 files changed, 1987 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs create mode 100644 library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs create mode 100644 library/compiler-builtins/src/int/specialized_div_rem/delegate.rs create mode 100644 library/compiler-builtins/src/int/specialized_div_rem/mod.rs create mode 100644 library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs create mode 100644 library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs create mode 100644 library/compiler-builtins/testcrate/tests/div_rem.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d4d1ad67d38..353d9a73755 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -40,6 +40,10 @@ panic-handler = { path = 'crates/panic-handler' } [features] default = ["compiler-builtins"] +# Some algorithms benefit from inline assembly, but some compiler backends do +# not support it, so inline assembly is only enabled when this flag is set. +asm = [] + # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics c = ["cc"] diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 7bafb82f884..5cfad1d6ccc 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,5 +1,7 @@ use core::ops; +mod specialized_div_rem; + pub mod addsub; pub mod leading_zeros; pub mod mul; diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index d8bb9c0939c..57ef03cdaa5 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,4 +1,4 @@ -use int::Int; +use int::specialized_div_rem::*; intrinsics! { #[maybe_use_optimized_c_shim] diff --git a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs new file mode 100644 index 00000000000..861e9174267 --- /dev/null +++ b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs @@ -0,0 +1,169 @@ +/// Creates unsigned and signed division functions optimized for dividing integers with the same +/// bitwidth as the largest operand in an asymmetrically sized division. For example, x86-64 has an +/// assembly instruction that can divide a 128 bit integer by a 64 bit integer if the quotient fits +/// in 64 bits. The 128 bit version of this algorithm would use that fast hardware division to +/// construct a full 128 bit by 128 bit division. +#[macro_export] +macro_rules! impl_asymmetric { + ( + $unsigned_name:ident, // name of the unsigned division function + $signed_name:ident, // name of the signed division function + $zero_div_fn:ident, // function called when division by zero is attempted + $half_division:ident, // function for division of a $uX by a $uX + $asymmetric_division:ident, // function for division of a $uD by a $uX + $n_h:expr, // the number of bits in a $iH or $uH + $uH:ident, // unsigned integer with half the bit width of $uX + $uX:ident, // unsigned integer with half the bit width of $uD + $uD:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iD:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($unsigned_attr:meta),*; // attributes for the unsigned function + $($signed_attr:meta),* // attributes for the signed function + ) => { + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$unsigned_attr] + )* + pub fn $unsigned_name(duo: $uD, div: $uD) -> ($uD,$uD) { + fn carrying_mul(lhs: $uX, rhs: $uX) -> ($uX, $uX) { + let tmp = (lhs as $uD).wrapping_mul(rhs as $uD); + (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) + } + fn carrying_mul_add(lhs: $uX, mul: $uX, add: $uX) -> ($uX, $uX) { + let tmp = (lhs as $uD).wrapping_mul(mul as $uD).wrapping_add(add as $uD); + (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) + } + + let n: u32 = $n_h * 2; + + // Many of these subalgorithms are taken from trifecta.rs, see that for better + // documentation. + + let duo_lo = duo as $uX; + let duo_hi = (duo >> n) as $uX; + let div_lo = div as $uX; + let div_hi = (div >> n) as $uX; + if div_hi == 0 { + if div_lo == 0 { + $zero_div_fn() + } + if duo_hi < div_lo { + // `$uD` by `$uX` division with a quotient that will fit into a `$uX` + let (quo, rem) = unsafe { $asymmetric_division(duo, div_lo) }; + return (quo as $uD, rem as $uD) + } else if (div_lo >> $n_h) == 0 { + // Short division of $uD by a $uH. + + // Some x86_64 CPUs have bad division implementations that make specializing + // this case faster. + let div_0 = div_lo as $uH as $uX; + let (quo_hi, rem_3) = $half_division(duo_hi, div_0); + + let duo_mid = + ((duo >> $n_h) as $uH as $uX) + | (rem_3 << $n_h); + let (quo_1, rem_2) = $half_division(duo_mid, div_0); + + let duo_lo = + (duo as $uH as $uX) + | (rem_2 << $n_h); + let (quo_0, rem_1) = $half_division(duo_lo, div_0); + + return ( + (quo_0 as $uD) + | ((quo_1 as $uD) << $n_h) + | ((quo_hi as $uD) << n), + rem_1 as $uD + ) + } else { + // Short division using the $uD by $uX division + let (quo_hi, rem_hi) = $half_division(duo_hi, div_lo); + let tmp = unsafe { + $asymmetric_division((duo_lo as $uD) | ((rem_hi as $uD) << n), div_lo) + }; + return ((tmp.0 as $uD) | ((quo_hi as $uD) << n), tmp.1 as $uD) + } + } + + let duo_lz = duo_hi.leading_zeros(); + let div_lz = div_hi.leading_zeros(); + let rel_leading_sb = div_lz.wrapping_sub(duo_lz); + if rel_leading_sb < $n_h { + // Some x86_64 CPUs have bad hardware division implementations that make putting + // a two possibility algorithm here beneficial. We also avoid a full `$uD` + // multiplication. + let shift = n - duo_lz; + let duo_sig_n = (duo >> shift) as $uX; + let div_sig_n = (div >> shift) as $uX; + let quo = $half_division(duo_sig_n, div_sig_n).0; + let div_lo = div as $uX; + let div_hi = (div >> n) as $uX; + let (tmp_lo, carry) = carrying_mul(quo, div_lo); + let (tmp_hi, overflow) = carrying_mul_add(quo, div_hi, carry); + let tmp = (tmp_lo as $uD) | ((tmp_hi as $uD) << n); + if (overflow != 0) || (duo < tmp) { + return ( + (quo - 1) as $uD, + duo.wrapping_add(div).wrapping_sub(tmp) + ) + } else { + return ( + quo as $uD, + duo - tmp + ) + } + } else { + // This has been adapted from + // https://www.codeproject.com/tips/785014/uint-division-modulus which was in turn + // adapted from Hacker's Delight. This is similar to the two possibility algorithm + // in that it uses only more significant parts of `duo` and `div` to divide a large + // integer with a smaller division instruction. + + let div_extra = n - div_lz; + let div_sig_n = (div >> div_extra) as $uX; + let tmp = unsafe { + $asymmetric_division(duo >> 1, div_sig_n) + }; + + let mut quo = tmp.0 >> ((n - 1) - div_lz); + if quo != 0 { + quo -= 1; + } + + // Note that this is a full `$uD` multiplication being used here + let mut rem = duo - (quo as $uD).wrapping_mul(div); + if div <= rem { + quo += 1; + rem -= div; + } + return (quo as $uD, rem) + } + } + + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$signed_attr] + )* + pub fn $signed_name(duo: $iD, div: $iD) -> ($iD, $iD) { + match (duo < 0, div < 0) { + (false, false) => { + let t = $unsigned_name(duo as $uD, div as $uD); + (t.0 as $iD, t.1 as $iD) + }, + (true, false) => { + let t = $unsigned_name(duo.wrapping_neg() as $uD, div as $uD); + ((t.0 as $iD).wrapping_neg(), (t.1 as $iD).wrapping_neg()) + }, + (false, true) => { + let t = $unsigned_name(duo as $uD, div.wrapping_neg() as $uD); + ((t.0 as $iD).wrapping_neg(), t.1 as $iD) + }, + (true, true) => { + let t = $unsigned_name(duo.wrapping_neg() as $uD, div.wrapping_neg() as $uD); + (t.0 as $iD, (t.1 as $iD).wrapping_neg()) + }, + } + } + } +} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs new file mode 100644 index 00000000000..4c63396a088 --- /dev/null +++ b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs @@ -0,0 +1,596 @@ +/// Creates unsigned and signed division functions that use binary long division, designed for +/// computer architectures without division instructions. These functions have good performance for +/// microarchitectures with large branch miss penalties and architectures without the ability to +/// predicate instructions. For architectures with predicated instructions, one of the algorithms +/// described in the documentation of these functions probably has higher performance, and a custom +/// assembly routine should be used instead. +#[macro_export] +macro_rules! impl_binary_long { + ( + $unsigned_name:ident, // name of the unsigned division function + $signed_name:ident, // name of the signed division function + $zero_div_fn:ident, // function called when division by zero is attempted + $normalization_shift:ident, // function for finding the normalization shift + $n:tt, // the number of bits in a $iX or $uX + $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($unsigned_attr:meta),*; // attributes for the unsigned function + $($signed_attr:meta),* // attributes for the signed function + ) => { + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$unsigned_attr] + )* + pub fn $unsigned_name(duo: $uX, div: $uX) -> ($uX, $uX) { + let mut duo = duo; + // handle edge cases before calling `$normalization_shift` + if div == 0 { + $zero_div_fn() + } + if duo < div { + return (0, duo) + } + + // There are many variations of binary division algorithm that could be used. This + // documentation gives a tour of different methods so that future readers wanting to + // optimize further do not have to painstakingly derive them. The SWAR variation is + // especially hard to understand without reading the less convoluted methods first. + + // You may notice that a `duo < div_original` check is included in many these + // algorithms. A critical optimization that many algorithms miss is handling of + // quotients that will turn out to have many trailing zeros or many leading zeros. This + // happens in cases of exact or close-to-exact divisions, divisions by power of two, and + // in cases where the quotient is small. The `duo < div_original` check handles these + // cases of early returns and ends up replacing other kinds of mundane checks that + // normally terminate a binary division algorithm. + // + // Something you may see in other algorithms that is not special-cased here is checks + // for division by powers of two. The `duo < div_original` check handles this case and + // more, however it can be checked up front before the bisection using the + // `((div > 0) && ((div & (div - 1)) == 0))` trick. This is not special-cased because + // compilers should handle most cases where divisions by power of two occur, and we do + // not want to add on a few cycles for every division operation just to save a few + // cycles rarely. + + // The following example is the most straightforward translation from the way binary + // long division is typically visualized: + // Dividing 178u8 (0b10110010) by 6u8 (0b110). `div` is shifted left by 5, according to + // the result from `$normalization_shift(duo, div, false)`. + // + // Step 0: `sub` is negative, so there is not full normalization, so no `quo` bit is set + // and `duo` is kept unchanged. + // duo:10110010, div_shifted:11000000, sub:11110010, quo:00000000, shl:5 + // + // Step 1: `sub` is positive, set a `quo` bit and update `duo` for next step. + // duo:10110010, div_shifted:01100000, sub:01010010, quo:00010000, shl:4 + // + // Step 2: Continue based on `sub`. The `quo` bits start accumulating. + // duo:01010010, div_shifted:00110000, sub:00100010, quo:00011000, shl:3 + // duo:00100010, div_shifted:00011000, sub:00001010, quo:00011100, shl:2 + // duo:00001010, div_shifted:00001100, sub:11111110, quo:00011100, shl:1 + // duo:00001010, div_shifted:00000110, sub:00000100, quo:00011100, shl:0 + // The `duo < div_original` check terminates the algorithm with the correct quotient of + // 29u8 and remainder of 4u8 + /* + let div_original = div; + let mut shl = $normalization_shift(duo, div, false); + let mut quo = 0; + loop { + let div_shifted = div << shl; + let sub = duo.wrapping_sub(div_shifted); + // it is recommended to use `println!`s like this if functionality is unclear + /* + println!("duo:{:08b}, div_shifted:{:08b}, sub:{:08b}, quo:{:08b}, shl:{}", + duo, + div_shifted, + sub, + quo, + shl + ); + */ + if 0 <= (sub as $iX) { + duo = sub; + quo += 1 << shl; + if duo < div_original { + // this branch is optional + return (quo, duo) + } + } + if shl == 0 { + return (quo, duo) + } + shl -= 1; + } + */ + + // This restoring binary long division algorithm reduces the number of operations + // overall via: + // - `pow` can be shifted right instead of recalculating from `shl` + // - starting `div` shifted left and shifting it right for each step instead of + // recalculating from `shl` + // - The `duo < div_original` branch is used to terminate the algorithm instead of the + // `shl == 0` branch. This check is strong enough to prevent set bits of `pow` and + // `div` from being shifted off the end. This check also only occurs on half of steps + // on average, since it is behind the `(sub as $iX) >= 0` branch. + // - `shl` is now not needed by any aspect of of the loop and thus only 3 variables are + // being updated between steps + // + // There are many variations of this algorithm, but this encompases the largest number + // of architectures and does not rely on carry flags, add-with-carry, or SWAR + // complications to be decently fast. + /* + let div_original = div; + let shl = $normalization_shift(duo, div, false); + let mut div: $uX = div << shl; + let mut pow: $uX = 1 << shl; + let mut quo: $uX = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as $iX) { + duo = sub; + quo |= pow; + if duo < div_original { + return (quo, duo) + } + } + div >>= 1; + pow >>= 1; + } + */ + + // If the architecture has flags and predicated arithmetic instructions, it is possible + // to do binary long division without branching and in only 3 or 4 instructions. This is + // a variation of a 3 instruction central loop from + // http://www.chiark.greenend.org.uk/~theom/riscos/docs/ultimate/a252div.txt. + // + // What allows doing division in only 3 instructions is realizing that instead of + // keeping `duo` in place and shifting `div` right to align bits, `div` can be kept in + // place and `duo` can be shifted left. This means `div` does not have to be updated, + // but causes edge case problems and makes `duo < div_original` tests harder. Some + // architectures have an option to shift an argument in an arithmetic operation, which + // means `duo` can be shifted left and subtracted from in one instruction. The other two + // instructions are updating `quo` and undoing the subtraction if it turns out things + // were not normalized. + + /* + // Perform one binary long division step on the already normalized arguments, because + // the main. Note that this does a full normalization since the central loop needs + // `duo.leading_zeros()` to be at least 1 more than `div.leading_zeros()`. The original + // variation only did normalization to the nearest 4 steps, but this makes handling edge + // cases much harder. We do a full normalization and perform a binary long division + // step. In the edge case where the msbs of `duo` and `div` are set, it clears the msb + // of `duo`, then the edge case handler shifts `div` right and does another long + // division step to always insure `duo.leading_zeros() + 1 >= div.leading_zeros()`. + let div_original = div; + let mut shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + let mut quo: $uX = 1; + duo = duo.wrapping_sub(div); + if duo < div_original { + return (1 << shl, duo); + } + let div_neg: $uX; + if (div as $iX) < 0 { + // A very ugly edge case where the most significant bit of `div` is set (after + // shifting to match `duo` when its most significant bit is at the sign bit), which + // leads to the sign bit of `div_neg` being cut off and carries not happening when + // they should. This branch performs a long division step that keeps `duo` in place + // and shifts `div` down. + div >>= 1; + div_neg = div.wrapping_neg(); + let (sub, carry) = duo.overflowing_add(div_neg); + duo = sub; + quo = quo.wrapping_add(quo).wrapping_add(carry as $uX); + if !carry { + duo = duo.wrapping_add(div); + } + shl -= 1; + } else { + div_neg = div.wrapping_neg(); + } + // The add-with-carry that updates `quo` needs to have the carry set when a normalized + // subtract happens. Using `duo.wrapping_shl(1).overflowing_sub(div)` to do the + // subtraction generates a carry when an unnormalized subtract happens, which is the + // opposite of what we want. Instead, we use + // `duo.wrapping_shl(1).overflowing_add(div_neg)`, where `div_neg` is negative `div`. + let mut i = shl; + loop { + if i == 0 { + break; + } + i -= 1; + // `ADDS duo, div, duo, LSL #1` + // (add `div` to `duo << 1` and set flags) + let (sub, carry) = duo.wrapping_shl(1).overflowing_add(div_neg); + duo = sub; + // `ADC quo, quo, quo` + // (add with carry). Effectively shifts `quo` left by 1 and sets the least + // significant bit to the carry. + quo = quo.wrapping_add(quo).wrapping_add(carry as $uX); + // `ADDCC duo, duo, div` + // (add if carry clear). Undoes the subtraction if no carry was generated. + if !carry { + duo = duo.wrapping_add(div); + } + } + return (quo, duo >> shl); + */ + + // This is the SWAR (SIMD within in a register) restoring division algorithm. + // This combines several ideas of the above algorithms: + // - If `duo` is shifted left instead of shifting `div` right like in the 3 instruction + // restoring division algorithm, some architectures can do the shifting and + // subtraction step in one instruction. + // - `quo` can be constructed by adding powers-of-two to it or shifting it left by one + // and adding one. + // - Every time `duo` is shifted left, there is another unused 0 bit shifted into the + // LSB, so what if we use those bits to store `quo`? + // Through a complex setup, it is possible to manage `duo` and `quo` in the same + // register, and perform one step with 2 or 3 instructions. The only major downsides are + // that there is significant setup (it is only saves instructions if `shl` is + // approximately more than 4), `duo < div_original` checks are impractical once SWAR is + // initiated, and the number of division steps taken has to be exact (we cannot do more + // division steps than `shl`, because it introduces edge cases where quotient bits in + // `duo` start to collide with the real part of `div`. + /* + // first step. The quotient bit is stored in `quo` for now + let div_original = div; + let mut shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + duo = duo.wrapping_sub(div); + let mut quo: $uX = 1 << shl; + if duo < div_original { + return (quo, duo); + } + + let mask: $uX; + if (div as $iX) < 0 { + // deal with same edge case as the 3 instruction restoring division algorithm, but + // the quotient bit from this step also has to be stored in `quo` + div >>= 1; + shl -= 1; + let tmp = 1 << shl; + mask = tmp - 1; + let sub = duo.wrapping_sub(div); + if (sub as $iX) >= 0 { + // restore + duo = sub; + quo |= tmp; + } + if duo < div_original { + return (quo, duo); + } + } else { + mask = quo - 1; + } + // There is now room for quotient bits in `duo`. + + // Note that `div` is already shifted left and has `shl` unset bits. We subtract 1 from + // `div` and end up with the subset of `shl` bits being all being set. This subset acts + // just like a two's complement negative one. The subset of `div` containing the divisor + // had 1 subtracted from it, but a carry will always be generated from the `shl` subset + // as long as the quotient stays positive. + // + // When the modified `div` is subtracted from `duo.wrapping_shl(1)`, the `shl` subset + // adds a quotient bit to the least significant bit. + // For example, 89 (0b01011001) divided by 3 (0b11): + // + // shl:4, div:0b00110000 + // first step: + // duo:0b01011001 + // + div_neg:0b11010000 + // ____________________ + // 0b00101001 + // quo is set to 0b00010000 and mask is set to 0b00001111 for later + // + // 1 is subtracted from `div`. I will differentiate the `shl` part of `div` and the + // quotient part of `duo` with `^`s. + // chars. + // div:0b00110000 + // ^^^^ + // + 0b11111111 + // ________________ + // 0b00101111 + // ^^^^ + // div_neg:0b11010001 + // + // first SWAR step: + // duo_shl1:0b01010010 + // ^ + // + div_neg:0b11010001 + // ____________________ + // 0b00100011 + // ^ + // second: + // duo_shl1:0b01000110 + // ^^ + // + div_neg:0b11010001 + // ____________________ + // 0b00010111 + // ^^ + // third: + // duo_shl1:0b00101110 + // ^^^ + // + div_neg:0b11010001 + // ____________________ + // 0b11111111 + // ^^^ + // 3 steps resulted in the quotient with 3 set bits as expected, but currently the real + // part of `duo` is negative and the third step was an unnormalized step. The restore + // branch then restores `duo`. Note that the restore branch does not shift `duo` left. + // + // duo:0b11111111 + // ^^^ + // + div:0b00101111 + // ^^^^ + // ________________ + // 0b00101110 + // ^^^ + // `duo` is now back in the `duo_shl1` state it was at in the the third step, with an + // unset quotient bit. + // + // final step (`shl` was 4, so exactly 4 steps must be taken) + // duo_shl1:0b01011100 + // ^^^^ + // + div_neg:0b11010001 + // ____________________ + // 0b00101101 + // ^^^^ + // The quotient includes the `^` bits added with the `quo` bits from the beginning that + // contained the first step and potential edge case step, + // `quo:0b00010000 + (duo:0b00101101 & mask:0b00001111) == 0b00011101 == 29u8`. + // The remainder is the bits remaining in `duo` that are not part of the quotient bits, + // `duo:0b00101101 >> shl == 0b0010 == 2u8`. + let div: $uX = div.wrapping_sub(1); + let mut i = shl; + loop { + if i == 0 { + break; + } + i -= 1; + duo = duo.wrapping_shl(1).wrapping_sub(div); + if (duo as $iX) < 0 { + // restore + duo = duo.wrapping_add(div); + } + } + // unpack the results of SWAR + return ((duo & mask) | quo, duo >> shl); + */ + + // The problem with the conditional restoring SWAR algorithm above is that, in practice, + // it requires assembly code to bring out its full unrolled potential (It seems that + // LLVM can't use unrolled conditionals optimally and ends up erasing all the benefit + // that my algorithm intends. On architectures without predicated instructions, the code + // gen is especially bad. We need a default software division algorithm that is + // guaranteed to get decent code gen for the central loop. + + // For non-SWAR algorithms, there is a way to do binary long division without + // predication or even branching. This involves creating a mask from the sign bit and + // performing different kinds of steps using that. + /* + let shl = $normalization_shift(duo, div, true); + let mut div: $uX = div << shl; + let mut pow: $uX = 1 << shl; + let mut quo: $uX = 0; + loop { + let sub = duo.wrapping_sub(div); + let sign_mask = !((sub as $iX).wrapping_shr($n - 1) as $uX); + duo -= div & sign_mask; + quo |= pow & sign_mask; + div >>= 1; + pow >>= 1; + if pow == 0 { + break; + } + } + return (quo, duo); + */ + // However, it requires about 4 extra operations (smearing the sign bit, negating the + // mask, and applying the mask twice) on top of the operations done by the actual + // algorithm. With SWAR however, just 2 extra operations are needed, making it + // practical and even the most optimal algorithm for some architectures. + + // What we do is use custom assembly for predicated architectures that need software + // division, and for the default algorithm use a mask based restoring SWAR algorithm + // without conditionals or branches. On almost all architectures, this Rust code is + // guaranteed to compile down to 5 assembly instructions or less for each step, and LLVM + // will unroll it in a decent way. + + // standard opening for SWAR algorithm with first step and edge case handling + let div_original = div; + let mut shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + duo = duo.wrapping_sub(div); + let mut quo: $uX = 1 << shl; + if duo < div_original { + return (quo, duo); + } + let mask: $uX; + if (div as $iX) < 0 { + div >>= 1; + shl -= 1; + let tmp = 1 << shl; + mask = tmp - 1; + let sub = duo.wrapping_sub(div); + if (sub as $iX) >= 0 { + duo = sub; + quo |= tmp; + } + if duo < div_original { + return (quo, duo); + } + } else { + mask = quo - 1; + } + + // central loop + div = div.wrapping_sub(1); + let mut i = shl; + loop { + if i == 0 { + break + } + i -= 1; + // shift left 1 and subtract + duo = duo.wrapping_shl(1).wrapping_sub(div); + // create mask + let mask = (duo as $iX).wrapping_shr($n - 1) as $uX; + // restore + duo = duo.wrapping_add(div & mask); + } + // unpack + return ((duo & mask) | quo, duo >> shl); + + // miscellanious binary long division algorithms that might be better for specific + // architectures + + // Another kind of long division uses an interesting fact that `div` and `pow` can be + // negated when `duo` is negative to perform a "negated" division step that works in + // place of any normalization mechanism. This is a non-restoring division algorithm that + // is very similar to the non-restoring division algorithms that can be found on the + // internet, except there is only one test for `duo < 0`. The subtraction from `quo` can + // be viewed as shifting the least significant set bit right (e.x. if we enter a series + // of negated binary long division steps starting with `quo == 0b1011_0000` and + // `pow == 0b0000_1000`, `quo` will progress like this: 0b1010_1000, 0b1010_0100, + // 0b1010_0010, 0b1010_0001). + /* + let div_original = div; + let shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + let mut pow: $uX = 1 << shl; + let mut quo: $uX = pow; + duo = duo.wrapping_sub(div); + if duo < div_original { + return (quo, duo); + } + div >>= 1; + pow >>= 1; + loop { + if (duo as $iX) < 0 { + // Negated binary long division step. + duo = duo.wrapping_add(div); + quo = quo.wrapping_sub(pow); + } else { + // Normal long division step. + if duo < div_original { + return (quo, duo) + } + duo = duo.wrapping_sub(div); + quo = quo.wrapping_add(pow); + } + pow >>= 1; + div >>= 1; + } + */ + + // This is the Nonrestoring SWAR algorithm, combining the nonrestoring algorithm with + // SWAR techniques that makes the only difference between steps be negation of `div`. + // If there was an architecture with an instruction that negated inputs to an adder + // based on conditionals, and in place shifting (or a three input addition operation + // that can have `duo` as two of the inputs to effectively shift it left by 1), then a + // single instruction central loop is possible. Microarchitectures often have inputs to + // their ALU that can invert the arguments and carry in of adders, but the architectures + // unfortunately do not have an instruction to dynamically invert this input based on + // conditionals. + /* + // SWAR opening + let div_original = div; + let mut shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + duo = duo.wrapping_sub(div); + let mut quo: $uX = 1 << shl; + if duo < div_original { + return (quo, duo); + } + let mask: $uX; + if (div as $iX) < 0 { + div >>= 1; + shl -= 1; + let tmp = 1 << shl; + let sub = duo.wrapping_sub(div); + if (sub as $iX) >= 0 { + // restore + duo = sub; + quo |= tmp; + } + if duo < div_original { + return (quo, duo); + } + mask = tmp - 1; + } else { + mask = quo - 1; + } + + // central loop + let div: $uX = div.wrapping_sub(1); + let mut i = shl; + loop { + if i == 0 { + break; + } + i -= 1; + // note: the `wrapping_shl(1)` can be factored out, but would require another + // restoring division step to prevent `(duo as $iX)` from overflowing + if (duo as $iX) < 0 { + // Negated binary long division step. + duo = duo.wrapping_shl(1).wrapping_add(div); + } else { + // Normal long division step. + duo = duo.wrapping_shl(1).wrapping_sub(div); + } + } + if (duo as $iX) < 0 { + // Restore. This was not needed in the original nonrestoring algorithm because of + // the `duo < div_original` checks. + duo = duo.wrapping_add(div); + } + // unpack + return ((duo & mask) | quo, duo >> shl); + */ + } + + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$signed_attr] + )* + pub fn $signed_name(duo: $iX, div: $iX) -> ($iX, $iX) { + // There is a way of doing this without any branches, but requires too many extra + // operations to be faster. + /* + let duo_s = duo >> ($n - 1); + let div_s = div >> ($n - 1); + let duo = (duo ^ duo_s).wrapping_sub(duo_s); + let div = (div ^ div_s).wrapping_sub(div_s); + let quo_s = duo_s ^ div_s; + let rem_s = duo_s; + let tmp = $unsigned_name(duo as $uX, div as $uX); + ( + ((tmp.0 as $iX) ^ quo_s).wrapping_sub(quo_s), + ((tmp.1 as $iX) ^ rem_s).wrapping_sub(rem_s), + ) + */ + + match (duo < 0, div < 0) { + (false, false) => { + let t = $unsigned_name(duo as $uX, div as $uX); + (t.0 as $iX, t.1 as $iX) + }, + (true, false) => { + let t = $unsigned_name(duo.wrapping_neg() as $uX, div as $uX); + ((t.0 as $iX).wrapping_neg(), (t.1 as $iX).wrapping_neg()) + }, + (false, true) => { + let t = $unsigned_name(duo as $uX, div.wrapping_neg() as $uX); + ((t.0 as $iX).wrapping_neg(), t.1 as $iX) + }, + (true, true) => { + let t = $unsigned_name(duo.wrapping_neg() as $uX, div.wrapping_neg() as $uX); + (t.0 as $iX, (t.1 as $iX).wrapping_neg()) + }, + } + } + } +} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs new file mode 100644 index 00000000000..1ba72431d61 --- /dev/null +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -0,0 +1,226 @@ +/// Creates unsigned and signed division functions that use a combination of hardware division and +/// binary long division to divide integers larger than what hardware division by itself can do. This +/// function is intended for microarchitectures that have division hardware, but not fast enough +/// multiplication hardware for `impl_trifecta` to be faster. +#[macro_export] +macro_rules! impl_delegate { + ( + $unsigned_name:ident, // name of the unsigned division function + $signed_name:ident, // name of the signed division function + $zero_div_fn:ident, // function called when division by zero is attempted + $half_normalization_shift:ident, // function for finding the normalization shift of $uX + $half_division:ident, // function for division of a $uX by a $uX + $n_h:expr, // the number of bits in $iH or $uH + $uH:ident, // unsigned integer with half the bit width of $uX + $uX:ident, // unsigned integer with half the bit width of $uD. + $uD:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iD:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($unsigned_attr:meta),*; // attributes for the unsigned function + $($signed_attr:meta),* // attributes for the signed function + ) => { + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$unsigned_attr] + )* + pub fn $unsigned_name(duo: $uD, div: $uD) -> ($uD, $uD) { + // The two possibility algorithm, undersubtracting long division algorithm, or any kind + // of reciprocal based algorithm will not be fastest, because they involve large + // multiplications that we assume to not be fast enough relative to the divisions to + // outweigh setup times. + + // the number of bits in a $uX + let n = $n_h * 2; + + let duo_lo = duo as $uX; + let duo_hi = (duo >> n) as $uX; + let div_lo = div as $uX; + let div_hi = (div >> n) as $uX; + + match (div_lo == 0, div_hi == 0, duo_hi == 0) { + (true, true, _) => { + $zero_div_fn() + } + (_, false, true) => { + // `duo` < `div` + return (0, duo) + } + (false, true, true) => { + // delegate to smaller division + let tmp = $half_division(duo_lo, div_lo); + return (tmp.0 as $uD, tmp.1 as $uD) + } + (false, true, false) => { + if duo_hi < div_lo { + // `quo_hi` will always be 0. This performs a binary long division algorithm + // to zero `duo_hi` followed by a half division. + + // We can calculate the normalization shift using only `$uX` size functions. + // If we calculated the normalization shift using + // `$half_normalization_shift(duo_hi, div_lo false)`, it would break the + // assumption the function has that the first argument is more than the + // second argument. If the arguments are switched, the assumption holds true + // since `duo_hi < div_lo`. + let norm_shift = $half_normalization_shift(div_lo, duo_hi, false); + let shl = if norm_shift == 0 { + // Consider what happens if the msbs of `duo_hi` and `div_lo` align with + // no shifting. The normalization shift will always return + // `norm_shift == 0` regardless of whether it is fully normalized, + // because `duo_hi < div_lo`. In that edge case, `n - norm_shift` would + // result in shift overflow down the line. For the edge case, because + // both `duo_hi < div_lo` and we are comparing all the significant bits + // of `duo_hi` and `div`, we can make `shl = n - 1`. + n - 1 + } else { + // We also cannot just use `shl = n - norm_shift - 1` in the general + // case, because when we are not in the edge case comparing all the + // significant bits, then the full `duo < div` may not be true and thus + // breaks the division algorithm. + n - norm_shift + }; + + // The 3 variable restoring division algorithm (see binary_long.rs) is ideal + // for this task, since `pow` and `quo` can be `$uX` and the delegation + // check is simple. + let mut div: $uD = div << shl; + let mut pow_lo: $uX = 1 << shl; + let mut quo_lo: $uX = 0; + let mut duo = duo; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as $iD) { + duo = sub; + quo_lo |= pow_lo; + let duo_hi = (duo >> n) as $uX; + if duo_hi == 0 { + // Delegate to get the rest of the quotient. Note that the + // `div_lo` here is the original unshifted `div`. + let tmp = $half_division(duo as $uX, div_lo); + return ((quo_lo | tmp.0) as $uD, tmp.1 as $uD) + } + } + div >>= 1; + pow_lo >>= 1; + } + } else if duo_hi == div_lo { + // `quo_hi == 1`. This branch is cheap and helps with edge cases. + let tmp = $half_division(duo as $uX, div as $uX); + return ((1 << n) | (tmp.0 as $uD), tmp.1 as $uD) + } else { + // `div_lo < duo_hi` + // `rem_hi == 0` + if (div_lo >> $n_h) == 0 { + // Short division of $uD by a $uH, using $uX by $uX division + let div_0 = div_lo as $uH as $uX; + let (quo_hi, rem_3) = $half_division(duo_hi, div_0); + + let duo_mid = + ((duo >> $n_h) as $uH as $uX) + | (rem_3 << $n_h); + let (quo_1, rem_2) = $half_division(duo_mid, div_0); + + let duo_lo = + (duo as $uH as $uX) + | (rem_2 << $n_h); + let (quo_0, rem_1) = $half_division(duo_lo, div_0); + + return ( + (quo_0 as $uD) + | ((quo_1 as $uD) << $n_h) + | ((quo_hi as $uD) << n), + rem_1 as $uD + ) + } + + // This is basically a short division composed of a half division for the hi + // part, specialized 3 variable binary long division in the middle, and + // another half division for the lo part. + let duo_lo = duo as $uX; + let tmp = $half_division(duo_hi, div_lo); + let quo_hi = tmp.0; + let mut duo = (duo_lo as $uD) | ((tmp.1 as $uD) << n); + // This check is required to avoid breaking the long division below. + if duo < div { + return ((quo_hi as $uD) << n, duo); + } + + // The half division handled all shift alignments down to `n`, so this + // division can continue with a shift of `n - 1`. + let mut div: $uD = div << (n - 1); + let mut pow_lo: $uX = 1 << (n - 1); + let mut quo_lo: $uX = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as $iD) { + duo = sub; + quo_lo |= pow_lo; + let duo_hi = (duo >> n) as $uX; + if duo_hi == 0 { + // Delegate to get the rest of the quotient. Note that the + // `div_lo` here is the original unshifted `div`. + let tmp = $half_division(duo as $uX, div_lo); + return ( + (tmp.0) as $uD | (quo_lo as $uD) | ((quo_hi as $uD) << n), + tmp.1 as $uD + ); + } + } + div >>= 1; + pow_lo >>= 1; + } + } + } + (_, false, false) => { + // Full $uD by $uD binary long division. `quo_hi` will always be 0. + if duo < div { + return (0, duo); + } + let div_original = div; + let shl = $half_normalization_shift(duo_hi, div_hi, false); + let mut duo = duo; + let mut div: $uD = div << shl; + let mut pow_lo: $uX = 1 << shl; + let mut quo_lo: $uX = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as $iD) { + duo = sub; + quo_lo |= pow_lo; + if duo < div_original { + return (quo_lo as $uD, duo) + } + } + div >>= 1; + pow_lo >>= 1; + } + } + } + } + + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$signed_attr] + )* + pub fn $signed_name(duo: $iD, div: $iD) -> ($iD, $iD) { + match (duo < 0, div < 0) { + (false, false) => { + let t = $unsigned_name(duo as $uD, div as $uD); + (t.0 as $iD, t.1 as $iD) + }, + (true, false) => { + let t = $unsigned_name(duo.wrapping_neg() as $uD, div as $uD); + ((t.0 as $iD).wrapping_neg(), (t.1 as $iD).wrapping_neg()) + }, + (false, true) => { + let t = $unsigned_name(duo as $uD, div.wrapping_neg() as $uD); + ((t.0 as $iD).wrapping_neg(), t.1 as $iD) + }, + (true, true) => { + let t = $unsigned_name(duo.wrapping_neg() as $uD, div.wrapping_neg() as $uD); + (t.0 as $iD, (t.1 as $iD).wrapping_neg()) + }, + } + } + } +} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs new file mode 100644 index 00000000000..5a034dcf10b --- /dev/null +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -0,0 +1,295 @@ +// TODO: when `unsafe_block_in_unsafe_fn` is stabilized, remove this +#![allow(unused_unsafe)] + +//! This `specialized_div_rem` module is originally from version 1.0.0 of the +//! `specialized-div-rem` crate. Note that `for` loops with ranges are not used in this +//! module, since unoptimized compilation may generate references to `memcpy`. +//! +//! The purpose of these macros is to easily change the both the division algorithm used +//! for a given integer size and the half division used by that algorithm. The way +//! functions call each other is also constructed such that linkers will find the chain of +//! software and hardware divisions needed for every size of signed and unsigned division. +//! For example, most target compilations do the following: +//! +//! - Many 128 bit division functions like `u128::wrapping_div` use +//! `std::intrinsics::unchecked_div`, which gets replaced by `__udivti3` because there +//! is not a 128 bit by 128 bit hardware division function in most architectures. +//! `__udivti3` uses `u128_div_rem` (this extra level of function calls exists because +//! `__umodti3` and `__udivmodti4` also exist, and `specialized_div_rem` supplies just +//! one function to calculate both the quotient and remainder. If configuration flags +//! enable it, `impl_trifecta!` defines `u128_div_rem` to use the trifecta algorithm, +//! which requires the half sized division `u64_by_u64_div_rem`. If the architecture +//! supplies a 64 bit hardware division instruction, `u64_by_u64_div_rem` will be +//! reduced to those instructions. Note that we do not specify the half size division +//! directly to be `__udivdi3`, because hardware division would never be introduced. +//! - If the architecture does not supply a 64 bit hardware division instruction, u64 +//! divisions will use functions such as `__udivdi3`. This will call `u64_div_rem` +//! which is defined by `impl_delegate!`. The half division for this algorithm is +//! `u32_by_u32_div_rem` which in turn becomes hardware division instructions or more +//! software division algorithms. +//! - If the architecture does not supply a 32 bit hardware instruction, linkers will +//! look for `__udivsi3`. `impl_binary_long!` is used, but this algorithm uses no half +//! division, so the chain of calls ends here. +//! +//! On some architectures like x86_64, an asymmetrically sized division is supplied, in +//! which 128 bit numbers can be divided by 64 bit numbers. `impl_asymmetric!` is used to +//! extend the 128 by 64 bit division to a full 128 by 128 bit division. + +// `allow(dead_code)` is used in various places, because the configuration code would otherwise be +// ridiculously complex + +#[macro_use] +mod norm_shift; + +#[macro_use] +mod binary_long; + +#[macro_use] +mod delegate; + +#[macro_use] +mod trifecta; + +#[macro_use] +mod asymmetric; + +/// The behavior of all divisions by zero is controlled by this function. This function should be +/// impossible to reach by Rust users, unless `compiler-builtins` public division functions or +/// `core/std::unchecked_div/rem` are directly used without a zero check in front. +fn zero_div_fn() -> ! { + // TODO: change this once the algorithms are verified + //unsafe {core::hint::unreachable_unchecked()} + ::abort() +} + +// The `B` extension on RISC-V determines if a CLZ assembly instruction exists +#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] +const USE_LZ: bool = cfg!(target_feature = "b"); + +#[cfg(target_arch = "arm")] +const USE_LZ: bool = if cfg!(target_feature = "thumb-mode") { + // ARM thumb targets have CLZ instructions if the instruction set of ARMv6T2 is supported. This + // is needed to successfully differentiate between targets like `thumbv8.base` and + // `thumbv8.main`. + cfg!(target_feature = "v6t2") +} else { + // Regular ARM targets have CLZ instructions if the ARMv5TE instruction set is supported. + // Technically, ARMv5T was the first to have CLZ, but the "v5t" target feature does not seem to + // work. + cfg!(target_feature = "v5te") +}; + +// All other targets Rust supports have CLZ instructions +#[cfg(not(any(target_arch = "arm", target_arch = "riscv32", target_arch = "riscv64")))] +const USE_LZ: bool = true; + +impl_normalization_shift!( + u32_normalization_shift, + USE_LZ, + 32, + u32, + i32, + allow(dead_code) +); +impl_normalization_shift!( + u64_normalization_shift, + USE_LZ, + 64, + u64, + i64, + allow(dead_code) +); + +/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. +/// `checked_div` and `checked_rem` are used to avoid bringing in panic function +/// dependencies. +#[inline] +fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { + if let Some(quo) = duo.checked_div(div) { + if let Some(rem) = duo.checked_rem(div) { + return (quo, rem); + } + } + zero_div_fn() +} + +// Whether `trifecta` or `delegate` is faster for 128 bit division depends on the speed at which a +// microarchitecture can multiply and divide. We decide to be optimistic and assume `trifecta` is +// faster if the target pointer width is at least 64. +#[cfg(all( + not(all(feature = "asm", target_arch = "x86_64")), + not(any(target_pointer_width = "16", target_pointer_width = "32")) +))] +impl_trifecta!( + u128_div_rem, + i128_div_rem, + zero_div_fn, + u64_by_u64_div_rem, + 32, + u32, + u64, + u128, + i128,; +); + +// If the pointer width less than 64, then the target architecture almost certainly does not have +// the fast 64 to 128 bit widening multiplication needed for `trifecta` to be faster. +#[cfg(all( + not(all(feature = "asm", target_arch = "x86_64")), + any(target_pointer_width = "16", target_pointer_width = "32") +))] +impl_delegate!( + u128_div_rem, + i128_div_rem, + zero_div_fn, + u64_normalization_shift, + u64_by_u64_div_rem, + 32, + u32, + u64, + u128, + i128,; +); + +/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. +/// +/// # Safety +/// +/// If the quotient does not fit in a `u64`, a floating point exception occurs. +/// If `div == 0`, then a division by zero exception occurs. +#[cfg(all(feature = "asm", target_arch = "x86_64"))] +#[inline] +unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { + let duo_lo = duo as u64; + let duo_hi = (duo >> 64) as u64; + let quo: u64; + let rem: u64; + unsafe { + // divides the combined registers rdx:rax (`duo` is split into two 64 bit parts to do this) + // by `div`. The quotient is stored in rax and the remainder in rdx. + asm!( + "div {0}", + in(reg) div, + inlateout("rax") duo_lo => quo, + inlateout("rdx") duo_hi => rem, + options(pure, nomem, nostack) + ); + } + (quo, rem) +} + +// use `asymmetric` instead of `trifecta` on x86_64 +#[cfg(all(feature = "asm", target_arch = "x86_64"))] +impl_asymmetric!( + u128_div_rem, + i128_div_rem, + zero_div_fn, + u64_by_u64_div_rem, + u128_by_u64_div_rem, + 32, + u32, + u64, + u128, + i128,; +); + +/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. +/// `checked_div` and `checked_rem` are used to avoid bringing in panic function +/// dependencies. +#[inline] +#[allow(dead_code)] +fn u32_by_u32_div_rem(duo: u32, div: u32) -> (u32, u32) { + if let Some(quo) = duo.checked_div(div) { + if let Some(rem) = duo.checked_rem(div) { + return (quo, rem); + } + } + zero_div_fn() +} + +// When not on x86 and the pointer width is not 64, use `delegate` since the division size is larger +// than register size. +#[cfg(all( + not(all(feature = "asm", target_arch = "x86")), + not(target_pointer_width = "64") +))] +impl_delegate!( + u64_div_rem, + i64_div_rem, + zero_div_fn, + u32_normalization_shift, + u32_by_u32_div_rem, + 16, + u16, + u32, + u64, + i64,; +); + +// When not on x86 and the pointer width is 64, use `binary_long`. +#[cfg(all( + not(all(feature = "asm", target_arch = "x86")), + target_pointer_width = "64" +))] +impl_binary_long!( + u64_div_rem, + i64_div_rem, + zero_div_fn, + u64_normalization_shift, + 64, + u64, + i64,; +); + +/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. +/// +/// # Safety +/// +/// If the quotient does not fit in a `u32`, a floating point exception occurs. +/// If `div == 0`, then a division by zero exception occurs. +#[cfg(all(feature = "asm", target_arch = "x86"))] +#[inline] +unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { + let duo_lo = duo as u32; + let duo_hi = (duo >> 32) as u32; + let quo: u32; + let rem: u32; + unsafe { + // divides the combined registers rdx:rax (`duo` is split into two 32 bit parts to do this) + // by `div`. The quotient is stored in rax and the remainder in rdx. + asm!( + "div {0}", + in(reg) div, + inlateout("rax") duo_lo => quo, + inlateout("rdx") duo_hi => rem, + options(pure, nomem, nostack) + ); + } + (quo, rem) +} + +// use `asymmetric` instead of `delegate` on x86 +#[cfg(all(feature = "asm", target_arch = "x86"))] +impl_asymmetric!( + u64_div_rem, + i64_div_rem, + zero_div_fn, + u32_by_u32_div_rem, + u64_by_u32_div_rem, + 16, + u16, + u32, + u64, + i64,; +); + +// 32 bits is the smallest division used by `compiler-builtins`, so we end with binary long division +impl_binary_long!( + u32_div_rem, + i32_div_rem, + zero_div_fn, + u32_normalization_shift, + 32, + u32, + i32,; +); diff --git a/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs b/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs new file mode 100644 index 00000000000..33348b37361 --- /dev/null +++ b/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs @@ -0,0 +1,106 @@ +/// Creates a function used by some division algorithms to compute the "normalization shift". +#[macro_export] +macro_rules! impl_normalization_shift { + ( + $name:ident, // name of the normalization shift function + // boolean for if `$uX::leading_zeros` should be used (if an architecture does not have a + // hardware instruction for `usize::leading_zeros`, then this should be `true`) + $use_lz:ident, + $n:tt, // the number of bits in a $iX or $uX + $uX:ident, // unsigned integer type for the inputs of `$name` + $iX:ident, // signed integer type for the inputs of `$name` + $($unsigned_attr:meta),* // attributes for the function + ) => { + /// Finds the shift left that the divisor `div` would need to be normalized for a binary + /// long division step with the dividend `duo`. NOTE: This function assumes that these edge + /// cases have been handled before reaching it: + /// ` + /// if div == 0 { + /// panic!("attempt to divide by zero") + /// } + /// if duo < div { + /// return (0, duo) + /// } + /// ` + /// + /// Normalization is defined as (where `shl` is the output of this function): + /// ` + /// if duo.leading_zeros() != (div << shl).leading_zeros() { + /// // If the most significant bits of `duo` and `div << shl` are not in the same place, + /// // then `div << shl` has one more leading zero than `duo`. + /// assert_eq!(duo.leading_zeros() + 1, (div << shl).leading_zeros()); + /// // Also, `2*(div << shl)` is not more than `duo` (otherwise the first division step + /// // would not be able to clear the msb of `duo`) + /// assert!(duo < (div << (shl + 1))); + /// } + /// if full_normalization { + /// // Some algorithms do not need "full" normalization, which means that `duo` is + /// // larger than `div << shl` when the most significant bits are aligned. + /// assert!((div << shl) <= duo); + /// } + /// ` + /// + /// Note: If the software bisection algorithm is being used in this function, it happens + /// that full normalization always occurs, so be careful that new algorithms are not + /// invisibly depending on this invariant when `full_normalization` is set to `false`. + $( + #[$unsigned_attr] + )* + fn $name(duo: $uX, div: $uX, full_normalization: bool) -> usize { + // We have to find the leading zeros of `div` to know where its msb (most significant + // set bit) is to even begin binary long division. It is also good to know where the msb + // of `duo` is so that useful work can be started instead of shifting `div` for all + // possible quotients (many division steps are wasted if `duo.leading_zeros()` is large + // and `div` starts out being shifted all the way to the msb). Aligning the msbs of + // `div` and `duo` could be done by shifting `div` left by + // `div.leading_zeros() - duo.leading_zeros()`, but some CPUs without division hardware + // also do not have single instructions for calculating `leading_zeros`. Instead of + // software doing two bisections to find the two `leading_zeros`, we do one bisection to + // find `div.leading_zeros() - duo.leading_zeros()` without actually knowing either of + // the leading zeros values. + + let mut shl: usize; + if $use_lz { + shl = (div.leading_zeros() - duo.leading_zeros()) as usize; + if full_normalization { + if duo < (div << shl) { + // when the msb of `duo` and `div` are aligned, the resulting `div` may be + // larger than `duo`, so we decrease the shift by 1. + shl -= 1; + } + } + } else { + let mut test = duo; + shl = 0usize; + let mut lvl = $n >> 1; + loop { + let tmp = test >> lvl; + // It happens that a final `duo < (div << shl)` check is not needed, because the + // `div <= tmp` check insures that the msb of `test` never passes the msb of + // `div`, and any set bits shifted off the end of `test` would still keep + // `div <= tmp` true. + if div <= tmp { + test = tmp; + shl += lvl; + } + // narrow down bisection + lvl >>= 1; + if lvl == 0 { + break + } + } + } + // tests the invariants that should hold before beginning binary long division + /* + if full_normalization { + assert!((div << shl) <= duo); + } + if duo.leading_zeros() != (div << shl).leading_zeros() { + assert_eq!(duo.leading_zeros() + 1, (div << shl).leading_zeros()); + assert!(duo < (div << (shl + 1))); + } + */ + shl + } + } +} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs new file mode 100644 index 00000000000..e76516f3490 --- /dev/null +++ b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs @@ -0,0 +1,441 @@ +/// Creates unsigned and signed division functions optimized for division of integers with bitwidths +/// larger than the largest hardware integer division supported. These functions use large radix +/// division algorithms that require both fast division and very fast widening multiplication on the +/// target microarchitecture. Otherwise, `impl_delegate` should be used instead. +#[macro_export] +macro_rules! impl_trifecta { + ( + $unsigned_name:ident, // name of the unsigned division function + $signed_name:ident, // name of the signed division function + $zero_div_fn:ident, // function called when division by zero is attempted + $half_division:ident, // function for division of a $uX by a $uX + $n_h:expr, // the number of bits in $iH or $uH + $uH:ident, // unsigned integer with half the bit width of $uX + $uX:ident, // unsigned integer with half the bit width of $uD + $uD:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iD:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($unsigned_attr:meta),*; // attributes for the unsigned function + $($signed_attr:meta),* // attributes for the signed function + ) => { + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$unsigned_attr] + )* + pub fn $unsigned_name(duo: $uD, div: $uD) -> ($uD, $uD) { + // This is called the trifecta algorithm because it uses three main algorithms: short + // division for small divisors, the two possibility algorithm for large divisors, and an + // undersubtracting long division algorithm for intermediate cases. + + // This replicates `carrying_mul` (rust-lang rfc #2417). LLVM correctly optimizes this + // to use a widening multiply to 128 bits on the relevant architectures. + fn carrying_mul(lhs: $uX, rhs: $uX) -> ($uX, $uX) { + let tmp = (lhs as $uD).wrapping_mul(rhs as $uD); + (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) + } + fn carrying_mul_add(lhs: $uX, mul: $uX, add: $uX) -> ($uX, $uX) { + let tmp = (lhs as $uD).wrapping_mul(mul as $uD).wrapping_add(add as $uD); + (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) + } + + // the number of bits in a $uX + let n = $n_h * 2; + + if div == 0 { + $zero_div_fn() + } + + // Trying to use a normalization shift function will cause inelegancies in the code and + // inefficiencies for architectures with a native count leading zeros instruction. The + // undersubtracting algorithm needs both values (keeping the original `div_lz` but + // updating `duo_lz` multiple times), so we assume hardware support for fast + // `leading_zeros` calculation. + let div_lz = div.leading_zeros(); + let mut duo_lz = duo.leading_zeros(); + + // the possible ranges of `duo` and `div` at this point: + // `0 <= duo < 2^n_d` + // `1 <= div < 2^n_d` + + // quotient is 0 or 1 branch + if div_lz <= duo_lz { + // The quotient cannot be more than 1. The highest set bit of `duo` needs to be at + // least one place higher than `div` for the quotient to be more than 1. + if duo >= div { + return (1, duo - div) + } else { + return (0, duo) + } + } + + // `_sb` is the number of significant bits (from the ones place to the highest set bit) + // `{2, 2^div_sb} <= duo < 2^n_d` + // `1 <= div < {2^duo_sb, 2^(n_d - 1)}` + // smaller division branch + if duo_lz >= n { + // `duo < 2^n` so it will fit in a $uX. `div` will also fit in a $uX (because of the + // `div_lz <= duo_lz` branch) so no numerical error. + let (quo, rem) = $half_division(duo as $uX, div as $uX); + return ( + quo as $uD, + rem as $uD + ) + } + + // `{2^n, 2^div_sb} <= duo < 2^n_d` + // `1 <= div < {2^duo_sb, 2^(n_d - 1)}` + // short division branch + if div_lz >= (n + $n_h) { + // `1 <= div < {2^duo_sb, 2^n_h}` + + // It is barely possible to improve the performance of this by calculating the + // reciprocal and removing one `$half_division`, but only if the CPU can do fast + // multiplications in parallel. Other reciprocal based methods can remove two + // `$half_division`s, but have multiplications that cannot be done in parallel and + // reduce performance. I have decided to use this trivial short division method and + // rely on the CPU having quick divisions. + + let duo_hi = (duo >> n) as $uX; + let div_0 = div as $uH as $uX; + let (quo_hi, rem_3) = $half_division(duo_hi, div_0); + + let duo_mid = + ((duo >> $n_h) as $uH as $uX) + | (rem_3 << $n_h); + let (quo_1, rem_2) = $half_division(duo_mid, div_0); + + let duo_lo = + (duo as $uH as $uX) + | (rem_2 << $n_h); + let (quo_0, rem_1) = $half_division(duo_lo, div_0); + + return ( + (quo_0 as $uD) + | ((quo_1 as $uD) << $n_h) + | ((quo_hi as $uD) << n), + rem_1 as $uD + ) + } + + // relative leading significant bits, cannot overflow because of above branches + let lz_diff = div_lz - duo_lz; + + // `{2^n, 2^div_sb} <= duo < 2^n_d` + // `2^n_h <= div < {2^duo_sb, 2^(n_d - 1)}` + // `mul` or `mul - 1` branch + if lz_diff < $n_h { + // Two possibility division algorithm + + // The most significant bits of `duo` and `div` are within `$n_h` bits of each + // other. If we take the `n` most significant bits of `duo` and divide them by the + // corresponding bits in `div`, it produces a quotient value `quo`. It happens that + // `quo` or `quo - 1` will always be the correct quotient for the whole number. In + // other words, the bits less significant than the `n` most significant bits of + // `duo` and `div` can only influence the quotient to be one of two values. + // Because there are only two possibilities, there only needs to be one `$uH` sized + // division, a `$uH` by `$uD` multiplication, and only one branch with a few simple + // operations. + // + // Proof that the true quotient can only be `quo` or `quo - 1`. + // All `/` operators here are floored divisions. + // + // `shift` is the number of bits not in the higher `n` significant bits of `duo`. + // (definitions) + // 0. shift = n - duo_lz + // 1. duo_sig_n == duo / 2^shift + // 2. div_sig_n == div / 2^shift + // 3. quo == duo_sig_n / div_sig_n + // + // + // We are trying to find the true quotient, `true_quo`. + // 4. true_quo = duo / div. (definition) + // + // This is true because of the bits that are cut off during the bit shift. + // 5. duo_sig_n * 2^shift <= duo < (duo_sig_n + 1) * 2^shift. + // 6. div_sig_n * 2^shift <= div < (div_sig_n + 1) * 2^shift. + // + // Dividing each bound of (5) by each bound of (6) gives 4 possibilities for what + // `true_quo == duo / div` is bounded by: + // (duo_sig_n * 2^shift) / (div_sig_n * 2^shift) + // (duo_sig_n * 2^shift) / ((div_sig_n + 1) * 2^shift) + // ((duo_sig_n + 1) * 2^shift) / (div_sig_n * 2^shift) + // ((duo_sig_n + 1) * 2^shift) / ((div_sig_n + 1) * 2^shift) + // + // Simplifying each of these four: + // duo_sig_n / div_sig_n + // duo_sig_n / (div_sig_n + 1) + // (duo_sig_n + 1) / div_sig_n + // (duo_sig_n + 1) / (div_sig_n + 1) + // + // Taking the smallest and the largest of these as the low and high bounds + // and replacing `duo / div` with `true_quo`: + // 7. duo_sig_n / (div_sig_n + 1) <= true_quo < (duo_sig_n + 1) / div_sig_n + // + // The `lz_diff < n_h` conditional on this branch makes sure that `div_sig_n` is at + // least `2^n_h`, and the `div_lz <= duo_lz` branch makes sure that the highest bit + // of `div_sig_n` is not the `2^(n - 1)` bit. + // 8. `2^(n - 1) <= duo_sig_n < 2^n` + // 9. `2^n_h <= div_sig_n < 2^(n - 1)` + // + // We want to prove that either + // `(duo_sig_n + 1) / div_sig_n == duo_sig_n / (div_sig_n + 1)` or that + // `(duo_sig_n + 1) / div_sig_n == duo_sig_n / (div_sig_n + 1) + 1`. + // + // We also want to prove that `quo` is one of these: + // `duo_sig_n / div_sig_n == duo_sig_n / (div_sig_n + 1)` or + // `duo_sig_n / div_sig_n == (duo_sig_n + 1) / div_sig_n`. + // + // When 1 is added to the numerator of `duo_sig_n / div_sig_n` to produce + // `(duo_sig_n + 1) / div_sig_n`, it is not possible that the value increases by + // more than 1 with floored integer arithmetic and `div_sig_n != 0`. Consider + // `x/y + 1 < (x + 1)/y` <=> `x/y + 1 < x/y + 1/y` <=> `1 < 1/y` <=> `y < 1`. + // `div_sig_n` is a nonzero integer. Thus, + // 10. `duo_sig_n / div_sig_n == (duo_sig_n + 1) / div_sig_n` or + // `(duo_sig_n / div_sig_n) + 1 == (duo_sig_n + 1) / div_sig_n. + // + // When 1 is added to the denominator of `duo_sig_n / div_sig_n` to produce + // `duo_sig_n / (div_sig_n + 1)`, it is not possible that the value decreases by + // more than 1 with the bounds (8) and (9). Consider `x/y - 1 <= x/(y + 1)` <=> + // `(x - y)/y < x/(y + 1)` <=> `(y + 1)*(x - y) < x*y` <=> `x*y - y*y + x - y < x*y` + // <=> `x < y*y + y`. The smallest value of `div_sig_n` is `2^n_h` and the largest + // value of `duo_sig_n` is `2^n - 1`. Substituting reveals `2^n - 1 < 2^n + 2^n_h`. + // Thus, + // 11. `duo_sig_n / div_sig_n == duo_sig_n / (div_sig_n + 1)` or + // `(duo_sig_n / div_sig_n) - 1` == duo_sig_n / (div_sig_n + 1)` + // + // Combining both (10) and (11), we know that + // `quo - 1 <= duo_sig_n / (div_sig_n + 1) <= true_quo + // < (duo_sig_n + 1) / div_sig_n <= quo + 1` and therefore: + // 12. quo - 1 <= true_quo < quo + 1 + // + // In a lot of division algorithms using smaller divisions to construct a larger + // division, we often encounter a situation where the approximate `quo` value + // calculated from a smaller division is multiple increments away from the true + // `quo` value. In those algorithms, multiple correction steps have to be applied. + // Those correction steps may need more multiplications to test `duo - (quo*div)` + // again. Because of the fact that our `quo` can only be one of two values, we can + // see if `duo - (quo*div)` overflows. If it did overflow, then we know that we have + // the larger of the two values (since the true quotient is unique, and any larger + // quotient will cause `duo - (quo*div)` to be negative). Also because there is only + // one correction needed, we can calculate the remainder `duo - (true_quo*div) == + // duo - ((quo - 1)*div) == duo - (quo*div - div) == duo + div - quo*div`. + // If `duo - (quo*div)` did not overflow, then we have the correct answer. + let shift = n - duo_lz; + let duo_sig_n = (duo >> shift) as $uX; + let div_sig_n = (div >> shift) as $uX; + let quo = $half_division(duo_sig_n, div_sig_n).0; + + // The larger `quo` value can overflow `$uD` in the right circumstances. This is a + // manual `carrying_mul_add` with overflow checking. + let div_lo = div as $uX; + let div_hi = (div >> n) as $uX; + let (tmp_lo, carry) = carrying_mul(quo, div_lo); + let (tmp_hi, overflow) = carrying_mul_add(quo, div_hi, carry); + let tmp = (tmp_lo as $uD) | ((tmp_hi as $uD) << n); + if (overflow != 0) || (duo < tmp) { + return ( + (quo - 1) as $uD, + // Both the addition and subtraction can overflow, but when combined end up + // as a correct positive number. + duo.wrapping_add(div).wrapping_sub(tmp) + ) + } else { + return ( + quo as $uD, + duo - tmp + ) + } + } + + // Undersubtracting long division algorithm. + // Instead of clearing a minimum of 1 bit from `duo` per iteration via binary long + // division, `n_h - 1` bits are cleared per iteration with this algorithm. It is a more + // complicated version of regular long division. Most integer division algorithms tend + // to guess a part of the quotient, and may have a larger quotient than the true + // quotient (which when multiplied by `div` will "oversubtract" the original dividend). + // They then check if the quotient was in fact too large and then have to correct it. + // This long division algorithm has been carefully constructed to always underguess the + // quotient by slim margins. This allows different subalgorithms to be blindly jumped to + // without needing an extra correction step. + // + // The only problem is that this subalgorithm will not work for many ranges of `duo` and + // `div`. Fortunately, the short division, two possibility algorithm, and other simple + // cases happen to exactly fill these gaps. + // + // For an example, consider the division of 76543210 by 213 and assume that `n_h` is + // equal to two decimal digits (note: we are working with base 10 here for readability). + // The first `sig_n_h` part of the divisor (21) is taken and is incremented by 1 to + // prevent oversubtraction. We also record the number of extra places not a part of + // the `sig_n` or `sig_n_h` parts. + // + // sig_n_h == 2 digits, sig_n == 4 digits + // + // vvvv <- `duo_sig_n` + // 76543210 + // ^^^^ <- extra places in duo, `duo_extra == 4` + // + // vv <- `div_sig_n_h` + // 213 + // ^ <- extra places in div, `div_extra == 1` + // + // The difference in extra places, `duo_extra - div_extra == extra_shl == 3`, is used + // for shifting partial sums in the long division. + // + // In the first step, the first `sig_n` part of duo (7654) is divided by + // `div_sig_n_h_add_1` (22), which results in a partial quotient of 347. This is + // multiplied by the whole divisor to make 73911, which is shifted left by `extra_shl` + // and subtracted from duo. The partial quotient is also shifted left by `extra_shl` to + // be added to `quo`. + // + // 347 + // ________ + // |76543210 + // -73911 + // 2632210 + // + // Variables dependent on duo have to be updated: + // + // vvvv <- `duo_sig_n == 2632` + // 2632210 + // ^^^ <- `duo_extra == 3` + // + // `extra_shl == 2` + // + // Two more steps are taken after this and then duo fits into `n` bits, and then a final + // normal long division step is made. The partial quotients are all progressively added + // to each other in the actual algorithm, but here I have left them all in a tower that + // can be added together to produce the quotient, 359357. + // + // 14 + // 443 + // 119 + // 347 + // ________ + // |76543210 + // -73911 + // 2632210 + // -25347 + // 97510 + // -94359 + // 3151 + // -2982 + // 169 <- the remainder + + let mut duo = duo; + let mut quo: $uD = 0; + + // The number of lesser significant bits not a part of `div_sig_n_h` + let div_extra = (n + $n_h) - div_lz; + + // The most significant `n_h` bits of div + let div_sig_n_h = (div >> div_extra) as $uH; + + // This needs to be a `$uX` in case of overflow from the increment + let div_sig_n_h_add1 = (div_sig_n_h as $uX) + 1; + + // `{2^n, 2^(div_sb + n_h)} <= duo < 2^n_d` + // `2^n_h <= div < {2^(duo_sb - n_h), 2^n}` + loop { + // The number of lesser significant bits not a part of `duo_sig_n` + let duo_extra = n - duo_lz; + + // The most significant `n` bits of `duo` + let duo_sig_n = (duo >> duo_extra) as $uX; + + // the two possibility algorithm requires that the difference between msbs is less + // than `n_h`, so the comparison is `<=` here. + if div_extra <= duo_extra { + // Undersubtracting long division step + let quo_part = $half_division(duo_sig_n, div_sig_n_h_add1).0 as $uD; + let extra_shl = duo_extra - div_extra; + + // Addition to the quotient. + quo += (quo_part << extra_shl); + + // Subtraction from `duo`. At least `n_h - 1` bits are cleared from `duo` here. + duo -= (div.wrapping_mul(quo_part) << extra_shl); + } else { + // Two possibility algorithm + let shift = n - duo_lz; + let duo_sig_n = (duo >> shift) as $uX; + let div_sig_n = (div >> shift) as $uX; + let quo_part = $half_division(duo_sig_n, div_sig_n).0; + let div_lo = div as $uX; + let div_hi = (div >> n) as $uX; + + let (tmp_lo, carry) = carrying_mul(quo_part, div_lo); + // The undersubtracting long division algorithm has already run once, so + // overflow beyond `$uD` bits is not possible here + let (tmp_hi, _) = carrying_mul_add(quo_part, div_hi, carry); + let tmp = (tmp_lo as $uD) | ((tmp_hi as $uD) << n); + + if duo < tmp { + return ( + quo + ((quo_part - 1) as $uD), + duo.wrapping_add(div).wrapping_sub(tmp) + ) + } else { + return ( + quo + (quo_part as $uD), + duo - tmp + ) + } + } + + duo_lz = duo.leading_zeros(); + + if div_lz <= duo_lz { + // quotient can have 0 or 1 added to it + if div <= duo { + return ( + quo + 1, + duo - div + ) + } else { + return ( + quo, + duo + ) + } + } + + // This can only happen if `div_sd < n` (because of previous "quo = 0 or 1" + // branches), but it is not worth it to unroll further. + if n <= duo_lz { + // simple division and addition + let tmp = $half_division(duo as $uX, div as $uX); + return ( + quo + (tmp.0 as $uD), + tmp.1 as $uD + ) + } + } + } + + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$signed_attr] + )* + pub fn $signed_name(duo: $iD, div: $iD) -> ($iD, $iD) { + match (duo < 0, div < 0) { + (false, false) => { + let t = $unsigned_name(duo as $uD, div as $uD); + (t.0 as $iD, t.1 as $iD) + }, + (true, false) => { + let t = $unsigned_name(duo.wrapping_neg() as $uD, div as $uD); + ((t.0 as $iD).wrapping_neg(), (t.1 as $iD).wrapping_neg()) + }, + (false, true) => { + let t = $unsigned_name(duo as $uD, div.wrapping_neg() as $uD); + ((t.0 as $iD).wrapping_neg(), t.1 as $iD) + }, + (true, true) => { + let t = $unsigned_name(duo.wrapping_neg() as $uD, div.wrapping_neg() as $uD); + (t.0 as $iD, (t.1 as $iD).wrapping_neg()) + }, + } + } + } +} diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 49151594964..3cd9be93cb1 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,4 +1,4 @@ -use int::{Int, LargeInt}; +use int::specialized_div_rem::*; intrinsics! { #[maybe_use_optimized_c_shim] diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 34397e0d256..cbd23850b3f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] +#![cfg_attr(feature = "asm", feature(asm))] #![feature(abi_unadjusted)] #![feature(llvm_asm)] #![feature(global_asm)] diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 61282af0bf5..5c3df79619e 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -28,7 +28,8 @@ utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japa utest-macros = { git = "https://github.com/japaric/utest" } [features] +default = ["asm", "mangled-names"] +asm = ["compiler_builtins/asm"] c = ["compiler_builtins/c"] mem = ["compiler_builtins/mem"] mangled-names = ["compiler_builtins/mangled-names"] -default = ["mangled-names"] diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs new file mode 100644 index 00000000000..2a154f5eb7e --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -0,0 +1,143 @@ +use rand_xoshiro::rand_core::{RngCore, SeedableRng}; +use rand_xoshiro::Xoshiro128StarStar; + +use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divti3, __modti3}; +use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4}; + +// because `__divmodti4` does not exist, we synthesize it +fn __divmodti4(a: i128, b: i128, rem: &mut i128) -> i128 { + *rem = __modti3(a, b); + __divti3(a, b) +} + +/// Creates intensive test functions for division functions of a certain size +macro_rules! test { + ( + $n:expr, // the number of bits in a $iX or $uX + $uX:ident, // unsigned integer that will be shifted + $iX:ident, // signed version of $uX + $test_name:ident, // name of the test function + $unsigned_name:ident, // unsigned division function + $signed_name:ident // signed division function + ) => { + #[test] + fn $test_name() { + fn assert_invariants(lhs: $uX, rhs: $uX) { + let rem: &mut $uX = &mut 0; + let quo: $uX = $unsigned_name(lhs, rhs, Some(rem)); + let rem = *rem; + if rhs <= rem || (lhs != rhs.wrapping_mul(quo).wrapping_add(rem)) { + panic!( + "unsigned division function failed with lhs:{} rhs:{} \ + expected:({}, {}) found:({}, {})", + lhs, + rhs, + lhs.wrapping_div(rhs), + lhs.wrapping_rem(rhs), + quo, + rem + ); + } + + // test the signed division function also + let lhs = lhs as $iX; + let rhs = rhs as $iX; + let mut rem: $iX = 0; + let quo: $iX = $signed_name(lhs, rhs, &mut rem); + // We cannot just test that + // `lhs == rhs.wrapping_mul(quo).wrapping_add(rem)`, but also + // need to make sure the remainder isn't larger than the divisor + // and has the correct sign. + let incorrect_rem = if rem == 0 { + false + } else if rhs == $iX::MIN { + // `rhs.wrapping_abs()` would overflow, so handle this case + // separately. + (lhs.is_negative() != rem.is_negative()) || (rem == $iX::MIN) + } else { + (lhs.is_negative() != rem.is_negative()) + || (rhs.wrapping_abs() <= rem.wrapping_abs()) + }; + if incorrect_rem || lhs != rhs.wrapping_mul(quo).wrapping_add(rem) { + panic!( + "signed division function failed with lhs:{} rhs:{} \ + expected:({}, {}) found:({}, {})", + lhs, + rhs, + lhs.wrapping_div(rhs), + lhs.wrapping_rem(rhs), + quo, + rem + ); + } + } + + // Specially designed random fuzzer + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut lhs: $uX = 0; + let mut rhs: $uX = 0; + // all ones constant + let ones: $uX = !0; + // Alternating ones and zeros (e.x. 0b1010101010101010). This catches second-order + // problems that might occur for algorithms with two modes of operation (potentially + // there is some invariant that can be broken for large `duo` and maintained via + // alternating between modes, breaking the algorithm when it reaches the end). + let mut alt_ones: $uX = 1; + for _ in 0..($n / 2) { + alt_ones <<= 2; + alt_ones |= 1; + } + // creates a mask for indexing the bits of the type + let bit_indexing_mask = $n - 1; + for _ in 0..1_000_000 { + // Randomly OR, AND, and XOR randomly sized and shifted continuous strings of + // ones with `lhs` and `rhs`. This results in excellent fuzzing entropy such as: + // lhs:10101010111101000000000100101010 rhs: 1010101010000000000000001000001 + // lhs:10101010111101000000000101001010 rhs: 1010101010101010101010100010100 + // lhs:10101010111101000000000101001010 rhs:11101010110101010101010100001110 + // lhs:10101010000000000000000001001010 rhs:10100010100000000000000000001010 + // lhs:10101010000000000000000001001010 rhs: 10101010101010101000 + // lhs:10101010000000000000000001100000 rhs:11111111111101010101010101001111 + // lhs:10101010000000101010101011000000 rhs:11111111111101010101010100000111 + // lhs:10101010101010101010101011101010 rhs: 1010100000000000000 + // lhs:11111111110101101010101011010111 rhs: 1010100000000000000 + // The msb is set half of the time by the fuzzer, but `assert_invariants` tests + // both the signed and unsigned functions. + let r0: u32 = bit_indexing_mask & rng.next_u32(); + let r1: u32 = bit_indexing_mask & rng.next_u32(); + let mask = ones.wrapping_shr(r0).rotate_left(r1); + match rng.next_u32() % 8 { + 0 => lhs |= mask, + 1 => lhs &= mask, + // both 2 and 3 to make XORs as common as ORs and ANDs combined, otherwise + // the entropy gets destroyed too often + 2 | 3 => lhs ^= mask, + 4 => rhs |= mask, + 5 => rhs &= mask, + _ => rhs ^= mask, + } + // do the same for alternating ones and zeros + let r0: u32 = bit_indexing_mask & rng.next_u32(); + let r1: u32 = bit_indexing_mask & rng.next_u32(); + let mask = alt_ones.wrapping_shr(r0).rotate_left(r1); + match rng.next_u32() % 8 { + 0 => lhs |= mask, + 1 => lhs &= mask, + // both 2 and 3 to make XORs as common as ORs and ANDs combined, otherwise + // the entropy gets destroyed too often + 2 | 3 => lhs ^= mask, + 4 => rhs |= mask, + 5 => rhs &= mask, + _ => rhs ^= mask, + } + if rhs != 0 { + assert_invariants(lhs, rhs); + } + } + } + }; +} + +test!(32, u32, i32, div_rem_si4, __udivmodsi4, __divmodsi4); +test!(64, u64, i64, div_rem_di4, __udivmoddi4, __divmoddi4); +test!(128, u128, i128, div_rem_ti4, __udivmodti4, __divmodti4); -- cgit 1.4.1-3-g733a5 From 11ae780481cd42edd7d3b9189536b724b4cac8c8 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Tue, 21 Jul 2020 23:16:52 -0500 Subject: Change inlining to favor three underlying division functions --- .../src/int/specialized_div_rem/mod.rs | 35 +++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 5a034dcf10b..0304aa2e7da 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -113,6 +113,13 @@ fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { zero_div_fn() } +// `inline(never)` is placed on unsigned division functions so that there are just three division +// functions (`u32_div_rem`, `u64_div_rem`, and `u128_div_rem`) backing all `compiler-builtins` +// division functions. The signed functions like `i32_div_rem` will get inlined into the +// `compiler-builtins` signed division functions, so that they directly call the three division +// functions. Otherwise, LLVM may try to inline the unsigned division functions 4 times into the +// signed division functions, which results in an explosion in code size. + // Whether `trifecta` or `delegate` is faster for 128 bit division depends on the speed at which a // microarchitecture can multiply and divide. We decide to be optimistic and assume `trifecta` is // faster if the target pointer width is at least 64. @@ -129,7 +136,9 @@ impl_trifecta!( u32, u64, u128, - i128,; + i128, + inline(never); + inline ); // If the pointer width less than 64, then the target architecture almost certainly does not have @@ -148,7 +157,9 @@ impl_delegate!( u32, u64, u128, - i128,; + i128, + inline(never); + inline ); /// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. @@ -190,7 +201,9 @@ impl_asymmetric!( u32, u64, u128, - i128,; + i128, + inline(never); + inline ); /// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. @@ -223,7 +236,9 @@ impl_delegate!( u16, u32, u64, - i64,; + i64, + inline(never); + inline ); // When not on x86 and the pointer width is 64, use `binary_long`. @@ -238,7 +253,9 @@ impl_binary_long!( u64_normalization_shift, 64, u64, - i64,; + i64, + inline(never); + inline ); /// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. @@ -280,7 +297,9 @@ impl_asymmetric!( u16, u32, u64, - i64,; + i64, + inline(never); + inline ); // 32 bits is the smallest division used by `compiler-builtins`, so we end with binary long division @@ -291,5 +310,7 @@ impl_binary_long!( u32_normalization_shift, 32, u32, - i32,; + i32, + inline(never); + inline ); -- cgit 1.4.1-3-g733a5 From ffb386369b280fe3e19ae2f004ebb71e7d72f801 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 14 Aug 2020 15:28:48 -0500 Subject: Use unreachable_unchecked --- library/compiler-builtins/src/int/specialized_div_rem/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 0304aa2e7da..f7dc044fa27 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -57,9 +57,7 @@ mod asymmetric; /// impossible to reach by Rust users, unless `compiler-builtins` public division functions or /// `core/std::unchecked_div/rem` are directly used without a zero check in front. fn zero_div_fn() -> ! { - // TODO: change this once the algorithms are verified - //unsafe {core::hint::unreachable_unchecked()} - ::abort() + unsafe { core::hint::unreachable_unchecked() } } // The `B` extension on RISC-V determines if a CLZ assembly instruction exists -- cgit 1.4.1-3-g733a5 From 51e969665e94ca3dd5af04026ea110059e9633d0 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 23 Aug 2020 23:31:51 +0100 Subject: Fix CI url for compiler-rt source --- library/compiler-builtins/.github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 1237bc03267..e4bcc9c1052 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -88,8 +88,8 @@ jobs: - run: rustup component add llvm-tools-preview - name: Download compiler-rt reference sources run: | - curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/10.0-2020-02-05.tar.gz - tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-10.0-2020-02-05/compiler-rt + curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/10.0-2020-05-05.tar.gz + tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-10.0-2020-05-05/compiler-rt echo "##[set-env name=RUST_COMPILER_RT_ROOT]./compiler-rt" shell: bash -- cgit 1.4.1-3-g733a5 From 29791313f5a81f0d933c3a3a1be836e7b4922ca9 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Thu, 6 Aug 2020 10:59:15 +0200 Subject: add compiler-rt fallbacks on aarch64-musl --- library/compiler-builtins/build.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a3b722ab776..f948edba9eb 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -419,6 +419,18 @@ mod c { if target_os != "windows" { sources.extend(&[("__multc3", "multc3.c")]); } + + if target_env == "musl" { + sources.extend(&[ + ("__addtf3", "addtf3.c"), + ("__multf3", "multf3.c"), + ("__subtf3", "subtf3.c"), + ("__divtf3", "divtf3.c"), + ("__powitf2", "powitf2.c"), + ("__fe_getround", "fp_mode.c"), + ("__fe_raise_inexact", "fp_mode.c"), + ]); + } } if target_arch == "mips" { -- cgit 1.4.1-3-g733a5 From 9daf318bef7ff97a970ebc26613e6a29c8f748a9 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 24 Aug 2020 12:45:58 +0100 Subject: Bump to 0.1.33 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d4d1ad67d38..957fd7bebfc 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.32" +version = "0.1.33" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 29cfa6fba9b1b98868b6dd640b8d16fc8886a6cc Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 27 Aug 2020 17:49:46 +0100 Subject: Bump to 0.1.34 0.1.33 was published without the libm submodule --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 957fd7bebfc..60429681dbd 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.33" +version = "0.1.34" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From c9c145c6d732c1bd0632b29d327f5068c3c6d760 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 28 Aug 2020 01:35:29 +0100 Subject: Bump to 0.1.35 This time using the proper procedure for including libm. --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 60429681dbd..b4fbb0b1e93 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.34" +version = "0.1.35" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 92f068074323bf09c2bce05edab034de11fa1d76 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Sat, 29 Aug 2020 18:02:57 -0500 Subject: Add `__divmodti4` --- library/compiler-builtins/src/int/sdiv.rs | 9 ++++++++- library/compiler-builtins/testcrate/build.rs | 13 +++++++++++++ library/compiler-builtins/testcrate/tests/div_rem.rs | 8 +------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 57ef03cdaa5..3d0c3afc11d 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -54,5 +54,12 @@ intrinsics! { i128_div_rem(a, b).1 } - // LLVM does not currently have a `__divmodti4` function + // LLVM does not currently have a `__divmodti4` function, but GCC does + #[maybe_use_optimized_c_shim] + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __divmodti4(a: i128, b: i128, rem: &mut i128) -> i128 { + let quo_rem = i128_div_rem(a, b); + *rem = quo_rem.1; + quo_rem.0 + } } diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index e1d4cf9e818..656fd2d20b7 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -805,6 +805,19 @@ fn main() { (builtins::int::sdiv::__divmodsi4(a, b, &mut r), r) }", ); + gen( + |(a, b): (MyI128, MyI128)| { + if b.0 == 0 { + None + } else { + Some((a.0 / b.0, a.0 % b.0)) + } + }, + "{ + let mut r = 0; + (builtins::int::sdiv::__divmodti4(a, b, &mut r), r) + }", + ); gen( |(a, b): (MyI32, MyI32)| { if b.0 == 0 { diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index 2a154f5eb7e..199fa9db71c 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -1,15 +1,9 @@ use rand_xoshiro::rand_core::{RngCore, SeedableRng}; use rand_xoshiro::Xoshiro128StarStar; -use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divti3, __modti3}; +use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4}; -// because `__divmodti4` does not exist, we synthesize it -fn __divmodti4(a: i128, b: i128, rem: &mut i128) -> i128 { - *rem = __modti3(a, b); - __divti3(a, b) -} - /// Creates intensive test functions for division functions of a certain size macro_rules! test { ( -- cgit 1.4.1-3-g733a5 From 53b15eaba20b9fb573d343938c4547e5815b6d81 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 13 Sep 2020 20:47:25 +0100 Subject: Bump to 0.1.36 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 4ee76946592..9262bb6d64f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.35" +version = "0.1.36" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 1dfa14595ef13349d31891c805b9bca505a8d09d Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 2 Oct 2020 16:35:55 -0500 Subject: Remove unneeded code from asymmetric.rs Rebenchmarking this showed that perf changed for the worse only on really low end CPUs --- .../src/int/specialized_div_rem/asymmetric.rs | 105 ++++----------------- 1 file changed, 20 insertions(+), 85 deletions(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs index 861e9174267..16ab2baadea 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs @@ -25,20 +25,8 @@ macro_rules! impl_asymmetric { #[$unsigned_attr] )* pub fn $unsigned_name(duo: $uD, div: $uD) -> ($uD,$uD) { - fn carrying_mul(lhs: $uX, rhs: $uX) -> ($uX, $uX) { - let tmp = (lhs as $uD).wrapping_mul(rhs as $uD); - (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) - } - fn carrying_mul_add(lhs: $uX, mul: $uX, add: $uX) -> ($uX, $uX) { - let tmp = (lhs as $uD).wrapping_mul(mul as $uD).wrapping_add(add as $uD); - (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) - } - let n: u32 = $n_h * 2; - // Many of these subalgorithms are taken from trifecta.rs, see that for better - // documentation. - let duo_lo = duo as $uX; let duo_hi = (duo >> n) as $uX; let div_lo = div as $uX; @@ -51,30 +39,6 @@ macro_rules! impl_asymmetric { // `$uD` by `$uX` division with a quotient that will fit into a `$uX` let (quo, rem) = unsafe { $asymmetric_division(duo, div_lo) }; return (quo as $uD, rem as $uD) - } else if (div_lo >> $n_h) == 0 { - // Short division of $uD by a $uH. - - // Some x86_64 CPUs have bad division implementations that make specializing - // this case faster. - let div_0 = div_lo as $uH as $uX; - let (quo_hi, rem_3) = $half_division(duo_hi, div_0); - - let duo_mid = - ((duo >> $n_h) as $uH as $uX) - | (rem_3 << $n_h); - let (quo_1, rem_2) = $half_division(duo_mid, div_0); - - let duo_lo = - (duo as $uH as $uX) - | (rem_2 << $n_h); - let (quo_0, rem_1) = $half_division(duo_lo, div_0); - - return ( - (quo_0 as $uD) - | ((quo_1 as $uD) << $n_h) - | ((quo_hi as $uD) << n), - rem_1 as $uD - ) } else { // Short division using the $uD by $uX division let (quo_hi, rem_hi) = $half_division(duo_hi, div_lo); @@ -85,59 +49,30 @@ macro_rules! impl_asymmetric { } } - let duo_lz = duo_hi.leading_zeros(); + // This has been adapted from + // https://www.codeproject.com/tips/785014/uint-division-modulus which was in turn + // adapted from Hacker's Delight. This is similar to the two possibility algorithm + // in that it uses only more significant parts of `duo` and `div` to divide a large + // integer with a smaller division instruction. let div_lz = div_hi.leading_zeros(); - let rel_leading_sb = div_lz.wrapping_sub(duo_lz); - if rel_leading_sb < $n_h { - // Some x86_64 CPUs have bad hardware division implementations that make putting - // a two possibility algorithm here beneficial. We also avoid a full `$uD` - // multiplication. - let shift = n - duo_lz; - let duo_sig_n = (duo >> shift) as $uX; - let div_sig_n = (div >> shift) as $uX; - let quo = $half_division(duo_sig_n, div_sig_n).0; - let div_lo = div as $uX; - let div_hi = (div >> n) as $uX; - let (tmp_lo, carry) = carrying_mul(quo, div_lo); - let (tmp_hi, overflow) = carrying_mul_add(quo, div_hi, carry); - let tmp = (tmp_lo as $uD) | ((tmp_hi as $uD) << n); - if (overflow != 0) || (duo < tmp) { - return ( - (quo - 1) as $uD, - duo.wrapping_add(div).wrapping_sub(tmp) - ) - } else { - return ( - quo as $uD, - duo - tmp - ) - } - } else { - // This has been adapted from - // https://www.codeproject.com/tips/785014/uint-division-modulus which was in turn - // adapted from Hacker's Delight. This is similar to the two possibility algorithm - // in that it uses only more significant parts of `duo` and `div` to divide a large - // integer with a smaller division instruction. - - let div_extra = n - div_lz; - let div_sig_n = (div >> div_extra) as $uX; - let tmp = unsafe { - $asymmetric_division(duo >> 1, div_sig_n) - }; + let div_extra = n - div_lz; + let div_sig_n = (div >> div_extra) as $uX; + let tmp = unsafe { + $asymmetric_division(duo >> 1, div_sig_n) + }; - let mut quo = tmp.0 >> ((n - 1) - div_lz); - if quo != 0 { - quo -= 1; - } + let mut quo = tmp.0 >> ((n - 1) - div_lz); + if quo != 0 { + quo -= 1; + } - // Note that this is a full `$uD` multiplication being used here - let mut rem = duo - (quo as $uD).wrapping_mul(div); - if div <= rem { - quo += 1; - rem -= div; - } - return (quo as $uD, rem) + // Note that this is a full `$uD` multiplication being used here + let mut rem = duo - (quo as $uD).wrapping_mul(div); + if div <= rem { + quo += 1; + rem -= div; } + return (quo as $uD, rem) } /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a -- cgit 1.4.1-3-g733a5 From 756a9dea00035d81b44956e552df978b307dbc97 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 2 Oct 2020 22:04:05 -0500 Subject: Construct signed division functions differently --- library/compiler-builtins/src/int/sdiv.rs | 207 +++++++++++++++------ .../src/int/specialized_div_rem/asymmetric.rs | 53 +----- .../src/int/specialized_div_rem/binary_long.rs | 64 +------ .../src/int/specialized_div_rem/delegate.rs | 76 ++------ .../src/int/specialized_div_rem/mod.rs | 45 +---- .../src/int/specialized_div_rem/trifecta.rs | 105 +++-------- 6 files changed, 221 insertions(+), 329 deletions(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 3d0c3afc11d..e1e3f33bbd0 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,65 +1,166 @@ -use int::specialized_div_rem::*; +use int::udiv::*; -intrinsics! { - #[maybe_use_optimized_c_shim] - #[arm_aeabi_alias = __aeabi_idiv] - /// Returns `n / d` - pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { - i32_div_rem(a, b).0 - } - - #[maybe_use_optimized_c_shim] - /// Returns `n % d` - pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { - i32_div_rem(a, b).1 - } - - #[maybe_use_optimized_c_shim] - /// Returns `n / d` and sets `*rem = n % d` - pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { - let quo_rem = i32_div_rem(a, b); - *rem = quo_rem.1; - quo_rem.0 +macro_rules! sdivmod { + ( + $unsigned_fn:ident, // name of the unsigned division function + $signed_fn:ident, // name of the signed division function + $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($attr:tt),* // attributes + ) => { + intrinsics! { + $( + #[$attr] + )* + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn $signed_fn(a: $iX, b: $iX, rem: &mut $iX) -> $iX { + let a_neg = a < 0; + let b_neg = b < 0; + let mut a = a; + let mut b = b; + if a_neg { + a = a.wrapping_neg(); + } + if b_neg { + b = b.wrapping_neg(); + } + let mut r = *rem as $uX; + let t = $unsigned_fn(a as $uX, b as $uX, Some(&mut r)) as $iX; + let mut r = r as $iX; + if a_neg { + r = r.wrapping_neg(); + } + *rem = r; + if a_neg != b_neg { + t.wrapping_neg() + } else { + t + } + } + } } +} - #[maybe_use_optimized_c_shim] - /// Returns `n / d` - pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 { - i64_div_rem(a, b).0 +macro_rules! sdiv { + ( + $unsigned_fn:ident, // name of the unsigned division function + $signed_fn:ident, // name of the signed division function + $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($attr:tt),* // attributes + ) => { + intrinsics! { + $( + #[$attr] + )* + /// Returns `n / d` + pub extern "C" fn $signed_fn(a: $iX, b: $iX) -> $iX { + let a_neg = a < 0; + let b_neg = b < 0; + let mut a = a; + let mut b = b; + if a_neg { + a = a.wrapping_neg(); + } + if b_neg { + b = b.wrapping_neg(); + } + let t = $unsigned_fn(a as $uX, b as $uX) as $iX; + if a_neg != b_neg { + t.wrapping_neg() + } else { + t + } + } + } } +} - #[maybe_use_optimized_c_shim] - /// Returns `n % d` - pub extern "C" fn __moddi3(a: i64, b: i64) -> i64 { - i64_div_rem(a, b).1 +macro_rules! smod { + ( + $unsigned_fn:ident, // name of the unsigned division function + $signed_fn:ident, // name of the signed division function + $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($attr:tt),* // attributes + ) => { + intrinsics! { + $( + #[$attr] + )* + /// Returns `n % d` + pub extern "C" fn $signed_fn(a: $iX, b: $iX) -> $iX { + let a_neg = a < 0; + let b_neg = b < 0; + let mut a = a; + let mut b = b; + if a_neg { + a = a.wrapping_neg(); + } + if b_neg { + b = b.wrapping_neg(); + } + let r = $unsigned_fn(a as $uX, b as $uX) as $iX; + if a_neg { + r.wrapping_neg() + } else { + r + } + } + } } +} +sdivmod!( + __udivmodsi4, + __divmodsi4, + u32, + i32, + maybe_use_optimized_c_shim +); +// The `#[arm_aeabi_alias = __aeabi_idiv]` attribute cannot be made to work with `intrinsics!` in macros +intrinsics! { #[maybe_use_optimized_c_shim] - /// Returns `n / d` and sets `*rem = n % d` - pub extern "C" fn __divmoddi4(a: i64, b: i64, rem: &mut i64) -> i64 { - let quo_rem = i64_div_rem(a, b); - *rem = quo_rem.1; - quo_rem.0 - } - - #[win64_128bit_abi_hack] + #[arm_aeabi_alias = __aeabi_idiv] /// Returns `n / d` - pub extern "C" fn __divti3(a: i128, b: i128) -> i128 { - i128_div_rem(a, b).0 + pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { + let a_neg = a < 0; + let b_neg = b < 0; + let mut a = a; + let mut b = b; + if a_neg { + a = a.wrapping_neg(); + } + if b_neg { + b = b.wrapping_neg(); + } + let t = __udivsi3(a as u32, b as u32) as i32; + if a_neg != b_neg { + t.wrapping_neg() + } else { + t + } } +} +smod!(__umodsi3, __modsi3, u32, i32, maybe_use_optimized_c_shim); - #[win64_128bit_abi_hack] - /// Returns `n % d` - pub extern "C" fn __modti3(a: i128, b: i128) -> i128 { - i128_div_rem(a, b).1 - } +sdivmod!( + __udivmoddi4, + __divmoddi4, + u64, + i64, + maybe_use_optimized_c_shim +); +sdiv!(__udivdi3, __divdi3, u64, i64, maybe_use_optimized_c_shim); +smod!(__umoddi3, __moddi3, u64, i64, maybe_use_optimized_c_shim); - // LLVM does not currently have a `__divmodti4` function, but GCC does - #[maybe_use_optimized_c_shim] - /// Returns `n / d` and sets `*rem = n % d` - pub extern "C" fn __divmodti4(a: i128, b: i128, rem: &mut i128) -> i128 { - let quo_rem = i128_div_rem(a, b); - *rem = quo_rem.1; - quo_rem.0 - } -} +// LLVM does not currently have a `__divmodti4` function, but GCC does +sdivmod!( + __udivmodti4, + __divmodti4, + u128, + i128, + maybe_use_optimized_c_shim +); +sdiv!(__udivti3, __divti3, u128, i128, win64_128bit_abi_hack); +smod!(__umodti3, __modti3, u128, i128, win64_128bit_abi_hack); diff --git a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs index 16ab2baadea..bbb77722dc9 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs @@ -1,4 +1,4 @@ -/// Creates unsigned and signed division functions optimized for dividing integers with the same +/// Creates an unsigned division function optimized for dividing integers with the same /// bitwidth as the largest operand in an asymmetrically sized division. For example, x86-64 has an /// assembly instruction that can divide a 128 bit integer by a 64 bit integer if the quotient fits /// in 64 bits. The 128 bit version of this algorithm would use that fast hardware division to @@ -6,25 +6,18 @@ #[macro_export] macro_rules! impl_asymmetric { ( - $unsigned_name:ident, // name of the unsigned division function - $signed_name:ident, // name of the signed division function + $fn:ident, // name of the unsigned division function $zero_div_fn:ident, // function called when division by zero is attempted $half_division:ident, // function for division of a $uX by a $uX $asymmetric_division:ident, // function for division of a $uD by a $uX $n_h:expr, // the number of bits in a $iH or $uH $uH:ident, // unsigned integer with half the bit width of $uX $uX:ident, // unsigned integer with half the bit width of $uD - $uD:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` - $iD:ident, // signed integer type for the inputs and outputs of `$signed_name` - $($unsigned_attr:meta),*; // attributes for the unsigned function - $($signed_attr:meta),* // attributes for the signed function + $uD:ident // unsigned integer type for the inputs and outputs of `$fn` ) => { /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a /// tuple. - $( - #[$unsigned_attr] - )* - pub fn $unsigned_name(duo: $uD, div: $uD) -> ($uD,$uD) { + pub fn $fn(duo: $uD, div: $uD) -> ($uD, $uD) { let n: u32 = $n_h * 2; let duo_lo = duo as $uX; @@ -38,14 +31,14 @@ macro_rules! impl_asymmetric { if duo_hi < div_lo { // `$uD` by `$uX` division with a quotient that will fit into a `$uX` let (quo, rem) = unsafe { $asymmetric_division(duo, div_lo) }; - return (quo as $uD, rem as $uD) + return (quo as $uD, rem as $uD); } else { // Short division using the $uD by $uX division let (quo_hi, rem_hi) = $half_division(duo_hi, div_lo); let tmp = unsafe { $asymmetric_division((duo_lo as $uD) | ((rem_hi as $uD) << n), div_lo) }; - return ((tmp.0 as $uD) | ((quo_hi as $uD) << n), tmp.1 as $uD) + return ((tmp.0 as $uD) | ((quo_hi as $uD) << n), tmp.1 as $uD); } } @@ -57,9 +50,7 @@ macro_rules! impl_asymmetric { let div_lz = div_hi.leading_zeros(); let div_extra = n - div_lz; let div_sig_n = (div >> div_extra) as $uX; - let tmp = unsafe { - $asymmetric_division(duo >> 1, div_sig_n) - }; + let tmp = unsafe { $asymmetric_division(duo >> 1, div_sig_n) }; let mut quo = tmp.0 >> ((n - 1) - div_lz); if quo != 0 { @@ -72,33 +63,7 @@ macro_rules! impl_asymmetric { quo += 1; rem -= div; } - return (quo as $uD, rem) + return (quo as $uD, rem); } - - /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a - /// tuple. - $( - #[$signed_attr] - )* - pub fn $signed_name(duo: $iD, div: $iD) -> ($iD, $iD) { - match (duo < 0, div < 0) { - (false, false) => { - let t = $unsigned_name(duo as $uD, div as $uD); - (t.0 as $iD, t.1 as $iD) - }, - (true, false) => { - let t = $unsigned_name(duo.wrapping_neg() as $uD, div as $uD); - ((t.0 as $iD).wrapping_neg(), (t.1 as $iD).wrapping_neg()) - }, - (false, true) => { - let t = $unsigned_name(duo as $uD, div.wrapping_neg() as $uD); - ((t.0 as $iD).wrapping_neg(), t.1 as $iD) - }, - (true, true) => { - let t = $unsigned_name(duo.wrapping_neg() as $uD, div.wrapping_neg() as $uD); - (t.0 as $iD, (t.1 as $iD).wrapping_neg()) - }, - } - } - } + }; } diff --git a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs index 4c63396a088..0f5e870b0ee 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs @@ -1,4 +1,4 @@ -/// Creates unsigned and signed division functions that use binary long division, designed for +/// Creates an unsigned division function that uses binary long division, designed for /// computer architectures without division instructions. These functions have good performance for /// microarchitectures with large branch miss penalties and architectures without the ability to /// predicate instructions. For architectures with predicated instructions, one of the algorithms @@ -7,29 +7,23 @@ #[macro_export] macro_rules! impl_binary_long { ( - $unsigned_name:ident, // name of the unsigned division function - $signed_name:ident, // name of the signed division function + $fn:ident, // name of the unsigned division function $zero_div_fn:ident, // function called when division by zero is attempted $normalization_shift:ident, // function for finding the normalization shift $n:tt, // the number of bits in a $iX or $uX - $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` - $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` - $($unsigned_attr:meta),*; // attributes for the unsigned function - $($signed_attr:meta),* // attributes for the signed function + $uX:ident, // unsigned integer type for the inputs and outputs of `$fn` + $iX:ident // signed integer type with same bitwidth as `$uX` ) => { /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a /// tuple. - $( - #[$unsigned_attr] - )* - pub fn $unsigned_name(duo: $uX, div: $uX) -> ($uX, $uX) { + pub fn $fn(duo: $uX, div: $uX) -> ($uX, $uX) { let mut duo = duo; // handle edge cases before calling `$normalization_shift` if div == 0 { $zero_div_fn() } if duo < div { - return (0, duo) + return (0, duo); } // There are many variations of binary division algorithm that could be used. This @@ -430,7 +424,7 @@ macro_rules! impl_binary_long { let mut i = shl; loop { if i == 0 { - break + break; } i -= 1; // shift left 1 and subtract @@ -550,47 +544,5 @@ macro_rules! impl_binary_long { return ((duo & mask) | quo, duo >> shl); */ } - - /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a - /// tuple. - $( - #[$signed_attr] - )* - pub fn $signed_name(duo: $iX, div: $iX) -> ($iX, $iX) { - // There is a way of doing this without any branches, but requires too many extra - // operations to be faster. - /* - let duo_s = duo >> ($n - 1); - let div_s = div >> ($n - 1); - let duo = (duo ^ duo_s).wrapping_sub(duo_s); - let div = (div ^ div_s).wrapping_sub(div_s); - let quo_s = duo_s ^ div_s; - let rem_s = duo_s; - let tmp = $unsigned_name(duo as $uX, div as $uX); - ( - ((tmp.0 as $iX) ^ quo_s).wrapping_sub(quo_s), - ((tmp.1 as $iX) ^ rem_s).wrapping_sub(rem_s), - ) - */ - - match (duo < 0, div < 0) { - (false, false) => { - let t = $unsigned_name(duo as $uX, div as $uX); - (t.0 as $iX, t.1 as $iX) - }, - (true, false) => { - let t = $unsigned_name(duo.wrapping_neg() as $uX, div as $uX); - ((t.0 as $iX).wrapping_neg(), (t.1 as $iX).wrapping_neg()) - }, - (false, true) => { - let t = $unsigned_name(duo as $uX, div.wrapping_neg() as $uX); - ((t.0 as $iX).wrapping_neg(), t.1 as $iX) - }, - (true, true) => { - let t = $unsigned_name(duo.wrapping_neg() as $uX, div.wrapping_neg() as $uX); - (t.0 as $iX, (t.1 as $iX).wrapping_neg()) - }, - } - } - } + }; } diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index 1ba72431d61..a74bdac02d4 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -1,29 +1,23 @@ -/// Creates unsigned and signed division functions that use a combination of hardware division and +/// Creates an unsigned division function that uses a combination of hardware division and /// binary long division to divide integers larger than what hardware division by itself can do. This /// function is intended for microarchitectures that have division hardware, but not fast enough /// multiplication hardware for `impl_trifecta` to be faster. #[macro_export] macro_rules! impl_delegate { ( - $unsigned_name:ident, // name of the unsigned division function - $signed_name:ident, // name of the signed division function + $fn:ident, // name of the unsigned division function $zero_div_fn:ident, // function called when division by zero is attempted $half_normalization_shift:ident, // function for finding the normalization shift of $uX $half_division:ident, // function for division of a $uX by a $uX $n_h:expr, // the number of bits in $iH or $uH $uH:ident, // unsigned integer with half the bit width of $uX $uX:ident, // unsigned integer with half the bit width of $uD. - $uD:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` - $iD:ident, // signed integer type for the inputs and outputs of `$signed_name` - $($unsigned_attr:meta),*; // attributes for the unsigned function - $($signed_attr:meta),* // attributes for the signed function + $uD:ident, // unsigned integer type for the inputs and outputs of `$fn` + $iD:ident // signed integer type with the same bitwidth as `$uD` ) => { /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a /// tuple. - $( - #[$unsigned_attr] - )* - pub fn $unsigned_name(duo: $uD, div: $uD) -> ($uD, $uD) { + pub fn $fn(duo: $uD, div: $uD) -> ($uD, $uD) { // The two possibility algorithm, undersubtracting long division algorithm, or any kind // of reciprocal based algorithm will not be fastest, because they involve large // multiplications that we assume to not be fast enough relative to the divisions to @@ -38,17 +32,15 @@ macro_rules! impl_delegate { let div_hi = (div >> n) as $uX; match (div_lo == 0, div_hi == 0, duo_hi == 0) { - (true, true, _) => { - $zero_div_fn() - } + (true, true, _) => $zero_div_fn(), (_, false, true) => { // `duo` < `div` - return (0, duo) + return (0, duo); } (false, true, true) => { // delegate to smaller division let tmp = $half_division(duo_lo, div_lo); - return (tmp.0 as $uD, tmp.1 as $uD) + return (tmp.0 as $uD, tmp.1 as $uD); } (false, true, false) => { if duo_hi < div_lo { @@ -96,7 +88,7 @@ macro_rules! impl_delegate { // Delegate to get the rest of the quotient. Note that the // `div_lo` here is the original unshifted `div`. let tmp = $half_division(duo as $uX, div_lo); - return ((quo_lo | tmp.0) as $uD, tmp.1 as $uD) + return ((quo_lo | tmp.0) as $uD, tmp.1 as $uD); } } div >>= 1; @@ -105,7 +97,7 @@ macro_rules! impl_delegate { } else if duo_hi == div_lo { // `quo_hi == 1`. This branch is cheap and helps with edge cases. let tmp = $half_division(duo as $uX, div as $uX); - return ((1 << n) | (tmp.0 as $uD), tmp.1 as $uD) + return ((1 << n) | (tmp.0 as $uD), tmp.1 as $uD); } else { // `div_lo < duo_hi` // `rem_hi == 0` @@ -114,22 +106,16 @@ macro_rules! impl_delegate { let div_0 = div_lo as $uH as $uX; let (quo_hi, rem_3) = $half_division(duo_hi, div_0); - let duo_mid = - ((duo >> $n_h) as $uH as $uX) - | (rem_3 << $n_h); + let duo_mid = ((duo >> $n_h) as $uH as $uX) | (rem_3 << $n_h); let (quo_1, rem_2) = $half_division(duo_mid, div_0); - let duo_lo = - (duo as $uH as $uX) - | (rem_2 << $n_h); + let duo_lo = (duo as $uH as $uX) | (rem_2 << $n_h); let (quo_0, rem_1) = $half_division(duo_lo, div_0); return ( - (quo_0 as $uD) - | ((quo_1 as $uD) << $n_h) - | ((quo_hi as $uD) << n), - rem_1 as $uD - ) + (quo_0 as $uD) | ((quo_1 as $uD) << $n_h) | ((quo_hi as $uD) << n), + rem_1 as $uD, + ); } // This is basically a short division composed of a half division for the hi @@ -161,7 +147,7 @@ macro_rules! impl_delegate { let tmp = $half_division(duo as $uX, div_lo); return ( (tmp.0) as $uD | (quo_lo as $uD) | ((quo_hi as $uD) << n), - tmp.1 as $uD + tmp.1 as $uD, ); } } @@ -187,7 +173,7 @@ macro_rules! impl_delegate { duo = sub; quo_lo |= pow_lo; if duo < div_original { - return (quo_lo as $uD, duo) + return (quo_lo as $uD, duo); } } div >>= 1; @@ -196,31 +182,5 @@ macro_rules! impl_delegate { } } } - - /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a - /// tuple. - $( - #[$signed_attr] - )* - pub fn $signed_name(duo: $iD, div: $iD) -> ($iD, $iD) { - match (duo < 0, div < 0) { - (false, false) => { - let t = $unsigned_name(duo as $uD, div as $uD); - (t.0 as $iD, t.1 as $iD) - }, - (true, false) => { - let t = $unsigned_name(duo.wrapping_neg() as $uD, div as $uD); - ((t.0 as $iD).wrapping_neg(), (t.1 as $iD).wrapping_neg()) - }, - (false, true) => { - let t = $unsigned_name(duo as $uD, div.wrapping_neg() as $uD); - ((t.0 as $iD).wrapping_neg(), t.1 as $iD) - }, - (true, true) => { - let t = $unsigned_name(duo.wrapping_neg() as $uD, div.wrapping_neg() as $uD); - (t.0 as $iD, (t.1 as $iD).wrapping_neg()) - }, - } - } - } + }; } diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index f7dc044fa27..3ac341b6f35 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -111,13 +111,6 @@ fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { zero_div_fn() } -// `inline(never)` is placed on unsigned division functions so that there are just three division -// functions (`u32_div_rem`, `u64_div_rem`, and `u128_div_rem`) backing all `compiler-builtins` -// division functions. The signed functions like `i32_div_rem` will get inlined into the -// `compiler-builtins` signed division functions, so that they directly call the three division -// functions. Otherwise, LLVM may try to inline the unsigned division functions 4 times into the -// signed division functions, which results in an explosion in code size. - // Whether `trifecta` or `delegate` is faster for 128 bit division depends on the speed at which a // microarchitecture can multiply and divide. We decide to be optimistic and assume `trifecta` is // faster if the target pointer width is at least 64. @@ -127,16 +120,12 @@ fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { ))] impl_trifecta!( u128_div_rem, - i128_div_rem, zero_div_fn, u64_by_u64_div_rem, 32, u32, u64, - u128, - i128, - inline(never); - inline + u128 ); // If the pointer width less than 64, then the target architecture almost certainly does not have @@ -147,7 +136,6 @@ impl_trifecta!( ))] impl_delegate!( u128_div_rem, - i128_div_rem, zero_div_fn, u64_normalization_shift, u64_by_u64_div_rem, @@ -155,9 +143,7 @@ impl_delegate!( u32, u64, u128, - i128, - inline(never); - inline + i128 ); /// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. @@ -191,17 +177,13 @@ unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { #[cfg(all(feature = "asm", target_arch = "x86_64"))] impl_asymmetric!( u128_div_rem, - i128_div_rem, zero_div_fn, u64_by_u64_div_rem, u128_by_u64_div_rem, 32, u32, u64, - u128, - i128, - inline(never); - inline + u128 ); /// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. @@ -226,7 +208,6 @@ fn u32_by_u32_div_rem(duo: u32, div: u32) -> (u32, u32) { ))] impl_delegate!( u64_div_rem, - i64_div_rem, zero_div_fn, u32_normalization_shift, u32_by_u32_div_rem, @@ -234,9 +215,7 @@ impl_delegate!( u16, u32, u64, - i64, - inline(never); - inline + i64 ); // When not on x86 and the pointer width is 64, use `binary_long`. @@ -246,14 +225,11 @@ impl_delegate!( ))] impl_binary_long!( u64_div_rem, - i64_div_rem, zero_div_fn, u64_normalization_shift, 64, u64, - i64, - inline(never); - inline + i64 ); /// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. @@ -287,28 +263,21 @@ unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { #[cfg(all(feature = "asm", target_arch = "x86"))] impl_asymmetric!( u64_div_rem, - i64_div_rem, zero_div_fn, u32_by_u32_div_rem, u64_by_u32_div_rem, 16, u16, u32, - u64, - i64, - inline(never); - inline + u64 ); // 32 bits is the smallest division used by `compiler-builtins`, so we end with binary long division impl_binary_long!( u32_div_rem, - i32_div_rem, zero_div_fn, u32_normalization_shift, 32, u32, - i32, - inline(never); - inline + i32 ); diff --git a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs index e76516f3490..65ce1c3f072 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs @@ -1,28 +1,21 @@ -/// Creates unsigned and signed division functions optimized for division of integers with bitwidths +/// Creates an unsigned division function optimized for division of integers with bitwidths /// larger than the largest hardware integer division supported. These functions use large radix /// division algorithms that require both fast division and very fast widening multiplication on the /// target microarchitecture. Otherwise, `impl_delegate` should be used instead. #[macro_export] macro_rules! impl_trifecta { ( - $unsigned_name:ident, // name of the unsigned division function - $signed_name:ident, // name of the signed division function + $fn:ident, // name of the unsigned division function $zero_div_fn:ident, // function called when division by zero is attempted $half_division:ident, // function for division of a $uX by a $uX $n_h:expr, // the number of bits in $iH or $uH $uH:ident, // unsigned integer with half the bit width of $uX $uX:ident, // unsigned integer with half the bit width of $uD - $uD:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` - $iD:ident, // signed integer type for the inputs and outputs of `$signed_name` - $($unsigned_attr:meta),*; // attributes for the unsigned function - $($signed_attr:meta),* // attributes for the signed function + $uD:ident // unsigned integer type for the inputs and outputs of `$unsigned_name` ) => { /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a /// tuple. - $( - #[$unsigned_attr] - )* - pub fn $unsigned_name(duo: $uD, div: $uD) -> ($uD, $uD) { + pub fn $fn(duo: $uD, div: $uD) -> ($uD, $uD) { // This is called the trifecta algorithm because it uses three main algorithms: short // division for small divisors, the two possibility algorithm for large divisors, and an // undersubtracting long division algorithm for intermediate cases. @@ -34,7 +27,9 @@ macro_rules! impl_trifecta { (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) } fn carrying_mul_add(lhs: $uX, mul: $uX, add: $uX) -> ($uX, $uX) { - let tmp = (lhs as $uD).wrapping_mul(mul as $uD).wrapping_add(add as $uD); + let tmp = (lhs as $uD) + .wrapping_mul(mul as $uD) + .wrapping_add(add as $uD); (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) } @@ -62,9 +57,9 @@ macro_rules! impl_trifecta { // The quotient cannot be more than 1. The highest set bit of `duo` needs to be at // least one place higher than `div` for the quotient to be more than 1. if duo >= div { - return (1, duo - div) + return (1, duo - div); } else { - return (0, duo) + return (0, duo); } } @@ -76,10 +71,7 @@ macro_rules! impl_trifecta { // `duo < 2^n` so it will fit in a $uX. `div` will also fit in a $uX (because of the // `div_lz <= duo_lz` branch) so no numerical error. let (quo, rem) = $half_division(duo as $uX, div as $uX); - return ( - quo as $uD, - rem as $uD - ) + return (quo as $uD, rem as $uD); } // `{2^n, 2^div_sb} <= duo < 2^n_d` @@ -99,22 +91,16 @@ macro_rules! impl_trifecta { let div_0 = div as $uH as $uX; let (quo_hi, rem_3) = $half_division(duo_hi, div_0); - let duo_mid = - ((duo >> $n_h) as $uH as $uX) - | (rem_3 << $n_h); + let duo_mid = ((duo >> $n_h) as $uH as $uX) | (rem_3 << $n_h); let (quo_1, rem_2) = $half_division(duo_mid, div_0); - let duo_lo = - (duo as $uH as $uX) - | (rem_2 << $n_h); + let duo_lo = (duo as $uH as $uX) | (rem_2 << $n_h); let (quo_0, rem_1) = $half_division(duo_lo, div_0); return ( - (quo_0 as $uD) - | ((quo_1 as $uD) << $n_h) - | ((quo_hi as $uD) << n), - rem_1 as $uD - ) + (quo_0 as $uD) | ((quo_1 as $uD) << $n_h) | ((quo_hi as $uD) << n), + rem_1 as $uD, + ); } // relative leading significant bits, cannot overflow because of above branches @@ -237,13 +223,10 @@ macro_rules! impl_trifecta { (quo - 1) as $uD, // Both the addition and subtraction can overflow, but when combined end up // as a correct positive number. - duo.wrapping_add(div).wrapping_sub(tmp) - ) + duo.wrapping_add(div).wrapping_sub(tmp), + ); } else { - return ( - quo as $uD, - duo - tmp - ) + return (quo as $uD, duo - tmp); } } @@ -372,13 +355,10 @@ macro_rules! impl_trifecta { if duo < tmp { return ( quo + ((quo_part - 1) as $uD), - duo.wrapping_add(div).wrapping_sub(tmp) - ) + duo.wrapping_add(div).wrapping_sub(tmp), + ); } else { - return ( - quo + (quo_part as $uD), - duo - tmp - ) + return (quo + (quo_part as $uD), duo - tmp); } } @@ -387,15 +367,9 @@ macro_rules! impl_trifecta { if div_lz <= duo_lz { // quotient can have 0 or 1 added to it if div <= duo { - return ( - quo + 1, - duo - div - ) + return (quo + 1, duo - div); } else { - return ( - quo, - duo - ) + return (quo, duo); } } @@ -404,38 +378,9 @@ macro_rules! impl_trifecta { if n <= duo_lz { // simple division and addition let tmp = $half_division(duo as $uX, div as $uX); - return ( - quo + (tmp.0 as $uD), - tmp.1 as $uD - ) + return (quo + (tmp.0 as $uD), tmp.1 as $uD); } } } - - /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a - /// tuple. - $( - #[$signed_attr] - )* - pub fn $signed_name(duo: $iD, div: $iD) -> ($iD, $iD) { - match (duo < 0, div < 0) { - (false, false) => { - let t = $unsigned_name(duo as $uD, div as $uD); - (t.0 as $iD, t.1 as $iD) - }, - (true, false) => { - let t = $unsigned_name(duo.wrapping_neg() as $uD, div as $uD); - ((t.0 as $iD).wrapping_neg(), (t.1 as $iD).wrapping_neg()) - }, - (false, true) => { - let t = $unsigned_name(duo as $uD, div.wrapping_neg() as $uD); - ((t.0 as $iD).wrapping_neg(), t.1 as $iD) - }, - (true, true) => { - let t = $unsigned_name(duo.wrapping_neg() as $uD, div.wrapping_neg() as $uD); - (t.0 as $iD, (t.1 as $iD).wrapping_neg()) - }, - } - } - } + }; } -- cgit 1.4.1-3-g733a5 From d2a252503504adbc84de2c838f873eacfc04b829 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 2 Oct 2020 23:26:12 -0500 Subject: Hide macros and functions These macros and functions are only in the public interface for testing purposes or because of `#[macro_export]` pollution --- library/compiler-builtins/src/int/leading_zeros.rs | 2 ++ library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs | 1 + library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs | 1 + library/compiler-builtins/src/int/specialized_div_rem/delegate.rs | 1 + library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs | 1 + library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs | 1 + 6 files changed, 7 insertions(+) diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index 78556f0bcf6..e4a9e5eb2b4 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -4,6 +4,7 @@ // Compilers will insert the check for zero in cases where it is needed. /// Returns the number of leading binary zeros in `x`. +#[doc(hidden)] pub fn usize_leading_zeros_default(x: usize) -> usize { // The basic idea is to test if the higher bits of `x` are zero and bisect the number // of leading zeros. It is possible for all branches of the bisection to use the same @@ -75,6 +76,7 @@ pub fn usize_leading_zeros_default(x: usize) -> usize { // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. /// Returns the number of leading binary zeros in `x`. +#[doc(hidden)] pub fn usize_leading_zeros_riscv(x: usize) -> usize { let mut x = x; // the number of potential leading zeros diff --git a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs index bbb77722dc9..45da657e9c9 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs @@ -3,6 +3,7 @@ /// assembly instruction that can divide a 128 bit integer by a 64 bit integer if the quotient fits /// in 64 bits. The 128 bit version of this algorithm would use that fast hardware division to /// construct a full 128 bit by 128 bit division. +#[doc(hidden)] #[macro_export] macro_rules! impl_asymmetric { ( diff --git a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs index 0f5e870b0ee..7de10e85276 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs @@ -4,6 +4,7 @@ /// predicate instructions. For architectures with predicated instructions, one of the algorithms /// described in the documentation of these functions probably has higher performance, and a custom /// assembly routine should be used instead. +#[doc(hidden)] #[macro_export] macro_rules! impl_binary_long { ( diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index a74bdac02d4..8310c142956 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -2,6 +2,7 @@ /// binary long division to divide integers larger than what hardware division by itself can do. This /// function is intended for microarchitectures that have division hardware, but not fast enough /// multiplication hardware for `impl_trifecta` to be faster. +#[doc(hidden)] #[macro_export] macro_rules! impl_delegate { ( diff --git a/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs b/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs index 33348b37361..be95d1b927e 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs @@ -1,4 +1,5 @@ /// Creates a function used by some division algorithms to compute the "normalization shift". +#[doc(hidden)] #[macro_export] macro_rules! impl_normalization_shift { ( diff --git a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs index 65ce1c3f072..a9ea603019d 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs @@ -2,6 +2,7 @@ /// larger than the largest hardware integer division supported. These functions use large radix /// division algorithms that require both fast division and very fast widening multiplication on the /// target microarchitecture. Otherwise, `impl_delegate` should be used instead. +#[doc(hidden)] #[macro_export] macro_rules! impl_trifecta { ( -- cgit 1.4.1-3-g733a5 From f9bf5fee785fb58292d409e74e620a64ed456c89 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 15 Oct 2020 00:10:38 +0800 Subject: Use weak linkage for aeabi memory functions (#385) --- library/compiler-builtins/src/arm.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 190bba72620..3a250609197 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -138,18 +138,20 @@ pub unsafe fn __aeabi_ldivmod() { intrinsics::unreachable(); } +// The following functions use weak linkage to allow users to override +// with custom implementation. // FIXME: The `*4` and `*8` variants should be defined as aliases. #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { ::mem::memcpy(dest, src, n); } #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) { // We are guaranteed 4-alignment, so accessing at u32 is okay. let mut dest = dest as *mut u32; @@ -167,35 +169,35 @@ pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memcpy4(dest, src, n); } #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { ::mem::memmove(dest, src, n); } #[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } #[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { // Note the different argument order ::mem::memset(dest, c, n); @@ -203,7 +205,7 @@ pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) { let mut dest = dest as *mut u32; @@ -221,28 +223,28 @@ pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32 #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { __aeabi_memset4(dest, n, c); } #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { __aeabi_memset(dest, n, 0); } #[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } #[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } -- cgit 1.4.1-3-g733a5 From 34e35d74b66f9473c29e75548196d6f4d53609fa Mon Sep 17 00:00:00 2001 From: Joseph Richey Date: Sat, 24 Oct 2020 08:58:04 -0700 Subject: Use REP MOVSQ/STOSQ on x86_64 (#365) * mem: Move mem* functions to separate directory Signed-off-by: Joe Richey * memcpy: Create separate memcpy.rs file Signed-off-by: Joe Richey * benches: Add benchmarks for mem* functions This allows comparing the "normal" implementations to the implementations provided by this crate. Signed-off-by: Joe Richey * mem: Add REP MOVSB/STOSB implementations The assembly generated seems correct: https://rust.godbolt.org/z/GGnec8 Signed-off-by: Joe Richey * mem: Add documentations for REP string insturctions Signed-off-by: Joe Richey * Use quad-word rep string instructions Signed-off-by: Joe Richey * Prevent panic when compiled in debug mode Signed-off-by: Joe Richey * Add tests for mem* functions Signed-off-by: Joe Richey * Add build/test with the "asm" feature Signed-off-by: Joe Richey * Add byte length to Bencher Signed-off-by: Joe Richey --- library/compiler-builtins/ci/run.sh | 4 + library/compiler-builtins/src/mem.rs | 194 --------------------- library/compiler-builtins/src/mem/memcpy.rs | 41 +++++ library/compiler-builtins/src/mem/mod.rs | 159 +++++++++++++++++ library/compiler-builtins/src/mem/x86_64.rs | 79 +++++++++ library/compiler-builtins/testcrate/benches/mem.rs | 162 +++++++++++++++++ library/compiler-builtins/testcrate/tests/mem.rs | 133 ++++++++++++++ 7 files changed, 578 insertions(+), 194 deletions(-) delete mode 100644 library/compiler-builtins/src/mem.rs create mode 100644 library/compiler-builtins/src/mem/memcpy.rs create mode 100644 library/compiler-builtins/src/mem/mod.rs create mode 100644 library/compiler-builtins/src/mem/x86_64.rs create mode 100644 library/compiler-builtins/testcrate/benches/mem.rs create mode 100644 library/compiler-builtins/testcrate/tests/mem.rs diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 3c9dc0247e6..9d163233355 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -12,12 +12,16 @@ else $run --release $run --features c $run --features c --release + $run --features asm + $run --features asm --release fi cargo build --target $1 cargo build --target $1 --release cargo build --target $1 --features c cargo build --target $1 --release --features c +cargo build --target $1 --features asm +cargo build --target $1 --release --features asm PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs deleted file mode 100644 index 24552ed8510..00000000000 --- a/library/compiler-builtins/src/mem.rs +++ /dev/null @@ -1,194 +0,0 @@ -#[allow(warnings)] -#[cfg(target_pointer_width = "16")] -type c_int = i16; -#[allow(warnings)] -#[cfg(not(target_pointer_width = "16"))] -type c_int = i32; - -use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, exact_div}; -use core::mem; -use core::ops::{BitOr, Shl}; - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); - i += 1; - } - dest -} - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - if src < dest as *const u8 { - // copy from end - let mut i = n; - while i != 0 { - i -= 1; - *dest.offset(i as isize) = *src.offset(i as isize); - } - } else { - // copy from beginning - let mut i = 0; - while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); - i += 1; - } - } - dest -} - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *s.offset(i as isize) = c as u8; - i += 1; - } - s -} - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - let mut i = 0; - while i < n { - let a = *s1.offset(i as isize); - let b = *s2.offset(i as isize); - if a != b { - return a as i32 - b as i32; - } - i += 1; - } - 0 -} - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - memcmp(s1, s2, n) -} - -// `bytes` must be a multiple of `mem::size_of::()` -fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { - unsafe { - let n = exact_div(bytes, mem::size_of::()); - let mut i = 0; - while i < n { - atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); - i += 1; - } - } -} - -// `bytes` must be a multiple of `mem::size_of::()` -fn memmove_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { - unsafe { - let n = exact_div(bytes, mem::size_of::()); - if src < dest as *const T { - // copy from end - let mut i = n; - while i != 0 { - i -= 1; - atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); - } - } else { - // copy from beginning - let mut i = 0; - while i < n { - atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); - i += 1; - } - } - } -} - -// `T` must be a primitive integer type, and `bytes` must be a multiple of `mem::size_of::()` -fn memset_element_unordered_atomic(s: *mut T, c: u8, bytes: usize) -where - T: Copy + From + Shl + BitOr, -{ - unsafe { - let n = exact_div(bytes, mem::size_of::()); - - // Construct a value of type `T` consisting of repeated `c` - // bytes, to let us ensure we write each `T` atomically. - let mut x = T::from(c); - let mut i = 1; - while i < mem::size_of::() { - x = x << 8 | T::from(c); - i += 1; - } - - // Write it to `s` - let mut i = 0; - while i < n { - atomic_store_unordered(s.add(i), x); - i += 1; - } - } -} - -intrinsics! { - #[cfg(target_has_atomic_load_store = "8")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "16")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "32")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "64")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "128")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - - #[cfg(target_has_atomic_load_store = "8")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "16")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "32")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "64")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "128")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - - #[cfg(target_has_atomic_load_store = "8")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } - #[cfg(target_has_atomic_load_store = "16")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_2(s: *mut u16, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } - #[cfg(target_has_atomic_load_store = "32")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_4(s: *mut u32, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } - #[cfg(target_has_atomic_load_store = "64")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } - #[cfg(target_has_atomic_load_store = "128")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } -} diff --git a/library/compiler-builtins/src/mem/memcpy.rs b/library/compiler-builtins/src/mem/memcpy.rs new file mode 100644 index 00000000000..8fada9bca09 --- /dev/null +++ b/library/compiler-builtins/src/mem/memcpy.rs @@ -0,0 +1,41 @@ +use super::c_int; + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + dest +} + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + if src < dest as *const u8 { + // copy from end + let mut i = n; + while i != 0 { + i -= 1; + *dest.offset(i as isize) = *src.offset(i as isize); + } + } else { + // copy from beginning + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + } + dest +} + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { + let mut i = 0; + while i < n { + *s.offset(i as isize) = c as u8; + i += 1; + } + s +} diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs new file mode 100644 index 00000000000..aa9d4b61deb --- /dev/null +++ b/library/compiler-builtins/src/mem/mod.rs @@ -0,0 +1,159 @@ +#[allow(warnings)] +#[cfg(target_pointer_width = "16")] +type c_int = i16; +#[allow(warnings)] +#[cfg(not(target_pointer_width = "16"))] +type c_int = i32; + +use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, exact_div}; +use core::mem; +use core::ops::{BitOr, Shl}; + +// memcpy/memmove/memset have optimized implementations on some architectures +#[cfg_attr(all(feature = "asm", target_arch = "x86_64"), path = "x86_64.rs")] +mod memcpy; +pub use self::memcpy::*; + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + let mut i = 0; + while i < n { + let a = *s1.offset(i as isize); + let b = *s2.offset(i as isize); + if a != b { + return a as i32 - b as i32; + } + i += 1; + } + 0 +} + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + memcmp(s1, s2, n) +} + +// `bytes` must be a multiple of `mem::size_of::()` +fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { + unsafe { + let n = exact_div(bytes, mem::size_of::()); + let mut i = 0; + while i < n { + atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); + i += 1; + } + } +} + +// `bytes` must be a multiple of `mem::size_of::()` +fn memmove_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { + unsafe { + let n = exact_div(bytes, mem::size_of::()); + if src < dest as *const T { + // copy from end + let mut i = n; + while i != 0 { + i -= 1; + atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); + } + } else { + // copy from beginning + let mut i = 0; + while i < n { + atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); + i += 1; + } + } + } +} + +// `T` must be a primitive integer type, and `bytes` must be a multiple of `mem::size_of::()` +fn memset_element_unordered_atomic(s: *mut T, c: u8, bytes: usize) +where + T: Copy + From + Shl + BitOr, +{ + unsafe { + let n = exact_div(bytes, mem::size_of::()); + + // Construct a value of type `T` consisting of repeated `c` + // bytes, to let us ensure we write each `T` atomically. + let mut x = T::from(c); + let mut i = 1; + while i < mem::size_of::() { + x = x << 8 | T::from(c); + i += 1; + } + + // Write it to `s` + let mut i = 0; + while i < n { + atomic_store_unordered(s.add(i), x); + i += 1; + } + } +} + +intrinsics! { + #[cfg(target_has_atomic_load_store = "8")] + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + #[cfg(target_has_atomic_load_store = "16")] + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + #[cfg(target_has_atomic_load_store = "32")] + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + #[cfg(target_has_atomic_load_store = "64")] + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + #[cfg(target_has_atomic_load_store = "128")] + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + + #[cfg(target_has_atomic_load_store = "8")] + pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + #[cfg(target_has_atomic_load_store = "16")] + pub extern "C" fn __llvm_memmove_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + #[cfg(target_has_atomic_load_store = "32")] + pub extern "C" fn __llvm_memmove_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + #[cfg(target_has_atomic_load_store = "64")] + pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + #[cfg(target_has_atomic_load_store = "128")] + pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + + #[cfg(target_has_atomic_load_store = "8")] + pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } + #[cfg(target_has_atomic_load_store = "16")] + pub extern "C" fn __llvm_memset_element_unordered_atomic_2(s: *mut u16, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } + #[cfg(target_has_atomic_load_store = "32")] + pub extern "C" fn __llvm_memset_element_unordered_atomic_4(s: *mut u32, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } + #[cfg(target_has_atomic_load_store = "64")] + pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } + #[cfg(target_has_atomic_load_store = "128")] + pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } +} diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs new file mode 100644 index 00000000000..1ecffce45f2 --- /dev/null +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -0,0 +1,79 @@ +use super::c_int; + +// On most modern Intel and AMD processors, "rep movsq" and "rep stosq" have +// been enhanced to perform better than an simple qword loop, making them ideal +// for implementing memcpy/memset. Note that "rep cmps" has received no such +// enhancement, so it is not used to implement memcmp. +// +// On certain recent Intel processors, "rep movsb" and "rep stosb" have been +// further enhanced to automatically select the best microarchitectural +// implementation based on length and alignment. See the following features from +// the "Intel® 64 and IA-32 Architectures Optimization Reference Manual": +// - ERMSB - Enhanced REP MOVSB and STOSB (Ivy Bridge and later) +// - FSRM - Fast Short REP MOV (Ice Lake and later) +// - Fast Zero-Length MOVSB (On no current hardware) +// - Fast Short STOSB (On no current hardware) +// However, to avoid run-time feature detection, we don't use these byte-based +// instructions for most of the copying, preferring the qword variants. + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 { + let qword_count = count >> 3; + let byte_count = count & 0b111; + asm!( + "rep movsq [rdi], [rsi]", + "mov ecx, {byte_count:e}", + "rep movsb [rdi], [rsi]", + byte_count = in(reg) byte_count, + inout("rcx") qword_count => _, + inout("rdi") dest => _, + inout("rsi") src => _, + options(nostack, preserves_flags) + ); + dest +} + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 { + let delta = (dest as usize).wrapping_sub(src as usize); + if delta >= count { + // We can copy forwards because either dest is far enough ahead of src, + // or src is ahead of dest (and delta overflowed). + return self::memcpy(dest, src, count); + } + // copy backwards + let qword_count = count >> 3; + let byte_count = count & 0b111; + asm!( + "std", + "rep movsq [rdi], [rsi]", + "mov ecx, {byte_count:e}", + "add rdi, 7", + "add rsi, 7", + "rep movsb [rdi], [rsi]", + "cld", + byte_count = in(reg) byte_count, + inout("rcx") qword_count => _, + inout("rdi") dest.offset(count as isize).wrapping_sub(8) => _, + inout("rsi") src.offset(count as isize).wrapping_sub(8) => _, + options(nostack) + ); + dest +} + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memset(dest: *mut u8, c: c_int, count: usize) -> *mut u8 { + let qword_count = count >> 3; + let byte_count = count & 0b111; + asm!( + "rep stosq [rdi], rax", + "mov ecx, {byte_count:e}", + "rep stosb [rdi], al", + byte_count = in(reg) byte_count, + inout("rcx") qword_count => _, + inout("rdi") dest => _, + in("rax") (c as u8 as u64) * 0x0101010101010101, + options(nostack, preserves_flags) + ); + dest +} diff --git a/library/compiler-builtins/testcrate/benches/mem.rs b/library/compiler-builtins/testcrate/benches/mem.rs new file mode 100644 index 00000000000..57d57508613 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/mem.rs @@ -0,0 +1,162 @@ +#![feature(test)] + +extern crate test; +use test::{black_box, Bencher}; + +extern crate compiler_builtins; +use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; + +fn memcpy_builtin(b: &mut Bencher, n: usize) { + let v1 = vec![1u8; n]; + let mut v2 = vec![0u8; n]; + b.bytes = n as u64; + b.iter(|| { + let src: &[u8] = black_box(&v1); + let dst: &mut [u8] = black_box(&mut v2); + dst.copy_from_slice(src); + }) +} + +fn memcpy_rust(b: &mut Bencher, n: usize) { + let v1 = vec![1u8; n]; + let mut v2 = vec![0u8; n]; + b.bytes = n as u64; + b.iter(|| { + let src: &[u8] = black_box(&v1); + let dst: &mut [u8] = black_box(&mut v2); + unsafe { memcpy(dst.as_mut_ptr(), src.as_ptr(), n) } + }) +} + +fn memset_builtin(b: &mut Bencher, n: usize) { + let mut v1 = vec![0u8; n]; + b.bytes = n as u64; + b.iter(|| { + let dst: &mut [u8] = black_box(&mut v1); + let val: u8 = black_box(27); + for b in dst { + *b = val; + } + }) +} + +fn memset_rust(b: &mut Bencher, n: usize) { + let mut v1 = vec![0u8; n]; + b.bytes = n as u64; + b.iter(|| { + let dst: &mut [u8] = black_box(&mut v1); + let val = black_box(27); + unsafe { memset(dst.as_mut_ptr(), val, n) } + }) +} + +fn memcmp_builtin(b: &mut Bencher, n: usize) { + let v1 = vec![0u8; n]; + let mut v2 = vec![0u8; n]; + v2[n - 1] = 1; + b.bytes = n as u64; + b.iter(|| { + let s1: &[u8] = black_box(&v1); + let s2: &[u8] = black_box(&v2); + s1.cmp(s2) + }) +} + +fn memcmp_rust(b: &mut Bencher, n: usize) { + let v1 = vec![0u8; n]; + let mut v2 = vec![0u8; n]; + v2[n - 1] = 1; + b.bytes = n as u64; + b.iter(|| { + let s1: &[u8] = black_box(&v1); + let s2: &[u8] = black_box(&v2); + unsafe { memcmp(s1.as_ptr(), s2.as_ptr(), n) } + }) +} + +fn memmove_builtin(b: &mut Bencher, n: usize) { + let mut v = vec![0u8; n + n / 2]; + b.bytes = n as u64; + b.iter(|| { + let s: &mut [u8] = black_box(&mut v); + s.copy_within(0..n, n / 2); + }) +} + +fn memmove_rust(b: &mut Bencher, n: usize) { + let mut v = vec![0u8; n + n / 2]; + b.bytes = n as u64; + b.iter(|| { + let dst: *mut u8 = black_box(&mut v[n / 2..]).as_mut_ptr(); + let src: *const u8 = black_box(&v).as_ptr(); + unsafe { memmove(dst, src, n) }; + }) +} + +#[bench] +fn memcpy_builtin_4096(b: &mut Bencher) { + memcpy_builtin(b, 4096) +} +#[bench] +fn memcpy_rust_4096(b: &mut Bencher) { + memcpy_rust(b, 4096) +} +#[bench] +fn memcpy_builtin_1048576(b: &mut Bencher) { + memcpy_builtin(b, 1048576) +} +#[bench] +fn memcpy_rust_1048576(b: &mut Bencher) { + memcpy_rust(b, 1048576) +} + +#[bench] +fn memset_builtin_4096(b: &mut Bencher) { + memset_builtin(b, 4096) +} +#[bench] +fn memset_rust_4096(b: &mut Bencher) { + memset_rust(b, 4096) +} +#[bench] +fn memset_builtin_1048576(b: &mut Bencher) { + memset_builtin(b, 1048576) +} +#[bench] +fn memset_rust_1048576(b: &mut Bencher) { + memset_rust(b, 1048576) +} + +#[bench] +fn memcmp_builtin_4096(b: &mut Bencher) { + memcmp_builtin(b, 4096) +} +#[bench] +fn memcmp_rust_4096(b: &mut Bencher) { + memcmp_rust(b, 4096) +} +#[bench] +fn memcmp_builtin_1048576(b: &mut Bencher) { + memcmp_builtin(b, 1048576) +} +#[bench] +fn memcmp_rust_1048576(b: &mut Bencher) { + memcmp_rust(b, 1048576) +} + +#[bench] +fn memmove_builtin_4096(b: &mut Bencher) { + memmove_builtin(b, 4096) +} +#[bench] +fn memmove_rust_4096(b: &mut Bencher) { + memmove_rust(b, 4096) +} +#[bench] +fn memmove_builtin_1048576(b: &mut Bencher) { + memmove_builtin(b, 1048576) +} +#[bench] +fn memmove_rust_1048576(b: &mut Bencher) { + memmove_rust(b, 1048576) +} diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs new file mode 100644 index 00000000000..a5596b2811d --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -0,0 +1,133 @@ +extern crate compiler_builtins; +use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; + +#[test] +fn memcpy_3() { + let mut arr: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + unsafe { + let src = arr.as_ptr().offset(9); + let dst = arr.as_mut_ptr().offset(1); + assert_eq!(memcpy(dst, src, 3), dst); + assert_eq!(arr, [0, 9, 10, 11, 4, 5, 6, 7, 8, 9, 10, 11]); + } + arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + unsafe { + let src = arr.as_ptr().offset(1); + let dst = arr.as_mut_ptr().offset(9); + assert_eq!(memcpy(dst, src, 3), dst); + assert_eq!(arr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3]); + } +} + +#[test] +fn memcpy_10() { + let arr: [u8; 18] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]; + let mut dst: [u8; 12] = [0; 12]; + unsafe { + let src = arr.as_ptr().offset(1); + assert_eq!(memcpy(dst.as_mut_ptr(), src, 10), dst.as_mut_ptr()); + assert_eq!(dst, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0]); + } + unsafe { + let src = arr.as_ptr().offset(8); + assert_eq!(memcpy(dst.as_mut_ptr(), src, 10), dst.as_mut_ptr()); + assert_eq!(dst, [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0, 0]); + } +} + +#[test] +fn memcpy_big() { + // Make the arrays cross 3 pages + const SIZE: usize = 8193; + let src: [u8; SIZE] = [22; SIZE]; + struct Dst { + start: usize, + buf: [u8; SIZE], + end: usize, + } + + let mut dst = Dst { + start: 0, + buf: [0; SIZE], + end: 0, + }; + unsafe { + assert_eq!( + memcpy(dst.buf.as_mut_ptr(), src.as_ptr(), SIZE), + dst.buf.as_mut_ptr() + ); + assert_eq!(dst.start, 0); + assert_eq!(dst.buf, [22; SIZE]); + assert_eq!(dst.end, 0); + } +} + +#[test] +fn memmove_forward() { + let mut arr: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + unsafe { + let src = arr.as_ptr().offset(6); + let dst = arr.as_mut_ptr().offset(3); + assert_eq!(memmove(dst, src, 5), dst); + assert_eq!(arr, [0, 1, 2, 6, 7, 8, 9, 10, 8, 9, 10, 11]); + } +} + +#[test] +fn memmove_backward() { + let mut arr: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + unsafe { + let src = arr.as_ptr().offset(3); + let dst = arr.as_mut_ptr().offset(6); + assert_eq!(memmove(dst, src, 5), dst); + assert_eq!(arr, [0, 1, 2, 3, 4, 5, 3, 4, 5, 6, 7, 11]); + } +} + +#[test] +fn memset_zero() { + let mut arr: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; + unsafe { + let ptr = arr.as_mut_ptr().offset(5); + assert_eq!(memset(ptr, 0, 2), ptr); + assert_eq!(arr, [0, 1, 2, 3, 4, 0, 0, 7]); + + // Only the LSB matters for a memset + assert_eq!(memset(arr.as_mut_ptr(), 0x2000, 8), arr.as_mut_ptr()); + assert_eq!(arr, [0, 0, 0, 0, 0, 0, 0, 0]); + } +} + +#[test] +fn memset_nonzero() { + let mut arr: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; + unsafe { + let ptr = arr.as_mut_ptr().offset(2); + assert_eq!(memset(ptr, 22, 3), ptr); + assert_eq!(arr, [0, 1, 22, 22, 22, 5, 6, 7]); + + // Only the LSB matters for a memset + assert_eq!(memset(arr.as_mut_ptr(), 0x2009, 8), arr.as_mut_ptr()); + assert_eq!(arr, [9, 9, 9, 9, 9, 9, 9, 9]); + } +} + +#[test] +fn memcmp_eq() { + let arr1: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; + let arr2: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; + unsafe { + assert_eq!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 8), 0); + assert_eq!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 3), 0); + } +} + +#[test] +fn memcmp_ne() { + let arr1: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; + let arr2: [u8; 8] = [0, 1, 2, 3, 4, 5, 7, 7]; + unsafe { + assert!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 8) < 0); + assert!(memcmp(arr2.as_ptr(), arr1.as_ptr(), 8) > 0); + } +} -- cgit 1.4.1-3-g733a5 From a97fe5f1d3d959bb8d555fcc8eeca9e82f8e12d5 Mon Sep 17 00:00:00 2001 From: Robert Jördens Date: Mon, 26 Oct 2020 17:37:02 +0100 Subject: math: add {fmin,fmax}{f,} for thumb*-none-eabi* (#389) These are exposed in core::f32 close #354 c.f. rust-lang/rust#62729 Patch from @whitequark (https://paste.debian.net/1168430/) --- library/compiler-builtins/src/math.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 4b27cb80f68..94f91124bf0 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -92,6 +92,10 @@ no_mangle! { // only for the thumb*-none-eabi* targets #[cfg(all(target_arch = "arm", target_os = "none"))] no_mangle! { + fn fmin(x: f64, y: f64) -> f64; + fn fminf(x: f32, y: f32) -> f32; + fn fmax(x: f64, y: f64) -> f64; + fn fmaxf(x: f32, y: f32) -> f32; // `f64 % f64` fn fmod(x: f64, y: f64) -> f64; // `f32 % f32` -- cgit 1.4.1-3-g733a5 From 53daa3c593a915b57ad79b138deda1d8945b6f4a Mon Sep 17 00:00:00 2001 From: Joseph Richey Date: Tue, 3 Nov 2020 06:57:08 -0800 Subject: Use REP MOVSB/STOSB when the ERMSB feature is present (#392) * Reorganize mem functions This reduces the amount of platform-specific code Signed-off-by: Joe Richey * Use ERMSB implementations if the feature is set Signed-off-by: Joe Richey * Add non-aligned benchmarks Signed-off-by: Joe Richey --- library/compiler-builtins/src/mem/impls.rs | 29 ++++++++ library/compiler-builtins/src/mem/memcpy.rs | 41 ----------- library/compiler-builtins/src/mem/mod.rs | 28 +++++++- library/compiler-builtins/src/mem/x86_64.rs | 58 ++++++++++------ library/compiler-builtins/testcrate/benches/mem.rs | 80 +++++++++++++++------- 5 files changed, 148 insertions(+), 88 deletions(-) create mode 100644 library/compiler-builtins/src/mem/impls.rs delete mode 100644 library/compiler-builtins/src/mem/memcpy.rs diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs new file mode 100644 index 00000000000..6bd1a7ba1db --- /dev/null +++ b/library/compiler-builtins/src/mem/impls.rs @@ -0,0 +1,29 @@ +use super::c_int; + +#[inline(always)] +pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, n: usize) { + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } +} + +#[inline(always)] +pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, n: usize) { + // copy from end + let mut i = n; + while i != 0 { + i -= 1; + *dest.offset(i as isize) = *src.offset(i as isize); + } +} + +#[inline(always)] +pub unsafe fn set_bytes(s: *mut u8, c: u8, n: usize) { + let mut i = 0; + while i < n { + *s.offset(i as isize) = c; + i += 1; + } +} diff --git a/library/compiler-builtins/src/mem/memcpy.rs b/library/compiler-builtins/src/mem/memcpy.rs deleted file mode 100644 index 8fada9bca09..00000000000 --- a/library/compiler-builtins/src/mem/memcpy.rs +++ /dev/null @@ -1,41 +0,0 @@ -use super::c_int; - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); - i += 1; - } - dest -} - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - if src < dest as *const u8 { - // copy from end - let mut i = n; - while i != 0 { - i -= 1; - *dest.offset(i as isize) = *src.offset(i as isize); - } - } else { - // copy from beginning - let mut i = 0; - while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); - i += 1; - } - } - dest -} - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *s.offset(i as isize) = c as u8; - i += 1; - } - s -} diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index aa9d4b61deb..6bc76337c0b 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -11,8 +11,32 @@ use core::ops::{BitOr, Shl}; // memcpy/memmove/memset have optimized implementations on some architectures #[cfg_attr(all(feature = "asm", target_arch = "x86_64"), path = "x86_64.rs")] -mod memcpy; -pub use self::memcpy::*; +mod impls; + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + impls::copy_forward(dest, src, n); + dest +} + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + let delta = (dest as usize).wrapping_sub(src as usize); + if delta >= n { + // We can copy forwards because either dest is far enough ahead of src, + // or src is ahead of dest (and delta overflowed). + impls::copy_forward(dest, src, n); + } else { + impls::copy_backward(dest, src, n); + } + dest +} + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { + impls::set_bytes(s, c as u8, n); + s +} #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 1ecffce45f2..7eefd8099b9 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -1,5 +1,3 @@ -use super::c_int; - // On most modern Intel and AMD processors, "rep movsq" and "rep stosq" have // been enhanced to perform better than an simple qword loop, making them ideal // for implementing memcpy/memset. Note that "rep cmps" has received no such @@ -13,11 +11,26 @@ use super::c_int; // - FSRM - Fast Short REP MOV (Ice Lake and later) // - Fast Zero-Length MOVSB (On no current hardware) // - Fast Short STOSB (On no current hardware) -// However, to avoid run-time feature detection, we don't use these byte-based -// instructions for most of the copying, preferring the qword variants. +// +// To simplify things, we switch to using the byte-based variants if the "ermsb" +// feature is present at compile-time. We don't bother detecting other features. +// Note that ERMSB does not enhance the backwards (DF=1) "rep movsb". + +#[inline(always)] +#[cfg(target_feature = "ermsb")] +pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { + asm!( + "rep movsb [rdi], [rsi]", + inout("rcx") count => _, + inout("rdi") dest => _, + inout("rsi") src => _, + options(nostack, preserves_flags) + ); +} -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 { +#[inline(always)] +#[cfg(not(target_feature = "ermsb"))] +pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; asm!( @@ -30,18 +43,10 @@ pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, count: usize) -> inout("rsi") src => _, options(nostack, preserves_flags) ); - dest } -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 { - let delta = (dest as usize).wrapping_sub(src as usize); - if delta >= count { - // We can copy forwards because either dest is far enough ahead of src, - // or src is ahead of dest (and delta overflowed). - return self::memcpy(dest, src, count); - } - // copy backwards +#[inline(always)] +pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; asm!( @@ -58,11 +63,23 @@ pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, count: usize) -> inout("rsi") src.offset(count as isize).wrapping_sub(8) => _, options(nostack) ); - dest } -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memset(dest: *mut u8, c: c_int, count: usize) -> *mut u8 { +#[inline(always)] +#[cfg(target_feature = "ermsb")] +pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { + asm!( + "rep stosb [rdi], al", + inout("rcx") count => _, + inout("rdi") dest => _, + inout("al") c => _, + options(nostack, preserves_flags) + ) +} + +#[inline(always)] +#[cfg(not(target_feature = "ermsb"))] +pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; asm!( @@ -72,8 +89,7 @@ pub unsafe extern "C" fn memset(dest: *mut u8, c: c_int, count: usize) -> *mut u byte_count = in(reg) byte_count, inout("rcx") qword_count => _, inout("rdi") dest => _, - in("rax") (c as u8 as u64) * 0x0101010101010101, + in("rax") (c as u64) * 0x0101010101010101, options(nostack, preserves_flags) ); - dest } diff --git a/library/compiler-builtins/testcrate/benches/mem.rs b/library/compiler-builtins/testcrate/benches/mem.rs index 57d57508613..cee64ae4d51 100644 --- a/library/compiler-builtins/testcrate/benches/mem.rs +++ b/library/compiler-builtins/testcrate/benches/mem.rs @@ -6,33 +6,33 @@ use test::{black_box, Bencher}; extern crate compiler_builtins; use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; -fn memcpy_builtin(b: &mut Bencher, n: usize) { - let v1 = vec![1u8; n]; - let mut v2 = vec![0u8; n]; +fn memcpy_builtin(b: &mut Bencher, n: usize, offset: usize) { + let v1 = vec![1u8; n + offset]; + let mut v2 = vec![0u8; n + offset]; b.bytes = n as u64; b.iter(|| { - let src: &[u8] = black_box(&v1); - let dst: &mut [u8] = black_box(&mut v2); + let src: &[u8] = black_box(&v1[offset..]); + let dst: &mut [u8] = black_box(&mut v2[offset..]); dst.copy_from_slice(src); }) } -fn memcpy_rust(b: &mut Bencher, n: usize) { - let v1 = vec![1u8; n]; - let mut v2 = vec![0u8; n]; +fn memcpy_rust(b: &mut Bencher, n: usize, offset: usize) { + let v1 = vec![1u8; n + offset]; + let mut v2 = vec![0u8; n + offset]; b.bytes = n as u64; b.iter(|| { - let src: &[u8] = black_box(&v1); - let dst: &mut [u8] = black_box(&mut v2); + let src: &[u8] = black_box(&v1[offset..]); + let dst: &mut [u8] = black_box(&mut v2[offset..]); unsafe { memcpy(dst.as_mut_ptr(), src.as_ptr(), n) } }) } -fn memset_builtin(b: &mut Bencher, n: usize) { - let mut v1 = vec![0u8; n]; +fn memset_builtin(b: &mut Bencher, n: usize, offset: usize) { + let mut v1 = vec![0u8; n + offset]; b.bytes = n as u64; b.iter(|| { - let dst: &mut [u8] = black_box(&mut v1); + let dst: &mut [u8] = black_box(&mut v1[offset..]); let val: u8 = black_box(27); for b in dst { *b = val; @@ -40,11 +40,11 @@ fn memset_builtin(b: &mut Bencher, n: usize) { }) } -fn memset_rust(b: &mut Bencher, n: usize) { - let mut v1 = vec![0u8; n]; +fn memset_rust(b: &mut Bencher, n: usize, offset: usize) { + let mut v1 = vec![0u8; n + offset]; b.bytes = n as u64; b.iter(|| { - let dst: &mut [u8] = black_box(&mut v1); + let dst: &mut [u8] = black_box(&mut v1[offset..]); let val = black_box(27); unsafe { memset(dst.as_mut_ptr(), val, n) } }) @@ -95,36 +95,68 @@ fn memmove_rust(b: &mut Bencher, n: usize) { #[bench] fn memcpy_builtin_4096(b: &mut Bencher) { - memcpy_builtin(b, 4096) + memcpy_builtin(b, 4096, 0) } #[bench] fn memcpy_rust_4096(b: &mut Bencher) { - memcpy_rust(b, 4096) + memcpy_rust(b, 4096, 0) } #[bench] fn memcpy_builtin_1048576(b: &mut Bencher) { - memcpy_builtin(b, 1048576) + memcpy_builtin(b, 1048576, 0) } #[bench] fn memcpy_rust_1048576(b: &mut Bencher) { - memcpy_rust(b, 1048576) + memcpy_rust(b, 1048576, 0) +} +#[bench] +fn memcpy_builtin_4096_offset(b: &mut Bencher) { + memcpy_builtin(b, 4096, 65) +} +#[bench] +fn memcpy_rust_4096_offset(b: &mut Bencher) { + memcpy_rust(b, 4096, 65) +} +#[bench] +fn memcpy_builtin_1048576_offset(b: &mut Bencher) { + memcpy_builtin(b, 1048576, 65) +} +#[bench] +fn memcpy_rust_1048576_offset(b: &mut Bencher) { + memcpy_rust(b, 1048576, 65) } #[bench] fn memset_builtin_4096(b: &mut Bencher) { - memset_builtin(b, 4096) + memset_builtin(b, 4096, 0) } #[bench] fn memset_rust_4096(b: &mut Bencher) { - memset_rust(b, 4096) + memset_rust(b, 4096, 0) } #[bench] fn memset_builtin_1048576(b: &mut Bencher) { - memset_builtin(b, 1048576) + memset_builtin(b, 1048576, 0) } #[bench] fn memset_rust_1048576(b: &mut Bencher) { - memset_rust(b, 1048576) + memset_rust(b, 1048576, 0) +} +#[bench] +fn memset_builtin_4096_offset(b: &mut Bencher) { + memset_builtin(b, 4096, 65) +} +#[bench] +fn memset_rust_4096_offset(b: &mut Bencher) { + memset_rust(b, 4096, 65) +} +#[bench] +fn memset_builtin_1048576_offset(b: &mut Bencher) { + memset_builtin(b, 1048576, 65) +} +#[bench] +fn memset_rust_1048576_offset(b: &mut Bencher) { + memset_rust(b, 1048576, 65) } #[bench] -- cgit 1.4.1-3-g733a5 From 5c294cedc0daba4a6f8cb99aa2de9cf58a8a2e4f Mon Sep 17 00:00:00 2001 From: Joseph Richey Date: Mon, 9 Nov 2020 07:24:25 -0800 Subject: Move from an "asm" flag to a "no-asm" feature flag (#386) * Use a no-asm feature instead of an asm feature This works better as core/alloc/std have trouble supporting default featues in this crate. Signed-off-by: Joe Richey * Have no-asm disable arm assembly intrinsics Signed-off-by: Joe Richey --- library/compiler-builtins/Cargo.toml | 8 ++++---- library/compiler-builtins/ci/run.sh | 8 ++++---- library/compiler-builtins/src/arm.rs | 2 ++ .../src/int/specialized_div_rem/mod.rs | 16 ++++++++-------- library/compiler-builtins/src/lib.rs | 6 +++--- library/compiler-builtins/src/mem/mod.rs | 5 ++++- library/compiler-builtins/src/probestack.rs | 2 ++ library/compiler-builtins/src/x86.rs | 21 ++++++++++++++++++--- library/compiler-builtins/src/x86_64.rs | 21 ++++++++++++++++++--- library/compiler-builtins/testcrate/Cargo.toml | 4 ++-- 10 files changed, 65 insertions(+), 28 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 9262bb6d64f..0c5fd15315e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -40,14 +40,14 @@ panic-handler = { path = 'crates/panic-handler' } [features] default = ["compiler-builtins"] -# Some algorithms benefit from inline assembly, but some compiler backends do -# not support it, so inline assembly is only enabled when this flag is set. -asm = [] - # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics c = ["cc"] +# Workaround for the Cranelift codegen backend. Disables any implementations +# which use inline assembly and fall back to pure Rust versions (if avalible). +no-asm = [] + # Flag this library as the unstable compiler-builtins lib compiler-builtins = [] diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 9d163233355..44ec30fb798 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -12,16 +12,16 @@ else $run --release $run --features c $run --features c --release - $run --features asm - $run --features asm --release + $run --features no-asm + $run --features no-asm --release fi cargo build --target $1 cargo build --target $1 --release cargo build --target $1 --features c cargo build --target $1 --release --features c -cargo build --target $1 --features asm -cargo build --target $1 --release --features asm +cargo build --target $1 --features no-asm +cargo build --target $1 --release --features no-asm PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 3a250609197..2b17b4f9613 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,3 +1,5 @@ +#![cfg(not(feature = "no-asm"))] + use core::intrinsics; // NOTE This function and the ones below are implemented using assembly because they using a custom diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 3ac341b6f35..7f37f62202b 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -115,7 +115,7 @@ fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { // microarchitecture can multiply and divide. We decide to be optimistic and assume `trifecta` is // faster if the target pointer width is at least 64. #[cfg(all( - not(all(feature = "asm", target_arch = "x86_64")), + not(all(not(feature = "no-asm"), target_arch = "x86_64")), not(any(target_pointer_width = "16", target_pointer_width = "32")) ))] impl_trifecta!( @@ -131,7 +131,7 @@ impl_trifecta!( // If the pointer width less than 64, then the target architecture almost certainly does not have // the fast 64 to 128 bit widening multiplication needed for `trifecta` to be faster. #[cfg(all( - not(all(feature = "asm", target_arch = "x86_64")), + not(all(not(feature = "no-asm"), target_arch = "x86_64")), any(target_pointer_width = "16", target_pointer_width = "32") ))] impl_delegate!( @@ -152,7 +152,7 @@ impl_delegate!( /// /// If the quotient does not fit in a `u64`, a floating point exception occurs. /// If `div == 0`, then a division by zero exception occurs. -#[cfg(all(feature = "asm", target_arch = "x86_64"))] +#[cfg(all(not(feature = "no-asm"), target_arch = "x86_64"))] #[inline] unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { let duo_lo = duo as u64; @@ -174,7 +174,7 @@ unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { } // use `asymmetric` instead of `trifecta` on x86_64 -#[cfg(all(feature = "asm", target_arch = "x86_64"))] +#[cfg(all(not(feature = "no-asm"), target_arch = "x86_64"))] impl_asymmetric!( u128_div_rem, zero_div_fn, @@ -203,7 +203,7 @@ fn u32_by_u32_div_rem(duo: u32, div: u32) -> (u32, u32) { // When not on x86 and the pointer width is not 64, use `delegate` since the division size is larger // than register size. #[cfg(all( - not(all(feature = "asm", target_arch = "x86")), + not(all(not(feature = "no-asm"), target_arch = "x86")), not(target_pointer_width = "64") ))] impl_delegate!( @@ -220,7 +220,7 @@ impl_delegate!( // When not on x86 and the pointer width is 64, use `binary_long`. #[cfg(all( - not(all(feature = "asm", target_arch = "x86")), + not(all(not(feature = "no-asm"), target_arch = "x86")), target_pointer_width = "64" ))] impl_binary_long!( @@ -238,7 +238,7 @@ impl_binary_long!( /// /// If the quotient does not fit in a `u32`, a floating point exception occurs. /// If `div == 0`, then a division by zero exception occurs. -#[cfg(all(feature = "asm", target_arch = "x86"))] +#[cfg(all(not(feature = "no-asm"), target_arch = "x86"))] #[inline] unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { let duo_lo = duo as u32; @@ -260,7 +260,7 @@ unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { } // use `asymmetric` instead of `delegate` on x86 -#[cfg(all(feature = "asm", target_arch = "x86"))] +#[cfg(all(not(feature = "no-asm"), target_arch = "x86"))] impl_asymmetric!( u64_div_rem, zero_div_fn, diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index cbd23850b3f..4a7c746a2ff 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,8 +1,8 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] -#![cfg_attr(feature = "asm", feature(asm))] +#![cfg_attr(not(feature = "no-asm"), feature(asm))] #![feature(abi_unadjusted)] -#![feature(llvm_asm)] -#![feature(global_asm)] +#![cfg_attr(not(feature = "no-asm"), feature(llvm_asm))] +#![cfg_attr(not(feature = "no-asm"), feature(global_asm))] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index 6bc76337c0b..adb7c2c64c9 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -10,7 +10,10 @@ use core::mem; use core::ops::{BitOr, Shl}; // memcpy/memmove/memset have optimized implementations on some architectures -#[cfg_attr(all(feature = "asm", target_arch = "x86_64"), path = "x86_64.rs")] +#[cfg_attr( + all(not(feature = "no-asm"), target_arch = "x86_64"), + path = "x86_64.rs" +)] mod impls; #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 2f37a104ece..ac3ae1ebbc4 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -44,6 +44,8 @@ #![cfg(not(feature = "mangled-names"))] // Windows already has builtins to do this. #![cfg(not(windows))] +// All these builtins require assembly +#![cfg(not(feature = "no-asm"))] // We only define stack probing for these architectures today. #![cfg(any(target_arch = "x86_64", target_arch = "x86"))] diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index 5511c4572e5..e038231bb0e 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -8,7 +8,12 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca -#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] +#[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm"), + not(feature = "mangled-names") +))] #[naked] #[no_mangle] pub unsafe fn ___chkstk_ms() { @@ -34,7 +39,12 @@ pub unsafe fn ___chkstk_ms() { } // FIXME: __alloca should be an alias to __chkstk -#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] +#[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm"), + not(feature = "mangled-names") +))] #[naked] #[no_mangle] pub unsafe fn __alloca() { @@ -43,7 +53,12 @@ pub unsafe fn __alloca() { intrinsics::unreachable(); } -#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] +#[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm"), + not(feature = "mangled-names") +))] #[naked] #[no_mangle] pub unsafe fn ___chkstk() { diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 6a0cd566873..91c0f24fca6 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -8,7 +8,12 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca -#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] +#[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm"), + not(feature = "mangled-names") +))] #[naked] #[no_mangle] pub unsafe fn ___chkstk_ms() { @@ -33,7 +38,12 @@ pub unsafe fn ___chkstk_ms() { intrinsics::unreachable(); } -#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] +#[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm"), + not(feature = "mangled-names") +))] #[naked] #[no_mangle] pub unsafe fn __alloca() { @@ -43,7 +53,12 @@ pub unsafe fn __alloca() { intrinsics::unreachable(); } -#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] +#[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm"), + not(feature = "mangled-names") +))] #[naked] #[no_mangle] pub unsafe fn ___chkstk() { diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 5c3df79619e..ce8df2d12c5 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -28,8 +28,8 @@ utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japa utest-macros = { git = "https://github.com/japaric/utest" } [features] -default = ["asm", "mangled-names"] -asm = ["compiler_builtins/asm"] +default = ["mangled-names"] c = ["compiler_builtins/c"] +no-asm = ["compiler_builtins/no-asm"] mem = ["compiler_builtins/mem"] mangled-names = ["compiler_builtins/mangled-names"] -- cgit 1.4.1-3-g733a5 From 82bee10b5bfcdd165ffefbbb69dc6d4e3d56aa43 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 20 Nov 2020 10:29:35 -0600 Subject: Update CI to fix on GitHub Actions (#394) Should hopefully fix the master branch... --- library/compiler-builtins/.github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index e4bcc9c1052..01dffb8451e 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -90,7 +90,7 @@ jobs: run: | curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/10.0-2020-05-05.tar.gz tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-10.0-2020-05-05/compiler-rt - echo "##[set-env name=RUST_COMPILER_RT_ROOT]./compiler-rt" + echo RUST_COMPILER_RT_ROOT=./compiler-rt >> $GITHUB_ENV shell: bash # Non-linux tests just use our raw script -- cgit 1.4.1-3-g733a5 From a7548bea0d32e11c4e16f5260485366ad28a34cd Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Mon, 23 Nov 2020 09:05:02 -0600 Subject: fix division on SPARC (#393) --- .../src/int/specialized_div_rem/delegate.rs | 130 +++++++++++++++++++++ .../src/int/specialized_div_rem/mod.rs | 49 ++++---- library/compiler-builtins/src/int/udiv.rs | 38 +++++- 3 files changed, 190 insertions(+), 27 deletions(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index 8310c142956..135d3402a3a 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -185,3 +185,133 @@ macro_rules! impl_delegate { } }; } + +/// Returns `n / d` and sets `*rem = n % d`. +/// +/// This specialization exists because: +/// - The LLVM backend for 32-bit SPARC cannot compile functions that return `(u128, u128)`, +/// so we have to use an old fashioned `&mut u128` argument to return the remainder. +/// - 64-bit SPARC does not have u64 * u64 => u128 widening multiplication, which makes the +/// delegate algorithm strategy the only reasonably fast way to perform `u128` division. +#[doc(hidden)] +pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { + use super::*; + let duo_lo = duo as u64; + let duo_hi = (duo >> 64) as u64; + let div_lo = div as u64; + let div_hi = (div >> 64) as u64; + + match (div_lo == 0, div_hi == 0, duo_hi == 0) { + (true, true, _) => zero_div_fn(), + (_, false, true) => { + *rem = duo; + return 0; + } + (false, true, true) => { + let tmp = u64_by_u64_div_rem(duo_lo, div_lo); + *rem = tmp.1 as u128; + return tmp.0 as u128; + } + (false, true, false) => { + if duo_hi < div_lo { + let norm_shift = u64_normalization_shift(div_lo, duo_hi, false); + let shl = if norm_shift == 0 { + 64 - 1 + } else { + 64 - norm_shift + }; + + let mut div: u128 = div << shl; + let mut pow_lo: u64 = 1 << shl; + let mut quo_lo: u64 = 0; + let mut duo = duo; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as i128) { + duo = sub; + quo_lo |= pow_lo; + let duo_hi = (duo >> 64) as u64; + if duo_hi == 0 { + let tmp = u64_by_u64_div_rem(duo as u64, div_lo); + *rem = tmp.1 as u128; + return (quo_lo | tmp.0) as u128; + } + } + div >>= 1; + pow_lo >>= 1; + } + } else if duo_hi == div_lo { + let tmp = u64_by_u64_div_rem(duo as u64, div as u64); + *rem = tmp.1 as u128; + return (1 << 64) | (tmp.0 as u128); + } else { + if (div_lo >> 32) == 0 { + let div_0 = div_lo as u32 as u64; + let (quo_hi, rem_3) = u64_by_u64_div_rem(duo_hi, div_0); + + let duo_mid = ((duo >> 32) as u32 as u64) | (rem_3 << 32); + let (quo_1, rem_2) = u64_by_u64_div_rem(duo_mid, div_0); + + let duo_lo = (duo as u32 as u64) | (rem_2 << 32); + let (quo_0, rem_1) = u64_by_u64_div_rem(duo_lo, div_0); + + *rem = rem_1 as u128; + return (quo_0 as u128) | ((quo_1 as u128) << 32) | ((quo_hi as u128) << 64); + } + + let duo_lo = duo as u64; + let tmp = u64_by_u64_div_rem(duo_hi, div_lo); + let quo_hi = tmp.0; + let mut duo = (duo_lo as u128) | ((tmp.1 as u128) << 64); + if duo < div { + *rem = duo; + return (quo_hi as u128) << 64; + } + + let mut div: u128 = div << (64 - 1); + let mut pow_lo: u64 = 1 << (64 - 1); + let mut quo_lo: u64 = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as i128) { + duo = sub; + quo_lo |= pow_lo; + let duo_hi = (duo >> 64) as u64; + if duo_hi == 0 { + let tmp = u64_by_u64_div_rem(duo as u64, div_lo); + *rem = tmp.1 as u128; + return (tmp.0) as u128 | (quo_lo as u128) | ((quo_hi as u128) << 64); + } + } + div >>= 1; + pow_lo >>= 1; + } + } + } + (_, false, false) => { + if duo < div { + *rem = duo; + return 0; + } + let div_original = div; + let shl = u64_normalization_shift(duo_hi, div_hi, false); + let mut duo = duo; + let mut div: u128 = div << shl; + let mut pow_lo: u64 = 1 << shl; + let mut quo_lo: u64 = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as i128) { + duo = sub; + quo_lo |= pow_lo; + if duo < div_original { + *rem = duo; + return quo_lo as u128; + } + } + div >>= 1; + pow_lo >>= 1; + } + } + } +} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 7f37f62202b..eaeb030e389 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -46,6 +46,7 @@ mod binary_long; #[macro_use] mod delegate; +pub use self::delegate::u128_divide_sparc; #[macro_use] mod trifecta; @@ -60,27 +61,31 @@ fn zero_div_fn() -> ! { unsafe { core::hint::unreachable_unchecked() } } -// The `B` extension on RISC-V determines if a CLZ assembly instruction exists -#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] -const USE_LZ: bool = cfg!(target_feature = "b"); - -#[cfg(target_arch = "arm")] -const USE_LZ: bool = if cfg!(target_feature = "thumb-mode") { - // ARM thumb targets have CLZ instructions if the instruction set of ARMv6T2 is supported. This - // is needed to successfully differentiate between targets like `thumbv8.base` and - // `thumbv8.main`. - cfg!(target_feature = "v6t2") -} else { - // Regular ARM targets have CLZ instructions if the ARMv5TE instruction set is supported. - // Technically, ARMv5T was the first to have CLZ, but the "v5t" target feature does not seem to - // work. - cfg!(target_feature = "v5te") +const USE_LZ: bool = { + if cfg!(target_arch = "arm") { + if cfg!(target_feature = "thumb-mode") { + // ARM thumb targets have CLZ instructions if the instruction set of ARMv6T2 is + // supported. This is needed to successfully differentiate between targets like + // `thumbv8.base` and `thumbv8.main`. + cfg!(target_feature = "v6t2") + } else { + // Regular ARM targets have CLZ instructions if the ARMv5TE instruction set is + // supported. Technically, ARMv5T was the first to have CLZ, but the "v5t" target + // feature does not seem to work. + cfg!(target_feature = "v5te") + } + } else if cfg!(any(target_arch = "sparc", target_arch = "sparc64")) { + // LZD or LZCNT on SPARC only exists for the VIS 3 extension and later. + cfg!(target_feature = "vis3") + } else if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { + // The `B` extension on RISC-V determines if a CLZ assembly instruction exists + cfg!(target_feature = "b") + } else { + // All other common targets Rust supports should have CLZ instructions + true + } }; -// All other targets Rust supports have CLZ instructions -#[cfg(not(any(target_arch = "arm", target_arch = "riscv32", target_arch = "riscv64")))] -const USE_LZ: bool = true; - impl_normalization_shift!( u32_normalization_shift, USE_LZ, @@ -115,8 +120,9 @@ fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { // microarchitecture can multiply and divide. We decide to be optimistic and assume `trifecta` is // faster if the target pointer width is at least 64. #[cfg(all( + not(any(target_pointer_width = "16", target_pointer_width = "32")), not(all(not(feature = "no-asm"), target_arch = "x86_64")), - not(any(target_pointer_width = "16", target_pointer_width = "32")) + not(any(target_arch = "sparc", target_arch = "sparc64")) ))] impl_trifecta!( u128_div_rem, @@ -131,8 +137,9 @@ impl_trifecta!( // If the pointer width less than 64, then the target architecture almost certainly does not have // the fast 64 to 128 bit widening multiplication needed for `trifecta` to be faster. #[cfg(all( + any(target_pointer_width = "16", target_pointer_width = "32"), not(all(not(feature = "no-asm"), target_arch = "x86_64")), - any(target_pointer_width = "16", target_pointer_width = "32") + not(any(target_arch = "sparc", target_arch = "sparc64")) ))] impl_delegate!( u128_div_rem, diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 3cd9be93cb1..d9717807849 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,3 +1,4 @@ +pub use int::specialized_div_rem::u128_divide_sparc; use int::specialized_div_rem::*; intrinsics! { @@ -46,25 +47,50 @@ intrinsics! { quo_rem.0 } + // Note: we use block configuration and not `if cfg!(...)`, because we need to entirely disable + // the existence of `u128_div_rem` to get 32-bit SPARC to compile, see `u128_divide_sparc` docs. + #[win64_128bit_abi_hack] /// Returns `n / d` pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { - u128_div_rem(n, d).0 + #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { + u128_div_rem(n, d).0 + } + #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] { + u128_divide_sparc(n, d, &mut 0) + } } #[win64_128bit_abi_hack] /// Returns `n % d` pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { - u128_div_rem(n, d).1 + #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { + u128_div_rem(n, d).1 + } + #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] { + let mut rem = 0; + u128_divide_sparc(n, d, &mut rem); + rem + } } #[win64_128bit_abi_hack] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { - let quo_rem = u128_div_rem(n, d); - if let Some(rem) = rem { - *rem = quo_rem.1; + #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { + let quo_rem = u128_div_rem(n, d); + if let Some(rem) = rem { + *rem = quo_rem.1; + } + quo_rem.0 + } + #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] { + let mut tmp = 0; + let quo = u128_divide_sparc(n, d, &mut tmp); + if let Some(rem) = rem { + *rem = tmp; + } + quo } - quo_rem.0 } } -- cgit 1.4.1-3-g733a5 From ea7feb2e0fd9dca228ec5f5b1094956b1339b657 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Tue, 13 Oct 2020 00:06:27 -0500 Subject: Remove `aapcs_on_arm` mistake --- library/compiler-builtins/src/int/mul.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 42f13913e3e..1e32560c2ae 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -90,7 +90,6 @@ intrinsics! { a.mul(b) } - #[aapcs_on_arm] pub extern "C" fn __multi3(a: i128, b: i128) -> i128 { a.mul(b) } -- cgit 1.4.1-3-g733a5 From e049a3096478ef8fdbc82131a5a26f7e57863ca1 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Mon, 12 Oct 2020 17:58:02 -0500 Subject: Introduce the `DInt` and `HInt` traits and add various methods that will be used for improved fuzzing --- library/compiler-builtins/src/int/mod.rs | 203 ++++++++++++++++++++++++++++++- 1 file changed, 202 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 5e695d5f7e0..da2263f6ef8 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -12,13 +12,15 @@ pub mod udiv; pub use self::leading_zeros::__clzsi2; /// Trait for some basic operations on integers -pub(crate) trait Int: +#[doc(hidden)] +pub trait Int: Copy + PartialEq + PartialOrd + ops::AddAssign + ops::BitAndAssign + ops::BitOrAssign + + ops::BitXorAssign + ops::ShlAssign + ops::ShrAssign + ops::Add @@ -41,6 +43,14 @@ pub(crate) trait Int: const ZERO: Self; const ONE: Self; + const MIN: Self; + + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, + /// 112,119,120,125,126,127]. + const FUZZ_LENGTHS: [u8; 20]; + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize; /// Extracts the sign from self and returns a tuple. /// @@ -59,17 +69,25 @@ pub(crate) trait Int: fn from_bool(b: bool) -> Self; + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; fn max_value() -> Self; fn min_value() -> Self; + fn wrapping_neg(self) -> Self; fn wrapping_add(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self; fn wrapping_sub(self, other: Self) -> Self; fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; fn overflowing_add(self, other: Self) -> (Self, bool); fn aborting_div(self, other: Self) -> Self; fn aborting_rem(self, other: Self) -> Self; fn leading_zeros(self) -> u32; + fn count_ones(self) -> u32; } fn unwrap(t: Option) -> T { @@ -85,11 +103,78 @@ macro_rules! int_impl_common { const ZERO: Self = 0; const ONE: Self = 1; + const MIN: Self = ::MIN; + + const FUZZ_LENGTHS: [u8; 20] = { + let bits = ::BITS; + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v + }; + + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; fn from_bool(b: bool) -> Self { b as $ty } + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + fn max_value() -> Self { ::max_value() } @@ -98,6 +183,10 @@ macro_rules! int_impl_common { ::min_value() } + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + fn wrapping_add(self, other: Self) -> Self { ::wrapping_add(self, other) } @@ -114,6 +203,14 @@ macro_rules! int_impl_common { ::wrapping_shl(self, other) } + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + fn overflowing_add(self, other: Self) -> (Self, bool) { ::overflowing_add(self, other) } @@ -129,6 +226,10 @@ macro_rules! int_impl_common { fn leading_zeros(self) -> u32 { ::leading_zeros(self) } + + fn count_ones(self) -> u32 { + ::count_ones(self) + } }; } @@ -178,11 +279,111 @@ macro_rules! int_impl { }; } +int_impl!(isize, usize, usize::MAX.count_ones()); +int_impl!(i8, u8, 8); int_impl!(i16, u16, 16); int_impl!(i32, u32, 32); int_impl!(i64, u64, 64); int_impl!(i128, u128, 128); +/// Trait for integers twice the bit width of another integer. This is implemented for all +/// primitives except for `u8`, because there is not a smaller primitive. +#[doc(hidden)] +pub trait DInt: Int { + /// Integer that is half the bit width of the integer this trait is implemented for + type H: HInt + Int; + + /// Returns the low half of `self` + fn lo(self) -> Self::H; + /// Returns the high half of `self` + fn hi(self) -> Self::H; + /// Returns the low and high halves of `self` as a tuple + fn lo_hi(self) -> (Self::H, Self::H); + /// Constructs an integer using lower and higher half parts + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self; +} + +/// Trait for integers half the bit width of another integer. This is implemented for all +/// primitives except for `u128`, because it there is not a larger primitive. +#[doc(hidden)] +pub trait HInt: Int { + /// Integer that is double the bit width of the integer this trait is implemented for + type D: DInt + Int; + + /// Widens (using default extension) the integer to have double bit width + fn widen(self) -> Self::D; + /// Widens (zero extension only) the integer to have double bit width. This is needed to get + /// around problems with associated type bounds (such as `Int`) being unstable + fn zero_widen(self) -> Self::D; + /// Widens the integer to have double bit width and shifts the integer into the higher bits + fn widen_hi(self) -> Self::D; + /// Widening multiplication with zero widening. This cannot overflow. + fn zero_widen_mul(self, rhs: Self) -> Self::D; + /// Widening multiplication. This cannot overflow. + fn widen_mul(self, rhs: Self) -> Self::D; +} + +macro_rules! impl_d_int { + ($($X:ident $D:ident),*) => { + $( + impl DInt for $D { + type H = $X; + + fn lo(self) -> Self::H { + self as $X + } + fn hi(self) -> Self::H { + (self >> <$X as Int>::BITS) as $X + } + fn lo_hi(self) -> (Self::H, Self::H) { + (self.lo(), self.hi()) + } + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { + lo.zero_widen() | hi.widen_hi() + } + } + )* + }; +} + +macro_rules! impl_h_int { + ($($H:ident $uH:ident $X:ident),*) => { + $( + impl HInt for $H { + type D = $X; + + fn widen(self) -> Self::D { + self as $X + } + fn zero_widen(self) -> Self::D { + (self as $uH) as $X + } + fn widen_hi(self) -> Self::D { + (self as $X) << <$H as Int>::BITS + } + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen().wrapping_mul(rhs.zero_widen()) + } + fn widen_mul(self, rhs: Self) -> Self::D { + self.widen().wrapping_mul(rhs.widen()) + } + } + )* + }; +} + +impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); +impl_h_int!( + u8 u8 u16, + u16 u16 u32, + u32 u32 u64, + u64 u64 u128, + i8 u8 i16, + i16 u16 i32, + i32 u32 i64, + i64 u64 i128 +); + /// Trait to convert an integer to/from smaller parts pub(crate) trait LargeInt: Int { type LowHalf: Int; -- cgit 1.4.1-3-g733a5 From d5b7e2b6d3a16c3b08b710ca1412aa10ee35bafc Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Mon, 12 Oct 2020 17:59:34 -0500 Subject: Overhaul overflowing multiplication impls --- library/compiler-builtins/src/float/conv.rs | 6 +- library/compiler-builtins/src/int/mul.rs | 123 +++++++++++++++------------- 2 files changed, 71 insertions(+), 58 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 8a0fc6cb424..e9ca0f138ca 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -11,7 +11,7 @@ macro_rules! int_to_float { let mant_dig = <$fty>::SIGNIFICAND_BITS + 1; let exponent_bias = <$fty>::EXPONENT_BIAS; - let n = <$ity>::BITS; + let n = <$ity as Int>::BITS; let (s, a) = i.extract_sign(); let mut a = a; @@ -21,7 +21,7 @@ macro_rules! int_to_float { // exponent let mut e = sd - 1; - if <$ity>::BITS < mant_dig { + if <$ity as Int>::BITS < mant_dig { return <$fty>::from_parts( s, (e + exponent_bias) as <$fty as Float>::Int, @@ -165,7 +165,7 @@ macro_rules! float_to_int { let f = $f; let fixint_min = <$ity>::min_value(); let fixint_max = <$ity>::max_value(); - let fixint_bits = <$ity>::BITS as usize; + let fixint_bits = <$ity as Int>::BITS as usize; let fixint_unsigned = fixint_min == 0; let sign_bit = <$fty>::SIGN_MASK; diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 1e32560c2ae..e5c0afc1eb0 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,7 +1,5 @@ -use core::ops; - -use int::Int; use int::LargeInt; +use int::{DInt, HInt, Int}; trait Mul: LargeInt { fn mul(self, other: Self) -> Self { @@ -29,59 +27,72 @@ trait Mul: LargeInt { impl Mul for u64 {} impl Mul for i128 {} -trait Mulo: Int + ops::Neg { - fn mulo(self, other: Self, overflow: &mut i32) -> Self { - *overflow = 0; - let result = self.wrapping_mul(other); - if self == Self::min_value() { - if other != Self::ZERO && other != Self::ONE { - *overflow = 1; +pub(crate) trait UMulo: Int + DInt { + fn mulo(self, rhs: Self) -> (Self, bool) { + match (self.hi().is_zero(), rhs.hi().is_zero()) { + // overflow is guaranteed + (false, false) => (self.wrapping_mul(rhs), true), + (true, false) => { + let mul_lo = self.lo().widen_mul(rhs.lo()); + let mul_hi = self.lo().widen_mul(rhs.hi()); + let (mul, o) = mul_lo.overflowing_add(mul_hi.lo().widen_hi()); + (mul, o || !mul_hi.hi().is_zero()) } - return result; - } - if other == Self::min_value() { - if self != Self::ZERO && self != Self::ONE { - *overflow = 1; + (false, true) => { + let mul_lo = rhs.lo().widen_mul(self.lo()); + let mul_hi = rhs.lo().widen_mul(self.hi()); + let (mul, o) = mul_lo.overflowing_add(mul_hi.lo().widen_hi()); + (mul, o || !mul_hi.hi().is_zero()) } - return result; + // overflow is guaranteed to not happen, and use a smaller widening multiplication + (true, true) => (self.lo().widen_mul(rhs.lo()), false), } + } +} - let sa = self >> (Self::BITS - 1); - let abs_a = (self ^ sa) - sa; - let sb = other >> (Self::BITS - 1); - let abs_b = (other ^ sb) - sb; - let two = Self::ONE + Self::ONE; - if abs_a < two || abs_b < two { - return result; - } - if sa == sb { - if abs_a > Self::max_value().aborting_div(abs_b) { - *overflow = 1; +impl UMulo for u32 {} +impl UMulo for u64 {} +impl UMulo for u128 {} + +macro_rules! impl_signed_mulo { + ($fn:ident, $iD:ident, $uD:ident) => { + fn $fn(lhs: $iD, rhs: $iD) -> ($iD, bool) { + let mut lhs = lhs; + let mut rhs = rhs; + // the test against `mul_neg` below fails without this early return + if lhs == 0 || rhs == 0 { + return (0, false); } - } else { - if abs_a > Self::min_value().aborting_div(-abs_b) { - *overflow = 1; + + let lhs_neg = lhs < 0; + let rhs_neg = rhs < 0; + if lhs_neg { + lhs = lhs.wrapping_neg(); } - } - result - } -} + if rhs_neg { + rhs = rhs.wrapping_neg(); + } + let mul_neg = lhs_neg != rhs_neg; -impl Mulo for i32 {} -impl Mulo for i64 {} -impl Mulo for i128 {} + let (mul, o) = (lhs as $uD).mulo(rhs as $uD); + let mut mul = mul as $iD; -trait UMulo: Int { - fn mulo(self, other: Self, overflow: &mut i32) -> Self { - *overflow = 0; - let result = self.wrapping_mul(other); - if self > Self::max_value().aborting_div(other) { - *overflow = 1; + if mul_neg { + mul = mul.wrapping_neg(); + } + if (mul < 0) != mul_neg { + // this one check happens to catch all edge cases related to `$iD::MIN` + (mul, true) + } else { + (mul, o) + } } - result - } + }; } -impl UMulo for u128 {} + +impl_signed_mulo!(i32_overflowing_mul, i32, u32); +impl_signed_mulo!(i64_overflowing_mul, i64, u64); +impl_signed_mulo!(i128_overflowing_mul, i128, u128); intrinsics! { #[maybe_use_optimized_c_shim] @@ -95,27 +106,29 @@ intrinsics! { } pub extern "C" fn __mulosi4(a: i32, b: i32, oflow: &mut i32) -> i32 { - a.mulo(b, oflow) + let (mul, o) = i32_overflowing_mul(a, b); + *oflow = o as i32; + mul } pub extern "C" fn __mulodi4(a: i64, b: i64, oflow: &mut i32) -> i64 { - a.mulo(b, oflow) + let (mul, o) = i64_overflowing_mul(a, b); + *oflow = o as i32; + mul } #[unadjusted_on_win64] pub extern "C" fn __muloti4(a: i128, b: i128, oflow: &mut i32) -> i128 { - a.mulo(b, oflow) + let (mul, o) = i128_overflowing_mul(a, b); + *oflow = o as i32; + mul } pub extern "C" fn __rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = __muloti4(a, b, &mut oflow); - (r, oflow != 0) + i128_overflowing_mul(a, b) } pub extern "C" fn __rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.mulo(b, &mut oflow); - (r, oflow != 0) + a.mulo(b) } } -- cgit 1.4.1-3-g733a5 From fac884b0c47d6b5f7dfc23f8732b0b2ede315c99 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Mon, 12 Oct 2020 23:58:55 -0500 Subject: Completely replace `LargeInt` --- library/compiler-builtins/src/int/addsub.rs | 84 ++++++++--------------------- library/compiler-builtins/src/int/mod.rs | 44 --------------- library/compiler-builtins/src/int/mul.rs | 45 ++++++++-------- library/compiler-builtins/src/int/shift.rs | 72 +++++++++++-------------- library/compiler-builtins/src/macros.rs | 8 +-- 5 files changed, 83 insertions(+), 170 deletions(-) diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs index 0a88e2fc8f1..f4841e90f63 100644 --- a/library/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/src/int/addsub.rs @@ -1,25 +1,16 @@ -use int::Int; -use int::LargeInt; +use int::{DInt, Int}; -trait UAddSub: LargeInt { +trait UAddSub: DInt { fn uadd(self, other: Self) -> Self { - let (low, carry) = self.low().overflowing_add(other.low()); - let high = self.high().wrapping_add(other.high()); - let carry = if carry { - Self::HighHalf::ONE - } else { - Self::HighHalf::ZERO - }; - Self::from_parts(low, high.wrapping_add(carry)) + let (lo, carry) = self.lo().overflowing_add(other.lo()); + let hi = self.hi().wrapping_add(other.hi()); + let carry = if carry { Self::H::ONE } else { Self::H::ZERO }; + Self::from_lo_hi(lo, hi.wrapping_add(carry)) } fn uadd_one(self) -> Self { - let (low, carry) = self.low().overflowing_add(Self::LowHalf::ONE); - let carry = if carry { - Self::HighHalf::ONE - } else { - Self::HighHalf::ZERO - }; - Self::from_parts(low, self.high().wrapping_add(carry)) + let (lo, carry) = self.lo().overflowing_add(Self::H::ONE); + let carry = if carry { Self::H::ONE } else { Self::H::ZERO }; + Self::from_lo_hi(lo, self.hi().wrapping_add(carry)) } fn usub(self, other: Self) -> Self { let uneg = (!other).uadd_one(); @@ -48,19 +39,9 @@ trait Addo: AddSub where ::UnsignedInt: UAddSub, { - fn addo(self, other: Self, overflow: &mut i32) -> Self { - *overflow = 0; - let result = AddSub::add(self, other); - if other >= Self::ZERO { - if result < self { - *overflow = 1; - } - } else { - if result >= self { - *overflow = 1; - } - } - result + fn addo(self, other: Self) -> (Self, bool) { + let sum = AddSub::add(self, other); + (sum, (other < Self::ZERO) != (sum < self)) } } @@ -71,19 +52,9 @@ trait Subo: AddSub where ::UnsignedInt: UAddSub, { - fn subo(self, other: Self, overflow: &mut i32) -> Self { - *overflow = 0; - let result = AddSub::sub(self, other); - if other >= Self::ZERO { - if result > self { - *overflow = 1; - } - } else { - if result <= self { - *overflow = 1; - } - } - result + fn subo(self, other: Self) -> (Self, bool) { + let sum = AddSub::sub(self, other); + (sum, (other < Self::ZERO) != (self < sum)) } } @@ -92,43 +63,34 @@ impl Subo for u128 {} intrinsics! { pub extern "C" fn __rust_i128_add(a: i128, b: i128) -> i128 { - __rust_u128_add(a as _, b as _) as _ + AddSub::add(a,b) } pub extern "C" fn __rust_i128_addo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = a.addo(b, &mut oflow); - (r, oflow != 0) + a.addo(b) } pub extern "C" fn __rust_u128_add(a: u128, b: u128) -> u128 { - a.add(b) + AddSub::add(a,b) } pub extern "C" fn __rust_u128_addo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.addo(b, &mut oflow); - (r, oflow != 0) + a.addo(b) } - pub extern "C" fn __rust_i128_sub(a: i128, b: i128) -> i128 { - __rust_u128_sub(a as _, b as _) as _ + AddSub::sub(a,b) } pub extern "C" fn __rust_i128_subo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = a.subo(b, &mut oflow); - (r, oflow != 0) + a.subo(b) } pub extern "C" fn __rust_u128_sub(a: u128, b: u128) -> u128 { - a.sub(b) + AddSub::sub(a,b) } pub extern "C" fn __rust_u128_subo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.subo(b, &mut oflow); - (r, oflow != 0) + a.subo(b) } } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index da2263f6ef8..1ce3d92da38 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -384,50 +384,6 @@ impl_h_int!( i64 u64 i128 ); -/// Trait to convert an integer to/from smaller parts -pub(crate) trait LargeInt: Int { - type LowHalf: Int; - type HighHalf: Int; - - fn low(self) -> Self::LowHalf; - fn low_as_high(low: Self::LowHalf) -> Self::HighHalf; - fn high(self) -> Self::HighHalf; - fn high_as_low(low: Self::HighHalf) -> Self::LowHalf; - fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; -} - -macro_rules! large_int { - ($ty:ty, $tylow:ty, $tyhigh:ty, $halfbits:expr) => { - impl LargeInt for $ty { - type LowHalf = $tylow; - type HighHalf = $tyhigh; - - fn low(self) -> $tylow { - self as $tylow - } - fn low_as_high(low: $tylow) -> $tyhigh { - low as $tyhigh - } - fn high(self) -> $tyhigh { - (self >> $halfbits) as $tyhigh - } - fn high_as_low(high: $tyhigh) -> $tylow { - high as $tylow - } - fn from_parts(low: $tylow, high: $tyhigh) -> $ty { - low as $ty | ((high as $ty) << $halfbits) - } - } - }; -} - -large_int!(u32, u16, u16, 16); -large_int!(i32, u16, i16, 16); -large_int!(u64, u32, u32, 32); -large_int!(i64, u32, i32, 32); -large_int!(u128, u64, u64, 64); -large_int!(i128, u64, i64, 64); - /// Trait to express (possibly lossy) casting of integers pub(crate) trait CastInto: Copy { fn cast(self) -> T; diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index e5c0afc1eb0..a5238eeac70 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,26 +1,29 @@ -use int::LargeInt; use int::{DInt, HInt, Int}; -trait Mul: LargeInt { - fn mul(self, other: Self) -> Self { - let half_bits = Self::BITS / 4; - let lower_mask = !<::LowHalf>::ZERO >> half_bits; - let mut low = (self.low() & lower_mask).wrapping_mul(other.low() & lower_mask); - let mut t = low >> half_bits; - low &= lower_mask; - t += (self.low() >> half_bits).wrapping_mul(other.low() & lower_mask); - low += (t & lower_mask) << half_bits; - let mut high = Self::low_as_high(t >> half_bits); - t = low >> half_bits; - low &= lower_mask; - t += (other.low() >> half_bits).wrapping_mul(self.low() & lower_mask); - low += (t & lower_mask) << half_bits; - high += Self::low_as_high(t >> half_bits); - high += Self::low_as_high((self.low() >> half_bits).wrapping_mul(other.low() >> half_bits)); - high = high - .wrapping_add(self.high().wrapping_mul(Self::low_as_high(other.low()))) - .wrapping_add(Self::low_as_high(self.low()).wrapping_mul(other.high())); - Self::from_parts(low, high) +trait Mul: DInt +where + Self::H: DInt, +{ + fn mul(self, rhs: Self) -> Self { + // In order to prevent infinite recursion, we cannot use the `widen_mul` in this: + //self.lo().widen_mul(rhs.lo()) + // .wrapping_add(self.lo().wrapping_mul(rhs.hi()).widen_hi()) + // .wrapping_add(self.hi().wrapping_mul(rhs.lo()).widen_hi()) + + let lhs_lo = self.lo(); + let rhs_lo = rhs.lo(); + // construct the widening multiplication using only `Self::H` sized multiplications + let tmp_0 = lhs_lo.lo().zero_widen_mul(rhs_lo.lo()); + let tmp_1 = lhs_lo.lo().zero_widen_mul(rhs_lo.hi()); + let tmp_2 = lhs_lo.hi().zero_widen_mul(rhs_lo.lo()); + let tmp_3 = lhs_lo.hi().zero_widen_mul(rhs_lo.hi()); + // sum up all widening partials + let mul = Self::from_lo_hi(tmp_0, tmp_3) + .wrapping_add(tmp_1.zero_widen() << (Self::BITS / 4)) + .wrapping_add(tmp_2.zero_widen() << (Self::BITS / 4)); + // add the higher partials + mul.wrapping_add(lhs_lo.wrapping_mul(rhs.hi()).widen_hi()) + .wrapping_add(self.hi().wrapping_mul(rhs_lo).widen_hi()) } } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 674c3ee8ca7..20561786b2f 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,20 +1,18 @@ -use int::{Int, LargeInt}; +use int::{DInt, HInt, Int}; -trait Ashl: Int + LargeInt { +trait Ashl: DInt { /// Returns `a << b`, requires `b < Self::BITS` - fn ashl(self, offset: u32) -> Self - where - Self: LargeInt::LowHalf>, - { - let half_bits = Self::BITS / 2; - if offset & half_bits != 0 { - Self::from_parts(Int::ZERO, self.low() << (offset - half_bits)) - } else if offset == 0 { + fn ashl(self, shl: u32) -> Self { + let n_h = Self::H::BITS; + if shl & n_h != 0 { + // we only need `self.lo()` because `self.hi()` will be shifted out entirely + (self.lo() << (shl - n_h)).widen_hi() + } else if shl == 0 { self } else { - Self::from_parts( - self.low() << offset, - (self.high() << offset) | (self.low() >> (half_bits - offset)), + Self::from_lo_hi( + self.lo() << shl, + self.lo().logical_shr(n_h - shl) | (self.hi() << shl), ) } } @@ -24,25 +22,22 @@ impl Ashl for u32 {} impl Ashl for u64 {} impl Ashl for u128 {} -trait Ashr: Int + LargeInt { +trait Ashr: DInt { /// Returns arithmetic `a >> b`, requires `b < Self::BITS` - fn ashr(self, offset: u32) -> Self - where - Self: LargeInt::HighHalf as Int>::UnsignedInt>, - { - let half_bits = Self::BITS / 2; - if offset & half_bits != 0 { - Self::from_parts( - (self.high() >> (offset - half_bits)).unsigned(), - self.high() >> (half_bits - 1), + fn ashr(self, shr: u32) -> Self { + let n_h = Self::H::BITS; + if shr & n_h != 0 { + Self::from_lo_hi( + self.hi() >> (shr - n_h), + // smear the sign bit + self.hi() >> (n_h - 1), ) - } else if offset == 0 { + } else if shr == 0 { self } else { - let high_unsigned = self.high().unsigned(); - Self::from_parts( - (high_unsigned << (half_bits - offset)) | (self.low() >> offset), - self.high() >> offset, + Self::from_lo_hi( + self.lo().logical_shr(shr) | (self.hi() << (n_h - shr)), + self.hi() >> shr, ) } } @@ -52,21 +47,18 @@ impl Ashr for i32 {} impl Ashr for i64 {} impl Ashr for i128 {} -trait Lshr: Int + LargeInt { +trait Lshr: DInt { /// Returns logical `a >> b`, requires `b < Self::BITS` - fn lshr(self, offset: u32) -> Self - where - Self: LargeInt::LowHalf>, - { - let half_bits = Self::BITS / 2; - if offset & half_bits != 0 { - Self::from_parts(self.high() >> (offset - half_bits), Int::ZERO) - } else if offset == 0 { + fn lshr(self, shr: u32) -> Self { + let n_h = Self::H::BITS; + if shr & n_h != 0 { + self.hi().logical_shr(shr - n_h).zero_widen() + } else if shr == 0 { self } else { - Self::from_parts( - (self.high() << (half_bits - offset)) | (self.low() >> offset), - self.high() >> offset, + Self::from_lo_hi( + self.lo().logical_shr(shr) | (self.hi() << (n_h - shr)), + self.hi().logical_shr(shr), ) } } diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index b02f3ea5ced..56f27164a93 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -284,16 +284,16 @@ pub mod win64_128bit_abi_hack { impl From for U64x2 { fn from(i: i128) -> U64x2 { - use int::LargeInt; + use int::DInt; let j = i as u128; - U64x2(j.low(), j.high()) + U64x2(j.lo(), j.hi()) } } impl From for U64x2 { fn from(i: u128) -> U64x2 { - use int::LargeInt; - U64x2(i.low(), i.high()) + use int::DInt; + U64x2(i.lo(), i.hi()) } } } -- cgit 1.4.1-3-g733a5 From cb4e9755b8620c59407080fc9d2c6cf14f46947a Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Tue, 1 Dec 2020 23:16:26 -0600 Subject: Remove `WideInt` --- library/compiler-builtins/src/float/cmp.rs | 19 +++---------- library/compiler-builtins/src/float/div.rs | 10 +++---- library/compiler-builtins/src/float/mod.rs | 11 ++++++-- library/compiler-builtins/src/float/mul.rs | 30 ++++++++++++-------- library/compiler-builtins/src/int/mod.rs | 45 ------------------------------ 5 files changed, 36 insertions(+), 79 deletions(-) diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 20ab92e4b9a..79c26b09921 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -1,7 +1,7 @@ #![allow(unreachable_code)] use float::Float; -use int::{CastInto, Int}; +use int::Int; #[derive(Clone, Copy)] enum Result { @@ -31,13 +31,7 @@ impl Result { } } -fn cmp(a: F, b: F) -> Result -where - u32: CastInto, - F::Int: CastInto, - i32: CastInto, - F::Int: CastInto, -{ +fn cmp(a: F, b: F) -> Result { let one = F::Int::ONE; let zero = F::Int::ZERO; let szero = F::SignedInt::ZERO; @@ -90,13 +84,8 @@ where } } } -fn unord(a: F, b: F) -> bool -where - u32: CastInto, - F::Int: CastInto, - i32: CastInto, - F::Int: CastInto, -{ + +fn unord(a: F, b: F) -> bool { let one = F::Int::ONE; let sign_bit = F::SIGN_MASK as F::Int; diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 7c582a4408d..dd6467f88fb 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -1,5 +1,5 @@ use float::Float; -use int::{CastInto, Int, WideInt}; +use int::{CastInto, DInt, HInt, Int}; fn div32(a: F, b: F) -> F where @@ -7,7 +7,7 @@ where F::Int: CastInto, i32: CastInto, F::Int: CastInto, - F::Int: WideInt, + F::Int: HInt, { let one = F::Int::ONE; let zero = F::Int::ZERO; @@ -156,7 +156,7 @@ where // is the error in the reciprocal of b scaled by the maximum // possible value of a. As a consequence of this error bound, // either q or nextafter(q) is the correctly rounded - let (mut quotient, _) = ::wide_mul(a_significand << 1, reciprocal.cast()); + let mut quotient = (a_significand << 1).widen_mul(reciprocal.cast()).hi(); // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). // In either case, we are going to compute a residual of the form @@ -211,7 +211,7 @@ where F::Int: CastInto, i64: CastInto, F::Int: CastInto, - F::Int: WideInt, + F::Int: HInt, { let one = F::Int::ONE; let zero = F::Int::ZERO; @@ -394,7 +394,7 @@ where // We need a 64 x 64 multiply high to compute q, which isn't a basic // operation in C, so we need to be a little bit fussy. - let (mut quotient, _) = ::wide_mul(a_significand << 2, reciprocal.cast()); + let mut quotient = (a_significand << 2).widen_mul(reciprocal.cast()).hi(); // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). // In either case, we are going to compute a residual of the form diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 06e9aad4b42..34b3c6ac1e8 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -13,7 +13,8 @@ pub mod pow; pub mod sub; /// Trait for some basic operations on floats -pub(crate) trait Float: +#[doc(hidden)] +pub trait Float: Copy + PartialEq + PartialOrd @@ -66,7 +67,6 @@ pub(crate) trait Float: /// Returns `self` transmuted to `Self::SignedInt` fn signed_repr(self) -> Self::SignedInt; - #[cfg(test)] /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be /// represented in multiple different ways. This method returns `true` if two NaNs are /// compared. @@ -80,6 +80,9 @@ pub(crate) trait Float: /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); + + /// Returns if `self` is subnormal + fn is_subnormal(&self) -> bool; } // FIXME: Some of this can be removed if RFC Issue #1424 is resolved @@ -106,7 +109,6 @@ macro_rules! float_impl { fn signed_repr(self) -> Self::SignedInt { unsafe { mem::transmute(self) } } - #[cfg(test)] fn eq_repr(self, rhs: Self) -> bool { if self.is_nan() && rhs.is_nan() { true @@ -133,6 +135,9 @@ macro_rules! float_impl { significand << shift as Self::Int, ) } + fn is_subnormal(&self) -> bool { + (self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO + } } }; } diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 7b28793c8e7..540e7bdcfe3 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -1,5 +1,5 @@ use float::Float; -use int::{CastInto, Int, WideInt}; +use int::{CastInto, DInt, HInt, Int}; fn mul(a: F, b: F) -> F where @@ -7,7 +7,7 @@ where F::Int: CastInto, i32: CastInto, F::Int: CastInto, - F::Int: WideInt, + F::Int: HInt, { let one = F::Int::ONE; let zero = F::Int::ZERO; @@ -112,8 +112,9 @@ where // have (exponentBits + 2) integral digits, all but two of which must be // zero. Normalizing this result is just a conditional left-shift by one // and bumping the exponent accordingly. - let (mut product_high, mut product_low) = - ::wide_mul(a_significand, b_significand << exponent_bits); + let (mut product_low, mut product_high) = a_significand + .widen_mul(b_significand << exponent_bits) + .lo_hi(); let a_exponent_i32: i32 = a_exponent.cast(); let b_exponent_i32: i32 = b_exponent.cast(); @@ -126,7 +127,8 @@ where if (product_high & implicit_bit) != zero { product_exponent = product_exponent.wrapping_add(1); } else { - ::wide_shift_left(&mut product_high, &mut product_low, 1); + product_high = (product_high << 1) | (product_low >> (bits - 1)); + product_low <<= 1; } // If we have overflowed the type, return +/- infinity. @@ -142,17 +144,23 @@ where // handle this case separately, but we make it a special case to // simplify the shift logic. let shift = one.wrapping_sub(product_exponent.cast()).cast(); - if shift >= bits as i32 { + if shift >= bits { return F::from_repr(product_sign); } // Otherwise, shift the significand of the result so that the round // bit is the high bit of productLo. - ::wide_shift_right_with_sticky( - &mut product_high, - &mut product_low, - shift, - ) + if shift < bits { + let sticky = product_low << (bits - shift); + product_low = product_high << (bits - shift) | product_low >> shift | sticky; + product_high >>= shift; + } else if shift < (2 * bits) { + let sticky = product_high << (2 * bits - shift) | product_low; + product_low = product_high >> (shift - bits) | sticky; + product_high = zero; + } else { + product_high = zero; + } } else { // Result is normal before rounding; insert the exponent. product_high &= significand_mask; diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 1ce3d92da38..d23028263d8 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -408,48 +408,3 @@ cast_into!(u64); cast_into!(i64); cast_into!(u128); cast_into!(i128); - -pub(crate) trait WideInt: Int { - type Output: Int; - - fn wide_mul(self, other: Self) -> (Self, Self); - fn wide_shift_left(&mut self, low: &mut Self, count: i32); - fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32); -} - -macro_rules! impl_wide_int { - ($ty:ty, $tywide:ty, $bits:expr) => { - impl WideInt for $ty { - type Output = $ty; - - fn wide_mul(self, other: Self) -> (Self, Self) { - let product = (self as $tywide).wrapping_mul(other as $tywide); - ((product >> ($bits as $ty)) as $ty, product as $ty) - } - - fn wide_shift_left(&mut self, low: &mut Self, count: i32) { - *self = (*self << count) | (*low >> ($bits - count)); - *low = *low << count; - } - - fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32) { - if count < $bits { - let sticky = *low << ($bits - count); - *low = *self << ($bits - count) | *low >> count | sticky; - *self = *self >> count; - } else if count < 2 * $bits { - let sticky = *self << (2 * $bits - count) | *low; - *low = *self >> (count - $bits) | sticky; - *self = 0; - } else { - let sticky = *self | *low; - *self = sticky; - *self = 0; - } - } - } - }; -} - -impl_wide_int!(u32, u64, 32); -impl_wide_int!(u64, u128, 64); -- cgit 1.4.1-3-g733a5 From 26681724f35c6d941abbdcffc426255bc4a4adb2 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Tue, 1 Dec 2020 23:09:57 -0600 Subject: replace some transmutes --- library/compiler-builtins/src/float/mod.rs | 9 +++------ library/compiler-builtins/testcrate/build.rs | 8 ++++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 34b3c6ac1e8..c4b6901613f 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,4 +1,3 @@ -use core::mem; use core::ops; use super::int::Int; @@ -85,8 +84,6 @@ pub trait Float: fn is_subnormal(&self) -> bool; } -// FIXME: Some of this can be removed if RFC Issue #1424 is resolved -// https://github.com/rust-lang/rfcs/issues/1424 macro_rules! float_impl { ($ty:ident, $ity:ident, $sity:ident, $bits:expr, $significand_bits:expr) => { impl Float for $ty { @@ -104,10 +101,10 @@ macro_rules! float_impl { const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); fn repr(self) -> Self::Int { - unsafe { mem::transmute(self) } + self.to_bits() } fn signed_repr(self) -> Self::SignedInt { - unsafe { mem::transmute(self) } + self.to_bits() as Self::SignedInt } fn eq_repr(self, rhs: Self) -> bool { if self.is_nan() && rhs.is_nan() { @@ -117,7 +114,7 @@ macro_rules! float_impl { } } fn from_repr(a: Self::Int) -> Self { - unsafe { mem::transmute(a) } + Self::from_bits(a) } fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { Self::from_repr( diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 1baa6a96607..1ecd0179e88 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -633,7 +633,7 @@ fn main() { if a.0.is_nan() || b.0.is_nan() || c.is_nan() - || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } + || c.abs() <= f64::from_bits(4503599627370495u64) { None } else { @@ -651,7 +651,7 @@ fn main() { if a.0.is_nan() || b.0.is_nan() || c.is_nan() - || c.abs() <= unsafe { mem::transmute(16777215u32) } + || c.abs() <= f32::from_bits(16777215u32) { None } else { @@ -671,7 +671,7 @@ fn main() { if a.0.is_nan() || b.0.is_nan() || c.is_nan() - || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } + || c.abs() <= f64::from_bits(4503599627370495u64) { None } else { @@ -689,7 +689,7 @@ fn main() { if a.0.is_nan() || b.0.is_nan() || c.is_nan() - || c.abs() <= unsafe { mem::transmute(16777215u32) } + || c.abs() <= f32::from_bits(16777215u32) { None } else { -- cgit 1.4.1-3-g733a5 From f61c411e2b51ad1d8af1d6e8bdb46ece7b669ff1 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Sat, 7 Nov 2020 13:09:51 -0600 Subject: fix some clippy warnings --- library/compiler-builtins/src/mem/impls.rs | 8 +++----- library/compiler-builtins/src/mem/mod.rs | 4 ++-- library/compiler-builtins/src/mem/x86_64.rs | 4 ++-- library/compiler-builtins/testcrate/build.rs | 5 +---- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index 6bd1a7ba1db..b3eef9901dd 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -1,10 +1,8 @@ -use super::c_int; - #[inline(always)] pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, n: usize) { let mut i = 0; while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); + *dest.add(i) = *src.add(i); i += 1; } } @@ -15,7 +13,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, n: usize) { let mut i = n; while i != 0 { i -= 1; - *dest.offset(i as isize) = *src.offset(i as isize); + *dest.add(i) = *src.add(i); } } @@ -23,7 +21,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, n: usize) { pub unsafe fn set_bytes(s: *mut u8, c: u8, n: usize) { let mut i = 0; while i < n { - *s.offset(i as isize) = c; + *s.add(i) = c; i += 1; } } diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index adb7c2c64c9..107762c43a6 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -45,8 +45,8 @@ pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { let mut i = 0; while i < n { - let a = *s1.offset(i as isize); - let b = *s2.offset(i as isize); + let a = *s1.add(i); + let b = *s2.add(i); if a != b { return a as i32 - b as i32; } diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 7eefd8099b9..8cbbdf779a6 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -59,8 +59,8 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { "cld", byte_count = in(reg) byte_count, inout("rcx") qword_count => _, - inout("rdi") dest.offset(count as isize).wrapping_sub(8) => _, - inout("rsi") src.offset(count as isize).wrapping_sub(8) => _, + inout("rdi") dest.add(count).wrapping_sub(8) => _, + inout("rsi") src.add(count).wrapping_sub(8) => _, options(nostack) ); } diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 1ecd0179e88..39c2486c692 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -648,10 +648,7 @@ fn main() { return None; } let c = a.0 / b.0; - if a.0.is_nan() - || b.0.is_nan() - || c.is_nan() - || c.abs() <= f32::from_bits(16777215u32) + if a.0.is_nan() || b.0.is_nan() || c.is_nan() || c.abs() <= f32::from_bits(16777215u32) { None } else { -- cgit 1.4.1-3-g733a5 From 69a3c571f7f8273d21d1a6a35f8d536142ab1270 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Mon, 7 Dec 2020 23:25:42 -0600 Subject: Completely overhaul fuzz testing adds testing for almost every numerical intrinsic --- library/compiler-builtins/src/int/mod.rs | 11 + library/compiler-builtins/testcrate/Cargo.toml | 2 +- library/compiler-builtins/testcrate/src/lib.rs | 258 +++++++++++++++++++++ .../compiler-builtins/testcrate/tests/addsub.rs | 109 +++++++++ library/compiler-builtins/testcrate/tests/cmp.rs | 52 +++++ library/compiler-builtins/testcrate/tests/conv.rs | 125 ++++++++++ .../compiler-builtins/testcrate/tests/div_rem.rs | 147 ++++++------ .../testcrate/tests/leading_zeros.rs | 54 ----- library/compiler-builtins/testcrate/tests/misc.rs | 134 +++++++++++ library/compiler-builtins/testcrate/tests/mul.rs | 114 +++++++++ library/compiler-builtins/testcrate/tests/shift.rs | 60 +++++ 11 files changed, 937 insertions(+), 129 deletions(-) create mode 100644 library/compiler-builtins/testcrate/tests/addsub.rs create mode 100644 library/compiler-builtins/testcrate/tests/cmp.rs create mode 100644 library/compiler-builtins/testcrate/tests/conv.rs delete mode 100644 library/compiler-builtins/testcrate/tests/leading_zeros.rs create mode 100644 library/compiler-builtins/testcrate/tests/misc.rs create mode 100644 library/compiler-builtins/testcrate/tests/mul.rs create mode 100644 library/compiler-builtins/testcrate/tests/shift.rs diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index d23028263d8..cb94803a470 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -72,6 +72,9 @@ pub trait Int: /// Prevents the need for excessive conversions between signed and unsigned fn logical_shr(self, other: u32) -> Self; + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + // copied from primitive integers, but put in a trait fn is_zero(self) -> bool; fn max_value() -> Self; @@ -251,6 +254,10 @@ macro_rules! int_impl { me } + fn abs_diff(self, other: Self) -> Self { + (self.wrapping_sub(other) as $ity).wrapping_abs() as $uty + } + int_impl_common!($uty, $bits); } @@ -274,6 +281,10 @@ macro_rules! int_impl { me as $ity } + fn abs_diff(self, other: Self) -> $uty { + self.wrapping_sub(other).wrapping_abs() as $uty + } + int_impl_common!($ity, $bits); } }; diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index ce8df2d12c5..ff9a6a453bb 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -11,7 +11,7 @@ doctest = false [build-dependencies] rand = "0.7" -[dev-dependencies] +[dependencies] # For fuzzing tests we want a deterministic seedable RNG. We also eliminate potential # problems with system RNGs on the variety of platforms this crate is tested on. # `xoshiro128**` is used for its quality, size, and speed at generating `u32` shift amounts. diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 0c9ac1ac8e4..9bd155f6f10 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -1 +1,259 @@ +//! This crate is for integration testing and fuzz testing of functions in `compiler-builtins`. This +//! includes publicly documented intrinsics and some internal alternative implementation functions +//! such as `usize_leading_zeros_riscv` (which are tested because they are configured for +//! architectures not tested by the CI). +//! +//! The general idea is to use a combination of edge case testing and randomized fuzz testing. The +//! edge case testing is crucial for checking cases like where both inputs are equal or equal to +//! special values such as `i128::MIN`, which is unlikely for the random fuzzer by itself to +//! encounter. The randomized fuzz testing is specially designed to cover wide swaths of search +//! space in as few iterations as possible. See `fuzz_values` in `testcrate/tests/misc.rs` for an +//! example. +//! +//! Some floating point tests are disabled for specific architectures, because they do not have +//! correct rounding. #![no_std] + +use compiler_builtins::float::Float; +use compiler_builtins::int::Int; + +use rand_xoshiro::rand_core::{RngCore, SeedableRng}; +use rand_xoshiro::Xoshiro128StarStar; + +/// Sets the number of fuzz iterations run for most tests. In practice, the vast majority of bugs +/// are caught by the edge case testers. Most of the remaining bugs triggered by more complex +/// sequences are caught well within 10_000 fuzz iterations. For classes of algorithms like division +/// that are vulnerable to rare edge cases, we want 1_000_000 iterations to be more confident. In +/// practical CI, however, we only want to run the more strenuous test once to catch algorithmic +/// level bugs, and run the 10_000 iteration test on most targets. Target-dependent bugs are likely +/// to involve miscompilation and misconfiguration that is likely to break algorithms in quickly +/// caught ways. We choose to configure `N = 1_000_000` iterations for `x86_64` targets (and if +/// debug assertions are disabled. Tests without `--release` would take too long) which are likely +/// to have fast hardware, and run `N = 10_000` for all other targets. +pub const N: u32 = if cfg!(target_arch = "x86_64") && !cfg!(debug_assertions) { + 1_000_000 +} else { + 10_000 +}; + +/// Random fuzzing step. When run several times, it results in excellent fuzzing entropy such as: +/// 11110101010101011110111110011111 +/// 10110101010100001011101011001010 +/// 1000000000000000 +/// 10000000000000110111110000001010 +/// 1111011111111101010101111110101 +/// 101111111110100000000101000000 +/// 10000000110100000000100010101 +/// 1010101010101000 +fn fuzz_step(rng: &mut Xoshiro128StarStar, x: &mut I) { + let ones = !I::ZERO; + let bit_indexing_mask: u32 = I::BITS - 1; + // It happens that all the RNG we need can come from one call. 7 bits are needed to index a + // worst case 128 bit integer, and there are 4 indexes that need to be made plus 4 bits for + // selecting operations + let rng32 = rng.next_u32(); + + // Randomly OR, AND, and XOR randomly sized and shifted continuous strings of + // ones with `lhs` and `rhs`. + let r0 = bit_indexing_mask & rng32; + let r1 = bit_indexing_mask & (rng32 >> 7); + let mask = ones.wrapping_shl(r0).rotate_left(r1); + match (rng32 >> 14) % 4 { + 0 => *x |= mask, + 1 => *x &= mask, + // both 2 and 3 to make XORs as common as ORs and ANDs combined + _ => *x ^= mask, + } + + // Alternating ones and zeros (e.x. 0b1010101010101010). This catches second-order + // problems that might occur for algorithms with two modes of operation (potentially + // there is some invariant that can be broken and maintained via alternating between modes, + // breaking the algorithm when it reaches the end). + let mut alt_ones = I::ONE; + for _ in 0..(I::BITS / 2) { + alt_ones <<= 2; + alt_ones |= I::ONE; + } + let r0 = bit_indexing_mask & (rng32 >> 16); + let r1 = bit_indexing_mask & (rng32 >> 23); + let mask = alt_ones.wrapping_shl(r0).rotate_left(r1); + match rng32 >> 30 { + 0 => *x |= mask, + 1 => *x &= mask, + _ => *x ^= mask, + } +} + +// We need macros like this, because `#![no_std]` prevents us from using iterators +macro_rules! edge_cases { + ($I:ident, $case:ident, $inner:block) => { + for i0 in 0..$I::FUZZ_NUM { + let mask_lo = (!$I::UnsignedInt::ZERO).wrapping_shr($I::FUZZ_LENGTHS[i0] as u32); + for i1 in i0..I::FUZZ_NUM { + let mask_hi = + (!$I::UnsignedInt::ZERO).wrapping_shl($I::FUZZ_LENGTHS[i1 - i0] as u32); + let $case = I::from_unsigned(mask_lo & mask_hi); + $inner + } + } + }; +} + +/// Feeds a series of fuzzing inputs to `f`. The fuzzer first uses an algorithm designed to find +/// edge cases, followed by a more random fuzzer that runs `n` times. +pub fn fuzz(n: u32, mut f: F) { + // edge case tester. Calls `f` 210 times for u128. + // zero gets skipped by the loop + f(I::ZERO); + edge_cases!(I, case, { + f(case); + }); + + // random fuzzer + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x: I = Int::ZERO; + for _ in 0..n { + fuzz_step(&mut rng, &mut x); + f(x) + } +} + +/// The same as `fuzz`, except `f` has two inputs. +pub fn fuzz_2(n: u32, f: F) { + // Check cases where the first and second inputs are zero. Both call `f` 210 times for `u128`. + edge_cases!(I, case, { + f(I::ZERO, case); + }); + edge_cases!(I, case, { + f(case, I::ZERO); + }); + // Nested edge tester. Calls `f` 44100 times for `u128`. + edge_cases!(I, case0, { + edge_cases!(I, case1, { + f(case0, case1); + }) + }); + + // random fuzzer + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x: I = I::ZERO; + let mut y: I = I::ZERO; + for _ in 0..n { + fuzz_step(&mut rng, &mut x); + fuzz_step(&mut rng, &mut y); + f(x, y) + } +} + +/// Tester for shift functions +pub fn fuzz_shift(f: F) { + // Shift functions are very simple and do not need anything other than shifting a small + // set of random patterns for every fuzz length. + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x: I = Int::ZERO; + for i in 0..I::FUZZ_NUM { + fuzz_step(&mut rng, &mut x); + f(x, Int::ZERO); + f(x, I::FUZZ_LENGTHS[i] as u32); + } +} + +fn fuzz_float_step(rng: &mut Xoshiro128StarStar, f: &mut F) { + let rng32 = rng.next_u32(); + // we need to fuzz the different parts of the float separately, because the masking on larger + // significands will tend to set the exponent to all ones or all zeros frequently + + // sign bit fuzzing + let sign = (rng32 & 1) != 0; + + // exponent fuzzing. Only 4 bits for the selector needed. + let ones = (F::Int::ONE << F::EXPONENT_BITS) - F::Int::ONE; + let r0 = (rng32 >> 1) % F::EXPONENT_BITS; + let r1 = (rng32 >> 5) % F::EXPONENT_BITS; + // custom rotate shift. Note that `F::Int` is unsigned, so we can shift right without smearing + // the sign bit. + let mask = if r1 == 0 { + ones.wrapping_shr(r0) + } else { + let tmp = ones.wrapping_shr(r0); + (tmp.wrapping_shl(r1) | tmp.wrapping_shr(F::EXPONENT_BITS - r1)) & ones + }; + let mut exp = (f.repr() & F::EXPONENT_MASK) >> F::SIGNIFICAND_BITS; + match (rng32 >> 9) % 4 { + 0 => exp |= mask, + 1 => exp &= mask, + _ => exp ^= mask, + } + + // significand fuzzing + let mut sig = f.repr() & F::SIGNIFICAND_MASK; + fuzz_step(rng, &mut sig); + sig &= F::SIGNIFICAND_MASK; + + *f = F::from_parts(sign, exp, sig); +} + +macro_rules! float_edge_cases { + ($F:ident, $case:ident, $inner:block) => { + for exponent in [ + F::Int::ZERO, + F::Int::ONE, + F::Int::ONE << (F::EXPONENT_BITS / 2), + (F::Int::ONE << (F::EXPONENT_BITS - 1)) - F::Int::ONE, + F::Int::ONE << (F::EXPONENT_BITS - 1), + (F::Int::ONE << (F::EXPONENT_BITS - 1)) + F::Int::ONE, + (F::Int::ONE << F::EXPONENT_BITS) - F::Int::ONE, + ] + .iter() + { + for significand in [ + F::Int::ZERO, + F::Int::ONE, + F::Int::ONE << (F::SIGNIFICAND_BITS / 2), + (F::Int::ONE << (F::SIGNIFICAND_BITS - 1)) - F::Int::ONE, + F::Int::ONE << (F::SIGNIFICAND_BITS - 1), + (F::Int::ONE << (F::SIGNIFICAND_BITS - 1)) + F::Int::ONE, + (F::Int::ONE << F::SIGNIFICAND_BITS) - F::Int::ONE, + ] + .iter() + { + for sign in [false, true].iter() { + let $case = F::from_parts(*sign, *exponent, *significand); + $inner + } + } + } + }; +} + +pub fn fuzz_float(n: u32, f: E) { + float_edge_cases!(F, case, { + f(case); + }); + + // random fuzzer + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x = F::ZERO; + for _ in 0..n { + fuzz_float_step(&mut rng, &mut x); + f(x); + } +} + +pub fn fuzz_float_2(n: u32, f: E) { + float_edge_cases!(F, case0, { + float_edge_cases!(F, case1, { + f(case0, case1); + }); + }); + + // random fuzzer + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x = F::ZERO; + let mut y = F::ZERO; + for _ in 0..n { + fuzz_float_step(&mut rng, &mut x); + fuzz_float_step(&mut rng, &mut y); + f(x, y) + } +} diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs new file mode 100644 index 00000000000..ff56668b78b --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -0,0 +1,109 @@ +use testcrate::*; + +macro_rules! sum { + ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { + $( + fuzz_2(N, |x: $i, y: $i| { + let add0 = x.wrapping_add(y); + let sub0 = x.wrapping_sub(y); + let add1: $i = $fn_add(x, y); + let sub1: $i = $fn_sub(x, y); + if add0 != add1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_add), x, y, add0, add1 + ); + } + if sub0 != sub1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_sub), x, y, sub0, sub1 + ); + } + }); + )* + }; +} + +macro_rules! overflowing_sum { + ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { + $( + fuzz_2(N, |x: $i, y: $i| { + let add0 = x.overflowing_add(y); + let sub0 = x.overflowing_sub(y); + let add1: ($i, bool) = $fn_add(x, y); + let sub1: ($i, bool) = $fn_sub(x, y); + if add0.0 != add1.0 || add0.1 != add1.1 { + panic!( + "{}({}, {}): std: {:?}, builtins: {:?}", + stringify!($fn_add), x, y, add0, add1 + ); + } + if sub0.0 != sub1.0 || sub0.1 != sub1.1 { + panic!( + "{}({}, {}): std: {:?}, builtins: {:?}", + stringify!($fn_sub), x, y, sub0, sub1 + ); + } + }); + )* + }; +} + +#[test] +fn addsub() { + use compiler_builtins::int::addsub::{ + __rust_i128_add, __rust_i128_addo, __rust_i128_sub, __rust_i128_subo, __rust_u128_add, + __rust_u128_addo, __rust_u128_sub, __rust_u128_subo, + }; + + // Integer addition and subtraction is very simple, so 100 fuzzing passes should be plenty. + sum!( + u128, __rust_u128_add, __rust_u128_sub; + i128, __rust_i128_add, __rust_i128_sub; + ); + overflowing_sum!( + u128, __rust_u128_addo, __rust_u128_subo; + i128, __rust_i128_addo, __rust_i128_subo; + ); +} + +macro_rules! float_sum { + ($($f:ty, $fn_add:ident, $fn_sub:ident);*;) => { + $( + fuzz_float_2(N, |x: $f, y: $f| { + let add0 = x + y; + let sub0 = x - y; + let add1: $f = $fn_add(x, y); + let sub1: $f = $fn_sub(x, y); + if !Float::eq_repr(add0, add1) { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_add), x, y, add0, add1 + ); + } + if !Float::eq_repr(sub0, sub1) { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_sub), x, y, sub0, sub1 + ); + } + }); + )* + }; +} + +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +#[test] +fn float_addsub() { + use compiler_builtins::float::{ + add::{__adddf3, __addsf3}, + sub::{__subdf3, __subsf3}, + Float, + }; + + float_sum!( + f32, __addsf3, __subsf3; + f64, __adddf3, __subdf3; + ); +} diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs new file mode 100644 index 00000000000..d359b65d7e4 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -0,0 +1,52 @@ +use testcrate::*; + +macro_rules! cmp { + ($x:ident, $y:ident, $($unordered_val:expr, $fn:ident);*;) => { + $( + let cmp0 = if $x.is_nan() || $y.is_nan() { + $unordered_val + } else if $x < $y { + -1 + } else if $x == $y { + 0 + } else { + 1 + }; + let cmp1 = $fn($x, $y); + if cmp0 != cmp1 { + panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1); + } + )* + }; +} + +#[test] +fn float_comparisons() { + use compiler_builtins::float::cmp::{ + __eqdf2, __eqsf2, __gedf2, __gesf2, __gtdf2, __gtsf2, __ledf2, __lesf2, __ltdf2, __ltsf2, + __nedf2, __nesf2, __unorddf2, __unordsf2, + }; + + fuzz_float_2(N, |x: f32, y: f32| { + assert_eq!(__unordsf2(x, y) != 0, x.is_nan() || y.is_nan()); + cmp!(x, y, + 1, __ltsf2; + 1, __lesf2; + 1, __eqsf2; + -1, __gesf2; + -1, __gtsf2; + 1, __nesf2; + ); + }); + fuzz_float_2(N, |x: f64, y: f64| { + assert_eq!(__unorddf2(x, y) != 0, x.is_nan() || y.is_nan()); + cmp!(x, y, + 1, __ltdf2; + 1, __ledf2; + 1, __eqdf2; + -1, __gedf2; + -1, __gtdf2; + 1, __nedf2; + ); + }); +} diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs new file mode 100644 index 00000000000..7cdbf9fbb69 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -0,0 +1,125 @@ +use testcrate::*; + +macro_rules! i_to_f { + ($($from:ty, $into:ty, $fn:ident);*;) => { + $( + fuzz(N, |x: $from| { + let f0 = x as $into; + let f1: $into = $fn(x); + // This makes sure that the conversion produced the best rounding possible, and does + // this independent of `x as $into` rounding correctly. + // This assumes that float to integer conversion is correct. + let y_minus_ulp = <$into>::from_bits(f1.to_bits().wrapping_sub(1)) as $from; + let y = f1 as $from; + let y_plus_ulp = <$into>::from_bits(f1.to_bits().wrapping_add(1)) as $from; + let error_minus = <$from as Int>::abs_diff(y_minus_ulp, x); + let error = <$from as Int>::abs_diff(y, x); + let error_plus = <$from as Int>::abs_diff(y_plus_ulp, x); + // The first two conditions check that none of the two closest float values are + // strictly closer in representation to `x`. The second makes sure that rounding is + // towards even significand if two float values are equally close to the integer. + if error_minus < error + || error_plus < error + || ((error_minus == error || error_plus == error) + && ((f0.to_bits() & 1) != 0)) + { + panic!( + "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", + stringify!($fn), + x, + f1.to_bits(), + y_minus_ulp, + y, + y_plus_ulp, + error_minus, + error, + error_plus, + ); + } + // Test against native conversion. We disable testing on all `x86` because of + // rounding bugs with `i686`. `powerpc` also has the same rounding bug. + if f0 != f1 && !cfg!(any( + target_arch = "x86", + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + f0, + f1, + ); + } + }); + )* + }; +} + +#[test] +fn int_to_float() { + use compiler_builtins::float::conv::{ + __floatdidf, __floatdisf, __floatsidf, __floatsisf, __floattidf, __floattisf, + __floatundidf, __floatundisf, __floatunsidf, __floatunsisf, __floatuntidf, __floatuntisf, + }; + use compiler_builtins::int::Int; + + i_to_f!( + u32, f32, __floatunsisf; + u32, f64, __floatunsidf; + i32, f32, __floatsisf; + i32, f64, __floatsidf; + u64, f32, __floatundisf; + u64, f64, __floatundidf; + i64, f32, __floatdisf; + i64, f64, __floatdidf; + u128, f32, __floatuntisf; + u128, f64, __floatuntidf; + i128, f32, __floattisf; + i128, f64, __floattidf; + ); +} + +macro_rules! f_to_i { + ($x:ident, $($f:ty, $fn:ident);*;) => { + $( + // it is undefined behavior in the first place to do conversions with NaNs + if !$x.is_nan() { + let conv0 = $x as $f; + let conv1: $f = $fn($x); + if conv0 != conv1 { + panic!("{}({}): std: {}, builtins: {}", stringify!($fn), $x, conv0, conv1); + } + } + )* + }; +} + +#[test] +fn float_to_int() { + use compiler_builtins::float::conv::{ + __fixdfdi, __fixdfsi, __fixdfti, __fixsfdi, __fixsfsi, __fixsfti, __fixunsdfdi, + __fixunsdfsi, __fixunsdfti, __fixunssfdi, __fixunssfsi, __fixunssfti, + }; + + fuzz_float(N, |x: f32| { + f_to_i!(x, + u32, __fixunssfsi; + u64, __fixunssfdi; + u128, __fixunssfti; + i32, __fixsfsi; + i64, __fixsfdi; + i128, __fixsfti; + ); + }); + fuzz_float(N, |x: f64| { + f_to_i!(x, + u32, __fixunsdfsi; + u64, __fixunsdfdi; + u128, __fixunsdfti; + i32, __fixdfsi; + i64, __fixdfdi; + i128, __fixdfti; + ); + }); +} diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index 199fa9db71c..0007c15aee5 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -1,8 +1,9 @@ -use rand_xoshiro::rand_core::{RngCore, SeedableRng}; -use rand_xoshiro::Xoshiro128StarStar; - use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; -use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4}; +use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc}; +use testcrate::*; + +// Division algorithms have by far the nastiest and largest number of edge cases, and experience shows +// that sometimes 100_000 iterations of the random fuzzer is needed. /// Creates intensive test functions for division functions of a certain size macro_rules! test { @@ -16,14 +17,17 @@ macro_rules! test { ) => { #[test] fn $test_name() { - fn assert_invariants(lhs: $uX, rhs: $uX) { - let rem: &mut $uX = &mut 0; - let quo: $uX = $unsigned_name(lhs, rhs, Some(rem)); - let rem = *rem; + fuzz_2(N, |lhs, rhs| { + if rhs == 0 { + return; + } + + let mut rem: $uX = 0; + let quo: $uX = $unsigned_name(lhs, rhs, Some(&mut rem)); if rhs <= rem || (lhs != rhs.wrapping_mul(quo).wrapping_add(rem)) { panic!( "unsigned division function failed with lhs:{} rhs:{} \ - expected:({}, {}) found:({}, {})", + std:({}, {}) builtins:({}, {})", lhs, rhs, lhs.wrapping_div(rhs), @@ -55,7 +59,7 @@ macro_rules! test { if incorrect_rem || lhs != rhs.wrapping_mul(quo).wrapping_add(rem) { panic!( "signed division function failed with lhs:{} rhs:{} \ - expected:({}, {}) found:({}, {})", + std:({}, {}) builtins:({}, {})", lhs, rhs, lhs.wrapping_div(rhs), @@ -64,70 +68,7 @@ macro_rules! test { rem ); } - } - - // Specially designed random fuzzer - let mut rng = Xoshiro128StarStar::seed_from_u64(0); - let mut lhs: $uX = 0; - let mut rhs: $uX = 0; - // all ones constant - let ones: $uX = !0; - // Alternating ones and zeros (e.x. 0b1010101010101010). This catches second-order - // problems that might occur for algorithms with two modes of operation (potentially - // there is some invariant that can be broken for large `duo` and maintained via - // alternating between modes, breaking the algorithm when it reaches the end). - let mut alt_ones: $uX = 1; - for _ in 0..($n / 2) { - alt_ones <<= 2; - alt_ones |= 1; - } - // creates a mask for indexing the bits of the type - let bit_indexing_mask = $n - 1; - for _ in 0..1_000_000 { - // Randomly OR, AND, and XOR randomly sized and shifted continuous strings of - // ones with `lhs` and `rhs`. This results in excellent fuzzing entropy such as: - // lhs:10101010111101000000000100101010 rhs: 1010101010000000000000001000001 - // lhs:10101010111101000000000101001010 rhs: 1010101010101010101010100010100 - // lhs:10101010111101000000000101001010 rhs:11101010110101010101010100001110 - // lhs:10101010000000000000000001001010 rhs:10100010100000000000000000001010 - // lhs:10101010000000000000000001001010 rhs: 10101010101010101000 - // lhs:10101010000000000000000001100000 rhs:11111111111101010101010101001111 - // lhs:10101010000000101010101011000000 rhs:11111111111101010101010100000111 - // lhs:10101010101010101010101011101010 rhs: 1010100000000000000 - // lhs:11111111110101101010101011010111 rhs: 1010100000000000000 - // The msb is set half of the time by the fuzzer, but `assert_invariants` tests - // both the signed and unsigned functions. - let r0: u32 = bit_indexing_mask & rng.next_u32(); - let r1: u32 = bit_indexing_mask & rng.next_u32(); - let mask = ones.wrapping_shr(r0).rotate_left(r1); - match rng.next_u32() % 8 { - 0 => lhs |= mask, - 1 => lhs &= mask, - // both 2 and 3 to make XORs as common as ORs and ANDs combined, otherwise - // the entropy gets destroyed too often - 2 | 3 => lhs ^= mask, - 4 => rhs |= mask, - 5 => rhs &= mask, - _ => rhs ^= mask, - } - // do the same for alternating ones and zeros - let r0: u32 = bit_indexing_mask & rng.next_u32(); - let r1: u32 = bit_indexing_mask & rng.next_u32(); - let mask = alt_ones.wrapping_shr(r0).rotate_left(r1); - match rng.next_u32() % 8 { - 0 => lhs |= mask, - 1 => lhs &= mask, - // both 2 and 3 to make XORs as common as ORs and ANDs combined, otherwise - // the entropy gets destroyed too often - 2 | 3 => lhs ^= mask, - 4 => rhs |= mask, - 5 => rhs &= mask, - _ => rhs ^= mask, - } - if rhs != 0 { - assert_invariants(lhs, rhs); - } - } + }); } }; } @@ -135,3 +76,61 @@ macro_rules! test { test!(32, u32, i32, div_rem_si4, __udivmodsi4, __divmodsi4); test!(64, u64, i64, div_rem_di4, __udivmoddi4, __divmoddi4); test!(128, u128, i128, div_rem_ti4, __udivmodti4, __divmodti4); + +#[test] +fn divide_sparc() { + fuzz_2(N, |lhs, rhs| { + if rhs == 0 { + return; + } + + let mut rem: u128 = 0; + let quo: u128 = u128_divide_sparc(lhs, rhs, &mut rem); + if rhs <= rem || (lhs != rhs.wrapping_mul(quo).wrapping_add(rem)) { + panic!( + "u128_divide_sparc({}, {}): \ + std:({}, {}), builtins:({}, {})", + lhs, + rhs, + lhs.wrapping_div(rhs), + lhs.wrapping_rem(rhs), + quo, + rem + ); + } + }); +} + +macro_rules! float { + ($($i:ty, $fn:ident);*;) => { + $( + fuzz_float_2(N, |x: $i, y: $i| { + let quo0 = x / y; + let quo1: $i = $fn(x, y); + // division of subnormals is not currently handled + if !(Float::is_subnormal(&quo0) || Float::is_subnormal(&quo1)) { + if !Float::eq_repr(quo0, quo1) { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, quo0, quo1 + ); + } + } + }); + )* + }; +} + +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +#[test] +fn float_div() { + use compiler_builtins::float::{ + div::{__divdf3, __divsf3}, + Float, + }; + + float!( + f32, __divsf3; + f64, __divdf3; + ); +} diff --git a/library/compiler-builtins/testcrate/tests/leading_zeros.rs b/library/compiler-builtins/testcrate/tests/leading_zeros.rs deleted file mode 100644 index b857d9e0c31..00000000000 --- a/library/compiler-builtins/testcrate/tests/leading_zeros.rs +++ /dev/null @@ -1,54 +0,0 @@ -use rand_xoshiro::rand_core::{RngCore, SeedableRng}; -use rand_xoshiro::Xoshiro128StarStar; - -use compiler_builtins::int::__clzsi2; -use compiler_builtins::int::leading_zeros::{ - usize_leading_zeros_default, usize_leading_zeros_riscv, -}; - -#[test] -fn __clzsi2_test() { - // Binary fuzzer. We cannot just send a random number directly to `__clzsi2()`, because we need - // large sequences of zeros to test. This XORs, ANDs, and ORs random length strings of 1s to - // `x`. ORs insure sequences of ones, ANDs insures sequences of zeros, and XORs are not often - // destructive but add entropy. - let mut rng = Xoshiro128StarStar::seed_from_u64(0); - let mut x = 0usize; - // creates a mask for indexing the bits of the type - let bit_indexing_mask = usize::MAX.count_ones() - 1; - // 10000 iterations is enough to make sure edge cases like single set bits are tested and to go - // through many paths. - for _ in 0..10_000 { - let r0 = bit_indexing_mask & rng.next_u32(); - // random length of ones - let ones: usize = !0 >> r0; - let r1 = bit_indexing_mask & rng.next_u32(); - // random circular shift - let mask = ones.rotate_left(r1); - match rng.next_u32() % 4 { - 0 => x |= mask, - 1 => x &= mask, - // both 2 and 3 to make XORs as common as ORs and ANDs combined - _ => x ^= mask, - } - let lz = x.leading_zeros() as usize; - let lz0 = __clzsi2(x); - let lz1 = usize_leading_zeros_default(x); - let lz2 = usize_leading_zeros_riscv(x); - if lz0 != lz { - panic!("__clzsi2({}): expected: {}, found: {}", x, lz, lz0); - } - if lz1 != lz { - panic!( - "usize_leading_zeros_default({}): expected: {}, found: {}", - x, lz, lz1 - ); - } - if lz2 != lz { - panic!( - "usize_leading_zeros_riscv({}): expected: {}, found: {}", - x, lz, lz2 - ); - } - } -} diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs new file mode 100644 index 00000000000..d31e3e6b6a7 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -0,0 +1,134 @@ +use testcrate::*; + +/// Make sure that the the edge case tester and randomized tester don't break, and list examples of +/// fuzz values for documentation purposes. +#[test] +fn fuzz_values() { + const VALS: [u16; 47] = [ + 0b0, // edge cases + 0b1111111111111111, + 0b1111111111111110, + 0b1111111111111100, + 0b1111111110000000, + 0b1111111100000000, + 0b1110000000000000, + 0b1100000000000000, + 0b1000000000000000, + 0b111111111111111, + 0b111111111111110, + 0b111111111111100, + 0b111111110000000, + 0b111111100000000, + 0b110000000000000, + 0b100000000000000, + 0b11111111111111, + 0b11111111111110, + 0b11111111111100, + 0b11111110000000, + 0b11111100000000, + 0b10000000000000, + 0b111111111, + 0b111111110, + 0b111111100, + 0b110000000, + 0b100000000, + 0b11111111, + 0b11111110, + 0b11111100, + 0b10000000, + 0b111, + 0b110, + 0b100, + 0b11, + 0b10, + 0b1, + 0b1010110100000, // beginning of random fuzzing + 0b1100011001011010, + 0b1001100101001111, + 0b1101010100011010, + 0b100010001, + 0b1000000000000000, + 0b1100000000000101, + 0b1100111101010101, + 0b1100010111111111, + 0b1111110101111111, + ]; + let mut i = 0; + fuzz(10, |x: u16| { + assert_eq!(x, VALS[i]); + i += 1; + }); +} + +#[test] +fn leading_zeros() { + use compiler_builtins::int::__clzsi2; + use compiler_builtins::int::leading_zeros::{ + usize_leading_zeros_default, usize_leading_zeros_riscv, + }; + fuzz(N, |x: usize| { + let lz = x.leading_zeros() as usize; + let lz0 = __clzsi2(x); + let lz1 = usize_leading_zeros_default(x); + let lz2 = usize_leading_zeros_riscv(x); + if lz0 != lz { + panic!("__clzsi2({}): std: {}, builtins: {}", x, lz, lz0); + } + if lz1 != lz { + panic!( + "usize_leading_zeros_default({}): std: {}, builtins: {}", + x, lz, lz1 + ); + } + if lz2 != lz { + panic!( + "usize_leading_zeros_riscv({}): std: {}, builtins: {}", + x, lz, lz2 + ); + } + }) +} + +#[test] +fn float_extend() { + fuzz_float(N, |x: f32| { + let tmp0 = x as f64; + let tmp1: f64 = compiler_builtins::float::extend::__extendsfdf2(x); + if !compiler_builtins::float::Float::eq_repr(tmp0, tmp1) { + panic!("__extendsfdf2({}): std: {}, builtins: {}", x, tmp0, tmp1); + } + }); +} + +// This doesn't quite work because of issues related to +// https://github.com/rust-lang/rust/issues/73920. +// TODO how do we resolve this? +/* +macro_rules! pow { + ($($f:ty, $fn:ident);*;) => { + $( + fuzz_float_2(N, |x: $f, y: $f| { + let n = y as i32; + let tmp0: $f = x.powi(n); + let tmp1: $f = $fn(x, n); + if tmp0 != tmp1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, tmp0, tmp1 + ); + } + }); + )* + }; +} + +#[test] +fn float_pow() { + use compiler_builtins::float::pow::{__powidf2, __powisf2}; + + pow!( + f32, __powisf2; + f64, __powidf2; + ); +} +*/ diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs new file mode 100644 index 00000000000..8b97ea46c35 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -0,0 +1,114 @@ +use testcrate::*; + +macro_rules! mul { + ($($i:ty, $fn:ident);*;) => { + $( + fuzz_2(N, |x: $i, y: $i| { + let mul0 = x.wrapping_mul(y); + let mul1: $i = $fn(x, y); + if mul0 != mul1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, mul0, mul1 + ); + } + }); + )* + }; +} + +#[test] +fn mul() { + use compiler_builtins::int::mul::{__muldi3, __multi3}; + + mul!( + u64, __muldi3; + i128, __multi3; + ); +} + +macro_rules! overflowing_mul { + ($($i:ty, $fn:ident);*;) => { + $( + fuzz_2(N, |x: $i, y: $i| { + let (mul0, o0) = x.overflowing_mul(y); + let mut o1 = 0i32; + let mul1: $i = $fn(x, y, &mut o1); + let o1 = o1 != 0; + if mul0 != mul1 || o0 != o1 { + panic!( + "{}({}, {}): std: ({}, {}), builtins: ({}, {})", + stringify!($fn), x, y, mul0, o0, mul1, o1 + ); + } + }); + )* + }; +} + +#[test] +fn overflowing_mul() { + use compiler_builtins::int::mul::{ + __mulodi4, __mulosi4, __muloti4, __rust_i128_mulo, __rust_u128_mulo, + }; + + overflowing_mul!( + i32, __mulosi4; + i64, __mulodi4; + i128, __muloti4; + ); + fuzz_2(N, |x: u128, y: u128| { + let (mul0, o0) = x.overflowing_mul(y); + let (mul1, o1) = __rust_u128_mulo(x, y); + if mul0 != mul1 || o0 != o1 { + panic!( + "__rust_u128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", + x, y, mul0, o0, mul1, o1 + ); + } + let x = x as i128; + let y = y as i128; + let (mul0, o0) = x.overflowing_mul(y); + let (mul1, o1) = __rust_i128_mulo(x, y); + if mul0 != mul1 || o0 != o1 { + panic!( + "__rust_i128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", + x, y, mul0, o0, mul1, o1 + ); + } + }); +} + +macro_rules! float_mul { + ($($f:ty, $fn:ident);*;) => { + $( + fuzz_float_2(N, |x: $f, y: $f| { + let mul0 = x * y; + let mul1: $f = $fn(x, y); + // multiplication of subnormals is not currently handled + if !(Float::is_subnormal(&mul0) || Float::is_subnormal(&mul1)) { + if !Float::eq_repr(mul0, mul1) { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, mul0, mul1 + ); + } + } + }); + )* + }; +} + +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +#[test] +fn float_mul() { + use compiler_builtins::float::{ + mul::{__muldf3, __mulsf3}, + Float, + }; + + float_mul!( + f32, __mulsf3; + f64, __muldf3; + ); +} diff --git a/library/compiler-builtins/testcrate/tests/shift.rs b/library/compiler-builtins/testcrate/tests/shift.rs new file mode 100644 index 00000000000..ecb13a133e1 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/shift.rs @@ -0,0 +1,60 @@ +use testcrate::*; + +macro_rules! shift { + ($($i:ty, $fn_std:ident, $fn_builtins:ident);*;) => { + $( + fuzz_shift(|x: $i, s: u32| { + let tmp0: $i = x.$fn_std(s); + let tmp1: $i = $fn_builtins(x, s); + if tmp0 != tmp1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_builtins), x, s, tmp0, tmp1 + ); + } + }); + )* + }; +} + +macro_rules! overflowing_shift { + ($($i:ty, $fn_std:ident, $fn_builtins:ident);*;) => { + $( + fuzz_shift(|x: $i, s: u32| { + let tmp0: $i = x.$fn_std(s); + let (tmp1, o1): ($i, bool) = $fn_builtins(x, s.into()); + if tmp0 != tmp1 || o1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_builtins), x, s, tmp0, tmp1 + ); + } + }); + )* + }; +} + +#[test] +fn shift() { + use compiler_builtins::int::shift::{ + __ashldi3, __ashlsi3, __ashlti3, __ashrdi3, __ashrsi3, __ashrti3, __lshrdi3, __lshrsi3, + __lshrti3, __rust_i128_shlo, __rust_i128_shro, __rust_u128_shlo, __rust_u128_shro, + }; + shift!( + u32, wrapping_shl, __ashlsi3; + u64, wrapping_shl, __ashldi3; + u128, wrapping_shl, __ashlti3; + i32, wrapping_shr, __ashrsi3; + i64, wrapping_shr, __ashrdi3; + i128, wrapping_shr, __ashrti3; + u32, wrapping_shr, __lshrsi3; + u64, wrapping_shr, __lshrdi3; + u128, wrapping_shr, __lshrti3; + ); + overflowing_shift!( + u128, wrapping_shl, __rust_u128_shlo; + i128, wrapping_shl, __rust_i128_shlo; + u128, wrapping_shr, __rust_u128_shro; + i128, wrapping_shr, __rust_i128_shro; + ); +} -- cgit 1.4.1-3-g733a5 From 176ae46ff852517fcf3670053db26ad67b309d62 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 9 Dec 2020 12:17:29 +0000 Subject: Bump to 0.1.37 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0c5fd15315e..c9ac6d0a761 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.36" +version = "0.1.37" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 7645c0b869292a07e287cc6862971016f72ed34b Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 11 Dec 2020 21:56:10 +0900 Subject: Use the AT&T syntax to support old LLVM on rust-lang/rust --- .../src/int/specialized_div_rem/mod.rs | 6 ++-- library/compiler-builtins/src/mem/x86_64.rs | 41 ++++++++++++---------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index eaeb030e389..14e758fc5a8 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -169,12 +169,13 @@ unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { unsafe { // divides the combined registers rdx:rax (`duo` is split into two 64 bit parts to do this) // by `div`. The quotient is stored in rax and the remainder in rdx. + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. asm!( "div {0}", in(reg) div, inlateout("rax") duo_lo => quo, inlateout("rdx") duo_hi => rem, - options(pure, nomem, nostack) + options(att_syntax, pure, nomem, nostack) ); } (quo, rem) @@ -255,12 +256,13 @@ unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { unsafe { // divides the combined registers rdx:rax (`duo` is split into two 32 bit parts to do this) // by `div`. The quotient is stored in rax and the remainder in rdx. + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. asm!( "div {0}", in(reg) div, inlateout("rax") duo_lo => quo, inlateout("rdx") duo_hi => rem, - options(pure, nomem, nostack) + options(att_syntax, pure, nomem, nostack) ); } (quo, rem) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 8cbbdf779a6..abdb8eb67e0 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -19,12 +19,13 @@ #[inline(always)] #[cfg(target_feature = "ermsb")] pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. asm!( - "rep movsb [rdi], [rsi]", + "repe movsb (%rsi), (%rdi)", inout("rcx") count => _, inout("rdi") dest => _, inout("rsi") src => _, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } @@ -33,15 +34,16 @@ pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. asm!( - "rep movsq [rdi], [rsi]", - "mov ecx, {byte_count:e}", - "rep movsb [rdi], [rsi]", + "repe movsq (%rsi), (%rdi)", + "mov {byte_count:e}, %ecx", + "repe movsb (%rsi), (%rdi)", byte_count = in(reg) byte_count, inout("rcx") qword_count => _, inout("rdi") dest => _, inout("rsi") src => _, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } @@ -49,31 +51,33 @@ pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. asm!( "std", - "rep movsq [rdi], [rsi]", - "mov ecx, {byte_count:e}", - "add rdi, 7", - "add rsi, 7", - "rep movsb [rdi], [rsi]", + "repe movsq (%rsi), (%rdi)", + "movl {byte_count:e}, %ecx", + "addq $7, %rdi", + "addq $7, %rsi", + "repe movsb (%rsi), (%rdi)", "cld", byte_count = in(reg) byte_count, inout("rcx") qword_count => _, inout("rdi") dest.add(count).wrapping_sub(8) => _, inout("rsi") src.add(count).wrapping_sub(8) => _, - options(nostack) + options(att_syntax, nostack) ); } #[inline(always)] #[cfg(target_feature = "ermsb")] pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. asm!( - "rep stosb [rdi], al", + "repe stosb %al, (%rdi)", inout("rcx") count => _, inout("rdi") dest => _, inout("al") c => _, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ) } @@ -82,14 +86,15 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. asm!( - "rep stosq [rdi], rax", - "mov ecx, {byte_count:e}", - "rep stosb [rdi], al", + "repe stosq %rax, (%rdi)", + "mov {byte_count:e}, %ecx", + "repe stosb %al, (%rdi)", byte_count = in(reg) byte_count, inout("rcx") qword_count => _, inout("rdi") dest => _, in("rax") (c as u64) * 0x0101010101010101, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } -- cgit 1.4.1-3-g733a5 From f0a9f9e3e1905b220d086fdb6453ecade95c50c2 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 12 Dec 2020 12:11:21 +0000 Subject: Bump to 0.1.38 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c9ac6d0a761..901b33c3f7f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.37" +version = "0.1.38" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From e5b667554e81efe2129f412a6eea5d8739c5f990 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Mon, 4 Jan 2021 09:17:44 -0600 Subject: Remove `count_ones` (#399) --- library/compiler-builtins/src/int/mod.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index cb94803a470..06054c84af6 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -90,7 +90,6 @@ pub trait Int: fn aborting_div(self, other: Self) -> Self; fn aborting_rem(self, other: Self) -> Self; fn leading_zeros(self) -> u32; - fn count_ones(self) -> u32; } fn unwrap(t: Option) -> T { @@ -229,10 +228,6 @@ macro_rules! int_impl_common { fn leading_zeros(self) -> u32 { ::leading_zeros(self) } - - fn count_ones(self) -> u32 { - ::count_ones(self) - } }; } -- cgit 1.4.1-3-g733a5 From 80fb6752fad5ea4963b0cd5630e1767971e8f765 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 6 Jan 2021 23:39:48 +0000 Subject: Bump to 0.1.39 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 901b33c3f7f..f1052d59d67 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.38" +version = "0.1.39" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 57205c0b8654a121a07c70e63abfd5cf761f5eaa Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 5 Feb 2021 23:40:17 +0100 Subject: Use the newly stabilized BITS constant on the integer types --- library/compiler-builtins/src/int/mod.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 06054c84af6..e50b2e60838 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -100,8 +100,8 @@ fn unwrap(t: Option) -> T { } macro_rules! int_impl_common { - ($ty:ty, $bits:expr) => { - const BITS: u32 = $bits; + ($ty:ty) => { + const BITS: u32 = ::BITS; const ZERO: Self = 0; const ONE: Self = 1; @@ -232,7 +232,7 @@ macro_rules! int_impl_common { } macro_rules! int_impl { - ($ity:ty, $uty:ty, $bits:expr) => { + ($ity:ty, $uty:ty) => { impl Int for $uty { type OtherSign = $ity; type UnsignedInt = $uty; @@ -253,7 +253,7 @@ macro_rules! int_impl { (self.wrapping_sub(other) as $ity).wrapping_abs() as $uty } - int_impl_common!($uty, $bits); + int_impl_common!($uty); } impl Int for $ity { @@ -280,17 +280,17 @@ macro_rules! int_impl { self.wrapping_sub(other).wrapping_abs() as $uty } - int_impl_common!($ity, $bits); + int_impl_common!($ity); } }; } -int_impl!(isize, usize, usize::MAX.count_ones()); -int_impl!(i8, u8, 8); -int_impl!(i16, u16, 16); -int_impl!(i32, u32, 32); -int_impl!(i64, u64, 64); -int_impl!(i128, u128, 128); +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); /// Trait for integers twice the bit width of another integer. This is implemented for all /// primitives except for `u8`, because there is not a smaller primitive. -- cgit 1.4.1-3-g733a5 From c75621f12c8844a353226914b94259db2cf23c44 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 21 Feb 2021 11:36:47 +0100 Subject: Remove unused __rust_* shift intrinsics They are rust specific and used by neither cg_llvm nor cg_clif --- library/compiler-builtins/src/int/shift.rs | 16 -------------- library/compiler-builtins/testcrate/tests/shift.rs | 25 +--------------------- 2 files changed, 1 insertion(+), 40 deletions(-) diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 20561786b2f..59909929e58 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -113,20 +113,4 @@ intrinsics! { pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 { a.lshr(b) } - - pub extern "C" fn __rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { - (__ashlti3(a as _, b as _) as _, b >= 128) - } - - pub extern "C" fn __rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { - (__ashlti3(a, b as _), b >= 128) - } - - pub extern "C" fn __rust_i128_shro(a: i128, b: u128) -> (i128, bool) { - (__ashrti3(a, b as _), b >= 128) - } - - pub extern "C" fn __rust_u128_shro(a: u128, b: u128) -> (u128, bool) { - (__lshrti3(a, b as _), b >= 128) - } } diff --git a/library/compiler-builtins/testcrate/tests/shift.rs b/library/compiler-builtins/testcrate/tests/shift.rs index ecb13a133e1..7a76b164685 100644 --- a/library/compiler-builtins/testcrate/tests/shift.rs +++ b/library/compiler-builtins/testcrate/tests/shift.rs @@ -17,28 +17,11 @@ macro_rules! shift { }; } -macro_rules! overflowing_shift { - ($($i:ty, $fn_std:ident, $fn_builtins:ident);*;) => { - $( - fuzz_shift(|x: $i, s: u32| { - let tmp0: $i = x.$fn_std(s); - let (tmp1, o1): ($i, bool) = $fn_builtins(x, s.into()); - if tmp0 != tmp1 || o1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn_builtins), x, s, tmp0, tmp1 - ); - } - }); - )* - }; -} - #[test] fn shift() { use compiler_builtins::int::shift::{ __ashldi3, __ashlsi3, __ashlti3, __ashrdi3, __ashrsi3, __ashrti3, __lshrdi3, __lshrsi3, - __lshrti3, __rust_i128_shlo, __rust_i128_shro, __rust_u128_shlo, __rust_u128_shro, + __lshrti3, }; shift!( u32, wrapping_shl, __ashlsi3; @@ -51,10 +34,4 @@ fn shift() { u64, wrapping_shr, __lshrdi3; u128, wrapping_shr, __lshrti3; ); - overflowing_shift!( - u128, wrapping_shl, __rust_u128_shlo; - i128, wrapping_shl, __rust_i128_shlo; - u128, wrapping_shr, __rust_u128_shro; - i128, wrapping_shr, __rust_i128_shro; - ); } -- cgit 1.4.1-3-g733a5 From 9ba75196bda13e70473ceb12f998f7a324577279 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Sun, 28 Mar 2021 12:24:08 +0200 Subject: add "readme"-key to Cargo.toml in order for this crate to have a preview on crates.io --- library/compiler-builtins/libm/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index d9d6680409e..106de51dfb6 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -6,6 +6,7 @@ documentation = "https://docs.rs/libm" keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" +readme = "README.md" repository = "https://github.com/rust-lang/libm" version = "0.2.1" edition = "2018" -- cgit 1.4.1-3-g733a5 From 880ec8bb83fc367907942a36e0ccadda877e16cf Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 2 Apr 2021 12:36:57 +0100 Subject: Disable AArch64 FP-to-int tests This is a temporary workaround for https://github.com/rust-lang/rust/issues/83467 --- library/compiler-builtins/testcrate/tests/conv.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 7cdbf9fbb69..17c31a8a00e 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -95,6 +95,8 @@ macro_rules! f_to_i { }; } +// AArch64 tests are currently broken due to https://github.com/rust-lang/rust/issues/83467 +#[cfg(not(target_arch = "aarch64"))] #[test] fn float_to_int() { use compiler_builtins::float::conv::{ -- cgit 1.4.1-3-g733a5 From 0ce47b3c1f200f59e5459eb50fb6c2715c3b2259 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Thu, 10 Dec 2020 17:00:45 -0600 Subject: fix abs_diff bug --- library/compiler-builtins/src/int/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index e50b2e60838..a186a95aa66 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -250,7 +250,11 @@ macro_rules! int_impl { } fn abs_diff(self, other: Self) -> Self { - (self.wrapping_sub(other) as $ity).wrapping_abs() as $uty + if self < other { + other.wrapping_sub(self) + } else { + self.wrapping_sub(other) + } } int_impl_common!($uty); -- cgit 1.4.1-3-g733a5 From ec4fc5dab5718fa0ef048d9aec88784e4d2fe5fd Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Tue, 8 Dec 2020 19:28:05 -0600 Subject: refactor float conversion --- library/compiler-builtins/src/float/conv.rs | 299 ++++++++++----------- library/compiler-builtins/src/float/mod.rs | 39 ++- library/compiler-builtins/src/float/pow.rs | 3 +- library/compiler-builtins/src/int/mod.rs | 70 ++--- library/compiler-builtins/src/lib.rs | 5 - .../compiler-builtins/testcrate/tests/div_rem.rs | 2 +- library/compiler-builtins/testcrate/tests/mul.rs | 2 +- 7 files changed, 198 insertions(+), 222 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index e9ca0f138ca..8c46e4d2e7a 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,90 +1,88 @@ use float::Float; -use int::Int; - -macro_rules! int_to_float { - ($i:expr, $ity:ty, $fty:ty) => {{ - let i = $i; - if i == 0 { - return 0.0; - } - - let mant_dig = <$fty>::SIGNIFICAND_BITS + 1; - let exponent_bias = <$fty>::EXPONENT_BIAS; - - let n = <$ity as Int>::BITS; - let (s, a) = i.extract_sign(); - let mut a = a; - - // number of significant digits - let sd = n - a.leading_zeros(); - - // exponent - let mut e = sd - 1; +use int::{CastInto, Int}; + +fn int_to_float(i: I) -> F +where + F::Int: CastInto, + F::Int: CastInto, + I::UnsignedInt: CastInto, + u32: CastInto, +{ + if i == I::ZERO { + return F::ZERO; + } - if <$ity as Int>::BITS < mant_dig { - return <$fty>::from_parts( - s, - (e + exponent_bias) as <$fty as Float>::Int, - (a as <$fty as Float>::Int) << (mant_dig - e - 1), - ); - } + let two = I::UnsignedInt::ONE + I::UnsignedInt::ONE; + let four = two + two; + let sign = i < I::ZERO; + let mut x = Int::abs_diff(i, I::ZERO); + + // number of significant digits in the integer + let i_sd = I::BITS - x.leading_zeros(); + // significant digits for the float, including implicit bit + let f_sd = F::SIGNIFICAND_BITS + 1; + + // exponent + let mut exp = i_sd - 1; + + if I::BITS < f_sd { + return F::from_parts( + sign, + (exp + F::EXPONENT_BIAS).cast(), + x.cast() << (f_sd - exp - 1), + ); + } - a = if sd > mant_dig { - /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx - * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR - * 12345678901234567890123456 - * 1 = msb 1 bit - * P = bit MANT_DIG-1 bits to the right of 1 - * Q = bit MANT_DIG bits to the right of 1 - * R = "or" of all bits to the right of Q - */ - let mant_dig_plus_one = mant_dig + 1; - let mant_dig_plus_two = mant_dig + 2; - a = if sd == mant_dig_plus_one { - a << 1 - } else if sd == mant_dig_plus_two { - a - } else { - (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt - | ((a & <$ity as Int>::UnsignedInt::max_value()) - .wrapping_shl((n + mant_dig_plus_two) - sd) - != 0) as <$ity as Int>::UnsignedInt - }; - - /* finish: */ - a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */ - a += 1; /* round - this step may add a significant bit */ - a >>= 2; /* dump Q and R */ - - /* a is now rounded to mant_dig or mant_dig+1 bits */ - if (a & (1 << mant_dig)) != 0 { - a >>= 1; - e += 1; - } - a - /* a is now rounded to mant_dig bits */ + x = if i_sd > f_sd { + // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + // 12345678901234567890123456 + // 1 = the implicit bit + // P = bit f_sd-1 bits to the right of 1 + // Q = bit f_sd bits to the right of 1 + // R = "or" of all bits to the right of Q + let f_sd_add2 = f_sd + 2; + x = if i_sd == (f_sd + 1) { + x << 1 + } else if i_sd == f_sd_add2 { + x } else { - a.wrapping_shl(mant_dig - sd) - /* a is now rounded to mant_dig bits */ + (x >> (i_sd - f_sd_add2)) + | Int::from_bool( + (x & I::UnsignedInt::MAX).wrapping_shl((I::BITS + f_sd_add2) - i_sd) + != Int::ZERO, + ) }; - <$fty>::from_parts( - s, - (e + exponent_bias) as <$fty as Float>::Int, - a as <$fty as Float>::Int, - ) - }}; + // R |= P + x |= Int::from_bool((x & four) != I::UnsignedInt::ZERO); + // round - this step may add a significant bit + x += Int::ONE; + // dump Q and R + x >>= 2; + + // a is now rounded to f_sd or f_sd+1 bits + if (x & (I::UnsignedInt::ONE << f_sd)) != Int::ZERO { + x >>= 1; + exp += 1; + } + x + } else { + x.wrapping_shl(f_sd - i_sd) + }; + + F::from_parts(sign, (exp + F::EXPONENT_BIAS).cast(), x.cast()) } intrinsics! { #[arm_aeabi_alias = __aeabi_i2f] pub extern "C" fn __floatsisf(i: i32) -> f32 { - int_to_float!(i, i32, f32) + int_to_float(i) } #[arm_aeabi_alias = __aeabi_i2d] pub extern "C" fn __floatsidf(i: i32) -> f64 { - int_to_float!(i, i32, f64) + int_to_float(i) } #[maybe_use_optimized_c_shim] @@ -95,7 +93,7 @@ intrinsics! { if cfg!(target_arch = "x86_64") { i as f32 } else { - int_to_float!(i, i64, f32) + int_to_float(i) } } @@ -107,181 +105,172 @@ intrinsics! { if cfg!(target_arch = "x86_64") { i as f64 } else { - int_to_float!(i, i64, f64) + int_to_float(i) } } #[unadjusted_on_win64] pub extern "C" fn __floattisf(i: i128) -> f32 { - int_to_float!(i, i128, f32) + int_to_float(i) } #[unadjusted_on_win64] pub extern "C" fn __floattidf(i: i128) -> f64 { - int_to_float!(i, i128, f64) + int_to_float(i) } #[arm_aeabi_alias = __aeabi_ui2f] pub extern "C" fn __floatunsisf(i: u32) -> f32 { - int_to_float!(i, u32, f32) + int_to_float(i) } #[arm_aeabi_alias = __aeabi_ui2d] pub extern "C" fn __floatunsidf(i: u32) -> f64 { - int_to_float!(i, u32, f64) + int_to_float(i) } #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_ul2f] pub extern "C" fn __floatundisf(i: u64) -> f32 { - int_to_float!(i, u64, f32) + int_to_float(i) } #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { - int_to_float!(i, u64, f64) + int_to_float(i) } #[unadjusted_on_win64] pub extern "C" fn __floatuntisf(i: u128) -> f32 { - int_to_float!(i, u128, f32) + int_to_float(i) } #[unadjusted_on_win64] pub extern "C" fn __floatuntidf(i: u128) -> f64 { - int_to_float!(i, u128, f64) + int_to_float(i) } } -#[derive(PartialEq)] -enum Sign { - Positive, - Negative, -} +fn float_to_int(f: F) -> I +where + F::ExpInt: CastInto, + u32: CastInto, + F::Int: CastInto, +{ + // converting NaNs is UB, so we don't consider them + + let sign = f.sign(); + let mut exp = f.exp(); -macro_rules! float_to_int { - ($f:expr, $fty:ty, $ity:ty) => {{ - let f = $f; - let fixint_min = <$ity>::min_value(); - let fixint_max = <$ity>::max_value(); - let fixint_bits = <$ity as Int>::BITS as usize; - let fixint_unsigned = fixint_min == 0; - - let sign_bit = <$fty>::SIGN_MASK; - let significand_bits = <$fty>::SIGNIFICAND_BITS as usize; - let exponent_bias = <$fty>::EXPONENT_BIAS as usize; - //let exponent_max = <$fty>::exponent_max() as usize; - - // Break a into sign, exponent, significand - let a_rep = <$fty>::repr(f); - let a_abs = a_rep & !sign_bit; - - // this is used to work around -1 not being available for unsigned - let sign = if (a_rep & sign_bit) == 0 { - Sign::Positive + // if less than one or unsigned & negative + if (exp < F::EXPONENT_BIAS.cast()) || (!I::SIGNED && sign) { + return I::ZERO; + } + exp -= F::EXPONENT_BIAS.cast(); + + // If the value is too large for `I`, saturate. + let bits: F::ExpInt = I::BITS.cast(); + let max = if I::SIGNED { + bits - F::ExpInt::ONE + } else { + bits + }; + if max <= exp { + return if sign { + // It happens that I::MIN is handled correctly + I::MIN } else { - Sign::Negative + I::MAX }; - let mut exponent = (a_abs >> significand_bits) as usize; - let significand = (a_abs & <$fty>::SIGNIFICAND_MASK) | <$fty>::IMPLICIT_BIT; + }; - // if < 1 or unsigned & negative - if exponent < exponent_bias || fixint_unsigned && sign == Sign::Negative { - return 0; - } - exponent -= exponent_bias; - - // If the value is infinity, saturate. - // If the value is too large for the integer type, 0. - if exponent - >= (if fixint_unsigned { - fixint_bits - } else { - fixint_bits - 1 - }) - { - return if sign == Sign::Positive { - fixint_max - } else { - fixint_min - }; - } - // If 0 <= exponent < significand_bits, right shift to get the result. - // Otherwise, shift left. - // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned - let r = if exponent < significand_bits { - (significand >> (significand_bits - exponent)) as $ity + // `0 <= exp < max` + + // If 0 <= exponent < F::SIGNIFICAND_BITS, right shift to get the result. Otherwise, shift left. + let sig_bits: F::ExpInt = F::SIGNIFICAND_BITS.cast(); + // The larger integer has to be casted into, or else the shift overflows + let r: I = if F::Int::BITS < I::BITS { + let tmp: I = if exp < sig_bits { + f.imp_frac().cast() >> (sig_bits - exp).cast() } else { - (significand as $ity) << (exponent - significand_bits) + f.imp_frac().cast() << (exp - sig_bits).cast() }; - - if sign == Sign::Negative { - (!r).wrapping_add(1) + tmp + } else { + let tmp: F::Int = if exp < sig_bits { + f.imp_frac() >> (sig_bits - exp).cast() } else { - r - } - }}; + f.imp_frac() << (exp - sig_bits).cast() + }; + tmp.cast() + }; + + if sign { + r.wrapping_neg() + } else { + r + } } intrinsics! { #[arm_aeabi_alias = __aeabi_f2iz] pub extern "C" fn __fixsfsi(f: f32) -> i32 { - float_to_int!(f, f32, i32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_f2lz] pub extern "C" fn __fixsfdi(f: f32) -> i64 { - float_to_int!(f, f32, i64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixsfti(f: f32) -> i128 { - float_to_int!(f, f32, i128) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2iz] pub extern "C" fn __fixdfsi(f: f64) -> i32 { - float_to_int!(f, f64, i32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2lz] pub extern "C" fn __fixdfdi(f: f64) -> i64 { - float_to_int!(f, f64, i64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixdfti(f: f64) -> i128 { - float_to_int!(f, f64, i128) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { - float_to_int!(f, f32, u32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_f2ulz] pub extern "C" fn __fixunssfdi(f: f32) -> u64 { - float_to_int!(f, f32, u64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixunssfti(f: f32) -> u128 { - float_to_int!(f, f32, u128) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { - float_to_int!(f, f64, u32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2ulz] pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { - float_to_int!(f, f64, u64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { - float_to_int!(f, f64, u128) + float_to_int(f) } } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index c4b6901613f..5a0d37a7deb 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -30,6 +30,9 @@ pub trait Float: /// A int of the same with as the float type SignedInt: Int; + /// An int capable of containing the exponent bits plus a sign bit. This is signed. + type ExpInt: Int; + const ZERO: Self; const ONE: Self; @@ -71,6 +74,18 @@ pub trait Float: /// compared. fn eq_repr(self, rhs: Self) -> bool; + /// Returns the sign bit + fn sign(self) -> bool; + + /// Returns the exponent with bias + fn exp(self) -> Self::ExpInt; + + /// Returns the significand with no implicit bit (or the "fractional" part) + fn frac(self) -> Self::Int; + + /// Returns the significand with implicit bit + fn imp_frac(self) -> Self::Int; + /// Returns a `Self::Int` transmuted back to `Self` fn from_repr(a: Self::Int) -> Self; @@ -81,14 +96,16 @@ pub trait Float: fn normalize(significand: Self::Int) -> (i32, Self::Int); /// Returns if `self` is subnormal - fn is_subnormal(&self) -> bool; + fn is_subnormal(self) -> bool; } macro_rules! float_impl { - ($ty:ident, $ity:ident, $sity:ident, $bits:expr, $significand_bits:expr) => { + ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { impl Float for $ty { type Int = $ity; type SignedInt = $sity; + type ExpInt = $expty; + const ZERO: Self = 0.0; const ONE: Self = 1.0; @@ -113,6 +130,18 @@ macro_rules! float_impl { self.repr() == rhs.repr() } } + fn sign(self) -> bool { + self.signed_repr() < Self::SignedInt::ZERO + } + fn exp(self) -> Self::ExpInt { + ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt + } + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIGNIFICAND_MASK + } + fn imp_frac(self) -> Self::Int { + self.frac() | Self::IMPLICIT_BIT + } fn from_repr(a: Self::Int) -> Self { Self::from_bits(a) } @@ -132,12 +161,12 @@ macro_rules! float_impl { significand << shift as Self::Int, ) } - fn is_subnormal(&self) -> bool { + fn is_subnormal(self) -> bool { (self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO } } }; } -float_impl!(f32, u32, i32, 32, 23); -float_impl!(f64, u64, i64, 64, 52); +float_impl!(f32, u32, i32, i16, 32, 23); +float_impl!(f64, u64, i64, i16, 64, 52); diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 2eedf67584e..7d7f75972c7 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,5 +1,4 @@ use float::Float; -use int::Int; trait Pow: Float { /// Returns `a` raised to the power `b` @@ -11,7 +10,7 @@ trait Pow: Float { if (b & 1) != 0 { r *= a; } - b = b.aborting_div(2); + b = ((b as u32) >> 1) as i32; if b == 0 { break; } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index a186a95aa66..d8524a58a5e 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -15,9 +15,11 @@ pub use self::leading_zeros::__clzsi2; #[doc(hidden)] pub trait Int: Copy + + core::fmt::Debug + PartialEq + PartialOrd + ops::AddAssign + + ops::SubAssign + ops::BitAndAssign + ops::BitOrAssign + ops::BitXorAssign @@ -38,12 +40,16 @@ pub trait Int: /// Unsigned version of Self type UnsignedInt: Int; + /// If `Self` is a signed integer + const SIGNED: bool; + /// The bitwidth of the int type const BITS: u32; const ZERO: Self; const ONE: Self; const MIN: Self; + const MAX: Self; /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, @@ -52,18 +58,6 @@ pub trait Int: /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. const FUZZ_NUM: usize; - /// Extracts the sign from self and returns a tuple. - /// - /// # Examples - /// - /// ```rust,ignore - /// let i = -25_i32; - /// let (sign, u) = i.extract_sign(); - /// assert_eq!(sign, true); - /// assert_eq!(u, 25_u32); - /// ``` - fn extract_sign(self) -> (bool, Self::UnsignedInt); - fn unsigned(self) -> Self::UnsignedInt; fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; @@ -77,8 +71,6 @@ pub trait Int: // copied from primitive integers, but put in a trait fn is_zero(self) -> bool; - fn max_value() -> Self; - fn min_value() -> Self; fn wrapping_neg(self) -> Self; fn wrapping_add(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self; @@ -87,25 +79,18 @@ pub trait Int: fn wrapping_shr(self, other: u32) -> Self; fn rotate_left(self, other: u32) -> Self; fn overflowing_add(self, other: Self) -> (Self, bool); - fn aborting_div(self, other: Self) -> Self; - fn aborting_rem(self, other: Self) -> Self; fn leading_zeros(self) -> u32; } -fn unwrap(t: Option) -> T { - match t { - Some(t) => t, - None => ::abort(), - } -} - macro_rules! int_impl_common { ($ty:ty) => { const BITS: u32 = ::BITS; + const SIGNED: bool = Self::MIN != Self::ZERO; const ZERO: Self = 0; const ONE: Self = 1; const MIN: Self = ::MIN; + const MAX: Self = ::MAX; const FUZZ_LENGTHS: [u8; 20] = { let bits = ::BITS; @@ -177,14 +162,6 @@ macro_rules! int_impl_common { self == Self::ZERO } - fn max_value() -> Self { - ::max_value() - } - - fn min_value() -> Self { - ::min_value() - } - fn wrapping_neg(self) -> Self { ::wrapping_neg(self) } @@ -217,14 +194,6 @@ macro_rules! int_impl_common { ::overflowing_add(self, other) } - fn aborting_div(self, other: Self) -> Self { - unwrap(::checked_div(self, other)) - } - - fn aborting_rem(self, other: Self) -> Self { - unwrap(::checked_rem(self, other)) - } - fn leading_zeros(self) -> u32 { ::leading_zeros(self) } @@ -237,10 +206,6 @@ macro_rules! int_impl { type OtherSign = $ity; type UnsignedInt = $uty; - fn extract_sign(self) -> (bool, $uty) { - (false, self) - } - fn unsigned(self) -> $uty { self } @@ -264,14 +229,6 @@ macro_rules! int_impl { type OtherSign = $uty; type UnsignedInt = $uty; - fn extract_sign(self) -> (bool, $uty) { - if self < 0 { - (true, (!(self as $uty)).wrapping_add(1)) - } else { - (false, self as $uty) - } - } - fn unsigned(self) -> $uty { self as $uty } @@ -395,13 +352,14 @@ impl_h_int!( ); /// Trait to express (possibly lossy) casting of integers -pub(crate) trait CastInto: Copy { +#[doc(hidden)] +pub trait CastInto: Copy { fn cast(self) -> T; } macro_rules! cast_into { ($ty:ty) => { - cast_into!($ty; usize, isize, u32, i32, u64, i64, u128, i128); + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); }; ($ty:ty; $($into:ty),*) => {$( impl CastInto<$into> for $ty { @@ -412,6 +370,12 @@ macro_rules! cast_into { )*}; } +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); cast_into!(u32); cast_into!(i32); cast_into!(u64); diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 4a7c746a2ff..9190c4251e5 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -31,11 +31,6 @@ #[cfg(test)] extern crate core; -#[allow(unused_unsafe)] -fn abort() -> ! { - unsafe { core::intrinsics::abort() } -} - #[macro_use] mod macros; diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index 0007c15aee5..bb4a08e42ae 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -108,7 +108,7 @@ macro_rules! float { let quo0 = x / y; let quo1: $i = $fn(x, y); // division of subnormals is not currently handled - if !(Float::is_subnormal(&quo0) || Float::is_subnormal(&quo1)) { + if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) { if !Float::eq_repr(quo0, quo1) { panic!( "{}({}, {}): std: {}, builtins: {}", diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 8b97ea46c35..272bfa06881 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -86,7 +86,7 @@ macro_rules! float_mul { let mul0 = x * y; let mul1: $f = $fn(x, y); // multiplication of subnormals is not currently handled - if !(Float::is_subnormal(&mul0) || Float::is_subnormal(&mul1)) { + if !(Float::is_subnormal(mul0) || Float::is_subnormal(mul1)) { if !Float::eq_repr(mul0, mul1) { panic!( "{}({}, {}): std: {}, builtins: {}", -- cgit 1.4.1-3-g733a5 From 96a6110d69358304f6dbff1503de2cd6243dc231 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Thu, 10 Dec 2020 19:56:36 -0600 Subject: add remaining floating point tests --- .../compiler-builtins/testcrate/tests/addsub.rs | 17 ++++++ library/compiler-builtins/testcrate/tests/cmp.rs | 60 ++++++++++++++++++++ .../compiler-builtins/testcrate/tests/div_rem.rs | 16 ++++++ library/compiler-builtins/testcrate/tests/misc.rs | 66 +++++++++++++++++----- library/compiler-builtins/testcrate/tests/mul.rs | 16 ++++++ 5 files changed, 160 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs index ff56668b78b..da7684ec901 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -1,3 +1,5 @@ +#![allow(unused_macros)] + use testcrate::*; macro_rules! sum { @@ -107,3 +109,18 @@ fn float_addsub() { f64, __adddf3, __subdf3; ); } + +#[cfg(target_arch = "arm")] +#[test] +fn float_addsub_arm() { + use compiler_builtins::float::{ + add::{__adddf3vfp, __addsf3vfp}, + sub::{__subdf3vfp, __subsf3vfp}, + Float, + }; + + float_sum!( + f32, __addsf3vfp, __subsf3vfp; + f64, __adddf3vfp, __subdf3vfp; + ); +} diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index d359b65d7e4..a49779ad0e4 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -1,3 +1,5 @@ +#![allow(unused_macros)] + use testcrate::*; macro_rules! cmp { @@ -50,3 +52,61 @@ fn float_comparisons() { ); }); } + +macro_rules! cmp2 { + ($x:ident, $y:ident, $($unordered_val:expr, $fn_std:expr, $fn_builtins:ident);*;) => { + $( + let cmp0: i32 = if $x.is_nan() || $y.is_nan() { + $unordered_val + } else { + $fn_std as i32 + }; + let cmp1: i32 = $fn_builtins($x, $y); + if cmp0 != cmp1 { + panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1); + } + )* + }; +} + +#[cfg(target_arch = "arm")] +#[test] +fn float_comparisons_arm() { + use compiler_builtins::float::cmp::{ + __aeabi_dcmpeq, __aeabi_dcmpge, __aeabi_dcmpgt, __aeabi_dcmple, __aeabi_dcmplt, + __aeabi_fcmpeq, __aeabi_fcmpge, __aeabi_fcmpgt, __aeabi_fcmple, __aeabi_fcmplt, __eqdf2vfp, + __eqsf2vfp, __gedf2vfp, __gesf2vfp, __gtdf2vfp, __gtsf2vfp, __ledf2vfp, __lesf2vfp, + __ltdf2vfp, __ltsf2vfp, __nedf2vfp, __nesf2vfp, + }; + + fuzz_float_2(N, |x: f32, y: f32| { + cmp2!(x, y, + 0, x < y, __aeabi_fcmplt; + 0, x <= y, __aeabi_fcmple; + 0, x == y, __aeabi_fcmpeq; + 0, x >= y, __aeabi_fcmpge; + 0, x > y, __aeabi_fcmpgt; + 0, x < y, __ltsf2vfp; + 0, x <= y, __lesf2vfp; + 0, x == y, __eqsf2vfp; + 0, x >= y, __gesf2vfp; + 0, x > y, __gtsf2vfp; + 1, x != y, __nesf2vfp; + ); + }); + fuzz_float_2(N, |x: f64, y: f64| { + cmp2!(x, y, + 0, x < y, __aeabi_dcmplt; + 0, x <= y, __aeabi_dcmple; + 0, x == y, __aeabi_dcmpeq; + 0, x >= y, __aeabi_dcmpge; + 0, x > y, __aeabi_dcmpgt; + 0, x < y, __ltdf2vfp; + 0, x <= y, __ledf2vfp; + 0, x == y, __eqdf2vfp; + 0, x >= y, __gedf2vfp; + 0, x > y, __gtdf2vfp; + 1, x != y, __nedf2vfp; + ); + }); +} diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index bb4a08e42ae..c3f0676400e 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -1,3 +1,5 @@ +#![allow(unused_macros)] + use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc}; use testcrate::*; @@ -134,3 +136,17 @@ fn float_div() { f64, __divdf3; ); } + +#[cfg(target_arch = "arm")] +#[test] +fn float_div_arm() { + use compiler_builtins::float::{ + div::{__divdf3vfp, __divsf3vfp}, + Float, + }; + + float!( + f32, __divsf3vfp; + f64, __divdf3vfp; + ); +} diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index d31e3e6b6a7..ec3e9d96d45 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -1,3 +1,7 @@ +// makes configuration easier +#![allow(unused_macros)] + +use compiler_builtins::float::Float; use testcrate::*; /// Make sure that the the edge case tester and randomized tester don't break, and list examples of @@ -89,15 +93,37 @@ fn leading_zeros() { }) } +macro_rules! extend { + ($fX:ident, $fD:ident, $fn:ident) => { + fuzz_float(N, |x: $fX| { + let tmp0 = x as $fD; + let tmp1: $fD = $fn(x); + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + tmp0, + tmp1 + ); + } + }); + }; +} + #[test] fn float_extend() { - fuzz_float(N, |x: f32| { - let tmp0 = x as f64; - let tmp1: f64 = compiler_builtins::float::extend::__extendsfdf2(x); - if !compiler_builtins::float::Float::eq_repr(tmp0, tmp1) { - panic!("__extendsfdf2({}): std: {}, builtins: {}", x, tmp0, tmp1); - } - }); + use compiler_builtins::float::extend::__extendsfdf2; + + extend!(f32, f64, __extendsfdf2); +} + +#[cfg(target_arch = "arm")] +#[test] +fn float_extend_arm() { + use compiler_builtins::float::extend::__extendsfdf2vfp; + + extend!(f32, f64, __extendsfdf2vfp); } // This doesn't quite work because of issues related to @@ -108,14 +134,16 @@ macro_rules! pow { ($($f:ty, $fn:ident);*;) => { $( fuzz_float_2(N, |x: $f, y: $f| { - let n = y as i32; - let tmp0: $f = x.powi(n); - let tmp1: $f = $fn(x, n); - if tmp0 != tmp1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, y, tmp0, tmp1 - ); + if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x < 0. || y < 0.) { + let n = y as i32; + let tmp0: $f = x.powi(n); + let tmp1: $f = $fn(x, n); + if tmp0 != tmp1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, tmp0, tmp1 + ); + } } }); )* @@ -132,3 +160,11 @@ fn float_pow() { ); } */ + +// placeholder test to make sure basic functionality works +#[test] +fn float_pow() { + use compiler_builtins::float::pow::{__powidf2, __powisf2}; + assert_eq!(__powisf2(-3.0, 3), -27.0); + assert_eq!(__powidf2(-3.0, 3), -27.0); +} diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 272bfa06881..819f06ca9ef 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -1,3 +1,5 @@ +#![allow(unused_macros)] + use testcrate::*; macro_rules! mul { @@ -112,3 +114,17 @@ fn float_mul() { f64, __muldf3; ); } + +#[cfg(target_arch = "arm")] +#[test] +fn float_mul_arm() { + use compiler_builtins::float::{ + mul::{__muldf3vfp, __mulsf3vfp}, + Float, + }; + + float_mul!( + f32, __mulsf3vfp; + f64, __muldf3vfp; + ); +} -- cgit 1.4.1-3-g733a5 From 3871282eee1de561eb90f47ea7cee4a70b272dd1 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Thu, 10 Dec 2020 20:30:48 -0600 Subject: fix `powi` --- library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/src/float/pow.rs | 47 +++++++++++------------ library/compiler-builtins/testcrate/tests/misc.rs | 47 ++++++++++++++--------- 3 files changed, 51 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 5a0d37a7deb..69e4dc63517 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -15,6 +15,7 @@ pub mod sub; #[doc(hidden)] pub trait Float: Copy + + core::fmt::Debug + PartialEq + PartialOrd + ops::AddAssign diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 7d7f75972c7..5ab5e4201c2 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,39 +1,36 @@ use float::Float; +use int::Int; -trait Pow: Float { - /// Returns `a` raised to the power `b` - fn pow(self, mut b: i32) -> Self { - let mut a = self; - let recip = b < 0; - let mut r = Self::ONE; - loop { - if (b & 1) != 0 { - r *= a; - } - b = ((b as u32) >> 1) as i32; - if b == 0 { - break; - } - a *= a; +/// Returns `a` raised to the power `b` +fn pow(a: F, b: i32) -> F { + let mut a = a; + let recip = b < 0; + let mut pow = i32::abs_diff(b, 0); + let mut mul = F::ONE; + loop { + if (pow & 1) != 0 { + mul *= a; } - - if recip { - Self::ONE / r - } else { - r + pow >>= 1; + if pow == 0 { + break; } + a *= a; } -} -impl Pow for f32 {} -impl Pow for f64 {} + if recip { + F::ONE / mul + } else { + mul + } +} intrinsics! { pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 { - a.pow(b) + pow(a, b) } pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 { - a.pow(b) + pow(a, b) } } diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index ec3e9d96d45..82a1ea27b47 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -126,22 +126,39 @@ fn float_extend_arm() { extend!(f32, f64, __extendsfdf2vfp); } -// This doesn't quite work because of issues related to +// This is approximate because of issues related to // https://github.com/rust-lang/rust/issues/73920. -// TODO how do we resolve this? -/* +// TODO how do we resolve this indeterminacy? macro_rules! pow { - ($($f:ty, $fn:ident);*;) => { + ($($f:ty, $tolerance:expr, $fn:ident);*;) => { $( fuzz_float_2(N, |x: $f, y: $f| { - if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x < 0. || y < 0.) { - let n = y as i32; + if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) { + let n = y.to_bits() & !<$f as Float>::SIGNIFICAND_MASK; + let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS; + let n = n as i32; let tmp0: $f = x.powi(n); let tmp1: $f = $fn(x, n); - if tmp0 != tmp1 { + let (a, b) = if tmp0 < tmp1 { + (tmp0, tmp1) + } else { + (tmp1, tmp0) + }; + let good = { + if a == b { + // handles infinity equality + true + } else if a < $tolerance { + b < $tolerance + } else { + let quo = b / a; + (quo < (1. + $tolerance)) && (quo > (1. - $tolerance)) + } + }; + if !good { panic!( "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, y, tmp0, tmp1 + stringify!($fn), x, n, tmp0, tmp1 ); } } @@ -150,21 +167,13 @@ macro_rules! pow { }; } +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] #[test] fn float_pow() { use compiler_builtins::float::pow::{__powidf2, __powisf2}; pow!( - f32, __powisf2; - f64, __powidf2; + f32, 1e-4, __powisf2; + f64, 1e-12, __powidf2; ); } -*/ - -// placeholder test to make sure basic functionality works -#[test] -fn float_pow() { - use compiler_builtins::float::pow::{__powidf2, __powisf2}; - assert_eq!(__powisf2(-3.0, 3), -27.0); - assert_eq!(__powidf2(-3.0, 3), -27.0); -} -- cgit 1.4.1-3-g733a5 From 94af8a82683fa4984881305893eea3a120efc651 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 11 Dec 2020 13:26:41 -0600 Subject: Delete redundant tests The old tests were hacky and did not cover nearly as many cases as the new tests do. --- library/compiler-builtins/testcrate/build.rs | 1443 -------------------- .../compiler-builtins/testcrate/tests/generated.rs | 37 - 2 files changed, 1480 deletions(-) delete mode 100644 library/compiler-builtins/testcrate/build.rs delete mode 100644 library/compiler-builtins/testcrate/tests/generated.rs diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs deleted file mode 100644 index 39c2486c692..00000000000 --- a/library/compiler-builtins/testcrate/build.rs +++ /dev/null @@ -1,1443 +0,0 @@ -use rand::seq::SliceRandom; -use rand::Rng; -use std::collections::HashMap; -use std::fmt; -use std::fmt::Write as FmtWrite; -use std::fs::{self, OpenOptions}; -use std::hash::{Hash, Hasher}; -use std::io::Write; -use std::path::PathBuf; -use std::{env, mem}; - -const NTESTS: usize = 1_000; - -fn main() { - let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let out_file = out_dir.join("generated.rs"); - drop(fs::remove_file(&out_file)); - - let target = env::var("TARGET").unwrap(); - let target_arch_arm = target.contains("arm") || target.contains("thumb"); - let target_arch_mips = target.contains("mips"); - - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - - // float/add.rs - gen( - |(a, b): (MyF64, MyF64)| { - let c = a.0 + b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::add::__adddf3(a, b)", - ); - gen( - |(a, b): (MyF32, MyF32)| { - let c = a.0 + b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::add::__addsf3(a, b)", - ); - - if target_arch_arm { - gen( - |(a, b): (MyF64, MyF64)| { - let c = a.0 + b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::add::__adddf3vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - let c = a.0 + b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::add::__addsf3vfp(a, b)", - ); - } - - // float/cmp.rs - gen( - |(a, b): (MyF64, MyF64)| { - let (a, b) = (a.0, b.0); - if a.is_nan() || b.is_nan() { - return None; - } - - if a.is_nan() || b.is_nan() { - Some(-1) - } else if a < b { - Some(-1) - } else if a > b { - Some(1) - } else { - Some(0) - } - }, - "builtins::float::cmp::__gedf2(a, b)", - ); - gen( - |(a, b): (MyF32, MyF32)| { - let (a, b) = (a.0, b.0); - if a.is_nan() || b.is_nan() { - return None; - } - - if a.is_nan() || b.is_nan() { - Some(-1) - } else if a < b { - Some(-1) - } else if a > b { - Some(1) - } else { - Some(0) - } - }, - "builtins::float::cmp::__gesf2(a, b)", - ); - gen( - |(a, b): (MyF64, MyF64)| { - let (a, b) = (a.0, b.0); - if a.is_nan() || b.is_nan() { - return None; - } - - if a.is_nan() || b.is_nan() { - Some(1) - } else if a < b { - Some(-1) - } else if a > b { - Some(1) - } else { - Some(0) - } - }, - "builtins::float::cmp::__ledf2(a, b)", - ); - gen( - |(a, b): (MyF32, MyF32)| { - let (a, b) = (a.0, b.0); - if a.is_nan() || b.is_nan() { - return None; - } - - if a.is_nan() || b.is_nan() { - Some(1) - } else if a < b { - Some(-1) - } else if a > b { - Some(1) - } else { - Some(0) - } - }, - "builtins::float::cmp::__lesf2(a, b)", - ); - - gen( - |(a, b): (MyF32, MyF32)| { - let c = a.0.is_nan() || b.0.is_nan(); - Some(c as i32) - }, - "builtins::float::cmp::__unordsf2(a, b)", - ); - - gen( - |(a, b): (MyF64, MyF64)| { - let c = a.0.is_nan() || b.0.is_nan(); - Some(c as i32) - }, - "builtins::float::cmp::__unorddf2(a, b)", - ); - - if target_arch_arm { - gen( - |(a, b): (MyF32, MyF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 <= b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_fcmple(a, b)", - ); - - gen( - |(a, b): (MyF32, MyF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 >= b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_fcmpge(a, b)", - ); - - gen( - |(a, b): (MyF32, MyF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 == b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_fcmpeq(a, b)", - ); - - gen( - |(a, b): (MyF32, MyF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 < b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_fcmplt(a, b)", - ); - - gen( - |(a, b): (MyF32, MyF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 > b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_fcmpgt(a, b)", - ); - - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 <= b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_dcmple(a, b)", - ); - - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 >= b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_dcmpge(a, b)", - ); - - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 == b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_dcmpeq(a, b)", - ); - - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 < b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_dcmplt(a, b)", - ); - - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 > b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_dcmpgt(a, b)", - ); - - gen( - |(a, b): (LargeF32, LargeF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 >= b.0) as i32) - }, - "builtins::float::cmp::__gesf2vfp(a, b)", - ); - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 >= b.0) as i32) - }, - "builtins::float::cmp::__gedf2vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 > b.0) as i32) - }, - "builtins::float::cmp::__gtsf2vfp(a, b)", - ); - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 > b.0) as i32) - }, - "builtins::float::cmp::__gtdf2vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 < b.0) as i32) - }, - "builtins::float::cmp::__ltsf2vfp(a, b)", - ); - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 < b.0) as i32) - }, - "builtins::float::cmp::__ltdf2vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 <= b.0) as i32) - }, - "builtins::float::cmp::__lesf2vfp(a, b)", - ); - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 <= b.0) as i32) - }, - "builtins::float::cmp::__ledf2vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 != b.0) as i32) - }, - "builtins::float::cmp::__nesf2vfp(a, b)", - ); - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 != b.0) as i32) - }, - "builtins::float::cmp::__nedf2vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 == b.0) as i32) - }, - "builtins::float::cmp::__eqsf2vfp(a, b)", - ); - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 == b.0) as i32) - }, - "builtins::float::cmp::__eqdf2vfp(a, b)", - ); - } - - // float/extend.rs - gen( - |a: MyF32| { - if a.0.is_nan() { - return None; - } - Some(f64::from(a.0)) - }, - "builtins::float::extend::__extendsfdf2(a)", - ); - if target_arch_arm { - gen( - |a: LargeF32| { - if a.0.is_nan() { - return None; - } - Some(f64::from(a.0)) - }, - "builtins::float::extend::__extendsfdf2vfp(a)", - ); - } - - // float/conv.rs - gen( - |a: MyF64| i64::cast(a.0), - "builtins::float::conv::__fixdfdi(a)", - ); - gen( - |a: MyF64| i32::cast(a.0), - "builtins::float::conv::__fixdfsi(a)", - ); - gen( - |a: MyF32| i64::cast(a.0), - "builtins::float::conv::__fixsfdi(a)", - ); - gen( - |a: MyF32| i32::cast(a.0), - "builtins::float::conv::__fixsfsi(a)", - ); - gen( - |a: MyF32| i128::cast(a.0), - "builtins::float::conv::__fixsfti(a)", - ); - gen( - |a: MyF64| i128::cast(a.0), - "builtins::float::conv::__fixdfti(a)", - ); - gen( - |a: MyF64| u64::cast(a.0), - "builtins::float::conv::__fixunsdfdi(a)", - ); - gen( - |a: MyF64| u32::cast(a.0), - "builtins::float::conv::__fixunsdfsi(a)", - ); - gen( - |a: MyF32| u64::cast(a.0), - "builtins::float::conv::__fixunssfdi(a)", - ); - gen( - |a: MyF32| u32::cast(a.0), - "builtins::float::conv::__fixunssfsi(a)", - ); - gen( - |a: MyF32| u128::cast(a.0), - "builtins::float::conv::__fixunssfti(a)", - ); - gen( - |a: MyF64| u128::cast(a.0), - "builtins::float::conv::__fixunsdfti(a)", - ); - gen( - |a: MyI64| Some(a.0 as f64), - "builtins::float::conv::__floatdidf(a)", - ); - gen( - |a: MyI32| Some(a.0 as f64), - "builtins::float::conv::__floatsidf(a)", - ); - gen( - |a: MyI32| Some(a.0 as f32), - "builtins::float::conv::__floatsisf(a)", - ); - gen( - |a: MyU64| Some(a.0 as f64), - "builtins::float::conv::__floatundidf(a)", - ); - gen( - |a: MyU32| Some(a.0 as f64), - "builtins::float::conv::__floatunsidf(a)", - ); - gen( - |a: MyU32| Some(a.0 as f32), - "builtins::float::conv::__floatunsisf(a)", - ); - gen( - |a: MyU128| Some(a.0 as f32), - "builtins::float::conv::__floatuntisf(a)", - ); - if !target_arch_mips { - gen( - |a: MyI128| Some(a.0 as f32), - "builtins::float::conv::__floattisf(a)", - ); - gen( - |a: MyI128| Some(a.0 as f64), - "builtins::float::conv::__floattidf(a)", - ); - gen( - |a: MyU128| Some(a.0 as f64), - "builtins::float::conv::__floatuntidf(a)", - ); - } - - // float/pow.rs - gen( - |(a, b): (MyF64, MyI32)| { - let c = a.0.powi(b.0); - if a.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::pow::__powidf2(a, b)", - ); - gen( - |(a, b): (MyF32, MyI32)| { - let c = a.0.powi(b.0); - if a.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::pow::__powisf2(a, b)", - ); - - // float/sub.rs - gen( - |(a, b): (MyF64, MyF64)| { - let c = a.0 - b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::sub::__subdf3(a, b)", - ); - gen( - |(a, b): (MyF32, MyF32)| { - let c = a.0 - b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::sub::__subsf3(a, b)", - ); - - if target_arch_arm { - gen( - |(a, b): (MyF64, MyF64)| { - let c = a.0 - b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::sub::__subdf3vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - let c = a.0 - b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::sub::__subsf3vfp(a, b)", - ); - } - - // float/mul.rs - gen( - |(a, b): (MyF64, MyF64)| { - let c = a.0 * b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::mul::__muldf3(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - let c = a.0 * b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::mul::__mulsf3(a, b)", - ); - - if target_arch_arm { - gen( - |(a, b): (MyF64, MyF64)| { - let c = a.0 * b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::mul::__muldf3vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - let c = a.0 * b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::mul::__mulsf3vfp(a, b)", - ); - } - - // float/div.rs - gen( - |(a, b): (MyF64, MyF64)| { - if b.0 == 0.0 { - return None; - } - let c = a.0 / b.0; - if a.0.is_nan() - || b.0.is_nan() - || c.is_nan() - || c.abs() <= f64::from_bits(4503599627370495u64) - { - None - } else { - Some(c) - } - }, - "builtins::float::div::__divdf3(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - if b.0 == 0.0 { - return None; - } - let c = a.0 / b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() || c.abs() <= f32::from_bits(16777215u32) - { - None - } else { - Some(c) - } - }, - "builtins::float::div::__divsf3(a, b)", - ); - - if target_arch_arm { - gen( - |(a, b): (MyF64, MyF64)| { - if b.0 == 0.0 { - return None; - } - let c = a.0 / b.0; - if a.0.is_nan() - || b.0.is_nan() - || c.is_nan() - || c.abs() <= f64::from_bits(4503599627370495u64) - { - None - } else { - Some(c) - } - }, - "builtins::float::div::__divdf3vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - if b.0 == 0.0 { - return None; - } - let c = a.0 / b.0; - if a.0.is_nan() - || b.0.is_nan() - || c.is_nan() - || c.abs() <= f32::from_bits(16777215u32) - { - None - } else { - Some(c) - } - }, - "builtins::float::div::__divsf3vfp(a, b)", - ); - } - - // int/addsub.rs - gen( - |(a, b): (MyU128, MyU128)| Some(a.0.wrapping_add(b.0)), - "builtins::int::addsub::__rust_u128_add(a, b)", - ); - gen( - |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_add(b.0)), - "builtins::int::addsub::__rust_i128_add(a, b)", - ); - gen( - |(a, b): (MyU128, MyU128)| Some(a.0.overflowing_add(b.0)), - "builtins::int::addsub::__rust_u128_addo(a, b)", - ); - gen( - |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_add(b.0)), - "builtins::int::addsub::__rust_i128_addo(a, b)", - ); - gen( - |(a, b): (MyU128, MyU128)| Some(a.0.wrapping_sub(b.0)), - "builtins::int::addsub::__rust_u128_sub(a, b)", - ); - gen( - |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_sub(b.0)), - "builtins::int::addsub::__rust_i128_sub(a, b)", - ); - gen( - |(a, b): (MyU128, MyU128)| Some(a.0.overflowing_sub(b.0)), - "builtins::int::addsub::__rust_u128_subo(a, b)", - ); - gen( - |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_sub(b.0)), - "builtins::int::addsub::__rust_i128_subo(a, b)", - ); - - // int/mul.rs - gen( - |(a, b): (MyU64, MyU64)| Some(a.0.wrapping_mul(b.0)), - "builtins::int::mul::__muldi3(a, b)", - ); - gen( - |(a, b): (MyI64, MyI64)| Some(a.0.overflowing_mul(b.0)), - "{ - let mut o = 2; - let c = builtins::int::mul::__mulodi4(a, b, &mut o); - (c, match o { 0 => false, 1 => true, _ => panic!() }) - }", - ); - gen( - |(a, b): (MyI32, MyI32)| Some(a.0.overflowing_mul(b.0)), - "{ - let mut o = 2; - let c = builtins::int::mul::__mulosi4(a, b, &mut o); - (c, match o { 0 => false, 1 => true, _ => panic!() }) - }", - ); - gen( - |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_mul(b.0)), - "builtins::int::mul::__multi3(a, b)", - ); - gen( - |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_mul(b.0)), - "{ - let mut o = 2; - let c = builtins::int::mul::__muloti4(a, b, &mut o); - (c, match o { 0 => false, 1 => true, _ => panic!() }) - }", - ); - - // int/sdiv.rs - gen( - |(a, b): (MyI64, MyI64)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::sdiv::__divdi3(a, b)", - ); - gen( - |(a, b): (MyI64, MyI64)| { - if b.0 == 0 { - None - } else { - Some((a.0 / b.0, a.0 % b.0)) - } - }, - "{ - let mut r = 0; - (builtins::int::sdiv::__divmoddi4(a, b, &mut r), r) - }", - ); - gen( - |(a, b): (MyI32, MyI32)| { - if b.0 == 0 { - None - } else { - Some((a.0 / b.0, a.0 % b.0)) - } - }, - "{ - let mut r = 0; - (builtins::int::sdiv::__divmodsi4(a, b, &mut r), r) - }", - ); - gen( - |(a, b): (MyI128, MyI128)| { - if b.0 == 0 { - None - } else { - Some((a.0 / b.0, a.0 % b.0)) - } - }, - "{ - let mut r = 0; - (builtins::int::sdiv::__divmodti4(a, b, &mut r), r) - }", - ); - gen( - |(a, b): (MyI32, MyI32)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::sdiv::__divsi3(a, b)", - ); - gen( - |(a, b): (MyI32, MyI32)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::sdiv::__modsi3(a, b)", - ); - gen( - |(a, b): (MyI64, MyI64)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::sdiv::__moddi3(a, b)", - ); - gen( - |(a, b): (MyI128, MyI128)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::sdiv::__divti3(a, b)", - ); - gen( - |(a, b): (MyI128, MyI128)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::sdiv::__modti3(a, b)", - ); - - // int/shift.rs - gen( - |(a, b): (MyU32, MyU32)| Some(a.0 << (b.0 % 32)), - "builtins::int::shift::__ashlsi3(a, b % 32)", - ); - gen( - |(a, b): (MyU64, MyU32)| Some(a.0 << (b.0 % 64)), - "builtins::int::shift::__ashldi3(a, b % 64)", - ); - gen( - |(a, b): (MyU128, MyU32)| Some(a.0 << (b.0 % 128)), - "builtins::int::shift::__ashlti3(a, b % 128)", - ); - gen( - |(a, b): (MyI32, MyU32)| Some(a.0 >> (b.0 % 32)), - "builtins::int::shift::__ashrsi3(a, b % 32)", - ); - gen( - |(a, b): (MyI64, MyU32)| Some(a.0 >> (b.0 % 64)), - "builtins::int::shift::__ashrdi3(a, b % 64)", - ); - gen( - |(a, b): (MyI128, MyU32)| Some(a.0 >> (b.0 % 128)), - "builtins::int::shift::__ashrti3(a, b % 128)", - ); - gen( - |(a, b): (MyU32, MyU32)| Some(a.0 >> (b.0 % 32)), - "builtins::int::shift::__lshrsi3(a, b % 32)", - ); - gen( - |(a, b): (MyU64, MyU32)| Some(a.0 >> (b.0 % 64)), - "builtins::int::shift::__lshrdi3(a, b % 64)", - ); - gen( - |(a, b): (MyU128, MyU32)| Some(a.0 >> (b.0 % 128)), - "builtins::int::shift::__lshrti3(a, b % 128)", - ); - - // int/udiv.rs - gen( - |(a, b): (MyU64, MyU64)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::udiv::__udivdi3(a, b)", - ); - gen( - |(a, b): (MyU64, MyU64)| { - if b.0 == 0 { - None - } else { - Some((a.0 / b.0, a.0 % b.0)) - } - }, - "{ - let mut r = 0; - (builtins::int::udiv::__udivmoddi4(a, b, Some(&mut r)), r) - }", - ); - gen( - |(a, b): (MyU32, MyU32)| { - if b.0 == 0 { - None - } else { - Some((a.0 / b.0, a.0 % b.0)) - } - }, - "{ - let mut r = 0; - (builtins::int::udiv::__udivmodsi4(a, b, Some(&mut r)), r) - }", - ); - gen( - |(a, b): (MyU32, MyU32)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::udiv::__udivsi3(a, b)", - ); - gen( - |(a, b): (MyU32, MyU32)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::udiv::__umodsi3(a, b)", - ); - gen( - |(a, b): (MyU64, MyU64)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::udiv::__umoddi3(a, b)", - ); - gen( - |(a, b): (MyU128, MyU128)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::udiv::__udivti3(a, b)", - ); - gen( - |(a, b): (MyU128, MyU128)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::udiv::__umodti3(a, b)", - ); - gen( - |(a, b): (MyU128, MyU128)| { - if b.0 == 0 { - None - } else { - Some((a.0 / b.0, a.0 % b.0)) - } - }, - "{ - let mut r = 0; - (builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) - }", - ); -} - -macro_rules! gen_float { - ($name:ident, - $fty:ident, - $uty:ident, - $bits:expr, - $significand_bits:expr) => { - pub fn $name(rng: &mut R) -> $fty - where - R: Rng + ?Sized, - { - const BITS: u8 = $bits; - const SIGNIFICAND_BITS: u8 = $significand_bits; - - const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; - const SIGN_MASK: $uty = (1 << (BITS - 1)); - const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); - - fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { - unsafe { - mem::transmute( - ((sign as $uty) << (BITS - 1)) - | ((exponent & EXPONENT_MASK) << SIGNIFICAND_BITS) - | (significand & SIGNIFICAND_MASK), - ) - } - } - - if rng.gen_range(0, 10) == 1 { - // Special values - *[ - -0.0, - 0.0, - ::std::$fty::MIN, - ::std::$fty::MIN_POSITIVE, - ::std::$fty::MAX, - ::std::$fty::NAN, - ::std::$fty::INFINITY, - -::std::$fty::INFINITY, - ] - .choose(rng) - .unwrap() - } else if rng.gen_range(0, 10) == 1 { - // NaN patterns - mk_f32(rng.gen(), rng.gen(), 0) - } else if rng.gen() { - // Denormalized - mk_f32(rng.gen(), 0, rng.gen()) - } else { - // Random anything - mk_f32(rng.gen(), rng.gen(), rng.gen()) - } - } - }; -} - -gen_float!(gen_f32, f32, u32, 32, 23); -gen_float!(gen_f64, f64, u64, 64, 52); - -macro_rules! gen_large_float { - ($name:ident, - $fty:ident, - $uty:ident, - $bits:expr, - $significand_bits:expr) => { - pub fn $name(rng: &mut R) -> $fty - where - R: Rng + ?Sized, - { - const BITS: u8 = $bits; - const SIGNIFICAND_BITS: u8 = $significand_bits; - - const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; - const SIGN_MASK: $uty = (1 << (BITS - 1)); - const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); - - fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { - unsafe { - mem::transmute( - ((sign as $uty) << (BITS - 1)) - | ((exponent & EXPONENT_MASK) << SIGNIFICAND_BITS) - | (significand & SIGNIFICAND_MASK), - ) - } - } - - if rng.gen_range(0, 10) == 1 { - // Special values - *[ - -0.0, - 0.0, - ::std::$fty::MIN, - ::std::$fty::MIN_POSITIVE, - ::std::$fty::MAX, - ::std::$fty::NAN, - ::std::$fty::INFINITY, - -::std::$fty::INFINITY, - ] - .choose(rng) - .unwrap() - } else if rng.gen_range(0, 10) == 1 { - // NaN patterns - mk_f32(rng.gen(), rng.gen(), 0) - } else if rng.gen() { - // Denormalized - mk_f32(rng.gen(), 0, rng.gen()) - } else { - // Random anything - rng.gen::<$fty>() - } - } - }; -} - -gen_large_float!(gen_large_f32, f32, u32, 32, 23); -gen_large_float!(gen_large_f64, f64, u64, 64, 52); - -trait TestInput: Hash + Eq + fmt::Debug { - fn ty_name() -> String; - fn generate_lets(container: &str, cnt: &mut u8) -> String; - fn generate_static(&self, dst: &mut String); -} - -trait TestOutput { - fn ty_name() -> String; - fn generate_static(&self, dst: &mut String); - fn generate_expr(container: &str) -> String; -} - -fn gen(mut generate: F, test: &str) -where - F: FnMut(A) -> Option, - A: TestInput + Copy, - R: TestOutput, - rand::distributions::Standard: rand::distributions::Distribution, -{ - let rng = &mut rand::thread_rng(); - let testname = test.split("::").last().unwrap().split("(").next().unwrap(); - let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let out_file = out_dir.join("generated.rs"); - - let mut testcases = HashMap::new(); - let mut n = NTESTS; - while n > 0 { - let input: A = rng.gen(); - if testcases.contains_key(&input) { - continue; - } - let output = match generate(input) { - Some(o) => o, - None => continue, - }; - testcases.insert(input, output); - n -= 1; - } - - let mut contents = String::new(); - contents.push_str(&format!("mod {} {{\nuse super::*;\n", testname)); - contents.push_str("#[test]\n"); - contents.push_str("fn test() {\n"); - contents.push_str(&format!( - "static TESTS: [({}, {}); {}] = [\n", - A::ty_name(), - R::ty_name(), - NTESTS - )); - for (input, output) in testcases { - contents.push_str(" ("); - input.generate_static(&mut contents); - contents.push_str(", "); - output.generate_static(&mut contents); - contents.push_str("),\n"); - } - contents.push_str("];\n"); - - contents.push_str(&format!( - r#" - for &(inputs, output) in TESTS.iter() {{ - {} - assert_eq!({}, {}, "inputs {{:?}}", inputs) - }} - "#, - A::generate_lets("inputs", &mut 0), - R::generate_expr("output"), - test, - )); - contents.push_str("\n}\n"); - contents.push_str("\n}\n"); - - OpenOptions::new() - .write(true) - .append(true) - .create(true) - .open(out_file) - .unwrap() - .write_all(contents.as_bytes()) - .unwrap(); -} - -macro_rules! my_float { - ($(struct $name:ident($inner:ident) = $gen:ident;)*) => ($( - #[derive(Debug, Clone, Copy)] - struct $name($inner); - - impl TestInput for $name { - fn ty_name() -> String { - format!("u{}", &stringify!($inner)[1..]) - } - - fn generate_lets(container: &str, cnt: &mut u8) -> String { - let me = *cnt; - *cnt += 1; - format!("let {} = {}::from_bits({});\n", - (b'a' + me) as char, - stringify!($inner), - container) - } - - fn generate_static(&self, dst: &mut String) { - write!(dst, "{}", self.0.to_bits()).unwrap(); - } - } - - impl rand::distributions::Distribution<$name> for rand::distributions::Standard { - fn sample(&self, r: &mut R) -> $name { - $name($gen(r)) - } - } - - impl Hash for $name { - fn hash(&self, h: &mut H) { - self.0.to_bits().hash(h) - } - } - - impl PartialEq for $name { - fn eq(&self, other: &$name) -> bool { - self.0.to_bits() == other.0.to_bits() - } - } - - impl Eq for $name {} - - )*) -} - -my_float! { - struct MyF64(f64) = gen_f64; - struct LargeF64(f64) = gen_large_f64; - struct MyF32(f32) = gen_f32; - struct LargeF32(f32) = gen_large_f32; -} - -macro_rules! my_integer { - ($(struct $name:ident($inner:ident);)*) => ($( - #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] - struct $name($inner); - - impl TestInput for $name { - fn ty_name() -> String { - stringify!($inner).to_string() - } - - fn generate_lets(container: &str, cnt: &mut u8) -> String { - let me = *cnt; - *cnt += 1; - format!("let {} = {};\n", - (b'a' + me) as char, - container) - } - - fn generate_static(&self, dst: &mut String) { - write!(dst, "{}", self.0).unwrap(); - } - } - - impl rand::distributions::Distribution<$name> for rand::distributions::Standard { - fn sample(&self, r: &mut R) -> $name { - let bits = (0 as $inner).count_zeros(); - let mut mk = || { - if r.gen_range(0, 10) == 1 { - *[ - ::std::$inner::MAX >> (bits / 2), - 0, - ::std::$inner::MIN >> (bits / 2), - ].choose(r).unwrap() - } else { - r.gen::<$inner>() - } - }; - let a = mk(); - let b = mk(); - $name((a << (bits / 2)) | (b & (!0 << (bits / 2)))) - } - } - )*) -} - -my_integer! { - struct MyI32(i32); - struct MyI64(i64); - struct MyI128(i128); - struct MyU16(u16); - struct MyU32(u32); - struct MyU64(u64); - struct MyU128(u128); -} - -impl TestInput for (A, B) -where - A: TestInput, - B: TestInput, -{ - fn ty_name() -> String { - format!("({}, {})", A::ty_name(), B::ty_name()) - } - - fn generate_lets(container: &str, cnt: &mut u8) -> String { - format!( - "{}{}", - A::generate_lets(&format!("{}.0", container), cnt), - B::generate_lets(&format!("{}.1", container), cnt) - ) - } - - fn generate_static(&self, dst: &mut String) { - dst.push_str("("); - self.0.generate_static(dst); - dst.push_str(", "); - self.1.generate_static(dst); - dst.push_str(")"); - } -} - -impl TestOutput for f64 { - fn ty_name() -> String { - "u64".to_string() - } - - fn generate_static(&self, dst: &mut String) { - write!(dst, "{}", self.to_bits()).unwrap(); - } - - fn generate_expr(container: &str) -> String { - format!("f64::from_bits({})", container) - } -} - -impl TestOutput for f32 { - fn ty_name() -> String { - "u32".to_string() - } - - fn generate_static(&self, dst: &mut String) { - write!(dst, "{}", self.to_bits()).unwrap(); - } - - fn generate_expr(container: &str) -> String { - format!("f32::from_bits({})", container) - } -} - -macro_rules! plain_test_output { - ($($i:tt)*) => ($( - impl TestOutput for $i { - fn ty_name() -> String { - stringify!($i).to_string() - } - - fn generate_static(&self, dst: &mut String) { - write!(dst, "{}", self).unwrap(); - } - - fn generate_expr(container: &str) -> String { - container.to_string() - } - } - )*) -} - -plain_test_output!(i32 i64 i128 u32 u64 u128 bool); - -impl TestOutput for (A, B) -where - A: TestOutput, - B: TestOutput, -{ - fn ty_name() -> String { - format!("({}, {})", A::ty_name(), B::ty_name()) - } - - fn generate_static(&self, dst: &mut String) { - dst.push_str("("); - self.0.generate_static(dst); - dst.push_str(", "); - self.1.generate_static(dst); - dst.push_str(")"); - } - - fn generate_expr(container: &str) -> String { - container.to_string() - } -} - -trait FromFloat: Sized { - fn cast(src: T) -> Option; -} - -macro_rules! from_float { - ($($src:ident => $($dst:ident),+);+;) => { - $( - $( - impl FromFloat<$src> for $dst { - fn cast(src: $src) -> Option<$dst> { - use std::{$dst, $src}; - - if src.is_nan() || - src.is_infinite() || - src < std::$dst::MIN as $src || - src > std::$dst::MAX as $src - { - None - } else { - Some(src as $dst) - } - } - } - )+ - )+ - } -} - -from_float! { - f32 => i32, i64, i128, u32, u64, u128; - f64 => i32, i64, i128, u32, u64, u128; -} diff --git a/library/compiler-builtins/testcrate/tests/generated.rs b/library/compiler-builtins/testcrate/tests/generated.rs deleted file mode 100644 index a296db22da6..00000000000 --- a/library/compiler-builtins/testcrate/tests/generated.rs +++ /dev/null @@ -1,37 +0,0 @@ -#![feature(lang_items)] -#![allow(bad_style)] -#![allow(unused_imports)] -#![no_std] - -extern crate compiler_builtins as builtins; - -#[cfg(all( - target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test -))] -extern crate utest_cortex_m_qemu; - -#[cfg(all( - target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test -))] -#[macro_use] -extern crate utest_macros; - -#[cfg(all( - target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test -))] -macro_rules! panic { // overrides `panic!` - ($($tt:tt)*) => { - upanic!($($tt)*); - }; -} - -include!(concat!(env!("OUT_DIR"), "/generated.rs")); -- cgit 1.4.1-3-g733a5 From 1d9d761e9fe941b014c698cc8d686824924da6d9 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 11 Dec 2020 14:20:51 -0600 Subject: Fix panic-handler documentation rust-lang/rust#51647 is fixed but panic-handler is still needed --- library/compiler-builtins/crates/panic-handler/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/crates/panic-handler/src/lib.rs b/library/compiler-builtins/crates/panic-handler/src/lib.rs index a75999a4b60..673e005224b 100644 --- a/library/compiler-builtins/crates/panic-handler/src/lib.rs +++ b/library/compiler-builtins/crates/panic-handler/src/lib.rs @@ -1,4 +1,4 @@ -// Hack of a crate until rust-lang/rust#51647 is fixed +//! This is needed for tests on targets that require a `#[panic_handler]` function #![feature(no_core)] #![no_core] -- cgit 1.4.1-3-g733a5 From 1cf47804df8d69192b60cafcf11b9d4d88e223da Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 11 Dec 2020 14:45:35 -0600 Subject: Fix all clippy warnings --- library/compiler-builtins/src/float/add.rs | 5 ++--- library/compiler-builtins/src/float/cmp.rs | 21 +++++++++------------ library/compiler-builtins/src/float/div.rs | 4 ++++ library/compiler-builtins/src/float/mul.rs | 2 +- .../src/int/specialized_div_rem/mod.rs | 7 +++++++ library/compiler-builtins/src/lib.rs | 2 ++ library/compiler-builtins/src/mem/mod.rs | 3 +++ 7 files changed, 28 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index e8b9f9e7742..67f6c2c1489 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -137,9 +137,8 @@ where a_significand <<= shift; a_exponent -= shift; } - } else - /* addition */ - { + } else { + // addition a_significand += b_significand; // If the addition carried up, we need to right-shift the result and diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 79c26b09921..1d4e384335b 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -63,25 +63,22 @@ fn cmp(a: F, b: F) -> Result { // a and b as signed integers as we would with a fp_ting-point compare. if a_srep & b_srep >= szero { if a_srep < b_srep { - return Result::Less; + Result::Less } else if a_srep == b_srep { - return Result::Equal; + Result::Equal } else { - return Result::Greater; + Result::Greater } - } // Otherwise, both are negative, so we need to flip the sense of the // comparison to get the correct result. (This assumes a twos- or ones- // complement integer representation; if integers are represented in a // sign-magnitude representation, then this flip is incorrect). - else { - if a_srep > b_srep { - return Result::Less; - } else if a_srep == b_srep { - return Result::Equal; - } else { - return Result::Greater; - } + } else if a_srep > b_srep { + Result::Less + } else if a_srep == b_srep { + Result::Equal + } else { + Result::Greater } } diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index dd6467f88fb..9ac1e87b4e2 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -1,3 +1,7 @@ +// The functions are complex with many branches, and explicit +// `return`s makes it clear where function exit points are +#![allow(clippy::needless_return)] + use float::Float; use int::{CastInto, DInt, HInt, Int}; diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 540e7bdcfe3..c89f22756af 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -181,7 +181,7 @@ where product_high += product_high & one; } - return F::from_repr(product_high); + F::from_repr(product_high) } intrinsics! { diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 14e758fc5a8..391db765da4 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -1,5 +1,12 @@ // TODO: when `unsafe_block_in_unsafe_fn` is stabilized, remove this #![allow(unused_unsafe)] +// The functions are complex with many branches, and explicit +// `return`s makes it clear where function exit points are +#![allow(clippy::needless_return)] +#![allow(clippy::comparison_chain)] +// Clippy is confused by the complex configuration +#![allow(clippy::if_same_then_else)] +#![allow(clippy::needless_bool)] //! This `specialized_div_rem` module is originally from version 1.0.0 of the //! `specialized-div-rem` crate. Note that `for` loops with ranges are not used in this diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 9190c4251e5..efd63ff7795 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -17,6 +17,8 @@ // compiler on ABIs and such, so we should be "good enough" for now and changes // to the `u128` ABI will be reflected here. #![allow(improper_ctypes, improper_ctypes_definitions)] +// `mem::swap` cannot be used because it may generate references to memcpy in unoptimized code. +#![allow(clippy::manual_swap)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index 107762c43a6..03dc965ca4a 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -1,3 +1,6 @@ +// Trying to satisfy clippy here is hopeless +#![allow(clippy::style)] + #[allow(warnings)] #[cfg(target_pointer_width = "16")] type c_int = i16; -- cgit 1.4.1-3-g733a5 From 9ae3728e5e85638453ebf81f3e08c5fd7a793be5 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 2 Apr 2021 09:24:00 -0500 Subject: fix CTFE cycle --- library/compiler-builtins/src/int/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index d8524a58a5e..2190a69b9d3 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -84,7 +84,7 @@ pub trait Int: macro_rules! int_impl_common { ($ty:ty) => { - const BITS: u32 = ::BITS; + const BITS: u32 = ::ZERO.count_zeros(); const SIGNED: bool = Self::MIN != Self::ZERO; const ZERO: Self = 0; -- cgit 1.4.1-3-g733a5 From 5221cef1fcd001128ced1900bef46c6a55f838e7 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 2 Apr 2021 09:35:01 -0500 Subject: Remove `rand` dependency, update `rand_xoshiro` --- library/compiler-builtins/testcrate/Cargo.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index ff9a6a453bb..a066a11345a 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -8,14 +8,11 @@ edition = "2018" test = false doctest = false -[build-dependencies] -rand = "0.7" - [dependencies] # For fuzzing tests we want a deterministic seedable RNG. We also eliminate potential # problems with system RNGs on the variety of platforms this crate is tested on. # `xoshiro128**` is used for its quality, size, and speed at generating `u32` shift amounts. -rand_xoshiro = "0.4" +rand_xoshiro = "0.6" [dependencies.compiler_builtins] path = ".." -- cgit 1.4.1-3-g733a5 From 2608f8392c0b36ccf6e61edcbc57e3e989875ccf Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 2 Apr 2021 20:31:08 +0100 Subject: Replace llvm_asm! with asm! --- library/compiler-builtins/examples/intrinsics.rs | 9 +- library/compiler-builtins/src/arm.rs | 188 +++++++++++------------ library/compiler-builtins/src/lib.rs | 1 - library/compiler-builtins/src/x86.rs | 96 ++++++------ library/compiler-builtins/src/x86_64.rs | 99 ++++++------ 5 files changed, 194 insertions(+), 199 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 519cea2ae0e..ddbb976a252 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -6,7 +6,7 @@ #![allow(unused_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] -#![feature(llvm_asm)] +#![feature(test)] #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] @@ -276,14 +276,9 @@ mod intrinsics { } fn run() { + use core::hint::black_box as bb; use intrinsics::*; - // A copy of "test::black_box". Used to prevent LLVM from optimizing away the intrinsics during LTO - fn bb(dummy: T) -> T { - unsafe { llvm_asm!("" : : "r"(&dummy)) } - dummy - } - bb(aeabi_d2f(bb(2.))); bb(aeabi_d2i(bb(2.))); bb(aeabi_d2l(bb(2.))); diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 2b17b4f9613..545d6a17a45 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -9,135 +9,135 @@ use core::intrinsics; #[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_uidivmod() { - llvm_asm!(" - push {lr} - sub sp, sp, #4 - mov r2, sp - bl __udivmodsi4 - ldr r1, [sp] - add sp, sp, #4 - pop {pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_uidivmod() { + asm!( + "push {{lr}}", + "sub sp, sp, #4", + "mov r2, sp", + "bl __udivmodsi4", + "ldr r1, [sp]", + "add sp, sp, #4", + "pop {{pc}}", + options(noreturn) + ); } #[cfg(target_os = "ios")] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_uidivmod() { - llvm_asm!(" - push {lr} - sub sp, sp, #4 - mov r2, sp - bl ___udivmodsi4 - ldr r1, [sp] - add sp, sp, #4 - pop {pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_uidivmod() { + asm!( + "push {{lr}}", + "sub sp, sp, #4", + "mov r2, sp", + "bl ___udivmodsi4", + "ldr r1, [sp]", + "add sp, sp, #4", + "pop {{pc}}", + options(noreturn) + ); } #[cfg(not(target_os = "ios"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_uldivmod() { - llvm_asm!(" - push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl __udivmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_uldivmod() { + asm!( + "push {{r4, lr}}", + "sub sp, sp, #16", + "add r4, sp, #8", + "str r4, [sp]", + "bl __udivmoddi4", + "ldr r2, [sp, #8]", + "ldr r3, [sp, #12]", + "add sp, sp, #16", + "pop {{r4, pc}}", + options(noreturn) + ); } #[cfg(target_os = "ios")] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_uldivmod() { - llvm_asm!(" - push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl ___udivmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_uldivmod() { + asm!( + "push {{r4, lr}}", + "sub sp, sp, #16", + "add r4, sp, #8", + "str r4, [sp]", + "bl ___udivmoddi4", + "ldr r2, [sp, #8]", + "ldr r3, [sp, #12]", + "add sp, sp, #16", + "pop {{r4, pc}}", + options(noreturn) + ); } #[cfg(not(target_os = "ios"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_idivmod() { - llvm_asm!(" - push {r0, r1, r4, lr} - bl __aeabi_idiv - pop {r1, r2} - muls r2, r2, r0 - subs r1, r1, r2 - pop {r4, pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_idivmod() { + asm!( + "push {{r0, r1, r4, lr}}", + "bl __aeabi_idiv", + "pop {{r1, r2}}", + "muls r2, r2, r0", + "subs r1, r1, r2", + "pop {{r4, pc}}", + options(noreturn) + ); } #[cfg(target_os = "ios")] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_idivmod() { - llvm_asm!(" - push {r0, r1, r4, lr} - bl ___aeabi_idiv - pop {r1, r2} - muls r2, r2, r0 - subs r1, r1, r2 - pop {r4, pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_idivmod() { + asm!( + "push {{r0, r1, r4, lr}}", + "bl ___aeabi_idiv", + "pop {{r1, r2}}", + "muls r2, r2, r0", + "subs r1, r1, r2", + "pop {{r4, pc}}", + options(noreturn) + ); } #[cfg(not(target_os = "ios"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_ldivmod() { - llvm_asm!(" - push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl __divmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_ldivmod() { + asm!( + "push {{r4, lr}}", + "sub sp, sp, #16", + "add r4, sp, #8", + "str r4, [sp]", + "bl __divmoddi4", + "ldr r2, [sp, #8]", + "ldr r3, [sp, #12]", + "add sp, sp, #16", + "pop {{r4, pc}}", + options(noreturn) + ); } #[cfg(target_os = "ios")] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_ldivmod() { - llvm_asm!(" - push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl ___divmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_ldivmod() { + asm!( + "push {{r4, lr}}", + "sub sp, sp, #16", + "add r4, sp, #8", + "str r4, [sp]", + "bl ___divmoddi4", + "ldr r2, [sp, #8]", + "ldr r3, [sp, #12]", + "add sp, sp, #16", + "pop {{r4, pc}}", + options(noreturn) + ); } // The following functions use weak linkage to allow users to override diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 4a7c746a2ff..1f93042e461 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,7 +1,6 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![cfg_attr(not(feature = "no-asm"), feature(asm))] #![feature(abi_unadjusted)] -#![cfg_attr(not(feature = "no-asm"), feature(llvm_asm))] #![cfg_attr(not(feature = "no-asm"), feature(global_asm))] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index e038231bb0e..4992de9da04 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -16,26 +16,27 @@ use core::intrinsics; ))] #[naked] #[no_mangle] -pub unsafe fn ___chkstk_ms() { - llvm_asm!(" - push %ecx - push %eax - cmp $$0x1000,%eax - lea 12(%esp),%ecx - jb 1f - 2: - sub $$0x1000,%ecx - test %ecx,(%ecx) - sub $$0x1000,%eax - cmp $$0x1000,%eax - ja 2b - 1: - sub %eax,%ecx - test %ecx,(%ecx) - pop %eax - pop %ecx - ret" ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn ___chkstk_ms() { + asm!( + "push %ecx", + "push %eax", + "cmp $0x1000,%eax", + "lea 12(%esp),%ecx", + "jb 1f", + "2:", + "sub $0x1000,%ecx", + "test %ecx,(%ecx)", + "sub $0x1000,%eax", + "cmp $0x1000,%eax", + "ja 2b", + "1:", + "sub %eax,%ecx", + "test %ecx,(%ecx)", + "pop %eax", + "pop %ecx", + "ret", + options(noreturn, att_syntax) + ); } // FIXME: __alloca should be an alias to __chkstk @@ -47,10 +48,11 @@ pub unsafe fn ___chkstk_ms() { ))] #[naked] #[no_mangle] -pub unsafe fn __alloca() { - llvm_asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" - ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __alloca() { + asm!( + "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" + options(noreturn, att_syntax) + ); } #[cfg(all( @@ -61,27 +63,27 @@ pub unsafe fn __alloca() { ))] #[naked] #[no_mangle] -pub unsafe fn ___chkstk() { - llvm_asm!(" - push %ecx - cmp $$0x1000,%eax - lea 8(%esp),%ecx // esp before calling this routine -> ecx - jb 1f - 2: - sub $$0x1000,%ecx - test %ecx,(%ecx) - sub $$0x1000,%eax - cmp $$0x1000,%eax - ja 2b - 1: - sub %eax,%ecx - test %ecx,(%ecx) - - lea 4(%esp),%eax // load pointer to the return address into eax - mov %ecx,%esp // install the new top of stack pointer into esp - mov -4(%eax),%ecx // restore ecx - push (%eax) // push return address onto the stack - sub %esp,%eax // restore the original value in eax - ret" ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn ___chkstk() { + asm!( + "push %ecx", + "cmp $0x1000,%eax", + "lea 8(%esp),%ecx", // esp before calling this routine -> ecx + "jb 1f", + "2:", + "sub $0x1000,%ecx", + "test %ecx,(%ecx)", + "sub $0x1000,%eax", + "cmp $0x1000,%eax", + "ja 2b", + "1:", + "sub %eax,%ecx", + "test %ecx,(%ecx)", + "lea 4(%esp),%eax", // load pointer to the return address into eax + "mov %ecx,%esp", // install the new top of stack pointer into esp + "mov -4(%eax),%ecx", // restore ecx + "push (%eax)", // push return address onto the stack + "sub %esp,%eax", // restore the original value in eax + "ret", + options(noreturn, att_syntax) + ); } diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 91c0f24fca6..b382b886c55 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -16,26 +16,27 @@ use core::intrinsics; ))] #[naked] #[no_mangle] -pub unsafe fn ___chkstk_ms() { - llvm_asm!(" - push %rcx - push %rax - cmp $$0x1000,%rax - lea 24(%rsp),%rcx - jb 1f - 2: - sub $$0x1000,%rcx - test %rcx,(%rcx) - sub $$0x1000,%rax - cmp $$0x1000,%rax - ja 2b - 1: - sub %rax,%rcx - test %rcx,(%rcx) - pop %rax - pop %rcx - ret" ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn ___chkstk_ms() { + asm!( + "push %rcx", + "push %rax", + "cmp $0x1000,%rax", + "lea 24(%rsp),%rcx", + "jb 1f", + "2:", + "sub $0x1000,%rcx", + "test %rcx,(%rcx)", + "sub $0x1000,%rax", + "cmp $0x1000,%rax", + "ja 2b", + "1:", + "sub %rax,%rcx", + "test %rcx,(%rcx)", + "pop %rax", + "pop %rcx", + "ret", + options(noreturn, att_syntax) + ); } #[cfg(all( @@ -46,11 +47,12 @@ pub unsafe fn ___chkstk_ms() { ))] #[naked] #[no_mangle] -pub unsafe fn __alloca() { - llvm_asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx - jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" - ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __alloca() { + asm!( + "mov %rcx,%rax", // x64 _alloca is a normal function with parameter in rcx + "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" + options(noreturn, att_syntax) + ); } #[cfg(all( @@ -61,32 +63,29 @@ pub unsafe fn __alloca() { ))] #[naked] #[no_mangle] -pub unsafe fn ___chkstk() { - llvm_asm!( - " - push %rcx - cmp $$0x1000,%rax - lea 16(%rsp),%rcx // rsp before calling this routine -> rcx - jb 1f - 2: - sub $$0x1000,%rcx - test %rcx,(%rcx) - sub $$0x1000,%rax - cmp $$0x1000,%rax - ja 2b - 1: - sub %rax,%rcx - test %rcx,(%rcx) - - lea 8(%rsp),%rax // load pointer to the return address into rax - mov %rcx,%rsp // install the new top of stack pointer into rsp - mov -8(%rax),%rcx // restore rcx - push (%rax) // push return address onto the stack - sub %rsp,%rax // restore the original value in rax - ret" - ::: "memory" : "volatile" +pub unsafe extern "C" fn ___chkstk() { + asm!( + "push %rcx", + "cmp $0x1000,%rax", + "lea 16(%rsp),%rcx", // rsp before calling this routine -> rcx + "jb 1f", + "2:", + "sub $0x1000,%rcx", + "test %rcx,(%rcx)", + "sub $0x1000,%rax", + "cmp $0x1000,%rax", + "ja 2b", + "1:", + "sub %rax,%rcx", + "test %rcx,(%rcx)", + "lea 8(%rsp),%rax", // load pointer to the return address into rax + "mov %rcx,%rsp", // install the new top of stack pointer into rsp + "mov -8(%rax),%rcx", // restore rcx + "push (%rax)", // push return address onto the stack + "sub %rsp,%rax", // restore the original value in rax + "ret", + options(noreturn, att_syntax) ); - intrinsics::unreachable(); } // HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM -- cgit 1.4.1-3-g733a5 From 500c8e0b2c055d20b8d43f6778e7f86398a9071e Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 2 Apr 2021 09:44:10 -0500 Subject: add clippy to CI --- library/compiler-builtins/.github/workflows/main.yml | 18 ++++++++++++++++-- library/compiler-builtins/src/int/mod.rs | 2 ++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 01dffb8451e..6e2d83879a2 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -109,6 +109,20 @@ jobs: - uses: actions/checkout@v1 with: submodules: true - - name: Install Rust - run: rustup update stable && rustup default stable && rustup component add rustfmt + - name: Install stable `rustfmt` + run: rustup set profile minimal && rustup default stable && rustup component add rustfmt - run: cargo fmt -- --check + + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + with: + submodules: true + # Unlike rustfmt, stable clippy does not work on code with nightly features. + # This acquires the most recent nightly with a clippy component. + - name: Install nightly `clippy` + run: | + rustup set profile minimal && rustup default "nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/clippy)" && rustup component add clippy + - run: cargo clippy -- -D clippy::all diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 2190a69b9d3..080a415de34 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -210,6 +210,8 @@ macro_rules! int_impl { self } + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] fn from_unsigned(me: $uty) -> Self { me } -- cgit 1.4.1-3-g733a5 From 6cd2f3ae40c60bb7bbd546d2470a10c97b4b8b34 Mon Sep 17 00:00:00 2001 From: messense Date: Wed, 24 Mar 2021 13:49:12 +0800 Subject: Add compiler-rt fallbacks on mips64-musl --- library/compiler-builtins/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index f948edba9eb..701c4d4950b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -449,6 +449,8 @@ mod c { ("__fixunstfsi", "fixunstfsi.c"), ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), + ("__divtf3", "divtf3.c"), + ("__trunctfdf2", "trunctfdf2.c"), ]); } -- cgit 1.4.1-3-g733a5 From 8c4127d044a78179f24f92b80133694b5c3a2a47 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sat, 3 Apr 2021 18:57:16 +0100 Subject: Add `#[linkage = "weak"]` attribute to all `mem` instrinics. --- library/compiler-builtins/src/mem/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index 03dc965ca4a..3d7372c8273 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -20,12 +20,14 @@ use core::ops::{BitOr, Shl}; mod impls; #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { impls::copy_forward(dest, src, n); dest } #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { let delta = (dest as usize).wrapping_sub(src as usize); if delta >= n { @@ -39,12 +41,14 @@ pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mu } #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { impls::set_bytes(s, c as u8, n); s } #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { let mut i = 0; while i < n { @@ -59,6 +63,7 @@ pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { } #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { memcmp(s1, s2, n) } -- cgit 1.4.1-3-g733a5 From 5dd043525adbd1db4519874afa800a62f1fc31d2 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 10 Apr 2021 16:03:19 +0200 Subject: Fix typo --- library/compiler-builtins/src/arm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 545d6a17a45..82c41fc5a10 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -2,8 +2,8 @@ use core::intrinsics; -// NOTE This function and the ones below are implemented using assembly because they using a custom -// calling convention which can't be implemented using a normal Rust function. +// NOTE This function and the ones below are implemented using assembly because they are using a +// custom calling convention which can't be implemented using a normal Rust function. // NOTE The only difference between the iOS and non-iOS versions of those functions is that the iOS // versions use 3 leading underscores in the names of called functions instead of 2. #[cfg(not(any(target_os = "ios", target_env = "msvc")))] -- cgit 1.4.1-3-g733a5 From 68df0eb8178799c4b032d3c375528918412cd4e5 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 10 Apr 2021 19:13:02 +0100 Subject: Mark global_asm! code with .att_syntax global_asm! will soon change to use Intel syntax by default. --- library/compiler-builtins/src/probestack.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index ac3ae1ebbc4..6892ab2d3ea 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -48,6 +48,8 @@ #![cfg(not(feature = "no-asm"))] // We only define stack probing for these architectures today. #![cfg(any(target_arch = "x86_64", target_arch = "x86"))] +// We need to add .att_syntax for bootstraping the new global_asm! +#![allow(unknown_lints, bad_asm_style)] extern "C" { pub fn __rust_probestack(); @@ -63,6 +65,7 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " + .att_syntax .pushsection .text.__rust_probestack .globl __rust_probestack .type __rust_probestack, @function -- cgit 1.4.1-3-g733a5 From 79916f0ac8155d9a0174490d3df690427fe4be52 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 11 Apr 2021 20:56:38 +0100 Subject: Bump to 0.1.40 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f1052d59d67..8d0c05084aa 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.39" +version = "0.1.40" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 189b987a250b05dd1628c5cf8703bc88223e3ada Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 23 Apr 2021 18:54:12 +0100 Subject: Revert "Disable AArch64 FP-to-int tests" This reverts commit 9e76b9115fa9571501d378b6329ce557266908b7. --- library/compiler-builtins/testcrate/tests/conv.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 17c31a8a00e..7cdbf9fbb69 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -95,8 +95,6 @@ macro_rules! f_to_i { }; } -// AArch64 tests are currently broken due to https://github.com/rust-lang/rust/issues/83467 -#[cfg(not(target_arch = "aarch64"))] #[test] fn float_to_int() { use compiler_builtins::float::conv::{ -- cgit 1.4.1-3-g733a5 From 61b2242af9c7cd48e65cacd781afdcff29297349 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 30 Apr 2021 19:15:53 +0100 Subject: Fix CI on latest nightly --- library/compiler-builtins/examples/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index ddbb976a252..dfa46b1b8fe 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -6,7 +6,7 @@ #![allow(unused_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] -#![feature(test)] +#![feature(bench_black_box)] #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] -- cgit 1.4.1-3-g733a5 From 5edaec6c970c92f5613021032790ea65037014ca Mon Sep 17 00:00:00 2001 From: George Burgess IV Date: Tue, 2 Mar 2021 15:50:09 -0800 Subject: add support for building outlined aarch64 intrinsics llvm/llvm-project@a4ac434c47434d80bca54bab96f295ed4e972cc6 saw the addition of out-of-line aarch64 atomic intrinsics. LLVM will sometimes emit these, so we need to ensure they're included in Rust's compiler-rt. --- library/compiler-builtins/build.rs | 71 +++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 701c4d4950b..2ff6443d7de 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -81,7 +81,7 @@ mod c { use std::collections::BTreeMap; use std::env; - use std::path::PathBuf; + use std::path::{Path, PathBuf}; struct Sources { // SYMBOL -> PATH TO SOURCE @@ -489,7 +489,20 @@ mod c { // use of that macro in lib/builtins/int_util.h in compiler-rt. cfg.flag_if_supported(&format!("-ffile-prefix-map={}=.", root.display())); + // Include out-of-line atomics for aarch64, which are all generated by supplying different + // sets of flags to the same source file. let src_dir = root.join("lib/builtins"); + if target_arch == "aarch64" { + let atomics_libs = build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); + if !atomics_libs.is_empty() { + for library in atomics_libs { + cfg.object(library); + } + // Some run-time CPU feature detection is necessary, as well. + sources.extend(&[("__aarch64_have_lse_atomics", "cpu_model.c")]); + } + } + for (sym, src) in sources.map.iter() { let src = src_dir.join(src); cfg.file(&src); @@ -499,4 +512,60 @@ mod c { cfg.compile("libcompiler-rt.a"); } + + fn build_aarch64_out_of_line_atomics_libraries( + builtins_dir: &Path, + cfg: &cc::Build, + ) -> Vec { + // NOTE: because we're recompiling the same source file in N different ways, building + // serially is necessary. If we want to lift this restriction, we can either: + // - create symlinks to lse.S and build those_(though we'd still need to pass special + // #define-like flags to each of these), or + // - synthesizing tiny .S files in out/ with the proper #defines, which ultimately #include + // lse.S. + // That said, it's unclear how useful this added complexity will be, so just do the simple + // thing for now. + let outlined_atomics_file = builtins_dir.join("aarch64/lse.S"); + + // A stable release hasn't been made with lse.S yet. Until we pick that up, do nothing. + if !outlined_atomics_file.exists() { + return vec![]; + } + + println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); + let out_dir: PathBuf = env::var("OUT_DIR").unwrap().into(); + + // Ideally, this would be a Vec of object files, but cc doesn't make it *entirely* + // trivial to build an individual object. + let mut atomics_libraries = Vec::new(); + for instruction_type in &["cas", "cwp", "ldadd", "ldclr", "ldeor", "ldset"] { + for size in &[1, 2, 4, 8, 16] { + if *size == 16 && *instruction_type != "cas" { + continue; + } + + for (model_number, model_name) in + &[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")] + { + let library_name = format!( + "liboutline_atomic_helper_{}_{}_{}.a", + instruction_type, size, model_name + ); + let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); + let mut cfg = cfg.clone(); + + cfg.include(&builtins_dir) + .define(&format!("L_{}", instruction_type), None) + .define("SIZE", size.to_string().as_str()) + .define("MODEL", model_number.to_string().as_str()) + .file(&outlined_atomics_file); + cfg.compile(&library_name); + + atomics_libraries.push(out_dir.join(library_name)); + println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); + } + } + } + atomics_libraries + } } -- cgit 1.4.1-3-g733a5 From b9da06f662b5fe013b2601550b81ba9ad22e87b1 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 30 Apr 2021 02:38:39 -0700 Subject: Fix typo in instruction name: s/cwp/swp/ --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2ff6443d7de..26296db0c84 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -538,7 +538,7 @@ mod c { // Ideally, this would be a Vec of object files, but cc doesn't make it *entirely* // trivial to build an individual object. let mut atomics_libraries = Vec::new(); - for instruction_type in &["cas", "cwp", "ldadd", "ldclr", "ldeor", "ldset"] { + for instruction_type in &["cas", "swp", "ldadd", "ldclr", "ldeor", "ldset"] { for size in &[1, 2, 4, 8, 16] { if *size == 16 && *instruction_type != "cas" { continue; -- cgit 1.4.1-3-g733a5 From df8e6f179a7f9045464617a8ce7d23bc7c90bfe1 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 30 Apr 2021 02:39:07 -0700 Subject: Require lse.S (now available in current LLVM) --- library/compiler-builtins/build.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 26296db0c84..2178dc9353c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -526,13 +526,8 @@ mod c { // That said, it's unclear how useful this added complexity will be, so just do the simple // thing for now. let outlined_atomics_file = builtins_dir.join("aarch64/lse.S"); - - // A stable release hasn't been made with lse.S yet. Until we pick that up, do nothing. - if !outlined_atomics_file.exists() { - return vec![]; - } - println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); + let out_dir: PathBuf = env::var("OUT_DIR").unwrap().into(); // Ideally, this would be a Vec of object files, but cc doesn't make it *entirely* -- cgit 1.4.1-3-g733a5 From 79c1e33364b002391584a35281d2862c1209efec Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 30 Apr 2021 02:41:44 -0700 Subject: Make the name of the intermediate library more closely match the intrinsic --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2178dc9353c..3ba6d5883f2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -543,7 +543,7 @@ mod c { &[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")] { let library_name = format!( - "liboutline_atomic_helper_{}_{}_{}.a", + "liboutline_atomic_helper_{}{}_{}.a", instruction_type, size, model_name ); let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); -- cgit 1.4.1-3-g733a5 From fee637a7b6366200952775abe399eafb404a8a7b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 30 Apr 2021 12:24:12 -0700 Subject: Update the version of compiler-rt in CI --- library/compiler-builtins/.github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 6e2d83879a2..3d63bc070cd 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -88,8 +88,8 @@ jobs: - run: rustup component add llvm-tools-preview - name: Download compiler-rt reference sources run: | - curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/10.0-2020-05-05.tar.gz - tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-10.0-2020-05-05/compiler-rt + curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/12.0-2021-04-15.tar.gz + tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-12.0-2021-04-15/compiler-rt echo RUST_COMPILER_RT_ROOT=./compiler-rt >> $GITHUB_ENV shell: bash -- cgit 1.4.1-3-g733a5 From a77e15f562fca6e2646e44726e32ec5703fef75b Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 30 Apr 2021 21:03:06 +0100 Subject: Bump to 0.1.41 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 8d0c05084aa..c59f7872882 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.40" +version = "0.1.41" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From fdbeb187ec5239d73798ddb87f17b506c3816757 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 2 May 2021 21:29:00 +0100 Subject: Add missing .att_syntax from #414 --- library/compiler-builtins/src/probestack.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 6892ab2d3ea..4d6cd694943 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -86,6 +86,7 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " + .att_syntax .globl __rust_probestack __rust_probestack: ", @@ -101,6 +102,7 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " + .att_syntax .globl ___rust_probestack ___rust_probestack: ", @@ -115,6 +117,7 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " + .att_syntax .globl ___rust_probestack ___rust_probestack: ", -- cgit 1.4.1-3-g733a5 From fcf675bf4a6d80500525655ad0a567f44fd0d84d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 2 May 2021 22:12:49 +0100 Subject: Bump to 0.1.42 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c59f7872882..0f5faebac44 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.41" +version = "0.1.42" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 1630c86e0761d9c9772cdc9dda28ad7a0e06581b Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 13 May 2021 21:35:34 +0100 Subject: Don't embed lse_*.a inside another static library --- library/compiler-builtins/build.rs | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 3ba6d5883f2..297a0adff05 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -493,14 +493,11 @@ mod c { // sets of flags to the same source file. let src_dir = root.join("lib/builtins"); if target_arch == "aarch64" { - let atomics_libs = build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); - if !atomics_libs.is_empty() { - for library in atomics_libs { - cfg.object(library); - } - // Some run-time CPU feature detection is necessary, as well. - sources.extend(&[("__aarch64_have_lse_atomics", "cpu_model.c")]); - } + // See below for why we're building these as separate libraries. + build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); + + // Some run-time CPU feature detection is necessary, as well. + sources.extend(&[("__aarch64_have_lse_atomics", "cpu_model.c")]); } for (sym, src) in sources.map.iter() { @@ -513,10 +510,7 @@ mod c { cfg.compile("libcompiler-rt.a"); } - fn build_aarch64_out_of_line_atomics_libraries( - builtins_dir: &Path, - cfg: &cc::Build, - ) -> Vec { + fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &cc::Build) { // NOTE: because we're recompiling the same source file in N different ways, building // serially is necessary. If we want to lift this restriction, we can either: // - create symlinks to lse.S and build those_(though we'd still need to pass special @@ -528,11 +522,8 @@ mod c { let outlined_atomics_file = builtins_dir.join("aarch64/lse.S"); println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); - let out_dir: PathBuf = env::var("OUT_DIR").unwrap().into(); - // Ideally, this would be a Vec of object files, but cc doesn't make it *entirely* // trivial to build an individual object. - let mut atomics_libraries = Vec::new(); for instruction_type in &["cas", "swp", "ldadd", "ldclr", "ldeor", "ldset"] { for size in &[1, 2, 4, 8, 16] { if *size == 16 && *instruction_type != "cas" { @@ -556,11 +547,9 @@ mod c { .file(&outlined_atomics_file); cfg.compile(&library_name); - atomics_libraries.push(out_dir.join(library_name)); println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); } } } - atomics_libraries } } -- cgit 1.4.1-3-g733a5 From 924d71851160705925f23e3398f2f327f4043efc Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 13 May 2021 21:41:46 +0100 Subject: Bump to 0.1.43 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0f5faebac44..f5ba632a031 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.42" +version = "0.1.43" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From c041104afd529680657fb10734062579b4c4c71f Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 26 May 2021 12:22:52 +0900 Subject: Suppress some warnings --- library/compiler-builtins/src/arm.rs | 1 + library/compiler-builtins/src/mem/mod.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 82c41fc5a10..7203d91e4a9 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,4 +1,5 @@ #![cfg(not(feature = "no-asm"))] +#![allow(unused_imports)] use core::intrinsics; diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index 3d7372c8273..2f9a9fd945e 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -69,6 +69,7 @@ pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { } // `bytes` must be a multiple of `mem::size_of::()` +#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { unsafe { let n = exact_div(bytes, mem::size_of::()); @@ -81,6 +82,7 @@ fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: } // `bytes` must be a multiple of `mem::size_of::()` +#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] fn memmove_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { unsafe { let n = exact_div(bytes, mem::size_of::()); @@ -103,6 +105,7 @@ fn memmove_element_unordered_atomic(dest: *mut T, src: *const T, bytes: } // `T` must be a primitive integer type, and `bytes` must be a multiple of `mem::size_of::()` +#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] fn memset_element_unordered_atomic(s: *mut T, c: u8, bytes: usize) where T: Copy + From + Shl + BitOr, -- cgit 1.4.1-3-g733a5 From 31e3ae708c51e42f3e13043fa11c2ec13ce9df8b Mon Sep 17 00:00:00 2001 From: Tilmann Meyer Date: Mon, 31 May 2021 16:32:46 +0200 Subject: Include Linux atomic emulation on androideabi The old androideabi uses armv5 and thus also needs the atomic emulation and because Android is basically Linux it can use the same implementation. --- library/compiler-builtins/build.rs | 7 +++++-- library/compiler-builtins/src/lib.rs | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 297a0adff05..0fb1e17bebc 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -69,8 +69,11 @@ fn main() { println!("cargo:rustc-cfg=thumb_1") } - // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. - if llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" { + // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. This + // includes the old androideabi. It is deprecated but it is available as a + // rustc target (arm-linux-androideabi). + if llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" || llvm_target[2] == "androideabi" + { println!("cargo:rustc-cfg=kernel_user_helpers") } } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index facdf946f6b..21796ca5541 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -49,7 +49,11 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; -#[cfg(all(kernel_user_helpers, target_os = "linux", target_arch = "arm"))] +#[cfg(all( + kernel_user_helpers, + any(target_os = "linux", target_os = "android"), + target_arch = "arm" +))] pub mod arm_linux; #[cfg(any(target_arch = "riscv32"))] -- cgit 1.4.1-3-g733a5 From bc956a76952d4e2418b30e0e8da18e1c36999d91 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 1 Jun 2021 19:08:32 +0100 Subject: Bump to 0.1.44 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f5ba632a031..5c917fc6838 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.43" +version = "0.1.44" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From fdcc30c3a386a5753cbbf898c9d6a68d10421c64 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Wed, 2 Jun 2021 13:11:28 -0500 Subject: Add public-test-deps feature for better visibility control --- library/compiler-builtins/Cargo.toml | 4 ++++ library/compiler-builtins/src/float/mod.rs | 5 +++-- library/compiler-builtins/src/int/leading_zeros.rs | 10 ++++++---- library/compiler-builtins/src/int/mod.rs | 20 ++++++++++++-------- .../src/int/specialized_div_rem/asymmetric.rs | 3 +-- .../src/int/specialized_div_rem/binary_long.rs | 3 +-- .../src/int/specialized_div_rem/delegate.rs | 10 ++++++---- .../src/int/specialized_div_rem/mod.rs | 7 +++++++ .../src/int/specialized_div_rem/norm_shift.rs | 3 +-- .../src/int/specialized_div_rem/trifecta.rs | 3 +-- library/compiler-builtins/src/int/udiv.rs | 7 +++++-- library/compiler-builtins/src/macros.rs | 16 ++++++++++++++++ library/compiler-builtins/testcrate/Cargo.toml | 2 +- 13 files changed, 64 insertions(+), 29 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f5ba632a031..e1f5cbf8fea 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -64,6 +64,10 @@ no-lang-items = [] # Only used in the compiler's build system rustc-dep-of-std = ['compiler-builtins', 'core'] +# This makes certain traits and function specializations public that +# are not normally public but are required by the `testcrate` +public-test-deps = [] + [[example]] name = "intrinsics" required-features = ["compiler-builtins"] diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 69e4dc63517..11680e7a9fa 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -11,9 +11,9 @@ pub mod mul; pub mod pow; pub mod sub; +public_test_dep! { /// Trait for some basic operations on floats -#[doc(hidden)] -pub trait Float: +pub(crate) trait Float: Copy + core::fmt::Debug + PartialEq @@ -99,6 +99,7 @@ pub trait Float: /// Returns if `self` is subnormal fn is_subnormal(self) -> bool; } +} macro_rules! float_impl { ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index e4a9e5eb2b4..0265b9a9d02 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -3,9 +3,9 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. +public_test_dep! { /// Returns the number of leading binary zeros in `x`. -#[doc(hidden)] -pub fn usize_leading_zeros_default(x: usize) -> usize { +pub(crate) fn usize_leading_zeros_default(x: usize) -> usize { // The basic idea is to test if the higher bits of `x` are zero and bisect the number // of leading zeros. It is possible for all branches of the bisection to use the same // code path by conditionally shifting the higher parts down to let the next bisection @@ -69,15 +69,16 @@ pub fn usize_leading_zeros_default(x: usize) -> usize { // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO // execution effects. Changing to using a LUT and branching is risky for smaller cores. } +} // The above method does not compile well on RISC-V (because of the lack of predicated // instructions), producing code with many branches or using an excessively long // branchless solution. This method takes advantage of the set-if-less-than instruction on // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. +public_test_dep! { /// Returns the number of leading binary zeros in `x`. -#[doc(hidden)] -pub fn usize_leading_zeros_riscv(x: usize) -> usize { +pub(crate) fn usize_leading_zeros_riscv(x: usize) -> usize { let mut x = x; // the number of potential leading zeros let mut z = usize::MAX.count_ones() as usize; @@ -126,6 +127,7 @@ pub fn usize_leading_zeros_riscv(x: usize) -> usize { // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. z - x } +} intrinsics! { #[maybe_use_optimized_c_shim] diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 080a415de34..509f9fdae39 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -11,9 +11,9 @@ pub mod udiv; pub use self::leading_zeros::__clzsi2; +public_test_dep! { /// Trait for some basic operations on integers -#[doc(hidden)] -pub trait Int: +pub(crate) trait Int: Copy + core::fmt::Debug + PartialEq @@ -81,6 +81,7 @@ pub trait Int: fn overflowing_add(self, other: Self) -> (Self, bool); fn leading_zeros(self) -> u32; } +} macro_rules! int_impl_common { ($ty:ty) => { @@ -255,10 +256,10 @@ int_impl!(i32, u32); int_impl!(i64, u64); int_impl!(i128, u128); +public_test_dep! { /// Trait for integers twice the bit width of another integer. This is implemented for all /// primitives except for `u8`, because there is not a smaller primitive. -#[doc(hidden)] -pub trait DInt: Int { +pub(crate) trait DInt: Int { /// Integer that is half the bit width of the integer this trait is implemented for type H: HInt + Int; @@ -271,11 +272,12 @@ pub trait DInt: Int { /// Constructs an integer using lower and higher half parts fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self; } +} +public_test_dep! { /// Trait for integers half the bit width of another integer. This is implemented for all /// primitives except for `u128`, because it there is not a larger primitive. -#[doc(hidden)] -pub trait HInt: Int { +pub(crate) trait HInt: Int { /// Integer that is double the bit width of the integer this trait is implemented for type D: DInt + Int; @@ -291,6 +293,7 @@ pub trait HInt: Int { /// Widening multiplication. This cannot overflow. fn widen_mul(self, rhs: Self) -> Self::D; } +} macro_rules! impl_d_int { ($($X:ident $D:ident),*) => { @@ -353,11 +356,12 @@ impl_h_int!( i64 u64 i128 ); +public_test_dep! { /// Trait to express (possibly lossy) casting of integers -#[doc(hidden)] -pub trait CastInto: Copy { +pub(crate) trait CastInto: Copy { fn cast(self) -> T; } +} macro_rules! cast_into { ($ty:ty) => { diff --git a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs index 45da657e9c9..56ce188a373 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs @@ -3,8 +3,7 @@ /// assembly instruction that can divide a 128 bit integer by a 64 bit integer if the quotient fits /// in 64 bits. The 128 bit version of this algorithm would use that fast hardware division to /// construct a full 128 bit by 128 bit division. -#[doc(hidden)] -#[macro_export] +#[allow(unused_macros)] macro_rules! impl_asymmetric { ( $fn:ident, // name of the unsigned division function diff --git a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs index 7de10e85276..0d7822882b0 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs @@ -4,8 +4,7 @@ /// predicate instructions. For architectures with predicated instructions, one of the algorithms /// described in the documentation of these functions probably has higher performance, and a custom /// assembly routine should be used instead. -#[doc(hidden)] -#[macro_export] +#[allow(unused_macros)] macro_rules! impl_binary_long { ( $fn:ident, // name of the unsigned division function diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index 135d3402a3a..330c6e4f80b 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -2,8 +2,7 @@ /// binary long division to divide integers larger than what hardware division by itself can do. This /// function is intended for microarchitectures that have division hardware, but not fast enough /// multiplication hardware for `impl_trifecta` to be faster. -#[doc(hidden)] -#[macro_export] +#[allow(unused_macros)] macro_rules! impl_delegate { ( $fn:ident, // name of the unsigned division function @@ -186,6 +185,7 @@ macro_rules! impl_delegate { }; } +public_test_dep! { /// Returns `n / d` and sets `*rem = n % d`. /// /// This specialization exists because: @@ -193,8 +193,9 @@ macro_rules! impl_delegate { /// so we have to use an old fashioned `&mut u128` argument to return the remainder. /// - 64-bit SPARC does not have u64 * u64 => u128 widening multiplication, which makes the /// delegate algorithm strategy the only reasonably fast way to perform `u128` division. -#[doc(hidden)] -pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { +// used on SPARC +#[allow(dead_code)] +pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { use super::*; let duo_lo = duo as u64; let duo_hi = (duo >> 64) as u64; @@ -315,3 +316,4 @@ pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { } } } +} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 391db765da4..f5b2af235bd 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -53,6 +53,13 @@ mod binary_long; #[macro_use] mod delegate; + +// used on SPARC +#[allow(unused_imports)] +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use self::delegate::u128_divide_sparc; + +#[cfg(feature = "public-test-deps")] pub use self::delegate::u128_divide_sparc; #[macro_use] diff --git a/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs b/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs index be95d1b927e..61b67b6bc3d 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs @@ -1,6 +1,5 @@ /// Creates a function used by some division algorithms to compute the "normalization shift". -#[doc(hidden)] -#[macro_export] +#[allow(unused_macros)] macro_rules! impl_normalization_shift { ( $name:ident, // name of the normalization shift function diff --git a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs index a9ea603019d..7e104053b8b 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs @@ -2,8 +2,7 @@ /// larger than the largest hardware integer division supported. These functions use large radix /// division algorithms that require both fast division and very fast widening multiplication on the /// target microarchitecture. Otherwise, `impl_delegate` should be used instead. -#[doc(hidden)] -#[macro_export] +#[allow(unused_macros)] macro_rules! impl_trifecta { ( $fn:ident, // name of the unsigned division function diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index d9717807849..2f236346d3d 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,5 +1,8 @@ -pub use int::specialized_div_rem::u128_divide_sparc; -use int::specialized_div_rem::*; +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use int::specialized_div_rem::*; + +#[cfg(feature = "public-test-deps")] +pub use int::specialized_div_rem::*; intrinsics! { #[maybe_use_optimized_c_shim] diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 56f27164a93..214f0795fc5 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,5 +1,21 @@ //! Macros shared throughout the compiler-builtins implementation +/// Changes the visibility to `pub` if feature "public-test-deps" is set +#[cfg(not(feature = "public-test-deps"))] +macro_rules! public_test_dep { + ($(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => { + $(#[$($meta)*])* pub(crate) $ident $($tokens)* + }; +} + +/// Changes the visibility to `pub` if feature "public-test-deps" is set +#[cfg(feature = "public-test-deps")] +macro_rules! public_test_dep { + {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*} => { + $(#[$($meta)*])* pub $ident $($tokens)* + }; +} + /// The "main macro" used for defining intrinsics. /// /// The compiler-builtins library is super platform-specific with tons of crazy diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index a066a11345a..1f77b255491 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -17,7 +17,7 @@ rand_xoshiro = "0.6" [dependencies.compiler_builtins] path = ".." default-features = false -features = ["no-lang-items"] +features = ["no-lang-items", "public-test-deps"] [target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] test = { git = "https://github.com/japaric/utest" } -- cgit 1.4.1-3-g733a5 From 77d9a28bbb6df8449a926b748044ee923b6aa75c Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 3 Jun 2021 22:59:34 +0100 Subject: Fix build on targets with fewer than 3 components in their name --- library/compiler-builtins/build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0fb1e17bebc..f0617b6e92a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -72,7 +72,9 @@ fn main() { // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. This // includes the old androideabi. It is deprecated but it is available as a // rustc target (arm-linux-androideabi). - if llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" || llvm_target[2] == "androideabi" + if llvm_target[0] == "armv4t" + || llvm_target[0] == "armv5te" + || llvm_target.get(2) == Some(&"androideabi") { println!("cargo:rustc-cfg=kernel_user_helpers") } -- cgit 1.4.1-3-g733a5 From bca8bedb939369b7a462ea83067920fc75510d5c Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 4 Jun 2021 00:20:57 +0100 Subject: Bump to 0.1.45 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f5d450938a6..2dd5a61ebf2 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.44" +version = "0.1.45" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From a9c912c42f92679abde009987552dadb9dc29725 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Thu, 24 Jun 2021 15:58:36 +0200 Subject: Fix build failure with latest nightly --- library/compiler-builtins/libm/src/math/pow.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index c7fd0dfa117..f79680a05d0 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -604,7 +604,7 @@ mod tests { // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - &[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS] + (&[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS]) .iter() .for_each(|int_set| { int_set.iter().for_each(|int| { @@ -616,7 +616,7 @@ mod tests { // Negative base (imaginary results): // (-anything except 0 and Infinity ^ non-integer should be NAN) - &NEG[1..(NEG.len() - 1)].iter().for_each(|set| { + (&NEG[1..(NEG.len() - 1)]).iter().for_each(|set| { set.iter().for_each(|val| { test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| NAN); }) -- cgit 1.4.1-3-g733a5 From eedfb239a35e1b2e0cf30c96776f3fe7b9f9d8c7 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Tue, 22 Jun 2021 18:06:17 +0200 Subject: Fix substract with borrow in FMA Fixes rust-lang/libm#242 --- library/compiler-builtins/libm/src/math/fma.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 3219dbcce1f..85d842119cb 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -122,9 +122,9 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { rhi += zhi + (rlo < zlo) as u64; } else { /* r -= z */ - let t = rlo; - rlo = rlo.wrapping_sub(zlo); - rhi = rhi.wrapping_sub(zhi.wrapping_sub((t < rlo) as u64)); + let (res, borrow) = rlo.overflowing_sub(zlo); + rlo = res; + rhi = rhi.wrapping_sub(zhi.wrapping_add(borrow as u64)); if (rhi >> 63) != 0 { rlo = (-(rlo as i64)) as u64; rhi = (-(rhi as i64)) as u64 - (rlo != 0) as u64; @@ -218,6 +218,14 @@ mod tests { -0.00000000000000022204460492503126, ); - assert_eq!(fma(-0.992, -0.992, -0.992), -0.00793599999988632,); + assert_eq!(fma(-0.992, -0.992, -0.992), -0.007936000000000007,); + } + + #[test] + fn fma_sbb() { + assert_eq!( + fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), + -3991680619069439e277 + ); } } -- cgit 1.4.1-3-g733a5 From 0534e104f312cea63f6eff57d3dc997040a13c55 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Fri, 25 Jun 2021 11:52:14 +0200 Subject: Update libm --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 2dd5a61ebf2..6f579f57b1c 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.45" +version = "0.1.46" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index fe396e00b7e..c2d22bf95e2 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit fe396e00b7e47821a81c4c87a481ddc6af1d2cdf +Subproject commit c2d22bf95e2f032ae6b237e8e4c336bc795a151c -- cgit 1.4.1-3-g733a5 From 5f23bf3c9bc4cf1681586003c3dca877ad0760a6 Mon Sep 17 00:00:00 2001 From: Brian Vincent Date: Wed, 30 Jun 2021 22:35:47 -0500 Subject: Optimize round and roundf --- library/compiler-builtins/libm/src/math/round.rs | 46 +++++++---------------- library/compiler-builtins/libm/src/math/roundf.rs | 44 +++++++--------------- 2 files changed, 28 insertions(+), 62 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index bf72f5b941d..46fabc90ff5 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -1,38 +1,10 @@ +use super::copysign; +use super::trunc; use core::f64; -const TOINT: f64 = 1.0 / f64::EPSILON; - #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn round(mut x: f64) -> f64 { - let i = x.to_bits(); - let e: u64 = i >> 52 & 0x7ff; - let mut y: f64; - - if e >= 0x3ff + 52 { - return x; - } - if e < 0x3ff - 1 { - // raise inexact if x!=0 - force_eval!(x + TOINT); - return 0.0 * x; - } - if i >> 63 != 0 { - x = -x; - } - y = x + TOINT - TOINT - x; - if y > 0.5 { - y = y + x - 1.0; - } else if y <= -0.5 { - y = y + x + 1.0; - } else { - y = y + x; - } - - if i >> 63 != 0 { - -y - } else { - y - } +pub fn round(x: f64) -> f64 { + trunc(x + copysign(0.5 - 0.25 * f64::EPSILON, x)) } #[cfg(test)] @@ -43,4 +15,14 @@ mod tests { fn negative_zero() { assert_eq!(round(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); } + + #[test] + fn sanity_check() { + assert_eq!(round(-1.0), -1.0); + assert_eq!(round(2.8), 3.0); + assert_eq!(round(-0.5), -1.0); + assert_eq!(round(0.5), 1.0); + assert_eq!(round(-1.5), -2.0); + assert_eq!(round(1.5), 2.0); + } } diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index 497e88d6254..c0872a7829d 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -1,36 +1,10 @@ +use super::copysignf; +use super::truncf; use core::f32; -const TOINT: f32 = 1.0 / f32::EPSILON; - #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf(mut x: f32) -> f32 { - let i = x.to_bits(); - let e: u32 = i >> 23 & 0xff; - let mut y: f32; - - if e >= 0x7f + 23 { - return x; - } - if e < 0x7f - 1 { - force_eval!(x + TOINT); - return 0.0 * x; - } - if i >> 31 != 0 { - x = -x; - } - y = x + TOINT - TOINT - x; - if y > 0.5f32 { - y = y + x - 1.0; - } else if y <= -0.5f32 { - y = y + x + 1.0; - } else { - y = y + x; - } - if i >> 31 != 0 { - -y - } else { - y - } +pub fn roundf(x: f32) -> f32 { + truncf(x + copysignf(0.5 - 0.25 * f32::EPSILON, x)) } #[cfg(test)] @@ -41,4 +15,14 @@ mod tests { fn negative_zero() { assert_eq!(roundf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); } + + #[test] + fn sanity_check() { + assert_eq!(roundf(-1.0), -1.0); + assert_eq!(roundf(2.8), 3.0); + assert_eq!(roundf(-0.5), -1.0); + assert_eq!(roundf(0.5), 1.0); + assert_eq!(roundf(-1.5), -2.0); + assert_eq!(roundf(1.5), 2.0); + } } -- cgit 1.4.1-3-g733a5 From 5428334eaac521c8c3a9ec65f1221e0082311b15 Mon Sep 17 00:00:00 2001 From: SuKiN-a Date: Fri, 9 Jul 2021 09:52:08 +0530 Subject: updated link to musl website --- library/compiler-builtins/libm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 5d9e9bddbf8..b864b5df8e7 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -2,7 +2,7 @@ A port of [MUSL]'s libm to Rust. -[MUSL]: https://www.musl-libc.org/ +[MUSL]: https://musl.libc.org/ ## Goals -- cgit 1.4.1-3-g733a5 From 6ff825785857197058b56d938a19403edded9839 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Tue, 13 Jul 2021 21:11:12 -0700 Subject: Support `long double` intrinsics in any aarch64 linux Expands the support added in #377 from just musl to any linux. Also checks for and avoids adding duplicate sources. Fixes #428 --- library/compiler-builtins/build.rs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index f0617b6e92a..730ea61dfc6 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -84,7 +84,7 @@ fn main() { mod c { extern crate cc; - use std::collections::BTreeMap; + use std::collections::{BTreeMap, HashSet}; use std::env; use std::path::{Path, PathBuf}; @@ -419,23 +419,18 @@ mod c { ("__floatunsitf", "floatunsitf.c"), ("__trunctfdf2", "trunctfdf2.c"), ("__trunctfsf2", "trunctfsf2.c"), + ("__addtf3", "addtf3.c"), + ("__multf3", "multf3.c"), + ("__subtf3", "subtf3.c"), + ("__divtf3", "divtf3.c"), + ("__powitf2", "powitf2.c"), + ("__fe_getround", "fp_mode.c"), + ("__fe_raise_inexact", "fp_mode.c"), ]); if target_os != "windows" { sources.extend(&[("__multc3", "multc3.c")]); } - - if target_env == "musl" { - sources.extend(&[ - ("__addtf3", "addtf3.c"), - ("__multf3", "multf3.c"), - ("__subtf3", "subtf3.c"), - ("__divtf3", "divtf3.c"), - ("__powitf2", "powitf2.c"), - ("__fe_getround", "fp_mode.c"), - ("__fe_raise_inexact", "fp_mode.c"), - ]); - } } if target_arch == "mips" { @@ -505,10 +500,13 @@ mod c { sources.extend(&[("__aarch64_have_lse_atomics", "cpu_model.c")]); } + let mut added_sources = HashSet::new(); for (sym, src) in sources.map.iter() { let src = src_dir.join(src); - cfg.file(&src); - println!("cargo:rerun-if-changed={}", src.display()); + if added_sources.insert(src.clone()) { + cfg.file(&src); + println!("cargo:rerun-if-changed={}", src.display()); + } println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); } -- cgit 1.4.1-3-g733a5 From b1440f2b0a903e886355148868d7ed2bbd3857fb Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 14 Jul 2021 21:40:46 +0200 Subject: Bump to 0.1.47 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6f579f57b1c..604e54d3001 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.46" +version = "0.1.47" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From ba100707db3a07d2b9561d78d93a93acc4c1fd0f Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 28 Jul 2021 13:44:49 -0400 Subject: Don't try to build out-of-line aarch64 atomics with the msvc toolchain The msvc toolchain does not support building `.s` files, clang only supports generating out-of-line atomics on Linux and gcc does not support aarch64 for Windows at all. Therefore, we don't need to compile `lse.s` on `aarch64-pc-windows-msvc`. --- library/compiler-builtins/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 730ea61dfc6..d4cfe0e1c2b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -491,8 +491,9 @@ mod c { // Include out-of-line atomics for aarch64, which are all generated by supplying different // sets of flags to the same source file. + // Note: Out-of-line aarch64 atomics are not supported by the msvc toolchain (#430). let src_dir = root.join("lib/builtins"); - if target_arch == "aarch64" { + if target_arch == "aarch64" && target_env != "msvc" { // See below for why we're building these as separate libraries. build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); -- cgit 1.4.1-3-g733a5 From 2e7151205ef4a6487b6745ee63ab06ce442ec13b Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 28 Jul 2021 22:30:59 +0200 Subject: Bump to 0.1.48 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 604e54d3001..b1dcd11c4f9 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.47" +version = "0.1.48" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 502370f277ccf9abf48914a0d901615c861d3f01 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 30 Jul 2021 00:23:15 +0200 Subject: Don't panic if the shift intrinsics receive out-of-range shifts LLVM sometimes emits calls with out-of-range shifts but then discards the results. We should avoid panics in these cases. --- library/compiler-builtins/src/int/shift.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 59909929e58..908e619e1dd 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -6,13 +6,13 @@ trait Ashl: DInt { let n_h = Self::H::BITS; if shl & n_h != 0 { // we only need `self.lo()` because `self.hi()` will be shifted out entirely - (self.lo() << (shl - n_h)).widen_hi() + self.lo().wrapping_shl(shl - n_h).widen_hi() } else if shl == 0 { self } else { Self::from_lo_hi( - self.lo() << shl, - self.lo().logical_shr(n_h - shl) | (self.hi() << shl), + self.lo().wrapping_shl(shl), + self.lo().logical_shr(n_h - shl) | self.hi().wrapping_shl(shl), ) } } @@ -28,16 +28,16 @@ trait Ashr: DInt { let n_h = Self::H::BITS; if shr & n_h != 0 { Self::from_lo_hi( - self.hi() >> (shr - n_h), + self.hi().wrapping_shr(shr - n_h), // smear the sign bit - self.hi() >> (n_h - 1), + self.hi().wrapping_shr(n_h - 1), ) } else if shr == 0 { self } else { Self::from_lo_hi( - self.lo().logical_shr(shr) | (self.hi() << (n_h - shr)), - self.hi() >> shr, + self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h - shr), + self.hi().wrapping_shr(shr), ) } } @@ -57,7 +57,7 @@ trait Lshr: DInt { self } else { Self::from_lo_hi( - self.lo().logical_shr(shr) | (self.hi() << (n_h - shr)), + self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h - shr), self.hi().logical_shr(shr), ) } -- cgit 1.4.1-3-g733a5 From 4ffaedd2e3a017648d1d7c84916e937bcffab5d7 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 30 Jul 2021 18:49:46 +0200 Subject: Bump to 0.1.49 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index b1dcd11c4f9..7979032d794 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.48" +version = "0.1.49" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From d282412f70c510185bcd34e29c99d177ea7078d3 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 9 Feb 2021 05:07:58 +0000 Subject: Add test cases for memcpy, memmove and memset for different alignment --- library/compiler-builtins/testcrate/tests/mem.rs | 129 +++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs index a5596b2811d..3f20e72a04c 100644 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -1,6 +1,8 @@ extern crate compiler_builtins; use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; +const WORD_SIZE: usize = core::mem::size_of::(); + #[test] fn memcpy_3() { let mut arr: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; @@ -131,3 +133,130 @@ fn memcmp_ne() { assert!(memcmp(arr2.as_ptr(), arr1.as_ptr(), 8) > 0); } } + +#[derive(Clone, Copy)] +struct AlignedStorage([u8; N], [usize; 0]); + +fn gen_arr() -> AlignedStorage { + let mut ret = AlignedStorage::([0; N], []); + for i in 0..N { + ret.0[i] = i as u8; + } + ret +} + +#[test] +fn memmove_forward_misaligned_nonaligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().offset(6); + let dst = arr.0.as_mut_ptr().offset(3); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(6..6 + 17, 3); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_forward_misaligned_aligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().offset(6); + let dst = arr.0.as_mut_ptr().add(0); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(6..6 + 17, 0); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_forward_aligned() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().add(3 + WORD_SIZE); + let dst = arr.0.as_mut_ptr().add(3); + assert_eq!(memmove(dst, src, 17), dst); + reference + .0 + .copy_within(3 + WORD_SIZE..3 + WORD_SIZE + 17, 3); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_backward_misaligned_nonaligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().offset(3); + let dst = arr.0.as_mut_ptr().offset(6); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(3..3 + 17, 6); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_backward_misaligned_aligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().offset(3); + let dst = arr.0.as_mut_ptr().add(WORD_SIZE); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(3..3 + 17, WORD_SIZE); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_backward_aligned() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().add(3); + let dst = arr.0.as_mut_ptr().add(3 + WORD_SIZE); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(3..3 + 17, 3 + WORD_SIZE); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memset_backward_misaligned_nonaligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let ptr = arr.0.as_mut_ptr().offset(6); + assert_eq!(memset(ptr, 0xCC, 17), ptr); + core::ptr::write_bytes(reference.0.as_mut_ptr().add(6), 0xCC, 17); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memset_backward_misaligned_aligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let ptr = arr.0.as_mut_ptr().add(WORD_SIZE); + assert_eq!(memset(ptr, 0xCC, 17), ptr); + core::ptr::write_bytes(reference.0.as_mut_ptr().add(WORD_SIZE), 0xCC, 17); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memset_backward_aligned() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let ptr = arr.0.as_mut_ptr().add(3 + WORD_SIZE); + assert_eq!(memset(ptr, 0xCC, 17), ptr); + core::ptr::write_bytes(reference.0.as_mut_ptr().add(3 + WORD_SIZE), 0xCC, 17); + assert_eq!(arr.0, reference.0); + } +} -- cgit 1.4.1-3-g733a5 From 45715eb7f73a1aaee6e4619521f3e836293e535a Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 9 Feb 2021 05:10:39 +0000 Subject: Implement word-sized copy --- library/compiler-builtins/src/mem/impls.rs | 224 ++++++++++++++++++++++++++--- 1 file changed, 208 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index b3eef9901dd..e60b160fdfd 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -1,27 +1,219 @@ +use core::intrinsics::likely; + +const WORD_SIZE: usize = core::mem::size_of::(); +const WORD_MASK: usize = WORD_SIZE - 1; + +// If the number of bytes involved exceed this threshold we will opt in word-wise copy. +// The value here selected is max(2 * WORD_SIZE, 16): +// * We need at least 2 * WORD_SIZE bytes to guarantee that at least 1 word will be copied through +// word-wise copy. +// * The word-wise copy logic needs to perform some checks so it has some small overhead. +// ensures that even on 32-bit platforms we have copied at least 8 bytes through +// word-wise copy so the saving of word-wise copy outweights the fixed overhead. +const WORD_COPY_THRESHOLD: usize = if 2 * WORD_SIZE > 16 { + 2 * WORD_SIZE +} else { + 16 +}; + #[inline(always)] -pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, n: usize) { - let mut i = 0; - while i < n { - *dest.add(i) = *src.add(i); - i += 1; +pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) { + #[inline(always)] + unsafe fn copy_forward_bytes(mut dest: *mut u8, mut src: *const u8, n: usize) { + let dest_end = dest.add(n); + while dest < dest_end { + *dest = *src; + dest = dest.add(1); + src = src.add(1); + } + } + + #[inline(always)] + unsafe fn copy_forward_aligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let mut src_usize = src as *mut usize; + let dest_end = dest.add(n) as *mut usize; + + while dest_usize < dest_end { + *dest_usize = *src_usize; + dest_usize = dest_usize.add(1); + src_usize = src_usize.add(1); + } + } + + #[inline(always)] + unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let dest_end = dest.add(n) as *mut usize; + + // Calculate the misalignment offset and shift needed to reassemble value. + let offset = src as usize & WORD_MASK; + let shift = offset * 8; + + // Realign src + let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; + // XXX: Could this possibly be UB? + let mut prev_word = *src_aligned; + + while dest_usize < dest_end { + src_aligned = src_aligned.add(1); + let cur_word = *src_aligned; + #[cfg(target_endian = "little")] + let resembled = prev_word >> shift | cur_word << (WORD_SIZE * 8 - shift); + #[cfg(target_endian = "big")] + let resembled = prev_word << shift | cur_word >> (WORD_SIZE * 8 - shift); + prev_word = cur_word; + + *dest_usize = resembled; + dest_usize = dest_usize.add(1); + } } + + if n >= WORD_COPY_THRESHOLD { + // Align dest + // Because of n >= 2 * WORD_SIZE, dst_misalignment < n + let dest_misalignment = (dest as usize).wrapping_neg() & WORD_MASK; + copy_forward_bytes(dest, src, dest_misalignment); + dest = dest.add(dest_misalignment); + src = src.add(dest_misalignment); + n -= dest_misalignment; + + let n_words = n & !WORD_MASK; + let src_misalignment = src as usize & WORD_MASK; + if likely(src_misalignment == 0) { + copy_forward_aligned_words(dest, src, n_words); + } else { + copy_forward_misaligned_words(dest, src, n_words); + } + dest = dest.add(n_words); + src = src.add(n_words); + n -= n_words; + } + copy_forward_bytes(dest, src, n); } #[inline(always)] -pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, n: usize) { - // copy from end - let mut i = n; - while i != 0 { - i -= 1; - *dest.add(i) = *src.add(i); +pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { + // The following backward copy helper functions uses the pointers past the end + // as their inputs instead of pointers to the start! + #[inline(always)] + unsafe fn copy_backward_bytes(mut dest: *mut u8, mut src: *const u8, n: usize) { + let dest_start = dest.sub(n); + while dest_start < dest { + dest = dest.sub(1); + src = src.sub(1); + *dest = *src; + } + } + + #[inline(always)] + unsafe fn copy_backward_aligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let mut src_usize = src as *mut usize; + let dest_start = dest.sub(n) as *mut usize; + + while dest_start < dest_usize { + dest_usize = dest_usize.sub(1); + src_usize = src_usize.sub(1); + *dest_usize = *src_usize; + } } + + #[inline(always)] + unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let dest_start = dest.sub(n) as *mut usize; + + // Calculate the misalignment offset and shift needed to reassemble value. + let offset = src as usize & WORD_MASK; + let shift = offset * 8; + + // Realign src_aligned + let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; + // XXX: Could this possibly be UB? + let mut prev_word = *src_aligned; + + while dest_start < dest_usize { + src_aligned = src_aligned.sub(1); + let cur_word = *src_aligned; + #[cfg(target_endian = "little")] + let resembled = prev_word << (WORD_SIZE * 8 - shift) | cur_word >> shift; + #[cfg(target_endian = "big")] + let resembled = prev_word >> (WORD_SIZE * 8 - shift) | cur_word << shift; + prev_word = cur_word; + + dest_usize = dest_usize.sub(1); + *dest_usize = resembled; + } + } + + let mut dest = dest.add(n); + let mut src = src.add(n); + + if n >= WORD_COPY_THRESHOLD { + // Align dest + // Because of n >= 2 * WORD_SIZE, dst_misalignment < n + let dest_misalignment = dest as usize & WORD_MASK; + copy_backward_bytes(dest, src, dest_misalignment); + dest = dest.sub(dest_misalignment); + src = src.sub(dest_misalignment); + n -= dest_misalignment; + + let n_words = n & !WORD_MASK; + let src_misalignment = src as usize & WORD_MASK; + if likely(src_misalignment == 0) { + copy_backward_aligned_words(dest, src, n_words); + } else { + copy_backward_misaligned_words(dest, src, n_words); + } + dest = dest.sub(n_words); + src = src.sub(n_words); + n -= n_words; + } + copy_backward_bytes(dest, src, n); } #[inline(always)] -pub unsafe fn set_bytes(s: *mut u8, c: u8, n: usize) { - let mut i = 0; - while i < n { - *s.add(i) = c; - i += 1; +pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { + #[inline(always)] + pub unsafe fn set_bytes_bytes(mut s: *mut u8, c: u8, n: usize) { + let end = s.add(n); + while s < end { + *s = c; + s = s.add(1); + } + } + + #[inline(always)] + pub unsafe fn set_bytes_words(s: *mut u8, c: u8, n: usize) { + let mut broadcast = c as usize; + let mut bits = 8; + while bits < WORD_SIZE * 8 { + broadcast |= broadcast << bits; + bits *= 2; + } + + let mut s_usize = s as *mut usize; + let end = s.add(n) as *mut usize; + + while s_usize < end { + *s_usize = broadcast; + s_usize = s_usize.add(1); + } + } + + if likely(n >= WORD_COPY_THRESHOLD) { + // Align s + // Because of n >= 2 * WORD_SIZE, dst_misalignment < n + let misalignment = (s as usize).wrapping_neg() & WORD_MASK; + set_bytes_bytes(s, c, misalignment); + s = s.add(misalignment); + n -= misalignment; + + let n_words = n & !WORD_MASK; + set_bytes_words(s, c, n_words); + s = s.add(n_words); + n -= n_words; } + set_bytes_bytes(s, c, n); } -- cgit 1.4.1-3-g733a5 From 8535675a1706733a51288b3f0752554a3b065028 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 10 Feb 2021 23:35:54 +0000 Subject: Add misaligned benchmarks --- library/compiler-builtins/testcrate/benches/mem.rs | 134 +++++++++++++++------ 1 file changed, 100 insertions(+), 34 deletions(-) diff --git a/library/compiler-builtins/testcrate/benches/mem.rs b/library/compiler-builtins/testcrate/benches/mem.rs index cee64ae4d51..b6883a93b24 100644 --- a/library/compiler-builtins/testcrate/benches/mem.rs +++ b/library/compiler-builtins/testcrate/benches/mem.rs @@ -6,30 +6,64 @@ use test::{black_box, Bencher}; extern crate compiler_builtins; use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; -fn memcpy_builtin(b: &mut Bencher, n: usize, offset: usize) { - let v1 = vec![1u8; n + offset]; - let mut v2 = vec![0u8; n + offset]; +const WORD_SIZE: usize = core::mem::size_of::(); + +struct AlignedVec { + vec: Vec, + size: usize, +} + +impl AlignedVec { + fn new(fill: u8, size: usize) -> Self { + let mut broadcast = fill as usize; + let mut bits = 8; + while bits < WORD_SIZE * 8 { + broadcast |= broadcast << bits; + bits *= 2; + } + + let vec = vec![broadcast; (size + WORD_SIZE - 1) & !WORD_SIZE]; + AlignedVec { vec, size } + } +} + +impl core::ops::Deref for AlignedVec { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { core::slice::from_raw_parts(self.vec.as_ptr() as *const u8, self.size) } + } +} + +impl core::ops::DerefMut for AlignedVec { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { core::slice::from_raw_parts_mut(self.vec.as_mut_ptr() as *mut u8, self.size) } + } +} + +fn memcpy_builtin(b: &mut Bencher, n: usize, offset1: usize, offset2: usize) { + let v1 = AlignedVec::new(1, n + offset1); + let mut v2 = AlignedVec::new(0, n + offset2); b.bytes = n as u64; b.iter(|| { - let src: &[u8] = black_box(&v1[offset..]); - let dst: &mut [u8] = black_box(&mut v2[offset..]); + let src: &[u8] = black_box(&v1[offset1..]); + let dst: &mut [u8] = black_box(&mut v2[offset2..]); dst.copy_from_slice(src); }) } -fn memcpy_rust(b: &mut Bencher, n: usize, offset: usize) { - let v1 = vec![1u8; n + offset]; - let mut v2 = vec![0u8; n + offset]; +fn memcpy_rust(b: &mut Bencher, n: usize, offset1: usize, offset2: usize) { + let v1 = AlignedVec::new(1, n + offset1); + let mut v2 = AlignedVec::new(0, n + offset2); b.bytes = n as u64; b.iter(|| { - let src: &[u8] = black_box(&v1[offset..]); - let dst: &mut [u8] = black_box(&mut v2[offset..]); + let src: &[u8] = black_box(&v1[offset1..]); + let dst: &mut [u8] = black_box(&mut v2[offset2..]); unsafe { memcpy(dst.as_mut_ptr(), src.as_ptr(), n) } }) } fn memset_builtin(b: &mut Bencher, n: usize, offset: usize) { - let mut v1 = vec![0u8; n + offset]; + let mut v1 = AlignedVec::new(0, n + offset); b.bytes = n as u64; b.iter(|| { let dst: &mut [u8] = black_box(&mut v1[offset..]); @@ -41,7 +75,7 @@ fn memset_builtin(b: &mut Bencher, n: usize, offset: usize) { } fn memset_rust(b: &mut Bencher, n: usize, offset: usize) { - let mut v1 = vec![0u8; n + offset]; + let mut v1 = AlignedVec::new(0, n + offset); b.bytes = n as u64; b.iter(|| { let dst: &mut [u8] = black_box(&mut v1[offset..]); @@ -51,8 +85,8 @@ fn memset_rust(b: &mut Bencher, n: usize, offset: usize) { } fn memcmp_builtin(b: &mut Bencher, n: usize) { - let v1 = vec![0u8; n]; - let mut v2 = vec![0u8; n]; + let v1 = AlignedVec::new(0, n); + let mut v2 = AlignedVec::new(0, n); v2[n - 1] = 1; b.bytes = n as u64; b.iter(|| { @@ -63,8 +97,8 @@ fn memcmp_builtin(b: &mut Bencher, n: usize) { } fn memcmp_rust(b: &mut Bencher, n: usize) { - let v1 = vec![0u8; n]; - let mut v2 = vec![0u8; n]; + let v1 = AlignedVec::new(0, n); + let mut v2 = AlignedVec::new(0, n); v2[n - 1] = 1; b.bytes = n as u64; b.iter(|| { @@ -74,20 +108,20 @@ fn memcmp_rust(b: &mut Bencher, n: usize) { }) } -fn memmove_builtin(b: &mut Bencher, n: usize) { - let mut v = vec![0u8; n + n / 2]; +fn memmove_builtin(b: &mut Bencher, n: usize, offset: usize) { + let mut v = AlignedVec::new(0, n + n / 2 + offset); b.bytes = n as u64; b.iter(|| { let s: &mut [u8] = black_box(&mut v); - s.copy_within(0..n, n / 2); + s.copy_within(0..n, n / 2 + offset); }) } -fn memmove_rust(b: &mut Bencher, n: usize) { - let mut v = vec![0u8; n + n / 2]; +fn memmove_rust(b: &mut Bencher, n: usize, offset: usize) { + let mut v = AlignedVec::new(0, n + n / 2 + offset); b.bytes = n as u64; b.iter(|| { - let dst: *mut u8 = black_box(&mut v[n / 2..]).as_mut_ptr(); + let dst: *mut u8 = black_box(&mut v[n / 2 + offset..]).as_mut_ptr(); let src: *const u8 = black_box(&v).as_ptr(); unsafe { memmove(dst, src, n) }; }) @@ -95,35 +129,51 @@ fn memmove_rust(b: &mut Bencher, n: usize) { #[bench] fn memcpy_builtin_4096(b: &mut Bencher) { - memcpy_builtin(b, 4096, 0) + memcpy_builtin(b, 4096, 0, 0) } #[bench] fn memcpy_rust_4096(b: &mut Bencher) { - memcpy_rust(b, 4096, 0) + memcpy_rust(b, 4096, 0, 0) } #[bench] fn memcpy_builtin_1048576(b: &mut Bencher) { - memcpy_builtin(b, 1048576, 0) + memcpy_builtin(b, 1048576, 0, 0) } #[bench] fn memcpy_rust_1048576(b: &mut Bencher) { - memcpy_rust(b, 1048576, 0) + memcpy_rust(b, 1048576, 0, 0) } #[bench] fn memcpy_builtin_4096_offset(b: &mut Bencher) { - memcpy_builtin(b, 4096, 65) + memcpy_builtin(b, 4096, 65, 65) } #[bench] fn memcpy_rust_4096_offset(b: &mut Bencher) { - memcpy_rust(b, 4096, 65) + memcpy_rust(b, 4096, 65, 65) } #[bench] fn memcpy_builtin_1048576_offset(b: &mut Bencher) { - memcpy_builtin(b, 1048576, 65) + memcpy_builtin(b, 1048576, 65, 65) } #[bench] fn memcpy_rust_1048576_offset(b: &mut Bencher) { - memcpy_rust(b, 1048576, 65) + memcpy_rust(b, 1048576, 65, 65) +} +#[bench] +fn memcpy_builtin_4096_misalign(b: &mut Bencher) { + memcpy_builtin(b, 4096, 65, 66) +} +#[bench] +fn memcpy_rust_4096_misalign(b: &mut Bencher) { + memcpy_rust(b, 4096, 65, 66) +} +#[bench] +fn memcpy_builtin_1048576_misalign(b: &mut Bencher) { + memcpy_builtin(b, 1048576, 65, 66) +} +#[bench] +fn memcpy_rust_1048576_misalign(b: &mut Bencher) { + memcpy_rust(b, 1048576, 65, 66) } #[bench] @@ -178,17 +228,33 @@ fn memcmp_rust_1048576(b: &mut Bencher) { #[bench] fn memmove_builtin_4096(b: &mut Bencher) { - memmove_builtin(b, 4096) + memmove_builtin(b, 4096, 0) } #[bench] fn memmove_rust_4096(b: &mut Bencher) { - memmove_rust(b, 4096) + memmove_rust(b, 4096, 0) } #[bench] fn memmove_builtin_1048576(b: &mut Bencher) { - memmove_builtin(b, 1048576) + memmove_builtin(b, 1048576, 0) } #[bench] fn memmove_rust_1048576(b: &mut Bencher) { - memmove_rust(b, 1048576) + memmove_rust(b, 1048576, 0) +} +#[bench] +fn memmove_builtin_4096_misalign(b: &mut Bencher) { + memmove_builtin(b, 4096, 1) +} +#[bench] +fn memmove_rust_4096_misalign(b: &mut Bencher) { + memmove_rust(b, 4096, 1) +} +#[bench] +fn memmove_builtin_1048576_misalign(b: &mut Bencher) { + memmove_builtin(b, 1048576, 1) +} +#[bench] +fn memmove_rust_1048576_misalign(b: &mut Bencher) { + memmove_rust(b, 1048576, 1) } -- cgit 1.4.1-3-g733a5 From 709bd6e11cc9b616fe9a36f3a4bc402eee73ddc9 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 21 Aug 2021 03:45:38 +0100 Subject: Add different misaligned path for archs with unaligned support --- library/compiler-builtins/build.rs | 5 ++++ library/compiler-builtins/src/mem/impls.rs | 38 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d4cfe0e1c2b..fb3dc373aa2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -33,6 +33,11 @@ fn main() { println!("cargo:rustc-cfg=feature=\"mem\""); } + // These targets have hardware unaligned access support. + if target.contains("x86_64") || target.contains("i686") || target.contains("aarch64") { + println!("cargo:rustc-cfg=feature=\"mem-unaligned\""); + } + // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the // target triple. This is usually correct for our built-in targets but can break in presence of // custom targets, which can have arbitrary names. diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index e60b160fdfd..7022d625711 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -16,6 +16,14 @@ const WORD_COPY_THRESHOLD: usize = if 2 * WORD_SIZE > 16 { 16 }; +#[cfg(feature = "mem-unaligned")] +unsafe fn read_usize_unaligned(x: *const usize) -> usize { + // Do not use `core::ptr::read_unaligned` here, since it calls `copy_nonoverlapping` which + // is translated to memcpy in LLVM. + let x_read = (x as *const [u8; core::mem::size_of::()]).read(); + core::mem::transmute(x_read) +} + #[inline(always)] pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) { #[inline(always)] @@ -41,6 +49,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) } } + #[cfg(not(feature = "mem-unaligned"))] #[inline(always)] unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; @@ -69,6 +78,20 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) } } + #[cfg(feature = "mem-unaligned")] + #[inline(always)] + unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let mut src_usize = src as *mut usize; + let dest_end = dest.add(n) as *mut usize; + + while dest_usize < dest_end { + *dest_usize = read_usize_unaligned(src_usize); + dest_usize = dest_usize.add(1); + src_usize = src_usize.add(1); + } + } + if n >= WORD_COPY_THRESHOLD { // Align dest // Because of n >= 2 * WORD_SIZE, dst_misalignment < n @@ -119,6 +142,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { } } + #[cfg(not(feature = "mem-unaligned"))] #[inline(always)] unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; @@ -147,6 +171,20 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { } } + #[cfg(feature = "mem-unaligned")] + #[inline(always)] + unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let mut src_usize = src as *mut usize; + let dest_start = dest.sub(n) as *mut usize; + + while dest_start < dest_usize { + dest_usize = dest_usize.sub(1); + src_usize = src_usize.sub(1); + *dest_usize = read_usize_unaligned(src_usize); + } + } + let mut dest = dest.add(n); let mut src = src.add(n); -- cgit 1.4.1-3-g733a5 From 1f0cbb29458fdd6d3a3656516d485a23a0aa18f3 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 31 Aug 2021 00:22:43 +0100 Subject: Use atomic_load_unordered for first word load in misaligned case --- library/compiler-builtins/src/mem/impls.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index 7022d625711..65887a33892 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -61,8 +61,8 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) // Realign src let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; - // XXX: Could this possibly be UB? - let mut prev_word = *src_aligned; + // This will read (but won't use) bytes out of bound. + let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); while dest_usize < dest_end { src_aligned = src_aligned.add(1); @@ -154,8 +154,8 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { // Realign src_aligned let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; - // XXX: Could this possibly be UB? - let mut prev_word = *src_aligned; + // This will read (but won't use) bytes out of bound. + let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); while dest_start < dest_usize { src_aligned = src_aligned.sub(1); -- cgit 1.4.1-3-g733a5 From abf75cc713538b590ee769e6957169e0a2f89288 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 1 Sep 2021 00:22:59 +0200 Subject: Bump to 0.1.50 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7979032d794..8c06d9621a1 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.49" +version = "0.1.50" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From a71b0e449395f68833b97a2a47bf58c0b157a54a Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 15 Oct 2021 01:56:08 +0200 Subject: Disable broken powerpc64 test due to https://github.com/rust-lang/rust/issues/88520 --- library/compiler-builtins/testcrate/tests/cmp.rs | 2 ++ library/compiler-builtins/testcrate/tests/conv.rs | 2 ++ library/compiler-builtins/testcrate/tests/misc.rs | 2 ++ 3 files changed, 6 insertions(+) diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index a49779ad0e4..5c10a560113 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -22,6 +22,8 @@ macro_rules! cmp { }; } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[test] fn float_comparisons() { use compiler_builtins::float::cmp::{ diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 7cdbf9fbb69..8c4b1946ce4 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -95,6 +95,8 @@ macro_rules! f_to_i { }; } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[test] fn float_to_int() { use compiler_builtins::float::conv::{ diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index 82a1ea27b47..5f74e006380 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -111,6 +111,8 @@ macro_rules! extend { }; } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[test] fn float_extend() { use compiler_builtins::float::extend::__extendsfdf2; -- cgit 1.4.1-3-g733a5 From 29dd109959b067323e5d21a3534ab93edb5201ae Mon Sep 17 00:00:00 2001 From: Georgy Shepelev Date: Wed, 29 Sep 2021 16:02:46 +0400 Subject: expose some math to UEFI envs --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/math.rs | 46 ++++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 21796ca5541..2bf6e00a8d5 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -40,6 +40,7 @@ pub mod int; #[cfg(any( all(target_arch = "wasm32", target_os = "unknown"), + all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") ))] diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 94f91124bf0..6bc1e907638 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -20,24 +20,17 @@ macro_rules! no_mangle { target_os = "unknown", not(target_env = "wasi") ), + all(target_arch = "x86_64", target_os = "uefi"), all(target_vendor = "fortanix", target_env = "sgx") ))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; - fn atan(x: f64) -> f64; - fn atan2(x: f64, y: f64) -> f64; fn cbrt(x: f64) -> f64; - fn cosh(x: f64) -> f64; fn expm1(x: f64) -> f64; fn hypot(x: f64, y: f64) -> f64; - fn log1p(x: f64) -> f64; - fn sinh(x: f64) -> f64; fn tan(x: f64) -> f64; - fn tanh(x: f64) -> f64; fn cos(x: f64) -> f64; - fn cosf(x: f32) -> f32; - fn exp(x: f64) -> f64; fn expf(x: f32) -> f32; fn log2(x: f64) -> f64; fn log2f(x: f32) -> f32; @@ -52,33 +45,52 @@ no_mangle! { fn round(x: f64) -> f64; fn roundf(x: f32) -> f32; fn sin(x: f64) -> f64; - fn sinf(x: f32) -> f32; fn pow(x: f64, y: f64) -> f64; fn powf(x: f32, y: f32) -> f32; - fn exp2(x: f64) -> f64; - fn exp2f(x: f32) -> f32; fn fmod(x: f64, y: f64) -> f64; fn fmodf(x: f32, y: f32) -> f32; - fn fma(x: f64, y: f64, z: f64) -> f64; - fn fmaf(x: f32, y: f32, z: f32) -> f32; fn acosf(n: f32) -> f32; - fn asinf(n: f32) -> f32; fn atan2f(a: f32, b: f32) -> f32; fn atanf(n: f32) -> f32; - fn cbrtf(n: f32) -> f32; fn coshf(n: f32) -> f32; fn expm1f(n: f32) -> f32; fn fdim(a: f64, b: f64) -> f64; fn fdimf(a: f32, b: f32) -> f32; - fn hypotf(x: f32, y: f32) -> f32; fn log1pf(n: f32) -> f32; fn sinhf(n: f32) -> f32; - fn tanf(n: f32) -> f32; fn tanhf(n: f32) -> f32; fn ldexp(f: f64, n: i32) -> f64; fn ldexpf(f: f32, n: i32) -> f32; } +#[cfg(any( + all( + target_arch = "wasm32", + target_os = "unknown", + not(target_env = "wasi") + ), + all(target_vendor = "fortanix", target_env = "sgx") +))] +no_mangle! { + fn atan(x: f64) -> f64; + fn atan2(x: f64, y: f64) -> f64; + fn cosh(x: f64) -> f64; + fn log1p(x: f64) -> f64; + fn sinh(x: f64) -> f64; + fn tanh(x: f64) -> f64; + fn cosf(x: f32) -> f32; + fn exp(x: f64) -> f64; + fn sinf(x: f32) -> f32; + fn exp2(x: f64) -> f64; + fn exp2f(x: f32) -> f32; + fn fma(x: f64, y: f64, z: f64) -> f64; + fn fmaf(x: f32, y: f32, z: f32) -> f32; + fn asinf(n: f32) -> f32; + fn cbrtf(n: f32) -> f32; + fn hypotf(x: f32, y: f32) -> f32; + fn tanf(n: f32) -> f32; +} + #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] no_mangle! { fn ceil(x: f64) -> f64; -- cgit 1.4.1-3-g733a5 From 3b4d10f6bcaefa98002c287a4ec7bde71342b6a1 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Fri, 8 Oct 2021 13:36:30 +0100 Subject: Add xtensa to list of soft math targets. --- library/compiler-builtins/src/math.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 6bc1e907638..6f024e7b38d 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -21,6 +21,7 @@ macro_rules! no_mangle { not(target_env = "wasi") ), all(target_arch = "x86_64", target_os = "uefi"), + all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") ))] no_mangle! { @@ -69,6 +70,7 @@ no_mangle! { target_os = "unknown", not(target_env = "wasi") ), + all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") ))] no_mangle! { -- cgit 1.4.1-3-g733a5 From 2d12d7150aa396e8d79cc493c4edf0ab55cfe371 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 17 Oct 2021 01:41:40 +0200 Subject: Bump to 0.1.51 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 8c06d9621a1..7874b99fdac 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.50" +version = "0.1.51" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From b7fb6c594a8267d5810b5319f2f3bf24b2ecb1de Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 28 Oct 2021 10:29:37 -0700 Subject: Adjust some build directives for wasm64 This is still an experimental target but this should get the wasm64 target to behave more like wasm32. --- library/compiler-builtins/build.rs | 8 ++++---- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/math.rs | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index fb3dc373aa2..60feb061932 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -23,9 +23,9 @@ fn main() { return; } - // Forcibly enable memory intrinsics on wasm32 & SGX as we don't have a libc to + // Forcibly enable memory intrinsics on wasm & SGX as we don't have a libc to // provide them. - if (target.contains("wasm32") && !target.contains("wasi")) + if (target.contains("wasm") && !target.contains("wasi")) || (target.contains("sgx") && target.contains("fortanix")) || target.contains("-none") || target.contains("nvptx") @@ -50,13 +50,13 @@ fn main() { if !cfg!(feature = "mangled-names") && cfg!(feature = "c") { // Don't use a C compiler for these targets: // - // * wasm32 - clang 8 for wasm is somewhat hard to come by and it's + // * wasm - clang for wasm is somewhat hard to come by and it's // unlikely that the C is really that much better than our own Rust. // * nvptx - everything is bitcode, not compatible with mixed C/Rust // * riscv - the rust-lang/rust distribution container doesn't have a C // compiler nor is cc-rs ready for compilation to riscv (at this // time). This can probably be removed in the future - if !target.contains("wasm32") && !target.contains("nvptx") && !target.starts_with("riscv") { + if !target.contains("wasm") && !target.contains("nvptx") && !target.starts_with("riscv") { #[cfg(feature = "c")] c::compile(&llvm_target, &target); } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 2bf6e00a8d5..b021a686414 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -40,6 +40,7 @@ pub mod int; #[cfg(any( all(target_arch = "wasm32", target_os = "unknown"), + all(target_arch = "wasm64", target_os = "unknown"), all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 6f024e7b38d..c6d47b80351 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -16,7 +16,7 @@ macro_rules! no_mangle { #[cfg(any( all( - target_arch = "wasm32", + any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown", not(target_env = "wasi") ), @@ -66,7 +66,7 @@ no_mangle! { #[cfg(any( all( - target_arch = "wasm32", + any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown", not(target_env = "wasi") ), -- cgit 1.4.1-3-g733a5 From 9a01750b1b85e5d9babd36930fab399101c3971c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 28 Oct 2021 16:32:30 -0700 Subject: Use more concise directives --- library/compiler-builtins/src/lib.rs | 3 +-- library/compiler-builtins/src/math.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index b021a686414..fcafb8978f1 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -39,8 +39,7 @@ pub mod float; pub mod int; #[cfg(any( - all(target_arch = "wasm32", target_os = "unknown"), - all(target_arch = "wasm64", target_os = "unknown"), + all(target_family = "wasm", target_os = "unknown"), all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index c6d47b80351..fa59753f8f6 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -16,7 +16,7 @@ macro_rules! no_mangle { #[cfg(any( all( - any(target_arch = "wasm32", target_arch = "wasm64"), + target_family = "wasm", target_os = "unknown", not(target_env = "wasi") ), @@ -66,7 +66,7 @@ no_mangle! { #[cfg(any( all( - any(target_arch = "wasm32", target_arch = "wasm64"), + target_family = "wasm", target_os = "unknown", not(target_env = "wasi") ), -- cgit 1.4.1-3-g733a5 From 8e7401a1515a9e72be19cd23849526fb4cf58892 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 1 Nov 2021 23:02:56 +0000 Subject: Bump to 0.1.52 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7874b99fdac..2caf6fed47d 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.51" +version = "0.1.52" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From d96a0a0877376a402332b4ba79467bc5b810e9ca Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Sun, 21 Nov 2021 06:54:00 +0000 Subject: Turn on the mem-unaligned feature for bpf targets Fixes the following LLVM segfault: Error: e: 05:02:06 [ERROR] fatal error: "Cannot select: 0x55e970a357d0: i64,ch = AtomicLoad<(load unordered (s64) from %ir.45)> 0x55e970410be8, 0x55e970a358a0\n 0x55e970a358a0: i64,ch = CopyFromReg 0x55e970410be8, Register:i64 %19\n 0x55e970a35490: i64 = Register %19\nIn function: memcpy" PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace. Stack dump: 0. Running pass 'Function Pass Manager' on module 'unroll-loop'. 1. Running pass 'BPF DAG->DAG Pattern Instruction Selection' on function '@memcpy' --- library/compiler-builtins/build.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 60feb061932..b930f1d8d61 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -34,7 +34,11 @@ fn main() { } // These targets have hardware unaligned access support. - if target.contains("x86_64") || target.contains("i686") || target.contains("aarch64") { + if target.contains("x86_64") + || target.contains("i686") + || target.contains("aarch64") + || target.contains("bpf") + { println!("cargo:rustc-cfg=feature=\"mem-unaligned\""); } -- cgit 1.4.1-3-g733a5 From 54e028e964a4dabdffcdcf02c25718129b9a6584 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 25 Nov 2021 00:01:25 +0000 Subject: Bump to 0.1.53 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 2caf6fed47d..d4348fb4f59 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.52" +version = "0.1.53" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From e6d7983889c621e0afb551f6c754da4897ac1b92 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Wed, 24 Nov 2021 21:51:50 -0500 Subject: Do not use atomic reads on platforms without atomic support in LLVM. --- library/compiler-builtins/src/mem/impls.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index 65887a33892..8151324254a 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -62,7 +62,12 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) // Realign src let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; // This will read (but won't use) bytes out of bound. + // cfg needed because not all targets will have atomic loads that can be lowered + // (e.g. BPF, MSP430), or provided by an external library (e.g. RV32I) + #[cfg(target_has_atomic_load_store = "ptr")] let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); + #[cfg(not(target_has_atomic_load_store = "ptr"))] + let mut prev_word = core::ptr::read_volatile(src_aligned); while dest_usize < dest_end { src_aligned = src_aligned.add(1); @@ -155,7 +160,12 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { // Realign src_aligned let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; // This will read (but won't use) bytes out of bound. + // cfg needed because not all targets will have atomic loads that can be lowered + // (e.g. BPF, MSP430), or provided by an external library (e.g. RV32I) + #[cfg(target_has_atomic_load_store = "ptr")] let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); + #[cfg(not(target_has_atomic_load_store = "ptr"))] + let mut prev_word = core::ptr::read_volatile(src_aligned); while dest_start < dest_usize { src_aligned = src_aligned.sub(1); -- cgit 1.4.1-3-g733a5 From f275e26e3d1c48abf65401c7727b6de8584952b8 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 27 Nov 2021 19:38:43 -0500 Subject: Use fully-qualified syntax for abs_diff to avoid warning, which can trigger a compiler error. --- library/compiler-builtins/src/float/pow.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 5ab5e4201c2..a75340c3093 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -5,7 +5,7 @@ use int::Int; fn pow(a: F, b: i32) -> F { let mut a = a; let recip = b < 0; - let mut pow = i32::abs_diff(b, 0); + let mut pow = Int::abs_diff(b, 0); let mut mul = F::ONE; loop { if (pow & 1) != 0 { -- cgit 1.4.1-3-g733a5 From a01a61bd36e31ae082ca1cbb83bea811ee840699 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 28 Nov 2021 11:19:54 +0000 Subject: Bump to 0.1.54 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d4348fb4f59..8beb767d444 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.53" +version = "0.1.54" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From c7502772685dd31ed1c877cc7a1c2007fc4d82ee Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 28 Nov 2021 12:50:21 +0000 Subject: Ensure AArch64 LSE object files have distinct names in an archive This is needed by libtool which rejects archives that contain object files with the same name multiple times. Fixes #443 --- library/compiler-builtins/build.rs | 51 +++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index b930f1d8d61..90b8a04face 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -95,6 +95,8 @@ mod c { use std::collections::{BTreeMap, HashSet}; use std::env; + use std::fs::File; + use std::io::Write; use std::path::{Path, PathBuf}; struct Sources { @@ -523,20 +525,13 @@ mod c { cfg.compile("libcompiler-rt.a"); } - fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &cc::Build) { - // NOTE: because we're recompiling the same source file in N different ways, building - // serially is necessary. If we want to lift this restriction, we can either: - // - create symlinks to lse.S and build those_(though we'd still need to pass special - // #define-like flags to each of these), or - // - synthesizing tiny .S files in out/ with the proper #defines, which ultimately #include - // lse.S. - // That said, it's unclear how useful this added complexity will be, so just do the simple - // thing for now. + fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &mut cc::Build) { + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let outlined_atomics_file = builtins_dir.join("aarch64/lse.S"); println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); - // Ideally, this would be a Vec of object files, but cc doesn't make it *entirely* - // trivial to build an individual object. + cfg.include(&builtins_dir); + for instruction_type in &["cas", "swp", "ldadd", "ldclr", "ldeor", "ldset"] { for size in &[1, 2, 4, 8, 16] { if *size == 16 && *instruction_type != "cas" { @@ -546,20 +541,30 @@ mod c { for (model_number, model_name) in &[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")] { - let library_name = format!( - "liboutline_atomic_helper_{}{}_{}.a", - instruction_type, size, model_name + // The original compiler-rt build system compiles the same + // source file multiple times with different compiler + // options. Here we do something slightly different: we + // create multiple .S files with the proper #defines and + // then include the original file. + // + // This is needed because the cc crate doesn't allow us to + // override the name of object files and libtool requires + // all objects in an archive to have unique names. + let path = + out_dir.join(format!("lse_{}{}_{}.S", instruction_type, size, model_name)); + let mut file = File::create(&path).unwrap(); + writeln!(file, "#define L_{}", instruction_type).unwrap(); + writeln!(file, "#define SIZE {}", size).unwrap(); + writeln!(file, "#define MODEL {}", model_number).unwrap(); + writeln!( + file, + "#include \"{}\"", + outlined_atomics_file.canonicalize().unwrap().display() ); - let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); - let mut cfg = cfg.clone(); - - cfg.include(&builtins_dir) - .define(&format!("L_{}", instruction_type), None) - .define("SIZE", size.to_string().as_str()) - .define("MODEL", model_number.to_string().as_str()) - .file(&outlined_atomics_file); - cfg.compile(&library_name); + drop(file); + cfg.file(path); + let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); } } -- cgit 1.4.1-3-g733a5 From c17d0c2780b2127b825dc9c361ef34cd5d790da5 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 28 Nov 2021 15:30:04 +0000 Subject: Bump to 0.1.55 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 8beb767d444..7a894b9584c 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.54" +version = "0.1.55" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 4abfecabef8901cf29a415dd275bef76194a1687 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 9 Dec 2021 23:51:18 +0000 Subject: Import the asm! macro from core::arch It is going to be removed from the prelude due to the decision in https://github.com/rust-lang/rust/issues/87228 --- library/compiler-builtins/build.rs | 3 +- library/compiler-builtins/src/arm.rs | 16 ++++----- library/compiler-builtins/src/int/leading_zeros.rs | 2 ++ .../src/int/specialized_div_rem/mod.rs | 4 +-- library/compiler-builtins/src/lib.rs | 2 ++ library/compiler-builtins/src/mem/x86_64.rs | 10 +++--- library/compiler-builtins/src/probestack.rs | 42 ++++++++++++---------- library/compiler-builtins/src/x86.rs | 6 ++-- library/compiler-builtins/src/x86_64.rs | 6 ++-- 9 files changed, 51 insertions(+), 40 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 90b8a04face..922cd07a0af 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -560,7 +560,8 @@ mod c { file, "#include \"{}\"", outlined_atomics_file.canonicalize().unwrap().display() - ); + ) + .unwrap(); drop(file); cfg.file(path); diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 7203d91e4a9..3660825aa73 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -11,7 +11,7 @@ use core::intrinsics; #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_uidivmod() { - asm!( + core::arch::asm!( "push {{lr}}", "sub sp, sp, #4", "mov r2, sp", @@ -27,7 +27,7 @@ pub unsafe extern "C" fn __aeabi_uidivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_uidivmod() { - asm!( + core::arch::asm!( "push {{lr}}", "sub sp, sp, #4", "mov r2, sp", @@ -43,7 +43,7 @@ pub unsafe extern "C" fn __aeabi_uidivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_uldivmod() { - asm!( + core::arch::asm!( "push {{r4, lr}}", "sub sp, sp, #16", "add r4, sp, #8", @@ -61,7 +61,7 @@ pub unsafe extern "C" fn __aeabi_uldivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_uldivmod() { - asm!( + core::arch::asm!( "push {{r4, lr}}", "sub sp, sp, #16", "add r4, sp, #8", @@ -79,7 +79,7 @@ pub unsafe extern "C" fn __aeabi_uldivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_idivmod() { - asm!( + core::arch::asm!( "push {{r0, r1, r4, lr}}", "bl __aeabi_idiv", "pop {{r1, r2}}", @@ -94,7 +94,7 @@ pub unsafe extern "C" fn __aeabi_idivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_idivmod() { - asm!( + core::arch::asm!( "push {{r0, r1, r4, lr}}", "bl ___aeabi_idiv", "pop {{r1, r2}}", @@ -109,7 +109,7 @@ pub unsafe extern "C" fn __aeabi_idivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_ldivmod() { - asm!( + core::arch::asm!( "push {{r4, lr}}", "sub sp, sp, #16", "add r4, sp, #8", @@ -127,7 +127,7 @@ pub unsafe extern "C" fn __aeabi_ldivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_ldivmod() { - asm!( + core::arch::asm!( "push {{r4, lr}}", "sub sp, sp, #16", "add r4, sp, #8", diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index 0265b9a9d02..9e60ab0d744 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -5,6 +5,7 @@ public_test_dep! { /// Returns the number of leading binary zeros in `x`. +#[allow(dead_code)] pub(crate) fn usize_leading_zeros_default(x: usize) -> usize { // The basic idea is to test if the higher bits of `x` are zero and bisect the number // of leading zeros. It is possible for all branches of the bisection to use the same @@ -78,6 +79,7 @@ pub(crate) fn usize_leading_zeros_default(x: usize) -> usize { public_test_dep! { /// Returns the number of leading binary zeros in `x`. +#[allow(dead_code)] pub(crate) fn usize_leading_zeros_riscv(x: usize) -> usize { let mut x = x; // the number of potential leading zeros diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index f5b2af235bd..6ec4675df94 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -184,7 +184,7 @@ unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { // divides the combined registers rdx:rax (`duo` is split into two 64 bit parts to do this) // by `div`. The quotient is stored in rax and the remainder in rdx. // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - asm!( + core::arch::asm!( "div {0}", in(reg) div, inlateout("rax") duo_lo => quo, @@ -271,7 +271,7 @@ unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { // divides the combined registers rdx:rax (`duo` is split into two 32 bit parts to do this) // by `div`. The quotient is stored in rax and the remainder in rdx. // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - asm!( + core::arch::asm!( "div {0}", in(reg) div, inlateout("rax") duo_lo => quo, diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index fcafb8978f1..c3eefbc0362 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -18,6 +18,8 @@ #![allow(improper_ctypes, improper_ctypes_definitions)] // `mem::swap` cannot be used because it may generate references to memcpy in unoptimized code. #![allow(clippy::manual_swap)] +// Support compiling on both stage0 and stage1 which may differ in supported stable features. +#![allow(stable_features)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index abdb8eb67e0..a7ab6f605bd 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -20,7 +20,7 @@ #[cfg(target_feature = "ermsb")] pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - asm!( + core::arch::asm!( "repe movsb (%rsi), (%rdi)", inout("rcx") count => _, inout("rdi") dest => _, @@ -35,7 +35,7 @@ pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - asm!( + core::arch::asm!( "repe movsq (%rsi), (%rdi)", "mov {byte_count:e}, %ecx", "repe movsb (%rsi), (%rdi)", @@ -52,7 +52,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - asm!( + core::arch::asm!( "std", "repe movsq (%rsi), (%rdi)", "movl {byte_count:e}, %ecx", @@ -72,7 +72,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { #[cfg(target_feature = "ermsb")] pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - asm!( + core::arch::asm!( "repe stosb %al, (%rdi)", inout("rcx") count => _, inout("rdi") dest => _, @@ -87,7 +87,7 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - asm!( + core::arch::asm!( "repe stosq %rax, (%rdi)", "mov {byte_count:e}, %ecx", "repe stosb %al, (%rdi)", diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 4d6cd694943..0c30384db38 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -48,8 +48,6 @@ #![cfg(not(feature = "no-asm"))] // We only define stack probing for these architectures today. #![cfg(any(target_arch = "x86_64", target_arch = "x86"))] -// We need to add .att_syntax for bootstraping the new global_asm! -#![allow(unknown_lints, bad_asm_style)] extern "C" { pub fn __rust_probestack(); @@ -65,7 +63,6 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " - .att_syntax .pushsection .text.__rust_probestack .globl __rust_probestack .type __rust_probestack, @function @@ -86,7 +83,6 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " - .att_syntax .globl __rust_probestack __rust_probestack: ", @@ -102,7 +98,6 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " - .att_syntax .globl ___rust_probestack ___rust_probestack: ", @@ -117,7 +112,6 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " - .att_syntax .globl ___rust_probestack ___rust_probestack: ", @@ -137,8 +131,9 @@ macro_rules! define_rust_probestack { target_arch = "x86_64", not(all(target_env = "sgx", target_vendor = "fortanix")) ))] -global_asm!(define_rust_probestack!( - " +core::arch::global_asm!( + define_rust_probestack!( + " .cfi_startproc pushq %rbp .cfi_adjust_cfa_offset 8 @@ -188,7 +183,9 @@ global_asm!(define_rust_probestack!( ret .cfi_endproc " -)); + ), + options(att_syntax) +); // This function is the same as above, except that some instructions are // [manually patched for LVI]. @@ -198,8 +195,9 @@ global_asm!(define_rust_probestack!( target_arch = "x86_64", all(target_env = "sgx", target_vendor = "fortanix") ))] -global_asm!(define_rust_probestack!( - " +core::arch::global_asm!( + define_rust_probestack!( + " .cfi_startproc pushq %rbp .cfi_adjust_cfa_offset 8 @@ -251,7 +249,9 @@ global_asm!(define_rust_probestack!( jmp *%r11 .cfi_endproc " -)); + ), + options(att_syntax) +); #[cfg(all(target_arch = "x86", not(target_os = "uefi")))] // This is the same as x86_64 above, only translated for 32-bit sizes. Note @@ -259,8 +259,9 @@ global_asm!(define_rust_probestack!( // function basically can't tamper with anything. // // The ABI here is the same as x86_64, except everything is 32-bits large. -global_asm!(define_rust_probestack!( - " +core::arch::global_asm!( + define_rust_probestack!( + " .cfi_startproc push %ebp .cfi_adjust_cfa_offset 4 @@ -291,7 +292,9 @@ global_asm!(define_rust_probestack!( ret .cfi_endproc " -)); + ), + options(att_syntax) +); #[cfg(all(target_arch = "x86", target_os = "uefi"))] // UEFI target is windows like target. LLVM will do _chkstk things like windows. @@ -304,8 +307,9 @@ global_asm!(define_rust_probestack!( // MSVC x32's _chkstk and cygwin/mingw's _alloca adjust %esp themselves. // MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp // themselves. -global_asm!(define_rust_probestack!( - " +core::arch::global_asm!( + define_rust_probestack!( + " .cfi_startproc push %ebp .cfi_adjust_cfa_offset 4 @@ -341,4 +345,6 @@ global_asm!(define_rust_probestack!( ret .cfi_endproc " -)); + ), + options(att_syntax) +); diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index 4992de9da04..abcc2bdb3d4 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -17,7 +17,7 @@ use core::intrinsics; #[naked] #[no_mangle] pub unsafe extern "C" fn ___chkstk_ms() { - asm!( + core::arch::asm!( "push %ecx", "push %eax", "cmp $0x1000,%eax", @@ -49,7 +49,7 @@ pub unsafe extern "C" fn ___chkstk_ms() { #[naked] #[no_mangle] pub unsafe extern "C" fn __alloca() { - asm!( + core::arch::asm!( "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" options(noreturn, att_syntax) ); @@ -64,7 +64,7 @@ pub unsafe extern "C" fn __alloca() { #[naked] #[no_mangle] pub unsafe extern "C" fn ___chkstk() { - asm!( + core::arch::asm!( "push %ecx", "cmp $0x1000,%eax", "lea 8(%esp),%ecx", // esp before calling this routine -> ecx diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index b382b886c55..ea3c9949790 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -17,7 +17,7 @@ use core::intrinsics; #[naked] #[no_mangle] pub unsafe extern "C" fn ___chkstk_ms() { - asm!( + core::arch::asm!( "push %rcx", "push %rax", "cmp $0x1000,%rax", @@ -48,7 +48,7 @@ pub unsafe extern "C" fn ___chkstk_ms() { #[naked] #[no_mangle] pub unsafe extern "C" fn __alloca() { - asm!( + core::arch::asm!( "mov %rcx,%rax", // x64 _alloca is a normal function with parameter in rcx "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" options(noreturn, att_syntax) @@ -64,7 +64,7 @@ pub unsafe extern "C" fn __alloca() { #[naked] #[no_mangle] pub unsafe extern "C" fn ___chkstk() { - asm!( + core::arch::asm!( "push %rcx", "cmp $0x1000,%rax", "lea 16(%rsp),%rcx", // rsp before calling this routine -> rcx -- cgit 1.4.1-3-g733a5 From 0928b32141c0a01b47e45670a223bc4d479bec55 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 10 Dec 2021 00:04:25 +0000 Subject: Fix clippy lints --- library/compiler-builtins/src/float/div.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 9ac1e87b4e2..528a8368d92 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -132,8 +132,9 @@ where // This doubles the number of correct binary digits in the approximation // with each iteration, so after three iterations, we have about 28 binary // digits of accuracy. - let mut correction: u32; - correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); + + let mut correction: u32 = + negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; @@ -342,8 +343,9 @@ where // This doubles the number of correct binary digits in the approximation // with each iteration, so after three iterations, we have about 28 binary // digits of accuracy. - let mut correction32: u32; - correction32 = negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); + + let mut correction32: u32 = + negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; correction32 = negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; @@ -359,16 +361,15 @@ where // We need to perform one more iteration to get us to 56 binary digits; // The last iteration needs to happen with extra precision. let q63blo = CastInto::::cast(b_significand << 11.cast()); - let correction: u64; - let mut reciprocal: u64; - correction = negate_u64( + + let correction: u64 = negate_u64( (recip32 as u64) .wrapping_mul(q31b as u64) .wrapping_add((recip32 as u64).wrapping_mul(q63blo as u64) >> 32), ); let c_hi = (correction >> 32) as u32; let c_lo = correction as u32; - reciprocal = (recip32 as u64) + let mut reciprocal: u64 = (recip32 as u64) .wrapping_mul(c_hi as u64) .wrapping_add((recip32 as u64).wrapping_mul(c_lo as u64) >> 32); -- cgit 1.4.1-3-g733a5 From c7dc3215a1a1384c51727227d01259fc06f5c6f6 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 10 Dec 2021 00:11:25 +0000 Subject: Bump to 0.1.56 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7a894b9584c..4b2ed2de1d6 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.55" +version = "0.1.65" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 9e650601841ad7fa2e34e46523bbd5bffc658d61 Mon Sep 17 00:00:00 2001 From: Ayrton Date: Sat, 11 Dec 2021 23:03:01 -0500 Subject: Add `__truncdfsf2` intrinsic This adds the truncdfsf2 intrinsic and a corresponding fuzz test case. The implementation of trunc is generic to make it easy to add truncdfhs2 and truncsfhf2 if rust ever gets `f16` support. --- library/compiler-builtins/README.md | 2 +- library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/src/float/trunc.rs | 118 ++++++++++++++++++++++ library/compiler-builtins/testcrate/tests/misc.rs | 25 +++++ 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/src/float/trunc.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index a20d038f8e9..108b2679ded 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -183,7 +183,7 @@ features = ["c"] - [x] subdf3.c - [x] subsf3.c - [ ] truncdfhf2.c -- [ ] truncdfsf2.c +- [x] truncdfsf2.c - [ ] truncsfhf2.c - [x] udivdi3.c - [x] udivmoddi4.c diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 11680e7a9fa..01a5504d52c 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -10,6 +10,7 @@ pub mod extend; pub mod mul; pub mod pow; pub mod sub; +pub mod trunc; public_test_dep! { /// Trait for some basic operations on floats diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs new file mode 100644 index 00000000000..a00994c76e7 --- /dev/null +++ b/library/compiler-builtins/src/float/trunc.rs @@ -0,0 +1,118 @@ +use float::Float; +use int::{CastInto, Int}; + +fn trunc(a: F) -> R +where + F::Int: CastInto, + F::Int: CastInto, + u64: CastInto, + u32: CastInto, + + R::Int: CastInto, + u32: CastInto, + F::Int: CastInto, +{ + let src_zero = F::Int::ZERO; + let src_one = F::Int::ONE; + let src_bits = F::BITS; + let src_exp_bias = F::EXPONENT_BIAS; + + let src_min_normal = F::IMPLICIT_BIT; + let src_significand_mask = F::SIGNIFICAND_MASK; + let src_infinity = F::EXPONENT_MASK; + let src_sign_mask = F::SIGN_MASK; + let src_abs_mask = src_sign_mask - src_one; + let round_mask = (src_one << (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)) - src_one; + let halfway = src_one << (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS - 1); + let src_qnan = src_one << (F::SIGNIFICAND_BITS - 1); + let src_nan_code = src_qnan - src_one; + + let dst_zero = R::Int::ZERO; + let dst_one = R::Int::ONE; + let dst_bits = R::BITS; + let dst_inf_exp = R::EXPONENT_MAX; + let dst_exp_bias = R::EXPONENT_BIAS; + + let underflow_exponent: F::Int = (src_exp_bias + 1 - dst_exp_bias).cast(); + let overflow_exponent: F::Int = (src_exp_bias + dst_inf_exp - dst_exp_bias).cast(); + let underflow: F::Int = underflow_exponent << F::SIGNIFICAND_BITS; + let overflow: F::Int = overflow_exponent << F::SIGNIFICAND_BITS; + + let dst_qnan = R::Int::ONE << (R::SIGNIFICAND_BITS - 1); + let dst_nan_code = dst_qnan - dst_one; + + let sign_bits_delta = F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS; + // Break a into a sign and representation of the absolute value. + let a_abs = a.repr() & src_abs_mask; + let sign = a.repr() & src_sign_mask; + let mut abs_result: R::Int; + + if a_abs.wrapping_sub(underflow) < a_abs.wrapping_sub(overflow) { + // The exponent of a is within the range of normal numbers in the + // destination format. We can convert by simply right-shifting with + // rounding and adjusting the exponent. + abs_result = (a_abs >> sign_bits_delta).cast(); + let tmp = src_exp_bias.wrapping_sub(dst_exp_bias) << R::SIGNIFICAND_BITS; + abs_result = abs_result.wrapping_sub(tmp.cast()); + + let round_bits = a_abs & round_mask; + if round_bits > halfway { + // Round to nearest. + abs_result += dst_one; + } else if round_bits == halfway { + // Tie to even. + abs_result += abs_result & dst_one; + }; + } else if a_abs > src_infinity { + // a is NaN. + // Conjure the result by beginning with infinity, setting the qNaN + // bit and inserting the (truncated) trailing NaN field. + abs_result = (dst_inf_exp << R::SIGNIFICAND_BITS).cast(); + abs_result |= dst_qnan; + abs_result |= dst_nan_code + & ((a_abs & src_nan_code) >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast(); + } else if a_abs >= overflow { + // a overflows to infinity. + abs_result = (dst_inf_exp << R::SIGNIFICAND_BITS).cast(); + } else { + // a underflows on conversion to the destination type or is an exact + // zero. The result may be a denormal or zero. Extract the exponent + // to get the shift amount for the denormalization. + let a_exp: u32 = (a_abs >> F::SIGNIFICAND_BITS).cast(); + let shift = src_exp_bias - dst_exp_bias - a_exp + 1; + + let significand = (a.repr() & src_significand_mask) | src_min_normal; + + // Right shift by the denormalization amount with sticky. + if shift > F::SIGNIFICAND_BITS { + abs_result = dst_zero; + } else { + let sticky = if (significand << (src_bits - shift)) != src_zero { + src_one + } else { + src_zero + }; + let denormalized_significand: F::Int = significand >> shift | sticky; + abs_result = + (denormalized_significand >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast(); + let round_bits = denormalized_significand & round_mask; + // Round to nearest + if round_bits > halfway { + abs_result += dst_one; + } + // Ties to even + else if round_bits == halfway { + abs_result += abs_result & dst_one; + }; + } + } + + // Apply the signbit to the absolute value. + R::from_repr(abs_result | sign.wrapping_shr(src_bits - dst_bits).cast()) +} + +intrinsics! { + pub extern "C" fn __truncdfsf2(a: f64) -> f32 { + trunc(a) + } +} diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index 5f74e006380..773153c43b8 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -179,3 +179,28 @@ fn float_pow() { f64, 1e-12, __powidf2; ); } + +macro_rules! trunc { + ($fX:ident, $fD:ident, $fn:ident) => { + fuzz_float(N, |x: $fX| { + let tmp0 = x as $fD; + let tmp1: $fD = $fn(x); + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + tmp0, + tmp1 + ); + } + }); + }; +} + +#[test] +fn float_trunc() { + use compiler_builtins::float::trunc::__truncdfsf2; + + trunc!(f64, f32, __truncdfsf2); +} -- cgit 1.4.1-3-g733a5 From 39cd6082e46febeb6f04c856a910a1da15a900c3 Mon Sep 17 00:00:00 2001 From: Ayrton Date: Sun, 12 Dec 2021 15:19:05 -0500 Subject: Add attribute for ARM alias --- library/compiler-builtins/src/float/trunc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index a00994c76e7..d3890e04017 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -112,6 +112,7 @@ where } intrinsics! { + #[arm_aeabi_alias = __aeabi_d2f] pub extern "C" fn __truncdfsf2(a: f64) -> f32 { trunc(a) } -- cgit 1.4.1-3-g733a5 From 03b4f6233719ec971eeaafd240b5db0f0b28634b Mon Sep 17 00:00:00 2001 From: Ayrton Date: Sun, 12 Dec 2021 15:36:09 -0500 Subject: Add `__truncdfsf2vfp` for ARM --- library/compiler-builtins/src/float/trunc.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index d3890e04017..5f846c66941 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -116,4 +116,9 @@ intrinsics! { pub extern "C" fn __truncdfsf2(a: f64) -> f32 { trunc(a) } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __truncdfsf2vfp(a: f64) -> f32 { + a as f32 + } } -- cgit 1.4.1-3-g733a5 From 9124cdc7ec431805441cf6810ed55315803811c5 Mon Sep 17 00:00:00 2001 From: Ayrton Date: Sun, 12 Dec 2021 21:12:42 -0500 Subject: Remove truncdfsf2.c from sources in build.rs and add test for __truncdfsf2vfp Also fixed the calling convention for truncdfsf2 on ARM --- library/compiler-builtins/README.md | 2 +- library/compiler-builtins/build.rs | 1 - library/compiler-builtins/examples/intrinsics.rs | 11 ++--------- library/compiler-builtins/src/float/trunc.rs | 1 + library/compiler-builtins/testcrate/tests/misc.rs | 8 ++++++++ 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 108b2679ded..8b25558a87e 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -126,7 +126,7 @@ features = ["c"] - [x] arm/softfloat-alias.list - [x] arm/subdf3vfp.S - [x] arm/subsf3vfp.S -- [ ] arm/truncdfsf2vfp.S +- [x] arm/truncdfsf2vfp.S - [ ] arm/udivmodsi4.S (generic version is done) - [ ] arm/udivsi3.S (generic version is done) - [ ] arm/umodsi3.S (generic version is done) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 922cd07a0af..dc1cd1d23c7 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -227,7 +227,6 @@ mod c { ("__negsf2", "negsf2.c"), ("__powixf2", "powixf2.c"), ("__truncdfhf2", "truncdfhf2.c"), - ("__truncdfsf2", "truncdfsf2.c"), ("__truncsfhf2", "truncsfhf2.c"), ]); } diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index dfa46b1b8fe..0ca30c215b3 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -24,16 +24,9 @@ extern "C" {} // have an additional comment: the function name is the ARM name for the intrinsic and the comment // in the non-ARM name for the intrinsic. mod intrinsics { - // trunccdfsf2 + // truncdfsf2 pub fn aeabi_d2f(x: f64) -> f32 { - // This is only implemented in C currently, so only test it there. - #[cfg(feature = "c")] - return x as f32; - #[cfg(not(feature = "c"))] - { - drop(x); - 0.0 - } + x as f32 } // fixdfsi diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 5f846c66941..d73713084d6 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -112,6 +112,7 @@ where } intrinsics! { + #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_d2f] pub extern "C" fn __truncdfsf2(a: f64) -> f32 { trunc(a) diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index 773153c43b8..537ba1e60c7 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -204,3 +204,11 @@ fn float_trunc() { trunc!(f64, f32, __truncdfsf2); } + +#[cfg(target_arch = "arm")] +#[test] +fn float_trunc_arm() { + use compiler_builtins::float::trunc::__truncdfsf2vfp; + + trunc!(f64, f32, __truncdfsf2vfp); +} -- cgit 1.4.1-3-g733a5 From df4d9cd6cce2dabf36cb0f513b6ce48decd7b2ee Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 13 Dec 2021 02:25:49 +0000 Subject: Bump to 0.1.66 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 4b2ed2de1d6..3f4c96745ef 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.65" +version = "0.1.66" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From e36ee3b4b78b449028874c4644d53d8b2f67d7f0 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 3 Jan 2022 19:00:31 +0100 Subject: Disable powerpc64 tests which were broken by the LLVM 13 upgrade --- library/compiler-builtins/libm/ci/run-docker.sh | 2 +- library/compiler-builtins/libm/src/math/ceilf.rs | 2 ++ library/compiler-builtins/libm/src/math/fabsf.rs | 2 ++ library/compiler-builtins/libm/src/math/floorf.rs | 2 ++ library/compiler-builtins/libm/src/math/j1f.rs | 2 ++ library/compiler-builtins/libm/src/math/roundf.rs | 2 ++ library/compiler-builtins/libm/src/math/sincosf.rs | 2 ++ library/compiler-builtins/libm/src/math/sqrtf.rs | 2 ++ library/compiler-builtins/libm/src/math/truncf.rs | 2 ++ 9 files changed, 17 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index e7b80c719e5..c7ad60fd499 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -18,7 +18,7 @@ run() { --user $(id -u):$(id -g) \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ - -v $(dirname $(dirname `which cargo`)):/cargo \ + -v "${HOME}/.cargo":/cargo \ -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ -v `rustc --print sysroot`:/rust:ro \ diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index f1edbd061bf..7bcc647ca76 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -40,6 +40,8 @@ pub fn ceilf(x: f32) -> f32 { f32::from_bits(ui) } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::*; diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 6655c4c3ccc..23f3646dc4a 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -14,6 +14,8 @@ pub fn fabsf(x: f32) -> f32 { f32::from_bits(x.to_bits() & 0x7fffffff) } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::*; diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 287f0864277..dfdab91a0f6 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -40,6 +40,8 @@ pub fn floorf(x: f32) -> f32 { f32::from_bits(ui) } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::*; diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 5095894d7a1..33694908ca2 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -357,6 +357,8 @@ fn qonef(x: f32) -> f32 { return (0.375 + r / s) / x; } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::{j1f, y1f}; diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index c0872a7829d..becdb5620a9 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -7,6 +7,8 @@ pub fn roundf(x: f32) -> f32 { truncf(x + copysignf(0.5 - 0.25 * f32::EPSILON, x)) } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::roundf; diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index 2725caad63c..83c9f40ee3a 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -122,6 +122,8 @@ pub fn sincosf(x: f32) -> (f32, f32) { } } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::sincosf; diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index ee868c8c811..00b20e578be 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -128,6 +128,8 @@ pub fn sqrtf(x: f32) -> f32 { } } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::*; diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index a4c001629a2..20d5b73bd67 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -31,6 +31,8 @@ pub fn truncf(x: f32) -> f32 { f32::from_bits(i) } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { #[test] -- cgit 1.4.1-3-g733a5 From 7a67cce08845f95c342de39442e41a713939113f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 3 Jan 2022 19:06:54 +0100 Subject: Disable i686-unknown-linux-gnu tests for now --- library/compiler-builtins/libm/.github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 80ce4ebd5a6..decd71f5c7a 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -12,7 +12,7 @@ jobs: - arm-unknown-linux-gnueabi - arm-unknown-linux-gnueabihf - armv7-unknown-linux-gnueabihf - - i686-unknown-linux-gnu + # - i686-unknown-linux-gnu - mips-unknown-linux-gnu - mips64-unknown-linux-gnuabi64 - mips64el-unknown-linux-gnuabi64 -- cgit 1.4.1-3-g733a5 From 54a57001f80274e2d8885b742aa9117061d5e93e Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 3 Jan 2022 19:52:31 +0100 Subject: Ignore some functions which don't match musl --- library/compiler-builtins/libm/build.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 9af6dec938b..13c3fa1cca0 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -26,7 +26,19 @@ mod musl_reference_tests { // These files are all internal functions or otherwise miscellaneous, not // defining a function we want to test. - const IGNORED_FILES: &[&str] = &["fenv.rs"]; + const IGNORED_FILES: &[&str] = &[ + "fenv.rs", + // These are giving slightly different results compared to musl + "lgamma.rs", + "lgammaf.rs", + "tgamma.rs", + "j0.rs", + "j0f.rs", + "jn.rs", + "jnf.rs", + "j1.rs", + "j1f.rs", + ]; struct Function { name: String, -- cgit 1.4.1-3-g733a5 From 4f5d1524fd60c59a0e070facd1da8e2d15c23337 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 3 Jan 2022 21:32:08 +0100 Subject: Fix no-panic --- library/compiler-builtins/libm/Cargo.toml | 4 ++++ library/compiler-builtins/libm/ci/run.sh | 3 +++ 2 files changed, 7 insertions(+) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 106de51dfb6..3a6c5851b71 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -33,3 +33,7 @@ no-panic = "0.1.8" [build-dependencies] rand = { version = "0.6.5", optional = true } + +# This is needed for no-panic to correctly detect the lack of panics +[profile.release] +lto = "fat" diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index ed253ab0d10..d0cd42a8d0b 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -5,6 +5,9 @@ TARGET=$1 CMD="cargo test --all --target $TARGET" +# Needed for no-panic to correct detect a lack of panics +export RUSTFLAGS="$RUSTFLAGS -Ccodegen-units=1" + # stable by default $CMD $CMD --release -- cgit 1.4.1-3-g733a5 From eb26f75f637c7492e4ef204088e3b438b921afac Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 4 Jan 2022 00:09:07 +0100 Subject: Disable musl tests on powerpc64 --- library/compiler-builtins/libm/build.rs | 7 +++++++ library/compiler-builtins/libm/src/lib.rs | 2 ++ 2 files changed, 9 insertions(+) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 13c3fa1cca0..80145a9ccac 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -18,6 +18,7 @@ fn main() { mod musl_reference_tests { use rand::seq::SliceRandom; use rand::Rng; + use std::env; use std::fs; use std::process::Command; @@ -60,6 +61,12 @@ mod musl_reference_tests { } pub fn generate() { + // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + if target_arch == "powerpc64" { + return; + } + let files = fs::read_dir("src/math") .unwrap() .map(|f| f.unwrap().path()) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index bbc79ecad56..29742b4510c 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -51,5 +51,7 @@ pub fn _eq(a: f64, b: f64) -> Result<(), u64> { } } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(all(test, feature = "musl-reference-tests"))] include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); -- cgit 1.4.1-3-g733a5 From d3fb52a7af8ba99ba8e1861d3453499b7ef8faa4 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Wed, 22 Dec 2021 00:56:18 +0000 Subject: force test_near_pi in rem_pio2.rs to be evaluated at runtime not compiletime. --- library/compiler-builtins/libm/src/math/rem_pio2.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 46f7c38ffed..f58fa359bab 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -190,20 +190,28 @@ mod tests { #[test] fn test_near_pi() { + let arg = 3.141592025756836; + force_eval!(arg); assert_eq!( - rem_pio2(3.141592025756836), + rem_pio2(arg), (2, -6.278329573009626e-7, -2.1125998133974653e-23) ); + let arg = 3.141592033207416; + force_eval!(arg); assert_eq!( - rem_pio2(3.141592033207416), + rem_pio2(arg), (2, -6.20382377148128e-7, -2.1125998133974653e-23) ); + let arg = 3.141592144966125; + force_eval!(arg); assert_eq!( - rem_pio2(3.141592144966125), + rem_pio2(arg), (2, -5.086236681942706e-7, -2.1125998133974653e-23) ); + let arg = 3.141592979431152; + force_eval!(arg); assert_eq!( - rem_pio2(3.141592979431152), + rem_pio2(arg), (2, 3.2584135866119817e-7, -2.1125998133974653e-23) ); } -- cgit 1.4.1-3-g733a5 From 17c907329893aca7c966aa6117f3e008315d5681 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Tue, 5 Jan 2021 17:32:30 +0000 Subject: Fix testcases on x87 --- library/compiler-builtins/libm/src/math/ceil.rs | 19 ++++++++++++ library/compiler-builtins/libm/src/math/floor.rs | 19 ++++++++++++ library/compiler-builtins/libm/src/math/j1f.rs | 6 +++- .../compiler-builtins/libm/src/math/rem_pio2f.rs | 4 ++- library/compiler-builtins/libm/src/math/sincosf.rs | 36 +++++++++++++++++++--- 5 files changed, 78 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index eda28b9a0f2..22d89297138 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -1,3 +1,4 @@ +#![allow(unreachable_code)] use core::f64; const TOINT: f64 = 1. / f64::EPSILON; @@ -15,6 +16,24 @@ pub fn ceil(x: f64) -> f64 { return unsafe { ::core::intrinsics::ceilf64(x) } } } + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + { + //use an alternative implementation on x86, because the + //main implementation fails with the x87 FPU used by + //debian i386, probablly due to excess precision issues. + //basic implementation taken from https://github.com/rust-lang/libm/issues/219 + use super::fabs; + if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated < x { + return truncated + 1.0; + } else { + return truncated; + } + } else { + return x; + } + } let u: u64 = x.to_bits(); let e: i64 = (u >> 52 & 0x7ff) as i64; let y: f64; diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index b2b760570de..d09f9a1a1f8 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -1,3 +1,4 @@ +#![allow(unreachable_code)] use core::f64; const TOINT: f64 = 1. / f64::EPSILON; @@ -15,6 +16,24 @@ pub fn floor(x: f64) -> f64 { return unsafe { ::core::intrinsics::floorf64(x) } } } + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + { + //use an alternative implementation on x86, because the + //main implementation fails with the x87 FPU used by + //debian i386, probablly due to excess precision issues. + //basic implementation taken from https://github.com/rust-lang/libm/issues/219 + use super::fabs; + if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated > x { + return truncated - 1.0; + } else { + return truncated; + } + } else { + return x; + } + } let ui = x.to_bits(); let e = ((ui >> 52) & 0x7ff) as i32; diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 33694908ca2..225b719bf96 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -369,6 +369,10 @@ mod tests { } #[test] fn test_y1f_2002() { - assert_eq!(y1f(2.0000002_f32), -0.10703229_f32); + //allow slightly different result on x87 + let res = y1f(2.0000002_f32); + if res != -0.10703231_f32 { + assert_eq!(res, -0.10703229_f32); + } } } diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 5d392ba2d7f..4d4499b986e 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -43,7 +43,9 @@ pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { if ix < 0x4dc90fdb { /* |x| ~< 2^28*(pi/2), medium size */ /* Use a specialized rint() to get fn. Assume round-to-nearest. */ - let f_n = x64 * INV_PIO2 + TOINT - TOINT; + // use to_bits and from_bits to force rounding to storage format on + // x87. + let f_n = f64::from_bits((x64 * INV_PIO2 + TOINT).to_bits()) - TOINT; return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); } if ix >= 0x7f800000 { diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index 83c9f40ee3a..5304e8ca027 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -147,10 +147,38 @@ mod tests { let (s_minus, c_minus) = sincosf(theta - 2. * PI); const TOLERANCE: f32 = 1e-6; - assert!((s - s_plus).abs() < TOLERANCE); - assert!((s - s_minus).abs() < TOLERANCE); - assert!((c - c_plus).abs() < TOLERANCE); - assert!((c - c_minus).abs() < TOLERANCE); + assert!( + (s - s_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_plus, + (s - s_plus).abs(), + TOLERANCE + ); + assert!( + (s - s_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_minus, + (s - s_minus).abs(), + TOLERANCE + ); + assert!( + (c - c_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_plus, + (c - c_plus).abs(), + TOLERANCE + ); + assert!( + (c - c_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_minus, + (c - c_minus).abs(), + TOLERANCE + ); } } } -- cgit 1.4.1-3-g733a5 From 874209b56c5ab1ce15e6c499bc83bcdecf5f7c74 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Tue, 21 Dec 2021 22:41:29 +0000 Subject: Use force_eval instead of to_bits/from_bits combination, Using to_bits/from_bits to force conversion to storage format apparently doesn't work in release mode. Also add an architecture conditional to avoid pessimising other architectures. --- library/compiler-builtins/libm/src/math/rem_pio2f.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 4d4499b986e..3ce8f9ab177 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -43,9 +43,11 @@ pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { if ix < 0x4dc90fdb { /* |x| ~< 2^28*(pi/2), medium size */ /* Use a specialized rint() to get fn. Assume round-to-nearest. */ - // use to_bits and from_bits to force rounding to storage format on - // x87. - let f_n = f64::from_bits((x64 * INV_PIO2 + TOINT).to_bits()) - TOINT; + let tmp = x64 * INV_PIO2 + TOINT; + // force rounding of tmp to it's storage format on x87 to avoid + // excess precision issues. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(tmp); + let f_n = tmp - TOINT; return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); } if ix >= 0x7f800000 { -- cgit 1.4.1-3-g733a5 From e95ea2b11dcadd99fa9b0b0057b6cfe2d299ac11 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Tue, 21 Dec 2021 23:53:06 +0000 Subject: Add forced rounding to storage format for x87 to rem_pio2.rs as well. --- .../compiler-builtins/libm/src/math/rem_pio2.rs | 6 +- library/compiler-builtins/libm/src/math/sincos.rs | 74 ++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index f58fa359bab..4ac9415b5f4 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -50,7 +50,11 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { fn medium(x: f64, ix: u32) -> (i32, f64, f64) { /* rint(x/(pi/2)), Assume round-to-nearest. */ - let f_n = x as f64 * INV_PIO2 + TO_INT - TO_INT; + let tmp = x as f64 * INV_PIO2 + TO_INT; + // force rounding of tmp to it's storage format on x87 to avoid + // excess precision issues. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(tmp); + let f_n = tmp - TO_INT; let n = f_n as i32; let mut r = x - f_n * PIO2_1; let mut w = f_n * PIO2_1T; /* 1st round, good to 85 bits */ diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs index d49f65c9707..bfc4561f8b2 100644 --- a/library/compiler-builtins/libm/src/math/sincos.rs +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -57,3 +57,77 @@ pub fn sincos(x: f64) -> (f64, f64) { _ => (0.0, 1.0), } } + +// These tests are based on those from sincosf.rs +#[cfg(test)] +mod tests { + use super::sincos; + + const TOLERANCE: f64 = 1e-6; + + #[test] + fn with_pi() { + let (s, c) = sincos(core::f64::consts::PI); + assert!( + (s - 0.0).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + 0.0, + (s - 0.0).abs(), + TOLERANCE + ); + assert!( + (c + 1.0).abs() < TOLERANCE, + "|{} + {}| = {} >= {}", + c, + 1.0, + (s + 1.0).abs(), + TOLERANCE + ); + } + + #[test] + fn rotational_symmetry() { + use core::f64::consts::PI; + const N: usize = 24; + for n in 0..N { + let theta = 2. * PI * (n as f64) / (N as f64); + let (s, c) = sincos(theta); + let (s_plus, c_plus) = sincos(theta + 2. * PI); + let (s_minus, c_minus) = sincos(theta - 2. * PI); + + assert!( + (s - s_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_plus, + (s - s_plus).abs(), + TOLERANCE + ); + assert!( + (s - s_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_minus, + (s - s_minus).abs(), + TOLERANCE + ); + assert!( + (c - c_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_plus, + (c - c_plus).abs(), + TOLERANCE + ); + assert!( + (c - c_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_minus, + (c - c_minus).abs(), + TOLERANCE + ); + } + } +} -- cgit 1.4.1-3-g733a5 From e3c3304557ba9f3888215f995d1bbf58ee1037e9 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Wed, 22 Dec 2021 00:21:25 +0000 Subject: round to storage format in some tests before comparison to prevent spurious errors on x87. --- library/compiler-builtins/libm/src/math/fma.rs | 5 ++++- library/compiler-builtins/libm/src/math/pow.rs | 2 ++ library/compiler-builtins/libm/src/math/sin.rs | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 85d842119cb..c20de94a57e 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -218,7 +218,10 @@ mod tests { -0.00000000000000022204460492503126, ); - assert_eq!(fma(-0.992, -0.992, -0.992), -0.007936000000000007,); + let result = fma(-0.992, -0.992, -0.992); + //force rounding to storage format on x87 to prevent superious errors. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(result); + assert_eq!(result, -0.007936000000000007,); } #[test] diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index f79680a05d0..3249e7eea03 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -484,6 +484,8 @@ mod tests { let exp = expected(*val); let res = computed(*val); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(exp); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(res); assert!( if exp.is_nan() { res.is_nan() diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index 1329b41a9d6..a562aa6e4a0 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -81,5 +81,7 @@ pub fn sin(x: f64) -> f64 { fn test_near_pi() { let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 - assert_eq!(sin(x), sx); + let result = sin(x); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(result); + assert_eq!(result, sx); } -- cgit 1.4.1-3-g733a5 From 94b416e4960830abe9afeb896df00b3931008089 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Tue, 4 Jan 2022 20:38:09 +0000 Subject: only allow x87-specific result in j1f.rs test on x87 --- library/compiler-builtins/libm/src/math/j1f.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 225b719bf96..775ff2b2ef1 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -371,8 +371,7 @@ mod tests { fn test_y1f_2002() { //allow slightly different result on x87 let res = y1f(2.0000002_f32); - if res != -0.10703231_f32 { - assert_eq!(res, -0.10703229_f32); - } + if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && (res == -0.10703231_f32) { return }; + assert_eq!(res, -0.10703229_f32); } } -- cgit 1.4.1-3-g733a5 From f8c8c8b2fe3610924ac062943bd210cb275196bb Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Tue, 4 Jan 2022 20:51:40 +0000 Subject: allow force_eval! to produce a result and use that result to more explicitly force rounding on x87. --- library/compiler-builtins/libm/src/math/fma.rs | 3 ++- library/compiler-builtins/libm/src/math/mod.rs | 2 +- library/compiler-builtins/libm/src/math/pow.rs | 6 ++++-- library/compiler-builtins/libm/src/math/rem_pio2.rs | 11 ++++++----- library/compiler-builtins/libm/src/math/rem_pio2f.rs | 3 ++- library/compiler-builtins/libm/src/math/sin.rs | 3 ++- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index c20de94a57e..516f9ad3a77 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -220,7 +220,8 @@ mod tests { let result = fma(-0.992, -0.992, -0.992); //force rounding to storage format on x87 to prevent superious errors. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(result); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let result = force_eval!(result); assert_eq!(result, -0.007936000000000007,); } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index ceeee0b31fb..7f4c8bcf4c0 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -1,7 +1,7 @@ macro_rules! force_eval { ($e:expr) => { unsafe { - ::core::ptr::read_volatile(&$e); + ::core::ptr::read_volatile(&$e) } }; } diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 3249e7eea03..6a19ae60111 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -484,8 +484,10 @@ mod tests { let exp = expected(*val); let res = computed(*val); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(exp); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(res); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let exp = force_eval!(exp); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let res = force_eval!(res); assert!( if exp.is_nan() { res.is_nan() diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 4ac9415b5f4..644616f2df8 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -53,7 +53,8 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { let tmp = x as f64 * INV_PIO2 + TO_INT; // force rounding of tmp to it's storage format on x87 to avoid // excess precision issues. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(tmp); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let tmp = force_eval!(tmp); let f_n = tmp - TO_INT; let n = f_n as i32; let mut r = x - f_n * PIO2_1; @@ -195,25 +196,25 @@ mod tests { #[test] fn test_near_pi() { let arg = 3.141592025756836; - force_eval!(arg); + let arg = force_eval!(arg); assert_eq!( rem_pio2(arg), (2, -6.278329573009626e-7, -2.1125998133974653e-23) ); let arg = 3.141592033207416; - force_eval!(arg); + let arg = force_eval!(arg); assert_eq!( rem_pio2(arg), (2, -6.20382377148128e-7, -2.1125998133974653e-23) ); let arg = 3.141592144966125; - force_eval!(arg); + let arg = force_eval!(arg); assert_eq!( rem_pio2(arg), (2, -5.086236681942706e-7, -2.1125998133974653e-23) ); let arg = 3.141592979431152; - force_eval!(arg); + let arg = force_eval!(arg); assert_eq!( rem_pio2(arg), (2, 3.2584135866119817e-7, -2.1125998133974653e-23) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 3ce8f9ab177..775f5d750fb 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -46,7 +46,8 @@ pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { let tmp = x64 * INV_PIO2 + TOINT; // force rounding of tmp to it's storage format on x87 to avoid // excess precision issues. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(tmp); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let tmp = force_eval!(tmp); let f_n = tmp - TOINT; return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); } diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index a562aa6e4a0..a53843dcdae 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -82,6 +82,7 @@ fn test_near_pi() { let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 let result = sin(x); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(result); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let result = force_eval!(result); assert_eq!(result, sx); } -- cgit 1.4.1-3-g733a5 From 8d91281fcc05a0cabd8c606a8999bc0ecc775d53 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Wed, 22 Dec 2021 01:50:25 +0000 Subject: Apply formatting fixes from CI --- library/compiler-builtins/libm/src/math/j1f.rs | 5 +++- library/compiler-builtins/libm/src/math/mod.rs | 4 +--- library/compiler-builtins/libm/src/math/sincos.rs | 28 +++++++++++------------ 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 775ff2b2ef1..c39f8ff7e96 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -371,7 +371,10 @@ mod tests { fn test_y1f_2002() { //allow slightly different result on x87 let res = y1f(2.0000002_f32); - if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && (res == -0.10703231_f32) { return }; + if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && (res == -0.10703231_f32) + { + return; + } assert_eq!(res, -0.10703229_f32); } } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 7f4c8bcf4c0..81bfc53ed85 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -1,8 +1,6 @@ macro_rules! force_eval { ($e:expr) => { - unsafe { - ::core::ptr::read_volatile(&$e) - } + unsafe { ::core::ptr::read_volatile(&$e) } }; } diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs index bfc4561f8b2..4ab588412a5 100644 --- a/library/compiler-builtins/libm/src/math/sincos.rs +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -69,21 +69,21 @@ mod tests { fn with_pi() { let (s, c) = sincos(core::f64::consts::PI); assert!( - (s - 0.0).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - 0.0, - (s - 0.0).abs(), - TOLERANCE - ); + (s - 0.0).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + 0.0, + (s - 0.0).abs(), + TOLERANCE + ); assert!( - (c + 1.0).abs() < TOLERANCE, - "|{} + {}| = {} >= {}", - c, - 1.0, - (s + 1.0).abs(), - TOLERANCE - ); + (c + 1.0).abs() < TOLERANCE, + "|{} + {}| = {} >= {}", + c, + 1.0, + (s + 1.0).abs(), + TOLERANCE + ); } #[test] -- cgit 1.4.1-3-g733a5 From 554fa533abb120fe78e2a9d2c5da3d67b70aa13c Mon Sep 17 00:00:00 2001 From: Daniel Sommermann Date: Thu, 27 Jan 2022 11:53:50 -0800 Subject: Stop emitting duplicate symbols for `armv7-linux-androideabi` The change in 186517b3266a7bb2b2310927f7342ea7f41790c3 was intended to affect only `arm-linux-androideabi` but also affected `armv7-linux-androideabi` which is not a pre-ARMv6 architecture. Fixes #449 --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index dc1cd1d23c7..2b34540dc44 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -83,7 +83,7 @@ fn main() { // rustc target (arm-linux-androideabi). if llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" - || llvm_target.get(2) == Some(&"androideabi") + || target == "arm-linux-androideabi" { println!("cargo:rustc-cfg=kernel_user_helpers") } -- cgit 1.4.1-3-g733a5 From f5fa287bc2ac15e5023db1c0ae8abdbeddacfdd3 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 28 Jan 2022 12:47:27 +0000 Subject: Bump to 0.1.67 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 3f4c96745ef..a8278f0b816 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.66" +version = "0.1.67" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From c51299d63abd66542afc51e34b03a27da6b48f06 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 6 Feb 2022 09:20:19 +0000 Subject: Fix run-docker.sh so it can be run locally --- library/compiler-builtins/ci/run-docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 4bb2a78d934..8c4af0eff20 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -19,7 +19,7 @@ run() { -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ -e RUST_COMPILER_RT_ROOT \ - -v $(dirname $(dirname `which cargo`)):/cargo \ + -v "${HOME}/.cargo":/cargo \ -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ -v `rustc --print sysroot`:/rust:ro \ -- cgit 1.4.1-3-g733a5 From f03c7fd6afe41392479bb921e118abf6f2f5c136 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 6 Feb 2022 09:20:43 +0000 Subject: Wrap all intrinsics in the intrinsics! macro This ensures that each intrinsic ends up in a separate module, which in turn (because rustc treats compiler_builtins specially) will result in each intrinsic ending up in its own object file. This allows the linker to only pick up object files for intrinsics that are missing and avoids duplicate symbol definition errors. --- library/compiler-builtins/src/arm.rs | 376 ++++++++++++----------------- library/compiler-builtins/src/arm_linux.rs | 21 +- library/compiler-builtins/src/macros.rs | 119 +++++++-- library/compiler-builtins/src/mem/mod.rs | 112 ++++----- library/compiler-builtins/src/x86.rs | 148 ++++++------ library/compiler-builtins/src/x86_64.rs | 158 ++++++------ 6 files changed, 469 insertions(+), 465 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 3660825aa73..95bde511662 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -3,251 +3,181 @@ use core::intrinsics; -// NOTE This function and the ones below are implemented using assembly because they are using a -// custom calling convention which can't be implemented using a normal Rust function. -// NOTE The only difference between the iOS and non-iOS versions of those functions is that the iOS -// versions use 3 leading underscores in the names of called functions instead of 2. -#[cfg(not(any(target_os = "ios", target_env = "msvc")))] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_uidivmod() { - core::arch::asm!( - "push {{lr}}", - "sub sp, sp, #4", - "mov r2, sp", - "bl __udivmodsi4", - "ldr r1, [sp]", - "add sp, sp, #4", - "pop {{pc}}", - options(noreturn) - ); -} - +// iOS symbols have a leading underscore. #[cfg(target_os = "ios")] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_uidivmod() { - core::arch::asm!( - "push {{lr}}", - "sub sp, sp, #4", - "mov r2, sp", - "bl ___udivmodsi4", - "ldr r1, [sp]", - "add sp, sp, #4", - "pop {{pc}}", - options(noreturn) - ); +macro_rules! bl { + ($func:literal) => { + concat!("bl _", $func) + }; } - #[cfg(not(target_os = "ios"))] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_uldivmod() { - core::arch::asm!( - "push {{r4, lr}}", - "sub sp, sp, #16", - "add r4, sp, #8", - "str r4, [sp]", - "bl __udivmoddi4", - "ldr r2, [sp, #8]", - "ldr r3, [sp, #12]", - "add sp, sp, #16", - "pop {{r4, pc}}", - options(noreturn) - ); -} - -#[cfg(target_os = "ios")] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_uldivmod() { - core::arch::asm!( - "push {{r4, lr}}", - "sub sp, sp, #16", - "add r4, sp, #8", - "str r4, [sp]", - "bl ___udivmoddi4", - "ldr r2, [sp, #8]", - "ldr r3, [sp, #12]", - "add sp, sp, #16", - "pop {{r4, pc}}", - options(noreturn) - ); -} - -#[cfg(not(target_os = "ios"))] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_idivmod() { - core::arch::asm!( - "push {{r0, r1, r4, lr}}", - "bl __aeabi_idiv", - "pop {{r1, r2}}", - "muls r2, r2, r0", - "subs r1, r1, r2", - "pop {{r4, pc}}", - options(noreturn) - ); -} - -#[cfg(target_os = "ios")] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_idivmod() { - core::arch::asm!( - "push {{r0, r1, r4, lr}}", - "bl ___aeabi_idiv", - "pop {{r1, r2}}", - "muls r2, r2, r0", - "subs r1, r1, r2", - "pop {{r4, pc}}", - options(noreturn) - ); -} +macro_rules! bl { + ($func:literal) => { + concat!("bl ", $func) + }; +} + +intrinsics! { + // NOTE This function and the ones below are implemented using assembly because they are using a + // custom calling convention which can't be implemented using a normal Rust function. + #[naked] + #[cfg(not(target_env = "msvc"))] + pub unsafe extern "C" fn __aeabi_uidivmod() { + core::arch::asm!( + "push {{lr}}", + "sub sp, sp, #4", + "mov r2, sp", + bl!("__udivmodsi4"), + "ldr r1, [sp]", + "add sp, sp, #4", + "pop {{pc}}", + options(noreturn) + ); + } -#[cfg(not(target_os = "ios"))] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_ldivmod() { - core::arch::asm!( - "push {{r4, lr}}", - "sub sp, sp, #16", - "add r4, sp, #8", - "str r4, [sp]", - "bl __divmoddi4", - "ldr r2, [sp, #8]", - "ldr r3, [sp, #12]", - "add sp, sp, #16", - "pop {{r4, pc}}", - options(noreturn) - ); -} + #[naked] + pub unsafe extern "C" fn __aeabi_uldivmod() { + core::arch::asm!( + "push {{r4, lr}}", + "sub sp, sp, #16", + "add r4, sp, #8", + "str r4, [sp]", + bl!("__udivmodsi4"), + "ldr r2, [sp, #8]", + "ldr r3, [sp, #12]", + "add sp, sp, #16", + "pop {{r4, pc}}", + options(noreturn) + ); + } -#[cfg(target_os = "ios")] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_ldivmod() { - core::arch::asm!( - "push {{r4, lr}}", - "sub sp, sp, #16", - "add r4, sp, #8", - "str r4, [sp]", - "bl ___divmoddi4", - "ldr r2, [sp, #8]", - "ldr r3, [sp, #12]", - "add sp, sp, #16", - "pop {{r4, pc}}", - options(noreturn) - ); -} + #[naked] + pub unsafe extern "C" fn __aeabi_idivmod() { + core::arch::asm!( + "push {{r0, r1, r4, lr}}", + bl!("__aeabi_idiv"), + "pop {{r1, r2}}", + "muls r2, r2, r0", + "subs r1, r1, r2", + "pop {{r4, pc}}", + options(noreturn) + ); + } -// The following functions use weak linkage to allow users to override -// with custom implementation. -// FIXME: The `*4` and `*8` variants should be defined as aliases. + #[naked] + pub unsafe extern "C" fn __aeabi_ldivmod() { + core::arch::asm!( + "push {{r4, lr}}", + "sub sp, sp, #16", + "add r4, sp, #8", + "str r4, [sp]", + bl!("__divmoddi4"), + "ldr r2, [sp, #8]", + "ldr r3, [sp, #12]", + "add sp, sp, #16", + "pop {{r4, pc}}", + options(noreturn) + ); + } -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { - ::mem::memcpy(dest, src, n); -} + // The following functions use weak linkage to allow users to override + // with custom implementation. + // FIXME: The `*4` and `*8` variants should be defined as aliases. -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) { - // We are guaranteed 4-alignment, so accessing at u32 is okay. - let mut dest = dest as *mut u32; - let mut src = src as *mut u32; + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { + ::mem::memcpy(dest, src, n); + } - while n >= 4 { - *dest = *src; - dest = dest.offset(1); - src = src.offset(1); - n -= 4; + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { + // We are guaranteed 4-alignment, so accessing at u32 is okay. + let mut dest = dest as *mut u32; + let mut src = src as *mut u32; + let mut n = n; + + while n >= 4 { + *dest = *src; + dest = dest.offset(1); + src = src.offset(1); + n -= 4; + } + + __aeabi_memcpy(dest as *mut u8, src as *const u8, n); } - __aeabi_memcpy(dest as *mut u8, src as *const u8, n); -} + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { + __aeabi_memcpy4(dest, src, n); + } -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memcpy4(dest, src, n); -} + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { + ::mem::memmove(dest, src, n); + } -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { - ::mem::memmove(dest, src, n); -} + #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { + __aeabi_memmove(dest, src, n); + } -#[cfg(not(any(target_os = "ios", target_env = "msvc")))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memmove(dest, src, n); -} + #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { + __aeabi_memmove(dest, src, n); + } -#[cfg(not(any(target_os = "ios", target_env = "msvc")))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memmove(dest, src, n); -} + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { + // Note the different argument order + ::mem::memset(dest, c, n); + } -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { - // Note the different argument order - ::mem::memset(dest, c, n); -} + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { + let mut dest = dest as *mut u32; + let mut n = n; -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) { - let mut dest = dest as *mut u32; + let byte = (c as u32) & 0xff; + let c = (byte << 24) | (byte << 16) | (byte << 8) | byte; - let byte = (c as u32) & 0xff; - let c = (byte << 24) | (byte << 16) | (byte << 8) | byte; + while n >= 4 { + *dest = c; + dest = dest.offset(1); + n -= 4; + } - while n >= 4 { - *dest = c; - dest = dest.offset(1); - n -= 4; + __aeabi_memset(dest as *mut u8, n, byte as i32); } - __aeabi_memset(dest as *mut u8, n, byte as i32); -} - -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { - __aeabi_memset4(dest, n, c); -} + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { + __aeabi_memset4(dest, n, c); + } -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { - __aeabi_memset(dest, n, 0); -} + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { + __aeabi_memset(dest, n, 0); + } -#[cfg(not(any(target_os = "ios", target_env = "msvc")))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { - __aeabi_memset4(dest, n, 0); -} + #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { + __aeabi_memset4(dest, n, 0); + } -#[cfg(not(any(target_os = "ios", target_env = "msvc")))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { - __aeabi_memset4(dest, n, 0); + #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { + __aeabi_memset4(dest, n, 0); + } } diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs index e710c1ab98a..df1723d99c6 100644 --- a/library/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/src/arm_linux.rs @@ -90,17 +90,19 @@ unsafe fn atomic_cmpxchg(ptr: *mut T, oldval: u32, newval: u32) -> u32 { macro_rules! atomic_rmw { ($name:ident, $ty:ty, $op:expr) => { - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty { - atomic_rmw(ptr, |x| $op(x as $ty, val) as u32) as $ty + intrinsics! { + pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty { + atomic_rmw(ptr, |x| $op(x as $ty, val) as u32) as $ty + } } }; } macro_rules! atomic_cmpxchg { ($name:ident, $ty:ty) => { - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - pub unsafe extern "C" fn $name(ptr: *mut $ty, oldval: $ty, newval: $ty) -> $ty { - atomic_cmpxchg(ptr, oldval as u32, newval as u32) as $ty + intrinsics! { + pub unsafe extern "C" fn $name(ptr: *mut $ty, oldval: $ty, newval: $ty) -> $ty { + atomic_cmpxchg(ptr, oldval as u32, newval as u32) as $ty + } } }; } @@ -205,7 +207,8 @@ atomic_cmpxchg!(__sync_val_compare_and_swap_1, u8); atomic_cmpxchg!(__sync_val_compare_and_swap_2, u16); atomic_cmpxchg!(__sync_val_compare_and_swap_4, u32); -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __sync_synchronize() { - __kuser_memory_barrier(); +intrinsics! { + pub unsafe extern "C" fn __sync_synchronize() { + __kuser_memory_barrier(); + } } diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 214f0795fc5..6926feac055 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -76,7 +76,7 @@ macro_rules! intrinsics { ( #[maybe_use_optimized_c_shim] $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } @@ -84,9 +84,9 @@ macro_rules! intrinsics { ) => ( #[cfg($name = "optimized-c")] - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { extern $abi { - fn $name($($argname: $ty),*) -> $ret; + fn $name($($argname: $ty),*) $(-> $ret)?; } unsafe { $name($($argname),*) @@ -96,7 +96,7 @@ macro_rules! intrinsics { #[cfg(not($name = "optimized-c"))] intrinsics! { $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -110,7 +110,7 @@ macro_rules! intrinsics { ( #[aapcs_on_arm] $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } @@ -119,7 +119,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] intrinsics! { $(#[$($attr)*])* - pub extern "aapcs" fn $name( $($argname: $ty),* ) -> $ret { + pub extern "aapcs" fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -127,7 +127,7 @@ macro_rules! intrinsics { #[cfg(not(target_arch = "arm"))] intrinsics! { $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -140,7 +140,7 @@ macro_rules! intrinsics { ( #[unadjusted_on_win64] $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } @@ -149,7 +149,7 @@ macro_rules! intrinsics { #[cfg(all(windows, target_pointer_width = "64"))] intrinsics! { $(#[$($attr)*])* - pub extern "unadjusted" fn $name( $($argname: $ty),* ) -> $ret { + pub extern "unadjusted" fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -157,7 +157,7 @@ macro_rules! intrinsics { #[cfg(not(all(windows, target_pointer_width = "64")))] intrinsics! { $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -175,7 +175,7 @@ macro_rules! intrinsics { ( #[win64_128bit_abi_hack] $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } @@ -183,7 +183,7 @@ macro_rules! intrinsics { ) => ( #[cfg(all(windows, target_arch = "x86_64"))] $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -193,7 +193,7 @@ macro_rules! intrinsics { pub extern $abi fn $name( $($argname: $ty),* ) -> ::macros::win64_128bit_abi_hack::U64x2 { - let e: $ret = super::$name($($argname),*); + let e: $($ret)? = super::$name($($argname),*); ::macros::win64_128bit_abi_hack::U64x2::from(e) } } @@ -201,7 +201,7 @@ macro_rules! intrinsics { #[cfg(not(all(windows, target_arch = "x86_64")))] intrinsics! { $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -216,21 +216,21 @@ macro_rules! intrinsics { ( #[arm_aeabi_alias = $alias:ident] $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } $($rest:tt)* ) => ( #[cfg(target_arch = "arm")] - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } #[cfg(target_arch = "arm")] pub mod $name { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } @@ -238,7 +238,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] pub mod $alias { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - pub extern "aapcs" fn $alias( $($argname: $ty),* ) -> $ret { + pub extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } @@ -246,7 +246,57 @@ macro_rules! intrinsics { #[cfg(not(target_arch = "arm"))] intrinsics! { $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // C mem* functions are only generated when the "mem" feature is enabled. + ( + #[mem_builtin] + $(#[$($attr:tt)*])* + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + $(#[$($attr)*])* + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + + #[cfg(feature = "mem")] + pub mod $name { + $(#[$($attr)*])* + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + super::$name($($argname),*) + } + } + + intrinsics!($($rest)*); + ); + + // Naked functions are special: we can't generate wrappers for them since + // they use a custom calling convention. + ( + #[naked] + $(#[$($attr:tt)*])* + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + pub mod $name { + #[naked] + $(#[$($attr)*])* + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -268,21 +318,46 @@ macro_rules! intrinsics { // input we were given. ( $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + + pub mod $name { + $(#[$($attr)*])* + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + super::$name($($argname),*) + } + } + + intrinsics!($($rest)*); + ); + + // Same as the above for unsafe functions. + ( + $(#[$($attr:tt)*])* + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } $($rest:tt)* ) => ( $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } pub mod $name { $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index 2f9a9fd945e..dce4d87e0a5 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -19,53 +19,55 @@ use core::ops::{BitOr, Shl}; )] mod impls; -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] -pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - impls::copy_forward(dest, src, n); - dest -} - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] -pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - let delta = (dest as usize).wrapping_sub(src as usize); - if delta >= n { - // We can copy forwards because either dest is far enough ahead of src, - // or src is ahead of dest (and delta overflowed). +intrinsics! { + #[mem_builtin] + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] + pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { impls::copy_forward(dest, src, n); - } else { - impls::copy_backward(dest, src, n); + dest } - dest -} -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] -pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { - impls::set_bytes(s, c as u8, n); - s -} + #[mem_builtin] + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] + pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + let delta = (dest as usize).wrapping_sub(src as usize); + if delta >= n { + // We can copy forwards because either dest is far enough ahead of src, + // or src is ahead of dest (and delta overflowed). + impls::copy_forward(dest, src, n); + } else { + impls::copy_backward(dest, src, n); + } + dest + } -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] -pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - let mut i = 0; - while i < n { - let a = *s1.add(i); - let b = *s2.add(i); - if a != b { - return a as i32 - b as i32; + #[mem_builtin] + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] + pub unsafe extern "C" fn memset(s: *mut u8, c: crate::mem::c_int, n: usize) -> *mut u8 { + impls::set_bytes(s, c as u8, n); + s + } + + #[mem_builtin] + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] + pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + let mut i = 0; + while i < n { + let a = *s1.add(i); + let b = *s2.add(i); + if a != b { + return a as i32 - b as i32; + } + i += 1; } - i += 1; + 0 } - 0 -} -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] -pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - memcmp(s1, s2, n) + #[mem_builtin] + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] + pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + memcmp(s1, s2, n) + } } // `bytes` must be a multiple of `mem::size_of::()` @@ -133,65 +135,65 @@ where intrinsics! { #[cfg(target_has_atomic_load_store = "8")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "16")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "32")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "64")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "128")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "8")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "16")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "32")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "64")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "128")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "8")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } #[cfg(target_has_atomic_load_store = "16")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_2(s: *mut u16, c: u8, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_2(s: *mut u16, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } #[cfg(target_has_atomic_load_store = "32")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_4(s: *mut u32, c: u8, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_4(s: *mut u32, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } #[cfg(target_has_atomic_load_store = "64")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } #[cfg(target_has_atomic_load_store = "128")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } } diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index abcc2bdb3d4..fd1f32e3a7d 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -8,82 +8,78 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca -#[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm"), - not(feature = "mangled-names") -))] -#[naked] -#[no_mangle] -pub unsafe extern "C" fn ___chkstk_ms() { - core::arch::asm!( - "push %ecx", - "push %eax", - "cmp $0x1000,%eax", - "lea 12(%esp),%ecx", - "jb 1f", - "2:", - "sub $0x1000,%ecx", - "test %ecx,(%ecx)", - "sub $0x1000,%eax", - "cmp $0x1000,%eax", - "ja 2b", - "1:", - "sub %eax,%ecx", - "test %ecx,(%ecx)", - "pop %eax", - "pop %ecx", - "ret", - options(noreturn, att_syntax) - ); -} +intrinsics! { + #[naked] + #[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn ___chkstk_ms() { + core::arch::asm!( + "push %ecx", + "push %eax", + "cmp $0x1000,%eax", + "lea 12(%esp),%ecx", + "jb 1f", + "2:", + "sub $0x1000,%ecx", + "test %ecx,(%ecx)", + "sub $0x1000,%eax", + "cmp $0x1000,%eax", + "ja 2b", + "1:", + "sub %eax,%ecx", + "test %ecx,(%ecx)", + "pop %eax", + "pop %ecx", + "ret", + options(noreturn, att_syntax) + ); + } -// FIXME: __alloca should be an alias to __chkstk -#[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm"), - not(feature = "mangled-names") -))] -#[naked] -#[no_mangle] -pub unsafe extern "C" fn __alloca() { - core::arch::asm!( - "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" - options(noreturn, att_syntax) - ); -} + // FIXME: __alloca should be an alias to __chkstk + #[naked] + #[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn __alloca() { + core::arch::asm!( + "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" + options(noreturn, att_syntax) + ); + } -#[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm"), - not(feature = "mangled-names") -))] -#[naked] -#[no_mangle] -pub unsafe extern "C" fn ___chkstk() { - core::arch::asm!( - "push %ecx", - "cmp $0x1000,%eax", - "lea 8(%esp),%ecx", // esp before calling this routine -> ecx - "jb 1f", - "2:", - "sub $0x1000,%ecx", - "test %ecx,(%ecx)", - "sub $0x1000,%eax", - "cmp $0x1000,%eax", - "ja 2b", - "1:", - "sub %eax,%ecx", - "test %ecx,(%ecx)", - "lea 4(%esp),%eax", // load pointer to the return address into eax - "mov %ecx,%esp", // install the new top of stack pointer into esp - "mov -4(%eax),%ecx", // restore ecx - "push (%eax)", // push return address onto the stack - "sub %esp,%eax", // restore the original value in eax - "ret", - options(noreturn, att_syntax) - ); + #[naked] + #[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn ___chkstk() { + core::arch::asm!( + "push %ecx", + "cmp $0x1000,%eax", + "lea 8(%esp),%ecx", // esp before calling this routine -> ecx + "jb 1f", + "2:", + "sub $0x1000,%ecx", + "test %ecx,(%ecx)", + "sub $0x1000,%eax", + "cmp $0x1000,%eax", + "ja 2b", + "1:", + "sub %eax,%ecx", + "test %ecx,(%ecx)", + "lea 4(%esp),%eax", // load pointer to the return address into eax + "mov %ecx,%esp", // install the new top of stack pointer into esp + "mov -4(%eax),%ecx", // restore ecx + "push (%eax)", // push return address onto the stack + "sub %esp,%eax", // restore the original value in eax + "ret", + options(noreturn, att_syntax) + ); + } } diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index ea3c9949790..393eeddd877 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -8,89 +8,87 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca -#[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm"), - not(feature = "mangled-names") -))] -#[naked] -#[no_mangle] -pub unsafe extern "C" fn ___chkstk_ms() { - core::arch::asm!( - "push %rcx", - "push %rax", - "cmp $0x1000,%rax", - "lea 24(%rsp),%rcx", - "jb 1f", - "2:", - "sub $0x1000,%rcx", - "test %rcx,(%rcx)", - "sub $0x1000,%rax", - "cmp $0x1000,%rax", - "ja 2b", - "1:", - "sub %rax,%rcx", - "test %rcx,(%rcx)", - "pop %rax", - "pop %rcx", - "ret", - options(noreturn, att_syntax) - ); -} +intrinsics! { + #[naked] + #[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn ___chkstk_ms() { + core::arch::asm!( + "push %rcx", + "push %rax", + "cmp $0x1000,%rax", + "lea 24(%rsp),%rcx", + "jb 1f", + "2:", + "sub $0x1000,%rcx", + "test %rcx,(%rcx)", + "sub $0x1000,%rax", + "cmp $0x1000,%rax", + "ja 2b", + "1:", + "sub %rax,%rcx", + "test %rcx,(%rcx)", + "pop %rax", + "pop %rcx", + "ret", + options(noreturn, att_syntax) + ); + } -#[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm"), - not(feature = "mangled-names") -))] -#[naked] -#[no_mangle] -pub unsafe extern "C" fn __alloca() { - core::arch::asm!( - "mov %rcx,%rax", // x64 _alloca is a normal function with parameter in rcx - "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" - options(noreturn, att_syntax) - ); -} + #[naked] + #[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn __alloca() { + core::arch::asm!( + "mov %rcx,%rax", // x64 _alloca is a normal function with parameter in rcx + "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" + options(noreturn, att_syntax) + ); + } -#[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm"), - not(feature = "mangled-names") -))] -#[naked] -#[no_mangle] -pub unsafe extern "C" fn ___chkstk() { - core::arch::asm!( - "push %rcx", - "cmp $0x1000,%rax", - "lea 16(%rsp),%rcx", // rsp before calling this routine -> rcx - "jb 1f", - "2:", - "sub $0x1000,%rcx", - "test %rcx,(%rcx)", - "sub $0x1000,%rax", - "cmp $0x1000,%rax", - "ja 2b", - "1:", - "sub %rax,%rcx", - "test %rcx,(%rcx)", - "lea 8(%rsp),%rax", // load pointer to the return address into rax - "mov %rcx,%rsp", // install the new top of stack pointer into rsp - "mov -8(%rax),%rcx", // restore rcx - "push (%rax)", // push return address onto the stack - "sub %rsp,%rax", // restore the original value in rax - "ret", - options(noreturn, att_syntax) - ); + #[naked] + #[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn ___chkstk() { + core::arch::asm!( + "push %rcx", + "cmp $0x1000,%rax", + "lea 16(%rsp),%rcx", // rsp before calling this routine -> rcx + "jb 1f", + "2:", + "sub $0x1000,%rcx", + "test %rcx,(%rcx)", + "sub $0x1000,%rax", + "cmp $0x1000,%rax", + "ja 2b", + "1:", + "sub %rax,%rcx", + "test %rcx,(%rcx)", + "lea 8(%rsp),%rax", // load pointer to the return address into rax + "mov %rcx,%rsp", // install the new top of stack pointer into rsp + "mov -8(%rax),%rcx", // restore rcx + "push (%rax)", // push return address onto the stack + "sub %rsp,%rax", // restore the original value in rax + "ret", + options(noreturn, att_syntax) + ); + } } // HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM // support unless we emit the _fltused -#[no_mangle] -#[used] -#[cfg(target_os = "uefi")] -static _fltused: i32 = 0; +mod _fltused { + #[no_mangle] + #[used] + #[cfg(target_os = "uefi")] + static _fltused: i32 = 0; +} -- cgit 1.4.1-3-g733a5 From 76f02fa2db306804d6f4d0d5c5de3fbf089564b4 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 6 Feb 2022 09:52:15 +0000 Subject: Bump to 0.2.2 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 3a6c5851b71..99055ad47b1 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.1" +version = "0.2.2" edition = "2018" [features] -- cgit 1.4.1-3-g733a5 From f34d42cf4909a4dca8cd7875fd1fe3903cf7ba6f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 6 Feb 2022 09:53:16 +0000 Subject: Update libm submodule to 0.2.2 --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index c2d22bf95e2..1f7b8eb61ca 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit c2d22bf95e2f032ae6b237e8e4c336bc795a151c +Subproject commit 1f7b8eb61cab5f62ec93d2343432bebd1ada30f2 -- cgit 1.4.1-3-g733a5 From 2f988a88ffdbd03a8d4c2904e1e4cd3323d4acf0 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 6 Feb 2022 09:59:11 +0000 Subject: Bump to 0.1.68 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index a8278f0b816..2ac4a6ba104 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.67" +version = "0.1.68" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 5bdeade2c4c4cea3d81ec219eaecf6e721e3b366 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 9 Feb 2022 20:54:39 +0000 Subject: Fix typo in __aeabi_uldivmod Accidentally introduced in #452 --- library/compiler-builtins/src/arm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 95bde511662..9c1b6ad123a 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -42,7 +42,7 @@ intrinsics! { "sub sp, sp, #16", "add r4, sp, #8", "str r4, [sp]", - bl!("__udivmodsi4"), + bl!("__udivmoddi4"), "ldr r2, [sp, #8]", "ldr r3, [sp, #12]", "add sp, sp, #16", -- cgit 1.4.1-3-g733a5 From e771805ee5a11e6e94d2463fa2e768069d2e258d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 9 Feb 2022 21:02:02 +0000 Subject: Bump to 0.1.69 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 2ac4a6ba104..491cc5a8299 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.68" +version = "0.1.69" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 0575846f80e894ddddd048b0c19ab63d7af15b44 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 13 Feb 2022 17:54:35 +0100 Subject: Handle Win64 builtins ABI change in LLVM 14 As of https://reviews.llvm.org/D110413, these no longer use the unadjusted ABI (and use normal C ABI instead, passing i128 indirectly and returning it as <2 x i64>). To support both LLVM 14 and older versions, rustc will expose a "llvm14-builtins-abi" target feature, based on which compiler-builtins can chose the appropriate ABI. This is needed for rust-lang/rust#93577. --- library/compiler-builtins/src/float/conv.rs | 116 +++++++++++++++++++--------- 1 file changed, 81 insertions(+), 35 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 8c46e4d2e7a..c0cee437328 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -109,16 +109,6 @@ intrinsics! { } } - #[unadjusted_on_win64] - pub extern "C" fn __floattisf(i: i128) -> f32 { - int_to_float(i) - } - - #[unadjusted_on_win64] - pub extern "C" fn __floattidf(i: i128) -> f64 { - int_to_float(i) - } - #[arm_aeabi_alias = __aeabi_ui2f] pub extern "C" fn __floatunsisf(i: u32) -> f32 { int_to_float(i) @@ -140,16 +130,6 @@ intrinsics! { pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float(i) } - - #[unadjusted_on_win64] - pub extern "C" fn __floatuntisf(i: u128) -> f32 { - int_to_float(i) - } - - #[unadjusted_on_win64] - pub extern "C" fn __floatuntidf(i: u128) -> f64 { - int_to_float(i) - } } fn float_to_int(f: F) -> I @@ -224,11 +204,6 @@ intrinsics! { float_to_int(f) } - #[unadjusted_on_win64] - pub extern "C" fn __fixsfti(f: f32) -> i128 { - float_to_int(f) - } - #[arm_aeabi_alias = __aeabi_d2iz] pub extern "C" fn __fixdfsi(f: f64) -> i32 { float_to_int(f) @@ -239,11 +214,6 @@ intrinsics! { float_to_int(f) } - #[unadjusted_on_win64] - pub extern "C" fn __fixdfti(f: f64) -> i128 { - float_to_int(f) - } - #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { float_to_int(f) @@ -254,11 +224,6 @@ intrinsics! { float_to_int(f) } - #[unadjusted_on_win64] - pub extern "C" fn __fixunssfti(f: f32) -> u128 { - float_to_int(f) - } - #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { float_to_int(f) @@ -268,6 +233,87 @@ intrinsics! { pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { float_to_int(f) } +} + +// The ABI for the following intrinsics changed in LLVM 14. On Win64, they now +// use Win64 ABI rather than unadjusted ABI. Pick the correct ABI based on the +// llvm14-builtins-abi target feature. + +#[cfg(target_feature = "llvm14-builtins-abi")] +intrinsics! { + pub extern "C" fn __floattisf(i: i128) -> f32 { + int_to_float(i) + } + + pub extern "C" fn __floattidf(i: i128) -> f64 { + int_to_float(i) + } + + pub extern "C" fn __floatuntisf(i: u128) -> f32 { + int_to_float(i) + } + + pub extern "C" fn __floatuntidf(i: u128) -> f64 { + int_to_float(i) + } + + #[win64_128bit_abi_hack] + pub extern "C" fn __fixsfti(f: f32) -> i128 { + float_to_int(f) + } + + #[win64_128bit_abi_hack] + pub extern "C" fn __fixdfti(f: f64) -> i128 { + float_to_int(f) + } + + #[win64_128bit_abi_hack] + pub extern "C" fn __fixunssfti(f: f32) -> u128 { + float_to_int(f) + } + + #[win64_128bit_abi_hack] + pub extern "C" fn __fixunsdfti(f: f64) -> u128 { + float_to_int(f) + } +} + +#[cfg(not(target_feature = "llvm14-builtins-abi"))] +intrinsics! { + #[unadjusted_on_win64] + pub extern "C" fn __floattisf(i: i128) -> f32 { + int_to_float(i) + } + + #[unadjusted_on_win64] + pub extern "C" fn __floattidf(i: i128) -> f64 { + int_to_float(i) + } + + #[unadjusted_on_win64] + pub extern "C" fn __floatuntisf(i: u128) -> f32 { + int_to_float(i) + } + + #[unadjusted_on_win64] + pub extern "C" fn __floatuntidf(i: u128) -> f64 { + int_to_float(i) + } + + #[unadjusted_on_win64] + pub extern "C" fn __fixsfti(f: f32) -> i128 { + float_to_int(f) + } + + #[unadjusted_on_win64] + pub extern "C" fn __fixdfti(f: f64) -> i128 { + float_to_int(f) + } + + #[unadjusted_on_win64] + pub extern "C" fn __fixunssfti(f: f32) -> u128 { + float_to_int(f) + } #[unadjusted_on_win64] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { -- cgit 1.4.1-3-g733a5 From 96339ec86d42f31388028c452b5cbb132534771f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 16 Feb 2022 01:18:05 +0000 Subject: Bump to 0.1.70 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 491cc5a8299..80e118a9478 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.69" +version = "0.1.70" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 002fc52f002d7ef62665e756c741bb3feb9e808f Mon Sep 17 00:00:00 2001 From: Vladimir Michael Eatwell Date: Thu, 17 Jun 2021 17:40:45 +0100 Subject: [watch_os] add watchOS --- library/compiler-builtins/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2b34540dc44..c8b77001112 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -241,7 +241,7 @@ mod c { // On iOS and 32-bit OSX these are all just empty intrinsics, no need to // include them. - if target_os != "ios" && (target_vendor != "apple" || target_arch != "x86") { + if target_os != "ios" && target_os != "watchos" && (target_vendor != "apple" || target_arch != "x86") { sources.extend(&[ ("__absvti2", "absvti2.c"), ("__addvti3", "addvti3.c"), @@ -318,7 +318,7 @@ mod c { } } - if target_arch == "arm" && target_os != "ios" && target_env != "msvc" { + if target_arch == "arm" && target_os != "ios" && target_os != "watchos" && target_env != "msvc" { sources.extend(&[ ("__aeabi_div0", "arm/aeabi_div0.c"), ("__aeabi_drsub", "arm/aeabi_drsub.c"), -- cgit 1.4.1-3-g733a5 From 50c5587f82f590553df41831629e4f494d016d16 Mon Sep 17 00:00:00 2001 From: Vladimir Michael Eatwell Date: Tue, 8 Mar 2022 10:18:07 +0000 Subject: [watch_os] Fix formatting --- library/compiler-builtins/build.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index c8b77001112..d811fc5cb45 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -241,7 +241,10 @@ mod c { // On iOS and 32-bit OSX these are all just empty intrinsics, no need to // include them. - if target_os != "ios" && target_os != "watchos" && (target_vendor != "apple" || target_arch != "x86") { + if target_os != "ios" + && target_os != "watchos" + && (target_vendor != "apple" || target_arch != "x86") + { sources.extend(&[ ("__absvti2", "absvti2.c"), ("__addvti3", "addvti3.c"), @@ -318,7 +321,11 @@ mod c { } } - if target_arch == "arm" && target_os != "ios" && target_os != "watchos" && target_env != "msvc" { + if target_arch == "arm" + && target_os != "ios" + && target_os != "watchos" + && target_env != "msvc" + { sources.extend(&[ ("__aeabi_div0", "arm/aeabi_div0.c"), ("__aeabi_drsub", "arm/aeabi_drsub.c"), -- cgit 1.4.1-3-g733a5 From 7f535824f5ebeb0774d6c3185e89cf76a3a5d65e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 18 Mar 2022 18:18:28 +0300 Subject: Provide an implementation of `strlen` to be used as a fallback --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/mem/mod.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index c3eefbc0362..9ca72bc20f4 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -4,6 +4,7 @@ #![cfg_attr(not(feature = "no-asm"), feature(global_asm))] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] +#![feature(core_ffi_c)] #![feature(core_intrinsics)] #![feature(lang_items)] #![feature(linkage)] diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index dce4d87e0a5..a551138612b 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -68,6 +68,18 @@ intrinsics! { pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { memcmp(s1, s2, n) } + + #[mem_builtin] + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] + pub unsafe extern "C" fn strlen(s: *const core::ffi::c_char) -> usize { + let mut n = 0; + let mut s = s; + while *s != 0 { + n += 1; + s = s.offset(1); + } + n + } } // `bytes` must be a multiple of `mem::size_of::()` -- cgit 1.4.1-3-g733a5 From 8abefcd926c9d4e9261c286cac923c7deef30f5a Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 18 Mar 2022 20:12:07 +0000 Subject: Bump to 0.1.71 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 80e118a9478..8c49b8c9e8f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.70" +version = "0.1.71" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From c491ca7ec58cab3e40e48f28d7dee651f5e3119f Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Tue, 22 Mar 2022 19:06:50 -0700 Subject: Build emutls.c on Android. Android uses emulated TLS so we need a runtime support function from this source file. --- library/compiler-builtins/build.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d811fc5cb45..e199124b26d 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -489,6 +489,16 @@ mod c { sources.remove(&["__aeabi_cdcmp", "__aeabi_cfcmp"]); } + // Android uses emulated TLS so we need a runtime support function. + if target_os == "android" { + sources.extend(&[("__emutls_get_address", "emutls.c")]); + + // Work around a bug in the NDK headers (fixed in + // https://r.android.com/2038949 which will be released in a future + // NDK version) by providing a definition of LONG_BIT. + cfg.define("LONG_BIT", "(8 * sizeof(long))"); + } + // When compiling the C code we require the user to tell us where the // source code is, and this is largely done so when we're compiling as // part of rust-lang/rust we can use the same llvm-project repository as -- cgit 1.4.1-3-g733a5 From c307915e7850b82ac25b8a1f1598bf05d725b998 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 30 Mar 2022 19:39:47 +0100 Subject: Bump to 0.1.72 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 8c49b8c9e8f..99f2947242d 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.71" +version = "0.1.72" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 10971912e87e0ab10e1f7c6e9da8086f11ced68a Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Mon, 2 May 2022 23:00:12 +0200 Subject: rv64 implement muldi3 intrinsic Implement the __muldi3 intrinsic to prevent infinite recursion during multiplication on rv64 without the 'm' extension. --- library/compiler-builtins/src/int/mul.rs | 1 + library/compiler-builtins/src/lib.rs | 4 ++-- library/compiler-builtins/src/riscv.rs | 35 ++++++++++++++++++++++++++++++++ library/compiler-builtins/src/riscv32.rs | 18 ---------------- 4 files changed, 38 insertions(+), 20 deletions(-) create mode 100644 library/compiler-builtins/src/riscv.rs delete mode 100644 library/compiler-builtins/src/riscv32.rs diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index a5238eeac70..37eb03ec054 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -100,6 +100,7 @@ impl_signed_mulo!(i128_overflowing_mul, i128, u128); intrinsics! { #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lmul] + #[cfg(not(target_arch = "riscv64"))] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { a.mul(b) } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 9ca72bc20f4..009923d27e5 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -60,8 +60,8 @@ pub mod arm; ))] pub mod arm_linux; -#[cfg(any(target_arch = "riscv32"))] -pub mod riscv32; +#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] +pub mod riscv; #[cfg(target_arch = "x86")] pub mod x86; diff --git a/library/compiler-builtins/src/riscv.rs b/library/compiler-builtins/src/riscv.rs new file mode 100644 index 00000000000..d9a65e20074 --- /dev/null +++ b/library/compiler-builtins/src/riscv.rs @@ -0,0 +1,35 @@ +intrinsics! { + // Implementation from gcc + // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c + #[cfg(target_arch = "riscv32")] + pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { + let (mut a, mut b) = (a, b); + let mut r = 0; + + while a > 0 { + if a & 1 > 0 { + r += b; + } + a >>= 1; + b <<= 1; + } + + r + } + + #[cfg(target_arch = "riscv64")] + pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { + let (mut a, mut b) = (a, b); + let mut r = 0; + + while a > 0 { + if a & 1 > 0 { + r += b; + } + a >>= 1; + b <<= 1; + } + + r + } +} diff --git a/library/compiler-builtins/src/riscv32.rs b/library/compiler-builtins/src/riscv32.rs deleted file mode 100644 index 9a3c1714c1f..00000000000 --- a/library/compiler-builtins/src/riscv32.rs +++ /dev/null @@ -1,18 +0,0 @@ -intrinsics! { - // Implementation from gcc - // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c - pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { - let (mut a, mut b) = (a, b); - let mut r = 0; - - while a > 0 { - if a & 1 > 0 { - r += b; - } - a >>= 1; - b <<= 1; - } - - r - } -} -- cgit 1.4.1-3-g733a5 From 7d79662fd1d81932ffa6feffafbf384417a82189 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 2 May 2022 16:05:03 -0700 Subject: Remove apple_versioning.c inclusion According to the README this file isn't used by rust, but it's currently included which leads to these linker warnings in some cases: ``` ld: warning: linker symbol '$ld$hide$os10.5$___udivti3' hides a non-existent symbol '___udivti3' ld: warning: linker symbol '$ld$hide$os10.4$___umoddi3' hides a non-existent symbol '___umoddi3' ld: warning: linker symbol '$ld$hide$os10.5$___umoddi3' hides a non-existent symbol '___umoddi3' ld: warning: linker symbol '$ld$hide$os10.4$___umodti3' hides a non-existent symbol '___umodti3' ld: warning: linker symbol '$ld$hide$os10.5$___umodti3' hides a non-existent symbol '___umodti3' ``` This file exclusively contains macros which hides old symbols on Apple OS versions where they don't exist. https://github.com/rust-lang/llvm-project/blob/fc10370ef7d91babf512c10505f8f2176bc8519d/compiler-rt/lib/builtins/apple_versioning.c --- library/compiler-builtins/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e199124b26d..a1bcf2ea1fc 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -193,7 +193,6 @@ mod c { ("__absvsi2", "absvsi2.c"), ("__addvdi3", "addvdi3.c"), ("__addvsi3", "addvsi3.c"), - ("apple_versioning", "apple_versioning.c"), ("__clzdi2", "clzdi2.c"), ("__clzsi2", "clzsi2.c"), ("__cmpdi2", "cmpdi2.c"), -- cgit 1.4.1-3-g733a5 From 65ec71d38687ee2338129622e97f249fa2402196 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Thu, 12 May 2022 00:34:49 +0200 Subject: rv32 rv64: adapt conditional compilation Adapt conditional compilation as: rv32i : riscv:__mulsi3, riscv:__muldi3 rv32im: riscv:__mulsi3, int/mul:__muldi3 rv64i : riscv:__mulsi3, riscv:__muldi3 rv64im: riscv:__mulsi3, int/mul:__muldi3 --- library/compiler-builtins/src/int/mul.rs | 2 +- library/compiler-builtins/src/riscv.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 37eb03ec054..07ce061c994 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -100,7 +100,7 @@ impl_signed_mulo!(i128_overflowing_mul, i128, u128); intrinsics! { #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lmul] - #[cfg(not(target_arch = "riscv64"))] + #[cfg(any(not(any(target_arch = "riscv32", target_arch = "riscv64")), target_feature = "m"))] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { a.mul(b) } diff --git a/library/compiler-builtins/src/riscv.rs b/library/compiler-builtins/src/riscv.rs index d9a65e20074..ee78b9dbacf 100644 --- a/library/compiler-builtins/src/riscv.rs +++ b/library/compiler-builtins/src/riscv.rs @@ -1,7 +1,6 @@ intrinsics! { // Implementation from gcc // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c - #[cfg(target_arch = "riscv32")] pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { let (mut a, mut b) = (a, b); let mut r = 0; @@ -17,7 +16,7 @@ intrinsics! { r } - #[cfg(target_arch = "riscv64")] + #[cfg(not(target_feature = "m"))] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { let (mut a, mut b) = (a, b); let mut r = 0; -- cgit 1.4.1-3-g733a5 From a695a800d542d7a0fac55ec8ee2eb5ea926389e2 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Sun, 15 May 2022 12:58:38 +0200 Subject: Fix division on AVRs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For division and modulo, AVR uses a custom calling convention that does not match compiler_builtins' expectations, leading to non-working code¹. Ideally we'd just use hand-written naked functions (as, afair, ARM does), but that's a lot of code to port², so hopefully we'll be able to do it gradually later. For the time being, I'd suggest not compiling problematic functions for AVR target - this causes avr-gcc (which is a mandatory part of Rust+AVR toolchain anyway) to link hand-written assembly from libgcc, which is confirmed to work. I've tested the code locally on simavr and the patch seems to be working correctly :-) ¹ https://github.com/rust-lang/rust/issues/82242, https://github.com/rust-lang/rust/issues/83281 ² https://github.com/gcc-mirror/gcc/blob/31048012db98f5ec9c2ba537bfd850374bdd771f/libgcc/config/avr/lib1funcs.S Closes https://github.com/rust-lang/rust/issues/82242 Closes https://github.com/rust-lang/rust/issues/83281 --- library/compiler-builtins/src/int/sdiv.rs | 3 +++ library/compiler-builtins/src/int/udiv.rs | 5 +++++ library/compiler-builtins/src/macros.rs | 31 ++++++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index e1e3f33bbd0..f1822f0f86e 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -9,6 +9,7 @@ macro_rules! sdivmod { $($attr:tt),* // attributes ) => { intrinsics! { + #[avr_skip] $( #[$attr] )* @@ -50,6 +51,7 @@ macro_rules! sdiv { $($attr:tt),* // attributes ) => { intrinsics! { + #[avr_skip] $( #[$attr] )* @@ -85,6 +87,7 @@ macro_rules! smod { $($attr:tt),* // attributes ) => { intrinsics! { + #[avr_skip] $( #[$attr] )* diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 2f236346d3d..c5ef4a6b197 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -18,6 +18,7 @@ intrinsics! { u32_div_rem(n, d).1 } + #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { @@ -28,18 +29,21 @@ intrinsics! { quo_rem.0 } + #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n / d` pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { u64_div_rem(n, d).0 } + #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { u64_div_rem(n, d).1 } + #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { @@ -77,6 +81,7 @@ intrinsics! { } } + #[avr_skip] #[win64_128bit_abi_hack] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 6926feac055..4c1d8af6281 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -82,7 +82,6 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg($name = "optimized-c")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { extern $abi { @@ -304,6 +303,36 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // For division and modulo, AVR uses a custom calling convention¹ that does + // not match our definitions here. Ideally we would just use hand-written + // naked functions, but that's quite a lot of code to port² - so for the + // time being we are just ignoring the problematic functions, letting + // avr-gcc (which is required to compile to AVR anyway) link them from + // libgcc. + // + // ¹ https://gcc.gnu.org/wiki/avr-gcc (see "Exceptions to the Calling + // Convention") + // ² https://github.com/gcc-mirror/gcc/blob/31048012db98f5ec9c2ba537bfd850374bdd771f/libgcc/config/avr/lib1funcs.S + ( + #[avr_skip] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(not(target_arch = "avr"))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + // This is the final catch-all rule. At this point we generate an // intrinsic with a conditional `#[no_mangle]` directive to avoid // interfering with duplicate symbols and whatnot during testing. -- cgit 1.4.1-3-g733a5 From 2063e07b353fe5d675a986351228278ec7244f14 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 20 May 2022 14:43:16 +0200 Subject: Support cfg_attr attributes in intrinsics!() macro. --- library/compiler-builtins/src/macros.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 6926feac055..22d82e3fab9 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -61,6 +61,35 @@ macro_rules! public_test_dep { macro_rules! intrinsics { () => (); + // Support cfg_attr: + ( + #[cfg_attr($e:meta, $($attr:tt)*)] + $(#[$($attrs:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + $($rest:tt)* + ) => ( + #[cfg($e)] + intrinsics! { + #[$($attr)*] + $(#[$($attrs)*])* + pub extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { + $($body)* + } + } + + #[cfg(not($e))] + intrinsics! { + $(#[$($attrs)*])* + pub extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + // Right now there's a bunch of architecture-optimized intrinsics in the // stock compiler-rt implementation. Not all of these have been ported over // to Rust yet so when the `c` feature of this crate is enabled we fall back -- cgit 1.4.1-3-g733a5 From 7ed26a7e7a32f7124d2ccf9004ab820a0766c2a6 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 20 May 2022 14:43:34 +0200 Subject: De-duplicate 128 bit float conv intrinsics using cfg_attr. --- library/compiler-builtins/src/float/conv.rs | 60 ++++++----------------------- 1 file changed, 12 insertions(+), 48 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index c0cee437328..0e21a1ed3bf 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -239,83 +239,47 @@ intrinsics! { // use Win64 ABI rather than unadjusted ABI. Pick the correct ABI based on the // llvm14-builtins-abi target feature. -#[cfg(target_feature = "llvm14-builtins-abi")] intrinsics! { + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __floattisf(i: i128) -> f32 { int_to_float(i) } + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __floattidf(i: i128) -> f64 { int_to_float(i) } + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __floatuntisf(i: u128) -> f32 { int_to_float(i) } + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __floatuntidf(i: u128) -> f64 { int_to_float(i) } - #[win64_128bit_abi_hack] + #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __fixsfti(f: f32) -> i128 { float_to_int(f) } - #[win64_128bit_abi_hack] + #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __fixdfti(f: f64) -> i128 { float_to_int(f) } - #[win64_128bit_abi_hack] + #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __fixunssfti(f: f32) -> u128 { float_to_int(f) } - #[win64_128bit_abi_hack] - pub extern "C" fn __fixunsdfti(f: f64) -> u128 { - float_to_int(f) - } -} - -#[cfg(not(target_feature = "llvm14-builtins-abi"))] -intrinsics! { - #[unadjusted_on_win64] - pub extern "C" fn __floattisf(i: i128) -> f32 { - int_to_float(i) - } - - #[unadjusted_on_win64] - pub extern "C" fn __floattidf(i: i128) -> f64 { - int_to_float(i) - } - - #[unadjusted_on_win64] - pub extern "C" fn __floatuntisf(i: u128) -> f32 { - int_to_float(i) - } - - #[unadjusted_on_win64] - pub extern "C" fn __floatuntidf(i: u128) -> f64 { - int_to_float(i) - } - - #[unadjusted_on_win64] - pub extern "C" fn __fixsfti(f: f32) -> i128 { - float_to_int(f) - } - - #[unadjusted_on_win64] - pub extern "C" fn __fixdfti(f: f64) -> i128 { - float_to_int(f) - } - - #[unadjusted_on_win64] - pub extern "C" fn __fixunssfti(f: f32) -> u128 { - float_to_int(f) - } - - #[unadjusted_on_win64] + #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { float_to_int(f) } -- cgit 1.4.1-3-g733a5 From 425c78ee7a71ebfa6a43eb7df2be58b656e7b7af Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 20 May 2022 16:25:18 +0200 Subject: Faster int<->float conversions. --- library/compiler-builtins/build.rs | 12 +- library/compiler-builtins/src/float/conv.rs | 481 ++++++++++++++++------------ 2 files changed, 274 insertions(+), 219 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e199124b26d..3868510bea5 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -281,10 +281,7 @@ mod c { if target_env == "msvc" { if target_arch == "x86_64" { - sources.extend(&[ - ("__floatdisf", "x86_64/floatdisf.c"), - ("__floatdixf", "x86_64/floatdixf.c"), - ]); + sources.extend(&[("__floatdixf", "x86_64/floatdixf.c")]); } } else { // None of these seem to be used on x86_64 windows, and they've all @@ -292,10 +289,7 @@ mod c { if target_os != "windows" { if target_arch == "x86_64" { sources.extend(&[ - ("__floatdisf", "x86_64/floatdisf.c"), ("__floatdixf", "x86_64/floatdixf.c"), - ("__floatundidf", "x86_64/floatundidf.S"), - ("__floatundisf", "x86_64/floatundisf.S"), ("__floatundixf", "x86_64/floatundixf.S"), ]); } @@ -306,11 +300,7 @@ mod c { ("__ashldi3", "i386/ashldi3.S"), ("__ashrdi3", "i386/ashrdi3.S"), ("__divdi3", "i386/divdi3.S"), - ("__floatdidf", "i386/floatdidf.S"), - ("__floatdisf", "i386/floatdisf.S"), ("__floatdixf", "i386/floatdixf.S"), - ("__floatundidf", "i386/floatundidf.S"), - ("__floatundisf", "i386/floatundisf.S"), ("__floatundixf", "i386/floatundixf.S"), ("__lshrdi3", "i386/lshrdi3.S"), ("__moddi3", "i386/moddi3.S"), diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 0e21a1ed3bf..86847ed6c79 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,286 +1,351 @@ -use float::Float; -use int::{CastInto, Int}; - -fn int_to_float(i: I) -> F -where - F::Int: CastInto, - F::Int: CastInto, - I::UnsignedInt: CastInto, - u32: CastInto, -{ - if i == I::ZERO { - return F::ZERO; - } - - let two = I::UnsignedInt::ONE + I::UnsignedInt::ONE; - let four = two + two; - let sign = i < I::ZERO; - let mut x = Int::abs_diff(i, I::ZERO); - - // number of significant digits in the integer - let i_sd = I::BITS - x.leading_zeros(); - // significant digits for the float, including implicit bit - let f_sd = F::SIGNIFICAND_BITS + 1; - - // exponent - let mut exp = i_sd - 1; - - if I::BITS < f_sd { - return F::from_parts( - sign, - (exp + F::EXPONENT_BIAS).cast(), - x.cast() << (f_sd - exp - 1), - ); +/// Conversions from integers to floats. +/// +/// These are hand-optimized bit twiddling code, +/// which unfortunately isn't the easiest kind of code to read. +/// +/// The algorithm is explained here: https://blog.m-ou.se/floats/ +mod int_to_float { + pub fn u32_to_f32_bits(i: u32) -> u32 { + if i == 0 { + return 0; + } + let n = i.leading_zeros(); + let a = i << n >> 8; // Significant bits, with bit 24 still in tact. + let b = i << n << 24; // Insignificant bits, only relevant for rounding. + let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. + let e = 157 - n as u32; // Exponent plus 127, minus one. + (e << 23) + m // + not |, so the mantissa can overflow into the exponent. } - x = if i_sd > f_sd { - // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx - // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR - // 12345678901234567890123456 - // 1 = the implicit bit - // P = bit f_sd-1 bits to the right of 1 - // Q = bit f_sd bits to the right of 1 - // R = "or" of all bits to the right of Q - let f_sd_add2 = f_sd + 2; - x = if i_sd == (f_sd + 1) { - x << 1 - } else if i_sd == f_sd_add2 { - x - } else { - (x >> (i_sd - f_sd_add2)) - | Int::from_bool( - (x & I::UnsignedInt::MAX).wrapping_shl((I::BITS + f_sd_add2) - i_sd) - != Int::ZERO, - ) - }; - - // R |= P - x |= Int::from_bool((x & four) != I::UnsignedInt::ZERO); - // round - this step may add a significant bit - x += Int::ONE; - // dump Q and R - x >>= 2; - - // a is now rounded to f_sd or f_sd+1 bits - if (x & (I::UnsignedInt::ONE << f_sd)) != Int::ZERO { - x >>= 1; - exp += 1; + pub fn u32_to_f64_bits(i: u32) -> u64 { + if i == 0 { + return 0; } - x - } else { - x.wrapping_shl(f_sd - i_sd) - }; - - F::from_parts(sign, (exp + F::EXPONENT_BIAS).cast(), x.cast()) -} - -intrinsics! { - #[arm_aeabi_alias = __aeabi_i2f] - pub extern "C" fn __floatsisf(i: i32) -> f32 { - int_to_float(i) + let n = i.leading_zeros(); + let m = (i as u64) << (21 + n); // Significant bits, with bit 53 still in tact. + let e = 1053 - n as u64; // Exponent plus 1023, minus one. + (e << 52) + m // Bit 53 of m will overflow into e. } - #[arm_aeabi_alias = __aeabi_i2d] - pub extern "C" fn __floatsidf(i: i32) -> f64 { - int_to_float(i) + pub fn u64_to_f32_bits(i: u64) -> u32 { + let n = i.leading_zeros(); + let y = i.wrapping_shl(n); + let a = (y >> 40) as u32; // Significant bits, with bit 24 still in tact. + let b = (y >> 8 | y & 0xFFFF) as u32; // Insignificant bits, only relevant for rounding. + let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. + let e = if i == 0 { 0 } else { 189 - n }; // Exponent plus 127, minus one, except for zero. + (e << 23) + m // + not |, so the mantissa can overflow into the exponent. } - #[maybe_use_optimized_c_shim] - #[arm_aeabi_alias = __aeabi_l2f] - pub extern "C" fn __floatdisf(i: i64) -> f32 { - // On x86_64 LLVM will use native instructions for this conversion, we - // can just do it directly - if cfg!(target_arch = "x86_64") { - i as f32 - } else { - int_to_float(i) + pub fn u64_to_f64_bits(i: u64) -> u64 { + if i == 0 { + return 0; } + let n = i.leading_zeros(); + let a = (i << n >> 11) as u64; // Significant bits, with bit 53 still in tact. + let b = (i << n << 53) as u64; // Insignificant bits, only relevant for rounding. + let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even. + let e = 1085 - n as u64; // Exponent plus 1023, minus one. + (e << 52) + m // + not |, so the mantissa can overflow into the exponent. } - #[maybe_use_optimized_c_shim] - #[arm_aeabi_alias = __aeabi_l2d] - pub extern "C" fn __floatdidf(i: i64) -> f64 { - // On x86_64 LLVM will use native instructions for this conversion, we - // can just do it directly - if cfg!(target_arch = "x86_64") { - i as f64 - } else { - int_to_float(i) - } + pub fn u128_to_f32_bits(i: u128) -> u32 { + let n = i.leading_zeros(); + let y = i.wrapping_shl(n); + let a = (y >> 104) as u32; // Significant bits, with bit 24 still in tact. + let b = (y >> 72) as u32 | (y << 32 >> 32 != 0) as u32; // Insignificant bits, only relevant for rounding. + let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. + let e = if i == 0 { 0 } else { 253 - n }; // Exponent plus 127, minus one, except for zero. + (e << 23) + m // + not |, so the mantissa can overflow into the exponent. + } + + pub fn u128_to_f64_bits(i: u128) -> u64 { + let n = i.leading_zeros(); + let y = i.wrapping_shl(n); + let a = (y >> 75) as u64; // Significant bits, with bit 53 still in tact. + let b = (y >> 11 | y & 0xFFFF_FFFF) as u64; // Insignificant bits, only relevant for rounding. + let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even. + let e = if i == 0 { 0 } else { 1149 - n as u64 }; // Exponent plus 1023, minus one, except for zero. + (e << 52) + m // + not |, so the mantissa can overflow into the exponent. } +} +// Conversions from unsigned integers to floats. +intrinsics! { #[arm_aeabi_alias = __aeabi_ui2f] pub extern "C" fn __floatunsisf(i: u32) -> f32 { - int_to_float(i) + f32::from_bits(int_to_float::u32_to_f32_bits(i)) } #[arm_aeabi_alias = __aeabi_ui2d] pub extern "C" fn __floatunsidf(i: u32) -> f64 { - int_to_float(i) + f64::from_bits(int_to_float::u32_to_f64_bits(i)) } - #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_ul2f] pub extern "C" fn __floatundisf(i: u64) -> f32 { - int_to_float(i) + f32::from_bits(int_to_float::u64_to_f32_bits(i)) } - #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { - int_to_float(i) + f64::from_bits(int_to_float::u64_to_f64_bits(i)) } -} - -fn float_to_int(f: F) -> I -where - F::ExpInt: CastInto, - u32: CastInto, - F::Int: CastInto, -{ - // converting NaNs is UB, so we don't consider them - let sign = f.sign(); - let mut exp = f.exp(); - - // if less than one or unsigned & negative - if (exp < F::EXPONENT_BIAS.cast()) || (!I::SIGNED && sign) { - return I::ZERO; + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + pub extern "C" fn __floatuntisf(i: u128) -> f32 { + f32::from_bits(int_to_float::u128_to_f32_bits(i)) } - exp -= F::EXPONENT_BIAS.cast(); - - // If the value is too large for `I`, saturate. - let bits: F::ExpInt = I::BITS.cast(); - let max = if I::SIGNED { - bits - F::ExpInt::ONE - } else { - bits - }; - if max <= exp { - return if sign { - // It happens that I::MIN is handled correctly - I::MIN - } else { - I::MAX - }; - }; - // `0 <= exp < max` - - // If 0 <= exponent < F::SIGNIFICAND_BITS, right shift to get the result. Otherwise, shift left. - let sig_bits: F::ExpInt = F::SIGNIFICAND_BITS.cast(); - // The larger integer has to be casted into, or else the shift overflows - let r: I = if F::Int::BITS < I::BITS { - let tmp: I = if exp < sig_bits { - f.imp_frac().cast() >> (sig_bits - exp).cast() - } else { - f.imp_frac().cast() << (exp - sig_bits).cast() - }; - tmp - } else { - let tmp: F::Int = if exp < sig_bits { - f.imp_frac() >> (sig_bits - exp).cast() - } else { - f.imp_frac() << (exp - sig_bits).cast() - }; - tmp.cast() - }; - - if sign { - r.wrapping_neg() - } else { - r + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + pub extern "C" fn __floatuntidf(i: u128) -> f64 { + f64::from_bits(int_to_float::u128_to_f64_bits(i)) } } +// Conversions from signed integers to floats. intrinsics! { - #[arm_aeabi_alias = __aeabi_f2iz] - pub extern "C" fn __fixsfsi(f: f32) -> i32 { - float_to_int(f) + #[arm_aeabi_alias = __aeabi_i2f] + pub extern "C" fn __floatsisf(i: i32) -> f32 { + let sign_bit = ((i >> 31) as u32) << 31; + f32::from_bits(int_to_float::u32_to_f32_bits(i.unsigned_abs()) | sign_bit) } - #[arm_aeabi_alias = __aeabi_f2lz] - pub extern "C" fn __fixsfdi(f: f32) -> i64 { - float_to_int(f) + #[arm_aeabi_alias = __aeabi_i2d] + pub extern "C" fn __floatsidf(i: i32) -> f64 { + let sign_bit = ((i >> 31) as u64) << 63; + f64::from_bits(int_to_float::u32_to_f64_bits(i.unsigned_abs()) | sign_bit) } - #[arm_aeabi_alias = __aeabi_d2iz] - pub extern "C" fn __fixdfsi(f: f64) -> i32 { - float_to_int(f) + #[arm_aeabi_alias = __aeabi_l2f] + pub extern "C" fn __floatdisf(i: i64) -> f32 { + let sign_bit = ((i >> 63) as u32) << 31; + f32::from_bits(int_to_float::u64_to_f32_bits(i.unsigned_abs()) | sign_bit) } - #[arm_aeabi_alias = __aeabi_d2lz] - pub extern "C" fn __fixdfdi(f: f64) -> i64 { - float_to_int(f) + #[arm_aeabi_alias = __aeabi_l2d] + pub extern "C" fn __floatdidf(i: i64) -> f64 { + let sign_bit = ((i >> 63) as u64) << 63; + f64::from_bits(int_to_float::u64_to_f64_bits(i.unsigned_abs()) | sign_bit) + } + + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + pub extern "C" fn __floattisf(i: i128) -> f32 { + let sign_bit = ((i >> 127) as u32) << 31; + f32::from_bits(int_to_float::u128_to_f32_bits(i.unsigned_abs()) | sign_bit) } + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + pub extern "C" fn __floattidf(i: i128) -> f64 { + let sign_bit = ((i >> 127) as u64) << 63; + f64::from_bits(int_to_float::u128_to_f64_bits(i.unsigned_abs()) | sign_bit) + } +} + +// Conversions from floats to unsigned integers. +intrinsics! { #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { - float_to_int(f) + let fbits = f.to_bits(); + if fbits < 127 << 23 { // >= 0, < 1 + 0 + } else if fbits < 159 << 23 { // >= 1, < max + let m = 1 << 31 | fbits << 8; // Mantissa and the implicit 1-bit. + let s = 158 - (fbits >> 23); // Shift based on the exponent and bias. + m >> s + } else if fbits <= 255 << 23 { // >= max (incl. inf) + u32::MAX + } else { // Negative or NaN + 0 + } } #[arm_aeabi_alias = __aeabi_f2ulz] pub extern "C" fn __fixunssfdi(f: f32) -> u64 { - float_to_int(f) + let fbits = f.to_bits(); + if fbits < 127 << 23 { // >= 0, < 1 + 0 + } else if fbits < 191 << 23 { // >= 1, < max + let m = 1 << 63 | (fbits as u64) << 40; // Mantissa and the implicit 1-bit. + let s = 190 - (fbits >> 23); // Shift based on the exponent and bias. + m >> s + } else if fbits <= 255 << 23 { // >= max (incl. inf) + u64::MAX + } else { // Negative or NaN + 0 + } + } + + #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + pub extern "C" fn __fixunssfti(f: f32) -> u128 { + let fbits = f.to_bits(); + if fbits < 127 << 23 { // >= 0, < 1 + 0 + } else if fbits < 255 << 23 { // >= 1, < inf + let m = 1 << 127 | (fbits as u128) << 104; // Mantissa and the implicit 1-bit. + let s = 254 - (fbits >> 23); // Shift based on the exponent and bias. + m >> s + } else if fbits == 255 << 23 { // == inf + u128::MAX + } else { // Negative or NaN + 0 + } } #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { - float_to_int(f) + let fbits = f.to_bits(); + if fbits < 1023 << 52 { // >= 0, < 1 + 0 + } else if fbits < 1055 << 52 { // >= 1, < max + let m = 1 << 31 | (fbits >> 21) as u32; // Mantissa and the implicit 1-bit. + let s = 1054 - (fbits >> 52); // Shift based on the exponent and bias. + m >> s + } else if fbits <= 2047 << 52 { // >= max (incl. inf) + u32::MAX + } else { // Negative or NaN + 0 + } } #[arm_aeabi_alias = __aeabi_d2ulz] pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { - float_to_int(f) - } -} - -// The ABI for the following intrinsics changed in LLVM 14. On Win64, they now -// use Win64 ABI rather than unadjusted ABI. Pick the correct ABI based on the -// llvm14-builtins-abi target feature. - -intrinsics! { - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] - pub extern "C" fn __floattisf(i: i128) -> f32 { - int_to_float(i) + let fbits = f.to_bits(); + if fbits < 1023 << 52 { // >= 0, < 1 + 0 + } else if fbits < 1087 << 52 { // >= 1, < max + let m = 1 << 63 | fbits << 11; // Mantissa and the implicit 1-bit. + let s = 1086 - (fbits >> 52); // Shift based on the exponent and bias. + m >> s + } else if fbits <= 2047 << 52 { // >= max (incl. inf) + u64::MAX + } else { // Negative or NaN + 0 + } } + #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] - pub extern "C" fn __floattidf(i: i128) -> f64 { - int_to_float(i) + pub extern "C" fn __fixunsdfti(f: f64) -> u128 { + let fbits = f.to_bits(); + if fbits < 1023 << 52 { // >= 0, < 1 + 0 + } else if fbits < 1151 << 52 { // >= 1, < max + let m = 1 << 127 | (fbits as u128) << 75; // Mantissa and the implicit 1-bit. + let s = 1150 - (fbits >> 52); // Shift based on the exponent and bias. + m >> s + } else if fbits <= 2047 << 52 { // >= max (incl. inf) + u128::MAX + } else { // Negative or NaN + 0 + } } +} - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] - pub extern "C" fn __floatuntisf(i: u128) -> f32 { - int_to_float(i) +// Conversions from floats to signed integers. +intrinsics! { + #[arm_aeabi_alias = __aeabi_f2iz] + pub extern "C" fn __fixsfsi(f: f32) -> i32 { + let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. + if fbits < 127 << 23 { // >= 0, < 1 + 0 + } else if fbits < 158 << 23 { // >= 1, < max + let m = 1 << 31 | fbits << 8; // Mantissa and the implicit 1-bit. + let s = 158 - (fbits >> 23); // Shift based on the exponent and bias. + let u = (m >> s) as i32; // Unsigned result. + if f.is_sign_negative() { -u } else { u } + } else if fbits <= 255 << 23 { // >= max (incl. inf) + if f.is_sign_negative() { i32::MIN } else { i32::MAX } + } else { // NaN + 0 + } } - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] - pub extern "C" fn __floatuntidf(i: u128) -> f64 { - int_to_float(i) + #[arm_aeabi_alias = __aeabi_f2lz] + pub extern "C" fn __fixsfdi(f: f32) -> i64 { + let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. + if fbits < 127 << 23 { // >= 0, < 1 + 0 + } else if fbits < 190 << 23 { // >= 1, < max + let m = 1 << 63 | (fbits as u64) << 40; // Mantissa and the implicit 1-bit. + let s = 190 - (fbits >> 23); // Shift based on the exponent and bias. + let u = (m >> s) as i64; // Unsigned result. + if f.is_sign_negative() { -u } else { u } + } else if fbits <= 255 << 23 { // >= max (incl. inf) + if f.is_sign_negative() { i64::MIN } else { i64::MAX } + } else { // NaN + 0 + } } #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __fixsfti(f: f32) -> i128 { - float_to_int(f) + let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. + if fbits < 127 << 23 { // >= 0, < 1 + 0 + } else if fbits < 254 << 23 { // >= 1, < max + let m = 1 << 127 | (fbits as u128) << 104; // Mantissa and the implicit 1-bit. + let s = 254 - (fbits >> 23); // Shift based on the exponent and bias. + let u = (m >> s) as i128; // Unsigned result. + if f.is_sign_negative() { -u } else { u } + } else if fbits <= 255 << 23 { // >= max (incl. inf) + if f.is_sign_negative() { i128::MIN } else { i128::MAX } + } else { // NaN + 0 + } } - #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] - pub extern "C" fn __fixdfti(f: f64) -> i128 { - float_to_int(f) + #[arm_aeabi_alias = __aeabi_d2iz] + pub extern "C" fn __fixdfsi(f: f64) -> i32 { + let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. + if fbits < 1023 << 52 { // >= 0, < 1 + 0 + } else if fbits < 1054 << 52 { // >= 1, < max + let m = 1 << 31 | (fbits >> 21) as u32; // Mantissa and the implicit 1-bit. + let s = 1054 - (fbits >> 52); // Shift based on the exponent and bias. + let u = (m >> s) as i32; // Unsigned result. + if f.is_sign_negative() { -u } else { u } + } else if fbits <= 2047 << 52 { // >= max (incl. inf) + if f.is_sign_negative() { i32::MIN } else { i32::MAX } + } else { // NaN + 0 + } } - #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] - pub extern "C" fn __fixunssfti(f: f32) -> u128 { - float_to_int(f) + #[arm_aeabi_alias = __aeabi_d2lz] + pub extern "C" fn __fixdfdi(f: f64) -> i64 { + let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. + if fbits < 1023 << 52 { // >= 0, < 1 + 0 + } else if fbits < 1086 << 52 { // >= 1, < max + let m = 1 << 63 | fbits << 11; // Mantissa and the implicit 1-bit. + let s = 1086 - (fbits >> 52); // Shift based on the exponent and bias. + let u = (m >> s) as i64; // Unsigned result. + if f.is_sign_negative() { -u } else { u } + } else if fbits <= 2047 << 52 { // >= max (incl. inf) + if f.is_sign_negative() { i64::MIN } else { i64::MAX } + } else { // NaN + 0 + } } #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] - pub extern "C" fn __fixunsdfti(f: f64) -> u128 { - float_to_int(f) + pub extern "C" fn __fixdfti(f: f64) -> i128 { + let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. + if fbits < 1023 << 52 { // >= 0, < 1 + 0 + } else if fbits < 1150 << 52 { // >= 1, < max + let m = 1 << 127 | (fbits as u128) << 75; // Mantissa and the implicit 1-bit. + let s = 1150 - (fbits >> 52); // Shift based on the exponent and bias. + let u = (m >> s) as i128; // Unsigned result. + if f.is_sign_negative() { -u } else { u } + } else if fbits <= 2047 << 52 { // >= max (incl. inf) + if f.is_sign_negative() { i128::MIN } else { i128::MAX } + } else { // NaN + 0 + } } } -- cgit 1.4.1-3-g733a5 From dcdd9bbc565ea30a07416b93fe043b95f2abb9c2 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Mon, 23 May 2022 23:34:10 -0700 Subject: Avoid int to ptr transmute by casting first --- library/compiler-builtins/src/arm_linux.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs index df1723d99c6..8fe09485bcf 100644 --- a/library/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/src/arm_linux.rs @@ -4,11 +4,11 @@ use core::mem; // Kernel-provided user-mode helper functions: // https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt unsafe fn __kuser_cmpxchg(oldval: u32, newval: u32, ptr: *mut u32) -> bool { - let f: extern "C" fn(u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0u32); + let f: extern "C" fn(u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0usize as *const ()); f(oldval, newval, ptr) == 0 } unsafe fn __kuser_memory_barrier() { - let f: extern "C" fn() = mem::transmute(0xffff0fa0u32); + let f: extern "C" fn() = mem::transmute(0xffff0fa0usize as *const ()); f(); } -- cgit 1.4.1-3-g733a5 From ac47841ce294f13108fa619fd164b154c3ea7fb7 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Tue, 24 May 2022 19:49:08 +0200 Subject: Add avr_skip for __udivti3 & __umodti3 --- library/compiler-builtins/src/int/udiv.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index c5ef4a6b197..fb09f87d89c 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -57,6 +57,7 @@ intrinsics! { // Note: we use block configuration and not `if cfg!(...)`, because we need to entirely disable // the existence of `u128_div_rem` to get 32-bit SPARC to compile, see `u128_divide_sparc` docs. + #[avr_skip] #[win64_128bit_abi_hack] /// Returns `n / d` pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { @@ -68,6 +69,7 @@ intrinsics! { } } + #[avr_skip] #[win64_128bit_abi_hack] /// Returns `n % d` pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { -- cgit 1.4.1-3-g733a5 From ca517a25e7c232c7d9a6a72ff4ab70917eb36683 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 26 May 2022 17:17:38 +0200 Subject: Explicitly use parentheses for associativity of shift operators. --- library/compiler-builtins/src/float/conv.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 86847ed6c79..07b58f3d232 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -10,8 +10,8 @@ mod int_to_float { return 0; } let n = i.leading_zeros(); - let a = i << n >> 8; // Significant bits, with bit 24 still in tact. - let b = i << n << 24; // Insignificant bits, only relevant for rounding. + let a = (i << n) >> 8; // Significant bits, with bit 24 still in tact. + let b = (i << n) << 24; // Insignificant bits, only relevant for rounding. let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. let e = 157 - n as u32; // Exponent plus 127, minus one. (e << 23) + m // + not |, so the mantissa can overflow into the exponent. @@ -42,8 +42,8 @@ mod int_to_float { return 0; } let n = i.leading_zeros(); - let a = (i << n >> 11) as u64; // Significant bits, with bit 53 still in tact. - let b = (i << n << 53) as u64; // Insignificant bits, only relevant for rounding. + let a = ((i << n) >> 11) as u64; // Significant bits, with bit 53 still in tact. + let b = ((i << n) << 53) as u64; // Insignificant bits, only relevant for rounding. let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even. let e = 1085 - n as u64; // Exponent plus 1023, minus one. (e << 52) + m // + not |, so the mantissa can overflow into the exponent. @@ -53,7 +53,7 @@ mod int_to_float { let n = i.leading_zeros(); let y = i.wrapping_shl(n); let a = (y >> 104) as u32; // Significant bits, with bit 24 still in tact. - let b = (y >> 72) as u32 | (y << 32 >> 32 != 0) as u32; // Insignificant bits, only relevant for rounding. + let b = (y >> 72) as u32 | ((y << 32) >> 32 != 0) as u32; // Insignificant bits, only relevant for rounding. let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. let e = if i == 0 { 0 } else { 253 - n }; // Exponent plus 127, minus one, except for zero. (e << 23) + m // + not |, so the mantissa can overflow into the exponent. -- cgit 1.4.1-3-g733a5 From 735ad075010c8462b203df4c10af6029e086dd38 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 26 May 2022 19:54:32 +0100 Subject: Bump to 0.1.73 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 99f2947242d..ac1794b187a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.72" +version = "0.1.73" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 4dbd8387f9bc3e5c30e7c3060db0c1c25cd49f89 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Tue, 1 Mar 2022 09:50:55 +0100 Subject: Implement faster memcmp for x86_64 x86_64 can load unaligned words in a single cache line as fast as aligned words. Even when crossing cache or page boundaries it is just as fast to do an unaligned word read instead of multiple byte reads. Also add a couple more tests & benchmarks. --- library/compiler-builtins/src/mem/impls.rs | 14 +++ library/compiler-builtins/src/mem/mod.rs | 11 +-- library/compiler-builtins/src/mem/x86_64.rs | 41 ++++++++ library/compiler-builtins/testcrate/benches/mem.rs | 104 +++++++++++++++++++++ library/compiler-builtins/testcrate/tests/mem.rs | 38 +++++++- 5 files changed, 193 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index 8151324254a..f31366d765c 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -265,3 +265,17 @@ pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { } set_bytes_bytes(s, c, n); } + +#[inline(always)] +pub unsafe fn compare_bytes(s1: *const u8, s2: *const u8, n: usize) { + let mut i = 0; + while i < n { + let a = *s1.add(i); + let b = *s2.add(i); + if a != b { + return a as i32 - b as i32; + } + i += 1; + } + 0 +} diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index a551138612b..c5b0ddc16ec 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -51,16 +51,7 @@ intrinsics! { #[mem_builtin] #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - let mut i = 0; - while i < n { - let a = *s1.add(i); - let b = *s2.add(i); - if a != b { - return a as i32 - b as i32; - } - i += 1; - } - 0 + impls::compare_bytes(s1, s2, n) } #[mem_builtin] diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index a7ab6f605bd..0bfacf713c5 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -16,6 +16,8 @@ // feature is present at compile-time. We don't bother detecting other features. // Note that ERMSB does not enhance the backwards (DF=1) "rep movsb". +use core::mem; + #[inline(always)] #[cfg(target_feature = "ermsb")] pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { @@ -98,3 +100,42 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { options(att_syntax, nostack, preserves_flags) ); } + +#[inline(always)] +pub unsafe fn compare_bytes( + a: *const u8, + b: *const u8, + n: usize, +) -> i32 { + unsafe fn cmp(mut a: *const T, mut b: *const T, n: usize, f: F) -> i32 + where + T: Clone + Copy + Eq, + U: Clone + Copy + Eq, + F: FnOnce(*const U, *const U, usize) -> i32, + { + for _ in 0..n / mem::size_of::() { + if a.read_unaligned() != b.read_unaligned() { + return f(a.cast(), b.cast(), mem::size_of::()); + } + a = a.add(1); + b = b.add(1); + } + f(a.cast(), b.cast(), n % mem::size_of::()) + } + let c1 = |mut a: *const u8, mut b: *const u8, n| { + for _ in 0..n { + if a.read() != b.read() { + return i32::from(a.read()) - i32::from(b.read()); + } + a = a.add(1); + b = b.add(1); + } + 0 + }; + let c2 = |a: *const u16, b, n| cmp(a, b, n, c1); + let c4 = |a: *const u32, b, n| cmp(a, b, n, c2); + let c8 = |a: *const u64, b, n| cmp(a, b, n, c4); + let c16 = |a: *const u128, b, n| cmp(a, b, n, c8); + let c32 = |a: *const [u128; 2], b, n| cmp(a, b, n, c16); + c32(a.cast(), b.cast(), n) +} diff --git a/library/compiler-builtins/testcrate/benches/mem.rs b/library/compiler-builtins/testcrate/benches/mem.rs index b6883a93b24..98a040958c4 100644 --- a/library/compiler-builtins/testcrate/benches/mem.rs +++ b/library/compiler-builtins/testcrate/benches/mem.rs @@ -96,6 +96,18 @@ fn memcmp_builtin(b: &mut Bencher, n: usize) { }) } +fn memcmp_builtin_unaligned(b: &mut Bencher, n: usize) { + let v1 = AlignedVec::new(0, n); + let mut v2 = AlignedVec::new(0, n); + v2[n - 1] = 1; + b.bytes = n as u64; + b.iter(|| { + let s1: &[u8] = black_box(&v1[0..]); + let s2: &[u8] = black_box(&v2[1..]); + s1.cmp(s2) + }) +} + fn memcmp_rust(b: &mut Bencher, n: usize) { let v1 = AlignedVec::new(0, n); let mut v2 = AlignedVec::new(0, n); @@ -108,6 +120,18 @@ fn memcmp_rust(b: &mut Bencher, n: usize) { }) } +fn memcmp_rust_unaligned(b: &mut Bencher, n: usize) { + let v1 = AlignedVec::new(0, n); + let mut v2 = AlignedVec::new(0, n); + v2[n - 1] = 1; + b.bytes = n as u64; + b.iter(|| { + let s1: &[u8] = black_box(&v1[0..]); + let s2: &[u8] = black_box(&v2[1..]); + unsafe { memcmp(s1.as_ptr(), s2.as_ptr(), n - 1) } + }) +} + fn memmove_builtin(b: &mut Bencher, n: usize, offset: usize) { let mut v = AlignedVec::new(0, n + n / 2 + offset); b.bytes = n as u64; @@ -209,6 +233,38 @@ fn memset_rust_1048576_offset(b: &mut Bencher) { memset_rust(b, 1048576, 65) } +#[bench] +fn memcmp_builtin_8(b: &mut Bencher) { + memcmp_builtin(b, 8) +} +#[bench] +fn memcmp_rust_8(b: &mut Bencher) { + memcmp_rust(b, 8) +} +#[bench] +fn memcmp_builtin_16(b: &mut Bencher) { + memcmp_builtin(b, 16) +} +#[bench] +fn memcmp_rust_16(b: &mut Bencher) { + memcmp_rust(b, 16) +} +#[bench] +fn memcmp_builtin_32(b: &mut Bencher) { + memcmp_builtin(b, 32) +} +#[bench] +fn memcmp_rust_32(b: &mut Bencher) { + memcmp_rust(b, 32) +} +#[bench] +fn memcmp_builtin_64(b: &mut Bencher) { + memcmp_builtin(b, 64) +} +#[bench] +fn memcmp_rust_64(b: &mut Bencher) { + memcmp_rust(b, 64) +} #[bench] fn memcmp_builtin_4096(b: &mut Bencher) { memcmp_builtin(b, 4096) @@ -225,6 +281,54 @@ fn memcmp_builtin_1048576(b: &mut Bencher) { fn memcmp_rust_1048576(b: &mut Bencher) { memcmp_rust(b, 1048576) } +#[bench] +fn memcmp_builtin_unaligned_7(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 8) +} +#[bench] +fn memcmp_rust_unaligned_7(b: &mut Bencher) { + memcmp_rust_unaligned(b, 8) +} +#[bench] +fn memcmp_builtin_unaligned_15(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 16) +} +#[bench] +fn memcmp_rust_unaligned_15(b: &mut Bencher) { + memcmp_rust_unaligned(b, 16) +} +#[bench] +fn memcmp_builtin_unaligned_31(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 32) +} +#[bench] +fn memcmp_rust_unaligned_31(b: &mut Bencher) { + memcmp_rust_unaligned(b, 32) +} +#[bench] +fn memcmp_builtin_unaligned_63(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 64) +} +#[bench] +fn memcmp_rust_unaligned_63(b: &mut Bencher) { + memcmp_rust_unaligned(b, 64) +} +#[bench] +fn memcmp_builtin_unaligned_4095(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 4096) +} +#[bench] +fn memcmp_rust_unaligned_4095(b: &mut Bencher) { + memcmp_rust_unaligned(b, 4096) +} +#[bench] +fn memcmp_builtin_unaligned_1048575(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 1048576) +} +#[bench] +fn memcmp_rust_unaligned_1048575(b: &mut Bencher) { + memcmp_rust_unaligned(b, 1048576) +} #[bench] fn memmove_builtin_4096(b: &mut Bencher) { diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs index 3f20e72a04c..69a63e71df5 100644 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -116,11 +116,13 @@ fn memset_nonzero() { #[test] fn memcmp_eq() { - let arr1: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; - let arr2: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; - unsafe { - assert_eq!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 8), 0); - assert_eq!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 3), 0); + let arr1: [u8; 32] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]; + let arr2: [u8; 32] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]; + for i in 0..32 { + unsafe { + assert_eq!(memcmp(arr1.as_ptr(), arr2.as_ptr(), i), 0); + assert_eq!(memcmp(arr2.as_ptr(), arr1.as_ptr(), i), 0); + } } } @@ -134,6 +136,32 @@ fn memcmp_ne() { } } +#[test] +fn memcmp_ne_16() { + let arr1: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + let arr2: [u8; 16] = [0, 1, 2, 3, 4, 5, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + unsafe { + assert!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 16) < 0); + assert!(memcmp(arr2.as_ptr(), arr1.as_ptr(), 16) > 0); + } +} + +#[test] +fn memcmp_ne_32() { + let arr1: [u8; 32] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + ]; + let arr2: [u8; 32] = [ + 0, 1, 2, 3, 4, 5, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + ]; + unsafe { + assert!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 32) < 0); + assert!(memcmp(arr2.as_ptr(), arr1.as_ptr(), 32) > 0); + } +} + #[derive(Clone, Copy)] struct AlignedStorage([u8; N], [usize; 0]); -- cgit 1.4.1-3-g733a5 From d6650678de2239397ae8ab1a6af443a2b2ecfcef Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Fri, 27 May 2022 22:37:54 +0200 Subject: Fix formatting --- library/compiler-builtins/testcrate/tests/mem.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs index 69a63e71df5..8385dfc2cec 100644 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -116,8 +116,14 @@ fn memset_nonzero() { #[test] fn memcmp_eq() { - let arr1: [u8; 32] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]; - let arr2: [u8; 32] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]; + let arr1: [u8; 32] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, + ]; + let arr2: [u8; 32] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, + ]; for i in 0..32 { unsafe { assert_eq!(memcmp(arr1.as_ptr(), arr2.as_ptr(), i), 0); -- cgit 1.4.1-3-g733a5 From e7a8932e3b6173d98b0925ee5011d8601d023a3b Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sat, 28 May 2022 00:09:02 +0200 Subject: Fix CI, better memcmp tests --- library/compiler-builtins/src/mem/impls.rs | 2 +- library/compiler-builtins/src/mem/x86_64.rs | 6 +-- library/compiler-builtins/testcrate/tests/mem.rs | 55 ++++++------------------ 3 files changed, 15 insertions(+), 48 deletions(-) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index f31366d765c..72003a5c472 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -267,7 +267,7 @@ pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { } #[inline(always)] -pub unsafe fn compare_bytes(s1: *const u8, s2: *const u8, n: usize) { +pub unsafe fn compare_bytes(s1: *const u8, s2: *const u8, n: usize) -> i32 { let mut i = 0; while i < n { let a = *s1.add(i); diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 0bfacf713c5..fc89aa768d3 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -102,11 +102,7 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { } #[inline(always)] -pub unsafe fn compare_bytes( - a: *const u8, - b: *const u8, - n: usize, -) -> i32 { +pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { unsafe fn cmp(mut a: *const T, mut b: *const T, n: usize, f: F) -> i32 where T: Clone + Copy + Eq, diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs index 8385dfc2cec..48ac95adc17 100644 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -116,55 +116,26 @@ fn memset_nonzero() { #[test] fn memcmp_eq() { - let arr1: [u8; 32] = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, - ]; - let arr2: [u8; 32] = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, - ]; - for i in 0..32 { + let arr1 @ arr2 = gen_arr::<256>(); + for i in 0..256 { unsafe { - assert_eq!(memcmp(arr1.as_ptr(), arr2.as_ptr(), i), 0); - assert_eq!(memcmp(arr2.as_ptr(), arr1.as_ptr(), i), 0); + assert_eq!(memcmp(arr1.0.as_ptr(), arr2.0.as_ptr(), i), 0); + assert_eq!(memcmp(arr2.0.as_ptr(), arr1.0.as_ptr(), i), 0); } } } #[test] fn memcmp_ne() { - let arr1: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; - let arr2: [u8; 8] = [0, 1, 2, 3, 4, 5, 7, 7]; - unsafe { - assert!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 8) < 0); - assert!(memcmp(arr2.as_ptr(), arr1.as_ptr(), 8) > 0); - } -} - -#[test] -fn memcmp_ne_16() { - let arr1: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; - let arr2: [u8; 16] = [0, 1, 2, 3, 4, 5, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15]; - unsafe { - assert!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 16) < 0); - assert!(memcmp(arr2.as_ptr(), arr1.as_ptr(), 16) > 0); - } -} - -#[test] -fn memcmp_ne_32() { - let arr1: [u8; 32] = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, - ]; - let arr2: [u8; 32] = [ - 0, 1, 2, 3, 4, 5, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, - ]; - unsafe { - assert!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 32) < 0); - assert!(memcmp(arr2.as_ptr(), arr1.as_ptr(), 32) > 0); + let arr1 @ arr2 = gen_arr::<256>(); + for i in 0..256 { + let mut diff_arr = arr1; + diff_arr.0[i] = 127; + let expect = diff_arr.0[i].cmp(&arr2.0[i]); + for k in i + 1..256 { + let result = unsafe { memcmp(diff_arr.0.as_ptr(), arr2.0.as_ptr(), k) }; + assert_eq!(expect, result.cmp(&0)); + } } } -- cgit 1.4.1-3-g733a5 From 2071d05a19980737bbb15948c5d914cae7ba23de Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sat, 28 May 2022 00:50:05 +0200 Subject: Always inline compare_bytes::cmp --- library/compiler-builtins/src/mem/x86_64.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index fc89aa768d3..65b61224dc2 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -103,6 +103,7 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { #[inline(always)] pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { + #[inline(always)] unsafe fn cmp(mut a: *const T, mut b: *const T, n: usize, f: F) -> i32 where T: Clone + Copy + Eq, -- cgit 1.4.1-3-g733a5 From 217748f91bbe20959262a46246edf2d0d3c9a7bd Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sat, 28 May 2022 01:23:50 +0200 Subject: Fix panic not being optimized out. I don't know why it isn't being optimized out though, which worries me. --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/mem/x86_64.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 009923d27e5..acac040be33 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -6,6 +6,7 @@ #![feature(compiler_builtins)] #![feature(core_ffi_c)] #![feature(core_intrinsics)] +#![feature(inline_const)] #![feature(lang_items)] #![feature(linkage)] #![feature(naked_functions)] diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 65b61224dc2..6eecd5a515e 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -110,14 +110,20 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { U: Clone + Copy + Eq, F: FnOnce(*const U, *const U, usize) -> i32, { - for _ in 0..n / mem::size_of::() { + // Just to be sure we're actually working with powers of two... + let _ = const { 1 - mem::size_of::().count_ones() }; // <= 1 + let _ = const { mem::size_of::().count_ones() - 1 }; // >= 1 + // This should be equivalent to division with power-of-two sizes, except the former + // somehow still leaves a call to panic because ?? + for _ in 0..n >> mem::size_of::().trailing_zeros() { if a.read_unaligned() != b.read_unaligned() { return f(a.cast(), b.cast(), mem::size_of::()); } a = a.add(1); b = b.add(1); } - f(a.cast(), b.cast(), n % mem::size_of::()) + // Ditto + f(a.cast(), b.cast(), n & (mem::size_of::() - 1)) } let c1 = |mut a: *const u8, mut b: *const u8, n| { for _ in 0..n { -- cgit 1.4.1-3-g733a5 From 95d2cd550288c798e14be620229de936c54cc0c3 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sat, 28 May 2022 08:16:46 +0200 Subject: Fix rustfmt sillyness --- library/compiler-builtins/src/mem/x86_64.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 6eecd5a515e..66b51fedf8a 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -113,6 +113,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { // Just to be sure we're actually working with powers of two... let _ = const { 1 - mem::size_of::().count_ones() }; // <= 1 let _ = const { mem::size_of::().count_ones() - 1 }; // >= 1 + // This should be equivalent to division with power-of-two sizes, except the former // somehow still leaves a call to panic because ?? for _ in 0..n >> mem::size_of::().trailing_zeros() { -- cgit 1.4.1-3-g733a5 From b94e93ead806cc90f9831ca6a150318edcea35fe Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sat, 28 May 2022 22:46:16 +0200 Subject: Slightly optimize main (32b) memcmp loop It only seems to save a single instruction at first sight yet the effects are significant. --- library/compiler-builtins/src/mem/x86_64.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 66b51fedf8a..2b4875697ae 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -116,7 +116,8 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { // This should be equivalent to division with power-of-two sizes, except the former // somehow still leaves a call to panic because ?? - for _ in 0..n >> mem::size_of::().trailing_zeros() { + let end = a.add(n >> mem::size_of::().trailing_zeros()); + while a != end { if a.read_unaligned() != b.read_unaligned() { return f(a.cast(), b.cast(), mem::size_of::()); } -- cgit 1.4.1-3-g733a5 From cb63d7d500f03b19618fd166e1cd9afd91612fa6 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Tue, 31 May 2022 08:20:30 +0200 Subject: Use unchecked_div/rem --- library/compiler-builtins/src/mem/x86_64.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 2b4875697ae..4d2f6e5ee32 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -16,6 +16,7 @@ // feature is present at compile-time. We don't bother detecting other features. // Note that ERMSB does not enhance the backwards (DF=1) "rep movsb". +use core::intrinsics; use core::mem; #[inline(always)] @@ -110,13 +111,10 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { U: Clone + Copy + Eq, F: FnOnce(*const U, *const U, usize) -> i32, { - // Just to be sure we're actually working with powers of two... - let _ = const { 1 - mem::size_of::().count_ones() }; // <= 1 - let _ = const { mem::size_of::().count_ones() - 1 }; // >= 1 + // Ensure T is not a ZST. + const { assert!(mem::size_of::() != 0) }; - // This should be equivalent to division with power-of-two sizes, except the former - // somehow still leaves a call to panic because ?? - let end = a.add(n >> mem::size_of::().trailing_zeros()); + let end = a.add(intrinsics::unchecked_div(n, mem::size_of::())); while a != end { if a.read_unaligned() != b.read_unaligned() { return f(a.cast(), b.cast(), mem::size_of::()); @@ -124,8 +122,11 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { a = a.add(1); b = b.add(1); } - // Ditto - f(a.cast(), b.cast(), n & (mem::size_of::() - 1)) + f( + a.cast(), + b.cast(), + intrinsics::unchecked_rem(n, mem::size_of::()), + ) } let c1 = |mut a: *const u8, mut b: *const u8, n| { for _ in 0..n { -- cgit 1.4.1-3-g733a5 From cfc0422a7e5427ca7571392f101f729abd495832 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 31 May 2022 17:19:27 +0100 Subject: Bump to 0.1.74 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index ac1794b187a..31cf41265fb 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.73" +version = "0.1.74" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From bb0b7d660f47e8c383267a9524ede705859b87d3 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 9 Jun 2022 08:40:15 +0800 Subject: build: compile C code for "xous" operating system The "xous" operating system is enturely Rust-based, meaning it has no libc. Therefore, it relies on `compiler-builtins` for all intrinsics. Unfortunately, there are not yet Rust equivalents for all C functions. For example, triganometric functions are still missing. In the meantime, enable C replacements for these functions so that Rust programs compiled for Xous can call these functions. Signed-off-by: Sean Cross --- library/compiler-builtins/build.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 11deffb9c92..87622493421 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -58,9 +58,11 @@ fn main() { // unlikely that the C is really that much better than our own Rust. // * nvptx - everything is bitcode, not compatible with mixed C/Rust // * riscv - the rust-lang/rust distribution container doesn't have a C - // compiler nor is cc-rs ready for compilation to riscv (at this - // time). This can probably be removed in the future - if !target.contains("wasm") && !target.contains("nvptx") && !target.starts_with("riscv") { + // compiler. + if !target.contains("wasm") + && !target.contains("nvptx") + && (!target.starts_with("riscv") || target.contains("xous")) + { #[cfg(feature = "c")] c::compile(&llvm_target, &target); } -- cgit 1.4.1-3-g733a5 From 7cdad114a59af6b503f611e82ba3a5fd177c4c36 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 9 Sep 2021 11:21:33 +0800 Subject: math: compile math functions for Xous This adds support for Xous, enabling users to call math functions on primitives such as `cos()`. Signed-off-by: Sean Cross --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/math.rs | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index acac040be33..e7bc61e4c0f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -46,6 +46,7 @@ pub mod int; all(target_family = "wasm", target_os = "unknown"), all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), + target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx") ))] pub mod math; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index fa59753f8f6..14a65395eb8 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -20,6 +20,7 @@ macro_rules! no_mangle { target_os = "unknown", not(target_env = "wasi") ), + target_os = "xous", all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") @@ -70,6 +71,7 @@ no_mangle! { target_os = "unknown", not(target_env = "wasi") ), + target_os = "xous", all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") ))] @@ -93,7 +95,16 @@ no_mangle! { fn tanf(n: f32) -> f32; } -#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] +#[cfg(target_os = "xous")] +no_mangle! { + fn sqrtf(x: f32) -> f32; + fn sqrt(x: f64) -> f64; +} + +#[cfg(any( + all(target_vendor = "fortanix", target_env = "sgx"), + target_os = "xous" +))] no_mangle! { fn ceil(x: f64) -> f64; fn ceilf(x: f32) -> f32; -- cgit 1.4.1-3-g733a5 From 08f4f4007d9aaaef367949c2d31c0882b4f1bc27 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sat, 11 Jun 2022 09:13:28 +0200 Subject: Fix infinite recursion in x86_64 memcmp if SSE2 is not present Fixes #470 --- library/compiler-builtins/src/mem/x86_64.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 4d2f6e5ee32..3b372d10d1a 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -143,5 +143,16 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { let c8 = |a: *const u64, b, n| cmp(a, b, n, c4); let c16 = |a: *const u128, b, n| cmp(a, b, n, c8); let c32 = |a: *const [u128; 2], b, n| cmp(a, b, n, c16); - c32(a.cast(), b.cast(), n) + // [u128; 2] internally uses raw_eq for comparisons, which may emit a call to memcmp + // above a certain size threshold. When SSE2 is enabled this threshold does not seem + // to be reached but without SSE2 a call is emitted, leading to infinite recursion. + // + // While replacing [u128; 2] with (u128, u128) fixes the issues it degrades performance + // severely. Likewise, removing c32() has a lesser but still significant impact. Instead the + // [u128; 2] case is only enabled when SSE2 is present. + if cfg!(target_feature = "sse2") { + c32(a.cast(), b.cast(), n) + } else { + c16(a.cast(), b.cast(), n) + } } -- cgit 1.4.1-3-g733a5 From 4d44679eb5e5ce9fc10fa12ff31330f9a1b5ce57 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 12 Jun 2022 01:19:53 +0100 Subject: Bump to 0.1.75 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 31cf41265fb..520a1f7dc98 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.74" +version = "0.1.75" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From f6ab9ca9a7c469af22deb9ae93d63c30efe95b6c Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 28 Jun 2022 20:16:07 +0530 Subject: Enable mem for UEFI Signed-off-by: Ayush Singh --- library/compiler-builtins/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 11deffb9c92..8d482fa2199 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -29,6 +29,7 @@ fn main() { || (target.contains("sgx") && target.contains("fortanix")) || target.contains("-none") || target.contains("nvptx") + || target.contains("uefi") { println!("cargo:rustc-cfg=feature=\"mem\""); } -- cgit 1.4.1-3-g733a5 From 5e484198368fe373ff6245d5cc5518f858a78c73 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 29 Jun 2022 01:08:54 +0100 Subject: Bump to 0.1.76 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 520a1f7dc98..22ce34d366a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.75" +version = "0.1.76" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 011f92c877db3cc595f0a8c1e6ad3649e5481dbc Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 22 Jul 2022 17:14:18 -0600 Subject: add weak linkage to the ARM AEABI division functions --- library/compiler-builtins/src/arm.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 9c1b6ad123a..f3b22544a8c 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -22,6 +22,7 @@ intrinsics! { // custom calling convention which can't be implemented using a normal Rust function. #[naked] #[cfg(not(target_env = "msvc"))] + #[linkage = "weak"] pub unsafe extern "C" fn __aeabi_uidivmod() { core::arch::asm!( "push {{lr}}", @@ -36,6 +37,7 @@ intrinsics! { } #[naked] + #[linkage = "weak"] pub unsafe extern "C" fn __aeabi_uldivmod() { core::arch::asm!( "push {{r4, lr}}", @@ -52,6 +54,7 @@ intrinsics! { } #[naked] + #[linkage = "weak"] pub unsafe extern "C" fn __aeabi_idivmod() { core::arch::asm!( "push {{r0, r1, r4, lr}}", @@ -65,6 +68,7 @@ intrinsics! { } #[naked] + #[linkage = "weak"] pub unsafe extern "C" fn __aeabi_ldivmod() { core::arch::asm!( "push {{r4, lr}}", -- cgit 1.4.1-3-g733a5 From 6b6db5cc843e6790367a16d8c4238e0f9dd9e5bd Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 28 Jul 2022 16:02:04 +0100 Subject: Disable some PPC64 tests which are failing due to an LLVM(?) bug See https://github.com/rust-lang/rust/issues/99853 --- library/compiler-builtins/testcrate/tests/mem.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs index 48ac95adc17..5099d69ed6c 100644 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -230,6 +230,8 @@ fn memmove_backward_aligned() { } } +// PowerPC tests are failing: https://github.com/rust-lang/rust/issues/99853 +#[cfg(not(target_arch = "powerpc64"))] #[test] fn memset_backward_misaligned_nonaligned_start() { let mut arr = gen_arr::<32>(); @@ -242,6 +244,8 @@ fn memset_backward_misaligned_nonaligned_start() { } } +// PowerPC tests are failing: https://github.com/rust-lang/rust/issues/99853 +#[cfg(not(target_arch = "powerpc64"))] #[test] fn memset_backward_misaligned_aligned_start() { let mut arr = gen_arr::<32>(); @@ -254,6 +258,8 @@ fn memset_backward_misaligned_aligned_start() { } } +// PowerPC tests are failing: https://github.com/rust-lang/rust/issues/99853 +#[cfg(not(target_arch = "powerpc64"))] #[test] fn memset_backward_aligned() { let mut arr = gen_arr::<32>(); -- cgit 1.4.1-3-g733a5 From f2ac36348c9b8570732ed2153cf4ffd50bc8f172 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Thu, 28 Jul 2022 17:58:16 +0530 Subject: Use all of src/math for UEFI This is needed for libtest --- library/compiler-builtins/src/math.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 14a65395eb8..7337dabb93a 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -72,6 +72,7 @@ no_mangle! { not(target_env = "wasi") ), target_os = "xous", + all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") ))] @@ -95,7 +96,7 @@ no_mangle! { fn tanf(n: f32) -> f32; } -#[cfg(target_os = "xous")] +#[cfg(any(target_os = "xous", target_os = "uefi"))] no_mangle! { fn sqrtf(x: f32) -> f32; fn sqrt(x: f64) -> f64; @@ -103,7 +104,8 @@ no_mangle! { #[cfg(any( all(target_vendor = "fortanix", target_env = "sgx"), - target_os = "xous" + target_os = "xous", + target_os = "uefi" ))] no_mangle! { fn ceil(x: f64) -> f64; -- cgit 1.4.1-3-g733a5 From 8568a33255ab36b8be9a6b19c9fa2ee4628621ae Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 28 Jul 2022 09:42:18 -0600 Subject: restrict linkage to platforms using ELF binaries on windows and apple (which don't use ELF) we can't apply weak linkage --- library/compiler-builtins/src/arm.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index f3b22544a8c..e517a9ef34b 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -22,7 +22,7 @@ intrinsics! { // custom calling convention which can't be implemented using a normal Rust function. #[naked] #[cfg(not(target_env = "msvc"))] - #[linkage = "weak"] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_uidivmod() { core::arch::asm!( "push {{lr}}", @@ -37,7 +37,7 @@ intrinsics! { } #[naked] - #[linkage = "weak"] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_uldivmod() { core::arch::asm!( "push {{r4, lr}}", @@ -54,7 +54,7 @@ intrinsics! { } #[naked] - #[linkage = "weak"] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_idivmod() { core::arch::asm!( "push {{r0, r1, r4, lr}}", @@ -68,7 +68,7 @@ intrinsics! { } #[naked] - #[linkage = "weak"] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_ldivmod() { core::arch::asm!( "push {{r4, lr}}", -- cgit 1.4.1-3-g733a5 From 586e2b38ef2f5dabad565dfa96bf1625aba134df Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 9 Jul 2022 22:41:14 -0400 Subject: Enable win64_128bit_abi_hack for x86_64-unknown-uefi The `x86_64-unknown-uefi` target is Windows-like [1], and requires the same altered ABI for some 128-bit integer intrinsics. See also https://github.com/rust-lang/rust/issues/86494. [1]: https://github.com/rust-lang/rust/blob/master/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs --- library/compiler-builtins/src/macros.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 518a18d4de8..6acf1be969e 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -209,13 +209,13 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(windows, target_arch = "x86_64"))] + #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } - #[cfg(all(windows, target_arch = "x86_64"))] + #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] pub mod $name { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) @@ -226,7 +226,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(windows, target_arch = "x86_64")))] + #[cfg(not(all(any(windows, target_os = "uefi"), target_arch = "x86_64")))] intrinsics! { $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { @@ -426,7 +426,7 @@ macro_rules! intrinsics { // Hack for LLVM expectations for ABI on windows. This is used by the // `#[win64_128bit_abi_hack]` attribute recognized above -#[cfg(all(windows, target_pointer_width = "64"))] +#[cfg(all(any(windows, target_os = "uefi"), target_pointer_width = "64"))] pub mod win64_128bit_abi_hack { #[repr(simd)] pub struct U64x2(u64, u64); -- cgit 1.4.1-3-g733a5 From a977b01090ce83dd2cfc900b77ceaeb6eb61f795 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sat, 2 Jul 2022 23:54:30 +0200 Subject: Align destination in mem* instructions. While misaligned reads are generally fast, misaligned writes aren't and can have severe penalties. --- library/compiler-builtins/src/mem/x86_64.rs | 130 ++++++++++++++++++++-------- 1 file changed, 94 insertions(+), 36 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 3b372d10d1a..68ef17f1e86 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -16,6 +16,7 @@ // feature is present at compile-time. We don't bother detecting other features. // Note that ERMSB does not enhance the backwards (DF=1) "rep movsb". +use core::arch::asm; use core::intrinsics; use core::mem; @@ -34,40 +35,61 @@ pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { #[inline(always)] #[cfg(not(target_feature = "ermsb"))] -pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { - let qword_count = count >> 3; - let byte_count = count & 0b111; - // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - core::arch::asm!( - "repe movsq (%rsi), (%rdi)", - "mov {byte_count:e}, %ecx", - "repe movsb (%rsi), (%rdi)", - byte_count = in(reg) byte_count, +pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) { + let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); + // Separating the blocks gives the compiler more freedom to reorder instructions. + // It also allows us to trivially skip the rep movsb, which is faster when memcpying + // aligned data. + if pre_byte_count > 0 { + asm!( + "rep movsb", + inout("ecx") pre_byte_count => _, + inout("rdi") dest => dest, + inout("rsi") src => src, + options(nostack, preserves_flags) + ); + } + asm!( + "rep movsq", inout("rcx") qword_count => _, - inout("rdi") dest => _, - inout("rsi") src => _, - options(att_syntax, nostack, preserves_flags) + inout("rdi") dest => dest, + inout("rsi") src => src, + options(nostack, preserves_flags) ); + if byte_count > 0 { + asm!( + "rep movsb", + inout("ecx") byte_count => _, + inout("rdi") dest => _, + inout("rsi") src => _, + options(nostack, preserves_flags) + ); + } } #[inline(always)] pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { - let qword_count = count >> 3; - let byte_count = count & 0b111; - // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - core::arch::asm!( + let (pre_byte_count, qword_count, byte_count) = rep_param_rev(dest, count); + // We can't separate this block due to std/cld + asm!( "std", - "repe movsq (%rsi), (%rdi)", - "movl {byte_count:e}, %ecx", - "addq $7, %rdi", - "addq $7, %rsi", - "repe movsb (%rsi), (%rdi)", + "rep movsb", + "sub rsi, 7", + "sub rdi, 7", + "mov rcx, {qword_count}", + "rep movsq", + "add rsi, 7", + "add rdi, 7", + "mov ecx, {byte_count:e}", + "rep movsb", "cld", byte_count = in(reg) byte_count, - inout("rcx") qword_count => _, - inout("rdi") dest.add(count).wrapping_sub(8) => _, - inout("rsi") src.add(count).wrapping_sub(8) => _, - options(att_syntax, nostack) + qword_count = in(reg) qword_count, + inout("ecx") pre_byte_count => _, + inout("rdi") dest.add(count - 1) => _, + inout("rsi") src.add(count - 1) => _, + // We modify flags, but we restore it afterwards + options(nostack, preserves_flags) ); } @@ -86,20 +108,36 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { #[inline(always)] #[cfg(not(target_feature = "ermsb"))] -pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { - let qword_count = count >> 3; - let byte_count = count & 0b111; - // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - core::arch::asm!( - "repe stosq %rax, (%rdi)", - "mov {byte_count:e}, %ecx", - "repe stosb %al, (%rdi)", - byte_count = in(reg) byte_count, +pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { + let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); + // Separating the blocks gives the compiler more freedom to reorder instructions. + // It also allows us to trivially skip the rep stosb, which is faster when memcpying + // aligned data. + if pre_byte_count > 0 { + asm!( + "rep stosb", + inout("ecx") pre_byte_count => _, + inout("rdi") dest => dest, + in("al") c, + options(nostack, preserves_flags) + ); + } + asm!( + "rep stosq", inout("rcx") qword_count => _, - inout("rdi") dest => _, + inout("rdi") dest => dest, in("rax") (c as u64) * 0x0101010101010101, - options(att_syntax, nostack, preserves_flags) + options(nostack, preserves_flags) ); + if byte_count > 0 { + asm!( + "rep stosb", + inout("ecx") byte_count => _, + inout("rdi") dest => _, + in("al") c, + options(nostack, preserves_flags) + ); + } } #[inline(always)] @@ -156,3 +194,23 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { c16(a.cast(), b.cast(), n) } } + +/// Determine optimal parameters for a `rep` instruction. +fn rep_param(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { + // Unaligned writes are still slow on modern processors, so align the destination address. + let pre_byte_count = ((8 - (dest as usize & 0b111)) & 0b111).min(count); + count -= pre_byte_count; + let qword_count = count >> 3; + let byte_count = count & 0b111; + (pre_byte_count, qword_count, byte_count) +} + +/// Determine optimal parameters for a reverse `rep` instruction (i.e. direction bit is set). +fn rep_param_rev(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { + // Unaligned writes are still slow on modern processors, so align the destination address. + let pre_byte_count = ((dest as usize + count) & 0b111).min(count); + count -= pre_byte_count; + let qword_count = count >> 3; + let byte_count = count & 0b111; + (pre_byte_count, qword_count, byte_count) +} -- cgit 1.4.1-3-g733a5 From 45e2996c965162844433ac72702681c9cb571580 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Thu, 7 Jul 2022 11:53:44 +0200 Subject: Fix suboptimal codegen in memset --- library/compiler-builtins/src/mem/x86_64.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 68ef17f1e86..3cbbbba53e3 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -109,6 +109,7 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { #[inline(always)] #[cfg(not(target_feature = "ermsb"))] pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { + let c = c as u64 * 0x0101_0101_0101_0101; let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); // Separating the blocks gives the compiler more freedom to reorder instructions. // It also allows us to trivially skip the rep stosb, which is faster when memcpying @@ -118,7 +119,7 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { "rep stosb", inout("ecx") pre_byte_count => _, inout("rdi") dest => dest, - in("al") c, + in("rax") c, options(nostack, preserves_flags) ); } @@ -126,7 +127,7 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { "rep stosq", inout("rcx") qword_count => _, inout("rdi") dest => dest, - in("rax") (c as u64) * 0x0101010101010101, + in("rax") c, options(nostack, preserves_flags) ); if byte_count > 0 { @@ -134,7 +135,7 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { "rep stosb", inout("ecx") byte_count => _, inout("rdi") dest => _, - in("al") c, + in("rax") c, options(nostack, preserves_flags) ); } -- cgit 1.4.1-3-g733a5 From 897a1338698a13b82bea082110aad71e4a952ae1 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Thu, 7 Jul 2022 13:13:19 +0200 Subject: Remove rep_param_rev --- library/compiler-builtins/src/mem/x86_64.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 3cbbbba53e3..483a3e31b79 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -69,7 +69,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) #[inline(always)] pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { - let (pre_byte_count, qword_count, byte_count) = rep_param_rev(dest, count); + let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); // We can't separate this block due to std/cld asm!( "std", @@ -80,12 +80,12 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { "rep movsq", "add rsi, 7", "add rdi, 7", - "mov ecx, {byte_count:e}", + "mov ecx, {pre_byte_count:e}", "rep movsb", "cld", - byte_count = in(reg) byte_count, + pre_byte_count = in(reg) pre_byte_count, qword_count = in(reg) qword_count, - inout("ecx") pre_byte_count => _, + inout("ecx") byte_count => _, inout("rdi") dest.add(count - 1) => _, inout("rsi") src.add(count - 1) => _, // We modify flags, but we restore it afterwards @@ -205,13 +205,3 @@ fn rep_param(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { let byte_count = count & 0b111; (pre_byte_count, qword_count, byte_count) } - -/// Determine optimal parameters for a reverse `rep` instruction (i.e. direction bit is set). -fn rep_param_rev(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { - // Unaligned writes are still slow on modern processors, so align the destination address. - let pre_byte_count = ((dest as usize + count) & 0b111).min(count); - count -= pre_byte_count; - let qword_count = count >> 3; - let byte_count = count & 0b111; - (pre_byte_count, qword_count, byte_count) -} -- cgit 1.4.1-3-g733a5 From 30e0c1f4c296bef105368c0a7025a0f9228a5188 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Thu, 7 Jul 2022 13:19:06 +0200 Subject: Use att_syntax for now --- library/compiler-builtins/src/mem/x86_64.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 483a3e31b79..a1015f61282 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -46,7 +46,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) inout("ecx") pre_byte_count => _, inout("rdi") dest => dest, inout("rsi") src => src, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } asm!( @@ -54,7 +54,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) inout("rcx") qword_count => _, inout("rdi") dest => dest, inout("rsi") src => src, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); if byte_count > 0 { asm!( @@ -62,7 +62,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) inout("ecx") byte_count => _, inout("rdi") dest => _, inout("rsi") src => _, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } } @@ -74,13 +74,13 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { asm!( "std", "rep movsb", - "sub rsi, 7", - "sub rdi, 7", - "mov rcx, {qword_count}", + "sub $7, %rsi", + "sub $7, %rdi", + "mov {qword_count}, %rcx", "rep movsq", - "add rsi, 7", - "add rdi, 7", - "mov ecx, {pre_byte_count:e}", + "add $7, %rsi", + "add $7, %rdi", + "mov {pre_byte_count:e}, %ecx", "rep movsb", "cld", pre_byte_count = in(reg) pre_byte_count, @@ -89,7 +89,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { inout("rdi") dest.add(count - 1) => _, inout("rsi") src.add(count - 1) => _, // We modify flags, but we restore it afterwards - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } @@ -120,7 +120,7 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { inout("ecx") pre_byte_count => _, inout("rdi") dest => dest, in("rax") c, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } asm!( @@ -128,7 +128,7 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { inout("rcx") qword_count => _, inout("rdi") dest => dest, in("rax") c, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); if byte_count > 0 { asm!( @@ -136,7 +136,7 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { inout("ecx") byte_count => _, inout("rdi") dest => _, in("rax") c, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } } -- cgit 1.4.1-3-g733a5 From 04c223f0df126df6c0e076caab33d04f9792c317 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Thu, 7 Jul 2022 13:20:41 +0200 Subject: Skip rep movsb in copy_backward if possible There is currently no measureable performance difference in benchmarks but it likely will make a difference in real workloads. --- library/compiler-builtins/src/mem/x86_64.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index a1015f61282..e9c1c56d539 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -73,15 +73,21 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { // We can't separate this block due to std/cld asm!( "std", + "test %ecx, %ecx", + "jz 1f", "rep movsb", + "1:", "sub $7, %rsi", "sub $7, %rdi", "mov {qword_count}, %rcx", "rep movsq", + "test {pre_byte_count:e}, {pre_byte_count:e}", + "jz 1f", "add $7, %rsi", "add $7, %rdi", "mov {pre_byte_count:e}, %ecx", "rep movsb", + "1:", "cld", pre_byte_count = in(reg) pre_byte_count, qword_count = in(reg) qword_count, -- cgit 1.4.1-3-g733a5 From 66f22e0931e00d5c0beb2f6564ca0c45d3f80699 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Thu, 28 Jul 2022 18:43:45 +0200 Subject: Remove branches around rep movsb/stosb While it is measurably faster for older CPUs, removing them keeps the code smaller and is likely more beneficial for newer CPUs. --- library/compiler-builtins/src/mem/x86_64.rs | 73 +++++++++++------------------ 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index e9c1c56d539..dd98e37c5f0 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -38,17 +38,13 @@ pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) { let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); // Separating the blocks gives the compiler more freedom to reorder instructions. - // It also allows us to trivially skip the rep movsb, which is faster when memcpying - // aligned data. - if pre_byte_count > 0 { - asm!( - "rep movsb", - inout("ecx") pre_byte_count => _, - inout("rdi") dest => dest, - inout("rsi") src => src, - options(att_syntax, nostack, preserves_flags) - ); - } + asm!( + "rep movsb", + inout("ecx") pre_byte_count => _, + inout("rdi") dest => dest, + inout("rsi") src => src, + options(att_syntax, nostack, preserves_flags) + ); asm!( "rep movsq", inout("rcx") qword_count => _, @@ -56,15 +52,13 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) inout("rsi") src => src, options(att_syntax, nostack, preserves_flags) ); - if byte_count > 0 { - asm!( - "rep movsb", - inout("ecx") byte_count => _, - inout("rdi") dest => _, - inout("rsi") src => _, - options(att_syntax, nostack, preserves_flags) - ); - } + asm!( + "rep movsb", + inout("ecx") byte_count => _, + inout("rdi") dest => _, + inout("rsi") src => _, + options(att_syntax, nostack, preserves_flags) + ); } #[inline(always)] @@ -73,21 +67,16 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { // We can't separate this block due to std/cld asm!( "std", - "test %ecx, %ecx", - "jz 1f", "rep movsb", - "1:", "sub $7, %rsi", "sub $7, %rdi", "mov {qword_count}, %rcx", "rep movsq", "test {pre_byte_count:e}, {pre_byte_count:e}", - "jz 1f", "add $7, %rsi", "add $7, %rdi", "mov {pre_byte_count:e}, %ecx", "rep movsb", - "1:", "cld", pre_byte_count = in(reg) pre_byte_count, qword_count = in(reg) qword_count, @@ -118,17 +107,13 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { let c = c as u64 * 0x0101_0101_0101_0101; let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); // Separating the blocks gives the compiler more freedom to reorder instructions. - // It also allows us to trivially skip the rep stosb, which is faster when memcpying - // aligned data. - if pre_byte_count > 0 { - asm!( - "rep stosb", - inout("ecx") pre_byte_count => _, - inout("rdi") dest => dest, - in("rax") c, - options(att_syntax, nostack, preserves_flags) - ); - } + asm!( + "rep stosb", + inout("ecx") pre_byte_count => _, + inout("rdi") dest => dest, + in("rax") c, + options(att_syntax, nostack, preserves_flags) + ); asm!( "rep stosq", inout("rcx") qword_count => _, @@ -136,15 +121,13 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { in("rax") c, options(att_syntax, nostack, preserves_flags) ); - if byte_count > 0 { - asm!( - "rep stosb", - inout("ecx") byte_count => _, - inout("rdi") dest => _, - in("rax") c, - options(att_syntax, nostack, preserves_flags) - ); - } + asm!( + "rep stosb", + inout("ecx") byte_count => _, + inout("rdi") dest => _, + in("rax") c, + options(att_syntax, nostack, preserves_flags) + ); } #[inline(always)] -- cgit 1.4.1-3-g733a5 From 1913181e243f312539336fec39d4c6d9efb9b59a Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 28 Jul 2022 20:58:02 +0100 Subject: Bump to 0.1.77 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 22ce34d366a..cd471883061 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.76" +version = "0.1.77" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 89df6f6bc0709f0dbdebe901a8996d484f9040bb Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Thu, 28 Jul 2022 16:21:37 -0700 Subject: Added tgamma and tgammaf --- library/compiler-builtins/src/math.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 14a65395eb8..c3b9788e1dc 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -63,6 +63,8 @@ no_mangle! { fn tanhf(n: f32) -> f32; fn ldexp(f: f64, n: i32) -> f64; fn ldexpf(f: f32, n: i32) -> f32; + fn tgamma(x: f64) -> f64; + fn tgammaf(x: f32) -> f32; } #[cfg(any( -- cgit 1.4.1-3-g733a5 From de09c87e0b9da96b53fc6d7d01e8eebb696672ca Mon Sep 17 00:00:00 2001 From: Alex Huszagh Date: Fri, 29 Jul 2022 15:52:23 -0500 Subject: Add compiler-rt fallback for __trunctfsf2 on mips64-musl. --- library/compiler-builtins/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index befc5e2e3bb..73952bb9f3e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -460,6 +460,7 @@ mod c { ("__fe_getround", "fp_mode.c"), ("__divtf3", "divtf3.c"), ("__trunctfdf2", "trunctfdf2.c"), + ("__trunctfsf2", "trunctfsf2.c"), ]); } -- cgit 1.4.1-3-g733a5 From 599dcc2c46d0c312629feb9fd419bc07a1c5a02e Mon Sep 17 00:00:00 2001 From: Alex Huszagh Date: Fri, 29 Jul 2022 16:58:05 -0500 Subject: Add compiler-rt fallbacks for sync builtins on armv5te-musl. --- library/compiler-builtins/src/arm_linux.rs | 110 +++++++++++++++++++---------- 1 file changed, 73 insertions(+), 37 deletions(-) diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs index 8fe09485bcf..8f22eb62866 100644 --- a/library/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/src/arm_linux.rs @@ -55,7 +55,7 @@ fn insert_aligned(aligned: u32, val: u32, shift: u32, mask: u32) -> u32 { } // Generic atomic read-modify-write operation -unsafe fn atomic_rmw u32>(ptr: *mut T, f: F) -> u32 { +unsafe fn atomic_rmw u32, G: Fn(u32, u32) -> u32>(ptr: *mut T, f: F, g: G) -> u32 { let aligned_ptr = align_ptr(ptr); let (shift, mask) = get_shift_mask(ptr); @@ -65,7 +65,7 @@ unsafe fn atomic_rmw u32>(ptr: *mut T, f: F) -> u32 { let newval = f(curval); let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask); if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) { - return curval; + return g(curval, newval); } } } @@ -89,13 +89,21 @@ unsafe fn atomic_cmpxchg(ptr: *mut T, oldval: u32, newval: u32) -> u32 { } macro_rules! atomic_rmw { - ($name:ident, $ty:ty, $op:expr) => { + ($name:ident, $ty:ty, $op:expr, $fetch:expr) => { intrinsics! { pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty { - atomic_rmw(ptr, |x| $op(x as $ty, val) as u32) as $ty + atomic_rmw(ptr, |x| $op(x as $ty, val) as u32, |old, new| $fetch(old, new)) as $ty } } }; + + (@old $name:ident, $ty:ty, $op:expr) => { + atomic_rmw!($name, $ty, $op, |old, _| old); + }; + + (@new $name:ident, $ty:ty, $op:expr) => { + atomic_rmw!($name, $ty, $op, |_, new| new); + }; } macro_rules! atomic_cmpxchg { ($name:ident, $ty:ty) => { @@ -107,101 +115,129 @@ macro_rules! atomic_cmpxchg { }; } -atomic_rmw!(__sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b)); -atomic_rmw!(__sync_fetch_and_add_2, u16, |a: u16, b: u16| a +atomic_rmw!(@old __sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b)); +atomic_rmw!(@old __sync_fetch_and_add_2, u16, |a: u16, b: u16| a + .wrapping_add(b)); +atomic_rmw!(@old __sync_fetch_and_add_4, u32, |a: u32, b: u32| a + .wrapping_add(b)); + +atomic_rmw!(@new __sync_add_and_fetch_1, u8, |a: u8, b: u8| a.wrapping_add(b)); +atomic_rmw!(@new __sync_add_and_fetch_2, u16, |a: u16, b: u16| a .wrapping_add(b)); -atomic_rmw!(__sync_fetch_and_add_4, u32, |a: u32, b: u32| a +atomic_rmw!(@new __sync_add_and_fetch_4, u32, |a: u32, b: u32| a .wrapping_add(b)); -atomic_rmw!(__sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); -atomic_rmw!(__sync_fetch_and_sub_2, u16, |a: u16, b: u16| a +atomic_rmw!(@old __sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); +atomic_rmw!(@old __sync_fetch_and_sub_2, u16, |a: u16, b: u16| a .wrapping_sub(b)); -atomic_rmw!(__sync_fetch_and_sub_4, u32, |a: u32, b: u32| a +atomic_rmw!(@old __sync_fetch_and_sub_4, u32, |a: u32, b: u32| a .wrapping_sub(b)); -atomic_rmw!(__sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b); -atomic_rmw!(__sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b); -atomic_rmw!(__sync_fetch_and_and_4, u32, |a: u32, b: u32| a & b); +atomic_rmw!(@new __sync_sub_and_fetch_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); +atomic_rmw!(@new __sync_sub_and_fetch_2, u16, |a: u16, b: u16| a + .wrapping_sub(b)); +atomic_rmw!(@new __sync_sub_and_fetch_4, u32, |a: u32, b: u32| a + .wrapping_sub(b)); + +atomic_rmw!(@old __sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b); +atomic_rmw!(@old __sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b); +atomic_rmw!(@old __sync_fetch_and_and_4, u32, |a: u32, b: u32| a & b); + +atomic_rmw!(@new __sync_and_and_fetch_1, u8, |a: u8, b: u8| a & b); +atomic_rmw!(@new __sync_and_and_fetch_2, u16, |a: u16, b: u16| a & b); +atomic_rmw!(@new __sync_and_and_fetch_4, u32, |a: u32, b: u32| a & b); + +atomic_rmw!(@old __sync_fetch_and_or_1, u8, |a: u8, b: u8| a | b); +atomic_rmw!(@old __sync_fetch_and_or_2, u16, |a: u16, b: u16| a | b); +atomic_rmw!(@old __sync_fetch_and_or_4, u32, |a: u32, b: u32| a | b); + +atomic_rmw!(@new __sync_or_and_fetch_1, u8, |a: u8, b: u8| a | b); +atomic_rmw!(@new __sync_or_and_fetch_2, u16, |a: u16, b: u16| a | b); +atomic_rmw!(@new __sync_or_and_fetch_4, u32, |a: u32, b: u32| a | b); + +atomic_rmw!(@old __sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b); +atomic_rmw!(@old __sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b); +atomic_rmw!(@old __sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b); -atomic_rmw!(__sync_fetch_and_or_1, u8, |a: u8, b: u8| a | b); -atomic_rmw!(__sync_fetch_and_or_2, u16, |a: u16, b: u16| a | b); -atomic_rmw!(__sync_fetch_and_or_4, u32, |a: u32, b: u32| a | b); +atomic_rmw!(@new __sync_xor_and_fetch_1, u8, |a: u8, b: u8| a ^ b); +atomic_rmw!(@new __sync_xor_and_fetch_2, u16, |a: u16, b: u16| a ^ b); +atomic_rmw!(@new __sync_xor_and_fetch_4, u32, |a: u32, b: u32| a ^ b); -atomic_rmw!(__sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b); -atomic_rmw!(__sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b); -atomic_rmw!(__sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b); +atomic_rmw!(@old __sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b)); +atomic_rmw!(@old __sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b)); +atomic_rmw!(@old __sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b)); -atomic_rmw!(__sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b)); -atomic_rmw!(__sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b)); -atomic_rmw!(__sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b)); +atomic_rmw!(@new __sync_nand_and_fetch_1, u8, |a: u8, b: u8| !(a & b)); +atomic_rmw!(@new __sync_nand_and_fetch_2, u16, |a: u16, b: u16| !(a & b)); +atomic_rmw!(@new __sync_nand_and_fetch_4, u32, |a: u32, b: u32| !(a & b)); -atomic_rmw!(__sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { +atomic_rmw!(@old __sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { +atomic_rmw!(@old __sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { +atomic_rmw!(@old __sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { +atomic_rmw!(@old __sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { +atomic_rmw!(@old __sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { +atomic_rmw!(@old __sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { +atomic_rmw!(@old __sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { +atomic_rmw!(@old __sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { +atomic_rmw!(@old __sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { +atomic_rmw!(@old __sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { +atomic_rmw!(@old __sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { +atomic_rmw!(@old __sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { a } else { b }); -atomic_rmw!(__sync_lock_test_and_set_1, u8, |_: u8, b: u8| b); -atomic_rmw!(__sync_lock_test_and_set_2, u16, |_: u16, b: u16| b); -atomic_rmw!(__sync_lock_test_and_set_4, u32, |_: u32, b: u32| b); +atomic_rmw!(@old __sync_lock_test_and_set_1, u8, |_: u8, b: u8| b); +atomic_rmw!(@old __sync_lock_test_and_set_2, u16, |_: u16, b: u16| b); +atomic_rmw!(@old __sync_lock_test_and_set_4, u32, |_: u32, b: u32| b); atomic_cmpxchg!(__sync_val_compare_and_swap_1, u8); atomic_cmpxchg!(__sync_val_compare_and_swap_2, u16); -- cgit 1.4.1-3-g733a5 From 4d8d134d103af0e86316acddd4db8b2016376330 Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Fri, 29 Jul 2022 16:52:30 -0700 Subject: Remove panics from tgamma and tgammaf --- library/compiler-builtins/libm/src/math/tgamma.rs | 13 +++++++------ library/compiler-builtins/libm/src/math/tgammaf.rs | 1 + 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs index f8ccf669a25..e64eff61f06 100644 --- a/library/compiler-builtins/libm/src/math/tgamma.rs +++ b/library/compiler-builtins/libm/src/math/tgamma.rs @@ -38,7 +38,7 @@ fn sinpi(mut x: f64) -> f64 { /* reduce x into [-.25,.25] */ n = (4.0 * x) as isize; - n = (n + 1) / 2; + n = div!(n + 1, 2); x -= (n as f64) * 0.5; x *= PI; @@ -118,18 +118,19 @@ fn s(x: f64) -> f64 { /* to avoid overflow handle large x differently */ if x < 8.0 { for i in (0..=N).rev() { - num = num * x + SNUM[i]; - den = den * x + SDEN[i]; + num = num * x + i!(SNUM, i); + den = den * x + i!(SDEN, i); } } else { for i in 0..=N { - num = num / x + SNUM[i]; - den = den / x + SDEN[i]; + num = num / x + i!(SNUM, i); + den = den / x + i!(SDEN, i); } } return num / den; } +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgamma(mut x: f64) -> f64 { let u: u64 = x.to_bits(); let absx: f64; @@ -157,7 +158,7 @@ pub fn tgamma(mut x: f64) -> f64 { return 0.0 / 0.0; } if x <= FACT.len() as f64 { - return FACT[(x as usize) - 1]; + return i!(FACT, (x as usize) - 1); } } diff --git a/library/compiler-builtins/libm/src/math/tgammaf.rs b/library/compiler-builtins/libm/src/math/tgammaf.rs index a8f161f0c1c..23e3814f99f 100644 --- a/library/compiler-builtins/libm/src/math/tgammaf.rs +++ b/library/compiler-builtins/libm/src/math/tgammaf.rs @@ -1,5 +1,6 @@ use super::tgamma; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgammaf(x: f32) -> f32 { tgamma(x as f64) as f32 } -- cgit 1.4.1-3-g733a5 From d9cd50d32f209a34e26c9c7032c3724d3d171482 Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Fri, 29 Jul 2022 17:34:06 -0700 Subject: Update libm --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 1f7b8eb61ca..add735e30df 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 1f7b8eb61cab5f62ec93d2343432bebd1ada30f2 +Subproject commit add735e30df2ba780fb76187f43163dedcd96fa7 -- cgit 1.4.1-3-g733a5 From 365558d74903e88447b40134e94dd0e79ba7d643 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 30 Jul 2022 01:43:36 +0100 Subject: Bump to 0.2.3 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 99055ad47b1..a94a85a26ea 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.2" +version = "0.2.3" edition = "2018" [features] -- cgit 1.4.1-3-g733a5 From 8a9e33297ab2bc21404d43066f3a63cd72c8c755 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 30 Jul 2022 01:45:31 +0100 Subject: Bump to 0.1.78 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index cd471883061..826dee795b4 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.77" +version = "0.1.78" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index add735e30df..d6d8a1610c9 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit add735e30df2ba780fb76187f43163dedcd96fa7 +Subproject commit d6d8a1610c9912c84c4c1d12d994d0204dc702ef -- cgit 1.4.1-3-g733a5 From ada0be15bf8858e313bb2dc0a5283a96c9a12842 Mon Sep 17 00:00:00 2001 From: Outurnate Date: Sun, 31 Jul 2022 14:37:57 -0400 Subject: Use smaller IPIO2 table for 16 and 32 bit architectures --- library/compiler-builtins/libm/src/math/rem_pio2_large.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 65473f0abda..db97a39d490 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -27,7 +27,7 @@ const INIT_JK: [usize; 4] = [3, 4, 4, 6]; // // NB: This table must have at least (e0-3)/24 + jk terms. // For quad precision (e0 <= 16360, jk = 6), this is 686. -#[cfg(target_pointer_width = "32")] +#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] const IPIO2: [i32; 66] = [ 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, -- cgit 1.4.1-3-g733a5 From fecd4045afc6cf00d70403e548348de973535699 Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Sun, 31 Jul 2022 13:57:20 -0700 Subject: Ensure more functions do not panic --- library/compiler-builtins/libm/src/math/acosh.rs | 1 + library/compiler-builtins/libm/src/math/acoshf.rs | 1 + library/compiler-builtins/libm/src/math/asinh.rs | 1 + library/compiler-builtins/libm/src/math/asinhf.rs | 1 + library/compiler-builtins/libm/src/math/atanh.rs | 1 + library/compiler-builtins/libm/src/math/atanhf.rs | 1 + library/compiler-builtins/libm/src/math/copysign.rs | 1 + library/compiler-builtins/libm/src/math/copysignf.rs | 1 + library/compiler-builtins/libm/src/math/erf.rs | 1 + library/compiler-builtins/libm/src/math/erff.rs | 1 + library/compiler-builtins/libm/src/math/exp10.rs | 5 +++-- library/compiler-builtins/libm/src/math/exp10f.rs | 5 +++-- library/compiler-builtins/libm/src/math/ilogb.rs | 1 + library/compiler-builtins/libm/src/math/ilogbf.rs | 1 + library/compiler-builtins/libm/src/math/lgamma.rs | 1 + library/compiler-builtins/libm/src/math/lgamma_r.rs | 3 ++- library/compiler-builtins/libm/src/math/lgammaf.rs | 1 + library/compiler-builtins/libm/src/math/lgammaf_r.rs | 3 ++- library/compiler-builtins/libm/src/math/sincos.rs | 1 + library/compiler-builtins/libm/src/math/sincosf.rs | 1 + 20 files changed, 26 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/acosh.rs b/library/compiler-builtins/libm/src/math/acosh.rs index ac7a5f1c623..d1f5b9fa937 100644 --- a/library/compiler-builtins/libm/src/math/acosh.rs +++ b/library/compiler-builtins/libm/src/math/acosh.rs @@ -7,6 +7,7 @@ const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa3 /// Calculates the inverse hyperbolic cosine of `x`. /// Is defined as `log(x + sqrt(x*x-1))`. /// `x` must be a number greater than or equal to 1. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acosh(x: f64) -> f64 { let u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/acoshf.rs b/library/compiler-builtins/libm/src/math/acoshf.rs index 0879e1edb0a..ad3455fdd48 100644 --- a/library/compiler-builtins/libm/src/math/acoshf.rs +++ b/library/compiler-builtins/libm/src/math/acoshf.rs @@ -7,6 +7,7 @@ const LN2: f32 = 0.693147180559945309417232121458176568; /// Calculates the inverse hyperbolic cosine of `x`. /// Is defined as `log(x + sqrt(x*x-1))`. /// `x` must be a number greater than or equal to 1. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acoshf(x: f32) -> f32 { let u = x.to_bits(); let a = u & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/asinh.rs b/library/compiler-builtins/libm/src/math/asinh.rs index 14295357a55..0abd80c2fd7 100644 --- a/library/compiler-builtins/libm/src/math/asinh.rs +++ b/library/compiler-builtins/libm/src/math/asinh.rs @@ -7,6 +7,7 @@ const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa3 /// /// Calculates the inverse hyperbolic sine of `x`. /// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asinh(mut x: f64) -> f64 { let mut u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/src/math/asinhf.rs index e22a291323f..09c77823e10 100644 --- a/library/compiler-builtins/libm/src/math/asinhf.rs +++ b/library/compiler-builtins/libm/src/math/asinhf.rs @@ -7,6 +7,7 @@ const LN2: f32 = 0.693147180559945309417232121458176568; /// /// Calculates the inverse hyperbolic sine of `x`. /// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asinhf(mut x: f32) -> f32 { let u = x.to_bits(); let i = u & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/atanh.rs b/library/compiler-builtins/libm/src/math/atanh.rs index 79a989c42d1..b984c4ac628 100644 --- a/library/compiler-builtins/libm/src/math/atanh.rs +++ b/library/compiler-builtins/libm/src/math/atanh.rs @@ -5,6 +5,7 @@ use super::log1p; /// /// Calculates the inverse hyperbolic tangent of `x`. /// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atanh(x: f64) -> f64 { let u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs index 7b2f34d97d4..a1aa314a50f 100644 --- a/library/compiler-builtins/libm/src/math/atanhf.rs +++ b/library/compiler-builtins/libm/src/math/atanhf.rs @@ -5,6 +5,7 @@ use super::log1pf; /// /// Calculates the inverse hyperbolic tangent of `x`. /// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atanhf(mut x: f32) -> f32 { let mut u = x.to_bits(); let sign = (u >> 31) != 0; diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs index 1527fb6ea8b..1f4a35a331b 100644 --- a/library/compiler-builtins/libm/src/math/copysign.rs +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -2,6 +2,7 @@ /// /// Constructs a number with the magnitude (absolute value) of its /// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn copysign(x: f64, y: f64) -> f64 { let mut ux = x.to_bits(); let uy = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs index 35148561a86..6c346e3a528 100644 --- a/library/compiler-builtins/libm/src/math/copysignf.rs +++ b/library/compiler-builtins/libm/src/math/copysignf.rs @@ -2,6 +2,7 @@ /// /// Constructs a number with the magnitude (absolute value) of its /// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn copysignf(x: f32, y: f32) -> f32 { let mut ux = x.to_bits(); let uy = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs index a2c617d341d..5e21ba578df 100644 --- a/library/compiler-builtins/libm/src/math/erf.rs +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -219,6 +219,7 @@ fn erfc2(ix: u32, mut x: f64) -> f64 { /// Calculates an approximation to the “error function”, which estimates /// the probability that an observation will fall within x standard /// deviations of the mean (assuming a normal distribution). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn erf(x: f64) -> f64 { let r: f64; let s: f64; diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs index 384052293fe..f74d4b63249 100644 --- a/library/compiler-builtins/libm/src/math/erff.rs +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -130,6 +130,7 @@ fn erfc2(mut ix: u32, mut x: f32) -> f32 { /// Calculates an approximation to the “error function”, which estimates /// the probability that an observation will fall within x standard /// deviations of the mean (assuming a normal distribution). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn erff(x: f32) -> f32 { let r: f32; let s: f32; diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs index 9537f76f136..559930e109f 100644 --- a/library/compiler-builtins/libm/src/math/exp10.rs +++ b/library/compiler-builtins/libm/src/math/exp10.rs @@ -6,16 +6,17 @@ const P10: &[f64] = &[ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, ]; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp10(x: f64) -> f64 { let (mut y, n) = modf(x); let u: u64 = n.to_bits(); /* fabs(n) < 16 without raising invalid on nan */ if (u >> 52 & 0x7ff) < 0x3ff + 4 { if y == 0.0 { - return P10[((n as isize) + 15) as usize]; + return i!(P10, ((n as isize) + 15) as usize); } y = exp2(LN10 * y); - return y * P10[((n as isize) + 15) as usize]; + return y * i!(P10, ((n as isize) + 15) as usize); } return pow(10.0, x); } diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs index d45fff36ea3..1279bc6c566 100644 --- a/library/compiler-builtins/libm/src/math/exp10f.rs +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -6,16 +6,17 @@ const P10: &[f32] = &[ 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, ]; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp10f(x: f32) -> f32 { let (mut y, n) = modff(x); let u = n.to_bits(); /* fabsf(n) < 8 without raising invalid on nan */ if (u >> 23 & 0xff) < 0x7f + 3 { if y == 0.0 { - return P10[((n as isize) + 7) as usize]; + return i!(P10, ((n as isize) + 7) as usize); } y = exp2f(LN10_F32 * y); - return y * P10[((n as isize) + 7) as usize]; + return y * i!(P10, ((n as isize) + 7) as usize); } return exp2(LN10_F64 * (x as f64)) as f32; } diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs index 0a380b7efd3..7d74dcfb666 100644 --- a/library/compiler-builtins/libm/src/math/ilogb.rs +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -1,6 +1,7 @@ const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; const FP_ILOGB0: i32 = FP_ILOGBNAN; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ilogb(x: f64) -> i32 { let mut i: u64 = x.to_bits(); let e = ((i >> 52) & 0x7ff) as i32; diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs index b384fa4b20d..0fa58748c2f 100644 --- a/library/compiler-builtins/libm/src/math/ilogbf.rs +++ b/library/compiler-builtins/libm/src/math/ilogbf.rs @@ -1,6 +1,7 @@ const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; const FP_ILOGB0: i32 = FP_ILOGBNAN; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ilogbf(x: f32) -> i32 { let mut i = x.to_bits(); let e = ((i >> 23) & 0xff) as i32; diff --git a/library/compiler-builtins/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/src/math/lgamma.rs index 5bc87e85e8c..a08bc5b641e 100644 --- a/library/compiler-builtins/libm/src/math/lgamma.rs +++ b/library/compiler-builtins/libm/src/math/lgamma.rs @@ -1,5 +1,6 @@ use super::lgamma_r; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgamma(x: f64) -> f64 { lgamma_r(x).0 } diff --git a/library/compiler-builtins/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/src/math/lgamma_r.rs index 9533e882cc9..b26177e6ebf 100644 --- a/library/compiler-builtins/libm/src/math/lgamma_r.rs +++ b/library/compiler-builtins/libm/src/math/lgamma_r.rs @@ -152,7 +152,7 @@ fn sin_pi(mut x: f64) -> f64 { x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ n = (x * 4.0) as i32; - n = (n + 1) / 2; + n = div!(n + 1, 2); x -= (n as f64) * 0.5; x *= PI; @@ -164,6 +164,7 @@ fn sin_pi(mut x: f64) -> f64 { } } +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgamma_r(mut x: f64) -> (f64, i32) { let u: u64 = x.to_bits(); let mut t: f64; diff --git a/library/compiler-builtins/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/src/math/lgammaf.rs index dfdc87f9622..a9c2da75bd7 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf.rs @@ -1,5 +1,6 @@ use super::lgammaf_r; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgammaf(x: f32) -> f32 { lgammaf_r(x).0 } diff --git a/library/compiler-builtins/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/src/math/lgammaf_r.rs index c5e559f4652..723c90daf1e 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf_r.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf_r.rs @@ -88,7 +88,7 @@ fn sin_pi(mut x: f32) -> f32 { x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ n = (x * 4.0) as isize; - n = (n + 1) / 2; + n = div!(n + 1, 2); y = (x as f64) - (n as f64) * 0.5; y *= 3.14159265358979323846; match n { @@ -99,6 +99,7 @@ fn sin_pi(mut x: f32) -> f32 { } } +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgammaf_r(mut x: f32) -> (f32, i32) { let u = x.to_bits(); let mut t: f32; diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs index 4ab588412a5..ff5d87a1c60 100644 --- a/library/compiler-builtins/libm/src/math/sincos.rs +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -12,6 +12,7 @@ use super::{get_high_word, k_cos, k_sin, rem_pio2}; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincos(x: f64) -> (f64, f64) { let s: f64; let c: f64; diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index 5304e8ca027..9a4c36104e9 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -23,6 +23,7 @@ const S2PIO2: f32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ const S3PIO2: f32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ const S4PIO2: f32 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincosf(x: f32) -> (f32, f32) { let s: f32; let c: f32; -- cgit 1.4.1-3-g733a5 From abb6893a85b99defdbf6acd569d7f7151bfd67d8 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 31 Jul 2022 11:07:33 -0400 Subject: Enable unadjusted_on_win64 for UEFI in some cases The conversion functions from i128/u128 to f32/f64 have the `unadjusted_on_win64` attribute, but it is disabled starting with LLVM14. This seems to be the correct thing to do for Win64, but for some reason x86_64-unknown-uefi is different, despite generally using the same ABI as Win64. --- library/compiler-builtins/src/float/conv.rs | 8 ++++---- library/compiler-builtins/src/macros.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 07b58f3d232..68ba63408e9 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -92,12 +92,12 @@ intrinsics! { f64::from_bits(int_to_float::u64_to_f64_bits(i)) } - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] pub extern "C" fn __floatuntisf(i: u128) -> f32 { f32::from_bits(int_to_float::u128_to_f32_bits(i)) } - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] pub extern "C" fn __floatuntidf(i: u128) -> f64 { f64::from_bits(int_to_float::u128_to_f64_bits(i)) } @@ -129,13 +129,13 @@ intrinsics! { f64::from_bits(int_to_float::u64_to_f64_bits(i.unsigned_abs()) | sign_bit) } - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] pub extern "C" fn __floattisf(i: i128) -> f32 { let sign_bit = ((i >> 127) as u32) << 31; f32::from_bits(int_to_float::u128_to_f32_bits(i.unsigned_abs()) | sign_bit) } - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] pub extern "C" fn __floattidf(i: i128) -> f64 { let sign_bit = ((i >> 127) as u64) << 63; f64::from_bits(int_to_float::u128_to_f64_bits(i.unsigned_abs()) | sign_bit) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 6acf1be969e..7d90b7aadbe 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -174,7 +174,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(windows, target_pointer_width = "64"))] + #[cfg(all(any(windows, all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64"))] intrinsics! { $(#[$($attr)*])* pub extern "unadjusted" fn $name( $($argname: $ty),* ) $(-> $ret)? { @@ -182,7 +182,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(windows, target_pointer_width = "64")))] + #[cfg(not(all(any(windows, all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64")))] intrinsics! { $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { -- cgit 1.4.1-3-g733a5 From 142261c91cba56c32c1554d67de8561d71d48631 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 10 Aug 2022 01:11:33 +0100 Subject: Fix fmaf not to depend on FE_TOWARDZERO Ported from upstream musl commit 4f3d346bffdf9ed2b1803653643dc31242490944 Fixes rust-lang/libm#263 --- library/compiler-builtins/libm/src/math/fenv.rs | 6 ----- library/compiler-builtins/libm/src/math/fmaf.rs | 35 ++++++++++++++++--------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fenv.rs b/library/compiler-builtins/libm/src/math/fenv.rs index 652e6032452..c91272e8268 100644 --- a/library/compiler-builtins/libm/src/math/fenv.rs +++ b/library/compiler-builtins/libm/src/math/fenv.rs @@ -5,7 +5,6 @@ pub(crate) const FE_UNDERFLOW: i32 = 0; pub(crate) const FE_INEXACT: i32 = 0; pub(crate) const FE_TONEAREST: i32 = 0; -pub(crate) const FE_TOWARDZERO: i32 = 0; #[inline] pub(crate) fn feclearexcept(_mask: i32) -> i32 { @@ -26,8 +25,3 @@ pub(crate) fn fetestexcept(_mask: i32) -> i32 { pub(crate) fn fegetround() -> i32 { FE_TONEAREST } - -#[inline] -pub(crate) fn fesetround(_r: i32) -> i32 { - 0 -} diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index 03d371c55f2..2848f2aee0c 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -29,8 +29,7 @@ use core::f32; use core::ptr::read_volatile; use super::fenv::{ - feclearexcept, fegetround, feraiseexcept, fesetround, fetestexcept, FE_INEXACT, FE_TONEAREST, - FE_TOWARDZERO, FE_UNDERFLOW, + feclearexcept, fegetround, feraiseexcept, fetestexcept, FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, }; /* @@ -91,16 +90,28 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { * If result is inexact, and exactly halfway between two float values, * we need to adjust the low-order bit in the direction of the error. */ - fesetround(FE_TOWARDZERO); - // prevent `vxy + z` from being CSE'd with `xy + z` above - let vxy: f64 = unsafe { read_volatile(&xy) }; - let mut adjusted_result: f64 = vxy + z as f64; - fesetround(FE_TONEAREST); - if result == adjusted_result { - ui = adjusted_result.to_bits(); + let neg = ui >> 63 != 0; + let err = if neg == (z as f64 > xy) { + xy - result + z as f64 + } else { + z as f64 - result + xy + }; + if neg == (err < 0.0) { ui += 1; - adjusted_result = f64::from_bits(ui); + } else { + ui -= 1; + } + f64::from_bits(ui) as f32 +} + +#[cfg(test)] +mod tests { + #[test] + fn issue_263() { + let a = f32::from_bits(1266679807); + let b = f32::from_bits(1300234242); + let c = f32::from_bits(1115553792); + let expected = f32::from_bits(1501560833); + assert_eq!(super::fmaf(a, b, c), expected); } - z = adjusted_result as f32; - z } -- cgit 1.4.1-3-g733a5 From a695cf95cfd6a2067f1068384a9ee98c94a3a492 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Wed, 10 Aug 2022 11:29:38 +0200 Subject: Remove c32() from x86_64 memcmp Fixes https://github.com/rust-lang/compiler-builtins/issues/487 --- library/compiler-builtins/src/mem/x86_64.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index dd98e37c5f0..17b461f7914 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -170,19 +170,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { let c4 = |a: *const u32, b, n| cmp(a, b, n, c2); let c8 = |a: *const u64, b, n| cmp(a, b, n, c4); let c16 = |a: *const u128, b, n| cmp(a, b, n, c8); - let c32 = |a: *const [u128; 2], b, n| cmp(a, b, n, c16); - // [u128; 2] internally uses raw_eq for comparisons, which may emit a call to memcmp - // above a certain size threshold. When SSE2 is enabled this threshold does not seem - // to be reached but without SSE2 a call is emitted, leading to infinite recursion. - // - // While replacing [u128; 2] with (u128, u128) fixes the issues it degrades performance - // severely. Likewise, removing c32() has a lesser but still significant impact. Instead the - // [u128; 2] case is only enabled when SSE2 is present. - if cfg!(target_feature = "sse2") { - c32(a.cast(), b.cast(), n) - } else { - c16(a.cast(), b.cast(), n) - } + c16(a.cast(), b.cast(), n) } /// Determine optimal parameters for a `rep` instruction. -- cgit 1.4.1-3-g733a5 From 8b42fe77b7485de7a4215dba8b13402deaaacc65 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 10 Aug 2022 15:23:56 +0100 Subject: Bump to 0.2.5 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index a94a85a26ea..527c383b99f 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.3" +version = "0.2.5" edition = "2018" [features] -- cgit 1.4.1-3-g733a5 From 1eb4cc19776282cfee7be880749ff7cd6786371f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 10 Aug 2022 15:19:30 +0100 Subject: Update libm submodule --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index d6d8a1610c9..14a76eaf8da 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit d6d8a1610c9912c84c4c1d12d994d0204dc702ef +Subproject commit 14a76eaf8dab437e92c5fc505c48fb4ed0eb3483 -- cgit 1.4.1-3-g733a5 From 83c4ff5f9672683bdcc45188f39d48c58d60c150 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 10 Aug 2022 15:28:39 +0100 Subject: Bump to 0.1.79 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 826dee795b4..26258dd4f94 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.78" +version = "0.1.79" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 1d5b9521002e6b8c6a3beba995d767f29ec82ff9 Mon Sep 17 00:00:00 2001 From: D1plo1d Date: Sat, 17 Sep 2022 11:47:21 -0400 Subject: math: Enabled floating point intrinsics for RISCV32 microcontrollers --- library/compiler-builtins/src/math.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index fa983618695..3fc33b12738 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -118,8 +118,11 @@ no_mangle! { fn truncf(x: f32) -> f32; } -// only for the thumb*-none-eabi* targets -#[cfg(all(target_arch = "arm", target_os = "none"))] +// only for the thumb*-none-eabi* targets and riscv32*-none-elf targets that lack the floating point instruction set +#[cfg(any( + all(target_arch = "arm", target_os = "none"), + all(target_arch = "riscv32", not(target_feature = "f"), target_os = "none") +))] no_mangle! { fn fmin(x: f64, y: f64) -> f64; fn fminf(x: f32, y: f32) -> f32; -- cgit 1.4.1-3-g733a5 From 4c8bb40c8df0313192982a7df6e19338c1a74c49 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 20 Sep 2022 16:20:52 +0800 Subject: Bump to 0.1.80 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 26258dd4f94..f44b8e1113c 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.79" +version = "0.1.80" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From f6cd5cf8060b82911c3e549d468e919e86b2d64a Mon Sep 17 00:00:00 2001 From: Lokathor Date: Tue, 27 Sep 2022 13:22:45 -0600 Subject: Update macros.rs --- library/compiler-builtins/src/macros.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 7d90b7aadbe..477c2568431 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -266,6 +266,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] pub mod $alias { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } -- cgit 1.4.1-3-g733a5 From 8bc227d1fe7cbffd1c742bbf93a02eb4597e25bd Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 29 Sep 2022 03:16:50 +0100 Subject: Bump to 0.1.81 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f44b8e1113c..5c8ea2597c9 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.80" +version = "0.1.81" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 98e9ab973a653aaa70d29dd7d5af759ae262d854 Mon Sep 17 00:00:00 2001 From: Andrew Tribick Date: Fri, 30 Sep 2022 14:11:15 +0200 Subject: Use wrapping_neg() to avoid fma errors on underflow --- library/compiler-builtins/libm/src/math/fma.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 516f9ad3a77..f9a86dc6063 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -126,8 +126,8 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { rlo = res; rhi = rhi.wrapping_sub(zhi.wrapping_add(borrow as u64)); if (rhi >> 63) != 0 { - rlo = (-(rlo as i64)) as u64; - rhi = (-(rhi as i64)) as u64 - (rlo != 0) as u64; + rlo = (rlo as i64).wrapping_neg() as u64; + rhi = (rhi as i64).wrapping_neg() as u64 - (rlo != 0) as u64; sign = (sign == 0) as i32; } nonzero = (rhi != 0) as i32; @@ -232,4 +232,12 @@ mod tests { -3991680619069439e277 ); } + + #[test] + fn fma_underflow() { + assert_eq!( + fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), + 0.0, + ); + } } -- cgit 1.4.1-3-g733a5 From 2e0590c997215db442213b19db6b0ff7e0605d7b Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 10 Oct 2022 17:40:16 +0100 Subject: Fix clippy lints --- library/compiler-builtins/src/float/conv.rs | 6 +++--- library/compiler-builtins/src/float/div.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 68ba63408e9..19fdc2fdc69 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -13,7 +13,7 @@ mod int_to_float { let a = (i << n) >> 8; // Significant bits, with bit 24 still in tact. let b = (i << n) << 24; // Insignificant bits, only relevant for rounding. let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. - let e = 157 - n as u32; // Exponent plus 127, minus one. + let e = 157 - n; // Exponent plus 127, minus one. (e << 23) + m // + not |, so the mantissa can overflow into the exponent. } @@ -42,8 +42,8 @@ mod int_to_float { return 0; } let n = i.leading_zeros(); - let a = ((i << n) >> 11) as u64; // Significant bits, with bit 53 still in tact. - let b = ((i << n) << 53) as u64; // Insignificant bits, only relevant for rounding. + let a = (i << n) >> 11; // Significant bits, with bit 53 still in tact. + let b = (i << n) << 53; // Insignificant bits, only relevant for rounding. let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even. let e = 1085 - n as u64; // Exponent plus 1023, minus one. (e << 52) + m // + not |, so the mantissa can overflow into the exponent. diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 528a8368d92..c2d6c07e73d 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -135,11 +135,11 @@ where let mut correction: u32 = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); - reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; + reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) >> 31) as u32; correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); - reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; + reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) >> 31) as u32; correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); - reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; + reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) >> 31) as u32; // Exhaustive testing shows that the error in reciprocal after three steps // is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our -- cgit 1.4.1-3-g733a5 From 626754531561adee4f076916fc6cb029b5f59e27 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Oct 2022 14:58:18 +0200 Subject: invoke the unreachable intrinsic, not the stable wrapper --- library/compiler-builtins/src/int/specialized_div_rem/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 6ec4675df94..77034eb5476 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -72,7 +72,10 @@ mod asymmetric; /// impossible to reach by Rust users, unless `compiler-builtins` public division functions or /// `core/std::unchecked_div/rem` are directly used without a zero check in front. fn zero_div_fn() -> ! { - unsafe { core::hint::unreachable_unchecked() } + // Calling the intrinsic directly, to avoid the `assert_unsafe_precondition` that cannot be used + // here because it involves non-`inline` functions + // (https://github.com/rust-lang/compiler-builtins/issues/491). + unsafe { core::intrinsics::unreachable() } } const USE_LZ: bool = { -- cgit 1.4.1-3-g733a5 From 6f53a4f0749f19a0bc309daa5eb900563f296413 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 10 Oct 2022 19:04:06 +0100 Subject: Bump to 0.1.82 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 5c8ea2597c9..fb113b922be 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.81" +version = "0.1.82" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 8266a1343b3ee164da223f9f034562ba1aa44d45 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 25 Oct 2022 11:25:14 -0400 Subject: Document origins of the multiplication method being used here. --- library/compiler-builtins/src/riscv.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/riscv.rs b/library/compiler-builtins/src/riscv.rs index ee78b9dbacf..eff249692ce 100644 --- a/library/compiler-builtins/src/riscv.rs +++ b/library/compiler-builtins/src/riscv.rs @@ -1,5 +1,18 @@ intrinsics! { - // Implementation from gcc + // Ancient Egyptian/Ethiopian/Russian multiplication method + // see https://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication + // + // This is a long-available stock algorithm; e.g. it is documented in + // Knuth's "The Art of Computer Programming" volume 2 (under the section + // "Evaluation of Powers") since at least the 2nd edition (1981). + // + // The main attraction of this method is that it implements (software) + // multiplication atop four simple operations: doubling, halving, checking + // if a value is even/odd, and addition. This is *not* considered to be the + // fastest multiplication method, but it may be amongst the simplest (and + // smallest with respect to code size). + // + // for reference, see also implementation from gcc // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { let (mut a, mut b) = (a, b); -- cgit 1.4.1-3-g733a5 From 2faf57c08da1098b16591430940a07fa865b2e98 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 25 Oct 2022 12:32:41 -0400 Subject: might as well add the link to the LLVM assembly code as well. --- library/compiler-builtins/src/riscv.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/src/riscv.rs b/library/compiler-builtins/src/riscv.rs index eff249692ce..ae361b33acf 100644 --- a/library/compiler-builtins/src/riscv.rs +++ b/library/compiler-builtins/src/riscv.rs @@ -14,6 +14,9 @@ intrinsics! { // // for reference, see also implementation from gcc // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c + // + // and from LLVM (in relatively readable RISC-V assembly): + // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/riscv/int_mul_impl.inc pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { let (mut a, mut b) = (a, b); let mut r = 0; -- cgit 1.4.1-3-g733a5 From e3efddc2c25b36408fa5184b6bc8c7700d32b2a4 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 7 Nov 2022 12:34:47 -0500 Subject: Add `roundeven` and `roundevenf` --- library/compiler-builtins/libm/build.rs | 3 ++ library/compiler-builtins/libm/src/math/mod.rs | 4 ++ .../compiler-builtins/libm/src/math/roundeven.rs | 50 ++++++++++++++++++++++ .../compiler-builtins/libm/src/math/roundevenf.rs | 50 ++++++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/roundeven.rs create mode 100644 library/compiler-builtins/libm/src/math/roundevenf.rs diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 80145a9ccac..403304a1383 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -39,6 +39,9 @@ mod musl_reference_tests { "jnf.rs", "j1.rs", "j1f.rs", + // musl doens't have these + "roundeven.rs", + "roundevenf.rs", ]; struct Function { diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 81bfc53ed85..e710bd381bc 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -171,6 +171,8 @@ mod remainderf; mod remquo; mod remquof; mod round; +mod roundeven; +mod roundevenf; mod roundf; mod scalbn; mod scalbnf; @@ -285,6 +287,8 @@ pub use self::remainderf::remainderf; pub use self::remquo::remquo; pub use self::remquof::remquof; pub use self::round::round; +pub use self::roundeven::roundeven; +pub use self::roundevenf::roundevenf; pub use self::roundf::roundf; pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; diff --git a/library/compiler-builtins/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/src/math/roundeven.rs new file mode 100644 index 00000000000..5cc30c8af82 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundeven.rs @@ -0,0 +1,50 @@ +// Source: musl libm rint +// (equivalent to roundeven when rounding mode is default, +// which Rust assumes) + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundeven(x: f64) -> f64 { + let one_over_e = 1.0 / f64::EPSILON; + let as_u64: u64 = x.to_bits(); + let exponent: u64 = as_u64 >> 52 & 0x7ff; + let is_positive = (as_u64 >> 63) == 0; + if exponent >= 0x3ff + 52 { + x + } else { + let ans = if is_positive { + x + one_over_e - one_over_e + } else { + x - one_over_e + one_over_e + }; + + if ans == 0.0 { + if is_positive { + 0.0 + } else { + -0.0 + } + } else { + ans + } + } +} + +#[cfg(test)] +mod tests { + use super::roundeven; + + #[test] + fn negative_zero() { + assert_eq!(roundeven(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); + } + + #[test] + fn sanity_check() { + assert_eq!(roundeven(-1.0), -1.0); + assert_eq!(roundeven(2.8), 3.0); + assert_eq!(roundeven(-0.5), -0.0); + assert_eq!(roundeven(0.5), 0.0); + assert_eq!(roundeven(-1.5), -2.0); + assert_eq!(roundeven(1.5), 2.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/roundevenf.rs b/library/compiler-builtins/libm/src/math/roundevenf.rs new file mode 100644 index 00000000000..e720dcd9478 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundevenf.rs @@ -0,0 +1,50 @@ +// Source: musl libm rintf +// (equivalent to roundevenf when rounding mode is default, +// which Rust assumes) + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf(x: f32) -> f32 { + let one_over_e = 1.0 / f32::EPSILON; + let as_u32: u32 = x.to_bits(); + let exponent: u32 = as_u32 >> 23 & 0xff; + let is_positive = (as_u32 >> 31) == 0; + if exponent >= 0x7f + 23 { + x + } else { + let ans = if is_positive { + x + one_over_e - one_over_e + } else { + x - one_over_e + one_over_e + }; + + if ans == 0.0 { + if is_positive { + 0.0 + } else { + -0.0 + } + } else { + ans + } + } +} + +#[cfg(test)] +mod tests { + use super::roundevenf; + + #[test] + fn negative_zero() { + assert_eq!(roundevenf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); + } + + #[test] + fn sanity_check() { + assert_eq!(roundevenf(-1.0), -1.0); + assert_eq!(roundevenf(2.8), 3.0); + assert_eq!(roundevenf(-0.5), -0.0); + assert_eq!(roundevenf(0.5), 0.0); + assert_eq!(roundevenf(-1.5), -2.0); + assert_eq!(roundevenf(1.5), 2.0); + } +} -- cgit 1.4.1-3-g733a5 From 292221cf4c1055850c219f141525c7cfade0cab6 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 7 Nov 2022 12:53:26 -0500 Subject: `rint`/`rintf` instead of `roundeven`/`roundevenf` --- library/compiler-builtins/libm/build.rs | 3 -- library/compiler-builtins/libm/src/math/mod.rs | 8 ++-- library/compiler-builtins/libm/src/math/rint.rs | 46 ++++++++++++++++++++ library/compiler-builtins/libm/src/math/rintf.rs | 46 ++++++++++++++++++++ .../compiler-builtins/libm/src/math/roundeven.rs | 50 ---------------------- .../compiler-builtins/libm/src/math/roundevenf.rs | 50 ---------------------- 6 files changed, 96 insertions(+), 107 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/rint.rs create mode 100644 library/compiler-builtins/libm/src/math/rintf.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundeven.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundevenf.rs diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 403304a1383..80145a9ccac 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -39,9 +39,6 @@ mod musl_reference_tests { "jnf.rs", "j1.rs", "j1f.rs", - // musl doens't have these - "roundeven.rs", - "roundevenf.rs", ]; struct Function { diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e710bd381bc..05ebb708c9c 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -170,9 +170,9 @@ mod remainder; mod remainderf; mod remquo; mod remquof; +mod rint; +mod rintf; mod round; -mod roundeven; -mod roundevenf; mod roundf; mod scalbn; mod scalbnf; @@ -286,9 +286,9 @@ pub use self::remainder::remainder; pub use self::remainderf::remainderf; pub use self::remquo::remquo; pub use self::remquof::remquof; +pub use self::rint::rint; +pub use self::rintf::rintf; pub use self::round::round; -pub use self::roundeven::roundeven; -pub use self::roundevenf::roundevenf; pub use self::roundf::roundf; pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs new file mode 100644 index 00000000000..97d167ab835 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -0,0 +1,46 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rint(x: f64) -> f64 { + let one_over_e = 1.0 / f64::EPSILON; + let as_u64: u64 = x.to_bits(); + let exponent: u64 = as_u64 >> 52 & 0x7ff; + let is_positive = (as_u64 >> 63) == 0; + if exponent >= 0x3ff + 52 { + x + } else { + let ans = if is_positive { + x + one_over_e - one_over_e + } else { + x - one_over_e + one_over_e + }; + + if ans == 0.0 { + if is_positive { + 0.0 + } else { + -0.0 + } + } else { + ans + } + } +} + +#[cfg(test)] +mod tests { + use super::rint; + + #[test] + fn negative_zero() { + assert_eq!(rint(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); + } + + #[test] + fn sanity_check() { + assert_eq!(rint(-1.0), -1.0); + assert_eq!(rint(2.8), 3.0); + assert_eq!(rint(-0.5), -0.0); + assert_eq!(rint(0.5), 0.0); + assert_eq!(rint(-1.5), -2.0); + assert_eq!(rint(1.5), 2.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs new file mode 100644 index 00000000000..7b87fafb3c5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -0,0 +1,46 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf(x: f32) -> f32 { + let one_over_e = 1.0 / f32::EPSILON; + let as_u32: u32 = x.to_bits(); + let exponent: u32 = as_u32 >> 23 & 0xff; + let is_positive = (as_u32 >> 31) == 0; + if exponent >= 0x7f + 23 { + x + } else { + let ans = if is_positive { + x + one_over_e - one_over_e + } else { + x - one_over_e + one_over_e + }; + + if ans == 0.0 { + if is_positive { + 0.0 + } else { + -0.0 + } + } else { + ans + } + } +} + +#[cfg(test)] +mod tests { + use super::rintf; + + #[test] + fn negative_zero() { + assert_eq!(rintf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); + } + + #[test] + fn sanity_check() { + assert_eq!(rintf(-1.0), -1.0); + assert_eq!(rintf(2.8), 3.0); + assert_eq!(rintf(-0.5), -0.0); + assert_eq!(rintf(0.5), 0.0); + assert_eq!(rintf(-1.5), -2.0); + assert_eq!(rintf(1.5), 2.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/src/math/roundeven.rs deleted file mode 100644 index 5cc30c8af82..00000000000 --- a/library/compiler-builtins/libm/src/math/roundeven.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Source: musl libm rint -// (equivalent to roundeven when rounding mode is default, -// which Rust assumes) - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundeven(x: f64) -> f64 { - let one_over_e = 1.0 / f64::EPSILON; - let as_u64: u64 = x.to_bits(); - let exponent: u64 = as_u64 >> 52 & 0x7ff; - let is_positive = (as_u64 >> 63) == 0; - if exponent >= 0x3ff + 52 { - x - } else { - let ans = if is_positive { - x + one_over_e - one_over_e - } else { - x - one_over_e + one_over_e - }; - - if ans == 0.0 { - if is_positive { - 0.0 - } else { - -0.0 - } - } else { - ans - } - } -} - -#[cfg(test)] -mod tests { - use super::roundeven; - - #[test] - fn negative_zero() { - assert_eq!(roundeven(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(roundeven(-1.0), -1.0); - assert_eq!(roundeven(2.8), 3.0); - assert_eq!(roundeven(-0.5), -0.0); - assert_eq!(roundeven(0.5), 0.0); - assert_eq!(roundeven(-1.5), -2.0); - assert_eq!(roundeven(1.5), 2.0); - } -} diff --git a/library/compiler-builtins/libm/src/math/roundevenf.rs b/library/compiler-builtins/libm/src/math/roundevenf.rs deleted file mode 100644 index e720dcd9478..00000000000 --- a/library/compiler-builtins/libm/src/math/roundevenf.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Source: musl libm rintf -// (equivalent to roundevenf when rounding mode is default, -// which Rust assumes) - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundevenf(x: f32) -> f32 { - let one_over_e = 1.0 / f32::EPSILON; - let as_u32: u32 = x.to_bits(); - let exponent: u32 = as_u32 >> 23 & 0xff; - let is_positive = (as_u32 >> 31) == 0; - if exponent >= 0x7f + 23 { - x - } else { - let ans = if is_positive { - x + one_over_e - one_over_e - } else { - x - one_over_e + one_over_e - }; - - if ans == 0.0 { - if is_positive { - 0.0 - } else { - -0.0 - } - } else { - ans - } - } -} - -#[cfg(test)] -mod tests { - use super::roundevenf; - - #[test] - fn negative_zero() { - assert_eq!(roundevenf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(roundevenf(-1.0), -1.0); - assert_eq!(roundevenf(2.8), 3.0); - assert_eq!(roundevenf(-0.5), -0.0); - assert_eq!(roundevenf(0.5), 0.0); - assert_eq!(roundevenf(-1.5), -2.0); - assert_eq!(roundevenf(1.5), 2.0); - } -} -- cgit 1.4.1-3-g733a5 From 83524d4aa286c80207b4742cb49b96e3c452d521 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 7 Nov 2022 13:19:05 -0500 Subject: Disable tests on PowerPC --- library/compiler-builtins/libm/src/math/rint.rs | 2 ++ library/compiler-builtins/libm/src/math/rintf.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 97d167ab835..0c6025c1f73 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -25,6 +25,8 @@ pub fn rint(x: f64) -> f64 { } } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::rint; diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 7b87fafb3c5..d427793f7fc 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -25,6 +25,8 @@ pub fn rintf(x: f32) -> f32 { } } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::rintf; -- cgit 1.4.1-3-g733a5 From 90128a1abb9b1a30c3b4dcc322ba408d6d5e24e6 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 7 Nov 2022 23:43:14 -0500 Subject: Add benchmarks --- library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs b/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs index b6d8741531f..ca999b90f27 100644 --- a/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs +++ b/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs @@ -107,7 +107,8 @@ macro_rules! bessel { unary!( acos, acosh, asin, atan, cbrt, ceil, cos, cosh, erf, exp, exp2, exp10, expm1, fabs, floor, j0, - j1, lgamma, log, log1p, log2, log10, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc, y0, y1 + j1, lgamma, log, log1p, log2, log10, rint, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc, + y0, y1 ); binary!(atan2, copysign, fdim, fmax, fmin, fmod, hypot, pow); trinary!(fma); -- cgit 1.4.1-3-g733a5 From 53dec2fc63522c995dbdc82f3b8bedf6eedfe119 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 9 Nov 2022 01:30:02 +0000 Subject: Bump to 0.2.6 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 527c383b99f..f942fdec3c9 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.5" +version = "0.2.6" edition = "2018" [features] -- cgit 1.4.1-3-g733a5 From af5664be846f41ebd0a48725936ac489f10d57c1 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Tue, 8 Nov 2022 21:02:21 -0500 Subject: Update `libm`, add `rint` and `rintf` --- library/compiler-builtins/libm | 2 +- library/compiler-builtins/src/math.rs | 16 ++-------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 14a76eaf8da..4c8a973741c 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 14a76eaf8dab437e92c5fc505c48fb4ed0eb3483 +Subproject commit 4c8a973741c014b11ce7f1477693a3e5d4ef9609 diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 3fc33b12738..4ae174891c2 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -46,6 +46,8 @@ no_mangle! { fn fmaxf(x: f32, y: f32) -> f32; fn round(x: f64) -> f64; fn roundf(x: f32) -> f32; + fn rint(x: f64) -> f64; + fn rintf(x: f32) -> f32; fn sin(x: f64) -> f64; fn pow(x: f64, y: f64) -> f64; fn powf(x: f32, y: f32) -> f32; @@ -65,20 +67,6 @@ no_mangle! { fn ldexpf(f: f32, n: i32) -> f32; fn tgamma(x: f64) -> f64; fn tgammaf(x: f32) -> f32; -} - -#[cfg(any( - all( - target_family = "wasm", - target_os = "unknown", - not(target_env = "wasi") - ), - target_os = "xous", - all(target_arch = "x86_64", target_os = "uefi"), - all(target_arch = "xtensa", target_os = "none"), - all(target_vendor = "fortanix", target_env = "sgx") -))] -no_mangle! { fn atan(x: f64) -> f64; fn atan2(x: f64, y: f64) -> f64; fn cosh(x: f64) -> f64; -- cgit 1.4.1-3-g733a5 From a996f56f5a4fbfe42ad34373d6b5ab28458321df Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 9 Nov 2022 04:12:51 +0000 Subject: Bump to 0.1.83 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index fb113b922be..092460e4254 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.82" +version = "0.1.83" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 524ca7ceb6111681fae7ffa73491d477d008ea3c Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 12 Nov 2022 12:06:04 -0500 Subject: Remove unused `no-lang-items` feature --- library/compiler-builtins/Cargo.toml | 3 --- library/compiler-builtins/testcrate/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 092460e4254..36c1f8a08df 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -58,9 +58,6 @@ mem = [] # compiler-rt implementations. Also used for testing mangled-names = [] -# Don't generate lang items for i128 intrisnics and such -no-lang-items = [] - # Only used in the compiler's build system rustc-dep-of-std = ['compiler-builtins', 'core'] diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 1f77b255491..762d3293b2b 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -17,7 +17,7 @@ rand_xoshiro = "0.6" [dependencies.compiler_builtins] path = ".." default-features = false -features = ["no-lang-items", "public-test-deps"] +features = ["public-test-deps"] [target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] test = { git = "https://github.com/japaric/utest" } -- cgit 1.4.1-3-g733a5 From 95c860d1bf676ec1652f069a30a060db0ded9355 Mon Sep 17 00:00:00 2001 From: Luc Date: Mon, 14 Nov 2022 16:49:43 +0100 Subject: Add Small Conformance tests to Sqrt(f) --- library/compiler-builtins/libm/src/math/sqrt.rs | 12 ++++++++++++ library/compiler-builtins/libm/src/math/sqrtf.rs | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index f06b209a49f..9a700d8ea0f 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -261,4 +261,16 @@ mod tests { assert_eq!(sqrt(f), f); } } + + #[test] + fn conformance_tests() { + let values = [3.14159265359, 10000.0, -1.0, INFINITY]; + let results = [4610661241675116657u64, 4636737291354636288u64, + 18444492273895866368u64, 9218868437227405312u64]; + + for i in 0..values.len() { + let bits = f64::to_bits(sqrt(values[i])); + assert_eq!(results[i], bits); + } + } } diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 00b20e578be..b1321137629 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -151,4 +151,15 @@ mod tests { assert_eq!(sqrtf(f), f); } } + + #[test] + fn conformance_tests() { + let values = [3.14159265359f32, 10000.0f32, -1.0f32, INFINITY]; + let results = [1071833029u32, 1120403456u32, 4290772992u32, 2139095040u32]; + + for i in 0..values.len() { + let bits = f32::to_bits(sqrtf(values[i])); + assert_eq!(results[i], bits); + } + } } -- cgit 1.4.1-3-g733a5 From 294eab952066583556a05fe5c68e8bac0e5fe370 Mon Sep 17 00:00:00 2001 From: Luc Date: Wed, 16 Nov 2022 15:39:13 +0100 Subject: Remove negative numbers from test --- library/compiler-builtins/libm/src/math/sqrt.rs | 4 ++-- library/compiler-builtins/libm/src/math/sqrtf.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 9a700d8ea0f..434d4d6d775 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -264,9 +264,9 @@ mod tests { #[test] fn conformance_tests() { - let values = [3.14159265359, 10000.0, -1.0, INFINITY]; + let values = [3.14159265359, 10000.0, f64::from_bits(0x0000000f), INFINITY]; let results = [4610661241675116657u64, 4636737291354636288u64, - 18444492273895866368u64, 9218868437227405312u64]; + 2197470602079456986u64, 9218868437227405312u64]; for i in 0..values.len() { let bits = f64::to_bits(sqrt(values[i])); diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index b1321137629..04301355e75 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -154,9 +154,9 @@ mod tests { #[test] fn conformance_tests() { - let values = [3.14159265359f32, 10000.0f32, -1.0f32, INFINITY]; - let results = [1071833029u32, 1120403456u32, 4290772992u32, 2139095040u32]; - + let values = [3.14159265359f32, 10000.0f32, f32::from_bits(0x0000000f), INFINITY]; + let results = [1071833029u32, 1120403456u32, 456082799u32, 2139095040u32]; + for i in 0..values.len() { let bits = f32::to_bits(sqrtf(values[i])); assert_eq!(results[i], bits); -- cgit 1.4.1-3-g733a5 From b90b2f8547209a01362ed50b7aad80667e1190f5 Mon Sep 17 00:00:00 2001 From: Luc Date: Wed, 16 Nov 2022 15:44:43 +0100 Subject: Fix formatting Forgot to run cargo fmt last time... --- library/compiler-builtins/libm/src/math/sqrt.rs | 14 +++++++++----- library/compiler-builtins/libm/src/math/sqrtf.rs | 13 +++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 434d4d6d775..3733ba0400f 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -261,16 +261,20 @@ mod tests { assert_eq!(sqrt(f), f); } } - + #[test] fn conformance_tests() { let values = [3.14159265359, 10000.0, f64::from_bits(0x0000000f), INFINITY]; - let results = [4610661241675116657u64, 4636737291354636288u64, - 2197470602079456986u64, 9218868437227405312u64]; - + let results = [ + 4610661241675116657u64, + 4636737291354636288u64, + 2197470602079456986u64, + 9218868437227405312u64, + ]; + for i in 0..values.len() { let bits = f64::to_bits(sqrt(values[i])); assert_eq!(results[i], bits); - } + } } } diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 04301355e75..8ec72fbf7fa 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -151,15 +151,20 @@ mod tests { assert_eq!(sqrtf(f), f); } } - - #[test] + + #[test] fn conformance_tests() { - let values = [3.14159265359f32, 10000.0f32, f32::from_bits(0x0000000f), INFINITY]; + let values = [ + 3.14159265359f32, + 10000.0f32, + f32::from_bits(0x0000000f), + INFINITY, + ]; let results = [1071833029u32, 1120403456u32, 456082799u32, 2139095040u32]; for i in 0..values.len() { let bits = f32::to_bits(sqrtf(values[i])); assert_eq!(results[i], bits); - } + } } } -- cgit 1.4.1-3-g733a5 From 98b3454d3db1110a26df7a8dde4efaf81bd278a0 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Tue, 15 Nov 2022 21:01:21 -0500 Subject: Skip assembly implementations on the UEFI targets The UEFI targets link with `/SAFESEH`. That requires that objects have a symbol called [`@feat.00`]. Clang adds that symbol for COFF targets if the input is a C file, but not if the input is an ASM file. That doesn't prevent compiler_builtins or rustc from building, but using the resulting rustc to compile something that references one of the objects lacking `@feat.00` will result in a linker error. Fix by removing all the `.S` implementations when `target_os == uefi`. [`@feat.00`]: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#the-sxdata-section --- library/compiler-builtins/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 73952bb9f3e..8fde89d9101 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -465,7 +465,8 @@ mod c { } // Remove the assembly implementations that won't compile for the target - if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { + if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" || target_os == "uefi" + { let mut to_remove = Vec::new(); for (k, v) in sources.map.iter() { if v.ends_with(".S") { -- cgit 1.4.1-3-g733a5 From ebaca42a412c5650e04be953615e58a9b5fcf80a Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Wed, 16 Nov 2022 17:52:46 -0500 Subject: Use a stub stdlib.h when compiling for UEFI targets int_util.c includes stdlib.h if `_WIN32` is defined. When compiling the UEFI targets with clang they are treated as Windows targets (e.g. if the Rust target is x86_64-unknown-uefi, the clang target is x86_64-unknown-windows-gnu). So stdlib.h gets included, even though we are compilling with `-ffreestanding` and don't want stdlib.h to be used. That file may not be present, or an incompatible version might be installed leading to typedef redefinition errors. The contents of stdlib.h aren't actually needed for these targets anyway (due to `__STDC_HOSTED__` being 0), so create a minimal stdlib.h in `build.rs` when `target_os == uefi` and add it to the include path. --- library/compiler-builtins/build.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 8fde89d9101..3f5dbd3ab27 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -98,7 +98,7 @@ mod c { use std::collections::{BTreeMap, HashSet}; use std::env; - use std::fs::File; + use std::fs::{self, File}; use std::io::Write; use std::path::{Path, PathBuf}; @@ -190,6 +190,21 @@ mod c { cfg.define("VISIBILITY_HIDDEN", None); } + // int_util.c tries to include stdlib.h if `_WIN32` is defined, + // which it is when compiling UEFI targets with clang. This is + // at odds with compiling with `-ffreestanding`, as the header + // may be incompatible or not present. Create a minimal stub + // header to use instead. + if target_os == "uefi" { + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let include_dir = out_dir.join("include"); + if !include_dir.exists() { + fs::create_dir(&include_dir).unwrap(); + } + fs::write(include_dir.join("stdlib.h"), "#include ").unwrap(); + cfg.flag(&format!("-I{}", include_dir.to_str().unwrap())); + } + let mut sources = Sources::new(); sources.extend(&[ ("__absvdi2", "absvdi2.c"), -- cgit 1.4.1-3-g733a5 From ad4ab99a2e0419b015a9a3f5f4c9cdd3f270c48a Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 18 Nov 2022 02:58:11 +0000 Subject: Bump to 0.1.84 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 36c1f8a08df..1b89d51e904 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.83" +version = "0.1.84" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 80828bfb0b880822131243a016dbf38882a99dff Mon Sep 17 00:00:00 2001 From: Jérome Eertmans Date: Mon, 28 Nov 2022 10:53:42 +0100 Subject: fix(docs): typo in docstrings Hello, I think you misspelled `width` to `with`. --- library/compiler-builtins/src/float/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 01a5504d52c..fdbe9dde35b 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -26,10 +26,10 @@ pub(crate) trait Float: + ops::Div + ops::Rem { - /// A uint of the same with as the float + /// A uint of the same width as the float type Int: Int; - /// A int of the same with as the float + /// A int of the same width as the float type SignedInt: Int; /// An int capable of containing the exponent bits plus a sign bit. This is signed. -- cgit 1.4.1-3-g733a5 From 620f50589e7e27d18121c52c4f82cb2c57173117 Mon Sep 17 00:00:00 2001 From: Martin Kröning Date: Wed, 7 Dec 2022 16:08:01 +0100 Subject: Expose minimal floating point symbols for x86_64-unknown-none --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/math.rs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index e7bc61e4c0f..10b4aafec31 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -44,6 +44,7 @@ pub mod int; #[cfg(any( all(target_family = "wasm", target_os = "unknown"), + all(target_arch = "x86_64", target_os = "none"), all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), target_os = "xous", diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 4ae174891c2..c64984e9ee7 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -106,10 +106,11 @@ no_mangle! { fn truncf(x: f32) -> f32; } -// only for the thumb*-none-eabi* targets and riscv32*-none-elf targets that lack the floating point instruction set +// only for the thumb*-none-eabi*, riscv32*-none-elf and x86_64-unknown-none targets that lack the floating point instruction set #[cfg(any( all(target_arch = "arm", target_os = "none"), - all(target_arch = "riscv32", not(target_feature = "f"), target_os = "none") + all(target_arch = "riscv32", not(target_feature = "f"), target_os = "none"), + all(target_arch = "x86_64", target_os = "none") ))] no_mangle! { fn fmin(x: f64, y: f64) -> f64; -- cgit 1.4.1-3-g733a5 From 62cd3780ae22bf341afaa2dfc1417f5e334efc73 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 8 Dec 2022 13:31:59 +0000 Subject: Bump to 0.1.85 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 1b89d51e904..00998e40f80 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.84" +version = "0.1.85" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From d20eea4d47593b37f6355d6fb364aa9826770fd8 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Sun, 25 Dec 2022 11:46:30 +0100 Subject: fix: Add `#[avr_skip]` for bit shifts This commit follows the same logic as: - https://github.com/rust-lang/compiler-builtins/pull/462 - https://github.com/rust-lang/compiler-builtins/pull/466 I've tested the changes by preparing a simple program: ```rust fn calc() -> ... { let x = hint::black_box(4u...); // 4u8, 4u16, 4u32, 4u64, 4u128 + signed let y = hint::black_box(1u32); // x >> y // x << y } fn main() -> ! { let dp = arduino_hal::Peripherals::take().unwrap(); let pins = arduino_hal::pins!(dp); let mut serial = arduino_hal::default_serial!(dp, pins, 57600); for b in calc().to_le_bytes() { _ = ufmt::uwrite!(&mut serial, "{} ", b); } _ = ufmt::uwriteln!(&mut serial, ""); loop { // } } ``` ... switching types & operators in `calc()`, and observing the results; what I ended up with was: ``` u32 << u32 - ok u64 << u32 - ok u128 << u32 - error (undefined reference to `__ashlti3') i32 >> u32 - ok i64 >> u32 - ok i128 >> u32 - error (undefined reference to `__ashrti3') u32 >> u32 - ok u64 >> u32 - ok u128 >> u32 - error (undefined reference to `__lshrti3') (where "ok" = compiles and returns correct results) ``` As with multiplication and division, so do in here 128-bit operations not work, because avr-gcc's standard library doesn't provide them (at the same time, requiring that specific calling convention, making it pretty difficult for compiler-builtins to jump in). I think 128-bit operations non-working on an 8-bit controller is an acceptable trade-off - :innocent: - and so the entire fix in here is just about skipping those functions. --- library/compiler-builtins/src/int/shift.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 908e619e1dd..2d2c081a680 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -69,47 +69,56 @@ impl Lshr for u64 {} impl Lshr for u128 {} intrinsics! { + #[avr_skip] #[maybe_use_optimized_c_shim] pub extern "C" fn __ashlsi3(a: u32, b: u32) -> u32 { a.ashl(b) } + #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsl] pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { a.ashl(b) } + #[avr_skip] pub extern "C" fn __ashlti3(a: u128, b: u32) -> u128 { a.ashl(b) } + #[avr_skip] #[maybe_use_optimized_c_shim] pub extern "C" fn __ashrsi3(a: i32, b: u32) -> i32 { a.ashr(b) } + #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lasr] pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { a.ashr(b) } + #[avr_skip] pub extern "C" fn __ashrti3(a: i128, b: u32) -> i128 { a.ashr(b) } + #[avr_skip] #[maybe_use_optimized_c_shim] pub extern "C" fn __lshrsi3(a: u32, b: u32) -> u32 { a.lshr(b) } + #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsr] pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { a.lshr(b) } + #[avr_skip] pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 { a.lshr(b) } -- cgit 1.4.1-3-g733a5 From 7f39126ff9c97ad21d4c87ae8e12f2315681c0ed Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 29 Dec 2022 20:36:57 +0100 Subject: Bump to 0.1.86 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 00998e40f80..f143c1033f0 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.85" +version = "0.1.86" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 7777c60a0b574a0f0fcb7f5a423a03199a9a4060 Mon Sep 17 00:00:00 2001 From: Moritz Meier Date: Tue, 17 Jan 2023 20:41:24 +0100 Subject: add generic libm helper Add editorconfig + docs refactor --- library/compiler-builtins/libm/.editorconfig | 21 +++ library/compiler-builtins/libm/src/lib.rs | 2 + library/compiler-builtins/libm/src/libm_helper.rs | 171 ++++++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 library/compiler-builtins/libm/.editorconfig create mode 100644 library/compiler-builtins/libm/src/libm_helper.rs diff --git a/library/compiler-builtins/libm/.editorconfig b/library/compiler-builtins/libm/.editorconfig new file mode 100644 index 00000000000..ec6e107d547 --- /dev/null +++ b/library/compiler-builtins/libm/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 4 + +[*.md] +# double whitespace at end of line +# denotes a line break in Markdown +trim_trailing_whitespace = false + +[*.yml] +indent_size = 2 diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 29742b4510c..4a17d3a77a2 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -12,11 +12,13 @@ #![allow(clippy::eq_op)] #![allow(clippy::assign_op_pattern)] +mod libm_helper; mod math; use core::{f32, f64}; pub use self::math::*; +pub use libm_helper::*; /// Approximate equality with 1 ULP of tolerance #[doc(hidden)] diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs new file mode 100644 index 00000000000..52d0c4c2a11 --- /dev/null +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -0,0 +1,171 @@ +use core::marker::PhantomData; + +use crate::*; + +/// Generic helper for libm functions, abstracting over f32 and f64.
+/// # Type Parameter: +/// - `T`: Either `f32` or `f64` +/// +/// # Examples +/// ```rust +/// use libm::{self, Libm}; +/// +/// const PI_F32: f32 = 3.1415927410e+00; +/// const PI_F64: f64 = 3.1415926535897931160e+00; +/// +/// assert!(Libm::::cos(0.0f32) == libm::cosf(0.0)); +/// assert!(Libm::::sin(PI_F32) == libm::sinf(PI_F32)); +/// +/// assert!(Libm::::cos(0.0f64) == libm::cos(0.0)); +/// assert!(Libm::::sin(PI_F64) == libm::sin(PI_F64)); +/// ``` +pub struct Libm(PhantomData); + +macro_rules! libm_helper { + ($t:ident, funcs: $funcs:tt) => { + impl Libm<$t> { + #![allow(unused_parens)] + + libm_helper! { $funcs } + } + }; + + ({$($func:tt);*}) => { + $( + libm_helper! { $func } + )* + }; + + ((fn $func:ident($($arg:ident: $arg_typ:ty),*) -> ($($ret_typ:ty),*); => $libm_fn:ident)) => { + #[inline(always)] + pub fn $func($($arg: $arg_typ),*) -> ($($ret_typ),*) { + $libm_fn($($arg),*) + } + }; +} + +libm_helper! { + f32, + funcs: { + (fn acos(x: f32) -> (f32); => acosf); + (fn acosh(x: f32) -> (f32); => acoshf); + (fn asin(x: f32) -> (f32); => asinf); + (fn asinh(x: f32) -> (f32); => asinhf); + (fn atan(x: f32) -> (f32); => atanf); + (fn atan2(y: f32, x: f32) -> (f32); => atan2f); + (fn atanh(x: f32) -> (f32); => atanhf); + (fn cbrt(x: f32) -> (f32); => cbrtf); + (fn ceil(x: f32) -> (f32); => ceilf); + (fn copysign(x: f32, y: f32) -> (f32); => copysignf); + (fn cos(x: f32) -> (f32); => cosf); + (fn cosh(x: f32) -> (f32); => coshf); + (fn erf(x: f32) -> (f32); => erff); + (fn erfc(x: f32) -> (f32); => erfcf); + (fn exp(x: f32) -> (f32); => expf); + (fn exp2(x: f32) -> (f32); => exp2f); + (fn exp10(x: f32) -> (f32); => exp10f); + (fn expm1(x: f32) -> (f32); => expm1f); + (fn fabs(x: f32) -> (f32); => fabsf); + (fn fdim(x: f32, y: f32) -> (f32); => fdimf); + (fn floor(x: f32) -> (f32); => floorf); + (fn fma(x: f32, y: f32, z: f32) -> (f32); => fmaf); + (fn fmax(x: f32, y: f32) -> (f32); => fmaxf); + (fn fmin(x: f32, y: f32) -> (f32); => fminf); + (fn fmod(x: f32, y: f32) -> (f32); => fmodf); + (fn frexp(x: f32) -> (f32, i32); => frexpf); + (fn hypot(x: f32, y: f32) -> (f32); => hypotf); + (fn ilogb(x: f32) -> (i32); => ilogbf); + (fn j0(x: f32) -> (f32); => j0f); + (fn j1(x: f32) -> (f32); => j1f); + (fn jn(n: i32, x: f32) -> (f32); => jnf); + (fn ldexp(x: f32, n: i32) -> (f32); => ldexpf); + (fn lgamma_r(x: f32) -> (f32, i32); => lgammaf_r); + (fn lgamma(x: f32) -> (f32); => lgammaf); + (fn log(x: f32) -> (f32); => logf); + (fn log1p(x: f32) -> (f32); => log1pf); + (fn log2(x: f32) -> (f32); => log2f); + (fn log10(x: f32) -> (f32); => log10f); + (fn modf(x: f32) -> (f32, f32); => modff); + (fn nextafter(x: f32, y: f32) -> (f32); => nextafterf); + (fn pow(x: f32, y: f32) -> (f32); => powf); + (fn remainder(x: f32, y: f32) -> (f32); => remainderf); + (fn remquo(x: f32, y: f32) -> (f32, i32); => remquof); + (fn rint(x: f32) -> (f32); => rintf); + (fn round(x: f32) -> (f32); => roundf); + (fn scalbn(x: f32, n: i32) -> (f32); => scalbnf); + (fn sin(x: f32) -> (f32); => sinf); + (fn sincos(x: f32) -> (f32, f32); => sincosf); + (fn sinh(x: f32) -> (f32); => sinhf); + (fn sqrt(x: f32) -> (f32); => sqrtf); + (fn tan(x: f32) -> (f32); => tanf); + (fn tanh(x: f32) -> (f32); => tanhf); + (fn tgamma(x: f32) -> (f32); => tgammaf); + (fn trunc(x: f32) -> (f32); => truncf); + (fn y0(x: f32) -> (f32); => y0f); + (fn y1(x: f32) -> (f32); => y1f); + (fn yn(n: i32, x: f32) -> (f32); => ynf) + } +} + +libm_helper! { + f64, + funcs: { + (fn acos(x: f64) -> (f64); => acos); + (fn acosh(x: f64) -> (f64); => acosh); + (fn asin(x: f64) -> (f64); => asin); + (fn asinh(x: f64) -> (f64); => asinh); + (fn atan(x: f64) -> (f64); => atan); + (fn atan2(y: f64, x: f64) -> (f64); => atan2); + (fn atanh(x: f64) -> (f64); => atanh); + (fn cbrt(x: f64) -> (f64); => cbrt); + (fn ceil(x: f64) -> (f64); => ceil); + (fn copysign(x: f64, y: f64) -> (f64); => copysign); + (fn cos(x: f64) -> (f64); => cos); + (fn cosh(x: f64) -> (f64); => cosh); + (fn erf(x: f64) -> (f64); => erf); + (fn erfc(x: f64) -> (f64); => erfc); + (fn exp(x: f64) -> (f64); => exp); + (fn exp2(x: f64) -> (f64); => exp2); + (fn exp10(x: f64) -> (f64); => exp10); + (fn expm1(x: f64) -> (f64); => expm1); + (fn fabs(x: f64) -> (f64); => fabs); + (fn fdim(x: f64, y: f64) -> (f64); => fdim); + (fn floor(x: f64) -> (f64); => floor); + (fn fma(x: f64, y: f64, z: f64) -> (f64); => fma); + (fn fmax(x: f64, y: f64) -> (f64); => fmax); + (fn fmin(x: f64, y: f64) -> (f64); => fmin); + (fn fmod(x: f64, y: f64) -> (f64); => fmod); + (fn frexp(x: f64) -> (f64, i32); => frexp); + (fn hypot(x: f64, y: f64) -> (f64); => hypot); + (fn ilogb(x: f64) -> (i32); => ilogb); + (fn j0(x: f64) -> (f64); => j0); + (fn j1(x: f64) -> (f64); => j1); + (fn jn(n: i32, x: f64) -> (f64); => jn); + (fn ldexp(x: f64, n: i32) -> (f64); => ldexp); + (fn lgamma_r(x: f64) -> (f64, i32); => lgamma_r); + (fn lgamma(x: f64) -> (f64); => lgamma); + (fn log(x: f64) -> (f64); => log); + (fn log1p(x: f64) -> (f64); => log1p); + (fn log2(x: f64) -> (f64); => log2); + (fn log10(x: f64) -> (f64); => log10); + (fn modf(x: f64) -> (f64, f64); => modf); + (fn nextafter(x: f64, y: f64) -> (f64); => nextafter); + (fn pow(x: f64, y: f64) -> (f64); => pow); + (fn remainder(x: f64, y: f64) -> (f64); => remainder); + (fn remquo(x: f64, y: f64) -> (f64, i32); => remquo); + (fn rint(x: f64) -> (f64); => rint); + (fn round(x: f64) -> (f64); => round); + (fn scalbn(x: f64, n: i32) -> (f64); => scalbn); + (fn sin(x: f64) -> (f64); => sin); + (fn sincos(x: f64) -> (f64, f64); => sincos); + (fn sinh(x: f64) -> (f64); => sinh); + (fn sqrt(x: f64) -> (f64); => sqrt); + (fn tan(x: f64) -> (f64); => tan); + (fn tanh(x: f64) -> (f64); => tanh); + (fn tgamma(x: f64) -> (f64); => tgamma); + (fn trunc(x: f64) -> (f64); => trunc); + (fn y0(x: f64) -> (f64); => y0); + (fn y1(x: f64) -> (f64); => y1); + (fn yn(n: i32, x: f64) -> (f64); => yn) + } +} -- cgit 1.4.1-3-g733a5 From 929b5841db27b43934b1322c450327df27144e69 Mon Sep 17 00:00:00 2001 From: "James D. Turner" Date: Fri, 20 Jan 2023 13:39:41 -0500 Subject: Fix descriptions of erfc and erfcf As described in the second paragraph of the docs for these functions, they are the complementary error function, not the error function. --- library/compiler-builtins/libm/src/math/erf.rs | 2 +- library/compiler-builtins/libm/src/math/erff.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs index 5e21ba578df..55569affc97 100644 --- a/library/compiler-builtins/libm/src/math/erf.rs +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -263,7 +263,7 @@ pub fn erf(x: f64) -> f64 { } } -/// Error function (f64) +/// Complementary error function (f64) /// /// Calculates the complementary probability. /// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs index f74d4b63249..7b25474f602 100644 --- a/library/compiler-builtins/libm/src/math/erff.rs +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -174,7 +174,7 @@ pub fn erff(x: f32) -> f32 { } } -/// Error function (f32) +/// Complementary error function (f32) /// /// Calculates the complementary probability. /// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid -- cgit 1.4.1-3-g733a5 From 8d4e9062066b10bf5914d94b68dfb6a190ea09ae Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 1 Feb 2023 14:52:18 -0800 Subject: Drop the llvm14-builtins-abi hack --- library/compiler-builtins/src/float/conv.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 19fdc2fdc69..a27d542fae3 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -92,12 +92,12 @@ intrinsics! { f64::from_bits(int_to_float::u64_to_f64_bits(i)) } - #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] + #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] pub extern "C" fn __floatuntisf(i: u128) -> f32 { f32::from_bits(int_to_float::u128_to_f32_bits(i)) } - #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] + #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] pub extern "C" fn __floatuntidf(i: u128) -> f64 { f64::from_bits(int_to_float::u128_to_f64_bits(i)) } @@ -129,13 +129,13 @@ intrinsics! { f64::from_bits(int_to_float::u64_to_f64_bits(i.unsigned_abs()) | sign_bit) } - #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] + #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] pub extern "C" fn __floattisf(i: i128) -> f32 { let sign_bit = ((i >> 127) as u32) << 31; f32::from_bits(int_to_float::u128_to_f32_bits(i.unsigned_abs()) | sign_bit) } - #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] + #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] pub extern "C" fn __floattidf(i: i128) -> f64 { let sign_bit = ((i >> 127) as u64) << 63; f64::from_bits(int_to_float::u128_to_f64_bits(i.unsigned_abs()) | sign_bit) @@ -176,8 +176,7 @@ intrinsics! { } } - #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[win64_128bit_abi_hack] pub extern "C" fn __fixunssfti(f: f32) -> u128 { let fbits = f.to_bits(); if fbits < 127 << 23 { // >= 0, < 1 @@ -225,8 +224,7 @@ intrinsics! { } } - #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[win64_128bit_abi_hack] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { let fbits = f.to_bits(); if fbits < 1023 << 52 { // >= 0, < 1 @@ -279,8 +277,7 @@ intrinsics! { } } - #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[win64_128bit_abi_hack] pub extern "C" fn __fixsfti(f: f32) -> i128 { let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. if fbits < 127 << 23 { // >= 0, < 1 @@ -331,8 +328,7 @@ intrinsics! { } } - #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[win64_128bit_abi_hack] pub extern "C" fn __fixdfti(f: f64) -> i128 { let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. if fbits < 1023 << 52 { // >= 0, < 1 -- cgit 1.4.1-3-g733a5 From 2ca64c27984e30f812216908d248c3b28bd9dc63 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 3 Feb 2023 19:21:40 +0100 Subject: Bump to 0.1.87 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f143c1033f0..ca0d96aa6af 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.86" +version = "0.1.87" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 8753da27ae52a7c76ffdbccf1fc681171e6aed9b Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Thu, 16 Feb 2023 18:22:17 +0100 Subject: Small tweak to `mul` in `fma.rs`. --- library/compiler-builtins/libm/src/math/fma.rs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index f9a86dc6063..940ee2db927 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -29,21 +29,10 @@ fn normalize(x: f64) -> Num { Num { m: ix, e, sign } } +#[inline] fn mul(x: u64, y: u64) -> (u64, u64) { - let t1: u64; - let t2: u64; - let t3: u64; - let xlo: u64 = x as u32 as u64; - let xhi: u64 = x >> 32; - let ylo: u64 = y as u32 as u64; - let yhi: u64 = y >> 32; - - t1 = xlo * ylo; - t2 = xlo * yhi + xhi * ylo; - t3 = xhi * yhi; - let lo = t1.wrapping_add(t2 << 32); - let hi = t3 + (t2 >> 32) + (t1 > lo) as u64; - (hi, lo) + let t = (x as u128).wrapping_mul(y as u128); + ((t >> 64) as u64, t as u64) } /// Floating multiply add (f64) -- cgit 1.4.1-3-g733a5 From a11bd1cfdb3642bc137b2e2bda3254c2a6a827f4 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Tue, 21 Feb 2023 23:13:02 +0100 Subject: Specialize `strlen` for `x86_64`. --- library/compiler-builtins/src/mem/impls.rs | 10 ++++++++++ library/compiler-builtins/src/mem/mod.rs | 8 +------- library/compiler-builtins/src/mem/x86_64.rs | 29 +++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index 72003a5c472..23c9d8d3275 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -279,3 +279,13 @@ pub unsafe fn compare_bytes(s1: *const u8, s2: *const u8, n: usize) -> i32 { } 0 } + +#[inline(always)] +pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { + let mut n = 0; + while *s != 0 { + n += 1; + s = s.add(1); + } + n +} diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index c5b0ddc16ec..be118778b1a 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -63,13 +63,7 @@ intrinsics! { #[mem_builtin] #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn strlen(s: *const core::ffi::c_char) -> usize { - let mut n = 0; - let mut s = s; - while *s != 0 { - n += 1; - s = s.offset(1); - } - n + impls::c_string_length(s) } } diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 17b461f7914..ea8f6d819de 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -173,6 +173,35 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { c16(a.cast(), b.cast(), n) } +#[inline(always)] +pub unsafe fn c_string_length(s: *const std::ffi::c_char) -> usize { + let mut n: usize; + + std::arch::asm!( + // search for a zero byte + "xor al, al", + + // unbounded memory region + "xor rcx, rcx", + "not rcx", + + // forward direction + "cld", + + // perform search + "repne scasb", + + // extract length + "not rcx", + "dec rcx", + inout("rdi") s => _, + out("rcx") n, + options(nostack), + ); + + n +} + /// Determine optimal parameters for a `rep` instruction. fn rep_param(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { // Unaligned writes are still slow on modern processors, so align the destination address. -- cgit 1.4.1-3-g733a5 From 990596fa283a6f35e27a089f0ebd8d7aad0e1bce Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Tue, 21 Feb 2023 23:32:39 +0100 Subject: Correct path. --- library/compiler-builtins/src/mem/x86_64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index ea8f6d819de..13e186e649b 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -177,7 +177,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { pub unsafe fn c_string_length(s: *const std::ffi::c_char) -> usize { let mut n: usize; - std::arch::asm!( + asm!( // search for a zero byte "xor al, al", -- cgit 1.4.1-3-g733a5 From 44d34e87fa462edb0b75732212595e3d2933eb45 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Tue, 21 Feb 2023 23:36:47 +0100 Subject: Update path for argument. --- library/compiler-builtins/src/mem/x86_64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 13e186e649b..282074a6cbc 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -174,7 +174,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { } #[inline(always)] -pub unsafe fn c_string_length(s: *const std::ffi::c_char) -> usize { +pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { let mut n: usize; asm!( -- cgit 1.4.1-3-g733a5 From b53c1ae17ad396730c12bafdd745b04e2b170ed9 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Wed, 22 Feb 2023 00:07:41 +0100 Subject: Improve assembly quality + AT&T syntax. --- library/compiler-builtins/src/mem/x86_64.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 282074a6cbc..fe93ae7aed4 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -179,24 +179,25 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { asm!( // search for a zero byte - "xor al, al", + "xor %eax, %eax", // unbounded memory region - "xor rcx, rcx", - "not rcx", + "xor %ecx, %ecx", + "not %rcx", // forward direction - "cld", + // (already set thanks to abi) + //"cld", // perform search - "repne scasb", + "repne scasb (%rdi), %al", // extract length - "not rcx", - "dec rcx", + "not %rcx", + "dec %rcx", inout("rdi") s => _, out("rcx") n, - options(nostack), + options(att_syntax, nostack), ); n -- cgit 1.4.1-3-g733a5 From e9e34801a69f2e29e5f93d5cf2916fb183e130ed Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Wed, 22 Feb 2023 00:10:46 +0100 Subject: Remove superfluous comment. --- library/compiler-builtins/src/mem/x86_64.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index fe93ae7aed4..5752005a478 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -185,10 +185,6 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { "xor %ecx, %ecx", "not %rcx", - // forward direction - // (already set thanks to abi) - //"cld", - // perform search "repne scasb (%rdi), %al", -- cgit 1.4.1-3-g733a5 From 97402fc580b9fd9858b6c6e5db95b85f2464aeb3 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Wed, 22 Feb 2023 21:54:33 +0100 Subject: Change implementation to SSE --- library/compiler-builtins/src/mem/x86_64.rs | 77 +++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 5752005a478..daa92098e6b 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -178,21 +178,78 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { let mut n: usize; asm!( - // search for a zero byte + // For small sizes, we avoid invoking SSE instructions. + // make manual comparisons instead. "xor %eax, %eax", + "cmpb $0, (%rdi)", + "je 3f", + "mov $1, %eax", + "cmpb $0, 1(%rdi)", + "je 3f", + "mov $2, %eax", + "cmpb $0, 2(%rdi)", + "je 3f", + "mov $3, %eax", + "cmpb $0, 3(%rdi)", + "je 3f", - // unbounded memory region - "xor %ecx, %ecx", - "not %rcx", + // Adjust address + "add $4, %rdi", - // perform search - "repne scasb (%rdi), %al", + // Align the address to 16 bytes (xmm register size). + // This is important, since an n byte read + // with n byte alignment is guranteed to never cross + // a page boundary and thus will never try to access + // memory which may not be accessible. + "mov %edi, %ecx", + "and $15, %ecx", + "and $-16, %rdi", - // extract length - "not %rcx", - "dec %rcx", + // zero out an xmm register for comparisons with zero. + "pxor %xmm0, %xmm0", + + // One manual iteration of a zero byte search. + // Ensuring proper alignment may cause us to read + // memory _before_ the actual string start. + // Thus, one separate iteration is needed to handle this special case. + "movdqa (%rdi), %xmm1", + "pcmpeqb %xmm0, %xmm1", + "pmovmskb %xmm1, %eax", + // Shift out comparisons that don't belong to the actual string. + "shr %cl, %eax", + // Check if there was a zero + "test %eax, %eax", + "jz 1f", + + // A zero was found: calculate result and exit. + "bsf %eax, %eax", + "add $4, %eax", + "jmp 3f", + + // No zero was found: prepare main loop. + "1:", + "add $16, %rdi", + "neg %rcx", + "add $4, %rcx", + + // main loop + "2:", + "movdqa (%rdi), %xmm1", + "add $16, %rdi", + "add $16, %rcx", + "pcmpeqb %xmm0, %xmm1", + "pmovmskb %xmm1, %eax", + // Check if there was a zero + "test %eax, %eax", + "jz 2b", + + // A zero was found: calculate result and exit. + "bsf %eax, %eax", + "add %rcx, %rax", + "3:", inout("rdi") s => _, - out("rcx") n, + out("rax") n, + out("rcx") _, options(att_syntax, nostack), ); -- cgit 1.4.1-3-g733a5 From 67ebc4ae1480c5d5a1a9be05213e5dc30466f3ab Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Wed, 22 Feb 2023 20:35:06 +0000 Subject: Extend the intrinsics exported for Xtensa no_std --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/math.rs | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 10b4aafec31..71f249c8eb3 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -47,6 +47,7 @@ pub mod int; all(target_arch = "x86_64", target_os = "none"), all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), + all(target_arch = "xtensa", target_os = "none"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx") ))] diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index c64984e9ee7..982c9499a21 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -86,7 +86,11 @@ no_mangle! { fn tanf(n: f32) -> f32; } -#[cfg(any(target_os = "xous", target_os = "uefi"))] +#[cfg(any( + target_os = "xous", + target_os = "uefi", + all(target_arch = "xtensa", target_os = "none"), +))] no_mangle! { fn sqrtf(x: f32) -> f32; fn sqrt(x: f64) -> f64; @@ -94,6 +98,7 @@ no_mangle! { #[cfg(any( all(target_vendor = "fortanix", target_env = "sgx"), + all(target_arch = "xtensa", target_os = "none"), target_os = "xous", target_os = "uefi" ))] -- cgit 1.4.1-3-g733a5 From c7404df0694435bba4e1118ee5ca539a780bacbf Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Wed, 22 Feb 2023 22:16:29 +0100 Subject: Provide a non-sse version for x86_64. --- library/compiler-builtins/src/mem/x86_64.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index daa92098e6b..e9003310c20 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -173,6 +173,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { c16(a.cast(), b.cast(), n) } +#[cfg(target_feature="sse2")] #[inline(always)] pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { let mut n: usize; @@ -256,6 +257,19 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { n } +// Provided for scenarios like kernel development, where SSE might not +// be available. +#[cfg(not(target_feature="sse2"))] +#[inline(always)] +pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { + let mut n = 0; + while *s != 0 { + n += 1; + s = s.add(1); + } + n +} + /// Determine optimal parameters for a `rep` instruction. fn rep_param(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { // Unaligned writes are still slow on modern processors, so align the destination address. -- cgit 1.4.1-3-g733a5 From 04fe48216003d3bc92647946a36d7eaa23b5e54f Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Wed, 22 Feb 2023 22:19:10 +0100 Subject: Formatting --- library/compiler-builtins/src/mem/x86_64.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index e9003310c20..321d5929687 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -173,7 +173,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { c16(a.cast(), b.cast(), n) } -#[cfg(target_feature="sse2")] +#[cfg(target_feature = "sse2")] #[inline(always)] pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { let mut n: usize; @@ -259,7 +259,7 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { // Provided for scenarios like kernel development, where SSE might not // be available. -#[cfg(not(target_feature="sse2"))] +#[cfg(not(target_feature = "sse2"))] #[inline(always)] pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { let mut n = 0; -- cgit 1.4.1-3-g733a5 From 3e59619de7fea763ca81e530b43aab313309ed4e Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 23 Feb 2023 18:19:41 +0000 Subject: Bump to 0.1.88 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index ca0d96aa6af..8c0f6221c91 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.87" +version = "0.1.88" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 59fb34e63ae41d3bd93bfe656882f37da7b31a83 Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Sun, 5 Mar 2023 12:17:21 -0800 Subject: Added lgamma_r and lgammaf_r --- library/compiler-builtins/src/math.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 982c9499a21..498e4d85ff0 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -86,6 +86,31 @@ no_mangle! { fn tanf(n: f32) -> f32; } +#[cfg(any( + all( + target_family = "wasm", + target_os = "unknown", + not(target_env = "wasi") + ), + target_os = "xous", + all(target_arch = "x86_64", target_os = "uefi"), + all(target_arch = "xtensa", target_os = "none"), + all(target_vendor = "fortanix", target_env = "sgx") +))] +intrinsics! { + pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { + let r = self::libm::lgamma_r(x); + *s = r.1; + r.0 + } + + pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { + let r = self::libm::lgammaf_r(x); + *s = r.1; + r.0 + } +} + #[cfg(any( target_os = "xous", target_os = "uefi", -- cgit 1.4.1-3-g733a5 From 215f63ad19405a06266c832f3c246b23a4f60cf1 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Mon, 6 Mar 2023 19:20:30 +0100 Subject: Final version. --- library/compiler-builtins/src/mem/x86_64.rs | 181 +++++++++++++++++----------- 1 file changed, 108 insertions(+), 73 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 321d5929687..ad6ff9d172b 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -173,88 +173,82 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { c16(a.cast(), b.cast(), n) } + +// In order to process more than on byte simultaneously when executing strlen, +// two things must be considered: +// * An n byte read with an n-byte aligned address will never cross +// a page boundary and will always succeed. Any smaller alignment +// may result in a read that will cross a page boundary, which may +// trigger an access violation. +// * Surface Rust considers any kind of out-of-bounds read as undefined +// behaviour. To dodge this, memory access operations are written +// using inline assembly. + #[cfg(target_feature = "sse2")] #[inline(always)] pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { - let mut n: usize; - - asm!( - // For small sizes, we avoid invoking SSE instructions. - // make manual comparisons instead. - "xor %eax, %eax", - "cmpb $0, (%rdi)", - "je 3f", - "mov $1, %eax", - "cmpb $0, 1(%rdi)", - "je 3f", - "mov $2, %eax", - "cmpb $0, 2(%rdi)", - "je 3f", - "mov $3, %eax", - "cmpb $0, 3(%rdi)", - "je 3f", - - // Adjust address - "add $4, %rdi", + use core::arch::x86_64::{__m128i, _mm_cmpeq_epi8, _mm_movemask_epi8, _mm_set1_epi8}; - // Align the address to 16 bytes (xmm register size). - // This is important, since an n byte read - // with n byte alignment is guranteed to never cross - // a page boundary and thus will never try to access - // memory which may not be accessible. - "mov %edi, %ecx", - "and $15, %ecx", - "and $-16, %rdi", + let mut n = 0; + + // The use of _mm_movemask_epi8 and company allow for speedups, + // but they aren't cheap by themselves. Thus, possibly small strings + // are handled in simple loops. - // zero out an xmm register for comparisons with zero. - "pxor %xmm0, %xmm0", + for _ in 0..4 { + if *s == 0 { + return n; + } - // One manual iteration of a zero byte search. - // Ensuring proper alignment may cause us to read - // memory _before_ the actual string start. - // Thus, one separate iteration is needed to handle this special case. - "movdqa (%rdi), %xmm1", - "pcmpeqb %xmm0, %xmm1", - "pmovmskb %xmm1, %eax", - // Shift out comparisons that don't belong to the actual string. - "shr %cl, %eax", - // Check if there was a zero - "test %eax, %eax", - "jz 1f", + n += 1; + s = s.add(1); + } + + // Shave of the least significand bits to align the address to a 16 + // byte boundary. The shaved of bits are used to correct the first iteration. - // A zero was found: calculate result and exit. - "bsf %eax, %eax", - "add $4, %eax", - "jmp 3f", + let align = s as usize & 15; + let mut s = ((s as usize) - align) as *const __m128i; + let zero = _mm_set1_epi8(0); - // No zero was found: prepare main loop. - "1:", - "add $16, %rdi", - "neg %rcx", - "add $4, %rcx", + let x = { + let r; + asm!( + "movdqa ({addr}), {dest}", + addr = in(reg) s, + dest = out(xmm_reg) r, + options(att_syntax, nostack), + ); + r + }; + let cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(x, zero)) >> align; - // main loop - "2:", - "movdqa (%rdi), %xmm1", - "add $16, %rdi", - "add $16, %rcx", - "pcmpeqb %xmm0, %xmm1", - "pmovmskb %xmm1, %eax", - // Check if there was a zero - "test %eax, %eax", - "jz 2b", + if cmp != 0 { + return n + cmp.trailing_zeros() as usize; + } - // A zero was found: calculate result and exit. - "bsf %eax, %eax", - "add %rcx, %rax", - "3:", - inout("rdi") s => _, - out("rax") n, - out("rcx") _, - options(att_syntax, nostack), - ); + n += 16 - align; + s = s.add(1); - n + loop { + let x = { + let r; + asm!( + "movdqa ({addr}), {dest}", + addr = in(reg) s, + dest = out(xmm_reg) r, + options(att_syntax, nostack), + ); + r + }; + let cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(x, zero)) as u32; + if cmp == 0 { + n += 16; + s = s.add(1); + } else { + return n + cmp.trailing_zeros() as usize; + } + } } // Provided for scenarios like kernel development, where SSE might not @@ -263,11 +257,52 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { #[inline(always)] pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { let mut n = 0; - while *s != 0 { + + // Check bytes in steps of one until + // either a zero byte is discovered or + // pointer is aligned to an eight byte boundary. + + while s as usize & 7 != 0 { + if *s == 0 { + return n; + } + n += 1; s = s.add(1); } - n + + // Check bytes in steps of eight until a zero + // byte is discovered. + + let mut s = s as *const u64; + + loop { + let mut cs = { + let r: u64; + asm!( + "mov ({addr}), {dest}", + addr = in(reg) s, + dest = out(reg) r, + options(att_syntax, nostack), + ); + r + }; + // Detect if a word has a zero byte, taken from + // https://graphics.stanford.edu/~seander/bithacks.html + if (cs.wrapping_sub(0x0101010101010101) & !cs & 0x8080808080808080) != 0 { + loop { + if cs & 255 == 0 { + return n; + } else { + cs >>= 8; + n += 1; + } + } + } else { + n += 8; + s = s.add(1); + } + } } /// Determine optimal parameters for a `rep` instruction. -- cgit 1.4.1-3-g733a5 From 73fa0deaa62f240b782523cfb5f45aa8e2f09791 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Mon, 6 Mar 2023 19:24:02 +0100 Subject: formatting --- library/compiler-builtins/src/mem/x86_64.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index ad6ff9d172b..5377f04236f 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -173,7 +173,6 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { c16(a.cast(), b.cast(), n) } - // In order to process more than on byte simultaneously when executing strlen, // two things must be considered: // * An n byte read with an n-byte aligned address will never cross @@ -190,7 +189,7 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { use core::arch::x86_64::{__m128i, _mm_cmpeq_epi8, _mm_movemask_epi8, _mm_set1_epi8}; let mut n = 0; - + // The use of _mm_movemask_epi8 and company allow for speedups, // but they aren't cheap by themselves. Thus, possibly small strings // are handled in simple loops. @@ -266,11 +265,10 @@ pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { if *s == 0 { return n; } - n += 1; s = s.add(1); } - + // Check bytes in steps of eight until a zero // byte is discovered. -- cgit 1.4.1-3-g733a5 From 59766673e76d056123933834ea89cb640a650bd1 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Mon, 6 Mar 2023 19:28:49 +0100 Subject: more fixing --- library/compiler-builtins/src/mem/x86_64.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 5377f04236f..40b67093f51 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -185,7 +185,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { #[cfg(target_feature = "sse2")] #[inline(always)] -pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { +pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { use core::arch::x86_64::{__m128i, _mm_cmpeq_epi8, _mm_movemask_epi8, _mm_set1_epi8}; let mut n = 0; @@ -202,7 +202,7 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { n += 1; s = s.add(1); } - + // Shave of the least significand bits to align the address to a 16 // byte boundary. The shaved of bits are used to correct the first iteration. -- cgit 1.4.1-3-g733a5 From 20fb963ab68e086d38a51f419ed41c83dfa39333 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 10 Mar 2023 19:59:23 +0000 Subject: Add emutls.c for OpenHarmony --- library/compiler-builtins/build.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 3f5dbd3ab27..766dec05d9b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -508,6 +508,11 @@ mod c { cfg.define("LONG_BIT", "(8 * sizeof(long))"); } + // OpenHarmony also uses emulated TLS. + if target_env == "ohos" { + sources.extend(&[("__emutls_get_address", "emutls.c")]); + } + // When compiling the C code we require the user to tell us where the // source code is, and this is largely done so when we're compiling as // part of rust-lang/rust we can use the same llvm-project repository as -- cgit 1.4.1-3-g733a5 From 2f43b936033c5c83cc7c7bafe75c27e95e3f00f9 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Thu, 23 Mar 2023 22:00:22 +0900 Subject: Fix panic due to overflow in riscv.rs and int/shift.rs --- library/compiler-builtins/src/int/shift.rs | 6 +++--- library/compiler-builtins/src/riscv.rs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 2d2c081a680..080de2a14eb 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -12,7 +12,7 @@ trait Ashl: DInt { } else { Self::from_lo_hi( self.lo().wrapping_shl(shl), - self.lo().logical_shr(n_h - shl) | self.hi().wrapping_shl(shl), + self.lo().logical_shr(n_h.wrapping_sub(shl)) | self.hi().wrapping_shl(shl), ) } } @@ -36,7 +36,7 @@ trait Ashr: DInt { self } else { Self::from_lo_hi( - self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h - shr), + self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h.wrapping_sub(shr)), self.hi().wrapping_shr(shr), ) } @@ -57,7 +57,7 @@ trait Lshr: DInt { self } else { Self::from_lo_hi( - self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h - shr), + self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h.wrapping_sub(shr)), self.hi().logical_shr(shr), ) } diff --git a/library/compiler-builtins/src/riscv.rs b/library/compiler-builtins/src/riscv.rs index ae361b33acf..bf312553341 100644 --- a/library/compiler-builtins/src/riscv.rs +++ b/library/compiler-builtins/src/riscv.rs @@ -19,11 +19,11 @@ intrinsics! { // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/riscv/int_mul_impl.inc pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { let (mut a, mut b) = (a, b); - let mut r = 0; + let mut r: u32 = 0; while a > 0 { if a & 1 > 0 { - r += b; + r = r.wrapping_add(b); } a >>= 1; b <<= 1; @@ -35,11 +35,11 @@ intrinsics! { #[cfg(not(target_feature = "m"))] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { let (mut a, mut b) = (a, b); - let mut r = 0; + let mut r: u64 = 0; while a > 0 { if a & 1 > 0 { - r += b; + r = r.wrapping_add(b); } a >>= 1; b <<= 1; -- cgit 1.4.1-3-g733a5 From 26e2432c25dbed8712456ce5eb78b37004e3633b Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 25 Mar 2023 21:55:23 +0000 Subject: Bump to 0.1.90 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 8c0f6221c91..2c1d03ba61e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.88" +version = "0.1.90" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 7db8c0581d8e72d6561880f9906bd3837faa1689 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 29 Mar 2023 21:49:08 +0100 Subject: Disable another test on powerpc --- library/compiler-builtins/testcrate/tests/conv.rs | 29 +++++++++++++---------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 8c4b1946ce4..2a70db17890 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -23,18 +23,23 @@ macro_rules! i_to_f { || ((error_minus == error || error_plus == error) && ((f0.to_bits() & 1) != 0)) { - panic!( - "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", - stringify!($fn), - x, - f1.to_bits(), - y_minus_ulp, - y, - y_plus_ulp, - error_minus, - error, - error_plus, - ); + if !cfg!(any( + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + panic!( + "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", + stringify!($fn), + x, + f1.to_bits(), + y_minus_ulp, + y, + y_plus_ulp, + error_minus, + error, + error_plus, + ); + } } // Test against native conversion. We disable testing on all `x86` because of // rounding bugs with `i686`. `powerpc` also has the same rounding bug. -- cgit 1.4.1-3-g733a5 From 5246405d61ca3d70e0e7409846cea18ef6c18ece Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 26 Mar 2023 00:00:58 -0400 Subject: Ensure shift instrinsic arguments match width of compiler-rt's (int vs si_int). --- library/compiler-builtins/src/int/shift.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 080de2a14eb..c90cf1de320 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -78,8 +78,8 @@ intrinsics! { #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsl] - pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { - a.ashl(b) + pub extern "C" fn __ashldi3(a: u64, b: core::ffi::c_uint) -> u64 { + a.ashl(b as u32) } #[avr_skip] @@ -96,8 +96,8 @@ intrinsics! { #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lasr] - pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { - a.ashr(b) + pub extern "C" fn __ashrdi3(a: i64, b: core::ffi::c_uint) -> i64 { + a.ashr(b as u32) } #[avr_skip] @@ -114,8 +114,8 @@ intrinsics! { #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsr] - pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { - a.lshr(b) + pub extern "C" fn __lshrdi3(a: u64, b: core::ffi::c_uint) -> u64 { + a.lshr(b as u32) } #[avr_skip] -- cgit 1.4.1-3-g733a5 From 7749ed65809779b193978797f4c453017d9e7bed Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 29 Mar 2023 23:55:20 +0100 Subject: Bump to 0.1.91 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 2c1d03ba61e..9b9812836b4 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.90" +version = "0.1.91" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From eac491efc3e3862bf2453c6f4cb633b414d6a2f2 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 13 May 2023 15:16:59 +0900 Subject: Prepare 0.2.7 release Signed-off-by: Yuki Okushi --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index f942fdec3c9..393d95e4af2 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.6" +version = "0.2.7" edition = "2018" [features] -- cgit 1.4.1-3-g733a5 From fb77604e79c307900366e90b2de17bf8e2ccea1c Mon Sep 17 00:00:00 2001 From: danakj Date: Fri, 19 May 2023 15:47:57 -0400 Subject: Add the weak-intrinsics feature When enabled, the weak-intrinsics feature will cause all intrinsics functions to be marked with weak linkage (i.e. `#[linkage = "weak"]) so that they can be replaced at link time by a stronger symbol. This can be set to use C++ intrinsics from the compiler-rt library, as it will avoid Rust's implementation replacing the compiler-rt implementation as long as the compiler-rt symbols are linked as strong symbols. Typically this requires the compiler-rt library to be explicitly specified in the link command. Addresses https://github.com/rust-lang/compiler-builtins/issues/525. Without weak-intrinsics, from nm: ``` 00000000 W __aeabi_memclr8 // Is explicitly weak 00000000 T __udivsi3 // Is not. ``` With weak-intrinsics, from nm: ``` 00000000 W __aeabi_memclr8 // Is explicitly weak 00000000 W __udivsi3 // Is weak due to weak-intrinsics ``` --- library/compiler-builtins/Cargo.toml | 11 ++++ library/compiler-builtins/src/arm.rs | 32 ++++----- library/compiler-builtins/src/macros.rs | 110 ++++++++++++++++++++++++++++++- library/compiler-builtins/src/mem/mod.rs | 12 ++-- 4 files changed, 141 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 9b9812836b4..57b8b34c75d 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -65,6 +65,17 @@ rustc-dep-of-std = ['compiler-builtins', 'core'] # are not normally public but are required by the `testcrate` public-test-deps = [] +# Marks all intrinsics functions with weak linkage so that they can be +# replaced at link time by another implementation. This is particularly useful +# for mixed Rust/C++ binaries that want to use the C++ intrinsics, otherwise +# linking against the Rust stdlib will replace those from the compiler-rt +# library. +# +# Unlike the "c" feature, the intrinsics are still provided by the Rust +# implementations and each will be used unless a stronger symbol replaces +# it during linking. +weak-intrinsics = [] + [[example]] name = "intrinsics" required-features = ["compiler-builtins"] diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index e517a9ef34b..a062a54e008 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -20,9 +20,9 @@ macro_rules! bl { intrinsics! { // NOTE This function and the ones below are implemented using assembly because they are using a // custom calling convention which can't be implemented using a normal Rust function. + #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] #[cfg(not(target_env = "msvc"))] - #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_uidivmod() { core::arch::asm!( "push {{lr}}", @@ -36,8 +36,8 @@ intrinsics! { ); } + #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] - #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_uldivmod() { core::arch::asm!( "push {{r4, lr}}", @@ -53,8 +53,8 @@ intrinsics! { ); } + #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] - #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_idivmod() { core::arch::asm!( "push {{r0, r1, r4, lr}}", @@ -67,8 +67,8 @@ intrinsics! { ); } + #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] - #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_ldivmod() { core::arch::asm!( "push {{r4, lr}}", @@ -88,14 +88,14 @@ intrinsics! { // with custom implementation. // FIXME: The `*4` and `*8` variants should be defined as aliases. + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { ::mem::memcpy(dest, src, n); } + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { // We are guaranteed 4-alignment, so accessing at u32 is okay. let mut dest = dest as *mut u32; @@ -112,39 +112,39 @@ intrinsics! { __aeabi_memcpy(dest as *mut u8, src as *const u8, n); } + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memcpy4(dest, src, n); } + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { ::mem::memmove(dest, src, n); } + #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } + #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { // Note the different argument order ::mem::memset(dest, c, n); } + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { let mut dest = dest as *mut u32; let mut n = n; @@ -161,26 +161,26 @@ intrinsics! { __aeabi_memset(dest as *mut u8, n, byte as i32); } + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { __aeabi_memset4(dest, n, c); } + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { __aeabi_memset(dest, n, 0); } + #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } + #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 477c2568431..59f25317e66 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -25,6 +25,12 @@ macro_rules! public_test_dep { /// platforms need and elsewhere in this library it just looks like normal Rust /// code. /// +/// When the weak-intrinsics feature is enabled, all intrinsics functions are +/// marked with #[linkage = "weak"] so that they can be replaced by another +/// implementation at link time. This is particularly useful for mixed Rust/C++ +/// binaries that want to use the C++ intrinsics, otherwise linking against the +/// Rust stdlib will replace those from the compiler-rt library. +/// /// This macro is structured to be invoked with a bunch of functions that looks /// like: /// @@ -46,6 +52,10 @@ macro_rules! public_test_dep { /// /// A quick overview of attributes supported right now are: /// +/// * `weak` - indicates that the function should always be given weak linkage. +/// This attribute must come before other attributes, as the other attributes +/// will generate the final output function and need to have `weak` modify +/// them. /// * `maybe_use_optimized_c_shim` - indicates that the Rust implementation is /// ignored if an optimized C version was compiled. /// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and @@ -57,7 +67,6 @@ macro_rules! public_test_dep { /// it's a normal ABI elsewhere for returning a 128 bit integer. /// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM /// their otherwise typical names to other prefixed ones. -/// macro_rules! intrinsics { () => (); @@ -89,6 +98,95 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // Same as above but for unsafe. + ( + #[cfg_attr($e:meta, $($attr:tt)*)] + $(#[$($attrs:tt)*])* + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + $($rest:tt)* + ) => ( + #[cfg($e)] + intrinsics! { + #[$($attr)*] + $(#[$($attrs)*])* + pub unsafe extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { + $($body)* + } + } + + #[cfg(not($e))] + intrinsics! { + $(#[$($attrs)*])* + pub unsafe extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // Explicit weak linkage gets dropped when weak-intrinsics is on since it + // will be added unconditionally to all intrinsics and would conflict + // otherwise. + ( + #[weak] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(feature = "weak-intrinsics")] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + #[cfg(not(feature = "weak-intrinsics"))] + intrinsics! { + $(#[$($attr)*])* + #[linkage = "weak"] + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + // Same as above but for unsafe. + ( + #[weak] + $(#[$($attr:tt)*])* + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(feature = "weak-intrinsics")] + intrinsics! { + $(#[$($attr)*])* + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + #[cfg(not(feature = "weak-intrinsics"))] + intrinsics! { + $(#[$($attr)*])* + #[linkage = "weak"] + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); // Right now there's a bunch of architecture-optimized intrinsics in the // stock compiler-rt implementation. Not all of these have been ported over @@ -112,6 +210,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg($name = "optimized-c")] + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { extern $abi { fn $name($($argname: $ty),*) $(-> $ret)?; @@ -211,6 +310,7 @@ macro_rules! intrinsics { ) => ( #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] $(#[$($attr)*])* + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -218,6 +318,7 @@ macro_rules! intrinsics { #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] pub mod $name { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) -> ::macros::win64_128bit_abi_hack::U64x2 { @@ -258,6 +359,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] pub mod $name { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -266,7 +368,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] pub mod $alias { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] + #[cfg_attr(any(all(not(windows), not(target_vendor="apple"), feature = "weak-intrinsics")), linkage = "weak")] pub extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -302,6 +404,7 @@ macro_rules! intrinsics { pub mod $name { $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -325,6 +428,7 @@ macro_rules! intrinsics { #[naked] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -391,6 +495,7 @@ macro_rules! intrinsics { pub mod $name { $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -416,6 +521,7 @@ macro_rules! intrinsics { pub mod $name { $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index be118778b1a..ccf191779f4 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -20,15 +20,15 @@ use core::ops::{BitOr, Shl}; mod impls; intrinsics! { + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { impls::copy_forward(dest, src, n); dest } + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { let delta = (dest as usize).wrapping_sub(src as usize); if delta >= n { @@ -41,27 +41,27 @@ intrinsics! { dest } + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memset(s: *mut u8, c: crate::mem::c_int, n: usize) -> *mut u8 { impls::set_bytes(s, c as u8, n); s } + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { impls::compare_bytes(s1, s2, n) } + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { memcmp(s1, s2, n) } + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn strlen(s: *const core::ffi::c_char) -> usize { impls::c_string_length(s) } -- cgit 1.4.1-3-g733a5 From 2eb4f692bc0b3e375cd16edea7b75c3abfd02cff Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 20 May 2023 10:49:41 +0200 Subject: Upgrade libm to 0.2.7 --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 4c8a973741c..1dbb9d2d476 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 4c8a973741c014b11ce7f1477693a3e5d4ef9609 +Subproject commit 1dbb9d2d476d65d020feca17b11391652038e2e1 -- cgit 1.4.1-3-g733a5 From 92d88fd7a4a556cb438fe583215061dc1dfded4d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 20 May 2023 10:50:12 +0200 Subject: Bump to 0.1.92 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 57b8b34c75d..0f30668cc6f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.91" +version = "0.1.92" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 73f57893aa93547d247efce0b7b513d837df2111 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Mon, 12 Jun 2023 14:04:10 +0200 Subject: fix: Add `#[avr_skip]` for floats Same story as always, i.e. ABI mismatch: - https://github.com/rust-lang/compiler-builtins/pull/462 - https://github.com/rust-lang/compiler-builtins/pull/466 - https://github.com/rust-lang/compiler-builtins/pull/513 I've made sure the changes work by rendering a Mandelbrot fractal: ```rust #[arduino_hal::entry] fn main() -> ! { let dp = arduino_hal::Peripherals::take().unwrap(); let pins = arduino_hal::pins!(dp); let mut serial = arduino_hal::default_serial!(dp, pins, 57600); mandelbrot(&mut serial, 60, 40, -2.05, -1.12, 0.47, 1.12, 100); loop { // } } fn mandelbrot( output: &mut T, viewport_width: i64, viewport_height: i64, x1: f32, y1: f32, x2: f32, y2: f32, max_iterations: i64, ) where T: uWrite, { for viewport_y in 0..viewport_height { let y0 = y1 + (y2 - y1) * ((viewport_y as f32) / (viewport_height as f32)); for viewport_x in 0..viewport_width { let x0 = x1 + (x2 - x1) * ((viewport_x as f32) / (viewport_width as f32)); let mut x = 0.0; let mut y = 0.0; let mut iterations = max_iterations; while x * x + y * y <= 4.0 && iterations > 0 { let xtemp = x * x - y * y + x0; y = 2.0 * x * y + y0; x = xtemp; iterations -= 1; } let ch = "#%=-:,. " .chars() .nth((8.0 * ((iterations as f32) / (max_iterations as f32))) as _) .unwrap(); _ = ufmt::uwrite!(output, "{}", ch); } _ = ufmt::uwriteln!(output, ""); } } ``` ... where without avr_skips, the code printed an image full of only `#`. Note that because libgcc doesn't provide implementations for f64, using those (e.g. swapping f32 to f64 in the code above) will cause linking to fail: ``` undefined reference to `__divdf3' undefined reference to `__muldf3' undefined reference to `__gedf2' undefined reference to `__fixunsdfsi' undefined reference to `__gtdf2' ``` Ideally compiler-builtins could jump right in and provide those, but f64 also require a special calling convention which hasn't been yet exposed through LLVM. Note that because using 64-bit floats on an 8-bit target is a pretty niche thing to do, and because f64 floats don't work correctly anyway at the moment (due to this ABI mismatch), we're not actually breaking anything by skipping those functions, since any code that currently uses f64 on AVR works by accident. Closes https://github.com/rust-lang/rust/issues/108489. --- library/compiler-builtins/src/float/cmp.rs | 14 ++++++++++++++ library/compiler-builtins/src/macros.rs | 11 +++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 1d4e384335b..1bd7aa284d8 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -99,60 +99,74 @@ fn unord(a: F, b: F) -> bool { } intrinsics! { + #[avr_skip] pub extern "C" fn __lesf2(a: f32, b: f32) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __gesf2(a: f32, b: f32) -> i32 { cmp(a, b).to_ge_abi() } + #[avr_skip] #[arm_aeabi_alias = __aeabi_fcmpun] pub extern "C" fn __unordsf2(a: f32, b: f32) -> i32 { unord(a, b) as i32 } + #[avr_skip] pub extern "C" fn __eqsf2(a: f32, b: f32) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __ltsf2(a: f32, b: f32) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __nesf2(a: f32, b: f32) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __gtsf2(a: f32, b: f32) -> i32 { cmp(a, b).to_ge_abi() } + #[avr_skip] pub extern "C" fn __ledf2(a: f64, b: f64) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __gedf2(a: f64, b: f64) -> i32 { cmp(a, b).to_ge_abi() } + #[avr_skip] #[arm_aeabi_alias = __aeabi_dcmpun] pub extern "C" fn __unorddf2(a: f64, b: f64) -> i32 { unord(a, b) as i32 } + #[avr_skip] pub extern "C" fn __eqdf2(a: f64, b: f64) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __ltdf2(a: f64, b: f64) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __nedf2(a: f64, b: f64) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __gtdf2(a: f64, b: f64) -> i32 { cmp(a, b).to_ge_abi() } diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 59f25317e66..f1e2c533a3f 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -437,12 +437,11 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // For division and modulo, AVR uses a custom calling convention¹ that does - // not match our definitions here. Ideally we would just use hand-written - // naked functions, but that's quite a lot of code to port² - so for the - // time being we are just ignoring the problematic functions, letting - // avr-gcc (which is required to compile to AVR anyway) link them from - // libgcc. + // For some intrinsics, AVR uses a custom calling convention¹ that does not + // match our definitions here. Ideally we would just use hand-written naked + // functions, but that's quite a lot of code to port² - so for the time + // being we are just ignoring the problematic functions, letting avr-gcc + // (which is required to compile to AVR anyway) link them from libgcc. // // ¹ https://gcc.gnu.org/wiki/avr-gcc (see "Exceptions to the Calling // Convention") -- cgit 1.4.1-3-g733a5 From 2eeedaf25aea1a466231d7f625a55b578683b920 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 12 Jun 2023 15:37:22 +0100 Subject: Bump to 0.1.93 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0f30668cc6f..6cfa2b99e38 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.92" +version = "0.1.93" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From d3951c082ef5265c39ec5718ad54da0db9356962 Mon Sep 17 00:00:00 2001 From: kirk Date: Sat, 17 Jun 2023 14:07:45 +0000 Subject: allow stable features lint, fix link formatting warning, add ignore block to intrinsics macro documentation --- library/compiler-builtins/examples/intrinsics.rs | 1 + library/compiler-builtins/src/float/conv.rs | 2 +- library/compiler-builtins/src/macros.rs | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 0ca30c215b3..19bb569b57d 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -4,6 +4,7 @@ // to link due to the missing intrinsic (symbol). #![allow(unused_features)] +#![allow(stable_features)] // bench_black_box feature is stable, leaving for backcompat #![cfg_attr(thumb, no_main)] #![deny(dead_code)] #![feature(bench_black_box)] diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index a27d542fae3..790c0ab9f35 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -3,7 +3,7 @@ /// These are hand-optimized bit twiddling code, /// which unfortunately isn't the easiest kind of code to read. /// -/// The algorithm is explained here: https://blog.m-ou.se/floats/ +/// The algorithm is explained here: mod int_to_float { pub fn u32_to_f32_bits(i: u32) -> u32 { if i == 0 { diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index f1e2c533a3f..b3becde7230 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -33,7 +33,7 @@ macro_rules! public_test_dep { /// /// This macro is structured to be invoked with a bunch of functions that looks /// like: -/// +/// ```ignore /// intrinsics! { /// pub extern "C" fn foo(a: i32) -> u32 { /// // ... @@ -44,6 +44,7 @@ macro_rules! public_test_dep { /// // ... /// } /// } +/// ``` /// /// Each function is defined in a manner that looks like a normal Rust function. /// The macro then accepts a few nonstandard attributes that can decorate -- cgit 1.4.1-3-g733a5 From fad0b3a4316f5cb954af4513dd42f2e80b087ef4 Mon Sep 17 00:00:00 2001 From: kirk Date: Sat, 17 Jun 2023 14:35:00 +0000 Subject: change links in README to match reference code version used in CI --- library/compiler-builtins/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 8b25558a87e..da0adbce70c 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -59,8 +59,8 @@ features = ["c"] 5. Once the PR passes our extensive [testing infrastructure][4], we'll merge it! 6. Celebrate :tada: -[1]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/test/builtins/Unit -[2]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/lib/builtins +[1]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/test/builtins/Unit +[2]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/lib/builtins [3]: https://github.com/rust-lang/compiler-builtins/blob/0ba07e49264a54cb5bbd4856fcea083bb3fbec15/build.rs#L180-L265 [4]: https://travis-ci.org/rust-lang/compiler-builtins -- cgit 1.4.1-3-g733a5 From 21c821c6c973bbdffe558ede2dd7c483735b9f3f Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 25 Jun 2023 21:07:00 +0000 Subject: Port outline-atomics to rust This has a very long history, summarized in https://github.com/rust-lang/rust/issues/109064. This port is a very minimal subset of `aarch64/lse.S` from LLVM's compiler-rt. In particular, it is missing the following: 1. Any form of runtime dispatch between LL/SC and LSE. Determining which version of the intrinsics to use requires one of the following: i) `getauxval` from glibc. It's unclear whether `compiler_builtins` is allowed to depend on libc at all, and musl doesn't even support getauxval. Don't enshrine the requirement "de-facto" by making it required for outline-atomics. ii) kernel support. Linux and FreeBSD have limited support, but it requires an extremely recent kernel version and doesn't work at all under QEMU (https://github.com/rust-lang/rust/issues/109064#issuecomment-1494939904). Instead, we hard-code LL/SC intrinsics. Users who want LSE support should use the LLVM compiler-rt (if you're building from source in rust-lang/rust, make sure you have `src/llvm-project` checked out locally. the goal is to soon add a new `optimized-compiler-builtins` option so this is easier to discover). 2. The global `___aarch64_have_lse_atomics` CTOR, required to do runtime dispatch. Thom Chiviolani has this to say about global CTORs: > static ctors are problems because we are pretty eager about dead code elim > in general if you have a module that isnt directly reference we will probably not have its static ctors > also, while llvm has a super robust way to have a static ctor (theres s special "appending global" to use for c++), we dont use that and just have people make a #[used] static in a special section > 1. the robust way kinda requires rust knowing that the argument is a static ctor (maybe a #[rustc_static_ctor] attribute). it also would be... finnicky, since on windows we actually care beyond being a static ctor, that we run as part in a specific group of ctors, which means a very specific section (one for TLS and the other for, uh, i dont remember) > 2. we still actually have to codegen the cgu that isn't referenced. but maybe we could remember that it has that attribute and use that So while this is possible in theory, it's decidedly non-trivial, and needs invasive changes to rust itself. In any case, it doesn't matter until we decide the story around libc. 3. The 16-byte (i128) version of compare_and_swap. This wouldn't be *too* hard to add, but it would be hard to test. The way I tested the existing code was not just with unit tests but also by loading it as a path dependency and running `x test core` - the latter caught several bugs the unit tests didn't catch (because I originally wrote the tests wrong). So I am slightly nervous about adding a 16-byte version that is much more poorly tested than the other intrinsics. --- library/compiler-builtins/build.rs | 57 +++++- library/compiler-builtins/src/aarch64.rs | 221 +++++++++++++++++++++++ library/compiler-builtins/src/lib.rs | 3 + library/compiler-builtins/src/macros.rs | 2 +- library/compiler-builtins/testcrate/tests/lse.rs | 88 +++++++++ 5 files changed, 369 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/src/aarch64.rs create mode 100644 library/compiler-builtins/testcrate/tests/lse.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 766dec05d9b..266cc28bb2f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,4 +1,4 @@ -use std::env; +use std::{collections::HashMap, env, sync::atomic::Ordering}; fn main() { println!("cargo:rerun-if-changed=build.rs"); @@ -90,6 +90,61 @@ fn main() { { println!("cargo:rustc-cfg=kernel_user_helpers") } + + if llvm_target[0] == "aarch64" { + generate_aarch64_outlined_atomics(); + } +} + +fn aarch64_symbol(ordering: Ordering) -> &'static str { + match ordering { + Ordering::Relaxed => "relax", + Ordering::Acquire => "acq", + Ordering::Release => "rel", + Ordering::AcqRel => "acq_rel", + _ => panic!("unknown symbol for {:?}", ordering), + } +} + +/// The `concat_idents` macro is extremely annoying and doesn't allow us to define new items. +/// Define them from the build script instead. +/// Note that the majority of the code is still defined in `aarch64.rs` through inline macros. +fn generate_aarch64_outlined_atomics() { + use std::fmt::Write; + // #[macro_export] so that we can use this in tests + let gen_macro = + |name| format!("#[macro_export] macro_rules! foreach_{name} {{ ($macro:path) => {{\n"); + + // Generate different macros for add/clr/eor/set so that we can test them separately. + let sym_names = ["cas", "ldadd", "ldclr", "ldeor", "ldset", "swp"]; + let mut macros = HashMap::new(); + for sym in sym_names { + macros.insert(sym, gen_macro(sym)); + } + + for ordering in [ + Ordering::Relaxed, + Ordering::Acquire, + Ordering::Release, + Ordering::AcqRel, + ] { + let sym_ordering = aarch64_symbol(ordering); + // TODO: support CAS 16 + for size in [1, 2, 4, 8 /* , 16*/] { + for (sym, macro_) in &mut macros { + let name = format!("__aarch64_{sym}{size}_{sym_ordering}"); + writeln!(macro_, "$macro!( {ordering:?}, {size}, {name} );").unwrap(); + } + } + } + + let mut buf = String::new(); + for macro_def in macros.values() { + buf += macro_def; + buf += "}; }"; + } + let dst = std::env::var("OUT_DIR").unwrap() + "/outlined_atomics.rs"; + std::fs::write(dst, buf).unwrap(); } #[cfg(feature = "c")] diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64.rs new file mode 100644 index 00000000000..018880650d3 --- /dev/null +++ b/library/compiler-builtins/src/aarch64.rs @@ -0,0 +1,221 @@ +//! Aarch64 targets have two possible implementations for atomics: +//! 1. Load-Locked, Store-Conditional (LL/SC), older and slower. +//! 2. Large System Extensions (LSE), newer and faster. +//! To avoid breaking backwards compat, C toolchains introduced a concept of "outlined atomics", +//! where atomic operations call into the compiler runtime to dispatch between two depending on +//! which is supported on the current CPU. +//! See https://community.arm.com/arm-community-blogs/b/tools-software-ides-blog/posts/making-the-most-of-the-arm-architecture-in-gcc-10#:~:text=out%20of%20line%20atomics for more discussion. +//! +//! Currently we only support LL/SC, because LSE requires `getauxval` from libc in order to do runtime detection. +//! Use the `compiler-rt` intrinsics if you want LSE support. +//! +//! Ported from `aarch64/lse.S` in LLVM's compiler-rt. +//! +//! Generate functions for each of the following symbols: +//! __aarch64_swpN_ORDER +//! __aarch64_ldaddN_ORDER +//! __aarch64_ldclrN_ORDER +//! __aarch64_ldeorN_ORDER +//! __aarch64_ldsetN_ORDER +//! for N = {1, 2, 4, 8}, M = {1, 2, 4, 8}, ORDER = { relax, acq, rel, acq_rel } +//! +//! TODO: M = 16 +//! +//! The original `lse.S` has some truly horrifying code that expects to be compiled multiple times with different constants. +//! We do something similar, but with macro arguments. + +/// We don't do runtime dispatch so we don't have to worry about the global ctor. +/// Apparently MacOS uses a different number of underscores in the symbol name (???) +// #[cfg(target_vendor = "apple")] +// macro_rules! have_lse { +// () => { ___aarch64_have_lse_atomics } +// } + +// #[cfg(not(target_vendor = "apple"))] +// macro_rules! have_lse { +// () => { __aarch64_have_lse_atomics } +// } + +/// Translate a byte size to a Rust type. +macro_rules! int_ty { + (1) => { i8 }; + (2) => { i16 }; + (4) => { i32 }; + (8) => { i64 }; + (16) => { i128 }; +} + +/// Given a byte size and a register number, return a register of the appropriate size. +/// +/// See . +macro_rules! reg { + (1, $num:literal) => { concat!("w", $num) }; + (2, $num:literal) => { concat!("w", $num) }; + (4, $num:literal) => { concat!("w", $num) }; + (8, $num:literal) => { concat!("x", $num) }; +} + +/// Given an atomic ordering, translate it to the acquire suffix for the lxdr aarch64 ASM instruction. +macro_rules! acquire { + (Relaxed) => { "" }; + (Acquire) => { "a" }; + (Release) => { "" }; + (AcqRel) => { "a" }; +} + +/// Given an atomic ordering, translate it to the release suffix for the stxr aarch64 ASM instruction. +macro_rules! release { + (Relaxed) => { "" }; + (Acquire) => { "" }; + (Release) => { "l" }; + (AcqRel) => { "l" }; +} + +/// Given a size in bytes, translate it to the byte suffix for an aarch64 ASM instruction. +macro_rules! size { + (1) => { "b" }; + (2) => { "h" }; + (4) => { "" }; + (8) => { "" }; + (16) => { "" }; +} + +/// Given a byte size, translate it to an Unsigned eXTend instruction +/// with the correct semantics. +/// +/// See +macro_rules! uxt { + (1) => { "uxtb" }; + (2) => { "uxth" }; + ($_:tt) => { "mov" }; +} + +/// Given an atomic ordering and byte size, translate it to a LoaD eXclusive Register instruction +/// with the correct semantics. +/// +/// See . +macro_rules! ldxr { + ($ordering:ident, $bytes:tt) => { concat!("ld", acquire!($ordering), "xr", size!($bytes)) } +} + +/// Given an atomic ordering and byte size, translate it to a STore eXclusive Register instruction +/// with the correct semantics. +/// +/// See . +macro_rules! stxr { + ($ordering:ident, $bytes:tt) => { concat!("st", release!($ordering), "xr", size!($bytes)) } +} + +/// See . +macro_rules! compare_and_swap { + ($ordering:ident, $bytes:tt, $name:ident) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub extern "C" fn $name ( + expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes) + ) -> int_ty!($bytes) { + // We can't use `AtomicI8::compare_and_swap`; we *are* compare_and_swap. + unsafe { core::arch::asm! { + // UXT s(tmp0), s(0) + concat!(uxt!($bytes), " ", reg!($bytes, 16), ", ", reg!($bytes, 0)), + "0:", + // LDXR s(0), [x2] + concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x2]"), + // cmp s(0), s(tmp0) + concat!("cmp ", reg!($bytes, 0), ", ", reg!($bytes, 16)), + "bne 1f", + // STXR w(tmp1), s(1), [x2] + concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 1), ", [x2]"), + "cbnz w17, 0b", + "1:", + "ret", + options(noreturn) + } } + } + } + } +} + + +/// See . +macro_rules! swap { + ($ordering:ident, $bytes:tt, $name:ident) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub extern "C" fn $name ( + left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes) + ) -> int_ty!($bytes) { + unsafe { core::arch::asm! { + // mov s(tmp0), s(0) + concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), + "0:", + // LDXR s(0), [x1] + concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x1]"), + // STXR w(tmp1), s(tmp0), [x1] + concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 16), ", [x1]"), + "cbnz w17, 0b", + "ret", + options(noreturn) + } } + } + } + } +} + +/// See (e.g.) . +macro_rules! fetch_op { + ($ordering:ident, $bytes:tt, $name:ident, $op:literal) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub extern "C" fn $name ( + val: int_ty!($bytes), ptr: *mut int_ty!($bytes) + ) -> int_ty!($bytes) { + unsafe { core::arch::asm! { + // mov s(tmp0), s(0) + concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), + "0:", + // LDXR s(0), [x1] + concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x1]"), + // OP s(tmp1), s(0), s(tmp0) + concat!($op, " ", reg!($bytes, 17), ", ", reg!($bytes, 0), ", ", reg!($bytes, 16)), + // STXR w(tmp2), s(tmp1), [x1] + concat!(stxr!($ordering, $bytes), " w15, ", reg!($bytes, 17), ", [x1]"), + "cbnz w15, 0b", + "ret", + options(noreturn) + } } + } + } + } +} + +// We need a single macro to pass to `foreach_ldadd`. +macro_rules! add { + ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "add" } } +} + +macro_rules! and { + ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "bic" } } +} + +macro_rules! xor { + ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "eor" } } +} + +macro_rules! or { + ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "orr" } } +} + +// See `generate_aarch64_outlined_atomics` in build.rs. +include!(concat!(env!("OUT_DIR"), "/outlined_atomics.rs")); +foreach_cas!(compare_and_swap); +foreach_swp!(swap); +foreach_ldadd!(add); +foreach_ldclr!(and); +foreach_ldeor!(xor); +foreach_ldset!(or); + +// TODO: CAS 16 diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 71f249c8eb3..90b21f1fc7f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -57,6 +57,9 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; +#[cfg(target_arch = "aarch64")] +pub mod aarch64; + #[cfg(all( kernel_user_helpers, any(target_os = "linux", target_os = "android"), diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index b3becde7230..e3a381928c6 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -419,7 +419,7 @@ macro_rules! intrinsics { ( #[naked] $(#[$($attr:tt)*])* - pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + pub $(unsafe)? extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } diff --git a/library/compiler-builtins/testcrate/tests/lse.rs b/library/compiler-builtins/testcrate/tests/lse.rs new file mode 100644 index 00000000000..49d73177e3b --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/lse.rs @@ -0,0 +1,88 @@ +#![cfg(target_arch = "aarch64")] +#![feature(decl_macro)] // so we can use pub(super) + +/// Translate a byte size to a Rust type. +macro int_ty { + (1) => { i8 }, + (2) => { i16 }, + (4) => { i32 }, + (8) => { i64 }, + (16) => { i128 } +} + +mod cas { + pub(super) macro test($_ordering:ident, $bytes:tt, $name:ident) { + #[test] + fn $name() { + testcrate::fuzz_2(10000, |expected: super::int_ty!($bytes), new| { + let mut target = expected.wrapping_add(10); + assert_eq!( + unsafe { compiler_builtins::aarch64::$name::$name(expected, new, &mut target) }, + expected.wrapping_add(10), + "return value should always be the previous value", + ); + assert_eq!( + target, + expected.wrapping_add(10), + "shouldn't have changed target" + ); + + target = expected; + assert_eq!( + unsafe { compiler_builtins::aarch64::$name::$name(expected, new, &mut target) }, + expected + ); + assert_eq!(target, new, "should have updated target"); + }); + } + } +} + +mod swap { + pub(super) macro test($_ordering:ident, $bytes:tt, $name:ident) { + #[test] + fn $name() { + testcrate::fuzz_2(10000, |left: super::int_ty!($bytes), mut right| { + let orig_right = right; + assert_eq!( + unsafe { compiler_builtins::aarch64::$name::$name(left, &mut right) }, + orig_right + ); + assert_eq!(left, right); + }); + } + } +} + +macro_rules! test_op { + ($mod:ident, $( $op:tt )* ) => { + mod $mod { + pub(super) macro test { + ($_ordering:ident, $bytes:tt, $name:ident) => { + #[test] + fn $name() { + testcrate::fuzz_2(10000, |old, val| { + let mut target = old; + let op: fn(super::int_ty!($bytes), super::int_ty!($bytes)) -> _ = $($op)*; + let expected = op(old, val); + assert_eq!(old, unsafe { compiler_builtins::aarch64::$name::$name(val, &mut target) }, "{} should return original value", stringify!($name)); + assert_eq!(expected, target, "{} should store to target", stringify!($name)); + }); + } + } + } + } + }; +} + +test_op!(add, |left, right| left.wrapping_add(right)); +test_op!(clr, |left, right| left & !right); +test_op!(xor, std::ops::BitXor::bitxor); +test_op!(or, std::ops::BitOr::bitor); + +compiler_builtins::foreach_cas!(cas::test); +compiler_builtins::foreach_swp!(swap::test); +compiler_builtins::foreach_ldadd!(add::test); +compiler_builtins::foreach_ldclr!(clr::test); +compiler_builtins::foreach_ldeor!(xor::test); +compiler_builtins::foreach_ldset!(or::test); -- cgit 1.4.1-3-g733a5 From 6242fd629e7a680d090e5606954de85ccf5be187 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 26 Jun 2023 13:54:47 +0000 Subject: address review comments and fix CI - implement CAS 16 - remove useless commented out symbol name - support `feature("no-asm")` - fix warnings when `feature("c")` is enabled - rustfmt --- library/compiler-builtins/build.rs | 10 ++- library/compiler-builtins/src/aarch64.rs | 103 +++++++++++++++++------ library/compiler-builtins/src/lib.rs | 6 +- library/compiler-builtins/testcrate/tests/lse.rs | 7 +- 4 files changed, 97 insertions(+), 29 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 266cc28bb2f..4549d0b4f16 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -122,6 +122,9 @@ fn generate_aarch64_outlined_atomics() { macros.insert(sym, gen_macro(sym)); } + // Only CAS supports 16 bytes, and it has a different implementation that uses a different macro. + let mut cas16 = gen_macro("cas16"); + for ordering in [ Ordering::Relaxed, Ordering::Acquire, @@ -129,17 +132,18 @@ fn generate_aarch64_outlined_atomics() { Ordering::AcqRel, ] { let sym_ordering = aarch64_symbol(ordering); - // TODO: support CAS 16 - for size in [1, 2, 4, 8 /* , 16*/] { + for size in [1, 2, 4, 8] { for (sym, macro_) in &mut macros { let name = format!("__aarch64_{sym}{size}_{sym_ordering}"); writeln!(macro_, "$macro!( {ordering:?}, {size}, {name} );").unwrap(); } } + let name = format!("__aarch64_cas16_{sym_ordering}"); + writeln!(cas16, "$macro!( {ordering:?}, {name} );").unwrap(); } let mut buf = String::new(); - for macro_def in macros.values() { + for macro_def in macros.values().chain(std::iter::once(&cas16)) { buf += macro_def; buf += "}; }"; } diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64.rs index 018880650d3..1aaa1a69472 100644 --- a/library/compiler-builtins/src/aarch64.rs +++ b/library/compiler-builtins/src/aarch64.rs @@ -12,31 +12,21 @@ //! Ported from `aarch64/lse.S` in LLVM's compiler-rt. //! //! Generate functions for each of the following symbols: +//! __aarch64_casM_ORDER //! __aarch64_swpN_ORDER //! __aarch64_ldaddN_ORDER //! __aarch64_ldclrN_ORDER //! __aarch64_ldeorN_ORDER //! __aarch64_ldsetN_ORDER -//! for N = {1, 2, 4, 8}, M = {1, 2, 4, 8}, ORDER = { relax, acq, rel, acq_rel } -//! -//! TODO: M = 16 +//! for N = {1, 2, 4, 8}, M = {1, 2, 4, 8, 16}, ORDER = { relax, acq, rel, acq_rel } //! //! The original `lse.S` has some truly horrifying code that expects to be compiled multiple times with different constants. //! We do something similar, but with macro arguments. -/// We don't do runtime dispatch so we don't have to worry about the global ctor. -/// Apparently MacOS uses a different number of underscores in the symbol name (???) -// #[cfg(target_vendor = "apple")] -// macro_rules! have_lse { -// () => { ___aarch64_have_lse_atomics } -// } - -// #[cfg(not(target_vendor = "apple"))] -// macro_rules! have_lse { -// () => { __aarch64_have_lse_atomics } -// } +// We don't do runtime dispatch so we don't have to worry about the `__aarch64_have_lse_atomics` global ctor. /// Translate a byte size to a Rust type. +#[rustfmt::skip] macro_rules! int_ty { (1) => { i8 }; (2) => { i16 }; @@ -48,6 +38,7 @@ macro_rules! int_ty { /// Given a byte size and a register number, return a register of the appropriate size. /// /// See . +#[rustfmt::skip] macro_rules! reg { (1, $num:literal) => { concat!("w", $num) }; (2, $num:literal) => { concat!("w", $num) }; @@ -56,6 +47,7 @@ macro_rules! reg { } /// Given an atomic ordering, translate it to the acquire suffix for the lxdr aarch64 ASM instruction. +#[rustfmt::skip] macro_rules! acquire { (Relaxed) => { "" }; (Acquire) => { "a" }; @@ -64,6 +56,7 @@ macro_rules! acquire { } /// Given an atomic ordering, translate it to the release suffix for the stxr aarch64 ASM instruction. +#[rustfmt::skip] macro_rules! release { (Relaxed) => { "" }; (Acquire) => { "" }; @@ -72,6 +65,7 @@ macro_rules! release { } /// Given a size in bytes, translate it to the byte suffix for an aarch64 ASM instruction. +#[rustfmt::skip] macro_rules! size { (1) => { "b" }; (2) => { "h" }; @@ -84,6 +78,7 @@ macro_rules! size { /// with the correct semantics. /// /// See +#[rustfmt::skip] macro_rules! uxt { (1) => { "uxtb" }; (2) => { "uxth" }; @@ -95,7 +90,9 @@ macro_rules! uxt { /// /// See . macro_rules! ldxr { - ($ordering:ident, $bytes:tt) => { concat!("ld", acquire!($ordering), "xr", size!($bytes)) } + ($ordering:ident, $bytes:tt) => { + concat!("ld", acquire!($ordering), "xr", size!($bytes)) + }; } /// Given an atomic ordering and byte size, translate it to a STore eXclusive Register instruction @@ -103,7 +100,29 @@ macro_rules! ldxr { /// /// See . macro_rules! stxr { - ($ordering:ident, $bytes:tt) => { concat!("st", release!($ordering), "xr", size!($bytes)) } + ($ordering:ident, $bytes:tt) => { + concat!("st", release!($ordering), "xr", size!($bytes)) + }; +} + +/// Given an atomic ordering and byte size, translate it to a LoaD eXclusive Pair of registers instruction +/// with the correct semantics. +/// +/// See +macro_rules! ldxp { + ($ordering:ident) => { + concat!("ld", acquire!($ordering), "xp") + }; +} + +/// Given an atomic ordering and byte size, translate it to a STore eXclusive Pair of registers instruction +/// with the correct semantics. +/// +/// See . +macro_rules! stxp { + ($ordering:ident) => { + concat!("st", release!($ordering), "xp") + }; } /// See . @@ -134,9 +153,38 @@ macro_rules! compare_and_swap { } } } } - } + }; } +// i128 uses a completely different impl, so it has its own macro. +macro_rules! compare_and_swap_i128 { + ($ordering:ident, $name:ident) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub extern "C" fn $name ( + expected: i128, desired: i128, ptr: *mut i128 + ) -> i128 { + unsafe { core::arch::asm! { + "mov x16, x0", + "mov x17, x1", + "0:", + // LDXP x0, x1, [x4] + concat!(ldxp!($ordering), " x0, x1, [x4]"), + "cmp x0, x16", + "ccmp x1, x17, #0, eq", + "bne 1f", + // STXP w(tmp2), x2, x3, [x4] + concat!(stxp!($ordering), " w15, x2, x3, [x4]"), + "cbnz w15, 0b", + "1:", + "ret", + options(noreturn) + } } + } + } + }; +} /// See . macro_rules! swap { @@ -161,7 +209,7 @@ macro_rules! swap { } } } } - } + }; } /// See (e.g.) . @@ -194,28 +242,35 @@ macro_rules! fetch_op { // We need a single macro to pass to `foreach_ldadd`. macro_rules! add { - ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "add" } } + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "add" } + }; } macro_rules! and { - ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "bic" } } + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "bic" } + }; } macro_rules! xor { - ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "eor" } } + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "eor" } + }; } macro_rules! or { - ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "orr" } } + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "orr" } + }; } // See `generate_aarch64_outlined_atomics` in build.rs. include!(concat!(env!("OUT_DIR"), "/outlined_atomics.rs")); foreach_cas!(compare_and_swap); +foreach_cas16!(compare_and_swap_i128); foreach_swp!(swap); foreach_ldadd!(add); foreach_ldclr!(and); foreach_ldeor!(xor); foreach_ldset!(or); - -// TODO: CAS 16 diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 90b21f1fc7f..4b44adc266d 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -57,7 +57,11 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; -#[cfg(target_arch = "aarch64")] +#[cfg(all( + target_arch = "aarch64", + not(feature = "no-asm"), + not(feature = "optimized-c") +))] pub mod aarch64; #[cfg(all( diff --git a/library/compiler-builtins/testcrate/tests/lse.rs b/library/compiler-builtins/testcrate/tests/lse.rs index 49d73177e3b..7b54ab5d286 100644 --- a/library/compiler-builtins/testcrate/tests/lse.rs +++ b/library/compiler-builtins/testcrate/tests/lse.rs @@ -1,5 +1,5 @@ -#![cfg(target_arch = "aarch64")] #![feature(decl_macro)] // so we can use pub(super) +#![cfg(all(target_arch = "aarch64", not(feature = "no-asm")))] /// Translate a byte size to a Rust type. macro int_ty { @@ -38,6 +38,10 @@ mod cas { } } +macro test_cas16($_ordering:ident, $name:ident) { + cas::test!($_ordering, 16, $name); +} + mod swap { pub(super) macro test($_ordering:ident, $bytes:tt, $name:ident) { #[test] @@ -81,6 +85,7 @@ test_op!(xor, std::ops::BitXor::bitxor); test_op!(or, std::ops::BitOr::bitor); compiler_builtins::foreach_cas!(cas::test); +compiler_builtins::foreach_cas16!(test_cas16); compiler_builtins::foreach_swp!(swap::test); compiler_builtins::foreach_ldadd!(add::test); compiler_builtins::foreach_ldclr!(clr::test); -- cgit 1.4.1-3-g733a5 From e7c4a453484da043e2affdd8320151beafec94b1 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 26 Jun 2023 16:27:16 +0000 Subject: require naked functions to be unsafe again they dereference raw pointers, so the caller needs to make sure the pointer is valid. note that this requires changing `maybe_use_optimized_c_shim` to support unsafe functions. --- library/compiler-builtins/src/aarch64.rs | 8 ++++---- library/compiler-builtins/src/macros.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64.rs index 1aaa1a69472..ddbec6d327b 100644 --- a/library/compiler-builtins/src/aarch64.rs +++ b/library/compiler-builtins/src/aarch64.rs @@ -131,7 +131,7 @@ macro_rules! compare_and_swap { intrinsics! { #[maybe_use_optimized_c_shim] #[naked] - pub extern "C" fn $name ( + pub unsafe extern "C" fn $name ( expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { // We can't use `AtomicI8::compare_and_swap`; we *are* compare_and_swap. @@ -162,7 +162,7 @@ macro_rules! compare_and_swap_i128 { intrinsics! { #[maybe_use_optimized_c_shim] #[naked] - pub extern "C" fn $name ( + pub unsafe extern "C" fn $name ( expected: i128, desired: i128, ptr: *mut i128 ) -> i128 { unsafe { core::arch::asm! { @@ -192,7 +192,7 @@ macro_rules! swap { intrinsics! { #[maybe_use_optimized_c_shim] #[naked] - pub extern "C" fn $name ( + pub unsafe extern "C" fn $name ( left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { unsafe { core::arch::asm! { @@ -218,7 +218,7 @@ macro_rules! fetch_op { intrinsics! { #[maybe_use_optimized_c_shim] #[naked] - pub extern "C" fn $name ( + pub unsafe extern "C" fn $name ( val: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { unsafe { core::arch::asm! { diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index e3a381928c6..b11114f1238 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -204,7 +204,7 @@ macro_rules! intrinsics { ( #[maybe_use_optimized_c_shim] $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + pub $(unsafe $(@ $empty:tt)? )? extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } @@ -212,7 +212,7 @@ macro_rules! intrinsics { ) => ( #[cfg($name = "optimized-c")] #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { extern $abi { fn $name($($argname: $ty),*) $(-> $ret)?; } @@ -224,7 +224,7 @@ macro_rules! intrinsics { #[cfg(not($name = "optimized-c"))] intrinsics! { $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -419,7 +419,7 @@ macro_rules! intrinsics { ( #[naked] $(#[$($attr:tt)*])* - pub $(unsafe)? extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } -- cgit 1.4.1-3-g733a5 From 379445f9a5514de341b0d2d731b8dfdcdcf20415 Mon Sep 17 00:00:00 2001 From: kirk Date: Sun, 25 Jun 2023 13:06:18 +0000 Subject: port updated version of llvm float div --- library/compiler-builtins/src/float/div.rs | 857 ++++++++++++++++----- .../compiler-builtins/testcrate/tests/div_rem.rs | 11 +- 2 files changed, 667 insertions(+), 201 deletions(-) diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index c2d6c07e73d..c0aae34fb63 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -12,11 +12,17 @@ where i32: CastInto, F::Int: CastInto, F::Int: HInt, + ::Int: core::ops::Mul, { + const NUMBER_OF_HALF_ITERATIONS: usize = 0; + const NUMBER_OF_FULL_ITERATIONS: usize = 3; + const USE_NATIVE_FULL_ITERATIONS: bool = true; + let one = F::Int::ONE; let zero = F::Int::ZERO; + let hw = F::BITS / 2; + let lo_mask = u32::MAX >> hw; - // let bits = F::BITS; let significand_bits = F::SIGNIFICAND_BITS; let max_exponent = F::EXPONENT_MAX; @@ -109,101 +115,341 @@ where } } - // Or in the implicit significand bit. (If we fell through from the + // Set the implicit significand bit. If we fell through from the // denormal path it was already set by normalize( ), but setting it twice - // won't hurt anything.) + // won't hurt anything. a_significand |= implicit_bit; b_significand |= implicit_bit; - let mut quotient_exponent: i32 = CastInto::::cast(a_exponent) - .wrapping_sub(CastInto::::cast(b_exponent)) - .wrapping_add(scale); - - // Align the significand of b as a Q31 fixed-point number in the range - // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax - // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This - // is accurate to about 3.5 binary digits. - let q31b = CastInto::::cast(b_significand << 8.cast()); - let mut reciprocal = (0x7504f333u32).wrapping_sub(q31b); - - // Now refine the reciprocal estimate using a Newton-Raphson iteration: - // - // x1 = x0 * (2 - x0 * b) - // - // This doubles the number of correct binary digits in the approximation - // with each iteration, so after three iterations, we have about 28 binary - // digits of accuracy. - - let mut correction: u32 = - negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); - reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) >> 31) as u32; - correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); - reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) >> 31) as u32; - correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); - reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) >> 31) as u32; - - // Exhaustive testing shows that the error in reciprocal after three steps - // is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our - // expectations. We bump the reciprocal by a tiny value to force the error - // to be strictly positive (in the range [0x1.4fdfp-37,0x1.287246p-29], to - // be specific). This also causes 1/1 to give a sensible approximation - // instead of zero (due to overflow). - reciprocal = reciprocal.wrapping_sub(2); - - // The numerical reciprocal is accurate to within 2^-28, lies in the - // interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller - // than the true reciprocal of b. Multiplying a by this reciprocal thus - // gives a numerical q = a/b in Q24 with the following properties: - // - // 1. q < a/b - // 2. q is in the interval [0x1.000000eep-1, 0x1.fffffffcp0) - // 3. the error in q is at most 2^-24 + 2^-27 -- the 2^24 term comes - // from the fact that we truncate the product, and the 2^27 term - // is the error in the reciprocal of b scaled by the maximum - // possible value of a. As a consequence of this error bound, - // either q or nextafter(q) is the correctly rounded - let mut quotient = (a_significand << 1).widen_mul(reciprocal.cast()).hi(); - - // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). - // In either case, we are going to compute a residual of the form - // - // r = a - q*b + + let written_exponent: i32 = CastInto::::cast( + a_exponent + .wrapping_sub(b_exponent) + .wrapping_add(scale.cast()), + ) + .wrapping_add(exponent_bias) as i32; + let b_uq1 = b_significand << (F::BITS - significand_bits - 1); + + // Align the significand of b as a UQ1.(n-1) fixed-point number in the range + // [1.0, 2.0) and get a UQ0.n approximate reciprocal using a small minimax + // polynomial approximation: x0 = 3/4 + 1/sqrt(2) - b/2. + // The max error for this approximation is achieved at endpoints, so + // abs(x0(b) - 1/b) <= abs(x0(1) - 1/1) = 3/4 - 1/sqrt(2) = 0.04289..., + // which is about 4.5 bits. + // The initial approximation is between x0(1.0) = 0.9571... and x0(2.0) = 0.4571... + + // Then, refine the reciprocal estimate using a quadratically converging + // Newton-Raphson iteration: + // x_{n+1} = x_n * (2 - x_n * b) // - // We know from the construction of q that r satisfies: + // Let b be the original divisor considered "in infinite precision" and + // obtained from IEEE754 representation of function argument (with the + // implicit bit set). Corresponds to rep_t-sized b_UQ1 represented in + // UQ1.(W-1). // - // 0 <= r < ulp(q)*b + // Let b_hw be an infinitely precise number obtained from the highest (HW-1) + // bits of divisor significand (with the implicit bit set). Corresponds to + // half_rep_t-sized b_UQ1_hw represented in UQ1.(HW-1) that is a **truncated** + // version of b_UQ1. // - // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we - // already have the correct result. The exact halfway case cannot occur. - // We also take this time to right shift quotient if it falls in the [1,2) - // range and adjust the exponent accordingly. - let residual = if quotient < (implicit_bit << 1) { - quotient_exponent = quotient_exponent.wrapping_sub(1); - (a_significand << (significand_bits + 1)).wrapping_sub(quotient.wrapping_mul(b_significand)) + // Let e_n := x_n - 1/b_hw + // E_n := x_n - 1/b + // abs(E_n) <= abs(e_n) + (1/b_hw - 1/b) + // = abs(e_n) + (b - b_hw) / (b*b_hw) + // <= abs(e_n) + 2 * 2^-HW + + // rep_t-sized iterations may be slower than the corresponding half-width + // variant depending on the handware and whether single/double/quad precision + // is selected. + // NB: Using half-width iterations increases computation errors due to + // rounding, so error estimations have to be computed taking the selected + // mode into account! + + #[allow(clippy::absurd_extreme_comparisons)] + let mut x_uq0 = if NUMBER_OF_HALF_ITERATIONS > 0 { + // Starting with (n-1) half-width iterations + let b_uq1_hw: u16 = + (CastInto::::cast(b_significand) >> (significand_bits + 1 - hw)) as u16; + + // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW + // with W0 being either 16 or 32 and W0 <= HW. + // That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from which + // b/2 is subtracted to obtain x0) wrapped to [0, 1) range. + + // HW is at least 32. Shifting into the highest bits if needed. + let c_hw = (0x7504_u32 as u16).wrapping_shl(hw.wrapping_sub(32)); + + // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, + // so x0 fits to UQ0.HW without wrapping. + let x_uq0_hw: u16 = { + let mut x_uq0_hw: u16 = c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); + // An e_0 error is comprised of errors due to + // * x0 being an inherently imprecise first approximation of 1/b_hw + // * C_hw being some (irrational) number **truncated** to W0 bits + // Please note that e_0 is calculated against the infinitely precise + // reciprocal of b_hw (that is, **truncated** version of b). + // + // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0 + + // By construction, 1 <= b < 2 + // f(x) = x * (2 - b*x) = 2*x - b*x^2 + // f'(x) = 2 * (1 - b*x) + // + // On the [0, 1] interval, f(0) = 0, + // then it increses until f(1/b) = 1 / b, maximum on (0, 1), + // then it decreses to f(1) = 2 - b + // + // Let g(x) = x - f(x) = b*x^2 - x. + // On (0, 1/b), g(x) < 0 <=> f(x) > x + // On (1/b, 1], g(x) > 0 <=> f(x) < x + // + // For half-width iterations, b_hw is used instead of b. + #[allow(clippy::reversed_empty_ranges)] + for _ in 0..NUMBER_OF_HALF_ITERATIONS { + // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp + // of corr_UQ1_hw. + // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1). + // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided + // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is + // expected to be strictly positive because b_UQ1_hw has its highest bit set + // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). + let corr_uq1_hw: u16 = + 0.wrapping_sub((x_uq0_hw as u32).wrapping_mul(b_uq1_hw.cast()) >> hw) as u16; + + // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally + // obtaining an UQ1.(HW-1) number and proving its highest bit could be + // considered to be 0 to be able to represent it in UQ0.HW. + // From the above analysis of f(x), if corr_UQ1_hw would be represented + // without any intermediate loss of precision (that is, in twice_rep_t) + // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly + // less otherwise. On the other hand, to obtain [1.]000..., one have to pass + // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due + // to 1.0 being not representable as UQ0.HW). + // The fact corr_UQ1_hw was virtually round up (due to result of + // multiplication being **first** truncated, then negated - to improve + // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. + x_uq0_hw = ((x_uq0_hw as u32).wrapping_mul(corr_uq1_hw as u32) >> (hw - 1)) as u16; + // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t + // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after + // any number of iterations, so just subtract 2 from the reciprocal + // approximation after last iteration. + + // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW: + // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1 + // = 1 - e_n * b_hw + 2*eps1 + // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2 + // = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2 + // = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw + // \------ >0 -------/ \-- >0 ---/ + // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U) + } + // For initial half-width iterations, U = 2^-HW + // Let abs(e_n) <= u_n * U, + // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U) + // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2) + + // Account for possible overflow (see above). For an overflow to occur for the + // first time, for "ideal" corr_UQ1_hw (that is, without intermediate + // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum + // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to + // be not below that value (see g(x) above), so it is safe to decrement just + // once after the final iteration. On the other hand, an effective value of + // divisor changes after this point (from b_hw to b), so adjust here. + x_uq0_hw.wrapping_sub(1_u16) + }; + + // Error estimations for full-precision iterations are calculated just + // as above, but with U := 2^-W and taking extra decrementing into account. + // We need at least one such iteration. + + // Simulating operations on a twice_rep_t to perform a single final full-width + // iteration. Using ad-hoc multiplication implementations to take advantage + // of particular structure of operands. + + let blo: u32 = (CastInto::::cast(b_uq1)) & lo_mask; + // x_UQ0 = x_UQ0_hw * 2^HW - 1 + // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1 + // + // <--- higher half ---><--- lower half ---> + // [x_UQ0_hw * b_UQ1_hw] + // + [ x_UQ0_hw * blo ] + // - [ b_UQ1 ] + // = [ result ][.... discarded ...] + let corr_uq1 = negate_u32( + (x_uq0_hw as u32) * (b_uq1_hw as u32) + (((x_uq0_hw as u32) * (blo)) >> hw) - 1, + ); // account for *possible* carry + let lo_corr = corr_uq1 & lo_mask; + let hi_corr = corr_uq1 >> hw; + // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1 + let mut x_uq0: ::Int = ((((x_uq0_hw as u32) * hi_corr) << 1) + .wrapping_add(((x_uq0_hw as u32) * lo_corr) >> (hw - 1)) + .wrapping_sub(2)) + .cast(); // 1 to account for the highest bit of corr_UQ1 can be 1 + // 1 to account for possible carry + // Just like the case of half-width iterations but with possibility + // of overflowing by one extra Ulp of x_UQ0. + x_uq0 -= one; + // ... and then traditional fixup by 2 should work + + // On error estimation: + // abs(E_{N-1}) <= (u_{N-1} + 2 /* due to conversion e_n -> E_n */) * 2^-HW + // + (2^-HW + 2^-W)) + // abs(E_{N-1}) <= (u_{N-1} + 3.01) * 2^-HW + + // Then like for the half-width iterations: + // With 0 <= eps1, eps2 < 2^-W + // E_N = 4 * E_{N-1} * eps1 - (E_{N-1}^2 * b + 4 * eps2) + 4 * eps1 / b + // abs(E_N) <= 2^-W * [ 4 * abs(E_{N-1}) + max(2 * abs(E_{N-1})^2 * 2^W + 4, 8)) ] + // abs(E_N) <= 2^-W * [ 4 * (u_{N-1} + 3.01) * 2^-HW + max(4 + 2 * (u_{N-1} + 3.01)^2, 8) ] + x_uq0 } else { - quotient >>= 1; - (a_significand << significand_bits).wrapping_sub(quotient.wrapping_mul(b_significand)) + // C is (3/4 + 1/sqrt(2)) - 1 truncated to 32 fractional bits as UQ0.n + let c: ::Int = (0x7504F333 << (F::BITS - 32)).cast(); + let x_uq0: ::Int = c.wrapping_sub(b_uq1); + // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-32 + x_uq0 + }; + + let mut x_uq0 = if USE_NATIVE_FULL_ITERATIONS { + for _ in 0..NUMBER_OF_FULL_ITERATIONS { + let corr_uq1: u32 = 0.wrapping_sub( + ((CastInto::::cast(x_uq0) as u64) * (CastInto::::cast(b_uq1) as u64)) + >> F::BITS, + ) as u32; + x_uq0 = ((((CastInto::::cast(x_uq0) as u64) * (corr_uq1 as u64)) >> (F::BITS - 1)) + as u32) + .cast(); + } + x_uq0 + } else { + // not using native full iterations + x_uq0 }; - let written_exponent = quotient_exponent.wrapping_add(exponent_bias as i32); + // Finally, account for possible overflow, as explained above. + x_uq0 = x_uq0.wrapping_sub(2.cast()); + + // u_n for different precisions (with N-1 half-width iterations): + // W0 is the precision of C + // u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW + + // Estimated with bc: + // define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; } + // define half2(un) { return 2.0 * un / 2.0^hw + 2.0; } + // define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; } + // define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; } + + // | f32 (0 + 3) | f32 (2 + 1) | f64 (3 + 1) | f128 (4 + 1) + // u_0 | < 184224974 | < 2812.1 | < 184224974 | < 791240234244348797 + // u_1 | < 15804007 | < 242.7 | < 15804007 | < 67877681371350440 + // u_2 | < 116308 | < 2.81 | < 116308 | < 499533100252317 + // u_3 | < 7.31 | | < 7.31 | < 27054456580 + // u_4 | | | | < 80.4 + // Final (U_N) | same as u_3 | < 72 | < 218 | < 13920 + + // Add 2 to U_N due to final decrement. + + let reciprocal_precision: ::Int = 10.cast(); + + // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W + let x_uq0 = x_uq0 - reciprocal_precision; + // Now 1/b - (2*P) * 2^-W < x < 1/b + // FIXME Is x_UQ0 still >= 0.5? + + let mut quotient: ::Int = x_uq0.widen_mul(a_significand << 1).hi(); + // Now, a/b - 4*P * 2^-W < q < a/b for q= in UQ1.(SB+1+W). + + // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1), + // adjust it to be in [1.0, 2.0) as UQ1.SB. + let (mut residual, written_exponent) = if quotient < (implicit_bit << 1) { + // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB, + // effectively doubling its value as well as its error estimation. + let residual_lo = (a_significand << (significand_bits + 1)).wrapping_sub( + (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) + .cast(), + ); + a_significand <<= 1; + (residual_lo, written_exponent.wrapping_sub(1)) + } else { + // Highest bit is 1 (the UQ1.(SB+1) value is in [1, 2)), convert it + // to UQ1.SB by right shifting by 1. Least significant bit is omitted. + quotient >>= 1; + let residual_lo = (a_significand << significand_bits).wrapping_sub( + (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) + .cast(), + ); + (residual_lo, written_exponent) + }; + //drop mutability + let quotient = quotient; + + // NB: residualLo is calculated above for the normal result case. + // It is re-computed on denormal path that is expected to be not so + // performance-sensitive. + + // Now, q cannot be greater than a/b and can differ by at most 8*P * 2^-W + 2^-SB + // Each NextAfter() increments the floating point value by at least 2^-SB + // (more, if exponent was incremented). + // Different cases (<---> is of 2^-SB length, * = a/b that is shown as a midpoint): + // q + // | | * | | | | | + // <---> 2^t + // | | | | | * | | + // q + // To require at most one NextAfter(), an error should be less than 1.5 * 2^-SB. + // (8*P) * 2^-W + 2^-SB < 1.5 * 2^-SB + // (8*P) * 2^-W < 0.5 * 2^-SB + // P < 2^(W-4-SB) + // Generally, for at most R NextAfter() to be enough, + // P < (2*R - 1) * 2^(W-4-SB) + // For f32 (0+3): 10 < 32 (OK) + // For f32 (2+1): 32 < 74 < 32 * 3, so two NextAfter() are required + // For f64: 220 < 256 (OK) + // For f128: 4096 * 3 < 13922 < 4096 * 5 (three NextAfter() are required) + + // If we have overflowed the exponent, return infinity if written_exponent >= max_exponent as i32 { - // If we have overflowed the exponent, return infinity. return F::from_repr(inf_rep | quotient_sign); - } else if written_exponent < 1 { - // Flush denormals to zero. In the future, it would be nice to add - // code to round them correctly. - return F::from_repr(quotient_sign); - } else { - let round = ((residual << 1) > b_significand) as u32; - // Clear the implicit bits - let mut abs_result = quotient & significand_mask; - // Insert the exponent - abs_result |= written_exponent.cast() << significand_bits; - // Round - abs_result = abs_result.wrapping_add(round.cast()); - // Insert the sign and return - return F::from_repr(abs_result | quotient_sign); } + + // Now, quotient <= the correctly-rounded result + // and may need taking NextAfter() up to 3 times (see error estimates above) + // r = a - b * q + let abs_result = if written_exponent > 0 { + let mut ret = quotient & significand_mask; + ret |= ((written_exponent as u32) << significand_bits).cast(); + residual <<= 1; + ret + } else { + if (significand_bits as i32 + written_exponent) < 0 { + return F::from_repr(quotient_sign); + } + let ret = quotient.wrapping_shr(negate_u32(CastInto::::cast(written_exponent)) + 1); + residual = (CastInto::::cast( + a_significand.wrapping_shl( + significand_bits.wrapping_add(CastInto::::cast(written_exponent)), + ), + ) + .wrapping_sub( + (CastInto::::cast(ret).wrapping_mul(CastInto::::cast(b_significand))) << 1, + )) + .cast(); + ret + }; + // Round + let abs_result = { + residual += abs_result & one; // tie to even + // The above line conditionally turns the below LT comparison into LTE + + if residual > b_significand { + abs_result + one + } else { + abs_result + } + }; + F::from_repr(abs_result | quotient_sign) } fn div64(a: F, b: F) -> F @@ -218,10 +464,15 @@ where F::Int: CastInto, F::Int: HInt, { + const NUMBER_OF_HALF_ITERATIONS: usize = 3; + const NUMBER_OF_FULL_ITERATIONS: usize = 1; + const USE_NATIVE_FULL_ITERATIONS: bool = false; + let one = F::Int::ONE; let zero = F::Int::ZERO; + let hw = F::BITS / 2; + let lo_mask = u64::MAX >> hw; - // let bits = F::BITS; let significand_bits = F::SIGNIFICAND_BITS; let max_exponent = F::EXPONENT_MAX; @@ -235,12 +486,6 @@ where let inf_rep = exponent_mask; let quiet_bit = implicit_bit >> 1; let qnan_rep = exponent_mask | quiet_bit; - // let exponent_bits = F::EXPONENT_BITS; - - #[inline(always)] - fn negate_u32(a: u32) -> u32 { - (::wrapping_neg(a as i32)) as u32 - } #[inline(always)] fn negate_u64(a: u64) -> u64 { @@ -320,128 +565,340 @@ where } } - // Or in the implicit significand bit. (If we fell through from the + // Set the implicit significand bit. If we fell through from the // denormal path it was already set by normalize( ), but setting it twice - // won't hurt anything.) + // won't hurt anything. a_significand |= implicit_bit; b_significand |= implicit_bit; - let mut quotient_exponent: i32 = CastInto::::cast(a_exponent) - .wrapping_sub(CastInto::::cast(b_exponent)) - .wrapping_add(scale); - - // Align the significand of b as a Q31 fixed-point number in the range - // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax - // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This - // is accurate to about 3.5 binary digits. - let q31b = CastInto::::cast(b_significand >> 21.cast()); - let mut recip32 = (0x7504f333u32).wrapping_sub(q31b); - - // Now refine the reciprocal estimate using a Newton-Raphson iteration: - // - // x1 = x0 * (2 - x0 * b) - // - // This doubles the number of correct binary digits in the approximation - // with each iteration, so after three iterations, we have about 28 binary - // digits of accuracy. - - let mut correction32: u32 = - negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); - recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; - correction32 = negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); - recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; - correction32 = negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); - recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; - - // recip32 might have overflowed to exactly zero in the preceeding - // computation if the high word of b is exactly 1.0. This would sabotage - // the full-width final stage of the computation that follows, so we adjust - // recip32 downward by one bit. - recip32 = recip32.wrapping_sub(1); - - // We need to perform one more iteration to get us to 56 binary digits; - // The last iteration needs to happen with extra precision. - let q63blo = CastInto::::cast(b_significand << 11.cast()); - - let correction: u64 = negate_u64( - (recip32 as u64) - .wrapping_mul(q31b as u64) - .wrapping_add((recip32 as u64).wrapping_mul(q63blo as u64) >> 32), - ); - let c_hi = (correction >> 32) as u32; - let c_lo = correction as u32; - let mut reciprocal: u64 = (recip32 as u64) - .wrapping_mul(c_hi as u64) - .wrapping_add((recip32 as u64).wrapping_mul(c_lo as u64) >> 32); - - // We already adjusted the 32-bit estimate, now we need to adjust the final - // 64-bit reciprocal estimate downward to ensure that it is strictly smaller - // than the infinitely precise exact reciprocal. Because the computation - // of the Newton-Raphson step is truncating at every step, this adjustment - // is small; most of the work is already done. - reciprocal = reciprocal.wrapping_sub(2); - - // The numerical reciprocal is accurate to within 2^-56, lies in the - // interval [0.5, 1.0), and is strictly smaller than the true reciprocal - // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b - // in Q53 with the following properties: - // - // 1. q < a/b - // 2. q is in the interval [0.5, 2.0) - // 3. the error in q is bounded away from 2^-53 (actually, we have a - // couple of bits to spare, but this is all we need). - - // We need a 64 x 64 multiply high to compute q, which isn't a basic - // operation in C, so we need to be a little bit fussy. - // let mut quotient: F::Int = ((((reciprocal as u64) - // .wrapping_mul(CastInto::::cast(a_significand << 1) as u64)) - // >> 32) as u32) - // .cast(); - - // We need a 64 x 64 multiply high to compute q, which isn't a basic - // operation in C, so we need to be a little bit fussy. - let mut quotient = (a_significand << 2).widen_mul(reciprocal.cast()).hi(); - - // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). - // In either case, we are going to compute a residual of the form - // - // r = a - q*b + + let written_exponent: i64 = CastInto::::cast( + a_exponent + .wrapping_sub(b_exponent) + .wrapping_add(scale.cast()), + ) + .wrapping_add(exponent_bias as u64) as i64; + let b_uq1 = b_significand << (F::BITS - significand_bits - 1); + + // Align the significand of b as a UQ1.(n-1) fixed-point number in the range + // [1.0, 2.0) and get a UQ0.n approximate reciprocal using a small minimax + // polynomial approximation: x0 = 3/4 + 1/sqrt(2) - b/2. + // The max error for this approximation is achieved at endpoints, so + // abs(x0(b) - 1/b) <= abs(x0(1) - 1/1) = 3/4 - 1/sqrt(2) = 0.04289..., + // which is about 4.5 bits. + // The initial approximation is between x0(1.0) = 0.9571... and x0(2.0) = 0.4571... + + // Then, refine the reciprocal estimate using a quadratically converging + // Newton-Raphson iteration: + // x_{n+1} = x_n * (2 - x_n * b) // - // We know from the construction of q that r satisfies: + // Let b be the original divisor considered "in infinite precision" and + // obtained from IEEE754 representation of function argument (with the + // implicit bit set). Corresponds to rep_t-sized b_UQ1 represented in + // UQ1.(W-1). // - // 0 <= r < ulp(q)*b + // Let b_hw be an infinitely precise number obtained from the highest (HW-1) + // bits of divisor significand (with the implicit bit set). Corresponds to + // half_rep_t-sized b_UQ1_hw represented in UQ1.(HW-1) that is a **truncated** + // version of b_UQ1. // - // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we - // already have the correct result. The exact halfway case cannot occur. - // We also take this time to right shift quotient if it falls in the [1,2) - // range and adjust the exponent accordingly. - let residual = if quotient < (implicit_bit << 1) { - quotient_exponent = quotient_exponent.wrapping_sub(1); - (a_significand << (significand_bits + 1)).wrapping_sub(quotient.wrapping_mul(b_significand)) + // Let e_n := x_n - 1/b_hw + // E_n := x_n - 1/b + // abs(E_n) <= abs(e_n) + (1/b_hw - 1/b) + // = abs(e_n) + (b - b_hw) / (b*b_hw) + // <= abs(e_n) + 2 * 2^-HW + + // rep_t-sized iterations may be slower than the corresponding half-width + // variant depending on the handware and whether single/double/quad precision + // is selected. + // NB: Using half-width iterations increases computation errors due to + // rounding, so error estimations have to be computed taking the selected + // mode into account! + + let mut x_uq0 = if NUMBER_OF_HALF_ITERATIONS > 0 { + // Starting with (n-1) half-width iterations + let b_uq1_hw: u32 = + (CastInto::::cast(b_significand) >> (significand_bits + 1 - hw)) as u32; + + // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW + // with W0 being either 16 or 32 and W0 <= HW. + // That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from which + // b/2 is subtracted to obtain x0) wrapped to [0, 1) range. + + // HW is at least 32. Shifting into the highest bits if needed. + let c_hw = (0x7504F333_u64 as u32).wrapping_shl(hw.wrapping_sub(32)); + + // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, + // so x0 fits to UQ0.HW without wrapping. + let x_uq0_hw: u32 = { + let mut x_uq0_hw: u32 = c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); + // dbg!(x_uq0_hw); + // An e_0 error is comprised of errors due to + // * x0 being an inherently imprecise first approximation of 1/b_hw + // * C_hw being some (irrational) number **truncated** to W0 bits + // Please note that e_0 is calculated against the infinitely precise + // reciprocal of b_hw (that is, **truncated** version of b). + // + // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0 + + // By construction, 1 <= b < 2 + // f(x) = x * (2 - b*x) = 2*x - b*x^2 + // f'(x) = 2 * (1 - b*x) + // + // On the [0, 1] interval, f(0) = 0, + // then it increses until f(1/b) = 1 / b, maximum on (0, 1), + // then it decreses to f(1) = 2 - b + // + // Let g(x) = x - f(x) = b*x^2 - x. + // On (0, 1/b), g(x) < 0 <=> f(x) > x + // On (1/b, 1], g(x) > 0 <=> f(x) < x + // + // For half-width iterations, b_hw is used instead of b. + for _ in 0..NUMBER_OF_HALF_ITERATIONS { + // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp + // of corr_UQ1_hw. + // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1). + // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided + // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is + // expected to be strictly positive because b_UQ1_hw has its highest bit set + // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). + let corr_uq1_hw: u32 = + 0.wrapping_sub(((x_uq0_hw as u64).wrapping_mul(b_uq1_hw as u64)) >> hw) as u32; + // dbg!(corr_uq1_hw); + + // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally + // obtaining an UQ1.(HW-1) number and proving its highest bit could be + // considered to be 0 to be able to represent it in UQ0.HW. + // From the above analysis of f(x), if corr_UQ1_hw would be represented + // without any intermediate loss of precision (that is, in twice_rep_t) + // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly + // less otherwise. On the other hand, to obtain [1.]000..., one have to pass + // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due + // to 1.0 being not representable as UQ0.HW). + // The fact corr_UQ1_hw was virtually round up (due to result of + // multiplication being **first** truncated, then negated - to improve + // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. + x_uq0_hw = ((x_uq0_hw as u64).wrapping_mul(corr_uq1_hw as u64) >> (hw - 1)) as u32; + // dbg!(x_uq0_hw); + // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t + // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after + // any number of iterations, so just subtract 2 from the reciprocal + // approximation after last iteration. + + // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW: + // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1 + // = 1 - e_n * b_hw + 2*eps1 + // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2 + // = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2 + // = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw + // \------ >0 -------/ \-- >0 ---/ + // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U) + } + // For initial half-width iterations, U = 2^-HW + // Let abs(e_n) <= u_n * U, + // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U) + // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2) + + // Account for possible overflow (see above). For an overflow to occur for the + // first time, for "ideal" corr_UQ1_hw (that is, without intermediate + // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum + // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to + // be not below that value (see g(x) above), so it is safe to decrement just + // once after the final iteration. On the other hand, an effective value of + // divisor changes after this point (from b_hw to b), so adjust here. + x_uq0_hw.wrapping_sub(1_u32) + }; + + // Error estimations for full-precision iterations are calculated just + // as above, but with U := 2^-W and taking extra decrementing into account. + // We need at least one such iteration. + + // Simulating operations on a twice_rep_t to perform a single final full-width + // iteration. Using ad-hoc multiplication implementations to take advantage + // of particular structure of operands. + let blo: u64 = (CastInto::::cast(b_uq1)) & lo_mask; + // x_UQ0 = x_UQ0_hw * 2^HW - 1 + // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1 + // + // <--- higher half ---><--- lower half ---> + // [x_UQ0_hw * b_UQ1_hw] + // + [ x_UQ0_hw * blo ] + // - [ b_UQ1 ] + // = [ result ][.... discarded ...] + let corr_uq1 = negate_u64( + (x_uq0_hw as u64) * (b_uq1_hw as u64) + (((x_uq0_hw as u64) * (blo)) >> hw) - 1, + ); // account for *possible* carry + let lo_corr = corr_uq1 & lo_mask; + let hi_corr = corr_uq1 >> hw; + // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1 + let mut x_uq0: ::Int = ((((x_uq0_hw as u64) * hi_corr) << 1) + .wrapping_add(((x_uq0_hw as u64) * lo_corr) >> (hw - 1)) + .wrapping_sub(2)) + .cast(); // 1 to account for the highest bit of corr_UQ1 can be 1 + // 1 to account for possible carry + // Just like the case of half-width iterations but with possibility + // of overflowing by one extra Ulp of x_UQ0. + x_uq0 -= one; + // ... and then traditional fixup by 2 should work + + // On error estimation: + // abs(E_{N-1}) <= (u_{N-1} + 2 /* due to conversion e_n -> E_n */) * 2^-HW + // + (2^-HW + 2^-W)) + // abs(E_{N-1}) <= (u_{N-1} + 3.01) * 2^-HW + + // Then like for the half-width iterations: + // With 0 <= eps1, eps2 < 2^-W + // E_N = 4 * E_{N-1} * eps1 - (E_{N-1}^2 * b + 4 * eps2) + 4 * eps1 / b + // abs(E_N) <= 2^-W * [ 4 * abs(E_{N-1}) + max(2 * abs(E_{N-1})^2 * 2^W + 4, 8)) ] + // abs(E_N) <= 2^-W * [ 4 * (u_{N-1} + 3.01) * 2^-HW + max(4 + 2 * (u_{N-1} + 3.01)^2, 8) ] + x_uq0 } else { - quotient >>= 1; - (a_significand << significand_bits).wrapping_sub(quotient.wrapping_mul(b_significand)) + // C is (3/4 + 1/sqrt(2)) - 1 truncated to 64 fractional bits as UQ0.n + let c: ::Int = (0x7504F333 << (F::BITS - 32)).cast(); + let x_uq0: ::Int = c.wrapping_sub(b_uq1); + // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-64 + x_uq0 + }; + + let mut x_uq0 = if USE_NATIVE_FULL_ITERATIONS { + for _ in 0..NUMBER_OF_FULL_ITERATIONS { + let corr_uq1: u64 = 0.wrapping_sub( + (CastInto::::cast(x_uq0) * (CastInto::::cast(b_uq1))) >> F::BITS, + ); + x_uq0 = ((((CastInto::::cast(x_uq0) as u128) * (corr_uq1 as u128)) + >> (F::BITS - 1)) as u64) + .cast(); + } + x_uq0 + } else { + // not using native full iterations + x_uq0 }; - let written_exponent = quotient_exponent.wrapping_add(exponent_bias as i32); + // Finally, account for possible overflow, as explained above. + x_uq0 = x_uq0.wrapping_sub(2.cast()); + + // u_n for different precisions (with N-1 half-width iterations): + // W0 is the precision of C + // u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW + + // Estimated with bc: + // define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; } + // define half2(un) { return 2.0 * un / 2.0^hw + 2.0; } + // define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; } + // define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; } + + // | f32 (0 + 3) | f32 (2 + 1) | f64 (3 + 1) | f128 (4 + 1) + // u_0 | < 184224974 | < 2812.1 | < 184224974 | < 791240234244348797 + // u_1 | < 15804007 | < 242.7 | < 15804007 | < 67877681371350440 + // u_2 | < 116308 | < 2.81 | < 116308 | < 499533100252317 + // u_3 | < 7.31 | | < 7.31 | < 27054456580 + // u_4 | | | | < 80.4 + // Final (U_N) | same as u_3 | < 72 | < 218 | < 13920 + + // Add 2 to U_N due to final decrement. + + let reciprocal_precision: ::Int = 220.cast(); + + // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W + let x_uq0 = x_uq0 - reciprocal_precision; + // Now 1/b - (2*P) * 2^-W < x < 1/b + // FIXME Is x_UQ0 still >= 0.5? + + let mut quotient: ::Int = x_uq0.widen_mul(a_significand << 1).hi(); + // Now, a/b - 4*P * 2^-W < q < a/b for q= in UQ1.(SB+1+W). + + // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1), + // adjust it to be in [1.0, 2.0) as UQ1.SB. + let (mut residual, written_exponent) = if quotient < (implicit_bit << 1) { + // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB, + // effectively doubling its value as well as its error estimation. + let residual_lo = (a_significand << (significand_bits + 1)).wrapping_sub( + (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) + .cast(), + ); + a_significand <<= 1; + (residual_lo, written_exponent.wrapping_sub(1)) + } else { + // Highest bit is 1 (the UQ1.(SB+1) value is in [1, 2)), convert it + // to UQ1.SB by right shifting by 1. Least significant bit is omitted. + quotient >>= 1; + let residual_lo = (a_significand << significand_bits).wrapping_sub( + (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) + .cast(), + ); + (residual_lo, written_exponent) + }; - if written_exponent >= max_exponent as i32 { - // If we have overflowed the exponent, return infinity. + //drop mutability + let quotient = quotient; + + // NB: residualLo is calculated above for the normal result case. + // It is re-computed on denormal path that is expected to be not so + // performance-sensitive. + + // Now, q cannot be greater than a/b and can differ by at most 8*P * 2^-W + 2^-SB + // Each NextAfter() increments the floating point value by at least 2^-SB + // (more, if exponent was incremented). + // Different cases (<---> is of 2^-SB length, * = a/b that is shown as a midpoint): + // q + // | | * | | | | | + // <---> 2^t + // | | | | | * | | + // q + // To require at most one NextAfter(), an error should be less than 1.5 * 2^-SB. + // (8*P) * 2^-W + 2^-SB < 1.5 * 2^-SB + // (8*P) * 2^-W < 0.5 * 2^-SB + // P < 2^(W-4-SB) + // Generally, for at most R NextAfter() to be enough, + // P < (2*R - 1) * 2^(W-4-SB) + // For f32 (0+3): 10 < 32 (OK) + // For f32 (2+1): 32 < 74 < 32 * 3, so two NextAfter() are required + // For f64: 220 < 256 (OK) + // For f128: 4096 * 3 < 13922 < 4096 * 5 (three NextAfter() are required) + + // If we have overflowed the exponent, return infinity + if written_exponent >= max_exponent as i64 { return F::from_repr(inf_rep | quotient_sign); - } else if written_exponent < 1 { - // Flush denormals to zero. In the future, it would be nice to add - // code to round them correctly. - return F::from_repr(quotient_sign); - } else { - let round = ((residual << 1) > b_significand) as u32; - // Clear the implicit bits - let mut abs_result = quotient & significand_mask; - // Insert the exponent - abs_result |= written_exponent.cast() << significand_bits; - // Round - abs_result = abs_result.wrapping_add(round.cast()); - // Insert the sign and return - return F::from_repr(abs_result | quotient_sign); } + + // Now, quotient <= the correctly-rounded result + // and may need taking NextAfter() up to 3 times (see error estimates above) + // r = a - b * q + let abs_result = if written_exponent > 0 { + let mut ret = quotient & significand_mask; + ret |= ((written_exponent as u64) << significand_bits).cast(); + residual <<= 1; + ret + } else { + if (significand_bits as i64 + written_exponent) < 0 { + return F::from_repr(quotient_sign); + } + let ret = + quotient.wrapping_shr((negate_u64(CastInto::::cast(written_exponent)) + 1) as u32); + residual = (CastInto::::cast( + a_significand.wrapping_shl( + significand_bits.wrapping_add(CastInto::::cast(written_exponent)), + ), + ) + .wrapping_sub( + (CastInto::::cast(ret).wrapping_mul(CastInto::::cast(b_significand))) << 1, + )) + .cast(); + ret + }; + // Round + let abs_result = { + residual += abs_result & one; // tie to even + // conditionally turns the below LT comparison into LTE + if residual > b_significand { + abs_result + one + } else { + abs_result + } + }; + F::from_repr(abs_result | quotient_sign) } intrinsics! { diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index c3f0676400e..de3bd9bee8f 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -109,7 +109,16 @@ macro_rules! float { fuzz_float_2(N, |x: $i, y: $i| { let quo0 = x / y; let quo1: $i = $fn(x, y); - // division of subnormals is not currently handled + #[cfg(not(target_arch = "arm"))] + if !Float::eq_repr(quo0, quo1) { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, quo0, quo1 + ); + } + + // ARM SIMD instructions always flush subnormals to zero + #[cfg(target_arch = "arm")] if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) { if !Float::eq_repr(quo0, quo1) { panic!( -- cgit 1.4.1-3-g733a5 From 1a41e48d11a1d764d905047d38e80c591500d624 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 27 Jun 2023 02:31:42 +0000 Subject: fix tests to work with `--feature c` --- library/compiler-builtins/src/aarch64.rs | 1 + library/compiler-builtins/src/lib.rs | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64.rs index ddbec6d327b..62144e53199 100644 --- a/library/compiler-builtins/src/aarch64.rs +++ b/library/compiler-builtins/src/aarch64.rs @@ -22,6 +22,7 @@ //! //! The original `lse.S` has some truly horrifying code that expects to be compiled multiple times with different constants. //! We do something similar, but with macro arguments. +#![cfg_attr(feature = "c", allow(unused_macros))] // avoid putting the macros into a submodule // We don't do runtime dispatch so we don't have to worry about the `__aarch64_have_lse_atomics` global ctor. diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 4b44adc266d..2e5c587fb95 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -57,11 +57,7 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; -#[cfg(all( - target_arch = "aarch64", - not(feature = "no-asm"), - not(feature = "optimized-c") -))] +#[cfg(all(target_arch = "aarch64", not(feature = "no-asm"),))] pub mod aarch64; #[cfg(all( -- cgit 1.4.1-3-g733a5 From c6fa74aacb1d516124c2914c429378ce32c6a414 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 28 Jun 2023 21:35:33 +0200 Subject: enable simple f32/f64 support needed by core library --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/math.rs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 71f249c8eb3..729b1ec54bf 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -48,6 +48,7 @@ pub mod int; all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), all(target_arch = "xtensa", target_os = "none"), + all(target_arch = "mips", target_os = "none"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx") ))] diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 498e4d85ff0..b4e5fc1138b 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -136,11 +136,12 @@ no_mangle! { fn truncf(x: f32) -> f32; } -// only for the thumb*-none-eabi*, riscv32*-none-elf and x86_64-unknown-none targets that lack the floating point instruction set +// only for the thumb*-none-eabi*, riscv32*-none-elf, x86_64-unknown-none and mips*-unknown-none targets that lack the floating point instruction set #[cfg(any( all(target_arch = "arm", target_os = "none"), all(target_arch = "riscv32", not(target_feature = "f"), target_os = "none"), - all(target_arch = "x86_64", target_os = "none") + all(target_arch = "x86_64", target_os = "none"), + all(target_arch = "mips", target_os = "none"), ))] no_mangle! { fn fmin(x: f64, y: f64) -> f64; -- cgit 1.4.1-3-g733a5 From 9234bedeea54889aa7f5d9dc477b9c00af0c527c Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 28 Jun 2023 23:44:06 +0100 Subject: Bump to 0.1.94 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6cfa2b99e38..c468bdf7586 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.93" +version = "0.1.94" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 1dbb9d2d476..4c8a973741c 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 1dbb9d2d476d65d020feca17b11391652038e2e1 +Subproject commit 4c8a973741c014b11ce7f1477693a3e5d4ef9609 -- cgit 1.4.1-3-g733a5 From c4e9f479add8a54dce33069e43814426843099d9 Mon Sep 17 00:00:00 2001 From: jyn Date: Sun, 2 Jul 2023 14:43:25 -0500 Subject: Only compile outlined-atomics intrinsics on linux --- library/compiler-builtins/src/aarch64.rs | 277 ----------------------- library/compiler-builtins/src/aarch64_linux.rs | 277 +++++++++++++++++++++++ library/compiler-builtins/src/lib.rs | 4 +- library/compiler-builtins/testcrate/tests/lse.rs | 12 +- 4 files changed, 287 insertions(+), 283 deletions(-) delete mode 100644 library/compiler-builtins/src/aarch64.rs create mode 100644 library/compiler-builtins/src/aarch64_linux.rs diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64.rs deleted file mode 100644 index 62144e53199..00000000000 --- a/library/compiler-builtins/src/aarch64.rs +++ /dev/null @@ -1,277 +0,0 @@ -//! Aarch64 targets have two possible implementations for atomics: -//! 1. Load-Locked, Store-Conditional (LL/SC), older and slower. -//! 2. Large System Extensions (LSE), newer and faster. -//! To avoid breaking backwards compat, C toolchains introduced a concept of "outlined atomics", -//! where atomic operations call into the compiler runtime to dispatch between two depending on -//! which is supported on the current CPU. -//! See https://community.arm.com/arm-community-blogs/b/tools-software-ides-blog/posts/making-the-most-of-the-arm-architecture-in-gcc-10#:~:text=out%20of%20line%20atomics for more discussion. -//! -//! Currently we only support LL/SC, because LSE requires `getauxval` from libc in order to do runtime detection. -//! Use the `compiler-rt` intrinsics if you want LSE support. -//! -//! Ported from `aarch64/lse.S` in LLVM's compiler-rt. -//! -//! Generate functions for each of the following symbols: -//! __aarch64_casM_ORDER -//! __aarch64_swpN_ORDER -//! __aarch64_ldaddN_ORDER -//! __aarch64_ldclrN_ORDER -//! __aarch64_ldeorN_ORDER -//! __aarch64_ldsetN_ORDER -//! for N = {1, 2, 4, 8}, M = {1, 2, 4, 8, 16}, ORDER = { relax, acq, rel, acq_rel } -//! -//! The original `lse.S` has some truly horrifying code that expects to be compiled multiple times with different constants. -//! We do something similar, but with macro arguments. -#![cfg_attr(feature = "c", allow(unused_macros))] // avoid putting the macros into a submodule - -// We don't do runtime dispatch so we don't have to worry about the `__aarch64_have_lse_atomics` global ctor. - -/// Translate a byte size to a Rust type. -#[rustfmt::skip] -macro_rules! int_ty { - (1) => { i8 }; - (2) => { i16 }; - (4) => { i32 }; - (8) => { i64 }; - (16) => { i128 }; -} - -/// Given a byte size and a register number, return a register of the appropriate size. -/// -/// See . -#[rustfmt::skip] -macro_rules! reg { - (1, $num:literal) => { concat!("w", $num) }; - (2, $num:literal) => { concat!("w", $num) }; - (4, $num:literal) => { concat!("w", $num) }; - (8, $num:literal) => { concat!("x", $num) }; -} - -/// Given an atomic ordering, translate it to the acquire suffix for the lxdr aarch64 ASM instruction. -#[rustfmt::skip] -macro_rules! acquire { - (Relaxed) => { "" }; - (Acquire) => { "a" }; - (Release) => { "" }; - (AcqRel) => { "a" }; -} - -/// Given an atomic ordering, translate it to the release suffix for the stxr aarch64 ASM instruction. -#[rustfmt::skip] -macro_rules! release { - (Relaxed) => { "" }; - (Acquire) => { "" }; - (Release) => { "l" }; - (AcqRel) => { "l" }; -} - -/// Given a size in bytes, translate it to the byte suffix for an aarch64 ASM instruction. -#[rustfmt::skip] -macro_rules! size { - (1) => { "b" }; - (2) => { "h" }; - (4) => { "" }; - (8) => { "" }; - (16) => { "" }; -} - -/// Given a byte size, translate it to an Unsigned eXTend instruction -/// with the correct semantics. -/// -/// See -#[rustfmt::skip] -macro_rules! uxt { - (1) => { "uxtb" }; - (2) => { "uxth" }; - ($_:tt) => { "mov" }; -} - -/// Given an atomic ordering and byte size, translate it to a LoaD eXclusive Register instruction -/// with the correct semantics. -/// -/// See . -macro_rules! ldxr { - ($ordering:ident, $bytes:tt) => { - concat!("ld", acquire!($ordering), "xr", size!($bytes)) - }; -} - -/// Given an atomic ordering and byte size, translate it to a STore eXclusive Register instruction -/// with the correct semantics. -/// -/// See . -macro_rules! stxr { - ($ordering:ident, $bytes:tt) => { - concat!("st", release!($ordering), "xr", size!($bytes)) - }; -} - -/// Given an atomic ordering and byte size, translate it to a LoaD eXclusive Pair of registers instruction -/// with the correct semantics. -/// -/// See -macro_rules! ldxp { - ($ordering:ident) => { - concat!("ld", acquire!($ordering), "xp") - }; -} - -/// Given an atomic ordering and byte size, translate it to a STore eXclusive Pair of registers instruction -/// with the correct semantics. -/// -/// See . -macro_rules! stxp { - ($ordering:ident) => { - concat!("st", release!($ordering), "xp") - }; -} - -/// See . -macro_rules! compare_and_swap { - ($ordering:ident, $bytes:tt, $name:ident) => { - intrinsics! { - #[maybe_use_optimized_c_shim] - #[naked] - pub unsafe extern "C" fn $name ( - expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes) - ) -> int_ty!($bytes) { - // We can't use `AtomicI8::compare_and_swap`; we *are* compare_and_swap. - unsafe { core::arch::asm! { - // UXT s(tmp0), s(0) - concat!(uxt!($bytes), " ", reg!($bytes, 16), ", ", reg!($bytes, 0)), - "0:", - // LDXR s(0), [x2] - concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x2]"), - // cmp s(0), s(tmp0) - concat!("cmp ", reg!($bytes, 0), ", ", reg!($bytes, 16)), - "bne 1f", - // STXR w(tmp1), s(1), [x2] - concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 1), ", [x2]"), - "cbnz w17, 0b", - "1:", - "ret", - options(noreturn) - } } - } - } - }; -} - -// i128 uses a completely different impl, so it has its own macro. -macro_rules! compare_and_swap_i128 { - ($ordering:ident, $name:ident) => { - intrinsics! { - #[maybe_use_optimized_c_shim] - #[naked] - pub unsafe extern "C" fn $name ( - expected: i128, desired: i128, ptr: *mut i128 - ) -> i128 { - unsafe { core::arch::asm! { - "mov x16, x0", - "mov x17, x1", - "0:", - // LDXP x0, x1, [x4] - concat!(ldxp!($ordering), " x0, x1, [x4]"), - "cmp x0, x16", - "ccmp x1, x17, #0, eq", - "bne 1f", - // STXP w(tmp2), x2, x3, [x4] - concat!(stxp!($ordering), " w15, x2, x3, [x4]"), - "cbnz w15, 0b", - "1:", - "ret", - options(noreturn) - } } - } - } - }; -} - -/// See . -macro_rules! swap { - ($ordering:ident, $bytes:tt, $name:ident) => { - intrinsics! { - #[maybe_use_optimized_c_shim] - #[naked] - pub unsafe extern "C" fn $name ( - left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes) - ) -> int_ty!($bytes) { - unsafe { core::arch::asm! { - // mov s(tmp0), s(0) - concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), - "0:", - // LDXR s(0), [x1] - concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x1]"), - // STXR w(tmp1), s(tmp0), [x1] - concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 16), ", [x1]"), - "cbnz w17, 0b", - "ret", - options(noreturn) - } } - } - } - }; -} - -/// See (e.g.) . -macro_rules! fetch_op { - ($ordering:ident, $bytes:tt, $name:ident, $op:literal) => { - intrinsics! { - #[maybe_use_optimized_c_shim] - #[naked] - pub unsafe extern "C" fn $name ( - val: int_ty!($bytes), ptr: *mut int_ty!($bytes) - ) -> int_ty!($bytes) { - unsafe { core::arch::asm! { - // mov s(tmp0), s(0) - concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), - "0:", - // LDXR s(0), [x1] - concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x1]"), - // OP s(tmp1), s(0), s(tmp0) - concat!($op, " ", reg!($bytes, 17), ", ", reg!($bytes, 0), ", ", reg!($bytes, 16)), - // STXR w(tmp2), s(tmp1), [x1] - concat!(stxr!($ordering, $bytes), " w15, ", reg!($bytes, 17), ", [x1]"), - "cbnz w15, 0b", - "ret", - options(noreturn) - } } - } - } - } -} - -// We need a single macro to pass to `foreach_ldadd`. -macro_rules! add { - ($ordering:ident, $bytes:tt, $name:ident) => { - fetch_op! { $ordering, $bytes, $name, "add" } - }; -} - -macro_rules! and { - ($ordering:ident, $bytes:tt, $name:ident) => { - fetch_op! { $ordering, $bytes, $name, "bic" } - }; -} - -macro_rules! xor { - ($ordering:ident, $bytes:tt, $name:ident) => { - fetch_op! { $ordering, $bytes, $name, "eor" } - }; -} - -macro_rules! or { - ($ordering:ident, $bytes:tt, $name:ident) => { - fetch_op! { $ordering, $bytes, $name, "orr" } - }; -} - -// See `generate_aarch64_outlined_atomics` in build.rs. -include!(concat!(env!("OUT_DIR"), "/outlined_atomics.rs")); -foreach_cas!(compare_and_swap); -foreach_cas16!(compare_and_swap_i128); -foreach_swp!(swap); -foreach_ldadd!(add); -foreach_ldclr!(and); -foreach_ldeor!(xor); -foreach_ldset!(or); diff --git a/library/compiler-builtins/src/aarch64_linux.rs b/library/compiler-builtins/src/aarch64_linux.rs new file mode 100644 index 00000000000..62144e53199 --- /dev/null +++ b/library/compiler-builtins/src/aarch64_linux.rs @@ -0,0 +1,277 @@ +//! Aarch64 targets have two possible implementations for atomics: +//! 1. Load-Locked, Store-Conditional (LL/SC), older and slower. +//! 2. Large System Extensions (LSE), newer and faster. +//! To avoid breaking backwards compat, C toolchains introduced a concept of "outlined atomics", +//! where atomic operations call into the compiler runtime to dispatch between two depending on +//! which is supported on the current CPU. +//! See https://community.arm.com/arm-community-blogs/b/tools-software-ides-blog/posts/making-the-most-of-the-arm-architecture-in-gcc-10#:~:text=out%20of%20line%20atomics for more discussion. +//! +//! Currently we only support LL/SC, because LSE requires `getauxval` from libc in order to do runtime detection. +//! Use the `compiler-rt` intrinsics if you want LSE support. +//! +//! Ported from `aarch64/lse.S` in LLVM's compiler-rt. +//! +//! Generate functions for each of the following symbols: +//! __aarch64_casM_ORDER +//! __aarch64_swpN_ORDER +//! __aarch64_ldaddN_ORDER +//! __aarch64_ldclrN_ORDER +//! __aarch64_ldeorN_ORDER +//! __aarch64_ldsetN_ORDER +//! for N = {1, 2, 4, 8}, M = {1, 2, 4, 8, 16}, ORDER = { relax, acq, rel, acq_rel } +//! +//! The original `lse.S` has some truly horrifying code that expects to be compiled multiple times with different constants. +//! We do something similar, but with macro arguments. +#![cfg_attr(feature = "c", allow(unused_macros))] // avoid putting the macros into a submodule + +// We don't do runtime dispatch so we don't have to worry about the `__aarch64_have_lse_atomics` global ctor. + +/// Translate a byte size to a Rust type. +#[rustfmt::skip] +macro_rules! int_ty { + (1) => { i8 }; + (2) => { i16 }; + (4) => { i32 }; + (8) => { i64 }; + (16) => { i128 }; +} + +/// Given a byte size and a register number, return a register of the appropriate size. +/// +/// See . +#[rustfmt::skip] +macro_rules! reg { + (1, $num:literal) => { concat!("w", $num) }; + (2, $num:literal) => { concat!("w", $num) }; + (4, $num:literal) => { concat!("w", $num) }; + (8, $num:literal) => { concat!("x", $num) }; +} + +/// Given an atomic ordering, translate it to the acquire suffix for the lxdr aarch64 ASM instruction. +#[rustfmt::skip] +macro_rules! acquire { + (Relaxed) => { "" }; + (Acquire) => { "a" }; + (Release) => { "" }; + (AcqRel) => { "a" }; +} + +/// Given an atomic ordering, translate it to the release suffix for the stxr aarch64 ASM instruction. +#[rustfmt::skip] +macro_rules! release { + (Relaxed) => { "" }; + (Acquire) => { "" }; + (Release) => { "l" }; + (AcqRel) => { "l" }; +} + +/// Given a size in bytes, translate it to the byte suffix for an aarch64 ASM instruction. +#[rustfmt::skip] +macro_rules! size { + (1) => { "b" }; + (2) => { "h" }; + (4) => { "" }; + (8) => { "" }; + (16) => { "" }; +} + +/// Given a byte size, translate it to an Unsigned eXTend instruction +/// with the correct semantics. +/// +/// See +#[rustfmt::skip] +macro_rules! uxt { + (1) => { "uxtb" }; + (2) => { "uxth" }; + ($_:tt) => { "mov" }; +} + +/// Given an atomic ordering and byte size, translate it to a LoaD eXclusive Register instruction +/// with the correct semantics. +/// +/// See . +macro_rules! ldxr { + ($ordering:ident, $bytes:tt) => { + concat!("ld", acquire!($ordering), "xr", size!($bytes)) + }; +} + +/// Given an atomic ordering and byte size, translate it to a STore eXclusive Register instruction +/// with the correct semantics. +/// +/// See . +macro_rules! stxr { + ($ordering:ident, $bytes:tt) => { + concat!("st", release!($ordering), "xr", size!($bytes)) + }; +} + +/// Given an atomic ordering and byte size, translate it to a LoaD eXclusive Pair of registers instruction +/// with the correct semantics. +/// +/// See +macro_rules! ldxp { + ($ordering:ident) => { + concat!("ld", acquire!($ordering), "xp") + }; +} + +/// Given an atomic ordering and byte size, translate it to a STore eXclusive Pair of registers instruction +/// with the correct semantics. +/// +/// See . +macro_rules! stxp { + ($ordering:ident) => { + concat!("st", release!($ordering), "xp") + }; +} + +/// See . +macro_rules! compare_and_swap { + ($ordering:ident, $bytes:tt, $name:ident) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub unsafe extern "C" fn $name ( + expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes) + ) -> int_ty!($bytes) { + // We can't use `AtomicI8::compare_and_swap`; we *are* compare_and_swap. + unsafe { core::arch::asm! { + // UXT s(tmp0), s(0) + concat!(uxt!($bytes), " ", reg!($bytes, 16), ", ", reg!($bytes, 0)), + "0:", + // LDXR s(0), [x2] + concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x2]"), + // cmp s(0), s(tmp0) + concat!("cmp ", reg!($bytes, 0), ", ", reg!($bytes, 16)), + "bne 1f", + // STXR w(tmp1), s(1), [x2] + concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 1), ", [x2]"), + "cbnz w17, 0b", + "1:", + "ret", + options(noreturn) + } } + } + } + }; +} + +// i128 uses a completely different impl, so it has its own macro. +macro_rules! compare_and_swap_i128 { + ($ordering:ident, $name:ident) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub unsafe extern "C" fn $name ( + expected: i128, desired: i128, ptr: *mut i128 + ) -> i128 { + unsafe { core::arch::asm! { + "mov x16, x0", + "mov x17, x1", + "0:", + // LDXP x0, x1, [x4] + concat!(ldxp!($ordering), " x0, x1, [x4]"), + "cmp x0, x16", + "ccmp x1, x17, #0, eq", + "bne 1f", + // STXP w(tmp2), x2, x3, [x4] + concat!(stxp!($ordering), " w15, x2, x3, [x4]"), + "cbnz w15, 0b", + "1:", + "ret", + options(noreturn) + } } + } + } + }; +} + +/// See . +macro_rules! swap { + ($ordering:ident, $bytes:tt, $name:ident) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub unsafe extern "C" fn $name ( + left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes) + ) -> int_ty!($bytes) { + unsafe { core::arch::asm! { + // mov s(tmp0), s(0) + concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), + "0:", + // LDXR s(0), [x1] + concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x1]"), + // STXR w(tmp1), s(tmp0), [x1] + concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 16), ", [x1]"), + "cbnz w17, 0b", + "ret", + options(noreturn) + } } + } + } + }; +} + +/// See (e.g.) . +macro_rules! fetch_op { + ($ordering:ident, $bytes:tt, $name:ident, $op:literal) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub unsafe extern "C" fn $name ( + val: int_ty!($bytes), ptr: *mut int_ty!($bytes) + ) -> int_ty!($bytes) { + unsafe { core::arch::asm! { + // mov s(tmp0), s(0) + concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), + "0:", + // LDXR s(0), [x1] + concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x1]"), + // OP s(tmp1), s(0), s(tmp0) + concat!($op, " ", reg!($bytes, 17), ", ", reg!($bytes, 0), ", ", reg!($bytes, 16)), + // STXR w(tmp2), s(tmp1), [x1] + concat!(stxr!($ordering, $bytes), " w15, ", reg!($bytes, 17), ", [x1]"), + "cbnz w15, 0b", + "ret", + options(noreturn) + } } + } + } + } +} + +// We need a single macro to pass to `foreach_ldadd`. +macro_rules! add { + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "add" } + }; +} + +macro_rules! and { + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "bic" } + }; +} + +macro_rules! xor { + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "eor" } + }; +} + +macro_rules! or { + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "orr" } + }; +} + +// See `generate_aarch64_outlined_atomics` in build.rs. +include!(concat!(env!("OUT_DIR"), "/outlined_atomics.rs")); +foreach_cas!(compare_and_swap); +foreach_cas16!(compare_and_swap_i128); +foreach_swp!(swap); +foreach_ldadd!(add); +foreach_ldclr!(and); +foreach_ldeor!(xor); +foreach_ldset!(or); diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 58603a57c00..a6b61bdf5fc 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -58,8 +58,8 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; -#[cfg(all(target_arch = "aarch64", not(feature = "no-asm"),))] -pub mod aarch64; +#[cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm"),))] +pub mod aarch64_linux; #[cfg(all( kernel_user_helpers, diff --git a/library/compiler-builtins/testcrate/tests/lse.rs b/library/compiler-builtins/testcrate/tests/lse.rs index 7b54ab5d286..5589f22f1e9 100644 --- a/library/compiler-builtins/testcrate/tests/lse.rs +++ b/library/compiler-builtins/testcrate/tests/lse.rs @@ -17,7 +17,9 @@ mod cas { testcrate::fuzz_2(10000, |expected: super::int_ty!($bytes), new| { let mut target = expected.wrapping_add(10); assert_eq!( - unsafe { compiler_builtins::aarch64::$name::$name(expected, new, &mut target) }, + unsafe { + compiler_builtins::aarch64_linux::$name::$name(expected, new, &mut target) + }, expected.wrapping_add(10), "return value should always be the previous value", ); @@ -29,7 +31,9 @@ mod cas { target = expected; assert_eq!( - unsafe { compiler_builtins::aarch64::$name::$name(expected, new, &mut target) }, + unsafe { + compiler_builtins::aarch64_linux::$name::$name(expected, new, &mut target) + }, expected ); assert_eq!(target, new, "should have updated target"); @@ -49,7 +53,7 @@ mod swap { testcrate::fuzz_2(10000, |left: super::int_ty!($bytes), mut right| { let orig_right = right; assert_eq!( - unsafe { compiler_builtins::aarch64::$name::$name(left, &mut right) }, + unsafe { compiler_builtins::aarch64_linux::$name::$name(left, &mut right) }, orig_right ); assert_eq!(left, right); @@ -69,7 +73,7 @@ macro_rules! test_op { let mut target = old; let op: fn(super::int_ty!($bytes), super::int_ty!($bytes)) -> _ = $($op)*; let expected = op(old, val); - assert_eq!(old, unsafe { compiler_builtins::aarch64::$name::$name(val, &mut target) }, "{} should return original value", stringify!($name)); + assert_eq!(old, unsafe { compiler_builtins::aarch64_linux::$name::$name(val, &mut target) }, "{} should return original value", stringify!($name)); assert_eq!(expected, target, "{} should store to target", stringify!($name)); }); } -- cgit 1.4.1-3-g733a5 From 8a3c3942a544313af237a739e3648581702dfa4c Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 3 Jul 2023 10:45:20 +0200 Subject: Bump to 0.1.95 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c468bdf7586..52c1ee39a82 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.94" +version = "0.1.95" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 4c8a973741c..1dbb9d2d476 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 4c8a973741c014b11ce7f1477693a3e5d4ef9609 +Subproject commit 1dbb9d2d476d65d020feca17b11391652038e2e1 -- cgit 1.4.1-3-g733a5 From 28f24376147d3fae9959d4d3143dccf21998cb06 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 6 Jul 2023 20:20:19 +0200 Subject: Disable MIPS in CI See https://github.com/rust-lang/compiler-team/issues/648 --- .../compiler-builtins/.github/workflows/main.yml | 26 ++++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 3d63bc070cd..b69c48c16a9 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -23,18 +23,20 @@ jobs: - target: i686-unknown-linux-gnu os: ubuntu-latest rust: nightly - - target: mips-unknown-linux-gnu - os: ubuntu-latest - rust: nightly - - target: mips64-unknown-linux-gnuabi64 - os: ubuntu-latest - rust: nightly - - target: mips64el-unknown-linux-gnuabi64 - os: ubuntu-latest - rust: nightly - - target: mipsel-unknown-linux-gnu - os: ubuntu-latest - rust: nightly + # MIPS targets disabled since they are dropped to tier 3. + # See https://github.com/rust-lang/compiler-team/issues/648 + #- target: mips-unknown-linux-gnu + # os: ubuntu-latest + # rust: nightly + #- target: mips64-unknown-linux-gnuabi64 + # os: ubuntu-latest + # rust: nightly + #- target: mips64el-unknown-linux-gnuabi64 + # os: ubuntu-latest + # rust: nightly + #- target: mipsel-unknown-linux-gnu + # os: ubuntu-latest + # rust: nightly - target: powerpc-unknown-linux-gnu os: ubuntu-latest rust: nightly -- cgit 1.4.1-3-g733a5 From 025076f763405d3d2a9e05716b9b055ee8b52155 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Thu, 6 Jul 2023 01:51:47 -0500 Subject: Use the target_feature "zbb" instead of "b" for RISC-V --- library/compiler-builtins/src/int/specialized_div_rem/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 77034eb5476..1ff1d19dc8c 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -95,8 +95,9 @@ const USE_LZ: bool = { // LZD or LZCNT on SPARC only exists for the VIS 3 extension and later. cfg!(target_feature = "vis3") } else if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { - // The `B` extension on RISC-V determines if a CLZ assembly instruction exists - cfg!(target_feature = "b") + // The 'Zbb' Basic Bit-Manipulation extension on RISC-V + // determines if a CLZ assembly instruction exists + cfg!(target_feature = "zbb") } else { // All other common targets Rust supports should have CLZ instructions true -- cgit 1.4.1-3-g733a5 From e2f0b9cd3ade182c6b92782e781b31328b972cfb Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Fri, 7 Jul 2023 10:49:54 -0400 Subject: Add lgamma_r and lgammaf_r to MSVC --- library/compiler-builtins/src/math.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index b4e5fc1138b..4e255ca1a34 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -95,7 +95,8 @@ no_mangle! { target_os = "xous", all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "xtensa", target_os = "none"), - all(target_vendor = "fortanix", target_env = "sgx") + all(target_vendor = "fortanix", target_env = "sgx"), + target_env = "msvc" ))] intrinsics! { pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { -- cgit 1.4.1-3-g733a5 From 716d2064f0b144b6c704a5d689457a3af0ff1733 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 8 Jul 2023 14:18:27 +0900 Subject: Fix build error on aarch64_be linux --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 4549d0b4f16..26db6b4be9a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -91,7 +91,7 @@ fn main() { println!("cargo:rustc-cfg=kernel_user_helpers") } - if llvm_target[0] == "aarch64" { + if llvm_target[0].starts_with("aarch64") { generate_aarch64_outlined_atomics(); } } -- cgit 1.4.1-3-g733a5 From 5cc74482b40b4c88368114e4edfcb36f1335a857 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 17 Jul 2023 13:51:40 +0100 Subject: Bump to 0.1.96 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 52c1ee39a82..6c6c8d1365e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.95" +version = "0.1.96" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 1dbb9d2d476..4c8a973741c 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 1dbb9d2d476d65d020feca17b11391652038e2e1 +Subproject commit 4c8a973741c014b11ce7f1477693a3e5d4ef9609 -- cgit 1.4.1-3-g733a5 From 7eca0c2ba3f5e4d606aac99e7717ad98b3db2f91 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Tue, 18 Jul 2023 21:59:39 -0400 Subject: Enable chkstk/alloca intrinsics on x86_64-unknown-uefi --- library/compiler-builtins/src/x86_64.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 393eeddd877..7ad94115825 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -11,8 +11,7 @@ use core::intrinsics; intrinsics! { #[naked] #[cfg(all( - windows, - target_env = "gnu", + any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") ))] pub unsafe extern "C" fn ___chkstk_ms() { @@ -40,8 +39,7 @@ intrinsics! { #[naked] #[cfg(all( - windows, - target_env = "gnu", + any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") ))] pub unsafe extern "C" fn __alloca() { @@ -54,8 +52,7 @@ intrinsics! { #[naked] #[cfg(all( - windows, - target_env = "gnu", + any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") ))] pub unsafe extern "C" fn ___chkstk() { -- cgit 1.4.1-3-g733a5 From 2a14bca476c42884837051e6359302a7da08cf24 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 21 Jul 2023 14:29:00 +0100 Subject: Bump to 0.1.97 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6c6c8d1365e..d95a69530ad 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.96" +version = "0.1.97" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 2b29ddcca785a937c5b02e61dd4170a9dc922ee0 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 21 Jul 2023 17:45:47 +0100 Subject: Upgrade to libm 0.2.7 --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 4c8a973741c..1dbb9d2d476 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 4c8a973741c014b11ce7f1477693a3e5d4ef9609 +Subproject commit 1dbb9d2d476d65d020feca17b11391652038e2e1 -- cgit 1.4.1-3-g733a5 From 05ca9048adad29393892b6ef0728b8e80c625343 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 21 Jul 2023 17:46:23 +0100 Subject: Bump to 0.1.98 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d95a69530ad..d1072fe6dbd 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.97" +version = "0.1.98" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From da052339350055721f0cd721042a5fa4a3766707 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 22 Jul 2023 15:05:30 -0400 Subject: Add __chkstk for aarch64-unknown-uefi This is based on compiler-rt/lib/builtins/aarch64/chkstk.S: https://github.com/llvm/llvm-project/commit/f8e19b37995751f7913692bf9eed8ebb14a95f2d --- library/compiler-builtins/src/aarch64.rs | 22 ++++++++++++++++++++++ library/compiler-builtins/src/lib.rs | 3 +++ 2 files changed, 25 insertions(+) create mode 100644 library/compiler-builtins/src/aarch64.rs diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64.rs new file mode 100644 index 00000000000..e5747d5258f --- /dev/null +++ b/library/compiler-builtins/src/aarch64.rs @@ -0,0 +1,22 @@ +#![allow(unused_imports)] + +use core::intrinsics; + +intrinsics! { + #[naked] + #[cfg(all(target_os = "uefi", not(feature = "no-asm")))] + pub unsafe extern "C" fn __chkstk() { + core::arch::asm!( + ".p2align 2", + "lsl x16, x15, #4", + "mov x17, sp", + "1:", + "sub x17, x17, 4096", + "subs x16, x16, 4096", + "ldr xzr, [x17]", + "b.gt 1b", + "ret", + options(noreturn) + ); + } +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index a6b61bdf5fc..f77f08268ca 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -58,6 +58,9 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; +#[cfg(target_arch = "aarch64")] +pub mod aarch64; + #[cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm"),))] pub mod aarch64_linux; -- cgit 1.4.1-3-g733a5 From d4477f8218d5521c0e3a3a72748ce846baa5dfdc Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Sun, 30 Jul 2023 10:45:26 -0700 Subject: Add lgamma_r and lgammaf_r to MSVC --- library/compiler-builtins/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index f77f08268ca..73cb3d505d2 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -50,7 +50,8 @@ pub mod int; all(target_arch = "xtensa", target_os = "none"), all(target_arch = "mips", target_os = "none"), target_os = "xous", - all(target_vendor = "fortanix", target_env = "sgx") + all(target_vendor = "fortanix", target_env = "sgx"), + target_env = "msvc" ))] pub mod math; pub mod mem; -- cgit 1.4.1-3-g733a5 From 0db7a3a020f9f0694c6411715ba17f5be0367bc1 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 30 Jul 2023 23:56:13 +0100 Subject: Bump to 0.1.99 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d1072fe6dbd..dde57030f11 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.98" +version = "0.1.99" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 2a197cb5c9c46d2b389e6a46eb26c7321e81b114 Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Mon, 31 Jul 2023 15:08:37 -0700 Subject: Add lgamma_r and lgammaf_r to MinGW --- library/compiler-builtins/src/lib.rs | 2 +- library/compiler-builtins/src/math.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 73cb3d505d2..dd81608f2e0 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -51,7 +51,7 @@ pub mod int; all(target_arch = "mips", target_os = "none"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx"), - target_env = "msvc" + target_os = "windows" ))] pub mod math; pub mod mem; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 4e255ca1a34..e0f7d8e8b66 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -96,7 +96,7 @@ no_mangle! { all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx"), - target_env = "msvc" + target_os = "windows" ))] intrinsics! { pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { -- cgit 1.4.1-3-g733a5 From c52ae9d5974b08f6455c33c0a87c1e995184c4f5 Mon Sep 17 00:00:00 2001 From: mulhern Date: Wed, 2 Aug 2023 14:05:07 -0400 Subject: Exclude ci directory from packaged crate I do not think there is compelling reason to release the ci support as part of a Rust source code package. In addition, the crate, as it is released now, gets flagged in some security scans due to the presence of Dockerfiles which are considered to be following some unsafe practices. Most Linux distros package using the vendored appraoch and provide a vendor tarfile of an application's dependencies. Scanners will tend to expect that the contents of the vendor tarfile will be source code. These Dockerfiles are already being flagged by some scanners; other contents of the ci directory may be flagged in future. --- library/compiler-builtins/libm/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 393d95e4af2..50e6ed6e222 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -10,6 +10,7 @@ readme = "README.md" repository = "https://github.com/rust-lang/libm" version = "0.2.7" edition = "2018" +exclude = ["/ci/"] [features] default = [] -- cgit 1.4.1-3-g733a5 From 54577e0039af34884e9a8f98e7e9103efe173766 Mon Sep 17 00:00:00 2001 From: mulhern Date: Thu, 3 Aug 2023 15:05:28 -0400 Subject: Exclude GitHub Workflows files from packaged crate --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 50e6ed6e222..12126c6d085 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" repository = "https://github.com/rust-lang/libm" version = "0.2.7" edition = "2018" -exclude = ["/ci/"] +exclude = ["/ci/", "/.github/workflows/"] [features] default = [] -- cgit 1.4.1-3-g733a5 From dd34581ec9062dd91bcc93e1934fe021fee9a328 Mon Sep 17 00:00:00 2001 From: klensy Date: Thu, 20 Jul 2023 17:23:56 +0300 Subject: edition 2018 --- library/compiler-builtins/Cargo.toml | 1 + library/compiler-builtins/src/arm.rs | 6 +++--- library/compiler-builtins/src/float/add.rs | 4 ++-- library/compiler-builtins/src/float/cmp.rs | 4 ++-- library/compiler-builtins/src/float/div.rs | 4 ++-- library/compiler-builtins/src/float/extend.rs | 4 ++-- library/compiler-builtins/src/float/mul.rs | 4 ++-- library/compiler-builtins/src/float/pow.rs | 4 ++-- library/compiler-builtins/src/float/sub.rs | 6 +++--- library/compiler-builtins/src/float/trunc.rs | 4 ++-- library/compiler-builtins/src/int/addsub.rs | 2 +- library/compiler-builtins/src/int/mul.rs | 2 +- library/compiler-builtins/src/int/sdiv.rs | 2 +- library/compiler-builtins/src/int/shift.rs | 2 +- library/compiler-builtins/src/int/udiv.rs | 4 ++-- library/compiler-builtins/src/macros.rs | 8 ++++---- library/compiler-builtins/src/math.rs | 1 + 17 files changed, 32 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index dde57030f11..bc8528087d1 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -7,6 +7,7 @@ readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" homepage = "https://github.com/rust-lang/compiler-builtins" documentation = "https://docs.rs/compiler_builtins" +edition = "2018" description = """ Compiler intrinsics used by the Rust compiler. Also available for other targets if necessary! diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index a062a54e008..cc67642e16b 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -91,7 +91,7 @@ intrinsics! { #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { - ::mem::memcpy(dest, src, n); + crate::mem::memcpy(dest, src, n); } #[weak] @@ -121,7 +121,7 @@ intrinsics! { #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { - ::mem::memmove(dest, src, n); + crate::mem::memmove(dest, src, n); } #[weak] @@ -140,7 +140,7 @@ intrinsics! { #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { // Note the different argument order - ::mem::memset(dest, c, n); + crate::mem::memset(dest, c, n); } #[weak] diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 67f6c2c1489..804f4b5100b 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,5 +1,5 @@ -use float::Float; -use int::{CastInto, Int}; +use crate::float::Float; +use crate::int::{CastInto, Int}; /// Returns `a + b` fn add(a: F, b: F) -> F diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 1bd7aa284d8..1c8917af8ad 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -1,7 +1,7 @@ #![allow(unreachable_code)] -use float::Float; -use int::Int; +use crate::float::Float; +use crate::int::Int; #[derive(Clone, Copy)] enum Result { diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index c0aae34fb63..8c4cf55b8d3 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -2,8 +2,8 @@ // `return`s makes it clear where function exit points are #![allow(clippy::needless_return)] -use float::Float; -use int::{CastInto, DInt, HInt, Int}; +use crate::float::Float; +use crate::int::{CastInto, DInt, HInt, Int}; fn div32(a: F, b: F) -> F where diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 39633773b25..cffc57510e6 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -1,5 +1,5 @@ -use float::Float; -use int::{CastInto, Int}; +use crate::float::Float; +use crate::int::{CastInto, Int}; /// Generic conversion from a narrower to a wider IEEE-754 floating-point type fn extend(a: F) -> R diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index c89f22756af..1b8c61203e6 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -1,5 +1,5 @@ -use float::Float; -use int::{CastInto, DInt, HInt, Int}; +use crate::float::Float; +use crate::int::{CastInto, DInt, HInt, Int}; fn mul(a: F, b: F) -> F where diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index a75340c3093..0232ef405d1 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,5 +1,5 @@ -use float::Float; -use int::Int; +use crate::float::Float; +use crate::int::Int; /// Returns `a` raised to the power `b` fn pow(a: F, b: i32) -> F { diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 8d300e9d248..0ea071b3ce9 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -1,6 +1,6 @@ -use float::add::__adddf3; -use float::add::__addsf3; -use float::Float; +use crate::float::add::__adddf3; +use crate::float::add::__addsf3; +use crate::float::Float; intrinsics! { #[arm_aeabi_alias = __aeabi_fsub] diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index d73713084d6..9bc4d6e57e1 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -1,5 +1,5 @@ -use float::Float; -use int::{CastInto, Int}; +use crate::float::Float; +use crate::int::{CastInto, Int}; fn trunc(a: F) -> R where diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs index f4841e90f63..f31eff4bd03 100644 --- a/library/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/src/int/addsub.rs @@ -1,4 +1,4 @@ -use int::{DInt, Int}; +use crate::int::{DInt, Int}; trait UAddSub: DInt { fn uadd(self, other: Self) -> Self { diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 07ce061c994..2538e2f4181 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,4 +1,4 @@ -use int::{DInt, HInt, Int}; +use crate::int::{DInt, HInt, Int}; trait Mul: DInt where diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index f1822f0f86e..9d316c76eca 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,4 +1,4 @@ -use int::udiv::*; +use crate::int::udiv::*; macro_rules! sdivmod { ( diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index c90cf1de320..dbd04018732 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,4 +1,4 @@ -use int::{DInt, HInt, Int}; +use crate::int::{DInt, HInt, Int}; trait Ashl: DInt { /// Returns `a << b`, requires `b < Self::BITS` diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index fb09f87d89c..c891eede4b1 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,8 +1,8 @@ #[cfg(not(feature = "public-test-deps"))] -pub(crate) use int::specialized_div_rem::*; +pub(crate) use crate::int::specialized_div_rem::*; #[cfg(feature = "public-test-deps")] -pub use int::specialized_div_rem::*; +pub use crate::int::specialized_div_rem::*; intrinsics! { #[maybe_use_optimized_c_shim] diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index b11114f1238..d2b5734d525 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -321,10 +321,10 @@ macro_rules! intrinsics { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) - -> ::macros::win64_128bit_abi_hack::U64x2 + -> $crate::macros::win64_128bit_abi_hack::U64x2 { let e: $($ret)? = super::$name($($argname),*); - ::macros::win64_128bit_abi_hack::U64x2::from(e) + $crate::macros::win64_128bit_abi_hack::U64x2::from(e) } } @@ -540,7 +540,7 @@ pub mod win64_128bit_abi_hack { impl From for U64x2 { fn from(i: i128) -> U64x2 { - use int::DInt; + use crate::int::DInt; let j = i as u128; U64x2(j.lo(), j.hi()) } @@ -548,7 +548,7 @@ pub mod win64_128bit_abi_hack { impl From for U64x2 { fn from(i: u128) -> U64x2 { - use int::DInt; + use crate::int::DInt; U64x2(i.lo(), i.hi()) } } diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 4e255ca1a34..21d23ff978f 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -2,6 +2,7 @@ #[path = "../libm/src/math/mod.rs"] mod libm; +#[allow(unused_macros)] macro_rules! no_mangle { ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { intrinsics! { -- cgit 1.4.1-3-g733a5 From 10f6ee84e38143e2d54c03f6e70a918ad8edd8e4 Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 7 Aug 2023 17:52:27 +0300 Subject: allow internal_features, added in https://github.com/rust-lang/rust/pull/108955 --- library/compiler-builtins/examples/intrinsics.rs | 1 + library/compiler-builtins/src/lib.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 19bb569b57d..54b703dfbc7 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -5,6 +5,7 @@ #![allow(unused_features)] #![allow(stable_features)] // bench_black_box feature is stable, leaving for backcompat +#![allow(internal_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] #![feature(bench_black_box)] diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 73cb3d505d2..2ef28fc6330 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -14,6 +14,7 @@ #![no_builtins] #![no_std] #![allow(unused_features)] +#![allow(internal_features)] // We use `u128` in a whole bunch of places which we currently agree with the // compiler on ABIs and such, so we should be "good enough" for now and changes // to the `u128` ABI will be reflected here. -- cgit 1.4.1-3-g733a5 From a15a3a5df00da818d5a39b63d79a318d034c5dc4 Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 7 Aug 2023 21:19:25 +0300 Subject: impl_binary_long allow to pass attribute --- library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs | 4 ++++ library/compiler-builtins/src/int/specialized_div_rem/mod.rs | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs index 0d7822882b0..2c61a45e06e 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs @@ -13,9 +13,13 @@ macro_rules! impl_binary_long { $n:tt, // the number of bits in a $iX or $uX $uX:ident, // unsigned integer type for the inputs and outputs of `$fn` $iX:ident // signed integer type with same bitwidth as `$uX` + $(, $fun_attr:meta)* // attributes for the function ) => { /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a /// tuple. + $( + #[$fun_attr] + )* pub fn $fn(duo: $uX, div: $uX) -> ($uX, $uX) { let mut duo = duo; // handle edge cases before calling `$normalization_shift` diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 1ff1d19dc8c..760f5f5b7a3 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -306,5 +306,6 @@ impl_binary_long!( u32_normalization_shift, 32, u32, - i32 + i32, + allow(dead_code) ); -- cgit 1.4.1-3-g733a5 From ceffc1c25fc59994d072404ba5b67341db012be8 Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 7 Aug 2023 21:51:34 +0300 Subject: fix ci, disable mips, mirrors https://github.com/rust-lang/compiler-builtins/pull/537 --- library/compiler-builtins/libm/.github/workflows/main.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index decd71f5c7a..5408ac23fb4 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -13,9 +13,11 @@ jobs: - arm-unknown-linux-gnueabihf - armv7-unknown-linux-gnueabihf # - i686-unknown-linux-gnu - - mips-unknown-linux-gnu - - mips64-unknown-linux-gnuabi64 - - mips64el-unknown-linux-gnuabi64 + # MIPS targets disabled since they are dropped to tier 3. + # See https://github.com/rust-lang/compiler-team/issues/648 + #- mips-unknown-linux-gnu + #- mips64-unknown-linux-gnuabi64 + #- mips64el-unknown-linux-gnuabi64 - powerpc-unknown-linux-gnu - powerpc64-unknown-linux-gnu - powerpc64le-unknown-linux-gnu -- cgit 1.4.1-3-g733a5 From 14f4e11a86c857426cba130bb333d9d2a193aad5 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 7 Aug 2023 23:37:59 +0100 Subject: Bump to 0.1.100 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index bc8528087d1..797857d7645 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.99" +version = "0.1.100" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 10df3f61ad291eee4a3c8e6e1129601acf18b011 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 10 Aug 2023 13:50:04 +0800 Subject: build: compile memory intrinsics on xous Like SGX, Xous does not have any libc to link against. As a result, memory intrinsics need to be available as part of `compiler_builtins` Signed-off-by: Sean Cross --- library/compiler-builtins/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 26db6b4be9a..10c7aaa63e0 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -30,6 +30,7 @@ fn main() { || target.contains("-none") || target.contains("nvptx") || target.contains("uefi") + || target.contains("xous") { println!("cargo:rustc-cfg=feature=\"mem\""); } -- cgit 1.4.1-3-g733a5 From 5642f6ba4c4b0d4aaffa3499247ea1ae1f9faeb4 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 12 Aug 2023 10:28:45 +0200 Subject: Bump to 0.1.101 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 797857d7645..239191a9bce 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.100" +version = "0.1.101" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 1dbb9d2d476..5bcbc3b636b 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 1dbb9d2d476d65d020feca17b11391652038e2e1 +Subproject commit 5bcbc3b636b79da7a3061b1c257d4ae53f033018 -- cgit 1.4.1-3-g733a5 From 6595f3631751b622ace9e83745edd9dbcca89c65 Mon Sep 17 00:00:00 2001 From: James Farrell Date: Mon, 28 Aug 2023 22:14:18 +0000 Subject: Generate outlined_atomics.rs in a deterministic order. Also add a missing newline. --- library/compiler-builtins/build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 10c7aaa63e0..b60181062a7 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, env, sync::atomic::Ordering}; +use std::{collections::BTreeMap, env, sync::atomic::Ordering}; fn main() { println!("cargo:rerun-if-changed=build.rs"); @@ -118,7 +118,7 @@ fn generate_aarch64_outlined_atomics() { // Generate different macros for add/clr/eor/set so that we can test them separately. let sym_names = ["cas", "ldadd", "ldclr", "ldeor", "ldset", "swp"]; - let mut macros = HashMap::new(); + let mut macros = BTreeMap::new(); for sym in sym_names { macros.insert(sym, gen_macro(sym)); } @@ -146,7 +146,7 @@ fn generate_aarch64_outlined_atomics() { let mut buf = String::new(); for macro_def in macros.values().chain(std::iter::once(&cas16)) { buf += macro_def; - buf += "}; }"; + buf += "}; }\n"; } let dst = std::env::var("OUT_DIR").unwrap() + "/outlined_atomics.rs"; std::fs::write(dst, buf).unwrap(); -- cgit 1.4.1-3-g733a5 From 36e334dfb02a0c072005e8836a9364137b517ee9 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Thu, 5 Oct 2023 17:38:44 +0000 Subject: Fix rint and rintf on x87. --- library/compiler-builtins/libm/src/math/rint.rs | 14 ++++++++++++-- library/compiler-builtins/libm/src/math/rintf.rs | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 0c6025c1f73..8edbe344022 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -8,9 +8,19 @@ pub fn rint(x: f64) -> f64 { x } else { let ans = if is_positive { - x + one_over_e - one_over_e + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let x = force_eval!(x); + let xplusoneovere = x + one_over_e; + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let xplusoneovere = force_eval!(xplusoneovere); + xplusoneovere - one_over_e } else { - x - one_over_e + one_over_e + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let x = force_eval!(x); + let xminusoneovere = x - one_over_e; + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let xminusoneovere = force_eval!(xminusoneovere); + xminusoneovere + one_over_e }; if ans == 0.0 { diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index d427793f7fc..7a7da618ad8 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -8,9 +8,19 @@ pub fn rintf(x: f32) -> f32 { x } else { let ans = if is_positive { - x + one_over_e - one_over_e + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let x = force_eval!(x); + let xplusoneovere = x + one_over_e; + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let xplusoneovere = force_eval!(xplusoneovere); + xplusoneovere - one_over_e } else { - x - one_over_e + one_over_e + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let x = force_eval!(x); + let xminusoneovere = x - one_over_e; + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let xminusoneovere = force_eval!(xminusoneovere); + xminusoneovere + one_over_e }; if ans == 0.0 { -- cgit 1.4.1-3-g733a5 From 5531828bfceeb8d794e6445aa0a8c50adca9d331 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 6 Oct 2023 11:25:38 +0200 Subject: Release 0.2.8 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 12126c6d085..d33ca61cd47 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.7" +version = "0.2.8" edition = "2018" exclude = ["/ci/", "/.github/workflows/"] -- cgit 1.4.1-3-g733a5 From 25fa91e1b249218b5df895c725273888b5e68147 Mon Sep 17 00:00:00 2001 From: Sebastian Imlay Date: Fri, 6 Oct 2023 17:35:20 -0400 Subject: Add tvOS to build script --- library/compiler-builtins/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index b60181062a7..0486116778c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -320,6 +320,7 @@ mod c { // include them. if target_os != "ios" && target_os != "watchos" + && target_os != "tvos" && (target_vendor != "apple" || target_arch != "x86") { sources.extend(&[ @@ -391,6 +392,7 @@ mod c { if target_arch == "arm" && target_os != "ios" && target_os != "watchos" + && target_os != "tvos" && target_env != "msvc" { sources.extend(&[ -- cgit 1.4.1-3-g733a5 From de2da94c49d4ad76b29bb3ccb6b4966e2440522b Mon Sep 17 00:00:00 2001 From: Grant Elbert Date: Mon, 23 Oct 2023 15:54:05 -0500 Subject: intrinsics macro: fix non-weak aeabi generation Signed-off-by: Grant Elbert --- library/compiler-builtins/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index d2b5734d525..2aa9a742c57 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -369,7 +369,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] pub mod $alias { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(any(all(not(windows), not(target_vendor="apple"), feature = "weak-intrinsics")), linkage = "weak")] + #[cfg_attr(any(all(not(windows), not(target_vendor="apple")), feature = "weak-intrinsics"), linkage = "weak")] pub extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } -- cgit 1.4.1-3-g733a5 From e8509dd054bf960bde4de66f76829a755a0c46a9 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Fri, 27 Oct 2023 20:19:55 +0000 Subject: Enable src/math for all UEFI targets This fixes various math operations on aarch64-unknown-uefi and i686-unknown-uefi. --- library/compiler-builtins/src/lib.rs | 2 +- library/compiler-builtins/src/math.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index d1195a4a83d..e2e35fbd324 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -46,7 +46,7 @@ pub mod int; #[cfg(any( all(target_family = "wasm", target_os = "unknown"), all(target_arch = "x86_64", target_os = "none"), - all(target_arch = "x86_64", target_os = "uefi"), + target_os = "uefi", all(target_arch = "arm", target_os = "none"), all(target_arch = "xtensa", target_os = "none"), all(target_arch = "mips", target_os = "none"), diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index f8f9d225bea..63d85833393 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -22,7 +22,7 @@ macro_rules! no_mangle { not(target_env = "wasi") ), target_os = "xous", - all(target_arch = "x86_64", target_os = "uefi"), + target_os = "uefi", all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") ))] @@ -94,7 +94,7 @@ no_mangle! { not(target_env = "wasi") ), target_os = "xous", - all(target_arch = "x86_64", target_os = "uefi"), + target_os = "uefi", all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx"), target_os = "windows" -- cgit 1.4.1-3-g733a5 From 8ec53915fefeed8fc1656573e1ffea859fefbdc4 Mon Sep 17 00:00:00 2001 From: Michał Chodzikiewicz Date: Tue, 31 Oct 2023 20:32:53 +0100 Subject: Enable math module for all "none" os targets This was initially a bugfix that fixed gating math module for riscv32, but conclusiion is it makes no sense to gate on target architecture. --- library/compiler-builtins/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index e2e35fbd324..3e54918782b 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -45,11 +45,8 @@ pub mod int; #[cfg(any( all(target_family = "wasm", target_os = "unknown"), - all(target_arch = "x86_64", target_os = "none"), target_os = "uefi", - all(target_arch = "arm", target_os = "none"), - all(target_arch = "xtensa", target_os = "none"), - all(target_arch = "mips", target_os = "none"), + target_os = "none", target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx"), target_os = "windows" -- cgit 1.4.1-3-g733a5 From 7a32a99352cc6001c24c8bff0885c0d0cb937678 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Tue, 31 Oct 2023 15:59:56 -0600 Subject: This updates the exponent calculations done in the nextafter functions related to detecting underflow/overflow. The functions now match the behavior of the MUSL implementations these were based on. Fixes rust-lang/libm#286 --- library/compiler-builtins/libm/src/math/nextafter.rs | 2 +- library/compiler-builtins/libm/src/math/nextafterf.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/src/math/nextafter.rs index 13094a17c34..05762619109 100644 --- a/library/compiler-builtins/libm/src/math/nextafter.rs +++ b/library/compiler-builtins/libm/src/math/nextafter.rs @@ -23,7 +23,7 @@ pub fn nextafter(x: f64, y: f64) -> f64 { ux_i += 1; } - let e = ux_i.wrapping_shr(52 & 0x7ff); + let e = ux_i >> 52 & 0x7ff; // raise overflow if ux.f is infinite and x is finite if e == 0x7ff { force_eval!(x + x); diff --git a/library/compiler-builtins/libm/src/math/nextafterf.rs b/library/compiler-builtins/libm/src/math/nextafterf.rs index df9b1082978..8ba3833562f 100644 --- a/library/compiler-builtins/libm/src/math/nextafterf.rs +++ b/library/compiler-builtins/libm/src/math/nextafterf.rs @@ -23,7 +23,7 @@ pub fn nextafterf(x: f32, y: f32) -> f32 { ux_i += 1; } - let e = ux_i.wrapping_shr(0x7f80_0000_u32); + let e = ux_i & 0x7f80_0000_u32; // raise overflow if ux_f is infinite and x is finite if e == 0x7f80_0000_u32 { force_eval!(x + x); -- cgit 1.4.1-3-g733a5 From 44d0e30db9aeb6eba2da5bf888f255b2d3b2ed5d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 4 Nov 2023 00:28:36 +0000 Subject: Bump to 0.1.102 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 239191a9bce..320a4c1fe3c 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.101" +version = "0.1.102" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 52959b58006bc4b746384a36e8ddea2ad4f1b630 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 4 Nov 2023 00:29:27 +0000 Subject: Bump to 0.1.103 There was a mistake in publishing the 0.1.102 release. --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 320a4c1fe3c..5a022cc4b84 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.102" +version = "0.1.103" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From c2c4c8e146ec7127d9fa0fc3f27da56dba9597ab Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Sun, 26 Nov 2023 16:17:00 +0100 Subject: fix: Add (even more) `#[avr_skip]` for floats Tale as old as the world - there's an ABI mismatch: https://github.com/rust-lang/compiler-builtins/pull/527 Fortunately, newest GCCs (from v11, it seems) actually provide most of those intrinsics (even for f64!), so that's pretty cool. (the only intrinsics not provided by GCC are `__powisf2` & `__powidf2`, but our codegen for AVR doesn't emit those anyway.) Fixes https://github.com/rust-lang/rust/issues/118079. --- library/compiler-builtins/src/float/div.rs | 2 ++ library/compiler-builtins/src/float/extend.rs | 1 + library/compiler-builtins/src/float/mul.rs | 2 ++ library/compiler-builtins/src/float/pow.rs | 2 ++ library/compiler-builtins/src/float/sub.rs | 2 ++ library/compiler-builtins/src/float/trunc.rs | 1 + 6 files changed, 10 insertions(+) diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 8c4cf55b8d3..d587fe4f98f 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -902,11 +902,13 @@ where } intrinsics! { + #[avr_skip] #[arm_aeabi_alias = __aeabi_fdiv] pub extern "C" fn __divsf3(a: f32, b: f32) -> f32 { div32(a, b) } + #[avr_skip] #[arm_aeabi_alias = __aeabi_ddiv] pub extern "C" fn __divdf3(a: f64, b: f64) -> f64 { div64(a, b) diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index cffc57510e6..0e6673b9c09 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -70,6 +70,7 @@ where } intrinsics! { + #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_f2d] pub extern "C" fn __extendsfdf2(a: f32) -> f64 { diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 1b8c61203e6..378fa970116 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -185,12 +185,14 @@ where } intrinsics! { + #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_fmul] pub extern "C" fn __mulsf3(a: f32, b: f32) -> f32 { mul(a, b) } + #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_dmul] pub extern "C" fn __muldf3(a: f64, b: f64) -> f64 { diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 0232ef405d1..3103fe6f697 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -26,10 +26,12 @@ fn pow(a: F, b: i32) -> F { } intrinsics! { + #[avr_skip] pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 { pow(a, b) } + #[avr_skip] pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 { pow(a, b) } diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 0ea071b3ce9..64653ee25ff 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -3,11 +3,13 @@ use crate::float::add::__addsf3; use crate::float::Float; intrinsics! { + #[avr_skip] #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { __addsf3(a, f32::from_repr(b.repr() ^ f32::SIGN_MASK)) } + #[avr_skip] #[arm_aeabi_alias = __aeabi_dsub] pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { __adddf3(a, f64::from_repr(b.repr() ^ f64::SIGN_MASK)) diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 9bc4d6e57e1..0beeb9f98de 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -112,6 +112,7 @@ where } intrinsics! { + #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_d2f] pub extern "C" fn __truncdfsf2(a: f64) -> f32 { -- cgit 1.4.1-3-g733a5 From d46758a18f9122956723b115b58f2cb4f30f4b6e Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 28 Nov 2023 08:02:43 +0000 Subject: Bump to 0.1.104 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 5a022cc4b84..6ebabfdcbeb 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.103" +version = "0.1.104" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 5bcbc3b636b..721a5edc1be 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 5bcbc3b636b79da7a3061b1c257d4ae53f033018 +Subproject commit 721a5edc1be6b0412e4b1704590aed76f9a55899 -- cgit 1.4.1-3-g733a5 From c4a7058a1193584f156f83f141e56c53e7720ab0 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 5 Nov 2023 18:42:34 -0800 Subject: Add hexagon support Signed-off-by: Brian Cain --- library/compiler-builtins/src/hexagon.rs | 55 +++ library/compiler-builtins/src/hexagon/dfaddsub.s | 321 ++++++++++++ library/compiler-builtins/src/hexagon/dfdiv.s | 372 ++++++++++++++ library/compiler-builtins/src/hexagon/dffma.s | 536 +++++++++++++++++++++ library/compiler-builtins/src/hexagon/dfminmax.s | 51 ++ library/compiler-builtins/src/hexagon/dfmul.s | 309 ++++++++++++ library/compiler-builtins/src/hexagon/dfsqrt.s | 277 +++++++++++ library/compiler-builtins/src/hexagon/divdi3.s | 64 +++ library/compiler-builtins/src/hexagon/divsi3.s | 53 ++ .../src/hexagon/fastmath2_dlib_asm.s | 266 ++++++++++ .../src/hexagon/fastmath2_ldlib_asm.s | 187 +++++++ library/compiler-builtins/src/hexagon/func_macro.s | 12 + .../src/hexagon/memcpy_forward_vp4cp4n2.s | 91 ++++ .../src/hexagon/memcpy_likely_aligned.s | 42 ++ library/compiler-builtins/src/hexagon/moddi3.s | 63 +++ library/compiler-builtins/src/hexagon/modsi3.s | 44 ++ library/compiler-builtins/src/hexagon/sfdiv_opt.s | 42 ++ library/compiler-builtins/src/hexagon/sfsqrt_opt.s | 49 ++ library/compiler-builtins/src/hexagon/udivdi3.s | 50 ++ library/compiler-builtins/src/hexagon/udivmoddi4.s | 50 ++ library/compiler-builtins/src/hexagon/udivmodsi4.s | 39 ++ library/compiler-builtins/src/hexagon/udivsi3.s | 36 ++ library/compiler-builtins/src/hexagon/umoddi3.s | 53 ++ library/compiler-builtins/src/hexagon/umodsi3.s | 34 ++ library/compiler-builtins/src/lib.rs | 4 + 25 files changed, 3100 insertions(+) create mode 100644 library/compiler-builtins/src/hexagon.rs create mode 100644 library/compiler-builtins/src/hexagon/dfaddsub.s create mode 100644 library/compiler-builtins/src/hexagon/dfdiv.s create mode 100644 library/compiler-builtins/src/hexagon/dffma.s create mode 100644 library/compiler-builtins/src/hexagon/dfminmax.s create mode 100644 library/compiler-builtins/src/hexagon/dfmul.s create mode 100644 library/compiler-builtins/src/hexagon/dfsqrt.s create mode 100644 library/compiler-builtins/src/hexagon/divdi3.s create mode 100644 library/compiler-builtins/src/hexagon/divsi3.s create mode 100644 library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s create mode 100644 library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s create mode 100644 library/compiler-builtins/src/hexagon/func_macro.s create mode 100644 library/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s create mode 100644 library/compiler-builtins/src/hexagon/memcpy_likely_aligned.s create mode 100644 library/compiler-builtins/src/hexagon/moddi3.s create mode 100644 library/compiler-builtins/src/hexagon/modsi3.s create mode 100644 library/compiler-builtins/src/hexagon/sfdiv_opt.s create mode 100644 library/compiler-builtins/src/hexagon/sfsqrt_opt.s create mode 100644 library/compiler-builtins/src/hexagon/udivdi3.s create mode 100644 library/compiler-builtins/src/hexagon/udivmoddi4.s create mode 100644 library/compiler-builtins/src/hexagon/udivmodsi4.s create mode 100644 library/compiler-builtins/src/hexagon/udivsi3.s create mode 100644 library/compiler-builtins/src/hexagon/umoddi3.s create mode 100644 library/compiler-builtins/src/hexagon/umodsi3.s diff --git a/library/compiler-builtins/src/hexagon.rs b/library/compiler-builtins/src/hexagon.rs new file mode 100644 index 00000000000..91cf91c3142 --- /dev/null +++ b/library/compiler-builtins/src/hexagon.rs @@ -0,0 +1,55 @@ +#![cfg(not(feature = "no-asm"))] + +use core::arch::global_asm; + +global_asm!(include_str!("hexagon/func_macro.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfaddsub.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfdiv.s"), options(raw)); + +global_asm!(include_str!("hexagon/dffma.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfminmax.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfmul.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfsqrt.s"), options(raw)); + +global_asm!(include_str!("hexagon/divdi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/divsi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/fastmath2_dlib_asm.s"), options(raw)); + +global_asm!(include_str!("hexagon/fastmath2_ldlib_asm.s"), options(raw)); + +global_asm!( + include_str!("hexagon/memcpy_forward_vp4cp4n2.s"), + options(raw) +); + +global_asm!( + include_str!("hexagon/memcpy_likely_aligned.s"), + options(raw) +); + +global_asm!(include_str!("hexagon/moddi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/modsi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/sfdiv_opt.s"), options(raw)); + +global_asm!(include_str!("hexagon/sfsqrt_opt.s"), options(raw)); + +global_asm!(include_str!("hexagon/udivdi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/udivmoddi4.s"), options(raw)); + +global_asm!(include_str!("hexagon/udivmodsi4.s"), options(raw)); + +global_asm!(include_str!("hexagon/udivsi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/umoddi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/umodsi3.s"), options(raw)); diff --git a/library/compiler-builtins/src/hexagon/dfaddsub.s b/library/compiler-builtins/src/hexagon/dfaddsub.s new file mode 100644 index 00000000000..1f59e460be6 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/dfaddsub.s @@ -0,0 +1,321 @@ + .text + .global __hexagon_adddf3 + .global __hexagon_subdf3 + .type __hexagon_adddf3, @function + .type __hexagon_subdf3, @function + +.global __qdsp_adddf3 ; .set __qdsp_adddf3, __hexagon_adddf3 +.global __hexagon_fast_adddf3 ; .set __hexagon_fast_adddf3, __hexagon_adddf3 +.global __hexagon_fast2_adddf3 ; .set __hexagon_fast2_adddf3, __hexagon_adddf3 +.global __qdsp_subdf3 ; .set __qdsp_subdf3, __hexagon_subdf3 +.global __hexagon_fast_subdf3 ; .set __hexagon_fast_subdf3, __hexagon_subdf3 +.global __hexagon_fast2_subdf3 ; .set __hexagon_fast2_subdf3, __hexagon_subdf3 + + .p2align 5 +__hexagon_adddf3: + { + r4 = extractu(r1,#11,#20) + r5 = extractu(r3,#11,#20) + r13:12 = combine(##0x20000000,#0) + } + { + p3 = dfclass(r1:0,#2) + p3 = dfclass(r3:2,#2) + r9:8 = r13:12 + p2 = cmp.gtu(r5,r4) + } + { + if (!p3) jump .Ladd_abnormal + if (p2) r1:0 = r3:2 + if (p2) r3:2 = r1:0 + if (p2) r5:4 = combine(r4,r5) + } + { + r13:12 = insert(r1:0,#52,#11 -2) + r9:8 = insert(r3:2,#52,#11 -2) + r15 = sub(r4,r5) + r7:6 = combine(#62,#1) + } + + + + + +.Ladd_continue: + { + r15 = min(r15,r7) + + r11:10 = neg(r13:12) + p2 = cmp.gt(r1,#-1) + r14 = #0 + } + { + if (!p2) r13:12 = r11:10 + r11:10 = extractu(r9:8,r15:14) + r9:8 = ASR(r9:8,r15) + + + + + r15:14 = #0 + } + { + p1 = cmp.eq(r11:10,r15:14) + if (!p1.new) r8 = or(r8,r6) + r5 = add(r4,#-1024 -60) + p3 = cmp.gt(r3,#-1) + } + { + r13:12 = add(r13:12,r9:8) + r11:10 = sub(r13:12,r9:8) + r7:6 = combine(#54,##2045) + } + { + p0 = cmp.gtu(r4,r7) + p0 = !cmp.gtu(r4,r6) + if (!p0.new) jump:nt .Ladd_ovf_unf + if (!p3) r13:12 = r11:10 + } + { + r1:0 = convert_d2df(r13:12) + p0 = cmp.eq(r13,#0) + p0 = cmp.eq(r12,#0) + if (p0.new) jump:nt .Ladd_zero + } + { + r1 += asl(r5,#20) + jumpr r31 + } + .falign +__hexagon_subdf3: + { + r3 = togglebit(r3,#31) + jump __qdsp_adddf3 + } + + + .falign +.Ladd_zero: + + + { + r28 = USR + r1:0 = #0 + r3 = #1 + } + { + r28 = extractu(r28,#2,#22) + r3 = asl(r3,#31) + } + { + p0 = cmp.eq(r28,#2) + if (p0.new) r1 = xor(r1,r3) + jumpr r31 + } + .falign +.Ladd_ovf_unf: + { + r1:0 = convert_d2df(r13:12) + p0 = cmp.eq(r13,#0) + p0 = cmp.eq(r12,#0) + if (p0.new) jump:nt .Ladd_zero + } + { + r28 = extractu(r1,#11,#20) + r1 += asl(r5,#20) + } + { + r5 = add(r5,r28) + r3:2 = combine(##0x00100000,#0) + } + { + p0 = cmp.gt(r5,##1024 +1024 -2) + if (p0.new) jump:nt .Ladd_ovf + } + { + p0 = cmp.gt(r5,#0) + if (p0.new) jumpr:t r31 + r28 = sub(#1,r5) + } + { + r3:2 = insert(r1:0,#52,#0) + r1:0 = r13:12 + } + { + r3:2 = lsr(r3:2,r28) + } + { + r1:0 = insert(r3:2,#63,#0) + jumpr r31 + } + .falign +.Ladd_ovf: + + { + r1:0 = r13:12 + r28 = USR + r13:12 = combine(##0x7fefffff,#-1) + } + { + r5 = extractu(r28,#2,#22) + r28 = or(r28,#0x28) + r9:8 = combine(##0x7ff00000,#0) + } + { + USR = r28 + r5 ^= lsr(r1,#31) + r28 = r5 + } + { + p0 = !cmp.eq(r28,#1) + p0 = !cmp.eq(r5,#2) + if (p0.new) r13:12 = r9:8 + } + { + r1:0 = insert(r13:12,#63,#0) + } + { + p0 = dfcmp.eq(r1:0,r1:0) + jumpr r31 + } + +.Ladd_abnormal: + { + r13:12 = extractu(r1:0,#63,#0) + r9:8 = extractu(r3:2,#63,#0) + } + { + p3 = cmp.gtu(r13:12,r9:8) + if (!p3.new) r1:0 = r3:2 + if (!p3.new) r3:2 = r1:0 + } + { + + p0 = dfclass(r1:0,#0x0f) + if (!p0.new) jump:nt .Linvalid_nan_add + if (!p3) r13:12 = r9:8 + if (!p3) r9:8 = r13:12 + } + { + + + p1 = dfclass(r1:0,#0x08) + if (p1.new) jump:nt .Linf_add + } + { + p2 = dfclass(r3:2,#0x01) + if (p2.new) jump:nt .LB_zero + r13:12 = #0 + } + + { + p0 = dfclass(r1:0,#4) + if (p0.new) jump:nt .Ladd_two_subnormal + r13:12 = combine(##0x20000000,#0) + } + { + r4 = extractu(r1,#11,#20) + r5 = #1 + + r9:8 = asl(r9:8,#11 -2) + } + + + + { + r13:12 = insert(r1:0,#52,#11 -2) + r15 = sub(r4,r5) + r7:6 = combine(#62,#1) + jump .Ladd_continue + } + +.Ladd_two_subnormal: + { + r13:12 = extractu(r1:0,#63,#0) + r9:8 = extractu(r3:2,#63,#0) + } + { + r13:12 = neg(r13:12) + r9:8 = neg(r9:8) + p0 = cmp.gt(r1,#-1) + p1 = cmp.gt(r3,#-1) + } + { + if (p0) r13:12 = r1:0 + if (p1) r9:8 = r3:2 + } + { + r13:12 = add(r13:12,r9:8) + } + { + r9:8 = neg(r13:12) + p0 = cmp.gt(r13,#-1) + r3:2 = #0 + } + { + if (!p0) r1:0 = r9:8 + if (p0) r1:0 = r13:12 + r3 = ##0x80000000 + } + { + if (!p0) r1 = or(r1,r3) + p0 = dfcmp.eq(r1:0,r3:2) + if (p0.new) jump:nt .Lzero_plus_zero + } + { + jumpr r31 + } + +.Linvalid_nan_add: + { + r28 = convert_df2sf(r1:0) + p0 = dfclass(r3:2,#0x0f) + if (p0.new) r3:2 = r1:0 + } + { + r2 = convert_df2sf(r3:2) + r1:0 = #-1 + jumpr r31 + } + .falign +.LB_zero: + { + p0 = dfcmp.eq(r13:12,r1:0) + if (!p0.new) jumpr:t r31 + } + + + + +.Lzero_plus_zero: + { + p0 = cmp.eq(r1:0,r3:2) + if (p0.new) jumpr:t r31 + } + { + r28 = USR + } + { + r28 = extractu(r28,#2,#22) + r1:0 = #0 + } + { + p0 = cmp.eq(r28,#2) + if (p0.new) r1 = ##0x80000000 + jumpr r31 + } +.Linf_add: + + { + p0 = !cmp.eq(r1,r3) + p0 = dfclass(r3:2,#8) + if (!p0.new) jumpr:t r31 + } + { + r2 = ##0x7f800001 + } + { + r1:0 = convert_sf2df(r2) + jumpr r31 + } +.size __hexagon_adddf3,.-__hexagon_adddf3 diff --git a/library/compiler-builtins/src/hexagon/dfdiv.s b/library/compiler-builtins/src/hexagon/dfdiv.s new file mode 100644 index 00000000000..6d65dbfc4df --- /dev/null +++ b/library/compiler-builtins/src/hexagon/dfdiv.s @@ -0,0 +1,372 @@ + .text + .global __hexagon_divdf3 + .type __hexagon_divdf3,@function + .global __qdsp_divdf3 ; .set __qdsp_divdf3, __hexagon_divdf3 + .global __hexagon_fast_divdf3 ; .set __hexagon_fast_divdf3, __hexagon_divdf3 + .global __hexagon_fast2_divdf3 ; .set __hexagon_fast2_divdf3, __hexagon_divdf3 + .p2align 5 +__hexagon_divdf3: + { + p2 = dfclass(r1:0,#0x02) + p2 = dfclass(r3:2,#0x02) + r13:12 = combine(r3,r1) + r28 = xor(r1,r3) + } + { + if (!p2) jump .Ldiv_abnormal + r7:6 = extractu(r3:2,#23,#52 -23) + r8 = ##0x3f800001 + } + { + r9 = or(r8,r6) + r13 = extractu(r13,#11,#52 -32) + r12 = extractu(r12,#11,#52 -32) + p3 = cmp.gt(r28,#-1) + } + + +.Ldenorm_continue: + { + r11,p0 = sfrecipa(r8,r9) + r10 = and(r8,#-2) + r28 = #1 + r12 = sub(r12,r13) + } + + + { + r10 -= sfmpy(r11,r9):lib + r1 = insert(r28,#11 +1,#52 -32) + r13 = ##0x00800000 << 3 + } + { + r11 += sfmpy(r11,r10):lib + r3 = insert(r28,#11 +1,#52 -32) + r10 = and(r8,#-2) + } + { + r10 -= sfmpy(r11,r9):lib + r5 = #-0x3ff +1 + r4 = #0x3ff -1 + } + { + r11 += sfmpy(r11,r10):lib + p1 = cmp.gt(r12,r5) + p1 = !cmp.gt(r12,r4) + } + { + r13 = insert(r11,#23,#3) + r5:4 = #0 + r12 = add(r12,#-61) + } + + + + + { + r13 = add(r13,#((-3) << 3)) + } + { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASL(r7:6, # ( 14 )); r1:0 -= asl(r15:14, # 32); } + { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASR(r7:6, # ( 1 )); r1:0 -= asl(r15:14, # 32); } + { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASR(r7:6, # ( 16 )); r1:0 -= asl(r15:14, # 32); } + { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASR(r7:6, # ( 31 )); r1:0 -= asl(r15:14, # 32); r7:6=# ( 0 ); } + + + + + + + + { + + r15:14 = sub(r1:0,r3:2) + p0 = cmp.gtu(r3:2,r1:0) + + if (!p0.new) r6 = #2 + } + { + r5:4 = add(r5:4,r7:6) + if (!p0) r1:0 = r15:14 + r15:14 = #0 + } + { + p0 = cmp.eq(r1:0,r15:14) + if (!p0.new) r4 = or(r4,r28) + } + { + r7:6 = neg(r5:4) + } + { + if (!p3) r5:4 = r7:6 + } + { + r1:0 = convert_d2df(r5:4) + if (!p1) jump .Ldiv_ovf_unf + } + { + r1 += asl(r12,#52 -32) + jumpr r31 + } + +.Ldiv_ovf_unf: + { + r1 += asl(r12,#52 -32) + r13 = extractu(r1,#11,#52 -32) + } + { + r7:6 = abs(r5:4) + r12 = add(r12,r13) + } + { + p0 = cmp.gt(r12,##0x3ff +0x3ff) + if (p0.new) jump:nt .Ldiv_ovf + } + { + p0 = cmp.gt(r12,#0) + if (p0.new) jump:nt .Lpossible_unf2 + } + { + r13 = add(clb(r7:6),#-1) + r12 = sub(#7,r12) + r10 = USR + r11 = #63 + } + { + r13 = min(r12,r11) + r11 = or(r10,#0x030) + r7:6 = asl(r7:6,r13) + r12 = #0 + } + { + r15:14 = extractu(r7:6,r13:12) + r7:6 = lsr(r7:6,r13) + r3:2 = #1 + } + { + p0 = cmp.gtu(r3:2,r15:14) + if (!p0.new) r6 = or(r2,r6) + r7 = setbit(r7,#52 -32+4) + } + { + r5:4 = neg(r7:6) + p0 = bitsclr(r6,#(1<<4)-1) + if (!p0.new) r10 = r11 + } + { + USR = r10 + if (p3) r5:4 = r7:6 + r10 = #-0x3ff -(52 +4) + } + { + r1:0 = convert_d2df(r5:4) + } + { + r1 += asl(r10,#52 -32) + jumpr r31 + } + + +.Lpossible_unf2: + + + { + r3:2 = extractu(r1:0,#63,#0) + r15:14 = combine(##0x00100000,#0) + r10 = #0x7FFF + } + { + p0 = dfcmp.eq(r15:14,r3:2) + p0 = bitsset(r7,r10) + } + + + + + + + { + if (!p0) jumpr r31 + r10 = USR + } + + { + r10 = or(r10,#0x30) + } + { + USR = r10 + } + { + p0 = dfcmp.eq(r1:0,r1:0) + jumpr r31 + } + +.Ldiv_ovf: + + + + { + r10 = USR + r3:2 = combine(##0x7fefffff,#-1) + r1 = mux(p3,#0,#-1) + } + { + r7:6 = combine(##0x7ff00000,#0) + r5 = extractu(r10,#2,#22) + r10 = or(r10,#0x28) + } + { + USR = r10 + r5 ^= lsr(r1,#31) + r4 = r5 + } + { + p0 = !cmp.eq(r4,#1) + p0 = !cmp.eq(r5,#2) + if (p0.new) r3:2 = r7:6 + p0 = dfcmp.eq(r3:2,r3:2) + } + { + r1:0 = insert(r3:2,#63,#0) + jumpr r31 + } + + + + + + + +.Ldiv_abnormal: + { + p0 = dfclass(r1:0,#0x0F) + p0 = dfclass(r3:2,#0x0F) + p3 = cmp.gt(r28,#-1) + } + { + p1 = dfclass(r1:0,#0x08) + p1 = dfclass(r3:2,#0x08) + } + { + p2 = dfclass(r1:0,#0x01) + p2 = dfclass(r3:2,#0x01) + } + { + if (!p0) jump .Ldiv_nan + if (p1) jump .Ldiv_invalid + } + { + if (p2) jump .Ldiv_invalid + } + { + p2 = dfclass(r1:0,#(0x0F ^ 0x01)) + p2 = dfclass(r3:2,#(0x0F ^ 0x08)) + } + { + p1 = dfclass(r1:0,#(0x0F ^ 0x08)) + p1 = dfclass(r3:2,#(0x0F ^ 0x01)) + } + { + if (!p2) jump .Ldiv_zero_result + if (!p1) jump .Ldiv_inf_result + } + + + + + + { + p0 = dfclass(r1:0,#0x02) + p1 = dfclass(r3:2,#0x02) + r10 = ##0x00100000 + } + { + r13:12 = combine(r3,r1) + r1 = insert(r10,#11 +1,#52 -32) + r3 = insert(r10,#11 +1,#52 -32) + } + { + if (p0) r1 = or(r1,r10) + if (p1) r3 = or(r3,r10) + } + { + r5 = add(clb(r1:0),#-11) + r4 = add(clb(r3:2),#-11) + r10 = #1 + } + { + r12 = extractu(r12,#11,#52 -32) + r13 = extractu(r13,#11,#52 -32) + } + { + r1:0 = asl(r1:0,r5) + r3:2 = asl(r3:2,r4) + if (!p0) r12 = sub(r10,r5) + if (!p1) r13 = sub(r10,r4) + } + { + r7:6 = extractu(r3:2,#23,#52 -23) + } + { + r9 = or(r8,r6) + jump .Ldenorm_continue + } + +.Ldiv_zero_result: + { + r1 = xor(r1,r3) + r3:2 = #0 + } + { + r1:0 = insert(r3:2,#63,#0) + jumpr r31 + } +.Ldiv_inf_result: + { + p2 = dfclass(r3:2,#0x01) + p2 = dfclass(r1:0,#(0x0F ^ 0x08)) + } + { + r10 = USR + if (!p2) jump 1f + r1 = xor(r1,r3) + } + { + r10 = or(r10,#0x04) + } + { + USR = r10 + } +1: + { + r3:2 = combine(##0x7ff00000,#0) + p0 = dfcmp.uo(r3:2,r3:2) + } + { + r1:0 = insert(r3:2,#63,#0) + jumpr r31 + } +.Ldiv_nan: + { + p0 = dfclass(r1:0,#0x10) + p1 = dfclass(r3:2,#0x10) + if (!p0.new) r1:0 = r3:2 + if (!p1.new) r3:2 = r1:0 + } + { + r5 = convert_df2sf(r1:0) + r4 = convert_df2sf(r3:2) + } + { + r1:0 = #-1 + jumpr r31 + } + +.Ldiv_invalid: + { + r10 = ##0x7f800001 + } + { + r1:0 = convert_sf2df(r10) + jumpr r31 + } +.size __hexagon_divdf3,.-__hexagon_divdf3 diff --git a/library/compiler-builtins/src/hexagon/dffma.s b/library/compiler-builtins/src/hexagon/dffma.s new file mode 100644 index 00000000000..043a1d294a3 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/dffma.s @@ -0,0 +1,536 @@ + .text + .global __hexagon_fmadf4 + .type __hexagon_fmadf4,@function + .global __hexagon_fmadf5 + .type __hexagon_fmadf5,@function + .global fma + .type fma,@function + .global __qdsp_fmadf5 ; .set __qdsp_fmadf5, __hexagon_fmadf5 + .p2align 5 +__hexagon_fmadf4: +__hexagon_fmadf5: +fma: + { + p0 = dfclass(r1:0,#2) + p0 = dfclass(r3:2,#2) + r13:12 = #0 + r15:14 = #0 + } + { + r13:12 = insert(r1:0,#52,#11 -3) + r15:14 = insert(r3:2,#52,#11 -3) + r7 = ##0x10000000 + allocframe(#32) + } + { + r9:8 = mpyu(r12,r14) + if (!p0) jump .Lfma_abnormal_ab + r13 = or(r13,r7) + r15 = or(r15,r7) + } + { + p0 = dfclass(r5:4,#2) + if (!p0.new) jump:nt .Lfma_abnormal_c + r11:10 = combine(r7,#0) + r7:6 = combine(#0,r9) + } +.Lfma_abnormal_c_restart: + { + r7:6 += mpyu(r14,r13) + r11:10 = insert(r5:4,#52,#11 -3) + memd(r29+#0) = r17:16 + memd(r29+#8) = r19:18 + } + { + r7:6 += mpyu(r12,r15) + r19:18 = neg(r11:10) + p0 = cmp.gt(r5,#-1) + r28 = xor(r1,r3) + } + { + r18 = extractu(r1,#11,#20) + r19 = extractu(r3,#11,#20) + r17:16 = combine(#0,r7) + if (!p0) r11:10 = r19:18 + } + { + r17:16 += mpyu(r13,r15) + r9:8 = combine(r6,r8) + r18 = add(r18,r19) + + + + + r19 = extractu(r5,#11,#20) + } + { + r18 = add(r18,#-1023 +(4)) + p3 = !cmp.gt(r28,#-1) + r7:6 = #0 + r15:14 = #0 + } + { + r7:6 = sub(r7:6,r9:8,p3):carry + p0 = !cmp.gt(r28,#-1) + p1 = cmp.gt(r19,r18) + if (p1.new) r19:18 = combine(r18,r19) + } + { + r15:14 = sub(r15:14,r17:16,p3):carry + if (p0) r9:8 = r7:6 + + + + + r7:6 = #0 + r19 = sub(r18,r19) + } + { + if (p0) r17:16 = r15:14 + p0 = cmp.gt(r19,#63) + if (p1) r9:8 = r7:6 + if (p1) r7:6 = r9:8 + } + + + + + + + + { + if (p1) r17:16 = r11:10 + if (p1) r11:10 = r17:16 + if (p0) r19 = add(r19,#-64) + r28 = #63 + } + { + + if (p0) r7:6 = r11:10 + r28 = asr(r11,#31) + r13 = min(r19,r28) + r12 = #0 + } + + + + + + + { + if (p0) r11:10 = combine(r28,r28) + r5:4 = extract(r7:6,r13:12) + r7:6 = lsr(r7:6,r13) + r12 = sub(#64,r13) + } + { + r15:14 = #0 + r28 = #-2 + r7:6 |= lsl(r11:10,r12) + r11:10 = asr(r11:10,r13) + } + { + p3 = cmp.gtu(r5:4,r15:14) + if (p3.new) r6 = and(r6,r28) + + + + r15:14 = #1 + r5:4 = #0 + } + { + r9:8 = add(r7:6,r9:8,p3):carry + } + { + r17:16 = add(r11:10,r17:16,p3):carry + r28 = #62 + } + + + + + + + + { + r12 = add(clb(r17:16),#-2) + if (!cmp.eq(r12.new,r28)) jump:t 1f + } + + { + r11:10 = extractu(r9:8,#62,#2) + r9:8 = asl(r9:8,#62) + r18 = add(r18,#-62) + } + { + r17:16 = insert(r11:10,#62,#0) + } + { + r12 = add(clb(r17:16),#-2) + } + .falign +1: + { + r11:10 = asl(r17:16,r12) + r5:4 |= asl(r9:8,r12) + r13 = sub(#64,r12) + r18 = sub(r18,r12) + } + { + r11:10 |= lsr(r9:8,r13) + p2 = cmp.gtu(r15:14,r5:4) + r28 = #1023 +1023 -2 + } + { + if (!p2) r10 = or(r10,r14) + + p0 = !cmp.gt(r18,r28) + p0 = cmp.gt(r18,#1) + if (!p0.new) jump:nt .Lfma_ovf_unf + } + { + + p0 = cmp.gtu(r15:14,r11:10) + r1:0 = convert_d2df(r11:10) + r18 = add(r18,#-1023 -60) + r17:16 = memd(r29+#0) + } + { + r1 += asl(r18,#20) + r19:18 = memd(r29+#8) + if (!p0) dealloc_return + } +.Ladd_yields_zero: + + { + r28 = USR + r1:0 = #0 + } + { + r28 = extractu(r28,#2,#22) + r17:16 = memd(r29+#0) + r19:18 = memd(r29+#8) + } + { + p0 = cmp.eq(r28,#2) + if (p0.new) r1 = ##0x80000000 + dealloc_return + } +.Lfma_ovf_unf: + { + p0 = cmp.gtu(r15:14,r11:10) + if (p0.new) jump:nt .Ladd_yields_zero + } + { + r1:0 = convert_d2df(r11:10) + r18 = add(r18,#-1023 -60) + r28 = r18 + } + + + { + r1 += asl(r18,#20) + r7 = extractu(r1,#11,#20) + } + { + r6 = add(r18,r7) + r17:16 = memd(r29+#0) + r19:18 = memd(r29+#8) + r9:8 = abs(r11:10) + } + { + p0 = cmp.gt(r6,##1023 +1023) + if (p0.new) jump:nt .Lfma_ovf + } + { + p0 = cmp.gt(r6,#0) + if (p0.new) jump:nt .Lpossible_unf0 + } + { + + + + r7 = add(clb(r9:8),#-2) + r6 = sub(#1+5,r28) + p3 = cmp.gt(r11,#-1) + } + + + + { + r6 = add(r6,r7) + r9:8 = asl(r9:8,r7) + r1 = USR + r28 = #63 + } + { + r7 = min(r6,r28) + r6 = #0 + r0 = #0x0030 + } + { + r3:2 = extractu(r9:8,r7:6) + r9:8 = asr(r9:8,r7) + } + { + p0 = cmp.gtu(r15:14,r3:2) + if (!p0.new) r8 = or(r8,r14) + r9 = setbit(r9,#20 +3) + } + { + r11:10 = neg(r9:8) + p1 = bitsclr(r8,#(1<<3)-1) + if (!p1.new) r1 = or(r1,r0) + r3:2 = #0 + } + { + if (p3) r11:10 = r9:8 + USR = r1 + r28 = #-1023 -(52 +3) + } + { + r1:0 = convert_d2df(r11:10) + } + { + r1 += asl(r28,#20) + dealloc_return + } +.Lpossible_unf0: + { + r28 = ##0x7fefffff + r9:8 = abs(r11:10) + } + { + p0 = cmp.eq(r0,#0) + p0 = bitsclr(r1,r28) + if (!p0.new) dealloc_return:t + r28 = #0x7fff + } + { + p0 = bitsset(r9,r28) + r3 = USR + r2 = #0x0030 + } + { + if (p0) r3 = or(r3,r2) + } + { + USR = r3 + } + { + p0 = dfcmp.eq(r1:0,r1:0) + dealloc_return + } +.Lfma_ovf: + { + r28 = USR + r11:10 = combine(##0x7fefffff,#-1) + r1:0 = r11:10 + } + { + r9:8 = combine(##0x7ff00000,#0) + r3 = extractu(r28,#2,#22) + r28 = or(r28,#0x28) + } + { + USR = r28 + r3 ^= lsr(r1,#31) + r2 = r3 + } + { + p0 = !cmp.eq(r2,#1) + p0 = !cmp.eq(r3,#2) + } + { + p0 = dfcmp.eq(r9:8,r9:8) + if (p0.new) r11:10 = r9:8 + } + { + r1:0 = insert(r11:10,#63,#0) + dealloc_return + } +.Lfma_abnormal_ab: + { + r9:8 = extractu(r1:0,#63,#0) + r11:10 = extractu(r3:2,#63,#0) + deallocframe + } + { + p3 = cmp.gtu(r9:8,r11:10) + if (!p3.new) r1:0 = r3:2 + if (!p3.new) r3:2 = r1:0 + } + { + p0 = dfclass(r1:0,#0x0f) + if (!p0.new) jump:nt .Lnan + if (!p3) r9:8 = r11:10 + if (!p3) r11:10 = r9:8 + } + { + p1 = dfclass(r1:0,#0x08) + p1 = dfclass(r3:2,#0x0e) + } + { + p0 = dfclass(r1:0,#0x08) + p0 = dfclass(r3:2,#0x01) + } + { + if (p1) jump .Lab_inf + p2 = dfclass(r3:2,#0x01) + } + { + if (p0) jump .Linvalid + if (p2) jump .Lab_true_zero + r28 = ##0x7c000000 + } + + + + + + { + p0 = bitsclr(r1,r28) + if (p0.new) jump:nt .Lfma_ab_tiny + } + { + r28 = add(clb(r11:10),#-11) + } + { + r11:10 = asl(r11:10,r28) + } + { + r3:2 = insert(r11:10,#63,#0) + r1 -= asl(r28,#20) + } + jump fma + +.Lfma_ab_tiny: + r9:8 = combine(##0x00100000,#0) + { + r1:0 = insert(r9:8,#63,#0) + r3:2 = insert(r9:8,#63,#0) + } + jump fma + +.Lab_inf: + { + r3:2 = lsr(r3:2,#63) + p0 = dfclass(r5:4,#0x10) + } + { + r1:0 ^= asl(r3:2,#63) + if (p0) jump .Lnan + } + { + p1 = dfclass(r5:4,#0x08) + if (p1.new) jump:nt .Lfma_inf_plus_inf + } + + { + jumpr r31 + } + .falign +.Lfma_inf_plus_inf: + { + p0 = dfcmp.eq(r1:0,r5:4) + if (!p0.new) jump:nt .Linvalid + } + { + jumpr r31 + } + +.Lnan: + { + p0 = dfclass(r3:2,#0x10) + p1 = dfclass(r5:4,#0x10) + if (!p0.new) r3:2 = r1:0 + if (!p1.new) r5:4 = r1:0 + } + { + r3 = convert_df2sf(r3:2) + r2 = convert_df2sf(r5:4) + } + { + r3 = convert_df2sf(r1:0) + r1:0 = #-1 + jumpr r31 + } + +.Linvalid: + { + r28 = ##0x7f800001 + } + { + r1:0 = convert_sf2df(r28) + jumpr r31 + } + +.Lab_true_zero: + + { + p0 = dfclass(r5:4,#0x10) + if (p0.new) jump:nt .Lnan + if (p0.new) r1:0 = r5:4 + } + { + p0 = dfcmp.eq(r3:2,r5:4) + r1 = lsr(r1,#31) + } + { + r3 ^= asl(r1,#31) + if (!p0) r1:0 = r5:4 + if (!p0) jumpr r31 + } + + { + p0 = cmp.eq(r3:2,r5:4) + if (p0.new) jumpr:t r31 + r1:0 = r3:2 + } + { + r28 = USR + } + { + r28 = extractu(r28,#2,#22) + r1:0 = #0 + } + { + p0 = cmp.eq(r28,#2) + if (p0.new) r1 = ##0x80000000 + jumpr r31 + } + + + + + .falign +.Lfma_abnormal_c: + + + { + p0 = dfclass(r5:4,#0x10) + if (p0.new) jump:nt .Lnan + if (p0.new) r1:0 = r5:4 + deallocframe + } + { + p0 = dfclass(r5:4,#0x08) + if (p0.new) r1:0 = r5:4 + if (p0.new) jumpr:nt r31 + } + + + { + p0 = dfclass(r5:4,#0x01) + if (p0.new) jump:nt __hexagon_muldf3 + r28 = #1 + } + + + { + allocframe(#32) + r11:10 = #0 + r5 = insert(r28,#11,#20) + jump .Lfma_abnormal_c_restart + } +.size fma,.-fma diff --git a/library/compiler-builtins/src/hexagon/dfminmax.s b/library/compiler-builtins/src/hexagon/dfminmax.s new file mode 100644 index 00000000000..3337a3223ec --- /dev/null +++ b/library/compiler-builtins/src/hexagon/dfminmax.s @@ -0,0 +1,51 @@ + .text + .global __hexagon_mindf3 + .global __hexagon_maxdf3 + .global fmin + .type fmin,@function + .global fmax + .type fmax,@function + .type __hexagon_mindf3,@function + .type __hexagon_maxdf3,@function + .global __qdsp_mindf3 ; .set __qdsp_mindf3, __hexagon_mindf3 + .global __qdsp_maxdf3 ; .set __qdsp_maxdf3, __hexagon_maxdf3 + .p2align 5 +__hexagon_mindf3: +fmin: + { + p0 = dfclass(r1:0,#0x10) + p1 = dfcmp.gt(r1:0,r3:2) + r5:4 = r1:0 + } + { + if (p0) r1:0 = r3:2 + if (p1) r1:0 = r3:2 + p2 = dfcmp.eq(r1:0,r3:2) + if (!p2.new) jumpr:t r31 + } + + { + r1:0 = or(r5:4,r3:2) + jumpr r31 + } +.size __hexagon_mindf3,.-__hexagon_mindf3 + .falign +__hexagon_maxdf3: +fmax: + { + p0 = dfclass(r1:0,#0x10) + p1 = dfcmp.gt(r3:2,r1:0) + r5:4 = r1:0 + } + { + if (p0) r1:0 = r3:2 + if (p1) r1:0 = r3:2 + p2 = dfcmp.eq(r1:0,r3:2) + if (!p2.new) jumpr:t r31 + } + + { + r1:0 = and(r5:4,r3:2) + jumpr r31 + } +.size __hexagon_maxdf3,.-__hexagon_maxdf3 diff --git a/library/compiler-builtins/src/hexagon/dfmul.s b/library/compiler-builtins/src/hexagon/dfmul.s new file mode 100644 index 00000000000..32fc674f975 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/dfmul.s @@ -0,0 +1,309 @@ + .text + .global __hexagon_muldf3 + .type __hexagon_muldf3,@function + .global __qdsp_muldf3 ; .set __qdsp_muldf3, __hexagon_muldf3 + .global __hexagon_fast_muldf3 ; .set __hexagon_fast_muldf3, __hexagon_muldf3 + .global __hexagon_fast2_muldf3 ; .set __hexagon_fast2_muldf3, __hexagon_muldf3 + .p2align 5 +__hexagon_muldf3: + { + p0 = dfclass(r1:0,#2) + p0 = dfclass(r3:2,#2) + r13:12 = combine(##0x40000000,#0) + } + { + r13:12 = insert(r1:0,#52,#11 -1) + r5:4 = asl(r3:2,#11 -1) + r28 = #-1024 + r9:8 = #1 + } + { + r7:6 = mpyu(r4,r13) + r5:4 = insert(r9:8,#2,#62) + } + + + + + { + r15:14 = mpyu(r12,r4) + r7:6 += mpyu(r12,r5) + } + { + r7:6 += lsr(r15:14,#32) + r11:10 = mpyu(r13,r5) + r5:4 = combine(##1024 +1024 -4,#0) + } + { + r11:10 += lsr(r7:6,#32) + if (!p0) jump .Lmul_abnormal + p1 = cmp.eq(r14,#0) + p1 = cmp.eq(r6,#0) + } + { + if (!p1) r10 = or(r10,r8) + r6 = extractu(r1,#11,#20) + r7 = extractu(r3,#11,#20) + } + { + r15:14 = neg(r11:10) + r6 += add(r28,r7) + r28 = xor(r1,r3) + } + { + if (!p2.new) r11:10 = r15:14 + p2 = cmp.gt(r28,#-1) + p0 = !cmp.gt(r6,r5) + p0 = cmp.gt(r6,r4) + if (!p0.new) jump:nt .Lmul_ovf_unf + } + { + r1:0 = convert_d2df(r11:10) + r6 = add(r6,#-1024 -58) + } + { + r1 += asl(r6,#20) + jumpr r31 + } + + .falign +.Lpossible_unf1: + { + p0 = cmp.eq(r0,#0) + p0 = bitsclr(r1,r4) + if (!p0.new) jumpr:t r31 + r5 = #0x7fff + } + { + p0 = bitsset(r13,r5) + r4 = USR + r5 = #0x030 + } + { + if (p0) r4 = or(r4,r5) + } + { + USR = r4 + } + { + p0 = dfcmp.eq(r1:0,r1:0) + jumpr r31 + } + .falign +.Lmul_ovf_unf: + { + r1:0 = convert_d2df(r11:10) + r13:12 = abs(r11:10) + r7 = add(r6,#-1024 -58) + } + { + r1 += asl(r7,#20) + r7 = extractu(r1,#11,#20) + r4 = ##0x7FEFFFFF + } + { + r7 += add(r6,##-1024 -58) + + r5 = #0 + } + { + p0 = cmp.gt(r7,##1024 +1024 -2) + if (p0.new) jump:nt .Lmul_ovf + } + { + p0 = cmp.gt(r7,#0) + if (p0.new) jump:nt .Lpossible_unf1 + r5 = sub(r6,r5) + r28 = #63 + } + { + r4 = #0 + r5 = sub(#5,r5) + } + { + p3 = cmp.gt(r11,#-1) + r5 = min(r5,r28) + r11:10 = r13:12 + } + { + r28 = USR + r15:14 = extractu(r11:10,r5:4) + } + { + r11:10 = asr(r11:10,r5) + r4 = #0x0030 + r1 = insert(r9,#11,#20) + } + { + p0 = cmp.gtu(r9:8,r15:14) + if (!p0.new) r10 = or(r10,r8) + r11 = setbit(r11,#20 +3) + } + { + r15:14 = neg(r11:10) + p1 = bitsclr(r10,#0x7) + if (!p1.new) r28 = or(r4,r28) + } + { + if (!p3) r11:10 = r15:14 + USR = r28 + } + { + r1:0 = convert_d2df(r11:10) + p0 = dfcmp.eq(r1:0,r1:0) + } + { + r1 = insert(r9,#11 -1,#20 +1) + jumpr r31 + } + .falign +.Lmul_ovf: + + { + r28 = USR + r13:12 = combine(##0x7fefffff,#-1) + r1:0 = r11:10 + } + { + r14 = extractu(r28,#2,#22) + r28 = or(r28,#0x28) + r5:4 = combine(##0x7ff00000,#0) + } + { + USR = r28 + r14 ^= lsr(r1,#31) + r28 = r14 + } + { + p0 = !cmp.eq(r28,#1) + p0 = !cmp.eq(r14,#2) + if (p0.new) r13:12 = r5:4 + p0 = dfcmp.eq(r1:0,r1:0) + } + { + r1:0 = insert(r13:12,#63,#0) + jumpr r31 + } + +.Lmul_abnormal: + { + r13:12 = extractu(r1:0,#63,#0) + r5:4 = extractu(r3:2,#63,#0) + } + { + p3 = cmp.gtu(r13:12,r5:4) + if (!p3.new) r1:0 = r3:2 + if (!p3.new) r3:2 = r1:0 + } + { + + p0 = dfclass(r1:0,#0x0f) + if (!p0.new) jump:nt .Linvalid_nan + if (!p3) r13:12 = r5:4 + if (!p3) r5:4 = r13:12 + } + { + + p1 = dfclass(r1:0,#0x08) + p1 = dfclass(r3:2,#0x0e) + } + { + + + p0 = dfclass(r1:0,#0x08) + p0 = dfclass(r3:2,#0x01) + } + { + if (p1) jump .Ltrue_inf + p2 = dfclass(r3:2,#0x01) + } + { + if (p0) jump .Linvalid_zeroinf + if (p2) jump .Ltrue_zero + r28 = ##0x7c000000 + } + + + + + + { + p0 = bitsclr(r1,r28) + if (p0.new) jump:nt .Lmul_tiny + } + { + r28 = cl0(r5:4) + } + { + r28 = add(r28,#-11) + } + { + r5:4 = asl(r5:4,r28) + } + { + r3:2 = insert(r5:4,#63,#0) + r1 -= asl(r28,#20) + } + jump __hexagon_muldf3 +.Lmul_tiny: + { + r28 = USR + r1:0 = xor(r1:0,r3:2) + } + { + r28 = or(r28,#0x30) + r1:0 = insert(r9:8,#63,#0) + r5 = extractu(r28,#2,#22) + } + { + USR = r28 + p0 = cmp.gt(r5,#1) + if (!p0.new) r0 = #0 + r5 ^= lsr(r1,#31) + } + { + p0 = cmp.eq(r5,#3) + if (!p0.new) r0 = #0 + jumpr r31 + } +.Linvalid_zeroinf: + { + r28 = USR + } + { + r1:0 = #-1 + r28 = or(r28,#2) + } + { + USR = r28 + } + { + p0 = dfcmp.uo(r1:0,r1:0) + jumpr r31 + } +.Linvalid_nan: + { + p0 = dfclass(r3:2,#0x0f) + r28 = convert_df2sf(r1:0) + if (p0.new) r3:2 = r1:0 + } + { + r2 = convert_df2sf(r3:2) + r1:0 = #-1 + jumpr r31 + } + .falign +.Ltrue_zero: + { + r1:0 = r3:2 + r3:2 = r1:0 + } +.Ltrue_inf: + { + r3 = extract(r3,#1,#31) + } + { + r1 ^= asl(r3,#31) + jumpr r31 + } +.size __hexagon_muldf3,.-__hexagon_muldf3 diff --git a/library/compiler-builtins/src/hexagon/dfsqrt.s b/library/compiler-builtins/src/hexagon/dfsqrt.s new file mode 100644 index 00000000000..14f584a1133 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/dfsqrt.s @@ -0,0 +1,277 @@ + .text + .global __hexagon_sqrtdf2 + .type __hexagon_sqrtdf2,@function + .global __hexagon_sqrt + .type __hexagon_sqrt,@function + .global __qdsp_sqrtdf2 ; .set __qdsp_sqrtdf2, __hexagon_sqrtdf2; .type __qdsp_sqrtdf2,@function + .global __qdsp_sqrt ; .set __qdsp_sqrt, __hexagon_sqrt; .type __qdsp_sqrt,@function + .global __hexagon_fast_sqrtdf2 ; .set __hexagon_fast_sqrtdf2, __hexagon_sqrtdf2; .type __hexagon_fast_sqrtdf2,@function + .global __hexagon_fast_sqrt ; .set __hexagon_fast_sqrt, __hexagon_sqrt; .type __hexagon_fast_sqrt,@function + .global __hexagon_fast2_sqrtdf2 ; .set __hexagon_fast2_sqrtdf2, __hexagon_sqrtdf2; .type __hexagon_fast2_sqrtdf2,@function + .global __hexagon_fast2_sqrt ; .set __hexagon_fast2_sqrt, __hexagon_sqrt; .type __hexagon_fast2_sqrt,@function + .type sqrt,@function + .p2align 5 +__hexagon_sqrtdf2: +__hexagon_sqrt: + { + r15:14 = extractu(r1:0,#23 +1,#52 -23) + r28 = extractu(r1,#11,#52 -32) + r5:4 = combine(##0x3f000004,#1) + } + { + p2 = dfclass(r1:0,#0x02) + p2 = cmp.gt(r1,#-1) + if (!p2.new) jump:nt .Lsqrt_abnormal + r9 = or(r5,r14) + } + +.Ldenormal_restart: + { + r11:10 = r1:0 + r7,p0 = sfinvsqrta(r9) + r5 = and(r5,#-16) + r3:2 = #0 + } + { + r3 += sfmpy(r7,r9):lib + r2 += sfmpy(r7,r5):lib + r6 = r5 + + + r9 = and(r28,#1) + } + { + r6 -= sfmpy(r3,r2):lib + r11 = insert(r4,#11 +1,#52 -32) + p1 = cmp.gtu(r9,#0) + } + { + r3 += sfmpy(r3,r6):lib + r2 += sfmpy(r2,r6):lib + r6 = r5 + r9 = mux(p1,#8,#9) + } + { + r6 -= sfmpy(r3,r2):lib + r11:10 = asl(r11:10,r9) + r9 = mux(p1,#3,#2) + } + { + r2 += sfmpy(r2,r6):lib + + r15:14 = asl(r11:10,r9) + } + { + r2 = and(r2,##0x007fffff) + } + { + r2 = add(r2,##0x00800000 - 3) + r9 = mux(p1,#7,#8) + } + { + r8 = asl(r2,r9) + r9 = mux(p1,#15-(1+1),#15-(1+0)) + } + { + r13:12 = mpyu(r8,r15) + } + { + r1:0 = asl(r11:10,#15) + r15:14 = mpyu(r13,r13) + p1 = cmp.eq(r0,r0) + } + { + r1:0 -= asl(r15:14,#15) + r15:14 = mpyu(r13,r12) + p2 = cmp.eq(r0,r0) + } + { + r1:0 -= lsr(r15:14,#16) + p3 = cmp.eq(r0,r0) + } + { + r1:0 = mpyu(r1,r8) + } + { + r13:12 += lsr(r1:0,r9) + r9 = add(r9,#16) + r1:0 = asl(r11:10,#31) + } + + { + r15:14 = mpyu(r13,r13) + r1:0 -= mpyu(r13,r12) + } + { + r1:0 -= asl(r15:14,#31) + r15:14 = mpyu(r12,r12) + } + { + r1:0 -= lsr(r15:14,#33) + } + { + r1:0 = mpyu(r1,r8) + } + { + r13:12 += lsr(r1:0,r9) + r9 = add(r9,#16) + r1:0 = asl(r11:10,#47) + } + + { + r15:14 = mpyu(r13,r13) + } + { + r1:0 -= asl(r15:14,#47) + r15:14 = mpyu(r13,r12) + } + { + r1:0 -= asl(r15:14,#16) + r15:14 = mpyu(r12,r12) + } + { + r1:0 -= lsr(r15:14,#17) + } + { + r1:0 = mpyu(r1,r8) + } + { + r13:12 += lsr(r1:0,r9) + } + { + r3:2 = mpyu(r13,r12) + r5:4 = mpyu(r12,r12) + r15:14 = #0 + r1:0 = #0 + } + { + r3:2 += lsr(r5:4,#33) + r5:4 += asl(r3:2,#33) + p1 = cmp.eq(r0,r0) + } + { + r7:6 = mpyu(r13,r13) + r1:0 = sub(r1:0,r5:4,p1):carry + r9:8 = #1 + } + { + r7:6 += lsr(r3:2,#31) + r9:8 += asl(r13:12,#1) + } + + + + + + { + r15:14 = sub(r11:10,r7:6,p1):carry + r5:4 = sub(r1:0,r9:8,p2):carry + + + + + r7:6 = #1 + r11:10 = #0 + } + { + r3:2 = sub(r15:14,r11:10,p2):carry + r7:6 = add(r13:12,r7:6) + r28 = add(r28,#-0x3ff) + } + { + + if (p2) r13:12 = r7:6 + if (p2) r1:0 = r5:4 + if (p2) r15:14 = r3:2 + } + { + r5:4 = sub(r1:0,r9:8,p3):carry + r7:6 = #1 + r28 = asr(r28,#1) + } + { + r3:2 = sub(r15:14,r11:10,p3):carry + r7:6 = add(r13:12,r7:6) + } + { + if (p3) r13:12 = r7:6 + if (p3) r1:0 = r5:4 + + + + + + r2 = #1 + } + { + p0 = cmp.eq(r1:0,r11:10) + if (!p0.new) r12 = or(r12,r2) + r3 = cl0(r13:12) + r28 = add(r28,#-63) + } + + + + { + r1:0 = convert_ud2df(r13:12) + r28 = add(r28,r3) + } + { + r1 += asl(r28,#52 -32) + jumpr r31 + } +.Lsqrt_abnormal: + { + p0 = dfclass(r1:0,#0x01) + if (p0.new) jumpr:t r31 + } + { + p0 = dfclass(r1:0,#0x10) + if (p0.new) jump:nt .Lsqrt_nan + } + { + p0 = cmp.gt(r1,#-1) + if (!p0.new) jump:nt .Lsqrt_invalid_neg + if (!p0.new) r28 = ##0x7F800001 + } + { + p0 = dfclass(r1:0,#0x08) + if (p0.new) jumpr:nt r31 + } + + + { + r1:0 = extractu(r1:0,#52,#0) + } + { + r28 = add(clb(r1:0),#-11) + } + { + r1:0 = asl(r1:0,r28) + r28 = sub(#1,r28) + } + { + r1 = insert(r28,#1,#52 -32) + } + { + r3:2 = extractu(r1:0,#23 +1,#52 -23) + r5 = ##0x3f000004 + } + { + r9 = or(r5,r2) + r5 = and(r5,#-16) + jump .Ldenormal_restart + } +.Lsqrt_nan: + { + r28 = convert_df2sf(r1:0) + r1:0 = #-1 + jumpr r31 + } +.Lsqrt_invalid_neg: + { + r1:0 = convert_sf2df(r28) + jumpr r31 + } +.size __hexagon_sqrt,.-__hexagon_sqrt +.size __hexagon_sqrtdf2,.-__hexagon_sqrtdf2 diff --git a/library/compiler-builtins/src/hexagon/divdi3.s b/library/compiler-builtins/src/hexagon/divdi3.s new file mode 100644 index 00000000000..0fee6e70f06 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/divdi3.s @@ -0,0 +1,64 @@ + +FUNCTION_BEGIN __hexagon_divdi3 + { + p2 = tstbit(r1,#31) + p3 = tstbit(r3,#31) + } + { + r1:0 = abs(r1:0) + r3:2 = abs(r3:2) + } + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + p3 = xor(p2,p3) + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jump .hexagon_divdi3_return + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + +.hexagon_divdi3_return: + { + r3:2 = neg(r1:0) + } + { + r1:0 = vmux(p3,r3:2,r1:0) + jumpr r31 + } +FUNCTION_END __hexagon_divdi3 + + .globl __qdsp_divdi3 + .set __qdsp_divdi3, __hexagon_divdi3 diff --git a/library/compiler-builtins/src/hexagon/divsi3.s b/library/compiler-builtins/src/hexagon/divsi3.s new file mode 100644 index 00000000000..fc957a43146 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/divsi3.s @@ -0,0 +1,53 @@ + +FUNCTION_BEGIN __hexagon_divsi3 + { + p0 = cmp.ge(r0,#0) + p1 = cmp.ge(r1,#0) + r1 = abs(r0) + r2 = abs(r1) + } + { + r3 = cl0(r1) + r4 = cl0(r2) + r5 = sub(r1,r2) + p2 = cmp.gtu(r2,r1) + } + { + r0 = #0 + p1 = xor(p0,p1) + p0 = cmp.gtu(r2,r5) + if (p2) jumpr r31 + } + + { + r0 = mux(p1,#-1,#1) + if (p0) jumpr r31 + r4 = sub(r4,r3) + r3 = #1 + } + { + r0 = #0 + r3:2 = vlslw(r3:2,r4) + loop0(1f,r4) + } + .falign +1: + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r1 = sub(r1,r2) + if (!p0.new) r0 = add(r0,r3) + r3:2 = vlsrw(r3:2,#1) + }:endloop0 + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r0 = add(r0,r3) + if (!p1) jumpr r31 + } + { + r0 = neg(r0) + jumpr r31 + } +FUNCTION_END __hexagon_divsi3 + + .globl __qdsp_divsi3 + .set __qdsp_divsi3, __hexagon_divsi3 diff --git a/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s b/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s new file mode 100644 index 00000000000..15c387846fa --- /dev/null +++ b/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s @@ -0,0 +1,266 @@ + .text + .global fast2_dadd_asm + .type fast2_dadd_asm, @function +fast2_dadd_asm: + .falign + { + R7:6 = VABSDIFFH(R1:0, R3:2) + R9 = #62 + R4 = SXTH(R0) + R5 = SXTH(R2) + } { + R6 = SXTH(R6) + P0 = CMP.GT(R4, R5); + if ( P0.new) R8 = add(R4, #1) + if (!P0.new) R8 = add(R5, #1) + } { + if ( P0) R4 = #1 + if (!P0) R5 = #1 + R0.L = #0 + R6 = MIN(R6, R9) + } { + if (!P0) R4 = add(R6, #1) + if ( P0) R5 = add(R6, #1) + R2.L = #0 + R11:10 = #0 + } { + R1:0 = ASR(R1:0, R4) + R3:2 = ASR(R3:2, R5) + } { + R1:0 = add(R1:0, R3:2) + R10.L = #0x8001 + } { + R4 = clb(R1:0) + R9 = #58 + } { + R4 = add(R4, #-1) + p0 = cmp.gt(R4, R9) + } { + R1:0 = ASL(R1:0, R4) + R8 = SUB(R8, R4) + if(p0) jump .Ldenorma + } { + R0 = insert(R8, #16, #0) + jumpr r31 + } +.Ldenorma: + { + R1:0 = R11:10 + jumpr r31 + } + .text + .global fast2_dsub_asm + .type fast2_dsub_asm, @function +fast2_dsub_asm: + .falign + { + R7:6 = VABSDIFFH(R1:0, R3:2) + R9 = #62 + R4 = SXTH(R0) + R5 = SXTH(R2) + } { + R6 = SXTH(R6) + P0 = CMP.GT(R4, R5); + if ( P0.new) R8 = add(R4, #1) + if (!P0.new) R8 = add(R5, #1) + } { + if ( P0) R4 = #1 + if (!P0) R5 = #1 + R0.L = #0 + R6 = MIN(R6, R9) + } { + if (!P0) R4 = add(R6, #1) + if ( P0) R5 = add(R6, #1) + R2.L = #0 + R11:10 = #0 + } { + R1:0 = ASR(R1:0, R4) + R3:2 = ASR(R3:2, R5) + } { + R1:0 = sub(R1:0, R3:2) + R10.L = #0x8001 + } { + R4 = clb(R1:0) + R9 = #58 + } { + R4 = add(R4, #-1) + p0 = cmp.gt(R4, R9) + } { + R1:0 = ASL(R1:0, R4) + R8 = SUB(R8, R4) + if(p0) jump .Ldenorm + } { + R0 = insert(R8, #16, #0) + jumpr r31 + } +.Ldenorm: + { + R1:0 = R11:10 + jumpr r31 + } + .text + .global fast2_dmpy_asm + .type fast2_dmpy_asm, @function +fast2_dmpy_asm: + .falign + { + R13= lsr(R2, #16) + R5 = sxth(R2) + R4 = sxth(R0) + R12= lsr(R0, #16) + } + { + R11:10 = mpy(R1, R3) + R7:6 = mpy(R1, R13) + R0.L = #0x0 + R15:14 = #0 + } + { + R11:10 = add(R11:10, R11:10) + R7:6 += mpy(R3, R12) + R2.L = #0x0 + R15.H = #0x8000 + } + { + R7:6 = asr(R7:6, #15) + R12.L = #0x8001 + p1 = cmp.eq(R1:0, R3:2) + } + { + R7:6 = add(R7:6, R11:10) + R8 = add(R4, R5) + p2 = cmp.eq(R1:0, R15:14) + } + { + R9 = clb(R7:6) + R3:2 = abs(R7:6) + R11 = #58 + } + { + p1 = and(p1, p2) + R8 = sub(R8, R9) + R9 = add(R9, #-1) + p0 = cmp.gt(R9, R11) + } + { + R8 = add(R8, #1) + R1:0 = asl(R7:6, R9) + if(p1) jump .Lsat + } + { + R0 = insert(R8,#16, #0) + if(!p0) jumpr r31 + } + { + R0 = insert(R12,#16, #0) + jumpr r31 + } +.Lsat: + { + R1:0 = #-1 + } + { + R1:0 = lsr(R1:0, #1) + } + { + R0 = insert(R8,#16, #0) + jumpr r31 + } + .text + .global fast2_qd2f_asm + .type fast2_qd2f_asm, @function +fast2_qd2f_asm: + .falign + { + R3 = abs(R1):sat + R4 = sxth(R0) + R5 = #0x40 + R6.L = #0xffc0 + } + { + R0 = extractu(R3, #8, #0) + p2 = cmp.gt(R4, #126) + p3 = cmp.ge(R4, #-126) + R6.H = #0x7fff + } + { + p1 = cmp.eq(R0,#0x40) + if(p1.new) R5 = #0 + R4 = add(R4, #126) + if(!p3) jump .Lmin + } + { + p0 = bitsset(R3, R6) + R0.L = #0x0000 + R2 = add(R3, R5) + R7 = lsr(R6, #8) + } + { + if(p0) R4 = add(R4, #1) + if(p0) R3 = #0 + R2 = lsr(R2, #7) + R0.H = #0x8000 + } + { + R0 = and(R0, R1) + R6 &= asl(R4, #23) + if(!p0) R3 = and(R2, R7) + if(p2) jump .Lmax + } + { + R0 += add(R6, R3) + jumpr r31 + } +.Lmax: + { + R0.L = #0xffff; + } + { + R0.H = #0x7f7f; + jumpr r31 + } +.Lmin: + { + R0 = #0x0 + jumpr r31 + } + .text + .global fast2_f2qd_asm + .type fast2_f2qd_asm, @function +fast2_f2qd_asm: + + + + + + + + .falign + { + R1 = asl(R0, #7) + p0 = tstbit(R0, #31) + R5:4 = #0 + R3 = add(R0,R0) + } + { + R1 = setbit(R1, #30) + R0= extractu(R0,#8,#23) + R4.L = #0x8001 + p1 = cmp.eq(R3, #0) + } + { + R1= extractu(R1, #31, #0) + R0= add(R0, #-126) + R2 = #0 + if(p1) jump .Lminqd + } + { + R0 = zxth(R0) + if(p0) R1= sub(R2, R1) + jumpr r31 + } +.Lminqd: + { + R1:0 = R5:4 + jumpr r31 + } diff --git a/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s b/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s new file mode 100644 index 00000000000..b72b7550afc --- /dev/null +++ b/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s @@ -0,0 +1,187 @@ + .text + .global fast2_ldadd_asm + .type fast2_ldadd_asm, @function +fast2_ldadd_asm: + .falign + { + R4 = memw(r29+#8) + R5 = memw(r29+#24) + r7 = r0 + } + { + R6 = sub(R4, R5):sat + P0 = CMP.GT(R4, R5); + if ( P0.new) R8 = add(R4, #1) + if (!P0.new) R8 = add(R5, #1) + } { + R6 = abs(R6):sat + if ( P0) R4 = #1 + if (!P0) R5 = #1 + R9 = #62 + } { + R6 = MIN(R6, R9) + R1:0 = memd(r29+#0) + R3:2 = memd(r29+#16) + } { + if (!P0) R4 = add(R6, #1) + if ( P0) R5 = add(R6, #1) + } { + R1:0 = ASR(R1:0, R4) + R3:2 = ASR(R3:2, R5) + } { + R1:0 = add(R1:0, R3:2) + R3:2 = #0 + } { + R4 = clb(R1:0) + R9.L =#0x0001 + } { + R8 -= add(R4, #-1) + R4 = add(R4, #-1) + p0 = cmp.gt(R4, #58) + R9.H =#0x8000 + } { + if(!p0)memw(r7+#8) = R8 + R1:0 = ASL(R1:0, R4) + if(p0) jump .Ldenorma1 + } { + memd(r7+#0) = R1:0 + jumpr r31 + } +.Ldenorma1: + memd(r7+#0) = R3:2 + { + memw(r7+#8) = R9 + jumpr r31 + } + .text + .global fast2_ldsub_asm + .type fast2_ldsub_asm, @function +fast2_ldsub_asm: + .falign + { + R4 = memw(r29+#8) + R5 = memw(r29+#24) + r7 = r0 + } + { + R6 = sub(R4, R5):sat + P0 = CMP.GT(R4, R5); + if ( P0.new) R8 = add(R4, #1) + if (!P0.new) R8 = add(R5, #1) + } { + R6 = abs(R6):sat + if ( P0) R4 = #1 + if (!P0) R5 = #1 + R9 = #62 + } { + R6 = min(R6, R9) + R1:0 = memd(r29+#0) + R3:2 = memd(r29+#16) + } { + if (!P0) R4 = add(R6, #1) + if ( P0) R5 = add(R6, #1) + } { + R1:0 = ASR(R1:0, R4) + R3:2 = ASR(R3:2, R5) + } { + R1:0 = sub(R1:0, R3:2) + R3:2 = #0 + } { + R4 = clb(R1:0) + R9.L =#0x0001 + } { + R8 -= add(R4, #-1) + R4 = add(R4, #-1) + p0 = cmp.gt(R4, #58) + R9.H =#0x8000 + } { + if(!p0)memw(r7+#8) = R8 + R1:0 = asl(R1:0, R4) + if(p0) jump .Ldenorma_s + } { + memd(r7+#0) = R1:0 + jumpr r31 + } +.Ldenorma_s: + memd(r7+#0) = R3:2 + { + memw(r7+#8) = R9 + jumpr r31 + } + .text + .global fast2_ldmpy_asm + .type fast2_ldmpy_asm, @function +fast2_ldmpy_asm: + .falign + { + R15:14 = memd(r29+#0) + R3:2 = memd(r29+#16) + R13:12 = #0 + } + { + R8= extractu(R2, #31, #1) + R9= extractu(R14, #31, #1) + R13.H = #0x8000 + } + { + R11:10 = mpy(R15, R3) + R7:6 = mpy(R15, R8) + R4 = memw(r29+#8) + R5 = memw(r29+#24) + } + { + R11:10 = add(R11:10, R11:10) + R7:6 += mpy(R3, R9) + } + { + R7:6 = asr(R7:6, #30) + R8.L = #0x0001 + p1 = cmp.eq(R15:14, R3:2) + } + { + R7:6 = add(R7:6, R11:10) + R4= add(R4, R5) + p2 = cmp.eq(R3:2, R13:12) + } + { + R9 = clb(R7:6) + R8.H = #0x8000 + p1 = and(p1, p2) + } + { + R4-= add(R9, #-1) + R9 = add(R9, #-1) + if(p1) jump .Lsat1 + } + { + R7:6 = asl(R7:6, R9) + memw(R0+#8) = R4 + p0 = cmp.gt(R9, #58) + if(p0.new) jump:NT .Ldenorm1 + } + { + memd(R0+#0) = R7:6 + jumpr r31 + } +.Lsat1: + { + R13:12 = #0 + R4+= add(R9, #1) + } + { + R13.H = #0x4000 + memw(R0+#8) = R4 + } + { + memd(R0+#0) = R13:12 + jumpr r31 + } +.Ldenorm1: + { + memw(R0+#8) = R8 + R15:14 = #0 + } + { + memd(R0+#0) = R15:14 + jumpr r31 + } diff --git a/library/compiler-builtins/src/hexagon/func_macro.s b/library/compiler-builtins/src/hexagon/func_macro.s new file mode 100644 index 00000000000..9a1e11aebcb --- /dev/null +++ b/library/compiler-builtins/src/hexagon/func_macro.s @@ -0,0 +1,12 @@ + .macro FUNCTION_BEGIN name + .text + .p2align 5 + .globl \name + .type \name, @function +\name: + .endm + + .macro FUNCTION_END name + .size \name, . - \name + .endm + diff --git a/library/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s b/library/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s new file mode 100644 index 00000000000..89f69010aa4 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s @@ -0,0 +1,91 @@ + .text + + + + + + + .globl hexagon_memcpy_forward_vp4cp4n2 + .balign 32 + .type hexagon_memcpy_forward_vp4cp4n2,@function +hexagon_memcpy_forward_vp4cp4n2: + + + + + { + r3 = sub(##4096, r1) + r5 = lsr(r2, #3) + } + { + + + r3 = extractu(r3, #10, #2) + r4 = extractu(r3, #7, #5) + } + { + r3 = minu(r2, r3) + r4 = minu(r5, r4) + } + { + r4 = or(r4, ##2105344) + p0 = cmp.eq(r3, #0) + if (p0.new) jump:nt .Lskipprolog + } + l2fetch(r1, r4) + { + loop0(.Lprolog, r3) + r2 = sub(r2, r3) + } + .falign +.Lprolog: + { + r4 = memw(r1++#4) + memw(r0++#4) = r4.new + } :endloop0 +.Lskipprolog: + { + + r3 = lsr(r2, #10) + if (cmp.eq(r3.new, #0)) jump:nt .Lskipmain + } + { + loop1(.Lout, r3) + r2 = extractu(r2, #10, #0) + r3 = ##2105472 + } + + .falign +.Lout: + + l2fetch(r1, r3) + loop0(.Lpage, #512) + .falign +.Lpage: + r5:4 = memd(r1++#8) + { + memw(r0++#8) = r4 + memw(r0+#4) = r5 + } :endloop0:endloop1 +.Lskipmain: + { + r3 = ##2105344 + r4 = lsr(r2, #3) + p0 = cmp.eq(r2, #0) + if (p0.new) jumpr:nt r31 + } + { + r3 = or(r3, r4) + loop0(.Lepilog, r2) + } + l2fetch(r1, r3) + .falign +.Lepilog: + { + r4 = memw(r1++#4) + memw(r0++#4) = r4.new + } :endloop0 + + jumpr r31 + +.size hexagon_memcpy_forward_vp4cp4n2, . - hexagon_memcpy_forward_vp4cp4n2 diff --git a/library/compiler-builtins/src/hexagon/memcpy_likely_aligned.s b/library/compiler-builtins/src/hexagon/memcpy_likely_aligned.s new file mode 100644 index 00000000000..7e9b62f6a79 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/memcpy_likely_aligned.s @@ -0,0 +1,42 @@ + +FUNCTION_BEGIN __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes + { + p0 = bitsclr(r1,#7) + p0 = bitsclr(r0,#7) + if (p0.new) r5:4 = memd(r1) + r3 = #-3 + } + { + if (!p0) jump .Lmemcpy_call + if (p0) memd(r0++#8) = r5:4 + if (p0) r5:4 = memd(r1+#8) + r3 += lsr(r2,#3) + } + { + memd(r0++#8) = r5:4 + r5:4 = memd(r1+#16) + r1 = add(r1,#24) + loop0(1f,r3) + } + .falign +1: + { + memd(r0++#8) = r5:4 + r5:4 = memd(r1++#8) + }:endloop0 + { + memd(r0) = r5:4 + r0 -= add(r2,#-8) + jumpr r31 + } +FUNCTION_END __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes + +.Lmemcpy_call: + + jump memcpy@PLT + + + + + .globl __qdsp_memcpy_likely_aligned_min32bytes_mult8bytes + .set __qdsp_memcpy_likely_aligned_min32bytes_mult8bytes, __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes diff --git a/library/compiler-builtins/src/hexagon/moddi3.s b/library/compiler-builtins/src/hexagon/moddi3.s new file mode 100644 index 00000000000..53ea6d52a58 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/moddi3.s @@ -0,0 +1,63 @@ + + +FUNCTION_BEGIN __hexagon_moddi3 + { + p3 = tstbit(r1,#31) + } + { + r1:0 = abs(r1:0) + r3:2 = abs(r3:2) + } + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jump .hexagon_moddi3_return + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + +.hexagon_moddi3_return: + { + r1:0 = neg(r3:2) + } + { + r1:0 = vmux(p3,r1:0,r3:2) + jumpr r31 + } +FUNCTION_END __hexagon_moddi3 + + .globl __qdsp_moddi3 + .set __qdsp_moddi3, __hexagon_moddi3 diff --git a/library/compiler-builtins/src/hexagon/modsi3.s b/library/compiler-builtins/src/hexagon/modsi3.s new file mode 100644 index 00000000000..c4ae7e59edc --- /dev/null +++ b/library/compiler-builtins/src/hexagon/modsi3.s @@ -0,0 +1,44 @@ + + +FUNCTION_BEGIN __hexagon_modsi3 + { + p2 = cmp.ge(r0,#0) + r2 = abs(r0) + r1 = abs(r1) + } + { + r3 = cl0(r2) + r4 = cl0(r1) + p0 = cmp.gtu(r1,r2) + } + { + r3 = sub(r4,r3) + if (p0) jumpr r31 + } + { + p1 = cmp.eq(r3,#0) + loop0(1f,r3) + r0 = r2 + r2 = lsl(r1,r3) + } + .falign +1: + { + p0 = cmp.gtu(r2,r0) + if (!p0.new) r0 = sub(r0,r2) + r2 = lsr(r2,#1) + if (p1) r1 = #0 + }:endloop0 + { + p0 = cmp.gtu(r2,r0) + if (!p0.new) r0 = sub(r0,r1) + if (p2) jumpr r31 + } + { + r0 = neg(r0) + jumpr r31 + } +FUNCTION_END __hexagon_modsi3 + + .globl __qdsp_modsi3 + .set __qdsp_modsi3, __hexagon_modsi3 diff --git a/library/compiler-builtins/src/hexagon/sfdiv_opt.s b/library/compiler-builtins/src/hexagon/sfdiv_opt.s new file mode 100644 index 00000000000..26c91f15cbb --- /dev/null +++ b/library/compiler-builtins/src/hexagon/sfdiv_opt.s @@ -0,0 +1,42 @@ + +FUNCTION_BEGIN __hexagon_divsf3 + { + r2,p0 = sfrecipa(r0,r1) + r4 = sffixupd(r0,r1) + r3 = ##0x3f800000 + } + { + r5 = sffixupn(r0,r1) + r3 -= sfmpy(r4,r2):lib + r6 = ##0x80000000 + r7 = r3 + } + { + r2 += sfmpy(r3,r2):lib + r3 = r7 + r6 = r5 + r0 = and(r6,r5) + } + { + r3 -= sfmpy(r4,r2):lib + r0 += sfmpy(r5,r2):lib + } + { + r2 += sfmpy(r3,r2):lib + r6 -= sfmpy(r0,r4):lib + } + { + r0 += sfmpy(r6,r2):lib + } + { + r5 -= sfmpy(r0,r4):lib + } + { + r0 += sfmpy(r5,r2,p0):scale + jumpr r31 + } +FUNCTION_END __hexagon_divsf3 + +.global __qdsp_divsf3 ; .set __qdsp_divsf3, __hexagon_divsf3 +.global __hexagon_fast_divsf3 ; .set __hexagon_fast_divsf3, __hexagon_divsf3 +.global __hexagon_fast2_divsf3 ; .set __hexagon_fast2_divsf3, __hexagon_divsf3 diff --git a/library/compiler-builtins/src/hexagon/sfsqrt_opt.s b/library/compiler-builtins/src/hexagon/sfsqrt_opt.s new file mode 100644 index 00000000000..c90af179754 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/sfsqrt_opt.s @@ -0,0 +1,49 @@ +FUNCTION_BEGIN __hexagon_sqrtf + { + r3,p0 = sfinvsqrta(r0) + r5 = sffixupr(r0) + r4 = ##0x3f000000 + r1:0 = combine(#0,#0) + } + { + r0 += sfmpy(r3,r5):lib + r1 += sfmpy(r3,r4):lib + r2 = r4 + r3 = r5 + } + { + r2 -= sfmpy(r0,r1):lib + p1 = sfclass(r5,#1) + + } + { + r0 += sfmpy(r0,r2):lib + r1 += sfmpy(r1,r2):lib + r2 = r4 + r3 = r5 + } + { + r2 -= sfmpy(r0,r1):lib + r3 -= sfmpy(r0,r0):lib + } + { + r0 += sfmpy(r1,r3):lib + r1 += sfmpy(r1,r2):lib + r2 = r4 + r3 = r5 + } + { + + r3 -= sfmpy(r0,r0):lib + if (p1) r0 = or(r0,r5) + } + { + r0 += sfmpy(r1,r3,p0):scale + jumpr r31 + } + +FUNCTION_END __hexagon_sqrtf + +.global __qdsp_sqrtf ; .set __qdsp_sqrtf, __hexagon_sqrtf +.global __hexagon_fast_sqrtf ; .set __hexagon_fast_sqrtf, __hexagon_sqrtf +.global __hexagon_fast2_sqrtf ; .set __hexagon_fast2_sqrtf, __hexagon_sqrtf diff --git a/library/compiler-builtins/src/hexagon/udivdi3.s b/library/compiler-builtins/src/hexagon/udivdi3.s new file mode 100644 index 00000000000..f0fffc23df0 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/udivdi3.s @@ -0,0 +1,50 @@ + + +FUNCTION_BEGIN __hexagon_udivdi3 + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jumpr r31 + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + { + jumpr r31 + } +FUNCTION_END __hexagon_udivdi3 + + .globl __qdsp_udivdi3 + .set __qdsp_udivdi3, __hexagon_udivdi3 diff --git a/library/compiler-builtins/src/hexagon/udivmoddi4.s b/library/compiler-builtins/src/hexagon/udivmoddi4.s new file mode 100644 index 00000000000..cbfb3987dd2 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/udivmoddi4.s @@ -0,0 +1,50 @@ + + +FUNCTION_BEGIN __hexagon_udivmoddi4 + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jumpr r31 + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + { + jumpr r31 + } +FUNCTION_END __hexagon_udivmoddi4 + + .globl __qdsp_udivmoddi4 + .set __qdsp_udivmoddi4, __hexagon_udivmoddi4 diff --git a/library/compiler-builtins/src/hexagon/udivmodsi4.s b/library/compiler-builtins/src/hexagon/udivmodsi4.s new file mode 100644 index 00000000000..83489c51431 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/udivmodsi4.s @@ -0,0 +1,39 @@ + + +FUNCTION_BEGIN __hexagon_udivmodsi4 + { + r2 = cl0(r0) + r3 = cl0(r1) + r5:4 = combine(#1,#0) + p0 = cmp.gtu(r1,r0) + } + { + r6 = sub(r3,r2) + r4 = r1 + r1:0 = combine(r0,r4) + if (p0) jumpr r31 + } + { + r3:2 = vlslw(r5:4,r6) + loop0(1f,r6) + p0 = cmp.eq(r6,#0) + if (p0.new) r4 = #0 + } + .falign +1: + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r1 = sub(r1,r2) + if (!p0.new) r0 = add(r0,r3) + r3:2 = vlsrw(r3:2,#1) + }:endloop0 + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r1 = sub(r1,r4) + if (!p0.new) r0 = add(r0,r3) + jumpr r31 + } +FUNCTION_END __hexagon_udivmodsi4 + + .globl __qdsp_udivmodsi4 + .set __qdsp_udivmodsi4, __hexagon_udivmodsi4 diff --git a/library/compiler-builtins/src/hexagon/udivsi3.s b/library/compiler-builtins/src/hexagon/udivsi3.s new file mode 100644 index 00000000000..e0b94aa9982 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/udivsi3.s @@ -0,0 +1,36 @@ + + +FUNCTION_BEGIN __hexagon_udivsi3 + { + r2 = cl0(r0) + r3 = cl0(r1) + r5:4 = combine(#1,#0) + p0 = cmp.gtu(r1,r0) + } + { + r6 = sub(r3,r2) + r4 = r1 + r1:0 = combine(r0,r4) + if (p0) jumpr r31 + } + { + r3:2 = vlslw(r5:4,r6) + loop0(1f,r6) + } + .falign +1: + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r1 = sub(r1,r2) + if (!p0.new) r0 = add(r0,r3) + r3:2 = vlsrw(r3:2,#1) + }:endloop0 + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r0 = add(r0,r3) + jumpr r31 + } +FUNCTION_END __hexagon_udivsi3 + + .globl __qdsp_udivsi3 + .set __qdsp_udivsi3, __hexagon_udivsi3 diff --git a/library/compiler-builtins/src/hexagon/umoddi3.s b/library/compiler-builtins/src/hexagon/umoddi3.s new file mode 100644 index 00000000000..c76011c3e7a --- /dev/null +++ b/library/compiler-builtins/src/hexagon/umoddi3.s @@ -0,0 +1,53 @@ + + +FUNCTION_BEGIN __hexagon_umoddi3 + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jump .hexagon_umoddi3_return + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + +.hexagon_umoddi3_return: + { + r1:0 = r3:2 + jumpr r31 + } +FUNCTION_END __hexagon_umoddi3 + + .globl __qdsp_umoddi3 + .set __qdsp_umoddi3, __hexagon_umoddi3 diff --git a/library/compiler-builtins/src/hexagon/umodsi3.s b/library/compiler-builtins/src/hexagon/umodsi3.s new file mode 100644 index 00000000000..1b592a7c561 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/umodsi3.s @@ -0,0 +1,34 @@ + + +FUNCTION_BEGIN __hexagon_umodsi3 + { + r2 = cl0(r0) + r3 = cl0(r1) + p0 = cmp.gtu(r1,r0) + } + { + r2 = sub(r3,r2) + if (p0) jumpr r31 + } + { + loop0(1f,r2) + p1 = cmp.eq(r2,#0) + r2 = lsl(r1,r2) + } + .falign +1: + { + p0 = cmp.gtu(r2,r0) + if (!p0.new) r0 = sub(r0,r2) + r2 = lsr(r2,#1) + if (p1) r1 = #0 + }:endloop0 + { + p0 = cmp.gtu(r2,r0) + if (!p0.new) r0 = sub(r0,r1) + jumpr r31 + } +FUNCTION_END __hexagon_umodsi3 + + .globl __qdsp_umodsi3 + .set __qdsp_umodsi3, __hexagon_umodsi3 diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3e54918782b..47aef540e41 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![cfg_attr(not(feature = "no-asm"), feature(asm))] #![feature(abi_unadjusted)] +#![feature(asm_experimental_arch)] #![cfg_attr(not(feature = "no-asm"), feature(global_asm))] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] @@ -70,6 +71,9 @@ pub mod aarch64_linux; ))] pub mod arm_linux; +#[cfg(target_arch = "hexagon")] +pub mod hexagon; + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] pub mod riscv; -- cgit 1.4.1-3-g733a5 From 72dbe301ff7ebf19fc01dc790973bc24d8742347 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 14 Dec 2023 20:23:55 +0000 Subject: Bump to 0.1.105 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6ebabfdcbeb..1b8b426ce05 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.104" +version = "0.1.105" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From e898296fd9bc1937e4156cc44e30b7f92f90342f Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 20 Dec 2023 09:30:11 +1000 Subject: build: Allow building C compiler-rt fallbacks for RISC-V Now that https://github.com/rust-lang/rust/pull/117654 has been merged the rust-lang/rust distribution containers contain RISC-V C compilers. This means that we can now enable the "c" feature fallback. Resolves: https://github.com/rust-lang/compiler-builtins/issues/350 Signed-off-by: Alistair Francis --- library/compiler-builtins/build.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0486116778c..d4b2a9b499e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -59,12 +59,7 @@ fn main() { // * wasm - clang for wasm is somewhat hard to come by and it's // unlikely that the C is really that much better than our own Rust. // * nvptx - everything is bitcode, not compatible with mixed C/Rust - // * riscv - the rust-lang/rust distribution container doesn't have a C - // compiler. - if !target.contains("wasm") - && !target.contains("nvptx") - && (!target.starts_with("riscv") || target.contains("xous")) - { + if !target.contains("wasm") && !target.contains("nvptx") { #[cfg(feature = "c")] c::compile(&llvm_target, &target); } @@ -519,7 +514,7 @@ mod c { } } - if target_arch == "mips" { + if target_arch == "mips" || target_arch == "riscv32" || target_arch == "riscv64" { sources.extend(&[("__bswapsi2", "bswapsi2.c")]); } -- cgit 1.4.1-3-g733a5 From c464d5a38d5030ca413686b65b3389acea9e71b9 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 9 Jan 2024 00:07:27 +0900 Subject: Update actions/checkout action to v4 --- library/compiler-builtins/.github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index b69c48c16a9..360ed97391d 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -80,7 +80,7 @@ jobs: os: windows-latest rust: nightly-x86_64-gnu steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: submodules: true - name: Install Rust (rustup) @@ -108,7 +108,7 @@ jobs: name: Rustfmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: submodules: true - name: Install stable `rustfmt` @@ -119,7 +119,7 @@ jobs: name: Clippy runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: submodules: true # Unlike rustfmt, stable clippy does not work on code with nightly features. -- cgit 1.4.1-3-g733a5 From 0808cdeb67fa5e0ec24c381e0164eee021b5b1b0 Mon Sep 17 00:00:00 2001 From: trevyn <230691+trevyn@users.noreply.github.com> Date: Tue, 9 Jan 2024 01:23:59 +0400 Subject: build: Allow building C compiler-rt fallbacks for wasm --- library/compiler-builtins/.github/workflows/main.yml | 4 ++-- library/compiler-builtins/build.rs | 7 +------ .../compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile | 2 +- library/compiler-builtins/ci/run.sh | 1 + 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index b69c48c16a9..8110e27f76e 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -90,8 +90,8 @@ jobs: - run: rustup component add llvm-tools-preview - name: Download compiler-rt reference sources run: | - curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/12.0-2021-04-15.tar.gz - tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-12.0-2021-04-15/compiler-rt + curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/13.0-2021-08-08.tar.gz + tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-13.0-2021-08-08/compiler-rt echo RUST_COMPILER_RT_ROOT=./compiler-rt >> $GITHUB_ENV shell: bash diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0486116778c..9bf6a254724 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -56,15 +56,10 @@ fn main() { if !cfg!(feature = "mangled-names") && cfg!(feature = "c") { // Don't use a C compiler for these targets: // - // * wasm - clang for wasm is somewhat hard to come by and it's - // unlikely that the C is really that much better than our own Rust. // * nvptx - everything is bitcode, not compatible with mixed C/Rust // * riscv - the rust-lang/rust distribution container doesn't have a C // compiler. - if !target.contains("wasm") - && !target.contains("nvptx") - && (!target.starts_with("riscv") || target.contains("xous")) - { + if !target.contains("nvptx") && (!target.starts_with("riscv") || target.contains("xous")) { #[cfg(feature = "c")] c::compile(&llvm_target, &target); } diff --git a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile index 758d94d5013..85ead29aaee 100644 --- a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile +++ b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:20.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates + gcc clang libc6-dev ca-certificates ENV CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER=true diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 44ec30fb798..6376d2216d9 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -66,6 +66,7 @@ for rlib in $(echo $path); do grep -v __x86.get_pc_thunk | \ grep -v __builtin_cl | \ grep -v __builtin_ctz | \ + grep -v __builtin_sadd_overflow | \ grep 'T __' if test $? = 0; then -- cgit 1.4.1-3-g733a5 From 0dc7f73408c4465f73d7b9cc14877fa6b12e4ac1 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 18 Jan 2024 01:27:08 +0000 Subject: Bump to 0.1.106 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 1b8b426ce05..e3540f4658e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.105" +version = "0.1.106" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 105f0d834d67546166ec44be3d561a8b7739c98e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 22 Jan 2024 12:55:25 +0100 Subject: Only add 80-bit long double source on x86 These no longer build on other architectures with LLVM 18. In previous versions they used an incorrect float layout. --- library/compiler-builtins/build.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d4b2a9b499e..690a4fc9b68 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -290,17 +290,23 @@ mod c { sources.extend(&[ ("__divdc3", "divdc3.c"), ("__divsc3", "divsc3.c"), - ("__divxc3", "divxc3.c"), ("__extendhfsf2", "extendhfsf2.c"), ("__muldc3", "muldc3.c"), ("__mulsc3", "mulsc3.c"), - ("__mulxc3", "mulxc3.c"), ("__negdf2", "negdf2.c"), ("__negsf2", "negsf2.c"), - ("__powixf2", "powixf2.c"), ("__truncdfhf2", "truncdfhf2.c"), ("__truncsfhf2", "truncsfhf2.c"), ]); + + if target_arch == "x86" || target_arch == "x86_64" { + // Only add 80-bit long double sources on x86. + sources.extend(&[ + ("__divxc3", "divxc3.c"), + ("__mulxc3", "mulxc3.c"), + ("__powixf2", "powixf2.c"), + ]); + } } // When compiling in rustbuild (the rust-lang/rust repo) this library -- cgit 1.4.1-3-g733a5 From 8ca492c7d7858ded13f2f83c560d8b467e700a54 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Wed, 24 Jan 2024 19:38:55 +0100 Subject: CI: add a success conclusion job --- library/compiler-builtins/.github/workflows/main.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 360ed97391d..9f15cb9d831 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -128,3 +128,18 @@ jobs: run: | rustup set profile minimal && rustup default "nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/clippy)" && rustup component add clippy - run: cargo clippy -- -D clippy::all + + success: + needs: + - test + - rustfmt + - clippy + runs-on: ubuntu-latest + # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency + # failed" as success. So we have to do some contortions to ensure the job fails if any of its + # dependencies fails. + if: always() # make sure this is never "skipped" + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: check if any dependency failed + run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' -- cgit 1.4.1-3-g733a5 From 845f4e75d12c43acbbc7a7347e6d07ee2094f21a Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Wed, 24 Jan 2024 13:57:31 -0500 Subject: fix: replace travis link with github actions link --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index da0adbce70c..adcdcacbac1 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -62,7 +62,7 @@ features = ["c"] [1]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/test/builtins/Unit [2]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/lib/builtins [3]: https://github.com/rust-lang/compiler-builtins/blob/0ba07e49264a54cb5bbd4856fcea083bb3fbec15/build.rs#L180-L265 -[4]: https://travis-ci.org/rust-lang/compiler-builtins +[4]: https://github.com/rust-lang/compiler-builtins/actions ### Porting Reminders -- cgit 1.4.1-3-g733a5 From 45a113effb32fabd8d6098a412bca2a2cbb85f15 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Thu, 4 Jan 2024 18:43:58 -0800 Subject: Handle move of cpu_model.c This happened in https://github.com/llvm/llvm-project/pull/75635/files and shows up when building against a recent commit of LLVM. --- library/compiler-builtins/build.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 690a4fc9b68..c133d5e7ced 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -602,7 +602,12 @@ mod c { build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); // Some run-time CPU feature detection is necessary, as well. - sources.extend(&[("__aarch64_have_lse_atomics", "cpu_model.c")]); + let cpu_model_src = if src_dir.join("cpu_model.c").exists() { + "cpu_model.c" + } else { + "cpu_model/aarch64.c" + }; + sources.extend(&[("__aarch64_have_lse_atomics", cpu_model_src)]); } let mut added_sources = HashSet::new(); -- cgit 1.4.1-3-g733a5 From 1cd23fa8b0343828dd523009eebb20ff8e03d097 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 31 Jan 2024 08:36:00 +0000 Subject: Bump to 0.1.107 (#571) --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index e3540f4658e..b7e504ad5d7 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.106" +version = "0.1.107" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 2f8b08f9e34ce405befb67ff681595fb30add102 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 31 Jan 2024 17:37:26 +0100 Subject: Remove 80-bit builtins entirely It turns out that these also don't build on x86 + MSVC. Rather than fixing up the condition, I'm just deleting them entirely. As far as I know, Rust does not support 80-bit floats and has no plan to support them, so we shouldn't need them. --- library/compiler-builtins/build.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6ad7f71538e..8082131ef8c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -296,15 +296,6 @@ mod c { ("__truncdfhf2", "truncdfhf2.c"), ("__truncsfhf2", "truncsfhf2.c"), ]); - - if target_arch == "x86" || target_arch == "x86_64" { - // Only add 80-bit long double sources on x86. - sources.extend(&[ - ("__divxc3", "divxc3.c"), - ("__mulxc3", "mulxc3.c"), - ("__powixf2", "powixf2.c"), - ]); - } } // When compiling in rustbuild (the rust-lang/rust repo) this library -- cgit 1.4.1-3-g733a5 From 168bc9ecd7214e33610d6a53212026d35b49c89d Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 2 Feb 2024 10:04:55 +0100 Subject: Also don't build floatdixf and floatundixf --- library/compiler-builtins/build.rs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 8082131ef8c..6268fd2ff34 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -347,29 +347,12 @@ mod c { ]); } - if target_env == "msvc" { - if target_arch == "x86_64" { - sources.extend(&[("__floatdixf", "x86_64/floatdixf.c")]); - } - } else { - // None of these seem to be used on x86_64 windows, and they've all - // got the wrong ABI anyway, so we want to avoid them. - if target_os != "windows" { - if target_arch == "x86_64" { - sources.extend(&[ - ("__floatdixf", "x86_64/floatdixf.c"), - ("__floatundixf", "x86_64/floatundixf.S"), - ]); - } - } - + if target_env != "msvc" { if target_arch == "x86" { sources.extend(&[ ("__ashldi3", "i386/ashldi3.S"), ("__ashrdi3", "i386/ashrdi3.S"), ("__divdi3", "i386/divdi3.S"), - ("__floatdixf", "i386/floatdixf.S"), - ("__floatundixf", "i386/floatundixf.S"), ("__lshrdi3", "i386/lshrdi3.S"), ("__moddi3", "i386/moddi3.S"), ("__muldi3", "i386/muldi3.S"), -- cgit 1.4.1-3-g733a5 From 079d7d857ca878d13d3a5ceed917e7627735b8e8 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 4 Feb 2024 06:37:55 +0000 Subject: Release 0.1.108 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index b7e504ad5d7..e94c2f7625f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.107" +version = "0.1.108" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From cdf7ac490c22f055b83d1068bfc455f2b63fdd9f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 21 Feb 2024 00:58:14 +0000 Subject: Allow internal_features lint when building with "unstable" --- library/compiler-builtins/libm/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 4a17d3a77a2..1f23ef8a80e 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,7 +1,8 @@ //! libm in pure Rust #![deny(warnings)] #![no_std] -#![cfg_attr(all(feature = "unstable"), feature(core_intrinsics))] +#![cfg_attr(feature = "unstable", allow(internal_features))] +#![cfg_attr(feature = "unstable", feature(core_intrinsics))] #![allow(clippy::unreadable_literal)] #![allow(clippy::many_single_char_names)] #![allow(clippy::needless_return)] -- cgit 1.4.1-3-g733a5 From d752cbfb0ebcad536011a6a03612775450d63c9a Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Sun, 11 Feb 2024 18:03:42 +0800 Subject: Remove unneeded `extern core` in `tgamma` --- library/compiler-builtins/libm/src/math/tgamma.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs index e64eff61f06..3f38c0b1d9f 100644 --- a/library/compiler-builtins/libm/src/math/tgamma.rs +++ b/library/compiler-builtins/libm/src/math/tgamma.rs @@ -22,7 +22,6 @@ Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) most ideas and constants are from boost and python */ -extern crate core; use super::{exp, floor, k_cos, k_sin, pow}; const PI: f64 = 3.141592653589793238462643383279502884; -- cgit 1.4.1-3-g733a5 From 68b5a7a0ad1d516955c13a0dde3d1ec0c547472d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 24 Mar 2024 20:27:38 +0000 Subject: Clean up and rework CI script --- .../compiler-builtins/.github/workflows/main.yml | 1 + .../ci/docker/thumbv6m-none-eabi/Dockerfile | 2 +- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 2 +- .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 2 +- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 2 +- library/compiler-builtins/ci/run.sh | 58 ++++++++++++---------- 6 files changed, 37 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 9071e4ff063..f5600c1ed32 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -6,6 +6,7 @@ jobs: name: Test runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: include: - target: aarch64-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index 04d4f442905..dc7dd431ba3 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -4,4 +4,4 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV XARGO=1 +ENV NO_STD=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 04d4f442905..dc7dd431ba3 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -4,4 +4,4 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV XARGO=1 +ENV NO_STD=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index 04d4f442905..dc7dd431ba3 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -4,4 +4,4 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV XARGO=1 +ENV NO_STD=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index 04d4f442905..dc7dd431ba3 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -4,4 +4,4 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV XARGO=1 +ENV NO_STD=1 diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 6376d2216d9..b059d566052 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,10 +1,7 @@ set -ex -cargo=cargo - # Test our implementation -if [ "$XARGO" = "1" ]; then - # FIXME: currently these tests don't work... +if [ "$NO_STD" = "1" ]; then echo nothing to do else run="cargo test --manifest-path testcrate/Cargo.toml --target $1" @@ -16,6 +13,15 @@ else $run --features no-asm --release fi +if [ -d /target ]; then + path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib +else + path=target/${1}/debug/deps/libcompiler_builtins-*.rlib +fi + +# Remove any existing artifacts from previous tests that don't set #![compiler_builtins] +rm -f $path + cargo build --target $1 cargo build --target $1 --release cargo build --target $1 --features c @@ -36,15 +42,15 @@ case $1 in ;; esac -NM=$(find $(rustc --print sysroot) -name llvm-nm) +NM=$(find $(rustc --print sysroot) \( -name llvm-nm -o -name llvm-nm.exe \) ) if [ "$NM" = "" ]; then NM=${PREFIX}nm fi - -if [ -d /target ]; then - path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib -else - path=target/${1}/debug/deps/libcompiler_builtins-*.rlib +# i686-pc-windows-gnu tools have a dependency on some DLLs, so run it with +# rustup run to ensure that those are in PATH. +TOOLCHAIN=$(rustup show active-toolchain | sed 's/ (default)//') +if [[ $TOOLCHAIN == *i686-pc-windows-gnu ]]; then + NM="rustup run $TOOLCHAIN $NM" fi # Look out for duplicated symbols when we include the compiler-rt (C) implementation @@ -79,29 +85,29 @@ done rm -f $path # Verify that we haven't drop any intrinsic/symbol -build_intrinsics="$cargo build --target $1 -v --example intrinsics" -RUSTFLAGS="-C debug-assertions=no" $build_intrinsics -RUSTFLAGS="-C debug-assertions=no" $build_intrinsics --release -RUSTFLAGS="-C debug-assertions=no" $build_intrinsics --features c -RUSTFLAGS="-C debug-assertions=no" $build_intrinsics --features c --release +build_intrinsics="cargo build --target $1 -v --example intrinsics" +$build_intrinsics +$build_intrinsics --release +$build_intrinsics --features c +$build_intrinsics --features c --release # Verify that there are no undefined symbols to `panic` within our # implementations -# -# TODO(#79) fix the undefined references problem for debug-assertions+lto -if [ -z "$DEBUG_LTO_BUILD_DOESNT_WORK" ]; then - RUSTFLAGS="-C debug-assertions=no" \ - CARGO_INCREMENTAL=0 \ - CARGO_PROFILE_DEV_LTO=true \ - $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics -fi +CARGO_PROFILE_DEV_LTO=true \ + cargo build --target $1 --example intrinsics CARGO_PROFILE_RELEASE_LTO=true \ - $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics --release + cargo build --target $1 --example intrinsics --release -# Ensure no references to a panicking function +# Ensure no references to any symbols from core for rlib in $(echo $path); do set +ex - $NM -u $rlib 2>&1 | grep panicking + echo "================================================================" + echo checking $rlib for references to core + echo "================================================================" + + $NM --quiet -U $rlib | grep 'T _ZN4core' | awk '{print $3}' | sort | uniq > defined_symbols.txt + $NM --quiet -u $rlib | grep 'U _ZN4core' | awk '{print $2}' | sort | uniq > undefined_symbols.txt + grep -v -F -x -f defined_symbols.txt undefined_symbols.txt if test $? = 0; then exit 1 -- cgit 1.4.1-3-g733a5 From ce85d06f3b4e76ac22ec6cc1dc40b9548fff6a5b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Mar 2024 18:16:35 +0100 Subject: add c_unwind feature --- library/compiler-builtins/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 47aef540e41..66540bb9b6b 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -12,6 +12,7 @@ #![feature(linkage)] #![feature(naked_functions)] #![feature(repr_simd)] +#![feature(c_unwind)] #![no_builtins] #![no_std] #![allow(unused_features)] -- cgit 1.4.1-3-g733a5 From 75624cc8aecd693871aa95d5126023f1eaa81ef9 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Tue, 14 Nov 2023 18:43:39 +0800 Subject: Add compiler-rt fallbacks on loongarch64-musl --- library/compiler-builtins/build.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6268fd2ff34..1b901b7e8fa 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -514,6 +514,24 @@ mod c { ]); } + if target_arch == "loongarch64" { + sources.extend(&[ + ("__extenddftf2", "extenddftf2.c"), + ("__netf2", "comparetf2.c"), + ("__addtf3", "addtf3.c"), + ("__multf3", "multf3.c"), + ("__subtf3", "subtf3.c"), + ("__fixtfsi", "fixtfsi.c"), + ("__floatsitf", "floatsitf.c"), + ("__fixunstfsi", "fixunstfsi.c"), + ("__floatunsitf", "floatunsitf.c"), + ("__fe_getround", "fp_mode.c"), + ("__divtf3", "divtf3.c"), + ("__trunctfdf2", "trunctfdf2.c"), + ("__trunctfsf2", "trunctfsf2.c"), + ]); + } + // Remove the assembly implementations that won't compile for the target if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" || target_os == "uefi" { -- cgit 1.4.1-3-g733a5 From dc1321a5ca88cb97aa845bd0221d5e3a26396777 Mon Sep 17 00:00:00 2001 From: trevyn <230691+trevyn@users.noreply.github.com> Date: Thu, 8 Feb 2024 07:34:09 -0800 Subject: Remove duplicate symbol workaround --- library/compiler-builtins/.github/workflows/main.yml | 4 ++-- library/compiler-builtins/ci/run.sh | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index f5600c1ed32..97d298cf09c 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -91,8 +91,8 @@ jobs: - run: rustup component add llvm-tools-preview - name: Download compiler-rt reference sources run: | - curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/13.0-2021-08-08.tar.gz - tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-13.0-2021-08-08/compiler-rt + curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/18.0-2024-02-13.tar.gz + tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-18.0-2024-02-13/compiler-rt echo RUST_COMPILER_RT_ROOT=./compiler-rt >> $GITHUB_ENV shell: bash diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index b059d566052..09728191a22 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -63,16 +63,11 @@ for rlib in $(echo $path); do stdout=$($NM -g --defined-only $rlib 2>&1) # NOTE On i586, It's normal that the get_pc_thunk symbol appears several # times so ignore it - # - # FIXME(#167) - we shouldn't ignore `__builtin_cl` style symbols here. set +e echo "$stdout" | \ sort | \ uniq -d | \ grep -v __x86.get_pc_thunk | \ - grep -v __builtin_cl | \ - grep -v __builtin_ctz | \ - grep -v __builtin_sadd_overflow | \ grep 'T __' if test $? = 0; then -- cgit 1.4.1-3-g733a5 From 30182128c970316f820d97ae4e889107bd0077be Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Fri, 23 Feb 2024 10:51:15 -0800 Subject: Add support for arm64ec --- library/compiler-builtins/build.rs | 2 +- library/compiler-builtins/src/lib.rs | 2 +- library/compiler-builtins/testcrate/tests/lse.rs | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 1b901b7e8fa..44946c1240c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -461,7 +461,7 @@ mod c { ]); } - if target_arch == "aarch64" && consider_float_intrinsics { + if (target_arch == "aarch64" || target_arch == "arm64ec") && consider_float_intrinsics { sources.extend(&[ ("__comparetf2", "comparetf2.c"), ("__extenddftf2", "extenddftf2.c"), diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 66540bb9b6b..a414efde0ce 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -59,7 +59,7 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; -#[cfg(target_arch = "aarch64")] +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] pub mod aarch64; #[cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm"),))] diff --git a/library/compiler-builtins/testcrate/tests/lse.rs b/library/compiler-builtins/testcrate/tests/lse.rs index 5589f22f1e9..63c98957cf4 100644 --- a/library/compiler-builtins/testcrate/tests/lse.rs +++ b/library/compiler-builtins/testcrate/tests/lse.rs @@ -1,5 +1,8 @@ #![feature(decl_macro)] // so we can use pub(super) -#![cfg(all(target_arch = "aarch64", not(feature = "no-asm")))] +#![cfg(all( + any(target_arch = "aarch64", target_arch = "arm64ec"), + not(feature = "no-asm") +))] /// Translate a byte size to a Rust type. macro int_ty { -- cgit 1.4.1-3-g733a5 From f04f8a6a9dcf7d813fb23f6af03437fc3bf54bcd Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sat, 10 Feb 2024 14:47:03 +0100 Subject: Sync x86 chkstk intrinsics with LLVM Incorporates the following commits: https://github.com/llvm/llvm-project/commit/885d7b759b5c166c07c07f4c58c6e0ba110fb0c2 https://github.com/llvm/llvm-project/commit/1f9eff100ce8faea1284d68b779d844c6e019b77 https://github.com/llvm/llvm-project/commit/7a5cba8bea8f774d48db1b0426bcc102edd2b69f --- library/compiler-builtins/README.md | 2 -- library/compiler-builtins/src/x86.rs | 47 ++------------------------------- library/compiler-builtins/src/x86_64.rs | 44 ------------------------------ 3 files changed, 2 insertions(+), 91 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index adcdcacbac1..ffef4e52c79 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -163,7 +163,6 @@ features = ["c"] - [ ] i386/ashldi3.S - [ ] i386/ashrdi3.S - [x] i386/chkstk.S -- [x] i386/chkstk2.S - [ ] i386/divdi3.S - [ ] i386/lshrdi3.S - [ ] i386/moddi3.S @@ -192,7 +191,6 @@ features = ["c"] - [x] umoddi3.c - [x] umodsi3.c - [x] x86_64/chkstk.S -- [x] x86_64/chkstk2.S These builtins are needed to support 128-bit integers, which are in the process of being added to Rust. diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index fd1f32e3a7d..5016816eb36 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -6,7 +6,6 @@ use core::intrinsics; // calling convention which can't be implemented using a normal Rust function // NOTE These functions are never mangled as they are not tested against compiler-rt -// and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca intrinsics! { #[naked] @@ -15,50 +14,8 @@ intrinsics! { target_env = "gnu", not(feature = "no-asm") ))] - pub unsafe extern "C" fn ___chkstk_ms() { - core::arch::asm!( - "push %ecx", - "push %eax", - "cmp $0x1000,%eax", - "lea 12(%esp),%ecx", - "jb 1f", - "2:", - "sub $0x1000,%ecx", - "test %ecx,(%ecx)", - "sub $0x1000,%eax", - "cmp $0x1000,%eax", - "ja 2b", - "1:", - "sub %eax,%ecx", - "test %ecx,(%ecx)", - "pop %eax", - "pop %ecx", - "ret", - options(noreturn, att_syntax) - ); - } - - // FIXME: __alloca should be an alias to __chkstk - #[naked] - #[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm") - ))] - pub unsafe extern "C" fn __alloca() { - core::arch::asm!( - "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" - options(noreturn, att_syntax) - ); - } - - #[naked] - #[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm") - ))] - pub unsafe extern "C" fn ___chkstk() { + pub unsafe extern "C" fn _alloca() { + // _chkstk and _alloca are the same function core::arch::asm!( "push %ecx", "cmp $0x1000,%eax", diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 7ad94115825..8048f85c8ff 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -6,7 +6,6 @@ use core::intrinsics; // calling convention which can't be implemented using a normal Rust function // NOTE These functions are never mangled as they are not tested against compiler-rt -// and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca intrinsics! { #[naked] @@ -36,49 +35,6 @@ intrinsics! { options(noreturn, att_syntax) ); } - - #[naked] - #[cfg(all( - any(all(windows, target_env = "gnu"), target_os = "uefi"), - not(feature = "no-asm") - ))] - pub unsafe extern "C" fn __alloca() { - core::arch::asm!( - "mov %rcx,%rax", // x64 _alloca is a normal function with parameter in rcx - "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" - options(noreturn, att_syntax) - ); - } - - #[naked] - #[cfg(all( - any(all(windows, target_env = "gnu"), target_os = "uefi"), - not(feature = "no-asm") - ))] - pub unsafe extern "C" fn ___chkstk() { - core::arch::asm!( - "push %rcx", - "cmp $0x1000,%rax", - "lea 16(%rsp),%rcx", // rsp before calling this routine -> rcx - "jb 1f", - "2:", - "sub $0x1000,%rcx", - "test %rcx,(%rcx)", - "sub $0x1000,%rax", - "cmp $0x1000,%rax", - "ja 2b", - "1:", - "sub %rax,%rcx", - "test %rcx,(%rcx)", - "lea 8(%rsp),%rax", // load pointer to the return address into rax - "mov %rcx,%rsp", // install the new top of stack pointer into rsp - "mov -8(%rax),%rcx", // restore rcx - "push (%rax)", // push return address onto the stack - "sub %rsp,%rax", // restore the original value in rax - "ret", - options(noreturn, att_syntax) - ); - } } // HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM -- cgit 1.4.1-3-g733a5 From 9c0ab26d3be9f4543376457498d4dc6fa12fd539 Mon Sep 17 00:00:00 2001 From: Jeff Thuong Date: Tue, 2 Apr 2024 11:35:08 +0800 Subject: Corrected English typos --- library/compiler-builtins/libm/src/math/ceil.rs | 2 +- library/compiler-builtins/libm/src/math/floor.rs | 2 +- library/compiler-builtins/libm/src/math/pow.rs | 2 +- library/compiler-builtins/libm/src/math/sqrt.rs | 2 +- library/compiler-builtins/libm/src/math/sqrtf.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 22d89297138..cde5a19d0c8 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -20,7 +20,7 @@ pub fn ceil(x: f64) -> f64 { { //use an alternative implementation on x86, because the //main implementation fails with the x87 FPU used by - //debian i386, probablly due to excess precision issues. + //debian i386, probably due to excess precision issues. //basic implementation taken from https://github.com/rust-lang/libm/issues/219 use super::fabs; if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index d09f9a1a1f8..b7d1a04d2cd 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -20,7 +20,7 @@ pub fn floor(x: f64) -> f64 { { //use an alternative implementation on x86, because the //main implementation fails with the x87 FPU used by - //debian i386, probablly due to excess precision issues. + //debian i386, probably due to excess precision issues. //basic implementation taken from https://github.com/rust-lang/libm/issues/219 use super::fabs; if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 6a19ae60111..09d12c1851b 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -16,7 +16,7 @@ // 1. Compute and return log2(x) in two pieces: // log2(x) = w1 + w2, // where w1 has 53-24 = 29 bit trailing zeros. -// 2. Perform y*log2(x) = n+y' by simulating muti-precision +// 2. Perform y*log2(x) = n+y' by simulating multi-precision // arithmetic, where |y'|<=0.5. // 3. Return x**y = 2**n*exp(y'*log2) // diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 3733ba0400f..baa0db9f8d1 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -96,7 +96,7 @@ pub fn sqrt(x: f64) -> f64 { { // Note: This path is unlikely since LLVM will usually have already // optimized sqrt calls into hardware instructions if sse2 is available, - // but if someone does end up here they'll apprected the speed increase. + // but if someone does end up here they'll appreciate the speed increase. #[cfg(target_arch = "x86")] use core::arch::x86::*; #[cfg(target_arch = "x86_64")] diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 8ec72fbf7fa..12bd60028ee 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -31,7 +31,7 @@ pub fn sqrtf(x: f32) -> f32 { { // Note: This path is unlikely since LLVM will usually have already // optimized sqrt calls into hardware instructions if sse is available, - // but if someone does end up here they'll apprected the speed increase. + // but if someone does end up here they'll appreciate the speed increase. #[cfg(target_arch = "x86")] use core::arch::x86::*; #[cfg(target_arch = "x86_64")] -- cgit 1.4.1-3-g733a5 From f23a83c53cca5a10153420178395e7c7b09a8d5c Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Sun, 7 Apr 2024 09:32:17 -0700 Subject: Add __chkstk on i686-pc-windows-gnu. libLLVMSupport.a(DynamicLibrary.cpp.obj) references ___chkstk, which is an alias of __alloca in libgcc. This crate provided __alloca, but libgcc's implementation was also pulled in by the linker due to the reference to ___chkstk, causing a multiple definition linker error. Providing that symbol here prevents that. Fixes #585 --- library/compiler-builtins/src/x86.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index 5016816eb36..c348d082d9e 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -8,6 +8,19 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt intrinsics! { + #[naked] + #[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn __chkstk() { + core::arch::asm!( + "jmp __alloca", // Jump to __alloca since fallthrough may be unreliable" + options(noreturn, att_syntax) + ); + } + #[naked] #[cfg(all( windows, @@ -15,7 +28,7 @@ intrinsics! { not(feature = "no-asm") ))] pub unsafe extern "C" fn _alloca() { - // _chkstk and _alloca are the same function + // __chkstk and _alloca are the same function core::arch::asm!( "push %ecx", "cmp $0x1000,%eax", -- cgit 1.4.1-3-g733a5 From bf0ce314e9471d95432168a5d812a76a0681d042 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Apr 2024 21:56:02 +0200 Subject: add lib.miri.rs file for miri-test-libstd --- library/compiler-builtins/src/lib.miri.rs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 library/compiler-builtins/src/lib.miri.rs diff --git a/library/compiler-builtins/src/lib.miri.rs b/library/compiler-builtins/src/lib.miri.rs new file mode 100644 index 00000000000..17288058e5e --- /dev/null +++ b/library/compiler-builtins/src/lib.miri.rs @@ -0,0 +1,5 @@ +//! Grep bootstrap for `MIRI_REPLACE_LIBRS_IF_NOT_TEST` to learn what this is about. +#![no_std] +#![feature(rustc_private)] +extern crate compiler_builtins as real; +pub use real::*; -- cgit 1.4.1-3-g733a5 From 5416c204a9173afadc9c69c9ca14ffd71f9ce1e8 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Mon, 19 Feb 2024 16:41:17 +0800 Subject: Always have math functions but with `weak` linking attribute if we can This is a replacement for https://github.com/rust-lang/libm/pull/290 This fixes crashes during compilations for targets that don't have math symbols by default. So, we will provide them libm symbols, but mark it as `weak` (if its supported), so that the linker will choose the system builtin functions, since those are sometimes more optimized. If the linker couldn't find those, it will go with `libm` implementation. --- library/compiler-builtins/src/math.rs | 84 +++++++---------------------------- 1 file changed, 17 insertions(+), 67 deletions(-) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 63d85833393..b04b0b66a75 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -7,6 +7,7 @@ macro_rules! no_mangle { ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { intrinsics! { $( + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), weak)] pub extern "C" fn $fun($($iid: $ity),+) -> $oty { self::libm::$fun($($iid),+) } @@ -15,17 +16,6 @@ macro_rules! no_mangle { } } -#[cfg(any( - all( - target_family = "wasm", - target_os = "unknown", - not(target_env = "wasi") - ), - target_os = "xous", - target_os = "uefi", - all(target_arch = "xtensa", target_os = "none"), - all(target_vendor = "fortanix", target_env = "sgx") -))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; @@ -41,10 +31,6 @@ no_mangle! { fn log10f(x: f32) -> f32; fn log(x: f64) -> f64; fn logf(x: f32) -> f32; - fn fmin(x: f64, y: f64) -> f64; - fn fminf(x: f32, y: f32) -> f32; - fn fmax(x: f64, y: f64) -> f64; - fn fmaxf(x: f32, y: f32) -> f32; fn round(x: f64) -> f64; fn roundf(x: f32) -> f32; fn rint(x: f64) -> f64; @@ -52,8 +38,6 @@ no_mangle! { fn sin(x: f64) -> f64; fn pow(x: f64, y: f64) -> f64; fn powf(x: f32, y: f32) -> f32; - fn fmod(x: f64, y: f64) -> f64; - fn fmodf(x: f32, y: f32) -> f32; fn acosf(n: f32) -> f32; fn atan2f(a: f32, b: f32) -> f32; fn atanf(n: f32) -> f32; @@ -85,67 +69,17 @@ no_mangle! { fn cbrtf(n: f32) -> f32; fn hypotf(x: f32, y: f32) -> f32; fn tanf(n: f32) -> f32; -} - -#[cfg(any( - all( - target_family = "wasm", - target_os = "unknown", - not(target_env = "wasi") - ), - target_os = "xous", - target_os = "uefi", - all(target_arch = "xtensa", target_os = "none"), - all(target_vendor = "fortanix", target_env = "sgx"), - target_os = "windows" -))] -intrinsics! { - pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { - let r = self::libm::lgamma_r(x); - *s = r.1; - r.0 - } - - pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { - let r = self::libm::lgammaf_r(x); - *s = r.1; - r.0 - } -} -#[cfg(any( - target_os = "xous", - target_os = "uefi", - all(target_arch = "xtensa", target_os = "none"), -))] -no_mangle! { fn sqrtf(x: f32) -> f32; fn sqrt(x: f64) -> f64; -} -#[cfg(any( - all(target_vendor = "fortanix", target_env = "sgx"), - all(target_arch = "xtensa", target_os = "none"), - target_os = "xous", - target_os = "uefi" -))] -no_mangle! { fn ceil(x: f64) -> f64; fn ceilf(x: f32) -> f32; fn floor(x: f64) -> f64; fn floorf(x: f32) -> f32; fn trunc(x: f64) -> f64; fn truncf(x: f32) -> f32; -} -// only for the thumb*-none-eabi*, riscv32*-none-elf, x86_64-unknown-none and mips*-unknown-none targets that lack the floating point instruction set -#[cfg(any( - all(target_arch = "arm", target_os = "none"), - all(target_arch = "riscv32", not(target_feature = "f"), target_os = "none"), - all(target_arch = "x86_64", target_os = "none"), - all(target_arch = "mips", target_os = "none"), -))] -no_mangle! { fn fmin(x: f64, y: f64) -> f64; fn fminf(x: f32, y: f32) -> f32; fn fmax(x: f64, y: f64) -> f64; @@ -155,3 +89,19 @@ no_mangle! { // `f32 % f32` fn fmodf(x: f32, y: f32) -> f32; } + +intrinsics! { + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), weak)] + pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { + let r = self::libm::lgamma_r(x); + *s = r.1; + r.0 + } + + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), weak)] + pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { + let r = self::libm::lgammaf_r(x); + *s = r.1; + r.0 + } +} -- cgit 1.4.1-3-g733a5 From 6cf5c13e8762354e9d1334b546286857e1cc7a75 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Sun, 31 Mar 2024 13:53:15 +0300 Subject: Do not include math intrinsics for windows and apple targets --- library/compiler-builtins/src/math.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index b04b0b66a75..593a1a19c46 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -16,6 +16,7 @@ macro_rules! no_mangle { } } +#[cfg(all(not(windows), not(target_vendor = "apple")))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; -- cgit 1.4.1-3-g733a5 From bd48df66bd6d8976fae571cabab47e8840e84387 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 10 Apr 2024 13:16:43 +0100 Subject: Release 0.1.109 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index e94c2f7625f..267f1b950b6 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.108" +version = "0.1.109" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 47f2241db97ab321d74dde297e3a2d9f6fd0215b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 13 Apr 2024 04:32:49 -0400 Subject: Change aarch64_linux module and lse tests to have the same gating Trying to run testcrate on non-linux aarch64 currently hits a compilation error. Make this test linux-only, to be consistent with the `aarch64_linux` module that it depends on. Additionally, enable the `aarch64_linux` module for `target_arch = "arm64ec"` to be the same as these tests. --- library/compiler-builtins/testcrate/tests/lse.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/lse.rs b/library/compiler-builtins/testcrate/tests/lse.rs index 63c98957cf4..cbecd6143e7 100644 --- a/library/compiler-builtins/testcrate/tests/lse.rs +++ b/library/compiler-builtins/testcrate/tests/lse.rs @@ -1,8 +1,5 @@ #![feature(decl_macro)] // so we can use pub(super) -#![cfg(all( - any(target_arch = "aarch64", target_arch = "arm64ec"), - not(feature = "no-asm") -))] +#![cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm")))] /// Translate a byte size to a Rust type. macro int_ty { -- cgit 1.4.1-3-g733a5 From d5bc2de9ec39ff0814d162fb4c06de8bc415ae48 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 16 Apr 2024 03:04:37 -0400 Subject: Add CI testing for AArch64 Darwin The Apple ARM silicon has been around for a while now and hopefully will become Rust Tier 1 at some point. Add it to CI since it is distinct enough from aarch64-linux and x86_86-darwin that there may be differences. --- library/compiler-builtins/.github/workflows/main.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 97d298cf09c..57497e05001 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -9,6 +9,9 @@ jobs: fail-fast: false matrix: include: + - target: aarch64-apple-darwin + os: macos-14 + rust: nightly - target: aarch64-unknown-linux-gnu os: ubuntu-latest rust: nightly @@ -81,6 +84,8 @@ jobs: os: windows-latest rust: nightly-x86_64-gnu steps: + - name: Print runner information + run: uname -a - uses: actions/checkout@v4 with: submodules: true -- cgit 1.4.1-3-g733a5 From a55604fd8c2830de66c241b297872c55ea3ab3c2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 13 Apr 2024 00:42:36 -0400 Subject: Add a way to run tests on non-linux machines Allow using the `rust-lang/rust:nightly` docker image to run tests in cases where the host rust and cargo cannot be used, such as non-linux hosts. --- library/compiler-builtins/.gitignore | 2 + library/compiler-builtins/README.md | 20 +++++ library/compiler-builtins/build.rs | 4 +- .../ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 3 +- .../ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 3 +- .../docker/arm-unknown-linux-gnueabihf/Dockerfile | 3 +- .../armv7-unknown-linux-gnueabihf/Dockerfile | 3 +- .../ci/docker/i586-unknown-linux-gnu/Dockerfile | 3 +- .../ci/docker/i686-unknown-linux-gnu/Dockerfile | 3 +- .../ci/docker/mips-unknown-linux-gnu/Dockerfile | 3 +- .../mips64-unknown-linux-gnuabi64/Dockerfile | 3 +- .../mips64el-unknown-linux-gnuabi64/Dockerfile | 3 +- .../ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 3 +- .../ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 3 +- .../docker/powerpc64-unknown-linux-gnu/Dockerfile | 3 +- .../powerpc64le-unknown-linux-gnu/Dockerfile | 3 +- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 3 +- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 3 +- .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 3 +- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 3 +- .../ci/docker/wasm32-unknown-unknown/Dockerfile | 3 +- .../ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 3 +- library/compiler-builtins/ci/run-docker.sh | 73 +++++++++++++----- library/compiler-builtins/ci/run.sh | 88 ++++++++++++++-------- 24 files changed, 176 insertions(+), 68 deletions(-) diff --git a/library/compiler-builtins/.gitignore b/library/compiler-builtins/.gitignore index b203ea61f2a..97df30ffaa8 100644 --- a/library/compiler-builtins/.gitignore +++ b/library/compiler-builtins/.gitignore @@ -1,3 +1,5 @@ *.rs.bk Cargo.lock target +compiler-rt +*.tar.gz diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index ffef4e52c79..5a364a23d1a 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -78,6 +78,26 @@ features = ["c"] [8]: http://en.cppreference.com/w/cpp/language/implicit_conversion [9]: https://doc.rust-lang.org/std/primitive.i32.html +## Testing + +The easiest way to test locally is using Docker. This can be done by running +`./ci/run-docker.sh [target]`. If no target is specified, all targets will be +run. + +In order to run the full test suite, you will also need the C compiler runtime +to test against, located in a directory called `compiler-rt`. This can be +obtained with the following: + +```sh +curl -L -o rustc-llvm-18.0.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/18.0-2024-02-13.tar.gz +tar xzf rustc-llvm-18.0.tar.gz --strip-components 1 llvm-project-rustc-18.0-2024-02-13/compiler-rt +```` + +Local targets may also be tested with `./ci/run.sh [target]`. + +Note that testing may not work on all hosts, in which cases it is acceptable to +rely on CI. + ## Progress - [x] adddf3.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 44946c1240c..bb2dba97ae1 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -572,7 +572,9 @@ mod c { // rust-lang/rust. let root = match env::var_os("RUST_COMPILER_RT_ROOT") { Some(s) => PathBuf::from(s), - None => panic!("RUST_COMPILER_RT_ROOT is not set"), + None => { + panic!("RUST_COMPILER_RT_ROOT is not set. You may need to download compiler-rt.") + } }; if !root.exists() { panic!("RUST_COMPILER_RT_ROOT={} does not exist", root.display()); diff --git a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index 9e2559f4ab3..5de76efc375 100644 --- a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile index afab874bc28..dc95da0f3c5 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile index 3ed3602b0dc..55e5e3d5754 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile index 6617af1558c..fd2ad18d1a3 100644 --- a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile index 5783e28e122..f161ec76725 100644 --- a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc-multilib libc6-dev ca-certificates diff --git a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile index 5783e28e122..f161ec76725 100644 --- a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc-multilib libc6-dev ca-certificates diff --git a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile index f47e8f5227b..042dd4219de 100644 --- a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile index 8fa77c7bd07..45b3089c9ed 100644 --- a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile index c6611d9ac89..bda6be1d674 100644 --- a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile index 0bc69562462..702a26ec1a5 100644 --- a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile index 2d39fef6142..6bae7cb3b65 100644 --- a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile index 653cd351156..2c315e509e3 100644 --- a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile index 63ea9af9d20..da8f9db604b 100644 --- a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index dc7dd431ba3..d7256a9c533 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index dc7dd431ba3..d7256a9c533 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index dc7dd431ba3..d7256a9c533 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index dc7dd431ba3..d7256a9c533 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile index 85ead29aaee..4d12b6ff426 100644 --- a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile +++ b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:20.04 +ARG IMAGE=ubuntu:20.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc clang libc6-dev ca-certificates diff --git a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile index 98000f4eb81..d495d5044ad 100644 --- a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 8c4af0eff20..81964303935 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -1,38 +1,77 @@ +#!/bin/bash + # Small script to run tests for a target (or all targets) inside all the # respective docker images. -set -ex +set -eux run() { - local target=$1 + local target="$1" - echo $target + echo "TESTING TARGET: $target" # This directory needs to exist before calling docker, otherwise docker will create it but it # will be owned by root mkdir -p target - docker build -t $target ci/docker/$target + if [ $(uname -s) = "Linux" ] && [ -z "${DOCKER_BASE_IMAGE:-}" ]; then + # Share the host rustc and target. Do this only on Linux and if the image + # isn't overridden + run_args=( + --user "$(id -u):$(id -g)" + -e "CARGO_HOME=/cargo" + -v "${HOME}/.cargo:/cargo" + -v "$(pwd)/target:/builtins-target" + -v "$(rustc --print sysroot):/rust:ro" + ) + run_cmd="HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" + else + # Use rustc provided by a docker image + docker volume create compiler-builtins-cache + build_args=( + "--build-arg" "IMAGE=${DOCKER_BASE_IMAGE:-rustlang/rust:nightly}" + ) + run_args=( + -v "compiler-builtins-cache:/builtins-target" + ) + run_cmd="HOME=/tmp USING_CONTAINER_RUSTC=1 ci/run.sh $target" + fi + + if [ -d compiler-rt ]; then + export RUST_COMPILER_RT_ROOT=./compiler-rt + fi + + docker build \ + -t "builtins-$target" \ + ${build_args[@]:-} \ + "ci/docker/$target" docker run \ --rm \ - --user $(id -u):$(id -g) \ - -e CARGO_HOME=/cargo \ - -e CARGO_TARGET_DIR=/target \ -e RUST_COMPILER_RT_ROOT \ - -v "${HOME}/.cargo":/cargo \ - -v `pwd`/target:/target \ - -v `pwd`:/checkout:ro \ - -v `rustc --print sysroot`:/rust:ro \ + -e "CARGO_TARGET_DIR=/builtins-target" \ + -v "$(pwd):/checkout:ro" \ -w /checkout \ + ${run_args[@]:-} \ --init \ - $target \ - sh -c "HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" + "builtins-$target" \ + sh -c "$run_cmd" } -if [ -z "$1" ]; then - for d in `ls ci/docker/`; do - run $d +if [ "${1:-}" = "--help" ] || [ "$#" -gt 1 ]; then + set +x + echo "\ + usage: ./ci/run-docker.sh [target] + + you can also set DOCKER_BASE_IMAGE to use something other than the default + ubuntu:18.04 (or rustlang/rust:nightly). + " + exit +fi + +if [ -z "${1:-}" ]; then + for d in ci/docker/*; do + run $(basename "$d") done else - run $1 + run "$1" fi diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 09728191a22..d2ea797310e 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,10 +1,25 @@ -set -ex +set -eux + +target="${1:-}" + +if [ -z "${1:-}" ]; then + host_target=$(rustc -vV | awk '/^host/ { print $2 }') + echo "Defaulted to host target $host_target" + target="$host_target" +fi + +if [ "${USING_CONTAINER_RUSTC:-}" = 1 ]; then + # Install nonstandard components if we have control of the environment + rustup target list --installed | + grep -E "^$target\$" || + rustup target add "$target" +fi # Test our implementation -if [ "$NO_STD" = "1" ]; then - echo nothing to do +if [ "${NO_STD:-}" = "1" ]; then + echo "nothing to do for no_std" else - run="cargo test --manifest-path testcrate/Cargo.toml --target $1" + run="cargo test --manifest-path testcrate/Cargo.toml --target $target" $run $run --release $run --features c @@ -13,24 +28,24 @@ else $run --features no-asm --release fi -if [ -d /target ]; then - path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib +if [ -d /builtins-target ]; then + path=/builtins-target/${target}/debug/deps/libcompiler_builtins-*.rlib else - path=target/${1}/debug/deps/libcompiler_builtins-*.rlib + path=target/${target}/debug/deps/libcompiler_builtins-*.rlib fi # Remove any existing artifacts from previous tests that don't set #![compiler_builtins] rm -f $path -cargo build --target $1 -cargo build --target $1 --release -cargo build --target $1 --features c -cargo build --target $1 --release --features c -cargo build --target $1 --features no-asm -cargo build --target $1 --release --features no-asm +cargo build --target "$target" +cargo build --target "$target" --release +cargo build --target "$target" --features c +cargo build --target "$target" --release --features c +cargo build --target "$target" --features no-asm +cargo build --target "$target" --release --features no-asm -PREFIX=$(echo $1 | sed -e 's/unknown-//')- -case $1 in +PREFIX=$(echo "$target" | sed -e 's/unknown-//')- +case "$target" in armv7-*) PREFIX=arm-linux-gnueabihf- ;; @@ -44,12 +59,12 @@ esac NM=$(find $(rustc --print sysroot) \( -name llvm-nm -o -name llvm-nm.exe \) ) if [ "$NM" = "" ]; then - NM=${PREFIX}nm + NM="${PREFIX}nm" fi # i686-pc-windows-gnu tools have a dependency on some DLLs, so run it with # rustup run to ensure that those are in PATH. -TOOLCHAIN=$(rustup show active-toolchain | sed 's/ (default)//') -if [[ $TOOLCHAIN == *i686-pc-windows-gnu ]]; then +TOOLCHAIN="$(rustup show active-toolchain | sed 's/ (default)//')" +if [[ "$TOOLCHAIN" == *i686-pc-windows-gnu ]]; then NM="rustup run $TOOLCHAIN $NM" fi @@ -57,7 +72,7 @@ fi for rlib in $(echo $path); do set +x echo "================================================================" - echo checking $rlib for duplicate symbols + echo "checking $rlib for duplicate symbols" echo "================================================================" stdout=$($NM -g --defined-only $rlib 2>&1) @@ -80,7 +95,7 @@ done rm -f $path # Verify that we haven't drop any intrinsic/symbol -build_intrinsics="cargo build --target $1 -v --example intrinsics" +build_intrinsics="cargo build --target "$target" -v --example intrinsics" $build_intrinsics $build_intrinsics --release $build_intrinsics --features c @@ -89,25 +104,36 @@ $build_intrinsics --features c --release # Verify that there are no undefined symbols to `panic` within our # implementations CARGO_PROFILE_DEV_LTO=true \ - cargo build --target $1 --example intrinsics + cargo build --target "$target" --example intrinsics CARGO_PROFILE_RELEASE_LTO=true \ - cargo build --target $1 --example intrinsics --release + cargo build --target "$target" --example intrinsics --release # Ensure no references to any symbols from core for rlib in $(echo $path); do - set +ex + set +x echo "================================================================" - echo checking $rlib for references to core + echo "checking $rlib for references to core" echo "================================================================" - - $NM --quiet -U $rlib | grep 'T _ZN4core' | awk '{print $3}' | sort | uniq > defined_symbols.txt - $NM --quiet -u $rlib | grep 'U _ZN4core' | awk '{print $2}' | sort | uniq > undefined_symbols.txt - grep -v -F -x -f defined_symbols.txt undefined_symbols.txt - - if test $? = 0; then + set -x + + tmpdir="${CARGO_TARGET_DIR:-target}/tmp" + test -d "$tmpdir" || mkdir "$tmpdir" + defined="$tmpdir/defined_symbols.txt" + undefined="$tmpdir/defined_symbols.txt" + + $NM --quiet -U $rlib | grep 'T _ZN4core' | awk '{print $3}' | sort | uniq > "$defined" + $NM --quiet -u $rlib | grep 'U _ZN4core' | awk '{print $2}' | sort | uniq > "$undefined" + grep_failed=0 + grep -v -F -x -f "$defined" "$undefined" && grep_failed=1 + + if [ "$target" = "powerpc64-unknown-linux-gnu" ]; then + echo "FIXME: powerpc64 fails these tests" + elif [ "$grep_failed" != 0 ]; then + echo "error: found unexpected references to core" exit 1 + else + echo "success; no references to core found" fi - set -ex done true -- cgit 1.4.1-3-g733a5 From 1b679e5cee1ae035b531c4101f09b73b94ce209f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 15 Apr 2024 14:44:39 -0400 Subject: Apply some more fixes suggested by Shellcheck --- library/compiler-builtins/ci/run-docker.sh | 2 +- library/compiler-builtins/ci/run.sh | 64 ++++++++++++++++-------------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 81964303935..b85f64133a7 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -3,7 +3,7 @@ # Small script to run tests for a target (or all targets) inside all the # respective docker images. -set -eux +set -euxo pipefail run() { local target="$1" diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index d2ea797310e..65fffec5fdd 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,3 +1,5 @@ +#!/bin/bash + set -eux target="${1:-}" @@ -29,13 +31,13 @@ else fi if [ -d /builtins-target ]; then - path=/builtins-target/${target}/debug/deps/libcompiler_builtins-*.rlib + rlib_paths=/builtins-target/"${target}"/debug/deps/libcompiler_builtins-*.rlib else - path=target/${target}/debug/deps/libcompiler_builtins-*.rlib + rlib_paths=target/"${target}"/debug/deps/libcompiler_builtins-*.rlib fi # Remove any existing artifacts from previous tests that don't set #![compiler_builtins] -rm -f $path +rm -f $rlib_paths cargo build --target "$target" cargo build --target "$target" --release @@ -44,7 +46,7 @@ cargo build --target "$target" --release --features c cargo build --target "$target" --features no-asm cargo build --target "$target" --release --features no-asm -PREFIX=$(echo "$target" | sed -e 's/unknown-//')- +PREFIX=${target//unknown-/}- case "$target" in armv7-*) PREFIX=arm-linux-gnueabihf- @@ -57,7 +59,7 @@ case "$target" in ;; esac -NM=$(find $(rustc --print sysroot) \( -name llvm-nm -o -name llvm-nm.exe \) ) +NM=$(find "$(rustc --print sysroot)" \( -name llvm-nm -o -name llvm-nm.exe \) ) if [ "$NM" = "" ]; then NM="${PREFIX}nm" fi @@ -69,37 +71,41 @@ if [[ "$TOOLCHAIN" == *i686-pc-windows-gnu ]]; then fi # Look out for duplicated symbols when we include the compiler-rt (C) implementation -for rlib in $(echo $path); do +for rlib in $rlib_paths; do set +x echo "================================================================" echo "checking $rlib for duplicate symbols" echo "================================================================" + + duplicates_found=0 - stdout=$($NM -g --defined-only $rlib 2>&1) # NOTE On i586, It's normal that the get_pc_thunk symbol appears several # times so ignore it - set +e - echo "$stdout" | \ - sort | \ - uniq -d | \ - grep -v __x86.get_pc_thunk | \ - grep 'T __' - - if test $? = 0; then + $NM -g --defined-only "$rlib" 2>&1 | + sort | + uniq -d | + grep -v __x86.get_pc_thunk --quiet | + grep 'T __' && duplicates_found=1 + + if [ "$duplicates_found" != 0 ]; then + echo "error: found duplicate symbols" exit 1 + else + echo "success; no duplicate symbols found" fi - - set -ex done -rm -f $path +rm -f $rlib_paths + +build_intrinsics() { + cargo build --target "$target" -v --example intrinsics "$@" +} # Verify that we haven't drop any intrinsic/symbol -build_intrinsics="cargo build --target "$target" -v --example intrinsics" -$build_intrinsics -$build_intrinsics --release -$build_intrinsics --features c -$build_intrinsics --features c --release +build_intrinsics +build_intrinsics --release +build_intrinsics --features c +build_intrinsics --features c --release # Verify that there are no undefined symbols to `panic` within our # implementations @@ -109,7 +115,7 @@ CARGO_PROFILE_RELEASE_LTO=true \ cargo build --target "$target" --example intrinsics --release # Ensure no references to any symbols from core -for rlib in $(echo $path); do +for rlib in $(echo $rlib_paths); do set +x echo "================================================================" echo "checking $rlib for references to core" @@ -121,14 +127,14 @@ for rlib in $(echo $path); do defined="$tmpdir/defined_symbols.txt" undefined="$tmpdir/defined_symbols.txt" - $NM --quiet -U $rlib | grep 'T _ZN4core' | awk '{print $3}' | sort | uniq > "$defined" - $NM --quiet -u $rlib | grep 'U _ZN4core' | awk '{print $2}' | sort | uniq > "$undefined" - grep_failed=0 - grep -v -F -x -f "$defined" "$undefined" && grep_failed=1 + $NM --quiet -U "$rlib" | grep 'T _ZN4core' | awk '{print $3}' | sort | uniq > "$defined" + $NM --quiet -u "$rlib" | grep 'U _ZN4core' | awk '{print $2}' | sort | uniq > "$undefined" + grep_has_results=0 + grep -v -F -x -f "$defined" "$undefined" && grep_has_results=1 if [ "$target" = "powerpc64-unknown-linux-gnu" ]; then echo "FIXME: powerpc64 fails these tests" - elif [ "$grep_failed" != 0 ]; then + elif [ "$grep_has_results" != 0 ]; then echo "error: found unexpected references to core" exit 1 else -- cgit 1.4.1-3-g733a5 From a2587f7b028b28f65879512e61a6b67acaad2384 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 28 Apr 2024 17:41:35 +0100 Subject: Update status of 128-bit integers in README.md --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 5a364a23d1a..0c97690ca82 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -212,7 +212,7 @@ rely on CI. - [x] umodsi3.c - [x] x86_64/chkstk.S -These builtins are needed to support 128-bit integers, which are in the process of being added to Rust. +These builtins are needed to support 128-bit integers. - [x] ashlti3.c - [x] ashrti3.c -- cgit 1.4.1-3-g733a5 From 1b15dd5eb2a8a8acfbae2f08bf92a8aed3471395 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:14:55 +0800 Subject: Fix `clippy::deprecated_cfg_attr` on compiler_builtins --- library/compiler-builtins/libm/src/math/exp2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index e0e385df2e7..dce2ab4df6f 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -28,7 +28,7 @@ use super::scalbn; const TBLSIZE: usize = 256; -#[cfg_attr(rustfmt, rustfmt_skip)] +#[rustfmt::skip] static TBL: [u64; TBLSIZE * 2] = [ // exp2(z + eps) eps 0x3fe6a09e667f3d5d, 0x3d39880000000000, -- cgit 1.4.1-3-g733a5 From 2ce9bc0cc107d2f7c07962ce55cf5ba6ccf58c18 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Mon, 15 Apr 2024 19:14:41 +0800 Subject: Fix math libraries not being linked on some platforms This is a continuation/fix of 018616e. In that commit, we made it add the math functions to all platforms (except apple-targets and windows), and use `weak` linking, so that it can be used if the system doesn't have those functions. Didn't notice `mod math` was behind another set of `cfg`, so removed it as well here. --- library/compiler-builtins/src/lib.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index a414efde0ce..da438de7778 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -45,14 +45,6 @@ mod macros; pub mod float; pub mod int; -#[cfg(any( - all(target_family = "wasm", target_os = "unknown"), - target_os = "uefi", - target_os = "none", - target_os = "xous", - all(target_vendor = "fortanix", target_env = "sgx"), - target_os = "windows" -))] pub mod math; pub mod mem; -- cgit 1.4.1-3-g733a5 From f761f0382295a13c42bc5f96f9a0e1af6f4b5cd9 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Mon, 15 Apr 2024 19:37:48 +0800 Subject: Fix clippy warnings in `math` The solution is not pretty, but not sure why we still get clippy warning from one of the files in `libm` even though we use `allow(clippy::all)` --- library/compiler-builtins/src/lib.rs | 3 +++ library/compiler-builtins/src/math.rs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index da438de7778..e7975098c9f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -45,6 +45,9 @@ mod macros; pub mod float; pub mod int; +// For some reason, we still get clippy error `clippy::deprecated_cfg_attr` even though, we have +// used `allow(clippy::all)` in the file. So, we are disabling the clippy check for this file. +#[cfg(not(clippy))] pub mod math; pub mod mem; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 593a1a19c46..e47b834e446 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -1,4 +1,6 @@ #[allow(dead_code)] +#[allow(unused_imports)] +#[allow(clippy::all)] #[path = "../libm/src/math/mod.rs"] mod libm; -- cgit 1.4.1-3-g733a5 From 656106f0506960732b8d3d9caf9259e37c6c8c4f Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Tue, 30 Apr 2024 18:40:45 +0800 Subject: Updated `libm` to fix `clippy` warning --- library/compiler-builtins/libm | 2 +- library/compiler-builtins/src/lib.rs | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 721a5edc1be..a1e8a5bf95e 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 721a5edc1be6b0412e4b1704590aed76f9a55899 +Subproject commit a1e8a5bf95e99309760b764b2a332d0039d08350 diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index e7975098c9f..da438de7778 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -45,9 +45,6 @@ mod macros; pub mod float; pub mod int; -// For some reason, we still get clippy error `clippy::deprecated_cfg_attr` even though, we have -// used `allow(clippy::all)` in the file. So, we are disabling the clippy check for this file. -#[cfg(not(clippy))] pub mod math; pub mod mem; -- cgit 1.4.1-3-g733a5 From 229babb1d078ecd44def70abdd50ee5bf7a35945 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 14 Apr 2024 08:05:18 +0100 Subject: Add builtins for `f16`/`f128` float conversions --- library/compiler-builtins/Cargo.toml | 4 + library/compiler-builtins/README.md | 61 ++++++----- library/compiler-builtins/build.rs | 21 ++-- library/compiler-builtins/ci/run.sh | 4 + library/compiler-builtins/src/float/extend.rs | 34 ++++++ library/compiler-builtins/src/float/mod.rs | 19 +++- library/compiler-builtins/src/float/trunc.rs | 55 +++++++++- library/compiler-builtins/src/lib.rs | 2 + library/compiler-builtins/testcrate/Cargo.toml | 5 +- library/compiler-builtins/testcrate/tests/conv.rs | 125 ++++++++++++++++++++++ library/compiler-builtins/testcrate/tests/misc.rs | 68 ------------ 11 files changed, 283 insertions(+), 115 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 267f1b950b6..96e85d7b5fb 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -49,6 +49,10 @@ c = ["cc"] # which use inline assembly and fall back to pure Rust versions (if avalible). no-asm = [] +# Workaround for codegen backends which haven't yet implemented `f16` and +# `f128` support. Disabled any intrinsics which use those types. +no-f16-f128 = [] + # Flag this library as the unstable compiler-builtins lib compiler-builtins = [] diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 0c97690ca82..00d547f1bdb 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -162,7 +162,6 @@ rely on CI. - [x] divmodsi4.c - [x] divsf3.c - [x] divsi3.c -- [ ] extendhfsf2.c - [x] extendsfdf2.c - [x] fixdfdi.c - [x] fixdfsi.c @@ -201,9 +200,7 @@ rely on CI. - [x] powisf2.c - [x] subdf3.c - [x] subsf3.c -- [ ] truncdfhf2.c - [x] truncdfsf2.c -- [ ] truncsfhf2.c - [x] udivdi3.c - [x] udivmoddi4.c - [x] udivmodsi4.c @@ -233,60 +230,68 @@ These builtins are needed to support 128-bit integers. - [x] udivti3.c - [x] umodti3.c +These builtins are needed to support `f16` and `f128`, which are in the process of being added to Rust. + +- [ ] addtf3.c +- [ ] comparetf2.c +- [ ] divtf3.c +- [x] extenddftf2.c +- [x] extendhfsf2.c +- [x] extendhftf2.c +- [x] extendsftf2.c +- [ ] fixtfdi.c +- [ ] fixtfsi.c +- [ ] fixtfti.c +- [ ] fixunstfdi.c +- [ ] fixunstfsi.c +- [ ] fixunstfti.c +- [ ] floatditf.c +- [ ] floatsitf.c +- [ ] floatunditf.c +- [ ] floatunsitf.c +- [ ] multf3.c +- [ ] powitf2.c +- [ ] ppc/fixtfdi.c +- [ ] ppc/fixunstfdi.c +- [ ] ppc/floatditf.c +- [ ] ppc/floatunditf.c +- [ ] subtf3.c +- [x] truncdfhf2.c +- [x] truncsfhf2.c +- [x] trunctfdf2.c +- [x] trunctfhf2.c +- [x] trunctfsf2.c + ## Unimplemented functions -These builtins involve floating-point types ("`f128`", "`f80`" and complex numbers) that are not supported by Rust. +These builtins involve floating-point types ("`f80`" and complex numbers) that are not supported by Rust. -- ~~addtf3.c~~ -- ~~comparetf2.c~~ - ~~divdc3.c~~ - ~~divsc3.c~~ - ~~divtc3.c~~ -- ~~divtf3.c~~ - ~~divxc3.c~~ -- ~~extenddftf2.c~~ -- ~~extendsftf2.c~~ -- ~~fixtfdi.c~~ -- ~~fixtfsi.c~~ -- ~~fixtfti.c~~ -- ~~fixunstfdi.c~~ -- ~~fixunstfsi.c~~ -- ~~fixunstfti.c~~ - ~~fixunsxfdi.c~~ - ~~fixunsxfsi.c~~ - ~~fixunsxfti.c~~ - ~~fixxfdi.c~~ - ~~fixxfti.c~~ -- ~~floatditf.c~~ - ~~floatdixf.c~~ -- ~~floatsitf.c~~ - ~~floattixf.c~~ -- ~~floatunditf.c~~ - ~~floatundixf.c~~ -- ~~floatunsitf.c~~ - ~~floatuntixf.c~~ - ~~i386/floatdixf.S~~ - ~~i386/floatundixf.S~~ - ~~muldc3.c~~ - ~~mulsc3.c~~ - ~~multc3.c~~ -- ~~multf3.c~~ - ~~mulxc3.c~~ -- ~~powitf2.c~~ - ~~powixf2.c~~ - ~~ppc/divtc3.c~~ -- ~~ppc/fixtfdi.c~~ -- ~~ppc/fixunstfdi.c~~ -- ~~ppc/floatditf.c~~ -- ~~ppc/floatunditf.c~~ - ~~ppc/gcc_qadd.c~~ - ~~ppc/gcc_qdiv.c~~ - ~~ppc/gcc_qmul.c~~ - ~~ppc/gcc_qsub.c~~ - ~~ppc/multc3.c~~ -- ~~subtf3.c~~ -- ~~trunctfdf2.c~~ -- ~~trunctfsf2.c~~ - ~~x86_64/floatdixf.c~~ - ~~x86_64/floatundixf.S~~ diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index bb2dba97ae1..bafbf75d068 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -217,6 +217,14 @@ mod c { } } + // `compiler-rt` requires `COMPILER_RT_HAS_FLOAT16` to be defined to make it use the + // `_Float16` type for `f16` intrinsics. This shouldn't matter as all existing `f16` + // intrinsics have been ported to Rust in `compiler-builtins` as C compilers don't + // support `_Float16` on all targets (whereas Rust does). However, define the macro + // anyway to prevent issues like rust#118813 and rust#123885 silently reoccuring if more + // `f16` intrinsics get accidentally added here in the future. + cfg.define("COMPILER_RT_HAS_FLOAT16", None); + cfg.warnings(false); if target_env == "msvc" { @@ -288,13 +296,10 @@ mod c { sources.extend(&[ ("__divdc3", "divdc3.c"), ("__divsc3", "divsc3.c"), - ("__extendhfsf2", "extendhfsf2.c"), ("__muldc3", "muldc3.c"), ("__mulsc3", "mulsc3.c"), ("__negdf2", "negdf2.c"), ("__negsf2", "negsf2.c"), - ("__truncdfhf2", "truncdfhf2.c"), - ("__truncsfhf2", "truncsfhf2.c"), ]); } @@ -464,8 +469,6 @@ mod c { if (target_arch == "aarch64" || target_arch == "arm64ec") && consider_float_intrinsics { sources.extend(&[ ("__comparetf2", "comparetf2.c"), - ("__extenddftf2", "extenddftf2.c"), - ("__extendsftf2", "extendsftf2.c"), ("__fixtfdi", "fixtfdi.c"), ("__fixtfsi", "fixtfsi.c"), ("__fixtfti", "fixtfti.c"), @@ -476,8 +479,6 @@ mod c { ("__floatsitf", "floatsitf.c"), ("__floatunditf", "floatunditf.c"), ("__floatunsitf", "floatunsitf.c"), - ("__trunctfdf2", "trunctfdf2.c"), - ("__trunctfsf2", "trunctfsf2.c"), ("__addtf3", "addtf3.c"), ("__multf3", "multf3.c"), ("__subtf3", "subtf3.c"), @@ -498,7 +499,6 @@ mod c { if target_arch == "mips64" { sources.extend(&[ - ("__extenddftf2", "extenddftf2.c"), ("__netf2", "comparetf2.c"), ("__addtf3", "addtf3.c"), ("__multf3", "multf3.c"), @@ -509,14 +509,11 @@ mod c { ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), ("__divtf3", "divtf3.c"), - ("__trunctfdf2", "trunctfdf2.c"), - ("__trunctfsf2", "trunctfsf2.c"), ]); } if target_arch == "loongarch64" { sources.extend(&[ - ("__extenddftf2", "extenddftf2.c"), ("__netf2", "comparetf2.c"), ("__addtf3", "addtf3.c"), ("__multf3", "multf3.c"), @@ -527,8 +524,6 @@ mod c { ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), ("__divtf3", "divtf3.c"), - ("__trunctfdf2", "trunctfdf2.c"), - ("__trunctfsf2", "trunctfsf2.c"), ]); } diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 65fffec5fdd..1298093a658 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -28,6 +28,8 @@ else $run --features c --release $run --features no-asm $run --features no-asm --release + $run --features no-f16-f128 + $run --features no-f16-f128 --release fi if [ -d /builtins-target ]; then @@ -45,6 +47,8 @@ cargo build --target "$target" --features c cargo build --target "$target" --release --features c cargo build --target "$target" --features no-asm cargo build --target "$target" --release --features no-asm +cargo build --target "$target" --features no-f16-f128 +cargo build --target "$target" --release --features no-f16-f128 PREFIX=${target//unknown-/}- case "$target" in diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 0e6673b9c09..7c2446603f2 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -82,3 +82,37 @@ intrinsics! { a as f64 // LLVM generate 'fcvtds' } } + +#[cfg(not(feature = "no-f16-f128"))] +intrinsics! { + #[avr_skip] + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_h2f] + pub extern "C" fn __extendhfsf2(a: f16) -> f32 { + extend(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __gnu_h2f_ieee(a: f16) -> f32 { + extend(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __extendhftf2(a: f16) -> f128 { + extend(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __extendsftf2(a: f32) -> f128 { + extend(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __extenddftf2(a: f64) -> f128 { + extend(a) + } +} diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index fdbe9dde35b..a82dd7d2a3b 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -127,7 +127,20 @@ macro_rules! float_impl { self.to_bits() as Self::SignedInt } fn eq_repr(self, rhs: Self) -> bool { - if self.is_nan() && rhs.is_nan() { + #[cfg(feature = "mangled-names")] + fn is_nan(x: $ty) -> bool { + // When using mangled-names, the "real" compiler-builtins might not have the + // necessary builtin (__unordtf2) to test whether `f128` is NaN. + // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin + // x is NaN if all the bits of the exponent are set and the significand is non-0 + x.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK + && x.repr() & $ty::SIGNIFICAND_MASK != 0 + } + #[cfg(not(feature = "mangled-names"))] + fn is_nan(x: $ty) -> bool { + x.is_nan() + } + if is_nan(self) && is_nan(rhs) { true } else { self.repr() == rhs.repr() @@ -171,5 +184,9 @@ macro_rules! float_impl { }; } +#[cfg(not(feature = "no-f16-f128"))] +float_impl!(f16, u16, i16, i8, 16, 10); float_impl!(f32, u32, i32, i16, 32, 23); float_impl!(f64, u64, i64, i16, 64, 52); +#[cfg(not(feature = "no-f16-f128"))] +float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 0beeb9f98de..6de446c1006 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -52,8 +52,10 @@ where // destination format. We can convert by simply right-shifting with // rounding and adjusting the exponent. abs_result = (a_abs >> sign_bits_delta).cast(); - let tmp = src_exp_bias.wrapping_sub(dst_exp_bias) << R::SIGNIFICAND_BITS; - abs_result = abs_result.wrapping_sub(tmp.cast()); + // Cast before shifting to prevent overflow. + let bias_diff: R::Int = src_exp_bias.wrapping_sub(dst_exp_bias).cast(); + let tmp = bias_diff << R::SIGNIFICAND_BITS; + abs_result = abs_result.wrapping_sub(tmp); let round_bits = a_abs & round_mask; if round_bits > halfway { @@ -67,13 +69,17 @@ where // a is NaN. // Conjure the result by beginning with infinity, setting the qNaN // bit and inserting the (truncated) trailing NaN field. - abs_result = (dst_inf_exp << R::SIGNIFICAND_BITS).cast(); + // Cast before shifting to prevent overflow. + let dst_inf_exp: R::Int = dst_inf_exp.cast(); + abs_result = dst_inf_exp << R::SIGNIFICAND_BITS; abs_result |= dst_qnan; abs_result |= dst_nan_code & ((a_abs & src_nan_code) >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast(); } else if a_abs >= overflow { // a overflows to infinity. - abs_result = (dst_inf_exp << R::SIGNIFICAND_BITS).cast(); + // Cast before shifting to prevent overflow. + let dst_inf_exp: R::Int = dst_inf_exp.cast(); + abs_result = dst_inf_exp << R::SIGNIFICAND_BITS; } else { // a underflows on conversion to the destination type or is an exact // zero. The result may be a denormal or zero. Extract the exponent @@ -124,3 +130,44 @@ intrinsics! { a as f32 } } + +#[cfg(not(feature = "no-f16-f128"))] +intrinsics! { + #[avr_skip] + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_f2h] + pub extern "C" fn __truncsfhf2(a: f32) -> f16 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __gnu_f2h_ieee(a: f32) -> f16 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_d2h] + pub extern "C" fn __truncdfhf2(a: f64) -> f16 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __trunctfhf2(a: f128) -> f16 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __trunctfsf2(a: f128) -> f32 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __trunctfdf2(a: f128) -> f64 { + trunc(a) + } +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index da438de7778..40564178a24 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -13,6 +13,8 @@ #![feature(naked_functions)] #![feature(repr_simd)] #![feature(c_unwind)] +#![cfg_attr(not(feature = "no-f16-f128"), feature(f16))] +#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))] #![no_builtins] #![no_std] #![allow(unused_features)] diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 762d3293b2b..6ff3fde1705 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -2,7 +2,7 @@ name = "testcrate" version = "0.1.0" authors = ["Alex Crichton "] -edition = "2018" +edition = "2021" [lib] test = false @@ -13,6 +13,8 @@ doctest = false # problems with system RNGs on the variety of platforms this crate is tested on. # `xoshiro128**` is used for its quality, size, and speed at generating `u32` shift amounts. rand_xoshiro = "0.6" +# To compare float builtins against +rustc_apfloat = "0.2.0" [dependencies.compiler_builtins] path = ".." @@ -28,5 +30,6 @@ utest-macros = { git = "https://github.com/japaric/utest" } default = ["mangled-names"] c = ["compiler_builtins/c"] no-asm = ["compiler_builtins/no-asm"] +no-f16-f128 = ["compiler_builtins/no-f16-f128"] mem = ["compiler_builtins/mem"] mangled-names = ["compiler_builtins/mangled-names"] diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 2a70db17890..84828dbfa6c 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -1,3 +1,13 @@ +#![cfg_attr(not(feature = "no-f16-f128"), feature(f16))] +#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))] +// makes configuration easier +#![allow(unused_macros)] + +use compiler_builtins::float::Float; +use rustc_apfloat::ieee::{Double, Single}; +#[cfg(not(feature = "no-f16-f128"))] +use rustc_apfloat::ieee::{Half, Quad}; +use rustc_apfloat::{Float as _, FloatConvert as _}; use testcrate::*; macro_rules! i_to_f { @@ -130,3 +140,118 @@ fn float_to_int() { ); }); } + +macro_rules! conv { + ($fX:ident, $fD:ident, $fn:ident, $apfloatX:ident, $apfloatD:ident) => { + fuzz_float(N, |x: $fX| { + let tmp0: $apfloatD = $apfloatX::from_bits(x.to_bits().into()) + .convert(&mut false) + .value; + let tmp0 = $fD::from_bits(tmp0.to_bits().try_into().unwrap()); + let tmp1: $fD = $fn(x); + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({x:?}): apfloat: {tmp0:?}, builtins: {tmp1:?}", + stringify!($fn) + ); + } + }); + }; +} + +macro_rules! extend { + ($fX:ident, $fD:ident, $fn:ident) => { + fuzz_float(N, |x: $fX| { + let tmp0 = x as $fD; + let tmp1: $fD = $fn(x); + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + tmp0, + tmp1 + ); + } + }); + }; +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[test] +fn float_extend() { + use compiler_builtins::float::extend::__extendsfdf2; + + extend!(f32, f64, __extendsfdf2); + conv!(f32, f64, __extendsfdf2, Single, Double); + #[cfg(not(feature = "no-f16-f128"))] + { + use compiler_builtins::float::extend::{ + __extenddftf2, __extendhfsf2, __extendhftf2, __extendsftf2, __gnu_h2f_ieee, + }; + // FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly + conv!(f16, f32, __extendhfsf2, Half, Single); + conv!(f16, f32, __gnu_h2f_ieee, Half, Single); + conv!(f16, f128, __extendhftf2, Half, Quad); + conv!(f32, f128, __extendsftf2, Single, Quad); + conv!(f64, f128, __extenddftf2, Double, Quad); + } +} + +#[cfg(target_arch = "arm")] +#[test] +fn float_extend_arm() { + use compiler_builtins::float::extend::__extendsfdf2vfp; + + extend!(f32, f64, __extendsfdf2vfp); + conv!(f32, f64, __extendsfdf2vfp, Single, Double); +} + +macro_rules! trunc { + ($fX:ident, $fD:ident, $fn:ident) => { + fuzz_float(N, |x: $fX| { + let tmp0 = x as $fD; + let tmp1: $fD = $fn(x); + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + tmp0, + tmp1 + ); + } + }); + }; +} + +#[test] +fn float_trunc() { + use compiler_builtins::float::trunc::__truncdfsf2; + + trunc!(f64, f32, __truncdfsf2); + conv!(f64, f32, __truncdfsf2, Double, Single); + #[cfg(not(feature = "no-f16-f128"))] + { + use compiler_builtins::float::trunc::{ + __gnu_f2h_ieee, __truncdfhf2, __truncsfhf2, __trunctfdf2, __trunctfhf2, __trunctfsf2, + }; + // FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly + conv!(f32, f16, __truncsfhf2, Single, Half); + conv!(f32, f16, __gnu_f2h_ieee, Single, Half); + conv!(f64, f16, __truncdfhf2, Double, Half); + conv!(f128, f16, __trunctfhf2, Quad, Half); + conv!(f128, f32, __trunctfsf2, Quad, Single); + conv!(f128, f64, __trunctfdf2, Quad, Double); + } +} + +#[cfg(target_arch = "arm")] +#[test] +fn float_trunc_arm() { + use compiler_builtins::float::trunc::__truncdfsf2vfp; + + trunc!(f64, f32, __truncdfsf2vfp); + conv!(f64, f32, __truncdfsf2vfp, Double, Single) +} diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index 537ba1e60c7..402d202a82b 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -93,41 +93,6 @@ fn leading_zeros() { }) } -macro_rules! extend { - ($fX:ident, $fD:ident, $fn:ident) => { - fuzz_float(N, |x: $fX| { - let tmp0 = x as $fD; - let tmp1: $fD = $fn(x); - if !Float::eq_repr(tmp0, tmp1) { - panic!( - "{}({}): std: {}, builtins: {}", - stringify!($fn), - x, - tmp0, - tmp1 - ); - } - }); - }; -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[test] -fn float_extend() { - use compiler_builtins::float::extend::__extendsfdf2; - - extend!(f32, f64, __extendsfdf2); -} - -#[cfg(target_arch = "arm")] -#[test] -fn float_extend_arm() { - use compiler_builtins::float::extend::__extendsfdf2vfp; - - extend!(f32, f64, __extendsfdf2vfp); -} - // This is approximate because of issues related to // https://github.com/rust-lang/rust/issues/73920. // TODO how do we resolve this indeterminacy? @@ -179,36 +144,3 @@ fn float_pow() { f64, 1e-12, __powidf2; ); } - -macro_rules! trunc { - ($fX:ident, $fD:ident, $fn:ident) => { - fuzz_float(N, |x: $fX| { - let tmp0 = x as $fD; - let tmp1: $fD = $fn(x); - if !Float::eq_repr(tmp0, tmp1) { - panic!( - "{}({}): std: {}, builtins: {}", - stringify!($fn), - x, - tmp0, - tmp1 - ); - } - }); - }; -} - -#[test] -fn float_trunc() { - use compiler_builtins::float::trunc::__truncdfsf2; - - trunc!(f64, f32, __truncdfsf2); -} - -#[cfg(target_arch = "arm")] -#[test] -fn float_trunc_arm() { - use compiler_builtins::float::trunc::__truncdfsf2vfp; - - trunc!(f64, f32, __truncdfsf2vfp); -} -- cgit 1.4.1-3-g733a5 From 2e096145c3bfb175d4fea9e3a518f67aa4851875 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Mon, 29 Apr 2024 22:05:30 +0800 Subject: Apply `weak` attributes to all intrinsics Removed the `weak-intrinsics` feature, so that all functions will have the `weak` linkage attribute. Also this fixed the bug in https://github.com/rust-lang/rust/issues/124042. Before this commit, generated code will be ```rust pub extern "C" fn (...) -> ... { // code... } pub mod { #[linkage = "weak"] #[no_mangle] pub extern "C" fn (...) -> ... { super::(...) } } ``` The issue is that there is 2 `weak` linkage, the first one is not required. Along refactoring `weak` attributes, this was fixed. --- library/compiler-builtins/Cargo.toml | 11 ---- library/compiler-builtins/src/arm.rs | 18 ------- library/compiler-builtins/src/macros.rs | 93 +++++--------------------------- library/compiler-builtins/src/math.rs | 3 -- library/compiler-builtins/src/mem/mod.rs | 6 --- 5 files changed, 14 insertions(+), 117 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 96e85d7b5fb..c8f164c94d2 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -70,17 +70,6 @@ rustc-dep-of-std = ['compiler-builtins', 'core'] # are not normally public but are required by the `testcrate` public-test-deps = [] -# Marks all intrinsics functions with weak linkage so that they can be -# replaced at link time by another implementation. This is particularly useful -# for mixed Rust/C++ binaries that want to use the C++ intrinsics, otherwise -# linking against the Rust stdlib will replace those from the compiler-rt -# library. -# -# Unlike the "c" feature, the intrinsics are still provided by the Rust -# implementations and each will be used unless a stronger symbol replaces -# it during linking. -weak-intrinsics = [] - [[example]] name = "intrinsics" required-features = ["compiler-builtins"] diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index cc67642e16b..dcae22b73fb 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -20,7 +20,6 @@ macro_rules! bl { intrinsics! { // NOTE This function and the ones below are implemented using assembly because they are using a // custom calling convention which can't be implemented using a normal Rust function. - #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] #[cfg(not(target_env = "msvc"))] pub unsafe extern "C" fn __aeabi_uidivmod() { @@ -36,7 +35,6 @@ intrinsics! { ); } - #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] pub unsafe extern "C" fn __aeabi_uldivmod() { core::arch::asm!( @@ -53,7 +51,6 @@ intrinsics! { ); } - #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] pub unsafe extern "C" fn __aeabi_idivmod() { core::arch::asm!( @@ -67,7 +64,6 @@ intrinsics! { ); } - #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] pub unsafe extern "C" fn __aeabi_ldivmod() { core::arch::asm!( @@ -84,17 +80,13 @@ intrinsics! { ); } - // The following functions use weak linkage to allow users to override - // with custom implementation. // FIXME: The `*4` and `*8` variants should be defined as aliases. - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { crate::mem::memcpy(dest, src, n); } - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { // We are guaranteed 4-alignment, so accessing at u32 is okay. @@ -112,38 +104,32 @@ intrinsics! { __aeabi_memcpy(dest as *mut u8, src as *const u8, n); } - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memcpy4(dest, src, n); } - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { crate::mem::memmove(dest, src, n); } - #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } - #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { // Note the different argument order crate::mem::memset(dest, c, n); } - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { let mut dest = dest as *mut u32; @@ -161,25 +147,21 @@ intrinsics! { __aeabi_memset(dest as *mut u8, n, byte as i32); } - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { __aeabi_memset4(dest, n, c); } - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { __aeabi_memset(dest, n, 0); } - #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } - #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 2aa9a742c57..32c615f010e 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -25,11 +25,12 @@ macro_rules! public_test_dep { /// platforms need and elsewhere in this library it just looks like normal Rust /// code. /// -/// When the weak-intrinsics feature is enabled, all intrinsics functions are -/// marked with #[linkage = "weak"] so that they can be replaced by another -/// implementation at link time. This is particularly useful for mixed Rust/C++ -/// binaries that want to use the C++ intrinsics, otherwise linking against the -/// Rust stdlib will replace those from the compiler-rt library. +/// All intrinsics functions are marked with #[linkage = "weak"] when +/// `not(windows) and not(target_vendor = "apple")`. +/// `weak` linkage attribute is used so that these functions can be replaced +/// by another implementation at link time. This is particularly useful for mixed +/// Rust/C++ binaries that want to use the C++ intrinsics, otherwise linking against +/// the Rust stdlib will replace those from the compiler-rt library. /// /// This macro is structured to be invoked with a bunch of functions that looks /// like: @@ -53,10 +54,6 @@ macro_rules! public_test_dep { /// /// A quick overview of attributes supported right now are: /// -/// * `weak` - indicates that the function should always be given weak linkage. -/// This attribute must come before other attributes, as the other attributes -/// will generate the final output function and need to have `weak` modify -/// them. /// * `maybe_use_optimized_c_shim` - indicates that the Rust implementation is /// ignored if an optimized C version was compiled. /// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and @@ -128,67 +125,6 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // Explicit weak linkage gets dropped when weak-intrinsics is on since it - // will be added unconditionally to all intrinsics and would conflict - // otherwise. - ( - #[weak] - $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(feature = "weak-intrinsics")] - intrinsics! { - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - #[cfg(not(feature = "weak-intrinsics"))] - intrinsics! { - $(#[$($attr)*])* - #[linkage = "weak"] - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - // Same as above but for unsafe. - ( - #[weak] - $(#[$($attr:tt)*])* - pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(feature = "weak-intrinsics")] - intrinsics! { - $(#[$($attr)*])* - pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - #[cfg(not(feature = "weak-intrinsics"))] - intrinsics! { - $(#[$($attr)*])* - #[linkage = "weak"] - pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - // Right now there's a bunch of architecture-optimized intrinsics in the // stock compiler-rt implementation. Not all of these have been ported over // to Rust yet so when the `c` feature of this crate is enabled we fall back @@ -211,7 +147,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg($name = "optimized-c")] - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { extern $abi { fn $name($($argname: $ty),*) $(-> $ret)?; @@ -311,7 +247,6 @@ macro_rules! intrinsics { ) => ( #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] $(#[$($attr)*])* - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -319,7 +254,7 @@ macro_rules! intrinsics { #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] pub mod $name { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) -> $crate::macros::win64_128bit_abi_hack::U64x2 { @@ -360,7 +295,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] pub mod $name { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -369,7 +304,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] pub mod $alias { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(any(all(not(windows), not(target_vendor="apple")), feature = "weak-intrinsics"), linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -405,7 +340,7 @@ macro_rules! intrinsics { pub mod $name { $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -429,7 +364,7 @@ macro_rules! intrinsics { #[naked] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -495,7 +430,7 @@ macro_rules! intrinsics { pub mod $name { $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -521,7 +456,7 @@ macro_rules! intrinsics { pub mod $name { $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index e47b834e446..7d4d1787678 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -9,7 +9,6 @@ macro_rules! no_mangle { ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { intrinsics! { $( - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), weak)] pub extern "C" fn $fun($($iid: $ity),+) -> $oty { self::libm::$fun($($iid),+) } @@ -94,14 +93,12 @@ no_mangle! { } intrinsics! { - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), weak)] pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { let r = self::libm::lgamma_r(x); *s = r.1; r.0 } - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), weak)] pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { let r = self::libm::lgammaf_r(x); *s = r.1; diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index ccf191779f4..d0ff501585b 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -20,14 +20,12 @@ use core::ops::{BitOr, Shl}; mod impls; intrinsics! { - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { impls::copy_forward(dest, src, n); dest } - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { let delta = (dest as usize).wrapping_sub(src as usize); @@ -41,26 +39,22 @@ intrinsics! { dest } - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] pub unsafe extern "C" fn memset(s: *mut u8, c: crate::mem::c_int, n: usize) -> *mut u8 { impls::set_bytes(s, c as u8, n); s } - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { impls::compare_bytes(s1, s2, n) } - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { memcmp(s1, s2, n) } - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] pub unsafe extern "C" fn strlen(s: *const core::ffi::c_char) -> usize { impls::c_string_length(s) -- cgit 1.4.1-3-g733a5 From e232a7914666faa57bbaeff501fe89c7861b3115 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Thu, 2 May 2024 21:50:00 +0800 Subject: Remove unneeded `weak` for `optimized-c` function `weak` is only used with `no_mangle` --- library/compiler-builtins/src/macros.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 32c615f010e..89cd6468999 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -147,7 +147,6 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg($name = "optimized-c")] - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { extern $abi { fn $name($($argname: $ty),*) $(-> $ret)?; -- cgit 1.4.1-3-g733a5 From ce8a0c346d5ce003d1f82d11c3e7bc451b349325 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Thu, 2 May 2024 22:00:29 +0800 Subject: Cleanup `manged-names` macro Don't generate the whole function if we are not going to use `no_mangle`, there is no point --- library/compiler-builtins/src/macros.rs | 47 ++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 89cd6468999..f762ef4da21 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -250,11 +250,11 @@ macro_rules! intrinsics { $($body)* } - #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] - pub mod $name { - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64", not(feature = "mangled-names")))] + mod $name { + #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] - pub extern $abi fn $name( $($argname: $ty),* ) + extern $abi fn $name( $($argname: $ty),* ) -> $crate::macros::win64_128bit_abi_hack::U64x2 { let e: $($ret)? = super::$name($($argname),*); @@ -291,20 +291,20 @@ macro_rules! intrinsics { $($body)* } - #[cfg(target_arch = "arm")] - pub mod $name { - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] + mod $name { + #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } - #[cfg(target_arch = "arm")] - pub mod $alias { - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] + mod $alias { + #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] - pub extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { + extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } @@ -335,12 +335,12 @@ macro_rules! intrinsics { $($body)* } - #[cfg(feature = "mem")] - pub mod $name { + #[cfg(all(feature = "mem", not(feature = "mangled-names")))] + mod $name { $(#[$($attr)*])* - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] - pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } @@ -359,6 +359,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( + // `#[naked]` definitions are referenced by other places, so we can't use `cfg` like the others pub mod $name { #[naked] $(#[$($attr)*])* @@ -426,11 +427,12 @@ macro_rules! intrinsics { $($body)* } - pub mod $name { + #[cfg(not(feature = "mangled-names"))] + mod $name { $(#[$($attr)*])* - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } @@ -452,11 +454,12 @@ macro_rules! intrinsics { $($body)* } - pub mod $name { + #[cfg(not(feature = "mangled-names"))] + mod $name { $(#[$($attr)*])* - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] - pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + unsafe fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } -- cgit 1.4.1-3-g733a5 From 8c0c504d4fe380dc0b6e233bbe474dbef2647e40 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 4 May 2024 14:56:01 +0200 Subject: Update reference to rustc-std-workspace-core --- library/compiler-builtins/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c8f164c94d2..6a3c53de805 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -28,8 +28,8 @@ links = 'compiler-rt' test = false [dependencies] -# For more information on this dependency see rust-lang/rust's -# `src/tools/rustc-std-workspace` folder +# For more information on this dependency see +# https://github.com/rust-lang/rust/tree/master/library/rustc-std-workspace-core core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } [build-dependencies] -- cgit 1.4.1-3-g733a5 From 060391b020cb694f29329da3a9ff9200c84918e7 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 4 May 2024 15:31:14 +0100 Subject: Release version 0.1.110 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6a3c53de805..1f4d319298a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.109" +version = "0.1.110" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 461682bd914ef9c5f112ea8d3e43fc150d221492 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Sat, 4 May 2024 15:30:43 +0200 Subject: fix: Add `#[avr_skip]` for `__addsf3` & `__adddf3` It looks like I've forgotten about them [back in 2023](https://github.com/rust-lang/compiler-builtins/pull/527). --- library/compiler-builtins/src/float/add.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 804f4b5100b..97f73e2f44c 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -189,12 +189,14 @@ where } intrinsics! { + #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_fadd] pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 { add(a, b) } + #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_dadd] pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 { -- cgit 1.4.1-3-g733a5 From 2faef31e960b88893dc8b9a6be0062546bfdad61 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 4 May 2024 19:57:27 +0100 Subject: Release version 0.1.111 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 1f4d319298a..0606ef1e7bc 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.110" +version = "0.1.111" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From c7eadedd5f5da45bad10b761e507e09ecec47ce0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 May 2024 04:16:52 -0500 Subject: Deny warnings in CI The main crate already has `#![deny(warnings)]`. Set RUSTFLAGS in CI to enforce this for other crates in the workspace. --- library/compiler-builtins/libm/.github/workflows/main.yml | 4 ++++ library/compiler-builtins/libm/build.rs | 4 ++++ library/compiler-builtins/libm/ci/run-docker.sh | 1 + .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 3 +++ .../libm/crates/compiler-builtins-smoke-test/build.rs | 3 +++ .../libm/crates/compiler-builtins-smoke-test/src/lib.rs | 2 +- 6 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 5408ac23fb4..2f2e46822b9 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -1,6 +1,10 @@ name: CI on: [push, pull_request] +env: + RUSTDOCFLAGS: -Dwarnings + RUSTFLAGS: -Dwarnings + jobs: docker: name: Docker diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 80145a9ccac..c9ae232607f 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -2,10 +2,14 @@ use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); + println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); + println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\"))"); #[cfg(feature = "musl-reference-tests")] musl_reference_tests::generate(); + println!("cargo::rustc-check-cfg=cfg(feature, values(\"checked\"))"); + #[allow(unexpected_cfgs)] if !cfg!(feature = "checked") { let lvl = env::var("OPT_LEVEL").unwrap(); if lvl != "0" { diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index c7ad60fd499..8d323634a67 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -16,6 +16,7 @@ run() { docker run \ --rm \ --user $(id -u):$(id -g) \ + -e RUSTFLAGS \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ -v "${HOME}/.cargo":/cargo \ diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index ac192a9132f..695b710ff30 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -7,3 +7,6 @@ authors = ["Jorge Aparicio "] test = false bench = false +[features] +unstable = [] +checked = [] diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs new file mode 100644 index 00000000000..27d4a0e89d0 --- /dev/null +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); +} diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index 7fad301b983..ab744c45bce 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -6,4 +6,4 @@ #![no_std] #[path = "../../../src/math/mod.rs"] -mod libm; +pub mod libm; -- cgit 1.4.1-3-g733a5 From e4e03883ed315dd21724b003ef1875309627505f Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Wed, 8 May 2024 21:45:13 -0400 Subject: Enable chkstk/alloca intrinsics on i686-unknown-uefi --- library/compiler-builtins/src/x86.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index c348d082d9e..ceec3912eab 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -10,8 +10,7 @@ use core::intrinsics; intrinsics! { #[naked] #[cfg(all( - windows, - target_env = "gnu", + any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") ))] pub unsafe extern "C" fn __chkstk() { @@ -23,8 +22,7 @@ intrinsics! { #[naked] #[cfg(all( - windows, - target_env = "gnu", + any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") ))] pub unsafe extern "C" fn _alloca() { -- cgit 1.4.1-3-g733a5 From ccfe0e38081c45684c01e7c4dd3748a88526c613 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 May 2024 02:49:35 -0500 Subject: Deny warnings in CI There are currently a lot of warnings printed in CI, mostly dead code. Update CI to deny warnings. --- library/compiler-builtins/.github/workflows/main.yml | 4 ++++ library/compiler-builtins/ci/run-docker.sh | 1 + 2 files changed, 5 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 57497e05001..970a32ae518 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -1,6 +1,10 @@ name: CI on: [push, pull_request] +env: + RUSTDOCFLAGS: -Dwarnings + RUSTFLAGS: -Dwarnings + jobs: test: name: Test diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index b85f64133a7..e5ff8a46b26 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -48,6 +48,7 @@ run() { docker run \ --rm \ -e RUST_COMPILER_RT_ROOT \ + -e RUSTFLAGS \ -e "CARGO_TARGET_DIR=/builtins-target" \ -v "$(pwd):/checkout:ro" \ -w /checkout \ -- cgit 1.4.1-3-g733a5 From 286944e479693949e2da8fc105ff397bc1166ffc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 May 2024 03:04:47 -0500 Subject: Emit directives for cargo-check-cfg --- library/compiler-builtins/build.rs | 73 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index bafbf75d068..31e527a0b6a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -2,6 +2,7 @@ use std::{collections::BTreeMap, env, sync::atomic::Ordering}; fn main() { println!("cargo:rerun-if-changed=build.rs"); + configure_check_cfg(); let target = env::var("TARGET").unwrap(); let cwd = env::current_dir().unwrap(); @@ -9,6 +10,7 @@ fn main() { println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); // Activate libm's unstable features to make full use of Nightly. + println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\"))"); println!("cargo:rustc-cfg=feature=\"unstable\""); // Emscripten's runtime includes all the builtins @@ -36,6 +38,7 @@ fn main() { } // These targets have hardware unaligned access support. + println!("cargo::rustc-check-cfg=cfg(feature, values(\"mem-unaligned\"))"); if target.contains("x86_64") || target.contains("i686") || target.contains("aarch64") @@ -64,6 +67,7 @@ fn main() { } // To compile intrinsics.rs for thumb targets, where there is no libc + println!("cargo::rustc-check-cfg=cfg(thumb)"); if llvm_target[0].starts_with("thumb") { println!("cargo:rustc-cfg=thumb") } @@ -71,6 +75,7 @@ fn main() { // compiler-rt `cfg`s away some intrinsics for thumbv6m and thumbv8m.base because // these targets do not have full Thumb-2 support but only original Thumb-1. // We have to cfg our code accordingly. + println!("cargo::rustc-check-cfg=cfg(thumb_1)"); if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { println!("cargo:rustc-cfg=thumb_1") } @@ -78,6 +83,7 @@ fn main() { // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. This // includes the old androideabi. It is deprecated but it is available as a // rustc target (arm-linux-androideabi). + println!("cargo::rustc-check-cfg=cfg(kernel_user_helpers)"); if llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" || target == "arm-linux-androideabi" @@ -145,6 +151,72 @@ fn generate_aarch64_outlined_atomics() { std::fs::write(dst, buf).unwrap(); } +/// Emit directives for features we expect to support that aren't in `Cargo.toml`. +/// +/// These are mostly cfg elements emitted by this `build.rs`. +fn configure_check_cfg() { + // Functions where we can set the "optimized-c" flag + const HAS_OPTIMIZED_C: &[&str] = &[ + "__ashldi3", + "__ashlsi3", + "__ashrdi3", + "__ashrsi3", + "__clzsi2", + "__divdi3", + "__divsi3", + "__divmoddi4", + "__divmodsi4", + "__divmodsi4", + "__divmodti4", + "__lshrdi3", + "__lshrsi3", + "__moddi3", + "__modsi3", + "__muldi3", + "__udivdi3", + "__udivmoddi4", + "__udivmodsi4", + "__udivsi3", + "__umoddi3", + "__umodsi3", + ]; + + // Build a list of all aarch64 atomic operation functions + let mut aarch_atomic = Vec::new(); + for aarch_op in ["cas", "ldadd", "ldclr", "ldeor", "ldset", "swp"] { + let op_sizes = if aarch_op == "cas" { + [1, 2, 4, 8, 16].as_slice() + } else { + [1, 2, 4, 8].as_slice() + }; + + for op_size in op_sizes { + for ordering in ["relax", "acq", "rel", "acq_rel"] { + aarch_atomic.push(format!("__aarch64_{}{}_{}", aarch_op, op_size, ordering)); + } + } + } + + for fn_name in HAS_OPTIMIZED_C + .iter() + .copied() + .chain(aarch_atomic.iter().map(|s| s.as_str())) + { + println!( + "cargo::rustc-check-cfg=cfg({}, values(\"optimized-c\"))", + fn_name + ); + } + + // Rustc is unaware of sparc target features, but this does show up from + // `rustc --print target-features --target sparc64-unknown-linux-gnu`. + println!("cargo::rustc-check-cfg=cfg(target_feature, values(\"vis3\"))"); + + // FIXME: these come from libm and should be changed there + println!("cargo::rustc-check-cfg=cfg(feature, values(\"checked\"))"); + println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); +} + #[cfg(feature = "c")] mod c { extern crate cc; @@ -307,6 +379,7 @@ mod c { // also needs to satisfy intrinsics that jemalloc or C in general may // need, so include a few more that aren't typically needed by // LLVM/Rust. + #[allow(unexpected_cfgs)] if cfg!(feature = "rustbuild") { sources.extend(&[("__ffsdi2", "ffsdi2.c")]); } -- cgit 1.4.1-3-g733a5 From 54d96150b58a498165ea2f1ea4fdefbf774f3bbe Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 May 2024 03:23:36 -0500 Subject: Update `cfg` to fix warnings --- library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/src/int/mod.rs | 1 + library/compiler-builtins/testcrate/tests/cmp.rs | 1 + library/compiler-builtins/testcrate/tests/conv.rs | 2 +- library/compiler-builtins/testcrate/tests/misc.rs | 2 +- 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index a82dd7d2a3b..b0fbe8affcf 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -14,6 +14,7 @@ pub mod trunc; public_test_dep! { /// Trait for some basic operations on floats +#[allow(dead_code)] pub(crate) trait Float: Copy + core::fmt::Debug diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 509f9fdae39..3ef71da8d5d 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -13,6 +13,7 @@ pub use self::leading_zeros::__clzsi2; public_test_dep! { /// Trait for some basic operations on integers +#[allow(dead_code)] pub(crate) trait Int: Copy + core::fmt::Debug diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index 5c10a560113..14dd76b2d7a 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -1,5 +1,6 @@ #![allow(unused_macros)] +#[cfg(not(target_arch = "powerpc64"))] use testcrate::*; macro_rules! cmp { diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 84828dbfa6c..5cff01202a8 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -155,7 +155,7 @@ macro_rules! conv { stringify!($fn) ); } - }); + }) }; } diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index 402d202a82b..cdc37e2a0d7 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -1,7 +1,6 @@ // makes configuration easier #![allow(unused_macros)] -use compiler_builtins::float::Float; use testcrate::*; /// Make sure that the the edge case tester and randomized tester don't break, and list examples of @@ -138,6 +137,7 @@ macro_rules! pow { #[test] fn float_pow() { use compiler_builtins::float::pow::{__powidf2, __powisf2}; + use compiler_builtins::float::Float; pow!( f32, 1e-4, __powisf2; -- cgit 1.4.1-3-g733a5 From f52b4a268fda27b2e629fed7368f743db0dc9aad Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 May 2024 04:26:49 -0500 Subject: Remove the undocumented and unused `rustbuild` feature See --- library/compiler-builtins/build.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 31e527a0b6a..47c8b4ffe56 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -375,15 +375,6 @@ mod c { ]); } - // When compiling in rustbuild (the rust-lang/rust repo) this library - // also needs to satisfy intrinsics that jemalloc or C in general may - // need, so include a few more that aren't typically needed by - // LLVM/Rust. - #[allow(unexpected_cfgs)] - if cfg!(feature = "rustbuild") { - sources.extend(&[("__ffsdi2", "ffsdi2.c")]); - } - // On iOS and 32-bit OSX these are all just empty intrinsics, no need to // include them. if target_os != "ios" -- cgit 1.4.1-3-g733a5 From f16e62159b91919d602399b51efe4c1c80884580 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 11 May 2024 09:50:21 +0200 Subject: Release 0.1.112 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0606ef1e7bc..4564ba9e54c 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.111" +version = "0.1.112" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index a1e8a5bf95e..279e5f6abe0 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit a1e8a5bf95e99309760b764b2a332d0039d08350 +Subproject commit 279e5f6abe0a2ca9066962d9ec894f0df1f417ac -- cgit 1.4.1-3-g733a5 From a5779e5d37a9efce7b55914d9cc56e38bc260444 Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Mon, 13 May 2024 11:17:07 -0700 Subject: Fix paths for Windows arm64 build --- library/compiler-builtins/build.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index bafbf75d068..c6af5a9e7b2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,4 +1,4 @@ -use std::{collections::BTreeMap, env, sync::atomic::Ordering}; +use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering}; fn main() { println!("cargo:rerun-if-changed=build.rs"); @@ -141,8 +141,8 @@ fn generate_aarch64_outlined_atomics() { buf += macro_def; buf += "}; }\n"; } - let dst = std::env::var("OUT_DIR").unwrap() + "/outlined_atomics.rs"; - std::fs::write(dst, buf).unwrap(); + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); + std::fs::write(out_dir.join("outlined_atomics.rs"), buf).unwrap(); } #[cfg(feature = "c")] @@ -612,7 +612,7 @@ mod c { fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &mut cc::Build) { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let outlined_atomics_file = builtins_dir.join("aarch64/lse.S"); + let outlined_atomics_file = builtins_dir.join("aarch64").join("lse.S"); println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); cfg.include(&builtins_dir); -- cgit 1.4.1-3-g733a5 From 4edceece666ff008a61bc645469ee792de087ecf Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Mon, 13 May 2024 11:29:55 -0700 Subject: Add aarch64 target --- library/compiler-builtins/.github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 57497e05001..f1c63e4f93f 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -83,6 +83,9 @@ jobs: - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu + - target: aarch64-pc-windows-gnu + os: windows-latest + rust: nightly steps: - name: Print runner information run: uname -a -- cgit 1.4.1-3-g733a5 From 6ef61fd85a795ba688a383b018765f730a995c37 Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Mon, 13 May 2024 11:31:23 -0700 Subject: Update target --- library/compiler-builtins/.github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index f1c63e4f93f..7a799eaed5c 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -83,7 +83,7 @@ jobs: - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu - - target: aarch64-pc-windows-gnu + - target: aarch64-pc-windows-msvc os: windows-latest rust: nightly steps: -- cgit 1.4.1-3-g733a5 From 8c27bcb11acc4f505699521051111853354de5ed Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Mon, 13 May 2024 11:38:43 -0700 Subject: Maybe try arm64 --- library/compiler-builtins/.github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 7a799eaed5c..ba555387978 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -15,6 +15,9 @@ jobs: - target: aarch64-unknown-linux-gnu os: ubuntu-latest rust: nightly + - target: aarch64-pc-windows-msvc + os: [windows-latest, arm64] + rust: nightly - target: arm-unknown-linux-gnueabi os: ubuntu-latest rust: nightly @@ -83,9 +86,6 @@ jobs: - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu - - target: aarch64-pc-windows-msvc - os: windows-latest - rust: nightly steps: - name: Print runner information run: uname -a -- cgit 1.4.1-3-g733a5 From 4c35dc3b1e436750ad3a04c867bdb531db713193 Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Tue, 14 May 2024 15:47:07 -0700 Subject: Remove aarch64 CI --- library/compiler-builtins/.github/workflows/main.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index ba555387978..57497e05001 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -15,9 +15,6 @@ jobs: - target: aarch64-unknown-linux-gnu os: ubuntu-latest rust: nightly - - target: aarch64-pc-windows-msvc - os: [windows-latest, arm64] - rust: nightly - target: arm-unknown-linux-gnueabi os: ubuntu-latest rust: nightly -- cgit 1.4.1-3-g733a5 From 10689247bc50a2dff10b244c1a5434ad3c847b97 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 10 May 2024 18:38:09 -0500 Subject: Split `Int` into `Int` and `MinInt` `MinInt` contains the basic methods that are only needed by integers involved in widening operations, i.e. big integers. `Int` retains all other operations and convenience methods. --- library/compiler-builtins/src/float/add.rs | 22 +-- library/compiler-builtins/src/float/cmp.rs | 2 +- library/compiler-builtins/src/float/div.rs | 79 +++++---- library/compiler-builtins/src/float/extend.rs | 2 +- library/compiler-builtins/src/float/mod.rs | 7 +- library/compiler-builtins/src/float/mul.rs | 2 +- library/compiler-builtins/src/float/trunc.rs | 2 +- library/compiler-builtins/src/int/addsub.rs | 10 +- library/compiler-builtins/src/int/mod.rs | 232 +++++++++++++------------ library/compiler-builtins/src/int/mul.rs | 4 +- library/compiler-builtins/src/int/shift.rs | 2 +- library/compiler-builtins/testcrate/src/lib.rs | 18 +- 12 files changed, 210 insertions(+), 172 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 97f73e2f44c..909948ad29c 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::{CastInto, Int}; +use crate::int::{CastInto, Int, MinInt}; /// Returns `a + b` fn add(a: F, b: F) -> F @@ -57,9 +57,9 @@ where } // zero + anything = anything - if a_abs == Int::ZERO { + if a_abs == MinInt::ZERO { // but we need to get the sign right for zero + zero - if b_abs == Int::ZERO { + if b_abs == MinInt::ZERO { return F::from_repr(a.repr() & b.repr()); } else { return b; @@ -67,7 +67,7 @@ where } // anything + zero = anything - if b_abs == Int::ZERO { + if b_abs == MinInt::ZERO { return a; } } @@ -113,10 +113,10 @@ where // Shift the significand of b by the difference in exponents, with a sticky // bottom bit to get rounding correct. let align = a_exponent.wrapping_sub(b_exponent).cast(); - if align != Int::ZERO { + if align != MinInt::ZERO { if align < bits { let sticky = - F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != Int::ZERO); + F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != MinInt::ZERO); b_significand = (b_significand >> align.cast()) | sticky; } else { b_significand = one; // sticky; b is known to be non-zero. @@ -125,8 +125,8 @@ where if subtraction { a_significand = a_significand.wrapping_sub(b_significand); // If a == -b, return +zero. - if a_significand == Int::ZERO { - return F::from_repr(Int::ZERO); + if a_significand == MinInt::ZERO { + return F::from_repr(MinInt::ZERO); } // If partial cancellation occured, we need to left-shift the result @@ -143,8 +143,8 @@ where // If the addition carried up, we need to right-shift the result and // adjust the exponent: - if a_significand & implicit_bit << 4 != Int::ZERO { - let sticky = F::Int::from_bool(a_significand & one != Int::ZERO); + if a_significand & implicit_bit << 4 != MinInt::ZERO { + let sticky = F::Int::from_bool(a_significand & one != MinInt::ZERO); a_significand = a_significand >> 1 | sticky; a_exponent += 1; } @@ -160,7 +160,7 @@ where // need to shift the significand. let shift = (1 - a_exponent).cast(); let sticky = - F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != Int::ZERO); + F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != MinInt::ZERO); a_significand = a_significand >> shift.cast() | sticky; a_exponent = 0; } diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 1c8917af8ad..193c5df368c 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -1,7 +1,7 @@ #![allow(unreachable_code)] use crate::float::Float; -use crate::int::Int; +use crate::int::MinInt; #[derive(Clone, Copy)] enum Result { diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index d587fe4f98f..c0d780b66dd 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -3,7 +3,9 @@ #![allow(clippy::needless_return)] use crate::float::Float; -use crate::int::{CastInto, DInt, HInt, Int}; +use crate::int::{CastInto, DInt, HInt, Int, MinInt}; + +use super::HalfRep; fn div32(a: F, b: F) -> F where @@ -454,15 +456,20 @@ where fn div64(a: F, b: F) -> F where - u32: CastInto, F::Int: CastInto, - i32: CastInto, F::Int: CastInto, - u64: CastInto, + F::Int: CastInto>, + F::Int: From>, + F::Int: From, F::Int: CastInto, - i64: CastInto, F::Int: CastInto, - F::Int: HInt, + F::Int: HInt + DInt, + u16: CastInto, + i32: CastInto, + i64: CastInto, + u32: CastInto, + u64: CastInto, + u64: CastInto>, { const NUMBER_OF_HALF_ITERATIONS: usize = 3; const NUMBER_OF_FULL_ITERATIONS: usize = 1; @@ -471,7 +478,7 @@ where let one = F::Int::ONE; let zero = F::Int::ZERO; let hw = F::BITS / 2; - let lo_mask = u64::MAX >> hw; + let lo_mask = F::Int::MAX >> hw; let significand_bits = F::SIGNIFICAND_BITS; let max_exponent = F::EXPONENT_MAX; @@ -616,8 +623,9 @@ where let mut x_uq0 = if NUMBER_OF_HALF_ITERATIONS > 0 { // Starting with (n-1) half-width iterations - let b_uq1_hw: u32 = - (CastInto::::cast(b_significand) >> (significand_bits + 1 - hw)) as u32; + let b_uq1_hw: HalfRep = CastInto::>::cast( + CastInto::::cast(b_significand) >> (significand_bits + 1 - hw), + ); // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW // with W0 being either 16 or 32 and W0 <= HW. @@ -625,12 +633,13 @@ where // b/2 is subtracted to obtain x0) wrapped to [0, 1) range. // HW is at least 32. Shifting into the highest bits if needed. - let c_hw = (0x7504F333_u64 as u32).wrapping_shl(hw.wrapping_sub(32)); + let c_hw = (CastInto::>::cast(0x7504F333_u64)).wrapping_shl(hw.wrapping_sub(32)); // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, // so x0 fits to UQ0.HW without wrapping. - let x_uq0_hw: u32 = { - let mut x_uq0_hw: u32 = c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); + let x_uq0_hw: HalfRep = { + let mut x_uq0_hw: HalfRep = + c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); // dbg!(x_uq0_hw); // An e_0 error is comprised of errors due to // * x0 being an inherently imprecise first approximation of 1/b_hw @@ -661,8 +670,9 @@ where // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is // expected to be strictly positive because b_UQ1_hw has its highest bit set // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). - let corr_uq1_hw: u32 = - 0.wrapping_sub(((x_uq0_hw as u64).wrapping_mul(b_uq1_hw as u64)) >> hw) as u32; + let corr_uq1_hw: HalfRep = CastInto::>::cast(zero.wrapping_sub( + ((F::Int::from(x_uq0_hw)).wrapping_mul(F::Int::from(b_uq1_hw))) >> hw, + )); // dbg!(corr_uq1_hw); // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally @@ -677,7 +687,9 @@ where // The fact corr_UQ1_hw was virtually round up (due to result of // multiplication being **first** truncated, then negated - to improve // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. - x_uq0_hw = ((x_uq0_hw as u64).wrapping_mul(corr_uq1_hw as u64) >> (hw - 1)) as u32; + x_uq0_hw = ((F::Int::from(x_uq0_hw)).wrapping_mul(F::Int::from(corr_uq1_hw)) + >> (hw - 1)) + .cast(); // dbg!(x_uq0_hw); // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after @@ -707,7 +719,7 @@ where // be not below that value (see g(x) above), so it is safe to decrement just // once after the final iteration. On the other hand, an effective value of // divisor changes after this point (from b_hw to b), so adjust here. - x_uq0_hw.wrapping_sub(1_u32) + x_uq0_hw.wrapping_sub(HalfRep::::ONE) }; // Error estimations for full-precision iterations are calculated just @@ -717,7 +729,7 @@ where // Simulating operations on a twice_rep_t to perform a single final full-width // iteration. Using ad-hoc multiplication implementations to take advantage // of particular structure of operands. - let blo: u64 = (CastInto::::cast(b_uq1)) & lo_mask; + let blo: F::Int = b_uq1 & lo_mask; // x_UQ0 = x_UQ0_hw * 2^HW - 1 // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1 // @@ -726,19 +738,20 @@ where // + [ x_UQ0_hw * blo ] // - [ b_UQ1 ] // = [ result ][.... discarded ...] - let corr_uq1 = negate_u64( - (x_uq0_hw as u64) * (b_uq1_hw as u64) + (((x_uq0_hw as u64) * (blo)) >> hw) - 1, - ); // account for *possible* carry - let lo_corr = corr_uq1 & lo_mask; - let hi_corr = corr_uq1 >> hw; + let corr_uq1: F::Int = (F::Int::from(x_uq0_hw) * F::Int::from(b_uq1_hw) + + ((F::Int::from(x_uq0_hw) * blo) >> hw)) + .wrapping_sub(one) + .wrapping_neg(); // account for *possible* carry + let lo_corr: F::Int = corr_uq1 & lo_mask; + let hi_corr: F::Int = corr_uq1 >> hw; // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1 - let mut x_uq0: ::Int = ((((x_uq0_hw as u64) * hi_corr) << 1) - .wrapping_add(((x_uq0_hw as u64) * lo_corr) >> (hw - 1)) - .wrapping_sub(2)) - .cast(); // 1 to account for the highest bit of corr_UQ1 can be 1 - // 1 to account for possible carry - // Just like the case of half-width iterations but with possibility - // of overflowing by one extra Ulp of x_UQ0. + let mut x_uq0: F::Int = ((F::Int::from(x_uq0_hw) * hi_corr) << 1) + .wrapping_add((F::Int::from(x_uq0_hw) * lo_corr) >> (hw - 1)) + .wrapping_sub(F::Int::from(2u8)); + // 1 to account for the highest bit of corr_UQ1 can be 1 + // 1 to account for possible carry + // Just like the case of half-width iterations but with possibility + // of overflowing by one extra Ulp of x_UQ0. x_uq0 -= one; // ... and then traditional fixup by 2 should work @@ -755,8 +768,8 @@ where x_uq0 } else { // C is (3/4 + 1/sqrt(2)) - 1 truncated to 64 fractional bits as UQ0.n - let c: ::Int = (0x7504F333 << (F::BITS - 32)).cast(); - let x_uq0: ::Int = c.wrapping_sub(b_uq1); + let c: F::Int = (0x7504F333 << (F::BITS - 32)).cast(); + let x_uq0: F::Int = c.wrapping_sub(b_uq1); // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-64 x_uq0 }; @@ -806,7 +819,7 @@ where // Now 1/b - (2*P) * 2^-W < x < 1/b // FIXME Is x_UQ0 still >= 0.5? - let mut quotient: ::Int = x_uq0.widen_mul(a_significand << 1).hi(); + let mut quotient: F::Int = x_uq0.widen_mul(a_significand << 1).hi(); // Now, a/b - 4*P * 2^-W < q < a/b for q= in UQ1.(SB+1+W). // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1), @@ -868,7 +881,7 @@ where // r = a - b * q let abs_result = if written_exponent > 0 { let mut ret = quotient & significand_mask; - ret |= ((written_exponent as u64) << significand_bits).cast(); + ret |= written_exponent.cast() << significand_bits; residual <<= 1; ret } else { diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 7c2446603f2..5b0c0d97268 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::{CastInto, Int}; +use crate::int::{CastInto, Int, MinInt}; /// Generic conversion from a narrower to a wider IEEE-754 floating-point type fn extend(a: F) -> R diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index b0fbe8affcf..e62a3fe0fd5 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,6 +1,6 @@ use core::ops; -use super::int::Int; +use crate::int::{DInt, Int, MinInt}; pub mod add; pub mod cmp; @@ -12,6 +12,9 @@ pub mod pow; pub mod sub; pub mod trunc; +/// Wrapper to extract the integer type half of the float's size +pub(crate) type HalfRep = <::Int as DInt>::H; + public_test_dep! { /// Trait for some basic operations on floats #[allow(dead_code)] @@ -60,7 +63,7 @@ pub(crate) trait Float: /// A mask for the significand const SIGNIFICAND_MASK: Self::Int; - // The implicit bit of the float format + /// The implicit bit of the float format const IMPLICIT_BIT: Self::Int; /// A mask for the exponent diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 378fa970116..46c41d09f19 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::{CastInto, DInt, HInt, Int}; +use crate::int::{CastInto, DInt, HInt, Int, MinInt}; fn mul(a: F, b: F) -> F where diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 6de446c1006..b607a654983 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::{CastInto, Int}; +use crate::int::{CastInto, Int, MinInt}; fn trunc(a: F) -> R where diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs index f31eff4bd03..e95590d84dc 100644 --- a/library/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/src/int/addsub.rs @@ -1,6 +1,6 @@ -use crate::int::{DInt, Int}; +use crate::int::{DInt, Int, MinInt}; -trait UAddSub: DInt { +trait UAddSub: DInt + Int { fn uadd(self, other: Self) -> Self { let (lo, carry) = self.lo().overflowing_add(other.lo()); let hi = self.hi().wrapping_add(other.hi()); @@ -22,7 +22,7 @@ impl UAddSub for u128 {} trait AddSub: Int where - ::UnsignedInt: UAddSub, + ::UnsignedInt: UAddSub, { fn add(self, other: Self) -> Self { Self::from_unsigned(self.unsigned().uadd(other.unsigned())) @@ -37,7 +37,7 @@ impl AddSub for i128 {} trait Addo: AddSub where - ::UnsignedInt: UAddSub, + ::UnsignedInt: UAddSub, { fn addo(self, other: Self) -> (Self, bool) { let sum = AddSub::add(self, other); @@ -50,7 +50,7 @@ impl Addo for u128 {} trait Subo: AddSub where - ::UnsignedInt: UAddSub, + ::UnsignedInt: UAddSub, { fn subo(self, other: Self) -> (Self, bool) { let sum = AddSub::sub(self, other); diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 3ef71da8d5d..dd23da3b752 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -9,37 +9,22 @@ pub mod sdiv; pub mod shift; pub mod udiv; -pub use self::leading_zeros::__clzsi2; +pub use leading_zeros::__clzsi2; public_test_dep! { -/// Trait for some basic operations on integers +/// Minimal integer implementations needed on all integer types, including wide integers. #[allow(dead_code)] -pub(crate) trait Int: - Copy +pub(crate) trait MinInt: Copy + core::fmt::Debug - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Div - + ops::Shl - + ops::Shr + ops::BitOr - + ops::BitXor - + ops::BitAnd + ops::Not + + ops::Shl { + /// Type with the same width but other signedness - type OtherSign: Int; + type OtherSign: MinInt; /// Unsigned version of Self - type UnsignedInt: Int; + type UnsignedInt: MinInt; /// If `Self` is a signed integer const SIGNED: bool; @@ -51,13 +36,47 @@ pub(crate) trait Int: const ONE: Self; const MIN: Self; const MAX: Self; +} +} +public_test_dep! { +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub(crate) trait Int: MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, /// 112,119,120,125,126,127]. - const FUZZ_LENGTHS: [u8; 20]; + const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. - const FUZZ_NUM: usize; + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; fn unsigned(self) -> Self::UnsignedInt; fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; @@ -84,74 +103,54 @@ pub(crate) trait Int: } } +pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v +} + macro_rules! int_impl_common { ($ty:ty) => { - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - - const FUZZ_LENGTHS: [u8; 20] = { - let bits = ::BITS; - let mut v = [0u8; 20]; - v[0] = 0; - v[1] = 1; - v[2] = 2; // important for parity and the iX::MIN case when reversed - let mut i = 3; - // No need for any more until the byte boundary, because there should be no algorithms - // that are sensitive to anything not next to byte boundaries after 2. We also scale - // in powers of two, which is important to prevent u128 corner tests from getting too - // big. - let mut l = 8; - loop { - if l >= ((bits / 2) as u8) { - break; - } - // get both sides of the byte boundary - v[i] = l - 1; - i += 1; - v[i] = l; - i += 1; - l *= 2; - } - - if bits != 8 { - // add the lower side of the middle boundary - v[i] = ((bits / 2) - 1) as u8; - i += 1; - } - - // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS - // boundary because of algorithms that split the high part up. We reverse the scaling - // as we go to Self::BITS. - let mid = i; - let mut j = 1; - loop { - v[i] = (bits as u8) - (v[mid - j]) - 1; - if j == mid { - break; - } - i += 1; - j += 1; - } - v - }; - - const FUZZ_NUM: usize = { - let log2 = (::BITS - 1).count_ones() as usize; - if log2 == 3 { - // case for u8 - 6 - } else { - // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate - // boundaries. - 8 + (4 * (log2 - 4)) - } - }; - fn from_bool(b: bool) -> Self { b as $ty } @@ -204,10 +203,20 @@ macro_rules! int_impl_common { macro_rules! int_impl { ($ity:ty, $uty:ty) => { - impl Int for $uty { + impl MinInt for $uty { type OtherSign = $ity; type UnsignedInt = $uty; + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { fn unsigned(self) -> $uty { self } @@ -229,10 +238,20 @@ macro_rules! int_impl { int_impl_common!($uty); } - impl Int for $ity { + impl MinInt for $ity { type OtherSign = $uty; type UnsignedInt = $uty; + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { fn unsigned(self) -> $uty { self as $uty } @@ -260,18 +279,22 @@ int_impl!(i128, u128); public_test_dep! { /// Trait for integers twice the bit width of another integer. This is implemented for all /// primitives except for `u8`, because there is not a smaller primitive. -pub(crate) trait DInt: Int { +pub(crate) trait DInt: MinInt { /// Integer that is half the bit width of the integer this trait is implemented for - type H: HInt + Int; + type H: HInt; /// Returns the low half of `self` fn lo(self) -> Self::H; /// Returns the high half of `self` fn hi(self) -> Self::H; /// Returns the low and high halves of `self` as a tuple - fn lo_hi(self) -> (Self::H, Self::H); + fn lo_hi(self) -> (Self::H, Self::H) { + (self.lo(), self.hi()) + } /// Constructs an integer using lower and higher half parts - fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self; + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { + lo.zero_widen() | hi.widen_hi() + } } } @@ -280,7 +303,7 @@ public_test_dep! { /// primitives except for `u128`, because it there is not a larger primitive. pub(crate) trait HInt: Int { /// Integer that is double the bit width of the integer this trait is implemented for - type D: DInt + Int; + type D: DInt + MinInt; /// Widens (using default extension) the integer to have double bit width fn widen(self) -> Self::D; @@ -288,7 +311,9 @@ pub(crate) trait HInt: Int { /// around problems with associated type bounds (such as `Int`) being unstable fn zero_widen(self) -> Self::D; /// Widens the integer to have double bit width and shifts the integer into the higher bits - fn widen_hi(self) -> Self::D; + fn widen_hi(self) -> Self::D { + self.widen() << ::BITS + } /// Widening multiplication with zero widening. This cannot overflow. fn zero_widen_mul(self, rhs: Self) -> Self::D; /// Widening multiplication. This cannot overflow. @@ -306,13 +331,7 @@ macro_rules! impl_d_int { self as $X } fn hi(self) -> Self::H { - (self >> <$X as Int>::BITS) as $X - } - fn lo_hi(self) -> (Self::H, Self::H) { - (self.lo(), self.hi()) - } - fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { - lo.zero_widen() | hi.widen_hi() + (self >> <$X as MinInt>::BITS) as $X } } )* @@ -331,9 +350,6 @@ macro_rules! impl_h_int { fn zero_widen(self) -> Self::D { (self as $uH) as $X } - fn widen_hi(self) -> Self::D { - (self as $X) << <$H as Int>::BITS - } fn zero_widen_mul(self, rhs: Self) -> Self::D { self.zero_widen().wrapping_mul(rhs.zero_widen()) } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 2538e2f4181..e0093a725c2 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,6 +1,6 @@ use crate::int::{DInt, HInt, Int}; -trait Mul: DInt +trait Mul: DInt + Int where Self::H: DInt, { @@ -30,7 +30,7 @@ where impl Mul for u64 {} impl Mul for i128 {} -pub(crate) trait UMulo: Int + DInt { +pub(crate) trait UMulo: DInt + Int { fn mulo(self, rhs: Self) -> (Self, bool) { match (self.hi().is_zero(), rhs.hi().is_zero()) { // overflow is guaranteed diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index dbd04018732..317272988ce 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,4 +1,4 @@ -use crate::int::{DInt, HInt, Int}; +use crate::int::{DInt, HInt, Int, MinInt}; trait Ashl: DInt { /// Returns `a << b`, requires `b < Self::BITS` diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 9bd155f6f10..13abf459eba 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -15,7 +15,7 @@ #![no_std] use compiler_builtins::float::Float; -use compiler_builtins::int::Int; +use compiler_builtins::int::{Int, MinInt}; use rand_xoshiro::rand_core::{RngCore, SeedableRng}; use rand_xoshiro::Xoshiro128StarStar; @@ -101,7 +101,10 @@ macro_rules! edge_cases { /// Feeds a series of fuzzing inputs to `f`. The fuzzer first uses an algorithm designed to find /// edge cases, followed by a more random fuzzer that runs `n` times. -pub fn fuzz(n: u32, mut f: F) { +pub fn fuzz(n: u32, mut f: F) +where + ::UnsignedInt: Int, +{ // edge case tester. Calls `f` 210 times for u128. // zero gets skipped by the loop f(I::ZERO); @@ -111,7 +114,7 @@ pub fn fuzz(n: u32, mut f: F) { // random fuzzer let mut rng = Xoshiro128StarStar::seed_from_u64(0); - let mut x: I = Int::ZERO; + let mut x: I = MinInt::ZERO; for _ in 0..n { fuzz_step(&mut rng, &mut x); f(x) @@ -119,7 +122,10 @@ pub fn fuzz(n: u32, mut f: F) { } /// The same as `fuzz`, except `f` has two inputs. -pub fn fuzz_2(n: u32, f: F) { +pub fn fuzz_2(n: u32, f: F) +where + ::UnsignedInt: Int, +{ // Check cases where the first and second inputs are zero. Both call `f` 210 times for `u128`. edge_cases!(I, case, { f(I::ZERO, case); @@ -150,10 +156,10 @@ pub fn fuzz_shift(f: F) { // Shift functions are very simple and do not need anything other than shifting a small // set of random patterns for every fuzz length. let mut rng = Xoshiro128StarStar::seed_from_u64(0); - let mut x: I = Int::ZERO; + let mut x: I = MinInt::ZERO; for i in 0..I::FUZZ_NUM { fuzz_step(&mut rng, &mut x); - f(x, Int::ZERO); + f(x, MinInt::ZERO); f(x, I::FUZZ_LENGTHS[i] as u32); } } -- cgit 1.4.1-3-g733a5 From 23b91f2b58a08f7e6958f6dd1080f03bc87f9a04 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 10 May 2024 18:50:36 -0500 Subject: Add `i256` and `u256` bigint types --- library/compiler-builtins/src/int/big.rs | 251 +++++++++++++++++++++++ library/compiler-builtins/src/int/mod.rs | 2 + library/compiler-builtins/testcrate/tests/big.rs | 61 ++++++ 3 files changed, 314 insertions(+) create mode 100644 library/compiler-builtins/src/int/big.rs create mode 100644 library/compiler-builtins/testcrate/tests/big.rs diff --git a/library/compiler-builtins/src/int/big.rs b/library/compiler-builtins/src/int/big.rs new file mode 100644 index 00000000000..019dd728b5d --- /dev/null +++ b/library/compiler-builtins/src/int/big.rs @@ -0,0 +1,251 @@ +//! Integers used for wide operations, larger than `u128`. + +#![allow(unused)] + +use crate::int::{DInt, HInt, Int, MinInt}; +use core::{fmt, ops}; + +const WORD_LO_MASK: u64 = 0x00000000ffffffff; +const WORD_HI_MASK: u64 = 0xffffffff00000000; +const WORD_FULL_MASK: u64 = 0xffffffffffffffff; +const U128_LO_MASK: u128 = u64::MAX as u128; +const U128_HI_MASK: u128 = (u64::MAX as u128) << 64; + +/// A 256-bit unsigned integer represented as 4 64-bit limbs. +/// +/// Each limb is a native-endian number, but the array is little-limb-endian. +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +pub struct u256(pub [u64; 4]); + +impl u256 { + pub const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX]); + + /// Reinterpret as a signed integer + pub fn signed(self) -> i256 { + i256(self.0) + } +} + +/// A 256-bit signed integer represented as 4 64-bit limbs. +/// +/// Each limb is a native-endian number, but the array is little-limb-endian. +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +pub struct i256(pub [u64; 4]); + +impl i256 { + /// Reinterpret as an unsigned integer + pub fn unsigned(self) -> u256 { + u256(self.0) + } +} + +impl MinInt for u256 { + type OtherSign = i256; + + type UnsignedInt = u256; + + const SIGNED: bool = false; + const BITS: u32 = 256; + const ZERO: Self = Self([0u64; 4]); + const ONE: Self = Self([1, 0, 0, 0]); + const MIN: Self = Self([0u64; 4]); + const MAX: Self = Self([u64::MAX; 4]); +} + +impl MinInt for i256 { + type OtherSign = u256; + + type UnsignedInt = u256; + + const SIGNED: bool = false; + const BITS: u32 = 256; + const ZERO: Self = Self([0u64; 4]); + const ONE: Self = Self([1, 0, 0, 0]); + const MIN: Self = Self([0, 0, 0, 1 << 63]); + const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX << 1]); +} + +macro_rules! impl_common { + ($ty:ty) => { + impl ops::BitOr for $ty { + type Output = Self; + + fn bitor(mut self, rhs: Self) -> Self::Output { + self.0[0] |= rhs.0[0]; + self.0[1] |= rhs.0[1]; + self.0[2] |= rhs.0[2]; + self.0[3] |= rhs.0[3]; + self + } + } + + impl ops::Not for $ty { + type Output = Self; + + fn not(self) -> Self::Output { + Self([!self.0[0], !self.0[1], !self.0[2], !self.0[3]]) + } + } + + impl ops::Shl for $ty { + type Output = Self; + + fn shl(self, rhs: u32) -> Self::Output { + todo!() + } + } + }; +} + +impl_common!(i256); +impl_common!(u256); + +macro_rules! word { + (1, $val:expr) => { + (($val >> (32 * 3)) & Self::from(WORD_LO_MASK)) as u64 + }; + (2, $val:expr) => { + (($val >> (32 * 2)) & Self::from(WORD_LO_MASK)) as u64 + }; + (3, $val:expr) => { + (($val >> (32 * 1)) & Self::from(WORD_LO_MASK)) as u64 + }; + (4, $val:expr) => { + (($val >> (32 * 0)) & Self::from(WORD_LO_MASK)) as u64 + }; +} + +impl HInt for u128 { + type D = u256; + + fn widen(self) -> Self::D { + let w0 = self & u128::from(u64::MAX); + let w1 = (self >> u64::BITS) & u128::from(u64::MAX); + u256([w0 as u64, w1 as u64, 0, 0]) + } + + fn zero_widen(self) -> Self::D { + self.widen() + } + + fn zero_widen_mul(self, rhs: Self) -> Self::D { + let product11: u64 = word!(1, self) * word!(1, rhs); + let product12: u64 = word!(1, self) * word!(2, rhs); + let product13: u64 = word!(1, self) * word!(3, rhs); + let product14: u64 = word!(1, self) * word!(4, rhs); + let product21: u64 = word!(2, self) * word!(1, rhs); + let product22: u64 = word!(2, self) * word!(2, rhs); + let product23: u64 = word!(2, self) * word!(3, rhs); + let product24: u64 = word!(2, self) * word!(4, rhs); + let product31: u64 = word!(3, self) * word!(1, rhs); + let product32: u64 = word!(3, self) * word!(2, rhs); + let product33: u64 = word!(3, self) * word!(3, rhs); + let product34: u64 = word!(3, self) * word!(4, rhs); + let product41: u64 = word!(4, self) * word!(1, rhs); + let product42: u64 = word!(4, self) * word!(2, rhs); + let product43: u64 = word!(4, self) * word!(3, rhs); + let product44: u64 = word!(4, self) * word!(4, rhs); + + let sum0: u128 = u128::from(product44); + let sum1: u128 = u128::from(product34) + u128::from(product43); + let sum2: u128 = u128::from(product24) + u128::from(product33) + u128::from(product42); + let sum3: u128 = u128::from(product14) + + u128::from(product23) + + u128::from(product32) + + u128::from(product41); + let sum4: u128 = u128::from(product13) + u128::from(product22) + u128::from(product31); + let sum5: u128 = u128::from(product12) + u128::from(product21); + let sum6: u128 = u128::from(product11); + + let r0: u128 = + (sum0 & u128::from(WORD_FULL_MASK)) + ((sum1 & u128::from(WORD_LO_MASK)) << 32); + let r1: u128 = (sum0 >> 64) + + ((sum1 >> 32) & u128::from(WORD_FULL_MASK)) + + (sum2 & u128::from(WORD_FULL_MASK)) + + ((sum3 << 32) & u128::from(WORD_HI_MASK)); + + let (lo, carry) = r0.overflowing_add(r1 << 64); + let hi = (r1 >> 64) + + (sum1 >> 96) + + (sum2 >> 64) + + (sum3 >> 32) + + sum4 + + (sum5 << 32) + + (sum6 << 64) + + u128::from(carry); + + u256([ + (lo & U128_LO_MASK) as u64, + ((lo >> 64) & U128_LO_MASK) as u64, + (hi & U128_LO_MASK) as u64, + ((hi >> 64) & U128_LO_MASK) as u64, + ]) + } + + fn widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen_mul(rhs) + } +} + +impl HInt for i128 { + type D = i256; + + fn widen(self) -> Self::D { + let mut ret = self.unsigned().zero_widen().signed(); + if self.is_negative() { + ret.0[2] = u64::MAX; + ret.0[3] = u64::MAX; + } + ret + } + + fn zero_widen(self) -> Self::D { + self.unsigned().zero_widen().signed() + } + + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.unsigned().zero_widen_mul(rhs.unsigned()).signed() + } + + fn widen_mul(self, rhs: Self) -> Self::D { + unimplemented!("signed i128 widening multiply is not used") + } +} + +impl DInt for u256 { + type H = u128; + + fn lo(self) -> Self::H { + let mut tmp = [0u8; 16]; + tmp[..8].copy_from_slice(&self.0[0].to_le_bytes()); + tmp[8..].copy_from_slice(&self.0[1].to_le_bytes()); + u128::from_le_bytes(tmp) + } + + fn hi(self) -> Self::H { + let mut tmp = [0u8; 16]; + tmp[..8].copy_from_slice(&self.0[2].to_le_bytes()); + tmp[8..].copy_from_slice(&self.0[3].to_le_bytes()); + u128::from_le_bytes(tmp) + } +} + +impl DInt for i256 { + type H = i128; + + fn lo(self) -> Self::H { + let mut tmp = [0u8; 16]; + tmp[..8].copy_from_slice(&self.0[0].to_le_bytes()); + tmp[8..].copy_from_slice(&self.0[1].to_le_bytes()); + i128::from_le_bytes(tmp) + } + + fn hi(self) -> Self::H { + let mut tmp = [0u8; 16]; + tmp[..8].copy_from_slice(&self.0[2].to_le_bytes()); + tmp[8..].copy_from_slice(&self.0[3].to_le_bytes()); + i128::from_le_bytes(tmp) + } +} diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index dd23da3b752..2b6d4b812ee 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -3,12 +3,14 @@ use core::ops; mod specialized_div_rem; pub mod addsub; +mod big; pub mod leading_zeros; pub mod mul; pub mod sdiv; pub mod shift; pub mod udiv; +pub use big::{i256, u256}; pub use leading_zeros::__clzsi2; public_test_dep! { diff --git a/library/compiler-builtins/testcrate/tests/big.rs b/library/compiler-builtins/testcrate/tests/big.rs new file mode 100644 index 00000000000..128b5ddfd6d --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/big.rs @@ -0,0 +1,61 @@ +use compiler_builtins::int::{i256, u256, HInt, MinInt}; + +const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; + +/// Print a `u256` as hex since we can't add format implementations +fn hexu(v: u256) -> String { + format!( + "0x{:016x}{:016x}{:016x}{:016x}", + v.0[3], v.0[2], v.0[1], v.0[0] + ) +} + +#[test] +fn widen_u128() { + assert_eq!(u128::MAX.widen(), u256([u64::MAX, u64::MAX, 0, 0])); + assert_eq!( + LOHI_SPLIT.widen(), + u256([u64::MAX, 0xaaaaaaaaaaaaaaaa, 0, 0]) + ); +} + +#[test] +fn widen_i128() { + assert_eq!((-1i128).widen(), u256::MAX.signed()); + assert_eq!( + (LOHI_SPLIT as i128).widen(), + i256([u64::MAX, 0xaaaaaaaaaaaaaaaa, u64::MAX, u64::MAX]) + ); + assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); +} + +#[test] +fn widen_mul_u128() { + let tests = [ + (u128::MAX / 2, 2_u128, u256([u64::MAX - 1, u64::MAX, 0, 0])), + (u128::MAX, 2_u128, u256([u64::MAX - 1, u64::MAX, 1, 0])), + (u128::MAX, u128::MAX, u256([1, 0, u64::MAX - 1, u64::MAX])), + (u128::MIN, u128::MIN, u256::ZERO), + (1234, 0, u256::ZERO), + (0, 1234, u256::ZERO), + ]; + + let mut errors = Vec::new(); + for (i, (a, b, exp)) in tests.iter().copied().enumerate() { + let res = a.widen_mul(b); + let res_z = a.zero_widen_mul(b); + assert_eq!(res, res_z); + if res != exp { + errors.push((i, a, b, exp, res)); + } + } + + for (i, a, b, exp, res) in &errors { + eprintln!( + "FAILURE ({i}): {a:#034x} * {b:#034x} = {} got {}", + hexu(*exp), + hexu(*res) + ); + } + assert!(errors.is_empty()); +} -- cgit 1.4.1-3-g733a5 From 1be662630700d380dc57160f9faf33ae23001e3d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 10 May 2024 19:01:49 -0500 Subject: Refactor float test macros to have a fallback Change float test macros to fall back to testing against `rustc_apfloat` when system implementations are not available, rather than just skipping tests. This allows for easier debugging where operations may not be supported. --- library/compiler-builtins/testcrate/src/lib.rs | 52 ++++++++++++++++++++++ .../compiler-builtins/testcrate/tests/addsub.rs | 21 ++++----- library/compiler-builtins/testcrate/tests/cmp.rs | 39 +++++++++++++--- .../compiler-builtins/testcrate/tests/div_rem.rs | 35 ++++++++++----- library/compiler-builtins/testcrate/tests/mul.rs | 16 ++++--- 5 files changed, 127 insertions(+), 36 deletions(-) diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 13abf459eba..1f3a4b82621 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -263,3 +263,55 @@ pub fn fuzz_float_2(n: u32, f: E) { f(x, y) } } + +/// Perform an operation using builtin types if available, falling back to apfloat if not. +#[macro_export] +macro_rules! apfloat_fallback { + ( + $float_ty:ty, + // Type name in `rustc_apfloat::ieee`. Not a full path, it automatically gets the prefix. + $apfloat_ty:ident, + // Cfg expression for when builtin system operations should be used + $sys_available:meta, + // The expression to run. This expression may use `FloatTy` for its signature. + // Optionally, the final conversion back to a float can be suppressed using + // `=> no_convert` (for e.g. operations that return a bool). + $op:expr $(=> $convert:ident)?, + // Arguments that get passed to `$op` after converting to a float + $($arg:expr),+ + $(,)? + ) => {{ + #[cfg($sys_available)] + let ret = { + type FloatTy = $float_ty; + $op( $($arg),+ ) + }; + + #[cfg(not($sys_available))] + let ret = { + use rustc_apfloat::Float; + type FloatTy = rustc_apfloat::ieee::$apfloat_ty; + + let op_res = $op( $(FloatTy::from_bits($arg.to_bits().into())),+ ); + + apfloat_fallback!(@convert $float_ty, op_res $(,$convert)?) + }; + + ret + }}; + + // Operations that do not need converting back to a float + (@convert $float_ty:ty, $val:expr, no_convert) => { + $val + }; + + // Some apfloat operations return a `StatusAnd` that we need to extract the value from. This + // is the default. + (@convert $float_ty:ty, $val:expr) => {{ + // ignore the status, just get the value + let unwrapped = $val.value; + + <$float_ty>::from_bits(FloatTy::to_bits(unwrapped).try_into().unwrap()) + }}; + +} diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs index da7684ec901..85250ac3d48 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -1,5 +1,6 @@ #![allow(unused_macros)] +use core::ops::{Add, Sub}; use testcrate::*; macro_rules! sum { @@ -71,28 +72,28 @@ fn addsub() { } macro_rules! float_sum { - ($($f:ty, $fn_add:ident, $fn_sub:ident);*;) => { + ($($f:ty, $fn_add:ident, $fn_sub:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { $( fuzz_float_2(N, |x: $f, y: $f| { - let add0 = x + y; - let sub0 = x - y; + let add0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Add::add, x, y); + let sub0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Sub::sub, x, y); let add1: $f = $fn_add(x, y); let sub1: $f = $fn_sub(x, y); if !Float::eq_repr(add0, add1) { panic!( - "{}({}, {}): std: {}, builtins: {}", + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", stringify!($fn_add), x, y, add0, add1 ); } if !Float::eq_repr(sub0, sub1) { panic!( - "{}({}, {}): std: {}, builtins: {}", + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", stringify!($fn_sub), x, y, sub0, sub1 ); } }); )* - }; + } } #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] @@ -105,8 +106,8 @@ fn float_addsub() { }; float_sum!( - f32, __addsf3, __subsf3; - f64, __adddf3, __subdf3; + f32, __addsf3, __subsf3, Single, all(); + f64, __adddf3, __subdf3, Double, all(); ); } @@ -120,7 +121,7 @@ fn float_addsub_arm() { }; float_sum!( - f32, __addsf3vfp, __subsf3vfp; - f64, __adddf3vfp, __subdf3vfp; + f32, __addsf3vfp, __subsf3vfp, Single, all(); + f64, __adddf3vfp, __subdf3vfp, Double, all(); ); } diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index 14dd76b2d7a..20915b25d12 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -1,23 +1,48 @@ #![allow(unused_macros)] +#![allow(unreachable_code)] #[cfg(not(target_arch = "powerpc64"))] use testcrate::*; macro_rules! cmp { - ($x:ident, $y:ident, $($unordered_val:expr, $fn:ident);*;) => { + ( + $f:ty, $x:ident, $y:ident, $apfloat_ty:ident, $sys_available:meta, + $($unordered_val:expr, $fn:ident);*; + ) => { $( - let cmp0 = if $x.is_nan() || $y.is_nan() { + let cmp0 = if apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |x: FloatTy| x.is_nan() => no_convert, + $x + ) || apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |y: FloatTy| y.is_nan() => no_convert, + $y + ) + { $unordered_val - } else if $x < $y { + } else if apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |x, y| x < y => no_convert, + $x, $y + ) { -1 - } else if $x == $y { + } else if apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |x, y| x == y => no_convert, + $x, $y + ) { 0 } else { 1 }; + let cmp1 = $fn($x, $y); if cmp0 != cmp1 { - panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1); + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), $x, $y, cmp0, cmp1 + ); } )* }; @@ -34,7 +59,7 @@ fn float_comparisons() { fuzz_float_2(N, |x: f32, y: f32| { assert_eq!(__unordsf2(x, y) != 0, x.is_nan() || y.is_nan()); - cmp!(x, y, + cmp!(f32, x, y, Single, all(), 1, __ltsf2; 1, __lesf2; 1, __eqsf2; @@ -45,7 +70,7 @@ fn float_comparisons() { }); fuzz_float_2(N, |x: f64, y: f64| { assert_eq!(__unorddf2(x, y) != 0, x.is_nan() || y.is_nan()); - cmp!(x, y, + cmp!(f64, x, y, Double, all(), 1, __ltdf2; 1, __ledf2; 1, __eqdf2; diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index de3bd9bee8f..461e084d068 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -2,6 +2,7 @@ use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc}; + use testcrate::*; // Division algorithms have by far the nastiest and largest number of edge cases, and experience shows @@ -104,16 +105,20 @@ fn divide_sparc() { } macro_rules! float { - ($($i:ty, $fn:ident);*;) => { + ($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { $( - fuzz_float_2(N, |x: $i, y: $i| { - let quo0 = x / y; - let quo1: $i = $fn(x, y); + fuzz_float_2(N, |x: $f, y: $f| { + let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y); + let quo1: $f = $fn(x, y); #[cfg(not(target_arch = "arm"))] if !Float::eq_repr(quo0, quo1) { panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, y, quo0, quo1 + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), + x, + y, + quo0, + quo1 ); } @@ -122,8 +127,12 @@ macro_rules! float { if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) { if !Float::eq_repr(quo0, quo1) { panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, y, quo0, quo1 + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), + x, + y, + quo0, + quo1 ); } } @@ -139,10 +148,11 @@ fn float_div() { div::{__divdf3, __divsf3}, Float, }; + use core::ops::Div; float!( - f32, __divsf3; - f64, __divdf3; + f32, __divsf3, Single, all(); + f64, __divdf3, Double, all(); ); } @@ -153,9 +163,10 @@ fn float_div_arm() { div::{__divdf3vfp, __divsf3vfp}, Float, }; + use core::ops::Div; float!( - f32, __divsf3vfp; - f64, __divdf3vfp; + f32, __divsf3vfp, Single, all(); + f64, __divdf3vfp, Double, all(); ); } diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 819f06ca9ef..4fca2c13fa6 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -82,16 +82,16 @@ fn overflowing_mul() { } macro_rules! float_mul { - ($($f:ty, $fn:ident);*;) => { + ($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { $( fuzz_float_2(N, |x: $f, y: $f| { - let mul0 = x * y; + let mul0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Mul::mul, x, y); let mul1: $f = $fn(x, y); // multiplication of subnormals is not currently handled if !(Float::is_subnormal(mul0) || Float::is_subnormal(mul1)) { if !Float::eq_repr(mul0, mul1) { panic!( - "{}({}, {}): std: {}, builtins: {}", + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", stringify!($fn), x, y, mul0, mul1 ); } @@ -108,10 +108,11 @@ fn float_mul() { mul::{__muldf3, __mulsf3}, Float, }; + use core::ops::Mul; float_mul!( - f32, __mulsf3; - f64, __muldf3; + f32, __mulsf3, Single, all(); + f64, __muldf3, Double, all(); ); } @@ -122,9 +123,10 @@ fn float_mul_arm() { mul::{__muldf3vfp, __mulsf3vfp}, Float, }; + use core::ops::Mul; float_mul!( - f32, __mulsf3vfp; - f64, __muldf3vfp; + f32, __mulsf3vfp, Single, all(); + f64, __muldf3vfp, Double, all(); ); } -- cgit 1.4.1-3-g733a5 From 4509315d2fe3b3567c3e8457599ac50ff7c06d80 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 10 May 2024 19:36:35 -0500 Subject: Enable no-fail-fast for more usable test output --- library/compiler-builtins/ci/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 1298093a658..847b52435a1 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -21,7 +21,7 @@ fi if [ "${NO_STD:-}" = "1" ]; then echo "nothing to do for no_std" else - run="cargo test --manifest-path testcrate/Cargo.toml --target $target" + run="cargo test --manifest-path testcrate/Cargo.toml --no-fail-fast --target $target" $run $run --release $run --features c -- cgit 1.4.1-3-g733a5 From 2755f457f8bbdb5a5528e644c2c7d952f356221b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 10 May 2024 19:22:03 -0500 Subject: Implement `f128` addition and subtraction --- library/compiler-builtins/README.md | 4 ++-- library/compiler-builtins/build.rs | 6 ----- library/compiler-builtins/src/float/add.rs | 10 ++++++++ library/compiler-builtins/src/float/sub.rs | 12 ++++++++++ library/compiler-builtins/testcrate/Cargo.toml | 2 ++ library/compiler-builtins/testcrate/build.rs | 27 ++++++++++++++++++++++ .../compiler-builtins/testcrate/tests/addsub.rs | 17 +++++++++++++- 7 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 library/compiler-builtins/testcrate/build.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 00d547f1bdb..c7241ec7c0f 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -232,7 +232,7 @@ These builtins are needed to support 128-bit integers. These builtins are needed to support `f16` and `f128`, which are in the process of being added to Rust. -- [ ] addtf3.c +- [x] addtf3.c - [ ] comparetf2.c - [ ] divtf3.c - [x] extenddftf2.c @@ -255,7 +255,7 @@ These builtins are needed to support `f16` and `f128`, which are in the process - [ ] ppc/fixunstfdi.c - [ ] ppc/floatditf.c - [ ] ppc/floatunditf.c -- [ ] subtf3.c +- [x] subtf3.c - [x] truncdfhf2.c - [x] truncsfhf2.c - [x] trunctfdf2.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index f9eba6ee29b..a5705242946 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -543,9 +543,7 @@ mod c { ("__floatsitf", "floatsitf.c"), ("__floatunditf", "floatunditf.c"), ("__floatunsitf", "floatunsitf.c"), - ("__addtf3", "addtf3.c"), ("__multf3", "multf3.c"), - ("__subtf3", "subtf3.c"), ("__divtf3", "divtf3.c"), ("__powitf2", "powitf2.c"), ("__fe_getround", "fp_mode.c"), @@ -564,9 +562,7 @@ mod c { if target_arch == "mips64" { sources.extend(&[ ("__netf2", "comparetf2.c"), - ("__addtf3", "addtf3.c"), ("__multf3", "multf3.c"), - ("__subtf3", "subtf3.c"), ("__fixtfsi", "fixtfsi.c"), ("__floatsitf", "floatsitf.c"), ("__fixunstfsi", "fixunstfsi.c"), @@ -579,9 +575,7 @@ mod c { if target_arch == "loongarch64" { sources.extend(&[ ("__netf2", "comparetf2.c"), - ("__addtf3", "addtf3.c"), ("__multf3", "multf3.c"), - ("__subtf3", "subtf3.c"), ("__fixtfsi", "fixtfsi.c"), ("__floatsitf", "floatsitf.c"), ("__fixunstfsi", "fixunstfsi.c"), diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 909948ad29c..fd151f77d8a 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -203,6 +203,16 @@ intrinsics! { add(a, b) } + #[cfg(not(any(feature = "no-f16-f128", target_arch = "powerpc", target_arch = "powerpc64")))] + pub extern "C" fn __addtf3(a: f128, b: f128) -> f128 { + add(a, b) + } + + #[cfg(all(not(feature = "no-f16-f128"), any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub extern "C" fn __addkf3(a: f128, b: f128) -> f128 { + add(a, b) + } + #[cfg(target_arch = "arm")] pub extern "C" fn __addsf3vfp(a: f32, b: f32) -> f32 { a + b diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 64653ee25ff..de33259d640 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -15,6 +15,18 @@ intrinsics! { __adddf3(a, f64::from_repr(b.repr() ^ f64::SIGN_MASK)) } + #[cfg(not(any(feature = "no-f16-f128", target_arch = "powerpc", target_arch = "powerpc64")))] + pub extern "C" fn __subtf3(a: f128, b: f128) -> f128 { + use crate::float::add::__addtf3; + __addtf3(a, f128::from_repr(b.repr() ^ f128::SIGN_MASK)) + } + + #[cfg(all(not(feature = "no-f16-f128"), any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub extern "C" fn __subkf3(a: f128, b: f128) -> f128 { + use crate::float::add::__addkf3; + __addkf3(a, f128::from_repr(b.repr() ^ f128::SIGN_MASK)) + } + #[cfg(target_arch = "arm")] pub extern "C" fn __subsf3vfp(a: f32, b: f32) -> f32 { a - b diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 6ff3fde1705..6f771181a05 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -33,3 +33,5 @@ no-asm = ["compiler_builtins/no-asm"] no-f16-f128 = ["compiler_builtins/no-f16-f128"] mem = ["compiler_builtins/mem"] mangled-names = ["compiler_builtins/mangled-names"] +# Skip tests that rely on f128 symbols being available on the system +no-sys-f128 = [] diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs new file mode 100644 index 00000000000..f24dae3c664 --- /dev/null +++ b/library/compiler-builtins/testcrate/build.rs @@ -0,0 +1,27 @@ +use std::env; + +fn main() { + let target = env::var("TARGET").unwrap(); + + // These platforms do not have f128 symbols available in their system libraries, so + // skip related tests. + if target.starts_with("arm-") + || target.contains("apple-darwin") + || target.contains("windows-msvc") + // GCC and LLVM disagree on the ABI of `f16` and `f128` with MinGW. See + // . + || target.contains("windows-gnu") + // FIXME(llvm): There is an ABI incompatibility between GCC and Clang on 32-bit x86. + // See . + || target.starts_with("i686") + // 32-bit PowerPC gets code generated that Qemu cannot handle. See + // . + || target.starts_with("powerpc-") + // FIXME: We get different results from the builtin functions. See + // . + || target.starts_with("powerpc64-") + { + println!("cargo:warning=using apfloat fallback for f128"); + println!("cargo:rustc-cfg=feature=\"no-sys-f128\""); + } +} diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs index 85250ac3d48..d3e96d57de3 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -1,6 +1,7 @@ #![allow(unused_macros)] +#![feature(f128)] +#![feature(f16)] -use core::ops::{Add, Sub}; use testcrate::*; macro_rules! sum { @@ -104,11 +105,24 @@ fn float_addsub() { sub::{__subdf3, __subsf3}, Float, }; + use core::ops::{Add, Sub}; float_sum!( f32, __addsf3, __subsf3, Single, all(); f64, __adddf3, __subdf3, Double, all(); ); + + #[cfg(not(feature = "no-f16-f128"))] + { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + use compiler_builtins::float::{add::__addkf3 as __addtf3, sub::__subkf3 as __subtf3}; + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + use compiler_builtins::float::{add::__addtf3, sub::__subtf3}; + + float_sum!( + f128, __addtf3, __subtf3, Quad, not(feature = "no-sys-f128"); + ); + } } #[cfg(target_arch = "arm")] @@ -119,6 +133,7 @@ fn float_addsub_arm() { sub::{__subdf3vfp, __subsf3vfp}, Float, }; + use core::ops::{Add, Sub}; float_sum!( f32, __addsf3vfp, __subsf3vfp, Single, all(); -- cgit 1.4.1-3-g733a5 From 191c1b88cde9ff8c34ffd7027aad1d7ae1c54bcd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 10 May 2024 19:46:50 -0500 Subject: Implement `f128` multiplication --- library/compiler-builtins/README.md | 2 +- library/compiler-builtins/build.rs | 5 ----- library/compiler-builtins/src/float/mul.rs | 11 +++++++++++ library/compiler-builtins/testcrate/tests/mul.rs | 17 +++++++++++++++++ 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index c7241ec7c0f..1986c21c669 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -249,7 +249,7 @@ These builtins are needed to support `f16` and `f128`, which are in the process - [ ] floatsitf.c - [ ] floatunditf.c - [ ] floatunsitf.c -- [ ] multf3.c +- [x] multf3.c - [ ] powitf2.c - [ ] ppc/fixtfdi.c - [ ] ppc/fixunstfdi.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a5705242946..ec830ecb34b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -543,7 +543,6 @@ mod c { ("__floatsitf", "floatsitf.c"), ("__floatunditf", "floatunditf.c"), ("__floatunsitf", "floatunsitf.c"), - ("__multf3", "multf3.c"), ("__divtf3", "divtf3.c"), ("__powitf2", "powitf2.c"), ("__fe_getround", "fp_mode.c"), @@ -562,26 +561,22 @@ mod c { if target_arch == "mips64" { sources.extend(&[ ("__netf2", "comparetf2.c"), - ("__multf3", "multf3.c"), ("__fixtfsi", "fixtfsi.c"), ("__floatsitf", "floatsitf.c"), ("__fixunstfsi", "fixunstfsi.c"), ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), - ("__divtf3", "divtf3.c"), ]); } if target_arch == "loongarch64" { sources.extend(&[ ("__netf2", "comparetf2.c"), - ("__multf3", "multf3.c"), ("__fixtfsi", "fixtfsi.c"), ("__floatsitf", "floatsitf.c"), ("__fixunstfsi", "fixunstfsi.c"), ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), - ("__divtf3", "divtf3.c"), ]); } diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 46c41d09f19..9866b62804d 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -199,6 +199,17 @@ intrinsics! { mul(a, b) } + #[cfg(not(any(feature = "no-f16-f128", target_arch = "powerpc", target_arch = "powerpc64")))] + pub extern "C" fn __multf3(a: f128, b: f128) -> f128 { + mul(a, b) + } + + + #[cfg(all(not(feature = "no-f16-f128"), any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub extern "C" fn __mulkf3(a: f128, b: f128) -> f128 { + mul(a, b) + } + #[cfg(target_arch = "arm")] pub extern "C" fn __mulsf3vfp(a: f32, b: f32) -> f32 { a * b diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 4fca2c13fa6..ffbe638644d 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -1,4 +1,6 @@ #![allow(unused_macros)] +#![feature(f128)] +#![feature(f16)] use testcrate::*; @@ -114,6 +116,21 @@ fn float_mul() { f32, __mulsf3, Single, all(); f64, __muldf3, Double, all(); ); + + #[cfg(not(feature = "no-f16-f128"))] + { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + use compiler_builtins::float::mul::__mulkf3 as __multf3; + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + use compiler_builtins::float::mul::__multf3; + + float_mul!( + f128, __multf3, Quad, + // FIXME(llvm): there is a bug in LLVM rt. + // See . + not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux"))); + ); + } } #[cfg(target_arch = "arm")] -- cgit 1.4.1-3-g733a5 From aaa52607489e964eafb369904f23246edd1ec402 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 11 May 2024 01:18:38 -0500 Subject: Implement `f128` comparison --- library/compiler-builtins/README.md | 2 +- library/compiler-builtins/src/float/cmp.rs | 83 ++++++++++++++++++++++++ library/compiler-builtins/testcrate/tests/cmp.rs | 40 ++++++++++++ 3 files changed, 124 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 1986c21c669..37d7ab2e671 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -233,7 +233,7 @@ These builtins are needed to support 128-bit integers. These builtins are needed to support `f16` and `f128`, which are in the process of being added to Rust. - [x] addtf3.c -- [ ] comparetf2.c +- [x] comparetf2.c - [ ] divtf3.c - [x] extenddftf2.c - [x] extendhfsf2.c diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 193c5df368c..44ebf6262ea 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -172,6 +172,89 @@ intrinsics! { } } +#[cfg(not(any( + feature = "no-f16-f128", + target_arch = "powerpc", + target_arch = "powerpc64" +)))] +intrinsics! { + #[avr_skip] + pub extern "C" fn __letf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __getf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_ge_abi() + } + + #[avr_skip] + pub extern "C" fn __unordtf2(a: f128, b: f128) -> i32 { + unord(a, b) as i32 + } + + #[avr_skip] + pub extern "C" fn __eqtf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __lttf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __netf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __gttf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_ge_abi() + } +} + +#[cfg(all( + not(feature = "no-f16-f128"), + any(target_arch = "powerpc", target_arch = "powerpc64") +))] +intrinsics! { + #[avr_skip] + pub extern "C" fn __lekf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __gekf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_ge_abi() + } + + #[avr_skip] + pub extern "C" fn __unordkf2(a: f128, b: f128) -> i32 { + unord(a, b) as i32 + } + + #[avr_skip] + pub extern "C" fn __eqkf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __ltkf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __nekf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __gtkf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_ge_abi() + } +} + #[cfg(target_arch = "arm")] intrinsics! { pub extern "aapcs" fn __aeabi_fcmple(a: f32, b: f32) -> i32 { diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index 20915b25d12..0d15f5d421f 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -1,5 +1,7 @@ #![allow(unused_macros)] #![allow(unreachable_code)] +#![feature(f128)] +#![feature(f16)] #[cfg(not(target_arch = "powerpc64"))] use testcrate::*; @@ -79,6 +81,44 @@ fn float_comparisons() { 1, __nedf2; ); }); + + #[cfg(not(feature = "no-f16-f128"))] + { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + use compiler_builtins::float::cmp::{ + __eqkf2 as __eqtf2, __gekf2 as __getf2, __gtkf2 as __gttf2, __lekf2 as __letf2, + __ltkf2 as __lttf2, __nekf2 as __netf2, __unordkf2 as __unordtf2, + }; + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + use compiler_builtins::float::cmp::{ + __eqtf2, __getf2, __gttf2, __letf2, __lttf2, __netf2, __unordtf2, + }; + + fuzz_float_2(N, |x: f128, y: f128| { + let x_is_nan = apfloat_fallback!( + f128, Quad, not(feature = "no-sys-f128"), + |x: FloatTy| x.is_nan() => no_convert, + x + ); + let y_is_nan = apfloat_fallback!( + f128, Quad, not(feature = "no-sys-f128"), + |x: FloatTy| x.is_nan() => no_convert, + y + ); + + assert_eq!(__unordtf2(x, y) != 0, x_is_nan || y_is_nan); + + cmp!(f128, x, y, Quad, not(feature = "no-sys-f128"), + 1, __lttf2; + 1, __letf2; + 1, __eqtf2; + -1, __getf2; + -1, __gttf2; + 1, __netf2; + ); + }); + } } macro_rules! cmp2 { -- cgit 1.4.1-3-g733a5 From a82491ed5401386defb3335fcc82bfb37fbd41aa Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 May 2024 17:17:46 -0500 Subject: Correct f128 extend and truncate symbol names on powerpc PowerPC uses `kf` instead of `tf`: --- library/compiler-builtins/src/float/extend.rs | 18 ++++++++++++++++++ library/compiler-builtins/src/float/trunc.rs | 18 ++++++++++++++++++ library/compiler-builtins/testcrate/tests/conv.rs | 16 ++++++++++++++-- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 5b0c0d97268..12e5fc9e10f 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -100,19 +100,37 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pub extern "C" fn __extendhftf2(a: f16) -> f128 { extend(a) } + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + pub extern "C" fn __extendhfkf2(a: f16) -> f128 { + extend(a) + } + #[avr_skip] #[aapcs_on_arm] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pub extern "C" fn __extendsftf2(a: f32) -> f128 { extend(a) } + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + pub extern "C" fn __extendsfkf2(a: f32) -> f128 { + extend(a) + } + #[avr_skip] #[aapcs_on_arm] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pub extern "C" fn __extenddftf2(a: f64) -> f128 { extend(a) } + + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + pub extern "C" fn __extenddfkf2(a: f64) -> f128 { + extend(a) + } } diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index b607a654983..31351b5e969 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -155,19 +155,37 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pub extern "C" fn __trunctfhf2(a: f128) -> f16 { trunc(a) } + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + pub extern "C" fn __trunckfhf2(a: f128) -> f16 { + trunc(a) + } + #[avr_skip] #[aapcs_on_arm] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pub extern "C" fn __trunctfsf2(a: f128) -> f32 { trunc(a) } + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + pub extern "C" fn __trunckfsf2(a: f128) -> f32 { + trunc(a) + } + #[avr_skip] #[aapcs_on_arm] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pub extern "C" fn __trunctfdf2(a: f128) -> f64 { trunc(a) } + + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + pub extern "C" fn __trunckfdf2(a: f128) -> f64 { + trunc(a) + } } diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 5cff01202a8..f0ef9525563 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -187,9 +187,15 @@ fn float_extend() { conv!(f32, f64, __extendsfdf2, Single, Double); #[cfg(not(feature = "no-f16-f128"))] { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] use compiler_builtins::float::extend::{ - __extenddftf2, __extendhfsf2, __extendhftf2, __extendsftf2, __gnu_h2f_ieee, + __extenddfkf2 as __extenddftf2, __extendhfkf2 as __extendhftf2, + __extendsfkf2 as __extendsftf2, }; + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + use compiler_builtins::float::extend::{__extenddftf2, __extendhftf2, __extendsftf2}; + use compiler_builtins::float::extend::{__extendhfsf2, __gnu_h2f_ieee}; + // FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly conv!(f16, f32, __extendhfsf2, Half, Single); conv!(f16, f32, __gnu_h2f_ieee, Half, Single); @@ -234,9 +240,15 @@ fn float_trunc() { conv!(f64, f32, __truncdfsf2, Double, Single); #[cfg(not(feature = "no-f16-f128"))] { + use compiler_builtins::float::trunc::{__gnu_f2h_ieee, __truncdfhf2, __truncsfhf2}; + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] use compiler_builtins::float::trunc::{ - __gnu_f2h_ieee, __truncdfhf2, __truncsfhf2, __trunctfdf2, __trunctfhf2, __trunctfsf2, + __trunckfdf2 as __trunctfdf2, __trunckfhf2 as __trunctfhf2, + __trunckfsf2 as __trunctfsf2, }; + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + use compiler_builtins::float::trunc::{__trunctfdf2, __trunctfhf2, __trunctfsf2}; + // FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly conv!(f32, f16, __truncsfhf2, Single, Half); conv!(f32, f16, __gnu_f2h_ieee, Single, Half); -- cgit 1.4.1-3-g733a5 From f82e1f14fc6f61dfcba3dd67fcb6bd40e6a40cda Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 18 May 2024 04:07:37 -0400 Subject: Rework the test crate to separate individual tests Currently, tests of the same kind are grouped together across all types into a single function. This makes it difficult to understand exactly what failed in CI. Change test macros to create separate functions for separate types so failures are more fine grained. --- .../compiler-builtins/testcrate/tests/addsub.rs | 226 ++++++----- library/compiler-builtins/testcrate/tests/cmp.rs | 279 +++++++------ library/compiler-builtins/testcrate/tests/conv.rs | 435 +++++++++++++-------- .../compiler-builtins/testcrate/tests/div_rem.rs | 70 ++-- library/compiler-builtins/testcrate/tests/misc.rs | 71 ++-- library/compiler-builtins/testcrate/tests/mul.rs | 238 +++++------ library/compiler-builtins/testcrate/tests/shift.rs | 52 ++- 7 files changed, 756 insertions(+), 615 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs index d3e96d57de3..f21f61ff679 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -4,139 +4,149 @@ use testcrate::*; -macro_rules! sum { - ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { - $( - fuzz_2(N, |x: $i, y: $i| { - let add0 = x.wrapping_add(y); - let sub0 = x.wrapping_sub(y); - let add1: $i = $fn_add(x, y); - let sub1: $i = $fn_sub(x, y); - if add0 != add1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn_add), x, y, add0, add1 - ); - } - if sub0 != sub1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn_sub), x, y, sub0, sub1 - ); - } - }); - )* - }; -} +mod int_addsub { + use super::*; -macro_rules! overflowing_sum { - ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { - $( - fuzz_2(N, |x: $i, y: $i| { - let add0 = x.overflowing_add(y); - let sub0 = x.overflowing_sub(y); - let add1: ($i, bool) = $fn_add(x, y); - let sub1: ($i, bool) = $fn_sub(x, y); - if add0.0 != add1.0 || add0.1 != add1.1 { - panic!( - "{}({}, {}): std: {:?}, builtins: {:?}", - stringify!($fn_add), x, y, add0, add1 - ); - } - if sub0.0 != sub1.0 || sub0.1 != sub1.1 { - panic!( - "{}({}, {}): std: {:?}, builtins: {:?}", - stringify!($fn_sub), x, y, sub0, sub1 - ); + macro_rules! sum { + ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { + $( + #[test] + fn $fn_add() { + use compiler_builtins::int::addsub::{$fn_add, $fn_sub}; + + fuzz_2(N, |x: $i, y: $i| { + let add0 = x.wrapping_add(y); + let sub0 = x.wrapping_sub(y); + let add1: $i = $fn_add(x, y); + let sub1: $i = $fn_sub(x, y); + if add0 != add1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_add), x, y, add0, add1 + ); + } + if sub0 != sub1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_sub), x, y, sub0, sub1 + ); + } + }); } - }); - )* - }; -} + )* + }; + } + + macro_rules! overflowing_sum { + ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { + $( + #[test] + fn $fn_add() { + use compiler_builtins::int::addsub::{$fn_add, $fn_sub}; -#[test] -fn addsub() { - use compiler_builtins::int::addsub::{ - __rust_i128_add, __rust_i128_addo, __rust_i128_sub, __rust_i128_subo, __rust_u128_add, - __rust_u128_addo, __rust_u128_sub, __rust_u128_subo, - }; + fuzz_2(N, |x: $i, y: $i| { + let add0 = x.overflowing_add(y); + let sub0 = x.overflowing_sub(y); + let add1: ($i, bool) = $fn_add(x, y); + let sub1: ($i, bool) = $fn_sub(x, y); + if add0.0 != add1.0 || add0.1 != add1.1 { + panic!( + "{}({}, {}): std: {:?}, builtins: {:?}", + stringify!($fn_add), x, y, add0, add1 + ); + } + if sub0.0 != sub1.0 || sub0.1 != sub1.1 { + panic!( + "{}({}, {}): std: {:?}, builtins: {:?}", + stringify!($fn_sub), x, y, sub0, sub1 + ); + } + }); + } + )* + }; + } // Integer addition and subtraction is very simple, so 100 fuzzing passes should be plenty. - sum!( + sum! { u128, __rust_u128_add, __rust_u128_sub; i128, __rust_i128_add, __rust_i128_sub; - ); - overflowing_sum!( + } + + overflowing_sum! { u128, __rust_u128_addo, __rust_u128_subo; i128, __rust_i128_addo, __rust_i128_subo; - ); + } } macro_rules! float_sum { ($($f:ty, $fn_add:ident, $fn_sub:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { $( - fuzz_float_2(N, |x: $f, y: $f| { - let add0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Add::add, x, y); - let sub0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Sub::sub, x, y); - let add1: $f = $fn_add(x, y); - let sub1: $f = $fn_sub(x, y); - if !Float::eq_repr(add0, add1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn_add), x, y, add0, add1 - ); - } - if !Float::eq_repr(sub0, sub1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn_sub), x, y, sub0, sub1 - ); - } - }); + #[test] + fn $fn_add() { + use core::ops::{Add, Sub}; + use compiler_builtins::float::{{add::$fn_add, sub::$fn_sub}, Float}; + + fuzz_float_2(N, |x: $f, y: $f| { + let add0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Add::add, x, y); + let sub0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Sub::sub, x, y); + let add1: $f = $fn_add(x, y); + let sub1: $f = $fn_sub(x, y); + if !Float::eq_repr(add0, add1) { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn_add), x, y, add0, add1 + ); + } + if !Float::eq_repr(sub0, sub1) { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn_sub), x, y, sub0, sub1 + ); + } + }); + } )* } } #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -#[test] -fn float_addsub() { - use compiler_builtins::float::{ - add::{__adddf3, __addsf3}, - sub::{__subdf3, __subsf3}, - Float, - }; - use core::ops::{Add, Sub}; - - float_sum!( +mod float_addsub { + use super::*; + + float_sum! { f32, __addsf3, __subsf3, Single, all(); f64, __adddf3, __subdf3, Double, all(); - ); - - #[cfg(not(feature = "no-f16-f128"))] - { - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - use compiler_builtins::float::{add::__addkf3 as __addtf3, sub::__subkf3 as __subtf3}; - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - use compiler_builtins::float::{add::__addtf3, sub::__subtf3}; - - float_sum!( - f128, __addtf3, __subtf3, Quad, not(feature = "no-sys-f128"); - ); + } +} + +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] +mod float_addsub_f128 { + use super::*; + + float_sum! { + f128, __addtf3, __subtf3, Quad, not(feature = "no-sys-f128"); + } +} + +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +mod float_addsub_f128_ppc { + use super::*; + + float_sum! { + f128, __addkf3, __subkf3, Quad, not(feature = "no-sys-f128"); } } #[cfg(target_arch = "arm")] -#[test] -fn float_addsub_arm() { - use compiler_builtins::float::{ - add::{__adddf3vfp, __addsf3vfp}, - sub::{__subdf3vfp, __subsf3vfp}, - Float, - }; - use core::ops::{Add, Sub}; - - float_sum!( +mod float_addsub_arm { + use super::*; + + float_sum! { f32, __addsf3vfp, __subsf3vfp, Single, all(); f64, __adddf3vfp, __subdf3vfp, Double, all(); - ); + } } diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index 0d15f5d421f..e8a0eb165c3 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -6,84 +6,96 @@ #[cfg(not(target_arch = "powerpc64"))] use testcrate::*; -macro_rules! cmp { - ( - $f:ty, $x:ident, $y:ident, $apfloat_ty:ident, $sys_available:meta, - $($unordered_val:expr, $fn:ident);*; - ) => { - $( - let cmp0 = if apfloat_fallback!( +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +mod float_comparisons { + use super::*; + + macro_rules! cmp { + ( + $f:ty, $x:ident, $y:ident, $apfloat_ty:ident, $sys_available:meta, + $($unordered_val:expr, $fn:ident);*; + ) => { + $( + let cmp0 = if apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |x: FloatTy| x.is_nan() => no_convert, + $x + ) || apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |y: FloatTy| y.is_nan() => no_convert, + $y + ) + { + $unordered_val + } else if apfloat_fallback!( $f, $apfloat_ty, $sys_available, - |x: FloatTy| x.is_nan() => no_convert, - $x - ) || apfloat_fallback!( + |x, y| x < y => no_convert, + $x, $y + ) { + -1 + } else if apfloat_fallback!( $f, $apfloat_ty, $sys_available, - |y: FloatTy| y.is_nan() => no_convert, - $y - ) - { - $unordered_val - } else if apfloat_fallback!( - $f, $apfloat_ty, $sys_available, - |x, y| x < y => no_convert, - $x, $y - ) { - -1 - } else if apfloat_fallback!( - $f, $apfloat_ty, $sys_available, - |x, y| x == y => no_convert, - $x, $y - ) { - 0 - } else { - 1 - }; - - let cmp1 = $fn($x, $y); - if cmp0 != cmp1 { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), $x, $y, cmp0, cmp1 - ); - } - )* - }; -} + |x, y| x == y => no_convert, + $x, $y + ) { + 0 + } else { + 1 + }; -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[test] -fn float_comparisons() { - use compiler_builtins::float::cmp::{ - __eqdf2, __eqsf2, __gedf2, __gesf2, __gtdf2, __gtsf2, __ledf2, __lesf2, __ltdf2, __ltsf2, - __nedf2, __nesf2, __unorddf2, __unordsf2, - }; - - fuzz_float_2(N, |x: f32, y: f32| { - assert_eq!(__unordsf2(x, y) != 0, x.is_nan() || y.is_nan()); - cmp!(f32, x, y, Single, all(), - 1, __ltsf2; - 1, __lesf2; - 1, __eqsf2; - -1, __gesf2; - -1, __gtsf2; - 1, __nesf2; - ); - }); - fuzz_float_2(N, |x: f64, y: f64| { - assert_eq!(__unorddf2(x, y) != 0, x.is_nan() || y.is_nan()); - cmp!(f64, x, y, Double, all(), - 1, __ltdf2; - 1, __ledf2; - 1, __eqdf2; - -1, __gedf2; - -1, __gtdf2; - 1, __nedf2; - ); - }); + let cmp1 = $fn($x, $y); + if cmp0 != cmp1 { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), $x, $y, cmp0, cmp1 + ); + } + )* + }; + } + + #[test] + fn cmp_f32() { + use compiler_builtins::float::cmp::{ + __eqsf2, __gesf2, __gtsf2, __lesf2, __ltsf2, __nesf2, __unordsf2, + }; + fuzz_float_2(N, |x: f32, y: f32| { + assert_eq!(__unordsf2(x, y) != 0, x.is_nan() || y.is_nan()); + cmp!(f32, x, y, Single, all(), + 1, __ltsf2; + 1, __lesf2; + 1, __eqsf2; + -1, __gesf2; + -1, __gtsf2; + 1, __nesf2; + ); + }); + } + + #[test] + fn cmp_f64() { + use compiler_builtins::float::cmp::{ + __eqdf2, __gedf2, __gtdf2, __ledf2, __ltdf2, __nedf2, __unorddf2, + }; + + fuzz_float_2(N, |x: f64, y: f64| { + assert_eq!(__unorddf2(x, y) != 0, x.is_nan() || y.is_nan()); + cmp!(f64, x, y, Double, all(), + 1, __ltdf2; + 1, __ledf2; + 1, __eqdf2; + -1, __gedf2; + -1, __gtdf2; + 1, __nedf2; + ); + }); + } + + #[test] #[cfg(not(feature = "no-f16-f128"))] - { + fn cmp_f128() { #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] use compiler_builtins::float::cmp::{ __eqkf2 as __eqtf2, __gekf2 as __getf2, __gtkf2 as __gttf2, __lekf2 as __letf2, @@ -121,60 +133,71 @@ fn float_comparisons() { } } -macro_rules! cmp2 { - ($x:ident, $y:ident, $($unordered_val:expr, $fn_std:expr, $fn_builtins:ident);*;) => { - $( - let cmp0: i32 = if $x.is_nan() || $y.is_nan() { - $unordered_val - } else { - $fn_std as i32 - }; - let cmp1: i32 = $fn_builtins($x, $y); - if cmp0 != cmp1 { - panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1); - } - )* - }; -} - #[cfg(target_arch = "arm")] -#[test] -fn float_comparisons_arm() { - use compiler_builtins::float::cmp::{ - __aeabi_dcmpeq, __aeabi_dcmpge, __aeabi_dcmpgt, __aeabi_dcmple, __aeabi_dcmplt, - __aeabi_fcmpeq, __aeabi_fcmpge, __aeabi_fcmpgt, __aeabi_fcmple, __aeabi_fcmplt, __eqdf2vfp, - __eqsf2vfp, __gedf2vfp, __gesf2vfp, __gtdf2vfp, __gtsf2vfp, __ledf2vfp, __lesf2vfp, - __ltdf2vfp, __ltsf2vfp, __nedf2vfp, __nesf2vfp, - }; - - fuzz_float_2(N, |x: f32, y: f32| { - cmp2!(x, y, - 0, x < y, __aeabi_fcmplt; - 0, x <= y, __aeabi_fcmple; - 0, x == y, __aeabi_fcmpeq; - 0, x >= y, __aeabi_fcmpge; - 0, x > y, __aeabi_fcmpgt; - 0, x < y, __ltsf2vfp; - 0, x <= y, __lesf2vfp; - 0, x == y, __eqsf2vfp; - 0, x >= y, __gesf2vfp; - 0, x > y, __gtsf2vfp; - 1, x != y, __nesf2vfp; - ); - }); - fuzz_float_2(N, |x: f64, y: f64| { - cmp2!(x, y, - 0, x < y, __aeabi_dcmplt; - 0, x <= y, __aeabi_dcmple; - 0, x == y, __aeabi_dcmpeq; - 0, x >= y, __aeabi_dcmpge; - 0, x > y, __aeabi_dcmpgt; - 0, x < y, __ltdf2vfp; - 0, x <= y, __ledf2vfp; - 0, x == y, __eqdf2vfp; - 0, x >= y, __gedf2vfp; - 0, x > y, __gtdf2vfp; - 1, x != y, __nedf2vfp; - ); - }); +mod float_comparisons_arm { + use super::*; + + macro_rules! cmp2 { + ($x:ident, $y:ident, $($unordered_val:expr, $fn_std:expr, $fn_builtins:ident);*;) => { + $( + let cmp0: i32 = if $x.is_nan() || $y.is_nan() { + $unordered_val + } else { + $fn_std as i32 + }; + let cmp1: i32 = $fn_builtins($x, $y); + if cmp0 != cmp1 { + panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1); + } + )* + }; + } + + #[test] + fn cmp_f32() { + use compiler_builtins::float::cmp::{ + __aeabi_fcmpeq, __aeabi_fcmpge, __aeabi_fcmpgt, __aeabi_fcmple, __aeabi_fcmplt, + __eqsf2vfp, __gesf2vfp, __gtsf2vfp, __lesf2vfp, __ltsf2vfp, __nesf2vfp, + }; + + fuzz_float_2(N, |x: f32, y: f32| { + cmp2!(x, y, + 0, x < y, __aeabi_fcmplt; + 0, x <= y, __aeabi_fcmple; + 0, x == y, __aeabi_fcmpeq; + 0, x >= y, __aeabi_fcmpge; + 0, x > y, __aeabi_fcmpgt; + 0, x < y, __ltsf2vfp; + 0, x <= y, __lesf2vfp; + 0, x == y, __eqsf2vfp; + 0, x >= y, __gesf2vfp; + 0, x > y, __gtsf2vfp; + 1, x != y, __nesf2vfp; + ); + }); + } + + #[test] + fn cmp_f64() { + use compiler_builtins::float::cmp::{ + __aeabi_dcmpeq, __aeabi_dcmpge, __aeabi_dcmpgt, __aeabi_dcmple, __aeabi_dcmplt, + __eqdf2vfp, __gedf2vfp, __gtdf2vfp, __ledf2vfp, __ltdf2vfp, __nedf2vfp, + }; + + fuzz_float_2(N, |x: f64, y: f64| { + cmp2!(x, y, + 0, x < y, __aeabi_dcmplt; + 0, x <= y, __aeabi_dcmple; + 0, x == y, __aeabi_dcmpeq; + 0, x >= y, __aeabi_dcmpge; + 0, x > y, __aeabi_dcmpgt; + 0, x < y, __ltdf2vfp; + 0, x <= y, __ledf2vfp; + 0, x == y, __eqdf2vfp; + 0, x >= y, __gedf2vfp; + 0, x > y, __gtdf2vfp; + 1, x != y, __nedf2vfp; + ); + }); + } } diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index f0ef9525563..7b672ac251e 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -2,84 +2,83 @@ #![cfg_attr(not(feature = "no-f16-f128"), feature(f128))] // makes configuration easier #![allow(unused_macros)] +#![allow(unused_imports)] use compiler_builtins::float::Float; -use rustc_apfloat::ieee::{Double, Single}; -#[cfg(not(feature = "no-f16-f128"))] -use rustc_apfloat::ieee::{Half, Quad}; use rustc_apfloat::{Float as _, FloatConvert as _}; use testcrate::*; -macro_rules! i_to_f { - ($($from:ty, $into:ty, $fn:ident);*;) => { - $( - fuzz(N, |x: $from| { - let f0 = x as $into; - let f1: $into = $fn(x); - // This makes sure that the conversion produced the best rounding possible, and does - // this independent of `x as $into` rounding correctly. - // This assumes that float to integer conversion is correct. - let y_minus_ulp = <$into>::from_bits(f1.to_bits().wrapping_sub(1)) as $from; - let y = f1 as $from; - let y_plus_ulp = <$into>::from_bits(f1.to_bits().wrapping_add(1)) as $from; - let error_minus = <$from as Int>::abs_diff(y_minus_ulp, x); - let error = <$from as Int>::abs_diff(y, x); - let error_plus = <$from as Int>::abs_diff(y_plus_ulp, x); - // The first two conditions check that none of the two closest float values are - // strictly closer in representation to `x`. The second makes sure that rounding is - // towards even significand if two float values are equally close to the integer. - if error_minus < error - || error_plus < error - || ((error_minus == error || error_plus == error) - && ((f0.to_bits() & 1) != 0)) - { - if !cfg!(any( - target_arch = "powerpc", - target_arch = "powerpc64" - )) { - panic!( - "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", - stringify!($fn), - x, - f1.to_bits(), - y_minus_ulp, - y, - y_plus_ulp, - error_minus, - error, - error_plus, - ); - } - } - // Test against native conversion. We disable testing on all `x86` because of - // rounding bugs with `i686`. `powerpc` also has the same rounding bug. - if f0 != f1 && !cfg!(any( - target_arch = "x86", - target_arch = "powerpc", - target_arch = "powerpc64" - )) { - panic!( - "{}({}): std: {}, builtins: {}", - stringify!($fn), - x, - f0, - f1, - ); - } - }); - )* - }; -} +mod int_to_float { + use super::*; -#[test] -fn int_to_float() { - use compiler_builtins::float::conv::{ - __floatdidf, __floatdisf, __floatsidf, __floatsisf, __floattidf, __floattisf, - __floatundidf, __floatundisf, __floatunsidf, __floatunsisf, __floatuntidf, __floatuntisf, - }; - use compiler_builtins::int::Int; + macro_rules! i_to_f { + ($($from:ty, $into:ty, $fn:ident);*;) => { + $( + #[test] + fn $fn() { + use compiler_builtins::float::conv::$fn; + use compiler_builtins::int::Int; - i_to_f!( + fuzz(N, |x: $from| { + let f0 = x as $into; + let f1: $into = $fn(x); + // This makes sure that the conversion produced the best rounding possible, and does + // this independent of `x as $into` rounding correctly. + // This assumes that float to integer conversion is correct. + let y_minus_ulp = <$into>::from_bits(f1.to_bits().wrapping_sub(1)) as $from; + let y = f1 as $from; + let y_plus_ulp = <$into>::from_bits(f1.to_bits().wrapping_add(1)) as $from; + let error_minus = <$from as Int>::abs_diff(y_minus_ulp, x); + let error = <$from as Int>::abs_diff(y, x); + let error_plus = <$from as Int>::abs_diff(y_plus_ulp, x); + // The first two conditions check that none of the two closest float values are + // strictly closer in representation to `x`. The second makes sure that rounding is + // towards even significand if two float values are equally close to the integer. + if error_minus < error + || error_plus < error + || ((error_minus == error || error_plus == error) + && ((f0.to_bits() & 1) != 0)) + { + if !cfg!(any( + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + panic!( + "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", + stringify!($fn), + x, + f1.to_bits(), + y_minus_ulp, + y, + y_plus_ulp, + error_minus, + error, + error_plus, + ); + } + } + // Test against native conversion. We disable testing on all `x86` because of + // rounding bugs with `i686`. `powerpc` also has the same rounding bug. + if f0 != f1 && !cfg!(any( + target_arch = "x86", + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + f0, + f1, + ); + } + }); + } + )* + }; + } + + i_to_f! { u32, f32, __floatunsisf; u32, f64, __floatunsidf; i32, f32, __floatsisf; @@ -92,53 +91,64 @@ fn int_to_float() { u128, f64, __floatuntidf; i128, f32, __floattisf; i128, f64, __floattidf; - ); -} - -macro_rules! f_to_i { - ($x:ident, $($f:ty, $fn:ident);*;) => { - $( - // it is undefined behavior in the first place to do conversions with NaNs - if !$x.is_nan() { - let conv0 = $x as $f; - let conv1: $f = $fn($x); - if conv0 != conv1 { - panic!("{}({}): std: {}, builtins: {}", stringify!($fn), $x, conv0, conv1); - } - } - )* - }; + } } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 #[cfg(not(target_arch = "powerpc64"))] -#[test] -fn float_to_int() { - use compiler_builtins::float::conv::{ - __fixdfdi, __fixdfsi, __fixdfti, __fixsfdi, __fixsfsi, __fixsfti, __fixunsdfdi, - __fixunsdfsi, __fixunsdfti, __fixunssfdi, __fixunssfsi, __fixunssfti, - }; +mod f_to_i { + use super::*; + + macro_rules! f_to_i { + ($x:ident, $($f:ty, $fn:ident);*;) => { + $( + // it is undefined behavior in the first place to do conversions with NaNs + if !$x.is_nan() { + let conv0 = $x as $f; + let conv1: $f = $fn($x); + if conv0 != conv1 { + panic!("{}({}): std: {}, builtins: {}", stringify!($fn), $x, conv0, conv1); + } + } + )* + }; + } - fuzz_float(N, |x: f32| { - f_to_i!(x, - u32, __fixunssfsi; - u64, __fixunssfdi; - u128, __fixunssfti; - i32, __fixsfsi; - i64, __fixsfdi; - i128, __fixsfti; - ); - }); - fuzz_float(N, |x: f64| { - f_to_i!(x, - u32, __fixunsdfsi; - u64, __fixunsdfdi; - u128, __fixunsdfti; - i32, __fixdfsi; - i64, __fixdfdi; - i128, __fixdfti; - ); - }); + #[test] + fn f32_to_int() { + use compiler_builtins::float::conv::{ + __fixsfdi, __fixsfsi, __fixsfti, __fixunssfdi, __fixunssfsi, __fixunssfti, + }; + + fuzz_float(N, |x: f32| { + f_to_i!(x, + u32, __fixunssfsi; + u64, __fixunssfdi; + u128, __fixunssfti; + i32, __fixsfsi; + i64, __fixsfdi; + i128, __fixsfti; + ); + }); + } + + #[test] + fn f64_to_int() { + use compiler_builtins::float::conv::{ + __fixdfdi, __fixdfsi, __fixdfti, __fixunsdfdi, __fixunsdfsi, __fixunsdfti, + }; + + fuzz_float(N, |x: f64| { + f_to_i!(x, + u32, __fixunsdfsi; + u64, __fixunsdfdi; + u128, __fixunsdfti; + i32, __fixdfsi; + i64, __fixdfdi; + i128, __fixdfti; + ); + }); + } } macro_rules! conv { @@ -161,40 +171,54 @@ macro_rules! conv { macro_rules! extend { ($fX:ident, $fD:ident, $fn:ident) => { - fuzz_float(N, |x: $fX| { - let tmp0 = x as $fD; - let tmp1: $fD = $fn(x); - if !Float::eq_repr(tmp0, tmp1) { - panic!( - "{}({}): std: {}, builtins: {}", - stringify!($fn), - x, - tmp0, - tmp1 - ); - } - }); + #[test] + fn $fn() { + use compiler_builtins::float::extend::$fn; + + fuzz_float(N, |x: $fX| { + let tmp0 = x as $fD; + let tmp1: $fD = $fn(x); + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + tmp0, + tmp1 + ); + } + }); + } }; } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 #[cfg(not(target_arch = "powerpc64"))] -#[test] -fn float_extend() { - use compiler_builtins::float::extend::__extendsfdf2; +mod float_extend { + use super::*; extend!(f32, f64, __extendsfdf2); - conv!(f32, f64, __extendsfdf2, Single, Double); - #[cfg(not(feature = "no-f16-f128"))] - { - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + + #[test] + fn conv() { + use compiler_builtins::float::extend::__extendsfdf2; + use rustc_apfloat::ieee::{Double, Single}; + + conv!(f32, f64, __extendsfdf2, Single, Double); + } +} + +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] +mod float_extend_f128 { + use super::*; + + #[test] + fn conv() { use compiler_builtins::float::extend::{ - __extenddfkf2 as __extenddftf2, __extendhfkf2 as __extendhftf2, - __extendsfkf2 as __extendsftf2, + __extenddftf2, __extendhfsf2, __extendhftf2, __extendsftf2, __gnu_h2f_ieee, }; - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - use compiler_builtins::float::extend::{__extenddftf2, __extendhftf2, __extendsftf2}; - use compiler_builtins::float::extend::{__extendhfsf2, __gnu_h2f_ieee}; + use rustc_apfloat::ieee::{Double, Half, Quad, Single}; // FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly conv!(f16, f32, __extendhfsf2, Half, Single); @@ -205,49 +229,91 @@ fn float_extend() { } } +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +mod float_extend_f128_ppc { + use super::*; + + #[test] + fn conv() { + use compiler_builtins::float::extend::{ + __extenddfkf2, __extendhfkf2, __extendhfsf2, __extendsfkf2, __gnu_h2f_ieee, + }; + use rustc_apfloat::ieee::{Double, Half, Quad, Single}; + + // FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly + conv!(f16, f32, __extendhfsf2, Half, Single); + conv!(f16, f32, __gnu_h2f_ieee, Half, Single); + conv!(f16, f128, __extendhfkf2, Half, Quad); + conv!(f32, f128, __extendsfkf2, Single, Quad); + conv!(f64, f128, __extenddfkf2, Double, Quad); + } +} + #[cfg(target_arch = "arm")] -#[test] -fn float_extend_arm() { - use compiler_builtins::float::extend::__extendsfdf2vfp; +mod float_extend_arm { + use super::*; extend!(f32, f64, __extendsfdf2vfp); - conv!(f32, f64, __extendsfdf2vfp, Single, Double); + + #[test] + fn conv() { + use compiler_builtins::float::extend::__extendsfdf2vfp; + use rustc_apfloat::ieee::{Double, Single}; + + conv!(f32, f64, __extendsfdf2vfp, Single, Double); + } } macro_rules! trunc { ($fX:ident, $fD:ident, $fn:ident) => { - fuzz_float(N, |x: $fX| { - let tmp0 = x as $fD; - let tmp1: $fD = $fn(x); - if !Float::eq_repr(tmp0, tmp1) { - panic!( - "{}({}): std: {}, builtins: {}", - stringify!($fn), - x, - tmp0, - tmp1 - ); - } - }); + #[test] + fn $fn() { + use compiler_builtins::float::trunc::$fn; + + fuzz_float(N, |x: $fX| { + let tmp0 = x as $fD; + let tmp1: $fD = $fn(x); + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + tmp0, + tmp1 + ); + } + }); + } }; } -#[test] -fn float_trunc() { - use compiler_builtins::float::trunc::__truncdfsf2; +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +mod float_trunc { + use super::*; trunc!(f64, f32, __truncdfsf2); - conv!(f64, f32, __truncdfsf2, Double, Single); - #[cfg(not(feature = "no-f16-f128"))] - { + + #[test] + fn conv() { + use compiler_builtins::float::trunc::__truncdfsf2; + use rustc_apfloat::ieee::{Double, Single}; + + conv!(f64, f32, __truncdfsf2, Double, Single); + } +} + +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] +mod float_trunc_f128 { + use super::*; + + #[test] + fn conv() { use compiler_builtins::float::trunc::{__gnu_f2h_ieee, __truncdfhf2, __truncsfhf2}; - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - use compiler_builtins::float::trunc::{ - __trunckfdf2 as __trunctfdf2, __trunckfhf2 as __trunctfhf2, - __trunckfsf2 as __trunctfsf2, - }; - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] use compiler_builtins::float::trunc::{__trunctfdf2, __trunctfhf2, __trunctfsf2}; + use rustc_apfloat::ieee::{Double, Half, Quad, Single}; // FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly conv!(f32, f16, __truncsfhf2, Single, Half); @@ -259,11 +325,38 @@ fn float_trunc() { } } +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +mod float_trunc_f128_ppc { + use super::*; + + #[test] + fn conv() { + use compiler_builtins::float::trunc::{__gnu_f2h_ieee, __truncdfhf2, __truncsfhf2}; + use compiler_builtins::float::trunc::{__trunckfdf2, __trunckfhf2, __trunckfsf2}; + use rustc_apfloat::ieee::{Double, Half, Quad, Single}; + + // FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly + conv!(f32, f16, __truncsfhf2, Single, Half); + conv!(f32, f16, __gnu_f2h_ieee, Single, Half); + conv!(f64, f16, __truncdfhf2, Double, Half); + conv!(f128, f16, __trunckfhf2, Quad, Half); + conv!(f128, f32, __trunckfsf2, Quad, Single); + conv!(f128, f64, __trunckfdf2, Quad, Double); + } +} + #[cfg(target_arch = "arm")] -#[test] -fn float_trunc_arm() { - use compiler_builtins::float::trunc::__truncdfsf2vfp; +mod float_trunc_arm { + use super::*; trunc!(f64, f32, __truncdfsf2vfp); - conv!(f64, f32, __truncdfsf2vfp, Double, Single) + + #[test] + fn conv() { + use compiler_builtins::float::trunc::__truncdfsf2vfp; + use rustc_apfloat::ieee::{Double, Single}; + + conv!(f64, f32, __truncdfsf2vfp, Double, Single) + } } diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index 461e084d068..ff78b4f54d5 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -107,24 +107,15 @@ fn divide_sparc() { macro_rules! float { ($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { $( - fuzz_float_2(N, |x: $f, y: $f| { - let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y); - let quo1: $f = $fn(x, y); - #[cfg(not(target_arch = "arm"))] - if !Float::eq_repr(quo0, quo1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), - x, - y, - quo0, - quo1 - ); - } + #[test] + fn $fn() { + use compiler_builtins::float::{div::$fn, Float}; + use core::ops::Div; - // ARM SIMD instructions always flush subnormals to zero - #[cfg(target_arch = "arm")] - if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) { + fuzz_float_2(N, |x: $f, y: $f| { + let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y); + let quo1: $f = $fn(x, y); + #[cfg(not(target_arch = "arm"))] if !Float::eq_repr(quo0, quo1) { panic!( "{}({:?}, {:?}): std: {:?}, builtins: {:?}", @@ -135,38 +126,43 @@ macro_rules! float { quo1 ); } - } - }); + + // ARM SIMD instructions always flush subnormals to zero + #[cfg(target_arch = "arm")] + if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) { + if !Float::eq_repr(quo0, quo1) { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), + x, + y, + quo0, + quo1 + ); + } + } + }); + } )* }; } #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -#[test] -fn float_div() { - use compiler_builtins::float::{ - div::{__divdf3, __divsf3}, - Float, - }; - use core::ops::Div; +mod float_div { + use super::*; - float!( + float! { f32, __divsf3, Single, all(); f64, __divdf3, Double, all(); - ); + } } #[cfg(target_arch = "arm")] -#[test] -fn float_div_arm() { - use compiler_builtins::float::{ - div::{__divdf3vfp, __divsf3vfp}, - Float, - }; - use core::ops::Div; +mod float_div_arm { + use super::*; - float!( + float! { f32, __divsf3vfp, Single, all(); f64, __divdf3vfp, Double, all(); - ); + } } diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index cdc37e2a0d7..e01223c7484 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -98,49 +98,52 @@ fn leading_zeros() { macro_rules! pow { ($($f:ty, $tolerance:expr, $fn:ident);*;) => { $( - fuzz_float_2(N, |x: $f, y: $f| { - if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) { - let n = y.to_bits() & !<$f as Float>::SIGNIFICAND_MASK; - let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS; - let n = n as i32; - let tmp0: $f = x.powi(n); - let tmp1: $f = $fn(x, n); - let (a, b) = if tmp0 < tmp1 { - (tmp0, tmp1) - } else { - (tmp1, tmp0) - }; - let good = { - if a == b { - // handles infinity equality - true - } else if a < $tolerance { - b < $tolerance + #[test] + fn $fn() { + use compiler_builtins::float::pow::$fn; + use compiler_builtins::float::Float; + fuzz_float_2(N, |x: $f, y: $f| { + if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) { + let n = y.to_bits() & !<$f as Float>::SIGNIFICAND_MASK; + let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS; + let n = n as i32; + let tmp0: $f = x.powi(n); + let tmp1: $f = $fn(x, n); + let (a, b) = if tmp0 < tmp1 { + (tmp0, tmp1) } else { - let quo = b / a; - (quo < (1. + $tolerance)) && (quo > (1. - $tolerance)) + (tmp1, tmp0) + }; + let good = { + if a == b { + // handles infinity equality + true + } else if a < $tolerance { + b < $tolerance + } else { + let quo = b / a; + (quo < (1. + $tolerance)) && (quo > (1. - $tolerance)) + } + }; + if !good { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, n, tmp0, tmp1 + ); } - }; - if !good { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, n, tmp0, tmp1 - ); } - } - }); + }); + } )* }; } #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -#[test] -fn float_pow() { - use compiler_builtins::float::pow::{__powidf2, __powisf2}; - use compiler_builtins::float::Float; +mod float_pow { + use super::*; - pow!( + pow! { f32, 1e-4, __powisf2; f64, 1e-12, __powidf2; - ); + } } diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index ffbe638644d..5daeadeb22b 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -4,146 +4,164 @@ use testcrate::*; -macro_rules! mul { - ($($i:ty, $fn:ident);*;) => { - $( - fuzz_2(N, |x: $i, y: $i| { - let mul0 = x.wrapping_mul(y); - let mul1: $i = $fn(x, y); - if mul0 != mul1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, y, mul0, mul1 - ); - } - }); - )* - }; -} +mod int_mul { + use super::*; -#[test] -fn mul() { - use compiler_builtins::int::mul::{__muldi3, __multi3}; + macro_rules! mul { + ($($i:ty, $fn:ident);*;) => { + $( + #[test] + fn $fn() { + use compiler_builtins::int::mul::$fn; - mul!( + fuzz_2(N, |x: $i, y: $i| { + let mul0 = x.wrapping_mul(y); + let mul1: $i = $fn(x, y); + if mul0 != mul1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, mul0, mul1 + ); + } + }); + + } + )* + }; + } + + mul! { u64, __muldi3; i128, __multi3; - ); + } } -macro_rules! overflowing_mul { - ($($i:ty, $fn:ident);*;) => { - $( - fuzz_2(N, |x: $i, y: $i| { - let (mul0, o0) = x.overflowing_mul(y); - let mut o1 = 0i32; - let mul1: $i = $fn(x, y, &mut o1); - let o1 = o1 != 0; - if mul0 != mul1 || o0 != o1 { - panic!( - "{}({}, {}): std: ({}, {}), builtins: ({}, {})", - stringify!($fn), x, y, mul0, o0, mul1, o1 - ); - } - }); - )* - }; -} +mod int_overflowing_mul { + use super::*; -#[test] -fn overflowing_mul() { - use compiler_builtins::int::mul::{ - __mulodi4, __mulosi4, __muloti4, __rust_i128_mulo, __rust_u128_mulo, - }; + macro_rules! overflowing_mul { + ($($i:ty, $fn:ident);*;) => { + $( + #[test] + fn $fn() { + use compiler_builtins::int::mul::$fn; + + fuzz_2(N, |x: $i, y: $i| { + let (mul0, o0) = x.overflowing_mul(y); + let mut o1 = 0i32; + let mul1: $i = $fn(x, y, &mut o1); + let o1 = o1 != 0; + if mul0 != mul1 || o0 != o1 { + panic!( + "{}({}, {}): std: ({}, {}), builtins: ({}, {})", + stringify!($fn), x, y, mul0, o0, mul1, o1 + ); + } + }); + } + )* + }; + } - overflowing_mul!( + overflowing_mul! { i32, __mulosi4; i64, __mulodi4; i128, __muloti4; - ); - fuzz_2(N, |x: u128, y: u128| { - let (mul0, o0) = x.overflowing_mul(y); - let (mul1, o1) = __rust_u128_mulo(x, y); - if mul0 != mul1 || o0 != o1 { - panic!( - "__rust_u128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", - x, y, mul0, o0, mul1, o1 - ); - } - let x = x as i128; - let y = y as i128; - let (mul0, o0) = x.overflowing_mul(y); - let (mul1, o1) = __rust_i128_mulo(x, y); - if mul0 != mul1 || o0 != o1 { - panic!( - "__rust_i128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", - x, y, mul0, o0, mul1, o1 - ); - } - }); + } + + #[test] + fn overflowing_mul_u128() { + use compiler_builtins::int::mul::{__rust_i128_mulo, __rust_u128_mulo}; + + fuzz_2(N, |x: u128, y: u128| { + let (mul0, o0) = x.overflowing_mul(y); + let (mul1, o1) = __rust_u128_mulo(x, y); + if mul0 != mul1 || o0 != o1 { + panic!( + "__rust_u128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", + x, y, mul0, o0, mul1, o1 + ); + } + let x = x as i128; + let y = y as i128; + let (mul0, o0) = x.overflowing_mul(y); + let (mul1, o1) = __rust_i128_mulo(x, y); + if mul0 != mul1 || o0 != o1 { + panic!( + "__rust_i128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", + x, y, mul0, o0, mul1, o1 + ); + } + }); + } } macro_rules! float_mul { ($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { $( - fuzz_float_2(N, |x: $f, y: $f| { - let mul0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Mul::mul, x, y); - let mul1: $f = $fn(x, y); - // multiplication of subnormals is not currently handled - if !(Float::is_subnormal(mul0) || Float::is_subnormal(mul1)) { - if !Float::eq_repr(mul0, mul1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), x, y, mul0, mul1 - ); + #[test] + fn $fn() { + use compiler_builtins::float::{mul::$fn, Float}; + use core::ops::Mul; + + fuzz_float_2(N, |x: $f, y: $f| { + let mul0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Mul::mul, x, y); + let mul1: $f = $fn(x, y); + // multiplication of subnormals is not currently handled + if !(Float::is_subnormal(mul0) || Float::is_subnormal(mul1)) { + if !Float::eq_repr(mul0, mul1) { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), x, y, mul0, mul1 + ); + } } - } - }); + }); + } )* }; } #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -#[test] -fn float_mul() { - use compiler_builtins::float::{ - mul::{__muldf3, __mulsf3}, - Float, - }; - use core::ops::Mul; +mod float_mul { + use super::*; - float_mul!( + float_mul! { f32, __mulsf3, Single, all(); f64, __muldf3, Double, all(); - ); - - #[cfg(not(feature = "no-f16-f128"))] - { - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - use compiler_builtins::float::mul::__mulkf3 as __multf3; - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - use compiler_builtins::float::mul::__multf3; - - float_mul!( - f128, __multf3, Quad, - // FIXME(llvm): there is a bug in LLVM rt. - // See . - not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux"))); - ); + } +} + +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] +mod float_mul_f128 { + use super::*; + + float_mul! { + f128, __multf3, Quad, + // FIXME(llvm): there is a bug in LLVM rt. + // See . + not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux"))); + } +} + +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +mod float_mul_f128_ppc { + use super::*; + + float_mul! { + f128, __mulkf3, Quad, not(feature = "no-sys-f128"); } } #[cfg(target_arch = "arm")] -#[test] -fn float_mul_arm() { - use compiler_builtins::float::{ - mul::{__muldf3vfp, __mulsf3vfp}, - Float, - }; - use core::ops::Mul; +mod float_mul_arm { + use super::*; - float_mul!( + float_mul! { f32, __mulsf3vfp, Single, all(); f64, __muldf3vfp, Double, all(); - ); + } } diff --git a/library/compiler-builtins/testcrate/tests/shift.rs b/library/compiler-builtins/testcrate/tests/shift.rs index 7a76b164685..23e3395edc6 100644 --- a/library/compiler-builtins/testcrate/tests/shift.rs +++ b/library/compiler-builtins/testcrate/tests/shift.rs @@ -3,35 +3,33 @@ use testcrate::*; macro_rules! shift { ($($i:ty, $fn_std:ident, $fn_builtins:ident);*;) => { $( - fuzz_shift(|x: $i, s: u32| { - let tmp0: $i = x.$fn_std(s); - let tmp1: $i = $fn_builtins(x, s); - if tmp0 != tmp1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn_builtins), x, s, tmp0, tmp1 - ); - } - }); + #[test] + fn $fn_builtins() { + use compiler_builtins::int::shift::$fn_builtins; + + fuzz_shift(|x: $i, s: u32| { + let tmp0: $i = x.$fn_std(s); + let tmp1: $i = $fn_builtins(x, s); + if tmp0 != tmp1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_builtins), x, s, tmp0, tmp1 + ); + } + }); + } )* }; } -#[test] -fn shift() { - use compiler_builtins::int::shift::{ - __ashldi3, __ashlsi3, __ashlti3, __ashrdi3, __ashrsi3, __ashrti3, __lshrdi3, __lshrsi3, - __lshrti3, - }; - shift!( - u32, wrapping_shl, __ashlsi3; - u64, wrapping_shl, __ashldi3; - u128, wrapping_shl, __ashlti3; - i32, wrapping_shr, __ashrsi3; - i64, wrapping_shr, __ashrdi3; - i128, wrapping_shr, __ashrti3; - u32, wrapping_shr, __lshrsi3; - u64, wrapping_shr, __lshrdi3; - u128, wrapping_shr, __lshrti3; - ); +shift! { + u32, wrapping_shl, __ashlsi3; + u64, wrapping_shl, __ashldi3; + u128, wrapping_shl, __ashlti3; + i32, wrapping_shr, __ashrsi3; + i64, wrapping_shr, __ashrdi3; + i128, wrapping_shr, __ashrti3; + u32, wrapping_shr, __lshrsi3; + u64, wrapping_shr, __lshrdi3; + u128, wrapping_shr, __lshrti3; } -- cgit 1.4.1-3-g733a5 From 3fdef93258ab56f7cd0a6912dd271566b1ab87a1 Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Wed, 15 May 2024 10:32:06 -0700 Subject: Add tests for UNC paths on windows builds --- library/compiler-builtins/.github/workflows/main.yml | 9 +++++++++ library/compiler-builtins/ci/run.sh | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 970a32ae518..01188636621 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -19,6 +19,11 @@ jobs: - target: aarch64-unknown-linux-gnu os: ubuntu-latest rust: nightly + - target: aarch64-pc-windows-msvc + os: windows-latest + rust: nightly + test_unc: 1 + no_std: 1 - target: arm-unknown-linux-gnueabi os: ubuntu-latest rust: nightly @@ -78,6 +83,7 @@ jobs: - target: i686-pc-windows-msvc os: windows-latest rust: nightly + test_unc: 1 - target: x86_64-pc-windows-msvc os: windows-latest rust: nightly @@ -109,6 +115,9 @@ jobs: - run: ./ci/run.sh ${{ matrix.target }} if: matrix.os != 'ubuntu-latest' shell: bash + env: + NO_STD: ${{ matrix.no_std }} + TEST_UNC: ${{ matrix.test_unc }} # Otherwise we use our docker containers to run builds - run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 847b52435a1..f05744e8720 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -32,6 +32,18 @@ else $run --features no-f16-f128 --release fi +if [ "${TEST_UNC:-}" = "1" ]; then + run="cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir \"\\\\?\\$(pwd)\"" + $run + $run --release + $run --features c + $run --features c --release + $run --features no-asm + $run --features no-asm --release + $run --features no-f16-f128 + $run --features no-f16-f128 --release +fi + if [ -d /builtins-target ]; then rlib_paths=/builtins-target/"${target}"/debug/deps/libcompiler_builtins-*.rlib else -- cgit 1.4.1-3-g733a5 From 24cb0c2bcc044d5d60830334e18eb403c4d9ac2d Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Wed, 15 May 2024 10:40:48 -0700 Subject: Fix CI --- library/compiler-builtins/.github/workflows/main.yml | 1 + library/compiler-builtins/ci/run.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 01188636621..6518a4dd688 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -87,6 +87,7 @@ jobs: - target: x86_64-pc-windows-msvc os: windows-latest rust: nightly + test_unc: 1 - target: i686-pc-windows-gnu os: windows-latest rust: nightly-i686-gnu diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index f05744e8720..b2728eacf35 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -33,7 +33,7 @@ else fi if [ "${TEST_UNC:-}" = "1" ]; then - run="cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir \"\\\\?\\$(pwd)\"" + run="cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir \\\\?\\$TEMP\\test_unc" $run $run --release $run --features c -- cgit 1.4.1-3-g733a5 From e246ba5a460e45aaf24aaa5a8d2ccbc04227544c Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Wed, 15 May 2024 10:44:58 -0700 Subject: Use cmd.exe --- library/compiler-builtins/.github/workflows/main.yml | 2 ++ library/compiler-builtins/ci/run.sh | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 6518a4dd688..531a4c308a4 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -91,9 +91,11 @@ jobs: - target: i686-pc-windows-gnu os: windows-latest rust: nightly-i686-gnu + test_unc: 1 - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu + test_unc: 1 steps: - name: Print runner information run: uname -a diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index b2728eacf35..2620dfff8e6 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -33,15 +33,17 @@ else fi if [ "${TEST_UNC:-}" = "1" ]; then - run="cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir \\\\?\\$TEMP\\test_unc" - $run - $run --release - $run --features c - $run --features c --release - $run --features no-asm - $run --features no-asm --release - $run --features no-f16-f128 - $run --features no-f16-f128 --release + function run() { + cmd.exe /c cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir "\\\\?\\%TEMP%\\test_unc" "$@" + } + run + run --release + run --features c + run --features c --release + run --features no-asm + run --features no-asm --release + run --features no-f16-f128 + run --features no-f16-f128 --release fi if [ -d /builtins-target ]; then -- cgit 1.4.1-3-g733a5 From 0000f98d7307ebc2ab0e81914b5a3e0fa60f4a3b Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Wed, 15 May 2024 10:47:07 -0700 Subject: Fix backslash --- library/compiler-builtins/ci/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 2620dfff8e6..d4f0b80fbf7 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -34,7 +34,7 @@ fi if [ "${TEST_UNC:-}" = "1" ]; then function run() { - cmd.exe /c cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir "\\\\?\\%TEMP%\\test_unc" "$@" + cmd.exe /c cargo build --manifest-path "testcrate\\Cargo.toml" --target $target --target-dir "\\\\?\\%TEMP%\\test_unc" "$@" } run run --release -- cgit 1.4.1-3-g733a5 From e3d86a8350a7ced205f9129995a96e34cd5043b4 Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Wed, 15 May 2024 10:54:40 -0700 Subject: Instead have cmd.exe dump out path --- library/compiler-builtins/ci/run.sh | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index d4f0b80fbf7..b4bf18b1014 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -33,17 +33,16 @@ else fi if [ "${TEST_UNC:-}" = "1" ]; then - function run() { - cmd.exe /c cargo build --manifest-path "testcrate\\Cargo.toml" --target $target --target-dir "\\\\?\\%TEMP%\\test_unc" "$@" - } - run - run --release - run --features c - run --features c --release - run --features no-asm - run --features no-asm --release - run --features no-f16-f128 - run --features no-f16-f128 --release + path=$(cmd.exe "/C echo \\\\?\\%cd%\\testcrate\\target_unc") + run="cargo test --manifest-path testcrate/Cargo.toml --target $target --target-dir $path" + $run + $run --release + $run --features c + $run --features c --release + $run --features no-asm + $run --features no-asm --release + $run --features no-f16-f128 + $run --features no-f16-f128 --release fi if [ -d /builtins-target ]; then -- cgit 1.4.1-3-g733a5 From fd290b133955f59e8b73dfe4e3891d2c0dc12d8f Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Wed, 15 May 2024 11:05:20 -0700 Subject: Properly escape /C and fix naming --- library/compiler-builtins/.github/workflows/main.yml | 12 ++++++------ library/compiler-builtins/ci/run.sh | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 531a4c308a4..b27267ba66c 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -22,7 +22,7 @@ jobs: - target: aarch64-pc-windows-msvc os: windows-latest rust: nightly - test_unc: 1 + test_verbatim: 1 no_std: 1 - target: arm-unknown-linux-gnueabi os: ubuntu-latest @@ -83,19 +83,19 @@ jobs: - target: i686-pc-windows-msvc os: windows-latest rust: nightly - test_unc: 1 + test_verbatim: 1 - target: x86_64-pc-windows-msvc os: windows-latest rust: nightly - test_unc: 1 + test_verbatim: 1 - target: i686-pc-windows-gnu os: windows-latest rust: nightly-i686-gnu - test_unc: 1 + test_verbatim: 1 - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu - test_unc: 1 + test_verbatim: 1 steps: - name: Print runner information run: uname -a @@ -120,7 +120,7 @@ jobs: shell: bash env: NO_STD: ${{ matrix.no_std }} - TEST_UNC: ${{ matrix.test_unc }} + TEST_VERBATIM: ${{ matrix.test_verbatim }} # Otherwise we use our docker containers to run builds - run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index b4bf18b1014..cc07090d4d1 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -32,9 +32,9 @@ else $run --features no-f16-f128 --release fi -if [ "${TEST_UNC:-}" = "1" ]; then - path=$(cmd.exe "/C echo \\\\?\\%cd%\\testcrate\\target_unc") - run="cargo test --manifest-path testcrate/Cargo.toml --target $target --target-dir $path" +if [ "${TEST_VERBATIM:-}" = "1" ]; then + verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\testcrate\\target2) + run="cargo test --manifest-path testcrate/Cargo.toml --target $target --target-dir $verb_path" $run $run --release $run --features c -- cgit 1.4.1-3-g733a5 From 416be726df79f30cd6ebba972bd689fbd09b7821 Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Wed, 15 May 2024 11:07:06 -0700 Subject: verbatim tests only need to build --- library/compiler-builtins/ci/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index cc07090d4d1..3c33bbf835f 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -34,7 +34,7 @@ fi if [ "${TEST_VERBATIM:-}" = "1" ]; then verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\testcrate\\target2) - run="cargo test --manifest-path testcrate/Cargo.toml --target $target --target-dir $verb_path" + run="cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir $verb_path" $run $run --release $run --features c -- cgit 1.4.1-3-g733a5 From 7d60c93165e80cefb4ab6fc8ada0405593c1fe58 Mon Sep 17 00:00:00 2001 From: Henry Wang Date: Fri, 17 May 2024 08:40:39 -0700 Subject: Only run `--features c` for verbatim test --- library/compiler-builtins/ci/run.sh | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 3c33bbf835f..2512dc633e5 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -34,15 +34,7 @@ fi if [ "${TEST_VERBATIM:-}" = "1" ]; then verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\testcrate\\target2) - run="cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir $verb_path" - $run - $run --release - $run --features c - $run --features c --release - $run --features no-asm - $run --features no-asm --release - $run --features no-f16-f128 - $run --features no-f16-f128 --release + cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir $verb_path --features c fi if [ -d /builtins-target ]; then -- cgit 1.4.1-3-g733a5 From 0722bc4275c2e6e0f5d6b8e1b3813b61cd6efff1 Mon Sep 17 00:00:00 2001 From: Henry Wang Date: Fri, 17 May 2024 08:41:59 -0700 Subject: Don't run verbatim test on windows-gnu --- library/compiler-builtins/.github/workflows/main.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index b27267ba66c..72d441c4e7d 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -91,11 +91,9 @@ jobs: - target: i686-pc-windows-gnu os: windows-latest rust: nightly-i686-gnu - test_verbatim: 1 - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu - test_verbatim: 1 steps: - name: Print runner information run: uname -a -- cgit 1.4.1-3-g733a5 From bac7b1e77718fea6649ce3f88dc1fd7e628508e9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 17 May 2024 22:02:37 -0500 Subject: Add `CastFrom` as a convenience form of `CastInto` --- library/compiler-builtins/src/int/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 2b6d4b812ee..0c67a4c1656 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -380,6 +380,16 @@ public_test_dep! { pub(crate) trait CastInto: Copy { fn cast(self) -> T; } + +pub(crate) trait CastFrom:Copy { + fn cast_from(value: T) -> Self; +} +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } } macro_rules! cast_into { -- cgit 1.4.1-3-g733a5 From fc53fb64fc06642417c35e9d544bf4b0b40beba9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 17 May 2024 22:04:03 -0500 Subject: Make float to integer conversions generic Deduplicate code used for float to integer conversions in order to make adding `f128` conversion functions easier. --- library/compiler-builtins/src/float/conv.rs | 250 +++++++++++----------------- library/compiler-builtins/src/float/mod.rs | 8 +- library/compiler-builtins/src/int/mod.rs | 5 + 3 files changed, 109 insertions(+), 154 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 790c0ab9f35..931840f1596 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,3 +1,9 @@ +use core::ops::Neg; + +use crate::int::{CastFrom, CastInto, Int, MinInt}; + +use super::Float; + /// Conversions from integers to floats. /// /// These are hand-optimized bit twiddling code, @@ -142,102 +148,118 @@ intrinsics! { } } +/// Generic float to unsigned int conversions. +fn float_to_unsigned_int(f: F) -> U +where + F: Float, + U: Int, + F::Int: CastInto, + F::Int: CastFrom, + F::Int: CastInto, + u32: CastFrom, +{ + float_to_int_inner::(f.repr(), |i: U| i, || U::MAX) +} + +/// Generic float to signed int conversions. +fn float_to_signed_int(f: F) -> I +where + F: Float, + I: Int + Neg, + I::UnsignedInt: Int, + F::Int: CastInto, + F::Int: CastFrom, + u32: CastFrom, +{ + float_to_int_inner::( + f.repr() & !F::SIGN_MASK, + |i: I| if f.is_sign_negative() { -i } else { i }, + || if f.is_sign_negative() { I::MIN } else { I::MAX }, + ) +} + +/// Float to int conversions, generic for both signed and unsigned. +/// +/// Parameters: +/// - `fbits`: `abg(f)` bitcasted to an integer. +/// - `map_inbounds`: apply this transformation to integers that are within range (add the sign +/// back). +/// - `out_of_bounds`: return value when out of range for `I`. +fn float_to_int_inner( + fbits: F::Int, + map_inbounds: FnFoo, + out_of_bounds: FnOob, +) -> I +where + F: Float, + I: Int, + FnFoo: FnOnce(I) -> I, + FnOob: FnOnce() -> I, + I::UnsignedInt: Int, + F::Int: CastInto, + F::Int: CastFrom, + u32: CastFrom, +{ + let int_max_exp = F::EXPONENT_BIAS + I::MAX.ilog2() + 1; + let foobar = F::EXPONENT_BIAS + I::UnsignedInt::BITS - 1; + + if fbits < F::ONE.repr() { + // < 0 gets rounded to 0 + I::ZERO + } else if fbits < F::Int::cast_from(int_max_exp) << F::SIGNIFICAND_BITS { + // >= 1, < integer max + let m_base = if I::UnsignedInt::BITS >= F::Int::BITS { + I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIGNIFICAND_BITS - 1) + } else { + I::UnsignedInt::cast_from(fbits >> (F::SIGNIFICAND_BITS - I::BITS + 1)) + }; + + // Set the implicit 1-bit. + let m: I::UnsignedInt = I::UnsignedInt::ONE << (I::BITS - 1) | m_base; + + // Shift based on the exponent and bias. + let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIGNIFICAND_BITS); + + let unsigned = m >> s; + map_inbounds(I::from_unsigned(unsigned)) + } else if fbits <= F::EXPONENT_MASK { + // >= max (incl. inf) + out_of_bounds() + } else { + I::ZERO + } +} + // Conversions from floats to unsigned integers. intrinsics! { #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { - let fbits = f.to_bits(); - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 159 << 23 { // >= 1, < max - let m = 1 << 31 | fbits << 8; // Mantissa and the implicit 1-bit. - let s = 158 - (fbits >> 23); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 255 << 23 { // >= max (incl. inf) - u32::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[arm_aeabi_alias = __aeabi_f2ulz] pub extern "C" fn __fixunssfdi(f: f32) -> u64 { - let fbits = f.to_bits(); - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 191 << 23 { // >= 1, < max - let m = 1 << 63 | (fbits as u64) << 40; // Mantissa and the implicit 1-bit. - let s = 190 - (fbits >> 23); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 255 << 23 { // >= max (incl. inf) - u64::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[win64_128bit_abi_hack] pub extern "C" fn __fixunssfti(f: f32) -> u128 { - let fbits = f.to_bits(); - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 255 << 23 { // >= 1, < inf - let m = 1 << 127 | (fbits as u128) << 104; // Mantissa and the implicit 1-bit. - let s = 254 - (fbits >> 23); // Shift based on the exponent and bias. - m >> s - } else if fbits == 255 << 23 { // == inf - u128::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { - let fbits = f.to_bits(); - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1055 << 52 { // >= 1, < max - let m = 1 << 31 | (fbits >> 21) as u32; // Mantissa and the implicit 1-bit. - let s = 1054 - (fbits >> 52); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - u32::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[arm_aeabi_alias = __aeabi_d2ulz] pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { - let fbits = f.to_bits(); - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1087 << 52 { // >= 1, < max - let m = 1 << 63 | fbits << 11; // Mantissa and the implicit 1-bit. - let s = 1086 - (fbits >> 52); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - u64::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[win64_128bit_abi_hack] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { - let fbits = f.to_bits(); - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1151 << 52 { // >= 1, < max - let m = 1 << 127 | (fbits as u128) << 75; // Mantissa and the implicit 1-bit. - let s = 1150 - (fbits >> 52); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - u128::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } } @@ -245,103 +267,31 @@ intrinsics! { intrinsics! { #[arm_aeabi_alias = __aeabi_f2iz] pub extern "C" fn __fixsfsi(f: f32) -> i32 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 158 << 23 { // >= 1, < max - let m = 1 << 31 | fbits << 8; // Mantissa and the implicit 1-bit. - let s = 158 - (fbits >> 23); // Shift based on the exponent and bias. - let u = (m >> s) as i32; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 255 << 23 { // >= max (incl. inf) - if f.is_sign_negative() { i32::MIN } else { i32::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[arm_aeabi_alias = __aeabi_f2lz] pub extern "C" fn __fixsfdi(f: f32) -> i64 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 190 << 23 { // >= 1, < max - let m = 1 << 63 | (fbits as u64) << 40; // Mantissa and the implicit 1-bit. - let s = 190 - (fbits >> 23); // Shift based on the exponent and bias. - let u = (m >> s) as i64; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 255 << 23 { // >= max (incl. inf) - if f.is_sign_negative() { i64::MIN } else { i64::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[win64_128bit_abi_hack] pub extern "C" fn __fixsfti(f: f32) -> i128 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 254 << 23 { // >= 1, < max - let m = 1 << 127 | (fbits as u128) << 104; // Mantissa and the implicit 1-bit. - let s = 254 - (fbits >> 23); // Shift based on the exponent and bias. - let u = (m >> s) as i128; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 255 << 23 { // >= max (incl. inf) - if f.is_sign_negative() { i128::MIN } else { i128::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[arm_aeabi_alias = __aeabi_d2iz] pub extern "C" fn __fixdfsi(f: f64) -> i32 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1054 << 52 { // >= 1, < max - let m = 1 << 31 | (fbits >> 21) as u32; // Mantissa and the implicit 1-bit. - let s = 1054 - (fbits >> 52); // Shift based on the exponent and bias. - let u = (m >> s) as i32; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - if f.is_sign_negative() { i32::MIN } else { i32::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[arm_aeabi_alias = __aeabi_d2lz] pub extern "C" fn __fixdfdi(f: f64) -> i64 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1086 << 52 { // >= 1, < max - let m = 1 << 63 | fbits << 11; // Mantissa and the implicit 1-bit. - let s = 1086 - (fbits >> 52); // Shift based on the exponent and bias. - let u = (m >> s) as i64; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - if f.is_sign_negative() { i64::MIN } else { i64::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[win64_128bit_abi_hack] pub extern "C" fn __fixdfti(f: f64) -> i128 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1150 << 52 { // >= 1, < max - let m = 1 << 127 | (fbits as u128) << 75; // Mantissa and the implicit 1-bit. - let s = 1150 - (fbits >> 52); // Shift based on the exponent and bias. - let u = (m >> s) as i128; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - if f.is_sign_negative() { i128::MIN } else { i128::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index e62a3fe0fd5..5fef1df32a5 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -80,8 +80,8 @@ pub(crate) trait Float: /// compared. fn eq_repr(self, rhs: Self) -> bool; - /// Returns the sign bit - fn sign(self) -> bool; + /// Returns true if the sign is negative + fn is_sign_negative(self) -> bool; /// Returns the exponent with bias fn exp(self) -> Self::ExpInt; @@ -150,8 +150,8 @@ macro_rules! float_impl { self.repr() == rhs.repr() } } - fn sign(self) -> bool { - self.signed_repr() < Self::SignedInt::ZERO + fn is_sign_negative(self) -> bool { + self.is_sign_negative() } fn exp(self) -> Self::ExpInt { ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 0c67a4c1656..45d38388031 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -102,6 +102,7 @@ pub(crate) trait Int: MinInt fn rotate_left(self, other: u32) -> Self; fn overflowing_add(self, other: Self) -> (Self, bool); fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; } } @@ -200,6 +201,10 @@ macro_rules! int_impl_common { fn leading_zeros(self) -> u32 { ::leading_zeros(self) } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } }; } -- cgit 1.4.1-3-g733a5 From a3b1dfb8d51d8032ba8e4f7769863dc85b4142a2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 17 May 2024 22:04:49 -0500 Subject: Allow a specific fallback function in `apfloat_fallback` `as` casts are only allowed for primitives, doing the same operations with `rustc_apfloat` requires using functions. Add a way to specify these separately. --- library/compiler-builtins/testcrate/src/lib.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 1f3a4b82621..5ee96ad2751 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -276,7 +276,7 @@ macro_rules! apfloat_fallback { // The expression to run. This expression may use `FloatTy` for its signature. // Optionally, the final conversion back to a float can be suppressed using // `=> no_convert` (for e.g. operations that return a bool). - $op:expr $(=> $convert:ident)?, + $op:expr $(=> $convert:ident)? $(; $apfloat_op:expr)?, // Arguments that get passed to `$op` after converting to a float $($arg:expr),+ $(,)? @@ -292,26 +292,40 @@ macro_rules! apfloat_fallback { use rustc_apfloat::Float; type FloatTy = rustc_apfloat::ieee::$apfloat_ty; - let op_res = $op( $(FloatTy::from_bits($arg.to_bits().into())),+ ); - - apfloat_fallback!(@convert $float_ty, op_res $(,$convert)?) + apfloat_fallback!(@inner + fty: $float_ty, + // Apply a conversion to `FloatTy` to each arg, then pass all args to `$op` + op_res: $op( $(FloatTy::from_bits($arg.to_bits().into())),+ ), + $(apfloat_op: $apfloat_op, )? + $(conv_opts: $convert,)? + args: $($arg),+ + ) }; ret }}; // Operations that do not need converting back to a float - (@convert $float_ty:ty, $val:expr, no_convert) => { + (@inner fty: $float_ty:ty, op_res: $val:expr, conv_opts: no_convert, args: $($_arg:expr),+) => { $val }; // Some apfloat operations return a `StatusAnd` that we need to extract the value from. This // is the default. - (@convert $float_ty:ty, $val:expr) => {{ + (@inner fty: $float_ty:ty, op_res: $val:expr, args: $($_arg:expr),+) => {{ // ignore the status, just get the value let unwrapped = $val.value; <$float_ty>::from_bits(FloatTy::to_bits(unwrapped).try_into().unwrap()) }}; + // This is the case where we can't use the same expression for the default builtin and + // nonstandard apfloat fallbac (e.g. `as` casts in std are normal functions in apfloat, so + // two separate expressions must be specified. + (@inner + fty: $float_ty:ty, op_res: $_val:expr, + apfloat_op: $apfloat_op:expr, args: $($arg:expr),+ + ) => {{ + $apfloat_op($($arg),+) + }}; } -- cgit 1.4.1-3-g733a5 From aaaf62bd6b1b18f8f2b333785aaaedcc49caf2de Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 20 May 2024 20:00:02 -0400 Subject: Add an apfloat fallback for float to integer tests --- library/compiler-builtins/testcrate/tests/conv.rs | 35 +++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 7b672ac251e..1e26950fe35 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -100,14 +100,39 @@ mod f_to_i { use super::*; macro_rules! f_to_i { - ($x:ident, $($f:ty, $fn:ident);*;) => { + ($x:ident, $f_ty:ty, $apfloat_ty:ident, $sys_available:meta, $($i_ty:ty, $fn:ident);*;) => { $( // it is undefined behavior in the first place to do conversions with NaNs - if !$x.is_nan() { - let conv0 = $x as $f; - let conv1: $f = $fn($x); + if !apfloat_fallback!( + $f_ty, $apfloat_ty, $sys_available, |x: FloatTy| x.is_nan() => no_convert, $x + ) { + let conv0 = apfloat_fallback!( + $f_ty, $apfloat_ty, $sys_available, + // Use an `as` cast when the builtin is available on the system. + |x| x as $i_ty; + // When the builtin is not available, we need to use a different conversion + // method (since apfloat doesn't support `as` casting). + |x: $f_ty| { + use compiler_builtins::int::MinInt; + + let apf = FloatTy::from_bits(x.to_bits().into()); + let bits: usize = <$i_ty>::BITS.try_into().unwrap(); + + let err_fn = || panic!( + "Unable to convert value {x:?} to type {}:", stringify!($i_ty) + ); + + if <$i_ty>::SIGNED { + <$i_ty>::try_from(apf.to_i128(bits).value).ok().unwrap_or_else(err_fn) + } else { + <$i_ty>::try_from(apf.to_u128(bits).value).ok().unwrap_or_else(err_fn) + } + }, + $x + ); + let conv1: $i_ty = $fn($x); if conv0 != conv1 { - panic!("{}({}): std: {}, builtins: {}", stringify!($fn), $x, conv0, conv1); + panic!("{}({:?}): std: {:?}, builtins: {:?}", stringify!($fn), $x, conv0, conv1); } } )* -- cgit 1.4.1-3-g733a5 From ccd179b23144c703701cdc848935342c4325e1a7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 20 May 2024 20:00:11 -0400 Subject: Add `f128` float to integer conversion functions Add the following: - `__fixtfsi` - `__fixtfdi` - `__fixtfti` - `__fixunstfsi` - `__fixunstfdi` - `__fixunstfti` --- library/compiler-builtins/README.md | 12 ++++----- library/compiler-builtins/build.rs | 10 -------- library/compiler-builtins/src/float/conv.rs | 30 ++++++++++++++++++++++ library/compiler-builtins/testcrate/Cargo.toml | 4 ++- library/compiler-builtins/testcrate/build.rs | 31 ++++++++++++++++++++--- library/compiler-builtins/testcrate/tests/conv.rs | 27 ++++++++++++++++++-- 6 files changed, 92 insertions(+), 22 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 37d7ab2e671..8233c669c6d 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -239,12 +239,12 @@ These builtins are needed to support `f16` and `f128`, which are in the process - [x] extendhfsf2.c - [x] extendhftf2.c - [x] extendsftf2.c -- [ ] fixtfdi.c -- [ ] fixtfsi.c -- [ ] fixtfti.c -- [ ] fixunstfdi.c -- [ ] fixunstfsi.c -- [ ] fixunstfti.c +- [x] fixtfdi.c +- [x] fixtfsi.c +- [x] fixtfti.c +- [x] fixunstfdi.c +- [x] fixunstfsi.c +- [x] fixunstfti.c - [ ] floatditf.c - [ ] floatsitf.c - [ ] floatunditf.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index ec830ecb34b..50415910d29 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -533,12 +533,6 @@ mod c { if (target_arch == "aarch64" || target_arch == "arm64ec") && consider_float_intrinsics { sources.extend(&[ ("__comparetf2", "comparetf2.c"), - ("__fixtfdi", "fixtfdi.c"), - ("__fixtfsi", "fixtfsi.c"), - ("__fixtfti", "fixtfti.c"), - ("__fixunstfdi", "fixunstfdi.c"), - ("__fixunstfsi", "fixunstfsi.c"), - ("__fixunstfti", "fixunstfti.c"), ("__floatditf", "floatditf.c"), ("__floatsitf", "floatsitf.c"), ("__floatunditf", "floatunditf.c"), @@ -561,9 +555,7 @@ mod c { if target_arch == "mips64" { sources.extend(&[ ("__netf2", "comparetf2.c"), - ("__fixtfsi", "fixtfsi.c"), ("__floatsitf", "floatsitf.c"), - ("__fixunstfsi", "fixunstfsi.c"), ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), ]); @@ -572,9 +564,7 @@ mod c { if target_arch == "loongarch64" { sources.extend(&[ ("__netf2", "comparetf2.c"), - ("__fixtfsi", "fixtfsi.c"), ("__floatsitf", "floatsitf.c"), - ("__fixunstfsi", "fixunstfsi.c"), ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), ]); diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 931840f1596..a37206cdce6 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -261,6 +261,21 @@ intrinsics! { pub extern "C" fn __fixunsdfti(f: f64) -> u128 { float_to_unsigned_int(f) } + + #[cfg(not(feature = "no-f16-f128"))] + pub extern "C" fn __fixunstfsi(f: f128) -> u32 { + float_to_unsigned_int(f) + } + + #[cfg(not(feature = "no-f16-f128"))] + pub extern "C" fn __fixunstfdi(f: f128) -> u64 { + float_to_unsigned_int(f) + } + + #[cfg(not(feature = "no-f16-f128"))] + pub extern "C" fn __fixunstfti(f: f128) -> u128 { + float_to_unsigned_int(f) + } } // Conversions from floats to signed integers. @@ -294,4 +309,19 @@ intrinsics! { pub extern "C" fn __fixdfti(f: f64) -> i128 { float_to_signed_int(f) } + + #[cfg(not(feature = "no-f16-f128"))] + pub extern "C" fn __fixtfsi(f: f128) -> i32 { + float_to_signed_int(f) + } + + #[cfg(not(feature = "no-f16-f128"))] + pub extern "C" fn __fixtfdi(f: f128) -> i64 { + float_to_signed_int(f) + } + + #[cfg(not(feature = "no-f16-f128"))] + pub extern "C" fn __fixtfti(f: f128) -> i128 { + float_to_signed_int(f) + } } diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 6f771181a05..1de0c39761e 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -34,4 +34,6 @@ no-f16-f128 = ["compiler_builtins/no-f16-f128"] mem = ["compiler_builtins/mem"] mangled-names = ["compiler_builtins/mangled-names"] # Skip tests that rely on f128 symbols being available on the system -no-sys-f128 = [] +no-sys-f128 = ["no-sys-f128-int-convert"] +# Some platforms have some f128 functions but everything except integer conversions +no-sys-f128-int-convert = [] diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index f24dae3c664..1dad6c5e649 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -1,7 +1,15 @@ -use std::env; +use std::{collections::HashSet, env}; + +/// Features to enable +#[derive(Debug, PartialEq, Eq, Hash)] +enum Feature { + NoSysF128, + NoSysF128IntConvert, +} fn main() { let target = env::var("TARGET").unwrap(); + let mut features = HashSet::new(); // These platforms do not have f128 symbols available in their system libraries, so // skip related tests. @@ -21,7 +29,24 @@ fn main() { // . || target.starts_with("powerpc64-") { - println!("cargo:warning=using apfloat fallback for f128"); - println!("cargo:rustc-cfg=feature=\"no-sys-f128\""); + features.insert(Feature::NoSysF128); + features.insert(Feature::NoSysF128IntConvert); + } + + if target.starts_with("i586") || target.starts_with("i686") { + // 32-bit x86 seems to not have `__fixunstfti`, but does have everything else + features.insert(Feature::NoSysF128IntConvert); + } + + for feature in features { + let (name, warning) = match feature { + Feature::NoSysF128 => ("no-sys-f128", "using apfloat fallback for f128"), + Feature::NoSysF128IntConvert => ( + "no-sys-f128-int-convert", + "using apfloat fallback for f128 to int conversions", + ), + }; + println!("cargo:warning={warning}"); + println!("cargo:rustc-cfg=feature=\"{name}\""); } } diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 1e26950fe35..f73b809d04f 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -146,7 +146,7 @@ mod f_to_i { }; fuzz_float(N, |x: f32| { - f_to_i!(x, + f_to_i!(x, f32, Single, all(), u32, __fixunssfsi; u64, __fixunssfdi; u128, __fixunssfti; @@ -164,7 +164,7 @@ mod f_to_i { }; fuzz_float(N, |x: f64| { - f_to_i!(x, + f_to_i!(x, f64, Double, all(), u32, __fixunsdfsi; u64, __fixunsdfdi; u128, __fixunsdfti; @@ -174,6 +174,29 @@ mod f_to_i { ); }); } + + #[test] + #[cfg(not(feature = "no-f16-f128"))] + fn f128_to_int() { + use compiler_builtins::float::conv::{ + __fixtfdi, __fixtfsi, __fixtfti, __fixunstfdi, __fixunstfsi, __fixunstfti, + }; + + fuzz_float(N, |x: f128| { + f_to_i!( + x, + f128, + Quad, + not(feature = "no-sys-f128-int-convert"), + u32, __fixunstfsi; + u64, __fixunstfdi; + u128, __fixunstfti; + i32, __fixtfsi; + i64, __fixtfdi; + i128, __fixtfti; + ); + }); + } } macro_rules! conv { -- cgit 1.4.1-3-g733a5 From c7bd2a565517664e1e7b67d2655e0381bc5d0f2b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 May 2024 03:41:06 -0400 Subject: Add `ppc_alias` to the `intrinsics!` macro PowerPC platforms use `kf` rather than `tf` for `f128`. Add a way to alias this in the macro to make the code cleaner. This also fixes the names of `fixunstf*` and `fixtf*` on Power PC (`fixunskf*` and `fixkf*` are correct). --- library/compiler-builtins/src/float/add.rs | 8 +--- library/compiler-builtins/src/float/cmp.rs | 54 ++++------------------- library/compiler-builtins/src/float/conv.rs | 6 +++ library/compiler-builtins/src/float/extend.rs | 21 ++------- library/compiler-builtins/src/float/mul.rs | 9 +--- library/compiler-builtins/src/float/sub.rs | 13 +++--- library/compiler-builtins/src/float/trunc.rs | 21 ++------- library/compiler-builtins/src/macros.rs | 33 ++++++++++++++ library/compiler-builtins/testcrate/tests/conv.rs | 7 +++ 9 files changed, 70 insertions(+), 102 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index fd151f77d8a..7e8529f3e29 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -203,16 +203,12 @@ intrinsics! { add(a, b) } - #[cfg(not(any(feature = "no-f16-f128", target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __addkf3] + #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __addtf3(a: f128, b: f128) -> f128 { add(a, b) } - #[cfg(all(not(feature = "no-f16-f128"), any(target_arch = "powerpc", target_arch = "powerpc64")))] - pub extern "C" fn __addkf3(a: f128, b: f128) -> f128 { - add(a, b) - } - #[cfg(target_arch = "arm")] pub extern "C" fn __addsf3vfp(a: f32, b: f32) -> f32 { a + b diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 44ebf6262ea..5c431304c61 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -172,89 +172,51 @@ intrinsics! { } } -#[cfg(not(any( - feature = "no-f16-f128", - target_arch = "powerpc", - target_arch = "powerpc64" -)))] +#[cfg(not(feature = "no-f16-f128",))] intrinsics! { #[avr_skip] + #[ppc_alias = __lekf2] pub extern "C" fn __letf2(a: f128, b: f128) -> i32 { cmp(a, b).to_le_abi() } #[avr_skip] + #[ppc_alias = __gekf2] pub extern "C" fn __getf2(a: f128, b: f128) -> i32 { cmp(a, b).to_ge_abi() } #[avr_skip] + #[ppc_alias = __unordkf2] pub extern "C" fn __unordtf2(a: f128, b: f128) -> i32 { unord(a, b) as i32 } #[avr_skip] + #[ppc_alias = __eqkf2] pub extern "C" fn __eqtf2(a: f128, b: f128) -> i32 { cmp(a, b).to_le_abi() } #[avr_skip] + #[ppc_alias = __ltkf2] pub extern "C" fn __lttf2(a: f128, b: f128) -> i32 { cmp(a, b).to_le_abi() } #[avr_skip] + #[ppc_alias = __nekf2] pub extern "C" fn __netf2(a: f128, b: f128) -> i32 { cmp(a, b).to_le_abi() } #[avr_skip] + #[ppc_alias = __gtkf2] pub extern "C" fn __gttf2(a: f128, b: f128) -> i32 { cmp(a, b).to_ge_abi() } } -#[cfg(all( - not(feature = "no-f16-f128"), - any(target_arch = "powerpc", target_arch = "powerpc64") -))] -intrinsics! { - #[avr_skip] - pub extern "C" fn __lekf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __gekf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_ge_abi() - } - - #[avr_skip] - pub extern "C" fn __unordkf2(a: f128, b: f128) -> i32 { - unord(a, b) as i32 - } - - #[avr_skip] - pub extern "C" fn __eqkf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __ltkf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __nekf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __gtkf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_ge_abi() - } -} - #[cfg(target_arch = "arm")] intrinsics! { pub extern "aapcs" fn __aeabi_fcmple(a: f32, b: f32) -> i32 { diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index a37206cdce6..52119f3e800 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -262,16 +262,19 @@ intrinsics! { float_to_unsigned_int(f) } + #[ppc_alias = __fixunskfsi] #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __fixunstfsi(f: f128) -> u32 { float_to_unsigned_int(f) } + #[ppc_alias = __fixunskfdi] #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __fixunstfdi(f: f128) -> u64 { float_to_unsigned_int(f) } + #[ppc_alias = __fixunskfti] #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __fixunstfti(f: f128) -> u128 { float_to_unsigned_int(f) @@ -310,16 +313,19 @@ intrinsics! { float_to_signed_int(f) } + #[ppc_alias = __fixkfsi] #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __fixtfsi(f: f128) -> i32 { float_to_signed_int(f) } + #[ppc_alias = __fixkfdi] #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __fixtfdi(f: f128) -> i64 { float_to_signed_int(f) } + #[ppc_alias = __fixkfti] #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __fixtfti(f: f128) -> i128 { float_to_signed_int(f) diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 12e5fc9e10f..55604899133 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -100,37 +100,22 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __extendhfkf2] pub extern "C" fn __extendhftf2(a: f16) -> f128 { extend(a) } - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - pub extern "C" fn __extendhfkf2(a: f16) -> f128 { - extend(a) - } - #[avr_skip] #[aapcs_on_arm] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __extendsfkf2] pub extern "C" fn __extendsftf2(a: f32) -> f128 { extend(a) } - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - pub extern "C" fn __extendsfkf2(a: f32) -> f128 { - extend(a) - } - #[avr_skip] #[aapcs_on_arm] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __extenddfkf2] pub extern "C" fn __extenddftf2(a: f64) -> f128 { extend(a) } - - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - pub extern "C" fn __extenddfkf2(a: f64) -> f128 { - extend(a) - } } diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 9866b62804d..007cc09a498 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -199,17 +199,12 @@ intrinsics! { mul(a, b) } - #[cfg(not(any(feature = "no-f16-f128", target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __mulkf3] + #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __multf3(a: f128, b: f128) -> f128 { mul(a, b) } - - #[cfg(all(not(feature = "no-f16-f128"), any(target_arch = "powerpc", target_arch = "powerpc64")))] - pub extern "C" fn __mulkf3(a: f128, b: f128) -> f128 { - mul(a, b) - } - #[cfg(target_arch = "arm")] pub extern "C" fn __mulsf3vfp(a: f32, b: f32) -> f32 { a * b diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index de33259d640..1492679f623 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -15,16 +15,15 @@ intrinsics! { __adddf3(a, f64::from_repr(b.repr() ^ f64::SIGN_MASK)) } - #[cfg(not(any(feature = "no-f16-f128", target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __subkf3] + #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __subtf3(a: f128, b: f128) -> f128 { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + use crate::float::add::__addkf3 as __addtf3; + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] use crate::float::add::__addtf3; - __addtf3(a, f128::from_repr(b.repr() ^ f128::SIGN_MASK)) - } - #[cfg(all(not(feature = "no-f16-f128"), any(target_arch = "powerpc", target_arch = "powerpc64")))] - pub extern "C" fn __subkf3(a: f128, b: f128) -> f128 { - use crate::float::add::__addkf3; - __addkf3(a, f128::from_repr(b.repr() ^ f128::SIGN_MASK)) + __addtf3(a, f128::from_repr(b.repr() ^ f128::SIGN_MASK)) } #[cfg(target_arch = "arm")] diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 31351b5e969..9aea6f91ebc 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -155,37 +155,22 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __trunckfhf2] pub extern "C" fn __trunctfhf2(a: f128) -> f16 { trunc(a) } - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - pub extern "C" fn __trunckfhf2(a: f128) -> f16 { - trunc(a) - } - #[avr_skip] #[aapcs_on_arm] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __trunckfsf2] pub extern "C" fn __trunctfsf2(a: f128) -> f32 { trunc(a) } - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - pub extern "C" fn __trunckfsf2(a: f128) -> f32 { - trunc(a) - } - #[avr_skip] #[aapcs_on_arm] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __trunckfdf2] pub extern "C" fn __trunctfdf2(a: f128) -> f64 { trunc(a) } - - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - pub extern "C" fn __trunckfdf2(a: f128) -> f64 { - trunc(a) - } } diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index f762ef4da21..f537c1a968f 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -65,6 +65,9 @@ macro_rules! public_test_dep { /// it's a normal ABI elsewhere for returning a 128 bit integer. /// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM /// their otherwise typical names to other prefixed ones. +/// * `ppc_alias` - changes the name of the symbol on PowerPC platforms without +/// changing any other behavior. This is mostly for `f128`, which is `tf` on +/// most platforms but `kf` on PowerPC. macro_rules! intrinsics { () => (); @@ -320,6 +323,36 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // PowerPC usually uses `kf` rather than `tf` for `f128`. This is just an easy + // way to add an alias on those targets. + ( + #[ppc_alias = $alias:ident] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $alias( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + // C mem* functions are only generated when the "mem" feature is enabled. ( #[mem_builtin] diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index f73b809d04f..1425b49ce49 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -178,6 +178,13 @@ mod f_to_i { #[test] #[cfg(not(feature = "no-f16-f128"))] fn f128_to_int() { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + use compiler_builtins::float::conv::{ + __fixkfdi as __fixtfdi, __fixkfsi as __fixtfsi, __fixkfti as __fixtfti, + __fixunskfdi as __fixunstfdi, __fixunskfsi as __fixunstfsi, + __fixunskfti as __fixunstfti, + }; + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] use compiler_builtins::float::conv::{ __fixtfdi, __fixtfsi, __fixtfti, __fixunstfdi, __fixunstfsi, __fixunstfti, }; -- cgit 1.4.1-3-g733a5 From d696144b878277236f2fae367d2fc7d41b5f13c1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 May 2024 01:45:17 -0400 Subject: Organize functions in intrinsics example --- library/compiler-builtins/examples/intrinsics.rs | 179 ++++++++++++----------- 1 file changed, 96 insertions(+), 83 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 54b703dfbc7..201c9a7e053 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -8,10 +8,12 @@ #![allow(internal_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] +#![feature(allocator_api)] #![feature(bench_black_box)] +#![feature(f128)] +#![feature(f16)] #![feature(lang_items)] #![feature(start)] -#![feature(allocator_api)] #![no_std] extern crate panic_handler; @@ -26,126 +28,132 @@ extern "C" {} // have an additional comment: the function name is the ARM name for the intrinsic and the comment // in the non-ARM name for the intrinsic. mod intrinsics { - // truncdfsf2 - pub fn aeabi_d2f(x: f64) -> f32 { - x as f32 + /* f32 operations */ + + // extendsfdf2 + pub fn aeabi_f2d(x: f32) -> f64 { + x as f64 } - // fixdfsi - pub fn aeabi_d2i(x: f64) -> i32 { + // fixsfsi + pub fn aeabi_f2iz(x: f32) -> i32 { x as i32 } - // fixdfdi - pub fn aeabi_d2l(x: f64) -> i64 { + // fixsfdi + pub fn aeabi_f2lz(x: f32) -> i64 { x as i64 } - // fixunsdfsi - pub fn aeabi_d2uiz(x: f64) -> u32 { + // fixunssfsi + pub fn aeabi_f2uiz(x: f32) -> u32 { x as u32 } - // fixunsdfdi - pub fn aeabi_d2ulz(x: f64) -> u64 { + // fixunssfdi + pub fn aeabi_f2ulz(x: f32) -> u64 { x as u64 } - // adddf3 - pub fn aeabi_dadd(a: f64, b: f64) -> f64 { + // addsf3 + pub fn aeabi_fadd(a: f32, b: f32) -> f32 { a + b } - // eqdf2 - pub fn aeabi_dcmpeq(a: f64, b: f64) -> bool { + // eqsf2 + pub fn aeabi_fcmpeq(a: f32, b: f32) -> bool { a == b } - // gtdf2 - pub fn aeabi_dcmpgt(a: f64, b: f64) -> bool { + // gtsf2 + pub fn aeabi_fcmpgt(a: f32, b: f32) -> bool { a > b } - // ltdf2 - pub fn aeabi_dcmplt(a: f64, b: f64) -> bool { + // ltsf2 + pub fn aeabi_fcmplt(a: f32, b: f32) -> bool { a < b } - // divdf3 - pub fn aeabi_ddiv(a: f64, b: f64) -> f64 { + // divsf3 + pub fn aeabi_fdiv(a: f32, b: f32) -> f32 { a / b } - // muldf3 - pub fn aeabi_dmul(a: f64, b: f64) -> f64 { + // mulsf3 + pub fn aeabi_fmul(a: f32, b: f32) -> f32 { a * b } - // subdf3 - pub fn aeabi_dsub(a: f64, b: f64) -> f64 { + // subsf3 + pub fn aeabi_fsub(a: f32, b: f32) -> f32 { a - b } - // extendsfdf2 - pub fn aeabi_f2d(x: f32) -> f64 { - x as f64 + /* f64 operations */ + + // truncdfsf2 + pub fn aeabi_d2f(x: f64) -> f32 { + x as f32 } - // fixsfsi - pub fn aeabi_f2iz(x: f32) -> i32 { + // fixdfsi + pub fn aeabi_d2i(x: f64) -> i32 { x as i32 } - // fixsfdi - pub fn aeabi_f2lz(x: f32) -> i64 { + // fixdfdi + pub fn aeabi_d2l(x: f64) -> i64 { x as i64 } - // fixunssfsi - pub fn aeabi_f2uiz(x: f32) -> u32 { + // fixunsdfsi + pub fn aeabi_d2uiz(x: f64) -> u32 { x as u32 } - // fixunssfdi - pub fn aeabi_f2ulz(x: f32) -> u64 { + // fixunsdfdi + pub fn aeabi_d2ulz(x: f64) -> u64 { x as u64 } - // addsf3 - pub fn aeabi_fadd(a: f32, b: f32) -> f32 { + // adddf3 + pub fn aeabi_dadd(a: f64, b: f64) -> f64 { a + b } - // eqsf2 - pub fn aeabi_fcmpeq(a: f32, b: f32) -> bool { + // eqdf2 + pub fn aeabi_dcmpeq(a: f64, b: f64) -> bool { a == b } - // gtsf2 - pub fn aeabi_fcmpgt(a: f32, b: f32) -> bool { + // gtdf2 + pub fn aeabi_dcmpgt(a: f64, b: f64) -> bool { a > b } - // ltsf2 - pub fn aeabi_fcmplt(a: f32, b: f32) -> bool { + // ltdf2 + pub fn aeabi_dcmplt(a: f64, b: f64) -> bool { a < b } - // divsf3 - pub fn aeabi_fdiv(a: f32, b: f32) -> f32 { + // divdf3 + pub fn aeabi_ddiv(a: f64, b: f64) -> f64 { a / b } - // mulsf3 - pub fn aeabi_fmul(a: f32, b: f32) -> f32 { + // muldf3 + pub fn aeabi_dmul(a: f64, b: f64) -> f64 { a * b } - // subsf3 - pub fn aeabi_fsub(a: f32, b: f32) -> f32 { + // subdf3 + pub fn aeabi_dsub(a: f64, b: f64) -> f64 { a - b } + /* i32 operations */ + // floatsidf pub fn aeabi_i2d(x: i32) -> f64 { x as f64 @@ -164,14 +172,20 @@ mod intrinsics { a % b } + /* i64 operations */ + + // floatdisf + pub fn aeabi_l2f(x: i64) -> f32 { + x as f32 + } + // floatdidf pub fn aeabi_l2d(x: i64) -> f64 { x as f64 } - // floatdisf - pub fn aeabi_l2f(x: i64) -> f32 { - x as f32 + pub fn mulodi4(a: i64, b: i64) -> i64 { + a * b } // divdi3 @@ -179,11 +193,31 @@ mod intrinsics { a / b } + pub fn moddi3(a: i64, b: i64) -> i64 { + a % b + } + // muldi3 pub fn aeabi_lmul(a: i64, b: i64) -> i64 { a.wrapping_mul(b) } + /* i128 operations */ + + pub fn lshrti3(a: i128, b: usize) -> i128 { + a >> b + } + + pub fn divti3(a: i128, b: i128) -> i128 { + a / b + } + + pub fn modti3(a: i128, b: i128) -> i128 { + a % b + } + + /* u32 operations */ + // floatunsidf pub fn aeabi_ui2d(x: u32) -> f64 { x as f64 @@ -202,26 +236,20 @@ mod intrinsics { a % b } - // floatundidf - pub fn aeabi_ul2d(x: u64) -> f64 { - x as f64 - } + /* u64 operations */ // floatundisf pub fn aeabi_ul2f(x: u64) -> f32 { x as f32 } - // udivdi3 - pub fn aeabi_uldivmod(a: u64, b: u64) -> u64 { - a * b - } - - pub fn moddi3(a: i64, b: i64) -> i64 { - a % b + // floatundidf + pub fn aeabi_ul2d(x: u64) -> f64 { + x as f64 } - pub fn mulodi4(a: i64, b: i64) -> i64 { + // udivdi3 + pub fn aeabi_uldivmod(a: u64, b: u64) -> u64 { a * b } @@ -229,6 +257,8 @@ mod intrinsics { a % b } + /* u128 operations */ + pub fn muloti4(a: u128, b: u128) -> Option { a.checked_mul(b) } @@ -245,10 +275,6 @@ mod intrinsics { a << b } - pub fn lshrti3(a: i128, b: usize) -> i128 { - a >> b - } - pub fn udivti3(a: u128, b: u128) -> u128 { a / b } @@ -256,18 +282,6 @@ mod intrinsics { pub fn umodti3(a: u128, b: u128) -> u128 { a % b } - - pub fn divti3(a: i128, b: i128) -> i128 { - a / b - } - - pub fn modti3(a: i128, b: i128) -> i128 { - a % b - } - - pub fn udivsi3(a: u32, b: u32) -> u32 { - a / b - } } fn run() { @@ -325,7 +339,6 @@ fn run() { bb(umodti3(bb(2), bb(2))); bb(divti3(bb(2), bb(2))); bb(modti3(bb(2), bb(2))); - bb(udivsi3(bb(2), bb(2))); something_with_a_dtor(&|| assert_eq!(bb(1), 1)); -- cgit 1.4.1-3-g733a5 From 324544fb6a1acb678cb4259d29173e17ed266958 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 May 2024 01:55:46 -0400 Subject: Add f16 and f128 intrinsics to the example test --- library/compiler-builtins/examples/intrinsics.rs | 134 ++++++++++++++++++++++- 1 file changed, 128 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 201c9a7e053..e4fcb3e35e3 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -28,13 +28,36 @@ extern "C" {} // have an additional comment: the function name is the ARM name for the intrinsic and the comment // in the non-ARM name for the intrinsic. mod intrinsics { + /* f16 operations */ + + pub fn extendhfsf(x: f16) -> f32 { + x as f32 + } + + pub fn extendhfdf(x: f16) -> f64 { + x as f64 + } + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn extendhftf(x: f16) -> f128 { + x as f128 + } + /* f32 operations */ + pub fn truncsfhf(x: f32) -> f16 { + x as f16 + } + // extendsfdf2 pub fn aeabi_f2d(x: f32) -> f64 { x as f64 } + pub fn extendsftf(x: f32) -> f128 { + x as f128 + } + // fixsfsi pub fn aeabi_f2iz(x: f32) -> i32 { x as i32 @@ -152,6 +175,75 @@ mod intrinsics { a - b } + /* f128 operations */ + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn trunctfhf(x: f128) -> f16 { + x as f16 + } + + pub fn trunctfsf(x: f128) -> f32 { + x as f32 + } + + pub fn trunctfdf(x: f128) -> f64 { + x as f64 + } + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn fixtfsi(x: f128) -> i32 { + x as i32 + } + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn fixtfdi(x: f128) -> i64 { + x as i64 + } + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn fixtfti(x: f128) -> i128 { + x as i128 + } + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn fixunstfsi(x: f128) -> u32 { + x as u32 + } + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn fixunstfdi(x: f128) -> u64 { + x as u64 + } + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn fixunstfti(x: f128) -> u128 { + x as u128 + } + + pub fn addtf(a: f128, b: f128) -> f128 { + a + b + } + + pub fn eqtf(a: f128, b: f128) -> bool { + a == b + } + + pub fn gttf(a: f128, b: f128) -> bool { + a > b + } + + pub fn lttf(a: f128, b: f128) -> bool { + a < b + } + + pub fn multf(a: f128, b: f128) -> f128 { + a * b + } + + pub fn subtf(a: f128, b: f128) -> f128 { + a - b + } + /* i32 operations */ // floatsidf @@ -288,6 +380,9 @@ fn run() { use core::hint::black_box as bb; use intrinsics::*; + // FIXME(f16_f128): some PPC f128 <-> int conversion functions have the wrong names + + bb(addtf(bb(2.), bb(2.))); bb(aeabi_d2f(bb(2.))); bb(aeabi_d2i(bb(2.))); bb(aeabi_d2l(bb(2.))); @@ -327,18 +422,45 @@ fn run() { bb(aeabi_ul2d(bb(2))); bb(aeabi_ul2f(bb(2))); bb(aeabi_uldivmod(bb(2), bb(3))); + bb(ashlti3(bb(2), bb(2))); + bb(ashrti3(bb(2), bb(2))); + bb(divti3(bb(2), bb(2))); + bb(eqtf(bb(2.), bb(2.))); + bb(extendhfdf(bb(2.))); + bb(extendhfsf(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(extendhftf(bb(2.))); + bb(extendsftf(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(fixtfdi(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(fixtfsi(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(fixtfti(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(fixunstfdi(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(fixunstfsi(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(fixunstfti(bb(2.))); + bb(gttf(bb(2.), bb(2.))); + bb(lshrti3(bb(2), bb(2))); + bb(lttf(bb(2.), bb(2.))); bb(moddi3(bb(2), bb(3))); + bb(modti3(bb(2), bb(2))); bb(mulodi4(bb(2), bb(3))); - bb(umoddi3(bb(2), bb(3))); bb(muloti4(bb(2), bb(2))); + bb(multf(bb(2.), bb(2.))); bb(multi3(bb(2), bb(2))); - bb(ashlti3(bb(2), bb(2))); - bb(ashrti3(bb(2), bb(2))); - bb(lshrti3(bb(2), bb(2))); + bb(subtf(bb(2.), bb(2.))); + bb(truncsfhf(bb(2.))); + bb(trunctfdf(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(trunctfhf(bb(2.))); + bb(trunctfsf(bb(2.))); bb(udivti3(bb(2), bb(2))); + bb(umoddi3(bb(2), bb(3))); bb(umodti3(bb(2), bb(2))); - bb(divti3(bb(2), bb(2))); - bb(modti3(bb(2), bb(2))); something_with_a_dtor(&|| assert_eq!(bb(1), 1)); -- cgit 1.4.1-3-g733a5 From ec123994707db2421c41d7bda9fc38c5a9a31a07 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 May 2024 01:59:00 -0400 Subject: Update outdated contribution guidelines --- library/compiler-builtins/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 8233c669c6d..9a847da3f69 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -52,17 +52,17 @@ features = ["c"] 2. Fork this repository. 3. Port the intrinsic(s) and their corresponding [unit tests][1] from their [C implementation][2] to Rust. -4. Implement a [test generator][3] to compare the behavior of the ported intrinsic(s) - with their implementation on the testing host. Note that randomized compiler-builtin tests - should be run using `cargo test --features gen-tests`. -4. Send a Pull Request (PR). -5. Once the PR passes our extensive [testing infrastructure][4], we'll merge it! -6. Celebrate :tada: +4. Add a test to compare the behavior of the ported intrinsic(s) with their + implementation on the testing host. +5. Add the intrinsic to `examples/intrinsics.rs` to verify it can be linked on + all targets. +6. Send a Pull Request (PR). +7. Once the PR passes our extensive [testing infrastructure][4], we'll merge it! +8. Celebrate :tada: [1]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/test/builtins/Unit [2]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/lib/builtins -[3]: https://github.com/rust-lang/compiler-builtins/blob/0ba07e49264a54cb5bbd4856fcea083bb3fbec15/build.rs#L180-L265 -[4]: https://github.com/rust-lang/compiler-builtins/actions +[3]: https://github.com/rust-lang/compiler-builtins/actions ### Porting Reminders -- cgit 1.4.1-3-g733a5 From 81fbfedd9214ea9b488aac5cbf69e328799bd8a9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 May 2024 02:02:21 -0400 Subject: Add some missing functions to examples/intrinsics --- library/compiler-builtins/examples/intrinsics.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index e4fcb3e35e3..8bb70767376 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -68,6 +68,10 @@ mod intrinsics { x as i64 } + pub fn fixsfti(x: f32) -> i128 { + x as i128 + } + // fixunssfsi pub fn aeabi_f2uiz(x: f32) -> u32 { x as u32 @@ -78,6 +82,10 @@ mod intrinsics { x as u64 } + pub fn fixunssfti(x: f32) -> u128 { + x as u128 + } + // addsf3 pub fn aeabi_fadd(a: f32, b: f32) -> f32 { a + b @@ -130,6 +138,10 @@ mod intrinsics { x as i64 } + pub fn fixdfti(x: f64) -> i128 { + x as i128 + } + // fixunsdfsi pub fn aeabi_d2uiz(x: f64) -> u32 { x as u32 @@ -140,6 +152,10 @@ mod intrinsics { x as u64 } + pub fn fixunsdfti(x: f64) -> u128 { + x as u128 + } + // adddf3 pub fn aeabi_dadd(a: f64, b: f64) -> f64 { a + b @@ -431,12 +447,16 @@ fn run() { #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] bb(extendhftf(bb(2.))); bb(extendsftf(bb(2.))); + bb(fixdfti(bb(2.))); + bb(fixsfti(bb(2.))); #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] bb(fixtfdi(bb(2.))); #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] bb(fixtfsi(bb(2.))); #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] bb(fixtfti(bb(2.))); + bb(fixunsdfti(bb(2.))); + bb(fixunssfti(bb(2.))); #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] bb(fixunstfdi(bb(2.))); #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] -- cgit 1.4.1-3-g733a5 From 2fa55c4ef5f70a7fee319d6da962b6ed4e441836 Mon Sep 17 00:00:00 2001 From: Quentin Perez Date: Wed, 22 May 2024 09:49:08 +0200 Subject: Add Apple visionOS support --- library/compiler-builtins/build.rs | 13 ++----------- library/compiler-builtins/src/arm.rs | 30 +++++++++++++++--------------- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 50415910d29..0ecd399118e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -377,11 +377,7 @@ mod c { // On iOS and 32-bit OSX these are all just empty intrinsics, no need to // include them. - if target_os != "ios" - && target_os != "watchos" - && target_os != "tvos" - && (target_vendor != "apple" || target_arch != "x86") - { + if target_vendor != "apple" || target_arch != "x86" { sources.extend(&[ ("__absvti2", "absvti2.c"), ("__addvti3", "addvti3.c"), @@ -431,12 +427,7 @@ mod c { } } - if target_arch == "arm" - && target_os != "ios" - && target_os != "watchos" - && target_os != "tvos" - && target_env != "msvc" - { + if target_arch == "arm" && target_vendor != "apple" && target_env != "msvc" { sources.extend(&[ ("__aeabi_div0", "arm/aeabi_div0.c"), ("__aeabi_drsub", "arm/aeabi_drsub.c"), diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index dcae22b73fb..55cdda1f3e0 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -3,14 +3,14 @@ use core::intrinsics; -// iOS symbols have a leading underscore. -#[cfg(target_os = "ios")] +// Apple symbols have a leading underscore. +#[cfg(target_vendor = "apple")] macro_rules! bl { ($func:literal) => { concat!("bl _", $func) }; } -#[cfg(not(target_os = "ios"))] +#[cfg(not(target_vendor = "apple"))] macro_rules! bl { ($func:literal) => { concat!("bl ", $func) @@ -82,12 +82,12 @@ intrinsics! { // FIXME: The `*4` and `*8` variants should be defined as aliases. - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { crate::mem::memcpy(dest, src, n); } - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { // We are guaranteed 4-alignment, so accessing at u32 is okay. let mut dest = dest as *mut u32; @@ -104,33 +104,33 @@ intrinsics! { __aeabi_memcpy(dest as *mut u8, src as *const u8, n); } - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memcpy4(dest, src, n); } - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { crate::mem::memmove(dest, src, n); } - #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } - #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { // Note the different argument order crate::mem::memset(dest, c, n); } - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { let mut dest = dest as *mut u32; let mut n = n; @@ -147,22 +147,22 @@ intrinsics! { __aeabi_memset(dest as *mut u8, n, byte as i32); } - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { __aeabi_memset4(dest, n, c); } - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { __aeabi_memset(dest, n, 0); } - #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } - #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } -- cgit 1.4.1-3-g733a5 From 6cd17ff4d23977ea6df711f3197b191994a5513e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 19 May 2024 05:02:25 -0400 Subject: Add benchmarks for floating point math This adds comparisons among the compiler-builtins function, system functions if available, and optionally handwritten assembly. These also help us identify inconsistencies between this crate and system functions, which may otherwise go unnoticed if intrinsics get lowered to inline operations rather than library calls. --- library/compiler-builtins/ci/run.sh | 6 +- library/compiler-builtins/testcrate/Cargo.toml | 48 +- .../testcrate/bench-175b45d1-aarch64-macos.txt | 500 +++++++++++++++ .../testcrate/bench-3cee6376-aarch64-macos.txt | 699 +++++++++++++++++++++ .../testcrate/benches/float_add.rs | 81 +++ .../testcrate/benches/float_cmp.rs | 202 ++++++ .../testcrate/benches/float_conv.rs | 547 ++++++++++++++++ .../testcrate/benches/float_div.rs | 70 +++ .../testcrate/benches/float_extend.rs | 93 +++ .../testcrate/benches/float_mul.rs | 81 +++ .../testcrate/benches/float_pow.rs | 24 + .../testcrate/benches/float_sub.rs | 81 +++ .../testcrate/benches/float_trunc.rs | 127 ++++ library/compiler-builtins/testcrate/build.rs | 19 + library/compiler-builtins/testcrate/src/bench.rs | 348 ++++++++++ library/compiler-builtins/testcrate/src/lib.rs | 6 + 16 files changed, 2930 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt create mode 100644 library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt create mode 100644 library/compiler-builtins/testcrate/benches/float_add.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_cmp.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_conv.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_div.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_extend.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_mul.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_pow.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_sub.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_trunc.rs create mode 100644 library/compiler-builtins/testcrate/src/bench.rs diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 2512dc633e5..dcbe1caf4ef 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -4,7 +4,9 @@ set -eux target="${1:-}" -if [ -z "${1:-}" ]; then +export RUST_BACKTRACE="${RUST_BACKTRACE:-full}" + +if [ -z "$target" ]; then host_target=$(rustc -vV | awk '/^host/ { print $2 }') echo "Defaulted to host target $host_target" target="$host_target" @@ -30,6 +32,8 @@ else $run --features no-asm --release $run --features no-f16-f128 $run --features no-f16-f128 --release + $run --benches + $run --benches --release fi if [ "${TEST_VERBATIM:-}" = "1" ]; then diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 1de0c39761e..6b5c4cf48d2 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -21,6 +21,10 @@ path = ".." default-features = false features = ["public-test-deps"] +[dev-dependencies] +criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } +paste = "1.0.15" + [target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] test = { git = "https://github.com/japaric/utest" } utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japaric/utest" } @@ -34,6 +38,48 @@ no-f16-f128 = ["compiler_builtins/no-f16-f128"] mem = ["compiler_builtins/mem"] mangled-names = ["compiler_builtins/mangled-names"] # Skip tests that rely on f128 symbols being available on the system -no-sys-f128 = ["no-sys-f128-int-convert"] +no-sys-f128 = ["no-sys-f128-int-convert", "no-sys-f16-f128-convert"] # Some platforms have some f128 functions but everything except integer conversions no-sys-f128-int-convert = [] +no-sys-f16-f128-convert = [] +# Skip tests that rely on f16 symbols being available on the system +no-sys-f16 = [] + +# Enable report generation without bringing in more dependencies by default +benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] + +[[bench]] +name = "float_add" +harness = false + +[[bench]] +name = "float_sub" +harness = false + +[[bench]] +name = "float_mul" +harness = false + +[[bench]] +name = "float_div" +harness = false + +[[bench]] +name = "float_cmp" +harness = false + +[[bench]] +name = "float_conv" +harness = false + +[[bench]] +name = "float_extend" +harness = false + +[[bench]] +name = "float_trunc" +harness = false + +[[bench]] +name = "float_pow" +harness = false diff --git a/library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt b/library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt new file mode 100644 index 00000000000..e79bbe36873 --- /dev/null +++ b/library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt @@ -0,0 +1,500 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +add_f32 compiler-builtins + time: [35.804 µs 35.863 µs 35.920 µs] +Found 5 outliers among 100 measurements (5.00%) + 2 (2.00%) high mild + 3 (3.00%) high severe + +add_f32 system time: [39.084 µs 39.127 µs 39.169 µs] +Found 11 outliers among 100 measurements (11.00%) + 7 (7.00%) high mild + 4 (4.00%) high severe + +add_f32 assembly (aarch64 unix) + time: [8.1034 µs 8.1441 µs 8.1866 µs] +Found 4 outliers among 100 measurements (4.00%) + 4 (4.00%) high mild + +add_f64 compiler-builtins + time: [35.647 µs 35.725 µs 35.799 µs] +Found 10 outliers among 100 measurements (10.00%) + 8 (8.00%) high mild + 2 (2.00%) high severe + +add_f64 system time: [39.308 µs 39.322 µs 39.336 µs] +Found 7 outliers among 100 measurements (7.00%) + 4 (4.00%) high mild + 3 (3.00%) high severe + +add_f64 assembly (aarch64 unix) + time: [8.0401 µs 8.0442 µs 8.0499 µs] +Found 11 outliers among 100 measurements (11.00%) + 2 (2.00%) high mild + 9 (9.00%) high severe + +add_f128 compiler-builtins + time: [41.801 µs 41.986 µs 42.201 µs] +Found 7 outliers among 100 measurements (7.00%) + 4 (4.00%) high mild + 3 (3.00%) high severe + +cmp_f32_gt compiler-builtins + time: [13.579 µs 13.675 µs 13.778 µs] +Found 16 outliers among 100 measurements (16.00%) + 6 (6.00%) high mild + 10 (10.00%) high severe + +cmp_f32_gt system time: [12.343 µs 12.348 µs 12.355 µs] +Found 13 outliers among 100 measurements (13.00%) + 1 (1.00%) low mild + 3 (3.00%) high mild + 9 (9.00%) high severe + +cmp_f32_gt assembly (aarch64 unix) + time: [8.2593 µs 8.3185 µs 8.3813 µs] +Found 1 outliers among 100 measurements (1.00%) + 1 (1.00%) high mild + +cmp_f32_unord compiler-builtins + time: [11.977 µs 12.042 µs 12.109 µs] +Found 13 outliers among 100 measurements (13.00%) + 5 (5.00%) low severe + 6 (6.00%) low mild + 2 (2.00%) high mild + +cmp_f32_unord system time: [8.1236 µs 8.1736 µs 8.2350 µs] +Found 18 outliers among 100 measurements (18.00%) + 5 (5.00%) high mild + 13 (13.00%) high severe + +cmp_f32_unord assembly (aarch64 unix) + time: [8.1446 µs 8.2080 µs 8.2762 µs] +Found 14 outliers among 100 measurements (14.00%) + 6 (6.00%) high mild + 8 (8.00%) high severe + +cmp_f64_gt compiler-builtins + time: [16.073 µs 16.077 µs 16.082 µs] +Found 17 outliers among 100 measurements (17.00%) + 2 (2.00%) low mild + 4 (4.00%) high mild + 11 (11.00%) high severe + +cmp_f64_gt system time: [12.456 µs 12.487 µs 12.522 µs] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe + +cmp_f64_gt assembly (aarch64 unix) + time: [8.0557 µs 8.0616 µs 8.0685 µs] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe + +cmp_f64_unord compiler-builtins + time: [10.715 µs 10.724 µs 10.737 µs] +Found 13 outliers among 100 measurements (13.00%) + 3 (3.00%) high mild + 10 (10.00%) high severe + +cmp_f64_unord system time: [8.0692 µs 8.0734 µs 8.0784 µs] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe + +cmp_f64_unord assembly (aarch64 unix) + time: [8.0569 µs 8.0677 µs 8.0818 µs] +Found 18 outliers among 100 measurements (18.00%) + 4 (4.00%) high mild + 14 (14.00%) high severe + +cmp_f128_gt compiler-builtins + time: [18.234 µs 18.401 µs 18.602 µs] + +cmp_f128_unord compiler-builtins + time: [13.410 µs 13.471 µs 13.542 µs] +Found 7 outliers among 100 measurements (7.00%) + 7 (7.00%) high mild + +conv_u32_f32 compiler-builtins + time: [774.58 ns 776.01 ns 777.59 ns] +Found 9 outliers among 100 measurements (9.00%) + 2 (2.00%) high mild + 7 (7.00%) high severe + +conv_u32_f32 system time: [622.68 ns 625.64 ns 629.26 ns] +Found 16 outliers among 100 measurements (16.00%) + 7 (7.00%) high mild + 9 (9.00%) high severe + +conv_u32_f32 assembly (aarch64 unix) + time: [468.05 ns 469.76 ns 471.46 ns] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe + +conv_u32_f64 compiler-builtins + time: [617.61 ns 618.00 ns 618.52 ns] +Found 13 outliers among 100 measurements (13.00%) + 4 (4.00%) high mild + 9 (9.00%) high severe + +conv_u32_f64 system time: [469.56 ns 471.03 ns 472.81 ns] +Found 11 outliers among 100 measurements (11.00%) + 7 (7.00%) high mild + 4 (4.00%) high severe + +conv_u32_f64 assembly (aarch64 unix) + time: [464.43 ns 465.01 ns 465.72 ns] +Found 13 outliers among 100 measurements (13.00%) + 5 (5.00%) high mild + 8 (8.00%) high severe + +conv_u64_f32 compiler-builtins + time: [847.95 ns 848.19 ns 848.46 ns] +Found 19 outliers among 100 measurements (19.00%) + 3 (3.00%) low mild + 9 (9.00%) high mild + 7 (7.00%) high severe + +conv_u64_f32 system time: [701.68 ns 701.95 ns 702.30 ns] +Found 10 outliers among 100 measurements (10.00%) + 4 (4.00%) high mild + 6 (6.00%) high severe + +conv_u64_f32 assembly (aarch64 unix) + time: [511.73 ns 512.43 ns 513.32 ns] +Found 6 outliers among 100 measurements (6.00%) + 6 (6.00%) high mild + +conv_u64_f64 compiler-builtins + time: [681.23 ns 682.55 ns 684.30 ns] +Found 18 outliers among 100 measurements (18.00%) + 1 (1.00%) high mild + 17 (17.00%) high severe + +conv_u64_f64 system time: [679.34 ns 679.57 ns 679.88 ns] +Found 18 outliers among 100 measurements (18.00%) + 1 (1.00%) low mild + 6 (6.00%) high mild + 11 (11.00%) high severe + +conv_u64_f64 assembly (aarch64 unix) + time: [509.90 ns 510.09 ns 510.30 ns] +Found 15 outliers among 100 measurements (15.00%) + 6 (6.00%) high mild + 9 (9.00%) high severe + +conv_u128_f32 compiler-builtins + time: [1.1368 µs 1.1372 µs 1.1377 µs] +Found 14 outliers among 100 measurements (14.00%) + 8 (8.00%) high mild + 6 (6.00%) high severe + +conv_u128_f32 system time: [1.4338 µs 1.4370 µs 1.4410 µs] +Found 7 outliers among 100 measurements (7.00%) + 2 (2.00%) high mild + 5 (5.00%) high severe + +conv_u128_f64 compiler-builtins + time: [1.0133 µs 1.0143 µs 1.0156 µs] +Found 16 outliers among 100 measurements (16.00%) + 2 (2.00%) high mild + 14 (14.00%) high severe + +conv_u128_f64 system time: [1.3473 µs 1.3530 µs 1.3600 µs] +Found 4 outliers among 100 measurements (4.00%) + 4 (4.00%) high mild + +conv_i32_f32 compiler-builtins + time: [906.53 ns 907.86 ns 909.23 ns] +Found 7 outliers among 100 measurements (7.00%) + 4 (4.00%) high mild + 3 (3.00%) high severe + +conv_i32_f32 system time: [914.53 ns 915.69 ns 917.01 ns] +Found 10 outliers among 100 measurements (10.00%) + 6 (6.00%) high mild + 4 (4.00%) high severe + +conv_i32_f32 assembly (aarch64 unix) + time: [464.55 ns 465.10 ns 465.83 ns] +Found 4 outliers among 100 measurements (4.00%) + 4 (4.00%) high mild + +conv_i32_f64 compiler-builtins + time: [617.63 ns 617.92 ns 618.27 ns] +Found 12 outliers among 100 measurements (12.00%) + 3 (3.00%) high mild + 9 (9.00%) high severe + +conv_i32_f64 system time: [622.83 ns 624.19 ns 625.61 ns] +Found 6 outliers among 100 measurements (6.00%) + 5 (5.00%) high mild + 1 (1.00%) high severe + +conv_i32_f64 assembly (aarch64 unix) + time: [465.24 ns 466.04 ns 466.95 ns] +Found 11 outliers among 100 measurements (11.00%) + 4 (4.00%) high mild + 7 (7.00%) high severe + +conv_i64_f32 compiler-builtins + time: [852.67 ns 853.92 ns 855.34 ns] +Found 11 outliers among 100 measurements (11.00%) + 3 (3.00%) high mild + 8 (8.00%) high severe + +conv_i64_f32 system time: [906.94 ns 908.04 ns 909.33 ns] +Found 15 outliers among 100 measurements (15.00%) + 2 (2.00%) high mild + 13 (13.00%) high severe + +conv_i64_f32 assembly (aarch64 unix) + time: [510.84 ns 511.27 ns 511.80 ns] +Found 8 outliers among 100 measurements (8.00%) + 3 (3.00%) high mild + 5 (5.00%) high severe + +conv_i64_f64 compiler-builtins + time: [932.35 ns 932.97 ns 933.76 ns] +Found 10 outliers among 100 measurements (10.00%) + 4 (4.00%) high mild + 6 (6.00%) high severe + +conv_i64_f64 system time: [955.91 ns 958.95 ns 962.05 ns] +Found 5 outliers among 100 measurements (5.00%) + 3 (3.00%) high mild + 2 (2.00%) high severe + +conv_i64_f64 assembly (aarch64 unix) + time: [510.19 ns 510.72 ns 511.44 ns] +Found 9 outliers among 100 measurements (9.00%) + 5 (5.00%) high mild + 4 (4.00%) high severe + +conv_i128_f32 compiler-builtins + time: [1.4248 µs 1.4285 µs 1.4323 µs] +Found 12 outliers among 100 measurements (12.00%) + 7 (7.00%) high mild + 5 (5.00%) high severe + +conv_i128_f32 system time: [1.6970 µs 1.7017 µs 1.7069 µs] +Found 5 outliers among 100 measurements (5.00%) + 3 (3.00%) high mild + 2 (2.00%) high severe + +conv_i128_f64 compiler-builtins + time: [1.3132 µs 1.3161 µs 1.3191 µs] +Found 2 outliers among 100 measurements (2.00%) + 1 (1.00%) high mild + 1 (1.00%) high severe + +conv_i128_f64 system time: [1.6071 µs 1.6100 µs 1.6133 µs] +Found 4 outliers among 100 measurements (4.00%) + 3 (3.00%) high mild + 1 (1.00%) high severe + +conv_f64_u32 compiler-builtins + time: [640.35 ns 641.00 ns 641.68 ns] +Found 6 outliers among 100 measurements (6.00%) + 4 (4.00%) high mild + 2 (2.00%) high severe + +conv_f64_u32 system time: [640.87 ns 641.63 ns 642.42 ns] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe + +conv_f64_u32 assembly (aarch64 unix) + time: [482.02 ns 482.67 ns 483.38 ns] +Found 1 outliers among 100 measurements (1.00%) + 1 (1.00%) high severe + +conv_f64_u64 compiler-builtins + time: [638.58 ns 638.98 ns 639.45 ns] +Found 15 outliers among 100 measurements (15.00%) + 1 (1.00%) high mild + 14 (14.00%) high severe + +conv_f64_u64 system time: [642.54 ns 644.07 ns 645.59 ns] +Found 4 outliers among 100 measurements (4.00%) + 3 (3.00%) high mild + 1 (1.00%) high severe + +conv_f64_u64 assembly (aarch64 unix) + time: [482.65 ns 483.70 ns 484.87 ns] +Found 1 outliers among 100 measurements (1.00%) + 1 (1.00%) high mild + +conv_f64_u128 compiler-builtins + time: [1.0631 µs 1.0652 µs 1.0674 µs] +Found 8 outliers among 100 measurements (8.00%) + 7 (7.00%) high mild + 1 (1.00%) high severe + +conv_f64_u128 system time: [821.41 ns 823.45 ns 825.74 ns] +Found 11 outliers among 100 measurements (11.00%) + 8 (8.00%) high mild + 3 (3.00%) high severe + +conv_f64_i32 compiler-builtins + time: [826.76 ns 845.08 ns 870.23 ns] +Found 4 outliers among 100 measurements (4.00%) + 4 (4.00%) high mild + +conv_f64_i32 system time: [764.12 ns 764.63 ns 765.26 ns] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high severe + +conv_f64_i32 assembly (aarch64 unix) + time: [484.50 ns 485.98 ns 487.54 ns] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe + +conv_f64_i64 compiler-builtins + time: [797.27 ns 798.19 ns 799.84 ns] +Found 9 outliers among 100 measurements (9.00%) + 5 (5.00%) high mild + 4 (4.00%) high severe + +conv_f64_i64 system time: [768.74 ns 769.52 ns 770.23 ns] +Found 1 outliers among 100 measurements (1.00%) + 1 (1.00%) high severe + +conv_f64_i64 assembly (aarch64 unix) + time: [480.59 ns 481.03 ns 481.46 ns] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe + +conv_f64_i128 compiler-builtins + time: [1.0577 µs 1.0591 µs 1.0606 µs] +Found 2 outliers among 100 measurements (2.00%) + 1 (1.00%) high mild + 1 (1.00%) high severe + +conv_f64_i128 system time: [1.0181 µs 1.0195 µs 1.0211 µs] +Found 3 outliers among 100 measurements (3.00%) + 3 (3.00%) high mild + +conv_f32_u32 compiler-builtins + time: [800.40 ns 801.39 ns 802.35 ns] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high mild + +conv_f32_u32 system time: [638.12 ns 638.34 ns 638.63 ns] +Found 11 outliers among 100 measurements (11.00%) + 4 (4.00%) high mild + 7 (7.00%) high severe + +conv_f32_u32 assembly (aarch64 unix) + time: [479.37 ns 480.97 ns 483.32 ns] +Found 13 outliers among 100 measurements (13.00%) + 6 (6.00%) high mild + 7 (7.00%) high severe + +conv_f32_u64 compiler-builtins + time: [801.95 ns 803.64 ns 805.75 ns] + +conv_f32_u64 system time: [638.20 ns 638.56 ns 639.07 ns] +Found 10 outliers among 100 measurements (10.00%) + 1 (1.00%) high mild + 9 (9.00%) high severe + +conv_f32_u64 assembly (aarch64 unix) + time: [480.07 ns 480.47 ns 480.86 ns] +Found 2 outliers among 100 measurements (2.00%) + 1 (1.00%) high mild + 1 (1.00%) high severe + +conv_f32_u128 compiler-builtins + time: [1.1579 µs 1.1623 µs 1.1657 µs] +Found 14 outliers among 100 measurements (14.00%) + 2 (2.00%) low severe + 7 (7.00%) high mild + 5 (5.00%) high severe + +conv_f32_u128 system time: [1.0344 µs 1.0394 µs 1.0450 µs] + +conv_f32_i32 compiler-builtins + time: [800.14 ns 801.52 ns 803.26 ns] +Found 10 outliers among 100 measurements (10.00%) + 8 (8.00%) high mild + 2 (2.00%) high severe + +conv_f32_i32 system time: [741.36 ns 741.74 ns 742.13 ns] +Found 4 outliers among 100 measurements (4.00%) + 2 (2.00%) high mild + 2 (2.00%) high severe + +conv_f32_i32 assembly (aarch64 unix) + time: [484.35 ns 486.08 ns 488.11 ns] +Found 17 outliers among 100 measurements (17.00%) + 9 (9.00%) high mild + 8 (8.00%) high severe + +conv_f32_i64 compiler-builtins + time: [800.94 ns 802.68 ns 804.74 ns] + +conv_f32_i64 system time: [748.60 ns 750.68 ns 753.16 ns] +Found 9 outliers among 100 measurements (9.00%) + 4 (4.00%) high mild + 5 (5.00%) high severe + +conv_f32_i64 assembly (aarch64 unix) + time: [480.70 ns 481.23 ns 481.82 ns] +Found 4 outliers among 100 measurements (4.00%) + 2 (2.00%) high mild + 2 (2.00%) high severe + +conv_f32_i128 compiler-builtins + time: [1.1774 µs 1.1829 µs 1.1887 µs] +Found 11 outliers among 100 measurements (11.00%) + 1 (1.00%) low severe + 7 (7.00%) low mild + 1 (1.00%) high mild + 2 (2.00%) high severe + +conv_f32_i128 system time: [1.1785 µs 1.1853 µs 1.1941 µs] +Found 7 outliers among 100 measurements (7.00%) + 2 (2.00%) high mild + 5 (5.00%) high severe + +div_f32 compiler-builtins + time: [38.852 µs 39.011 µs 39.178 µs] +Found 3 outliers among 100 measurements (3.00%) + 3 (3.00%) high mild + +div_f32 system time: [41.846 µs 41.920 µs 42.005 µs] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe + +div_f32 assembly (aarch64 unix) + time: [8.1309 µs 8.1627 µs 8.2005 µs] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high mild + +div_f64 compiler-builtins + time: [50.369 µs 50.605 µs 50.857 µs] +Found 15 outliers among 100 measurements (15.00%) + 11 (11.00%) high mild + 4 (4.00%) high severe + +div_f64 system time: [53.506 µs 53.582 µs 53.676 µs] +Found 8 outliers among 100 measurements (8.00%) + 4 (4.00%) high mild + 4 (4.00%) high severe + +div_f64 assembly (aarch64 unix) + time: [8.0695 µs 8.0807 µs 8.0948 µs] +Found 4 outliers among 100 measurements (4.00%) + 2 (2.00%) high mild + 2 (2.00%) high severe + diff --git a/library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt b/library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt new file mode 100644 index 00000000000..131e7a85a0b --- /dev/null +++ b/library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt @@ -0,0 +1,699 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +add_f32/compiler-builtins + time: [36.813 µs 37.048 µs 37.303 µs] +Found 5 outliers among 100 measurements (5.00%) + 5 (5.00%) high mild +add_f32/system time: [39.103 µs 39.142 µs 39.189 µs] +Found 8 outliers among 100 measurements (8.00%) + 2 (2.00%) high mild + 6 (6.00%) high severe +add_f32/assembly (aarch64 unix) + time: [8.3786 µs 8.4680 µs 8.5570 µs] + +add_f64/compiler-builtins + time: [35.784 µs 35.819 µs 35.863 µs] +Found 4 outliers among 100 measurements (4.00%) + 1 (1.00%) high mild + 3 (3.00%) high severe +add_f64/system time: [39.634 µs 39.689 µs 39.746 µs] +Found 16 outliers among 100 measurements (16.00%) + 4 (4.00%) high mild + 12 (12.00%) high severe +add_f64/assembly (aarch64 unix) + time: [8.0533 µs 8.0599 µs 8.0670 µs] +Found 14 outliers among 100 measurements (14.00%) + 6 (6.00%) high mild + 8 (8.00%) high severe + +add_f128/compiler-builtins + time: [41.830 µs 41.920 µs 42.005 µs] + +cmp_f32_gt/compiler-builtins + time: [13.405 µs 13.411 µs 13.418 µs] +Found 18 outliers among 100 measurements (18.00%) + 4 (4.00%) high mild + 14 (14.00%) high severe +cmp_f32_gt/system time: [12.348 µs 12.355 µs 12.363 µs] +Found 12 outliers among 100 measurements (12.00%) + 2 (2.00%) high mild + 10 (10.00%) high severe +cmp_f32_gt/assembly (aarch64 unix) + time: [8.1233 µs 8.1625 µs 8.2072 µs] +Found 12 outliers among 100 measurements (12.00%) + 7 (7.00%) high mild + 5 (5.00%) high severe + +cmp_f32_unord/compiler-builtins + time: [11.349 µs 11.467 µs 11.584 µs] +cmp_f32_unord/system time: [8.0714 µs 8.0792 µs 8.0890 µs] +Found 16 outliers among 100 measurements (16.00%) + 4 (4.00%) high mild + 12 (12.00%) high severe +cmp_f32_unord/assembly (aarch64 unix) + time: [8.1121 µs 8.1705 µs 8.2325 µs] +Found 20 outliers among 100 measurements (20.00%) + 3 (3.00%) high mild + 17 (17.00%) high severe + +cmp_f64_gt/compiler-builtins + time: [13.749 µs 13.837 µs 13.934 µs] +Found 20 outliers among 100 measurements (20.00%) + 9 (9.00%) low mild + 7 (7.00%) high mild + 4 (4.00%) high severe +cmp_f64_gt/system time: [12.475 µs 12.515 µs 12.565 µs] +Found 4 outliers among 100 measurements (4.00%) + 4 (4.00%) high mild +cmp_f64_gt/assembly (aarch64 unix) + time: [8.0456 µs 8.0540 µs 8.0653 µs] +Found 12 outliers among 100 measurements (12.00%) + 3 (3.00%) high mild + 9 (9.00%) high severe + +cmp_f64_unord/compiler-builtins + time: [10.723 µs 10.730 µs 10.739 µs] +Found 15 outliers among 100 measurements (15.00%) + 5 (5.00%) high mild + 10 (10.00%) high severe +cmp_f64_unord/system time: [8.0944 µs 8.1296 µs 8.1683 µs] +Found 17 outliers among 100 measurements (17.00%) + 4 (4.00%) high mild + 13 (13.00%) high severe +cmp_f64_unord/assembly (aarch64 unix) + time: [8.1042 µs 8.1337 µs 8.1662 µs] +Found 3 outliers among 100 measurements (3.00%) + 3 (3.00%) high mild + +cmp_f128_gt/compiler-builtins + time: [20.508 µs 20.558 µs 20.615 µs] +Found 8 outliers among 100 measurements (8.00%) + 2 (2.00%) high mild + 6 (6.00%) high severe + +cmp_f128_unord/compiler-builtins + time: [13.332 µs 13.346 µs 13.360 µs] +Found 4 outliers among 100 measurements (4.00%) + 2 (2.00%) high mild + 2 (2.00%) high severe + +conv_u32_f32/compiler-builtins + time: [621.20 ns 621.89 ns 622.65 ns] +Found 7 outliers among 100 measurements (7.00%) + 4 (4.00%) high mild + 3 (3.00%) high severe +conv_u32_f32/system time: [621.44 ns 622.08 ns 622.74 ns] +Found 4 outliers among 100 measurements (4.00%) + 3 (3.00%) high mild + 1 (1.00%) high severe +conv_u32_f32/assembly (aarch64 unix) + time: [465.96 ns 466.65 ns 467.45 ns] +Found 13 outliers among 100 measurements (13.00%) + 3 (3.00%) high mild + 10 (10.00%) high severe + +conv_u32_f64/compiler-builtins + time: [619.71 ns 620.51 ns 621.52 ns] +Found 5 outliers among 100 measurements (5.00%) + 4 (4.00%) high mild + 1 (1.00%) high severe +conv_u32_f64/system time: [466.60 ns 467.14 ns 467.77 ns] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high mild +conv_u32_f64/assembly (aarch64 unix) + time: [464.02 ns 464.32 ns 464.69 ns] +Found 2 outliers among 100 measurements (2.00%) + 1 (1.00%) high mild + 1 (1.00%) high severe + +conv_u64_f32/compiler-builtins + time: [851.24 ns 852.98 ns 854.77 ns] +Found 5 outliers among 100 measurements (5.00%) + 5 (5.00%) high mild +conv_u64_f32/system time: [724.35 ns 729.43 ns 735.07 ns] +Found 4 outliers among 100 measurements (4.00%) + 4 (4.00%) high mild +conv_u64_f32/assembly (aarch64 unix) + time: [513.30 ns 514.64 ns 516.16 ns] +Found 8 outliers among 100 measurements (8.00%) + 8 (8.00%) high mild + +conv_u64_f64/compiler-builtins + time: [850.72 ns 853.26 ns 856.54 ns] +Found 15 outliers among 100 measurements (15.00%) + 2 (2.00%) high mild + 13 (13.00%) high severe +conv_u64_f64/system time: [681.43 ns 682.54 ns 683.79 ns] +Found 4 outliers among 100 measurements (4.00%) + 3 (3.00%) high mild + 1 (1.00%) high severe +conv_u64_f64/assembly (aarch64 unix) + time: [511.37 ns 511.71 ns 512.02 ns] +Found 1 outliers among 100 measurements (1.00%) + 1 (1.00%) high severe + +conv_u128_f32/compiler-builtins + time: [1.1395 µs 1.1409 µs 1.1424 µs] +Found 10 outliers among 100 measurements (10.00%) + 6 (6.00%) high mild + 4 (4.00%) high severe +conv_u128_f32/system time: [1.4348 µs 1.4369 µs 1.4390 µs] +Found 5 outliers among 100 measurements (5.00%) + 4 (4.00%) high mild + 1 (1.00%) high severe + +conv_u128_f64/compiler-builtins + time: [1.0148 µs 1.0157 µs 1.0167 µs] +Found 4 outliers among 100 measurements (4.00%) + 3 (3.00%) high mild + 1 (1.00%) high severe +conv_u128_f64/system time: [1.3404 µs 1.3423 µs 1.3442 µs] +Found 8 outliers among 100 measurements (8.00%) + 7 (7.00%) high mild + 1 (1.00%) high severe + +conv_i32_f32/compiler-builtins + time: [902.89 ns 903.81 ns 904.84 ns] +Found 7 outliers among 100 measurements (7.00%) + 4 (4.00%) high mild + 3 (3.00%) high severe +conv_i32_f32/system time: [942.62 ns 949.04 ns 955.77 ns] +Found 4 outliers among 100 measurements (4.00%) + 3 (3.00%) high mild + 1 (1.00%) high severe +conv_i32_f32/assembly (aarch64 unix) + time: [466.06 ns 466.60 ns 467.27 ns] +Found 1 outliers among 100 measurements (1.00%) + 1 (1.00%) high severe + +conv_i32_f64/compiler-builtins + time: [618.98 ns 619.24 ns 619.55 ns] +Found 17 outliers among 100 measurements (17.00%) + 1 (1.00%) low mild + 3 (3.00%) high mild + 13 (13.00%) high severe +conv_i32_f64/system time: [622.18 ns 623.41 ns 624.85 ns] +Found 8 outliers among 100 measurements (8.00%) + 5 (5.00%) high mild + 3 (3.00%) high severe +conv_i32_f64/assembly (aarch64 unix) + time: [466.26 ns 466.76 ns 467.35 ns] +Found 9 outliers among 100 measurements (9.00%) + 5 (5.00%) high mild + 4 (4.00%) high severe + +conv_i64_f32/compiler-builtins + time: [850.11 ns 850.45 ns 850.88 ns] +Found 15 outliers among 100 measurements (15.00%) + 1 (1.00%) low severe + 1 (1.00%) low mild + 3 (3.00%) high mild + 10 (10.00%) high severe +conv_i64_f32/system time: [908.36 ns 908.70 ns 909.10 ns] +Found 12 outliers among 100 measurements (12.00%) + 3 (3.00%) high mild + 9 (9.00%) high severe +conv_i64_f32/assembly (aarch64 unix) + time: [513.56 ns 514.44 ns 515.38 ns] +Found 8 outliers among 100 measurements (8.00%) + 8 (8.00%) high mild + +conv_i64_f64/compiler-builtins + time: [935.39 ns 935.78 ns 936.26 ns] +Found 13 outliers among 100 measurements (13.00%) + 5 (5.00%) high mild + 8 (8.00%) high severe +conv_i64_f64/system time: [946.56 ns 947.33 ns 948.20 ns] +Found 8 outliers among 100 measurements (8.00%) + 6 (6.00%) high mild + 2 (2.00%) high severe +conv_i64_f64/assembly (aarch64 unix) + time: [511.55 ns 512.03 ns 512.56 ns] +Found 21 outliers among 100 measurements (21.00%) + 4 (4.00%) high mild + 17 (17.00%) high severe + +conv_i128_f32/compiler-builtins + time: [1.4206 µs 1.4218 µs 1.4232 µs] +Found 10 outliers among 100 measurements (10.00%) + 5 (5.00%) high mild + 5 (5.00%) high severe +conv_i128_f32/system time: [1.6863 µs 1.6891 µs 1.6922 µs] +Found 10 outliers among 100 measurements (10.00%) + 9 (9.00%) high mild + 1 (1.00%) high severe + +conv_i128_f64/compiler-builtins + time: [1.3110 µs 1.3122 µs 1.3136 µs] +Found 4 outliers among 100 measurements (4.00%) + 2 (2.00%) high mild + 2 (2.00%) high severe +conv_i128_f64/system time: [1.6022 µs 1.6048 µs 1.6090 µs] +Found 5 outliers among 100 measurements (5.00%) + 3 (3.00%) high mild + 2 (2.00%) high severe + +conv_f64_u32/compiler-builtins + time: [798.65 ns 799.42 ns 800.39 ns] +Found 15 outliers among 100 measurements (15.00%) + 6 (6.00%) high mild + 9 (9.00%) high severe +conv_f64_u32/system time: [639.48 ns 639.88 ns 640.40 ns] +Found 16 outliers among 100 measurements (16.00%) + 1 (1.00%) low mild + 5 (5.00%) high mild + 10 (10.00%) high severe +conv_f64_u32/assembly (aarch64 unix) + time: [480.78 ns 481.35 ns 482.17 ns] +Found 7 outliers among 100 measurements (7.00%) + 5 (5.00%) high mild + 2 (2.00%) high severe + +conv_f64_u64/compiler-builtins + time: [799.56 ns 800.54 ns 801.89 ns] +Found 4 outliers among 100 measurements (4.00%) + 2 (2.00%) high mild + 2 (2.00%) high severe +conv_f64_u64/system time: [640.72 ns 641.24 ns 641.81 ns] +Found 5 outliers among 100 measurements (5.00%) + 3 (3.00%) high mild + 2 (2.00%) high severe +conv_f64_u64/assembly (aarch64 unix) + time: [481.54 ns 482.48 ns 483.53 ns] +Found 6 outliers among 100 measurements (6.00%) + 1 (1.00%) low severe + 1 (1.00%) low mild + 3 (3.00%) high mild + 1 (1.00%) high severe + +conv_f64_u128/compiler-builtins + time: [1.0510 µs 1.0515 µs 1.0520 µs] +Found 13 outliers among 100 measurements (13.00%) + 1 (1.00%) low mild + 2 (2.00%) high mild + 10 (10.00%) high severe +conv_f64_u128/system time: [818.45 ns 819.23 ns 820.15 ns] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high mild + +conv_f64_i32/compiler-builtins + time: [800.56 ns 801.31 ns 802.21 ns] +Found 5 outliers among 100 measurements (5.00%) + 3 (3.00%) high mild + 2 (2.00%) high severe +conv_f64_i32/system time: [765.62 ns 766.15 ns 766.80 ns] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe +conv_f64_i32/assembly (aarch64 unix) + time: [471.65 ns 472.77 ns 473.89 ns] +Found 10 outliers among 100 measurements (10.00%) + 1 (1.00%) low mild + 8 (8.00%) high mild + 1 (1.00%) high severe + +conv_f64_i64/compiler-builtins + time: [801.00 ns 804.55 ns 808.72 ns] +Found 18 outliers among 100 measurements (18.00%) + 6 (6.00%) high mild + 12 (12.00%) high severe +conv_f64_i64/system time: [770.28 ns 772.47 ns 775.21 ns] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high mild +conv_f64_i64/assembly (aarch64 unix) + time: [491.56 ns 494.96 ns 499.19 ns] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe + +conv_f64_i128/compiler-builtins + time: [1.0637 µs 1.0704 µs 1.0762 µs] +Found 5 outliers among 100 measurements (5.00%) + 5 (5.00%) high mild +conv_f64_i128/system time: [1.0022 µs 1.0027 µs 1.0033 µs] +Found 4 outliers among 100 measurements (4.00%) + 1 (1.00%) low severe + 3 (3.00%) high severe + +conv_f32_u32/compiler-builtins + time: [644.56 ns 647.01 ns 649.95 ns] +Found 15 outliers among 100 measurements (15.00%) + 13 (13.00%) high mild + 2 (2.00%) high severe +conv_f32_u32/system time: [648.12 ns 651.20 ns 654.54 ns] +Found 9 outliers among 100 measurements (9.00%) + 7 (7.00%) high mild + 2 (2.00%) high severe +conv_f32_u32/assembly (aarch64 unix) + time: [481.02 ns 482.71 ns 484.60 ns] +Found 12 outliers among 100 measurements (12.00%) + 1 (1.00%) low mild + 10 (10.00%) high mild + 1 (1.00%) high severe + +conv_f32_u64/compiler-builtins + time: [644.14 ns 646.61 ns 649.53 ns] +Found 11 outliers among 100 measurements (11.00%) + 6 (6.00%) high mild + 5 (5.00%) high severe +conv_f32_u64/system time: [646.21 ns 650.17 ns 654.55 ns] +Found 3 outliers among 100 measurements (3.00%) + 3 (3.00%) high mild +conv_f32_u64/assembly (aarch64 unix) + time: [473.36 ns 474.60 ns 476.00 ns] +Found 9 outliers among 100 measurements (9.00%) + 2 (2.00%) low mild + 5 (5.00%) high mild + 2 (2.00%) high severe + +conv_f32_u128/compiler-builtins + time: [1.0820 µs 1.0828 µs 1.0839 µs] +Found 2 outliers among 100 measurements (2.00%) + 1 (1.00%) high mild + 1 (1.00%) high severe +conv_f32_u128/system time: [1.0003 µs 1.0042 µs 1.0076 µs] +Found 21 outliers among 100 measurements (21.00%) + 1 (1.00%) low mild + 3 (3.00%) high mild + 17 (17.00%) high severe + +conv_f32_i32/compiler-builtins + time: [801.13 ns 801.82 ns 802.53 ns] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high severe +conv_f32_i32/system time: [745.17 ns 745.97 ns 746.78 ns] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high severe +conv_f32_i32/assembly (aarch64 unix) + time: [469.87 ns 470.65 ns 471.57 ns] +Found 1 outliers among 100 measurements (1.00%) + 1 (1.00%) high mild + +conv_f32_i64/compiler-builtins + time: [799.44 ns 799.94 ns 800.59 ns] +Found 4 outliers among 100 measurements (4.00%) + 1 (1.00%) high mild + 3 (3.00%) high severe +conv_f32_i64/system time: [744.81 ns 745.17 ns 745.62 ns] +Found 14 outliers among 100 measurements (14.00%) + 5 (5.00%) high mild + 9 (9.00%) high severe +conv_f32_i64/assembly (aarch64 unix) + time: [465.06 ns 466.01 ns 467.12 ns] +Found 13 outliers among 100 measurements (13.00%) + 2 (2.00%) low severe + 5 (5.00%) high mild + 6 (6.00%) high severe + +conv_f32_i128/compiler-builtins + time: [1.1390 µs 1.1515 µs 1.1637 µs] +conv_f32_i128/system time: [1.1315 µs 1.1330 µs 1.1347 µs] +Found 6 outliers among 100 measurements (6.00%) + 3 (3.00%) low mild + 2 (2.00%) high mild + 1 (1.00%) high severe + +div_f32/compiler-builtins + time: [39.408 µs 39.676 µs 39.969 µs] +Found 5 outliers among 100 measurements (5.00%) + 5 (5.00%) high mild +div_f32/system time: [42.108 µs 42.248 µs 42.528 µs] +Found 11 outliers among 100 measurements (11.00%) + 4 (4.00%) high mild + 7 (7.00%) high severe +div_f32/assembly (aarch64 unix) + time: [8.0724 µs 8.0794 µs 8.0870 µs] +Found 7 outliers among 100 measurements (7.00%) + 5 (5.00%) high mild + 2 (2.00%) high severe + +div_f64/compiler-builtins + time: [49.992 µs 50.014 µs 50.040 µs] +Found 5 outliers among 100 measurements (5.00%) + 5 (5.00%) high severe +div_f64/system time: [53.577 µs 53.651 µs 53.743 µs] +Found 6 outliers among 100 measurements (6.00%) + 4 (4.00%) high mild + 2 (2.00%) high severe +div_f64/assembly (aarch64 unix) + time: [8.0976 µs 8.1064 µs 8.1158 µs] +Found 6 outliers among 100 measurements (6.00%) + 3 (3.00%) high mild + 3 (3.00%) high severe + +extend_f16_f32/compiler-builtins + time: [804.09 ns 805.38 ns 807.09 ns] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe +extend_f16_f32/system time: [641.07 ns 641.76 ns 642.60 ns] +Found 12 outliers among 100 measurements (12.00%) + 6 (6.00%) high mild + 6 (6.00%) high severe +extend_f16_f32/assembly (aarch64 unix) + time: [456.69 ns 457.14 ns 457.68 ns] +Found 8 outliers among 100 measurements (8.00%) + 4 (4.00%) low mild + 2 (2.00%) high mild + 2 (2.00%) high severe + +extend_f16_f128/compiler-builtins + time: [1.1025 µs 1.1035 µs 1.1045 µs] +Found 2 outliers among 100 measurements (2.00%) + 1 (1.00%) high mild + 1 (1.00%) high severe + +extend_f32_f64/compiler-builtins + time: [799.30 ns 799.68 ns 800.16 ns] +Found 13 outliers among 100 measurements (13.00%) + 3 (3.00%) high mild + 10 (10.00%) high severe +extend_f32_f64/system time: [992.48 ns 993.27 ns 994.32 ns] +Found 15 outliers among 100 measurements (15.00%) + 3 (3.00%) high mild + 12 (12.00%) high severe +extend_f32_f64/assembly (aarch64 unix) + time: [457.65 ns 460.39 ns 463.78 ns] + +extend_f32_f128/compiler-builtins + time: [1.0295 µs 1.0311 µs 1.0327 µs] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) low mild + 1 (1.00%) high mild + +extend_f64_f128/compiler-builtins + time: [1.0400 µs 1.0412 µs 1.0426 µs] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high mild + +mul_f32/compiler-builtins + time: [25.604 µs 25.705 µs 25.818 µs] +Found 23 outliers among 100 measurements (23.00%) + 17 (17.00%) low severe + 3 (3.00%) high mild + 3 (3.00%) high severe +mul_f32/system time: [29.914 µs 29.977 µs 30.043 µs] +Found 5 outliers among 100 measurements (5.00%) + 5 (5.00%) high mild +mul_f32/assembly (aarch64 unix) + time: [8.1384 µs 8.1964 µs 8.2603 µs] +Found 13 outliers among 100 measurements (13.00%) + 3 (3.00%) high mild + 10 (10.00%) high severe + +mul_f64/compiler-builtins + time: [25.596 µs 25.615 µs 25.637 µs] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe +mul_f64/system time: [30.931 µs 30.963 µs 31.002 µs] +Found 3 outliers among 100 measurements (3.00%) + 3 (3.00%) high mild +mul_f64/assembly (aarch64 unix) + time: [8.0589 µs 8.0638 µs 8.0695 µs] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe + +mul_f128/compiler-builtins + time: [54.242 µs 54.306 µs 54.374 µs] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe + +powi_f32/compiler-builtins + time: [129.91 µs 130.09 µs 130.24 µs] +powi_f32/system time: [126.97 µs 127.34 µs 127.82 µs] +Found 4 outliers among 100 measurements (4.00%) + 3 (3.00%) high mild + 1 (1.00%) high severe + +powi_f64/compiler-builtins + time: [130.08 µs 130.81 µs 131.46 µs] +Found 13 outliers among 100 measurements (13.00%) + 13 (13.00%) high mild +powi_f64/system time: [128.51 µs 128.68 µs 128.88 µs] +Found 21 outliers among 100 measurements (21.00%) + 4 (4.00%) high mild + 17 (17.00%) high severe + +sub_f32/compiler-builtins + time: [37.861 µs 38.012 µs 38.158 µs] +Found 26 outliers among 100 measurements (26.00%) + 18 (18.00%) low mild + 7 (7.00%) high mild + 1 (1.00%) high severe +sub_f32/system time: [39.586 µs 39.628 µs 39.673 µs] +Found 2 outliers among 100 measurements (2.00%) + 1 (1.00%) high mild + 1 (1.00%) high severe +sub_f32/assembly (aarch64 unix) + time: [8.0976 µs 8.1584 µs 8.2208 µs] +Found 6 outliers among 100 measurements (6.00%) + 6 (6.00%) high mild + +sub_f64/compiler-builtins + time: [37.755 µs 37.838 µs 37.921 µs] +Found 25 outliers among 100 measurements (25.00%) + 7 (7.00%) low severe + 3 (3.00%) low mild + 4 (4.00%) high mild + 11 (11.00%) high severe +sub_f64/system time: [39.979 µs 40.019 µs 40.064 µs] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe +sub_f64/assembly (aarch64 unix) + time: [8.0669 µs 8.0733 µs 8.0801 µs] +Found 7 outliers among 100 measurements (7.00%) + 3 (3.00%) high mild + 4 (4.00%) high severe + +sub_f128/compiler-builtins + time: [68.618 µs 68.899 µs 69.293 µs] +Found 11 outliers among 100 measurements (11.00%) + 2 (2.00%) high mild + 9 (9.00%) high severe + +trunc_f32_f16/compiler-builtins + time: [1.3343 µs 1.3468 µs 1.3608 µs] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe +trunc_f32_f16/system time: [1.2687 µs 1.2714 µs 1.2738 µs] +trunc_f32_f16/assembly (aarch64 unix) + time: [470.06 ns 472.96 ns 475.30 ns] + +trunc_f64_f16/compiler-builtins + time: [1.2729 µs 1.2738 µs 1.2749 µs] +Found 7 outliers among 100 measurements (7.00%) + 2 (2.00%) high mild + 5 (5.00%) high severe +trunc_f64_f16/assembly (aarch64 unix) + time: [455.91 ns 456.61 ns 457.33 ns] +Found 12 outliers among 100 measurements (12.00%) + 1 (1.00%) low severe + 2 (2.00%) low mild + 6 (6.00%) high mild + 3 (3.00%) high severe + +trunc_f64_f32/compiler-builtins + time: [1.2240 µs 1.2325 µs 1.2410 µs] +Found 17 outliers among 100 measurements (17.00%) + 4 (4.00%) low mild + 2 (2.00%) high mild + 11 (11.00%) high severe +trunc_f64_f32/system time: [1.2784 µs 1.2835 µs 1.2884 µs] +Found 10 outliers among 100 measurements (10.00%) + 6 (6.00%) low severe + 1 (1.00%) low mild + 2 (2.00%) high mild + 1 (1.00%) high severe +trunc_f64_f32/assembly (aarch64 unix) + time: [455.64 ns 456.08 ns 456.58 ns] +Found 18 outliers among 100 measurements (18.00%) + 3 (3.00%) low severe + 4 (4.00%) low mild + 8 (8.00%) high mild + 3 (3.00%) high severe + +trunc_f128_f16/compiler-builtins + time: [1.2563 µs 1.2666 µs 1.2776 µs] +Found 3 outliers among 100 measurements (3.00%) + 3 (3.00%) high mild + +trunc_f128_f32/compiler-builtins + time: [1.2459 µs 1.2482 µs 1.2507 µs] +Found 6 outliers among 100 measurements (6.00%) + 2 (2.00%) low mild + 2 (2.00%) high mild + 2 (2.00%) high severe + +trunc_f128_f64/compiler-builtins + time: [1.2821 µs 1.3047 µs 1.3452 µs] +Found 8 outliers among 100 measurements (8.00%) + 4 (4.00%) low severe + 1 (1.00%) low mild + 2 (2.00%) high mild + 1 (1.00%) high severe + + +running 52 tests +test memcmp_builtin_1048576 ... bench: 20,975.52 ns/iter (+/- 239.69) = 49991 MB/s +test memcmp_builtin_16 ... bench: 1.60 ns/iter (+/- 0.05) = 16000 MB/s +test memcmp_builtin_32 ... bench: 1.61 ns/iter (+/- 0.03) = 32000 MB/s +test memcmp_builtin_4096 ... bench: 95.84 ns/iter (+/- 2.82) = 43115 MB/s +test memcmp_builtin_64 ... bench: 2.39 ns/iter (+/- 0.09) = 32000 MB/s +test memcmp_builtin_8 ... bench: 1.60 ns/iter (+/- 0.04) = 8000 MB/s +test memcmp_builtin_unaligned_1048575 ... bench: 22,060.00 ns/iter (+/- 873.55) = 47532 MB/s +test memcmp_builtin_unaligned_15 ... bench: 3.19 ns/iter (+/- 0.02) = 5333 MB/s +test memcmp_builtin_unaligned_31 ... bench: 1.61 ns/iter (+/- 0.01) = 32000 MB/s +test memcmp_builtin_unaligned_4095 ... bench: 96.63 ns/iter (+/- 4.58) = 42666 MB/s +test memcmp_builtin_unaligned_63 ... bench: 2.40 ns/iter (+/- 0.11) = 32000 MB/s +test memcmp_builtin_unaligned_7 ... bench: 3.37 ns/iter (+/- 0.05) = 2666 MB/s +test memcmp_rust_1048576 ... bench: 309,647.23 ns/iter (+/- 6,077.35) = 3386 MB/s +test memcmp_rust_16 ... bench: 5.66 ns/iter (+/- 0.30) = 3200 MB/s +test memcmp_rust_32 ... bench: 10.47 ns/iter (+/- 0.14) = 3200 MB/s +test memcmp_rust_4096 ... bench: 1,124.34 ns/iter (+/- 36.92) = 3644 MB/s +test memcmp_rust_64 ... bench: 19.90 ns/iter (+/- 0.36) = 3368 MB/s +test memcmp_rust_8 ... bench: 3.46 ns/iter (+/- 0.11) = 2666 MB/s +test memcmp_rust_unaligned_1048575 ... bench: 308,613.87 ns/iter (+/- 6,613.18) = 3397 MB/s +test memcmp_rust_unaligned_15 ... bench: 5.35 ns/iter (+/- 0.05) = 3200 MB/s +test memcmp_rust_unaligned_31 ... bench: 9.94 ns/iter (+/- 0.06) = 3555 MB/s +test memcmp_rust_unaligned_4095 ... bench: 1,120.06 ns/iter (+/- 5.03) = 3657 MB/s +test memcmp_rust_unaligned_63 ... bench: 19.64 ns/iter (+/- 0.82) = 3368 MB/s +test memcmp_rust_unaligned_7 ... bench: 3.22 ns/iter (+/- 0.10) = 2666 MB/s +test memcpy_builtin_1048576 ... bench: 12,538.05 ns/iter (+/- 354.79) = 83631 MB/s +test memcpy_builtin_1048576_misalign ... bench: 30,092.56 ns/iter (+/- 8,064.04) = 34845 MB/s +test memcpy_builtin_1048576_offset ... bench: 12,538.36 ns/iter (+/- 359.04) = 83631 MB/s +test memcpy_builtin_4096 ... bench: 44.24 ns/iter (+/- 6.80) = 93090 MB/s +test memcpy_builtin_4096_misalign ... bench: 45.34 ns/iter (+/- 2.13) = 91022 MB/s +test memcpy_builtin_4096_offset ... bench: 44.71 ns/iter (+/- 0.61) = 93090 MB/s +test memcpy_rust_1048576 ... bench: 17,943.33 ns/iter (+/- 243.18) = 58439 MB/s +test memcpy_rust_1048576_misalign ... bench: 15,004.68 ns/iter (+/- 3,978.65) = 69886 MB/s +test memcpy_rust_1048576_offset ... bench: 14,722.06 ns/iter (+/- 479.54) = 71225 MB/s +test memcpy_rust_4096 ... bench: 44.91 ns/iter (+/- 4.62) = 93090 MB/s +test memcpy_rust_4096_misalign ... bench: 76.21 ns/iter (+/- 8.21) = 53894 MB/s +test memcpy_rust_4096_offset ... bench: 76.27 ns/iter (+/- 4.69) = 53894 MB/s +test memmove_builtin_1048576 ... bench: 18,644.50 ns/iter (+/- 379.84) = 56242 MB/s +test memmove_builtin_1048576_misalign ... bench: 18,947.70 ns/iter (+/- 1,226.26) = 55342 MB/s +test memmove_builtin_4096 ... bench: 44.21 ns/iter (+/- 0.79) = 93090 MB/s +test memmove_builtin_4096_misalign ... bench: 47.21 ns/iter (+/- 3.12) = 87148 MB/s +test memmove_rust_1048576 ... bench: 34,813.33 ns/iter (+/- 3,637.47) = 30120 MB/s +test memmove_rust_1048576_misalign ... bench: 35,067.19 ns/iter (+/- 1,699.63) = 29902 MB/s +test memmove_rust_4096 ... bench: 148.69 ns/iter (+/- 1.31) = 27675 MB/s +test memmove_rust_4096_misalign ... bench: 153.81 ns/iter (+/- 1.71) = 26771 MB/s +test memset_builtin_1048576 ... bench: 15,704.12 ns/iter (+/- 12,113.86) = 66771 MB/s +test memset_builtin_1048576_offset ... bench: 17,894.23 ns/iter (+/- 175.12) = 58599 MB/s +test memset_builtin_4096 ... bench: 39.95 ns/iter (+/- 0.19) = 105025 MB/s +test memset_builtin_4096_offset ... bench: 40.48 ns/iter (+/- 3.11) = 102400 MB/s +test memset_rust_1048576 ... bench: 10,600.66 ns/iter (+/- 1,559.93) = 98922 MB/s +test memset_rust_1048576_offset ... bench: 14,810.85 ns/iter (+/- 575.27) = 70801 MB/s +test memset_rust_4096 ... bench: 37.91 ns/iter (+/- 2.77) = 110702 MB/s +test memset_rust_4096_offset ... bench: 59.99 ns/iter (+/- 10.45) = 69423 MB/s + +test result: ok. 0 passed; 0 failed; 0 ignored; 52 measured; 0 filtered out; finished in 97.74s + diff --git a/library/compiler-builtins/testcrate/benches/float_add.rs b/library/compiler-builtins/testcrate/benches/float_add.rs new file mode 100644 index 00000000000..eef1ecc57c1 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_add.rs @@ -0,0 +1,81 @@ +#![feature(f128)] + +use compiler_builtins::float::add; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +float_bench! { + name: add_f32, + sig: (a: f32, b: f32) -> f32, + crate_fn: add::__addsf3, + sys_fn: __addsf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "addss {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fadd {a:s}, {a:s}, {b:s}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: add_f64, + sig: (a: f64, b: f64) -> f64, + crate_fn: add::__adddf3, + sys_fn: __adddf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "addsd {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fadd {a:d}, {a:d}, {b:d}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: add_f128, + sig: (a: f128, b: f128) -> f128, + crate_fn: add::__addtf3, + crate_fn_ppc: add::__addkf3, + sys_fn: __addtf3, + sys_fn_ppc: __addkf3, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +criterion_group!(float_add, add_f32, add_f64, add_f128); +criterion_main!(float_add); diff --git a/library/compiler-builtins/testcrate/benches/float_cmp.rs b/library/compiler-builtins/testcrate/benches/float_cmp.rs new file mode 100644 index 00000000000..641eb0ac5d4 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_cmp.rs @@ -0,0 +1,202 @@ +#![feature(f128)] + +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +use compiler_builtins::float::cmp; + +/// `gt` symbols are allowed to return differing results, they just get compared +/// to 0. +fn gt_res_eq(a: i32, b: i32) -> bool { + let a_lt_0 = a <= 0; + let b_lt_0 = b <= 0; + (a_lt_0 && b_lt_0) || (!a_lt_0 && !b_lt_0) +} + +float_bench! { + name: cmp_f32_gt, + sig: (a: f32, b: f32) -> i32, + crate_fn: cmp::__gtsf2, + sys_fn: __gtsf2, + sys_available: all(), + output_eq: gt_res_eq, + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: i32; + asm!( + "xor {ret:e}, {ret:e}", + "ucomiss {a}, {b}", + "seta {ret:l}", + a = in(xmm_reg) a, + b = in(xmm_reg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcmp {a:s}, {b:s}", + "cset {ret:w}, gt", + a = in(vreg) a, + b = in(vreg) b, + ret = out(reg) ret, + options(nomem,nostack), + ); + + ret + }; + ], +} + +float_bench! { + name: cmp_f32_unord, + sig: (a: f32, b: f32) -> i32, + crate_fn: cmp::__unordsf2, + sys_fn: __unordsf2, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: i32; + asm!( + "xor {ret:e}, {ret:e}", + "ucomiss {a}, {b}", + "setp {ret:l}", + a = in(xmm_reg) a, + b = in(xmm_reg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcmp {a:s}, {b:s}", + "cset {ret:w}, vs", + a = in(vreg) a, + b = in(vreg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + ], +} + +float_bench! { + name: cmp_f64_gt, + sig: (a: f64, b: f64) -> i32, + crate_fn: cmp::__gtdf2, + sys_fn: __gtdf2, + sys_available: all(), + output_eq: gt_res_eq, + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: i32; + asm!( + "xor {ret:e}, {ret:e}", + "ucomisd {a}, {b}", + "seta {ret:l}", + a = in(xmm_reg) a, + b = in(xmm_reg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcmp {a:d}, {b:d}", + "cset {ret:w}, gt", + a = in(vreg) a, + b = in(vreg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + ], +} + +float_bench! { + name: cmp_f64_unord, + sig: (a: f64, b: f64) -> i32, + crate_fn: cmp::__unorddf2, + sys_fn: __unorddf2, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: i32; + asm!( + "xor {ret:e}, {ret:e}", + "ucomisd {a}, {b}", + "setp {ret:l}", + a = in(xmm_reg) a, + b = in(xmm_reg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcmp {a:d}, {b:d}", + "cset {ret:w}, vs", + a = in(vreg) a, + b = in(vreg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + ], +} + +float_bench! { + name: cmp_f128_gt, + sig: (a: f128, b: f128) -> i32, + crate_fn: cmp::__gttf2, + crate_fn_ppc: cmp::__gtkf2, + sys_fn: __gttf2, + sys_fn_ppc: __gtkf2, + sys_available: not(feature = "no-sys-f128"), + output_eq: gt_res_eq, + asm: [] +} + +float_bench! { + name: cmp_f128_unord, + sig: (a: f128, b: f128) -> i32, + crate_fn: cmp::__unordtf2, + crate_fn_ppc: cmp::__unordkf2, + sys_fn: __unordtf2, + sys_fn_ppc: __unordkf2, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +criterion_group!( + float_cmp, + cmp_f32_gt, + cmp_f32_unord, + cmp_f64_gt, + cmp_f64_unord, + cmp_f128_gt, + cmp_f128_unord +); +criterion_main!(float_cmp); diff --git a/library/compiler-builtins/testcrate/benches/float_conv.rs b/library/compiler-builtins/testcrate/benches/float_conv.rs new file mode 100644 index 00000000000..bbd3a06851d --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_conv.rs @@ -0,0 +1,547 @@ +#![feature(f128)] +#![allow(improper_ctypes)] + +use compiler_builtins::float::conv; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +/* unsigned int -> float */ + +float_bench! { + name: conv_u32_f32, + sig: (a: u32) -> f32, + crate_fn: conv::__floatunsisf, + sys_fn: __floatunsisf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f32; + asm!( + "mov {tmp:e}, {a:e}", + "cvtsi2ss {ret}, {tmp}", + a = in(reg) a, + tmp = out(reg) _, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "ucvtf {ret:s}, {a:w}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_u32_f64, + sig: (a: u32) -> f64, + crate_fn: conv::__floatunsidf, + sys_fn: __floatunsidf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f64; + asm!( + "mov {tmp:e}, {a:e}", + "cvtsi2sd {ret}, {tmp}", + a = in(reg) a, + tmp = out(reg) _, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "ucvtf {ret:d}, {a:w}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_u64_f32, + sig: (a: u64) -> f32, + crate_fn: conv::__floatundisf, + sys_fn: __floatundisf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "ucvtf {ret:s}, {a:x}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_u64_f64, + sig: (a: u64) -> f64, + crate_fn: conv::__floatundidf, + sys_fn: __floatundidf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "ucvtf {ret:d}, {a:x}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_u128_f32, + sig: (a: u128) -> f32, + crate_fn: conv::__floatuntisf, + sys_fn: __floatuntisf, + sys_available: all(), + asm: [] +} + +float_bench! { + name: conv_u128_f64, + sig: (a: u128) -> f64, + crate_fn: conv::__floatuntidf, + sys_fn: __floatuntidf, + sys_available: all(), + asm: [] +} + +/* signed int -> float */ + +float_bench! { + name: conv_i32_f32, + sig: (a: i32) -> f32, + crate_fn: conv::__floatsisf, + sys_fn: __floatsisf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f32; + asm!( + "cvtsi2ss {ret}, {a:e}", + a = in(reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "scvtf {ret:s}, {a:w}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_i32_f64, + sig: (a: i32) -> f64, + crate_fn: conv::__floatsidf, + sys_fn: __floatsidf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f64; + asm!( + "cvtsi2sd {ret}, {a:e}", + a = in(reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "scvtf {ret:d}, {a:w}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_i64_f32, + sig: (a: i64) -> f32, + crate_fn: conv::__floatdisf, + sys_fn: __floatdisf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f32; + asm!( + "cvtsi2ss {ret}, {a:r}", + a = in(reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "scvtf {ret:s}, {a:x}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_i64_f64, + sig: (a: i64) -> f64, + crate_fn: conv::__floatdidf, + sys_fn: __floatdidf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f64; + asm!( + "cvtsi2sd {ret}, {a:r}", + a = in(reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "scvtf {ret:d}, {a:x}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_i128_f32, + sig: (a: i128) -> f32, + crate_fn: conv::__floattisf, + sys_fn: __floattisf, + sys_available: all(), + asm: [] +} + +float_bench! { + name: conv_i128_f64, + sig: (a: i128) -> f64, + crate_fn: conv::__floattidf, + sys_fn: __floattidf, + sys_available: all(), + asm: [] +} + +/* float -> unsigned int */ + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_u32, + sig: (a: f32) -> u32, + crate_fn: conv::__fixunssfsi, + sys_fn: __fixunssfsi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: u32; + asm!( + "fcvtzu {ret:w}, {a:s}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_u64, + sig: (a: f32) -> u64, + crate_fn: conv::__fixunssfdi, + sys_fn: __fixunssfdi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: u64; + asm!( + "fcvtzu {ret:x}, {a:s}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_u128, + sig: (a: f32) -> u128, + crate_fn: conv::__fixunssfti, + sys_fn: __fixunssfti, + sys_available: all(), + asm: [] +} + +float_bench! { + name: conv_f64_u32, + sig: (a: f64) -> u32, + crate_fn: conv::__fixunsdfsi, + sys_fn: __fixunsdfsi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: u32; + asm!( + "fcvtzu {ret:w}, {a:d}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_f64_u64, + sig: (a: f64) -> u64, + crate_fn: conv::__fixunsdfdi, + sys_fn: __fixunsdfdi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: u64; + asm!( + "fcvtzu {ret:x}, {a:d}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_f64_u128, + sig: (a: f64) -> u128, + crate_fn: conv::__fixunsdfti, + sys_fn: __fixunsdfti, + sys_available: all(), + asm: [] +} + +/* float -> signed int */ + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_i32, + sig: (a: f32) -> i32, + crate_fn: conv::__fixsfsi, + sys_fn: __fixsfsi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcvtzs {ret:w}, {a:s}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_i64, + sig: (a: f32) -> i64, + crate_fn: conv::__fixsfdi, + sys_fn: __fixsfdi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: i64; + asm!( + "fcvtzs {ret:x}, {a:s}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_i128, + sig: (a: f32) -> i128, + crate_fn: conv::__fixsfti, + sys_fn: __fixsfti, + sys_available: all(), + asm: [] +} + +float_bench! { + name: conv_f64_i32, + sig: (a: f64) -> i32, + crate_fn: conv::__fixdfsi, + sys_fn: __fixdfsi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcvtzs {ret:w}, {a:d}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_f64_i64, + sig: (a: f64) -> i64, + crate_fn: conv::__fixdfdi, + sys_fn: __fixdfdi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: i64; + asm!( + "fcvtzs {ret:x}, {a:d}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_f64_i128, + sig: (a: f64) -> i128, + crate_fn: conv::__fixdfti, + sys_fn: __fixdfti, + sys_available: all(), + asm: [] +} + +criterion_group!( + float_conv, + conv_u32_f32, + conv_u32_f64, + conv_u64_f32, + conv_u64_f64, + conv_u128_f32, + conv_u128_f64, + conv_i32_f32, + conv_i32_f64, + conv_i64_f32, + conv_i64_f64, + conv_i128_f32, + conv_i128_f64, + conv_f64_u32, + conv_f64_u64, + conv_f64_u128, + conv_f64_i32, + conv_f64_i64, + conv_f64_i128, +); + +// FIXME: ppc64le has a sporadic overflow panic in the crate functions +// +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +criterion_group!( + float_conv_not_ppc64le, + conv_f32_u32, + conv_f32_u64, + conv_f32_u128, + conv_f32_i32, + conv_f32_i64, + conv_f32_i128, +); + +#[cfg(all(target_arch = "powerpc64", target_endian = "little"))] +criterion_main!(float_conv); + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +criterion_main!(float_conv, float_conv_not_ppc64le); diff --git a/library/compiler-builtins/testcrate/benches/float_div.rs b/library/compiler-builtins/testcrate/benches/float_div.rs new file mode 100644 index 00000000000..e679f8ccccb --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_div.rs @@ -0,0 +1,70 @@ +#![feature(f128)] + +use compiler_builtins::float::div; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +float_bench! { + name: div_f32, + sig: (a: f32, b: f32) -> f32, + crate_fn: div::__divsf3, + sys_fn: __divsf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "divss {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fdiv {a:s}, {a:s}, {b:s}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: div_f64, + sig: (a: f64, b: f64) -> f64, + crate_fn: div::__divdf3, + sys_fn: __divdf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "divsd {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fdiv {a:d}, {a:d}, {b:d}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +criterion_group!(float_div, div_f32, div_f64); +criterion_main!(float_div); diff --git a/library/compiler-builtins/testcrate/benches/float_extend.rs b/library/compiler-builtins/testcrate/benches/float_extend.rs new file mode 100644 index 00000000000..9bd8009e93b --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_extend.rs @@ -0,0 +1,93 @@ +#![allow(unused_variables)] // "unused" f16 registers +#![feature(f128)] +#![feature(f16)] + +use compiler_builtins::float::extend; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +float_bench! { + name: extend_f16_f32, + sig: (a: f16) -> f32, + crate_fn: extend::__extendhfsf2, + sys_fn: __extendhfsf2, + sys_available: not(feature = "no-sys-f16"), + asm: [ + #[cfg(target_arch = "aarch64")] { + // FIXME(f16_f128): remove `to_bits()` after f16 asm support (rust-lang/rust/#116909) + let ret: f32; + asm!( + "fcvt {ret:s}, {a:h}", + a = in(vreg) a.to_bits(), + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: extend_f16_f128, + sig: (a: f16) -> f128, + crate_fn: extend::__extendhftf2, + crate_fn_ppc: extend::__extendhfkf2, + sys_fn: __extendhftf2, + sys_fn_ppc: __extendhfkf2, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [], +} + +float_bench! { + name: extend_f32_f64, + sig: (a: f32) -> f64, + crate_fn: extend::__extendsfdf2, + sys_fn: __extendsfdf2, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "fcvt {ret:d}, {a:s}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: extend_f32_f128, + sig: (a: f32) -> f128, + crate_fn: extend::__extendsftf2, + crate_fn_ppc: extend::__extendsfkf2, + sys_fn: __extendsftf2, + sys_fn_ppc: __extendsfkf2, + sys_available: not(feature = "no-sys-f128"), + asm: [], +} + +float_bench! { + name: extend_f64_f128, + sig: (a: f64) -> f128, + crate_fn: extend::__extenddftf2, + crate_fn_ppc: extend::__extenddfkf2, + sys_fn: __extenddftf2, + sys_fn_ppc: __extenddfkf2, + sys_available: not(feature = "no-sys-f128"), + asm: [], +} + +criterion_group!( + float_extend, + extend_f16_f32, + extend_f16_f128, + extend_f32_f64, + extend_f32_f128, + extend_f64_f128, +); +criterion_main!(float_extend); diff --git a/library/compiler-builtins/testcrate/benches/float_mul.rs b/library/compiler-builtins/testcrate/benches/float_mul.rs new file mode 100644 index 00000000000..efa32b28563 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_mul.rs @@ -0,0 +1,81 @@ +#![feature(f128)] + +use compiler_builtins::float::mul; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +float_bench! { + name: mul_f32, + sig: (a: f32, b: f32) -> f32, + crate_fn: mul::__mulsf3, + sys_fn: __mulsf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "mulss {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fmul {a:s}, {a:s}, {b:s}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: mul_f64, + sig: (a: f64, b: f64) -> f64, + crate_fn: mul::__muldf3, + sys_fn: __muldf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "mulsd {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fmul {a:d}, {a:d}, {b:d}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: mul_f128, + sig: (a: f128, b: f128) -> f128, + crate_fn: mul::__multf3, + crate_fn_ppc: mul::__mulkf3, + sys_fn: __multf3, + sys_fn_ppc: __mulkf3, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +criterion_group!(float_mul, mul_f32, mul_f64, mul_f128); +criterion_main!(float_mul); diff --git a/library/compiler-builtins/testcrate/benches/float_pow.rs b/library/compiler-builtins/testcrate/benches/float_pow.rs new file mode 100644 index 00000000000..252f740120d --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_pow.rs @@ -0,0 +1,24 @@ +use compiler_builtins::float::pow; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +float_bench! { + name: powi_f32, + sig: (a: f32, b: i32) -> f32, + crate_fn: pow::__powisf2, + sys_fn: __powisf2, + sys_available: all(), + asm: [], +} + +float_bench! { + name: powi_f64, + sig: (a: f64, b: i32) -> f64, + crate_fn: pow::__powidf2, + sys_fn: __powidf2, + sys_available: all(), + asm: [], +} + +criterion_group!(float_add, powi_f32, powi_f64); +criterion_main!(float_add); diff --git a/library/compiler-builtins/testcrate/benches/float_sub.rs b/library/compiler-builtins/testcrate/benches/float_sub.rs new file mode 100644 index 00000000000..6d87604aac7 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_sub.rs @@ -0,0 +1,81 @@ +#![feature(f128)] + +use compiler_builtins::float::sub; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +float_bench! { + name: sub_f32, + sig: (a: f32, b: f32) -> f32, + crate_fn: sub::__subsf3, + sys_fn: __subsf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "subss {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fsub {a:s}, {a:s}, {b:s}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: sub_f64, + sig: (a: f64, b: f64) -> f64, + crate_fn: sub::__subdf3, + sys_fn: __subdf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "subsd {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fsub {a:d}, {a:d}, {b:d}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: sub_f128, + sig: (a: f128, b: f128) -> f128, + crate_fn: sub::__subtf3, + crate_fn_ppc: sub::__subkf3, + sys_fn: __subtf3, + sys_fn_ppc: __subkf3, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +criterion_group!(float_sub, sub_f32, sub_f64, sub_f128); +criterion_main!(float_sub); diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs new file mode 100644 index 00000000000..1553dacee08 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_trunc.rs @@ -0,0 +1,127 @@ +#![feature(f128)] +#![feature(f16)] + +use compiler_builtins::float::trunc; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +float_bench! { + name: trunc_f32_f16, + sig: (a: f32) -> f16, + crate_fn: trunc::__truncsfhf2, + sys_fn: __truncsfhf2, + sys_available: not(feature = "no-sys-f16"), + asm: [ + #[cfg(target_arch = "aarch64")] { + // FIXME(f16_f128): remove `from_bits()` after f16 asm support (rust-lang/rust/#116909) + let ret: u16; + asm!( + "fcvt {ret:h}, {a:s}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + f16::from_bits(ret) + }; + ], +} + +float_bench! { + name: trunc_f64_f16, + sig: (a: f64) -> f16, + crate_fn: trunc::__truncdfhf2, + sys_fn: __truncdfhf2, + sys_available: not(feature = "no-sys-f128"), + asm: [ + #[cfg(target_arch = "aarch64")] { + // FIXME(f16_f128): remove `from_bits()` after f16 asm support (rust-lang/rust/#116909) + let ret: u16; + asm!( + "fcvt {ret:h}, {a:d}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + f16::from_bits(ret) + }; + ], +} + +float_bench! { + name: trunc_f64_f32, + sig: (a: f64) -> f32, + crate_fn: trunc::__truncdfsf2, + sys_fn: __truncdfsf2, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f32; + asm!( + "cvtsd2ss {ret}, {a}", + a = in(xmm_reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "fcvt {ret:s}, {a:d}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: trunc_f128_f16, + sig: (a: f128) -> f16, + crate_fn: trunc::__trunctfhf2, + crate_fn_ppc: trunc::__trunckfhf2, + sys_fn: __trunctfhf2, + sys_fn_ppc: __trunckfhf2, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [], +} + +float_bench! { + name: trunc_f128_f32, + sig: (a: f128) -> f32, + crate_fn: trunc::__trunctfsf2, + crate_fn_ppc: trunc::__trunckfsf2, + sys_fn: __trunctfsf2, + sys_fn_ppc: __trunckfsf2, + sys_available: not(feature = "no-sys-f128"), + asm: [], +} + +float_bench! { + name: trunc_f128_f64, + sig: (a: f128) -> f64, + crate_fn: trunc::__trunctfdf2, + crate_fn_ppc: trunc::__trunckfdf2, + sys_fn: __trunctfdf2, + sys_fn_ppc: __trunckfdf2, + sys_available: not(feature = "no-sys-f128"), + asm: [], +} + +criterion_group!( + float_trunc, + trunc_f32_f16, + trunc_f64_f16, + trunc_f64_f32, + trunc_f128_f16, + trunc_f128_f32, + trunc_f128_f64, +); +criterion_main!(float_trunc); diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 1dad6c5e649..cae83e1fc09 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -5,6 +5,8 @@ use std::{collections::HashSet, env}; enum Feature { NoSysF128, NoSysF128IntConvert, + NoSysF16, + NoSysF16F128Convert, } fn main() { @@ -31,6 +33,7 @@ fn main() { { features.insert(Feature::NoSysF128); features.insert(Feature::NoSysF128IntConvert); + features.insert(Feature::NoSysF16F128Convert); } if target.starts_with("i586") || target.starts_with("i686") { @@ -38,6 +41,17 @@ fn main() { features.insert(Feature::NoSysF128IntConvert); } + if target.contains("-unknown-linux-") { + // No `__extendhftf2` on x86, no `__trunctfhf2` on aarch64 + features.insert(Feature::NoSysF16F128Convert); + } + + if target.starts_with("wasm32-") { + // Linking says "error: function signature mismatch: __extendhfsf2" and seems to + // think the signature is either `(i32) -> f32` or `(f32) -> f32` + features.insert(Feature::NoSysF16); + } + for feature in features { let (name, warning) = match feature { Feature::NoSysF128 => ("no-sys-f128", "using apfloat fallback for f128"), @@ -45,6 +59,11 @@ fn main() { "no-sys-f128-int-convert", "using apfloat fallback for f128 to int conversions", ), + Feature::NoSysF16F128Convert => ( + "no-sys-f16-f128-convert", + "skipping using apfloat fallback for f16 <-> f128 conversions", + ), + Feature::NoSysF16 => ("no-sys-f16", "using apfloat fallback for f16"), }; println!("cargo:warning={warning}"); println!("cargo:rustc-cfg=feature=\"{name}\""); diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs new file mode 100644 index 00000000000..1374d7b4f77 --- /dev/null +++ b/library/compiler-builtins/testcrate/src/bench.rs @@ -0,0 +1,348 @@ +use core::cell::RefCell; + +use alloc::vec::Vec; +use compiler_builtins::float::Float; + +/// Fuzz with these many items to ensure equal functions +pub const CHECK_ITER_ITEMS: u32 = 10_000; +/// Benchmark with this many items to get a variety +pub const BENCH_ITER_ITEMS: u32 = 500; + +/// Still run benchmarks/tests but don't check correctness between compiler-builtins and +/// builtin system functions functions +pub fn skip_sys_checks(test_name: &str) -> bool { + const ALWAYS_SKIPPED: &[&str] = &[ + // FIXME(f16_f128): system symbols have incorrect results + // + "extend_f16_f32", + "trunc_f32_f16", + "trunc_f64_f16", + // FIXME(f16_f128): rounding error + // + "mul_f128", + ]; + + // FIXME(f16_f128): error on LE ppc64. There are more tests that are cfg-ed out completely + // in their benchmark modules due to runtime panics. + // + const PPC64LE_SKIPPED: &[&str] = &["extend_f32_f128"]; + + // FIXME(f16_f128): system symbols have incorrect results + // + const X86_NO_SSE_SKIPPED: &[&str] = &["add_f128", "sub_f128", "powi_f32", "powi_f64"]; + + // FIXME(llvm): system symbols have incorrect results on Windows + // + const WINDOWS_SKIPPED: &[&str] = &[ + "conv_f32_u128", + "conv_f32_i128", + "conv_f64_u128", + "conv_f64_i128", + ]; + + if cfg!(target_arch = "arm") { + // The Arm symbols need a different ABI that our macro doesn't handle, just skip it + return true; + } + + if ALWAYS_SKIPPED.contains(&test_name) { + return true; + } + + if cfg!(all(target_arch = "powerpc64", target_endian = "little")) + && PPC64LE_SKIPPED.contains(&test_name) + { + return true; + } + + if cfg!(all(target_arch = "x86", not(target_feature = "sse"))) + && X86_NO_SSE_SKIPPED.contains(&test_name) + { + return true; + } + + if cfg!(target_family = "windows") && WINDOWS_SKIPPED.contains(&test_name) { + return true; + } + + false +} + +/// Still run benchmarks/tests but don't check correctness between compiler-builtins and +/// assembly functions +pub fn skip_asm_checks(test_name: &str) -> bool { + // FIXME(f16_f128): rounding error + // + const SKIPPED: &[&str] = &["mul_f32", "mul_f64"]; + + SKIPPED.contains(&test_name) +} + +/// Create a comparison of the system symbol, compiler_builtins, and optionally handwritten +/// assembly. +#[macro_export] +macro_rules! float_bench { + ( + // Name of this benchmark + name: $name:ident, + // The function signature to be tested + sig: ($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty, + // Path to the crate in compiler_builtins + crate_fn: $crate_fn:path, + // Optional alias on ppc + $( crate_fn_ppc: $crate_fn_ppc:path, )? + // Name of the system symbol + sys_fn: $sys_fn:ident, + // Optional alias on ppc + $( sys_fn_ppc: $sys_fn_ppc:path, )? + // Meta saying whether the system symbol is available + sys_available: $sys_available:meta, + // An optional function to validate the results of two functions are equal, if not + // just `$ret_ty::check_eq` + $( output_eq: $output_eq:expr, )? + // Assembly implementations, if any. + asm: [ + $( + #[cfg($asm_meta:meta)] { + $($asm_tt:tt)* + } + );* + $(;)? + ] + $(,)? + ) => {paste::paste! { + #[cfg($sys_available)] + extern "C" { + /// Binding for the system function + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + fn $sys_fn($($arg: $arg_ty),*) -> $ret_ty; + + + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + float_bench! { @coalesce_fn $($sys_fn_ppc)? => + fn $sys_fn($($arg: $arg_ty),*) -> $ret_ty; + } + } + + fn $name(c: &mut Criterion) { + use core::hint::black_box; + use compiler_builtins::float::Float; + use $crate::bench::TestIO; + + #[inline(never)] // equalize with external calls + fn crate_fn($($arg: $arg_ty),*) -> $ret_ty { + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + let target_crate_fn = $crate_fn; + + // On PPC, use an alias if specified + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + let target_crate_fn = float_bench!(@coalesce $($crate_fn_ppc)?, $crate_fn); + + target_crate_fn( $($arg),* ) + } + + #[inline(always)] // already a branch + #[cfg($sys_available)] + fn sys_fn($($arg: $arg_ty),*) -> $ret_ty { + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + let target_sys_fn = $sys_fn; + + // On PPC, use an alias if specified + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + let target_sys_fn = float_bench!(@coalesce $($sys_fn_ppc)?, $sys_fn); + + unsafe { target_sys_fn( $($arg),* ) } + } + + #[inline(never)] // equalize with external calls + #[cfg(any( $($asm_meta),* ))] + fn asm_fn($(mut $arg: $arg_ty),*) -> $ret_ty { + use core::arch::asm; + $( + #[cfg($asm_meta)] + unsafe { $($asm_tt)* } + )* + } + + let testvec = <($($arg_ty),*)>::make_testvec($crate::bench::CHECK_ITER_ITEMS); + let benchvec = <($($arg_ty),*)>::make_testvec($crate::bench::BENCH_ITER_ITEMS); + let test_name = stringify!($name); + let check_eq = float_bench!(@coalesce $($output_eq)?, $ret_ty::check_eq); + + // Verify math lines up. We run the crate functions even if we don't validate the + // output here to make sure there are no panics or crashes. + + #[cfg($sys_available)] + for ($($arg),*) in testvec.iter().copied() { + let crate_res = crate_fn($($arg),*); + let sys_res = sys_fn($($arg),*); + + if $crate::bench::skip_sys_checks(test_name) { + continue; + } + + assert!( + check_eq(crate_res, sys_res), + "{test_name}{:?}: crate: {crate_res:?}, sys: {sys_res:?}", + ($($arg),* ,) + ); + } + + #[cfg(any( $($asm_meta),* ))] + { + for ($($arg),*) in testvec.iter().copied() { + let crate_res = crate_fn($($arg),*); + let asm_res = asm_fn($($arg),*); + + if $crate::bench::skip_asm_checks(test_name) { + continue; + } + + assert!( + check_eq(crate_res, asm_res), + "{test_name}{:?}: crate: {crate_res:?}, asm: {asm_res:?}", + ($($arg),* ,) + ); + } + } + + let mut group = c.benchmark_group(test_name); + group.bench_function("compiler-builtins", |b| b.iter(|| { + for ($($arg),*) in benchvec.iter().copied() { + black_box(crate_fn( $(black_box($arg)),* )); + } + })); + + #[cfg($sys_available)] + group.bench_function("system", |b| b.iter(|| { + for ($($arg),*) in benchvec.iter().copied() { + black_box(sys_fn( $(black_box($arg)),* )); + } + })); + + #[cfg(any( $($asm_meta),* ))] + group.bench_function(&format!( + "assembly ({} {})", std::env::consts::ARCH, std::env::consts::FAMILY + ), |b| b.iter(|| { + for ($($arg),*) in benchvec.iter().copied() { + black_box(asm_fn( $(black_box($arg)),* )); + } + })); + + group.finish(); + } + }}; + + // Allow overriding a default + (@coalesce $specified:expr, $default:expr) => { $specified }; + (@coalesce, $default:expr) => { $default }; + + // Allow overriding a function name + (@coalesce_fn $specified:ident => fn $default_name:ident $($tt:tt)+) => { + fn $specified $($tt)+ + }; + (@coalesce_fn => fn $default_name:ident $($tt:tt)+) => { + fn $default_name $($tt)+ + }; +} + +/// A type used as either an input or output to/from a benchmark function. +pub trait TestIO: Sized { + fn make_testvec(len: u32) -> Vec; + fn check_eq(a: Self, b: Self) -> bool; +} + +macro_rules! impl_testio { + (float $($f_ty:ty),+) => {$( + impl TestIO for $f_ty { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ret = RefCell::new(Vec::new()); + crate::fuzz_float(len, |a| ret.borrow_mut().push(a)); + ret.into_inner() + } + + fn check_eq(a: Self, b: Self) -> bool { + Float::eq_repr(a, b) + } + } + + impl TestIO for ($f_ty, $f_ty) { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ret = RefCell::new(Vec::new()); + crate::fuzz_float_2(len, |a, b| ret.borrow_mut().push((a, b))); + ret.into_inner() + } + + fn check_eq(_a: Self, _b: Self) -> bool { + unimplemented!() + } + } + )*}; + + (int $($i_ty:ty),+) => {$( + impl TestIO for $i_ty { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ret = RefCell::new(Vec::new()); + crate::fuzz(len, |a| ret.borrow_mut().push(a)); + ret.into_inner() + } + + fn check_eq(a: Self, b: Self) -> bool { + a == b + } + } + + impl TestIO for ($i_ty, $i_ty) { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ret = RefCell::new(Vec::new()); + crate::fuzz_2(len, |a, b| ret.borrow_mut().push((a, b))); + ret.into_inner() + } + + fn check_eq(_a: Self, _b: Self) -> bool { + unimplemented!() + } + } + )*}; + + ((float, int) ($f_ty:ty, $i_ty:ty)) => { + impl TestIO for ($f_ty, $i_ty) { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ivec = RefCell::new(Vec::new()); + let fvec = RefCell::new(Vec::new()); + + crate::fuzz(len.isqrt(), |a| ivec.borrow_mut().push(a)); + crate::fuzz_float(len.isqrt(), |a| fvec.borrow_mut().push(a)); + + let mut ret = Vec::new(); + let ivec = ivec.into_inner(); + let fvec = fvec.into_inner(); + + for f in fvec { + for i in &ivec { + ret.push((f, *i)); + } + } + + ret + } + + fn check_eq(_a: Self, _b: Self) -> bool { + unimplemented!() + } + } + } +} + +#[cfg(not(feature = "no-f16-f128"))] +impl_testio!(float f16, f128); +impl_testio!(float f32, f64); +impl_testio!(int i16, i32, i64, i128); +impl_testio!(int u16, u32, u64, u128); +impl_testio!((float, int)(f32, i32)); +impl_testio!((float, int)(f64, i32)); diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 5ee96ad2751..f9b052528f0 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -13,6 +13,12 @@ //! Some floating point tests are disabled for specific architectures, because they do not have //! correct rounding. #![no_std] +#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))] +#![cfg_attr(not(feature = "no-f16-f128"), feature(f16))] +#![feature(isqrt)] + +pub mod bench; +extern crate alloc; use compiler_builtins::float::Float; use compiler_builtins::int::{Int, MinInt}; -- cgit 1.4.1-3-g733a5 From d0fdc0044a61bec6c7c4f8db8d7f41ca71eb688c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 May 2024 05:06:36 -0400 Subject: Enable cache for Cargo components of the build --- library/compiler-builtins/.github/workflows/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 72d441c4e7d..98d22c75af9 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -105,6 +105,9 @@ jobs: shell: bash - run: rustup target add ${{ matrix.target }} - run: rustup component add llvm-tools-preview + - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} - name: Download compiler-rt reference sources run: | curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/18.0-2024-02-13.tar.gz @@ -147,6 +150,7 @@ jobs: - name: Install nightly `clippy` run: | rustup set profile minimal && rustup default "nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/clippy)" && rustup component add clippy + - uses: Swatinem/rust-cache@v2 - run: cargo clippy -- -D clippy::all success: -- cgit 1.4.1-3-g733a5 From 98ddf3c66dd6f25d426c504554276d21fcac1c33 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 May 2024 05:23:06 -0400 Subject: Enable cache for Docker images --- .../compiler-builtins/.github/workflows/main.yml | 21 +++++++++++++++++++++ library/compiler-builtins/ci/run-docker.sh | 14 +++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 98d22c75af9..9e89c3a98bd 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -108,6 +108,14 @@ jobs: - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} + - name: Cache Docker layers + uses: actions/cache@v2 + if: matrix.os == 'ubuntu-latest' + with: + path: /tmp/.buildx-cache + key: ${{ matrix.target }}-buildx-${{ github.sha }} + restore-keys: ${{ matrix.target }}-buildx- + - name: Download compiler-rt reference sources run: | curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/18.0-2024-02-13.tar.gz @@ -123,10 +131,23 @@ jobs: NO_STD: ${{ matrix.no_std }} TEST_VERBATIM: ${{ matrix.test_verbatim }} + # Configure buildx to use Docker layer caching + - uses: docker/setup-buildx-action@v3 + if: matrix.os == 'ubuntu-latest' + # Otherwise we use our docker containers to run builds - run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} if: matrix.os == 'ubuntu-latest' + # Workaround to keep Docker cache smaller + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + - name: Move Docker cache + if: matrix.os == 'ubuntu-latest' + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache + rustfmt: name: Rustfmt runs-on: ubuntu-latest diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index e5ff8a46b26..14b1a32d712 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -41,7 +41,19 @@ run() { export RUST_COMPILER_RT_ROOT=./compiler-rt fi - docker build \ + if [ "$GITHUB_ACTIONS" = "true" ]; then + # Enable Docker image caching on GHA + + buildx="buildx" + build_args=( + "--cache-from" "type=local,src=/tmp/.buildx-cache" + "--cache-to" "type=local,dest=/tmp/.buildx-cache-new" + "${build_args[@]:-}" + "--load" + ) + fi + + docker "${buildx:-}" build \ -t "builtins-$target" \ ${build_args[@]:-} \ "ci/docker/$target" -- cgit 1.4.1-3-g733a5 From 84e87eb15b3307af12abea4316ac9650024d8a43 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 May 2024 15:20:31 -0400 Subject: Add caching for downloading compiler-rt --- library/compiler-builtins/.github/workflows/main.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 9e89c3a98bd..38064543f3e 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -4,6 +4,8 @@ on: [push, pull_request] env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings + RUST_LLVM_VERSION: 18.0-2024-02-13 + RUST_COMPILER_RT_ROOT: ./compiler-rt jobs: test: @@ -115,12 +117,18 @@ jobs: path: /tmp/.buildx-cache key: ${{ matrix.target }}-buildx-${{ github.sha }} restore-keys: ${{ matrix.target }}-buildx- - + + - name: Cache compiler-rt + id: cache-compiler-rt + uses: actions/cache@v4 + with: + path: compiler-rt + key: ${{ runner.os }}-compiler-rt-${{ env.RUST_LLVM_VERSION }} - name: Download compiler-rt reference sources + if: steps.cache-compiler-rt.outputs.cache-hit != 'true' run: | - curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/18.0-2024-02-13.tar.gz - tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-18.0-2024-02-13/compiler-rt - echo RUST_COMPILER_RT_ROOT=./compiler-rt >> $GITHUB_ENV + curl -L -o code.tar.gz "https://github.com/rust-lang/llvm-project/archive/rustc/${RUST_LLVM_VERSION}.tar.gz" + tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-${RUST_LLVM_VERSION}/compiler-rt shell: bash # Non-linux tests just use our raw script -- cgit 1.4.1-3-g733a5 From e35091a2d0b5fda2045c27ee4facc33f6dd8d486 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 17 Jun 2024 19:38:55 -0500 Subject: Disable libm on x86 without sse2 In , symbols for the Rust port of libm were made always weakly available. This seems to be causing problems on platforms with ABI issues, as explained at . Disable Rust libm on x86 without sse2 to mitigate this. --- library/compiler-builtins/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 40564178a24..0d207a914bf 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -47,6 +47,9 @@ mod macros; pub mod float; pub mod int; +// Disabled on x86 without sse2 due to ABI issues +// +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse2"))))] pub mod math; pub mod mem; -- cgit 1.4.1-3-g733a5 From f2092967cb163255a1e5ea7d36c5eac07e467067 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 29 May 2024 03:38:57 -0500 Subject: Update the Ubuntu docker image to the latest version --- .../compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 2 +- .../compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 2 +- .../compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile | 2 +- .../ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile | 2 +- library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile | 2 +- library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile | 2 +- library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile | 2 +- .../ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile | 2 +- .../ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile | 2 +- library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 2 +- .../compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 2 +- .../compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile | 2 +- .../ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile | 2 +- library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile | 2 +- library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile | 2 +- library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile | 2 +- library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile | 2 +- library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 2 +- library/compiler-builtins/ci/run-docker.sh | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index 5de76efc375..1aef14a962d 100644 --- a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile index dc95da0f3c5..fc9803777f8 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile index 55e5e3d5754..a127f67cb73 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile index fd2ad18d1a3..67a3e51a964 100644 --- a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile index f161ec76725..15285d9bb06 100644 --- a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile index f161ec76725..15285d9bb06 100644 --- a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile index 042dd4219de..a47dd9f1931 100644 --- a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile index 45b3089c9ed..688aa1ab231 100644 --- a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile index bda6be1d674..27d032a1441 100644 --- a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile index 702a26ec1a5..4d18a6edbc9 100644 --- a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile index 6bae7cb3b65..5225b833c0c 100644 --- a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile index 2c315e509e3..cbd78eac421 100644 --- a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile index da8f9db604b..bad064297c3 100644 --- a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index d7256a9c533..f966b2b9f2a 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index d7256a9c533..f966b2b9f2a 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index d7256a9c533..f966b2b9f2a 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index d7256a9c533..f966b2b9f2a 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile index d495d5044ad..670c2439764 100644 --- a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 14b1a32d712..aff3564732f 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -76,7 +76,7 @@ if [ "${1:-}" = "--help" ] || [ "$#" -gt 1 ]; then usage: ./ci/run-docker.sh [target] you can also set DOCKER_BASE_IMAGE to use something other than the default - ubuntu:18.04 (or rustlang/rust:nightly). + ubuntu:24.04 (or rustlang/rust:nightly). " exit fi -- cgit 1.4.1-3-g733a5 From 21690f7320ad03cb33801239cf7f0bd99fae0c74 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 22 Jun 2024 06:05:25 -0400 Subject: Skip f128 tests on powerpc64le __addkf3 and __mulkf3 seem to hit a nondescript SIGILL. This is probably likely to just be another Qemu limitation. --- library/compiler-builtins/testcrate/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index cae83e1fc09..f18bd90df16 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -24,9 +24,10 @@ fn main() { // FIXME(llvm): There is an ABI incompatibility between GCC and Clang on 32-bit x86. // See . || target.starts_with("i686") - // 32-bit PowerPC gets code generated that Qemu cannot handle. See + // 32-bit PowerPC and 64-bit LE gets code generated that Qemu cannot handle. See // . || target.starts_with("powerpc-") + || target.starts_with("powerpc64le-") // FIXME: We get different results from the builtin functions. See // . || target.starts_with("powerpc64-") -- cgit 1.4.1-3-g733a5 From fdec3b65142a95a3d7020d0160d926243cf8e81c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 22 Jun 2024 04:20:48 -0500 Subject: Fix unset variables in the build script These were preventing building via Docker locally. --- library/compiler-builtins/ci/run-docker.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index aff3564732f..50ae9dc83a1 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -41,10 +41,10 @@ run() { export RUST_COMPILER_RT_ROOT=./compiler-rt fi - if [ "$GITHUB_ACTIONS" = "true" ]; then + if [ "${GITHUB_ACTIONS:-}" = "true" ]; then # Enable Docker image caching on GHA - buildx="buildx" + build_cmd=("buildx" "build") build_args=( "--cache-from" "type=local,src=/tmp/.buildx-cache" "--cache-to" "type=local,dest=/tmp/.buildx-cache-new" @@ -53,7 +53,7 @@ run() { ) fi - docker "${buildx:-}" build \ + docker ${build_cmd[@]:-build} \ -t "builtins-$target" \ ${build_args[@]:-} \ "ci/docker/$target" -- cgit 1.4.1-3-g733a5 From bf503b5c9b1cefa2709f1b1b7fc5174485f43f50 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 23 Jun 2024 19:19:25 +0100 Subject: Fix building on AVR --- library/compiler-builtins/src/float/sub.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 1492679f623..3ab46495d4f 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -1,18 +1,16 @@ -use crate::float::add::__adddf3; -use crate::float::add::__addsf3; use crate::float::Float; intrinsics! { #[avr_skip] #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { - __addsf3(a, f32::from_repr(b.repr() ^ f32::SIGN_MASK)) + crate::float::add::__addsf3(a, f32::from_repr(b.repr() ^ f32::SIGN_MASK)) } #[avr_skip] #[arm_aeabi_alias = __aeabi_dsub] pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { - __adddf3(a, f64::from_repr(b.repr() ^ f64::SIGN_MASK)) + crate::float::add::__adddf3(a, f64::from_repr(b.repr() ^ f64::SIGN_MASK)) } #[ppc_alias = __subkf3] -- cgit 1.4.1-3-g733a5 From 1d7f2847e32d91aeae3ceb716589ba73361a66f2 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 25 Jun 2024 22:51:05 +0100 Subject: Release 0.1.113 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 4564ba9e54c..ab43951593b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.112" +version = "0.1.113" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 55b3f8b13d2abdd93232f608e45f218e2ba0e8a6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 22 Jun 2024 13:47:33 -0500 Subject: Enable `f128 -> f16` tests on Linux Since updating the docker images in , it looks like `__extendhftf2` and `__trunctfhf2` are available on all 64-bit Linux platforms. --- library/compiler-builtins/testcrate/build.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index f18bd90df16..12c3e7d1365 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -38,12 +38,9 @@ fn main() { } if target.starts_with("i586") || target.starts_with("i686") { - // 32-bit x86 seems to not have `__fixunstfti`, but does have everything else + // 32-bit x86 does not have `__fixunstfti`/`__fixtfti` but does have everything else features.insert(Feature::NoSysF128IntConvert); - } - - if target.contains("-unknown-linux-") { - // No `__extendhftf2` on x86, no `__trunctfhf2` on aarch64 + // FIXME: 32-bit x86 has a bug in `f128 -> f16` system libraries features.insert(Feature::NoSysF16F128Convert); } -- cgit 1.4.1-3-g733a5 From ffb31aee1341454ea96daaeee67110aafaa5c4d3 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 30 Jun 2024 22:02:41 +0100 Subject: Fix incorrect rounding with subnormal/zero results of float multiplication --- library/compiler-builtins/src/float/mul.rs | 19 +++++++------------ library/compiler-builtins/testcrate/tests/mul.rs | 13 +++++-------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 007cc09a498..decf722e29a 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -149,18 +149,13 @@ where } // Otherwise, shift the significand of the result so that the round - // bit is the high bit of productLo. - if shift < bits { - let sticky = product_low << (bits - shift); - product_low = product_high << (bits - shift) | product_low >> shift | sticky; - product_high >>= shift; - } else if shift < (2 * bits) { - let sticky = product_high << (2 * bits - shift) | product_low; - product_low = product_high >> (shift - bits) | sticky; - product_high = zero; - } else { - product_high = zero; - } + // bit is the high bit of `product_low`. + // Ensure one of the non-highest bits in `product_low` is set if the shifted out bit are + // not all zero so that the result is correctly rounded below. + let sticky = product_low << (bits - shift) != zero; + product_low = + product_high << (bits - shift) | product_low >> shift | (sticky as u32).cast(); + product_high >>= shift; } else { // Result is normal before rounding; insert the exponent. product_high &= significand_mask; diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 5daeadeb22b..818ca656a0d 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -107,14 +107,11 @@ macro_rules! float_mul { fuzz_float_2(N, |x: $f, y: $f| { let mul0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Mul::mul, x, y); let mul1: $f = $fn(x, y); - // multiplication of subnormals is not currently handled - if !(Float::is_subnormal(mul0) || Float::is_subnormal(mul1)) { - if !Float::eq_repr(mul0, mul1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), x, y, mul0, mul1 - ); - } + if !Float::eq_repr(mul0, mul1) { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), x, y, mul0, mul1 + ); } }); } -- cgit 1.4.1-3-g733a5 From c6bf88ab1cb5510971b51b4a16610db8eb792484 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 30 Jun 2024 22:40:57 +0100 Subject: Ignore broken nightly/system builtins --- library/compiler-builtins/testcrate/src/bench.rs | 17 ++++++++++++++--- library/compiler-builtins/testcrate/tests/mul.rs | 6 ++++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs index 1374d7b4f77..5ab9bac8715 100644 --- a/library/compiler-builtins/testcrate/src/bench.rs +++ b/library/compiler-builtins/testcrate/src/bench.rs @@ -17,9 +17,10 @@ pub fn skip_sys_checks(test_name: &str) -> bool { "extend_f16_f32", "trunc_f32_f16", "trunc_f64_f16", - // FIXME(f16_f128): rounding error + // FIXME(#616): re-enable once fix is in nightly // - "mul_f128", + "mul_f32", + "mul_f64", ]; // FIXME(f16_f128): error on LE ppc64. There are more tests that are cfg-ed out completely @@ -29,7 +30,13 @@ pub fn skip_sys_checks(test_name: &str) -> bool { // FIXME(f16_f128): system symbols have incorrect results // - const X86_NO_SSE_SKIPPED: &[&str] = &["add_f128", "sub_f128", "powi_f32", "powi_f64"]; + const X86_NO_SSE_SKIPPED: &[&str] = + &["add_f128", "sub_f128", "mul_f128", "powi_f32", "powi_f64"]; + + // FIXME(f16_f128): Wide multiply carry bug in `compiler-rt`, re-enable when nightly no longer + // uses `compiler-rt` version. + // + const AARCH64_SKIPPED: &[&str] = &["mul_f128"]; // FIXME(llvm): system symbols have incorrect results on Windows // @@ -61,6 +68,10 @@ pub fn skip_sys_checks(test_name: &str) -> bool { return true; } + if cfg!(target_arch = "aarch64") && AARCH64_SKIPPED.contains(&test_name) { + return true; + } + if cfg!(target_family = "windows") && WINDOWS_SKIPPED.contains(&test_name) { return true; } diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 818ca656a0d..90144bb0635 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -123,9 +123,11 @@ macro_rules! float_mul { mod float_mul { use super::*; + // FIXME(#616): Stop ignoring arches that don't have native support once fix for builtins is in + // nightly. float_mul! { - f32, __mulsf3, Single, all(); - f64, __muldf3, Double, all(); + f32, __mulsf3, Single, not(target_arch = "arm"); + f64, __muldf3, Double, not(target_arch = "arm"); } } -- cgit 1.4.1-3-g733a5 From 086a1c33eb4826d6159fcbee71857e54b7907427 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 30 Jun 2024 23:14:19 +0100 Subject: Temporarily `use define_rust_probestack;` --- library/compiler-builtins/src/probestack.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 0c30384db38..46caf167687 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -120,6 +120,10 @@ macro_rules! define_rust_probestack { }; } +// FIXME(rust-lang/rust#126984): Remove allow once lint is fixed +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +use define_rust_probestack; + // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, // ensuring that if any pages are unmapped we'll make a page fault. // -- cgit 1.4.1-3-g733a5 From 32b12b647b97b1bf047c8a090e6686e3703b196f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 30 Jun 2024 23:03:44 -0400 Subject: Remove unnecessary benchmark files --- .../testcrate/bench-175b45d1-aarch64-macos.txt | 500 --------------- .../testcrate/bench-3cee6376-aarch64-macos.txt | 699 --------------------- 2 files changed, 1199 deletions(-) delete mode 100644 library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt delete mode 100644 library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt diff --git a/library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt b/library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt deleted file mode 100644 index e79bbe36873..00000000000 --- a/library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt +++ /dev/null @@ -1,500 +0,0 @@ - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s - -add_f32 compiler-builtins - time: [35.804 µs 35.863 µs 35.920 µs] -Found 5 outliers among 100 measurements (5.00%) - 2 (2.00%) high mild - 3 (3.00%) high severe - -add_f32 system time: [39.084 µs 39.127 µs 39.169 µs] -Found 11 outliers among 100 measurements (11.00%) - 7 (7.00%) high mild - 4 (4.00%) high severe - -add_f32 assembly (aarch64 unix) - time: [8.1034 µs 8.1441 µs 8.1866 µs] -Found 4 outliers among 100 measurements (4.00%) - 4 (4.00%) high mild - -add_f64 compiler-builtins - time: [35.647 µs 35.725 µs 35.799 µs] -Found 10 outliers among 100 measurements (10.00%) - 8 (8.00%) high mild - 2 (2.00%) high severe - -add_f64 system time: [39.308 µs 39.322 µs 39.336 µs] -Found 7 outliers among 100 measurements (7.00%) - 4 (4.00%) high mild - 3 (3.00%) high severe - -add_f64 assembly (aarch64 unix) - time: [8.0401 µs 8.0442 µs 8.0499 µs] -Found 11 outliers among 100 measurements (11.00%) - 2 (2.00%) high mild - 9 (9.00%) high severe - -add_f128 compiler-builtins - time: [41.801 µs 41.986 µs 42.201 µs] -Found 7 outliers among 100 measurements (7.00%) - 4 (4.00%) high mild - 3 (3.00%) high severe - -cmp_f32_gt compiler-builtins - time: [13.579 µs 13.675 µs 13.778 µs] -Found 16 outliers among 100 measurements (16.00%) - 6 (6.00%) high mild - 10 (10.00%) high severe - -cmp_f32_gt system time: [12.343 µs 12.348 µs 12.355 µs] -Found 13 outliers among 100 measurements (13.00%) - 1 (1.00%) low mild - 3 (3.00%) high mild - 9 (9.00%) high severe - -cmp_f32_gt assembly (aarch64 unix) - time: [8.2593 µs 8.3185 µs 8.3813 µs] -Found 1 outliers among 100 measurements (1.00%) - 1 (1.00%) high mild - -cmp_f32_unord compiler-builtins - time: [11.977 µs 12.042 µs 12.109 µs] -Found 13 outliers among 100 measurements (13.00%) - 5 (5.00%) low severe - 6 (6.00%) low mild - 2 (2.00%) high mild - -cmp_f32_unord system time: [8.1236 µs 8.1736 µs 8.2350 µs] -Found 18 outliers among 100 measurements (18.00%) - 5 (5.00%) high mild - 13 (13.00%) high severe - -cmp_f32_unord assembly (aarch64 unix) - time: [8.1446 µs 8.2080 µs 8.2762 µs] -Found 14 outliers among 100 measurements (14.00%) - 6 (6.00%) high mild - 8 (8.00%) high severe - -cmp_f64_gt compiler-builtins - time: [16.073 µs 16.077 µs 16.082 µs] -Found 17 outliers among 100 measurements (17.00%) - 2 (2.00%) low mild - 4 (4.00%) high mild - 11 (11.00%) high severe - -cmp_f64_gt system time: [12.456 µs 12.487 µs 12.522 µs] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe - -cmp_f64_gt assembly (aarch64 unix) - time: [8.0557 µs 8.0616 µs 8.0685 µs] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe - -cmp_f64_unord compiler-builtins - time: [10.715 µs 10.724 µs 10.737 µs] -Found 13 outliers among 100 measurements (13.00%) - 3 (3.00%) high mild - 10 (10.00%) high severe - -cmp_f64_unord system time: [8.0692 µs 8.0734 µs 8.0784 µs] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe - -cmp_f64_unord assembly (aarch64 unix) - time: [8.0569 µs 8.0677 µs 8.0818 µs] -Found 18 outliers among 100 measurements (18.00%) - 4 (4.00%) high mild - 14 (14.00%) high severe - -cmp_f128_gt compiler-builtins - time: [18.234 µs 18.401 µs 18.602 µs] - -cmp_f128_unord compiler-builtins - time: [13.410 µs 13.471 µs 13.542 µs] -Found 7 outliers among 100 measurements (7.00%) - 7 (7.00%) high mild - -conv_u32_f32 compiler-builtins - time: [774.58 ns 776.01 ns 777.59 ns] -Found 9 outliers among 100 measurements (9.00%) - 2 (2.00%) high mild - 7 (7.00%) high severe - -conv_u32_f32 system time: [622.68 ns 625.64 ns 629.26 ns] -Found 16 outliers among 100 measurements (16.00%) - 7 (7.00%) high mild - 9 (9.00%) high severe - -conv_u32_f32 assembly (aarch64 unix) - time: [468.05 ns 469.76 ns 471.46 ns] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe - -conv_u32_f64 compiler-builtins - time: [617.61 ns 618.00 ns 618.52 ns] -Found 13 outliers among 100 measurements (13.00%) - 4 (4.00%) high mild - 9 (9.00%) high severe - -conv_u32_f64 system time: [469.56 ns 471.03 ns 472.81 ns] -Found 11 outliers among 100 measurements (11.00%) - 7 (7.00%) high mild - 4 (4.00%) high severe - -conv_u32_f64 assembly (aarch64 unix) - time: [464.43 ns 465.01 ns 465.72 ns] -Found 13 outliers among 100 measurements (13.00%) - 5 (5.00%) high mild - 8 (8.00%) high severe - -conv_u64_f32 compiler-builtins - time: [847.95 ns 848.19 ns 848.46 ns] -Found 19 outliers among 100 measurements (19.00%) - 3 (3.00%) low mild - 9 (9.00%) high mild - 7 (7.00%) high severe - -conv_u64_f32 system time: [701.68 ns 701.95 ns 702.30 ns] -Found 10 outliers among 100 measurements (10.00%) - 4 (4.00%) high mild - 6 (6.00%) high severe - -conv_u64_f32 assembly (aarch64 unix) - time: [511.73 ns 512.43 ns 513.32 ns] -Found 6 outliers among 100 measurements (6.00%) - 6 (6.00%) high mild - -conv_u64_f64 compiler-builtins - time: [681.23 ns 682.55 ns 684.30 ns] -Found 18 outliers among 100 measurements (18.00%) - 1 (1.00%) high mild - 17 (17.00%) high severe - -conv_u64_f64 system time: [679.34 ns 679.57 ns 679.88 ns] -Found 18 outliers among 100 measurements (18.00%) - 1 (1.00%) low mild - 6 (6.00%) high mild - 11 (11.00%) high severe - -conv_u64_f64 assembly (aarch64 unix) - time: [509.90 ns 510.09 ns 510.30 ns] -Found 15 outliers among 100 measurements (15.00%) - 6 (6.00%) high mild - 9 (9.00%) high severe - -conv_u128_f32 compiler-builtins - time: [1.1368 µs 1.1372 µs 1.1377 µs] -Found 14 outliers among 100 measurements (14.00%) - 8 (8.00%) high mild - 6 (6.00%) high severe - -conv_u128_f32 system time: [1.4338 µs 1.4370 µs 1.4410 µs] -Found 7 outliers among 100 measurements (7.00%) - 2 (2.00%) high mild - 5 (5.00%) high severe - -conv_u128_f64 compiler-builtins - time: [1.0133 µs 1.0143 µs 1.0156 µs] -Found 16 outliers among 100 measurements (16.00%) - 2 (2.00%) high mild - 14 (14.00%) high severe - -conv_u128_f64 system time: [1.3473 µs 1.3530 µs 1.3600 µs] -Found 4 outliers among 100 measurements (4.00%) - 4 (4.00%) high mild - -conv_i32_f32 compiler-builtins - time: [906.53 ns 907.86 ns 909.23 ns] -Found 7 outliers among 100 measurements (7.00%) - 4 (4.00%) high mild - 3 (3.00%) high severe - -conv_i32_f32 system time: [914.53 ns 915.69 ns 917.01 ns] -Found 10 outliers among 100 measurements (10.00%) - 6 (6.00%) high mild - 4 (4.00%) high severe - -conv_i32_f32 assembly (aarch64 unix) - time: [464.55 ns 465.10 ns 465.83 ns] -Found 4 outliers among 100 measurements (4.00%) - 4 (4.00%) high mild - -conv_i32_f64 compiler-builtins - time: [617.63 ns 617.92 ns 618.27 ns] -Found 12 outliers among 100 measurements (12.00%) - 3 (3.00%) high mild - 9 (9.00%) high severe - -conv_i32_f64 system time: [622.83 ns 624.19 ns 625.61 ns] -Found 6 outliers among 100 measurements (6.00%) - 5 (5.00%) high mild - 1 (1.00%) high severe - -conv_i32_f64 assembly (aarch64 unix) - time: [465.24 ns 466.04 ns 466.95 ns] -Found 11 outliers among 100 measurements (11.00%) - 4 (4.00%) high mild - 7 (7.00%) high severe - -conv_i64_f32 compiler-builtins - time: [852.67 ns 853.92 ns 855.34 ns] -Found 11 outliers among 100 measurements (11.00%) - 3 (3.00%) high mild - 8 (8.00%) high severe - -conv_i64_f32 system time: [906.94 ns 908.04 ns 909.33 ns] -Found 15 outliers among 100 measurements (15.00%) - 2 (2.00%) high mild - 13 (13.00%) high severe - -conv_i64_f32 assembly (aarch64 unix) - time: [510.84 ns 511.27 ns 511.80 ns] -Found 8 outliers among 100 measurements (8.00%) - 3 (3.00%) high mild - 5 (5.00%) high severe - -conv_i64_f64 compiler-builtins - time: [932.35 ns 932.97 ns 933.76 ns] -Found 10 outliers among 100 measurements (10.00%) - 4 (4.00%) high mild - 6 (6.00%) high severe - -conv_i64_f64 system time: [955.91 ns 958.95 ns 962.05 ns] -Found 5 outliers among 100 measurements (5.00%) - 3 (3.00%) high mild - 2 (2.00%) high severe - -conv_i64_f64 assembly (aarch64 unix) - time: [510.19 ns 510.72 ns 511.44 ns] -Found 9 outliers among 100 measurements (9.00%) - 5 (5.00%) high mild - 4 (4.00%) high severe - -conv_i128_f32 compiler-builtins - time: [1.4248 µs 1.4285 µs 1.4323 µs] -Found 12 outliers among 100 measurements (12.00%) - 7 (7.00%) high mild - 5 (5.00%) high severe - -conv_i128_f32 system time: [1.6970 µs 1.7017 µs 1.7069 µs] -Found 5 outliers among 100 measurements (5.00%) - 3 (3.00%) high mild - 2 (2.00%) high severe - -conv_i128_f64 compiler-builtins - time: [1.3132 µs 1.3161 µs 1.3191 µs] -Found 2 outliers among 100 measurements (2.00%) - 1 (1.00%) high mild - 1 (1.00%) high severe - -conv_i128_f64 system time: [1.6071 µs 1.6100 µs 1.6133 µs] -Found 4 outliers among 100 measurements (4.00%) - 3 (3.00%) high mild - 1 (1.00%) high severe - -conv_f64_u32 compiler-builtins - time: [640.35 ns 641.00 ns 641.68 ns] -Found 6 outliers among 100 measurements (6.00%) - 4 (4.00%) high mild - 2 (2.00%) high severe - -conv_f64_u32 system time: [640.87 ns 641.63 ns 642.42 ns] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe - -conv_f64_u32 assembly (aarch64 unix) - time: [482.02 ns 482.67 ns 483.38 ns] -Found 1 outliers among 100 measurements (1.00%) - 1 (1.00%) high severe - -conv_f64_u64 compiler-builtins - time: [638.58 ns 638.98 ns 639.45 ns] -Found 15 outliers among 100 measurements (15.00%) - 1 (1.00%) high mild - 14 (14.00%) high severe - -conv_f64_u64 system time: [642.54 ns 644.07 ns 645.59 ns] -Found 4 outliers among 100 measurements (4.00%) - 3 (3.00%) high mild - 1 (1.00%) high severe - -conv_f64_u64 assembly (aarch64 unix) - time: [482.65 ns 483.70 ns 484.87 ns] -Found 1 outliers among 100 measurements (1.00%) - 1 (1.00%) high mild - -conv_f64_u128 compiler-builtins - time: [1.0631 µs 1.0652 µs 1.0674 µs] -Found 8 outliers among 100 measurements (8.00%) - 7 (7.00%) high mild - 1 (1.00%) high severe - -conv_f64_u128 system time: [821.41 ns 823.45 ns 825.74 ns] -Found 11 outliers among 100 measurements (11.00%) - 8 (8.00%) high mild - 3 (3.00%) high severe - -conv_f64_i32 compiler-builtins - time: [826.76 ns 845.08 ns 870.23 ns] -Found 4 outliers among 100 measurements (4.00%) - 4 (4.00%) high mild - -conv_f64_i32 system time: [764.12 ns 764.63 ns 765.26 ns] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high severe - -conv_f64_i32 assembly (aarch64 unix) - time: [484.50 ns 485.98 ns 487.54 ns] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe - -conv_f64_i64 compiler-builtins - time: [797.27 ns 798.19 ns 799.84 ns] -Found 9 outliers among 100 measurements (9.00%) - 5 (5.00%) high mild - 4 (4.00%) high severe - -conv_f64_i64 system time: [768.74 ns 769.52 ns 770.23 ns] -Found 1 outliers among 100 measurements (1.00%) - 1 (1.00%) high severe - -conv_f64_i64 assembly (aarch64 unix) - time: [480.59 ns 481.03 ns 481.46 ns] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe - -conv_f64_i128 compiler-builtins - time: [1.0577 µs 1.0591 µs 1.0606 µs] -Found 2 outliers among 100 measurements (2.00%) - 1 (1.00%) high mild - 1 (1.00%) high severe - -conv_f64_i128 system time: [1.0181 µs 1.0195 µs 1.0211 µs] -Found 3 outliers among 100 measurements (3.00%) - 3 (3.00%) high mild - -conv_f32_u32 compiler-builtins - time: [800.40 ns 801.39 ns 802.35 ns] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high mild - -conv_f32_u32 system time: [638.12 ns 638.34 ns 638.63 ns] -Found 11 outliers among 100 measurements (11.00%) - 4 (4.00%) high mild - 7 (7.00%) high severe - -conv_f32_u32 assembly (aarch64 unix) - time: [479.37 ns 480.97 ns 483.32 ns] -Found 13 outliers among 100 measurements (13.00%) - 6 (6.00%) high mild - 7 (7.00%) high severe - -conv_f32_u64 compiler-builtins - time: [801.95 ns 803.64 ns 805.75 ns] - -conv_f32_u64 system time: [638.20 ns 638.56 ns 639.07 ns] -Found 10 outliers among 100 measurements (10.00%) - 1 (1.00%) high mild - 9 (9.00%) high severe - -conv_f32_u64 assembly (aarch64 unix) - time: [480.07 ns 480.47 ns 480.86 ns] -Found 2 outliers among 100 measurements (2.00%) - 1 (1.00%) high mild - 1 (1.00%) high severe - -conv_f32_u128 compiler-builtins - time: [1.1579 µs 1.1623 µs 1.1657 µs] -Found 14 outliers among 100 measurements (14.00%) - 2 (2.00%) low severe - 7 (7.00%) high mild - 5 (5.00%) high severe - -conv_f32_u128 system time: [1.0344 µs 1.0394 µs 1.0450 µs] - -conv_f32_i32 compiler-builtins - time: [800.14 ns 801.52 ns 803.26 ns] -Found 10 outliers among 100 measurements (10.00%) - 8 (8.00%) high mild - 2 (2.00%) high severe - -conv_f32_i32 system time: [741.36 ns 741.74 ns 742.13 ns] -Found 4 outliers among 100 measurements (4.00%) - 2 (2.00%) high mild - 2 (2.00%) high severe - -conv_f32_i32 assembly (aarch64 unix) - time: [484.35 ns 486.08 ns 488.11 ns] -Found 17 outliers among 100 measurements (17.00%) - 9 (9.00%) high mild - 8 (8.00%) high severe - -conv_f32_i64 compiler-builtins - time: [800.94 ns 802.68 ns 804.74 ns] - -conv_f32_i64 system time: [748.60 ns 750.68 ns 753.16 ns] -Found 9 outliers among 100 measurements (9.00%) - 4 (4.00%) high mild - 5 (5.00%) high severe - -conv_f32_i64 assembly (aarch64 unix) - time: [480.70 ns 481.23 ns 481.82 ns] -Found 4 outliers among 100 measurements (4.00%) - 2 (2.00%) high mild - 2 (2.00%) high severe - -conv_f32_i128 compiler-builtins - time: [1.1774 µs 1.1829 µs 1.1887 µs] -Found 11 outliers among 100 measurements (11.00%) - 1 (1.00%) low severe - 7 (7.00%) low mild - 1 (1.00%) high mild - 2 (2.00%) high severe - -conv_f32_i128 system time: [1.1785 µs 1.1853 µs 1.1941 µs] -Found 7 outliers among 100 measurements (7.00%) - 2 (2.00%) high mild - 5 (5.00%) high severe - -div_f32 compiler-builtins - time: [38.852 µs 39.011 µs 39.178 µs] -Found 3 outliers among 100 measurements (3.00%) - 3 (3.00%) high mild - -div_f32 system time: [41.846 µs 41.920 µs 42.005 µs] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe - -div_f32 assembly (aarch64 unix) - time: [8.1309 µs 8.1627 µs 8.2005 µs] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high mild - -div_f64 compiler-builtins - time: [50.369 µs 50.605 µs 50.857 µs] -Found 15 outliers among 100 measurements (15.00%) - 11 (11.00%) high mild - 4 (4.00%) high severe - -div_f64 system time: [53.506 µs 53.582 µs 53.676 µs] -Found 8 outliers among 100 measurements (8.00%) - 4 (4.00%) high mild - 4 (4.00%) high severe - -div_f64 assembly (aarch64 unix) - time: [8.0695 µs 8.0807 µs 8.0948 µs] -Found 4 outliers among 100 measurements (4.00%) - 2 (2.00%) high mild - 2 (2.00%) high severe - diff --git a/library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt b/library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt deleted file mode 100644 index 131e7a85a0b..00000000000 --- a/library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt +++ /dev/null @@ -1,699 +0,0 @@ - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s - -add_f32/compiler-builtins - time: [36.813 µs 37.048 µs 37.303 µs] -Found 5 outliers among 100 measurements (5.00%) - 5 (5.00%) high mild -add_f32/system time: [39.103 µs 39.142 µs 39.189 µs] -Found 8 outliers among 100 measurements (8.00%) - 2 (2.00%) high mild - 6 (6.00%) high severe -add_f32/assembly (aarch64 unix) - time: [8.3786 µs 8.4680 µs 8.5570 µs] - -add_f64/compiler-builtins - time: [35.784 µs 35.819 µs 35.863 µs] -Found 4 outliers among 100 measurements (4.00%) - 1 (1.00%) high mild - 3 (3.00%) high severe -add_f64/system time: [39.634 µs 39.689 µs 39.746 µs] -Found 16 outliers among 100 measurements (16.00%) - 4 (4.00%) high mild - 12 (12.00%) high severe -add_f64/assembly (aarch64 unix) - time: [8.0533 µs 8.0599 µs 8.0670 µs] -Found 14 outliers among 100 measurements (14.00%) - 6 (6.00%) high mild - 8 (8.00%) high severe - -add_f128/compiler-builtins - time: [41.830 µs 41.920 µs 42.005 µs] - -cmp_f32_gt/compiler-builtins - time: [13.405 µs 13.411 µs 13.418 µs] -Found 18 outliers among 100 measurements (18.00%) - 4 (4.00%) high mild - 14 (14.00%) high severe -cmp_f32_gt/system time: [12.348 µs 12.355 µs 12.363 µs] -Found 12 outliers among 100 measurements (12.00%) - 2 (2.00%) high mild - 10 (10.00%) high severe -cmp_f32_gt/assembly (aarch64 unix) - time: [8.1233 µs 8.1625 µs 8.2072 µs] -Found 12 outliers among 100 measurements (12.00%) - 7 (7.00%) high mild - 5 (5.00%) high severe - -cmp_f32_unord/compiler-builtins - time: [11.349 µs 11.467 µs 11.584 µs] -cmp_f32_unord/system time: [8.0714 µs 8.0792 µs 8.0890 µs] -Found 16 outliers among 100 measurements (16.00%) - 4 (4.00%) high mild - 12 (12.00%) high severe -cmp_f32_unord/assembly (aarch64 unix) - time: [8.1121 µs 8.1705 µs 8.2325 µs] -Found 20 outliers among 100 measurements (20.00%) - 3 (3.00%) high mild - 17 (17.00%) high severe - -cmp_f64_gt/compiler-builtins - time: [13.749 µs 13.837 µs 13.934 µs] -Found 20 outliers among 100 measurements (20.00%) - 9 (9.00%) low mild - 7 (7.00%) high mild - 4 (4.00%) high severe -cmp_f64_gt/system time: [12.475 µs 12.515 µs 12.565 µs] -Found 4 outliers among 100 measurements (4.00%) - 4 (4.00%) high mild -cmp_f64_gt/assembly (aarch64 unix) - time: [8.0456 µs 8.0540 µs 8.0653 µs] -Found 12 outliers among 100 measurements (12.00%) - 3 (3.00%) high mild - 9 (9.00%) high severe - -cmp_f64_unord/compiler-builtins - time: [10.723 µs 10.730 µs 10.739 µs] -Found 15 outliers among 100 measurements (15.00%) - 5 (5.00%) high mild - 10 (10.00%) high severe -cmp_f64_unord/system time: [8.0944 µs 8.1296 µs 8.1683 µs] -Found 17 outliers among 100 measurements (17.00%) - 4 (4.00%) high mild - 13 (13.00%) high severe -cmp_f64_unord/assembly (aarch64 unix) - time: [8.1042 µs 8.1337 µs 8.1662 µs] -Found 3 outliers among 100 measurements (3.00%) - 3 (3.00%) high mild - -cmp_f128_gt/compiler-builtins - time: [20.508 µs 20.558 µs 20.615 µs] -Found 8 outliers among 100 measurements (8.00%) - 2 (2.00%) high mild - 6 (6.00%) high severe - -cmp_f128_unord/compiler-builtins - time: [13.332 µs 13.346 µs 13.360 µs] -Found 4 outliers among 100 measurements (4.00%) - 2 (2.00%) high mild - 2 (2.00%) high severe - -conv_u32_f32/compiler-builtins - time: [621.20 ns 621.89 ns 622.65 ns] -Found 7 outliers among 100 measurements (7.00%) - 4 (4.00%) high mild - 3 (3.00%) high severe -conv_u32_f32/system time: [621.44 ns 622.08 ns 622.74 ns] -Found 4 outliers among 100 measurements (4.00%) - 3 (3.00%) high mild - 1 (1.00%) high severe -conv_u32_f32/assembly (aarch64 unix) - time: [465.96 ns 466.65 ns 467.45 ns] -Found 13 outliers among 100 measurements (13.00%) - 3 (3.00%) high mild - 10 (10.00%) high severe - -conv_u32_f64/compiler-builtins - time: [619.71 ns 620.51 ns 621.52 ns] -Found 5 outliers among 100 measurements (5.00%) - 4 (4.00%) high mild - 1 (1.00%) high severe -conv_u32_f64/system time: [466.60 ns 467.14 ns 467.77 ns] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high mild -conv_u32_f64/assembly (aarch64 unix) - time: [464.02 ns 464.32 ns 464.69 ns] -Found 2 outliers among 100 measurements (2.00%) - 1 (1.00%) high mild - 1 (1.00%) high severe - -conv_u64_f32/compiler-builtins - time: [851.24 ns 852.98 ns 854.77 ns] -Found 5 outliers among 100 measurements (5.00%) - 5 (5.00%) high mild -conv_u64_f32/system time: [724.35 ns 729.43 ns 735.07 ns] -Found 4 outliers among 100 measurements (4.00%) - 4 (4.00%) high mild -conv_u64_f32/assembly (aarch64 unix) - time: [513.30 ns 514.64 ns 516.16 ns] -Found 8 outliers among 100 measurements (8.00%) - 8 (8.00%) high mild - -conv_u64_f64/compiler-builtins - time: [850.72 ns 853.26 ns 856.54 ns] -Found 15 outliers among 100 measurements (15.00%) - 2 (2.00%) high mild - 13 (13.00%) high severe -conv_u64_f64/system time: [681.43 ns 682.54 ns 683.79 ns] -Found 4 outliers among 100 measurements (4.00%) - 3 (3.00%) high mild - 1 (1.00%) high severe -conv_u64_f64/assembly (aarch64 unix) - time: [511.37 ns 511.71 ns 512.02 ns] -Found 1 outliers among 100 measurements (1.00%) - 1 (1.00%) high severe - -conv_u128_f32/compiler-builtins - time: [1.1395 µs 1.1409 µs 1.1424 µs] -Found 10 outliers among 100 measurements (10.00%) - 6 (6.00%) high mild - 4 (4.00%) high severe -conv_u128_f32/system time: [1.4348 µs 1.4369 µs 1.4390 µs] -Found 5 outliers among 100 measurements (5.00%) - 4 (4.00%) high mild - 1 (1.00%) high severe - -conv_u128_f64/compiler-builtins - time: [1.0148 µs 1.0157 µs 1.0167 µs] -Found 4 outliers among 100 measurements (4.00%) - 3 (3.00%) high mild - 1 (1.00%) high severe -conv_u128_f64/system time: [1.3404 µs 1.3423 µs 1.3442 µs] -Found 8 outliers among 100 measurements (8.00%) - 7 (7.00%) high mild - 1 (1.00%) high severe - -conv_i32_f32/compiler-builtins - time: [902.89 ns 903.81 ns 904.84 ns] -Found 7 outliers among 100 measurements (7.00%) - 4 (4.00%) high mild - 3 (3.00%) high severe -conv_i32_f32/system time: [942.62 ns 949.04 ns 955.77 ns] -Found 4 outliers among 100 measurements (4.00%) - 3 (3.00%) high mild - 1 (1.00%) high severe -conv_i32_f32/assembly (aarch64 unix) - time: [466.06 ns 466.60 ns 467.27 ns] -Found 1 outliers among 100 measurements (1.00%) - 1 (1.00%) high severe - -conv_i32_f64/compiler-builtins - time: [618.98 ns 619.24 ns 619.55 ns] -Found 17 outliers among 100 measurements (17.00%) - 1 (1.00%) low mild - 3 (3.00%) high mild - 13 (13.00%) high severe -conv_i32_f64/system time: [622.18 ns 623.41 ns 624.85 ns] -Found 8 outliers among 100 measurements (8.00%) - 5 (5.00%) high mild - 3 (3.00%) high severe -conv_i32_f64/assembly (aarch64 unix) - time: [466.26 ns 466.76 ns 467.35 ns] -Found 9 outliers among 100 measurements (9.00%) - 5 (5.00%) high mild - 4 (4.00%) high severe - -conv_i64_f32/compiler-builtins - time: [850.11 ns 850.45 ns 850.88 ns] -Found 15 outliers among 100 measurements (15.00%) - 1 (1.00%) low severe - 1 (1.00%) low mild - 3 (3.00%) high mild - 10 (10.00%) high severe -conv_i64_f32/system time: [908.36 ns 908.70 ns 909.10 ns] -Found 12 outliers among 100 measurements (12.00%) - 3 (3.00%) high mild - 9 (9.00%) high severe -conv_i64_f32/assembly (aarch64 unix) - time: [513.56 ns 514.44 ns 515.38 ns] -Found 8 outliers among 100 measurements (8.00%) - 8 (8.00%) high mild - -conv_i64_f64/compiler-builtins - time: [935.39 ns 935.78 ns 936.26 ns] -Found 13 outliers among 100 measurements (13.00%) - 5 (5.00%) high mild - 8 (8.00%) high severe -conv_i64_f64/system time: [946.56 ns 947.33 ns 948.20 ns] -Found 8 outliers among 100 measurements (8.00%) - 6 (6.00%) high mild - 2 (2.00%) high severe -conv_i64_f64/assembly (aarch64 unix) - time: [511.55 ns 512.03 ns 512.56 ns] -Found 21 outliers among 100 measurements (21.00%) - 4 (4.00%) high mild - 17 (17.00%) high severe - -conv_i128_f32/compiler-builtins - time: [1.4206 µs 1.4218 µs 1.4232 µs] -Found 10 outliers among 100 measurements (10.00%) - 5 (5.00%) high mild - 5 (5.00%) high severe -conv_i128_f32/system time: [1.6863 µs 1.6891 µs 1.6922 µs] -Found 10 outliers among 100 measurements (10.00%) - 9 (9.00%) high mild - 1 (1.00%) high severe - -conv_i128_f64/compiler-builtins - time: [1.3110 µs 1.3122 µs 1.3136 µs] -Found 4 outliers among 100 measurements (4.00%) - 2 (2.00%) high mild - 2 (2.00%) high severe -conv_i128_f64/system time: [1.6022 µs 1.6048 µs 1.6090 µs] -Found 5 outliers among 100 measurements (5.00%) - 3 (3.00%) high mild - 2 (2.00%) high severe - -conv_f64_u32/compiler-builtins - time: [798.65 ns 799.42 ns 800.39 ns] -Found 15 outliers among 100 measurements (15.00%) - 6 (6.00%) high mild - 9 (9.00%) high severe -conv_f64_u32/system time: [639.48 ns 639.88 ns 640.40 ns] -Found 16 outliers among 100 measurements (16.00%) - 1 (1.00%) low mild - 5 (5.00%) high mild - 10 (10.00%) high severe -conv_f64_u32/assembly (aarch64 unix) - time: [480.78 ns 481.35 ns 482.17 ns] -Found 7 outliers among 100 measurements (7.00%) - 5 (5.00%) high mild - 2 (2.00%) high severe - -conv_f64_u64/compiler-builtins - time: [799.56 ns 800.54 ns 801.89 ns] -Found 4 outliers among 100 measurements (4.00%) - 2 (2.00%) high mild - 2 (2.00%) high severe -conv_f64_u64/system time: [640.72 ns 641.24 ns 641.81 ns] -Found 5 outliers among 100 measurements (5.00%) - 3 (3.00%) high mild - 2 (2.00%) high severe -conv_f64_u64/assembly (aarch64 unix) - time: [481.54 ns 482.48 ns 483.53 ns] -Found 6 outliers among 100 measurements (6.00%) - 1 (1.00%) low severe - 1 (1.00%) low mild - 3 (3.00%) high mild - 1 (1.00%) high severe - -conv_f64_u128/compiler-builtins - time: [1.0510 µs 1.0515 µs 1.0520 µs] -Found 13 outliers among 100 measurements (13.00%) - 1 (1.00%) low mild - 2 (2.00%) high mild - 10 (10.00%) high severe -conv_f64_u128/system time: [818.45 ns 819.23 ns 820.15 ns] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high mild - -conv_f64_i32/compiler-builtins - time: [800.56 ns 801.31 ns 802.21 ns] -Found 5 outliers among 100 measurements (5.00%) - 3 (3.00%) high mild - 2 (2.00%) high severe -conv_f64_i32/system time: [765.62 ns 766.15 ns 766.80 ns] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe -conv_f64_i32/assembly (aarch64 unix) - time: [471.65 ns 472.77 ns 473.89 ns] -Found 10 outliers among 100 measurements (10.00%) - 1 (1.00%) low mild - 8 (8.00%) high mild - 1 (1.00%) high severe - -conv_f64_i64/compiler-builtins - time: [801.00 ns 804.55 ns 808.72 ns] -Found 18 outliers among 100 measurements (18.00%) - 6 (6.00%) high mild - 12 (12.00%) high severe -conv_f64_i64/system time: [770.28 ns 772.47 ns 775.21 ns] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high mild -conv_f64_i64/assembly (aarch64 unix) - time: [491.56 ns 494.96 ns 499.19 ns] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe - -conv_f64_i128/compiler-builtins - time: [1.0637 µs 1.0704 µs 1.0762 µs] -Found 5 outliers among 100 measurements (5.00%) - 5 (5.00%) high mild -conv_f64_i128/system time: [1.0022 µs 1.0027 µs 1.0033 µs] -Found 4 outliers among 100 measurements (4.00%) - 1 (1.00%) low severe - 3 (3.00%) high severe - -conv_f32_u32/compiler-builtins - time: [644.56 ns 647.01 ns 649.95 ns] -Found 15 outliers among 100 measurements (15.00%) - 13 (13.00%) high mild - 2 (2.00%) high severe -conv_f32_u32/system time: [648.12 ns 651.20 ns 654.54 ns] -Found 9 outliers among 100 measurements (9.00%) - 7 (7.00%) high mild - 2 (2.00%) high severe -conv_f32_u32/assembly (aarch64 unix) - time: [481.02 ns 482.71 ns 484.60 ns] -Found 12 outliers among 100 measurements (12.00%) - 1 (1.00%) low mild - 10 (10.00%) high mild - 1 (1.00%) high severe - -conv_f32_u64/compiler-builtins - time: [644.14 ns 646.61 ns 649.53 ns] -Found 11 outliers among 100 measurements (11.00%) - 6 (6.00%) high mild - 5 (5.00%) high severe -conv_f32_u64/system time: [646.21 ns 650.17 ns 654.55 ns] -Found 3 outliers among 100 measurements (3.00%) - 3 (3.00%) high mild -conv_f32_u64/assembly (aarch64 unix) - time: [473.36 ns 474.60 ns 476.00 ns] -Found 9 outliers among 100 measurements (9.00%) - 2 (2.00%) low mild - 5 (5.00%) high mild - 2 (2.00%) high severe - -conv_f32_u128/compiler-builtins - time: [1.0820 µs 1.0828 µs 1.0839 µs] -Found 2 outliers among 100 measurements (2.00%) - 1 (1.00%) high mild - 1 (1.00%) high severe -conv_f32_u128/system time: [1.0003 µs 1.0042 µs 1.0076 µs] -Found 21 outliers among 100 measurements (21.00%) - 1 (1.00%) low mild - 3 (3.00%) high mild - 17 (17.00%) high severe - -conv_f32_i32/compiler-builtins - time: [801.13 ns 801.82 ns 802.53 ns] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high severe -conv_f32_i32/system time: [745.17 ns 745.97 ns 746.78 ns] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high severe -conv_f32_i32/assembly (aarch64 unix) - time: [469.87 ns 470.65 ns 471.57 ns] -Found 1 outliers among 100 measurements (1.00%) - 1 (1.00%) high mild - -conv_f32_i64/compiler-builtins - time: [799.44 ns 799.94 ns 800.59 ns] -Found 4 outliers among 100 measurements (4.00%) - 1 (1.00%) high mild - 3 (3.00%) high severe -conv_f32_i64/system time: [744.81 ns 745.17 ns 745.62 ns] -Found 14 outliers among 100 measurements (14.00%) - 5 (5.00%) high mild - 9 (9.00%) high severe -conv_f32_i64/assembly (aarch64 unix) - time: [465.06 ns 466.01 ns 467.12 ns] -Found 13 outliers among 100 measurements (13.00%) - 2 (2.00%) low severe - 5 (5.00%) high mild - 6 (6.00%) high severe - -conv_f32_i128/compiler-builtins - time: [1.1390 µs 1.1515 µs 1.1637 µs] -conv_f32_i128/system time: [1.1315 µs 1.1330 µs 1.1347 µs] -Found 6 outliers among 100 measurements (6.00%) - 3 (3.00%) low mild - 2 (2.00%) high mild - 1 (1.00%) high severe - -div_f32/compiler-builtins - time: [39.408 µs 39.676 µs 39.969 µs] -Found 5 outliers among 100 measurements (5.00%) - 5 (5.00%) high mild -div_f32/system time: [42.108 µs 42.248 µs 42.528 µs] -Found 11 outliers among 100 measurements (11.00%) - 4 (4.00%) high mild - 7 (7.00%) high severe -div_f32/assembly (aarch64 unix) - time: [8.0724 µs 8.0794 µs 8.0870 µs] -Found 7 outliers among 100 measurements (7.00%) - 5 (5.00%) high mild - 2 (2.00%) high severe - -div_f64/compiler-builtins - time: [49.992 µs 50.014 µs 50.040 µs] -Found 5 outliers among 100 measurements (5.00%) - 5 (5.00%) high severe -div_f64/system time: [53.577 µs 53.651 µs 53.743 µs] -Found 6 outliers among 100 measurements (6.00%) - 4 (4.00%) high mild - 2 (2.00%) high severe -div_f64/assembly (aarch64 unix) - time: [8.0976 µs 8.1064 µs 8.1158 µs] -Found 6 outliers among 100 measurements (6.00%) - 3 (3.00%) high mild - 3 (3.00%) high severe - -extend_f16_f32/compiler-builtins - time: [804.09 ns 805.38 ns 807.09 ns] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe -extend_f16_f32/system time: [641.07 ns 641.76 ns 642.60 ns] -Found 12 outliers among 100 measurements (12.00%) - 6 (6.00%) high mild - 6 (6.00%) high severe -extend_f16_f32/assembly (aarch64 unix) - time: [456.69 ns 457.14 ns 457.68 ns] -Found 8 outliers among 100 measurements (8.00%) - 4 (4.00%) low mild - 2 (2.00%) high mild - 2 (2.00%) high severe - -extend_f16_f128/compiler-builtins - time: [1.1025 µs 1.1035 µs 1.1045 µs] -Found 2 outliers among 100 measurements (2.00%) - 1 (1.00%) high mild - 1 (1.00%) high severe - -extend_f32_f64/compiler-builtins - time: [799.30 ns 799.68 ns 800.16 ns] -Found 13 outliers among 100 measurements (13.00%) - 3 (3.00%) high mild - 10 (10.00%) high severe -extend_f32_f64/system time: [992.48 ns 993.27 ns 994.32 ns] -Found 15 outliers among 100 measurements (15.00%) - 3 (3.00%) high mild - 12 (12.00%) high severe -extend_f32_f64/assembly (aarch64 unix) - time: [457.65 ns 460.39 ns 463.78 ns] - -extend_f32_f128/compiler-builtins - time: [1.0295 µs 1.0311 µs 1.0327 µs] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) low mild - 1 (1.00%) high mild - -extend_f64_f128/compiler-builtins - time: [1.0400 µs 1.0412 µs 1.0426 µs] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high mild - -mul_f32/compiler-builtins - time: [25.604 µs 25.705 µs 25.818 µs] -Found 23 outliers among 100 measurements (23.00%) - 17 (17.00%) low severe - 3 (3.00%) high mild - 3 (3.00%) high severe -mul_f32/system time: [29.914 µs 29.977 µs 30.043 µs] -Found 5 outliers among 100 measurements (5.00%) - 5 (5.00%) high mild -mul_f32/assembly (aarch64 unix) - time: [8.1384 µs 8.1964 µs 8.2603 µs] -Found 13 outliers among 100 measurements (13.00%) - 3 (3.00%) high mild - 10 (10.00%) high severe - -mul_f64/compiler-builtins - time: [25.596 µs 25.615 µs 25.637 µs] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe -mul_f64/system time: [30.931 µs 30.963 µs 31.002 µs] -Found 3 outliers among 100 measurements (3.00%) - 3 (3.00%) high mild -mul_f64/assembly (aarch64 unix) - time: [8.0589 µs 8.0638 µs 8.0695 µs] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe - -mul_f128/compiler-builtins - time: [54.242 µs 54.306 µs 54.374 µs] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe - -powi_f32/compiler-builtins - time: [129.91 µs 130.09 µs 130.24 µs] -powi_f32/system time: [126.97 µs 127.34 µs 127.82 µs] -Found 4 outliers among 100 measurements (4.00%) - 3 (3.00%) high mild - 1 (1.00%) high severe - -powi_f64/compiler-builtins - time: [130.08 µs 130.81 µs 131.46 µs] -Found 13 outliers among 100 measurements (13.00%) - 13 (13.00%) high mild -powi_f64/system time: [128.51 µs 128.68 µs 128.88 µs] -Found 21 outliers among 100 measurements (21.00%) - 4 (4.00%) high mild - 17 (17.00%) high severe - -sub_f32/compiler-builtins - time: [37.861 µs 38.012 µs 38.158 µs] -Found 26 outliers among 100 measurements (26.00%) - 18 (18.00%) low mild - 7 (7.00%) high mild - 1 (1.00%) high severe -sub_f32/system time: [39.586 µs 39.628 µs 39.673 µs] -Found 2 outliers among 100 measurements (2.00%) - 1 (1.00%) high mild - 1 (1.00%) high severe -sub_f32/assembly (aarch64 unix) - time: [8.0976 µs 8.1584 µs 8.2208 µs] -Found 6 outliers among 100 measurements (6.00%) - 6 (6.00%) high mild - -sub_f64/compiler-builtins - time: [37.755 µs 37.838 µs 37.921 µs] -Found 25 outliers among 100 measurements (25.00%) - 7 (7.00%) low severe - 3 (3.00%) low mild - 4 (4.00%) high mild - 11 (11.00%) high severe -sub_f64/system time: [39.979 µs 40.019 µs 40.064 µs] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe -sub_f64/assembly (aarch64 unix) - time: [8.0669 µs 8.0733 µs 8.0801 µs] -Found 7 outliers among 100 measurements (7.00%) - 3 (3.00%) high mild - 4 (4.00%) high severe - -sub_f128/compiler-builtins - time: [68.618 µs 68.899 µs 69.293 µs] -Found 11 outliers among 100 measurements (11.00%) - 2 (2.00%) high mild - 9 (9.00%) high severe - -trunc_f32_f16/compiler-builtins - time: [1.3343 µs 1.3468 µs 1.3608 µs] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe -trunc_f32_f16/system time: [1.2687 µs 1.2714 µs 1.2738 µs] -trunc_f32_f16/assembly (aarch64 unix) - time: [470.06 ns 472.96 ns 475.30 ns] - -trunc_f64_f16/compiler-builtins - time: [1.2729 µs 1.2738 µs 1.2749 µs] -Found 7 outliers among 100 measurements (7.00%) - 2 (2.00%) high mild - 5 (5.00%) high severe -trunc_f64_f16/assembly (aarch64 unix) - time: [455.91 ns 456.61 ns 457.33 ns] -Found 12 outliers among 100 measurements (12.00%) - 1 (1.00%) low severe - 2 (2.00%) low mild - 6 (6.00%) high mild - 3 (3.00%) high severe - -trunc_f64_f32/compiler-builtins - time: [1.2240 µs 1.2325 µs 1.2410 µs] -Found 17 outliers among 100 measurements (17.00%) - 4 (4.00%) low mild - 2 (2.00%) high mild - 11 (11.00%) high severe -trunc_f64_f32/system time: [1.2784 µs 1.2835 µs 1.2884 µs] -Found 10 outliers among 100 measurements (10.00%) - 6 (6.00%) low severe - 1 (1.00%) low mild - 2 (2.00%) high mild - 1 (1.00%) high severe -trunc_f64_f32/assembly (aarch64 unix) - time: [455.64 ns 456.08 ns 456.58 ns] -Found 18 outliers among 100 measurements (18.00%) - 3 (3.00%) low severe - 4 (4.00%) low mild - 8 (8.00%) high mild - 3 (3.00%) high severe - -trunc_f128_f16/compiler-builtins - time: [1.2563 µs 1.2666 µs 1.2776 µs] -Found 3 outliers among 100 measurements (3.00%) - 3 (3.00%) high mild - -trunc_f128_f32/compiler-builtins - time: [1.2459 µs 1.2482 µs 1.2507 µs] -Found 6 outliers among 100 measurements (6.00%) - 2 (2.00%) low mild - 2 (2.00%) high mild - 2 (2.00%) high severe - -trunc_f128_f64/compiler-builtins - time: [1.2821 µs 1.3047 µs 1.3452 µs] -Found 8 outliers among 100 measurements (8.00%) - 4 (4.00%) low severe - 1 (1.00%) low mild - 2 (2.00%) high mild - 1 (1.00%) high severe - - -running 52 tests -test memcmp_builtin_1048576 ... bench: 20,975.52 ns/iter (+/- 239.69) = 49991 MB/s -test memcmp_builtin_16 ... bench: 1.60 ns/iter (+/- 0.05) = 16000 MB/s -test memcmp_builtin_32 ... bench: 1.61 ns/iter (+/- 0.03) = 32000 MB/s -test memcmp_builtin_4096 ... bench: 95.84 ns/iter (+/- 2.82) = 43115 MB/s -test memcmp_builtin_64 ... bench: 2.39 ns/iter (+/- 0.09) = 32000 MB/s -test memcmp_builtin_8 ... bench: 1.60 ns/iter (+/- 0.04) = 8000 MB/s -test memcmp_builtin_unaligned_1048575 ... bench: 22,060.00 ns/iter (+/- 873.55) = 47532 MB/s -test memcmp_builtin_unaligned_15 ... bench: 3.19 ns/iter (+/- 0.02) = 5333 MB/s -test memcmp_builtin_unaligned_31 ... bench: 1.61 ns/iter (+/- 0.01) = 32000 MB/s -test memcmp_builtin_unaligned_4095 ... bench: 96.63 ns/iter (+/- 4.58) = 42666 MB/s -test memcmp_builtin_unaligned_63 ... bench: 2.40 ns/iter (+/- 0.11) = 32000 MB/s -test memcmp_builtin_unaligned_7 ... bench: 3.37 ns/iter (+/- 0.05) = 2666 MB/s -test memcmp_rust_1048576 ... bench: 309,647.23 ns/iter (+/- 6,077.35) = 3386 MB/s -test memcmp_rust_16 ... bench: 5.66 ns/iter (+/- 0.30) = 3200 MB/s -test memcmp_rust_32 ... bench: 10.47 ns/iter (+/- 0.14) = 3200 MB/s -test memcmp_rust_4096 ... bench: 1,124.34 ns/iter (+/- 36.92) = 3644 MB/s -test memcmp_rust_64 ... bench: 19.90 ns/iter (+/- 0.36) = 3368 MB/s -test memcmp_rust_8 ... bench: 3.46 ns/iter (+/- 0.11) = 2666 MB/s -test memcmp_rust_unaligned_1048575 ... bench: 308,613.87 ns/iter (+/- 6,613.18) = 3397 MB/s -test memcmp_rust_unaligned_15 ... bench: 5.35 ns/iter (+/- 0.05) = 3200 MB/s -test memcmp_rust_unaligned_31 ... bench: 9.94 ns/iter (+/- 0.06) = 3555 MB/s -test memcmp_rust_unaligned_4095 ... bench: 1,120.06 ns/iter (+/- 5.03) = 3657 MB/s -test memcmp_rust_unaligned_63 ... bench: 19.64 ns/iter (+/- 0.82) = 3368 MB/s -test memcmp_rust_unaligned_7 ... bench: 3.22 ns/iter (+/- 0.10) = 2666 MB/s -test memcpy_builtin_1048576 ... bench: 12,538.05 ns/iter (+/- 354.79) = 83631 MB/s -test memcpy_builtin_1048576_misalign ... bench: 30,092.56 ns/iter (+/- 8,064.04) = 34845 MB/s -test memcpy_builtin_1048576_offset ... bench: 12,538.36 ns/iter (+/- 359.04) = 83631 MB/s -test memcpy_builtin_4096 ... bench: 44.24 ns/iter (+/- 6.80) = 93090 MB/s -test memcpy_builtin_4096_misalign ... bench: 45.34 ns/iter (+/- 2.13) = 91022 MB/s -test memcpy_builtin_4096_offset ... bench: 44.71 ns/iter (+/- 0.61) = 93090 MB/s -test memcpy_rust_1048576 ... bench: 17,943.33 ns/iter (+/- 243.18) = 58439 MB/s -test memcpy_rust_1048576_misalign ... bench: 15,004.68 ns/iter (+/- 3,978.65) = 69886 MB/s -test memcpy_rust_1048576_offset ... bench: 14,722.06 ns/iter (+/- 479.54) = 71225 MB/s -test memcpy_rust_4096 ... bench: 44.91 ns/iter (+/- 4.62) = 93090 MB/s -test memcpy_rust_4096_misalign ... bench: 76.21 ns/iter (+/- 8.21) = 53894 MB/s -test memcpy_rust_4096_offset ... bench: 76.27 ns/iter (+/- 4.69) = 53894 MB/s -test memmove_builtin_1048576 ... bench: 18,644.50 ns/iter (+/- 379.84) = 56242 MB/s -test memmove_builtin_1048576_misalign ... bench: 18,947.70 ns/iter (+/- 1,226.26) = 55342 MB/s -test memmove_builtin_4096 ... bench: 44.21 ns/iter (+/- 0.79) = 93090 MB/s -test memmove_builtin_4096_misalign ... bench: 47.21 ns/iter (+/- 3.12) = 87148 MB/s -test memmove_rust_1048576 ... bench: 34,813.33 ns/iter (+/- 3,637.47) = 30120 MB/s -test memmove_rust_1048576_misalign ... bench: 35,067.19 ns/iter (+/- 1,699.63) = 29902 MB/s -test memmove_rust_4096 ... bench: 148.69 ns/iter (+/- 1.31) = 27675 MB/s -test memmove_rust_4096_misalign ... bench: 153.81 ns/iter (+/- 1.71) = 26771 MB/s -test memset_builtin_1048576 ... bench: 15,704.12 ns/iter (+/- 12,113.86) = 66771 MB/s -test memset_builtin_1048576_offset ... bench: 17,894.23 ns/iter (+/- 175.12) = 58599 MB/s -test memset_builtin_4096 ... bench: 39.95 ns/iter (+/- 0.19) = 105025 MB/s -test memset_builtin_4096_offset ... bench: 40.48 ns/iter (+/- 3.11) = 102400 MB/s -test memset_rust_1048576 ... bench: 10,600.66 ns/iter (+/- 1,559.93) = 98922 MB/s -test memset_rust_1048576_offset ... bench: 14,810.85 ns/iter (+/- 575.27) = 70801 MB/s -test memset_rust_4096 ... bench: 37.91 ns/iter (+/- 2.77) = 110702 MB/s -test memset_rust_4096_offset ... bench: 59.99 ns/iter (+/- 10.45) = 69423 MB/s - -test result: ok. 0 passed; 0 failed; 0 ignored; 52 measured; 0 filtered out; finished in 97.74s - -- cgit 1.4.1-3-g733a5 From 98195c0348ebd5fdc90e45de3fd4d30a337ad2c8 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Tue, 25 Jun 2024 13:52:02 +0300 Subject: Get rid of a warning --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/build.rs | 2 -- library/compiler-builtins/crates/panic-handler/Cargo.toml | 1 + 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index ab43951593b..c8d78ec3e26 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -7,7 +7,7 @@ readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" homepage = "https://github.com/rust-lang/compiler-builtins" documentation = "https://docs.rs/compiler_builtins" -edition = "2018" +edition = "2021" description = """ Compiler intrinsics used by the Rust compiler. Also available for other targets if necessary! diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0ecd399118e..d7e3be59403 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -219,8 +219,6 @@ fn configure_check_cfg() { #[cfg(feature = "c")] mod c { - extern crate cc; - use std::collections::{BTreeMap, HashSet}; use std::env; use std::fs::{self, File}; diff --git a/library/compiler-builtins/crates/panic-handler/Cargo.toml b/library/compiler-builtins/crates/panic-handler/Cargo.toml index 1dea613d192..4fb81eb82a4 100644 --- a/library/compiler-builtins/crates/panic-handler/Cargo.toml +++ b/library/compiler-builtins/crates/panic-handler/Cargo.toml @@ -2,5 +2,6 @@ name = "panic-handler" version = "0.1.0" authors = ["Alex Crichton "] +edition = "2021" [dependencies] -- cgit 1.4.1-3-g733a5 From 45465cc488c02030575ef939b026d2e11530845b Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Sat, 22 Jun 2024 00:01:52 +0300 Subject: Implement __bswap[sdt]i2 intrinsics These can be emitted by gcc, at least if requested specifically via __builtin_bswap{32,64,128}. --- library/compiler-builtins/README.md | 3 ++ library/compiler-builtins/build.rs | 3 ++ library/compiler-builtins/src/int/bswap.rs | 22 +++++++++++++++ library/compiler-builtins/src/int/mod.rs | 1 + library/compiler-builtins/testcrate/tests/misc.rs | 34 +++++++++++++++++++++++ 5 files changed, 63 insertions(+) create mode 100644 library/compiler-builtins/src/int/bswap.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 9a847da3f69..a24c127392d 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -154,6 +154,9 @@ rely on CI. - [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c +- [x] bswapdi2.c +- [x] bswapsi2.c +- [x] bswapti2.c - [x] comparedf2.c - [x] comparesf2.c - [x] divdf3.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d7e3be59403..34467d8f54b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -161,6 +161,9 @@ fn configure_check_cfg() { "__ashlsi3", "__ashrdi3", "__ashrsi3", + "__bswapsi2", + "__bswapdi2", + "__bswapti2", "__clzsi2", "__divdi3", "__divsi3", diff --git a/library/compiler-builtins/src/int/bswap.rs b/library/compiler-builtins/src/int/bswap.rs new file mode 100644 index 00000000000..9df80204d0e --- /dev/null +++ b/library/compiler-builtins/src/int/bswap.rs @@ -0,0 +1,22 @@ +intrinsics! { + #[maybe_use_optimized_c_shim] + #[avr_skip] + /// Swaps bytes in 32-bit number + pub extern "C" fn __bswapsi2(x: u32) -> u32 { + x.swap_bytes() + } + + #[maybe_use_optimized_c_shim] + #[avr_skip] + /// Swaps bytes in 64-bit number + pub extern "C" fn __bswapdi2(x: u64) -> u64 { + x.swap_bytes() + } + + #[maybe_use_optimized_c_shim] + #[avr_skip] + /// Swaps bytes in 128-bit number + pub extern "C" fn __bswapti2(x: u128) -> u128 { + x.swap_bytes() + } +} diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 45d38388031..ddbffd74044 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -4,6 +4,7 @@ mod specialized_div_rem; pub mod addsub; mod big; +pub mod bswap; pub mod leading_zeros; pub mod mul; pub mod sdiv; diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index e01223c7484..c19923b75c2 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -92,6 +92,40 @@ fn leading_zeros() { }) } +#[test] +#[cfg(not(target_arch = "avr"))] +fn bswap() { + use compiler_builtins::int::bswap::{__bswapdi2, __bswapsi2}; + fuzz(N, |x: u32| { + assert_eq!(x.swap_bytes(), __bswapsi2(x)); + }); + fuzz(N, |x: u64| { + assert_eq!(x.swap_bytes(), __bswapdi2(x)); + }); + + assert_eq!(__bswapsi2(0x12345678u32), 0x78563412u32); + assert_eq!(__bswapsi2(0x00000001u32), 0x01000000u32); + assert_eq!(__bswapdi2(0x123456789ABCDEF0u64), 0xF0DEBC9A78563412u64); + assert_eq!(__bswapdi2(0x0200000001000000u64), 0x0000000100000002u64); + + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + use compiler_builtins::int::bswap::__bswapti2; + fuzz(N, |x: u128| { + assert_eq!(x.swap_bytes(), __bswapti2(x)); + }); + + assert_eq!( + __bswapti2(0x123456789ABCDEF013579BDF02468ACEu128), + 0xCE8A4602DF9B5713F0DEBC9A78563412u128 + ); + assert_eq!( + __bswapti2(0x04000000030000000200000001000000u128), + 0x00000001000000020000000300000004u128 + ); + } +} + // This is approximate because of issues related to // https://github.com/rust-lang/rust/issues/73920. // TODO how do we resolve this indeterminacy? -- cgit 1.4.1-3-g733a5 From ddd97dc19a62a3be9495aecc5cd93c94d89237fe Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 18 Jul 2024 03:25:03 -0500 Subject: Fix missing `extern "C"` for unsafe functions `unsafe` functions were being matched in a different block that did not include `extern $abi`. This means that some intrinsics were getting generated with the Rust ABI rather than C. Combine the last two blocks using an optional token matcher, which fixes this problem and is cleaner. --- library/compiler-builtins/src/macros.rs | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index f537c1a968f..fb14660af98 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -449,41 +449,14 @@ macro_rules! intrinsics { // input we were given. ( $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - - #[cfg(not(feature = "mangled-names"))] - mod $name { - $(#[$($attr)*])* - #[no_mangle] - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] - extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - super::$name($($argname),*) - } - } - - intrinsics!($($rest)*); - ); - - // Same as the above for unsafe functions. - ( - $(#[$($attr:tt)*])* - pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + pub $(unsafe $(@ $empty:tt)?)? extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } $($rest:tt)* ) => ( $(#[$($attr)*])* - pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + pub $(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -492,7 +465,7 @@ macro_rules! intrinsics { $(#[$($attr)*])* #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] - unsafe fn $name( $($argname: $ty),* ) $(-> $ret)? { + $(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } -- cgit 1.4.1-3-g733a5 From a5c7a17d5598fd3aaf4757b05aad9e9560832456 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Sat, 22 Jun 2024 00:01:52 +0300 Subject: Implement remaining __clz*i2 intrinsics --- library/compiler-builtins/README.md | 6 +- library/compiler-builtins/build.rs | 2 +- library/compiler-builtins/src/int/leading_zeros.rs | 92 +++++++++++++--------- library/compiler-builtins/src/int/mod.rs | 1 - library/compiler-builtins/testcrate/tests/misc.rs | 89 +++++++++++++++------ 5 files changed, 123 insertions(+), 67 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index a24c127392d..6ff0de1909f 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -157,6 +157,9 @@ rely on CI. - [x] bswapdi2.c - [x] bswapsi2.c - [x] bswapti2.c +- [x] clzdi2.c +- [x] clzsi2.c +- [x] clzti2.c - [x] comparedf2.c - [x] comparesf2.c - [x] divdf3.c @@ -325,9 +328,6 @@ These builtins are never called by LLVM. - ~~arm/switch32.S~~ - ~~arm/switch8.S~~ - ~~arm/switchu8.S~~ -- ~~clzdi2.c~~ -- ~~clzsi2.c~~ -- ~~clzti2.c~~ - ~~cmpdi2.c~~ - ~~cmpti2.c~~ - ~~ctzdi2.c~~ diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 34467d8f54b..79f994456aa 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -165,6 +165,7 @@ fn configure_check_cfg() { "__bswapdi2", "__bswapti2", "__clzsi2", + "__clzdi2", "__divdi3", "__divsi3", "__divmoddi4", @@ -382,7 +383,6 @@ mod c { sources.extend(&[ ("__absvti2", "absvti2.c"), ("__addvti3", "addvti3.c"), - ("__clzti2", "clzti2.c"), ("__cmpti2", "cmpti2.c"), ("__ctzti2", "ctzti2.c"), ("__ffsti2", "ffsti2.c"), diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index 9e60ab0d744..68ac55ac70c 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -3,10 +3,12 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. +use crate::int::{CastInto, Int}; + public_test_dep! { /// Returns the number of leading binary zeros in `x`. #[allow(dead_code)] -pub(crate) fn usize_leading_zeros_default(x: usize) -> usize { +pub(crate) fn leading_zeros_default>(x: T) -> usize { // The basic idea is to test if the higher bits of `x` are zero and bisect the number // of leading zeros. It is possible for all branches of the bisection to use the same // code path by conditionally shifting the higher parts down to let the next bisection @@ -16,46 +18,47 @@ pub(crate) fn usize_leading_zeros_default(x: usize) -> usize { // because it simplifies the final bisection step. let mut x = x; // the number of potential leading zeros - let mut z = usize::MAX.count_ones() as usize; + let mut z = T::BITS as usize; // a temporary - let mut t: usize; - #[cfg(target_pointer_width = "64")] - { + let mut t: T; + + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { t = x >> 32; - if t != 0 { + if t != T::ZERO { z -= 32; x = t; } } - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { + if T::BITS >= 32 { t = x >> 16; - if t != 0 { + if t != T::ZERO { z -= 16; x = t; } } + const { assert!(T::BITS >= 16) }; t = x >> 8; - if t != 0 { + if t != T::ZERO { z -= 8; x = t; } t = x >> 4; - if t != 0 { + if t != T::ZERO { z -= 4; x = t; } t = x >> 2; - if t != 0 { + if t != T::ZERO { z -= 2; x = t; } // the last two bisections are combined into one conditional t = x >> 1; - if t != 0 { + if t != T::ZERO { z - 2 } else { - z - x + z - x.cast() } // We could potentially save a few cycles by using the LUT trick from @@ -80,12 +83,12 @@ pub(crate) fn usize_leading_zeros_default(x: usize) -> usize { public_test_dep! { /// Returns the number of leading binary zeros in `x`. #[allow(dead_code)] -pub(crate) fn usize_leading_zeros_riscv(x: usize) -> usize { +pub(crate) fn leading_zeros_riscv>(x: T) -> usize { let mut x = x; // the number of potential leading zeros - let mut z = usize::MAX.count_ones() as usize; + let mut z = T::BITS; // a temporary - let mut t: usize; + let mut t: u32; // RISC-V does not have a set-if-greater-than-or-equal instruction and // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is @@ -95,11 +98,11 @@ pub(crate) fn usize_leading_zeros_riscv(x: usize) -> usize { // right). If we try to save an instruction by using `x < imm` for each bisection, we // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, // but the immediate will never fit into 12 bits and never save an instruction. - #[cfg(target_pointer_width = "64")] - { + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise // `t` is set to 0. - t = ((x >= (1 << 32)) as usize) << 5; + t = ((x >= (T::ONE << 32)) as u32) << 5; // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the // next step to process. x >>= t; @@ -107,43 +110,58 @@ pub(crate) fn usize_leading_zeros_riscv(x: usize) -> usize { // leading zeros z -= t; } - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { - t = ((x >= (1 << 16)) as usize) << 4; + if T::BITS >= 32 { + t = ((x >= (T::ONE << 16)) as u32) << 4; x >>= t; z -= t; } - t = ((x >= (1 << 8)) as usize) << 3; + const { assert!(T::BITS >= 16) }; + t = ((x >= (T::ONE << 8)) as u32) << 3; x >>= t; z -= t; - t = ((x >= (1 << 4)) as usize) << 2; + t = ((x >= (T::ONE << 4)) as u32) << 2; x >>= t; z -= t; - t = ((x >= (1 << 2)) as usize) << 1; + t = ((x >= (T::ONE << 2)) as u32) << 1; x >>= t; z -= t; - t = (x >= (1 << 1)) as usize; + t = (x >= (T::ONE << 1)) as u32; x >>= t; z -= t; // All bits except the LSB are guaranteed to be zero for this final bisection step. // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. - z - x + z as usize - x.cast() } } intrinsics! { #[maybe_use_optimized_c_shim] - #[cfg(any( - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64" - ))] - /// Returns the number of leading binary zeros in `x`. - pub extern "C" fn __clzsi2(x: usize) -> usize { + /// Returns the number of leading binary zeros in `x` + pub extern "C" fn __clzsi2(x: u32) -> usize { + if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { + leading_zeros_riscv(x) + } else { + leading_zeros_default(x) + } + } + + #[maybe_use_optimized_c_shim] + /// Returns the number of leading binary zeros in `x` + pub extern "C" fn __clzdi2(x: u64) -> usize { if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { - usize_leading_zeros_riscv(x) + leading_zeros_riscv(x) + } else { + leading_zeros_default(x) + } + } + + /// Returns the number of leading binary zeros in `x` + pub extern "C" fn __clzti2(x: u128) -> usize { + let hi = (x >> 64) as u64; + if hi == 0 { + 64 + __clzdi2(x as u64) } else { - usize_leading_zeros_default(x) + __clzdi2(hi) } } } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index ddbffd74044..728ce1d5718 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -12,7 +12,6 @@ pub mod shift; pub mod udiv; pub use big::{i256, u256}; -pub use leading_zeros::__clzsi2; public_test_dep! { /// Minimal integer implementations needed on all integer types, including wide integers. diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index c19923b75c2..f830a54230e 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -65,31 +65,70 @@ fn fuzz_values() { #[test] fn leading_zeros() { - use compiler_builtins::int::__clzsi2; - use compiler_builtins::int::leading_zeros::{ - usize_leading_zeros_default, usize_leading_zeros_riscv, - }; - fuzz(N, |x: usize| { - let lz = x.leading_zeros() as usize; - let lz0 = __clzsi2(x); - let lz1 = usize_leading_zeros_default(x); - let lz2 = usize_leading_zeros_riscv(x); - if lz0 != lz { - panic!("__clzsi2({}): std: {}, builtins: {}", x, lz, lz0); - } - if lz1 != lz { - panic!( - "usize_leading_zeros_default({}): std: {}, builtins: {}", - x, lz, lz1 - ); - } - if lz2 != lz { - panic!( - "usize_leading_zeros_riscv({}): std: {}, builtins: {}", - x, lz, lz2 - ); - } - }) + use compiler_builtins::int::leading_zeros::{leading_zeros_default, leading_zeros_riscv}; + { + use compiler_builtins::int::leading_zeros::__clzsi2; + fuzz(N, |x: u32| { + if x == 0 { + return; // undefined value for an intrinsic + } + let lz = x.leading_zeros() as usize; + let lz0 = __clzsi2(x); + let lz1 = leading_zeros_default(x); + let lz2 = leading_zeros_riscv(x); + if lz0 != lz { + panic!("__clzsi2({}): std: {}, builtins: {}", x, lz, lz0); + } + if lz1 != lz { + panic!( + "leading_zeros_default({}): std: {}, builtins: {}", + x, lz, lz1 + ); + } + if lz2 != lz { + panic!("leading_zeros_riscv({}): std: {}, builtins: {}", x, lz, lz2); + } + }); + } + + { + use compiler_builtins::int::leading_zeros::__clzdi2; + fuzz(N, |x: u64| { + if x == 0 { + return; // undefined value for an intrinsic + } + let lz = x.leading_zeros() as usize; + let lz0 = __clzdi2(x); + let lz1 = leading_zeros_default(x); + let lz2 = leading_zeros_riscv(x); + if lz0 != lz { + panic!("__clzdi2({}): std: {}, builtins: {}", x, lz, lz0); + } + if lz1 != lz { + panic!( + "leading_zeros_default({}): std: {}, builtins: {}", + x, lz, lz1 + ); + } + if lz2 != lz { + panic!("leading_zeros_riscv({}): std: {}, builtins: {}", x, lz, lz2); + } + }); + } + + { + use compiler_builtins::int::leading_zeros::__clzti2; + fuzz(N, |x: u128| { + if x == 0 { + return; // undefined value for an intrinsic + } + let lz = x.leading_zeros() as usize; + let lz0 = __clzti2(x); + if lz0 != lz { + panic!("__clzti2({}): std: {}, builtins: {}", x, lz, lz0); + } + }); + } } #[test] -- cgit 1.4.1-3-g733a5 From cc64c7978eb663cf0f6a5965dd136ef580004af4 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Tue, 16 Jul 2024 14:03:43 +0300 Subject: Never use C version of clz builtins --- library/compiler-builtins/build.rs | 9 --------- library/compiler-builtins/src/int/leading_zeros.rs | 2 -- 2 files changed, 11 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 79f994456aa..b8da7cc56c1 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -164,8 +164,6 @@ fn configure_check_cfg() { "__bswapsi2", "__bswapdi2", "__bswapti2", - "__clzsi2", - "__clzdi2", "__divdi3", "__divsi3", "__divmoddi4", @@ -346,8 +344,6 @@ mod c { ("__absvsi2", "absvsi2.c"), ("__addvdi3", "addvdi3.c"), ("__addvsi3", "addvsi3.c"), - ("__clzdi2", "clzdi2.c"), - ("__clzsi2", "clzsi2.c"), ("__cmpdi2", "cmpdi2.c"), ("__ctzdi2", "ctzdi2.c"), ("__ctzsi2", "ctzsi2.c"), @@ -435,8 +431,6 @@ mod c { ("__aeabi_frsub", "arm/aeabi_frsub.c"), ("__bswapdi2", "arm/bswapdi2.S"), ("__bswapsi2", "arm/bswapsi2.S"), - ("__clzdi2", "arm/clzdi2.S"), - ("__clzsi2", "arm/clzsi2.S"), ("__divmodsi4", "arm/divmodsi4.S"), ("__divsi3", "arm/divsi3.S"), ("__modsi3", "arm/modsi3.S"), @@ -572,9 +566,6 @@ mod c { } } sources.remove(&to_remove); - - // But use some generic implementations where possible - sources.extend(&[("__clzdi2", "clzdi2.c"), ("__clzsi2", "clzsi2.c")]) } if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index 68ac55ac70c..1fee9fcf5d8 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -135,7 +135,6 @@ pub(crate) fn leading_zeros_riscv>(x: T) -> usize { } intrinsics! { - #[maybe_use_optimized_c_shim] /// Returns the number of leading binary zeros in `x` pub extern "C" fn __clzsi2(x: u32) -> usize { if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { @@ -145,7 +144,6 @@ intrinsics! { } } - #[maybe_use_optimized_c_shim] /// Returns the number of leading binary zeros in `x` pub extern "C" fn __clzdi2(x: u64) -> usize { if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { -- cgit 1.4.1-3-g733a5 From a96c82123e7b1ae1936340406efa7d79adb134b8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 25 Jun 2024 02:34:17 -0400 Subject: Remove a broken link in README --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 6ff0de1909f..b5f06170628 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -57,7 +57,7 @@ features = ["c"] 5. Add the intrinsic to `examples/intrinsics.rs` to verify it can be linked on all targets. 6. Send a Pull Request (PR). -7. Once the PR passes our extensive [testing infrastructure][4], we'll merge it! +7. Once the PR passes our extensive testing infrastructure, we'll merge it! 8. Celebrate :tada: [1]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/test/builtins/Unit -- cgit 1.4.1-3-g733a5 From fb27c7283c666442adb8ea6f973928cf5cde0d62 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 25 Jun 2024 02:51:45 -0400 Subject: Move IBM extended double to the unneeded section --- library/compiler-builtins/README.md | 41 ++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index b5f06170628..b33a7d6f7f4 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -257,10 +257,6 @@ These builtins are needed to support `f16` and `f128`, which are in the process - [ ] floatunsitf.c - [x] multf3.c - [ ] powitf2.c -- [ ] ppc/fixtfdi.c -- [ ] ppc/fixunstfdi.c -- [ ] ppc/floatditf.c -- [ ] ppc/floatunditf.c - [x] subtf3.c - [x] truncdfhf2.c - [x] truncsfhf2.c @@ -270,12 +266,9 @@ These builtins are needed to support `f16` and `f128`, which are in the process ## Unimplemented functions -These builtins involve floating-point types ("`f80`" and complex numbers) that are not supported by Rust. +These builtins are for x87 `f80` floating-point numbers that are not supported +by Rust. -- ~~divdc3.c~~ -- ~~divsc3.c~~ -- ~~divtc3.c~~ -- ~~divxc3.c~~ - ~~fixunsxfdi.c~~ - ~~fixunsxfsi.c~~ - ~~fixunsxfti.c~~ @@ -287,19 +280,35 @@ These builtins involve floating-point types ("`f80`" and complex numbers) that a - ~~floatuntixf.c~~ - ~~i386/floatdixf.S~~ - ~~i386/floatundixf.S~~ -- ~~muldc3.c~~ -- ~~mulsc3.c~~ -- ~~multc3.c~~ -- ~~mulxc3.c~~ -- ~~powixf2.c~~ +- ~~x86_64/floatdixf.c~~ +- ~~x86_64/floatundixf.S~~ + +These builtins are for IBM "extended double" non-IEEE 128-bit floating-point +numbers. + - ~~ppc/divtc3.c~~ +- ~~ppc/fixtfdi.c~~ +- ~~ppc/fixunstfdi.c~~ +- ~~ppc/floatditf.c~~ +- ~~ppc/floatunditf.c~~ - ~~ppc/gcc_qadd.c~~ - ~~ppc/gcc_qdiv.c~~ - ~~ppc/gcc_qmul.c~~ - ~~ppc/gcc_qsub.c~~ - ~~ppc/multc3.c~~ -- ~~x86_64/floatdixf.c~~ -- ~~x86_64/floatundixf.S~~ + +These builtins involve complex floating-point types that are not supported by +Rust. + +- ~~divdc3.c~~ +- ~~divsc3.c~~ +- ~~divtc3.c~~ +- ~~divxc3.c~~ +- ~~muldc3.c~~ +- ~~mulsc3.c~~ +- ~~multc3.c~~ +- ~~mulxc3.c~~ +- ~~powixf2.c~~ These builtins are never called by LLVM. -- cgit 1.4.1-3-g733a5 From 6ef2b95d46f233d3d53aad297867b7ab213d95af Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 25 Jun 2024 03:56:21 -0400 Subject: Add missing symbols from compiler-rt to the README --- library/compiler-builtins/README.md | 86 +++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index b33a7d6f7f4..2d7aa337841 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -16,13 +16,13 @@ you can use this crate to get those intrinsics and solve the linker errors. To do that, add this crate somewhere in the dependency graph of the crate you are building: -``` toml +```toml # Cargo.toml [dependencies] compiler_builtins = { git = "https://github.com/rust-lang/compiler-builtins" } ``` -``` rust +```rust extern crate compiler_builtins; // ... @@ -91,7 +91,7 @@ obtained with the following: ```sh curl -L -o rustc-llvm-18.0.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/18.0-2024-02-13.tar.gz tar xzf rustc-llvm-18.0.tar.gz --strip-components 1 llvm-project-rustc-18.0-2024-02-13/compiler-rt -```` +``` Local targets may also be tested with `./ci/run.sh [target]`. @@ -100,9 +100,11 @@ rely on CI. ## Progress +- [x] aarch64/chkstk.S - [x] adddf3.c - [x] addsf3.c - [x] arm/adddf3vfp.S +- [x] arm/addsf3.S - [x] arm/addsf3vfp.S - [x] arm/aeabi_dcmp.S - [x] arm/aeabi_fcmp.S @@ -113,6 +115,7 @@ rely on CI. - [x] arm/aeabi_memset.S - [x] arm/aeabi_uidivmod.S - [x] arm/aeabi_uldivmod.S +- [ ] arm/chkstk.S - [x] arm/divdf3vfp.S - [ ] arm/divmodsi4.S (generic version is done) - [x] arm/divsf3vfp.S @@ -154,6 +157,12 @@ rely on CI. - [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c +- [ ] avr/divmodhi4.S +- [ ] avr/divmodqi4.S +- [ ] avr/mulhi3.S +- [ ] avr/mulqi3.S +- [ ] avr/udivmodhi4.S +- [ ] avr/udivmodqi4.S - [x] bswapdi2.c - [x] bswapsi2.c - [x] bswapti2.c @@ -166,6 +175,7 @@ rely on CI. - [x] divdi3.c - [x] divmoddi4.c - [x] divmodsi4.c +- [x] divmodti4.c - [x] divsf3.c - [x] divsi3.c - [x] extendsfdf2.c @@ -204,6 +214,8 @@ rely on CI. - [x] mulsf3.c - [x] powidf2.c - [x] powisf2.c +- [ ] riscv/muldi3.S +- [ ] riscv/mulsi3.S - [x] subdf3.c - [x] subsf3.c - [x] truncdfsf2.c @@ -236,7 +248,8 @@ These builtins are needed to support 128-bit integers. - [x] udivti3.c - [x] umodti3.c -These builtins are needed to support `f16` and `f128`, which are in the process of being added to Rust. +These builtins are needed to support `f16` and `f128`, which are in the process +of being added to Rust. - [x] addtf3.c - [x] comparetf2.c @@ -253,8 +266,10 @@ These builtins are needed to support `f16` and `f128`, which are in the process - [x] fixunstfti.c - [ ] floatditf.c - [ ] floatsitf.c +- [ ] floattitf.c - [ ] floatunditf.c - [ ] floatunsitf.c +- [ ] floatuntitf.c - [x] multf3.c - [ ] powitf2.c - [x] subtf3.c @@ -264,11 +279,42 @@ These builtins are needed to support `f16` and `f128`, which are in the process - [x] trunctfhf2.c - [x] trunctfsf2.c + +These builtins are used by the Hexagon DSP + +- [ ] hexagon/common_entry_exit_abi1.S +- [ ] hexagon/common_entry_exit_abi2.S +- [ ] hexagon/common_entry_exit_legacy.S +- [x] hexagon/dfaddsub.S~~ +- [x] hexagon/dfdiv.S~~ +- [x] hexagon/dffma.S~~ +- [x] hexagon/dfminmax.S~~ +- [x] hexagon/dfmul.S~~ +- [x] hexagon/dfsqrt.S~~ +- [x] hexagon/divdi3.S~~ +- [x] hexagon/divsi3.S~~ +- [x] hexagon/fastmath2_dlib_asm.S~~ +- [x] hexagon/fastmath2_ldlib_asm.S~~ +- [x] hexagon/fastmath_dlib_asm.S~~ +- [x] hexagon/memcpy_forward_vp4cp4n2.S~~ +- [x] hexagon/memcpy_likely_aligned.S~~ +- [x] hexagon/moddi3.S~~ +- [x] hexagon/modsi3.S~~ +- [x] hexagon/sfdiv_opt.S~~ +- [x] hexagon/sfsqrt_opt.S~~ +- [x] hexagon/udivdi3.S~~ +- [x] hexagon/udivmoddi4.S~~ +- [x] hexagon/udivmodsi4.S~~ +- [x] hexagon/udivsi3.S~~ +- [x] hexagon/umoddi3.S~~ +- [x] hexagon/umodsi3.S~~ + ## Unimplemented functions These builtins are for x87 `f80` floating-point numbers that are not supported by Rust. +- ~~extendxftf2.c~~ - ~~fixunsxfdi.c~~ - ~~fixunsxfsi.c~~ - ~~fixunsxfti.c~~ @@ -288,8 +334,11 @@ numbers. - ~~ppc/divtc3.c~~ - ~~ppc/fixtfdi.c~~ +- ~~ppc/fixtfti.c~~ - ~~ppc/fixunstfdi.c~~ +- ~~ppc/fixunstfti.c~~ - ~~ppc/floatditf.c~~ +- ~~ppc/floattitf.c~~ - ~~ppc/floatunditf.c~~ - ~~ppc/gcc_qadd.c~~ - ~~ppc/gcc_qdiv.c~~ @@ -297,6 +346,13 @@ numbers. - ~~ppc/gcc_qsub.c~~ - ~~ppc/multc3.c~~ +These builtins are for 16-bit brain floating-point numbers that are not +supported by Rust. + +- ~~truncdfbf2.c~~ +- ~~truncsfbf2.c~~ +- ~~trunctfxf2.c~~ + These builtins involve complex floating-point types that are not supported by Rust. @@ -342,6 +398,7 @@ These builtins are never called by LLVM. - ~~ctzdi2.c~~ - ~~ctzsi2.c~~ - ~~ctzti2.c~~ +- ~~ffssi2.c~~ - ~~ffsdi2.c~~ - this is [called by gcc][jemalloc-fail] though! - ~~ffsti2.c~~ - ~~mulvdi3.c~~ @@ -404,13 +461,34 @@ Rust only exposes atomic types on platforms that support them, and therefore doe Miscellaneous functionality that is not used by Rust. +- ~~aarch64/fp_mode.c~~ +- ~~aarch64/lse.S~~ (LSE atomics) +- ~~aarch64/sme-abi-init.c~~ (matrix extension) +- ~~aarch64/sme-abi.S~~ (matrix extension) +- ~~aarch64/sme-libc-routines.c~~ (matrix extension) - ~~apple_versioning.c~~ +- ~~arm/fp_mode.c~~ +- ~~avr/exit.S~~ - ~~clear_cache.c~~ +- ~~cpu_model/aarch64.c~~ +- ~~cpu_model/x86.c~~ +- ~~crtbegin.c~~ +- ~~crtend.c~~ - ~~emutls.c~~ - ~~enable_execute_stack.c~~ - ~~eprintf.c~~ +- ~~fp_mode.c~~ (float exception handling) - ~~gcc_personality_v0.c~~ +- ~~i386/fp_mode.c~~ +- ~~int_util.c~~ +- ~~loongarch/fp_mode.c~~ +- ~~os_version_check.c~~ +- ~~riscv/fp_mode.c~~ +- ~~riscv/restore.S~~ (callee-saved registers) +- ~~riscv/save.S~~ (callee-saved registers) - ~~trampoline_setup.c~~ +- ~~ve/grow_stack.S~~ +- ~~ve/grow_stack_align.S~~ Floating-point implementations of builtins that are only called from soft-float code. It would be better to simply use the generic soft-float versions in this case. -- cgit 1.4.1-3-g733a5 From adabbe73d9234ae4f7b4ae0695e87e27accbd8e9 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Sat, 22 Jun 2024 00:01:52 +0300 Subject: Implement __ctz*i2 intrinsics --- library/compiler-builtins/README.md | 6 +- library/compiler-builtins/build.rs | 3 - library/compiler-builtins/src/int/mod.rs | 1 + .../compiler-builtins/src/int/trailing_zeros.rs | 64 ++++++++++++++++++++++ library/compiler-builtins/testcrate/tests/misc.rs | 43 +++++++++++++++ 5 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/src/int/trailing_zeros.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 2d7aa337841..51bef5e2e7c 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -171,6 +171,9 @@ rely on CI. - [x] clzti2.c - [x] comparedf2.c - [x] comparesf2.c +- [x] ctzdi2.c +- [x] ctzsi2.c +- [x] ctzti2.c - [x] divdf3.c - [x] divdi3.c - [x] divmoddi4.c @@ -395,9 +398,6 @@ These builtins are never called by LLVM. - ~~arm/switchu8.S~~ - ~~cmpdi2.c~~ - ~~cmpti2.c~~ -- ~~ctzdi2.c~~ -- ~~ctzsi2.c~~ -- ~~ctzti2.c~~ - ~~ffssi2.c~~ - ~~ffsdi2.c~~ - this is [called by gcc][jemalloc-fail] though! - ~~ffsti2.c~~ diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index b8da7cc56c1..d267d3cc4a8 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -345,8 +345,6 @@ mod c { ("__addvdi3", "addvdi3.c"), ("__addvsi3", "addvsi3.c"), ("__cmpdi2", "cmpdi2.c"), - ("__ctzdi2", "ctzdi2.c"), - ("__ctzsi2", "ctzsi2.c"), ("__int_util", "int_util.c"), ("__mulvdi3", "mulvdi3.c"), ("__mulvsi3", "mulvsi3.c"), @@ -380,7 +378,6 @@ mod c { ("__absvti2", "absvti2.c"), ("__addvti3", "addvti3.c"), ("__cmpti2", "cmpti2.c"), - ("__ctzti2", "ctzti2.c"), ("__ffsti2", "ffsti2.c"), ("__mulvti3", "mulvti3.c"), ("__negti2", "negti2.c"), diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 728ce1d5718..5f56c6b6ee1 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -9,6 +9,7 @@ pub mod leading_zeros; pub mod mul; pub mod sdiv; pub mod shift; +pub mod trailing_zeros; pub mod udiv; pub use big::{i256, u256}; diff --git a/library/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/src/int/trailing_zeros.rs new file mode 100644 index 00000000000..cea366b0754 --- /dev/null +++ b/library/compiler-builtins/src/int/trailing_zeros.rs @@ -0,0 +1,64 @@ +use crate::int::{CastInto, Int}; + +public_test_dep! { +/// Returns number of trailing binary zeros in `x`. +#[allow(dead_code)] +pub(crate) fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + let mut x = x; + let mut r: u32 = 0; + let mut t: u32; + + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + x >>= r; // remove 32 zero bits + } + + if T::BITS >= 32 { + t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 + r += t; + x >>= t; // x = [0 - 0xFFFF] + higher garbage bits + } + + const { assert!(T::BITS >= 16) }; + t = ((CastInto::::cast(x) == 0) as u32) << 3; + x >>= t; // x = [0 - 0xFF] + higher garbage bits + r += t; + + let mut x: u8 = x.cast(); + + t = (((x & 0x0F) == 0) as u32) << 2; + x >>= t; // x = [0 - 0xF] + higher garbage bits + r += t; + + t = (((x & 0x3) == 0) as u32) << 1; + x >>= t; // x = [0 - 0x3] + higher garbage bits + r += t; + + x &= 3; + + r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) +} +} + +intrinsics! { + /// Returns the number of trailing binary zeros in `x` (32 bit version). + pub extern "C" fn __ctzsi2(x: u32) -> usize { + trailing_zeros(x) + } + + /// Returns the number of trailing binary zeros in `x` (64 bit version). + pub extern "C" fn __ctzdi2(x: u64) -> usize { + trailing_zeros(x) + } + + /// Returns the number of trailing binary zeros in `x` (128 bit version). + pub extern "C" fn __ctzti2(x: u128) -> usize { + let lo = x as u64; + if lo == 0 { + 64 + __ctzdi2((x >> 64) as u64) + } else { + __ctzdi2(lo) + } + } +} diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index f830a54230e..f9431915b15 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -131,6 +131,49 @@ fn leading_zeros() { } } +#[test] +fn trailing_zeros() { + use compiler_builtins::int::trailing_zeros::{__ctzdi2, __ctzsi2, __ctzti2, trailing_zeros}; + fuzz(N, |x: u32| { + if x == 0 { + return; // undefined value for an intrinsic + } + let tz = x.trailing_zeros() as usize; + let tz0 = __ctzsi2(x); + let tz1 = trailing_zeros(x); + if tz0 != tz { + panic!("__ctzsi2({}): std: {}, builtins: {}", x, tz, tz0); + } + if tz1 != tz { + panic!("trailing_zeros({}): std: {}, builtins: {}", x, tz, tz1); + } + }); + fuzz(N, |x: u64| { + if x == 0 { + return; // undefined value for an intrinsic + } + let tz = x.trailing_zeros() as usize; + let tz0 = __ctzdi2(x); + let tz1 = trailing_zeros(x); + if tz0 != tz { + panic!("__ctzdi2({}): std: {}, builtins: {}", x, tz, tz0); + } + if tz1 != tz { + panic!("trailing_zeros({}): std: {}, builtins: {}", x, tz, tz1); + } + }); + fuzz(N, |x: u128| { + if x == 0 { + return; // undefined value for an intrinsic + } + let tz = x.trailing_zeros() as usize; + let tz0 = __ctzti2(x); + if tz0 != tz { + panic!("__ctzti2({}): std: {}, builtins: {}", x, tz, tz0); + } + }); +} + #[test] #[cfg(not(target_arch = "avr"))] fn bswap() { -- cgit 1.4.1-3-g733a5 From 364dd5fd5b431323792a96103df302303ccde325 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 18 Jul 2024 00:29:04 -0500 Subject: Add `release-plz` for automatic releases. This is what `cc-rs` is using and should create a release PR whenever a change to `master` is made. If the branch is merged, it should publish the new version. Includes configuration to disable semver checks and not keep a changelog since this is an implementation detail. --- .../.github/workflows/publish.yml | 30 ++++++++++++++++++++++ library/compiler-builtins/.release-plz.toml | 3 +++ .../crates/panic-handler/Cargo.toml | 1 + library/compiler-builtins/testcrate/Cargo.toml | 1 + 4 files changed, 35 insertions(+) create mode 100644 library/compiler-builtins/.github/workflows/publish.yml create mode 100644 library/compiler-builtins/.release-plz.toml diff --git a/library/compiler-builtins/.github/workflows/publish.yml b/library/compiler-builtins/.github/workflows/publish.yml new file mode 100644 index 00000000000..d568f375738 --- /dev/null +++ b/library/compiler-builtins/.github/workflows/publish.yml @@ -0,0 +1,30 @@ +name: Release-plz + +permissions: + pull-requests: write + contents: write + +on: + push: + branches: + - master + +jobs: + release-plz: + name: Release-plz + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: true + - name: Install Rust (rustup) + run: rustup update nightly --no-self-update && rustup default nightly + - name: Publish `libm` as part of builtins, rather than its own crate + run: rm libm/Cargo.toml + - name: Run release-plz + uses: MarcoIeni/release-plz-action@v0.5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/library/compiler-builtins/.release-plz.toml b/library/compiler-builtins/.release-plz.toml new file mode 100644 index 00000000000..affc102650f --- /dev/null +++ b/library/compiler-builtins/.release-plz.toml @@ -0,0 +1,3 @@ +[workspace] +changelog_update = false +semver_check = false diff --git a/library/compiler-builtins/crates/panic-handler/Cargo.toml b/library/compiler-builtins/crates/panic-handler/Cargo.toml index 4fb81eb82a4..2ad85840900 100644 --- a/library/compiler-builtins/crates/panic-handler/Cargo.toml +++ b/library/compiler-builtins/crates/panic-handler/Cargo.toml @@ -3,5 +3,6 @@ name = "panic-handler" version = "0.1.0" authors = ["Alex Crichton "] edition = "2021" +publish = false [dependencies] diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 6b5c4cf48d2..e39c35b6791 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -3,6 +3,7 @@ name = "testcrate" version = "0.1.0" authors = ["Alex Crichton "] edition = "2021" +publish = false [lib] test = false -- cgit 1.4.1-3-g733a5 From 99456ad08e5b2bab7042771fabcbabec67f7e0d5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 28 Jul 2024 17:00:41 -0400 Subject: Set allow_dirty to release-plz This should resolve the issue in --- library/compiler-builtins/.release-plz.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/.release-plz.toml b/library/compiler-builtins/.release-plz.toml index affc102650f..fce19d15755 100644 --- a/library/compiler-builtins/.release-plz.toml +++ b/library/compiler-builtins/.release-plz.toml @@ -1,3 +1,8 @@ [workspace] changelog_update = false semver_check = false + +# As part of the release process, we delete `libm/Cargo.toml`. Since +# this is only run in CI, we shouldn't need to worry about it. +allow_dirty = true +publish_allow_dirty = true -- cgit 1.4.1-3-g733a5 From 85d4ef72c8b839f819d978959c08676ca6693169 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 28 Jul 2024 21:08:01 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c8d78ec3e26..706031bbf71 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.113" +version = "0.1.114" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 22e4aa37da718b86332745bbc40375e096862664 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 13:41:08 -0400 Subject: Switch to a target structure in build.rs --- library/compiler-builtins/build.rs | 118 ++++++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 40 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d267d3cc4a8..80454815f2c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,10 +1,50 @@ use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering}; +#[allow(dead_code)] +struct Target { + triple: String, + os: String, + arch: String, + vendor: String, + env: String, + pointer_width: u8, + little_endian: bool, + features: Vec, +} + +impl Target { + fn from_env() -> Self { + let little_endian = match env::var("CARGO_CFG_TARGET_ENDIAN").unwrap().as_str() { + "little" => true, + "big" => false, + x => panic!("unknown endian {x}"), + }; + + Self { + triple: env::var("TARGET").unwrap(), + os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), + vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), + env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), + pointer_width: env::var("CARGO_CFG_TARGET_POINTER_WIDTH") + .unwrap() + .parse() + .unwrap(), + little_endian, + features: env::var("CARGO_CFG_TARGET_FEATURE") + .unwrap_or_default() + .split(",") + .map(ToOwned::to_owned) + .collect(), + } + } +} + fn main() { println!("cargo:rerun-if-changed=build.rs"); configure_check_cfg(); - let target = env::var("TARGET").unwrap(); + let target = Target::from_env(); let cwd = env::current_dir().unwrap(); println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); @@ -14,12 +54,12 @@ fn main() { println!("cargo:rustc-cfg=feature=\"unstable\""); // Emscripten's runtime includes all the builtins - if target.contains("emscripten") { + if target.env == "emscripten" { return; } // OpenBSD provides compiler_rt by default, use it instead of rebuilding it from source - if target.contains("openbsd") { + if target.os == "openbsd" { println!("cargo:rustc-link-search=native=/usr/lib"); println!("cargo:rustc-link-lib=compiler_rt"); return; @@ -27,22 +67,22 @@ fn main() { // Forcibly enable memory intrinsics on wasm & SGX as we don't have a libc to // provide them. - if (target.contains("wasm") && !target.contains("wasi")) - || (target.contains("sgx") && target.contains("fortanix")) - || target.contains("-none") - || target.contains("nvptx") - || target.contains("uefi") - || target.contains("xous") + if (target.triple.contains("wasm") && !target.triple.contains("wasi")) + || (target.triple.contains("sgx") && target.triple.contains("fortanix")) + || target.triple.contains("-none") + || target.triple.contains("nvptx") + || target.triple.contains("uefi") + || target.triple.contains("xous") { println!("cargo:rustc-cfg=feature=\"mem\""); } // These targets have hardware unaligned access support. println!("cargo::rustc-check-cfg=cfg(feature, values(\"mem-unaligned\"))"); - if target.contains("x86_64") - || target.contains("i686") - || target.contains("aarch64") - || target.contains("bpf") + if target.arch.contains("x86_64") + || target.arch.contains("i686") + || target.arch.contains("aarch64") + || target.arch.contains("bpf") { println!("cargo:rustc-cfg=feature=\"mem-unaligned\""); } @@ -50,7 +90,7 @@ fn main() { // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the // target triple. This is usually correct for our built-in targets but can break in presence of // custom targets, which can have arbitrary names. - let llvm_target = target.split('-').collect::>(); + let llvm_target = target.triple.split('-').collect::>(); // Build missing intrinsics from compiler-rt C source code. If we're // mangling names though we assume that we're also in test mode so we don't @@ -60,7 +100,7 @@ fn main() { // Don't use a C compiler for these targets: // // * nvptx - everything is bitcode, not compatible with mixed C/Rust - if !target.contains("nvptx") { + if !target.arch.contains("nvptx") { #[cfg(feature = "c")] c::compile(&llvm_target, &target); } @@ -86,7 +126,7 @@ fn main() { println!("cargo::rustc-check-cfg=cfg(kernel_user_helpers)"); if llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" - || target == "arm-linux-androideabi" + || target.triple == "arm-linux-androideabi" { println!("cargo:rustc-cfg=kernel_user_helpers") } @@ -227,6 +267,8 @@ mod c { use std::io::Write; use std::path::{Path, PathBuf}; + use super::Target; + struct Sources { // SYMBOL -> PATH TO SOURCE map: BTreeMap<&'static str, &'static str>, @@ -267,11 +309,7 @@ mod c { } /// Compile intrinsics from the compiler-rt C source code - pub fn compile(llvm_target: &[&str], target: &String) { - let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); - let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); - let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); + pub fn compile(llvm_target: &[&str], target: &Target) { let mut consider_float_intrinsics = true; let cfg = &mut cc::Build::new(); @@ -280,8 +318,8 @@ mod c { // // Therefore, evaluate if those flags are present and set a boolean that causes any // compiler-rt intrinsics that contain floating point source to be excluded for this target. - if target_arch == "aarch64" { - let cflags_key = String::from("CFLAGS_") + &(target.to_owned().replace("-", "_")); + if target.arch == "aarch64" { + let cflags_key = String::from("CFLAGS_") + &(target.triple.replace("-", "_")); if let Ok(cflags_value) = env::var(cflags_key) { if cflags_value.contains("+nofp") || cflags_value.contains("+nosimd") { consider_float_intrinsics = false; @@ -299,7 +337,7 @@ mod c { cfg.warnings(false); - if target_env == "msvc" { + if target.env == "msvc" { // Don't pull in extra libraries on MSVC cfg.flag("/Zl"); @@ -328,7 +366,7 @@ mod c { // at odds with compiling with `-ffreestanding`, as the header // may be incompatible or not present. Create a minimal stub // header to use instead. - if target_os == "uefi" { + if target.os == "uefi" { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let include_dir = out_dir.join("include"); if !include_dir.exists() { @@ -373,7 +411,7 @@ mod c { // On iOS and 32-bit OSX these are all just empty intrinsics, no need to // include them. - if target_vendor != "apple" || target_arch != "x86" { + if target.vendor != "apple" || target.arch != "x86" { sources.extend(&[ ("__absvti2", "absvti2.c"), ("__addvti3", "addvti3.c"), @@ -392,7 +430,7 @@ mod c { } } - if target_vendor == "apple" { + if target.vendor == "apple" { sources.extend(&[ ("atomic_flag_clear", "atomic_flag_clear.c"), ("atomic_flag_clear_explicit", "atomic_flag_clear_explicit.c"), @@ -406,8 +444,8 @@ mod c { ]); } - if target_env != "msvc" { - if target_arch == "x86" { + if target.env != "msvc" { + if target.arch == "x86" { sources.extend(&[ ("__ashldi3", "i386/ashldi3.S"), ("__ashrdi3", "i386/ashrdi3.S"), @@ -421,7 +459,7 @@ mod c { } } - if target_arch == "arm" && target_vendor != "apple" && target_env != "msvc" { + if target.arch == "arm" && target.vendor != "apple" && target.env != "msvc" { sources.extend(&[ ("__aeabi_div0", "arm/aeabi_div0.c"), ("__aeabi_drsub", "arm/aeabi_drsub.c"), @@ -441,7 +479,7 @@ mod c { ("__umodsi3", "arm/umodsi3.S"), ]); - if target_os == "freebsd" { + if target.os == "freebsd" { sources.extend(&[("__clear_cache", "clear_cache.c")]); } @@ -513,7 +551,7 @@ mod c { ]); } - if (target_arch == "aarch64" || target_arch == "arm64ec") && consider_float_intrinsics { + if (target.arch == "aarch64" || target.arch == "arm64ec") && consider_float_intrinsics { sources.extend(&[ ("__comparetf2", "comparetf2.c"), ("__floatditf", "floatditf.c"), @@ -526,16 +564,16 @@ mod c { ("__fe_raise_inexact", "fp_mode.c"), ]); - if target_os != "windows" { + if target.os != "windows" { sources.extend(&[("__multc3", "multc3.c")]); } } - if target_arch == "mips" || target_arch == "riscv32" || target_arch == "riscv64" { + if target.arch == "mips" || target.arch == "riscv32" || target.arch == "riscv64" { sources.extend(&[("__bswapsi2", "bswapsi2.c")]); } - if target_arch == "mips64" { + if target.arch == "mips64" { sources.extend(&[ ("__netf2", "comparetf2.c"), ("__floatsitf", "floatsitf.c"), @@ -544,7 +582,7 @@ mod c { ]); } - if target_arch == "loongarch64" { + if target.arch == "loongarch64" { sources.extend(&[ ("__netf2", "comparetf2.c"), ("__floatsitf", "floatsitf.c"), @@ -554,7 +592,7 @@ mod c { } // Remove the assembly implementations that won't compile for the target - if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" || target_os == "uefi" + if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" || target.os == "uefi" { let mut to_remove = Vec::new(); for (k, v) in sources.map.iter() { @@ -570,7 +608,7 @@ mod c { } // Android uses emulated TLS so we need a runtime support function. - if target_os == "android" { + if target.os == "android" { sources.extend(&[("__emutls_get_address", "emutls.c")]); // Work around a bug in the NDK headers (fixed in @@ -580,7 +618,7 @@ mod c { } // OpenHarmony also uses emulated TLS. - if target_env == "ohos" { + if target.env == "ohos" { sources.extend(&[("__emutls_get_address", "emutls.c")]); } @@ -607,7 +645,7 @@ mod c { // sets of flags to the same source file. // Note: Out-of-line aarch64 atomics are not supported by the msvc toolchain (#430). let src_dir = root.join("lib/builtins"); - if target_arch == "aarch64" && target_env != "msvc" { + if target.arch == "aarch64" && target.env != "msvc" { // See below for why we're building these as separate libraries. build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); -- cgit 1.4.1-3-g733a5 From b32758cdc2be7fbcb1e692738d821310ff866c0c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 17:42:36 -0400 Subject: Add back remaining config on `arm_aeabi_alias` Intrinsics marked with `arm_aeabi_alias = ...` were having the rest of their attributes eaten. Add them back. --- library/compiler-builtins/src/macros.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index fb14660af98..42c83ee55fb 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -290,6 +290,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg(target_arch = "arm")] + $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -298,6 +299,7 @@ macro_rules! intrinsics { mod $name { #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] + $(#[$($attr)*])* extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -307,6 +309,7 @@ macro_rules! intrinsics { mod $alias { #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] + $(#[$($attr)*])* extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } -- cgit 1.4.1-3-g733a5 From b168f56dd4cf5605df9f170daab0541ef16ff66a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 13:48:13 -0400 Subject: Configure which platforms get `f16` and `f128` enabled by default By moving the logic for which platforms get symbols to `compiler_builtins` rather than rust-lang/rust, we can control where symbols get enabled without relying on Cargo features. Using Cargo features turned out to be a problem in [1]. This will help resolve errors like [2]. [1]: https://github.com/rust-lang/rust/issues/128358 [2]: https://github.com/rust-lang/rust/issues/128401 --- library/compiler-builtins/build.rs | 46 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 80454815f2c..749a08a5ae2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -42,11 +42,12 @@ impl Target { fn main() { println!("cargo:rerun-if-changed=build.rs"); - configure_check_cfg(); - let target = Target::from_env(); let cwd = env::current_dir().unwrap(); + configure_check_cfg(); + configure_f16_f128(&target); + println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); // Activate libm's unstable features to make full use of Nightly. @@ -259,6 +260,47 @@ fn configure_check_cfg() { println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); } +/// Configure whether or not `f16` and `f128` support should be enabled. +fn configure_f16_f128(target: &Target) { + // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means + // that the backend will not crash when using these types. This does not mean that the + // backend does the right thing, or that the platform doesn't have ABI bugs. + // + // We do this here rather than in `rust-lang/rust` because configuring via cargo features is + // not straightforward. + // + // Original source of this list: + // + let (f16_ok, f128_ok) = match target.arch.as_str() { + // `f16` and `f128` both crash + "arm64ec" => (false, false), + // `f16` crashes + "s390x" => (false, true), + // `f128` crashes + "mips64" | "mips64r6" => (true, false), + // `f128` crashes + "powerpc64" if &target.os == "aix" => (true, false), + // `f128` crashes + "sparc" | "sparcv9" => (true, false), + // Most everything else works as of LLVM 19 + _ => (true, true), + }; + + // If the feature is set, disable these types. + let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); + + println!("cargo::rustc-check-cfg=cfg(f16_enabled)"); + println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); + + if f16_ok && !disable_both { + println!("cargo::rustc-cfg=f16_enabled"); + } + + if f128_ok && !disable_both { + println!("cargo::rustc-cfg=f128_enabled"); + } +} + #[cfg(feature = "c")] mod c { use std::collections::{BTreeMap, HashSet}; -- cgit 1.4.1-3-g733a5 From 8199433bb260b63a7a7398c2d52d752a2cdb040f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 15:58:29 -0400 Subject: Make use of new `f16` and `f128` config options Change from `not(feature = "no-f16-f128")` to `f16_enabled` or `f128_disabled`, as applicable. --- library/compiler-builtins/src/float/add.rs | 2 +- library/compiler-builtins/src/float/cmp.rs | 2 +- library/compiler-builtins/src/float/conv.rs | 12 ++++++------ library/compiler-builtins/src/float/extend.rs | 6 +++++- library/compiler-builtins/src/float/mod.rs | 4 ++-- library/compiler-builtins/src/float/mul.rs | 2 +- library/compiler-builtins/src/float/sub.rs | 2 +- library/compiler-builtins/src/float/trunc.rs | 7 ++++++- library/compiler-builtins/src/lib.rs | 4 ++-- 9 files changed, 25 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 7e8529f3e29..03ed131af26 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -204,7 +204,7 @@ intrinsics! { } #[ppc_alias = __addkf3] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __addtf3(a: f128, b: f128) -> f128 { add(a, b) } diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 5c431304c61..1901ca4b362 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -172,7 +172,7 @@ intrinsics! { } } -#[cfg(not(feature = "no-f16-f128",))] +#[cfg(f128_enabled)] intrinsics! { #[avr_skip] #[ppc_alias = __lekf2] diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 52119f3e800..d275f982bb4 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -263,19 +263,19 @@ intrinsics! { } #[ppc_alias = __fixunskfsi] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __fixunstfsi(f: f128) -> u32 { float_to_unsigned_int(f) } #[ppc_alias = __fixunskfdi] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __fixunstfdi(f: f128) -> u64 { float_to_unsigned_int(f) } #[ppc_alias = __fixunskfti] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __fixunstfti(f: f128) -> u128 { float_to_unsigned_int(f) } @@ -314,19 +314,19 @@ intrinsics! { } #[ppc_alias = __fixkfsi] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __fixtfsi(f: f128) -> i32 { float_to_signed_int(f) } #[ppc_alias = __fixkfdi] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __fixtfdi(f: f128) -> i64 { float_to_signed_int(f) } #[ppc_alias = __fixkfti] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __fixtfti(f: f128) -> i128 { float_to_signed_int(f) } diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 55604899133..2f392255fea 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -83,17 +83,18 @@ intrinsics! { } } -#[cfg(not(feature = "no-f16-f128"))] intrinsics! { #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_h2f] + #[cfg(f16_enabled)] pub extern "C" fn __extendhfsf2(a: f16) -> f32 { extend(a) } #[avr_skip] #[aapcs_on_arm] + #[cfg(f16_enabled)] pub extern "C" fn __gnu_h2f_ieee(a: f16) -> f32 { extend(a) } @@ -101,6 +102,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __extendhfkf2] + #[cfg(all(f16_enabled, f128_enabled))] pub extern "C" fn __extendhftf2(a: f16) -> f128 { extend(a) } @@ -108,6 +110,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __extendsfkf2] + #[cfg(f128_enabled)] pub extern "C" fn __extendsftf2(a: f32) -> f128 { extend(a) } @@ -115,6 +118,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __extenddfkf2] + #[cfg(f128_enabled)] pub extern "C" fn __extenddftf2(a: f64) -> f128 { extend(a) } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 5fef1df32a5..8473732057a 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -188,9 +188,9 @@ macro_rules! float_impl { }; } -#[cfg(not(feature = "no-f16-f128"))] +#[cfg(f16_enabled)] float_impl!(f16, u16, i16, i8, 16, 10); float_impl!(f32, u32, i32, i16, 32, 23); float_impl!(f64, u64, i64, i16, 64, 52); -#[cfg(not(feature = "no-f16-f128"))] +#[cfg(f128_enabled)] float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index decf722e29a..cb0fcdfa853 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -195,7 +195,7 @@ intrinsics! { } #[ppc_alias = __mulkf3] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __multf3(a: f128, b: f128) -> f128 { mul(a, b) } diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 3ab46495d4f..d33016ead2e 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -14,7 +14,7 @@ intrinsics! { } #[ppc_alias = __subkf3] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __subtf3(a: f128, b: f128) -> f128 { #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] use crate::float::add::__addkf3 as __addtf3; diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 9aea6f91ebc..c54ff7805f5 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -131,17 +131,18 @@ intrinsics! { } } -#[cfg(not(feature = "no-f16-f128"))] intrinsics! { #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_f2h] + #[cfg(f16_enabled)] pub extern "C" fn __truncsfhf2(a: f32) -> f16 { trunc(a) } #[avr_skip] #[aapcs_on_arm] + #[cfg(f16_enabled)] pub extern "C" fn __gnu_f2h_ieee(a: f32) -> f16 { trunc(a) } @@ -149,6 +150,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_d2h] + #[cfg(f16_enabled)] pub extern "C" fn __truncdfhf2(a: f64) -> f16 { trunc(a) } @@ -156,6 +158,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __trunckfhf2] + #[cfg(all(f16_enabled, f128_enabled))] pub extern "C" fn __trunctfhf2(a: f128) -> f16 { trunc(a) } @@ -163,6 +166,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __trunckfsf2] + #[cfg(f128_enabled)] pub extern "C" fn __trunctfsf2(a: f128) -> f32 { trunc(a) } @@ -170,6 +174,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __trunckfdf2] + #[cfg(f128_enabled)] pub extern "C" fn __trunctfdf2(a: f128) -> f64 { trunc(a) } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0d207a914bf..0d44fdf9654 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -13,8 +13,8 @@ #![feature(naked_functions)] #![feature(repr_simd)] #![feature(c_unwind)] -#![cfg_attr(not(feature = "no-f16-f128"), feature(f16))] -#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] +#![cfg_attr(f128_enabled, feature(f128))] #![no_builtins] #![no_std] #![allow(unused_features)] -- cgit 1.4.1-3-g733a5 From db8daebd5bef86ee00887aaca082faa87c120ca0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 19:20:26 -0400 Subject: Update which platforms have no `f16` symbols Previously we were building the C versions of these symbols. Since we added the Rust version and updated compiler builtins, these are no longer available by default. This is unintentional, but it gives a better indicator of which symbol versions are not actually provided by the system. Use the list of build failures to correct the list of platforms that do not have `f16` symbols. --- library/compiler-builtins/testcrate/build.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 12c3e7d1365..fc01f3f8d02 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -44,10 +44,20 @@ fn main() { features.insert(Feature::NoSysF16F128Convert); } - if target.starts_with("wasm32-") { + // These platforms do not have f16 symbols available in their system libraries, so + // skip related tests. Most of these are missing `f16 <-> f32` conversion routines. + if (target.starts_with("aarch64-") && target.contains("linux")) + || target.starts_with("arm") + || target.starts_with("powerpc-") + || target.starts_with("powerpc64-") + || target.starts_with("powerpc64le-") + || target.contains("windows-") // Linking says "error: function signature mismatch: __extendhfsf2" and seems to // think the signature is either `(i32) -> f32` or `(f32) -> f32` + || target.starts_with("wasm32-") + { features.insert(Feature::NoSysF16); + features.insert(Feature::NoSysF16F128Convert); } for feature in features { -- cgit 1.4.1-3-g733a5 From 1cdeaed9f9ef495b5cb5080ccc1d6b83c1a73eae Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 19:29:37 -0400 Subject: Correct `sys_avialable` for `f64` -> `f16` truncation The `sys_available` gate was incorrect. Update it. --- library/compiler-builtins/testcrate/benches/float_trunc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs index 1553dacee08..70869bcaf62 100644 --- a/library/compiler-builtins/testcrate/benches/float_trunc.rs +++ b/library/compiler-builtins/testcrate/benches/float_trunc.rs @@ -32,7 +32,7 @@ float_bench! { sig: (a: f64) -> f16, crate_fn: trunc::__truncdfhf2, sys_fn: __truncdfhf2, - sys_available: not(feature = "no-sys-f128"), + sys_available: not(feature = "no-sys-f16"), asm: [ #[cfg(target_arch = "aarch64")] { // FIXME(f16_f128): remove `from_bits()` after f16 asm support (rust-lang/rust/#116909) -- cgit 1.4.1-3-g733a5 From b6c2b6ebf7499d83f25b8c420e837cc1d24a2085 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 21:44:36 -0400 Subject: Update to the latest `rustc_apfloat` The latest version has a convenient `.unwrap()`. Increase the version so we can use this. --- library/compiler-builtins/testcrate/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index e39c35b6791..21cec170109 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -15,7 +15,7 @@ doctest = false # `xoshiro128**` is used for its quality, size, and speed at generating `u32` shift amounts. rand_xoshiro = "0.6" # To compare float builtins against -rustc_apfloat = "0.2.0" +rustc_apfloat = "0.2.1" [dependencies.compiler_builtins] path = ".." -- cgit 1.4.1-3-g733a5 From e0e6243b219835bdfbde2d198f548175c4c1d16b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 21:45:59 -0400 Subject: Update float conversion tests Since there are more platforms that do not have symbols present, we need to use `rustc_apfloat` for more conversion tests. Make use of the fallback like other tests, and refactor so each test gets its own function. Previously we were testing both apfloat and system conversion methods when possible. This changes to only test one or the other, depending on whether or not the system version is available. This seems reasonable because it is consistent with all other tests, but we should consider updating all tests to check both at some point. This also includes an adjustment of PowerPC configuration to account for the linking errors at [1]. [1]: https://github.com/rust-lang/compiler-builtins/issues/655 --- .../testcrate/benches/float_extend.rs | 11 + .../testcrate/benches/float_trunc.rs | 6 + library/compiler-builtins/testcrate/build.rs | 1 + library/compiler-builtins/testcrate/src/lib.rs | 6 +- library/compiler-builtins/testcrate/tests/conv.rs | 252 +++++++-------------- 5 files changed, 100 insertions(+), 176 deletions(-) diff --git a/library/compiler-builtins/testcrate/benches/float_extend.rs b/library/compiler-builtins/testcrate/benches/float_extend.rs index 9bd8009e93b..bf136f49a0b 100644 --- a/library/compiler-builtins/testcrate/benches/float_extend.rs +++ b/library/compiler-builtins/testcrate/benches/float_extend.rs @@ -82,6 +82,7 @@ float_bench! { asm: [], } +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] criterion_group!( float_extend, extend_f16_f32, @@ -90,4 +91,14 @@ criterion_group!( extend_f32_f128, extend_f64_f128, ); + +// FIXME(#655): `f16` tests disabled until we can bootstrap symbols +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +criterion_group!( + float_extend, + extend_f32_f64, + extend_f32_f128, + extend_f64_f128, +); + criterion_main!(float_extend); diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs index 70869bcaf62..74b43dfc833 100644 --- a/library/compiler-builtins/testcrate/benches/float_trunc.rs +++ b/library/compiler-builtins/testcrate/benches/float_trunc.rs @@ -115,6 +115,7 @@ float_bench! { asm: [], } +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] criterion_group!( float_trunc, trunc_f32_f16, @@ -124,4 +125,9 @@ criterion_group!( trunc_f128_f32, trunc_f128_f64, ); + +// FIXME(#655): `f16` tests disabled until we can bootstrap symbols +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +criterion_group!(float_trunc, trunc_f64_f32, trunc_f128_f32, trunc_f128_f64,); + criterion_main!(float_trunc); diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index fc01f3f8d02..8c441de8a95 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -51,6 +51,7 @@ fn main() { || target.starts_with("powerpc-") || target.starts_with("powerpc64-") || target.starts_with("powerpc64le-") + || target.starts_with("i586-") || target.contains("windows-") // Linking says "error: function signature mismatch: __extendhfsf2" and seems to // think the signature is either `(i32) -> f32` or `(f32) -> f32` diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index f9b052528f0..5458c9ab6d0 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -282,6 +282,8 @@ macro_rules! apfloat_fallback { // The expression to run. This expression may use `FloatTy` for its signature. // Optionally, the final conversion back to a float can be suppressed using // `=> no_convert` (for e.g. operations that return a bool). + // + // If the apfloat needs a different operation, it can be provided here. $op:expr $(=> $convert:ident)? $(; $apfloat_op:expr)?, // Arguments that get passed to `$op` after converting to a float $($arg:expr),+ @@ -318,7 +320,7 @@ macro_rules! apfloat_fallback { // Some apfloat operations return a `StatusAnd` that we need to extract the value from. This // is the default. - (@inner fty: $float_ty:ty, op_res: $val:expr, args: $($_arg:expr),+) => {{ + (@inner fty: $float_ty:ty, op_res: $val:expr, args: $($_arg:expr),+) => {{ // ignore the status, just get the value let unwrapped = $val.value; @@ -326,7 +328,7 @@ macro_rules! apfloat_fallback { }}; // This is the case where we can't use the same expression for the default builtin and - // nonstandard apfloat fallbac (e.g. `as` casts in std are normal functions in apfloat, so + // nonstandard apfloat fallback (e.g. `as` casts in std are normal functions in apfloat, so // two separate expressions must be specified. (@inner fty: $float_ty:ty, op_res: $_val:expr, diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 1425b49ce49..e394183cf57 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -206,212 +206,116 @@ mod f_to_i { } } -macro_rules! conv { - ($fX:ident, $fD:ident, $fn:ident, $apfloatX:ident, $apfloatD:ident) => { - fuzz_float(N, |x: $fX| { - let tmp0: $apfloatD = $apfloatX::from_bits(x.to_bits().into()) - .convert(&mut false) - .value; - let tmp0 = $fD::from_bits(tmp0.to_bits().try_into().unwrap()); - let tmp1: $fD = $fn(x); - if !Float::eq_repr(tmp0, tmp1) { - panic!( - "{}({x:?}): apfloat: {tmp0:?}, builtins: {tmp1:?}", - stringify!($fn) - ); - } - }) - }; -} - -macro_rules! extend { - ($fX:ident, $fD:ident, $fn:ident) => { +macro_rules! f_to_f { + ( + $mod:ident, + $( + $from_ty:ty => $to_ty:ty, + $from_ap_ty:ident => $to_ap_ty:ident, + $fn:ident, $sys_available:meta + );+; + ) => {$( #[test] fn $fn() { - use compiler_builtins::float::extend::$fn; + use compiler_builtins::float::{$mod::$fn, Float}; + use rustc_apfloat::ieee::{$from_ap_ty, $to_ap_ty}; + + fuzz_float(N, |x: $from_ty| { + let tmp0: $to_ty = apfloat_fallback!( + $from_ty, + $from_ap_ty, + $sys_available, + |x: $from_ty| x as $to_ty; + |x: $from_ty| { + let from_apf = FloatTy::from_bits(x.to_bits().into()); + // Get `value` directly to ignore INVALID_OP + let to_apf: $to_ap_ty = from_apf.convert(&mut false).value; + <$to_ty>::from_bits(to_apf.to_bits().try_into().unwrap()) + }, + x + ); + let tmp1: $to_ty = $fn(x); - fuzz_float(N, |x: $fX| { - let tmp0 = x as $fD; - let tmp1: $fD = $fn(x); if !Float::eq_repr(tmp0, tmp1) { panic!( - "{}({}): std: {}, builtins: {}", + "{}({:?}): std: {:?}, builtins: {:?}", stringify!($fn), x, tmp0, tmp1 ); } - }); + }) } - }; + )+}; } -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -mod float_extend { +mod extend { use super::*; - extend!(f32, f64, __extendsfdf2); - - #[test] - fn conv() { - use compiler_builtins::float::extend::__extendsfdf2; - use rustc_apfloat::ieee::{Double, Single}; - - conv!(f32, f64, __extendsfdf2, Single, Double); + f_to_f! { + extend, + f32 => f64, Single => Double, __extendsfdf2, all(); } -} - -#[cfg(not(feature = "no-f16-f128"))] -#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] -mod float_extend_f128 { - use super::*; - - #[test] - fn conv() { - use compiler_builtins::float::extend::{ - __extenddftf2, __extendhfsf2, __extendhftf2, __extendsftf2, __gnu_h2f_ieee, - }; - use rustc_apfloat::ieee::{Double, Half, Quad, Single}; - // FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly - conv!(f16, f32, __extendhfsf2, Half, Single); - conv!(f16, f32, __gnu_h2f_ieee, Half, Single); - conv!(f16, f128, __extendhftf2, Half, Quad); - conv!(f32, f128, __extendsftf2, Single, Quad); - conv!(f64, f128, __extenddftf2, Double, Quad); + #[cfg(target_arch = "arm")] + f_to_f! { + extend, + f32 => f64, Single => Double, __extendsfdf2vfp, all(); } -} -#[cfg(not(feature = "no-f16-f128"))] -#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] -mod float_extend_f128_ppc { - use super::*; - - #[test] - fn conv() { - use compiler_builtins::float::extend::{ - __extenddfkf2, __extendhfkf2, __extendhfsf2, __extendsfkf2, __gnu_h2f_ieee, - }; - use rustc_apfloat::ieee::{Double, Half, Quad, Single}; - - // FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly - conv!(f16, f32, __extendhfsf2, Half, Single); - conv!(f16, f32, __gnu_h2f_ieee, Half, Single); - conv!(f16, f128, __extendhfkf2, Half, Quad); - conv!(f32, f128, __extendsfkf2, Single, Quad); - conv!(f64, f128, __extenddfkf2, Double, Quad); + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + f_to_f! { + extend, + f16 => f32, Half => Single, __extendhfsf2, not(feature = "no-sys-f16"); + f16 => f32, Half => Single, __gnu_h2f_ieee, not(feature = "no-sys-f16"); + f16 => f128, Half => Quad, __extendhftf2, not(feature = "no-sys-f16-f128-convert"); + f32 => f128, Single => Quad, __extendsftf2, not(feature = "no-sys-f128"); + f64 => f128, Double => Quad, __extenddftf2, not(feature = "no-sys-f128"); } -} - -#[cfg(target_arch = "arm")] -mod float_extend_arm { - use super::*; - extend!(f32, f64, __extendsfdf2vfp); - - #[test] - fn conv() { - use compiler_builtins::float::extend::__extendsfdf2vfp; - use rustc_apfloat::ieee::{Double, Single}; - - conv!(f32, f64, __extendsfdf2vfp, Single, Double); + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + f_to_f! { + extend, + // FIXME(#655): `f16` tests disabled until we can bootstrap symbols + f32 => f128, Single => Quad, __extendsfkf2, not(feature = "no-sys-f128"); + f64 => f128, Double => Quad, __extenddfkf2, not(feature = "no-sys-f128"); } } -macro_rules! trunc { - ($fX:ident, $fD:ident, $fn:ident) => { - #[test] - fn $fn() { - use compiler_builtins::float::trunc::$fn; - - fuzz_float(N, |x: $fX| { - let tmp0 = x as $fD; - let tmp1: $fD = $fn(x); - if !Float::eq_repr(tmp0, tmp1) { - panic!( - "{}({}): std: {}, builtins: {}", - stringify!($fn), - x, - tmp0, - tmp1 - ); - } - }); - } - }; -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -mod float_trunc { +mod trunc { use super::*; - trunc!(f64, f32, __truncdfsf2); - - #[test] - fn conv() { - use compiler_builtins::float::trunc::__truncdfsf2; - use rustc_apfloat::ieee::{Double, Single}; - - conv!(f64, f32, __truncdfsf2, Double, Single); + f_to_f! { + trunc, + f64 => f32, Double => Single, __truncdfsf2, all(); } -} -#[cfg(not(feature = "no-f16-f128"))] -#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] -mod float_trunc_f128 { - use super::*; - - #[test] - fn conv() { - use compiler_builtins::float::trunc::{__gnu_f2h_ieee, __truncdfhf2, __truncsfhf2}; - use compiler_builtins::float::trunc::{__trunctfdf2, __trunctfhf2, __trunctfsf2}; - use rustc_apfloat::ieee::{Double, Half, Quad, Single}; - - // FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly - conv!(f32, f16, __truncsfhf2, Single, Half); - conv!(f32, f16, __gnu_f2h_ieee, Single, Half); - conv!(f64, f16, __truncdfhf2, Double, Half); - conv!(f128, f16, __trunctfhf2, Quad, Half); - conv!(f128, f32, __trunctfsf2, Quad, Single); - conv!(f128, f64, __trunctfdf2, Quad, Double); + #[cfg(target_arch = "arm")] + f_to_f! { + trunc, + f64 => f32, Double => Single, __truncdfsf2vfp, all(); } -} - -#[cfg(not(feature = "no-f16-f128"))] -#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] -mod float_trunc_f128_ppc { - use super::*; - - #[test] - fn conv() { - use compiler_builtins::float::trunc::{__gnu_f2h_ieee, __truncdfhf2, __truncsfhf2}; - use compiler_builtins::float::trunc::{__trunckfdf2, __trunckfhf2, __trunckfsf2}; - use rustc_apfloat::ieee::{Double, Half, Quad, Single}; - // FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly - conv!(f32, f16, __truncsfhf2, Single, Half); - conv!(f32, f16, __gnu_f2h_ieee, Single, Half); - conv!(f64, f16, __truncdfhf2, Double, Half); - conv!(f128, f16, __trunckfhf2, Quad, Half); - conv!(f128, f32, __trunckfsf2, Quad, Single); - conv!(f128, f64, __trunckfdf2, Quad, Double); + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + f_to_f! { + trunc, + f32 => f16, Single => Half, __truncsfhf2, not(feature = "no-sys-f16"); + f32 => f16, Single => Half, __gnu_f2h_ieee, not(feature = "no-sys-f16"); + f128 => f16, Quad => Half, __trunctfhf2, not(feature = "no-sys-f16-f128-convert"); + f128 => f32, Quad => Single, __trunctfsf2, not(feature = "no-sys-f128"); + f128 => f64, Quad => Double, __trunctfdf2, not(feature = "no-sys-f128"); } -} - -#[cfg(target_arch = "arm")] -mod float_trunc_arm { - use super::*; - trunc!(f64, f32, __truncdfsf2vfp); - - #[test] - fn conv() { - use compiler_builtins::float::trunc::__truncdfsf2vfp; - use rustc_apfloat::ieee::{Double, Single}; - - conv!(f64, f32, __truncdfsf2vfp, Double, Single) + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + f_to_f! { + trunc, + // FIXME(#655): `f16` tests disabled until we can bootstrap symbols + f128 => f32, Quad => Single, __trunckfsf2, not(feature = "no-sys-f128"); + f128 => f64, Quad => Double, __trunckfdf2, not(feature = "no-sys-f128"); } } -- cgit 1.4.1-3-g733a5 From 72e745ff9c4713a6dbf5be82c84839ab09f196c7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 4 Aug 2024 23:17:25 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 706031bbf71..805b44cad0f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.114" +version = "0.1.115" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 5a4ccab86684a05075cf93ac0063d782bdc2ae42 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 5 Aug 2024 16:26:27 -0500 Subject: Fix emscripten as `os` rather than `env`. b7af6078 ("Switch to a target structure...") is checking whether the target environment is emscripten, but it seems emscripten is the OS. Fix this, which should resolve the issue in . --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 749a08a5ae2..bbae9e2862f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -55,7 +55,7 @@ fn main() { println!("cargo:rustc-cfg=feature=\"unstable\""); // Emscripten's runtime includes all the builtins - if target.env == "emscripten" { + if target.os == "emscripten" { return; } -- cgit 1.4.1-3-g733a5 From 976881c9c90536a62eea5e1754cc0e90ab6fece2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 3 Aug 2024 21:29:58 -0400 Subject: Eliminate the use of `public_test_dep!` Replace `public_test_dep!` by placing optionally public items into new modules, then controlling what is exported with the `public-test-deps` feature. This is nicer for automatic formatting and diagnostics. --- library/compiler-builtins/src/float/mod.rs | 190 +--------- library/compiler-builtins/src/float/traits.rs | 184 +++++++++ library/compiler-builtins/src/int/leading_zeros.rs | 228 +++++------ library/compiler-builtins/src/int/mod.rs | 417 +-------------------- .../src/int/specialized_div_rem/delegate.rs | 4 +- .../compiler-builtins/src/int/trailing_zeros.rs | 70 ++-- library/compiler-builtins/src/int/traits.rs | 402 ++++++++++++++++++++ library/compiler-builtins/src/macros.rs | 16 - 8 files changed, 752 insertions(+), 759 deletions(-) create mode 100644 library/compiler-builtins/src/float/traits.rs create mode 100644 library/compiler-builtins/src/int/traits.rs diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 8473732057a..41b308626b3 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,7 +1,3 @@ -use core::ops; - -use crate::int::{DInt, Int, MinInt}; - pub mod add; pub mod cmp; pub mod conv; @@ -10,187 +6,11 @@ pub mod extend; pub mod mul; pub mod pow; pub mod sub; +pub(crate) mod traits; pub mod trunc; -/// Wrapper to extract the integer type half of the float's size -pub(crate) type HalfRep = <::Int as DInt>::H; - -public_test_dep! { -/// Trait for some basic operations on floats -#[allow(dead_code)] -pub(crate) trait Float: - Copy - + core::fmt::Debug - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::MulAssign - + ops::Add - + ops::Sub - + ops::Div - + ops::Rem -{ - /// A uint of the same width as the float - type Int: Int; - - /// A int of the same width as the float - type SignedInt: Int; - - /// An int capable of containing the exponent bits plus a sign bit. This is signed. - type ExpInt: Int; - - const ZERO: Self; - const ONE: Self; - - /// The bitwidth of the float type - const BITS: u32; - - /// The bitwidth of the significand - const SIGNIFICAND_BITS: u32; - - /// The bitwidth of the exponent - const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; - - /// The maximum value of the exponent - const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; - - /// The exponent bias value - const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; - - /// A mask for the sign bit - const SIGN_MASK: Self::Int; - - /// A mask for the significand - const SIGNIFICAND_MASK: Self::Int; - - /// The implicit bit of the float format - const IMPLICIT_BIT: Self::Int; - - /// A mask for the exponent - const EXPONENT_MASK: Self::Int; - - /// Returns `self` transmuted to `Self::Int` - fn repr(self) -> Self::Int; - - /// Returns `self` transmuted to `Self::SignedInt` - fn signed_repr(self) -> Self::SignedInt; - - /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. This method returns `true` if two NaNs are - /// compared. - fn eq_repr(self, rhs: Self) -> bool; - - /// Returns true if the sign is negative - fn is_sign_negative(self) -> bool; - - /// Returns the exponent with bias - fn exp(self) -> Self::ExpInt; - - /// Returns the significand with no implicit bit (or the "fractional" part) - fn frac(self) -> Self::Int; - - /// Returns the significand with implicit bit - fn imp_frac(self) -> Self::Int; - - /// Returns a `Self::Int` transmuted back to `Self` - fn from_repr(a: Self::Int) -> Self; - - /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; - - /// Returns (normalized exponent, normalized significand) - fn normalize(significand: Self::Int) -> (i32, Self::Int); - - /// Returns if `self` is subnormal - fn is_subnormal(self) -> bool; -} -} - -macro_rules! float_impl { - ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { - impl Float for $ty { - type Int = $ity; - type SignedInt = $sity; - type ExpInt = $expty; - - const ZERO: Self = 0.0; - const ONE: Self = 1.0; - - const BITS: u32 = $bits; - const SIGNIFICAND_BITS: u32 = $significand_bits; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; - const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); - - fn repr(self) -> Self::Int { - self.to_bits() - } - fn signed_repr(self) -> Self::SignedInt { - self.to_bits() as Self::SignedInt - } - fn eq_repr(self, rhs: Self) -> bool { - #[cfg(feature = "mangled-names")] - fn is_nan(x: $ty) -> bool { - // When using mangled-names, the "real" compiler-builtins might not have the - // necessary builtin (__unordtf2) to test whether `f128` is NaN. - // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin - // x is NaN if all the bits of the exponent are set and the significand is non-0 - x.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK - && x.repr() & $ty::SIGNIFICAND_MASK != 0 - } - #[cfg(not(feature = "mangled-names"))] - fn is_nan(x: $ty) -> bool { - x.is_nan() - } - if is_nan(self) && is_nan(rhs) { - true - } else { - self.repr() == rhs.repr() - } - } - fn is_sign_negative(self) -> bool { - self.is_sign_negative() - } - fn exp(self) -> Self::ExpInt { - ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt - } - fn frac(self) -> Self::Int { - self.to_bits() & Self::SIGNIFICAND_MASK - } - fn imp_frac(self) -> Self::Int { - self.frac() | Self::IMPLICIT_BIT - } - fn from_repr(a: Self::Int) -> Self { - Self::from_bits(a) - } - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr( - ((sign as Self::Int) << (Self::BITS - 1)) - | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) - | (significand & Self::SIGNIFICAND_MASK), - ) - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand - .leading_zeros() - .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros()); - ( - 1i32.wrapping_sub(shift as i32), - significand << shift as Self::Int, - ) - } - fn is_subnormal(self) -> bool { - (self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO - } - } - }; -} +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use traits::{Float, HalfRep}; -#[cfg(f16_enabled)] -float_impl!(f16, u16, i16, i8, 16, 10); -float_impl!(f32, u32, i32, i16, 32, 23); -float_impl!(f64, u64, i64, i16, 64, 52); -#[cfg(f128_enabled)] -float_impl!(f128, u128, i128, i16, 128, 112); +#[cfg(feature = "public-test-deps")] +pub use traits::{Float, HalfRep}; diff --git a/library/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/src/float/traits.rs new file mode 100644 index 00000000000..e57bd1b9825 --- /dev/null +++ b/library/compiler-builtins/src/float/traits.rs @@ -0,0 +1,184 @@ +use core::ops; + +use crate::int::{DInt, Int, MinInt}; + +/// Wrapper to extract the integer type half of the float's size +pub type HalfRep = <::Int as DInt>::H; + +/// Trait for some basic operations on floats +#[allow(dead_code)] +pub trait Float: + Copy + + core::fmt::Debug + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::MulAssign + + ops::Add + + ops::Sub + + ops::Div + + ops::Rem +{ + /// A uint of the same width as the float + type Int: Int; + + /// A int of the same width as the float + type SignedInt: Int; + + /// An int capable of containing the exponent bits plus a sign bit. This is signed. + type ExpInt: Int; + + const ZERO: Self; + const ONE: Self; + + /// The bitwidth of the float type + const BITS: u32; + + /// The bitwidth of the significand + const SIGNIFICAND_BITS: u32; + + /// The bitwidth of the exponent + const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + + /// The maximum value of the exponent + const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; + + /// The exponent bias value + const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; + + /// A mask for the sign bit + const SIGN_MASK: Self::Int; + + /// A mask for the significand + const SIGNIFICAND_MASK: Self::Int; + + /// The implicit bit of the float format + const IMPLICIT_BIT: Self::Int; + + /// A mask for the exponent + const EXPONENT_MASK: Self::Int; + + /// Returns `self` transmuted to `Self::Int` + fn repr(self) -> Self::Int; + + /// Returns `self` transmuted to `Self::SignedInt` + fn signed_repr(self) -> Self::SignedInt; + + /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be + /// represented in multiple different ways. This method returns `true` if two NaNs are + /// compared. + fn eq_repr(self, rhs: Self) -> bool; + + /// Returns true if the sign is negative + fn is_sign_negative(self) -> bool; + + /// Returns the exponent with bias + fn exp(self) -> Self::ExpInt; + + /// Returns the significand with no implicit bit (or the "fractional" part) + fn frac(self) -> Self::Int; + + /// Returns the significand with implicit bit + fn imp_frac(self) -> Self::Int; + + /// Returns a `Self::Int` transmuted back to `Self` + fn from_repr(a: Self::Int) -> Self; + + /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; + + /// Returns (normalized exponent, normalized significand) + fn normalize(significand: Self::Int) -> (i32, Self::Int); + + /// Returns if `self` is subnormal + fn is_subnormal(self) -> bool; +} + +macro_rules! float_impl { + ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { + impl Float for $ty { + type Int = $ity; + type SignedInt = $sity; + type ExpInt = $expty; + + const ZERO: Self = 0.0; + const ONE: Self = 1.0; + + const BITS: u32 = $bits; + const SIGNIFICAND_BITS: u32 = $significand_bits; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; + const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + + fn repr(self) -> Self::Int { + self.to_bits() + } + fn signed_repr(self) -> Self::SignedInt { + self.to_bits() as Self::SignedInt + } + fn eq_repr(self, rhs: Self) -> bool { + #[cfg(feature = "mangled-names")] + fn is_nan(x: $ty) -> bool { + // When using mangled-names, the "real" compiler-builtins might not have the + // necessary builtin (__unordtf2) to test whether `f128` is NaN. + // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin + // x is NaN if all the bits of the exponent are set and the significand is non-0 + x.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK + && x.repr() & $ty::SIGNIFICAND_MASK != 0 + } + #[cfg(not(feature = "mangled-names"))] + fn is_nan(x: $ty) -> bool { + x.is_nan() + } + if is_nan(self) && is_nan(rhs) { + true + } else { + self.repr() == rhs.repr() + } + } + fn is_sign_negative(self) -> bool { + self.is_sign_negative() + } + fn exp(self) -> Self::ExpInt { + ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt + } + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIGNIFICAND_MASK + } + fn imp_frac(self) -> Self::Int { + self.frac() | Self::IMPLICIT_BIT + } + fn from_repr(a: Self::Int) -> Self { + Self::from_bits(a) + } + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_repr( + ((sign as Self::Int) << (Self::BITS - 1)) + | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) + | (significand & Self::SIGNIFICAND_MASK), + ) + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand + .leading_zeros() + .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros()); + ( + 1i32.wrapping_sub(shift as i32), + significand << shift as Self::Int, + ) + } + fn is_subnormal(self) -> bool { + (self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO + } + } + }; +} + +#[cfg(not(feature = "no-f16-f128"))] +float_impl!(f16, u16, i16, i8, 16, 10); +float_impl!(f32, u32, i32, i16, 32, 23); +float_impl!(f64, u64, i64, i16, 64, 52); +#[cfg(not(feature = "no-f16-f128"))] +float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index 1fee9fcf5d8..eede1ebe61c 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -3,137 +3,141 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. -use crate::int::{CastInto, Int}; +mod implementation { + use crate::int::{CastInto, Int}; -public_test_dep! { -/// Returns the number of leading binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn leading_zeros_default>(x: T) -> usize { - // The basic idea is to test if the higher bits of `x` are zero and bisect the number - // of leading zeros. It is possible for all branches of the bisection to use the same - // code path by conditionally shifting the higher parts down to let the next bisection - // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` - // and adding to the number of zeros, it is slightly faster to start with - // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, - // because it simplifies the final bisection step. - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS as usize; - // a temporary - let mut t: T; + /// Returns the number of leading binary zeros in `x`. + #[allow(dead_code)] + pub fn leading_zeros_default>(x: T) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS as usize; + // a temporary + let mut t: T; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - t = x >> 32; + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + t = x >> 32; + if t != T::ZERO { + z -= 32; + x = t; + } + } + if T::BITS >= 32 { + t = x >> 16; + if t != T::ZERO { + z -= 16; + x = t; + } + } + const { assert!(T::BITS >= 16) }; + t = x >> 8; if t != T::ZERO { - z -= 32; + z -= 8; x = t; } - } - if T::BITS >= 32 { - t = x >> 16; + t = x >> 4; if t != T::ZERO { - z -= 16; + z -= 4; x = t; } - } - const { assert!(T::BITS >= 16) }; - t = x >> 8; - if t != T::ZERO { - z -= 8; - x = t; - } - t = x >> 4; - if t != T::ZERO { - z -= 4; - x = t; - } - t = x >> 2; - if t != T::ZERO { - z -= 2; - x = t; - } - // the last two bisections are combined into one conditional - t = x >> 1; - if t != T::ZERO { - z - 2 - } else { - z - x.cast() - } + t = x >> 2; + if t != T::ZERO { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != T::ZERO { + z - 2 + } else { + z - x.cast() + } - // We could potentially save a few cycles by using the LUT trick from - // "https://embeddedgurus.com/state-space/2014/09/ - // fast-deterministic-and-portable-counting-leading-zeros/". - // However, 256 bytes for a LUT is too large for embedded use cases. We could remove - // the last 3 bisections and use this 16 byte LUT for the rest of the work: - //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; - //z -= LUT[x] as usize; - //z - // However, it ends up generating about the same number of instructions. When benchmarked - // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO - // execution effects. Changing to using a LUT and branching is risky for smaller cores. -} -} + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/ + // fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. + } -// The above method does not compile well on RISC-V (because of the lack of predicated -// instructions), producing code with many branches or using an excessively long -// branchless solution. This method takes advantage of the set-if-less-than instruction on -// RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + // The above method does not compile well on RISC-V (because of the lack of predicated + // instructions), producing code with many branches or using an excessively long + // branchless solution. This method takes advantage of the set-if-less-than instruction on + // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. -public_test_dep! { -/// Returns the number of leading binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn leading_zeros_riscv>(x: T) -> usize { - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS; - // a temporary - let mut t: u32; + /// Returns the number of leading binary zeros in `x`. + #[allow(dead_code)] + pub fn leading_zeros_riscv>(x: T) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS; + // a temporary + let mut t: u32; - // RISC-V does not have a set-if-greater-than-or-equal instruction and - // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is - // still the most optimal method. A conditional set can only be turned into a single - // immediate instruction if `x` is compared with an immediate `imm` (that can fit into - // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the - // right). If we try to save an instruction by using `x < imm` for each bisection, we - // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, - // but the immediate will never fit into 12 bits and never save an instruction. - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise - // `t` is set to 0. - t = ((x >= (T::ONE << 32)) as u32) << 5; - // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the - // next step to process. + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (T::ONE << 32)) as u32) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. + x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros + z -= t; + } + if T::BITS >= 32 { + t = ((x >= (T::ONE << 16)) as u32) << 4; + x >>= t; + z -= t; + } + const { assert!(T::BITS >= 16) }; + t = ((x >= (T::ONE << 8)) as u32) << 3; x >>= t; - // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential - // leading zeros z -= t; - } - if T::BITS >= 32 { - t = ((x >= (T::ONE << 16)) as u32) << 4; + t = ((x >= (T::ONE << 4)) as u32) << 2; x >>= t; z -= t; + t = ((x >= (T::ONE << 2)) as u32) << 1; + x >>= t; + z -= t; + t = (x >= (T::ONE << 1)) as u32; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z as usize - x.cast() } - const { assert!(T::BITS >= 16) }; - t = ((x >= (T::ONE << 8)) as u32) << 3; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 4)) as u32) << 2; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 2)) as u32) << 1; - x >>= t; - z -= t; - t = (x >= (T::ONE << 1)) as u32; - x >>= t; - z -= t; - // All bits except the LSB are guaranteed to be zero for this final bisection step. - // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. - z as usize - x.cast() -} } +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use implementation::*; + +#[cfg(feature = "public-test-deps")] +pub use implementation::*; + intrinsics! { /// Returns the number of leading binary zeros in `x` pub extern "C" fn __clzsi2(x: u32) -> usize { diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 5f56c6b6ee1..a0d992e136d 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,6 +1,4 @@ -use core::ops; - -mod specialized_div_rem; +pub(crate) mod specialized_div_rem; pub mod addsub; mod big; @@ -10,416 +8,13 @@ pub mod mul; pub mod sdiv; pub mod shift; pub mod trailing_zeros; +mod traits; pub mod udiv; pub use big::{i256, u256}; -public_test_dep! { -/// Minimal integer implementations needed on all integer types, including wide integers. -#[allow(dead_code)] -pub(crate) trait MinInt: Copy - + core::fmt::Debug - + ops::BitOr - + ops::Not - + ops::Shl -{ - - /// Type with the same width but other signedness - type OtherSign: MinInt; - /// Unsigned version of Self - type UnsignedInt: MinInt; - - /// If `Self` is a signed integer - const SIGNED: bool; - - /// The bitwidth of the int type - const BITS: u32; - - const ZERO: Self; - const ONE: Self; - const MIN: Self; - const MAX: Self; -} -} - -public_test_dep! { -/// Trait for some basic operations on integers -#[allow(dead_code)] -pub(crate) trait Int: MinInt - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Shr - + ops::BitXor - + ops::BitAnd -{ - /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing - /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, - /// 112,119,120,125,126,127]. - const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); - - /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. - const FUZZ_NUM: usize = { - let log2 = (::BITS - 1).count_ones() as usize; - if log2 == 3 { - // case for u8 - 6 - } else { - // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate - // boundaries. - 8 + (4 * (log2 - 4)) - } - }; - - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; - - fn from_bool(b: bool) -> Self; - - /// Prevents the need for excessive conversions between signed and unsigned - fn logical_shr(self, other: u32) -> Self; - - /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; - - // copied from primitive integers, but put in a trait - fn is_zero(self) -> bool; - fn wrapping_neg(self) -> Self; - fn wrapping_add(self, other: Self) -> Self; - fn wrapping_mul(self, other: Self) -> Self; - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - fn ilog2(self) -> u32; -} -} - -pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { - let mut v = [0u8; 20]; - v[0] = 0; - v[1] = 1; - v[2] = 2; // important for parity and the iX::MIN case when reversed - let mut i = 3; - - // No need for any more until the byte boundary, because there should be no algorithms - // that are sensitive to anything not next to byte boundaries after 2. We also scale - // in powers of two, which is important to prevent u128 corner tests from getting too - // big. - let mut l = 8; - loop { - if l >= ((bits / 2) as u8) { - break; - } - // get both sides of the byte boundary - v[i] = l - 1; - i += 1; - v[i] = l; - i += 1; - l *= 2; - } - - if bits != 8 { - // add the lower side of the middle boundary - v[i] = ((bits / 2) - 1) as u8; - i += 1; - } - - // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS - // boundary because of algorithms that split the high part up. We reverse the scaling - // as we go to Self::BITS. - let mid = i; - let mut j = 1; - loop { - v[i] = (bits as u8) - (v[mid - j]) - 1; - if j == mid { - break; - } - i += 1; - j += 1; - } - v -} - -macro_rules! int_impl_common { - ($ty:ty) => { - fn from_bool(b: bool) -> Self { - b as $ty - } - - fn logical_shr(self, other: u32) -> Self { - Self::from_unsigned(self.unsigned().wrapping_shr(other)) - } - - fn is_zero(self) -> bool { - self == Self::ZERO - } - - fn wrapping_neg(self) -> Self { - ::wrapping_neg(self) - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn wrapping_shr(self, other: u32) -> Self { - ::wrapping_shr(self, other) - } - - fn rotate_left(self, other: u32) -> Self { - ::rotate_left(self, other) - } - - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - - fn ilog2(self) -> u32 { - ::ilog2(self) - } - }; -} - -macro_rules! int_impl { - ($ity:ty, $uty:ty) => { - impl MinInt for $uty { - type OtherSign = $ity; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $uty { - fn unsigned(self) -> $uty { - self - } - - // It makes writing macros easier if this is implemented for both signed and unsigned - #[allow(clippy::wrong_self_convention)] - fn from_unsigned(me: $uty) -> Self { - me - } - - fn abs_diff(self, other: Self) -> Self { - if self < other { - other.wrapping_sub(self) - } else { - self.wrapping_sub(other) - } - } - - int_impl_common!($uty); - } - - impl MinInt for $ity { - type OtherSign = $uty; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $ity { - fn unsigned(self) -> $uty { - self as $uty - } - - fn from_unsigned(me: $uty) -> Self { - me as $ity - } - - fn abs_diff(self, other: Self) -> $uty { - self.wrapping_sub(other).wrapping_abs() as $uty - } - - int_impl_common!($ity); - } - }; -} - -int_impl!(isize, usize); -int_impl!(i8, u8); -int_impl!(i16, u16); -int_impl!(i32, u32); -int_impl!(i64, u64); -int_impl!(i128, u128); - -public_test_dep! { -/// Trait for integers twice the bit width of another integer. This is implemented for all -/// primitives except for `u8`, because there is not a smaller primitive. -pub(crate) trait DInt: MinInt { - /// Integer that is half the bit width of the integer this trait is implemented for - type H: HInt; - - /// Returns the low half of `self` - fn lo(self) -> Self::H; - /// Returns the high half of `self` - fn hi(self) -> Self::H; - /// Returns the low and high halves of `self` as a tuple - fn lo_hi(self) -> (Self::H, Self::H) { - (self.lo(), self.hi()) - } - /// Constructs an integer using lower and higher half parts - fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { - lo.zero_widen() | hi.widen_hi() - } -} -} - -public_test_dep! { -/// Trait for integers half the bit width of another integer. This is implemented for all -/// primitives except for `u128`, because it there is not a larger primitive. -pub(crate) trait HInt: Int { - /// Integer that is double the bit width of the integer this trait is implemented for - type D: DInt + MinInt; - - /// Widens (using default extension) the integer to have double bit width - fn widen(self) -> Self::D; - /// Widens (zero extension only) the integer to have double bit width. This is needed to get - /// around problems with associated type bounds (such as `Int`) being unstable - fn zero_widen(self) -> Self::D; - /// Widens the integer to have double bit width and shifts the integer into the higher bits - fn widen_hi(self) -> Self::D { - self.widen() << ::BITS - } - /// Widening multiplication with zero widening. This cannot overflow. - fn zero_widen_mul(self, rhs: Self) -> Self::D; - /// Widening multiplication. This cannot overflow. - fn widen_mul(self, rhs: Self) -> Self::D; -} -} - -macro_rules! impl_d_int { - ($($X:ident $D:ident),*) => { - $( - impl DInt for $D { - type H = $X; - - fn lo(self) -> Self::H { - self as $X - } - fn hi(self) -> Self::H { - (self >> <$X as MinInt>::BITS) as $X - } - } - )* - }; -} - -macro_rules! impl_h_int { - ($($H:ident $uH:ident $X:ident),*) => { - $( - impl HInt for $H { - type D = $X; - - fn widen(self) -> Self::D { - self as $X - } - fn zero_widen(self) -> Self::D { - (self as $uH) as $X - } - fn zero_widen_mul(self, rhs: Self) -> Self::D { - self.zero_widen().wrapping_mul(rhs.zero_widen()) - } - fn widen_mul(self, rhs: Self) -> Self::D { - self.widen().wrapping_mul(rhs.widen()) - } - } - )* - }; -} - -impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); -impl_h_int!( - u8 u8 u16, - u16 u16 u32, - u32 u32 u64, - u64 u64 u128, - i8 u8 i16, - i16 u16 i32, - i32 u32 i64, - i64 u64 i128 -); - -public_test_dep! { -/// Trait to express (possibly lossy) casting of integers -pub(crate) trait CastInto: Copy { - fn cast(self) -> T; -} - -pub(crate) trait CastFrom:Copy { - fn cast_from(value: T) -> Self; -} -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - self as $into - } - } - )*}; -} +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); +#[cfg(feature = "public-test-deps")] +pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index 330c6e4f80b..f5c6e50239a 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -185,7 +185,6 @@ macro_rules! impl_delegate { }; } -public_test_dep! { /// Returns `n / d` and sets `*rem = n % d`. /// /// This specialization exists because: @@ -195,7 +194,7 @@ public_test_dep! { /// delegate algorithm strategy the only reasonably fast way to perform `u128` division. // used on SPARC #[allow(dead_code)] -pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { +pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { use super::*; let duo_lo = duo as u64; let duo_hi = (duo >> 64) as u64; @@ -316,4 +315,3 @@ pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { } } } -} diff --git a/library/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/src/int/trailing_zeros.rs index cea366b0754..9878a16878e 100644 --- a/library/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/src/int/trailing_zeros.rs @@ -1,46 +1,52 @@ -use crate::int::{CastInto, Int}; +mod implementation { + use crate::int::{CastInto, Int}; -public_test_dep! { -/// Returns number of trailing binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { - let mut x = x; - let mut r: u32 = 0; - let mut t: u32; + /// Returns number of trailing binary zeros in `x`. + #[allow(dead_code)] + pub fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + let mut x = x; + let mut r: u32 = 0; + let mut t: u32; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 - x >>= r; // remove 32 zero bits - } + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + x >>= r; // remove 32 zero bits + } - if T::BITS >= 32 { - t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 - r += t; - x >>= t; // x = [0 - 0xFFFF] + higher garbage bits - } + if T::BITS >= 32 { + t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 + r += t; + x >>= t; // x = [0 - 0xFFFF] + higher garbage bits + } - const { assert!(T::BITS >= 16) }; - t = ((CastInto::::cast(x) == 0) as u32) << 3; - x >>= t; // x = [0 - 0xFF] + higher garbage bits - r += t; + const { assert!(T::BITS >= 16) }; + t = ((CastInto::::cast(x) == 0) as u32) << 3; + x >>= t; // x = [0 - 0xFF] + higher garbage bits + r += t; - let mut x: u8 = x.cast(); + let mut x: u8 = x.cast(); - t = (((x & 0x0F) == 0) as u32) << 2; - x >>= t; // x = [0 - 0xF] + higher garbage bits - r += t; + t = (((x & 0x0F) == 0) as u32) << 2; + x >>= t; // x = [0 - 0xF] + higher garbage bits + r += t; - t = (((x & 0x3) == 0) as u32) << 1; - x >>= t; // x = [0 - 0x3] + higher garbage bits - r += t; + t = (((x & 0x3) == 0) as u32) << 1; + x >>= t; // x = [0 - 0x3] + higher garbage bits + r += t; - x &= 3; + x &= 3; - r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) -} + r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) + } } +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use implementation::*; + +#[cfg(feature = "public-test-deps")] +pub use implementation::*; + intrinsics! { /// Returns the number of trailing binary zeros in `x` (32 bit version). pub extern "C" fn __ctzsi2(x: u32) -> usize { diff --git a/library/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/src/int/traits.rs new file mode 100644 index 00000000000..e9d8796273a --- /dev/null +++ b/library/compiler-builtins/src/int/traits.rs @@ -0,0 +1,402 @@ +use core::ops; + +/// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] +pub trait MinInt: + Copy + + core::fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type UnsignedInt: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} + +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub trait Int: + MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, + /// 112,119,120,125,126,127]. + const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); + + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; + + fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} + +const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn unsigned(self) -> $uty { + self + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn abs_diff(self, other: Self) -> Self { + if self < other { + other.wrapping_sub(self) + } else { + self.wrapping_sub(other) + } + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn unsigned(self) -> $uty { + self as $uty + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn abs_diff(self, other: Self) -> $uty { + self.wrapping_sub(other).wrapping_abs() as $uty + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +/// Trait for integers twice the bit width of another integer. This is implemented for all +/// primitives except for `u8`, because there is not a smaller primitive. +pub trait DInt: MinInt { + /// Integer that is half the bit width of the integer this trait is implemented for + type H: HInt; + + /// Returns the low half of `self` + fn lo(self) -> Self::H; + /// Returns the high half of `self` + fn hi(self) -> Self::H; + /// Returns the low and high halves of `self` as a tuple + fn lo_hi(self) -> (Self::H, Self::H) { + (self.lo(), self.hi()) + } + /// Constructs an integer using lower and higher half parts + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { + lo.zero_widen() | hi.widen_hi() + } +} + +/// Trait for integers half the bit width of another integer. This is implemented for all +/// primitives except for `u128`, because it there is not a larger primitive. +pub trait HInt: Int { + /// Integer that is double the bit width of the integer this trait is implemented for + type D: DInt + MinInt; + + /// Widens (using default extension) the integer to have double bit width + fn widen(self) -> Self::D; + /// Widens (zero extension only) the integer to have double bit width. This is needed to get + /// around problems with associated type bounds (such as `Int`) being unstable + fn zero_widen(self) -> Self::D; + /// Widens the integer to have double bit width and shifts the integer into the higher bits + fn widen_hi(self) -> Self::D { + self.widen() << ::BITS + } + /// Widening multiplication with zero widening. This cannot overflow. + fn zero_widen_mul(self, rhs: Self) -> Self::D; + /// Widening multiplication. This cannot overflow. + fn widen_mul(self, rhs: Self) -> Self::D; +} + +macro_rules! impl_d_int { + ($($X:ident $D:ident),*) => { + $( + impl DInt for $D { + type H = $X; + + fn lo(self) -> Self::H { + self as $X + } + fn hi(self) -> Self::H { + (self >> <$X as MinInt>::BITS) as $X + } + } + )* + }; +} + +macro_rules! impl_h_int { + ($($H:ident $uH:ident $X:ident),*) => { + $( + impl HInt for $H { + type D = $X; + + fn widen(self) -> Self::D { + self as $X + } + fn zero_widen(self) -> Self::D { + (self as $uH) as $X + } + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen().wrapping_mul(rhs.zero_widen()) + } + fn widen_mul(self, rhs: Self) -> Self::D { + self.widen().wrapping_mul(rhs.widen()) + } + } + )* + }; +} + +impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); +impl_h_int!( + u8 u8 u16, + u16 u16 u32, + u32 u32 u64, + u64 u64 u128, + i8 u8 i16, + i16 u16 i32, + i32 u32 i64, + i64 u64 i128 +); + +/// Trait to express (possibly lossy) casting of integers +pub trait CastInto: Copy { + fn cast(self) -> T; +} + +pub trait CastFrom: Copy { + fn cast_from(value: T) -> Self; +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} + +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 42c83ee55fb..9f951d51585 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,21 +1,5 @@ //! Macros shared throughout the compiler-builtins implementation -/// Changes the visibility to `pub` if feature "public-test-deps" is set -#[cfg(not(feature = "public-test-deps"))] -macro_rules! public_test_dep { - ($(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => { - $(#[$($meta)*])* pub(crate) $ident $($tokens)* - }; -} - -/// Changes the visibility to `pub` if feature "public-test-deps" is set -#[cfg(feature = "public-test-deps")] -macro_rules! public_test_dep { - {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*} => { - $(#[$($meta)*])* pub $ident $($tokens)* - }; -} - /// The "main macro" used for defining intrinsics. /// /// The compiler-builtins library is super platform-specific with tons of crazy -- cgit 1.4.1-3-g733a5 From c1a498db17b5eadc4f17048fb2f11aa8d578732f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 Aug 2024 17:16:03 +0200 Subject: Add `only-soft-floats` feature to prevent using any intrinsics or arch-specific code --- library/compiler-builtins/libm/Cargo.toml | 3 +++ .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 1 + library/compiler-builtins/libm/src/math/mod.rs | 2 +- library/compiler-builtins/libm/src/math/sqrt.rs | 4 ++-- library/compiler-builtins/libm/src/math/sqrtf.rs | 4 ++-- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index d33ca61cd47..893a2e19d35 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -23,6 +23,9 @@ unstable = [] # musl libc. musl-reference-tests = ['rand'] +# Used to prevent using any intrinsics or arch-specific code. +only-soft-floats = [] + [workspace] members = [ "crates/compiler-builtins-smoke-test", diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 695b710ff30..ec48ca20601 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -10,3 +10,4 @@ bench = false [features] unstable = [] checked = [] +only-soft-floats = [] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 05ebb708c9c..04d3bbb6203 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -76,7 +76,7 @@ macro_rules! div { macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all(feature = "unstable", $($clause)*))] + #[cfg(all(feature = "unstable", not(feature = "only-soft-floats"), $($clause)*))] { if true { // thwart the dead code lint $e diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index baa0db9f8d1..a0003cb0566 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -92,7 +92,7 @@ pub fn sqrt(x: f64) -> f64 { } } } - #[cfg(target_feature = "sse2")] + #[cfg(all(target_feature = "sse2", not(feature = "only-soft-floats")))] { // Note: This path is unlikely since LLVM will usually have already // optimized sqrt calls into hardware instructions if sse2 is available, @@ -107,7 +107,7 @@ pub fn sqrt(x: f64) -> f64 { _mm_cvtsd_f64(m_sqrt) } } - #[cfg(not(target_feature = "sse2"))] + #[cfg(any(not(target_feature = "sse2"), feature = "only-soft-floats"))] { use core::num::Wrapping; diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 12bd60028ee..0cef073ea3e 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -27,7 +27,7 @@ pub fn sqrtf(x: f32) -> f32 { } } } - #[cfg(target_feature = "sse")] + #[cfg(all(target_feature = "sse", not(feature = "only-soft-floats")))] { // Note: This path is unlikely since LLVM will usually have already // optimized sqrt calls into hardware instructions if sse is available, @@ -42,7 +42,7 @@ pub fn sqrtf(x: f32) -> f32 { _mm_cvtss_f32(m_sqrt) } } - #[cfg(not(target_feature = "sse"))] + #[cfg(any(not(target_feature = "sse"), feature = "only-soft-floats"))] { const TINY: f32 = 1.0e-30; -- cgit 1.4.1-3-g733a5 From 41df199623a12fbf79097e2d0aa5c7b1eeca2cb5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 21:48:51 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 805b44cad0f..6c07fd555ef 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.115" +version = "0.1.116" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 14bd1e6ae194c6688b69184bde987dc31c3fe5aa Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 6 Aug 2024 22:11:19 -0400 Subject: Revert "Eliminate the use of `public_test_dep!`" --- library/compiler-builtins/src/float/mod.rs | 190 +++++++++- library/compiler-builtins/src/float/traits.rs | 184 --------- library/compiler-builtins/src/int/leading_zeros.rs | 228 ++++++----- library/compiler-builtins/src/int/mod.rs | 417 ++++++++++++++++++++- .../src/int/specialized_div_rem/delegate.rs | 4 +- .../compiler-builtins/src/int/trailing_zeros.rs | 70 ++-- library/compiler-builtins/src/int/traits.rs | 402 -------------------- library/compiler-builtins/src/macros.rs | 16 + 8 files changed, 759 insertions(+), 752 deletions(-) delete mode 100644 library/compiler-builtins/src/float/traits.rs delete mode 100644 library/compiler-builtins/src/int/traits.rs diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 41b308626b3..8473732057a 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,3 +1,7 @@ +use core::ops; + +use crate::int::{DInt, Int, MinInt}; + pub mod add; pub mod cmp; pub mod conv; @@ -6,11 +10,187 @@ pub mod extend; pub mod mul; pub mod pow; pub mod sub; -pub(crate) mod traits; pub mod trunc; -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use traits::{Float, HalfRep}; +/// Wrapper to extract the integer type half of the float's size +pub(crate) type HalfRep = <::Int as DInt>::H; + +public_test_dep! { +/// Trait for some basic operations on floats +#[allow(dead_code)] +pub(crate) trait Float: + Copy + + core::fmt::Debug + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::MulAssign + + ops::Add + + ops::Sub + + ops::Div + + ops::Rem +{ + /// A uint of the same width as the float + type Int: Int; + + /// A int of the same width as the float + type SignedInt: Int; + + /// An int capable of containing the exponent bits plus a sign bit. This is signed. + type ExpInt: Int; + + const ZERO: Self; + const ONE: Self; + + /// The bitwidth of the float type + const BITS: u32; + + /// The bitwidth of the significand + const SIGNIFICAND_BITS: u32; + + /// The bitwidth of the exponent + const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + + /// The maximum value of the exponent + const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; + + /// The exponent bias value + const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; + + /// A mask for the sign bit + const SIGN_MASK: Self::Int; + + /// A mask for the significand + const SIGNIFICAND_MASK: Self::Int; + + /// The implicit bit of the float format + const IMPLICIT_BIT: Self::Int; + + /// A mask for the exponent + const EXPONENT_MASK: Self::Int; + + /// Returns `self` transmuted to `Self::Int` + fn repr(self) -> Self::Int; + + /// Returns `self` transmuted to `Self::SignedInt` + fn signed_repr(self) -> Self::SignedInt; + + /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be + /// represented in multiple different ways. This method returns `true` if two NaNs are + /// compared. + fn eq_repr(self, rhs: Self) -> bool; + + /// Returns true if the sign is negative + fn is_sign_negative(self) -> bool; + + /// Returns the exponent with bias + fn exp(self) -> Self::ExpInt; + + /// Returns the significand with no implicit bit (or the "fractional" part) + fn frac(self) -> Self::Int; + + /// Returns the significand with implicit bit + fn imp_frac(self) -> Self::Int; + + /// Returns a `Self::Int` transmuted back to `Self` + fn from_repr(a: Self::Int) -> Self; + + /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; + + /// Returns (normalized exponent, normalized significand) + fn normalize(significand: Self::Int) -> (i32, Self::Int); + + /// Returns if `self` is subnormal + fn is_subnormal(self) -> bool; +} +} + +macro_rules! float_impl { + ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { + impl Float for $ty { + type Int = $ity; + type SignedInt = $sity; + type ExpInt = $expty; + + const ZERO: Self = 0.0; + const ONE: Self = 1.0; + + const BITS: u32 = $bits; + const SIGNIFICAND_BITS: u32 = $significand_bits; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; + const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + + fn repr(self) -> Self::Int { + self.to_bits() + } + fn signed_repr(self) -> Self::SignedInt { + self.to_bits() as Self::SignedInt + } + fn eq_repr(self, rhs: Self) -> bool { + #[cfg(feature = "mangled-names")] + fn is_nan(x: $ty) -> bool { + // When using mangled-names, the "real" compiler-builtins might not have the + // necessary builtin (__unordtf2) to test whether `f128` is NaN. + // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin + // x is NaN if all the bits of the exponent are set and the significand is non-0 + x.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK + && x.repr() & $ty::SIGNIFICAND_MASK != 0 + } + #[cfg(not(feature = "mangled-names"))] + fn is_nan(x: $ty) -> bool { + x.is_nan() + } + if is_nan(self) && is_nan(rhs) { + true + } else { + self.repr() == rhs.repr() + } + } + fn is_sign_negative(self) -> bool { + self.is_sign_negative() + } + fn exp(self) -> Self::ExpInt { + ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt + } + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIGNIFICAND_MASK + } + fn imp_frac(self) -> Self::Int { + self.frac() | Self::IMPLICIT_BIT + } + fn from_repr(a: Self::Int) -> Self { + Self::from_bits(a) + } + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_repr( + ((sign as Self::Int) << (Self::BITS - 1)) + | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) + | (significand & Self::SIGNIFICAND_MASK), + ) + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand + .leading_zeros() + .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros()); + ( + 1i32.wrapping_sub(shift as i32), + significand << shift as Self::Int, + ) + } + fn is_subnormal(self) -> bool { + (self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO + } + } + }; +} -#[cfg(feature = "public-test-deps")] -pub use traits::{Float, HalfRep}; +#[cfg(f16_enabled)] +float_impl!(f16, u16, i16, i8, 16, 10); +float_impl!(f32, u32, i32, i16, 32, 23); +float_impl!(f64, u64, i64, i16, 64, 52); +#[cfg(f128_enabled)] +float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/src/float/traits.rs deleted file mode 100644 index e57bd1b9825..00000000000 --- a/library/compiler-builtins/src/float/traits.rs +++ /dev/null @@ -1,184 +0,0 @@ -use core::ops; - -use crate::int::{DInt, Int, MinInt}; - -/// Wrapper to extract the integer type half of the float's size -pub type HalfRep = <::Int as DInt>::H; - -/// Trait for some basic operations on floats -#[allow(dead_code)] -pub trait Float: - Copy - + core::fmt::Debug - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::MulAssign - + ops::Add - + ops::Sub - + ops::Div - + ops::Rem -{ - /// A uint of the same width as the float - type Int: Int; - - /// A int of the same width as the float - type SignedInt: Int; - - /// An int capable of containing the exponent bits plus a sign bit. This is signed. - type ExpInt: Int; - - const ZERO: Self; - const ONE: Self; - - /// The bitwidth of the float type - const BITS: u32; - - /// The bitwidth of the significand - const SIGNIFICAND_BITS: u32; - - /// The bitwidth of the exponent - const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; - - /// The maximum value of the exponent - const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; - - /// The exponent bias value - const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; - - /// A mask for the sign bit - const SIGN_MASK: Self::Int; - - /// A mask for the significand - const SIGNIFICAND_MASK: Self::Int; - - /// The implicit bit of the float format - const IMPLICIT_BIT: Self::Int; - - /// A mask for the exponent - const EXPONENT_MASK: Self::Int; - - /// Returns `self` transmuted to `Self::Int` - fn repr(self) -> Self::Int; - - /// Returns `self` transmuted to `Self::SignedInt` - fn signed_repr(self) -> Self::SignedInt; - - /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. This method returns `true` if two NaNs are - /// compared. - fn eq_repr(self, rhs: Self) -> bool; - - /// Returns true if the sign is negative - fn is_sign_negative(self) -> bool; - - /// Returns the exponent with bias - fn exp(self) -> Self::ExpInt; - - /// Returns the significand with no implicit bit (or the "fractional" part) - fn frac(self) -> Self::Int; - - /// Returns the significand with implicit bit - fn imp_frac(self) -> Self::Int; - - /// Returns a `Self::Int` transmuted back to `Self` - fn from_repr(a: Self::Int) -> Self; - - /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; - - /// Returns (normalized exponent, normalized significand) - fn normalize(significand: Self::Int) -> (i32, Self::Int); - - /// Returns if `self` is subnormal - fn is_subnormal(self) -> bool; -} - -macro_rules! float_impl { - ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { - impl Float for $ty { - type Int = $ity; - type SignedInt = $sity; - type ExpInt = $expty; - - const ZERO: Self = 0.0; - const ONE: Self = 1.0; - - const BITS: u32 = $bits; - const SIGNIFICAND_BITS: u32 = $significand_bits; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; - const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); - - fn repr(self) -> Self::Int { - self.to_bits() - } - fn signed_repr(self) -> Self::SignedInt { - self.to_bits() as Self::SignedInt - } - fn eq_repr(self, rhs: Self) -> bool { - #[cfg(feature = "mangled-names")] - fn is_nan(x: $ty) -> bool { - // When using mangled-names, the "real" compiler-builtins might not have the - // necessary builtin (__unordtf2) to test whether `f128` is NaN. - // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin - // x is NaN if all the bits of the exponent are set and the significand is non-0 - x.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK - && x.repr() & $ty::SIGNIFICAND_MASK != 0 - } - #[cfg(not(feature = "mangled-names"))] - fn is_nan(x: $ty) -> bool { - x.is_nan() - } - if is_nan(self) && is_nan(rhs) { - true - } else { - self.repr() == rhs.repr() - } - } - fn is_sign_negative(self) -> bool { - self.is_sign_negative() - } - fn exp(self) -> Self::ExpInt { - ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt - } - fn frac(self) -> Self::Int { - self.to_bits() & Self::SIGNIFICAND_MASK - } - fn imp_frac(self) -> Self::Int { - self.frac() | Self::IMPLICIT_BIT - } - fn from_repr(a: Self::Int) -> Self { - Self::from_bits(a) - } - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr( - ((sign as Self::Int) << (Self::BITS - 1)) - | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) - | (significand & Self::SIGNIFICAND_MASK), - ) - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand - .leading_zeros() - .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros()); - ( - 1i32.wrapping_sub(shift as i32), - significand << shift as Self::Int, - ) - } - fn is_subnormal(self) -> bool { - (self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO - } - } - }; -} - -#[cfg(not(feature = "no-f16-f128"))] -float_impl!(f16, u16, i16, i8, 16, 10); -float_impl!(f32, u32, i32, i16, 32, 23); -float_impl!(f64, u64, i64, i16, 64, 52); -#[cfg(not(feature = "no-f16-f128"))] -float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index eede1ebe61c..1fee9fcf5d8 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -3,140 +3,136 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. -mod implementation { - use crate::int::{CastInto, Int}; +use crate::int::{CastInto, Int}; - /// Returns the number of leading binary zeros in `x`. - #[allow(dead_code)] - pub fn leading_zeros_default>(x: T) -> usize { - // The basic idea is to test if the higher bits of `x` are zero and bisect the number - // of leading zeros. It is possible for all branches of the bisection to use the same - // code path by conditionally shifting the higher parts down to let the next bisection - // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` - // and adding to the number of zeros, it is slightly faster to start with - // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, - // because it simplifies the final bisection step. - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS as usize; - // a temporary - let mut t: T; +public_test_dep! { +/// Returns the number of leading binary zeros in `x`. +#[allow(dead_code)] +pub(crate) fn leading_zeros_default>(x: T) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS as usize; + // a temporary + let mut t: T; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - t = x >> 32; - if t != T::ZERO { - z -= 32; - x = t; - } - } - if T::BITS >= 32 { - t = x >> 16; - if t != T::ZERO { - z -= 16; - x = t; - } - } - const { assert!(T::BITS >= 16) }; - t = x >> 8; + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + t = x >> 32; if t != T::ZERO { - z -= 8; + z -= 32; x = t; } - t = x >> 4; - if t != T::ZERO { - z -= 4; - x = t; - } - t = x >> 2; + } + if T::BITS >= 32 { + t = x >> 16; if t != T::ZERO { - z -= 2; + z -= 16; x = t; } - // the last two bisections are combined into one conditional - t = x >> 1; - if t != T::ZERO { - z - 2 - } else { - z - x.cast() - } - - // We could potentially save a few cycles by using the LUT trick from - // "https://embeddedgurus.com/state-space/2014/09/ - // fast-deterministic-and-portable-counting-leading-zeros/". - // However, 256 bytes for a LUT is too large for embedded use cases. We could remove - // the last 3 bisections and use this 16 byte LUT for the rest of the work: - //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; - //z -= LUT[x] as usize; - //z - // However, it ends up generating about the same number of instructions. When benchmarked - // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO - // execution effects. Changing to using a LUT and branching is risky for smaller cores. + } + const { assert!(T::BITS >= 16) }; + t = x >> 8; + if t != T::ZERO { + z -= 8; + x = t; + } + t = x >> 4; + if t != T::ZERO { + z -= 4; + x = t; + } + t = x >> 2; + if t != T::ZERO { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != T::ZERO { + z - 2 + } else { + z - x.cast() } - // The above method does not compile well on RISC-V (because of the lack of predicated - // instructions), producing code with many branches or using an excessively long - // branchless solution. This method takes advantage of the set-if-less-than instruction on - // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/ + // fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. +} +} - /// Returns the number of leading binary zeros in `x`. - #[allow(dead_code)] - pub fn leading_zeros_riscv>(x: T) -> usize { - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS; - // a temporary - let mut t: u32; +// The above method does not compile well on RISC-V (because of the lack of predicated +// instructions), producing code with many branches or using an excessively long +// branchless solution. This method takes advantage of the set-if-less-than instruction on +// RISC-V that allows `(x >= power-of-two) as usize` to be branchless. - // RISC-V does not have a set-if-greater-than-or-equal instruction and - // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is - // still the most optimal method. A conditional set can only be turned into a single - // immediate instruction if `x` is compared with an immediate `imm` (that can fit into - // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the - // right). If we try to save an instruction by using `x < imm` for each bisection, we - // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, - // but the immediate will never fit into 12 bits and never save an instruction. - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise - // `t` is set to 0. - t = ((x >= (T::ONE << 32)) as u32) << 5; - // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the - // next step to process. - x >>= t; - // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential - // leading zeros - z -= t; - } - if T::BITS >= 32 { - t = ((x >= (T::ONE << 16)) as u32) << 4; - x >>= t; - z -= t; - } - const { assert!(T::BITS >= 16) }; - t = ((x >= (T::ONE << 8)) as u32) << 3; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 4)) as u32) << 2; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 2)) as u32) << 1; +public_test_dep! { +/// Returns the number of leading binary zeros in `x`. +#[allow(dead_code)] +pub(crate) fn leading_zeros_riscv>(x: T) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS; + // a temporary + let mut t: u32; + + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (T::ONE << 32)) as u32) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros z -= t; - t = (x >= (T::ONE << 1)) as u32; + } + if T::BITS >= 32 { + t = ((x >= (T::ONE << 16)) as u32) << 4; x >>= t; z -= t; - // All bits except the LSB are guaranteed to be zero for this final bisection step. - // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. - z as usize - x.cast() } + const { assert!(T::BITS >= 16) }; + t = ((x >= (T::ONE << 8)) as u32) << 3; + x >>= t; + z -= t; + t = ((x >= (T::ONE << 4)) as u32) << 2; + x >>= t; + z -= t; + t = ((x >= (T::ONE << 2)) as u32) << 1; + x >>= t; + z -= t; + t = (x >= (T::ONE << 1)) as u32; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z as usize - x.cast() +} } - -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use implementation::*; - -#[cfg(feature = "public-test-deps")] -pub use implementation::*; intrinsics! { /// Returns the number of leading binary zeros in `x` diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index a0d992e136d..5f56c6b6ee1 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,4 +1,6 @@ -pub(crate) mod specialized_div_rem; +use core::ops; + +mod specialized_div_rem; pub mod addsub; mod big; @@ -8,13 +10,416 @@ pub mod mul; pub mod sdiv; pub mod shift; pub mod trailing_zeros; -mod traits; pub mod udiv; pub use big::{i256, u256}; -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; +public_test_dep! { +/// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] +pub(crate) trait MinInt: Copy + + core::fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type UnsignedInt: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} +} + +public_test_dep! { +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub(crate) trait Int: MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, + /// 112,119,120,125,126,127]. + const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); + + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; + + fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} +} + +pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn unsigned(self) -> $uty { + self + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn abs_diff(self, other: Self) -> Self { + if self < other { + other.wrapping_sub(self) + } else { + self.wrapping_sub(other) + } + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn unsigned(self) -> $uty { + self as $uty + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn abs_diff(self, other: Self) -> $uty { + self.wrapping_sub(other).wrapping_abs() as $uty + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +public_test_dep! { +/// Trait for integers twice the bit width of another integer. This is implemented for all +/// primitives except for `u8`, because there is not a smaller primitive. +pub(crate) trait DInt: MinInt { + /// Integer that is half the bit width of the integer this trait is implemented for + type H: HInt; + + /// Returns the low half of `self` + fn lo(self) -> Self::H; + /// Returns the high half of `self` + fn hi(self) -> Self::H; + /// Returns the low and high halves of `self` as a tuple + fn lo_hi(self) -> (Self::H, Self::H) { + (self.lo(), self.hi()) + } + /// Constructs an integer using lower and higher half parts + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { + lo.zero_widen() | hi.widen_hi() + } +} +} + +public_test_dep! { +/// Trait for integers half the bit width of another integer. This is implemented for all +/// primitives except for `u128`, because it there is not a larger primitive. +pub(crate) trait HInt: Int { + /// Integer that is double the bit width of the integer this trait is implemented for + type D: DInt + MinInt; + + /// Widens (using default extension) the integer to have double bit width + fn widen(self) -> Self::D; + /// Widens (zero extension only) the integer to have double bit width. This is needed to get + /// around problems with associated type bounds (such as `Int`) being unstable + fn zero_widen(self) -> Self::D; + /// Widens the integer to have double bit width and shifts the integer into the higher bits + fn widen_hi(self) -> Self::D { + self.widen() << ::BITS + } + /// Widening multiplication with zero widening. This cannot overflow. + fn zero_widen_mul(self, rhs: Self) -> Self::D; + /// Widening multiplication. This cannot overflow. + fn widen_mul(self, rhs: Self) -> Self::D; +} +} + +macro_rules! impl_d_int { + ($($X:ident $D:ident),*) => { + $( + impl DInt for $D { + type H = $X; + + fn lo(self) -> Self::H { + self as $X + } + fn hi(self) -> Self::H { + (self >> <$X as MinInt>::BITS) as $X + } + } + )* + }; +} + +macro_rules! impl_h_int { + ($($H:ident $uH:ident $X:ident),*) => { + $( + impl HInt for $H { + type D = $X; + + fn widen(self) -> Self::D { + self as $X + } + fn zero_widen(self) -> Self::D { + (self as $uH) as $X + } + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen().wrapping_mul(rhs.zero_widen()) + } + fn widen_mul(self, rhs: Self) -> Self::D { + self.widen().wrapping_mul(rhs.widen()) + } + } + )* + }; +} + +impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); +impl_h_int!( + u8 u8 u16, + u16 u16 u32, + u32 u32 u64, + u64 u64 u128, + i8 u8 i16, + i16 u16 i32, + i32 u32 i64, + i64 u64 i128 +); + +public_test_dep! { +/// Trait to express (possibly lossy) casting of integers +pub(crate) trait CastInto: Copy { + fn cast(self) -> T; +} + +pub(crate) trait CastFrom:Copy { + fn cast_from(value: T) -> Self; +} +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} -#[cfg(feature = "public-test-deps")] -pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index f5c6e50239a..330c6e4f80b 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -185,6 +185,7 @@ macro_rules! impl_delegate { }; } +public_test_dep! { /// Returns `n / d` and sets `*rem = n % d`. /// /// This specialization exists because: @@ -194,7 +195,7 @@ macro_rules! impl_delegate { /// delegate algorithm strategy the only reasonably fast way to perform `u128` division. // used on SPARC #[allow(dead_code)] -pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { +pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { use super::*; let duo_lo = duo as u64; let duo_hi = (duo >> 64) as u64; @@ -315,3 +316,4 @@ pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { } } } +} diff --git a/library/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/src/int/trailing_zeros.rs index 9878a16878e..cea366b0754 100644 --- a/library/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/src/int/trailing_zeros.rs @@ -1,51 +1,45 @@ -mod implementation { - use crate::int::{CastInto, Int}; +use crate::int::{CastInto, Int}; - /// Returns number of trailing binary zeros in `x`. - #[allow(dead_code)] - pub fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { - let mut x = x; - let mut r: u32 = 0; - let mut t: u32; +public_test_dep! { +/// Returns number of trailing binary zeros in `x`. +#[allow(dead_code)] +pub(crate) fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + let mut x = x; + let mut r: u32 = 0; + let mut t: u32; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 - x >>= r; // remove 32 zero bits - } - - if T::BITS >= 32 { - t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 - r += t; - x >>= t; // x = [0 - 0xFFFF] + higher garbage bits - } + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + x >>= r; // remove 32 zero bits + } - const { assert!(T::BITS >= 16) }; - t = ((CastInto::::cast(x) == 0) as u32) << 3; - x >>= t; // x = [0 - 0xFF] + higher garbage bits + if T::BITS >= 32 { + t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 r += t; + x >>= t; // x = [0 - 0xFFFF] + higher garbage bits + } - let mut x: u8 = x.cast(); - - t = (((x & 0x0F) == 0) as u32) << 2; - x >>= t; // x = [0 - 0xF] + higher garbage bits - r += t; + const { assert!(T::BITS >= 16) }; + t = ((CastInto::::cast(x) == 0) as u32) << 3; + x >>= t; // x = [0 - 0xFF] + higher garbage bits + r += t; - t = (((x & 0x3) == 0) as u32) << 1; - x >>= t; // x = [0 - 0x3] + higher garbage bits - r += t; + let mut x: u8 = x.cast(); - x &= 3; + t = (((x & 0x0F) == 0) as u32) << 2; + x >>= t; // x = [0 - 0xF] + higher garbage bits + r += t; - r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) - } -} + t = (((x & 0x3) == 0) as u32) << 1; + x >>= t; // x = [0 - 0x3] + higher garbage bits + r += t; -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use implementation::*; + x &= 3; -#[cfg(feature = "public-test-deps")] -pub use implementation::*; + r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) +} +} intrinsics! { /// Returns the number of trailing binary zeros in `x` (32 bit version). diff --git a/library/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/src/int/traits.rs deleted file mode 100644 index e9d8796273a..00000000000 --- a/library/compiler-builtins/src/int/traits.rs +++ /dev/null @@ -1,402 +0,0 @@ -use core::ops; - -/// Minimal integer implementations needed on all integer types, including wide integers. -#[allow(dead_code)] -pub trait MinInt: - Copy - + core::fmt::Debug - + ops::BitOr - + ops::Not - + ops::Shl -{ - /// Type with the same width but other signedness - type OtherSign: MinInt; - /// Unsigned version of Self - type UnsignedInt: MinInt; - - /// If `Self` is a signed integer - const SIGNED: bool; - - /// The bitwidth of the int type - const BITS: u32; - - const ZERO: Self; - const ONE: Self; - const MIN: Self; - const MAX: Self; -} - -/// Trait for some basic operations on integers -#[allow(dead_code)] -pub trait Int: - MinInt - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Shr - + ops::BitXor - + ops::BitAnd -{ - /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing - /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, - /// 112,119,120,125,126,127]. - const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); - - /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. - const FUZZ_NUM: usize = { - let log2 = (::BITS - 1).count_ones() as usize; - if log2 == 3 { - // case for u8 - 6 - } else { - // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate - // boundaries. - 8 + (4 * (log2 - 4)) - } - }; - - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; - - fn from_bool(b: bool) -> Self; - - /// Prevents the need for excessive conversions between signed and unsigned - fn logical_shr(self, other: u32) -> Self; - - /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; - - // copied from primitive integers, but put in a trait - fn is_zero(self) -> bool; - fn wrapping_neg(self) -> Self; - fn wrapping_add(self, other: Self) -> Self; - fn wrapping_mul(self, other: Self) -> Self; - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - fn ilog2(self) -> u32; -} - -const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { - let mut v = [0u8; 20]; - v[0] = 0; - v[1] = 1; - v[2] = 2; // important for parity and the iX::MIN case when reversed - let mut i = 3; - - // No need for any more until the byte boundary, because there should be no algorithms - // that are sensitive to anything not next to byte boundaries after 2. We also scale - // in powers of two, which is important to prevent u128 corner tests from getting too - // big. - let mut l = 8; - loop { - if l >= ((bits / 2) as u8) { - break; - } - // get both sides of the byte boundary - v[i] = l - 1; - i += 1; - v[i] = l; - i += 1; - l *= 2; - } - - if bits != 8 { - // add the lower side of the middle boundary - v[i] = ((bits / 2) - 1) as u8; - i += 1; - } - - // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS - // boundary because of algorithms that split the high part up. We reverse the scaling - // as we go to Self::BITS. - let mid = i; - let mut j = 1; - loop { - v[i] = (bits as u8) - (v[mid - j]) - 1; - if j == mid { - break; - } - i += 1; - j += 1; - } - v -} - -macro_rules! int_impl_common { - ($ty:ty) => { - fn from_bool(b: bool) -> Self { - b as $ty - } - - fn logical_shr(self, other: u32) -> Self { - Self::from_unsigned(self.unsigned().wrapping_shr(other)) - } - - fn is_zero(self) -> bool { - self == Self::ZERO - } - - fn wrapping_neg(self) -> Self { - ::wrapping_neg(self) - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn wrapping_shr(self, other: u32) -> Self { - ::wrapping_shr(self, other) - } - - fn rotate_left(self, other: u32) -> Self { - ::rotate_left(self, other) - } - - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - - fn ilog2(self) -> u32 { - ::ilog2(self) - } - }; -} - -macro_rules! int_impl { - ($ity:ty, $uty:ty) => { - impl MinInt for $uty { - type OtherSign = $ity; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $uty { - fn unsigned(self) -> $uty { - self - } - - // It makes writing macros easier if this is implemented for both signed and unsigned - #[allow(clippy::wrong_self_convention)] - fn from_unsigned(me: $uty) -> Self { - me - } - - fn abs_diff(self, other: Self) -> Self { - if self < other { - other.wrapping_sub(self) - } else { - self.wrapping_sub(other) - } - } - - int_impl_common!($uty); - } - - impl MinInt for $ity { - type OtherSign = $uty; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $ity { - fn unsigned(self) -> $uty { - self as $uty - } - - fn from_unsigned(me: $uty) -> Self { - me as $ity - } - - fn abs_diff(self, other: Self) -> $uty { - self.wrapping_sub(other).wrapping_abs() as $uty - } - - int_impl_common!($ity); - } - }; -} - -int_impl!(isize, usize); -int_impl!(i8, u8); -int_impl!(i16, u16); -int_impl!(i32, u32); -int_impl!(i64, u64); -int_impl!(i128, u128); - -/// Trait for integers twice the bit width of another integer. This is implemented for all -/// primitives except for `u8`, because there is not a smaller primitive. -pub trait DInt: MinInt { - /// Integer that is half the bit width of the integer this trait is implemented for - type H: HInt; - - /// Returns the low half of `self` - fn lo(self) -> Self::H; - /// Returns the high half of `self` - fn hi(self) -> Self::H; - /// Returns the low and high halves of `self` as a tuple - fn lo_hi(self) -> (Self::H, Self::H) { - (self.lo(), self.hi()) - } - /// Constructs an integer using lower and higher half parts - fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { - lo.zero_widen() | hi.widen_hi() - } -} - -/// Trait for integers half the bit width of another integer. This is implemented for all -/// primitives except for `u128`, because it there is not a larger primitive. -pub trait HInt: Int { - /// Integer that is double the bit width of the integer this trait is implemented for - type D: DInt + MinInt; - - /// Widens (using default extension) the integer to have double bit width - fn widen(self) -> Self::D; - /// Widens (zero extension only) the integer to have double bit width. This is needed to get - /// around problems with associated type bounds (such as `Int`) being unstable - fn zero_widen(self) -> Self::D; - /// Widens the integer to have double bit width and shifts the integer into the higher bits - fn widen_hi(self) -> Self::D { - self.widen() << ::BITS - } - /// Widening multiplication with zero widening. This cannot overflow. - fn zero_widen_mul(self, rhs: Self) -> Self::D; - /// Widening multiplication. This cannot overflow. - fn widen_mul(self, rhs: Self) -> Self::D; -} - -macro_rules! impl_d_int { - ($($X:ident $D:ident),*) => { - $( - impl DInt for $D { - type H = $X; - - fn lo(self) -> Self::H { - self as $X - } - fn hi(self) -> Self::H { - (self >> <$X as MinInt>::BITS) as $X - } - } - )* - }; -} - -macro_rules! impl_h_int { - ($($H:ident $uH:ident $X:ident),*) => { - $( - impl HInt for $H { - type D = $X; - - fn widen(self) -> Self::D { - self as $X - } - fn zero_widen(self) -> Self::D { - (self as $uH) as $X - } - fn zero_widen_mul(self, rhs: Self) -> Self::D { - self.zero_widen().wrapping_mul(rhs.zero_widen()) - } - fn widen_mul(self, rhs: Self) -> Self::D { - self.widen().wrapping_mul(rhs.widen()) - } - } - )* - }; -} - -impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); -impl_h_int!( - u8 u8 u16, - u16 u16 u32, - u32 u32 u64, - u64 u64 u128, - i8 u8 i16, - i16 u16 i32, - i32 u32 i64, - i64 u64 i128 -); - -/// Trait to express (possibly lossy) casting of integers -pub trait CastInto: Copy { - fn cast(self) -> T; -} - -pub trait CastFrom: Copy { - fn cast_from(value: T) -> Self; -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - self as $into - } - } - )*}; -} - -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 9f951d51585..42c83ee55fb 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,5 +1,21 @@ //! Macros shared throughout the compiler-builtins implementation +/// Changes the visibility to `pub` if feature "public-test-deps" is set +#[cfg(not(feature = "public-test-deps"))] +macro_rules! public_test_dep { + ($(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => { + $(#[$($meta)*])* pub(crate) $ident $($tokens)* + }; +} + +/// Changes the visibility to `pub` if feature "public-test-deps" is set +#[cfg(feature = "public-test-deps")] +macro_rules! public_test_dep { + {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*} => { + $(#[$($meta)*])* pub $ident $($tokens)* + }; +} + /// The "main macro" used for defining intrinsics. /// /// The compiler-builtins library is super platform-specific with tons of crazy -- cgit 1.4.1-3-g733a5 From 6565fbb704a65394a8515d98f52eed5e4bc12b5e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 7 Aug 2024 02:18:44 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6c07fd555ef..e0a4abc638f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.116" +version = "0.1.117" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 7bc2291ac555e8e635d8aeae3d09a0ae39a96542 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 7 Aug 2024 11:29:47 +0200 Subject: Rename `only-soft-floats` feature into `force-soft-floats` --- library/compiler-builtins/libm/Cargo.toml | 2 +- .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 2 +- library/compiler-builtins/libm/src/math/mod.rs | 2 +- library/compiler-builtins/libm/src/math/sqrt.rs | 4 ++-- library/compiler-builtins/libm/src/math/sqrtf.rs | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 893a2e19d35..c2388083b61 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -24,7 +24,7 @@ unstable = [] musl-reference-tests = ['rand'] # Used to prevent using any intrinsics or arch-specific code. -only-soft-floats = [] +force-soft-floats = [] [workspace] members = [ diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index ec48ca20601..481d386a4b2 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -10,4 +10,4 @@ bench = false [features] unstable = [] checked = [] -only-soft-floats = [] +force-soft-floats = [] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 04d3bbb6203..a56532dddc1 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -76,7 +76,7 @@ macro_rules! div { macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all(feature = "unstable", not(feature = "only-soft-floats"), $($clause)*))] + #[cfg(all(feature = "unstable", not(feature = "force-soft-floats"), $($clause)*))] { if true { // thwart the dead code lint $e diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index a0003cb0566..66cb7659c2d 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -92,7 +92,7 @@ pub fn sqrt(x: f64) -> f64 { } } } - #[cfg(all(target_feature = "sse2", not(feature = "only-soft-floats")))] + #[cfg(all(target_feature = "sse2", not(feature = "force-soft-floats")))] { // Note: This path is unlikely since LLVM will usually have already // optimized sqrt calls into hardware instructions if sse2 is available, @@ -107,7 +107,7 @@ pub fn sqrt(x: f64) -> f64 { _mm_cvtsd_f64(m_sqrt) } } - #[cfg(any(not(target_feature = "sse2"), feature = "only-soft-floats"))] + #[cfg(any(not(target_feature = "sse2"), feature = "force-soft-floats"))] { use core::num::Wrapping; diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 0cef073ea3e..16cbb2f9770 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -27,7 +27,7 @@ pub fn sqrtf(x: f32) -> f32 { } } } - #[cfg(all(target_feature = "sse", not(feature = "only-soft-floats")))] + #[cfg(all(target_feature = "sse", not(feature = "force-soft-floats")))] { // Note: This path is unlikely since LLVM will usually have already // optimized sqrt calls into hardware instructions if sse is available, @@ -42,7 +42,7 @@ pub fn sqrtf(x: f32) -> f32 { _mm_cvtss_f32(m_sqrt) } } - #[cfg(any(not(target_feature = "sse"), feature = "only-soft-floats"))] + #[cfg(any(not(target_feature = "sse"), feature = "force-soft-floats"))] { const TINY: f32 = 1.0e-30; -- cgit 1.4.1-3-g733a5 From 281c14d4fc5a1a88511a521f69c0ce66e72c2589 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Aug 2024 14:00:59 +0200 Subject: Update `libm` submodule --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 279e5f6abe0..300edb32520 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 279e5f6abe0a2ca9066962d9ec894f0df1f417ac +Subproject commit 300edb32520b1673e16d2411a0e2e6273959eb46 -- cgit 1.4.1-3-g733a5 From 145143a0b7c03afbdeb02d7853bc8edd005c9213 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Aug 2024 14:09:07 +0200 Subject: Activate `force-soft-floats` feature in `build.rs` --- library/compiler-builtins/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index bbae9e2862f..93e323e6b23 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -51,8 +51,9 @@ fn main() { println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); // Activate libm's unstable features to make full use of Nightly. - println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\"))"); + println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\", \"force-soft-floats\"))"); println!("cargo:rustc-cfg=feature=\"unstable\""); + println!("cargo:rustc-cfg=feature=\"force-soft-floats\""); // Emscripten's runtime includes all the builtins if target.os == "emscripten" { -- cgit 1.4.1-3-g733a5 From 4860f2246016d87d329fdf5a498a255712ff4cae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 8 Aug 2024 12:17:09 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index e0a4abc638f..49b315779ec 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.117" +version = "0.1.118" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 5dad727bdc9aa69145cd48c08c42b8e878a3c84b Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sun, 11 Aug 2024 11:36:25 +0200 Subject: Configure `f16` and `f128` support for WebAssembly --- library/compiler-builtins/build.rs | 2 ++ library/compiler-builtins/testcrate/build.rs | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 93e323e6b23..56716b906ab 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -283,6 +283,8 @@ fn configure_f16_f128(target: &Target) { "powerpc64" if &target.os == "aix" => (true, false), // `f128` crashes "sparc" | "sparcv9" => (true, false), + // `f16` miscompiles + "wasm32" | "wasm64" => (false, true), // Most everything else works as of LLVM 19 _ => (true, true), }; diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 8c441de8a95..74d74559ef6 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -54,8 +54,9 @@ fn main() { || target.starts_with("i586-") || target.contains("windows-") // Linking says "error: function signature mismatch: __extendhfsf2" and seems to - // think the signature is either `(i32) -> f32` or `(f32) -> f32` - || target.starts_with("wasm32-") + // think the signature is either `(i32) -> f32` or `(f32) -> f32`. See + // . + || target.starts_with("wasm") { features.insert(Feature::NoSysF16); features.insert(Feature::NoSysF16F128Convert); -- cgit 1.4.1-3-g733a5 From 13cc7daf05d75b9e54f32db649132da682cc7bbe Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 12 Aug 2024 08:08:41 +0200 Subject: Fix CI for targets that conditionally disable `f16` or `f128` support --- library/compiler-builtins/build.rs | 83 +-------------------- library/compiler-builtins/configure.rs | 86 ++++++++++++++++++++++ .../testcrate/benches/float_add.rs | 18 ++++- .../testcrate/benches/float_cmp.rs | 28 ++++--- .../testcrate/benches/float_conv.rs | 1 - .../testcrate/benches/float_div.rs | 2 - .../testcrate/benches/float_extend.rs | 49 +++++++----- .../testcrate/benches/float_mul.rs | 18 ++++- .../testcrate/benches/float_sub.rs | 18 ++++- .../testcrate/benches/float_trunc.rs | 51 ++++++++----- library/compiler-builtins/testcrate/build.rs | 45 ++++++----- library/compiler-builtins/testcrate/src/bench.rs | 6 +- library/compiler-builtins/testcrate/src/lib.rs | 4 +- .../compiler-builtins/testcrate/tests/addsub.rs | 7 +- library/compiler-builtins/testcrate/tests/cmp.rs | 5 +- library/compiler-builtins/testcrate/tests/conv.rs | 14 ++-- library/compiler-builtins/testcrate/tests/mul.rs | 7 +- 17 files changed, 260 insertions(+), 182 deletions(-) create mode 100644 library/compiler-builtins/configure.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 56716b906ab..894508b54ab 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,44 +1,8 @@ use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering}; -#[allow(dead_code)] -struct Target { - triple: String, - os: String, - arch: String, - vendor: String, - env: String, - pointer_width: u8, - little_endian: bool, - features: Vec, -} - -impl Target { - fn from_env() -> Self { - let little_endian = match env::var("CARGO_CFG_TARGET_ENDIAN").unwrap().as_str() { - "little" => true, - "big" => false, - x => panic!("unknown endian {x}"), - }; +mod configure; - Self { - triple: env::var("TARGET").unwrap(), - os: env::var("CARGO_CFG_TARGET_OS").unwrap(), - arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), - vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), - env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), - pointer_width: env::var("CARGO_CFG_TARGET_POINTER_WIDTH") - .unwrap() - .parse() - .unwrap(), - little_endian, - features: env::var("CARGO_CFG_TARGET_FEATURE") - .unwrap_or_default() - .split(",") - .map(ToOwned::to_owned) - .collect(), - } - } -} +use configure::{configure_f16_f128, Target}; fn main() { println!("cargo:rerun-if-changed=build.rs"); @@ -261,49 +225,6 @@ fn configure_check_cfg() { println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); } -/// Configure whether or not `f16` and `f128` support should be enabled. -fn configure_f16_f128(target: &Target) { - // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means - // that the backend will not crash when using these types. This does not mean that the - // backend does the right thing, or that the platform doesn't have ABI bugs. - // - // We do this here rather than in `rust-lang/rust` because configuring via cargo features is - // not straightforward. - // - // Original source of this list: - // - let (f16_ok, f128_ok) = match target.arch.as_str() { - // `f16` and `f128` both crash - "arm64ec" => (false, false), - // `f16` crashes - "s390x" => (false, true), - // `f128` crashes - "mips64" | "mips64r6" => (true, false), - // `f128` crashes - "powerpc64" if &target.os == "aix" => (true, false), - // `f128` crashes - "sparc" | "sparcv9" => (true, false), - // `f16` miscompiles - "wasm32" | "wasm64" => (false, true), - // Most everything else works as of LLVM 19 - _ => (true, true), - }; - - // If the feature is set, disable these types. - let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); - - println!("cargo::rustc-check-cfg=cfg(f16_enabled)"); - println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); - - if f16_ok && !disable_both { - println!("cargo::rustc-cfg=f16_enabled"); - } - - if f128_ok && !disable_both { - println!("cargo::rustc-cfg=f128_enabled"); - } -} - #[cfg(feature = "c")] mod c { use std::collections::{BTreeMap, HashSet}; diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs new file mode 100644 index 00000000000..676c88f3a4f --- /dev/null +++ b/library/compiler-builtins/configure.rs @@ -0,0 +1,86 @@ +// Configuration that is shared between `compiler_builtins` and `testcrate`. + +use std::env; + +#[allow(dead_code)] +pub struct Target { + pub triple: String, + pub os: String, + pub arch: String, + pub vendor: String, + pub env: String, + pub pointer_width: u8, + pub little_endian: bool, + pub features: Vec, +} + +impl Target { + pub fn from_env() -> Self { + let little_endian = match env::var("CARGO_CFG_TARGET_ENDIAN").unwrap().as_str() { + "little" => true, + "big" => false, + x => panic!("unknown endian {x}"), + }; + + Self { + triple: env::var("TARGET").unwrap(), + os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), + vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), + env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), + pointer_width: env::var("CARGO_CFG_TARGET_POINTER_WIDTH") + .unwrap() + .parse() + .unwrap(), + little_endian, + features: env::var("CARGO_CFG_TARGET_FEATURE") + .unwrap_or_default() + .split(",") + .map(ToOwned::to_owned) + .collect(), + } + } +} + +/// Configure whether or not `f16` and `f128` support should be enabled. +pub fn configure_f16_f128(target: &Target) { + // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means + // that the backend will not crash when using these types. This does not mean that the + // backend does the right thing, or that the platform doesn't have ABI bugs. + // + // We do this here rather than in `rust-lang/rust` because configuring via cargo features is + // not straightforward. + // + // Original source of this list: + // + let (f16_ok, f128_ok) = match target.arch.as_str() { + // `f16` and `f128` both crash + "arm64ec" => (false, false), + // `f16` crashes + "s390x" => (false, true), + // `f128` crashes + "mips64" | "mips64r6" => (true, false), + // `f128` crashes + "powerpc64" if &target.os == "aix" => (true, false), + // `f128` crashes + "sparc" | "sparcv9" => (true, false), + // `f16` miscompiles + "wasm32" | "wasm64" => (false, true), + // Most everything else works as of LLVM 19 + _ => (true, true), + }; + + // If the feature is set, disable these types. + let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); + + println!("cargo::rustc-check-cfg=cfg(f16_enabled)"); + println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); + + if f16_ok && !disable_both { + println!("cargo::rustc-cfg=f16_enabled"); + } + + if f128_ok && !disable_both { + println!("cargo::rustc-cfg=f128_enabled"); + } +} diff --git a/library/compiler-builtins/testcrate/benches/float_add.rs b/library/compiler-builtins/testcrate/benches/float_add.rs index eef1ecc57c1..3311e7b5b29 100644 --- a/library/compiler-builtins/testcrate/benches/float_add.rs +++ b/library/compiler-builtins/testcrate/benches/float_add.rs @@ -1,7 +1,7 @@ -#![feature(f128)] +#![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::add; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; float_bench! { @@ -66,6 +66,7 @@ float_bench! { ], } +#[cfg(f128_enabled)] float_bench! { name: add_f128, sig: (a: f128, b: f128) -> f128, @@ -77,5 +78,16 @@ float_bench! { asm: [] } -criterion_group!(float_add, add_f32, add_f64, add_f128); +pub fn float_add() { + let mut criterion = Criterion::default().configure_from_args(); + + add_f32(&mut criterion); + add_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + add_f128(&mut criterion); + } +} + criterion_main!(float_add); diff --git a/library/compiler-builtins/testcrate/benches/float_cmp.rs b/library/compiler-builtins/testcrate/benches/float_cmp.rs index 641eb0ac5d4..400c09b427a 100644 --- a/library/compiler-builtins/testcrate/benches/float_cmp.rs +++ b/library/compiler-builtins/testcrate/benches/float_cmp.rs @@ -1,6 +1,6 @@ -#![feature(f128)] +#![cfg_attr(f128_enabled, feature(f128))] -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; use compiler_builtins::float::cmp; @@ -190,13 +190,19 @@ float_bench! { asm: [] } -criterion_group!( - float_cmp, - cmp_f32_gt, - cmp_f32_unord, - cmp_f64_gt, - cmp_f64_unord, - cmp_f128_gt, - cmp_f128_unord -); +pub fn float_cmp() { + let mut criterion = Criterion::default().configure_from_args(); + + cmp_f32_gt(&mut criterion); + cmp_f32_unord(&mut criterion); + cmp_f64_gt(&mut criterion); + cmp_f64_unord(&mut criterion); + + #[cfg(f128_enabled)] + { + cmp_f128_gt(&mut criterion); + cmp_f128_unord(&mut criterion); + } +} + criterion_main!(float_cmp); diff --git a/library/compiler-builtins/testcrate/benches/float_conv.rs b/library/compiler-builtins/testcrate/benches/float_conv.rs index bbd3a06851d..de2043b04f8 100644 --- a/library/compiler-builtins/testcrate/benches/float_conv.rs +++ b/library/compiler-builtins/testcrate/benches/float_conv.rs @@ -1,4 +1,3 @@ -#![feature(f128)] #![allow(improper_ctypes)] use compiler_builtins::float::conv; diff --git a/library/compiler-builtins/testcrate/benches/float_div.rs b/library/compiler-builtins/testcrate/benches/float_div.rs index e679f8ccccb..6ba439b0420 100644 --- a/library/compiler-builtins/testcrate/benches/float_div.rs +++ b/library/compiler-builtins/testcrate/benches/float_div.rs @@ -1,5 +1,3 @@ -#![feature(f128)] - use compiler_builtins::float::div; use criterion::{criterion_group, criterion_main, Criterion}; use testcrate::float_bench; diff --git a/library/compiler-builtins/testcrate/benches/float_extend.rs b/library/compiler-builtins/testcrate/benches/float_extend.rs index bf136f49a0b..a9563741a68 100644 --- a/library/compiler-builtins/testcrate/benches/float_extend.rs +++ b/library/compiler-builtins/testcrate/benches/float_extend.rs @@ -1,11 +1,12 @@ #![allow(unused_variables)] // "unused" f16 registers -#![feature(f128)] -#![feature(f16)] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] use compiler_builtins::float::extend; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; +#[cfg(f16_enabled)] float_bench! { name: extend_f16_f32, sig: (a: f16) -> f32, @@ -28,6 +29,7 @@ float_bench! { ], } +#[cfg(all(f16_enabled, f128_enabled))] float_bench! { name: extend_f16_f128, sig: (a: f16) -> f128, @@ -60,6 +62,7 @@ float_bench! { ], } +#[cfg(f128_enabled)] float_bench! { name: extend_f32_f128, sig: (a: f32) -> f128, @@ -71,6 +74,7 @@ float_bench! { asm: [], } +#[cfg(f128_enabled)] float_bench! { name: extend_f64_f128, sig: (a: f64) -> f128, @@ -82,23 +86,28 @@ float_bench! { asm: [], } -#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] -criterion_group!( - float_extend, - extend_f16_f32, - extend_f16_f128, - extend_f32_f64, - extend_f32_f128, - extend_f64_f128, -); +pub fn float_extend() { + let mut criterion = Criterion::default().configure_from_args(); -// FIXME(#655): `f16` tests disabled until we can bootstrap symbols -#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] -criterion_group!( - float_extend, - extend_f32_f64, - extend_f32_f128, - extend_f64_f128, -); + // FIXME(#655): `f16` tests disabled until we can bootstrap symbols + #[cfg(f16_enabled)] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + { + extend_f16_f32(&mut criterion); + + #[cfg(f128_enabled)] + { + extend_f16_f128(&mut criterion); + } + } + + extend_f32_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + extend_f32_f128(&mut criterion); + extend_f64_f128(&mut criterion); + } +} criterion_main!(float_extend); diff --git a/library/compiler-builtins/testcrate/benches/float_mul.rs b/library/compiler-builtins/testcrate/benches/float_mul.rs index efa32b28563..6e30b7866c7 100644 --- a/library/compiler-builtins/testcrate/benches/float_mul.rs +++ b/library/compiler-builtins/testcrate/benches/float_mul.rs @@ -1,7 +1,7 @@ -#![feature(f128)] +#![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::mul; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; float_bench! { @@ -66,6 +66,7 @@ float_bench! { ], } +#[cfg(f128_enabled)] float_bench! { name: mul_f128, sig: (a: f128, b: f128) -> f128, @@ -77,5 +78,16 @@ float_bench! { asm: [] } -criterion_group!(float_mul, mul_f32, mul_f64, mul_f128); +pub fn float_mul() { + let mut criterion = Criterion::default().configure_from_args(); + + mul_f32(&mut criterion); + mul_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + mul_f128(&mut criterion); + } +} + criterion_main!(float_mul); diff --git a/library/compiler-builtins/testcrate/benches/float_sub.rs b/library/compiler-builtins/testcrate/benches/float_sub.rs index 6d87604aac7..cdb678eef05 100644 --- a/library/compiler-builtins/testcrate/benches/float_sub.rs +++ b/library/compiler-builtins/testcrate/benches/float_sub.rs @@ -1,7 +1,7 @@ -#![feature(f128)] +#![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::sub; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; float_bench! { @@ -66,6 +66,7 @@ float_bench! { ], } +#[cfg(f128_enabled)] float_bench! { name: sub_f128, sig: (a: f128, b: f128) -> f128, @@ -77,5 +78,16 @@ float_bench! { asm: [] } -criterion_group!(float_sub, sub_f32, sub_f64, sub_f128); +pub fn float_sub() { + let mut criterion = Criterion::default().configure_from_args(); + + sub_f32(&mut criterion); + sub_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + sub_f128(&mut criterion); + } +} + criterion_main!(float_sub); diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs index 74b43dfc833..8d874e4b2e0 100644 --- a/library/compiler-builtins/testcrate/benches/float_trunc.rs +++ b/library/compiler-builtins/testcrate/benches/float_trunc.rs @@ -1,10 +1,11 @@ -#![feature(f128)] -#![feature(f16)] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] use compiler_builtins::float::trunc; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; +#[cfg(f16_enabled)] float_bench! { name: trunc_f32_f16, sig: (a: f32) -> f16, @@ -27,6 +28,7 @@ float_bench! { ], } +#[cfg(f16_enabled)] float_bench! { name: trunc_f64_f16, sig: (a: f64) -> f16, @@ -82,6 +84,7 @@ float_bench! { ], } +#[cfg(all(f16_enabled, f128_enabled))] float_bench! { name: trunc_f128_f16, sig: (a: f128) -> f16, @@ -93,6 +96,7 @@ float_bench! { asm: [], } +#[cfg(f128_enabled)] float_bench! { name: trunc_f128_f32, sig: (a: f128) -> f32, @@ -104,6 +108,7 @@ float_bench! { asm: [], } +#[cfg(f128_enabled)] float_bench! { name: trunc_f128_f64, sig: (a: f128) -> f64, @@ -115,19 +120,31 @@ float_bench! { asm: [], } -#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] -criterion_group!( - float_trunc, - trunc_f32_f16, - trunc_f64_f16, - trunc_f64_f32, - trunc_f128_f16, - trunc_f128_f32, - trunc_f128_f64, -); - -// FIXME(#655): `f16` tests disabled until we can bootstrap symbols -#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] -criterion_group!(float_trunc, trunc_f64_f32, trunc_f128_f32, trunc_f128_f64,); +pub fn float_trunc() { + let mut criterion = Criterion::default().configure_from_args(); + + // FIXME(#655): `f16` tests disabled until we can bootstrap symbols + #[cfg(f16_enabled)] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + { + trunc_f32_f16(&mut criterion); + trunc_f64_f16(&mut criterion); + } + + trunc_f64_f32(&mut criterion); + + #[cfg(f128_enabled)] + { + // FIXME(#655): `f16` tests disabled until we can bootstrap symbols + #[cfg(f16_enabled)] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + { + trunc_f128_f16(&mut criterion); + } + + trunc_f128_f32(&mut criterion); + trunc_f128_f64(&mut criterion); + } +} criterion_main!(float_trunc); diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 74d74559ef6..fde4e5b56f3 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -1,4 +1,4 @@ -use std::{collections::HashSet, env}; +use std::collections::HashSet; /// Features to enable #[derive(Debug, PartialEq, Eq, Hash)] @@ -9,35 +9,39 @@ enum Feature { NoSysF16F128Convert, } +mod builtins_configure { + include!("../configure.rs"); +} + fn main() { - let target = env::var("TARGET").unwrap(); + let target = builtins_configure::Target::from_env(); let mut features = HashSet::new(); // These platforms do not have f128 symbols available in their system libraries, so // skip related tests. - if target.starts_with("arm-") - || target.contains("apple-darwin") - || target.contains("windows-msvc") + if target.arch == "arm" + || target.vendor == "apple" + || target.env == "msvc" // GCC and LLVM disagree on the ABI of `f16` and `f128` with MinGW. See // . - || target.contains("windows-gnu") + || (target.os == "windows" && target.env == "gnu") // FIXME(llvm): There is an ABI incompatibility between GCC and Clang on 32-bit x86. // See . - || target.starts_with("i686") + || target.arch == "i686" // 32-bit PowerPC and 64-bit LE gets code generated that Qemu cannot handle. See // . - || target.starts_with("powerpc-") - || target.starts_with("powerpc64le-") + || target.arch == "powerpc" + || target.arch == "powerpc64le" // FIXME: We get different results from the builtin functions. See // . - || target.starts_with("powerpc64-") + || target.arch == "powerpc64" { features.insert(Feature::NoSysF128); features.insert(Feature::NoSysF128IntConvert); features.insert(Feature::NoSysF16F128Convert); } - if target.starts_with("i586") || target.starts_with("i686") { + if target.arch == "i586" || target.arch == "i686" { // 32-bit x86 does not have `__fixunstfti`/`__fixtfti` but does have everything else features.insert(Feature::NoSysF128IntConvert); // FIXME: 32-bit x86 has a bug in `f128 -> f16` system libraries @@ -46,17 +50,18 @@ fn main() { // These platforms do not have f16 symbols available in their system libraries, so // skip related tests. Most of these are missing `f16 <-> f32` conversion routines. - if (target.starts_with("aarch64-") && target.contains("linux")) - || target.starts_with("arm") - || target.starts_with("powerpc-") - || target.starts_with("powerpc64-") - || target.starts_with("powerpc64le-") - || target.starts_with("i586-") - || target.contains("windows-") + if (target.arch == "aarch64" && target.os == "linux") + || target.arch.starts_with("arm") + || target.arch == "powerpc" + || target.arch == "powerpc64" + || target.arch == "powerpc64le" + || target.arch == "i586" + || target.os == "windows" // Linking says "error: function signature mismatch: __extendhfsf2" and seems to // think the signature is either `(i32) -> f32` or `(f32) -> f32`. See // . - || target.starts_with("wasm") + || target.arch == "wasm32" + || target.arch == "wasm64" { features.insert(Feature::NoSysF16); features.insert(Feature::NoSysF16F128Convert); @@ -78,4 +83,6 @@ fn main() { println!("cargo:warning={warning}"); println!("cargo:rustc-cfg=feature=\"{name}\""); } + + builtins_configure::configure_f16_f128(&target); } diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs index 5ab9bac8715..1d571a6cf3b 100644 --- a/library/compiler-builtins/testcrate/src/bench.rs +++ b/library/compiler-builtins/testcrate/src/bench.rs @@ -350,9 +350,11 @@ macro_rules! impl_testio { } } -#[cfg(not(feature = "no-f16-f128"))] -impl_testio!(float f16, f128); +#[cfg(f16_enabled)] +impl_testio!(float f16); impl_testio!(float f32, f64); +#[cfg(f128_enabled)] +impl_testio!(float f128); impl_testio!(int i16, i32, i64, i128); impl_testio!(int u16, u32, u64, u128); impl_testio!((float, int)(f32, i32)); diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 5458c9ab6d0..cc9e73938fb 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -13,8 +13,8 @@ //! Some floating point tests are disabled for specific architectures, because they do not have //! correct rounding. #![no_std] -#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))] -#![cfg_attr(not(feature = "no-f16-f128"), feature(f16))] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] #![feature(isqrt)] pub mod bench; diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs index f21f61ff679..1ba2df74191 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -1,6 +1,5 @@ #![allow(unused_macros)] -#![feature(f128)] -#![feature(f16)] +#![cfg_attr(f128_enabled, feature(f128))] use testcrate::*; @@ -120,7 +119,7 @@ mod float_addsub { } } -#[cfg(not(feature = "no-f16-f128"))] +#[cfg(f128_enabled)] #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] mod float_addsub_f128 { @@ -131,7 +130,7 @@ mod float_addsub_f128 { } } -#[cfg(not(feature = "no-f16-f128"))] +#[cfg(f128_enabled)] #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] mod float_addsub_f128_ppc { use super::*; diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index e8a0eb165c3..7e973e7e5ed 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -1,7 +1,6 @@ #![allow(unused_macros)] #![allow(unreachable_code)] -#![feature(f128)] -#![feature(f16)] +#![cfg_attr(f128_enabled, feature(f128))] #[cfg(not(target_arch = "powerpc64"))] use testcrate::*; @@ -94,7 +93,7 @@ mod float_comparisons { } #[test] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] fn cmp_f128() { #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] use compiler_builtins::float::cmp::{ diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index e394183cf57..ce1f64e67d1 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -1,5 +1,5 @@ -#![cfg_attr(not(feature = "no-f16-f128"), feature(f16))] -#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] // makes configuration easier #![allow(unused_macros)] #![allow(unused_imports)] @@ -176,7 +176,7 @@ mod f_to_i { } #[test] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] fn f128_to_int() { #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] use compiler_builtins::float::conv::{ @@ -264,7 +264,7 @@ mod extend { f32 => f64, Single => Double, __extendsfdf2vfp, all(); } - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(all(f16_enabled, f128_enabled))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] f_to_f! { extend, @@ -275,7 +275,7 @@ mod extend { f64 => f128, Double => Quad, __extenddftf2, not(feature = "no-sys-f128"); } - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] f_to_f! { extend, @@ -299,7 +299,7 @@ mod trunc { f64 => f32, Double => Single, __truncdfsf2vfp, all(); } - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(all(f16_enabled, f128_enabled))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] f_to_f! { trunc, @@ -310,7 +310,7 @@ mod trunc { f128 => f64, Quad => Double, __trunctfdf2, not(feature = "no-sys-f128"); } - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] f_to_f! { trunc, diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 90144bb0635..867622fdf07 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -1,6 +1,5 @@ #![allow(unused_macros)] -#![feature(f128)] -#![feature(f16)] +#![cfg_attr(f128_enabled, feature(f128))] use testcrate::*; @@ -131,7 +130,7 @@ mod float_mul { } } -#[cfg(not(feature = "no-f16-f128"))] +#[cfg(f128_enabled)] #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] mod float_mul_f128 { @@ -145,7 +144,7 @@ mod float_mul_f128 { } } -#[cfg(not(feature = "no-f16-f128"))] +#[cfg(f128_enabled)] #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] mod float_mul_f128_ppc { use super::*; -- cgit 1.4.1-3-g733a5 From 3869b3962c830aafa3f1ca39e46c685023dc7619 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:42:17 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 49b315779ec..44cc3994bd3 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.118" +version = "0.1.119" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 18cbc52ee63946fb21b8c29fa64b6c17ecd61c30 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 12 Aug 2024 19:45:28 +0200 Subject: Add `configure.rs` to the `include` list --- library/compiler-builtins/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 44cc3994bd3..8f2d8a5698a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -15,6 +15,7 @@ if necessary! include = [ '/Cargo.toml', '/build.rs', + '/configure.rs', '/src/*', '/examples/*', '/LICENSE.txt', -- cgit 1.4.1-3-g733a5 From db9debf096e31322eb7a03a8ea67229ea69eced1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 07:04:07 -0500 Subject: Apply fixes to `build.rs` files Make the following changes: - Add `rerun-if-changed` to the new `configure.rs`, it seems this was causing incorrect caching. - Change from matching `i686` to `x86`. The target triple starts with `i686` so that is what we were checking before, but the architecture is `x86`. This change should have been made when we added `struct Target`, update it now instead. --- library/compiler-builtins/build.rs | 6 ++++-- library/compiler-builtins/configure.rs | 6 ++++++ library/compiler-builtins/testcrate/build.rs | 12 +++++++----- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 894508b54ab..5ccff76e7c5 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -5,7 +5,9 @@ mod configure; use configure::{configure_f16_f128, Target}; fn main() { - println!("cargo:rerun-if-changed=build.rs"); + println!("cargo::rerun-if-changed=build.rs"); + println!("cargo::rerun-if-changed=configure.rs"); + let target = Target::from_env(); let cwd = env::current_dir().unwrap(); @@ -46,7 +48,7 @@ fn main() { // These targets have hardware unaligned access support. println!("cargo::rustc-check-cfg=cfg(feature, values(\"mem-unaligned\"))"); if target.arch.contains("x86_64") - || target.arch.contains("i686") + || target.arch.contains("x86") || target.arch.contains("aarch64") || target.arch.contains("bpf") { diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index 676c88f3a4f..e23c0e83935 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -2,6 +2,7 @@ use std::env; +#[derive(Debug)] #[allow(dead_code)] pub struct Target { pub triple: String, @@ -40,6 +41,11 @@ impl Target { .collect(), } } + + #[allow(dead_code)] + pub fn has_feature(&self, feature: &str) -> bool { + self.features.iter().any(|f| f == feature) + } } /// Configure whether or not `f16` and `f128` support should be enabled. diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index fde4e5b56f3..6205c7ac6fe 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -14,6 +14,8 @@ mod builtins_configure { } fn main() { + println!("cargo::rerun-if-changed=../configure.rs"); + let target = builtins_configure::Target::from_env(); let mut features = HashSet::new(); @@ -27,7 +29,7 @@ fn main() { || (target.os == "windows" && target.env == "gnu") // FIXME(llvm): There is an ABI incompatibility between GCC and Clang on 32-bit x86. // See . - || target.arch == "i686" + || target.arch == "x86" // 32-bit PowerPC and 64-bit LE gets code generated that Qemu cannot handle. See // . || target.arch == "powerpc" @@ -41,7 +43,7 @@ fn main() { features.insert(Feature::NoSysF16F128Convert); } - if target.arch == "i586" || target.arch == "i686" { + if target.arch == "x86" { // 32-bit x86 does not have `__fixunstfti`/`__fixtfti` but does have everything else features.insert(Feature::NoSysF128IntConvert); // FIXME: 32-bit x86 has a bug in `f128 -> f16` system libraries @@ -55,7 +57,7 @@ fn main() { || target.arch == "powerpc" || target.arch == "powerpc64" || target.arch == "powerpc64le" - || target.arch == "i586" + || (target.arch == "x86" && !target.has_feature("sse")) || target.os == "windows" // Linking says "error: function signature mismatch: __extendhfsf2" and seems to // think the signature is either `(i32) -> f32` or `(f32) -> f32`. See @@ -72,11 +74,11 @@ fn main() { Feature::NoSysF128 => ("no-sys-f128", "using apfloat fallback for f128"), Feature::NoSysF128IntConvert => ( "no-sys-f128-int-convert", - "using apfloat fallback for f128 to int conversions", + "using apfloat fallback for f128 <-> int conversions", ), Feature::NoSysF16F128Convert => ( "no-sys-f16-f128-convert", - "skipping using apfloat fallback for f16 <-> f128 conversions", + "using apfloat fallback for f16 <-> f128 conversions", ), Feature::NoSysF16 => ("no-sys-f16", "using apfloat fallback for f16"), }; -- cgit 1.4.1-3-g733a5 From b71531e64eb1c3085d1570177c160ad35f86eae7 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:59:06 +0800 Subject: Fix weak linkage on windows and apple platforms There were some issues regarding windows and apple platform, we were exporting symbols that are already provided by the compiler but weren't marked as `weak` which resulted in conflicted symbols in the linking process. Initially, we didn't add `weak` because we thought it is not supported on windows and apple platforms, but it looks like its only not supported on windows-gnu platforms Signed-off-by: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> --- library/compiler-builtins/src/macros.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 42c83ee55fb..18535d633f7 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -256,7 +256,7 @@ macro_rules! intrinsics { #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64", not(feature = "mangled-names")))] mod $name { #[no_mangle] - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] extern $abi fn $name( $($argname: $ty),* ) -> $crate::macros::win64_128bit_abi_hack::U64x2 { @@ -298,7 +298,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] mod $name { #[no_mangle] - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] $(#[$($attr)*])* extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) @@ -308,7 +308,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] mod $alias { #[no_mangle] - #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] $(#[$($attr)*])* extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) @@ -375,7 +375,7 @@ macro_rules! intrinsics { mod $name { $(#[$($attr)*])* #[no_mangle] - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -400,7 +400,7 @@ macro_rules! intrinsics { #[naked] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -467,7 +467,7 @@ macro_rules! intrinsics { mod $name { $(#[$($attr)*])* #[no_mangle] - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] $(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } -- cgit 1.4.1-3-g733a5 From 7033f32bacbc07e34eae5048d6b1133590d2a34e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 06:03:55 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 8f2d8a5698a..37051218172 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.119" +version = "0.1.120" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 40d2a60c224239904cf8f366f8835b5b0050ae9b Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 22 Aug 2024 00:43:02 -0700 Subject: Use array simd in `U64x2` --- library/compiler-builtins/src/macros.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 18535d633f7..f7c6d0bfeee 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -482,20 +482,20 @@ macro_rules! intrinsics { #[cfg(all(any(windows, target_os = "uefi"), target_pointer_width = "64"))] pub mod win64_128bit_abi_hack { #[repr(simd)] - pub struct U64x2(u64, u64); + pub struct U64x2([u64; 2]); impl From for U64x2 { fn from(i: i128) -> U64x2 { use crate::int::DInt; let j = i as u128; - U64x2(j.lo(), j.hi()) + U64x2([j.lo(), j.hi()]) } } impl From for U64x2 { fn from(i: u128) -> U64x2 { use crate::int::DInt; - U64x2(i.lo(), i.hi()) + U64x2([i.lo(), i.hi()]) } } } -- cgit 1.4.1-3-g733a5 From 25be87d8a80c4df9209dc02434afb2fed05defe1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 08:01:13 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 37051218172..3f104b037a9 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.120" +version = "0.1.121" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From a1ba7445d4077d3a421ff2ff721b3e8ec3171e20 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 22 Aug 2024 03:43:13 -0500 Subject: Add a `success` job to CI This will allow us to enable auto merge once CI completes. --- .../compiler-builtins/libm/.github/workflows/main.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 2f2e46822b9..322043d85af 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -71,3 +71,20 @@ jobs: - name: Install Rust run: rustup update nightly && rustup default nightly - run: cargo bench --all + + success: + needs: + - docker + - rustfmt + - wasm + - cb + - benchmarks + runs-on: ubuntu-latest + # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency + # failed" as success. So we have to do some contortions to ensure the job fails if any of its + # dependencies fails. + if: always() # make sure this is never "skipped" + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: check if any dependency failed + run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' -- cgit 1.4.1-3-g733a5 From d6588dff8f9075d8cd2b20eba02aaf934f6aa88a Mon Sep 17 00:00:00 2001 From: beetrees Date: Sat, 24 Aug 2024 11:24:45 +0100 Subject: Use `macos-latest` in CI for `aarch64-apple-darwin` --- library/compiler-builtins/.github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 38064543f3e..affb3a82445 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -16,7 +16,7 @@ jobs: matrix: include: - target: aarch64-apple-darwin - os: macos-14 + os: macos-latest rust: nightly - target: aarch64-unknown-linux-gnu os: ubuntu-latest -- cgit 1.4.1-3-g733a5 From 09a1f57604462039a1bd09b537f6311985ab3a66 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sat, 24 Aug 2024 11:52:41 +0100 Subject: Use `macos-13` in CI for `x86_64-apple-darwin` --- library/compiler-builtins/.github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index affb3a82445..fddb5973eb5 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -80,7 +80,7 @@ jobs: os: ubuntu-latest rust: nightly - target: x86_64-apple-darwin - os: macos-latest + os: macos-13 rust: nightly - target: i686-pc-windows-msvc os: windows-latest -- cgit 1.4.1-3-g733a5 From a17a15b08ad237431eeead760d2aebf086d764ba Mon Sep 17 00:00:00 2001 From: beetrees Date: Fri, 23 Aug 2024 12:39:31 +0100 Subject: Fix ABI for `f16` builtins on Intel Apple targets --- library/compiler-builtins/src/float/extend.rs | 2 + library/compiler-builtins/src/float/trunc.rs | 3 + library/compiler-builtins/src/macros.rs | 100 ++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 2f392255fea..9fabcde25a5 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -86,6 +86,7 @@ intrinsics! { intrinsics! { #[avr_skip] #[aapcs_on_arm] + #[apple_f16_arg_abi] #[arm_aeabi_alias = __aeabi_h2f] #[cfg(f16_enabled)] pub extern "C" fn __extendhfsf2(a: f16) -> f32 { @@ -94,6 +95,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] + #[apple_f16_arg_abi] #[cfg(f16_enabled)] pub extern "C" fn __gnu_h2f_ieee(a: f16) -> f32 { extend(a) diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index c54ff7805f5..5c17cd96acf 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -134,6 +134,7 @@ intrinsics! { intrinsics! { #[avr_skip] #[aapcs_on_arm] + #[apple_f16_ret_abi] #[arm_aeabi_alias = __aeabi_f2h] #[cfg(f16_enabled)] pub extern "C" fn __truncsfhf2(a: f32) -> f16 { @@ -142,6 +143,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] + #[apple_f16_ret_abi] #[cfg(f16_enabled)] pub extern "C" fn __gnu_f2h_ieee(a: f32) -> f16 { trunc(a) @@ -149,6 +151,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] + #[apple_f16_ret_abi] #[arm_aeabi_alias = __aeabi_d2h] #[cfg(f16_enabled)] pub extern "C" fn __truncdfhf2(a: f64) -> f16 { diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index f7c6d0bfeee..f51e49e9876 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -276,6 +276,106 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // `arm_aeabi_alias` would conflict with `f16_apple_{arg,ret}_abi` not handled here. Avoid macro ambiguity by combining in a + // single `#[]`. + ( + #[apple_f16_arg_abi] + #[arm_aeabi_alias = $alias:ident] + $($t:tt)* + ) => { + intrinsics! { + #[apple_f16_arg_abi, arm_aeabi_alias = $alias] + $($t)* + } + }; + ( + #[apple_f16_ret_abi] + #[arm_aeabi_alias = $alias:ident] + $($t:tt)* + ) => { + intrinsics! { + #[apple_f16_ret_abi, arm_aeabi_alias = $alias] + $($t)* + } + }; + + // On x86 (32-bit and 64-bit) Apple platforms, `f16` is passed and returned like a `u16` unless + // the builtin involves `f128`. + ( + // `arm_aeabi_alias` would conflict if not handled here. Avoid macro ambiguity by combining + // in a single `#[]`. + #[apple_f16_arg_abi $(, arm_aeabi_alias = $alias:ident)?] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64")))] + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + + #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] + mod $name { + #[no_mangle] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + $(#[$($attr)*])* + extern $abi fn $name( $($argname: u16),* ) $(-> $ret)? { + super::$name($(f16::from_bits($argname)),*) + } + } + + #[cfg(not(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"))))] + intrinsics! { + $(#[arm_aeabi_alias = $alias])? + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + ( + #[apple_f16_ret_abi $(, arm_aeabi_alias = $alias:ident)?] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64")))] + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + + #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] + mod $name { + #[no_mangle] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + $(#[$($attr)*])* + extern $abi fn $name( $($argname: $ty),* ) -> u16 { + super::$name($($argname),*).to_bits() + } + } + + #[cfg(not(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"))))] + intrinsics! { + $(#[arm_aeabi_alias = $alias])? + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + // A bunch of intrinsics on ARM are aliased in the standard compiler-rt // build under `__aeabi_*` aliases, and LLVM will call these instead of the // original function. The aliasing here is used to generate these symbols in -- cgit 1.4.1-3-g733a5 From 18109c2d2d78dc77840e6708ebaf20b51cf2aef2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 25 Aug 2024 04:08:06 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 3f104b037a9..b9de326d994 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.121" +version = "0.1.122" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 1652ba219c7b28be8e440ad1c129c659625aff9b Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:55:05 +0800 Subject: Don't include `math` for `unix` and `wasi` targets This fixes such as (https://github.com/rust-lang/rust/issues/128386) where, our implementation is being used on systems where there is already `math` library and its more performant and accurate. So with this change, linux will go back to the previous behavior and not include these functions, windows and apple were generally not affected. Looking at the targets we have builtin now in rust, everything else is probably good to have the math symbols. > A note on the above, the `hermit` os uses `libm` directly for itself, > but I think its Ok to keep providing math in `compiler_builtin` for it, > its technically the same implementation either from `compiler_builtin` > or `hermit-builtins`. Signed-off-by: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> --- library/compiler-builtins/src/lib.rs | 13 ++++++++++--- library/compiler-builtins/src/math.rs | 3 ++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0d44fdf9654..b85f789fdd0 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -47,9 +47,16 @@ mod macros; pub mod float; pub mod int; -// Disabled on x86 without sse2 due to ABI issues -// -#[cfg(not(all(target_arch = "x86", not(target_feature = "sse2"))))] +// Disable for any of the following: +// - x86 without sse2 due to ABI issues +// - +// - All unix targets (linux, macos, freebsd, android, etc) +// - wasm with known target_os +#[cfg(not(any( + all(target_arch = "x86", not(target_feature = "sse2")), + unix, + all(target_family = "wasm", not(target_os = "unknown")) +)))] pub mod math; pub mod mem; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 7d4d1787678..477dfe36516 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -17,7 +17,7 @@ macro_rules! no_mangle { } } -#[cfg(all(not(windows), not(target_vendor = "apple")))] +#[cfg(not(windows))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; @@ -92,6 +92,7 @@ no_mangle! { fn fmodf(x: f32, y: f32) -> f32; } +// allow for windows (and other targets) intrinsics! { pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { let r = self::libm::lgamma_r(x); -- cgit 1.4.1-3-g733a5 From 5b227e47723b8c71ca30dd7b3023bee1fe4df11e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 16:15:09 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index b9de326d994..525095b17f7 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.122" +version = "0.1.123" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From a3a5a00b9a13c0f9949449313a591390a0546db6 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sat, 31 Aug 2024 12:54:21 -0500 Subject: [hexagon] Remove aliases w/o leading __ These hexagon builtins incorrectly created aliases in the global namespace which can (and in at least one case, did) conflict with symbols defined by other programs. This should address the issue reported as https://github.com/rust-lang/rust/issues/129823: Compiling compiler_builtins v0.1.123 Compiling core v0.0.0 (/home/ben/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core) Compiling rustc-std-workspace-core v1.99.0 (/home/ben/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/rustc-std-workspace-core) Compiling byteorder v1.5.0 Compiling zerocopy v0.7.34 error: symbol 'fma' is already defined error: could not compile `compiler_builtins` (lib) due to 1 previous error Also: some of the symbols defined were not just aliases, so those are now qualified with `__hexagon_`. The compiler does not yet emit calls to these particular ones, but if/when it does, it can use the new names. --- library/compiler-builtins/src/hexagon/dffma.s | 2 -- library/compiler-builtins/src/hexagon/dfminmax.s | 6 ----- .../src/hexagon/fastmath2_dlib_asm.s | 30 +++++++++++----------- .../src/hexagon/fastmath2_ldlib_asm.s | 18 ++++++------- 4 files changed, 24 insertions(+), 32 deletions(-) diff --git a/library/compiler-builtins/src/hexagon/dffma.s b/library/compiler-builtins/src/hexagon/dffma.s index 043a1d294a3..97d05eb1839 100644 --- a/library/compiler-builtins/src/hexagon/dffma.s +++ b/library/compiler-builtins/src/hexagon/dffma.s @@ -3,8 +3,6 @@ .type __hexagon_fmadf4,@function .global __hexagon_fmadf5 .type __hexagon_fmadf5,@function - .global fma - .type fma,@function .global __qdsp_fmadf5 ; .set __qdsp_fmadf5, __hexagon_fmadf5 .p2align 5 __hexagon_fmadf4: diff --git a/library/compiler-builtins/src/hexagon/dfminmax.s b/library/compiler-builtins/src/hexagon/dfminmax.s index 3337a3223ec..953e773bf19 100644 --- a/library/compiler-builtins/src/hexagon/dfminmax.s +++ b/library/compiler-builtins/src/hexagon/dfminmax.s @@ -1,17 +1,12 @@ .text .global __hexagon_mindf3 .global __hexagon_maxdf3 - .global fmin - .type fmin,@function - .global fmax - .type fmax,@function .type __hexagon_mindf3,@function .type __hexagon_maxdf3,@function .global __qdsp_mindf3 ; .set __qdsp_mindf3, __hexagon_mindf3 .global __qdsp_maxdf3 ; .set __qdsp_maxdf3, __hexagon_maxdf3 .p2align 5 __hexagon_mindf3: -fmin: { p0 = dfclass(r1:0,#0x10) p1 = dfcmp.gt(r1:0,r3:2) @@ -31,7 +26,6 @@ fmin: .size __hexagon_mindf3,.-__hexagon_mindf3 .falign __hexagon_maxdf3: -fmax: { p0 = dfclass(r1:0,#0x10) p1 = dfcmp.gt(r3:2,r1:0) diff --git a/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s b/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s index 15c387846fa..e77b7db0332 100644 --- a/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s +++ b/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s @@ -1,7 +1,7 @@ .text - .global fast2_dadd_asm - .type fast2_dadd_asm, @function -fast2_dadd_asm: + .global __hexagon_fast2_dadd_asm + .type __hexagon_fast2_dadd_asm, @function +__hexagon_fast2_dadd_asm: .falign { R7:6 = VABSDIFFH(R1:0, R3:2) @@ -49,9 +49,9 @@ fast2_dadd_asm: jumpr r31 } .text - .global fast2_dsub_asm - .type fast2_dsub_asm, @function -fast2_dsub_asm: + .global __hexagon_fast2_dsub_asm + .type __hexagon_fast2_dsub_asm, @function +__hexagon_fast2_dsub_asm: .falign { R7:6 = VABSDIFFH(R1:0, R3:2) @@ -99,9 +99,9 @@ fast2_dsub_asm: jumpr r31 } .text - .global fast2_dmpy_asm - .type fast2_dmpy_asm, @function -fast2_dmpy_asm: + .global __hexagon_fast2_dmpy_asm + .type __hexagon_fast2_dmpy_asm, @function +__hexagon_fast2_dmpy_asm: .falign { R13= lsr(R2, #16) @@ -167,9 +167,9 @@ fast2_dmpy_asm: jumpr r31 } .text - .global fast2_qd2f_asm - .type fast2_qd2f_asm, @function -fast2_qd2f_asm: + .global __hexagon_fast2_qd2f_asm + .type __hexagon_fast2_qd2f_asm, @function +__hexagon_fast2_qd2f_asm: .falign { R3 = abs(R1):sat @@ -225,9 +225,9 @@ fast2_qd2f_asm: jumpr r31 } .text - .global fast2_f2qd_asm - .type fast2_f2qd_asm, @function -fast2_f2qd_asm: + .global __hexagon_fast2_f2qd_asm + .type __hexagon_fast2_f2qd_asm, @function +__hexagon_fast2_f2qd_asm: diff --git a/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s b/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s index b72b7550afc..3251057d78c 100644 --- a/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s +++ b/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s @@ -1,7 +1,7 @@ .text - .global fast2_ldadd_asm - .type fast2_ldadd_asm, @function -fast2_ldadd_asm: + .global __hexagon_fast2ldadd_asm + .type __hexagon_fast2ldadd_asm, @function +__hexagon_fast2ldadd_asm: .falign { R4 = memw(r29+#8) @@ -54,9 +54,9 @@ fast2_ldadd_asm: jumpr r31 } .text - .global fast2_ldsub_asm - .type fast2_ldsub_asm, @function -fast2_ldsub_asm: + .global __hexagon_fast2ldsub_asm + .type __hexagon_fast2ldsub_asm, @function +__hexagon_fast2ldsub_asm: .falign { R4 = memw(r29+#8) @@ -109,9 +109,9 @@ fast2_ldsub_asm: jumpr r31 } .text - .global fast2_ldmpy_asm - .type fast2_ldmpy_asm, @function -fast2_ldmpy_asm: + .global __hexagon_fast2ldmpy_asm + .type __hexagon_fast2ldmpy_asm, @function +__hexagon_fast2ldmpy_asm: .falign { R15:14 = memd(r29+#0) -- cgit 1.4.1-3-g733a5 From 39920c73dd5fbfb1d8541daee35330133e114527 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 03:20:30 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 525095b17f7..f5a04747a72 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.123" +version = "0.1.124" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 69406c118a8d1f863bda99830d813489d9a7e063 Mon Sep 17 00:00:00 2001 From: Sbstn Bcht Date: Wed, 4 Sep 2024 04:55:44 +0200 Subject: Remove unsupported *vfp functions (#678) Remove all *vfp functions and related tests since LLVM no longer emits them. Link: https://github.com/rust-lang/compiler-builtins/pull/626 [ Reword commit message - Trevor ] --- library/compiler-builtins/README.md | 71 +++++++++++----------- library/compiler-builtins/src/float/add.rs | 10 --- library/compiler-builtins/src/float/cmp.rs | 51 ---------------- library/compiler-builtins/src/float/div.rs | 10 --- library/compiler-builtins/src/float/extend.rs | 5 -- library/compiler-builtins/src/float/mul.rs | 10 --- library/compiler-builtins/src/float/sub.rs | 10 --- library/compiler-builtins/src/float/trunc.rs | 5 -- .../compiler-builtins/testcrate/tests/addsub.rs | 10 --- library/compiler-builtins/testcrate/tests/cmp.rs | 14 ----- library/compiler-builtins/testcrate/tests/conv.rs | 12 ---- .../compiler-builtins/testcrate/tests/div_rem.rs | 10 --- library/compiler-builtins/testcrate/tests/mul.rs | 10 --- 13 files changed, 37 insertions(+), 191 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 51bef5e2e7c..46983a281eb 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -103,9 +103,7 @@ rely on CI. - [x] aarch64/chkstk.S - [x] adddf3.c - [x] addsf3.c -- [x] arm/adddf3vfp.S - [x] arm/addsf3.S -- [x] arm/addsf3vfp.S - [x] arm/aeabi_dcmp.S - [x] arm/aeabi_fcmp.S - [x] arm/aeabi_idivmod.S @@ -116,45 +114,13 @@ rely on CI. - [x] arm/aeabi_uidivmod.S - [x] arm/aeabi_uldivmod.S - [ ] arm/chkstk.S -- [x] arm/divdf3vfp.S - [ ] arm/divmodsi4.S (generic version is done) -- [x] arm/divsf3vfp.S - [ ] arm/divsi3.S (generic version is done) -- [x] arm/eqdf2vfp.S -- [x] arm/eqsf2vfp.S -- [x] arm/extendsfdf2vfp.S -- [ ] arm/fixdfsivfp.S -- [ ] arm/fixsfsivfp.S -- [ ] arm/fixunsdfsivfp.S -- [ ] arm/fixunssfsivfp.S -- [ ] arm/floatsidfvfp.S -- [ ] arm/floatsisfvfp.S -- [ ] arm/floatunssidfvfp.S -- [ ] arm/floatunssisfvfp.S -- [x] arm/gedf2vfp.S -- [x] arm/gesf2vfp.S -- [x] arm/gtdf2vfp.S -- [x] arm/gtsf2vfp.S -- [x] arm/ledf2vfp.S -- [x] arm/lesf2vfp.S -- [x] arm/ltdf2vfp.S -- [x] arm/ltsf2vfp.S - [ ] arm/modsi3.S (generic version is done) -- [x] arm/muldf3vfp.S -- [x] arm/mulsf3vfp.S -- [x] arm/nedf2vfp.S -- [ ] arm/negdf2vfp.S -- [ ] arm/negsf2vfp.S -- [x] arm/nesf2vfp.S - [x] arm/softfloat-alias.list -- [x] arm/subdf3vfp.S -- [x] arm/subsf3vfp.S -- [x] arm/truncdfsf2vfp.S - [ ] arm/udivmodsi4.S (generic version is done) - [ ] arm/udivsi3.S (generic version is done) - [ ] arm/umodsi3.S (generic version is done) -- [ ] arm/unorddf2vfp.S -- [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c - [ ] avr/divmodhi4.S @@ -501,6 +467,43 @@ Floating-point implementations of builtins that are only called from soft-float - ~~x86_64/floatdidf.c~~ - ~~x86_64/floatdisf.c~~ +Unsupported in any current target: used on old versions of 32-bit iOS with ARMv5. + +- ~~arm/adddf3vfp.S~~ +- ~~arm/addsf3vfp.S~~ +- ~~arm/divdf3vfp.S~~ +- ~~arm/divsf3vfp.S~~ +- ~~arm/eqdf2vfp.S~~ +- ~~arm/eqsf2vfp.S~~ +- ~~arm/extendsfdf2vfp.S~~ +- ~~arm/fixdfsivfp.S~~ +- ~~arm/fixsfsivfp.S~~ +- ~~arm/fixunsdfsivfp.S~~ +- ~~arm/fixunssfsivfp.S~~ +- ~~arm/floatsidfvfp.S~~ +- ~~arm/floatsisfvfp.S~~ +- ~~arm/floatunssidfvfp.S~~ +- ~~arm/floatunssisfvfp.S~~ +- ~~arm/gedf2vfp.S~~ +- ~~arm/gesf2vfp.S~~ +- ~~arm/gtdf2vfp.S~~ +- ~~arm/gtsf2vfp.S~~ +- ~~arm/ledf2vfp.S~~ +- ~~arm/lesf2vfp.S~~ +- ~~arm/ltdf2vfp.S~~ +- ~~arm/ltsf2vfp.S~~ +- ~~arm/muldf3vfp.S~~ +- ~~arm/mulsf3vfp.S~~ +- ~~arm/nedf2vfp.S~~ +- ~~arm/negdf2vfp.S~~ +- ~~arm/negsf2vfp.S~~ +- ~~arm/nesf2vfp.S~~ +- ~~arm/subdf3vfp.S~~ +- ~~arm/subsf3vfp.S~~ +- ~~arm/truncdfsf2vfp.S~~ +- ~~arm/unorddf2vfp.S~~ +- ~~arm/unordsf2vfp.S~~ + ## License The compiler-builtins crate is dual licensed under both the University of diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 03ed131af26..bceef7b0ed9 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -208,14 +208,4 @@ intrinsics! { pub extern "C" fn __addtf3(a: f128, b: f128) -> f128 { add(a, b) } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __addsf3vfp(a: f32, b: f32) -> f32 { - a + b - } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __adddf3vfp(a: f64, b: f64) -> f64 { - a + b - } } diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 1901ca4b362..bb7d4b498fe 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -258,55 +258,4 @@ intrinsics! { pub extern "aapcs" fn __aeabi_dcmpgt(a: f64, b: f64) -> i32 { (__gtdf2(a, b) > 0) as i32 } - - // On hard-float targets LLVM will use native instructions - // for all VFP intrinsics below - - pub extern "C" fn __gesf2vfp(a: f32, b: f32) -> i32 { - (a >= b) as i32 - } - - pub extern "C" fn __gedf2vfp(a: f64, b: f64) -> i32 { - (a >= b) as i32 - } - - pub extern "C" fn __gtsf2vfp(a: f32, b: f32) -> i32 { - (a > b) as i32 - } - - pub extern "C" fn __gtdf2vfp(a: f64, b: f64) -> i32 { - (a > b) as i32 - } - - pub extern "C" fn __ltsf2vfp(a: f32, b: f32) -> i32 { - (a < b) as i32 - } - - pub extern "C" fn __ltdf2vfp(a: f64, b: f64) -> i32 { - (a < b) as i32 - } - - pub extern "C" fn __lesf2vfp(a: f32, b: f32) -> i32 { - (a <= b) as i32 - } - - pub extern "C" fn __ledf2vfp(a: f64, b: f64) -> i32 { - (a <= b) as i32 - } - - pub extern "C" fn __nesf2vfp(a: f32, b: f32) -> i32 { - (a != b) as i32 - } - - pub extern "C" fn __nedf2vfp(a: f64, b: f64) -> i32 { - (a != b) as i32 - } - - pub extern "C" fn __eqsf2vfp(a: f32, b: f32) -> i32 { - (a == b) as i32 - } - - pub extern "C" fn __eqdf2vfp(a: f64, b: f64) -> i32 { - (a == b) as i32 - } } diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index c0d780b66dd..2a57ee1a0bd 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -926,14 +926,4 @@ intrinsics! { pub extern "C" fn __divdf3(a: f64, b: f64) -> f64 { div64(a, b) } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __divsf3vfp(a: f32, b: f32) -> f32 { - a / b - } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __divdf3vfp(a: f64, b: f64) -> f64 { - a / b - } } diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 9fabcde25a5..997475c8e04 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -76,11 +76,6 @@ intrinsics! { pub extern "C" fn __extendsfdf2(a: f32) -> f64 { extend(a) } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __extendsfdf2vfp(a: f32) -> f64 { - a as f64 // LLVM generate 'fcvtds' - } } intrinsics! { diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index cb0fcdfa853..a4c69ea8707 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -199,14 +199,4 @@ intrinsics! { pub extern "C" fn __multf3(a: f128, b: f128) -> f128 { mul(a, b) } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __mulsf3vfp(a: f32, b: f32) -> f32 { - a * b - } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __muldf3vfp(a: f64, b: f64) -> f64 { - a * b - } } diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index d33016ead2e..7e8a8945848 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -23,14 +23,4 @@ intrinsics! { __addtf3(a, f128::from_repr(b.repr() ^ f128::SIGN_MASK)) } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __subsf3vfp(a: f32, b: f32) -> f32 { - a - b - } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __subdf3vfp(a: f64, b: f64) -> f64 { - a - b - } } diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 5c17cd96acf..a25b6eabc5e 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -124,11 +124,6 @@ intrinsics! { pub extern "C" fn __truncdfsf2(a: f64) -> f32 { trunc(a) } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __truncdfsf2vfp(a: f64) -> f32 { - a as f32 - } } intrinsics! { diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs index 1ba2df74191..284a2bf5a11 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -139,13 +139,3 @@ mod float_addsub_f128_ppc { f128, __addkf3, __subkf3, Quad, not(feature = "no-sys-f128"); } } - -#[cfg(target_arch = "arm")] -mod float_addsub_arm { - use super::*; - - float_sum! { - f32, __addsf3vfp, __subsf3vfp, Single, all(); - f64, __adddf3vfp, __subdf3vfp, Double, all(); - } -} diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index 7e973e7e5ed..e3161f37429 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -156,7 +156,6 @@ mod float_comparisons_arm { fn cmp_f32() { use compiler_builtins::float::cmp::{ __aeabi_fcmpeq, __aeabi_fcmpge, __aeabi_fcmpgt, __aeabi_fcmple, __aeabi_fcmplt, - __eqsf2vfp, __gesf2vfp, __gtsf2vfp, __lesf2vfp, __ltsf2vfp, __nesf2vfp, }; fuzz_float_2(N, |x: f32, y: f32| { @@ -166,12 +165,6 @@ mod float_comparisons_arm { 0, x == y, __aeabi_fcmpeq; 0, x >= y, __aeabi_fcmpge; 0, x > y, __aeabi_fcmpgt; - 0, x < y, __ltsf2vfp; - 0, x <= y, __lesf2vfp; - 0, x == y, __eqsf2vfp; - 0, x >= y, __gesf2vfp; - 0, x > y, __gtsf2vfp; - 1, x != y, __nesf2vfp; ); }); } @@ -180,7 +173,6 @@ mod float_comparisons_arm { fn cmp_f64() { use compiler_builtins::float::cmp::{ __aeabi_dcmpeq, __aeabi_dcmpge, __aeabi_dcmpgt, __aeabi_dcmple, __aeabi_dcmplt, - __eqdf2vfp, __gedf2vfp, __gtdf2vfp, __ledf2vfp, __ltdf2vfp, __nedf2vfp, }; fuzz_float_2(N, |x: f64, y: f64| { @@ -190,12 +182,6 @@ mod float_comparisons_arm { 0, x == y, __aeabi_dcmpeq; 0, x >= y, __aeabi_dcmpge; 0, x > y, __aeabi_dcmpgt; - 0, x < y, __ltdf2vfp; - 0, x <= y, __ledf2vfp; - 0, x == y, __eqdf2vfp; - 0, x >= y, __gedf2vfp; - 0, x > y, __gtdf2vfp; - 1, x != y, __nedf2vfp; ); }); } diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index ce1f64e67d1..24f3a04a4ee 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -258,12 +258,6 @@ mod extend { f32 => f64, Single => Double, __extendsfdf2, all(); } - #[cfg(target_arch = "arm")] - f_to_f! { - extend, - f32 => f64, Single => Double, __extendsfdf2vfp, all(); - } - #[cfg(all(f16_enabled, f128_enabled))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] f_to_f! { @@ -293,12 +287,6 @@ mod trunc { f64 => f32, Double => Single, __truncdfsf2, all(); } - #[cfg(target_arch = "arm")] - f_to_f! { - trunc, - f64 => f32, Double => Single, __truncdfsf2vfp, all(); - } - #[cfg(all(f16_enabled, f128_enabled))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] f_to_f! { diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index ff78b4f54d5..418e9c18937 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -156,13 +156,3 @@ mod float_div { f64, __divdf3, Double, all(); } } - -#[cfg(target_arch = "arm")] -mod float_div_arm { - use super::*; - - float! { - f32, __divsf3vfp, Single, all(); - f64, __divdf3vfp, Double, all(); - } -} diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 867622fdf07..449d194804a 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -153,13 +153,3 @@ mod float_mul_f128_ppc { f128, __mulkf3, Quad, not(feature = "no-sys-f128"); } } - -#[cfg(target_arch = "arm")] -mod float_mul_arm { - use super::*; - - float_mul! { - f32, __mulsf3vfp, Single, all(); - f64, __muldf3vfp, Double, all(); - } -} -- cgit 1.4.1-3-g733a5 From 625462202e58c0043156e5407b54e5eeb14b7ad7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 5 Sep 2024 09:03:28 -0700 Subject: Use the trifecta div algorithm for 128-bit div on wasm This commit updates the `#[cfg]` annotations used to select the implementation of 128-bit division in compiler-builtins on wasm targets. This is done with relation to https://github.com/WebAssembly/128-bit-arithmetic where performance of 128-bit operations is being investigated on WebAssembly. While I don't know much about the particulars of the two algorithms involved here the comments indicate that the "trifecta" variant is preferred if possible but it's not selected on 32-bit architectures. This rationale isn't as applicable to WebAssembly targets because despite the 32-bit pointer width there are often wider-than-pointer operations available as it's typically run on 64-bit machines. Locally in testing a benchmark that performs division with a Rust-based bignum libraries whent from 350% slower-than-native to 220% slower-than-native with this change, a nice increase in speed. While this was tested with Wasmtime other runtimes are likely to see an improvement as well. --- .../src/int/specialized_div_rem/mod.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 760f5f5b7a3..a91fe6632ee 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -136,9 +136,15 @@ fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { // Whether `trifecta` or `delegate` is faster for 128 bit division depends on the speed at which a // microarchitecture can multiply and divide. We decide to be optimistic and assume `trifecta` is -// faster if the target pointer width is at least 64. +// faster if the target pointer width is at least 64. Note that this +// implementation is additionally included on WebAssembly despite the typical +// pointer width there being 32 because it's typically run on a 64-bit machine +// that has access to faster 64-bit operations. #[cfg(all( - not(any(target_pointer_width = "16", target_pointer_width = "32")), + any( + target_family = "wasm", + not(any(target_pointer_width = "16", target_pointer_width = "32")), + ), not(all(not(feature = "no-asm"), target_arch = "x86_64")), not(any(target_arch = "sparc", target_arch = "sparc64")) ))] @@ -152,10 +158,14 @@ impl_trifecta!( u128 ); -// If the pointer width less than 64, then the target architecture almost certainly does not have -// the fast 64 to 128 bit widening multiplication needed for `trifecta` to be faster. +// If the pointer width less than 64 and this isn't wasm, then the target +// architecture almost certainly does not have the fast 64 to 128 bit widening +// multiplication needed for `trifecta` to be faster. #[cfg(all( - any(target_pointer_width = "16", target_pointer_width = "32"), + not(any( + target_family = "wasm", + not(any(target_pointer_width = "16", target_pointer_width = "32")), + )), not(all(not(feature = "no-asm"), target_arch = "x86_64")), not(any(target_arch = "sparc", target_arch = "sparc64")) ))] -- cgit 1.4.1-3-g733a5 From 07112912290385f038777a3b26b467fa7ff0ba52 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 16:14:31 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f5a04747a72..1c7bc5db0ee 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.124" +version = "0.1.125" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 1a343b61182ae1de868cdd00e54fce9231e9ae5c Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 9 Sep 2024 16:44:50 +0200 Subject: use `naked_asm!` in `#[naked]` functions --- library/compiler-builtins/src/aarch64.rs | 3 +-- library/compiler-builtins/src/aarch64_linux.rs | 12 ++++-------- library/compiler-builtins/src/arm.rs | 12 ++++-------- library/compiler-builtins/src/x86.rs | 8 ++++---- library/compiler-builtins/src/x86_64.rs | 4 ++-- 5 files changed, 15 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64.rs index e5747d5258f..cce485c4682 100644 --- a/library/compiler-builtins/src/aarch64.rs +++ b/library/compiler-builtins/src/aarch64.rs @@ -6,7 +6,7 @@ intrinsics! { #[naked] #[cfg(all(target_os = "uefi", not(feature = "no-asm")))] pub unsafe extern "C" fn __chkstk() { - core::arch::asm!( + core::arch::naked_asm!( ".p2align 2", "lsl x16, x15, #4", "mov x17, sp", @@ -16,7 +16,6 @@ intrinsics! { "ldr xzr, [x17]", "b.gt 1b", "ret", - options(noreturn) ); } } diff --git a/library/compiler-builtins/src/aarch64_linux.rs b/library/compiler-builtins/src/aarch64_linux.rs index 62144e53199..caac3e6025d 100644 --- a/library/compiler-builtins/src/aarch64_linux.rs +++ b/library/compiler-builtins/src/aarch64_linux.rs @@ -136,7 +136,7 @@ macro_rules! compare_and_swap { expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { // We can't use `AtomicI8::compare_and_swap`; we *are* compare_and_swap. - unsafe { core::arch::asm! { + unsafe { core::arch::naked_asm! { // UXT s(tmp0), s(0) concat!(uxt!($bytes), " ", reg!($bytes, 16), ", ", reg!($bytes, 0)), "0:", @@ -150,7 +150,6 @@ macro_rules! compare_and_swap { "cbnz w17, 0b", "1:", "ret", - options(noreturn) } } } } @@ -166,7 +165,7 @@ macro_rules! compare_and_swap_i128 { pub unsafe extern "C" fn $name ( expected: i128, desired: i128, ptr: *mut i128 ) -> i128 { - unsafe { core::arch::asm! { + unsafe { core::arch::naked_asm! { "mov x16, x0", "mov x17, x1", "0:", @@ -180,7 +179,6 @@ macro_rules! compare_and_swap_i128 { "cbnz w15, 0b", "1:", "ret", - options(noreturn) } } } } @@ -196,7 +194,7 @@ macro_rules! swap { pub unsafe extern "C" fn $name ( left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { - unsafe { core::arch::asm! { + unsafe { core::arch::naked_asm! { // mov s(tmp0), s(0) concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), "0:", @@ -206,7 +204,6 @@ macro_rules! swap { concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 16), ", [x1]"), "cbnz w17, 0b", "ret", - options(noreturn) } } } } @@ -222,7 +219,7 @@ macro_rules! fetch_op { pub unsafe extern "C" fn $name ( val: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { - unsafe { core::arch::asm! { + unsafe { core::arch::naked_asm! { // mov s(tmp0), s(0) concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), "0:", @@ -234,7 +231,6 @@ macro_rules! fetch_op { concat!(stxr!($ordering, $bytes), " w15, ", reg!($bytes, 17), ", [x1]"), "cbnz w15, 0b", "ret", - options(noreturn) } } } } diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 55cdda1f3e0..9e6608397a8 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -23,7 +23,7 @@ intrinsics! { #[naked] #[cfg(not(target_env = "msvc"))] pub unsafe extern "C" fn __aeabi_uidivmod() { - core::arch::asm!( + core::arch::naked_asm!( "push {{lr}}", "sub sp, sp, #4", "mov r2, sp", @@ -31,13 +31,12 @@ intrinsics! { "ldr r1, [sp]", "add sp, sp, #4", "pop {{pc}}", - options(noreturn) ); } #[naked] pub unsafe extern "C" fn __aeabi_uldivmod() { - core::arch::asm!( + core::arch::naked_asm!( "push {{r4, lr}}", "sub sp, sp, #16", "add r4, sp, #8", @@ -47,26 +46,24 @@ intrinsics! { "ldr r3, [sp, #12]", "add sp, sp, #16", "pop {{r4, pc}}", - options(noreturn) ); } #[naked] pub unsafe extern "C" fn __aeabi_idivmod() { - core::arch::asm!( + core::arch::naked_asm!( "push {{r0, r1, r4, lr}}", bl!("__aeabi_idiv"), "pop {{r1, r2}}", "muls r2, r2, r0", "subs r1, r1, r2", "pop {{r4, pc}}", - options(noreturn) ); } #[naked] pub unsafe extern "C" fn __aeabi_ldivmod() { - core::arch::asm!( + core::arch::naked_asm!( "push {{r4, lr}}", "sub sp, sp, #16", "add r4, sp, #8", @@ -76,7 +73,6 @@ intrinsics! { "ldr r3, [sp, #12]", "add sp, sp, #16", "pop {{r4, pc}}", - options(noreturn) ); } diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index ceec3912eab..ad04d2108ea 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -14,9 +14,9 @@ intrinsics! { not(feature = "no-asm") ))] pub unsafe extern "C" fn __chkstk() { - core::arch::asm!( + core::arch::naked_asm!( "jmp __alloca", // Jump to __alloca since fallthrough may be unreliable" - options(noreturn, att_syntax) + options(att_syntax) ); } @@ -27,7 +27,7 @@ intrinsics! { ))] pub unsafe extern "C" fn _alloca() { // __chkstk and _alloca are the same function - core::arch::asm!( + core::arch::naked_asm!( "push %ecx", "cmp $0x1000,%eax", "lea 8(%esp),%ecx", // esp before calling this routine -> ecx @@ -47,7 +47,7 @@ intrinsics! { "push (%eax)", // push return address onto the stack "sub %esp,%eax", // restore the original value in eax "ret", - options(noreturn, att_syntax) + options(att_syntax) ); } } diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 8048f85c8ff..9c91a45561e 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -14,7 +14,7 @@ intrinsics! { not(feature = "no-asm") ))] pub unsafe extern "C" fn ___chkstk_ms() { - core::arch::asm!( + core::arch::naked_asm!( "push %rcx", "push %rax", "cmp $0x1000,%rax", @@ -32,7 +32,7 @@ intrinsics! { "pop %rax", "pop %rcx", "ret", - options(noreturn, att_syntax) + options(att_syntax) ); } } -- cgit 1.4.1-3-g733a5 From 22ef22e30b151dbb4eeafa15aa3a54a009652d70 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 17:09:04 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 1c7bc5db0ee..1aa6e5668d9 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.125" +version = "0.1.126" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 44840a12bcdbdef7eabd82a6dd5b396fdf7d90ed Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 15:33:05 -0500 Subject: Add `Shr` to `u256` Float division requires some shift operations on big integers; implement right shift here. --- library/compiler-builtins/src/int/big.rs | 37 +++++++++++- library/compiler-builtins/testcrate/tests/big.rs | 73 ++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/big.rs b/library/compiler-builtins/src/int/big.rs index 019dd728b5d..e565da89720 100644 --- a/library/compiler-builtins/src/int/big.rs +++ b/library/compiler-builtins/src/int/big.rs @@ -93,7 +93,7 @@ macro_rules! impl_common { type Output = Self; fn shl(self, rhs: u32) -> Self::Output { - todo!() + unimplemented!("only used to meet trait bounds") } } }; @@ -102,6 +102,41 @@ macro_rules! impl_common { impl_common!(i256); impl_common!(u256); +impl ops::Shr for u256 { + type Output = Self; + + fn shr(self, rhs: u32) -> Self::Output { + assert!(rhs < Self::BITS, "attempted to shift right with overflow"); + + if rhs == 0 { + return self; + } + + let mut ret = self; + let byte_shift = rhs / 64; + let bit_shift = rhs % 64; + + for idx in 0..4 { + let base_idx = idx + byte_shift as usize; + + let Some(base) = ret.0.get(base_idx) else { + ret.0[idx] = 0; + continue; + }; + + let mut new_val = base >> bit_shift; + + if let Some(new) = ret.0.get(base_idx + 1) { + new_val |= new.overflowing_shl(64 - bit_shift).0; + } + + ret.0[idx] = new_val; + } + + ret + } +} + macro_rules! word { (1, $val:expr) => { (($val >> (32 * 3)) & Self::from(WORD_LO_MASK)) as u64 diff --git a/library/compiler-builtins/testcrate/tests/big.rs b/library/compiler-builtins/testcrate/tests/big.rs index 128b5ddfd6d..595f6225607 100644 --- a/library/compiler-builtins/testcrate/tests/big.rs +++ b/library/compiler-builtins/testcrate/tests/big.rs @@ -59,3 +59,76 @@ fn widen_mul_u128() { } assert!(errors.is_empty()); } + +#[test] +fn not_u128() { + assert_eq!(!u256::ZERO, u256::MAX); +} + +#[test] +fn shr_u128() { + let only_low = [ + 1, + u16::MAX.into(), + u32::MAX.into(), + u64::MAX.into(), + u128::MAX, + ]; + + let mut errors = Vec::new(); + + for a in only_low { + for perturb in 0..10 { + let a = a.saturating_add(perturb); + for shift in 0..128 { + let res = a.widen() >> shift; + let expected = (a >> shift).widen(); + if res != expected { + errors.push((a.widen(), shift, res, expected)); + } + } + } + } + + let check = [ + ( + u256::MAX, + 1, + u256([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 1]), + ), + ( + u256::MAX, + 5, + u256([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 5]), + ), + (u256::MAX, 63, u256([u64::MAX, u64::MAX, u64::MAX, 1])), + (u256::MAX, 64, u256([u64::MAX, u64::MAX, u64::MAX, 0])), + (u256::MAX, 65, u256([u64::MAX, u64::MAX, u64::MAX >> 1, 0])), + (u256::MAX, 127, u256([u64::MAX, u64::MAX, 1, 0])), + (u256::MAX, 128, u256([u64::MAX, u64::MAX, 0, 0])), + (u256::MAX, 129, u256([u64::MAX, u64::MAX >> 1, 0, 0])), + (u256::MAX, 191, u256([u64::MAX, 1, 0, 0])), + (u256::MAX, 192, u256([u64::MAX, 0, 0, 0])), + (u256::MAX, 193, u256([u64::MAX >> 1, 0, 0, 0])), + (u256::MAX, 191, u256([u64::MAX, 1, 0, 0])), + (u256::MAX, 254, u256([0b11, 0, 0, 0])), + (u256::MAX, 255, u256([1, 0, 0, 0])), + ]; + + for (input, shift, expected) in check { + let res = input >> shift; + if res != expected { + errors.push((input, shift, res, expected)); + } + } + + for (a, b, res, expected) in &errors { + eprintln!( + "FAILURE: {} >> {b} = {} got {}", + hexu(*a), + hexu(*expected), + hexu(*res), + ); + } + assert!(errors.is_empty()); +} -- cgit 1.4.1-3-g733a5 From 23af8ca763ca8096a05569065485879fc8b6d84f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 15:35:49 -0500 Subject: Update bounds and docs for the `Float` trait Add some bounds to integer types that allow our function trait bounds to be slightly less verbose. Also clarify documentation and remove a redundant operation. --- library/compiler-builtins/src/float/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 8473732057a..704bba0c025 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -31,10 +31,10 @@ pub(crate) trait Float: + ops::Rem { /// A uint of the same width as the float - type Int: Int; + type Int: Int; /// A int of the same width as the float - type SignedInt: Int; + type SignedInt: Int + MinInt; /// An int capable of containing the exponent bits plus a sign bit. This is signed. type ExpInt: Int; @@ -51,7 +51,7 @@ pub(crate) trait Float: /// The bitwidth of the exponent const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; - /// The maximum value of the exponent + /// The saturated value of the exponent (infinite representation), in the rightmost postiion. const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; /// The exponent bias value @@ -83,7 +83,7 @@ pub(crate) trait Float: /// Returns true if the sign is negative fn is_sign_negative(self) -> bool; - /// Returns the exponent with bias + /// Returns the exponent, not adjusting for bias. fn exp(self) -> Self::ExpInt; /// Returns the significand with no implicit bit (or the "fractional" part) @@ -175,7 +175,7 @@ macro_rules! float_impl { fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand .leading_zeros() - .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros()); + .wrapping_sub(Self::EXPONENT_BITS); ( 1i32.wrapping_sub(shift as i32), significand << shift as Self::Int, -- cgit 1.4.1-3-g733a5 From 4f8afbabdc26f140e2800056440ed14876976b80 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 15:40:43 -0500 Subject: Make float division generic Float division currently has a separate `div32` and `div64` for `f32` and `f64`, respectively. Combine these to make use of generics. This will make it easier to support `f128` division, and reduces a lot of redundant code. This includes a simplification of division tests. --- library/compiler-builtins/src/float/div.rs | 1027 +++++++------------- .../compiler-builtins/testcrate/tests/div_rem.rs | 23 +- 2 files changed, 366 insertions(+), 684 deletions(-) diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 2a57ee1a0bd..4aec3418f4b 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -1,518 +1,149 @@ -// The functions are complex with many branches, and explicit -// `return`s makes it clear where function exit points are -#![allow(clippy::needless_return)] - -use crate::float::Float; -use crate::int::{CastInto, DInt, HInt, Int, MinInt}; +//! Floating point division routines. +//! +//! This module documentation gives an overview of the method used. More documentation is inline. +//! +//! # Relevant notation +//! +//! - `m_a`: the mantissa of `a`, in base 2 +//! - `p_a`: the exponent of `a`, in base 2. I.e. `a = m_a * 2^p_a` +//! - `uqN` (e.g. `uq1`): this refers to Q notation for fixed-point numbers. UQ1.31 is an unsigned +//! fixed-point number with 1 integral bit, and 31 decimal bits. A `uqN` variable of type `uM` +//! will have N bits of integer and M-N bits of fraction. +//! - `hw`: half width, i.e. for `f64` this will be a `u32`. +//! - `x` is the best estimate of `1/m_b` +//! +//! # Method Overview +//! +//! Division routines must solve for `a / b`, which is `res = m_a*2^p_a / m_b*2^p_b`. The basic +//! process is as follows: +//! +//! - Rearange the exponent and significand to simplify the operations: +//! `res = (m_a / m_b) * 2^{p_a - p_b}`. +//! - Check for early exits (infinity, zero, etc). +//! - If `a` or `b` are subnormal, normalize by shifting the mantissa and adjusting the exponent. +//! - Set the implicit bit so math is correct. +//! - Shift mantissa significant digits (with implicit bit) fully left such that fixed-point UQ1 +//! or UQ0 numbers can be used for mantissa math. These will have greater precision than the +//! actual mantissa, which is important for correct rounding. +//! - Calculate the reciprocal of `m_b`, `x`. +//! - Use the reciprocal to multiply rather than divide: `res = m_a * x_b * 2^{p_a - p_b}`. +//! - Reapply rounding. +//! +//! # Reciprocal calculation +//! +//! Calculating the reciprocal is the most complicated part of this process. It uses the +//! [Newton-Raphson method], which picks an initial estimation (of the reciprocal) and performs +//! a number of iterations to increase its precision. +//! +//! In general, Newton's method takes the following form: +//! +//! ```text +//! `x_n` is a guess or the result of a previous iteration. Increasing `n` converges to the +//! desired result. +//! +//! The result approaches a zero of `f(x)` by applying a correction to the previous gues. +//! +//! x_{n+1} = x_n - f(x_n) / f'(x_n) +//! ``` +//! +//! Applying this to find the reciprocal: +//! +//! ```text +//! 1 / x = b +//! +//! Rearrange so we can solve by finding a zero +//! 0 = (1 / x) - b = f(x) +//! +//! f'(x) = -x^{-2} +//! +//! x_{n+1} = 2*x_n - b*x_n^2 +//! ``` +//! +//! This is a process that can be repeated to calculate the reciprocal with enough precision to +//! achieve a correctly rounded result for the overall division operation. The maximum required +//! number of iterations is known since precision doubles with each iteration. +//! +//! # Half-width operations +//! +//! Calculating the reciprocal requires widening multiplication and performing arithmetic on the +//! results, meaning that emulated integer arithmetic on `u128` (for `f64`) and `u256` (for `f128`) +//! gets used instead of native math. +//! +//! To make this more efficient, all but the final operation can be computed using half-width +//! integers. For example, rather than computing four iterations using 128-bit integers for `f64`, +//! we can instead perform three iterations using native 64-bit integers and only one final +//! iteration using the full 128 bits. +//! +//! This works because of precision doubling. Some leeway is allowed here because the fixed-point +//! number has more bits than the final mantissa will. +//! +//! [Newton-Raphson method]: https://en.wikipedia.org/wiki/Newton%27s_method use super::HalfRep; +use crate::float::Float; +use crate::int::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; +use core::mem::size_of; +use core::ops; -fn div32(a: F, b: F) -> F -where - u32: CastInto, - F::Int: CastInto, - i32: CastInto, - F::Int: CastInto, - F::Int: HInt, - ::Int: core::ops::Mul, -{ - const NUMBER_OF_HALF_ITERATIONS: usize = 0; - const NUMBER_OF_FULL_ITERATIONS: usize = 3; - const USE_NATIVE_FULL_ITERATIONS: bool = true; - - let one = F::Int::ONE; - let zero = F::Int::ZERO; - let hw = F::BITS / 2; - let lo_mask = u32::MAX >> hw; - - let significand_bits = F::SIGNIFICAND_BITS; - let max_exponent = F::EXPONENT_MAX; - - let exponent_bias = F::EXPONENT_BIAS; - - let implicit_bit = F::IMPLICIT_BIT; - let significand_mask = F::SIGNIFICAND_MASK; - let sign_bit = F::SIGN_MASK as F::Int; - let abs_mask = sign_bit - one; - let exponent_mask = F::EXPONENT_MASK; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; - - #[inline(always)] - fn negate_u32(a: u32) -> u32 { - (::wrapping_neg(a as i32)) as u32 - } - - let a_rep = a.repr(); - let b_rep = b.repr(); - - let a_exponent = (a_rep >> significand_bits) & max_exponent.cast(); - let b_exponent = (b_rep >> significand_bits) & max_exponent.cast(); - let quotient_sign = (a_rep ^ b_rep) & sign_bit; - - let mut a_significand = a_rep & significand_mask; - let mut b_significand = b_rep & significand_mask; - let mut scale = 0; - - // Detect if a or b is zero, denormal, infinity, or NaN. - if a_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() - || b_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() - { - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; - - // NaN / anything = qNaN - if a_abs > inf_rep { - return F::from_repr(a_rep | quiet_bit); - } - // anything / NaN = qNaN - if b_abs > inf_rep { - return F::from_repr(b_rep | quiet_bit); - } - - if a_abs == inf_rep { - if b_abs == inf_rep { - // infinity / infinity = NaN - return F::from_repr(qnan_rep); - } else { - // infinity / anything else = +/- infinity - return F::from_repr(a_abs | quotient_sign); - } - } - - // anything else / infinity = +/- 0 - if b_abs == inf_rep { - return F::from_repr(quotient_sign); - } - - if a_abs == zero { - if b_abs == zero { - // zero / zero = NaN - return F::from_repr(qnan_rep); - } else { - // zero / anything else = +/- zero - return F::from_repr(quotient_sign); - } - } - - // anything else / zero = +/- infinity - if b_abs == zero { - return F::from_repr(inf_rep | quotient_sign); - } - - // one or both of a or b is denormal, the other (if applicable) is a - // normal number. Renormalize one or both of a and b, and set scale to - // include the necessary exponent adjustment. - if a_abs < implicit_bit { - let (exponent, significand) = F::normalize(a_significand); - scale += exponent; - a_significand = significand; - } - - if b_abs < implicit_bit { - let (exponent, significand) = F::normalize(b_significand); - scale -= exponent; - b_significand = significand; - } - } - - // Set the implicit significand bit. If we fell through from the - // denormal path it was already set by normalize( ), but setting it twice - // won't hurt anything. - a_significand |= implicit_bit; - b_significand |= implicit_bit; - - let written_exponent: i32 = CastInto::::cast( - a_exponent - .wrapping_sub(b_exponent) - .wrapping_add(scale.cast()), - ) - .wrapping_add(exponent_bias) as i32; - let b_uq1 = b_significand << (F::BITS - significand_bits - 1); - - // Align the significand of b as a UQ1.(n-1) fixed-point number in the range - // [1.0, 2.0) and get a UQ0.n approximate reciprocal using a small minimax - // polynomial approximation: x0 = 3/4 + 1/sqrt(2) - b/2. - // The max error for this approximation is achieved at endpoints, so - // abs(x0(b) - 1/b) <= abs(x0(1) - 1/1) = 3/4 - 1/sqrt(2) = 0.04289..., - // which is about 4.5 bits. - // The initial approximation is between x0(1.0) = 0.9571... and x0(2.0) = 0.4571... - - // Then, refine the reciprocal estimate using a quadratically converging - // Newton-Raphson iteration: - // x_{n+1} = x_n * (2 - x_n * b) - // - // Let b be the original divisor considered "in infinite precision" and - // obtained from IEEE754 representation of function argument (with the - // implicit bit set). Corresponds to rep_t-sized b_UQ1 represented in - // UQ1.(W-1). - // - // Let b_hw be an infinitely precise number obtained from the highest (HW-1) - // bits of divisor significand (with the implicit bit set). Corresponds to - // half_rep_t-sized b_UQ1_hw represented in UQ1.(HW-1) that is a **truncated** - // version of b_UQ1. - // - // Let e_n := x_n - 1/b_hw - // E_n := x_n - 1/b - // abs(E_n) <= abs(e_n) + (1/b_hw - 1/b) - // = abs(e_n) + (b - b_hw) / (b*b_hw) - // <= abs(e_n) + 2 * 2^-HW - - // rep_t-sized iterations may be slower than the corresponding half-width - // variant depending on the handware and whether single/double/quad precision - // is selected. - // NB: Using half-width iterations increases computation errors due to - // rounding, so error estimations have to be computed taking the selected - // mode into account! - - #[allow(clippy::absurd_extreme_comparisons)] - let mut x_uq0 = if NUMBER_OF_HALF_ITERATIONS > 0 { - // Starting with (n-1) half-width iterations - let b_uq1_hw: u16 = - (CastInto::::cast(b_significand) >> (significand_bits + 1 - hw)) as u16; - - // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW - // with W0 being either 16 or 32 and W0 <= HW. - // That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from which - // b/2 is subtracted to obtain x0) wrapped to [0, 1) range. - - // HW is at least 32. Shifting into the highest bits if needed. - let c_hw = (0x7504_u32 as u16).wrapping_shl(hw.wrapping_sub(32)); - - // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, - // so x0 fits to UQ0.HW without wrapping. - let x_uq0_hw: u16 = { - let mut x_uq0_hw: u16 = c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); - // An e_0 error is comprised of errors due to - // * x0 being an inherently imprecise first approximation of 1/b_hw - // * C_hw being some (irrational) number **truncated** to W0 bits - // Please note that e_0 is calculated against the infinitely precise - // reciprocal of b_hw (that is, **truncated** version of b). - // - // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0 - - // By construction, 1 <= b < 2 - // f(x) = x * (2 - b*x) = 2*x - b*x^2 - // f'(x) = 2 * (1 - b*x) - // - // On the [0, 1] interval, f(0) = 0, - // then it increses until f(1/b) = 1 / b, maximum on (0, 1), - // then it decreses to f(1) = 2 - b - // - // Let g(x) = x - f(x) = b*x^2 - x. - // On (0, 1/b), g(x) < 0 <=> f(x) > x - // On (1/b, 1], g(x) > 0 <=> f(x) < x - // - // For half-width iterations, b_hw is used instead of b. - #[allow(clippy::reversed_empty_ranges)] - for _ in 0..NUMBER_OF_HALF_ITERATIONS { - // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp - // of corr_UQ1_hw. - // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1). - // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided - // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is - // expected to be strictly positive because b_UQ1_hw has its highest bit set - // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). - let corr_uq1_hw: u16 = - 0.wrapping_sub((x_uq0_hw as u32).wrapping_mul(b_uq1_hw.cast()) >> hw) as u16; - - // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally - // obtaining an UQ1.(HW-1) number and proving its highest bit could be - // considered to be 0 to be able to represent it in UQ0.HW. - // From the above analysis of f(x), if corr_UQ1_hw would be represented - // without any intermediate loss of precision (that is, in twice_rep_t) - // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly - // less otherwise. On the other hand, to obtain [1.]000..., one have to pass - // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due - // to 1.0 being not representable as UQ0.HW). - // The fact corr_UQ1_hw was virtually round up (due to result of - // multiplication being **first** truncated, then negated - to improve - // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. - x_uq0_hw = ((x_uq0_hw as u32).wrapping_mul(corr_uq1_hw as u32) >> (hw - 1)) as u16; - // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t - // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after - // any number of iterations, so just subtract 2 from the reciprocal - // approximation after last iteration. - - // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW: - // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1 - // = 1 - e_n * b_hw + 2*eps1 - // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2 - // = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2 - // = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2 - // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2 - // = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw - // \------ >0 -------/ \-- >0 ---/ - // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U) - } - // For initial half-width iterations, U = 2^-HW - // Let abs(e_n) <= u_n * U, - // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U) - // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2) - - // Account for possible overflow (see above). For an overflow to occur for the - // first time, for "ideal" corr_UQ1_hw (that is, without intermediate - // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum - // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to - // be not below that value (see g(x) above), so it is safe to decrement just - // once after the final iteration. On the other hand, an effective value of - // divisor changes after this point (from b_hw to b), so adjust here. - x_uq0_hw.wrapping_sub(1_u16) - }; - - // Error estimations for full-precision iterations are calculated just - // as above, but with U := 2^-W and taking extra decrementing into account. - // We need at least one such iteration. - - // Simulating operations on a twice_rep_t to perform a single final full-width - // iteration. Using ad-hoc multiplication implementations to take advantage - // of particular structure of operands. - - let blo: u32 = (CastInto::::cast(b_uq1)) & lo_mask; - // x_UQ0 = x_UQ0_hw * 2^HW - 1 - // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1 - // - // <--- higher half ---><--- lower half ---> - // [x_UQ0_hw * b_UQ1_hw] - // + [ x_UQ0_hw * blo ] - // - [ b_UQ1 ] - // = [ result ][.... discarded ...] - let corr_uq1 = negate_u32( - (x_uq0_hw as u32) * (b_uq1_hw as u32) + (((x_uq0_hw as u32) * (blo)) >> hw) - 1, - ); // account for *possible* carry - let lo_corr = corr_uq1 & lo_mask; - let hi_corr = corr_uq1 >> hw; - // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1 - let mut x_uq0: ::Int = ((((x_uq0_hw as u32) * hi_corr) << 1) - .wrapping_add(((x_uq0_hw as u32) * lo_corr) >> (hw - 1)) - .wrapping_sub(2)) - .cast(); // 1 to account for the highest bit of corr_UQ1 can be 1 - // 1 to account for possible carry - // Just like the case of half-width iterations but with possibility - // of overflowing by one extra Ulp of x_UQ0. - x_uq0 -= one; - // ... and then traditional fixup by 2 should work - - // On error estimation: - // abs(E_{N-1}) <= (u_{N-1} + 2 /* due to conversion e_n -> E_n */) * 2^-HW - // + (2^-HW + 2^-W)) - // abs(E_{N-1}) <= (u_{N-1} + 3.01) * 2^-HW - - // Then like for the half-width iterations: - // With 0 <= eps1, eps2 < 2^-W - // E_N = 4 * E_{N-1} * eps1 - (E_{N-1}^2 * b + 4 * eps2) + 4 * eps1 / b - // abs(E_N) <= 2^-W * [ 4 * abs(E_{N-1}) + max(2 * abs(E_{N-1})^2 * 2^W + 4, 8)) ] - // abs(E_N) <= 2^-W * [ 4 * (u_{N-1} + 3.01) * 2^-HW + max(4 + 2 * (u_{N-1} + 3.01)^2, 8) ] - x_uq0 - } else { - // C is (3/4 + 1/sqrt(2)) - 1 truncated to 32 fractional bits as UQ0.n - let c: ::Int = (0x7504F333 << (F::BITS - 32)).cast(); - let x_uq0: ::Int = c.wrapping_sub(b_uq1); - // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-32 - x_uq0 - }; - - let mut x_uq0 = if USE_NATIVE_FULL_ITERATIONS { - for _ in 0..NUMBER_OF_FULL_ITERATIONS { - let corr_uq1: u32 = 0.wrapping_sub( - ((CastInto::::cast(x_uq0) as u64) * (CastInto::::cast(b_uq1) as u64)) - >> F::BITS, - ) as u32; - x_uq0 = ((((CastInto::::cast(x_uq0) as u64) * (corr_uq1 as u64)) >> (F::BITS - 1)) - as u32) - .cast(); - } - x_uq0 - } else { - // not using native full iterations - x_uq0 - }; - - // Finally, account for possible overflow, as explained above. - x_uq0 = x_uq0.wrapping_sub(2.cast()); - - // u_n for different precisions (with N-1 half-width iterations): - // W0 is the precision of C - // u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW - - // Estimated with bc: - // define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; } - // define half2(un) { return 2.0 * un / 2.0^hw + 2.0; } - // define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; } - // define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; } - - // | f32 (0 + 3) | f32 (2 + 1) | f64 (3 + 1) | f128 (4 + 1) - // u_0 | < 184224974 | < 2812.1 | < 184224974 | < 791240234244348797 - // u_1 | < 15804007 | < 242.7 | < 15804007 | < 67877681371350440 - // u_2 | < 116308 | < 2.81 | < 116308 | < 499533100252317 - // u_3 | < 7.31 | | < 7.31 | < 27054456580 - // u_4 | | | | < 80.4 - // Final (U_N) | same as u_3 | < 72 | < 218 | < 13920 - - // Add 2 to U_N due to final decrement. - - let reciprocal_precision: ::Int = 10.cast(); - - // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W - let x_uq0 = x_uq0 - reciprocal_precision; - // Now 1/b - (2*P) * 2^-W < x < 1/b - // FIXME Is x_UQ0 still >= 0.5? - - let mut quotient: ::Int = x_uq0.widen_mul(a_significand << 1).hi(); - // Now, a/b - 4*P * 2^-W < q < a/b for q= in UQ1.(SB+1+W). - - // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1), - // adjust it to be in [1.0, 2.0) as UQ1.SB. - let (mut residual, written_exponent) = if quotient < (implicit_bit << 1) { - // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB, - // effectively doubling its value as well as its error estimation. - let residual_lo = (a_significand << (significand_bits + 1)).wrapping_sub( - (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) - .cast(), - ); - a_significand <<= 1; - (residual_lo, written_exponent.wrapping_sub(1)) - } else { - // Highest bit is 1 (the UQ1.(SB+1) value is in [1, 2)), convert it - // to UQ1.SB by right shifting by 1. Least significant bit is omitted. - quotient >>= 1; - let residual_lo = (a_significand << significand_bits).wrapping_sub( - (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) - .cast(), - ); - (residual_lo, written_exponent) - }; - - //drop mutability - let quotient = quotient; - - // NB: residualLo is calculated above for the normal result case. - // It is re-computed on denormal path that is expected to be not so - // performance-sensitive. - - // Now, q cannot be greater than a/b and can differ by at most 8*P * 2^-W + 2^-SB - // Each NextAfter() increments the floating point value by at least 2^-SB - // (more, if exponent was incremented). - // Different cases (<---> is of 2^-SB length, * = a/b that is shown as a midpoint): - // q - // | | * | | | | | - // <---> 2^t - // | | | | | * | | - // q - // To require at most one NextAfter(), an error should be less than 1.5 * 2^-SB. - // (8*P) * 2^-W + 2^-SB < 1.5 * 2^-SB - // (8*P) * 2^-W < 0.5 * 2^-SB - // P < 2^(W-4-SB) - // Generally, for at most R NextAfter() to be enough, - // P < (2*R - 1) * 2^(W-4-SB) - // For f32 (0+3): 10 < 32 (OK) - // For f32 (2+1): 32 < 74 < 32 * 3, so two NextAfter() are required - // For f64: 220 < 256 (OK) - // For f128: 4096 * 3 < 13922 < 4096 * 5 (three NextAfter() are required) - - // If we have overflowed the exponent, return infinity - if written_exponent >= max_exponent as i32 { - return F::from_repr(inf_rep | quotient_sign); - } - - // Now, quotient <= the correctly-rounded result - // and may need taking NextAfter() up to 3 times (see error estimates above) - // r = a - b * q - let abs_result = if written_exponent > 0 { - let mut ret = quotient & significand_mask; - ret |= ((written_exponent as u32) << significand_bits).cast(); - residual <<= 1; - ret - } else { - if (significand_bits as i32 + written_exponent) < 0 { - return F::from_repr(quotient_sign); - } - let ret = quotient.wrapping_shr(negate_u32(CastInto::::cast(written_exponent)) + 1); - residual = (CastInto::::cast( - a_significand.wrapping_shl( - significand_bits.wrapping_add(CastInto::::cast(written_exponent)), - ), - ) - .wrapping_sub( - (CastInto::::cast(ret).wrapping_mul(CastInto::::cast(b_significand))) << 1, - )) - .cast(); - ret - }; - // Round - let abs_result = { - residual += abs_result & one; // tie to even - // The above line conditionally turns the below LT comparison into LTE - - if residual > b_significand { - abs_result + one - } else { - abs_result - } - }; - F::from_repr(abs_result | quotient_sign) -} - -fn div64(a: F, b: F) -> F +fn div(a: F, b: F) -> F where - F::Int: CastInto, F::Int: CastInto, - F::Int: CastInto>, F::Int: From>, F::Int: From, - F::Int: CastInto, - F::Int: CastInto, F::Int: HInt + DInt, + ::D: ops::Shr::D>, + F::Int: From, u16: CastInto, i32: CastInto, - i64: CastInto, u32: CastInto, - u64: CastInto, - u64: CastInto>, + u128: CastInto>, { - const NUMBER_OF_HALF_ITERATIONS: usize = 3; - const NUMBER_OF_FULL_ITERATIONS: usize = 1; - const USE_NATIVE_FULL_ITERATIONS: bool = false; - let one = F::Int::ONE; let zero = F::Int::ZERO; + let one_hw = HalfRep::::ONE; + let zero_hw = HalfRep::::ZERO; let hw = F::BITS / 2; let lo_mask = F::Int::MAX >> hw; let significand_bits = F::SIGNIFICAND_BITS; - let max_exponent = F::EXPONENT_MAX; + // Saturated exponent, representing infinity + let exponent_sat: F::Int = F::EXPONENT_MAX.cast(); let exponent_bias = F::EXPONENT_BIAS; - let implicit_bit = F::IMPLICIT_BIT; let significand_mask = F::SIGNIFICAND_MASK; - let sign_bit = F::SIGN_MASK as F::Int; + let sign_bit = F::SIGN_MASK; let abs_mask = sign_bit - one; let exponent_mask = F::EXPONENT_MASK; let inf_rep = exponent_mask; let quiet_bit = implicit_bit >> 1; let qnan_rep = exponent_mask | quiet_bit; + let (mut half_iterations, full_iterations) = get_iterations::(); + let recip_precision = reciprocal_precision::(); - #[inline(always)] - fn negate_u64(a: u64) -> u64 { - (::wrapping_neg(a as i64)) as u64 + if F::BITS == 128 { + // FIXME(tgross35): f128 seems to require one more half iteration than expected + half_iterations += 1; } let a_rep = a.repr(); let b_rep = b.repr(); - let a_exponent = (a_rep >> significand_bits) & max_exponent.cast(); - let b_exponent = (b_rep >> significand_bits) & max_exponent.cast(); + // Exponent numeric representationm not accounting for bias + let a_exponent = (a_rep >> significand_bits) & exponent_sat; + let b_exponent = (b_rep >> significand_bits) & exponent_sat; let quotient_sign = (a_rep ^ b_rep) & sign_bit; let mut a_significand = a_rep & significand_mask; let mut b_significand = b_rep & significand_mask; - let mut scale = 0; + + // The exponent of our final result in its encoded form + let mut res_exponent: i32 = + i32::cast_from(a_exponent) - i32::cast_from(b_exponent) + (exponent_bias as i32); // Detect if a or b is zero, denormal, infinity, or NaN. - if a_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() - || b_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + if a_exponent.wrapping_sub(one) >= (exponent_sat - one) + || b_exponent.wrapping_sub(one) >= (exponent_sat - one) { let a_abs = a_rep & abs_mask; let b_abs = b_rep & abs_mask; @@ -521,6 +152,7 @@ where if a_abs > inf_rep { return F::from_repr(a_rep | quiet_bit); } + // anything / NaN = qNaN if b_abs > inf_rep { return F::from_repr(b_rep | quiet_bit); @@ -556,34 +188,31 @@ where return F::from_repr(inf_rep | quotient_sign); } - // one or both of a or b is denormal, the other (if applicable) is a - // normal number. Renormalize one or both of a and b, and set scale to - // include the necessary exponent adjustment. + // a is denormal. Renormalize it and set the scale to include the necessary exponent + // adjustment. if a_abs < implicit_bit { let (exponent, significand) = F::normalize(a_significand); - scale += exponent; + res_exponent += exponent; a_significand = significand; } + // b is denormal. Renormalize it and set the scale to include the necessary exponent + // adjustment. if b_abs < implicit_bit { let (exponent, significand) = F::normalize(b_significand); - scale -= exponent; + res_exponent -= exponent; b_significand = significand; } } - // Set the implicit significand bit. If we fell through from the + // Set the implicit significand bit. If we fell through from the // denormal path it was already set by normalize( ), but setting it twice // won't hurt anything. a_significand |= implicit_bit; b_significand |= implicit_bit; - let written_exponent: i64 = CastInto::::cast( - a_exponent - .wrapping_sub(b_exponent) - .wrapping_add(scale.cast()), - ) - .wrapping_add(exponent_bias as u64) as i64; + // Transform to a fixed-point representation by shifting the significand to the high bits. We + // know this is in the range [1.0, 2.0] since the implicit bit is set to 1 above. let b_uq1 = b_significand << (F::BITS - significand_bits - 1); // Align the significand of b as a UQ1.(n-1) fixed-point number in the range @@ -593,7 +222,7 @@ where // abs(x0(b) - 1/b) <= abs(x0(1) - 1/1) = 3/4 - 1/sqrt(2) = 0.04289..., // which is about 4.5 bits. // The initial approximation is between x0(1.0) = 0.9571... and x0(2.0) = 0.4571... - + // // Then, refine the reciprocal estimate using a quadratically converging // Newton-Raphson iteration: // x_{n+1} = x_n * (2 - x_n * b) @@ -613,123 +242,116 @@ where // abs(E_n) <= abs(e_n) + (1/b_hw - 1/b) // = abs(e_n) + (b - b_hw) / (b*b_hw) // <= abs(e_n) + 2 * 2^-HW - + // // rep_t-sized iterations may be slower than the corresponding half-width // variant depending on the handware and whether single/double/quad precision // is selected. + // // NB: Using half-width iterations increases computation errors due to // rounding, so error estimations have to be computed taking the selected // mode into account! - - let mut x_uq0 = if NUMBER_OF_HALF_ITERATIONS > 0 { + let mut x_uq0 = if half_iterations > 0 { // Starting with (n-1) half-width iterations - let b_uq1_hw: HalfRep = CastInto::>::cast( - CastInto::::cast(b_significand) >> (significand_bits + 1 - hw), - ); + let b_uq1_hw: HalfRep = b_uq1.hi(); // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW // with W0 being either 16 or 32 and W0 <= HW. // That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from which // b/2 is subtracted to obtain x0) wrapped to [0, 1) range. + let c_hw = c_hw::(); - // HW is at least 32. Shifting into the highest bits if needed. - let c_hw = (CastInto::>::cast(0x7504F333_u64)).wrapping_shl(hw.wrapping_sub(32)); + // Check that the top bit is set, i.e. value is within `[1, 2)`. + debug_assert!(b_uq1_hw & one_hw << (HalfRep::::BITS - 1) > zero_hw); // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, // so x0 fits to UQ0.HW without wrapping. - let x_uq0_hw: HalfRep = { - let mut x_uq0_hw: HalfRep = - c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); - // dbg!(x_uq0_hw); - // An e_0 error is comprised of errors due to - // * x0 being an inherently imprecise first approximation of 1/b_hw - // * C_hw being some (irrational) number **truncated** to W0 bits - // Please note that e_0 is calculated against the infinitely precise - // reciprocal of b_hw (that is, **truncated** version of b). - // - // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0 - - // By construction, 1 <= b < 2 - // f(x) = x * (2 - b*x) = 2*x - b*x^2 - // f'(x) = 2 * (1 - b*x) + let mut x_uq0_hw: HalfRep = + c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); + + // An e_0 error is comprised of errors due to + // * x0 being an inherently imprecise first approximation of 1/b_hw + // * C_hw being some (irrational) number **truncated** to W0 bits + // Please note that e_0 is calculated against the infinitely precise + // reciprocal of b_hw (that is, **truncated** version of b). + // + // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0 + // + // By construction, 1 <= b < 2 + // f(x) = x * (2 - b*x) = 2*x - b*x^2 + // f'(x) = 2 * (1 - b*x) + // + // On the [0, 1] interval, f(0) = 0, + // then it increses until f(1/b) = 1 / b, maximum on (0, 1), + // then it decreses to f(1) = 2 - b + // + // Let g(x) = x - f(x) = b*x^2 - x. + // On (0, 1/b), g(x) < 0 <=> f(x) > x + // On (1/b, 1], g(x) > 0 <=> f(x) < x + // + // For half-width iterations, b_hw is used instead of b. + for _ in 0..half_iterations { + // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp + // of corr_UQ1_hw. + // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1). + // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided + // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is + // expected to be strictly positive because b_UQ1_hw has its highest bit set + // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). // - // On the [0, 1] interval, f(0) = 0, - // then it increses until f(1/b) = 1 / b, maximum on (0, 1), - // then it decreses to f(1) = 2 - b + // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally + // obtaining an UQ1.(HW-1) number and proving its highest bit could be + // considered to be 0 to be able to represent it in UQ0.HW. + // From the above analysis of f(x), if corr_UQ1_hw would be represented + // without any intermediate loss of precision (that is, in twice_rep_t) + // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly + // less otherwise. On the other hand, to obtain [1.]000..., one have to pass + // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due + // to 1.0 being not representable as UQ0.HW). + // The fact corr_UQ1_hw was virtually round up (due to result of + // multiplication being **first** truncated, then negated - to improve + // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. // - // Let g(x) = x - f(x) = b*x^2 - x. - // On (0, 1/b), g(x) < 0 <=> f(x) > x - // On (1/b, 1], g(x) > 0 <=> f(x) < x + // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t + // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after + // any number of iterations, so just subtract 2 from the reciprocal + // approximation after last iteration. // - // For half-width iterations, b_hw is used instead of b. - for _ in 0..NUMBER_OF_HALF_ITERATIONS { - // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp - // of corr_UQ1_hw. - // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1). - // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided - // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is - // expected to be strictly positive because b_UQ1_hw has its highest bit set - // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). - let corr_uq1_hw: HalfRep = CastInto::>::cast(zero.wrapping_sub( - ((F::Int::from(x_uq0_hw)).wrapping_mul(F::Int::from(b_uq1_hw))) >> hw, - )); - // dbg!(corr_uq1_hw); - - // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally - // obtaining an UQ1.(HW-1) number and proving its highest bit could be - // considered to be 0 to be able to represent it in UQ0.HW. - // From the above analysis of f(x), if corr_UQ1_hw would be represented - // without any intermediate loss of precision (that is, in twice_rep_t) - // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly - // less otherwise. On the other hand, to obtain [1.]000..., one have to pass - // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due - // to 1.0 being not representable as UQ0.HW). - // The fact corr_UQ1_hw was virtually round up (due to result of - // multiplication being **first** truncated, then negated - to improve - // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. - x_uq0_hw = ((F::Int::from(x_uq0_hw)).wrapping_mul(F::Int::from(corr_uq1_hw)) - >> (hw - 1)) - .cast(); - // dbg!(x_uq0_hw); - // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t - // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after - // any number of iterations, so just subtract 2 from the reciprocal - // approximation after last iteration. - - // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW: - // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1 - // = 1 - e_n * b_hw + 2*eps1 - // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2 - // = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2 - // = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2 - // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2 - // = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw - // \------ >0 -------/ \-- >0 ---/ - // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U) - } - // For initial half-width iterations, U = 2^-HW - // Let abs(e_n) <= u_n * U, - // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U) - // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2) - - // Account for possible overflow (see above). For an overflow to occur for the - // first time, for "ideal" corr_UQ1_hw (that is, without intermediate - // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum - // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to - // be not below that value (see g(x) above), so it is safe to decrement just - // once after the final iteration. On the other hand, an effective value of - // divisor changes after this point (from b_hw to b), so adjust here. - x_uq0_hw.wrapping_sub(HalfRep::::ONE) - }; + // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW: + // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1 + // = 1 - e_n * b_hw + 2*eps1 + // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2 + // = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2 + // = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw + // \------ >0 -------/ \-- >0 ---/ + // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U) + x_uq0_hw = next_guess(x_uq0_hw, b_uq1_hw); + } + + // For initial half-width iterations, U = 2^-HW + // Let abs(e_n) <= u_n * U, + // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U) + // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2) + // + // Account for possible overflow (see above). For an overflow to occur for the + // first time, for "ideal" corr_UQ1_hw (that is, without intermediate + // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum + // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to + // be not below that value (see g(x) above), so it is safe to decrement just + // once after the final iteration. On the other hand, an effective value of + // divisor changes after this point (from b_hw to b), so adjust here. + x_uq0_hw = x_uq0_hw.wrapping_sub(one_hw); // Error estimations for full-precision iterations are calculated just // as above, but with U := 2^-W and taking extra decrementing into account. // We need at least one such iteration. - + // // Simulating operations on a twice_rep_t to perform a single final full-width // iteration. Using ad-hoc multiplication implementations to take advantage // of particular structure of operands. let blo: F::Int = b_uq1 & lo_mask; + // x_UQ0 = x_UQ0_hw * 2^HW - 1 // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1 // @@ -742,16 +364,19 @@ where + ((F::Int::from(x_uq0_hw) * blo) >> hw)) .wrapping_sub(one) .wrapping_neg(); // account for *possible* carry + let lo_corr: F::Int = corr_uq1 & lo_mask; let hi_corr: F::Int = corr_uq1 >> hw; + // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1 let mut x_uq0: F::Int = ((F::Int::from(x_uq0_hw) * hi_corr) << 1) .wrapping_add((F::Int::from(x_uq0_hw) * lo_corr) >> (hw - 1)) + // 1 to account for the highest bit of corr_UQ1 can be 1 + // 1 to account for possible carry + // Just like the case of half-width iterations but with possibility + // of overflowing by one extra Ulp of x_UQ0. .wrapping_sub(F::Int::from(2u8)); - // 1 to account for the highest bit of corr_UQ1 can be 1 - // 1 to account for possible carry - // Just like the case of half-width iterations but with possibility - // of overflowing by one extra Ulp of x_UQ0. + x_uq0 -= one; // ... and then traditional fixup by 2 should work @@ -759,7 +384,7 @@ where // abs(E_{N-1}) <= (u_{N-1} + 2 /* due to conversion e_n -> E_n */) * 2^-HW // + (2^-HW + 2^-W)) // abs(E_{N-1}) <= (u_{N-1} + 3.01) * 2^-HW - + // // Then like for the half-width iterations: // With 0 <= eps1, eps2 < 2^-W // E_N = 4 * E_{N-1} * eps1 - (E_{N-1}^2 * b + 4 * eps2) + 4 * eps1 / b @@ -768,89 +393,54 @@ where x_uq0 } else { // C is (3/4 + 1/sqrt(2)) - 1 truncated to 64 fractional bits as UQ0.n - let c: F::Int = (0x7504F333 << (F::BITS - 32)).cast(); - let x_uq0: F::Int = c.wrapping_sub(b_uq1); - // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-64 - x_uq0 - }; + let c: F::Int = F::Int::from(0x7504F333u32) << (F::BITS - 32); + let mut x_uq0: F::Int = c.wrapping_sub(b_uq1); - let mut x_uq0 = if USE_NATIVE_FULL_ITERATIONS { - for _ in 0..NUMBER_OF_FULL_ITERATIONS { - let corr_uq1: u64 = 0.wrapping_sub( - (CastInto::::cast(x_uq0) * (CastInto::::cast(b_uq1))) >> F::BITS, - ); - x_uq0 = ((((CastInto::::cast(x_uq0) as u128) * (corr_uq1 as u128)) - >> (F::BITS - 1)) as u64) - .cast(); + // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-64 + // x_uq0 + for _ in 0..full_iterations { + x_uq0 = next_guess(x_uq0, b_uq1); } - x_uq0 - } else { - // not using native full iterations + x_uq0 }; // Finally, account for possible overflow, as explained above. x_uq0 = x_uq0.wrapping_sub(2.cast()); - // u_n for different precisions (with N-1 half-width iterations): - // W0 is the precision of C - // u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW - - // Estimated with bc: - // define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; } - // define half2(un) { return 2.0 * un / 2.0^hw + 2.0; } - // define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; } - // define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; } - - // | f32 (0 + 3) | f32 (2 + 1) | f64 (3 + 1) | f128 (4 + 1) - // u_0 | < 184224974 | < 2812.1 | < 184224974 | < 791240234244348797 - // u_1 | < 15804007 | < 242.7 | < 15804007 | < 67877681371350440 - // u_2 | < 116308 | < 2.81 | < 116308 | < 499533100252317 - // u_3 | < 7.31 | | < 7.31 | < 27054456580 - // u_4 | | | | < 80.4 - // Final (U_N) | same as u_3 | < 72 | < 218 | < 13920 - - // Add 2 to U_N due to final decrement. - - let reciprocal_precision: ::Int = 220.cast(); - // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W - let x_uq0 = x_uq0 - reciprocal_precision; + x_uq0 -= recip_precision.cast(); + // Now 1/b - (2*P) * 2^-W < x < 1/b // FIXME Is x_UQ0 still >= 0.5? - let mut quotient: F::Int = x_uq0.widen_mul(a_significand << 1).hi(); + let mut quotient_uq1: F::Int = x_uq0.widen_mul(a_significand << 1).hi(); // Now, a/b - 4*P * 2^-W < q < a/b for q= in UQ1.(SB+1+W). // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1), // adjust it to be in [1.0, 2.0) as UQ1.SB. - let (mut residual, written_exponent) = if quotient < (implicit_bit << 1) { + let mut residual_lo = if quotient_uq1 < (implicit_bit << 1) { // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB, // effectively doubling its value as well as its error estimation. - let residual_lo = (a_significand << (significand_bits + 1)).wrapping_sub( - (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) - .cast(), - ); + let residual_lo = (a_significand << (significand_bits + 1)) + .wrapping_sub(quotient_uq1.wrapping_mul(b_significand)); + res_exponent -= 1; a_significand <<= 1; - (residual_lo, written_exponent.wrapping_sub(1)) + residual_lo } else { // Highest bit is 1 (the UQ1.(SB+1) value is in [1, 2)), convert it // to UQ1.SB by right shifting by 1. Least significant bit is omitted. - quotient >>= 1; - let residual_lo = (a_significand << significand_bits).wrapping_sub( - (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) - .cast(), - ); - (residual_lo, written_exponent) + quotient_uq1 >>= 1; + (a_significand << significand_bits).wrapping_sub(quotient_uq1.wrapping_mul(b_significand)) }; - //drop mutability - let quotient = quotient; + // drop mutability + let quotient = quotient_uq1; // NB: residualLo is calculated above for the normal result case. // It is re-computed on denormal path that is expected to be not so // performance-sensitive. - + // // Now, q cannot be greater than a/b and can differ by at most 8*P * 2^-W + 2^-SB // Each NextAfter() increments the floating point value by at least 2^-SB // (more, if exponent was incremented). @@ -870,60 +460,161 @@ where // For f32 (2+1): 32 < 74 < 32 * 3, so two NextAfter() are required // For f64: 220 < 256 (OK) // For f128: 4096 * 3 < 13922 < 4096 * 5 (three NextAfter() are required) - + // // If we have overflowed the exponent, return infinity - if written_exponent >= max_exponent as i64 { + if res_exponent >= i32::cast_from(exponent_sat) { return F::from_repr(inf_rep | quotient_sign); } // Now, quotient <= the correctly-rounded result // and may need taking NextAfter() up to 3 times (see error estimates above) // r = a - b * q - let abs_result = if written_exponent > 0 { + let mut abs_result = if res_exponent > 0 { let mut ret = quotient & significand_mask; - ret |= written_exponent.cast() << significand_bits; - residual <<= 1; + ret |= F::Int::from(res_exponent as u32) << significand_bits; + residual_lo <<= 1; ret } else { - if (significand_bits as i64 + written_exponent) < 0 { + if ((significand_bits as i32) + res_exponent) < 0 { return F::from_repr(quotient_sign); } - let ret = - quotient.wrapping_shr((negate_u64(CastInto::::cast(written_exponent)) + 1) as u32); - residual = (CastInto::::cast( - a_significand.wrapping_shl( - significand_bits.wrapping_add(CastInto::::cast(written_exponent)), - ), - ) - .wrapping_sub( - (CastInto::::cast(ret).wrapping_mul(CastInto::::cast(b_significand))) << 1, - )) - .cast(); + + let ret = quotient.wrapping_shr(u32::cast_from(res_exponent.wrapping_neg()) + 1); + residual_lo = a_significand + .wrapping_shl(significand_bits.wrapping_add(CastInto::::cast(res_exponent))) + .wrapping_sub(ret.wrapping_mul(b_significand) << 1); ret }; - // Round - let abs_result = { - residual += abs_result & one; // tie to even - // conditionally turns the below LT comparison into LTE - if residual > b_significand { - abs_result + one - } else { - abs_result - } - }; + + residual_lo += abs_result & one; // tie to even + // conditionally turns the below LT comparison into LTE + abs_result += u8::from(residual_lo > b_significand).into(); + + if F::BITS == 128 || (F::BITS == 32 && half_iterations > 0) { + // Do not round Infinity to NaN + abs_result += + u8::from(abs_result < inf_rep && residual_lo > (2 + 1).cast() * b_significand).into(); + } + + if F::BITS == 128 { + abs_result += + u8::from(abs_result < inf_rep && residual_lo > (4 + 1).cast() * b_significand).into(); + } + F::from_repr(abs_result | quotient_sign) } +/// Calculate the number of iterations required for a float type's precision. +/// +/// This returns `(h, f)` where `h` is the number of iterations to be done using integers at half +/// the float's bit width, and `f` is the number of iterations done using integers of the float's +/// full width. This is further explained in the module documentation. +/// +/// # Requirements +/// +/// The initial estimate should have at least 8 bits of precision. If this is not true, results +/// will be inaccurate. +const fn get_iterations() -> (usize, usize) { + // Precision doubles with each iteration. Assume we start with 8 bits of precision. + let total_iterations = F::BITS.ilog2() as usize - 2; + + if 2 * size_of::() <= size_of::<*const ()>() { + // If widening multiplication will be efficient (uses word-sized integers), there is no + // reason to use half-sized iterations. + (0, total_iterations) + } else { + // Otherwise, do as many iterations as possible at half width. + (total_iterations - 1, 1) + } +} + +/// `u_n` for different precisions (with N-1 half-width iterations). +/// +/// W0 is the precision of C +/// u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW +/// +/// Estimated with bc: +/// +/// ```text +/// define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; } +/// define half2(un) { return 2.0 * un / 2.0^hw + 2.0; } +/// define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; } +/// define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; } +/// +/// | f32 (0 + 3) | f32 (2 + 1) | f64 (3 + 1) | f128 (4 + 1) +/// u_0 | < 184224974 | < 2812.1 | < 184224974 | < 791240234244348797 +/// u_1 | < 15804007 | < 242.7 | < 15804007 | < 67877681371350440 +/// u_2 | < 116308 | < 2.81 | < 116308 | < 499533100252317 +/// u_3 | < 7.31 | | < 7.31 | < 27054456580 +/// u_4 | | | | < 80.4 +/// Final (U_N) | same as u_3 | < 72 | < 218 | < 13920 +/// ```` +/// +/// Add 2 to `U_N` due to final decrement. +const fn reciprocal_precision() -> u16 { + let (half_iterations, full_iterations) = get_iterations::(); + + if full_iterations < 1 { + panic!("Must have at least one full iteration"); + } + + // FIXME(tgross35): calculate this programmatically + if F::BITS == 32 && half_iterations == 2 && full_iterations == 1 { + 74u16 + } else if F::BITS == 32 && half_iterations == 0 && full_iterations == 3 { + 10 + } else if F::BITS == 64 && half_iterations == 3 && full_iterations == 1 { + 220 + } else if F::BITS == 128 && half_iterations == 4 && full_iterations == 1 { + 13922 + } else { + panic!("Invalid number of iterations") + } +} + +/// The value of `C` adjusted to half width. +/// +/// C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW with W0 being either +/// 16 or 32 and W0 <= HW. That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from +/// which b/2 is subtracted to obtain x0) wrapped to [0, 1) range. +fn c_hw() -> HalfRep +where + F::Int: DInt, + u128: CastInto>, +{ + const C_U128: u128 = 0x7504f333f9de6108b2fb1366eaa6a542; + const { C_U128 >> (u128::BITS - >::BITS) }.cast() +} + +/// Perform one iteration at any width to approach `1/b`, given previous guess `x`. Returns +/// the next `x` as a UQ0 number. +/// +/// This is the `x_{n+1} = 2*x_n - b*x_n^2` algorithm, implemented as `x_n * (2 - b*x_n)`. It +/// uses widening multiplication to calculate the result with necessary precision. +fn next_guess(x_uq0: I, b_uq1: I) -> I +where + I: Int + HInt, + ::D: ops::Shr::D>, +{ + // `corr = 2 - b*x_n` + // + // This looks like `0 - b*x_n`. However, this works - in `UQ1`, `0.0 - x = 2.0 - x`. + let corr_uq1: I = I::ZERO.wrapping_sub(x_uq0.widen_mul(b_uq1).hi()); + + // `x_n * corr = x_n * (2 - b*x_n)` + (x_uq0.widen_mul(corr_uq1) >> (I::BITS - 1)).lo() +} + intrinsics! { #[avr_skip] #[arm_aeabi_alias = __aeabi_fdiv] pub extern "C" fn __divsf3(a: f32, b: f32) -> f32 { - div32(a, b) + div(a, b) } #[avr_skip] #[arm_aeabi_alias = __aeabi_ddiv] pub extern "C" fn __divdf3(a: f64, b: f64) -> f64 { - div64(a, b) + div(a, b) } } diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index 418e9c18937..2de61c707d8 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -115,7 +115,13 @@ macro_rules! float { fuzz_float_2(N, |x: $f, y: $f| { let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y); let quo1: $f = $fn(x, y); - #[cfg(not(target_arch = "arm"))] + + // ARM SIMD instructions always flush subnormals to zero + if cfg!(target_arch = "arm") && + ((Float::is_subnormal(quo0)) || Float::is_subnormal(quo1)) { + return; + } + if !Float::eq_repr(quo0, quo1) { panic!( "{}({:?}, {:?}): std: {:?}, builtins: {:?}", @@ -126,21 +132,6 @@ macro_rules! float { quo1 ); } - - // ARM SIMD instructions always flush subnormals to zero - #[cfg(target_arch = "arm")] - if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) { - if !Float::eq_repr(quo0, quo1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), - x, - y, - quo0, - quo1 - ); - } - } }); } )* -- cgit 1.4.1-3-g733a5 From 764a177497f9cb27d788e5734b775053187607ac Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 15:46:05 -0500 Subject: Add `f128` division Use the new generic division algorithm to expose `__divtf3` and `__divkf3`. --- library/compiler-builtins/README.md | 2 +- library/compiler-builtins/build.rs | 1 - library/compiler-builtins/examples/intrinsics.rs | 5 +++++ library/compiler-builtins/src/float/div.rs | 17 +++++++++++++++++ library/compiler-builtins/testcrate/tests/div_rem.rs | 16 ++++++++++++++++ 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 46983a281eb..06137f3c754 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -222,7 +222,7 @@ of being added to Rust. - [x] addtf3.c - [x] comparetf2.c -- [ ] divtf3.c +- [x] divtf3.c - [x] extenddftf2.c - [x] extendhfsf2.c - [x] extendhftf2.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 5ccff76e7c5..3b2805f8328 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -526,7 +526,6 @@ mod c { ("__floatsitf", "floatsitf.c"), ("__floatunditf", "floatunditf.c"), ("__floatunsitf", "floatunsitf.c"), - ("__divtf3", "divtf3.c"), ("__powitf2", "powitf2.c"), ("__fe_getround", "fp_mode.c"), ("__fe_raise_inexact", "fp_mode.c"), diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 8bb70767376..6dcd3820f0d 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -256,6 +256,10 @@ mod intrinsics { a * b } + pub fn divtf(a: f128, b: f128) -> f128 { + a / b + } + pub fn subtf(a: f128, b: f128) -> f128 { a - b } @@ -440,6 +444,7 @@ fn run() { bb(aeabi_uldivmod(bb(2), bb(3))); bb(ashlti3(bb(2), bb(2))); bb(ashrti3(bb(2), bb(2))); + bb(divtf(bb(2.), bb(2.))); bb(divti3(bb(2), bb(2))); bb(eqtf(bb(2.), bb(2.))); bb(extendhfdf(bb(2.))); diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 4aec3418f4b..f085455fa3e 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -617,4 +617,21 @@ intrinsics! { pub extern "C" fn __divdf3(a: f64, b: f64) -> f64 { div(a, b) } + + #[avr_skip] + #[ppc_alias = __divkf3] + #[cfg(not(feature = "no-f16-f128"))] + pub extern "C" fn __divtf3(a: f128, b: f128) -> f128 { + div(a, b) + } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __divsf3vfp(a: f32, b: f32) -> f32 { + a / b + } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __divdf3vfp(a: f64, b: f64) -> f64 { + a / b + } } diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index 2de61c707d8..ac87eb6302b 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -1,3 +1,4 @@ +#![feature(f128)] #![allow(unused_macros)] use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; @@ -146,4 +147,19 @@ mod float_div { f32, __divsf3, Single, all(); f64, __divdf3, Double, all(); } + + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + float! { + f128, __divtf3, Quad, + // FIXME(llvm): there is a bug in LLVM rt. + // See . + not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux"))); + } + + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + float! { + f128, __divkf3, Quad, not(feature = "no-sys-f128"); + } } -- cgit 1.4.1-3-g733a5 From 4842bd6ab10b0d99c9e12c96490089e6edf4a3c8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 15:46:40 -0500 Subject: Add benchmarks for `f128` division --- .../testcrate/benches/float_div.rs | 29 ++++++++++++++++++++-- library/compiler-builtins/testcrate/src/bench.rs | 7 +++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/testcrate/benches/float_div.rs b/library/compiler-builtins/testcrate/benches/float_div.rs index 6ba439b0420..6a039a82a93 100644 --- a/library/compiler-builtins/testcrate/benches/float_div.rs +++ b/library/compiler-builtins/testcrate/benches/float_div.rs @@ -1,5 +1,7 @@ +#![cfg_attr(f128_enabled, feature(f128))] + use compiler_builtins::float::div; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; float_bench! { @@ -64,5 +66,28 @@ float_bench! { ], } -criterion_group!(float_div, div_f32, div_f64); +#[cfg(f128_enabled)] +float_bench! { + name: div_f128, + sig: (a: f128, b: f128) -> f128, + crate_fn: div::__divtf3, + crate_fn_ppc: div::__divkf3, + sys_fn: __divtf3, + sys_fn_ppc: __divkf3, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +pub fn float_div() { + let mut criterion = Criterion::default().configure_from_args(); + + div_f32(&mut criterion); + div_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + div_f128(&mut criterion); + } +} + criterion_main!(float_div); diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs index 1d571a6cf3b..f831b5a6655 100644 --- a/library/compiler-builtins/testcrate/src/bench.rs +++ b/library/compiler-builtins/testcrate/src/bench.rs @@ -30,13 +30,14 @@ pub fn skip_sys_checks(test_name: &str) -> bool { // FIXME(f16_f128): system symbols have incorrect results // - const X86_NO_SSE_SKIPPED: &[&str] = - &["add_f128", "sub_f128", "mul_f128", "powi_f32", "powi_f64"]; + const X86_NO_SSE_SKIPPED: &[&str] = &[ + "add_f128", "sub_f128", "mul_f128", "div_f128", "powi_f32", "powi_f64", + ]; // FIXME(f16_f128): Wide multiply carry bug in `compiler-rt`, re-enable when nightly no longer // uses `compiler-rt` version. // - const AARCH64_SKIPPED: &[&str] = &["mul_f128"]; + const AARCH64_SKIPPED: &[&str] = &["mul_f128", "div_f128"]; // FIXME(llvm): system symbols have incorrect results on Windows // -- cgit 1.4.1-3-g733a5 From d6d29197e46cea8e43e0cdfe64c60027278dba10 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 16:40:44 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 1aa6e5668d9..fa89c152e5b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.126" +version = "0.1.127" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 70d74bb7a431a19c2d20d2cdf100da789ab877df Mon Sep 17 00:00:00 2001 From: Artyom Tetyukhin <51746822+arttet@users.noreply.github.com> Date: Wed, 25 Sep 2024 18:21:36 +0400 Subject: Bump cc dependency --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index fa89c152e5b..86cddd24d6e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -34,7 +34,7 @@ test = false core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } [build-dependencies] -cc = { optional = true, version = "1.0" } +cc = { optional = true, version = "1.1" } [dev-dependencies] panic-handler = { path = 'crates/panic-handler' } -- cgit 1.4.1-3-g733a5 From 1e5bf9e1661d18059948e73d6bde54ea7a547ebf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:37:03 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 86cddd24d6e..7fd3b22300c 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.127" +version = "0.1.128" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 8c31ec9e7df736487be79280d3021ecca2ef85fa Mon Sep 17 00:00:00 2001 From: Davide Mor Date: Thu, 26 Sep 2024 15:17:47 +0200 Subject: Fixed `__divtf3` having wrong cfg for f128 --- library/compiler-builtins/src/float/div.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index f085455fa3e..f125771a017 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -620,7 +620,7 @@ intrinsics! { #[avr_skip] #[ppc_alias = __divkf3] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __divtf3(a: f128, b: f128) -> f128 { div(a, b) } -- cgit 1.4.1-3-g733a5 From 1649f72ea628d372f7c3f67f32b76d048e7d0472 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Sep 2024 07:00:19 -0400 Subject: Revert "Bump cc dependency" --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7fd3b22300c..75cebda89f9 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -34,7 +34,7 @@ test = false core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } [build-dependencies] -cc = { optional = true, version = "1.1" } +cc = { optional = true, version = "1.0" } [dev-dependencies] panic-handler = { path = 'crates/panic-handler' } -- cgit 1.4.1-3-g733a5 From c48926906a30cb858fd8e6177023db3d516dd727 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 11:08:02 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 75cebda89f9..670bcd74ad0 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.128" +version = "0.1.129" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 18b42ebb78fe378c179859136c0774e9c85da41e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Sep 2024 00:01:01 -0400 Subject: Remove unneeded features A few of the features that we enable have been stabilized, others may have been needed at some point but are no longer required. Clean this up. --- library/compiler-builtins/examples/intrinsics.rs | 2 -- library/compiler-builtins/src/lib.rs | 6 ------ library/compiler-builtins/testcrate/tests/aeabi_memclr.rs | 1 - library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs | 1 - library/compiler-builtins/testcrate/tests/aeabi_memset.rs | 1 - 5 files changed, 11 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 6dcd3820f0d..06d77233027 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -4,12 +4,10 @@ // to link due to the missing intrinsic (symbol). #![allow(unused_features)] -#![allow(stable_features)] // bench_black_box feature is stable, leaving for backcompat #![allow(internal_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] #![feature(allocator_api)] -#![feature(bench_black_box)] #![feature(f128)] #![feature(f16)] #![feature(lang_items)] diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index b85f789fdd0..dea30a3c6ac 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,18 +1,12 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] -#![cfg_attr(not(feature = "no-asm"), feature(asm))] #![feature(abi_unadjusted)] #![feature(asm_experimental_arch)] -#![cfg_attr(not(feature = "no-asm"), feature(global_asm))] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] -#![feature(core_ffi_c)] #![feature(core_intrinsics)] -#![feature(inline_const)] -#![feature(lang_items)] #![feature(linkage)] #![feature(naked_functions)] #![feature(repr_simd)] -#![feature(c_unwind)] #![cfg_attr(f16_enabled, feature(f16))] #![cfg_attr(f128_enabled, feature(f128))] #![no_builtins] diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs index 59507693988..bfd15a391aa 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs @@ -5,7 +5,6 @@ feature = "mem" ))] #![feature(compiler_builtins_lib)] -#![feature(lang_items)] #![no_std] extern crate compiler_builtins; diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs index 2d72dfbbaa6..c892c5aba0f 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs @@ -5,7 +5,6 @@ feature = "mem" ))] #![feature(compiler_builtins_lib)] -#![feature(lang_items)] #![no_std] extern crate compiler_builtins; diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs index f03729bed35..34ab3acc78c 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs @@ -5,7 +5,6 @@ feature = "mem" ))] #![feature(compiler_builtins_lib)] -#![feature(lang_items)] #![no_std] extern crate compiler_builtins; -- cgit 1.4.1-3-g733a5 From 2a32f80cdc060eb55eb2abd5a9dccc297fb31b9a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 17:31:23 -0400 Subject: Move `float_pow` tests to their own file --- .../compiler-builtins/testcrate/tests/float_pow.rs | 54 +++++++++++++++++++++ library/compiler-builtins/testcrate/tests/misc.rs | 56 ---------------------- 2 files changed, 54 insertions(+), 56 deletions(-) create mode 100644 library/compiler-builtins/testcrate/tests/float_pow.rs diff --git a/library/compiler-builtins/testcrate/tests/float_pow.rs b/library/compiler-builtins/testcrate/tests/float_pow.rs new file mode 100644 index 00000000000..761a6611dda --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/float_pow.rs @@ -0,0 +1,54 @@ +#![allow(unused_macros)] +#![cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] + +use testcrate::*; + +// This is approximate because of issues related to +// https://github.com/rust-lang/rust/issues/73920. +// TODO how do we resolve this indeterminacy? +macro_rules! pow { + ($($f:ty, $tolerance:expr, $fn:ident);*;) => { + $( + #[test] + fn $fn() { + use compiler_builtins::float::pow::$fn; + use compiler_builtins::float::Float; + fuzz_float_2(N, |x: $f, y: $f| { + if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) { + let n = y.to_bits() & !<$f as Float>::SIGNIFICAND_MASK; + let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS; + let n = n as i32; + let tmp0: $f = x.powi(n); + let tmp1: $f = $fn(x, n); + let (a, b) = if tmp0 < tmp1 { + (tmp0, tmp1) + } else { + (tmp1, tmp0) + }; + + let good = if a == b { + // handles infinity equality + true + } else if a < $tolerance { + b < $tolerance + } else { + let quo = b / a; + (quo < (1. + $tolerance)) && (quo > (1. - $tolerance)) + }; + + assert!( + good, + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), x, n, tmp0, tmp1 + ); + } + }); + } + )* + }; +} + +pow! { + f32, 1e-4, __powisf2; + f64, 1e-12, __powidf2; +} diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index f9431915b15..f5ac2ab7da1 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -207,59 +207,3 @@ fn bswap() { ); } } - -// This is approximate because of issues related to -// https://github.com/rust-lang/rust/issues/73920. -// TODO how do we resolve this indeterminacy? -macro_rules! pow { - ($($f:ty, $tolerance:expr, $fn:ident);*;) => { - $( - #[test] - fn $fn() { - use compiler_builtins::float::pow::$fn; - use compiler_builtins::float::Float; - fuzz_float_2(N, |x: $f, y: $f| { - if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) { - let n = y.to_bits() & !<$f as Float>::SIGNIFICAND_MASK; - let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS; - let n = n as i32; - let tmp0: $f = x.powi(n); - let tmp1: $f = $fn(x, n); - let (a, b) = if tmp0 < tmp1 { - (tmp0, tmp1) - } else { - (tmp1, tmp0) - }; - let good = { - if a == b { - // handles infinity equality - true - } else if a < $tolerance { - b < $tolerance - } else { - let quo = b / a; - (quo < (1. + $tolerance)) && (quo > (1. - $tolerance)) - } - }; - if !good { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, n, tmp0, tmp1 - ); - } - } - }); - } - )* - }; -} - -#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -mod float_pow { - use super::*; - - pow! { - f32, 1e-4, __powisf2; - f64, 1e-12, __powidf2; - } -} -- cgit 1.4.1-3-g733a5 From 606d971958936c77245d77b0ebd0cf09a2d461c2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 17:32:42 -0400 Subject: Add support for `f128` integer exponentiation Create the symbol `__powitf2`. --- library/compiler-builtins/README.md | 2 +- library/compiler-builtins/build.rs | 1 - library/compiler-builtins/src/float/pow.rs | 9 ++++++++ .../compiler-builtins/testcrate/tests/float_pow.rs | 24 +++++++++++++++++++--- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 06137f3c754..985020f5a8f 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -240,7 +240,7 @@ of being added to Rust. - [ ] floatunsitf.c - [ ] floatuntitf.c - [x] multf3.c -- [ ] powitf2.c +- [x] powitf2.c - [x] subtf3.c - [x] truncdfhf2.c - [x] truncsfhf2.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 3b2805f8328..df98688d16a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -526,7 +526,6 @@ mod c { ("__floatsitf", "floatsitf.c"), ("__floatunditf", "floatunditf.c"), ("__floatunsitf", "floatunsitf.c"), - ("__powitf2", "powitf2.c"), ("__fe_getround", "fp_mode.c"), ("__fe_raise_inexact", "fp_mode.c"), ]); diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 3103fe6f697..dac768f7be3 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -35,4 +35,13 @@ intrinsics! { pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 { pow(a, b) } + + #[avr_skip] + #[ppc_alias = __powikf2] + #[cfg(f128_enabled)] + // FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly. + #[cfg(not(target_env = "msvc"))] + pub extern "C" fn __powitf2(a: f128, b: i32) -> f128 { + pow(a, b) + } } diff --git a/library/compiler-builtins/testcrate/tests/float_pow.rs b/library/compiler-builtins/testcrate/tests/float_pow.rs index 761a6611dda..d85ee99dfd3 100644 --- a/library/compiler-builtins/testcrate/tests/float_pow.rs +++ b/library/compiler-builtins/testcrate/tests/float_pow.rs @@ -1,4 +1,5 @@ #![allow(unused_macros)] +#![cfg_attr(f128_enabled, feature(f128))] #![cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] use testcrate::*; @@ -7,9 +8,12 @@ use testcrate::*; // https://github.com/rust-lang/rust/issues/73920. // TODO how do we resolve this indeterminacy? macro_rules! pow { - ($($f:ty, $tolerance:expr, $fn:ident);*;) => { + ($($f:ty, $tolerance:expr, $fn:ident, $sys_available:meta);*;) => { $( #[test] + // FIXME(apfloat): We skip tests if system symbols aren't available rather + // than providing a fallback, since `rustc_apfloat` does not provide `pow`. + #[cfg($sys_available)] fn $fn() { use compiler_builtins::float::pow::$fn; use compiler_builtins::float::Float; @@ -49,6 +53,20 @@ macro_rules! pow { } pow! { - f32, 1e-4, __powisf2; - f64, 1e-12, __powidf2; + f32, 1e-4, __powisf2, all(); + f64, 1e-12, __powidf2, all(); +} + +#[cfg(f128_enabled)] +// FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly. +#[cfg(not(target_env = "msvc"))] +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] +pow! { + f128, 1e-36, __powitf2, not(feature = "no-sys-f128"); +} + +#[cfg(f128_enabled)] +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +pow! { + f128, 1e-36, __powikf2, not(feature = "no-sys-f128"); } -- cgit 1.4.1-3-g733a5 From b2db9e8e897c97acf9baf394104faf6a6b62549f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 17:37:41 -0400 Subject: Add a benchmark for `__powitf2` --- .../testcrate/benches/float_pow.rs | 31 +++++++++++++++++++--- library/compiler-builtins/testcrate/src/bench.rs | 2 ++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/testcrate/benches/float_pow.rs b/library/compiler-builtins/testcrate/benches/float_pow.rs index 252f740120d..46da3f25ceb 100644 --- a/library/compiler-builtins/testcrate/benches/float_pow.rs +++ b/library/compiler-builtins/testcrate/benches/float_pow.rs @@ -1,5 +1,7 @@ +#![cfg_attr(f128_enabled, feature(f128))] + use compiler_builtins::float::pow; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; float_bench! { @@ -20,5 +22,28 @@ float_bench! { asm: [], } -criterion_group!(float_add, powi_f32, powi_f64); -criterion_main!(float_add); +// FIXME(f16_f128): can be changed to only `f128_enabled` once `__multf3` and `__divtf3` are +// distributed by nightly. +#[cfg(all(f128_enabled, not(feature = "no-sys-f128")))] +float_bench! { + name: powi_f128, + sig: (a: f128, b: i32) -> f128, + crate_fn: pow::__powitf2, + crate_fn_ppc: pow::__powikf2, + sys_fn: __powitf2, + sys_fn_ppc: __powikf2, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +pub fn float_pow() { + let mut criterion = Criterion::default().configure_from_args(); + + powi_f32(&mut criterion); + powi_f64(&mut criterion); + + #[cfg(all(f128_enabled, not(feature = "no-sys-f128")))] + powi_f128(&mut criterion); +} + +criterion_main!(float_pow); diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs index f831b5a6655..798be6579d6 100644 --- a/library/compiler-builtins/testcrate/src/bench.rs +++ b/library/compiler-builtins/testcrate/src/bench.rs @@ -360,3 +360,5 @@ impl_testio!(int i16, i32, i64, i128); impl_testio!(int u16, u32, u64, u128); impl_testio!((float, int)(f32, i32)); impl_testio!((float, int)(f64, i32)); +#[cfg(f128_enabled)] +impl_testio!((float, int)(f128, i32)); -- cgit 1.4.1-3-g733a5 From 8a13ab7dfccc876a4442c24a4212eff9c0bbb49d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 15:13:17 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 670bcd74ad0..e84c5545e19 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.129" +version = "0.1.130" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 4ae984cbce80966be33cfc9f229e8c62e659e122 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 28 Sep 2024 17:57:06 -0400 Subject: Resolve FIXMEs related to `f16` assembly We have a couple FIXMEs from before aarch64 `f16` assembly support existed. We have this available now, so resolve the notes here. --- .../compiler-builtins/testcrate/benches/float_extend.rs | 7 ++----- library/compiler-builtins/testcrate/benches/float_trunc.rs | 14 +++++--------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/testcrate/benches/float_extend.rs b/library/compiler-builtins/testcrate/benches/float_extend.rs index a9563741a68..a0cdaf48aca 100644 --- a/library/compiler-builtins/testcrate/benches/float_extend.rs +++ b/library/compiler-builtins/testcrate/benches/float_extend.rs @@ -15,11 +15,10 @@ float_bench! { sys_available: not(feature = "no-sys-f16"), asm: [ #[cfg(target_arch = "aarch64")] { - // FIXME(f16_f128): remove `to_bits()` after f16 asm support (rust-lang/rust/#116909) let ret: f32; asm!( "fcvt {ret:s}, {a:h}", - a = in(vreg) a.to_bits(), + a = in(vreg) a, ret = lateout(vreg) ret, options(nomem, nostack, pure), ); @@ -96,9 +95,7 @@ pub fn float_extend() { extend_f16_f32(&mut criterion); #[cfg(f128_enabled)] - { - extend_f16_f128(&mut criterion); - } + extend_f16_f128(&mut criterion); } extend_f32_f64(&mut criterion); diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs index 8d874e4b2e0..de9b5bf8c0b 100644 --- a/library/compiler-builtins/testcrate/benches/float_trunc.rs +++ b/library/compiler-builtins/testcrate/benches/float_trunc.rs @@ -14,8 +14,7 @@ float_bench! { sys_available: not(feature = "no-sys-f16"), asm: [ #[cfg(target_arch = "aarch64")] { - // FIXME(f16_f128): remove `from_bits()` after f16 asm support (rust-lang/rust/#116909) - let ret: u16; + let ret: f16; asm!( "fcvt {ret:h}, {a:s}", a = in(vreg) a, @@ -23,7 +22,7 @@ float_bench! { options(nomem, nostack, pure), ); - f16::from_bits(ret) + ret }; ], } @@ -37,8 +36,7 @@ float_bench! { sys_available: not(feature = "no-sys-f16"), asm: [ #[cfg(target_arch = "aarch64")] { - // FIXME(f16_f128): remove `from_bits()` after f16 asm support (rust-lang/rust/#116909) - let ret: u16; + let ret: f16; asm!( "fcvt {ret:h}, {a:d}", a = in(vreg) a, @@ -46,7 +44,7 @@ float_bench! { options(nomem, nostack, pure), ); - f16::from_bits(ret) + ret }; ], } @@ -138,9 +136,7 @@ pub fn float_trunc() { // FIXME(#655): `f16` tests disabled until we can bootstrap symbols #[cfg(f16_enabled)] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - { - trunc_f128_f16(&mut criterion); - } + trunc_f128_f16(&mut criterion); trunc_f128_f32(&mut criterion); trunc_f128_f64(&mut criterion); -- cgit 1.4.1-3-g733a5 From e226c0dce5c610194ac1c2562318f3306b5ea742 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 28 Sep 2024 18:11:38 -0400 Subject: Ungate tests that were skipped due to a broken implementation The upstream issue [1] has been resolved so we can enable these tests again. [1]: https://github.com/rust-lang/compiler-builtins/issues/616 --- library/compiler-builtins/testcrate/src/bench.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs index 798be6579d6..f5da1f3ae50 100644 --- a/library/compiler-builtins/testcrate/src/bench.rs +++ b/library/compiler-builtins/testcrate/src/bench.rs @@ -82,12 +82,9 @@ pub fn skip_sys_checks(test_name: &str) -> bool { /// Still run benchmarks/tests but don't check correctness between compiler-builtins and /// assembly functions -pub fn skip_asm_checks(test_name: &str) -> bool { - // FIXME(f16_f128): rounding error - // - const SKIPPED: &[&str] = &["mul_f32", "mul_f64"]; - - SKIPPED.contains(&test_name) +pub fn skip_asm_checks(_test_name: &str) -> bool { + // Nothing to skip at this time + false } /// Create a comparison of the system symbol, compiler_builtins, and optionally handwritten -- cgit 1.4.1-3-g733a5 From c6b434e5a3279244c48a84e74387cbacf35a419c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 28 Sep 2024 18:19:52 -0400 Subject: Revert "Temporarily `use define_rust_probestack;`" has been resolved. Remove the workaround that was introduced to suppress it. This reverts commit 254edbcad4cfd6a8af32e3297c1037d7984c3c49. --- library/compiler-builtins/src/probestack.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 46caf167687..0c30384db38 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -120,10 +120,6 @@ macro_rules! define_rust_probestack { }; } -// FIXME(rust-lang/rust#126984): Remove allow once lint is fixed -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use define_rust_probestack; - // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, // ensuring that if any pages are unmapped we'll make a page fault. // -- cgit 1.4.1-3-g733a5 From 85cd4c06608870bb9fcb4630adc6ea9348329695 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 28 Sep 2024 19:53:09 -0400 Subject: Fix some warnings from shellcheck --- library/compiler-builtins/ci/run-docker.sh | 14 ++++++++------ library/compiler-builtins/ci/run.sh | 31 ++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 50ae9dc83a1..215ad71a3c1 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -14,7 +14,7 @@ run() { # will be owned by root mkdir -p target - if [ $(uname -s) = "Linux" ] && [ -z "${DOCKER_BASE_IMAGE:-}" ]; then + if [ "$(uname -s)" = "Linux" ] && [ -z "${DOCKER_BASE_IMAGE:-}" ]; then # Share the host rustc and target. Do this only on Linux and if the image # isn't overridden run_args=( @@ -43,19 +43,21 @@ run() { if [ "${GITHUB_ACTIONS:-}" = "true" ]; then # Enable Docker image caching on GHA - + build_cmd=("buildx" "build") build_args=( "--cache-from" "type=local,src=/tmp/.buildx-cache" "--cache-to" "type=local,dest=/tmp/.buildx-cache-new" - "${build_args[@]:-}" + # This is the beautiful bash syntax for expanding an array but neither + # raising an error nor returning an empty string if the array is empty. + "${build_args[@]:+"${build_args[@]}"}" "--load" ) fi - docker ${build_cmd[@]:-build} \ + docker "${build_cmd[@]:-build}" \ -t "builtins-$target" \ - ${build_args[@]:-} \ + "${build_args[@]:-}" \ "ci/docker/$target" docker run \ --rm \ @@ -64,7 +66,7 @@ run() { -e "CARGO_TARGET_DIR=/builtins-target" \ -v "$(pwd):/checkout:ro" \ -w /checkout \ - ${run_args[@]:-} \ + "${run_args[@]:-}" \ --init \ "builtins-$target" \ sh -c "$run_cmd" diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index dcbe1caf4ef..057cdb083f7 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -38,17 +38,24 @@ fi if [ "${TEST_VERBATIM:-}" = "1" ]; then verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\testcrate\\target2) - cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir $verb_path --features c + cargo build --manifest-path testcrate/Cargo.toml \ + --target "$target" --target-dir "$verb_path" --features c fi -if [ -d /builtins-target ]; then - rlib_paths=/builtins-target/"${target}"/debug/deps/libcompiler_builtins-*.rlib -else - rlib_paths=target/"${target}"/debug/deps/libcompiler_builtins-*.rlib -fi +declare -a rlib_paths + +# Set the `rlib_paths` global array to a list of all compiler-builtins rlibs +update_rlib_paths() { + if [ -d /builtins-target ]; then + rlib_paths=( /builtins-target/"${target}"/debug/deps/libcompiler_builtins-*.rlib ) + else + rlib_paths=( target/"${target}"/debug/deps/libcompiler_builtins-*.rlib ) + fi +} # Remove any existing artifacts from previous tests that don't set #![compiler_builtins] -rm -f $rlib_paths +update_rlib_paths +rm -f "${rlib_paths[@]}" cargo build --target "$target" cargo build --target "$target" --release @@ -76,6 +83,7 @@ NM=$(find "$(rustc --print sysroot)" \( -name llvm-nm -o -name llvm-nm.exe \) ) if [ "$NM" = "" ]; then NM="${PREFIX}nm" fi + # i686-pc-windows-gnu tools have a dependency on some DLLs, so run it with # rustup run to ensure that those are in PATH. TOOLCHAIN="$(rustup show active-toolchain | sed 's/ (default)//')" @@ -84,11 +92,13 @@ if [[ "$TOOLCHAIN" == *i686-pc-windows-gnu ]]; then fi # Look out for duplicated symbols when we include the compiler-rt (C) implementation -for rlib in $rlib_paths; do +update_rlib_paths +for rlib in "${rlib_paths[@]}"; do set +x echo "================================================================" echo "checking $rlib for duplicate symbols" echo "================================================================" + set -x duplicates_found=0 @@ -108,7 +118,7 @@ for rlib in $rlib_paths; do fi done -rm -f $rlib_paths +rm -f "${rlib_paths[@]}" build_intrinsics() { cargo build --target "$target" -v --example intrinsics "$@" @@ -128,7 +138,8 @@ CARGO_PROFILE_RELEASE_LTO=true \ cargo build --target "$target" --example intrinsics --release # Ensure no references to any symbols from core -for rlib in $(echo $rlib_paths); do +update_rlib_paths +for rlib in "${rlib_paths[@]}"; do set +x echo "================================================================" echo "checking $rlib for references to core" -- cgit 1.4.1-3-g733a5 From 0c97b10dc0034216bef6a81e02cd2b57773d387f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 2 Oct 2024 16:23:46 -0400 Subject: Add riscv64gc to CI There is a proposal to promote `riscv64gc-unknown-linux-gnu` to tier 1 [1]. We do not currently test RISC-V in CI; add it here. [1]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Imminent.20RFC.20PR.3A.20riscv64gc-unknown-linux-gnu.20to.20Tier-1 --- library/compiler-builtins/.github/workflows/main.yml | 3 +++ .../ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index fddb5973eb5..001acd2cc57 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -61,6 +61,9 @@ jobs: - target: powerpc64le-unknown-linux-gnu os: ubuntu-latest rust: nightly + - target: riscv64gc-unknown-linux-gnu + os: ubuntu-latest + rust: nightly - target: thumbv6m-none-eabi os: ubuntu-latest rust: nightly diff --git a/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..4d4a194fdc6 --- /dev/null +++ b/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-riscv64-linux-gnu libc6-dev-riscv64-cross \ + qemu-system-riscv64 + +ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER=riscv64-linux-gnu-gcc \ + CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER=qemu-riscv64-static \ + QEMU_LD_PREFIX=/usr/riscv64-linux-gnu \ + RUST_TEST_THREADS=1 -- cgit 1.4.1-3-g733a5 From edc6f80dcc83722bfbf8dcba278163fd669b86f1 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Thu, 30 May 2024 16:44:39 -0400 Subject: Build with `-Werror=implicit-function-declaration` To prevent fail-fast in situations like https://github.com/rust-lang/rust/issues/125619, where an upstream source compiles but creates a link error way downstream. --- library/compiler-builtins/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index df98688d16a..e5503e88fc3 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -327,6 +327,8 @@ mod c { // in https://github.com/rust-lang/compiler-rt/blob/c8fbcb3/cmake/config-ix.cmake#L19. cfg.flag_if_supported("-fomit-frame-pointer"); cfg.define("VISIBILITY_HIDDEN", None); + // Avoid implicitly creating references to undefined functions + cfg.flag("-Werror=implicit-function-declaration"); } // int_util.c tries to include stdlib.h if `_WIN32` is defined, -- cgit 1.4.1-3-g733a5 From 859e22b4aee859b09f636193b84ecb9d76a9161f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 15:37:33 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index e84c5545e19..835a4764922 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.130" +version = "0.1.131" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 76580a96a7573c304792631e1d3a49f9d5821551 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 2 Oct 2024 13:53:56 -0400 Subject: Upgrade CI LLVM version to 19.1 19.1 is the latest stable release from 2024-09-17. This will match what is currently being used in rust-lang/rust. --- library/compiler-builtins/.github/workflows/main.yml | 2 +- library/compiler-builtins/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 001acd2cc57..ec5c059bac0 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -4,7 +4,7 @@ on: [push, pull_request] env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings - RUST_LLVM_VERSION: 18.0-2024-02-13 + RUST_LLVM_VERSION: 19.1-2024-09-17 RUST_COMPILER_RT_ROOT: ./compiler-rt jobs: diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 985020f5a8f..f792d188324 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -89,8 +89,8 @@ to test against, located in a directory called `compiler-rt`. This can be obtained with the following: ```sh -curl -L -o rustc-llvm-18.0.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/18.0-2024-02-13.tar.gz -tar xzf rustc-llvm-18.0.tar.gz --strip-components 1 llvm-project-rustc-18.0-2024-02-13/compiler-rt +curl -L -o rustc-llvm-19.1.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/19.1-2024-09-17.tar.gz +tar xzf rustc-llvm-19.1.tar.gz --strip-components 1 llvm-project-rustc-19.1-2024-09-17/compiler-rt ``` Local targets may also be tested with `./ci/run.sh [target]`. -- cgit 1.4.1-3-g733a5 From 3f70601e3c78c4af30cb2016cb91a1d37d046460 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Fri, 4 Oct 2024 12:33:16 -0400 Subject: Allow implicit function decl on A64 Testing in , we found that is unusable with the current LLVM version. --- library/compiler-builtins/build.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e5503e88fc3..2863c979fa3 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -327,8 +327,16 @@ mod c { // in https://github.com/rust-lang/compiler-rt/blob/c8fbcb3/cmake/config-ix.cmake#L19. cfg.flag_if_supported("-fomit-frame-pointer"); cfg.define("VISIBILITY_HIDDEN", None); - // Avoid implicitly creating references to undefined functions - cfg.flag("-Werror=implicit-function-declaration"); + + if let "aarch64" | "arm64ec" = target.arch.as_str() { + // FIXME(llvm20): Older GCCs on A64 fail to build with + // -Werror=implicit-function-declaration due to a compiler-rt bug. + // With a newer LLVM we should be able to enable the flag everywhere. + // https://github.com/llvm/llvm-project/commit/8aa9d6206ce55bdaaf422839c351fbd63f033b89 + } else { + // Avoid implicitly creating references to undefined functions + cfg.flag("-Werror=implicit-function-declaration"); + } } // int_util.c tries to include stdlib.h if `_WIN32` is defined, -- cgit 1.4.1-3-g733a5 From 3edc27ef567f70a7dbcb145ebbd49f6540dce9b7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 17:17:03 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 835a4764922..d0adf744461 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.131" +version = "0.1.132" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From f59dd82cca4d5320065d60559ce259a5a30768b6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 5 Oct 2024 13:57:10 -0500 Subject: Move `musl-reference-tests` to a new `libm-test` crate There isn't any reason for this feature to be exposed or part of the build script. Move it to a separate crate. We will also want more tests that require some support functions; this will create a place for them. --- library/compiler-builtins/libm/CONTRIBUTING.md | 4 +- library/compiler-builtins/libm/Cargo.toml | 11 +- library/compiler-builtins/libm/build.rs | 452 +------------------- library/compiler-builtins/libm/ci/run.sh | 14 +- .../libm/crates/libm-test/Cargo.toml | 18 + .../libm/crates/libm-test/build.rs | 456 +++++++++++++++++++++ .../libm/crates/libm-test/src/lib.rs | 1 + .../libm/crates/libm-test/tests/musl_biteq.rs | 4 + library/compiler-builtins/libm/src/lib.rs | 5 - 9 files changed, 494 insertions(+), 471 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/Cargo.toml create mode 100644 library/compiler-builtins/libm/crates/libm-test/build.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/lib.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index 59c37a6f959..c15c45a4336 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -7,7 +7,7 @@ in `src/lib.rs`. - Write some simple tests in your module (using `#[test]`) - Run `cargo test` to make sure it works -- Run `cargo test --features musl-reference-tests` to compare your +- Run `cargo test --features libm-test/musl-reference-tests` to compare your implementation against musl's - Send us a pull request! Make sure to run `cargo fmt` on your code before sending the PR. Also include "closes #42" in the PR description to close the @@ -88,7 +88,7 @@ If you'd like to run tests with randomized inputs that get compared against musl itself, you'll need to be on a Linux system and then you can execute: ``` -cargo test --features musl-reference-tests +cargo test --features libm-test/musl-reference-tests ``` Note that you may need to pass `--release` to Cargo if there are errors related diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index c2388083b61..fc2db0c2088 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -19,10 +19,6 @@ default = [] # that it should activate any useful Nightly things accordingly. unstable = [] -# Generate tests which are random inputs and the outputs are calculated with -# musl libc. -musl-reference-tests = ['rand'] - # Used to prevent using any intrinsics or arch-specific code. force-soft-floats = [] @@ -30,13 +26,16 @@ force-soft-floats = [] members = [ "crates/compiler-builtins-smoke-test", "crates/libm-bench", + "crates/libm-test", +] +default-members = [ + ".", + "crates/libm-test", ] [dev-dependencies] no-panic = "0.1.8" -[build-dependencies] -rand = { version = "0.6.5", optional = true } # This is needed for no-panic to correctly detect the lack of panics [profile.release] diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index c9ae232607f..653ccf7993f 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -5,10 +5,8 @@ fn main() { println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\"))"); - #[cfg(feature = "musl-reference-tests")] - musl_reference_tests::generate(); - println!("cargo::rustc-check-cfg=cfg(feature, values(\"checked\"))"); + #[allow(unexpected_cfgs)] if !cfg!(feature = "checked") { let lvl = env::var("OPT_LEVEL").unwrap(); @@ -17,451 +15,3 @@ fn main() { } } } - -#[cfg(feature = "musl-reference-tests")] -mod musl_reference_tests { - use rand::seq::SliceRandom; - use rand::Rng; - use std::env; - use std::fs; - use std::process::Command; - - // Number of tests to generate for each function - const NTESTS: usize = 500; - - // These files are all internal functions or otherwise miscellaneous, not - // defining a function we want to test. - const IGNORED_FILES: &[&str] = &[ - "fenv.rs", - // These are giving slightly different results compared to musl - "lgamma.rs", - "lgammaf.rs", - "tgamma.rs", - "j0.rs", - "j0f.rs", - "jn.rs", - "jnf.rs", - "j1.rs", - "j1f.rs", - ]; - - struct Function { - name: String, - args: Vec, - ret: Vec, - tests: Vec, - } - - enum Ty { - F32, - F64, - I32, - Bool, - } - - struct Test { - inputs: Vec, - outputs: Vec, - } - - pub fn generate() { - // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 - let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - if target_arch == "powerpc64" { - return; - } - - let files = fs::read_dir("src/math") - .unwrap() - .map(|f| f.unwrap().path()) - .collect::>(); - - let mut math = Vec::new(); - for file in files { - if IGNORED_FILES.iter().any(|f| file.ends_with(f)) { - continue; - } - - println!("generating musl reference tests in {:?}", file); - - let contents = fs::read_to_string(file).unwrap(); - let mut functions = contents.lines().filter(|f| f.starts_with("pub fn")); - while let Some(function_to_test) = functions.next() { - math.push(parse(function_to_test)); - } - } - - // Generate a bunch of random inputs for each function. This will - // attempt to generate a good set of uniform test cases for exercising - // all the various functionality. - generate_random_tests(&mut math, &mut rand::thread_rng()); - - // After we have all our inputs, use the x86_64-unknown-linux-musl - // target to generate the expected output. - generate_test_outputs(&mut math); - //panic!("Boo"); - // ... and now that we have both inputs and expected outputs, do a bunch - // of codegen to create the unit tests which we'll actually execute. - generate_unit_tests(&math); - } - - /// A "poor man's" parser for the signature of a function - fn parse(s: &str) -> Function { - let s = eat(s, "pub fn "); - let pos = s.find('(').unwrap(); - let name = &s[..pos]; - let s = &s[pos + 1..]; - let end = s.find(')').unwrap(); - let args = s[..end] - .split(',') - .map(|arg| { - let colon = arg.find(':').unwrap(); - parse_ty(arg[colon + 1..].trim()) - }) - .collect::>(); - let tail = &s[end + 1..]; - let tail = eat(tail, " -> "); - let ret = parse_retty(tail.replace("{", "").trim()); - - return Function { - name: name.to_string(), - args, - ret, - tests: Vec::new(), - }; - - fn parse_ty(s: &str) -> Ty { - match s { - "f32" => Ty::F32, - "f64" => Ty::F64, - "i32" => Ty::I32, - "bool" => Ty::Bool, - other => panic!("unknown type `{}`", other), - } - } - - fn parse_retty(s: &str) -> Vec { - match s { - "(f32, f32)" => vec![Ty::F32, Ty::F32], - "(f32, i32)" => vec![Ty::F32, Ty::I32], - "(f64, f64)" => vec![Ty::F64, Ty::F64], - "(f64, i32)" => vec![Ty::F64, Ty::I32], - other => vec![parse_ty(other)], - } - } - - fn eat<'a>(s: &'a str, prefix: &str) -> &'a str { - if s.starts_with(prefix) { - &s[prefix.len()..] - } else { - panic!("{:?} didn't start with {:?}", s, prefix) - } - } - } - - fn generate_random_tests(functions: &mut [Function], rng: &mut R) { - for function in functions { - for _ in 0..NTESTS { - function.tests.push(generate_test(function, rng)); - } - } - - fn generate_test(function: &Function, rng: &mut R) -> Test { - let mut inputs = function - .args - .iter() - .map(|ty| ty.gen_i64(rng)) - .collect::>(); - - // First argument to this function appears to be a number of - // iterations, so passing in massive random numbers causes it to - // take forever to execute, so make sure we're not running random - // math code until the heat death of the universe. - if function.name == "jn" || function.name == "jnf" { - inputs[0] &= 0xffff; - } - - Test { - inputs, - // zero output for now since we'll generate it later - outputs: vec![], - } - } - } - - impl Ty { - fn gen_i64(&self, r: &mut R) -> i64 { - use std::f32; - use std::f64; - - return match self { - Ty::F32 => { - if r.gen_range(0, 20) < 1 { - let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY] - .choose(r) - .unwrap(); - i.to_bits().into() - } else { - r.gen::().to_bits().into() - } - } - Ty::F64 => { - if r.gen_range(0, 20) < 1 { - let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY] - .choose(r) - .unwrap(); - i.to_bits() as i64 - } else { - r.gen::().to_bits() as i64 - } - } - Ty::I32 => { - if r.gen_range(0, 10) < 1 { - let i = *[i32::max_value(), 0, i32::min_value()].choose(r).unwrap(); - i.into() - } else { - r.gen::().into() - } - } - Ty::Bool => r.gen::() as i64, - }; - } - - fn libc_ty(&self) -> &'static str { - match self { - Ty::F32 => "f32", - Ty::F64 => "f64", - Ty::I32 => "i32", - Ty::Bool => "i32", - } - } - - fn libc_pty(&self) -> &'static str { - match self { - Ty::F32 => "*mut f32", - Ty::F64 => "*mut f64", - Ty::I32 => "*mut i32", - Ty::Bool => "*mut i32", - } - } - - fn default(&self) -> &'static str { - match self { - Ty::F32 => "0_f32", - Ty::F64 => "0_f64", - Ty::I32 => "0_i32", - Ty::Bool => "false", - } - } - - fn to_i64(&self) -> &'static str { - match self { - Ty::F32 => ".to_bits() as i64", - Ty::F64 => ".to_bits() as i64", - Ty::I32 => " as i64", - Ty::Bool => " as i64", - } - } - } - - fn generate_test_outputs(functions: &mut [Function]) { - let mut src = String::new(); - let dst = std::env::var("OUT_DIR").unwrap(); - - // Generate a program which will run all tests with all inputs in - // `functions`. This program will write all outputs to stdout (in a - // binary format). - src.push_str("use std::io::Write;"); - src.push_str("fn main() {"); - src.push_str("let mut result = Vec::new();"); - for function in functions.iter_mut() { - src.push_str("unsafe {"); - src.push_str("extern { fn "); - src.push_str(&function.name); - src.push_str("("); - - let (ret, retptr) = match function.name.as_str() { - "sincos" | "sincosf" => (None, &function.ret[..]), - _ => (Some(&function.ret[0]), &function.ret[1..]), - }; - for (i, arg) in function.args.iter().enumerate() { - src.push_str(&format!("arg{}: {},", i, arg.libc_ty())); - } - for (i, ret) in retptr.iter().enumerate() { - src.push_str(&format!("argret{}: {},", i, ret.libc_pty())); - } - src.push_str(")"); - if let Some(ty) = ret { - src.push_str(" -> "); - src.push_str(ty.libc_ty()); - } - src.push_str("; }"); - - src.push_str(&format!("static TESTS: &[[i64; {}]]", function.args.len())); - src.push_str(" = &["); - for test in function.tests.iter() { - src.push_str("["); - for val in test.inputs.iter() { - src.push_str(&val.to_string()); - src.push_str(","); - } - src.push_str("],"); - } - src.push_str("];"); - - src.push_str("for test in TESTS {"); - for (i, arg) in retptr.iter().enumerate() { - src.push_str(&format!("let mut argret{} = {};", i, arg.default())); - } - src.push_str("let output = "); - src.push_str(&function.name); - src.push_str("("); - for (i, arg) in function.args.iter().enumerate() { - src.push_str(&match arg { - Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), - Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), - Ty::I32 => format!("test[{}] as i32", i), - Ty::Bool => format!("test[{}] as i32", i), - }); - src.push_str(","); - } - for (i, _) in retptr.iter().enumerate() { - src.push_str(&format!("&mut argret{},", i)); - } - src.push_str(");"); - if let Some(ty) = &ret { - src.push_str(&format!("let output = output{};", ty.to_i64())); - src.push_str("result.extend_from_slice(&output.to_le_bytes());"); - } - - for (i, ret) in retptr.iter().enumerate() { - src.push_str(&format!( - "result.extend_from_slice(&(argret{}{}).to_le_bytes());", - i, - ret.to_i64(), - )); - } - src.push_str("}"); - - src.push_str("}"); - } - - src.push_str("std::io::stdout().write_all(&result).unwrap();"); - - src.push_str("}"); - - let path = format!("{}/gen.rs", dst); - fs::write(&path, src).unwrap(); - - // Make it somewhat pretty if something goes wrong - drop(Command::new("rustfmt").arg(&path).status()); - - // Compile and execute this tests for the musl target, assuming we're an - // x86_64 host effectively. - let status = Command::new("rustc") - .current_dir(&dst) - .arg(&path) - .arg("--target=x86_64-unknown-linux-musl") - .status() - .unwrap(); - assert!(status.success()); - let output = Command::new("./gen").current_dir(&dst).output().unwrap(); - assert!(output.status.success()); - assert!(output.stderr.is_empty()); - - // Map all the output bytes back to an `i64` and then shove it all into - // the expected results. - let mut results = output.stdout.chunks_exact(8).map(|buf| { - let mut exact = [0; 8]; - exact.copy_from_slice(buf); - i64::from_le_bytes(exact) - }); - - for f in functions.iter_mut() { - for test in f.tests.iter_mut() { - test.outputs = (0..f.ret.len()).map(|_| results.next().unwrap()).collect(); - } - } - assert!(results.next().is_none()); - } - - /// Codegens a file which has a ton of `#[test]` annotations for all the - /// tests that we generated above. - fn generate_unit_tests(functions: &[Function]) { - let mut src = String::new(); - let dst = std::env::var("OUT_DIR").unwrap(); - - for function in functions { - src.push_str("#[test]"); - src.push_str("fn "); - src.push_str(&function.name); - src.push_str("_matches_musl() {"); - src.push_str(&format!( - "static TESTS: &[([i64; {}], [i64; {}])]", - function.args.len(), - function.ret.len(), - )); - src.push_str(" = &["); - for test in function.tests.iter() { - src.push_str("(["); - for val in test.inputs.iter() { - src.push_str(&val.to_string()); - src.push_str(","); - } - src.push_str("],"); - src.push_str("["); - for val in test.outputs.iter() { - src.push_str(&val.to_string()); - src.push_str(","); - } - src.push_str("],"); - src.push_str("),"); - } - src.push_str("];"); - - src.push_str("for (test, expected) in TESTS {"); - src.push_str("let output = "); - src.push_str(&function.name); - src.push_str("("); - for (i, arg) in function.args.iter().enumerate() { - src.push_str(&match arg { - Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), - Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), - Ty::I32 => format!("test[{}] as i32", i), - Ty::Bool => format!("test[{}] as i32", i), - }); - src.push_str(","); - } - src.push_str(");"); - - for (i, ret) in function.ret.iter().enumerate() { - let get = if function.ret.len() == 1 { - String::new() - } else { - format!(".{}", i) - }; - src.push_str(&(match ret { - Ty::F32 => format!("if _eqf(output{}, f32::from_bits(expected[{}] as u32)).is_ok() {{ continue }}", get, i), - Ty::F64 => format!("if _eq(output{}, f64::from_bits(expected[{}] as u64)).is_ok() {{ continue }}", get, i), - Ty::I32 => format!("if output{} as i64 == expected[{}] {{ continue }}", get, i), - Ty::Bool => unreachable!(), - })); - } - - src.push_str( - r#" - panic!("INPUT: {:?} EXPECTED: {:?} ACTUAL {:?}", test, expected, output); - "#, - ); - src.push_str("}"); - - src.push_str("}"); - } - - let path = format!("{}/musl-tests.rs", dst); - fs::write(&path, src).unwrap(); - - // Try to make it somewhat pretty - drop(Command::new("rustfmt").arg(&path).status()); - } -} diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index d0cd42a8d0b..2a1ac52b13c 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -3,19 +3,19 @@ set -ex TARGET=$1 -CMD="cargo test --all --target $TARGET" +cmd="cargo test --all --target $TARGET" # Needed for no-panic to correct detect a lack of panics export RUSTFLAGS="$RUSTFLAGS -Ccodegen-units=1" # stable by default -$CMD -$CMD --release +$cmd +$cmd --release # unstable with a feature -$CMD --features 'unstable' -$CMD --release --features 'unstable' +$cmd --features 'unstable' +$cmd --release --features 'unstable' # also run the reference tests -$CMD --features 'unstable musl-reference-tests' -$CMD --release --features 'unstable musl-reference-tests' +$cmd --features 'unstable libm-test/musl-reference-tests' +$cmd --release --features 'unstable libm-test/musl-reference-tests' diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml new file mode 100644 index 00000000000..03e55b1d9a4 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "libm-test" +version = "0.1.0" +edition = "2021" +publish = false + +[features] +default = [] + +# Generate tests which are random inputs and the outputs are calculated with +# musl libc. +musl-reference-tests = ["rand"] + +[dependencies] +libm = { path = "../.." } + +[build-dependencies] +rand = { version = "0.6.5", optional = true } diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs new file mode 100644 index 00000000000..fc8f305d665 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -0,0 +1,456 @@ +fn main() { + #[cfg(feature = "musl-reference-tests")] + musl_reference_tests::generate(); +} + +#[cfg(feature = "musl-reference-tests")] +mod musl_reference_tests { + use rand::seq::SliceRandom; + use rand::Rng; + use std::env; + use std::fs; + use std::path::PathBuf; + use std::process::Command; + + // Number of tests to generate for each function + const NTESTS: usize = 500; + + // These files are all internal functions or otherwise miscellaneous, not + // defining a function we want to test. + const IGNORED_FILES: &[&str] = &[ + "fenv.rs", + // These are giving slightly different results compared to musl + "lgamma.rs", + "lgammaf.rs", + "tgamma.rs", + "j0.rs", + "j0f.rs", + "jn.rs", + "jnf.rs", + "j1.rs", + "j1f.rs", + ]; + + struct Function { + name: String, + args: Vec, + ret: Vec, + tests: Vec, + } + + enum Ty { + F32, + F64, + I32, + Bool, + } + + struct Test { + inputs: Vec, + outputs: Vec, + } + + pub fn generate() { + // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let libm_test = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let math_src = libm_test.join("../../src/math"); + + if target_arch == "powerpc64" { + return; + } + + let files = fs::read_dir(math_src) + .unwrap() + .map(|f| f.unwrap().path()) + .collect::>(); + + let mut math = Vec::new(); + for file in files { + if IGNORED_FILES.iter().any(|f| file.ends_with(f)) { + continue; + } + + println!("generating musl reference tests in {:?}", file); + + let contents = fs::read_to_string(file).unwrap(); + let mut functions = contents.lines().filter(|f| f.starts_with("pub fn")); + while let Some(function_to_test) = functions.next() { + math.push(parse(function_to_test)); + } + } + + // Generate a bunch of random inputs for each function. This will + // attempt to generate a good set of uniform test cases for exercising + // all the various functionality. + generate_random_tests(&mut math, &mut rand::thread_rng()); + + // After we have all our inputs, use the x86_64-unknown-linux-musl + // target to generate the expected output. + generate_test_outputs(&mut math); + //panic!("Boo"); + // ... and now that we have both inputs and expected outputs, do a bunch + // of codegen to create the unit tests which we'll actually execute. + generate_unit_tests(&math); + } + + /// A "poor man's" parser for the signature of a function + fn parse(s: &str) -> Function { + let s = eat(s, "pub fn "); + let pos = s.find('(').unwrap(); + let name = &s[..pos]; + let s = &s[pos + 1..]; + let end = s.find(')').unwrap(); + let args = s[..end] + .split(',') + .map(|arg| { + let colon = arg.find(':').unwrap(); + parse_ty(arg[colon + 1..].trim()) + }) + .collect::>(); + let tail = &s[end + 1..]; + let tail = eat(tail, " -> "); + let ret = parse_retty(tail.replace("{", "").trim()); + + return Function { + name: name.to_string(), + args, + ret, + tests: Vec::new(), + }; + + fn parse_ty(s: &str) -> Ty { + match s { + "f32" => Ty::F32, + "f64" => Ty::F64, + "i32" => Ty::I32, + "bool" => Ty::Bool, + other => panic!("unknown type `{}`", other), + } + } + + fn parse_retty(s: &str) -> Vec { + match s { + "(f32, f32)" => vec![Ty::F32, Ty::F32], + "(f32, i32)" => vec![Ty::F32, Ty::I32], + "(f64, f64)" => vec![Ty::F64, Ty::F64], + "(f64, i32)" => vec![Ty::F64, Ty::I32], + other => vec![parse_ty(other)], + } + } + + fn eat<'a>(s: &'a str, prefix: &str) -> &'a str { + if s.starts_with(prefix) { + &s[prefix.len()..] + } else { + panic!("{:?} didn't start with {:?}", s, prefix) + } + } + } + + fn generate_random_tests(functions: &mut [Function], rng: &mut R) { + for function in functions { + for _ in 0..NTESTS { + function.tests.push(generate_test(function, rng)); + } + } + + fn generate_test(function: &Function, rng: &mut R) -> Test { + let mut inputs = function + .args + .iter() + .map(|ty| ty.gen_i64(rng)) + .collect::>(); + + // First argument to this function appears to be a number of + // iterations, so passing in massive random numbers causes it to + // take forever to execute, so make sure we're not running random + // math code until the heat death of the universe. + if function.name == "jn" || function.name == "jnf" { + inputs[0] &= 0xffff; + } + + Test { + inputs, + // zero output for now since we'll generate it later + outputs: vec![], + } + } + } + + impl Ty { + fn gen_i64(&self, r: &mut R) -> i64 { + use std::f32; + use std::f64; + + return match self { + Ty::F32 => { + if r.gen_range(0, 20) < 1 { + let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY] + .choose(r) + .unwrap(); + i.to_bits().into() + } else { + r.gen::().to_bits().into() + } + } + Ty::F64 => { + if r.gen_range(0, 20) < 1 { + let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY] + .choose(r) + .unwrap(); + i.to_bits() as i64 + } else { + r.gen::().to_bits() as i64 + } + } + Ty::I32 => { + if r.gen_range(0, 10) < 1 { + let i = *[i32::max_value(), 0, i32::min_value()].choose(r).unwrap(); + i.into() + } else { + r.gen::().into() + } + } + Ty::Bool => r.gen::() as i64, + }; + } + + fn libc_ty(&self) -> &'static str { + match self { + Ty::F32 => "f32", + Ty::F64 => "f64", + Ty::I32 => "i32", + Ty::Bool => "i32", + } + } + + fn libc_pty(&self) -> &'static str { + match self { + Ty::F32 => "*mut f32", + Ty::F64 => "*mut f64", + Ty::I32 => "*mut i32", + Ty::Bool => "*mut i32", + } + } + + fn default(&self) -> &'static str { + match self { + Ty::F32 => "0_f32", + Ty::F64 => "0_f64", + Ty::I32 => "0_i32", + Ty::Bool => "false", + } + } + + fn to_i64(&self) -> &'static str { + match self { + Ty::F32 => ".to_bits() as i64", + Ty::F64 => ".to_bits() as i64", + Ty::I32 => " as i64", + Ty::Bool => " as i64", + } + } + } + + fn generate_test_outputs(functions: &mut [Function]) { + let mut src = String::new(); + let dst = std::env::var("OUT_DIR").unwrap(); + + // Generate a program which will run all tests with all inputs in + // `functions`. This program will write all outputs to stdout (in a + // binary format). + src.push_str("use std::io::Write;"); + src.push_str("fn main() {"); + src.push_str("let mut result = Vec::new();"); + for function in functions.iter_mut() { + src.push_str("unsafe {"); + src.push_str("extern { fn "); + src.push_str(&function.name); + src.push_str("("); + + let (ret, retptr) = match function.name.as_str() { + "sincos" | "sincosf" => (None, &function.ret[..]), + _ => (Some(&function.ret[0]), &function.ret[1..]), + }; + for (i, arg) in function.args.iter().enumerate() { + src.push_str(&format!("arg{}: {},", i, arg.libc_ty())); + } + for (i, ret) in retptr.iter().enumerate() { + src.push_str(&format!("argret{}: {},", i, ret.libc_pty())); + } + src.push_str(")"); + if let Some(ty) = ret { + src.push_str(" -> "); + src.push_str(ty.libc_ty()); + } + src.push_str("; }"); + + src.push_str(&format!("static TESTS: &[[i64; {}]]", function.args.len())); + src.push_str(" = &["); + for test in function.tests.iter() { + src.push_str("["); + for val in test.inputs.iter() { + src.push_str(&val.to_string()); + src.push_str(","); + } + src.push_str("],"); + } + src.push_str("];"); + + src.push_str("for test in TESTS {"); + for (i, arg) in retptr.iter().enumerate() { + src.push_str(&format!("let mut argret{} = {};", i, arg.default())); + } + src.push_str("let output = "); + src.push_str(&function.name); + src.push_str("("); + for (i, arg) in function.args.iter().enumerate() { + src.push_str(&match arg { + Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), + Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), + Ty::I32 => format!("test[{}] as i32", i), + Ty::Bool => format!("test[{}] as i32", i), + }); + src.push_str(","); + } + for (i, _) in retptr.iter().enumerate() { + src.push_str(&format!("&mut argret{},", i)); + } + src.push_str(");"); + if let Some(ty) = &ret { + src.push_str(&format!("let output = output{};", ty.to_i64())); + src.push_str("result.extend_from_slice(&output.to_le_bytes());"); + } + + for (i, ret) in retptr.iter().enumerate() { + src.push_str(&format!( + "result.extend_from_slice(&(argret{}{}).to_le_bytes());", + i, + ret.to_i64(), + )); + } + src.push_str("}"); + + src.push_str("}"); + } + + src.push_str("std::io::stdout().write_all(&result).unwrap();"); + + src.push_str("}"); + + let path = format!("{}/gen.rs", dst); + fs::write(&path, src).unwrap(); + + // Make it somewhat pretty if something goes wrong + drop(Command::new("rustfmt").arg(&path).status()); + + // Compile and execute this tests for the musl target, assuming we're an + // x86_64 host effectively. + let status = Command::new("rustc") + .current_dir(&dst) + .arg(&path) + .arg("--target=x86_64-unknown-linux-musl") + .status() + .unwrap(); + assert!(status.success()); + let output = Command::new("./gen").current_dir(&dst).output().unwrap(); + assert!(output.status.success()); + assert!(output.stderr.is_empty()); + + // Map all the output bytes back to an `i64` and then shove it all into + // the expected results. + let mut results = output.stdout.chunks_exact(8).map(|buf| { + let mut exact = [0; 8]; + exact.copy_from_slice(buf); + i64::from_le_bytes(exact) + }); + + for f in functions.iter_mut() { + for test in f.tests.iter_mut() { + test.outputs = (0..f.ret.len()).map(|_| results.next().unwrap()).collect(); + } + } + assert!(results.next().is_none()); + } + + /// Codegens a file which has a ton of `#[test]` annotations for all the + /// tests that we generated above. + fn generate_unit_tests(functions: &[Function]) { + let mut src = String::new(); + let dst = std::env::var("OUT_DIR").unwrap(); + + for function in functions { + src.push_str("#[test]"); + src.push_str("fn "); + src.push_str(&function.name); + src.push_str("_matches_musl() {"); + src.push_str(&format!( + "static TESTS: &[([i64; {}], [i64; {}])]", + function.args.len(), + function.ret.len(), + )); + src.push_str(" = &["); + for test in function.tests.iter() { + src.push_str("(["); + for val in test.inputs.iter() { + src.push_str(&val.to_string()); + src.push_str(","); + } + src.push_str("],"); + src.push_str("["); + for val in test.outputs.iter() { + src.push_str(&val.to_string()); + src.push_str(","); + } + src.push_str("],"); + src.push_str("),"); + } + src.push_str("];"); + + src.push_str("for (test, expected) in TESTS {"); + src.push_str("let output = libm::"); + src.push_str(&function.name); + src.push_str("("); + for (i, arg) in function.args.iter().enumerate() { + src.push_str(&match arg { + Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), + Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), + Ty::I32 => format!("test[{}] as i32", i), + Ty::Bool => format!("test[{}] as i32", i), + }); + src.push_str(","); + } + src.push_str(");"); + + for (i, ret) in function.ret.iter().enumerate() { + let get = if function.ret.len() == 1 { + String::new() + } else { + format!(".{}", i) + }; + src.push_str(&(match ret { + Ty::F32 => format!("if libm::_eqf(output{}, f32::from_bits(expected[{}] as u32)).is_ok() {{ continue }}", get, i), + Ty::F64 => format!("if libm::_eq(output{}, f64::from_bits(expected[{}] as u64)).is_ok() {{ continue }}", get, i), + Ty::I32 => format!("if output{} as i64 == expected[{}] {{ continue }}", get, i), + Ty::Bool => unreachable!(), + })); + } + + src.push_str( + r#" + panic!("INPUT: {:?} EXPECTED: {:?} ACTUAL {:?}", test, expected, output); + "#, + ); + src.push_str("}"); + + src.push_str("}"); + } + + let path = format!("{}/musl-tests.rs", dst); + fs::write(&path, src).unwrap(); + + // Try to make it somewhat pretty + drop(Command::new("rustfmt").arg(&path).status()); + } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -0,0 +1 @@ + diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs b/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs new file mode 100644 index 00000000000..46d4f356306 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs @@ -0,0 +1,4 @@ +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(all(test, feature = "musl-reference-tests"))] +include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 1f23ef8a80e..23885ecf8da 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -53,8 +53,3 @@ pub fn _eq(a: f64, b: f64) -> Result<(), u64> { } } } - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(all(test, feature = "musl-reference-tests"))] -include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); -- cgit 1.4.1-3-g733a5 From 8153729f91e925902490a995c72537208b0232aa Mon Sep 17 00:00:00 2001 From: "Enzo \"raskyld\" Nocera" Date: Sun, 6 Oct 2024 03:45:06 +0200 Subject: fix(int): avoid infinite recursion on left shift Please, see this discussion for the full context: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/.5Bwasm32.5D.20Infinite.20recursion.20.60compiler-builtins.60.20.60__multi3.60 Signed-off-by: Enzo "raskyld" Nocera We determined that some recursion problems on SPARC and WASM were due to infinite recusion. This was introduced at 9c6fcb56e8 ("Split Int into Int and MinInt") when moving the implementation of `widen_hi` from something on each `impl` block to a default on the trait. The reasoning is not fully understood, but undoing this portion of the change seems to resolve the issue. [ add the above context - Trevor ] Signed-off-by: Trevor Gross --- library/compiler-builtins/src/int/big.rs | 8 ++++++++ library/compiler-builtins/src/int/mod.rs | 7 ++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/int/big.rs b/library/compiler-builtins/src/int/big.rs index e565da89720..0ef3caaedff 100644 --- a/library/compiler-builtins/src/int/big.rs +++ b/library/compiler-builtins/src/int/big.rs @@ -222,6 +222,10 @@ impl HInt for u128 { fn widen_mul(self, rhs: Self) -> Self::D { self.zero_widen_mul(rhs) } + + fn widen_hi(self) -> Self::D { + self.widen() << ::BITS + } } impl HInt for i128 { @@ -247,6 +251,10 @@ impl HInt for i128 { fn widen_mul(self, rhs: Self) -> Self::D { unimplemented!("signed i128 widening multiply is not used") } + + fn widen_hi(self) -> Self::D { + self.widen() << ::BITS + } } impl DInt for u256 { diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 5f56c6b6ee1..c7ca45e713e 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -319,9 +319,7 @@ pub(crate) trait HInt: Int { /// around problems with associated type bounds (such as `Int`) being unstable fn zero_widen(self) -> Self::D; /// Widens the integer to have double bit width and shifts the integer into the higher bits - fn widen_hi(self) -> Self::D { - self.widen() << ::BITS - } + fn widen_hi(self) -> Self::D; /// Widening multiplication with zero widening. This cannot overflow. fn zero_widen_mul(self, rhs: Self) -> Self::D; /// Widening multiplication. This cannot overflow. @@ -364,6 +362,9 @@ macro_rules! impl_h_int { fn widen_mul(self, rhs: Self) -> Self::D { self.widen().wrapping_mul(rhs.widen()) } + fn widen_hi(self) -> Self::D { + (self as $X) << ::BITS + } } )* }; -- cgit 1.4.1-3-g733a5 From 996799a896c9d64f5d7d6e5f9c959b0268a0e693 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 5 Oct 2024 20:55:47 -0500 Subject: Add a note about avoiding default implemenations in some places Link: https://github.com/rust-lang/compiler-builtins/pull/707 --- library/compiler-builtins/src/int/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index c7ca45e713e..e6f31c53013 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -313,6 +313,10 @@ pub(crate) trait HInt: Int { /// Integer that is double the bit width of the integer this trait is implemented for type D: DInt + MinInt; + // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for + // unknown reasons this can cause infinite recursion when optimizations are disabled. See + // for context. + /// Widens (using default extension) the integer to have double bit width fn widen(self) -> Self::D; /// Widens (zero extension only) the integer to have double bit width. This is needed to get -- cgit 1.4.1-3-g733a5 From fedfc6aaab58eee7af80db5c0315fb916bba6661 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 6 Oct 2024 02:08:00 +0000 Subject: chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d0adf744461..34e1dcdfd43 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.132" +version = "0.1.133" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From c236051681210a65a9a6bf8f8ceb06b359e355c1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 5 Oct 2024 21:42:28 -0500 Subject: Rename the `musl-reference-tests` feature to `musl-bitwise-tests` The plan is to add more test related features that could be considered "reference tests". Rename the feature here to avoid future confusion. --- library/compiler-builtins/libm/CONTRIBUTING.md | 4 ++-- library/compiler-builtins/libm/ci/run.sh | 4 ++-- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 2 +- library/compiler-builtins/libm/crates/libm-test/build.rs | 4 ++-- library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs | 4 +++- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index c15c45a4336..1b5235db9ce 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -7,7 +7,7 @@ in `src/lib.rs`. - Write some simple tests in your module (using `#[test]`) - Run `cargo test` to make sure it works -- Run `cargo test --features libm-test/musl-reference-tests` to compare your +- Run `cargo test --features libm-test/musl-bitwise-tests` to compare your implementation against musl's - Send us a pull request! Make sure to run `cargo fmt` on your code before sending the PR. Also include "closes #42" in the PR description to close the @@ -88,7 +88,7 @@ If you'd like to run tests with randomized inputs that get compared against musl itself, you'll need to be on a Linux system and then you can execute: ``` -cargo test --features libm-test/musl-reference-tests +cargo test --features libm-test/musl-bitwise-tests ``` Note that you may need to pass `--release` to Cargo if there are errors related diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 2a1ac52b13c..b5d6e45f710 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -17,5 +17,5 @@ $cmd --features 'unstable' $cmd --release --features 'unstable' # also run the reference tests -$cmd --features 'unstable libm-test/musl-reference-tests' -$cmd --release --features 'unstable libm-test/musl-reference-tests' +$cmd --features 'unstable libm-test/musl-bitwise-tests' +$cmd --release --features 'unstable libm-test/musl-bitwise-tests' diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 03e55b1d9a4..d0445237639 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -9,7 +9,7 @@ default = [] # Generate tests which are random inputs and the outputs are calculated with # musl libc. -musl-reference-tests = ["rand"] +musl-bitwise-tests = ["rand"] [dependencies] libm = { path = "../.." } diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index fc8f305d665..09eb384103a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -1,9 +1,9 @@ fn main() { - #[cfg(feature = "musl-reference-tests")] + #[cfg(feature = "musl-bitwise-tests")] musl_reference_tests::generate(); } -#[cfg(feature = "musl-reference-tests")] +#[cfg(feature = "musl-bitwise-tests")] mod musl_reference_tests { use rand::seq::SliceRandom; use rand::Rng; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs b/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs index 46d4f356306..1a6b7181709 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs @@ -1,4 +1,6 @@ +//! compare + // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 #[cfg(not(target_arch = "powerpc64"))] -#[cfg(all(test, feature = "musl-reference-tests"))] +#[cfg(all(test, feature = "musl-bitwise-tests"))] include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); -- cgit 1.4.1-3-g733a5 From cb305df1940fc52fd1004046b7c33afc6b56aa39 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 5 Oct 2024 22:24:14 -0500 Subject: Upgrade all dependencies None of these affect the distributed library. --- library/compiler-builtins/libm/Cargo.toml | 2 +- library/compiler-builtins/libm/crates/libm-bench/Cargo.toml | 4 ++-- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index fc2db0c2088..712baee79a5 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -34,7 +34,7 @@ default-members = [ ] [dev-dependencies] -no-panic = "0.1.8" +no-panic = "0.1.30" # This is needed for no-panic to correctly detect the lack of panics diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml index b09db339b5b..ac9cb83a601 100644 --- a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml @@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0" [dependencies] libm = { path = "../..", default-features = false } -rand = "0.6.5" -paste = "0.1.5" +rand = "0.8.5" +paste = "1.0.15" [features] default = [] diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index d0445237639..7c193d3bbca 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -15,4 +15,4 @@ musl-bitwise-tests = ["rand"] libm = { path = "../.." } [build-dependencies] -rand = { version = "0.6.5", optional = true } +rand = { version = "0.8.5", optional = true } -- cgit 1.4.1-3-g733a5 From d8c234b959959d832c2b8532d843d62ca779b4e8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 5 Oct 2024 22:28:38 -0500 Subject: Do library updates necessary with dependency upgrades --- library/compiler-builtins/libm/crates/libm-test/build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index 09eb384103a..c2c4b0bd28e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -185,7 +185,7 @@ mod musl_reference_tests { return match self { Ty::F32 => { - if r.gen_range(0, 20) < 1 { + if r.gen_range(0..20) < 1 { let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY] .choose(r) .unwrap(); @@ -195,7 +195,7 @@ mod musl_reference_tests { } } Ty::F64 => { - if r.gen_range(0, 20) < 1 { + if r.gen_range(0..20) < 1 { let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY] .choose(r) .unwrap(); @@ -205,7 +205,7 @@ mod musl_reference_tests { } } Ty::I32 => { - if r.gen_range(0, 10) < 1 { + if r.gen_range(0..10) < 1 { let i = *[i32::max_value(), 0, i32::min_value()].choose(r).unwrap(); i.into() } else { -- cgit 1.4.1-3-g733a5 From 0be441d5adb1079b2a158278c5787c8803e2805f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 6 Oct 2024 00:07:55 -0500 Subject: Update Ubuntu images to 24.04 We don't have any specific reason to stay on 18.04, so upgrade to the latest LTS version. --- .../libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 3 ++- .../libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 3 ++- .../libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile | 3 ++- .../libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile | 3 ++- .../compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile | 3 ++- .../compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile | 2 +- .../libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile | 3 ++- .../libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile | 3 ++- .../libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 2 +- .../libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 2 +- .../libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile | 2 +- .../libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile | 2 +- .../libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 3 ++- 13 files changed, 21 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index 9e2559f4ab3..b6b23d86522 100644 --- a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile index afab874bc28..ff340fba4c7 100644 --- a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile index 3ed3602b0dc..15cd6eee909 100644 --- a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile index 6617af1558c..3090a83f808 100644 --- a/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile index 5783e28e122..3b0bfc0d3d9 100644 --- a/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc-multilib libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile index f47e8f5227b..2850e775ca3 100644 --- a/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile index 8fa77c7bd07..ec23159c9aa 100644 --- a/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ diff --git a/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile index c6611d9ac89..0ff1fba9c00 100644 --- a/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ diff --git a/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile index 0bc69562462..dfb9d0c87e2 100644 --- a/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile index 2d39fef6142..532f2cb05f7 100644 --- a/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile index 653cd351156..3ce687873f1 100644 --- a/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile index 63ea9af9d20..90212fe45c3 100644 --- a/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile index 98000f4eb81..15723ab57ee 100644 --- a/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates -- cgit 1.4.1-3-g733a5 From d0f1dd6010eb14f025cd814df9272a5cb3d15726 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 6 Oct 2024 00:12:58 -0500 Subject: Set target-specific `AR` and `CC` arguments The Rust `cc` crate reads these, so make sure they are set for when we start making use of `cc`. --- .../libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 6 +++++- .../libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 6 +++++- .../libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile | 6 +++++- .../libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile | 6 +++++- .../libm/ci/docker/mips-unknown-linux-gnu/Dockerfile | 5 ++++- .../libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile | 7 +++++-- .../libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile | 7 +++++-- .../libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 5 ++++- .../libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 5 ++++- .../libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile | 6 ++++-- .../libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile | 5 ++++- 11 files changed, 50 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index b6b23d86522..a7b23cb9e02 100644 --- a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -5,7 +5,11 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ qemu-user-static -ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + +ENV TOOLCHAIN_PREFIX=aarch64-linux-gnu- +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-aarch64-static \ + AR_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile index ff340fba4c7..e070a7d936e 100644 --- a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -4,7 +4,11 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabi- +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER=qemu-arm-static \ + AR_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"ar \ + CC_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile index 15cd6eee909..29f1e04a9b5 100644 --- a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -4,7 +4,11 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ + AR_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ + CC_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile index 3090a83f808..0a30801b44d 100644 --- a/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -4,7 +4,11 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static -ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- +ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ + AR_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ + CC_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile index 2850e775ca3..298208c925a 100644 --- a/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -6,7 +6,10 @@ RUN apt-get update && \ gcc-mips-linux-gnu libc6-dev-mips-cross \ binfmt-support qemu-user-static qemu-system-mips -ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=mips-linux-gnu- +ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER=qemu-mips-static \ + AR_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mips-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile index ec23159c9aa..101b3853efe 100644 --- a/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -9,8 +9,11 @@ RUN apt-get update && \ libc6-dev-mips64-cross \ qemu-user-static \ qemu-system-mips -ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ + +ENV TOOLCHAIN_PREFIX=mips64-linux-gnuabi64- +ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64-static \ - CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ + AR_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ + CC_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile index 0ff1fba9c00..0eb14f9acf5 100644 --- a/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -8,8 +8,11 @@ RUN apt-get update && \ libc6-dev \ libc6-dev-mips64el-cross \ qemu-user-static -ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER=mips64el-linux-gnuabi64-gcc \ + +ENV TOOLCHAIN_PREFIX=mips64el-linux-gnuabi64- +ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64el-static \ - CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \ + AR_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ + CC_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile index dfb9d0c87e2..1b9817cfef8 100644 --- a/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -6,7 +6,10 @@ RUN apt-get update && \ gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ binfmt-support qemu-user-static -ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=mipsel-linux-gnu- +ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER=qemu-mipsel-static \ + AR_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile index 532f2cb05f7..1ea2e30a242 100644 --- a/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -6,7 +6,10 @@ RUN apt-get update && \ gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ qemu-system-ppc -ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=powerpc-linux-gnu- +ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc-static \ + AR_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile index 3ce687873f1..373814bcafd 100644 --- a/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -6,8 +6,10 @@ RUN apt-get update && \ gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ binfmt-support qemu-user-static qemu-system-ppc -ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=powerpc64-linux-gnu- +ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64-static \ - CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ + AR_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile index 90212fe45c3..403bb1d95b2 100644 --- a/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -6,8 +6,11 @@ RUN apt-get update && \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ qemu-system-ppc -ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=powerpc64le-linux-gnu- +ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64le-static \ + AR_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_CPU=POWER8 \ QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ RUST_TEST_THREADS=1 -- cgit 1.4.1-3-g733a5 From d82eb887223582c0fd678ecfd2913ae48b90d452 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 6 Oct 2024 13:44:25 -0500 Subject: Fix shellcheck warnings in scripts --- library/compiler-builtins/libm/ci/run-docker.sh | 24 ++++++++++++++---------- library/compiler-builtins/libm/ci/run.sh | 9 +++++---- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index 8d323634a67..9191a17e2ba 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -1,36 +1,40 @@ +#!/bin/bash + # Small script to run tests for a target (or all targets) inside all the # respective docker images. -set -ex +set -euxo pipefail run() { local target=$1 - echo $target + echo "testing target: $target" # This directory needs to exist before calling docker, otherwise docker will create it but it # will be owned by root mkdir -p target - docker build -t $target ci/docker/$target + docker build -t "$target" "ci/docker/$target" docker run \ --rm \ - --user $(id -u):$(id -g) \ + --user "$(id -u):$(id -g)" \ -e RUSTFLAGS \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ - -v "${HOME}/.cargo":/cargo \ - -v `pwd`/target:/target \ - -v `pwd`:/checkout:ro \ - -v `rustc --print sysroot`:/rust:ro \ + -v "${HOME}/.cargo:/cargo" \ + -v "$(pwd)/target:/target" \ + -v "$(pwd):/checkout:ro" \ + -v "$(rustc --print sysroot):/rust:ro" \ --init \ -w /checkout \ - $target \ + "$target" \ sh -c "HOME=/tmp PATH=\$PATH:/rust/bin exec ci/run.sh $target" } if [ -z "$1" ]; then - for d in `ls ci/docker/`; do + echo "running tests for all targets" + + for d in ci/docker/*; do run $d done else diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index b5d6e45f710..1b016cc4fb2 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -1,9 +1,10 @@ -#!/usr/bin/env sh +#!/bin/sh -set -ex -TARGET=$1 +set -eux -cmd="cargo test --all --target $TARGET" +target="$1" + +cmd="cargo test --all --target $target" # Needed for no-panic to correct detect a lack of panics export RUSTFLAGS="$RUSTFLAGS -Ccodegen-units=1" -- cgit 1.4.1-3-g733a5 From d3943b1863e47cc207820c9c0eda13fc045a805b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 7 Oct 2024 00:18:41 -0500 Subject: Set edition to 2021 for all crates --- library/compiler-builtins/libm/Cargo.toml | 2 +- .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 1 + .../libm/crates/compiler-builtins-smoke-test/src/lib.rs | 2 ++ library/compiler-builtins/libm/crates/libm-bench/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 712baee79a5..181000f343e 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -9,7 +9,7 @@ name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" version = "0.2.8" -edition = "2018" +edition = "2021" exclude = ["/ci/", "/.github/workflows/"] [features] diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 481d386a4b2..4bc62304a9d 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -2,6 +2,7 @@ name = "cb" version = "0.1.0" authors = ["Jorge Aparicio "] +edition = "2021" [lib] test = false diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index ab744c45bce..e65cb8da3c4 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -2,6 +2,8 @@ //! //! This is used to test that we can source import `libm` into the compiler-builtins crate. +#![feature(core_intrinsics)] +#![allow(internal_features)] #![allow(dead_code)] #![no_std] diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml index ac9cb83a601..282752c6183 100644 --- a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml @@ -2,7 +2,7 @@ name = "libm-bench" version = "0.1.0" authors = ["Gonzalo Brito Gadeschi "] -edition = "2018" +edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -- cgit 1.4.1-3-g733a5 From 2a738c50ab2899194ca7bbed287961f7a1d9fb3a Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 16 Oct 2024 22:12:38 -0400 Subject: Use wrapping pointer arithmetic in mem/impls.rs Add a comment (and fix a typo) --- library/compiler-builtins/src/mem/impls.rs | 105 +++++++++++++++++------------ 1 file changed, 61 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index 23c9d8d3275..c602a67dbd7 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -1,3 +1,20 @@ +// In C and Rust it is UB to read or write to usize::MAX because if an allocation extends to the +// last byte of address space (there must be an allocation to do the read or write), in C computing +// its one-past-the-end pointer would be equal to NULL and in Rust computing the address of a +// trailing ZST member with a safe place projection would wrap (place projection address computation +// is non-wrapping). +// +// However, some embedded systems have special memory at usize::MAX, and need to access that +// memory. If they do that with the intrinsics provided by compiler-builtins (such as memcpy!), the +// ptr::add in these loops will wrap. And if compiler-builtins is compiled with cfg(ub_checks), +// this will fail a UB check at runtime. +// +// Since this scenario is UB, we are within our rights hit this check and halt execution... +// But we are also within our rights to try to make it work. +// We use wrapping_add/wrapping_sub for pointer arithmetic in this module in an attempt to support +// this use. Of course this is not a guarantee that such use will work, it just means that this +// crate doing wrapping pointer arithmetic with a method that must not wrap won't be the problem if +// something does go wrong at runtime. use core::intrinsics::likely; const WORD_SIZE: usize = core::mem::size_of::(); @@ -9,7 +26,7 @@ const WORD_MASK: usize = WORD_SIZE - 1; // word-wise copy. // * The word-wise copy logic needs to perform some checks so it has some small overhead. // ensures that even on 32-bit platforms we have copied at least 8 bytes through -// word-wise copy so the saving of word-wise copy outweights the fixed overhead. +// word-wise copy so the saving of word-wise copy outweighs the fixed overhead. const WORD_COPY_THRESHOLD: usize = if 2 * WORD_SIZE > 16 { 2 * WORD_SIZE } else { @@ -28,11 +45,11 @@ unsafe fn read_usize_unaligned(x: *const usize) -> usize { pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) { #[inline(always)] unsafe fn copy_forward_bytes(mut dest: *mut u8, mut src: *const u8, n: usize) { - let dest_end = dest.add(n); + let dest_end = dest.wrapping_add(n); while dest < dest_end { *dest = *src; - dest = dest.add(1); - src = src.add(1); + dest = dest.wrapping_add(1); + src = src.wrapping_add(1); } } @@ -40,12 +57,12 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) unsafe fn copy_forward_aligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; let mut src_usize = src as *mut usize; - let dest_end = dest.add(n) as *mut usize; + let dest_end = dest.wrapping_add(n) as *mut usize; while dest_usize < dest_end { *dest_usize = *src_usize; - dest_usize = dest_usize.add(1); - src_usize = src_usize.add(1); + dest_usize = dest_usize.wrapping_add(1); + src_usize = src_usize.wrapping_add(1); } } @@ -53,7 +70,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) #[inline(always)] unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; - let dest_end = dest.add(n) as *mut usize; + let dest_end = dest.wrapping_add(n) as *mut usize; // Calculate the misalignment offset and shift needed to reassemble value. let offset = src as usize & WORD_MASK; @@ -70,7 +87,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) let mut prev_word = core::ptr::read_volatile(src_aligned); while dest_usize < dest_end { - src_aligned = src_aligned.add(1); + src_aligned = src_aligned.wrapping_add(1); let cur_word = *src_aligned; #[cfg(target_endian = "little")] let resembled = prev_word >> shift | cur_word << (WORD_SIZE * 8 - shift); @@ -79,7 +96,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) prev_word = cur_word; *dest_usize = resembled; - dest_usize = dest_usize.add(1); + dest_usize = dest_usize.wrapping_add(1); } } @@ -88,12 +105,12 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; let mut src_usize = src as *mut usize; - let dest_end = dest.add(n) as *mut usize; + let dest_end = dest.wrapping_add(n) as *mut usize; while dest_usize < dest_end { *dest_usize = read_usize_unaligned(src_usize); - dest_usize = dest_usize.add(1); - src_usize = src_usize.add(1); + dest_usize = dest_usize.wrapping_add(1); + src_usize = src_usize.wrapping_add(1); } } @@ -102,8 +119,8 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) // Because of n >= 2 * WORD_SIZE, dst_misalignment < n let dest_misalignment = (dest as usize).wrapping_neg() & WORD_MASK; copy_forward_bytes(dest, src, dest_misalignment); - dest = dest.add(dest_misalignment); - src = src.add(dest_misalignment); + dest = dest.wrapping_add(dest_misalignment); + src = src.wrapping_add(dest_misalignment); n -= dest_misalignment; let n_words = n & !WORD_MASK; @@ -113,8 +130,8 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) } else { copy_forward_misaligned_words(dest, src, n_words); } - dest = dest.add(n_words); - src = src.add(n_words); + dest = dest.wrapping_add(n_words); + src = src.wrapping_add(n_words); n -= n_words; } copy_forward_bytes(dest, src, n); @@ -126,10 +143,10 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { // as their inputs instead of pointers to the start! #[inline(always)] unsafe fn copy_backward_bytes(mut dest: *mut u8, mut src: *const u8, n: usize) { - let dest_start = dest.sub(n); + let dest_start = dest.wrapping_sub(n); while dest_start < dest { - dest = dest.sub(1); - src = src.sub(1); + dest = dest.wrapping_sub(1); + src = src.wrapping_sub(1); *dest = *src; } } @@ -138,11 +155,11 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { unsafe fn copy_backward_aligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; let mut src_usize = src as *mut usize; - let dest_start = dest.sub(n) as *mut usize; + let dest_start = dest.wrapping_sub(n) as *mut usize; while dest_start < dest_usize { - dest_usize = dest_usize.sub(1); - src_usize = src_usize.sub(1); + dest_usize = dest_usize.wrapping_sub(1); + src_usize = src_usize.wrapping_sub(1); *dest_usize = *src_usize; } } @@ -151,7 +168,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { #[inline(always)] unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; - let dest_start = dest.sub(n) as *mut usize; + let dest_start = dest.wrapping_sub(n) as *mut usize; // Calculate the misalignment offset and shift needed to reassemble value. let offset = src as usize & WORD_MASK; @@ -168,7 +185,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { let mut prev_word = core::ptr::read_volatile(src_aligned); while dest_start < dest_usize { - src_aligned = src_aligned.sub(1); + src_aligned = src_aligned.wrapping_sub(1); let cur_word = *src_aligned; #[cfg(target_endian = "little")] let resembled = prev_word << (WORD_SIZE * 8 - shift) | cur_word >> shift; @@ -176,7 +193,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { let resembled = prev_word >> (WORD_SIZE * 8 - shift) | cur_word << shift; prev_word = cur_word; - dest_usize = dest_usize.sub(1); + dest_usize = dest_usize.wrapping_sub(1); *dest_usize = resembled; } } @@ -186,25 +203,25 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; let mut src_usize = src as *mut usize; - let dest_start = dest.sub(n) as *mut usize; + let dest_start = dest.wrapping_sub(n) as *mut usize; while dest_start < dest_usize { - dest_usize = dest_usize.sub(1); - src_usize = src_usize.sub(1); + dest_usize = dest_usize.wrapping_sub(1); + src_usize = src_usize.wrapping_sub(1); *dest_usize = read_usize_unaligned(src_usize); } } - let mut dest = dest.add(n); - let mut src = src.add(n); + let mut dest = dest.wrapping_add(n); + let mut src = src.wrapping_add(n); if n >= WORD_COPY_THRESHOLD { // Align dest // Because of n >= 2 * WORD_SIZE, dst_misalignment < n let dest_misalignment = dest as usize & WORD_MASK; copy_backward_bytes(dest, src, dest_misalignment); - dest = dest.sub(dest_misalignment); - src = src.sub(dest_misalignment); + dest = dest.wrapping_sub(dest_misalignment); + src = src.wrapping_sub(dest_misalignment); n -= dest_misalignment; let n_words = n & !WORD_MASK; @@ -214,8 +231,8 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { } else { copy_backward_misaligned_words(dest, src, n_words); } - dest = dest.sub(n_words); - src = src.sub(n_words); + dest = dest.wrapping_sub(n_words); + src = src.wrapping_sub(n_words); n -= n_words; } copy_backward_bytes(dest, src, n); @@ -225,10 +242,10 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { #[inline(always)] pub unsafe fn set_bytes_bytes(mut s: *mut u8, c: u8, n: usize) { - let end = s.add(n); + let end = s.wrapping_add(n); while s < end { *s = c; - s = s.add(1); + s = s.wrapping_add(1); } } @@ -242,11 +259,11 @@ pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { } let mut s_usize = s as *mut usize; - let end = s.add(n) as *mut usize; + let end = s.wrapping_add(n) as *mut usize; while s_usize < end { *s_usize = broadcast; - s_usize = s_usize.add(1); + s_usize = s_usize.wrapping_add(1); } } @@ -255,12 +272,12 @@ pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { // Because of n >= 2 * WORD_SIZE, dst_misalignment < n let misalignment = (s as usize).wrapping_neg() & WORD_MASK; set_bytes_bytes(s, c, misalignment); - s = s.add(misalignment); + s = s.wrapping_add(misalignment); n -= misalignment; let n_words = n & !WORD_MASK; set_bytes_words(s, c, n_words); - s = s.add(n_words); + s = s.wrapping_add(n_words); n -= n_words; } set_bytes_bytes(s, c, n); @@ -270,8 +287,8 @@ pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { pub unsafe fn compare_bytes(s1: *const u8, s2: *const u8, n: usize) -> i32 { let mut i = 0; while i < n { - let a = *s1.add(i); - let b = *s2.add(i); + let a = *s1.wrapping_add(i); + let b = *s2.wrapping_add(i); if a != b { return a as i32 - b as i32; } @@ -285,7 +302,7 @@ pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { let mut n = 0; while *s != 0 { n += 1; - s = s.add(1); + s = s.wrapping_add(1); } n } -- cgit 1.4.1-3-g733a5 From 3e922da15677f0bb29550e722e850665c94c03de Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 23:55:25 +0000 Subject: chore: release v0.1.134 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 34e1dcdfd43..7b853dedddf 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.133" +version = "0.1.134" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 68b820187bd0637c1b81cf1933e346ed774d2981 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Mon, 21 Oct 2024 15:35:31 +0200 Subject: Re-enable math module on i686-unknown-uefi In 9ba77d1583e6de5ab9cf7c9b82827ba8fcb9062f, this was disabled for x86 without sse2. It should be fine to re-enable it for UEFI, as explained at . --- library/compiler-builtins/src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index dea30a3c6ac..ffcd3586ce7 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -44,10 +44,16 @@ pub mod int; // Disable for any of the following: // - x86 without sse2 due to ABI issues // - +// - but exclude UEFI since it is a soft-float target +// - // - All unix targets (linux, macos, freebsd, android, etc) // - wasm with known target_os #[cfg(not(any( - all(target_arch = "x86", not(target_feature = "sse2")), + all( + target_arch = "x86", + not(target_feature = "sse2"), + not(target_os = "uefi"), + ), unix, all(target_family = "wasm", not(target_os = "unknown")) )))] -- cgit 1.4.1-3-g733a5 From ce89a70ae42ccad1c7d856c33e0cf300de9951ed Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 09:57:03 +0000 Subject: chore: release v0.1.135 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7b853dedddf..ab966b84eb8 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.134" +version = "0.1.135" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 2f7fafd182f53e827f12da5af5ab42b3484e44d6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 25 Oct 2024 14:18:53 -0500 Subject: Rename `Float::repr` and `Float::from_repr` `to_bits` and `from_bits` are builtin methods on float types. Rename `repr` to `to_bits` and `from_repr` to `from_bits` so this is consistent with usage that doesn't go through the trait. --- library/compiler-builtins/src/float/add.rs | 20 +++++++++--------- library/compiler-builtins/src/float/cmp.rs | 12 +++++------ library/compiler-builtins/src/float/conv.rs | 6 +++--- library/compiler-builtins/src/float/div.rs | 26 ++++++++++++------------ library/compiler-builtins/src/float/extend.rs | 6 +++--- library/compiler-builtins/src/float/mod.rs | 28 +++++++++++++------------- library/compiler-builtins/src/float/mul.rs | 26 ++++++++++++------------ library/compiler-builtins/src/float/sub.rs | 6 +++--- library/compiler-builtins/src/float/trunc.rs | 9 ++++----- library/compiler-builtins/testcrate/src/lib.rs | 4 ++-- 10 files changed, 71 insertions(+), 72 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index bceef7b0ed9..ecb96264a18 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -25,8 +25,8 @@ where let quiet_bit = implicit_bit >> 1; let qnan_rep = exponent_mask | quiet_bit; - let mut a_rep = a.repr(); - let mut b_rep = b.repr(); + let mut a_rep = a.to_bits(); + let mut b_rep = b.to_bits(); let a_abs = a_rep & abs_mask; let b_abs = b_rep & abs_mask; @@ -34,17 +34,17 @@ where if a_abs.wrapping_sub(one) >= inf_rep - one || b_abs.wrapping_sub(one) >= inf_rep - one { // NaN + anything = qNaN if a_abs > inf_rep { - return F::from_repr(a_abs | quiet_bit); + return F::from_bits(a_abs | quiet_bit); } // anything + NaN = qNaN if b_abs > inf_rep { - return F::from_repr(b_abs | quiet_bit); + return F::from_bits(b_abs | quiet_bit); } if a_abs == inf_rep { // +/-infinity + -/+infinity = qNaN - if (a.repr() ^ b.repr()) == sign_bit { - return F::from_repr(qnan_rep); + if (a.to_bits() ^ b.to_bits()) == sign_bit { + return F::from_bits(qnan_rep); } else { // +/-infinity + anything remaining = +/- infinity return a; @@ -60,7 +60,7 @@ where if a_abs == MinInt::ZERO { // but we need to get the sign right for zero + zero if b_abs == MinInt::ZERO { - return F::from_repr(a.repr() & b.repr()); + return F::from_bits(a.to_bits() & b.to_bits()); } else { return b; } @@ -126,7 +126,7 @@ where a_significand = a_significand.wrapping_sub(b_significand); // If a == -b, return +zero. if a_significand == MinInt::ZERO { - return F::from_repr(MinInt::ZERO); + return F::from_bits(MinInt::ZERO); } // If partial cancellation occured, we need to left-shift the result @@ -152,7 +152,7 @@ where // If we have overflowed the type, return +/- infinity: if a_exponent >= max_exponent as i32 { - return F::from_repr(inf_rep | result_sign); + return F::from_bits(inf_rep | result_sign); } if a_exponent <= 0 { @@ -185,7 +185,7 @@ where result += result & one; } - F::from_repr(result) + F::from_bits(result) } intrinsics! { diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index bb7d4b498fe..8b97a0b5cce 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -41,8 +41,8 @@ fn cmp(a: F, b: F) -> Result { let exponent_mask = F::EXPONENT_MASK; let inf_rep = exponent_mask; - let a_rep = a.repr(); - let b_rep = b.repr(); + let a_rep = a.to_bits(); + let b_rep = b.to_bits(); let a_abs = a_rep & abs_mask; let b_abs = b_rep & abs_mask; @@ -56,8 +56,8 @@ fn cmp(a: F, b: F) -> Result { return Result::Equal; } - let a_srep = a.signed_repr(); - let b_srep = b.signed_repr(); + let a_srep = a.to_bits_signed(); + let b_srep = b.to_bits_signed(); // If at least one of a and b is positive, we get the same result comparing // a and b as signed integers as we would with a fp_ting-point compare. @@ -90,8 +90,8 @@ fn unord(a: F, b: F) -> bool { let exponent_mask = F::EXPONENT_MASK; let inf_rep = exponent_mask; - let a_rep = a.repr(); - let b_rep = b.repr(); + let a_rep = a.to_bits(); + let b_rep = b.to_bits(); let a_abs = a_rep & abs_mask; let b_abs = b_rep & abs_mask; diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index d275f982bb4..e86fee6dc5f 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -158,7 +158,7 @@ where F::Int: CastInto, u32: CastFrom, { - float_to_int_inner::(f.repr(), |i: U| i, || U::MAX) + float_to_int_inner::(f.to_bits(), |i: U| i, || U::MAX) } /// Generic float to signed int conversions. @@ -172,7 +172,7 @@ where u32: CastFrom, { float_to_int_inner::( - f.repr() & !F::SIGN_MASK, + f.to_bits() & !F::SIGN_MASK, |i: I| if f.is_sign_negative() { -i } else { i }, || if f.is_sign_negative() { I::MIN } else { I::MAX }, ) @@ -203,7 +203,7 @@ where let int_max_exp = F::EXPONENT_BIAS + I::MAX.ilog2() + 1; let foobar = F::EXPONENT_BIAS + I::UnsignedInt::BITS - 1; - if fbits < F::ONE.repr() { + if fbits < F::ONE.to_bits() { // < 0 gets rounded to 0 I::ZERO } else if fbits < F::Int::cast_from(int_max_exp) << F::SIGNIFICAND_BITS { diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index f125771a017..4b3f97c3575 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -126,8 +126,8 @@ where half_iterations += 1; } - let a_rep = a.repr(); - let b_rep = b.repr(); + let a_rep = a.to_bits(); + let b_rep = b.to_bits(); // Exponent numeric representationm not accounting for bias let a_exponent = (a_rep >> significand_bits) & exponent_sat; @@ -150,42 +150,42 @@ where // NaN / anything = qNaN if a_abs > inf_rep { - return F::from_repr(a_rep | quiet_bit); + return F::from_bits(a_rep | quiet_bit); } // anything / NaN = qNaN if b_abs > inf_rep { - return F::from_repr(b_rep | quiet_bit); + return F::from_bits(b_rep | quiet_bit); } if a_abs == inf_rep { if b_abs == inf_rep { // infinity / infinity = NaN - return F::from_repr(qnan_rep); + return F::from_bits(qnan_rep); } else { // infinity / anything else = +/- infinity - return F::from_repr(a_abs | quotient_sign); + return F::from_bits(a_abs | quotient_sign); } } // anything else / infinity = +/- 0 if b_abs == inf_rep { - return F::from_repr(quotient_sign); + return F::from_bits(quotient_sign); } if a_abs == zero { if b_abs == zero { // zero / zero = NaN - return F::from_repr(qnan_rep); + return F::from_bits(qnan_rep); } else { // zero / anything else = +/- zero - return F::from_repr(quotient_sign); + return F::from_bits(quotient_sign); } } // anything else / zero = +/- infinity if b_abs == zero { - return F::from_repr(inf_rep | quotient_sign); + return F::from_bits(inf_rep | quotient_sign); } // a is denormal. Renormalize it and set the scale to include the necessary exponent @@ -463,7 +463,7 @@ where // // If we have overflowed the exponent, return infinity if res_exponent >= i32::cast_from(exponent_sat) { - return F::from_repr(inf_rep | quotient_sign); + return F::from_bits(inf_rep | quotient_sign); } // Now, quotient <= the correctly-rounded result @@ -476,7 +476,7 @@ where ret } else { if ((significand_bits as i32) + res_exponent) < 0 { - return F::from_repr(quotient_sign); + return F::from_bits(quotient_sign); } let ret = quotient.wrapping_shr(u32::cast_from(res_exponent.wrapping_neg()) + 1); @@ -501,7 +501,7 @@ where u8::from(abs_result < inf_rep && residual_lo > (4 + 1).cast() * b_significand).into(); } - F::from_repr(abs_result | quotient_sign) + F::from_bits(abs_result | quotient_sign) } /// Calculate the number of iterations required for a float type's precision. diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 997475c8e04..2ec79070cb8 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -32,7 +32,7 @@ where let sign_bits_delta = dst_sign_bits - src_sign_bits; let exp_bias_delta = dst_exp_bias - src_exp_bias; - let a_abs = a.repr() & src_abs_mask; + let a_abs = a.to_bits() & src_abs_mask; let mut abs_result = R::Int::ZERO; if a_abs.wrapping_sub(src_min_normal) < src_infinity.wrapping_sub(src_min_normal) { @@ -65,8 +65,8 @@ where abs_result = (abs_result ^ dst_min_normal) | (bias_dst.wrapping_shl(dst_sign_bits)); } - let sign_result: R::Int = (a.repr() & src_sign_mask).cast(); - R::from_repr(abs_result | (sign_result.wrapping_shl(dst_bits - src_bits))) + let sign_result: R::Int = (a.to_bits() & src_sign_mask).cast(); + R::from_bits(abs_result | (sign_result.wrapping_shl(dst_bits - src_bits))) } intrinsics! { diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 704bba0c025..5eedf544f12 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -70,10 +70,10 @@ pub(crate) trait Float: const EXPONENT_MASK: Self::Int; /// Returns `self` transmuted to `Self::Int` - fn repr(self) -> Self::Int; + fn to_bits(self) -> Self::Int; /// Returns `self` transmuted to `Self::SignedInt` - fn signed_repr(self) -> Self::SignedInt; + fn to_bits_signed(self) -> Self::SignedInt; /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be /// represented in multiple different ways. This method returns `true` if two NaNs are @@ -93,10 +93,10 @@ pub(crate) trait Float: fn imp_frac(self) -> Self::Int; /// Returns a `Self::Int` transmuted back to `Self` - fn from_repr(a: Self::Int) -> Self; + fn from_bits(a: Self::Int) -> Self; /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self; /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); @@ -124,10 +124,10 @@ macro_rules! float_impl { const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); - fn repr(self) -> Self::Int { + fn to_bits(self) -> Self::Int { self.to_bits() } - fn signed_repr(self) -> Self::SignedInt { + fn to_bits_signed(self) -> Self::SignedInt { self.to_bits() as Self::SignedInt } fn eq_repr(self, rhs: Self) -> bool { @@ -137,8 +137,8 @@ macro_rules! float_impl { // necessary builtin (__unordtf2) to test whether `f128` is NaN. // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin // x is NaN if all the bits of the exponent are set and the significand is non-0 - x.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK - && x.repr() & $ty::SIGNIFICAND_MASK != 0 + x.to_bits() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK + && x.to_bits() & $ty::SIGNIFICAND_MASK != 0 } #[cfg(not(feature = "mangled-names"))] fn is_nan(x: $ty) -> bool { @@ -147,7 +147,7 @@ macro_rules! float_impl { if is_nan(self) && is_nan(rhs) { true } else { - self.repr() == rhs.repr() + self.to_bits() == rhs.to_bits() } } fn is_sign_negative(self) -> bool { @@ -162,12 +162,12 @@ macro_rules! float_impl { fn imp_frac(self) -> Self::Int { self.frac() | Self::IMPLICIT_BIT } - fn from_repr(a: Self::Int) -> Self { + fn from_bits(a: Self::Int) -> Self { Self::from_bits(a) } - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr( - ((sign as Self::Int) << (Self::BITS - 1)) + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_bits( + ((negative as Self::Int) << (Self::BITS - 1)) | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) | (significand & Self::SIGNIFICAND_MASK), ) @@ -182,7 +182,7 @@ macro_rules! float_impl { ) } fn is_subnormal(self) -> bool { - (self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO + (self.to_bits() & Self::EXPONENT_MASK) == Self::Int::ZERO } } }; diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index a4c69ea8707..77a271d65a9 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -28,8 +28,8 @@ where let qnan_rep = exponent_mask | quiet_bit; let exponent_bits = F::EXPONENT_BITS; - let a_rep = a.repr(); - let b_rep = b.repr(); + let a_rep = a.to_bits(); + let b_rep = b.to_bits(); let a_exponent = (a_rep >> significand_bits) & max_exponent.cast(); let b_exponent = (b_rep >> significand_bits) & max_exponent.cast(); @@ -48,41 +48,41 @@ where // NaN + anything = qNaN if a_abs > inf_rep { - return F::from_repr(a_rep | quiet_bit); + return F::from_bits(a_rep | quiet_bit); } // anything + NaN = qNaN if b_abs > inf_rep { - return F::from_repr(b_rep | quiet_bit); + return F::from_bits(b_rep | quiet_bit); } if a_abs == inf_rep { if b_abs != zero { // infinity * non-zero = +/- infinity - return F::from_repr(a_abs | product_sign); + return F::from_bits(a_abs | product_sign); } else { // infinity * zero = NaN - return F::from_repr(qnan_rep); + return F::from_bits(qnan_rep); } } if b_abs == inf_rep { if a_abs != zero { // infinity * non-zero = +/- infinity - return F::from_repr(b_abs | product_sign); + return F::from_bits(b_abs | product_sign); } else { // infinity * zero = NaN - return F::from_repr(qnan_rep); + return F::from_bits(qnan_rep); } } // zero * anything = +/- zero if a_abs == zero { - return F::from_repr(product_sign); + return F::from_bits(product_sign); } // anything * zero = +/- zero if b_abs == zero { - return F::from_repr(product_sign); + return F::from_bits(product_sign); } // one or both of a or b is denormal, the other (if applicable) is a @@ -133,7 +133,7 @@ where // If we have overflowed the type, return +/- infinity. if product_exponent >= max_exponent as i32 { - return F::from_repr(inf_rep | product_sign); + return F::from_bits(inf_rep | product_sign); } if product_exponent <= 0 { @@ -145,7 +145,7 @@ where // simplify the shift logic. let shift = one.wrapping_sub(product_exponent.cast()).cast(); if shift >= bits { - return F::from_repr(product_sign); + return F::from_bits(product_sign); } // Otherwise, shift the significand of the result so that the round @@ -176,7 +176,7 @@ where product_high += product_high & one; } - F::from_repr(product_high) + F::from_bits(product_high) } intrinsics! { diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 7e8a8945848..175b3a16500 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -4,13 +4,13 @@ intrinsics! { #[avr_skip] #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { - crate::float::add::__addsf3(a, f32::from_repr(b.repr() ^ f32::SIGN_MASK)) + crate::float::add::__addsf3(a, f32::from_bits(b.to_bits() ^ f32::SIGN_MASK)) } #[avr_skip] #[arm_aeabi_alias = __aeabi_dsub] pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { - crate::float::add::__adddf3(a, f64::from_repr(b.repr() ^ f64::SIGN_MASK)) + crate::float::add::__adddf3(a, f64::from_bits(b.to_bits() ^ f64::SIGN_MASK)) } #[ppc_alias = __subkf3] @@ -21,6 +21,6 @@ intrinsics! { #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] use crate::float::add::__addtf3; - __addtf3(a, f128::from_repr(b.repr() ^ f128::SIGN_MASK)) + __addtf3(a, f128::from_bits(b.to_bits() ^ f128::SIGN_MASK)) } } diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index a25b6eabc5e..6fe44f50b94 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -7,7 +7,6 @@ where F::Int: CastInto, u64: CastInto, u32: CastInto, - R::Int: CastInto, u32: CastInto, F::Int: CastInto, @@ -43,8 +42,8 @@ where let sign_bits_delta = F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS; // Break a into a sign and representation of the absolute value. - let a_abs = a.repr() & src_abs_mask; - let sign = a.repr() & src_sign_mask; + let a_abs = a.to_bits() & src_abs_mask; + let sign = a.to_bits() & src_sign_mask; let mut abs_result: R::Int; if a_abs.wrapping_sub(underflow) < a_abs.wrapping_sub(overflow) { @@ -87,7 +86,7 @@ where let a_exp: u32 = (a_abs >> F::SIGNIFICAND_BITS).cast(); let shift = src_exp_bias - dst_exp_bias - a_exp + 1; - let significand = (a.repr() & src_significand_mask) | src_min_normal; + let significand = (a.to_bits() & src_significand_mask) | src_min_normal; // Right shift by the denormalization amount with sticky. if shift > F::SIGNIFICAND_BITS { @@ -114,7 +113,7 @@ where } // Apply the signbit to the absolute value. - R::from_repr(abs_result | sign.wrapping_shr(src_bits - dst_bits).cast()) + R::from_bits(abs_result | sign.wrapping_shr(src_bits - dst_bits).cast()) } intrinsics! { diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index cc9e73938fb..58419bf1bd0 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -190,7 +190,7 @@ fn fuzz_float_step(rng: &mut Xoshiro128StarStar, f: &mut F) { let tmp = ones.wrapping_shr(r0); (tmp.wrapping_shl(r1) | tmp.wrapping_shr(F::EXPONENT_BITS - r1)) & ones }; - let mut exp = (f.repr() & F::EXPONENT_MASK) >> F::SIGNIFICAND_BITS; + let mut exp = (f.to_bits() & F::EXPONENT_MASK) >> F::SIGNIFICAND_BITS; match (rng32 >> 9) % 4 { 0 => exp |= mask, 1 => exp &= mask, @@ -198,7 +198,7 @@ fn fuzz_float_step(rng: &mut Xoshiro128StarStar, f: &mut F) { } // significand fuzzing - let mut sig = f.repr() & F::SIGNIFICAND_MASK; + let mut sig = f.to_bits() & F::SIGNIFICAND_MASK; fuzz_step(rng, &mut sig); sig &= F::SIGNIFICAND_MASK; -- cgit 1.4.1-3-g733a5 From 394fb9f2bcf0fa2e6d0ab6d0787e7859cdd9e8ac Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 25 Oct 2024 14:30:03 -0500 Subject: Add an `abs` function to the `Float` trait There is no in-crate use for this yet, but we will make use of it in `libm`. --- library/compiler-builtins/src/float/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 5eedf544f12..af83986447e 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -98,6 +98,11 @@ pub(crate) trait Float: /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self; + fn abs(self) -> Self { + let abs_mask = !Self::SIGN_MASK ; + Self::from_bits(self.to_bits() & abs_mask) + } + /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); -- cgit 1.4.1-3-g733a5 From a68516ed6aa0489a1e225277598423f627fd45f4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 25 Oct 2024 20:57:19 -0400 Subject: Rename the `musl-bitwise-tests` feature to `test-musl-serialized` We will have more test features in the near future, and it would be nice for them all to have a common `test-` prefix. Reverse the existing feature so this is the case. --- library/compiler-builtins/libm/CONTRIBUTING.md | 8 ++++---- library/compiler-builtins/libm/ci/run.sh | 4 ++-- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 2 +- library/compiler-builtins/libm/crates/libm-test/build.rs | 4 ++-- .../compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index 1b5235db9ce..a39623696c4 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -7,7 +7,7 @@ in `src/lib.rs`. - Write some simple tests in your module (using `#[test]`) - Run `cargo test` to make sure it works -- Run `cargo test --features libm-test/musl-bitwise-tests` to compare your +- Run `cargo test --features libm-test/test-musl-serialized` to compare your implementation against musl's - Send us a pull request! Make sure to run `cargo fmt` on your code before sending the PR. Also include "closes #42" in the PR description to close the @@ -80,15 +80,15 @@ let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 12 Normal tests can be executed with: -``` +```sh cargo test ``` If you'd like to run tests with randomized inputs that get compared against musl itself, you'll need to be on a Linux system and then you can execute: -``` -cargo test --features libm-test/musl-bitwise-tests +```sh +cargo test --features libm-test/test-musl-serialized ``` Note that you may need to pass `--release` to Cargo if there are errors related diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 1b016cc4fb2..505e2589187 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -18,5 +18,5 @@ $cmd --features 'unstable' $cmd --release --features 'unstable' # also run the reference tests -$cmd --features 'unstable libm-test/musl-bitwise-tests' -$cmd --release --features 'unstable libm-test/musl-bitwise-tests' +$cmd --features 'unstable libm-test/test-musl-serialized' +$cmd --release --features 'unstable libm-test/test-musl-serialized' diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 7c193d3bbca..6367bdca52c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -9,7 +9,7 @@ default = [] # Generate tests which are random inputs and the outputs are calculated with # musl libc. -musl-bitwise-tests = ["rand"] +test-musl-serialized = ["rand"] [dependencies] libm = { path = "../.." } diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index c2c4b0bd28e..3a49e3c5731 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -1,9 +1,9 @@ fn main() { - #[cfg(feature = "musl-bitwise-tests")] + #[cfg(feature = "test-musl-serialized")] musl_reference_tests::generate(); } -#[cfg(feature = "musl-bitwise-tests")] +#[cfg(feature = "test-musl-serialized")] mod musl_reference_tests { use rand::seq::SliceRandom; use rand::Rng; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs b/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs index 1a6b7181709..f586fd03d12 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs @@ -2,5 +2,5 @@ // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 #[cfg(not(target_arch = "powerpc64"))] -#[cfg(all(test, feature = "musl-bitwise-tests"))] +#[cfg(all(test, feature = "test-musl-serialized"))] include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); -- cgit 1.4.1-3-g733a5 From 79bf4fe1f2f527563969276e723511366efaf046 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 00:54:26 -0500 Subject: Don't deny warnings in lib.rs Having `#![deny(warnings)]` for the entire crate is a bit of a development annoyance. We already run CI with `RUSTFLAGS=-Dwarnings` so there isn't much of a reason to check this locally. Thus, remove the attribute. Additionally, sort the clippy allows. --- library/compiler-builtins/libm/src/lib.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 23885ecf8da..04f4ac0f2e1 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,17 +1,16 @@ //! libm in pure Rust -#![deny(warnings)] #![no_std] #![cfg_attr(feature = "unstable", allow(internal_features))] #![cfg_attr(feature = "unstable", feature(core_intrinsics))] -#![allow(clippy::unreadable_literal)] -#![allow(clippy::many_single_char_names)] -#![allow(clippy::needless_return)] -#![allow(clippy::int_plus_one)] +#![allow(clippy::assign_op_pattern)] #![allow(clippy::deprecated_cfg_attr)] -#![allow(clippy::mixed_case_hex_literals)] -#![allow(clippy::float_cmp)] #![allow(clippy::eq_op)] -#![allow(clippy::assign_op_pattern)] +#![allow(clippy::float_cmp)] +#![allow(clippy::int_plus_one)] +#![allow(clippy::many_single_char_names)] +#![allow(clippy::mixed_case_hex_literals)] +#![allow(clippy::needless_return)] +#![allow(clippy::unreadable_literal)] mod libm_helper; mod math; -- cgit 1.4.1-3-g733a5 From bd82e67afc5ac829eba994a3e6f27739a27fa435 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 24 Oct 2024 18:53:46 -0500 Subject: Update licensing to MIT AND (MIT OR Apache-2.0) Currently both Cargo.toml and the license files indicate that this library may be used under either MIT or Apache-2.0. However, this is not accurate; since portions of this library were derived from musl libc, which is available under the MIT license, this terms of use for this library must also include use under the MIT license. That is, it is not correct that this library may be used under only the Apache-2.0 license. Update the SPDX license identifier to `MIT OR (MIT AND Apache-2.0)` to indicate that use must include the MIT license, but to clarify that contributions are made under `MIT OR Apache-2.0`. This is compatible with the current state of this repository since it has always contained both license files, and the `Cargo.toml` license field has indicated `MIT OR Apache-2.0` since it was added. In accordance with the above, replace the two license files with a combined LICENSE.txt that makes these terms clear and gives attribution to works from which this library is derived. Fixes: https://github.com/rust-lang/libm/issues/215 Link: https://rust-lang.zulipchat.com/#narrow/channel/335408-foundation/topic/Request.20for.20legal.20team.20input.20on.20crate.20licensing Link: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT --- library/compiler-builtins/libm/Cargo.toml | 2 +- library/compiler-builtins/libm/LICENSE-APACHE | 201 -------------------- library/compiler-builtins/libm/LICENSE-MIT | 25 --- library/compiler-builtins/libm/LICENSE.txt | 258 ++++++++++++++++++++++++++ library/compiler-builtins/libm/README.md | 19 +- 5 files changed, 269 insertions(+), 236 deletions(-) delete mode 100644 library/compiler-builtins/libm/LICENSE-APACHE delete mode 100644 library/compiler-builtins/libm/LICENSE-MIT create mode 100644 library/compiler-builtins/libm/LICENSE.txt diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 181000f343e..9ae8bd84156 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -4,7 +4,7 @@ categories = ["no-std"] description = "libm in pure Rust" documentation = "https://docs.rs/libm" keywords = ["libm", "math"] -license = "MIT OR Apache-2.0" +license = "MIT AND (MIT OR Apache-2.0)" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" diff --git a/library/compiler-builtins/libm/LICENSE-APACHE b/library/compiler-builtins/libm/LICENSE-APACHE deleted file mode 100644 index 16fe87b06e8..00000000000 --- a/library/compiler-builtins/libm/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/compiler-builtins/libm/LICENSE-MIT b/library/compiler-builtins/libm/LICENSE-MIT deleted file mode 100644 index 432fbea04d3..00000000000 --- a/library/compiler-builtins/libm/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2018 Jorge Aparicio - -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/compiler-builtins/libm/LICENSE.txt b/library/compiler-builtins/libm/LICENSE.txt new file mode 100644 index 00000000000..2f8e41f1474 --- /dev/null +++ b/library/compiler-builtins/libm/LICENSE.txt @@ -0,0 +1,258 @@ +rust-lang/libm as a whole is available for use under the MIT license: + +------------------------------------------------------------------------------ +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. +------------------------------------------------------------------------------ + +As a contributor, you agree that your code can be used under either the MIT +license or the Apache-2.0 license: + +------------------------------------------------------------------------------ + 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. + + 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. +------------------------------------------------------------------------------ + +This Rust library contains the following copyrights: + + Copyright (c) 2018 Jorge Aparicio + +Portions of this software are derived from third-party works licensed under +terms compatible with the above MIT license: + +* musl libc https://www.musl-libc.org/. This library contains the following + copyright: + + Copyright © 2005-2020 Rich Felker, et al. + +* The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH + routines are available under the MIT license on a per-file basis. + +The musl libc COPYRIGHT file also includes the following notice relevant to +math portions of the library: + +------------------------------------------------------------------------------ +Much of the math library code (src/math/* and src/complex/*) is +Copyright © 1993,2004 Sun Microsystems or +Copyright © 2003-2011 David Schultz or +Copyright © 2003-2009 Steven G. Kargl or +Copyright © 2003-2009 Bruce D. Evans or +Copyright © 2008 Stephen L. Moshier or +Copyright © 2017-2018 Arm Limited +and labelled as such in comments in the individual source files. All +have been licensed under extremely permissive terms. +------------------------------------------------------------------------------ + +Copyright notices are retained in src/* files where relevant. diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index b864b5df8e7..24ee3d1c163 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -36,16 +36,17 @@ Please check [CONTRIBUTING.md](CONTRIBUTING.md) ## License -Licensed under either of +Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or +http://opensource.org/licenses/MIT). -- 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 the -work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any -additional terms or conditions. +Contributions are licensed under both the MIT license and the Apache License, +Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or +http://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state +otherwise, any contribution intentionally submitted for inclusion in the work +by you, as defined in the Apache-2.0 license, shall be dual licensed as +mentioned, without any additional terms or conditions. + +See `LICENSE.txt` for full details. -- cgit 1.4.1-3-g733a5 From 6399bed36c0613e6ccb0366bcb7425aa2e64ecbc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 24 Oct 2024 20:13:56 -0500 Subject: Update licensing to MIT AND Apache-2.0 WITH LLVM-exception Currently, Cargo.toml specifies Apache-2.0 OR MIT, but LICENSE.txt describes MIT OR NCSA. compiler-builtins is derived from LLVM's compiler-rt. LICENSE.txt correctly reflects the state of compiler-rt prior to relicensing on 2019-01-19, during which time software was available for use under either MIT or the University of Illinois NCSA license. After relicensing, however, compiler-rt is available for use only under Apache-2.0 with the LLVM exception; this is not reflected anywhere in the repository. Update the SPDX license identifier to `MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)`. Each AND portion covers something specific: * Apache-2.0 WITH LLVM-exception: this covers work that is derived from the LLVM repository since after the LLVM relicensing. * MIT: This covers work that is derived from LLVM before the LLVM relicensing (under MIT OR NCSA), as well as the vendored `libm` components. * MIT AND Apache-2.0: This ensures that any contributions to this repository, in addition to meeting the above required licenses, is also released for use under the Rust-standard Apache-2.0 with no LLVM exception. See also the parallel license update in rust-lang/libm [1]. Fixes: https://github.com/rust-lang/compiler-builtins/issues/307 Closes: https://github.com/rust-lang/compiler-builtins/pull/511 Link: https://rust-lang.zulipchat.com/#narrow/channel/335408-foundation/topic/Request.20for.20legal.20team.20input.20on.20crate.20licensing Link: https://github.com/rust-lang/libm/pull/317 [1] --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/LICENSE.txt | 317 ++++++++++++++++++++++++++-------- 2 files changed, 249 insertions(+), 70 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index ab966b84eb8..c29fe6afe62 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -2,7 +2,7 @@ authors = ["Jorge Aparicio "] name = "compiler_builtins" version = "0.1.135" -license = "MIT/Apache-2.0" +license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" homepage = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/LICENSE.txt b/library/compiler-builtins/LICENSE.txt index 92bbe113ab2..367e3538df0 100644 --- a/library/compiler-builtins/LICENSE.txt +++ b/library/compiler-builtins/LICENSE.txt @@ -1,91 +1,270 @@ -============================================================================== -compiler-builtins License -============================================================================== +compiler-builtins as a whole is available for use under both the MIT license +and the Apache-2.0 license with the LLVM exception (MIT AND Apache-2.0 WITH +LLVM-exception). -The compiler-builtins crate is dual licensed under both the University of -Illinois "BSD-Like" license and the MIT license. As a user of this code you may -choose to use it under either license. As a contributor, you agree to allow -your code to be used under both. +As a contributor, you agree that your code can be used under either the MIT +license, or the Apache-2.0 license, or the Apache-2.0 license with the LLVM +exception. -Full text of the relevant licenses is included below. +Text of the relevant licenses is provided below: -============================================================================== +------------------------------------------------------------------------------ +MIT License -University of Illinois/NCSA -Open Source License +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: -Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -All rights reserved. +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. +------------------------------------------------------------------------------ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Developed by: + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - LLVM Team + 1. Definitions. - University of Illinois at Urbana-Champaign + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. - http://llvm.org + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal with -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: + "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. - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimers. + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimers in the - documentation and/or other materials provided with the distribution. + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. - * Neither the names of the LLVM Team, University of Illinois at - Urbana-Champaign, nor the names of its contributors may be used to - endorse or promote products derived from this Software without specific - prior written permission. + "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. -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 -CONTRIBUTORS 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 WITH THE -SOFTWARE. + "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. -Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT + "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." -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: + "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. -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. + 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. -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. - -============================================================================== -Copyrights and Licenses for Third Party Software Distributed with LLVM: -============================================================================== -The LLVM software contains code written by third parties. Such software will -have its own individual LICENSE.TXT file in the directory in which it appears. -This file will describe the copyrights, license, and restrictions which apply -to that code. - -The disclaimer of warranty in the University of Illinois Open Source License -applies to all code in the LLVM Distribution, and nothing in any of the -other licenses gives permission to use the names of the LLVM Team or the -University of Illinois to endorse or promote products derived from this + 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. + + 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. + + +---- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined Software. +------------------------------------------------------------------------------ + +Portions of this software are derived from third-party works licensed under +terms compatible with the above Apache-2.0 WITH LLVM-exception AND MIT +license: + +* compiler-builtins is derived from LLVM's compiler-rt (https://llvm.org/). + Work derived from compiler-rt prior to 2019-01-19 is usable under the MIT + license, with the following copyright: + + Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT + + The relevant CREDITS.TXT is located at + https://github.com/llvm/llvm-project/blob/main/compiler-rt/CREDITS.TXT. + +* Work derived from compiler-rt after 2019-01-19 is usable under the + Apache-2.0 license with the LLVM exception. + +* The bundled `math` module is from rust-lang/libm, usable under the MIT + license. See https://github.com/rust-lang/libm for details. +Additionally, some source files may contain comments with specific copyrights +or licenses. -- cgit 1.4.1-3-g733a5 From 47961340db34c5c70ea98ed4bfc61cf539a1b68c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 17:57:24 -0500 Subject: Add release-plz for automated releases --- .../libm/.github/workflows/publish.yml | 29 ++++++++++++++++++++++ .../crates/compiler-builtins-smoke-test/Cargo.toml | 1 + .../libm/crates/libm-bench/Cargo.toml | 1 + 3 files changed, 31 insertions(+) create mode 100644 library/compiler-builtins/libm/.github/workflows/publish.yml diff --git a/library/compiler-builtins/libm/.github/workflows/publish.yml b/library/compiler-builtins/libm/.github/workflows/publish.yml new file mode 100644 index 00000000000..1241181a026 --- /dev/null +++ b/library/compiler-builtins/libm/.github/workflows/publish.yml @@ -0,0 +1,29 @@ +name: Release-plz + +permissions: + pull-requests: write + contents: write + +on: + push: + branches: + - master + +jobs: + release-plz: + name: Release-plz + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install Rust (rustup) + run: rustup update nightly --no-self-update && rustup default nightly + - name: Publish `libm` as part of builtins, rather than its own crate + run: rm libm/Cargo.toml + - name: Run release-plz + uses: MarcoIeni/release-plz-action@v0.5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 4bc62304a9d..8d084ee341e 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -3,6 +3,7 @@ name = "cb" version = "0.1.0" authors = ["Jorge Aparicio "] edition = "2021" +publish = false [lib] test = false diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml index 282752c6183..ee8c5820037 100644 --- a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Gonzalo Brito Gadeschi "] edition = "2021" license = "MIT OR Apache-2.0" +publish = false [dependencies] libm = { path = "../..", default-features = false } -- cgit 1.4.1-3-g733a5 From 0433caa0ba6f8c5fc4231e6944af6b4bd943ecd6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 18:01:56 -0500 Subject: Fix release-plz workflow configuration --- library/compiler-builtins/libm/.github/workflows/publish.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/publish.yml b/library/compiler-builtins/libm/.github/workflows/publish.yml index 1241181a026..e715c61871f 100644 --- a/library/compiler-builtins/libm/.github/workflows/publish.yml +++ b/library/compiler-builtins/libm/.github/workflows/publish.yml @@ -20,8 +20,6 @@ jobs: fetch-depth: 0 - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly - - name: Publish `libm` as part of builtins, rather than its own crate - run: rm libm/Cargo.toml - name: Run release-plz uses: MarcoIeni/release-plz-action@v0.5 env: -- cgit 1.4.1-3-g733a5 From 4f3418a4d77ba4cfb4e55055e87ab78173a0ca65 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 23:04:46 +0000 Subject: chore: release v0.2.9 --- library/compiler-builtins/libm/CHANGELOG.md | 39 ++++++++++++++++++++++++++--- library/compiler-builtins/libm/Cargo.toml | 2 +- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index e8e9acf9b5c..36ed41d6ba5 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -1,20 +1,50 @@ -# Change Log +# Changelog All notable changes to this project will be documented in this file. -This project adheres to [Semantic Versioning](http://semver.org/). + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to +[Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] -... +## [0.2.9](https://github.com/rust-lang/libm/compare/libm-v0.2.8...libm-v0.2.9) - 2024-10-26 + +### Fixed + +- Update exponent calculations in nextafter to match musl + +### Changed + +- Update licensing to MIT AND (MIT OR Apache-2.0), as this is derivative from + MIT-licensed musl. +- Set edition to 2021 for all crates +- Upgrade all dependencies + +### Other + +- Don't deny warnings in lib.rs +- Rename the `musl-bitwise-tests` feature to `test-musl-serialized` +- Rename the `musl-reference-tests` feature to `musl-bitwise-tests` +- Move `musl-reference-tests` to a new `libm-test` crate +- Add a `force-soft-floats` feature to prevent using any intrinsics or + arch-specific code +- Deny warnings in CI +- Fix `clippy::deprecated_cfg_attr` on compiler_builtins +- Corrected English typos +- Remove unneeded `extern core` in `tgamma` +- Allow internal_features lint when building with "unstable" ## [v0.2.1] - 2019-11-22 ### Fixed + - sincosf ## [v0.2.0] - 2019-10-18 ### Added + - Benchmarks - signum - remainder @@ -23,17 +53,20 @@ This project adheres to [Semantic Versioning](http://semver.org/). - nextafterf ### Fixed + - Rounding to negative zero - Overflows in rem_pio2 and remquo - Overflows in fma - sincosf ### Removed + - F32Ext and F64Ext traits ## [v0.1.4] - 2019-06-12 ### Fixed + - Restored compatibility with Rust 1.31.0 ## [v0.1.3] - 2019-05-14 diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 9ae8bd84156..f04fc12df4d 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT AND (MIT OR Apache-2.0)" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.8" +version = "0.2.9" edition = "2021" exclude = ["/ci/", "/.github/workflows/"] -- cgit 1.4.1-3-g733a5 From 01a2a13a01ba323791bd2b229bebeda1726a45d8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 18:19:18 -0500 Subject: Update the libm submodule --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 300edb32520..f4e5b38aee0 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 300edb32520b1673e16d2411a0e2e6273959eb46 +Subproject commit f4e5b38aee0e0c592a82ed45b21cd068c9b6c89a -- cgit 1.4.1-3-g733a5 From f9914e98b3cb55af066ac3062d16d4ae504c53d0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 23:29:14 +0000 Subject: chore: release v0.1.136 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c29fe6afe62..4a85e5215b2 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.135" +version = "0.1.136" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 710ca6e38ecde09939c51a81752ae27d966ae974 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 20:18:50 -0500 Subject: Add a rustfmt.toml file matching rust-lang/rust Duplicate the settings from rust-lang/rust to this repository. This is mostly for consistency, but `use_small_heuristics = "Max"` does make a large difference with lookup tables. Also apply the needed CI changes to run nightly rustfmt. --- library/compiler-builtins/libm/.github/workflows/main.yml | 2 +- library/compiler-builtins/libm/.rustfmt.toml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/.rustfmt.toml diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 322043d85af..f312e1f5e67 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -41,7 +41,7 @@ jobs: steps: - uses: actions/checkout@master - name: Install Rust - run: rustup update stable && rustup default stable && rustup component add rustfmt + run: rustup update nightly && rustup default nightly && rustup component add rustfmt - run: cargo fmt -- --check wasm: diff --git a/library/compiler-builtins/libm/.rustfmt.toml b/library/compiler-builtins/libm/.rustfmt.toml new file mode 100644 index 00000000000..c73bb9301e3 --- /dev/null +++ b/library/compiler-builtins/libm/.rustfmt.toml @@ -0,0 +1,5 @@ +# This matches rustc +style_edition = "2024" +use_small_heuristics = "Max" +group_imports = "StdExternalCrate" +imports_granularity = "Module" -- cgit 1.4.1-3-g733a5 From ab0c8e84fb3b76136aa38b800a17c0f97fa469a7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 20:22:24 -0500 Subject: Run `cargo fmt` with new settings Apply the changes from the `.rustfmt.toml` file added in the previous commit. --- .../libm/crates/libm-test/build.rs | 43 +++++-------------- library/compiler-builtins/libm/src/lib.rs | 15 ++----- library/compiler-builtins/libm/src/math/asin.rs | 6 +-- library/compiler-builtins/libm/src/math/asinf.rs | 6 +-- library/compiler-builtins/libm/src/math/asinh.rs | 6 +-- library/compiler-builtins/libm/src/math/asinhf.rs | 6 +-- library/compiler-builtins/libm/src/math/atan.rs | 12 +++--- library/compiler-builtins/libm/src/math/atan2.rs | 3 +- library/compiler-builtins/libm/src/math/atan2f.rs | 3 +- library/compiler-builtins/libm/src/math/atanf.rs | 15 ++----- library/compiler-builtins/libm/src/math/atanh.rs | 6 +-- library/compiler-builtins/libm/src/math/atanhf.rs | 6 +-- library/compiler-builtins/libm/src/math/ceil.rs | 15 ++----- library/compiler-builtins/libm/src/math/ceilf.rs | 3 +- library/compiler-builtins/libm/src/math/cosf.rs | 4 +- library/compiler-builtins/libm/src/math/cosh.rs | 4 +- library/compiler-builtins/libm/src/math/coshf.rs | 4 +- library/compiler-builtins/libm/src/math/erf.rs | 12 +----- library/compiler-builtins/libm/src/math/erff.rs | 12 +----- library/compiler-builtins/libm/src/math/exp.rs | 6 +-- library/compiler-builtins/libm/src/math/exp10f.rs | 5 +-- library/compiler-builtins/libm/src/math/expf.rs | 6 +-- library/compiler-builtins/libm/src/math/expm1f.rs | 6 +-- library/compiler-builtins/libm/src/math/fabs.rs | 3 +- library/compiler-builtins/libm/src/math/fabsf.rs | 3 +- library/compiler-builtins/libm/src/math/floor.rs | 15 ++----- library/compiler-builtins/libm/src/math/floorf.rs | 3 +- library/compiler-builtins/libm/src/math/fma.rs | 10 +---- library/compiler-builtins/libm/src/math/fmaf.rs | 8 +--- library/compiler-builtins/libm/src/math/fmodf.rs | 3 +- library/compiler-builtins/libm/src/math/ilogb.rs | 6 +-- library/compiler-builtins/libm/src/math/ilogbf.rs | 6 +-- library/compiler-builtins/libm/src/math/jn.rs | 12 +----- library/compiler-builtins/libm/src/math/jnf.rs | 12 +----- library/compiler-builtins/libm/src/math/k_sin.rs | 6 +-- library/compiler-builtins/libm/src/math/log1p.rs | 6 +-- library/compiler-builtins/libm/src/math/log1pf.rs | 6 +-- library/compiler-builtins/libm/src/math/mod.rs | 32 ++++++-------- library/compiler-builtins/libm/src/math/pow.rs | 50 ++++++---------------- library/compiler-builtins/libm/src/math/powf.rs | 12 +----- .../compiler-builtins/libm/src/math/rem_pio2.rs | 20 ++------- .../libm/src/math/rem_pio2_large.rs | 3 +- .../compiler-builtins/libm/src/math/rem_pio2f.rs | 4 +- library/compiler-builtins/libm/src/math/remquo.rs | 6 +-- library/compiler-builtins/libm/src/math/remquof.rs | 6 +-- library/compiler-builtins/libm/src/math/rint.rs | 10 +---- library/compiler-builtins/libm/src/math/rintf.rs | 10 +---- library/compiler-builtins/libm/src/math/round.rs | 4 +- library/compiler-builtins/libm/src/math/roundf.rs | 4 +- library/compiler-builtins/libm/src/math/sinf.rs | 16 ++----- library/compiler-builtins/libm/src/math/sinhf.rs | 3 +- library/compiler-builtins/libm/src/math/sqrt.rs | 3 +- library/compiler-builtins/libm/src/math/sqrtf.rs | 10 ++--- library/compiler-builtins/libm/src/math/tan.rs | 6 +-- library/compiler-builtins/libm/src/math/tanf.rs | 10 ++--- library/compiler-builtins/libm/src/math/tanh.rs | 6 +-- library/compiler-builtins/libm/src/math/tanhf.rs | 6 +-- 57 files changed, 131 insertions(+), 393 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index 3a49e3c5731..9653bd83013 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -5,12 +5,12 @@ fn main() { #[cfg(feature = "test-musl-serialized")] mod musl_reference_tests { - use rand::seq::SliceRandom; - use rand::Rng; - use std::env; - use std::fs; use std::path::PathBuf; use std::process::Command; + use std::{env, fs}; + + use rand::Rng; + use rand::seq::SliceRandom; // Number of tests to generate for each function const NTESTS: usize = 500; @@ -60,10 +60,7 @@ mod musl_reference_tests { return; } - let files = fs::read_dir(math_src) - .unwrap() - .map(|f| f.unwrap().path()) - .collect::>(); + let files = fs::read_dir(math_src).unwrap().map(|f| f.unwrap().path()).collect::>(); let mut math = Vec::new(); for file in files { @@ -112,12 +109,7 @@ mod musl_reference_tests { let tail = eat(tail, " -> "); let ret = parse_retty(tail.replace("{", "").trim()); - return Function { - name: name.to_string(), - args, - ret, - tests: Vec::new(), - }; + return Function { name: name.to_string(), args, ret, tests: Vec::new() }; fn parse_ty(s: &str) -> Ty { match s { @@ -156,11 +148,7 @@ mod musl_reference_tests { } fn generate_test(function: &Function, rng: &mut R) -> Test { - let mut inputs = function - .args - .iter() - .map(|ty| ty.gen_i64(rng)) - .collect::>(); + let mut inputs = function.args.iter().map(|ty| ty.gen_i64(rng)).collect::>(); // First argument to this function appears to be a number of // iterations, so passing in massive random numbers causes it to @@ -180,15 +168,12 @@ mod musl_reference_tests { impl Ty { fn gen_i64(&self, r: &mut R) -> i64 { - use std::f32; - use std::f64; + use std::{f32, f64}; return match self { Ty::F32 => { if r.gen_range(0..20) < 1 { - let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY] - .choose(r) - .unwrap(); + let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY].choose(r).unwrap(); i.to_bits().into() } else { r.gen::().to_bits().into() @@ -196,9 +181,7 @@ mod musl_reference_tests { } Ty::F64 => { if r.gen_range(0..20) < 1 { - let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY] - .choose(r) - .unwrap(); + let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY].choose(r).unwrap(); i.to_bits() as i64 } else { r.gen::().to_bits() as i64 @@ -424,11 +407,7 @@ mod musl_reference_tests { src.push_str(");"); for (i, ret) in function.ret.iter().enumerate() { - let get = if function.ret.len() == 1 { - String::new() - } else { - format!(".{}", i) - }; + let get = if function.ret.len() == 1 { String::new() } else { format!(".{}", i) }; src.push_str(&(match ret { Ty::F32 => format!("if libm::_eqf(output{}, f32::from_bits(expected[{}] as u32)).is_ok() {{ continue }}", get, i), Ty::F64 => format!("if libm::_eq(output{}, f64::from_bits(expected[{}] as u64)).is_ok() {{ continue }}", get, i), diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 04f4ac0f2e1..6d95fa1737b 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -17,9 +17,10 @@ mod math; use core::{f32, f64}; -pub use self::math::*; pub use libm_helper::*; +pub use self::math::*; + /// Approximate equality with 1 ULP of tolerance #[doc(hidden)] #[inline] @@ -29,11 +30,7 @@ pub fn _eqf(a: f32, b: f32) -> Result<(), u32> { } else { let err = (a.to_bits() as i32).wrapping_sub(b.to_bits() as i32).abs(); - if err <= 1 { - Ok(()) - } else { - Err(err as u32) - } + if err <= 1 { Ok(()) } else { Err(err as u32) } } } @@ -45,10 +42,6 @@ pub fn _eq(a: f64, b: f64) -> Result<(), u64> { } else { let err = (a.to_bits() as i64).wrapping_sub(b.to_bits() as i64).abs(); - if err <= 1 { - Ok(()) - } else { - Err(err as u64) - } + if err <= 1 { Ok(()) } else { Err(err as u64) } } } diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs index 3e4b7c56eba..12fe08fc745 100644 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -111,9 +111,5 @@ pub fn asin(mut x: f64) -> f64 { c = (z - f * f) / (s + f); x = 0.5 * PIO2_HI - (2.0 * s * r - (PIO2_LO - 2.0 * c) - (0.5 * PIO2_HI - 2.0 * f)); } - if hx >> 31 != 0 { - -x - } else { - x - } + if hx >> 31 != 0 { -x } else { x } } diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index 6ec61b62978..2c785abe2ba 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -64,9 +64,5 @@ pub fn asinf(mut x: f32) -> f32 { let z = (1. - fabsf(x)) * 0.5; let s = sqrt(z as f64); x = (PIO2 - 2. * (s + s * (r(z) as f64))) as f32; - if (hx >> 31) != 0 { - -x - } else { - x - } + if (hx >> 31) != 0 { -x } else { x } } diff --git a/library/compiler-builtins/libm/src/math/asinh.rs b/library/compiler-builtins/libm/src/math/asinh.rs index 0abd80c2fd7..75d3c3ad462 100644 --- a/library/compiler-builtins/libm/src/math/asinh.rs +++ b/library/compiler-builtins/libm/src/math/asinh.rs @@ -32,9 +32,5 @@ pub fn asinh(mut x: f64) -> f64 { force_eval!(x + x1p120); } - if sign { - -x - } else { - x - } + if sign { -x } else { x } } diff --git a/library/compiler-builtins/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/src/math/asinhf.rs index 09c77823e10..27ed9dd372d 100644 --- a/library/compiler-builtins/libm/src/math/asinhf.rs +++ b/library/compiler-builtins/libm/src/math/asinhf.rs @@ -31,9 +31,5 @@ pub fn asinhf(mut x: f32) -> f32 { force_eval!(x + x1p120); } - if sign { - -x - } else { - x - } + if sign { -x } else { x } } diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index 4259dc71aab..4ca5cc91a1e 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -29,9 +29,10 @@ * to produce the hexadecimal values shown. */ -use super::fabs; use core::f64; +use super::fabs; + const ATANHI: [f64; 4] = [ 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ @@ -128,18 +129,15 @@ pub fn atan(x: f64) -> f64 { let z = i!(ATANHI, id as usize) - (x * (s1 + s2) - i!(ATANLO, id as usize) - x); - if sign != 0 { - -z - } else { - z - } + if sign != 0 { -z } else { z } } #[cfg(test)] mod tests { - use super::atan; use core::f64; + use super::atan; + #[test] fn sanity_check() { for (input, answer) in [ diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index fb2ea4edaf5..b9bf0da935b 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -37,8 +37,7 @@ * to produce the hexadecimal values shown. */ -use super::atan; -use super::fabs; +use super::{atan, fabs}; const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs index eae3b002dae..fa33f54f6f7 100644 --- a/library/compiler-builtins/libm/src/math/atan2f.rs +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -13,8 +13,7 @@ * ==================================================== */ -use super::atanf; -use super::fabsf; +use super::{atanf, fabsf}; const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index d042b3bc0fd..eb3d401cd96 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -29,13 +29,8 @@ const ATAN_LO: [f32; 4] = [ 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ ]; -const A_T: [f32; 5] = [ - 3.3333328366e-01, - -1.9999158382e-01, - 1.4253635705e-01, - -1.0648017377e-01, - 6.1687607318e-02, -]; +const A_T: [f32; 5] = + [3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, -1.0648017377e-01, 6.1687607318e-02]; /// Arctangent (f32) /// @@ -104,9 +99,5 @@ pub fn atanf(mut x: f32) -> f32 { } let id = id as usize; let z = i!(ATAN_HI, id) - ((x * (s1 + s2) - i!(ATAN_LO, id)) - x); - if sign { - -z - } else { - z - } + if sign { -z } else { z } } diff --git a/library/compiler-builtins/libm/src/math/atanh.rs b/library/compiler-builtins/libm/src/math/atanh.rs index b984c4ac628..9dc826f5605 100644 --- a/library/compiler-builtins/libm/src/math/atanh.rs +++ b/library/compiler-builtins/libm/src/math/atanh.rs @@ -29,9 +29,5 @@ pub fn atanh(x: f64) -> f64 { y = 0.5 * log1p(2.0 * (y / (1.0 - y))); } - if sign { - -y - } else { - y - } + if sign { -y } else { y } } diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs index a1aa314a50f..3545411bbd5 100644 --- a/library/compiler-builtins/libm/src/math/atanhf.rs +++ b/library/compiler-builtins/libm/src/math/atanhf.rs @@ -29,9 +29,5 @@ pub fn atanhf(mut x: f32) -> f32 { x = 0.5 * log1pf(2.0 * (x / (1.0 - x))); } - if sign { - -x - } else { - x - } + if sign { -x } else { x } } diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index cde5a19d0c8..1593fdaffce 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -42,28 +42,21 @@ pub fn ceil(x: f64) -> f64 { return x; } // y = int(x) - x, where int(x) is an integer neighbor of x - y = if (u >> 63) != 0 { - x - TOINT + TOINT - x - } else { - x + TOINT - TOINT - x - }; + y = if (u >> 63) != 0 { x - TOINT + TOINT - x } else { x + TOINT - TOINT - x }; // special case because of non-nearest rounding modes if e < 0x3ff { force_eval!(y); return if (u >> 63) != 0 { -0. } else { 1. }; } - if y < 0. { - x + y + 1. - } else { - x + y - } + if y < 0. { x + y + 1. } else { x + y } } #[cfg(test)] mod tests { - use super::*; use core::f64::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(ceil(1.1), 2.0); diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 7bcc647ca76..bf9ba12279c 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -44,9 +44,10 @@ pub fn ceilf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use super::*; use core::f32::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(ceilf(1.1), 2.0); diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index 424fa42eda6..0a01335f770 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -14,10 +14,10 @@ * ==================================================== */ -use super::{k_cosf, k_sinf, rem_pio2f}; - use core::f64::consts::FRAC_PI_2; +use super::{k_cosf, k_sinf, rem_pio2f}; + /* Small multiples of pi/2 rounded to double precision. */ const C1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs index 2fb568ab314..d2e43fd6cb6 100644 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -1,6 +1,4 @@ -use super::exp; -use super::expm1; -use super::k_expo2; +use super::{exp, expm1, k_expo2}; /// Hyperbolic cosine (f64) /// diff --git a/library/compiler-builtins/libm/src/math/coshf.rs b/library/compiler-builtins/libm/src/math/coshf.rs index e7b68458788..567a24410e7 100644 --- a/library/compiler-builtins/libm/src/math/coshf.rs +++ b/library/compiler-builtins/libm/src/math/coshf.rs @@ -1,6 +1,4 @@ -use super::expf; -use super::expm1f; -use super::k_expo2f; +use super::{expf, expm1f, k_expo2f}; /// Hyperbolic cosine (f64) /// diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs index 55569affc97..1b634abec6b 100644 --- a/library/compiler-builtins/libm/src/math/erf.rs +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -256,11 +256,7 @@ pub fn erf(x: f64) -> f64 { y = 1.0 - x1p_1022; } - if sign != 0 { - -y - } else { - y - } + if sign != 0 { -y } else { y } } /// Complementary error function (f64) @@ -310,9 +306,5 @@ pub fn erfc(x: f64) -> f64 { } let x1p_1022 = f64::from_bits(0x0010000000000000); - if sign != 0 { - 2.0 - x1p_1022 - } else { - x1p_1022 * x1p_1022 - } + if sign != 0 { 2.0 - x1p_1022 } else { x1p_1022 * x1p_1022 } } diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs index 7b25474f602..2e41183bfc0 100644 --- a/library/compiler-builtins/libm/src/math/erff.rs +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -167,11 +167,7 @@ pub fn erff(x: f32) -> f32 { y = 1.0 - x1p_120; } - if sign != 0 { - -y - } else { - y - } + if sign != 0 { -y } else { y } } /// Complementary error function (f32) @@ -222,9 +218,5 @@ pub fn erfcf(x: f32) -> f32 { } let x1p_120 = f32::from_bits(0x03800000); - if sign != 0 { - 2.0 - x1p_120 - } else { - x1p_120 * x1p_120 - } + if sign != 0 { 2.0 - x1p_120 } else { x1p_120 * x1p_120 } } diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs index d4994277f89..782042b62cd 100644 --- a/library/compiler-builtins/libm/src/math/exp.rs +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -146,9 +146,5 @@ pub fn exp(mut x: f64) -> f64 { xx = x * x; c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); y = 1. + (x * c / (2. - c) - lo + hi); - if k == 0 { - y - } else { - scalbn(y, k) - } + if k == 0 { y } else { scalbn(y, k) } } diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs index 1279bc6c566..786305481dc 100644 --- a/library/compiler-builtins/libm/src/math/exp10f.rs +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -2,9 +2,8 @@ use super::{exp2, exp2f, modff}; const LN10_F32: f32 = 3.32192809488736234787031942948939; const LN10_F64: f64 = 3.32192809488736234787031942948939; -const P10: &[f32] = &[ - 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, -]; +const P10: &[f32] = + &[1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7]; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp10f(x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index a53aa90a646..8dc067ab084 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -93,9 +93,5 @@ pub fn expf(mut x: f32) -> f32 { let xx = x * x; let c = x - xx * (P1 + xx * P2); let y = 1. + (x * c / (2. - c) - lo + hi); - if k == 0 { - y - } else { - scalbnf(y, k) - } + if k == 0 { y } else { scalbnf(y, k) } } diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs index 3fc2a247b5b..a862fe2558c 100644 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -126,9 +126,5 @@ pub fn expm1f(mut x: f32) -> f32 { return y - 1.; } let uf = f32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */ - if k < 23 { - (x - e + (1. - uf)) * twopk - } else { - (x - (e + uf) + 1.) * twopk - } + if k < 23 { (x - e + (1. - uf)) * twopk } else { (x - (e + uf) + 1.) * twopk } } diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index b2255ad32cf..3b0628aa63a 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -18,9 +18,10 @@ pub fn fabs(x: f64) -> f64 { #[cfg(test)] mod tests { - use super::*; use core::f64::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(fabs(-1.0), 1.0); diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 23f3646dc4a..f81c8ca4423 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -18,9 +18,10 @@ pub fn fabsf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use super::*; use core::f32::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(fabsf(-1.0), 1.0); diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index b7d1a04d2cd..e8fb21e5884 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -41,28 +41,21 @@ pub fn floor(x: f64) -> f64 { return x; } /* y = int(x) - x, where int(x) is an integer neighbor of x */ - let y = if (ui >> 63) != 0 { - x - TOINT + TOINT - x - } else { - x + TOINT - TOINT - x - }; + let y = if (ui >> 63) != 0 { x - TOINT + TOINT - x } else { x + TOINT - TOINT - x }; /* special case because of non-nearest rounding modes */ if e < 0x3ff { force_eval!(y); return if (ui >> 63) != 0 { -1. } else { 0. }; } - if y > 0. { - x + y - 1. - } else { - x + y - } + if y > 0. { x + y - 1. } else { x + y } } #[cfg(test)] mod tests { - use super::*; use core::f64::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(floor(1.1), 1.0); diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index dfdab91a0f6..f66cab74fdc 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -44,9 +44,10 @@ pub fn floorf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use super::*; use core::f32::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(floorf(0.5), 0.0); diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 940ee2db927..bb2028fa77f 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -216,17 +216,11 @@ mod tests { #[test] fn fma_sbb() { - assert_eq!( - fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), - -3991680619069439e277 - ); + assert_eq!(fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), -3991680619069439e277); } #[test] fn fma_underflow() { - assert_eq!( - fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), - 0.0, - ); + assert_eq!(fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), 0.0,); } } diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index 2848f2aee0c..10bdaeab33d 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -29,7 +29,7 @@ use core::f32; use core::ptr::read_volatile; use super::fenv::{ - feclearexcept, fegetround, feraiseexcept, fetestexcept, FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, + FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, feclearexcept, fegetround, feraiseexcept, fetestexcept, }; /* @@ -91,11 +91,7 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { * we need to adjust the low-order bit in the direction of the error. */ let neg = ui >> 63 != 0; - let err = if neg == (z as f64 > xy) { - xy - result + z as f64 - } else { - z as f64 - result + xy - }; + let err = if neg == (z as f64 > xy) { xy - result + z as f64 } else { z as f64 - result + xy }; if neg == (err < 0.0) { ui += 1; } else { diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index c53dc186aeb..1d80013842e 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -1,5 +1,4 @@ -use core::f32; -use core::u32; +use core::{f32, u32}; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmodf(x: f32, y: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs index 7d74dcfb666..9d58d06081b 100644 --- a/library/compiler-builtins/libm/src/math/ilogb.rs +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -21,11 +21,7 @@ pub fn ilogb(x: f64) -> i32 { e } else if e == 0x7ff { force_eval!(0.0 / 0.0); - if (i << 12) != 0 { - FP_ILOGBNAN - } else { - i32::max_value() - } + if (i << 12) != 0 { FP_ILOGBNAN } else { i32::max_value() } } else { e - 0x3ff } diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs index 0fa58748c2f..85deb43c83b 100644 --- a/library/compiler-builtins/libm/src/math/ilogbf.rs +++ b/library/compiler-builtins/libm/src/math/ilogbf.rs @@ -21,11 +21,7 @@ pub fn ilogbf(x: f32) -> i32 { e } else if e == 0xff { force_eval!(0.0 / 0.0); - if (i << 9) != 0 { - FP_ILOGBNAN - } else { - i32::max_value() - } + if (i << 9) != 0 { FP_ILOGBNAN } else { i32::max_value() } } else { e - 0x7f } diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs index 1be167f8461..22ced20c15a 100644 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -244,11 +244,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { } } - if sign { - -b - } else { - b - } + if sign { -b } else { b } } pub fn yn(n: i32, x: f64) -> f64 { @@ -335,9 +331,5 @@ pub fn yn(n: i32, x: f64) -> f64 { } } - if sign { - -b - } else { - b - } + if sign { -b } else { b } } diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs index 360f62e201d..9cd0bb37de9 100644 --- a/library/compiler-builtins/libm/src/math/jnf.rs +++ b/library/compiler-builtins/libm/src/math/jnf.rs @@ -188,11 +188,7 @@ pub fn jnf(n: i32, mut x: f32) -> f32 { } } - if sign { - -b - } else { - b - } + if sign { -b } else { b } } pub fn ynf(n: i32, x: f32) -> f32 { @@ -251,9 +247,5 @@ pub fn ynf(n: i32, x: f32) -> f32 { a = temp; } - if sign { - -b - } else { - b - } + if sign { -b } else { b } } diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs index 9dd96c94474..42441455ff3 100644 --- a/library/compiler-builtins/libm/src/math/k_sin.rs +++ b/library/compiler-builtins/libm/src/math/k_sin.rs @@ -49,9 +49,5 @@ pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { let w = z * z; let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); let v = z * x; - if iy == 0 { - x + v * (S1 + z * r) - } else { - x - ((z * (0.5 * y - v * r) - y) - v * S1) - } + if iy == 0 { x + v * (S1 + z * r) } else { x - ((z * (0.5 * y - v * r) - y) - v * S1) } } diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index 4fd1c73eb81..552de549bfc 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -117,11 +117,7 @@ pub fn log1p(x: f64) -> f64 { k = (hu >> 20) as i32 - 0x3ff; /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ if k < 54 { - c = if k >= 2 { - 1. - (f64::from_bits(ui) - x) - } else { - x - (f64::from_bits(ui) - 1.) - }; + c = if k >= 2 { 1. - (f64::from_bits(ui) - x) } else { x - (f64::from_bits(ui) - 1.) }; c /= f64::from_bits(ui); } else { c = 0.; diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index 500e8eeaa85..8068128db4f 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -72,11 +72,7 @@ pub fn log1pf(x: f32) -> f32 { k = (iu >> 23) as i32 - 0x7f; /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ if k < 25 { - c = if k >= 2 { - 1. - (f32::from_bits(ui) - x) - } else { - x - (f32::from_bits(ui) - 1.) - }; + c = if k >= 2 { 1. - (f32::from_bits(ui) - x) } else { x - (f32::from_bits(ui) - 1.) }; c /= f32::from_bits(ui); } else { c = 0.; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index a56532dddc1..85c9fc5bf15 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -218,15 +218,13 @@ pub use self::cos::cos; pub use self::cosf::cosf; pub use self::cosh::cosh; pub use self::coshf::coshf; -pub use self::erf::erf; -pub use self::erf::erfc; -pub use self::erff::erfcf; -pub use self::erff::erff; +pub use self::erf::{erf, erfc}; +pub use self::erff::{erfcf, erff}; pub use self::exp::exp; -pub use self::exp10::exp10; -pub use self::exp10f::exp10f; pub use self::exp2::exp2; pub use self::exp2f::exp2f; +pub use self::exp10::exp10; +pub use self::exp10f::exp10f; pub use self::expf::expf; pub use self::expm1::expm1; pub use self::expm1f::expm1f; @@ -250,18 +248,12 @@ pub use self::hypot::hypot; pub use self::hypotf::hypotf; pub use self::ilogb::ilogb; pub use self::ilogbf::ilogbf; -pub use self::j0::j0; -pub use self::j0::y0; -pub use self::j0f::j0f; -pub use self::j0f::y0f; -pub use self::j1::j1; -pub use self::j1::y1; -pub use self::j1f::j1f; -pub use self::j1f::y1f; -pub use self::jn::jn; -pub use self::jn::yn; -pub use self::jnf::jnf; -pub use self::jnf::ynf; +pub use self::j0::{j0, y0}; +pub use self::j0f::{j0f, y0f}; +pub use self::j1::{j1, y1}; +pub use self::j1f::{j1f, y1f}; +pub use self::jn::{jn, yn}; +pub use self::jnf::{jnf, ynf}; pub use self::ldexp::ldexp; pub use self::ldexpf::ldexpf; pub use self::lgamma::lgamma; @@ -269,12 +261,12 @@ pub use self::lgamma_r::lgamma_r; pub use self::lgammaf::lgammaf; pub use self::lgammaf_r::lgammaf_r; pub use self::log::log; -pub use self::log10::log10; -pub use self::log10f::log10f; pub use self::log1p::log1p; pub use self::log1pf::log1pf; pub use self::log2::log2; pub use self::log2f::log2f; +pub use self::log10::log10; +pub use self::log10f::log10f; pub use self::logf::logf; pub use self::modf::modf; pub use self::modff::modff; diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 09d12c1851b..9b617cadbfe 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -159,18 +159,10 @@ pub fn pow(x: f64, y: f64) -> f64 { 1.0 } else if ix >= 0x3ff00000 { /* (|x|>1)**+-inf = inf,0 */ - if hy >= 0 { - y - } else { - 0.0 - } + if hy >= 0 { y } else { 0.0 } } else { /* (|x|<1)**+-inf = 0,inf */ - if hy >= 0 { - 0.0 - } else { - -y - } + if hy >= 0 { 0.0 } else { -y } }; } @@ -246,18 +238,10 @@ pub fn pow(x: f64, y: f64) -> f64 { /* over/underflow if x is not close to one */ if ix < 0x3fefffff { - return if hy < 0 { - s * HUGE * HUGE - } else { - s * TINY * TINY - }; + return if hy < 0 { s * HUGE * HUGE } else { s * TINY * TINY }; } if ix > 0x3ff00000 { - return if hy > 0 { - s * HUGE * HUGE - } else { - s * TINY * TINY - }; + return if hy > 0 { s * HUGE * HUGE } else { s * TINY * TINY }; } /* now |1-x| is TINY <= 2**-20, suffice to compute @@ -455,11 +439,7 @@ mod tests { fn pow_test(base: f64, exponent: f64, expected: f64) { let res = pow(base, exponent); assert!( - if expected.is_nan() { - res.is_nan() - } else { - pow(base, exponent) == expected - }, + if expected.is_nan() { res.is_nan() } else { pow(base, exponent) == expected }, "{} ** {} was {} instead of {}", base, exponent, @@ -469,13 +449,11 @@ mod tests { } fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { - sets.iter() - .for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); + sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); } fn test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) { - sets.iter() - .for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); + sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); } fn test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) { @@ -489,11 +467,7 @@ mod tests { #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] let res = force_eval!(res); assert!( - if exp.is_nan() { - res.is_nan() - } else { - exp == res - }, + if exp.is_nan() { res.is_nan() } else { exp == res }, "test for {} was {} instead of {}", val, res, @@ -608,15 +582,15 @@ mod tests { // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - (&[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS]) - .iter() - .for_each(|int_set| { + (&[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS]).iter().for_each( + |int_set| { int_set.iter().for_each(|int| { test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| { pow(-1.0, *int) * pow(v, *int) }); }) - }); + }, + ); // Negative base (imaginary results): // (-anything except 0 and Infinity ^ non-integer should be NAN) diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index 68d2083bbdd..d47ab4b3d1d 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -181,19 +181,11 @@ pub fn powf(x: f32, y: f32) -> f32 { /* if |y| > 2**27 */ /* over/underflow if x is not close to one */ if ix < 0x3f7ffff8 { - return if hy < 0 { - sn * HUGE * HUGE - } else { - sn * TINY * TINY - }; + return if hy < 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; } if ix > 0x3f800007 { - return if hy > 0 { - sn * HUGE * HUGE - } else { - sn * TINY * TINY - }; + return if hy > 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; } /* now |1-x| is TINY <= 2**-20, suffice to compute diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 644616f2df8..6be23a43ced 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -197,28 +197,16 @@ mod tests { fn test_near_pi() { let arg = 3.141592025756836; let arg = force_eval!(arg); - assert_eq!( - rem_pio2(arg), - (2, -6.278329573009626e-7, -2.1125998133974653e-23) - ); + assert_eq!(rem_pio2(arg), (2, -6.278329573009626e-7, -2.1125998133974653e-23)); let arg = 3.141592033207416; let arg = force_eval!(arg); - assert_eq!( - rem_pio2(arg), - (2, -6.20382377148128e-7, -2.1125998133974653e-23) - ); + assert_eq!(rem_pio2(arg), (2, -6.20382377148128e-7, -2.1125998133974653e-23)); let arg = 3.141592144966125; let arg = force_eval!(arg); - assert_eq!( - rem_pio2(arg), - (2, -5.086236681942706e-7, -2.1125998133974653e-23) - ); + assert_eq!(rem_pio2(arg), (2, -5.086236681942706e-7, -2.1125998133974653e-23)); let arg = 3.141592979431152; let arg = force_eval!(arg); - assert_eq!( - rem_pio2(arg), - (2, 3.2584135866119817e-7, -2.1125998133974653e-23) - ); + assert_eq!(rem_pio2(arg), (2, 3.2584135866119817e-7, -2.1125998133974653e-23)); } #[test] diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index db97a39d490..1dfbba3b1b2 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -11,8 +11,7 @@ * ==================================================== */ -use super::floor; -use super::scalbn; +use super::{floor, scalbn}; // initial value for jk const INIT_JK: [usize; 4] = [3, 4, 4, 6]; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 775f5d750fb..3c658fe3dbc 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -14,10 +14,10 @@ * ==================================================== */ -use super::rem_pio2_large; - use core::f64; +use super::rem_pio2_large; + const TOINT: f64 = 1.5 / f64::EPSILON; /// 53 bits of 2/pi diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs index 0afd1f7f5f2..4c11e848746 100644 --- a/library/compiler-builtins/libm/src/math/remquo.rs +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -91,11 +91,7 @@ pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { } q &= 0x7fffffff; let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; - if sx { - (-x, quo) - } else { - (x, quo) - } + if sx { (-x, quo) } else { (x, quo) } } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs index d71bd38e3dd..b0e85ca6611 100644 --- a/library/compiler-builtins/libm/src/math/remquof.rs +++ b/library/compiler-builtins/libm/src/math/remquof.rs @@ -89,9 +89,5 @@ pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { } q &= 0x7fffffff; let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; - if sx { - (-x, quo) - } else { - (x, quo) - } + if sx { (-x, quo) } else { (x, quo) } } diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 8edbe344022..618b26e5466 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -23,15 +23,7 @@ pub fn rint(x: f64) -> f64 { xminusoneovere + one_over_e }; - if ans == 0.0 { - if is_positive { - 0.0 - } else { - -0.0 - } - } else { - ans - } + if ans == 0.0 { if is_positive { 0.0 } else { -0.0 } } else { ans } } } diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 7a7da618ad8..0726d83ba67 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -23,15 +23,7 @@ pub fn rintf(x: f32) -> f32 { xminusoneovere + one_over_e }; - if ans == 0.0 { - if is_positive { - 0.0 - } else { - -0.0 - } - } else { - ans - } + if ans == 0.0 { if is_positive { 0.0 } else { -0.0 } } else { ans } } } diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 46fabc90ff5..b81ebaa1dbe 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -1,7 +1,7 @@ -use super::copysign; -use super::trunc; use core::f64; +use super::{copysign, trunc}; + #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn round(x: f64) -> f64 { trunc(x + copysign(0.5 - 0.25 * f64::EPSILON, x)) diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index becdb5620a9..fb974bbfe73 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -1,7 +1,7 @@ -use super::copysignf; -use super::truncf; use core::f32; +use super::{copysignf, truncf}; + #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundf(x: f32) -> f32 { truncf(x + copysignf(0.5 - 0.25 * f32::EPSILON, x)) diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs index 6e20be2aeee..ca181462723 100644 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -14,10 +14,10 @@ * ==================================================== */ -use super::{k_cosf, k_sinf, rem_pio2f}; - use core::f64::consts::FRAC_PI_2; +use super::{k_cosf, k_sinf, rem_pio2f}; + /* Small multiples of pi/2 rounded to double precision. */ const S1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ @@ -39,11 +39,7 @@ pub fn sinf(x: f32) -> f32 { if ix < 0x39800000 { /* |x| < 2**-12 */ /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00800000 { - x / x1p120 - } else { - x + x1p120 - }); + force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); return x; } return k_sinf(x64); @@ -58,11 +54,7 @@ pub fn sinf(x: f32) -> f32 { return k_cosf(x64 - S1_PIO2); } } - return k_sinf(if sign { - -(x64 + S2_PIO2) - } else { - -(x64 - S2_PIO2) - }); + return k_sinf(if sign { -(x64 + S2_PIO2) } else { -(x64 - S2_PIO2) }); } if ix <= 0x40e231d5 { /* |x| ~<= 9*pi/4 */ diff --git a/library/compiler-builtins/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/src/math/sinhf.rs index 24f863c4465..6788642f0c9 100644 --- a/library/compiler-builtins/libm/src/math/sinhf.rs +++ b/library/compiler-builtins/libm/src/math/sinhf.rs @@ -1,5 +1,4 @@ -use super::expm1f; -use super::k_expo2f; +use super::{expm1f, k_expo2f}; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinhf(x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 66cb7659c2d..5862b119b64 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -242,9 +242,10 @@ pub fn sqrt(x: f64) -> f64 { #[cfg(test)] mod tests { - use super::*; use core::f64::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(sqrt(100.0), 10.0); diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 16cbb2f9770..f7324c94137 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -132,9 +132,10 @@ pub fn sqrtf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use super::*; use core::f32::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(sqrtf(100.0), 10.0); @@ -154,12 +155,7 @@ mod tests { #[test] fn conformance_tests() { - let values = [ - 3.14159265359f32, - 10000.0f32, - f32::from_bits(0x0000000f), - INFINITY, - ]; + let values = [3.14159265359f32, 10000.0f32, f32::from_bits(0x0000000f), INFINITY]; let results = [1071833029u32, 1120403456u32, 456082799u32, 2139095040u32]; for i in 0..values.len() { diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs index 5a72f68014a..5aa44aeef72 100644 --- a/library/compiler-builtins/libm/src/math/tan.rs +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -49,11 +49,7 @@ pub fn tan(x: f64) -> f64 { if ix < 0x3e400000 { /* |x| < 2**-27 */ /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00100000 { - x / x1p120 as f64 - } else { - x + x1p120 as f64 - }); + force_eval!(if ix < 0x00100000 { x / x1p120 as f64 } else { x + x1p120 as f64 }); return x; } return k_tan(x, 0.0, 0); diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs index 10de59c3917..f6b2399d094 100644 --- a/library/compiler-builtins/libm/src/math/tanf.rs +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -14,10 +14,10 @@ * ==================================================== */ -use super::{k_tanf, rem_pio2f}; - use core::f64::consts::FRAC_PI_2; +use super::{k_tanf, rem_pio2f}; + /* Small multiples of pi/2 rounded to double precision. */ const T1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ @@ -39,11 +39,7 @@ pub fn tanf(x: f32) -> f32 { if ix < 0x39800000 { /* |x| < 2**-12 */ /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00800000 { - x / x1p120 - } else { - x + x1p120 - }); + force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); return x; } return k_tanf(x64, false); diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs index 980c68554fd..cfea2c16703 100644 --- a/library/compiler-builtins/libm/src/math/tanh.rs +++ b/library/compiler-builtins/libm/src/math/tanh.rs @@ -45,9 +45,5 @@ pub fn tanh(mut x: f64) -> f64 { t = x; } - if sign { - -t - } else { - t - } + if sign { -t } else { t } } diff --git a/library/compiler-builtins/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/src/math/tanhf.rs index fc94e3ddd58..ab13e1abf4c 100644 --- a/library/compiler-builtins/libm/src/math/tanhf.rs +++ b/library/compiler-builtins/libm/src/math/tanhf.rs @@ -31,9 +31,5 @@ pub fn tanhf(mut x: f32) -> f32 { force_eval!(x * x); x }; - if sign { - -tt - } else { - tt - } + if sign { -tt } else { tt } } -- cgit 1.4.1-3-g733a5 From 79f065ab24d763de2aff166e297ba6df713651c5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 20:25:50 -0500 Subject: Add a .git-blame-ignore-revs file Include the recent formatting commit. --- library/compiler-builtins/libm/.git-blame-ignore-revs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 library/compiler-builtins/libm/.git-blame-ignore-revs diff --git a/library/compiler-builtins/libm/.git-blame-ignore-revs b/library/compiler-builtins/libm/.git-blame-ignore-revs new file mode 100644 index 00000000000..c1e43134f36 --- /dev/null +++ b/library/compiler-builtins/libm/.git-blame-ignore-revs @@ -0,0 +1,5 @@ +# Use `git config blame.ignorerevsfile .git-blame-ignore-revs` to make +# `git blame` ignore the following commits. + +# Reformat with a new `.rustfmt.toml` +5882cabb83c30bf7c36023f9a55a80583636b0e8 -- cgit 1.4.1-3-g733a5 From 4d6aeca6b3ae26628b73725a2b754f888dbb483a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 27 Oct 2024 01:08:38 -0500 Subject: Add a CI test that the crate builds on stable Currently everything we have runs with nightly Rust. Add a stable test to make sure we don't accidentally make use of behavior that isn't yet stable without gating it. --- library/compiler-builtins/libm/.github/workflows/main.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index f312e1f5e67..5340e91e569 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -35,6 +35,16 @@ jobs: - run: cargo generate-lockfile - run: ./ci/run-docker.sh ${{ matrix.target }} + stable: + name: Build succeeds on stable + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update stable && rustup default stable + - run: cargo build -p libm + + rustfmt: name: Rustfmt runs-on: ubuntu-latest -- cgit 1.4.1-3-g733a5 From 3180b04aa3e7a09a9ba5c02d35348090d25e287d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 27 Oct 2024 22:45:37 -0500 Subject: Change `build.rs` to use the older `:` rather than `::` This allows supporting Rust < 1.77. --- library/compiler-builtins/libm/build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 653ccf7993f..b683557e4af 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -2,10 +2,10 @@ use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); - println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); - println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\"))"); + println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); + println!("cargo:rustc-check-cfg=cfg(feature, values(\"unstable\"))"); - println!("cargo::rustc-check-cfg=cfg(feature, values(\"checked\"))"); + println!("cargo:rustc-check-cfg=cfg(feature, values(\"checked\"))"); #[allow(unexpected_cfgs)] if !cfg!(feature = "checked") { -- cgit 1.4.1-3-g733a5 From 3541e834df89db5e64c7baa29ea2ad743af05858 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 27 Oct 2024 22:46:22 -0500 Subject: Set the MSRV to 1.63 and document it as such Fixes: https://github.com/rust-lang/libm/issues/330 --- library/compiler-builtins/libm/.github/workflows/main.yml | 10 +++++++--- library/compiler-builtins/libm/Cargo.toml | 1 + library/compiler-builtins/libm/README.md | 4 ++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 5340e91e569..400ca2c0b07 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -35,13 +35,17 @@ jobs: - run: cargo generate-lockfile - run: ./ci/run-docker.sh ${{ matrix.target }} - stable: - name: Build succeeds on stable + msrv: + name: Check MSRV runs-on: ubuntu-latest steps: - uses: actions/checkout@master + - run: | + msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' Cargo.toml)" + echo "MSRV: $msrv" + echo "MSRV=$msrv" >> "$GITHUB_ENV" - name: Install Rust - run: rustup update stable && rustup default stable + run: rustup update "$MSRV" && rustup default "$MSRV" - run: cargo build -p libm diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index f04fc12df4d..a498b4eb78d 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -11,6 +11,7 @@ repository = "https://github.com/rust-lang/libm" version = "0.2.9" edition = "2021" exclude = ["/ci/", "/.github/workflows/"] +rust-version = "1.63" [features] default = [] diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 24ee3d1c163..e5d64bd2dc0 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -34,6 +34,10 @@ To run all benchmarks: Please check [CONTRIBUTING.md](CONTRIBUTING.md) +## Minimum Rust version policy + +This crate supports rustc 1.63 and newer. + ## License Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or -- cgit 1.4.1-3-g733a5 From 476585d6a0befbfcaae2435e77591e4388600aab Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 03:49:48 +0000 Subject: chore: release v0.2.10 --- library/compiler-builtins/libm/CHANGELOG.md | 6 ++++++ library/compiler-builtins/libm/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 36ed41d6ba5..317dfafc007 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -8,6 +8,12 @@ and this project adheres to ## [Unreleased] +## [0.2.10](https://github.com/rust-lang/libm/compare/libm-v0.2.9...libm-v0.2.10) - 2024-10-28 + +### Other + +- Set the MSRV to 1.63 and test this in CI + ## [0.2.9](https://github.com/rust-lang/libm/compare/libm-v0.2.8...libm-v0.2.9) - 2024-10-26 ### Fixed diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index a498b4eb78d..9282b71576d 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT AND (MIT OR Apache-2.0)" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.9" +version = "0.2.10" edition = "2021" exclude = ["/ci/", "/.github/workflows/"] rust-version = "1.63" -- cgit 1.4.1-3-g733a5 From b49ef8c5101cedf6e16966de970b84c916e78fe4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 27 Oct 2024 23:17:52 -0500 Subject: Don't deny warnings when checking MSRV 1.63 reports some false positive lints that we don't need to worry about. Make sure we don't fail CI for this. --- library/compiler-builtins/libm/.github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 400ca2c0b07..f834b5defa1 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -38,6 +38,8 @@ jobs: msrv: name: Check MSRV runs-on: ubuntu-latest + env: + RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` steps: - uses: actions/checkout@master - run: | -- cgit 1.4.1-3-g733a5 From a3fd7732f0f0fd001950e094902c55b6d6429603 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 27 Oct 2024 23:41:29 -0500 Subject: ci: `rustup --no-self-update` and reuqire MSRV checks Pass `--no-self-update` to `rustup`, which is typical for CI. Also add the MSRV job to `success` so GitHub won't merge without it passing. --- .../libm/.github/workflows/main.yml | 63 +++++++++++----------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index f834b5defa1..926e3c19e2e 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -29,44 +29,19 @@ jobs: steps: - uses: actions/checkout@master - name: Install Rust - run: rustup update nightly && rustup default nightly + run: rustup update nightly --no-self-update && rustup default nightly - run: rustup target add ${{ matrix.target }} - run: rustup target add x86_64-unknown-linux-musl - run: cargo generate-lockfile - run: ./ci/run-docker.sh ${{ matrix.target }} - msrv: - name: Check MSRV - runs-on: ubuntu-latest - env: - RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` - steps: - - uses: actions/checkout@master - - run: | - msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' Cargo.toml)" - echo "MSRV: $msrv" - echo "MSRV=$msrv" >> "$GITHUB_ENV" - - name: Install Rust - run: rustup update "$MSRV" && rustup default "$MSRV" - - run: cargo build -p libm - - - rustfmt: - name: Rustfmt - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Install Rust - run: rustup update nightly && rustup default nightly && rustup component add rustfmt - - run: cargo fmt -- --check - wasm: name: WebAssembly runs-on: ubuntu-latest steps: - uses: actions/checkout@master - name: Install Rust - run: rustup update nightly && rustup default nightly + run: rustup update nightly --no-self-update && rustup default nightly - run: rustup target add wasm32-unknown-unknown - run: cargo build --target wasm32-unknown-unknown @@ -76,7 +51,7 @@ jobs: steps: - uses: actions/checkout@master - name: Install Rust - run: rustup update nightly && rustup default nightly + run: rustup update nightly --no-self-update && rustup default nightly - run: cargo build -p cb benchmarks: @@ -85,16 +60,44 @@ jobs: steps: - uses: actions/checkout@master - name: Install Rust - run: rustup update nightly && rustup default nightly + run: rustup update nightly --no-self-update && rustup default nightly - run: cargo bench --all + msrv: + name: Check MSRV + runs-on: ubuntu-latest + env: + RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` + steps: + - uses: actions/checkout@master + - run: | + msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' Cargo.toml)" + echo "MSRV: $msrv" + echo "MSRV=$msrv" >> "$GITHUB_ENV" + - name: Install Rust + run: rustup update "$MSRV" --no-self-update && rustup default "$MSRV" + - run: cargo build -p libm + + rustfmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + rustup component add rustfmt + - run: cargo fmt -- --check + success: needs: - docker - - rustfmt - wasm - cb - benchmarks + - msrv + - rustfmt runs-on: ubuntu-latest # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its -- cgit 1.4.1-3-g733a5 From db55857a731cb3d09ff309e00d1797c753e2141c Mon Sep 17 00:00:00 2001 From: Johanna Sörngård <44257381+JSorngard@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:12:45 +0100 Subject: Add basic docstrings to some functions (#337) * Add docstring to Bessel functions * Add docstrings to logarithm functions * Add docstrings to pow functions * Specify argument bit-size of the Bessel functions * Specify argument bit-size for pow functions * Specify argument bit-size for logarithms * Add docstrings to sin, cos, sincos and sinh functions * Add docstrings to sqrt * Add docstrings to tan and tanh functions * Add an inline link to https://en.wikipedia.org/wiki/Bessel_function to the docstrings of all Bessel functions. --- library/compiler-builtins/libm/src/math/cos.rs | 4 ++++ library/compiler-builtins/libm/src/math/cosf.rs | 3 +++ library/compiler-builtins/libm/src/math/j0.rs | 2 ++ library/compiler-builtins/libm/src/math/j0f.rs | 2 ++ library/compiler-builtins/libm/src/math/j1.rs | 2 ++ library/compiler-builtins/libm/src/math/j1f.rs | 2 ++ library/compiler-builtins/libm/src/math/jn.rs | 2 ++ library/compiler-builtins/libm/src/math/jnf.rs | 2 ++ library/compiler-builtins/libm/src/math/log.rs | 1 + library/compiler-builtins/libm/src/math/log10.rs | 1 + library/compiler-builtins/libm/src/math/log10f.rs | 1 + library/compiler-builtins/libm/src/math/log1p.rs | 1 + library/compiler-builtins/libm/src/math/log1pf.rs | 1 + library/compiler-builtins/libm/src/math/log2.rs | 1 + library/compiler-builtins/libm/src/math/log2f.rs | 1 + library/compiler-builtins/libm/src/math/logf.rs | 1 + library/compiler-builtins/libm/src/math/pow.rs | 1 + library/compiler-builtins/libm/src/math/powf.rs | 1 + library/compiler-builtins/libm/src/math/sin.rs | 4 ++++ library/compiler-builtins/libm/src/math/sincos.rs | 3 +++ library/compiler-builtins/libm/src/math/sincosf.rs | 3 +++ library/compiler-builtins/libm/src/math/sinf.rs | 3 +++ library/compiler-builtins/libm/src/math/sinh.rs | 2 ++ library/compiler-builtins/libm/src/math/sinhf.rs | 1 + library/compiler-builtins/libm/src/math/sqrt.rs | 1 + library/compiler-builtins/libm/src/math/sqrtf.rs | 1 + library/compiler-builtins/libm/src/math/tan.rs | 4 ++++ library/compiler-builtins/libm/src/math/tanf.rs | 3 +++ library/compiler-builtins/libm/src/math/tanh.rs | 4 ++++ library/compiler-builtins/libm/src/math/tanhf.rs | 3 +++ 30 files changed, 61 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs index db8bc498926..de99cd4c5e4 100644 --- a/library/compiler-builtins/libm/src/math/cos.rs +++ b/library/compiler-builtins/libm/src/math/cos.rs @@ -41,6 +41,10 @@ use super::{k_cos, k_sin, rem_pio2}; // Accuracy: // TRIG(x) returns trig(x) nearly rounded // + +/// The cosine of `x` (f64). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cos(x: f64) -> f64 { let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index 0a01335f770..27c2fc3b994 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -24,6 +24,9 @@ const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ +/// The cosine of `x` (f32). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cosf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/j0.rs b/library/compiler-builtins/libm/src/math/j0.rs index c4258ccca16..5e5e839f81a 100644 --- a/library/compiler-builtins/libm/src/math/j0.rs +++ b/library/compiler-builtins/libm/src/math/j0.rs @@ -109,6 +109,7 @@ const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). pub fn j0(mut x: f64) -> f64 { let z: f64; let r: f64; @@ -162,6 +163,7 @@ const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). pub fn y0(x: f64) -> f64 { let z: f64; let u: f64; diff --git a/library/compiler-builtins/libm/src/math/j0f.rs b/library/compiler-builtins/libm/src/math/j0f.rs index 91c03dbbcdd..afb6ee9ba8b 100644 --- a/library/compiler-builtins/libm/src/math/j0f.rs +++ b/library/compiler-builtins/libm/src/math/j0f.rs @@ -62,6 +62,7 @@ const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). pub fn j0f(mut x: f32) -> f32 { let z: f32; let r: f32; @@ -107,6 +108,7 @@ const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). pub fn y0f(x: f32) -> f32 { let z: f32; let u: f32; diff --git a/library/compiler-builtins/libm/src/math/j1.rs b/library/compiler-builtins/libm/src/math/j1.rs index 02a65ca5a29..cef17a63e37 100644 --- a/library/compiler-builtins/libm/src/math/j1.rs +++ b/library/compiler-builtins/libm/src/math/j1.rs @@ -113,6 +113,7 @@ const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). pub fn j1(x: f64) -> f64 { let mut z: f64; let r: f64; @@ -158,6 +159,7 @@ const V0: [f64; 5] = [ 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ ]; +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). pub fn y1(x: f64) -> f64 { let z: f64; let u: f64; diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index c39f8ff7e96..02a3efd2435 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -63,6 +63,7 @@ const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). pub fn j1f(x: f32) -> f32 { let mut z: f32; let r: f32; @@ -107,6 +108,7 @@ const V0: [f32; 5] = [ 1.6655924903e-11, /* 0x2d9281cf */ ]; +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). pub fn y1f(x: f32) -> f32 { let z: f32; let u: f32; diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs index 22ced20c15a..aff051f2406 100644 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -38,6 +38,7 @@ use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). pub fn jn(n: i32, mut x: f64) -> f64 { let mut ix: u32; let lx: u32; @@ -247,6 +248,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { if sign { -b } else { b } } +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). pub fn yn(n: i32, x: f64) -> f64 { let mut ix: u32; let lx: u32; diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs index 9cd0bb37de9..e5afda44896 100644 --- a/library/compiler-builtins/libm/src/math/jnf.rs +++ b/library/compiler-builtins/libm/src/math/jnf.rs @@ -15,6 +15,7 @@ use super::{fabsf, j0f, j1f, logf, y0f, y1f}; +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). pub fn jnf(n: i32, mut x: f32) -> f32 { let mut ix: u32; let mut nm1: i32; @@ -191,6 +192,7 @@ pub fn jnf(n: i32, mut x: f32) -> f32 { if sign { -b } else { b } } +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). pub fn ynf(n: i32, x: f32) -> f32 { let mut ix: u32; let mut ib: u32; diff --git a/library/compiler-builtins/libm/src/math/log.rs b/library/compiler-builtins/libm/src/math/log.rs index 27a26da60a9..f2dc47ec5cc 100644 --- a/library/compiler-builtins/libm/src/math/log.rs +++ b/library/compiler-builtins/libm/src/math/log.rs @@ -70,6 +70,7 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +/// The natural logarithm of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs index 40dacf2c916..f9d118f1292 100644 --- a/library/compiler-builtins/libm/src/math/log10.rs +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -31,6 +31,7 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +/// The base 10 logarithm of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs index 108dfa8b508..18bf8fcc832 100644 --- a/library/compiler-builtins/libm/src/math/log10f.rs +++ b/library/compiler-builtins/libm/src/math/log10f.rs @@ -25,6 +25,7 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +/// The base 10 logarithm of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index 552de549bfc..80561ec7415 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -65,6 +65,7 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +/// The natural logarithm of 1+`x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1p(x: f64) -> f64 { let mut ui: u64 = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index 8068128db4f..bba5b8a2f21 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -20,6 +20,7 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +/// The natural logarithm of 1+`x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1pf(x: f32) -> f32 { let mut ui: u32 = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index 83da3a19366..59533340bd8 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -29,6 +29,7 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +/// The base 2 logarithm of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs index 3a20fb15bd6..5ba2427d1d4 100644 --- a/library/compiler-builtins/libm/src/math/log2f.rs +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -23,6 +23,7 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +/// The base 2 logarithm of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs index 2b57b934fb9..68d1943025e 100644 --- a/library/compiler-builtins/libm/src/math/logf.rs +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -21,6 +21,7 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +/// The natural logarithm of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn logf(mut x: f32) -> f32 { let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 9b617cadbfe..7ecad291d18 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -89,6 +89,7 @@ const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ +/// Returns `x` to the power of `y` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn pow(x: f64, y: f64) -> f64 { let t1: f64; diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index d47ab4b3d1d..2d9d1e4bbfd 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -43,6 +43,7 @@ const IVLN2: f32 = 1.4426950216e+00; const IVLN2_H: f32 = 1.4426879883e+00; const IVLN2_L: f32 = 7.0526075433e-06; +/// Returns `x` to the power of `y` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn powf(x: f32, y: f32) -> f32 { let mut z: f32; diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index a53843dcdae..e04e0d6a09d 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -40,6 +40,10 @@ use super::{k_cos, k_sin, rem_pio2}; // // Accuracy: // TRIG(x) returns trig(x) nearly rounded + +/// The sine of `x` (f64). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sin(x: f64) -> f64 { let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs index ff5d87a1c60..ebf482f2df3 100644 --- a/library/compiler-builtins/libm/src/math/sincos.rs +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -12,6 +12,9 @@ use super::{get_high_word, k_cos, k_sin, rem_pio2}; +/// Both the sine and cosine of `x` (f64). +/// +/// `x` is specified in radians and the return value is (sin(x), cos(x)). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincos(x: f64) -> (f64, f64) { let s: f64; diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index 9a4c36104e9..82c40fb8c89 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -23,6 +23,9 @@ const S2PIO2: f32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ const S3PIO2: f32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ const S4PIO2: f32 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ +/// Both the sine and cosine of `x` (f32). +/// +/// `x` is specified in radians and the return value is (sin(x), cos(x)). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincosf(x: f32) -> (f32, f32) { let s: f32; diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs index ca181462723..b8fae2c9801 100644 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -24,6 +24,9 @@ const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ +/// The sine of `x` (f32). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs index fd24fd20cf7..79184198263 100644 --- a/library/compiler-builtins/libm/src/math/sinh.rs +++ b/library/compiler-builtins/libm/src/math/sinh.rs @@ -4,6 +4,8 @@ use super::{expm1, expo2}; // = (exp(x)-1 + (exp(x)-1)/exp(x))/2 // = x + x^3/6 + o(x^5) // + +/// The hyperbolic sine of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinh(x: f64) -> f64 { // union {double f; uint64_t i;} u = {.f = x}; diff --git a/library/compiler-builtins/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/src/math/sinhf.rs index 6788642f0c9..44d2e3560d5 100644 --- a/library/compiler-builtins/libm/src/math/sinhf.rs +++ b/library/compiler-builtins/libm/src/math/sinhf.rs @@ -1,5 +1,6 @@ use super::{expm1f, k_expo2f}; +/// The hyperbolic sine of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinhf(x: f32) -> f32 { let mut h = 0.5f32; diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 5862b119b64..e2907384dcd 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -78,6 +78,7 @@ use core::f64; +/// The square root of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index f7324c94137..a738fc0b663 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -13,6 +13,7 @@ * ==================================================== */ +/// The square root of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs index 5aa44aeef72..a074ca5540a 100644 --- a/library/compiler-builtins/libm/src/math/tan.rs +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -39,6 +39,10 @@ use super::{k_tan, rem_pio2}; // // Accuracy: // TRIG(x) returns trig(x) nearly rounded + +/// The tangent of `x` (f64). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tan(x: f64) -> f64 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs index f6b2399d094..7586aae4c7e 100644 --- a/library/compiler-builtins/libm/src/math/tanf.rs +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -24,6 +24,9 @@ const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ +/// The tangent of `x` (f32). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs index cfea2c16703..cc0abe4fcb2 100644 --- a/library/compiler-builtins/libm/src/math/tanh.rs +++ b/library/compiler-builtins/libm/src/math/tanh.rs @@ -4,6 +4,10 @@ use super::expm1; * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) */ + +/// The hyperbolic tangent of `x` (f64). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanh(mut x: f64) -> f64 { let mut uf: f64 = x; diff --git a/library/compiler-builtins/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/src/math/tanhf.rs index ab13e1abf4c..fffbba6c6ec 100644 --- a/library/compiler-builtins/libm/src/math/tanhf.rs +++ b/library/compiler-builtins/libm/src/math/tanhf.rs @@ -1,5 +1,8 @@ use super::expm1f; +/// The hyperbolic tangent of `x` (f32). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanhf(mut x: f32) -> f32 { /* x = |x| */ -- cgit 1.4.1-3-g733a5 From 750027cbbeece8bcd5852d621c150ef01179e9b8 Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Mon, 28 Oct 2024 19:59:21 +0200 Subject: fix type of constants in ported sincosf (#331) * fix type of constants in ported sincosf --- library/compiler-builtins/libm/src/math/sincosf.rs | 50 +++++++++------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index 82c40fb8c89..423845e44c2 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -17,11 +17,11 @@ use super::{k_cosf, k_sinf, rem_pio2f}; /* Small multiples of pi/2 rounded to double precision. */ -const PI_2: f32 = 0.5 * 3.1415926535897931160E+00; -const S1PIO2: f32 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ -const S2PIO2: f32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ -const S3PIO2: f32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const S4PIO2: f32 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ +const PI_2: f64 = 0.5 * 3.1415926535897931160E+00; +const S1PIO2: f64 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2PIO2: f64 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ +const S3PIO2: f64 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4PIO2: f64 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ /// Both the sine and cosine of `x` (f32). /// @@ -59,21 +59,21 @@ pub fn sincosf(x: f32) -> (f32, f32) { if ix <= 0x4016cbe3 { /* |x| ~<= 3pi/4 */ if sign { - s = -k_cosf((x + S1PIO2) as f64); - c = k_sinf((x + S1PIO2) as f64); + s = -k_cosf(x as f64 + S1PIO2); + c = k_sinf(x as f64 + S1PIO2); } else { - s = k_cosf((S1PIO2 - x) as f64); - c = k_sinf((S1PIO2 - x) as f64); + s = k_cosf(S1PIO2 - x as f64); + c = k_sinf(S1PIO2 - x as f64); } } /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ else { if sign { - s = -k_sinf((x + S2PIO2) as f64); - c = -k_cosf((x + S2PIO2) as f64); + s = -k_sinf(x as f64 + S2PIO2); + c = -k_cosf(x as f64 + S2PIO2); } else { - s = -k_sinf((x - S2PIO2) as f64); - c = -k_cosf((x - S2PIO2) as f64); + s = -k_sinf(x as f64 - S2PIO2); + c = -k_cosf(x as f64 - S2PIO2); } } @@ -85,19 +85,19 @@ pub fn sincosf(x: f32) -> (f32, f32) { if ix <= 0x40afeddf { /* |x| ~<= 7*pi/4 */ if sign { - s = k_cosf((x + S3PIO2) as f64); - c = -k_sinf((x + S3PIO2) as f64); + s = k_cosf(x as f64 + S3PIO2); + c = -k_sinf(x as f64 + S3PIO2); } else { - s = -k_cosf((x - S3PIO2) as f64); - c = k_sinf((x - S3PIO2) as f64); + s = -k_cosf(x as f64 - S3PIO2); + c = k_sinf(x as f64 - S3PIO2); } } else { if sign { - s = k_sinf((x + S4PIO2) as f64); - c = k_cosf((x + S4PIO2) as f64); + s = k_sinf(x as f64 + S4PIO2); + c = k_cosf(x as f64 + S4PIO2); } else { - s = k_sinf((x - S4PIO2) as f64); - c = k_cosf((x - S4PIO2) as f64); + s = k_sinf(x as f64 - S4PIO2); + c = k_cosf(x as f64 - S4PIO2); } } @@ -131,14 +131,6 @@ pub fn sincosf(x: f32) -> (f32, f32) { #[cfg(test)] mod tests { use super::sincosf; - use crate::_eqf; - - #[test] - fn with_pi() { - let (s, c) = sincosf(core::f32::consts::PI); - _eqf(s.abs(), 0.0).unwrap(); - _eqf(c, -1.0).unwrap(); - } #[test] fn rotational_symmetry() { -- cgit 1.4.1-3-g733a5 From 36b52c7d1b281b257c09179eae3e11bfdc17595a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:25:16 -0500 Subject: Introduce `musl-math-sys` for bindings to musl math symbols This crate builds math symbols from a musl checkout and provides a Rust interface. The intent is that we will be able to compare our implementations against musl on more than just linux (which are the only currently the only targets we run `*-musl` targets against for comparison). Musl libc can't compile on anything other than Linux; however, the routines in `src/math` are cross platform enough to build on MacOS and windows-gnu with only minor adjustments. We take advantage of this and build only needed files using `cc`. The build script also performs remapping (via defines) so that e.g. `cos` gets defined as `musl_cos`. This gives us more certainty that we are actually testing against the intended symbol; without it, it is easy to unknowingly link to system libraries or even Rust's `libm` itself and wind up with an ineffective test. There is also a small procedure to verify remapping worked correctly by checking symbols in object files. --- library/compiler-builtins/libm/.gitignore | 5 +- library/compiler-builtins/libm/Cargo.toml | 2 + .../libm/crates/musl-math-sys/Cargo.toml | 12 + .../libm/crates/musl-math-sys/build.rs | 328 +++++++++++++++++++++ .../libm/crates/musl-math-sys/c_patches/alias.c | 40 +++ .../libm/crates/musl-math-sys/c_patches/features.h | 39 +++ .../libm/crates/musl-math-sys/src/lib.rs | 279 ++++++++++++++++++ 7 files changed, 703 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml create mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/build.rs create mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/c_patches/alias.c create mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/c_patches/features.h create mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs diff --git a/library/compiler-builtins/libm/.gitignore b/library/compiler-builtins/libm/.gitignore index 39950911a62..b6a53275151 100644 --- a/library/compiler-builtins/libm/.gitignore +++ b/library/compiler-builtins/libm/.gitignore @@ -1,8 +1,9 @@ -**/*.rs.bk +**.bk .#* /bin /math/src /math/target /target -/tests Cargo.lock +musl/ +**.tar.gz diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 9282b71576d..99bfdbfdc85 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -24,10 +24,12 @@ unstable = [] force-soft-floats = [] [workspace] +resolver = "2" members = [ "crates/compiler-builtins-smoke-test", "crates/libm-bench", "crates/libm-test", + "crates/musl-math-sys", ] default-members = [ ".", diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml new file mode 100644 index 00000000000..449ce4f3ed1 --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "musl-math-sys" +version = "0.1.0" +edition = "2021" + +[dependencies] + +[dev-dependencies] +libm = { path = "../../" } + +[build-dependencies] +cc = "1.1.24" diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs new file mode 100644 index 00000000000..03df06c7934 --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs @@ -0,0 +1,328 @@ +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; +use std::{env, fs, str}; + +/// Static library that will be built +const LIB_NAME: &str = "musl_math_prefixed"; + +/// Files that have more than one symbol. Map of file names to the symbols defined in that file. +const MULTIPLE_SYMBOLS: &[(&str, &[&str])] = &[ + ("__invtrigl", &["__invtrigl", "__invtrigl_R", "__pio2_hi", "__pio2_lo"]), + ("__polevll", &["__polevll", "__p1evll"]), + ("erf", &["erf", "erfc"]), + ("erff", &["erff", "erfcf"]), + ("erfl", &["erfl", "erfcl"]), + ("exp10", &["exp10", "pow10"]), + ("exp10f", &["exp10f", "pow10f"]), + ("exp10l", &["exp10l", "pow10l"]), + ("exp2f_data", &["exp2f_data", "__exp2f_data"]), + ("exp_data", &["exp_data", "__exp_data"]), + ("j0", &["j0", "y0"]), + ("j0f", &["j0f", "y0f"]), + ("j1", &["j1", "y1"]), + ("j1f", &["j1f", "y1f"]), + ("jn", &["jn", "yn"]), + ("jnf", &["jnf", "ynf"]), + ("lgamma", &["lgamma", "__lgamma_r"]), + ("remainder", &["remainder", "drem"]), + ("remainderf", &["remainderf", "dremf"]), + ("lgammaf", &["lgammaf", "lgammaf_r", "__lgammaf_r"]), + ("lgammal", &["lgammal", "lgammal_r", "__lgammal_r"]), + ("log2_data", &["log2_data", "__log2_data"]), + ("log2f_data", &["log2f_data", "__log2f_data"]), + ("log_data", &["log_data", "__log_data"]), + ("logf_data", &["logf_data", "__logf_data"]), + ("pow_data", &["pow_data", "__pow_log_data"]), + ("powf_data", &["powf_data", "__powf_log2_data"]), + ("signgam", &["signgam", "__signgam"]), + ("sqrt_data", &["sqrt_data", "__rsqrt_tab"]), +]; + +fn main() { + let cfg = Config::from_env(); + + if cfg.target_env == "msvc" + || cfg.target_family == "wasm" + || cfg.target_features.iter().any(|f| f == "thumb-mode") + { + println!( + "cargo::warning=Musl doesn't compile with the current \ + target {}; skipping build", + &cfg.target_string + ); + return; + } + + build_musl_math(&cfg); +} + +#[allow(dead_code)] +#[derive(Debug)] +struct Config { + manifest_dir: PathBuf, + out_dir: PathBuf, + musl_dir: PathBuf, + musl_arch: String, + target_arch: String, + target_env: String, + target_family: String, + target_os: String, + target_string: String, + target_vendor: String, + target_features: Vec, +} + +impl Config { + fn from_env() -> Self { + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let target_features = env::var("CARGO_CFG_TARGET_FEATURE") + .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) + .unwrap_or_default(); + + // Default to the `{workspace_root}/musl` if not specified + let musl_dir = env::var("MUSL_SOURCE_DIR") + .map(PathBuf::from) + .unwrap_or_else(|_| manifest_dir.parent().unwrap().parent().unwrap().join("musl")); + + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let musl_arch = if target_arch == "x86" { "i386".to_owned() } else { target_arch.clone() }; + + println!("cargo::rerun-if-changed={}/c_patches", manifest_dir.display()); + println!("cargo::rerun-if-env-changed=MUSL_SOURCE_DIR"); + println!("cargo::rerun-if-changed={}", musl_dir.display()); + + Self { + manifest_dir, + out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), + musl_dir, + musl_arch, + target_arch, + target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), + target_family: env::var("CARGO_CFG_TARGET_FAMILY").unwrap(), + target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + target_string: env::var("TARGET").unwrap(), + target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), + target_features, + } + } +} + +/// Build musl math symbols to a static library +fn build_musl_math(cfg: &Config) { + let musl_dir = &cfg.musl_dir; + assert!( + musl_dir.exists(), + "musl source is missing. it can be downloaded with ./ci/download-musl.sh" + ); + + let math = musl_dir.join("src/math"); + let arch_dir = musl_dir.join("arch").join(&cfg.musl_arch); + let source_map = find_math_source(&math, cfg); + let out_path = cfg.out_dir.join(format!("lib{LIB_NAME}.a")); + + // Run configuration steps. Usually done as part of the musl `Makefile`. + let obj_include = cfg.out_dir.join("musl_obj/include"); + fs::create_dir_all(&obj_include).unwrap(); + fs::create_dir_all(&obj_include.join("bits")).unwrap(); + let sed_stat = Command::new("sed") + .arg("-f") + .arg(musl_dir.join("tools/mkalltypes.sed")) + .arg(arch_dir.join("bits/alltypes.h.in")) + .arg(musl_dir.join("include/alltypes.h.in")) + .stderr(Stdio::inherit()) + .output() + .unwrap(); + assert!(sed_stat.status.success(), "sed command failed: {:?}", sed_stat.status); + + fs::write(obj_include.join("bits/alltypes.h"), sed_stat.stdout).unwrap(); + + let mut cbuild = cc::Build::new(); + cbuild + .extra_warnings(false) + .warnings(false) + .flag_if_supported("-Wno-bitwise-op-parentheses") + .flag_if_supported("-Wno-literal-range") + .flag_if_supported("-Wno-parentheses") + .flag_if_supported("-Wno-shift-count-overflow") + .flag_if_supported("-Wno-shift-op-parentheses") + .flag_if_supported("-Wno-unused-but-set-variable") + .flag_if_supported("-std=c99") + .flag_if_supported("-ffreestanding") + .flag_if_supported("-nostdinc") + .define("_ALL_SOURCE", "1") + .opt_level(3) + .define( + "ROOT_INCLUDE_FEATURES", + Some(musl_dir.join("include/features.h").to_str().unwrap()), + ) + // Our overrides are in this directory + .include(cfg.manifest_dir.join("c_patches")) + .include(musl_dir.join("arch").join(&cfg.musl_arch)) + .include(musl_dir.join("arch/generic")) + .include(musl_dir.join("src/include")) + .include(musl_dir.join("src/internal")) + .include(obj_include) + .include(musl_dir.join("include")) + .file(cfg.manifest_dir.join("c_patches/alias.c")); + + for (sym_name, src_file) in source_map { + // Build the source file + cbuild.file(src_file); + + // Trickery! Redefine the symbol names to have the prefix `musl_`, which allows us to + // differentiate these symbols from whatever we provide. + if let Some((_names, syms)) = + MULTIPLE_SYMBOLS.iter().find(|(name, _syms)| *name == sym_name) + { + // Handle the occasional file that defines multiple symbols + for sym in *syms { + cbuild.define(sym, Some(format!("musl_{sym}").as_str())); + } + } else { + // If the file doesn't define multiple symbols, the file name will be the symbol + cbuild.define(&sym_name, Some(format!("musl_{sym_name}").as_str())); + } + } + + if cfg!(windows) { + // On Windows we don't have a good way to check symbols, so skip that step. + cbuild.compile(LIB_NAME); + return; + } + + let objfiles = cbuild.compile_intermediates(); + + // We create the archive ourselves with relocations rather than letting `cc` do it so we can + // encourage it to resolve symbols now. This should help avoid accidentally linking the wrong + // thing. + let stat = cbuild + .get_compiler() + .to_command() + .arg("-r") + .arg("-o") + .arg(&out_path) + .args(objfiles) + .status() + .unwrap(); + assert!(stat.success()); + + println!("cargo::rustc-link-lib={LIB_NAME}"); + println!("cargo::rustc-link-search=native={}", cfg.out_dir.display()); + + validate_archive_symbols(&out_path); +} + +/// Build a map of `name -> path`. `name` is typically the symbol name, but this doesn't account +/// for files that provide multiple symbols. +fn find_math_source(math_root: &Path, cfg: &Config) -> BTreeMap { + let mut map = BTreeMap::new(); + let mut arch_dir = None; + + // Locate all files and directories + for item in fs::read_dir(math_root).unwrap() { + let path = item.unwrap().path(); + let meta = fs::metadata(&path).unwrap(); + + if meta.is_dir() { + // Make note of the arch-specific directory if it exists + if path.file_name().unwrap() == cfg.target_arch.as_str() { + arch_dir = Some(path); + } + continue; + } + + // Skip non-source files + if path.extension().is_some_and(|ext| ext == "h") { + continue; + } + + let sym_name = path.file_stem().unwrap(); + map.insert(sym_name.to_str().unwrap().to_owned(), path.to_owned()); + } + + // If arch-specific versions are available, build those instead. + if let Some(arch_dir) = arch_dir { + for item in fs::read_dir(arch_dir).unwrap() { + let path = item.unwrap().path(); + let sym_name = path.file_stem().unwrap(); + + if path.extension().unwrap() == "s" { + // FIXME: we never build assembly versions since we have no good way to + // rename the symbol (our options are probably preprocessor or objcopy). + continue; + } + map.insert(sym_name.to_str().unwrap().to_owned(), path); + } + } + + map +} + +/// Make sure we don't have something like a loose unprefixed `_cos` called somewhere, which could +/// wind up linking to system libraries rather than the built musl library. +fn validate_archive_symbols(out_path: &Path) { + const ALLOWED_UNDEF_PFX: &[&str] = &[ + // PIC and arch-specific + ".TOC", + "_GLOBAL_OFFSET_TABLE_", + "__x86.get_pc_thunk", + // gcc/compiler-rt/compiler-builtins symbols + "__add", + "__aeabi_", + "__div", + "__eq", + "__extend", + "__fix", + "__float", + "__gcc_", + "__ge", + "__gt", + "__le", + "__lshr", + "__lt", + "__mul", + "__ne", + "__stack_chk_fail", + "__stack_chk_guard", + "__sub", + "__trunc", + "__undef", + // string routines + "__bzero", + "bzero", + // FPENV interfaces + "feclearexcept", + "fegetround", + "feraiseexcept", + "fesetround", + "fetestexcept", + ]; + + // List global undefined symbols + let out = + Command::new("nm").arg("-guj").arg(out_path).stderr(Stdio::inherit()).output().unwrap(); + + let undef = str::from_utf8(&out.stdout).unwrap(); + let mut undef = undef.lines().collect::>(); + undef.retain(|sym| { + // Account for file formats that add a leading `_` + !ALLOWED_UNDEF_PFX.iter().any(|pfx| sym.starts_with(pfx) || sym[1..].starts_with(pfx)) + }); + + assert!(undef.is_empty(), "found disallowed undefined symbols: {undef:#?}"); + + // Find any symbols that are missing the `_musl_` prefix` + let out = + Command::new("nm").arg("-gUj").arg(out_path).stderr(Stdio::inherit()).output().unwrap(); + + let defined = str::from_utf8(&out.stdout).unwrap(); + let mut defined = defined.lines().collect::>(); + defined.retain(|sym| { + !(sym.starts_with("_musl_") + || sym.starts_with("musl_") + || sym.starts_with("__x86.get_pc_thunk")) + }); + + assert!(defined.is_empty(), "found unprefixed symbols: {defined:#?}"); +} diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/alias.c b/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/alias.c new file mode 100644 index 00000000000..63e0f08d5eb --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/alias.c @@ -0,0 +1,40 @@ +/* On platforms that don't support weak symbols, define required aliases + * as wrappers. See comments in `features.h` for more. + */ +#if defined(__APPLE__) || defined(__MINGW32__) + +double __lgamma_r(double a, int *b); +float __lgammaf_r(float a, int *b); +long __lgammal_r(long double a, int *b); +double exp10(double a); +float exp10f(float a); +long exp10l(long double a); +double remainder(double a, double b); +float remainderf(float a, float b); + +double lgamma_r(double a, int *b) { + return __lgamma_r(a, b); +} +float lgammaf_r(float a, int *b) { + return __lgammaf_r(a, b); +} +long double lgammal_r(long double a, int *b) { + return __lgammal_r(a, b); +} +double pow10(double a) { + return exp10(a); +} +float pow10f(float a) { + return exp10f(a); +} +long double pow10l(long double a) { + return exp10l(a); +} +double drem(double a, double b) { + return remainder(a, b); +} +float dremf(float a, float b) { + return remainderf(a, b); +} + +#endif diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/features.h b/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/features.h new file mode 100644 index 00000000000..97af935979a --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/features.h @@ -0,0 +1,39 @@ +/* This is meant to override Musl's src/include/features.h + * + * We use a separate file here to redefine some attributes that don't work on + * all platforms that we would like to build on. + */ + +#ifndef FEATURES_H +#define FEATURES_H + +/* Get the required `#include "../../include/features.h"` since we can't use + * the relative path. The C macros need double indirection to get a usable + * string. */ +#define _stringify_inner(s) #s +#define _stringify(s) _stringify_inner(s) +#include _stringify(ROOT_INCLUDE_FEATURES) + +#if defined(__APPLE__) +#define weak __attribute__((__weak__)) +#define hidden __attribute__((__visibility__("hidden"))) + +/* We _should_ be able to define this as: + * _Pragma(_stringify(weak musl_ ## new = musl_ ## old)) + * However, weak symbols aren't handled correctly [1]. So we manually write + * wrappers, which are in `alias.c`. + * + * [1]: https://github.com/llvm/llvm-project/issues/111321 + */ +#define weak_alias(old, new) /* nothing */ + +#else +#define weak __attribute__((__weak__)) +#define hidden __attribute__((__visibility__("hidden"))) +#define weak_alias(old, new) \ + extern __typeof(old) musl_ ## new \ + __attribute__((__weak__, __alias__(_stringify(musl_ ## old)))) + +#endif /* defined(__APPLE__) */ + +#endif diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs new file mode 100644 index 00000000000..fe3c89229b6 --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs @@ -0,0 +1,279 @@ +//! Bindings to Musl math functions (these are built in `build.rs`). + +use std::ffi::{c_char, c_int, c_long}; + +/// Macro for creating bindings and exposing a safe function (since the implementations have no +/// preconditions). Included functions must have correct signatures, otherwise this will be +/// unsound. +macro_rules! functions { + ( $( + $pfx_name:ident: $name:ident( $($arg:ident: $aty:ty),+ ) -> $rty:ty; + )* ) => { + extern "C" { + $( fn $pfx_name( $($arg: $aty),+ ) -> $rty; )* + } + + $( + // Expose a safe version + pub fn $name( $($arg: $aty),+ ) -> $rty { + // SAFETY: FFI calls with no preconditions + unsafe { $pfx_name( $($arg),+ ) } + } + )* + + #[cfg(test)] + mod tests { + use super::*; + use test_support::CallTest; + + $( functions!( + @single_test + $name($($arg: $aty),+) -> $rty + ); )* + } + }; + + (@single_test + $name:ident( $($arg:ident: $aty:ty),+ ) -> $rty:ty + ) => { + // Run a simple check to ensure we can link and call the function without crashing. + #[test] + // FIXME(#309): LE PPC crashes calling some musl functions + #[cfg_attr(all(target_arch = "powerpc64", target_endian = "little"), ignore)] + fn $name() { + $rty>::check(super::$name); + } + }; +} + +#[cfg(test)] +mod test_support { + use core::ffi::c_char; + + /// Just verify that we are able to call the function. + pub trait CallTest { + fn check(f: Self); + } + + macro_rules! impl_calltest { + ($( ($($arg:ty),*) -> $ret:ty; )*) => { + $( + impl CallTest for fn($($arg),*) -> $ret { + fn check(f: Self) { + f($(1 as $arg),*); + } + } + )* + }; + } + + impl_calltest! { + (f32) -> f32; + (f64) -> f64; + (f32, f32) -> f32; + (f64, f64) -> f64; + (i32, f32) -> f32; + (i32, f64) -> f64; + (f32, f32, f32) -> f32; + (f64, f64, f64) -> f64; + (f32, i32) -> f32; + (f32, i64) -> f32; + (f32) -> i32; + (f64) -> i32; + (f64, i32) -> f64; + (f64, i64) -> f64; + } + + impl CallTest for fn(f32, &mut f32) -> f32 { + fn check(f: Self) { + let mut tmp = 0.0; + f(0.0, &mut tmp); + } + } + impl CallTest for fn(f64, &mut f64) -> f64 { + fn check(f: Self) { + let mut tmp = 0.0; + f(0.0, &mut tmp); + } + } + impl CallTest for fn(f32, &mut i32) -> f32 { + fn check(f: Self) { + let mut tmp = 1; + f(0.0, &mut tmp); + } + } + impl CallTest for fn(f64, &mut i32) -> f64 { + fn check(f: Self) { + let mut tmp = 1; + f(0.0, &mut tmp); + } + } + impl CallTest for fn(f32, f32, &mut i32) -> f32 { + fn check(f: Self) { + let mut tmp = 1; + f(0.0, 0.0, &mut tmp); + } + } + impl CallTest for fn(f64, f64, &mut i32) -> f64 { + fn check(f: Self) { + let mut tmp = 1; + f(0.0, 0.0, &mut tmp); + } + } + impl CallTest for fn(f32, &mut f32, &mut f32) { + fn check(f: Self) { + let mut tmp1 = 1.0; + let mut tmp2 = 1.0; + f(0.0, &mut tmp1, &mut tmp2); + } + } + impl CallTest for fn(f64, &mut f64, &mut f64) { + fn check(f: Self) { + let mut tmp1 = 1.0; + let mut tmp2 = 1.0; + f(0.0, &mut tmp1, &mut tmp2); + } + } + impl CallTest for fn(*const c_char) -> f32 { + fn check(f: Self) { + f(c"1".as_ptr()); + } + } + impl CallTest for fn(*const c_char) -> f64 { + fn check(f: Self) { + f(c"1".as_ptr()); + } + } +} + +functions! { + musl_acos: acos(a: f64) -> f64; + musl_acosf: acosf(a: f32) -> f32; + musl_acosh: acosh(a: f64) -> f64; + musl_acoshf: acoshf(a: f32) -> f32; + musl_asin: asin(a: f64) -> f64; + musl_asinf: asinf(a: f32) -> f32; + musl_asinh: asinh(a: f64) -> f64; + musl_asinhf: asinhf(a: f32) -> f32; + musl_atan2: atan2(a: f64, b: f64) -> f64; + musl_atan2f: atan2f(a: f32, b: f32) -> f32; + musl_atan: atan(a: f64) -> f64; + musl_atanf: atanf(a: f32) -> f32; + musl_atanh: atanh(a: f64) -> f64; + musl_atanhf: atanhf(a: f32) -> f32; + musl_cbrt: cbrt(a: f64) -> f64; + musl_cbrtf: cbrtf(a: f32) -> f32; + musl_ceil: ceil(a: f64) -> f64; + musl_ceilf: ceilf(a: f32) -> f32; + musl_copysign: copysign(a: f64, b: f64) -> f64; + musl_copysignf: copysignf(a: f32, b: f32) -> f32; + musl_cos: cos(a: f64) -> f64; + musl_cosf: cosf(a: f32) -> f32; + musl_cosh: cosh(a: f64) -> f64; + musl_coshf: coshf(a: f32) -> f32; + musl_drem: drem(a: f64, b: f64) -> f64; + musl_dremf: dremf(a: f32, b: f32) -> f32; + musl_erf: erf(a: f64) -> f64; + musl_erfc: erfc(a: f64) -> f64; + musl_erfcf: erfcf(a: f32) -> f32; + musl_erff: erff(a: f32) -> f32; + musl_exp10: exp10(a: f64) -> f64; + musl_exp10f: exp10f(a: f32) -> f32; + musl_exp2: exp2(a: f64) -> f64; + musl_exp2f: exp2f(a: f32) -> f32; + musl_exp: exp(a: f64) -> f64; + musl_expf: expf(a: f32) -> f32; + musl_expm1: expm1(a: f64) -> f64; + musl_expm1f: expm1f(a: f32) -> f32; + musl_fabs: fabs(a: f64) -> f64; + musl_fabsf: fabsf(a: f32) -> f32; + musl_fdim: fdim(a: f64, b: f64) -> f64; + musl_fdimf: fdimf(a: f32, b: f32) -> f32; + musl_finite: finite(a: f64) -> c_int; + musl_finitef: finitef(a: f32) -> c_int; + musl_floor: floor(a: f64) -> f64; + musl_floorf: floorf(a: f32) -> f32; + musl_fma: fma(a: f64, b: f64, c: f64) -> f64; + musl_fmaf: fmaf(a: f32, b: f32, c: f32) -> f32; + musl_fmax: fmax(a: f64, b: f64) -> f64; + musl_fmaxf: fmaxf(a: f32, b: f32) -> f32; + musl_fmin: fmin(a: f64, b: f64) -> f64; + musl_fminf: fminf(a: f32, b: f32) -> f32; + musl_fmod: fmod(a: f64, b: f64) -> f64; + musl_fmodf: fmodf(a: f32, b: f32) -> f32; + musl_frexp: frexp(a: f64, b: &mut c_int) -> f64; + musl_frexpf: frexpf(a: f32, b: &mut c_int) -> f32; + musl_hypot: hypot(a: f64, b: f64) -> f64; + musl_hypotf: hypotf(a: f32, b: f32) -> f32; + musl_ilogb: ilogb(a: f64) -> c_int; + musl_ilogbf: ilogbf(a: f32) -> c_int; + musl_j0: j0(a: f64) -> f64; + musl_j0f: j0f(a: f32) -> f32; + musl_j1: j1(a: f64) -> f64; + musl_j1f: j1f(a: f32) -> f32; + musl_jn: jn(a: c_int, b: f64) -> f64; + musl_jnf: jnf(a: c_int, b: f32) -> f32; + musl_ldexp: ldexp(a: f64, b: c_int) -> f64; + musl_ldexpf: ldexpf(a: f32, b: c_int) -> f32; + musl_lgamma: lgamma(a: f64) -> f64; + musl_lgamma_r: lgamma_r(a: f64, b: &mut c_int) -> f64; + musl_lgammaf: lgammaf(a: f32) -> f32; + musl_lgammaf_r: lgammaf_r(a: f32, b: &mut c_int) -> f32; + musl_log10: log10(a: f64) -> f64; + musl_log10f: log10f(a: f32) -> f32; + musl_log1p: log1p(a: f64) -> f64; + musl_log1pf: log1pf(a: f32) -> f32; + musl_log2: log2(a: f64) -> f64; + musl_log2f: log2f(a: f32) -> f32; + musl_log: log(a: f64) -> f64; + musl_logb: logb(a: f64) -> f64; + musl_logbf: logbf(a: f32) -> f32; + musl_logf: logf(a: f32) -> f32; + musl_modf: modf(a: f64, b: &mut f64) -> f64; + musl_modff: modff(a: f32, b: &mut f32) -> f32; + musl_nan: nan(a: *const c_char) -> f64; + musl_nanf: nanf(a: *const c_char) -> f32; + musl_nearbyint: nearbyint(a: f64) -> f64; + musl_nearbyintf: nearbyintf(a: f32) -> f32; + musl_nextafter: nextafter(a: f64, b: f64) -> f64; + musl_nextafterf: nextafterf(a: f32, b: f32) -> f32; + musl_pow10: pow10(a: f64) -> f64; + musl_pow10f: pow10f(a: f32) -> f32; + musl_pow: pow(a: f64, b: f64) -> f64; + musl_powf: powf(a: f32, b: f32) -> f32; + musl_remainder: remainder(a: f64, b: f64) -> f64; + musl_remainderf: remainderf(a: f32, b: f32) -> f32; + musl_remquo: remquo(a: f64, b: f64, c: &mut c_int) -> f64; + musl_remquof: remquof(a: f32, b: f32, c: &mut c_int) -> f32; + musl_rint: rint(a: f64) -> f64; + musl_rintf: rintf(a: f32) -> f32; + musl_round: round(a: f64) -> f64; + musl_roundf: roundf(a: f32) -> f32; + musl_scalbln: scalbln(a: f64, b: c_long) -> f64; + musl_scalblnf: scalblnf(a: f32, b: c_long) -> f32; + musl_scalbn: scalbn(a: f64, b: c_int) -> f64; + musl_scalbnf: scalbnf(a: f32, b: c_int) -> f32; + musl_significand: significand(a: f64) -> f64; + musl_significandf: significandf(a: f32) -> f32; + musl_sin: sin(a: f64) -> f64; + musl_sincos: sincos(a: f64, b: &mut f64, c: &mut f64) -> (); + musl_sincosf: sincosf(a: f32, b: &mut f32, c: &mut f32) -> (); + musl_sinf: sinf(a: f32) -> f32; + musl_sinh: sinh(a: f64) -> f64; + musl_sinhf: sinhf(a: f32) -> f32; + musl_sqrt: sqrt(a: f64) -> f64; + musl_sqrtf: sqrtf(a: f32) -> f32; + musl_tan: tan(a: f64) -> f64; + musl_tanf: tanf(a: f32) -> f32; + musl_tanh: tanh(a: f64) -> f64; + musl_tanhf: tanhf(a: f32) -> f32; + musl_tgamma: tgamma(a: f64) -> f64; + musl_tgammaf: tgammaf(a: f32) -> f32; + musl_trunc: trunc(a: f64) -> f64; + musl_truncf: truncf(a: f32) -> f32; + musl_y0: y0(a: f64) -> f64; + musl_y0f: y0f(a: f32) -> f32; + musl_y1: y1(a: f64) -> f64; + musl_y1f: y1f(a: f32) -> f32; + musl_ynf: ynf(a: c_int, b: f32) -> f32; +} -- cgit 1.4.1-3-g733a5 From 5fc3068762a9b04899e894cd20eb4da509e30dfb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:36:05 -0500 Subject: Add a script for downloading musl --- library/compiler-builtins/libm/ci/download-musl.sh | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100755 library/compiler-builtins/libm/ci/download-musl.sh diff --git a/library/compiler-builtins/libm/ci/download-musl.sh b/library/compiler-builtins/libm/ci/download-musl.sh new file mode 100755 index 00000000000..d0d8b310e87 --- /dev/null +++ b/library/compiler-builtins/libm/ci/download-musl.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# Download the expected version of musl to a directory `musl` + +set -eux + +fname=musl-1.2.5.tar.gz +sha=a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4 + +mkdir musl +curl "https://musl.libc.org/releases/$fname" -O + +case "$(uname -s)" in + MINGW*) + # Need to extract the second line because certutil does human output + fsha=$(certutil -hashfile "$fname" SHA256 | sed -n '2p') + [ "$sha" = "$fsha" ] || exit 1 + ;; + *) + echo "$sha $fname" | shasum -a 256 --check || exit 1 + ;; +esac + +tar -xzf "$fname" -C musl --strip-components 1 +rm "$fname" -- cgit 1.4.1-3-g733a5 From 56deb13bd4d767193bf49b3ff137533706398bbf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:37:44 -0500 Subject: Add a procedural macro for expanding all function signatures Introduce `libm_test::for_each_function`. which macro takes a callback macro and invokes it once per function signature. This provides an easier way of registering various tests and benchmarks without duplicating the function names and signatures each time. --- library/compiler-builtins/libm/Cargo.toml | 2 + .../libm/crates/libm-macros/Cargo.toml | 12 + .../libm/crates/libm-macros/src/lib.rs | 541 +++++++++++++++++++++ .../libm/crates/libm-macros/src/parse.rs | 236 +++++++++ .../libm/crates/libm-macros/tests/basic.rs | 96 ++++ 5 files changed, 887 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-macros/Cargo.toml create mode 100644 library/compiler-builtins/libm/crates/libm-macros/src/lib.rs create mode 100644 library/compiler-builtins/libm/crates/libm-macros/src/parse.rs create mode 100644 library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 99bfdbfdc85..72b6dcd5e8e 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -28,11 +28,13 @@ resolver = "2" members = [ "crates/compiler-builtins-smoke-test", "crates/libm-bench", + "crates/libm-macros", "crates/libm-test", "crates/musl-math-sys", ] default-members = [ ".", + "crates/libm-macros", "crates/libm-test", ] diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml new file mode 100644 index 00000000000..9d2b08e2d78 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "libm-macros" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.88" +quote = "1.0.37" +syn = { version = "2.0.79", features = ["full", "extra-traits", "visit-mut"] } diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs new file mode 100644 index 00000000000..dc78598ca76 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs @@ -0,0 +1,541 @@ +mod parse; +use std::sync::LazyLock; + +use parse::{Invocation, StructuredInput}; +use proc_macro as pm; +use proc_macro2::{self as pm2, Span}; +use quote::{ToTokens, quote}; +use syn::Ident; +use syn::visit_mut::VisitMut; + +const ALL_FUNCTIONS: &[(Signature, Option, &[&str])] = &[ + ( + // `fn(f32) -> f32` + Signature { args: &[Ty::F32], returns: &[Ty::F32] }, + None, + &[ + "acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf", + "coshf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", "j0f", "j1f", + "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", "sinf", "sinhf", + "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", + ], + ), + ( + // `(f64) -> f64` + Signature { args: &[Ty::F64], returns: &[Ty::F64] }, + None, + &[ + "acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh", + "erf", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", "log10", + "log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", + "tgamma", "trunc", + ], + ), + ( + // `(f32, f32) -> f32` + Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] }, + None, + &[ + "atan2f", + "copysignf", + "fdimf", + "fmaxf", + "fminf", + "fmodf", + "hypotf", + "nextafterf", + "powf", + "remainderf", + ], + ), + ( + // `(f64, f64) -> f64` + Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] }, + None, + &[ + "atan2", + "copysign", + "fdim", + "fmax", + "fmin", + "fmod", + "hypot", + "nextafter", + "pow", + "remainder", + ], + ), + ( + // `(f32, f32, f32) -> f32` + Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] }, + None, + &["fmaf"], + ), + ( + // `(f64, f64, f64) -> f64` + Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] }, + None, + &["fma"], + ), + ( + // `(f32) -> i32` + Signature { args: &[Ty::F32], returns: &[Ty::I32] }, + None, + &["ilogbf"], + ), + ( + // `(f64) -> i32` + Signature { args: &[Ty::F64], returns: &[Ty::I32] }, + None, + &["ilogb"], + ), + ( + // `(i32, f32) -> f32` + Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] }, + None, + &["jnf"], + ), + ( + // `(i32, f64) -> f64` + Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] }, + None, + &["jn"], + ), + ( + // `(f32, i32) -> f32` + Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] }, + None, + &["scalbnf", "ldexpf"], + ), + ( + // `(f64, i64) -> f64` + Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] }, + None, + &["scalbn", "ldexp"], + ), + ( + // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, + Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }), + &["modff"], + ), + ( + // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, + Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }), + &["modf"], + ), + ( + // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] }, + Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), + &["frexpf", "lgammaf_r"], + ), + ( + // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] }, + Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), + &["frexp", "lgamma_r"], + ), + ( + // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` + Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] }, + Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), + &["remquof"], + ), + ( + // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` + Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] }, + Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), + &["remquo"], + ), + ( + // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, + Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }), + &["sincosf"], + ), + ( + // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, + Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }), + &["sincos"], + ), +]; + +/// A type used in a function signature. +#[allow(dead_code)] +#[derive(Debug, Clone, Copy)] +enum Ty { + F16, + F32, + F64, + F128, + I32, + CInt, + MutF16, + MutF32, + MutF64, + MutF128, + MutI32, + MutCInt, +} + +impl ToTokens for Ty { + fn to_tokens(&self, tokens: &mut pm2::TokenStream) { + let ts = match self { + Ty::F16 => quote! { f16 }, + Ty::F32 => quote! { f32 }, + Ty::F64 => quote! { f64 }, + Ty::F128 => quote! { f128 }, + Ty::I32 => quote! { i32 }, + Ty::CInt => quote! { ::core::ffi::c_int }, + Ty::MutF16 => quote! { &mut f16 }, + Ty::MutF32 => quote! { &mut f32 }, + Ty::MutF64 => quote! { &mut f64 }, + Ty::MutF128 => quote! { &mut f128 }, + Ty::MutI32 => quote! { &mut i32 }, + Ty::MutCInt => quote! { &mut core::ffi::c_int }, + }; + + tokens.extend(ts); + } +} + +/// Representation of e.g. `(f32, f32) -> f32` +#[derive(Debug, Clone)] +struct Signature { + args: &'static [Ty], + returns: &'static [Ty], +} + +/// Combined information about a function implementation. +#[derive(Debug, Clone)] +struct FunctionInfo { + name: &'static str, + /// Function signature for C implementations + c_sig: Signature, + /// Function signature for Rust implementations + rust_sig: Signature, +} + +/// A flat representation of `ALL_FUNCTIONS`. +static ALL_FUNCTIONS_FLAT: LazyLock> = LazyLock::new(|| { + let mut ret = Vec::new(); + + for (rust_sig, c_sig, names) in ALL_FUNCTIONS { + for name in *names { + let api = FunctionInfo { + name, + rust_sig: rust_sig.clone(), + c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()), + }; + ret.push(api); + } + } + + ret.sort_by_key(|item| item.name); + ret +}); + +/// Do something for each function present in this crate. +/// +/// Takes a callback macro and invokes it multiple times, once for each function that +/// this crate exports. This makes it easy to create generic tests, benchmarks, or other checks +/// and apply it to each symbol. +/// +/// Additionally, the `extra` and `fn_extra` patterns can make use of magic identifiers: +/// +/// - `MACRO_FN_NAME`: gets replaced with the name of the function on that invocation. +/// - `MACRO_FN_NAME_NORMALIZED`: similar to the above, but removes sufixes so e.g. `sinf` becomes +/// `sin`, `cosf128` becomes `cos`, etc. +/// +/// Invoke as: +/// +/// ``` +/// // Macro that is invoked once per function +/// macro_rules! callback_macro { +/// ( +/// // Name of that function +/// fn_name: $fn_name:ident, +/// // Function signature of the C version (e.g. `fn(f32, &mut f32) -> f32`) +/// CFn: $CFn:ty, +/// // A tuple representing the C version's arguments (e.g. `(f32, &mut f32)`) +/// CArgs: $CArgs:ty, +/// // The C version's return type (e.g. `f32`) +/// CRet: $CRet:ty, +/// // Function signature of the Rust version (e.g. `fn(f32) -> (f32, f32)`) +/// RustFn: $RustFn:ty, +/// // A tuple representing the Rust version's arguments (e.g. `(f32,)`) +/// RustArgs: $RustArgs:ty, +/// // The Rust version's return type (e.g. `(f32, f32)`) +/// RustRet: $RustRet:ty, +/// // Attributes for the current function, if any +/// attrs: [$($meta:meta)*] +/// // Extra tokens passed directly (if any) +/// extra: [$extra:ident], +/// // Extra function-tokens passed directly (if any) +/// fn_extra: $fn_extra:expr, +/// ) => { }; +/// } +/// +/// libm_macros::for_each_function! { +/// // The macro to invoke as a callback +/// callback: callback_macro, +/// // Functions to skip, i.e. `callback` shouldn't be called at all for these. +/// // +/// // This is an optional field. +/// skip: [sin, cos], +/// // Attributes passed as `attrs` for specific functions. For example, here the invocation +/// // with `sinf` and that with `cosf` will both get `meta1` and `meta2`, but no others will. +/// // +/// // This is an optional field. +/// attributes: [ +/// #[meta1] +/// #[meta2] +/// [sinf, cosf], +/// ], +/// // Any tokens that should be passed directly to all invocations of the callback. This can +/// // be used to pass local variables or other things the macro needs access to. +/// // +/// // This is an optional field. +/// extra: [foo], +/// // Similar to `extra`, but allow providing a pattern for only specific functions. Uses +/// // a simplified match-like syntax. +/// fn_extra: match MACRO_FN_NAME { +/// hypot | hypotf => |x| x.hypot(), +/// _ => |x| x, +/// }, +/// } +/// ``` +#[proc_macro] +pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream { + let input = syn::parse_macro_input!(tokens as Invocation); + + let res = StructuredInput::from_fields(input) + .and_then(|s_in| validate(&s_in).map(|fn_list| (s_in, fn_list))) + .and_then(|(s_in, fn_list)| expand(s_in, &fn_list)); + + match res { + Ok(ts) => ts.into(), + Err(e) => e.into_compile_error().into(), + } +} + +/// Check for any input that is structurally correct but has other problems. +/// +/// Returns the list of function names that we should expand for. +fn validate(input: &StructuredInput) -> syn::Result> { + // Collect lists of all functions that are provied as macro inputs in various fields (only, + // skip, attributes). + let attr_mentions = input + .attributes + .iter() + .flat_map(|map_list| map_list.iter()) + .flat_map(|attr_map| attr_map.names.iter()); + let only_mentions = input.only.iter().flat_map(|only_list| only_list.iter()); + let fn_extra_mentions = + input.fn_extra.iter().flat_map(|v| v.keys()).filter(|name| *name != "_"); + let all_mentioned_fns = + input.skip.iter().chain(only_mentions).chain(attr_mentions).chain(fn_extra_mentions); + + // Make sure that every function mentioned is a real function + for mentioned in all_mentioned_fns { + if !ALL_FUNCTIONS_FLAT.iter().any(|func| mentioned == func.name) { + let e = syn::Error::new( + mentioned.span(), + format!("unrecognized function name `{mentioned}`"), + ); + return Err(e); + } + } + + if !input.skip.is_empty() && input.only.is_some() { + let e = syn::Error::new( + input.only_span.unwrap(), + format!("only one of `skip` or `only` may be specified"), + ); + return Err(e); + } + + // Construct a list of what we intend to expand + let mut fn_list = Vec::new(); + for func in ALL_FUNCTIONS_FLAT.iter() { + let fn_name = func.name; + // If we have an `only` list and it does _not_ contain this function name, skip it + if input.only.as_ref().is_some_and(|only| !only.iter().any(|o| o == fn_name)) { + continue; + } + + // If there is a `skip` list that contains this function name, skip it + if input.skip.iter().any(|s| s == fn_name) { + continue; + } + + // Run everything else + fn_list.push(func); + } + + if let Some(map) = &input.fn_extra { + if !map.keys().any(|key| key == "_") { + // No default provided; make sure every expected function is covered + let mut fns_not_covered = Vec::new(); + for func in &fn_list { + if !map.keys().any(|key| key == func.name) { + // `name` was not mentioned in the `match` statement + fns_not_covered.push(func); + } + } + + if !fns_not_covered.is_empty() { + let e = syn::Error::new( + input.fn_extra_span.unwrap(), + format!( + "`fn_extra`: no default `_` pattern specified and the following \ + patterns are not covered: {fns_not_covered:#?}" + ), + ); + return Err(e); + } + } + }; + + Ok(fn_list) +} + +/// Expand our structured macro input into invocations of the callback macro. +fn expand(input: StructuredInput, fn_list: &[&FunctionInfo]) -> syn::Result { + let mut out = pm2::TokenStream::new(); + let default_ident = Ident::new("_", Span::call_site()); + let callback = input.callback; + + for func in fn_list { + let fn_name = Ident::new(func.name, Span::call_site()); + + // Prepare attributes in an `attrs: ...` field + let meta_field = match &input.attributes { + Some(attrs) => { + let meta = attrs + .iter() + .filter(|map| map.names.contains(&fn_name)) + .flat_map(|map| &map.meta); + quote! { attrs: [ #( #meta )* ] } + } + None => pm2::TokenStream::new(), + }; + + // Prepare extra in an `extra: ...` field, running the replacer + let extra_field = match input.extra.clone() { + Some(mut extra) => { + let mut v = MacroReplace::new(func.name); + v.visit_expr_mut(&mut extra); + v.finish()?; + + quote! { extra: #extra, } + } + None => pm2::TokenStream::new(), + }; + + // Prepare function-specific extra in a `fn_extra: ...` field, running the replacer + let fn_extra_field = match input.fn_extra { + Some(ref map) => { + let mut fn_extra = + map.get(&fn_name).or_else(|| map.get(&default_ident)).unwrap().clone(); + + let mut v = MacroReplace::new(func.name); + v.visit_expr_mut(&mut fn_extra); + v.finish()?; + + quote! { fn_extra: #fn_extra, } + } + None => pm2::TokenStream::new(), + }; + + let c_args = &func.c_sig.args; + let c_ret = &func.c_sig.returns; + let rust_args = &func.rust_sig.args; + let rust_ret = &func.rust_sig.returns; + + let new = quote! { + #callback! { + fn_name: #fn_name, + CFn: fn( #(#c_args),* ,) -> ( #(#c_ret),* ), + CArgs: ( #(#c_args),* ,), + CRet: ( #(#c_ret),* ), + RustFn: fn( #(#rust_args),* ,) -> ( #(#rust_ret),* ), + RustArgs: ( #(#rust_args),* ,), + RustRet: ( #(#rust_ret),* ), + #meta_field + #extra_field + #fn_extra_field + } + }; + + out.extend(new); + } + + Ok(out) +} + +/// Visitor to replace "magic" identifiers that we allow: `MACRO_FN_NAME` and +/// `MACRO_FN_NAME_NORMALIZED`. +struct MacroReplace { + fn_name: &'static str, + /// Remove the trailing `f` or `f128` to make + norm_name: String, + error: Option, +} + +impl MacroReplace { + fn new(name: &'static str) -> Self { + // Keep this in sync with `libm_test::canonical_name` + let known_mappings = &[ + ("erff", "erf"), + ("erf", "erf"), + ("lgammaf_r", "lgamma_r"), + ("modff", "modf"), + ("modf", "modf"), + ]; + + let norm_name = match known_mappings.iter().find(|known| known.0 == name) { + Some(found) => found.1, + None => name + .strip_suffix("f") + .or_else(|| name.strip_suffix("f16")) + .or_else(|| name.strip_suffix("f128")) + .unwrap_or(name), + }; + + Self { fn_name: name, norm_name: norm_name.to_owned(), error: None } + } + + fn finish(self) -> syn::Result<()> { + match self.error { + Some(e) => Err(e), + None => Ok(()), + } + } + + fn visit_ident_inner(&mut self, i: &mut Ident) { + let s = i.to_string(); + if !s.starts_with("MACRO") || self.error.is_some() { + return; + } + + match s.as_str() { + "MACRO_FN_NAME" => *i = Ident::new(self.fn_name, i.span()), + "MACRO_FN_NAME_NORMALIZED" => *i = Ident::new(&self.norm_name, i.span()), + _ => { + self.error = + Some(syn::Error::new(i.span(), format!("unrecognized meta expression `{s}`"))); + } + } + } +} + +impl VisitMut for MacroReplace { + fn visit_ident_mut(&mut self, i: &mut Ident) { + self.visit_ident_inner(i); + syn::visit_mut::visit_ident_mut(self, i); + } +} diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs b/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs new file mode 100644 index 00000000000..ee9bd524bbe --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs @@ -0,0 +1,236 @@ +use std::collections::BTreeMap; + +use proc_macro2::Span; +use quote::ToTokens; +use syn::parse::{Parse, ParseStream, Parser}; +use syn::punctuated::Punctuated; +use syn::spanned::Spanned; +use syn::token::Comma; +use syn::{Arm, Attribute, Expr, ExprMatch, Ident, Meta, Token, bracketed}; + +/// The input to our macro; just a list of `field: value` items. +#[derive(Debug)] +pub struct Invocation { + fields: Punctuated, +} + +impl Parse for Invocation { + fn parse(input: ParseStream) -> syn::Result { + Ok(Self { fields: input.parse_terminated(Mapping::parse, Token![,])? }) + } +} + +/// A `key: expression` mapping with nothing else. Basically a simplified `syn::Field`. +#[derive(Debug)] +struct Mapping { + name: Ident, + _sep: Token![:], + expr: Expr, +} + +impl Parse for Mapping { + fn parse(input: ParseStream) -> syn::Result { + Ok(Self { name: input.parse()?, _sep: input.parse()?, expr: input.parse()? }) + } +} + +/// The input provided to our proc macro, after parsing into the form we expect. +#[derive(Debug)] +pub struct StructuredInput { + /// Macro to invoke once per function + pub callback: Ident, + /// Skip these functions + pub skip: Vec, + /// Invoke only for these functions + pub only: Option>, + /// Attributes that get applied to specific functions + pub attributes: Option>, + /// Extra expressions to pass to all invocations of the macro + pub extra: Option, + /// Per-function extra expressions to pass to the macro + pub fn_extra: Option>, + // For diagnostics + pub only_span: Option, + pub fn_extra_span: Option, +} + +impl StructuredInput { + pub fn from_fields(input: Invocation) -> syn::Result { + let mut map: Vec<_> = input.fields.into_iter().collect(); + let cb_expr = expect_field(&mut map, "callback")?; + let skip_expr = expect_field(&mut map, "skip").ok(); + let only_expr = expect_field(&mut map, "only").ok(); + let attr_expr = expect_field(&mut map, "attributes").ok(); + let extra = expect_field(&mut map, "extra").ok(); + let fn_extra = expect_field(&mut map, "fn_extra").ok(); + + if !map.is_empty() { + Err(syn::Error::new( + map.first().unwrap().name.span(), + format!("unexpected fields {map:?}"), + ))?; + } + + let skip = match skip_expr { + Some(expr) => Parser::parse2(parse_ident_array, expr.into_token_stream())?, + None => Vec::new(), + }; + + let only_span = only_expr.as_ref().map(|expr| expr.span()); + let only = match only_expr { + Some(expr) => Some(Parser::parse2(parse_ident_array, expr.into_token_stream())?), + None => None, + }; + + let attributes = match attr_expr { + Some(expr) => { + let mut attributes = Vec::new(); + let attr_exprs = Parser::parse2(parse_expr_array, expr.into_token_stream())?; + + for attr in attr_exprs { + attributes.push(syn::parse2(attr.into_token_stream())?); + } + Some(attributes) + } + None => None, + }; + + let fn_extra_span = fn_extra.as_ref().map(|expr| expr.span()); + let fn_extra = match fn_extra { + Some(expr) => Some(extract_fn_extra_field(expr)?), + None => None, + }; + + Ok(Self { + callback: expect_ident(cb_expr)?, + skip, + only, + only_span, + attributes, + extra, + fn_extra, + fn_extra_span, + }) + } +} + +fn extract_fn_extra_field(expr: Expr) -> syn::Result> { + let Expr::Match(mexpr) = expr else { + let e = syn::Error::new(expr.span(), "`fn_extra` expects a match expression"); + return Err(e); + }; + + let ExprMatch { attrs, match_token: _, expr, brace_token: _, arms } = mexpr; + + expect_empty_attrs(&attrs)?; + + let match_on = expect_ident(*expr)?; + if match_on != "MACRO_FN_NAME" { + let e = syn::Error::new(match_on.span(), "only allowed to match on `MACRO_FN_NAME`"); + return Err(e); + } + + let mut res = BTreeMap::new(); + + for arm in arms { + let Arm { attrs, pat, guard, fat_arrow_token: _, body, comma: _ } = arm; + + expect_empty_attrs(&attrs)?; + + let keys = match pat { + syn::Pat::Wild(w) => vec![Ident::new("_", w.span())], + _ => Parser::parse2(parse_ident_pat, pat.into_token_stream())?, + }; + + if let Some(guard) = guard { + let e = syn::Error::new(guard.0.span(), "no guards allowed in this position"); + return Err(e); + } + + for key in keys { + let inserted = res.insert(key.clone(), *body.clone()); + if inserted.is_some() { + let e = syn::Error::new(key.span(), format!("key `{key}` specified twice")); + return Err(e); + } + } + } + + Ok(res) +} + +fn expect_empty_attrs(attrs: &[Attribute]) -> syn::Result<()> { + if attrs.is_empty() { + return Ok(()); + } + + let e = + syn::Error::new(attrs.first().unwrap().span(), "no attributes allowed in this position"); + Err(e) +} + +/// Extract a named field from a map, raising an error if it doesn't exist. +fn expect_field(v: &mut Vec, name: &str) -> syn::Result { + let pos = v.iter().position(|v| v.name == name).ok_or_else(|| { + syn::Error::new(Span::call_site(), format!("missing expected field `{name}`")) + })?; + + Ok(v.remove(pos).expr) +} + +/// Coerce an expression into a simple identifier. +fn expect_ident(expr: Expr) -> syn::Result { + syn::parse2(expr.into_token_stream()) +} + +/// Parse an array of expressions. +fn parse_expr_array(input: ParseStream) -> syn::Result> { + let content; + let _ = bracketed!(content in input); + let fields = content.parse_terminated(Expr::parse, Token![,])?; + Ok(fields.into_iter().collect()) +} + +/// Parse an array of idents, e.g. `[foo, bar, baz]`. +fn parse_ident_array(input: ParseStream) -> syn::Result> { + let content; + let _ = bracketed!(content in input); + let fields = content.parse_terminated(Ident::parse, Token![,])?; + Ok(fields.into_iter().collect()) +} + +/// Parse an pattern of idents, specifically `(foo | bar | baz)`. +fn parse_ident_pat(input: ParseStream) -> syn::Result> { + if !input.peek2(Token![|]) { + return Ok(vec![input.parse()?]); + } + + let fields = Punctuated::::parse_separated_nonempty(input)?; + Ok(fields.into_iter().collect()) +} + +/// A mapping of attributes to identifiers (just a simplified `Expr`). +/// +/// Expressed as: +/// +/// ```ignore +/// #[meta1] +/// #[meta2] +/// [foo, bar, baz] +/// ``` +#[derive(Debug)] +pub struct AttributeMap { + pub meta: Vec, + pub names: Vec, +} + +impl Parse for AttributeMap { + fn parse(input: ParseStream) -> syn::Result { + let attrs = input.call(Attribute::parse_outer)?; + + Ok(Self { + meta: attrs.into_iter().map(|a| a.meta).collect(), + names: parse_ident_array(input)?, + }) + } +} diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs new file mode 100644 index 00000000000..8f8c09f1b64 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs @@ -0,0 +1,96 @@ +// `STATUS_DLL_NOT_FOUND` on i686 MinGW, not worth looking into. +#![cfg(not(all(target_arch = "x86", target_os = "windows", target_env = "gnu")))] + +macro_rules! basic { + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + attrs: [$($meta:meta)*] + extra: [$($extra_tt:tt)*], + fn_extra: $fn_extra:expr, + ) => { + $(#[$meta])* + mod $fn_name { + #[allow(unused)] + type CFnTy = $CFn; + // type CArgsTy<'_> = $CArgs; + // type CRetTy<'_> = $CRet; + #[allow(unused)] + type RustFnTy = $RustFn; + #[allow(unused)] + type RustArgsTy = $RustArgs; + #[allow(unused)] + type RustRetTy = $RustRet; + #[allow(unused)] + const A: &[&str] = &[$($extra_tt)*]; + #[allow(unused)] + fn foo(a: f32) -> f32 { + $fn_extra(a) + } + } + }; +} + +mod test_basic { + libm_macros::for_each_function! { + callback: basic, + skip: [sin, cos], + attributes: [ + // just some random attributes + #[allow(clippy::pedantic)] + #[allow(dead_code)] + [sinf, cosf] + ], + extra: ["foo", "bar"], + fn_extra: match MACRO_FN_NAME { + sin => |x| x + 2.0, + cos | cosf => |x: f32| x.MACRO_FN_NAME_NORMALIZED(), + _ => |_x| 100.0 + } + } +} + +macro_rules! basic_no_extra { + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + ) => { + mod $fn_name { + #[allow(unused)] + type CFnTy = $CFn; + // type CArgsTy<'_> = $CArgs; + // type CRetTy<'_> = $CRet; + #[allow(unused)] + type RustFnTy = $RustFn; + #[allow(unused)] + type RustArgsTy = $RustArgs; + #[allow(unused)] + type RustRetTy = $RustRet; + } + }; +} + +mod test_basic_no_extra { + // Test with no extra, no skip, and no attributes + libm_macros::for_each_function! { + callback: basic_no_extra, + } +} + +mod test_only { + // Test that only works + libm_macros::for_each_function! { + callback: basic_no_extra, + only: [sin, sinf], + } +} -- cgit 1.4.1-3-g733a5 From 0acb3e2b50781a59c5932b4af71fe7a8b20d0e1a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:41:07 -0500 Subject: Collect all function names to an array Use a build script for `libm-test` to enumerate all symbols provided by `libm` and provide this list in a variable. This will allow us to make sure no functions are missed anytime they must be manually listed. Additionally, introduce some helper config options. --- .../libm/crates/libm-test/build.rs | 100 ++++++++++++++++++++- .../libm/crates/libm-test/src/lib.rs | 3 +- 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index 9653bd83013..472dec9d33e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -1,10 +1,106 @@ +use std::fmt::Write; +use std::path::PathBuf; +use std::{env, fs}; + fn main() { + let cfg = Config::from_env(); + + emit_optimization_cfg(&cfg); + emit_cfg_shorthands(&cfg); + list_all_tests(&cfg); + #[cfg(feature = "test-musl-serialized")] - musl_reference_tests::generate(); + musl_serialized_tests::generate(); +} + +#[allow(dead_code)] +struct Config { + manifest_dir: PathBuf, + out_dir: PathBuf, + opt_level: u8, + target_arch: String, + target_env: String, + target_family: Option, + target_os: String, + target_string: String, + target_vendor: String, + target_features: Vec, +} + +impl Config { + fn from_env() -> Self { + let target_features = env::var("CARGO_CFG_TARGET_FEATURE") + .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) + .unwrap_or_default(); + + Self { + manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()), + out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), + opt_level: env::var("OPT_LEVEL").unwrap().parse().unwrap(), + target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), + target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), + target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(), + target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + target_string: env::var("TARGET").unwrap(), + target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), + target_features, + } + } +} + +/// Some tests are extremely slow. Emit a config option based on optimization level. +fn emit_optimization_cfg(cfg: &Config) { + println!("cargo::rustc-check-cfg=cfg(optimizations_enabled)"); + + if cfg.opt_level >= 2 { + println!("cargo::rustc-cfg=optimizations_enabled"); + } +} + +/// Provide an alias for common longer config combinations. +fn emit_cfg_shorthands(cfg: &Config) { + println!("cargo::rustc-check-cfg=cfg(x86_no_sse)"); + if cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse") { + // Shorthand to detect i586 targets + println!("cargo::rustc-cfg=x86_no_sse"); + } +} + +/// Create a list of all source files in an array. This can be used for making sure that +/// all functions are tested or otherwise covered in some way. +// FIXME: it would probably be better to use rustdoc JSON output to get public functions. +fn list_all_tests(cfg: &Config) { + let math_src = cfg.manifest_dir.join("../../src/math"); + + let mut files = fs::read_dir(math_src) + .unwrap() + .map(|f| f.unwrap().path()) + .filter(|entry| entry.is_file()) + .map(|f| f.file_stem().unwrap().to_str().unwrap().to_owned()) + .collect::>(); + files.sort(); + + let mut s = "pub const ALL_FUNCTIONS: &[&str] = &[".to_owned(); + for f in files { + if f == "mod" { + // skip mod.rs + continue; + } + write!(s, "\"{f}\",").unwrap(); + } + write!(s, "];").unwrap(); + + let outfile = cfg.out_dir.join("all_files.rs"); + fs::write(outfile, s).unwrap(); } +/// At build time, generate the output of what the corresponding `*musl` target does with a range +/// of inputs. +/// +/// Serialize that target's output, run the same thing with our symbols, then load and compare +/// the resulting values. #[cfg(feature = "test-musl-serialized")] -mod musl_reference_tests { +mod musl_serialized_tests { use std::path::PathBuf; use std::process::Command; use std::{env, fs}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 8b137891791..32c0618964f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1 +1,2 @@ - +// List of all files present in libm's source +include!(concat!(env!("OUT_DIR"), "/all_files.rs")); -- cgit 1.4.1-3-g733a5 From 05c9691f15b09b8adff1b775275fe43902091124 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:44:31 -0500 Subject: Add a test that `for_each_fn` correctly lists all functions Create a new test that checks `for_each_fn` against `ALL_FUNCTIONS`, i.e. the manually entered function list against the automatically collected list. If any are missing (e.g. new symbol added), then this will produce an error. --- .../libm/crates/libm-test/Cargo.toml | 1 + .../libm/crates/libm-test/tests/check_coverage.rs | 60 ++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 6367bdca52c..1e76fb70707 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -13,6 +13,7 @@ test-musl-serialized = ["rand"] [dependencies] libm = { path = "../.." } +libm-macros = { path = "../libm-macros" } [build-dependencies] rand = { version = "0.8.5", optional = true } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs new file mode 100644 index 00000000000..ef6d21fdbba --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs @@ -0,0 +1,60 @@ +//! Ensure that `for_each_function!` isn't missing any symbols. + +/// Files in `src/` that do not export a testable symbol. +const ALLOWED_SKIPS: &[&str] = &[ + // Not a generic test function + "fenv", + // Nonpublic functions + "expo2", + "k_cos", + "k_cosf", + "k_expo2", + "k_expo2f", + "k_sin", + "k_sinf", + "k_tan", + "k_tanf", + "rem_pio2", + "rem_pio2_large", + "rem_pio2f", +]; + +macro_rules! callback { + ( + fn_name: $name:ident, + CFn: $_CFn:ty, + CArgs: $_CArgs:ty, + CRet: $_CRet:ty, + RustFn: $_RustFn:ty, + RustArgs: $_RustArgs:ty, + RustRet: $_RustRet:ty, + extra: [$push_to:ident], + ) => { + $push_to.push(stringify!($name)); + }; +} + +#[test] +fn test_for_each_function_all_included() { + let mut included = Vec::new(); + let mut missing = Vec::new(); + + libm_macros::for_each_function! { + callback: callback, + extra: [included], + }; + + for f in libm_test::ALL_FUNCTIONS { + if !included.contains(f) && !ALLOWED_SKIPS.contains(f) { + missing.push(f) + } + } + + if !missing.is_empty() { + panic!( + "missing tests for the following: {missing:#?} \ + \nmake sure any new functions are entered in \ + `ALL_FUNCTIONS` (in `libm-macros`)." + ); + } +} -- cgit 1.4.1-3-g733a5 From 8be6ef1e0a29864131de6046dc44230b1a2e7eeb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:47:55 -0500 Subject: Add numeric traits These traits are simplified versions of what we have in `compiler_builtins` and will be used for tests. --- .../libm/crates/libm-test/src/lib.rs | 4 + .../libm/crates/libm-test/src/num_traits.rs | 181 +++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 32c0618964f..5444709d87c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,2 +1,6 @@ +mod num_traits; + +pub use num_traits::{Float, Hex, Int}; + // List of all files present in libm's source include!(concat!(env!("OUT_DIR"), "/all_files.rs")); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs new file mode 100644 index 00000000000..835d6e46d43 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs @@ -0,0 +1,181 @@ +use std::fmt; + +/// Common types and methods for floating point numbers. +pub trait Float: Copy + fmt::Display + fmt::Debug + PartialEq { + type Int: Int; + type SignedInt: Int + Int; + + const ZERO: Self; + const ONE: Self; + + /// The bitwidth of the float type + const BITS: u32; + + /// The bitwidth of the significand + const SIGNIFICAND_BITS: u32; + + /// The bitwidth of the exponent + const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + + fn is_nan(self) -> bool; + fn is_infinite(self) -> bool; + fn to_bits(self) -> Self::Int; + fn from_bits(bits: Self::Int) -> Self; + fn signum(self) -> Self; +} + +macro_rules! impl_float { + ($($fty:ty, $ui:ty, $si:ty, $significand_bits:expr;)+) => { + $( + impl Float for $fty { + type Int = $ui; + type SignedInt = $si; + + const ZERO: Self = 0.0; + const ONE: Self = 1.0; + + const BITS: u32 = <$ui>::BITS; + const SIGNIFICAND_BITS: u32 = $significand_bits; + + fn is_nan(self) -> bool { + self.is_nan() + } + fn is_infinite(self) -> bool { + self.is_infinite() + } + fn to_bits(self) -> Self::Int { + self.to_bits() + } + fn from_bits(bits: Self::Int) -> Self { + Self::from_bits(bits) + } + fn signum(self) -> Self { + self.signum() + } + } + + impl Hex for $fty { + fn hex(self) -> String { + self.to_bits().hex() + } + } + )+ + } +} + +impl_float!( + f32, u32, i32, 23; + f64, u64, i64, 52; +); + +/// Common types and methods for integers. +pub trait Int: Copy + fmt::Display + fmt::Debug + PartialEq { + type OtherSign: Int; + type Unsigned: Int; + const BITS: u32; + const SIGNED: bool; + + fn signed(self) -> ::OtherSign; + fn unsigned(self) -> Self::Unsigned; + fn checked_sub(self, other: Self) -> Option; + fn abs(self) -> Self; +} + +macro_rules! impl_int { + ($($ui:ty, $si:ty ;)+) => { + $( + impl Int for $ui { + type OtherSign = $si; + type Unsigned = Self; + const BITS: u32 = <$ui>::BITS; + const SIGNED: bool = false; + fn signed(self) -> Self::OtherSign { + self as $si + } + fn unsigned(self) -> Self { + self + } + fn checked_sub(self, other: Self) -> Option { + self.checked_sub(other) + } + fn abs(self) -> Self { + unimplemented!() + } + } + + impl Int for $si { + type OtherSign = $ui; + type Unsigned = $ui; + const BITS: u32 = <$ui>::BITS; + const SIGNED: bool = true; + fn signed(self) -> Self { + self + } + fn unsigned(self) -> $ui { + self as $ui + } + fn checked_sub(self, other: Self) -> Option { + self.checked_sub(other) + } + fn abs(self) -> Self { + self.abs() + } + } + + impl_int!(@for_both $si); + impl_int!(@for_both $ui); + + )+ + }; + + (@for_both $ty:ty) => { + impl Hex for $ty { + fn hex(self) -> String { + format!("{self:#0width$x}", width = ((Self::BITS / 4) + 2) as usize) + } + } + } +} + +impl_int!( + u32, i32; + u64, i64; +); + +/// A helper trait to print something as hex with the correct number of nibbles, e.g. a `u32` +/// will always print with `0x` followed by 8 digits. +/// +/// This is only used for printing errors so allocating is okay. +pub trait Hex: Copy { + fn hex(self) -> String; +} + +impl Hex for (T1,) +where + T1: Hex, +{ + fn hex(self) -> String { + format!("({},)", self.0.hex()) + } +} + +impl Hex for (T1, T2) +where + T1: Hex, + T2: Hex, +{ + fn hex(self) -> String { + format!("({}, {})", self.0.hex(), self.1.hex()) + } +} + +impl Hex for (T1, T2, T3) +where + T1: Hex, + T2: Hex, + T3: Hex, +{ + fn hex(self) -> String { + format!("({}, {}, {})", self.0.hex(), self.1.hex(), self.2.hex()) + } +} -- cgit 1.4.1-3-g733a5 From d45f6f6fad392b7d84ce788c2236bc3b282f2241 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:55:05 -0500 Subject: Add traits for testing These traits give us a more generic way to interface with tuples used for (1) test input, (2) function arguments, and (3) test input. --- .../libm/crates/libm-test/Cargo.toml | 1 + .../libm/crates/libm-test/src/lib.rs | 6 + .../libm/crates/libm-test/src/num_traits.rs | 25 +++ .../libm/crates/libm-test/src/test_traits.rs | 217 +++++++++++++++++++++ 4 files changed, 249 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 1e76fb70707..b6e2ced5877 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -12,6 +12,7 @@ default = [] test-musl-serialized = ["rand"] [dependencies] +anyhow = "1.0.90" libm = { path = "../.." } libm-macros = { path = "../libm-macros" } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 5444709d87c..41873099f63 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,6 +1,12 @@ mod num_traits; +mod test_traits; pub use num_traits::{Float, Hex, Int}; +pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, TupleCall}; + +/// Result type for tests is usually from `anyhow`. Most times there is no success value to +/// propagate. +pub type TestResult = Result; // List of all files present in libm's source include!(concat!(env!("OUT_DIR"), "/all_files.rs")); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs index 835d6e46d43..d7d806bab9e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs @@ -1,5 +1,7 @@ use std::fmt; +use crate::TestResult; + /// Common types and methods for floating point numbers. pub trait Float: Copy + fmt::Display + fmt::Debug + PartialEq { type Int: Int; @@ -134,6 +136,29 @@ macro_rules! impl_int { format!("{self:#0width$x}", width = ((Self::BITS / 4) + 2) as usize) } } + + impl $crate::CheckOutput for $ty { + fn validate<'a>( + self, + expected: Self, + input: Input, + _ctx: &$crate::CheckCtx, + ) -> TestResult { + anyhow::ensure!( + self == expected, + "\ + \n input: {input:?} {ibits}\ + \n expected: {expected:<22?} {expbits}\ + \n actual: {self:<22?} {actbits}\ + ", + actbits = self.hex(), + expbits = expected.hex(), + ibits = input.hex(), + ); + + Ok(()) + } + } } } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs new file mode 100644 index 00000000000..c6f1f84ae05 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -0,0 +1,217 @@ +//! Traits related to testing. +//! +//! There are three main traits in this module: +//! +//! - `GenerateInput`: implemented on any types that create test cases. +//! - `TupleCall`: implemented on tuples to allow calling them as function arguments. +//! - `CheckOutput`: implemented on anything that is an output type for validation against an +//! expected value. + +use std::fmt; + +use anyhow::{Context, bail, ensure}; + +use crate::{Float, Hex, Int, TestResult}; + +/// Implement this on types that can generate a sequence of tuples for test input. +pub trait GenerateInput { + fn get_cases(&self) -> impl Iterator; +} + +/// Trait for calling a function with a tuple as arguments. +/// +/// Implemented on the tuple with the function signature as the generic (so we can use the same +/// tuple for multiple signatures). +pub trait TupleCall: fmt::Debug { + type Output; + fn call(self, f: Func) -> Self::Output; +} + +/// Context passed to [`CheckOutput`]. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CheckCtx { + /// Allowed ULP deviation + pub ulp: u32, + /// Function name. + pub fname: &'static str, + /// Source of truth for tests. + pub basis: CheckBasis, +} + +/// Possible items to test against +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum CheckBasis {} + +/// A trait to implement on any output type so we can verify it in a generic way. +pub trait CheckOutput: Sized { + /// Validate `self` (actual) and `expected` are the same. + /// + /// `input` is only used here for error messages. + fn validate<'a>(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult; +} + +impl TupleCall R> for (T1,) +where + T1: fmt::Debug, +{ + type Output = R; + + fn call(self, f: fn(T1) -> R) -> Self::Output { + f(self.0) + } +} + +impl TupleCall R> for (T1, T2) +where + T1: fmt::Debug, + T2: fmt::Debug, +{ + type Output = R; + + fn call(self, f: fn(T1, T2) -> R) -> Self::Output { + f(self.0, self.1) + } +} + +impl TupleCall R> for (T1,) +where + T1: fmt::Debug, + T2: fmt::Debug + Default, +{ + type Output = (R, T2); + + fn call(self, f: fn(T1, &mut T2) -> R) -> Self::Output { + let mut t2 = T2::default(); + (f(self.0, &mut t2), t2) + } +} + +impl TupleCall R> for (T1, T2, T3) +where + T1: fmt::Debug, + T2: fmt::Debug, + T3: fmt::Debug, +{ + type Output = R; + + fn call(self, f: fn(T1, T2, T3) -> R) -> Self::Output { + f(self.0, self.1, self.2) + } +} + +impl TupleCall R> for (T1, T2) +where + T1: fmt::Debug, + T2: fmt::Debug, + T3: fmt::Debug + Default, +{ + type Output = (R, T3); + + fn call(self, f: fn(T1, T2, &mut T3) -> R) -> Self::Output { + let mut t3 = T3::default(); + (f(self.0, self.1, &mut t3), t3) + } +} + +impl TupleCall for (T1,) +where + T1: fmt::Debug, + T2: fmt::Debug + Default, + T3: fmt::Debug + Default, +{ + type Output = (T2, T3); + + fn call(self, f: fn(T1, &mut T2, &mut T3)) -> Self::Output { + let mut t2 = T2::default(); + let mut t3 = T3::default(); + f(self.0, &mut t2, &mut t3); + (t2, t3) + } +} + +// Implement for floats +impl CheckOutput for F +where + F: Float + Hex, + Input: Hex + fmt::Debug, + u32: TryFrom, +{ + fn validate<'a>(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult { + // Create a wrapper function so we only need to `.with_context` once. + let inner = || -> TestResult { + // Check when both are NaNs + if self.is_nan() && expected.is_nan() { + ensure!(self.to_bits() == expected.to_bits(), "NaNs have different bitpatterns"); + // Nothing else to check + return Ok(()); + } else if self.is_nan() || expected.is_nan() { + // Check when only one is a NaN + bail!("real value != NaN") + } + + // Make sure that the signs are the same before checing ULP to avoid wraparound + let act_sig = self.signum(); + let exp_sig = expected.signum(); + ensure!(act_sig == exp_sig, "mismatched signs {act_sig} {exp_sig}"); + + if self.is_infinite() ^ expected.is_infinite() { + bail!("mismatched infinities"); + } + + let act_bits = self.to_bits().signed(); + let exp_bits = expected.to_bits().signed(); + + let ulp_diff = act_bits.checked_sub(exp_bits).unwrap().abs(); + + let ulp_u32 = u32::try_from(ulp_diff) + .map_err(|e| anyhow::anyhow!("{e:?}: ulp of {ulp_diff} exceeds u32::MAX"))?; + + let allowed_ulp = ctx.ulp; + ensure!(ulp_u32 <= allowed_ulp, "ulp {ulp_diff} > {allowed_ulp}",); + + Ok(()) + }; + + inner().with_context(|| { + format!( + "\ + \n input: {input:?} {ibits}\ + \n expected: {expected:<22?} {expbits}\ + \n actual: {self:<22?} {actbits}\ + ", + actbits = self.hex(), + expbits = expected.hex(), + ibits = input.hex(), + ) + }) + } +} + +/// Implement `CheckOutput` for combinations of types. +macro_rules! impl_tuples { + ($(($a:ty, $b:ty);)*) => { + $( + impl CheckOutput for ($a, $b) { + fn validate<'a>( + self, + expected: Self, + input: Input, + ctx: &CheckCtx, + ) -> TestResult { + self.0.validate(expected.0, input, ctx,) + .and_then(|()| self.1.validate(expected.1, input, ctx)) + .with_context(|| format!( + "full input {input:?} full actual {self:?} expected {expected:?}" + )) + } + } + )* + }; +} + +impl_tuples!( + (f32, i32); + (f64, i32); + (f32, f32); + (f64, f64); +); -- cgit 1.4.1-3-g733a5 From 128e572054342be4bffc283bf235cfa17c7f5640 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:56:28 -0500 Subject: Add a helper for cached test inputs Add a type that caches values used to implement `GenerateInput` on a variety of signatures. --- .../libm/crates/libm-test/src/gen.rs | 71 ++++++++++++++++++++++ .../libm/crates/libm-test/src/lib.rs | 1 + 2 files changed, 72 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs new file mode 100644 index 00000000000..12e17d47653 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -0,0 +1,71 @@ +//! Different generators that can create random or systematic bit patterns. + +use crate::GenerateInput; + +/// Helper type to turn any reusable input into a generator. +#[derive(Clone, Debug, Default)] +pub struct CachedInput { + pub inputs_f32: Vec<(f32, f32, f32)>, + pub inputs_f64: Vec<(f64, f64, f64)>, + pub inputs_i32: Vec<(i32, i32, i32)>, +} + +impl GenerateInput<(f32,)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_f32.iter().map(|f| (f.0,)) + } +} + +impl GenerateInput<(f32, f32)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_f32.iter().map(|f| (f.0, f.1)) + } +} + +impl GenerateInput<(i32, f32)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_i32.iter().zip(self.inputs_f32.iter()).map(|(i, f)| (i.0, f.0)) + } +} + +impl GenerateInput<(f32, i32)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + GenerateInput::<(i32, f32)>::get_cases(self).map(|(i, f)| (f, i)) + } +} + +impl GenerateInput<(f32, f32, f32)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_f32.iter().copied() + } +} + +impl GenerateInput<(f64,)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_f64.iter().map(|f| (f.0,)) + } +} + +impl GenerateInput<(f64, f64)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_f64.iter().map(|f| (f.0, f.1)) + } +} + +impl GenerateInput<(i32, f64)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_i32.iter().zip(self.inputs_f64.iter()).map(|(i, f)| (i.0, f.0)) + } +} + +impl GenerateInput<(f64, i32)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + GenerateInput::<(i32, f64)>::get_cases(self).map(|(i, f)| (f, i)) + } +} + +impl GenerateInput<(f64, f64, f64)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_f64.iter().copied() + } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 41873099f63..fc5385ecbc2 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,3 +1,4 @@ +pub mod gen; mod num_traits; mod test_traits; -- cgit 1.4.1-3-g733a5 From 593fa8f3cba2daa5b35d87965c5be4e0b59341d0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Oct 2024 16:59:14 -0500 Subject: Add a deterministic random generator Create a test generator that creates a known number of random inputs and caches them, such that the same inputs are used for all functions. --- .../libm/crates/libm-test/Cargo.toml | 6 + .../libm/crates/libm-test/src/gen.rs | 1 + .../libm/crates/libm-test/src/gen/random.rs | 125 +++++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index b6e2ced5877..760340e518c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -15,6 +15,12 @@ test-musl-serialized = ["rand"] anyhow = "1.0.90" libm = { path = "../.." } libm-macros = { path = "../libm-macros" } +rand = "0.8.5" +rand_chacha = "0.3.1" + +[target.'cfg(target_family = "wasm")'.dependencies] +# Enable randomness on WASM +getrandom = { version = "0.2", features = ["js"] } [build-dependencies] rand = { version = "0.8.5", optional = true } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index 12e17d47653..3e9eca37a67 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -1,6 +1,7 @@ //! Different generators that can create random or systematic bit patterns. use crate::GenerateInput; +pub mod random; /// Helper type to turn any reusable input into a generator. #[derive(Clone, Debug, Default)] diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs new file mode 100644 index 00000000000..e5964319569 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -0,0 +1,125 @@ +//! A simple generator that produces deterministic random input, caching to use the same +//! inputs for all functions. + +use std::sync::LazyLock; + +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; + +use super::CachedInput; +use crate::GenerateInput; + +const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; + +/// Number of tests to run. +const NTESTS: usize = { + let ntests = if cfg!(optimizations_enabled) { + if cfg!(target_arch = "x86_64") || cfg!(target_arch = "aarch64") { + 5_000_000 + } else if !cfg!(target_pointer_width = "64") + || cfg!(all(target_arch = "x86_64", target_vendor = "apple")) + || option_env!("EMULATED").is_some() + && cfg!(any(target_arch = "aarch64", target_arch = "powerpc64")) + { + // Tests are pretty slow on: + // - Non-64-bit targets + // - Emulated ppc + // - Emulated aarch64 + // - x86 MacOS + // So reduce the number of iterations + 100_000 + } else { + // Most everything else gets tested in docker and works okay, but we still + // don't need 20 minutes of tests. + 1_000_000 + } + } else { + 800 + }; + + ntests +}; + +/// Tested inputs. +static TEST_CASES: LazyLock = LazyLock::new(|| make_test_cases(NTESTS)); + +/// The first argument to `jn` and `jnf` is the number of iterations. Make this a reasonable +/// value so tests don't run forever. +static TEST_CASES_JN: LazyLock = LazyLock::new(|| { + // Start with regular test cases + let mut cases = (&*TEST_CASES).clone(); + + // These functions are extremely slow, limit them + cases.inputs_i32.truncate((NTESTS / 1000).max(80)); + cases.inputs_f32.truncate((NTESTS / 1000).max(80)); + cases.inputs_f64.truncate((NTESTS / 1000).max(80)); + + // It is easy to overflow the stack with these in debug mode + let max_iterations = if cfg!(optimizations_enabled) && cfg!(target_pointer_width = "64") { + 0xffff + } else if cfg!(windows) { + 0x00ff + } else { + 0x0fff + }; + + let mut rng = ChaCha8Rng::from_seed(SEED); + + for case in cases.inputs_i32.iter_mut() { + case.0 = rng.gen_range(3..=max_iterations); + } + + cases +}); + +fn make_test_cases(ntests: usize) -> CachedInput { + let mut rng = ChaCha8Rng::from_seed(SEED); + + // make sure we include some basic cases + let mut inputs_i32 = vec![(0, 0, 0), (1, 1, 1), (-1, -1, -1)]; + let mut inputs_f32 = vec![ + (0.0, 0.0, 0.0), + (f32::EPSILON, f32::EPSILON, f32::EPSILON), + (f32::INFINITY, f32::INFINITY, f32::INFINITY), + (f32::NEG_INFINITY, f32::NEG_INFINITY, f32::NEG_INFINITY), + (f32::MAX, f32::MAX, f32::MAX), + (f32::MIN, f32::MIN, f32::MIN), + (f32::MIN_POSITIVE, f32::MIN_POSITIVE, f32::MIN_POSITIVE), + (f32::NAN, f32::NAN, f32::NAN), + ]; + let mut inputs_f64 = vec![ + (0.0, 0.0, 0.0), + (f64::EPSILON, f64::EPSILON, f64::EPSILON), + (f64::INFINITY, f64::INFINITY, f64::INFINITY), + (f64::NEG_INFINITY, f64::NEG_INFINITY, f64::NEG_INFINITY), + (f64::MAX, f64::MAX, f64::MAX), + (f64::MIN, f64::MIN, f64::MIN), + (f64::MIN_POSITIVE, f64::MIN_POSITIVE, f64::MIN_POSITIVE), + (f64::NAN, f64::NAN, f64::NAN), + ]; + + inputs_i32.extend((0..(ntests - inputs_i32.len())).map(|_| rng.gen::<(i32, i32, i32)>())); + + // Generate integers to get a full range of bitpatterns, then convert back to + // floats. + inputs_f32.extend((0..(ntests - inputs_f32.len())).map(|_| { + let ints = rng.gen::<(u32, u32, u32)>(); + (f32::from_bits(ints.0), f32::from_bits(ints.1), f32::from_bits(ints.2)) + })); + inputs_f64.extend((0..(ntests - inputs_f64.len())).map(|_| { + let ints = rng.gen::<(u64, u64, u64)>(); + (f64::from_bits(ints.0), f64::from_bits(ints.1), f64::from_bits(ints.2)) + })); + + CachedInput { inputs_f32, inputs_f64, inputs_i32 } +} + +/// Create a test case iterator. +pub fn get_test_cases(fname: &str) -> impl Iterator +where + CachedInput: GenerateInput, +{ + let inputs = if fname == "jn" || fname == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; + + CachedInput::get_cases(inputs) +} -- cgit 1.4.1-3-g733a5 From 98647ddc2fb3ff6f9bdff9792b967d5b626ea76f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Oct 2024 00:52:00 -0500 Subject: Introduce a generic way to control checks for specific cases Sometimes we want to be able to xfail specific inputs without changing the checked ULP for all cases or skipping the tests. There are also some cases where we need to perform extra checks for only specific functions. Add a trait that provides a hook for providing extra checks or skipping existing checks on a per-function or per-input basis. --- .../libm/crates/libm-test/src/lib.rs | 23 ++++++ .../libm/crates/libm-test/src/num_traits.rs | 14 +++- .../libm/crates/libm-test/src/special_case.rs | 95 ++++++++++++++++++++++ .../libm/crates/libm-test/src/test_traits.rs | 39 +++++++-- 4 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/special_case.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index fc5385ecbc2..511b5139f0d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,8 +1,10 @@ pub mod gen; mod num_traits; +mod special_case; mod test_traits; pub use num_traits::{Float, Hex, Int}; +pub use special_case::{MaybeOverride, SpecialCase}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to @@ -11,3 +13,24 @@ pub type TestResult = Result; // List of all files present in libm's source include!(concat!(env!("OUT_DIR"), "/all_files.rs")); + +/// Return the unsuffixed version of a function name; e.g. `abs` and `absf` both return `abs`, +/// `lgamma_r` and `lgammaf_r` both return `lgamma_r`. +pub fn canonical_name(name: &str) -> &str { + let known_mappings = &[ + ("erff", "erf"), + ("erf", "erf"), + ("lgammaf_r", "lgamma_r"), + ("modff", "modf"), + ("modf", "modf"), + ]; + + match known_mappings.iter().find(|known| known.0 == name) { + Some(found) => found.1, + None => name + .strip_suffix("f") + .or_else(|| name.strip_suffix("f16")) + .or_else(|| name.strip_suffix("f128")) + .unwrap_or(name), + } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs index d7d806bab9e..e16f4e4dca4 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs @@ -1,6 +1,6 @@ use std::fmt; -use crate::TestResult; +use crate::{MaybeOverride, SpecialCase, TestResult}; /// Common types and methods for floating point numbers. pub trait Float: Copy + fmt::Display + fmt::Debug + PartialEq { @@ -137,13 +137,21 @@ macro_rules! impl_int { } } - impl $crate::CheckOutput for $ty { + impl $crate::CheckOutput for $ty + where + Input: Hex + fmt::Debug, + SpecialCase: MaybeOverride, + { fn validate<'a>( self, expected: Self, input: Input, - _ctx: &$crate::CheckCtx, + ctx: &$crate::CheckCtx, ) -> TestResult { + if let Some(res) = SpecialCase::check_int(input, self, expected, ctx) { + return res; + } + anyhow::ensure!( self == expected, "\ diff --git a/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs b/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs new file mode 100644 index 00000000000..116a0a1881e --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs @@ -0,0 +1,95 @@ +//! Configuration for skipping or changing the result for individual test cases (inputs) rather +//! than ignoring entire tests. + +use crate::{CheckCtx, Float, Int, TestResult}; + +/// Type implementing [`IgnoreCase`]. +pub struct SpecialCase; + +/// Don't run further validation on this test case. +const SKIP: Option = Some(Ok(())); + +/// Return this to skip checks on a test that currently fails but shouldn't. Looks +/// the same as skip, but we keep them separate to better indicate purpose. +const XFAIL: Option = Some(Ok(())); + +/// Allow overriding the outputs of specific test cases. +/// +/// There are some cases where we want to xfail specific cases or handle certain inputs +/// differently than the rest of calls to `validate`. This provides a hook to do that. +/// +/// If `None` is returned, checks will proceed as usual. If `Some(result)` is returned, checks +/// are skipped and the provided result is returned instead. +/// +/// This gets implemented once per input type, then the functions provide further filtering +/// based on function name and values. +/// +/// `ulp` can also be set to adjust the ULP for that specific test, even if `None` is still +/// returned. +pub trait MaybeOverride { + fn check_float( + _input: Input, + _actual: F, + _expected: F, + _ulp: &mut u32, + _ctx: &CheckCtx, + ) -> Option { + None + } + + fn check_int( + _input: Input, + _actual: I, + _expected: I, + _ctx: &CheckCtx, + ) -> Option { + None + } +} + +impl MaybeOverride<(f32,)> for SpecialCase { + fn check_float( + _input: (f32,), + actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_check_nan_bits(actual, expected, ctx) + } +} + +impl MaybeOverride<(f64,)> for SpecialCase { + fn check_float( + _input: (f64,), + actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_check_nan_bits(actual, expected, ctx) + } +} + +impl MaybeOverride<(f32, f32)> for SpecialCase {} +impl MaybeOverride<(f64, f64)> for SpecialCase {} +impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} +impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} +impl MaybeOverride<(i32, f32)> for SpecialCase {} +impl MaybeOverride<(i32, f64)> for SpecialCase {} +impl MaybeOverride<(f32, i32)> for SpecialCase {} +impl MaybeOverride<(f64, i32)> for SpecialCase {} + +/// Check NaN bits if the function requires it +fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { + if !(ctx.canonical_name == "abs" || ctx.canonical_name == "copysigh") { + return None; + } + + // abs and copysign require signaling NaNs to be propagated, so verify bit equality. + if actual.to_bits() == expected.to_bits() { + return SKIP; + } else { + Some(Err(anyhow::anyhow!("NaNs have different bitpatterns"))) + } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index c6f1f84ae05..296f1b0fd18 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -11,7 +11,7 @@ use std::fmt; use anyhow::{Context, bail, ensure}; -use crate::{Float, Hex, Int, TestResult}; +use crate::{Float, Hex, Int, MaybeOverride, SpecialCase, TestResult}; /// Implement this on types that can generate a sequence of tuples for test input. pub trait GenerateInput { @@ -34,10 +34,19 @@ pub struct CheckCtx { pub ulp: u32, /// Function name. pub fname: &'static str, + /// Return the unsuffixed version of the function name. + pub canonical_name: &'static str, /// Source of truth for tests. pub basis: CheckBasis, } +impl CheckCtx { + pub fn new(ulp: u32, fname: &'static str, basis: CheckBasis) -> Self { + let canonical_fname = crate::canonical_name(fname); + Self { ulp, fname, canonical_name: canonical_fname, basis } + } +} + /// Possible items to test against #[derive(Clone, Debug, PartialEq, Eq)] pub enum CheckBasis {} @@ -135,10 +144,20 @@ where F: Float + Hex, Input: Hex + fmt::Debug, u32: TryFrom, + SpecialCase: MaybeOverride, { fn validate<'a>(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult { // Create a wrapper function so we only need to `.with_context` once. let inner = || -> TestResult { + let mut allowed_ulp = ctx.ulp; + + // If the tested function requires a nonstandard test, run it here. + if let Some(res) = + SpecialCase::check_float(input, self, expected, &mut allowed_ulp, ctx) + { + return res; + } + // Check when both are NaNs if self.is_nan() && expected.is_nan() { ensure!(self.to_bits() == expected.to_bits(), "NaNs have different bitpatterns"); @@ -166,7 +185,6 @@ where let ulp_u32 = u32::try_from(ulp_diff) .map_err(|e| anyhow::anyhow!("{e:?}: ulp of {ulp_diff} exceeds u32::MAX"))?; - let allowed_ulp = ctx.ulp; ensure!(ulp_u32 <= allowed_ulp, "ulp {ulp_diff} > {allowed_ulp}",); Ok(()) @@ -191,17 +209,28 @@ where macro_rules! impl_tuples { ($(($a:ty, $b:ty);)*) => { $( - impl CheckOutput for ($a, $b) { + impl CheckOutput for ($a, $b) + where + Input: Hex + fmt::Debug, + SpecialCase: MaybeOverride, + { fn validate<'a>( self, expected: Self, input: Input, ctx: &CheckCtx, ) -> TestResult { - self.0.validate(expected.0, input, ctx,) + self.0.validate(expected.0, input, ctx) .and_then(|()| self.1.validate(expected.1, input, ctx)) .with_context(|| format!( - "full input {input:?} full actual {self:?} expected {expected:?}" + "full context:\ + \n input: {input:?} {ibits}\ + \n expected: {expected:?} {expbits}\ + \n actual: {self:?} {actbits}\ + ", + actbits = self.hex(), + expbits = expected.hex(), + ibits = input.hex(), )) } } -- cgit 1.4.1-3-g733a5 From 1073858c72cf7fed6a40a5ab24a80c696e56c384 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:59:17 -0500 Subject: Add a test against musl libm Check our functions against `musl-math-sys`. This is similar to the existing musl tests that go through binary serialization, but works on more platforms. --- .../libm/crates/libm-test/Cargo.toml | 5 + .../libm/crates/libm-test/src/lib.rs | 28 ++++ .../libm/crates/libm-test/src/special_case.rs | 170 +++++++++++++++++++-- .../libm/crates/libm-test/src/test_traits.rs | 8 +- .../crates/libm-test/tests/compare_built_musl.rs | 52 +++++++ 5 files changed, 247 insertions(+), 16 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 760340e518c..703524bcd70 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -11,10 +11,15 @@ default = [] # musl libc. test-musl-serialized = ["rand"] +# Build our own musl for testing and benchmarks +build-musl = ["dep:musl-math-sys"] + [dependencies] anyhow = "1.0.90" libm = { path = "../.." } libm-macros = { path = "../libm-macros" } +musl-math-sys = { path = "../musl-math-sys", optional = true } +paste = "1.0.15" rand = "0.8.5" rand_chacha = "0.3.1" diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 511b5139f0d..3baf77524f0 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -14,6 +14,34 @@ pub type TestResult = Result; // List of all files present in libm's source include!(concat!(env!("OUT_DIR"), "/all_files.rs")); +/// ULP allowed to differ from musl (note that musl itself may not be accurate). +const MUSL_DEFAULT_ULP: u32 = 2; + +/// Certain functions have different allowed ULP (consider these xfail). +/// +/// Note that these results were obtained using 400,000,000 rounds of random inputs, which +/// is not a value used by default. +pub fn musl_allowed_ulp(name: &str) -> u32 { + match name { + #[cfg(x86_no_sse)] + "asinh" | "asinhf" => 6, + "lgamma" | "lgamma_r" | "lgammaf" | "lgammaf_r" => 400, + "tanh" | "tanhf" => 4, + "tgamma" => 20, + "j0" | "j0f" | "j1" | "j1f" => { + // Results seem very target-dependent + if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } + } + "jn" | "jnf" => 1000, + "sincosf" => 500, + #[cfg(not(target_pointer_width = "64"))] + "exp10" => 4, + #[cfg(not(target_pointer_width = "64"))] + "exp10f" => 4, + _ => MUSL_DEFAULT_ULP, + } +} + /// Return the unsuffixed version of a function name; e.g. `abs` and `absf` both return `abs`, /// `lgamma_r` and `lgammaf_r` both return `lgamma_r`. pub fn canonical_name(name: &str) -> &str { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs b/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs index 116a0a1881e..df263d7428c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs @@ -1,7 +1,9 @@ //! Configuration for skipping or changing the result for individual test cases (inputs) rather //! than ignoring entire tests. -use crate::{CheckCtx, Float, Int, TestResult}; +use core::f32; + +use crate::{CheckBasis, CheckCtx, Float, Int, TestResult}; /// Type implementing [`IgnoreCase`]. pub struct SpecialCase; @@ -49,43 +51,97 @@ pub trait MaybeOverride { impl MaybeOverride<(f32,)> for SpecialCase { fn check_float( - _input: (f32,), + input: (f32,), actual: F, expected: F, _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { + if ctx.basis == CheckBasis::Musl { + if ctx.fname == "acoshf" && input.0 < -1.0 { + // acoshf is undefined for x <= 1.0, but we return a random result at lower + // values. + return XFAIL; + } + + if ctx.fname == "sincosf" { + let factor_frac_pi_2 = input.0.abs() / f32::consts::FRAC_PI_2; + if (factor_frac_pi_2 - factor_frac_pi_2.round()).abs() < 1e-2 { + // we have a bad approximation near multiples of pi/2 + return XFAIL; + } + } + + if ctx.fname == "expm1f" && input.0 > 80.0 && actual.is_infinite() { + // we return infinity but the number is representable + return XFAIL; + } + + if ctx.fname == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { + // we return some NaN that should be real values or infinite + // doesn't seem to happen on x86 + return XFAIL; + } + + if ctx.fname == "lgammaf" || ctx.fname == "lgammaf_r" && input.0 < 0.0 { + // loggamma should not be defined for x < 0, yet we both return results + return XFAIL; + } + } + maybe_check_nan_bits(actual, expected, ctx) } } impl MaybeOverride<(f64,)> for SpecialCase { fn check_float( - _input: (f64,), + input: (f64,), actual: F, expected: F, _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { + if ctx.basis == CheckBasis::Musl { + if cfg!(target_arch = "x86") && ctx.fname == "acosh" && input.0 < 1.0 { + // The function is undefined, both implementations return random results + return SKIP; + } + + if cfg!(x86_no_sse) + && ctx.fname == "ceil" + && input.0 < 0.0 + && input.0 > -1.0 + && expected == F::ZERO + && actual == F::ZERO + { + // musl returns -0.0, we return +0.0 + return XFAIL; + } + + if ctx.fname == "lgamma" || ctx.fname == "lgamma_r" && input.0 < 0.0 { + // loggamma should not be defined for x < 0, yet we both return results + return XFAIL; + } + } + maybe_check_nan_bits(actual, expected, ctx) } } -impl MaybeOverride<(f32, f32)> for SpecialCase {} -impl MaybeOverride<(f64, f64)> for SpecialCase {} -impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} -impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} -impl MaybeOverride<(i32, f32)> for SpecialCase {} -impl MaybeOverride<(i32, f64)> for SpecialCase {} -impl MaybeOverride<(f32, i32)> for SpecialCase {} -impl MaybeOverride<(f64, i32)> for SpecialCase {} - /// Check NaN bits if the function requires it fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { - if !(ctx.canonical_name == "abs" || ctx.canonical_name == "copysigh") { + if !(ctx.canonical_name == "fabs" || ctx.canonical_name == "copysign") { return None; } + // LLVM currently uses x87 instructions which quieten signalling NaNs to handle the i686 + // `extern "C"` `f32`/`f64` return ABI. + // LLVM issue + // Rust issue + if cfg!(target_arch = "x86") && ctx.basis == CheckBasis::Musl { + return SKIP; + } + // abs and copysign require signaling NaNs to be propagated, so verify bit equality. if actual.to_bits() == expected.to_bits() { return SKIP; @@ -93,3 +149,91 @@ fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Opt Some(Err(anyhow::anyhow!("NaNs have different bitpatterns"))) } } + +impl MaybeOverride<(f32, f32)> for SpecialCase { + fn check_float( + input: (f32, f32), + _actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_skip_min_max_nan(input, expected, ctx) + } +} +impl MaybeOverride<(f64, f64)> for SpecialCase { + fn check_float( + input: (f64, f64), + _actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_skip_min_max_nan(input, expected, ctx) + } +} + +/// Musl propagates NaNs if one is provided as the input, but we return the other input. +// F1 and F2 are always the same type, this is just to please generics +fn maybe_skip_min_max_nan( + input: (F1, F1), + expected: F2, + ctx: &CheckCtx, +) -> Option { + if (ctx.canonical_name == "fmax" || ctx.canonical_name == "fmin") + && (input.0.is_nan() || input.1.is_nan()) + && expected.is_nan() + { + return XFAIL; + } else { + None + } +} + +impl MaybeOverride<(i32, f32)> for SpecialCase { + fn check_float( + input: (i32, f32), + _actual: F, + _expected: F, + ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + bessel_prec_dropoff(input, ulp, ctx) + } +} +impl MaybeOverride<(i32, f64)> for SpecialCase { + fn check_float( + input: (i32, f64), + _actual: F, + _expected: F, + ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + bessel_prec_dropoff(input, ulp, ctx) + } +} + +/// Our bessel functions blow up with large N values +fn bessel_prec_dropoff( + input: (i32, F), + ulp: &mut u32, + ctx: &CheckCtx, +) -> Option { + if ctx.canonical_name == "jn" { + if input.0 > 4000 { + return XFAIL; + } else if input.0 > 2000 { + // *ulp = 20_000; + *ulp = 20000; + } else if input.0 > 1000 { + *ulp = 4000; + } + } + + None +} + +impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} +impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} +impl MaybeOverride<(f32, i32)> for SpecialCase {} +impl MaybeOverride<(f64, i32)> for SpecialCase {} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 296f1b0fd18..c24ac6e43bc 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -49,7 +49,10 @@ impl CheckCtx { /// Possible items to test against #[derive(Clone, Debug, PartialEq, Eq)] -pub enum CheckBasis {} +pub enum CheckBasis { + /// Check against Musl's math sources. + Musl, +} /// A trait to implement on any output type so we can verify it in a generic way. pub trait CheckOutput: Sized { @@ -160,8 +163,7 @@ where // Check when both are NaNs if self.is_nan() && expected.is_nan() { - ensure!(self.to_bits() == expected.to_bits(), "NaNs have different bitpatterns"); - // Nothing else to check + // By default, NaNs have nothing special to check. return Ok(()); } else if self.is_nan() || expected.is_nan() { // Check when only one is a NaN diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs new file mode 100644 index 00000000000..208b8e28618 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -0,0 +1,52 @@ +//! Compare our implementations with the result of musl functions, as provided by `musl-math-sys`. +//! +//! Currently this only tests randomized inputs. In the future this may be improved to test edge +//! cases or run exhaustive tests. +//! +//! Note that musl functions do not always provide 0.5ULP rounding, so our functions can do better +//! than these results. + +// There are some targets we can't build musl for +#![cfg(feature = "build-musl")] + +use libm_test::gen::random; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, TupleCall, musl_allowed_ulp}; +use musl_math_sys as musl; + +macro_rules! musl_rand_tests { + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + attrs: [$($meta:meta)*] + ) => { paste::paste! { + #[test] + $(#[$meta])* + fn [< musl_random_ $fn_name >]() { + let fname = stringify!($fn_name); + let ulp = musl_allowed_ulp(fname); + let cases = random::get_test_cases::<$RustArgs>(fname); + let ctx = CheckCtx::new(ulp, fname, CheckBasis::Musl); + + for input in cases { + let musl_res = input.call(musl::$fn_name as $CFn); + let crate_res = input.call(libm::$fn_name as $RustFn); + + crate_res.validate(musl_res, input, &ctx).unwrap(); + } + } + } }; +} + +libm_macros::for_each_function! { + callback: musl_rand_tests, + skip: [], + attributes: [ + #[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586 + [exp10, exp10f, exp2, exp2f, rint] + ], +} -- cgit 1.4.1-3-g733a5 From 31d0132ac14dc2e2b3fb24ac38309ca5ab7ca235 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:33:27 -0500 Subject: Add dockerfiles for i586, riscv, and thumb These targets are tested in `compiler-builtins`, but not yet `libm`. Add dockerfiles to prepare for this. --- .../libm/ci/docker/i586-unknown-linux-gnu/Dockerfile | 5 +++++ .../libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile | 15 +++++++++++++++ .../libm/ci/docker/thumbv6m-none-eabi/Dockerfile | 9 +++++++++ .../libm/ci/docker/thumbv7em-none-eabi/Dockerfile | 9 +++++++++ .../libm/ci/docker/thumbv7em-none-eabihf/Dockerfile | 9 +++++++++ .../libm/ci/docker/thumbv7m-none-eabi/Dockerfile | 9 +++++++++ 6 files changed, 56 insertions(+) create mode 100644 library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/thumbv6m-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/thumbv7m-none-eabi/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..3b0bfc0d3d9 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc-multilib libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..5f8a2892411 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-riscv64-linux-gnu libc6-dev-riscv64-cross \ + qemu-system-riscv64 + +ENV TOOLCHAIN_PREFIX=riscv64-linux-gnu- +ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ + CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER=qemu-riscv64-static \ + AR_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ + QEMU_LD_PREFIX=/usr/riscv64-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/thumbv6m-none-eabi/Dockerfile new file mode 100644 index 00000000000..ad0d4351ea6 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -0,0 +1,9 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabi/Dockerfile new file mode 100644 index 00000000000..ad0d4351ea6 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -0,0 +1,9 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile new file mode 100644 index 00000000000..ad0d4351ea6 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -0,0 +1,9 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/libm/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/thumbv7m-none-eabi/Dockerfile new file mode 100644 index 00000000000..ad0d4351ea6 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -0,0 +1,9 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV BUILD_ONLY=1 -- cgit 1.4.1-3-g733a5 From ee131ffa47ee17f4ac1f3d32230bbb3638183c0c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 23:00:17 -0500 Subject: Disable a unit test that is failing on i586 --- library/compiler-builtins/libm/src/math/rem_pio2.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 6be23a43ced..4dfb8c65883 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -194,6 +194,8 @@ mod tests { use super::rem_pio2; #[test] + // FIXME(correctness): inaccurate results on i586 + #[cfg_attr(all(target_arch = "x86", not(target_feature = "sse")), ignore)] fn test_near_pi() { let arg = 3.141592025756836; let arg = force_eval!(arg); -- cgit 1.4.1-3-g733a5 From f5d30ecc3b8b886c2ce0cd7ebaf3cbb80206eac1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:59:59 -0500 Subject: Enable more targets on CI This brings the targets tested here in line with those tested in `compiler-builtins`. --- .../libm/.github/workflows/main.yml | 121 ++++++++++++++++----- library/compiler-builtins/libm/ci/run-docker.sh | 1 + library/compiler-builtins/libm/ci/run.sh | 69 +++++++++--- 3 files changed, 151 insertions(+), 40 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 926e3c19e2e..a2c7795261d 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -2,38 +2,103 @@ name: CI on: [push, pull_request] env: + CARGO_TERM_VERBOSE: true RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings + RUST_BACKTRACE: full jobs: - docker: + test: name: Docker - runs-on: ubuntu-latest + timeout-minutes: 20 strategy: + fail-fast: false matrix: - target: - - aarch64-unknown-linux-gnu - - arm-unknown-linux-gnueabi - - arm-unknown-linux-gnueabihf - - armv7-unknown-linux-gnueabihf - # - i686-unknown-linux-gnu - # MIPS targets disabled since they are dropped to tier 3. - # See https://github.com/rust-lang/compiler-team/issues/648 - #- mips-unknown-linux-gnu - #- mips64-unknown-linux-gnuabi64 - #- mips64el-unknown-linux-gnuabi64 - - powerpc-unknown-linux-gnu - - powerpc64-unknown-linux-gnu - - powerpc64le-unknown-linux-gnu - - x86_64-unknown-linux-gnu + include: + - target: aarch64-apple-darwin + os: macos-latest + - target: aarch64-unknown-linux-gnu + os: ubuntu-latest + - target: aarch64-pc-windows-msvc + os: windows-latest + build_only: 1 # Can't run on x86 hosts + - target: arm-unknown-linux-gnueabi + os: ubuntu-latest + - target: arm-unknown-linux-gnueabihf + os: ubuntu-latest + - target: armv7-unknown-linux-gnueabihf + os: ubuntu-latest + - target: i586-unknown-linux-gnu + os: ubuntu-latest + - target: i686-unknown-linux-gnu + os: ubuntu-latest + - target: powerpc-unknown-linux-gnu + os: ubuntu-latest + - target: powerpc64-unknown-linux-gnu + os: ubuntu-latest + - target: powerpc64le-unknown-linux-gnu + os: ubuntu-latest + - target: riscv64gc-unknown-linux-gnu + os: ubuntu-latest + - target: thumbv6m-none-eabi + os: ubuntu-latest + - target: thumbv7em-none-eabi + os: ubuntu-latest + - target: thumbv7em-none-eabihf + os: ubuntu-latest + - target: thumbv7m-none-eabi + os: ubuntu-latest + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + - target: x86_64-apple-darwin + os: macos-13 + - target: i686-pc-windows-msvc + os: windows-latest + - target: x86_64-pc-windows-msvc + os: windows-latest + - target: i686-pc-windows-gnu + os: windows-latest + channel: nightly-i686-gnu + - target: x86_64-pc-windows-gnu + os: windows-latest + channel: nightly-x86_64-gnu + runs-on: ${{ matrix.os }} + env: + BUILD_ONLY: ${{ matrix.build_only }} steps: - - uses: actions/checkout@master - - name: Install Rust - run: rustup update nightly --no-self-update && rustup default nightly - - run: rustup target add ${{ matrix.target }} - - run: rustup target add x86_64-unknown-linux-musl - - run: cargo generate-lockfile - - run: ./ci/run-docker.sh ${{ matrix.target }} + - name: Print runner information + run: uname -a + - uses: actions/checkout@v4 + - name: Install Rust (rustup) + shell: bash + run: | + channel="nightly" + # Account for channels that have required components (MinGW) + [ -n "${{ matrix.channel }}" ] && channel="${{ matrix.channel }}" + rustup update "$channel" --no-self-update + rustup default "$channel" + rustup target add ${{ matrix.target }} + rustup component add llvm-tools-preview + - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} + + - name: Download musl source + run: ./ci/download-musl.sh + shell: bash + + # Non-linux tests just use our raw script + - name: Run locally + if: matrix.os != 'ubuntu-latest' + shell: bash + run: ./ci/run.sh ${{ matrix.target }} + + # Otherwise we use our docker containers to run builds + - name: Run in Docker + if: matrix.os == 'ubuntu-latest' + run: | + rustup target add x86_64-unknown-linux-musl + cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} wasm: name: WebAssembly @@ -45,7 +110,7 @@ jobs: - run: rustup target add wasm32-unknown-unknown - run: cargo build --target wasm32-unknown-unknown - cb: + builtins: name: "The compiler-builtins crate works" runs-on: ubuntu-latest steps: @@ -61,6 +126,8 @@ jobs: - uses: actions/checkout@master - name: Install Rust run: rustup update nightly --no-self-update && rustup default nightly + - name: Download musl source + run: ./ci/download-musl.sh - run: cargo bench --all msrv: @@ -92,9 +159,9 @@ jobs: success: needs: - - docker + - test - wasm - - cb + - builtins - benchmarks - msrv - rustfmt diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index 9191a17e2ba..2e09dd41a57 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -21,6 +21,7 @@ run() { -e RUSTFLAGS \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ + -e EMULATED=1 \ -v "${HOME}/.cargo:/cargo" \ -v "$(pwd)/target:/target" \ -v "$(pwd):/checkout:ro" \ diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 505e2589187..f61fff8433e 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -2,21 +2,64 @@ set -eux -target="$1" +export RUST_BACKTRACE="${RUST_BACKTRACE:-full}" +# Needed for no-panic to correct detect a lack of panics +export RUSTFLAGS="${RUSTFLAGS:-} -Ccodegen-units=1" -cmd="cargo test --all --target $target" +target="${1:-}" -# Needed for no-panic to correct detect a lack of panics -export RUSTFLAGS="$RUSTFLAGS -Ccodegen-units=1" +if [ -z "$target" ]; then + host_target=$(rustc -vV | awk '/^host/ { print $2 }') + echo "Defaulted to host target $host_target" + target="$host_target" +fi + +extra_flags="" + +# We need to specifically skip tests for musl-math-sys on systems that can't +# build musl since otherwise `--all` will activate it. +case "$target" in + # Can't build at all on MSVC, WASM, or thumb + *windows-msvc*) extra_flags="$extra_flags --exclude musl-math-sys" ;; + *wasm*) extra_flags="$extra_flags --exclude musl-math-sys" ;; + *thumb*) extra_flags="$extra_flags --exclude musl-math-sys" ;; + + # We can build musl on MinGW but running tests gets a stack overflow + *windows-gnu*) ;; + # FIXME(#309): LE PPC crashes calling the musl version of some functions. It + # seems like a qemu bug but should be investigated further at some point. + # See . + *powerpc64le*) ;; + + # Everything else gets musl enabled + *) extra_flags="$extra_flags --features libm-test/build-musl" ;; +esac + +# FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. +# +case "$target" in + *windows-gnu) extra_flags="$extra_flags --exclude libm-macros" ;; +esac + +if [ "$(uname -a)" = "Linux" ]; then + # also run the reference tests when we can. requires a Linux host. + extra_flags="$extra_flags --features libm-test/test-musl-serialized" +fi + +if [ "${BUILD_ONLY:-}" = "1" ]; then + cmd="cargo build --target $target --package libm" + $cmd + $cmd --features 'unstable' -# stable by default -$cmd -$cmd --release + echo "can't run tests on $target" +else + cmd="cargo test --all --target $target $extra_flags" -# unstable with a feature -$cmd --features 'unstable' -$cmd --release --features 'unstable' + # stable by default + $cmd + $cmd --release -# also run the reference tests -$cmd --features 'unstable libm-test/test-musl-serialized' -$cmd --release --features 'unstable libm-test/test-musl-serialized' + # unstable with a feature + $cmd --features 'unstable' + $cmd --release --features 'unstable' +fi -- cgit 1.4.1-3-g733a5 From bf757e3a7b35473ca3affdff0ab2b8e7e422b3fe Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 13:22:57 -0500 Subject: Mark libm-macros and musl-math-sys as publish=false --- library/compiler-builtins/libm/crates/libm-macros/Cargo.toml | 1 + library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml index 9d2b08e2d78..3da9d45a2b9 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml @@ -2,6 +2,7 @@ name = "libm-macros" version = "0.1.0" edition = "2021" +publish = false [lib] proc-macro = true diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml index 449ce4f3ed1..7f6272d79ed 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml +++ b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml @@ -2,6 +2,7 @@ name = "musl-math-sys" version = "0.1.0" edition = "2021" +publish = false [dependencies] -- cgit 1.4.1-3-g733a5 From ebb2dc11d854f048537bbc41fb11448e4ce27481 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 13:30:39 -0500 Subject: Reduce the number of iterations on emulated aarch64 Linux CI for aarch64 Linux is significantly slower than the others. Adjust how iteration selection is done to better handle this case, which also simplifies things. Also set the `EMULATED` environment variable in Docker to be more accurate, and reindents run-docker.sh. --- library/compiler-builtins/libm/ci/run-docker.sh | 48 +++++++++++++--------- .../libm/crates/libm-test/src/gen/random.rs | 26 ++++-------- .../libm/crates/libm-test/src/lib.rs | 9 ++++ 3 files changed, 46 insertions(+), 37 deletions(-) diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index 2e09dd41a57..a040126df84 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -5,39 +5,49 @@ set -euxo pipefail +host_arch="$(uname -m | sed 's/arm64/aarch64/')" + run() { local target=$1 echo "testing target: $target" + target_arch="$(echo "$target" | cut -d'-' -f1)" + + emulated="" + if [ "$target_arch" != "$host_arch" ]; then + emulated=1 + echo "target is emulated" + fi + # This directory needs to exist before calling docker, otherwise docker will create it but it # will be owned by root mkdir -p target docker build -t "$target" "ci/docker/$target" docker run \ - --rm \ - --user "$(id -u):$(id -g)" \ - -e RUSTFLAGS \ - -e CARGO_HOME=/cargo \ - -e CARGO_TARGET_DIR=/target \ - -e EMULATED=1 \ - -v "${HOME}/.cargo:/cargo" \ - -v "$(pwd)/target:/target" \ - -v "$(pwd):/checkout:ro" \ - -v "$(rustc --print sysroot):/rust:ro" \ - --init \ - -w /checkout \ - "$target" \ - sh -c "HOME=/tmp PATH=\$PATH:/rust/bin exec ci/run.sh $target" + --rm \ + --user "$(id -u):$(id -g)" \ + -e RUSTFLAGS \ + -e CARGO_HOME=/cargo \ + -e CARGO_TARGET_DIR=/target \ + -e "EMULATED=$emulated" \ + -v "${HOME}/.cargo:/cargo" \ + -v "$(pwd)/target:/target" \ + -v "$(pwd):/checkout:ro" \ + -v "$(rustc --print sysroot):/rust:ro" \ + --init \ + -w /checkout \ + "$target" \ + sh -c "HOME=/tmp PATH=\$PATH:/rust/bin exec ci/run.sh $target" } if [ -z "$1" ]; then - echo "running tests for all targets" + echo "running tests for all targets" - for d in ci/docker/*; do - run $d - done + for d in ci/docker/*; do + run $d + done else - run $1 + run $1 fi diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index e5964319569..601ef4f1d46 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -13,31 +13,21 @@ const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; /// Number of tests to run. const NTESTS: usize = { - let ntests = if cfg!(optimizations_enabled) { - if cfg!(target_arch = "x86_64") || cfg!(target_arch = "aarch64") { - 5_000_000 - } else if !cfg!(target_pointer_width = "64") + if cfg!(optimizations_enabled) { + if crate::emulated() + || !cfg!(target_pointer_width = "64") || cfg!(all(target_arch = "x86_64", target_vendor = "apple")) - || option_env!("EMULATED").is_some() - && cfg!(any(target_arch = "aarch64", target_arch = "powerpc64")) { - // Tests are pretty slow on: - // - Non-64-bit targets - // - Emulated ppc - // - Emulated aarch64 - // - x86 MacOS - // So reduce the number of iterations + // Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run + // in QEMU. 100_000 } else { - // Most everything else gets tested in docker and works okay, but we still - // don't need 20 minutes of tests. - 1_000_000 + 5_000_000 } } else { + // Without optimizations just run a quick check 800 - }; - - ntests + } }; /// Tested inputs. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 3baf77524f0..2abe7f605ea 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -62,3 +62,12 @@ pub fn canonical_name(name: &str) -> &str { .unwrap_or(name), } } + +/// True if `EMULATED` is set and nonempty. Used to determine how many iterations to run. +pub const fn emulated() -> bool { + match option_env!("EMULATED") { + Some(s) if s.is_empty() => false, + None => false, + Some(_) => true, + } +} -- cgit 1.4.1-3-g733a5 From 0109445d5967f59d48f8e530acc36c29cb1912c1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 15:07:34 -0500 Subject: Enable caching on all CI jobs that build the crate (#341) --- library/compiler-builtins/libm/.github/workflows/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index a2c7795261d..15eba6e8905 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -108,6 +108,7 @@ jobs: - name: Install Rust run: rustup update nightly --no-self-update && rustup default nightly - run: rustup target add wasm32-unknown-unknown + - uses: Swatinem/rust-cache@v2 - run: cargo build --target wasm32-unknown-unknown builtins: @@ -117,6 +118,7 @@ jobs: - uses: actions/checkout@master - name: Install Rust run: rustup update nightly --no-self-update && rustup default nightly + - uses: Swatinem/rust-cache@v2 - run: cargo build -p cb benchmarks: @@ -126,6 +128,7 @@ jobs: - uses: actions/checkout@master - name: Install Rust run: rustup update nightly --no-self-update && rustup default nightly + - uses: Swatinem/rust-cache@v2 - name: Download musl source run: ./ci/download-musl.sh - run: cargo bench --all @@ -143,6 +146,7 @@ jobs: echo "MSRV=$msrv" >> "$GITHUB_ENV" - name: Install Rust run: rustup update "$MSRV" --no-self-update && rustup default "$MSRV" + - uses: Swatinem/rust-cache@v2 - run: cargo build -p libm rustfmt: -- cgit 1.4.1-3-g733a5 From c14fac725a16d121047dcd1d2bd97e8e28b963c6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 20:08:07 +0000 Subject: chore: release v0.2.11 --- library/compiler-builtins/libm/CHANGELOG.md | 13 +++++++++++++ library/compiler-builtins/libm/Cargo.toml | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 317dfafc007..4e5acb899d2 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -8,6 +8,19 @@ and this project adheres to ## [Unreleased] +## [0.2.11](https://github.com/rust-lang/libm/compare/libm-v0.2.10...libm-v0.2.11) - 2024-10-28 + +### Fixed + +- fix type of constants in ported sincosf ([#331](https://github.com/rust-lang/libm/pull/331)) + +### Other + +- Disable a unit test that is failing on i586 +- Add a procedural macro for expanding all function signatures +- Introduce `musl-math-sys` for bindings to musl math symbols +- Add basic docstrings to some functions ([#337](https://github.com/rust-lang/libm/pull/337)) + ## [0.2.10](https://github.com/rust-lang/libm/compare/libm-v0.2.9...libm-v0.2.10) - 2024-10-28 ### Other diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 72b6dcd5e8e..aa6c08ddb01 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT AND (MIT OR Apache-2.0)" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.10" +version = "0.2.11" edition = "2021" exclude = ["/ci/", "/.github/workflows/"] rust-version = "1.63" -- cgit 1.4.1-3-g733a5 From 66f8906862fba51ffde9d9a73b527a29402bce93 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 17:44:02 -0500 Subject: Move the existing "unstable" feature to "unstable-intrinsics" Currently there is a single feature called "unstable" that is used to control whether intrinsics may be called. In anticipation of adding other unstable features that we will want to control separately, create a new feature called "unstable-intrinsics" that is enabled by "unstable". Then move everything gated by "unstable" to "unstable-intrinsics". --- library/compiler-builtins/libm/Cargo.toml | 5 ++++- library/compiler-builtins/libm/ci/run.sh | 6 +++--- .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 2 ++ library/compiler-builtins/libm/src/lib.rs | 4 ++-- library/compiler-builtins/libm/src/math/mod.rs | 8 +++++--- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index aa6c08ddb01..de450468a47 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -18,7 +18,10 @@ default = [] # This tells the compiler to assume that a Nightly toolchain is being used and # that it should activate any useful Nightly things accordingly. -unstable = [] +unstable = ["unstable-intrinsics"] + +# Enable calls to functions in `core::intrinsics` +unstable-intrinsics = [] # Used to prevent using any intrinsics or arch-specific code. force-soft-floats = [] diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index f61fff8433e..f1ca4b0cb10 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -49,7 +49,7 @@ fi if [ "${BUILD_ONLY:-}" = "1" ]; then cmd="cargo build --target $target --package libm" $cmd - $cmd --features 'unstable' + $cmd --features "unstable-intrinsics" echo "can't run tests on $target" else @@ -60,6 +60,6 @@ else $cmd --release # unstable with a feature - $cmd --features 'unstable' - $cmd --release --features 'unstable' + $cmd --features "unstable-intrinsics" + $cmd --release --features "unstable-intrinsics" fi diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 8d084ee341e..2aa7c83718b 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -10,6 +10,8 @@ test = false bench = false [features] +# Duplicated from libm's Cargo.toml unstable = [] +unstable-intrinsics = [] checked = [] force-soft-floats = [] diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 6d95fa1737b..1305d35abf7 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,7 +1,7 @@ //! libm in pure Rust #![no_std] -#![cfg_attr(feature = "unstable", allow(internal_features))] -#![cfg_attr(feature = "unstable", feature(core_intrinsics))] +#![cfg_attr(feature = "unstable-intrinsics", allow(internal_features))] +#![cfg_attr(feature = "unstable-intrinsics", feature(core_intrinsics))] #![allow(clippy::assign_op_pattern)] #![allow(clippy::deprecated_cfg_attr)] #![allow(clippy::eq_op)] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 85c9fc5bf15..17b9e6b4cf6 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -60,14 +60,14 @@ macro_rules! i { // the time of this writing this is only used in a few places, and once // rust-lang/rust#72751 is fixed then this macro will no longer be necessary and // the native `/` operator can be used and panics won't be codegen'd. -#[cfg(any(debug_assertions, not(feature = "unstable")))] +#[cfg(any(debug_assertions, not(feature = "unstable-intrinsics")))] macro_rules! div { ($a:expr, $b:expr) => { $a / $b }; } -#[cfg(all(not(debug_assertions), feature = "unstable"))] +#[cfg(all(not(debug_assertions), feature = "unstable-intrinsics"))] macro_rules! div { ($a:expr, $b:expr) => { unsafe { core::intrinsics::unchecked_div($a, $b) } @@ -76,7 +76,9 @@ macro_rules! div { macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all(feature = "unstable", not(feature = "force-soft-floats"), $($clause)*))] + #[cfg(all( + feature = "unstable-intrinsics", not(feature = "force-soft-floats"), $($clause)* + ))] { if true { // thwart the dead code lint $e -- cgit 1.4.1-3-g733a5 From e6f7053c2e2d7fe2de0cf5582bfd529c2cd3b5a7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 18:15:19 -0500 Subject: Replace `feature = "unstable-intrinsics"` with `intrinsics_enabled` We currently have a non-additive feature, "force-soft-floats", and we will need to gain another "no-f16-f128". This makes `cfg` usage in code somewhat confusing and redundant. Use `build.rs` to figure out if "unstable-intrinsics" is enabled while "force-soft-floats" is not enabled and if so, emit a cfg `intrinsics_enabled`. This is cleaner to use and should make adding more features easier to reason about. Also use this as an opportunity to eliminate the build.rs from the compiler-builtins test crate, replaced with the `[lints]` table in Cargo.toml. --- library/compiler-builtins/libm/Cargo.toml | 5 +++++ library/compiler-builtins/libm/build.rs | 15 ++++++++++++++- library/compiler-builtins/libm/ci/run.sh | 4 ++++ .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 6 ++++++ .../libm/crates/compiler-builtins-smoke-test/build.rs | 3 --- library/compiler-builtins/libm/src/lib.rs | 4 ++-- library/compiler-builtins/libm/src/math/mod.rs | 8 +++----- 7 files changed, 34 insertions(+), 11 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index de450468a47..5e4565556b0 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -24,6 +24,11 @@ unstable = ["unstable-intrinsics"] unstable-intrinsics = [] # Used to prevent using any intrinsics or arch-specific code. +# +# HACK: this is a negative feature which is generally a bad idea in Cargo, but +# we need it to be able to forbid other features when this crate is used in +# Rust dependencies. Setting this overrides all features that may enable +# hard float operations. force-soft-floats = [] [workspace] diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index b683557e4af..adb52140730 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -3,7 +3,6 @@ use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); - println!("cargo:rustc-check-cfg=cfg(feature, values(\"unstable\"))"); println!("cargo:rustc-check-cfg=cfg(feature, values(\"checked\"))"); @@ -14,4 +13,18 @@ fn main() { println!("cargo:rustc-cfg=assert_no_panic"); } } + + configure_intrinsics(); +} + +/// Simplify the feature logic for enabling intrinsics so code only needs to use +/// `cfg(intrinsics_enabled)`. +fn configure_intrinsics() { + println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)"); + + // Disabled by default; `unstable-intrinsics` enables again; `force-soft-floats` overrides + // to disable. + if cfg!(feature = "unstable-intrinsics") && !cfg!(feature = "force-soft-floats") { + println!("cargo:rustc-cfg=intrinsics_enabled"); + } } diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index f1ca4b0cb10..d3fc4ce240d 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -46,6 +46,10 @@ if [ "$(uname -a)" = "Linux" ]; then extra_flags="$extra_flags --features libm-test/test-musl-serialized" fi +# Make sure we can build with overriding features. We test the indibidual +# features it controls separately. +cargo check --features "force-soft-floats" + if [ "${BUILD_ONLY:-}" = "1" ]; then cmd="cargo build --target $target --package libm" $cmd diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 2aa7c83718b..2a6c62961e3 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -15,3 +15,9 @@ unstable = [] unstable-intrinsics = [] checked = [] force-soft-floats = [] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = [ + "cfg(assert_no_panic)", + "cfg(intrinsics_enabled)", +] } diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs deleted file mode 100644 index 27d4a0e89d0..00000000000 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); -} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 1305d35abf7..98ac55988d0 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,7 +1,7 @@ //! libm in pure Rust #![no_std] -#![cfg_attr(feature = "unstable-intrinsics", allow(internal_features))] -#![cfg_attr(feature = "unstable-intrinsics", feature(core_intrinsics))] +#![cfg_attr(intrinsics_enabled, allow(internal_features))] +#![cfg_attr(intrinsics_enabled, feature(core_intrinsics))] #![allow(clippy::assign_op_pattern)] #![allow(clippy::deprecated_cfg_attr)] #![allow(clippy::eq_op)] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 17b9e6b4cf6..9baa57fc882 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -60,14 +60,14 @@ macro_rules! i { // the time of this writing this is only used in a few places, and once // rust-lang/rust#72751 is fixed then this macro will no longer be necessary and // the native `/` operator can be used and panics won't be codegen'd. -#[cfg(any(debug_assertions, not(feature = "unstable-intrinsics")))] +#[cfg(any(debug_assertions, not(intrinsics_enabled)))] macro_rules! div { ($a:expr, $b:expr) => { $a / $b }; } -#[cfg(all(not(debug_assertions), feature = "unstable-intrinsics"))] +#[cfg(all(not(debug_assertions), intrinsics_enabled))] macro_rules! div { ($a:expr, $b:expr) => { unsafe { core::intrinsics::unchecked_div($a, $b) } @@ -76,9 +76,7 @@ macro_rules! div { macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all( - feature = "unstable-intrinsics", not(feature = "force-soft-floats"), $($clause)* - ))] + #[cfg(all(intrinsics_enabled, not(feature = "force-soft-floats"), $($clause)*))] { if true { // thwart the dead code lint $e -- cgit 1.4.1-3-g733a5 From 1b7346bf5fb63c4c74ad492e7a566b01feec6f56 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 19:30:04 -0500 Subject: Introduce `math::arch::intrinsics` This module provides implementations of basic functions that defer to LLVM for what to do, rather than either using a builtin operation or calling another function in this library. `math::arch` will become the home of anything architecture-specific in the future. --- .../libm/src/math/arch/intrinsics.rs | 52 ++++++++++++++++++++++ .../compiler-builtins/libm/src/math/arch/mod.rs | 9 ++++ library/compiler-builtins/libm/src/math/mod.rs | 1 + 3 files changed, 62 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/arch/intrinsics.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/mod.rs diff --git a/library/compiler-builtins/libm/src/math/arch/intrinsics.rs b/library/compiler-builtins/libm/src/math/arch/intrinsics.rs new file mode 100644 index 00000000000..1cf9291f4c7 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/intrinsics.rs @@ -0,0 +1,52 @@ +// Config is needed for times when this module is available but we don't call everything +#![allow(dead_code)] + +pub fn ceil(x: f64) -> f64 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::ceilf64(x) } +} + +pub fn ceilf(x: f32) -> f32 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::ceilf32(x) } +} + +pub fn fabs(x: f64) -> f64 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::fabsf64(x) } +} + +pub fn fabsf(x: f32) -> f32 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::fabsf32(x) } +} + +pub fn floor(x: f64) -> f64 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::floorf64(x) } +} + +pub fn floorf(x: f32) -> f32 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::floorf32(x) } +} + +pub fn sqrt(x: f64) -> f64 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::sqrtf64(x) } +} + +pub fn sqrtf(x: f32) -> f32 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::sqrtf32(x) } +} + +pub fn trunc(x: f64) -> f64 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::truncf64(x) } +} + +pub fn truncf(x: f32) -> f32 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::truncf32(x) } +} diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs new file mode 100644 index 00000000000..a4bc218b743 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -0,0 +1,9 @@ +//! Architecture-specific routines and operations. +//! +//! LLVM will already optimize calls to some of these in cases that there are hardware +//! instructions. Providing an implementation here just ensures that the faster implementation +//! is used when calling the function directly. This helps anyone who uses `libm` directly, as +//! well as improving things when these routines are called as part of other implementations. + +#[cfg(intrinsics_enabled)] +pub mod intrinsics; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 9baa57fc882..e3e6846d377 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -302,6 +302,7 @@ pub use self::trunc::trunc; pub use self::truncf::truncf; // Private modules +mod arch; mod expo2; mod fenv; mod k_cos; -- cgit 1.4.1-3-g733a5 From d54896343cab56e2f4c9866e54e7954c9c70d753 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 02:56:22 -0500 Subject: Introduce a `select_implementation` macro Currently there is a macro called `llvm_intrinsically_optimized` that uses an intrinsic rather than the function implementation if the configuration is correct. Add a new macro `select_implementation` that is somewhat cleaner to use. In the future, we can update this macro with more fields to specify other implementations that may be selected, such as something architecture-specific or e.g. using a generic implementation for `f32` routines, rather than those that convert to `f64`. This introduces a `macros` module within `math/support`. We will be able to move more things here later. --- library/compiler-builtins/libm/src/math/mod.rs | 63 +++++++++++----------- .../libm/src/math/support/macros.rs | 34 ++++++++++++ .../compiler-builtins/libm/src/math/support/mod.rs | 2 + 3 files changed, 69 insertions(+), 30 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/support/macros.rs create mode 100644 library/compiler-builtins/libm/src/math/support/mod.rs diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e3e6846d377..a7e16bfc865 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -74,6 +74,7 @@ macro_rules! div { }; } +// FIXME: phase this out, to be replaced by the more flexible `select_implementation` macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { #[cfg(all(intrinsics_enabled, not(feature = "force-soft-floats"), $($clause)*))] @@ -85,6 +86,38 @@ macro_rules! llvm_intrinsically_optimized { }; } +// Private modules +#[macro_use] +mod support; +mod arch; +mod expo2; +mod fenv; +mod k_cos; +mod k_cosf; +mod k_expo2; +mod k_expo2f; +mod k_sin; +mod k_sinf; +mod k_tan; +mod k_tanf; +mod rem_pio2; +mod rem_pio2_large; +mod rem_pio2f; + +// Private re-imports +use self::expo2::expo2; +use self::k_cos::k_cos; +use self::k_cosf::k_cosf; +use self::k_expo2::k_expo2; +use self::k_expo2f::k_expo2f; +use self::k_sin::k_sin; +use self::k_sinf::k_sinf; +use self::k_tan::k_tan; +use self::k_tanf::k_tanf; +use self::rem_pio2::rem_pio2; +use self::rem_pio2_large::rem_pio2_large; +use self::rem_pio2f::rem_pio2f; + // Public modules mod acos; mod acosf; @@ -301,36 +334,6 @@ pub use self::tgammaf::tgammaf; pub use self::trunc::trunc; pub use self::truncf::truncf; -// Private modules -mod arch; -mod expo2; -mod fenv; -mod k_cos; -mod k_cosf; -mod k_expo2; -mod k_expo2f; -mod k_sin; -mod k_sinf; -mod k_tan; -mod k_tanf; -mod rem_pio2; -mod rem_pio2_large; -mod rem_pio2f; - -// Private re-imports -use self::expo2::expo2; -use self::k_cos::k_cos; -use self::k_cosf::k_cosf; -use self::k_expo2::k_expo2; -use self::k_expo2f::k_expo2f; -use self::k_sin::k_sin; -use self::k_sinf::k_sinf; -use self::k_tan::k_tan; -use self::k_tanf::k_tanf; -use self::rem_pio2::rem_pio2; -use self::rem_pio2_large::rem_pio2_large; -use self::rem_pio2f::rem_pio2f; - #[inline] fn get_high_word(x: f64) -> u32 { (x.to_bits() >> 32) as u32 diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs new file mode 100644 index 00000000000..6bc75837a34 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -0,0 +1,34 @@ +/// Choose among using an intrinsic (if available) and falling back to the default function body. +/// Returns directly if the intrinsic version is used, otherwise continues to the rest of the +/// function. +/// +/// Use this if the intrinsic is likely to be more performant on the platform(s) specified +/// in `intrinsic_available`. +/// +/// The `cfg` used here is controlled by `build.rs` so the passed meta does not need to account +/// for e.g. the `unstable-intrinsics` or `force-soft-float` features. +macro_rules! select_implementation { + ( + name: $fname:ident, + // Configuration meta for when to call intrinsics and let LLVM figure it out + $( use_intrinsic: $use_intrinsic:meta, )? + args: $($arg:ident),+ , + ) => { + // FIXME: these use paths that are a pretty fragile (`super`). We should figure out + // something better w.r.t. how this is vendored into compiler-builtins. + + // Never use intrinsics if we are forcing soft floats, and only enable with the + // `unstable-intrinsics` feature. + #[cfg(intrinsics_enabled)] + select_implementation! { + @cfg $( $use_intrinsic )?; + if true { + return super::arch::intrinsics::$fname( $($arg),+ ); + } + } + }; + + // Coalesce helper to construct an expression only if a config is provided + (@cfg ; $ex:expr) => { }; + (@cfg $provided:meta; $ex:expr) => { #[cfg($provided)] $ex }; +} diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs new file mode 100644 index 00000000000..10532f0d115 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -0,0 +1,2 @@ +#[macro_use] +pub mod macros; -- cgit 1.4.1-3-g733a5 From 60e7e3b338c3aea7b615073d712c9c568e2a0e9a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 19:38:19 -0500 Subject: Make use of `select_implementation` Replace all uses of `llvm_intrinsically` with select_implementation`. --- library/compiler-builtins/libm/src/math/ceil.rs | 12 +++++------- library/compiler-builtins/libm/src/math/ceilf.rs | 12 +++++------- library/compiler-builtins/libm/src/math/fabs.rs | 12 +++++------- library/compiler-builtins/libm/src/math/fabsf.rs | 12 +++++------- library/compiler-builtins/libm/src/math/floor.rs | 12 +++++------- library/compiler-builtins/libm/src/math/floorf.rs | 12 +++++------- library/compiler-builtins/libm/src/math/mod.rs | 12 ------------ library/compiler-builtins/libm/src/math/sqrt.rs | 16 +++++----------- library/compiler-builtins/libm/src/math/sqrtf.rs | 16 +++++----------- library/compiler-builtins/libm/src/math/trunc.rs | 12 +++++------- library/compiler-builtins/libm/src/math/truncf.rs | 12 +++++------- 11 files changed, 50 insertions(+), 90 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 1593fdaffce..0da01b4d0b6 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -8,14 +8,12 @@ const TOINT: f64 = 1. / f64::EPSILON; /// Finds the nearest integer greater than or equal to `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceil(x: f64) -> f64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.ceil` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::ceilf64(x) } - } + select_implementation! { + name: ceil, + use_intrinsic: target_arch = "wasm32", + args: x, } + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] { //use an alternative implementation on x86, because the diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index bf9ba12279c..0da384350ae 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -5,14 +5,12 @@ use core::f32; /// Finds the nearest integer greater than or equal to `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceilf(x: f32) -> f32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.ceil` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::ceilf32(x) } - } + select_implementation! { + name: ceilf, + use_intrinsic: target_arch = "wasm32", + args: x, } + let mut ui = x.to_bits(); let e = (((ui >> 23) & 0xff).wrapping_sub(0x7f)) as i32; diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 3b0628aa63a..8d3ea2fd647 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -5,14 +5,12 @@ use core::u64; /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabs(x: f64) -> f64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.abs` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::fabsf64(x) } - } + select_implementation! { + name: fabs, + use_intrinsic: target_arch = "wasm32", + args: x, } + f64::from_bits(x.to_bits() & (u64::MAX / 2)) } diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index f81c8ca4423..1dac6389d8f 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -3,14 +3,12 @@ /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabsf(x: f32) -> f32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.abs` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::fabsf32(x) } - } + select_implementation! { + name: fabsf, + use_intrinsic: target_arch = "wasm32", + args: x, } + f32::from_bits(x.to_bits() & 0x7fffffff) } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index e8fb21e5884..2b9955ebae3 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -8,14 +8,12 @@ const TOINT: f64 = 1. / f64::EPSILON; /// Finds the nearest integer less than or equal to `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floor(x: f64) -> f64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.floor` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::floorf64(x) } - } + select_implementation! { + name: floor, + use_intrinsic: target_arch = "wasm32", + args: x, } + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] { //use an alternative implementation on x86, because the diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index f66cab74fdc..4f38cb15b7d 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -5,14 +5,12 @@ use core::f32; /// Finds the nearest integer less than or equal to `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floorf(x: f32) -> f32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.floor` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::floorf32(x) } - } + select_implementation! { + name: floorf, + use_intrinsic: target_arch = "wasm32", + args: x, } + let mut ui = x.to_bits(); let e = (((ui >> 23) as i32) & 0xff) - 0x7f; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index a7e16bfc865..393bc515093 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -74,18 +74,6 @@ macro_rules! div { }; } -// FIXME: phase this out, to be replaced by the more flexible `select_implementation` -macro_rules! llvm_intrinsically_optimized { - (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all(intrinsics_enabled, not(feature = "force-soft-floats"), $($clause)*))] - { - if true { // thwart the dead code lint - $e - } - } - }; -} - // Private modules #[macro_use] mod support; diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index e2907384dcd..2e856100f7d 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -81,18 +81,12 @@ use core::f64; /// The square root of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.sqrt` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return if x < 0.0 { - f64::NAN - } else { - unsafe { ::core::intrinsics::sqrtf64(x) } - } - } + select_implementation! { + name: sqrt, + use_intrinsic: target_arch = "wasm32", + args: x, } + #[cfg(all(target_feature = "sse2", not(feature = "force-soft-floats")))] { // Note: This path is unlikely since LLVM will usually have already diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index a738fc0b663..b2996b350cb 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -16,18 +16,12 @@ /// The square root of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf(x: f32) -> f32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.sqrt` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return if x < 0.0 { - ::core::f32::NAN - } else { - unsafe { ::core::intrinsics::sqrtf32(x) } - } - } + select_implementation! { + name: sqrtf, + use_intrinsic: target_arch = "wasm32", + args: x, } + #[cfg(all(target_feature = "sse", not(feature = "force-soft-floats")))] { // Note: This path is unlikely since LLVM will usually have already diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index f7892a2c553..6961bb95060 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -2,14 +2,12 @@ use core::f64; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn trunc(x: f64) -> f64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.trunc` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::truncf64(x) } - } + select_implementation! { + name: trunc, + use_intrinsic: target_arch = "wasm32", + args: x, } + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 let mut i: u64 = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index 20d5b73bd67..8270c8eb392 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -2,14 +2,12 @@ use core::f32; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn truncf(x: f32) -> f32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.trunc` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::truncf32(x) } - } + select_implementation! { + name: truncf, + use_intrinsic: target_arch = "wasm32", + args: x, } + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 let mut i: u32 = x.to_bits(); -- cgit 1.4.1-3-g733a5 From 3502d8eff6a26c67d5564e3012434d2f54248ff9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 20:45:12 -0500 Subject: Combine the WASM CI job with the others There isn't any reason to be distinct here, and it would be better to test with all feature configurations in run.sh anyway. --- .../libm/.github/workflows/main.yml | 23 +++++++--------------- library/compiler-builtins/libm/ci/run.sh | 2 +- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 15eba6e8905..cc0d23ffc2f 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -9,7 +9,7 @@ env: jobs: test: - name: Docker + name: Build and test timeout-minutes: 20 strategy: fail-fast: false @@ -52,6 +52,9 @@ jobs: os: ubuntu-latest - target: x86_64-apple-darwin os: macos-13 + - target: wasm32-unknown-unknown + os: ubuntu-latest + build_only: 1 - target: i686-pc-windows-msvc os: windows-latest - target: x86_64-pc-windows-msvc @@ -89,30 +92,19 @@ jobs: # Non-linux tests just use our raw script - name: Run locally - if: matrix.os != 'ubuntu-latest' + if: matrix.os != 'ubuntu-latest' || contains(matrix.target, 'wasm') shell: bash run: ./ci/run.sh ${{ matrix.target }} # Otherwise we use our docker containers to run builds - name: Run in Docker - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-latest' && !contains(matrix.target, 'wasm') run: | rustup target add x86_64-unknown-linux-musl cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} - wasm: - name: WebAssembly - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Install Rust - run: rustup update nightly --no-self-update && rustup default nightly - - run: rustup target add wasm32-unknown-unknown - - uses: Swatinem/rust-cache@v2 - - run: cargo build --target wasm32-unknown-unknown - builtins: - name: "The compiler-builtins crate works" + name: Check use with compiler-builtins runs-on: ubuntu-latest steps: - uses: actions/checkout@master @@ -164,7 +156,6 @@ jobs: success: needs: - test - - wasm - builtins - benchmarks - msrv diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index d3fc4ce240d..30265e513a2 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -55,7 +55,7 @@ if [ "${BUILD_ONLY:-}" = "1" ]; then $cmd $cmd --features "unstable-intrinsics" - echo "can't run tests on $target" + echo "can't run tests on $target; skipping" else cmd="cargo test --all --target $target $extra_flags" -- cgit 1.4.1-3-g733a5 From c09e58be46e9fd2b2961c155d40cb04b04866a26 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Oct 2024 17:38:57 -0500 Subject: Create interfaces for testing against MPFR Add a way to call MPFR versions of functions in a predictable way, using the `MpOp` trait. Everything new here is guarded by the feature `test-multiprecision` since MPFR cannot easily build on Windows or any cross compiled targets. --- .../libm/crates/libm-test/Cargo.toml | 3 + .../libm/crates/libm-test/src/lib.rs | 2 + .../libm/crates/libm-test/src/mpfloat.rs | 389 +++++++++++++++++++++ 3 files changed, 394 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 703524bcd70..72ac57232b3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -10,18 +10,21 @@ default = [] # Generate tests which are random inputs and the outputs are calculated with # musl libc. test-musl-serialized = ["rand"] +test-multiprecision = ["dep:az", "dep:rug"] # Build our own musl for testing and benchmarks build-musl = ["dep:musl-math-sys"] [dependencies] anyhow = "1.0.90" +az = { version = "1.2.1", optional = true } libm = { path = "../.." } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } paste = "1.0.15" rand = "0.8.5" rand_chacha = "0.3.1" +rug = { version = "1.26.1", optional = true, default-features = false, features = ["float", "std"] } [target.'cfg(target_family = "wasm")'.dependencies] # Enable randomness on WASM diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 2abe7f605ea..64343e00d5d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,4 +1,6 @@ pub mod gen; +#[cfg(feature = "test-multiprecision")] +pub mod mpfloat; mod num_traits; mod special_case; mod test_traits; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs new file mode 100644 index 00000000000..db072780aeb --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -0,0 +1,389 @@ +//! Interfaces needed to support testing with multi-precision floating point numbers. +//! +//! Within this module, the macros create a submodule for each `libm` function. These contain +//! a struct named `Operation` that implements [`MpOp`]. + +use std::cmp::Ordering; + +use az::Az; +use rug::Assign; +pub use rug::Float as MpFloat; +use rug::float::Round::Nearest; +use rug::ops::{PowAssignRound, RemAssignRound}; + +use crate::Float; + +/// Create a multiple-precision float with the correct number of bits for a concrete float type. +fn new_mpfloat() -> MpFloat { + MpFloat::new(F::SIGNIFICAND_BITS + 1) +} + +/// Set subnormal emulation and convert to a concrete float type. +fn prep_retval(mp: &mut MpFloat, ord: Ordering) -> F +where + for<'a> &'a MpFloat: az::Cast, +{ + mp.subnormalize_ieee_round(ord, Nearest); + (&*mp).az::() +} + +/// Structures that represent a float operation. +/// +/// The struct itself should hold any context that can be reused among calls to `run` (allocated +/// `MpFloat`s). +pub trait MpOp { + /// Inputs to the operation (concrete float types). + type Input; + + /// Outputs from the operation (concrete float types). + type Output; + + /// Create a new instance. + fn new() -> Self; + + /// Perform the operation. + /// + /// Usually this means assigning inputs to cached floats, performing the operation, applying + /// subnormal approximation, and converting the result back to concrete values. + fn run(&mut self, input: Self::Input) -> Self::Output; +} + +/// Implement `MpOp` for functions with a single return value. +macro_rules! impl_mp_op { + // Matcher for unary functions + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: fn($fty:ty,) -> $_ret:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + fn_extra: $fn_name_normalized:expr, + ) => { + paste::paste! { + pub mod $fn_name { + use super::*; + pub struct Operation(MpFloat); + + impl MpOp for Operation { + type Input = $RustArgs; + type Output = $RustRet; + + fn new() -> Self { + Self(new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + let ord = self.0.[< $fn_name_normalized _round >](Nearest); + prep_retval::(&mut self.0, ord) + } + } + } + } + }; + // Matcher for binary functions + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: fn($fty:ty, $_fty2:ty,) -> $_ret:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + fn_extra: $fn_name_normalized:expr, + ) => { + paste::paste! { + pub mod $fn_name { + use super::*; + pub struct Operation(MpFloat, MpFloat); + + impl MpOp for Operation { + type Input = $RustArgs; + type Output = $RustRet; + + fn new() -> Self { + Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.1.assign(input.1); + let ord = self.0.[< $fn_name_normalized _round >](&self.1, Nearest); + prep_retval::(&mut self.0, ord) + } + } + } + } + }; + // Matcher for ternary functions + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: fn($fty:ty, $_fty2:ty, $_fty3:ty,) -> $_ret:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + fn_extra: $fn_name_normalized:expr, + ) => { + paste::paste! { + pub mod $fn_name { + use super::*; + pub struct Operation(MpFloat, MpFloat, MpFloat); + + impl MpOp for Operation { + type Input = $RustArgs; + type Output = $RustRet; + + fn new() -> Self { + Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.1.assign(input.1); + self.2.assign(input.2); + let ord = self.0.[< $fn_name_normalized _round >](&self.1, &self.2, Nearest); + prep_retval::(&mut self.0, ord) + } + } + } + } + }; +} + +libm_macros::for_each_function! { + callback: impl_mp_op, + skip: [ + // Most of these need a manual implementation + fabs, ceil, copysign, floor, rint, round, trunc, + fabsf, ceilf, copysignf, floorf, rintf, roundf, truncf, + fmod, fmodf, frexp, frexpf, ilogb, ilogbf, jn, jnf, ldexp, ldexpf, + lgamma_r, lgammaf_r, modf, modff, nextafter, nextafterf, pow,powf, + remquo, remquof, scalbn, scalbnf, sincos, sincosf, + ], + fn_extra: match MACRO_FN_NAME { + // Remap function names that are different between mpfr and libm + expm1 | expm1f => exp_m1, + fabs | fabsf => abs, + fdim | fdimf => positive_diff, + fma | fmaf => mul_add, + fmax | fmaxf => max, + fmin | fminf => min, + lgamma | lgammaf => ln_gamma, + log | logf => ln, + log1p | log1pf => ln_1p, + tgamma | tgammaf => gamma, + _ => MACRO_FN_NAME_NORMALIZED + } +} + +/// Implement unary functions that don't have a `_round` version +macro_rules! impl_no_round { + // Unary matcher + ($($fn_name:ident, $rug_name:ident;)*) => { + paste::paste! { + // Implement for both f32 and f64 + $( impl_no_round!{ @inner_unary [< $fn_name f >], (f32,), $rug_name } )* + $( impl_no_round!{ @inner_unary $fn_name, (f64,), $rug_name } )* + } + }; + + (@inner_unary $fn_name:ident, ($fty:ty,), $rug_name:ident) => { + pub mod $fn_name { + use super::*; + pub struct Operation(MpFloat); + + impl MpOp for Operation { + type Input = ($fty,); + type Output = $fty; + + fn new() -> Self { + Self(new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.0.$rug_name(); + prep_retval::(&mut self.0, Ordering::Equal) + } + } + } + }; +} + +impl_no_round! { + fabs, abs_mut; + ceil, ceil_mut; + floor, floor_mut; + rint, round_even_mut; // FIXME: respect rounding mode + round, round_mut; + trunc, trunc_mut; +} + +/// Some functions are difficult to do in a generic way. Implement them here. +macro_rules! impl_op_for_ty { + ($fty:ty, $suffix:literal) => { + paste::paste! { + pub mod [] { + use super::*; + pub struct Operation(MpFloat, MpFloat); + + impl MpOp for Operation { + type Input = ($fty, $fty); + type Output = $fty; + + fn new() -> Self { + Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.1.assign(input.1); + self.0.copysign_mut(&self.1); + prep_retval::(&mut self.0, Ordering::Equal) + } + } + } + + pub mod [] { + use super::*; + pub struct Operation(MpFloat, MpFloat); + + impl MpOp for Operation { + type Input = ($fty, $fty); + type Output = $fty; + + fn new() -> Self { + Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.1.assign(input.1); + self.0.next_toward(&self.1); + prep_retval::(&mut self.0, Ordering::Equal) + } + } + } + + pub mod [] { + use super::*; + pub struct Operation(MpFloat, MpFloat); + + impl MpOp for Operation { + type Input = ($fty, $fty); + type Output = $fty; + + fn new() -> Self { + Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.1.assign(input.1); + let ord = self.0.pow_assign_round(&self.1, Nearest); + prep_retval::(&mut self.0, ord) + } + } + } + + pub mod [] { + use super::*; + pub struct Operation(MpFloat, MpFloat); + + impl MpOp for Operation { + type Input = ($fty, $fty); + type Output = $fty; + + fn new() -> Self { + Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.1.assign(input.1); + let ord = self.0.rem_assign_round(&self.1, Nearest); + prep_retval::(&mut self.0, ord) + } + } + } + + pub mod [] { + use super::*; + pub struct Operation(MpFloat); + + impl MpOp for Operation { + type Input = ($fty,); + type Output = ($fty, i32); + + fn new() -> Self { + Self(new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + let (sign, ord) = self.0.ln_abs_gamma_round(Nearest); + let ret = prep_retval::<$fty>(&mut self.0, ord); + (ret, sign as i32) + } + } + } + + pub mod [] { + use super::*; + pub struct Operation(i32, MpFloat); + + impl MpOp for Operation { + type Input = (i32, $fty); + type Output = $fty; + + fn new() -> Self { + Self(0, new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0 = input.0; + self.1.assign(input.1); + let ord = self.1.jn_round(self.0, Nearest); + prep_retval::<$fty>(&mut self.1, ord) + } + } + } + + pub mod [] { + use super::*; + pub struct Operation(MpFloat, MpFloat); + + impl MpOp for Operation { + type Input = ($fty,); + type Output = ($fty, $fty); + + fn new() -> Self { + Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.1.assign(0.0); + let (sord, cord) = self.0.sin_cos_round(&mut self.1, Nearest); + ( + prep_retval::<$fty>(&mut self.0, sord), + prep_retval::<$fty>(&mut self.1, cord) + ) + } + } + } + } + }; +} + +impl_op_for_ty!(f32, "f"); +impl_op_for_ty!(f64, ""); + +// Account for `lgamma_r` not having a simple `f` suffix +pub mod lgammaf_r { + pub use super::lgamma_rf::*; +} -- cgit 1.4.1-3-g733a5 From 64131ec5cdb74213f3f9b0fa435f97ebd9fedba7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Oct 2024 17:41:24 -0500 Subject: Add a test against MPFR using random inputs --- .../libm/crates/libm-test/src/gen/random.rs | 16 +-- .../libm/crates/libm-test/src/lib.rs | 29 +++- .../libm/crates/libm-test/src/mpfloat.rs | 21 --- .../libm/crates/libm-test/src/special_case.rs | 157 ++++++++++++++++----- .../libm/crates/libm-test/src/test_traits.rs | 2 + .../crates/libm-test/tests/compare_built_musl.rs | 2 +- .../libm/crates/libm-test/tests/multiprecision.rs | 71 ++++++++++ 7 files changed, 228 insertions(+), 70 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 601ef4f1d46..c73937aacc9 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -7,7 +7,7 @@ use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; use super::CachedInput; -use crate::GenerateInput; +use crate::{CheckCtx, GenerateInput}; const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; @@ -40,9 +40,10 @@ static TEST_CASES_JN: LazyLock = LazyLock::new(|| { let mut cases = (&*TEST_CASES).clone(); // These functions are extremely slow, limit them - cases.inputs_i32.truncate((NTESTS / 1000).max(80)); - cases.inputs_f32.truncate((NTESTS / 1000).max(80)); - cases.inputs_f64.truncate((NTESTS / 1000).max(80)); + let ntests_jn = (NTESTS / 1000).max(80); + cases.inputs_i32.truncate(ntests_jn); + cases.inputs_f32.truncate(ntests_jn); + cases.inputs_f64.truncate(ntests_jn); // It is easy to overflow the stack with these in debug mode let max_iterations = if cfg!(optimizations_enabled) && cfg!(target_pointer_width = "64") { @@ -105,11 +106,10 @@ fn make_test_cases(ntests: usize) -> CachedInput { } /// Create a test case iterator. -pub fn get_test_cases(fname: &str) -> impl Iterator +pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator where CachedInput: GenerateInput, { - let inputs = if fname == "jn" || fname == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; - - CachedInput::get_cases(inputs) + let inputs = if ctx.fname == "jn" || ctx.fname == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; + inputs.get_cases() } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 64343e00d5d..13b76d6c5a8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -16,14 +16,18 @@ pub type TestResult = Result; // List of all files present in libm's source include!(concat!(env!("OUT_DIR"), "/all_files.rs")); -/// ULP allowed to differ from musl (note that musl itself may not be accurate). +/// Default ULP allowed to differ from musl (note that musl itself may not be accurate). const MUSL_DEFAULT_ULP: u32 = 2; -/// Certain functions have different allowed ULP (consider these xfail). +/// Default ULP allowed to differ from multiprecision (i.e. infinite) results. +const MULTIPREC_DEFAULT_ULP: u32 = 1; + +/// ULP allowed to differ from muls results. /// /// Note that these results were obtained using 400,000,000 rounds of random inputs, which /// is not a value used by default. pub fn musl_allowed_ulp(name: &str) -> u32 { + // Consider overrides xfail match name { #[cfg(x86_no_sse)] "asinh" | "asinhf" => 6, @@ -44,6 +48,27 @@ pub fn musl_allowed_ulp(name: &str) -> u32 { } } +/// ULP allowed to differ from multiprecision results. +pub fn multiprec_allowed_ulp(name: &str) -> u32 { + // Consider overrides xfail + match name { + "asinh" | "asinhf" => 2, + "acoshf" => 4, + "atanh" | "atanhf" => 2, + "exp10" | "exp10f" => 3, + "j0" | "j0f" | "j1" | "j1f" => { + // Results seem very target-dependent + if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } + } + "jn" | "jnf" => 1000, + "lgamma" | "lgammaf" | "lgamma_r" | "lgammaf_r" => 16, + "sinh" | "sinhf" => 2, + "tanh" | "tanhf" => 2, + "tgamma" => 20, + _ => MULTIPREC_DEFAULT_ULP, + } +} + /// Return the unsuffixed version of a function name; e.g. `abs` and `absf` both return `abs`, /// `lgamma_r` and `lgammaf_r` both return `lgamma_r`. pub fn canonical_name(name: &str) -> &str { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index db072780aeb..44962d11679 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -248,27 +248,6 @@ macro_rules! impl_op_for_ty { } } - pub mod [] { - use super::*; - pub struct Operation(MpFloat, MpFloat); - - impl MpOp for Operation { - type Input = ($fty, $fty); - type Output = $fty; - - fn new() -> Self { - Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) - } - - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.1.assign(input.1); - self.0.next_toward(&self.1); - prep_retval::(&mut self.0, Ordering::Equal) - } - } - } - pub mod [] { use super::*; pub struct Operation(MpFloat, MpFloat); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs b/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs index df263d7428c..dac7a349dc4 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs @@ -58,20 +58,6 @@ impl MaybeOverride<(f32,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if ctx.fname == "acoshf" && input.0 < -1.0 { - // acoshf is undefined for x <= 1.0, but we return a random result at lower - // values. - return XFAIL; - } - - if ctx.fname == "sincosf" { - let factor_frac_pi_2 = input.0.abs() / f32::consts::FRAC_PI_2; - if (factor_frac_pi_2 - factor_frac_pi_2.round()).abs() < 1e-2 { - // we have a bad approximation near multiples of pi/2 - return XFAIL; - } - } - if ctx.fname == "expm1f" && input.0 > 80.0 && actual.is_infinite() { // we return infinity but the number is representable return XFAIL; @@ -82,15 +68,40 @@ impl MaybeOverride<(f32,)> for SpecialCase { // doesn't seem to happen on x86 return XFAIL; } + } - if ctx.fname == "lgammaf" || ctx.fname == "lgammaf_r" && input.0 < 0.0 { - // loggamma should not be defined for x < 0, yet we both return results - return XFAIL; - } + if ctx.fname == "acoshf" && input.0 < -1.0 { + // acoshf is undefined for x <= 1.0, but we return a random result at lower + // values. + return XFAIL; + } + + if ctx.fname == "lgammaf" || ctx.fname == "lgammaf_r" && input.0 < 0.0 { + // loggamma should not be defined for x < 0, yet we both return results + return XFAIL; } maybe_check_nan_bits(actual, expected, ctx) } + + fn check_int( + input: (f32,), + actual: I, + expected: I, + ctx: &CheckCtx, + ) -> Option> { + // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR + // sets +1 + if ctx.basis == CheckBasis::Mpfr + && ctx.fname == "lgammaf_r" + && input.0 == f32::NEG_INFINITY + && actual.abs() == expected.abs() + { + XFAIL + } else { + None + } + } } impl MaybeOverride<(f64,)> for SpecialCase { @@ -117,15 +128,40 @@ impl MaybeOverride<(f64,)> for SpecialCase { // musl returns -0.0, we return +0.0 return XFAIL; } + } - if ctx.fname == "lgamma" || ctx.fname == "lgamma_r" && input.0 < 0.0 { - // loggamma should not be defined for x < 0, yet we both return results - return XFAIL; - } + if ctx.fname == "acosh" && input.0 < 1.0 { + // The function is undefined for the inputs, musl and our libm both return + // random results. + return XFAIL; + } + + if ctx.fname == "lgamma" || ctx.fname == "lgamma_r" && input.0 < 0.0 { + // loggamma should not be defined for x < 0, yet we both return results + return XFAIL; } maybe_check_nan_bits(actual, expected, ctx) } + + fn check_int( + input: (f64,), + actual: I, + expected: I, + ctx: &CheckCtx, + ) -> Option> { + // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR + // sets +1 + if ctx.basis == CheckBasis::Mpfr + && ctx.fname == "lgamma_r" + && input.0 == f64::NEG_INFINITY + && actual.abs() == expected.abs() + { + XFAIL + } else { + None + } + } } /// Check NaN bits if the function requires it @@ -142,6 +178,11 @@ fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Opt return SKIP; } + // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. + if ctx.basis == CheckBasis::Mpfr { + return SKIP; + } + // abs and copysign require signaling NaNs to be propagated, so verify bit equality. if actual.to_bits() == expected.to_bits() { return SKIP; @@ -158,9 +199,10 @@ impl MaybeOverride<(f32, f32)> for SpecialCase { _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - maybe_skip_min_max_nan(input, expected, ctx) + maybe_skip_binop_nan(input, expected, ctx) } } + impl MaybeOverride<(f64, f64)> for SpecialCase { fn check_float( input: (f64, f64), @@ -169,47 +211,86 @@ impl MaybeOverride<(f64, f64)> for SpecialCase { _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - maybe_skip_min_max_nan(input, expected, ctx) + maybe_skip_binop_nan(input, expected, ctx) } } /// Musl propagates NaNs if one is provided as the input, but we return the other input. // F1 and F2 are always the same type, this is just to please generics -fn maybe_skip_min_max_nan( +fn maybe_skip_binop_nan( input: (F1, F1), expected: F2, ctx: &CheckCtx, ) -> Option { - if (ctx.canonical_name == "fmax" || ctx.canonical_name == "fmin") - && (input.0.is_nan() || input.1.is_nan()) - && expected.is_nan() - { - return XFAIL; - } else { - None + match ctx.basis { + CheckBasis::Musl => { + if (ctx.canonical_name == "fmax" || ctx.canonical_name == "fmin") + && (input.0.is_nan() || input.1.is_nan()) + && expected.is_nan() + { + XFAIL + } else { + None + } + } + CheckBasis::Mpfr => { + if ctx.canonical_name == "copysign" && input.1.is_nan() { + SKIP + } else { + None + } + } } } impl MaybeOverride<(i32, f32)> for SpecialCase { fn check_float( input: (i32, f32), - _actual: F, - _expected: F, + actual: F, + expected: F, ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - bessel_prec_dropoff(input, ulp, ctx) + match ctx.basis { + CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), + CheckBasis::Mpfr => { + // We return +0.0, MPFR returns -0.0 + if ctx.fname == "jnf" + && input.1 == f32::NEG_INFINITY + && actual == F::ZERO + && expected == F::ZERO + { + XFAIL + } else { + None + } + } + } } } impl MaybeOverride<(i32, f64)> for SpecialCase { fn check_float( input: (i32, f64), - _actual: F, - _expected: F, + actual: F, + expected: F, ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - bessel_prec_dropoff(input, ulp, ctx) + match ctx.basis { + CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), + CheckBasis::Mpfr => { + // We return +0.0, MPFR returns -0.0 + if ctx.fname == "jn" + && input.1 == f64::NEG_INFINITY + && actual == F::ZERO + && expected == F::ZERO + { + XFAIL + } else { + bessel_prec_dropoff(input, ulp, ctx) + } + } + } } } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index c24ac6e43bc..deb837887fa 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -52,6 +52,8 @@ impl CheckCtx { pub enum CheckBasis { /// Check against Musl's math sources. Musl, + /// Check against infinite precision (MPFR). + Mpfr, } /// A trait to implement on any output type so we can verify it in a generic way. diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 208b8e28618..5a118f7c209 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -29,8 +29,8 @@ macro_rules! musl_rand_tests { fn [< musl_random_ $fn_name >]() { let fname = stringify!($fn_name); let ulp = musl_allowed_ulp(fname); - let cases = random::get_test_cases::<$RustArgs>(fname); let ctx = CheckCtx::new(ulp, fname, CheckBasis::Musl); + let cases = random::get_test_cases::<$RustArgs>(&ctx); for input in cases { let musl_res = input.call(musl::$fn_name as $CFn); diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs new file mode 100644 index 00000000000..f8d94a1609e --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -0,0 +1,71 @@ +//! Test with "infinite precision" + +#![cfg(feature = "test-multiprecision")] + +use libm_test::gen::random; +use libm_test::mpfloat::{self, MpOp}; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, TupleCall, multiprec_allowed_ulp}; + +/// Implement a test against MPFR with random inputs. +macro_rules! multiprec_rand_tests { + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + attrs: [$($meta:meta)*] + ) => { + paste::paste! { + #[test] + $(#[$meta])* + fn [< multiprec_random_ $fn_name >]() { + type MpOpTy = mpfloat::$fn_name::Operation; + + let fname = stringify!($fn_name); + let ulp = multiprec_allowed_ulp(fname); + let mut mp_vals = MpOpTy::new(); + let ctx = CheckCtx::new(ulp, fname, CheckBasis::Mpfr); + let cases = random::get_test_cases::<$RustArgs>(&ctx); + + for input in cases { + let mp_res = mp_vals.run(input); + let crate_res = input.call(libm::$fn_name as $RustFn); + + crate_res.validate(mp_res, input, &ctx).unwrap(); + } + } + } + }; +} + +libm_macros::for_each_function! { + callback: multiprec_rand_tests, + attributes: [ + // Also an assertion failure on i686: at `MPFR_ASSERTN (! mpfr_erangeflag_p ())` + #[ignore = "large values are infeasible in MPFR"] + [jn, jnf], + ], + skip: [ + // FIXME: MPFR tests needed + frexp, + frexpf, + ilogb, + ilogbf, + ldexp, + ldexpf, + modf, + modff, + remquo, + remquof, + scalbn, + scalbnf, + + // FIXME: test needed, see + // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 + nextafter, + nextafterf, + ], +} -- cgit 1.4.1-3-g733a5 From 54c8ae0980a6b53495a6af3e1d85796f2e53fd8b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Oct 2024 17:41:42 -0500 Subject: Run tests against MPFR on CI where possible This effectively gives us tests against infinite-precision results on MacOS and x86+sse Linux. --- .../libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 2 +- .../libm/ci/docker/i686-unknown-linux-gnu/Dockerfile | 2 +- .../libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 2 +- library/compiler-builtins/libm/ci/run.sh | 16 ++++++++++++++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index a7b23cb9e02..7fa06b28601 100644 --- a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -3,7 +3,7 @@ FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ - gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ + gcc-aarch64-linux-gnu m4 make libc6-dev-arm64-cross \ qemu-user-static ENV TOOLCHAIN_PREFIX=aarch64-linux-gnu- diff --git a/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile index 3b0bfc0d3d9..37e206a84fc 100644 --- a/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -2,4 +2,4 @@ FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc-multilib libc6-dev ca-certificates + gcc-multilib m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile index 15723ab57ee..c84a31c57a9 100644 --- a/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -2,4 +2,4 @@ FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates + gcc m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 30265e513a2..94612adc72f 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -35,6 +35,22 @@ case "$target" in *) extra_flags="$extra_flags --features libm-test/build-musl" ;; esac +# Configure which targets test against MPFR +case "$target" in + # MSVC cannot link MPFR + *windows-msvc*) ;; + # FIXME: MinGW should be able to build MPFR, but setup in CI is nontrivial. + *windows-gnu*) ;; + # Targets that aren't cross compiled work fine + # FIXME(ci): we should be able to enable aarch64 Linux here once GHA + # support rolls out. + x86_64*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; + # i686 works fine, i586 does not + i686*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; + # Apple aarch64 is native + aarch64*apple*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; +esac + # FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. # case "$target" in -- cgit 1.4.1-3-g733a5 From 395419d2d2178dade8bfc51935ae596c3231175b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 21:44:28 -0500 Subject: Rename the `special_case` module to `precision` and move default ULP Having the default ULP in lib.rs doesn't make much sense when everything else precision-related is in special_case.rs. Rename `special_case` to `precision` and move the `*_allowed_ulp` functions there. --- .../libm/crates/libm-test/src/lib.rs | 57 +--- .../libm/crates/libm-test/src/precision.rs | 373 +++++++++++++++++++++ .../libm/crates/libm-test/src/special_case.rs | 320 ------------------ 3 files changed, 375 insertions(+), 375 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/precision.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/special_case.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 13b76d6c5a8..31b95e46c06 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -2,11 +2,11 @@ pub mod gen; #[cfg(feature = "test-multiprecision")] pub mod mpfloat; mod num_traits; -mod special_case; +mod precision; mod test_traits; pub use num_traits::{Float, Hex, Int}; -pub use special_case::{MaybeOverride, SpecialCase}; +pub use precision::{MaybeOverride, SpecialCase, multiprec_allowed_ulp, musl_allowed_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to @@ -16,59 +16,6 @@ pub type TestResult = Result; // List of all files present in libm's source include!(concat!(env!("OUT_DIR"), "/all_files.rs")); -/// Default ULP allowed to differ from musl (note that musl itself may not be accurate). -const MUSL_DEFAULT_ULP: u32 = 2; - -/// Default ULP allowed to differ from multiprecision (i.e. infinite) results. -const MULTIPREC_DEFAULT_ULP: u32 = 1; - -/// ULP allowed to differ from muls results. -/// -/// Note that these results were obtained using 400,000,000 rounds of random inputs, which -/// is not a value used by default. -pub fn musl_allowed_ulp(name: &str) -> u32 { - // Consider overrides xfail - match name { - #[cfg(x86_no_sse)] - "asinh" | "asinhf" => 6, - "lgamma" | "lgamma_r" | "lgammaf" | "lgammaf_r" => 400, - "tanh" | "tanhf" => 4, - "tgamma" => 20, - "j0" | "j0f" | "j1" | "j1f" => { - // Results seem very target-dependent - if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } - } - "jn" | "jnf" => 1000, - "sincosf" => 500, - #[cfg(not(target_pointer_width = "64"))] - "exp10" => 4, - #[cfg(not(target_pointer_width = "64"))] - "exp10f" => 4, - _ => MUSL_DEFAULT_ULP, - } -} - -/// ULP allowed to differ from multiprecision results. -pub fn multiprec_allowed_ulp(name: &str) -> u32 { - // Consider overrides xfail - match name { - "asinh" | "asinhf" => 2, - "acoshf" => 4, - "atanh" | "atanhf" => 2, - "exp10" | "exp10f" => 3, - "j0" | "j0f" | "j1" | "j1f" => { - // Results seem very target-dependent - if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } - } - "jn" | "jnf" => 1000, - "lgamma" | "lgammaf" | "lgamma_r" | "lgammaf_r" => 16, - "sinh" | "sinhf" => 2, - "tanh" | "tanhf" => 2, - "tgamma" => 20, - _ => MULTIPREC_DEFAULT_ULP, - } -} - /// Return the unsuffixed version of a function name; e.g. `abs` and `absf` both return `abs`, /// `lgamma_r` and `lgammaf_r` both return `lgamma_r`. pub fn canonical_name(name: &str) -> &str { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs new file mode 100644 index 00000000000..e2ad638c412 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -0,0 +1,373 @@ +//! Configuration for skipping or changing the result for individual test cases (inputs) rather +//! than ignoring entire tests. + +use core::f32; + +use crate::{CheckBasis, CheckCtx, Float, Int, TestResult}; + +/// Type implementing [`IgnoreCase`]. +pub struct SpecialCase; + +/// Default ULP allowed to differ from musl (note that musl itself may not be accurate). +const MUSL_DEFAULT_ULP: u32 = 2; + +/// Default ULP allowed to differ from multiprecision (i.e. infinite) results. +const MULTIPREC_DEFAULT_ULP: u32 = 1; + +/// ULP allowed to differ from muls results. +/// +/// Note that these results were obtained using 400,000,000 rounds of random inputs, which +/// is not a value used by default. +pub fn musl_allowed_ulp(name: &str) -> u32 { + // Consider overrides xfail + match name { + #[cfg(x86_no_sse)] + "asinh" | "asinhf" => 6, + "lgamma" | "lgamma_r" | "lgammaf" | "lgammaf_r" => 400, + "tanh" | "tanhf" => 4, + "tgamma" => 20, + "j0" | "j0f" | "j1" | "j1f" => { + // Results seem very target-dependent + if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } + } + "jn" | "jnf" => 1000, + "sincosf" => 500, + #[cfg(not(target_pointer_width = "64"))] + "exp10" => 4, + #[cfg(not(target_pointer_width = "64"))] + "exp10f" => 4, + _ => MUSL_DEFAULT_ULP, + } +} + +/// ULP allowed to differ from multiprecision results. +pub fn multiprec_allowed_ulp(name: &str) -> u32 { + // Consider overrides xfail + match name { + "asinh" | "asinhf" => 2, + "acoshf" => 4, + "atanh" | "atanhf" => 2, + "exp10" | "exp10f" => 3, + "j0" | "j0f" | "j1" | "j1f" => { + // Results seem very target-dependent + if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } + } + "jn" | "jnf" => 1000, + "lgamma" | "lgammaf" | "lgamma_r" | "lgammaf_r" => 16, + "sinh" | "sinhf" => 2, + "tanh" | "tanhf" => 2, + "tgamma" => 20, + _ => MULTIPREC_DEFAULT_ULP, + } +} + +/// Don't run further validation on this test case. +const SKIP: Option = Some(Ok(())); + +/// Return this to skip checks on a test that currently fails but shouldn't. Looks +/// the same as skip, but we keep them separate to better indicate purpose. +const XFAIL: Option = Some(Ok(())); + +/// Allow overriding the outputs of specific test cases. +/// +/// There are some cases where we want to xfail specific cases or handle certain inputs +/// differently than the rest of calls to `validate`. This provides a hook to do that. +/// +/// If `None` is returned, checks will proceed as usual. If `Some(result)` is returned, checks +/// are skipped and the provided result is returned instead. +/// +/// This gets implemented once per input type, then the functions provide further filtering +/// based on function name and values. +/// +/// `ulp` can also be set to adjust the ULP for that specific test, even if `None` is still +/// returned. +pub trait MaybeOverride { + fn check_float( + _input: Input, + _actual: F, + _expected: F, + _ulp: &mut u32, + _ctx: &CheckCtx, + ) -> Option { + None + } + + fn check_int( + _input: Input, + _actual: I, + _expected: I, + _ctx: &CheckCtx, + ) -> Option { + None + } +} + +impl MaybeOverride<(f32,)> for SpecialCase { + fn check_float( + input: (f32,), + actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + if ctx.basis == CheckBasis::Musl { + if ctx.fname == "expm1f" && input.0 > 80.0 && actual.is_infinite() { + // we return infinity but the number is representable + return XFAIL; + } + + if ctx.fname == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { + // we return some NaN that should be real values or infinite + // doesn't seem to happen on x86 + return XFAIL; + } + } + + if ctx.fname == "acoshf" && input.0 < -1.0 { + // acoshf is undefined for x <= 1.0, but we return a random result at lower + // values. + return XFAIL; + } + + if ctx.fname == "lgammaf" || ctx.fname == "lgammaf_r" && input.0 < 0.0 { + // loggamma should not be defined for x < 0, yet we both return results + return XFAIL; + } + + maybe_check_nan_bits(actual, expected, ctx) + } + + fn check_int( + input: (f32,), + actual: I, + expected: I, + ctx: &CheckCtx, + ) -> Option> { + // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR + // sets +1 + if ctx.basis == CheckBasis::Mpfr + && ctx.fname == "lgammaf_r" + && input.0 == f32::NEG_INFINITY + && actual.abs() == expected.abs() + { + XFAIL + } else { + None + } + } +} + +impl MaybeOverride<(f64,)> for SpecialCase { + fn check_float( + input: (f64,), + actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + if ctx.basis == CheckBasis::Musl { + if cfg!(target_arch = "x86") && ctx.fname == "acosh" && input.0 < 1.0 { + // The function is undefined, both implementations return random results + return SKIP; + } + + if cfg!(x86_no_sse) + && ctx.fname == "ceil" + && input.0 < 0.0 + && input.0 > -1.0 + && expected == F::ZERO + && actual == F::ZERO + { + // musl returns -0.0, we return +0.0 + return XFAIL; + } + } + + if ctx.fname == "acosh" && input.0 < 1.0 { + // The function is undefined for the inputs, musl and our libm both return + // random results. + return XFAIL; + } + + if ctx.fname == "lgamma" || ctx.fname == "lgamma_r" && input.0 < 0.0 { + // loggamma should not be defined for x < 0, yet we both return results + return XFAIL; + } + + maybe_check_nan_bits(actual, expected, ctx) + } + + fn check_int( + input: (f64,), + actual: I, + expected: I, + ctx: &CheckCtx, + ) -> Option> { + // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR + // sets +1 + if ctx.basis == CheckBasis::Mpfr + && ctx.fname == "lgamma_r" + && input.0 == f64::NEG_INFINITY + && actual.abs() == expected.abs() + { + XFAIL + } else { + None + } + } +} + +/// Check NaN bits if the function requires it +fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { + if !(ctx.canonical_name == "fabs" || ctx.canonical_name == "copysign") { + return None; + } + + // LLVM currently uses x87 instructions which quieten signalling NaNs to handle the i686 + // `extern "C"` `f32`/`f64` return ABI. + // LLVM issue + // Rust issue + if cfg!(target_arch = "x86") && ctx.basis == CheckBasis::Musl { + return SKIP; + } + + // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. + if ctx.basis == CheckBasis::Mpfr { + return SKIP; + } + + // abs and copysign require signaling NaNs to be propagated, so verify bit equality. + if actual.to_bits() == expected.to_bits() { + return SKIP; + } else { + Some(Err(anyhow::anyhow!("NaNs have different bitpatterns"))) + } +} + +impl MaybeOverride<(f32, f32)> for SpecialCase { + fn check_float( + input: (f32, f32), + _actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_skip_binop_nan(input, expected, ctx) + } +} + +impl MaybeOverride<(f64, f64)> for SpecialCase { + fn check_float( + input: (f64, f64), + _actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_skip_binop_nan(input, expected, ctx) + } +} + +/// Musl propagates NaNs if one is provided as the input, but we return the other input. +// F1 and F2 are always the same type, this is just to please generics +fn maybe_skip_binop_nan( + input: (F1, F1), + expected: F2, + ctx: &CheckCtx, +) -> Option { + match ctx.basis { + CheckBasis::Musl => { + if (ctx.canonical_name == "fmax" || ctx.canonical_name == "fmin") + && (input.0.is_nan() || input.1.is_nan()) + && expected.is_nan() + { + XFAIL + } else { + None + } + } + CheckBasis::Mpfr => { + if ctx.canonical_name == "copysign" && input.1.is_nan() { + SKIP + } else { + None + } + } + } +} + +impl MaybeOverride<(i32, f32)> for SpecialCase { + fn check_float( + input: (i32, f32), + actual: F, + expected: F, + ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + match ctx.basis { + CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), + CheckBasis::Mpfr => { + // We return +0.0, MPFR returns -0.0 + if ctx.fname == "jnf" + && input.1 == f32::NEG_INFINITY + && actual == F::ZERO + && expected == F::ZERO + { + XFAIL + } else { + None + } + } + } + } +} +impl MaybeOverride<(i32, f64)> for SpecialCase { + fn check_float( + input: (i32, f64), + actual: F, + expected: F, + ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + match ctx.basis { + CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), + CheckBasis::Mpfr => { + // We return +0.0, MPFR returns -0.0 + if ctx.fname == "jn" + && input.1 == f64::NEG_INFINITY + && actual == F::ZERO + && expected == F::ZERO + { + XFAIL + } else { + bessel_prec_dropoff(input, ulp, ctx) + } + } + } + } +} + +/// Our bessel functions blow up with large N values +fn bessel_prec_dropoff( + input: (i32, F), + ulp: &mut u32, + ctx: &CheckCtx, +) -> Option { + if ctx.canonical_name == "jn" { + if input.0 > 4000 { + return XFAIL; + } else if input.0 > 2000 { + // *ulp = 20_000; + *ulp = 20000; + } else if input.0 > 1000 { + *ulp = 4000; + } + } + + None +} + +impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} +impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} +impl MaybeOverride<(f32, i32)> for SpecialCase {} +impl MaybeOverride<(f64, i32)> for SpecialCase {} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs b/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs deleted file mode 100644 index dac7a349dc4..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs +++ /dev/null @@ -1,320 +0,0 @@ -//! Configuration for skipping or changing the result for individual test cases (inputs) rather -//! than ignoring entire tests. - -use core::f32; - -use crate::{CheckBasis, CheckCtx, Float, Int, TestResult}; - -/// Type implementing [`IgnoreCase`]. -pub struct SpecialCase; - -/// Don't run further validation on this test case. -const SKIP: Option = Some(Ok(())); - -/// Return this to skip checks on a test that currently fails but shouldn't. Looks -/// the same as skip, but we keep them separate to better indicate purpose. -const XFAIL: Option = Some(Ok(())); - -/// Allow overriding the outputs of specific test cases. -/// -/// There are some cases where we want to xfail specific cases or handle certain inputs -/// differently than the rest of calls to `validate`. This provides a hook to do that. -/// -/// If `None` is returned, checks will proceed as usual. If `Some(result)` is returned, checks -/// are skipped and the provided result is returned instead. -/// -/// This gets implemented once per input type, then the functions provide further filtering -/// based on function name and values. -/// -/// `ulp` can also be set to adjust the ULP for that specific test, even if `None` is still -/// returned. -pub trait MaybeOverride { - fn check_float( - _input: Input, - _actual: F, - _expected: F, - _ulp: &mut u32, - _ctx: &CheckCtx, - ) -> Option { - None - } - - fn check_int( - _input: Input, - _actual: I, - _expected: I, - _ctx: &CheckCtx, - ) -> Option { - None - } -} - -impl MaybeOverride<(f32,)> for SpecialCase { - fn check_float( - input: (f32,), - actual: F, - expected: F, - _ulp: &mut u32, - ctx: &CheckCtx, - ) -> Option { - if ctx.basis == CheckBasis::Musl { - if ctx.fname == "expm1f" && input.0 > 80.0 && actual.is_infinite() { - // we return infinity but the number is representable - return XFAIL; - } - - if ctx.fname == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { - // we return some NaN that should be real values or infinite - // doesn't seem to happen on x86 - return XFAIL; - } - } - - if ctx.fname == "acoshf" && input.0 < -1.0 { - // acoshf is undefined for x <= 1.0, but we return a random result at lower - // values. - return XFAIL; - } - - if ctx.fname == "lgammaf" || ctx.fname == "lgammaf_r" && input.0 < 0.0 { - // loggamma should not be defined for x < 0, yet we both return results - return XFAIL; - } - - maybe_check_nan_bits(actual, expected, ctx) - } - - fn check_int( - input: (f32,), - actual: I, - expected: I, - ctx: &CheckCtx, - ) -> Option> { - // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR - // sets +1 - if ctx.basis == CheckBasis::Mpfr - && ctx.fname == "lgammaf_r" - && input.0 == f32::NEG_INFINITY - && actual.abs() == expected.abs() - { - XFAIL - } else { - None - } - } -} - -impl MaybeOverride<(f64,)> for SpecialCase { - fn check_float( - input: (f64,), - actual: F, - expected: F, - _ulp: &mut u32, - ctx: &CheckCtx, - ) -> Option { - if ctx.basis == CheckBasis::Musl { - if cfg!(target_arch = "x86") && ctx.fname == "acosh" && input.0 < 1.0 { - // The function is undefined, both implementations return random results - return SKIP; - } - - if cfg!(x86_no_sse) - && ctx.fname == "ceil" - && input.0 < 0.0 - && input.0 > -1.0 - && expected == F::ZERO - && actual == F::ZERO - { - // musl returns -0.0, we return +0.0 - return XFAIL; - } - } - - if ctx.fname == "acosh" && input.0 < 1.0 { - // The function is undefined for the inputs, musl and our libm both return - // random results. - return XFAIL; - } - - if ctx.fname == "lgamma" || ctx.fname == "lgamma_r" && input.0 < 0.0 { - // loggamma should not be defined for x < 0, yet we both return results - return XFAIL; - } - - maybe_check_nan_bits(actual, expected, ctx) - } - - fn check_int( - input: (f64,), - actual: I, - expected: I, - ctx: &CheckCtx, - ) -> Option> { - // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR - // sets +1 - if ctx.basis == CheckBasis::Mpfr - && ctx.fname == "lgamma_r" - && input.0 == f64::NEG_INFINITY - && actual.abs() == expected.abs() - { - XFAIL - } else { - None - } - } -} - -/// Check NaN bits if the function requires it -fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { - if !(ctx.canonical_name == "fabs" || ctx.canonical_name == "copysign") { - return None; - } - - // LLVM currently uses x87 instructions which quieten signalling NaNs to handle the i686 - // `extern "C"` `f32`/`f64` return ABI. - // LLVM issue - // Rust issue - if cfg!(target_arch = "x86") && ctx.basis == CheckBasis::Musl { - return SKIP; - } - - // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. - if ctx.basis == CheckBasis::Mpfr { - return SKIP; - } - - // abs and copysign require signaling NaNs to be propagated, so verify bit equality. - if actual.to_bits() == expected.to_bits() { - return SKIP; - } else { - Some(Err(anyhow::anyhow!("NaNs have different bitpatterns"))) - } -} - -impl MaybeOverride<(f32, f32)> for SpecialCase { - fn check_float( - input: (f32, f32), - _actual: F, - expected: F, - _ulp: &mut u32, - ctx: &CheckCtx, - ) -> Option { - maybe_skip_binop_nan(input, expected, ctx) - } -} - -impl MaybeOverride<(f64, f64)> for SpecialCase { - fn check_float( - input: (f64, f64), - _actual: F, - expected: F, - _ulp: &mut u32, - ctx: &CheckCtx, - ) -> Option { - maybe_skip_binop_nan(input, expected, ctx) - } -} - -/// Musl propagates NaNs if one is provided as the input, but we return the other input. -// F1 and F2 are always the same type, this is just to please generics -fn maybe_skip_binop_nan( - input: (F1, F1), - expected: F2, - ctx: &CheckCtx, -) -> Option { - match ctx.basis { - CheckBasis::Musl => { - if (ctx.canonical_name == "fmax" || ctx.canonical_name == "fmin") - && (input.0.is_nan() || input.1.is_nan()) - && expected.is_nan() - { - XFAIL - } else { - None - } - } - CheckBasis::Mpfr => { - if ctx.canonical_name == "copysign" && input.1.is_nan() { - SKIP - } else { - None - } - } - } -} - -impl MaybeOverride<(i32, f32)> for SpecialCase { - fn check_float( - input: (i32, f32), - actual: F, - expected: F, - ulp: &mut u32, - ctx: &CheckCtx, - ) -> Option { - match ctx.basis { - CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), - CheckBasis::Mpfr => { - // We return +0.0, MPFR returns -0.0 - if ctx.fname == "jnf" - && input.1 == f32::NEG_INFINITY - && actual == F::ZERO - && expected == F::ZERO - { - XFAIL - } else { - None - } - } - } - } -} -impl MaybeOverride<(i32, f64)> for SpecialCase { - fn check_float( - input: (i32, f64), - actual: F, - expected: F, - ulp: &mut u32, - ctx: &CheckCtx, - ) -> Option { - match ctx.basis { - CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), - CheckBasis::Mpfr => { - // We return +0.0, MPFR returns -0.0 - if ctx.fname == "jn" - && input.1 == f64::NEG_INFINITY - && actual == F::ZERO - && expected == F::ZERO - { - XFAIL - } else { - bessel_prec_dropoff(input, ulp, ctx) - } - } - } - } -} - -/// Our bessel functions blow up with large N values -fn bessel_prec_dropoff( - input: (i32, F), - ulp: &mut u32, - ctx: &CheckCtx, -) -> Option { - if ctx.canonical_name == "jn" { - if input.0 > 4000 { - return XFAIL; - } else if input.0 > 2000 { - // *ulp = 20_000; - *ulp = 20000; - } else if input.0 > 1000 { - *ulp = 4000; - } - } - - None -} - -impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} -impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} -impl MaybeOverride<(f32, i32)> for SpecialCase {} -impl MaybeOverride<(f64, i32)> for SpecialCase {} -- cgit 1.4.1-3-g733a5 From ad1c65229384b21e3dafdc40f8d2119df3186cae Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 03:05:01 -0500 Subject: Update `libm-test/build.rs` to skip directories Don't try to generate tests for directories, or for files that contain `f16` or `f128` (as these types are not provided by musl's math implementations). (cherry picked from commit fd7ad36b70d0bbc0f0b9bc7e54d10258423fda29) --- .../compiler-builtins/libm/crates/libm-test/build.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index 472dec9d33e..40b3e56c046 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -156,7 +156,11 @@ mod musl_serialized_tests { return; } - let files = fs::read_dir(math_src).unwrap().map(|f| f.unwrap().path()).collect::>(); + let files = fs::read_dir(math_src) + .unwrap() + .map(|f| f.unwrap().path()) + .filter(file_needs_test) + .collect::>(); let mut math = Vec::new(); for file in files { @@ -187,6 +191,19 @@ mod musl_serialized_tests { generate_unit_tests(&math); } + /// Check whether a path within `src/math` should get tests generated. + fn file_needs_test(path: &PathBuf) -> bool { + // Skip directories + if path.is_dir() { + return false; + } + + let fname = path.file_name().unwrap().to_str().unwrap(); + + // Musl doesn't support `f16` or `f128` + !(fname.contains("f16") || fname.contains("f128")) + } + /// A "poor man's" parser for the signature of a function fn parse(s: &str) -> Function { let s = eat(s, "pub fn "); -- cgit 1.4.1-3-g733a5 From ec1ca5129826bdaf4f6f1c97255547bfc8d12b77 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 02:56:22 -0500 Subject: Vendor `cfg_if::cfg_if!` `cfg_if` is helpful for applying `cfg` attributes to groups of items, like we will need to do with architecture-specific modules of `f16` and `f128`. However, `libm` can't have dependencies. The `cfg_if` macro is complex but small, so just vendor it here. --- .../libm/src/math/support/macros.rs | 46 ++++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index 6bc75837a34..39a6fe82772 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -1,6 +1,46 @@ -/// Choose among using an intrinsic (if available) and falling back to the default function body. -/// Returns directly if the intrinsic version is used, otherwise continues to the rest of the -/// function. +/// `libm` cannot have dependencies, so this is vendored directly from the `cfg-if` crate +/// (with some comments stripped for compactness). +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($meta:meta)] { $($tokens:tt)* } + ) else * else { + $($tokens2:tt)* + }) => { + cfg_if! { @__items () ; $( ( ($meta) ($($tokens)*) ), )* ( () ($($tokens2)*) ), } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($i_met:meta)] { $($i_tokens:tt)* } + $( else if #[cfg($e_met:meta)] { $($e_tokens:tt)* } )* + ) => { + cfg_if! { + @__items + () ; + ( ($i_met) ($($i_tokens)*) ), + $( ( ($e_met) ($($e_tokens)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($tokens:tt)*) ), $($rest:tt)*) => { + #[cfg(all($($m,)* not(any($($not),*))))] cfg_if! { @__identity $($tokens)* } + cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to make __apply work out right for different match types, + // because of how macros matching/expand stuff. + (@__identity $($tokens:tt)*) => { $($tokens)* }; +} + +/// Choose between using an intrinsic (if available) and the function body. Returns directly if +/// the intrinsic is used, otherwise the rest of the function body is used. /// /// Use this if the intrinsic is likely to be more performant on the platform(s) specified /// in `intrinsic_available`. -- cgit 1.4.1-3-g733a5 From 6d1033e7fc2beb6ce494c7099770326a8a3883c4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 20:24:46 -0500 Subject: Add an "arch" Cargo feature that is on by default Introduce a Cargo feature to enable or disable architecture-specific features (SIMD, assembly), which is on by default. This allows for more fine grained control compared to relying on the `force-soft-floats` feature. Similar to "unstable-intrinsics", introduce a build.rs config option for `unstable-intrinsics AND NOT force-soft-floats`, which makes this easier to work with in code. Effectively, this allows moving our non-additive Cargo feature (force-soft-floats) to a positive one by default, allowing for an override when needed. --- library/compiler-builtins/libm/Cargo.toml | 5 ++++- library/compiler-builtins/libm/build.rs | 12 ++++++++++++ library/compiler-builtins/libm/ci/run.sh | 1 + .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 1 + 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 5e4565556b0..2e74012eae4 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -14,7 +14,10 @@ exclude = ["/ci/", "/.github/workflows/"] rust-version = "1.63" [features] -default = [] +default = ["arch"] + +# Enable architecture-specific features such as SIMD or assembly routines. +arch = [] # This tells the compiler to assume that a Nightly toolchain is being used and # that it should activate any useful Nightly things accordingly. diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index adb52140730..00102923611 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -15,6 +15,7 @@ fn main() { } configure_intrinsics(); + configure_arch(); } /// Simplify the feature logic for enabling intrinsics so code only needs to use @@ -28,3 +29,14 @@ fn configure_intrinsics() { println!("cargo:rustc-cfg=intrinsics_enabled"); } } + +/// Simplify the feature logic for enabling arch-specific features so code only needs to use +/// `cfg(arch_enabled)`. +fn configure_arch() { + println!("cargo:rustc-check-cfg=cfg(arch_enabled)"); + + // Enabled by default via the "arch" feature, `force-soft-floats` overrides to disable. + if cfg!(feature = "arch") && !cfg!(feature = "force-soft-floats") { + println!("cargo:rustc-cfg=arch_enabled"); + } +} diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 94612adc72f..9f642326ba8 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -64,6 +64,7 @@ fi # Make sure we can build with overriding features. We test the indibidual # features it controls separately. +cargo check --no-default-features cargo check --features "force-soft-floats" if [ "${BUILD_ONLY:-}" = "1" ]; then diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 2a6c62961e3..7118bfe06f1 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -18,6 +18,7 @@ force-soft-floats = [] [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ + "cfg(arch_enabled)", "cfg(assert_no_panic)", "cfg(intrinsics_enabled)", ] } -- cgit 1.4.1-3-g733a5 From 7108e80dc23b9c4971151b0627925554013346de Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 20:29:55 -0500 Subject: Update `select_implementation` to accept arch configuration --- .../libm/src/math/support/macros.rs | 45 +++++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index 39a6fe82772..f85a6122ee8 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -39,17 +39,31 @@ macro_rules! cfg_if { (@__identity $($tokens:tt)*) => { $($tokens)* }; } -/// Choose between using an intrinsic (if available) and the function body. Returns directly if -/// the intrinsic is used, otherwise the rest of the function body is used. +/// Choose among using an intrinsic, an arch-specific implementation, and the function body. +/// Returns directly if the intrinsic or arch is used, otherwise continue with the rest of the +/// function. /// -/// Use this if the intrinsic is likely to be more performant on the platform(s) specified -/// in `intrinsic_available`. +/// Specify a `use_intrinsic` meta field if the intrinsic is (1) available on the platforms (i.e. +/// LLVM lowers it without libcalls that may recurse), (2) it is likely to be more performant. +/// Intrinsics require wrappers in the `math::arch::intrinsics` module. /// -/// The `cfg` used here is controlled by `build.rs` so the passed meta does not need to account -/// for e.g. the `unstable-intrinsics` or `force-soft-float` features. +/// Specify a `use_arch` meta field if an architecture-specific implementation is provided. +/// These live in the `math::arch::some_target_arch` module. +/// +/// Specify a `use_arch_required` meta field if something architecture-specific must be used +/// regardless of feature configuration (`force-soft-floats`). +/// +/// The passed meta options do not need to account for relevant Cargo features +/// (`unstable-intrinsics`, `arch`, `force-soft-floats`), this macro handles that part. macro_rules! select_implementation { ( name: $fname:ident, + // Configuration meta for when to use arch-specific implementation that requires hard + // float ops + $( use_arch: $use_arch:meta, )? + // Configuration meta for when to use the arch module regardless of whether softfloats + // have been requested. + $( use_arch_required: $use_arch_required:meta, )? // Configuration meta for when to call intrinsics and let LLVM figure it out $( use_intrinsic: $use_intrinsic:meta, )? args: $($arg:ident),+ , @@ -57,6 +71,25 @@ macro_rules! select_implementation { // FIXME: these use paths that are a pretty fragile (`super`). We should figure out // something better w.r.t. how this is vendored into compiler-builtins. + // However, we do need a few things from `arch` that are used even with soft floats. + // + select_implementation! { + @cfg $($use_arch_required)?; + if true { + return super::arch::$fname( $($arg),+ ); + } + } + + // By default, never use arch-specific implementations if we have force-soft-floats + #[cfg(arch_enabled)] + select_implementation! { + @cfg $($use_arch)?; + // Wrap in `if true` to avoid unused warnings + if true { + return super::arch::$fname( $($arg),+ ); + } + } + // Never use intrinsics if we are forcing soft floats, and only enable with the // `unstable-intrinsics` feature. #[cfg(intrinsics_enabled)] -- cgit 1.4.1-3-g733a5 From d6646ae2d1170e2716c5f964cc394f14b4b6a7da Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 20:31:48 -0500 Subject: Move architecture-specific code to `src/math/arch` Move the code and call into its new location with `select_implementation`. --- .../compiler-builtins/libm/src/math/arch/i586.rs | 37 ++++ .../compiler-builtins/libm/src/math/arch/i686.rs | 24 +++ .../compiler-builtins/libm/src/math/arch/mod.rs | 19 ++ library/compiler-builtins/libm/src/math/ceil.rs | 19 +- library/compiler-builtins/libm/src/math/floor.rs | 19 +- library/compiler-builtins/libm/src/math/sqrt.rs | 233 ++++++++++----------- library/compiler-builtins/libm/src/math/sqrtf.rs | 159 +++++++------- 7 files changed, 261 insertions(+), 249 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/arch/i586.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/i686.rs diff --git a/library/compiler-builtins/libm/src/math/arch/i586.rs b/library/compiler-builtins/libm/src/math/arch/i586.rs new file mode 100644 index 00000000000..f92b9a2af71 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/i586.rs @@ -0,0 +1,37 @@ +//! Architecture-specific support for x86-32 without SSE2 + +use super::super::fabs; + +/// Use an alternative implementation on x86, because the +/// main implementation fails with the x87 FPU used by +/// debian i386, probably due to excess precision issues. +/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219. +pub fn ceil(x: f64) -> f64 { + if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated < x { + return truncated + 1.0; + } else { + return truncated; + } + } else { + return x; + } +} + +/// Use an alternative implementation on x86, because the +/// main implementation fails with the x87 FPU used by +/// debian i386, probably due to excess precision issues. +/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219. +pub fn floor(x: f64) -> f64 { + if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated > x { + return truncated - 1.0; + } else { + return truncated; + } + } else { + return x; + } +} diff --git a/library/compiler-builtins/libm/src/math/arch/i686.rs b/library/compiler-builtins/libm/src/math/arch/i686.rs new file mode 100644 index 00000000000..80f7face174 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/i686.rs @@ -0,0 +1,24 @@ +//! Architecture-specific support for x86-32 and x86-64 with SSE2 + +#![cfg(not(feature = "force-soft-floats"))] + +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; + +pub fn sqrtf(x: f32) -> f32 { + unsafe { + let m = _mm_set_ss(x); + let m_sqrt = _mm_sqrt_ss(m); + _mm_cvtss_f32(m_sqrt) + } +} + +pub fn sqrt(x: f64) -> f64 { + unsafe { + let m = _mm_set_sd(x); + let m_sqrt = _mm_sqrt_pd(m); + _mm_cvtsd_f64(m_sqrt) + } +} diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index a4bc218b743..cf9547117b8 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -7,3 +7,22 @@ #[cfg(intrinsics_enabled)] pub mod intrinsics; + +// Most implementations should be defined here, to ensure they are not made available when +// soft floats are required. +#[cfg(arch_enabled)] +cfg_if! { + if #[cfg(target_feature = "sse2")] { + mod i686; + pub use i686::{sqrt, sqrtf}; + } +} + +// There are certain architecture-specific implementations that are needed for correctness +// even with `force-soft-float`. These are configured here. +cfg_if! { + if #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] { + mod i586; + pub use i586::{ceil, floor}; + } +} diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 0da01b4d0b6..c7e857dbb6f 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -10,28 +10,11 @@ const TOINT: f64 = 1. / f64::EPSILON; pub fn ceil(x: f64) -> f64 { select_implementation! { name: ceil, + use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), use_intrinsic: target_arch = "wasm32", args: x, } - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - { - //use an alternative implementation on x86, because the - //main implementation fails with the x87 FPU used by - //debian i386, probably due to excess precision issues. - //basic implementation taken from https://github.com/rust-lang/libm/issues/219 - use super::fabs; - if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { - let truncated = x as i64 as f64; - if truncated < x { - return truncated + 1.0; - } else { - return truncated; - } - } else { - return x; - } - } let u: u64 = x.to_bits(); let e: i64 = (u >> 52 & 0x7ff) as i64; let y: f64; diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index 2b9955ebae3..532226b9f86 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -10,28 +10,11 @@ const TOINT: f64 = 1. / f64::EPSILON; pub fn floor(x: f64) -> f64 { select_implementation! { name: floor, + use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), use_intrinsic: target_arch = "wasm32", args: x, } - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - { - //use an alternative implementation on x86, because the - //main implementation fails with the x87 FPU used by - //debian i386, probably due to excess precision issues. - //basic implementation taken from https://github.com/rust-lang/libm/issues/219 - use super::fabs; - if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { - let truncated = x as i64 as f64; - if truncated > x { - return truncated - 1.0; - } else { - return truncated; - } - } else { - return x; - } - } let ui = x.to_bits(); let e = ((ui >> 52) & 0x7ff) as i32; diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 2e856100f7d..a443b7e4c61 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -83,156 +83,139 @@ use core::f64; pub fn sqrt(x: f64) -> f64 { select_implementation! { name: sqrt, + use_arch: target_feature = "sse2", use_intrinsic: target_arch = "wasm32", args: x, } - #[cfg(all(target_feature = "sse2", not(feature = "force-soft-floats")))] - { - // Note: This path is unlikely since LLVM will usually have already - // optimized sqrt calls into hardware instructions if sse2 is available, - // but if someone does end up here they'll appreciate the speed increase. - #[cfg(target_arch = "x86")] - use core::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::*; - unsafe { - let m = _mm_set_sd(x); - let m_sqrt = _mm_sqrt_pd(m); - _mm_cvtsd_f64(m_sqrt) - } - } - #[cfg(any(not(target_feature = "sse2"), feature = "force-soft-floats"))] - { - use core::num::Wrapping; + use core::num::Wrapping; - const TINY: f64 = 1.0e-300; + const TINY: f64 = 1.0e-300; - let mut z: f64; - let sign: Wrapping = Wrapping(0x80000000); - let mut ix0: i32; - let mut s0: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: Wrapping; - let mut t1: Wrapping; - let mut s1: Wrapping; - let mut ix1: Wrapping; - let mut q1: Wrapping; + let mut z: f64; + let sign: Wrapping = Wrapping(0x80000000); + let mut ix0: i32; + let mut s0: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: Wrapping; + let mut t1: Wrapping; + let mut s1: Wrapping; + let mut ix1: Wrapping; + let mut q1: Wrapping; - ix0 = (x.to_bits() >> 32) as i32; - ix1 = Wrapping(x.to_bits() as u32); + ix0 = (x.to_bits() >> 32) as i32; + ix1 = Wrapping(x.to_bits() as u32); - /* take care of Inf and NaN */ - if (ix0 & 0x7ff00000) == 0x7ff00000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + /* take care of Inf and NaN */ + if (ix0 & 0x7ff00000) == 0x7ff00000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if ix0 <= 0 { + if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { + return x; /* sqrt(+-0) = +-0 */ } - /* take care of zero */ - if ix0 <= 0 { - if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix0 < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } + if ix0 < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ } - /* normalize x */ - m = ix0 >> 20; - if m == 0 { - /* subnormal x */ - while ix0 == 0 { - m -= 21; - ix0 |= (ix1 >> 11).0 as i32; - ix1 <<= 21; - } - i = 0; - while (ix0 & 0x00100000) == 0 { - i += 1; - ix0 <<= 1; - } - m -= i - 1; - ix0 |= (ix1 >> (32 - i) as usize).0 as i32; - ix1 = ix1 << i as usize; + } + /* normalize x */ + m = ix0 >> 20; + if m == 0 { + /* subnormal x */ + while ix0 == 0 { + m -= 21; + ix0 |= (ix1 >> 11).0 as i32; + ix1 <<= 21; } - m -= 1023; /* unbias exponent */ - ix0 = (ix0 & 0x000fffff) | 0x00100000; - if (m & 1) == 1 { - /* odd m, double x to make it even */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; + i = 0; + while (ix0 & 0x00100000) == 0 { + i += 1; + ix0 <<= 1; } - m >>= 1; /* m = [m/2] */ - - /* generate sqrt(x) bit by bit */ + m -= i - 1; + ix0 |= (ix1 >> (32 - i) as usize).0 as i32; + ix1 = ix1 << i as usize; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0 & 0x000fffff) | 0x00100000; + if (m & 1) == 1 { + /* odd m, double x to make it even */ ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; - q = 0; /* [q,q1] = sqrt(x) */ - q1 = Wrapping(0); - s0 = 0; - s1 = Wrapping(0); - r = Wrapping(0x00200000); /* r = moving bit from right to left */ + } + m >>= 1; /* m = [m/2] */ - while r != Wrapping(0) { - t = s0 + r.0 as i32; - if t <= ix0 { - s0 = t + r.0 as i32; - ix0 -= t; - q += r.0 as i32; - } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + q = 0; /* [q,q1] = sqrt(x) */ + q1 = Wrapping(0); + s0 = 0; + s1 = Wrapping(0); + r = Wrapping(0x00200000); /* r = moving bit from right to left */ + + while r != Wrapping(0) { + t = s0 + r.0 as i32; + if t <= ix0 { + s0 = t + r.0 as i32; + ix0 -= t; + q += r.0 as i32; } + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + r >>= 1; + } - r = sign; - while r != Wrapping(0) { - t1 = s1 + r; - t = s0; - if t < ix0 || (t == ix0 && t1 <= ix1) { - s1 = t1 + r; - if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { - s0 += 1; - } - ix0 -= t; - if ix1 < t1 { - ix0 -= 1; - } - ix1 -= t1; - q1 += r; + r = sign; + while r != Wrapping(0) { + t1 = s1 + r; + t = s0; + if t < ix0 || (t == ix0 && t1 <= ix1) { + s1 = t1 + r; + if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { + s0 += 1; } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; + ix0 -= t; + if ix1 < t1 { + ix0 -= 1; + } + ix1 -= t1; + q1 += r; } + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + r >>= 1; + } - /* use floating add to find out rounding direction */ - if (ix0 as u32 | ix1.0) != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if q1.0 == 0xffffffff { - q1 = Wrapping(0); + /* use floating add to find out rounding direction */ + if (ix0 as u32 | ix1.0) != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if q1.0 == 0xffffffff { + q1 = Wrapping(0); + q += 1; + } else if z > 1.0 { + if q1.0 == 0xfffffffe { q += 1; - } else if z > 1.0 { - if q1.0 == 0xfffffffe { - q += 1; - } - q1 += Wrapping(2); - } else { - q1 += q1 & Wrapping(1); } + q1 += Wrapping(2); + } else { + q1 += q1 & Wrapping(1); } } - ix0 = (q >> 1) + 0x3fe00000; - ix1 = q1 >> 1; - if (q & 1) == 1 { - ix1 |= sign; - } - ix0 += m << 20; - f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } + ix0 = (q >> 1) + 0x3fe00000; + ix1 = q1 >> 1; + if (q & 1) == 1 { + ix1 |= sign; + } + ix0 += m << 20; + f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index b2996b350cb..d2f7ae70334 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -18,109 +18,92 @@ pub fn sqrtf(x: f32) -> f32 { select_implementation! { name: sqrtf, + use_arch: target_feature = "sse2", use_intrinsic: target_arch = "wasm32", args: x, } - #[cfg(all(target_feature = "sse", not(feature = "force-soft-floats")))] - { - // Note: This path is unlikely since LLVM will usually have already - // optimized sqrt calls into hardware instructions if sse is available, - // but if someone does end up here they'll appreciate the speed increase. - #[cfg(target_arch = "x86")] - use core::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::*; - unsafe { - let m = _mm_set_ss(x); - let m_sqrt = _mm_sqrt_ss(m); - _mm_cvtss_f32(m_sqrt) - } - } - #[cfg(any(not(target_feature = "sse"), feature = "force-soft-floats"))] - { - const TINY: f32 = 1.0e-30; - - let mut z: f32; - let sign: i32 = 0x80000000u32 as i32; - let mut ix: i32; - let mut s: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: u32; - - ix = x.to_bits() as i32; - - /* take care of Inf and NaN */ - if (ix as u32 & 0x7f800000) == 0x7f800000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } + const TINY: f32 = 1.0e-30; - /* take care of zero */ - if ix <= 0 { - if (ix & !sign) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } + let mut z: f32; + let sign: i32 = 0x80000000u32 as i32; + let mut ix: i32; + let mut s: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: u32; - /* normalize x */ - m = ix >> 23; - if m == 0 { - /* subnormal x */ - i = 0; - while ix & 0x00800000 == 0 { - ix <<= 1; - i = i + 1; - } - m -= i - 1; + ix = x.to_bits() as i32; + + /* take care of Inf and NaN */ + if (ix as u32 & 0x7f800000) == 0x7f800000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + + /* take care of zero */ + if ix <= 0 { + if (ix & !sign) == 0 { + return x; /* sqrt(+-0) = +-0 */ } - m -= 127; /* unbias exponent */ - ix = (ix & 0x007fffff) | 0x00800000; - if m & 1 == 1 { - /* odd m, double x to make it even */ - ix += ix; + if ix < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ } - m >>= 1; /* m = [m/2] */ + } - /* generate sqrt(x) bit by bit */ + /* normalize x */ + m = ix >> 23; + if m == 0 { + /* subnormal x */ + i = 0; + while ix & 0x00800000 == 0 { + ix <<= 1; + i = i + 1; + } + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if m & 1 == 1 { + /* odd m, double x to make it even */ ix += ix; - q = 0; - s = 0; - r = 0x01000000; /* r = moving bit from right to left */ - - while r != 0 { - t = s + r as i32; - if t <= ix { - s = t + r as i32; - ix -= t; - q += r as i32; - } - ix += ix; - r >>= 1; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = 0; + s = 0; + r = 0x01000000; /* r = moving bit from right to left */ + + while r != 0 { + t = s + r as i32; + if t <= ix { + s = t + r as i32; + ix -= t; + q += r as i32; } + ix += ix; + r >>= 1; + } - /* use floating add to find out rounding direction */ - if ix != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if z > 1.0 { - q += 2; - } else { - q += q & 1; - } + /* use floating add to find out rounding direction */ + if ix != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if z > 1.0 { + q += 2; + } else { + q += q & 1; } } - - ix = (q >> 1) + 0x3f000000; - ix += m << 23; - f32::from_bits(ix as u32) } + + ix = (q >> 1) + 0x3f000000; + ix += m << 23; + f32::from_bits(ix as u32) } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -- cgit 1.4.1-3-g733a5 From 360d3ee184e821e9329a71a18361123aac8e2f8d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 00:42:02 -0500 Subject: Add float and integer traits from compiler-builtins In preparation of adding generic algorithms to `libm`, add the traits from `compiler-builtins`. Eventually we should be able to unify the two crates so we don't have duplicate implementations. --- library/compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/src/math/support/float_traits.rs | 168 ++++++++++ .../libm/src/math/support/int_traits.rs | 343 +++++++++++++++++++++ .../compiler-builtins/libm/src/math/support/mod.rs | 5 + 4 files changed, 518 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/support/float_traits.rs create mode 100644 library/compiler-builtins/libm/src/math/support/int_traits.rs diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 393bc515093..2cd77f1327b 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -105,6 +105,8 @@ use self::k_tanf::k_tanf; use self::rem_pio2::rem_pio2; use self::rem_pio2_large::rem_pio2_large; use self::rem_pio2f::rem_pio2f; +#[allow(unused_imports)] +use self::support::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; // Public modules mod acos; diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs new file mode 100644 index 00000000000..4cf5d7c6165 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -0,0 +1,168 @@ +use core::ops; + +use super::int_traits::{Int, MinInt}; + +/// Trait for some basic operations on floats +#[allow(dead_code)] +pub trait Float: + Copy + + core::fmt::Debug + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::MulAssign + + ops::Add + + ops::Sub + + ops::Div + + ops::Rem +{ + /// A uint of the same width as the float + type Int: Int; + + /// A int of the same width as the float + type SignedInt: Int + MinInt; + + /// An int capable of containing the exponent bits plus a sign bit. This is signed. + type ExpInt: Int; + + const ZERO: Self; + const ONE: Self; + + /// The bitwidth of the float type + const BITS: u32; + + /// The bitwidth of the significand + const SIGNIFICAND_BITS: u32; + + /// The bitwidth of the exponent + const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + + /// The saturated value of the exponent (infinite representation), in the rightmost postiion. + const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; + + /// The exponent bias value + const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; + + /// A mask for the sign bit + const SIGN_MASK: Self::Int; + + /// A mask for the significand + const SIGNIFICAND_MASK: Self::Int; + + /// The implicit bit of the float format + const IMPLICIT_BIT: Self::Int; + + /// A mask for the exponent + const EXPONENT_MASK: Self::Int; + + /// Returns `self` transmuted to `Self::Int` + fn to_bits(self) -> Self::Int; + + /// Returns `self` transmuted to `Self::SignedInt` + fn to_bits_signed(self) -> Self::SignedInt; + + /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be + /// represented in multiple different ways. This method returns `true` if two NaNs are + /// compared. + fn eq_repr(self, rhs: Self) -> bool; + + /// Returns true if the sign is negative + fn is_sign_negative(self) -> bool; + + /// Returns the exponent, not adjusting for bias. + fn exp(self) -> Self::ExpInt; + + /// Returns the significand with no implicit bit (or the "fractional" part) + fn frac(self) -> Self::Int; + + /// Returns the significand with implicit bit + fn imp_frac(self) -> Self::Int; + + /// Returns a `Self::Int` transmuted back to `Self` + fn from_bits(a: Self::Int) -> Self; + + /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self; + + fn abs(self) -> Self { + let abs_mask = !Self::SIGN_MASK; + Self::from_bits(self.to_bits() & abs_mask) + } + + /// Returns (normalized exponent, normalized significand) + fn normalize(significand: Self::Int) -> (i32, Self::Int); + + /// Returns if `self` is subnormal + fn is_subnormal(self) -> bool; +} + +macro_rules! float_impl { + ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { + impl Float for $ty { + type Int = $ity; + type SignedInt = $sity; + type ExpInt = $expty; + + const ZERO: Self = 0.0; + const ONE: Self = 1.0; + + const BITS: u32 = $bits; + const SIGNIFICAND_BITS: u32 = $significand_bits; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; + const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + + fn to_bits(self) -> Self::Int { + self.to_bits() + } + fn to_bits_signed(self) -> Self::SignedInt { + self.to_bits() as Self::SignedInt + } + fn eq_repr(self, rhs: Self) -> bool { + fn is_nan(x: $ty) -> bool { + // When using mangled-names, the "real" compiler-builtins might not have the + // necessary builtin (__unordtf2) to test whether `f128` is NaN. + // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin + // x is NaN if all the bits of the exponent are set and the significand is non-0 + x.to_bits() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK + && x.to_bits() & $ty::SIGNIFICAND_MASK != 0 + } + if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() } + } + fn is_sign_negative(self) -> bool { + self.is_sign_negative() + } + fn exp(self) -> Self::ExpInt { + ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt + } + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIGNIFICAND_MASK + } + fn imp_frac(self) -> Self::Int { + self.frac() | Self::IMPLICIT_BIT + } + fn from_bits(a: Self::Int) -> Self { + Self::from_bits(a) + } + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_bits( + ((negative as Self::Int) << (Self::BITS - 1)) + | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) + | (significand & Self::SIGNIFICAND_MASK), + ) + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand.leading_zeros().wrapping_sub(Self::EXPONENT_BITS); + (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) + } + fn is_subnormal(self) -> bool { + (self.to_bits() & Self::EXPONENT_MASK) == Self::Int::ZERO + } + } + }; +} + +float_impl!(f32, u32, i32, i16, 32, 23); +float_impl!(f64, u64, i64, i16, 64, 52); diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs new file mode 100644 index 00000000000..bdf3afd48ce --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -0,0 +1,343 @@ +use core::{fmt, ops}; + +/// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] +pub trait MinInt: + Copy + + fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type UnsignedInt: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} + +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub trait Int: + MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ + fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn unsigned(self) -> $uty { + self + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn abs_diff(self, other: Self) -> Self { + if self < other { other.wrapping_sub(self) } else { self.wrapping_sub(other) } + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn unsigned(self) -> $uty { + self as $uty + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn abs_diff(self, other: Self) -> $uty { + self.wrapping_sub(other).wrapping_abs() as $uty + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +/// Trait for integers twice the bit width of another integer. This is implemented for all +/// primitives except for `u8`, because there is not a smaller primitive. +#[allow(unused)] +pub trait DInt: MinInt { + /// Integer that is half the bit width of the integer this trait is implemented for + type H: HInt; + + /// Returns the low half of `self` + fn lo(self) -> Self::H; + /// Returns the high half of `self` + fn hi(self) -> Self::H; + /// Returns the low and high halves of `self` as a tuple + fn lo_hi(self) -> (Self::H, Self::H) { + (self.lo(), self.hi()) + } + /// Constructs an integer using lower and higher half parts + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { + lo.zero_widen() | hi.widen_hi() + } +} + +/// Trait for integers half the bit width of another integer. This is implemented for all +/// primitives except for `u128`, because it there is not a larger primitive. +#[allow(unused)] +pub trait HInt: Int { + /// Integer that is double the bit width of the integer this trait is implemented for + type D: DInt + MinInt; + + // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for + // unknown reasons this can cause infinite recursion when optimizations are disabled. See + // for context. + + /// Widens (using default extension) the integer to have double bit width + fn widen(self) -> Self::D; + /// Widens (zero extension only) the integer to have double bit width. This is needed to get + /// around problems with associated type bounds (such as `Int`) being unstable + fn zero_widen(self) -> Self::D; + /// Widens the integer to have double bit width and shifts the integer into the higher bits + fn widen_hi(self) -> Self::D; + /// Widening multiplication with zero widening. This cannot overflow. + fn zero_widen_mul(self, rhs: Self) -> Self::D; + /// Widening multiplication. This cannot overflow. + fn widen_mul(self, rhs: Self) -> Self::D; +} + +macro_rules! impl_d_int { + ($($X:ident $D:ident),*) => { + $( + impl DInt for $D { + type H = $X; + + fn lo(self) -> Self::H { + self as $X + } + fn hi(self) -> Self::H { + (self >> <$X as MinInt>::BITS) as $X + } + } + )* + }; +} + +macro_rules! impl_h_int { + ($($H:ident $uH:ident $X:ident),*) => { + $( + impl HInt for $H { + type D = $X; + + fn widen(self) -> Self::D { + self as $X + } + fn zero_widen(self) -> Self::D { + (self as $uH) as $X + } + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen().wrapping_mul(rhs.zero_widen()) + } + fn widen_mul(self, rhs: Self) -> Self::D { + self.widen().wrapping_mul(rhs.widen()) + } + fn widen_hi(self) -> Self::D { + (self as $X) << ::BITS + } + } + )* + }; +} + +impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); +impl_h_int!( + u8 u8 u16, + u16 u16 u32, + u32 u32 u64, + u64 u64 u128, + i8 u8 i16, + i16 u16 i32, + i32 u32 i64, + i64 u64 i128 +); + +/// Trait to express (possibly lossy) casting of integers +#[allow(unused)] +pub trait CastInto: Copy { + fn cast(self) -> T; +} + +#[allow(unused)] +pub trait CastFrom: Copy { + fn cast_from(value: T) -> Self; +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} + +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 10532f0d115..f054df6cdf3 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -1,2 +1,7 @@ #[macro_use] pub mod macros; +mod float_traits; +mod int_traits; + +pub use float_traits::Float; +pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -- cgit 1.4.1-3-g733a5 From 1dc50415cdf4ae22ef7001ae264be0fe4040c81a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 29 May 2024 02:56:59 -0500 Subject: Add an apfloat fallback for int to float tests --- library/compiler-builtins/testcrate/tests/conv.rs | 129 +++++++++++++--------- 1 file changed, 77 insertions(+), 52 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 24f3a04a4ee..6096803871b 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -12,60 +12,82 @@ mod int_to_float { use super::*; macro_rules! i_to_f { - ($($from:ty, $into:ty, $fn:ident);*;) => { + ($f_ty:ty, $apfloat_ty:ident, $sys_available:meta, $($i_ty:ty, $fn:ident);*;) => { $( #[test] fn $fn() { use compiler_builtins::float::conv::$fn; use compiler_builtins::int::Int; - fuzz(N, |x: $from| { - let f0 = x as $into; - let f1: $into = $fn(x); - // This makes sure that the conversion produced the best rounding possible, and does - // this independent of `x as $into` rounding correctly. - // This assumes that float to integer conversion is correct. - let y_minus_ulp = <$into>::from_bits(f1.to_bits().wrapping_sub(1)) as $from; - let y = f1 as $from; - let y_plus_ulp = <$into>::from_bits(f1.to_bits().wrapping_add(1)) as $from; - let error_minus = <$from as Int>::abs_diff(y_minus_ulp, x); - let error = <$from as Int>::abs_diff(y, x); - let error_plus = <$from as Int>::abs_diff(y_plus_ulp, x); - // The first two conditions check that none of the two closest float values are - // strictly closer in representation to `x`. The second makes sure that rounding is - // towards even significand if two float values are equally close to the integer. - if error_minus < error - || error_plus < error - || ((error_minus == error || error_plus == error) - && ((f0.to_bits() & 1) != 0)) - { - if !cfg!(any( - target_arch = "powerpc", - target_arch = "powerpc64" - )) { - panic!( - "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", - stringify!($fn), - x, - f1.to_bits(), - y_minus_ulp, - y, - y_plus_ulp, - error_minus, - error, - error_plus, - ); + fuzz(N, |x: $i_ty| { + let f0 = apfloat_fallback!( + $f_ty, $apfloat_ty, $sys_available, + |x| x as $f_ty; + // When the builtin is not available, we need to use a different conversion + // method (since apfloat doesn't support `as` casting). + |x: $i_ty| { + use compiler_builtins::int::MinInt; + + let apf = if <$i_ty>::SIGNED { + FloatTy::from_i128(x.try_into().unwrap()).value + } else { + FloatTy::from_u128(x.try_into().unwrap()).value + }; + + <$f_ty>::from_bits(apf.to_bits()) + }, + x + ); + let f1: $f_ty = $fn(x); + + #[cfg($sys_available)] { + // This makes sure that the conversion produced the best rounding possible, and does + // this independent of `x as $into` rounding correctly. + // This assumes that float to integer conversion is correct. + let y_minus_ulp = <$f_ty>::from_bits(f1.to_bits().wrapping_sub(1)) as $i_ty; + let y = f1 as $i_ty; + let y_plus_ulp = <$f_ty>::from_bits(f1.to_bits().wrapping_add(1)) as $i_ty; + let error_minus = <$i_ty as Int>::abs_diff(y_minus_ulp, x); + let error = <$i_ty as Int>::abs_diff(y, x); + let error_plus = <$i_ty as Int>::abs_diff(y_plus_ulp, x); + + // The first two conditions check that none of the two closest float values are + // strictly closer in representation to `x`. The second makes sure that rounding is + // towards even significand if two float values are equally close to the integer. + if error_minus < error + || error_plus < error + || ((error_minus == error || error_plus == error) + && ((f0.to_bits() & 1) != 0)) + { + if !cfg!(any( + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + panic!( + "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", + stringify!($fn), + x, + f1.to_bits(), + y_minus_ulp, + y, + y_plus_ulp, + error_minus, + error, + error_plus, + ); + } } } + // Test against native conversion. We disable testing on all `x86` because of // rounding bugs with `i686`. `powerpc` also has the same rounding bug. - if f0 != f1 && !cfg!(any( + if !Float::eq_repr(f0, f1) && !cfg!(any( target_arch = "x86", target_arch = "powerpc", target_arch = "powerpc64" )) { panic!( - "{}({}): std: {}, builtins: {}", + "{}({}): std: {:?}, builtins: {:?}", stringify!($fn), x, f0, @@ -78,19 +100,22 @@ mod int_to_float { }; } - i_to_f! { - u32, f32, __floatunsisf; - u32, f64, __floatunsidf; - i32, f32, __floatsisf; - i32, f64, __floatsidf; - u64, f32, __floatundisf; - u64, f64, __floatundidf; - i64, f32, __floatdisf; - i64, f64, __floatdidf; - u128, f32, __floatuntisf; - u128, f64, __floatuntidf; - i128, f32, __floattisf; - i128, f64, __floattidf; + i_to_f! { f32, Single, all(), + u32, __floatunsisf; + i32, __floatsisf; + u64, __floatundisf; + i64, __floatdisf; + u128, __floatuntisf; + i128, __floattisf; + } + + i_to_f! { f64, Double, all(), + u32, __floatunsidf; + i32, __floatsidf; + u64, __floatundidf; + i64, __floatdidf; + u128, __floatuntidf; + i128, __floattidf; } } -- cgit 1.4.1-3-g733a5 From 51dd4da05328da2f2e658b815046d9845a0214c5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 13 Jun 2024 06:50:44 -0500 Subject: Refactor integer to float conversion Extract some common routines to separate functions in order to deduplicate code and remove some of the magic. --- library/compiler-builtins/src/float/conv.rs | 174 ++++++++++++++++------ library/compiler-builtins/src/int/mod.rs | 10 +- library/compiler-builtins/testcrate/tests/conv.rs | 2 +- 3 files changed, 138 insertions(+), 48 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index e86fee6dc5f..da87b3caef8 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -6,21 +6,91 @@ use super::Float; /// Conversions from integers to floats. /// -/// These are hand-optimized bit twiddling code, -/// which unfortunately isn't the easiest kind of code to read. +/// The algorithm is explained here: . It roughly does the following: +/// - Calculate a base mantissa by shifting the integer into mantissa position. This gives us a +/// mantissa _with the implicit bit set_! +/// - Figure out if rounding needs to occur by classifying the bits that are to be truncated. Some +/// patterns are used to simplify this. Adjust the mantissa with the result if needed. +/// - Calculate the exponent based on the base-2 logarithm of `i` (leading zeros). Subtract one. +/// - Shift the exponent and add the mantissa to create the final representation. Subtracting one +/// from the exponent (above) accounts for the explicit bit being set in the mantissa. /// -/// The algorithm is explained here: +/// # Terminology +/// +/// - `i`: the original integer +/// - `i_m`: the integer, shifted fully left (no leading zeros) +/// - `n`: number of leading zeroes +/// - `e`: the resulting exponent. Usually 1 is subtracted to offset the mantissa implicit bit. +/// - `m_base`: the mantissa before adjusting for truncated bits. Implicit bit is usually set. +/// - `adj`: the bits that will be truncated, possibly compressed in some way. +/// - `m`: the resulting mantissa. Implicit bit is usually set. mod int_to_float { + use super::*; + + /// Calculate the exponent from the number of leading zeros. + /// + /// Usually 1 is subtracted from this function's result, so that a mantissa with the implicit + /// bit set can be added back later. + fn exp>>(n: u32) -> F::Int { + F::Int::cast_from(F::EXPONENT_BIAS - 1 + I::BITS - n) + } + + /// Adjust a mantissa with dropped bits to perform correct rounding. + /// + /// The dropped bits should be exactly the bits that get truncated (left-aligned), but they + /// can be combined or compressed in some way that simplifies operations. + fn m_adj(m_base: F::Int, dropped_bits: F::Int) -> F::Int { + // Branchlessly extract a `1` if rounding up should happen, 0 otherwise + // This accounts for rounding to even. + let adj = (dropped_bits - (dropped_bits >> (F::BITS - 1) & !m_base)) >> (F::BITS - 1); + + // Add one when we need to round up. Break ties to even. + m_base + adj + } + + /// Shift the exponent to its position and add the mantissa. + /// + /// If the mantissa has the implicit bit set, the exponent should be one less than its actual + /// value to cancel it out. + fn repr(e: F::Int, m: F::Int) -> F::Int { + // + rather than | so the mantissa can overflow into the exponent + (e << F::SIGNIFICAND_BITS) + m + } + + /// Shift distance from a left-aligned integer to a smaller float. + fn shift_f_lt_i() -> u32 { + (I::BITS - F::BITS) + F::EXPONENT_BITS + } + + /// Shift distance from an integer with `n` leading zeros to a smaller float. + fn shift_f_gt_i(n: u32) -> u32 { + F::SIGNIFICAND_BITS - I::BITS + 1 + n + } + + /// Perform a signed operation as unsigned, then add the sign back. + pub fn signed(i: I, conv: Conv) -> F + where + F: Float, + I: Int, + F::Int: CastFrom, + Conv: Fn(I::UnsignedInt) -> F::Int, + { + let sign_bit = F::Int::cast_from(i >> (I::BITS - 1)) << (F::BITS - 1); + F::from_bits(conv(i.unsigned_abs()) | sign_bit) + } + pub fn u32_to_f32_bits(i: u32) -> u32 { if i == 0 { return 0; } let n = i.leading_zeros(); - let a = (i << n) >> 8; // Significant bits, with bit 24 still in tact. - let b = (i << n) << 24; // Insignificant bits, only relevant for rounding. - let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. - let e = 157 - n; // Exponent plus 127, minus one. - (e << 23) + m // + not |, so the mantissa can overflow into the exponent. + // Mantissa with implicit bit set (significant bits) + let m_base = (i << n) >> f32::EXPONENT_BITS; + // Bits that will be dropped (insignificant bits) + let adj = (i << n) << (f32::SIGNIFICAND_BITS + 1); + let m = m_adj::(m_base, adj); + let e = exp::(n) - 1; + repr::(e, m) } pub fn u32_to_f64_bits(i: u32) -> u64 { @@ -28,19 +98,23 @@ mod int_to_float { return 0; } let n = i.leading_zeros(); - let m = (i as u64) << (21 + n); // Significant bits, with bit 53 still in tact. - let e = 1053 - n as u64; // Exponent plus 1023, minus one. - (e << 52) + m // Bit 53 of m will overflow into e. + // Mantissa with implicit bit set + let m = (i as u64) << shift_f_gt_i::(n); + let e = exp::(n) - 1; + repr::(e, m) } pub fn u64_to_f32_bits(i: u64) -> u32 { let n = i.leading_zeros(); - let y = i.wrapping_shl(n); - let a = (y >> 40) as u32; // Significant bits, with bit 24 still in tact. - let b = (y >> 8 | y & 0xFFFF) as u32; // Insignificant bits, only relevant for rounding. - let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. - let e = if i == 0 { 0 } else { 189 - n }; // Exponent plus 127, minus one, except for zero. - (e << 23) + m // + not |, so the mantissa can overflow into the exponent. + let i_m = i.wrapping_shl(n); + // Mantissa with implicit bit set + let m_base: u32 = (i_m >> shift_f_lt_i::()) as u32; + // The entire lower half of `i` will be truncated (masked portion), plus the + // next `EXPONENT_BITS` bits. + let adj = (i_m >> f32::EXPONENT_BITS | i_m & 0xFFFF) as u32; + let m = m_adj::(m_base, adj); + let e = if i == 0 { 0 } else { exp::(n) - 1 }; + repr::(e, m) } pub fn u64_to_f64_bits(i: u64) -> u64 { @@ -48,31 +122,45 @@ mod int_to_float { return 0; } let n = i.leading_zeros(); - let a = (i << n) >> 11; // Significant bits, with bit 53 still in tact. - let b = (i << n) << 53; // Insignificant bits, only relevant for rounding. - let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even. - let e = 1085 - n as u64; // Exponent plus 1023, minus one. - (e << 52) + m // + not |, so the mantissa can overflow into the exponent. + // Mantissa with implicit bit set + let m_base = (i << n) >> f64::EXPONENT_BITS; + let adj = (i << n) << (f64::SIGNIFICAND_BITS + 1); + let m = m_adj::(m_base, adj); + let e = exp::(n) - 1; + repr::(e, m) } pub fn u128_to_f32_bits(i: u128) -> u32 { let n = i.leading_zeros(); - let y = i.wrapping_shl(n); - let a = (y >> 104) as u32; // Significant bits, with bit 24 still in tact. - let b = (y >> 72) as u32 | ((y << 32) >> 32 != 0) as u32; // Insignificant bits, only relevant for rounding. - let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. - let e = if i == 0 { 0 } else { 253 - n }; // Exponent plus 127, minus one, except for zero. - (e << 23) + m // + not |, so the mantissa can overflow into the exponent. + let i_m = i.wrapping_shl(n); // Mantissa, shifted so the first bit is nonzero + let m_base: u32 = (i_m >> shift_f_lt_i::()) as u32; + + // Within the upper `F::BITS`, everything except for the signifcand + // gets truncated + let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIGNIFICAND_BITS - 1)).cast(); + + // The entire rest of `i_m` gets truncated. Zero the upper `F::BITS` then just + // check if it is nonzero. + let d2: u32 = (i_m << f32::BITS >> f32::BITS != 0).into(); + let adj = d1 | d2; + + // Mantissa with implicit bit set + let m = m_adj::(m_base, adj); + let e = if i == 0 { 0 } else { exp::(n) - 1 }; + repr::(e, m) } pub fn u128_to_f64_bits(i: u128) -> u64 { let n = i.leading_zeros(); - let y = i.wrapping_shl(n); - let a = (y >> 75) as u64; // Significant bits, with bit 53 still in tact. - let b = (y >> 11 | y & 0xFFFF_FFFF) as u64; // Insignificant bits, only relevant for rounding. - let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even. - let e = if i == 0 { 0 } else { 1149 - n as u64 }; // Exponent plus 1023, minus one, except for zero. - (e << 52) + m // + not |, so the mantissa can overflow into the exponent. + let i_m = i.wrapping_shl(n); + // Mantissa with implicit bit set + let m_base: u64 = (i_m >> shift_f_lt_i::()) as u64; + // The entire lower half of `i` will be truncated (masked portion), plus the + // next `EXPONENT_BITS` bits. + let adj = (i_m >> f64::EXPONENT_BITS | i_m & 0xFFFF_FFFF) as u64; + let m = m_adj::(m_base, adj); + let e = if i == 0 { 0 } else { exp::(n) - 1 }; + repr::(e, m) } } @@ -113,38 +201,32 @@ intrinsics! { intrinsics! { #[arm_aeabi_alias = __aeabi_i2f] pub extern "C" fn __floatsisf(i: i32) -> f32 { - let sign_bit = ((i >> 31) as u32) << 31; - f32::from_bits(int_to_float::u32_to_f32_bits(i.unsigned_abs()) | sign_bit) + int_to_float::signed(i, int_to_float::u32_to_f32_bits) } #[arm_aeabi_alias = __aeabi_i2d] pub extern "C" fn __floatsidf(i: i32) -> f64 { - let sign_bit = ((i >> 31) as u64) << 63; - f64::from_bits(int_to_float::u32_to_f64_bits(i.unsigned_abs()) | sign_bit) + int_to_float::signed(i, int_to_float::u32_to_f64_bits) } #[arm_aeabi_alias = __aeabi_l2f] pub extern "C" fn __floatdisf(i: i64) -> f32 { - let sign_bit = ((i >> 63) as u32) << 31; - f32::from_bits(int_to_float::u64_to_f32_bits(i.unsigned_abs()) | sign_bit) + int_to_float::signed(i, int_to_float::u64_to_f32_bits) } #[arm_aeabi_alias = __aeabi_l2d] pub extern "C" fn __floatdidf(i: i64) -> f64 { - let sign_bit = ((i >> 63) as u64) << 63; - f64::from_bits(int_to_float::u64_to_f64_bits(i.unsigned_abs()) | sign_bit) + int_to_float::signed(i, int_to_float::u64_to_f64_bits) } #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] pub extern "C" fn __floattisf(i: i128) -> f32 { - let sign_bit = ((i >> 127) as u32) << 31; - f32::from_bits(int_to_float::u128_to_f32_bits(i.unsigned_abs()) | sign_bit) + int_to_float::signed(i, int_to_float::u128_to_f32_bits) } #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] pub extern "C" fn __floattidf(i: i128) -> f64 { - let sign_bit = ((i >> 127) as u64) << 63; - f64::from_bits(int_to_float::u128_to_f64_bits(i.unsigned_abs()) | sign_bit) + int_to_float::signed(i, int_to_float::u128_to_f64_bits) } } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index e6f31c53013..0d3b0ce4048 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -83,6 +83,7 @@ pub(crate) trait Int: MinInt fn unsigned(self) -> Self::UnsignedInt; fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + fn unsigned_abs(self) -> Self::UnsignedInt; fn from_bool(b: bool) -> Self; @@ -178,7 +179,6 @@ macro_rules! int_impl_common { fn wrapping_mul(self, other: Self) -> Self { ::wrapping_mul(self, other) } - fn wrapping_sub(self, other: Self) -> Self { ::wrapping_sub(self, other) } @@ -235,6 +235,10 @@ macro_rules! int_impl { me } + fn unsigned_abs(self) -> Self { + self + } + fn abs_diff(self, other: Self) -> Self { if self < other { other.wrapping_sub(self) @@ -268,6 +272,10 @@ macro_rules! int_impl { me as $ity } + fn unsigned_abs(self) -> Self::UnsignedInt { + self.unsigned_abs() + } + fn abs_diff(self, other: Self) -> $uty { self.wrapping_sub(other).wrapping_abs() as $uty } diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 6096803871b..01cc588cf3c 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -8,7 +8,7 @@ use compiler_builtins::float::Float; use rustc_apfloat::{Float as _, FloatConvert as _}; use testcrate::*; -mod int_to_float { +mod i_to_f { use super::*; macro_rules! i_to_f { -- cgit 1.4.1-3-g733a5 From fbd690735826fd4b3b3f9862820944b23ae9000e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 13 Jun 2024 06:52:46 -0500 Subject: Add integer to `f128` conversions --- library/compiler-builtins/README.md | 12 +- library/compiler-builtins/build.rs | 18 +- library/compiler-builtins/examples/intrinsics.rs | 62 +++++- library/compiler-builtins/src/float/conv.rs | 80 ++++++++ .../testcrate/benches/float_conv.rs | 222 +++++++++++++++++---- library/compiler-builtins/testcrate/tests/conv.rs | 22 ++ 6 files changed, 348 insertions(+), 68 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index f792d188324..a2b38cce0ef 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -233,12 +233,12 @@ of being added to Rust. - [x] fixunstfdi.c - [x] fixunstfsi.c - [x] fixunstfti.c -- [ ] floatditf.c -- [ ] floatsitf.c -- [ ] floattitf.c -- [ ] floatunditf.c -- [ ] floatunsitf.c -- [ ] floatuntitf.c +- [x] floatditf.c +- [x] floatsitf.c +- [x] floattitf.c +- [x] floatunditf.c +- [x] floatunsitf.c +- [x] floatuntitf.c - [x] multf3.c - [x] powitf2.c - [x] subtf3.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2863c979fa3..22ec9e4d275 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -532,10 +532,6 @@ mod c { if (target.arch == "aarch64" || target.arch == "arm64ec") && consider_float_intrinsics { sources.extend(&[ ("__comparetf2", "comparetf2.c"), - ("__floatditf", "floatditf.c"), - ("__floatsitf", "floatsitf.c"), - ("__floatunditf", "floatunditf.c"), - ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), ("__fe_raise_inexact", "fp_mode.c"), ]); @@ -550,21 +546,11 @@ mod c { } if target.arch == "mips64" { - sources.extend(&[ - ("__netf2", "comparetf2.c"), - ("__floatsitf", "floatsitf.c"), - ("__floatunsitf", "floatunsitf.c"), - ("__fe_getround", "fp_mode.c"), - ]); + sources.extend(&[("__netf2", "comparetf2.c"), ("__fe_getround", "fp_mode.c")]); } if target.arch == "loongarch64" { - sources.extend(&[ - ("__netf2", "comparetf2.c"), - ("__floatsitf", "floatsitf.c"), - ("__floatunsitf", "floatunsitf.c"), - ("__fe_getround", "fp_mode.c"), - ]); + sources.extend(&[("__netf2", "comparetf2.c"), ("__fe_getround", "fp_mode.c")]); } // Remove the assembly implementations that won't compile for the target diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 06d77233027..368da6af2e4 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -264,14 +264,18 @@ mod intrinsics { /* i32 operations */ + // floatsisf + pub fn aeabi_i2f(x: i32) -> f32 { + x as f32 + } + // floatsidf pub fn aeabi_i2d(x: i32) -> f64 { x as f64 } - // floatsisf - pub fn aeabi_i2f(x: i32) -> f32 { - x as f32 + pub fn floatsitf(x: i32) -> f128 { + x as f128 } pub fn aeabi_idiv(a: i32, b: i32) -> i32 { @@ -294,6 +298,10 @@ mod intrinsics { x as f64 } + pub fn floatditf(x: i64) -> f128 { + x as f128 + } + pub fn mulodi4(a: i64, b: i64) -> i64 { a * b } @@ -314,6 +322,18 @@ mod intrinsics { /* i128 operations */ + pub fn floattisf(x: i128) -> f32 { + x as f32 + } + + pub fn floattidf(x: i128) -> f64 { + x as f64 + } + + pub fn floattitf(x: i128) -> f128 { + x as f128 + } + pub fn lshrti3(a: i128, b: usize) -> i128 { a >> b } @@ -328,14 +348,18 @@ mod intrinsics { /* u32 operations */ + // floatunsisf + pub fn aeabi_ui2f(x: u32) -> f32 { + x as f32 + } + // floatunsidf pub fn aeabi_ui2d(x: u32) -> f64 { x as f64 } - // floatunsisf - pub fn aeabi_ui2f(x: u32) -> f32 { - x as f32 + pub fn floatunsitf(x: u32) -> f128 { + x as f128 } pub fn aeabi_uidiv(a: u32, b: u32) -> u32 { @@ -358,6 +382,10 @@ mod intrinsics { x as f64 } + pub fn floatunditf(x: u64) -> f128 { + x as f128 + } + // udivdi3 pub fn aeabi_uldivmod(a: u64, b: u64) -> u64 { a * b @@ -369,6 +397,18 @@ mod intrinsics { /* u128 operations */ + pub fn floatuntisf(x: u128) -> f32 { + x as f32 + } + + pub fn floatuntidf(x: u128) -> f64 { + x as f64 + } + + pub fn floatuntitf(x: u128) -> f128 { + x as f128 + } + pub fn muloti4(a: u128, b: u128) -> Option { a.checked_mul(b) } @@ -466,6 +506,16 @@ fn run() { bb(fixunstfsi(bb(2.))); #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] bb(fixunstfti(bb(2.))); + bb(floatditf(bb(2))); + bb(floatsitf(bb(2))); + bb(floattidf(bb(2))); + bb(floattisf(bb(2))); + bb(floattitf(bb(2))); + bb(floatunditf(bb(2))); + bb(floatunsitf(bb(2))); + bb(floatuntidf(bb(2))); + bb(floatuntisf(bb(2))); + bb(floatuntitf(bb(2))); bb(gttf(bb(2.), bb(2.))); bb(lshrti3(bb(2), bb(2))); bb(lttf(bb(2.), bb(2.))); diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index da87b3caef8..4aea67c9152 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -104,6 +104,24 @@ mod int_to_float { repr::(e, m) } + #[cfg(f128_enabled)] + pub fn u32_to_f128_bits(i: u32) -> u128 { + if i == 0 { + return 0; + } + let n = i.leading_zeros(); + + // Shift into mantissa position that is correct for the type, but shifted into the lower + // 64 bits over so can can avoid 128-bit math. + let m = (i as u64) << (shift_f_gt_i::(n) - 64); + let e = exp::(n) as u64 - 1; + // High 64 bits of f128 representation. + let h = (e << (f128::SIGNIFICAND_BITS - 64)) + m; + + // Shift back to the high bits, the rest of the mantissa will always be 0. + (h as u128) << 64 + } + pub fn u64_to_f32_bits(i: u64) -> u32 { let n = i.leading_zeros(); let i_m = i.wrapping_shl(n); @@ -130,6 +148,18 @@ mod int_to_float { repr::(e, m) } + #[cfg(f128_enabled)] + pub fn u64_to_f128_bits(i: u64) -> u128 { + if i == 0 { + return 0; + } + let n = i.leading_zeros(); + // Mantissa with implicit bit set + let m = (i as u128) << shift_f_gt_i::(n); + let e = exp::(n) - 1; + repr::(e, m) + } + pub fn u128_to_f32_bits(i: u128) -> u32 { let n = i.leading_zeros(); let i_m = i.wrapping_shl(n); // Mantissa, shifted so the first bit is nonzero @@ -162,6 +192,20 @@ mod int_to_float { let e = if i == 0 { 0 } else { exp::(n) - 1 }; repr::(e, m) } + + #[cfg(f128_enabled)] + pub fn u128_to_f128_bits(i: u128) -> u128 { + if i == 0 { + return 0; + } + let n = i.leading_zeros(); + // Mantissa with implicit bit set + let m_base = (i << n) >> f128::EXPONENT_BITS; + let adj = (i << n) << (f128::SIGNIFICAND_BITS + 1); + let m = m_adj::(m_base, adj); + let e = exp::(n) - 1; + repr::(e, m) + } } // Conversions from unsigned integers to floats. @@ -195,6 +239,24 @@ intrinsics! { pub extern "C" fn __floatuntidf(i: u128) -> f64 { f64::from_bits(int_to_float::u128_to_f64_bits(i)) } + + #[ppc_alias = __floatunsikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatunsitf(i: u32) -> f128 { + f128::from_bits(int_to_float::u32_to_f128_bits(i)) + } + + #[ppc_alias = __floatundikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatunditf(i: u64) -> f128 { + f128::from_bits(int_to_float::u64_to_f128_bits(i)) + } + + #[ppc_alias = __floatuntikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatuntitf(i: u128) -> f128 { + f128::from_bits(int_to_float::u128_to_f128_bits(i)) + } } // Conversions from signed integers to floats. @@ -228,6 +290,24 @@ intrinsics! { pub extern "C" fn __floattidf(i: i128) -> f64 { int_to_float::signed(i, int_to_float::u128_to_f64_bits) } + + #[ppc_alias = __floatsikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatsitf(i: i32) -> f128 { + int_to_float::signed(i, int_to_float::u32_to_f128_bits) + } + + #[ppc_alias = __floatdikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatditf(i: i64) -> f128 { + int_to_float::signed(i, int_to_float::u64_to_f128_bits) + } + + #[ppc_alias = __floattikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floattitf(i: i128) -> f128 { + int_to_float::signed(i, int_to_float::u128_to_f128_bits) + } } /// Generic float to unsigned int conversions. diff --git a/library/compiler-builtins/testcrate/benches/float_conv.rs b/library/compiler-builtins/testcrate/benches/float_conv.rs index de2043b04f8..0625a1ae5dd 100644 --- a/library/compiler-builtins/testcrate/benches/float_conv.rs +++ b/library/compiler-builtins/testcrate/benches/float_conv.rs @@ -1,7 +1,8 @@ #![allow(improper_ctypes)] +#![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::conv; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; /* unsigned int -> float */ @@ -76,6 +77,18 @@ float_bench! { ], } +#[cfg(f128_enabled)] +float_bench! { + name: conv_u32_f128, + sig: (a: u32) -> f128, + crate_fn: conv::__floatunsitf, + crate_fn_ppc: conv::__floatunsikf, + sys_fn: __floatunsitf, + sys_fn_ppc: __floatunsikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + float_bench! { name: conv_u64_f32, sig: (a: u64) -> f32, @@ -118,6 +131,18 @@ float_bench! { ], } +#[cfg(f128_enabled)] +float_bench! { + name: conv_u64_f128, + sig: (a: u64) -> f128, + crate_fn: conv::__floatunditf, + crate_fn_ppc: conv::__floatundikf, + sys_fn: __floatunditf, + sys_fn_ppc: __floatundikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + float_bench! { name: conv_u128_f32, sig: (a: u128) -> f32, @@ -136,6 +161,18 @@ float_bench! { asm: [] } +#[cfg(f128_enabled)] +float_bench! { + name: conv_u128_f128, + sig: (a: u128) -> f128, + crate_fn: conv::__floatuntitf, + crate_fn_ppc: conv::__floatuntikf, + sys_fn: __floatuntitf, + sys_fn_ppc: __floatuntikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + /* signed int -> float */ float_bench! { @@ -205,6 +242,18 @@ float_bench! { ], } +#[cfg(f128_enabled)] +float_bench! { + name: conv_i32_f128, + sig: (a: i32) -> f128, + crate_fn: conv::__floatsitf, + crate_fn_ppc: conv::__floatsikf, + sys_fn: __floatsitf, + sys_fn_ppc: __floatsikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + float_bench! { name: conv_i64_f32, sig: (a: i64) -> f32, @@ -272,6 +321,18 @@ float_bench! { ], } +#[cfg(f128_enabled)] +float_bench! { + name: conv_i64_f128, + sig: (a: i64) -> f128, + crate_fn: conv::__floatditf, + crate_fn_ppc: conv::__floatdikf, + sys_fn: __floatditf, + sys_fn_ppc: __floatdikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + float_bench! { name: conv_i128_f32, sig: (a: i128) -> f32, @@ -290,6 +351,18 @@ float_bench! { asm: [] } +#[cfg(f128_enabled)] +float_bench! { + name: conv_i128_f128, + sig: (a: i128) -> f128, + crate_fn: conv::__floattitf, + crate_fn_ppc: conv::__floattikf, + sys_fn: __floattitf, + sys_fn_ppc: __floattikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + /* float -> unsigned int */ #[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] @@ -397,6 +470,39 @@ float_bench! { asm: [] } +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_u32, + sig: (a: f128) -> u32, + crate_fn: conv::__fixunstfsi, + crate_fn_ppc: conv::__fixunskfsi, + sys_fn: __fixunstfsi, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_u64, + sig: (a: f128) -> u64, + crate_fn: conv::__fixunstfdi, + crate_fn_ppc: conv::__fixunskfdi, + sys_fn: __fixunstfdi, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_u128, + sig: (a: f128) -> u128, + crate_fn: conv::__fixunstfti, + crate_fn_ppc: conv::__fixunskfti, + sys_fn: __fixunstfti, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + /* float -> signed int */ #[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] @@ -504,43 +610,79 @@ float_bench! { asm: [] } -criterion_group!( - float_conv, - conv_u32_f32, - conv_u32_f64, - conv_u64_f32, - conv_u64_f64, - conv_u128_f32, - conv_u128_f64, - conv_i32_f32, - conv_i32_f64, - conv_i64_f32, - conv_i64_f64, - conv_i128_f32, - conv_i128_f64, - conv_f64_u32, - conv_f64_u64, - conv_f64_u128, - conv_f64_i32, - conv_f64_i64, - conv_f64_i128, -); - -// FIXME: ppc64le has a sporadic overflow panic in the crate functions -// -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] -criterion_group!( - float_conv_not_ppc64le, - conv_f32_u32, - conv_f32_u64, - conv_f32_u128, - conv_f32_i32, - conv_f32_i64, - conv_f32_i128, -); - -#[cfg(all(target_arch = "powerpc64", target_endian = "little"))] -criterion_main!(float_conv); +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_i32, + sig: (a: f128) -> i32, + crate_fn: conv::__fixtfsi, + crate_fn_ppc: conv::__fixkfsi, + sys_fn: __fixtfsi, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] -criterion_main!(float_conv, float_conv_not_ppc64le); +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_i64, + sig: (a: f128) -> i64, + crate_fn: conv::__fixtfdi, + crate_fn_ppc: conv::__fixkfdi, + sys_fn: __fixtfdi, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_i128, + sig: (a: f128) -> i128, + crate_fn: conv::__fixtfti, + crate_fn_ppc: conv::__fixkfti, + sys_fn: __fixtfti, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +pub fn float_conv() { + let mut criterion = Criterion::default().configure_from_args(); + + conv_u32_f32(&mut criterion); + conv_u32_f64(&mut criterion); + conv_u64_f32(&mut criterion); + conv_u64_f64(&mut criterion); + conv_u128_f32(&mut criterion); + conv_u128_f64(&mut criterion); + conv_i32_f32(&mut criterion); + conv_i32_f64(&mut criterion); + conv_i64_f32(&mut criterion); + conv_i64_f64(&mut criterion); + conv_i128_f32(&mut criterion); + conv_i128_f64(&mut criterion); + conv_f64_u32(&mut criterion); + conv_f64_u64(&mut criterion); + conv_f64_u128(&mut criterion); + conv_f64_i32(&mut criterion); + conv_f64_i64(&mut criterion); + conv_f64_i128(&mut criterion); + + #[cfg(all(f128_enabled))] + // FIXME: ppc64le has a sporadic overflow panic in the crate functions + // + #[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] + { + conv_u32_f128(&mut criterion); + conv_u64_f128(&mut criterion); + conv_u128_f128(&mut criterion); + conv_i32_f128(&mut criterion); + conv_i64_f128(&mut criterion); + conv_i128_f128(&mut criterion); + conv_f128_u32(&mut criterion); + conv_f128_u64(&mut criterion); + conv_f128_u128(&mut criterion); + conv_f128_i32(&mut criterion); + conv_f128_i64(&mut criterion); + conv_f128_i128(&mut criterion); + } +} + +criterion_main!(float_conv); diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 01cc588cf3c..a08748af781 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -117,6 +117,28 @@ mod i_to_f { u128, __floatuntidf; i128, __floattidf; } + + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + i_to_f! { f128, Quad, not(feature = "no-sys-f128-int-convert"), + u32, __floatunsitf; + i32, __floatsitf; + u64, __floatunditf; + i64, __floatditf; + u128, __floatuntitf; + i128, __floattitf; + } + + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + i_to_f! { f128, Quad, not(feature = "no-sys-f128-int-convert"), + u32, __floatunsikf; + i32, __floatsikf; + u64, __floatundikf; + i64, __floatdikf; + u128, __floatuntikf; + i128, __floattikf; + } } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -- cgit 1.4.1-3-g733a5 From 9818afad7c5952cbfbb80a064055ca8e1860dfbb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 30 Oct 2024 12:27:59 -0500 Subject: Remove the unneeded `isqrt` feature gate [1] has been stabilized so we no longer need to enable it. [1]: https://github.com/rust-lang/rust/issues/116226 --- library/compiler-builtins/testcrate/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 58419bf1bd0..4154e0fb34f 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -15,7 +15,6 @@ #![no_std] #![cfg_attr(f128_enabled, feature(f128))] #![cfg_attr(f16_enabled, feature(f16))] -#![feature(isqrt)] pub mod bench; extern crate alloc; -- cgit 1.4.1-3-g733a5 From 55236070450c7be6a8c20c3f880472e57632fc81 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 30 Oct 2024 13:45:53 -0500 Subject: Rename `canonical_name` to `base_name` "Canonical" isn't really the right word here, update to "base". --- .../libm/crates/libm-test/src/gen/random.rs | 3 +- .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/precision.rs | 32 +++++++++++----------- .../libm/crates/libm-test/src/test_traits.rs | 8 +++--- .../libm/src/math/support/macros.rs | 8 +++--- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index c73937aacc9..d03d1ff797f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -110,6 +110,7 @@ pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator, { - let inputs = if ctx.fname == "jn" || ctx.fname == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; + let inputs = + if ctx.fn_name == "jn" || ctx.fn_name == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; inputs.get_cases() } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 31b95e46c06..6c7a3f5ece2 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -18,7 +18,7 @@ include!(concat!(env!("OUT_DIR"), "/all_files.rs")); /// Return the unsuffixed version of a function name; e.g. `abs` and `absf` both return `abs`, /// `lgamma_r` and `lgammaf_r` both return `lgamma_r`. -pub fn canonical_name(name: &str) -> &str { +pub fn base_name(name: &str) -> &str { let known_mappings = &[ ("erff", "erf"), ("erf", "erf"), diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index e2ad638c412..9ef0e818d13 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -111,25 +111,25 @@ impl MaybeOverride<(f32,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if ctx.fname == "expm1f" && input.0 > 80.0 && actual.is_infinite() { + if ctx.fn_name == "expm1f" && input.0 > 80.0 && actual.is_infinite() { // we return infinity but the number is representable return XFAIL; } - if ctx.fname == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { + if ctx.fn_name == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { // we return some NaN that should be real values or infinite // doesn't seem to happen on x86 return XFAIL; } } - if ctx.fname == "acoshf" && input.0 < -1.0 { + if ctx.fn_name == "acoshf" && input.0 < -1.0 { // acoshf is undefined for x <= 1.0, but we return a random result at lower // values. return XFAIL; } - if ctx.fname == "lgammaf" || ctx.fname == "lgammaf_r" && input.0 < 0.0 { + if ctx.fn_name == "lgammaf" || ctx.fn_name == "lgammaf_r" && input.0 < 0.0 { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -146,7 +146,7 @@ impl MaybeOverride<(f32,)> for SpecialCase { // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fname == "lgammaf_r" + && ctx.fn_name == "lgammaf_r" && input.0 == f32::NEG_INFINITY && actual.abs() == expected.abs() { @@ -166,13 +166,13 @@ impl MaybeOverride<(f64,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if cfg!(target_arch = "x86") && ctx.fname == "acosh" && input.0 < 1.0 { + if cfg!(target_arch = "x86") && ctx.fn_name == "acosh" && input.0 < 1.0 { // The function is undefined, both implementations return random results return SKIP; } if cfg!(x86_no_sse) - && ctx.fname == "ceil" + && ctx.fn_name == "ceil" && input.0 < 0.0 && input.0 > -1.0 && expected == F::ZERO @@ -183,13 +183,13 @@ impl MaybeOverride<(f64,)> for SpecialCase { } } - if ctx.fname == "acosh" && input.0 < 1.0 { + if ctx.fn_name == "acosh" && input.0 < 1.0 { // The function is undefined for the inputs, musl and our libm both return // random results. return XFAIL; } - if ctx.fname == "lgamma" || ctx.fname == "lgamma_r" && input.0 < 0.0 { + if ctx.fn_name == "lgamma" || ctx.fn_name == "lgamma_r" && input.0 < 0.0 { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -206,7 +206,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fname == "lgamma_r" + && ctx.fn_name == "lgamma_r" && input.0 == f64::NEG_INFINITY && actual.abs() == expected.abs() { @@ -219,7 +219,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { /// Check NaN bits if the function requires it fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { - if !(ctx.canonical_name == "fabs" || ctx.canonical_name == "copysign") { + if !(ctx.base_name == "fabs" || ctx.base_name == "copysign") { return None; } @@ -277,7 +277,7 @@ fn maybe_skip_binop_nan( ) -> Option { match ctx.basis { CheckBasis::Musl => { - if (ctx.canonical_name == "fmax" || ctx.canonical_name == "fmin") + if (ctx.base_name == "fmax" || ctx.base_name == "fmin") && (input.0.is_nan() || input.1.is_nan()) && expected.is_nan() { @@ -287,7 +287,7 @@ fn maybe_skip_binop_nan( } } CheckBasis::Mpfr => { - if ctx.canonical_name == "copysign" && input.1.is_nan() { + if ctx.base_name == "copysign" && input.1.is_nan() { SKIP } else { None @@ -308,7 +308,7 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), CheckBasis::Mpfr => { // We return +0.0, MPFR returns -0.0 - if ctx.fname == "jnf" + if ctx.fn_name == "jnf" && input.1 == f32::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO @@ -333,7 +333,7 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), CheckBasis::Mpfr => { // We return +0.0, MPFR returns -0.0 - if ctx.fname == "jn" + if ctx.fn_name == "jn" && input.1 == f64::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO @@ -353,7 +353,7 @@ fn bessel_prec_dropoff( ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - if ctx.canonical_name == "jn" { + if ctx.base_name == "jn" { if input.0 > 4000 { return XFAIL; } else if input.0 > 2000 { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index deb837887fa..34e15e0b286 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -33,17 +33,17 @@ pub struct CheckCtx { /// Allowed ULP deviation pub ulp: u32, /// Function name. - pub fname: &'static str, + pub fn_name: &'static str, /// Return the unsuffixed version of the function name. - pub canonical_name: &'static str, + pub base_name: &'static str, /// Source of truth for tests. pub basis: CheckBasis, } impl CheckCtx { pub fn new(ulp: u32, fname: &'static str, basis: CheckBasis) -> Self { - let canonical_fname = crate::canonical_name(fname); - Self { ulp, fname, canonical_name: canonical_fname, basis } + let base_name = crate::base_name(fname); + Self { ulp, fn_name: fname, base_name, basis } } } diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index f85a6122ee8..b14bbec388d 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -57,7 +57,7 @@ macro_rules! cfg_if { /// (`unstable-intrinsics`, `arch`, `force-soft-floats`), this macro handles that part. macro_rules! select_implementation { ( - name: $fname:ident, + name: $fn_name:ident, // Configuration meta for when to use arch-specific implementation that requires hard // float ops $( use_arch: $use_arch:meta, )? @@ -76,7 +76,7 @@ macro_rules! select_implementation { select_implementation! { @cfg $($use_arch_required)?; if true { - return super::arch::$fname( $($arg),+ ); + return super::arch::$fn_name( $($arg),+ ); } } @@ -86,7 +86,7 @@ macro_rules! select_implementation { @cfg $($use_arch)?; // Wrap in `if true` to avoid unused warnings if true { - return super::arch::$fname( $($arg),+ ); + return super::arch::$fn_name( $($arg),+ ); } } @@ -96,7 +96,7 @@ macro_rules! select_implementation { select_implementation! { @cfg $( $use_intrinsic )?; if true { - return super::arch::intrinsics::$fname( $($arg),+ ); + return super::arch::intrinsics::$fn_name( $($arg),+ ); } } }; -- cgit 1.4.1-3-g733a5 From baae082fc5227a0e7e34fcee2e441d14d0044320 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Thu, 31 Oct 2024 19:29:13 +0800 Subject: ci: add support for loongarch64-unknown-linux-gnu --- library/compiler-builtins/libm/.github/workflows/main.yml | 2 ++ .../libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile | 13 +++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 library/compiler-builtins/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index cc0d23ffc2f..f0c5fe7c03e 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -32,6 +32,8 @@ jobs: os: ubuntu-latest - target: i686-unknown-linux-gnu os: ubuntu-latest + - target: loongarch64-unknown-linux-gnu + os: ubuntu-latest - target: powerpc-unknown-linux-gnu os: ubuntu-latest - target: powerpc64-unknown-linux-gnu diff --git a/library/compiler-builtins/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..a9ce320e8b4 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-14-loongarch64-linux-gnu libc6-dev-loong64-cross + +ENV CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER=loongarch64-linux-gnu-gcc-14 \ + CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-loongarch64-static \ + AR_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-ar \ + CC_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-gcc-14 \ + QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu \ + RUST_TEST_THREADS=1 -- cgit 1.4.1-3-g733a5 From 94e6ed373a0597f4a9c6141c7a5e6d5fa0209daf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:36:39 +0000 Subject: chore: release v0.1.137 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 4a85e5215b2..ecd5ecd0822 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.136" +version = "0.1.137" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From abff7cd82a392c48e141d5f3f09bd02869352d9b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Oct 2024 18:27:01 -0500 Subject: Add benchmarks against musl libm Add a benchmark for each function that checks against `musl_math_sys`. --- .../libm/crates/libm-test/Cargo.toml | 13 +++ .../libm/crates/libm-test/benches/random.rs | 119 +++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/benches/random.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 72ac57232b3..fedf745ed7f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -15,6 +15,12 @@ test-multiprecision = ["dep:az", "dep:rug"] # Build our own musl for testing and benchmarks build-musl = ["dep:musl-math-sys"] +# Enable report generation without bringing in more dependencies by default +benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] + +# Run with a reduced set of benchmarks, such as for CI +short-benchmarks = [] + [dependencies] anyhow = "1.0.90" az = { version = "1.2.1", optional = true } @@ -32,3 +38,10 @@ getrandom = { version = "0.2", features = ["js"] } [build-dependencies] rand = { version = "0.8.5", optional = true } + +[dev-dependencies] +criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } + +[[bench]] +name = "random" +harness = false diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs new file mode 100644 index 00000000000..6c9047c3cdb --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -0,0 +1,119 @@ +use std::hint::black_box; +use std::time::Duration; + +use criterion::{Criterion, criterion_main}; +use libm_test::gen::random; +use libm_test::{CheckBasis, CheckCtx, TupleCall}; + +/// Benchmark with this many items to get a variety +const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { 50 } else { 500 }; + +macro_rules! musl_rand_benches { + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + fn_extra: $skip_on_i586:expr, + ) => { + paste::paste! { + fn [< musl_bench_ $fn_name >](c: &mut Criterion) { + let fn_name = stringify!($fn_name); + + let ulp = libm_test::musl_allowed_ulp(fn_name); + let ctx = CheckCtx::new(ulp, fn_name, CheckBasis::Musl); + let benchvec: Vec<_> = random::get_test_cases::<$RustArgs>(&ctx) + .take(BENCH_ITER_ITEMS) + .collect(); + + // Perform a sanity check that we are benchmarking the same thing + // Don't test against musl if it is not available + #[cfg(feature = "build-musl")] + for input in benchvec.iter().copied() { + use anyhow::Context; + use libm_test::{CheckBasis, CheckCtx, CheckOutput}; + + if cfg!(x86_no_sse) && $skip_on_i586 { + break; + } + + let musl_res = input.call(musl_math_sys::$fn_name as $CFn); + let crate_res = input.call(libm::$fn_name as $RustFn); + + let ctx = CheckCtx::new(ulp, fn_name, CheckBasis::Musl); + crate_res.validate(musl_res, input, &ctx).context(fn_name).unwrap(); + } + + /* Function pointers are black boxed to avoid inlining in the benchmark loop */ + + let mut group = c.benchmark_group(fn_name); + group.bench_function("crate", |b| b.iter(|| { + let f = black_box(libm::$fn_name as $RustFn); + for input in benchvec.iter().copied() { + input.call(f); + } + })); + + // Don't test against musl if it is not available + #[cfg(feature = "build-musl")] + group.bench_function("musl", |b| b.iter(|| { + let f = black_box(musl_math_sys::$fn_name as $CFn); + for input in benchvec.iter().copied() { + input.call(f); + } + })); + } + } + }; +} + +libm_macros::for_each_function! { + callback: musl_rand_benches, + skip: [], + fn_extra: match MACRO_FN_NAME { + // FIXME(correctness): wrong result on i586 + exp10 | exp10f | exp2 | exp2f => true, + _ => false + } +} + +macro_rules! run_callback { + ( + fn_name: $fn_name:ident, + CFn: $_CFn:ty, + CArgs: $_CArgs:ty, + CRet: $_CRet:ty, + RustFn: $_RustFn:ty, + RustArgs: $_RustArgs:ty, + RustRet: $_RustRet:ty, + extra: [$criterion:ident], + ) => { + paste::paste! { + [< musl_bench_ $fn_name >](&mut $criterion) + } + }; +} + +pub fn musl_random() { + let mut criterion = Criterion::default(); + + // For CI, run a short 0.5s warmup and 1.0s tests. This makes benchmarks complete in + // about the same time as other tests. + if cfg!(feature = "short-benchmarks") { + criterion = criterion + .warm_up_time(Duration::from_millis(500)) + .measurement_time(Duration::from_millis(1000)); + } + + criterion = criterion.configure_from_args(); + + libm_macros::for_each_function! { + callback: run_callback, + extra: [criterion], + }; +} + +criterion_main!(musl_random); -- cgit 1.4.1-3-g733a5 From f770ec04b02282e652f38e1b6ec9da31e39777cc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Oct 2024 18:27:58 -0500 Subject: Remove `libm-bench` This has been superseded by the benchmarks in `libm-test`. --- library/compiler-builtins/libm/Cargo.toml | 1 - .../libm/crates/libm-bench/Cargo.toml | 16 --- .../libm/crates/libm-bench/benches/bench.rs | 116 --------------------- 3 files changed, 133 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/libm-bench/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 2e74012eae4..1786277664a 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -38,7 +38,6 @@ force-soft-floats = [] resolver = "2" members = [ "crates/compiler-builtins-smoke-test", - "crates/libm-bench", "crates/libm-macros", "crates/libm-test", "crates/musl-math-sys", diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml deleted file mode 100644 index ee8c5820037..00000000000 --- a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "libm-bench" -version = "0.1.0" -authors = ["Gonzalo Brito Gadeschi "] -edition = "2021" -license = "MIT OR Apache-2.0" -publish = false - -[dependencies] -libm = { path = "../..", default-features = false } -rand = "0.8.5" -paste = "1.0.15" - -[features] -default = [] -unstable = [ "libm/unstable" ] diff --git a/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs b/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs deleted file mode 100644 index ca999b90f27..00000000000 --- a/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs +++ /dev/null @@ -1,116 +0,0 @@ -#![feature(test)] -extern crate test; - -use rand::Rng; -use test::Bencher; - -macro_rules! unary { - ($($func:ident),*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](x))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](x))) - } - } - )*); -} -macro_rules! binary { - ($($func:ident),*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let y = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](x, y))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let y = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](x, y))) - } - } - )*); - ($($func:ident);*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let n = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](x, n))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let n = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](x, n))) - } - } - )*); -} -macro_rules! trinary { - ($($func:ident),*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let y = rng.gen::(); - let z = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](x, y, z))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let y = rng.gen::(); - let z = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](x, y, z))) - } - } - )*); -} -macro_rules! bessel { - ($($func:ident),*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let mut n = rng.gen::(); - n &= 0xffff; - let x = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](n, x))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let mut n = rng.gen::(); - n &= 0xffff; - let x = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](n, x))) - } - } - )*); -} - -unary!( - acos, acosh, asin, atan, cbrt, ceil, cos, cosh, erf, exp, exp2, exp10, expm1, fabs, floor, j0, - j1, lgamma, log, log1p, log2, log10, rint, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc, - y0, y1 -); -binary!(atan2, copysign, fdim, fmax, fmin, fmod, hypot, pow); -trinary!(fma); -bessel!(jn, yn); -binary!(ldexp; scalbn); -- cgit 1.4.1-3-g733a5 From be72d14ed5af76e233a18d76b0222d5805cf9147 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Oct 2024 18:35:11 -0500 Subject: Check benchmarks in CI --- library/compiler-builtins/libm/.github/workflows/main.yml | 2 +- library/compiler-builtins/libm/ci/run.sh | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index f0c5fe7c03e..bfd86497b4e 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -125,7 +125,7 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Download musl source run: ./ci/download-musl.sh - - run: cargo bench --all + - run: cargo bench --all --features libm-test/short-benchmarks,libm-test/build-musl msrv: name: Check MSRV diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 9f642326ba8..a211bc98cbf 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -83,4 +83,8 @@ else # unstable with a feature $cmd --features "unstable-intrinsics" $cmd --release --features "unstable-intrinsics" + + # Make sure benchmarks have correct results + $cmd --benches + $cmd --benches --release fi -- cgit 1.4.1-3-g733a5 From 4c1772ed85c9cc7cb37ab26a2f369a1e54fda748 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 22:47:11 -0500 Subject: Change prefixes used by the `Float` trait Change `EXPONENT_` to `EXP_` and `SIGNIFICAND_` to `SIG_`. These are pretty unambiguous, and just makes for less to type once these get used. --- .../libm/crates/libm-test/src/mpfloat.rs | 2 +- .../libm/src/math/support/float_traits.rs | 45 ++++++++++++---------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 44962d11679..2e6fdae7f19 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -15,7 +15,7 @@ use crate::Float; /// Create a multiple-precision float with the correct number of bits for a concrete float type. fn new_mpfloat() -> MpFloat { - MpFloat::new(F::SIGNIFICAND_BITS + 1) + MpFloat::new(F::SIG_BITS + 1) } /// Set subnormal emulation and convert to a concrete float type. diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 4cf5d7c6165..f90e99d5228 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -27,34 +27,37 @@ pub trait Float: const ZERO: Self; const ONE: Self; + const INFINITY: Self; + const NEG_INFINITY: Self; + const NAN: Self; /// The bitwidth of the float type const BITS: u32; /// The bitwidth of the significand - const SIGNIFICAND_BITS: u32; + const SIG_BITS: u32; /// The bitwidth of the exponent - const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; /// The saturated value of the exponent (infinite representation), in the rightmost postiion. - const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; + const EXP_MAX: u32 = (1 << Self::EXP_BITS) - 1; /// The exponent bias value - const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; + const EXP_BIAS: u32 = Self::EXP_MAX >> 1; /// A mask for the sign bit const SIGN_MASK: Self::Int; /// A mask for the significand - const SIGNIFICAND_MASK: Self::Int; + const SIG_MASK: Self::Int; + + /// A mask for the exponent + const EXP_MASK: Self::Int; /// The implicit bit of the float format const IMPLICIT_BIT: Self::Int; - /// A mask for the exponent - const EXPONENT_MASK: Self::Int; - /// Returns `self` transmuted to `Self::Int` fn to_bits(self) -> Self::Int; @@ -105,14 +108,17 @@ macro_rules! float_impl { const ZERO: Self = 0.0; const ONE: Self = 1.0; + const INFINITY: Self = Self::INFINITY; + const NEG_INFINITY: Self = Self::NEG_INFINITY; + const NAN: Self = Self::NAN; const BITS: u32 = $bits; - const SIGNIFICAND_BITS: u32 = $significand_bits; + const SIG_BITS: u32 = $significand_bits; const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; - const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; + const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); + const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; fn to_bits(self) -> Self::Int { self.to_bits() @@ -126,8 +132,7 @@ macro_rules! float_impl { // necessary builtin (__unordtf2) to test whether `f128` is NaN. // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin // x is NaN if all the bits of the exponent are set and the significand is non-0 - x.to_bits() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK - && x.to_bits() & $ty::SIGNIFICAND_MASK != 0 + x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 } if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() } } @@ -135,10 +140,10 @@ macro_rules! float_impl { self.is_sign_negative() } fn exp(self) -> Self::ExpInt { - ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt + ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt } fn frac(self) -> Self::Int { - self.to_bits() & Self::SIGNIFICAND_MASK + self.to_bits() & Self::SIG_MASK } fn imp_frac(self) -> Self::Int { self.frac() | Self::IMPLICIT_BIT @@ -149,16 +154,16 @@ macro_rules! float_impl { fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { Self::from_bits( ((negative as Self::Int) << (Self::BITS - 1)) - | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) - | (significand & Self::SIGNIFICAND_MASK), + | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) + | (significand & Self::SIG_MASK), ) } fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand.leading_zeros().wrapping_sub(Self::EXPONENT_BITS); + let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) } fn is_subnormal(self) -> bool { - (self.to_bits() & Self::EXPONENT_MASK) == Self::Int::ZERO + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO } } }; -- cgit 1.4.1-3-g733a5 From 5f54ad6389397af45bf38e1deed2dc8d92bd11ca Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 23:47:41 -0500 Subject: Update libm `Float` and `Int` with functions from the test traits The test versions of `Float` and `Int` have a few more methods and constants availablee. Update the in `libm` with everything missing from `libm_test` so we will be able to merge these. --- .../libm/src/math/support/float_traits.rs | 50 ++++++++++++++++++---- .../libm/src/math/support/int_traits.rs | 43 ++++++++++++++++--- 2 files changed, 77 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index f90e99d5228..a1d84faf2e2 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -1,4 +1,4 @@ -use core::ops; +use core::{fmt, ops}; use super::int_traits::{Int, MinInt}; @@ -6,7 +6,8 @@ use super::int_traits::{Int, MinInt}; #[allow(dead_code)] pub trait Float: Copy - + core::fmt::Debug + + fmt::Debug + + fmt::Display + PartialEq + PartialOrd + ops::AddAssign @@ -17,16 +18,17 @@ pub trait Float: + ops::Rem { /// A uint of the same width as the float - type Int: Int; + type Int: Int; /// A int of the same width as the float - type SignedInt: Int + MinInt; + type SignedInt: Int + MinInt; /// An int capable of containing the exponent bits plus a sign bit. This is signed. type ExpInt: Int; const ZERO: Self; const ONE: Self; + const NEG_ONE: Self; const INFINITY: Self; const NEG_INFINITY: Self; const NAN: Self; @@ -69,9 +71,18 @@ pub trait Float: /// compared. fn eq_repr(self, rhs: Self) -> bool; - /// Returns true if the sign is negative + /// Returns true if the value is NaN. + fn is_nan(self) -> bool; + + /// Returns true if the value is +inf or -inf. + fn is_infinite(self) -> bool; + + /// Returns true if the sign is negative. fn is_sign_negative(self) -> bool; + /// Returns if `self` is subnormal + fn is_subnormal(self) -> bool; + /// Returns the exponent, not adjusting for bias. fn exp(self) -> Self::ExpInt; @@ -95,8 +106,11 @@ pub trait Float: /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); - /// Returns if `self` is subnormal - fn is_subnormal(self) -> bool; + /// Returns a number composed of the magnitude of self and the sign of sign. + fn copysign(self, other: Self) -> Self; + + /// Returns a number that represents the sign of self. + fn signum(self) -> Self; } macro_rules! float_impl { @@ -108,6 +122,7 @@ macro_rules! float_impl { const ZERO: Self = 0.0; const ONE: Self = 1.0; + const NEG_ONE: Self = -1.0; const INFINITY: Self = Self::INFINITY; const NEG_INFINITY: Self = Self::NEG_INFINITY; const NAN: Self = Self::NAN; @@ -136,9 +151,18 @@ macro_rules! float_impl { } if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() } } + fn is_nan(self) -> bool { + self.is_nan() + } + fn is_infinite(self) -> bool { + self.is_infinite() + } fn is_sign_negative(self) -> bool { self.is_sign_negative() } + fn is_subnormal(self) -> bool { + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO + } fn exp(self) -> Self::ExpInt { ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt } @@ -162,8 +186,16 @@ macro_rules! float_impl { let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) } - fn is_subnormal(self) -> bool { - (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO + fn copysign(self, other: Self) -> Self { + let mut x = self.to_bits(); + let y = other.to_bits(); + x &= !Self::SIGN_MASK; + x |= y & Self::SIGN_MASK; + Self::from_bits(x) + } + + fn signum(self) -> Self { + if self.is_nan() { self } else { Self::ONE.copysign(self) } } } }; diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index bdf3afd48ce..c5feef8d726 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -12,7 +12,7 @@ pub trait MinInt: /// Type with the same width but other signedness type OtherSign: MinInt; /// Unsigned version of Self - type UnsignedInt: MinInt; + type Unsigned: MinInt; /// If `Self` is a signed integer const SIGNED: bool; @@ -30,6 +30,7 @@ pub trait MinInt: #[allow(dead_code)] pub trait Int: MinInt + + fmt::Display + PartialEq + PartialOrd + ops::AddAssign @@ -47,8 +48,10 @@ pub trait Int: + ops::BitXor + ops::BitAnd { - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + fn signed(self) -> ::OtherSign; + fn unsigned(self) -> Self::Unsigned; + fn from_unsigned(unsigned: Self::Unsigned) -> Self; + fn abs(self) -> Self; fn from_bool(b: bool) -> Self; @@ -56,10 +59,12 @@ pub trait Int: fn logical_shr(self, other: u32) -> Self; /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; + fn abs_diff(self, other: Self) -> Self::Unsigned; // copied from primitive integers, but put in a trait fn is_zero(self) -> bool; + fn checked_add(self, other: Self) -> Option; + fn checked_sub(self, other: Self) -> Option; fn wrapping_neg(self) -> Self; fn wrapping_add(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self; @@ -86,6 +91,14 @@ macro_rules! int_impl_common { self == Self::ZERO } + fn checked_add(self, other: Self) -> Option { + self.checked_add(other) + } + + fn checked_sub(self, other: Self) -> Option { + self.checked_sub(other) + } + fn wrapping_neg(self) -> Self { ::wrapping_neg(self) } @@ -132,7 +145,7 @@ macro_rules! int_impl { ($ity:ty, $uty:ty) => { impl MinInt for $uty { type OtherSign = $ity; - type UnsignedInt = $uty; + type Unsigned = $uty; const BITS: u32 = ::ZERO.count_zeros(); const SIGNED: bool = Self::MIN != Self::ZERO; @@ -144,10 +157,18 @@ macro_rules! int_impl { } impl Int for $uty { - fn unsigned(self) -> $uty { + fn signed(self) -> $ity { + self as $ity + } + + fn unsigned(self) -> Self { self } + fn abs(self) -> Self { + unimplemented!() + } + // It makes writing macros easier if this is implemented for both signed and unsigned #[allow(clippy::wrong_self_convention)] fn from_unsigned(me: $uty) -> Self { @@ -163,7 +184,7 @@ macro_rules! int_impl { impl MinInt for $ity { type OtherSign = $uty; - type UnsignedInt = $uty; + type Unsigned = $uty; const BITS: u32 = ::ZERO.count_zeros(); const SIGNED: bool = Self::MIN != Self::ZERO; @@ -175,10 +196,18 @@ macro_rules! int_impl { } impl Int for $ity { + fn signed(self) -> Self { + self + } + fn unsigned(self) -> $uty { self as $uty } + fn abs(self) -> Self { + self.abs() + } + fn from_unsigned(me: $uty) -> Self { me as $ity } -- cgit 1.4.1-3-g733a5 From 4b12a8404f3397c93d59711a3499a8e86213a015 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 23:52:27 -0500 Subject: Expose the `support` module publicly with a test feature --- library/compiler-builtins/libm/Cargo.toml | 3 +++ .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 1 + library/compiler-builtins/libm/src/math/mod.rs | 9 ++++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 1786277664a..98a60bfe3fe 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -26,6 +26,9 @@ unstable = ["unstable-intrinsics"] # Enable calls to functions in `core::intrinsics` unstable-intrinsics = [] +# Make some internal things public for testing. +unstable-test-support = [] + # Used to prevent using any intrinsics or arch-specific code. # # HACK: this is a negative feature which is generally a bad idea in Cargo, but diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 7118bfe06f1..e75c4f42bfa 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -13,6 +13,7 @@ bench = false # Duplicated from libm's Cargo.toml unstable = [] unstable-intrinsics = [] +unstable-test-support = [] checked = [] force-soft-floats = [] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 2cd77f1327b..afebdf5864c 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -74,9 +74,16 @@ macro_rules! div { }; } -// Private modules +// `support` may be public for testing +#[macro_use] +#[cfg(feature = "unstable-test-support")] +pub mod support; + #[macro_use] +#[cfg(not(feature = "unstable-test-support"))] mod support; + +// Private modules mod arch; mod expo2; mod fenv; -- cgit 1.4.1-3-g733a5 From dbf8a4ebe5106a28c7c95dc87b38ce716d6950c4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 23:53:03 -0500 Subject: Replace `libm_test::{Float, Int}` with `libm::{Float, Int}` This involves moving some things from full generic implementations (e.g. `impl SomeTrait for F { /* ... */ }` to generic functions and macros to implement traits that call them, due to orphan rule violations after `Float` became a not-in-crate trait. `Hex` was moved to `test_traits` so we can eliminate `num_traits`. --- .../libm/crates/libm-test/Cargo.toml | 2 +- .../libm/crates/libm-test/src/lib.rs | 5 +- .../libm/crates/libm-test/src/num_traits.rs | 214 ----------------- .../libm/crates/libm-test/src/test_traits.rs | 261 ++++++++++++++++----- 4 files changed, 199 insertions(+), 283 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index fedf745ed7f..3587b44e6a4 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -24,7 +24,7 @@ short-benchmarks = [] [dependencies] anyhow = "1.0.90" az = { version = "1.2.1", optional = true } -libm = { path = "../.." } +libm = { path = "../..", features = ["unstable-test-support"] } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } paste = "1.0.15" diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 6c7a3f5ece2..56a872779d6 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,13 +1,12 @@ pub mod gen; #[cfg(feature = "test-multiprecision")] pub mod mpfloat; -mod num_traits; mod precision; mod test_traits; -pub use num_traits::{Float, Hex, Int}; +pub use libm::support::{Float, Int}; pub use precision::{MaybeOverride, SpecialCase, multiprec_allowed_ulp, musl_allowed_ulp}; -pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, TupleCall}; +pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to /// propagate. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs deleted file mode 100644 index e16f4e4dca4..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs +++ /dev/null @@ -1,214 +0,0 @@ -use std::fmt; - -use crate::{MaybeOverride, SpecialCase, TestResult}; - -/// Common types and methods for floating point numbers. -pub trait Float: Copy + fmt::Display + fmt::Debug + PartialEq { - type Int: Int; - type SignedInt: Int + Int; - - const ZERO: Self; - const ONE: Self; - - /// The bitwidth of the float type - const BITS: u32; - - /// The bitwidth of the significand - const SIGNIFICAND_BITS: u32; - - /// The bitwidth of the exponent - const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; - - fn is_nan(self) -> bool; - fn is_infinite(self) -> bool; - fn to_bits(self) -> Self::Int; - fn from_bits(bits: Self::Int) -> Self; - fn signum(self) -> Self; -} - -macro_rules! impl_float { - ($($fty:ty, $ui:ty, $si:ty, $significand_bits:expr;)+) => { - $( - impl Float for $fty { - type Int = $ui; - type SignedInt = $si; - - const ZERO: Self = 0.0; - const ONE: Self = 1.0; - - const BITS: u32 = <$ui>::BITS; - const SIGNIFICAND_BITS: u32 = $significand_bits; - - fn is_nan(self) -> bool { - self.is_nan() - } - fn is_infinite(self) -> bool { - self.is_infinite() - } - fn to_bits(self) -> Self::Int { - self.to_bits() - } - fn from_bits(bits: Self::Int) -> Self { - Self::from_bits(bits) - } - fn signum(self) -> Self { - self.signum() - } - } - - impl Hex for $fty { - fn hex(self) -> String { - self.to_bits().hex() - } - } - )+ - } -} - -impl_float!( - f32, u32, i32, 23; - f64, u64, i64, 52; -); - -/// Common types and methods for integers. -pub trait Int: Copy + fmt::Display + fmt::Debug + PartialEq { - type OtherSign: Int; - type Unsigned: Int; - const BITS: u32; - const SIGNED: bool; - - fn signed(self) -> ::OtherSign; - fn unsigned(self) -> Self::Unsigned; - fn checked_sub(self, other: Self) -> Option; - fn abs(self) -> Self; -} - -macro_rules! impl_int { - ($($ui:ty, $si:ty ;)+) => { - $( - impl Int for $ui { - type OtherSign = $si; - type Unsigned = Self; - const BITS: u32 = <$ui>::BITS; - const SIGNED: bool = false; - fn signed(self) -> Self::OtherSign { - self as $si - } - fn unsigned(self) -> Self { - self - } - fn checked_sub(self, other: Self) -> Option { - self.checked_sub(other) - } - fn abs(self) -> Self { - unimplemented!() - } - } - - impl Int for $si { - type OtherSign = $ui; - type Unsigned = $ui; - const BITS: u32 = <$ui>::BITS; - const SIGNED: bool = true; - fn signed(self) -> Self { - self - } - fn unsigned(self) -> $ui { - self as $ui - } - fn checked_sub(self, other: Self) -> Option { - self.checked_sub(other) - } - fn abs(self) -> Self { - self.abs() - } - } - - impl_int!(@for_both $si); - impl_int!(@for_both $ui); - - )+ - }; - - (@for_both $ty:ty) => { - impl Hex for $ty { - fn hex(self) -> String { - format!("{self:#0width$x}", width = ((Self::BITS / 4) + 2) as usize) - } - } - - impl $crate::CheckOutput for $ty - where - Input: Hex + fmt::Debug, - SpecialCase: MaybeOverride, - { - fn validate<'a>( - self, - expected: Self, - input: Input, - ctx: &$crate::CheckCtx, - ) -> TestResult { - if let Some(res) = SpecialCase::check_int(input, self, expected, ctx) { - return res; - } - - anyhow::ensure!( - self == expected, - "\ - \n input: {input:?} {ibits}\ - \n expected: {expected:<22?} {expbits}\ - \n actual: {self:<22?} {actbits}\ - ", - actbits = self.hex(), - expbits = expected.hex(), - ibits = input.hex(), - ); - - Ok(()) - } - } - } -} - -impl_int!( - u32, i32; - u64, i64; -); - -/// A helper trait to print something as hex with the correct number of nibbles, e.g. a `u32` -/// will always print with `0x` followed by 8 digits. -/// -/// This is only used for printing errors so allocating is okay. -pub trait Hex: Copy { - fn hex(self) -> String; -} - -impl Hex for (T1,) -where - T1: Hex, -{ - fn hex(self) -> String { - format!("({},)", self.0.hex()) - } -} - -impl Hex for (T1, T2) -where - T1: Hex, - T2: Hex, -{ - fn hex(self) -> String { - format!("({}, {})", self.0.hex(), self.1.hex()) - } -} - -impl Hex for (T1, T2, T3) -where - T1: Hex, - T2: Hex, - T3: Hex, -{ - fn hex(self) -> String { - format!("({}, {}, {})", self.0.hex(), self.1.hex(), self.2.hex()) - } -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 34e15e0b286..67df83fb492 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -11,21 +11,7 @@ use std::fmt; use anyhow::{Context, bail, ensure}; -use crate::{Float, Hex, Int, MaybeOverride, SpecialCase, TestResult}; - -/// Implement this on types that can generate a sequence of tuples for test input. -pub trait GenerateInput { - fn get_cases(&self) -> impl Iterator; -} - -/// Trait for calling a function with a tuple as arguments. -/// -/// Implemented on the tuple with the function signature as the generic (so we can use the same -/// tuple for multiple signatures). -pub trait TupleCall: fmt::Debug { - type Output; - fn call(self, f: Func) -> Self::Output; -} +use crate::{Float, Int, MaybeOverride, SpecialCase, TestResult}; /// Context passed to [`CheckOutput`]. #[derive(Clone, Debug, PartialEq, Eq)] @@ -56,14 +42,38 @@ pub enum CheckBasis { Mpfr, } +/// Implement this on types that can generate a sequence of tuples for test input. +pub trait GenerateInput { + fn get_cases(&self) -> impl Iterator; +} + +/// Trait for calling a function with a tuple as arguments. +/// +/// Implemented on the tuple with the function signature as the generic (so we can use the same +/// tuple for multiple signatures). +pub trait TupleCall: fmt::Debug { + type Output; + fn call(self, f: Func) -> Self::Output; +} + /// A trait to implement on any output type so we can verify it in a generic way. pub trait CheckOutput: Sized { /// Validate `self` (actual) and `expected` are the same. /// /// `input` is only used here for error messages. - fn validate<'a>(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult; + fn validate(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult; +} + +/// A helper trait to print something as hex with the correct number of nibbles, e.g. a `u32` +/// will always print with `0x` followed by 8 digits. +/// +/// This is only used for printing errors so allocating is okay. +pub trait Hex: Copy { + fn hex(self) -> String; } +/* implement `TupleCall` */ + impl TupleCall R> for (T1,) where T1: fmt::Debug, @@ -143,72 +153,193 @@ where } } -// Implement for floats -impl CheckOutput for F +/* implement `Hex` */ + +impl Hex for (T1,) where - F: Float + Hex, + T1: Hex, +{ + fn hex(self) -> String { + format!("({},)", self.0.hex()) + } +} + +impl Hex for (T1, T2) +where + T1: Hex, + T2: Hex, +{ + fn hex(self) -> String { + format!("({}, {})", self.0.hex(), self.1.hex()) + } +} + +impl Hex for (T1, T2, T3) +where + T1: Hex, + T2: Hex, + T3: Hex, +{ + fn hex(self) -> String { + format!("({}, {}, {})", self.0.hex(), self.1.hex(), self.2.hex()) + } +} + +/* trait implementations for ints */ + +macro_rules! impl_int { + ($($ty:ty),*) => { + $( + impl Hex for $ty { + fn hex(self) -> String { + format!("{self:#0width$x}", width = ((Self::BITS / 4) + 2) as usize) + } + } + + impl $crate::CheckOutput for $ty + where + Input: Hex + fmt::Debug, + SpecialCase: MaybeOverride, + { + fn validate<'a>( + self, + expected: Self, + input: Input, + ctx: &$crate::CheckCtx, + ) -> TestResult { + validate_int(self, expected, input, ctx) + } + } + )* + }; +} + +fn validate_int<'a, I, Input>(actual: I, expected: I, input: Input, ctx: &CheckCtx) -> TestResult +where + I: Int + Hex, Input: Hex + fmt::Debug, - u32: TryFrom, SpecialCase: MaybeOverride, { - fn validate<'a>(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult { - // Create a wrapper function so we only need to `.with_context` once. - let inner = || -> TestResult { - let mut allowed_ulp = ctx.ulp; - - // If the tested function requires a nonstandard test, run it here. - if let Some(res) = - SpecialCase::check_float(input, self, expected, &mut allowed_ulp, ctx) - { - return res; + if let Some(res) = SpecialCase::check_int(input, actual, expected, ctx) { + return res; + } + + anyhow::ensure!( + actual == expected, + "\ + \n input: {input:?} {ibits}\ + \n expected: {expected:<22?} {expbits}\ + \n actual: {actual:<22?} {actbits}\ + ", + actbits = actual.hex(), + expbits = expected.hex(), + ibits = input.hex(), + ); + + Ok(()) +} + +impl_int!(u32, i32, u64, i64); + +/* trait implementations for floats */ + +macro_rules! impl_float { + ($($ty:ty),*) => { + $( + impl Hex for $ty { + fn hex(self) -> String { + format!( + "{:#0width$x}", + self.to_bits(), + width = ((Self::BITS / 4) + 2) as usize + ) + } } - // Check when both are NaNs - if self.is_nan() && expected.is_nan() { - // By default, NaNs have nothing special to check. - return Ok(()); - } else if self.is_nan() || expected.is_nan() { - // Check when only one is a NaN - bail!("real value != NaN") + impl $crate::CheckOutput for $ty + where + Input: Hex + fmt::Debug, + SpecialCase: MaybeOverride, + { + fn validate<'a>( + self, + expected: Self, + input: Input, + ctx: &$crate::CheckCtx, + ) -> TestResult { + validate_float(self, expected, input, ctx) + } } + )* + }; +} + +fn validate_float<'a, F, Input>(actual: F, expected: F, input: Input, ctx: &CheckCtx) -> TestResult +where + F: Float + Hex, + Input: Hex + fmt::Debug, + u32: TryFrom, + SpecialCase: MaybeOverride, +{ + // Create a wrapper function so we only need to `.with_context` once. + let inner = || -> TestResult { + let mut allowed_ulp = ctx.ulp; - // Make sure that the signs are the same before checing ULP to avoid wraparound - let act_sig = self.signum(); - let exp_sig = expected.signum(); - ensure!(act_sig == exp_sig, "mismatched signs {act_sig} {exp_sig}"); + // If the tested function requires a nonstandard test, run it here. + if let Some(res) = SpecialCase::check_float(input, actual, expected, &mut allowed_ulp, ctx) + { + return res; + } - if self.is_infinite() ^ expected.is_infinite() { - bail!("mismatched infinities"); - } + // Check when both are NaNs + if actual.is_nan() && expected.is_nan() { + // By default, NaNs have nothing special to check. + return Ok(()); + } else if actual.is_nan() || expected.is_nan() { + // Check when only one is a NaN + bail!("real value != NaN") + } - let act_bits = self.to_bits().signed(); - let exp_bits = expected.to_bits().signed(); + // Make sure that the signs are the same before checing ULP to avoid wraparound + let act_sig = actual.signum(); + let exp_sig = expected.signum(); + ensure!(act_sig == exp_sig, "mismatched signs {act_sig} {exp_sig}"); - let ulp_diff = act_bits.checked_sub(exp_bits).unwrap().abs(); + if actual.is_infinite() ^ expected.is_infinite() { + bail!("mismatched infinities"); + } - let ulp_u32 = u32::try_from(ulp_diff) - .map_err(|e| anyhow::anyhow!("{e:?}: ulp of {ulp_diff} exceeds u32::MAX"))?; + let act_bits = actual.to_bits().signed(); + let exp_bits = expected.to_bits().signed(); - ensure!(ulp_u32 <= allowed_ulp, "ulp {ulp_diff} > {allowed_ulp}",); + let ulp_diff = act_bits.checked_sub(exp_bits).unwrap().abs(); - Ok(()) - }; + let ulp_u32 = u32::try_from(ulp_diff) + .map_err(|e| anyhow::anyhow!("{e:?}: ulp of {ulp_diff} exceeds u32::MAX"))?; - inner().with_context(|| { - format!( - "\ - \n input: {input:?} {ibits}\ - \n expected: {expected:<22?} {expbits}\ - \n actual: {self:<22?} {actbits}\ - ", - actbits = self.hex(), - expbits = expected.hex(), - ibits = input.hex(), - ) - }) - } + ensure!(ulp_u32 <= allowed_ulp, "ulp {ulp_diff} > {allowed_ulp}",); + + Ok(()) + }; + + inner().with_context(|| { + format!( + "\ + \n input: {input:?} {ibits}\ + \n expected: {expected:<22?} {expbits}\ + \n actual: {actual:<22?} {actbits}\ + ", + actbits = actual.hex(), + expbits = expected.hex(), + ibits = input.hex(), + ) + }) } +impl_float!(f32, f64); + +/* trait implementations for compound types */ + /// Implement `CheckOutput` for combinations of types. macro_rules! impl_tuples { ($(($a:ty, $b:ty);)*) => { -- cgit 1.4.1-3-g733a5 From 53b3e71bbcab44510a0c3e0ff9e721a6592d677d Mon Sep 17 00:00:00 2001 From: hev Date: Fri, 1 Nov 2024 18:00:00 +0800 Subject: Disable `f16` for LoongArch64 (#722) Disable `f161` for LoongArch64 due to incorrect code generation on LLVM 19, which causes failures in `testcrate/tests/conv.rs`. This workaround will remain in place until llvm/llvm-project#109093 is merged or we upgrade to LLVM 20. --- library/compiler-builtins/configure.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index e23c0e83935..68b4d68e61b 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -64,6 +64,8 @@ pub fn configure_f16_f128(target: &Target) { "arm64ec" => (false, false), // `f16` crashes "s390x" => (false, true), + // FIXME(llvm): `f16` test failures fixed by + "loongarch64" => (false, true), // `f128` crashes "mips64" | "mips64r6" => (true, false), // `f128` crashes -- cgit 1.4.1-3-g733a5 From ca996df5c14554ce6c237972a06f7e3f0c8ae919 Mon Sep 17 00:00:00 2001 From: hev Date: Fri, 1 Nov 2024 18:34:51 +0800 Subject: Use `f16_enabled`/`f128_enabled` in `examples/intrinsics.rs` (#724) Enable conditional compilation for intrinsics with `f16_enabled` and `f128_enabled` --- library/compiler-builtins/examples/intrinsics.rs | 122 ++++++++++++++++++++--- 1 file changed, 106 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 368da6af2e4..ef7a3d43030 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -28,21 +28,28 @@ extern "C" {} mod intrinsics { /* f16 operations */ + #[cfg(f16_enabled)] pub fn extendhfsf(x: f16) -> f32 { x as f32 } + #[cfg(f16_enabled)] pub fn extendhfdf(x: f16) -> f64 { x as f64 } - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f16_enabled, + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn extendhftf(x: f16) -> f128 { x as f128 } /* f32 operations */ + #[cfg(f16_enabled)] pub fn truncsfhf(x: f32) -> f16 { x as f16 } @@ -52,6 +59,7 @@ mod intrinsics { x as f64 } + #[cfg(f128_enabled)] pub fn extendsftf(x: f32) -> f128 { x as f128 } @@ -191,73 +199,104 @@ mod intrinsics { /* f128 operations */ - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f16_enabled, + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn trunctfhf(x: f128) -> f16 { x as f16 } + #[cfg(f128_enabled)] pub fn trunctfsf(x: f128) -> f32 { x as f32 } + #[cfg(f128_enabled)] pub fn trunctfdf(x: f128) -> f64 { x as f64 } - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn fixtfsi(x: f128) -> i32 { x as i32 } - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn fixtfdi(x: f128) -> i64 { x as i64 } - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn fixtfti(x: f128) -> i128 { x as i128 } - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn fixunstfsi(x: f128) -> u32 { x as u32 } - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn fixunstfdi(x: f128) -> u64 { x as u64 } - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn fixunstfti(x: f128) -> u128 { x as u128 } + #[cfg(f128_enabled)] pub fn addtf(a: f128, b: f128) -> f128 { a + b } + #[cfg(f128_enabled)] pub fn eqtf(a: f128, b: f128) -> bool { a == b } + #[cfg(f128_enabled)] pub fn gttf(a: f128, b: f128) -> bool { a > b } + #[cfg(f128_enabled)] pub fn lttf(a: f128, b: f128) -> bool { a < b } + #[cfg(f128_enabled)] pub fn multf(a: f128, b: f128) -> f128 { a * b } + #[cfg(f128_enabled)] pub fn divtf(a: f128, b: f128) -> f128 { a / b } + #[cfg(f128_enabled)] pub fn subtf(a: f128, b: f128) -> f128 { a - b } @@ -274,6 +313,7 @@ mod intrinsics { x as f64 } + #[cfg(f128_enabled)] pub fn floatsitf(x: i32) -> f128 { x as f128 } @@ -298,6 +338,7 @@ mod intrinsics { x as f64 } + #[cfg(f128_enabled)] pub fn floatditf(x: i64) -> f128 { x as f128 } @@ -330,6 +371,7 @@ mod intrinsics { x as f64 } + #[cfg(f128_enabled)] pub fn floattitf(x: i128) -> f128 { x as f128 } @@ -358,6 +400,7 @@ mod intrinsics { x as f64 } + #[cfg(f128_enabled)] pub fn floatunsitf(x: u32) -> f128 { x as f128 } @@ -382,6 +425,7 @@ mod intrinsics { x as f64 } + #[cfg(f128_enabled)] pub fn floatunditf(x: u64) -> f128 { x as f128 } @@ -405,6 +449,7 @@ mod intrinsics { x as f64 } + #[cfg(f128_enabled)] pub fn floatuntitf(x: u128) -> f128 { x as f128 } @@ -440,6 +485,7 @@ fn run() { // FIXME(f16_f128): some PPC f128 <-> int conversion functions have the wrong names + #[cfg(f128_enabled)] bb(addtf(bb(2.), bb(2.))); bb(aeabi_d2f(bb(2.))); bb(aeabi_d2i(bb(2.))); @@ -482,54 +528,98 @@ fn run() { bb(aeabi_uldivmod(bb(2), bb(3))); bb(ashlti3(bb(2), bb(2))); bb(ashrti3(bb(2), bb(2))); + #[cfg(f128_enabled)] bb(divtf(bb(2.), bb(2.))); bb(divti3(bb(2), bb(2))); + #[cfg(f128_enabled)] bb(eqtf(bb(2.), bb(2.))); + #[cfg(f16_enabled)] bb(extendhfdf(bb(2.))); + #[cfg(f16_enabled)] bb(extendhfsf(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f16_enabled, + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(extendhftf(bb(2.))); + #[cfg(f128_enabled)] bb(extendsftf(bb(2.))); bb(fixdfti(bb(2.))); bb(fixsfti(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(fixtfdi(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(fixtfsi(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(fixtfti(bb(2.))); bb(fixunsdfti(bb(2.))); bb(fixunssfti(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(fixunstfdi(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(fixunstfsi(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(fixunstfti(bb(2.))); + #[cfg(f128_enabled)] bb(floatditf(bb(2))); + #[cfg(f128_enabled)] bb(floatsitf(bb(2))); bb(floattidf(bb(2))); bb(floattisf(bb(2))); + #[cfg(f128_enabled)] bb(floattitf(bb(2))); + #[cfg(f128_enabled)] bb(floatunditf(bb(2))); + #[cfg(f128_enabled)] bb(floatunsitf(bb(2))); bb(floatuntidf(bb(2))); bb(floatuntisf(bb(2))); + #[cfg(f128_enabled)] bb(floatuntitf(bb(2))); + #[cfg(f128_enabled)] bb(gttf(bb(2.), bb(2.))); bb(lshrti3(bb(2), bb(2))); + #[cfg(f128_enabled)] bb(lttf(bb(2.), bb(2.))); bb(moddi3(bb(2), bb(3))); bb(modti3(bb(2), bb(2))); bb(mulodi4(bb(2), bb(3))); bb(muloti4(bb(2), bb(2))); + #[cfg(f128_enabled)] bb(multf(bb(2.), bb(2.))); bb(multi3(bb(2), bb(2))); + #[cfg(f128_enabled)] bb(subtf(bb(2.), bb(2.))); + #[cfg(f16_enabled)] bb(truncsfhf(bb(2.))); + #[cfg(f128_enabled)] bb(trunctfdf(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f16_enabled, + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(trunctfhf(bb(2.))); + #[cfg(f128_enabled)] bb(trunctfsf(bb(2.))); bb(udivti3(bb(2), bb(2))); bb(umoddi3(bb(2), bb(3))); -- cgit 1.4.1-3-g733a5 From ec673535f7b0f6dd390a35d3cdd30fba8891edef Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Thu, 31 Oct 2024 21:36:57 +0800 Subject: ci: add support for loongarch64-unknown-linux-gnu --- library/compiler-builtins/.github/workflows/main.yml | 3 +++ .../ci/docker/loongarch64-unknown-linux-gnu/Dockerfile | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index ec5c059bac0..fee5c45eaf0 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -38,6 +38,9 @@ jobs: - target: i686-unknown-linux-gnu os: ubuntu-latest rust: nightly + - target: loongarch64-unknown-linux-gnu + os: ubuntu-latest + rust: nightly # MIPS targets disabled since they are dropped to tier 3. # See https://github.com/rust-lang/compiler-team/issues/648 #- target: mips-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..5107d20a2a8 --- /dev/null +++ b/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-14-loongarch64-linux-gnu libc6-dev-loong64-cross + +ENV CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER=loongarch64-linux-gnu-gcc-14 \ + CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-loongarch64-static \ + CC_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-gcc-14 \ + QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu \ + RUST_TEST_THREADS=1 -- cgit 1.4.1-3-g733a5 From 28fb4bc8689987b8f42d6bb5becb1a02251472a7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 1 Nov 2024 05:48:10 -0500 Subject: Enable the changelog for `release-plz` This crate isn't meant for direct use, but having an easy way to see what changed between versions would still be helpful when this crate is updated in rust-lang/rust. --- library/compiler-builtins/.release-plz.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/.release-plz.toml b/library/compiler-builtins/.release-plz.toml index fce19d15755..e32f6761084 100644 --- a/library/compiler-builtins/.release-plz.toml +++ b/library/compiler-builtins/.release-plz.toml @@ -1,5 +1,4 @@ [workspace] -changelog_update = false semver_check = false # As part of the release process, we delete `libm/Cargo.toml`. Since -- cgit 1.4.1-3-g733a5 From 4c7450d10cfec44c6a7b6d6b83fd0643dba819b2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 11:00:27 +0000 Subject: chore: release v0.1.138 --- library/compiler-builtins/CHANGELOG.md | 15 +++++++++++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/CHANGELOG.md diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md new file mode 100644 index 00000000000..f43b63b2b0c --- /dev/null +++ b/library/compiler-builtins/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.138](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.137...compiler_builtins-v0.1.138) - 2024-11-01 + +### Other + +- Use `f16_enabled`/`f128_enabled` in `examples/intrinsics.rs` ([#724](https://github.com/rust-lang/compiler-builtins/pull/724)) +- Disable `f16` for LoongArch64 ([#722](https://github.com/rust-lang/compiler-builtins/pull/722)) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index ecd5ecd0822..3d8a1f25503 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.137" +version = "0.1.138" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From c2402e4d3c2708cba97e463f7a863d08af8d51a1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 1 Nov 2024 06:05:42 -0500 Subject: Fix errors reported by Clippy in `libm` --- library/compiler-builtins/libm/src/lib.rs | 3 + library/compiler-builtins/libm/src/math/asin.rs | 2 +- library/compiler-builtins/libm/src/math/asinf.rs | 2 +- library/compiler-builtins/libm/src/math/atan2f.rs | 22 +- library/compiler-builtins/libm/src/math/atanhf.rs | 2 +- library/compiler-builtins/libm/src/math/exp2f.rs | 4 +- library/compiler-builtins/libm/src/math/expm1.rs | 2 +- library/compiler-builtins/libm/src/math/expm1f.rs | 2 +- library/compiler-builtins/libm/src/math/fabs.rs | 2 - library/compiler-builtins/libm/src/math/fdim.rs | 6 +- library/compiler-builtins/libm/src/math/fdimf.rs | 6 +- library/compiler-builtins/libm/src/math/fmaf.rs | 2 +- library/compiler-builtins/libm/src/math/fmod.rs | 4 +- library/compiler-builtins/libm/src/math/fmodf.rs | 2 +- library/compiler-builtins/libm/src/math/ilogb.rs | 2 +- library/compiler-builtins/libm/src/math/ilogbf.rs | 2 +- library/compiler-builtins/libm/src/math/jn.rs | 238 ++++++++++----------- library/compiler-builtins/libm/src/math/jnf.rs | 230 ++++++++++---------- .../compiler-builtins/libm/src/math/lgamma_r.rs | 3 +- .../compiler-builtins/libm/src/math/lgammaf_r.rs | 3 +- .../compiler-builtins/libm/src/math/nextafter.rs | 4 +- library/compiler-builtins/libm/src/math/pow.rs | 6 +- library/compiler-builtins/libm/src/math/powf.rs | 12 +- .../compiler-builtins/libm/src/math/rem_pio2.rs | 2 +- .../libm/src/math/rem_pio2_large.rs | 2 - library/compiler-builtins/libm/src/math/sincosf.rs | 26 +-- library/compiler-builtins/libm/src/math/sqrt.rs | 12 +- .../libm/src/math/support/int_traits.rs | 3 + library/compiler-builtins/libm/src/math/tgamma.rs | 5 +- 29 files changed, 306 insertions(+), 305 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 98ac55988d0..511ab598dba 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -5,12 +5,15 @@ #![allow(clippy::assign_op_pattern)] #![allow(clippy::deprecated_cfg_attr)] #![allow(clippy::eq_op)] +#![allow(clippy::excessive_precision)] #![allow(clippy::float_cmp)] #![allow(clippy::int_plus_one)] #![allow(clippy::many_single_char_names)] #![allow(clippy::mixed_case_hex_literals)] +#![allow(clippy::needless_late_init)] #![allow(clippy::needless_return)] #![allow(clippy::unreadable_literal)] +#![allow(clippy::zero_divided_by_zero)] mod libm_helper; mod math; diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs index 12fe08fc745..12d0cd35fa5 100644 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -90,7 +90,7 @@ pub fn asin(mut x: f64) -> f64 { /* |x| < 0.5 */ if ix < 0x3fe00000 { /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ - if ix < 0x3e500000 && ix >= 0x00100000 { + if (0x00100000..0x3e500000).contains(&ix) { return x; } else { return x + x * comp_r(x * x); diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index 2c785abe2ba..0ea49c0767c 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -54,7 +54,7 @@ pub fn asinf(mut x: f32) -> f32 { if ix < 0x3f000000 { /* |x| < 0.5 */ /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ - if (ix < 0x39800000) && (ix >= 0x00800000) { + if (0x00800000..0x39800000).contains(&ix) { return x; } return x + x * r(x * x); diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs index fa33f54f6f7..95b466fff4e 100644 --- a/library/compiler-builtins/libm/src/math/atan2f.rs +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -42,9 +42,9 @@ pub fn atan2f(y: f32, x: f32) -> f32 { /* when y = 0 */ if iy == 0 { return match m { - 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ - 2 => PI, /* atan(+0,-anything) = pi */ - 3 | _ => -PI, /* atan(-0,-anything) =-pi */ + 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ + 2 => PI, /* atan(+0,-anything) = pi */ + _ => -PI, /* atan(-0,-anything) =-pi */ }; } /* when x = 0 */ @@ -55,17 +55,17 @@ pub fn atan2f(y: f32, x: f32) -> f32 { if ix == 0x7f800000 { return if iy == 0x7f800000 { match m { - 0 => PI / 4., /* atan(+INF,+INF) */ - 1 => -PI / 4., /* atan(-INF,+INF) */ - 2 => 3. * PI / 4., /* atan(+INF,-INF)*/ - 3 | _ => -3. * PI / 4., /* atan(-INF,-INF)*/ + 0 => PI / 4., /* atan(+INF,+INF) */ + 1 => -PI / 4., /* atan(-INF,+INF) */ + 2 => 3. * PI / 4., /* atan(+INF,-INF)*/ + _ => -3. * PI / 4., /* atan(-INF,-INF)*/ } } else { match m { - 0 => 0., /* atan(+...,+INF) */ - 1 => -0., /* atan(-...,+INF) */ - 2 => PI, /* atan(+...,-INF) */ - 3 | _ => -PI, /* atan(-...,-INF) */ + 0 => 0., /* atan(+...,+INF) */ + 1 => -0., /* atan(-...,+INF) */ + 2 => PI, /* atan(+...,-INF) */ + _ => -PI, /* atan(-...,-INF) */ } }; } diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs index 3545411bbd5..80ccec1f67f 100644 --- a/library/compiler-builtins/libm/src/math/atanhf.rs +++ b/library/compiler-builtins/libm/src/math/atanhf.rs @@ -18,7 +18,7 @@ pub fn atanhf(mut x: f32) -> f32 { if u < 0x3f800000 - (32 << 23) { /* handle underflow */ if u < (1 << 23) { - force_eval!((x * x) as f32); + force_eval!(x * x); } } else { /* |x| < 0.5, up to 1.7ulp error */ diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index f4867b80eed..f452b6a20f8 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -95,7 +95,7 @@ pub fn exp2f(mut x: f32) -> f32 { /* NaN */ return x; } - if ui >= 0x43000000 && ui < 0x80000000 { + if (0x43000000..0x80000000).contains(&ui) { /* x >= 128 */ x *= x1p127; return x; @@ -127,7 +127,7 @@ pub fn exp2f(mut x: f32) -> f32 { let z: f64 = (x - uf) as f64; /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ let r: f64 = f64::from_bits(i!(EXP2FT, i0 as usize)); - let t: f64 = r as f64 * z; + let t: f64 = r * z; let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64); /* Scale by 2**k */ diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs index 42608509a40..f25153f32a3 100644 --- a/library/compiler-builtins/libm/src/math/expm1.rs +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -115,7 +115,7 @@ pub fn expm1(mut x: f64) -> f64 { } ui = ((0x3ff + k) as u64) << 52; /* 2^k */ let twopk = f64::from_bits(ui); - if k < 0 || k > 56 { + if !(0..=56).contains(&k) { /* suffice to return exp(x)-1 */ y = x - e + 1.0; if k == 1024 { diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs index a862fe2558c..12c6f532b96 100644 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -115,7 +115,7 @@ pub fn expm1f(mut x: f32) -> f32 { return 1. + 2. * (x - e); } let twopk = f32::from_bits(((0x7f + k) << 23) as u32); /* 2^k */ - if (k < 0) || (k > 56) { + if !(0..=56).contains(&k) { /* suffice to return exp(x)-1 */ let mut y = x - e + 1.; if k == 128 { diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 8d3ea2fd647..d7980eb65f2 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -1,5 +1,3 @@ -use core::u64; - /// Absolute value (magnitude) (f64) /// Calculates the absolute value (magnitude) of the argument `x`, /// by direct manipulation of the bit representation of `x`. diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index 014930097a0..7c58cb5a9a2 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -3,9 +3,9 @@ use core::f64; /// Positive difference (f64) /// /// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. /// /// A range error may occur. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index ea0b592d7ab..2abd49a64c9 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -3,9 +3,9 @@ use core::f32; /// Positive difference (f32) /// /// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. /// /// A range error may occur. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index 10bdaeab33d..79371c836c8 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -71,7 +71,7 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { underflow may not be raised correctly, example: fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) */ - if e < 0x3ff - 126 && e >= 0x3ff - 149 && fetestexcept(FE_INEXACT) != 0 { + if ((0x3ff - 149)..(0x3ff - 126)).contains(&e) && fetestexcept(FE_INEXACT) != 0 { feclearexcept(FE_INEXACT); // prevent `xy + vz` from being CSE'd with `xy + z` above let vz: f32 = unsafe { read_volatile(&z) }; diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs index d892ffd8b72..df16162bcae 100644 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -1,5 +1,3 @@ -use core::u64; - #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmod(x: f64, y: f64) -> f64 { let mut uxi = x.to_bits(); @@ -74,7 +72,7 @@ pub fn fmod(x: f64, y: f64) -> f64 { } else { uxi >>= -ex + 1; } - uxi |= (sx as u64) << 63; + uxi |= sx << 63; f64::from_bits(uxi) } diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index 1d80013842e..671af85800f 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -1,4 +1,4 @@ -use core::{f32, u32}; +use core::f32; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmodf(x: f32, y: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs index 9d58d06081b..ccc4914be2b 100644 --- a/library/compiler-builtins/libm/src/math/ilogb.rs +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -21,7 +21,7 @@ pub fn ilogb(x: f64) -> i32 { e } else if e == 0x7ff { force_eval!(0.0 / 0.0); - if (i << 12) != 0 { FP_ILOGBNAN } else { i32::max_value() } + if (i << 12) != 0 { FP_ILOGBNAN } else { i32::MAX } } else { e - 0x3ff } diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs index 85deb43c83b..3585d6d36f1 100644 --- a/library/compiler-builtins/libm/src/math/ilogbf.rs +++ b/library/compiler-builtins/libm/src/math/ilogbf.rs @@ -21,7 +21,7 @@ pub fn ilogbf(x: f32) -> i32 { e } else if e == 0xff { force_eval!(0.0 / 0.0); - if (i << 9) != 0 { FP_ILOGBNAN } else { i32::max_value() } + if (i << 9) != 0 { FP_ILOGBNAN } else { i32::MAX } } else { e - 0x7f } diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs index aff051f2406..7f98ddc055a 100644 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -104,7 +104,8 @@ pub fn jn(n: i32, mut x: f64) -> f64 { 0 => -cos(x) + sin(x), 1 => -cos(x) - sin(x), 2 => cos(x) - sin(x), - 3 | _ => cos(x) + sin(x), + // 3 + _ => cos(x) + sin(x), }; b = INVSQRTPI * temp / sqrt(x); } else { @@ -118,130 +119,128 @@ pub fn jn(n: i32, mut x: f64) -> f64 { a = temp; } } - } else { - if ix < 0x3e100000 { - /* x < 2**-29 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 32 { - /* underflow */ - b = 0.0; - } else { - temp = x * 0.5; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as f64; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } + } else if ix < 0x3e100000 { + /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 32 { + /* underflow */ + b = 0.0; } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: f64; - let mut q0: f64; - let mut q1: f64; - let mut w: f64; - let h: f64; - let mut z: f64; - let mut tmp: f64; - let nf: f64; + temp = x * 0.5; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f64; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f64; + let mut q0: f64; + let mut q1: f64; + let mut w: f64; + let h: f64; + let mut z: f64; + let mut tmp: f64; + let nf: f64; - let mut k: i32; + let mut k: i32; - nf = (nm1 as f64) + 1.0; - w = 2.0 * nf / x; - h = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e9 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as f64) + nf) / x - t); + nf = (nm1 as f64) + 1.0; + w = 2.0 * nf / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e9 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as f64) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * log(fabs(w)); + if tmp < 7.09782712893383973096e+02 { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as f64)) / x - a; + a = temp; i -= 1; } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf * log(fabs(w)); - if tmp < 7.09782712893383973096e+02 { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as f64)) / x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as f64)) / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 - if b > x1p500 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; + } else { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as f64)) / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 + if b > x1p500 { + a /= b; + t /= b; + b = 1.0; } + i -= 1; } - z = j0(x); - w = j1(x); - if fabs(z) >= fabs(w) { - b = t * z / b; - } else { - b = t * w / a; - } + } + z = j0(x); + w = j1(x); + if fabs(z) >= fabs(w) { + b = t * z / b; + } else { + b = t * w / a; } } @@ -315,7 +314,8 @@ pub fn yn(n: i32, x: f64) -> f64 { 0 => -sin(x) - cos(x), 1 => -sin(x) + cos(x), 2 => sin(x) + cos(x), - 3 | _ => sin(x) - cos(x), + // 3 + _ => sin(x) - cos(x), }; b = INVSQRTPI * temp / sqrt(x); } else { diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs index e5afda44896..754f8f33b5a 100644 --- a/library/compiler-builtins/libm/src/math/jnf.rs +++ b/library/compiler-builtins/libm/src/math/jnf.rs @@ -64,128 +64,126 @@ pub fn jnf(n: i32, mut x: f32) -> f32 { b = b * (2.0 * (i as f32) / x) - a; a = temp; } + } else if ix < 0x35800000 { + /* x < 2**-20 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 8 { + /* underflow */ + nm1 = 8; + } + temp = 0.5 * x; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f32; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; } else { - if ix < 0x35800000 { - /* x < 2**-20 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 8 { - /* underflow */ - nm1 = 8; - } - temp = 0.5 * x; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as f32; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: f32; - let mut q0: f32; - let mut q1: f32; - let mut w: f32; - let h: f32; - let mut z: f32; - let mut tmp: f32; - let nf: f32; - let mut k: i32; + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f32; + let mut q0: f32; + let mut q1: f32; + let mut w: f32; + let h: f32; + let mut z: f32; + let mut tmp: f32; + let nf: f32; + let mut k: i32; - nf = (nm1 as f32) + 1.0; - w = 2.0 * (nf as f32) / x; - h = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e4 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as f32) + nf) / x - t); + nf = (nm1 as f32) + 1.0; + w = 2.0 * nf / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e4 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as f32) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * logf(fabsf(w)); + if tmp < 88.721679688 { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as f32) * b / x - a; + a = temp; i -= 1; } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf * logf(fabsf(w)); - if tmp < 88.721679688 { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as f32) * b / x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as f32) * b / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 - if b > x1p60 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; + } else { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as f32) * b / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 + if b > x1p60 { + a /= b; + t /= b; + b = 1.0; } + i -= 1; } - z = j0f(x); - w = j1f(x); - if fabsf(z) >= fabsf(w) { - b = t * z / b; - } else { - b = t * w / a; - } + } + z = j0f(x); + w = j1f(x); + if fabsf(z) >= fabsf(w) { + b = t * z / b; + } else { + b = t * w / a; } } diff --git a/library/compiler-builtins/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/src/math/lgamma_r.rs index b26177e6ebf..6becaad2ce9 100644 --- a/library/compiler-builtins/libm/src/math/lgamma_r.rs +++ b/library/compiler-builtins/libm/src/math/lgamma_r.rs @@ -160,7 +160,8 @@ fn sin_pi(mut x: f64) -> f64 { 1 => k_cos(x, 0.0), 2 => k_sin(-x, 0.0, 0), 3 => -k_cos(x, 0.0), - 0 | _ => k_sin(x, 0.0, 0), + // 0 + _ => k_sin(x, 0.0, 0), } } diff --git a/library/compiler-builtins/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/src/math/lgammaf_r.rs index 723c90daf1e..10cecee541c 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf_r.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf_r.rs @@ -95,7 +95,8 @@ fn sin_pi(mut x: f32) -> f32 { 1 => k_cosf(y), 2 => k_sinf(-y), 3 => -k_cosf(y), - 0 | _ => k_sinf(y), + // 0 + _ => k_sinf(y), } } diff --git a/library/compiler-builtins/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/src/math/nextafter.rs index 05762619109..422bd7496d5 100644 --- a/library/compiler-builtins/libm/src/math/nextafter.rs +++ b/library/compiler-builtins/libm/src/math/nextafter.rs @@ -10,8 +10,8 @@ pub fn nextafter(x: f64, y: f64) -> f64 { return y; } - let ax = ux_i & !1_u64 / 2; - let ay = uy_i & !1_u64 / 2; + let ax = ux_i & (!1_u64 / 2); + let ay = uy_i & (!1_u64 / 2); if ax == 0 { if ay == 0 { return y; diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 7ecad291d18..736465cd16f 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -98,8 +98,8 @@ pub fn pow(x: f64, y: f64) -> f64 { let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); - let mut ix: i32 = (hx & 0x7fffffff) as i32; - let iy: i32 = (hy & 0x7fffffff) as i32; + let mut ix: i32 = hx & 0x7fffffff_i32; + let iy: i32 = hy & 0x7fffffff_i32; /* x**0 = 1, even if x is NaN */ if ((iy as u32) | ly) == 0 { @@ -355,7 +355,7 @@ pub fn pow(x: f64, y: f64) -> f64 { } /* compute 2**(p_h+p_l) */ - let i: i32 = j & (0x7fffffff as i32); + let i: i32 = j & 0x7fffffff_i32; k = (i >> 20) - 0x3ff; let mut n: i32 = 0; diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index 2d9d1e4bbfd..839c6c23d43 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -13,6 +13,8 @@ * ==================================================== */ +use core::cmp::Ordering; + use super::{fabsf, scalbnf, sqrtf}; const BP: [f32; 2] = [1.0, 1.5]; @@ -115,15 +117,13 @@ pub fn powf(x: f32, y: f32) -> f32 { /* special value of y */ if iy == 0x7f800000 { /* y is +-inf */ - if ix == 0x3f800000 { + match ix.cmp(&0x3f800000) { /* (-1)**+-inf is 1 */ - return 1.0; - } else if ix > 0x3f800000 { + Ordering::Equal => return 1.0, /* (|x|>1)**+-inf = inf,0 */ - return if hy >= 0 { y } else { 0.0 }; - } else { + Ordering::Greater => return if hy >= 0 { y } else { 0.0 }, /* (|x|<1)**+-inf = 0,inf */ - return if hy >= 0 { 0.0 } else { -y }; + Ordering::Less => return if hy >= 0 { 0.0 } else { -y }, } } if iy == 0x3f800000 { diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 4dfb8c65883..917e90819a5 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -50,7 +50,7 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { fn medium(x: f64, ix: u32) -> (i32, f64, f64) { /* rint(x/(pi/2)), Assume round-to-nearest. */ - let tmp = x as f64 * INV_PIO2 + TO_INT; + let tmp = x * INV_PIO2 + TO_INT; // force rounding of tmp to it's storage format on x87 to avoid // excess precision issues. #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 1dfbba3b1b2..ec8397f4b6f 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -425,8 +425,6 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> for i in (0..=jz).rev() { fw += i!(fq, i); } - // TODO: drop excess precision here once double_t is used - fw = fw as f64; i!(y, 0, =, if ih == 0 { fw } else { -fw }); fw = i!(fq, 0) - fw; for i in 1..=jz { diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index 423845e44c2..f3360767683 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -67,14 +67,12 @@ pub fn sincosf(x: f32) -> (f32, f32) { } } /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ - else { - if sign { - s = -k_sinf(x as f64 + S2PIO2); - c = -k_cosf(x as f64 + S2PIO2); - } else { - s = -k_sinf(x as f64 - S2PIO2); - c = -k_cosf(x as f64 - S2PIO2); - } + else if sign { + s = -k_sinf(x as f64 + S2PIO2); + c = -k_cosf(x as f64 + S2PIO2); + } else { + s = -k_sinf(x as f64 - S2PIO2); + c = -k_cosf(x as f64 - S2PIO2); } return (s, c); @@ -91,14 +89,12 @@ pub fn sincosf(x: f32) -> (f32, f32) { s = -k_cosf(x as f64 - S3PIO2); c = k_sinf(x as f64 - S3PIO2); } + } else if sign { + s = k_sinf(x as f64 + S4PIO2); + c = k_cosf(x as f64 + S4PIO2); } else { - if sign { - s = k_sinf(x as f64 + S4PIO2); - c = k_cosf(x as f64 + S4PIO2); - } else { - s = k_sinf(x as f64 - S4PIO2); - c = k_cosf(x as f64 - S4PIO2); - } + s = k_sinf(x as f64 - S4PIO2); + c = k_cosf(x as f64 - S4PIO2); } return (s, c); diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index a443b7e4c61..3eaf52cda8e 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -144,13 +144,15 @@ pub fn sqrt(x: f64) -> f64 { ix0 = (ix0 & 0x000fffff) | 0x00100000; if (m & 1) == 1 { /* odd m, double x to make it even */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix0 *= 2; + ix0 += ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; } m >>= 1; /* m = [m/2] */ /* generate sqrt(x) bit by bit */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix0 *= 2; + ix0 += ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; q = 0; /* [q,q1] = sqrt(x) */ q1 = Wrapping(0); @@ -165,7 +167,8 @@ pub fn sqrt(x: f64) -> f64 { ix0 -= t; q += r.0 as i32; } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix0 *= 2; + ix0 += ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; r >>= 1; } @@ -186,7 +189,8 @@ pub fn sqrt(x: f64) -> f64 { ix1 -= t1; q1 += r; } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix0 *= 2; + ix0 += ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; r >>= 1; } diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index c5feef8d726..b08907aa5b8 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -136,6 +136,9 @@ macro_rules! int_impl_common { } fn ilog2(self) -> u32 { + // On our older MSRV, this resolves to the trait method. Which won't actually work, + // but this is only called behind other gates. + #[allow(clippy::incompatible_msrv)] ::ilog2(self) } }; diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs index 3f38c0b1d9f..60451416ab3 100644 --- a/library/compiler-builtins/libm/src/math/tgamma.rs +++ b/library/compiler-builtins/libm/src/math/tgamma.rs @@ -45,7 +45,8 @@ fn sinpi(mut x: f64) -> f64 { 1 => k_cos(x, 0.0), 2 => k_sin(-x, 0.0, 0), 3 => -k_cos(x, 0.0), - 0 | _ => k_sin(x, 0.0, 0), + // 0 + _ => k_sin(x, 0.0, 0), } } @@ -143,7 +144,7 @@ pub fn tgamma(mut x: f64) -> f64 { /* special cases */ if ix >= 0x7ff00000 { /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ - return x + core::f64::INFINITY; + return x + f64::INFINITY; } if ix < ((0x3ff - 54) << 20) { /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ -- cgit 1.4.1-3-g733a5 From 659cdcad33b0baf5d98af698ccd05fa9369a0cc9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 1 Nov 2024 06:32:06 -0500 Subject: Enable clippy for `libm` in CI --- library/compiler-builtins/libm/.github/workflows/main.yml | 10 ++++++++-- library/compiler-builtins/libm/ci/run.sh | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index bfd86497b4e..14e55788479 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -82,8 +82,8 @@ jobs: [ -n "${{ matrix.channel }}" ] && channel="${{ matrix.channel }}" rustup update "$channel" --no-self-update rustup default "$channel" - rustup target add ${{ matrix.target }} - rustup component add llvm-tools-preview + rustup target add "${{ matrix.target }}" + rustup component add clippy llvm-tools-preview - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} @@ -105,6 +105,12 @@ jobs: rustup target add x86_64-unknown-linux-musl cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} + - name: Clippy + run: | + # Run clippy on `libm` + cargo clippy --target "${{ matrix.target }}" --package libm + + builtins: name: Check use with compiler-builtins runs-on: ubuntu-latest diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index a211bc98cbf..32453663e05 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -88,3 +88,4 @@ else $cmd --benches $cmd --benches --release fi + -- cgit 1.4.1-3-g733a5 From 0f9503532b2a52c4fe523c91d3b459c2be09a1fe Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 03:05:45 -0500 Subject: Introduce `hf32!` and `hf64!` macros for hex float support Rust does not have any native way to parse hex floats, but they are heavily used in the C algorithms that we derive from. Introduce a const function that can parse these, as well as macros `hf32!` and `hf64!` that ensure the string literals get handled at compiler time. These are currently not used but making everything available now will ease future development. Co-authored-by: quaternic <57393910+quaternic@users.noreply.github.com> --- library/compiler-builtins/libm/CONTRIBUTING.md | 34 +- .../libm/src/math/support/hex_float.rs | 399 +++++++++++++++++++++ .../libm/src/math/support/macros.rs | 20 ++ .../compiler-builtins/libm/src/math/support/mod.rs | 3 + 4 files changed, 430 insertions(+), 26 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/support/hex_float.rs diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index a39623696c4..0a174163190 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -44,37 +44,19 @@ Check [PR #65] for an example. `mod.rs`. - You may encounter weird literals like `0x1p127f` in the MUSL code. These are hexadecimal floating - point literals. Rust (the language) doesn't support these kind of literals. The best way I have - found to deal with these literals is to turn them into their integer representation using the - [`hexf!`] macro and then turn them back into floats. See below: + point literals. Rust (the language) doesn't support these kind of literals. This crate provides + two macros, `hf32!` and `hf64!`, which convert string literals to floats at compile time. -[`hexf!`]: https://crates.io/crates/hexf - -``` rust -// Step 1: write a program to convert the float into its integer representation -#[macro_use] -extern crate hexf; - -fn main() { - println!("{:#x}", hexf32!("0x1.0p127").to_bits()); -} -``` - -``` console -$ # Step 2: run the program -$ cargo run -0x7f000000 -``` - -``` rust -// Step 3: copy paste the output into libm -let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 12 -``` + ```rust + assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000); + assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000); + ``` - Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`] - newtype to avoid this problem. + newtype to avoid this problem, or individual methods like [`wrapping_add`]. [`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html +[`wrapping_add`]: https://doc.rust-lang.org/std/primitive.u32.html#method.wrapping_add ## Testing diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs new file mode 100644 index 00000000000..80434a5ec3e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -0,0 +1,399 @@ +//! Utilities for working with hex float formats. + +#![allow(dead_code)] // FIXME: remove once this gets used + +/// Construct a 32-bit float from hex float representation (C-style) +pub const fn hf32(s: &str) -> f32 { + f32_from_bits(parse_any(s, 32, 23) as u32) +} + +/// Construct a 64-bit float from hex float representation (C-style) +pub const fn hf64(s: &str) -> f64 { + f64_from_bits(parse_any(s, 64, 52) as u64) +} + +const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 { + let exp_bits: u32 = bits - sig_bits - 1; + let max_msb: i32 = (1 << (exp_bits - 1)) - 1; + // The exponent of one ULP in the subnormals + let min_lsb: i32 = 1 - max_msb - sig_bits as i32; + + let (neg, mut sig, exp) = parse_hex(s.as_bytes()); + + if sig == 0 { + return (neg as u128) << (bits - 1); + } + + // exponents of the least and most significant bits in the value + let lsb = sig.trailing_zeros() as i32; + let msb = u128_ilog2(sig) as i32; + let sig_bits = sig_bits as i32; + + assert!(msb - lsb <= sig_bits, "the value is too precise"); + assert!(msb + exp <= max_msb, "the value is too huge"); + assert!(lsb + exp >= min_lsb, "the value is too tiny"); + + // The parsed value is X = sig * 2^exp + // Expressed as a multiple U of the smallest subnormal value: + // X = U * 2^min_lsb, so U = sig * 2^(exp-min_lsb) + let mut uexp = exp - min_lsb; + + let shift = if uexp + msb >= sig_bits { + // normal, shift msb to position sig_bits + sig_bits - msb + } else { + // subnormal, shift so that uexp becomes 0 + uexp + }; + + if shift >= 0 { + sig <<= shift; + } else { + sig >>= -shift; + } + uexp -= shift; + + // the most significant bit is like having 1 in the exponent bits + // add any leftover exponent to that + assert!(uexp >= 0 && uexp < (1 << exp_bits) - 2); + sig += (uexp as u128) << sig_bits; + + // finally, set the sign bit if necessary + sig | ((neg as u128) << (bits - 1)) +} + +/// Parse a hexadecimal float x +/// returns (s,n,e): +/// s == x.is_sign_negative() +/// n * 2^e == x.abs() +const fn parse_hex(mut b: &[u8]) -> (bool, u128, i32) { + let mut neg = false; + let mut sig: u128 = 0; + let mut exp: i32 = 0; + + if let &[c @ (b'-' | b'+'), ref rest @ ..] = b { + b = rest; + neg = c == b'-'; + } + + if let &[b'0', b'x' | b'X', ref rest @ ..] = b { + b = rest; + } else { + panic!("no hex indicator"); + } + + let mut seen_point = false; + let mut some_digits = false; + + while let &[c, ref rest @ ..] = b { + b = rest; + + match c { + b'.' => { + assert!(!seen_point); + seen_point = true; + continue; + } + b'p' | b'P' => break, + c => { + let digit = hex_digit(c); + some_digits = true; + let of; + (sig, of) = sig.overflowing_mul(16); + assert!(!of, "too many digits"); + sig |= digit as u128; + // up until the fractional point, the value grows + // with more digits, but after it the exponent is + // compensated to match. + if seen_point { + exp -= 4; + } + } + } + } + assert!(some_digits, "at least one digit is required"); + some_digits = false; + + let mut negate_exp = false; + if let &[c @ (b'-' | b'+'), ref rest @ ..] = b { + b = rest; + negate_exp = c == b'-'; + } + + let mut pexp: i32 = 0; + while let &[c, ref rest @ ..] = b { + b = rest; + let digit = dec_digit(c); + some_digits = true; + let of; + (pexp, of) = pexp.overflowing_mul(10); + assert!(!of, "too many exponent digits"); + pexp += digit as i32; + } + assert!(some_digits, "at least one exponent digit is required"); + + if negate_exp { + exp -= pexp; + } else { + exp += pexp; + } + + (neg, sig, exp) +} + +const fn dec_digit(c: u8) -> u8 { + match c { + b'0'..=b'9' => c - b'0', + _ => panic!("bad char"), + } +} + +const fn hex_digit(c: u8) -> u8 { + match c { + b'0'..=b'9' => c - b'0', + b'a'..=b'f' => c - b'a' + 10, + b'A'..=b'F' => c - b'A' + 10, + _ => panic!("bad char"), + } +} + +/* FIXME(msrv): vendor some things that are not const stable at our MSRV */ + +/// `f32::from_bits` +const fn f32_from_bits(v: u32) -> f32 { + unsafe { core::mem::transmute(v) } +} + +/// `f64::from_bits` +const fn f64_from_bits(v: u64) -> f64 { + unsafe { core::mem::transmute(v) } +} + +/// `u128::ilog2` +const fn u128_ilog2(v: u128) -> u32 { + assert!(v != 0); + u128::BITS - 1 - v.leading_zeros() +} + +#[cfg(test)] +mod tests { + extern crate std; + use std::{format, println}; + + use super::*; + + #[test] + fn test_parse_any() { + for k in -149..=127 { + let s = format!("0x1p{k}"); + let x = hf32(&s); + let y = if k < 0 { 0.5f32.powi(-k) } else { 2.0f32.powi(k) }; + assert_eq!(x, y); + } + + let mut s = *b"0x.0000000p-121"; + for e in 0..40 { + for k in 0..(1 << 15) { + let expected = f32::from_bits(k) * 2.0f32.powi(e); + let x = hf32(std::str::from_utf8(&s).unwrap()); + assert_eq!( + x.to_bits(), + expected.to_bits(), + "\ + e={e}\n\ + k={k}\n\ + x={x}\n\ + expected={expected}\n\ + s={}\n\ + f32::from_bits(k)={}\n\ + 2.0f32.powi(e)={}\ + ", + std::str::from_utf8(&s).unwrap(), + f32::from_bits(k), + 2.0f32.powi(e), + ); + for i in (3..10).rev() { + if s[i] == b'f' { + s[i] = b'0'; + } else if s[i] == b'9' { + s[i] = b'a'; + break; + } else { + s[i] += 1; + break; + } + } + } + for i in (12..15).rev() { + if s[i] == b'0' { + s[i] = b'9'; + } else { + s[i] -= 1; + break; + } + } + for i in (3..10).rev() { + s[i] = b'0'; + } + } + } + + #[test] + fn test_f32() { + let checks = [ + ("0x.1234p+16", (0x1234 as f32).to_bits()), + ("0x1.234p+12", (0x1234 as f32).to_bits()), + ("0x12.34p+8", (0x1234 as f32).to_bits()), + ("0x123.4p+4", (0x1234 as f32).to_bits()), + ("0x1234p+0", (0x1234 as f32).to_bits()), + ("0x1234.p+0", (0x1234 as f32).to_bits()), + ("0x1234.0p+0", (0x1234 as f32).to_bits()), + ("0x1.fffffep+127", f32::MAX.to_bits()), + ("0x1.0p+1", 2.0f32.to_bits()), + ("0x1.0p+0", 1.0f32.to_bits()), + ("0x1.ffep+8", 0x43fff000), + ("+0x1.ffep+8", 0x43fff000), + ("0x1p+0", 0x3f800000), + ("0x1.99999ap-4", 0x3dcccccd), + ("0x1.9p+6", 0x42c80000), + ("0x1.2d5ed2p+20", 0x4996af69), + ("-0x1.348eb8p+10", 0xc49a475c), + ("-0x1.33dcfep-33", 0xaf19ee7f), + ("0x0.0p0", 0.0f32.to_bits()), + ("-0x0.0p0", (-0.0f32).to_bits()), + ("0x1.0p0", 1.0f32.to_bits()), + ("0x1.99999ap-4", (0.1f32).to_bits()), + ("-0x1.99999ap-4", (-0.1f32).to_bits()), + ("0x1.111114p-127", 0x00444445), + ("0x1.23456p-130", 0x00091a2b), + ("0x1p-149", 0x00000001), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + let act = hf32(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#010x} != {exp:#010x}\nact: {act:#034b}\nexp: {exp:#034b}" + ); + } + } + + #[test] + fn test_f64() { + let checks = [ + ("0x.1234p+16", (0x1234 as f64).to_bits()), + ("0x1.234p+12", (0x1234 as f64).to_bits()), + ("0x12.34p+8", (0x1234 as f64).to_bits()), + ("0x123.4p+4", (0x1234 as f64).to_bits()), + ("0x1234p+0", (0x1234 as f64).to_bits()), + ("0x1234.p+0", (0x1234 as f64).to_bits()), + ("0x1234.0p+0", (0x1234 as f64).to_bits()), + ("0x1.ffep+8", 0x407ffe0000000000), + ("0x1p+0", 0x3ff0000000000000), + ("0x1.999999999999ap-4", 0x3fb999999999999a), + ("0x1.9p+6", 0x4059000000000000), + ("0x1.2d5ed1fe1da7bp+20", 0x4132d5ed1fe1da7b), + ("-0x1.348eb851eb852p+10", 0xc09348eb851eb852), + ("-0x1.33dcfe54a3803p-33", 0xbde33dcfe54a3803), + ("0x1.0p0", 1.0f64.to_bits()), + ("0x0.0p0", 0.0f64.to_bits()), + ("-0x0.0p0", (-0.0f64).to_bits()), + ("0x1.999999999999ap-4", 0.1f64.to_bits()), + ("0x1.999999999998ap-4", (0.1f64 - f64::EPSILON).to_bits()), + ("-0x1.999999999999ap-4", (-0.1f64).to_bits()), + ("-0x1.999999999998ap-4", (-0.1f64 + f64::EPSILON).to_bits()), + ("0x0.8000000000001p-1022", 0x0008000000000001), + ("0x0.123456789abcdp-1022", 0x000123456789abcd), + ("0x0.0000000000002p-1022", 0x0000000000000002), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + let act = hf64(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#018x} != {exp:#018x}\nact: {act:#066b}\nexp: {exp:#066b}" + ); + } + } + + #[test] + fn test_f32_almost_extra_precision() { + // Exact maximum precision allowed + hf32("0x1.abcdeep+0"); + } + + #[test] + fn test_macros() { + assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000u32); + assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000u64); + } +} + +#[cfg(test)] +// FIXME(ppc): something with `should_panic` tests cause a SIGILL with ppc64le +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +mod tests_panicking { + extern crate std; + use super::*; + + #[test] + #[should_panic] + fn test_f32_extra_precision2() { + // One bit more than the above. + hf32("0x1.ffffffp+127"); + } + + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f32_overflow() { + // One bit more than the above. + hf32("0x1p+128"); + } + + #[test] + #[should_panic(expected = "the value is too precise")] + fn test_f32_extra_precision() { + // One bit more than the above. + hf32("0x1.abcdefp+0"); + } + + #[test] + fn test_f32_tiniest() { + let x = hf32("0x1.p-149"); + let y = hf32("0x0.0000000000000001p-85"); + let z = hf32("0x0.8p-148"); + assert_eq!(x, y); + assert_eq!(x, z); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f32_too_tiny() { + hf32("0x1.p-150"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f32_also_too_tiny() { + hf32("0x0.8p-149"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f32_again_too_tiny() { + hf32("0x0.0000000000000001p-86"); + } + + #[test] + fn test_f64_almost_extra_precision() { + // Exact maximum precision allowed + hf64("0x1.abcdabcdabcdfp+0"); + } + + #[test] + #[should_panic(expected = "the value is too precise")] + fn test_f64_extra_precision() { + // One bit more than the above. + hf64("0x1.abcdabcdabcdf8p+0"); + } +} diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index b14bbec388d..9441eace529 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -105,3 +105,23 @@ macro_rules! select_implementation { (@cfg ; $ex:expr) => { }; (@cfg $provided:meta; $ex:expr) => { #[cfg($provided)] $ex }; } + +/// Construct a 32-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[allow(unused_macros)] +macro_rules! hf32 { + ($s:literal) => {{ + const X: f32 = $crate::math::support::hf32($s); + X + }}; +} + +/// Construct a 64-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[allow(unused_macros)] +macro_rules! hf64 { + ($s:literal) => {{ + const X: f64 = $crate::math::support::hf64($s); + X + }}; +} diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index f054df6cdf3..04a313abc97 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -1,7 +1,10 @@ #[macro_use] pub mod macros; mod float_traits; +mod hex_float; mod int_traits; pub use float_traits::Float; +#[allow(unused_imports)] +pub use hex_float::{hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -- cgit 1.4.1-3-g733a5 From 9a9e47798f903447ffc3beb89b22284009c30e3d Mon Sep 17 00:00:00 2001 From: Johanna Sörngård <44257381+JSorngard@users.noreply.github.com> Date: Fri, 1 Nov 2024 13:29:03 +0100 Subject: Add some more basic docstrings (#352) * Add docstrings to the tgamma functions * Add docstrings to the lgamma functions * Add docstrings to trunc * Add docstrings to exp10 functions --- library/compiler-builtins/libm/src/math/exp10.rs | 1 + library/compiler-builtins/libm/src/math/exp10f.rs | 1 + library/compiler-builtins/libm/src/math/lgamma.rs | 2 ++ library/compiler-builtins/libm/src/math/lgammaf.rs | 2 ++ library/compiler-builtins/libm/src/math/tgamma.rs | 1 + library/compiler-builtins/libm/src/math/tgammaf.rs | 1 + library/compiler-builtins/libm/src/math/trunc.rs | 3 +++ library/compiler-builtins/libm/src/math/truncf.rs | 3 +++ 8 files changed, 14 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs index 559930e109f..2c3df017344 100644 --- a/library/compiler-builtins/libm/src/math/exp10.rs +++ b/library/compiler-builtins/libm/src/math/exp10.rs @@ -6,6 +6,7 @@ const P10: &[f64] = &[ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, ]; +/// Calculates 10 raised to the power of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp10(x: f64) -> f64 { let (mut y, n) = modf(x); diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs index 786305481dc..e81d18380b9 100644 --- a/library/compiler-builtins/libm/src/math/exp10f.rs +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -5,6 +5,7 @@ const LN10_F64: f64 = 3.32192809488736234787031942948939; const P10: &[f32] = &[1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7]; +/// Calculates 10 raised to the power of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp10f(x: f32) -> f32 { let (mut y, n) = modff(x); diff --git a/library/compiler-builtins/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/src/math/lgamma.rs index a08bc5b641e..8312dc18648 100644 --- a/library/compiler-builtins/libm/src/math/lgamma.rs +++ b/library/compiler-builtins/libm/src/math/lgamma.rs @@ -1,5 +1,7 @@ use super::lgamma_r; +/// The natural logarithm of the +/// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgamma(x: f64) -> f64 { lgamma_r(x).0 diff --git a/library/compiler-builtins/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/src/math/lgammaf.rs index a9c2da75bd7..d37512397cb 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf.rs @@ -1,5 +1,7 @@ use super::lgammaf_r; +/// The natural logarithm of the +/// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgammaf(x: f32) -> f32 { lgammaf_r(x).0 diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs index 60451416ab3..3059860646a 100644 --- a/library/compiler-builtins/libm/src/math/tgamma.rs +++ b/library/compiler-builtins/libm/src/math/tgamma.rs @@ -130,6 +130,7 @@ fn s(x: f64) -> f64 { return num / den; } +/// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgamma(mut x: f64) -> f64 { let u: u64 = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/tgammaf.rs b/library/compiler-builtins/libm/src/math/tgammaf.rs index 23e3814f99f..fe178f7a3c0 100644 --- a/library/compiler-builtins/libm/src/math/tgammaf.rs +++ b/library/compiler-builtins/libm/src/math/tgammaf.rs @@ -1,5 +1,6 @@ use super::tgamma; +/// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgammaf(x: f32) -> f32 { tgamma(x as f64) as f32 diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 6961bb95060..34bc2fdfa48 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -1,5 +1,8 @@ use core::f64; +/// Rounds the number toward 0 to the closest integral value (f64). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn trunc(x: f64) -> f64 { select_implementation! { diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index 8270c8eb392..a74f7898772 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -1,5 +1,8 @@ use core::f32; +/// Rounds the number toward 0 to the closest integral value (f32). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn truncf(x: f32) -> f32 { select_implementation! { -- cgit 1.4.1-3-g733a5 From c0f7b95e4350526519ab6c2044d1a1bc273297cd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 1 Nov 2024 07:45:19 -0500 Subject: Resolve clippy errors in `libm` tests and check this in CI --- .../libm/.github/workflows/main.yml | 5 +- library/compiler-builtins/libm/src/math/ceil.rs | 6 +- library/compiler-builtins/libm/src/math/ceilf.rs | 6 +- library/compiler-builtins/libm/src/math/fabs.rs | 8 +- library/compiler-builtins/libm/src/math/fabsf.rs | 8 +- library/compiler-builtins/libm/src/math/floor.rs | 6 +- library/compiler-builtins/libm/src/math/floorf.rs | 6 +- library/compiler-builtins/libm/src/math/pow.rs | 85 ++++++++++------------ library/compiler-builtins/libm/src/math/sqrt.rs | 9 +-- library/compiler-builtins/libm/src/math/sqrtf.rs | 9 +-- 10 files changed, 65 insertions(+), 83 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 14e55788479..c79d637ec03 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -106,9 +106,10 @@ jobs: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} - name: Clippy - run: | + # Tests and utilities can't build on no_std targets + if: "!contains(matrix.target, 'thumb')" # Run clippy on `libm` - cargo clippy --target "${{ matrix.target }}" --package libm + run: cargo clippy --target "${{ matrix.target }}" --package libm --all-targets builtins: diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index c7e857dbb6f..c198ebcfe1b 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -34,8 +34,6 @@ pub fn ceil(x: f64) -> f64 { #[cfg(test)] mod tests { - use core::f64::*; - use super::*; #[test] @@ -48,8 +46,8 @@ mod tests { #[test] fn spec_tests() { // Not Asserted: that the current rounding mode has no effect. - assert!(ceil(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert!(ceil(f64::NAN).is_nan()); + for f in [0.0, -0.0, f64::INFINITY, f64::NEG_INFINITY].iter().copied() { assert_eq!(ceil(f), f); } } diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 0da384350ae..9eb2ec07a42 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -42,8 +42,6 @@ pub fn ceilf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use core::f32::*; - use super::*; #[test] @@ -56,8 +54,8 @@ mod tests { #[test] fn spec_tests() { // Not Asserted: that the current rounding mode has no effect. - assert!(ceilf(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert!(ceilf(f32::NAN).is_nan()); + for f in [0.0, -0.0, f32::INFINITY, f32::NEG_INFINITY].iter().copied() { assert_eq!(ceilf(f), f); } } diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index d7980eb65f2..d083053e188 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -14,8 +14,6 @@ pub fn fabs(x: f64) -> f64 { #[cfg(test)] mod tests { - use core::f64::*; - use super::*; #[test] @@ -27,12 +25,12 @@ mod tests { /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs #[test] fn spec_tests() { - assert!(fabs(NAN).is_nan()); + assert!(fabs(f64::NAN).is_nan()); for f in [0.0, -0.0].iter().copied() { assert_eq!(fabs(f), 0.0); } - for f in [INFINITY, NEG_INFINITY].iter().copied() { - assert_eq!(fabs(f), INFINITY); + for f in [f64::INFINITY, f64::NEG_INFINITY].iter().copied() { + assert_eq!(fabs(f), f64::INFINITY); } } } diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 1dac6389d8f..eabe87254b7 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -16,8 +16,6 @@ pub fn fabsf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use core::f32::*; - use super::*; #[test] @@ -29,12 +27,12 @@ mod tests { /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs #[test] fn spec_tests() { - assert!(fabsf(NAN).is_nan()); + assert!(fabsf(f32::NAN).is_nan()); for f in [0.0, -0.0].iter().copied() { assert_eq!(fabsf(f), 0.0); } - for f in [INFINITY, NEG_INFINITY].iter().copied() { - assert_eq!(fabsf(f), INFINITY); + for f in [f32::INFINITY, f32::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf(f), f32::INFINITY); } } } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index 532226b9f86..e478f6d5472 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -33,8 +33,6 @@ pub fn floor(x: f64) -> f64 { #[cfg(test)] mod tests { - use core::f64::*; - use super::*; #[test] @@ -47,8 +45,8 @@ mod tests { #[test] fn spec_tests() { // Not Asserted: that the current rounding mode has no effect. - assert!(floor(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert!(floor(f64::NAN).is_nan()); + for f in [0.0, -0.0, f64::INFINITY, f64::NEG_INFINITY].iter().copied() { assert_eq!(floor(f), f); } } diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 4f38cb15b7d..bd1570c8696 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -42,8 +42,6 @@ pub fn floorf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use core::f32::*; - use super::*; #[test] @@ -57,8 +55,8 @@ mod tests { #[test] fn spec_tests() { // Not Asserted: that the current rounding mode has no effect. - assert!(floorf(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert!(floorf(f32::NAN).is_nan()); + for f in [0.0, -0.0, f32::INFINITY, f32::NEG_INFINITY].iter().copied() { assert_eq!(floorf(f), f); } } diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 736465cd16f..80b2a24999c 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -398,7 +398,6 @@ mod tests { extern crate core; use self::core::f64::consts::{E, PI}; - use self::core::f64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; use super::pow; const POS_ZERO: &[f64] = &[0.0]; @@ -407,15 +406,15 @@ mod tests { const NEG_ONE: &[f64] = &[-1.0]; const POS_FLOATS: &[f64] = &[99.0 / 70.0, E, PI]; const NEG_FLOATS: &[f64] = &[-99.0 / 70.0, -E, -PI]; - const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), MIN_POSITIVE, EPSILON]; - const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -MIN_POSITIVE, -EPSILON]; - const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, MAX]; - const NEG_EVENS: &[f64] = &[MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; + const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), f64::MIN_POSITIVE, f64::EPSILON]; + const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -f64::MIN_POSITIVE, -f64::EPSILON]; + const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, f64::MAX]; + const NEG_EVENS: &[f64] = &[f64::MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; const POS_ODDS: &[f64] = &[3.0, 7.0]; const NEG_ODDS: &[f64] = &[-7.0, -3.0]; - const NANS: &[f64] = &[NAN]; - const POS_INF: &[f64] = &[INFINITY]; - const NEG_INF: &[f64] = &[NEG_INFINITY]; + const NANS: &[f64] = &[f64::NAN]; + const POS_INF: &[f64] = &[f64::INFINITY]; + const NEG_INF: &[f64] = &[f64::NEG_INFINITY]; const ALL: &[&[f64]] = &[ POS_ZERO, @@ -492,83 +491,83 @@ mod tests { #[test] fn nan_inputs() { // NAN as the base: - // (NAN ^ anything *but 0* should be NAN) - test_sets_as_exponent(NAN, &ALL[2..], NAN); + // (f64::NAN ^ anything *but 0* should be f64::NAN) + test_sets_as_exponent(f64::NAN, &ALL[2..], f64::NAN); - // NAN as the exponent: - // (anything *but 1* ^ NAN should be NAN) - test_sets_as_base(&ALL[..(ALL.len() - 2)], NAN, NAN); + // f64::NAN as the exponent: + // (anything *but 1* ^ f64::NAN should be f64::NAN) + test_sets_as_base(&ALL[..(ALL.len() - 2)], f64::NAN, f64::NAN); } #[test] fn infinity_as_base() { // Positive Infinity as the base: - // (+Infinity ^ positive anything but 0 and NAN should be +Infinity) - test_sets_as_exponent(INFINITY, &POS[1..], INFINITY); + // (+Infinity ^ positive anything but 0 and f64::NAN should be +Infinity) + test_sets_as_exponent(f64::INFINITY, &POS[1..], f64::INFINITY); - // (+Infinity ^ negative anything except 0 and NAN should be 0.0) - test_sets_as_exponent(INFINITY, &NEG[1..], 0.0); + // (+Infinity ^ negative anything except 0 and f64::NAN should be 0.0) + test_sets_as_exponent(f64::INFINITY, &NEG[1..], 0.0); // Negative Infinity as the base: // (-Infinity ^ positive odd ints should be -Infinity) - test_sets_as_exponent(NEG_INFINITY, &[POS_ODDS], NEG_INFINITY); + test_sets_as_exponent(f64::NEG_INFINITY, &[POS_ODDS], f64::NEG_INFINITY); // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) // We can lump in pos/neg odd ints here because they don't seem to // cause panics (div by zero) in release mode (I think). - test_sets(ALL, &|v: f64| pow(NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); + test_sets(ALL, &|v: f64| pow(f64::NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); } #[test] fn infinity_as_exponent() { // Positive/Negative base greater than 1: - // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes NAN as the base) - test_sets_as_base(&ALL[5..(ALL.len() - 2)], INFINITY, INFINITY); + // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes f64::NAN as the base) + test_sets_as_base(&ALL[5..(ALL.len() - 2)], f64::INFINITY, f64::INFINITY); // (pos/neg > 1 ^ -Infinity should be 0.0) - test_sets_as_base(&ALL[5..ALL.len() - 2], NEG_INFINITY, 0.0); + test_sets_as_base(&ALL[5..ALL.len() - 2], f64::NEG_INFINITY, 0.0); // Positive/Negative base less than 1: let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS]; - // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes NAN as the base) - test_sets_as_base(base_below_one, INFINITY, 0.0); + // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes f64::NAN as the base) + test_sets_as_base(base_below_one, f64::INFINITY, 0.0); // (pos/neg < 1 ^ -Infinity should be Infinity) - test_sets_as_base(base_below_one, NEG_INFINITY, INFINITY); + test_sets_as_base(base_below_one, f64::NEG_INFINITY, f64::INFINITY); // Positive/Negative 1 as the base: // (pos/neg 1 ^ Infinity should be 1) - test_sets_as_base(&[NEG_ONE, POS_ONE], INFINITY, 1.0); + test_sets_as_base(&[NEG_ONE, POS_ONE], f64::INFINITY, 1.0); // (pos/neg 1 ^ -Infinity should be 1) - test_sets_as_base(&[NEG_ONE, POS_ONE], NEG_INFINITY, 1.0); + test_sets_as_base(&[NEG_ONE, POS_ONE], f64::NEG_INFINITY, 1.0); } #[test] fn zero_as_base() { // Positive Zero as the base: - // (+0 ^ anything positive but 0 and NAN should be +0) + // (+0 ^ anything positive but 0 and f64::NAN should be +0) test_sets_as_exponent(0.0, &POS[1..], 0.0); - // (+0 ^ anything negative but 0 and NAN should be Infinity) + // (+0 ^ anything negative but 0 and f64::NAN should be Infinity) // (this should panic because we're dividing by zero) - test_sets_as_exponent(0.0, &NEG[1..], INFINITY); + test_sets_as_exponent(0.0, &NEG[1..], f64::INFINITY); // Negative Zero as the base: - // (-0 ^ anything positive but 0, NAN, and odd ints should be +0) + // (-0 ^ anything positive but 0, f64::NAN, and odd ints should be +0) test_sets_as_exponent(-0.0, &POS[3..], 0.0); - // (-0 ^ anything negative but 0, NAN, and odd ints should be Infinity) + // (-0 ^ anything negative but 0, f64::NAN, and odd ints should be Infinity) // (should panic because of divide by zero) - test_sets_as_exponent(-0.0, &NEG[3..], INFINITY); + test_sets_as_exponent(-0.0, &NEG[3..], f64::INFINITY); // (-0 ^ positive odd ints should be -0) test_sets_as_exponent(-0.0, &[POS_ODDS], -0.0); // (-0 ^ negative odd ints should be -Infinity) // (should panic because of divide by zero) - test_sets_as_exponent(-0.0, &[NEG_ODDS], NEG_INFINITY); + test_sets_as_exponent(-0.0, &[NEG_ODDS], f64::NEG_INFINITY); } #[test] @@ -583,21 +582,17 @@ mod tests { // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - (&[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS]).iter().for_each( - |int_set| { - int_set.iter().for_each(|int| { - test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| { - pow(-1.0, *int) * pow(v, *int) - }); - }) - }, - ); + [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| { + int_set.iter().for_each(|int| { + test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| pow(-1.0, *int) * pow(v, *int)); + }) + }); // Negative base (imaginary results): // (-anything except 0 and Infinity ^ non-integer should be NAN) - (&NEG[1..(NEG.len() - 1)]).iter().for_each(|set| { + NEG[1..(NEG.len() - 1)].iter().for_each(|set| { set.iter().for_each(|val| { - test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| NAN); + test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| f64::NAN); }) }); } diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 3eaf52cda8e..d9a8f184ce0 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -224,8 +224,6 @@ pub fn sqrt(x: f64) -> f64 { #[cfg(test)] mod tests { - use core::f64::*; - use super::*; #[test] @@ -239,15 +237,16 @@ mod tests { fn spec_tests() { // Not Asserted: FE_INVALID exception is raised if argument is negative. assert!(sqrt(-1.0).is_nan()); - assert!(sqrt(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY].iter().copied() { + assert!(sqrt(f64::NAN).is_nan()); + for f in [0.0, -0.0, f64::INFINITY].iter().copied() { assert_eq!(sqrt(f), f); } } #[test] + #[allow(clippy::approx_constant)] fn conformance_tests() { - let values = [3.14159265359, 10000.0, f64::from_bits(0x0000000f), INFINITY]; + let values = [3.14159265359, 10000.0, f64::from_bits(0x0000000f), f64::INFINITY]; let results = [ 4610661241675116657u64, 4636737291354636288u64, diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index d2f7ae70334..23f9a844329 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -110,8 +110,6 @@ pub fn sqrtf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use core::f32::*; - use super::*; #[test] @@ -125,15 +123,16 @@ mod tests { fn spec_tests() { // Not Asserted: FE_INVALID exception is raised if argument is negative. assert!(sqrtf(-1.0).is_nan()); - assert!(sqrtf(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY].iter().copied() { + assert!(sqrtf(f32::NAN).is_nan()); + for f in [0.0, -0.0, f32::INFINITY].iter().copied() { assert_eq!(sqrtf(f), f); } } #[test] + #[allow(clippy::approx_constant)] fn conformance_tests() { - let values = [3.14159265359f32, 10000.0f32, f32::from_bits(0x0000000f), INFINITY]; + let values = [3.14159265359f32, 10000.0f32, f32::from_bits(0x0000000f), f32::INFINITY]; let results = [1071833029u32, 1120403456u32, 456082799u32, 2139095040u32]; for i in 0..values.len() { -- cgit 1.4.1-3-g733a5 From 241135794761352bd48642fab948d889435915b8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 1 Nov 2024 06:40:17 -0500 Subject: Fix clippy lints in `crates/` and enable this on CI --- .../libm/.github/workflows/main.yml | 24 ++++++++++++++++------ .../libm/crates/libm-macros/src/lib.rs | 2 +- .../libm/crates/libm-test/src/gen/random.rs | 2 +- .../libm/crates/libm-test/src/precision.rs | 2 +- .../libm/crates/libm-test/src/test_traits.rs | 4 ++-- .../libm/crates/musl-math-sys/build.rs | 2 +- .../libm/crates/musl-math-sys/src/lib.rs | 7 +++++++ 7 files changed, 31 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index c79d637ec03..866f0de9ec0 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -105,12 +105,24 @@ jobs: rustup target add x86_64-unknown-linux-musl cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} - - name: Clippy - # Tests and utilities can't build on no_std targets - if: "!contains(matrix.target, 'thumb')" - # Run clippy on `libm` - run: cargo clippy --target "${{ matrix.target }}" --package libm --all-targets - + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + rustup component add clippy + - uses: Swatinem/rust-cache@v2 + - name: Download musl source + run: ./ci/download-musl.sh + - run: | + cargo clippy --all \ + --exclude cb \ + --features libm-test/build-musl,libm-test/test-multiprecision \ + --all-targets builtins: name: Check use with compiler-builtins diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs index dc78598ca76..41d13035cf4 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs @@ -353,7 +353,7 @@ fn validate(input: &StructuredInput) -> syn::Result> if !input.skip.is_empty() && input.only.is_some() { let e = syn::Error::new( input.only_span.unwrap(), - format!("only one of `skip` or `only` may be specified"), + "only one of `skip` or `only` may be specified", ); return Err(e); } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index d03d1ff797f..e347b3c63ae 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -37,7 +37,7 @@ static TEST_CASES: LazyLock = LazyLock::new(|| make_test_cases(NTES /// value so tests don't run forever. static TEST_CASES_JN: LazyLock = LazyLock::new(|| { // Start with regular test cases - let mut cases = (&*TEST_CASES).clone(); + let mut cases = (*TEST_CASES).clone(); // These functions are extremely slow, limit them let ntests_jn = (NTESTS / 1000).max(80); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 9ef0e818d13..5b021e9467d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -238,7 +238,7 @@ fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Opt // abs and copysign require signaling NaNs to be propagated, so verify bit equality. if actual.to_bits() == expected.to_bits() { - return SKIP; + SKIP } else { Some(Err(anyhow::anyhow!("NaNs have different bitpatterns"))) } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 67df83fb492..e69e16d24a9 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -214,7 +214,7 @@ macro_rules! impl_int { }; } -fn validate_int<'a, I, Input>(actual: I, expected: I, input: Input, ctx: &CheckCtx) -> TestResult +fn validate_int(actual: I, expected: I, input: Input, ctx: &CheckCtx) -> TestResult where I: Int + Hex, Input: Hex + fmt::Debug, @@ -274,7 +274,7 @@ macro_rules! impl_float { }; } -fn validate_float<'a, F, Input>(actual: F, expected: F, input: Input, ctx: &CheckCtx) -> TestResult +fn validate_float(actual: F, expected: F, input: Input, ctx: &CheckCtx) -> TestResult where F: Float + Hex, Input: Hex + fmt::Debug, diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs index 03df06c7934..03deb4ff0ac 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs +++ b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs @@ -124,7 +124,7 @@ fn build_musl_math(cfg: &Config) { // Run configuration steps. Usually done as part of the musl `Makefile`. let obj_include = cfg.out_dir.join("musl_obj/include"); fs::create_dir_all(&obj_include).unwrap(); - fs::create_dir_all(&obj_include.join("bits")).unwrap(); + fs::create_dir_all(obj_include.join("bits")).unwrap(); let sed_stat = Command::new("sed") .arg("-f") .arg(musl_dir.join("tools/mkalltypes.sed")) diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs index fe3c89229b6..db352fab8df 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs +++ b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs @@ -7,6 +7,7 @@ use std::ffi::{c_char, c_int, c_long}; /// unsound. macro_rules! functions { ( $( + $( #[$meta:meta] )* $pfx_name:ident: $name:ident( $($arg:ident: $aty:ty),+ ) -> $rty:ty; )* ) => { extern "C" { @@ -15,6 +16,7 @@ macro_rules! functions { $( // Expose a safe version + $( #[$meta] )* pub fn $name( $($arg: $aty),+ ) -> $rty { // SAFETY: FFI calls with no preconditions unsafe { $pfx_name( $($arg),+ ) } @@ -231,8 +233,13 @@ functions! { musl_logf: logf(a: f32) -> f32; musl_modf: modf(a: f64, b: &mut f64) -> f64; musl_modff: modff(a: f32, b: &mut f32) -> f32; + + // FIXME: these need to be unsafe + #[allow(clippy::not_unsafe_ptr_arg_deref)] musl_nan: nan(a: *const c_char) -> f64; + #[allow(clippy::not_unsafe_ptr_arg_deref)] musl_nanf: nanf(a: *const c_char) -> f32; + musl_nearbyint: nearbyint(a: f64) -> f64; musl_nearbyintf: nearbyintf(a: f32) -> f32; musl_nextafter: nextafter(a: f64, b: f64) -> f64; -- cgit 1.4.1-3-g733a5 From 5b0a775c1244d40c7aa5b20b6f05279a14777374 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 02:44:00 -0500 Subject: Adjust how the proc macro emits types and add an enum Currently the macro always provides `CFn`, `RustFn`, `RustArgs`, etc. Change this so that: 1. This information must be explicily requested in the invocation. 2. There is a new `FTy` field available that emits a single float type, rather than a tuple or signature. Additionally, add two new macros that create enums representing function names. --- .../libm/crates/libm-macros/Cargo.toml | 1 + .../libm/crates/libm-macros/src/enums.rs | 132 ++++++++++++++ .../libm/crates/libm-macros/src/lib.rs | 191 ++++++++++++++++----- .../libm/crates/libm-macros/src/parse.rs | 24 ++- .../libm/crates/libm-macros/tests/basic.rs | 50 +++--- .../libm/crates/libm-macros/tests/enum.rs | 19 ++ 6 files changed, 354 insertions(+), 63 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-macros/src/enums.rs create mode 100644 library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml index 3da9d45a2b9..c9defb1c5cb 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml @@ -8,6 +8,7 @@ publish = false proc-macro = true [dependencies] +heck = "0.5.0" proc-macro2 = "1.0.88" quote = "1.0.37" syn = { version = "2.0.79", features = ["full", "extra-traits", "visit-mut"] } diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs new file mode 100644 index 00000000000..d9017dff72b --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs @@ -0,0 +1,132 @@ +use heck::ToUpperCamelCase; +use proc_macro2 as pm2; +use proc_macro2::{Ident, Span}; +use quote::quote; +use syn::spanned::Spanned; +use syn::{Fields, ItemEnum, Variant}; + +use crate::{ALL_FUNCTIONS_FLAT, base_name}; + +/// Implement `#[function_enum]`, see documentation in `lib.rs`. +pub fn function_enum( + mut item: ItemEnum, + attributes: pm2::TokenStream, +) -> syn::Result { + expect_empty_enum(&item)?; + let attr_span = attributes.span(); + let mut attr = attributes.into_iter(); + + // Attribute should be the identifier of the `BaseName` enum. + let Some(tt) = attr.next() else { + return Err(syn::Error::new(attr_span, "expected one attribute")); + }; + + let pm2::TokenTree::Ident(base_enum) = tt else { + return Err(syn::Error::new(tt.span(), "expected an identifier")); + }; + + if let Some(tt) = attr.next() { + return Err(syn::Error::new(tt.span(), "unexpected token after identifier")); + } + + let enum_name = &item.ident; + let mut as_str_arms = Vec::new(); + let mut base_arms = Vec::new(); + + for func in ALL_FUNCTIONS_FLAT.iter() { + let fn_name = func.name; + let ident = Ident::new(&fn_name.to_upper_camel_case(), Span::call_site()); + let bname_ident = Ident::new(&base_name(fn_name).to_upper_camel_case(), Span::call_site()); + + // Match arm for `fn as_str(self)` matcher + as_str_arms.push(quote! { Self::#ident => #fn_name }); + + // Match arm for `fn base_name(self)` matcher + base_arms.push(quote! { Self::#ident => #base_enum::#bname_ident }); + + let variant = + Variant { attrs: Vec::new(), ident, fields: Fields::Unit, discriminant: None }; + + item.variants.push(variant); + } + + let res = quote! { + // Instantiate the enum + #item + + impl #enum_name { + /// The stringified version of this function name. + const fn as_str(self) -> &'static str { + match self { + #( #as_str_arms , )* + } + } + + /// The base name enum for this function. + const fn base_name(self) -> #base_enum { + match self { + #( #base_arms, )* + } + } + } + }; + + Ok(res) +} + +/// Implement `#[base_name_enum]`, see documentation in `lib.rs`. +pub fn base_name_enum( + mut item: ItemEnum, + attributes: pm2::TokenStream, +) -> syn::Result { + expect_empty_enum(&item)?; + if !attributes.is_empty() { + let sp = attributes.span(); + return Err(syn::Error::new(sp.span(), "no attributes expected")); + } + + let mut base_names: Vec<_> = + ALL_FUNCTIONS_FLAT.iter().map(|func| base_name(func.name)).collect(); + base_names.sort_unstable(); + base_names.dedup(); + + let item_name = &item.ident; + let mut as_str_arms = Vec::new(); + + for base_name in base_names { + let ident = Ident::new(&base_name.to_upper_camel_case(), Span::call_site()); + + // Match arm for `fn as_str(self)` matcher + as_str_arms.push(quote! { Self::#ident => #base_name }); + + let variant = + Variant { attrs: Vec::new(), ident, fields: Fields::Unit, discriminant: None }; + + item.variants.push(variant); + } + + let res = quote! { + // Instantiate the enum + #item + + impl #item_name { + /// The stringified version of this base name. + const fn as_str(self) -> &'static str { + match self { + #( #as_str_arms ),* + } + } + } + }; + + Ok(res) +} + +/// Verify that an enum is empty, otherwise return an error +fn expect_empty_enum(item: &ItemEnum) -> syn::Result<()> { + if !item.variants.is_empty() { + Err(syn::Error::new(item.variants.span(), "expected an empty enum")) + } else { + Ok(()) + } +} diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs index 41d13035cf4..2db412e79a1 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs @@ -1,16 +1,20 @@ +mod enums; mod parse; + use std::sync::LazyLock; use parse::{Invocation, StructuredInput}; use proc_macro as pm; use proc_macro2::{self as pm2, Span}; use quote::{ToTokens, quote}; -use syn::Ident; +use syn::spanned::Spanned; use syn::visit_mut::VisitMut; +use syn::{Ident, ItemEnum}; -const ALL_FUNCTIONS: &[(Signature, Option, &[&str])] = &[ +const ALL_FUNCTIONS: &[(Ty, Signature, Option, &[&str])] = &[ ( // `fn(f32) -> f32` + Ty::F32, Signature { args: &[Ty::F32], returns: &[Ty::F32] }, None, &[ @@ -22,6 +26,7 @@ const ALL_FUNCTIONS: &[(Signature, Option, &[&str])] = &[ ), ( // `(f64) -> f64` + Ty::F64, Signature { args: &[Ty::F64], returns: &[Ty::F64] }, None, &[ @@ -33,6 +38,7 @@ const ALL_FUNCTIONS: &[(Signature, Option, &[&str])] = &[ ), ( // `(f32, f32) -> f32` + Ty::F32, Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] }, None, &[ @@ -50,6 +56,7 @@ const ALL_FUNCTIONS: &[(Signature, Option, &[&str])] = &[ ), ( // `(f64, f64) -> f64` + Ty::F64, Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] }, None, &[ @@ -67,102 +74,120 @@ const ALL_FUNCTIONS: &[(Signature, Option, &[&str])] = &[ ), ( // `(f32, f32, f32) -> f32` + Ty::F32, Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] }, None, &["fmaf"], ), ( // `(f64, f64, f64) -> f64` + Ty::F64, Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] }, None, &["fma"], ), ( // `(f32) -> i32` + Ty::F32, Signature { args: &[Ty::F32], returns: &[Ty::I32] }, None, &["ilogbf"], ), ( // `(f64) -> i32` + Ty::F64, Signature { args: &[Ty::F64], returns: &[Ty::I32] }, None, &["ilogb"], ), ( // `(i32, f32) -> f32` + Ty::F32, Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] }, None, &["jnf"], ), ( // `(i32, f64) -> f64` + Ty::F64, Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] }, None, &["jn"], ), ( // `(f32, i32) -> f32` + Ty::F32, Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] }, None, &["scalbnf", "ldexpf"], ), ( // `(f64, i64) -> f64` + Ty::F64, Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] }, None, &["scalbn", "ldexp"], ), ( // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` + Ty::F32, Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }), &["modff"], ), ( // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` + Ty::F64, Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }), &["modf"], ), ( // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` + Ty::F32, Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] }, Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), &["frexpf", "lgammaf_r"], ), ( // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` + Ty::F64, Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] }, Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), &["frexp", "lgamma_r"], ), ( // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` + Ty::F32, Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] }, Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), &["remquof"], ), ( // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` + Ty::F64, Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] }, Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), &["remquo"], ), ( // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` + Ty::F32, Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }), &["sincosf"], ), ( // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` + Ty::F64, Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }), &["sincos"], ), ]; +const KNOWN_TYPES: &[&str] = &["FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet"]; + /// A type used in a function signature. #[allow(dead_code)] #[derive(Debug, Clone, Copy)] @@ -190,12 +215,12 @@ impl ToTokens for Ty { Ty::F128 => quote! { f128 }, Ty::I32 => quote! { i32 }, Ty::CInt => quote! { ::core::ffi::c_int }, - Ty::MutF16 => quote! { &mut f16 }, - Ty::MutF32 => quote! { &mut f32 }, - Ty::MutF64 => quote! { &mut f64 }, - Ty::MutF128 => quote! { &mut f128 }, - Ty::MutI32 => quote! { &mut i32 }, - Ty::MutCInt => quote! { &mut core::ffi::c_int }, + Ty::MutF16 => quote! { &'a mut f16 }, + Ty::MutF32 => quote! { &'a mut f32 }, + Ty::MutF64 => quote! { &'a mut f64 }, + Ty::MutF128 => quote! { &'a mut f128 }, + Ty::MutI32 => quote! { &'a mut i32 }, + Ty::MutCInt => quote! { &'a mut core::ffi::c_int }, }; tokens.extend(ts); @@ -213,6 +238,7 @@ struct Signature { #[derive(Debug, Clone)] struct FunctionInfo { name: &'static str, + base_fty: Ty, /// Function signature for C implementations c_sig: Signature, /// Function signature for Rust implementations @@ -223,10 +249,11 @@ struct FunctionInfo { static ALL_FUNCTIONS_FLAT: LazyLock> = LazyLock::new(|| { let mut ret = Vec::new(); - for (rust_sig, c_sig, names) in ALL_FUNCTIONS { + for (base_fty, rust_sig, c_sig, names) in ALL_FUNCTIONS { for name in *names { let api = FunctionInfo { name, + base_fty: *base_fty, rust_sig: rust_sig.clone(), c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()), }; @@ -238,6 +265,37 @@ static ALL_FUNCTIONS_FLAT: LazyLock> = LazyLock::new(|| { ret }); +/// Populate an enum with a variant representing function. Names are in upper camel case. +/// +/// Applied to an empty enum. Expects one attribute `#[function_enum(BaseName)]` that provides +/// the name of the `BaseName` enum. +#[proc_macro_attribute] +pub fn function_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> pm::TokenStream { + let item = syn::parse_macro_input!(tokens as ItemEnum); + let res = enums::function_enum(item, attributes.into()); + + match res { + Ok(ts) => ts, + Err(e) => e.into_compile_error(), + } + .into() +} + +/// Create an enum representing all possible base names, with names in upper camel case. +/// +/// Applied to an empty enum. +#[proc_macro_attribute] +pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> pm::TokenStream { + let item = syn::parse_macro_input!(tokens as ItemEnum); + let res = enums::base_name_enum(item, attributes.into()); + + match res { + Ok(ts) => ts, + Err(e) => e.into_compile_error(), + } + .into() +} + /// Do something for each function present in this crate. /// /// Takes a callback macro and invokes it multiple times, once for each function that @@ -258,6 +316,8 @@ static ALL_FUNCTIONS_FLAT: LazyLock> = LazyLock::new(|| { /// ( /// // Name of that function /// fn_name: $fn_name:ident, +/// // The basic float type for this function (e.g. `f32`, `f64`) +/// FTy: $FTy:ty, /// // Function signature of the C version (e.g. `fn(f32, &mut f32) -> f32`) /// CFn: $CFn:ty, /// // A tuple representing the C version's arguments (e.g. `(f32, &mut f32)`) @@ -279,17 +339,16 @@ static ALL_FUNCTIONS_FLAT: LazyLock> = LazyLock::new(|| { /// ) => { }; /// } /// +/// // All fields except for `callback` are optional. /// libm_macros::for_each_function! { /// // The macro to invoke as a callback /// callback: callback_macro, +/// // Which types to include either as a list (`[CFn, RustFn, RustArgs]`) or "all" +/// emit_types: all, /// // Functions to skip, i.e. `callback` shouldn't be called at all for these. -/// // -/// // This is an optional field. /// skip: [sin, cos], /// // Attributes passed as `attrs` for specific functions. For example, here the invocation /// // with `sinf` and that with `cosf` will both get `meta1` and `meta2`, but no others will. -/// // -/// // This is an optional field. /// attributes: [ /// #[meta1] /// #[meta2] @@ -297,8 +356,6 @@ static ALL_FUNCTIONS_FLAT: LazyLock> = LazyLock::new(|| { /// ], /// // Any tokens that should be passed directly to all invocations of the callback. This can /// // be used to pass local variables or other things the macro needs access to. -/// // -/// // This is an optional field. /// extra: [foo], /// // Similar to `extra`, but allow providing a pattern for only specific functions. Uses /// // a simplified match-like syntax. @@ -313,7 +370,7 @@ pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream { let input = syn::parse_macro_input!(tokens as Invocation); let res = StructuredInput::from_fields(input) - .and_then(|s_in| validate(&s_in).map(|fn_list| (s_in, fn_list))) + .and_then(|mut s_in| validate(&mut s_in).map(|fn_list| (s_in, fn_list))) .and_then(|(s_in, fn_list)| expand(s_in, &fn_list)); match res { @@ -325,7 +382,7 @@ pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream { /// Check for any input that is structurally correct but has other problems. /// /// Returns the list of function names that we should expand for. -fn validate(input: &StructuredInput) -> syn::Result> { +fn validate(input: &mut StructuredInput) -> syn::Result> { // Collect lists of all functions that are provied as macro inputs in various fields (only, // skip, attributes). let attr_mentions = input @@ -376,6 +433,43 @@ fn validate(input: &StructuredInput) -> syn::Result> fn_list.push(func); } + // Types that the user would like us to provide in the macro + let mut add_all_types = false; + for ty in &input.emit_types { + let ty_name = ty.to_string(); + if ty_name == "all" { + add_all_types = true; + continue; + } + + // Check that all requested types are valid + if !KNOWN_TYPES.contains(&ty_name.as_str()) { + let e = syn::Error::new( + ty_name.span(), + format!("unrecognized type identifier `{ty_name}`"), + ); + return Err(e); + } + } + + if add_all_types { + // Ensure that if `all` was specified that nothing else was + if input.emit_types.len() > 1 { + let e = syn::Error::new( + input.emit_types_span.unwrap(), + "if `all` is specified, no other type identifiers may be given", + ); + return Err(e); + } + + // ...and then add all types + input.emit_types.clear(); + for ty in KNOWN_TYPES { + let ident = Ident::new(ty, Span::call_site()); + input.emit_types.push(ident); + } + } + if let Some(map) = &input.fn_extra { if !map.keys().any(|key| key == "_") { // No default provided; make sure every expected function is covered @@ -451,20 +545,31 @@ fn expand(input: StructuredInput, fn_list: &[&FunctionInfo]) -> syn::Result pm2::TokenStream::new(), }; + let base_fty = func.base_fty; let c_args = &func.c_sig.args; let c_ret = &func.c_sig.returns; let rust_args = &func.rust_sig.args; let rust_ret = &func.rust_sig.returns; + let mut ty_fields = Vec::new(); + for ty in &input.emit_types { + let field = match ty.to_string().as_str() { + "FTy" => quote! { FTy: #base_fty, }, + "CFn" => quote! { CFn: fn( #(#c_args),* ,) -> ( #(#c_ret),* ), }, + "CArgs" => quote! { CArgs: ( #(#c_args),* ,), }, + "CRet" => quote! { CRet: ( #(#c_ret),* ), }, + "RustFn" => quote! { RustFn: fn( #(#rust_args),* ,) -> ( #(#rust_ret),* ), }, + "RustArgs" => quote! { RustArgs: ( #(#rust_args),* ,), }, + "RustRet" => quote! { RustRet: ( #(#rust_ret),* ), }, + _ => unreachable!("checked in validation"), + }; + ty_fields.push(field); + } + let new = quote! { #callback! { fn_name: #fn_name, - CFn: fn( #(#c_args),* ,) -> ( #(#c_ret),* ), - CArgs: ( #(#c_args),* ,), - CRet: ( #(#c_ret),* ), - RustFn: fn( #(#rust_args),* ,) -> ( #(#rust_ret),* ), - RustArgs: ( #(#rust_args),* ,), - RustRet: ( #(#rust_ret),* ), + #( #ty_fields )* #meta_field #extra_field #fn_extra_field @@ -488,24 +593,7 @@ struct MacroReplace { impl MacroReplace { fn new(name: &'static str) -> Self { - // Keep this in sync with `libm_test::canonical_name` - let known_mappings = &[ - ("erff", "erf"), - ("erf", "erf"), - ("lgammaf_r", "lgamma_r"), - ("modff", "modf"), - ("modf", "modf"), - ]; - - let norm_name = match known_mappings.iter().find(|known| known.0 == name) { - Some(found) => found.1, - None => name - .strip_suffix("f") - .or_else(|| name.strip_suffix("f16")) - .or_else(|| name.strip_suffix("f128")) - .unwrap_or(name), - }; - + let norm_name = base_name(name); Self { fn_name: name, norm_name: norm_name.to_owned(), error: None } } @@ -539,3 +627,24 @@ impl VisitMut for MacroReplace { syn::visit_mut::visit_ident_mut(self, i); } } + +/// Return the unsuffixed name of a function. +fn base_name(name: &str) -> &str { + // Keep this in sync with `libm_test::base_name` + let known_mappings = &[ + ("erff", "erf"), + ("erf", "erf"), + ("lgammaf_r", "lgamma_r"), + ("modff", "modf"), + ("modf", "modf"), + ]; + + match known_mappings.iter().find(|known| known.0 == name) { + Some(found) => found.1, + None => name + .strip_suffix("f") + .or_else(|| name.strip_suffix("f16")) + .or_else(|| name.strip_suffix("f128")) + .unwrap_or(name), + } +} diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs b/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs index ee9bd524bbe..369bbae2f4f 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs @@ -5,7 +5,7 @@ use quote::ToTokens; use syn::parse::{Parse, ParseStream, Parser}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; -use syn::token::Comma; +use syn::token::{self, Comma}; use syn::{Arm, Attribute, Expr, ExprMatch, Ident, Meta, Token, bracketed}; /// The input to our macro; just a list of `field: value` items. @@ -39,6 +39,9 @@ impl Parse for Mapping { pub struct StructuredInput { /// Macro to invoke once per function pub callback: Ident, + /// Whether or not to provide `CFn` `CArgs` `RustFn` etc. This is really only needed + /// once for crate to set up the main trait. + pub emit_types: Vec, /// Skip these functions pub skip: Vec, /// Invoke only for these functions @@ -50,6 +53,7 @@ pub struct StructuredInput { /// Per-function extra expressions to pass to the macro pub fn_extra: Option>, // For diagnostics + pub emit_types_span: Option, pub only_span: Option, pub fn_extra_span: Option, } @@ -58,6 +62,7 @@ impl StructuredInput { pub fn from_fields(input: Invocation) -> syn::Result { let mut map: Vec<_> = input.fields.into_iter().collect(); let cb_expr = expect_field(&mut map, "callback")?; + let emit_types_expr = expect_field(&mut map, "emit_types").ok(); let skip_expr = expect_field(&mut map, "skip").ok(); let only_expr = expect_field(&mut map, "only").ok(); let attr_expr = expect_field(&mut map, "attributes").ok(); @@ -71,6 +76,12 @@ impl StructuredInput { ))?; } + let emit_types_span = emit_types_expr.as_ref().map(|expr| expr.span()); + let emit_types = match emit_types_expr { + Some(expr) => Parser::parse2(parse_ident_or_array, expr.into_token_stream())?, + None => Vec::new(), + }; + let skip = match skip_expr { Some(expr) => Parser::parse2(parse_ident_array, expr.into_token_stream())?, None => Vec::new(), @@ -103,6 +114,7 @@ impl StructuredInput { Ok(Self { callback: expect_ident(cb_expr)?, + emit_types, skip, only, only_span, @@ -110,6 +122,7 @@ impl StructuredInput { extra, fn_extra, fn_extra_span, + emit_types_span, }) } } @@ -183,6 +196,15 @@ fn expect_ident(expr: Expr) -> syn::Result { syn::parse2(expr.into_token_stream()) } +/// Parse either a single identifier (`foo`) or an array of identifiers (`[foo, bar, baz]`). +fn parse_ident_or_array(input: ParseStream) -> syn::Result> { + if !input.peek(token::Bracket) { + return Ok(vec![input.parse()?]); + } + + parse_ident_array(input) +} + /// Parse an array of expressions. fn parse_expr_array(input: ParseStream) -> syn::Result> { let content; diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs index 8f8c09f1b64..2eaba04f4c6 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs @@ -4,6 +4,7 @@ macro_rules! basic { ( fn_name: $fn_name:ident, + FTy: $FTy:ty, CFn: $CFn:ty, CArgs: $CArgs:ty, CRet: $CRet:ty, @@ -17,9 +18,9 @@ macro_rules! basic { $(#[$meta])* mod $fn_name { #[allow(unused)] - type CFnTy = $CFn; - // type CArgsTy<'_> = $CArgs; - // type CRetTy<'_> = $CRet; + type FTy= $FTy; + #[allow(unused)] + type CFnTy<'a> = $CFn; #[allow(unused)] type RustFnTy = $RustFn; #[allow(unused)] @@ -39,6 +40,7 @@ macro_rules! basic { mod test_basic { libm_macros::for_each_function! { callback: basic, + emit_types: all, skip: [sin, cos], attributes: [ // just some random attributes @@ -58,25 +60,8 @@ mod test_basic { macro_rules! basic_no_extra { ( fn_name: $fn_name:ident, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: $RustFn:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, ) => { - mod $fn_name { - #[allow(unused)] - type CFnTy = $CFn; - // type CArgsTy<'_> = $CArgs; - // type CRetTy<'_> = $CRet; - #[allow(unused)] - type RustFnTy = $RustFn; - #[allow(unused)] - type RustArgsTy = $RustArgs; - #[allow(unused)] - type RustRetTy = $RustRet; - } + mod $fn_name {} }; } @@ -94,3 +79,26 @@ mod test_only { only: [sin, sinf], } } + +macro_rules! specified_types { + ( + fn_name: $fn_name:ident, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + ) => { + mod $fn_name { + #[allow(unused)] + type RustFnTy = $RustFn; + #[allow(unused)] + type RustArgsTy = $RustArgs; + } + }; +} + +mod test_emit_types { + // Test that we can specify a couple types to emit + libm_macros::for_each_function! { + callback: specified_types, + emit_types: [RustFn, RustArgs], + } +} diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs new file mode 100644 index 00000000000..884b8d8d651 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs @@ -0,0 +1,19 @@ +#[libm_macros::function_enum(BaseName)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Function {} + +#[libm_macros::base_name_enum] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum BaseName {} + +#[test] +fn as_str() { + assert_eq!(Function::Sin.as_str(), "sin"); + assert_eq!(Function::Sinf.as_str(), "sinf"); +} + +#[test] +fn basename() { + assert_eq!(Function::Sin.base_name(), BaseName::Sin); + assert_eq!(Function::Sinf.base_name(), BaseName::Sin); +} -- cgit 1.4.1-3-g733a5 From 7db74d78e8918eaa091f546931a3b7b9b64b68b4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 02:45:37 -0500 Subject: Introduce a `op` module with struct representations of each routine This contains: 1. Per-function and per-operation enums created by the proc macro 2. The `MathOp` trait which is implemented once per struct representing a function 3. Submodules for each function, each containing a `Routine` struct that implements `MathOp` --- .../libm/crates/libm-test/src/lib.rs | 2 + .../libm/crates/libm-test/src/op.rs | 111 +++++++++++++++++++++ .../libm/crates/libm-test/src/test_traits.rs | 4 +- 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/op.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 56a872779d6..e64ad626408 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,10 +1,12 @@ pub mod gen; #[cfg(feature = "test-multiprecision")] pub mod mpfloat; +pub mod op; mod precision; mod test_traits; pub use libm::support::{Float, Int}; +pub use op::{BaseName, MathOp, Name}; pub use precision::{MaybeOverride, SpecialCase, multiprec_allowed_ulp, musl_allowed_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs new file mode 100644 index 00000000000..fe0a08a28e5 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -0,0 +1,111 @@ +//! Types representing individual functions. +//! +//! Each routine gets a module with its name, e.g. `mod sinf { /* ... */ }`. The module +//! contains a unit struct `Routine` which implements `MathOp`. +//! +//! Basically everything could be called a "function" here, so we loosely use the following +//! terminology: +//! +//! - "Function": the math operation that does not have an associated precision. E.g. `f(x) = e^x`, +//! `f(x) = log(x)`. +//! - "Routine": A code implementation of a math operation with a specific precision. E.g. `exp`, +//! `expf`, `expl`, `log`, `logf`. +//! - "Operation" / "Op": Something that relates a routine to a function or is otherwise higher +//! level. `Op` is also used as the name for generic parameters since it is terse. + +use crate::{CheckOutput, Float, TupleCall}; + +/// An enum representing each possible routine name. +#[libm_macros::function_enum(BaseName)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Name {} + +/// The name without any type specifier, e.g. `sin` and `sinf` both become `sin`. +#[libm_macros::base_name_enum] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum BaseName {} + +/// Attributes ascribed to a `libm` routine including signature, type information, +/// and naming. +pub trait MathOp { + /// The float type used for this operation. + type FTy: Float; + + /// The function type representing the signature in a C library. + type CFn: Copy; + + /// Arguments passed to the C library function as a tuple. These may include `&mut` return + /// values. + type CArgs<'a> + where + Self: 'a; + + /// The type returned by C implementations. + type CRet; + + /// The signature of the Rust function as a `fn(...) -> ...` type. + type RustFn: Copy; + + /// Arguments passed to the Rust library function as a tuple. + /// + /// The required `TupleCall` bounds ensure this type can be passed either to the C function or + /// to the Rust function. + type RustArgs: Copy + + TupleCall + + TupleCall; + + /// Type returned from the Rust function. + type RustRet: CheckOutput; + + /// The name of this function, including suffix (e.g. `sin`, `sinf`). + const NAME: Name; + + /// The name as a string. + const NAME_STR: &'static str = Self::NAME.as_str(); + + /// The name of the function excluding the type suffix, e.g. `sin` and `sinf` are both `sin`. + const BASE_NAME: BaseName = Self::NAME.base_name(); + + /// The function in `libm` which can be called. + const ROUTINE: Self::RustFn; +} + +macro_rules! do_thing { + // Matcher for unary functions + ( + fn_name: $fn_name:ident, + FTy: $FTy:ty, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + ) => { + paste::paste! { + pub mod $fn_name { + use super::*; + pub struct Routine; + + impl MathOp for Routine { + type FTy = $FTy; + type CFn = for<'a> $CFn; + type CArgs<'a> = $CArgs where Self: 'a; + type CRet = $CRet; + type RustFn = $RustFn; + type RustArgs = $RustArgs; + type RustRet = $RustRet; + + const NAME: Name = Name::[< $fn_name:camel >]; + const ROUTINE: Self::RustFn = libm::$fn_name; + } + } + + } + }; +} + +libm_macros::for_each_function! { + callback: do_thing, + emit_types: all, +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index e69e16d24a9..b9bec9a4479 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -137,7 +137,7 @@ where } } -impl TupleCall for (T1,) +impl TupleCall fn(T1, &'a mut T2, &'a mut T3)> for (T1,) where T1: fmt::Debug, T2: fmt::Debug + Default, @@ -145,7 +145,7 @@ where { type Output = (T2, T3); - fn call(self, f: fn(T1, &mut T2, &mut T3)) -> Self::Output { + fn call(self, f: for<'a> fn(T1, &'a mut T2, &'a mut T3)) -> Self::Output { let mut t2 = T2::default(); let mut t3 = T3::default(); f(self.0, &mut t2, &mut t3); -- cgit 1.4.1-3-g733a5 From f7f24a4ed899d75179176709622d4f6912188262 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 02:46:21 -0500 Subject: Rework tests to make use of the new `MathOp` trait --- .../libm/crates/libm-test/benches/random.rs | 129 +++++--- .../libm/crates/libm-test/src/mpfloat.rs | 355 +++++++++------------ .../libm/crates/libm-test/tests/check_coverage.rs | 6 - .../crates/libm-test/tests/compare_built_musl.rs | 54 ++-- .../libm/crates/libm-test/tests/multiprecision.rs | 49 +-- 5 files changed, 278 insertions(+), 315 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 6c9047c3cdb..6f2305dd27e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -2,72 +2,103 @@ use std::hint::black_box; use std::time::Duration; use criterion::{Criterion, criterion_main}; -use libm_test::gen::random; -use libm_test::{CheckBasis, CheckCtx, TupleCall}; +use libm_test::gen::{CachedInput, random}; +use libm_test::{CheckBasis, CheckCtx, GenerateInput, MathOp, TupleCall}; /// Benchmark with this many items to get a variety const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { 50 } else { 500 }; +/// Extra parameters we only care about if we are benchmarking against musl. +#[allow(dead_code)] +struct MuslExtra { + musl_fn: Option, + skip_on_i586: bool, +} + macro_rules! musl_rand_benches { ( fn_name: $fn_name:ident, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: $RustFn:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, fn_extra: $skip_on_i586:expr, ) => { paste::paste! { fn [< musl_bench_ $fn_name >](c: &mut Criterion) { - let fn_name = stringify!($fn_name); - - let ulp = libm_test::musl_allowed_ulp(fn_name); - let ctx = CheckCtx::new(ulp, fn_name, CheckBasis::Musl); - let benchvec: Vec<_> = random::get_test_cases::<$RustArgs>(&ctx) - .take(BENCH_ITER_ITEMS) - .collect(); + type Op = libm_test::op::$fn_name::Routine; - // Perform a sanity check that we are benchmarking the same thing - // Don't test against musl if it is not available #[cfg(feature = "build-musl")] - for input in benchvec.iter().copied() { - use anyhow::Context; - use libm_test::{CheckBasis, CheckCtx, CheckOutput}; + let musl_extra = MuslExtra { + musl_fn: Some(musl_math_sys::$fn_name as ::CFn), + skip_on_i586: $skip_on_i586 + }; + + #[cfg(not(feature = "build-musl"))] + let musl_extra = MuslExtra { + musl_fn: None, + skip_on_i586: $skip_on_i586 + }; + + bench_one::(c, musl_extra); + } + } + }; +} - if cfg!(x86_no_sse) && $skip_on_i586 { - break; - } +fn bench_one(c: &mut Criterion, musl_extra: MuslExtra) +where + Op: MathOp, + CachedInput: GenerateInput, +{ + let name = Op::NAME_STR; + + let ulp = libm_test::musl_allowed_ulp(name); + let ctx = CheckCtx::new(ulp, name, CheckBasis::Musl); + let benchvec: Vec<_> = + random::get_test_cases::(&ctx).take(BENCH_ITER_ITEMS).collect(); + + // Perform a sanity check that we are benchmarking the same thing + // Don't test against musl if it is not available + #[cfg(feature = "build-musl")] + for input in benchvec.iter().copied() { + use anyhow::Context; + use libm_test::CheckOutput; + + if cfg!(x86_no_sse) && musl_extra.skip_on_i586 { + break; + } - let musl_res = input.call(musl_math_sys::$fn_name as $CFn); - let crate_res = input.call(libm::$fn_name as $RustFn); + let musl_res = input.call(musl_extra.musl_fn.unwrap()); + let crate_res = input.call(Op::ROUTINE); - let ctx = CheckCtx::new(ulp, fn_name, CheckBasis::Musl); - crate_res.validate(musl_res, input, &ctx).context(fn_name).unwrap(); - } + crate_res.validate(musl_res, input, &ctx).context(name).unwrap(); + } - /* Function pointers are black boxed to avoid inlining in the benchmark loop */ + #[cfg(not(feature = "build-musl"))] + let _ = musl_extra; // silence unused warnings - let mut group = c.benchmark_group(fn_name); - group.bench_function("crate", |b| b.iter(|| { - let f = black_box(libm::$fn_name as $RustFn); - for input in benchvec.iter().copied() { - input.call(f); - } - })); + /* Option pointers are black boxed to avoid inlining in the benchmark loop */ - // Don't test against musl if it is not available - #[cfg(feature = "build-musl")] - group.bench_function("musl", |b| b.iter(|| { - let f = black_box(musl_math_sys::$fn_name as $CFn); - for input in benchvec.iter().copied() { - input.call(f); - } - })); + let mut group = c.benchmark_group(name); + group.bench_function("crate", |b| { + b.iter(|| { + let f = black_box(Op::ROUTINE); + for input in benchvec.iter().copied() { + input.call(f); } - } - }; + }) + }); + + // Don't test against musl if it is not available + #[cfg(feature = "build-musl")] + { + let musl_fn = musl_extra.musl_fn.unwrap(); + group.bench_function("musl", |b| { + b.iter(|| { + let f = black_box(musl_fn); + for input in benchvec.iter().copied() { + input.call(f); + } + }) + }); + } } libm_macros::for_each_function! { @@ -83,12 +114,6 @@ libm_macros::for_each_function! { macro_rules! run_callback { ( fn_name: $fn_name:ident, - CFn: $_CFn:ty, - CArgs: $_CArgs:ty, - CRet: $_CRet:ty, - RustFn: $_RustFn:ty, - RustArgs: $_RustArgs:ty, - RustRet: $_RustRet:ty, extra: [$criterion:ident], ) => { paste::paste! { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 2e6fdae7f19..507b077b37c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -11,7 +11,7 @@ pub use rug::Float as MpFloat; use rug::float::Round::Nearest; use rug::ops::{PowAssignRound, RemAssignRound}; -use crate::Float; +use crate::{Float, MathOp}; /// Create a multiple-precision float with the correct number of bits for a concrete float type. fn new_mpfloat() -> MpFloat { @@ -29,23 +29,19 @@ where /// Structures that represent a float operation. /// -/// The struct itself should hold any context that can be reused among calls to `run` (allocated -/// `MpFloat`s). -pub trait MpOp { - /// Inputs to the operation (concrete float types). - type Input; - - /// Outputs from the operation (concrete float types). - type Output; +pub trait MpOp: MathOp { + /// The struct itself should hold any context that can be reused among calls to `run` (allocated + /// `MpFloat`s). + type MpTy; /// Create a new instance. - fn new() -> Self; + fn new_mp() -> Self::MpTy; /// Perform the operation. /// /// Usually this means assigning inputs to cached floats, performing the operation, applying /// subnormal approximation, and converting the result back to concrete values. - fn run(&mut self, input: Self::Input) -> Self::Output; + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet; } /// Implement `MpOp` for functions with a single return value. @@ -53,32 +49,21 @@ macro_rules! impl_mp_op { // Matcher for unary functions ( fn_name: $fn_name:ident, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: fn($fty:ty,) -> $_ret:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, + RustFn: fn($_fty:ty,) -> $_ret:ty, fn_extra: $fn_name_normalized:expr, ) => { paste::paste! { - pub mod $fn_name { - use super::*; - pub struct Operation(MpFloat); - - impl MpOp for Operation { - type Input = $RustArgs; - type Output = $RustRet; - - fn new() -> Self { - Self(new_mpfloat::<$fty>()) - } - - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - let ord = self.0.[< $fn_name_normalized _round >](Nearest); - prep_retval::(&mut self.0, ord) - } + impl MpOp for crate::op::$fn_name::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + let ord = this.[< $fn_name_normalized _round >](Nearest); + prep_retval::(this, ord) } } } @@ -86,33 +71,22 @@ macro_rules! impl_mp_op { // Matcher for binary functions ( fn_name: $fn_name:ident, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: fn($fty:ty, $_fty2:ty,) -> $_ret:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, + RustFn: fn($_fty:ty, $_fty2:ty,) -> $_ret:ty, fn_extra: $fn_name_normalized:expr, ) => { paste::paste! { - pub mod $fn_name { - use super::*; - pub struct Operation(MpFloat, MpFloat); - - impl MpOp for Operation { - type Input = $RustArgs; - type Output = $RustRet; - - fn new() -> Self { - Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) - } - - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.1.assign(input.1); - let ord = self.0.[< $fn_name_normalized _round >](&self.1, Nearest); - prep_retval::(&mut self.0, ord) - } + impl MpOp for crate::op::$fn_name::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = this.0.[< $fn_name_normalized _round >](&this.1, Nearest); + prep_retval::(&mut this.0, ord) } } } @@ -120,34 +94,27 @@ macro_rules! impl_mp_op { // Matcher for ternary functions ( fn_name: $fn_name:ident, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: fn($fty:ty, $_fty2:ty, $_fty3:ty,) -> $_ret:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, + RustFn: fn($_fty:ty, $_fty2:ty, $_fty3:ty,) -> $_ret:ty, fn_extra: $fn_name_normalized:expr, ) => { paste::paste! { - pub mod $fn_name { - use super::*; - pub struct Operation(MpFloat, MpFloat, MpFloat); - - impl MpOp for Operation { - type Input = $RustArgs; - type Output = $RustRet; - - fn new() -> Self { - Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) - } - - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.1.assign(input.1); - self.2.assign(input.2); - let ord = self.0.[< $fn_name_normalized _round >](&self.1, &self.2, Nearest); - prep_retval::(&mut self.0, ord) - } + impl MpOp for crate::op::$fn_name::Routine { + type MpTy = (MpFloat, MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + ( + new_mpfloat::(), + new_mpfloat::(), + new_mpfloat::(), + ) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + this.2.assign(input.2); + let ord = this.0.[< $fn_name_normalized _round >](&this.1, &this.2, Nearest); + prep_retval::(&mut this.0, ord) } } } @@ -156,6 +123,7 @@ macro_rules! impl_mp_op { libm_macros::for_each_function! { callback: impl_mp_op, + emit_types: [RustFn], skip: [ // Most of these need a manual implementation fabs, ceil, copysign, floor, rint, round, trunc, @@ -186,29 +154,23 @@ macro_rules! impl_no_round { ($($fn_name:ident, $rug_name:ident;)*) => { paste::paste! { // Implement for both f32 and f64 - $( impl_no_round!{ @inner_unary [< $fn_name f >], (f32,), $rug_name } )* - $( impl_no_round!{ @inner_unary $fn_name, (f64,), $rug_name } )* + $( impl_no_round!{ @inner_unary [< $fn_name f >], $rug_name } )* + $( impl_no_round!{ @inner_unary $fn_name, $rug_name } )* } }; - (@inner_unary $fn_name:ident, ($fty:ty,), $rug_name:ident) => { - pub mod $fn_name { - use super::*; - pub struct Operation(MpFloat); + (@inner_unary $fn_name:ident, $rug_name:ident) => { + impl MpOp for crate::op::$fn_name::Routine { + type MpTy = MpFloat; - impl MpOp for Operation { - type Input = ($fty,); - type Output = $fty; - - fn new() -> Self { - Self(new_mpfloat::<$fty>()) - } + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.0.$rug_name(); - prep_retval::(&mut self.0, Ordering::Equal) - } + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + this.$rug_name(); + prep_retval::(this, Ordering::Equal) } } }; @@ -227,132 +189,81 @@ impl_no_round! { macro_rules! impl_op_for_ty { ($fty:ty, $suffix:literal) => { paste::paste! { - pub mod [] { - use super::*; - pub struct Operation(MpFloat, MpFloat); - - impl MpOp for Operation { - type Input = ($fty, $fty); - type Output = $fty; - - fn new() -> Self { - Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) - } - - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.1.assign(input.1); - self.0.copysign_mut(&self.1); - prep_retval::(&mut self.0, Ordering::Equal) - } + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) } - } - pub mod [] { - use super::*; - pub struct Operation(MpFloat, MpFloat); + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + this.0.copysign_mut(&this.1); + prep_retval::(&mut this.0, Ordering::Equal) + } + } - impl MpOp for Operation { - type Input = ($fty, $fty); - type Output = $fty; + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); - fn new() -> Self { - Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) - } + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.1.assign(input.1); - let ord = self.0.pow_assign_round(&self.1, Nearest); - prep_retval::(&mut self.0, ord) - } + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = this.0.pow_assign_round(&this.1, Nearest); + prep_retval::(&mut this.0, ord) } } - pub mod [] { - use super::*; - pub struct Operation(MpFloat, MpFloat); + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); - impl MpOp for Operation { - type Input = ($fty, $fty); - type Output = $fty; - - fn new() -> Self { - Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) - } + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.1.assign(input.1); - let ord = self.0.rem_assign_round(&self.1, Nearest); - prep_retval::(&mut self.0, ord) - } + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = this.0.rem_assign_round(&this.1, Nearest); + prep_retval::(&mut this.0, ord) } } - pub mod [] { - use super::*; - pub struct Operation(MpFloat); - - impl MpOp for Operation { - type Input = ($fty,); - type Output = ($fty, i32); + impl MpOp for crate::op::[]::Routine { + type MpTy = (i32, MpFloat); - fn new() -> Self { - Self(new_mpfloat::<$fty>()) - } + fn new_mp() -> Self::MpTy { + (0, new_mpfloat::()) + } - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - let (sign, ord) = self.0.ln_abs_gamma_round(Nearest); - let ret = prep_retval::<$fty>(&mut self.0, ord); - (ret, sign as i32) - } + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0 = input.0; + this.1.assign(input.1); + let ord = this.1.jn_round(this.0, Nearest); + prep_retval::(&mut this.1, ord) } } - pub mod [] { - use super::*; - pub struct Operation(i32, MpFloat); - - impl MpOp for Operation { - type Input = (i32, $fty); - type Output = $fty; + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); - fn new() -> Self { - Self(0, new_mpfloat::<$fty>()) - } - - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0 = input.0; - self.1.assign(input.1); - let ord = self.1.jn_round(self.0, Nearest); - prep_retval::<$fty>(&mut self.1, ord) - } + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) } - } - pub mod [] { - use super::*; - pub struct Operation(MpFloat, MpFloat); - - impl MpOp for Operation { - type Input = ($fty,); - type Output = ($fty, $fty); - - fn new() -> Self { - Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) - } - - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.1.assign(0.0); - let (sord, cord) = self.0.sin_cos_round(&mut self.1, Nearest); - ( - prep_retval::<$fty>(&mut self.0, sord), - prep_retval::<$fty>(&mut self.1, cord) - ) - } + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(0.0); + let (sord, cord) = this.0.sin_cos_round(&mut this.1, Nearest); + ( + prep_retval::(&mut this.0, sord), + prep_retval::(&mut this.1, cord) + ) } } } @@ -362,7 +273,33 @@ macro_rules! impl_op_for_ty { impl_op_for_ty!(f32, "f"); impl_op_for_ty!(f64, ""); -// Account for `lgamma_r` not having a simple `f` suffix -pub mod lgammaf_r { - pub use super::lgamma_rf::*; +// `lgamma_r` is not a simple suffix so we can't use the above macro. +impl MpOp for crate::op::lgamma_r::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + let (sign, ord) = this.ln_abs_gamma_round(Nearest); + let ret = prep_retval::(this, ord); + (ret, sign as i32) + } +} + +impl MpOp for crate::op::lgammaf_r::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + let (sign, ord) = this.ln_abs_gamma_round(Nearest); + let ret = prep_retval::(this, ord); + (ret, sign as i32) + } } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs index ef6d21fdbba..b7988660e66 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs @@ -22,12 +22,6 @@ const ALLOWED_SKIPS: &[&str] = &[ macro_rules! callback { ( fn_name: $name:ident, - CFn: $_CFn:ty, - CArgs: $_CArgs:ty, - CRet: $_CRet:ty, - RustFn: $_RustFn:ty, - RustArgs: $_RustArgs:ty, - RustRet: $_RustRet:ty, extra: [$push_to:ident], ) => { $push_to.push(stringify!($name)); diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 5a118f7c209..d4ba9e90010 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -9,42 +9,46 @@ // There are some targets we can't build musl for #![cfg(feature = "build-musl")] -use libm_test::gen::random; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, TupleCall, musl_allowed_ulp}; -use musl_math_sys as musl; +use libm_test::gen::{CachedInput, random}; +use libm_test::{ + CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall, musl_allowed_ulp, +}; macro_rules! musl_rand_tests { ( fn_name: $fn_name:ident, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: $RustFn:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, attrs: [$($meta:meta)*] - ) => { paste::paste! { - #[test] - $(#[$meta])* - fn [< musl_random_ $fn_name >]() { - let fname = stringify!($fn_name); - let ulp = musl_allowed_ulp(fname); - let ctx = CheckCtx::new(ulp, fname, CheckBasis::Musl); - let cases = random::get_test_cases::<$RustArgs>(&ctx); - - for input in cases { - let musl_res = input.call(musl::$fn_name as $CFn); - let crate_res = input.call(libm::$fn_name as $RustFn); - - crate_res.validate(musl_res, input, &ctx).unwrap(); + ) => { + paste::paste! { + #[test] + $(#[$meta])* + fn [< musl_random_ $fn_name >]() { + test_one::(musl_math_sys::$fn_name); } } - } }; + }; +} + +fn test_one(musl_fn: Op::CFn) +where + Op: MathOp, + CachedInput: GenerateInput, +{ + let name = Op::NAME_STR; + let ulp = musl_allowed_ulp(name); + let ctx = CheckCtx::new(ulp, name, CheckBasis::Musl); + let cases = random::get_test_cases::(&ctx); + + for input in cases { + let musl_res = input.call(musl_fn); + let crate_res = input.call(Op::ROUTINE); + + crate_res.validate(musl_res, input, &ctx).unwrap(); + } } libm_macros::for_each_function! { callback: musl_rand_tests, - skip: [], attributes: [ #[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586 [exp10, exp10f, exp2, exp2f, rint] diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index f8d94a1609e..676ee86a0d0 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -2,45 +2,48 @@ #![cfg(feature = "test-multiprecision")] -use libm_test::gen::random; -use libm_test::mpfloat::{self, MpOp}; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, TupleCall, multiprec_allowed_ulp}; +use libm_test::gen::{CachedInput, random}; +use libm_test::mpfloat::MpOp; +use libm_test::{ + CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall, multiprec_allowed_ulp, +}; /// Implement a test against MPFR with random inputs. macro_rules! multiprec_rand_tests { ( fn_name: $fn_name:ident, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: $RustFn:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, attrs: [$($meta:meta)*] ) => { paste::paste! { #[test] $(#[$meta])* fn [< multiprec_random_ $fn_name >]() { - type MpOpTy = mpfloat::$fn_name::Operation; - - let fname = stringify!($fn_name); - let ulp = multiprec_allowed_ulp(fname); - let mut mp_vals = MpOpTy::new(); - let ctx = CheckCtx::new(ulp, fname, CheckBasis::Mpfr); - let cases = random::get_test_cases::<$RustArgs>(&ctx); - - for input in cases { - let mp_res = mp_vals.run(input); - let crate_res = input.call(libm::$fn_name as $RustFn); - - crate_res.validate(mp_res, input, &ctx).unwrap(); - } + test_one::(); } } }; } +fn test_one() +where + Op: MathOp + MpOp, + CachedInput: GenerateInput, +{ + let name = Op::NAME_STR; + + let ulp = multiprec_allowed_ulp(name); + let mut mp_vals = Op::new_mp(); + let ctx = CheckCtx::new(ulp, name, CheckBasis::Mpfr); + let cases = random::get_test_cases::(&ctx); + + for input in cases { + let mp_res = Op::run(&mut mp_vals, input); + let crate_res = input.call(Op::ROUTINE); + + crate_res.validate(mp_res, input, &ctx).unwrap(); + } +} + libm_macros::for_each_function! { callback: multiprec_rand_tests, attributes: [ -- cgit 1.4.1-3-g733a5 From 6aef9e17c8b3f606cf42a7a233f69e489f17edb6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 2 Nov 2024 16:52:28 -0500 Subject: Correct the proc macro to emit `pub` functions --- library/compiler-builtins/libm/crates/libm-macros/src/enums.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs index d9017dff72b..1f9fca2ef9e 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs @@ -56,14 +56,14 @@ pub fn function_enum( impl #enum_name { /// The stringified version of this function name. - const fn as_str(self) -> &'static str { + pub const fn as_str(self) -> &'static str { match self { #( #as_str_arms , )* } } /// The base name enum for this function. - const fn base_name(self) -> #base_enum { + pub const fn base_name(self) -> #base_enum { match self { #( #base_arms, )* } @@ -111,7 +111,7 @@ pub fn base_name_enum( impl #item_name { /// The stringified version of this base name. - const fn as_str(self) -> &'static str { + pub const fn as_str(self) -> &'static str { match self { #( #as_str_arms ),* } -- cgit 1.4.1-3-g733a5 From 2fab4f4580b584489d25ed1f1173a3fc8713997f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 2 Nov 2024 22:35:30 -0500 Subject: Change the `CheckCtx` constructor to take a `Name` enum This prepares to eliminate some reliance on string matching but does not yet make those changes. --- .../libm/crates/libm-macros/src/lib.rs | 4 +-- .../libm/crates/libm-test/benches/random.rs | 2 +- .../libm/crates/libm-test/src/gen/random.rs | 7 +++-- .../libm/crates/libm-test/src/lib.rs | 21 -------------- .../libm/crates/libm-test/src/precision.rs | 32 +++++++++++----------- .../libm/crates/libm-test/src/test_traits.rs | 20 ++++++++++---- .../crates/libm-test/tests/compare_built_musl.rs | 2 +- .../libm/crates/libm-test/tests/multiprecision.rs | 2 +- 8 files changed, 40 insertions(+), 50 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs index 2db412e79a1..1e7cd08b908 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs @@ -628,9 +628,9 @@ impl VisitMut for MacroReplace { } } -/// Return the unsuffixed name of a function. +/// Return the unsuffixed version of a function name; e.g. `abs` and `absf` both return `abs`, +/// `lgamma_r` and `lgammaf_r` both return `lgamma_r`. fn base_name(name: &str) -> &str { - // Keep this in sync with `libm_test::base_name` let known_mappings = &[ ("erff", "erf"), ("erf", "erf"), diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 6f2305dd27e..72ace5d5335 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -50,7 +50,7 @@ where let name = Op::NAME_STR; let ulp = libm_test::musl_allowed_ulp(name); - let ctx = CheckCtx::new(ulp, name, CheckBasis::Musl); + let ctx = CheckCtx::new(ulp, Op::NAME, CheckBasis::Musl); let benchvec: Vec<_> = random::get_test_cases::(&ctx).take(BENCH_ITER_ITEMS).collect(); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index e347b3c63ae..b72247a4e9f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -110,7 +110,10 @@ pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator, { - let inputs = - if ctx.fn_name == "jn" || ctx.fn_name == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; + let inputs = if ctx.fn_name_str == "jn" || ctx.fn_name_str == "jnf" { + &TEST_CASES_JN + } else { + &TEST_CASES + }; inputs.get_cases() } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index e64ad626408..af6ad6da56a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -17,27 +17,6 @@ pub type TestResult = Result; // List of all files present in libm's source include!(concat!(env!("OUT_DIR"), "/all_files.rs")); -/// Return the unsuffixed version of a function name; e.g. `abs` and `absf` both return `abs`, -/// `lgamma_r` and `lgammaf_r` both return `lgamma_r`. -pub fn base_name(name: &str) -> &str { - let known_mappings = &[ - ("erff", "erf"), - ("erf", "erf"), - ("lgammaf_r", "lgamma_r"), - ("modff", "modf"), - ("modf", "modf"), - ]; - - match known_mappings.iter().find(|known| known.0 == name) { - Some(found) => found.1, - None => name - .strip_suffix("f") - .or_else(|| name.strip_suffix("f16")) - .or_else(|| name.strip_suffix("f128")) - .unwrap_or(name), - } -} - /// True if `EMULATED` is set and nonempty. Used to determine how many iterations to run. pub const fn emulated() -> bool { match option_env!("EMULATED") { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 5b021e9467d..5b5743020d7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -111,25 +111,25 @@ impl MaybeOverride<(f32,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if ctx.fn_name == "expm1f" && input.0 > 80.0 && actual.is_infinite() { + if ctx.fn_name_str == "expm1f" && input.0 > 80.0 && actual.is_infinite() { // we return infinity but the number is representable return XFAIL; } - if ctx.fn_name == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { + if ctx.fn_name_str == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { // we return some NaN that should be real values or infinite // doesn't seem to happen on x86 return XFAIL; } } - if ctx.fn_name == "acoshf" && input.0 < -1.0 { + if ctx.fn_name_str == "acoshf" && input.0 < -1.0 { // acoshf is undefined for x <= 1.0, but we return a random result at lower // values. return XFAIL; } - if ctx.fn_name == "lgammaf" || ctx.fn_name == "lgammaf_r" && input.0 < 0.0 { + if ctx.fn_name_str == "lgammaf" || ctx.fn_name_str == "lgammaf_r" && input.0 < 0.0 { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -146,7 +146,7 @@ impl MaybeOverride<(f32,)> for SpecialCase { // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fn_name == "lgammaf_r" + && ctx.fn_name_str == "lgammaf_r" && input.0 == f32::NEG_INFINITY && actual.abs() == expected.abs() { @@ -166,13 +166,13 @@ impl MaybeOverride<(f64,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if cfg!(target_arch = "x86") && ctx.fn_name == "acosh" && input.0 < 1.0 { + if cfg!(target_arch = "x86") && ctx.fn_name_str == "acosh" && input.0 < 1.0 { // The function is undefined, both implementations return random results return SKIP; } if cfg!(x86_no_sse) - && ctx.fn_name == "ceil" + && ctx.fn_name_str == "ceil" && input.0 < 0.0 && input.0 > -1.0 && expected == F::ZERO @@ -183,13 +183,13 @@ impl MaybeOverride<(f64,)> for SpecialCase { } } - if ctx.fn_name == "acosh" && input.0 < 1.0 { + if ctx.fn_name_str == "acosh" && input.0 < 1.0 { // The function is undefined for the inputs, musl and our libm both return // random results. return XFAIL; } - if ctx.fn_name == "lgamma" || ctx.fn_name == "lgamma_r" && input.0 < 0.0 { + if ctx.fn_name_str == "lgamma" || ctx.fn_name_str == "lgamma_r" && input.0 < 0.0 { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -206,7 +206,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fn_name == "lgamma_r" + && ctx.fn_name_str == "lgamma_r" && input.0 == f64::NEG_INFINITY && actual.abs() == expected.abs() { @@ -219,7 +219,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { /// Check NaN bits if the function requires it fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { - if !(ctx.base_name == "fabs" || ctx.base_name == "copysign") { + if !(ctx.base_name_str == "fabs" || ctx.base_name_str == "copysign") { return None; } @@ -277,7 +277,7 @@ fn maybe_skip_binop_nan( ) -> Option { match ctx.basis { CheckBasis::Musl => { - if (ctx.base_name == "fmax" || ctx.base_name == "fmin") + if (ctx.base_name_str == "fmax" || ctx.base_name_str == "fmin") && (input.0.is_nan() || input.1.is_nan()) && expected.is_nan() { @@ -287,7 +287,7 @@ fn maybe_skip_binop_nan( } } CheckBasis::Mpfr => { - if ctx.base_name == "copysign" && input.1.is_nan() { + if ctx.base_name_str == "copysign" && input.1.is_nan() { SKIP } else { None @@ -308,7 +308,7 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), CheckBasis::Mpfr => { // We return +0.0, MPFR returns -0.0 - if ctx.fn_name == "jnf" + if ctx.fn_name_str == "jnf" && input.1 == f32::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO @@ -333,7 +333,7 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), CheckBasis::Mpfr => { // We return +0.0, MPFR returns -0.0 - if ctx.fn_name == "jn" + if ctx.fn_name_str == "jn" && input.1 == f64::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO @@ -353,7 +353,7 @@ fn bessel_prec_dropoff( ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - if ctx.base_name == "jn" { + if ctx.base_name_str == "jn" { if input.0 > 4000 { return XFAIL; } else if input.0 > 2000 { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index b9bec9a4479..65faefd33a9 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -11,25 +11,33 @@ use std::fmt; use anyhow::{Context, bail, ensure}; -use crate::{Float, Int, MaybeOverride, SpecialCase, TestResult}; +use crate::{BaseName, Float, Int, MaybeOverride, Name, SpecialCase, TestResult}; /// Context passed to [`CheckOutput`]. #[derive(Clone, Debug, PartialEq, Eq)] pub struct CheckCtx { /// Allowed ULP deviation pub ulp: u32, + pub fn_name: Name, + pub base_name: BaseName, /// Function name. - pub fn_name: &'static str, + pub fn_name_str: &'static str, /// Return the unsuffixed version of the function name. - pub base_name: &'static str, + pub base_name_str: &'static str, /// Source of truth for tests. pub basis: CheckBasis, } impl CheckCtx { - pub fn new(ulp: u32, fname: &'static str, basis: CheckBasis) -> Self { - let base_name = crate::base_name(fname); - Self { ulp, fn_name: fname, base_name, basis } + pub fn new(ulp: u32, fn_name: Name, basis: CheckBasis) -> Self { + Self { + ulp, + fn_name, + fn_name_str: fn_name.as_str(), + base_name: fn_name.base_name(), + base_name_str: fn_name.base_name().as_str(), + basis, + } } } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index d4ba9e90010..f4c827fc931 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -36,7 +36,7 @@ where { let name = Op::NAME_STR; let ulp = musl_allowed_ulp(name); - let ctx = CheckCtx::new(ulp, name, CheckBasis::Musl); + let ctx = CheckCtx::new(ulp, Op::NAME, CheckBasis::Musl); let cases = random::get_test_cases::(&ctx); for input in cases { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 676ee86a0d0..5f38d846226 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -33,7 +33,7 @@ where let ulp = multiprec_allowed_ulp(name); let mut mp_vals = Op::new_mp(); - let ctx = CheckCtx::new(ulp, name, CheckBasis::Mpfr); + let ctx = CheckCtx::new(ulp, Op::NAME, CheckBasis::Mpfr); let cases = random::get_test_cases::(&ctx); for input in cases { -- cgit 1.4.1-3-g733a5 From f113f2be1e2b58d9a99807d3fd921c61799eff0f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 2 Nov 2024 22:40:09 -0500 Subject: Rename `Name` to `Identifier` to avoid some ambiguity of "name" --- .../libm/crates/libm-test/benches/random.rs | 4 ++-- .../libm/crates/libm-test/src/gen/random.rs | 7 ++----- .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/op.rs | 12 +++++------ .../libm/crates/libm-test/src/precision.rs | 24 +++++++++++----------- .../libm/crates/libm-test/src/test_traits.rs | 16 +++++++-------- .../crates/libm-test/tests/compare_built_musl.rs | 4 ++-- .../libm/crates/libm-test/tests/multiprecision.rs | 4 ++-- 8 files changed, 35 insertions(+), 38 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 72ace5d5335..5eea4331945 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -47,10 +47,10 @@ where Op: MathOp, CachedInput: GenerateInput, { - let name = Op::NAME_STR; + let name = Op::NAME; let ulp = libm_test::musl_allowed_ulp(name); - let ctx = CheckCtx::new(ulp, Op::NAME, CheckBasis::Musl); + let ctx = CheckCtx::new(ulp, Op::IDENTIFIER, CheckBasis::Musl); let benchvec: Vec<_> = random::get_test_cases::(&ctx).take(BENCH_ITER_ITEMS).collect(); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index b72247a4e9f..e347b3c63ae 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -110,10 +110,7 @@ pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator, { - let inputs = if ctx.fn_name_str == "jn" || ctx.fn_name_str == "jnf" { - &TEST_CASES_JN - } else { - &TEST_CASES - }; + let inputs = + if ctx.fn_name == "jn" || ctx.fn_name == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; inputs.get_cases() } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index af6ad6da56a..914e5824486 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -6,7 +6,7 @@ mod precision; mod test_traits; pub use libm::support::{Float, Int}; -pub use op::{BaseName, MathOp, Name}; +pub use op::{BaseName, Identifier, MathOp}; pub use precision::{MaybeOverride, SpecialCase, multiprec_allowed_ulp, musl_allowed_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index fe0a08a28e5..50b455d3a93 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -15,10 +15,10 @@ use crate::{CheckOutput, Float, TupleCall}; -/// An enum representing each possible routine name. +/// An enum representing each possible symbol name (`sin`, `sinf`, `sinl`, etc). #[libm_macros::function_enum(BaseName)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum Name {} +pub enum Identifier {} /// The name without any type specifier, e.g. `sin` and `sinf` both become `sin`. #[libm_macros::base_name_enum] @@ -58,13 +58,13 @@ pub trait MathOp { type RustRet: CheckOutput; /// The name of this function, including suffix (e.g. `sin`, `sinf`). - const NAME: Name; + const IDENTIFIER: Identifier; /// The name as a string. - const NAME_STR: &'static str = Self::NAME.as_str(); + const NAME: &'static str = Self::IDENTIFIER.as_str(); /// The name of the function excluding the type suffix, e.g. `sin` and `sinf` are both `sin`. - const BASE_NAME: BaseName = Self::NAME.base_name(); + const BASE_NAME: BaseName = Self::IDENTIFIER.base_name(); /// The function in `libm` which can be called. const ROUTINE: Self::RustFn; @@ -96,7 +96,7 @@ macro_rules! do_thing { type RustArgs = $RustArgs; type RustRet = $RustRet; - const NAME: Name = Name::[< $fn_name:camel >]; + const IDENTIFIER: Identifier = Identifier::[< $fn_name:camel >]; const ROUTINE: Self::RustFn = libm::$fn_name; } } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 5b5743020d7..afe8c1fb759 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -111,25 +111,25 @@ impl MaybeOverride<(f32,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if ctx.fn_name_str == "expm1f" && input.0 > 80.0 && actual.is_infinite() { + if ctx.fn_name == "expm1f" && input.0 > 80.0 && actual.is_infinite() { // we return infinity but the number is representable return XFAIL; } - if ctx.fn_name_str == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { + if ctx.fn_name == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { // we return some NaN that should be real values or infinite // doesn't seem to happen on x86 return XFAIL; } } - if ctx.fn_name_str == "acoshf" && input.0 < -1.0 { + if ctx.fn_name == "acoshf" && input.0 < -1.0 { // acoshf is undefined for x <= 1.0, but we return a random result at lower // values. return XFAIL; } - if ctx.fn_name_str == "lgammaf" || ctx.fn_name_str == "lgammaf_r" && input.0 < 0.0 { + if ctx.fn_name == "lgammaf" || ctx.fn_name == "lgammaf_r" && input.0 < 0.0 { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -146,7 +146,7 @@ impl MaybeOverride<(f32,)> for SpecialCase { // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fn_name_str == "lgammaf_r" + && ctx.fn_name == "lgammaf_r" && input.0 == f32::NEG_INFINITY && actual.abs() == expected.abs() { @@ -166,13 +166,13 @@ impl MaybeOverride<(f64,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if cfg!(target_arch = "x86") && ctx.fn_name_str == "acosh" && input.0 < 1.0 { + if cfg!(target_arch = "x86") && ctx.fn_name == "acosh" && input.0 < 1.0 { // The function is undefined, both implementations return random results return SKIP; } if cfg!(x86_no_sse) - && ctx.fn_name_str == "ceil" + && ctx.fn_name == "ceil" && input.0 < 0.0 && input.0 > -1.0 && expected == F::ZERO @@ -183,13 +183,13 @@ impl MaybeOverride<(f64,)> for SpecialCase { } } - if ctx.fn_name_str == "acosh" && input.0 < 1.0 { + if ctx.fn_name == "acosh" && input.0 < 1.0 { // The function is undefined for the inputs, musl and our libm both return // random results. return XFAIL; } - if ctx.fn_name_str == "lgamma" || ctx.fn_name_str == "lgamma_r" && input.0 < 0.0 { + if ctx.fn_name == "lgamma" || ctx.fn_name == "lgamma_r" && input.0 < 0.0 { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -206,7 +206,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fn_name_str == "lgamma_r" + && ctx.fn_name == "lgamma_r" && input.0 == f64::NEG_INFINITY && actual.abs() == expected.abs() { @@ -308,7 +308,7 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), CheckBasis::Mpfr => { // We return +0.0, MPFR returns -0.0 - if ctx.fn_name_str == "jnf" + if ctx.fn_name == "jnf" && input.1 == f32::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO @@ -333,7 +333,7 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), CheckBasis::Mpfr => { // We return +0.0, MPFR returns -0.0 - if ctx.fn_name_str == "jn" + if ctx.fn_name == "jn" && input.1 == f64::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 65faefd33a9..1803300588a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -11,17 +11,17 @@ use std::fmt; use anyhow::{Context, bail, ensure}; -use crate::{BaseName, Float, Int, MaybeOverride, Name, SpecialCase, TestResult}; +use crate::{BaseName, Float, Identifier, Int, MaybeOverride, SpecialCase, TestResult}; /// Context passed to [`CheckOutput`]. #[derive(Clone, Debug, PartialEq, Eq)] pub struct CheckCtx { /// Allowed ULP deviation pub ulp: u32, - pub fn_name: Name, + pub fn_ident: Identifier, pub base_name: BaseName, /// Function name. - pub fn_name_str: &'static str, + pub fn_name: &'static str, /// Return the unsuffixed version of the function name. pub base_name_str: &'static str, /// Source of truth for tests. @@ -29,13 +29,13 @@ pub struct CheckCtx { } impl CheckCtx { - pub fn new(ulp: u32, fn_name: Name, basis: CheckBasis) -> Self { + pub fn new(ulp: u32, fn_ident: Identifier, basis: CheckBasis) -> Self { Self { ulp, - fn_name, - fn_name_str: fn_name.as_str(), - base_name: fn_name.base_name(), - base_name_str: fn_name.base_name().as_str(), + fn_ident, + fn_name: fn_ident.as_str(), + base_name: fn_ident.base_name(), + base_name_str: fn_ident.base_name().as_str(), basis, } } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index f4c827fc931..c029a5d9758 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -34,9 +34,9 @@ where Op: MathOp, CachedInput: GenerateInput, { - let name = Op::NAME_STR; + let name = Op::NAME; let ulp = musl_allowed_ulp(name); - let ctx = CheckCtx::new(ulp, Op::NAME, CheckBasis::Musl); + let ctx = CheckCtx::new(ulp, Op::IDENTIFIER, CheckBasis::Musl); let cases = random::get_test_cases::(&ctx); for input in cases { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 5f38d846226..00c6278f67f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -29,11 +29,11 @@ where Op: MathOp + MpOp, CachedInput: GenerateInput, { - let name = Op::NAME_STR; + let name = Op::NAME; let ulp = multiprec_allowed_ulp(name); let mut mp_vals = Op::new_mp(); - let ctx = CheckCtx::new(ulp, Op::NAME, CheckBasis::Mpfr); + let ctx = CheckCtx::new(ulp, Op::IDENTIFIER, CheckBasis::Mpfr); let cases = random::get_test_cases::(&ctx); for input in cases { -- cgit 1.4.1-3-g733a5 From 5032fcf1399447d34cd16b9c9bb7fd64133db0d2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 2 Nov 2024 23:03:41 -0500 Subject: Change default ULP to use enum matching Migrate from string to enum matching and tie this to `CheckCtx::new`, so no tests need to explicitly set ULP. --- .../libm/crates/libm-test/benches/random.rs | 3 +- .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/precision.rs | 73 ++++++++++------------ .../libm/crates/libm-test/src/test_traits.rs | 11 ++-- .../crates/libm-test/tests/compare_built_musl.rs | 8 +-- .../libm/crates/libm-test/tests/multiprecision.rs | 9 +-- 6 files changed, 47 insertions(+), 59 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 5eea4331945..d77d579080e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -49,8 +49,7 @@ where { let name = Op::NAME; - let ulp = libm_test::musl_allowed_ulp(name); - let ctx = CheckCtx::new(ulp, Op::IDENTIFIER, CheckBasis::Musl); + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl); let benchvec: Vec<_> = random::get_test_cases::(&ctx).take(BENCH_ITER_ITEMS).collect(); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 914e5824486..7f0d9aa7553 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -7,7 +7,7 @@ mod test_traits; pub use libm::support::{Float, Int}; pub use op::{BaseName, Identifier, MathOp}; -pub use precision::{MaybeOverride, SpecialCase, multiprec_allowed_ulp, musl_allowed_ulp}; +pub use precision::{MaybeOverride, SpecialCase, default_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index afe8c1fb759..c761709b883 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -3,7 +3,10 @@ use core::f32; -use crate::{CheckBasis, CheckCtx, Float, Int, TestResult}; +use CheckBasis::{Mpfr, Musl}; +use Identifier as Id; + +use crate::{CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; /// Type implementing [`IgnoreCase`]. pub struct SpecialCase; @@ -14,50 +17,42 @@ const MUSL_DEFAULT_ULP: u32 = 2; /// Default ULP allowed to differ from multiprecision (i.e. infinite) results. const MULTIPREC_DEFAULT_ULP: u32 = 1; -/// ULP allowed to differ from muls results. +/// ULP allowed to differ from the results returned by a test basis. /// -/// Note that these results were obtained using 400,000,000 rounds of random inputs, which +/// Note that these results were obtained using 400M rounds of random inputs, which /// is not a value used by default. -pub fn musl_allowed_ulp(name: &str) -> u32 { - // Consider overrides xfail - match name { - #[cfg(x86_no_sse)] - "asinh" | "asinhf" => 6, - "lgamma" | "lgamma_r" | "lgammaf" | "lgammaf_r" => 400, - "tanh" | "tanhf" => 4, - "tgamma" => 20, - "j0" | "j0f" | "j1" | "j1f" => { +pub fn default_ulp(ctx: &CheckCtx) -> u32 { + match (&ctx.basis, ctx.fn_ident) { + // Overrides that apply to either basis + (_, Id::J0 | Id::J0f | Id::J1 | Id::J1f) => { // Results seem very target-dependent if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } } - "jn" | "jnf" => 1000, - "sincosf" => 500, - #[cfg(not(target_pointer_width = "64"))] - "exp10" => 4, - #[cfg(not(target_pointer_width = "64"))] - "exp10f" => 4, - _ => MUSL_DEFAULT_ULP, - } -} + (_, Id::Jn | Id::Jnf) => 1000, -/// ULP allowed to differ from multiprecision results. -pub fn multiprec_allowed_ulp(name: &str) -> u32 { - // Consider overrides xfail - match name { - "asinh" | "asinhf" => 2, - "acoshf" => 4, - "atanh" | "atanhf" => 2, - "exp10" | "exp10f" => 3, - "j0" | "j0f" | "j1" | "j1f" => { - // Results seem very target-dependent - if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } - } - "jn" | "jnf" => 1000, - "lgamma" | "lgammaf" | "lgamma_r" | "lgammaf_r" => 16, - "sinh" | "sinhf" => 2, - "tanh" | "tanhf" => 2, - "tgamma" => 20, - _ => MULTIPREC_DEFAULT_ULP, + // Overrides for musl + #[cfg(x86_no_sse)] + (Musl, Id::Asinh | Id::Asinhf) => 6, + #[cfg(not(target_pointer_width = "64"))] + (Musl, Id::Exp10 | Id::Exp10f) => 4, + (Musl, Id::Lgamma | Id::LgammaR | Id::Lgammaf | Id::LgammafR) => 400, + (Musl, Id::Sincosf) => 500, + (Musl, Id::Tanh | Id::Tanhf) => 4, + (Musl, Id::Tgamma) => 20, + + // Overrides for MPFR + (Mpfr, Id::Acoshf) => 4, + (Mpfr, Id::Asinh | Id::Asinhf) => 2, + (Mpfr, Id::Atanh | Id::Atanhf) => 2, + (Mpfr, Id::Exp10 | Id::Exp10f) => 3, + (Mpfr, Id::Lgamma | Id::LgammaR | Id::Lgammaf | Id::LgammafR) => 16, + (Mpfr, Id::Sinh | Id::Sinhf) => 2, + (Mpfr, Id::Tanh | Id::Tanhf) => 2, + (Mpfr, Id::Tgamma) => 20, + + // Defaults + (Musl, _) => MUSL_DEFAULT_ULP, + (Mpfr, _) => MULTIPREC_DEFAULT_ULP, } } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 1803300588a..ec14a8cf20a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -29,15 +29,18 @@ pub struct CheckCtx { } impl CheckCtx { - pub fn new(ulp: u32, fn_ident: Identifier, basis: CheckBasis) -> Self { - Self { - ulp, + /// Create a new check context, using the default ULP for the function. + pub fn new(fn_ident: Identifier, basis: CheckBasis) -> Self { + let mut ret = Self { + ulp: 0, fn_ident, fn_name: fn_ident.as_str(), base_name: fn_ident.base_name(), base_name_str: fn_ident.base_name().as_str(), basis, - } + }; + ret.ulp = crate::default_ulp(&ret); + ret } } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index c029a5d9758..0022ee03c21 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -10,9 +10,7 @@ #![cfg(feature = "build-musl")] use libm_test::gen::{CachedInput, random}; -use libm_test::{ - CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall, musl_allowed_ulp, -}; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall}; macro_rules! musl_rand_tests { ( @@ -34,9 +32,7 @@ where Op: MathOp, CachedInput: GenerateInput, { - let name = Op::NAME; - let ulp = musl_allowed_ulp(name); - let ctx = CheckCtx::new(ulp, Op::IDENTIFIER, CheckBasis::Musl); + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl); let cases = random::get_test_cases::(&ctx); for input in cases { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 00c6278f67f..47a85bdb3e5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -4,9 +4,7 @@ use libm_test::gen::{CachedInput, random}; use libm_test::mpfloat::MpOp; -use libm_test::{ - CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall, multiprec_allowed_ulp, -}; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall}; /// Implement a test against MPFR with random inputs. macro_rules! multiprec_rand_tests { @@ -29,11 +27,8 @@ where Op: MathOp + MpOp, CachedInput: GenerateInput, { - let name = Op::NAME; - - let ulp = multiprec_allowed_ulp(name); let mut mp_vals = Op::new_mp(); - let ctx = CheckCtx::new(ulp, Op::IDENTIFIER, CheckBasis::Mpfr); + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); let cases = random::get_test_cases::(&ctx); for input in cases { -- cgit 1.4.1-3-g733a5 From 10bdf3b6c1e0178ee934a6cdcb876ac79ef8b72c Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 3 Nov 2024 22:54:01 +0000 Subject: Remove incorrect `sparcv9` match pattern from `configure_f16_f128` --- library/compiler-builtins/configure.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index 68b4d68e61b..f8aafbe703a 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -71,7 +71,7 @@ pub fn configure_f16_f128(target: &Target) { // `f128` crashes "powerpc64" if &target.os == "aix" => (true, false), // `f128` crashes - "sparc" | "sparcv9" => (true, false), + "sparc" => (true, false), // `f16` miscompiles "wasm32" | "wasm64" => (false, true), // Most everything else works as of LLVM 19 -- cgit 1.4.1-3-g733a5 From c33f521bb523cc3ddcb7b14085a59712bad8d3d5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 23:08:41 +0000 Subject: chore: release v0.1.139 --- library/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index f43b63b2b0c..5c65aa8713e 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.139](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.138...compiler_builtins-v0.1.139) - 2024-11-03 + +### Other + +- Remove incorrect `sparcv9` match pattern from `configure_f16_f128` + ## [0.1.138](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.137...compiler_builtins-v0.1.138) - 2024-11-01 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 3d8a1f25503..33f1c9a3ad8 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.138" +version = "0.1.139" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From fcf8670668238b0ee5379dc0af04709e47e670c5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 3 Nov 2024 20:24:26 -0600 Subject: Change the `multiprec_` prefix to `mp_` Currently there is a combination of names starting with `multiprecision_`, `mp_` and `multiprec_`. Update so `multiprecision_` is always used when a long form makes sense, `mp_` otherwise (eliminating `multiprec_`). --- library/compiler-builtins/libm/crates/libm-test/src/precision.rs | 4 ++-- .../compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index c761709b883..cf9115430c4 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -15,7 +15,7 @@ pub struct SpecialCase; const MUSL_DEFAULT_ULP: u32 = 2; /// Default ULP allowed to differ from multiprecision (i.e. infinite) results. -const MULTIPREC_DEFAULT_ULP: u32 = 1; +const MP_DEFAULT_ULP: u32 = 1; /// ULP allowed to differ from the results returned by a test basis. /// @@ -52,7 +52,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { // Defaults (Musl, _) => MUSL_DEFAULT_ULP, - (Mpfr, _) => MULTIPREC_DEFAULT_ULP, + (Mpfr, _) => MP_DEFAULT_ULP, } } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 47a85bdb3e5..0b41fba82e5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -7,7 +7,7 @@ use libm_test::mpfloat::MpOp; use libm_test::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall}; /// Implement a test against MPFR with random inputs. -macro_rules! multiprec_rand_tests { +macro_rules! mp_rand_tests { ( fn_name: $fn_name:ident, attrs: [$($meta:meta)*] @@ -15,7 +15,7 @@ macro_rules! multiprec_rand_tests { paste::paste! { #[test] $(#[$meta])* - fn [< multiprec_random_ $fn_name >]() { + fn [< mp_random_ $fn_name >]() { test_one::(); } } @@ -40,7 +40,7 @@ where } libm_macros::for_each_function! { - callback: multiprec_rand_tests, + callback: mp_rand_tests, attributes: [ // Also an assertion failure on i686: at `MPFR_ASSERTN (! mpfr_erangeflag_p ())` #[ignore = "large values are infeasible in MPFR"] -- cgit 1.4.1-3-g733a5 From 9a2774a0ae661f0a0a905f3800bfec6e5696de32 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 3 Nov 2024 20:52:28 -0600 Subject: Move some numeric trait logic to default implementations There are a handful of functions we can move out of the macro and to the numeric traits as default implementations; do that here. Additionally, add some bounds that make sense for completeness. --- .../libm/crates/libm-test/src/test_traits.rs | 2 +- .../libm/src/math/support/float_traits.rs | 106 ++++++++++++--------- .../libm/src/math/support/int_traits.rs | 7 +- 3 files changed, 67 insertions(+), 48 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index ec14a8cf20a..b8e0aa108a3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -314,7 +314,7 @@ where // Make sure that the signs are the same before checing ULP to avoid wraparound let act_sig = actual.signum(); let exp_sig = expected.signum(); - ensure!(act_sig == exp_sig, "mismatched signs {act_sig} {exp_sig}"); + ensure!(act_sig == exp_sig, "mismatched signs {act_sig:?} {exp_sig:?}"); if actual.is_infinite() ^ expected.is_infinite() { bail!("mismatched infinities"); diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index a1d84faf2e2..0047ba3689e 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -1,4 +1,4 @@ -use core::{fmt, ops}; +use core::{fmt, mem, ops}; use super::int_traits::{Int, MinInt}; @@ -7,15 +7,17 @@ use super::int_traits::{Int, MinInt}; pub trait Float: Copy + fmt::Debug - + fmt::Display + PartialEq + PartialOrd + ops::AddAssign + ops::MulAssign + ops::Add + ops::Sub + + ops::Mul + ops::Div + ops::Rem + + ops::Neg + + 'static { /// A uint of the same width as the float type Int: Int; @@ -27,11 +29,16 @@ pub trait Float: type ExpInt: Int; const ZERO: Self; + const NEG_ZERO: Self; const ONE: Self; const NEG_ONE: Self; const INFINITY: Self; const NEG_INFINITY: Self; const NAN: Self; + const MAX: Self; + const MIN: Self; + const PI: Self; + const FRAC_PI_2: Self; /// The bitwidth of the float type const BITS: u32; @@ -69,7 +76,19 @@ pub trait Float: /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be /// represented in multiple different ways. This method returns `true` if two NaNs are /// compared. - fn eq_repr(self, rhs: Self) -> bool; + fn eq_repr(self, rhs: Self) -> bool { + let is_nan = |x: Self| -> bool { + // } + // fn is_nan(x: Self) -> bool { + // When using mangled-names, the "real" compiler-builtins might not have the + // necessary builtin (__unordtf2) to test whether `f128` is NaN. + // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin + // x is NaN if all the bits of the exponent are set and the significand is non-0 + x.to_bits() & Self::EXP_MASK == Self::EXP_MASK + && x.to_bits() & Self::SIG_MASK != Self::Int::ZERO + }; + if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() } + } /// Returns true if the value is NaN. fn is_nan(self) -> bool; @@ -81,22 +100,35 @@ pub trait Float: fn is_sign_negative(self) -> bool; /// Returns if `self` is subnormal - fn is_subnormal(self) -> bool; + fn is_subnormal(self) -> bool { + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO + } /// Returns the exponent, not adjusting for bias. fn exp(self) -> Self::ExpInt; /// Returns the significand with no implicit bit (or the "fractional" part) - fn frac(self) -> Self::Int; + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIG_MASK + } /// Returns the significand with implicit bit - fn imp_frac(self) -> Self::Int; + fn imp_frac(self) -> Self::Int { + self.frac() | Self::IMPLICIT_BIT + } /// Returns a `Self::Int` transmuted back to `Self` fn from_bits(a: Self::Int) -> Self; /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self; + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { + let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; + Self::from_bits( + (sign << (Self::BITS - 1)) + | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) + | (significand & Self::SIG_MASK), + ) + } fn abs(self) -> Self { let abs_mask = !Self::SIGN_MASK; @@ -107,10 +139,18 @@ pub trait Float: fn normalize(significand: Self::Int) -> (i32, Self::Int); /// Returns a number composed of the magnitude of self and the sign of sign. - fn copysign(self, other: Self) -> Self; + fn copysign(self, other: Self) -> Self { + let mut x = self.to_bits(); + let y = other.to_bits(); + x &= !Self::SIGN_MASK; + x |= y & Self::SIGN_MASK; + Self::from_bits(x) + } /// Returns a number that represents the sign of self. - fn signum(self) -> Self; + fn signum(self) -> Self { + if self.is_nan() { self } else { Self::ONE.copysign(self) } + } } macro_rules! float_impl { @@ -121,11 +161,22 @@ macro_rules! float_impl { type ExpInt = $expty; const ZERO: Self = 0.0; + const NEG_ZERO: Self = -0.0; const ONE: Self = 1.0; const NEG_ONE: Self = -1.0; const INFINITY: Self = Self::INFINITY; const NEG_INFINITY: Self = Self::NEG_INFINITY; const NAN: Self = Self::NAN; + const MAX: Self = -Self::MIN; + // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed + // FIXME(msrv): just use `from_bits` when available + // SAFETY: POD cast with no preconditions + const MIN: Self = unsafe { + mem::transmute::(Self::Int::MAX & !(1 << Self::SIG_BITS)) + }; + + const PI: Self = core::$ty::consts::PI; + const FRAC_PI_2: Self = core::$ty::consts::FRAC_PI_2; const BITS: u32 = $bits; const SIG_BITS: u32 = $significand_bits; @@ -141,16 +192,6 @@ macro_rules! float_impl { fn to_bits_signed(self) -> Self::SignedInt { self.to_bits() as Self::SignedInt } - fn eq_repr(self, rhs: Self) -> bool { - fn is_nan(x: $ty) -> bool { - // When using mangled-names, the "real" compiler-builtins might not have the - // necessary builtin (__unordtf2) to test whether `f128` is NaN. - // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin - // x is NaN if all the bits of the exponent are set and the significand is non-0 - x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 - } - if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() } - } fn is_nan(self) -> bool { self.is_nan() } @@ -160,43 +201,16 @@ macro_rules! float_impl { fn is_sign_negative(self) -> bool { self.is_sign_negative() } - fn is_subnormal(self) -> bool { - (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO - } fn exp(self) -> Self::ExpInt { ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt } - fn frac(self) -> Self::Int { - self.to_bits() & Self::SIG_MASK - } - fn imp_frac(self) -> Self::Int { - self.frac() | Self::IMPLICIT_BIT - } fn from_bits(a: Self::Int) -> Self { Self::from_bits(a) } - fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_bits( - ((negative as Self::Int) << (Self::BITS - 1)) - | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) - | (significand & Self::SIG_MASK), - ) - } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) } - fn copysign(self, other: Self) -> Self { - let mut x = self.to_bits(); - let y = other.to_bits(); - x &= !Self::SIGN_MASK; - x |= y & Self::SIGN_MASK; - Self::from_bits(x) - } - - fn signum(self) -> Self { - if self.is_nan() { self } else { Self::ONE.copysign(self) } - } } }; } diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index b08907aa5b8..c72c1d5cbbb 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -1,4 +1,4 @@ -use core::{fmt, ops}; +use core::{cmp, fmt, ops}; /// Minimal integer implementations needed on all integer types, including wide integers. #[allow(dead_code)] @@ -31,6 +31,8 @@ pub trait MinInt: pub trait Int: MinInt + fmt::Display + + fmt::Binary + + fmt::LowerHex + PartialEq + PartialOrd + ops::AddAssign @@ -47,6 +49,9 @@ pub trait Int: + ops::Shr + ops::BitXor + ops::BitAnd + + cmp::Ord + + CastInto + + CastFrom { fn signed(self) -> ::OtherSign; fn unsigned(self) -> Self::Unsigned; -- cgit 1.4.1-3-g733a5 From 04ccb683d940e2171bda34ba2228c62ac581e3a6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 5 Nov 2024 02:43:33 -0600 Subject: Disable `f16` on platforms that have recursion problems CI in [1] seems to indicate that there are cases where the `f16` infinite recursion bug ([2], [3]) can make its way into what gets called during tests, even though this doesn't seem to be the usual case. In order to make sure that we avoid these completely, just unset `f16_enabled` on any platforms that have the recursion problem. This also refactors the `match` statement to be more in line with `library/std/build.rs`. [1]: https://github.com/rust-lang/compiler-builtins/pull/729 [2]: https://github.com/llvm/llvm-project/issues/97981 [3]: https://github.com/rust-lang/compiler-builtins/issues/651 --- library/compiler-builtins/configure.rs | 55 +++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index f8aafbe703a..0a0bd503d53 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -51,31 +51,46 @@ impl Target { /// Configure whether or not `f16` and `f128` support should be enabled. pub fn configure_f16_f128(target: &Target) { // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means - // that the backend will not crash when using these types. This does not mean that the - // backend does the right thing, or that the platform doesn't have ABI bugs. + // that the backend will not crash when using these types and generates code that can be called + // without crashing (no infinite recursion). This does not mean that the platform doesn't have + // ABI or other bugs. // // We do this here rather than in `rust-lang/rust` because configuring via cargo features is // not straightforward. // // Original source of this list: // - let (f16_ok, f128_ok) = match target.arch.as_str() { - // `f16` and `f128` both crash - "arm64ec" => (false, false), - // `f16` crashes - "s390x" => (false, true), - // FIXME(llvm): `f16` test failures fixed by - "loongarch64" => (false, true), - // `f128` crashes - "mips64" | "mips64r6" => (true, false), - // `f128` crashes - "powerpc64" if &target.os == "aix" => (true, false), - // `f128` crashes - "sparc" => (true, false), - // `f16` miscompiles - "wasm32" | "wasm64" => (false, true), + let f16_enabled = match target.arch.as_str() { + // Unsupported + "arm64ec" => false, + // Selection failure + "s390x" => false, + // Infinite recursion + // FIXME(llvm): loongarch fixed by + "csky" => false, + "hexagon" => false, + "loongarch64" => false, + "mips" | "mips64" | "mips32r6" | "mips64r6" => false, + "powerpc" | "powerpc64" => false, + "sparc" | "sparc64" => false, + "wasm32" | "wasm64" => false, // Most everything else works as of LLVM 19 - _ => (true, true), + _ => true, + }; + + let f128_enabled = match target.arch.as_str() { + // Unsupported + "arm64ec" => false, + // Selection failure + "mips64" | "mips64r6" => false, + // Selection failure + "nvptx64" => false, + // Selection failure + "powerpc64" if &target.os == "aix" => false, + // Selection failure + "sparc" => false, + // Most everything else works as of LLVM 19 + _ => true, }; // If the feature is set, disable these types. @@ -84,11 +99,11 @@ pub fn configure_f16_f128(target: &Target) { println!("cargo::rustc-check-cfg=cfg(f16_enabled)"); println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); - if f16_ok && !disable_both { + if f16_enabled && !disable_both { println!("cargo::rustc-cfg=f16_enabled"); } - if f128_ok && !disable_both { + if f128_enabled && !disable_both { println!("cargo::rustc-cfg=f128_enabled"); } } -- cgit 1.4.1-3-g733a5 From 7c1072e3fc7bb80c34edbac666a53c59e569c4e4 Mon Sep 17 00:00:00 2001 From: beetrees Date: Thu, 14 Nov 2024 18:13:10 +0000 Subject: Use `https:` links in `README.md` --- library/compiler-builtins/libm/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index e5d64bd2dc0..52d760a4f15 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -41,14 +41,14 @@ This crate supports rustc 1.63 and newer. ## License Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or -http://opensource.org/licenses/MIT). +https://opensource.org/licenses/MIT). ### Contribution Contributions are licensed under both the MIT license and the Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or -http://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state +https://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as mentioned, without any additional terms or conditions. -- cgit 1.4.1-3-g733a5 From 76f37552e7463598d8374fc15a11891031dd051a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 05:03:21 +0000 Subject: Remove tests against system musl We now have tests against our custom-built musl as well as tests against MPFR. The tests against system musl covers less than those against custom-built musl, and are less portable; there isn't much benefit to keeping them around so just remove them. --- library/compiler-builtins/libm/CONTRIBUTING.md | 20 +- library/compiler-builtins/libm/ci/run.sh | 5 - .../libm/crates/libm-test/Cargo.toml | 1 - .../libm/crates/libm-test/build.rs | 456 --------------------- .../libm/crates/libm-test/tests/musl_biteq.rs | 6 - library/compiler-builtins/libm/src/lib.rs | 25 -- 6 files changed, 12 insertions(+), 501 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index 0a174163190..aadcdf03618 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -6,9 +6,8 @@ `src/math/mod.rs` accordingly. Also, uncomment the corresponding trait method in `src/lib.rs`. - Write some simple tests in your module (using `#[test]`) -- Run `cargo test` to make sure it works -- Run `cargo test --features libm-test/test-musl-serialized` to compare your - implementation against musl's +- Run `cargo test` to make sure it works. Full tests are only run when enabling + features, see [Testing](#testing) below. - Send us a pull request! Make sure to run `cargo fmt` on your code before sending the PR. Also include "closes #42" in the PR description to close the corresponding issue. @@ -66,12 +65,17 @@ Normal tests can be executed with: cargo test ``` -If you'd like to run tests with randomized inputs that get compared against musl -itself, you'll need to be on a Linux system and then you can execute: +If you'd like to run tests with randomized inputs that get compared against +infinite-precision results, run: ```sh -cargo test --features libm-test/test-musl-serialized +cargo test --features libm-test/test-multiprecision,libm-test/build-musl --release ``` -Note that you may need to pass `--release` to Cargo if there are errors related -to integer overflow. +The multiprecision tests use the [`rug`] crate for bindings to MPFR. MPFR can +be difficult to build on non-Unix systems, refer to [`gmp_mpfr_sys`] for help. + +`build-musl` does not build with MSVC, Wasm, or Thumb. + +[`rug`]: https://docs.rs/rug/latest/rug/ +[`gmp_mpfr_sys`]: https://docs.rs/gmp-mpfr-sys/1.6.4/gmp_mpfr_sys/ diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 32453663e05..d89c8bdf060 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -57,11 +57,6 @@ case "$target" in *windows-gnu) extra_flags="$extra_flags --exclude libm-macros" ;; esac -if [ "$(uname -a)" = "Linux" ]; then - # also run the reference tests when we can. requires a Linux host. - extra_flags="$extra_flags --features libm-test/test-musl-serialized" -fi - # Make sure we can build with overriding features. We test the indibidual # features it controls separately. cargo check --no-default-features diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 3587b44e6a4..4d75b25f81e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -9,7 +9,6 @@ default = [] # Generate tests which are random inputs and the outputs are calculated with # musl libc. -test-musl-serialized = ["rand"] test-multiprecision = ["dep:az", "dep:rug"] # Build our own musl for testing and benchmarks diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index 40b3e56c046..dc3126dbb94 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -8,9 +8,6 @@ fn main() { emit_optimization_cfg(&cfg); emit_cfg_shorthands(&cfg); list_all_tests(&cfg); - - #[cfg(feature = "test-musl-serialized")] - musl_serialized_tests::generate(); } #[allow(dead_code)] @@ -93,456 +90,3 @@ fn list_all_tests(cfg: &Config) { let outfile = cfg.out_dir.join("all_files.rs"); fs::write(outfile, s).unwrap(); } - -/// At build time, generate the output of what the corresponding `*musl` target does with a range -/// of inputs. -/// -/// Serialize that target's output, run the same thing with our symbols, then load and compare -/// the resulting values. -#[cfg(feature = "test-musl-serialized")] -mod musl_serialized_tests { - use std::path::PathBuf; - use std::process::Command; - use std::{env, fs}; - - use rand::Rng; - use rand::seq::SliceRandom; - - // Number of tests to generate for each function - const NTESTS: usize = 500; - - // These files are all internal functions or otherwise miscellaneous, not - // defining a function we want to test. - const IGNORED_FILES: &[&str] = &[ - "fenv.rs", - // These are giving slightly different results compared to musl - "lgamma.rs", - "lgammaf.rs", - "tgamma.rs", - "j0.rs", - "j0f.rs", - "jn.rs", - "jnf.rs", - "j1.rs", - "j1f.rs", - ]; - - struct Function { - name: String, - args: Vec, - ret: Vec, - tests: Vec, - } - - enum Ty { - F32, - F64, - I32, - Bool, - } - - struct Test { - inputs: Vec, - outputs: Vec, - } - - pub fn generate() { - // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 - let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - let libm_test = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - let math_src = libm_test.join("../../src/math"); - - if target_arch == "powerpc64" { - return; - } - - let files = fs::read_dir(math_src) - .unwrap() - .map(|f| f.unwrap().path()) - .filter(file_needs_test) - .collect::>(); - - let mut math = Vec::new(); - for file in files { - if IGNORED_FILES.iter().any(|f| file.ends_with(f)) { - continue; - } - - println!("generating musl reference tests in {:?}", file); - - let contents = fs::read_to_string(file).unwrap(); - let mut functions = contents.lines().filter(|f| f.starts_with("pub fn")); - while let Some(function_to_test) = functions.next() { - math.push(parse(function_to_test)); - } - } - - // Generate a bunch of random inputs for each function. This will - // attempt to generate a good set of uniform test cases for exercising - // all the various functionality. - generate_random_tests(&mut math, &mut rand::thread_rng()); - - // After we have all our inputs, use the x86_64-unknown-linux-musl - // target to generate the expected output. - generate_test_outputs(&mut math); - //panic!("Boo"); - // ... and now that we have both inputs and expected outputs, do a bunch - // of codegen to create the unit tests which we'll actually execute. - generate_unit_tests(&math); - } - - /// Check whether a path within `src/math` should get tests generated. - fn file_needs_test(path: &PathBuf) -> bool { - // Skip directories - if path.is_dir() { - return false; - } - - let fname = path.file_name().unwrap().to_str().unwrap(); - - // Musl doesn't support `f16` or `f128` - !(fname.contains("f16") || fname.contains("f128")) - } - - /// A "poor man's" parser for the signature of a function - fn parse(s: &str) -> Function { - let s = eat(s, "pub fn "); - let pos = s.find('(').unwrap(); - let name = &s[..pos]; - let s = &s[pos + 1..]; - let end = s.find(')').unwrap(); - let args = s[..end] - .split(',') - .map(|arg| { - let colon = arg.find(':').unwrap(); - parse_ty(arg[colon + 1..].trim()) - }) - .collect::>(); - let tail = &s[end + 1..]; - let tail = eat(tail, " -> "); - let ret = parse_retty(tail.replace("{", "").trim()); - - return Function { name: name.to_string(), args, ret, tests: Vec::new() }; - - fn parse_ty(s: &str) -> Ty { - match s { - "f32" => Ty::F32, - "f64" => Ty::F64, - "i32" => Ty::I32, - "bool" => Ty::Bool, - other => panic!("unknown type `{}`", other), - } - } - - fn parse_retty(s: &str) -> Vec { - match s { - "(f32, f32)" => vec![Ty::F32, Ty::F32], - "(f32, i32)" => vec![Ty::F32, Ty::I32], - "(f64, f64)" => vec![Ty::F64, Ty::F64], - "(f64, i32)" => vec![Ty::F64, Ty::I32], - other => vec![parse_ty(other)], - } - } - - fn eat<'a>(s: &'a str, prefix: &str) -> &'a str { - if s.starts_with(prefix) { - &s[prefix.len()..] - } else { - panic!("{:?} didn't start with {:?}", s, prefix) - } - } - } - - fn generate_random_tests(functions: &mut [Function], rng: &mut R) { - for function in functions { - for _ in 0..NTESTS { - function.tests.push(generate_test(function, rng)); - } - } - - fn generate_test(function: &Function, rng: &mut R) -> Test { - let mut inputs = function.args.iter().map(|ty| ty.gen_i64(rng)).collect::>(); - - // First argument to this function appears to be a number of - // iterations, so passing in massive random numbers causes it to - // take forever to execute, so make sure we're not running random - // math code until the heat death of the universe. - if function.name == "jn" || function.name == "jnf" { - inputs[0] &= 0xffff; - } - - Test { - inputs, - // zero output for now since we'll generate it later - outputs: vec![], - } - } - } - - impl Ty { - fn gen_i64(&self, r: &mut R) -> i64 { - use std::{f32, f64}; - - return match self { - Ty::F32 => { - if r.gen_range(0..20) < 1 { - let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY].choose(r).unwrap(); - i.to_bits().into() - } else { - r.gen::().to_bits().into() - } - } - Ty::F64 => { - if r.gen_range(0..20) < 1 { - let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY].choose(r).unwrap(); - i.to_bits() as i64 - } else { - r.gen::().to_bits() as i64 - } - } - Ty::I32 => { - if r.gen_range(0..10) < 1 { - let i = *[i32::max_value(), 0, i32::min_value()].choose(r).unwrap(); - i.into() - } else { - r.gen::().into() - } - } - Ty::Bool => r.gen::() as i64, - }; - } - - fn libc_ty(&self) -> &'static str { - match self { - Ty::F32 => "f32", - Ty::F64 => "f64", - Ty::I32 => "i32", - Ty::Bool => "i32", - } - } - - fn libc_pty(&self) -> &'static str { - match self { - Ty::F32 => "*mut f32", - Ty::F64 => "*mut f64", - Ty::I32 => "*mut i32", - Ty::Bool => "*mut i32", - } - } - - fn default(&self) -> &'static str { - match self { - Ty::F32 => "0_f32", - Ty::F64 => "0_f64", - Ty::I32 => "0_i32", - Ty::Bool => "false", - } - } - - fn to_i64(&self) -> &'static str { - match self { - Ty::F32 => ".to_bits() as i64", - Ty::F64 => ".to_bits() as i64", - Ty::I32 => " as i64", - Ty::Bool => " as i64", - } - } - } - - fn generate_test_outputs(functions: &mut [Function]) { - let mut src = String::new(); - let dst = std::env::var("OUT_DIR").unwrap(); - - // Generate a program which will run all tests with all inputs in - // `functions`. This program will write all outputs to stdout (in a - // binary format). - src.push_str("use std::io::Write;"); - src.push_str("fn main() {"); - src.push_str("let mut result = Vec::new();"); - for function in functions.iter_mut() { - src.push_str("unsafe {"); - src.push_str("extern { fn "); - src.push_str(&function.name); - src.push_str("("); - - let (ret, retptr) = match function.name.as_str() { - "sincos" | "sincosf" => (None, &function.ret[..]), - _ => (Some(&function.ret[0]), &function.ret[1..]), - }; - for (i, arg) in function.args.iter().enumerate() { - src.push_str(&format!("arg{}: {},", i, arg.libc_ty())); - } - for (i, ret) in retptr.iter().enumerate() { - src.push_str(&format!("argret{}: {},", i, ret.libc_pty())); - } - src.push_str(")"); - if let Some(ty) = ret { - src.push_str(" -> "); - src.push_str(ty.libc_ty()); - } - src.push_str("; }"); - - src.push_str(&format!("static TESTS: &[[i64; {}]]", function.args.len())); - src.push_str(" = &["); - for test in function.tests.iter() { - src.push_str("["); - for val in test.inputs.iter() { - src.push_str(&val.to_string()); - src.push_str(","); - } - src.push_str("],"); - } - src.push_str("];"); - - src.push_str("for test in TESTS {"); - for (i, arg) in retptr.iter().enumerate() { - src.push_str(&format!("let mut argret{} = {};", i, arg.default())); - } - src.push_str("let output = "); - src.push_str(&function.name); - src.push_str("("); - for (i, arg) in function.args.iter().enumerate() { - src.push_str(&match arg { - Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), - Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), - Ty::I32 => format!("test[{}] as i32", i), - Ty::Bool => format!("test[{}] as i32", i), - }); - src.push_str(","); - } - for (i, _) in retptr.iter().enumerate() { - src.push_str(&format!("&mut argret{},", i)); - } - src.push_str(");"); - if let Some(ty) = &ret { - src.push_str(&format!("let output = output{};", ty.to_i64())); - src.push_str("result.extend_from_slice(&output.to_le_bytes());"); - } - - for (i, ret) in retptr.iter().enumerate() { - src.push_str(&format!( - "result.extend_from_slice(&(argret{}{}).to_le_bytes());", - i, - ret.to_i64(), - )); - } - src.push_str("}"); - - src.push_str("}"); - } - - src.push_str("std::io::stdout().write_all(&result).unwrap();"); - - src.push_str("}"); - - let path = format!("{}/gen.rs", dst); - fs::write(&path, src).unwrap(); - - // Make it somewhat pretty if something goes wrong - drop(Command::new("rustfmt").arg(&path).status()); - - // Compile and execute this tests for the musl target, assuming we're an - // x86_64 host effectively. - let status = Command::new("rustc") - .current_dir(&dst) - .arg(&path) - .arg("--target=x86_64-unknown-linux-musl") - .status() - .unwrap(); - assert!(status.success()); - let output = Command::new("./gen").current_dir(&dst).output().unwrap(); - assert!(output.status.success()); - assert!(output.stderr.is_empty()); - - // Map all the output bytes back to an `i64` and then shove it all into - // the expected results. - let mut results = output.stdout.chunks_exact(8).map(|buf| { - let mut exact = [0; 8]; - exact.copy_from_slice(buf); - i64::from_le_bytes(exact) - }); - - for f in functions.iter_mut() { - for test in f.tests.iter_mut() { - test.outputs = (0..f.ret.len()).map(|_| results.next().unwrap()).collect(); - } - } - assert!(results.next().is_none()); - } - - /// Codegens a file which has a ton of `#[test]` annotations for all the - /// tests that we generated above. - fn generate_unit_tests(functions: &[Function]) { - let mut src = String::new(); - let dst = std::env::var("OUT_DIR").unwrap(); - - for function in functions { - src.push_str("#[test]"); - src.push_str("fn "); - src.push_str(&function.name); - src.push_str("_matches_musl() {"); - src.push_str(&format!( - "static TESTS: &[([i64; {}], [i64; {}])]", - function.args.len(), - function.ret.len(), - )); - src.push_str(" = &["); - for test in function.tests.iter() { - src.push_str("(["); - for val in test.inputs.iter() { - src.push_str(&val.to_string()); - src.push_str(","); - } - src.push_str("],"); - src.push_str("["); - for val in test.outputs.iter() { - src.push_str(&val.to_string()); - src.push_str(","); - } - src.push_str("],"); - src.push_str("),"); - } - src.push_str("];"); - - src.push_str("for (test, expected) in TESTS {"); - src.push_str("let output = libm::"); - src.push_str(&function.name); - src.push_str("("); - for (i, arg) in function.args.iter().enumerate() { - src.push_str(&match arg { - Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), - Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), - Ty::I32 => format!("test[{}] as i32", i), - Ty::Bool => format!("test[{}] as i32", i), - }); - src.push_str(","); - } - src.push_str(");"); - - for (i, ret) in function.ret.iter().enumerate() { - let get = if function.ret.len() == 1 { String::new() } else { format!(".{}", i) }; - src.push_str(&(match ret { - Ty::F32 => format!("if libm::_eqf(output{}, f32::from_bits(expected[{}] as u32)).is_ok() {{ continue }}", get, i), - Ty::F64 => format!("if libm::_eq(output{}, f64::from_bits(expected[{}] as u64)).is_ok() {{ continue }}", get, i), - Ty::I32 => format!("if output{} as i64 == expected[{}] {{ continue }}", get, i), - Ty::Bool => unreachable!(), - })); - } - - src.push_str( - r#" - panic!("INPUT: {:?} EXPECTED: {:?} ACTUAL {:?}", test, expected, output); - "#, - ); - src.push_str("}"); - - src.push_str("}"); - } - - let path = format!("{}/musl-tests.rs", dst); - fs::write(&path, src).unwrap(); - - // Try to make it somewhat pretty - drop(Command::new("rustfmt").arg(&path).status()); - } -} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs b/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs deleted file mode 100644 index f586fd03d12..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! compare - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(all(test, feature = "test-musl-serialized"))] -include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 511ab598dba..6bb06b5b81f 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -23,28 +23,3 @@ use core::{f32, f64}; pub use libm_helper::*; pub use self::math::*; - -/// Approximate equality with 1 ULP of tolerance -#[doc(hidden)] -#[inline] -pub fn _eqf(a: f32, b: f32) -> Result<(), u32> { - if a.is_nan() && b.is_nan() { - Ok(()) - } else { - let err = (a.to_bits() as i32).wrapping_sub(b.to_bits() as i32).abs(); - - if err <= 1 { Ok(()) } else { Err(err as u32) } - } -} - -#[doc(hidden)] -#[inline] -pub fn _eq(a: f64, b: f64) -> Result<(), u64> { - if a.is_nan() && b.is_nan() { - Ok(()) - } else { - let err = (a.to_bits() as i64).wrapping_sub(b.to_bits() as i64).abs(); - - if err <= 1 { Ok(()) } else { Err(err as u64) } - } -} -- cgit 1.4.1-3-g733a5 From a4d9b4a6a25dbe8bcdea6344256139a735d61135 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 21:49:37 +0000 Subject: Fix a bug in `abs_diff` These implementations of `abs_diff` were added in c2ff1b3119 ("Completely overhaul fuzz testing"), but the signed implementation is wrong when |x| + |y| exceeds the integer's limits (e.g. `(-128).abs_diff(1)` should be 128 but currently these return 127. Resolve this by just using `std`'s implementation since that is stable now. This isn't used anywhere critical, we probably just weren't hitting the edge case. --- library/compiler-builtins/src/int/mod.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 0d3b0ce4048..c0d5a6715e3 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -240,11 +240,7 @@ macro_rules! int_impl { } fn abs_diff(self, other: Self) -> Self { - if self < other { - other.wrapping_sub(self) - } else { - self.wrapping_sub(other) - } + self.abs_diff(other) } int_impl_common!($uty); @@ -277,7 +273,7 @@ macro_rules! int_impl { } fn abs_diff(self, other: Self) -> $uty { - self.wrapping_sub(other).wrapping_abs() as $uty + self.abs_diff(other) } int_impl_common!($ity); -- cgit 1.4.1-3-g733a5 From 2cbacf89afcc5a2db36c9f682f46e21b132944b0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 22:24:38 +0000 Subject: Fix a bug in `abs_diff` These were taken from `compiler-builtins` but the implementation has a bug near the integer limits. Fixed in `compiler-builtins` by using `core`'s implementation at [1], this is the corresponding fix for `libm`. [1]: https://github.com/rust-lang/compiler-builtins/pull/736 --- library/compiler-builtins/libm/src/math/support/int_traits.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index c72c1d5cbbb..ded990bdfde 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -184,7 +184,7 @@ macro_rules! int_impl { } fn abs_diff(self, other: Self) -> Self { - if self < other { other.wrapping_sub(self) } else { self.wrapping_sub(other) } + self.abs_diff(other) } int_impl_common!($uty); @@ -221,7 +221,7 @@ macro_rules! int_impl { } fn abs_diff(self, other: Self) -> $uty { - self.wrapping_sub(other).wrapping_abs() as $uty + self.abs_diff(other) } int_impl_common!($ity); -- cgit 1.4.1-3-g733a5 From 4cdb9ec6749e45982cbb4ff1d6d788a8136e551f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 23:15:16 +0000 Subject: Introduce helper types for accessing trait items The ambiguous associated types error sometimes fires in cases where it shouldn't be ambiguous ([1]), which can make things clunky when working with chained associated types (e.g. `Op::FTy::Int::*` does not work). Add helper types that we can use instead of the full syntax. There aren't too many cases in-crate now but this is relevant for some open PRs. [1]: https://github.com/rust-lang/rust/issues/38078 --- .../compiler-builtins/libm/crates/libm-test/benches/random.rs | 2 +- library/compiler-builtins/libm/crates/libm-test/src/lib.rs | 4 ++-- library/compiler-builtins/libm/crates/libm-test/src/op.rs | 9 +++++++++ library/compiler-builtins/libm/src/math/support/float_traits.rs | 4 ++++ library/compiler-builtins/libm/src/math/support/int_traits.rs | 6 +++++- library/compiler-builtins/libm/src/math/support/mod.rs | 3 ++- 6 files changed, 23 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index d77d579080e..9ccc38fe3a0 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -26,7 +26,7 @@ macro_rules! musl_rand_benches { #[cfg(feature = "build-musl")] let musl_extra = MuslExtra { - musl_fn: Some(musl_math_sys::$fn_name as ::CFn), + musl_fn: Some(musl_math_sys::$fn_name as libm_test::CFn), skip_on_i586: $skip_on_i586 }; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 7f0d9aa7553..bc96b466b56 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -5,8 +5,8 @@ pub mod op; mod precision; mod test_traits; -pub use libm::support::{Float, Int}; -pub use op::{BaseName, Identifier, MathOp}; +pub use libm::support::{Float, Int, IntTy}; +pub use op::{BaseName, CFn, FTy, Identifier, MathOp, RustFn, RustRet}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index 50b455d3a93..0faeceb0997 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -70,6 +70,15 @@ pub trait MathOp { const ROUTINE: Self::RustFn; } +/// Access the associated `FTy` type from an op (helper to avoid ambiguous associated types). +pub type FTy = ::FTy; +/// Access the associated `CFn` type from an op (helper to avoid ambiguous associated types). +pub type CFn = ::CFn; +/// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types). +pub type RustFn = ::RustFn; +/// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). +pub type RustRet = ::RustRet; + macro_rules! do_thing { // Matcher for unary functions ( diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 0047ba3689e..5808aeebc13 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -153,6 +153,10 @@ pub trait Float: } } +/// Access the associated `Int` type from a float (helper to avoid ambiguous associated types). +#[allow(dead_code)] +pub type IntTy = ::Int; + macro_rules! float_impl { ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { impl Float for $ty { diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index ded990bdfde..380313c1e6b 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -26,6 +26,10 @@ pub trait MinInt: const MAX: Self; } +/// Access the associated `OtherSign` type from an int (helper to avoid ambiguous associated +/// types). +pub type OtherSign = ::OtherSign; + /// Trait for some basic operations on integers #[allow(dead_code)] pub trait Int: @@ -53,7 +57,7 @@ pub trait Int: + CastInto + CastFrom { - fn signed(self) -> ::OtherSign; + fn signed(self) -> OtherSign; fn unsigned(self) -> Self::Unsigned; fn from_unsigned(unsigned: Self::Unsigned) -> Self; fn abs(self) -> Self; diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 04a313abc97..25681c307da 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -4,7 +4,8 @@ mod float_traits; mod hex_float; mod int_traits; -pub use float_traits::Float; +#[allow(unused_imports)] +pub use float_traits::{Float, IntTy}; #[allow(unused_imports)] pub use hex_float::{hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -- cgit 1.4.1-3-g733a5 From ba1d271158fb73b71955680dea6280bfa753cf2b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 23:56:45 +0000 Subject: Rename associated type helpers, add `OpITy` Change the names to make them less ambiguous. Additionally add `OpITy` for accessing the same-sized integer of an operation's float type. --- .../compiler-builtins/libm/crates/libm-test/benches/random.rs | 2 +- library/compiler-builtins/libm/crates/libm-test/src/lib.rs | 2 +- library/compiler-builtins/libm/crates/libm-test/src/op.rs | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 9ccc38fe3a0..b9c39334c14 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -26,7 +26,7 @@ macro_rules! musl_rand_benches { #[cfg(feature = "build-musl")] let musl_extra = MuslExtra { - musl_fn: Some(musl_math_sys::$fn_name as libm_test::CFn), + musl_fn: Some(musl_math_sys::$fn_name as libm_test::OpCFn), skip_on_i586: $skip_on_i586 }; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index bc96b466b56..17a06b3be3a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -6,7 +6,7 @@ mod precision; mod test_traits; pub use libm::support::{Float, Int, IntTy}; -pub use op::{BaseName, CFn, FTy, Identifier, MathOp, RustFn, RustRet}; +pub use op::{BaseName, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index 0faeceb0997..bcea31c22b6 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -71,13 +71,15 @@ pub trait MathOp { } /// Access the associated `FTy` type from an op (helper to avoid ambiguous associated types). -pub type FTy = ::FTy; +pub type OpFTy = ::FTy; +/// Access the associated `FTy::Int` type from an op (helper to avoid ambiguous associated types). +pub type OpITy = <::FTy as Float>::Int; /// Access the associated `CFn` type from an op (helper to avoid ambiguous associated types). -pub type CFn = ::CFn; +pub type OpCFn = ::CFn; /// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types). -pub type RustFn = ::RustFn; +pub type OpRustFn = ::RustFn; /// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). -pub type RustRet = ::RustRet; +pub type OpRustRet = ::RustRet; macro_rules! do_thing { // Matcher for unary functions -- cgit 1.4.1-3-g733a5 From e8eb76a45af2290ca8b00a82eef11a03ee559cc5 Mon Sep 17 00:00:00 2001 From: Sebastian Neubauer Date: Thu, 26 Dec 2024 06:01:14 +0100 Subject: Disable f128 for amdgpu (#737) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `compiler_builtins` fails to compile to amdgpu if f128 is enabled. The reason seems to be that compiler_builtins uses libcalls in the implementation. I’m not really familiar with what libcalls are, but the LLVM amdgpu backend explicitly does not support them. Error message: ``` LLVM ERROR: unsupported libcall legalization ``` --- library/compiler-builtins/configure.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index 0a0bd503d53..e20c717ec75 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -79,6 +79,8 @@ pub fn configure_f16_f128(target: &Target) { }; let f128_enabled = match target.arch.as_str() { + // Unsupported (libcall is not supported) + "amdgpu" => false, // Unsupported "arm64ec" => false, // Selection failure -- cgit 1.4.1-3-g733a5 From a078f5a0c54ec041cdfe351f2413214ea1b56966 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 26 Dec 2024 05:01:38 +0000 Subject: chore: release v0.1.140 --- library/compiler-builtins/CHANGELOG.md | 8 ++++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index 5c65aa8713e..f888591437b 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.140](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.139...compiler_builtins-v0.1.140) - 2024-12-26 + +### Other + +- Disable f128 for amdgpu ([#737](https://github.com/rust-lang/compiler-builtins/pull/737)) +- Fix a bug in `abs_diff` +- Disable `f16` on platforms that have recursion problems + ## [0.1.139](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.138...compiler_builtins-v0.1.139) - 2024-11-03 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 33f1c9a3ad8..33d5c06b78c 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.139" +version = "0.1.140" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 723e68d137ad20b20912be802669a6ce8367a17e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 26 Dec 2024 09:13:58 +0000 Subject: Replace string function name matching with enums where possible --- .../libm/crates/libm-test/src/gen/random.rs | 5 +- .../libm/crates/libm-test/src/precision.rs | 100 +++++++++------------ .../libm/crates/libm-test/src/test_traits.rs | 3 - 3 files changed, 46 insertions(+), 62 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index e347b3c63ae..527cd135142 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -7,7 +7,7 @@ use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; use super::CachedInput; -use crate::{CheckCtx, GenerateInput}; +use crate::{BaseName, CheckCtx, GenerateInput}; const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; @@ -110,7 +110,6 @@ pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator, { - let inputs = - if ctx.fn_name == "jn" || ctx.fn_name == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; + let inputs = if ctx.base_name == BaseName::Jn { &TEST_CASES_JN } else { &TEST_CASES }; inputs.get_cases() } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index cf9115430c4..c7f9d9e3011 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -6,7 +6,7 @@ use core::f32; use CheckBasis::{Mpfr, Musl}; use Identifier as Id; -use crate::{CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; +use crate::{BaseName, CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; /// Type implementing [`IgnoreCase`]. pub struct SpecialCase; @@ -106,25 +106,26 @@ impl MaybeOverride<(f32,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if ctx.fn_name == "expm1f" && input.0 > 80.0 && actual.is_infinite() { + if ctx.base_name == BaseName::Expm1 && input.0 > 80.0 && actual.is_infinite() { // we return infinity but the number is representable return XFAIL; } - if ctx.fn_name == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { + if ctx.base_name == BaseName::Sinh && input.0.abs() > 80.0 && actual.is_nan() { // we return some NaN that should be real values or infinite // doesn't seem to happen on x86 return XFAIL; } } - if ctx.fn_name == "acoshf" && input.0 < -1.0 { + if ctx.base_name == BaseName::Acosh && input.0 < -1.0 { // acoshf is undefined for x <= 1.0, but we return a random result at lower // values. return XFAIL; } - if ctx.fn_name == "lgammaf" || ctx.fn_name == "lgammaf_r" && input.0 < 0.0 { + if ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR && input.0 < 0.0 + { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -141,7 +142,7 @@ impl MaybeOverride<(f32,)> for SpecialCase { // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fn_name == "lgammaf_r" + && ctx.base_name == BaseName::LgammaR && input.0 == f32::NEG_INFINITY && actual.abs() == expected.abs() { @@ -161,13 +162,13 @@ impl MaybeOverride<(f64,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if cfg!(target_arch = "x86") && ctx.fn_name == "acosh" && input.0 < 1.0 { + if cfg!(target_arch = "x86") && ctx.base_name == BaseName::Acosh && input.0 < 1.0 { // The function is undefined, both implementations return random results return SKIP; } if cfg!(x86_no_sse) - && ctx.fn_name == "ceil" + && ctx.base_name == BaseName::Ceil && input.0 < 0.0 && input.0 > -1.0 && expected == F::ZERO @@ -178,13 +179,14 @@ impl MaybeOverride<(f64,)> for SpecialCase { } } - if ctx.fn_name == "acosh" && input.0 < 1.0 { + if ctx.base_name == BaseName::Acosh && input.0 < 1.0 { // The function is undefined for the inputs, musl and our libm both return // random results. return XFAIL; } - if ctx.fn_name == "lgamma" || ctx.fn_name == "lgamma_r" && input.0 < 0.0 { + if ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR && input.0 < 0.0 + { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -201,7 +203,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fn_name == "lgamma_r" + && ctx.base_name == BaseName::LgammaR && input.0 == f64::NEG_INFINITY && actual.abs() == expected.abs() { @@ -214,7 +216,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { /// Check NaN bits if the function requires it fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { - if !(ctx.base_name_str == "fabs" || ctx.base_name_str == "copysign") { + if !(ctx.base_name == BaseName::Fabs || ctx.base_name == BaseName::Copysign) { return None; } @@ -270,24 +272,16 @@ fn maybe_skip_binop_nan( expected: F2, ctx: &CheckCtx, ) -> Option { - match ctx.basis { - CheckBasis::Musl => { - if (ctx.base_name_str == "fmax" || ctx.base_name_str == "fmin") - && (input.0.is_nan() || input.1.is_nan()) - && expected.is_nan() - { - XFAIL - } else { - None - } - } - CheckBasis::Mpfr => { - if ctx.base_name_str == "copysign" && input.1.is_nan() { - SKIP - } else { - None - } + match (&ctx.basis, ctx.base_name) { + (Musl, BaseName::Fmin | BaseName::Fmax) + if (input.0.is_nan() || input.1.is_nan()) && expected.is_nan() => + { + XFAIL } + + (Mpfr, BaseName::Copysign) if input.1.is_nan() => SKIP, + + _ => None, } } @@ -299,20 +293,17 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - match ctx.basis { - CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), - CheckBasis::Mpfr => { - // We return +0.0, MPFR returns -0.0 - if ctx.fn_name == "jnf" - && input.1 == f32::NEG_INFINITY - && actual == F::ZERO - && expected == F::ZERO - { - XFAIL - } else { - None - } + match (&ctx.basis, ctx.base_name) { + (Musl, _) => bessel_prec_dropoff(input, ulp, ctx), + + // We return +0.0, MPFR returns -0.0 + (Mpfr, BaseName::Jn) + if input.1 == f32::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO => + { + XFAIL } + + _ => None, } } } @@ -324,20 +315,17 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - match ctx.basis { - CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), - CheckBasis::Mpfr => { - // We return +0.0, MPFR returns -0.0 - if ctx.fn_name == "jn" - && input.1 == f64::NEG_INFINITY - && actual == F::ZERO - && expected == F::ZERO - { - XFAIL - } else { - bessel_prec_dropoff(input, ulp, ctx) - } + match (&ctx.basis, ctx.base_name) { + (Musl, _) => bessel_prec_dropoff(input, ulp, ctx), + + // We return +0.0, MPFR returns -0.0 + (Mpfr, BaseName::Jn) + if input.1 == f64::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO => + { + XFAIL } + + _ => None, } } } @@ -348,7 +336,7 @@ fn bessel_prec_dropoff( ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - if ctx.base_name_str == "jn" { + if ctx.base_name == BaseName::Jn { if input.0 > 4000 { return XFAIL; } else if input.0 > 2000 { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index b8e0aa108a3..ca933bbda63 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -22,8 +22,6 @@ pub struct CheckCtx { pub base_name: BaseName, /// Function name. pub fn_name: &'static str, - /// Return the unsuffixed version of the function name. - pub base_name_str: &'static str, /// Source of truth for tests. pub basis: CheckBasis, } @@ -36,7 +34,6 @@ impl CheckCtx { fn_ident, fn_name: fn_ident.as_str(), base_name: fn_ident.base_name(), - base_name_str: fn_ident.base_name().as_str(), basis, }; ret.ulp = crate::default_ulp(&ret); -- cgit 1.4.1-3-g733a5 From 80dca45a80ebb17cc9974591289050b9dd867363 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Dec 2024 10:58:36 +0000 Subject: Fix new `clippy::precedence` lints [1] extends Clippy's `precedence` lint to cover `&`, `|`, and bitshifts. Update cases that are flagged by this in the most recent nightly. [1]: https://github.com/rust-lang/rust-clippy/pull/13743 --- library/compiler-builtins/libm/src/math/ceil.rs | 2 +- library/compiler-builtins/libm/src/math/exp10.rs | 2 +- library/compiler-builtins/libm/src/math/exp10f.rs | 2 +- library/compiler-builtins/libm/src/math/exp2.rs | 2 +- library/compiler-builtins/libm/src/math/fma.rs | 12 ++++++------ library/compiler-builtins/libm/src/math/fmod.rs | 4 ++-- library/compiler-builtins/libm/src/math/fmodf.rs | 4 ++-- library/compiler-builtins/libm/src/math/j1.rs | 4 ++-- library/compiler-builtins/libm/src/math/jn.rs | 4 ++-- library/compiler-builtins/libm/src/math/log10.rs | 2 +- library/compiler-builtins/libm/src/math/log1p.rs | 2 +- library/compiler-builtins/libm/src/math/log2.rs | 2 +- library/compiler-builtins/libm/src/math/mod.rs | 2 +- library/compiler-builtins/libm/src/math/modf.rs | 2 +- library/compiler-builtins/libm/src/math/modff.rs | 2 +- library/compiler-builtins/libm/src/math/nextafter.rs | 6 +++--- library/compiler-builtins/libm/src/math/rint.rs | 2 +- library/compiler-builtins/libm/src/math/rintf.rs | 2 +- library/compiler-builtins/libm/src/math/sqrt.rs | 2 +- library/compiler-builtins/libm/src/math/trunc.rs | 2 +- library/compiler-builtins/libm/src/math/truncf.rs | 2 +- 21 files changed, 32 insertions(+), 32 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index c198ebcfe1b..b0576f3dc1f 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -16,7 +16,7 @@ pub fn ceil(x: f64) -> f64 { } let u: u64 = x.to_bits(); - let e: i64 = (u >> 52 & 0x7ff) as i64; + let e: i64 = ((u >> 52) & 0x7ff) as i64; let y: f64; if e >= 0x3ff + 52 || x == 0. { diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs index 2c3df017344..7c33c92b603 100644 --- a/library/compiler-builtins/libm/src/math/exp10.rs +++ b/library/compiler-builtins/libm/src/math/exp10.rs @@ -12,7 +12,7 @@ pub fn exp10(x: f64) -> f64 { let (mut y, n) = modf(x); let u: u64 = n.to_bits(); /* fabs(n) < 16 without raising invalid on nan */ - if (u >> 52 & 0x7ff) < 0x3ff + 4 { + if ((u >> 52) & 0x7ff) < 0x3ff + 4 { if y == 0.0 { return i!(P10, ((n as isize) + 15) as usize); } diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs index e81d18380b9..0520a41f2e9 100644 --- a/library/compiler-builtins/libm/src/math/exp10f.rs +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -11,7 +11,7 @@ pub fn exp10f(x: f32) -> f32 { let (mut y, n) = modff(x); let u = n.to_bits(); /* fabsf(n) < 8 without raising invalid on nan */ - if (u >> 23 & 0xff) < 0x7f + 3 { + if ((u >> 23) & 0xff) < 0x7f + 3 { if y == 0.0 { return i!(P10, ((n as isize) + 7) as usize); } diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index dce2ab4df6f..6e98d066cbf 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -341,7 +341,7 @@ pub fn exp2(mut x: f64) -> f64 { /* Filter out exceptional cases. */ let ui = f64::to_bits(x); - let ix = ui >> 32 & 0x7fffffff; + let ix = (ui >> 32) & 0x7fffffff; if ix >= 0x408ff000 { /* |x| >= 1022 or nan */ if ix >= 0x40900000 && ui >> 63 == 0 { diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index bb2028fa77f..826143d5a47 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -82,7 +82,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { d -= 64; if d == 0 { } else if d < 64 { - rlo = rhi << (64 - d) | rlo >> d | ((rlo << (64 - d)) != 0) as u64; + rlo = (rhi << (64 - d)) | (rlo >> d) | ((rlo << (64 - d)) != 0) as u64; rhi = rhi >> d; } else { rlo = 1; @@ -95,7 +95,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { if d == 0 { zlo = nz.m; } else if d < 64 { - zlo = nz.m >> d | ((nz.m << (64 - d)) != 0) as u64; + zlo = (nz.m >> d) | ((nz.m << (64 - d)) != 0) as u64; } else { zlo = 1; } @@ -127,11 +127,11 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { e += 64; d = rhi.leading_zeros() as i32 - 1; /* note: d > 0 */ - rhi = rhi << d | rlo >> (64 - d) | ((rlo << d) != 0) as u64; + rhi = (rhi << d) | (rlo >> (64 - d)) | ((rlo << d) != 0) as u64; } else if rlo != 0 { d = rlo.leading_zeros() as i32 - 1; if d < 0 { - rhi = rlo >> 1 | (rlo & 1); + rhi = (rlo >> 1) | (rlo & 1); } else { rhi = rlo << d; } @@ -165,7 +165,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { /* one bit is lost when scaled, add another top bit to only round once at conversion if it is inexact */ if (rhi << 53) != 0 { - i = (rhi >> 1 | (rhi & 1) | 1 << 62) as i64; + i = ((rhi >> 1) | (rhi & 1) | (1 << 62)) as i64; if sign != 0 { i = -i; } @@ -182,7 +182,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { } else { /* only round once when scaled */ d = 10; - i = ((rhi >> d | ((rhi << (64 - d)) != 0) as u64) << d) as i64; + i = (((rhi >> d) | ((rhi << (64 - d)) != 0) as u64) << d) as i64; if sign != 0 { i = -i; } diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs index df16162bcae..b68e6b0ea3c 100644 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -2,8 +2,8 @@ pub fn fmod(x: f64, y: f64) -> f64 { let mut uxi = x.to_bits(); let mut uyi = y.to_bits(); - let mut ex = (uxi >> 52 & 0x7ff) as i64; - let mut ey = (uyi >> 52 & 0x7ff) as i64; + let mut ex = ((uxi >> 52) & 0x7ff) as i64; + let mut ey = ((uyi >> 52) & 0x7ff) as i64; let sx = uxi >> 63; let mut i; diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index 671af85800f..4de18195770 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -4,8 +4,8 @@ use core::f32; pub fn fmodf(x: f32, y: f32) -> f32 { let mut uxi = x.to_bits(); let mut uyi = y.to_bits(); - let mut ex = (uxi >> 23 & 0xff) as i32; - let mut ey = (uyi >> 23 & 0xff) as i32; + let mut ex = ((uxi >> 23) & 0xff) as i32; + let mut ey = ((uyi >> 23) & 0xff) as i32; let sx = uxi & 0x80000000; let mut i; diff --git a/library/compiler-builtins/libm/src/math/j1.rs b/library/compiler-builtins/libm/src/math/j1.rs index cef17a63e37..578ae59d3ab 100644 --- a/library/compiler-builtins/libm/src/math/j1.rs +++ b/library/compiler-builtins/libm/src/math/j1.rs @@ -171,10 +171,10 @@ pub fn y1(x: f64) -> f64 { lx = get_low_word(x); /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ - if (ix << 1 | lx) == 0 { + if (ix << 1) | lx == 0 { return -1.0 / 0.0; } - if (ix >> 31) != 0 { + if ix >> 31 != 0 { return 0.0 / 0.0; } if ix >= 0x7ff00000 { diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs index 7f98ddc055a..d228781d12a 100644 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -55,7 +55,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { ix &= 0x7fffffff; // -lx == !lx + 1 - if (ix | (lx | ((!lx).wrapping_add(1))) >> 31) > 0x7ff00000 { + if ix | ((lx | (!lx).wrapping_add(1)) >> 31) > 0x7ff00000 { /* nan */ return x; } @@ -265,7 +265,7 @@ pub fn yn(n: i32, x: f64) -> f64 { ix &= 0x7fffffff; // -lx == !lx + 1 - if (ix | (lx | ((!lx).wrapping_add(1))) >> 31) > 0x7ff00000 { + if ix | ((lx | (!lx).wrapping_add(1)) >> 31) > 0x7ff00000 { /* nan */ return x; } diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs index f9d118f1292..8c9d68c492d 100644 --- a/library/compiler-builtins/libm/src/math/log10.rs +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -78,7 +78,7 @@ pub fn log10(mut x: f64) -> f64 { hx += 0x3ff00000 - 0x3fe6a09e; k += (hx >> 20) as i32 - 0x3ff; hx = (hx & 0x000fffff) + 0x3fe6a09e; - ui = (hx as u64) << 32 | (ui & 0xffffffff); + ui = ((hx as u64) << 32) | (ui & 0xffffffff); x = f64::from_bits(ui); f = x - 1.0; diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index 80561ec7415..b7f3fb09e15 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -125,7 +125,7 @@ pub fn log1p(x: f64) -> f64 { } /* reduce u into [sqrt(2)/2, sqrt(2)] */ hu = (hu & 0x000fffff) + 0x3fe6a09e; - ui = (hu as u64) << 32 | (ui & 0xffffffff); + ui = ((hu as u64) << 32) | (ui & 0xffffffff); f = f64::from_bits(ui) - 1.; } hfsq = 0.5 * f * f; diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index 59533340bd8..701f63c25e7 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -75,7 +75,7 @@ pub fn log2(mut x: f64) -> f64 { hx += 0x3ff00000 - 0x3fe6a09e; k += (hx >> 20) as i32 - 0x3ff; hx = (hx & 0x000fffff) + 0x3fe6a09e; - ui = (hx as u64) << 32 | (ui & 0xffffffff); + ui = ((hx as u64) << 32) | (ui & 0xffffffff); x = f64::from_bits(ui); f = x - 1.0; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index afebdf5864c..3852c774e80 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -359,5 +359,5 @@ fn with_set_low_word(f: f64, lo: u32) -> f64 { #[inline] fn combine_words(hi: u32, lo: u32) -> f64 { - f64::from_bits((hi as u64) << 32 | lo as u64) + f64::from_bits(((hi as u64) << 32) | lo as u64) } diff --git a/library/compiler-builtins/libm/src/math/modf.rs b/library/compiler-builtins/libm/src/math/modf.rs index bcab33a810d..e29e80ccf5f 100644 --- a/library/compiler-builtins/libm/src/math/modf.rs +++ b/library/compiler-builtins/libm/src/math/modf.rs @@ -2,7 +2,7 @@ pub fn modf(x: f64) -> (f64, f64) { let rv2: f64; let mut u = x.to_bits(); let mask: u64; - let e = ((u >> 52 & 0x7ff) as i32) - 0x3ff; + let e = (((u >> 52) & 0x7ff) as i32) - 0x3ff; /* no fractional part */ if e >= 52 { diff --git a/library/compiler-builtins/libm/src/math/modff.rs b/library/compiler-builtins/libm/src/math/modff.rs index 56ece12e3c0..fac60abaa55 100644 --- a/library/compiler-builtins/libm/src/math/modff.rs +++ b/library/compiler-builtins/libm/src/math/modff.rs @@ -2,7 +2,7 @@ pub fn modff(x: f32) -> (f32, f32) { let rv2: f32; let mut u: u32 = x.to_bits(); let mask: u32; - let e = ((u >> 23 & 0xff) as i32) - 0x7f; + let e = (((u >> 23) & 0xff) as i32) - 0x7f; /* no fractional part */ if e >= 23 { diff --git a/library/compiler-builtins/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/src/math/nextafter.rs index 422bd7496d5..c991ff6f233 100644 --- a/library/compiler-builtins/libm/src/math/nextafter.rs +++ b/library/compiler-builtins/libm/src/math/nextafter.rs @@ -16,14 +16,14 @@ pub fn nextafter(x: f64, y: f64) -> f64 { if ay == 0 { return y; } - ux_i = (uy_i & 1_u64 << 63) | 1; - } else if ax > ay || ((ux_i ^ uy_i) & 1_u64 << 63) != 0 { + ux_i = (uy_i & (1_u64 << 63)) | 1; + } else if ax > ay || ((ux_i ^ uy_i) & (1_u64 << 63)) != 0 { ux_i -= 1; } else { ux_i += 1; } - let e = ux_i >> 52 & 0x7ff; + let e = (ux_i >> 52) & 0x7ff; // raise overflow if ux.f is infinite and x is finite if e == 0x7ff { force_eval!(x + x); diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 618b26e5466..cbdc3c2b91c 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -2,7 +2,7 @@ pub fn rint(x: f64) -> f64 { let one_over_e = 1.0 / f64::EPSILON; let as_u64: u64 = x.to_bits(); - let exponent: u64 = as_u64 >> 52 & 0x7ff; + let exponent: u64 = (as_u64 >> 52) & 0x7ff; let is_positive = (as_u64 >> 63) == 0; if exponent >= 0x3ff + 52 { x diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 0726d83ba67..2d22c939354 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -2,7 +2,7 @@ pub fn rintf(x: f32) -> f32 { let one_over_e = 1.0 / f32::EPSILON; let as_u32: u32 = x.to_bits(); - let exponent: u32 = as_u32 >> 23 & 0xff; + let exponent: u32 = (as_u32 >> 23) & 0xff; let is_positive = (as_u32 >> 31) == 0; if exponent >= 0x7f + 23 { x diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index d9a8f184ce0..3f1a10fddc6 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -219,7 +219,7 @@ pub fn sqrt(x: f64) -> f64 { ix1 |= sign; } ix0 += m << 20; - f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) + f64::from_bits(((ix0 as u64) << 32) | ix1.0 as u64) } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 34bc2fdfa48..d85bffb40e4 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -14,7 +14,7 @@ pub fn trunc(x: f64) -> f64 { let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 let mut i: u64 = x.to_bits(); - let mut e: i64 = (i >> 52 & 0x7ff) as i64 - 0x3ff + 12; + let mut e: i64 = ((i >> 52) & 0x7ff) as i64 - 0x3ff + 12; let m: u64; if e >= 52 + 12 { diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index a74f7898772..82017b87b7c 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -14,7 +14,7 @@ pub fn truncf(x: f32) -> f32 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 let mut i: u32 = x.to_bits(); - let mut e: i32 = (i >> 23 & 0xff) as i32 - 0x7f + 9; + let mut e: i32 = ((i >> 23) & 0xff) as i32 - 0x7f + 9; let m: u32; if e >= 23 + 9 { -- cgit 1.4.1-3-g733a5 From 4e5a156cd0e5269991e16dbef059a9979540def2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Dec 2024 11:02:40 +0000 Subject: Allow Clippy lints in `compiler-builtins-smoke-test` Rather than always needing to exclude `cb` when running `cargo clippy`, just disable Clippy for the included module. --- library/compiler-builtins/libm/.github/workflows/main.yml | 1 - .../libm/crates/compiler-builtins-smoke-test/src/lib.rs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 866f0de9ec0..d290d09a55f 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -120,7 +120,6 @@ jobs: run: ./ci/download-musl.sh - run: | cargo clippy --all \ - --exclude cb \ --features libm-test/build-musl,libm-test/test-multiprecision \ --all-targets diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index e65cb8da3c4..e3a51a575e4 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -4,8 +4,9 @@ #![feature(core_intrinsics)] #![allow(internal_features)] -#![allow(dead_code)] #![no_std] +#[allow(dead_code)] +#[allow(clippy::all)] // We don't get `libm`'s list of `allow`s, so just ignore Clippy. #[path = "../../../src/math/mod.rs"] pub mod libm; -- cgit 1.4.1-3-g733a5 From 51956a53c31ce2d96fce25bf4e8a024f47480f06 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Dec 2024 06:46:22 +0000 Subject: Change from `-latest` to named CI images GitHub will be upgrading the `-latest` tags of these images in the near future. Change all images to specify the latest version. --- .../libm/.github/workflows/main.yml | 62 +++++++++++----------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index d290d09a55f..93cd541f838 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -16,56 +16,56 @@ jobs: matrix: include: - target: aarch64-apple-darwin - os: macos-latest + os: macos-15 - target: aarch64-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: aarch64-pc-windows-msvc - os: windows-latest + os: windows-2025 build_only: 1 # Can't run on x86 hosts - target: arm-unknown-linux-gnueabi - os: ubuntu-latest + os: ubuntu-24.04 - target: arm-unknown-linux-gnueabihf - os: ubuntu-latest + os: ubuntu-24.04 - target: armv7-unknown-linux-gnueabihf - os: ubuntu-latest + os: ubuntu-24.04 - target: i586-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: i686-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: loongarch64-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: powerpc-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: powerpc64-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: powerpc64le-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: riscv64gc-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: thumbv6m-none-eabi - os: ubuntu-latest + os: ubuntu-24.04 - target: thumbv7em-none-eabi - os: ubuntu-latest + os: ubuntu-24.04 - target: thumbv7em-none-eabihf - os: ubuntu-latest + os: ubuntu-24.04 - target: thumbv7m-none-eabi - os: ubuntu-latest + os: ubuntu-24.04 - target: x86_64-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: x86_64-apple-darwin os: macos-13 - target: wasm32-unknown-unknown - os: ubuntu-latest + os: ubuntu-24.04 build_only: 1 - target: i686-pc-windows-msvc - os: windows-latest + os: windows-2025 - target: x86_64-pc-windows-msvc - os: windows-latest + os: windows-2025 - target: i686-pc-windows-gnu - os: windows-latest + os: windows-2025 channel: nightly-i686-gnu - target: x86_64-pc-windows-gnu - os: windows-latest + os: windows-2025 channel: nightly-x86_64-gnu runs-on: ${{ matrix.os }} env: @@ -94,20 +94,20 @@ jobs: # Non-linux tests just use our raw script - name: Run locally - if: matrix.os != 'ubuntu-latest' || contains(matrix.target, 'wasm') + if: matrix.os != 'ubuntu-24.04' || contains(matrix.target, 'wasm') shell: bash run: ./ci/run.sh ${{ matrix.target }} # Otherwise we use our docker containers to run builds - name: Run in Docker - if: matrix.os == 'ubuntu-latest' && !contains(matrix.target, 'wasm') + if: matrix.os == 'ubuntu-24.04' && !contains(matrix.target, 'wasm') run: | rustup target add x86_64-unknown-linux-musl cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} clippy: name: Clippy - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@master - name: Install Rust @@ -125,7 +125,7 @@ jobs: builtins: name: Check use with compiler-builtins - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@master - name: Install Rust @@ -135,7 +135,7 @@ jobs: benchmarks: name: Benchmarks - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@master - name: Install Rust @@ -147,7 +147,7 @@ jobs: msrv: name: Check MSRV - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` steps: @@ -163,7 +163,7 @@ jobs: rustfmt: name: Rustfmt - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@master - name: Install Rust @@ -180,7 +180,7 @@ jobs: - benchmarks - msrv - rustfmt - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its # dependencies fails. -- cgit 1.4.1-3-g733a5 From b9871da445687345ebf73476b595b991b4f1b793 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 03:07:58 -0500 Subject: Introduce generic `abs` and `copysign` Add generic versions of `abs` and `copysign`, which will provide an entrypoint for adding `f16` and `f128`. Since this implementation is identical to the existing type-specific implementations, make use of it for `f32` and `f64`. --- library/compiler-builtins/libm/src/math/copysign.rs | 6 +----- library/compiler-builtins/libm/src/math/copysignf.rs | 6 +----- library/compiler-builtins/libm/src/math/fabs.rs | 2 +- library/compiler-builtins/libm/src/math/fabsf.rs | 2 +- library/compiler-builtins/libm/src/math/generic/abs.rs | 6 ++++++ library/compiler-builtins/libm/src/math/generic/copysign.rs | 10 ++++++++++ library/compiler-builtins/libm/src/math/generic/mod.rs | 5 +++++ library/compiler-builtins/libm/src/math/mod.rs | 1 + 8 files changed, 26 insertions(+), 12 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/abs.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/copysign.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/mod.rs diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs index 1f4a35a331b..552bf3975b8 100644 --- a/library/compiler-builtins/libm/src/math/copysign.rs +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -4,9 +4,5 @@ /// first argument, `x`, and the sign of its second argument, `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn copysign(x: f64, y: f64) -> f64 { - let mut ux = x.to_bits(); - let uy = y.to_bits(); - ux &= (!0) >> 1; - ux |= uy & (1 << 63); - f64::from_bits(ux) + super::generic::copysign(x, y) } diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs index 6c346e3a528..8b9bed4c0c4 100644 --- a/library/compiler-builtins/libm/src/math/copysignf.rs +++ b/library/compiler-builtins/libm/src/math/copysignf.rs @@ -4,9 +4,5 @@ /// first argument, `x`, and the sign of its second argument, `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn copysignf(x: f32, y: f32) -> f32 { - let mut ux = x.to_bits(); - let uy = y.to_bits(); - ux &= 0x7fffffff; - ux |= uy & 0x80000000; - f32::from_bits(ux) + super::generic::copysign(x, y) } diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index d083053e188..2163637e728 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -9,7 +9,7 @@ pub fn fabs(x: f64) -> f64 { args: x, } - f64::from_bits(x.to_bits() & (u64::MAX / 2)) + super::generic::abs(x) } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index eabe87254b7..ac77c9201ad 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -9,7 +9,7 @@ pub fn fabsf(x: f32) -> f32 { args: x, } - f32::from_bits(x.to_bits() & 0x7fffffff) + super::generic::abs(x) } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 diff --git a/library/compiler-builtins/libm/src/math/generic/abs.rs b/library/compiler-builtins/libm/src/math/generic/abs.rs new file mode 100644 index 00000000000..2c9a43c1249 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/abs.rs @@ -0,0 +1,6 @@ +use super::super::Float; + +/// Absolute value. +pub fn abs(x: F) -> F { + x.abs() +} diff --git a/library/compiler-builtins/libm/src/math/generic/copysign.rs b/library/compiler-builtins/libm/src/math/generic/copysign.rs new file mode 100644 index 00000000000..d6b81489193 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/copysign.rs @@ -0,0 +1,10 @@ +use super::super::Float; + +/// Copy the sign of `y` to `x`. +pub fn copysign(x: F, y: F) -> F { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= !F::SIGN_MASK; + ux |= uy & (F::SIGN_MASK); + F::from_bits(ux) +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs new file mode 100644 index 00000000000..1ddd08f0eff --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -0,0 +1,5 @@ +mod abs; +mod copysign; + +pub use abs::abs; +pub use copysign::copysign; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 3852c774e80..ba199522816 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -87,6 +87,7 @@ mod support; mod arch; mod expo2; mod fenv; +mod generic; mod k_cos; mod k_cosf; mod k_expo2; -- cgit 1.4.1-3-g733a5 From f2e16b6ac1f3f5516f31809c0712b9a91eaa1a85 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 00:44:50 -0500 Subject: Add `f16` and `f128` configuration from `compiler-builtins` In preparation of adding routines from these two types, duplicate the `compiler-builtins` configuration here. --- library/compiler-builtins/libm/Cargo.toml | 5 +- library/compiler-builtins/libm/build.rs | 30 +--- library/compiler-builtins/libm/configure.rs | 168 +++++++++++++++++++++ .../crates/compiler-builtins-smoke-test/Cargo.toml | 2 + .../libm/crates/libm-macros/Cargo.toml | 7 + .../libm/crates/libm-test/Cargo.toml | 11 +- .../libm/crates/libm-test/build.rs | 62 +------- library/compiler-builtins/libm/src/lib.rs | 2 + .../libm/src/math/support/float_traits.rs | 4 + 9 files changed, 208 insertions(+), 83 deletions(-) create mode 100644 library/compiler-builtins/libm/configure.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 98a60bfe3fe..bfc11509e42 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -21,7 +21,7 @@ arch = [] # This tells the compiler to assume that a Nightly toolchain is being used and # that it should activate any useful Nightly things accordingly. -unstable = ["unstable-intrinsics"] +unstable = ["unstable-intrinsics", "unstable-float"] # Enable calls to functions in `core::intrinsics` unstable-intrinsics = [] @@ -29,6 +29,9 @@ unstable-intrinsics = [] # Make some internal things public for testing. unstable-test-support = [] +# Enable the nightly-only `f16` and `f128`. +unstable-float = [] + # Used to prevent using any intrinsics or arch-specific code. # # HACK: this is a negative feature which is generally a bad idea in Cargo, but diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 00102923611..9c9e0e72328 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -1,6 +1,10 @@ use std::env; +mod configure; + fn main() { + let cfg = configure::Config::from_env(); + println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); @@ -14,29 +18,5 @@ fn main() { } } - configure_intrinsics(); - configure_arch(); -} - -/// Simplify the feature logic for enabling intrinsics so code only needs to use -/// `cfg(intrinsics_enabled)`. -fn configure_intrinsics() { - println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)"); - - // Disabled by default; `unstable-intrinsics` enables again; `force-soft-floats` overrides - // to disable. - if cfg!(feature = "unstable-intrinsics") && !cfg!(feature = "force-soft-floats") { - println!("cargo:rustc-cfg=intrinsics_enabled"); - } -} - -/// Simplify the feature logic for enabling arch-specific features so code only needs to use -/// `cfg(arch_enabled)`. -fn configure_arch() { - println!("cargo:rustc-check-cfg=cfg(arch_enabled)"); - - // Enabled by default via the "arch" feature, `force-soft-floats` overrides to disable. - if cfg!(feature = "arch") && !cfg!(feature = "force-soft-floats") { - println!("cargo:rustc-cfg=arch_enabled"); - } + configure::emit_libm_config(&cfg); } diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs new file mode 100644 index 00000000000..389e86c3388 --- /dev/null +++ b/library/compiler-builtins/libm/configure.rs @@ -0,0 +1,168 @@ +// Configuration shared with both libm and libm-test + +use std::env; +use std::path::PathBuf; + +#[allow(dead_code)] +pub struct Config { + pub manifest_dir: PathBuf, + pub out_dir: PathBuf, + pub opt_level: u8, + pub target_arch: String, + pub target_env: String, + pub target_family: Option, + pub target_os: String, + pub target_string: String, + pub target_vendor: String, + pub target_features: Vec, +} + +impl Config { + pub fn from_env() -> Self { + let target_features = env::var("CARGO_CFG_TARGET_FEATURE") + .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) + .unwrap_or_default(); + + Self { + manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()), + out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), + opt_level: env::var("OPT_LEVEL").unwrap().parse().unwrap(), + target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), + target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), + target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(), + target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + target_string: env::var("TARGET").unwrap(), + target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), + target_features, + } + } +} + +/// Libm gets most config options made available. +#[allow(dead_code)] +pub fn emit_libm_config(cfg: &Config) { + emit_intrinsics_cfg(); + emit_arch_cfg(); + emit_optimization_cfg(cfg); + emit_cfg_shorthands(cfg); + emit_f16_f128_cfg(cfg); +} + +/// Tests don't need most feature-related config. +#[allow(dead_code)] +pub fn emit_test_config(cfg: &Config) { + emit_optimization_cfg(cfg); + emit_cfg_shorthands(cfg); + emit_f16_f128_cfg(cfg); +} + +/// Simplify the feature logic for enabling intrinsics so code only needs to use +/// `cfg(intrinsics_enabled)`. +fn emit_intrinsics_cfg() { + println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)"); + + // Disabled by default; `unstable-intrinsics` enables again; `force-soft-floats` overrides + // to disable. + if cfg!(feature = "unstable-intrinsics") && !cfg!(feature = "force-soft-floats") { + println!("cargo:rustc-cfg=intrinsics_enabled"); + } +} + +/// Simplify the feature logic for enabling arch-specific features so code only needs to use +/// `cfg(arch_enabled)`. +fn emit_arch_cfg() { + println!("cargo:rustc-check-cfg=cfg(arch_enabled)"); + + // Enabled by default via the "arch" feature, `force-soft-floats` overrides to disable. + if cfg!(feature = "arch") && !cfg!(feature = "force-soft-floats") { + println!("cargo:rustc-cfg=arch_enabled"); + } +} + +/// Some tests are extremely slow. Emit a config option based on optimization level. +fn emit_optimization_cfg(cfg: &Config) { + println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); + + if cfg.opt_level >= 2 { + println!("cargo:rustc-cfg=optimizations_enabled"); + } +} + +/// Provide an alias for common longer config combinations. +fn emit_cfg_shorthands(cfg: &Config) { + println!("cargo:rustc-check-cfg=cfg(x86_no_sse)"); + if cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse") { + // Shorthand to detect i586 targets + println!("cargo:rustc-cfg=x86_no_sse"); + } +} + +/// Configure whether or not `f16` and `f128` support should be enabled. +fn emit_f16_f128_cfg(cfg: &Config) { + println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); + println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); + + // `unstable-float` enables these features. + if !cfg!(feature = "unstable-float") { + return; + } + + // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means + // that the backend will not crash when using these types and generates code that can be called + // without crashing (no infinite recursion). This does not mean that the platform doesn't have + // ABI or other bugs. + // + // We do this here rather than in `rust-lang/rust` because configuring via cargo features is + // not straightforward. + // + // Original source of this list: + // + let f16_enabled = match cfg.target_arch.as_str() { + // Unsupported + "arm64ec" => false, + // Selection failure + "s390x" => false, + // Infinite recursion + // FIXME(llvm): loongarch fixed by + "csky" => false, + "hexagon" => false, + "loongarch64" => false, + "mips" | "mips64" | "mips32r6" | "mips64r6" => false, + "powerpc" | "powerpc64" => false, + "sparc" | "sparc64" => false, + "wasm32" | "wasm64" => false, + // Most everything else works as of LLVM 19 + _ => true, + }; + + let f128_enabled = match cfg.target_arch.as_str() { + // Unsupported (libcall is not supported) + "amdgpu" => false, + // Unsupported + "arm64ec" => false, + // Selection failure + "mips64" | "mips64r6" => false, + // Selection failure + "nvptx64" => false, + // Selection failure + "powerpc64" if &cfg.target_os == "aix" => false, + // Selection failure + "sparc" => false, + // Most everything else works as of LLVM 19 + _ => true, + }; + + // If the feature is set, disable these types. + let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); + + println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); + println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); + + if f16_enabled && !disable_both { + println!("cargo:rustc-cfg=f16_enabled"); + } + + if f128_enabled && !disable_both { + println!("cargo:rustc-cfg=f128_enabled"); + } +} diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index e75c4f42bfa..82cfeecb90f 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -21,5 +21,7 @@ force-soft-floats = [] unexpected_cfgs = { level = "warn", check-cfg = [ "cfg(arch_enabled)", "cfg(assert_no_panic)", + "cfg(f128_enabled)", + "cfg(f16_enabled)", "cfg(intrinsics_enabled)", ] } diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml index c9defb1c5cb..9194232b24c 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml @@ -12,3 +12,10 @@ heck = "0.5.0" proc-macro2 = "1.0.88" quote = "1.0.37" syn = { version = "2.0.79", features = ["full", "extra-traits", "visit-mut"] } + +[lints.rust] +# Values used during testing +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(f16_enabled)', + 'cfg(f128_enabled)', +] } diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 4d75b25f81e..f2dd88fa14c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -5,7 +5,10 @@ edition = "2021" publish = false [features] -default = [] +default = ["unstable-float"] + +# Propagated from libm because this affects which functions we test. +unstable-float = ["libm/unstable-float"] # Generate tests which are random inputs and the outputs are calculated with # musl libc. @@ -44,3 +47,9 @@ criterion = { version = "0.5.1", default-features = false, features = ["cargo_be [[bench]] name = "random" harness = false + +[lints.rust] +# Values from the chared config.rs used by `libm` but not the test crate +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(feature, values("arch", "force-soft-floats", "unstable-intrinsics"))', +] } diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index dc3126dbb94..f2cd298baf2 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -1,66 +1,16 @@ use std::fmt::Write; -use std::path::PathBuf; -use std::{env, fs}; +use std::fs; + +#[path = "../../configure.rs"] +mod configure; +use configure::Config; fn main() { let cfg = Config::from_env(); - emit_optimization_cfg(&cfg); - emit_cfg_shorthands(&cfg); list_all_tests(&cfg); -} - -#[allow(dead_code)] -struct Config { - manifest_dir: PathBuf, - out_dir: PathBuf, - opt_level: u8, - target_arch: String, - target_env: String, - target_family: Option, - target_os: String, - target_string: String, - target_vendor: String, - target_features: Vec, -} - -impl Config { - fn from_env() -> Self { - let target_features = env::var("CARGO_CFG_TARGET_FEATURE") - .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) - .unwrap_or_default(); - - Self { - manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()), - out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), - opt_level: env::var("OPT_LEVEL").unwrap().parse().unwrap(), - target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), - target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), - target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(), - target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), - target_string: env::var("TARGET").unwrap(), - target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), - target_features, - } - } -} -/// Some tests are extremely slow. Emit a config option based on optimization level. -fn emit_optimization_cfg(cfg: &Config) { - println!("cargo::rustc-check-cfg=cfg(optimizations_enabled)"); - - if cfg.opt_level >= 2 { - println!("cargo::rustc-cfg=optimizations_enabled"); - } -} - -/// Provide an alias for common longer config combinations. -fn emit_cfg_shorthands(cfg: &Config) { - println!("cargo::rustc-check-cfg=cfg(x86_no_sse)"); - if cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse") { - // Shorthand to detect i586 targets - println!("cargo::rustc-cfg=x86_no_sse"); - } + configure::emit_test_config(&cfg); } /// Create a list of all source files in an array. This can be used for making sure that diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 6bb06b5b81f..327e3d6e65b 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -2,6 +2,8 @@ #![no_std] #![cfg_attr(intrinsics_enabled, allow(internal_features))] #![cfg_attr(intrinsics_enabled, feature(core_intrinsics))] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] #![allow(clippy::assign_op_pattern)] #![allow(clippy::deprecated_cfg_attr)] #![allow(clippy::eq_op)] diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 5808aeebc13..7b3f6904b9d 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -219,5 +219,9 @@ macro_rules! float_impl { }; } +#[cfg(f16_enabled)] +float_impl!(f16, u16, i16, i8, 16, 10); float_impl!(f32, u32, i32, i16, 32, 23); float_impl!(f64, u64, i64, i16, 64, 52); +#[cfg(f128_enabled)] +float_impl!(f128, u128, i128, i16, 128, 112); -- cgit 1.4.1-3-g733a5 From 2323d3a2e3ed5a60fc13c7bf177bf875f91868db Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Dec 2024 07:37:01 +0000 Subject: Always enable `unstable-float` in CI Since these add new API but do not affect runtime, we can enable it for all tests that run with nightly. --- library/compiler-builtins/libm/ci/run.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index d89c8bdf060..7e514a1cd2e 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -62,22 +62,26 @@ esac cargo check --no-default-features cargo check --features "force-soft-floats" +# Always enable `unstable-float` since it expands available API but does not +# change any implementations. +extra_flags="$extra_flags --features unstable-float" + if [ "${BUILD_ONLY:-}" = "1" ]; then cmd="cargo build --target $target --package libm" $cmd - $cmd --features "unstable-intrinsics" + $cmd --features unstable-intrinsics echo "can't run tests on $target; skipping" else cmd="cargo test --all --target $target $extra_flags" - # stable by default + # Test without intrinsics $cmd $cmd --release - # unstable with a feature - $cmd --features "unstable-intrinsics" - $cmd --release --features "unstable-intrinsics" + # Test with intrinsic use + $cmd --features unstable-intrinsics + $cmd --release --features unstable-intrinsics # Make sure benchmarks have correct results $cmd --benches -- cgit 1.4.1-3-g733a5 From 5e6b813e514eb7147a139fb757b875a9fa8962f7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Dec 2024 11:47:04 +0000 Subject: Update and slightly refactor some of the `Float` trait Add a constant for negative pi and provide a standalone const `from_bits`, which can be combined with what we already had in `hex_float`. Also provide another default method to reduce what needs to be provided by the macro. --- .../libm/src/math/support/float_traits.rs | 47 +++++++++++++++------- .../libm/src/math/support/hex_float.rs | 12 +----- .../compiler-builtins/libm/src/math/support/mod.rs | 1 + 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 7b3f6904b9d..68ba600309a 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -38,6 +38,7 @@ pub trait Float: const MAX: Self; const MIN: Self; const PI: Self; + const NEG_PI: Self; const FRAC_PI_2: Self; /// The bitwidth of the float type @@ -71,7 +72,9 @@ pub trait Float: fn to_bits(self) -> Self::Int; /// Returns `self` transmuted to `Self::SignedInt` - fn to_bits_signed(self) -> Self::SignedInt; + fn to_bits_signed(self) -> Self::SignedInt { + self.to_bits().signed() + } /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be /// represented in multiple different ways. This method returns `true` if two NaNs are @@ -158,7 +161,15 @@ pub trait Float: pub type IntTy = ::Int; macro_rules! float_impl { - ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { + ( + $ty:ident, + $ity:ident, + $sity:ident, + $expty:ident, + $bits:expr, + $significand_bits:expr, + $from_bits:path + ) => { impl Float for $ty { type Int = $ity; type SignedInt = $sity; @@ -173,13 +184,10 @@ macro_rules! float_impl { const NAN: Self = Self::NAN; const MAX: Self = -Self::MIN; // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed - // FIXME(msrv): just use `from_bits` when available - // SAFETY: POD cast with no preconditions - const MIN: Self = unsafe { - mem::transmute::(Self::Int::MAX & !(1 << Self::SIG_BITS)) - }; + const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS)); const PI: Self = core::$ty::consts::PI; + const NEG_PI: Self = -Self::PI; const FRAC_PI_2: Self = core::$ty::consts::FRAC_PI_2; const BITS: u32 = $bits; @@ -193,9 +201,6 @@ macro_rules! float_impl { fn to_bits(self) -> Self::Int { self.to_bits() } - fn to_bits_signed(self) -> Self::SignedInt { - self.to_bits() as Self::SignedInt - } fn is_nan(self) -> bool { self.is_nan() } @@ -220,8 +225,22 @@ macro_rules! float_impl { } #[cfg(f16_enabled)] -float_impl!(f16, u16, i16, i8, 16, 10); -float_impl!(f32, u32, i32, i16, 32, 23); -float_impl!(f64, u64, i64, i16, 64, 52); +float_impl!(f16, u16, i16, i8, 16, 10, f16::from_bits); +float_impl!(f32, u32, i32, i16, 32, 23, f32_from_bits); +float_impl!(f64, u64, i64, i16, 64, 52, f64_from_bits); #[cfg(f128_enabled)] -float_impl!(f128, u128, i128, i16, 128, 112); +float_impl!(f128, u128, i128, i16, 128, 112, f128::from_bits); + +/* FIXME(msrv): vendor some things that are not const stable at our MSRV */ + +/// `f32::from_bits` +pub const fn f32_from_bits(bits: u32) -> f32 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(bits) } +} + +/// `f64::from_bits` +pub const fn f64_from_bits(bits: u64) -> f64 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(bits) } +} diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index 80434a5ec3e..1666c615360 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -2,6 +2,8 @@ #![allow(dead_code)] // FIXME: remove once this gets used +use super::{f32_from_bits, f64_from_bits}; + /// Construct a 32-bit float from hex float representation (C-style) pub const fn hf32(s: &str) -> f32 { f32_from_bits(parse_any(s, 32, 23) as u32) @@ -159,16 +161,6 @@ const fn hex_digit(c: u8) -> u8 { /* FIXME(msrv): vendor some things that are not const stable at our MSRV */ -/// `f32::from_bits` -const fn f32_from_bits(v: u32) -> f32 { - unsafe { core::mem::transmute(v) } -} - -/// `f64::from_bits` -const fn f64_from_bits(v: u64) -> f64 { - unsafe { core::mem::transmute(v) } -} - /// `u128::ilog2` const fn u128_ilog2(v: u128) -> u32 { assert!(v != 0); diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 25681c307da..e2f4e0e981d 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -6,6 +6,7 @@ mod int_traits; #[allow(unused_imports)] pub use float_traits::{Float, IntTy}; +pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; #[allow(unused_imports)] pub use hex_float::{hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -- cgit 1.4.1-3-g733a5 From bae68206fad9089da26f1b82cb6082c592b6d253 Mon Sep 17 00:00:00 2001 From: beetrees Date: Thu, 19 Dec 2024 11:59:09 +0000 Subject: Remove an `is_nan` workaround that is no longer needed --- .../compiler-builtins/libm/src/math/support/float_traits.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 68ba600309a..e64640a0d15 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -80,17 +80,7 @@ pub trait Float: /// represented in multiple different ways. This method returns `true` if two NaNs are /// compared. fn eq_repr(self, rhs: Self) -> bool { - let is_nan = |x: Self| -> bool { - // } - // fn is_nan(x: Self) -> bool { - // When using mangled-names, the "real" compiler-builtins might not have the - // necessary builtin (__unordtf2) to test whether `f128` is NaN. - // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin - // x is NaN if all the bits of the exponent are set and the significand is non-0 - x.to_bits() & Self::EXP_MASK == Self::EXP_MASK - && x.to_bits() & Self::SIG_MASK != Self::Int::ZERO - }; - if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() } + if self.is_nan() && rhs.is_nan() { true } else { self.to_bits() == rhs.to_bits() } } /// Returns true if the value is NaN. -- cgit 1.4.1-3-g733a5 From 8d224a0de03bab7bd77c0784a4114a53b702e3f4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Dec 2024 11:18:33 +0000 Subject: Add an 8-bit float type for testing purposes Introduce `f8`, which is an 8-bit float compliant with IEEE-754. This type is useful for testing since it is easily possible to enumerate all values. --- .../libm/crates/libm-test/src/f8_impl.rs | 487 +++++++++++++++++++++ .../libm/crates/libm-test/src/lib.rs | 4 + 2 files changed, 491 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs new file mode 100644 index 00000000000..babcc6357a4 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -0,0 +1,487 @@ +//! An IEEE-compliant 8-bit float type for testing purposes. + +use std::cmp::{self, Ordering}; +use std::{fmt, ops}; + +use crate::Float; + +/// Sometimes verifying float logic is easiest when all values can quickly be checked exhaustively +/// or by hand. +/// +/// IEEE-754 compliant type that includes a 1 bit sign, 4 bit exponent, and 3 bit significand. +/// Bias is -7. +/// +/// Based on . +#[derive(Clone, Copy)] +#[repr(transparent)] +#[allow(non_camel_case_types)] +pub struct f8(u8); + +impl Float for f8 { + type Int = u8; + type SignedInt = i8; + type ExpInt = i8; + + const ZERO: Self = Self(0b0_0000_000); + const NEG_ZERO: Self = Self(0b1_0000_000); + const ONE: Self = Self(0b0_0111_000); + const NEG_ONE: Self = Self(0b1_0111_000); + const MAX: Self = Self(0b0_1110_111); + const MIN: Self = Self(0b1_1110_111); + const INFINITY: Self = Self(0b0_1111_000); + const NEG_INFINITY: Self = Self(0b1_1111_000); + const NAN: Self = Self(0b0_1111_100); + const PI: Self = Self::ZERO; + const NEG_PI: Self = Self::ZERO; + const FRAC_PI_2: Self = Self::ZERO; + + const BITS: u32 = 8; + const SIG_BITS: u32 = 3; + const SIGN_MASK: Self::Int = 0b1_0000_000; + const SIG_MASK: Self::Int = 0b0_0000_111; + const EXP_MASK: Self::Int = 0b0_1111_000; + const IMPLICIT_BIT: Self::Int = 0b0_0001_000; + + fn to_bits(self) -> Self::Int { + self.0 + } + + fn to_bits_signed(self) -> Self::SignedInt { + self.0 as i8 + } + + fn is_nan(self) -> bool { + self.0 & Self::EXP_MASK == Self::EXP_MASK && self.0 & Self::SIG_MASK != 0 + } + + fn is_infinite(self) -> bool { + self.0 & Self::EXP_MASK == Self::EXP_MASK && self.0 & Self::SIG_MASK == 0 + } + + fn is_sign_negative(self) -> bool { + self.0 & Self::SIGN_MASK != 0 + } + + fn exp(self) -> Self::ExpInt { + unimplemented!() + } + + fn from_bits(a: Self::Int) -> Self { + Self(a) + } + + fn normalize(_significand: Self::Int) -> (i32, Self::Int) { + unimplemented!() + } +} + +impl f8 { + pub const ALL_LEN: usize = 240; + + /// All non-infinite non-NaN values of `f8` + pub const ALL: [Self; Self::ALL_LEN] = [ + // -m*2^7 + Self(0b1_1110_111), // -240 + Self(0b1_1110_110), + Self(0b1_1110_101), + Self(0b1_1110_100), + Self(0b1_1110_011), + Self(0b1_1110_010), + Self(0b1_1110_001), + Self(0b1_1110_000), // -128 + // -m*2^6 + Self(0b1_1101_111), // -120 + Self(0b1_1101_110), + Self(0b1_1101_101), + Self(0b1_1101_100), + Self(0b1_1101_011), + Self(0b1_1101_010), + Self(0b1_1101_001), + Self(0b1_1101_000), // -64 + // -m*2^5 + Self(0b1_1100_111), // -60 + Self(0b1_1100_110), + Self(0b1_1100_101), + Self(0b1_1100_100), + Self(0b1_1100_011), + Self(0b1_1100_010), + Self(0b1_1100_001), + Self(0b1_1100_000), // -32 + // -m*2^4 + Self(0b1_1011_111), // -30 + Self(0b1_1011_110), + Self(0b1_1011_101), + Self(0b1_1011_100), + Self(0b1_1011_011), + Self(0b1_1011_010), + Self(0b1_1011_001), + Self(0b1_1011_000), // -16 + // -m*2^3 + Self(0b1_1010_111), // -15 + Self(0b1_1010_110), + Self(0b1_1010_101), + Self(0b1_1010_100), + Self(0b1_1010_011), + Self(0b1_1010_010), + Self(0b1_1010_001), + Self(0b1_1010_000), // -8 + // -m*2^2 + Self(0b1_1001_111), // -7.5 + Self(0b1_1001_110), + Self(0b1_1001_101), + Self(0b1_1001_100), + Self(0b1_1001_011), + Self(0b1_1001_010), + Self(0b1_1001_001), + Self(0b1_1001_000), // -4 + // -m*2^1 + Self(0b1_1000_111), // -3.75 + Self(0b1_1000_110), + Self(0b1_1000_101), + Self(0b1_1000_100), + Self(0b1_1000_011), + Self(0b1_1000_010), + Self(0b1_1000_001), + Self(0b1_1000_000), // -2 + // -m*2^0 + Self(0b1_0111_111), // -1.875 + Self(0b1_0111_110), + Self(0b1_0111_101), + Self(0b1_0111_100), + Self(0b1_0111_011), + Self(0b1_0111_010), + Self(0b1_0111_001), + Self(0b1_0111_000), // -1 + // -m*2^-1 + Self(0b1_0110_111), // −0.9375 + Self(0b1_0110_110), + Self(0b1_0110_101), + Self(0b1_0110_100), + Self(0b1_0110_011), + Self(0b1_0110_010), + Self(0b1_0110_001), + Self(0b1_0110_000), // -0.5 + // -m*2^-2 + Self(0b1_0101_111), // −0.46875 + Self(0b1_0101_110), + Self(0b1_0101_101), + Self(0b1_0101_100), + Self(0b1_0101_011), + Self(0b1_0101_010), + Self(0b1_0101_001), + Self(0b1_0101_000), // -0.25 + // -m*2^-3 + Self(0b1_0100_111), // −0.234375 + Self(0b1_0100_110), + Self(0b1_0100_101), + Self(0b1_0100_100), + Self(0b1_0100_011), + Self(0b1_0100_010), + Self(0b1_0100_001), + Self(0b1_0100_000), // -0.125 + // -m*2^-4 + Self(0b1_0011_111), // −0.1171875 + Self(0b1_0011_110), + Self(0b1_0011_101), + Self(0b1_0011_100), + Self(0b1_0011_011), + Self(0b1_0011_010), + Self(0b1_0011_001), + Self(0b1_0011_000), // −0.0625 + // -m*2^-5 + Self(0b1_0010_111), // −0.05859375 + Self(0b1_0010_110), + Self(0b1_0010_101), + Self(0b1_0010_100), + Self(0b1_0010_011), + Self(0b1_0010_010), + Self(0b1_0010_001), + Self(0b1_0010_000), // −0.03125 + // -m*2^-6 + Self(0b1_0001_111), // −0.029296875 + Self(0b1_0001_110), + Self(0b1_0001_101), + Self(0b1_0001_100), + Self(0b1_0001_011), + Self(0b1_0001_010), + Self(0b1_0001_001), + Self(0b1_0001_000), // −0.015625 + // -m*2^-7 subnormal numbers + Self(0b1_0000_111), // −0.013671875 + Self(0b1_0000_110), + Self(0b1_0000_101), + Self(0b1_0000_100), + Self(0b1_0000_011), + Self(0b1_0000_010), + Self(0b1_0000_001), // −0.001953125 + // Zeroes + Self(0b1_0000_000), // -0.0 + Self(0b0_0000_000), // 0.0 + // m*2^-7 // subnormal numbers + Self(0b0_0000_001), + Self(0b0_0000_010), + Self(0b0_0000_011), + Self(0b0_0000_100), + Self(0b0_0000_101), + Self(0b0_0000_110), + Self(0b0_0000_111), // 0.013671875 + // m*2^-6 + Self(0b0_0001_000), // 0.015625 + Self(0b0_0001_001), + Self(0b0_0001_010), + Self(0b0_0001_011), + Self(0b0_0001_100), + Self(0b0_0001_101), + Self(0b0_0001_110), + Self(0b0_0001_111), // 0.029296875 + // m*2^-5 + Self(0b0_0010_000), // 0.03125 + Self(0b0_0010_001), + Self(0b0_0010_010), + Self(0b0_0010_011), + Self(0b0_0010_100), + Self(0b0_0010_101), + Self(0b0_0010_110), + Self(0b0_0010_111), // 0.05859375 + // m*2^-4 + Self(0b0_0011_000), // 0.0625 + Self(0b0_0011_001), + Self(0b0_0011_010), + Self(0b0_0011_011), + Self(0b0_0011_100), + Self(0b0_0011_101), + Self(0b0_0011_110), + Self(0b0_0011_111), // 0.1171875 + // m*2^-3 + Self(0b0_0100_000), // 0.125 + Self(0b0_0100_001), + Self(0b0_0100_010), + Self(0b0_0100_011), + Self(0b0_0100_100), + Self(0b0_0100_101), + Self(0b0_0100_110), + Self(0b0_0100_111), // 0.234375 + // m*2^-2 + Self(0b0_0101_000), // 0.25 + Self(0b0_0101_001), + Self(0b0_0101_010), + Self(0b0_0101_011), + Self(0b0_0101_100), + Self(0b0_0101_101), + Self(0b0_0101_110), + Self(0b0_0101_111), // 0.46875 + // m*2^-1 + Self(0b0_0110_000), // 0.5 + Self(0b0_0110_001), + Self(0b0_0110_010), + Self(0b0_0110_011), + Self(0b0_0110_100), + Self(0b0_0110_101), + Self(0b0_0110_110), + Self(0b0_0110_111), // 0.9375 + // m*2^0 + Self(0b0_0111_000), // 1 + Self(0b0_0111_001), + Self(0b0_0111_010), + Self(0b0_0111_011), + Self(0b0_0111_100), + Self(0b0_0111_101), + Self(0b0_0111_110), + Self(0b0_0111_111), // 1.875 + // m*2^1 + Self(0b0_1000_000), // 2 + Self(0b0_1000_001), + Self(0b0_1000_010), + Self(0b0_1000_011), + Self(0b0_1000_100), + Self(0b0_1000_101), + Self(0b0_1000_110), + Self(0b0_1000_111), // 3.75 + // m*2^2 + Self(0b0_1001_000), // 4 + Self(0b0_1001_001), + Self(0b0_1001_010), + Self(0b0_1001_011), + Self(0b0_1001_100), + Self(0b0_1001_101), + Self(0b0_1001_110), + Self(0b0_1001_111), // 7.5 + // m*2^3 + Self(0b0_1010_000), // 8 + Self(0b0_1010_001), + Self(0b0_1010_010), + Self(0b0_1010_011), + Self(0b0_1010_100), + Self(0b0_1010_101), + Self(0b0_1010_110), + Self(0b0_1010_111), // 15 + // m*2^4 + Self(0b0_1011_000), // 16 + Self(0b0_1011_001), + Self(0b0_1011_010), + Self(0b0_1011_011), + Self(0b0_1011_100), + Self(0b0_1011_101), + Self(0b0_1011_110), + Self(0b0_1011_111), // 30 + // m*2^5 + Self(0b0_1100_000), // 32 + Self(0b0_1100_001), + Self(0b0_1100_010), + Self(0b0_1100_011), + Self(0b0_1100_100), + Self(0b0_1100_101), + Self(0b0_1100_110), + Self(0b0_1100_111), // 60 + // m*2^6 + Self(0b0_1101_000), // 64 + Self(0b0_1101_001), + Self(0b0_1101_010), + Self(0b0_1101_011), + Self(0b0_1101_100), + Self(0b0_1101_101), + Self(0b0_1101_110), + Self(0b0_1101_111), // 120 + // m*2^7 + Self(0b0_1110_000), // 128 + Self(0b0_1110_001), + Self(0b0_1110_010), + Self(0b0_1110_011), + Self(0b0_1110_100), + Self(0b0_1110_101), + Self(0b0_1110_110), + Self(0b0_1110_111), // 240 + ]; +} + +impl ops::Add for f8 { + type Output = Self; + fn add(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} + +impl ops::Sub for f8 { + type Output = Self; + fn sub(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} +impl ops::Mul for f8 { + type Output = Self; + fn mul(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} +impl ops::Div for f8 { + type Output = Self; + fn div(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} + +impl ops::Neg for f8 { + type Output = Self; + fn neg(self) -> Self::Output { + Self(self.0 ^ Self::SIGN_MASK) + } +} + +impl ops::Rem for f8 { + type Output = Self; + fn rem(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} + +impl ops::AddAssign for f8 { + fn add_assign(&mut self, _rhs: Self) { + unimplemented!() + } +} + +impl ops::SubAssign for f8 { + fn sub_assign(&mut self, _rhs: Self) { + unimplemented!() + } +} + +impl ops::MulAssign for f8 { + fn mul_assign(&mut self, _rhs: Self) { + unimplemented!() + } +} + +impl cmp::PartialEq for f8 { + fn eq(&self, other: &Self) -> bool { + if self.is_nan() || other.is_nan() { + false + } else if self.abs().to_bits() | other.abs().to_bits() == 0 { + true + } else { + self.0 == other.0 + } + } +} +impl cmp::PartialOrd for f8 { + fn partial_cmp(&self, other: &Self) -> Option { + let inf_rep = f8::EXP_MASK; + + let a_abs = self.abs().to_bits(); + let b_abs = other.abs().to_bits(); + + // If either a or b is NaN, they are unordered. + if a_abs > inf_rep || b_abs > inf_rep { + return None; + } + + // If a and b are both zeros, they are equal. + if a_abs | b_abs == 0 { + return Some(Ordering::Equal); + } + + let a_srep = self.to_bits_signed(); + let b_srep = other.to_bits_signed(); + let res = a_srep.cmp(&b_srep); + + if a_srep & b_srep >= 0 { + // If at least one of a and b is positive, we get the same result comparing + // a and b as signed integers as we would with a fp_ting-point compare. + Some(res) + } else { + // Otherwise, both are negative, so we need to flip the sense of the + // comparison to get the correct result. + Some(res.reverse()) + } + } +} +impl fmt::Display for f8 { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() + } +} + +impl fmt::Debug for f8 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Binary::fmt(self, f) + } +} + +impl fmt::Binary for f8 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let v = self.0; + write!( + f, + "0b{:b}_{:04b}_{:03b}", + v >> 7, + (v & Self::EXP_MASK) >> Self::SIG_BITS, + v & Self::SIG_MASK + ) + } +} + +impl fmt::LowerHex for f8 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 17a06b3be3a..ed7131713d5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,3 +1,6 @@ +#![allow(clippy::unusual_byte_groupings)] // sometimes we group by sign_exp_sig + +mod f8_impl; pub mod gen; #[cfg(feature = "test-multiprecision")] pub mod mpfloat; @@ -5,6 +8,7 @@ pub mod op; mod precision; mod test_traits; +pub use f8_impl::f8; pub use libm::support::{Float, Int, IntTy}; pub use op::{BaseName, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; -- cgit 1.4.1-3-g733a5 From 163ed2a133c36d42f67bcf09696057037dcbff5a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Dec 2024 15:10:35 +0000 Subject: Introduce a float extension trait and some numerical routines --- .../libm/crates/libm-test/src/lib.rs | 4 +- .../libm/crates/libm-test/src/num.rs | 458 +++++++++++++++++++++ 2 files changed, 461 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/num.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index ed7131713d5..48b382d20c1 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -4,12 +4,14 @@ mod f8_impl; pub mod gen; #[cfg(feature = "test-multiprecision")] pub mod mpfloat; +mod num; pub mod op; mod precision; mod test_traits; pub use f8_impl::f8; -pub use libm::support::{Float, Int, IntTy}; +pub use libm::support::{Float, Int, IntTy, MinInt}; +pub use num::{FloatExt, logspace}; pub use op::{BaseName, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num.rs b/library/compiler-builtins/libm/crates/libm-test/src/num.rs new file mode 100644 index 00000000000..4aa7f61b05a --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/num.rs @@ -0,0 +1,458 @@ +//! Helpful numeric operations. + +use std::cmp::min; + +use libm::support::{CastInto, Float}; + +use crate::{Int, MinInt}; + +/// Extension to `libm`'s `Float` trait with methods that are useful for tests but not +/// needed in `libm` itself. +pub trait FloatExt: Float { + /// The minimum subnormal number. + const TINY_BITS: Self::Int = Self::Int::ONE; + + /// Retrieve additional constants for this float type. + fn consts() -> Consts { + Consts::new() + } + + /// Increment by one ULP, saturating at infinity. + fn next_up(self) -> Self { + let bits = self.to_bits(); + if self.is_nan() || bits == Self::INFINITY.to_bits() { + return self; + } + + let abs = self.abs().to_bits(); + let next_bits = if abs == Self::Int::ZERO { + // Next up from 0 is the smallest subnormal + Self::TINY_BITS + } else if bits == abs { + // Positive: counting up is more positive + bits + Self::Int::ONE + } else { + // Negative: counting down is more positive + bits - Self::Int::ONE + }; + Self::from_bits(next_bits) + } + + /// A faster way to effectively call `next_up` `n` times. + fn n_up(self, n: Self::Int) -> Self { + let bits = self.to_bits(); + if self.is_nan() || bits == Self::INFINITY.to_bits() || n == Self::Int::ZERO { + return self; + } + + let abs = self.abs().to_bits(); + let is_positive = bits == abs; + let crosses_zero = !is_positive && n > abs; + let inf_bits = Self::INFINITY.to_bits(); + + let next_bits = if abs == Self::Int::ZERO { + min(n, inf_bits) + } else if crosses_zero { + min(n - abs, inf_bits) + } else if is_positive { + // Positive, counting up is more positive but this may overflow + match bits.checked_add(n) { + Some(v) if v >= inf_bits => inf_bits, + Some(v) => v, + None => inf_bits, + } + } else { + // Negative, counting down is more positive + bits - n + }; + Self::from_bits(next_bits) + } + + /// Decrement by one ULP, saturating at negative infinity. + fn next_down(self) -> Self { + let bits = self.to_bits(); + if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() { + return self; + } + + let abs = self.abs().to_bits(); + let next_bits = if abs == Self::Int::ZERO { + // Next up from 0 is the smallest negative subnormal + Self::TINY_BITS | Self::SIGN_MASK + } else if bits == abs { + // Positive: counting down is more negative + bits - Self::Int::ONE + } else { + // Negative: counting up is more negative + bits + Self::Int::ONE + }; + Self::from_bits(next_bits) + } + + /// A faster way to effectively call `next_down` `n` times. + fn n_down(self, n: Self::Int) -> Self { + let bits = self.to_bits(); + if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() || n == Self::Int::ZERO { + return self; + } + + let abs = self.abs().to_bits(); + let is_positive = bits == abs; + let crosses_zero = is_positive && n > abs; + let inf_bits = Self::INFINITY.to_bits(); + let ninf_bits = Self::NEG_INFINITY.to_bits(); + + let next_bits = if abs == Self::Int::ZERO { + min(n, inf_bits) | Self::SIGN_MASK + } else if crosses_zero { + min(n - abs, inf_bits) | Self::SIGN_MASK + } else if is_positive { + // Positive, counting down is more negative + bits - n + } else { + // Negative, counting up is more negative but this may overflow + match bits.checked_add(n) { + Some(v) if v > ninf_bits => ninf_bits, + Some(v) => v, + None => ninf_bits, + } + }; + Self::from_bits(next_bits) + } +} + +impl FloatExt for F where F: Float {} + +/// Extra constants that are useful for tests. +#[derive(Debug, Clone, Copy)] +pub struct Consts { + /// The default quiet NaN, which is also the minimum quiet NaN. + pub pos_nan: F, + /// The default quiet NaN with negative sign. + pub neg_nan: F, + /// NaN with maximum (unsigned) significand to be a quiet NaN. The significand is saturated. + pub max_qnan: F, + /// NaN with minimum (unsigned) significand to be a signaling NaN. + pub min_snan: F, + /// NaN with maximum (unsigned) significand to be a signaling NaN. + pub max_snan: F, + pub neg_max_qnan: F, + pub neg_min_snan: F, + pub neg_max_snan: F, +} + +impl Consts { + fn new() -> Self { + let top_sigbit_mask = F::Int::ONE << (F::SIG_BITS - 1); + let pos_nan = F::EXP_MASK | top_sigbit_mask; + let max_qnan = F::EXP_MASK | F::SIG_MASK; + let min_snan = F::EXP_MASK | F::Int::ONE; + let max_snan = (F::EXP_MASK | F::SIG_MASK) ^ top_sigbit_mask; + + let neg_nan = pos_nan | F::SIGN_MASK; + let neg_max_qnan = max_qnan | F::SIGN_MASK; + let neg_min_snan = min_snan | F::SIGN_MASK; + let neg_max_snan = max_snan | F::SIGN_MASK; + + Self { + pos_nan: F::from_bits(pos_nan), + neg_nan: F::from_bits(neg_nan), + max_qnan: F::from_bits(max_qnan), + min_snan: F::from_bits(min_snan), + max_snan: F::from_bits(max_snan), + neg_max_qnan: F::from_bits(neg_max_qnan), + neg_min_snan: F::from_bits(neg_min_snan), + neg_max_snan: F::from_bits(neg_max_snan), + } + } + + pub fn iter(self) -> impl Iterator { + // Destructure so we get unused warnings if we forget a list entry. + let Self { + pos_nan, + neg_nan, + max_qnan, + min_snan, + max_snan, + neg_max_qnan, + neg_min_snan, + neg_max_snan, + } = self; + + [pos_nan, neg_nan, max_qnan, min_snan, max_snan, neg_max_qnan, neg_min_snan, neg_max_snan] + .into_iter() + } +} + +/// Return the number of steps between two floats, returning `None` if either input is NaN. +/// +/// This is the number of steps needed for `n_up` or `n_down` to go between values. Infinities +/// are treated the same as those functions (will return the nearest finite value), and only one +/// of `-0` or `+0` is counted. It does not matter which value is greater. +pub fn ulp_between(x: F, y: F) -> Option { + let a = as_ulp_steps(x)?; + let b = as_ulp_steps(y)?; + Some(a.abs_diff(b)) +} + +/// Return the (signed) number of steps from zero to `x`. +fn as_ulp_steps(x: F) -> Option { + let s = x.to_bits_signed(); + let val = if s >= F::SignedInt::ZERO { + // each increment from `s = 0` is one step up from `x = 0.0` + s + } else { + // each increment from `s = F::SignedInt::MIN` is one step down from `x = -0.0` + F::SignedInt::MIN - s + }; + + // If `x` is NaN, return `None` + (!x.is_nan()).then_some(val) +} + +/// An iterator that returns floats with linearly spaced integer representations, which translates +/// to logarithmic spacing of their values. +/// +/// Note that this tends to skip negative zero, so that needs to be checked explicitly. +pub fn logspace(start: F, end: F, steps: F::Int) -> impl Iterator { + assert!(!start.is_nan()); + assert!(!end.is_nan()); + assert!(end >= start); + + let mut steps = steps.checked_sub(F::Int::ONE).expect("`steps` must be at least 2"); + let between = ulp_between(start, end).expect("`start` or `end` is NaN"); + let spacing = (between / steps).max(F::Int::ONE); + steps = steps.min(between); // At maximum, one step per ULP + + let mut x = start; + (0..=steps.cast()).map(move |_| { + let ret = x; + x = x.n_up(spacing); + ret + }) +} + +#[cfg(test)] +mod tests { + use std::cmp::max; + + use super::*; + use crate::f8; + + #[test] + fn test_next_up_down() { + for (i, v) in f8::ALL.into_iter().enumerate() { + let down = v.next_down().to_bits(); + let up = v.next_up().to_bits(); + + if i == 0 { + assert_eq!(down, f8::NEG_INFINITY.to_bits(), "{i} next_down({v:#010b})"); + } else { + let expected = + if v == f8::ZERO { 1 | f8::SIGN_MASK } else { f8::ALL[i - 1].to_bits() }; + assert_eq!(down, expected, "{i} next_down({v:#010b})"); + } + + if i == f8::ALL_LEN - 1 { + assert_eq!(up, f8::INFINITY.to_bits(), "{i} next_up({v:#010b})"); + } else { + let expected = if v == f8::NEG_ZERO { 1 } else { f8::ALL[i + 1].to_bits() }; + assert_eq!(up, expected, "{i} next_up({v:#010b})"); + } + } + } + + #[test] + fn test_next_up_down_inf_nan() { + assert_eq!(f8::NEG_INFINITY.next_up().to_bits(), f8::ALL[0].to_bits(),); + assert_eq!(f8::NEG_INFINITY.next_down().to_bits(), f8::NEG_INFINITY.to_bits(),); + assert_eq!(f8::INFINITY.next_down().to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits(),); + assert_eq!(f8::INFINITY.next_up().to_bits(), f8::INFINITY.to_bits(),); + assert_eq!(f8::NAN.next_up().to_bits(), f8::NAN.to_bits(),); + assert_eq!(f8::NAN.next_down().to_bits(), f8::NAN.to_bits(),); + } + + #[test] + fn test_n_up_down_quick() { + assert_eq!(f8::ALL[0].n_up(4).to_bits(), f8::ALL[4].to_bits(),); + assert_eq!( + f8::ALL[f8::ALL_LEN - 1].n_down(4).to_bits(), + f8::ALL[f8::ALL_LEN - 5].to_bits(), + ); + + // Check around zero + assert_eq!(f8::from_bits(0b0).n_up(7).to_bits(), 0b0_0000_111); + assert_eq!(f8::from_bits(0b0).n_down(7).to_bits(), 0b1_0000_111); + + // Check across zero + assert_eq!(f8::from_bits(0b1_0000_111).n_up(8).to_bits(), 0b0_0000_001); + assert_eq!(f8::from_bits(0b0_0000_111).n_down(8).to_bits(), 0b1_0000_001); + } + + #[test] + fn test_n_up_down_one() { + // Verify that `n_up(1)` and `n_down(1)` are the same as `next_up()` and next_down()`.` + for i in 0..u8::MAX { + let v = f8::from_bits(i); + assert_eq!(v.next_up().to_bits(), v.n_up(1).to_bits()); + assert_eq!(v.next_down().to_bits(), v.n_down(1).to_bits()); + } + } + + #[test] + fn test_n_up_down_inf_nan_zero() { + assert_eq!(f8::NEG_INFINITY.n_up(1).to_bits(), f8::ALL[0].to_bits()); + assert_eq!(f8::NEG_INFINITY.n_up(239).to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits()); + assert_eq!(f8::NEG_INFINITY.n_up(240).to_bits(), f8::INFINITY.to_bits()); + assert_eq!(f8::NEG_INFINITY.n_down(u8::MAX).to_bits(), f8::NEG_INFINITY.to_bits()); + + assert_eq!(f8::INFINITY.n_down(1).to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits()); + assert_eq!(f8::INFINITY.n_down(239).to_bits(), f8::ALL[0].to_bits()); + assert_eq!(f8::INFINITY.n_down(240).to_bits(), f8::NEG_INFINITY.to_bits()); + assert_eq!(f8::INFINITY.n_up(u8::MAX).to_bits(), f8::INFINITY.to_bits()); + + assert_eq!(f8::NAN.n_up(u8::MAX).to_bits(), f8::NAN.to_bits()); + assert_eq!(f8::NAN.n_down(u8::MAX).to_bits(), f8::NAN.to_bits()); + + assert_eq!(f8::ZERO.n_down(1).to_bits(), f8::TINY_BITS | f8::SIGN_MASK); + assert_eq!(f8::NEG_ZERO.n_up(1).to_bits(), f8::TINY_BITS); + } + + /// True if the specified range of `f8::ALL` includes both +0 and -0 + fn crossed_zero(start: usize, end: usize) -> bool { + let crossed = &f8::ALL[start..=end]; + crossed.iter().any(|f| f8::eq_repr(*f, f8::ZERO)) + && crossed.iter().any(|f| f8::eq_repr(*f, f8::NEG_ZERO)) + } + + #[test] + fn test_n_up_down() { + for (i, v) in f8::ALL.into_iter().enumerate() { + for n in 0..f8::ALL_LEN { + let down = v.n_down(n as u8).to_bits(); + let up = v.n_up(n as u8).to_bits(); + + if let Some(down_exp_idx) = i.checked_sub(n) { + // No overflow + let mut expected = f8::ALL[down_exp_idx].to_bits(); + if n >= 1 && crossed_zero(down_exp_idx, i) { + // If both -0 and +0 are included, we need to adjust our expected value + match down_exp_idx.checked_sub(1) { + Some(v) => expected = f8::ALL[v].to_bits(), + // Saturate to -inf if we are out of values + None => expected = f8::NEG_INFINITY.to_bits(), + } + } + assert_eq!(down, expected, "{i} {n} n_down({v:#010b})"); + } else { + // Overflow to -inf + assert_eq!(down, f8::NEG_INFINITY.to_bits(), "{i} {n} n_down({v:#010b})"); + } + + let mut up_exp_idx = i + n; + if up_exp_idx < f8::ALL_LEN { + // No overflow + if n >= 1 && up_exp_idx < f8::ALL_LEN && crossed_zero(i, up_exp_idx) { + // If both -0 and +0 are included, we need to adjust our expected value + up_exp_idx += 1; + } + + let expected = if up_exp_idx >= f8::ALL_LEN { + f8::INFINITY.to_bits() + } else { + f8::ALL[up_exp_idx].to_bits() + }; + + assert_eq!(up, expected, "{i} {n} n_up({v:#010b})"); + } else { + // Overflow to +inf + assert_eq!(up, f8::INFINITY.to_bits(), "{i} {n} n_up({v:#010b})"); + } + } + } + } + + #[test] + fn test_ulp_between() { + for (i, x) in f8::ALL.into_iter().enumerate() { + for (j, y) in f8::ALL.into_iter().enumerate() { + let ulp = ulp_between(x, y).unwrap(); + let make_msg = || format!("i: {i} j: {j} x: {x:b} y: {y:b} ulp {ulp}"); + + let i_low = min(i, j); + let i_hi = max(i, j); + let mut expected = u8::try_from(i_hi - i_low).unwrap(); + if crossed_zero(i_low, i_hi) { + expected -= 1; + } + + assert_eq!(ulp, expected, "{}", make_msg()); + + // Skip if either are zero since `next_{up,down}` will count over it + let either_zero = x == f8::ZERO || y == f8::ZERO; + if x < y && !either_zero { + assert_eq!(x.n_up(ulp).to_bits(), y.to_bits(), "{}", make_msg()); + assert_eq!(y.n_down(ulp).to_bits(), x.to_bits(), "{}", make_msg()); + } else if !either_zero { + assert_eq!(y.n_up(ulp).to_bits(), x.to_bits(), "{}", make_msg()); + assert_eq!(x.n_down(ulp).to_bits(), y.to_bits(), "{}", make_msg()); + } + } + } + } + + #[test] + fn test_ulp_between_inf_nan_zero() { + assert_eq!(ulp_between(f8::NEG_INFINITY, f8::INFINITY).unwrap(), f8::ALL_LEN as u8); + assert_eq!(ulp_between(f8::INFINITY, f8::NEG_INFINITY).unwrap(), f8::ALL_LEN as u8); + assert_eq!( + ulp_between(f8::NEG_INFINITY, f8::ALL[f8::ALL_LEN - 1]).unwrap(), + f8::ALL_LEN as u8 - 1 + ); + assert_eq!(ulp_between(f8::INFINITY, f8::ALL[0]).unwrap(), f8::ALL_LEN as u8 - 1); + + assert_eq!(ulp_between(f8::ZERO, f8::NEG_ZERO).unwrap(), 0); + assert_eq!(ulp_between(f8::NAN, f8::ZERO), None); + assert_eq!(ulp_between(f8::ZERO, f8::NAN), None); + } + + #[test] + fn test_logspace() { + let ls: Vec<_> = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 2).collect(); + let exp = [f8::from_bits(0x0), f8::from_bits(0x4)]; + assert_eq!(ls, exp); + + let ls: Vec<_> = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 3).collect(); + let exp = [f8::from_bits(0x0), f8::from_bits(0x2), f8::from_bits(0x4)]; + assert_eq!(ls, exp); + + // Check that we include all values with no repeats if `steps` exceeds the maximum number + // of steps. + let ls: Vec<_> = logspace(f8::from_bits(0x0), f8::from_bits(0x3), 10).collect(); + let exp = [f8::from_bits(0x0), f8::from_bits(0x1), f8::from_bits(0x2), f8::from_bits(0x3)]; + assert_eq!(ls, exp); + } + + #[test] + fn test_consts() { + let Consts { + pos_nan, + neg_nan, + max_qnan, + min_snan, + max_snan, + neg_max_qnan, + neg_min_snan, + neg_max_snan, + } = f8::consts(); + + assert_eq!(pos_nan.to_bits(), 0b0_1111_100); + assert_eq!(neg_nan.to_bits(), 0b1_1111_100); + assert_eq!(max_qnan.to_bits(), 0b0_1111_111); + assert_eq!(min_snan.to_bits(), 0b0_1111_001); + assert_eq!(max_snan.to_bits(), 0b0_1111_011); + assert_eq!(neg_max_qnan.to_bits(), 0b1_1111_111); + assert_eq!(neg_min_snan.to_bits(), 0b1_1111_001); + assert_eq!(neg_max_snan.to_bits(), 0b1_1111_011); + } +} -- cgit 1.4.1-3-g733a5 From a8a2f70ae6d1945be3af8c21a839c1d1df7e0e8e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Dec 2024 11:19:01 +0000 Subject: Add interfaces and tests based on function domains Create a type representing a function's domain and a test that does a logarithmic sweep of points within the domain. --- .../libm/crates/libm-test/src/domain.rs | 186 +++++++++++++++++++++ .../libm/crates/libm-test/src/gen.rs | 1 + .../crates/libm-test/src/gen/domain_logspace.rs | 43 +++++ .../libm/crates/libm-test/src/lib.rs | 1 + .../libm/crates/libm-test/tests/multiprecision.rs | 101 ++++++++++- 5 files changed, 327 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/domain.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs new file mode 100644 index 00000000000..43ba21974c8 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -0,0 +1,186 @@ +//! Traits and operations related to bounds of a function. + +use std::fmt; +use std::ops::{self, Bound}; + +use crate::Float; + +/// Representation of a function's domain. +#[derive(Clone, Debug)] +pub struct Domain { + /// Start of the region for which a function is defined (ignoring poles). + pub start: Bound, + /// Endof the region for which a function is defined (ignoring poles). + pub end: Bound, + /// Additional points to check closer around. These can be e.g. undefined asymptotes or + /// inflection points. + pub check_points: Option BoxIter>, +} + +type BoxIter = Box>; + +impl Domain { + /// The start of this domain, saturating at negative infinity. + pub fn range_start(&self) -> F { + match self.start { + Bound::Included(v) => v, + Bound::Excluded(v) => v.next_up(), + Bound::Unbounded => F::NEG_INFINITY, + } + } + + /// The end of this domain, saturating at infinity. + pub fn range_end(&self) -> F { + match self.end { + Bound::Included(v) => v, + Bound::Excluded(v) => v.next_down(), + Bound::Unbounded => F::INFINITY, + } + } +} + +impl Domain { + /// x ∈ ℝ + pub const UNBOUNDED: Self = + Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }; + + /// x ∈ ℝ >= 0 + pub const POSITIVE: Self = + Self { start: Bound::Included(F::ZERO), end: Bound::Unbounded, check_points: None }; + + /// x ∈ ℝ > 0 + pub const STRICTLY_POSITIVE: Self = + Self { start: Bound::Excluded(F::ZERO), end: Bound::Unbounded, check_points: None }; + + /// Used for versions of `asin` and `acos`. + pub const INVERSE_TRIG_PERIODIC: Self = Self { + start: Bound::Included(F::NEG_ONE), + end: Bound::Included(F::ONE), + check_points: None, + }; + + /// Domain for `acosh` + pub const ACOSH: Self = + Self { start: Bound::Included(F::ONE), end: Bound::Unbounded, check_points: None }; + + /// Domain for `atanh` + pub const ATANH: Self = Self { + start: Bound::Excluded(F::NEG_ONE), + end: Bound::Excluded(F::ONE), + check_points: None, + }; + + /// Domain for `sin`, `cos`, and `tan` + pub const TRIG: Self = Self { + // TODO + check_points: Some(|| Box::new([-F::PI, -F::FRAC_PI_2, F::FRAC_PI_2, F::PI].into_iter())), + ..Self::UNBOUNDED + }; + + /// Domain for `log` in various bases + pub const LOG: Self = Self::STRICTLY_POSITIVE; + + /// Domain for `log1p` i.e. `log(1 + x)` + pub const LOG1P: Self = + Self { start: Bound::Excluded(F::NEG_ONE), end: Bound::Unbounded, check_points: None }; + + /// Domain for `sqrt` + pub const SQRT: Self = Self::POSITIVE; + + /// Domain for `gamma` + pub const GAMMA: Self = Self { + check_points: Some(|| { + // Negative integers are asymptotes + Box::new((0..u8::MAX).map(|scale| { + let mut base = F::ZERO; + for _ in 0..scale { + base = base - F::ONE; + } + base + })) + }), + // Whether or not gamma is defined for negative numbers is implementation dependent + ..Self::UNBOUNDED + }; + + /// Domain for `loggamma` + pub const LGAMMA: Self = Self::STRICTLY_POSITIVE; +} + +/// Implement on `op::*` types to indicate how they are bounded. +pub trait HasDomain +where + T: Copy + fmt::Debug + ops::Add + ops::Sub + PartialOrd + 'static, +{ + const DOMAIN: Domain; +} + +/// Implement [`HasDomain`] for both the `f32` and `f64` variants of a function. +macro_rules! impl_has_domain { + ($($fn_name:ident => $domain:expr;)*) => { + paste::paste! { + $( + // Implement for f64 functions + impl HasDomain for $crate::op::$fn_name::Routine { + const DOMAIN: Domain = Domain::::$domain; + } + + // Implement for f32 functions + impl HasDomain for $crate::op::[< $fn_name f >]::Routine { + const DOMAIN: Domain = Domain::::$domain; + } + )* + } + }; +} + +// Tie functions together with their domains. +impl_has_domain! { + acos => INVERSE_TRIG_PERIODIC; + acosh => ACOSH; + asin => INVERSE_TRIG_PERIODIC; + asinh => UNBOUNDED; + atan => UNBOUNDED; + atanh => ATANH; + cbrt => UNBOUNDED; + ceil => UNBOUNDED; + cos => TRIG; + cosh => UNBOUNDED; + erf => UNBOUNDED; + exp => UNBOUNDED; + exp10 => UNBOUNDED; + exp2 => UNBOUNDED; + expm1 => UNBOUNDED; + fabs => UNBOUNDED; + floor => UNBOUNDED; + frexp => UNBOUNDED; + ilogb => UNBOUNDED; + j0 => UNBOUNDED; + j1 => UNBOUNDED; + lgamma => LGAMMA; + log => LOG; + log10 => LOG; + log1p => LOG1P; + log2 => LOG; + modf => UNBOUNDED; + rint => UNBOUNDED; + round => UNBOUNDED; + sin => TRIG; + sincos => TRIG; + sinh => UNBOUNDED; + sqrt => SQRT; + tan => TRIG; + tanh => UNBOUNDED; + tgamma => GAMMA; + trunc => UNBOUNDED; +} + +/* Manual implementations, these functions don't follow `foo`->`foof` naming */ + +impl HasDomain for crate::op::lgammaf_r::Routine { + const DOMAIN: Domain = Domain::::LGAMMA; +} + +impl HasDomain for crate::op::lgamma_r::Routine { + const DOMAIN: Domain = Domain::::LGAMMA; +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index 3e9eca37a67..e3c88c44a9e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -1,6 +1,7 @@ //! Different generators that can create random or systematic bit patterns. use crate::GenerateInput; +pub mod domain_logspace; pub mod random; /// Helper type to turn any reusable input into a generator. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs new file mode 100644 index 00000000000..e8cdb9d2b91 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs @@ -0,0 +1,43 @@ +//! A generator that produces logarithmically spaced values within domain bounds. + +use libm::support::{IntTy, MinInt}; + +use crate::domain::HasDomain; +use crate::op::OpITy; +use crate::{MathOp, logspace}; + +/// Number of tests to run. +// FIXME(ntests): replace this with a more logical algorithm +const NTESTS: usize = { + if cfg!(optimizations_enabled) { + if crate::emulated() + || !cfg!(target_pointer_width = "64") + || cfg!(all(target_arch = "x86_64", target_vendor = "apple")) + { + // Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run + // in QEMU. + 100_000 + } else { + 5_000_000 + } + } else { + // Without optimizations just run a quick check + 800 + } +}; + +/// Create a range of logarithmically spaced inputs within a function's domain. +/// +/// This allows us to get reasonably thorough coverage without wasting time on values that are +/// NaN or out of range. Random tests will still cover values that are excluded here. +pub fn get_test_cases() -> impl Iterator +where + Op: MathOp + HasDomain, + IntTy: TryFrom, +{ + let domain = Op::DOMAIN; + let start = domain.range_start(); + let end = domain.range_end(); + let steps = OpITy::::try_from(NTESTS).unwrap_or(OpITy::::MAX); + logspace(start, end, steps).map(|v| (v,)) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 48b382d20c1..622b2dec98c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,5 +1,6 @@ #![allow(clippy::unusual_byte_groupings)] // sometimes we group by sign_exp_sig +pub mod domain; mod f8_impl; pub mod gen; #[cfg(feature = "test-multiprecision")] diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 0b41fba82e5..e643f3c9c2c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -2,11 +2,14 @@ #![cfg(feature = "test-multiprecision")] -use libm_test::gen::{CachedInput, random}; +use libm_test::domain::HasDomain; +use libm_test::gen::{CachedInput, domain_logspace, random}; use libm_test::mpfloat::MpOp; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall}; +use libm_test::{ + CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, OpFTy, OpRustFn, OpRustRet, TupleCall, +}; -/// Implement a test against MPFR with random inputs. +/// Test against MPFR with random inputs. macro_rules! mp_rand_tests { ( fn_name: $fn_name:ident, @@ -16,13 +19,14 @@ macro_rules! mp_rand_tests { #[test] $(#[$meta])* fn [< mp_random_ $fn_name >]() { - test_one::(); + test_one_random::(); } } }; } -fn test_one() +/// Test a single routine with random inputs +fn test_one_random() where Op: MathOp + MpOp, CachedInput: GenerateInput, @@ -67,3 +71,90 @@ libm_macros::for_each_function! { nextafterf, ], } + +/// Test against MPFR with generators from a domain. +macro_rules! mp_domain_tests { + ( + fn_name: $fn_name:ident, + attrs: [$($meta:meta)*] + ) => { + paste::paste! { + #[test] + $(#[$meta])* + fn [< mp_logspace_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + domain_test_runner::(domain_logspace::get_test_cases::()); + } + } + }; +} + +/// Test a single routine against domaine-aware inputs. +fn domain_test_runner(cases: impl Iterator) +where + // Complicated generics... + // The operation must take a single float argument (unary only) + Op: MathOp::FTy,)>, + // It must also support multiprecision operations + Op: MpOp, + // And it must have a domain specified + Op: HasDomain, + // The single float argument tuple must be able to call the `RustFn` and return `RustRet` + (OpFTy,): TupleCall, Output = OpRustRet>, +{ + let mut mp_vals = Op::new_mp(); + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); + + for input in cases { + let mp_res = Op::run(&mut mp_vals, input); + let crate_res = input.call(Op::ROUTINE); + + crate_res.validate(mp_res, input, &ctx).unwrap(); + } +} + +libm_macros::for_each_function! { + callback: mp_domain_tests, + attributes: [], + skip: [ + // Functions with multiple inputs + atan2, + atan2f, + copysign, + copysignf, + fdim, + fdimf, + fma, + fmaf, + fmax, + fmaxf, + fmin, + fminf, + fmod, + fmodf, + hypot, + hypotf, + jn, + jnf, + ldexp, + ldexpf, + nextafter, + nextafterf, + pow, + powf, + remainder, + remainderf, + remquo, + remquof, + scalbn, + scalbnf, + + // FIXME: MPFR tests needed + frexp, + frexpf, + ilogb, + ilogbf, + modf, + modff, + ], +} -- cgit 1.4.1-3-g733a5 From 13611a1b7685e4e92b8b1b85449c2a6eb915f382 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Dec 2024 11:22:02 +0000 Subject: Add tests for edge cases Introduce a generator that will tests various points of interest including zeros, infinities, and NaNs. --- .../libm/crates/libm-test/src/domain.rs | 4 +- .../libm/crates/libm-test/src/gen.rs | 1 + .../libm/crates/libm-test/src/gen/edge_cases.rs | 90 ++++++++++++++++++++++ .../libm/crates/libm-test/tests/multiprecision.rs | 9 ++- 4 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index 43ba21974c8..9ee8a19b970 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -3,7 +3,7 @@ use std::fmt; use std::ops::{self, Bound}; -use crate::Float; +use crate::{Float, FloatExt}; /// Representation of a function's domain. #[derive(Clone, Debug)] @@ -19,7 +19,7 @@ pub struct Domain { type BoxIter = Box>; -impl Domain { +impl Domain { /// The start of this domain, saturating at negative infinity. pub fn range_start(&self) -> F { match self.start { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index e3c88c44a9e..2d15915d91a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -2,6 +2,7 @@ use crate::GenerateInput; pub mod domain_logspace; +pub mod edge_cases; pub mod random; /// Helper type to turn any reusable input into a generator. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs new file mode 100644 index 00000000000..625e18bc7a8 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs @@ -0,0 +1,90 @@ +//! A generator that checks a handful of cases near infinities, zeros, asymptotes, and NaNs. + +use libm::support::Float; + +use crate::domain::HasDomain; +use crate::{FloatExt, MathOp}; + +/// Number of values near an interesting point to check. +// FIXME(ntests): replace this with a more logical algorithm +const AROUND: usize = 100; + +/// Functions have infinite asymptotes, limit how many we check. +// FIXME(ntests): replace this with a more logical algorithm +const MAX_CHECK_POINTS: usize = 10; + +/// Create a list of values around interesting points (infinities, zeroes, NaNs). +pub fn get_test_cases() -> impl Iterator +where + Op: MathOp + HasDomain, + F: Float, +{ + let mut ret = Vec::new(); + let values = &mut ret; + let domain = Op::DOMAIN; + let domain_start = domain.range_start(); + let domain_end = domain.range_end(); + + // Check near some notable constants + count_up(F::ONE, values); + count_up(F::ZERO, values); + count_up(F::NEG_ONE, values); + count_down(F::ONE, values); + count_down(F::ZERO, values); + count_down(F::NEG_ONE, values); + values.push(F::NEG_ZERO); + + // Check values near the extremes + count_up(F::NEG_INFINITY, values); + count_down(F::INFINITY, values); + count_down(domain_end, values); + count_up(domain_start, values); + count_down(domain_start, values); + count_up(domain_end, values); + count_down(domain_end, values); + + // Check some special values that aren't included in the above ranges + values.push(F::NAN); + values.extend(F::consts().iter()); + + // Check around asymptotes + if let Some(f) = domain.check_points { + let iter = f(); + for x in iter.take(MAX_CHECK_POINTS) { + count_up(x, values); + count_down(x, values); + } + } + + // Some results may overlap so deduplicate the vector to save test cycles. + values.sort_by_key(|x| x.to_bits()); + values.dedup_by_key(|x| x.to_bits()); + + ret.into_iter().map(|v| (v,)) +} + +/// Add `AROUND` values starting at and including `x` and counting up. Uses the smallest possible +/// increments (1 ULP). +fn count_up(mut x: F, values: &mut Vec) { + assert!(!x.is_nan()); + + let mut count = 0; + while x < F::INFINITY && count < AROUND { + values.push(x); + x = x.next_up(); + count += 1; + } +} + +/// Add `AROUND` values starting at and including `x` and counting down. Uses the smallest possible +/// increments (1 ULP). +fn count_down(mut x: F, values: &mut Vec) { + assert!(!x.is_nan()); + + let mut count = 0; + while x > F::NEG_INFINITY && count < AROUND { + values.push(x); + x = x.next_down(); + count += 1; + } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index e643f3c9c2c..5255dc1cfd7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -3,7 +3,7 @@ #![cfg(feature = "test-multiprecision")] use libm_test::domain::HasDomain; -use libm_test::gen::{CachedInput, domain_logspace, random}; +use libm_test::gen::{CachedInput, domain_logspace, edge_cases, random}; use libm_test::mpfloat::MpOp; use libm_test::{ CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, OpFTy, OpRustFn, OpRustRet, TupleCall, @@ -79,6 +79,13 @@ macro_rules! mp_domain_tests { attrs: [$($meta:meta)*] ) => { paste::paste! { + #[test] + $(#[$meta])* + fn [< mp_edge_case_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + domain_test_runner::(edge_cases::get_test_cases::()); + } + #[test] $(#[$meta])* fn [< mp_logspace_ $fn_name >]() { -- cgit 1.4.1-3-g733a5 From 3c61c560acab44a41836d05b8c68482f3d82cd93 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Dec 2024 14:23:05 +0000 Subject: Update allowed precision to account for new tests --- .../libm/crates/libm-test/src/precision.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index c7f9d9e3011..b878212faf8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -41,10 +41,11 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { (Musl, Id::Tgamma) => 20, // Overrides for MPFR + (Mpfr, Id::Acosh) => 4, (Mpfr, Id::Acoshf) => 4, (Mpfr, Id::Asinh | Id::Asinhf) => 2, (Mpfr, Id::Atanh | Id::Atanhf) => 2, - (Mpfr, Id::Exp10 | Id::Exp10f) => 3, + (Mpfr, Id::Exp10 | Id::Exp10f) => 6, (Mpfr, Id::Lgamma | Id::LgammaR | Id::Lgammaf | Id::LgammafR) => 16, (Mpfr, Id::Sinh | Id::Sinhf) => 2, (Mpfr, Id::Tanh | Id::Tanhf) => 2, @@ -105,17 +106,14 @@ impl MaybeOverride<(f32,)> for SpecialCase { _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - if ctx.basis == CheckBasis::Musl { - if ctx.base_name == BaseName::Expm1 && input.0 > 80.0 && actual.is_infinite() { - // we return infinity but the number is representable - return XFAIL; - } + if ctx.base_name == BaseName::Expm1 && input.0 > 80.0 && actual.is_infinite() { + // we return infinity but the number is representable + return XFAIL; + } - if ctx.base_name == BaseName::Sinh && input.0.abs() > 80.0 && actual.is_nan() { - // we return some NaN that should be real values or infinite - // doesn't seem to happen on x86 - return XFAIL; - } + if ctx.base_name == BaseName::Sinh && input.0.abs() > 80.0 && actual.is_nan() { + // we return some NaN that should be real values or infinite + return XFAIL; } if ctx.base_name == BaseName::Acosh && input.0 < -1.0 { -- cgit 1.4.1-3-g733a5 From d86f8bee8b1bfa24a2fb3a08fa36b83810f5ba92 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Dec 2024 11:22:22 +0000 Subject: Add a way to plot the output from generators For visualization, add a simple script for generating scatter plots and a binary (via examples) to plot the inputs given various domains. --- .../libm/crates/libm-test/examples/plot_domains.rs | 105 ++++++++++++++ .../libm/crates/libm-test/examples/plot_file.jl | 157 +++++++++++++++++++++ 2 files changed, 262 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs new file mode 100644 index 00000000000..630a0c2337b --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs @@ -0,0 +1,105 @@ +//! Program to write all inputs from a generator to a file, then invoke a Julia script to plot +//! them. Output is in `target/plots`. +//! +//! Requires Julia with the `CairoMakie` dependency. +//! +//! Note that running in release mode by default generates a _lot_ more datapoints, which +//! causes plotting to be extremely slow (some simplification to be done in the script). + +use std::fmt::Write as _; +use std::io::{BufWriter, Write}; +use std::path::Path; +use std::process::Command; +use std::{env, fs}; + +use libm_test::domain::HasDomain; +use libm_test::gen::{domain_logspace, edge_cases}; +use libm_test::{MathOp, op}; + +const JL_PLOT: &str = "examples/plot_file.jl"; + +fn main() { + let manifest_env = env::var("CARGO_MANIFEST_DIR").unwrap(); + let manifest_dir = Path::new(&manifest_env); + let out_dir = manifest_dir.join("../../target/plots"); + if !out_dir.exists() { + fs::create_dir(&out_dir).unwrap(); + } + + let jl_script = manifest_dir.join(JL_PLOT); + let mut config = format!(r#"out_dir = "{}""#, out_dir.display()); + config.write_str("\n\n").unwrap(); + + // Plot a few domains with some functions that use them. + plot_one_operator::(&out_dir, &mut config); + plot_one_operator::(&out_dir, &mut config); + plot_one_operator::(&out_dir, &mut config); + + let config_path = out_dir.join("config.toml"); + fs::write(&config_path, config).unwrap(); + + // The script expects a path to `config.toml` to be passed as its only argument + let mut cmd = Command::new("julia"); + if cfg!(optimizations_enabled) { + cmd.arg("-O3"); + } + cmd.arg(jl_script).arg(config_path); + + println!("launching script... {cmd:?}"); + cmd.status().unwrap(); +} + +/// Run multiple generators for a single operator. +fn plot_one_operator(out_dir: &Path, config: &mut String) +where + Op: MathOp + HasDomain, +{ + plot_one_generator( + out_dir, + Op::BASE_NAME.as_str(), + "logspace", + config, + domain_logspace::get_test_cases::(), + ); + plot_one_generator( + out_dir, + Op::BASE_NAME.as_str(), + "edge_cases", + config, + edge_cases::get_test_cases::(), + ); +} + +/// Plot the output of a single generator. +fn plot_one_generator( + out_dir: &Path, + fn_name: &str, + gen_name: &str, + config: &mut String, + gen: impl Iterator, +) { + let text_file = out_dir.join(format!("input-{fn_name}-{gen_name}.txt")); + + let f = fs::File::create(&text_file).unwrap(); + let mut w = BufWriter::new(f); + let mut count = 0u64; + + for input in gen { + writeln!(w, "{:e}", input.0).unwrap(); + count += 1; + } + + w.flush().unwrap(); + println!("generated {count} inputs for {fn_name}-{gen_name}"); + + writeln!( + config, + r#"[[input]] +function = "{fn_name}" +generator = "{gen_name}" +input_file = "{}" +"#, + text_file.to_str().unwrap() + ) + .unwrap() +} diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl b/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl new file mode 100644 index 00000000000..14a128303c6 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl @@ -0,0 +1,157 @@ +"A quick script for plotting a list of floats. + +Takes a path to a TOML file (Julia has builtin TOML support but not JSON) which +specifies a list of source files to plot. Plots are done with both a linear and +a log scale. + +Requires [Makie] (specifically CairoMakie) for plotting. + +[Makie]: https://docs.makie.org/stable/ +" + +using CairoMakie +using TOML + +function main()::Nothing + CairoMakie.activate!(px_per_unit=10) + config_path = ARGS[1] + + cfg = Dict() + open(config_path, "r") do f + cfg = TOML.parse(f) + end + + out_dir = cfg["out_dir"] + for input in cfg["input"] + fn_name = input["function"] + gen_name = input["generator"] + input_file = input["input_file"] + + plot_one(input_file, out_dir, fn_name, gen_name) + end +end + +"Read inputs from a file, create both linear and log plots for one function" +function plot_one( + input_file::String, + out_dir::String, + fn_name::String, + gen_name::String, +)::Nothing + fig = Figure() + + lin_out_file = joinpath(out_dir, "plot-$fn_name-$gen_name.png") + log_out_file = joinpath(out_dir, "plot-$fn_name-$gen_name-log.png") + + # Map string function names to callable functions + if fn_name == "cos" + orig_func = cos + xlims = (-6.0, 6.0) + xlims_log = (-pi * 10, pi * 10) + elseif fn_name == "cbrt" + orig_func = cbrt + xlims = (-2.0, 2.0) + xlims_log = (-1000.0, 1000.0) + elseif fn_name == "sqrt" + orig_func = sqrt + xlims = (-1.1, 6.0) + xlims_log = (-1.1, 5000.0) + else + println("unrecognized function name `$fn_name`; update plot_file.jl") + exit(1) + end + + # Edge cases don't do much beyond +/-1, except for infinity. + if gen_name == "edge_cases" + xlims = (-1.1, 1.1) + xlims_log = (-1.1, 1.1) + end + + # Turn domain errors into NaN + func(x) = map_or(x, orig_func, NaN) + + # Parse a series of X values produced by the generator + inputs = readlines(input_file) + gen_x = map((v) -> parse(Float32, v), inputs) + + do_plot( + fig, gen_x, func, xlims[1], xlims[2], + "$fn_name $gen_name (linear scale)", + lin_out_file, false, + ) + + do_plot( + fig, gen_x, func, xlims_log[1], xlims_log[2], + "$fn_name $gen_name (log scale)", + log_out_file, true, + ) +end + +"Create a single plot" +function do_plot( + fig::Figure, + gen_x::Vector{F}, + func::Function, + xmin::AbstractFloat, + xmax::AbstractFloat, + title::String, + out_file::String, + logscale::Bool, +)::Nothing where F<:AbstractFloat + println("plotting $title") + + # `gen_x` is the values the generator produces. `actual_x` is for plotting a + # continuous function. + input_min = xmin - 1.0 + input_max = xmax + 1.0 + gen_x = filter((v) -> v >= input_min && v <= input_max, gen_x) + markersize = length(gen_x) < 10_000 ? 6.0 : 4.0 + + steps = 10_000 + if logscale + r = LinRange(symlog10(input_min), symlog10(input_max), steps) + actual_x = sympow10.(r) + xscale = Makie.pseudolog10 + else + actual_x = LinRange(input_min, input_max, steps) + xscale = identity + end + + gen_y = @. func(gen_x) + actual_y = @. func(actual_x) + + ax = Axis(fig[1, 1], xscale=xscale, title=title) + + lines!( + ax, actual_x, actual_y, color=(:lightblue, 0.6), + linewidth=6.0, label="true function", + ) + scatter!( + ax, gen_x, gen_y, color=(:darkblue, 0.9), + markersize=markersize, label="checked inputs", + ) + axislegend(ax, position=:rb, framevisible=false) + + save(out_file, fig) + delete!(ax) +end + +"Apply a function, returning the default if there is a domain error" +function map_or( + input::AbstractFloat, + f::Function, + default::Any +)::Union{AbstractFloat,Any} + try + return f(input) + catch + return default + end +end + +# Operations for logarithms that are symmetric about 0 +C = 10 +symlog10(x::Number) = sign(x) * (log10(1 + abs(x)/(10^C))) +sympow10(x::Number) = (10^C) * (10^x - 1) + +main() -- cgit 1.4.1-3-g733a5 From 1069346b6dcfac68e3d059bdd79000406b04c95c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 11:22:02 +0000 Subject: Move the macro's input function list to a new module `shared` This will enable us to `include!` the file to access these types in `libm-test`, rather than somehow reproducing the types as part of the macro. Ideally `libm-test` would just `use` the types from `libm-macros` but proc macro crates cannot currently export anything else. This also adjusts naming to closer match the scheme described in `libm_test::op`. --- .../libm/crates/libm-macros/src/enums.rs | 7 +- .../libm/crates/libm-macros/src/lib.rs | 299 +++------------------ .../libm/crates/libm-macros/src/shared.rs | 277 +++++++++++++++++++ 3 files changed, 320 insertions(+), 263 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-macros/src/shared.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs index 1f9fca2ef9e..82dedc66ecd 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs @@ -5,7 +5,7 @@ use quote::quote; use syn::spanned::Spanned; use syn::{Fields, ItemEnum, Variant}; -use crate::{ALL_FUNCTIONS_FLAT, base_name}; +use crate::{ALL_OPERATIONS, base_name}; /// Implement `#[function_enum]`, see documentation in `lib.rs`. pub fn function_enum( @@ -33,7 +33,7 @@ pub fn function_enum( let mut as_str_arms = Vec::new(); let mut base_arms = Vec::new(); - for func in ALL_FUNCTIONS_FLAT.iter() { + for func in ALL_OPERATIONS.iter() { let fn_name = func.name; let ident = Ident::new(&fn_name.to_upper_camel_case(), Span::call_site()); let bname_ident = Ident::new(&base_name(fn_name).to_upper_camel_case(), Span::call_site()); @@ -85,8 +85,7 @@ pub fn base_name_enum( return Err(syn::Error::new(sp.span(), "no attributes expected")); } - let mut base_names: Vec<_> = - ALL_FUNCTIONS_FLAT.iter().map(|func| base_name(func.name)).collect(); + let mut base_names: Vec<_> = ALL_OPERATIONS.iter().map(|func| base_name(func.name)).collect(); base_names.sort_unstable(); base_names.dedup(); diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs index 1e7cd08b908..916b539ed58 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs @@ -1,270 +1,18 @@ mod enums; mod parse; - -use std::sync::LazyLock; +mod shared; use parse::{Invocation, StructuredInput}; use proc_macro as pm; use proc_macro2::{self as pm2, Span}; use quote::{ToTokens, quote}; +pub(crate) use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; use syn::spanned::Spanned; use syn::visit_mut::VisitMut; use syn::{Ident, ItemEnum}; -const ALL_FUNCTIONS: &[(Ty, Signature, Option, &[&str])] = &[ - ( - // `fn(f32) -> f32` - Ty::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32] }, - None, - &[ - "acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf", - "coshf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", "j0f", "j1f", - "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", "sinf", "sinhf", - "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", - ], - ), - ( - // `(f64) -> f64` - Ty::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64] }, - None, - &[ - "acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh", - "erf", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", "log10", - "log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", - "tgamma", "trunc", - ], - ), - ( - // `(f32, f32) -> f32` - Ty::F32, - Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] }, - None, - &[ - "atan2f", - "copysignf", - "fdimf", - "fmaxf", - "fminf", - "fmodf", - "hypotf", - "nextafterf", - "powf", - "remainderf", - ], - ), - ( - // `(f64, f64) -> f64` - Ty::F64, - Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] }, - None, - &[ - "atan2", - "copysign", - "fdim", - "fmax", - "fmin", - "fmod", - "hypot", - "nextafter", - "pow", - "remainder", - ], - ), - ( - // `(f32, f32, f32) -> f32` - Ty::F32, - Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] }, - None, - &["fmaf"], - ), - ( - // `(f64, f64, f64) -> f64` - Ty::F64, - Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] }, - None, - &["fma"], - ), - ( - // `(f32) -> i32` - Ty::F32, - Signature { args: &[Ty::F32], returns: &[Ty::I32] }, - None, - &["ilogbf"], - ), - ( - // `(f64) -> i32` - Ty::F64, - Signature { args: &[Ty::F64], returns: &[Ty::I32] }, - None, - &["ilogb"], - ), - ( - // `(i32, f32) -> f32` - Ty::F32, - Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] }, - None, - &["jnf"], - ), - ( - // `(i32, f64) -> f64` - Ty::F64, - Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] }, - None, - &["jn"], - ), - ( - // `(f32, i32) -> f32` - Ty::F32, - Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] }, - None, - &["scalbnf", "ldexpf"], - ), - ( - // `(f64, i64) -> f64` - Ty::F64, - Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] }, - None, - &["scalbn", "ldexp"], - ), - ( - // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` - Ty::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, - Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }), - &["modff"], - ), - ( - // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` - Ty::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, - Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }), - &["modf"], - ), - ( - // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` - Ty::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] }, - Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), - &["frexpf", "lgammaf_r"], - ), - ( - // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` - Ty::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] }, - Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), - &["frexp", "lgamma_r"], - ), - ( - // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` - Ty::F32, - Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] }, - Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), - &["remquof"], - ), - ( - // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` - Ty::F64, - Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] }, - Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), - &["remquo"], - ), - ( - // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` - Ty::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, - Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }), - &["sincosf"], - ), - ( - // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` - Ty::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, - Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }), - &["sincos"], - ), -]; - const KNOWN_TYPES: &[&str] = &["FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet"]; -/// A type used in a function signature. -#[allow(dead_code)] -#[derive(Debug, Clone, Copy)] -enum Ty { - F16, - F32, - F64, - F128, - I32, - CInt, - MutF16, - MutF32, - MutF64, - MutF128, - MutI32, - MutCInt, -} - -impl ToTokens for Ty { - fn to_tokens(&self, tokens: &mut pm2::TokenStream) { - let ts = match self { - Ty::F16 => quote! { f16 }, - Ty::F32 => quote! { f32 }, - Ty::F64 => quote! { f64 }, - Ty::F128 => quote! { f128 }, - Ty::I32 => quote! { i32 }, - Ty::CInt => quote! { ::core::ffi::c_int }, - Ty::MutF16 => quote! { &'a mut f16 }, - Ty::MutF32 => quote! { &'a mut f32 }, - Ty::MutF64 => quote! { &'a mut f64 }, - Ty::MutF128 => quote! { &'a mut f128 }, - Ty::MutI32 => quote! { &'a mut i32 }, - Ty::MutCInt => quote! { &'a mut core::ffi::c_int }, - }; - - tokens.extend(ts); - } -} - -/// Representation of e.g. `(f32, f32) -> f32` -#[derive(Debug, Clone)] -struct Signature { - args: &'static [Ty], - returns: &'static [Ty], -} - -/// Combined information about a function implementation. -#[derive(Debug, Clone)] -struct FunctionInfo { - name: &'static str, - base_fty: Ty, - /// Function signature for C implementations - c_sig: Signature, - /// Function signature for Rust implementations - rust_sig: Signature, -} - -/// A flat representation of `ALL_FUNCTIONS`. -static ALL_FUNCTIONS_FLAT: LazyLock> = LazyLock::new(|| { - let mut ret = Vec::new(); - - for (base_fty, rust_sig, c_sig, names) in ALL_FUNCTIONS { - for name in *names { - let api = FunctionInfo { - name, - base_fty: *base_fty, - rust_sig: rust_sig.clone(), - c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()), - }; - ret.push(api); - } - } - - ret.sort_by_key(|item| item.name); - ret -}); - /// Populate an enum with a variant representing function. Names are in upper camel case. /// /// Applied to an empty enum. Expects one attribute `#[function_enum(BaseName)]` that provides @@ -382,7 +130,7 @@ pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream { /// Check for any input that is structurally correct but has other problems. /// /// Returns the list of function names that we should expand for. -fn validate(input: &mut StructuredInput) -> syn::Result> { +fn validate(input: &mut StructuredInput) -> syn::Result> { // Collect lists of all functions that are provied as macro inputs in various fields (only, // skip, attributes). let attr_mentions = input @@ -398,7 +146,7 @@ fn validate(input: &mut StructuredInput) -> syn::Result syn::Result syn::Result syn::Result { +fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result { let mut out = pm2::TokenStream::new(); let default_ident = Ident::new("_", Span::call_site()); let callback = input.callback; @@ -545,7 +293,7 @@ fn expand(input: StructuredInput, fn_list: &[&FunctionInfo]) -> syn::Result pm2::TokenStream::new(), }; - let base_fty = func.base_fty; + let base_fty = func.float_ty; let c_args = &func.c_sig.args; let c_ret = &func.c_sig.returns; let rust_args = &func.rust_sig.args; @@ -648,3 +396,36 @@ fn base_name(name: &str) -> &str { .unwrap_or(name), } } + +impl ToTokens for Ty { + fn to_tokens(&self, tokens: &mut pm2::TokenStream) { + let ts = match self { + Ty::F16 => quote! { f16 }, + Ty::F32 => quote! { f32 }, + Ty::F64 => quote! { f64 }, + Ty::F128 => quote! { f128 }, + Ty::I32 => quote! { i32 }, + Ty::CInt => quote! { ::core::ffi::c_int }, + Ty::MutF16 => quote! { &'a mut f16 }, + Ty::MutF32 => quote! { &'a mut f32 }, + Ty::MutF64 => quote! { &'a mut f64 }, + Ty::MutF128 => quote! { &'a mut f128 }, + Ty::MutI32 => quote! { &'a mut i32 }, + Ty::MutCInt => quote! { &'a mut core::ffi::c_int }, + }; + + tokens.extend(ts); + } +} +impl ToTokens for FloatTy { + fn to_tokens(&self, tokens: &mut pm2::TokenStream) { + let ts = match self { + FloatTy::F16 => quote! { f16 }, + FloatTy::F32 => quote! { f32 }, + FloatTy::F64 => quote! { f64 }, + FloatTy::F128 => quote! { f128 }, + }; + + tokens.extend(ts); + } +} diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs new file mode 100644 index 00000000000..100bcc7ad8c --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -0,0 +1,277 @@ +/* List of all functions that is shared between `libm-macros` and `libm-test`. */ + +use std::fmt; +use std::sync::LazyLock; + +const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] = &[ + ( + // `fn(f32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::F32] }, + None, + &[ + "acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf", + "coshf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", "j0f", "j1f", + "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", "sinf", "sinhf", + "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", + ], + ), + ( + // `(f64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::F64] }, + None, + &[ + "acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh", + "erf", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", "log10", + "log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", + "tgamma", "trunc", + ], + ), + ( + // `(f32, f32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] }, + None, + &[ + "atan2f", + "copysignf", + "fdimf", + "fmaxf", + "fminf", + "fmodf", + "hypotf", + "nextafterf", + "powf", + "remainderf", + ], + ), + ( + // `(f64, f64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] }, + None, + &[ + "atan2", + "copysign", + "fdim", + "fmax", + "fmin", + "fmod", + "hypot", + "nextafter", + "pow", + "remainder", + ], + ), + ( + // `(f32, f32, f32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] }, + None, + &["fmaf"], + ), + ( + // `(f64, f64, f64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] }, + None, + &["fma"], + ), + ( + // `(f32) -> i32` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::I32] }, + None, + &["ilogbf"], + ), + ( + // `(f64) -> i32` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::I32] }, + None, + &["ilogb"], + ), + ( + // `(i32, f32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] }, + None, + &["jnf"], + ), + ( + // `(i32, f64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] }, + None, + &["jn"], + ), + ( + // `(f32, i32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] }, + None, + &["scalbnf", "ldexpf"], + ), + ( + // `(f64, i64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] }, + None, + &["scalbn", "ldexp"], + ), + ( + // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, + Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }), + &["modff"], + ), + ( + // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, + Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }), + &["modf"], + ), + ( + // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] }, + Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), + &["frexpf", "lgammaf_r"], + ), + ( + // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] }, + Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), + &["frexp", "lgamma_r"], + ), + ( + // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` + FloatTy::F32, + Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] }, + Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), + &["remquof"], + ), + ( + // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` + FloatTy::F64, + Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] }, + Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), + &["remquo"], + ), + ( + // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, + Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }), + &["sincosf"], + ), + ( + // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, + Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }), + &["sincos"], + ), +]; + +/// A type used in a function signature. +#[allow(dead_code)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Ty { + F16, + F32, + F64, + F128, + I32, + CInt, + MutF16, + MutF32, + MutF64, + MutF128, + MutI32, + MutCInt, +} + +/// A subset of [`Ty`] representing only floats. +#[allow(dead_code)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum FloatTy { + F16, + F32, + F64, + F128, +} + +impl fmt::Display for Ty { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + Ty::F16 => "f16", + Ty::F32 => "f32", + Ty::F64 => "f64", + Ty::F128 => "f128", + Ty::I32 => "i32", + Ty::CInt => "::core::ffi::c_int", + Ty::MutF16 => "&mut f16", + Ty::MutF32 => "&mut f32", + Ty::MutF64 => "&mut f64", + Ty::MutF128 => "&mut f128", + Ty::MutI32 => "&mut i32", + Ty::MutCInt => "&mut ::core::ffi::c_int", + }; + f.write_str(s) + } +} + +impl fmt::Display for FloatTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + FloatTy::F16 => "f16", + FloatTy::F32 => "f32", + FloatTy::F64 => "f64", + FloatTy::F128 => "f128", + }; + f.write_str(s) + } +} + +/// Representation of e.g. `(f32, f32) -> f32` +#[derive(Debug, Clone)] +pub struct Signature { + pub args: &'static [Ty], + pub returns: &'static [Ty], +} + +/// Combined information about a function implementation. +#[derive(Debug, Clone)] +pub struct MathOpInfo { + pub name: &'static str, + pub float_ty: FloatTy, + /// Function signature for C implementations + pub c_sig: Signature, + /// Function signature for Rust implementations + pub rust_sig: Signature, +} + +/// A flat representation of `ALL_FUNCTIONS`. +pub static ALL_OPERATIONS: LazyLock> = LazyLock::new(|| { + let mut ret = Vec::new(); + + for (base_fty, rust_sig, c_sig, names) in ALL_OPERATIONS_NESTED { + for name in *names { + let api = MathOpInfo { + name, + float_ty: *base_fty, + rust_sig: rust_sig.clone(), + c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()), + }; + ret.push(api); + } + } + + ret.sort_by_key(|item| item.name); + ret +}); -- cgit 1.4.1-3-g733a5 From fc4b88aecd8c044d246e026d0c267a10350e9406 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 11:41:43 +0000 Subject: Include `shared.rs` in `libm_test::op` These types from `libm-macros` provide a way to get information about an operation at runtime, rather than only being encoded in the type system. Include the file and reexport relevant types. --- library/compiler-builtins/libm/crates/libm-test/src/lib.rs | 2 +- library/compiler-builtins/libm/crates/libm-test/src/op.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 622b2dec98c..e3a69067841 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -13,7 +13,7 @@ mod test_traits; pub use f8_impl::f8; pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, logspace}; -pub use op::{BaseName, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet}; +pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index bcea31c22b6..a2f21d3c191 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -13,8 +13,16 @@ //! - "Operation" / "Op": Something that relates a routine to a function or is otherwise higher //! level. `Op` is also used as the name for generic parameters since it is terse. +use std::fmt; + +pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; + use crate::{CheckOutput, Float, TupleCall}; +mod shared { + include!("../../libm-macros/src/shared.rs"); +} + /// An enum representing each possible symbol name (`sin`, `sinf`, `sinl`, etc). #[libm_macros::function_enum(BaseName)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -- cgit 1.4.1-3-g733a5 From b9ecacf03b7d295f898368216d2c9750b1affe5f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Dec 2024 08:06:53 +0000 Subject: Add new trait implementations for `Identifier` and `BaseName` These allow for more convenient printing, as well as storage in map types. --- .../compiler-builtins/libm/crates/libm-test/src/op.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index a2f21d3c191..e58c2890362 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -25,14 +25,26 @@ mod shared { /// An enum representing each possible symbol name (`sin`, `sinf`, `sinl`, etc). #[libm_macros::function_enum(BaseName)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Identifier {} +impl fmt::Display for Identifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + /// The name without any type specifier, e.g. `sin` and `sinf` both become `sin`. #[libm_macros::base_name_enum] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum BaseName {} +impl fmt::Display for BaseName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + /// Attributes ascribed to a `libm` routine including signature, type information, /// and naming. pub trait MathOp { -- cgit 1.4.1-3-g733a5 From 6e97fef9c9b340b71e8f5051389ed24185003909 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 11:26:22 +0000 Subject: Add `ALL`, `from_str` and `math_op` to `Identifier` Introduce new API to iterate the function list and associate items with their `MathOp`. --- .../libm/crates/libm-macros/src/enums.rs | 23 +++++++++++++++++ .../libm/crates/libm-macros/tests/enum.rs | 29 ++++++++++++++++++---- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs index 82dedc66ecd..864b625eab3 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs @@ -31,6 +31,7 @@ pub fn function_enum( let enum_name = &item.ident; let mut as_str_arms = Vec::new(); + let mut from_str_arms = Vec::new(); let mut base_arms = Vec::new(); for func in ALL_OPERATIONS.iter() { @@ -40,6 +41,7 @@ pub fn function_enum( // Match arm for `fn as_str(self)` matcher as_str_arms.push(quote! { Self::#ident => #fn_name }); + from_str_arms.push(quote! { #fn_name => Self::#ident }); // Match arm for `fn base_name(self)` matcher base_arms.push(quote! { Self::#ident => #base_enum::#bname_ident }); @@ -50,11 +52,18 @@ pub fn function_enum( item.variants.push(variant); } + let variants = item.variants.iter(); + let res = quote! { // Instantiate the enum #item impl #enum_name { + /// All variants of this enum. + pub const ALL: &[Self] = &[ + #( Self::#variants, )* + ]; + /// The stringified version of this function name. pub const fn as_str(self) -> &'static str { match self { @@ -62,12 +71,26 @@ pub fn function_enum( } } + /// If `s` is the name of a function, return it. + pub fn from_str(s: &str) -> Option { + let ret = match s { + #( #from_str_arms , )* + _ => return None, + }; + Some(ret) + } + /// The base name enum for this function. pub const fn base_name(self) -> #base_enum { match self { #( #base_arms, )* } } + + /// Return information about this operation. + pub fn math_op(self) -> &'static crate::op::MathOpInfo { + crate::op::ALL_OPERATIONS.iter().find(|op| op.name == self.as_str()).unwrap() + } } }; diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs index 884b8d8d651..93e209a0dcc 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs @@ -1,6 +1,6 @@ #[libm_macros::function_enum(BaseName)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum Function {} +pub enum Identifier {} #[libm_macros::base_name_enum] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -8,12 +8,31 @@ pub enum BaseName {} #[test] fn as_str() { - assert_eq!(Function::Sin.as_str(), "sin"); - assert_eq!(Function::Sinf.as_str(), "sinf"); + assert_eq!(Identifier::Sin.as_str(), "sin"); + assert_eq!(Identifier::Sinf.as_str(), "sinf"); +} + +#[test] +fn from_str() { + assert_eq!(Identifier::from_str("sin").unwrap(), Identifier::Sin); + assert_eq!(Identifier::from_str("sinf").unwrap(), Identifier::Sinf); } #[test] fn basename() { - assert_eq!(Function::Sin.base_name(), BaseName::Sin); - assert_eq!(Function::Sinf.base_name(), BaseName::Sin); + assert_eq!(Identifier::Sin.base_name(), BaseName::Sin); + assert_eq!(Identifier::Sinf.base_name(), BaseName::Sin); } + +#[test] +fn math_op() { + assert_eq!(Identifier::Sin.math_op().float_ty, FloatTy::F64); + assert_eq!(Identifier::Sinf.math_op().float_ty, FloatTy::F32); +} + +// Replicate the structure that we have in `libm-test` +mod op { + include!("../../libm-macros/src/shared.rs"); +} + +use op::FloatTy; -- cgit 1.4.1-3-g733a5 From 86aeee818b4c888279b1feb48161f7d93871ca8f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 26 Dec 2024 07:43:56 +0000 Subject: Move `CheckBasis` and `CheckCtx` to a new `run_cfg` module These are used more places than just test traits, so this new module should be a better home. `run_cfg` will also be expanded in the near future. --- .../libm/crates/libm-test/src/lib.rs | 4 +- .../libm/crates/libm-test/src/run_cfg.rs | 51 ++++++++++++++++++++++ .../libm/crates/libm-test/src/test_traits.rs | 39 +---------------- 3 files changed, 55 insertions(+), 39 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index e3a69067841..eb457b0ae7b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -8,6 +8,7 @@ pub mod mpfloat; mod num; pub mod op; mod precision; +mod run_cfg; mod test_traits; pub use f8_impl::f8; @@ -15,7 +16,8 @@ pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, logspace}; pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; -pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; +pub use run_cfg::{CheckBasis, CheckCtx}; +pub use test_traits::{CheckOutput, GenerateInput, Hex, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to /// propagate. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs new file mode 100644 index 00000000000..eb7e0e2c1a9 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -0,0 +1,51 @@ +//! Configuration for how tests get run. + +#![allow(unused)] + +use std::collections::BTreeMap; +use std::env; +use std::sync::LazyLock; + +use crate::{BaseName, FloatTy, Identifier, op}; + +pub const EXTENSIVE_ENV: &str = "LIBM_EXTENSIVE_TESTS"; + +/// Context passed to [`CheckOutput`]. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CheckCtx { + /// Allowed ULP deviation + pub ulp: u32, + pub fn_ident: Identifier, + pub base_name: BaseName, + /// Function name. + pub fn_name: &'static str, + /// Return the unsuffixed version of the function name. + pub base_name_str: &'static str, + /// Source of truth for tests. + pub basis: CheckBasis, +} + +impl CheckCtx { + /// Create a new check context, using the default ULP for the function. + pub fn new(fn_ident: Identifier, basis: CheckBasis) -> Self { + let mut ret = Self { + ulp: 0, + fn_ident, + fn_name: fn_ident.as_str(), + base_name: fn_ident.base_name(), + base_name_str: fn_ident.base_name().as_str(), + basis, + }; + ret.ulp = crate::default_ulp(&ret); + ret + } +} + +/// Possible items to test against +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum CheckBasis { + /// Check against Musl's math sources. + Musl, + /// Check against infinite precision (MPFR). + Mpfr, +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index ca933bbda63..6b833dfb5dd 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -11,44 +11,7 @@ use std::fmt; use anyhow::{Context, bail, ensure}; -use crate::{BaseName, Float, Identifier, Int, MaybeOverride, SpecialCase, TestResult}; - -/// Context passed to [`CheckOutput`]. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CheckCtx { - /// Allowed ULP deviation - pub ulp: u32, - pub fn_ident: Identifier, - pub base_name: BaseName, - /// Function name. - pub fn_name: &'static str, - /// Source of truth for tests. - pub basis: CheckBasis, -} - -impl CheckCtx { - /// Create a new check context, using the default ULP for the function. - pub fn new(fn_ident: Identifier, basis: CheckBasis) -> Self { - let mut ret = Self { - ulp: 0, - fn_ident, - fn_name: fn_ident.as_str(), - base_name: fn_ident.base_name(), - basis, - }; - ret.ulp = crate::default_ulp(&ret); - ret - } -} - -/// Possible items to test against -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum CheckBasis { - /// Check against Musl's math sources. - Musl, - /// Check against infinite precision (MPFR). - Mpfr, -} +use crate::{CheckCtx, Float, Int, MaybeOverride, SpecialCase, TestResult}; /// Implement this on types that can generate a sequence of tuples for test input. pub trait GenerateInput { -- cgit 1.4.1-3-g733a5 From 7082f9baf72fbcff1a3a824848439bdc4b602f12 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 26 Dec 2024 07:42:13 +0000 Subject: Use `CheckCtx` in more places Rather than passing names or identifiers, just pass `CheckCtx` in a few more places. --- .../libm/crates/libm-test/examples/plot_domains.rs | 14 ++++++++------ .../libm/crates/libm-test/src/gen/domain_logspace.rs | 4 ++-- .../libm/crates/libm-test/src/gen/edge_cases.rs | 4 ++-- .../libm/crates/libm-test/tests/multiprecision.rs | 8 +++++--- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs index 630a0c2337b..62651124535 100644 --- a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs +++ b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs @@ -14,7 +14,7 @@ use std::{env, fs}; use libm_test::domain::HasDomain; use libm_test::gen::{domain_logspace, edge_cases}; -use libm_test::{MathOp, op}; +use libm_test::{CheckBasis, CheckCtx, MathOp, op}; const JL_PLOT: &str = "examples/plot_file.jl"; @@ -54,30 +54,32 @@ fn plot_one_operator(out_dir: &Path, config: &mut String) where Op: MathOp + HasDomain, { + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); plot_one_generator( out_dir, - Op::BASE_NAME.as_str(), + &ctx, "logspace", config, - domain_logspace::get_test_cases::(), + domain_logspace::get_test_cases::(&ctx), ); plot_one_generator( out_dir, - Op::BASE_NAME.as_str(), + &ctx, "edge_cases", config, - edge_cases::get_test_cases::(), + edge_cases::get_test_cases::(&ctx), ); } /// Plot the output of a single generator. fn plot_one_generator( out_dir: &Path, - fn_name: &str, + ctx: &CheckCtx, gen_name: &str, config: &mut String, gen: impl Iterator, ) { + let fn_name = ctx.base_name_str; let text_file = out_dir.join(format!("input-{fn_name}-{gen_name}.txt")); let f = fs::File::create(&text_file).unwrap(); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs index e8cdb9d2b91..3e69bee34dd 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs @@ -4,7 +4,7 @@ use libm::support::{IntTy, MinInt}; use crate::domain::HasDomain; use crate::op::OpITy; -use crate::{MathOp, logspace}; +use crate::{CheckCtx, MathOp, logspace}; /// Number of tests to run. // FIXME(ntests): replace this with a more logical algorithm @@ -30,7 +30,7 @@ const NTESTS: usize = { /// /// This allows us to get reasonably thorough coverage without wasting time on values that are /// NaN or out of range. Random tests will still cover values that are excluded here. -pub fn get_test_cases() -> impl Iterator +pub fn get_test_cases(_ctx: &CheckCtx) -> impl Iterator where Op: MathOp + HasDomain, IntTy: TryFrom, diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs index 625e18bc7a8..3387f6c485a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs @@ -3,7 +3,7 @@ use libm::support::Float; use crate::domain::HasDomain; -use crate::{FloatExt, MathOp}; +use crate::{CheckCtx, FloatExt, MathOp}; /// Number of values near an interesting point to check. // FIXME(ntests): replace this with a more logical algorithm @@ -14,7 +14,7 @@ const AROUND: usize = 100; const MAX_CHECK_POINTS: usize = 10; /// Create a list of values around interesting points (infinities, zeroes, NaNs). -pub fn get_test_cases() -> impl Iterator +pub fn get_test_cases(_ctx: &CheckCtx) -> impl Iterator where Op: MathOp + HasDomain, F: Float, diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 5255dc1cfd7..2675ca0185a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -83,21 +83,21 @@ macro_rules! mp_domain_tests { $(#[$meta])* fn [< mp_edge_case_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - domain_test_runner::(edge_cases::get_test_cases::()); + domain_test_runner::(edge_cases::get_test_cases::); } #[test] $(#[$meta])* fn [< mp_logspace_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - domain_test_runner::(domain_logspace::get_test_cases::()); + domain_test_runner::(domain_logspace::get_test_cases::); } } }; } /// Test a single routine against domaine-aware inputs. -fn domain_test_runner(cases: impl Iterator) +fn domain_test_runner(gen: impl FnOnce(&CheckCtx) -> I) where // Complicated generics... // The operation must take a single float argument (unary only) @@ -108,9 +108,11 @@ where Op: HasDomain, // The single float argument tuple must be able to call the `RustFn` and return `RustRet` (OpFTy,): TupleCall, Output = OpRustRet>, + I: Iterator, { let mut mp_vals = Op::new_mp(); let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); + let cases = gen(&ctx); for input in cases { let mp_res = Op::run(&mut mp_vals, input); -- cgit 1.4.1-3-g733a5 From a93f659d7c3378569da9b6c8ef6a9d963d420dcd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Dec 2024 09:04:18 +0000 Subject: Don't run `push` CI on anything other than `master` --- library/compiler-builtins/libm/.github/workflows/main.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 93cd541f838..83875f3682c 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -1,5 +1,9 @@ name: CI -on: [push, pull_request] +on: + push: + branches: + - master + pull_request: env: CARGO_TERM_VERBOSE: true -- cgit 1.4.1-3-g733a5 From e8c501861a30b45111cb4fed85e184accd75782f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Dec 2024 01:53:29 +0000 Subject: Set the allowed FMA ULP to 0 It is currently getting the default of 1 or 2. Since this operation should always be infinite precision, no deviation is allowed. --- library/compiler-builtins/libm/crates/libm-test/src/precision.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index b878212faf8..058d01c6e4e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -24,6 +24,8 @@ const MP_DEFAULT_ULP: u32 = 1; pub fn default_ulp(ctx: &CheckCtx) -> u32 { match (&ctx.basis, ctx.fn_ident) { // Overrides that apply to either basis + // FMA is expected to be infinite precision. + (_, Id::Fma | Id::Fmaf) => 0, (_, Id::J0 | Id::J0f | Id::J1 | Id::J1f) => { // Results seem very target-dependent if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } -- cgit 1.4.1-3-g733a5 From cf58a7ce90c21093e1f390ab899d29932d17d42c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Dec 2024 05:55:41 +0000 Subject: Remove lossy casting in `logspace` Currently `logspace` does a lossy cast from `F::Int` to `usize`. This could be problematic in the rare cases that this is called with a step count exceeding what is representable in `usize`. Resolve this by instead adding bounds so the float's integer type itself can be iterated. --- .../libm/crates/libm-test/src/gen/domain_logspace.rs | 3 +++ library/compiler-builtins/libm/crates/libm-test/src/num.rs | 10 +++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs index 3e69bee34dd..5e37170fa1a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs @@ -1,5 +1,7 @@ //! A generator that produces logarithmically spaced values within domain bounds. +use std::ops::RangeInclusive; + use libm::support::{IntTy, MinInt}; use crate::domain::HasDomain; @@ -34,6 +36,7 @@ pub fn get_test_cases(_ctx: &CheckCtx) -> impl Iterator where Op: MathOp + HasDomain, IntTy: TryFrom, + RangeInclusive>: Iterator, { let domain = Op::DOMAIN; let start = domain.range_start(); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num.rs b/library/compiler-builtins/libm/crates/libm-test/src/num.rs index 4aa7f61b05a..eff2fbc1fdd 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/num.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/num.rs @@ -1,8 +1,9 @@ //! Helpful numeric operations. use std::cmp::min; +use std::ops::RangeInclusive; -use libm::support::{CastInto, Float}; +use libm::support::Float; use crate::{Int, MinInt}; @@ -214,7 +215,10 @@ fn as_ulp_steps(x: F) -> Option { /// to logarithmic spacing of their values. /// /// Note that this tends to skip negative zero, so that needs to be checked explicitly. -pub fn logspace(start: F, end: F, steps: F::Int) -> impl Iterator { +pub fn logspace(start: F, end: F, steps: F::Int) -> impl Iterator +where + RangeInclusive: Iterator, +{ assert!(!start.is_nan()); assert!(!end.is_nan()); assert!(end >= start); @@ -225,7 +229,7 @@ pub fn logspace(start: F, end: F, steps: F::Int) -> impl Iterator Date: Sun, 22 Dec 2024 10:14:56 +0000 Subject: Forward the `CI` environment variable when running in Docker We want to be able to adjust our configuration based on whether we are running in CI, propagate this so our tests can use it. --- library/compiler-builtins/libm/ci/run-docker.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index a040126df84..d9f29656d71 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -28,6 +28,7 @@ run() { docker run \ --rm \ --user "$(id -u):$(id -g)" \ + -e CI \ -e RUSTFLAGS \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ -- cgit 1.4.1-3-g733a5 From ed72c4ec69a132890b782d3c9e44e387d44a5799 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Dec 2024 22:56:36 +0000 Subject: Use `rustdoc` output to create a list of public API Rather than collecting a list of file names in `libm-test/build.rs`, just use a script to parse rustdoc's JSON output. --- .../libm/.github/workflows/main.yml | 4 + .../libm/crates/libm-test/build.rs | 34 ------ .../libm/crates/libm-test/src/lib.rs | 12 ++- .../libm/crates/libm-test/tests/check_coverage.rs | 70 ++++++------ .../compiler-builtins/libm/etc/function-list.txt | 115 ++++++++++++++++++++ .../compiler-builtins/libm/etc/update-api-list.py | 117 +++++++++++++++++++++ 6 files changed, 283 insertions(+), 69 deletions(-) create mode 100644 library/compiler-builtins/libm/etc/function-list.txt create mode 100755 library/compiler-builtins/libm/etc/update-api-list.py diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 83875f3682c..0f5becf7305 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -96,6 +96,10 @@ jobs: run: ./ci/download-musl.sh shell: bash + - name: Verify API list + if: matrix.os == 'ubuntu-24.04' + run: python3 etc/update-api-list.py --check + # Non-linux tests just use our raw script - name: Run locally if: matrix.os != 'ubuntu-24.04' || contains(matrix.target, 'wasm') diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index f2cd298baf2..134fb11ceeb 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -1,42 +1,8 @@ -use std::fmt::Write; -use std::fs; - #[path = "../../configure.rs"] mod configure; use configure::Config; fn main() { let cfg = Config::from_env(); - - list_all_tests(&cfg); - configure::emit_test_config(&cfg); } - -/// Create a list of all source files in an array. This can be used for making sure that -/// all functions are tested or otherwise covered in some way. -// FIXME: it would probably be better to use rustdoc JSON output to get public functions. -fn list_all_tests(cfg: &Config) { - let math_src = cfg.manifest_dir.join("../../src/math"); - - let mut files = fs::read_dir(math_src) - .unwrap() - .map(|f| f.unwrap().path()) - .filter(|entry| entry.is_file()) - .map(|f| f.file_stem().unwrap().to_str().unwrap().to_owned()) - .collect::>(); - files.sort(); - - let mut s = "pub const ALL_FUNCTIONS: &[&str] = &[".to_owned(); - for f in files { - if f == "mod" { - // skip mod.rs - continue; - } - write!(s, "\"{f}\",").unwrap(); - } - write!(s, "];").unwrap(); - - let outfile = cfg.out_dir.join("all_files.rs"); - fs::write(outfile, s).unwrap(); -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index eb457b0ae7b..fdba0357f7f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -23,9 +23,6 @@ pub use test_traits::{CheckOutput, GenerateInput, Hex, TupleCall}; /// propagate. pub type TestResult = Result; -// List of all files present in libm's source -include!(concat!(env!("OUT_DIR"), "/all_files.rs")); - /// True if `EMULATED` is set and nonempty. Used to determine how many iterations to run. pub const fn emulated() -> bool { match option_env!("EMULATED") { @@ -34,3 +31,12 @@ pub const fn emulated() -> bool { Some(_) => true, } } + +/// True if `CI` is set and nonempty. +pub const fn ci() -> bool { + match option_env!("CI") { + Some(s) if s.is_empty() => false, + None => false, + Some(_) => true, + } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs index b7988660e66..9f85d64244b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs @@ -1,54 +1,60 @@ //! Ensure that `for_each_function!` isn't missing any symbols. -/// Files in `src/` that do not export a testable symbol. -const ALLOWED_SKIPS: &[&str] = &[ - // Not a generic test function - "fenv", - // Nonpublic functions - "expo2", - "k_cos", - "k_cosf", - "k_expo2", - "k_expo2f", - "k_sin", - "k_sinf", - "k_tan", - "k_tanf", - "rem_pio2", - "rem_pio2_large", - "rem_pio2f", -]; +use std::collections::HashSet; +use std::env; +use std::path::Path; +use std::process::Command; macro_rules! callback { ( fn_name: $name:ident, - extra: [$push_to:ident], + extra: [$set:ident], ) => { - $push_to.push(stringify!($name)); + let name = stringify!($name); + let new = $set.insert(name); + assert!(new, "duplicate function `{name}` in `ALL_OPERATIONS`"); }; } #[test] fn test_for_each_function_all_included() { - let mut included = Vec::new(); - let mut missing = Vec::new(); + let all_functions: HashSet<_> = include_str!("../../../etc/function-list.txt") + .lines() + .filter(|line| !line.starts_with("#")) + .collect(); + + let mut tested = HashSet::new(); libm_macros::for_each_function! { callback: callback, - extra: [included], + extra: [tested], }; - for f in libm_test::ALL_FUNCTIONS { - if !included.contains(f) && !ALLOWED_SKIPS.contains(f) { - missing.push(f) - } - } - - if !missing.is_empty() { + let untested = all_functions.difference(&tested); + if untested.clone().next().is_some() { panic!( - "missing tests for the following: {missing:#?} \ + "missing tests for the following: {untested:#?} \ \nmake sure any new functions are entered in \ - `ALL_FUNCTIONS` (in `libm-macros`)." + `ALL_OPERATIONS` (in `libm-macros`)." ); } + assert_eq!(all_functions, tested); +} + +#[test] +fn ensure_list_updated() { + if libm_test::ci() { + // Most CI tests run in Docker where we don't have Python or Rustdoc, so it's easiest + // to just run the python file directly when it is available. + eprintln!("skipping test; CI runs the python file directly"); + return; + } + + let res = Command::new("python3") + .arg(Path::new(env!("CARGO_MANIFEST_DIR")).join("../../etc/update-api-list.py")) + .arg("--check") + .status() + .unwrap(); + + assert!(res.success(), "May need to run `./etc/update-api-list.py`"); } diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt new file mode 100644 index 00000000000..51f5b221c26 --- /dev/null +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -0,0 +1,115 @@ +# autogenerated by update-api-list.py +acos +acosf +acosh +acoshf +asin +asinf +asinh +asinhf +atan +atan2 +atan2f +atanf +atanh +atanhf +cbrt +cbrtf +ceil +ceilf +copysign +copysignf +cos +cosf +cosh +coshf +erf +erfc +erfcf +erff +exp +exp10 +exp10f +exp2 +exp2f +expf +expm1 +expm1f +fabs +fabsf +fdim +fdimf +floor +floorf +fma +fmaf +fmax +fmaxf +fmin +fminf +fmod +fmodf +frexp +frexpf +hypot +hypotf +ilogb +ilogbf +j0 +j0f +j1 +j1f +jn +jnf +ldexp +ldexpf +lgamma +lgamma_r +lgammaf +lgammaf_r +log +log10 +log10f +log1p +log1pf +log2 +log2f +logf +modf +modff +nextafter +nextafterf +pow +powf +remainder +remainderf +remquo +remquof +rint +rintf +round +roundf +scalbn +scalbnf +sin +sincos +sincosf +sinf +sinh +sinhf +sqrt +sqrtf +tan +tanf +tanh +tanhf +tgamma +tgammaf +trunc +truncf +y0 +y0f +y1 +y1f +yn +ynf diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py new file mode 100755 index 00000000000..7284a628c6a --- /dev/null +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +"""Create a text file listing all public API. This can be used to ensure that all +functions are covered by our macros. +""" + +import json +import subprocess as sp +import sys +import difflib +from pathlib import Path +from typing import Any + +ETC_DIR = Path(__file__).parent + + +def get_rustdoc_json() -> dict[Any, Any]: + """Get rustdoc's JSON output for the `libm` crate.""" + + librs_path = ETC_DIR.joinpath("../src/lib.rs") + j = sp.check_output( + [ + "rustdoc", + librs_path, + "--edition=2021", + "--output-format=json", + "-Zunstable-options", + "-o-", + ], + text=True, + ) + j = json.loads(j) + return j + + +def list_public_functions() -> list[str]: + """Get a list of public functions from rustdoc JSON output. + + Note that this only finds functions that are reexported in `lib.rs`, this will + need to be adjusted if we need to account for functions that are defined there. + """ + names = [] + index: dict[str, dict[str, Any]] = get_rustdoc_json()["index"] + for item in index.values(): + # Find public items + if item["visibility"] != "public": + continue + + # Find only reexports + if "use" not in item["inner"].keys(): + continue + + # Locate the item that is reexported + id = item["inner"]["use"]["id"] + srcitem = index.get(str(id)) + + # External crate + if srcitem is None: + continue + + # Skip if not a function + if "function" not in srcitem["inner"].keys(): + continue + + names.append(srcitem["name"]) + + names.sort() + return names + + +def diff_and_exit(actual: str, expected: str): + """If the two strings are different, print a diff between them and then exit + with an error. + """ + if actual == expected: + print("output matches expected; success") + return + + a = [f"{line}\n" for line in actual.splitlines()] + b = [f"{line}\n" for line in expected.splitlines()] + + diff = difflib.unified_diff(a, b, "actual", "expected") + sys.stdout.writelines(diff) + print("mismatched function list") + exit(1) + + +def main(): + """By default overwrite the file. If `--check` is passed, print a diff instead and + error if the files are different. + """ + match sys.argv: + case [_]: + check = False + case [_, "--check"]: + check = True + case _: + print("unrecognized arguments") + exit(1) + + names = list_public_functions() + output = "# autogenerated by update-api-list.py\n" + for name in names: + output += f"{name}\n" + + out_file = ETC_DIR.joinpath("function-list.txt") + + if check: + with open(out_file, "r") as f: + current = f.read() + diff_and_exit(current, output) + else: + with open(out_file, "w") as f: + f.write(output) + + +if __name__ == "__main__": + main() -- cgit 1.4.1-3-g733a5 From e754ecb6d99aa8c76824ac56bb332320e1cf9ac4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Dec 2024 22:57:21 +0000 Subject: Add missing functions to the macro list Now that we are using rustdoc output to locate public functions, the test is indicating a few that were missed since they don't have their own function. Update everything to now include the following routines: * `erfc` * `erfcf` * `y0` * `y0f` * `y1` * `y1f` * `yn` * `ynf` --- .../libm/crates/libm-macros/src/shared.rs | 16 ++++++++-------- .../libm/crates/libm-test/src/domain.rs | 3 +++ .../libm/crates/libm-test/src/gen/random.rs | 6 +++++- .../libm/crates/libm-test/src/mpfloat.rs | 17 ++++++++++++++++- .../libm/crates/libm-test/src/precision.rs | 14 ++++++-------- .../libm/crates/libm-test/tests/multiprecision.rs | 4 +++- .../libm/crates/musl-math-sys/src/lib.rs | 1 + 7 files changed, 42 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 100bcc7ad8c..ef0f188014b 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -11,9 +11,9 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] None, &[ "acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf", - "coshf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", "j0f", "j1f", - "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", "sinf", "sinhf", - "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", + "coshf", "erff", "erfcf", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", + "j0f", "j1f", "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", + "sinf", "sinhf", "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", "y0f", "y1f", ], ), ( @@ -23,9 +23,9 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] None, &[ "acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh", - "erf", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", "log10", - "log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", - "tgamma", "trunc", + "erf", "erfc", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", + "log10", "log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", + "tgamma", "trunc", "y0", "y1", ], ), ( @@ -97,14 +97,14 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F32, Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] }, None, - &["jnf"], + &["jnf", "ynf"], ), ( // `(i32, f64) -> f64` FloatTy::F64, Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] }, None, - &["jn"], + &["jn", "yn"], ), ( // `(f32, i32) -> f32` diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index 9ee8a19b970..7b5a01b9683 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -147,6 +147,7 @@ impl_has_domain! { cos => TRIG; cosh => UNBOUNDED; erf => UNBOUNDED; + erfc => UNBOUNDED; exp => UNBOUNDED; exp10 => UNBOUNDED; exp2 => UNBOUNDED; @@ -173,6 +174,8 @@ impl_has_domain! { tanh => UNBOUNDED; tgamma => GAMMA; trunc => UNBOUNDED; + y0 => UNBOUNDED; + y1 => UNBOUNDED; } /* Manual implementations, these functions don't follow `foo`->`foof` naming */ diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 527cd135142..4f75da07b89 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -110,6 +110,10 @@ pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator, { - let inputs = if ctx.base_name == BaseName::Jn { &TEST_CASES_JN } else { &TEST_CASES }; + let inputs = if ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn { + &TEST_CASES_JN + } else { + &TEST_CASES + }; inputs.get_cases() } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 507b077b37c..28df916bd61 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -130,7 +130,7 @@ libm_macros::for_each_function! { fabsf, ceilf, copysignf, floorf, rintf, roundf, truncf, fmod, fmodf, frexp, frexpf, ilogb, ilogbf, jn, jnf, ldexp, ldexpf, lgamma_r, lgammaf_r, modf, modff, nextafter, nextafterf, pow,powf, - remquo, remquof, scalbn, scalbnf, sincos, sincosf, + remquo, remquof, scalbn, scalbnf, sincos, sincosf, yn, ynf, ], fn_extra: match MACRO_FN_NAME { // Remap function names that are different between mpfr and libm @@ -266,6 +266,21 @@ macro_rules! impl_op_for_ty { ) } } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (i32, MpFloat); + + fn new_mp() -> Self::MpTy { + (0, new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0 = input.0; + this.1.assign(input.1); + let ord = this.1.yn_round(this.0, Nearest); + prep_retval::(&mut this.1, ord) + } + } } }; } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 058d01c6e4e..6d4561c4376 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -26,11 +26,9 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { // Overrides that apply to either basis // FMA is expected to be infinite precision. (_, Id::Fma | Id::Fmaf) => 0, - (_, Id::J0 | Id::J0f | Id::J1 | Id::J1f) => { - // Results seem very target-dependent - if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } - } - (_, Id::Jn | Id::Jnf) => 1000, + (_, Id::J0 | Id::J0f | Id::J1 | Id::J1f | Id::Y0 | Id::Y0f | Id::Y1 | Id::Y1f) => 800_000, + (_, Id::Jn | Id::Jnf | Id::Yn | Id::Ynf) => 1000, + (_, Id::Erfc | Id::Erfcf) => 4, // Overrides for musl #[cfg(x86_no_sse)] @@ -297,7 +295,7 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { (Musl, _) => bessel_prec_dropoff(input, ulp, ctx), // We return +0.0, MPFR returns -0.0 - (Mpfr, BaseName::Jn) + (Mpfr, BaseName::Jn | BaseName::Yn) if input.1 == f32::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO => { XFAIL @@ -319,7 +317,7 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { (Musl, _) => bessel_prec_dropoff(input, ulp, ctx), // We return +0.0, MPFR returns -0.0 - (Mpfr, BaseName::Jn) + (Mpfr, BaseName::Jn | BaseName::Yn) if input.1 == f64::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO => { XFAIL @@ -336,7 +334,7 @@ fn bessel_prec_dropoff( ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - if ctx.base_name == BaseName::Jn { + if ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn { if input.0 > 4000 { return XFAIL; } else if input.0 > 2000 { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 2675ca0185a..4821f74461f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -48,7 +48,7 @@ libm_macros::for_each_function! { attributes: [ // Also an assertion failure on i686: at `MPFR_ASSERTN (! mpfr_erangeflag_p ())` #[ignore = "large values are infeasible in MPFR"] - [jn, jnf], + [jn, jnf, yn, ynf], ], skip: [ // FIXME: MPFR tests needed @@ -157,6 +157,8 @@ libm_macros::for_each_function! { remquof, scalbn, scalbnf, + yn, + ynf, // FIXME: MPFR tests needed frexp, diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs index db352fab8df..07277ef3e6e 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs +++ b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs @@ -282,5 +282,6 @@ functions! { musl_y0f: y0f(a: f32) -> f32; musl_y1: y1(a: f64) -> f64; musl_y1f: y1f(a: f32) -> f32; + musl_yn: yn(a: c_int, b: f64) -> f64; musl_ynf: ynf(a: c_int, b: f32) -> f32; } -- cgit 1.4.1-3-g733a5 From 3fb16fbdbe6bd0953a43797bb275bfa1d39692e2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 2 Jan 2025 21:23:28 +0000 Subject: macros: Always emit `f16_enabled` and `f128_enabled` attributes Once we start addinf `f16` and `f128` routines, we will need to have this cfg for almost all uses of `for_each_function`. Rather than needing to specify this each time, always emit `#[cfg(f16_enabled)]` or `#[cfg(f128_enabled)]` for each function that uses `f16` or `f128`, respectively. --- .../libm/crates/libm-macros/src/lib.rs | 37 +++++++++++++++------- .../libm/crates/libm-macros/tests/basic.rs | 10 ++++-- .../libm/crates/libm-test/benches/random.rs | 4 +++ .../libm/crates/libm-test/src/lib.rs | 2 ++ .../libm/crates/libm-test/src/mpfloat.rs | 6 ++++ .../libm/crates/libm-test/src/op.rs | 3 ++ .../libm/crates/libm-test/tests/check_coverage.rs | 1 + .../crates/libm-test/tests/compare_built_musl.rs | 4 +-- .../libm/crates/libm-test/tests/multiprecision.rs | 10 +++--- 9 files changed, 57 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs index 916b539ed58..3cee5385b62 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs @@ -79,7 +79,7 @@ pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> p /// // The Rust version's return type (e.g. `(f32, f32)`) /// RustRet: $RustRet:ty, /// // Attributes for the current function, if any -/// attrs: [$($meta:meta)*] +/// attrs: [$($attr:meta),*], /// // Extra tokens passed directly (if any) /// extra: [$extra:ident], /// // Extra function-tokens passed directly (if any) @@ -97,6 +97,9 @@ pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> p /// skip: [sin, cos], /// // Attributes passed as `attrs` for specific functions. For example, here the invocation /// // with `sinf` and that with `cosf` will both get `meta1` and `meta2`, but no others will. +/// // +/// // Note that `f16_enabled` and `f128_enabled` will always get emitted regardless of whether +/// // or not this is specified. /// attributes: [ /// #[meta1] /// #[meta2] @@ -255,16 +258,28 @@ fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result { - let meta = attrs - .iter() - .filter(|map| map.names.contains(&fn_name)) - .flat_map(|map| &map.meta); - quote! { attrs: [ #( #meta )* ] } - } - None => pm2::TokenStream::new(), - }; + let mut meta_fields = Vec::new(); + if let Some(attrs) = &input.attributes { + let meta_iter = attrs + .iter() + .filter(|map| map.names.contains(&fn_name)) + .flat_map(|map| &map.meta) + .map(|v| v.into_token_stream()); + + meta_fields.extend(meta_iter); + } + + // Always emit f16 and f128 meta so this doesn't need to be repeated everywhere + if func.rust_sig.args.contains(&Ty::F16) || func.rust_sig.returns.contains(&Ty::F16) { + let ts = quote! { cfg(f16_enabled) }; + meta_fields.push(ts); + } + if func.rust_sig.args.contains(&Ty::F128) || func.rust_sig.returns.contains(&Ty::F128) { + let ts = quote! { cfg(f128_enabled) }; + meta_fields.push(ts); + } + + let meta_field = quote! { attrs: [ #( #meta_fields ),* ], }; // Prepare extra in an `extra: ...` field, running the replacer let extra_field = match input.extra.clone() { diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs index 2eaba04f4c6..0aa417f13c8 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs @@ -1,3 +1,5 @@ +#![feature(f16)] +#![feature(f128)] // `STATUS_DLL_NOT_FOUND` on i686 MinGW, not worth looking into. #![cfg(not(all(target_arch = "x86", target_os = "windows", target_env = "gnu")))] @@ -11,11 +13,11 @@ macro_rules! basic { RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, RustRet: $RustRet:ty, - attrs: [$($meta:meta)*] + attrs: [$($attr:meta),*], extra: [$($extra_tt:tt)*], fn_extra: $fn_extra:expr, ) => { - $(#[$meta])* + $(#[$attr])* mod $fn_name { #[allow(unused)] type FTy= $FTy; @@ -60,7 +62,9 @@ mod test_basic { macro_rules! basic_no_extra { ( fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], ) => { + $(#[$attr])* mod $fn_name {} }; } @@ -85,7 +89,9 @@ macro_rules! specified_types { fn_name: $fn_name:ident, RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, + attrs: [$($attr:meta),*], ) => { + $(#[$attr])* mod $fn_name { #[allow(unused)] type RustFnTy = $RustFn; diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index b9c39334c14..06997cd3621 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -18,9 +18,11 @@ struct MuslExtra { macro_rules! musl_rand_benches { ( fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], fn_extra: $skip_on_i586:expr, ) => { paste::paste! { + $(#[$attr])* fn [< musl_bench_ $fn_name >](c: &mut Criterion) { type Op = libm_test::op::$fn_name::Routine; @@ -113,9 +115,11 @@ libm_macros::for_each_function! { macro_rules! run_callback { ( fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], extra: [$criterion:ident], ) => { paste::paste! { + $(#[$attr])* [< musl_bench_ $fn_name >](&mut $criterion) } }; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index fdba0357f7f..97907b2a160 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(f16_enabled, feature(f16))] +#![cfg_attr(f128_enabled, feature(f128))] #![allow(clippy::unusual_byte_groupings)] // sometimes we group by sign_exp_sig pub mod domain; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 28df916bd61..edb4cb962dc 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -50,9 +50,11 @@ macro_rules! impl_mp_op { ( fn_name: $fn_name:ident, RustFn: fn($_fty:ty,) -> $_ret:ty, + attrs: [$($attr:meta),*], fn_extra: $fn_name_normalized:expr, ) => { paste::paste! { + $(#[$attr])* impl MpOp for crate::op::$fn_name::Routine { type MpTy = MpFloat; @@ -72,9 +74,11 @@ macro_rules! impl_mp_op { ( fn_name: $fn_name:ident, RustFn: fn($_fty:ty, $_fty2:ty,) -> $_ret:ty, + attrs: [$($attr:meta),*], fn_extra: $fn_name_normalized:expr, ) => { paste::paste! { + $(#[$attr])* impl MpOp for crate::op::$fn_name::Routine { type MpTy = (MpFloat, MpFloat); @@ -95,9 +99,11 @@ macro_rules! impl_mp_op { ( fn_name: $fn_name:ident, RustFn: fn($_fty:ty, $_fty2:ty, $_fty3:ty,) -> $_ret:ty, + attrs: [$($attr:meta),*], fn_extra: $fn_name_normalized:expr, ) => { paste::paste! { + $(#[$attr])* impl MpOp for crate::op::$fn_name::Routine { type MpTy = (MpFloat, MpFloat, MpFloat); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index e58c2890362..ee61eb0b840 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -112,8 +112,11 @@ macro_rules! do_thing { RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, RustRet: $RustRet:ty, + attrs: [$($attr:meta),*], + ) => { paste::paste! { + $(#[$attr])* pub mod $fn_name { use super::*; pub struct Routine; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs index 9f85d64244b..c23298686fa 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs @@ -8,6 +8,7 @@ use std::process::Command; macro_rules! callback { ( fn_name: $name:ident, + attrs: [$($attr:meta),*], extra: [$set:ident], ) => { let name = stringify!($name); diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 0022ee03c21..71f080ab18f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -15,11 +15,11 @@ use libm_test::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleC macro_rules! musl_rand_tests { ( fn_name: $fn_name:ident, - attrs: [$($meta:meta)*] + attrs: [$($attr:meta),*], ) => { paste::paste! { #[test] - $(#[$meta])* + $(#[$attr])* fn [< musl_random_ $fn_name >]() { test_one::(musl_math_sys::$fn_name); } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 4821f74461f..71ff2ff965f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -13,11 +13,11 @@ use libm_test::{ macro_rules! mp_rand_tests { ( fn_name: $fn_name:ident, - attrs: [$($meta:meta)*] + attrs: [$($attr:meta),*], ) => { paste::paste! { #[test] - $(#[$meta])* + $(#[$attr])* fn [< mp_random_ $fn_name >]() { test_one_random::(); } @@ -76,18 +76,18 @@ libm_macros::for_each_function! { macro_rules! mp_domain_tests { ( fn_name: $fn_name:ident, - attrs: [$($meta:meta)*] + attrs: [$($attr:meta),*], ) => { paste::paste! { #[test] - $(#[$meta])* + $(#[$attr])* fn [< mp_edge_case_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; domain_test_runner::(edge_cases::get_test_cases::); } #[test] - $(#[$meta])* + $(#[$attr])* fn [< mp_logspace_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; domain_test_runner::(domain_logspace::get_test_cases::); -- cgit 1.4.1-3-g733a5 From a277ec6954384a02be15c3ed6560e4fc9b0c8cfa Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 2 Jan 2025 10:19:54 +0000 Subject: Rename generic `abs` to `fabs` Using the same name as the routines themselves means this will correctly get picked up by the CI job looking for exhaustive tests. --- library/compiler-builtins/libm/src/math/fabs.rs | 2 +- library/compiler-builtins/libm/src/math/fabsf.rs | 2 +- library/compiler-builtins/libm/src/math/generic/abs.rs | 6 ------ library/compiler-builtins/libm/src/math/generic/fabs.rs | 6 ++++++ library/compiler-builtins/libm/src/math/generic/mod.rs | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/generic/abs.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fabs.rs diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 2163637e728..6687fdcc356 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -9,7 +9,7 @@ pub fn fabs(x: f64) -> f64 { args: x, } - super::generic::abs(x) + super::generic::fabs(x) } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index ac77c9201ad..99bb5b5f1c9 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -9,7 +9,7 @@ pub fn fabsf(x: f32) -> f32 { args: x, } - super::generic::abs(x) + super::generic::fabs(x) } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 diff --git a/library/compiler-builtins/libm/src/math/generic/abs.rs b/library/compiler-builtins/libm/src/math/generic/abs.rs deleted file mode 100644 index 2c9a43c1249..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/abs.rs +++ /dev/null @@ -1,6 +0,0 @@ -use super::super::Float; - -/// Absolute value. -pub fn abs(x: F) -> F { - x.abs() -} diff --git a/library/compiler-builtins/libm/src/math/generic/fabs.rs b/library/compiler-builtins/libm/src/math/generic/fabs.rs new file mode 100644 index 00000000000..f2c7f0f465b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fabs.rs @@ -0,0 +1,6 @@ +use super::super::Float; + +/// Absolute value. +pub fn fabs(x: F) -> F { + x.abs() +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 1ddd08f0eff..08524b685e2 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -1,5 +1,5 @@ -mod abs; mod copysign; +mod fabs; -pub use abs::abs; pub use copysign::copysign; +pub use fabs::fabs; -- cgit 1.4.1-3-g733a5 From b47d3cc2f8e0b364cbd1288be2e1a856dadc9ec0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 02:53:35 +0000 Subject: Shorten prefixes for float constants Change `SIGNIFICAND_*` to `SIG_*` and `EXPONENT_*` to `EXP_*`. This makes things more consistent with `libm`, and terseness is convenient here since there isn't anything to confuse. --- library/compiler-builtins/src/float/add.rs | 8 ++-- library/compiler-builtins/src/float/cmp.rs | 4 +- library/compiler-builtins/src/float/conv.rs | 46 +++++++++---------- library/compiler-builtins/src/float/div.rs | 10 ++-- library/compiler-builtins/src/float/extend.rs | 14 +++--- library/compiler-builtins/src/float/mod.rs | 53 ++++++++++------------ library/compiler-builtins/src/float/mul.rs | 14 +++--- library/compiler-builtins/src/float/trunc.rs | 40 ++++++++-------- library/compiler-builtins/testcrate/src/lib.rs | 34 +++++++------- .../compiler-builtins/testcrate/tests/float_pow.rs | 4 +- 10 files changed, 111 insertions(+), 116 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index ecb96264a18..743cc441b36 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -13,14 +13,14 @@ where let zero = F::Int::ZERO; let bits = F::BITS.cast(); - let significand_bits = F::SIGNIFICAND_BITS; - let max_exponent = F::EXPONENT_MAX; + let significand_bits = F::SIG_BITS; + let max_exponent = F::EXP_MAX; let implicit_bit = F::IMPLICIT_BIT; - let significand_mask = F::SIGNIFICAND_MASK; + let significand_mask = F::SIG_MASK; let sign_bit = F::SIGN_MASK as F::Int; let abs_mask = sign_bit - one; - let exponent_mask = F::EXPONENT_MASK; + let exponent_mask = F::EXP_MASK; let inf_rep = exponent_mask; let quiet_bit = implicit_bit >> 1; let qnan_rep = exponent_mask | quiet_bit; diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 8b97a0b5cce..b9b4d0114b7 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -38,7 +38,7 @@ fn cmp(a: F, b: F) -> Result { let sign_bit = F::SIGN_MASK as F::Int; let abs_mask = sign_bit - one; - let exponent_mask = F::EXPONENT_MASK; + let exponent_mask = F::EXP_MASK; let inf_rep = exponent_mask; let a_rep = a.to_bits(); @@ -87,7 +87,7 @@ fn unord(a: F, b: F) -> bool { let sign_bit = F::SIGN_MASK as F::Int; let abs_mask = sign_bit - one; - let exponent_mask = F::EXPONENT_MASK; + let exponent_mask = F::EXP_MASK; let inf_rep = exponent_mask; let a_rep = a.to_bits(); diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 4aea67c9152..40d304719cd 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -32,7 +32,7 @@ mod int_to_float { /// Usually 1 is subtracted from this function's result, so that a mantissa with the implicit /// bit set can be added back later. fn exp>>(n: u32) -> F::Int { - F::Int::cast_from(F::EXPONENT_BIAS - 1 + I::BITS - n) + F::Int::cast_from(F::EXP_BIAS - 1 + I::BITS - n) } /// Adjust a mantissa with dropped bits to perform correct rounding. @@ -54,17 +54,17 @@ mod int_to_float { /// value to cancel it out. fn repr(e: F::Int, m: F::Int) -> F::Int { // + rather than | so the mantissa can overflow into the exponent - (e << F::SIGNIFICAND_BITS) + m + (e << F::SIG_BITS) + m } /// Shift distance from a left-aligned integer to a smaller float. fn shift_f_lt_i() -> u32 { - (I::BITS - F::BITS) + F::EXPONENT_BITS + (I::BITS - F::BITS) + F::EXP_BITS } /// Shift distance from an integer with `n` leading zeros to a smaller float. fn shift_f_gt_i(n: u32) -> u32 { - F::SIGNIFICAND_BITS - I::BITS + 1 + n + F::SIG_BITS - I::BITS + 1 + n } /// Perform a signed operation as unsigned, then add the sign back. @@ -85,9 +85,9 @@ mod int_to_float { } let n = i.leading_zeros(); // Mantissa with implicit bit set (significant bits) - let m_base = (i << n) >> f32::EXPONENT_BITS; + let m_base = (i << n) >> f32::EXP_BITS; // Bits that will be dropped (insignificant bits) - let adj = (i << n) << (f32::SIGNIFICAND_BITS + 1); + let adj = (i << n) << (f32::SIG_BITS + 1); let m = m_adj::(m_base, adj); let e = exp::(n) - 1; repr::(e, m) @@ -116,7 +116,7 @@ mod int_to_float { let m = (i as u64) << (shift_f_gt_i::(n) - 64); let e = exp::(n) as u64 - 1; // High 64 bits of f128 representation. - let h = (e << (f128::SIGNIFICAND_BITS - 64)) + m; + let h = (e << (f128::SIG_BITS - 64)) + m; // Shift back to the high bits, the rest of the mantissa will always be 0. (h as u128) << 64 @@ -128,8 +128,8 @@ mod int_to_float { // Mantissa with implicit bit set let m_base: u32 = (i_m >> shift_f_lt_i::()) as u32; // The entire lower half of `i` will be truncated (masked portion), plus the - // next `EXPONENT_BITS` bits. - let adj = (i_m >> f32::EXPONENT_BITS | i_m & 0xFFFF) as u32; + // next `EXP_BITS` bits. + let adj = (i_m >> f32::EXP_BITS | i_m & 0xFFFF) as u32; let m = m_adj::(m_base, adj); let e = if i == 0 { 0 } else { exp::(n) - 1 }; repr::(e, m) @@ -141,8 +141,8 @@ mod int_to_float { } let n = i.leading_zeros(); // Mantissa with implicit bit set - let m_base = (i << n) >> f64::EXPONENT_BITS; - let adj = (i << n) << (f64::SIGNIFICAND_BITS + 1); + let m_base = (i << n) >> f64::EXP_BITS; + let adj = (i << n) << (f64::SIG_BITS + 1); let m = m_adj::(m_base, adj); let e = exp::(n) - 1; repr::(e, m) @@ -167,7 +167,7 @@ mod int_to_float { // Within the upper `F::BITS`, everything except for the signifcand // gets truncated - let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIGNIFICAND_BITS - 1)).cast(); + let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIG_BITS - 1)).cast(); // The entire rest of `i_m` gets truncated. Zero the upper `F::BITS` then just // check if it is nonzero. @@ -186,8 +186,8 @@ mod int_to_float { // Mantissa with implicit bit set let m_base: u64 = (i_m >> shift_f_lt_i::()) as u64; // The entire lower half of `i` will be truncated (masked portion), plus the - // next `EXPONENT_BITS` bits. - let adj = (i_m >> f64::EXPONENT_BITS | i_m & 0xFFFF_FFFF) as u64; + // next `EXP_BITS` bits. + let adj = (i_m >> f64::EXP_BITS | i_m & 0xFFFF_FFFF) as u64; let m = m_adj::(m_base, adj); let e = if i == 0 { 0 } else { exp::(n) - 1 }; repr::(e, m) @@ -200,8 +200,8 @@ mod int_to_float { } let n = i.leading_zeros(); // Mantissa with implicit bit set - let m_base = (i << n) >> f128::EXPONENT_BITS; - let adj = (i << n) << (f128::SIGNIFICAND_BITS + 1); + let m_base = (i << n) >> f128::EXP_BITS; + let adj = (i << n) << (f128::SIG_BITS + 1); let m = m_adj::(m_base, adj); let e = exp::(n) - 1; repr::(e, m) @@ -362,29 +362,29 @@ where F::Int: CastFrom, u32: CastFrom, { - let int_max_exp = F::EXPONENT_BIAS + I::MAX.ilog2() + 1; - let foobar = F::EXPONENT_BIAS + I::UnsignedInt::BITS - 1; + let int_max_exp = F::EXP_BIAS + I::MAX.ilog2() + 1; + let foobar = F::EXP_BIAS + I::UnsignedInt::BITS - 1; if fbits < F::ONE.to_bits() { // < 0 gets rounded to 0 I::ZERO - } else if fbits < F::Int::cast_from(int_max_exp) << F::SIGNIFICAND_BITS { + } else if fbits < F::Int::cast_from(int_max_exp) << F::SIG_BITS { // >= 1, < integer max let m_base = if I::UnsignedInt::BITS >= F::Int::BITS { - I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIGNIFICAND_BITS - 1) + I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIG_BITS - 1) } else { - I::UnsignedInt::cast_from(fbits >> (F::SIGNIFICAND_BITS - I::BITS + 1)) + I::UnsignedInt::cast_from(fbits >> (F::SIG_BITS - I::BITS + 1)) }; // Set the implicit 1-bit. let m: I::UnsignedInt = I::UnsignedInt::ONE << (I::BITS - 1) | m_base; // Shift based on the exponent and bias. - let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIGNIFICAND_BITS); + let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIG_BITS); let unsigned = m >> s; map_inbounds(I::from_unsigned(unsigned)) - } else if fbits <= F::EXPONENT_MASK { + } else if fbits <= F::EXP_MASK { // >= max (incl. inf) out_of_bounds() } else { diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 4b3f97c3575..c211fabadda 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -105,16 +105,16 @@ where let hw = F::BITS / 2; let lo_mask = F::Int::MAX >> hw; - let significand_bits = F::SIGNIFICAND_BITS; + let significand_bits = F::SIG_BITS; // Saturated exponent, representing infinity - let exponent_sat: F::Int = F::EXPONENT_MAX.cast(); + let exponent_sat: F::Int = F::EXP_MAX.cast(); - let exponent_bias = F::EXPONENT_BIAS; + let exponent_bias = F::EXP_BIAS; let implicit_bit = F::IMPLICIT_BIT; - let significand_mask = F::SIGNIFICAND_MASK; + let significand_mask = F::SIG_MASK; let sign_bit = F::SIGN_MASK; let abs_mask = sign_bit - one; - let exponent_mask = F::EXPONENT_MASK; + let exponent_mask = F::EXP_MASK; let inf_rep = exponent_mask; let quiet_bit = implicit_bit >> 1; let qnan_rep = exponent_mask | quiet_bit; diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 2ec79070cb8..a5d69864b1f 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -15,19 +15,19 @@ where let src_zero = F::Int::ZERO; let src_one = F::Int::ONE; let src_bits = F::BITS; - let src_sign_bits = F::SIGNIFICAND_BITS; - let src_exp_bias = F::EXPONENT_BIAS; + let src_sign_bits = F::SIG_BITS; + let src_exp_bias = F::EXP_BIAS; let src_min_normal = F::IMPLICIT_BIT; - let src_infinity = F::EXPONENT_MASK; + let src_infinity = F::EXP_MASK; let src_sign_mask = F::SIGN_MASK as F::Int; let src_abs_mask = src_sign_mask - src_one; - let src_qnan = F::SIGNIFICAND_MASK; + let src_qnan = F::SIG_MASK; let src_nan_code = src_qnan - src_one; let dst_bits = R::BITS; - let dst_sign_bits = R::SIGNIFICAND_BITS; - let dst_inf_exp = R::EXPONENT_MAX; - let dst_exp_bias = R::EXPONENT_BIAS; + let dst_sign_bits = R::SIG_BITS; + let dst_inf_exp = R::EXP_MAX; + let dst_exp_bias = R::EXP_BIAS; let dst_min_normal = R::IMPLICIT_BIT; let sign_bits_delta = dst_sign_bits - src_sign_bits; diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index af83986447e..9ba447f97e3 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -42,32 +42,32 @@ pub(crate) trait Float: const ZERO: Self; const ONE: Self; - /// The bitwidth of the float type + /// The bitwidth of the float type. const BITS: u32; - /// The bitwidth of the significand - const SIGNIFICAND_BITS: u32; + /// The bitwidth of the significand. + const SIG_BITS: u32; - /// The bitwidth of the exponent - const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + /// The bitwidth of the exponent. + const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; /// The saturated value of the exponent (infinite representation), in the rightmost postiion. - const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; + const EXP_MAX: u32 = (1 << Self::EXP_BITS) - 1; - /// The exponent bias value - const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; + /// The exponent bias value. + const EXP_BIAS: u32 = Self::EXP_MAX >> 1; - /// A mask for the sign bit + /// A mask for the sign bit. const SIGN_MASK: Self::Int; - /// A mask for the significand - const SIGNIFICAND_MASK: Self::Int; + /// A mask for the significand. + const SIG_MASK: Self::Int; - /// The implicit bit of the float format + /// The implicit bit of the float format. const IMPLICIT_BIT: Self::Int; - /// A mask for the exponent - const EXPONENT_MASK: Self::Int; + /// A mask for the exponent. + const EXP_MASK: Self::Int; /// Returns `self` transmuted to `Self::Int` fn to_bits(self) -> Self::Int; @@ -122,12 +122,12 @@ macro_rules! float_impl { const ONE: Self = 1.0; const BITS: u32 = $bits; - const SIGNIFICAND_BITS: u32 = $significand_bits; + const SIG_BITS: u32 = $significand_bits; const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; - const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; + const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); fn to_bits(self) -> Self::Int { self.to_bits() @@ -142,8 +142,7 @@ macro_rules! float_impl { // necessary builtin (__unordtf2) to test whether `f128` is NaN. // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin // x is NaN if all the bits of the exponent are set and the significand is non-0 - x.to_bits() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK - && x.to_bits() & $ty::SIGNIFICAND_MASK != 0 + x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 } #[cfg(not(feature = "mangled-names"))] fn is_nan(x: $ty) -> bool { @@ -159,10 +158,10 @@ macro_rules! float_impl { self.is_sign_negative() } fn exp(self) -> Self::ExpInt { - ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt + ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt } fn frac(self) -> Self::Int { - self.to_bits() & Self::SIGNIFICAND_MASK + self.to_bits() & Self::SIG_MASK } fn imp_frac(self) -> Self::Int { self.frac() | Self::IMPLICIT_BIT @@ -173,21 +172,19 @@ macro_rules! float_impl { fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { Self::from_bits( ((negative as Self::Int) << (Self::BITS - 1)) - | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) - | (significand & Self::SIGNIFICAND_MASK), + | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) + | (significand & Self::SIG_MASK), ) } fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand - .leading_zeros() - .wrapping_sub(Self::EXPONENT_BITS); + let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); ( 1i32.wrapping_sub(shift as i32), significand << shift as Self::Int, ) } fn is_subnormal(self) -> bool { - (self.to_bits() & Self::EXPONENT_MASK) == Self::Int::ZERO + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO } } }; diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 77a271d65a9..62895293abb 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -13,20 +13,20 @@ where let zero = F::Int::ZERO; let bits = F::BITS; - let significand_bits = F::SIGNIFICAND_BITS; - let max_exponent = F::EXPONENT_MAX; + let significand_bits = F::SIG_BITS; + let max_exponent = F::EXP_MAX; - let exponent_bias = F::EXPONENT_BIAS; + let exponent_bias = F::EXP_BIAS; let implicit_bit = F::IMPLICIT_BIT; - let significand_mask = F::SIGNIFICAND_MASK; - let sign_bit = F::SIGN_MASK as F::Int; + let significand_mask = F::SIG_MASK; + let sign_bit = F::SIGN_MASK; let abs_mask = sign_bit - one; - let exponent_mask = F::EXPONENT_MASK; + let exponent_mask = F::EXP_MASK; let inf_rep = exponent_mask; let quiet_bit = implicit_bit >> 1; let qnan_rep = exponent_mask | quiet_bit; - let exponent_bits = F::EXPONENT_BITS; + let exponent_bits = F::EXP_BITS; let a_rep = a.to_bits(); let b_rep = b.to_bits(); diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 6fe44f50b94..c95e9c198e3 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -14,33 +14,33 @@ where let src_zero = F::Int::ZERO; let src_one = F::Int::ONE; let src_bits = F::BITS; - let src_exp_bias = F::EXPONENT_BIAS; + let src_exp_bias = F::EXP_BIAS; let src_min_normal = F::IMPLICIT_BIT; - let src_significand_mask = F::SIGNIFICAND_MASK; - let src_infinity = F::EXPONENT_MASK; + let src_significand_mask = F::SIG_MASK; + let src_infinity = F::EXP_MASK; let src_sign_mask = F::SIGN_MASK; let src_abs_mask = src_sign_mask - src_one; - let round_mask = (src_one << (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)) - src_one; - let halfway = src_one << (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS - 1); - let src_qnan = src_one << (F::SIGNIFICAND_BITS - 1); + let round_mask = (src_one << (F::SIG_BITS - R::SIG_BITS)) - src_one; + let halfway = src_one << (F::SIG_BITS - R::SIG_BITS - 1); + let src_qnan = src_one << (F::SIG_BITS - 1); let src_nan_code = src_qnan - src_one; let dst_zero = R::Int::ZERO; let dst_one = R::Int::ONE; let dst_bits = R::BITS; - let dst_inf_exp = R::EXPONENT_MAX; - let dst_exp_bias = R::EXPONENT_BIAS; + let dst_inf_exp = R::EXP_MAX; + let dst_exp_bias = R::EXP_BIAS; let underflow_exponent: F::Int = (src_exp_bias + 1 - dst_exp_bias).cast(); let overflow_exponent: F::Int = (src_exp_bias + dst_inf_exp - dst_exp_bias).cast(); - let underflow: F::Int = underflow_exponent << F::SIGNIFICAND_BITS; - let overflow: F::Int = overflow_exponent << F::SIGNIFICAND_BITS; + let underflow: F::Int = underflow_exponent << F::SIG_BITS; + let overflow: F::Int = overflow_exponent << F::SIG_BITS; - let dst_qnan = R::Int::ONE << (R::SIGNIFICAND_BITS - 1); + let dst_qnan = R::Int::ONE << (R::SIG_BITS - 1); let dst_nan_code = dst_qnan - dst_one; - let sign_bits_delta = F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS; + let sign_bits_delta = F::SIG_BITS - R::SIG_BITS; // Break a into a sign and representation of the absolute value. let a_abs = a.to_bits() & src_abs_mask; let sign = a.to_bits() & src_sign_mask; @@ -53,7 +53,7 @@ where abs_result = (a_abs >> sign_bits_delta).cast(); // Cast before shifting to prevent overflow. let bias_diff: R::Int = src_exp_bias.wrapping_sub(dst_exp_bias).cast(); - let tmp = bias_diff << R::SIGNIFICAND_BITS; + let tmp = bias_diff << R::SIG_BITS; abs_result = abs_result.wrapping_sub(tmp); let round_bits = a_abs & round_mask; @@ -70,26 +70,25 @@ where // bit and inserting the (truncated) trailing NaN field. // Cast before shifting to prevent overflow. let dst_inf_exp: R::Int = dst_inf_exp.cast(); - abs_result = dst_inf_exp << R::SIGNIFICAND_BITS; + abs_result = dst_inf_exp << R::SIG_BITS; abs_result |= dst_qnan; - abs_result |= dst_nan_code - & ((a_abs & src_nan_code) >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast(); + abs_result |= dst_nan_code & ((a_abs & src_nan_code) >> (F::SIG_BITS - R::SIG_BITS)).cast(); } else if a_abs >= overflow { // a overflows to infinity. // Cast before shifting to prevent overflow. let dst_inf_exp: R::Int = dst_inf_exp.cast(); - abs_result = dst_inf_exp << R::SIGNIFICAND_BITS; + abs_result = dst_inf_exp << R::SIG_BITS; } else { // a underflows on conversion to the destination type or is an exact // zero. The result may be a denormal or zero. Extract the exponent // to get the shift amount for the denormalization. - let a_exp: u32 = (a_abs >> F::SIGNIFICAND_BITS).cast(); + let a_exp: u32 = (a_abs >> F::SIG_BITS).cast(); let shift = src_exp_bias - dst_exp_bias - a_exp + 1; let significand = (a.to_bits() & src_significand_mask) | src_min_normal; // Right shift by the denormalization amount with sticky. - if shift > F::SIGNIFICAND_BITS { + if shift > F::SIG_BITS { abs_result = dst_zero; } else { let sticky = if (significand << (src_bits - shift)) != src_zero { @@ -98,8 +97,7 @@ where src_zero }; let denormalized_significand: F::Int = significand >> shift | sticky; - abs_result = - (denormalized_significand >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast(); + abs_result = (denormalized_significand >> (F::SIG_BITS - R::SIG_BITS)).cast(); let round_bits = denormalized_significand & round_mask; // Round to nearest if round_bits > halfway { diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 4154e0fb34f..894c2782a45 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -178,18 +178,18 @@ fn fuzz_float_step(rng: &mut Xoshiro128StarStar, f: &mut F) { let sign = (rng32 & 1) != 0; // exponent fuzzing. Only 4 bits for the selector needed. - let ones = (F::Int::ONE << F::EXPONENT_BITS) - F::Int::ONE; - let r0 = (rng32 >> 1) % F::EXPONENT_BITS; - let r1 = (rng32 >> 5) % F::EXPONENT_BITS; + let ones = (F::Int::ONE << F::EXP_BITS) - F::Int::ONE; + let r0 = (rng32 >> 1) % F::EXP_BITS; + let r1 = (rng32 >> 5) % F::EXP_BITS; // custom rotate shift. Note that `F::Int` is unsigned, so we can shift right without smearing // the sign bit. let mask = if r1 == 0 { ones.wrapping_shr(r0) } else { let tmp = ones.wrapping_shr(r0); - (tmp.wrapping_shl(r1) | tmp.wrapping_shr(F::EXPONENT_BITS - r1)) & ones + (tmp.wrapping_shl(r1) | tmp.wrapping_shr(F::EXP_BITS - r1)) & ones }; - let mut exp = (f.to_bits() & F::EXPONENT_MASK) >> F::SIGNIFICAND_BITS; + let mut exp = (f.to_bits() & F::EXP_MASK) >> F::SIG_BITS; match (rng32 >> 9) % 4 { 0 => exp |= mask, 1 => exp &= mask, @@ -197,9 +197,9 @@ fn fuzz_float_step(rng: &mut Xoshiro128StarStar, f: &mut F) { } // significand fuzzing - let mut sig = f.to_bits() & F::SIGNIFICAND_MASK; + let mut sig = f.to_bits() & F::SIG_MASK; fuzz_step(rng, &mut sig); - sig &= F::SIGNIFICAND_MASK; + sig &= F::SIG_MASK; *f = F::from_parts(sign, exp, sig); } @@ -209,22 +209,22 @@ macro_rules! float_edge_cases { for exponent in [ F::Int::ZERO, F::Int::ONE, - F::Int::ONE << (F::EXPONENT_BITS / 2), - (F::Int::ONE << (F::EXPONENT_BITS - 1)) - F::Int::ONE, - F::Int::ONE << (F::EXPONENT_BITS - 1), - (F::Int::ONE << (F::EXPONENT_BITS - 1)) + F::Int::ONE, - (F::Int::ONE << F::EXPONENT_BITS) - F::Int::ONE, + F::Int::ONE << (F::EXP_BITS / 2), + (F::Int::ONE << (F::EXP_BITS - 1)) - F::Int::ONE, + F::Int::ONE << (F::EXP_BITS - 1), + (F::Int::ONE << (F::EXP_BITS - 1)) + F::Int::ONE, + (F::Int::ONE << F::EXP_BITS) - F::Int::ONE, ] .iter() { for significand in [ F::Int::ZERO, F::Int::ONE, - F::Int::ONE << (F::SIGNIFICAND_BITS / 2), - (F::Int::ONE << (F::SIGNIFICAND_BITS - 1)) - F::Int::ONE, - F::Int::ONE << (F::SIGNIFICAND_BITS - 1), - (F::Int::ONE << (F::SIGNIFICAND_BITS - 1)) + F::Int::ONE, - (F::Int::ONE << F::SIGNIFICAND_BITS) - F::Int::ONE, + F::Int::ONE << (F::SIG_BITS / 2), + (F::Int::ONE << (F::SIG_BITS - 1)) - F::Int::ONE, + F::Int::ONE << (F::SIG_BITS - 1), + (F::Int::ONE << (F::SIG_BITS - 1)) + F::Int::ONE, + (F::Int::ONE << F::SIG_BITS) - F::Int::ONE, ] .iter() { diff --git a/library/compiler-builtins/testcrate/tests/float_pow.rs b/library/compiler-builtins/testcrate/tests/float_pow.rs index d85ee99dfd3..8d86392f535 100644 --- a/library/compiler-builtins/testcrate/tests/float_pow.rs +++ b/library/compiler-builtins/testcrate/tests/float_pow.rs @@ -19,8 +19,8 @@ macro_rules! pow { use compiler_builtins::float::Float; fuzz_float_2(N, |x: $f, y: $f| { if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) { - let n = y.to_bits() & !<$f as Float>::SIGNIFICAND_MASK; - let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS; + let n = y.to_bits() & !<$f as Float>::SIG_MASK; + let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIG_BITS; let n = n as i32; let tmp0: $f = x.powi(n); let tmp1: $f = $fn(x, n); -- cgit 1.4.1-3-g733a5 From 7065cd0420e3932071e87f23c2b51d1c29179f81 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 02:56:34 +0000 Subject: Rename `EXP_MAX` to `EXP_SAT` "Maximum" is technically correct here with regards to what the bitpattern can represent, but it is not the numeric maximum value of the exponent which has a relationship with the bias. So, replace the maximum terminology with "saturated" to indicate it only means the full bitpattern. This change is more relevant to `libm` than `compiler-builtins`. --- library/compiler-builtins/src/float/add.rs | 2 +- library/compiler-builtins/src/float/div.rs | 2 +- library/compiler-builtins/src/float/extend.rs | 2 +- library/compiler-builtins/src/float/mod.rs | 9 ++++++--- library/compiler-builtins/src/float/mul.rs | 2 +- library/compiler-builtins/src/float/trunc.rs | 2 +- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 743cc441b36..004ea3ebca8 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -14,7 +14,7 @@ where let bits = F::BITS.cast(); let significand_bits = F::SIG_BITS; - let max_exponent = F::EXP_MAX; + let max_exponent = F::EXP_SAT; let implicit_bit = F::IMPLICIT_BIT; let significand_mask = F::SIG_MASK; diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index c211fabadda..a461397ea90 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -107,7 +107,7 @@ where let significand_bits = F::SIG_BITS; // Saturated exponent, representing infinity - let exponent_sat: F::Int = F::EXP_MAX.cast(); + let exponent_sat: F::Int = F::EXP_SAT.cast(); let exponent_bias = F::EXP_BIAS; let implicit_bit = F::IMPLICIT_BIT; diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index a5d69864b1f..a1a9b9720a8 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -26,7 +26,7 @@ where let dst_bits = R::BITS; let dst_sign_bits = R::SIG_BITS; - let dst_inf_exp = R::EXP_MAX; + let dst_inf_exp = R::EXP_SAT; let dst_exp_bias = R::EXP_BIAS; let dst_min_normal = R::IMPLICIT_BIT; diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 9ba447f97e3..6ee55950e18 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -51,11 +51,14 @@ pub(crate) trait Float: /// The bitwidth of the exponent. const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; - /// The saturated value of the exponent (infinite representation), in the rightmost postiion. - const EXP_MAX: u32 = (1 << Self::EXP_BITS) - 1; + /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite + /// representation. + /// + /// This is in the rightmost position, use `EXP_MASK` for the shifted value. + const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; /// The exponent bias value. - const EXP_BIAS: u32 = Self::EXP_MAX >> 1; + const EXP_BIAS: u32 = Self::EXP_SAT >> 1; /// A mask for the sign bit. const SIGN_MASK: Self::Int; diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 62895293abb..f0f261a2844 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -14,7 +14,7 @@ where let bits = F::BITS; let significand_bits = F::SIG_BITS; - let max_exponent = F::EXP_MAX; + let max_exponent = F::EXP_SAT; let exponent_bias = F::EXP_BIAS; diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index c95e9c198e3..5efeac98e44 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -29,7 +29,7 @@ where let dst_zero = R::Int::ZERO; let dst_one = R::Int::ONE; let dst_bits = R::BITS; - let dst_inf_exp = R::EXP_MAX; + let dst_inf_exp = R::EXP_SAT; let dst_exp_bias = R::EXP_BIAS; let underflow_exponent: F::Int = (src_exp_bias + 1 - dst_exp_bias).cast(); -- cgit 1.4.1-3-g733a5 From 5d60d2a905179a021b90928729e2cc1c16374884 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 03:09:07 +0000 Subject: Fix new `clippy::precedence` errors `clippy::precedence` now applies to bitwise `&` and `|`. Update with all of its suggestions, including a separate elided lifetime suggestion. --- library/compiler-builtins/examples/intrinsics.rs | 2 +- library/compiler-builtins/src/float/add.rs | 8 ++++---- library/compiler-builtins/src/float/conv.rs | 8 ++++---- library/compiler-builtins/src/float/div.rs | 2 +- library/compiler-builtins/src/float/mul.rs | 2 +- library/compiler-builtins/src/float/trunc.rs | 2 +- library/compiler-builtins/src/mem/mod.rs | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index ef7a3d43030..e13c0fb1fa2 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -640,7 +640,7 @@ fn run() { fn something_with_a_dtor(f: &dyn Fn()) { struct A<'a>(&'a (dyn Fn() + 'a)); - impl<'a> Drop for A<'a> { + impl Drop for A<'_> { fn drop(&mut self) { (self.0)(); } diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 004ea3ebca8..ef04ddc165c 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -143,9 +143,9 @@ where // If the addition carried up, we need to right-shift the result and // adjust the exponent: - if a_significand & implicit_bit << 4 != MinInt::ZERO { + if a_significand & (implicit_bit << 4) != MinInt::ZERO { let sticky = F::Int::from_bool(a_significand & one != MinInt::ZERO); - a_significand = a_significand >> 1 | sticky; + a_significand = (a_significand >> 1) | sticky; a_exponent += 1; } } @@ -161,7 +161,7 @@ where let shift = (1 - a_exponent).cast(); let sticky = F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != MinInt::ZERO); - a_significand = a_significand >> shift.cast() | sticky; + a_significand = (a_significand >> shift.cast()) | sticky; a_exponent = 0; } @@ -170,7 +170,7 @@ where let round_guard_sticky: i32 = a_significand_i32 & 0x7; // Shift the significand into place, and mask off the implicit bit. - let mut result = a_significand >> 3 & significand_mask; + let mut result = (a_significand >> 3) & significand_mask; // Insert the exponent and sign. result |= a_exponent.cast() << significand_bits; diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 40d304719cd..83a181c37d4 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -42,7 +42,7 @@ mod int_to_float { fn m_adj(m_base: F::Int, dropped_bits: F::Int) -> F::Int { // Branchlessly extract a `1` if rounding up should happen, 0 otherwise // This accounts for rounding to even. - let adj = (dropped_bits - (dropped_bits >> (F::BITS - 1) & !m_base)) >> (F::BITS - 1); + let adj = (dropped_bits - ((dropped_bits >> (F::BITS - 1)) & !m_base)) >> (F::BITS - 1); // Add one when we need to round up. Break ties to even. m_base + adj @@ -129,7 +129,7 @@ mod int_to_float { let m_base: u32 = (i_m >> shift_f_lt_i::()) as u32; // The entire lower half of `i` will be truncated (masked portion), plus the // next `EXP_BITS` bits. - let adj = (i_m >> f32::EXP_BITS | i_m & 0xFFFF) as u32; + let adj = ((i_m >> f32::EXP_BITS) | i_m & 0xFFFF) as u32; let m = m_adj::(m_base, adj); let e = if i == 0 { 0 } else { exp::(n) - 1 }; repr::(e, m) @@ -187,7 +187,7 @@ mod int_to_float { let m_base: u64 = (i_m >> shift_f_lt_i::()) as u64; // The entire lower half of `i` will be truncated (masked portion), plus the // next `EXP_BITS` bits. - let adj = (i_m >> f64::EXP_BITS | i_m & 0xFFFF_FFFF) as u64; + let adj = ((i_m >> f64::EXP_BITS) | i_m & 0xFFFF_FFFF) as u64; let m = m_adj::(m_base, adj); let e = if i == 0 { 0 } else { exp::(n) - 1 }; repr::(e, m) @@ -377,7 +377,7 @@ where }; // Set the implicit 1-bit. - let m: I::UnsignedInt = I::UnsignedInt::ONE << (I::BITS - 1) | m_base; + let m: I::UnsignedInt = (I::UnsignedInt::ONE << (I::BITS - 1)) | m_base; // Shift based on the exponent and bias. let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIG_BITS); diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index a461397ea90..21c757dd639 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -261,7 +261,7 @@ where let c_hw = c_hw::(); // Check that the top bit is set, i.e. value is within `[1, 2)`. - debug_assert!(b_uq1_hw & one_hw << (HalfRep::::BITS - 1) > zero_hw); + debug_assert!(b_uq1_hw & (one_hw << (HalfRep::::BITS - 1)) > zero_hw); // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, // so x0 fits to UQ0.HW without wrapping. diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index f0f261a2844..58636cb5ebe 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -154,7 +154,7 @@ where // not all zero so that the result is correctly rounded below. let sticky = product_low << (bits - shift) != zero; product_low = - product_high << (bits - shift) | product_low >> shift | (sticky as u32).cast(); + (product_high << (bits - shift)) | (product_low >> shift) | (sticky as u32).cast(); product_high >>= shift; } else { // Result is normal before rounding; insert the exponent. diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 5efeac98e44..3759aa7dc43 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -96,7 +96,7 @@ where } else { src_zero }; - let denormalized_significand: F::Int = significand >> shift | sticky; + let denormalized_significand: F::Int = (significand >> shift) | sticky; abs_result = (denormalized_significand >> (F::SIG_BITS - R::SIG_BITS)).cast(); let round_bits = denormalized_significand & round_mask; // Round to nearest diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index d0ff501585b..f10439e2d3f 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -111,7 +111,7 @@ where let mut x = T::from(c); let mut i = 1; while i < mem::size_of::() { - x = x << 8 | T::from(c); + x = (x << 8) | T::from(c); i += 1; } -- cgit 1.4.1-3-g733a5 From 14e6d05dfba4ec4cf69d347f4510640ff97419bc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 12:04:45 +0000 Subject: Use intrinsics for `abs` and `copysign` when available Currently our implementations for `abs` and `copysign` are defined on the trait, and these are then called from `generic`. It would be better to call core's `.abs()` / `.copysign(y)`, but we can't do this in the generic because calling the standalone function could become recursive (`fabsf` becomes `intrinsics::fabsf32`, that may lower to a call to `fabsf`). Change this so the traits uses the call to `core` if available, falling back to a call to the standalone generic function. In practice the recursion isn't likely to be a problem since LLVM probably always lowers `abs`/`copysign` to assembly, but this pattern should be more correct for functions that we will add in the future (e.g. `fma`). This should eventually be followed by a change to call the trait methods rather than `fabs`/`copysign` directly. --- .../libm/crates/libm-test/src/f8_impl.rs | 8 +++++ .../libm/src/math/generic/copysign.rs | 2 +- .../libm/src/math/generic/fabs.rs | 3 +- library/compiler-builtins/libm/src/math/mod.rs | 9 +++++- .../libm/src/math/support/float_traits.rs | 37 ++++++++++++++-------- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index babcc6357a4..d378863f2fd 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -70,6 +70,14 @@ impl Float for f8 { Self(a) } + fn abs(self) -> Self { + libm::generic::fabs(self) + } + + fn copysign(self, other: Self) -> Self { + libm::generic::copysign(self, other) + } + fn normalize(_significand: Self::Int) -> (i32, Self::Int) { unimplemented!() } diff --git a/library/compiler-builtins/libm/src/math/generic/copysign.rs b/library/compiler-builtins/libm/src/math/generic/copysign.rs index d6b81489193..04864a35905 100644 --- a/library/compiler-builtins/libm/src/math/generic/copysign.rs +++ b/library/compiler-builtins/libm/src/math/generic/copysign.rs @@ -5,6 +5,6 @@ pub fn copysign(x: F, y: F) -> F { let mut ux = x.to_bits(); let uy = y.to_bits(); ux &= !F::SIGN_MASK; - ux |= uy & (F::SIGN_MASK); + ux |= uy & F::SIGN_MASK; F::from_bits(ux) } diff --git a/library/compiler-builtins/libm/src/math/generic/fabs.rs b/library/compiler-builtins/libm/src/math/generic/fabs.rs index f2c7f0f465b..75b473107c6 100644 --- a/library/compiler-builtins/libm/src/math/generic/fabs.rs +++ b/library/compiler-builtins/libm/src/math/generic/fabs.rs @@ -2,5 +2,6 @@ use super::super::Float; /// Absolute value. pub fn fabs(x: F) -> F { - x.abs() + let abs_mask = !F::SIGN_MASK; + F::from_bits(x.to_bits() & abs_mask) } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index ba199522816..e7b21de6762 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -83,11 +83,18 @@ pub mod support; #[cfg(not(feature = "unstable-test-support"))] mod support; +cfg_if! { + if #[cfg(feature = "unstable-test-support")] { + pub mod generic; + } else { + mod generic; + } +} + // Private modules mod arch; mod expo2; mod fenv; -mod generic; mod k_cos; mod k_cosf; mod k_expo2; diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index e64640a0d15..3b5be4fa3d3 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -123,23 +123,14 @@ pub trait Float: ) } - fn abs(self) -> Self { - let abs_mask = !Self::SIGN_MASK; - Self::from_bits(self.to_bits() & abs_mask) - } + fn abs(self) -> Self; + + /// Returns a number composed of the magnitude of self and the sign of sign. + fn copysign(self, other: Self) -> Self; /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); - /// Returns a number composed of the magnitude of self and the sign of sign. - fn copysign(self, other: Self) -> Self { - let mut x = self.to_bits(); - let y = other.to_bits(); - x &= !Self::SIGN_MASK; - x |= y & Self::SIGN_MASK; - Self::from_bits(x) - } - /// Returns a number that represents the sign of self. fn signum(self) -> Self { if self.is_nan() { self } else { Self::ONE.copysign(self) } @@ -206,6 +197,26 @@ macro_rules! float_impl { fn from_bits(a: Self::Int) -> Self { Self::from_bits(a) } + fn abs(self) -> Self { + cfg_if! { + // FIXME(msrv): `abs` is available in `core` starting with 1.85. + if #[cfg(feature = "unstable-intrinsics")] { + self.abs() + } else { + super::super::generic::fabs(self) + } + } + } + fn copysign(self, other: Self) -> Self { + cfg_if! { + // FIXME(msrv): `copysign` is available in `core` starting with 1.85. + if #[cfg(feature = "unstable-intrinsics")] { + self.copysign(other) + } else { + super::super::generic::copysign(self, other) + } + } + } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) -- cgit 1.4.1-3-g733a5 From 3030182c6692c6007c126d933cf57f5d96124205 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 22:26:39 +0000 Subject: Change to exhaustive matching for `default_ulp` Make it more obvious what the expected ULP for a given routine is. This also narrows ULP to 0 for operations that require exact results. --- .../libm/crates/libm-test/src/precision.rs | 130 ++++++++++++++------- 1 file changed, 91 insertions(+), 39 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 6d4561c4376..89b66146c43 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -4,57 +4,109 @@ use core::f32; use CheckBasis::{Mpfr, Musl}; -use Identifier as Id; +use {BaseName as Bn, Identifier as Id}; use crate::{BaseName, CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; /// Type implementing [`IgnoreCase`]. pub struct SpecialCase; -/// Default ULP allowed to differ from musl (note that musl itself may not be accurate). -const MUSL_DEFAULT_ULP: u32 = 2; - -/// Default ULP allowed to differ from multiprecision (i.e. infinite) results. -const MP_DEFAULT_ULP: u32 = 1; - /// ULP allowed to differ from the results returned by a test basis. /// /// Note that these results were obtained using 400M rounds of random inputs, which /// is not a value used by default. pub fn default_ulp(ctx: &CheckCtx) -> u32 { - match (&ctx.basis, ctx.fn_ident) { - // Overrides that apply to either basis - // FMA is expected to be infinite precision. - (_, Id::Fma | Id::Fmaf) => 0, - (_, Id::J0 | Id::J0f | Id::J1 | Id::J1f | Id::Y0 | Id::Y0f | Id::Y1 | Id::Y1f) => 800_000, - (_, Id::Jn | Id::Jnf | Id::Yn | Id::Ynf) => 1000, - (_, Id::Erfc | Id::Erfcf) => 4, - - // Overrides for musl - #[cfg(x86_no_sse)] - (Musl, Id::Asinh | Id::Asinhf) => 6, - #[cfg(not(target_pointer_width = "64"))] - (Musl, Id::Exp10 | Id::Exp10f) => 4, - (Musl, Id::Lgamma | Id::LgammaR | Id::Lgammaf | Id::LgammafR) => 400, - (Musl, Id::Sincosf) => 500, - (Musl, Id::Tanh | Id::Tanhf) => 4, - (Musl, Id::Tgamma) => 20, - - // Overrides for MPFR - (Mpfr, Id::Acosh) => 4, - (Mpfr, Id::Acoshf) => 4, - (Mpfr, Id::Asinh | Id::Asinhf) => 2, - (Mpfr, Id::Atanh | Id::Atanhf) => 2, - (Mpfr, Id::Exp10 | Id::Exp10f) => 6, - (Mpfr, Id::Lgamma | Id::LgammaR | Id::Lgammaf | Id::LgammafR) => 16, - (Mpfr, Id::Sinh | Id::Sinhf) => 2, - (Mpfr, Id::Tanh | Id::Tanhf) => 2, - (Mpfr, Id::Tgamma) => 20, - - // Defaults - (Musl, _) => MUSL_DEFAULT_ULP, - (Mpfr, _) => MP_DEFAULT_ULP, + // ULP compared to the infinite (MPFR) result. + let mut ulp = match ctx.base_name { + // Operations that require exact results. This list should correlate with what we + // have documented at . + Bn::Ceil + | Bn::Copysign + | Bn::Fabs + | Bn::Fdim + | Bn::Floor + | Bn::Fma + | Bn::Fmax + | Bn::Fmin + | Bn::Fmod + | Bn::Frexp + | Bn::Ldexp + | Bn::Modf + | Bn::Nextafter + | Bn::Remainder + | Bn::Remquo + | Bn::Rint + | Bn::Round + | Bn::Scalbn + | Bn::Sqrt + | Bn::Trunc => 0, + + // Operations that aren't required to be exact, but our implementations are. + Bn::Cbrt if ctx.fn_ident != Id::Cbrt => 0, + Bn::Ilogb => 0, + Bn::Tgamma if ctx.fn_ident != Id::Tgamma => 0, + + // Bessel functions have large inaccuracies. + Bn::J0 | Bn::J1 | Bn::Y0 | Bn::Y1 => 8_000_000, + Bn::Jn | Bn::Yn => 1_000, + + // For all other operations, specify our implementation's worst case precision. + Bn::Acos => 1, + Bn::Acosh => 4, + Bn::Asin => 1, + Bn::Asinh => 2, + Bn::Atan => 1, + Bn::Atan2 => 1, + Bn::Atanh => 2, + Bn::Cbrt => 1, + Bn::Cos => 1, + Bn::Cosh => 1, + Bn::Erf => 1, + Bn::Erfc => 4, + Bn::Exp => 1, + Bn::Exp10 => 6, + Bn::Exp2 => 1, + Bn::Expm1 => 1, + Bn::Hypot => 1, + Bn::Lgamma | Bn::LgammaR => 16, + Bn::Log => 1, + Bn::Log10 => 1, + Bn::Log1p => 1, + Bn::Log2 => 1, + Bn::Pow => 1, + Bn::Sin => 1, + Bn::Sincos => 1, + Bn::Sinh => 2, + Bn::Tan => 1, + Bn::Tanh => 2, + Bn::Tgamma => 20, + }; + + // There are some cases where musl's approximation is less accurate than ours. For these + // cases, increase the ULP. + if ctx.basis == Musl { + match ctx.base_name { + Bn::Cosh => ulp = 2, + Bn::Exp10 if usize::BITS < 64 => ulp = 4, + Bn::Lgamma | Bn::LgammaR => ulp = 400, + Bn::Tanh => ulp = 4, + _ if ctx.fn_ident == Id::Sincosf => ulp = 500, + _ if ctx.fn_ident == Id::Tgamma => ulp = 20, + _ => (), + } } + + // In some cases, our implementation is less accurate than musl on i586. + if cfg!(x86_no_sse) { + match ctx.fn_ident { + Id::Log1p | Id::Log1pf => ulp = 2, + Id::Round => ulp = 1, + Id::Tan => ulp = 2, + _ => (), + } + } + + ulp } /// Don't run further validation on this test case. -- cgit 1.4.1-3-g733a5 From d50c12b21953e19dee6722e0e2abd718ef65ead6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 4 Jan 2025 11:14:31 +0000 Subject: precision: Sort `ilogb` with other precise operations This is a nonfunctional change. --- library/compiler-builtins/libm/crates/libm-test/src/precision.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 89b66146c43..8bedcde4427 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -30,6 +30,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { | Bn::Fmin | Bn::Fmod | Bn::Frexp + | Bn::Ilogb | Bn::Ldexp | Bn::Modf | Bn::Nextafter @@ -43,7 +44,6 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { // Operations that aren't required to be exact, but our implementations are. Bn::Cbrt if ctx.fn_ident != Id::Cbrt => 0, - Bn::Ilogb => 0, Bn::Tgamma if ctx.fn_ident != Id::Tgamma => 0, // Bessel functions have large inaccuracies. -- cgit 1.4.1-3-g733a5 From f99d8acc203823dc957ee8843b4edfbe0021cb78 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 5 Jan 2025 02:06:02 +0000 Subject: Clean up integers stored in `MpTy` There isn't any need to cache the integer since it gets provided as an argument anyway. Simplify this in `jn` and `yn`. --- .../libm/crates/libm-test/src/mpfloat.rs | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index edb4cb962dc..5e516ef6875 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -241,17 +241,17 @@ macro_rules! impl_op_for_ty { } impl MpOp for crate::op::[]::Routine { - type MpTy = (i32, MpFloat); + type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - (0, new_mpfloat::()) + new_mpfloat::() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0 = input.0; - this.1.assign(input.1); - let ord = this.1.jn_round(this.0, Nearest); - prep_retval::(&mut this.1, ord) + let (n, x) = input; + this.assign(x); + let ord = this.jn_round(n, Nearest); + prep_retval::(this, ord) } } @@ -274,17 +274,17 @@ macro_rules! impl_op_for_ty { } impl MpOp for crate::op::[]::Routine { - type MpTy = (i32, MpFloat); + type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - (0, new_mpfloat::()) + new_mpfloat::() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0 = input.0; - this.1.assign(input.1); - let ord = this.1.yn_round(this.0, Nearest); - prep_retval::(&mut this.1, ord) + let (n, x) = input; + this.assign(x); + let ord = this.yn_round(n, Nearest); + prep_retval::(this, ord) } } } -- cgit 1.4.1-3-g733a5 From 59964fbbca7757c4d95a925f9e590837c3e4fa83 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 4 Jan 2025 09:53:58 +0000 Subject: Add tests against MPFR for `modf` and `modff` Rug provides `trunc_fract_round`, which implements `modf`, use it to add a test. --- .../libm/crates/libm-test/src/mpfloat.rs | 18 ++++++++++++++++++ .../libm/crates/libm-test/tests/multiprecision.rs | 4 ---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 5e516ef6875..b9e71d68aaa 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -210,6 +210,24 @@ macro_rules! impl_op_for_ty { } } + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(&this.0); + let (ord0, ord1) = this.0.trunc_fract_round(&mut this.1, Nearest); + ( + prep_retval::(&mut this.1, ord0), + prep_retval::(&mut this.0, ord1), + ) + } + } + impl MpOp for crate::op::[]::Routine { type MpTy = (MpFloat, MpFloat); diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 71ff2ff965f..54d313059f9 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -58,8 +58,6 @@ libm_macros::for_each_function! { ilogbf, ldexp, ldexpf, - modf, - modff, remquo, remquof, scalbn, @@ -165,7 +163,5 @@ libm_macros::for_each_function! { frexpf, ilogb, ilogbf, - modf, - modff, ], } -- cgit 1.4.1-3-g733a5 From e9bc33e8d398b412b49315a67c7b3cc246b977e9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 4 Jan 2025 10:39:27 +0000 Subject: Add tests against MPFR for `frexp` and `frexpf` This implementation comes from `rug::Float::to_f32_exp` [1]. [1]: https://docs.rs/rug/1.26.1/rug/struct.Float.html#method.to_f32_exp --- .../libm/crates/libm-test/src/mpfloat.rs | 19 +++++++++++++++++++ .../libm/crates/libm-test/tests/multiprecision.rs | 4 ---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index b9e71d68aaa..4d40858f2b2 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -258,6 +258,25 @@ macro_rules! impl_op_for_ty { } } + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + // Implementation taken from `rug::Float::to_f32_exp`. + this.assign(input.0); + let exp = this.get_exp().unwrap_or(0); + if exp != 0 { + *this >>= exp; + } + + (prep_retval::(this, Ordering::Equal), exp) + } + } + impl MpOp for crate::op::[]::Routine { type MpTy = MpFloat; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 54d313059f9..ade5a255384 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -52,8 +52,6 @@ libm_macros::for_each_function! { ], skip: [ // FIXME: MPFR tests needed - frexp, - frexpf, ilogb, ilogbf, ldexp, @@ -159,8 +157,6 @@ libm_macros::for_each_function! { ynf, // FIXME: MPFR tests needed - frexp, - frexpf, ilogb, ilogbf, ], -- cgit 1.4.1-3-g733a5 From 4b15d9e5e362ba8bbf1bb71437c11d359bf6309c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 05:28:39 +0000 Subject: Add tests against MPFR for `scalbn{f}` and `ldexp{f}` --- .../libm/crates/libm-test/src/mpfloat.rs | 28 ++++++++++++++++++++++ .../libm/crates/libm-test/tests/multiprecision.rs | 4 ---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 4d40858f2b2..8b829800489 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -292,6 +292,34 @@ macro_rules! impl_op_for_ty { } } + // `ldexp` and `scalbn` are the same for binary floating point, so just forward all + // methods. + impl MpOp for crate::op::[]::Routine { + type MpTy = ]::Routine as MpOp>::MpTy; + + fn new_mp() -> Self::MpTy { + ]::Routine as MpOp>::new_mp() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + ]::Routine as MpOp>::run(this, input) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + *this <<= input.1; + prep_retval::(this, Ordering::Equal) + } + } + impl MpOp for crate::op::[]::Routine { type MpTy = (MpFloat, MpFloat); diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index ade5a255384..4cdba0942cd 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -54,12 +54,8 @@ libm_macros::for_each_function! { // FIXME: MPFR tests needed ilogb, ilogbf, - ldexp, - ldexpf, remquo, remquof, - scalbn, - scalbnf, // FIXME: test needed, see // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 -- cgit 1.4.1-3-g733a5 From b7b22b54c0f008993bea29ac26c3db042601ee06 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Dec 2024 08:45:08 +0000 Subject: Add a way for tests to log to a file Occasionally it is useful to see some information from running tests without making everything noisy from `--nocapture`. Add a function to log this kind of output to a file, and print the file as part of CI. --- .../libm/.github/workflows/main.yml | 5 ++ library/compiler-builtins/libm/configure.rs | 15 ++++++ .../libm/crates/libm-test/src/lib.rs | 53 ++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 0f5becf7305..023ec58c06a 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -113,6 +113,11 @@ jobs: rustup target add x86_64-unknown-linux-musl cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} + - name: Print test logs if available + if: always() + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + clippy: name: Clippy runs-on: ubuntu-24.04 diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index 389e86c3388..a18937c3c9e 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -8,6 +8,7 @@ pub struct Config { pub manifest_dir: PathBuf, pub out_dir: PathBuf, pub opt_level: u8, + pub cargo_features: Vec, pub target_arch: String, pub target_env: String, pub target_family: Option, @@ -22,11 +23,16 @@ impl Config { let target_features = env::var("CARGO_CFG_TARGET_FEATURE") .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) .unwrap_or_default(); + let cargo_features = env::vars() + .filter_map(|(name, _value)| name.strip_prefix("CARGO_FEATURE_").map(ToOwned::to_owned)) + .map(|s| s.to_lowercase().replace("_", "-")) + .collect(); Self { manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()), out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), opt_level: env::var("OPT_LEVEL").unwrap().parse().unwrap(), + cargo_features, target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(), @@ -45,6 +51,7 @@ pub fn emit_libm_config(cfg: &Config) { emit_arch_cfg(); emit_optimization_cfg(cfg); emit_cfg_shorthands(cfg); + emit_cfg_env(cfg); emit_f16_f128_cfg(cfg); } @@ -53,6 +60,7 @@ pub fn emit_libm_config(cfg: &Config) { pub fn emit_test_config(cfg: &Config) { emit_optimization_cfg(cfg); emit_cfg_shorthands(cfg); + emit_cfg_env(cfg); emit_f16_f128_cfg(cfg); } @@ -97,6 +105,13 @@ fn emit_cfg_shorthands(cfg: &Config) { } } +/// Reemit config that we make use of for test logging. +fn emit_cfg_env(cfg: &Config) { + println!("cargo:rustc-env=CFG_CARGO_FEATURES={:?}", cfg.cargo_features); + println!("cargo:rustc-env=CFG_OPT_LEVEL={}", cfg.opt_level); + println!("cargo:rustc-env=CFG_TARGET_FEATURES={:?}", cfg.target_features); +} + /// Configure whether or not `f16` and `f128` support should be enabled. fn emit_f16_f128_cfg(cfg: &Config) { println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 97907b2a160..c1aec023030 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -13,6 +13,13 @@ mod precision; mod run_cfg; mod test_traits; +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; +use std::sync::LazyLock; +use std::time::SystemTime; + pub use f8_impl::f8; pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, logspace}; @@ -42,3 +49,49 @@ pub const fn ci() -> bool { Some(_) => true, } } + +/// Print to stderr and additionally log it to `target/test-log.txt`. This is useful for saving +/// output that would otherwise be consumed by the test harness. +pub fn test_log(s: &str) { + // Handle to a file opened in append mode, unless a suitable path can't be determined. + static OUTFILE: LazyLock> = LazyLock::new(|| { + // If the target directory is overridden, use that environment variable. Otherwise, save + // at the default path `{workspace_root}/target`. + let target_dir = match env::var("CARGO_TARGET_DIR") { + Ok(s) => PathBuf::from(s), + Err(_) => { + let Ok(x) = env::var("CARGO_MANIFEST_DIR") else { + return None; + }; + + PathBuf::from(x).parent().unwrap().parent().unwrap().join("target") + } + }; + let outfile = target_dir.join("test-log.txt"); + + let mut f = File::options() + .create(true) + .append(true) + .open(outfile) + .expect("failed to open logfile"); + let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); + + writeln!(f, "\n\nTest run at {}", now.as_secs()).unwrap(); + writeln!(f, "arch: {}", env::consts::ARCH).unwrap(); + writeln!(f, "os: {}", env::consts::OS).unwrap(); + writeln!(f, "bits: {}", usize::BITS).unwrap(); + writeln!(f, "emulated: {}", emulated()).unwrap(); + writeln!(f, "ci: {}", ci()).unwrap(); + writeln!(f, "cargo features: {}", env!("CFG_CARGO_FEATURES")).unwrap(); + writeln!(f, "opt level: {}", env!("CFG_OPT_LEVEL")).unwrap(); + writeln!(f, "target features: {}", env!("CFG_TARGET_FEATURES")).unwrap(); + + Some(f) + }); + + eprintln!("{s}"); + + if let Some(mut f) = OUTFILE.as_ref() { + writeln!(f, "{s}").unwrap(); + } +} -- cgit 1.4.1-3-g733a5 From 9a7a5193706319b17c260da433f27c2c2c8f5b07 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 26 Dec 2024 07:44:54 +0000 Subject: Streamline the way that test iteration count is determined Currently, tests use a handful of constants to determine how many iterations to perform: `NTESTS`, `AROUND`, and `MAX_CHECK_POINTS`. This configuration is not very straightforward to adjust and needs to be repeated everywhere it is used. Replace this with new functions in the `run_cfg` module that determine iteration counts in a more reusable and documented way. This only updates `edge_cases` and `domain_logspace`, `random` is refactored in a later commit. --- .../crates/libm-test/src/gen/domain_logspace.rs | 31 +--- .../libm/crates/libm-test/src/gen/edge_cases.rs | 54 +++---- .../libm/crates/libm-test/src/gen/random.rs | 1 + .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/run_cfg.rs | 177 ++++++++++++++++++++- 5 files changed, 208 insertions(+), 57 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs index 5e37170fa1a..3d8a3e7fe73 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs @@ -6,41 +6,26 @@ use libm::support::{IntTy, MinInt}; use crate::domain::HasDomain; use crate::op::OpITy; +use crate::run_cfg::{GeneratorKind, iteration_count}; use crate::{CheckCtx, MathOp, logspace}; -/// Number of tests to run. -// FIXME(ntests): replace this with a more logical algorithm -const NTESTS: usize = { - if cfg!(optimizations_enabled) { - if crate::emulated() - || !cfg!(target_pointer_width = "64") - || cfg!(all(target_arch = "x86_64", target_vendor = "apple")) - { - // Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run - // in QEMU. - 100_000 - } else { - 5_000_000 - } - } else { - // Without optimizations just run a quick check - 800 - } -}; - /// Create a range of logarithmically spaced inputs within a function's domain. /// /// This allows us to get reasonably thorough coverage without wasting time on values that are /// NaN or out of range. Random tests will still cover values that are excluded here. -pub fn get_test_cases(_ctx: &CheckCtx) -> impl Iterator +pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator where Op: MathOp + HasDomain, - IntTy: TryFrom, + IntTy: TryFrom, RangeInclusive>: Iterator, { let domain = Op::DOMAIN; + let ntests = iteration_count(ctx, GeneratorKind::Domain, 0); + + // We generate logspaced inputs within a specific range, excluding values that are out of + // range in order to make iterations useful (random tests still cover the full range). let start = domain.range_start(); let end = domain.range_end(); - let steps = OpITy::::try_from(NTESTS).unwrap_or(OpITy::::MAX); + let steps = OpITy::::try_from(ntests).unwrap_or(OpITy::::MAX); logspace(start, end, steps).map(|v| (v,)) } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs index 3387f6c485a..1f27c1467dc 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs @@ -3,18 +3,11 @@ use libm::support::Float; use crate::domain::HasDomain; +use crate::run_cfg::{check_near_count, check_point_count}; use crate::{CheckCtx, FloatExt, MathOp}; -/// Number of values near an interesting point to check. -// FIXME(ntests): replace this with a more logical algorithm -const AROUND: usize = 100; - -/// Functions have infinite asymptotes, limit how many we check. -// FIXME(ntests): replace this with a more logical algorithm -const MAX_CHECK_POINTS: usize = 10; - /// Create a list of values around interesting points (infinities, zeroes, NaNs). -pub fn get_test_cases(_ctx: &CheckCtx) -> impl Iterator +pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator where Op: MathOp + HasDomain, F: Float, @@ -25,23 +18,26 @@ where let domain_start = domain.range_start(); let domain_end = domain.range_end(); + let check_points = check_point_count(ctx); + let near_points = check_near_count(ctx); + // Check near some notable constants - count_up(F::ONE, values); - count_up(F::ZERO, values); - count_up(F::NEG_ONE, values); - count_down(F::ONE, values); - count_down(F::ZERO, values); - count_down(F::NEG_ONE, values); + count_up(F::ONE, near_points, values); + count_up(F::ZERO, near_points, values); + count_up(F::NEG_ONE, near_points, values); + count_down(F::ONE, near_points, values); + count_down(F::ZERO, near_points, values); + count_down(F::NEG_ONE, near_points, values); values.push(F::NEG_ZERO); // Check values near the extremes - count_up(F::NEG_INFINITY, values); - count_down(F::INFINITY, values); - count_down(domain_end, values); - count_up(domain_start, values); - count_down(domain_start, values); - count_up(domain_end, values); - count_down(domain_end, values); + count_up(F::NEG_INFINITY, near_points, values); + count_down(F::INFINITY, near_points, values); + count_down(domain_end, near_points, values); + count_up(domain_start, near_points, values); + count_down(domain_start, near_points, values); + count_up(domain_end, near_points, values); + count_down(domain_end, near_points, values); // Check some special values that aren't included in the above ranges values.push(F::NAN); @@ -50,9 +46,9 @@ where // Check around asymptotes if let Some(f) = domain.check_points { let iter = f(); - for x in iter.take(MAX_CHECK_POINTS) { - count_up(x, values); - count_down(x, values); + for x in iter.take(check_points) { + count_up(x, near_points, values); + count_down(x, near_points, values); } } @@ -65,11 +61,11 @@ where /// Add `AROUND` values starting at and including `x` and counting up. Uses the smallest possible /// increments (1 ULP). -fn count_up(mut x: F, values: &mut Vec) { +fn count_up(mut x: F, points: u64, values: &mut Vec) { assert!(!x.is_nan()); let mut count = 0; - while x < F::INFINITY && count < AROUND { + while x < F::INFINITY && count < points { values.push(x); x = x.next_up(); count += 1; @@ -78,11 +74,11 @@ fn count_up(mut x: F, values: &mut Vec) { /// Add `AROUND` values starting at and including `x` and counting down. Uses the smallest possible /// increments (1 ULP). -fn count_down(mut x: F, values: &mut Vec) { +fn count_down(mut x: F, points: u64, values: &mut Vec) { assert!(!x.is_nan()); let mut count = 0; - while x > F::NEG_INFINITY && count < AROUND { + while x > F::NEG_INFINITY && count < points { values.push(x); x = x.next_down(); count += 1; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 4f75da07b89..a30a3674e6a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -12,6 +12,7 @@ use crate::{BaseName, CheckCtx, GenerateInput}; const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; /// Number of tests to run. +// FIXME(ntests): clean this up when possible const NTESTS: usize = { if cfg!(optimizations_enabled) { if crate::emulated() diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index c1aec023030..80ec2373615 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -25,7 +25,7 @@ pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, logspace}; pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; -pub use run_cfg::{CheckBasis, CheckCtx}; +pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind}; pub use test_traits::{CheckOutput, GenerateInput, Hex, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index eb7e0e2c1a9..46a6a1fadaa 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -1,13 +1,11 @@ //! Configuration for how tests get run. -#![allow(unused)] - -use std::collections::BTreeMap; use std::env; use std::sync::LazyLock; -use crate::{BaseName, FloatTy, Identifier, op}; +use crate::{BaseName, FloatTy, Identifier, test_log}; +/// The environment variable indicating which extensive tests should be run. pub const EXTENSIVE_ENV: &str = "LIBM_EXTENSIVE_TESTS"; /// Context passed to [`CheckOutput`]. @@ -49,3 +47,174 @@ pub enum CheckBasis { /// Check against infinite precision (MPFR). Mpfr, } + +/// The different kinds of generators that provide test input. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum GeneratorKind { + Domain, + Random, +} + +/// A list of all functions that should get extensive tests. +/// +/// This also supports the special test name `all` to run all tests, as well as `all_f16`, +/// `all_f32`, `all_f64`, and `all_f128` to run all tests for a specific float type. +static EXTENSIVE: LazyLock> = LazyLock::new(|| { + let var = env::var(EXTENSIVE_ENV).unwrap_or_default(); + let list = var.split(",").filter(|s| !s.is_empty()).collect::>(); + let mut ret = Vec::new(); + + let append_ty_ops = |ret: &mut Vec<_>, fty: FloatTy| { + let iter = Identifier::ALL.iter().filter(move |id| id.math_op().float_ty == fty).copied(); + ret.extend(iter); + }; + + for item in list { + match item { + "all" => ret = Identifier::ALL.to_owned(), + "all_f16" => append_ty_ops(&mut ret, FloatTy::F16), + "all_f32" => append_ty_ops(&mut ret, FloatTy::F32), + "all_f64" => append_ty_ops(&mut ret, FloatTy::F64), + "all_f128" => append_ty_ops(&mut ret, FloatTy::F128), + s => { + let id = Identifier::from_str(s) + .unwrap_or_else(|| panic!("unrecognized test name `{s}`")); + ret.push(id); + } + } + } + + ret +}); + +/// Information about the function to be tested. +#[derive(Debug)] +struct TestEnv { + /// Tests should be reduced because the platform is slow. E.g. 32-bit or emulated. + slow_platform: bool, + /// The float cannot be tested exhaustively, `f64` or `f128`. + large_float_ty: bool, + /// Env indicates that an extensive test should be run. + should_run_extensive: bool, + /// Multiprecision tests will be run. + mp_tests_enabled: bool, + /// The number of inputs to the function. + input_count: usize, +} + +impl TestEnv { + fn from_env(ctx: &CheckCtx) -> Self { + let id = ctx.fn_ident; + let op = id.math_op(); + + let will_run_mp = cfg!(feature = "test-multiprecision"); + + // Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run in QEMU. Start + // with a reduced number on these platforms. + let slow_on_ci = crate::emulated() + || usize::BITS < 64 + || cfg!(all(target_arch = "x86_64", target_vendor = "apple")); + let slow_platform = slow_on_ci && crate::ci(); + + let large_float_ty = match op.float_ty { + FloatTy::F16 | FloatTy::F32 => false, + FloatTy::F64 | FloatTy::F128 => true, + }; + + let will_run_extensive = EXTENSIVE.contains(&id); + + let input_count = op.rust_sig.args.len(); + + Self { + slow_platform, + large_float_ty, + should_run_extensive: will_run_extensive, + mp_tests_enabled: will_run_mp, + input_count, + } + } +} + +/// The number of iterations to run for a given test. +pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) -> u64 { + let t_env = TestEnv::from_env(ctx); + + // Ideally run 5M tests + let mut domain_iter_count: u64 = 4_000_000; + + // Start with a reduced number of tests on slow platforms. + if t_env.slow_platform { + domain_iter_count = 100_000; + } + + // Larger float types get more iterations. + if t_env.large_float_ty { + domain_iter_count *= 4; + } + + // Functions with more arguments get more iterations. + let arg_multiplier = 1 << (t_env.input_count - 1); + domain_iter_count *= arg_multiplier; + + // If we will be running tests against MPFR, we don't need to test as much against musl. + // However, there are some platforms where we have to test against musl since MPFR can't be + // built. + if t_env.mp_tests_enabled && ctx.basis == CheckBasis::Musl { + domain_iter_count /= 100; + } + + // Run fewer random tests than domain tests. + let random_iter_count = domain_iter_count / 100; + + let mut total_iterations = match gen_kind { + GeneratorKind::Domain => domain_iter_count, + GeneratorKind::Random => random_iter_count, + }; + + if cfg!(optimizations_enabled) { + // Always run at least 10,000 tests. + total_iterations = total_iterations.max(10_000); + } else { + // Without optimizations, just run a quick check regardless of other parameters. + total_iterations = 800; + } + + // Adjust for the number of inputs + let ntests = match t_env.input_count { + 1 => total_iterations, + 2 => (total_iterations as f64).sqrt().ceil() as u64, + 3 => (total_iterations as f64).cbrt().ceil() as u64, + _ => panic!("test has more than three arguments"), + }; + let total = ntests.pow(t_env.input_count.try_into().unwrap()); + + test_log(&format!( + "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {ntests} iterations \ + ({total} total)", + basis = ctx.basis, + fn_ident = ctx.fn_ident, + arg = argnum + 1, + args = t_env.input_count, + )); + + ntests +} + +/// For domain tests, limit how many asymptotes or specified check points we test. +pub fn check_point_count(ctx: &CheckCtx) -> usize { + let t_env = TestEnv::from_env(ctx); + if t_env.slow_platform || !cfg!(optimizations_enabled) { 4 } else { 10 } +} + +/// When validating points of interest (e.g. asymptotes, inflection points, extremes), also check +/// this many surrounding values. +pub fn check_near_count(_ctx: &CheckCtx) -> u64 { + if cfg!(optimizations_enabled) { 100 } else { 10 } +} + +/// Check whether extensive actions should be run or skipped. +#[expect(dead_code, reason = "extensive tests have not yet been added")] +pub fn skip_extensive_test(ctx: &CheckCtx) -> bool { + let t_env = TestEnv::from_env(ctx); + !t_env.should_run_extensive +} -- cgit 1.4.1-3-g733a5 From b78f7b7b482fa6dbc540cabd6f1a6233d48f0b9f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Dec 2024 06:12:16 +0000 Subject: Add an iterator that ensures known size Introduce the `KnownSize` iterator wrapper, which allows providing the size at construction time. This provides an `ExactSizeIterator` implemenation so we can check a generator's value count during testing. --- .../libm/crates/libm-test/src/gen.rs | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index 2d15915d91a..2305d2a2377 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -5,6 +5,43 @@ pub mod domain_logspace; pub mod edge_cases; pub mod random; +/// A wrapper to turn any iterator into an `ExactSizeIterator`. Asserts the final result to ensure +/// the provided size was correct. +#[derive(Debug)] +pub struct KnownSize { + total: u64, + current: u64, + iter: I, +} + +impl KnownSize { + pub fn new(iter: I, total: u64) -> Self { + Self { total, current: 0, iter } + } +} + +impl Iterator for KnownSize { + type Item = I::Item; + + fn next(&mut self) -> Option { + let next = self.iter.next(); + if next.is_some() { + self.current += 1; + return next; + } + + assert_eq!(self.current, self.total, "total items did not match expected"); + None + } + + fn size_hint(&self) -> (usize, Option) { + let remaining = usize::try_from(self.total - self.current).unwrap(); + (remaining, Some(remaining)) + } +} + +impl ExactSizeIterator for KnownSize {} + /// Helper type to turn any reusable input into a generator. #[derive(Clone, Debug, Default)] pub struct CachedInput { -- cgit 1.4.1-3-g733a5 From 37dbc534cba00c25d06fb6421facc9b39b69b6eb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Dec 2024 11:23:08 +0000 Subject: Rewrite the random test generator Currently, all inputs are generated and then cached. This works reasonably well but it isn't very configurable or extensible (adding `f16` and `f128` is awkward). Replace this with a trait for generating random sequences of tuples. This also removes possible storage limitations of caching all inputs. --- .../libm/crates/libm-test/benches/random.rs | 7 +- .../libm/crates/libm-test/src/gen.rs | 69 ------- .../libm/crates/libm-test/src/gen/random.rs | 206 ++++++++++----------- .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/run_cfg.rs | 32 +++- .../libm/crates/libm-test/src/test_traits.rs | 8 +- .../crates/libm-test/tests/compare_built_musl.rs | 11 +- .../libm/crates/libm-test/tests/multiprecision.rs | 9 +- 8 files changed, 148 insertions(+), 196 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 06997cd3621..23f42945583 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -2,8 +2,9 @@ use std::hint::black_box; use std::time::Duration; use criterion::{Criterion, criterion_main}; -use libm_test::gen::{CachedInput, random}; -use libm_test::{CheckBasis, CheckCtx, GenerateInput, MathOp, TupleCall}; +use libm_test::gen::random; +use libm_test::gen::random::RandomInput; +use libm_test::{CheckBasis, CheckCtx, MathOp, TupleCall}; /// Benchmark with this many items to get a variety const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { 50 } else { 500 }; @@ -47,7 +48,7 @@ macro_rules! musl_rand_benches { fn bench_one(c: &mut Criterion, musl_extra: MuslExtra) where Op: MathOp, - CachedInput: GenerateInput, + Op::RustArgs: RandomInput, { let name = Op::NAME; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index 2305d2a2377..83e00f31d28 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -1,6 +1,5 @@ //! Different generators that can create random or systematic bit patterns. -use crate::GenerateInput; pub mod domain_logspace; pub mod edge_cases; pub mod random; @@ -41,71 +40,3 @@ impl Iterator for KnownSize { } impl ExactSizeIterator for KnownSize {} - -/// Helper type to turn any reusable input into a generator. -#[derive(Clone, Debug, Default)] -pub struct CachedInput { - pub inputs_f32: Vec<(f32, f32, f32)>, - pub inputs_f64: Vec<(f64, f64, f64)>, - pub inputs_i32: Vec<(i32, i32, i32)>, -} - -impl GenerateInput<(f32,)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_f32.iter().map(|f| (f.0,)) - } -} - -impl GenerateInput<(f32, f32)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_f32.iter().map(|f| (f.0, f.1)) - } -} - -impl GenerateInput<(i32, f32)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_i32.iter().zip(self.inputs_f32.iter()).map(|(i, f)| (i.0, f.0)) - } -} - -impl GenerateInput<(f32, i32)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - GenerateInput::<(i32, f32)>::get_cases(self).map(|(i, f)| (f, i)) - } -} - -impl GenerateInput<(f32, f32, f32)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_f32.iter().copied() - } -} - -impl GenerateInput<(f64,)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_f64.iter().map(|f| (f.0,)) - } -} - -impl GenerateInput<(f64, f64)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_f64.iter().map(|f| (f.0, f.1)) - } -} - -impl GenerateInput<(i32, f64)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_i32.iter().zip(self.inputs_f64.iter()).map(|(i, f)| (i.0, f.0)) - } -} - -impl GenerateInput<(f64, i32)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - GenerateInput::<(i32, f64)>::get_cases(self).map(|(i, f)| (f, i)) - } -} - -impl GenerateInput<(f64, f64, f64)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_f64.iter().copied() - } -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index a30a3674e6a..6df9443178a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -1,120 +1,118 @@ -//! A simple generator that produces deterministic random input, caching to use the same -//! inputs for all functions. - +use std::env; +use std::ops::RangeInclusive; use std::sync::LazyLock; +use libm::support::Float; +use rand::distributions::{Alphanumeric, Standard}; +use rand::prelude::Distribution; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; -use super::CachedInput; -use crate::{BaseName, CheckCtx, GenerateInput}; - -const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; - -/// Number of tests to run. -// FIXME(ntests): clean this up when possible -const NTESTS: usize = { - if cfg!(optimizations_enabled) { - if crate::emulated() - || !cfg!(target_pointer_width = "64") - || cfg!(all(target_arch = "x86_64", target_vendor = "apple")) - { - // Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run - // in QEMU. - 100_000 - } else { - 5_000_000 - } - } else { - // Without optimizations just run a quick check - 800 - } -}; - -/// Tested inputs. -static TEST_CASES: LazyLock = LazyLock::new(|| make_test_cases(NTESTS)); - -/// The first argument to `jn` and `jnf` is the number of iterations. Make this a reasonable -/// value so tests don't run forever. -static TEST_CASES_JN: LazyLock = LazyLock::new(|| { - // Start with regular test cases - let mut cases = (*TEST_CASES).clone(); - - // These functions are extremely slow, limit them - let ntests_jn = (NTESTS / 1000).max(80); - cases.inputs_i32.truncate(ntests_jn); - cases.inputs_f32.truncate(ntests_jn); - cases.inputs_f64.truncate(ntests_jn); - - // It is easy to overflow the stack with these in debug mode - let max_iterations = if cfg!(optimizations_enabled) && cfg!(target_pointer_width = "64") { - 0xffff - } else if cfg!(windows) { - 0x00ff - } else { - 0x0fff - }; +use super::KnownSize; +use crate::run_cfg::{int_range, iteration_count}; +use crate::{CheckCtx, GeneratorKind}; - let mut rng = ChaCha8Rng::from_seed(SEED); +pub(crate) const SEED_ENV: &str = "LIBM_SEED"; - for case in cases.inputs_i32.iter_mut() { - case.0 = rng.gen_range(3..=max_iterations); - } +pub(crate) static SEED: LazyLock<[u8; 32]> = LazyLock::new(|| { + let s = env::var(SEED_ENV).unwrap_or_else(|_| { + let mut rng = rand::thread_rng(); + (0..32).map(|_| rng.sample(Alphanumeric) as char).collect() + }); - cases + s.as_bytes().try_into().unwrap_or_else(|_| { + panic!("Seed must be 32 characters, got `{s}`"); + }) }); -fn make_test_cases(ntests: usize) -> CachedInput { - let mut rng = ChaCha8Rng::from_seed(SEED); - - // make sure we include some basic cases - let mut inputs_i32 = vec![(0, 0, 0), (1, 1, 1), (-1, -1, -1)]; - let mut inputs_f32 = vec![ - (0.0, 0.0, 0.0), - (f32::EPSILON, f32::EPSILON, f32::EPSILON), - (f32::INFINITY, f32::INFINITY, f32::INFINITY), - (f32::NEG_INFINITY, f32::NEG_INFINITY, f32::NEG_INFINITY), - (f32::MAX, f32::MAX, f32::MAX), - (f32::MIN, f32::MIN, f32::MIN), - (f32::MIN_POSITIVE, f32::MIN_POSITIVE, f32::MIN_POSITIVE), - (f32::NAN, f32::NAN, f32::NAN), - ]; - let mut inputs_f64 = vec![ - (0.0, 0.0, 0.0), - (f64::EPSILON, f64::EPSILON, f64::EPSILON), - (f64::INFINITY, f64::INFINITY, f64::INFINITY), - (f64::NEG_INFINITY, f64::NEG_INFINITY, f64::NEG_INFINITY), - (f64::MAX, f64::MAX, f64::MAX), - (f64::MIN, f64::MIN, f64::MIN), - (f64::MIN_POSITIVE, f64::MIN_POSITIVE, f64::MIN_POSITIVE), - (f64::NAN, f64::NAN, f64::NAN), - ]; - - inputs_i32.extend((0..(ntests - inputs_i32.len())).map(|_| rng.gen::<(i32, i32, i32)>())); - - // Generate integers to get a full range of bitpatterns, then convert back to - // floats. - inputs_f32.extend((0..(ntests - inputs_f32.len())).map(|_| { - let ints = rng.gen::<(u32, u32, u32)>(); - (f32::from_bits(ints.0), f32::from_bits(ints.1), f32::from_bits(ints.2)) - })); - inputs_f64.extend((0..(ntests - inputs_f64.len())).map(|_| { - let ints = rng.gen::<(u64, u64, u64)>(); - (f64::from_bits(ints.0), f64::from_bits(ints.1), f64::from_bits(ints.2)) - })); - - CachedInput { inputs_f32, inputs_f64, inputs_i32 } +/// Generate a sequence of random values of this type. +pub trait RandomInput { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator; } -/// Create a test case iterator. -pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator +/// Generate a sequence of deterministically random floats. +fn random_floats(count: u64) -> impl Iterator where - CachedInput: GenerateInput, + Standard: Distribution, { - let inputs = if ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn { - &TEST_CASES_JN - } else { - &TEST_CASES + let mut rng = ChaCha8Rng::from_seed(*SEED); + + // Generate integers to get a full range of bitpatterns (including NaNs), then convert back + // to the float type. + (0..count).map(move |_| F::from_bits(rng.gen::())) +} + +/// Generate a sequence of deterministically random `i32`s within a specified range. +fn random_ints(count: u64, range: RangeInclusive) -> impl Iterator { + let mut rng = ChaCha8Rng::from_seed(*SEED); + (0..count).map(move |_| rng.gen_range::(range.clone())) +} + +macro_rules! impl_random_input { + ($fty:ty) => { + impl RandomInput for ($fty,) { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let count = iteration_count(ctx, GeneratorKind::Random, 0); + let iter = random_floats(count).map(|f: $fty| (f,)); + KnownSize::new(iter, count) + } + } + + impl RandomInput for ($fty, $fty) { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let count0 = iteration_count(ctx, GeneratorKind::Random, 0); + let count1 = iteration_count(ctx, GeneratorKind::Random, 1); + let iter = random_floats(count0) + .flat_map(move |f1: $fty| random_floats(count1).map(move |f2: $fty| (f1, f2))); + KnownSize::new(iter, count0 * count1) + } + } + + impl RandomInput for ($fty, $fty, $fty) { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let count0 = iteration_count(ctx, GeneratorKind::Random, 0); + let count1 = iteration_count(ctx, GeneratorKind::Random, 1); + let count2 = iteration_count(ctx, GeneratorKind::Random, 2); + let iter = random_floats(count0).flat_map(move |f1: $fty| { + random_floats(count1).flat_map(move |f2: $fty| { + random_floats(count2).map(move |f3: $fty| (f1, f2, f3)) + }) + }); + KnownSize::new(iter, count0 * count1 * count2) + } + } + + impl RandomInput for (i32, $fty) { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let count0 = iteration_count(ctx, GeneratorKind::Random, 0); + let count1 = iteration_count(ctx, GeneratorKind::Random, 1); + let range0 = int_range(ctx, 0); + let iter = random_ints(count0, range0) + .flat_map(move |f1: i32| random_floats(count1).map(move |f2: $fty| (f1, f2))); + KnownSize::new(iter, count0 * count1) + } + } + + impl RandomInput for ($fty, i32) { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let count0 = iteration_count(ctx, GeneratorKind::Random, 0); + let count1 = iteration_count(ctx, GeneratorKind::Random, 1); + let range1 = int_range(ctx, 1); + let iter = random_floats(count0).flat_map(move |f1: $fty| { + random_ints(count1, range1.clone()).map(move |f2: i32| (f1, f2)) + }); + KnownSize::new(iter, count0 * count1) + } + } }; - inputs.get_cases() +} + +impl_random_input!(f32); +impl_random_input!(f64); + +/// Create a test case iterator. +pub fn get_test_cases( + ctx: &CheckCtx, +) -> impl Iterator + use<'_, RustArgs> { + RustArgs::get_cases(ctx) } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 80ec2373615..8a4e782df70 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -26,7 +26,7 @@ pub use num::{FloatExt, logspace}; pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind}; -pub use test_traits::{CheckOutput, GenerateInput, Hex, TupleCall}; +pub use test_traits::{CheckOutput, Hex, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to /// propagate. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 46a6a1fadaa..9cede0cc722 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -1,8 +1,10 @@ //! Configuration for how tests get run. -use std::env; +use std::ops::RangeInclusive; use std::sync::LazyLock; +use std::{env, str}; +use crate::gen::random::{SEED, SEED_ENV}; use crate::{BaseName, FloatTy, Identifier, test_log}; /// The environment variable indicating which extensive tests should be run. @@ -188,9 +190,16 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - }; let total = ntests.pow(t_env.input_count.try_into().unwrap()); + let seed_msg = match gen_kind { + GeneratorKind::Domain => String::new(), + GeneratorKind::Random => { + format!(" using `{SEED_ENV}={}`", str::from_utf8(SEED.as_slice()).unwrap()) + } + }; + test_log(&format!( "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {ntests} iterations \ - ({total} total)", + ({total} total){seed_msg}", basis = ctx.basis, fn_ident = ctx.fn_ident, arg = argnum + 1, @@ -200,6 +209,25 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - ntests } +/// Some tests require that an integer be kept within reasonable limits; generate that here. +pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { + let t_env = TestEnv::from_env(ctx); + + if !matches!(ctx.base_name, BaseName::Jn | BaseName::Yn) { + return i32::MIN..=i32::MAX; + } + + assert_eq!(argnum, 0, "For `jn`/`yn`, only the first argument takes an integer"); + + // The integer argument to `jn` is an iteration count. Limit this to ensure tests can be + // completed in a reasonable amount of time. + if t_env.slow_platform || !cfg!(optimizations_enabled) { + (-0xf)..=0xff + } else { + (-0xff)..=0xffff + } +} + /// For domain tests, limit how many asymptotes or specified check points we test. pub fn check_point_count(ctx: &CheckCtx) -> usize { let t_env = TestEnv::from_env(ctx); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 6b833dfb5dd..261d1f2540d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -1,8 +1,7 @@ //! Traits related to testing. //! -//! There are three main traits in this module: +//! There are two main traits in this module: //! -//! - `GenerateInput`: implemented on any types that create test cases. //! - `TupleCall`: implemented on tuples to allow calling them as function arguments. //! - `CheckOutput`: implemented on anything that is an output type for validation against an //! expected value. @@ -13,11 +12,6 @@ use anyhow::{Context, bail, ensure}; use crate::{CheckCtx, Float, Int, MaybeOverride, SpecialCase, TestResult}; -/// Implement this on types that can generate a sequence of tuples for test input. -pub trait GenerateInput { - fn get_cases(&self) -> impl Iterator; -} - /// Trait for calling a function with a tuple as arguments. /// /// Implemented on the tuple with the function signature as the generic (so we can use the same diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 71f080ab18f..ecd379a0a68 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -9,8 +9,9 @@ // There are some targets we can't build musl for #![cfg(feature = "build-musl")] -use libm_test::gen::{CachedInput, random}; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall}; +use libm_test::gen::random; +use libm_test::gen::random::RandomInput; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, MathOp, TupleCall}; macro_rules! musl_rand_tests { ( @@ -21,16 +22,16 @@ macro_rules! musl_rand_tests { #[test] $(#[$attr])* fn [< musl_random_ $fn_name >]() { - test_one::(musl_math_sys::$fn_name); + test_one_random::(musl_math_sys::$fn_name); } } }; } -fn test_one(musl_fn: Op::CFn) +fn test_one_random(musl_fn: Op::CFn) where Op: MathOp, - CachedInput: GenerateInput, + Op::RustArgs: RandomInput, { let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl); let cases = random::get_test_cases::(&ctx); diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 4cdba0942cd..960c370d4b5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -3,11 +3,10 @@ #![cfg(feature = "test-multiprecision")] use libm_test::domain::HasDomain; -use libm_test::gen::{CachedInput, domain_logspace, edge_cases, random}; +use libm_test::gen::random::RandomInput; +use libm_test::gen::{domain_logspace, edge_cases, random}; use libm_test::mpfloat::MpOp; -use libm_test::{ - CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, OpFTy, OpRustFn, OpRustRet, TupleCall, -}; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, MathOp, OpFTy, OpRustFn, OpRustRet, TupleCall}; /// Test against MPFR with random inputs. macro_rules! mp_rand_tests { @@ -29,7 +28,7 @@ macro_rules! mp_rand_tests { fn test_one_random() where Op: MathOp + MpOp, - CachedInput: GenerateInput, + Op::RustArgs: RandomInput, { let mut mp_vals = Op::new_mp(); let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); -- cgit 1.4.1-3-g733a5 From cc6a84bf438072033d577284d0dabdd0a5d354d7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 00:36:18 +0000 Subject: Update precision based on new test results --- .../libm/crates/libm-test/src/precision.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 8bedcde4427..a8efe1015f8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -90,8 +90,15 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Bn::Exp10 if usize::BITS < 64 => ulp = 4, Bn::Lgamma | Bn::LgammaR => ulp = 400, Bn::Tanh => ulp = 4, - _ if ctx.fn_ident == Id::Sincosf => ulp = 500, - _ if ctx.fn_ident == Id::Tgamma => ulp = 20, + _ => (), + } + + match ctx.fn_ident { + // FIXME(#401): musl has an incorrect result here. + Id::Fdim => ulp = 2, + Id::Jnf | Id::Ynf => ulp = 4000, + Id::Sincosf => ulp = 500, + Id::Tgamma => ulp = 20, _ => (), } } @@ -99,6 +106,8 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { // In some cases, our implementation is less accurate than musl on i586. if cfg!(x86_no_sse) { match ctx.fn_ident { + Id::Asinh => ulp = 3, + Id::Asinhf => ulp = 3, Id::Log1p | Id::Log1pf => ulp = 2, Id::Round => ulp = 1, Id::Tan => ulp = 2, -- cgit 1.4.1-3-g733a5 From ea21b6045f07dd4b01a54c74f3b2a87d85ff1588 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 02:52:24 +0000 Subject: Rename `unstable-test-support` to `unstable-public-internals` The `support` module that this feature makes public will be useful for implementations in `compiler-builtins`, not only for testing. Give this feature a more accurate name. --- library/compiler-builtins/libm/Cargo.toml | 2 +- .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 13 +++++-------- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 2 +- library/compiler-builtins/libm/src/math/mod.rs | 6 +++--- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index bfc11509e42..dc362779e84 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -27,7 +27,7 @@ unstable = ["unstable-intrinsics", "unstable-float"] unstable-intrinsics = [] # Make some internal things public for testing. -unstable-test-support = [] +unstable-public-internals = [] # Enable the nightly-only `f16` and `f128`. unstable-float = [] diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 82cfeecb90f..1f09ce99c48 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -9,14 +9,6 @@ publish = false test = false bench = false -[features] -# Duplicated from libm's Cargo.toml -unstable = [] -unstable-intrinsics = [] -unstable-test-support = [] -checked = [] -force-soft-floats = [] - [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ "cfg(arch_enabled)", @@ -24,4 +16,9 @@ unexpected_cfgs = { level = "warn", check-cfg = [ "cfg(f128_enabled)", "cfg(f16_enabled)", "cfg(intrinsics_enabled)", + 'cfg(feature, values("checked"))', + 'cfg(feature, values("force-soft-floats"))', + 'cfg(feature, values("unstable"))', + 'cfg(feature, values("unstable-intrinsics"))', + 'cfg(feature, values("unstable-public-internals"))', ] } diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index f2dd88fa14c..9b3ab5c53b1 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -26,7 +26,7 @@ short-benchmarks = [] [dependencies] anyhow = "1.0.90" az = { version = "1.2.1", optional = true } -libm = { path = "../..", features = ["unstable-test-support"] } +libm = { path = "../..", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } paste = "1.0.15" diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e7b21de6762..9003a834288 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -76,15 +76,15 @@ macro_rules! div { // `support` may be public for testing #[macro_use] -#[cfg(feature = "unstable-test-support")] +#[cfg(feature = "unstable-public-internals")] pub mod support; #[macro_use] -#[cfg(not(feature = "unstable-test-support"))] +#[cfg(not(feature = "unstable-public-internals"))] mod support; cfg_if! { - if #[cfg(feature = "unstable-test-support")] { + if #[cfg(feature = "unstable-public-internals")] { pub mod generic; } else { mod generic; -- cgit 1.4.1-3-g733a5 From 206bf326d54fba056129150afbc083e5a7f3447a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 03:00:54 +0000 Subject: Increase the precision for `jn` and `jnf` New random seeds seem to indicate that this test does have some more failures, this is a recent failure on i586: ---- musl_random_jnf stdout ---- Random Musl jnf arg 1/2: 100 iterations (10000 total) using `LIBM_SEED=nLfzQ3U1OBVvqWaMBcto84UTMsC5FIaC` Random Musl jnf arg 2/2: 100 iterations (10000 total) using `LIBM_SEED=nLfzQ3U1OBVvqWaMBcto84UTMsC5FIaC` thread 'musl_random_jnf' panicked at crates/libm-test/tests/compare_built_musl.rs:43:51: called `Result::unwrap()` on an `Err` value: input: (205, 5497.891) (0x000000cd, 0x45abcf21) expected: 7.3291517e-6 0x36f5ecef actual: 7.331668e-6 0x36f6028c Caused by: ulp 5533 > 4000 It seems unlikely that `jn` would somehow have better precision than `j0`/`j1`, so just use the same precision. --- library/compiler-builtins/libm/crates/libm-test/src/precision.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index a8efe1015f8..4a6ca8af7b6 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -47,8 +47,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Bn::Tgamma if ctx.fn_ident != Id::Tgamma => 0, // Bessel functions have large inaccuracies. - Bn::J0 | Bn::J1 | Bn::Y0 | Bn::Y1 => 8_000_000, - Bn::Jn | Bn::Yn => 1_000, + Bn::J0 | Bn::J1 | Bn::Y0 | Bn::Y1 | Bn::Jn | Bn::Yn => 8_000_000, // For all other operations, specify our implementation's worst case precision. Bn::Acos => 1, @@ -96,7 +95,6 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { match ctx.fn_ident { // FIXME(#401): musl has an incorrect result here. Id::Fdim => ulp = 2, - Id::Jnf | Id::Ynf => ulp = 4000, Id::Sincosf => ulp = 500, Id::Tgamma => ulp = 20, _ => (), -- cgit 1.4.1-3-g733a5 From f453f5e5b561642bfc859e332a1e4ba8381b872f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 5 Jan 2025 01:58:40 +0000 Subject: Add tests against MPFR for `ilogb` and `ilogbf` --- .../libm/crates/libm-test/src/mpfloat.rs | 23 ++++++++++++++++++++++ .../libm/crates/libm-test/tests/multiprecision.rs | 6 ------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 8b829800489..ad98fafc87d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -277,6 +277,29 @@ macro_rules! impl_op_for_ty { } } + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + + // `get_exp` follows `frexp` for `0.5 <= |m| < 1.0`. Adjust the exponent by + // one to scale the significand to `1.0 <= |m| < 2.0`. + this.get_exp().map(|v| v - 1).unwrap_or_else(|| { + if this.is_infinite() { + i32::MAX + } else { + // Zero or NaN + i32::MIN + } + }) + } + } + impl MpOp for crate::op::[]::Routine { type MpTy = MpFloat; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 960c370d4b5..42ec965c144 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -51,8 +51,6 @@ libm_macros::for_each_function! { ], skip: [ // FIXME: MPFR tests needed - ilogb, - ilogbf, remquo, remquof, @@ -150,9 +148,5 @@ libm_macros::for_each_function! { scalbnf, yn, ynf, - - // FIXME: MPFR tests needed - ilogb, - ilogbf, ], } -- cgit 1.4.1-3-g733a5 From 7c04b1916a442949523fac7c18ddcd611cee7cbe Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 2 Jan 2025 10:21:35 +0000 Subject: Add more detailed definition output for `update-api-list.py` Update the script to produce, in addition to the simple text list, a JSON file listing routine names, the types they work with, and the source files that contain a function with the routine name. This gets consumed by another script and will be used to determine which extensive CI jobs to run. --- .../libm/etc/function-definitions.json | 764 +++++++++++++++++++++ .../compiler-builtins/libm/etc/update-api-list.py | 246 +++++-- 2 files changed, 945 insertions(+), 65 deletions(-) create mode 100644 library/compiler-builtins/libm/etc/function-definitions.json diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json new file mode 100644 index 00000000000..4b10812c3a7 --- /dev/null +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -0,0 +1,764 @@ +{ + "__comment": "Autogenerated by update-api-list.py. List of files that define a function with a given name. This file is checked in to make it obvious if refactoring breaks things", + "acos": { + "sources": [ + "src/libm_helper.rs", + "src/math/acos.rs" + ], + "type": "f64" + }, + "acosf": { + "sources": [ + "src/math/acosf.rs" + ], + "type": "f32" + }, + "acosh": { + "sources": [ + "src/libm_helper.rs", + "src/math/acosh.rs" + ], + "type": "f64" + }, + "acoshf": { + "sources": [ + "src/math/acoshf.rs" + ], + "type": "f32" + }, + "asin": { + "sources": [ + "src/libm_helper.rs", + "src/math/asin.rs" + ], + "type": "f64" + }, + "asinf": { + "sources": [ + "src/math/asinf.rs" + ], + "type": "f32" + }, + "asinh": { + "sources": [ + "src/libm_helper.rs", + "src/math/asinh.rs" + ], + "type": "f64" + }, + "asinhf": { + "sources": [ + "src/math/asinhf.rs" + ], + "type": "f32" + }, + "atan": { + "sources": [ + "src/libm_helper.rs", + "src/math/atan.rs" + ], + "type": "f64" + }, + "atan2": { + "sources": [ + "src/libm_helper.rs", + "src/math/atan2.rs" + ], + "type": "f64" + }, + "atan2f": { + "sources": [ + "src/math/atan2f.rs" + ], + "type": "f32" + }, + "atanf": { + "sources": [ + "src/math/atanf.rs" + ], + "type": "f32" + }, + "atanh": { + "sources": [ + "src/libm_helper.rs", + "src/math/atanh.rs" + ], + "type": "f64" + }, + "atanhf": { + "sources": [ + "src/math/atanhf.rs" + ], + "type": "f32" + }, + "cbrt": { + "sources": [ + "src/libm_helper.rs", + "src/math/cbrt.rs" + ], + "type": "f64" + }, + "cbrtf": { + "sources": [ + "src/math/cbrtf.rs" + ], + "type": "f32" + }, + "ceil": { + "sources": [ + "src/libm_helper.rs", + "src/math/arch/i586.rs", + "src/math/arch/intrinsics.rs", + "src/math/ceil.rs" + ], + "type": "f64" + }, + "ceilf": { + "sources": [ + "src/math/arch/intrinsics.rs", + "src/math/ceilf.rs" + ], + "type": "f32" + }, + "copysign": { + "sources": [ + "src/libm_helper.rs", + "src/math/copysign.rs", + "src/math/generic/copysign.rs", + "src/math/support/float_traits.rs" + ], + "type": "f64" + }, + "copysignf": { + "sources": [ + "src/math/copysignf.rs", + "src/math/generic/copysign.rs" + ], + "type": "f32" + }, + "cos": { + "sources": [ + "src/libm_helper.rs", + "src/math/cos.rs" + ], + "type": "f64" + }, + "cosf": { + "sources": [ + "src/math/cosf.rs" + ], + "type": "f32" + }, + "cosh": { + "sources": [ + "src/libm_helper.rs", + "src/math/cosh.rs" + ], + "type": "f64" + }, + "coshf": { + "sources": [ + "src/math/coshf.rs" + ], + "type": "f32" + }, + "erf": { + "sources": [ + "src/libm_helper.rs", + "src/math/erf.rs" + ], + "type": "f64" + }, + "erfc": { + "sources": [ + "src/libm_helper.rs", + "src/math/erf.rs" + ], + "type": "f64" + }, + "erfcf": { + "sources": [ + "src/math/erff.rs" + ], + "type": "f32" + }, + "erff": { + "sources": [ + "src/math/erff.rs" + ], + "type": "f32" + }, + "exp": { + "sources": [ + "src/libm_helper.rs", + "src/math/exp.rs", + "src/math/support/float_traits.rs" + ], + "type": "f64" + }, + "exp10": { + "sources": [ + "src/libm_helper.rs", + "src/math/exp10.rs" + ], + "type": "f64" + }, + "exp10f": { + "sources": [ + "src/math/exp10f.rs" + ], + "type": "f32" + }, + "exp2": { + "sources": [ + "src/libm_helper.rs", + "src/math/exp2.rs" + ], + "type": "f64" + }, + "exp2f": { + "sources": [ + "src/math/exp2f.rs" + ], + "type": "f32" + }, + "expf": { + "sources": [ + "src/math/expf.rs" + ], + "type": "f32" + }, + "expm1": { + "sources": [ + "src/libm_helper.rs", + "src/math/expm1.rs" + ], + "type": "f64" + }, + "expm1f": { + "sources": [ + "src/math/expm1f.rs" + ], + "type": "f32" + }, + "fabs": { + "sources": [ + "src/libm_helper.rs", + "src/math/arch/intrinsics.rs", + "src/math/fabs.rs", + "src/math/generic/fabs.rs" + ], + "type": "f64" + }, + "fabsf": { + "sources": [ + "src/math/arch/intrinsics.rs", + "src/math/fabsf.rs", + "src/math/generic/fabs.rs" + ], + "type": "f32" + }, + "fdim": { + "sources": [ + "src/libm_helper.rs", + "src/math/fdim.rs" + ], + "type": "f64" + }, + "fdimf": { + "sources": [ + "src/math/fdimf.rs" + ], + "type": "f32" + }, + "floor": { + "sources": [ + "src/libm_helper.rs", + "src/math/arch/i586.rs", + "src/math/arch/intrinsics.rs", + "src/math/floor.rs" + ], + "type": "f64" + }, + "floorf": { + "sources": [ + "src/math/arch/intrinsics.rs", + "src/math/floorf.rs" + ], + "type": "f32" + }, + "fma": { + "sources": [ + "src/libm_helper.rs", + "src/math/fma.rs" + ], + "type": "f64" + }, + "fmaf": { + "sources": [ + "src/math/fmaf.rs" + ], + "type": "f32" + }, + "fmax": { + "sources": [ + "src/libm_helper.rs", + "src/math/fmax.rs" + ], + "type": "f64" + }, + "fmaxf": { + "sources": [ + "src/math/fmaxf.rs" + ], + "type": "f32" + }, + "fmin": { + "sources": [ + "src/libm_helper.rs", + "src/math/fmin.rs" + ], + "type": "f64" + }, + "fminf": { + "sources": [ + "src/math/fminf.rs" + ], + "type": "f32" + }, + "fmod": { + "sources": [ + "src/libm_helper.rs", + "src/math/fmod.rs" + ], + "type": "f64" + }, + "fmodf": { + "sources": [ + "src/math/fmodf.rs" + ], + "type": "f32" + }, + "frexp": { + "sources": [ + "src/libm_helper.rs", + "src/math/frexp.rs" + ], + "type": "f64" + }, + "frexpf": { + "sources": [ + "src/math/frexpf.rs" + ], + "type": "f32" + }, + "hypot": { + "sources": [ + "src/libm_helper.rs", + "src/math/hypot.rs" + ], + "type": "f64" + }, + "hypotf": { + "sources": [ + "src/math/hypotf.rs" + ], + "type": "f32" + }, + "ilogb": { + "sources": [ + "src/libm_helper.rs", + "src/math/ilogb.rs" + ], + "type": "f64" + }, + "ilogbf": { + "sources": [ + "src/math/ilogbf.rs" + ], + "type": "f32" + }, + "j0": { + "sources": [ + "src/libm_helper.rs", + "src/math/j0.rs" + ], + "type": "f64" + }, + "j0f": { + "sources": [ + "src/math/j0f.rs" + ], + "type": "f32" + }, + "j1": { + "sources": [ + "src/libm_helper.rs", + "src/math/j1.rs" + ], + "type": "f64" + }, + "j1f": { + "sources": [ + "src/math/j1f.rs" + ], + "type": "f32" + }, + "jn": { + "sources": [ + "src/libm_helper.rs", + "src/math/jn.rs" + ], + "type": "f64" + }, + "jnf": { + "sources": [ + "src/math/jnf.rs" + ], + "type": "f32" + }, + "ldexp": { + "sources": [ + "src/libm_helper.rs", + "src/math/ldexp.rs" + ], + "type": "f64" + }, + "ldexpf": { + "sources": [ + "src/math/ldexpf.rs" + ], + "type": "f32" + }, + "lgamma": { + "sources": [ + "src/libm_helper.rs", + "src/math/lgamma.rs" + ], + "type": "f64" + }, + "lgamma_r": { + "sources": [ + "src/libm_helper.rs", + "src/math/lgamma_r.rs" + ], + "type": "f64" + }, + "lgammaf": { + "sources": [ + "src/math/lgammaf.rs" + ], + "type": "f32" + }, + "lgammaf_r": { + "sources": [ + "src/math/lgammaf_r.rs" + ], + "type": "f32" + }, + "log": { + "sources": [ + "src/libm_helper.rs", + "src/math/log.rs" + ], + "type": "f64" + }, + "log10": { + "sources": [ + "src/libm_helper.rs", + "src/math/log10.rs" + ], + "type": "f64" + }, + "log10f": { + "sources": [ + "src/math/log10f.rs" + ], + "type": "f32" + }, + "log1p": { + "sources": [ + "src/libm_helper.rs", + "src/math/log1p.rs" + ], + "type": "f64" + }, + "log1pf": { + "sources": [ + "src/math/log1pf.rs" + ], + "type": "f32" + }, + "log2": { + "sources": [ + "src/libm_helper.rs", + "src/math/log2.rs" + ], + "type": "f64" + }, + "log2f": { + "sources": [ + "src/math/log2f.rs" + ], + "type": "f32" + }, + "logf": { + "sources": [ + "src/math/logf.rs" + ], + "type": "f32" + }, + "modf": { + "sources": [ + "src/libm_helper.rs", + "src/math/modf.rs" + ], + "type": "f64" + }, + "modff": { + "sources": [ + "src/math/modff.rs" + ], + "type": "f32" + }, + "nextafter": { + "sources": [ + "src/libm_helper.rs", + "src/math/nextafter.rs" + ], + "type": "f64" + }, + "nextafterf": { + "sources": [ + "src/math/nextafterf.rs" + ], + "type": "f32" + }, + "pow": { + "sources": [ + "src/libm_helper.rs", + "src/math/pow.rs" + ], + "type": "f64" + }, + "powf": { + "sources": [ + "src/math/powf.rs" + ], + "type": "f32" + }, + "remainder": { + "sources": [ + "src/libm_helper.rs", + "src/math/remainder.rs" + ], + "type": "f64" + }, + "remainderf": { + "sources": [ + "src/math/remainderf.rs" + ], + "type": "f32" + }, + "remquo": { + "sources": [ + "src/libm_helper.rs", + "src/math/remquo.rs" + ], + "type": "f64" + }, + "remquof": { + "sources": [ + "src/math/remquof.rs" + ], + "type": "f32" + }, + "rint": { + "sources": [ + "src/libm_helper.rs", + "src/math/rint.rs" + ], + "type": "f64" + }, + "rintf": { + "sources": [ + "src/math/rintf.rs" + ], + "type": "f32" + }, + "round": { + "sources": [ + "src/libm_helper.rs", + "src/math/round.rs" + ], + "type": "f64" + }, + "roundf": { + "sources": [ + "src/math/roundf.rs" + ], + "type": "f32" + }, + "scalbn": { + "sources": [ + "src/libm_helper.rs", + "src/math/scalbn.rs" + ], + "type": "f64" + }, + "scalbnf": { + "sources": [ + "src/math/scalbnf.rs" + ], + "type": "f32" + }, + "sin": { + "sources": [ + "src/libm_helper.rs", + "src/math/sin.rs" + ], + "type": "f64" + }, + "sincos": { + "sources": [ + "src/libm_helper.rs", + "src/math/sincos.rs" + ], + "type": "f64" + }, + "sincosf": { + "sources": [ + "src/math/sincosf.rs" + ], + "type": "f32" + }, + "sinf": { + "sources": [ + "src/math/sinf.rs" + ], + "type": "f32" + }, + "sinh": { + "sources": [ + "src/libm_helper.rs", + "src/math/sinh.rs" + ], + "type": "f64" + }, + "sinhf": { + "sources": [ + "src/math/sinhf.rs" + ], + "type": "f32" + }, + "sqrt": { + "sources": [ + "src/libm_helper.rs", + "src/math/arch/i686.rs", + "src/math/arch/intrinsics.rs", + "src/math/sqrt.rs" + ], + "type": "f64" + }, + "sqrtf": { + "sources": [ + "src/math/arch/i686.rs", + "src/math/arch/intrinsics.rs", + "src/math/sqrtf.rs" + ], + "type": "f32" + }, + "tan": { + "sources": [ + "src/libm_helper.rs", + "src/math/tan.rs" + ], + "type": "f64" + }, + "tanf": { + "sources": [ + "src/math/tanf.rs" + ], + "type": "f32" + }, + "tanh": { + "sources": [ + "src/libm_helper.rs", + "src/math/tanh.rs" + ], + "type": "f64" + }, + "tanhf": { + "sources": [ + "src/math/tanhf.rs" + ], + "type": "f32" + }, + "tgamma": { + "sources": [ + "src/libm_helper.rs", + "src/math/tgamma.rs" + ], + "type": "f64" + }, + "tgammaf": { + "sources": [ + "src/math/tgammaf.rs" + ], + "type": "f32" + }, + "trunc": { + "sources": [ + "src/libm_helper.rs", + "src/math/arch/intrinsics.rs", + "src/math/trunc.rs" + ], + "type": "f64" + }, + "truncf": { + "sources": [ + "src/math/arch/intrinsics.rs", + "src/math/truncf.rs" + ], + "type": "f32" + }, + "y0": { + "sources": [ + "src/libm_helper.rs", + "src/math/j0.rs" + ], + "type": "f64" + }, + "y0f": { + "sources": [ + "src/math/j0f.rs" + ], + "type": "f32" + }, + "y1": { + "sources": [ + "src/libm_helper.rs", + "src/math/j1.rs" + ], + "type": "f64" + }, + "y1f": { + "sources": [ + "src/math/j1f.rs" + ], + "type": "f32" + }, + "yn": { + "sources": [ + "src/libm_helper.rs", + "src/math/jn.rs" + ], + "type": "f64" + }, + "ynf": { + "sources": [ + "src/math/jnf.rs" + ], + "type": "f32" + } +} diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index 7284a628c6a..a4587aa81d5 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -3,68 +3,166 @@ functions are covered by our macros. """ +import difflib import json import subprocess as sp import sys -import difflib +from dataclasses import dataclass +from glob import glob from pathlib import Path -from typing import Any +from typing import Any, TypeAlias ETC_DIR = Path(__file__).parent +IndexTy: TypeAlias = dict[str, dict[str, Any]] +"""Type of the `index` item in rustdoc's JSON output""" -def get_rustdoc_json() -> dict[Any, Any]: - """Get rustdoc's JSON output for the `libm` crate.""" - - librs_path = ETC_DIR.joinpath("../src/lib.rs") - j = sp.check_output( - [ - "rustdoc", - librs_path, - "--edition=2021", - "--output-format=json", - "-Zunstable-options", - "-o-", - ], - text=True, - ) - j = json.loads(j) - return j - -def list_public_functions() -> list[str]: - """Get a list of public functions from rustdoc JSON output. - - Note that this only finds functions that are reexported in `lib.rs`, this will - need to be adjusted if we need to account for functions that are defined there. +@dataclass +class Crate: + """Representation of public interfaces and function defintion locations in + `libm`. """ - names = [] - index: dict[str, dict[str, Any]] = get_rustdoc_json()["index"] - for item in index.values(): - # Find public items - if item["visibility"] != "public": - continue - - # Find only reexports - if "use" not in item["inner"].keys(): - continue - # Locate the item that is reexported - id = item["inner"]["use"]["id"] - srcitem = index.get(str(id)) - - # External crate - if srcitem is None: - continue - - # Skip if not a function - if "function" not in srcitem["inner"].keys(): - continue - - names.append(srcitem["name"]) - - names.sort() - return names + public_functions: list[str] + """List of all public functions.""" + defs: dict[str, list[str]] + """Map from `name->[source files]` to find all places that define a public + function. We track this to know which tests need to be rerun when specific files + get updated. + """ + types: dict[str, str] + """Map from `name->type`.""" + + def __init__(self) -> None: + self.public_functions = [] + self.defs = {} + self.types = {} + + j = self.get_rustdoc_json() + index: IndexTy = j["index"] + self._init_function_list(index) + self._init_defs(index) + self._init_types() + + @staticmethod + def get_rustdoc_json() -> dict[Any, Any]: + """Get rustdoc's JSON output for the `libm` crate.""" + + j = sp.check_output( + [ + "rustdoc", + "src/lib.rs", + "--edition=2021", + "--document-private-items", + "--output-format=json", + "-Zunstable-options", + "-o-", + ], + cwd=ETC_DIR.parent, + text=True, + ) + j = json.loads(j) + return j + + def _init_function_list(self, index: IndexTy) -> None: + """Get a list of public functions from rustdoc JSON output. + + Note that this only finds functions that are reexported in `lib.rs`, this will + need to be adjusted if we need to account for functions that are defined there, or + glob reexports in other locations. + """ + # Filter out items that are not public + public = [i for i in index.values() if i["visibility"] == "public"] + + # Collect a list of source IDs for reexported items in `lib.rs` or `mod math`. + use = (i for i in public if "use" in i["inner"]) + use = ( + i for i in use if i["span"]["filename"] in ["src/math/mod.rs", "src/lib.rs"] + ) + reexported_ids = [item["inner"]["use"]["id"] for item in use] + + # Collect a list of reexported items that are functions + for id in reexported_ids: + srcitem = index.get(str(id)) + # External crate + if srcitem is None: + continue + + # Skip if not a function + if "function" not in srcitem["inner"]: + continue + + self.public_functions.append(srcitem["name"]) + self.public_functions.sort() + + def _init_defs(self, index: IndexTy) -> None: + defs = {name: set() for name in self.public_functions} + funcs = (i for i in index.values() if "function" in i["inner"]) + funcs = (f for f in funcs if f["name"] in self.public_functions) + for func in funcs: + defs[func["name"]].add(func["span"]["filename"]) + + # A lot of the `arch` module is often configured out so doesn't show up in docs. Use + # string matching as a fallback. + for fname in glob("src/math/arch/**.rs", root_dir=ETC_DIR.parent): + contents = Path(fname).read_text() + + for name in self.public_functions: + if f"fn {name}" in contents: + defs[name].add(fname) + + for name, sources in defs.items(): + base_sources = defs[base_name(name)[0]] + for src in (s for s in base_sources if "generic" in s): + sources.add(src) + + # Sort the set + self.defs = {k: sorted(v) for (k, v) in defs.items()} + + def _init_types(self) -> None: + self.types = {name: base_name(name)[1] for name in self.public_functions} + + def write_function_list(self, check: bool) -> None: + """Collect the list of public functions to a simple text file.""" + output = "# autogenerated by update-api-list.py\n" + for name in self.public_functions: + output += f"{name}\n" + + out_file = ETC_DIR.joinpath("function-list.txt") + + if check: + with open(out_file, "r") as f: + current = f.read() + diff_and_exit(current, output) + else: + with open(out_file, "w") as f: + f.write(output) + + def write_function_defs(self, check: bool) -> None: + """Collect the list of information about public functions to a JSON file .""" + comment = ( + "Autogenerated by update-api-list.py. " + "List of files that define a function with a given name. " + "This file is checked in to make it obvious if refactoring breaks things" + ) + + d = {"__comment": comment} + d |= { + name: {"sources": self.defs[name], "type": self.types[name]} + for name in self.public_functions + } + + out_file = ETC_DIR.joinpath("function-definitions.json") + output = json.dumps(d, indent=4) + "\n" + + if check: + with open(out_file, "r") as f: + current = f.read() + diff_and_exit(current, output) + else: + with open(out_file, "w") as f: + f.write(output) def diff_and_exit(actual: str, expected: str): @@ -84,6 +182,35 @@ def diff_and_exit(actual: str, expected: str): exit(1) +def base_name(name: str) -> tuple[str, str]: + """Return the basename and type from a full function name. Keep in sync with Rust's + `fn base_name`. + """ + known_mappings = [ + ("erff", ("erf", "f32")), + ("erf", ("erf", "f64")), + ("modff", ("modf", "f32")), + ("modf", ("modf", "f64")), + ("lgammaf_r", ("lgamma_r", "f32")), + ("lgamma_r", ("lgamma_r", "f64")), + ] + + found = next((base for (full, base) in known_mappings if full == name), None) + if found is not None: + return found + + if name.endswith("f"): + return (name.rstrip("f"), "f32") + + if name.endswith("f16"): + return (name.rstrip("f16"), "f16") + + if name.endswith("f128"): + return (name.rstrip("f128"), "f128") + + return (name, "f64") + + def main(): """By default overwrite the file. If `--check` is passed, print a diff instead and error if the files are different. @@ -97,20 +224,9 @@ def main(): print("unrecognized arguments") exit(1) - names = list_public_functions() - output = "# autogenerated by update-api-list.py\n" - for name in names: - output += f"{name}\n" - - out_file = ETC_DIR.joinpath("function-list.txt") - - if check: - with open(out_file, "r") as f: - current = f.read() - diff_and_exit(current, output) - else: - with open(out_file, "w") as f: - f.write(output) + crate = Crate() + crate.write_function_list(check) + crate.write_function_defs(check) if __name__ == "__main__": -- cgit 1.4.1-3-g733a5 From 1bbf8b12daf95a2a65c1dd7e16c3a2ceb2680b7c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 11:47:44 +0000 Subject: Add extensive and exhaustive tests Add a generator that will test all inputs for input spaces `u32::MAX` or smaller (e.g. single-argument `f32` routines). For anything larger, still run approximately `u32::MAX` tests, but distribute inputs evenly across the function domain. Since we often only want to run one of these tests at a time, this implementation parallelizes within each test using `rayon`. A custom test runner is used so a progress bar is possible. Specific tests must be enabled by setting the `LIBM_EXTENSIVE_TESTS` environment variable, e.g. LIBM_EXTENSIVE_TESTS=all_f16,cos,cosf cargo run ... Testing on a recent machine, most tests take about two minutes or less. The Bessel functions are quite slow and take closer to 10 minutes, and FMA is increased to run for about the same. --- .../libm/crates/libm-test/Cargo.toml | 9 + .../libm/crates/libm-test/src/gen.rs | 1 + .../libm/crates/libm-test/src/gen/extensive.rs | 153 ++++++++++++++ .../libm/crates/libm-test/src/gen/random.rs | 4 +- .../libm/crates/libm-test/src/lib.rs | 4 +- .../libm/crates/libm-test/src/num.rs | 2 +- .../libm/crates/libm-test/src/run_cfg.rs | 37 +++- .../crates/libm-test/tests/z_extensive/main.rs | 14 ++ .../libm/crates/libm-test/tests/z_extensive/run.rs | 234 +++++++++++++++++++++ 9 files changed, 450 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 9b3ab5c53b1..69e96034ef8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -26,12 +26,14 @@ short-benchmarks = [] [dependencies] anyhow = "1.0.90" az = { version = "1.2.1", optional = true } +indicatif = { version = "0.17.9", default-features = false } libm = { path = "../..", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } paste = "1.0.15" rand = "0.8.5" rand_chacha = "0.3.1" +rayon = "1.10.0" rug = { version = "1.26.1", optional = true, default-features = false, features = ["float", "std"] } [target.'cfg(target_family = "wasm")'.dependencies] @@ -43,11 +45,18 @@ rand = { version = "0.8.5", optional = true } [dev-dependencies] criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } +libtest-mimic = "0.8.1" [[bench]] name = "random" harness = false +[[test]] +# No harness so that we can skip tests at runtime based on env. Prefixed with +# `z` so these tests get run last. +name = "z_extensive" +harness = false + [lints.rust] # Values from the chared config.rs used by `libm` but not the test crate unexpected_cfgs = { level = "warn", check-cfg = [ diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index 83e00f31d28..e2bfcdf34c8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -2,6 +2,7 @@ pub mod domain_logspace; pub mod edge_cases; +pub mod extensive; pub mod random; /// A wrapper to turn any iterator into an `ExactSizeIterator`. Asserts the final result to ensure diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs new file mode 100644 index 00000000000..d8b991b2a5f --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs @@ -0,0 +1,153 @@ +use std::fmt; +use std::ops::RangeInclusive; + +use libm::support::MinInt; + +use crate::domain::HasDomain; +use crate::gen::KnownSize; +use crate::op::OpITy; +use crate::run_cfg::{int_range, iteration_count}; +use crate::{CheckCtx, GeneratorKind, MathOp, logspace}; + +/// Generate a sequence of inputs that either cover the domain in completeness (for smaller float +/// types and single argument functions) or provide evenly spaced inputs across the domain with +/// approximately `u32::MAX` total iterations. +pub trait ExtensiveInput { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator + Send; +} + +/// Construct an iterator from `logspace` and also calculate the total number of steps expected +/// for that iterator. +fn logspace_steps( + start: Op::FTy, + end: Op::FTy, + ctx: &CheckCtx, + argnum: usize, +) -> (impl Iterator + Clone, u64) +where + Op: MathOp, + OpITy: TryFrom, + RangeInclusive>: Iterator, +{ + let max_steps = iteration_count(ctx, GeneratorKind::Extensive, argnum); + let max_steps = OpITy::::try_from(max_steps).unwrap_or(OpITy::::MAX); + let iter = logspace(start, end, max_steps); + + // `logspace` can't implement `ExactSizeIterator` because of the range, but its size hint + // should be accurate (assuming <= usize::MAX iterations). + let size_hint = iter.size_hint(); + assert_eq!(size_hint.0, size_hint.1.unwrap()); + + (iter, size_hint.0.try_into().unwrap()) +} + +macro_rules! impl_extensive_input { + ($fty:ty) => { + impl ExtensiveInput for ($fty,) + where + Op: MathOp, + Op: HasDomain, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let start = Op::DOMAIN.range_start(); + let end = Op::DOMAIN.range_end(); + let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); + let iter0 = iter0.map(|v| (v,)); + KnownSize::new(iter0, steps0) + } + } + + impl ExtensiveInput for ($fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; + let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); + let (iter1, steps1) = logspace_steps::(start, end, ctx, 1); + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + KnownSize::new(iter, count) + } + } + + impl ExtensiveInput for ($fty, $fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; + + let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); + let (iter1, steps1) = logspace_steps::(start, end, ctx, 1); + let (iter2, steps2) = logspace_steps::(start, end, ctx, 2); + + let iter = iter0 + .flat_map(move |first| iter1.clone().map(move |second| (first, second))) + .flat_map(move |(first, second)| { + iter2.clone().map(move |third| (first, second, third)) + }); + let count = steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); + + KnownSize::new(iter, count) + } + } + + impl ExtensiveInput for (i32, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; + + let iter0 = int_range(ctx, GeneratorKind::Extensive, 0); + let steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); + let (iter1, steps1) = logspace_steps::(start, end, ctx, 1); + + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + + KnownSize::new(iter, count) + } + } + + impl ExtensiveInput for ($fty, i32) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; + + let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); + let iter1 = int_range(ctx, GeneratorKind::Extensive, 0); + let steps1 = iteration_count(ctx, GeneratorKind::Extensive, 0); + + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + + KnownSize::new(iter, count) + } + } + }; +} + +impl_extensive_input!(f32); +impl_extensive_input!(f64); + +/// Create a test case iterator for extensive inputs. +pub fn get_test_cases( + ctx: &CheckCtx, +) -> impl ExactSizeIterator + Send + use<'_, Op> +where + Op: MathOp, + Op::RustArgs: ExtensiveInput, +{ + Op::RustArgs::get_cases(ctx) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 6df9443178a..29a9dcd2b08 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -86,7 +86,7 @@ macro_rules! impl_random_input { fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { let count0 = iteration_count(ctx, GeneratorKind::Random, 0); let count1 = iteration_count(ctx, GeneratorKind::Random, 1); - let range0 = int_range(ctx, 0); + let range0 = int_range(ctx, GeneratorKind::Random, 0); let iter = random_ints(count0, range0) .flat_map(move |f1: i32| random_floats(count1).map(move |f2: $fty| (f1, f2))); KnownSize::new(iter, count0 * count1) @@ -97,7 +97,7 @@ macro_rules! impl_random_input { fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { let count0 = iteration_count(ctx, GeneratorKind::Random, 0); let count1 = iteration_count(ctx, GeneratorKind::Random, 1); - let range1 = int_range(ctx, 1); + let range1 = int_range(ctx, GeneratorKind::Random, 1); let iter = random_floats(count0).flat_map(move |f1: $fty| { random_ints(count1, range1.clone()).map(move |f2: i32| (f1, f2)) }); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 8a4e782df70..a940db1d206 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -25,7 +25,8 @@ pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, logspace}; pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; -pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind}; +use run_cfg::EXTENSIVE_MAX_ITERATIONS; +pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, skip_extensive_test}; pub use test_traits::{CheckOutput, Hex, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to @@ -85,6 +86,7 @@ pub fn test_log(s: &str) { writeln!(f, "cargo features: {}", env!("CFG_CARGO_FEATURES")).unwrap(); writeln!(f, "opt level: {}", env!("CFG_OPT_LEVEL")).unwrap(); writeln!(f, "target features: {}", env!("CFG_TARGET_FEATURES")).unwrap(); + writeln!(f, "extensive iterations {}", *EXTENSIVE_MAX_ITERATIONS).unwrap(); Some(f) }); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num.rs b/library/compiler-builtins/libm/crates/libm-test/src/num.rs index eff2fbc1fdd..f693ef02f1f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/num.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/num.rs @@ -215,7 +215,7 @@ fn as_ulp_steps(x: F) -> Option { /// to logarithmic spacing of their values. /// /// Note that this tends to skip negative zero, so that needs to be checked explicitly. -pub fn logspace(start: F, end: F, steps: F::Int) -> impl Iterator +pub fn logspace(start: F, end: F, steps: F::Int) -> impl Iterator + Clone where RangeInclusive: Iterator, { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 9cede0cc722..48a654caaf8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -10,6 +10,22 @@ use crate::{BaseName, FloatTy, Identifier, test_log}; /// The environment variable indicating which extensive tests should be run. pub const EXTENSIVE_ENV: &str = "LIBM_EXTENSIVE_TESTS"; +/// Specify the number of iterations via this environment variable, rather than using the default. +pub const EXTENSIVE_ITER_ENV: &str = "LIBM_EXTENSIVE_ITERATIONS"; + +/// Maximum number of iterations to run for a single routine. +/// +/// The default value of one greater than `u32::MAX` allows testing single-argument `f32` routines +/// and single- or double-argument `f16` routines exhaustively. `f64` and `f128` can't feasibly +/// be tested exhaustively; however, [`EXTENSIVE_ITER_ENV`] can be set to run tests for multiple +/// hours. +pub static EXTENSIVE_MAX_ITERATIONS: LazyLock = LazyLock::new(|| { + let default = 1 << 32; + env::var(EXTENSIVE_ITER_ENV) + .map(|v| v.parse().expect("failed to parse iteration count")) + .unwrap_or(default) +}); + /// Context passed to [`CheckOutput`]. #[derive(Clone, Debug, PartialEq, Eq)] pub struct CheckCtx { @@ -54,6 +70,7 @@ pub enum CheckBasis { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum GeneratorKind { Domain, + Extensive, Random, } @@ -171,8 +188,14 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - let mut total_iterations = match gen_kind { GeneratorKind::Domain => domain_iter_count, GeneratorKind::Random => random_iter_count, + GeneratorKind::Extensive => *EXTENSIVE_MAX_ITERATIONS, }; + // FMA has a huge domain but is reasonably fast to run, so increase iterations. + if ctx.base_name == BaseName::Fma { + total_iterations *= 4; + } + if cfg!(optimizations_enabled) { // Always run at least 10,000 tests. total_iterations = total_iterations.max(10_000); @@ -191,7 +214,7 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - let total = ntests.pow(t_env.input_count.try_into().unwrap()); let seed_msg = match gen_kind { - GeneratorKind::Domain => String::new(), + GeneratorKind::Domain | GeneratorKind::Extensive => String::new(), GeneratorKind::Random => { format!(" using `{SEED_ENV}={}`", str::from_utf8(SEED.as_slice()).unwrap()) } @@ -210,7 +233,7 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - } /// Some tests require that an integer be kept within reasonable limits; generate that here. -pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { +pub fn int_range(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) -> RangeInclusive { let t_env = TestEnv::from_env(ctx); if !matches!(ctx.base_name, BaseName::Jn | BaseName::Yn) { @@ -221,10 +244,17 @@ pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { // The integer argument to `jn` is an iteration count. Limit this to ensure tests can be // completed in a reasonable amount of time. - if t_env.slow_platform || !cfg!(optimizations_enabled) { + let non_extensive_range = if t_env.slow_platform || !cfg!(optimizations_enabled) { (-0xf)..=0xff } else { (-0xff)..=0xffff + }; + + let extensive_range = (-0xfff)..=0xfffff; + + match gen_kind { + GeneratorKind::Extensive => extensive_range, + GeneratorKind::Domain | GeneratorKind::Random => non_extensive_range, } } @@ -241,7 +271,6 @@ pub fn check_near_count(_ctx: &CheckCtx) -> u64 { } /// Check whether extensive actions should be run or skipped. -#[expect(dead_code, reason = "extensive tests have not yet been added")] pub fn skip_extensive_test(ctx: &CheckCtx) -> bool { let t_env = TestEnv::from_env(ctx); !t_env.should_run_extensive diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs new file mode 100644 index 00000000000..3a2af88bd83 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs @@ -0,0 +1,14 @@ +//! `main` is just a wrapper to handle configuration. + +#[cfg(not(feature = "test-multiprecision"))] +fn main() { + eprintln!("multiprecision not enabled; skipping extensive tests"); +} + +#[cfg(feature = "test-multiprecision")] +mod run; + +#[cfg(feature = "test-multiprecision")] +fn main() { + run::run(); +} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs new file mode 100644 index 00000000000..7acff5324ab --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs @@ -0,0 +1,234 @@ +//! Exhaustive tests for `f16` and `f32`, high-iteration for `f64` and `f128`. + +use std::fmt; +use std::io::{self, IsTerminal}; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::time::Duration; + +use indicatif::{ProgressBar, ProgressStyle}; +use libm_test::gen::extensive::{self, ExtensiveInput}; +use libm_test::mpfloat::MpOp; +use libm_test::{ + CheckBasis, CheckCtx, CheckOutput, MathOp, TestResult, TupleCall, skip_extensive_test, +}; +use libtest_mimic::{Arguments, Trial}; +use rayon::prelude::*; + +/// Run the extensive test suite. +pub fn run() { + let mut args = Arguments::from_args(); + // Prevent multiple tests from running in parallel, each test gets parallized internally. + args.test_threads = Some(1); + let tests = register_all_tests(); + + // With default parallelism, the CPU doesn't saturate. We don't need to be nice to + // other processes, so do 1.5x to make sure we use all available resources. + let threads = std::thread::available_parallelism().map(Into::into).unwrap_or(0) * 3 / 2; + rayon::ThreadPoolBuilder::new().num_threads(threads).build_global().unwrap(); + + libtest_mimic::run(&args, tests).exit(); +} + +macro_rules! mp_extensive_tests { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + extra: [$push_to:ident], + ) => { + $(#[$attr])* + register_single_test::(&mut $push_to); + }; +} + +/// Create a list of tests for consumption by `libtest_mimic`. +fn register_all_tests() -> Vec { + let mut all_tests = Vec::new(); + + libm_macros::for_each_function! { + callback: mp_extensive_tests, + extra: [all_tests], + skip: [ + // FIXME: MPFR tests needed + remquo, + remquof, + + // FIXME: test needed, see + // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 + nextafter, + nextafterf, + ], + } + + all_tests +} + +/// Add a single test to the list. +fn register_single_test(all: &mut Vec) +where + Op: MathOp + MpOp, + Op::RustArgs: ExtensiveInput + Send, +{ + let test_name = format!("mp_extensive_{}", Op::NAME); + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); + let skip = skip_extensive_test(&ctx); + + let runner = move || { + if !cfg!(optimizations_enabled) { + panic!("extensive tests should be run with --release"); + } + + let res = run_single_test::(); + let e = match res { + Ok(()) => return Ok(()), + Err(e) => e, + }; + + // Format with the `Debug` implementation so we get the error cause chain, and print it + // here so we see the result immediately (rather than waiting for all tests to conclude). + let e = format!("{e:?}"); + eprintln!("failure testing {}:{e}\n", Op::IDENTIFIER); + + Err(e.into()) + }; + + all.push(Trial::test(test_name, runner).with_ignored_flag(skip)); +} + +/// Test runner for a signle routine. +fn run_single_test() -> TestResult +where + Op: MathOp + MpOp, + Op::RustArgs: ExtensiveInput + Send, +{ + // Small delay before printing anything so other output from the runner has a chance to flush. + std::thread::sleep(Duration::from_millis(500)); + eprintln!(); + + let completed = AtomicU64::new(0); + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); + let cases = &mut extensive::get_test_cases::(&ctx); + let total: u64 = cases.len().try_into().unwrap(); + let pb = Progress::new(Op::NAME, total); + + let test_single_chunk = |mp_vals: &mut Op::MpTy, input_vec: Vec| -> TestResult { + for input in input_vec { + // Test the input. + let mp_res = Op::run(mp_vals, input); + let crate_res = input.call(Op::ROUTINE); + crate_res.validate(mp_res, input, &ctx)?; + + let completed = completed.fetch_add(1, Ordering::Relaxed) + 1; + pb.update(completed, input); + } + + Ok(()) + }; + + // Chunk the cases so Rayon doesn't switch threads between each iterator item. 50k seems near + // a performance sweet spot. Ideally we would reuse these allocations rather than discarding, + // but that is difficult with Rayon's API. + let chunk_size = 50_000; + let chunks = std::iter::from_fn(move || { + let mut v = Vec::with_capacity(chunk_size); + v.extend(cases.take(chunk_size)); + (!v.is_empty()).then_some(v) + }); + + // Run the actual tests + let res = chunks.par_bridge().try_for_each_init(Op::new_mp, test_single_chunk); + + let real_total = completed.load(Ordering::Relaxed); + pb.complete(real_total); + + if res.is_ok() && real_total != total { + // Provide a warning if our estimate needs to be updated. + panic!("total run {real_total} does not match expected {total}"); + } + + res +} + +/// Wrapper around a `ProgressBar` that handles styles and non-TTY messages. +struct Progress { + pb: ProgressBar, + name_padded: String, + final_style: ProgressStyle, + is_tty: bool, +} + +impl Progress { + const PB_TEMPLATE: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \ + {human_pos:>13}/{human_len:13} {per_sec:18} eta {eta:8} {msg}"; + const PB_TEMPLATE_FINAL: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \ + {human_pos:>13}/{human_len:13} {per_sec:18} done in {elapsed_precise}"; + + fn new(name: &str, total: u64) -> Self { + eprintln!("starting extensive tests for `{name}`"); + let name_padded = format!("{name:9}"); + let is_tty = io::stderr().is_terminal(); + + let initial_style = + ProgressStyle::with_template(&Self::PB_TEMPLATE.replace("NAME", &name_padded)) + .unwrap() + .progress_chars("##-"); + + let final_style = + ProgressStyle::with_template(&Self::PB_TEMPLATE_FINAL.replace("NAME", &name_padded)) + .unwrap() + .progress_chars("##-"); + + let pb = ProgressBar::new(total); + pb.set_style(initial_style); + + Self { pb, final_style, name_padded, is_tty } + } + + fn update(&self, completed: u64, input: impl fmt::Debug) { + // Infrequently update the progress bar. + if completed % 20_000 == 0 { + self.pb.set_position(completed); + } + + if completed % 500_000 == 0 { + self.pb.set_message(format!("input: {input:<24?}")); + } + + if !self.is_tty && completed % 5_000_000 == 0 { + let len = self.pb.length().unwrap_or_default(); + eprintln!( + "[{elapsed:3?}s {percent:3.0}%] {name} \ + {human_pos:>10}/{human_len:<10} {per_sec:14.2}/s eta {eta:4}s {input:<24?}", + elapsed = self.pb.elapsed().as_secs(), + percent = completed as f32 * 100.0 / len as f32, + name = self.name_padded, + human_pos = completed, + human_len = len, + per_sec = self.pb.per_sec(), + eta = self.pb.eta().as_secs() + ); + } + } + + fn complete(self, real_total: u64) { + self.pb.set_style(self.final_style); + self.pb.set_position(real_total); + self.pb.abandon(); + + if !self.is_tty { + let len = self.pb.length().unwrap_or_default(); + eprintln!( + "[{elapsed:3}s {percent:3.0}%] {name} \ + {human_pos:>10}/{human_len:<10} {per_sec:14.2}/s done in {elapsed_precise}", + elapsed = self.pb.elapsed().as_secs(), + percent = real_total as f32 * 100.0 / len as f32, + name = self.name_padded, + human_pos = real_total, + human_len = len, + per_sec = self.pb.per_sec(), + elapsed_precise = self.pb.elapsed().as_secs(), + ); + } + + eprintln!(); + } +} -- cgit 1.4.1-3-g733a5 From 05a1f4a982b09f8c9293e5c8cf4300a995432a6f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 11:47:53 +0000 Subject: Update precision based on failures from extensive tests --- .../libm/crates/libm-test/src/precision.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 4a6ca8af7b6..696bb373578 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -55,7 +55,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Bn::Asin => 1, Bn::Asinh => 2, Bn::Atan => 1, - Bn::Atan2 => 1, + Bn::Atan2 => 2, Bn::Atanh => 2, Bn::Cbrt => 1, Bn::Cos => 1, @@ -187,6 +187,20 @@ impl MaybeOverride<(f32,)> for SpecialCase { return XFAIL; } + if (ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR) + && input.0 > 4e36 + && expected.is_infinite() + && !actual.is_infinite() + { + // This result should saturate but we return a finite value. + return XFAIL; + } + + if ctx.base_name == BaseName::J0 && input.0 < -1e34 { + // Errors get huge close to -inf + return XFAIL; + } + maybe_check_nan_bits(actual, expected, ctx) } @@ -248,6 +262,11 @@ impl MaybeOverride<(f64,)> for SpecialCase { return XFAIL; } + if ctx.base_name == BaseName::J0 && input.0 < -1e300 { + // Errors get huge close to -inf + return XFAIL; + } + maybe_check_nan_bits(actual, expected, ctx) } @@ -364,6 +383,7 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { } } } + impl MaybeOverride<(i32, f64)> for SpecialCase { fn check_float( input: (i32, f64), -- cgit 1.4.1-3-g733a5 From f8a184e6af9540e0329fd50944c604d82ba1fb14 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 2 Jan 2025 10:25:27 +0000 Subject: Run extensive tests in CI when relevant files change Add a CI job with a dynamically calculated matrix that runs extensive jobs on changed files. This makes use of the new `function-definitions.json` file to determine which changed files require full tests for a routine to run. --- .../libm/.github/workflows/main.yml | 59 +++++++- .../libm/ci/calculate-exhaustive-matrix.py | 148 +++++++++++++++++++++ 2 files changed, 206 insertions(+), 1 deletion(-) create mode 100755 library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 023ec58c06a..1b2fd12ba87 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -14,7 +14,7 @@ env: jobs: test: name: Build and test - timeout-minutes: 20 + timeout-minutes: 25 strategy: fail-fast: false matrix: @@ -186,6 +186,62 @@ jobs: rustup component add rustfmt - run: cargo fmt -- --check + # Determine which extensive tests should be run based on changed files. + calculate_extensive_matrix: + name: Calculate job matrix + runs-on: ubuntu-24.04 + outputs: + matrix: ${{ steps.script.outputs.matrix }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 100 + - name: Fetch pull request ref + run: git fetch origin "$GITHUB_REF:$GITHUB_REF" + - run: python3 ci/calculate-exhaustive-matrix.py >> "$GITHUB_OUTPUT" + id: script + + extensive: + name: Extensive tests for ${{ matrix.ty }} + needs: + # Wait on `clippy` so we have some confidence that the crate will build + - clippy + - calculate_extensive_matrix + runs-on: ubuntu-24.04 + timeout-minutes: 80 + strategy: + matrix: + # Use the output from `calculate_extensive_matrix` to calculate the matrix + # FIXME: it would be better to run all jobs (i.e. all types) but mark those that + # didn't change as skipped, rather than completely excluding the job. However, + # this is not currently possible https://github.com/actions/runner/issues/1985. + include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }} + env: + CHANGED: ${{ matrix.changed }} + steps: + - uses: actions/checkout@v4 + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + - uses: Swatinem/rust-cache@v2 + - name: Download musl source + run: ./ci/download-musl.sh + - name: Run extensive tests + run: | + echo "Changed: '$CHANGED'" + if [ -z "$CHANGED" ]; then + echo "No tests to run, exiting." + exit + fi + + LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \ + --features test-multiprecision,unstable \ + --release -- extensive + - name: Print test logs if available + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + success: needs: - test @@ -193,6 +249,7 @@ jobs: - benchmarks - msrv - rustfmt + - extensive runs-on: ubuntu-24.04 # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its diff --git a/library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py b/library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py new file mode 100755 index 00000000000..8b42f9389f9 --- /dev/null +++ b/library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 +"""Calculate which exhaustive tests should be run as part of CI. + +This dynamically prepares a list of routines that had a source file change based on +git history. +""" + +import subprocess as sp +import sys +import json +from dataclasses import dataclass +from os import getenv +from pathlib import Path +from typing import TypedDict + + +REPO_ROOT = Path(__file__).parent.parent +GIT = ["git", "-C", REPO_ROOT] + +# Don't run exhaustive tests if these files change, even if they contaiin a function +# definition. +IGNORE_FILES = [ + "src/math/support/", + "src/libm_helper.rs", + "src/math/arch/intrinsics.rs", +] + +TYPES = ["f16", "f32", "f64", "f128"] + + +class FunctionDef(TypedDict): + """Type for an entry in `function-definitions.json`""" + + sources: list[str] + type: str + + +@dataclass +class Context: + gh_ref: str | None + changed: list[Path] + defs: dict[str, FunctionDef] + + def __init__(self) -> None: + self.gh_ref = getenv("GITHUB_REF") + self.changed = [] + self._init_change_list() + + with open(REPO_ROOT.joinpath("etc/function-definitions.json")) as f: + defs = json.load(f) + + defs.pop("__comment", None) + self.defs = defs + + def _init_change_list(self): + """Create a list of files that have been changed. This uses GITHUB_REF if + available, otherwise a diff between `HEAD` and `master`. + """ + + # For pull requests, GitHub creates a ref `refs/pull/1234/merge` (1234 being + # the PR number), and sets this as `GITHUB_REF`. + ref = self.gh_ref + eprint(f"using ref `{ref}`") + if ref is None or "merge" not in ref: + # If the ref is not for `merge` then we are not in PR CI + eprint("No diff available for ref") + return + + # The ref is for a dummy merge commit. We can extract the merge base by + # inspecting all parents (`^@`). + merge_sha = sp.check_output( + GIT + ["show-ref", "--hash", ref], text=True + ).strip() + merge_log = sp.check_output(GIT + ["log", "-1", merge_sha], text=True) + eprint(f"Merge:\n{merge_log}\n") + + parents = ( + sp.check_output(GIT + ["rev-parse", f"{merge_sha}^@"], text=True) + .strip() + .splitlines() + ) + assert len(parents) == 2, f"expected two-parent merge but got:\n{parents}" + base = parents[0].strip() + incoming = parents[1].strip() + + eprint(f"base: {base}, incoming: {incoming}") + textlist = sp.check_output( + GIT + ["diff", base, incoming, "--name-only"], text=True + ) + self.changed = [Path(p) for p in textlist.splitlines()] + + @staticmethod + def _ignore_file(fname: str) -> bool: + return any(fname.startswith(pfx) for pfx in IGNORE_FILES) + + def changed_routines(self) -> dict[str, list[str]]: + """Create a list of routines for which one or more files have been updated, + separated by type. + """ + routines = set() + for name, meta in self.defs.items(): + # Don't update if changes to the file should be ignored + sources = (f for f in meta["sources"] if not self._ignore_file(f)) + + # Select changed files + changed = [f for f in sources if Path(f) in self.changed] + + if len(changed) > 0: + eprint(f"changed files for {name}: {changed}") + routines.add(name) + + ret = {} + for r in sorted(routines): + ret.setdefault(self.defs[r]["type"], []).append(r) + + return ret + + def make_workflow_output(self) -> str: + """Create a JSON object a list items for each type's changed files, if any + did change, and the routines that were affected by the change. + """ + changed = self.changed_routines() + ret = [] + for ty in TYPES: + ty_changed = changed.get(ty, []) + item = { + "ty": ty, + "changed": ",".join(ty_changed), + } + ret.append(item) + output = json.dumps({"matrix": ret}, separators=(",", ":")) + eprint(f"output: {output}") + return output + + +def eprint(*args, **kwargs): + """Print to stderr.""" + print(*args, file=sys.stderr, **kwargs) + + +def main(): + ctx = Context() + output = ctx.make_workflow_output() + print(f"matrix={output}") + + +if __name__ == "__main__": + main() -- cgit 1.4.1-3-g733a5 From aabb7d9dcc9037579df402cbb45abbac2e3f551c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 2 Jan 2025 21:41:58 +0000 Subject: Enable `f16` and `f128` when creating the API change list Additionally, read glob output as absoulte paths. This enables the script to work properly even when invoked from a different directory. --- library/compiler-builtins/libm/etc/update-api-list.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index a4587aa81d5..67f73e59cf1 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -13,6 +13,7 @@ from pathlib import Path from typing import Any, TypeAlias ETC_DIR = Path(__file__).parent +ROOT_DIR = ETC_DIR.parent IndexTy: TypeAlias = dict[str, dict[str, Any]] """Type of the `index` item in rustdoc's JSON output""" @@ -56,10 +57,12 @@ class Crate: "--edition=2021", "--document-private-items", "--output-format=json", + "--cfg=f16_enabled", + "--cfg=f128_enabled", "-Zunstable-options", "-o-", ], - cwd=ETC_DIR.parent, + cwd=ROOT_DIR, text=True, ) j = json.loads(j) @@ -105,8 +108,8 @@ class Crate: # A lot of the `arch` module is often configured out so doesn't show up in docs. Use # string matching as a fallback. - for fname in glob("src/math/arch/**.rs", root_dir=ETC_DIR.parent): - contents = Path(fname).read_text() + for fname in glob("src/math/arch/**.rs", root_dir=ROOT_DIR): + contents = (ROOT_DIR.joinpath(fname)).read_text() for name in self.public_functions: if f"fn {name}" in contents: -- cgit 1.4.1-3-g733a5 From 42c7ace5ba74b78bb06765438a9dd6f6fa57d58f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 2 Jan 2025 21:11:50 +0000 Subject: Add `fabsf16`, `fabsf128`, `copysignf16`, and `copysignf128` Use the generic implementations to provide these simple methods. --- library/compiler-builtins/libm/src/libm_helper.rs | 24 ++++++++++++-- .../libm/src/math/copysignf128.rs | 8 +++++ .../compiler-builtins/libm/src/math/copysignf16.rs | 8 +++++ library/compiler-builtins/libm/src/math/fabs.rs | 1 + library/compiler-builtins/libm/src/math/fabsf.rs | 1 + .../compiler-builtins/libm/src/math/fabsf128.rs | 37 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/fabsf16.rs | 37 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 20 ++++++++++++ 8 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/copysignf128.rs create mode 100644 library/compiler-builtins/libm/src/math/copysignf16.rs create mode 100644 library/compiler-builtins/libm/src/math/fabsf128.rs create mode 100644 library/compiler-builtins/libm/src/math/fabsf16.rs diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index 52d0c4c2a11..f087267e46c 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -30,7 +30,7 @@ macro_rules! libm_helper { } }; - ({$($func:tt);*}) => { + ({$($func:tt;)*}) => { $( libm_helper! { $func } )* @@ -103,7 +103,7 @@ libm_helper! { (fn trunc(x: f32) -> (f32); => truncf); (fn y0(x: f32) -> (f32); => y0f); (fn y1(x: f32) -> (f32); => y1f); - (fn yn(n: i32, x: f32) -> (f32); => ynf) + (fn yn(n: i32, x: f32) -> (f32); => ynf); } } @@ -166,6 +166,24 @@ libm_helper! { (fn trunc(x: f64) -> (f64); => trunc); (fn y0(x: f64) -> (f64); => y0); (fn y1(x: f64) -> (f64); => y1); - (fn yn(n: i32, x: f64) -> (f64); => yn) + (fn yn(n: i32, x: f64) -> (f64); => yn); + } +} + +#[cfg(f16_enabled)] +libm_helper! { + f16, + funcs: { + (fn copysign(x: f16, y: f16) -> (f16); => copysignf16); + (fn fabs(x: f16) -> (f16); => fabsf16); + } +} + +#[cfg(f128_enabled)] +libm_helper! { + f128, + funcs: { + (fn copysign(x: f128, y: f128) -> (f128); => copysignf128); + (fn fabs(x: f128) -> (f128); => fabsf128); } } diff --git a/library/compiler-builtins/libm/src/math/copysignf128.rs b/library/compiler-builtins/libm/src/math/copysignf128.rs new file mode 100644 index 00000000000..7bd81d42b2e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/copysignf128.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f128) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf128(x: f128, y: f128) -> f128 { + super::generic::copysign(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/copysignf16.rs b/library/compiler-builtins/libm/src/math/copysignf16.rs new file mode 100644 index 00000000000..82065868601 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/copysignf16.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f16) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf16(x: f16, y: f16) -> f16 { + super::generic::copysign(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 6687fdcc356..46c0d88a5c0 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -1,4 +1,5 @@ /// Absolute value (magnitude) (f64) +/// /// Calculates the absolute value (magnitude) of the argument `x`, /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 99bb5b5f1c9..d5775b600d9 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -1,4 +1,5 @@ /// Absolute value (magnitude) (f32) +/// /// Calculates the absolute value (magnitude) of the argument `x`, /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/library/compiler-builtins/libm/src/math/fabsf128.rs b/library/compiler-builtins/libm/src/math/fabsf128.rs new file mode 100644 index 00000000000..ef531bd91a4 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fabsf128.rs @@ -0,0 +1,37 @@ +/// Absolute value (magnitude) (f128) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf128(x: f128) -> f128 { + select_implementation! { + name: fabsf, + use_intrinsic: target_arch = "wasm32", + args: x, + } + + super::generic::fabs(x) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf128(-1.0), 1.0); + assert_eq!(fabsf128(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf128(f128::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf128(f), 0.0); + } + for f in [f128::INFINITY, f128::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf128(f), f128::INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/fabsf16.rs b/library/compiler-builtins/libm/src/math/fabsf16.rs new file mode 100644 index 00000000000..eb41f7391e5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fabsf16.rs @@ -0,0 +1,37 @@ +/// Absolute value (magnitude) (f16) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf16(x: f16) -> f16 { + select_implementation! { + name: fabsf, + use_intrinsic: target_arch = "wasm32", + args: x, + } + + super::generic::fabs(x) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf16(-1.0), 1.0); + assert_eq!(fabsf16(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf16(f16::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf16(f), 0.0); + } + for f in [f16::INFINITY, f16::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf16(f), f16::INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 9003a834288..5baf35e4245 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -339,6 +339,26 @@ pub use self::tgammaf::tgammaf; pub use self::trunc::trunc; pub use self::truncf::truncf; +cfg_if! { + if #[cfg(f16_enabled)] { + mod copysignf16; + mod fabsf16; + + pub use self::copysignf16::copysignf16; + pub use self::fabsf16::fabsf16; + } +} + +cfg_if! { + if #[cfg(f128_enabled)] { + mod copysignf128; + mod fabsf128; + + pub use self::copysignf128::copysignf128; + pub use self::fabsf128::fabsf128; + } +} + #[inline] fn get_high_word(x: f64) -> u32 { (x.to_bits() >> 32) as u32 -- cgit 1.4.1-3-g733a5 From 6b5e8b20f0ca6573307f68f4fdbfc177bcb3850f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 00:12:53 +0000 Subject: Add test infrastructure for `f16` and `f128` Update test traits to support `f16` and `f128`, as applicable. Add the new routines (`fabs` and `copysign` for `f16` and `f128`) to the list of all operations. --- .../libm/crates/libm-macros/src/shared.rs | 28 ++++++++ .../libm/crates/libm-test/Cargo.toml | 2 +- .../libm/crates/libm-test/benches/random.rs | 47 ++++++++----- .../libm/crates/libm-test/src/domain.rs | 12 ++++ .../libm/crates/libm-test/src/gen/extensive.rs | 4 ++ .../libm/crates/libm-test/src/gen/random.rs | 4 ++ .../libm/crates/libm-test/src/mpfloat.rs | 77 +++++++++++++++------- .../libm/crates/libm-test/src/precision.rs | 32 +++++++++ .../libm/crates/libm-test/src/test_traits.rs | 6 ++ .../crates/libm-test/tests/compare_built_musl.rs | 2 + .../libm/crates/libm-test/tests/multiprecision.rs | 2 + .../libm/etc/function-definitions.json | 28 ++++++++ .../compiler-builtins/libm/etc/function-list.txt | 4 ++ 13 files changed, 205 insertions(+), 43 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index ef0f188014b..16547404fff 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -4,6 +4,13 @@ use std::fmt; use std::sync::LazyLock; const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] = &[ + ( + // `fn(f16) -> f16` + FloatTy::F16, + Signature { args: &[Ty::F16], returns: &[Ty::F16] }, + None, + &["fabsf16"], + ), ( // `fn(f32) -> f32` FloatTy::F32, @@ -28,6 +35,20 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "tgamma", "trunc", "y0", "y1", ], ), + ( + // `fn(f128) -> f128` + FloatTy::F128, + Signature { args: &[Ty::F128], returns: &[Ty::F128] }, + None, + &["fabsf128"], + ), + ( + // `(f16, f16) -> f16` + FloatTy::F16, + Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, + None, + &["copysignf16"], + ), ( // `(f32, f32) -> f32` FloatTy::F32, @@ -64,6 +85,13 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "remainder", ], ), + ( + // `(f128, f128) -> f128` + FloatTy::F128, + Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, + None, + &["copysignf128"], + ), ( // `(f32, f32, f32) -> f32` FloatTy::F32, diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 69e96034ef8..2761d3d5213 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -8,7 +8,7 @@ publish = false default = ["unstable-float"] # Propagated from libm because this affects which functions we test. -unstable-float = ["libm/unstable-float"] +unstable-float = ["libm/unstable-float", "rug?/nightly-float"] # Generate tests which are random inputs and the outputs are calculated with # musl libc. diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 23f42945583..cd1e2d2ccc6 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -20,7 +20,7 @@ macro_rules! musl_rand_benches { ( fn_name: $fn_name:ident, attrs: [$($attr:meta),*], - fn_extra: $skip_on_i586:expr, + fn_extra: ($skip_on_i586:expr, $musl_fn:expr), ) => { paste::paste! { $(#[$attr])* @@ -28,15 +28,15 @@ macro_rules! musl_rand_benches { type Op = libm_test::op::$fn_name::Routine; #[cfg(feature = "build-musl")] - let musl_extra = MuslExtra { - musl_fn: Some(musl_math_sys::$fn_name as libm_test::OpCFn), - skip_on_i586: $skip_on_i586 + let musl_extra = MuslExtra::> { + musl_fn: $musl_fn, + skip_on_i586: $skip_on_i586, }; #[cfg(not(feature = "build-musl"))] let musl_extra = MuslExtra { musl_fn: None, - skip_on_i586: $skip_on_i586 + skip_on_i586: $skip_on_i586, }; bench_one::(c, musl_extra); @@ -67,7 +67,10 @@ where break; } - let musl_res = input.call(musl_extra.musl_fn.unwrap()); + let Some(musl_fn) = musl_extra.musl_fn else { + continue; + }; + let musl_res = input.call(musl_fn); let crate_res = input.call(Op::ROUTINE); crate_res.validate(musl_res, input, &ctx).context(name).unwrap(); @@ -91,15 +94,16 @@ where // Don't test against musl if it is not available #[cfg(feature = "build-musl")] { - let musl_fn = musl_extra.musl_fn.unwrap(); - group.bench_function("musl", |b| { - b.iter(|| { - let f = black_box(musl_fn); - for input in benchvec.iter().copied() { - input.call(f); - } - }) - }); + if let Some(musl_fn) = musl_extra.musl_fn { + group.bench_function("musl", |b| { + b.iter(|| { + let f = black_box(musl_fn); + for input in benchvec.iter().copied() { + input.call(f); + } + }) + }); + } } } @@ -107,9 +111,16 @@ libm_macros::for_each_function! { callback: musl_rand_benches, skip: [], fn_extra: match MACRO_FN_NAME { - // FIXME(correctness): wrong result on i586 - exp10 | exp10f | exp2 | exp2f => true, - _ => false + // We pass a tuple of `(skip_on_i586, musl_fn)` + + // FIXME(correctness): exp functions have the wrong result on i586 + exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)), + + // Musl does not provide `f16` and `f128` functions + copysignf16 | copysignf128 | fabsf16 | fabsf128 => (false, None), + + // By default we never skip (false) and always have a musl function available + _ => (false, Some(musl_math_sys::MACRO_FN_NAME)) } } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index 7b5a01b9683..52393d40243 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -187,3 +187,15 @@ impl HasDomain for crate::op::lgammaf_r::Routine { impl HasDomain for crate::op::lgamma_r::Routine { const DOMAIN: Domain = Domain::::LGAMMA; } + +/* Not all `f16` and `f128` functions exist yet so we can't easily use the macros. */ + +#[cfg(f16_enabled)] +impl HasDomain for crate::op::fabsf16::Routine { + const DOMAIN: Domain = Domain::::UNBOUNDED; +} + +#[cfg(f128_enabled)] +impl HasDomain for crate::op::fabsf128::Routine { + const DOMAIN: Domain = Domain::::UNBOUNDED; +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs index d8b991b2a5f..d724226e95b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs @@ -138,8 +138,12 @@ macro_rules! impl_extensive_input { }; } +#[cfg(f16_enabled)] +impl_extensive_input!(f16); impl_extensive_input!(f32); impl_extensive_input!(f64); +#[cfg(f128_enabled)] +impl_extensive_input!(f128); /// Create a test case iterator for extensive inputs. pub fn get_test_cases( diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 29a9dcd2b08..6b08e560dff 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -107,8 +107,12 @@ macro_rules! impl_random_input { }; } +#[cfg(f16_enabled)] +impl_random_input!(f16); impl_random_input!(f32); impl_random_input!(f64); +#[cfg(f128_enabled)] +impl_random_input!(f128); /// Create a test case iterator. pub fn get_test_cases( diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index ad98fafc87d..f2b7b2f25da 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -137,6 +137,7 @@ libm_macros::for_each_function! { fmod, fmodf, frexp, frexpf, ilogb, ilogbf, jn, jnf, ldexp, ldexpf, lgamma_r, lgammaf_r, modf, modff, nextafter, nextafterf, pow,powf, remquo, remquof, scalbn, scalbnf, sincos, sincosf, yn, ynf, + copysignf16, copysignf128, fabsf16, fabsf128, ], fn_extra: match MACRO_FN_NAME { // Remap function names that are different between mpfr and libm @@ -157,10 +158,8 @@ libm_macros::for_each_function! { /// Implement unary functions that don't have a `_round` version macro_rules! impl_no_round { // Unary matcher - ($($fn_name:ident, $rug_name:ident;)*) => { + ($($fn_name:ident => $rug_name:ident;)*) => { paste::paste! { - // Implement for both f32 and f64 - $( impl_no_round!{ @inner_unary [< $fn_name f >], $rug_name } )* $( impl_no_round!{ @inner_unary $fn_name, $rug_name } )* } }; @@ -183,33 +182,34 @@ macro_rules! impl_no_round { } impl_no_round! { - fabs, abs_mut; - ceil, ceil_mut; - floor, floor_mut; - rint, round_even_mut; // FIXME: respect rounding mode - round, round_mut; - trunc, trunc_mut; + ceil => ceil_mut; + ceilf => ceil_mut; + fabs => abs_mut; + fabsf => abs_mut; + floor => floor_mut; + floorf => floor_mut; + rint => round_even_mut; // FIXME: respect rounding mode + rintf => round_even_mut; // FIXME: respect rounding mode + round => round_mut; + roundf => round_mut; + trunc => trunc_mut; + truncf => trunc_mut; +} + +#[cfg(f16_enabled)] +impl_no_round! { + fabsf16 => abs_mut; +} + +#[cfg(f128_enabled)] +impl_no_round! { + fabsf128 => abs_mut; } /// Some functions are difficult to do in a generic way. Implement them here. macro_rules! impl_op_for_ty { ($fty:ty, $suffix:literal) => { paste::paste! { - impl MpOp for crate::op::[]::Routine { - type MpTy = (MpFloat, MpFloat); - - fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0.assign(input.0); - this.1.assign(input.1); - this.0.copysign_mut(&this.1); - prep_retval::(&mut this.0, Ordering::Equal) - } - } - impl MpOp for crate::op::[]::Routine { type MpTy = (MpFloat, MpFloat); @@ -379,9 +379,38 @@ macro_rules! impl_op_for_ty { }; } +/// Version of `impl_op_for_ty` with only functions that have `f16` and `f128` implementations. +macro_rules! impl_op_for_ty_all { + ($fty:ty, $suffix:literal) => { + paste::paste! { + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + this.0.copysign_mut(&this.1); + prep_retval::(&mut this.0, Ordering::Equal) + } + } + } + }; +} + impl_op_for_ty!(f32, "f"); impl_op_for_ty!(f64, ""); +#[cfg(f16_enabled)] +impl_op_for_ty_all!(f16, "f16"); +impl_op_for_ty_all!(f32, "f"); +impl_op_for_ty_all!(f64, ""); +#[cfg(f128_enabled)] +impl_op_for_ty_all!(f128, "f128"); + // `lgamma_r` is not a simple suffix so we can't use the above macro. impl MpOp for crate::op::lgamma_r::Routine { type MpTy = MpFloat; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 696bb373578..f8c3a7b8fcf 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -157,6 +157,9 @@ pub trait MaybeOverride { } } +#[cfg(f16_enabled)] +impl MaybeOverride<(f16,)> for SpecialCase {} + impl MaybeOverride<(f32,)> for SpecialCase { fn check_float( input: (f32,), @@ -290,6 +293,9 @@ impl MaybeOverride<(f64,)> for SpecialCase { } } +#[cfg(f128_enabled)] +impl MaybeOverride<(f128,)> for SpecialCase {} + /// Check NaN bits if the function requires it fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { if !(ctx.base_name == BaseName::Fabs || ctx.base_name == BaseName::Copysign) { @@ -317,6 +323,19 @@ fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Opt } } +#[cfg(f16_enabled)] +impl MaybeOverride<(f16, f16)> for SpecialCase { + fn check_float( + input: (f16, f16), + _actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_skip_binop_nan(input, expected, ctx) + } +} + impl MaybeOverride<(f32, f32)> for SpecialCase { fn check_float( input: (f32, f32), @@ -341,6 +360,19 @@ impl MaybeOverride<(f64, f64)> for SpecialCase { } } +#[cfg(f128_enabled)] +impl MaybeOverride<(f128, f128)> for SpecialCase { + fn check_float( + input: (f128, f128), + _actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_skip_binop_nan(input, expected, ctx) + } +} + /// Musl propagates NaNs if one is provided as the input, but we return the other input. // F1 and F2 are always the same type, this is just to please generics fn maybe_skip_binop_nan( diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 261d1f2540d..0a4baa2e36f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -303,6 +303,12 @@ where impl_float!(f32, f64); +#[cfg(f16_enabled)] +impl_float!(f16); + +#[cfg(f128_enabled)] +impl_float!(f128); + /* trait implementations for compound types */ /// Implement `CheckOutput` for combinations of types. diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index ecd379a0a68..3e11d322acd 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -46,6 +46,8 @@ where libm_macros::for_each_function! { callback: musl_rand_tests, + // Musl does not support `f16` and `f128` on all platforms. + skip: [copysignf16, copysignf128, fabsf16, fabsf128], attributes: [ #[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586 [exp10, exp10f, exp2, exp2f, rint] diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 42ec965c144..7961b080258 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -120,6 +120,8 @@ libm_macros::for_each_function! { atan2f, copysign, copysignf, + copysignf16, + copysignf128, fdim, fdimf, fma, diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 4b10812c3a7..0b2d6214f76 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -136,6 +136,20 @@ ], "type": "f32" }, + "copysignf128": { + "sources": [ + "src/math/copysignf128.rs", + "src/math/generic/copysign.rs" + ], + "type": "f128" + }, + "copysignf16": { + "sources": [ + "src/math/copysignf16.rs", + "src/math/generic/copysign.rs" + ], + "type": "f16" + }, "cos": { "sources": [ "src/libm_helper.rs", @@ -258,6 +272,20 @@ ], "type": "f32" }, + "fabsf128": { + "sources": [ + "src/math/fabsf128.rs", + "src/math/generic/fabs.rs" + ], + "type": "f128" + }, + "fabsf16": { + "sources": [ + "src/math/fabsf16.rs", + "src/math/generic/fabs.rs" + ], + "type": "f16" + }, "fdim": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 51f5b221c26..0a1bbab244d 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -19,6 +19,8 @@ ceil ceilf copysign copysignf +copysignf128 +copysignf16 cos cosf cosh @@ -37,6 +39,8 @@ expm1 expm1f fabs fabsf +fabsf128 +fabsf16 fdim fdimf floor -- cgit 1.4.1-3-g733a5 From a3363785ea5e496e8dd925abe611169a6c11cbab Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 28 Dec 2024 09:52:19 +0000 Subject: Add domain and edge case tests to musl This provides an increase in test coverage on platforms that cannot test against MPFR. --- .../libm/crates/libm-test/src/lib.rs | 4 +- .../libm/crates/libm-test/src/op.rs | 2 + .../crates/libm-test/tests/compare_built_musl.rs | 97 +++++++++++++++++++++- 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index a940db1d206..251114a0dcb 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -23,7 +23,9 @@ use std::time::SystemTime; pub use f8_impl::f8; pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, logspace}; -pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty}; +pub use op::{ + BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustFn, OpRustRet, Ty, +}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; use run_cfg::EXTENSIVE_MAX_ITERATIONS; pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, skip_extensive_test}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index ee61eb0b840..8329d3424c3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -96,6 +96,8 @@ pub type OpFTy = ::FTy; pub type OpITy = <::FTy as Float>::Int; /// Access the associated `CFn` type from an op (helper to avoid ambiguous associated types). pub type OpCFn = ::CFn; +/// Access the associated `CRet` type from an op (helper to avoid ambiguous associated types). +pub type OpCRet = ::CRet; /// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types). pub type OpRustFn = ::RustFn; /// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 3e11d322acd..b91d7f9f50d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -9,8 +9,9 @@ // There are some targets we can't build musl for #![cfg(feature = "build-musl")] -use libm_test::gen::random; +use libm_test::domain::HasDomain; use libm_test::gen::random::RandomInput; +use libm_test::gen::{domain_logspace, edge_cases, random}; use libm_test::{CheckBasis, CheckCtx, CheckOutput, MathOp, TupleCall}; macro_rules! musl_rand_tests { @@ -53,3 +54,97 @@ libm_macros::for_each_function! { [exp10, exp10f, exp2, exp2f, rint] ], } + +/// Test against musl with generators from a domain. +macro_rules! musl_domain_tests { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + ) => { + paste::paste! { + #[test] + $(#[$attr])* + fn [< musl_edge_case_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + domain_test_runner::( + edge_cases::get_test_cases::, + musl_math_sys::$fn_name, + ); + } + + #[test] + $(#[$attr])* + fn [< musl_logspace_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + domain_test_runner::( + domain_logspace::get_test_cases::, + musl_math_sys::$fn_name, + ); + } + } + }; +} + +/// Test a single routine against domaine-aware inputs. +fn domain_test_runner(gen: impl FnOnce(&CheckCtx) -> I, musl_fn: Op::CFn) +where + Op: MathOp, + Op: HasDomain, + I: Iterator, +{ + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl); + let cases = gen(&ctx); + + for input in cases { + let musl_res = input.call(musl_fn); + let crate_res = input.call(Op::ROUTINE); + + crate_res.validate(musl_res, input, &ctx).unwrap(); + } +} + +libm_macros::for_each_function! { + callback: musl_domain_tests, + attributes: [], + skip: [ + // Functions with multiple inputs + atan2, + atan2f, + copysign, + copysignf, + copysignf16, + copysignf128, + fdim, + fdimf, + fma, + fmaf, + fmax, + fmaxf, + fmin, + fminf, + fmod, + fmodf, + hypot, + hypotf, + jn, + jnf, + ldexp, + ldexpf, + nextafter, + nextafterf, + pow, + powf, + remainder, + remainderf, + remquo, + remquof, + scalbn, + scalbnf, + yn, + ynf, + + // Not provided by musl + fabsf16, + fabsf128, + ], +} -- cgit 1.4.1-3-g733a5 From 4b014bff40c0fffe97fd64f854c152c0d33b4973 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 09:26:27 +0000 Subject: Add an override for failing ceil/floor tests on i586 --- .../compiler-builtins/libm/crates/libm-test/src/precision.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index f8c3a7b8fcf..817ea0fae64 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -270,6 +270,16 @@ impl MaybeOverride<(f64,)> for SpecialCase { return XFAIL; } + if (ctx.fn_ident == Identifier::Ceil || ctx.fn_ident == Identifier::Floor) + && expected.eq_repr(F::NEG_ZERO) + && actual.eq_repr(F::ZERO) + && cfg!(x86_no_sse) + { + // FIXME: the x87 implementations do not keep the distinction between -0.0 and 0.0. + // See https://github.com/rust-lang/libm/pull/404#issuecomment-2572399955 + return XFAIL; + } + maybe_check_nan_bits(actual, expected, ctx) } -- cgit 1.4.1-3-g733a5 From 449d41a24fffd282b088c4b2967e5c3e9899189c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 09:46:16 +0000 Subject: Loosen precision on i586 based on new tests --- .../libm/crates/libm-test/src/precision.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 817ea0fae64..1a66a430c50 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -106,7 +106,11 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { match ctx.fn_ident { Id::Asinh => ulp = 3, Id::Asinhf => ulp = 3, + Id::Exp10 | Id::Exp10f => ulp = 1_000_000, + Id::Exp2 | Id::Exp2f => ulp = 10_000_000, + Id::Fmaf => ulp = 1, Id::Log1p | Id::Log1pf => ulp = 2, + Id::Rint => ulp = 100_000, Id::Round => ulp = 1, Id::Tan => ulp = 2, _ => (), @@ -271,15 +275,23 @@ impl MaybeOverride<(f64,)> for SpecialCase { } if (ctx.fn_ident == Identifier::Ceil || ctx.fn_ident == Identifier::Floor) + && cfg!(x86_no_sse) && expected.eq_repr(F::NEG_ZERO) && actual.eq_repr(F::ZERO) - && cfg!(x86_no_sse) { // FIXME: the x87 implementations do not keep the distinction between -0.0 and 0.0. // See https://github.com/rust-lang/libm/pull/404#issuecomment-2572399955 return XFAIL; } + if (ctx.fn_ident == Identifier::Exp10 || ctx.fn_ident == Identifier::Exp2) + && cfg!(x86_no_sse) + { + // FIXME: i586 has very imprecise results with ULP > u32::MAX for these + // operations so we can't reasonably provide a limit. + return XFAIL; + } + maybe_check_nan_bits(actual, expected, ctx) } -- cgit 1.4.1-3-g733a5 From a882639e7f76d6f599840fa23e691c4dc30cc5f2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 20:17:38 +0000 Subject: ci: Only update the github ref for pull requests On master, this fetch fails with: fatal: refusing to fetch into branch 'refs/heads/master' checked out at '/home/runner/work/libm/libm' Just skip the command when this shouldn't be needed. --- library/compiler-builtins/libm/.github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 1b2fd12ba87..320800f2ea7 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -198,6 +198,7 @@ jobs: fetch-depth: 100 - name: Fetch pull request ref run: git fetch origin "$GITHUB_REF:$GITHUB_REF" + if: github.event_name == 'pull_request' - run: python3 ci/calculate-exhaustive-matrix.py >> "$GITHUB_OUTPUT" id: script -- cgit 1.4.1-3-g733a5 From a9407010b4fc2c5971f639d65b3c6585f2779be5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 05:15:40 +0000 Subject: Enable MPFR tests on i586 MPFR does build and run correctly without SSE, but requires `force-cross` be enabled. --- .../compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile | 2 +- library/compiler-builtins/libm/ci/run.sh | 2 +- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile index 3b0bfc0d3d9..37e206a84fc 100644 --- a/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -2,4 +2,4 @@ FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc-multilib libc6-dev ca-certificates + gcc-multilib m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 7e514a1cd2e..70fc271f194 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -45,8 +45,8 @@ case "$target" in # FIXME(ci): we should be able to enable aarch64 Linux here once GHA # support rolls out. x86_64*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; - # i686 works fine, i586 does not i686*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; + i586*) extra_flags="$extra_flags --features libm-test/test-multiprecision --features gmp-mpfr-sys/force-cross" ;; # Apple aarch64 is native aarch64*apple*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; esac diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 2761d3d5213..371beb19aa5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -12,7 +12,7 @@ unstable-float = ["libm/unstable-float", "rug?/nightly-float"] # Generate tests which are random inputs and the outputs are calculated with # musl libc. -test-multiprecision = ["dep:az", "dep:rug"] +test-multiprecision = ["dep:az", "dep:rug", "dep:gmp-mpfr-sys"] # Build our own musl for testing and benchmarks build-musl = ["dep:musl-math-sys"] @@ -26,6 +26,7 @@ short-benchmarks = [] [dependencies] anyhow = "1.0.90" az = { version = "1.2.1", optional = true } +gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false, features = ["mpfr"] } indicatif = { version = "0.17.9", default-features = false } libm = { path = "../..", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } -- cgit 1.4.1-3-g733a5 From 05b87887f46fb81a8ac3d06cd582d8220ddd8702 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 20:27:48 +0000 Subject: Increase the allowed precision for failing tests on i586 These will need to be fixed, for now just xfail them so this doesn't block better test coverage. --- library/compiler-builtins/libm/crates/libm-test/src/precision.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 1a66a430c50..03bf7ceccc3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -104,11 +104,14 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { // In some cases, our implementation is less accurate than musl on i586. if cfg!(x86_no_sse) { match ctx.fn_ident { + // FIXME(#401): these need to be correctly rounded but are not. + Id::Fmaf => ulp = 1, + Id::Fdim => ulp = 1, + Id::Asinh => ulp = 3, Id::Asinhf => ulp = 3, Id::Exp10 | Id::Exp10f => ulp = 1_000_000, Id::Exp2 | Id::Exp2f => ulp = 10_000_000, - Id::Fmaf => ulp = 1, Id::Log1p | Id::Log1pf => ulp = 2, Id::Rint => ulp = 100_000, Id::Round => ulp = 1, -- cgit 1.4.1-3-g733a5 From ac9fec04efbe4e65ab15b868dcc9a95fcc3a7280 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 21:57:29 +0000 Subject: Switch from using `unstable-intrinsics` to `intrinsics_enabled` Unlike `unstable-intrinsics`, `intrinsics_enabled` gets disabled with `force-soft-floats` which is what we want here. --- library/compiler-builtins/libm/src/math/arch/intrinsics.rs | 6 ++---- library/compiler-builtins/libm/src/math/support/float_traits.rs | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/arch/intrinsics.rs b/library/compiler-builtins/libm/src/math/arch/intrinsics.rs index 1cf9291f4c7..733af0f1a96 100644 --- a/library/compiler-builtins/libm/src/math/arch/intrinsics.rs +++ b/library/compiler-builtins/libm/src/math/arch/intrinsics.rs @@ -12,13 +12,11 @@ pub fn ceilf(x: f32) -> f32 { } pub fn fabs(x: f64) -> f64 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::fabsf64(x) } + x.abs() } pub fn fabsf(x: f32) -> f32 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::fabsf32(x) } + x.abs() } pub fn floor(x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 3b5be4fa3d3..69705096658 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -200,7 +200,7 @@ macro_rules! float_impl { fn abs(self) -> Self { cfg_if! { // FIXME(msrv): `abs` is available in `core` starting with 1.85. - if #[cfg(feature = "unstable-intrinsics")] { + if #[cfg(intrinsics_enabled)] { self.abs() } else { super::super::generic::fabs(self) @@ -210,7 +210,7 @@ macro_rules! float_impl { fn copysign(self, other: Self) -> Self { cfg_if! { // FIXME(msrv): `copysign` is available in `core` starting with 1.85. - if #[cfg(feature = "unstable-intrinsics")] { + if #[cfg(intrinsics_enabled)] { self.copysign(other) } else { super::super::generic::copysign(self, other) -- cgit 1.4.1-3-g733a5 From b5a217b11c3ef6f4b22f82b67b0b06dc9cb739c9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 22:52:01 +0000 Subject: Remove an unused `feature = "force-soft-floats"` gate --- library/compiler-builtins/libm/src/math/arch/i686.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/arch/i686.rs b/library/compiler-builtins/libm/src/math/arch/i686.rs index 80f7face174..ad54d8b61d7 100644 --- a/library/compiler-builtins/libm/src/math/arch/i686.rs +++ b/library/compiler-builtins/libm/src/math/arch/i686.rs @@ -1,7 +1,5 @@ //! Architecture-specific support for x86-32 and x86-64 with SSE2 -#![cfg(not(feature = "force-soft-floats"))] - #[cfg(target_arch = "x86")] use core::arch::x86::*; #[cfg(target_arch = "x86_64")] -- cgit 1.4.1-3-g733a5 From c5741455771caef8810428647b39b91f5b81d3ea Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 23:17:38 +0000 Subject: Don't use intrinsics abs for `f16` and `f128` on wasm32 This configuration was duplicated from `fabs` and `fabsf`, but wasm is unlikely to have an intrinsic lowering for these float types. So, just always use the generic. --- library/compiler-builtins/libm/src/math/fabsf128.rs | 6 ------ library/compiler-builtins/libm/src/math/fabsf16.rs | 6 ------ 2 files changed, 12 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fabsf128.rs b/library/compiler-builtins/libm/src/math/fabsf128.rs index ef531bd91a4..46429ca4940 100644 --- a/library/compiler-builtins/libm/src/math/fabsf128.rs +++ b/library/compiler-builtins/libm/src/math/fabsf128.rs @@ -4,12 +4,6 @@ /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabsf128(x: f128) -> f128 { - select_implementation! { - name: fabsf, - use_intrinsic: target_arch = "wasm32", - args: x, - } - super::generic::fabs(x) } diff --git a/library/compiler-builtins/libm/src/math/fabsf16.rs b/library/compiler-builtins/libm/src/math/fabsf16.rs index eb41f7391e5..eee42ac6a3c 100644 --- a/library/compiler-builtins/libm/src/math/fabsf16.rs +++ b/library/compiler-builtins/libm/src/math/fabsf16.rs @@ -4,12 +4,6 @@ /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabsf16(x: f16) -> f16 { - select_implementation! { - name: fabsf, - use_intrinsic: target_arch = "wasm32", - args: x, - } - super::generic::fabs(x) } -- cgit 1.4.1-3-g733a5 From f4f942c3e9aa46a3bd729dcf9721c5762936af9f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 01:10:04 +0000 Subject: Update the `libm` submodule --- library/compiler-builtins/build.rs | 49 ++++++++++++++++++++++++++++++---- library/compiler-builtins/configure.rs | 8 ++++++ library/compiler-builtins/libm | 2 +- library/compiler-builtins/src/math.rs | 1 + 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 22ec9e4d275..2bb8651d7f7 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -14,12 +14,9 @@ fn main() { configure_check_cfg(); configure_f16_f128(&target); - println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); + configure_libm(&target); - // Activate libm's unstable features to make full use of Nightly. - println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\", \"force-soft-floats\"))"); - println!("cargo:rustc-cfg=feature=\"unstable\""); - println!("cargo:rustc-cfg=feature=\"force-soft-floats\""); + println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); // Emscripten's runtime includes all the builtins if target.os == "emscripten" { @@ -104,6 +101,48 @@ fn main() { } } +/// Run configuration for `libm` since it is included directly. +/// +/// Much of this is copied from `libm/configure.rs`. +fn configure_libm(target: &Target) { + println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)"); + println!("cargo:rustc-check-cfg=cfg(arch_enabled)"); + println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); + println!("cargo:rustc-check-cfg=cfg(feature, values(\"unstable-public-internals\"))"); + + // Always use intrinsics + println!("cargo:rustc-cfg=intrinsics_enabled"); + + // The arch module may contain assembly. + if cfg!(feature = "no-asm") { + println!("cargo:rustc-cfg=feature=\"force-soft-floats\""); + } else { + println!("cargo:rustc-cfg=arch_enabled"); + } + + println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); + if target.opt_level >= 2 { + println!("cargo:rustc-cfg=optimizations_enabled"); + } + + // Config shorthands + println!("cargo:rustc-check-cfg=cfg(x86_no_sse)"); + if target.arch == "x86" && !target.features.iter().any(|f| f == "sse") { + // Shorthand to detect i586 targets + println!("cargo:rustc-cfg=x86_no_sse"); + } + + println!( + "cargo:rustc-env=CFG_CARGO_FEATURES={:?}", + target.cargo_features + ); + println!("cargo:rustc-env=CFG_OPT_LEVEL={}", target.opt_level); + println!("cargo:rustc-env=CFG_TARGET_FEATURES={:?}", target.features); + + // Activate libm's unstable features to make full use of Nightly. + println!("cargo:rustc-cfg=feature=\"unstable-intrinsics\""); +} + fn aarch64_symbol(ordering: Ordering) -> &'static str { match ordering { Ordering::Relaxed => "relax", diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index e20c717ec75..6cfbe11c2ed 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -6,6 +6,8 @@ use std::env; #[allow(dead_code)] pub struct Target { pub triple: String, + pub opt_level: u8, + pub cargo_features: Vec, pub os: String, pub arch: String, pub vendor: String, @@ -22,10 +24,16 @@ impl Target { "big" => false, x => panic!("unknown endian {x}"), }; + let cargo_features = env::vars() + .filter_map(|(name, _value)| name.strip_prefix("CARGO_FEATURE_").map(ToOwned::to_owned)) + .map(|s| s.to_lowercase().replace("_", "-")) + .collect(); Self { triple: env::var("TARGET").unwrap(), os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + opt_level: env::var("OPT_LEVEL").unwrap().parse().unwrap(), + cargo_features, arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index f4e5b38aee0..424c3ece1a7 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit f4e5b38aee0e0c592a82ed45b21cd068c9b6c89a +Subproject commit 424c3ece1a7546de8530fa9d0fbf90d3b182cd18 diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 477dfe36516..da208239e83 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -1,3 +1,4 @@ +#[rustfmt::skip] #[allow(dead_code)] #[allow(unused_imports)] #[allow(clippy::all)] -- cgit 1.4.1-3-g733a5 From f3ad123a090f50991796cf766ab00ec24210c8bb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 00:19:26 +0000 Subject: Replace "intrinsic" config with "arch" config WASM is the only architecture we use `intrinsics::` for. We probably don't want to do this for any other architectures since it is better to use assembly, or work toward getting the functions available in `core`. To more accurately reflect the relationship between arch and intrinsics, make wasm32 an `arch` module and call the intrinsics from there. --- .../libm/etc/function-definitions.json | 20 ++++----- .../libm/src/math/arch/intrinsics.rs | 50 --------------------- .../compiler-builtins/libm/src/math/arch/mod.rs | 8 ++-- .../compiler-builtins/libm/src/math/arch/wasm32.rs | 52 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/ceil.rs | 2 +- library/compiler-builtins/libm/src/math/ceilf.rs | 2 +- library/compiler-builtins/libm/src/math/fabs.rs | 2 +- library/compiler-builtins/libm/src/math/fabsf.rs | 2 +- library/compiler-builtins/libm/src/math/floor.rs | 2 +- library/compiler-builtins/libm/src/math/floorf.rs | 2 +- library/compiler-builtins/libm/src/math/sqrt.rs | 6 ++- library/compiler-builtins/libm/src/math/sqrtf.rs | 6 ++- .../libm/src/math/support/macros.rs | 25 ++--------- library/compiler-builtins/libm/src/math/trunc.rs | 2 +- library/compiler-builtins/libm/src/math/truncf.rs | 2 +- 15 files changed, 85 insertions(+), 98 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/arch/intrinsics.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/wasm32.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 0b2d6214f76..3cf7e0fed3d 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -108,14 +108,14 @@ "sources": [ "src/libm_helper.rs", "src/math/arch/i586.rs", - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/ceil.rs" ], "type": "f64" }, "ceilf": { "sources": [ - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/ceilf.rs" ], "type": "f32" @@ -258,7 +258,7 @@ "fabs": { "sources": [ "src/libm_helper.rs", - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/fabs.rs", "src/math/generic/fabs.rs" ], @@ -266,7 +266,7 @@ }, "fabsf": { "sources": [ - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/fabsf.rs", "src/math/generic/fabs.rs" ], @@ -303,14 +303,14 @@ "sources": [ "src/libm_helper.rs", "src/math/arch/i586.rs", - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/floor.rs" ], "type": "f64" }, "floorf": { "sources": [ - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/floorf.rs" ], "type": "f32" @@ -683,7 +683,7 @@ "sources": [ "src/libm_helper.rs", "src/math/arch/i686.rs", - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/sqrt.rs" ], "type": "f64" @@ -691,7 +691,7 @@ "sqrtf": { "sources": [ "src/math/arch/i686.rs", - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/sqrtf.rs" ], "type": "f32" @@ -738,14 +738,14 @@ "trunc": { "sources": [ "src/libm_helper.rs", - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/trunc.rs" ], "type": "f64" }, "truncf": { "sources": [ - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/truncf.rs" ], "type": "f32" diff --git a/library/compiler-builtins/libm/src/math/arch/intrinsics.rs b/library/compiler-builtins/libm/src/math/arch/intrinsics.rs deleted file mode 100644 index 733af0f1a96..00000000000 --- a/library/compiler-builtins/libm/src/math/arch/intrinsics.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Config is needed for times when this module is available but we don't call everything -#![allow(dead_code)] - -pub fn ceil(x: f64) -> f64 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::ceilf64(x) } -} - -pub fn ceilf(x: f32) -> f32 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::ceilf32(x) } -} - -pub fn fabs(x: f64) -> f64 { - x.abs() -} - -pub fn fabsf(x: f32) -> f32 { - x.abs() -} - -pub fn floor(x: f64) -> f64 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::floorf64(x) } -} - -pub fn floorf(x: f32) -> f32 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::floorf32(x) } -} - -pub fn sqrt(x: f64) -> f64 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::sqrtf64(x) } -} - -pub fn sqrtf(x: f32) -> f32 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::sqrtf32(x) } -} - -pub fn trunc(x: f64) -> f64 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::truncf64(x) } -} - -pub fn truncf(x: f32) -> f32 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::truncf32(x) } -} diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index cf9547117b8..bd79ae1c69c 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -5,14 +5,14 @@ //! is used when calling the function directly. This helps anyone who uses `libm` directly, as //! well as improving things when these routines are called as part of other implementations. -#[cfg(intrinsics_enabled)] -pub mod intrinsics; - // Most implementations should be defined here, to ensure they are not made available when // soft floats are required. #[cfg(arch_enabled)] cfg_if! { - if #[cfg(target_feature = "sse2")] { + if #[cfg(all(target_arch = "wasm32", intrinsics_enabled))] { + mod wasm32; + pub use wasm32::{ceil, ceilf, fabs, fabsf, floor, floorf, sqrt, sqrtf, trunc, truncf}; + } else if #[cfg(target_feature = "sse2")] { mod i686; pub use i686::{sqrt, sqrtf}; } diff --git a/library/compiler-builtins/libm/src/math/arch/wasm32.rs b/library/compiler-builtins/libm/src/math/arch/wasm32.rs new file mode 100644 index 00000000000..09df8624e8b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/wasm32.rs @@ -0,0 +1,52 @@ +//! Wasm asm is not stable; just use intrinsics for operations that have asm routine equivalents. +//! +//! Note that we need to be absolutely certain that everything here lowers to assembly operations, +//! otherwise libcalls will be recursive. + +pub fn ceil(x: f64) -> f64 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::ceilf64(x) } +} + +pub fn ceilf(x: f32) -> f32 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::ceilf32(x) } +} + +pub fn fabs(x: f64) -> f64 { + x.abs() +} + +pub fn fabsf(x: f32) -> f32 { + x.abs() +} + +pub fn floor(x: f64) -> f64 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::floorf64(x) } +} + +pub fn floorf(x: f32) -> f32 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::floorf32(x) } +} + +pub fn sqrt(x: f64) -> f64 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::sqrtf64(x) } +} + +pub fn sqrtf(x: f32) -> f32 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::sqrtf32(x) } +} + +pub fn trunc(x: f64) -> f64 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::truncf64(x) } +} + +pub fn truncf(x: f32) -> f32 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::truncf32(x) } +} diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index b0576f3dc1f..398bfee47a2 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -10,8 +10,8 @@ const TOINT: f64 = 1. / f64::EPSILON; pub fn ceil(x: f64) -> f64 { select_implementation! { name: ceil, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), - use_intrinsic: target_arch = "wasm32", args: x, } diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 9eb2ec07a42..9e8e78e3e53 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -7,7 +7,7 @@ use core::f32; pub fn ceilf(x: f32) -> f32 { select_implementation! { name: ceilf, - use_intrinsic: target_arch = "wasm32", + use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 46c0d88a5c0..22867fab056 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -6,7 +6,7 @@ pub fn fabs(x: f64) -> f64 { select_implementation! { name: fabs, - use_intrinsic: target_arch = "wasm32", + use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index d5775b600d9..e5820a26c52 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -6,7 +6,7 @@ pub fn fabsf(x: f32) -> f32 { select_implementation! { name: fabsf, - use_intrinsic: target_arch = "wasm32", + use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index e478f6d5472..2823bf44d9c 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -10,8 +10,8 @@ const TOINT: f64 = 1. / f64::EPSILON; pub fn floor(x: f64) -> f64 { select_implementation! { name: floor, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), - use_intrinsic: target_arch = "wasm32", args: x, } diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index bd1570c8696..23a18c0f737 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -7,7 +7,7 @@ use core::f32; pub fn floorf(x: f32) -> f32 { select_implementation! { name: floorf, - use_intrinsic: target_arch = "wasm32", + use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 3f1a10fddc6..2fd7070b110 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -83,8 +83,10 @@ use core::f64; pub fn sqrt(x: f64) -> f64 { select_implementation! { name: sqrt, - use_arch: target_feature = "sse2", - use_intrinsic: target_arch = "wasm32", + use_arch: any( + all(target_arch = "wasm32", intrinsics_enabled), + target_feature = "sse2" + ), args: x, } diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 23f9a844329..319335163ae 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -18,8 +18,10 @@ pub fn sqrtf(x: f32) -> f32 { select_implementation! { name: sqrtf, - use_arch: target_feature = "sse2", - use_intrinsic: target_arch = "wasm32", + use_arch: any( + all(target_arch = "wasm32", intrinsics_enabled), + target_feature = "sse2" + ), args: x, } diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index 9441eace529..f5094b9da89 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -39,13 +39,8 @@ macro_rules! cfg_if { (@__identity $($tokens:tt)*) => { $($tokens)* }; } -/// Choose among using an intrinsic, an arch-specific implementation, and the function body. -/// Returns directly if the intrinsic or arch is used, otherwise continue with the rest of the -/// function. -/// -/// Specify a `use_intrinsic` meta field if the intrinsic is (1) available on the platforms (i.e. -/// LLVM lowers it without libcalls that may recurse), (2) it is likely to be more performant. -/// Intrinsics require wrappers in the `math::arch::intrinsics` module. +/// Choose between using an arch-specific implementation and the function body. Returns directly +/// if the arch implementation is used, otherwise continue with the rest of the function. /// /// Specify a `use_arch` meta field if an architecture-specific implementation is provided. /// These live in the `math::arch::some_target_arch` module. @@ -53,8 +48,7 @@ macro_rules! cfg_if { /// Specify a `use_arch_required` meta field if something architecture-specific must be used /// regardless of feature configuration (`force-soft-floats`). /// -/// The passed meta options do not need to account for relevant Cargo features -/// (`unstable-intrinsics`, `arch`, `force-soft-floats`), this macro handles that part. +/// The passed meta options do not need to account for the `arch` target feature. macro_rules! select_implementation { ( name: $fn_name:ident, @@ -64,15 +58,12 @@ macro_rules! select_implementation { // Configuration meta for when to use the arch module regardless of whether softfloats // have been requested. $( use_arch_required: $use_arch_required:meta, )? - // Configuration meta for when to call intrinsics and let LLVM figure it out - $( use_intrinsic: $use_intrinsic:meta, )? args: $($arg:ident),+ , ) => { // FIXME: these use paths that are a pretty fragile (`super`). We should figure out // something better w.r.t. how this is vendored into compiler-builtins. // However, we do need a few things from `arch` that are used even with soft floats. - // select_implementation! { @cfg $($use_arch_required)?; if true { @@ -89,16 +80,6 @@ macro_rules! select_implementation { return super::arch::$fn_name( $($arg),+ ); } } - - // Never use intrinsics if we are forcing soft floats, and only enable with the - // `unstable-intrinsics` feature. - #[cfg(intrinsics_enabled)] - select_implementation! { - @cfg $( $use_intrinsic )?; - if true { - return super::arch::intrinsics::$fn_name( $($arg),+ ); - } - } }; // Coalesce helper to construct an expression only if a config is provided diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index d85bffb40e4..7e5c4f2c2ae 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -7,7 +7,7 @@ use core::f64; pub fn trunc(x: f64) -> f64 { select_implementation! { name: trunc, - use_intrinsic: target_arch = "wasm32", + use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index 82017b87b7c..b491747d999 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -7,7 +7,7 @@ use core::f32; pub fn truncf(x: f32) -> f32 { select_implementation! { name: truncf, - use_intrinsic: target_arch = "wasm32", + use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } -- cgit 1.4.1-3-g733a5 From e6ea2802d17ab8a388ebb9b38ea87267ba15235c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 01:49:52 +0000 Subject: Update the `libm` submodule --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 424c3ece1a7..44770b96920 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 424c3ece1a7546de8530fa9d0fbf90d3b182cd18 +Subproject commit 44770b96920557baf38990d2ee4142e166be579d -- cgit 1.4.1-3-g733a5 From 1b0adb233c5c249ed4282bd54302abf6ebd29ca1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 01:57:53 +0000 Subject: chore: release v0.1.141 --- library/compiler-builtins/CHANGELOG.md | 9 +++++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index f888591437b..ccfc97d1bb0 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.141](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.140...compiler_builtins-v0.1.141) - 2025-01-07 + +### Other + +- Update the `libm` submodule +- Fix new `clippy::precedence` errors +- Rename `EXP_MAX` to `EXP_SAT` +- Shorten prefixes for float constants + ## [0.1.140](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.139...compiler_builtins-v0.1.140) - 2024-12-26 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 33d5c06b78c..a0c4cfaaffd 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.140" +version = "0.1.141" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 0359db23c7ad1e8ee023150b938a4e28110b245e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 02:54:37 +0000 Subject: Increase the allowed ULP for `tgammaf` Extensive tests report that the precision isn't actually 0: ---- mp_extensive_tgammaf ---- input: (-0.00063536887,) (0xba268ee2,) expected: -1574.4668 0xc4c4cef0 actual: -1574.4667 0xc4c4ceef Caused by: ulp 1 > 0 Update ULP to reflect this. After this change, `tgammaf` extensive tests pass. --- library/compiler-builtins/libm/crates/libm-test/src/precision.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 03bf7ceccc3..cbe4bdf8848 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -44,7 +44,6 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { // Operations that aren't required to be exact, but our implementations are. Bn::Cbrt if ctx.fn_ident != Id::Cbrt => 0, - Bn::Tgamma if ctx.fn_ident != Id::Tgamma => 0, // Bessel functions have large inaccuracies. Bn::J0 | Bn::J1 | Bn::Y0 | Bn::Y1 | Bn::Jn | Bn::Yn => 8_000_000, @@ -78,6 +77,8 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Bn::Sinh => 2, Bn::Tan => 1, Bn::Tanh => 2, + // tgammaf has higher accuracy than tgamma. + Bn::Tgamma if ctx.fn_ident != Id::Tgamma => 1, Bn::Tgamma => 20, }; -- cgit 1.4.1-3-g733a5 From 76714a5657d8e876a41f49e87c8008110304fd61 Mon Sep 17 00:00:00 2001 From: beetrees Date: Tue, 7 Jan 2025 13:51:15 +0000 Subject: Make extensive tests exhaustive if there are enough iterations available --- .../crates/libm-test/src/gen/domain_logspace.rs | 2 +- .../libm/crates/libm-test/src/gen/extensive.rs | 237 +++++++++++++++------ .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/num.rs | 89 +++++++- .../libm/crates/libm-test/tests/z_extensive/run.rs | 3 +- 5 files changed, 252 insertions(+), 81 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs index 3d8a3e7fe73..c6963ad436a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs @@ -27,5 +27,5 @@ where let start = domain.range_start(); let end = domain.range_end(); let steps = OpITy::::try_from(ntests).unwrap_or(OpITy::::MAX); - logspace(start, end, steps).map(|v| (v,)) + logspace(start, end, steps).0.map(|v| (v,)) } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs index d724226e95b..fb709e54684 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs @@ -1,19 +1,18 @@ use std::fmt; use std::ops::RangeInclusive; -use libm::support::MinInt; +use libm::support::{Float, MinInt}; use crate::domain::HasDomain; -use crate::gen::KnownSize; use crate::op::OpITy; use crate::run_cfg::{int_range, iteration_count}; -use crate::{CheckCtx, GeneratorKind, MathOp, logspace}; +use crate::{CheckCtx, GeneratorKind, MathOp, linear_ints, logspace}; /// Generate a sequence of inputs that either cover the domain in completeness (for smaller float /// types and single argument functions) or provide evenly spaced inputs across the domain with /// approximately `u32::MAX` total iterations. pub trait ExtensiveInput { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator + Send; + fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); } /// Construct an iterator from `logspace` and also calculate the total number of steps expected @@ -21,24 +20,60 @@ pub trait ExtensiveInput { fn logspace_steps( start: Op::FTy, end: Op::FTy, - ctx: &CheckCtx, - argnum: usize, + max_steps: u64, ) -> (impl Iterator + Clone, u64) where Op: MathOp, OpITy: TryFrom, + u64: TryFrom, Error: fmt::Debug>, RangeInclusive>: Iterator, { - let max_steps = iteration_count(ctx, GeneratorKind::Extensive, argnum); let max_steps = OpITy::::try_from(max_steps).unwrap_or(OpITy::::MAX); - let iter = logspace(start, end, max_steps); + let (iter, steps) = logspace(start, end, max_steps); + + // `steps` will be <= the original `max_steps`, which is a `u64`. + (iter, steps.try_into().unwrap()) +} + +/// Represents the iterator in either `Left` or `Right`. +enum EitherIter { + A(A), + B(B), +} - // `logspace` can't implement `ExactSizeIterator` because of the range, but its size hint - // should be accurate (assuming <= usize::MAX iterations). - let size_hint = iter.size_hint(); - assert_eq!(size_hint.0, size_hint.1.unwrap()); +impl, B: Iterator> Iterator for EitherIter { + type Item = T; - (iter, size_hint.0.try_into().unwrap()) + fn next(&mut self) -> Option { + match self { + Self::A(iter) => iter.next(), + Self::B(iter) => iter.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self { + Self::A(iter) => iter.size_hint(), + Self::B(iter) => iter.size_hint(), + } + } +} + +/// Gets the total number of possible values, returning `None` if that number doesn't fit in a +/// `u64`. +fn value_count() -> Option +where + u64: TryFrom, +{ + u64::try_from(F::Int::MAX).ok().and_then(|max| max.checked_add(1)) +} + +/// Returns an iterator of every possible value of type `F`. +fn all_values() -> impl Iterator +where + RangeInclusive: Iterator, +{ + (F::Int::MIN..=F::Int::MAX).map(|bits| F::from_bits(bits)) } macro_rules! impl_extensive_input { @@ -48,12 +83,23 @@ macro_rules! impl_extensive_input { Op: MathOp, Op: HasDomain, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let start = Op::DOMAIN.range_start(); - let end = Op::DOMAIN.range_end(); - let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); - let iter0 = iter0.map(|v| (v,)); - KnownSize::new(iter0, steps0) + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); + // `f16` and `f32` can have exhaustive tests. + match value_count::() { + Some(steps0) if steps0 <= max_steps0 => { + let iter0 = all_values(); + let iter0 = iter0.map(|v| (v,)); + (EitherIter::A(iter0), steps0) + } + _ => { + let start = Op::DOMAIN.range_start(); + let end = Op::DOMAIN.range_end(); + let (iter0, steps0) = logspace_steps::(start, end, max_steps0); + let iter0 = iter0.map(|v| (v,)); + (EitherIter::B(iter0), steps0) + } + } } } @@ -61,15 +107,28 @@ macro_rules! impl_extensive_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; - let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); - let (iter1, steps1) = logspace_steps::(start, end, ctx, 1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); - KnownSize::new(iter, count) + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); + let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); + // `f16` can have exhaustive tests. + match value_count::() { + Some(count) if count <= max_steps0 && count <= max_steps1 => { + let iter = all_values() + .flat_map(|first| all_values().map(move |second| (first, second))); + (EitherIter::A(iter), count.checked_mul(count).unwrap()) + } + _ => { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; + let (iter0, steps0) = logspace_steps::(start, end, max_steps0); + let (iter1, steps1) = logspace_steps::(start, end, max_steps1); + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); + (EitherIter::B(iter), count) + } + } } } @@ -77,22 +136,41 @@ macro_rules! impl_extensive_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; - - let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); - let (iter1, steps1) = logspace_steps::(start, end, ctx, 1); - let (iter2, steps2) = logspace_steps::(start, end, ctx, 2); - - let iter = iter0 - .flat_map(move |first| iter1.clone().map(move |second| (first, second))) - .flat_map(move |(first, second)| { - iter2.clone().map(move |third| (first, second, third)) - }); - let count = steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); - - KnownSize::new(iter, count) + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); + let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); + let max_steps2 = iteration_count(ctx, GeneratorKind::Extensive, 2); + // `f16` can be exhaustive tested if `LIBM_EXTENSIVE_TESTS` is incresed. + match value_count::() { + Some(count) + if count <= max_steps0 && count <= max_steps1 && count <= max_steps2 => + { + let iter = all_values().flat_map(|first| { + all_values().flat_map(move |second| { + all_values().map(move |third| (first, second, third)) + }) + }); + (EitherIter::A(iter), count.checked_pow(3).unwrap()) + } + _ => { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; + + let (iter0, steps0) = logspace_steps::(start, end, max_steps0); + let (iter1, steps1) = logspace_steps::(start, end, max_steps1); + let (iter2, steps2) = logspace_steps::(start, end, max_steps2); + + let iter = iter0 + .flat_map(move |first| iter1.clone().map(move |second| (first, second))) + .flat_map(move |(first, second)| { + iter2.clone().map(move |third| (first, second, third)) + }); + let count = + steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); + + (EitherIter::B(iter), count) + } + } } } @@ -100,19 +178,32 @@ macro_rules! impl_extensive_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let range0 = int_range(ctx, GeneratorKind::Extensive, 0); + let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); + let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); + match value_count::() { + Some(count1) if count1 <= max_steps1 => { + let (iter0, steps0) = linear_ints(range0, max_steps0); + let iter = iter0 + .flat_map(move |first| all_values().map(move |second| (first, second))); + (EitherIter::A(iter), steps0.checked_mul(count1).unwrap()) + } + _ => { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; - let iter0 = int_range(ctx, GeneratorKind::Extensive, 0); - let steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); - let (iter1, steps1) = logspace_steps::(start, end, ctx, 1); + let (iter0, steps0) = linear_ints(range0, max_steps0); + let (iter1, steps1) = logspace_steps::(start, end, max_steps1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); - KnownSize::new(iter, count) + (EitherIter::B(iter), count) + } + } } } @@ -120,19 +211,33 @@ macro_rules! impl_extensive_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); + let range1 = int_range(ctx, GeneratorKind::Extensive, 1); + let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); + match value_count::() { + Some(count0) if count0 <= max_steps0 => { + let (iter1, steps1) = linear_ints(range1, max_steps1); + let iter = all_values().flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + (EitherIter::A(iter), count0.checked_mul(steps1).unwrap()) + } + _ => { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; - let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); - let iter1 = int_range(ctx, GeneratorKind::Extensive, 0); - let steps1 = iteration_count(ctx, GeneratorKind::Extensive, 0); + let (iter0, steps0) = logspace_steps::(start, end, max_steps0); + let (iter1, steps1) = linear_ints(range1, max_steps1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); - KnownSize::new(iter, count) + (EitherIter::B(iter), count) + } + } } } }; @@ -145,10 +250,10 @@ impl_extensive_input!(f64); #[cfg(f128_enabled)] impl_extensive_input!(f128); -/// Create a test case iterator for extensive inputs. +/// Create a test case iterator for extensive inputs. Also returns the total test case count. pub fn get_test_cases( ctx: &CheckCtx, -) -> impl ExactSizeIterator + Send + use<'_, Op> +) -> (impl Iterator + Send + use<'_, Op>, u64) where Op: MathOp, Op::RustArgs: ExtensiveInput, diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 251114a0dcb..6e7017f093c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -22,7 +22,7 @@ use std::time::SystemTime; pub use f8_impl::f8; pub use libm::support::{Float, Int, IntTy, MinInt}; -pub use num::{FloatExt, logspace}; +pub use num::{FloatExt, linear_ints, logspace}; pub use op::{ BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustFn, OpRustRet, Ty, }; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num.rs b/library/compiler-builtins/libm/crates/libm-test/src/num.rs index f693ef02f1f..eed941423d3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/num.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/num.rs @@ -215,7 +215,13 @@ fn as_ulp_steps(x: F) -> Option { /// to logarithmic spacing of their values. /// /// Note that this tends to skip negative zero, so that needs to be checked explicitly. -pub fn logspace(start: F, end: F, steps: F::Int) -> impl Iterator + Clone +/// +/// Returns `(iterator, iterator_length)`. +pub fn logspace( + start: F, + end: F, + steps: F::Int, +) -> (impl Iterator + Clone, F::Int) where RangeInclusive: Iterator, { @@ -223,17 +229,42 @@ where assert!(!end.is_nan()); assert!(end >= start); - let mut steps = steps.checked_sub(F::Int::ONE).expect("`steps` must be at least 2"); + let steps = steps.checked_sub(F::Int::ONE).expect("`steps` must be at least 2"); let between = ulp_between(start, end).expect("`start` or `end` is NaN"); let spacing = (between / steps).max(F::Int::ONE); - steps = steps.min(between); // At maximum, one step per ULP + let steps = steps.min(between); // At maximum, one step per ULP let mut x = start; - (F::Int::ZERO..=steps).map(move |_| { - let ret = x; - x = x.n_up(spacing); - ret - }) + ( + (F::Int::ZERO..=steps).map(move |_| { + let ret = x; + x = x.n_up(spacing); + ret + }), + steps + F::Int::ONE, + ) +} + +/// Returns an iterator of up to `steps` integers evenly distributed. +pub fn linear_ints( + range: RangeInclusive, + steps: u64, +) -> (impl Iterator + Clone, u64) { + let steps = steps.checked_sub(1).unwrap(); + let between = u64::from(range.start().abs_diff(*range.end())); + let spacing = i32::try_from((between / steps).max(1)).unwrap(); + let steps = steps.min(between); + let mut x: i32 = *range.start(); + ( + (0..=steps).map(move |_| { + let res = x; + // Wrapping add to avoid panic on last item (where `x` could overflow past i32::MAX as + // there is no next item). + x = x.wrapping_add(spacing); + res + }), + steps + 1, + ) } #[cfg(test)] @@ -422,19 +453,55 @@ mod tests { #[test] fn test_logspace() { - let ls: Vec<_> = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 2).collect(); + let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 2); + let ls: Vec<_> = ls.collect(); let exp = [f8::from_bits(0x0), f8::from_bits(0x4)]; assert_eq!(ls, exp); + assert_eq!(ls.len(), usize::from(count)); - let ls: Vec<_> = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 3).collect(); + let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 3); + let ls: Vec<_> = ls.collect(); let exp = [f8::from_bits(0x0), f8::from_bits(0x2), f8::from_bits(0x4)]; assert_eq!(ls, exp); + assert_eq!(ls.len(), usize::from(count)); // Check that we include all values with no repeats if `steps` exceeds the maximum number // of steps. - let ls: Vec<_> = logspace(f8::from_bits(0x0), f8::from_bits(0x3), 10).collect(); + let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x3), 10); + let ls: Vec<_> = ls.collect(); let exp = [f8::from_bits(0x0), f8::from_bits(0x1), f8::from_bits(0x2), f8::from_bits(0x3)]; assert_eq!(ls, exp); + assert_eq!(ls.len(), usize::from(count)); + } + + #[test] + fn test_linear_ints() { + let (ints, count) = linear_ints(0..=4, 2); + let ints: Vec<_> = ints.collect(); + let exp = [0, 4]; + assert_eq!(ints, exp); + assert_eq!(ints.len(), usize::try_from(count).unwrap()); + + let (ints, count) = linear_ints(0..=4, 3); + let ints: Vec<_> = ints.collect(); + let exp = [0, 2, 4]; + assert_eq!(ints, exp); + assert_eq!(ints.len(), usize::try_from(count).unwrap()); + + // Check that we include all values with no repeats if `steps` exceeds the maximum number + // of steps. + let (ints, count) = linear_ints(0x0..=0x3, 10); + let ints: Vec<_> = ints.collect(); + let exp = [0, 1, 2, 3]; + assert_eq!(ints, exp); + assert_eq!(ints.len(), usize::try_from(count).unwrap()); + + // Check that there are no panics around `i32::MAX`. + let (ints, count) = linear_ints(i32::MAX - 1..=i32::MAX, 5); + let ints: Vec<_> = ints.collect(); + let exp = [i32::MAX - 1, i32::MAX]; + assert_eq!(ints, exp); + assert_eq!(ints.len(), usize::try_from(count).unwrap()); } #[test] diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs index 7acff5324ab..07f4d5370dc 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs @@ -106,8 +106,7 @@ where let completed = AtomicU64::new(0); let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); - let cases = &mut extensive::get_test_cases::(&ctx); - let total: u64 = cases.len().try_into().unwrap(); + let (ref mut cases, total) = extensive::get_test_cases::(&ctx); let pb = Progress::new(Op::NAME, total); let test_single_chunk = |mp_vals: &mut Op::MpTy, input_vec: Vec| -> TestResult { -- cgit 1.4.1-3-g733a5 From 2b99475df321e952f2a4266468623683aad13b03 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 17:30:05 -0500 Subject: Account for optimization levels other than numbers The build script currently panics with `opt-level=z` or `opt-level=s`. Account for this here. --- library/compiler-builtins/libm/configure.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index a18937c3c9e..8b8ba981565 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -7,7 +7,7 @@ use std::path::PathBuf; pub struct Config { pub manifest_dir: PathBuf, pub out_dir: PathBuf, - pub opt_level: u8, + pub opt_level: String, pub cargo_features: Vec, pub target_arch: String, pub target_env: String, @@ -31,7 +31,7 @@ impl Config { Self { manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()), out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), - opt_level: env::var("OPT_LEVEL").unwrap().parse().unwrap(), + opt_level: env::var("OPT_LEVEL").unwrap(), cargo_features, target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), @@ -91,7 +91,7 @@ fn emit_arch_cfg() { fn emit_optimization_cfg(cfg: &Config) { println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); - if cfg.opt_level >= 2 { + if !matches!(cfg.opt_level.as_str(), "0" | "1") { println!("cargo:rustc-cfg=optimizations_enabled"); } } -- cgit 1.4.1-3-g733a5 From 77f34f3a4c6d50688c8d456e5bbe192050807932 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 18:11:40 -0500 Subject: Update the `libm` submodule This includes [1], which fixes a bug parsing non-numeric optimization levels. [1]: https://github.com/rust-lang/libm/pull/417 --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 44770b96920..8e82616f154 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 44770b96920557baf38990d2ee4142e166be579d +Subproject commit 8e82616f154b06cf4ee9cdb82a4f56474a403d04 -- cgit 1.4.1-3-g733a5 From 83a61e67fdd9fdaeb915e63ff3f280b79b6d75e0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 18:12:19 -0500 Subject: Account for optimization levels other than numbers The build script currently panics with `opt-level=z` or `opt-level=s`. Account for this here. This is the `compiler-builtins` version of [1]. Fixes: https://github.com/rust-lang/compiler-builtins/issues/742 [1]: https://github.com/rust-lang/libm/pull/417 --- library/compiler-builtins/build.rs | 2 +- library/compiler-builtins/configure.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2bb8651d7f7..f512fc2e667 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -121,7 +121,7 @@ fn configure_libm(target: &Target) { } println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); - if target.opt_level >= 2 { + if !matches!(target.opt_level.as_str(), "0" | "1") { println!("cargo:rustc-cfg=optimizations_enabled"); } diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index 6cfbe11c2ed..87bc7a0eed3 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -6,7 +6,7 @@ use std::env; #[allow(dead_code)] pub struct Target { pub triple: String, - pub opt_level: u8, + pub opt_level: String, pub cargo_features: Vec, pub os: String, pub arch: String, @@ -32,7 +32,7 @@ impl Target { Self { triple: env::var("TARGET").unwrap(), os: env::var("CARGO_CFG_TARGET_OS").unwrap(), - opt_level: env::var("OPT_LEVEL").unwrap().parse().unwrap(), + opt_level: env::var("OPT_LEVEL").unwrap(), cargo_features, arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), -- cgit 1.4.1-3-g733a5 From d0a79fd542f2aaaa9af3ebf79f0e0d8d58a0ab6d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 23:21:35 +0000 Subject: chore: release v0.1.142 --- library/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index ccfc97d1bb0..305f2790f33 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.142](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.141...compiler_builtins-v0.1.142) - 2025-01-07 + +### Other + +- Account for optimization levels other than numbers + ## [0.1.141](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.140...compiler_builtins-v0.1.141) - 2025-01-07 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index a0c4cfaaffd..943adc4c1f2 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.141" +version = "0.1.142" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From a0c03b2537cadc9b74c5dd5d86d4a995553d9961 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 5 Jan 2025 11:21:00 +0000 Subject: Add tests against MPFR for `remquo` and `remquof` Rug does not yet expose this function, but it is possible to use the MPFR bindings directly. --- .../libm/crates/libm-test/Cargo.toml | 2 +- .../libm/crates/libm-test/src/mpfloat.rs | 50 ++++++++++++++++++++++ .../libm/crates/libm-test/tests/multiprecision.rs | 4 -- .../libm/crates/libm-test/tests/z_extensive/run.rs | 4 -- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 371beb19aa5..621e587c56d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -35,7 +35,7 @@ paste = "1.0.15" rand = "0.8.5" rand_chacha = "0.3.1" rayon = "1.10.0" -rug = { version = "1.26.1", optional = true, default-features = false, features = ["float", "std"] } +rug = { version = "1.26.1", optional = true, default-features = false, features = ["float", "integer", "std"] } [target.'cfg(target_family = "wasm")'.dependencies] # Enable randomness on WASM diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index f2b7b2f25da..f71e72cd571 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -4,10 +4,13 @@ //! a struct named `Operation` that implements [`MpOp`]. use std::cmp::Ordering; +use std::ffi::{c_int, c_long}; use az::Az; +use gmp_mpfr_sys::mpfr::rnd_t; use rug::Assign; pub use rug::Float as MpFloat; +use rug::float::Round; use rug::float::Round::Nearest; use rug::ops::{PowAssignRound, RemAssignRound}; @@ -361,6 +364,32 @@ macro_rules! impl_op_for_ty { } } + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + ( + new_mpfloat::(), + new_mpfloat::(), + new_mpfloat::() + ) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let (ord, ql) = mpfr_remquo(&mut this.2, &this.0, &this.1, Nearest); + + // `remquo` integer results are sign-magnitude representation. Transfer the + // sign bit from the long result to the int result. + let clear = !(1 << (c_int::BITS - 1)); + let sign = ((ql >> (c_long::BITS - 1)) as i32) << (c_int::BITS - 1); + let q = (ql as i32) & clear | sign; + + (prep_retval::(&mut this.2, ord), q) + } + } + impl MpOp for crate::op::[]::Routine { type MpTy = MpFloat; @@ -441,3 +470,24 @@ impl MpOp for crate::op::lgammaf_r::Routine { (ret, sign as i32) } } + +/// `rug` does not provide `remquo` so this exposes `mpfr_remquo`. See rug#76. +fn mpfr_remquo(r: &mut MpFloat, x: &MpFloat, y: &MpFloat, round: Round) -> (Ordering, c_long) { + let r = r.as_raw_mut(); + let x = x.as_raw(); + let y = y.as_raw(); + let mut q: c_long = 0; + + let round = match round { + Round::Nearest => rnd_t::RNDN, + Round::Zero => rnd_t::RNDZ, + Round::Up => rnd_t::RNDU, + Round::Down => rnd_t::RNDD, + Round::AwayZero => rnd_t::RNDA, + _ => unreachable!(), + }; + + // SAFETY: mutable and const pointers are valid and do not alias, by Rust's rules. + let ord = unsafe { gmp_mpfr_sys::mpfr::remquo(r, &mut q, x, y, round) }; + (ord.cmp(&0), q) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 7961b080258..e2766cfdabd 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -50,10 +50,6 @@ libm_macros::for_each_function! { [jn, jnf, yn, ynf], ], skip: [ - // FIXME: MPFR tests needed - remquo, - remquof, - // FIXME: test needed, see // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 nextafter, diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs index 07f4d5370dc..7ee9678515e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs @@ -48,10 +48,6 @@ fn register_all_tests() -> Vec { callback: mp_extensive_tests, extra: [all_tests], skip: [ - // FIXME: MPFR tests needed - remquo, - remquof, - // FIXME: test needed, see // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 nextafter, -- cgit 1.4.1-3-g733a5 From ab1038a32bc6217104808020570016545c940904 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 11 Jan 2025 21:24:06 +0000 Subject: Use `core::arch::wasm` functions rather than intrinsics These wasm functions are available in `core::arch::wasm32` since [1], so we can use them while avoiding the possibly-recursive `intrinsics::*` calls (in practice none of those should always lower to libcalls on wasm, but that is up to LLVM). Since these require an unstable feature, they are still gated under `unstable-intrinsics`. [1]: https://github.com/rust-lang/stdarch/pull/1677 --- library/compiler-builtins/libm/src/lib.rs | 1 + .../compiler-builtins/libm/src/math/arch/wasm32.rs | 30 ++++++++-------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 327e3d6e65b..b0e4312110f 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -2,6 +2,7 @@ #![no_std] #![cfg_attr(intrinsics_enabled, allow(internal_features))] #![cfg_attr(intrinsics_enabled, feature(core_intrinsics))] +#![cfg_attr(all(intrinsics_enabled, target_family = "wasm"), feature(wasm_numeric_instr))] #![cfg_attr(f128_enabled, feature(f128))] #![cfg_attr(f16_enabled, feature(f16))] #![allow(clippy::assign_op_pattern)] diff --git a/library/compiler-builtins/libm/src/math/arch/wasm32.rs b/library/compiler-builtins/libm/src/math/arch/wasm32.rs index 09df8624e8b..384445f1291 100644 --- a/library/compiler-builtins/libm/src/math/arch/wasm32.rs +++ b/library/compiler-builtins/libm/src/math/arch/wasm32.rs @@ -1,16 +1,12 @@ -//! Wasm asm is not stable; just use intrinsics for operations that have asm routine equivalents. -//! -//! Note that we need to be absolutely certain that everything here lowers to assembly operations, -//! otherwise libcalls will be recursive. +//! Wasm has builtins for simple float operations. Use the unstable `core::arch` intrinsics which +//! are significantly faster than soft float operations. pub fn ceil(x: f64) -> f64 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::ceilf64(x) } + core::arch::wasm32::f64_ceil(x) } pub fn ceilf(x: f32) -> f32 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::ceilf32(x) } + core::arch::wasm32::f32_ceil(x) } pub fn fabs(x: f64) -> f64 { @@ -22,31 +18,25 @@ pub fn fabsf(x: f32) -> f32 { } pub fn floor(x: f64) -> f64 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::floorf64(x) } + core::arch::wasm32::f64_floor(x) } pub fn floorf(x: f32) -> f32 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::floorf32(x) } + core::arch::wasm32::f32_floor(x) } pub fn sqrt(x: f64) -> f64 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::sqrtf64(x) } + core::arch::wasm32::f64_sqrt(x) } pub fn sqrtf(x: f32) -> f32 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::sqrtf32(x) } + core::arch::wasm32::f32_sqrt(x) } pub fn trunc(x: f64) -> f64 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::truncf64(x) } + core::arch::wasm32::f64_trunc(x) } pub fn truncf(x: f32) -> f32 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::truncf32(x) } + core::arch::wasm32::f32_trunc(x) } -- cgit 1.4.1-3-g733a5 From beb34db83d4637199ee264ae427c0337aa92cd63 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 11 Jan 2025 22:04:32 +0000 Subject: Split `cast` into `cast` and `cast_lossy` There is a difference in intent between wishing to cast and truncate the value, and expecting the input to be within range. To make this clear, add separate `cast_lossy` and `cast_from_lossy` to indicate what that truncation is intended, leaving `cast` and `cast_from` to only be casts that expected not to truncate. Actually enforcing this at runtime is likely to have a cost, so just `debug_assert!` that `cast` doesn't truncate. --- .../libm/src/math/support/int_traits.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index 380313c1e6b..0f2d72d9be3 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -343,18 +343,30 @@ impl_h_int!( /// Trait to express (possibly lossy) casting of integers #[allow(unused)] pub trait CastInto: Copy { + /// By default, casts should be exact. fn cast(self) -> T; + + /// Call for casts that are expected to truncate. + fn cast_lossy(self) -> T; } #[allow(unused)] pub trait CastFrom: Copy { + /// By default, casts should be exact. fn cast_from(value: T) -> Self; + + /// Call for casts that are expected to truncate. + fn cast_from_lossy(value: T) -> Self; } impl + Copy> CastFrom for T { fn cast_from(value: U) -> Self { value.cast() } + + fn cast_from_lossy(value: U) -> Self { + value.cast_lossy() + } } macro_rules! cast_into { @@ -364,6 +376,13 @@ macro_rules! cast_into { ($ty:ty; $($into:ty),*) => {$( impl CastInto<$into> for $ty { fn cast(self) -> $into { + // All we can really do to enforce casting rules is check the rules when in + // debug mode. + debug_assert!(<$into>::try_from(self).is_ok(), "failed cast from {self}"); + self as $into + } + + fn cast_lossy(self) -> $into { self as $into } } -- cgit 1.4.1-3-g733a5 From 5e13eeca0147854cf4bb29189910d87d3878af05 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 11 Jan 2025 23:22:12 +0000 Subject: Reorder tests in `run.sh` I do not believe Cargo separately caches crates with different sets of features enabled. So, ensuring that tests run with `unstable-intrinsics` are always grouped should slightly reduce runtime. As an added benefit, all the debug mode tests run first so initial feedback is available faster. --- library/compiler-builtins/libm/ci/run.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 70fc271f194..89c9c86315f 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -75,16 +75,14 @@ if [ "${BUILD_ONLY:-}" = "1" ]; then else cmd="cargo test --all --target $target $extra_flags" - # Test without intrinsics + # Test once without intrinsics, once with intrinsics enabled $cmd - $cmd --release - - # Test with intrinsic use $cmd --features unstable-intrinsics + $cmd --features unstable-intrinsics --benches + + # Test the same in release mode, which also increases coverage. + $cmd --release $cmd --release --features unstable-intrinsics - - # Make sure benchmarks have correct results - $cmd --benches - $cmd --benches --release + $cmd --release --features unstable-intrinsics --benches fi -- cgit 1.4.1-3-g733a5 From 721960c17244975f65f6b542e39a00d04807728e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 11 Jan 2025 23:40:19 +0000 Subject: Remove `ExpInt` from `Float`, always use `i32` instead `ExpInt` is likely to only have performance benefits on 16-bit platforms, but makes working with the exponent more difficult. It seems like a worthwhile tradeoff to instead just use `i32`, so do that here. --- .../libm/crates/libm-test/src/f8_impl.rs | 5 ----- .../libm/src/math/support/float_traits.rs | 22 ++++++++-------------- .../libm/src/math/support/int_traits.rs | 2 ++ 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index d378863f2fd..299553d202a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -20,7 +20,6 @@ pub struct f8(u8); impl Float for f8 { type Int = u8; type SignedInt = i8; - type ExpInt = i8; const ZERO: Self = Self(0b0_0000_000); const NEG_ZERO: Self = Self(0b1_0000_000); @@ -62,10 +61,6 @@ impl Float for f8 { self.0 & Self::SIGN_MASK != 0 } - fn exp(self) -> Self::ExpInt { - unimplemented!() - } - fn from_bits(a: Self::Int) -> Self { Self(a) } diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 69705096658..f795527db97 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -1,6 +1,6 @@ use core::{fmt, mem, ops}; -use super::int_traits::{Int, MinInt}; +use super::int_traits::{CastInto, Int, MinInt}; /// Trait for some basic operations on floats #[allow(dead_code)] @@ -25,9 +25,6 @@ pub trait Float: /// A int of the same width as the float type SignedInt: Int + MinInt; - /// An int capable of containing the exponent bits plus a sign bit. This is signed. - type ExpInt: Int; - const ZERO: Self; const NEG_ZERO: Self; const ONE: Self; @@ -98,7 +95,9 @@ pub trait Float: } /// Returns the exponent, not adjusting for bias. - fn exp(self) -> Self::ExpInt; + fn exp(self) -> i32 { + ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS).cast() + } /// Returns the significand with no implicit bit (or the "fractional" part) fn frac(self) -> Self::Int { @@ -146,7 +145,6 @@ macro_rules! float_impl { $ty:ident, $ity:ident, $sity:ident, - $expty:ident, $bits:expr, $significand_bits:expr, $from_bits:path @@ -154,7 +152,6 @@ macro_rules! float_impl { impl Float for $ty { type Int = $ity; type SignedInt = $sity; - type ExpInt = $expty; const ZERO: Self = 0.0; const NEG_ZERO: Self = -0.0; @@ -191,9 +188,6 @@ macro_rules! float_impl { fn is_sign_negative(self) -> bool { self.is_sign_negative() } - fn exp(self) -> Self::ExpInt { - ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt - } fn from_bits(a: Self::Int) -> Self { Self::from_bits(a) } @@ -226,11 +220,11 @@ macro_rules! float_impl { } #[cfg(f16_enabled)] -float_impl!(f16, u16, i16, i8, 16, 10, f16::from_bits); -float_impl!(f32, u32, i32, i16, 32, 23, f32_from_bits); -float_impl!(f64, u64, i64, i16, 64, 52, f64_from_bits); +float_impl!(f16, u16, i16, 16, 10, f16::from_bits); +float_impl!(f32, u32, i32, 32, 23, f32_from_bits); +float_impl!(f64, u64, i64, 64, 52, f64_from_bits); #[cfg(f128_enabled)] -float_impl!(f128, u128, i128, i16, 128, 112, f128::from_bits); +float_impl!(f128, u128, i128, 128, 112, f128::from_bits); /* FIXME(msrv): vendor some things that are not const stable at our MSRV */ diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index 0f2d72d9be3..459f0a58bb2 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -55,6 +55,8 @@ pub trait Int: + ops::BitAnd + cmp::Ord + CastInto + + CastInto + + CastFrom + CastFrom { fn signed(self) -> OtherSign; -- cgit 1.4.1-3-g733a5 From 5c94cce6b2912d1d325d0d863195a6ea37e41503 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 11 Jan 2025 22:30:30 +0000 Subject: Add a `release-checked` profile with debug and overflow assertions A failing debug assertion or overflow without correctly wrapping or saturating is a bug, but the `debug` profile that has these enabled does not run enough test cases to hit edge cases that may trigger these. Add a new `release-checked` profile that enables debug assertions and overflow checks. This seems to only extend per-function test time by a few seconds (or around a minute on longer extensive tests), so enable this as the default on CI. In order to ensure `no_panic` still gets checked, add a build-only step to CI. --- library/compiler-builtins/libm/.github/workflows/main.yml | 3 ++- library/compiler-builtins/libm/Cargo.toml | 7 +++++++ library/compiler-builtins/libm/build.rs | 6 +++++- library/compiler-builtins/libm/ci/run.sh | 8 +++++--- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 320800f2ea7..98505ea35c5 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -238,7 +238,8 @@ jobs: LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \ --features test-multiprecision,unstable \ - --release -- extensive + --profile release-checked \ + -- extensive - name: Print test logs if available run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi shell: bash diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index dc362779e84..0e444b5834f 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -61,3 +61,10 @@ no-panic = "0.1.30" # This is needed for no-panic to correctly detect the lack of panics [profile.release] lto = "fat" + +# Release mode with debug assertions +[profile.release-checked] +inherits = "release" +debug-assertions = true +lto = "fat" +overflow-checks = true diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 9c9e0e72328..ca4a639a12a 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -13,8 +13,12 @@ fn main() { #[allow(unexpected_cfgs)] if !cfg!(feature = "checked") { let lvl = env::var("OPT_LEVEL").unwrap(); - if lvl != "0" { + if lvl != "0" && !cfg!(debug_assertions) { println!("cargo:rustc-cfg=assert_no_panic"); + } else if env::var("ENSURE_NO_PANIC").is_ok() { + // Give us a defensive way of ensureing that no-panic is checked when we + // expect it to be. + panic!("`assert_no_panic `was not enabled"); } } diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 89c9c86315f..244a22a076d 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -81,8 +81,10 @@ else $cmd --features unstable-intrinsics --benches # Test the same in release mode, which also increases coverage. - $cmd --release - $cmd --release --features unstable-intrinsics - $cmd --release --features unstable-intrinsics --benches + $cmd --profile release-checked + $cmd --profile release-checked --features unstable-intrinsics + $cmd --profile release-checked --features unstable-intrinsics --benches + + ENSURE_NO_PANIC=1 cargo build --target "$target" --release fi -- cgit 1.4.1-3-g733a5 From e1749bdb6d836e6d93c5e694c912b16bee29b317 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 03:25:25 +0000 Subject: Add `biteq` and `exp_unbiased` to `Float` These are two convenience methods. Additionally, add tests for the trait methods, and an `assert_biteq!` macro to check and print the output. --- .../libm/src/math/support/float_traits.rs | 125 +++++++++++++++++++-- .../libm/src/math/support/int_traits.rs | 8 +- .../libm/src/math/support/macros.rs | 20 ++++ 3 files changed, 143 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index f795527db97..3aa0d844a72 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -1,6 +1,6 @@ use core::{fmt, mem, ops}; -use super::int_traits::{CastInto, Int, MinInt}; +use super::int_traits::{CastFrom, CastInto, Int, MinInt}; /// Trait for some basic operations on floats #[allow(dead_code)] @@ -73,11 +73,18 @@ pub trait Float: self.to_bits().signed() } + /// Check bitwise equality. + fn biteq(self, rhs: Self) -> bool { + self.to_bits() == rhs.to_bits() + } + /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. This method returns `true` if two NaNs are - /// compared. + /// represented in multiple different ways. + /// + /// This method returns `true` if two NaNs are compared. Use [`biteq`](Self::biteq) instead + /// if `NaN` should not be treated separately. fn eq_repr(self, rhs: Self) -> bool { - if self.is_nan() && rhs.is_nan() { true } else { self.to_bits() == rhs.to_bits() } + if self.is_nan() && rhs.is_nan() { true } else { self.biteq(rhs) } } /// Returns true if the value is NaN. @@ -94,17 +101,22 @@ pub trait Float: (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO } - /// Returns the exponent, not adjusting for bias. + /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. fn exp(self) -> i32 { ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS).cast() } + /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. + fn exp_unbiased(self) -> i32 { + self.exp() - (Self::EXP_BIAS as i32) + } + /// Returns the significand with no implicit bit (or the "fractional" part) fn frac(self) -> Self::Int { self.to_bits() & Self::SIG_MASK } - /// Returns the significand with implicit bit + /// Returns the significand with implicit bit. fn imp_frac(self) -> Self::Int { self.frac() | Self::IMPLICIT_BIT } @@ -113,11 +125,11 @@ pub trait Float: fn from_bits(a: Self::Int) -> Self; /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { + fn from_parts(negative: bool, exponent: i32, significand: Self::Int) -> Self { let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; Self::from_bits( (sign << (Self::BITS - 1)) - | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) + | (Self::Int::cast_from(exponent as u32 & Self::EXP_MAX) << Self::SIG_BITS) | (significand & Self::SIG_MASK), ) } @@ -239,3 +251,100 @@ pub const fn f64_from_bits(bits: u64) -> f64 { // SAFETY: POD cast with no preconditions unsafe { mem::transmute::(bits) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(f16_enabled)] + fn check_f16() { + // Constants + assert_eq!(f16::EXP_MAX, 0b11111); + assert_eq!(f16::EXP_BIAS, 15); + + // `exp_unbiased` + assert_eq!(f16::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f16 / 2.0).exp_unbiased(), -1); + assert_eq!(f16::MAX.exp_unbiased(), 15); + assert_eq!(f16::MIN.exp_unbiased(), 15); + assert_eq!(f16::MIN_POSITIVE.exp_unbiased(), -14); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f16::ZERO.exp_unbiased(), -15); + assert_eq!(f16::from_bits(0x1).exp_unbiased(), -15); + + // `from_parts` + assert_biteq!(f16::from_parts(true, f16::EXP_BIAS as i32, 0), -1.0f16); + assert_biteq!(f16::from_parts(false, 0, 1), f16::from_bits(0x1)); + } + + #[test] + fn check_f32() { + // Constants + assert_eq!(f32::EXP_MAX, 0b11111111); + assert_eq!(f32::EXP_BIAS, 127); + + // `exp_unbiased` + assert_eq!(f32::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f32 / 2.0).exp_unbiased(), -1); + assert_eq!(f32::MAX.exp_unbiased(), 127); + assert_eq!(f32::MIN.exp_unbiased(), 127); + assert_eq!(f32::MIN_POSITIVE.exp_unbiased(), -126); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f32::ZERO.exp_unbiased(), -127); + assert_eq!(f32::from_bits(0x1).exp_unbiased(), -127); + + // `from_parts` + assert_biteq!(f32::from_parts(true, f32::EXP_BIAS as i32, 0), -1.0f32); + assert_biteq!(f32::from_parts(false, 10 + f32::EXP_BIAS as i32, 0), hf32!("0x1p10")); + assert_biteq!(f32::from_parts(false, 0, 1), f32::from_bits(0x1)); + } + + #[test] + fn check_f64() { + // Constants + assert_eq!(f64::EXP_MAX, 0b11111111111); + assert_eq!(f64::EXP_BIAS, 1023); + + // `exp_unbiased` + assert_eq!(f64::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f64 / 2.0).exp_unbiased(), -1); + assert_eq!(f64::MAX.exp_unbiased(), 1023); + assert_eq!(f64::MIN.exp_unbiased(), 1023); + assert_eq!(f64::MIN_POSITIVE.exp_unbiased(), -1022); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f64::ZERO.exp_unbiased(), -1023); + assert_eq!(f64::from_bits(0x1).exp_unbiased(), -1023); + + // `from_parts` + assert_biteq!(f64::from_parts(true, f64::EXP_BIAS as i32, 0), -1.0f64); + assert_biteq!(f64::from_parts(false, 10 + f64::EXP_BIAS as i32, 0), hf64!("0x1p10")); + assert_biteq!(f64::from_parts(false, 0, 1), f64::from_bits(0x1)); + } + + #[test] + #[cfg(f128_enabled)] + fn check_f128() { + // Constants + assert_eq!(f128::EXP_MAX, 0b111111111111111); + assert_eq!(f128::EXP_BIAS, 16383); + + // `exp_unbiased` + assert_eq!(f128::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f128 / 2.0).exp_unbiased(), -1); + assert_eq!(f128::MAX.exp_unbiased(), 16383); + assert_eq!(f128::MIN.exp_unbiased(), 16383); + assert_eq!(f128::MIN_POSITIVE.exp_unbiased(), -16382); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f128::ZERO.exp_unbiased(), -16383); + assert_eq!(f128::from_bits(0x1).exp_unbiased(), -16383); + + // `from_parts` + assert_biteq!(f128::from_parts(true, f128::EXP_BIAS as i32, 0), -1.0f128); + assert_biteq!(f128::from_parts(false, 0, 1), f128::from_bits(0x1)); + } +} diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index 459f0a58bb2..db799c030c2 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -54,10 +54,14 @@ pub trait Int: + ops::BitXor + ops::BitAnd + cmp::Ord - + CastInto - + CastInto + CastFrom + + CastFrom + CastFrom + + CastFrom + + CastInto + + CastInto + + CastInto + + CastInto { fn signed(self) -> OtherSign; fn unsigned(self) -> Self::Unsigned; diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index f5094b9da89..076fdf1f775 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -106,3 +106,23 @@ macro_rules! hf64 { X }}; } + +/// Assert `F::biteq` with better messages. +#[cfg(test)] +macro_rules! assert_biteq { + ($left:expr, $right:expr, $($arg:tt)*) => {{ + let bits = ($left.to_bits() * 0).leading_zeros(); // hack to get the width from the value + assert!( + $left.biteq($right), + "\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", + l = $left, + lb = $left.to_bits(), + r = $right, + rb = $right.to_bits(), + width = ((bits / 4) + 2) as usize + ); + }}; + ($left:expr, $right:expr $(,)?) => { + assert_biteq!($left, $right,) + }; +} -- cgit 1.4.1-3-g733a5 From 2912076e50f6887315c2bd53359eb57171e1615e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 03:55:46 +0000 Subject: Always use the same seed for benchmarking It would be preferable to switch to a different generator, or at least set the seed within the benchmark, but this is the most straightforward way to make things simple. --- library/compiler-builtins/libm/.github/workflows/main.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 98505ea35c5..b14ab40ecda 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -156,7 +156,11 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Download musl source run: ./ci/download-musl.sh - - run: cargo bench --all --features libm-test/short-benchmarks,libm-test/build-musl + - run: | + # Always use the same seed for benchmarks. Ideally we should switch to a + # non-random generator. + export LIBM_SEED=benchesbenchesbenchesbencheswoo! + cargo bench --all --features libm-test/short-benchmarks,libm-test/build-musl msrv: name: Check MSRV -- cgit 1.4.1-3-g733a5 From 5b1c1fca03586645768771b5fb1332d37708b182 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 07:43:24 +0000 Subject: Expose C versions of `libm` functions in the `cb` crate `compiler_builtins` exposes an `extern "C"` version of `libm` routines, so add the same here. There really isn't much to test here (unless we later add tests against C `libm` suites), but one nice benefit is this gives us a library with unmangled names that is easy to `objdump`. In accordance with that, also update `cb` to be a `staticlib`. Unfortunately this also means we have to remove it from the workspace, since Cargo doesn't allow setting `panic = "abort"` for a single crate. --- .../libm/.github/workflows/main.yml | 2 +- library/compiler-builtins/libm/.gitignore | 3 +- library/compiler-builtins/libm/Cargo.toml | 5 +- .../crates/compiler-builtins-smoke-test/Cargo.toml | 18 ++- .../crates/compiler-builtins-smoke-test/build.rs | 7 + .../crates/compiler-builtins-smoke-test/src/lib.rs | 171 +++++++++++++++++++++ 6 files changed, 200 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index b14ab40ecda..7e371d6136d 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -144,7 +144,7 @@ jobs: - name: Install Rust run: rustup update nightly --no-self-update && rustup default nightly - uses: Swatinem/rust-cache@v2 - - run: cargo build -p cb + - run: cargo test --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml benchmarks: name: Benchmarks diff --git a/library/compiler-builtins/libm/.gitignore b/library/compiler-builtins/libm/.gitignore index b6a53275151..4e9c9c03ddf 100644 --- a/library/compiler-builtins/libm/.gitignore +++ b/library/compiler-builtins/libm/.gitignore @@ -2,8 +2,7 @@ .#* /bin /math/src -/math/target -/target +target Cargo.lock musl/ **.tar.gz diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 0e444b5834f..fc881b77e54 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -43,7 +43,6 @@ force-soft-floats = [] [workspace] resolver = "2" members = [ - "crates/compiler-builtins-smoke-test", "crates/libm-macros", "crates/libm-test", "crates/musl-math-sys", @@ -53,6 +52,10 @@ default-members = [ "crates/libm-macros", "crates/libm-test", ] +exclude = [ + # Requires `panic = abort` so can't be a member of the workspace + "crates/compiler-builtins-smoke-test", +] [dev-dependencies] no-panic = "0.1.30" diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 1f09ce99c48..d578b0dcd0b 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -6,15 +6,21 @@ edition = "2021" publish = false [lib] +crate-type = ["staticlib"] test = false bench = false +[features] +default = ["arch", "unstable-float"] + +# Copied from `libm`'s root `Cargo.toml`' +unstable-float = [] +arch = [] + [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ "cfg(arch_enabled)", "cfg(assert_no_panic)", - "cfg(f128_enabled)", - "cfg(f16_enabled)", "cfg(intrinsics_enabled)", 'cfg(feature, values("checked"))', 'cfg(feature, values("force-soft-floats"))', @@ -22,3 +28,11 @@ unexpected_cfgs = { level = "warn", check-cfg = [ 'cfg(feature, values("unstable-intrinsics"))', 'cfg(feature, values("unstable-public-internals"))', ] } + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" +codegen-units = 1 +lto = "fat" diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs new file mode 100644 index 00000000000..401b7e1eb3a --- /dev/null +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs @@ -0,0 +1,7 @@ +#[path = "../../configure.rs"] +mod configure; + +fn main() { + let cfg = configure::Config::from_env(); + configure::emit_libm_config(&cfg); +} diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index e3a51a575e4..95ecb840d29 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -1,8 +1,12 @@ //! Fake compiler-builtins crate //! //! This is used to test that we can source import `libm` into the compiler-builtins crate. +//! Additionally, it provides a `#[no_mangle]` C API that can be easier to inspect than the +//! default `.rlib`. #![feature(core_intrinsics)] +#![feature(f16)] +#![feature(f128)] #![allow(internal_features)] #![no_std] @@ -10,3 +14,170 @@ #[allow(clippy::all)] // We don't get `libm`'s list of `allow`s, so just ignore Clippy. #[path = "../../../src/math/mod.rs"] pub mod libm; + +use core::ffi::c_int; + +/// Mark functions `#[no_mangle]` and with the C ABI. +macro_rules! no_mangle { + ($( $name:ident( $($tt:tt)+ ) -> $ret:ty; )+) => { + $( no_mangle!(@inner $name( $($tt)+ ) -> $ret); )+ + }; + + // Handle simple functions with single return types + (@inner $name:ident( $($arg:ident: $aty:ty),+ ) -> $ret:ty) => { + #[no_mangle] + extern "C" fn $name($($arg: $aty),+) -> $ret { + libm::$name($($arg),+) + } + }; + + + // Functions with `&mut` return values need to be handled differently, use `|` to + // separate inputs vs. outputs. + ( + @inner $name:ident( $($arg:ident: $aty:ty),+ | $($rarg:ident: $rty:ty),+) -> $ret:ty + ) => { + #[no_mangle] + extern "C" fn $name($($arg: $aty,)+ $($rarg: $rty),+) -> $ret { + let ret; + (ret, $(*$rarg),+) = libm::$name($($arg),+); + ret + } + }; +} + +no_mangle! { + frexp(x: f64 | y: &mut c_int) -> f64; + frexpf(x: f32 | y: &mut c_int) -> f32; + acos(x: f64) -> f64; + acosf(x: f32) -> f32; + acosh(x: f64) -> f64; + acoshf(x: f32) -> f32; + asin(x: f64) -> f64; + asinf(x: f32) -> f32; + asinh(x: f64) -> f64; + asinhf(x: f32) -> f32; + atan(x: f64) -> f64; + atan2(x: f64, y: f64) -> f64; + atan2f(x: f32, y: f32) -> f32; + atanf(x: f32) -> f32; + atanh(x: f64) -> f64; + atanhf(x: f32) -> f32; + cbrt(x: f64) -> f64; + cbrtf(x: f32) -> f32; + ceil(x: f64) -> f64; + ceilf(x: f32) -> f32; + copysign(x: f64, y: f64) -> f64; + copysignf(x: f32, y: f32) -> f32; + copysignf128(x: f128, y: f128) -> f128; + copysignf16(x: f16, y: f16) -> f16; + cos(x: f64) -> f64; + cosf(x: f32) -> f32; + cosh(x: f64) -> f64; + coshf(x: f32) -> f32; + erf(x: f64) -> f64; + erfc(x: f64) -> f64; + erfcf(x: f32) -> f32; + erff(x: f32) -> f32; + exp(x: f64) -> f64; + exp10(x: f64) -> f64; + exp10f(x: f32) -> f32; + exp2(x: f64) -> f64; + exp2f(x: f32) -> f32; + expf(x: f32) -> f32; + expm1(x: f64) -> f64; + expm1f(x: f32) -> f32; + fabs(x: f64) -> f64; + fabsf(x: f32) -> f32; + fabsf128(x: f128) -> f128; + fabsf16(x: f16) -> f16; + fdim(x: f64, y: f64) -> f64; + fdimf(x: f32, y: f32) -> f32; + floor(x: f64) -> f64; + floorf(x: f32) -> f32; + fma(x: f64, y: f64, z: f64) -> f64; + fmaf(x: f32, y: f32, z: f32) -> f32; + fmax(x: f64, y: f64) -> f64; + fmaxf(x: f32, y: f32) -> f32; + fmin(x: f64, y: f64) -> f64; + fminf(x: f32, y: f32) -> f32; + fmod(x: f64, y: f64) -> f64; + fmodf(x: f32, y: f32) -> f32; + hypot(x: f64, y: f64) -> f64; + hypotf(x: f32, y: f32) -> f32; + ilogb(x: f64) -> c_int; + ilogbf(x: f32) -> c_int; + j0(x: f64) -> f64; + j0f(x: f32) -> f32; + j1(x: f64) -> f64; + j1f(x: f32) -> f32; + jn(x: c_int, y: f64) -> f64; + jnf(x: c_int, y: f32) -> f32; + ldexp(x: f64, y: c_int) -> f64; + ldexpf(x: f32, y: c_int) -> f32; + lgamma(x: f64) -> f64; + lgamma_r(x: f64 | r: &mut c_int) -> f64; + lgammaf(x: f32) -> f32; + lgammaf_r(x: f32 | r: &mut c_int) -> f32; + log(x: f64) -> f64; + log10(x: f64) -> f64; + log10f(x: f32) -> f32; + log1p(x: f64) -> f64; + log1pf(x: f32) -> f32; + log2(x: f64) -> f64; + log2f(x: f32) -> f32; + logf(x: f32) -> f32; + modf(x: f64 | r: &mut f64) -> f64; + modff(x: f32 | r: &mut f32) -> f32; + nextafter(x: f64, y: f64) -> f64; + nextafterf(x: f32, y: f32) -> f32; + pow(x: f64, y: f64) -> f64; + powf(x: f32, y: f32) -> f32; + remainder(x: f64, y: f64) -> f64; + remainderf(x: f32, y: f32) -> f32; + remquo(x: f64, y: f64 | q: &mut c_int) -> f64; + remquof(x: f32, y: f32 | q: &mut c_int) -> f32; + rint(x: f64) -> f64; + rintf(x: f32) -> f32; + round(x: f64) -> f64; + roundf(x: f32) -> f32; + scalbn(x: f64, y: c_int) -> f64; + scalbnf(x: f32, y: c_int) -> f32; + sin(x: f64) -> f64; + sinf(x: f32) -> f32; + sinh(x: f64) -> f64; + sinhf(x: f32) -> f32; + sqrt(x: f64) -> f64; + sqrtf(x: f32) -> f32; + tan(x: f64) -> f64; + tanf(x: f32) -> f32; + tanh(x: f64) -> f64; + tanhf(x: f32) -> f32; + tgamma(x: f64) -> f64; + tgammaf(x: f32) -> f32; + trunc(x: f64) -> f64; + truncf(x: f32) -> f32; + y0(x: f64) -> f64; + y0f(x: f32) -> f32; + y1(x: f64) -> f64; + y1f(x: f32) -> f32; + yn(x: c_int, y: f64) -> f64; + ynf(x: c_int, y: f32) -> f32; +} + +/* sincos has no direct return type, not worth handling in the macro */ + +#[no_mangle] +extern "C" fn sincos(x: f64, s: &mut f64, c: &mut f64) { + (*s, *c) = libm::sincos(x); +} + +#[no_mangle] +extern "C" fn sincosf(x: f32, s: &mut f32, c: &mut f32) { + (*s, *c) = libm::sincosf(x); +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} -- cgit 1.4.1-3-g733a5 From 228c716a43f9c1e8f81762c4662c4cc5dd2c90f1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 04:24:03 +0000 Subject: Add a new precision adjustment for i586 `rint` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `rint` had a couple recent failures from the random tests: ---- mp_random_rint stdout ---- Random Mpfr rint arg 1/1: 10000 iterations (10000 total) using `LIBM_SEED=Fl1f69DaJnwkHN2FeuCXaBFRvJYsPvEY` thread 'mp_random_rint' panicked at crates/libm-test/tests/multiprecision.rs:41:49: called `Result::unwrap()` on an `Err` value: input: (-849751480.5001163,) (0xc1c95316dc4003d0,) expected: -849751481.0 0xc1c95316dc800000 actual: -849751480.0 0xc1c95316dc000000 Caused by: ulp 8388608 > 100000 And: ---- mp_random_rint stdout ---- Random Mpfr rint arg 1/1: 10000 iterations (10000 total) using `LIBM_SEED=XN7VCGhX3Wu6Mzn8COvJPITyZlGP7gN7` thread 'mp_random_rint' panicked at crates/libm-test/tests/multiprecision.rs:41:49: called `Result::unwrap()` on an `Err` value: input: (-12493089.499809155,) (0xc167d4242ffe6fc5,) expected: -12493089.0 0xc167d42420000000 actual: -12493090.0 0xc167d42440000000 Caused by: ulp 536870912 > 100000 It seems we just implement an incorrect rounding mode. Replace the existing `rint` override with an xfail if the difference is 0.0 <= ε <= 1.0. --- .../compiler-builtins/libm/crates/libm-test/src/precision.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index cbe4bdf8848..75b99c6524e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -114,7 +114,6 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Id::Exp10 | Id::Exp10f => ulp = 1_000_000, Id::Exp2 | Id::Exp2f => ulp = 10_000_000, Id::Log1p | Id::Log1pf => ulp = 2, - Id::Rint => ulp = 100_000, Id::Round => ulp = 1, Id::Tan => ulp = 2, _ => (), @@ -261,6 +260,15 @@ impl MaybeOverride<(f64,)> for SpecialCase { } } + if cfg!(x86_no_sse) + && ctx.base_name == BaseName::Rint + && (expected - actual).abs() <= F::ONE + && (expected - actual).abs() > F::ZERO + { + // Our rounding mode is incorrect. + return XFAIL; + } + if ctx.base_name == BaseName::Acosh && input.0 < 1.0 { // The function is undefined for the inputs, musl and our libm both return // random results. -- cgit 1.4.1-3-g733a5 From b50ea809ff78b75787dce326c64eab2eebe162d5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 08:02:44 +0000 Subject: Add a new precision adjustment for i586 `exp2f` There was a recent failure from the random tests: ---- mp_random_exp2f stdout ---- Random Mpfr exp2f arg 1/1: 10000 iterations (10000 total) using `LIBM_SEED=fqgMuzs6eqH1VZSEmQpLnThnaIyRUOWe` thread 'mp_random_exp2f' panicked at crates/libm-test/tests/multiprecision.rs:41:49: called `Result::unwrap()` on an `Err` value: input: (127.97238,) (0x42fff1dc,) expected: 3.3383009e38 0x7f7b2556 actual: inf 0x7f800000 Caused by: mismatched infinities Add an xfail for mismatched infinities on i586. --- library/compiler-builtins/libm/crates/libm-test/src/precision.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 75b99c6524e..15913fe6d75 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -211,6 +211,15 @@ impl MaybeOverride<(f32,)> for SpecialCase { return XFAIL; } + if cfg!(x86_no_sse) + && ctx.base_name == BaseName::Exp2 + && !expected.is_infinite() + && actual.is_infinite() + { + // We return infinity when there is a representable value. Test input: 127.97238 + return XFAIL; + } + maybe_check_nan_bits(actual, expected, ctx) } -- cgit 1.4.1-3-g733a5 From 7defd9b4290bce1fd912f55887217c213a642937 Mon Sep 17 00:00:00 2001 From: Hanna Kruppe Date: Sun, 12 Jan 2025 10:56:30 +0100 Subject: Use wasm32 arch intrinsics for rint{,f} --- library/compiler-builtins/libm/etc/function-definitions.json | 2 ++ library/compiler-builtins/libm/src/math/arch/mod.rs | 4 +++- library/compiler-builtins/libm/src/math/arch/wasm32.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/rint.rs | 6 ++++++ library/compiler-builtins/libm/src/math/rintf.rs | 6 ++++++ 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 3cf7e0fed3d..f60a7e5673c 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -604,12 +604,14 @@ "rint": { "sources": [ "src/libm_helper.rs", + "src/math/arch/wasm32.rs", "src/math/rint.rs" ], "type": "f64" }, "rintf": { "sources": [ + "src/math/arch/wasm32.rs", "src/math/rintf.rs" ], "type": "f32" diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index bd79ae1c69c..3992419cbaa 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -11,7 +11,9 @@ cfg_if! { if #[cfg(all(target_arch = "wasm32", intrinsics_enabled))] { mod wasm32; - pub use wasm32::{ceil, ceilf, fabs, fabsf, floor, floorf, sqrt, sqrtf, trunc, truncf}; + pub use wasm32::{ + ceil, ceilf, fabs, fabsf, floor, floorf, rint, rintf, sqrt, sqrtf, trunc, truncf, + }; } else if #[cfg(target_feature = "sse2")] { mod i686; pub use i686::{sqrt, sqrtf}; diff --git a/library/compiler-builtins/libm/src/math/arch/wasm32.rs b/library/compiler-builtins/libm/src/math/arch/wasm32.rs index 384445f1291..de80c8a5817 100644 --- a/library/compiler-builtins/libm/src/math/arch/wasm32.rs +++ b/library/compiler-builtins/libm/src/math/arch/wasm32.rs @@ -25,6 +25,14 @@ pub fn floorf(x: f32) -> f32 { core::arch::wasm32::f32_floor(x) } +pub fn rint(x: f64) -> f64 { + core::arch::wasm32::f64_nearest(x) +} + +pub fn rintf(x: f32) -> f32 { + core::arch::wasm32::f32_nearest(x) +} + pub fn sqrt(x: f64) -> f64 { core::arch::wasm32::f64_sqrt(x) } diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index cbdc3c2b91c..50192ffdf03 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -1,5 +1,11 @@ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rint(x: f64) -> f64 { + select_implementation! { + name: rint, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + let one_over_e = 1.0 / f64::EPSILON; let as_u64: u64 = x.to_bits(); let exponent: u64 = (as_u64 >> 52) & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 2d22c939354..64968b6be3a 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -1,5 +1,11 @@ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rintf(x: f32) -> f32 { + select_implementation! { + name: rintf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + let one_over_e = 1.0 / f32::EPSILON; let as_u32: u32 = x.to_bits(); let exponent: u32 = (as_u32 >> 23) & 0xff; -- cgit 1.4.1-3-g733a5 From 87cc064e35d4fc65caf2da13bf263b1323b16760 Mon Sep 17 00:00:00 2001 From: Hanna Kruppe Date: Sun, 12 Jan 2025 11:16:40 +0100 Subject: Introduce arch::aarch64 and use it for rint{,f} --- .../libm/etc/function-definitions.json | 2 ++ .../libm/src/math/arch/aarch64.rs | 33 ++++++++++++++++++++++ .../compiler-builtins/libm/src/math/arch/mod.rs | 7 +++++ library/compiler-builtins/libm/src/math/rint.rs | 5 +++- library/compiler-builtins/libm/src/math/rintf.rs | 5 +++- 5 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/arch/aarch64.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index f60a7e5673c..39b6c97029c 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -604,6 +604,7 @@ "rint": { "sources": [ "src/libm_helper.rs", + "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", "src/math/rint.rs" ], @@ -611,6 +612,7 @@ }, "rintf": { "sources": [ + "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", "src/math/rintf.rs" ], diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64.rs b/library/compiler-builtins/libm/src/math/arch/aarch64.rs new file mode 100644 index 00000000000..374ec11bfec --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/aarch64.rs @@ -0,0 +1,33 @@ +use core::arch::aarch64::{ + float32x2_t, float64x1_t, vdup_n_f32, vdup_n_f64, vget_lane_f32, vget_lane_f64, vrndn_f32, + vrndn_f64, +}; + +pub fn rint(x: f64) -> f64 { + // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. + let x_vec: float64x1_t = unsafe { vdup_n_f64(x) }; + + // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. + let result_vec: float64x1_t = unsafe { vrndn_f64(x_vec) }; + + // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. + let result: f64 = unsafe { vget_lane_f64::<0>(result_vec) }; + + result +} + +pub fn rintf(x: f32) -> f32 { + // There's a scalar form of this instruction (FRINTN) but core::arch doesn't expose it, so we + // have to use the vector form and drop the other lanes afterwards. + + // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. + let x_vec: float32x2_t = unsafe { vdup_n_f32(x) }; + + // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. + let result_vec: float32x2_t = unsafe { vrndn_f32(x_vec) }; + + // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. + let result: f32 = unsafe { vget_lane_f32::<0>(result_vec) }; + + result +} diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index 3992419cbaa..091d7650a5a 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -17,6 +17,13 @@ cfg_if! { } else if #[cfg(target_feature = "sse2")] { mod i686; pub use i686::{sqrt, sqrtf}; + } else if #[cfg(all( + target_arch = "aarch64", // TODO: also arm64ec? + target_feature = "neon", + target_endian = "little", // see https://github.com/rust-lang/stdarch/issues/1484 + ))] { + mod aarch64; + pub use aarch64::{rint, rintf}; } } diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 50192ffdf03..c9ea6402ec7 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -2,7 +2,10 @@ pub fn rint(x: f64) -> f64 { select_implementation! { name: rint, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), + use_arch: any( + all(target_arch = "wasm32", intrinsics_enabled), + all(target_arch = "aarch64", target_feature = "neon", target_endian = "little"), + ), args: x, } diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 64968b6be3a..33b5b3ddebf 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -2,7 +2,10 @@ pub fn rintf(x: f32) -> f32 { select_implementation! { name: rintf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), + use_arch: any( + all(target_arch = "wasm32", intrinsics_enabled), + all(target_arch = "aarch64", target_feature = "neon", target_endian = "little"), + ), args: x, } -- cgit 1.4.1-3-g733a5 From 504616d5a087126825357aae5a4a319d05f1a3ad Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 03:14:43 +0000 Subject: Rename the `test-multiprecision` feature to `build-mpfr` Currently the features that control what we test against are `build-musl` and `test-multiprecision`. I didn't name them very consistently and there isn't really any reason for that. Rename `test-multiprecision` to `build-mpfr` to better reflect what it actually does and to be more consistent with `build-musl`. --- library/compiler-builtins/libm/.github/workflows/main.yml | 4 ++-- library/compiler-builtins/libm/CONTRIBUTING.md | 2 +- library/compiler-builtins/libm/ci/run.sh | 8 ++++---- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 2 +- library/compiler-builtins/libm/crates/libm-test/src/lib.rs | 2 +- library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs | 2 +- .../libm/crates/libm-test/tests/multiprecision.rs | 2 +- .../libm/crates/libm-test/tests/z_extensive/main.rs | 6 +++--- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 7e371d6136d..d54288574ac 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -133,7 +133,7 @@ jobs: run: ./ci/download-musl.sh - run: | cargo clippy --all \ - --features libm-test/build-musl,libm-test/test-multiprecision \ + --features libm-test/build-musl,libm-test/build-mpfr \ --all-targets builtins: @@ -241,7 +241,7 @@ jobs: fi LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \ - --features test-multiprecision,unstable \ + --features build-mpfr,unstable \ --profile release-checked \ -- extensive - name: Print test logs if available diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index aadcdf03618..f7560878ddf 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -69,7 +69,7 @@ If you'd like to run tests with randomized inputs that get compared against infinite-precision results, run: ```sh -cargo test --features libm-test/test-multiprecision,libm-test/build-musl --release +cargo test --features libm-test/build-mpfr,libm-test/build-musl --release ``` The multiprecision tests use the [`rug`] crate for bindings to MPFR. MPFR can diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 244a22a076d..63678620c7c 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -44,11 +44,11 @@ case "$target" in # Targets that aren't cross compiled work fine # FIXME(ci): we should be able to enable aarch64 Linux here once GHA # support rolls out. - x86_64*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; - i686*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; - i586*) extra_flags="$extra_flags --features libm-test/test-multiprecision --features gmp-mpfr-sys/force-cross" ;; + x86_64*) extra_flags="$extra_flags --features libm-test/build-mpfr" ;; + i686*) extra_flags="$extra_flags --features libm-test/build-mpfr" ;; + i586*) extra_flags="$extra_flags --features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross" ;; # Apple aarch64 is native - aarch64*apple*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; + aarch64*apple*) extra_flags="$extra_flags --features libm-test/build-mpfr" ;; esac # FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 621e587c56d..3cf4a08e1da 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -12,7 +12,7 @@ unstable-float = ["libm/unstable-float", "rug?/nightly-float"] # Generate tests which are random inputs and the outputs are calculated with # musl libc. -test-multiprecision = ["dep:az", "dep:rug", "dep:gmp-mpfr-sys"] +build-mpfr = ["dep:az", "dep:rug", "dep:gmp-mpfr-sys"] # Build our own musl for testing and benchmarks build-musl = ["dep:musl-math-sys"] diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 6e7017f093c..cb89f1c8ba7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -5,7 +5,7 @@ pub mod domain; mod f8_impl; pub mod gen; -#[cfg(feature = "test-multiprecision")] +#[cfg(feature = "build-mpfr")] pub mod mpfloat; mod num; pub mod op; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 48a654caaf8..4a52091fe8d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -126,7 +126,7 @@ impl TestEnv { let id = ctx.fn_ident; let op = id.math_op(); - let will_run_mp = cfg!(feature = "test-multiprecision"); + let will_run_mp = cfg!(feature = "build-mpfr"); // Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run in QEMU. Start // with a reduced number on these platforms. diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index e2766cfdabd..2d8856e166e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -1,6 +1,6 @@ //! Test with "infinite precision" -#![cfg(feature = "test-multiprecision")] +#![cfg(feature = "build-mpfr")] use libm_test::domain::HasDomain; use libm_test::gen::random::RandomInput; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs index 3a2af88bd83..5448cb6eaa5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs @@ -1,14 +1,14 @@ //! `main` is just a wrapper to handle configuration. -#[cfg(not(feature = "test-multiprecision"))] +#[cfg(not(feature = "build-mpfr"))] fn main() { eprintln!("multiprecision not enabled; skipping extensive tests"); } -#[cfg(feature = "test-multiprecision")] +#[cfg(feature = "build-mpfr")] mod run; -#[cfg(feature = "test-multiprecision")] +#[cfg(feature = "build-mpfr")] fn main() { run::run(); } -- cgit 1.4.1-3-g733a5 From 3de783c40f5675f239db882f2aecf614907f1b01 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 03:17:54 +0000 Subject: Enable `build-mpfr` and `build-musl` by default Most users who are developing this crate are likely running on a Unix system, since there isn't much to test against otherwise. For convenience, enable the features required to run these tests by default. --- .../libm/.github/workflows/main.yml | 5 +--- library/compiler-builtins/libm/CONTRIBUTING.md | 11 ++++----- library/compiler-builtins/libm/ci/run.sh | 27 +++++++++++++--------- .../libm/crates/libm-test/Cargo.toml | 2 +- 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index d54288574ac..35b307f7711 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -131,10 +131,7 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Download musl source run: ./ci/download-musl.sh - - run: | - cargo clippy --all \ - --features libm-test/build-musl,libm-test/build-mpfr \ - --all-targets + - run: cargo clippy --all --all-features --all-targets builtins: name: Check use with compiler-builtins diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index f7560878ddf..ba7f78ca014 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -62,15 +62,12 @@ Check [PR #65] for an example. Normal tests can be executed with: ```sh -cargo test +# `--release` ables more test cases +cargo test --release ``` -If you'd like to run tests with randomized inputs that get compared against -infinite-precision results, run: - -```sh -cargo test --features libm-test/build-mpfr,libm-test/build-musl --release -``` +If you are on a system that cannot build musl or MPFR, passing +`--no-default-features` will run some limited tests. The multiprecision tests use the [`rug`] crate for bindings to MPFR. MPFR can be difficult to build on non-Unix systems, refer to [`gmp_mpfr_sys`] for help. diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 63678620c7c..35b84809fa2 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -14,7 +14,15 @@ if [ -z "$target" ]; then target="$host_target" fi -extra_flags="" +# We enumerate features manually. +extra_flags="--no-default-features" + +# Enable arch-specific routines when available. +extra_flags="$extra_flags --features arch" + +# Always enable `unstable-float` since it expands available API but does not +# change any implementations. +extra_flags="$extra_flags --features unstable-float" # We need to specifically skip tests for musl-math-sys on systems that can't # build musl since otherwise `--all` will activate it. @@ -57,14 +65,8 @@ case "$target" in *windows-gnu) extra_flags="$extra_flags --exclude libm-macros" ;; esac -# Make sure we can build with overriding features. We test the indibidual -# features it controls separately. -cargo check --no-default-features -cargo check --features "force-soft-floats" - -# Always enable `unstable-float` since it expands available API but does not -# change any implementations. -extra_flags="$extra_flags --features unstable-float" +# Make sure we can build with overriding features. +cargo check -p libm --no-default-features if [ "${BUILD_ONLY:-}" = "1" ]; then cmd="cargo build --target $target --package libm" @@ -80,11 +82,14 @@ else $cmd --features unstable-intrinsics $cmd --features unstable-intrinsics --benches - # Test the same in release mode, which also increases coverage. + # Test the same in release mode, which also increases coverage. Also ensure + # the soft float routines are checked. $cmd --profile release-checked + $cmd --profile release-checked --features force-soft-floats $cmd --profile release-checked --features unstable-intrinsics $cmd --profile release-checked --features unstable-intrinsics --benches - ENSURE_NO_PANIC=1 cargo build --target "$target" --release + # Ensure that the routines do not panic. + ENSURE_NO_PANIC=1 cargo build -p libm --target "$target" --no-default-features --release fi diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 3cf4a08e1da..d3f18ab3e5b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [features] -default = ["unstable-float"] +default = ["build-mpfr", "build-musl", "unstable-float"] # Propagated from libm because this affects which functions we test. unstable-float = ["libm/unstable-float", "rug?/nightly-float"] -- cgit 1.4.1-3-g733a5 From dfa694a8e43ad3fd56f2897ab48327a242d7c5b8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 03:12:12 +0000 Subject: Add a utility crate for quick evaluation Introduce a simple binary that can run arbitrary input against any of the available implementations (musl, MPFR, our libm). This provides an easy way to check results, or run specific cases against a debugger. Examples: $ cargo run -p util -- eval libm pow 1.6 2.4 3.089498284311124 $ cargo run -p util -- eval mpfr pow 1.6 2.4 3.089498284311124 $ cargo run -p util -- eval musl tgamma 1.2344597839132 0.9097442657960874 $ cargo run -p util -- eval mpfr tgamma 1.2344597839132 0.9097442657960874 $ cargo run -p util -- eval libm tgamma 1.2344597839132 0.9097442657960871 $ cargo run -p util -- eval musl sincos 3.1415926535 (8.979318433952318e-11, -1.0) --- library/compiler-builtins/libm/Cargo.toml | 1 + .../libm/crates/libm-test/src/mpfloat.rs | 26 +++ .../compiler-builtins/libm/crates/util/Cargo.toml | 19 ++ .../compiler-builtins/libm/crates/util/build.rs | 9 + .../compiler-builtins/libm/crates/util/src/main.rs | 243 +++++++++++++++++++++ 5 files changed, 298 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/util/Cargo.toml create mode 100644 library/compiler-builtins/libm/crates/util/build.rs create mode 100644 library/compiler-builtins/libm/crates/util/src/main.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index fc881b77e54..820c013478f 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -46,6 +46,7 @@ members = [ "crates/libm-macros", "crates/libm-test", "crates/musl-math-sys", + "crates/util", ] default-members = [ ".", diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index f71e72cd571..092f5f1d24d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -471,6 +471,32 @@ impl MpOp for crate::op::lgammaf_r::Routine { } } +/* stub implementations so we don't need to special case them */ + +impl MpOp for crate::op::nextafter::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + unimplemented!("nextafter does not yet have a MPFR operation"); + } + + fn run(_this: &mut Self::MpTy, _input: Self::RustArgs) -> Self::RustRet { + unimplemented!("nextafter does not yet have a MPFR operation"); + } +} + +impl MpOp for crate::op::nextafterf::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + unimplemented!("nextafter does not yet have a MPFR operation"); + } + + fn run(_this: &mut Self::MpTy, _input: Self::RustArgs) -> Self::RustRet { + unimplemented!("nextafter does not yet have a MPFR operation"); + } +} + /// `rug` does not provide `remquo` so this exposes `mpfr_remquo`. See rug#76. fn mpfr_remquo(r: &mut MpFloat, x: &MpFloat, y: &MpFloat, round: Round) -> (Ordering, c_long) { let r = r.as_raw_mut(); diff --git a/library/compiler-builtins/libm/crates/util/Cargo.toml b/library/compiler-builtins/libm/crates/util/Cargo.toml new file mode 100644 index 00000000000..acf5db704b1 --- /dev/null +++ b/library/compiler-builtins/libm/crates/util/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "util" +version = "0.1.0" +edition = "2021" +publish = false + +[features] +default = ["build-musl", "build-mpfr", "unstable-float"] +build-musl = ["libm-test/build-musl", "dep:musl-math-sys"] +build-mpfr = ["libm-test/build-mpfr", "dep:az", "dep:rug"] +unstable-float = ["libm/unstable-float", "libm-test/unstable-float", "rug?/nightly-float"] + +[dependencies] +az = { version = "1.2.1", optional = true } +libm = { path = "../..", default-features = false } +libm-macros = { path = "../libm-macros" } +libm-test = { path = "../libm-test", default-features = false } +musl-math-sys = { path = "../musl-math-sys", optional = true } +rug = { version = "1.26.1", optional = true, default-features = false, features = ["float", "std"] } diff --git a/library/compiler-builtins/libm/crates/util/build.rs b/library/compiler-builtins/libm/crates/util/build.rs new file mode 100644 index 00000000000..0745ef3dd6f --- /dev/null +++ b/library/compiler-builtins/libm/crates/util/build.rs @@ -0,0 +1,9 @@ +#![allow(unexpected_cfgs)] + +#[path = "../../configure.rs"] +mod configure; + +fn main() { + let cfg = configure::Config::from_env(); + configure::emit_libm_config(&cfg); +} diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs new file mode 100644 index 00000000000..f7bd31bb689 --- /dev/null +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -0,0 +1,243 @@ +//! Helper CLI utility for common tasks. + +#![cfg_attr(f16_enabled, feature(f16))] +#![cfg_attr(f128_enabled, feature(f128))] + +use std::any::type_name; +use std::env; +use std::str::FromStr; + +#[cfg(feature = "build-mpfr")] +use az::Az; +#[cfg(feature = "build-mpfr")] +use libm_test::mpfloat::MpOp; +use libm_test::{MathOp, TupleCall}; + +const USAGE: &str = "\ +usage: + +cargo run -p util -- + +SUBCOMMAND: + eval inputs... + Evaulate the expression with a given basis. This can be useful for + running routines with a debugger, or quickly checking input. Examples: + * eval musl sinf 1.234 # print the results of musl sinf(1.234f32) + * eval mpfr pow 1.234 2.432 # print the results of mpfr pow(1.234, 2.432) +"; + +fn main() { + let args = env::args().collect::>(); + let str_args = args.iter().map(|s| s.as_str()).collect::>(); + + match &str_args.as_slice()[1..] { + ["eval", basis, op, inputs @ ..] => do_eval(basis, op, inputs), + _ => { + println!("{USAGE}\nunrecognized input `{str_args:?}`"); + std::process::exit(1); + } + } +} + +macro_rules! handle_call { + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + attrs: [$($attr:meta),*], + extra: ($basis:ident, $op:ident, $inputs:ident), + fn_extra: $musl_fn:expr, + ) => { + $(#[$attr])* + if $op == stringify!($fn_name) { + type Op = libm_test::op::$fn_name::Routine; + + let input = <$RustArgs>::parse($inputs); + let libm_fn: ::RustFn = libm::$fn_name; + + let output = match $basis { + "libm" => input.call(libm_fn), + #[cfg(feature = "build-musl")] + "musl" => { + let musl_fn: ::CFn = + $musl_fn.unwrap_or_else(|| panic!("no musl function for {}", $op)); + input.call(musl_fn) + } + #[cfg(feature = "build-mpfr")] + "mpfr" => { + let mut mp = ::new_mp(); + Op::run(&mut mp, input) + } + _ => panic!("unrecognized or disabled basis '{}'", $basis), + }; + println!("{output:?}"); + return; + } + }; +} + +/// Evaluate the specified operation with a given basis. +fn do_eval(basis: &str, op: &str, inputs: &[&str]) { + libm_macros::for_each_function! { + callback: handle_call, + emit_types: [CFn, RustFn, RustArgs], + extra: (basis, op, inputs), + fn_extra: match MACRO_FN_NAME { + copysignf16 | copysignf128 | fabsf16 | fabsf128 => None, + _ => Some(musl_math_sys::MACRO_FN_NAME) + } + } + + panic!("no operation matching {op}"); +} + +/// Parse a tuple from a space-delimited string. +trait ParseTuple { + fn parse(input: &[&str]) -> Self; +} + +macro_rules! impl_parse_tuple { + ($ty:ty) => { + impl ParseTuple for ($ty,) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 1, "expected a single argument, got {input:?}"); + (parse(input, 0),) + } + } + + impl ParseTuple for ($ty, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse(input, 0), parse(input, 1)) + } + } + + impl ParseTuple for ($ty, i32) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse(input, 0), parse(input, 1)) + } + } + + impl ParseTuple for (i32, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse(input, 0), parse(input, 1)) + } + } + + impl ParseTuple for ($ty, $ty, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected three arguments, got {input:?}"); + (parse(input, 0), parse(input, 1), parse(input, 3)) + } + } + }; +} + +#[allow(unused_macros)] +#[cfg(feature = "build-mpfr")] +macro_rules! impl_parse_tuple_via_rug { + ($ty:ty) => { + impl ParseTuple for ($ty,) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 1, "expected a single argument, got {input:?}"); + (parse_rug(input, 0),) + } + } + + impl ParseTuple for ($ty, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse_rug(input, 0), parse_rug(input, 1)) + } + } + + impl ParseTuple for ($ty, i32) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse_rug(input, 0), parse(input, 1)) + } + } + + impl ParseTuple for (i32, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse(input, 0), parse_rug(input, 1)) + } + } + + impl ParseTuple for ($ty, $ty, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected three arguments, got {input:?}"); + (parse_rug(input, 0), parse_rug(input, 1), parse_rug(input, 3)) + } + } + }; +} + +// Fallback for when Rug is not built. +#[allow(unused_macros)] +#[cfg(not(feature = "build-mpfr"))] +macro_rules! impl_parse_tuple_via_rug { + ($ty:ty) => { + impl ParseTuple for ($ty,) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + + impl ParseTuple for ($ty, $ty) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + + impl ParseTuple for ($ty, i32) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + + impl ParseTuple for (i32, $ty) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + + impl ParseTuple for ($ty, $ty, $ty) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + }; +} + +impl_parse_tuple!(f32); +impl_parse_tuple!(f64); + +#[cfg(f16_enabled)] +impl_parse_tuple_via_rug!(f16); +#[cfg(f128_enabled)] +impl_parse_tuple_via_rug!(f128); + +/// Try to parse the number, printing a nice message on failure. +fn parse(input: &[&str], idx: usize) -> F { + let s = input[idx]; + s.parse().unwrap_or_else(|_| panic!("invalid {} input '{s}'", type_name::())) +} + +/// Try to parse the float type going via `rug`, for `f16` and `f128` which don't yet implement +/// `FromStr`. +#[cfg(feature = "build-mpfr")] +fn parse_rug(input: &[&str], idx: usize) -> F +where + rug::Float: az::Cast, +{ + let s = input[idx]; + let x = + rug::Float::parse(s).unwrap_or_else(|_| panic!("invalid {} input '{s}'", type_name::())); + let x = rug::Float::with_val(F::BITS, x); + x.az() +} -- cgit 1.4.1-3-g733a5 From 6ac06a97e591f3373b16859756567901ff5056fb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 11 Jan 2025 23:38:19 +0000 Subject: Add a generic version of `trunc` The algorithm is identical for both types, so this is a straightforward routine to port. --- .../compiler-builtins/libm/src/math/generic/mod.rs | 2 + .../libm/src/math/generic/trunc.rs | 54 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 +- library/compiler-builtins/libm/src/math/trunc.rs | 30 +----------- library/compiler-builtins/libm/src/math/truncf.rs | 22 +-------- 5 files changed, 59 insertions(+), 51 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/trunc.rs diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 08524b685e2..e5166ca10eb 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -1,5 +1,7 @@ mod copysign; mod fabs; +mod trunc; pub use copysign::copysign; pub use fabs::fabs; +pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs new file mode 100644 index 00000000000..5d0ba6109af --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -0,0 +1,54 @@ +use super::super::{Float, Int, IntTy, MinInt}; + +pub fn trunc(x: F) -> F { + let mut xi: F::Int = x.to_bits(); + let e: i32 = x.exp_unbiased(); + + // C1: The represented value has no fractional part, so no truncation is needed + if e >= F::SIG_BITS as i32 { + return x; + } + + let mask = if e < 0 { + // C2: If the exponent is negative, the result will be zero so we mask out everything + // except the sign. + F::SIGN_MASK + } else { + // C3: Otherwise, we mask out the last `e` bits of the significand. + !(F::SIG_MASK >> e.unsigned()) + }; + + // C4: If the to-be-masked-out portion is already zero, we have an exact result + if (xi & !mask) == IntTy::::ZERO { + return x; + } + + // C5: Otherwise the result is inexact and we will truncate. Raise `FE_INEXACT`, mask the + // result, and return. + force_eval!(x + F::MAX); + xi &= mask; + F::from_bits(xi) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_biteq!(trunc(1.1f32), 1.0); + assert_biteq!(trunc(1.1f64), 1.0); + + // C1 + assert_biteq!(trunc(hf32!("0x1p23")), hf32!("0x1p23")); + assert_biteq!(trunc(hf64!("0x1p52")), hf64!("0x1p52")); + assert_biteq!(trunc(hf32!("-0x1p23")), hf32!("-0x1p23")); + assert_biteq!(trunc(hf64!("-0x1p52")), hf64!("-0x1p52")); + + // C2 + assert_biteq!(trunc(hf32!("0x1p-1")), 0.0); + assert_biteq!(trunc(hf64!("0x1p-1")), 0.0); + assert_biteq!(trunc(hf32!("-0x1p-1")), -0.0); + assert_biteq!(trunc(hf64!("-0x1p-1")), -0.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 5baf35e4245..c0d038a0c67 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -121,7 +121,7 @@ use self::rem_pio2::rem_pio2; use self::rem_pio2_large::rem_pio2_large; use self::rem_pio2f::rem_pio2f; #[allow(unused_imports)] -use self::support::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; +use self::support::{CastFrom, CastInto, DInt, Float, HInt, Int, IntTy, MinInt}; // Public modules mod acos; diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 7e5c4f2c2ae..2cc8aaa7e8f 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -1,5 +1,3 @@ -use core::f64; - /// Rounds the number toward 0 to the closest integral value (f64). /// /// This effectively removes the decimal part of the number, leaving the integral part. @@ -11,31 +9,5 @@ pub fn trunc(x: f64) -> f64 { args: x, } - let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 - - let mut i: u64 = x.to_bits(); - let mut e: i64 = ((i >> 52) & 0x7ff) as i64 - 0x3ff + 12; - let m: u64; - - if e >= 52 + 12 { - return x; - } - if e < 12 { - e = 1; - } - m = -1i64 as u64 >> e; - if (i & m) == 0 { - return x; - } - force_eval!(x + x1p120); - i &= !m; - f64::from_bits(i) -} - -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::trunc(1.1), 1.0); - } + super::generic::trunc(x) } diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index b491747d999..14533a26706 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -1,5 +1,3 @@ -use core::f32; - /// Rounds the number toward 0 to the closest integral value (f32). /// /// This effectively removes the decimal part of the number, leaving the integral part. @@ -11,25 +9,7 @@ pub fn truncf(x: f32) -> f32 { args: x, } - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let mut i: u32 = x.to_bits(); - let mut e: i32 = ((i >> 23) & 0xff) as i32 - 0x7f + 9; - let m: u32; - - if e >= 23 + 9 { - return x; - } - if e < 9 { - e = 1; - } - m = -1i32 as u32 >> e; - if (i & m) == 0 { - return x; - } - force_eval!(x + x1p120); - i &= !m; - f32::from_bits(i) + super::generic::trunc(x) } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -- cgit 1.4.1-3-g733a5 From b558b365d380448159564df45de9638a60905815 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 04:12:56 +0000 Subject: Add `truncf16` and `truncf128` Use the generic algorithms to provide implementations for these routines. --- .../libm/crates/compiler-builtins-smoke-test/src/lib.rs | 2 ++ .../libm/crates/libm-macros/src/shared.rs | 4 ++-- .../libm/crates/libm-test/benches/random.rs | 2 +- .../libm/crates/libm-test/src/domain.rs | 10 ++++++++++ .../libm/crates/libm-test/src/mpfloat.rs | 3 +++ .../libm/crates/libm-test/tests/compare_built_musl.rs | 4 +++- library/compiler-builtins/libm/crates/util/src/main.rs | 2 +- .../compiler-builtins/libm/etc/function-definitions.json | 16 ++++++++++++++++ library/compiler-builtins/libm/etc/function-list.txt | 2 ++ library/compiler-builtins/libm/src/math/generic/trunc.rs | 3 +++ library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ library/compiler-builtins/libm/src/math/truncf128.rs | 7 +++++++ library/compiler-builtins/libm/src/math/truncf16.rs | 7 +++++++ 13 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/truncf128.rs create mode 100644 library/compiler-builtins/libm/src/math/truncf16.rs diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index 95ecb840d29..3416a222959 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -157,6 +157,8 @@ no_mangle! { tgammaf(x: f32) -> f32; trunc(x: f64) -> f64; truncf(x: f32) -> f32; + truncf128(x: f128) -> f128; + truncf16(x: f16) -> f16; y0(x: f64) -> f64; y0f(x: f32) -> f32; y1(x: f64) -> f64; diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 16547404fff..24fccd6f248 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["fabsf16"], + &["fabsf16", "truncf16"], ), ( // `fn(f32) -> f32` @@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["fabsf128"], + &["fabsf128", "truncf128"], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index cd1e2d2ccc6..8c6afff2598 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -117,7 +117,7 @@ libm_macros::for_each_function! { exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)), // Musl does not provide `f16` and `f128` functions - copysignf16 | copysignf128 | fabsf16 | fabsf128 => (false, None), + copysignf16 | copysignf128 | fabsf16 | fabsf128 | truncf16 | truncf128 => (false, None), // By default we never skip (false) and always have a musl function available _ => (false, Some(musl_math_sys::MACRO_FN_NAME)) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index 52393d40243..adafb9faa35 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -199,3 +199,13 @@ impl HasDomain for crate::op::fabsf16::Routine { impl HasDomain for crate::op::fabsf128::Routine { const DOMAIN: Domain = Domain::::UNBOUNDED; } + +#[cfg(f16_enabled)] +impl HasDomain for crate::op::truncf16::Routine { + const DOMAIN: Domain = Domain::::UNBOUNDED; +} + +#[cfg(f128_enabled)] +impl HasDomain for crate::op::truncf128::Routine { + const DOMAIN: Domain = Domain::::UNBOUNDED; +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 092f5f1d24d..2a740ed477e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -141,6 +141,7 @@ libm_macros::for_each_function! { lgamma_r, lgammaf_r, modf, modff, nextafter, nextafterf, pow,powf, remquo, remquof, scalbn, scalbnf, sincos, sincosf, yn, ynf, copysignf16, copysignf128, fabsf16, fabsf128, + truncf16, truncf128, ], fn_extra: match MACRO_FN_NAME { // Remap function names that are different between mpfr and libm @@ -202,11 +203,13 @@ impl_no_round! { #[cfg(f16_enabled)] impl_no_round! { fabsf16 => abs_mut; + truncf16 => trunc_mut; } #[cfg(f128_enabled)] impl_no_round! { fabsf128 => abs_mut; + truncf128 => trunc_mut; } /// Some functions are difficult to do in a generic way. Implement them here. diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index b91d7f9f50d..a395c6c5d38 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -48,7 +48,7 @@ where libm_macros::for_each_function! { callback: musl_rand_tests, // Musl does not support `f16` and `f128` on all platforms. - skip: [copysignf16, copysignf128, fabsf16, fabsf128], + skip: [copysignf16, copysignf128, fabsf16, fabsf128, truncf16, truncf128], attributes: [ #[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586 [exp10, exp10f, exp2, exp2f, rint] @@ -146,5 +146,7 @@ libm_macros::for_each_function! { // Not provided by musl fabsf16, fabsf128, + truncf16, + truncf128, ], } diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index f7bd31bb689..c8a03068a31 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -84,7 +84,7 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { emit_types: [CFn, RustFn, RustArgs], extra: (basis, op, inputs), fn_extra: match MACRO_FN_NAME { - copysignf16 | copysignf128 | fabsf16 | fabsf128 => None, + copysignf16 | copysignf128 | fabsf16 | fabsf128 | truncf16 | truncf128 => None, _ => Some(musl_math_sys::MACRO_FN_NAME) } } diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 39b6c97029c..86fa0210189 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -743,6 +743,7 @@ "sources": [ "src/libm_helper.rs", "src/math/arch/wasm32.rs", + "src/math/generic/trunc.rs", "src/math/trunc.rs" ], "type": "f64" @@ -750,10 +751,25 @@ "truncf": { "sources": [ "src/math/arch/wasm32.rs", + "src/math/generic/trunc.rs", "src/math/truncf.rs" ], "type": "f32" }, + "truncf128": { + "sources": [ + "src/math/generic/trunc.rs", + "src/math/truncf128.rs" + ], + "type": "f128" + }, + "truncf16": { + "sources": [ + "src/math/generic/trunc.rs", + "src/math/truncf16.rs" + ], + "type": "f16" + }, "y0": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 0a1bbab244d..8aa901762ab 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -111,6 +111,8 @@ tgamma tgammaf trunc truncf +truncf128 +truncf16 y0 y0f y1 diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs index 5d0ba6109af..ca5f1bdd627 100644 --- a/library/compiler-builtins/libm/src/math/generic/trunc.rs +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -1,3 +1,6 @@ +/* SPDX-License-Identifier: MIT + * origin: musl src/math/trunc.c */ + use super::super::{Float, Int, IntTy, MinInt}; pub fn trunc(x: F) -> F { diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c0d038a0c67..723be0e1dfd 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -343,9 +343,11 @@ cfg_if! { if #[cfg(f16_enabled)] { mod copysignf16; mod fabsf16; + mod truncf16; pub use self::copysignf16::copysignf16; pub use self::fabsf16::fabsf16; + pub use self::truncf16::truncf16; } } @@ -353,9 +355,11 @@ cfg_if! { if #[cfg(f128_enabled)] { mod copysignf128; mod fabsf128; + mod truncf128; pub use self::copysignf128::copysignf128; pub use self::fabsf128::fabsf128; + pub use self::truncf128::truncf128; } } diff --git a/library/compiler-builtins/libm/src/math/truncf128.rs b/library/compiler-builtins/libm/src/math/truncf128.rs new file mode 100644 index 00000000000..9dccc0d0e9d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/truncf128.rs @@ -0,0 +1,7 @@ +/// Rounds the number toward 0 to the closest integral value (f128). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf128(x: f128) -> f128 { + super::generic::trunc(x) +} diff --git a/library/compiler-builtins/libm/src/math/truncf16.rs b/library/compiler-builtins/libm/src/math/truncf16.rs new file mode 100644 index 00000000000..d7c3d225cf9 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/truncf16.rs @@ -0,0 +1,7 @@ +/// Rounds the number toward 0 to the closest integral value (f16). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf16(x: f16) -> f16 { + super::generic::trunc(x) +} -- cgit 1.4.1-3-g733a5 From 23c9f74b584f93dada7d7556ac9112b51a844fdd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 10:17:51 +0000 Subject: Disable `util` and `libm-macros` for optimized tests These crates take time building in CI, especially with the release profile having LTO enabled, but there isn't really any reason to test them with different features or in release mode. Disable this to save some CI runtime. --- library/compiler-builtins/libm/ci/run.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 35b84809fa2..94ff54cb725 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -77,8 +77,14 @@ if [ "${BUILD_ONLY:-}" = "1" ]; then else cmd="cargo test --all --target $target $extra_flags" - # Test once without intrinsics, once with intrinsics enabled + # Test once without intrinsics $cmd + + # Exclude the macros and utile crates from the rest of the tests to save CI + # runtime, they shouldn't have anything feature- or opt-level-dependent. + cmd="$cmd --exclude util --exclude libm-macros" + + # Test once with intrinsics enabled $cmd --features unstable-intrinsics $cmd --features unstable-intrinsics --benches -- cgit 1.4.1-3-g733a5 From 23dfe62a9db9ac4470b830a466fbaee8035780c4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 10:29:56 +0000 Subject: Format the MPFR manual implementation list --- .../libm/crates/libm-test/src/mpfloat.rs | 48 ++++++++++++++++++---- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 2a740ed477e..a4aad81f709 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -135,13 +135,47 @@ libm_macros::for_each_function! { emit_types: [RustFn], skip: [ // Most of these need a manual implementation - fabs, ceil, copysign, floor, rint, round, trunc, - fabsf, ceilf, copysignf, floorf, rintf, roundf, truncf, - fmod, fmodf, frexp, frexpf, ilogb, ilogbf, jn, jnf, ldexp, ldexpf, - lgamma_r, lgammaf_r, modf, modff, nextafter, nextafterf, pow,powf, - remquo, remquof, scalbn, scalbnf, sincos, sincosf, yn, ynf, - copysignf16, copysignf128, fabsf16, fabsf128, - truncf16, truncf128, + ceil, + ceilf, + copysign, + copysignf, + copysignf128, + copysignf16, + fabs, + fabsf, + fabsf128, + fabsf16,floor, + floorf, + fmod, + fmodf, + frexp, + frexpf, + ilogb, + ilogbf, + jn, + jnf, + ldexp,ldexpf, + lgamma_r, + lgammaf_r, + modf, + modff, + nextafter, + nextafterf, + pow, + powf,remquo, + remquof, + rint, + rintf, + round, + roundf, + scalbn, + scalbnf, + sincos,sincosf, + trunc, + truncf, + truncf128, + truncf16,yn, + ynf, ], fn_extra: match MACRO_FN_NAME { // Remap function names that are different between mpfr and libm -- cgit 1.4.1-3-g733a5 From 0f285df71649ca3120ca52b91b6398e6c9b17a10 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 13:49:43 +0000 Subject: Add a generic version of `fdim` --- .../compiler-builtins/libm/etc/function-definitions.json | 6 ++++-- library/compiler-builtins/libm/src/math/fdim.rs | 12 +----------- library/compiler-builtins/libm/src/math/fdimf.rs | 12 +----------- library/compiler-builtins/libm/src/math/generic/fdim.rs | 13 +++++++++++++ library/compiler-builtins/libm/src/math/generic/mod.rs | 2 ++ 5 files changed, 21 insertions(+), 24 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/fdim.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 86fa0210189..1e6d260feea 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -289,13 +289,15 @@ "fdim": { "sources": [ "src/libm_helper.rs", - "src/math/fdim.rs" + "src/math/fdim.rs", + "src/math/generic/fdim.rs" ], "type": "f64" }, "fdimf": { "sources": [ - "src/math/fdimf.rs" + "src/math/fdimf.rs", + "src/math/generic/fdim.rs" ], "type": "f32" }, diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index 7c58cb5a9a2..10ffa2881dd 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -1,5 +1,3 @@ -use core::f64; - /// Positive difference (f64) /// /// Determines the positive difference between arguments, returning: @@ -10,13 +8,5 @@ use core::f64; /// A range error may occur. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdim(x: f64, y: f64) -> f64 { - if x.is_nan() { - x - } else if y.is_nan() { - y - } else if x > y { - x - y - } else { - 0.0 - } + super::generic::fdim(x, y) } diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index 2abd49a64c9..367ef517c63 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -1,5 +1,3 @@ -use core::f32; - /// Positive difference (f32) /// /// Determines the positive difference between arguments, returning: @@ -10,13 +8,5 @@ use core::f32; /// A range error may occur. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdimf(x: f32, y: f32) -> f32 { - if x.is_nan() { - x - } else if y.is_nan() { - y - } else if x > y { - x - y - } else { - 0.0 - } + super::generic::fdim(x, y) } diff --git a/library/compiler-builtins/libm/src/math/generic/fdim.rs b/library/compiler-builtins/libm/src/math/generic/fdim.rs new file mode 100644 index 00000000000..2e54a41deea --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fdim.rs @@ -0,0 +1,13 @@ +use super::super::Float; + +pub fn fdim(x: F, y: F) -> F { + if x.is_nan() { + x + } else if y.is_nan() { + y + } else if x > y { + x - y + } else { + F::ZERO + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index e5166ca10eb..2b068d6c54d 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -1,7 +1,9 @@ mod copysign; mod fabs; +mod fdim; mod trunc; pub use copysign::copysign; pub use fabs::fabs; +pub use fdim::fdim; pub use trunc::trunc; -- cgit 1.4.1-3-g733a5 From 13b5bf3959b93e4aa32c519f999d8e3cb1f95176 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 13:58:40 +0000 Subject: Add `fdimf16` and `fdimf128` Use the generic algorithms to provide implementations for these routines. --- .../libm/crates/compiler-builtins-smoke-test/src/lib.rs | 2 ++ .../libm/crates/libm-macros/src/shared.rs | 4 ++-- .../libm/crates/libm-test/benches/random.rs | 9 ++++++++- .../libm/crates/libm-test/src/domain.rs | 10 ++++++++++ .../libm/crates/libm-test/src/mpfloat.rs | 2 +- .../libm/crates/libm-test/tests/compare_built_musl.rs | 17 ++++++++++++++--- .../libm/crates/libm-test/tests/multiprecision.rs | 2 ++ library/compiler-builtins/libm/crates/util/src/main.rs | 9 ++++++++- .../libm/etc/function-definitions.json | 14 ++++++++++++++ library/compiler-builtins/libm/etc/function-list.txt | 2 ++ library/compiler-builtins/libm/src/libm_helper.rs | 2 ++ library/compiler-builtins/libm/src/math/fdimf128.rs | 12 ++++++++++++ library/compiler-builtins/libm/src/math/fdimf16.rs | 12 ++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ 14 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fdimf128.rs create mode 100644 library/compiler-builtins/libm/src/math/fdimf16.rs diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index 3416a222959..b9521eb0715 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -93,6 +93,8 @@ no_mangle! { fabsf16(x: f16) -> f16; fdim(x: f64, y: f64) -> f64; fdimf(x: f32, y: f32) -> f32; + fdimf128(x: f128, y: f128) -> f128; + fdimf16(x: f16, y: f16) -> f16; floor(x: f64) -> f64; floorf(x: f32) -> f32; fma(x: f64, y: f64, z: f64) -> f64; diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 24fccd6f248..60838196236 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -47,7 +47,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, None, - &["copysignf16"], + &["copysignf16", "fdimf16"], ), ( // `(f32, f32) -> f32` @@ -90,7 +90,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, None, - &["copysignf128"], + &["copysignf128", "fdimf128"], ), ( // `(f32, f32, f32) -> f32` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 8c6afff2598..e790022779f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -117,7 +117,14 @@ libm_macros::for_each_function! { exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)), // Musl does not provide `f16` and `f128` functions - copysignf16 | copysignf128 | fabsf16 | fabsf128 | truncf16 | truncf128 => (false, None), + copysignf128 + | copysignf16 + | fabsf128 + | fabsf16 + | fdimf128 + | fdimf16 + | truncf128 + | truncf16 => (false, None), // By default we never skip (false) and always have a musl function available _ => (false, Some(musl_math_sys::MACRO_FN_NAME)) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index adafb9faa35..68b91bf02e8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -200,6 +200,16 @@ impl HasDomain for crate::op::fabsf128::Routine { const DOMAIN: Domain = Domain::::UNBOUNDED; } +#[cfg(f16_enabled)] +impl HasDomain for crate::op::fdimf16::Routine { + const DOMAIN: Domain = Domain::::UNBOUNDED; +} + +#[cfg(f128_enabled)] +impl HasDomain for crate::op::fdimf128::Routine { + const DOMAIN: Domain = Domain::::UNBOUNDED; +} + #[cfg(f16_enabled)] impl HasDomain for crate::op::truncf16::Routine { const DOMAIN: Domain = Domain::::UNBOUNDED; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index a4aad81f709..9d95356d39b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -181,7 +181,7 @@ libm_macros::for_each_function! { // Remap function names that are different between mpfr and libm expm1 | expm1f => exp_m1, fabs | fabsf => abs, - fdim | fdimf => positive_diff, + fdim | fdimf | fdimf16 | fdimf128 => positive_diff, fma | fmaf => mul_add, fmax | fmaxf => max, fmin | fminf => min, diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index a395c6c5d38..836c425a589 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -48,7 +48,16 @@ where libm_macros::for_each_function! { callback: musl_rand_tests, // Musl does not support `f16` and `f128` on all platforms. - skip: [copysignf16, copysignf128, fabsf16, fabsf128, truncf16, truncf128], + skip: [ + copysignf128, + copysignf16, + fabsf128, + fabsf16, + fdimf128, + fdimf16, + truncf128, + truncf16, + ], attributes: [ #[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586 [exp10, exp10f, exp2, exp2f, rint] @@ -144,9 +153,11 @@ libm_macros::for_each_function! { ynf, // Not provided by musl - fabsf16, fabsf128, - truncf16, + fabsf16, + fdimf128, + fdimf16, truncf128, + truncf16, ], } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 2d8856e166e..123abfdaf8b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -120,6 +120,8 @@ libm_macros::for_each_function! { copysignf128, fdim, fdimf, + fdimf16, + fdimf128, fma, fmaf, fmax, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index c8a03068a31..b979c60ad3c 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -84,7 +84,14 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { emit_types: [CFn, RustFn, RustArgs], extra: (basis, op, inputs), fn_extra: match MACRO_FN_NAME { - copysignf16 | copysignf128 | fabsf16 | fabsf128 | truncf16 | truncf128 => None, + copysignf128 + | copysignf16 + | fabsf128 + | fabsf16 + | fdimf128 + | fdimf16 + | truncf128 + | truncf16 => None, _ => Some(musl_math_sys::MACRO_FN_NAME) } } diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 1e6d260feea..dbaac931c76 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -301,6 +301,20 @@ ], "type": "f32" }, + "fdimf128": { + "sources": [ + "src/math/fdimf128.rs", + "src/math/generic/fdim.rs" + ], + "type": "f128" + }, + "fdimf16": { + "sources": [ + "src/math/fdimf16.rs", + "src/math/generic/fdim.rs" + ], + "type": "f16" + }, "floor": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 8aa901762ab..7f96a436227 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -43,6 +43,8 @@ fabsf128 fabsf16 fdim fdimf +fdimf128 +fdimf16 floor floorf fma diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index f087267e46c..73bae456761 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -176,6 +176,7 @@ libm_helper! { funcs: { (fn copysign(x: f16, y: f16) -> (f16); => copysignf16); (fn fabs(x: f16) -> (f16); => fabsf16); + (fn fdim(x: f16, y: f16) -> (f16); => fdimf16); } } @@ -185,5 +186,6 @@ libm_helper! { funcs: { (fn copysign(x: f128, y: f128) -> (f128); => copysignf128); (fn fabs(x: f128) -> (f128); => fabsf128); + (fn fdim(x: f128, y: f128) -> (f128); => fdimf128); } } diff --git a/library/compiler-builtins/libm/src/math/fdimf128.rs b/library/compiler-builtins/libm/src/math/fdimf128.rs new file mode 100644 index 00000000000..6f3d1d0ff1d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fdimf128.rs @@ -0,0 +1,12 @@ +/// Positive difference (f128) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf128(x: f128, y: f128) -> f128 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fdimf16.rs b/library/compiler-builtins/libm/src/math/fdimf16.rs new file mode 100644 index 00000000000..37bd6885817 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fdimf16.rs @@ -0,0 +1,12 @@ +/// Positive difference (f16) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf16(x: f16, y: f16) -> f16 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 723be0e1dfd..03adb6be193 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -343,10 +343,12 @@ cfg_if! { if #[cfg(f16_enabled)] { mod copysignf16; mod fabsf16; + mod fdimf16; mod truncf16; pub use self::copysignf16::copysignf16; pub use self::fabsf16::fabsf16; + pub use self::fdimf16::fdimf16; pub use self::truncf16::truncf16; } } @@ -355,10 +357,12 @@ cfg_if! { if #[cfg(f128_enabled)] { mod copysignf128; mod fabsf128; + mod fdimf128; mod truncf128; pub use self::copysignf128::copysignf128; pub use self::fabsf128::fabsf128; + pub use self::fdimf128::fdimf128; pub use self::truncf128::truncf128; } } -- cgit 1.4.1-3-g733a5 From fd7a45f7f6c68f7d2c3ba6851c313c4163a4782b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 22:57:38 +0000 Subject: Don't set `codegen-units=1` by default in CI We can set this only for the release profile, there isn't any reason to have it set for debug tests. --- library/compiler-builtins/libm/Cargo.toml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 820c013478f..f84f3eac6a4 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -61,14 +61,15 @@ exclude = [ [dev-dependencies] no-panic = "0.1.30" - -# This is needed for no-panic to correctly detect the lack of panics [profile.release] +# Options for no-panic to correctly detect the lack of panics +codegen-units = 1 lto = "fat" # Release mode with debug assertions [profile.release-checked] -inherits = "release" +codegen-units = 1 debug-assertions = true +inherits = "release" lto = "fat" overflow-checks = true -- cgit 1.4.1-3-g733a5 From bcd9d8a5c33d24b2f817a3e9cf5d5a16606f83cd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 23:00:39 +0000 Subject: Reduce indentation in `run.sh` using early return --- library/compiler-builtins/libm/ci/run.sh | 47 ++++++++++++++++---------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 94ff54cb725..008f32d5b8c 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -3,8 +3,6 @@ set -eux export RUST_BACKTRACE="${RUST_BACKTRACE:-full}" -# Needed for no-panic to correct detect a lack of panics -export RUSTFLAGS="${RUSTFLAGS:-} -Ccodegen-units=1" target="${1:-}" @@ -69,33 +67,36 @@ esac cargo check -p libm --no-default-features if [ "${BUILD_ONLY:-}" = "1" ]; then + # If we are on targets that can't run tests, verify that we can build. cmd="cargo build --target $target --package libm" $cmd $cmd --features unstable-intrinsics echo "can't run tests on $target; skipping" -else - cmd="cargo test --all --target $target $extra_flags" + exit +fi - # Test once without intrinsics - $cmd +# Otherwise, run the test suite. - # Exclude the macros and utile crates from the rest of the tests to save CI - # runtime, they shouldn't have anything feature- or opt-level-dependent. - cmd="$cmd --exclude util --exclude libm-macros" +cmd="cargo test --all --target $target $extra_flags" - # Test once with intrinsics enabled - $cmd --features unstable-intrinsics - $cmd --features unstable-intrinsics --benches - - # Test the same in release mode, which also increases coverage. Also ensure - # the soft float routines are checked. - $cmd --profile release-checked - $cmd --profile release-checked --features force-soft-floats - $cmd --profile release-checked --features unstable-intrinsics - $cmd --profile release-checked --features unstable-intrinsics --benches - - # Ensure that the routines do not panic. - ENSURE_NO_PANIC=1 cargo build -p libm --target "$target" --no-default-features --release -fi +# Test once without intrinsics +$cmd + +# Exclude the macros and utile crates from the rest of the tests to save CI +# runtime, they shouldn't have anything feature- or opt-level-dependent. +cmd="$cmd --exclude util --exclude libm-macros" + +# Test once with intrinsics enabled +$cmd --features unstable-intrinsics +$cmd --features unstable-intrinsics --benches + +# Test the same in release mode, which also increases coverage. Also ensure +# the soft float routines are checked. +$cmd --profile release-checked +$cmd --profile release-checked --features force-soft-floats +$cmd --profile release-checked --features unstable-intrinsics +$cmd --profile release-checked --features unstable-intrinsics --benches +# Ensure that the routines do not panic. +ENSURE_NO_PANIC=1 cargo build -p libm --target "$target" --no-default-features --release -- cgit 1.4.1-3-g733a5 From bfbe919adfae9ce1b0dc17260db2dba097c3c37c Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Tue, 14 Jan 2025 03:55:26 +0200 Subject: Simplify and optimize `fdim` (#442) The cases with NaN arguments can be handled by the same x - y expression, and this generates much better code: https://godbolt.org/z/f3rnT8jx4. --- library/compiler-builtins/libm/src/math/generic/fdim.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/fdim.rs b/library/compiler-builtins/libm/src/math/generic/fdim.rs index 2e54a41deea..bf971cd7d18 100644 --- a/library/compiler-builtins/libm/src/math/generic/fdim.rs +++ b/library/compiler-builtins/libm/src/math/generic/fdim.rs @@ -1,13 +1,5 @@ use super::super::Float; pub fn fdim(x: F, y: F) -> F { - if x.is_nan() { - x - } else if y.is_nan() { - y - } else if x > y { - x - y - } else { - F::ZERO - } + if x <= y { F::ZERO } else { x - y } } -- cgit 1.4.1-3-g733a5 From 26df5d6689635a1f78573c66baa802a0abc6ec8d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 23:40:42 +0000 Subject: Use cargo-nextest for running tests in CI The test suite for this repo has quite a lot of tests, and it is difficult to tell which contribute the most to the long CI runtime. libtest does have an unstable flag to report test times, but that is inconvenient to use because it needs to be passed only to libtest binaries. Switch to cargo-nextest [1] which provides time reporting and, overall, a better test UI. It may also improve test runtime, though this seems unlikely since we have larger test binaries with many small tests (nextest benefits the most when there are larger binaries that can be run in parallel). For anyone running locally without, `run.sh` should still fall back to `cargo test` if `cargo-nextest` is not available. This diff includes some cleanup and consistency changes to other CI-related files. [1]: https://nexte.st --- .../libm/.github/workflows/main.yml | 2 + .../libm/.github/workflows/publish.yml | 2 +- library/compiler-builtins/libm/ci/download-musl.sh | 2 +- library/compiler-builtins/libm/ci/run-docker.sh | 8 +-- library/compiler-builtins/libm/ci/run.sh | 58 +++++++++++++++------- 5 files changed, 48 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 35b307f7711..30976d47262 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -6,6 +6,7 @@ on: pull_request: env: + CARGO_TERM_COLOR: always CARGO_TERM_VERBOSE: true RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings @@ -88,6 +89,7 @@ jobs: rustup default "$channel" rustup target add "${{ matrix.target }}" rustup component add clippy llvm-tools-preview + - uses: taiki-e/install-action@nextest - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} diff --git a/library/compiler-builtins/libm/.github/workflows/publish.yml b/library/compiler-builtins/libm/.github/workflows/publish.yml index e715c61871f..15904079d27 100644 --- a/library/compiler-builtins/libm/.github/workflows/publish.yml +++ b/library/compiler-builtins/libm/.github/workflows/publish.yml @@ -12,7 +12,7 @@ on: jobs: release-plz: name: Release-plz - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/library/compiler-builtins/libm/ci/download-musl.sh b/library/compiler-builtins/libm/ci/download-musl.sh index d0d8b310e87..039e961575b 100755 --- a/library/compiler-builtins/libm/ci/download-musl.sh +++ b/library/compiler-builtins/libm/ci/download-musl.sh @@ -7,7 +7,7 @@ fname=musl-1.2.5.tar.gz sha=a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4 mkdir musl -curl "https://musl.libc.org/releases/$fname" -O +curl -L "https://musl.libc.org/releases/$fname" -O case "$(uname -s)" in MINGW*) diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index d9f29656d71..6626e722685 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -24,12 +24,14 @@ run() { # will be owned by root mkdir -p target - docker build -t "$target" "ci/docker/$target" + set_env="HOME=/tmp PATH=\$PATH:/rust/bin:/cargo/bin" + docker build -t "libm-$target" "ci/docker/$target" docker run \ --rm \ --user "$(id -u):$(id -g)" \ -e CI \ -e RUSTFLAGS \ + -e CARGO_TERM_COLOR \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ -e "EMULATED=$emulated" \ @@ -39,8 +41,8 @@ run() { -v "$(rustc --print sysroot):/rust:ro" \ --init \ -w /checkout \ - "$target" \ - sh -c "HOME=/tmp PATH=\$PATH:/rust/bin exec ci/run.sh $target" + "libm-$target" \ + sh -c "$set_env exec ci/run.sh $target" } if [ -z "$1" ]; then diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 008f32d5b8c..08ffaa81c6e 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -3,8 +3,10 @@ set -eux export RUST_BACKTRACE="${RUST_BACKTRACE:-full}" +export NEXTEST_STATUS_LEVEL=all target="${1:-}" +flags="" if [ -z "$target" ]; then host_target=$(rustc -vV | awk '/^host/ { print $2 }') @@ -13,22 +15,22 @@ if [ -z "$target" ]; then fi # We enumerate features manually. -extra_flags="--no-default-features" +flags="$flags --no-default-features" # Enable arch-specific routines when available. -extra_flags="$extra_flags --features arch" +flags="$flags --features arch" # Always enable `unstable-float` since it expands available API but does not # change any implementations. -extra_flags="$extra_flags --features unstable-float" +flags="$flags --features unstable-float" # We need to specifically skip tests for musl-math-sys on systems that can't # build musl since otherwise `--all` will activate it. case "$target" in # Can't build at all on MSVC, WASM, or thumb - *windows-msvc*) extra_flags="$extra_flags --exclude musl-math-sys" ;; - *wasm*) extra_flags="$extra_flags --exclude musl-math-sys" ;; - *thumb*) extra_flags="$extra_flags --exclude musl-math-sys" ;; + *windows-msvc*) flags="$flags --exclude musl-math-sys" ;; + *wasm*) flags="$flags --exclude musl-math-sys" ;; + *thumb*) flags="$flags --exclude musl-math-sys" ;; # We can build musl on MinGW but running tests gets a stack overflow *windows-gnu*) ;; @@ -38,7 +40,7 @@ case "$target" in *powerpc64le*) ;; # Everything else gets musl enabled - *) extra_flags="$extra_flags --features libm-test/build-musl" ;; + *) flags="$flags --features libm-test/build-musl" ;; esac # Configure which targets test against MPFR @@ -50,17 +52,17 @@ case "$target" in # Targets that aren't cross compiled work fine # FIXME(ci): we should be able to enable aarch64 Linux here once GHA # support rolls out. - x86_64*) extra_flags="$extra_flags --features libm-test/build-mpfr" ;; - i686*) extra_flags="$extra_flags --features libm-test/build-mpfr" ;; - i586*) extra_flags="$extra_flags --features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross" ;; + x86_64*) flags="$flags --features libm-test/build-mpfr" ;; + i686*) flags="$flags --features libm-test/build-mpfr" ;; + i586*) flags="$flags --features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross" ;; # Apple aarch64 is native - aarch64*apple*) extra_flags="$extra_flags --features libm-test/build-mpfr" ;; + aarch64*apple*) flags="$flags --features libm-test/build-mpfr" ;; esac # FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. # case "$target" in - *windows-gnu) extra_flags="$extra_flags --exclude libm-macros" ;; + *windows-gnu) flags="$flags --exclude libm-macros" ;; esac # Make sure we can build with overriding features. @@ -76,13 +78,31 @@ if [ "${BUILD_ONLY:-}" = "1" ]; then exit fi -# Otherwise, run the test suite. - -cmd="cargo test --all --target $target $extra_flags" +flags="$flags --all --target $target" +cmd="cargo test $flags" +profile="--profile" + +# If nextest is available, use that +command -v cargo-nextest && nextest=1 || nextest=0 +if [ "$nextest" = "1" ]; then + # Workaround for https://github.com/nextest-rs/nextest/issues/2066 + if [ -f /.dockerenv ]; then + cfg_file="/tmp/nextest-config.toml" + echo "[store]" >> "$cfg_file" + echo "dir = \"$CARGO_TARGET_DIR/nextest\"" >> "$cfg_file" + cfg_flag="--config-file $cfg_file" + fi + + cmd="cargo nextest run ${cfg_flag:-} $flags" + profile="--cargo-profile" +fi # Test once without intrinsics $cmd +# Run doctests if they were excluded by nextest +[ "$nextest" = "1" ] && cargo test --doc $flags + # Exclude the macros and utile crates from the rest of the tests to save CI # runtime, they shouldn't have anything feature- or opt-level-dependent. cmd="$cmd --exclude util --exclude libm-macros" @@ -93,10 +113,10 @@ $cmd --features unstable-intrinsics --benches # Test the same in release mode, which also increases coverage. Also ensure # the soft float routines are checked. -$cmd --profile release-checked -$cmd --profile release-checked --features force-soft-floats -$cmd --profile release-checked --features unstable-intrinsics -$cmd --profile release-checked --features unstable-intrinsics --benches +$cmd "$profile" release-checked +$cmd "$profile" release-checked --features force-soft-floats +$cmd "$profile" release-checked --features unstable-intrinsics +$cmd "$profile" release-checked --features unstable-intrinsics --benches # Ensure that the routines do not panic. ENSURE_NO_PANIC=1 cargo build -p libm --target "$target" --no-default-features --release -- cgit 1.4.1-3-g733a5 From 5e65179a3912f3b293fd39b05bf8903428a86346 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 14 Jan 2025 03:24:14 +0000 Subject: Change `.yml` files to the canonical extension `.yaml` --- .../libm/.github/workflows/main.yaml | 266 +++++++++++++++++++++ .../libm/.github/workflows/main.yml | 266 --------------------- .../libm/.github/workflows/publish.yaml | 27 +++ .../libm/.github/workflows/publish.yml | 27 --- 4 files changed, 293 insertions(+), 293 deletions(-) create mode 100644 library/compiler-builtins/libm/.github/workflows/main.yaml delete mode 100644 library/compiler-builtins/libm/.github/workflows/main.yml create mode 100644 library/compiler-builtins/libm/.github/workflows/publish.yaml delete mode 100644 library/compiler-builtins/libm/.github/workflows/publish.yml diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml new file mode 100644 index 00000000000..30976d47262 --- /dev/null +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -0,0 +1,266 @@ +name: CI +on: + push: + branches: + - master + pull_request: + +env: + CARGO_TERM_COLOR: always + CARGO_TERM_VERBOSE: true + RUSTDOCFLAGS: -Dwarnings + RUSTFLAGS: -Dwarnings + RUST_BACKTRACE: full + +jobs: + test: + name: Build and test + timeout-minutes: 25 + strategy: + fail-fast: false + matrix: + include: + - target: aarch64-apple-darwin + os: macos-15 + - target: aarch64-unknown-linux-gnu + os: ubuntu-24.04 + - target: aarch64-pc-windows-msvc + os: windows-2025 + build_only: 1 # Can't run on x86 hosts + - target: arm-unknown-linux-gnueabi + os: ubuntu-24.04 + - target: arm-unknown-linux-gnueabihf + os: ubuntu-24.04 + - target: armv7-unknown-linux-gnueabihf + os: ubuntu-24.04 + - target: i586-unknown-linux-gnu + os: ubuntu-24.04 + - target: i686-unknown-linux-gnu + os: ubuntu-24.04 + - target: loongarch64-unknown-linux-gnu + os: ubuntu-24.04 + - target: powerpc-unknown-linux-gnu + os: ubuntu-24.04 + - target: powerpc64-unknown-linux-gnu + os: ubuntu-24.04 + - target: powerpc64le-unknown-linux-gnu + os: ubuntu-24.04 + - target: riscv64gc-unknown-linux-gnu + os: ubuntu-24.04 + - target: thumbv6m-none-eabi + os: ubuntu-24.04 + - target: thumbv7em-none-eabi + os: ubuntu-24.04 + - target: thumbv7em-none-eabihf + os: ubuntu-24.04 + - target: thumbv7m-none-eabi + os: ubuntu-24.04 + - target: x86_64-unknown-linux-gnu + os: ubuntu-24.04 + - target: x86_64-apple-darwin + os: macos-13 + - target: wasm32-unknown-unknown + os: ubuntu-24.04 + build_only: 1 + - target: i686-pc-windows-msvc + os: windows-2025 + - target: x86_64-pc-windows-msvc + os: windows-2025 + - target: i686-pc-windows-gnu + os: windows-2025 + channel: nightly-i686-gnu + - target: x86_64-pc-windows-gnu + os: windows-2025 + channel: nightly-x86_64-gnu + runs-on: ${{ matrix.os }} + env: + BUILD_ONLY: ${{ matrix.build_only }} + steps: + - name: Print runner information + run: uname -a + - uses: actions/checkout@v4 + - name: Install Rust (rustup) + shell: bash + run: | + channel="nightly" + # Account for channels that have required components (MinGW) + [ -n "${{ matrix.channel }}" ] && channel="${{ matrix.channel }}" + rustup update "$channel" --no-self-update + rustup default "$channel" + rustup target add "${{ matrix.target }}" + rustup component add clippy llvm-tools-preview + - uses: taiki-e/install-action@nextest + - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} + + - name: Download musl source + run: ./ci/download-musl.sh + shell: bash + + - name: Verify API list + if: matrix.os == 'ubuntu-24.04' + run: python3 etc/update-api-list.py --check + + # Non-linux tests just use our raw script + - name: Run locally + if: matrix.os != 'ubuntu-24.04' || contains(matrix.target, 'wasm') + shell: bash + run: ./ci/run.sh ${{ matrix.target }} + + # Otherwise we use our docker containers to run builds + - name: Run in Docker + if: matrix.os == 'ubuntu-24.04' && !contains(matrix.target, 'wasm') + run: | + rustup target add x86_64-unknown-linux-musl + cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} + + - name: Print test logs if available + if: always() + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + + clippy: + name: Clippy + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@master + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + rustup component add clippy + - uses: Swatinem/rust-cache@v2 + - name: Download musl source + run: ./ci/download-musl.sh + - run: cargo clippy --all --all-features --all-targets + + builtins: + name: Check use with compiler-builtins + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update nightly --no-self-update && rustup default nightly + - uses: Swatinem/rust-cache@v2 + - run: cargo test --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml + + benchmarks: + name: Benchmarks + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update nightly --no-self-update && rustup default nightly + - uses: Swatinem/rust-cache@v2 + - name: Download musl source + run: ./ci/download-musl.sh + - run: | + # Always use the same seed for benchmarks. Ideally we should switch to a + # non-random generator. + export LIBM_SEED=benchesbenchesbenchesbencheswoo! + cargo bench --all --features libm-test/short-benchmarks,libm-test/build-musl + + msrv: + name: Check MSRV + runs-on: ubuntu-24.04 + env: + RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` + steps: + - uses: actions/checkout@master + - run: | + msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' Cargo.toml)" + echo "MSRV: $msrv" + echo "MSRV=$msrv" >> "$GITHUB_ENV" + - name: Install Rust + run: rustup update "$MSRV" --no-self-update && rustup default "$MSRV" + - uses: Swatinem/rust-cache@v2 + - run: cargo build -p libm + + rustfmt: + name: Rustfmt + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@master + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + rustup component add rustfmt + - run: cargo fmt -- --check + + # Determine which extensive tests should be run based on changed files. + calculate_extensive_matrix: + name: Calculate job matrix + runs-on: ubuntu-24.04 + outputs: + matrix: ${{ steps.script.outputs.matrix }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 100 + - name: Fetch pull request ref + run: git fetch origin "$GITHUB_REF:$GITHUB_REF" + if: github.event_name == 'pull_request' + - run: python3 ci/calculate-exhaustive-matrix.py >> "$GITHUB_OUTPUT" + id: script + + extensive: + name: Extensive tests for ${{ matrix.ty }} + needs: + # Wait on `clippy` so we have some confidence that the crate will build + - clippy + - calculate_extensive_matrix + runs-on: ubuntu-24.04 + timeout-minutes: 80 + strategy: + matrix: + # Use the output from `calculate_extensive_matrix` to calculate the matrix + # FIXME: it would be better to run all jobs (i.e. all types) but mark those that + # didn't change as skipped, rather than completely excluding the job. However, + # this is not currently possible https://github.com/actions/runner/issues/1985. + include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }} + env: + CHANGED: ${{ matrix.changed }} + steps: + - uses: actions/checkout@v4 + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + - uses: Swatinem/rust-cache@v2 + - name: Download musl source + run: ./ci/download-musl.sh + - name: Run extensive tests + run: | + echo "Changed: '$CHANGED'" + if [ -z "$CHANGED" ]; then + echo "No tests to run, exiting." + exit + fi + + LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \ + --features build-mpfr,unstable \ + --profile release-checked \ + -- extensive + - name: Print test logs if available + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + + success: + needs: + - test + - builtins + - benchmarks + - msrv + - rustfmt + - extensive + runs-on: ubuntu-24.04 + # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency + # failed" as success. So we have to do some contortions to ensure the job fails if any of its + # dependencies fails. + if: always() # make sure this is never "skipped" + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: check if any dependency failed + run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml deleted file mode 100644 index 30976d47262..00000000000 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ /dev/null @@ -1,266 +0,0 @@ -name: CI -on: - push: - branches: - - master - pull_request: - -env: - CARGO_TERM_COLOR: always - CARGO_TERM_VERBOSE: true - RUSTDOCFLAGS: -Dwarnings - RUSTFLAGS: -Dwarnings - RUST_BACKTRACE: full - -jobs: - test: - name: Build and test - timeout-minutes: 25 - strategy: - fail-fast: false - matrix: - include: - - target: aarch64-apple-darwin - os: macos-15 - - target: aarch64-unknown-linux-gnu - os: ubuntu-24.04 - - target: aarch64-pc-windows-msvc - os: windows-2025 - build_only: 1 # Can't run on x86 hosts - - target: arm-unknown-linux-gnueabi - os: ubuntu-24.04 - - target: arm-unknown-linux-gnueabihf - os: ubuntu-24.04 - - target: armv7-unknown-linux-gnueabihf - os: ubuntu-24.04 - - target: i586-unknown-linux-gnu - os: ubuntu-24.04 - - target: i686-unknown-linux-gnu - os: ubuntu-24.04 - - target: loongarch64-unknown-linux-gnu - os: ubuntu-24.04 - - target: powerpc-unknown-linux-gnu - os: ubuntu-24.04 - - target: powerpc64-unknown-linux-gnu - os: ubuntu-24.04 - - target: powerpc64le-unknown-linux-gnu - os: ubuntu-24.04 - - target: riscv64gc-unknown-linux-gnu - os: ubuntu-24.04 - - target: thumbv6m-none-eabi - os: ubuntu-24.04 - - target: thumbv7em-none-eabi - os: ubuntu-24.04 - - target: thumbv7em-none-eabihf - os: ubuntu-24.04 - - target: thumbv7m-none-eabi - os: ubuntu-24.04 - - target: x86_64-unknown-linux-gnu - os: ubuntu-24.04 - - target: x86_64-apple-darwin - os: macos-13 - - target: wasm32-unknown-unknown - os: ubuntu-24.04 - build_only: 1 - - target: i686-pc-windows-msvc - os: windows-2025 - - target: x86_64-pc-windows-msvc - os: windows-2025 - - target: i686-pc-windows-gnu - os: windows-2025 - channel: nightly-i686-gnu - - target: x86_64-pc-windows-gnu - os: windows-2025 - channel: nightly-x86_64-gnu - runs-on: ${{ matrix.os }} - env: - BUILD_ONLY: ${{ matrix.build_only }} - steps: - - name: Print runner information - run: uname -a - - uses: actions/checkout@v4 - - name: Install Rust (rustup) - shell: bash - run: | - channel="nightly" - # Account for channels that have required components (MinGW) - [ -n "${{ matrix.channel }}" ] && channel="${{ matrix.channel }}" - rustup update "$channel" --no-self-update - rustup default "$channel" - rustup target add "${{ matrix.target }}" - rustup component add clippy llvm-tools-preview - - uses: taiki-e/install-action@nextest - - uses: Swatinem/rust-cache@v2 - with: - key: ${{ matrix.target }} - - - name: Download musl source - run: ./ci/download-musl.sh - shell: bash - - - name: Verify API list - if: matrix.os == 'ubuntu-24.04' - run: python3 etc/update-api-list.py --check - - # Non-linux tests just use our raw script - - name: Run locally - if: matrix.os != 'ubuntu-24.04' || contains(matrix.target, 'wasm') - shell: bash - run: ./ci/run.sh ${{ matrix.target }} - - # Otherwise we use our docker containers to run builds - - name: Run in Docker - if: matrix.os == 'ubuntu-24.04' && !contains(matrix.target, 'wasm') - run: | - rustup target add x86_64-unknown-linux-musl - cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} - - - name: Print test logs if available - if: always() - run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi - shell: bash - - clippy: - name: Clippy - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@master - - name: Install Rust - run: | - rustup update nightly --no-self-update - rustup default nightly - rustup component add clippy - - uses: Swatinem/rust-cache@v2 - - name: Download musl source - run: ./ci/download-musl.sh - - run: cargo clippy --all --all-features --all-targets - - builtins: - name: Check use with compiler-builtins - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@master - - name: Install Rust - run: rustup update nightly --no-self-update && rustup default nightly - - uses: Swatinem/rust-cache@v2 - - run: cargo test --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml - - benchmarks: - name: Benchmarks - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@master - - name: Install Rust - run: rustup update nightly --no-self-update && rustup default nightly - - uses: Swatinem/rust-cache@v2 - - name: Download musl source - run: ./ci/download-musl.sh - - run: | - # Always use the same seed for benchmarks. Ideally we should switch to a - # non-random generator. - export LIBM_SEED=benchesbenchesbenchesbencheswoo! - cargo bench --all --features libm-test/short-benchmarks,libm-test/build-musl - - msrv: - name: Check MSRV - runs-on: ubuntu-24.04 - env: - RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` - steps: - - uses: actions/checkout@master - - run: | - msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' Cargo.toml)" - echo "MSRV: $msrv" - echo "MSRV=$msrv" >> "$GITHUB_ENV" - - name: Install Rust - run: rustup update "$MSRV" --no-self-update && rustup default "$MSRV" - - uses: Swatinem/rust-cache@v2 - - run: cargo build -p libm - - rustfmt: - name: Rustfmt - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@master - - name: Install Rust - run: | - rustup update nightly --no-self-update - rustup default nightly - rustup component add rustfmt - - run: cargo fmt -- --check - - # Determine which extensive tests should be run based on changed files. - calculate_extensive_matrix: - name: Calculate job matrix - runs-on: ubuntu-24.04 - outputs: - matrix: ${{ steps.script.outputs.matrix }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 100 - - name: Fetch pull request ref - run: git fetch origin "$GITHUB_REF:$GITHUB_REF" - if: github.event_name == 'pull_request' - - run: python3 ci/calculate-exhaustive-matrix.py >> "$GITHUB_OUTPUT" - id: script - - extensive: - name: Extensive tests for ${{ matrix.ty }} - needs: - # Wait on `clippy` so we have some confidence that the crate will build - - clippy - - calculate_extensive_matrix - runs-on: ubuntu-24.04 - timeout-minutes: 80 - strategy: - matrix: - # Use the output from `calculate_extensive_matrix` to calculate the matrix - # FIXME: it would be better to run all jobs (i.e. all types) but mark those that - # didn't change as skipped, rather than completely excluding the job. However, - # this is not currently possible https://github.com/actions/runner/issues/1985. - include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }} - env: - CHANGED: ${{ matrix.changed }} - steps: - - uses: actions/checkout@v4 - - name: Install Rust - run: | - rustup update nightly --no-self-update - rustup default nightly - - uses: Swatinem/rust-cache@v2 - - name: Download musl source - run: ./ci/download-musl.sh - - name: Run extensive tests - run: | - echo "Changed: '$CHANGED'" - if [ -z "$CHANGED" ]; then - echo "No tests to run, exiting." - exit - fi - - LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \ - --features build-mpfr,unstable \ - --profile release-checked \ - -- extensive - - name: Print test logs if available - run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi - shell: bash - - success: - needs: - - test - - builtins - - benchmarks - - msrv - - rustfmt - - extensive - runs-on: ubuntu-24.04 - # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency - # failed" as success. So we have to do some contortions to ensure the job fails if any of its - # dependencies fails. - if: always() # make sure this is never "skipped" - steps: - # Manually check the status of all dependencies. `if: failure()` does not work. - - name: check if any dependency failed - run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/library/compiler-builtins/libm/.github/workflows/publish.yaml b/library/compiler-builtins/libm/.github/workflows/publish.yaml new file mode 100644 index 00000000000..15904079d27 --- /dev/null +++ b/library/compiler-builtins/libm/.github/workflows/publish.yaml @@ -0,0 +1,27 @@ +name: Release-plz + +permissions: + pull-requests: write + contents: write + +on: + push: + branches: + - master + +jobs: + release-plz: + name: Release-plz + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install Rust (rustup) + run: rustup update nightly --no-self-update && rustup default nightly + - name: Run release-plz + uses: MarcoIeni/release-plz-action@v0.5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/library/compiler-builtins/libm/.github/workflows/publish.yml b/library/compiler-builtins/libm/.github/workflows/publish.yml deleted file mode 100644 index 15904079d27..00000000000 --- a/library/compiler-builtins/libm/.github/workflows/publish.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Release-plz - -permissions: - pull-requests: write - contents: write - -on: - push: - branches: - - master - -jobs: - release-plz: - name: Release-plz - runs-on: ubuntu-24.04 - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Install Rust (rustup) - run: rustup update nightly --no-self-update && rustup default nightly - - name: Run release-plz - uses: MarcoIeni/release-plz-action@v0.5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} -- cgit 1.4.1-3-g733a5 From f63ef37218c7def3efeb7a434fcfd0a2b87dcaec Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 14 Jan 2025 07:46:20 +0000 Subject: Slightly restructure `ci/calculate-exhaustive-matrix.py` Change this script into a generic CI utility that we will be able to expand in the future. --- .../libm/.github/workflows/main.yaml | 3 +- .../libm/ci/calculate-exhaustive-matrix.py | 148 ------------------ library/compiler-builtins/libm/ci/ci-util.py | 168 +++++++++++++++++++++ 3 files changed, 169 insertions(+), 150 deletions(-) delete mode 100755 library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py create mode 100755 library/compiler-builtins/libm/ci/ci-util.py diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 30976d47262..40b67c4c251 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -7,7 +7,6 @@ on: env: CARGO_TERM_COLOR: always - CARGO_TERM_VERBOSE: true RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings RUST_BACKTRACE: full @@ -202,7 +201,7 @@ jobs: - name: Fetch pull request ref run: git fetch origin "$GITHUB_REF:$GITHUB_REF" if: github.event_name == 'pull_request' - - run: python3 ci/calculate-exhaustive-matrix.py >> "$GITHUB_OUTPUT" + - run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT" id: script extensive: diff --git a/library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py b/library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py deleted file mode 100755 index 8b42f9389f9..00000000000 --- a/library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env python3 -"""Calculate which exhaustive tests should be run as part of CI. - -This dynamically prepares a list of routines that had a source file change based on -git history. -""" - -import subprocess as sp -import sys -import json -from dataclasses import dataclass -from os import getenv -from pathlib import Path -from typing import TypedDict - - -REPO_ROOT = Path(__file__).parent.parent -GIT = ["git", "-C", REPO_ROOT] - -# Don't run exhaustive tests if these files change, even if they contaiin a function -# definition. -IGNORE_FILES = [ - "src/math/support/", - "src/libm_helper.rs", - "src/math/arch/intrinsics.rs", -] - -TYPES = ["f16", "f32", "f64", "f128"] - - -class FunctionDef(TypedDict): - """Type for an entry in `function-definitions.json`""" - - sources: list[str] - type: str - - -@dataclass -class Context: - gh_ref: str | None - changed: list[Path] - defs: dict[str, FunctionDef] - - def __init__(self) -> None: - self.gh_ref = getenv("GITHUB_REF") - self.changed = [] - self._init_change_list() - - with open(REPO_ROOT.joinpath("etc/function-definitions.json")) as f: - defs = json.load(f) - - defs.pop("__comment", None) - self.defs = defs - - def _init_change_list(self): - """Create a list of files that have been changed. This uses GITHUB_REF if - available, otherwise a diff between `HEAD` and `master`. - """ - - # For pull requests, GitHub creates a ref `refs/pull/1234/merge` (1234 being - # the PR number), and sets this as `GITHUB_REF`. - ref = self.gh_ref - eprint(f"using ref `{ref}`") - if ref is None or "merge" not in ref: - # If the ref is not for `merge` then we are not in PR CI - eprint("No diff available for ref") - return - - # The ref is for a dummy merge commit. We can extract the merge base by - # inspecting all parents (`^@`). - merge_sha = sp.check_output( - GIT + ["show-ref", "--hash", ref], text=True - ).strip() - merge_log = sp.check_output(GIT + ["log", "-1", merge_sha], text=True) - eprint(f"Merge:\n{merge_log}\n") - - parents = ( - sp.check_output(GIT + ["rev-parse", f"{merge_sha}^@"], text=True) - .strip() - .splitlines() - ) - assert len(parents) == 2, f"expected two-parent merge but got:\n{parents}" - base = parents[0].strip() - incoming = parents[1].strip() - - eprint(f"base: {base}, incoming: {incoming}") - textlist = sp.check_output( - GIT + ["diff", base, incoming, "--name-only"], text=True - ) - self.changed = [Path(p) for p in textlist.splitlines()] - - @staticmethod - def _ignore_file(fname: str) -> bool: - return any(fname.startswith(pfx) for pfx in IGNORE_FILES) - - def changed_routines(self) -> dict[str, list[str]]: - """Create a list of routines for which one or more files have been updated, - separated by type. - """ - routines = set() - for name, meta in self.defs.items(): - # Don't update if changes to the file should be ignored - sources = (f for f in meta["sources"] if not self._ignore_file(f)) - - # Select changed files - changed = [f for f in sources if Path(f) in self.changed] - - if len(changed) > 0: - eprint(f"changed files for {name}: {changed}") - routines.add(name) - - ret = {} - for r in sorted(routines): - ret.setdefault(self.defs[r]["type"], []).append(r) - - return ret - - def make_workflow_output(self) -> str: - """Create a JSON object a list items for each type's changed files, if any - did change, and the routines that were affected by the change. - """ - changed = self.changed_routines() - ret = [] - for ty in TYPES: - ty_changed = changed.get(ty, []) - item = { - "ty": ty, - "changed": ",".join(ty_changed), - } - ret.append(item) - output = json.dumps({"matrix": ret}, separators=(",", ":")) - eprint(f"output: {output}") - return output - - -def eprint(*args, **kwargs): - """Print to stderr.""" - print(*args, file=sys.stderr, **kwargs) - - -def main(): - ctx = Context() - output = ctx.make_workflow_output() - print(f"matrix={output}") - - -if __name__ == "__main__": - main() diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py new file mode 100755 index 00000000000..733ec26fa33 --- /dev/null +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +"""Utilities for CI. + +This dynamically prepares a list of routines that had a source file change based on +git history. +""" + +import json +import subprocess as sp +import sys +from dataclasses import dataclass +from inspect import cleandoc +from os import getenv +from pathlib import Path +from typing import TypedDict + +USAGE = cleandoc( + """ + usage: + + ./ci/ci-util.py + + SUBCOMMAND: + generate-matrix Calculate a matrix of which functions had source change, + print that as JSON object. + """ +) + +REPO_ROOT = Path(__file__).parent.parent +GIT = ["git", "-C", REPO_ROOT] + +# Don't run exhaustive tests if these files change, even if they contaiin a function +# definition. +IGNORE_FILES = [ + "src/math/support/", + "src/libm_helper.rs", + "src/math/arch/intrinsics.rs", +] + +TYPES = ["f16", "f32", "f64", "f128"] + + +class FunctionDef(TypedDict): + """Type for an entry in `function-definitions.json`""" + + sources: list[str] + type: str + + +@dataclass +class Context: + gh_ref: str | None + changed: list[Path] + defs: dict[str, FunctionDef] + + def __init__(self) -> None: + self.gh_ref = getenv("GITHUB_REF") + self.changed = [] + self._init_change_list() + + with open(REPO_ROOT.joinpath("etc/function-definitions.json")) as f: + defs = json.load(f) + + defs.pop("__comment", None) + self.defs = defs + + def _init_change_list(self): + """Create a list of files that have been changed. This uses GITHUB_REF if + available, otherwise a diff between `HEAD` and `master`. + """ + + # For pull requests, GitHub creates a ref `refs/pull/1234/merge` (1234 being + # the PR number), and sets this as `GITHUB_REF`. + ref = self.gh_ref + eprint(f"using ref `{ref}`") + if ref is None or "merge" not in ref: + # If the ref is not for `merge` then we are not in PR CI + eprint("No diff available for ref") + return + + # The ref is for a dummy merge commit. We can extract the merge base by + # inspecting all parents (`^@`). + merge_sha = sp.check_output( + GIT + ["show-ref", "--hash", ref], text=True + ).strip() + merge_log = sp.check_output(GIT + ["log", "-1", merge_sha], text=True) + eprint(f"Merge:\n{merge_log}\n") + + parents = ( + sp.check_output(GIT + ["rev-parse", f"{merge_sha}^@"], text=True) + .strip() + .splitlines() + ) + assert len(parents) == 2, f"expected two-parent merge but got:\n{parents}" + base = parents[0].strip() + incoming = parents[1].strip() + + eprint(f"base: {base}, incoming: {incoming}") + textlist = sp.check_output( + GIT + ["diff", base, incoming, "--name-only"], text=True + ) + self.changed = [Path(p) for p in textlist.splitlines()] + + @staticmethod + def _ignore_file(fname: str) -> bool: + return any(fname.startswith(pfx) for pfx in IGNORE_FILES) + + def changed_routines(self) -> dict[str, list[str]]: + """Create a list of routines for which one or more files have been updated, + separated by type. + """ + routines = set() + for name, meta in self.defs.items(): + # Don't update if changes to the file should be ignored + sources = (f for f in meta["sources"] if not self._ignore_file(f)) + + # Select changed files + changed = [f for f in sources if Path(f) in self.changed] + + if len(changed) > 0: + eprint(f"changed files for {name}: {changed}") + routines.add(name) + + ret = {} + for r in sorted(routines): + ret.setdefault(self.defs[r]["type"], []).append(r) + + return ret + + def make_workflow_output(self) -> str: + """Create a JSON object a list items for each type's changed files, if any + did change, and the routines that were affected by the change. + """ + changed = self.changed_routines() + ret = [] + for ty in TYPES: + ty_changed = changed.get(ty, []) + item = { + "ty": ty, + "changed": ",".join(ty_changed), + } + ret.append(item) + output = json.dumps({"matrix": ret}, separators=(",", ":")) + eprint(f"output: {output}") + return output + + +def eprint(*args, **kwargs): + """Print to stderr.""" + print(*args, file=sys.stderr, **kwargs) + + +def main(): + match sys.argv[1:]: + case ["generate-matrix"]: + ctx = Context() + output = ctx.make_workflow_output() + print(f"matrix={output}") + case ["--help" | "-h"]: + print(USAGE) + exit() + case _: + eprint(USAGE) + exit(1) + + +if __name__ == "__main__": + main() -- cgit 1.4.1-3-g733a5 From b251f74843e654479fcea9b7954d474b05517a56 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 15 Jan 2025 00:54:55 +0000 Subject: Pass --max-fail to nextest so it doesn't fail fast --- library/compiler-builtins/libm/ci/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 08ffaa81c6e..bb749b72ad3 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -93,7 +93,7 @@ if [ "$nextest" = "1" ]; then cfg_flag="--config-file $cfg_file" fi - cmd="cargo nextest run ${cfg_flag:-} $flags" + cmd="cargo nextest run ${cfg_flag:-} --max-fail=10 $flags" profile="--cargo-profile" fi -- cgit 1.4.1-3-g733a5 From 45e3b98165090965e3ec5c24ae497444703d33c9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 15 Jan 2025 01:05:38 +0000 Subject: Add an override for a recent failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Failed on i686: ──── STDERR: libm-test::bench/random y1f/crate thread 'main' panicked at crates/libm-test/benches/random.rs:76:65: called `Result::unwrap()` on an `Err` value: ynf Caused by: 0: input: (213, 109.15641) (0x000000d5, 0x42da5015) expected: -3.3049217e38 0xff78a27a actual: -inf 0xff800000 1: mismatched infinities --- library/compiler-builtins/libm/crates/libm-test/src/precision.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 15913fe6d75..0b3fe89befd 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -454,6 +454,13 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { XFAIL } + // `ynf(213, 109.15641) = -inf` with our library, should be finite. + (_, BaseName::Yn) + if input.0 > 200 && !expected.is_infinite() && actual.is_infinite() => + { + XFAIL + } + _ => None, } } -- cgit 1.4.1-3-g733a5 From 7a87cdbae5e97ccd4fa24b729ac5cfb9d8daf58b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 15 Dec 2024 09:11:37 +0000 Subject: Use a C-safe return type for `__rust_[ui]128_*` overflowing intrinsics Most of our Rust-specific overflowing intrinsics currently return `(i128, bool)`, which is not guaranteed to have a stable ABI. Switch to returning the overflow via a mutable parameter and only directly returning the integer result. `__rust_i128_mulo` now matches the function signature of `__muloti4`, but they do not share the same ABI on Windows so we cannot easily deduplicate them. --- library/compiler-builtins/src/int/addsub.rs | 24 ++++++++++++++-------- library/compiler-builtins/src/int/mul.rs | 12 +++++++---- .../compiler-builtins/testcrate/tests/addsub.rs | 18 ++++++++-------- library/compiler-builtins/testcrate/tests/mul.rs | 9 ++++---- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs index e95590d84dc..1f84e8eb1e1 100644 --- a/library/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/src/int/addsub.rs @@ -66,31 +66,39 @@ intrinsics! { AddSub::add(a,b) } - pub extern "C" fn __rust_i128_addo(a: i128, b: i128) -> (i128, bool) { - a.addo(b) + pub extern "C" fn __rust_i128_addo(a: i128, b: i128, oflow: &mut i32) -> i128 { + let (add, o) = a.addo(b); + *oflow = o.into(); + add } pub extern "C" fn __rust_u128_add(a: u128, b: u128) -> u128 { AddSub::add(a,b) } - pub extern "C" fn __rust_u128_addo(a: u128, b: u128) -> (u128, bool) { - a.addo(b) + pub extern "C" fn __rust_u128_addo(a: u128, b: u128, oflow: &mut i32) -> u128 { + let (add, o) = a.addo(b); + *oflow = o.into(); + add } pub extern "C" fn __rust_i128_sub(a: i128, b: i128) -> i128 { AddSub::sub(a,b) } - pub extern "C" fn __rust_i128_subo(a: i128, b: i128) -> (i128, bool) { - a.subo(b) + pub extern "C" fn __rust_i128_subo(a: i128, b: i128, oflow: &mut i32) -> i128 { + let (sub, o) = a.subo(b); + *oflow = o.into(); + sub } pub extern "C" fn __rust_u128_sub(a: u128, b: u128) -> u128 { AddSub::sub(a,b) } - pub extern "C" fn __rust_u128_subo(a: u128, b: u128) -> (u128, bool) { - a.subo(b) + pub extern "C" fn __rust_u128_subo(a: u128, b: u128, oflow: &mut i32) -> u128 { + let (sub, o) = a.subo(b); + *oflow = o.into(); + sub } } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index e0093a725c2..040c69342d1 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -128,11 +128,15 @@ intrinsics! { mul } - pub extern "C" fn __rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { - i128_overflowing_mul(a, b) + pub extern "C" fn __rust_i128_mulo(a: i128, b: i128, oflow: &mut i32) -> i128 { + let (mul, o) = i128_overflowing_mul(a, b); + *oflow = o.into(); + mul } - pub extern "C" fn __rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { - a.mulo(b) + pub extern "C" fn __rust_u128_mulo(a: u128, b: u128, oflow: &mut i32) -> u128 { + let (mul, o) = a.mulo(b); + *oflow = o.into(); + mul } } diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs index 284a2bf5a11..3c0e20f77b1 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -44,20 +44,22 @@ mod int_addsub { use compiler_builtins::int::addsub::{$fn_add, $fn_sub}; fuzz_2(N, |x: $i, y: $i| { - let add0 = x.overflowing_add(y); - let sub0 = x.overflowing_sub(y); - let add1: ($i, bool) = $fn_add(x, y); - let sub1: ($i, bool) = $fn_sub(x, y); - if add0.0 != add1.0 || add0.1 != add1.1 { + let (add0, add_o0)= x.overflowing_add(y); + let (sub0, sub_o0)= x.overflowing_sub(y); + let mut add_o1 = 0; + let mut sub_o1 = 0; + let add1: $i = $fn_add(x, y, &mut add_o1); + let sub1: $i = $fn_sub(x, y, &mut sub_o1); + if add0 != add1 || i32::from(add_o0) != add_o1 { panic!( "{}({}, {}): std: {:?}, builtins: {:?}", - stringify!($fn_add), x, y, add0, add1 + stringify!($fn_add), x, y, (add0, add_o0) , (add1, add_o1) ); } - if sub0.0 != sub1.0 || sub0.1 != sub1.1 { + if sub0 != sub1 || i32::from(sub_o0) != sub_o1 { panic!( "{}({}, {}): std: {:?}, builtins: {:?}", - stringify!($fn_sub), x, y, sub0, sub1 + stringify!($fn_sub), x, y, (sub0, sub_o0) , (sub1, sub_o1) ); } }); diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 449d194804a..2113b177db4 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -73,9 +73,10 @@ mod int_overflowing_mul { use compiler_builtins::int::mul::{__rust_i128_mulo, __rust_u128_mulo}; fuzz_2(N, |x: u128, y: u128| { + let mut o1 = 0; let (mul0, o0) = x.overflowing_mul(y); - let (mul1, o1) = __rust_u128_mulo(x, y); - if mul0 != mul1 || o0 != o1 { + let mul1 = __rust_u128_mulo(x, y, &mut o1); + if mul0 != mul1 || i32::from(o0) != o1 { panic!( "__rust_u128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", x, y, mul0, o0, mul1, o1 @@ -84,8 +85,8 @@ mod int_overflowing_mul { let x = x as i128; let y = y as i128; let (mul0, o0) = x.overflowing_mul(y); - let (mul1, o1) = __rust_i128_mulo(x, y); - if mul0 != mul1 || o0 != o1 { + let mul1 = __rust_i128_mulo(x, y, &mut o1); + if mul0 != mul1 || i32::from(o0) != o1 { panic!( "__rust_i128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", x, y, mul0, o0, mul1, o1 -- cgit 1.4.1-3-g733a5 From 05d429523de334a1a34666ff32ea1e74ddab66dd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Jan 2025 03:53:29 +0000 Subject: chore: release v0.1.143 --- library/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index 305f2790f33..3c21dc2d282 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.143](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.142...compiler_builtins-v0.1.143) - 2025-01-15 + +### Other + +- Use a C-safe return type for `__rust_[ui]128_*` overflowing intrinsics + ## [0.1.142](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.141...compiler_builtins-v0.1.142) - 2025-01-07 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 943adc4c1f2..4d5bbe4a902 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.142" +version = "0.1.143" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 095ecabcad55f43dcf4beb8b420ad712e0c5671f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 15 Jan 2025 05:27:14 +0000 Subject: Eliminate the use of `public_test_dep!` Replace `public_test_dep!` by placing optionally public items into new modules, then controlling what is exported with the `public-test-deps` feature. This is nicer for automatic formatting and diagnostics. This is a reland of 2e2a9255 ("Eliminate the use of `public_test_dep!`"), which was reverted in 47e50fd2 ('Revert "Eliminate the use of..."') due to a bug exposed at [1]. This was fixed in [2], so the cleanup should be able to be applied again. [1]: https://github.com/rust-lang/rust/pull/128691 [2]: https://github.com/rust-lang/rust/pull/135278 --- library/compiler-builtins/src/float/mod.rs | 195 +--------- library/compiler-builtins/src/float/traits.rs | 189 +++++++++ library/compiler-builtins/src/int/leading_zeros.rs | 227 +++++------ library/compiler-builtins/src/int/mod.rs | 424 +-------------------- .../src/int/specialized_div_rem/delegate.rs | 4 +- .../compiler-builtins/src/int/trailing_zeros.rs | 69 ++-- library/compiler-builtins/src/int/traits.rs | 411 ++++++++++++++++++++ library/compiler-builtins/src/macros.rs | 16 - 8 files changed, 763 insertions(+), 772 deletions(-) create mode 100644 library/compiler-builtins/src/float/traits.rs create mode 100644 library/compiler-builtins/src/int/traits.rs diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 6ee55950e18..41b308626b3 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,7 +1,3 @@ -use core::ops; - -use crate::int::{DInt, Int, MinInt}; - pub mod add; pub mod cmp; pub mod conv; @@ -10,192 +6,11 @@ pub mod extend; pub mod mul; pub mod pow; pub mod sub; +pub(crate) mod traits; pub mod trunc; -/// Wrapper to extract the integer type half of the float's size -pub(crate) type HalfRep = <::Int as DInt>::H; - -public_test_dep! { -/// Trait for some basic operations on floats -#[allow(dead_code)] -pub(crate) trait Float: - Copy - + core::fmt::Debug - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::MulAssign - + ops::Add - + ops::Sub - + ops::Div - + ops::Rem -{ - /// A uint of the same width as the float - type Int: Int; - - /// A int of the same width as the float - type SignedInt: Int + MinInt; - - /// An int capable of containing the exponent bits plus a sign bit. This is signed. - type ExpInt: Int; - - const ZERO: Self; - const ONE: Self; - - /// The bitwidth of the float type. - const BITS: u32; - - /// The bitwidth of the significand. - const SIG_BITS: u32; - - /// The bitwidth of the exponent. - const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; - - /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite - /// representation. - /// - /// This is in the rightmost position, use `EXP_MASK` for the shifted value. - const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; - - /// The exponent bias value. - const EXP_BIAS: u32 = Self::EXP_SAT >> 1; - - /// A mask for the sign bit. - const SIGN_MASK: Self::Int; - - /// A mask for the significand. - const SIG_MASK: Self::Int; - - /// The implicit bit of the float format. - const IMPLICIT_BIT: Self::Int; - - /// A mask for the exponent. - const EXP_MASK: Self::Int; - - /// Returns `self` transmuted to `Self::Int` - fn to_bits(self) -> Self::Int; - - /// Returns `self` transmuted to `Self::SignedInt` - fn to_bits_signed(self) -> Self::SignedInt; - - /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. This method returns `true` if two NaNs are - /// compared. - fn eq_repr(self, rhs: Self) -> bool; - - /// Returns true if the sign is negative - fn is_sign_negative(self) -> bool; - - /// Returns the exponent, not adjusting for bias. - fn exp(self) -> Self::ExpInt; - - /// Returns the significand with no implicit bit (or the "fractional" part) - fn frac(self) -> Self::Int; - - /// Returns the significand with implicit bit - fn imp_frac(self) -> Self::Int; - - /// Returns a `Self::Int` transmuted back to `Self` - fn from_bits(a: Self::Int) -> Self; - - /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self; - - fn abs(self) -> Self { - let abs_mask = !Self::SIGN_MASK ; - Self::from_bits(self.to_bits() & abs_mask) - } - - /// Returns (normalized exponent, normalized significand) - fn normalize(significand: Self::Int) -> (i32, Self::Int); - - /// Returns if `self` is subnormal - fn is_subnormal(self) -> bool; -} -} - -macro_rules! float_impl { - ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { - impl Float for $ty { - type Int = $ity; - type SignedInt = $sity; - type ExpInt = $expty; - - const ZERO: Self = 0.0; - const ONE: Self = 1.0; - - const BITS: u32 = $bits; - const SIG_BITS: u32 = $significand_bits; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; - const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); - - fn to_bits(self) -> Self::Int { - self.to_bits() - } - fn to_bits_signed(self) -> Self::SignedInt { - self.to_bits() as Self::SignedInt - } - fn eq_repr(self, rhs: Self) -> bool { - #[cfg(feature = "mangled-names")] - fn is_nan(x: $ty) -> bool { - // When using mangled-names, the "real" compiler-builtins might not have the - // necessary builtin (__unordtf2) to test whether `f128` is NaN. - // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin - // x is NaN if all the bits of the exponent are set and the significand is non-0 - x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 - } - #[cfg(not(feature = "mangled-names"))] - fn is_nan(x: $ty) -> bool { - x.is_nan() - } - if is_nan(self) && is_nan(rhs) { - true - } else { - self.to_bits() == rhs.to_bits() - } - } - fn is_sign_negative(self) -> bool { - self.is_sign_negative() - } - fn exp(self) -> Self::ExpInt { - ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt - } - fn frac(self) -> Self::Int { - self.to_bits() & Self::SIG_MASK - } - fn imp_frac(self) -> Self::Int { - self.frac() | Self::IMPLICIT_BIT - } - fn from_bits(a: Self::Int) -> Self { - Self::from_bits(a) - } - fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_bits( - ((negative as Self::Int) << (Self::BITS - 1)) - | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) - | (significand & Self::SIG_MASK), - ) - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); - ( - 1i32.wrapping_sub(shift as i32), - significand << shift as Self::Int, - ) - } - fn is_subnormal(self) -> bool { - (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO - } - } - }; -} +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use traits::{Float, HalfRep}; -#[cfg(f16_enabled)] -float_impl!(f16, u16, i16, i8, 16, 10); -float_impl!(f32, u32, i32, i16, 32, 23); -float_impl!(f64, u64, i64, i16, 64, 52); -#[cfg(f128_enabled)] -float_impl!(f128, u128, i128, i16, 128, 112); +#[cfg(feature = "public-test-deps")] +pub use traits::{Float, HalfRep}; diff --git a/library/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/src/float/traits.rs new file mode 100644 index 00000000000..8ccaa7bcbd7 --- /dev/null +++ b/library/compiler-builtins/src/float/traits.rs @@ -0,0 +1,189 @@ +use core::ops; + +use crate::int::{DInt, Int, MinInt}; + +/// Wrapper to extract the integer type half of the float's size +pub type HalfRep = <::Int as DInt>::H; + +/// Trait for some basic operations on floats +#[allow(dead_code)] +pub trait Float: + Copy + + core::fmt::Debug + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::MulAssign + + ops::Add + + ops::Sub + + ops::Div + + ops::Rem +{ + /// A uint of the same width as the float + type Int: Int; + + /// A int of the same width as the float + type SignedInt: Int + MinInt; + + /// An int capable of containing the exponent bits plus a sign bit. This is signed. + type ExpInt: Int; + + const ZERO: Self; + const ONE: Self; + + /// The bitwidth of the float type. + const BITS: u32; + + /// The bitwidth of the significand. + const SIG_BITS: u32; + + /// The bitwidth of the exponent. + const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; + + /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite + /// representation. + /// + /// This is in the rightmost position, use `EXP_MASK` for the shifted value. + const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; + + /// The exponent bias value. + const EXP_BIAS: u32 = Self::EXP_SAT >> 1; + + /// A mask for the sign bit. + const SIGN_MASK: Self::Int; + + /// A mask for the significand. + const SIG_MASK: Self::Int; + + /// The implicit bit of the float format. + const IMPLICIT_BIT: Self::Int; + + /// A mask for the exponent. + const EXP_MASK: Self::Int; + + /// Returns `self` transmuted to `Self::Int` + fn to_bits(self) -> Self::Int; + + /// Returns `self` transmuted to `Self::SignedInt` + fn to_bits_signed(self) -> Self::SignedInt; + + /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be + /// represented in multiple different ways. This method returns `true` if two NaNs are + /// compared. + fn eq_repr(self, rhs: Self) -> bool; + + /// Returns true if the sign is negative + fn is_sign_negative(self) -> bool; + + /// Returns the exponent, not adjusting for bias. + fn exp(self) -> Self::ExpInt; + + /// Returns the significand with no implicit bit (or the "fractional" part) + fn frac(self) -> Self::Int; + + /// Returns the significand with implicit bit + fn imp_frac(self) -> Self::Int; + + /// Returns a `Self::Int` transmuted back to `Self` + fn from_bits(a: Self::Int) -> Self; + + /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self; + + fn abs(self) -> Self { + let abs_mask = !Self::SIGN_MASK; + Self::from_bits(self.to_bits() & abs_mask) + } + + /// Returns (normalized exponent, normalized significand) + fn normalize(significand: Self::Int) -> (i32, Self::Int); + + /// Returns if `self` is subnormal + fn is_subnormal(self) -> bool; +} + +macro_rules! float_impl { + ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { + impl Float for $ty { + type Int = $ity; + type SignedInt = $sity; + type ExpInt = $expty; + + const ZERO: Self = 0.0; + const ONE: Self = 1.0; + + const BITS: u32 = $bits; + const SIG_BITS: u32 = $significand_bits; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; + const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); + + fn to_bits(self) -> Self::Int { + self.to_bits() + } + fn to_bits_signed(self) -> Self::SignedInt { + self.to_bits() as Self::SignedInt + } + fn eq_repr(self, rhs: Self) -> bool { + #[cfg(feature = "mangled-names")] + fn is_nan(x: $ty) -> bool { + // When using mangled-names, the "real" compiler-builtins might not have the + // necessary builtin (__unordtf2) to test whether `f128` is NaN. + // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin + // x is NaN if all the bits of the exponent are set and the significand is non-0 + x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 + } + #[cfg(not(feature = "mangled-names"))] + fn is_nan(x: $ty) -> bool { + x.is_nan() + } + if is_nan(self) && is_nan(rhs) { + true + } else { + self.to_bits() == rhs.to_bits() + } + } + fn is_sign_negative(self) -> bool { + self.is_sign_negative() + } + fn exp(self) -> Self::ExpInt { + ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt + } + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIG_MASK + } + fn imp_frac(self) -> Self::Int { + self.frac() | Self::IMPLICIT_BIT + } + fn from_bits(a: Self::Int) -> Self { + Self::from_bits(a) + } + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_bits( + ((negative as Self::Int) << (Self::BITS - 1)) + | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) + | (significand & Self::SIG_MASK), + ) + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); + ( + 1i32.wrapping_sub(shift as i32), + significand << shift as Self::Int, + ) + } + fn is_subnormal(self) -> bool { + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO + } + } + }; +} + +#[cfg(f16_enabled)] +float_impl!(f16, u16, i16, i8, 16, 10); +float_impl!(f32, u32, i32, i16, 32, 23); +float_impl!(f64, u64, i64, i16, 64, 52); +#[cfg(f128_enabled)] +float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index 1fee9fcf5d8..ba735aa7462 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -3,135 +3,138 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. -use crate::int::{CastInto, Int}; +#[cfg(feature = "public-test-deps")] +pub use implementation::{leading_zeros_default, leading_zeros_riscv}; +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use implementation::{leading_zeros_default, leading_zeros_riscv}; -public_test_dep! { -/// Returns the number of leading binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn leading_zeros_default>(x: T) -> usize { - // The basic idea is to test if the higher bits of `x` are zero and bisect the number - // of leading zeros. It is possible for all branches of the bisection to use the same - // code path by conditionally shifting the higher parts down to let the next bisection - // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` - // and adding to the number of zeros, it is slightly faster to start with - // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, - // because it simplifies the final bisection step. - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS as usize; - // a temporary - let mut t: T; +mod implementation { + use crate::int::{CastInto, Int}; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - t = x >> 32; + /// Returns the number of leading binary zeros in `x`. + #[allow(dead_code)] + pub fn leading_zeros_default>(x: T) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS as usize; + // a temporary + let mut t: T; + + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + t = x >> 32; + if t != T::ZERO { + z -= 32; + x = t; + } + } + if T::BITS >= 32 { + t = x >> 16; + if t != T::ZERO { + z -= 16; + x = t; + } + } + const { assert!(T::BITS >= 16) }; + t = x >> 8; if t != T::ZERO { - z -= 32; + z -= 8; x = t; } - } - if T::BITS >= 32 { - t = x >> 16; + t = x >> 4; if t != T::ZERO { - z -= 16; + z -= 4; x = t; } - } - const { assert!(T::BITS >= 16) }; - t = x >> 8; - if t != T::ZERO { - z -= 8; - x = t; - } - t = x >> 4; - if t != T::ZERO { - z -= 4; - x = t; - } - t = x >> 2; - if t != T::ZERO { - z -= 2; - x = t; - } - // the last two bisections are combined into one conditional - t = x >> 1; - if t != T::ZERO { - z - 2 - } else { - z - x.cast() - } + t = x >> 2; + if t != T::ZERO { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != T::ZERO { + z - 2 + } else { + z - x.cast() + } - // We could potentially save a few cycles by using the LUT trick from - // "https://embeddedgurus.com/state-space/2014/09/ - // fast-deterministic-and-portable-counting-leading-zeros/". - // However, 256 bytes for a LUT is too large for embedded use cases. We could remove - // the last 3 bisections and use this 16 byte LUT for the rest of the work: - //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; - //z -= LUT[x] as usize; - //z - // However, it ends up generating about the same number of instructions. When benchmarked - // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO - // execution effects. Changing to using a LUT and branching is risky for smaller cores. -} -} + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/ + // fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. + } -// The above method does not compile well on RISC-V (because of the lack of predicated -// instructions), producing code with many branches or using an excessively long -// branchless solution. This method takes advantage of the set-if-less-than instruction on -// RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + // The above method does not compile well on RISC-V (because of the lack of predicated + // instructions), producing code with many branches or using an excessively long + // branchless solution. This method takes advantage of the set-if-less-than instruction on + // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. -public_test_dep! { -/// Returns the number of leading binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn leading_zeros_riscv>(x: T) -> usize { - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS; - // a temporary - let mut t: u32; + /// Returns the number of leading binary zeros in `x`. + #[allow(dead_code)] + pub fn leading_zeros_riscv>(x: T) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS; + // a temporary + let mut t: u32; - // RISC-V does not have a set-if-greater-than-or-equal instruction and - // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is - // still the most optimal method. A conditional set can only be turned into a single - // immediate instruction if `x` is compared with an immediate `imm` (that can fit into - // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the - // right). If we try to save an instruction by using `x < imm` for each bisection, we - // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, - // but the immediate will never fit into 12 bits and never save an instruction. - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise - // `t` is set to 0. - t = ((x >= (T::ONE << 32)) as u32) << 5; - // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the - // next step to process. + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (T::ONE << 32)) as u32) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. + x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros + z -= t; + } + if T::BITS >= 32 { + t = ((x >= (T::ONE << 16)) as u32) << 4; + x >>= t; + z -= t; + } + const { assert!(T::BITS >= 16) }; + t = ((x >= (T::ONE << 8)) as u32) << 3; x >>= t; - // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential - // leading zeros z -= t; - } - if T::BITS >= 32 { - t = ((x >= (T::ONE << 16)) as u32) << 4; + t = ((x >= (T::ONE << 4)) as u32) << 2; + x >>= t; + z -= t; + t = ((x >= (T::ONE << 2)) as u32) << 1; x >>= t; z -= t; + t = (x >= (T::ONE << 1)) as u32; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z as usize - x.cast() } - const { assert!(T::BITS >= 16) }; - t = ((x >= (T::ONE << 8)) as u32) << 3; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 4)) as u32) << 2; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 2)) as u32) << 1; - x >>= t; - z -= t; - t = (x >= (T::ONE << 1)) as u32; - x >>= t; - z -= t; - // All bits except the LSB are guaranteed to be zero for this final bisection step. - // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. - z as usize - x.cast() -} } intrinsics! { diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index c0d5a6715e3..1f1be711bbd 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,5 +1,3 @@ -use core::ops; - mod specialized_div_rem; pub mod addsub; @@ -10,425 +8,13 @@ pub mod mul; pub mod sdiv; pub mod shift; pub mod trailing_zeros; +mod traits; pub mod udiv; pub use big::{i256, u256}; -public_test_dep! { -/// Minimal integer implementations needed on all integer types, including wide integers. -#[allow(dead_code)] -pub(crate) trait MinInt: Copy - + core::fmt::Debug - + ops::BitOr - + ops::Not - + ops::Shl -{ - - /// Type with the same width but other signedness - type OtherSign: MinInt; - /// Unsigned version of Self - type UnsignedInt: MinInt; - - /// If `Self` is a signed integer - const SIGNED: bool; - - /// The bitwidth of the int type - const BITS: u32; - - const ZERO: Self; - const ONE: Self; - const MIN: Self; - const MAX: Self; -} -} - -public_test_dep! { -/// Trait for some basic operations on integers -#[allow(dead_code)] -pub(crate) trait Int: MinInt - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Shr - + ops::BitXor - + ops::BitAnd -{ - /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing - /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, - /// 112,119,120,125,126,127]. - const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); - - /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. - const FUZZ_NUM: usize = { - let log2 = (::BITS - 1).count_ones() as usize; - if log2 == 3 { - // case for u8 - 6 - } else { - // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate - // boundaries. - 8 + (4 * (log2 - 4)) - } - }; - - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; - fn unsigned_abs(self) -> Self::UnsignedInt; - - fn from_bool(b: bool) -> Self; - - /// Prevents the need for excessive conversions between signed and unsigned - fn logical_shr(self, other: u32) -> Self; - - /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; - - // copied from primitive integers, but put in a trait - fn is_zero(self) -> bool; - fn wrapping_neg(self) -> Self; - fn wrapping_add(self, other: Self) -> Self; - fn wrapping_mul(self, other: Self) -> Self; - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - fn ilog2(self) -> u32; -} -} - -pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { - let mut v = [0u8; 20]; - v[0] = 0; - v[1] = 1; - v[2] = 2; // important for parity and the iX::MIN case when reversed - let mut i = 3; - - // No need for any more until the byte boundary, because there should be no algorithms - // that are sensitive to anything not next to byte boundaries after 2. We also scale - // in powers of two, which is important to prevent u128 corner tests from getting too - // big. - let mut l = 8; - loop { - if l >= ((bits / 2) as u8) { - break; - } - // get both sides of the byte boundary - v[i] = l - 1; - i += 1; - v[i] = l; - i += 1; - l *= 2; - } - - if bits != 8 { - // add the lower side of the middle boundary - v[i] = ((bits / 2) - 1) as u8; - i += 1; - } - - // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS - // boundary because of algorithms that split the high part up. We reverse the scaling - // as we go to Self::BITS. - let mid = i; - let mut j = 1; - loop { - v[i] = (bits as u8) - (v[mid - j]) - 1; - if j == mid { - break; - } - i += 1; - j += 1; - } - v -} - -macro_rules! int_impl_common { - ($ty:ty) => { - fn from_bool(b: bool) -> Self { - b as $ty - } - - fn logical_shr(self, other: u32) -> Self { - Self::from_unsigned(self.unsigned().wrapping_shr(other)) - } - - fn is_zero(self) -> bool { - self == Self::ZERO - } - - fn wrapping_neg(self) -> Self { - ::wrapping_neg(self) - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn wrapping_shr(self, other: u32) -> Self { - ::wrapping_shr(self, other) - } - - fn rotate_left(self, other: u32) -> Self { - ::rotate_left(self, other) - } - - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - - fn ilog2(self) -> u32 { - ::ilog2(self) - } - }; -} - -macro_rules! int_impl { - ($ity:ty, $uty:ty) => { - impl MinInt for $uty { - type OtherSign = $ity; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $uty { - fn unsigned(self) -> $uty { - self - } - - // It makes writing macros easier if this is implemented for both signed and unsigned - #[allow(clippy::wrong_self_convention)] - fn from_unsigned(me: $uty) -> Self { - me - } - - fn unsigned_abs(self) -> Self { - self - } - - fn abs_diff(self, other: Self) -> Self { - self.abs_diff(other) - } - - int_impl_common!($uty); - } - - impl MinInt for $ity { - type OtherSign = $uty; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $ity { - fn unsigned(self) -> $uty { - self as $uty - } - - fn from_unsigned(me: $uty) -> Self { - me as $ity - } - - fn unsigned_abs(self) -> Self::UnsignedInt { - self.unsigned_abs() - } - - fn abs_diff(self, other: Self) -> $uty { - self.abs_diff(other) - } - - int_impl_common!($ity); - } - }; -} - -int_impl!(isize, usize); -int_impl!(i8, u8); -int_impl!(i16, u16); -int_impl!(i32, u32); -int_impl!(i64, u64); -int_impl!(i128, u128); - -public_test_dep! { -/// Trait for integers twice the bit width of another integer. This is implemented for all -/// primitives except for `u8`, because there is not a smaller primitive. -pub(crate) trait DInt: MinInt { - /// Integer that is half the bit width of the integer this trait is implemented for - type H: HInt; - - /// Returns the low half of `self` - fn lo(self) -> Self::H; - /// Returns the high half of `self` - fn hi(self) -> Self::H; - /// Returns the low and high halves of `self` as a tuple - fn lo_hi(self) -> (Self::H, Self::H) { - (self.lo(), self.hi()) - } - /// Constructs an integer using lower and higher half parts - fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { - lo.zero_widen() | hi.widen_hi() - } -} -} - -public_test_dep! { -/// Trait for integers half the bit width of another integer. This is implemented for all -/// primitives except for `u128`, because it there is not a larger primitive. -pub(crate) trait HInt: Int { - /// Integer that is double the bit width of the integer this trait is implemented for - type D: DInt + MinInt; - - // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for - // unknown reasons this can cause infinite recursion when optimizations are disabled. See - // for context. - - /// Widens (using default extension) the integer to have double bit width - fn widen(self) -> Self::D; - /// Widens (zero extension only) the integer to have double bit width. This is needed to get - /// around problems with associated type bounds (such as `Int`) being unstable - fn zero_widen(self) -> Self::D; - /// Widens the integer to have double bit width and shifts the integer into the higher bits - fn widen_hi(self) -> Self::D; - /// Widening multiplication with zero widening. This cannot overflow. - fn zero_widen_mul(self, rhs: Self) -> Self::D; - /// Widening multiplication. This cannot overflow. - fn widen_mul(self, rhs: Self) -> Self::D; -} -} - -macro_rules! impl_d_int { - ($($X:ident $D:ident),*) => { - $( - impl DInt for $D { - type H = $X; - - fn lo(self) -> Self::H { - self as $X - } - fn hi(self) -> Self::H { - (self >> <$X as MinInt>::BITS) as $X - } - } - )* - }; -} - -macro_rules! impl_h_int { - ($($H:ident $uH:ident $X:ident),*) => { - $( - impl HInt for $H { - type D = $X; - - fn widen(self) -> Self::D { - self as $X - } - fn zero_widen(self) -> Self::D { - (self as $uH) as $X - } - fn zero_widen_mul(self, rhs: Self) -> Self::D { - self.zero_widen().wrapping_mul(rhs.zero_widen()) - } - fn widen_mul(self, rhs: Self) -> Self::D { - self.widen().wrapping_mul(rhs.widen()) - } - fn widen_hi(self) -> Self::D { - (self as $X) << ::BITS - } - } - )* - }; -} - -impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); -impl_h_int!( - u8 u8 u16, - u16 u16 u32, - u32 u32 u64, - u64 u64 u128, - i8 u8 i16, - i16 u16 i32, - i32 u32 i64, - i64 u64 i128 -); - -public_test_dep! { -/// Trait to express (possibly lossy) casting of integers -pub(crate) trait CastInto: Copy { - fn cast(self) -> T; -} - -pub(crate) trait CastFrom:Copy { - fn cast_from(value: T) -> Self; -} -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - self as $into - } - } - )*}; -} +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); +#[cfg(feature = "public-test-deps")] +pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index 330c6e4f80b..f5c6e50239a 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -185,7 +185,6 @@ macro_rules! impl_delegate { }; } -public_test_dep! { /// Returns `n / d` and sets `*rem = n % d`. /// /// This specialization exists because: @@ -195,7 +194,7 @@ public_test_dep! { /// delegate algorithm strategy the only reasonably fast way to perform `u128` division. // used on SPARC #[allow(dead_code)] -pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { +pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { use super::*; let duo_lo = duo as u64; let duo_hi = (duo >> 64) as u64; @@ -316,4 +315,3 @@ pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { } } } -} diff --git a/library/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/src/int/trailing_zeros.rs index cea366b0754..dbc0cce9fac 100644 --- a/library/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/src/int/trailing_zeros.rs @@ -1,44 +1,49 @@ -use crate::int::{CastInto, Int}; +#[cfg(feature = "public-test-deps")] +pub use implementation::trailing_zeros; +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use implementation::trailing_zeros; -public_test_dep! { -/// Returns number of trailing binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { - let mut x = x; - let mut r: u32 = 0; - let mut t: u32; +mod implementation { + use crate::int::{CastInto, Int}; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 - x >>= r; // remove 32 zero bits - } + /// Returns number of trailing binary zeros in `x`. + #[allow(dead_code)] + pub fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + let mut x = x; + let mut r: u32 = 0; + let mut t: u32; - if T::BITS >= 32 { - t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 - r += t; - x >>= t; // x = [0 - 0xFFFF] + higher garbage bits - } + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + x >>= r; // remove 32 zero bits + } - const { assert!(T::BITS >= 16) }; - t = ((CastInto::::cast(x) == 0) as u32) << 3; - x >>= t; // x = [0 - 0xFF] + higher garbage bits - r += t; + if T::BITS >= 32 { + t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 + r += t; + x >>= t; // x = [0 - 0xFFFF] + higher garbage bits + } - let mut x: u8 = x.cast(); + const { assert!(T::BITS >= 16) }; + t = ((CastInto::::cast(x) == 0) as u32) << 3; + x >>= t; // x = [0 - 0xFF] + higher garbage bits + r += t; - t = (((x & 0x0F) == 0) as u32) << 2; - x >>= t; // x = [0 - 0xF] + higher garbage bits - r += t; + let mut x: u8 = x.cast(); - t = (((x & 0x3) == 0) as u32) << 1; - x >>= t; // x = [0 - 0x3] + higher garbage bits - r += t; + t = (((x & 0x0F) == 0) as u32) << 2; + x >>= t; // x = [0 - 0xF] + higher garbage bits + r += t; - x &= 3; + t = (((x & 0x3) == 0) as u32) << 1; + x >>= t; // x = [0 - 0x3] + higher garbage bits + r += t; - r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) -} + x &= 3; + + r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) + } } intrinsics! { diff --git a/library/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/src/int/traits.rs new file mode 100644 index 00000000000..9b079e2aa59 --- /dev/null +++ b/library/compiler-builtins/src/int/traits.rs @@ -0,0 +1,411 @@ +use core::ops; + +/// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] +pub trait MinInt: + Copy + + core::fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type UnsignedInt: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} + +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub trait Int: + MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, + /// 112,119,120,125,126,127]. + const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); + + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; + + fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + fn unsigned_abs(self) -> Self::UnsignedInt; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} + +pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn unsigned(self) -> $uty { + self + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn unsigned_abs(self) -> Self { + self + } + + fn abs_diff(self, other: Self) -> Self { + self.abs_diff(other) + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn unsigned(self) -> $uty { + self as $uty + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn unsigned_abs(self) -> Self::UnsignedInt { + self.unsigned_abs() + } + + fn abs_diff(self, other: Self) -> $uty { + self.abs_diff(other) + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +/// Trait for integers twice the bit width of another integer. This is implemented for all +/// primitives except for `u8`, because there is not a smaller primitive. +pub trait DInt: MinInt { + /// Integer that is half the bit width of the integer this trait is implemented for + type H: HInt; + + /// Returns the low half of `self` + fn lo(self) -> Self::H; + /// Returns the high half of `self` + fn hi(self) -> Self::H; + /// Returns the low and high halves of `self` as a tuple + fn lo_hi(self) -> (Self::H, Self::H) { + (self.lo(), self.hi()) + } + /// Constructs an integer using lower and higher half parts + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { + lo.zero_widen() | hi.widen_hi() + } +} + +/// Trait for integers half the bit width of another integer. This is implemented for all +/// primitives except for `u128`, because it there is not a larger primitive. +pub trait HInt: Int { + /// Integer that is double the bit width of the integer this trait is implemented for + type D: DInt + MinInt; + + // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for + // unknown reasons this can cause infinite recursion when optimizations are disabled. See + // for context. + + /// Widens (using default extension) the integer to have double bit width + fn widen(self) -> Self::D; + /// Widens (zero extension only) the integer to have double bit width. This is needed to get + /// around problems with associated type bounds (such as `Int`) being unstable + fn zero_widen(self) -> Self::D; + /// Widens the integer to have double bit width and shifts the integer into the higher bits + fn widen_hi(self) -> Self::D; + /// Widening multiplication with zero widening. This cannot overflow. + fn zero_widen_mul(self, rhs: Self) -> Self::D; + /// Widening multiplication. This cannot overflow. + fn widen_mul(self, rhs: Self) -> Self::D; +} + +macro_rules! impl_d_int { + ($($X:ident $D:ident),*) => { + $( + impl DInt for $D { + type H = $X; + + fn lo(self) -> Self::H { + self as $X + } + fn hi(self) -> Self::H { + (self >> <$X as MinInt>::BITS) as $X + } + } + )* + }; +} + +macro_rules! impl_h_int { + ($($H:ident $uH:ident $X:ident),*) => { + $( + impl HInt for $H { + type D = $X; + + fn widen(self) -> Self::D { + self as $X + } + fn zero_widen(self) -> Self::D { + (self as $uH) as $X + } + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen().wrapping_mul(rhs.zero_widen()) + } + fn widen_mul(self, rhs: Self) -> Self::D { + self.widen().wrapping_mul(rhs.widen()) + } + fn widen_hi(self) -> Self::D { + (self as $X) << ::BITS + } + } + )* + }; +} + +impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); +impl_h_int!( + u8 u8 u16, + u16 u16 u32, + u32 u32 u64, + u64 u64 u128, + i8 u8 i16, + i16 u16 i32, + i32 u32 i64, + i64 u64 i128 +); + +/// Trait to express (possibly lossy) casting of integers +pub trait CastInto: Copy { + fn cast(self) -> T; +} + +pub trait CastFrom: Copy { + fn cast_from(value: T) -> Self; +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} + +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index f51e49e9876..91606d42be1 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,21 +1,5 @@ //! Macros shared throughout the compiler-builtins implementation -/// Changes the visibility to `pub` if feature "public-test-deps" is set -#[cfg(not(feature = "public-test-deps"))] -macro_rules! public_test_dep { - ($(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => { - $(#[$($meta)*])* pub(crate) $ident $($tokens)* - }; -} - -/// Changes the visibility to `pub` if feature "public-test-deps" is set -#[cfg(feature = "public-test-deps")] -macro_rules! public_test_dep { - {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*} => { - $(#[$($meta)*])* pub $ident $($tokens)* - }; -} - /// The "main macro" used for defining intrinsics. /// /// The compiler-builtins library is super platform-specific with tons of crazy -- cgit 1.4.1-3-g733a5 From 49595ea04e8f8b658910a64734f2c7362ca44d60 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Jan 2025 21:19:09 +0000 Subject: chore: release v0.1.144 --- library/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index 3c21dc2d282..a1f95d17870 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.144](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.143...compiler_builtins-v0.1.144) - 2025-01-15 + +### Other + +- Eliminate the use of `public_test_dep!` + ## [0.1.143](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.142...compiler_builtins-v0.1.143) - 2025-01-15 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 4d5bbe4a902..0b0b7c36528 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.143" +version = "0.1.144" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 2d857e1c218ced55debba0981c22affeabe396d2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 06:28:04 +0000 Subject: Replace `HasDomain` to enable multi-argument edge case and domain tests This also allows reusing the same generator logic between logspace tests and extensive tests, so comes with a nice bit of cleanup. Changes: * Make the generator part of `CheckCtx` since a `Generator` and `CheckCtx` are almost always passed together. * Rename `domain_logspace` to `spaced` since this no longer only operates within a domain and we may want to handle integer spacing. * Domain is now calculated at runtime rather than using traits, which is much easier to work with. * With the above, domains for multidimensional functions are added. * The extensive test generator code tests has been combined with the domain_logspace generator code. With this, the domain tests have just become a subset of extensive tests. These were renamed to "quickspace" since, technically, the extensive tests are also "domain" or "domain logspace" tests. * Edge case generators now handle functions with multiple inputs. * The test runners can be significantly cleaned up and deduplicated. --- .../libm/crates/libm-test/benches/random.rs | 4 +- .../libm/crates/libm-test/examples/plot_domains.rs | 28 +- .../libm/crates/libm-test/src/domain.rs | 303 ++++++++++++--------- .../libm/crates/libm-test/src/gen.rs | 3 +- .../crates/libm-test/src/gen/domain_logspace.rs | 31 --- .../libm/crates/libm-test/src/gen/edge_cases.rs | 185 +++++++++++-- .../libm/crates/libm-test/src/gen/extensive.rs | 262 ------------------ .../libm/crates/libm-test/src/gen/random.rs | 26 +- .../libm/crates/libm-test/src/gen/spaced.rs | 253 +++++++++++++++++ .../libm/crates/libm-test/src/run_cfg.rs | 60 +++- .../crates/libm-test/tests/compare_built_musl.rs | 132 ++------- .../libm/crates/libm-test/tests/multiprecision.rs | 142 ++-------- .../libm/crates/libm-test/tests/z_extensive/run.rs | 24 +- 13 files changed, 736 insertions(+), 717 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/spaced.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index e790022779f..dcc7c1acac3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -4,7 +4,7 @@ use std::time::Duration; use criterion::{Criterion, criterion_main}; use libm_test::gen::random; use libm_test::gen::random::RandomInput; -use libm_test::{CheckBasis, CheckCtx, MathOp, TupleCall}; +use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, TupleCall}; /// Benchmark with this many items to get a variety const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { 50 } else { 500 }; @@ -52,7 +52,7 @@ where { let name = Op::NAME; - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl); + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl, GeneratorKind::Random); let benchvec: Vec<_> = random::get_test_cases::(&ctx).take(BENCH_ITER_ITEMS).collect(); diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs index 62651124535..fb7b854df85 100644 --- a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs +++ b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs @@ -12,9 +12,9 @@ use std::path::Path; use std::process::Command; use std::{env, fs}; -use libm_test::domain::HasDomain; -use libm_test::gen::{domain_logspace, edge_cases}; -use libm_test::{CheckBasis, CheckCtx, MathOp, op}; +use libm_test::gen::spaced::SpacedInput; +use libm_test::gen::{edge_cases, spaced}; +use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; const JL_PLOT: &str = "examples/plot_file.jl"; @@ -52,23 +52,13 @@ fn main() { /// Run multiple generators for a single operator. fn plot_one_operator(out_dir: &Path, config: &mut String) where - Op: MathOp + HasDomain, + Op: MathOp, + Op::RustArgs: SpacedInput, { - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); - plot_one_generator( - out_dir, - &ctx, - "logspace", - config, - domain_logspace::get_test_cases::(&ctx), - ); - plot_one_generator( - out_dir, - &ctx, - "edge_cases", - config, - edge_cases::get_test_cases::(&ctx), - ); + let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::QuickSpaced); + plot_one_generator(out_dir, &ctx, "logspace", config, spaced::get_test_cases::(&ctx).0); + ctx.gen_kind = GeneratorKind::EdgeCases; + plot_one_generator(out_dir, &ctx, "edge_cases", config, edge_cases::get_test_cases::(&ctx)); } /// Plot the output of a single generator. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index 68b91bf02e8..5d650c00a3b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -1,11 +1,13 @@ //! Traits and operations related to bounds of a function. use std::fmt; -use std::ops::{self, Bound}; +use std::ops::Bound; -use crate::{Float, FloatExt}; +use libm::support::Int; -/// Representation of a function's domain. +use crate::{BaseName, Float, FloatExt, Identifier}; + +/// Representation of a single dimension of a function's domain. #[derive(Clone, Debug)] pub struct Domain { /// Start of the region for which a function is defined (ignoring poles). @@ -39,56 +41,131 @@ impl Domain { } } +/// A value that may be any float type or any integer type. +#[derive(Clone, Debug)] +pub enum EitherPrim { + Float(F), + Int(I), +} + +impl EitherPrim { + pub fn unwrap_float(self) -> F { + match self { + EitherPrim::Float(f) => f, + EitherPrim::Int(_) => panic!("expected float; got {self:?}"), + } + } + + pub fn unwrap_int(self) -> I { + match self { + EitherPrim::Float(_) => panic!("expected int; got {self:?}"), + EitherPrim::Int(i) => i, + } + } +} + +/// Convenience 1-dimensional float domains. impl Domain { /// x ∈ ℝ - pub const UNBOUNDED: Self = + const UNBOUNDED: Self = Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }; /// x ∈ ℝ >= 0 - pub const POSITIVE: Self = + const POSITIVE: Self = Self { start: Bound::Included(F::ZERO), end: Bound::Unbounded, check_points: None }; /// x ∈ ℝ > 0 - pub const STRICTLY_POSITIVE: Self = + const STRICTLY_POSITIVE: Self = Self { start: Bound::Excluded(F::ZERO), end: Bound::Unbounded, check_points: None }; + /// Wrap in the float variant of [`EitherPrim`]. + const fn into_prim_float(self) -> EitherPrim> { + EitherPrim::Float(self) + } +} + +/// Convenience 1-dimensional integer domains. +impl Domain { + /// x ∈ ℝ + const UNBOUNDED_INT: Self = + Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }; + + /// Wrap in the int variant of [`EitherPrim`]. + const fn into_prim_int(self) -> EitherPrim, Self> { + EitherPrim::Int(self) + } +} + +/// Multidimensional domains, represented as an array of 1-D domains. +impl EitherPrim, Domain> { + /// x ∈ ℝ + const UNBOUNDED1: [Self; 1] = + [Domain { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None } + .into_prim_float()]; + + /// {x1, x2} ∈ ℝ + const UNBOUNDED2: [Self; 2] = + [Domain::UNBOUNDED.into_prim_float(), Domain::UNBOUNDED.into_prim_float()]; + + /// {x1, x2, x3} ∈ ℝ + const UNBOUNDED3: [Self; 3] = [ + Domain::UNBOUNDED.into_prim_float(), + Domain::UNBOUNDED.into_prim_float(), + Domain::UNBOUNDED.into_prim_float(), + ]; + + /// {x1, x2} ∈ ℝ, one float and one int + const UNBOUNDED_F_I: [Self; 2] = + [Domain::UNBOUNDED.into_prim_float(), Domain::UNBOUNDED_INT.into_prim_int()]; + + /// x ∈ ℝ >= 0 + const POSITIVE: [Self; 1] = [Domain::POSITIVE.into_prim_float()]; + + /// x ∈ ℝ > 0 + const STRICTLY_POSITIVE: [Self; 1] = [Domain::STRICTLY_POSITIVE.into_prim_float()]; + /// Used for versions of `asin` and `acos`. - pub const INVERSE_TRIG_PERIODIC: Self = Self { + const INVERSE_TRIG_PERIODIC: [Self; 1] = [Domain { start: Bound::Included(F::NEG_ONE), end: Bound::Included(F::ONE), check_points: None, - }; + } + .into_prim_float()]; /// Domain for `acosh` - pub const ACOSH: Self = - Self { start: Bound::Included(F::ONE), end: Bound::Unbounded, check_points: None }; + const ACOSH: [Self; 1] = + [Domain { start: Bound::Included(F::ONE), end: Bound::Unbounded, check_points: None } + .into_prim_float()]; /// Domain for `atanh` - pub const ATANH: Self = Self { + const ATANH: [Self; 1] = [Domain { start: Bound::Excluded(F::NEG_ONE), end: Bound::Excluded(F::ONE), check_points: None, - }; + } + .into_prim_float()]; /// Domain for `sin`, `cos`, and `tan` - pub const TRIG: Self = Self { - // TODO + const TRIG: [Self; 1] = [Domain { + // Trig functions have special behavior at fractions of π. check_points: Some(|| Box::new([-F::PI, -F::FRAC_PI_2, F::FRAC_PI_2, F::PI].into_iter())), - ..Self::UNBOUNDED - }; + ..Domain::UNBOUNDED + } + .into_prim_float()]; /// Domain for `log` in various bases - pub const LOG: Self = Self::STRICTLY_POSITIVE; + const LOG: [Self; 1] = Self::STRICTLY_POSITIVE; /// Domain for `log1p` i.e. `log(1 + x)` - pub const LOG1P: Self = - Self { start: Bound::Excluded(F::NEG_ONE), end: Bound::Unbounded, check_points: None }; + const LOG1P: [Self; 1] = + [Domain { start: Bound::Excluded(F::NEG_ONE), end: Bound::Unbounded, check_points: None } + .into_prim_float()]; /// Domain for `sqrt` - pub const SQRT: Self = Self::POSITIVE; + const SQRT: [Self; 1] = Self::POSITIVE; /// Domain for `gamma` - pub const GAMMA: Self = Self { + const GAMMA: [Self; 1] = [Domain { check_points: Some(|| { // Negative integers are asymptotes Box::new((0..u8::MAX).map(|scale| { @@ -100,122 +177,84 @@ impl Domain { })) }), // Whether or not gamma is defined for negative numbers is implementation dependent - ..Self::UNBOUNDED - }; + ..Domain::UNBOUNDED + } + .into_prim_float()]; /// Domain for `loggamma` - pub const LGAMMA: Self = Self::STRICTLY_POSITIVE; -} + const LGAMMA: [Self; 1] = Self::STRICTLY_POSITIVE; -/// Implement on `op::*` types to indicate how they are bounded. -pub trait HasDomain -where - T: Copy + fmt::Debug + ops::Add + ops::Sub + PartialOrd + 'static, -{ - const DOMAIN: Domain; + /// Domain for `jn` and `yn`. + // FIXME: the domain should provide some sort of "reasonable range" so we don't actually test + // the entire system unbounded. + const BESSEL_N: [Self; 2] = + [Domain::UNBOUNDED_INT.into_prim_int(), Domain::UNBOUNDED.into_prim_float()]; } -/// Implement [`HasDomain`] for both the `f32` and `f64` variants of a function. -macro_rules! impl_has_domain { - ($($fn_name:ident => $domain:expr;)*) => { - paste::paste! { - $( - // Implement for f64 functions - impl HasDomain for $crate::op::$fn_name::Routine { - const DOMAIN: Domain = Domain::::$domain; - } - - // Implement for f32 functions - impl HasDomain for $crate::op::[< $fn_name f >]::Routine { - const DOMAIN: Domain = Domain::::$domain; - } - )* - } +/// Get the domain for a given function. +pub fn get_domain( + id: Identifier, + argnum: usize, +) -> EitherPrim, Domain> { + let x = match id.base_name() { + BaseName::Acos => &EitherPrim::INVERSE_TRIG_PERIODIC[..], + BaseName::Acosh => &EitherPrim::ACOSH[..], + BaseName::Asin => &EitherPrim::INVERSE_TRIG_PERIODIC[..], + BaseName::Asinh => &EitherPrim::UNBOUNDED1[..], + BaseName::Atan => &EitherPrim::UNBOUNDED1[..], + BaseName::Atan2 => &EitherPrim::UNBOUNDED2[..], + BaseName::Cbrt => &EitherPrim::UNBOUNDED1[..], + BaseName::Atanh => &EitherPrim::ATANH[..], + BaseName::Ceil => &EitherPrim::UNBOUNDED1[..], + BaseName::Cosh => &EitherPrim::UNBOUNDED1[..], + BaseName::Copysign => &EitherPrim::UNBOUNDED2[..], + BaseName::Cos => &EitherPrim::TRIG[..], + BaseName::Exp => &EitherPrim::UNBOUNDED1[..], + BaseName::Erf => &EitherPrim::UNBOUNDED1[..], + BaseName::Erfc => &EitherPrim::UNBOUNDED1[..], + BaseName::Expm1 => &EitherPrim::UNBOUNDED1[..], + BaseName::Exp10 => &EitherPrim::UNBOUNDED1[..], + BaseName::Exp2 => &EitherPrim::UNBOUNDED1[..], + BaseName::Frexp => &EitherPrim::UNBOUNDED1[..], + BaseName::Fabs => &EitherPrim::UNBOUNDED1[..], + BaseName::Fdim => &EitherPrim::UNBOUNDED2[..], + BaseName::Floor => &EitherPrim::UNBOUNDED1[..], + BaseName::Fma => &EitherPrim::UNBOUNDED3[..], + BaseName::Fmax => &EitherPrim::UNBOUNDED2[..], + BaseName::Fmin => &EitherPrim::UNBOUNDED2[..], + BaseName::Fmod => &EitherPrim::UNBOUNDED2[..], + BaseName::Hypot => &EitherPrim::UNBOUNDED2[..], + BaseName::Ilogb => &EitherPrim::UNBOUNDED1[..], + BaseName::J0 => &EitherPrim::UNBOUNDED1[..], + BaseName::J1 => &EitherPrim::UNBOUNDED1[..], + BaseName::Jn => &EitherPrim::BESSEL_N[..], + BaseName::Ldexp => &EitherPrim::UNBOUNDED_F_I[..], + BaseName::Lgamma => &EitherPrim::LGAMMA[..], + BaseName::LgammaR => &EitherPrim::LGAMMA[..], + BaseName::Log => &EitherPrim::LOG[..], + BaseName::Log10 => &EitherPrim::LOG[..], + BaseName::Log1p => &EitherPrim::LOG1P[..], + BaseName::Log2 => &EitherPrim::LOG[..], + BaseName::Modf => &EitherPrim::UNBOUNDED1[..], + BaseName::Nextafter => &EitherPrim::UNBOUNDED2[..], + BaseName::Pow => &EitherPrim::UNBOUNDED2[..], + BaseName::Remainder => &EitherPrim::UNBOUNDED2[..], + BaseName::Remquo => &EitherPrim::UNBOUNDED2[..], + BaseName::Rint => &EitherPrim::UNBOUNDED1[..], + BaseName::Round => &EitherPrim::UNBOUNDED1[..], + BaseName::Scalbn => &EitherPrim::UNBOUNDED_F_I[..], + BaseName::Sin => &EitherPrim::TRIG[..], + BaseName::Sincos => &EitherPrim::TRIG[..], + BaseName::Sinh => &EitherPrim::UNBOUNDED1[..], + BaseName::Sqrt => &EitherPrim::SQRT[..], + BaseName::Tan => &EitherPrim::TRIG[..], + BaseName::Tanh => &EitherPrim::UNBOUNDED1[..], + BaseName::Tgamma => &EitherPrim::GAMMA[..], + BaseName::Trunc => &EitherPrim::UNBOUNDED1[..], + BaseName::Y0 => &EitherPrim::UNBOUNDED1[..], + BaseName::Y1 => &EitherPrim::UNBOUNDED1[..], + BaseName::Yn => &EitherPrim::BESSEL_N[..], }; -} - -// Tie functions together with their domains. -impl_has_domain! { - acos => INVERSE_TRIG_PERIODIC; - acosh => ACOSH; - asin => INVERSE_TRIG_PERIODIC; - asinh => UNBOUNDED; - atan => UNBOUNDED; - atanh => ATANH; - cbrt => UNBOUNDED; - ceil => UNBOUNDED; - cos => TRIG; - cosh => UNBOUNDED; - erf => UNBOUNDED; - erfc => UNBOUNDED; - exp => UNBOUNDED; - exp10 => UNBOUNDED; - exp2 => UNBOUNDED; - expm1 => UNBOUNDED; - fabs => UNBOUNDED; - floor => UNBOUNDED; - frexp => UNBOUNDED; - ilogb => UNBOUNDED; - j0 => UNBOUNDED; - j1 => UNBOUNDED; - lgamma => LGAMMA; - log => LOG; - log10 => LOG; - log1p => LOG1P; - log2 => LOG; - modf => UNBOUNDED; - rint => UNBOUNDED; - round => UNBOUNDED; - sin => TRIG; - sincos => TRIG; - sinh => UNBOUNDED; - sqrt => SQRT; - tan => TRIG; - tanh => UNBOUNDED; - tgamma => GAMMA; - trunc => UNBOUNDED; - y0 => UNBOUNDED; - y1 => UNBOUNDED; -} - -/* Manual implementations, these functions don't follow `foo`->`foof` naming */ - -impl HasDomain for crate::op::lgammaf_r::Routine { - const DOMAIN: Domain = Domain::::LGAMMA; -} - -impl HasDomain for crate::op::lgamma_r::Routine { - const DOMAIN: Domain = Domain::::LGAMMA; -} - -/* Not all `f16` and `f128` functions exist yet so we can't easily use the macros. */ - -#[cfg(f16_enabled)] -impl HasDomain for crate::op::fabsf16::Routine { - const DOMAIN: Domain = Domain::::UNBOUNDED; -} - -#[cfg(f128_enabled)] -impl HasDomain for crate::op::fabsf128::Routine { - const DOMAIN: Domain = Domain::::UNBOUNDED; -} - -#[cfg(f16_enabled)] -impl HasDomain for crate::op::fdimf16::Routine { - const DOMAIN: Domain = Domain::::UNBOUNDED; -} - -#[cfg(f128_enabled)] -impl HasDomain for crate::op::fdimf128::Routine { - const DOMAIN: Domain = Domain::::UNBOUNDED; -} - -#[cfg(f16_enabled)] -impl HasDomain for crate::op::truncf16::Routine { - const DOMAIN: Domain = Domain::::UNBOUNDED; -} -#[cfg(f128_enabled)] -impl HasDomain for crate::op::truncf128::Routine { - const DOMAIN: Domain = Domain::::UNBOUNDED; + x[argnum].clone() } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index e2bfcdf34c8..e0a7f576680 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -1,9 +1,8 @@ //! Different generators that can create random or systematic bit patterns. -pub mod domain_logspace; pub mod edge_cases; -pub mod extensive; pub mod random; +pub mod spaced; /// A wrapper to turn any iterator into an `ExactSizeIterator`. Asserts the final result to ensure /// the provided size was correct. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs deleted file mode 100644 index c6963ad436a..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! A generator that produces logarithmically spaced values within domain bounds. - -use std::ops::RangeInclusive; - -use libm::support::{IntTy, MinInt}; - -use crate::domain::HasDomain; -use crate::op::OpITy; -use crate::run_cfg::{GeneratorKind, iteration_count}; -use crate::{CheckCtx, MathOp, logspace}; - -/// Create a range of logarithmically spaced inputs within a function's domain. -/// -/// This allows us to get reasonably thorough coverage without wasting time on values that are -/// NaN or out of range. Random tests will still cover values that are excluded here. -pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator -where - Op: MathOp + HasDomain, - IntTy: TryFrom, - RangeInclusive>: Iterator, -{ - let domain = Op::DOMAIN; - let ntests = iteration_count(ctx, GeneratorKind::Domain, 0); - - // We generate logspaced inputs within a specific range, excluding values that are out of - // range in order to make iterations useful (random tests still cover the full range). - let start = domain.range_start(); - let end = domain.range_end(); - let steps = OpITy::::try_from(ntests).unwrap_or(OpITy::::MAX); - logspace(start, end, steps).0.map(|v| (v,)) -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs index 1f27c1467dc..d4014bdb360 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs @@ -1,20 +1,28 @@ //! A generator that checks a handful of cases near infinities, zeros, asymptotes, and NaNs. -use libm::support::Float; +use libm::support::{Float, Int}; -use crate::domain::HasDomain; +use crate::domain::get_domain; +use crate::gen::KnownSize; use crate::run_cfg::{check_near_count, check_point_count}; -use crate::{CheckCtx, FloatExt, MathOp}; +use crate::{CheckCtx, FloatExt, MathOp, test_log}; + +/// Generate a sequence of edge cases, e.g. numbers near zeroes and infiniteis. +pub trait EdgeCaseInput { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator + Send; +} /// Create a list of values around interesting points (infinities, zeroes, NaNs). -pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator +fn float_edge_cases( + ctx: &CheckCtx, + argnum: usize, +) -> (impl Iterator + Clone, u64) where - Op: MathOp + HasDomain, - F: Float, + Op: MathOp, { let mut ret = Vec::new(); let values = &mut ret; - let domain = Op::DOMAIN; + let domain = get_domain::<_, i8>(ctx.fn_ident, argnum).unwrap_float(); let domain_start = domain.range_start(); let domain_end = domain.range_end(); @@ -22,17 +30,17 @@ where let near_points = check_near_count(ctx); // Check near some notable constants - count_up(F::ONE, near_points, values); - count_up(F::ZERO, near_points, values); - count_up(F::NEG_ONE, near_points, values); - count_down(F::ONE, near_points, values); - count_down(F::ZERO, near_points, values); - count_down(F::NEG_ONE, near_points, values); - values.push(F::NEG_ZERO); + count_up(Op::FTy::ONE, near_points, values); + count_up(Op::FTy::ZERO, near_points, values); + count_up(Op::FTy::NEG_ONE, near_points, values); + count_down(Op::FTy::ONE, near_points, values); + count_down(Op::FTy::ZERO, near_points, values); + count_down(Op::FTy::NEG_ONE, near_points, values); + values.push(Op::FTy::NEG_ZERO); // Check values near the extremes - count_up(F::NEG_INFINITY, near_points, values); - count_down(F::INFINITY, near_points, values); + count_up(Op::FTy::NEG_INFINITY, near_points, values); + count_down(Op::FTy::INFINITY, near_points, values); count_down(domain_end, near_points, values); count_up(domain_start, near_points, values); count_down(domain_start, near_points, values); @@ -40,8 +48,8 @@ where count_down(domain_end, near_points, values); // Check some special values that aren't included in the above ranges - values.push(F::NAN); - values.extend(F::consts().iter()); + values.push(Op::FTy::NAN); + values.extend(Op::FTy::consts().iter()); // Check around asymptotes if let Some(f) = domain.check_points { @@ -56,7 +64,18 @@ where values.sort_by_key(|x| x.to_bits()); values.dedup_by_key(|x| x.to_bits()); - ret.into_iter().map(|v| (v,)) + let count = ret.len().try_into().unwrap(); + + test_log(&format!( + "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {count} edge cases", + gen_kind = ctx.gen_kind, + basis = ctx.basis, + fn_ident = ctx.fn_ident, + arg = argnum + 1, + args = ctx.input_count(), + )); + + (ret.into_iter(), count) } /// Add `AROUND` values starting at and including `x` and counting up. Uses the smallest possible @@ -84,3 +103,131 @@ fn count_down(mut x: F, points: u64, values: &mut Vec) { count += 1; } } + +/// Create a list of values around interesting integer points (min, zero, max). +pub fn int_edge_cases( + ctx: &CheckCtx, + _argnum: usize, +) -> (impl Iterator + Clone, u64) { + let mut values = Vec::new(); + let near_points = check_near_count(ctx); + + for up_from in [I::MIN, I::ZERO] { + let mut x = up_from; + for _ in 0..near_points { + values.push(x); + x += I::ONE; + } + } + + for down_from in [I::ZERO, I::MAX] { + let mut x = down_from; + for _ in 0..near_points { + values.push(x); + x -= I::ONE; + } + } + + values.sort(); + values.dedup(); + let len = values.len().try_into().unwrap(); + (values.into_iter(), len) +} + +macro_rules! impl_edge_case_input { + ($fty:ty) => { + impl EdgeCaseInput for ($fty,) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let (iter0, steps0) = float_edge_cases::(ctx, 0); + let iter0 = iter0.map(|v| (v,)); + KnownSize::new(iter0, steps0) + } + } + + impl EdgeCaseInput for ($fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let (iter0, steps0) = float_edge_cases::(ctx, 0); + let (iter1, steps1) = float_edge_cases::(ctx, 1); + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + KnownSize::new(iter, count) + } + } + + impl EdgeCaseInput for ($fty, $fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let (iter0, steps0) = float_edge_cases::(ctx, 0); + let (iter1, steps1) = float_edge_cases::(ctx, 1); + let (iter2, steps2) = float_edge_cases::(ctx, 2); + + let iter = iter0 + .flat_map(move |first| iter1.clone().map(move |second| (first, second))) + .flat_map(move |(first, second)| { + iter2.clone().map(move |third| (first, second, third)) + }); + let count = steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); + + KnownSize::new(iter, count) + } + } + + impl EdgeCaseInput for (i32, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let (iter0, steps0) = int_edge_cases(ctx, 0); + let (iter1, steps1) = float_edge_cases::(ctx, 1); + + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + + KnownSize::new(iter, count) + } + } + + impl EdgeCaseInput for ($fty, i32) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let (iter0, steps0) = float_edge_cases::(ctx, 0); + let (iter1, steps1) = int_edge_cases(ctx, 1); + + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + + KnownSize::new(iter, count) + } + } + }; +} + +#[cfg(f16_enabled)] +impl_edge_case_input!(f16); +impl_edge_case_input!(f32); +impl_edge_case_input!(f64); +#[cfg(f128_enabled)] +impl_edge_case_input!(f128); + +pub fn get_test_cases( + ctx: &CheckCtx, +) -> impl ExactSizeIterator + use<'_, Op> +where + Op: MathOp, + Op::RustArgs: EdgeCaseInput, +{ + Op::RustArgs::get_cases(ctx) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs deleted file mode 100644 index fb709e54684..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs +++ /dev/null @@ -1,262 +0,0 @@ -use std::fmt; -use std::ops::RangeInclusive; - -use libm::support::{Float, MinInt}; - -use crate::domain::HasDomain; -use crate::op::OpITy; -use crate::run_cfg::{int_range, iteration_count}; -use crate::{CheckCtx, GeneratorKind, MathOp, linear_ints, logspace}; - -/// Generate a sequence of inputs that either cover the domain in completeness (for smaller float -/// types and single argument functions) or provide evenly spaced inputs across the domain with -/// approximately `u32::MAX` total iterations. -pub trait ExtensiveInput { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); -} - -/// Construct an iterator from `logspace` and also calculate the total number of steps expected -/// for that iterator. -fn logspace_steps( - start: Op::FTy, - end: Op::FTy, - max_steps: u64, -) -> (impl Iterator + Clone, u64) -where - Op: MathOp, - OpITy: TryFrom, - u64: TryFrom, Error: fmt::Debug>, - RangeInclusive>: Iterator, -{ - let max_steps = OpITy::::try_from(max_steps).unwrap_or(OpITy::::MAX); - let (iter, steps) = logspace(start, end, max_steps); - - // `steps` will be <= the original `max_steps`, which is a `u64`. - (iter, steps.try_into().unwrap()) -} - -/// Represents the iterator in either `Left` or `Right`. -enum EitherIter { - A(A), - B(B), -} - -impl, B: Iterator> Iterator for EitherIter { - type Item = T; - - fn next(&mut self) -> Option { - match self { - Self::A(iter) => iter.next(), - Self::B(iter) => iter.next(), - } - } - - fn size_hint(&self) -> (usize, Option) { - match self { - Self::A(iter) => iter.size_hint(), - Self::B(iter) => iter.size_hint(), - } - } -} - -/// Gets the total number of possible values, returning `None` if that number doesn't fit in a -/// `u64`. -fn value_count() -> Option -where - u64: TryFrom, -{ - u64::try_from(F::Int::MAX).ok().and_then(|max| max.checked_add(1)) -} - -/// Returns an iterator of every possible value of type `F`. -fn all_values() -> impl Iterator -where - RangeInclusive: Iterator, -{ - (F::Int::MIN..=F::Int::MAX).map(|bits| F::from_bits(bits)) -} - -macro_rules! impl_extensive_input { - ($fty:ty) => { - impl ExtensiveInput for ($fty,) - where - Op: MathOp, - Op: HasDomain, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); - // `f16` and `f32` can have exhaustive tests. - match value_count::() { - Some(steps0) if steps0 <= max_steps0 => { - let iter0 = all_values(); - let iter0 = iter0.map(|v| (v,)); - (EitherIter::A(iter0), steps0) - } - _ => { - let start = Op::DOMAIN.range_start(); - let end = Op::DOMAIN.range_end(); - let (iter0, steps0) = logspace_steps::(start, end, max_steps0); - let iter0 = iter0.map(|v| (v,)); - (EitherIter::B(iter0), steps0) - } - } - } - } - - impl ExtensiveInput for ($fty, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); - let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); - // `f16` can have exhaustive tests. - match value_count::() { - Some(count) if count <= max_steps0 && count <= max_steps1 => { - let iter = all_values() - .flat_map(|first| all_values().map(move |second| (first, second))); - (EitherIter::A(iter), count.checked_mul(count).unwrap()) - } - _ => { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; - let (iter0, steps0) = logspace_steps::(start, end, max_steps0); - let (iter1, steps1) = logspace_steps::(start, end, max_steps1); - let iter = iter0.flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = steps0.checked_mul(steps1).unwrap(); - (EitherIter::B(iter), count) - } - } - } - } - - impl ExtensiveInput for ($fty, $fty, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); - let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); - let max_steps2 = iteration_count(ctx, GeneratorKind::Extensive, 2); - // `f16` can be exhaustive tested if `LIBM_EXTENSIVE_TESTS` is incresed. - match value_count::() { - Some(count) - if count <= max_steps0 && count <= max_steps1 && count <= max_steps2 => - { - let iter = all_values().flat_map(|first| { - all_values().flat_map(move |second| { - all_values().map(move |third| (first, second, third)) - }) - }); - (EitherIter::A(iter), count.checked_pow(3).unwrap()) - } - _ => { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; - - let (iter0, steps0) = logspace_steps::(start, end, max_steps0); - let (iter1, steps1) = logspace_steps::(start, end, max_steps1); - let (iter2, steps2) = logspace_steps::(start, end, max_steps2); - - let iter = iter0 - .flat_map(move |first| iter1.clone().map(move |second| (first, second))) - .flat_map(move |(first, second)| { - iter2.clone().map(move |third| (first, second, third)) - }); - let count = - steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); - - (EitherIter::B(iter), count) - } - } - } - } - - impl ExtensiveInput for (i32, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let range0 = int_range(ctx, GeneratorKind::Extensive, 0); - let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); - let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); - match value_count::() { - Some(count1) if count1 <= max_steps1 => { - let (iter0, steps0) = linear_ints(range0, max_steps0); - let iter = iter0 - .flat_map(move |first| all_values().map(move |second| (first, second))); - (EitherIter::A(iter), steps0.checked_mul(count1).unwrap()) - } - _ => { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; - - let (iter0, steps0) = linear_ints(range0, max_steps0); - let (iter1, steps1) = logspace_steps::(start, end, max_steps1); - - let iter = iter0.flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = steps0.checked_mul(steps1).unwrap(); - - (EitherIter::B(iter), count) - } - } - } - } - - impl ExtensiveInput for ($fty, i32) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); - let range1 = int_range(ctx, GeneratorKind::Extensive, 1); - let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); - match value_count::() { - Some(count0) if count0 <= max_steps0 => { - let (iter1, steps1) = linear_ints(range1, max_steps1); - let iter = all_values().flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - (EitherIter::A(iter), count0.checked_mul(steps1).unwrap()) - } - _ => { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; - - let (iter0, steps0) = logspace_steps::(start, end, max_steps0); - let (iter1, steps1) = linear_ints(range1, max_steps1); - - let iter = iter0.flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = steps0.checked_mul(steps1).unwrap(); - - (EitherIter::B(iter), count) - } - } - } - } - }; -} - -#[cfg(f16_enabled)] -impl_extensive_input!(f16); -impl_extensive_input!(f32); -impl_extensive_input!(f64); -#[cfg(f128_enabled)] -impl_extensive_input!(f128); - -/// Create a test case iterator for extensive inputs. Also returns the total test case count. -pub fn get_test_cases( - ctx: &CheckCtx, -) -> (impl Iterator + Send + use<'_, Op>, u64) -where - Op: MathOp, - Op::RustArgs: ExtensiveInput, -{ - Op::RustArgs::get_cases(ctx) -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 6b08e560dff..56c39981a44 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -9,8 +9,8 @@ use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; use super::KnownSize; +use crate::CheckCtx; use crate::run_cfg::{int_range, iteration_count}; -use crate::{CheckCtx, GeneratorKind}; pub(crate) const SEED_ENV: &str = "LIBM_SEED"; @@ -52,7 +52,7 @@ macro_rules! impl_random_input { ($fty:ty) => { impl RandomInput for ($fty,) { fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let count = iteration_count(ctx, GeneratorKind::Random, 0); + let count = iteration_count(ctx, 0); let iter = random_floats(count).map(|f: $fty| (f,)); KnownSize::new(iter, count) } @@ -60,8 +60,8 @@ macro_rules! impl_random_input { impl RandomInput for ($fty, $fty) { fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let count0 = iteration_count(ctx, GeneratorKind::Random, 0); - let count1 = iteration_count(ctx, GeneratorKind::Random, 1); + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); let iter = random_floats(count0) .flat_map(move |f1: $fty| random_floats(count1).map(move |f2: $fty| (f1, f2))); KnownSize::new(iter, count0 * count1) @@ -70,9 +70,9 @@ macro_rules! impl_random_input { impl RandomInput for ($fty, $fty, $fty) { fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let count0 = iteration_count(ctx, GeneratorKind::Random, 0); - let count1 = iteration_count(ctx, GeneratorKind::Random, 1); - let count2 = iteration_count(ctx, GeneratorKind::Random, 2); + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let count2 = iteration_count(ctx, 2); let iter = random_floats(count0).flat_map(move |f1: $fty| { random_floats(count1).flat_map(move |f2: $fty| { random_floats(count2).map(move |f3: $fty| (f1, f2, f3)) @@ -84,9 +84,9 @@ macro_rules! impl_random_input { impl RandomInput for (i32, $fty) { fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let count0 = iteration_count(ctx, GeneratorKind::Random, 0); - let count1 = iteration_count(ctx, GeneratorKind::Random, 1); - let range0 = int_range(ctx, GeneratorKind::Random, 0); + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let range0 = int_range(ctx, 0); let iter = random_ints(count0, range0) .flat_map(move |f1: i32| random_floats(count1).map(move |f2: $fty| (f1, f2))); KnownSize::new(iter, count0 * count1) @@ -95,9 +95,9 @@ macro_rules! impl_random_input { impl RandomInput for ($fty, i32) { fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let count0 = iteration_count(ctx, GeneratorKind::Random, 0); - let count1 = iteration_count(ctx, GeneratorKind::Random, 1); - let range1 = int_range(ctx, GeneratorKind::Random, 1); + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let range1 = int_range(ctx, 1); let iter = random_floats(count0).flat_map(move |f1: $fty| { random_ints(count1, range1.clone()).map(move |f2: i32| (f1, f2)) }); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/spaced.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/spaced.rs new file mode 100644 index 00000000000..bea3f4c7e1b --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/spaced.rs @@ -0,0 +1,253 @@ +use std::fmt; +use std::ops::RangeInclusive; + +use libm::support::{Float, MinInt}; + +use crate::domain::get_domain; +use crate::op::OpITy; +use crate::run_cfg::{int_range, iteration_count}; +use crate::{CheckCtx, MathOp, linear_ints, logspace}; + +/// Generate a sequence of inputs that eiher cover the domain in completeness (for smaller float +/// types and single argument functions) or provide evenly spaced inputs across the domain with +/// approximately `u32::MAX` total iterations. +pub trait SpacedInput { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); +} + +/// Construct an iterator from `logspace` and also calculate the total number of steps expected +/// for that iterator. +fn logspace_steps( + ctx: &CheckCtx, + argnum: usize, + max_steps: u64, +) -> (impl Iterator + Clone, u64) +where + Op: MathOp, + OpITy: TryFrom, + u64: TryFrom, Error: fmt::Debug>, + RangeInclusive>: Iterator, +{ + // i8 is a dummy type here, it can be any integer. + let domain = get_domain::(ctx.fn_ident, argnum).unwrap_float(); + let start = domain.range_start(); + let end = domain.range_end(); + + let max_steps = OpITy::::try_from(max_steps).unwrap_or(OpITy::::MAX); + let (iter, steps) = logspace(start, end, max_steps); + + // `steps` will be <= the original `max_steps`, which is a `u64`. + (iter, steps.try_into().unwrap()) +} + +/// Represents the iterator in either `Left` or `Right`. +enum EitherIter { + A(A), + B(B), +} + +impl, B: Iterator> Iterator for EitherIter { + type Item = T; + + fn next(&mut self) -> Option { + match self { + Self::A(iter) => iter.next(), + Self::B(iter) => iter.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self { + Self::A(iter) => iter.size_hint(), + Self::B(iter) => iter.size_hint(), + } + } +} + +/// Gets the total number of possible values, returning `None` if that number doesn't fit in a +/// `u64`. +fn value_count() -> Option +where + u64: TryFrom, +{ + u64::try_from(F::Int::MAX).ok().and_then(|max| max.checked_add(1)) +} + +/// Returns an iterator of every possible value of type `F`. +fn all_values() -> impl Iterator +where + RangeInclusive: Iterator, +{ + (F::Int::MIN..=F::Int::MAX).map(|bits| F::from_bits(bits)) +} + +macro_rules! impl_spaced_input { + ($fty:ty) => { + impl SpacedInput for ($fty,) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, 0); + // `f16` and `f32` can have exhaustive tests. + match value_count::() { + Some(steps0) if steps0 <= max_steps0 => { + let iter0 = all_values(); + let iter0 = iter0.map(|v| (v,)); + (EitherIter::A(iter0), steps0) + } + _ => { + let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); + let iter0 = iter0.map(|v| (v,)); + (EitherIter::B(iter0), steps0) + } + } + } + } + + impl SpacedInput for ($fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, 0); + let max_steps1 = iteration_count(ctx, 1); + // `f16` can have exhaustive tests. + match value_count::() { + Some(count) if count <= max_steps0 && count <= max_steps1 => { + let iter = all_values() + .flat_map(|first| all_values().map(move |second| (first, second))); + (EitherIter::A(iter), count.checked_mul(count).unwrap()) + } + _ => { + let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); + let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); + (EitherIter::B(iter), count) + } + } + } + } + + impl SpacedInput for ($fty, $fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, 0); + let max_steps1 = iteration_count(ctx, 1); + let max_steps2 = iteration_count(ctx, 2); + // `f16` can be exhaustive tested if `LIBM_EXTENSIVE_TESTS` is incresed. + match value_count::() { + Some(count) + if count <= max_steps0 && count <= max_steps1 && count <= max_steps2 => + { + let iter = all_values().flat_map(|first| { + all_values().flat_map(move |second| { + all_values().map(move |third| (first, second, third)) + }) + }); + (EitherIter::A(iter), count.checked_pow(3).unwrap()) + } + _ => { + let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); + let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); + let (iter2, steps2) = logspace_steps::(ctx, 2, max_steps2); + + let iter = iter0 + .flat_map(move |first| iter1.clone().map(move |second| (first, second))) + .flat_map(move |(first, second)| { + iter2.clone().map(move |third| (first, second, third)) + }); + let count = + steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); + + (EitherIter::B(iter), count) + } + } + } + } + + impl SpacedInput for (i32, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let range0 = int_range(ctx, 0); + let max_steps0 = iteration_count(ctx, 0); + let max_steps1 = iteration_count(ctx, 1); + match value_count::() { + Some(count1) if count1 <= max_steps1 => { + let (iter0, steps0) = linear_ints(range0, max_steps0); + let iter = iter0 + .flat_map(move |first| all_values().map(move |second| (first, second))); + (EitherIter::A(iter), steps0.checked_mul(count1).unwrap()) + } + _ => { + let (iter0, steps0) = linear_ints(range0, max_steps0); + let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); + + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); + + (EitherIter::B(iter), count) + } + } + } + } + + impl SpacedInput for ($fty, i32) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, 0); + let range1 = int_range(ctx, 1); + let max_steps1 = iteration_count(ctx, 1); + match value_count::() { + Some(count0) if count0 <= max_steps0 => { + let (iter1, steps1) = linear_ints(range1, max_steps1); + let iter = all_values().flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + (EitherIter::A(iter), count0.checked_mul(steps1).unwrap()) + } + _ => { + let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); + let (iter1, steps1) = linear_ints(range1, max_steps1); + + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); + + (EitherIter::B(iter), count) + } + } + } + } + }; +} + +#[cfg(f16_enabled)] +impl_spaced_input!(f16); +impl_spaced_input!(f32); +impl_spaced_input!(f64); +#[cfg(f128_enabled)] +impl_spaced_input!(f128); + +/// Create a test case iterator for extensive inputs. Also returns the total test case count. +pub fn get_test_cases( + ctx: &CheckCtx, +) -> (impl Iterator + Send + use<'_, Op>, u64) +where + Op: MathOp, + Op::RustArgs: SpacedInput, +{ + Op::RustArgs::get_cases(ctx) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 4a52091fe8d..6763de8bcc8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -39,11 +39,12 @@ pub struct CheckCtx { pub base_name_str: &'static str, /// Source of truth for tests. pub basis: CheckBasis, + pub gen_kind: GeneratorKind, } impl CheckCtx { /// Create a new check context, using the default ULP for the function. - pub fn new(fn_ident: Identifier, basis: CheckBasis) -> Self { + pub fn new(fn_ident: Identifier, basis: CheckBasis, gen_kind: GeneratorKind) -> Self { let mut ret = Self { ulp: 0, fn_ident, @@ -51,10 +52,16 @@ impl CheckCtx { base_name: fn_ident.base_name(), base_name_str: fn_ident.base_name().as_str(), basis, + gen_kind, }; ret.ulp = crate::default_ulp(&ret); ret } + + /// The number of input arguments for this function. + pub fn input_count(&self) -> usize { + self.fn_ident.math_op().rust_sig.args.len() + } } /// Possible items to test against @@ -66,11 +73,13 @@ pub enum CheckBasis { Mpfr, } -/// The different kinds of generators that provide test input. +/// The different kinds of generators that provide test input, which account for input pattern +/// and quantity. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum GeneratorKind { - Domain, + EdgeCases, Extensive, + QuickSpaced, Random, } @@ -155,7 +164,7 @@ impl TestEnv { } /// The number of iterations to run for a given test. -pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) -> u64 { +pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { let t_env = TestEnv::from_env(ctx); // Ideally run 5M tests @@ -185,10 +194,13 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - // Run fewer random tests than domain tests. let random_iter_count = domain_iter_count / 100; - let mut total_iterations = match gen_kind { - GeneratorKind::Domain => domain_iter_count, + let mut total_iterations = match ctx.gen_kind { + GeneratorKind::QuickSpaced => domain_iter_count, GeneratorKind::Random => random_iter_count, GeneratorKind::Extensive => *EXTENSIVE_MAX_ITERATIONS, + GeneratorKind::EdgeCases => { + unimplemented!("edge case tests shoudn't need `iteration_count`") + } }; // FMA has a huge domain but is reasonably fast to run, so increase iterations. @@ -213,16 +225,18 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - }; let total = ntests.pow(t_env.input_count.try_into().unwrap()); - let seed_msg = match gen_kind { - GeneratorKind::Domain | GeneratorKind::Extensive => String::new(), + let seed_msg = match ctx.gen_kind { + GeneratorKind::QuickSpaced | GeneratorKind::Extensive => String::new(), GeneratorKind::Random => { format!(" using `{SEED_ENV}={}`", str::from_utf8(SEED.as_slice()).unwrap()) } + GeneratorKind::EdgeCases => unreachable!(), }; test_log(&format!( "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {ntests} iterations \ ({total} total){seed_msg}", + gen_kind = ctx.gen_kind, basis = ctx.basis, fn_ident = ctx.fn_ident, arg = argnum + 1, @@ -233,7 +247,7 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - } /// Some tests require that an integer be kept within reasonable limits; generate that here. -pub fn int_range(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) -> RangeInclusive { +pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { let t_env = TestEnv::from_env(ctx); if !matches!(ctx.base_name, BaseName::Jn | BaseName::Yn) { @@ -252,22 +266,42 @@ pub fn int_range(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) -> Rang let extensive_range = (-0xfff)..=0xfffff; - match gen_kind { + match ctx.gen_kind { GeneratorKind::Extensive => extensive_range, - GeneratorKind::Domain | GeneratorKind::Random => non_extensive_range, + GeneratorKind::QuickSpaced | GeneratorKind::Random => non_extensive_range, + GeneratorKind::EdgeCases => extensive_range, } } /// For domain tests, limit how many asymptotes or specified check points we test. pub fn check_point_count(ctx: &CheckCtx) -> usize { + assert_eq!( + ctx.gen_kind, + GeneratorKind::EdgeCases, + "check_point_count is intended for edge case tests" + ); let t_env = TestEnv::from_env(ctx); if t_env.slow_platform || !cfg!(optimizations_enabled) { 4 } else { 10 } } /// When validating points of interest (e.g. asymptotes, inflection points, extremes), also check /// this many surrounding values. -pub fn check_near_count(_ctx: &CheckCtx) -> u64 { - if cfg!(optimizations_enabled) { 100 } else { 10 } +pub fn check_near_count(ctx: &CheckCtx) -> u64 { + assert_eq!( + ctx.gen_kind, + GeneratorKind::EdgeCases, + "check_near_count is intended for edge case tests" + ); + if cfg!(optimizations_enabled) { + // Taper based on the number of inputs. + match ctx.input_count() { + 1 | 2 => 100, + 3 => 50, + x => panic!("unexpected argument count {x}"), + } + } else { + 10 + } } /// Check whether extensive actions should be run or skipped. diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 836c425a589..f540a0b1551 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -9,150 +9,78 @@ // There are some targets we can't build musl for #![cfg(feature = "build-musl")] -use libm_test::domain::HasDomain; -use libm_test::gen::random::RandomInput; -use libm_test::gen::{domain_logspace, edge_cases, random}; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, MathOp, TupleCall}; +use libm_test::gen::{edge_cases, random, spaced}; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; -macro_rules! musl_rand_tests { - ( - fn_name: $fn_name:ident, - attrs: [$($attr:meta),*], - ) => { - paste::paste! { - #[test] - $(#[$attr])* - fn [< musl_random_ $fn_name >]() { - test_one_random::(musl_math_sys::$fn_name); - } - } - }; -} - -fn test_one_random(musl_fn: Op::CFn) -where - Op: MathOp, - Op::RustArgs: RandomInput, -{ - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl); - let cases = random::get_test_cases::(&ctx); +const BASIS: CheckBasis = CheckBasis::Musl; +fn musl_runner( + ctx: &CheckCtx, + cases: impl Iterator, + musl_fn: Op::CFn, +) { for input in cases { let musl_res = input.call(musl_fn); let crate_res = input.call(Op::ROUTINE); - crate_res.validate(musl_res, input, &ctx).unwrap(); + crate_res.validate(musl_res, input, ctx).unwrap(); } } -libm_macros::for_each_function! { - callback: musl_rand_tests, - // Musl does not support `f16` and `f128` on all platforms. - skip: [ - copysignf128, - copysignf16, - fabsf128, - fabsf16, - fdimf128, - fdimf16, - truncf128, - truncf16, - ], - attributes: [ - #[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586 - [exp10, exp10f, exp2, exp2f, rint] - ], -} - /// Test against musl with generators from a domain. -macro_rules! musl_domain_tests { +macro_rules! musl_tests { ( fn_name: $fn_name:ident, attrs: [$($attr:meta),*], ) => { paste::paste! { + #[test] + $(#[$attr])* + fn [< musl_random_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Random); + let cases = random::get_test_cases::<::RustArgs>(&ctx); + musl_runner::(&ctx, cases, musl_math_sys::$fn_name); + } + #[test] $(#[$attr])* fn [< musl_edge_case_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - domain_test_runner::( - edge_cases::get_test_cases::, - musl_math_sys::$fn_name, - ); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::EdgeCases); + let cases = edge_cases::get_test_cases::(&ctx); + musl_runner::(&ctx, cases, musl_math_sys::$fn_name); } #[test] $(#[$attr])* - fn [< musl_logspace_ $fn_name >]() { + fn [< musl_quickspace_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - domain_test_runner::( - domain_logspace::get_test_cases::, - musl_math_sys::$fn_name, - ); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::QuickSpaced); + let cases = spaced::get_test_cases::(&ctx).0; + musl_runner::(&ctx, cases, musl_math_sys::$fn_name); } } }; } -/// Test a single routine against domaine-aware inputs. -fn domain_test_runner(gen: impl FnOnce(&CheckCtx) -> I, musl_fn: Op::CFn) -where - Op: MathOp, - Op: HasDomain, - I: Iterator, -{ - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl); - let cases = gen(&ctx); - - for input in cases { - let musl_res = input.call(musl_fn); - let crate_res = input.call(Op::ROUTINE); - - crate_res.validate(musl_res, input, &ctx).unwrap(); - } -} - libm_macros::for_each_function! { - callback: musl_domain_tests, + callback: musl_tests, attributes: [], skip: [ - // Functions with multiple inputs - atan2, - atan2f, - copysign, - copysignf, - copysignf16, - copysignf128, - fdim, - fdimf, - fma, - fmaf, - fmax, - fmaxf, - fmin, - fminf, - fmod, - fmodf, - hypot, - hypotf, + // TODO integer inputs jn, jnf, ldexp, ldexpf, - nextafter, - nextafterf, - pow, - powf, - remainder, - remainderf, - remquo, - remquof, scalbn, scalbnf, yn, ynf, // Not provided by musl + copysignf128, + copysignf16, fabsf128, fabsf16, fdimf128, diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 123abfdaf8b..761ca1f851e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -2,151 +2,69 @@ #![cfg(feature = "build-mpfr")] -use libm_test::domain::HasDomain; -use libm_test::gen::random::RandomInput; -use libm_test::gen::{domain_logspace, edge_cases, random}; +use libm_test::gen::{edge_cases, random, spaced}; use libm_test::mpfloat::MpOp; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, MathOp, OpFTy, OpRustFn, OpRustRet, TupleCall}; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; -/// Test against MPFR with random inputs. -macro_rules! mp_rand_tests { - ( - fn_name: $fn_name:ident, - attrs: [$($attr:meta),*], - ) => { - paste::paste! { - #[test] - $(#[$attr])* - fn [< mp_random_ $fn_name >]() { - test_one_random::(); - } - } - }; -} +const BASIS: CheckBasis = CheckBasis::Mpfr; -/// Test a single routine with random inputs -fn test_one_random() -where - Op: MathOp + MpOp, - Op::RustArgs: RandomInput, -{ +fn mp_runner(ctx: &CheckCtx, cases: impl Iterator) { let mut mp_vals = Op::new_mp(); - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); - let cases = random::get_test_cases::(&ctx); - for input in cases { let mp_res = Op::run(&mut mp_vals, input); let crate_res = input.call(Op::ROUTINE); - crate_res.validate(mp_res, input, &ctx).unwrap(); + crate_res.validate(mp_res, input, ctx).unwrap(); } } -libm_macros::for_each_function! { - callback: mp_rand_tests, - attributes: [ - // Also an assertion failure on i686: at `MPFR_ASSERTN (! mpfr_erangeflag_p ())` - #[ignore = "large values are infeasible in MPFR"] - [jn, jnf, yn, ynf], - ], - skip: [ - // FIXME: test needed, see - // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 - nextafter, - nextafterf, - ], -} - -/// Test against MPFR with generators from a domain. -macro_rules! mp_domain_tests { +macro_rules! mp_tests { ( fn_name: $fn_name:ident, attrs: [$($attr:meta),*], ) => { paste::paste! { + #[test] + $(#[$attr])* + fn [< mp_random_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Random); + let cases = random::get_test_cases::<::RustArgs>(&ctx); + mp_runner::(&ctx, cases); + } + #[test] $(#[$attr])* fn [< mp_edge_case_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - domain_test_runner::(edge_cases::get_test_cases::); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::EdgeCases); + let cases = edge_cases::get_test_cases::(&ctx); + mp_runner::(&ctx, cases); } #[test] $(#[$attr])* - fn [< mp_logspace_ $fn_name >]() { + fn [< mp_quickspace_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - domain_test_runner::(domain_logspace::get_test_cases::); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::QuickSpaced); + let cases = spaced::get_test_cases::(&ctx).0; + mp_runner::(&ctx, cases); } } }; } -/// Test a single routine against domaine-aware inputs. -fn domain_test_runner(gen: impl FnOnce(&CheckCtx) -> I) -where - // Complicated generics... - // The operation must take a single float argument (unary only) - Op: MathOp::FTy,)>, - // It must also support multiprecision operations - Op: MpOp, - // And it must have a domain specified - Op: HasDomain, - // The single float argument tuple must be able to call the `RustFn` and return `RustRet` - (OpFTy,): TupleCall, Output = OpRustRet>, - I: Iterator, -{ - let mut mp_vals = Op::new_mp(); - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); - let cases = gen(&ctx); - - for input in cases { - let mp_res = Op::run(&mut mp_vals, input); - let crate_res = input.call(Op::ROUTINE); - - crate_res.validate(mp_res, input, &ctx).unwrap(); - } -} - libm_macros::for_each_function! { - callback: mp_domain_tests, - attributes: [], + callback: mp_tests, + attributes: [ + // Also an assertion failure on i686: at `MPFR_ASSERTN (! mpfr_erangeflag_p ())` + #[ignore = "large values are infeasible in MPFR"] + [jn, jnf, yn, ynf], + ], skip: [ - // Functions with multiple inputs - atan2, - atan2f, - copysign, - copysignf, - copysignf16, - copysignf128, - fdim, - fdimf, - fdimf16, - fdimf128, - fma, - fmaf, - fmax, - fmaxf, - fmin, - fminf, - fmod, - fmodf, - hypot, - hypotf, - jn, - jnf, - ldexp, - ldexpf, + // FIXME: test needed, see + // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 nextafter, nextafterf, - pow, - powf, - remainder, - remainderf, - remquo, - remquof, - scalbn, - scalbnf, - yn, - ynf, ], } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs index 7ee9678515e..a323c9110ee 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs @@ -6,13 +6,18 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::time::Duration; use indicatif::{ProgressBar, ProgressStyle}; -use libm_test::gen::extensive::{self, ExtensiveInput}; +use libm_test::gen::spaced; use libm_test::mpfloat::MpOp; use libm_test::{ - CheckBasis, CheckCtx, CheckOutput, MathOp, TestResult, TupleCall, skip_extensive_test, + CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TestResult, TupleCall, + skip_extensive_test, }; use libtest_mimic::{Arguments, Trial}; use rayon::prelude::*; +use spaced::SpacedInput; + +const BASIS: CheckBasis = CheckBasis::Mpfr; +const GEN_KIND: GeneratorKind = GeneratorKind::Extensive; /// Run the extensive test suite. pub fn run() { @@ -62,10 +67,10 @@ fn register_all_tests() -> Vec { fn register_single_test(all: &mut Vec) where Op: MathOp + MpOp, - Op::RustArgs: ExtensiveInput + Send, + Op::RustArgs: SpacedInput + Send, { let test_name = format!("mp_extensive_{}", Op::NAME); - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GEN_KIND); let skip = skip_extensive_test(&ctx); let runner = move || { @@ -73,7 +78,7 @@ where panic!("extensive tests should be run with --release"); } - let res = run_single_test::(); + let res = run_single_test::(&ctx); let e = match res { Ok(()) => return Ok(()), Err(e) => e, @@ -91,18 +96,17 @@ where } /// Test runner for a signle routine. -fn run_single_test() -> TestResult +fn run_single_test(ctx: &CheckCtx) -> TestResult where Op: MathOp + MpOp, - Op::RustArgs: ExtensiveInput + Send, + Op::RustArgs: SpacedInput + Send, { // Small delay before printing anything so other output from the runner has a chance to flush. std::thread::sleep(Duration::from_millis(500)); eprintln!(); let completed = AtomicU64::new(0); - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); - let (ref mut cases, total) = extensive::get_test_cases::(&ctx); + let (ref mut cases, total) = spaced::get_test_cases::(ctx); let pb = Progress::new(Op::NAME, total); let test_single_chunk = |mp_vals: &mut Op::MpTy, input_vec: Vec| -> TestResult { @@ -110,7 +114,7 @@ where // Test the input. let mp_res = Op::run(mp_vals, input); let crate_res = input.call(Op::ROUTINE); - crate_res.validate(mp_res, input, &ctx)?; + crate_res.validate(mp_res, input, ctx)?; let completed = completed.fetch_add(1, Ordering::Relaxed) + 1; pb.update(completed, input); -- cgit 1.4.1-3-g733a5 From ecca4879a2eb69dda14611260c54c95c0b1df93e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 21:10:12 +0000 Subject: Adjust precision and add xfails based on new tests --- .../libm/crates/libm-test/src/precision.rs | 149 +++++++++++++++++++-- .../libm/src/math/support/float_traits.rs | 7 +- 2 files changed, 143 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 0b3fe89befd..3cb5e420f26 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -102,6 +102,15 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { } } + if cfg!(target_arch = "x86") { + match ctx.fn_ident { + // Input `fma(0.999999999999999, 1.0000000000000013, 0.0) = 1.0000000000000002` is + // incorrect on i586 and i686. + Id::Fma => ulp = 1, + _ => (), + } + } + // In some cases, our implementation is less accurate than musl on i586. if cfg!(x86_no_sse) { match ctx.fn_ident { @@ -370,59 +379,129 @@ fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Opt impl MaybeOverride<(f16, f16)> for SpecialCase { fn check_float( input: (f16, f16), - _actual: F, + actual: F, expected: F, _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - maybe_skip_binop_nan(input, expected, ctx) + binop_common(input, actual, expected, ctx) } } impl MaybeOverride<(f32, f32)> for SpecialCase { fn check_float( input: (f32, f32), - _actual: F, + actual: F, expected: F, _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - maybe_skip_binop_nan(input, expected, ctx) + if ctx.base_name == BaseName::Fmin + && input.0.biteq(f32::NEG_ZERO) + && input.1.biteq(f32::ZERO) + && expected.biteq(F::NEG_ZERO) + && actual.biteq(F::ZERO) + { + return XFAIL; + } + + binop_common(input, actual, expected, ctx) + } + + fn check_int( + _input: (f32, f32), + actual: I, + expected: I, + ctx: &CheckCtx, + ) -> Option { + remquo_common(actual, expected, ctx) } } impl MaybeOverride<(f64, f64)> for SpecialCase { fn check_float( input: (f64, f64), - _actual: F, + actual: F, expected: F, _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - maybe_skip_binop_nan(input, expected, ctx) + if ctx.base_name == BaseName::Fmin + && input.0.biteq(f64::NEG_ZERO) + && input.1.biteq(f64::ZERO) + && expected.biteq(F::ZERO) + && actual.biteq(F::NEG_ZERO) + { + return XFAIL; + } + + binop_common(input, actual, expected, ctx) + } + + fn check_int( + _input: (f64, f64), + actual: I, + expected: I, + ctx: &CheckCtx, + ) -> Option { + remquo_common(actual, expected, ctx) + } +} + +fn remquo_common(actual: I, expected: I, ctx: &CheckCtx) -> Option { + // FIXME: Our MPFR implementation disagrees with musl and may need to be updated. + if ctx.basis == CheckBasis::Mpfr + && ctx.base_name == BaseName::Remquo + && expected == I::MIN + && actual == I::ZERO + { + return XFAIL; } + + None } #[cfg(f128_enabled)] impl MaybeOverride<(f128, f128)> for SpecialCase { fn check_float( input: (f128, f128), - _actual: F, + actual: F, expected: F, _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - maybe_skip_binop_nan(input, expected, ctx) + binop_common(input, actual, expected, ctx) } } -/// Musl propagates NaNs if one is provided as the input, but we return the other input. // F1 and F2 are always the same type, this is just to please generics -fn maybe_skip_binop_nan( +fn binop_common( input: (F1, F1), + actual: F2, expected: F2, ctx: &CheckCtx, ) -> Option { + /* FIXME(#439): we do not compare signed zeros */ + + if ctx.base_name == BaseName::Fmin + && input.0.biteq(F1::NEG_ZERO) + && input.1.biteq(F1::ZERO) + && expected.biteq(F2::NEG_ZERO) + && actual.biteq(F2::ZERO) + { + return XFAIL; + } + + if ctx.base_name == BaseName::Fmax + && input.0.biteq(F1::NEG_ZERO) + && input.1.biteq(F1::ZERO) + && expected.biteq(F2::ZERO) + && actual.biteq(F2::NEG_ZERO) + { + return XFAIL; + } + + // Musl propagates NaNs if one is provided as the input, but we return the other input. match (&ctx.basis, ctx.base_name) { (Musl, BaseName::Fmin | BaseName::Fmax) if (input.0.is_nan() || input.1.is_nan()) && expected.is_nan() => @@ -509,7 +588,53 @@ fn bessel_prec_dropoff( None } -impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} -impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} impl MaybeOverride<(f32, i32)> for SpecialCase {} impl MaybeOverride<(f64, i32)> for SpecialCase {} + +impl MaybeOverride<(f32, f32, f32)> for SpecialCase { + fn check_float( + input: (f32, f32, f32), + actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + ternop_common(input, actual, expected, ctx) + } +} +impl MaybeOverride<(f64, f64, f64)> for SpecialCase { + fn check_float( + input: (f64, f64, f64), + actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + ternop_common(input, actual, expected, ctx) + } +} + +// F1 and F2 are always the same type, this is just to please generics +fn ternop_common( + input: (F1, F1, F1), + actual: F2, + expected: F2, + ctx: &CheckCtx, +) -> Option { + // FIXME(fma): 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result + // of fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the + // exact result". Our implementation returns the wrong sign: + // fma(5e-324, -5e-324, 0.0) = 0.0 (should be -0.0) + if ctx.base_name == BaseName::Fma + && (input.0.is_sign_negative() ^ input.1.is_sign_negative()) + && input.0 != F1::ZERO + && input.1 != F1::ZERO + && input.2.biteq(F1::ZERO) + && expected.biteq(F2::NEG_ZERO) + && actual.biteq(F2::ZERO) + { + return XFAIL; + } + + None +} diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 3aa0d844a72..647f4f5e251 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -93,9 +93,14 @@ pub trait Float: /// Returns true if the value is +inf or -inf. fn is_infinite(self) -> bool; - /// Returns true if the sign is negative. + /// Returns true if the sign is negative. Extracts the sign bit regardless of zero or NaN. fn is_sign_negative(self) -> bool; + /// Returns true if the sign is positive. Extracts the sign bit regardless of zero or NaN. + fn is_sign_positive(self) -> bool { + !self.is_sign_negative() + } + /// Returns if `self` is subnormal fn is_subnormal(self) -> bool { (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO -- cgit 1.4.1-3-g733a5 From 17c86e4e7fea6a245641f576a48aeaf362f562ef Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 22:48:03 +0000 Subject: Increase the CI timeout --- library/compiler-builtins/libm/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 40b67c4c251..99a32a82ec1 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -14,7 +14,7 @@ env: jobs: test: name: Build and test - timeout-minutes: 25 + timeout-minutes: 40 strategy: fail-fast: false matrix: -- cgit 1.4.1-3-g733a5 From f56b41dbbdc660f303e0946c50be8989e3657689 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 07:30:51 +0000 Subject: Provide a way to override iteration count Benchmarks need a way to limit how many iterations get run. Introuce a way to inject this information here. --- .../libm/crates/libm-test/src/run_cfg.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 6763de8bcc8..3e91101f6ca 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -40,6 +40,8 @@ pub struct CheckCtx { /// Source of truth for tests. pub basis: CheckBasis, pub gen_kind: GeneratorKind, + /// If specified, this value will override the value returned by [`iteration_count`]. + pub override_iterations: Option, } impl CheckCtx { @@ -53,6 +55,7 @@ impl CheckCtx { base_name_str: fn_ident.base_name().as_str(), basis, gen_kind, + override_iterations: None, }; ret.ulp = crate::default_ulp(&ret); ret @@ -62,6 +65,10 @@ impl CheckCtx { pub fn input_count(&self) -> usize { self.fn_ident.math_op().rust_sig.args.len() } + + pub fn override_iterations(&mut self, count: u64) { + self.override_iterations = Some(count) + } } /// Possible items to test against @@ -71,6 +78,8 @@ pub enum CheckBasis { Musl, /// Check against infinite precision (MPFR). Mpfr, + /// Benchmarks or other times when this is not relevant. + None, } /// The different kinds of generators that provide test input, which account for input pattern @@ -216,6 +225,12 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { total_iterations = 800; } + let mut overridden = false; + if let Some(count) = ctx.override_iterations { + total_iterations = count; + overridden = true; + } + // Adjust for the number of inputs let ntests = match t_env.input_count { 1 => total_iterations, @@ -223,6 +238,7 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { 3 => (total_iterations as f64).cbrt().ceil() as u64, _ => panic!("test has more than three arguments"), }; + let total = ntests.pow(t_env.input_count.try_into().unwrap()); let seed_msg = match ctx.gen_kind { @@ -235,12 +251,13 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { test_log(&format!( "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {ntests} iterations \ - ({total} total){seed_msg}", + ({total} total){seed_msg}{omsg}", gen_kind = ctx.gen_kind, basis = ctx.basis, fn_ident = ctx.fn_ident, arg = argnum + 1, args = t_env.input_count, + omsg = if overridden { " (overridden)" } else { "" } )); ntests -- cgit 1.4.1-3-g733a5 From 490ebbb187ff309db6599eb1616b100114dc834d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 07:30:38 +0000 Subject: Add benchmarks using iai-callgrind Running walltime benchmarks in CI is notoriously unstable, Introduce benchmarks that instead use instruction count and other more reproducible metrics, using `iai-callgrind` [1], which we are able to run in CI with a high degree of reproducibility. Inputs to this benchmark are a logspace sweep, which gives an approximation for real-world use, but may fail to indicate outlier cases. [1]: https://github.com/iai-callgrind/iai-callgrind --- library/compiler-builtins/libm/Cargo.toml | 4 + .../libm/crates/libm-test/Cargo.toml | 9 ++ .../libm/crates/libm-test/benches/icount.rs | 175 +++++++++++++++++++++ .../libm/crates/libm-test/src/lib.rs | 3 +- .../libm/crates/libm-test/src/op.rs | 2 + 5 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/benches/icount.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index f84f3eac6a4..18d89997dcb 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -73,3 +73,7 @@ debug-assertions = true inherits = "release" lto = "fat" overflow-checks = true + +[profile.bench] +# Required for iai-callgrind +debug = true diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index d3f18ab3e5b..3a1ba87962a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -20,6 +20,9 @@ build-musl = ["dep:musl-math-sys"] # Enable report generation without bringing in more dependencies by default benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] +# Enable icount benchmarks (requires iai-callgrind and valgrind) +icount = ["dep:iai-callgrind"] + # Run with a reduced set of benchmarks, such as for CI short-benchmarks = [] @@ -27,6 +30,7 @@ short-benchmarks = [] anyhow = "1.0.90" az = { version = "1.2.1", optional = true } gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false, features = ["mpfr"] } +iai-callgrind = { version = "0.14.0", optional = true } indicatif = { version = "0.17.9", default-features = false } libm = { path = "../..", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } @@ -48,6 +52,11 @@ rand = { version = "0.8.5", optional = true } criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } libtest-mimic = "0.8.1" +[[bench]] +name = "icount" +harness = false +required-features = ["icount"] + [[bench]] name = "random" harness = false diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs new file mode 100644 index 00000000000..3a66249e85d --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -0,0 +1,175 @@ +//! Benchmarks that use `iai-cachegrind` to be reasonably CI-stable. + +use std::hint::black_box; + +use iai_callgrind::{library_benchmark, library_benchmark_group, main}; +use libm_test::gen::spaced; +use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, OpRustArgs, TupleCall, op}; + +const BENCH_ITER_ITEMS: u64 = 500; + +macro_rules! icount_benches { + ( + fn_name: $fn_name:ident, + attrs: [$($_attr:meta),*], + ) => { + paste::paste! { + // Construct benchmark inputs from the logspace generator. + fn [< setup_ $fn_name >]() -> Vec> { + type Op = op::$fn_name::Routine; + let mut ctx = CheckCtx::new( + Op::IDENTIFIER, + CheckBasis::None, + GeneratorKind::QuickSpaced + ); + ctx.override_iterations(BENCH_ITER_ITEMS); + let ret = spaced::get_test_cases::(&ctx).0.collect::>(); + println!("operation {}, {} steps", Op::NAME, ret.len()); + ret + } + + // Run benchmarks with the above inputs. + #[library_benchmark] + #[bench::logspace([< setup_ $fn_name >]())] + fn [< icount_bench_ $fn_name >](cases: Vec>) { + type Op = op::$fn_name::Routine; + let f = black_box(Op::ROUTINE); + for input in cases.iter().copied() { + input.call(f); + } + } + + library_benchmark_group!( + name = [< icount_bench_ $fn_name _group >]; + benchmarks = [< icount_bench_ $fn_name >] + ); + } + }; +} + +libm_macros::for_each_function! { + callback: icount_benches, +} + +main!( + library_benchmark_groups = icount_bench_acos_group, + icount_bench_acosf_group, + icount_bench_acosh_group, + icount_bench_acoshf_group, + icount_bench_asin_group, + icount_bench_asinf_group, + icount_bench_asinh_group, + icount_bench_asinhf_group, + icount_bench_atan2_group, + icount_bench_atan2f_group, + icount_bench_atan_group, + icount_bench_atanf_group, + icount_bench_atanh_group, + icount_bench_atanhf_group, + icount_bench_cbrt_group, + icount_bench_cbrtf_group, + icount_bench_ceil_group, + icount_bench_ceilf_group, + icount_bench_copysign_group, + icount_bench_copysignf128_group, + icount_bench_copysignf16_group, + icount_bench_copysignf_group, + icount_bench_cos_group, + icount_bench_cosf_group, + icount_bench_cosh_group, + icount_bench_coshf_group, + icount_bench_erf_group, + icount_bench_erfc_group, + icount_bench_erfcf_group, + icount_bench_erff_group, + icount_bench_exp10_group, + icount_bench_exp10f_group, + icount_bench_exp2_group, + icount_bench_exp2f_group, + icount_bench_exp_group, + icount_bench_expf_group, + icount_bench_expm1_group, + icount_bench_expm1f_group, + icount_bench_fabs_group, + icount_bench_fabsf128_group, + icount_bench_fabsf16_group, + icount_bench_fabsf_group, + icount_bench_fdim_group, + icount_bench_fdimf128_group, + icount_bench_fdimf16_group, + icount_bench_fdimf_group, + icount_bench_floor_group, + icount_bench_floorf_group, + icount_bench_fma_group, + icount_bench_fmaf_group, + icount_bench_fmax_group, + icount_bench_fmaxf_group, + icount_bench_fmin_group, + icount_bench_fminf_group, + icount_bench_fmod_group, + icount_bench_fmodf_group, + icount_bench_frexp_group, + icount_bench_frexpf_group, + icount_bench_hypot_group, + icount_bench_hypotf_group, + icount_bench_ilogb_group, + icount_bench_ilogbf_group, + icount_bench_j0_group, + icount_bench_j0f_group, + icount_bench_j1_group, + icount_bench_j1f_group, + icount_bench_jn_group, + icount_bench_jnf_group, + icount_bench_ldexp_group, + icount_bench_ldexpf_group, + icount_bench_lgamma_group, + icount_bench_lgamma_r_group, + icount_bench_lgammaf_group, + icount_bench_lgammaf_r_group, + icount_bench_log10_group, + icount_bench_log10f_group, + icount_bench_log1p_group, + icount_bench_log1pf_group, + icount_bench_log2_group, + icount_bench_log2f_group, + icount_bench_log_group, + icount_bench_logf_group, + icount_bench_modf_group, + icount_bench_modff_group, + icount_bench_nextafter_group, + icount_bench_nextafterf_group, + icount_bench_pow_group, + icount_bench_powf_group, + icount_bench_remainder_group, + icount_bench_remainderf_group, + icount_bench_remquo_group, + icount_bench_remquof_group, + icount_bench_rint_group, + icount_bench_rintf_group, + icount_bench_round_group, + icount_bench_roundf_group, + icount_bench_scalbn_group, + icount_bench_scalbnf_group, + icount_bench_sin_group, + icount_bench_sinf_group, + icount_bench_sinh_group, + icount_bench_sinhf_group, + icount_bench_sqrt_group, + icount_bench_sqrtf_group, + icount_bench_tan_group, + icount_bench_tanf_group, + icount_bench_tanh_group, + icount_bench_tanhf_group, + icount_bench_tgamma_group, + icount_bench_tgammaf_group, + icount_bench_trunc_group, + icount_bench_truncf128_group, + icount_bench_truncf16_group, + icount_bench_truncf_group, + icount_bench_y0_group, + icount_bench_y0f_group, + icount_bench_y1_group, + icount_bench_y1f_group, + icount_bench_yn_group, + icount_bench_ynf_group, +); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index cb89f1c8ba7..b90423c1bac 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -24,7 +24,8 @@ pub use f8_impl::f8; pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, linear_ints, logspace}; pub use op::{ - BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustFn, OpRustRet, Ty, + BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustArgs, OpRustFn, OpRustRet, + Ty, }; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; use run_cfg::EXTENSIVE_MAX_ITERATIONS; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index 8329d3424c3..239c9a3e1fd 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -100,6 +100,8 @@ pub type OpCFn = ::CFn; pub type OpCRet = ::CRet; /// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types). pub type OpRustFn = ::RustFn; +/// Access the associated `RustArgs` type from an op (helper to avoid ambiguous associated types). +pub type OpRustArgs = ::RustArgs; /// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). pub type OpRustRet = ::RustRet; -- cgit 1.4.1-3-g733a5 From cdb1e680e03bf1ec9330c0951a8ee328f6a272b6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 07:31:34 +0000 Subject: Run iai-callgrind benchmarks in CI Add support in `ci-util.py` for finding the most recent baseline and downloading it, which new tests can then be compared against. Arbitrarily select nightly-2025-01-16 as the rustc version to pin to in benchmarks. --- .../libm/.github/workflows/main.yaml | 58 +++++++- library/compiler-builtins/libm/ci/ci-util.py | 159 ++++++++++++++++++++- 2 files changed, 207 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 99a32a82ec1..9face93110b 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -10,6 +10,7 @@ env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings RUST_BACKTRACE: full + BENCHMARK_RUSTC: nightly-2025-01-16 # Pin the toolchain for reproducable results jobs: test: @@ -147,19 +148,70 @@ jobs: benchmarks: name: Benchmarks runs-on: ubuntu-24.04 + timeout-minutes: 20 steps: - uses: actions/checkout@master - - name: Install Rust - run: rustup update nightly --no-self-update && rustup default nightly + - uses: taiki-e/install-action@cargo-binstall + + - name: Set up dependencies + run: | + rustup update "$BENCHMARK_RUSTC" --no-self-update + rustup default "$BENCHMARK_RUSTC" + # Install the version of iai-callgrind-runner that is specified in Cargo.toml + iai_version="$(cargo metadata --format-version=1 --features icount | + jq -r '.packages[] | select(.name == "iai-callgrind").version')" + cargo binstall -y iai-callgrind-runner --version "$iai_version" + sudo apt-get install valgrind + - uses: Swatinem/rust-cache@v2 - name: Download musl source run: ./ci/download-musl.sh - - run: | + + - name: Run icount benchmarks + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -eux + iai_home="iai-home" + # Download the baseline from master + ./ci/ci-util.py locate-baseline --download --extract + + # Run iai-callgrind benchmarks + cargo bench --no-default-features \ + --features unstable,unstable-float,icount \ + --bench icount \ + -- \ + --save-baseline=default \ + --home "$(pwd)/$iai_home" \ + --regression='ir=5.0' \ + --save-summary + # NB: iai-callgrind should exit on error but does not, so we inspect the sumary + # for errors. See https://github.com/iai-callgrind/iai-callgrind/issues/337 + ./ci/ci-util.py check-regressions "$iai_home" + + # Name and tar the new baseline + name="baseline-icount-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}" + echo "BASELINE_NAME=$name" >> "$GITHUB_ENV" + tar cJf "$name.tar.xz" "$iai_home" + + - name: Upload the benchmark baseline + uses: actions/upload-artifact@v4 + with: + name: ${{ env.BASELINE_NAME }} + path: ${{ env.BASELINE_NAME }}.tar.xz + + - name: Run wall time benchmarks + run: | # Always use the same seed for benchmarks. Ideally we should switch to a # non-random generator. export LIBM_SEED=benchesbenchesbenchesbencheswoo! cargo bench --all --features libm-test/short-benchmarks,libm-test/build-musl + - name: Print test logs if available + if: always() + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + msrv: name: Check MSRV runs-on: ubuntu-24.04 diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index 733ec26fa33..1ec69b002ae 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -9,6 +9,7 @@ import json import subprocess as sp import sys from dataclasses import dataclass +from glob import glob, iglob from inspect import cleandoc from os import getenv from pathlib import Path @@ -18,16 +19,33 @@ USAGE = cleandoc( """ usage: - ./ci/ci-util.py + ./ci/ci-util.py [flags] - SUBCOMMAND: - generate-matrix Calculate a matrix of which functions had source change, - print that as JSON object. + COMMAND: + generate-matrix + Calculate a matrix of which functions had source change, print that as + a JSON object. + + locate-baseline [--download] [--extract] + Locate the most recent benchmark baseline available in CI and, if flags + specify, download and extract it. Never exits with nonzero status if + downloading fails. + + Note that `--extract` will overwrite files in `iai-home`. + + check-regressions [iai-home] + Check `iai-home` (or `iai-home` if unspecified) for `summary.json` + files and see if there are any regressions. This is used as a workaround + for `iai-callgrind` not exiting with error status; see + . """ ) REPO_ROOT = Path(__file__).parent.parent GIT = ["git", "-C", REPO_ROOT] +DEFAULT_BRANCH = "master" +WORKFLOW_NAME = "CI" # Workflow that generates the benchmark artifacts +ARTIFACT_GLOB = "baseline-icount*" # Don't run exhaustive tests if these files change, even if they contaiin a function # definition. @@ -40,6 +58,11 @@ IGNORE_FILES = [ TYPES = ["f16", "f32", "f64", "f128"] +def eprint(*args, **kwargs): + """Print to stderr.""" + print(*args, file=sys.stderr, **kwargs) + + class FunctionDef(TypedDict): """Type for an entry in `function-definitions.json`""" @@ -145,9 +168,125 @@ class Context: return output -def eprint(*args, **kwargs): - """Print to stderr.""" - print(*args, file=sys.stderr, **kwargs) +def locate_baseline(flags: list[str]) -> None: + """Find the most recent baseline from CI, download it if specified. + + This returns rather than erroring, even if the `gh` commands fail. This is to avoid + erroring in CI if the baseline is unavailable (artifact time limit exceeded, first + run on the branch, etc). + """ + + download = False + extract = False + + while len(flags) > 0: + match flags[0]: + case "--download": + download = True + case "--extract": + extract = True + case _: + eprint(USAGE) + exit(1) + flags = flags[1:] + + if extract and not download: + eprint("cannot extract without downloading") + exit(1) + + try: + # Locate the most recent job to complete with success on our branch + latest_job = sp.check_output( + [ + "gh", + "run", + "list", + "--limit=1", + "--status=success", + f"--branch={DEFAULT_BRANCH}", + "--json=databaseId,url,headSha,conclusion,createdAt," + "status,workflowDatabaseId,workflowName", + f'--jq=select(.[].workflowName == "{WORKFLOW_NAME}")', + ], + text=True, + ) + eprint(f"latest: '{latest_job}'") + except sp.CalledProcessError as e: + eprint(f"failed to run github command: {e}") + return + + try: + latest = json.loads(latest_job)[0] + eprint("latest job: ", json.dumps(latest, indent=4)) + except json.JSONDecodeError as e: + eprint(f"failed to decode json '{latest_job}', {e}") + return + + if not download: + eprint("--download not specified, returning") + return + + job_id = latest.get("databaseId") + if job_id is None: + eprint("skipping download step") + return + + sp.run( + ["gh", "run", "download", str(job_id), f"--pattern={ARTIFACT_GLOB}"], + check=False, + ) + + if not extract: + eprint("skipping extraction step") + return + + # Find the baseline with the most recent timestamp. GH downloads the files to e.g. + # `some-dirname/some-dirname.tar.xz`, so just glob the whole thing together. + candidate_baselines = glob(f"{ARTIFACT_GLOB}/{ARTIFACT_GLOB}") + if len(candidate_baselines) == 0: + eprint("no possible baseline directories found") + return + + candidate_baselines.sort(reverse=True) + baseline_archive = candidate_baselines[0] + eprint(f"extracting {baseline_archive}") + sp.run(["tar", "xJvf", baseline_archive], check=True) + eprint("baseline extracted successfully") + + +def check_iai_regressions(iai_home: str | None | Path): + """Find regressions in iai summary.json files, exit with failure if any are + found. + """ + if iai_home is None: + iai_home = "iai-home" + iai_home = Path(iai_home) + + found_summaries = False + regressions = [] + for summary_path in iglob("**/summary.json", root_dir=iai_home, recursive=True): + found_summaries = True + with open(iai_home / summary_path, "r") as f: + summary = json.load(f) + + summary_regs = [] + run = summary["callgrind_summary"]["callgrind_run"] + name_entry = {"name": f"{summary["function_name"]}.{summary["id"]}"} + + for segment in run["segments"]: + summary_regs.extend(segment["regressions"]) + + summary_regs.extend(run["total"]["regressions"]) + + regressions.extend(name_entry | reg for reg in summary_regs) + + if not found_summaries: + eprint(f"did not find any summary.json files within {iai_home}") + exit(1) + + if len(regressions) > 0: + eprint("Found regressions:", json.dumps(regressions, indent=4)) + exit(1) def main(): @@ -156,6 +295,12 @@ def main(): ctx = Context() output = ctx.make_workflow_output() print(f"matrix={output}") + case ["locate-baseline", *flags]: + locate_baseline(flags) + case ["check-regressions"]: + check_iai_regressions(None) + case ["check-regressions", iai_home]: + check_iai_regressions(iai_home) case ["--help" | "-h"]: print(USAGE) exit() -- cgit 1.4.1-3-g733a5 From 5139ba6f46923dc673a7449c09d396cba2a6eba6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 07:31:07 +0000 Subject: Reduce the warm up and measurement time for `short-benchmarks` The icount benchmarks are what we will be relying on in CI more than the existing benchmarks. There isn't much reason to keep these around, but there isn't much point in dropping them either. So, just reduce the runtime. --- library/compiler-builtins/libm/crates/libm-test/benches/random.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index dcc7c1acac3..88816126510 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -151,8 +151,8 @@ pub fn musl_random() { // about the same time as other tests. if cfg!(feature = "short-benchmarks") { criterion = criterion - .warm_up_time(Duration::from_millis(500)) - .measurement_time(Duration::from_millis(1000)); + .warm_up_time(Duration::from_millis(200)) + .measurement_time(Duration::from_millis(600)); } criterion = criterion.configure_from_args(); -- cgit 1.4.1-3-g733a5 From 3986206ce0f601d747953333bc82b836820443e9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 09:47:00 +0000 Subject: Add an xfail for recent ynf failures This failed a couple of times recently in CI, once on i686 and once on aarch64-apple: thread 'main' panicked at crates/libm-test/benches/random.rs:76:65: called `Result::unwrap()` on an `Err` value: ynf Caused by: 0: input: (681, 509.90924) (0x000002a9, 0x43fef462) expected: -3.2161271e38 0xff71f45b actual: -inf 0xff800000 1: mismatched infinities thread 'main' panicked at crates/libm-test/benches/random.rs:76:65: called `Result::unwrap()` on an `Err` value: ynf Caused by: 0: input: (132, 50.46604) (0x00000084, 0x4249dd3a) expected: -3.3364996e38 0xff7b02a5 actual: -inf 0xff800000 1: mismatched infinities Add a new override to account for this. --- .../libm/crates/libm-test/src/precision.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 3cb5e420f26..9d17ab8cccf 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -4,6 +4,7 @@ use core::f32; use CheckBasis::{Mpfr, Musl}; +use libm::support::CastFrom; use {BaseName as Bn, Identifier as Id}; use crate::{BaseName, CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; @@ -524,7 +525,7 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { ctx: &CheckCtx, ) -> Option { match (&ctx.basis, ctx.base_name) { - (Musl, _) => bessel_prec_dropoff(input, ulp, ctx), + (Musl, _) => bessel_prec_dropoff(input, actual, expected, ulp, ctx), // We return +0.0, MPFR returns -0.0 (Mpfr, BaseName::Jn | BaseName::Yn) @@ -554,7 +555,7 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { ctx: &CheckCtx, ) -> Option { match (&ctx.basis, ctx.base_name) { - (Musl, _) => bessel_prec_dropoff(input, ulp, ctx), + (Musl, _) => bessel_prec_dropoff(input, actual, expected, ulp, ctx), // We return +0.0, MPFR returns -0.0 (Mpfr, BaseName::Jn | BaseName::Yn) @@ -569,8 +570,10 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { } /// Our bessel functions blow up with large N values -fn bessel_prec_dropoff( - input: (i32, F), +fn bessel_prec_dropoff( + input: (i32, F1), + actual: F2, + expected: F2, ulp: &mut u32, ctx: &CheckCtx, ) -> Option { @@ -585,6 +588,17 @@ fn bessel_prec_dropoff( } } + // Values near infinity sometimes get cut off for us. `ynf(681, 509.90924) = -inf` but should + // be -3.2161271e38. + if ctx.fn_ident == Identifier::Ynf + && !expected.is_infinite() + && actual.is_infinite() + && (expected.abs().to_bits().abs_diff(actual.abs().to_bits()) + < F2::Int::cast_from(1_000_000u32)) + { + return XFAIL; + } + None } -- cgit 1.4.1-3-g733a5 From f39af6cb976ce8e3bd92ae543c21a5f6527081e2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 20:30:47 +0000 Subject: Remove the limit for querying a baseline `--limit=1` seems to apply before `jq` filtering, meaning our `WORKFLOW_NAME` ("CI") workflow may not appear in the input to the jq query. Removing `--limit` provides a default amount of inputs that jq can then filter from, so this works better. --- library/compiler-builtins/libm/ci/ci-util.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index 1ec69b002ae..7a9f1bd2bbe 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -201,22 +201,24 @@ def locate_baseline(flags: list[str]) -> None: "gh", "run", "list", - "--limit=1", "--status=success", f"--branch={DEFAULT_BRANCH}", "--json=databaseId,url,headSha,conclusion,createdAt," "status,workflowDatabaseId,workflowName", - f'--jq=select(.[].workflowName == "{WORKFLOW_NAME}")', + # Return the first array element matching our workflow name. NB: cannot + # just use `--limit=1`, jq filtering happens after limiting. We also + # cannot just use `--workflow` because GH gets confused from + # different file names in history. + f'--jq=[.[] | select(.workflowName == "{WORKFLOW_NAME}")][0]', ], text=True, ) - eprint(f"latest: '{latest_job}'") except sp.CalledProcessError as e: eprint(f"failed to run github command: {e}") return try: - latest = json.loads(latest_job)[0] + latest = json.loads(latest_job) eprint("latest job: ", json.dumps(latest, indent=4)) except json.JSONDecodeError as e: eprint(f"failed to decode json '{latest_job}', {e}") -- cgit 1.4.1-3-g733a5 From f9041943f1c5c2cc83b0c781ff0b48ba6301927f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 19:50:29 +0000 Subject: Switch to the arm-linux runner and enable MPFR The free arm64 Linux runners are now available [1]. Switch to using this image in CI, and enable tests against MPFR since this is now a native platform. [1]: https://github.blog/changelog/2025-01-16-linux-arm64-hosted-runners-now-available-for-free-in-public-repositories-public-preview/ --- library/compiler-builtins/libm/.github/workflows/main.yaml | 2 +- library/compiler-builtins/libm/ci/run.sh | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 9face93110b..8c0ff237d2f 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -23,7 +23,7 @@ jobs: - target: aarch64-apple-darwin os: macos-15 - target: aarch64-unknown-linux-gnu - os: ubuntu-24.04 + os: ubuntu-24.04-arm - target: aarch64-pc-windows-msvc os: windows-2025 build_only: 1 # Can't run on x86 hosts diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index bb749b72ad3..6b2f07ab283 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -49,14 +49,12 @@ case "$target" in *windows-msvc*) ;; # FIXME: MinGW should be able to build MPFR, but setup in CI is nontrivial. *windows-gnu*) ;; - # Targets that aren't cross compiled work fine - # FIXME(ci): we should be able to enable aarch64 Linux here once GHA - # support rolls out. - x86_64*) flags="$flags --features libm-test/build-mpfr" ;; - i686*) flags="$flags --features libm-test/build-mpfr" ;; - i586*) flags="$flags --features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross" ;; - # Apple aarch64 is native + # Targets that aren't cross compiled in CI work fine aarch64*apple*) flags="$flags --features libm-test/build-mpfr" ;; + aarch64*linux*) flags="$flags --features libm-test/build-mpfr" ;; + i586*) flags="$flags --features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross" ;; + i686*) flags="$flags --features libm-test/build-mpfr" ;; + x86_64*) flags="$flags --features libm-test/build-mpfr" ;; esac # FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. -- cgit 1.4.1-3-g733a5 From ba0cfe58dd1fc460cbbe5d61f2aa3650d05ec16b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 Jan 2025 07:44:13 +0000 Subject: Run icount benchmarks once with softfloat and once with hardfloat These benchmarks are fast to run, so the time cost here is pretty minimal. Running softfloat benchmarks just ensures that we don't e.g. test the performance of `_mm_sqrt_ss` rather than our implementation, and running without softfloat gives us a way to see the effect of arch intrinsics. --- .../libm/.github/workflows/main.yaml | 24 +--------- library/compiler-builtins/libm/ci/bench-icount.sh | 53 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 23 deletions(-) create mode 100755 library/compiler-builtins/libm/ci/bench-icount.sh diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 8c0ff237d2f..f9d3a5a159c 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -170,29 +170,7 @@ jobs: - name: Run icount benchmarks env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - set -eux - iai_home="iai-home" - # Download the baseline from master - ./ci/ci-util.py locate-baseline --download --extract - - # Run iai-callgrind benchmarks - cargo bench --no-default-features \ - --features unstable,unstable-float,icount \ - --bench icount \ - -- \ - --save-baseline=default \ - --home "$(pwd)/$iai_home" \ - --regression='ir=5.0' \ - --save-summary - # NB: iai-callgrind should exit on error but does not, so we inspect the sumary - # for errors. See https://github.com/iai-callgrind/iai-callgrind/issues/337 - ./ci/ci-util.py check-regressions "$iai_home" - - # Name and tar the new baseline - name="baseline-icount-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}" - echo "BASELINE_NAME=$name" >> "$GITHUB_ENV" - tar cJf "$name.tar.xz" "$iai_home" + run: ./ci/bench-icount.sh - name: Upload the benchmark baseline uses: actions/upload-artifact@v4 diff --git a/library/compiler-builtins/libm/ci/bench-icount.sh b/library/compiler-builtins/libm/ci/bench-icount.sh new file mode 100755 index 00000000000..40b3ac95c7b --- /dev/null +++ b/library/compiler-builtins/libm/ci/bench-icount.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +set -eux + +iai_home="iai-home" + +# Download the baseline from master +./ci/ci-util.py locate-baseline --download --extract + +# Run benchmarks once +function run_icount_benchmarks() { + cargo_args=( + "--bench" "icount" + "--no-default-features" + "--features" "unstable,unstable-float,icount" + ) + + iai_args=( + "--home" "$(pwd)/$iai_home" + "--regression=ir=5.0" + "--save-summary" + ) + + # Parse `cargo_arg0 cargo_arg1 -- iai_arg0 iai_arg1` syntax + parsing_iai_args=0 + while [ "$#" -gt 0 ]; do + if [ "$parsing_iai_args" == "1" ]; then + iai_args+=("$1") + elif [ "$1" == "--" ]; then + parsing_iai_args=1 + else + cargo_args+=("$1") + fi + + shift + done + + # Run iai-callgrind benchmarks + cargo bench "${cargo_args[@]}" -- "${iai_args[@]}" + + # NB: iai-callgrind should exit on error but does not, so we inspect the sumary + # for errors. See https://github.com/iai-callgrind/iai-callgrind/issues/337 + ./ci/ci-util.py check-regressions --home "$iai_home" || true +} + +# Run once with softfloats, once with arch instructions enabled +run_icount_benchmarks --features force-soft-floats -- --save-baseline=softfloat +run_icount_benchmarks -- --save-baseline=hardfloat + +# Name and tar the new baseline +name="baseline-icount-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}" +echo "BASELINE_NAME=$name" >>"$GITHUB_ENV" +tar cJf "$name.tar.xz" "$iai_home" -- cgit 1.4.1-3-g733a5 From c5dc1b8ca027d04245c2b68427f7f42e11c36e33 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 Jan 2025 07:45:44 +0000 Subject: Run wall time benchmarks with `--features force-soft-floats` Similar to changes for `icount` benchmarks, this ensures we aren't testing the throughput of architecture instructions. --- library/compiler-builtins/libm/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index f9d3a5a159c..f019c73f834 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -183,7 +183,7 @@ jobs: # Always use the same seed for benchmarks. Ideally we should switch to a # non-random generator. export LIBM_SEED=benchesbenchesbenchesbencheswoo! - cargo bench --all --features libm-test/short-benchmarks,libm-test/build-musl + cargo bench --all --features short-benchmarks,build-musl,force-soft-floats - name: Print test logs if available if: always() -- cgit 1.4.1-3-g733a5 From d3328a0dab30f5be9d896f38c87ac9824a52245b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 Jan 2025 07:47:41 +0000 Subject: Add a way to ignore benchmark regression checks Introduce a way to ignore the results of icount regression tests, by specifying `allow-regressions` in the pull request body. This should apply to both pull requests and the merges based on them, since `gh pr view` automatically handles both. --- .../libm/.github/workflows/main.yaml | 1 + library/compiler-builtins/libm/ci/bench-icount.sh | 7 ++- library/compiler-builtins/libm/ci/ci-util.py | 63 ++++++++++++++++++---- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index f019c73f834..7693de6559a 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -170,6 +170,7 @@ jobs: - name: Run icount benchmarks env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} run: ./ci/bench-icount.sh - name: Upload the benchmark baseline diff --git a/library/compiler-builtins/libm/ci/bench-icount.sh b/library/compiler-builtins/libm/ci/bench-icount.sh index 40b3ac95c7b..3a2155f5011 100755 --- a/library/compiler-builtins/libm/ci/bench-icount.sh +++ b/library/compiler-builtins/libm/ci/bench-icount.sh @@ -40,7 +40,12 @@ function run_icount_benchmarks() { # NB: iai-callgrind should exit on error but does not, so we inspect the sumary # for errors. See https://github.com/iai-callgrind/iai-callgrind/issues/337 - ./ci/ci-util.py check-regressions --home "$iai_home" || true + if [ -n "${PR_NUMBER:-}" ]; then + # If this is for a pull request, ignore regressions if specified. + ./ci/ci-util.py check-regressions --home "$iai_home" --allow-pr-override "$PR_NUMBER" + else + ./ci/ci-util.py check-regressions --home "$iai_home" || true + fi } # Run once with softfloats, once with arch instructions enabled diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index 7a9f1bd2bbe..7464fd42595 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -33,11 +33,14 @@ USAGE = cleandoc( Note that `--extract` will overwrite files in `iai-home`. - check-regressions [iai-home] + check-regressions [--home iai-home] [--allow-pr-override pr_number] Check `iai-home` (or `iai-home` if unspecified) for `summary.json` files and see if there are any regressions. This is used as a workaround for `iai-callgrind` not exiting with error status; see . + + If `--allow-pr-override` is specified, the regression check will not exit + with failure if any line in the PR starts with `allow-regressions`. """ ) @@ -46,6 +49,8 @@ GIT = ["git", "-C", REPO_ROOT] DEFAULT_BRANCH = "master" WORKFLOW_NAME = "CI" # Workflow that generates the benchmark artifacts ARTIFACT_GLOB = "baseline-icount*" +# Place this in a PR body to skip regression checks (must be at the start of a line). +REGRESSION_DIRECTIVE = "ci: allow-regressions" # Don't run exhaustive tests if these files change, even if they contaiin a function # definition. @@ -256,12 +261,26 @@ def locate_baseline(flags: list[str]) -> None: eprint("baseline extracted successfully") -def check_iai_regressions(iai_home: str | None | Path): +def check_iai_regressions(args: list[str]): """Find regressions in iai summary.json files, exit with failure if any are found. """ - if iai_home is None: - iai_home = "iai-home" + + iai_home = "iai-home" + pr_number = False + + while len(args) > 0: + match args: + case ["--home", home, *rest]: + iai_home = home + args = rest + case ["--allow-pr-override", pr_num, *rest]: + pr_number = pr_num + args = rest + case _: + eprint(USAGE) + exit(1) + iai_home = Path(iai_home) found_summaries = False @@ -286,9 +305,33 @@ def check_iai_regressions(iai_home: str | None | Path): eprint(f"did not find any summary.json files within {iai_home}") exit(1) - if len(regressions) > 0: - eprint("Found regressions:", json.dumps(regressions, indent=4)) - exit(1) + if len(regressions) == 0: + eprint("No regressions found") + return + + eprint("Found regressions:", json.dumps(regressions, indent=4)) + + if pr_number is not None: + pr_info = sp.check_output( + [ + "gh", + "pr", + "view", + str(pr_number), + "--json=number,commits,body,createdAt", + "--jq=.commits |= map(.oid)", + ], + text=True, + ) + pr = json.loads(pr_info) + eprint("PR info:", json.dumps(pr, indent=4)) + + lines = pr["body"].splitlines() + if any(line.startswith(REGRESSION_DIRECTIVE) for line in lines): + eprint("PR allows regressions, returning") + return + + exit(1) def main(): @@ -299,10 +342,8 @@ def main(): print(f"matrix={output}") case ["locate-baseline", *flags]: locate_baseline(flags) - case ["check-regressions"]: - check_iai_regressions(None) - case ["check-regressions", iai_home]: - check_iai_regressions(iai_home) + case ["check-regressions", *args]: + check_iai_regressions(args) case ["--help" | "-h"]: print(USAGE) exit() -- cgit 1.4.1-3-g733a5 From e21618c73e9c1a05aa4d5c75a3d144960d43158b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 Jan 2025 07:52:26 +0000 Subject: Ignore files relevant to benchmarking --- library/compiler-builtins/libm/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/libm/.gitignore b/library/compiler-builtins/libm/.gitignore index 4e9c9c03ddf..a447c34cd0f 100644 --- a/library/compiler-builtins/libm/.gitignore +++ b/library/compiler-builtins/libm/.gitignore @@ -6,3 +6,7 @@ target Cargo.lock musl/ **.tar.gz + +# Benchmark cache +iai-home +baseline-* -- cgit 1.4.1-3-g733a5 From b3d57f8c28da068201f64b26243f962390fcf3c9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 00:58:33 +0000 Subject: Remove trailing whitespace in scripts, run JuliaFormatter --- library/compiler-builtins/libm/ci/bench-icount.sh | 2 +- library/compiler-builtins/libm/ci/run.sh | 4 +- .../libm/crates/libm-test/examples/plot_file.jl | 52 ++++++++++++++-------- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/library/compiler-builtins/libm/ci/bench-icount.sh b/library/compiler-builtins/libm/ci/bench-icount.sh index 3a2155f5011..4d93e257a6c 100755 --- a/library/compiler-builtins/libm/ci/bench-icount.sh +++ b/library/compiler-builtins/libm/ci/bench-icount.sh @@ -7,7 +7,7 @@ iai_home="iai-home" # Download the baseline from master ./ci/ci-util.py locate-baseline --download --extract -# Run benchmarks once +# Run benchmarks once function run_icount_benchmarks() { cargo_args=( "--bench" "icount" diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 6b2f07ab283..296986d9727 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -90,7 +90,7 @@ if [ "$nextest" = "1" ]; then echo "dir = \"$CARGO_TARGET_DIR/nextest\"" >> "$cfg_file" cfg_flag="--config-file $cfg_file" fi - + cmd="cargo nextest run ${cfg_flag:-} --max-fail=10 $flags" profile="--cargo-profile" fi @@ -111,7 +111,7 @@ $cmd --features unstable-intrinsics --benches # Test the same in release mode, which also increases coverage. Also ensure # the soft float routines are checked. -$cmd "$profile" release-checked +$cmd "$profile" release-checked $cmd "$profile" release-checked --features force-soft-floats $cmd "$profile" release-checked --features unstable-intrinsics $cmd "$profile" release-checked --features unstable-intrinsics --benches diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl b/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl index 14a128303c6..acffd97569f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl +++ b/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl @@ -13,7 +13,7 @@ using CairoMakie using TOML function main()::Nothing - CairoMakie.activate!(px_per_unit=10) + CairoMakie.activate!(px_per_unit = 10) config_path = ARGS[1] cfg = Dict() @@ -75,15 +75,25 @@ function plot_one( gen_x = map((v) -> parse(Float32, v), inputs) do_plot( - fig, gen_x, func, xlims[1], xlims[2], + fig, + gen_x, + func, + xlims[1], + xlims[2], "$fn_name $gen_name (linear scale)", - lin_out_file, false, + lin_out_file, + false, ) do_plot( - fig, gen_x, func, xlims_log[1], xlims_log[2], + fig, + gen_x, + func, + xlims_log[1], + xlims_log[2], "$fn_name $gen_name (log scale)", - log_out_file, true, + log_out_file, + true, ) end @@ -97,7 +107,7 @@ function do_plot( title::String, out_file::String, logscale::Bool, -)::Nothing where F<:AbstractFloat +)::Nothing where {F<:AbstractFloat} println("plotting $title") # `gen_x` is the values the generator produces. `actual_x` is for plotting a @@ -116,32 +126,36 @@ function do_plot( actual_x = LinRange(input_min, input_max, steps) xscale = identity end - + gen_y = @. func(gen_x) actual_y = @. func(actual_x) - ax = Axis(fig[1, 1], xscale=xscale, title=title) + ax = Axis(fig[1, 1], xscale = xscale, title = title) lines!( - ax, actual_x, actual_y, color=(:lightblue, 0.6), - linewidth=6.0, label="true function", + ax, + actual_x, + actual_y, + color = (:lightblue, 0.6), + linewidth = 6.0, + label = "true function", ) scatter!( - ax, gen_x, gen_y, color=(:darkblue, 0.9), - markersize=markersize, label="checked inputs", + ax, + gen_x, + gen_y, + color = (:darkblue, 0.9), + markersize = markersize, + label = "checked inputs", ) - axislegend(ax, position=:rb, framevisible=false) + axislegend(ax, position = :rb, framevisible = false) save(out_file, fig) delete!(ax) end "Apply a function, returning the default if there is a domain error" -function map_or( - input::AbstractFloat, - f::Function, - default::Any -)::Union{AbstractFloat,Any} +function map_or(input::AbstractFloat, f::Function, default::Any)::Union{AbstractFloat,Any} try return f(input) catch @@ -151,7 +165,7 @@ end # Operations for logarithms that are symmetric about 0 C = 10 -symlog10(x::Number) = sign(x) * (log10(1 + abs(x)/(10^C))) +symlog10(x::Number) = sign(x) * (log10(1 + abs(x) / (10^C))) sympow10(x::Number) = (10^C) * (10^x - 1) main() -- cgit 1.4.1-3-g733a5 From 6ac9c14933a363a4a31bc8425d63b68df1fce364 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 02:35:29 +0000 Subject: Add a retry to the musl download This download has occasionally been failing in CI recently. Add a retry so this is less likely to cause the workflow to fail. --- library/compiler-builtins/libm/ci/download-musl.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/ci/download-musl.sh b/library/compiler-builtins/libm/ci/download-musl.sh index 039e961575b..8a8c58550bb 100755 --- a/library/compiler-builtins/libm/ci/download-musl.sh +++ b/library/compiler-builtins/libm/ci/download-musl.sh @@ -7,7 +7,7 @@ fname=musl-1.2.5.tar.gz sha=a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4 mkdir musl -curl -L "https://musl.libc.org/releases/$fname" -O +curl -L "https://musl.libc.org/releases/$fname" -O --retry 5 case "$(uname -s)" in MINGW*) -- cgit 1.4.1-3-g733a5 From 9c98c461473a26354c519702d79a689dda7f9645 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 15 Jan 2025 11:34:17 +0000 Subject: Don't set `opt_level` in the musl build script `cc` automatically reads this from Cargo's `OPT_LEVEL` variable so we don't need to set it explicitly. Remove this so running in a debugger makes more sense. --- library/compiler-builtins/libm/crates/musl-math-sys/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs index 03deb4ff0ac..d75748159ca 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs +++ b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs @@ -151,7 +151,6 @@ fn build_musl_math(cfg: &Config) { .flag_if_supported("-ffreestanding") .flag_if_supported("-nostdinc") .define("_ALL_SOURCE", "1") - .opt_level(3) .define( "ROOT_INCLUDE_FEATURES", Some(musl_dir.join("include/features.h").to_str().unwrap()), -- cgit 1.4.1-3-g733a5 From 8927014e919b789ef957d82ed13eaebe33922e29 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 05:29:36 +0000 Subject: Enable `force-soft-floats` for extensive tests Any architecture-specific float operations are likely to consist of only a few instructions, but the softfloat implementations are much more complex. Ensure this is what gets tested. --- library/compiler-builtins/libm/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 7693de6559a..89c5facef44 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -270,7 +270,7 @@ jobs: fi LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \ - --features build-mpfr,unstable \ + --features build-mpfr,unstable,force-soft-floats \ --profile release-checked \ -- extensive - name: Print test logs if available -- cgit 1.4.1-3-g733a5 From 573ded2ee8a59d3f3bb2a56477fc939b0922cf44 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 11:45:40 +0000 Subject: Port the most recent version of Musl's `sqrt` as a generic algorithm Musl commit 97e9b73d59 ("math: new software sqrt") adds a new algorithm using Goldschmidt division. Port this algorithm to Rust and make it generic, which shows a notable performance improvement over the existing algorithm. This also allows adding square root routines for `f16` and `f128`. --- .../libm/etc/function-definitions.json | 2 + .../compiler-builtins/libm/src/math/generic/mod.rs | 2 + .../libm/src/math/generic/sqrt.rs | 419 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/sqrt.rs | 252 +------------ library/compiler-builtins/libm/src/math/sqrtf.rs | 133 +------ .../libm/src/math/support/int_traits.rs | 2 + .../libm/src/math/support/macros.rs | 22 +- .../compiler-builtins/libm/src/math/support/mod.rs | 11 + 8 files changed, 450 insertions(+), 393 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/sqrt.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index dbaac931c76..9f7c8ab25a0 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -704,6 +704,7 @@ "src/libm_helper.rs", "src/math/arch/i686.rs", "src/math/arch/wasm32.rs", + "src/math/generic/sqrt.rs", "src/math/sqrt.rs" ], "type": "f64" @@ -712,6 +713,7 @@ "sources": [ "src/math/arch/i686.rs", "src/math/arch/wasm32.rs", + "src/math/generic/sqrt.rs", "src/math/sqrtf.rs" ], "type": "f32" diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 2b068d6c54d..3b5a2c3effd 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -1,9 +1,11 @@ mod copysign; mod fabs; mod fdim; +mod sqrt; mod trunc; pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; +pub use sqrt::sqrt; pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs new file mode 100644 index 00000000000..a2e054f3cf2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -0,0 +1,419 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/sqrt.c. Ported to generic Rust algorithm in 2025, TG. */ + +//! Generic square root algorithm. +//! +//! This routine operates around `m_u2`, a U.2 (fixed point with two integral bits) mantissa +//! within the range [1, 4). A table lookup provides an initial estimate, then goldschmidt +//! iterations at various widths are used to approach the real values. +//! +//! For the iterations, `r` is a U0 number that approaches `1/sqrt(m_u2)`, and `s` is a U2 number +//! that approaches `sqrt(m_u2)`. Recall that m_u2 ∈ [1, 4). +//! +//! With Newton-Raphson iterations, this would be: +//! +//! - `w = r * r w ~ 1 / m` +//! - `u = 3 - m * w u ~ 3 - m * w = 3 - m / m = 2` +//! - `r = r * u / 2 r ~ r` +//! +//! (Note that the righthand column does not show anything analytically meaningful (i.e. r ~ r), +//! since the value of performing one iteration is in reducing the error representable by `~`). +//! +//! Instead of Newton-Raphson iterations, Goldschmidt iterations are used to calculate +//! `s = m * r`: +//! +//! - `s = m * r s ~ m / sqrt(m)` +//! - `u = 3 - s * r u ~ 3 - (m / sqrt(m)) * (1 / sqrt(m)) = 3 - m / m = 2` +//! - `r = r * u / 2 r ~ r` +//! - `s = s * u / 2 s ~ s` +//! +//! The above is precise because it uses the original value `m`. There is also a faster version +//! that performs fewer steps but does not use `m`: +//! +//! - `u = 3 - s * r u ~ 3 - 1` +//! - `r = r * u / 2 r ~ r` +//! - `s = s * u / 2 s ~ s` +//! +//! Rounding errors accumulate faster with the second version, so it is only used for subsequent +//! iterations within the same width integer. The first version is always used for the first +//! iteration at a new width in order to avoid this accumulation. +//! +//! Goldschmidt has the advantage over Newton-Raphson that `sqrt(x)` and `1/sqrt(x)` are +//! computed at the same time, i.e. there is no need to calculate `1/sqrt(x)` and invert it. + +use super::super::support::{IntTy, cold_path, raise_invalid}; +use super::super::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; + +pub fn sqrt(x: F) -> F +where + F: Float + SqrtHelper, + F::Int: HInt, + F::Int: From, + F::Int: From, + F::Int: CastInto, + F::Int: CastInto, + u32: CastInto, +{ + let zero = IntTy::::ZERO; + let one = IntTy::::ONE; + + let mut ix = x.to_bits(); + + // Top is the exponent and sign, which may or may not be shifted. If the float fits into a + // `u32`, we can get by without paying shifting costs. + let noshift = F::BITS <= u32::BITS; + let (mut top, special_case) = if noshift { + let exp_lsb = one << F::SIG_BITS; + let special_case = ix.wrapping_sub(exp_lsb) >= F::EXP_MASK - exp_lsb; + (Exp::NoShift(()), special_case) + } else { + let top = u32::cast_from(ix >> F::SIG_BITS); + let special_case = top.wrapping_sub(1) >= F::EXP_MAX - 1; + (Exp::Shifted(top), special_case) + }; + + // Handle NaN, zero, and out of domain (<= 0) + if special_case { + cold_path(); + + // +/-0 + if ix << 1 == zero { + return x; + } + + // Positive infinity + if ix == F::EXP_MASK { + return x; + } + + // NaN or negative + if ix > F::EXP_MASK { + return raise_invalid(x); + } + + // Normalize subnormals by multiplying by 1.0 << SIG_BITS (e.g. 0x1p52 for doubles). + let scaled = x * F::from_parts(false, (F::SIG_BITS + F::EXP_BIAS) as i32, zero); + ix = scaled.to_bits(); + match top { + Exp::Shifted(ref mut v) => { + *v = scaled.exp().unsigned(); + *v = (*v).wrapping_sub(F::SIG_BITS); + } + Exp::NoShift(()) => { + ix = ix.wrapping_sub((F::SIG_BITS << F::SIG_BITS).cast()); + } + } + } + + // Reduce arguments such that `x = 4^e * m`: + // + // - m_u2 ∈ [1, 4), a fixed point U2.BITS number + // - 2^e is the exponent part of the result + let (m_u2, exp) = match top { + Exp::Shifted(top) => { + // We now know `x` is positive, so `top` is just its (biased) exponent + let mut e = top; + // Construct a fixed point representation of the mantissa. + let mut m_u2 = (ix | F::IMPLICIT_BIT) << F::EXP_BITS; + let even = (e & 1) != 0; + if even { + m_u2 >>= 1; + } + e = (e.wrapping_add(F::EXP_MAX >> 1)) >> 1; + (m_u2, Exp::Shifted(e)) + } + Exp::NoShift(()) => { + let even = ix & (one << F::SIG_BITS) != zero; + + // Exponent part of the return value + let mut e_noshift = ix >> 1; + // ey &= (F::EXP_MASK << 2) >> 2; // clear the top exponent bit (result = 1.0) + e_noshift += (F::EXP_MASK ^ (F::SIGN_MASK >> 1)) >> 1; + e_noshift &= F::EXP_MASK; + + let m1 = (ix << F::EXP_BITS) | F::SIGN_MASK; + let m0 = (ix << (F::EXP_BITS - 1)) & !F::SIGN_MASK; + let m_u2 = if even { m0 } else { m1 }; + + (m_u2, Exp::NoShift(e_noshift)) + } + }; + + // Extract the top 6 bits of the significand with the lowest bit of the exponent. + let i = usize::cast_from(ix >> (F::SIG_BITS - 6)) & 0b1111111; + + // Start with an initial guess for `r = 1 / sqrt(m)` from the table, and shift `m` as an + // initial value for `s = sqrt(m)`. See the module documentation for details. + let r1_u0: F::ISet1 = F::ISet1::cast_from(RSQRT_TAB[i]) << (F::ISet1::BITS - 16); + let s1_u2: F::ISet1 = ((m_u2) >> (F::BITS - F::ISet1::BITS)).cast(); + + // Perform iterations, if any, at quarter width (used for `f128`). + let (r1_u0, _s1_u2) = goldschmidt::(r1_u0, s1_u2, F::SET1_ROUNDS, false); + + // Widen values and perform iterations at half width (used for `f64` and `f128`). + let r2_u0: F::ISet2 = F::ISet2::from(r1_u0) << (F::ISet2::BITS - F::ISet1::BITS); + let s2_u2: F::ISet2 = ((m_u2) >> (F::BITS - F::ISet2::BITS)).cast(); + let (r2_u0, _s2_u2) = goldschmidt::(r2_u0, s2_u2, F::SET2_ROUNDS, false); + + // Perform final iterations at full width (used for all float types). + let r_u0: F::Int = F::Int::from(r2_u0) << (F::BITS - F::ISet2::BITS); + let s_u2: F::Int = m_u2; + let (_r_u0, s_u2) = goldschmidt::(r_u0, s_u2, F::FINAL_ROUNDS, true); + + // Shift back to mantissa position. + let mut m = s_u2 >> (F::EXP_BITS - 2); + + // The musl source includes the following comment (with literals replaced): + // + // > s < sqrt(m) < s + 0x1.09p-SIG_BITS + // > compute nearest rounded result: the nearest result to SIG_BITS bits is either s or + // > s+0x1p-SIG_BITS, we can decide by comparing (2^SIG_BITS s + 0.5)^2 to 2^(2*SIG_BITS) m. + // + // Expanding this with , with `SIG_BITS = p` and adjusting based on the operations done to + // `d0` and `d1`: + // + // - `2^(2p)m ≟ ((2^p)m + 0.5)^2` + // - `2^(2p)m ≟ 2^(2p)m^2 + (2^p)m + 0.25` + // - `2^(2p)m - m^2 ≟ (2^(2p) - 1)m^2 + (2^p)m + 0.25` + // - `(1 - 2^(2p))m + m^2 ≟ (1 - 2^(2p))m^2 + (1 - 2^p)m + 0.25` (?) + // + // I do not follow how the rounding bit is extracted from this comparison with the below + // operations. In any case, the algorithm is well tested. + + // The value needed to shift `m_u2` by to create `m*2^(2p)`. `2p = 2 * F::SIG_BITS`, + // `F::BITS - 2` accounts for the offset that `m_u2` already has. + let shift = 2 * F::SIG_BITS - (F::BITS - 2); + + // `2^(2p)m - m^2` + let d0 = (m_u2 << shift).wrapping_sub(m.wrapping_mul(m)); + // `m - 2^(2p)m + m^2` + let d1 = m.wrapping_sub(d0); + m += d1 >> (F::BITS - 1); + m &= F::SIG_MASK; + + match exp { + Exp::Shifted(e) => m |= IntTy::::cast_from(e) << F::SIG_BITS, + Exp::NoShift(e) => m |= e, + }; + + let mut y = F::from_bits(m); + + // FIXME(f16): the fenv math does not work for `f16` + if F::BITS > 16 { + // Handle rounding and inexact. `(m + 1)^2 == 2^shift m` is exact; for all other cases, add + // a tiny value to cause fenv effects. + let d2 = d1.wrapping_add(m).wrapping_add(one); + let mut tiny = if d2 == zero { + cold_path(); + zero + } else { + F::IMPLICIT_BIT + }; + + tiny |= (d1 ^ d2) & F::SIGN_MASK; + let t = F::from_bits(tiny); + y = y + t; + } + + y +} + +/// Multiply at the wider integer size, returning the high half. +fn wmulh(a: I, b: I) -> I { + a.widen_mul(b).hi() +} + +/// Perform `count` goldschmidt iterations, returning `(r_u0, s_u?)`. +/// +/// - `r_u0` is the reciprocal `r ~ 1 / sqrt(m)`, as U0. +/// - `s_u2` is the square root, `s ~ sqrt(m)`, as U2. +/// - `count` is the number of iterations to perform. +/// - `final_set` should be true if this is the last round (same-sized integer). If so, the +/// returned `s` will be U3, for later shifting. Otherwise, the returned `s` is U2. +/// +/// Note that performance relies on the optimizer being able to unroll these loops (reasonably +/// trivial, `count` is a constant when called). +#[inline] +fn goldschmidt(mut r_u0: I, mut s_u2: I, count: u32, final_set: bool) -> (I, I) +where + F: SqrtHelper, + I: HInt + From, +{ + let three_u2 = I::from(0b11u8) << (I::BITS - 2); + let mut u_u0 = r_u0; + + for i in 0..count { + // First iteration: `s = m*r` (`u_u0 = r_u0` set above) + // Subsequent iterations: `s=s*u/2` + s_u2 = wmulh(s_u2, u_u0); + + // Perform `s /= 2` if: + // + // 1. This is not the first iteration (the first iteration is `s = m*r`)... + // 2. ... and this is not the last set of iterations + // 3. ... or, if this is the last set, it is not the last iteration + // + // This step is not performed for the final iteration because the shift is combined with + // a later shift (moving `s` into the mantissa). + if i > 0 && (!final_set || i + 1 < count) { + s_u2 <<= 1; + } + + // u = 3 - s*r + let d_u2 = wmulh(s_u2, r_u0); + u_u0 = three_u2.wrapping_sub(d_u2); + + // r = r*u/2 + r_u0 = wmulh(r_u0, u_u0) << 1; + } + + (r_u0, s_u2) +} + +/// Representation of whether we shift the exponent into a `u32`, or modify it in place to save +/// the shift operations. +enum Exp { + /// The exponent has been shifted to a `u32` and is LSB-aligned. + Shifted(u32), + /// The exponent is in its natural position in integer repr. + NoShift(T), +} + +/// Size-specific constants related to the square root routine. +pub trait SqrtHelper: Float { + /// Integer for the first set of rounds. If unused, set to the same type as the next set. + type ISet1: HInt + Into + CastFrom + From; + /// Integer for the second set of rounds. If unused, set to the same type as the next set. + type ISet2: HInt + From + From; + + /// Number of rounds at `ISet1`. + const SET1_ROUNDS: u32 = 0; + /// Number of rounds at `ISet2`. + const SET2_ROUNDS: u32 = 0; + /// Number of rounds at `Self::Int`. + const FINAL_ROUNDS: u32; +} + +impl SqrtHelper for f32 { + type ISet1 = u32; // unused + type ISet2 = u32; // unused + + const FINAL_ROUNDS: u32 = 3; +} + +impl SqrtHelper for f64 { + type ISet1 = u32; // unused + type ISet2 = u32; + + const SET2_ROUNDS: u32 = 2; + const FINAL_ROUNDS: u32 = 2; +} + +/// A U0.16 representation of `1/sqrt(x)`. +/// +// / The index is a 7-bit number consisting of a single exponent bit and 6 bits of significand. +#[rustfmt::skip] +static RSQRT_TAB: [u16; 128] = [ + 0xb451, 0xb2f0, 0xb196, 0xb044, 0xaef9, 0xadb6, 0xac79, 0xab43, + 0xaa14, 0xa8eb, 0xa7c8, 0xa6aa, 0xa592, 0xa480, 0xa373, 0xa26b, + 0xa168, 0xa06a, 0x9f70, 0x9e7b, 0x9d8a, 0x9c9d, 0x9bb5, 0x9ad1, + 0x99f0, 0x9913, 0x983a, 0x9765, 0x9693, 0x95c4, 0x94f8, 0x9430, + 0x936b, 0x92a9, 0x91ea, 0x912e, 0x9075, 0x8fbe, 0x8f0a, 0x8e59, + 0x8daa, 0x8cfe, 0x8c54, 0x8bac, 0x8b07, 0x8a64, 0x89c4, 0x8925, + 0x8889, 0x87ee, 0x8756, 0x86c0, 0x862b, 0x8599, 0x8508, 0x8479, + 0x83ec, 0x8361, 0x82d8, 0x8250, 0x81c9, 0x8145, 0x80c2, 0x8040, + 0xff02, 0xfd0e, 0xfb25, 0xf947, 0xf773, 0xf5aa, 0xf3ea, 0xf234, + 0xf087, 0xeee3, 0xed47, 0xebb3, 0xea27, 0xe8a3, 0xe727, 0xe5b2, + 0xe443, 0xe2dc, 0xe17a, 0xe020, 0xdecb, 0xdd7d, 0xdc34, 0xdaf1, + 0xd9b3, 0xd87b, 0xd748, 0xd61a, 0xd4f1, 0xd3cd, 0xd2ad, 0xd192, + 0xd07b, 0xcf69, 0xce5b, 0xcd51, 0xcc4a, 0xcb48, 0xca4a, 0xc94f, + 0xc858, 0xc764, 0xc674, 0xc587, 0xc49d, 0xc3b7, 0xc2d4, 0xc1f4, + 0xc116, 0xc03c, 0xbf65, 0xbe90, 0xbdbe, 0xbcef, 0xbc23, 0xbb59, + 0xba91, 0xb9cc, 0xb90a, 0xb84a, 0xb78c, 0xb6d0, 0xb617, 0xb560, +]; + +#[cfg(test)] +mod tests { + use super::*; + + /// Test against edge cases from https://en.cppreference.com/w/cpp/numeric/math/sqrt + fn spec_test() + where + F: Float + SqrtHelper, + F::Int: HInt, + F::Int: From, + F::Int: From, + F::Int: CastInto, + F::Int: CastInto, + u32: CastInto, + { + // Not Asserted: FE_INVALID exception is raised if argument is negative. + assert!(sqrt(F::NEG_ONE).is_nan()); + assert!(sqrt(F::NAN).is_nan()); + for f in [F::ZERO, F::NEG_ZERO, F::INFINITY].iter().copied() { + assert_biteq!(sqrt(f), f); + } + } + + #[test] + fn sanity_check_f32() { + assert_biteq!(sqrt(100.0f32), 10.0); + assert_biteq!(sqrt(4.0f32), 2.0); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + #[allow(clippy::approx_constant)] + fn conformance_tests_f32() { + let cases = [ + (f32::PI, 0x3fe2dfc5_u32), + (10000.0f32, 0x42c80000_u32), + (f32::from_bits(0x0000000f), 0x1b2f456f_u32), + (f32::INFINITY, f32::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrt(input), + f32::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } + + #[test] + fn sanity_check_f64() { + assert_biteq!(sqrt(100.0f64), 10.0); + assert_biteq!(sqrt(4.0f64), 2.0); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[allow(clippy::approx_constant)] + fn conformance_tests_f64() { + let cases = [ + (f64::PI, 0x3ffc5bf891b4ef6a_u64), + (10000.0, 0x4059000000000000_u64), + (f64::from_bits(0x0000000f), 0x1e7efbdeb14f4eda_u64), + (f64::INFINITY, f64::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrt(input), + f64::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 2fd7070b110..0e1d0cd2c1c 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -1,83 +1,3 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* sqrt(x) - * Return correctly rounded sqrt. - * ------------------------------------------ - * | Use the hardware sqrt if you have one | - * ------------------------------------------ - * Method: - * Bit by bit method using integer arithmetic. (Slow, but portable) - * 1. Normalization - * Scale x to y in [1,4) with even powers of 2: - * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then - * sqrt(x) = 2^k * sqrt(y) - * 2. Bit by bit computation - * Let q = sqrt(y) truncated to i bit after binary point (q = 1), - * i 0 - * i+1 2 - * s = 2*q , and y = 2 * ( y - q ). (1) - * i i i i - * - * To compute q from q , one checks whether - * i+1 i - * - * -(i+1) 2 - * (q + 2 ) <= y. (2) - * i - * -(i+1) - * If (2) is false, then q = q ; otherwise q = q + 2 . - * i+1 i i+1 i - * - * With some algebraic manipulation, it is not difficult to see - * that (2) is equivalent to - * -(i+1) - * s + 2 <= y (3) - * i i - * - * The advantage of (3) is that s and y can be computed by - * i i - * the following recurrence formula: - * if (3) is false - * - * s = s , y = y ; (4) - * i+1 i i+1 i - * - * otherwise, - * -i -(i+1) - * s = s + 2 , y = y - s - 2 (5) - * i+1 i i+1 i i - * - * One may easily use induction to prove (4) and (5). - * Note. Since the left hand side of (3) contain only i+2 bits, - * it does not necessary to do a full (53-bit) comparison - * in (3). - * 3. Final rounding - * After generating the 53 bits result, we compute one more bit. - * Together with the remainder, we can decide whether the - * result is exact, bigger than 1/2ulp, or less than 1/2ulp - * (it will never equal to 1/2ulp). - * The rounding mode can be detected by checking whether - * huge + tiny is equal to huge, and whether huge - tiny is - * equal to huge for some floating point number "huge" and "tiny". - * - * Special cases: - * sqrt(+-0) = +-0 ... exact - * sqrt(inf) = inf - * sqrt(-ve) = NaN ... with invalid signal - * sqrt(NaN) = NaN ... with invalid signal for signaling NaN - */ - -use core::f64; - /// The square root of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { @@ -90,175 +10,5 @@ pub fn sqrt(x: f64) -> f64 { args: x, } - use core::num::Wrapping; - - const TINY: f64 = 1.0e-300; - - let mut z: f64; - let sign: Wrapping = Wrapping(0x80000000); - let mut ix0: i32; - let mut s0: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: Wrapping; - let mut t1: Wrapping; - let mut s1: Wrapping; - let mut ix1: Wrapping; - let mut q1: Wrapping; - - ix0 = (x.to_bits() >> 32) as i32; - ix1 = Wrapping(x.to_bits() as u32); - - /* take care of Inf and NaN */ - if (ix0 & 0x7ff00000) == 0x7ff00000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } - /* take care of zero */ - if ix0 <= 0 { - if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix0 < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } - /* normalize x */ - m = ix0 >> 20; - if m == 0 { - /* subnormal x */ - while ix0 == 0 { - m -= 21; - ix0 |= (ix1 >> 11).0 as i32; - ix1 <<= 21; - } - i = 0; - while (ix0 & 0x00100000) == 0 { - i += 1; - ix0 <<= 1; - } - m -= i - 1; - ix0 |= (ix1 >> (32 - i) as usize).0 as i32; - ix1 = ix1 << i as usize; - } - m -= 1023; /* unbias exponent */ - ix0 = (ix0 & 0x000fffff) | 0x00100000; - if (m & 1) == 1 { - /* odd m, double x to make it even */ - ix0 *= 2; - ix0 += ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - } - m >>= 1; /* m = [m/2] */ - - /* generate sqrt(x) bit by bit */ - ix0 *= 2; - ix0 += ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - q = 0; /* [q,q1] = sqrt(x) */ - q1 = Wrapping(0); - s0 = 0; - s1 = Wrapping(0); - r = Wrapping(0x00200000); /* r = moving bit from right to left */ - - while r != Wrapping(0) { - t = s0 + r.0 as i32; - if t <= ix0 { - s0 = t + r.0 as i32; - ix0 -= t; - q += r.0 as i32; - } - ix0 *= 2; - ix0 += ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; - } - - r = sign; - while r != Wrapping(0) { - t1 = s1 + r; - t = s0; - if t < ix0 || (t == ix0 && t1 <= ix1) { - s1 = t1 + r; - if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { - s0 += 1; - } - ix0 -= t; - if ix1 < t1 { - ix0 -= 1; - } - ix1 -= t1; - q1 += r; - } - ix0 *= 2; - ix0 += ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; - } - - /* use floating add to find out rounding direction */ - if (ix0 as u32 | ix1.0) != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if q1.0 == 0xffffffff { - q1 = Wrapping(0); - q += 1; - } else if z > 1.0 { - if q1.0 == 0xfffffffe { - q += 1; - } - q1 += Wrapping(2); - } else { - q1 += q1 & Wrapping(1); - } - } - } - ix0 = (q >> 1) + 0x3fe00000; - ix1 = q1 >> 1; - if (q & 1) == 1 { - ix1 |= sign; - } - ix0 += m << 20; - f64::from_bits(((ix0 as u64) << 32) | ix1.0 as u64) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(sqrt(100.0), 10.0); - assert_eq!(sqrt(4.0), 2.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt - #[test] - fn spec_tests() { - // Not Asserted: FE_INVALID exception is raised if argument is negative. - assert!(sqrt(-1.0).is_nan()); - assert!(sqrt(f64::NAN).is_nan()); - for f in [0.0, -0.0, f64::INFINITY].iter().copied() { - assert_eq!(sqrt(f), f); - } - } - - #[test] - #[allow(clippy::approx_constant)] - fn conformance_tests() { - let values = [3.14159265359, 10000.0, f64::from_bits(0x0000000f), f64::INFINITY]; - let results = [ - 4610661241675116657u64, - 4636737291354636288u64, - 2197470602079456986u64, - 9218868437227405312u64, - ]; - - for i in 0..values.len() { - let bits = f64::to_bits(sqrt(values[i])); - assert_eq!(results[i], bits); - } - } + super::generic::sqrt(x) } diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 319335163ae..2e69a4b6694 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -1,18 +1,3 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrtf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - /// The square root of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf(x: f32) -> f32 { @@ -25,121 +10,5 @@ pub fn sqrtf(x: f32) -> f32 { args: x, } - const TINY: f32 = 1.0e-30; - - let mut z: f32; - let sign: i32 = 0x80000000u32 as i32; - let mut ix: i32; - let mut s: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: u32; - - ix = x.to_bits() as i32; - - /* take care of Inf and NaN */ - if (ix as u32 & 0x7f800000) == 0x7f800000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } - - /* take care of zero */ - if ix <= 0 { - if (ix & !sign) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } - - /* normalize x */ - m = ix >> 23; - if m == 0 { - /* subnormal x */ - i = 0; - while ix & 0x00800000 == 0 { - ix <<= 1; - i = i + 1; - } - m -= i - 1; - } - m -= 127; /* unbias exponent */ - ix = (ix & 0x007fffff) | 0x00800000; - if m & 1 == 1 { - /* odd m, double x to make it even */ - ix += ix; - } - m >>= 1; /* m = [m/2] */ - - /* generate sqrt(x) bit by bit */ - ix += ix; - q = 0; - s = 0; - r = 0x01000000; /* r = moving bit from right to left */ - - while r != 0 { - t = s + r as i32; - if t <= ix { - s = t + r as i32; - ix -= t; - q += r as i32; - } - ix += ix; - r >>= 1; - } - - /* use floating add to find out rounding direction */ - if ix != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if z > 1.0 { - q += 2; - } else { - q += q & 1; - } - } - } - - ix = (q >> 1) + 0x3f000000; - ix += m << 23; - f32::from_bits(ix as u32) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(sqrtf(100.0), 10.0); - assert_eq!(sqrtf(4.0), 2.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt - #[test] - fn spec_tests() { - // Not Asserted: FE_INVALID exception is raised if argument is negative. - assert!(sqrtf(-1.0).is_nan()); - assert!(sqrtf(f32::NAN).is_nan()); - for f in [0.0, -0.0, f32::INFINITY].iter().copied() { - assert_eq!(sqrtf(f), f); - } - } - - #[test] - #[allow(clippy::approx_constant)] - fn conformance_tests() { - let values = [3.14159265359f32, 10000.0f32, f32::from_bits(0x0000000f), f32::INFINITY]; - let results = [1071833029u32, 1120403456u32, 456082799u32, 2139095040u32]; - - for i in 0..values.len() { - let bits = f32::to_bits(sqrtf(values[i])); - assert_eq!(results[i], bits); - } - } + super::generic::sqrt(x) } diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index db799c030c2..cf19762e816 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -55,10 +55,12 @@ pub trait Int: + ops::BitAnd + cmp::Ord + CastFrom + + CastFrom + CastFrom + CastFrom + CastFrom + CastInto + + CastInto + CastInto + CastInto + CastInto diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index 076fdf1f775..c9a36c0db1a 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -110,19 +110,21 @@ macro_rules! hf64 { /// Assert `F::biteq` with better messages. #[cfg(test)] macro_rules! assert_biteq { - ($left:expr, $right:expr, $($arg:tt)*) => {{ - let bits = ($left.to_bits() * 0).leading_zeros(); // hack to get the width from the value + ($left:expr, $right:expr, $($tt:tt)*) => {{ + let l = $left; + let r = $right; + let bits = (l.to_bits() - l.to_bits()).leading_zeros(); // hack to get the width from the value assert!( - $left.biteq($right), - "\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", - l = $left, - lb = $left.to_bits(), - r = $right, - rb = $right.to_bits(), - width = ((bits / 4) + 2) as usize + l.biteq(r), + "{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", + format_args!($($tt)*), + lb = l.to_bits(), + rb = r.to_bits(), + width = ((bits / 4) + 2) as usize, + ); }}; ($left:expr, $right:expr $(,)?) => { - assert_biteq!($left, $right,) + assert_biteq!($left, $right, "") }; } diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index e2f4e0e981d..b4a57a34ed4 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -10,3 +10,14 @@ pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; #[allow(unused_imports)] pub use hex_float::{hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; + +/// Hint to the compiler that the current path is cold. +pub fn cold_path() { + #[cfg(intrinsics_enabled)] + core::intrinsics::cold_path(); +} + +/// Return `x`, first raising `FE_INVALID`. +pub fn raise_invalid(x: F) -> F { + (x - x) / (x - x) +} -- cgit 1.4.1-3-g733a5 From 03041a0371565f1a32583d770e15f4ffb60232b5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 15 Jan 2025 11:49:28 +0000 Subject: Copy the u256 implementation from compiler_builtins --- .../compiler-builtins/libm/src/math/support/big.rs | 302 +++++++++++++++++++++ .../libm/src/math/support/big/tests.rs | 110 ++++++++ .../compiler-builtins/libm/src/math/support/mod.rs | 1 + 3 files changed, 413 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/support/big.rs create mode 100644 library/compiler-builtins/libm/src/math/support/big/tests.rs diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs new file mode 100644 index 00000000000..e0f5e52634e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -0,0 +1,302 @@ +//! Integers used for wide operations, larger than `u128`. + +#![allow(unused)] + +#[cfg(test)] +mod tests; + +use core::{fmt, ops}; + +use super::{DInt, HInt, Int, MinInt}; + +const WORD_LO_MASK: u64 = 0x00000000ffffffff; +const WORD_HI_MASK: u64 = 0xffffffff00000000; +const WORD_FULL_MASK: u64 = 0xffffffffffffffff; +const U128_LO_MASK: u128 = u64::MAX as u128; +const U128_HI_MASK: u128 = (u64::MAX as u128) << 64; + +/// A 256-bit unsigned integer represented as 4 64-bit limbs. +/// +/// Each limb is a native-endian number, but the array is little-limb-endian. +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +pub struct u256(pub [u64; 4]); + +impl u256 { + pub const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX]); + + /// Reinterpret as a signed integer + pub fn signed(self) -> i256 { + i256(self.0) + } +} + +/// A 256-bit signed integer represented as 4 64-bit limbs. +/// +/// Each limb is a native-endian number, but the array is little-limb-endian. +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +pub struct i256(pub [u64; 4]); + +impl i256 { + /// Reinterpret as an unsigned integer + pub fn unsigned(self) -> u256 { + u256(self.0) + } +} + +impl MinInt for u256 { + type OtherSign = i256; + + type Unsigned = u256; + + const SIGNED: bool = false; + const BITS: u32 = 256; + const ZERO: Self = Self([0u64; 4]); + const ONE: Self = Self([1, 0, 0, 0]); + const MIN: Self = Self([0u64; 4]); + const MAX: Self = Self([u64::MAX; 4]); +} + +impl MinInt for i256 { + type OtherSign = u256; + + type Unsigned = u256; + + const SIGNED: bool = false; + const BITS: u32 = 256; + const ZERO: Self = Self([0u64; 4]); + const ONE: Self = Self([1, 0, 0, 0]); + const MIN: Self = Self([0, 0, 0, 1 << 63]); + const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX << 1]); +} + +macro_rules! impl_common { + ($ty:ty) => { + impl ops::BitOr for $ty { + type Output = Self; + + fn bitor(mut self, rhs: Self) -> Self::Output { + self.0[0] |= rhs.0[0]; + self.0[1] |= rhs.0[1]; + self.0[2] |= rhs.0[2]; + self.0[3] |= rhs.0[3]; + self + } + } + + impl ops::Not for $ty { + type Output = Self; + + fn not(self) -> Self::Output { + Self([!self.0[0], !self.0[1], !self.0[2], !self.0[3]]) + } + } + + impl ops::Shl for $ty { + type Output = Self; + + fn shl(self, rhs: u32) -> Self::Output { + unimplemented!("only used to meet trait bounds") + } + } + }; +} + +impl_common!(i256); +impl_common!(u256); + +impl ops::Shr for u256 { + type Output = Self; + + fn shr(self, rhs: u32) -> Self::Output { + assert!(rhs < Self::BITS, "attempted to shift right with overflow"); + + if rhs == 0 { + return self; + } + + let mut ret = self; + let byte_shift = rhs / 64; + let bit_shift = rhs % 64; + + for idx in 0..4 { + let base_idx = idx + byte_shift as usize; + + // FIXME(msrv): could be let...else. + let base = match ret.0.get(base_idx) { + Some(v) => v, + None => { + ret.0[idx] = 0; + continue; + } + }; + + let mut new_val = base >> bit_shift; + + if let Some(new) = ret.0.get(base_idx + 1) { + new_val |= new.overflowing_shl(64 - bit_shift).0; + } + + ret.0[idx] = new_val; + } + + ret + } +} + +macro_rules! word { + (1, $val:expr) => { + (($val >> (32 * 3)) & Self::from(WORD_LO_MASK)) as u64 + }; + (2, $val:expr) => { + (($val >> (32 * 2)) & Self::from(WORD_LO_MASK)) as u64 + }; + (3, $val:expr) => { + (($val >> (32 * 1)) & Self::from(WORD_LO_MASK)) as u64 + }; + (4, $val:expr) => { + (($val >> (32 * 0)) & Self::from(WORD_LO_MASK)) as u64 + }; +} + +impl HInt for u128 { + type D = u256; + + fn widen(self) -> Self::D { + let w0 = self & u128::from(u64::MAX); + let w1 = (self >> u64::BITS) & u128::from(u64::MAX); + u256([w0 as u64, w1 as u64, 0, 0]) + } + + fn zero_widen(self) -> Self::D { + self.widen() + } + + fn zero_widen_mul(self, rhs: Self) -> Self::D { + let product11: u64 = word!(1, self) * word!(1, rhs); + let product12: u64 = word!(1, self) * word!(2, rhs); + let product13: u64 = word!(1, self) * word!(3, rhs); + let product14: u64 = word!(1, self) * word!(4, rhs); + let product21: u64 = word!(2, self) * word!(1, rhs); + let product22: u64 = word!(2, self) * word!(2, rhs); + let product23: u64 = word!(2, self) * word!(3, rhs); + let product24: u64 = word!(2, self) * word!(4, rhs); + let product31: u64 = word!(3, self) * word!(1, rhs); + let product32: u64 = word!(3, self) * word!(2, rhs); + let product33: u64 = word!(3, self) * word!(3, rhs); + let product34: u64 = word!(3, self) * word!(4, rhs); + let product41: u64 = word!(4, self) * word!(1, rhs); + let product42: u64 = word!(4, self) * word!(2, rhs); + let product43: u64 = word!(4, self) * word!(3, rhs); + let product44: u64 = word!(4, self) * word!(4, rhs); + + let sum0: u128 = u128::from(product44); + let sum1: u128 = u128::from(product34) + u128::from(product43); + let sum2: u128 = u128::from(product24) + u128::from(product33) + u128::from(product42); + let sum3: u128 = u128::from(product14) + + u128::from(product23) + + u128::from(product32) + + u128::from(product41); + let sum4: u128 = u128::from(product13) + u128::from(product22) + u128::from(product31); + let sum5: u128 = u128::from(product12) + u128::from(product21); + let sum6: u128 = u128::from(product11); + + let r0: u128 = + (sum0 & u128::from(WORD_FULL_MASK)) + ((sum1 & u128::from(WORD_LO_MASK)) << 32); + let r1: u128 = (sum0 >> 64) + + ((sum1 >> 32) & u128::from(WORD_FULL_MASK)) + + (sum2 & u128::from(WORD_FULL_MASK)) + + ((sum3 << 32) & u128::from(WORD_HI_MASK)); + + let (lo, carry) = r0.overflowing_add(r1 << 64); + let hi = (r1 >> 64) + + (sum1 >> 96) + + (sum2 >> 64) + + (sum3 >> 32) + + sum4 + + (sum5 << 32) + + (sum6 << 64) + + u128::from(carry); + + u256([ + (lo & U128_LO_MASK) as u64, + ((lo >> 64) & U128_LO_MASK) as u64, + (hi & U128_LO_MASK) as u64, + ((hi >> 64) & U128_LO_MASK) as u64, + ]) + } + + fn widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen_mul(rhs) + } + + fn widen_hi(self) -> Self::D { + self.widen() << ::BITS + } +} + +impl HInt for i128 { + type D = i256; + + fn widen(self) -> Self::D { + let mut ret = self.unsigned().zero_widen().signed(); + if self.is_negative() { + ret.0[2] = u64::MAX; + ret.0[3] = u64::MAX; + } + ret + } + + fn zero_widen(self) -> Self::D { + self.unsigned().zero_widen().signed() + } + + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.unsigned().zero_widen_mul(rhs.unsigned()).signed() + } + + fn widen_mul(self, rhs: Self) -> Self::D { + unimplemented!("signed i128 widening multiply is not used") + } + + fn widen_hi(self) -> Self::D { + self.widen() << ::BITS + } +} + +impl DInt for u256 { + type H = u128; + + fn lo(self) -> Self::H { + let mut tmp = [0u8; 16]; + tmp[..8].copy_from_slice(&self.0[0].to_le_bytes()); + tmp[8..].copy_from_slice(&self.0[1].to_le_bytes()); + u128::from_le_bytes(tmp) + } + + fn hi(self) -> Self::H { + let mut tmp = [0u8; 16]; + tmp[..8].copy_from_slice(&self.0[2].to_le_bytes()); + tmp[8..].copy_from_slice(&self.0[3].to_le_bytes()); + u128::from_le_bytes(tmp) + } +} + +impl DInt for i256 { + type H = i128; + + fn lo(self) -> Self::H { + let mut tmp = [0u8; 16]; + tmp[..8].copy_from_slice(&self.0[0].to_le_bytes()); + tmp[8..].copy_from_slice(&self.0[1].to_le_bytes()); + i128::from_le_bytes(tmp) + } + + fn hi(self) -> Self::H { + let mut tmp = [0u8; 16]; + tmp[..8].copy_from_slice(&self.0[2].to_le_bytes()); + tmp[8..].copy_from_slice(&self.0[3].to_le_bytes()); + i128::from_le_bytes(tmp) + } +} diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs new file mode 100644 index 00000000000..f95f8297316 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -0,0 +1,110 @@ +extern crate std; +use std::string::String; +use std::vec::Vec; +use std::{eprintln, format}; + +use super::{HInt, MinInt, i256, u256}; + +const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; + +/// Print a `u256` as hex since we can't add format implementations +fn hexu(v: u256) -> String { + format!("0x{:016x}{:016x}{:016x}{:016x}", v.0[3], v.0[2], v.0[1], v.0[0]) +} + +#[test] +fn widen_u128() { + assert_eq!(u128::MAX.widen(), u256([u64::MAX, u64::MAX, 0, 0])); + assert_eq!(LOHI_SPLIT.widen(), u256([u64::MAX, 0xaaaaaaaaaaaaaaaa, 0, 0])); +} + +#[test] +fn widen_i128() { + assert_eq!((-1i128).widen(), u256::MAX.signed()); + assert_eq!( + (LOHI_SPLIT as i128).widen(), + i256([u64::MAX, 0xaaaaaaaaaaaaaaaa, u64::MAX, u64::MAX]) + ); + assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); +} + +#[test] +fn widen_mul_u128() { + let tests = [ + (u128::MAX / 2, 2_u128, u256([u64::MAX - 1, u64::MAX, 0, 0])), + (u128::MAX, 2_u128, u256([u64::MAX - 1, u64::MAX, 1, 0])), + (u128::MAX, u128::MAX, u256([1, 0, u64::MAX - 1, u64::MAX])), + (u128::MIN, u128::MIN, u256::ZERO), + (1234, 0, u256::ZERO), + (0, 1234, u256::ZERO), + ]; + + let mut errors = Vec::new(); + for (i, (a, b, exp)) in tests.iter().copied().enumerate() { + let res = a.widen_mul(b); + let res_z = a.zero_widen_mul(b); + assert_eq!(res, res_z); + if res != exp { + errors.push((i, a, b, exp, res)); + } + } + + for (i, a, b, exp, res) in &errors { + eprintln!("FAILURE ({i}): {a:#034x} * {b:#034x} = {} got {}", hexu(*exp), hexu(*res)); + } + assert!(errors.is_empty()); +} + +#[test] +fn not_u128() { + assert_eq!(!u256::ZERO, u256::MAX); +} + +#[test] +fn shr_u128() { + let only_low = [1, u16::MAX.into(), u32::MAX.into(), u64::MAX.into(), u128::MAX]; + + let mut errors = Vec::new(); + + for a in only_low { + for perturb in 0..10 { + let a = a.saturating_add(perturb); + for shift in 0..128 { + let res = a.widen() >> shift; + let expected = (a >> shift).widen(); + if res != expected { + errors.push((a.widen(), shift, res, expected)); + } + } + } + } + + let check = [ + (u256::MAX, 1, u256([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 1])), + (u256::MAX, 5, u256([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 5])), + (u256::MAX, 63, u256([u64::MAX, u64::MAX, u64::MAX, 1])), + (u256::MAX, 64, u256([u64::MAX, u64::MAX, u64::MAX, 0])), + (u256::MAX, 65, u256([u64::MAX, u64::MAX, u64::MAX >> 1, 0])), + (u256::MAX, 127, u256([u64::MAX, u64::MAX, 1, 0])), + (u256::MAX, 128, u256([u64::MAX, u64::MAX, 0, 0])), + (u256::MAX, 129, u256([u64::MAX, u64::MAX >> 1, 0, 0])), + (u256::MAX, 191, u256([u64::MAX, 1, 0, 0])), + (u256::MAX, 192, u256([u64::MAX, 0, 0, 0])), + (u256::MAX, 193, u256([u64::MAX >> 1, 0, 0, 0])), + (u256::MAX, 191, u256([u64::MAX, 1, 0, 0])), + (u256::MAX, 254, u256([0b11, 0, 0, 0])), + (u256::MAX, 255, u256([1, 0, 0, 0])), + ]; + + for (input, shift, expected) in check { + let res = input >> shift; + if res != expected { + errors.push((input, shift, res, expected)); + } + } + + for (a, b, res, expected) in &errors { + eprintln!("FAILURE: {} >> {b} = {} got {}", hexu(*a), hexu(*expected), hexu(*res),); + } + assert!(errors.is_empty()); +} diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index b4a57a34ed4..ddfc2e3e071 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -1,5 +1,6 @@ #[macro_use] pub mod macros; +mod big; mod float_traits; mod hex_float; mod int_traits; -- cgit 1.4.1-3-g733a5 From 186eac9227e83b9ba0d771ac9326632d42e25086 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 Jan 2025 23:59:07 +0000 Subject: Add `sqrtf16` and `sqrtf128` Use the generic algorithms to provide implementations for these routines. --- .../libm/crates/libm-macros/src/shared.rs | 4 +- .../libm/crates/libm-test/benches/icount.rs | 2 + .../libm/crates/libm-test/benches/random.rs | 2 + .../crates/libm-test/tests/compare_built_musl.rs | 2 + .../compiler-builtins/libm/crates/util/src/main.rs | 2 + .../libm/etc/function-definitions.json | 14 ++++ .../compiler-builtins/libm/etc/function-list.txt | 2 + .../libm/src/math/generic/sqrt.rs | 92 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 4 + .../compiler-builtins/libm/src/math/sqrtf128.rs | 5 ++ library/compiler-builtins/libm/src/math/sqrtf16.rs | 5 ++ 11 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/sqrtf128.rs create mode 100644 library/compiler-builtins/libm/src/math/sqrtf16.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 60838196236..d17bc6ffccb 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["fabsf16", "truncf16"], + &["fabsf16", "sqrtf16", "truncf16"], ), ( // `fn(f32) -> f32` @@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["fabsf128", "truncf128"], + &["fabsf128", "sqrtf128", "truncf128"], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 3a66249e85d..c8451f88cd3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -155,6 +155,8 @@ main!( icount_bench_sinh_group, icount_bench_sinhf_group, icount_bench_sqrt_group, + icount_bench_sqrtf128_group, + icount_bench_sqrtf16_group, icount_bench_sqrtf_group, icount_bench_tan_group, icount_bench_tanf_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 88816126510..02684120253 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -123,6 +123,8 @@ libm_macros::for_each_function! { | fabsf16 | fdimf128 | fdimf16 + | sqrtf16 + | sqrtf128 | truncf128 | truncf16 => (false, None), diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index f540a0b1551..24703f27316 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -87,5 +87,7 @@ libm_macros::for_each_function! { fdimf16, truncf128, truncf16, + sqrtf16, + sqrtf128, ], } diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index b979c60ad3c..cd68d9afd1a 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -90,6 +90,8 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fabsf16 | fdimf128 | fdimf16 + | sqrtf128 + | sqrtf16 | truncf128 | truncf16 => None, _ => Some(musl_math_sys::MACRO_FN_NAME) diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 9f7c8ab25a0..2d0af3bcff0 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -718,6 +718,20 @@ ], "type": "f32" }, + "sqrtf128": { + "sources": [ + "src/math/generic/sqrt.rs", + "src/math/sqrtf128.rs" + ], + "type": "f128" + }, + "sqrtf16": { + "sources": [ + "src/math/generic/sqrt.rs", + "src/math/sqrtf16.rs" + ], + "type": "f16" + }, "tan": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 7f96a436227..47c34ab9052 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -105,6 +105,8 @@ sinh sinhf sqrt sqrtf +sqrtf128 +sqrtf16 tan tanf tanh diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index a2e054f3cf2..c892f999724 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -294,6 +294,14 @@ pub trait SqrtHelper: Float { const FINAL_ROUNDS: u32; } +#[cfg(f16_enabled)] +impl SqrtHelper for f16 { + type ISet1 = u16; // unused + type ISet2 = u16; // unused + + const FINAL_ROUNDS: u32 = 2; +} + impl SqrtHelper for f32 { type ISet1 = u32; // unused type ISet2 = u32; // unused @@ -309,6 +317,16 @@ impl SqrtHelper for f64 { const FINAL_ROUNDS: u32 = 2; } +#[cfg(f128_enabled)] +impl SqrtHelper for f128 { + type ISet1 = u32; + type ISet2 = u64; + + const SET1_ROUNDS: u32 = 1; + const SET2_ROUNDS: u32 = 2; + const FINAL_ROUNDS: u32 = 2; +} + /// A U0.16 representation of `1/sqrt(x)`. /// // / The index is a 7-bit number consisting of a single exponent bit and 6 bits of significand. @@ -355,6 +373,42 @@ mod tests { } } + #[test] + #[cfg(f16_enabled)] + fn sanity_check_f16() { + assert_biteq!(sqrt(100.0f16), 10.0); + assert_biteq!(sqrt(4.0f16), 2.0); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + #[cfg(f16_enabled)] + #[allow(clippy::approx_constant)] + fn conformance_tests_f16() { + let cases = [ + (f16::PI, 0x3f17_u16), + // 10_000.0, using a hex literal for MSRV hack (Rust < 1.67 checks literal widths as + // part of the AST, so the `cfg` is irrelevant here). + (f16::from_bits(0x70e2), 0x5640_u16), + (f16::from_bits(0x0000000f), 0x13bf_u16), + (f16::INFINITY, f16::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrt(input), + f16::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } + #[test] fn sanity_check_f32() { assert_biteq!(sqrt(100.0f32), 10.0); @@ -416,4 +470,42 @@ mod tests { ); } } + + #[test] + #[cfg(f128_enabled)] + fn sanity_check_f128() { + assert_biteq!(sqrt(100.0f128), 10.0); + assert_biteq!(sqrt(4.0f128), 2.0); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + #[allow(clippy::approx_constant)] + fn conformance_tests_f128() { + let cases = [ + (f128::PI, 0x3fffc5bf891b4ef6aa79c3b0520d5db9_u128), + // 10_000.0, see `f16` for reasoning. + ( + f128::from_bits(0x400c3880000000000000000000000000), + 0x40059000000000000000000000000000_u128, + ), + (f128::from_bits(0x0000000f), 0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128), + (f128::INFINITY, f128::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrt(input), + f128::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 03adb6be193..3684025a6c1 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -344,11 +344,13 @@ cfg_if! { mod copysignf16; mod fabsf16; mod fdimf16; + mod sqrtf16; mod truncf16; pub use self::copysignf16::copysignf16; pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; + pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; } } @@ -358,11 +360,13 @@ cfg_if! { mod copysignf128; mod fabsf128; mod fdimf128; + mod sqrtf128; mod truncf128; pub use self::copysignf128::copysignf128; pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; + pub use self::sqrtf128::sqrtf128; pub use self::truncf128::truncf128; } } diff --git a/library/compiler-builtins/libm/src/math/sqrtf128.rs b/library/compiler-builtins/libm/src/math/sqrtf128.rs new file mode 100644 index 00000000000..eaef6ae0c1c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sqrtf128.rs @@ -0,0 +1,5 @@ +/// The square root of `x` (f128). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf128(x: f128) -> f128 { + return super::generic::sqrt(x); +} diff --git a/library/compiler-builtins/libm/src/math/sqrtf16.rs b/library/compiler-builtins/libm/src/math/sqrtf16.rs new file mode 100644 index 00000000000..549bf902c72 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sqrtf16.rs @@ -0,0 +1,5 @@ +/// The square root of `x` (f16). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf16(x: f16) -> f16 { + return super::generic::sqrt(x); +} -- cgit 1.4.1-3-g733a5 From 5ac2f99954f2bd2d7d1c342abcaa5ffed7418e08 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 11:58:17 +0000 Subject: Shift then mask, rather than mask then shift This may allow for small optimizations with larger float types since `u32` math can be used after shifting. LLVM may be already getting this anyway. --- library/compiler-builtins/libm/src/math/support/float_traits.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 647f4f5e251..2e467111f32 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -1,6 +1,6 @@ use core::{fmt, mem, ops}; -use super::int_traits::{CastFrom, CastInto, Int, MinInt}; +use super::int_traits::{CastFrom, Int, MinInt}; /// Trait for some basic operations on floats #[allow(dead_code)] @@ -108,7 +108,7 @@ pub trait Float: /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. fn exp(self) -> i32 { - ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS).cast() + (u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_MAX).signed() } /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. -- cgit 1.4.1-3-g733a5 From a7cd13b6a32874dd6bc18cdb7e7d7e6bda105adf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 07:13:45 +0000 Subject: Make `Float::exp` return an unsigned integer `exp` does not perform any form of unbiasing, so there isn't any reason it should be signed. Change this. Additionally, add `EPSILON` to the `Float` trait. --- library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs | 2 ++ library/compiler-builtins/libm/src/math/generic/sqrt.rs | 2 +- library/compiler-builtins/libm/src/math/support/float_traits.rs | 8 +++++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index 299553d202a..96b78392453 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -30,6 +30,8 @@ impl Float for f8 { const INFINITY: Self = Self(0b0_1111_000); const NEG_INFINITY: Self = Self(0b1_1111_000); const NAN: Self = Self(0b0_1111_100); + // FIXME: incorrect values + const EPSILON: Self = Self::ZERO; const PI: Self = Self::ZERO; const NEG_PI: Self = Self::ZERO; const FRAC_PI_2: Self = Self::ZERO; diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index c892f999724..22ee93f57a3 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -96,7 +96,7 @@ where ix = scaled.to_bits(); match top { Exp::Shifted(ref mut v) => { - *v = scaled.exp().unsigned(); + *v = scaled.exp(); *v = (*v).wrapping_sub(F::SIG_BITS); } Exp::NoShift(()) => { diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 2e467111f32..1abb7c4ded8 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -34,6 +34,7 @@ pub trait Float: const NAN: Self; const MAX: Self; const MIN: Self; + const EPSILON: Self; const PI: Self; const NEG_PI: Self; const FRAC_PI_2: Self; @@ -107,13 +108,13 @@ pub trait Float: } /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. - fn exp(self) -> i32 { - (u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_MAX).signed() + fn exp(self) -> u32 { + u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_MAX } /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. fn exp_unbiased(self) -> i32 { - self.exp() - (Self::EXP_BIAS as i32) + self.exp().signed() - (Self::EXP_BIAS as i32) } /// Returns the significand with no implicit bit (or the "fractional" part) @@ -180,6 +181,7 @@ macro_rules! float_impl { const MAX: Self = -Self::MIN; // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS)); + const EPSILON: Self = <$ty>::EPSILON; const PI: Self = core::$ty::consts::PI; const NEG_PI: Self = -Self::PI; -- cgit 1.4.1-3-g733a5 From c00f1191666e6803fdd61eca2ac5f0cb07360656 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 11:17:03 +0000 Subject: Add a generic version of `ceil` Additionally, make use of this version to implement `ceil` and `ceilf`. Musl's `ceilf` algorithm seems to work better for all versions of the functions. Testing with a generic version of musl's `ceil` routine showed the following regressions: icount::icount_bench_ceil_group::icount_bench_ceil logspace:setup_ceil() Performance has regressed: Instructions (14064 > 13171) regressed by +6.78005% (>+5.00000) Baselines: softfloat|softfloat Instructions: 14064|13171 (+6.78005%) [+1.06780x] L1 Hits: 16697|15803 (+5.65715%) [+1.05657x] L2 Hits: 0|0 (No change) RAM Hits: 7|8 (-12.5000%) [-1.14286x] Total read+write: 16704|15811 (+5.64797%) [+1.05648x] Estimated Cycles: 16942|16083 (+5.34104%) [+1.05341x] icount::icount_bench_ceilf_group::icount_bench_ceilf logspace:setup_ceilf() Performance has regressed: Instructions (14732 > 9901) regressed by +48.7931% (>+5.00000) Baselines: softfloat|softfloat Instructions: 14732|9901 (+48.7931%) [+1.48793x] L1 Hits: 17494|12611 (+38.7202%) [+1.38720x] L2 Hits: 0|0 (No change) RAM Hits: 6|6 (No change) Total read+write: 17500|12617 (+38.7018%) [+1.38702x] Estimated Cycles: 17704|12821 (+38.0860%) [+1.38086x] --- library/compiler-builtins/libm/src/math/ceil.rs | 42 +---------- library/compiler-builtins/libm/src/math/ceilf.rs | 51 +------------ .../libm/src/math/generic/ceil.rs | 87 ++++++++++++++++++++++ .../compiler-builtins/libm/src/math/generic/mod.rs | 2 + 4 files changed, 91 insertions(+), 91 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/ceil.rs diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 398bfee47a2..535f434ac24 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -1,8 +1,3 @@ -#![allow(unreachable_code)] -use core::f64; - -const TOINT: f64 = 1. / f64::EPSILON; - /// Ceil (f64) /// /// Finds the nearest integer greater than or equal to `x`. @@ -15,40 +10,5 @@ pub fn ceil(x: f64) -> f64 { args: x, } - let u: u64 = x.to_bits(); - let e: i64 = ((u >> 52) & 0x7ff) as i64; - let y: f64; - - if e >= 0x3ff + 52 || x == 0. { - return x; - } - // y = int(x) - x, where int(x) is an integer neighbor of x - y = if (u >> 63) != 0 { x - TOINT + TOINT - x } else { x + TOINT - TOINT - x }; - // special case because of non-nearest rounding modes - if e < 0x3ff { - force_eval!(y); - return if (u >> 63) != 0 { -0. } else { 1. }; - } - if y < 0. { x + y + 1. } else { x + y } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(ceil(1.1), 2.0); - assert_eq!(ceil(2.9), 3.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil - #[test] - fn spec_tests() { - // Not Asserted: that the current rounding mode has no effect. - assert!(ceil(f64::NAN).is_nan()); - for f in [0.0, -0.0, f64::INFINITY, f64::NEG_INFINITY].iter().copied() { - assert_eq!(ceil(f), f); - } - } + super::generic::ceil(x) } diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 9e8e78e3e53..66d44189c92 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -1,5 +1,3 @@ -use core::f32; - /// Ceil (f32) /// /// Finds the nearest integer greater than or equal to `x`. @@ -11,52 +9,5 @@ pub fn ceilf(x: f32) -> f32 { args: x, } - let mut ui = x.to_bits(); - let e = (((ui >> 23) & 0xff).wrapping_sub(0x7f)) as i32; - - if e >= 23 { - return x; - } - if e >= 0 { - let m = 0x007fffff >> e; - if (ui & m) == 0 { - return x; - } - force_eval!(x + f32::from_bits(0x7b800000)); - if ui >> 31 == 0 { - ui += m; - } - ui &= !m; - } else { - force_eval!(x + f32::from_bits(0x7b800000)); - if ui >> 31 != 0 { - return -0.0; - } else if ui << 1 != 0 { - return 1.0; - } - } - f32::from_bits(ui) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(ceilf(1.1), 2.0); - assert_eq!(ceilf(2.9), 3.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil - #[test] - fn spec_tests() { - // Not Asserted: that the current rounding mode has no effect. - assert!(ceilf(f32::NAN).is_nan()); - for f in [0.0, -0.0, f32::INFINITY, f32::NEG_INFINITY].iter().copied() { - assert_eq!(ceilf(f), f); - } - } + super::generic::ceil(x) } diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs new file mode 100644 index 00000000000..d16d0657279 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/ceilf.c */ + +//! Generic `ceil` algorithm. +//! +//! Note that this uses the algorithm from musl's `ceilf` rather than `ceil` or `ceill` because +//! performance seems to be better (based on icount) and it does not seem to experience rounding +//! errors on i386. + +use super::super::{Float, Int, IntTy, MinInt}; + +pub fn ceil(x: F) -> F { + let zero = IntTy::::ZERO; + + let mut ix = x.to_bits(); + let e = x.exp_unbiased(); + + // If the represented value has no fractional part, no truncation is needed. + if e >= F::SIG_BITS as i32 { + return x; + } + + if e >= 0 { + // |x| >= 1.0 + + let m = F::SIG_MASK >> e.unsigned(); + if (ix & m) == zero { + // Portion to be masked is already zero; no adjustment needed. + return x; + } + + // Otherwise, raise an inexact exception. + force_eval!(x + F::MAX); + if x.is_sign_positive() { + ix += m; + } + ix &= !m; + } else { + // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). + force_eval!(x + F::MAX); + + if x.is_sign_negative() { + // -1.0 < x <= -0.0; rounding up goes toward -0.0. + return F::NEG_ZERO; + } else if ix << 1 != zero { + // 0.0 < x < 1.0; rounding up goes toward +1.0. + return F::ONE; + } + } + + F::from_bits(ix) +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil + fn spec_test() { + // Not Asserted: that the current rounding mode has no effect. + for f in [F::ZERO, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY].iter().copied() { + assert_biteq!(ceil(f), f); + } + } + + #[test] + fn sanity_check_f32() { + assert_eq!(ceil(1.1f32), 2.0); + assert_eq!(ceil(2.9f32), 3.0); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(ceil(1.1f64), 2.0); + assert_eq!(ceil(2.9f64), 3.0); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 3b5a2c3effd..f8bb9fa6adb 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -1,9 +1,11 @@ +mod ceil; mod copysign; mod fabs; mod fdim; mod sqrt; mod trunc; +pub use ceil::ceil; pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; -- cgit 1.4.1-3-g733a5 From 9064c42abe93f9864243aa982b529d54a731db80 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 11:17:17 +0000 Subject: Add `ceilf16` and `ceilf128` Use the generic algorithms to provide implementations for these routines. --- .../libm/crates/libm-macros/src/shared.rs | 4 ++-- .../libm/crates/libm-test/benches/icount.rs | 2 ++ .../libm/crates/libm-test/benches/random.rs | 4 +++- .../libm/crates/libm-test/src/mpfloat.rs | 4 ++++ .../crates/libm-test/tests/compare_built_musl.rs | 2 ++ .../compiler-builtins/libm/crates/util/src/main.rs | 4 +++- .../libm/etc/function-definitions.json | 20 ++++++++++++++++++-- library/compiler-builtins/libm/etc/function-list.txt | 2 ++ library/compiler-builtins/libm/src/math/ceilf128.rs | 7 +++++++ library/compiler-builtins/libm/src/math/ceilf16.rs | 7 +++++++ .../compiler-builtins/libm/src/math/generic/ceil.rs | 14 ++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ 12 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/ceilf128.rs create mode 100644 library/compiler-builtins/libm/src/math/ceilf16.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index d17bc6ffccb..e7d3d18d9a1 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["fabsf16", "sqrtf16", "truncf16"], + &["ceilf16", "fabsf16", "sqrtf16", "truncf16"], ), ( // `fn(f32) -> f32` @@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["fabsf128", "sqrtf128", "truncf128"], + &["ceilf128", "fabsf128", "sqrtf128", "truncf128"], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index c8451f88cd3..84be3d5245b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -69,6 +69,8 @@ main!( icount_bench_cbrt_group, icount_bench_cbrtf_group, icount_bench_ceil_group, + icount_bench_ceilf128_group, + icount_bench_ceilf16_group, icount_bench_ceilf_group, icount_bench_copysign_group, icount_bench_copysignf128_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 02684120253..511e26d9126 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -117,7 +117,9 @@ libm_macros::for_each_function! { exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)), // Musl does not provide `f16` and `f128` functions - copysignf128 + ceilf128 + | ceilf16 + | copysignf128 | copysignf16 | fabsf128 | fabsf16 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 9d95356d39b..bbd19dbb07b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -137,6 +137,8 @@ libm_macros::for_each_function! { // Most of these need a manual implementation ceil, ceilf, + ceilf128, + ceilf16, copysign, copysignf, copysignf128, @@ -237,12 +239,14 @@ impl_no_round! { #[cfg(f16_enabled)] impl_no_round! { fabsf16 => abs_mut; + ceilf16 => ceil_mut; truncf16 => trunc_mut; } #[cfg(f128_enabled)] impl_no_round! { fabsf128 => abs_mut; + ceilf128 => ceil_mut; truncf128 => trunc_mut; } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 24703f27316..e13acf3de21 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -79,6 +79,8 @@ libm_macros::for_each_function! { ynf, // Not provided by musl + ceilf128, + ceilf16, copysignf128, copysignf16, fabsf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index cd68d9afd1a..810919339ec 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -84,7 +84,9 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { emit_types: [CFn, RustFn, RustArgs], extra: (basis, op, inputs), fn_extra: match MACRO_FN_NAME { - copysignf128 + ceilf128 + | ceilf16 + | copysignf128 | copysignf16 | fabsf128 | fabsf16 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 2d0af3bcff0..c75152f6301 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -109,17 +109,33 @@ "src/libm_helper.rs", "src/math/arch/i586.rs", "src/math/arch/wasm32.rs", - "src/math/ceil.rs" + "src/math/ceil.rs", + "src/math/generic/ceil.rs" ], "type": "f64" }, "ceilf": { "sources": [ "src/math/arch/wasm32.rs", - "src/math/ceilf.rs" + "src/math/ceilf.rs", + "src/math/generic/ceil.rs" ], "type": "f32" }, + "ceilf128": { + "sources": [ + "src/math/ceilf128.rs", + "src/math/generic/ceil.rs" + ], + "type": "f128" + }, + "ceilf16": { + "sources": [ + "src/math/ceilf16.rs", + "src/math/generic/ceil.rs" + ], + "type": "f16" + }, "copysign": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 47c34ab9052..337e7e434e5 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -17,6 +17,8 @@ cbrt cbrtf ceil ceilf +ceilf128 +ceilf16 copysign copysignf copysignf128 diff --git a/library/compiler-builtins/libm/src/math/ceilf128.rs b/library/compiler-builtins/libm/src/math/ceilf128.rs new file mode 100644 index 00000000000..89980858eb5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ceilf128.rs @@ -0,0 +1,7 @@ +/// Ceil (f128) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf128(x: f128) -> f128 { + super::generic::ceil(x) +} diff --git a/library/compiler-builtins/libm/src/math/ceilf16.rs b/library/compiler-builtins/libm/src/math/ceilf16.rs new file mode 100644 index 00000000000..2af67eff0d2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ceilf16.rs @@ -0,0 +1,7 @@ +/// Ceil (f16) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf16(x: f16) -> f16 { + super::generic::ceil(x) +} diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs index d16d0657279..34261faf782 100644 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -63,6 +63,14 @@ mod tests { } } + /* Skipping f16 / f128 "sanity_check"s due to rejected literal lexing at MSRV */ + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + #[test] fn sanity_check_f32() { assert_eq!(ceil(1.1f32), 2.0); @@ -84,4 +92,10 @@ mod tests { fn spec_tests_f64() { spec_test::(); } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 3684025a6c1..5228e78b7f3 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -341,12 +341,14 @@ pub use self::truncf::truncf; cfg_if! { if #[cfg(f16_enabled)] { + mod ceilf16; mod copysignf16; mod fabsf16; mod fdimf16; mod sqrtf16; mod truncf16; + pub use self::ceilf16::ceilf16; pub use self::copysignf16::copysignf16; pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; @@ -357,12 +359,14 @@ cfg_if! { cfg_if! { if #[cfg(f128_enabled)] { + mod ceilf128; mod copysignf128; mod fabsf128; mod fdimf128; mod sqrtf128; mod truncf128; + pub use self::ceilf128::ceilf128; pub use self::copysignf128::copysignf128; pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; -- cgit 1.4.1-3-g733a5 From 42fce292ab45c4d28de82799a83f3313b9ca9907 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 13:27:22 +0000 Subject: Add a generic version of `floor` Additionally, make use of this version to implement `floor` and `floorf`. Similar to `ceil`, musl'f `ceilf` routine seems to work better for all float widths than the `ceil` algorithm. Trying with the `ceil` (`f64`) algorithm produced the following regressions: icount::icount_bench_floor_group::icount_bench_floor logspace:setup_floor() Performance has regressed: Instructions (14064 > 13171) regressed by +6.78005% (>+5.00000) Baselines: softfloat|softfloat Instructions: 14064|13171 (+6.78005%) [+1.06780x] L1 Hits: 16821|15802 (+6.44855%) [+1.06449x] L2 Hits: 0|0 (No change) RAM Hits: 8|9 (-11.1111%) [-1.12500x] Total read+write: 16829|15811 (+6.43856%) [+1.06439x] Estimated Cycles: 17101|16117 (+6.10535%) [+1.06105x] icount::icount_bench_floorf128_group::icount_bench_floorf128 logspace:setup_floorf128() Baselines: softfloat|softfloat Instructions: 166868|N/A (*********) L1 Hits: 221429|N/A (*********) L2 Hits: 1|N/A (*********) RAM Hits: 34|N/A (*********) Total read+write: 221464|N/A (*********) Estimated Cycles: 222624|N/A (*********) icount::icount_bench_floorf16_group::icount_bench_floorf16 logspace:setup_floorf16() Baselines: softfloat|softfloat Instructions: 143029|N/A (*********) L1 Hits: 176517|N/A (*********) L2 Hits: 1|N/A (*********) RAM Hits: 13|N/A (*********) Total read+write: 176531|N/A (*********) Estimated Cycles: 176977|N/A (*********) icount::icount_bench_floorf_group::icount_bench_floorf logspace:setup_floorf() Performance has regressed: Instructions (14732 > 10441) regressed by +41.0976% (>+5.00000) Baselines: softfloat|softfloat Instructions: 14732|10441 (+41.0976%) [+1.41098x] L1 Hits: 17616|13027 (+35.2268%) [+1.35227x] L2 Hits: 0|0 (No change) RAM Hits: 8|6 (+33.3333%) [+1.33333x] Total read+write: 17624|13033 (+35.2260%) [+1.35226x] Estimated Cycles: 17896|13237 (+35.1968%) [+1.35197x] --- .../libm/etc/function-definitions.json | 6 +- library/compiler-builtins/libm/src/math/floor.rs | 41 +------- library/compiler-builtins/libm/src/math/floorf.rs | 52 +--------- .../libm/src/math/generic/floor.rs | 106 +++++++++++++++++++++ .../compiler-builtins/libm/src/math/generic/mod.rs | 2 + 5 files changed, 114 insertions(+), 93 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/floor.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index c75152f6301..6a865f42784 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -336,14 +336,16 @@ "src/libm_helper.rs", "src/math/arch/i586.rs", "src/math/arch/wasm32.rs", - "src/math/floor.rs" + "src/math/floor.rs", + "src/math/generic/floor.rs" ], "type": "f64" }, "floorf": { "sources": [ "src/math/arch/wasm32.rs", - "src/math/floorf.rs" + "src/math/floorf.rs", + "src/math/generic/floor.rs" ], "type": "f32" }, diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index 2823bf44d9c..b4f02abc491 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -1,8 +1,3 @@ -#![allow(unreachable_code)] -use core::f64; - -const TOINT: f64 = 1. / f64::EPSILON; - /// Floor (f64) /// /// Finds the nearest integer less than or equal to `x`. @@ -15,39 +10,5 @@ pub fn floor(x: f64) -> f64 { args: x, } - let ui = x.to_bits(); - let e = ((ui >> 52) & 0x7ff) as i32; - - if (e >= 0x3ff + 52) || (x == 0.) { - return x; - } - /* y = int(x) - x, where int(x) is an integer neighbor of x */ - let y = if (ui >> 63) != 0 { x - TOINT + TOINT - x } else { x + TOINT - TOINT - x }; - /* special case because of non-nearest rounding modes */ - if e < 0x3ff { - force_eval!(y); - return if (ui >> 63) != 0 { -1. } else { 0. }; - } - if y > 0. { x + y - 1. } else { x + y } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(floor(1.1), 1.0); - assert_eq!(floor(2.9), 2.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor - #[test] - fn spec_tests() { - // Not Asserted: that the current rounding mode has no effect. - assert!(floor(f64::NAN).is_nan()); - for f in [0.0, -0.0, f64::INFINITY, f64::NEG_INFINITY].iter().copied() { - assert_eq!(floor(f), f); - } - } + return super::generic::floor(x); } diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 23a18c0f737..16957b7f355 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -1,5 +1,3 @@ -use core::f32; - /// Floor (f32) /// /// Finds the nearest integer less than or equal to `x`. @@ -11,53 +9,5 @@ pub fn floorf(x: f32) -> f32 { args: x, } - let mut ui = x.to_bits(); - let e = (((ui >> 23) as i32) & 0xff) - 0x7f; - - if e >= 23 { - return x; - } - if e >= 0 { - let m: u32 = 0x007fffff >> e; - if (ui & m) == 0 { - return x; - } - force_eval!(x + f32::from_bits(0x7b800000)); - if ui >> 31 != 0 { - ui += m; - } - ui &= !m; - } else { - force_eval!(x + f32::from_bits(0x7b800000)); - if ui >> 31 == 0 { - ui = 0; - } else if ui << 1 != 0 { - return -1.0; - } - } - f32::from_bits(ui) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(floorf(0.5), 0.0); - assert_eq!(floorf(1.1), 1.0); - assert_eq!(floorf(2.9), 2.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor - #[test] - fn spec_tests() { - // Not Asserted: that the current rounding mode has no effect. - assert!(floorf(f32::NAN).is_nan()); - for f in [0.0, -0.0, f32::INFINITY, f32::NEG_INFINITY].iter().copied() { - assert_eq!(floorf(f), f); - } - } + return super::generic::floor(x); } diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs new file mode 100644 index 00000000000..6754c08f870 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/floor.rs @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: MIT + * origin: musl src/math/floor.c */ + +//! Generic `floor` algorithm. +//! +//! Note that this uses the algorithm from musl's `floorf` rather than `floor` or `floorl` because +//! performance seems to be better (based on icount) and it does not seem to experience rounding +//! errors on i386. + +use super::super::{Float, Int, IntTy, MinInt}; + +pub fn floor(x: F) -> F { + let zero = IntTy::::ZERO; + + let mut ix = x.to_bits(); + let e = x.exp_unbiased(); + + // If the represented value has no fractional part, no truncation is needed. + if e >= F::SIG_BITS as i32 { + return x; + } + + if e >= 0 { + // |x| >= 1.0 + + let m = F::SIG_MASK >> e.unsigned(); + if ix & m == zero { + // Portion to be masked is already zero; no adjustment needed. + return x; + } + + // Otherwise, raise an inexact exception. + force_eval!(x + F::MAX); + + if x.is_sign_negative() { + ix += m; + } + + ix &= !m; + F::from_bits(ix) + } else { + // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). + force_eval!(x + F::MAX); + + if x.is_sign_positive() { + // 0.0 <= x < 1.0; rounding down goes toward +0.0. + F::ZERO + } else if ix << 1 != zero { + // -1.0 < x < 0.0; rounding down goes toward -1.0. + F::NEG_ONE + } else { + // -0.0 remains unchanged + x + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Test against https://en.cppreference.com/w/cpp/numeric/math/floor + fn spec_test() { + // Not Asserted: that the current rounding mode has no effect. + for f in [F::ZERO, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY].iter().copied() { + assert_biteq!(floor(f), f); + } + } + + /* Skipping f16 / f128 "sanity_check"s due to rejected literal lexing at MSRV */ + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(floor(0.5f32), 0.0); + assert_eq!(floor(1.1f32), 1.0); + assert_eq!(floor(2.9f32), 2.0); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(floor(1.1f64), 1.0); + assert_eq!(floor(2.9f64), 2.0); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index f8bb9fa6adb..b08a77d5d64 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -2,6 +2,7 @@ mod ceil; mod copysign; mod fabs; mod fdim; +mod floor; mod sqrt; mod trunc; @@ -9,5 +10,6 @@ pub use ceil::ceil; pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; +pub use floor::floor; pub use sqrt::sqrt; pub use trunc::trunc; -- cgit 1.4.1-3-g733a5 From 6a8bb0fa80ba2e777dea045441a0a879c4247b93 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 13:33:24 +0000 Subject: Add `floorf16` and `floorf128` Use the generic algorithms to provide implementations for these routines. --- .../libm/crates/compiler-builtins-smoke-test/src/lib.rs | 2 ++ .../libm/crates/libm-macros/src/shared.rs | 4 ++-- .../libm/crates/libm-test/benches/icount.rs | 2 ++ .../libm/crates/libm-test/benches/random.rs | 4 +++- .../compiler-builtins/libm/crates/libm-test/src/mpfloat.rs | 4 ++++ .../libm/crates/libm-test/tests/compare_built_musl.rs | 2 ++ library/compiler-builtins/libm/crates/util/src/main.rs | 2 ++ .../compiler-builtins/libm/etc/function-definitions.json | 14 ++++++++++++++ library/compiler-builtins/libm/etc/function-list.txt | 2 ++ library/compiler-builtins/libm/src/math/floorf128.rs | 7 +++++++ library/compiler-builtins/libm/src/math/floorf16.rs | 7 +++++++ library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ 12 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/floorf128.rs create mode 100644 library/compiler-builtins/libm/src/math/floorf16.rs diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index b9521eb0715..4834ba256eb 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -97,6 +97,8 @@ no_mangle! { fdimf16(x: f16, y: f16) -> f16; floor(x: f64) -> f64; floorf(x: f32) -> f32; + floorf128(x: f128) -> f128; + floorf16(x: f16) -> f16; fma(x: f64, y: f64, z: f64) -> f64; fmaf(x: f32, y: f32, z: f32) -> f32; fmax(x: f64, y: f64) -> f64; diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index e7d3d18d9a1..64623658d65 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["ceilf16", "fabsf16", "sqrtf16", "truncf16"], + &["ceilf16", "fabsf16", "floorf16", "sqrtf16", "truncf16"], ), ( // `fn(f32) -> f32` @@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["ceilf128", "fabsf128", "sqrtf128", "truncf128"], + &["ceilf128", "fabsf128", "floorf128", "sqrtf128", "truncf128"], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 84be3d5245b..eae63619c57 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -101,6 +101,8 @@ main!( icount_bench_fdimf16_group, icount_bench_fdimf_group, icount_bench_floor_group, + icount_bench_floorf128_group, + icount_bench_floorf16_group, icount_bench_floorf_group, icount_bench_fma_group, icount_bench_fmaf_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 511e26d9126..bd7b3597196 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -125,8 +125,10 @@ libm_macros::for_each_function! { | fabsf16 | fdimf128 | fdimf16 - | sqrtf16 + | floorf128 + | floorf16 | sqrtf128 + | sqrtf16 | truncf128 | truncf16 => (false, None), diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index bbd19dbb07b..53fade7d0ef 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -148,6 +148,8 @@ libm_macros::for_each_function! { fabsf128, fabsf16,floor, floorf, + floorf128, + floorf16, fmod, fmodf, frexp, @@ -240,6 +242,7 @@ impl_no_round! { impl_no_round! { fabsf16 => abs_mut; ceilf16 => ceil_mut; + floorf16 => floor_mut; truncf16 => trunc_mut; } @@ -247,6 +250,7 @@ impl_no_round! { impl_no_round! { fabsf128 => abs_mut; ceilf128 => ceil_mut; + floorf128 => floor_mut; truncf128 => trunc_mut; } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index e13acf3de21..335496fce36 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -87,6 +87,8 @@ libm_macros::for_each_function! { fabsf16, fdimf128, fdimf16, + floorf128, + floorf16, truncf128, truncf16, sqrtf16, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 810919339ec..988c01d0760 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -92,6 +92,8 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fabsf16 | fdimf128 | fdimf16 + | floorf128 + | floorf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 6a865f42784..eef176fb57c 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -349,6 +349,20 @@ ], "type": "f32" }, + "floorf128": { + "sources": [ + "src/math/floorf128.rs", + "src/math/generic/floor.rs" + ], + "type": "f128" + }, + "floorf16": { + "sources": [ + "src/math/floorf16.rs", + "src/math/generic/floor.rs" + ], + "type": "f16" + }, "fma": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 337e7e434e5..3bb895f4a29 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -49,6 +49,8 @@ fdimf128 fdimf16 floor floorf +floorf128 +floorf16 fma fmaf fmax diff --git a/library/compiler-builtins/libm/src/math/floorf128.rs b/library/compiler-builtins/libm/src/math/floorf128.rs new file mode 100644 index 00000000000..9a9fe415115 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/floorf128.rs @@ -0,0 +1,7 @@ +/// Floor (f128) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf128(x: f128) -> f128 { + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/src/math/floorf16.rs b/library/compiler-builtins/libm/src/math/floorf16.rs new file mode 100644 index 00000000000..f9b868e0410 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/floorf16.rs @@ -0,0 +1,7 @@ +/// Floor (f16) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf16(x: f16) -> f16 { + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 5228e78b7f3..68d201524b4 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -345,6 +345,7 @@ cfg_if! { mod copysignf16; mod fabsf16; mod fdimf16; + mod floorf16; mod sqrtf16; mod truncf16; @@ -352,6 +353,7 @@ cfg_if! { pub use self::copysignf16::copysignf16; pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; + pub use self::floorf16::floorf16; pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; } @@ -363,6 +365,7 @@ cfg_if! { mod copysignf128; mod fabsf128; mod fdimf128; + mod floorf128; mod sqrtf128; mod truncf128; @@ -370,6 +373,7 @@ cfg_if! { pub use self::copysignf128::copysignf128; pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; + pub use self::floorf128::floorf128; pub use self::sqrtf128::sqrtf128; pub use self::truncf128::truncf128; } -- cgit 1.4.1-3-g733a5 From 3ae70a4a6cdf1bd11be554ac3ba272707ce8da56 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 08:48:02 +0000 Subject: Adjust `ceil` style to be more similar to `floor` --- .../libm/crates/compiler-builtins-smoke-test/src/lib.rs | 2 ++ library/compiler-builtins/libm/src/math/generic/ceil.rs | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index 4834ba256eb..1a7aa983ee4 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -67,6 +67,8 @@ no_mangle! { cbrtf(x: f32) -> f32; ceil(x: f64) -> f64; ceilf(x: f32) -> f32; + ceilf128(x: f128) -> f128; + ceilf16(x: f16) -> f16; copysign(x: f64, y: f64) -> f64; copysignf(x: f32, y: f32) -> f32; copysignf128(x: f128, y: f128) -> f128; diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs index 34261faf782..971a4d3d8c5 100644 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -31,24 +31,28 @@ pub fn ceil(x: F) -> F { // Otherwise, raise an inexact exception. force_eval!(x + F::MAX); + if x.is_sign_positive() { ix += m; } + ix &= !m; + F::from_bits(ix) } else { // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). force_eval!(x + F::MAX); if x.is_sign_negative() { // -1.0 < x <= -0.0; rounding up goes toward -0.0. - return F::NEG_ZERO; + F::NEG_ZERO } else if ix << 1 != zero { // 0.0 < x < 1.0; rounding up goes toward +1.0. - return F::ONE; + F::ONE + } else { + // +0.0 remains unchanged + x } } - - F::from_bits(ix) } #[cfg(test)] -- cgit 1.4.1-3-g733a5 From bf2d171b1a29849b745cfd0dd6409c0c2b3c0cea Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 09:06:26 +0000 Subject: Add a generic version of `rint` Use this to implement `rint` and `rintf`. --- .../libm/etc/function-definitions.json | 2 + .../compiler-builtins/libm/src/math/generic/mod.rs | 2 + .../libm/src/math/generic/rint.rs | 72 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/rint.rs | 48 +-------------- library/compiler-builtins/libm/src/math/rintf.rs | 48 +-------------- 5 files changed, 78 insertions(+), 94 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/rint.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index eef176fb57c..86b0882927c 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -654,6 +654,7 @@ "src/libm_helper.rs", "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", + "src/math/generic/rint.rs", "src/math/rint.rs" ], "type": "f64" @@ -662,6 +663,7 @@ "sources": [ "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", + "src/math/generic/rint.rs", "src/math/rintf.rs" ], "type": "f32" diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index b08a77d5d64..d3df650e1a5 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -3,6 +3,7 @@ mod copysign; mod fabs; mod fdim; mod floor; +mod rint; mod sqrt; mod trunc; @@ -11,5 +12,6 @@ pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; +pub use rint::rint; pub use sqrt::sqrt; pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs new file mode 100644 index 00000000000..80ba1faac31 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/rint.c */ + +use super::super::Float; + +pub fn rint(x: F) -> F { + let toint = F::ONE / F::EPSILON; + let e = x.exp(); + let positive = x.is_sign_positive(); + + // On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise, + // the excess precission from x87 would cause an incorrect final result. + let use_force = cfg!(x86_no_sse) && F::BITS == 32 || F::BITS == 64; + + if e >= F::EXP_BIAS + F::SIG_BITS { + // No fractional part; exact result can be returned. + x + } else { + // Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode. + let y = if positive { + let tmp = if use_force { force_eval!(x) } else { x } + toint; + (if use_force { force_eval!(tmp) } else { tmp } - toint) + } else { + let tmp = if use_force { force_eval!(x) } else { x } - toint; + (if use_force { force_eval!(tmp) } else { tmp } + toint) + }; + + if y == F::ZERO { + // A zero result takes the sign of the input. + if positive { F::ZERO } else { F::NEG_ZERO } + } else { + y + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn zeroes_f32() { + assert_biteq!(rint(0.0_f32), 0.0_f32); + assert_biteq!(rint(-0.0_f32), -0.0_f32); + } + + #[test] + fn sanity_check_f32() { + assert_biteq!(rint(-1.0_f32), -1.0); + assert_biteq!(rint(2.8_f32), 3.0); + assert_biteq!(rint(-0.5_f32), -0.0); + assert_biteq!(rint(0.5_f32), 0.0); + assert_biteq!(rint(-1.5_f32), -2.0); + assert_biteq!(rint(1.5_f32), 2.0); + } + + #[test] + fn zeroes_f64() { + assert_biteq!(rint(0.0_f64), 0.0_f64); + assert_biteq!(rint(-0.0_f64), -0.0_f64); + } + + #[test] + fn sanity_check_f64() { + assert_biteq!(rint(-1.0_f64), -1.0); + assert_biteq!(rint(2.8_f64), 3.0); + assert_biteq!(rint(-0.5_f64), -0.0); + assert_biteq!(rint(0.5_f64), 0.0); + assert_biteq!(rint(-1.5_f64), -2.0); + assert_biteq!(rint(1.5_f64), 2.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index c9ea6402ec7..592583aa5e5 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -9,51 +9,5 @@ pub fn rint(x: f64) -> f64 { args: x, } - let one_over_e = 1.0 / f64::EPSILON; - let as_u64: u64 = x.to_bits(); - let exponent: u64 = (as_u64 >> 52) & 0x7ff; - let is_positive = (as_u64 >> 63) == 0; - if exponent >= 0x3ff + 52 { - x - } else { - let ans = if is_positive { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xplusoneovere = x + one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xplusoneovere = force_eval!(xplusoneovere); - xplusoneovere - one_over_e - } else { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xminusoneovere = x - one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xminusoneovere = force_eval!(xminusoneovere); - xminusoneovere + one_over_e - }; - - if ans == 0.0 { if is_positive { 0.0 } else { -0.0 } } else { ans } - } -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::rint; - - #[test] - fn negative_zero() { - assert_eq!(rint(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(rint(-1.0), -1.0); - assert_eq!(rint(2.8), 3.0); - assert_eq!(rint(-0.5), -0.0); - assert_eq!(rint(0.5), 0.0); - assert_eq!(rint(-1.5), -2.0); - assert_eq!(rint(1.5), 2.0); - } + super::generic::rint(x) } diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 33b5b3ddebf..56666df1154 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -9,51 +9,5 @@ pub fn rintf(x: f32) -> f32 { args: x, } - let one_over_e = 1.0 / f32::EPSILON; - let as_u32: u32 = x.to_bits(); - let exponent: u32 = (as_u32 >> 23) & 0xff; - let is_positive = (as_u32 >> 31) == 0; - if exponent >= 0x7f + 23 { - x - } else { - let ans = if is_positive { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xplusoneovere = x + one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xplusoneovere = force_eval!(xplusoneovere); - xplusoneovere - one_over_e - } else { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xminusoneovere = x - one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xminusoneovere = force_eval!(xminusoneovere); - xminusoneovere + one_over_e - }; - - if ans == 0.0 { if is_positive { 0.0 } else { -0.0 } } else { ans } - } -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::rintf; - - #[test] - fn negative_zero() { - assert_eq!(rintf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(rintf(-1.0), -1.0); - assert_eq!(rintf(2.8), 3.0); - assert_eq!(rintf(-0.5), -0.0); - assert_eq!(rintf(0.5), 0.0); - assert_eq!(rintf(-1.5), -2.0); - assert_eq!(rintf(1.5), 2.0); - } + super::generic::rint(x) } -- cgit 1.4.1-3-g733a5 From b22398d6580d1f90e020404e427b06403d204c9f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 10:58:29 +0000 Subject: Add `rintf16` and `rintf128` Use the generic algorithms to provide implementations for these routines. --- .../libm/crates/compiler-builtins-smoke-test/src/lib.rs | 2 ++ .../libm/crates/libm-macros/src/shared.rs | 4 ++-- .../libm/crates/libm-test/benches/icount.rs | 2 ++ .../libm/crates/libm-test/benches/random.rs | 2 ++ .../compiler-builtins/libm/crates/libm-test/src/mpfloat.rs | 8 ++++++-- .../libm/crates/libm-test/tests/compare_built_musl.rs | 6 ++++-- library/compiler-builtins/libm/crates/util/src/main.rs | 2 ++ .../compiler-builtins/libm/etc/function-definitions.json | 14 ++++++++++++++ library/compiler-builtins/libm/etc/function-list.txt | 2 ++ library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ library/compiler-builtins/libm/src/math/rint.rs | 1 + library/compiler-builtins/libm/src/math/rintf.rs | 1 + library/compiler-builtins/libm/src/math/rintf128.rs | 5 +++++ library/compiler-builtins/libm/src/math/rintf16.rs | 5 +++++ 14 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/rintf128.rs create mode 100644 library/compiler-builtins/libm/src/math/rintf16.rs diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index 1a7aa983ee4..ccd0642a20e 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -145,6 +145,8 @@ no_mangle! { remquof(x: f32, y: f32 | q: &mut c_int) -> f32; rint(x: f64) -> f64; rintf(x: f32) -> f32; + rintf128(x: f128) -> f128; + rintf16(x: f16) -> f16; round(x: f64) -> f64; roundf(x: f32) -> f32; scalbn(x: f64, y: c_int) -> f64; diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 64623658d65..80bd3e90753 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["ceilf16", "fabsf16", "floorf16", "sqrtf16", "truncf16"], + &["ceilf16", "fabsf16", "floorf16", "rintf16", "sqrtf16", "truncf16"], ), ( // `fn(f32) -> f32` @@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["ceilf128", "fabsf128", "floorf128", "sqrtf128", "truncf128"], + &["ceilf128", "fabsf128", "floorf128", "rintf128", "sqrtf128", "truncf128"], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index eae63619c57..84f95326267 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -149,6 +149,8 @@ main!( icount_bench_remquo_group, icount_bench_remquof_group, icount_bench_rint_group, + icount_bench_rintf128_group, + icount_bench_rintf16_group, icount_bench_rintf_group, icount_bench_round_group, icount_bench_roundf_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index bd7b3597196..4d050e817e2 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -127,6 +127,8 @@ libm_macros::for_each_function! { | fdimf16 | floorf128 | floorf16 + | rintf128 + | rintf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 53fade7d0ef..a404f227b26 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -170,6 +170,8 @@ libm_macros::for_each_function! { remquof, rint, rintf, + rintf128, + rintf16, round, roundf, scalbn, @@ -240,17 +242,19 @@ impl_no_round! { #[cfg(f16_enabled)] impl_no_round! { - fabsf16 => abs_mut; ceilf16 => ceil_mut; + fabsf16 => abs_mut; floorf16 => floor_mut; + rintf16 => round_even_mut; // FIXME: respect rounding mode truncf16 => trunc_mut; } #[cfg(f128_enabled)] impl_no_round! { - fabsf128 => abs_mut; ceilf128 => ceil_mut; + fabsf128 => abs_mut; floorf128 => floor_mut; + rintf128 => round_even_mut; // FIXME: respect rounding mode truncf128 => trunc_mut; } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 335496fce36..f009816c97f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -89,9 +89,11 @@ libm_macros::for_each_function! { fdimf16, floorf128, floorf16, + rintf128, + rintf16, + sqrtf128, + sqrtf16, truncf128, truncf16, - sqrtf16, - sqrtf128, ], } diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 988c01d0760..41d995b3b39 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -94,6 +94,8 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fdimf16 | floorf128 | floorf16 + | rintf128 + | rintf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 86b0882927c..d3810b940cb 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -668,6 +668,20 @@ ], "type": "f32" }, + "rintf128": { + "sources": [ + "src/math/generic/rint.rs", + "src/math/rintf128.rs" + ], + "type": "f128" + }, + "rintf16": { + "sources": [ + "src/math/generic/rint.rs", + "src/math/rintf16.rs" + ], + "type": "f16" + }, "round": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 3bb895f4a29..41bb4e06be8 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -97,6 +97,8 @@ remquo remquof rint rintf +rintf128 +rintf16 round roundf scalbn diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 68d201524b4..53d06974cee 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -346,6 +346,7 @@ cfg_if! { mod fabsf16; mod fdimf16; mod floorf16; + mod rintf16; mod sqrtf16; mod truncf16; @@ -354,6 +355,7 @@ cfg_if! { pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; pub use self::floorf16::floorf16; + pub use self::rintf16::rintf16; pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; } @@ -366,6 +368,7 @@ cfg_if! { mod fabsf128; mod fdimf128; mod floorf128; + mod rintf128; mod sqrtf128; mod truncf128; @@ -374,6 +377,7 @@ cfg_if! { pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; + pub use self::rintf128::rintf128; pub use self::sqrtf128::sqrtf128; pub use self::truncf128::truncf128; } diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 592583aa5e5..f409ec2821d 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -1,3 +1,4 @@ +/// Round `x` to the nearest integer, breaking ties toward even. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rint(x: f64) -> f64 { select_implementation! { diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 56666df1154..5e9f5f71876 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -1,3 +1,4 @@ +/// Round `x` to the nearest integer, breaking ties toward even. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rintf(x: f32) -> f32 { select_implementation! { diff --git a/library/compiler-builtins/libm/src/math/rintf128.rs b/library/compiler-builtins/libm/src/math/rintf128.rs new file mode 100644 index 00000000000..6b16fcd841a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rintf128.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf128(x: f128) -> f128 { + super::generic::rint(x) +} diff --git a/library/compiler-builtins/libm/src/math/rintf16.rs b/library/compiler-builtins/libm/src/math/rintf16.rs new file mode 100644 index 00000000000..84d792561f7 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rintf16.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf16(x: f16) -> f16 { + super::generic::rint(x) +} -- cgit 1.4.1-3-g733a5 From c788ced5022520ed2adbdbb788c18478b8f201b2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 21:31:06 +0000 Subject: Add the ability to parse hex, binary, and float hex with util --- .../compiler-builtins/libm/crates/util/src/main.rs | 94 ++++++++++++++++++++-- 1 file changed, 89 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 41d995b3b39..23aed06c00d 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -5,10 +5,12 @@ use std::any::type_name; use std::env; +use std::num::ParseIntError; use std::str::FromStr; #[cfg(feature = "build-mpfr")] use az::Az; +use libm::support::{hf32, hf64}; #[cfg(feature = "build-mpfr")] use libm_test::mpfloat::MpOp; use libm_test::{MathOp, TupleCall}; @@ -238,21 +240,103 @@ impl_parse_tuple_via_rug!(f16); impl_parse_tuple_via_rug!(f128); /// Try to parse the number, printing a nice message on failure. -fn parse(input: &[&str], idx: usize) -> F { +fn parse(input: &[&str], idx: usize) -> T { let s = input[idx]; - s.parse().unwrap_or_else(|_| panic!("invalid {} input '{s}'", type_name::())) + + let msg = || format!("invalid {} input '{s}'", type_name::()); + + if s.starts_with("0x") { + return T::from_str_radix(s, 16).unwrap_or_else(|_| panic!("{}", msg())); + } + + if s.starts_with("0b") { + return T::from_str_radix(s, 2).unwrap_or_else(|_| panic!("{}", msg())); + } + + s.parse().unwrap_or_else(|_| panic!("{}", msg())) } /// Try to parse the float type going via `rug`, for `f16` and `f128` which don't yet implement /// `FromStr`. #[cfg(feature = "build-mpfr")] -fn parse_rug(input: &[&str], idx: usize) -> F +fn parse_rug(input: &[&str], idx: usize) -> F where + F: libm_test::Float + FromStrRadix, rug::Float: az::Cast, { let s = input[idx]; - let x = - rug::Float::parse(s).unwrap_or_else(|_| panic!("invalid {} input '{s}'", type_name::())); + + let msg = || format!("invalid {} input '{s}'", type_name::()); + + if s.starts_with("0x") { + return F::from_str_radix(s, 16).unwrap_or_else(|_| panic!("{}", msg())); + } + + if s.starts_with("0b") { + return F::from_str_radix(s, 2).unwrap_or_else(|_| panic!("{}", msg())); + } + + let x = rug::Float::parse(s).unwrap_or_else(|_| panic!("{}", msg())); let x = rug::Float::with_val(F::BITS, x); x.az() } + +trait FromStrRadix: Sized { + fn from_str_radix(s: &str, radix: u32) -> Result; +} + +impl FromStrRadix for i32 { + fn from_str_radix(s: &str, radix: u32) -> Result { + let s = strip_radix_prefix(s, radix); + i32::from_str_radix(s, radix) + } +} + +#[cfg(f16_enabled)] +impl FromStrRadix for f16 { + fn from_str_radix(s: &str, radix: u32) -> Result { + let s = strip_radix_prefix(s, radix); + u16::from_str_radix(s, radix).map(Self::from_bits) + } +} + +impl FromStrRadix for f32 { + fn from_str_radix(s: &str, radix: u32) -> Result { + if radix == 16 && s.contains("p") { + // Parse as hex float + return Ok(hf32(s)); + } + + let s = strip_radix_prefix(s, radix); + u32::from_str_radix(s, radix).map(Self::from_bits) + } +} + +impl FromStrRadix for f64 { + fn from_str_radix(s: &str, radix: u32) -> Result { + if s.contains("p") { + return Ok(hf64(s)); + } + + let s = strip_radix_prefix(s, radix); + u64::from_str_radix(s, radix).map(Self::from_bits) + } +} + +#[cfg(f128_enabled)] +impl FromStrRadix for f128 { + fn from_str_radix(s: &str, radix: u32) -> Result { + let s = strip_radix_prefix(s, radix); + u128::from_str_radix(s, radix).map(Self::from_bits) + } +} + +fn strip_radix_prefix(s: &str, radix: u32) -> &str { + if radix == 16 { + s.strip_prefix("0x").unwrap() + } else if radix == 2 { + s.strip_prefix("0b").unwrap() + } else { + s + } +} -- cgit 1.4.1-3-g733a5 From 42e22132b41f3ee3839355513173854f17b460f5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 23:01:29 +0000 Subject: Fix the parsing of three-item tuples in `util` --- library/compiler-builtins/libm/crates/util/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 23aed06c00d..889823d2e4a 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -146,8 +146,8 @@ macro_rules! impl_parse_tuple { impl ParseTuple for ($ty, $ty, $ty) { fn parse(input: &[&str]) -> Self { - assert_eq!(input.len(), 2, "expected three arguments, got {input:?}"); - (parse(input, 0), parse(input, 1), parse(input, 3)) + assert_eq!(input.len(), 3, "expected three arguments, got {input:?}"); + (parse(input, 0), parse(input, 1), parse(input, 2)) } } }; @@ -187,8 +187,8 @@ macro_rules! impl_parse_tuple_via_rug { impl ParseTuple for ($ty, $ty, $ty) { fn parse(input: &[&str]) -> Self { - assert_eq!(input.len(), 2, "expected three arguments, got {input:?}"); - (parse_rug(input, 0), parse_rug(input, 1), parse_rug(input, 3)) + assert_eq!(input.len(), 3, "expected three arguments, got {input:?}"); + (parse_rug(input, 0), parse_rug(input, 1), parse_rug(input, 2)) } } }; -- cgit 1.4.1-3-g733a5 From 8dc4ef6f0fb9df5da1bcd9931c018d9233595d53 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 22:41:49 +0000 Subject: Add `hf16!` and `hf128!` Expand the existing hex float functions and macros with versions that work with `f16` and `f128`. --- .../libm/src/math/support/hex_float.rs | 246 ++++++++++++++++++++- .../libm/src/math/support/macros.rs | 22 ++ .../compiler-builtins/libm/src/math/support/mod.rs | 4 + 3 files changed, 266 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index 1666c615360..949f21a57ff 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -4,6 +4,12 @@ use super::{f32_from_bits, f64_from_bits}; +/// Construct a 16-bit float from hex float representation (C-style) +#[cfg(f16_enabled)] +pub const fn hf16(s: &str) -> f16 { + f16::from_bits(parse_any(s, 16, 10) as u16) +} + /// Construct a 32-bit float from hex float representation (C-style) pub const fn hf32(s: &str) -> f32 { f32_from_bits(parse_any(s, 32, 23) as u32) @@ -14,6 +20,12 @@ pub const fn hf64(s: &str) -> f64 { f64_from_bits(parse_any(s, 64, 52) as u64) } +/// Construct a 128-bit float from hex float representation (C-style) +#[cfg(f128_enabled)] +pub const fn hf128(s: &str) -> f128 { + f128::from_bits(parse_any(s, 128, 112)) +} + const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 { let exp_bits: u32 = bits - sig_bits - 1; let max_msb: i32 = (1 << (exp_bits - 1)) - 1; @@ -230,6 +242,57 @@ mod tests { } } + // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to + // hide them from the AST. + #[cfg(f16_enabled)] + macro_rules! f16_tests { + () => { + #[test] + fn test_f16() { + let checks = [ + ("0x.1234p+16", (0x1234 as f16).to_bits()), + ("0x1.234p+12", (0x1234 as f16).to_bits()), + ("0x12.34p+8", (0x1234 as f16).to_bits()), + ("0x123.4p+4", (0x1234 as f16).to_bits()), + ("0x1234p+0", (0x1234 as f16).to_bits()), + ("0x1234.p+0", (0x1234 as f16).to_bits()), + ("0x1234.0p+0", (0x1234 as f16).to_bits()), + ("0x1.ffcp+15", f16::MAX.to_bits()), + ("0x1.0p+1", 2.0f16.to_bits()), + ("0x1.0p+0", 1.0f16.to_bits()), + ("0x1.ffp+8", 0x5ffc), + ("+0x1.ffp+8", 0x5ffc), + ("0x1p+0", 0x3c00), + ("0x1.998p-4", 0x2e66), + ("0x1.9p+6", 0x5640), + ("0x0.0p0", 0.0f16.to_bits()), + ("-0x0.0p0", (-0.0f16).to_bits()), + ("0x1.0p0", 1.0f16.to_bits()), + ("0x1.998p-4", (0.1f16).to_bits()), + ("-0x1.998p-4", (-0.1f16).to_bits()), + ("0x0.123p-12", 0x0123), + ("0x1p-24", 0x0001), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + let act = hf16(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#06x} != {exp:#06x}\nact: {act:#018b}\nexp: {exp:#018b}" + ); + } + } + + #[test] + fn test_macros_f16() { + assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); + } + }; + } + + #[cfg(f16_enabled)] + f16_tests!(); + #[test] fn test_f32() { let checks = [ @@ -308,16 +371,67 @@ mod tests { } } - #[test] - fn test_f32_almost_extra_precision() { - // Exact maximum precision allowed - hf32("0x1.abcdeep+0"); + // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to + // hide them from the AST. + #[cfg(f128_enabled)] + macro_rules! f128_tests { + () => { + #[test] + fn test_f128() { + let checks = [ + ("0x.1234p+16", (0x1234 as f128).to_bits()), + ("0x1.234p+12", (0x1234 as f128).to_bits()), + ("0x12.34p+8", (0x1234 as f128).to_bits()), + ("0x123.4p+4", (0x1234 as f128).to_bits()), + ("0x1234p+0", (0x1234 as f128).to_bits()), + ("0x1234.p+0", (0x1234 as f128).to_bits()), + ("0x1234.0p+0", (0x1234 as f128).to_bits()), + ("0x1.ffffffffffffffffffffffffffffp+16383", f128::MAX.to_bits()), + ("0x1.0p+1", 2.0f128.to_bits()), + ("0x1.0p+0", 1.0f128.to_bits()), + ("0x1.ffep+8", 0x4007ffe0000000000000000000000000), + ("+0x1.ffep+8", 0x4007ffe0000000000000000000000000), + ("0x1p+0", 0x3fff0000000000000000000000000000), + ("0x1.999999999999999999999999999ap-4", 0x3ffb999999999999999999999999999a), + ("0x1.9p+6", 0x40059000000000000000000000000000), + ("0x0.0p0", 0.0f128.to_bits()), + ("-0x0.0p0", (-0.0f128).to_bits()), + ("0x1.0p0", 1.0f128.to_bits()), + ("0x1.999999999999999999999999999ap-4", (0.1f128).to_bits()), + ("-0x1.999999999999999999999999999ap-4", (-0.1f128).to_bits()), + ("0x0.abcdef0123456789abcdef012345p-16382", 0x0000abcdef0123456789abcdef012345), + ("0x1p-16494", 0x00000000000000000000000000000001), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + let act = hf128(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#034x} != {exp:#034x}\nact: {act:#0130b}\nexp: {exp:#0130b}" + ); + } + } + + #[test] + fn test_macros_f128() { + assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); + } + } } + #[cfg(f128_enabled)] + f128_tests!(); + #[test] fn test_macros() { - assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000u32); - assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000u64); + // FIXME(msrv): enable once parsing works + // #[cfg(f16_enabled)] + // assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); + assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000_u32); + assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000_u64); + // FIXME(msrv): enable once parsing works + // #[cfg(f128_enabled)] + // assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); } } @@ -328,6 +442,69 @@ mod tests_panicking { extern crate std; use super::*; + // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to + // hide them from the AST. + #[cfg(f16_enabled)] + macro_rules! f16_tests { + () => { + #[test] + fn test_f16_almost_extra_precision() { + // Exact maximum precision allowed + hf16("0x1.ffcp+0"); + } + + #[test] + #[should_panic(expected = "the value is too precise")] + fn test_f16_extra_precision() { + // One bit more than the above. + hf16("0x1.ffdp+0"); + } + + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f16_overflow() { + // One bit more than the above. + hf16("0x1p+16"); + } + + #[test] + fn test_f16_tiniest() { + let x = hf16("0x1.p-24"); + let y = hf16("0x0.001p-12"); + let z = hf16("0x0.8p-23"); + assert_eq!(x, y); + assert_eq!(x, z); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f16_too_tiny() { + hf16("0x1.p-25"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f16_also_too_tiny() { + hf16("0x0.8p-24"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f16_again_too_tiny() { + hf16("0x0.001p-13"); + } + }; + } + + #[cfg(f16_enabled)] + f16_tests!(); + + #[test] + fn test_f32_almost_extra_precision() { + // Exact maximum precision allowed + hf32("0x1.abcdeep+0"); + } + #[test] #[should_panic] fn test_f32_extra_precision2() { @@ -388,4 +565,61 @@ mod tests_panicking { // One bit more than the above. hf64("0x1.abcdabcdabcdf8p+0"); } + + // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to + // hide them from the AST. + #[cfg(f128_enabled)] + macro_rules! f128_tests { + () => { + #[test] + fn test_f128_almost_extra_precision() { + // Exact maximum precision allowed + hf128("0x1.ffffffffffffffffffffffffffffp+16383"); + } + + #[test] + #[should_panic(expected = "the value is too precise")] + fn test_f128_extra_precision() { + // One bit more than the above. + hf128("0x1.ffffffffffffffffffffffffffff8p+16383"); + } + + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f128_overflow() { + // One bit more than the above. + hf128("0x1p+16384"); + } + + #[test] + fn test_f128_tiniest() { + let x = hf128("0x1.p-16494"); + let y = hf128("0x0.0000000000000001p-16430"); + let z = hf128("0x0.8p-16493"); + assert_eq!(x, y); + assert_eq!(x, z); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f128_too_tiny() { + hf128("0x1.p-16495"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f128_again_too_tiny() { + hf128("0x0.0000000000000001p-16431"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f128_also_too_tiny() { + hf128("0x0.8p-16494"); + } + }; + } + + #[cfg(f128_enabled)] + f128_tests!(); } diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index c9a36c0db1a..d8ba04cffe7 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -87,6 +87,17 @@ macro_rules! select_implementation { (@cfg $provided:meta; $ex:expr) => { #[cfg($provided)] $ex }; } +/// Construct a 16-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[cfg(f16_enabled)] +#[allow(unused_macros)] +macro_rules! hf16 { + ($s:literal) => {{ + const X: f16 = $crate::math::support::hf16($s); + X + }}; +} + /// Construct a 32-bit float from hex float representation (C-style), guaranteed to /// evaluate at compile time. #[allow(unused_macros)] @@ -107,6 +118,17 @@ macro_rules! hf64 { }}; } +/// Construct a 128-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[cfg(f128_enabled)] +#[allow(unused_macros)] +macro_rules! hf128 { + ($s:literal) => {{ + const X: f128 = $crate::math::support::hf128($s); + X + }}; +} + /// Assert `F::biteq` with better messages. #[cfg(test)] macro_rules! assert_biteq { diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index ddfc2e3e071..da9e2c9ed62 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -8,6 +8,10 @@ mod int_traits; #[allow(unused_imports)] pub use float_traits::{Float, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; +#[cfg(f16_enabled)] +pub use hex_float::hf16; +#[cfg(f128_enabled)] +pub use hex_float::hf128; #[allow(unused_imports)] pub use hex_float::{hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -- cgit 1.4.1-3-g733a5 From ca8dccc5b6638aba06f4d3c06493500af3146846 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 23 Jan 2025 05:08:10 +0000 Subject: Introduce XFAILs that assert failure Currently our XFAILs are open ended; we do not check that it actually fails, so we have no easy way of knowing that a previously-failing test starts passing. Introduce a new enum that we return from overrides to give us more flexibility here, including the ability to assert that expected failures happen. With the new enum, it is also possible to specify ULP via return value rather than passing a `&mut u32` parameter. This includes refactoring of `precision.rs` to be more accurate about where errors come from, if possible. Fixes: https://github.com/rust-lang/libm/issues/455 --- .../libm/crates/libm-test/src/precision.rs | 461 ++++++++++----------- .../libm/crates/libm-test/src/test_traits.rs | 60 ++- 2 files changed, 268 insertions(+), 253 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 9d17ab8cccf..800425f12ad 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -118,13 +118,13 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { // FIXME(#401): these need to be correctly rounded but are not. Id::Fmaf => ulp = 1, Id::Fdim => ulp = 1, + Id::Round => ulp = 1, Id::Asinh => ulp = 3, Id::Asinhf => ulp = 3, Id::Exp10 | Id::Exp10f => ulp = 1_000_000, Id::Exp2 | Id::Exp2f => ulp = 10_000_000, Id::Log1p | Id::Log1pf => ulp = 2, - Id::Round => ulp = 1, Id::Tan => ulp = 2, _ => (), } @@ -133,12 +133,42 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { ulp } +/// Result of checking for possible overrides. +#[derive(Debug, Default)] +pub enum CheckAction { + /// The check should pass. Default case. + #[default] + AssertSuccess, + + /// Override the ULP for this check. + AssertWithUlp(u32), + + /// Failure is expected, ensure this is the case (xfail). Takes a contxt string to help trace + /// back exactly why we expect this to fail. + AssertFailure(&'static str), + + /// The override somehow validated the result, here it is. + Custom(TestResult), + + /// Disregard the output. + Skip, +} + /// Don't run further validation on this test case. -const SKIP: Option = Some(Ok(())); +const SKIP: CheckAction = CheckAction::Skip; -/// Return this to skip checks on a test that currently fails but shouldn't. Looks -/// the same as skip, but we keep them separate to better indicate purpose. -const XFAIL: Option = Some(Ok(())); +/// Return this to skip checks on a test that currently fails but shouldn't. Takes a description +/// of context. +const XFAIL: fn(&'static str) -> CheckAction = CheckAction::AssertFailure; + +/// Indicates that we expect a test to fail but we aren't asserting that it does (e.g. some results +/// within a range do actually pass). +/// +/// Same as `SKIP`, just indicates we have something to eventually fix. +const XFAIL_NOCHECK: CheckAction = CheckAction::Skip; + +/// By default, all tests should pass. +const DEFAULT: CheckAction = CheckAction::AssertSuccess; /// Allow overriding the outputs of specific test cases. /// @@ -158,19 +188,13 @@ pub trait MaybeOverride { _input: Input, _actual: F, _expected: F, - _ulp: &mut u32, _ctx: &CheckCtx, - ) -> Option { - None + ) -> CheckAction { + DEFAULT } - fn check_int( - _input: Input, - _actual: I, - _expected: I, - _ctx: &CheckCtx, - ) -> Option { - None + fn check_int(_input: Input, _actual: I, _expected: I, _ctx: &CheckCtx) -> CheckAction { + DEFAULT } } @@ -178,33 +202,35 @@ pub trait MaybeOverride { impl MaybeOverride<(f16,)> for SpecialCase {} impl MaybeOverride<(f32,)> for SpecialCase { - fn check_float( - input: (f32,), - actual: F, - expected: F, - _ulp: &mut u32, - ctx: &CheckCtx, - ) -> Option { - if ctx.base_name == BaseName::Expm1 && input.0 > 80.0 && actual.is_infinite() { + fn check_float(input: (f32,), actual: F, expected: F, ctx: &CheckCtx) -> CheckAction { + if ctx.base_name == BaseName::Expm1 + && !input.0.is_infinite() + && input.0 > 80.0 + && actual.is_infinite() + && !expected.is_infinite() + { // we return infinity but the number is representable - return XFAIL; - } - - if ctx.base_name == BaseName::Sinh && input.0.abs() > 80.0 && actual.is_nan() { - // we return some NaN that should be real values or infinite - return XFAIL; + if ctx.basis == CheckBasis::Musl { + return XFAIL_NOCHECK; + } + return XFAIL("expm1 representable numbers"); } - if ctx.base_name == BaseName::Acosh && input.0 < -1.0 { - // acoshf is undefined for x <= 1.0, but we return a random result at lower - // values. - return XFAIL; + if cfg!(x86_no_sse) + && ctx.base_name == BaseName::Exp2 + && !expected.is_infinite() + && actual.is_infinite() + { + // We return infinity when there is a representable value. Test input: 127.97238 + return XFAIL("586 exp2 representable numbers"); } - if ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR && input.0 < 0.0 - { - // loggamma should not be defined for x < 0, yet we both return results - return XFAIL; + if ctx.base_name == BaseName::Sinh && input.0.abs() > 80.0 && actual.is_nan() { + // we return some NaN that should be real values or infinite + if ctx.basis == CheckBasis::Musl { + return XFAIL_NOCHECK; + } + return XFAIL("sinh unexpected NaN"); } if (ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR) @@ -213,32 +239,18 @@ impl MaybeOverride<(f32,)> for SpecialCase { && !actual.is_infinite() { // This result should saturate but we return a finite value. - return XFAIL; + return XFAIL_NOCHECK; } if ctx.base_name == BaseName::J0 && input.0 < -1e34 { // Errors get huge close to -inf - return XFAIL; - } - - if cfg!(x86_no_sse) - && ctx.base_name == BaseName::Exp2 - && !expected.is_infinite() - && actual.is_infinite() - { - // We return infinity when there is a representable value. Test input: 127.97238 - return XFAIL; + return XFAIL_NOCHECK; } - maybe_check_nan_bits(actual, expected, ctx) + unop_common(input, actual, expected, ctx) } - fn check_int( - input: (f32,), - actual: I, - expected: I, - ctx: &CheckCtx, - ) -> Option> { + fn check_int(input: (f32,), actual: I, expected: I, ctx: &CheckCtx) -> CheckAction { // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr @@ -246,37 +258,25 @@ impl MaybeOverride<(f32,)> for SpecialCase { && input.0 == f32::NEG_INFINITY && actual.abs() == expected.abs() { - XFAIL - } else { - None + return XFAIL("lgammar integer result"); } + + DEFAULT } } impl MaybeOverride<(f64,)> for SpecialCase { - fn check_float( - input: (f64,), - actual: F, - expected: F, - _ulp: &mut u32, - ctx: &CheckCtx, - ) -> Option { - if ctx.basis == CheckBasis::Musl { - if cfg!(target_arch = "x86") && ctx.base_name == BaseName::Acosh && input.0 < 1.0 { - // The function is undefined, both implementations return random results - return SKIP; - } - - if cfg!(x86_no_sse) - && ctx.base_name == BaseName::Ceil - && input.0 < 0.0 - && input.0 > -1.0 - && expected == F::ZERO - && actual == F::ZERO - { - // musl returns -0.0, we return +0.0 - return XFAIL; - } + fn check_float(input: (f64,), actual: F, expected: F, ctx: &CheckCtx) -> CheckAction { + if cfg!(x86_no_sse) + && ctx.base_name == BaseName::Ceil + && ctx.basis == CheckBasis::Musl + && input.0 < 0.0 + && input.0 > -1.0 + && expected == F::ZERO + && actual == F::ZERO + { + // musl returns -0.0, we return +0.0 + return XFAIL("i586 ceil signed zero"); } if cfg!(x86_no_sse) @@ -285,53 +285,37 @@ impl MaybeOverride<(f64,)> for SpecialCase { && (expected - actual).abs() > F::ZERO { // Our rounding mode is incorrect. - return XFAIL; - } - - if ctx.base_name == BaseName::Acosh && input.0 < 1.0 { - // The function is undefined for the inputs, musl and our libm both return - // random results. - return XFAIL; - } - - if ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR && input.0 < 0.0 - { - // loggamma should not be defined for x < 0, yet we both return results - return XFAIL; + return XFAIL("i586 rint rounding mode"); } - if ctx.base_name == BaseName::J0 && input.0 < -1e300 { - // Errors get huge close to -inf - return XFAIL; - } - - if (ctx.fn_ident == Identifier::Ceil || ctx.fn_ident == Identifier::Floor) - && cfg!(x86_no_sse) + if cfg!(x86_no_sse) + && (ctx.fn_ident == Identifier::Ceil || ctx.fn_ident == Identifier::Floor) && expected.eq_repr(F::NEG_ZERO) && actual.eq_repr(F::ZERO) { // FIXME: the x87 implementations do not keep the distinction between -0.0 and 0.0. // See https://github.com/rust-lang/libm/pull/404#issuecomment-2572399955 - return XFAIL; + return XFAIL("i586 ceil/floor signed zero"); } - if (ctx.fn_ident == Identifier::Exp10 || ctx.fn_ident == Identifier::Exp2) - && cfg!(x86_no_sse) + if cfg!(x86_no_sse) + && (ctx.fn_ident == Identifier::Exp10 || ctx.fn_ident == Identifier::Exp2) { // FIXME: i586 has very imprecise results with ULP > u32::MAX for these // operations so we can't reasonably provide a limit. - return XFAIL; + return XFAIL_NOCHECK; } - maybe_check_nan_bits(actual, expected, ctx) + if ctx.base_name == BaseName::J0 && input.0 < -1e300 { + // Errors get huge close to -inf + return XFAIL_NOCHECK; + } + + // maybe_check_nan_bits(actual, expected, ctx) + unop_common(input, actual, expected, ctx) } - fn check_int( - input: (f64,), - actual: I, - expected: I, - ctx: &CheckCtx, - ) -> Option> { + fn check_int(input: (f64,), actual: I, expected: I, ctx: &CheckCtx) -> CheckAction { // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr @@ -339,41 +323,68 @@ impl MaybeOverride<(f64,)> for SpecialCase { && input.0 == f64::NEG_INFINITY && actual.abs() == expected.abs() { - XFAIL - } else { - None + return XFAIL("lgammar integer result"); } + + DEFAULT } } #[cfg(f128_enabled)] impl MaybeOverride<(f128,)> for SpecialCase {} -/// Check NaN bits if the function requires it -fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { - if !(ctx.base_name == BaseName::Fabs || ctx.base_name == BaseName::Copysign) { - return None; - } +// F1 and F2 are always the same type, this is just to please generics +fn unop_common( + input: (F1,), + actual: F2, + expected: F2, + ctx: &CheckCtx, +) -> CheckAction { + if ctx.base_name == BaseName::Acosh + && input.0 < F1::NEG_ONE + && !(expected.is_nan() && actual.is_nan()) + { + // acoshf is undefined for x <= 1.0, but we return a random result at lower values. - // LLVM currently uses x87 instructions which quieten signalling NaNs to handle the i686 - // `extern "C"` `f32`/`f64` return ABI. - // LLVM issue - // Rust issue - if cfg!(target_arch = "x86") && ctx.basis == CheckBasis::Musl { - return SKIP; + if ctx.basis == CheckBasis::Musl { + return XFAIL_NOCHECK; + } + + return XFAIL("acoshf undefined"); } - // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. - if ctx.basis == CheckBasis::Mpfr { - return SKIP; + if (ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR) + && input.0 < F1::ZERO + && !input.0.is_infinite() + { + // loggamma should not be defined for x < 0, yet we both return results + return XFAIL_NOCHECK; } - // abs and copysign require signaling NaNs to be propagated, so verify bit equality. - if actual.to_bits() == expected.to_bits() { - SKIP - } else { - Some(Err(anyhow::anyhow!("NaNs have different bitpatterns"))) + // fabs and copysign must leave NaNs untouched. + if ctx.base_name == BaseName::Fabs && input.0.is_nan() { + // LLVM currently uses x87 instructions which quieten signalling NaNs to handle the i686 + // `extern "C"` `f32`/`f64` return ABI. + // LLVM issue + // Rust issue + if cfg!(target_arch = "x86") && ctx.basis == CheckBasis::Musl && actual.is_nan() { + return XFAIL_NOCHECK; + } + + // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. + if ctx.basis == CheckBasis::Mpfr { + return DEFAULT; + } + + // abs and copysign require signaling NaNs to be propagated, so verify bit equality. + if actual.to_bits() == expected.to_bits() { + return CheckAction::Custom(Ok(())); + } else { + return CheckAction::Custom(Err(anyhow::anyhow!("NaNs have different bitpatterns"))); + } } + + DEFAULT } #[cfg(f16_enabled)] @@ -382,9 +393,8 @@ impl MaybeOverride<(f16, f16)> for SpecialCase { input: (f16, f16), actual: F, expected: F, - _ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { + ) -> CheckAction { binop_common(input, actual, expected, ctx) } } @@ -394,18 +404,8 @@ impl MaybeOverride<(f32, f32)> for SpecialCase { input: (f32, f32), actual: F, expected: F, - _ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { - if ctx.base_name == BaseName::Fmin - && input.0.biteq(f32::NEG_ZERO) - && input.1.biteq(f32::ZERO) - && expected.biteq(F::NEG_ZERO) - && actual.biteq(F::ZERO) - { - return XFAIL; - } - + ) -> CheckAction { binop_common(input, actual, expected, ctx) } @@ -414,7 +414,7 @@ impl MaybeOverride<(f32, f32)> for SpecialCase { actual: I, expected: I, ctx: &CheckCtx, - ) -> Option { + ) -> CheckAction { remquo_common(actual, expected, ctx) } } @@ -424,18 +424,8 @@ impl MaybeOverride<(f64, f64)> for SpecialCase { input: (f64, f64), actual: F, expected: F, - _ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { - if ctx.base_name == BaseName::Fmin - && input.0.biteq(f64::NEG_ZERO) - && input.1.biteq(f64::ZERO) - && expected.biteq(F::ZERO) - && actual.biteq(F::NEG_ZERO) - { - return XFAIL; - } - + ) -> CheckAction { binop_common(input, actual, expected, ctx) } @@ -444,33 +434,19 @@ impl MaybeOverride<(f64, f64)> for SpecialCase { actual: I, expected: I, ctx: &CheckCtx, - ) -> Option { + ) -> CheckAction { remquo_common(actual, expected, ctx) } } -fn remquo_common(actual: I, expected: I, ctx: &CheckCtx) -> Option { - // FIXME: Our MPFR implementation disagrees with musl and may need to be updated. - if ctx.basis == CheckBasis::Mpfr - && ctx.base_name == BaseName::Remquo - && expected == I::MIN - && actual == I::ZERO - { - return XFAIL; - } - - None -} - #[cfg(f128_enabled)] impl MaybeOverride<(f128, f128)> for SpecialCase { fn check_float( input: (f128, f128), actual: F, expected: F, - _ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { + ) -> CheckAction { binop_common(input, actual, expected, ctx) } } @@ -481,8 +457,17 @@ fn binop_common( actual: F2, expected: F2, ctx: &CheckCtx, -) -> Option { - /* FIXME(#439): we do not compare signed zeros */ +) -> CheckAction { + // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. Skip if + // the first input (magnitude source) is NaN and the output is also a NaN, or if the second + // input (sign source) is NaN. + if ctx.basis == CheckBasis::Mpfr + && ((input.0.is_nan() && actual.is_nan() && expected.is_nan()) || input.1.is_nan()) + { + return SKIP; + } + + /* FIXME(#439): our fmin and fmax do not compare signed zeros */ if ctx.base_name == BaseName::Fmin && input.0.biteq(F1::NEG_ZERO) @@ -490,7 +475,7 @@ fn binop_common( && expected.biteq(F2::NEG_ZERO) && actual.biteq(F2::ZERO) { - return XFAIL; + return XFAIL("fmin signed zeroes"); } if ctx.base_name == BaseName::Fmax @@ -499,21 +484,32 @@ fn binop_common( && expected.biteq(F2::ZERO) && actual.biteq(F2::NEG_ZERO) { - return XFAIL; + return XFAIL("fmax signed zeroes"); } // Musl propagates NaNs if one is provided as the input, but we return the other input. - match (&ctx.basis, ctx.base_name) { - (Musl, BaseName::Fmin | BaseName::Fmax) - if (input.0.is_nan() || input.1.is_nan()) && expected.is_nan() => - { - XFAIL - } + if (ctx.base_name == BaseName::Fmax || ctx.base_name == BaseName::Fmin) + && ctx.basis == Musl + && (input.0.is_nan() ^ input.1.is_nan()) + && expected.is_nan() + { + return XFAIL("fmax/fmin musl NaN"); + } - (Mpfr, BaseName::Copysign) if input.1.is_nan() => SKIP, + DEFAULT +} - _ => None, +fn remquo_common(actual: I, expected: I, ctx: &CheckCtx) -> CheckAction { + // FIXME: Our MPFR implementation disagrees with musl and may need to be updated. + if ctx.basis == CheckBasis::Mpfr + && ctx.base_name == BaseName::Remquo + && expected == I::MIN + && actual == I::ZERO + { + return XFAIL("remquo integer mismatch"); } + + DEFAULT } impl MaybeOverride<(i32, f32)> for SpecialCase { @@ -521,28 +517,19 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { input: (i32, f32), actual: F, expected: F, - ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { - match (&ctx.basis, ctx.base_name) { - (Musl, _) => bessel_prec_dropoff(input, actual, expected, ulp, ctx), - - // We return +0.0, MPFR returns -0.0 - (Mpfr, BaseName::Jn | BaseName::Yn) - if input.1 == f32::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO => - { - XFAIL - } - - // `ynf(213, 109.15641) = -inf` with our library, should be finite. - (_, BaseName::Yn) - if input.0 > 200 && !expected.is_infinite() && actual.is_infinite() => - { - XFAIL - } - - _ => None, + ) -> CheckAction { + // `ynf(213, 109.15641) = -inf` with our library, should be finite. + if ctx.basis == Mpfr + && ctx.base_name == BaseName::Yn + && input.0 > 200 + && !expected.is_infinite() + && actual.is_infinite() + { + return XFAIL("ynf infinity mismatch"); } + + int_float_common(input, actual, expected, ctx) } } @@ -551,55 +538,51 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { input: (i32, f64), actual: F, expected: F, - ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { - match (&ctx.basis, ctx.base_name) { - (Musl, _) => bessel_prec_dropoff(input, actual, expected, ulp, ctx), - - // We return +0.0, MPFR returns -0.0 - (Mpfr, BaseName::Jn | BaseName::Yn) - if input.1 == f64::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO => - { - XFAIL - } - - _ => None, - } + ) -> CheckAction { + int_float_common(input, actual, expected, ctx) } } -/// Our bessel functions blow up with large N values -fn bessel_prec_dropoff( +fn int_float_common( input: (i32, F1), actual: F2, expected: F2, - ulp: &mut u32, ctx: &CheckCtx, -) -> Option { - if ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn { +) -> CheckAction { + if ctx.basis == Mpfr + && (ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn) + && input.1 == F1::NEG_INFINITY + && actual == F2::ZERO + && expected == F2::ZERO + { + return XFAIL("mpfr b"); + } + + // Our bessel functions blow up with large N values + if ctx.basis == Musl && (ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn) { if input.0 > 4000 { - return XFAIL; + return XFAIL_NOCHECK; } else if input.0 > 2000 { - // *ulp = 20_000; - *ulp = 20000; + return CheckAction::AssertWithUlp(20_000); } else if input.0 > 1000 { - *ulp = 4000; + return CheckAction::AssertWithUlp(4_000); } } // Values near infinity sometimes get cut off for us. `ynf(681, 509.90924) = -inf` but should // be -3.2161271e38. - if ctx.fn_ident == Identifier::Ynf + if ctx.basis == Musl + && ctx.fn_ident == Identifier::Ynf && !expected.is_infinite() && actual.is_infinite() && (expected.abs().to_bits().abs_diff(actual.abs().to_bits()) < F2::Int::cast_from(1_000_000u32)) { - return XFAIL; + return XFAIL_NOCHECK; } - None + DEFAULT } impl MaybeOverride<(f32, i32)> for SpecialCase {} @@ -610,9 +593,8 @@ impl MaybeOverride<(f32, f32, f32)> for SpecialCase { input: (f32, f32, f32), actual: F, expected: F, - _ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { + ) -> CheckAction { ternop_common(input, actual, expected, ctx) } } @@ -621,9 +603,8 @@ impl MaybeOverride<(f64, f64, f64)> for SpecialCase { input: (f64, f64, f64), actual: F, expected: F, - _ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { + ) -> CheckAction { ternop_common(input, actual, expected, ctx) } } @@ -634,7 +615,7 @@ fn ternop_common( actual: F2, expected: F2, ctx: &CheckCtx, -) -> Option { +) -> CheckAction { // FIXME(fma): 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result // of fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the // exact result". Our implementation returns the wrong sign: @@ -647,8 +628,8 @@ fn ternop_common( && expected.biteq(F2::NEG_ZERO) && actual.biteq(F2::ZERO) { - return XFAIL; + return XFAIL("fma sign"); } - None + DEFAULT } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 0a4baa2e36f..a5806943e11 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -8,8 +8,9 @@ use std::fmt; -use anyhow::{Context, bail, ensure}; +use anyhow::{Context, anyhow, bail, ensure}; +use crate::precision::CheckAction; use crate::{CheckCtx, Float, Int, MaybeOverride, SpecialCase, TestResult}; /// Trait for calling a function with a tuple as arguments. @@ -185,20 +186,34 @@ where Input: Hex + fmt::Debug, SpecialCase: MaybeOverride, { - if let Some(res) = SpecialCase::check_int(input, actual, expected, ctx) { - return res; - } + let (result, xfail_msg) = match SpecialCase::check_int(input, actual, expected, ctx) { + CheckAction::AssertSuccess => (actual == expected, None), + CheckAction::AssertFailure(msg) => (actual != expected, Some(msg)), + CheckAction::Custom(res) => return res, + CheckAction::Skip => return Ok(()), + CheckAction::AssertWithUlp(_) => panic!("ulp has no meaning for integer checks"), + }; + + let make_xfail_msg = || match xfail_msg { + Some(m) => format!( + "expected failure but test passed. Does an XFAIL need to be updated?\n\ + failed at: {m}", + ), + None => String::new(), + }; anyhow::ensure!( - actual == expected, + result, "\ \n input: {input:?} {ibits}\ \n expected: {expected:<22?} {expbits}\ \n actual: {actual:<22?} {actbits}\ + \n {msg}\ ", actbits = actual.hex(), expbits = expected.hex(), ibits = input.hex(), + msg = make_xfail_msg() ); Ok(()) @@ -246,15 +261,19 @@ where u32: TryFrom, SpecialCase: MaybeOverride, { + let mut assert_failure_msg = None; + // Create a wrapper function so we only need to `.with_context` once. - let inner = || -> TestResult { + let mut inner = || -> TestResult { let mut allowed_ulp = ctx.ulp; - // If the tested function requires a nonstandard test, run it here. - if let Some(res) = SpecialCase::check_float(input, actual, expected, &mut allowed_ulp, ctx) - { - return res; - } + match SpecialCase::check_float(input, actual, expected, ctx) { + CheckAction::AssertSuccess => (), + CheckAction::AssertFailure(msg) => assert_failure_msg = Some(msg), + CheckAction::Custom(res) => return res, + CheckAction::Skip => return Ok(()), + CheckAction::AssertWithUlp(ulp_override) => allowed_ulp = ulp_override, + }; // Check when both are NaNs if actual.is_nan() && expected.is_nan() { @@ -280,14 +299,29 @@ where let ulp_diff = act_bits.checked_sub(exp_bits).unwrap().abs(); let ulp_u32 = u32::try_from(ulp_diff) - .map_err(|e| anyhow::anyhow!("{e:?}: ulp of {ulp_diff} exceeds u32::MAX"))?; + .map_err(|e| anyhow!("{e:?}: ulp of {ulp_diff} exceeds u32::MAX"))?; ensure!(ulp_u32 <= allowed_ulp, "ulp {ulp_diff} > {allowed_ulp}",); Ok(()) }; - inner().with_context(|| { + let mut res = inner(); + + if let Some(msg) = assert_failure_msg { + // Invert `Ok` and `Err` if the test is an xfail. + if res.is_ok() { + let e = anyhow!( + "expected failure but test passed. Does an XFAIL need to be updated?\n\ + failed at: {msg}", + ); + res = Err(e) + } else { + res = Ok(()) + } + } + + res.with_context(|| { format!( "\ \n input: {input:?} {ibits}\ -- cgit 1.4.1-3-g733a5 From b8da1919f92b9a7a97ac58ebe4623daeb098b01c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 23 Jan 2025 09:15:43 +0000 Subject: Change `from_parts` to take a `u32` exponent rather than `i32` Make things more consistent with other API that works with a bitwise representation of the exponent. That is, use `u32` when working with a bitwise (biased) representation, use `i32` when the bitwise representation has been adjusted for bias and ay be negative. Every place this has been used so far has an `as i32`, so this change makes things cleaner anyway. --- library/compiler-builtins/libm/src/math/generic/sqrt.rs | 2 +- .../libm/src/math/support/float_traits.rs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index 22ee93f57a3..c20c0f20525 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -92,7 +92,7 @@ where } // Normalize subnormals by multiplying by 1.0 << SIG_BITS (e.g. 0x1p52 for doubles). - let scaled = x * F::from_parts(false, (F::SIG_BITS + F::EXP_BIAS) as i32, zero); + let scaled = x * F::from_parts(false, F::SIG_BITS + F::EXP_BIAS, zero); ix = scaled.to_bits(); match top { Exp::Shifted(ref mut v) => { diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 1abb7c4ded8..57e4aebecfc 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -131,11 +131,11 @@ pub trait Float: fn from_bits(a: Self::Int) -> Self; /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(negative: bool, exponent: i32, significand: Self::Int) -> Self { + fn from_parts(negative: bool, exponent: u32, significand: Self::Int) -> Self { let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; Self::from_bits( (sign << (Self::BITS - 1)) - | (Self::Int::cast_from(exponent as u32 & Self::EXP_MAX) << Self::SIG_BITS) + | (Self::Int::cast_from(exponent & Self::EXP_MAX) << Self::SIG_BITS) | (significand & Self::SIG_MASK), ) } @@ -282,7 +282,7 @@ mod tests { assert_eq!(f16::from_bits(0x1).exp_unbiased(), -15); // `from_parts` - assert_biteq!(f16::from_parts(true, f16::EXP_BIAS as i32, 0), -1.0f16); + assert_biteq!(f16::from_parts(true, f16::EXP_BIAS, 0), -1.0f16); assert_biteq!(f16::from_parts(false, 0, 1), f16::from_bits(0x1)); } @@ -304,8 +304,8 @@ mod tests { assert_eq!(f32::from_bits(0x1).exp_unbiased(), -127); // `from_parts` - assert_biteq!(f32::from_parts(true, f32::EXP_BIAS as i32, 0), -1.0f32); - assert_biteq!(f32::from_parts(false, 10 + f32::EXP_BIAS as i32, 0), hf32!("0x1p10")); + assert_biteq!(f32::from_parts(true, f32::EXP_BIAS, 0), -1.0f32); + assert_biteq!(f32::from_parts(false, 10 + f32::EXP_BIAS, 0), hf32!("0x1p10")); assert_biteq!(f32::from_parts(false, 0, 1), f32::from_bits(0x1)); } @@ -327,8 +327,8 @@ mod tests { assert_eq!(f64::from_bits(0x1).exp_unbiased(), -1023); // `from_parts` - assert_biteq!(f64::from_parts(true, f64::EXP_BIAS as i32, 0), -1.0f64); - assert_biteq!(f64::from_parts(false, 10 + f64::EXP_BIAS as i32, 0), hf64!("0x1p10")); + assert_biteq!(f64::from_parts(true, f64::EXP_BIAS, 0), -1.0f64); + assert_biteq!(f64::from_parts(false, 10 + f64::EXP_BIAS, 0), hf64!("0x1p10")); assert_biteq!(f64::from_parts(false, 0, 1), f64::from_bits(0x1)); } @@ -351,7 +351,7 @@ mod tests { assert_eq!(f128::from_bits(0x1).exp_unbiased(), -16383); // `from_parts` - assert_biteq!(f128::from_parts(true, f128::EXP_BIAS as i32, 0), -1.0f128); + assert_biteq!(f128::from_parts(true, f128::EXP_BIAS, 0), -1.0f128); assert_biteq!(f128::from_parts(false, 0, 1), f128::from_bits(0x1)); } } -- cgit 1.4.1-3-g733a5 From 3aa2d1cfc2b47f23299bdf14214e2eb176482d05 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 23 Jan 2025 22:02:22 +0000 Subject: Add a generic version of `scalbn` This replaces the `f32` and `f64` versions of `scalbn` and `ldexp`. --- .../libm/crates/libm-test/src/mpfloat.rs | 3 +- .../libm/etc/function-definitions.json | 2 + .../compiler-builtins/libm/src/math/generic/mod.rs | 2 + .../libm/src/math/generic/scalbn.rs | 123 +++++++++++++++++++++ library/compiler-builtins/libm/src/math/scalbn.rs | 33 +----- library/compiler-builtins/libm/src/math/scalbnf.rs | 29 +---- 6 files changed, 133 insertions(+), 59 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/scalbn.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index a404f227b26..4ac70c2eb5e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -158,7 +158,8 @@ libm_macros::for_each_function! { ilogbf, jn, jnf, - ldexp,ldexpf, + ldexp, + ldexpf, lgamma_r, lgammaf_r, modf, diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index d3810b940cb..bbb2b40f14d 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -698,12 +698,14 @@ "scalbn": { "sources": [ "src/libm_helper.rs", + "src/math/generic/scalbn.rs", "src/math/scalbn.rs" ], "type": "f64" }, "scalbnf": { "sources": [ + "src/math/generic/scalbn.rs", "src/math/scalbnf.rs" ], "type": "f32" diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index d3df650e1a5..c7741cb4600 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -4,6 +4,7 @@ mod fabs; mod fdim; mod floor; mod rint; +mod scalbn; mod sqrt; mod trunc; @@ -13,5 +14,6 @@ pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; pub use rint::rint; +pub use scalbn::scalbn; pub use sqrt::sqrt; pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs new file mode 100644 index 00000000000..f036c15cc03 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs @@ -0,0 +1,123 @@ +use super::super::{CastFrom, CastInto, Float, IntTy, MinInt}; + +/// Scale the exponent. +/// +/// From N3220: +/// +/// > The scalbn and scalbln functions compute `x * b^n`, where `b = FLT_RADIX` if the return type +/// > of the function is a standard floating type, or `b = 10` if the return type of the function +/// > is a decimal floating type. A range error occurs for some finite x, depending on n. +/// > +/// > [...] +/// > +/// > * `scalbn(±0, n)` returns `±0`. +/// > * `scalbn(x, 0)` returns `x`. +/// > * `scalbn(±∞, n)` returns `±∞`. +/// > +/// > If the calculation does not overflow or underflow, the returned value is exact and +/// > independent of the current rounding direction mode. +pub fn scalbn(mut x: F, mut n: i32) -> F +where + u32: CastInto, + F::Int: CastFrom, + F::Int: CastFrom, +{ + let zero = IntTy::::ZERO; + + // Bits including the implicit bit + let sig_total_bits = F::SIG_BITS + 1; + + // Maximum and minimum values when biased + let exp_max: i32 = F::EXP_BIAS as i32; + let exp_min = -(exp_max - 1); + + // 2 ^ Emax, where Emax is the maximum biased exponent value (1023 for f64) + let f_exp_max = F::from_parts(false, F::EXP_BIAS << 1, zero); + + // 2 ^ Emin, where Emin is the minimum biased exponent value (-1022 for f64) + let f_exp_min = F::from_parts(false, 1, zero); + + // 2 ^ sig_total_bits, representation of what can be accounted for with subnormals + let f_exp_subnorm = F::from_parts(false, sig_total_bits + F::EXP_BIAS, zero); + + if n > exp_max { + x *= f_exp_max; + n -= exp_max; + if n > exp_max { + x *= f_exp_max; + n -= exp_max; + if n > exp_max { + n = exp_max; + } + } + } else if n < exp_min { + let mul = f_exp_min * f_exp_subnorm; + let add = (exp_max - 1) - sig_total_bits as i32; + + x *= mul; + n += add; + if n < exp_min { + x *= mul; + n += add; + if n < exp_min { + n = exp_min; + } + } + } + + x * F::from_parts(false, (F::EXP_BIAS as i32 + n) as u32, zero) +} + +#[cfg(test)] +mod tests { + use super::super::super::Int; + use super::*; + + // Tests against N3220 + fn spec_test() + where + u32: CastInto, + F::Int: CastFrom, + F::Int: CastFrom, + { + // `scalbn(±0, n)` returns `±0`. + assert_biteq!(scalbn(F::NEG_ZERO, 10), F::NEG_ZERO); + assert_biteq!(scalbn(F::NEG_ZERO, 0), F::NEG_ZERO); + assert_biteq!(scalbn(F::NEG_ZERO, -10), F::NEG_ZERO); + assert_biteq!(scalbn(F::ZERO, 10), F::ZERO); + assert_biteq!(scalbn(F::ZERO, 0), F::ZERO); + assert_biteq!(scalbn(F::ZERO, -10), F::ZERO); + + // `scalbn(x, 0)` returns `x`. + assert_biteq!(scalbn(F::MIN, 0), F::MIN); + assert_biteq!(scalbn(F::MAX, 0), F::MAX); + assert_biteq!(scalbn(F::INFINITY, 0), F::INFINITY); + assert_biteq!(scalbn(F::NEG_INFINITY, 0), F::NEG_INFINITY); + assert_biteq!(scalbn(F::ZERO, 0), F::ZERO); + assert_biteq!(scalbn(F::NEG_ZERO, 0), F::NEG_ZERO); + + // `scalbn(±∞, n)` returns `±∞`. + assert_biteq!(scalbn(F::INFINITY, 10), F::INFINITY); + assert_biteq!(scalbn(F::INFINITY, -10), F::INFINITY); + assert_biteq!(scalbn(F::NEG_INFINITY, 10), F::NEG_INFINITY); + assert_biteq!(scalbn(F::NEG_INFINITY, -10), F::NEG_INFINITY); + + // NaN should remain NaNs. + assert!(scalbn(F::NAN, 10).is_nan()); + assert!(scalbn(F::NAN, 0).is_nan()); + assert!(scalbn(F::NAN, -10).is_nan()); + assert!(scalbn(-F::NAN, 10).is_nan()); + assert!(scalbn(-F::NAN, 0).is_nan()); + assert!(scalbn(-F::NAN, -10).is_nan()); + } + + #[test] + fn spec_test_f32() { + spec_test::(); + } + + #[test] + fn spec_test_f64() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs index 00c455a1065..f809dad518a 100644 --- a/library/compiler-builtins/libm/src/math/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -1,33 +1,4 @@ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbn(x: f64, mut n: i32) -> f64 { - let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 - let x1p53 = f64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53 - let x1p_1022 = f64::from_bits(0x0010000000000000); // 0x1p-1022 === 2 ^ (-1022) - - let mut y = x; - - if n > 1023 { - y *= x1p1023; - n -= 1023; - if n > 1023 { - y *= x1p1023; - n -= 1023; - if n > 1023 { - n = 1023; - } - } - } else if n < -1022 { - /* make sure final n < -53 to avoid double - rounding in the subnormal range */ - y *= x1p_1022 * x1p53; - n += 1022 - 53; - if n < -1022 { - y *= x1p_1022 * x1p53; - n += 1022 - 53; - if n < -1022 { - n = -1022; - } - } - } - y * f64::from_bits(((0x3ff + n) as u64) << 52) +pub fn scalbn(x: f64, n: i32) -> f64 { + super::generic::scalbn(x, n) } diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs index 73f4bb57aaf..57e7ba76f60 100644 --- a/library/compiler-builtins/libm/src/math/scalbnf.rs +++ b/library/compiler-builtins/libm/src/math/scalbnf.rs @@ -1,29 +1,4 @@ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 - let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 - - if n > 127 { - x *= x1p127; - n -= 127; - if n > 127 { - x *= x1p127; - n -= 127; - if n > 127 { - n = 127; - } - } - } else if n < -126 { - x *= x1p_126 * x1p24; - n += 126 - 24; - if n < -126 { - x *= x1p_126 * x1p24; - n += 126 - 24; - if n < -126 { - n = -126; - } - } - } - x * f32::from_bits(((0x7f + n) as u32) << 23) +pub fn scalbnf(x: f32, n: i32) -> f32 { + super::generic::scalbn(x, n) } -- cgit 1.4.1-3-g733a5 From cdbe65b5036f69188978405d1a8785d7a846140a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 01:49:23 +0000 Subject: Add a generic version of `round` This replaces `round` and `roundf`. --- .../libm/etc/function-definitions.json | 2 + .../compiler-builtins/libm/src/math/generic/mod.rs | 2 + .../libm/src/math/generic/round.rs | 46 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/round.rs | 27 +------------ library/compiler-builtins/libm/src/math/roundf.rs | 29 +------------- 5 files changed, 54 insertions(+), 52 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/round.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index bbb2b40f14d..4aea45a0781 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -685,12 +685,14 @@ "round": { "sources": [ "src/libm_helper.rs", + "src/math/generic/round.rs", "src/math/round.rs" ], "type": "f64" }, "roundf": { "sources": [ + "src/math/generic/round.rs", "src/math/roundf.rs" ], "type": "f32" diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index c7741cb4600..1f557719f42 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -4,6 +4,7 @@ mod fabs; mod fdim; mod floor; mod rint; +mod round; mod scalbn; mod sqrt; mod trunc; @@ -14,6 +15,7 @@ pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; pub use rint::rint; +pub use round::round; pub use scalbn::scalbn; pub use sqrt::sqrt; pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/src/math/generic/round.rs b/library/compiler-builtins/libm/src/math/generic/round.rs new file mode 100644 index 00000000000..fc9a1b675c6 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/round.rs @@ -0,0 +1,46 @@ +use super::super::{Float, MinInt}; +use super::{copysign, trunc}; + +pub fn round(x: F) -> F { + let f0p5 = F::from_parts(false, F::EXP_BIAS - 1, F::Int::ZERO); // 0.5 + let f0p25 = F::from_parts(false, F::EXP_BIAS - 2, F::Int::ZERO); // 0.25 + + trunc(x + copysign(f0p5 - f0p25 * F::EPSILON, x)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn zeroes_f32() { + assert_biteq!(round(0.0_f32), 0.0_f32); + assert_biteq!(round(-0.0_f32), -0.0_f32); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(round(-1.0_f32), -1.0); + assert_eq!(round(2.8_f32), 3.0); + assert_eq!(round(-0.5_f32), -1.0); + assert_eq!(round(0.5_f32), 1.0); + assert_eq!(round(-1.5_f32), -2.0); + assert_eq!(round(1.5_f32), 2.0); + } + + #[test] + fn zeroes_f64() { + assert_biteq!(round(0.0_f64), 0.0_f64); + assert_biteq!(round(-0.0_f64), -0.0_f64); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(round(-1.0_f64), -1.0); + assert_eq!(round(2.8_f64), 3.0); + assert_eq!(round(-0.5_f64), -1.0); + assert_eq!(round(0.5_f64), 1.0); + assert_eq!(round(-1.5_f64), -2.0); + assert_eq!(round(1.5_f64), 2.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index b81ebaa1dbe..36e0eb1f2ed 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -1,28 +1,5 @@ -use core::f64; - -use super::{copysign, trunc}; - +/// Round `x` to the nearest integer, breaking ties away from zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn round(x: f64) -> f64 { - trunc(x + copysign(0.5 - 0.25 * f64::EPSILON, x)) -} - -#[cfg(test)] -mod tests { - use super::round; - - #[test] - fn negative_zero() { - assert_eq!(round(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(round(-1.0), -1.0); - assert_eq!(round(2.8), 3.0); - assert_eq!(round(-0.5), -1.0); - assert_eq!(round(0.5), 1.0); - assert_eq!(round(-1.5), -2.0); - assert_eq!(round(1.5), 2.0); - } + super::generic::round(x) } diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index fb974bbfe73..b5d7c9d693e 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -1,30 +1,5 @@ -use core::f32; - -use super::{copysignf, truncf}; - +/// Round `x` to the nearest integer, breaking ties away from zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundf(x: f32) -> f32 { - truncf(x + copysignf(0.5 - 0.25 * f32::EPSILON, x)) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::roundf; - - #[test] - fn negative_zero() { - assert_eq!(roundf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(roundf(-1.0), -1.0); - assert_eq!(roundf(2.8), 3.0); - assert_eq!(roundf(-0.5), -1.0); - assert_eq!(roundf(0.5), 1.0); - assert_eq!(roundf(-1.5), -2.0); - assert_eq!(roundf(1.5), 2.0); - } + super::generic::round(x) } -- cgit 1.4.1-3-g733a5 From d20a5e82a5a25e180482a0a4644adbbb33601545 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 01:57:12 +0000 Subject: Add `roundf16` and `roundf128` --- .../libm/crates/libm-macros/src/shared.rs | 4 +-- .../libm/crates/libm-test/benches/random.rs | 2 ++ .../libm/crates/libm-test/src/mpfloat.rs | 4 +++ .../crates/libm-test/tests/compare_built_musl.rs | 2 ++ .../compiler-builtins/libm/crates/util/src/main.rs | 2 ++ .../libm/etc/function-definitions.json | 14 +++++++++ .../compiler-builtins/libm/etc/function-list.txt | 2 ++ .../libm/src/math/generic/round.rs | 36 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 4 +++ .../compiler-builtins/libm/src/math/roundf128.rs | 5 +++ .../compiler-builtins/libm/src/math/roundf16.rs | 5 +++ 11 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/roundf128.rs create mode 100644 library/compiler-builtins/libm/src/math/roundf16.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 80bd3e90753..b233e34f182 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["ceilf16", "fabsf16", "floorf16", "rintf16", "sqrtf16", "truncf16"], + &["ceilf16", "fabsf16", "floorf16", "rintf16", "roundf16", "sqrtf16", "truncf16"], ), ( // `fn(f32) -> f32` @@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["ceilf128", "fabsf128", "floorf128", "rintf128", "sqrtf128", "truncf128"], + &["ceilf128", "fabsf128", "floorf128", "rintf128", "roundf128", "sqrtf128", "truncf128"], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 4d050e817e2..d0ecd851e34 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -129,6 +129,8 @@ libm_macros::for_each_function! { | floorf16 | rintf128 | rintf16 + | roundf128 + | roundf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 4ac70c2eb5e..4422ab88d0d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -175,6 +175,8 @@ libm_macros::for_each_function! { rintf16, round, roundf, + roundf128, + roundf16, scalbn, scalbnf, sincos,sincosf, @@ -247,6 +249,7 @@ impl_no_round! { fabsf16 => abs_mut; floorf16 => floor_mut; rintf16 => round_even_mut; // FIXME: respect rounding mode + roundf16 => round_mut; truncf16 => trunc_mut; } @@ -256,6 +259,7 @@ impl_no_round! { fabsf128 => abs_mut; floorf128 => floor_mut; rintf128 => round_even_mut; // FIXME: respect rounding mode + roundf128 => round_mut; truncf128 => trunc_mut; } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index f009816c97f..0fc1b0df13d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -91,6 +91,8 @@ libm_macros::for_each_function! { floorf16, rintf128, rintf16, + roundf128, + roundf16, sqrtf128, sqrtf16, truncf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 889823d2e4a..aaedda6d152 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -98,6 +98,8 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | floorf16 | rintf128 | rintf16 + | roundf128 + | roundf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 4aea45a0781..8c5903e93b9 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -697,6 +697,20 @@ ], "type": "f32" }, + "roundf128": { + "sources": [ + "src/math/generic/round.rs", + "src/math/roundf128.rs" + ], + "type": "f128" + }, + "roundf16": { + "sources": [ + "src/math/generic/round.rs", + "src/math/roundf16.rs" + ], + "type": "f16" + }, "scalbn": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 41bb4e06be8..0b6eed828b5 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -101,6 +101,8 @@ rintf128 rintf16 round roundf +roundf128 +roundf16 scalbn scalbnf sin diff --git a/library/compiler-builtins/libm/src/math/generic/round.rs b/library/compiler-builtins/libm/src/math/generic/round.rs index fc9a1b675c6..8b51381880c 100644 --- a/library/compiler-builtins/libm/src/math/generic/round.rs +++ b/library/compiler-builtins/libm/src/math/generic/round.rs @@ -12,6 +12,24 @@ pub fn round(x: F) -> F { mod tests { use super::*; + #[test] + #[cfg(f16_enabled)] + fn zeroes_f16() { + assert_biteq!(round(0.0_f16), 0.0_f16); + assert_biteq!(round(-0.0_f16), -0.0_f16); + } + + #[test] + #[cfg(f16_enabled)] + fn sanity_check_f16() { + assert_eq!(round(-1.0_f16), -1.0); + assert_eq!(round(2.8_f16), 3.0); + assert_eq!(round(-0.5_f16), -1.0); + assert_eq!(round(0.5_f16), 1.0); + assert_eq!(round(-1.5_f16), -2.0); + assert_eq!(round(1.5_f16), 2.0); + } + #[test] fn zeroes_f32() { assert_biteq!(round(0.0_f32), 0.0_f32); @@ -43,4 +61,22 @@ mod tests { assert_eq!(round(-1.5_f64), -2.0); assert_eq!(round(1.5_f64), 2.0); } + + #[test] + #[cfg(f128_enabled)] + fn zeroes_f128() { + assert_biteq!(round(0.0_f128), 0.0_f128); + assert_biteq!(round(-0.0_f128), -0.0_f128); + } + + #[test] + #[cfg(f128_enabled)] + fn sanity_check_f128() { + assert_eq!(round(-1.0_f128), -1.0); + assert_eq!(round(2.8_f128), 3.0); + assert_eq!(round(-0.5_f128), -1.0); + assert_eq!(round(0.5_f128), 1.0); + assert_eq!(round(-1.5_f128), -2.0); + assert_eq!(round(1.5_f128), 2.0); + } } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 53d06974cee..8db17a02dfc 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -347,6 +347,7 @@ cfg_if! { mod fdimf16; mod floorf16; mod rintf16; + mod roundf16; mod sqrtf16; mod truncf16; @@ -356,6 +357,7 @@ cfg_if! { pub use self::fdimf16::fdimf16; pub use self::floorf16::floorf16; pub use self::rintf16::rintf16; + pub use self::roundf16::roundf16; pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; } @@ -369,6 +371,7 @@ cfg_if! { mod fdimf128; mod floorf128; mod rintf128; + mod roundf128; mod sqrtf128; mod truncf128; @@ -378,6 +381,7 @@ cfg_if! { pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; pub use self::rintf128::rintf128; + pub use self::roundf128::roundf128; pub use self::sqrtf128::sqrtf128; pub use self::truncf128::truncf128; } diff --git a/library/compiler-builtins/libm/src/math/roundf128.rs b/library/compiler-builtins/libm/src/math/roundf128.rs new file mode 100644 index 00000000000..fc3164929fe --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundf128.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf128(x: f128) -> f128 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/src/math/roundf16.rs b/library/compiler-builtins/libm/src/math/roundf16.rs new file mode 100644 index 00000000000..8b356eaabee --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundf16.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf16(x: f16) -> f16 { + super::generic::round(x) +} -- cgit 1.4.1-3-g733a5 From 357ee34abbabd9742ff03013df9d764e0fffe8ab Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 01:57:41 +0000 Subject: Remove an outdated note about precision --- library/compiler-builtins/libm/crates/libm-test/src/precision.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 800425f12ad..bed6158825a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -13,9 +13,6 @@ use crate::{BaseName, CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; pub struct SpecialCase; /// ULP allowed to differ from the results returned by a test basis. -/// -/// Note that these results were obtained using 400M rounds of random inputs, which -/// is not a value used by default. pub fn default_ulp(ctx: &CheckCtx) -> u32 { // ULP compared to the infinite (MPFR) result. let mut ulp = match ctx.base_name { -- cgit 1.4.1-3-g733a5 From f94df5d52450a20a30b39a029ff4297fce35504a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 02:10:52 +0000 Subject: Add a generic version of `fmin` and `fmax` These can be used for `fmin`, `fminf`, `fmax`, and `fmaxf`. No changes to the implementation are made, so [1] is not fixed. [1]: https://github.com/rust-lang/libm/issues/439 --- .../compiler-builtins/libm/etc/function-definitions.json | 12 ++++++++---- library/compiler-builtins/libm/src/math/fmax.rs | 11 ++--------- library/compiler-builtins/libm/src/math/fmaxf.rs | 11 ++--------- library/compiler-builtins/libm/src/math/fmin.rs | 11 ++--------- library/compiler-builtins/libm/src/math/fminf.rs | 11 ++--------- library/compiler-builtins/libm/src/math/generic/fmax.rs | 14 ++++++++++++++ library/compiler-builtins/libm/src/math/generic/fmin.rs | 13 +++++++++++++ library/compiler-builtins/libm/src/math/generic/mod.rs | 4 ++++ 8 files changed, 47 insertions(+), 40 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/fmax.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fmin.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 8c5903e93b9..7ffe91eadd6 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -379,26 +379,30 @@ "fmax": { "sources": [ "src/libm_helper.rs", - "src/math/fmax.rs" + "src/math/fmax.rs", + "src/math/generic/fmax.rs" ], "type": "f64" }, "fmaxf": { "sources": [ - "src/math/fmaxf.rs" + "src/math/fmaxf.rs", + "src/math/generic/fmax.rs" ], "type": "f32" }, "fmin": { "sources": [ "src/libm_helper.rs", - "src/math/fmin.rs" + "src/math/fmin.rs", + "src/math/generic/fmin.rs" ], "type": "f64" }, "fminf": { "sources": [ - "src/math/fminf.rs" + "src/math/fminf.rs", + "src/math/generic/fmin.rs" ], "type": "f32" }, diff --git a/library/compiler-builtins/libm/src/math/fmax.rs b/library/compiler-builtins/libm/src/math/fmax.rs index 93c97bc611c..d5d9b513b84 100644 --- a/library/compiler-builtins/libm/src/math/fmax.rs +++ b/library/compiler-builtins/libm/src/math/fmax.rs @@ -1,12 +1,5 @@ +/// Return the greater of two arguments or, if either argument is NaN, the other argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmax(x: f64, y: f64) -> f64 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if x.is_nan() || x < y { y } else { x }) * 1.0 + super::generic::fmax(x, y) } diff --git a/library/compiler-builtins/libm/src/math/fmaxf.rs b/library/compiler-builtins/libm/src/math/fmaxf.rs index 60774664752..3197d5cf2ca 100644 --- a/library/compiler-builtins/libm/src/math/fmaxf.rs +++ b/library/compiler-builtins/libm/src/math/fmaxf.rs @@ -1,12 +1,5 @@ +/// Return the greater of two arguments or, if either argument is NaN, the other argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaxf(x: f32, y: f32) -> f32 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if x.is_nan() || x < y { y } else { x }) * 1.0 + super::generic::fmax(x, y) } diff --git a/library/compiler-builtins/libm/src/math/fmin.rs b/library/compiler-builtins/libm/src/math/fmin.rs index ab1509f34a6..df8ff7c32e3 100644 --- a/library/compiler-builtins/libm/src/math/fmin.rs +++ b/library/compiler-builtins/libm/src/math/fmin.rs @@ -1,12 +1,5 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmin(x: f64, y: f64) -> f64 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if y.is_nan() || x < y { x } else { y }) * 1.0 + super::generic::fmin(x, y) } diff --git a/library/compiler-builtins/libm/src/math/fminf.rs b/library/compiler-builtins/libm/src/math/fminf.rs index 0049e7117ae..b2cdfe89d64 100644 --- a/library/compiler-builtins/libm/src/math/fminf.rs +++ b/library/compiler-builtins/libm/src/math/fminf.rs @@ -1,12 +1,5 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fminf(x: f32, y: f32) -> f32 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if y.is_nan() || x < y { x } else { y }) * 1.0 + super::generic::fmin(x, y) } diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs new file mode 100644 index 00000000000..97803052bc2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmax.rs @@ -0,0 +1,14 @@ +use super::super::Float; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmax(x: F, y: F) -> F { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x.is_nan() || x < y { y } else { x }) * F::ONE +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs new file mode 100644 index 00000000000..697f7200486 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmin.rs @@ -0,0 +1,13 @@ +use super::super::Float; + +pub fn fmin(x: F, y: F) -> F { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if y.is_nan() || x < y { x } else { y }) * F::ONE +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 1f557719f42..819781a219a 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -3,6 +3,8 @@ mod copysign; mod fabs; mod fdim; mod floor; +mod fmax; +mod fmin; mod rint; mod round; mod scalbn; @@ -14,6 +16,8 @@ pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; +pub use fmax::fmax; +pub use fmin::fmin; pub use rint::rint; pub use round::round; pub use scalbn::scalbn; -- cgit 1.4.1-3-g733a5 From 6d5105c00636a4f8a8c8c76217db7f59ebd1f846 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 02:57:35 +0000 Subject: Add `fminf16`, `fmaxf16`, `fminf128`, and `fmaxf128` --- .../libm/crates/libm-macros/src/shared.rs | 4 ++-- .../libm/crates/libm-test/benches/random.rs | 4 ++++ .../libm/crates/libm-test/src/mpfloat.rs | 4 ++-- .../crates/libm-test/tests/compare_built_musl.rs | 4 ++++ .../compiler-builtins/libm/crates/util/src/main.rs | 4 ++++ .../libm/etc/function-definitions.json | 28 ++++++++++++++++++++++ .../compiler-builtins/libm/etc/function-list.txt | 4 ++++ .../compiler-builtins/libm/src/math/fmaxf128.rs | 5 ++++ library/compiler-builtins/libm/src/math/fmaxf16.rs | 5 ++++ .../compiler-builtins/libm/src/math/fminf128.rs | 5 ++++ library/compiler-builtins/libm/src/math/fminf16.rs | 5 ++++ library/compiler-builtins/libm/src/math/mod.rs | 8 +++++++ 12 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fmaxf128.rs create mode 100644 library/compiler-builtins/libm/src/math/fmaxf16.rs create mode 100644 library/compiler-builtins/libm/src/math/fminf128.rs create mode 100644 library/compiler-builtins/libm/src/math/fminf16.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index b233e34f182..fbe0702a60d 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -47,7 +47,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, None, - &["copysignf16", "fdimf16"], + &["copysignf16", "fdimf16", "fmaxf16", "fminf16"], ), ( // `(f32, f32) -> f32` @@ -90,7 +90,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, None, - &["copysignf128", "fdimf128"], + &["copysignf128", "fdimf128", "fmaxf128", "fminf128"], ), ( // `(f32, f32, f32) -> f32` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index d0ecd851e34..aac8379fd42 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -127,6 +127,10 @@ libm_macros::for_each_function! { | fdimf16 | floorf128 | floorf16 + | fmaxf128 + | fmaxf16 + | fminf128 + | fminf16 | rintf128 | rintf16 | roundf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 4422ab88d0d..da674c16273 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -192,8 +192,8 @@ libm_macros::for_each_function! { fabs | fabsf => abs, fdim | fdimf | fdimf16 | fdimf128 => positive_diff, fma | fmaf => mul_add, - fmax | fmaxf => max, - fmin | fminf => min, + fmax | fmaxf | fmaxf16 | fmaxf128 => max, + fmin | fminf | fminf16 | fminf128 => min, lgamma | lgammaf => ln_gamma, log | logf => ln, log1p | log1pf => ln_1p, diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 0fc1b0df13d..ca070e8f6ac 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -89,6 +89,10 @@ libm_macros::for_each_function! { fdimf16, floorf128, floorf16, + fmaxf128, + fmaxf16, + fminf128, + fminf16, rintf128, rintf16, roundf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index aaedda6d152..eb8e3758956 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -96,6 +96,10 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fdimf16 | floorf128 | floorf16 + | fmaxf128 + | fmaxf16 + | fminf128 + | fminf16 | rintf128 | rintf16 | roundf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 7ffe91eadd6..b6653295c10 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -391,6 +391,20 @@ ], "type": "f32" }, + "fmaxf128": { + "sources": [ + "src/math/fmaxf128.rs", + "src/math/generic/fmax.rs" + ], + "type": "f128" + }, + "fmaxf16": { + "sources": [ + "src/math/fmaxf16.rs", + "src/math/generic/fmax.rs" + ], + "type": "f16" + }, "fmin": { "sources": [ "src/libm_helper.rs", @@ -406,6 +420,20 @@ ], "type": "f32" }, + "fminf128": { + "sources": [ + "src/math/fminf128.rs", + "src/math/generic/fmin.rs" + ], + "type": "f128" + }, + "fminf16": { + "sources": [ + "src/math/fminf16.rs", + "src/math/generic/fmin.rs" + ], + "type": "f16" + }, "fmod": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 0b6eed828b5..25b92e58bad 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -55,8 +55,12 @@ fma fmaf fmax fmaxf +fmaxf128 +fmaxf16 fmin fminf +fminf128 +fminf16 fmod fmodf frexp diff --git a/library/compiler-builtins/libm/src/math/fmaxf128.rs b/library/compiler-builtins/libm/src/math/fmaxf128.rs new file mode 100644 index 00000000000..bace9ab53f2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmaxf128.rs @@ -0,0 +1,5 @@ +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf128(x: f128, y: f128) -> f128 { + super::generic::fmax(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fmaxf16.rs b/library/compiler-builtins/libm/src/math/fmaxf16.rs new file mode 100644 index 00000000000..fea15be8f14 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmaxf16.rs @@ -0,0 +1,5 @@ +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf16(x: f16, y: f16) -> f16 { + super::generic::fmax(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fminf128.rs b/library/compiler-builtins/libm/src/math/fminf128.rs new file mode 100644 index 00000000000..a9224c22aa5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fminf128.rs @@ -0,0 +1,5 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf128(x: f128, y: f128) -> f128 { + super::generic::fmin(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fminf16.rs b/library/compiler-builtins/libm/src/math/fminf16.rs new file mode 100644 index 00000000000..6d936be347a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fminf16.rs @@ -0,0 +1,5 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf16(x: f16, y: f16) -> f16 { + super::generic::fmin(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 8db17a02dfc..cb83b2587ee 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -346,6 +346,8 @@ cfg_if! { mod fabsf16; mod fdimf16; mod floorf16; + mod fmaxf16; + mod fminf16; mod rintf16; mod roundf16; mod sqrtf16; @@ -356,6 +358,8 @@ cfg_if! { pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; pub use self::floorf16::floorf16; + pub use self::fmaxf16::fmaxf16; + pub use self::fminf16::fminf16; pub use self::rintf16::rintf16; pub use self::roundf16::roundf16; pub use self::sqrtf16::sqrtf16; @@ -370,6 +374,8 @@ cfg_if! { mod fabsf128; mod fdimf128; mod floorf128; + mod fmaxf128; + mod fminf128; mod rintf128; mod roundf128; mod sqrtf128; @@ -380,6 +386,8 @@ cfg_if! { pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; + pub use self::fmaxf128::fmaxf128; + pub use self::fminf128::fminf128; pub use self::rintf128::rintf128; pub use self::roundf128::roundf128; pub use self::sqrtf128::sqrtf128; -- cgit 1.4.1-3-g733a5 From 08eda86de291c1cfa5959dac6f26fd7bd5a7392c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 05:02:47 +0000 Subject: Add a generic version of `fmod` This can replace `fmod` and `fmodf`. As part of this change I was able to replace some of the `while` loops with `leading_zeros`. --- .../libm/etc/function-definitions.json | 6 +- library/compiler-builtins/libm/src/math/fmod.rs | 77 +------------------ library/compiler-builtins/libm/src/math/fmodf.rs | 87 +--------------------- .../libm/src/math/generic/fmod.rs | 84 +++++++++++++++++++++ .../compiler-builtins/libm/src/math/generic/mod.rs | 2 + .../libm/src/math/support/int_traits.rs | 2 + 6 files changed, 96 insertions(+), 162 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/fmod.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index b6653295c10..866e9a43930 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -437,13 +437,15 @@ "fmod": { "sources": [ "src/libm_helper.rs", - "src/math/fmod.rs" + "src/math/fmod.rs", + "src/math/generic/fmod.rs" ], "type": "f64" }, "fmodf": { "sources": [ - "src/math/fmodf.rs" + "src/math/fmodf.rs", + "src/math/generic/fmod.rs" ], "type": "f32" }, diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs index b68e6b0ea3c..d9786b53d71 100644 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -1,78 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmod(x: f64, y: f64) -> f64 { - let mut uxi = x.to_bits(); - let mut uyi = y.to_bits(); - let mut ex = ((uxi >> 52) & 0x7ff) as i64; - let mut ey = ((uyi >> 52) & 0x7ff) as i64; - let sx = uxi >> 63; - let mut i; - - if uyi << 1 == 0 || y.is_nan() || ex == 0x7ff { - return (x * y) / (x * y); - } - if uxi << 1 <= uyi << 1 { - if uxi << 1 == uyi << 1 { - return 0.0 * x; - } - return x; - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 12; - while i >> 63 == 0 { - ex -= 1; - i <<= 1; - } - uxi <<= -ex + 1; - } else { - uxi &= u64::MAX >> 12; - uxi |= 1 << 52; - } - if ey == 0 { - i = uyi << 12; - while i >> 63 == 0 { - ey -= 1; - i <<= 1; - } - uyi <<= -ey + 1; - } else { - uyi &= u64::MAX >> 12; - uyi |= 1 << 52; - } - - /* x mod y */ - while ex > ey { - i = uxi.wrapping_sub(uyi); - if i >> 63 == 0 { - if i == 0 { - return 0.0 * x; - } - uxi = i; - } - uxi <<= 1; - ex -= 1; - } - i = uxi.wrapping_sub(uyi); - if i >> 63 == 0 { - if i == 0 { - return 0.0 * x; - } - uxi = i; - } - while uxi >> 52 == 0 { - uxi <<= 1; - ex -= 1; - } - - /* scale result */ - if ex > 0 { - uxi -= 1 << 52; - uxi |= (ex as u64) << 52; - } else { - uxi >>= -ex + 1; - } - uxi |= sx << 63; - - f64::from_bits(uxi) + super::generic::fmod(x, y) } diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index 4de18195770..4e95696e20d 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -1,88 +1,5 @@ -use core::f32; - +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmodf(x: f32, y: f32) -> f32 { - let mut uxi = x.to_bits(); - let mut uyi = y.to_bits(); - let mut ex = ((uxi >> 23) & 0xff) as i32; - let mut ey = ((uyi >> 23) & 0xff) as i32; - let sx = uxi & 0x80000000; - let mut i; - - if uyi << 1 == 0 || y.is_nan() || ex == 0xff { - return (x * y) / (x * y); - } - - if uxi << 1 <= uyi << 1 { - if uxi << 1 == uyi << 1 { - return 0.0 * x; - } - - return x; - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 9; - while i >> 31 == 0 { - ex -= 1; - i <<= 1; - } - - uxi <<= -ex + 1; - } else { - uxi &= u32::MAX >> 9; - uxi |= 1 << 23; - } - - if ey == 0 { - i = uyi << 9; - while i >> 31 == 0 { - ey -= 1; - i <<= 1; - } - - uyi <<= -ey + 1; - } else { - uyi &= u32::MAX >> 9; - uyi |= 1 << 23; - } - - /* x mod y */ - while ex > ey { - i = uxi.wrapping_sub(uyi); - if i >> 31 == 0 { - if i == 0 { - return 0.0 * x; - } - uxi = i; - } - uxi <<= 1; - - ex -= 1; - } - - i = uxi.wrapping_sub(uyi); - if i >> 31 == 0 { - if i == 0 { - return 0.0 * x; - } - uxi = i; - } - - while uxi >> 23 == 0 { - uxi <<= 1; - ex -= 1; - } - - /* scale result up */ - if ex > 0 { - uxi -= 1 << 23; - uxi |= (ex as u32) << 23; - } else { - uxi >>= -ex + 1; - } - uxi |= sx; - - f32::from_bits(uxi) + super::generic::fmod(x, y) } diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs new file mode 100644 index 00000000000..93da6c51e7e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fmod.c. Ported to generic Rust algorithm in 2025, TG. */ + +use super::super::{CastFrom, Float, Int, MinInt}; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmod(x: F, y: F) -> F { + let zero = F::Int::ZERO; + let one = F::Int::ONE; + let mut ix = x.to_bits(); + let mut iy = y.to_bits(); + let mut ex = x.exp().signed(); + let mut ey = y.exp().signed(); + let sx = ix & F::SIGN_MASK; + + if iy << 1 == zero || y.is_nan() || ex == F::EXP_MAX as i32 { + return (x * y) / (x * y); + } + + if ix << 1 <= iy << 1 { + if ix << 1 == iy << 1 { + return F::ZERO * x; + } + return x; + } + + /* normalize x and y */ + if ex == 0 { + let i = ix << F::EXP_BITS; + ex -= i.leading_zeros() as i32; + ix <<= -ex + 1; + } else { + ix &= F::Int::MAX >> F::EXP_BITS; + ix |= one << F::SIG_BITS; + } + + if ey == 0 { + let i = iy << F::EXP_BITS; + ey -= i.leading_zeros() as i32; + iy <<= -ey + 1; + } else { + iy &= F::Int::MAX >> F::EXP_BITS; + iy |= one << F::SIG_BITS; + } + + /* x mod y */ + while ex > ey { + let i = ix.wrapping_sub(iy); + if i >> (F::BITS - 1) == zero { + if i == zero { + return F::ZERO * x; + } + ix = i; + } + + ix <<= 1; + ex -= 1; + } + + let i = ix.wrapping_sub(iy); + if i >> (F::BITS - 1) == zero { + if i == zero { + return F::ZERO * x; + } + + ix = i; + } + + let shift = ix.leading_zeros().saturating_sub(F::EXP_BITS); + ix <<= shift; + ex -= shift as i32; + + /* scale result */ + if ex > 0 { + ix -= one << F::SIG_BITS; + ix |= F::Int::cast_from(ex) << F::SIG_BITS; + } else { + ix >>= -ex + 1; + } + + ix |= sx; + + F::from_bits(ix) +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 819781a219a..68686b0b255 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -5,6 +5,7 @@ mod fdim; mod floor; mod fmax; mod fmin; +mod fmod; mod rint; mod round; mod scalbn; @@ -18,6 +19,7 @@ pub use fdim::fdim; pub use floor::floor; pub use fmax::fmax; pub use fmin::fmin; +pub use fmod::fmod; pub use rint::rint; pub use round::round; pub use scalbn::scalbn; diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index cf19762e816..b403c658cb6 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -45,7 +45,9 @@ pub trait Int: + ops::BitOrAssign + ops::BitXorAssign + ops::ShlAssign + + ops::ShlAssign + ops::ShrAssign + + ops::ShrAssign + ops::Add + ops::Sub + ops::Mul -- cgit 1.4.1-3-g733a5 From 67218cbaa5870c1fef896762719b4ba04b9fccdd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 05:09:08 +0000 Subject: Add `fmodf16` using the generic implementation --- .../libm/crates/libm-macros/src/shared.rs | 2 +- .../libm/crates/libm-test/benches/icount.rs | 1 + .../libm/crates/libm-test/benches/random.rs | 1 + .../libm/crates/libm-test/src/mpfloat.rs | 17 +++++++++++++++++ .../libm/crates/libm-test/tests/compare_built_musl.rs | 1 + library/compiler-builtins/libm/crates/util/src/main.rs | 1 + .../libm/etc/function-definitions.json | 7 +++++++ library/compiler-builtins/libm/etc/function-list.txt | 1 + library/compiler-builtins/libm/src/math/fmodf16.rs | 5 +++++ library/compiler-builtins/libm/src/math/mod.rs | 2 ++ 10 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/src/math/fmodf16.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index fbe0702a60d..69fe45e03ce 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -47,7 +47,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, None, - &["copysignf16", "fdimf16", "fmaxf16", "fminf16"], + &["copysignf16", "fdimf16", "fmaxf16", "fminf16", "fmodf16"], ), ( // `(f32, f32) -> f32` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 84f95326267..97e78d8f1b1 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -111,6 +111,7 @@ main!( icount_bench_fmin_group, icount_bench_fminf_group, icount_bench_fmod_group, + icount_bench_fmodf16_group, icount_bench_fmodf_group, icount_bench_frexp_group, icount_bench_frexpf_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index aac8379fd42..3e816e81a61 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -131,6 +131,7 @@ libm_macros::for_each_function! { | fmaxf16 | fminf128 | fminf16 + | fmodf16 | rintf128 | rintf16 | roundf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index da674c16273..56234b14a52 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -152,6 +152,7 @@ libm_macros::for_each_function! { floorf16, fmod, fmodf, + fmodf16, frexp, frexpf, ilogb, @@ -525,6 +526,22 @@ impl MpOp for crate::op::lgammaf_r::Routine { } } +// No fmodf128 yet +impl MpOp for crate::op::fmodf16::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = this.0.rem_assign_round(&this.1, Nearest); + prep_retval::(&mut this.0, ord) + } +} + /* stub implementations so we don't need to special case them */ impl MpOp for crate::op::nextafter::Routine { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index ca070e8f6ac..46474c04688 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -93,6 +93,7 @@ libm_macros::for_each_function! { fmaxf16, fminf128, fminf16, + fmodf16, rintf128, rintf16, roundf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index eb8e3758956..999b03af9e3 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -100,6 +100,7 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fmaxf16 | fminf128 | fminf16 + | fmodf16 | rintf128 | rintf16 | roundf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 866e9a43930..966060f77c4 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -449,6 +449,13 @@ ], "type": "f32" }, + "fmodf16": { + "sources": [ + "src/math/fmodf16.rs", + "src/math/generic/fmod.rs" + ], + "type": "f16" + }, "frexp": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 25b92e58bad..ff4de0cb5d4 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -63,6 +63,7 @@ fminf128 fminf16 fmod fmodf +fmodf16 frexp frexpf hypot diff --git a/library/compiler-builtins/libm/src/math/fmodf16.rs b/library/compiler-builtins/libm/src/math/fmodf16.rs new file mode 100644 index 00000000000..11972a7de4f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmodf16.rs @@ -0,0 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf16(x: f16, y: f16) -> f16 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index cb83b2587ee..aab551bedbd 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -348,6 +348,7 @@ cfg_if! { mod floorf16; mod fmaxf16; mod fminf16; + mod fmodf16; mod rintf16; mod roundf16; mod sqrtf16; @@ -360,6 +361,7 @@ cfg_if! { pub use self::floorf16::floorf16; pub use self::fmaxf16::fmaxf16; pub use self::fminf16::fminf16; + pub use self::fmodf16::fmodf16; pub use self::rintf16::rintf16; pub use self::roundf16::roundf16; pub use self::sqrtf16::sqrtf16; -- cgit 1.4.1-3-g733a5 From 9d38c93fb080ce30b2f57b017f9220f26f3b9d13 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 06:24:45 +0000 Subject: Increase or set CI timeouts With the new routines, some of our tests are running close to their timeouts. Increase the timeout for test jobs, and set a short timeout for all other jobs that did not have one. --- library/compiler-builtins/libm/.github/workflows/main.yaml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 89c5facef44..59955271170 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -15,7 +15,7 @@ env: jobs: test: name: Build and test - timeout-minutes: 40 + timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -123,6 +123,7 @@ jobs: clippy: name: Clippy runs-on: ubuntu-24.04 + timeout-minutes: 10 steps: - uses: actions/checkout@master - name: Install Rust @@ -138,6 +139,7 @@ jobs: builtins: name: Check use with compiler-builtins runs-on: ubuntu-24.04 + timeout-minutes: 10 steps: - uses: actions/checkout@master - name: Install Rust @@ -194,6 +196,7 @@ jobs: msrv: name: Check MSRV runs-on: ubuntu-24.04 + timeout-minutes: 10 env: RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` steps: @@ -210,6 +213,7 @@ jobs: rustfmt: name: Rustfmt runs-on: ubuntu-24.04 + timeout-minutes: 10 steps: - uses: actions/checkout@master - name: Install Rust @@ -223,6 +227,7 @@ jobs: calculate_extensive_matrix: name: Calculate job matrix runs-on: ubuntu-24.04 + timeout-minutes: 10 outputs: matrix: ${{ steps.script.outputs.matrix }} steps: @@ -242,7 +247,7 @@ jobs: - clippy - calculate_extensive_matrix runs-on: ubuntu-24.04 - timeout-minutes: 80 + timeout-minutes: 180 strategy: matrix: # Use the output from `calculate_extensive_matrix` to calculate the matrix @@ -286,6 +291,7 @@ jobs: - rustfmt - extensive runs-on: ubuntu-24.04 + timeout-minutes: 10 # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its # dependencies fails. -- cgit 1.4.1-3-g733a5 From b863308979d4e57115227f751ab408c8b4cfc3a5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 07:59:09 +0000 Subject: Add way to override the number of iterations for specific tests Certain functions (`fmodf128`) are significantly slower than others, to the point that running the default number of tests adds tens of minutes to PR CI and extensive test time increases to ~1day. It does not make sense to do this by default; so, introduce `EXTREMELY_SLOW_TESTS` to test configuration that allows setting specific tests that need to have a reduced iteration count. --- .../libm/crates/libm-test/src/lib.rs | 4 +-- .../libm/crates/libm-test/src/run_cfg.rs | 34 +++++++++++++++++----- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index b90423c1bac..78b011b1f23 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -28,7 +28,7 @@ pub use op::{ Ty, }; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; -use run_cfg::EXTENSIVE_MAX_ITERATIONS; +use run_cfg::extensive_max_iterations; pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, skip_extensive_test}; pub use test_traits::{CheckOutput, Hex, TupleCall}; @@ -89,7 +89,7 @@ pub fn test_log(s: &str) { writeln!(f, "cargo features: {}", env!("CFG_CARGO_FEATURES")).unwrap(); writeln!(f, "opt level: {}", env!("CFG_OPT_LEVEL")).unwrap(); writeln!(f, "target features: {}", env!("CFG_TARGET_FEATURES")).unwrap(); - writeln!(f, "extensive iterations {}", *EXTENSIVE_MAX_ITERATIONS).unwrap(); + writeln!(f, "extensive iterations {}", extensive_max_iterations()).unwrap(); Some(f) }); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 3e91101f6ca..c76b6699faf 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -13,18 +13,27 @@ pub const EXTENSIVE_ENV: &str = "LIBM_EXTENSIVE_TESTS"; /// Specify the number of iterations via this environment variable, rather than using the default. pub const EXTENSIVE_ITER_ENV: &str = "LIBM_EXTENSIVE_ITERATIONS"; +/// The override value, if set by the above environment. +static EXTENSIVE_ITER_OVERRIDE: LazyLock> = LazyLock::new(|| { + env::var(EXTENSIVE_ITER_ENV).map(|v| v.parse().expect("failed to parse iteration count")).ok() +}); + +/// Specific tests that need to have a reduced amount of iterations to complete in a reasonable +/// amount of time. +/// +/// Contains the itentifier+generator combo to match on, plus the factor to reduce by. +const EXTEMELY_SLOW_TESTS: &[(Identifier, GeneratorKind, u64)] = &[]; + /// Maximum number of iterations to run for a single routine. /// /// The default value of one greater than `u32::MAX` allows testing single-argument `f32` routines /// and single- or double-argument `f16` routines exhaustively. `f64` and `f128` can't feasibly /// be tested exhaustively; however, [`EXTENSIVE_ITER_ENV`] can be set to run tests for multiple /// hours. -pub static EXTENSIVE_MAX_ITERATIONS: LazyLock = LazyLock::new(|| { - let default = 1 << 32; - env::var(EXTENSIVE_ITER_ENV) - .map(|v| v.parse().expect("failed to parse iteration count")) - .unwrap_or(default) -}); +pub fn extensive_max_iterations() -> u64 { + let default = 1 << 32; // default value + EXTENSIVE_ITER_OVERRIDE.unwrap_or(default) +} /// Context passed to [`CheckOutput`]. #[derive(Clone, Debug, PartialEq, Eq)] @@ -206,12 +215,23 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { let mut total_iterations = match ctx.gen_kind { GeneratorKind::QuickSpaced => domain_iter_count, GeneratorKind::Random => random_iter_count, - GeneratorKind::Extensive => *EXTENSIVE_MAX_ITERATIONS, + GeneratorKind::Extensive => extensive_max_iterations(), GeneratorKind::EdgeCases => { unimplemented!("edge case tests shoudn't need `iteration_count`") } }; + // Some tests are significantly slower than others and need to be further reduced. + if let Some((_id, _gen, scale)) = EXTEMELY_SLOW_TESTS + .iter() + .find(|(id, gen, _scale)| *id == ctx.fn_ident && *gen == ctx.gen_kind) + { + // However, do not override if the extensive iteration count has been manually set. + if !(ctx.gen_kind == GeneratorKind::Extensive && EXTENSIVE_ITER_OVERRIDE.is_some()) { + total_iterations /= scale; + } + } + // FMA has a huge domain but is reasonably fast to run, so increase iterations. if ctx.base_name == BaseName::Fma { total_iterations *= 4; -- cgit 1.4.1-3-g733a5 From 71200bc3ce854c6c15e05c9588954b49a7aea095 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 05:58:08 +0000 Subject: Add `fmodf128` This function is significantly slower than all others so includes an override in `EXTREMELY_SLOW_TESTS`. Without it, PR CI takes ~1hour and the extensive tests in CI take ~1day. --- .../libm/crates/libm-macros/src/shared.rs | 2 +- .../libm/crates/libm-test/benches/icount.rs | 1 + .../libm/crates/libm-test/benches/random.rs | 1 + .../libm/crates/libm-test/src/mpfloat.rs | 47 ++++++++-------------- .../libm/crates/libm-test/src/run_cfg.rs | 5 ++- .../crates/libm-test/tests/compare_built_musl.rs | 1 + .../compiler-builtins/libm/crates/util/src/main.rs | 1 + .../libm/etc/function-definitions.json | 7 ++++ .../compiler-builtins/libm/etc/function-list.txt | 1 + .../compiler-builtins/libm/src/math/fmodf128.rs | 5 +++ library/compiler-builtins/libm/src/math/mod.rs | 2 + 11 files changed, 40 insertions(+), 33 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fmodf128.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 69fe45e03ce..b1f4f46cc3b 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -90,7 +90,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, None, - &["copysignf128", "fdimf128", "fmaxf128", "fminf128"], + &["copysignf128", "fdimf128", "fmaxf128", "fminf128", "fmodf128"], ), ( // `(f32, f32, f32) -> f32` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 97e78d8f1b1..46a659524a6 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -111,6 +111,7 @@ main!( icount_bench_fmin_group, icount_bench_fminf_group, icount_bench_fmod_group, + icount_bench_fmodf128_group, icount_bench_fmodf16_group, icount_bench_fmodf_group, icount_bench_frexp_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 3e816e81a61..ca9e86c10bf 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -131,6 +131,7 @@ libm_macros::for_each_function! { | fmaxf16 | fminf128 | fminf16 + | fmodf128 | fmodf16 | rintf128 | rintf16 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 56234b14a52..98b80505f26 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -152,6 +152,7 @@ libm_macros::for_each_function! { floorf16, fmod, fmodf, + fmodf128, fmodf16, frexp, frexpf, @@ -301,21 +302,6 @@ macro_rules! impl_op_for_ty { } } - impl MpOp for crate::op::[]::Routine { - type MpTy = (MpFloat, MpFloat); - - fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0.assign(input.0); - this.1.assign(input.1); - let ord = this.0.rem_assign_round(&this.1, Nearest); - prep_retval::(&mut this.0, ord) - } - } - impl MpOp for crate::op::[]::Routine { type MpTy = MpFloat; @@ -481,6 +467,21 @@ macro_rules! impl_op_for_ty_all { prep_retval::(&mut this.0, Ordering::Equal) } } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = this.0.rem_assign_round(&this.1, Nearest); + prep_retval::(&mut this.0, ord) + } + } } }; } @@ -526,22 +527,6 @@ impl MpOp for crate::op::lgammaf_r::Routine { } } -// No fmodf128 yet -impl MpOp for crate::op::fmodf16::Routine { - type MpTy = (MpFloat, MpFloat); - - fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0.assign(input.0); - this.1.assign(input.1); - let ord = this.0.rem_assign_round(&this.1, Nearest); - prep_retval::(&mut this.0, ord) - } -} - /* stub implementations so we don't need to special case them */ impl MpOp for crate::op::nextafter::Routine { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index c76b6699faf..783142e3783 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -22,7 +22,10 @@ static EXTENSIVE_ITER_OVERRIDE: LazyLock> = LazyLock::new(|| { /// amount of time. /// /// Contains the itentifier+generator combo to match on, plus the factor to reduce by. -const EXTEMELY_SLOW_TESTS: &[(Identifier, GeneratorKind, u64)] = &[]; +const EXTEMELY_SLOW_TESTS: &[(Identifier, GeneratorKind, u64)] = &[ + (Identifier::Fmodf128, GeneratorKind::QuickSpaced, 40), + (Identifier::Fmodf128, GeneratorKind::Extensive, 40), +]; /// Maximum number of iterations to run for a single routine. /// diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 46474c04688..5466edf4f4c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -93,6 +93,7 @@ libm_macros::for_each_function! { fmaxf16, fminf128, fminf16, + fmodf128, fmodf16, rintf128, rintf16, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 999b03af9e3..f4ee8fd2e38 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -100,6 +100,7 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fmaxf16 | fminf128 | fminf16 + | fmodf128 | fmodf16 | rintf128 | rintf16 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 966060f77c4..574ffea2e50 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -449,6 +449,13 @@ ], "type": "f32" }, + "fmodf128": { + "sources": [ + "src/math/fmodf128.rs", + "src/math/generic/fmod.rs" + ], + "type": "f128" + }, "fmodf16": { "sources": [ "src/math/fmodf16.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index ff4de0cb5d4..d82838b3233 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -63,6 +63,7 @@ fminf128 fminf16 fmod fmodf +fmodf128 fmodf16 frexp frexpf diff --git a/library/compiler-builtins/libm/src/math/fmodf128.rs b/library/compiler-builtins/libm/src/math/fmodf128.rs new file mode 100644 index 00000000000..ff0e0493e26 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmodf128.rs @@ -0,0 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf128(x: f128, y: f128) -> f128 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index aab551bedbd..969c1bfd942 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -378,6 +378,7 @@ cfg_if! { mod floorf128; mod fmaxf128; mod fminf128; + mod fmodf128; mod rintf128; mod roundf128; mod sqrtf128; @@ -390,6 +391,7 @@ cfg_if! { pub use self::floorf128::floorf128; pub use self::fmaxf128::fmaxf128; pub use self::fminf128::fminf128; + pub use self::fmodf128::fmodf128; pub use self::rintf128::rintf128; pub use self::roundf128::roundf128; pub use self::sqrtf128::sqrtf128; -- cgit 1.4.1-3-g733a5 From 173a48ce8c8f6acfa2cc7173138600d3fde9d12e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 09:11:07 +0000 Subject: Enable missing icount benchmarks A few new functions were added but this list did not get updated. Do so here. --- library/compiler-builtins/libm/crates/libm-test/benches/icount.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 46a659524a6..d5026f461b0 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -107,8 +107,12 @@ main!( icount_bench_fma_group, icount_bench_fmaf_group, icount_bench_fmax_group, + icount_bench_fmaxf128_group, + icount_bench_fmaxf16_group, icount_bench_fmaxf_group, icount_bench_fmin_group, + icount_bench_fminf128_group, + icount_bench_fminf16_group, icount_bench_fminf_group, icount_bench_fmod_group, icount_bench_fmodf128_group, @@ -155,6 +159,8 @@ main!( icount_bench_rintf16_group, icount_bench_rintf_group, icount_bench_round_group, + icount_bench_roundf128_group, + icount_bench_roundf16_group, icount_bench_roundf_group, icount_bench_scalbn_group, icount_bench_scalbnf_group, -- cgit 1.4.1-3-g733a5 From 7c6c0c1b79e92e36525faa4de90eee0fefde1a73 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 00:50:02 +0000 Subject: Upgrade all dependencies to the latest version In particular, this includes updates to Rug that we can make use of [1], [2], [3], [4]. [1]: https://gitlab.com/tspiteri/rug/-/issues/78 [2]: https://gitlab.com/tspiteri/rug/-/issues/80 [3]: https://gitlab.com/tspiteri/rug/-/issues/76 [4]: https://gitlab.com/tspiteri/rug/-/issues/73 --- library/compiler-builtins/libm/Cargo.toml | 2 +- library/compiler-builtins/libm/crates/libm-macros/Cargo.toml | 6 +++--- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 4 ++-- library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml | 2 +- library/compiler-builtins/libm/crates/util/Cargo.toml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 18d89997dcb..7b6f9e1cecb 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -59,7 +59,7 @@ exclude = [ ] [dev-dependencies] -no-panic = "0.1.30" +no-panic = "0.1.33" [profile.release] # Options for no-panic to correctly detect the lack of panics diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml index 9194232b24c..f0de0e17689 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml @@ -9,9 +9,9 @@ proc-macro = true [dependencies] heck = "0.5.0" -proc-macro2 = "1.0.88" -quote = "1.0.37" -syn = { version = "2.0.79", features = ["full", "extra-traits", "visit-mut"] } +proc-macro2 = "1.0.93" +quote = "1.0.38" +syn = { version = "2.0.96", features = ["full", "extra-traits", "visit-mut"] } [lints.rust] # Values used during testing diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 3a1ba87962a..137b8146423 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -27,7 +27,7 @@ icount = ["dep:iai-callgrind"] short-benchmarks = [] [dependencies] -anyhow = "1.0.90" +anyhow = "1.0.95" az = { version = "1.2.1", optional = true } gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false, features = ["mpfr"] } iai-callgrind = { version = "0.14.0", optional = true } @@ -39,7 +39,7 @@ paste = "1.0.15" rand = "0.8.5" rand_chacha = "0.3.1" rayon = "1.10.0" -rug = { version = "1.26.1", optional = true, default-features = false, features = ["float", "integer", "std"] } +rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "integer", "std"] } [target.'cfg(target_family = "wasm")'.dependencies] # Enable randomness on WASM diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml index 7f6272d79ed..cde78fd3c97 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml +++ b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml @@ -10,4 +10,4 @@ publish = false libm = { path = "../../" } [build-dependencies] -cc = "1.1.24" +cc = "1.2.10" diff --git a/library/compiler-builtins/libm/crates/util/Cargo.toml b/library/compiler-builtins/libm/crates/util/Cargo.toml index acf5db704b1..51f44dddfaf 100644 --- a/library/compiler-builtins/libm/crates/util/Cargo.toml +++ b/library/compiler-builtins/libm/crates/util/Cargo.toml @@ -16,4 +16,4 @@ libm = { path = "../..", default-features = false } libm-macros = { path = "../libm-macros" } libm-test = { path = "../libm-test", default-features = false } musl-math-sys = { path = "../musl-math-sys", optional = true } -rug = { version = "1.26.1", optional = true, default-features = false, features = ["float", "std"] } +rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "std"] } -- cgit 1.4.1-3-g733a5 From 62f0fd40d1ca80b11ad68f4d310069b76ed12aa5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 00:55:03 +0000 Subject: Use `az` exported from Rug Since Rug 1.27.0, `az` is reexported. This means we no longer need to track it as a separate dependency. --- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 3 +-- library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs | 2 +- library/compiler-builtins/libm/crates/util/Cargo.toml | 3 +-- library/compiler-builtins/libm/crates/util/src/main.rs | 4 ++-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 137b8146423..31cbf6e6802 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -12,7 +12,7 @@ unstable-float = ["libm/unstable-float", "rug?/nightly-float"] # Generate tests which are random inputs and the outputs are calculated with # musl libc. -build-mpfr = ["dep:az", "dep:rug", "dep:gmp-mpfr-sys"] +build-mpfr = ["dep:rug", "dep:gmp-mpfr-sys"] # Build our own musl for testing and benchmarks build-musl = ["dep:musl-math-sys"] @@ -28,7 +28,6 @@ short-benchmarks = [] [dependencies] anyhow = "1.0.95" -az = { version = "1.2.1", optional = true } gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false, features = ["mpfr"] } iai-callgrind = { version = "0.14.0", optional = true } indicatif = { version = "0.17.9", default-features = false } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 98b80505f26..e2be6584d23 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -6,10 +6,10 @@ use std::cmp::Ordering; use std::ffi::{c_int, c_long}; -use az::Az; use gmp_mpfr_sys::mpfr::rnd_t; use rug::Assign; pub use rug::Float as MpFloat; +use rug::az::{self, Az}; use rug::float::Round; use rug::float::Round::Nearest; use rug::ops::{PowAssignRound, RemAssignRound}; diff --git a/library/compiler-builtins/libm/crates/util/Cargo.toml b/library/compiler-builtins/libm/crates/util/Cargo.toml index 51f44dddfaf..8005459dbf9 100644 --- a/library/compiler-builtins/libm/crates/util/Cargo.toml +++ b/library/compiler-builtins/libm/crates/util/Cargo.toml @@ -7,11 +7,10 @@ publish = false [features] default = ["build-musl", "build-mpfr", "unstable-float"] build-musl = ["libm-test/build-musl", "dep:musl-math-sys"] -build-mpfr = ["libm-test/build-mpfr", "dep:az", "dep:rug"] +build-mpfr = ["libm-test/build-mpfr", "dep:rug"] unstable-float = ["libm/unstable-float", "libm-test/unstable-float", "rug?/nightly-float"] [dependencies] -az = { version = "1.2.1", optional = true } libm = { path = "../..", default-features = false } libm-macros = { path = "../libm-macros" } libm-test = { path = "../libm-test", default-features = false } diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index f4ee8fd2e38..6ea1be3d9ae 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -8,12 +8,12 @@ use std::env; use std::num::ParseIntError; use std::str::FromStr; -#[cfg(feature = "build-mpfr")] -use az::Az; use libm::support::{hf32, hf64}; #[cfg(feature = "build-mpfr")] use libm_test::mpfloat::MpOp; use libm_test::{MathOp, TupleCall}; +#[cfg(feature = "build-mpfr")] +use rug::az::{self, Az}; const USAGE: &str = "\ usage: -- cgit 1.4.1-3-g733a5 From edd12893410c1fdcb73a4a365b28bd8a9b998e8a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 01:00:01 +0000 Subject: Use `frexp` from Rug Rug 1.27.0 exposes `frexp`. Make use of it for our tests. --- library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index e2be6584d23..6896425d157 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -310,13 +310,8 @@ macro_rules! impl_op_for_ty { } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - // Implementation taken from `rug::Float::to_f32_exp`. this.assign(input.0); - let exp = this.get_exp().unwrap_or(0); - if exp != 0 { - *this >>= exp; - } - + let exp = this.frexp_mut(); (prep_retval::(this, Ordering::Equal), exp) } } -- cgit 1.4.1-3-g733a5 From b9bd107a6747b3ac44e45b2acbe8a665deb9ffaf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 01:01:24 +0000 Subject: Use `remquo` from Rug Rug 1.27.0 exposes `remquo`; make use of it for our tests. Removing our workaround also allows removing the direct dependency on `gmp-mpfr-sys` --- .../libm/crates/libm-test/Cargo.toml | 3 +- .../libm/crates/libm-test/src/mpfloat.rs | 38 ++-------------------- .../libm/crates/libm-test/src/precision.rs | 31 ------------------ 3 files changed, 5 insertions(+), 67 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 31cbf6e6802..dcbddb667e8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -28,7 +28,8 @@ short-benchmarks = [] [dependencies] anyhow = "1.0.95" -gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false, features = ["mpfr"] } +# This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. +gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } iai-callgrind = { version = "0.14.0", optional = true } indicatif = { version = "0.17.9", default-features = false } libm = { path = "../..", features = ["unstable-public-internals"] } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 6896425d157..3d84740ccd7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -4,13 +4,10 @@ //! a struct named `Operation` that implements [`MpOp`]. use std::cmp::Ordering; -use std::ffi::{c_int, c_long}; -use gmp_mpfr_sys::mpfr::rnd_t; use rug::Assign; pub use rug::Float as MpFloat; use rug::az::{self, Az}; -use rug::float::Round; use rug::float::Round::Nearest; use rug::ops::{PowAssignRound, RemAssignRound}; @@ -401,28 +398,20 @@ macro_rules! impl_op_for_ty { } impl MpOp for crate::op::[]::Routine { - type MpTy = (MpFloat, MpFloat, MpFloat); + type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { ( new_mpfloat::(), new_mpfloat::(), - new_mpfloat::() ) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { this.0.assign(input.0); this.1.assign(input.1); - let (ord, ql) = mpfr_remquo(&mut this.2, &this.0, &this.1, Nearest); - - // `remquo` integer results are sign-magnitude representation. Transfer the - // sign bit from the long result to the int result. - let clear = !(1 << (c_int::BITS - 1)); - let sign = ((ql >> (c_long::BITS - 1)) as i32) << (c_int::BITS - 1); - let q = (ql as i32) & clear | sign; - - (prep_retval::(&mut this.2, ord), q) + let (ord, q) = this.0.remainder_quo31_round(&this.1, Nearest); + (prep_retval::(&mut this.0, ord), q) } } @@ -547,24 +536,3 @@ impl MpOp for crate::op::nextafterf::Routine { unimplemented!("nextafter does not yet have a MPFR operation"); } } - -/// `rug` does not provide `remquo` so this exposes `mpfr_remquo`. See rug#76. -fn mpfr_remquo(r: &mut MpFloat, x: &MpFloat, y: &MpFloat, round: Round) -> (Ordering, c_long) { - let r = r.as_raw_mut(); - let x = x.as_raw(); - let y = y.as_raw(); - let mut q: c_long = 0; - - let round = match round { - Round::Nearest => rnd_t::RNDN, - Round::Zero => rnd_t::RNDZ, - Round::Up => rnd_t::RNDU, - Round::Down => rnd_t::RNDD, - Round::AwayZero => rnd_t::RNDA, - _ => unreachable!(), - }; - - // SAFETY: mutable and const pointers are valid and do not alias, by Rust's rules. - let ord = unsafe { gmp_mpfr_sys::mpfr::remquo(r, &mut q, x, y, round) }; - (ord.cmp(&0), q) -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index bed6158825a..ffb322e38ff 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -405,15 +405,6 @@ impl MaybeOverride<(f32, f32)> for SpecialCase { ) -> CheckAction { binop_common(input, actual, expected, ctx) } - - fn check_int( - _input: (f32, f32), - actual: I, - expected: I, - ctx: &CheckCtx, - ) -> CheckAction { - remquo_common(actual, expected, ctx) - } } impl MaybeOverride<(f64, f64)> for SpecialCase { @@ -425,15 +416,6 @@ impl MaybeOverride<(f64, f64)> for SpecialCase { ) -> CheckAction { binop_common(input, actual, expected, ctx) } - - fn check_int( - _input: (f64, f64), - actual: I, - expected: I, - ctx: &CheckCtx, - ) -> CheckAction { - remquo_common(actual, expected, ctx) - } } #[cfg(f128_enabled)] @@ -496,19 +478,6 @@ fn binop_common( DEFAULT } -fn remquo_common(actual: I, expected: I, ctx: &CheckCtx) -> CheckAction { - // FIXME: Our MPFR implementation disagrees with musl and may need to be updated. - if ctx.basis == CheckBasis::Mpfr - && ctx.base_name == BaseName::Remquo - && expected == I::MIN - && actual == I::ZERO - { - return XFAIL("remquo integer mismatch"); - } - - DEFAULT -} - impl MaybeOverride<(i32, f32)> for SpecialCase { fn check_float( input: (i32, f32), -- cgit 1.4.1-3-g733a5 From 4a98907b8a9f7cabf758fa7241466a62735fba88 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 04:18:44 +0000 Subject: Remove remnants of the `checked` feature The Cargo feature `checked` was added in 410b0633a6b9 ("Overhaul tests") and later removed in e4ac1399062c ("swap stable to be unstable, checked is now debug_assertions"). However, there are a few remaining uses of `feature = "checked"` that did not get removed. Clean these up here. --- library/compiler-builtins/libm/build.rs | 19 +++++++------------ .../crates/compiler-builtins-smoke-test/Cargo.toml | 1 - .../compiler-builtins/libm/src/math/rem_pio2_large.rs | 5 +++-- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index ca4a639a12a..caf5a108a26 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -8,18 +8,13 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); - println!("cargo:rustc-check-cfg=cfg(feature, values(\"checked\"))"); - - #[allow(unexpected_cfgs)] - if !cfg!(feature = "checked") { - let lvl = env::var("OPT_LEVEL").unwrap(); - if lvl != "0" && !cfg!(debug_assertions) { - println!("cargo:rustc-cfg=assert_no_panic"); - } else if env::var("ENSURE_NO_PANIC").is_ok() { - // Give us a defensive way of ensureing that no-panic is checked when we - // expect it to be. - panic!("`assert_no_panic `was not enabled"); - } + let lvl = env::var("OPT_LEVEL").unwrap(); + if lvl != "0" && !cfg!(debug_assertions) { + println!("cargo:rustc-cfg=assert_no_panic"); + } else if env::var("ENSURE_NO_PANIC").is_ok() { + // Give us a defensive way of ensureing that no-panic is checked when we + // expect it to be. + panic!("`assert_no_panic `was not enabled"); } configure::emit_libm_config(&cfg); diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index d578b0dcd0b..24b33645e97 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -22,7 +22,6 @@ unexpected_cfgs = { level = "warn", check-cfg = [ "cfg(arch_enabled)", "cfg(assert_no_panic)", "cfg(intrinsics_enabled)", - 'cfg(feature, values("checked"))', 'cfg(feature, values("force-soft-floats"))', 'cfg(feature, values("unstable"))', 'cfg(feature, values("unstable-intrinsics"))', diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index ec8397f4b6f..6d679bbe98c 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -226,8 +226,9 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) - #[cfg(all(target_pointer_width = "64", feature = "checked"))] - assert!(e0 <= 16360); + if cfg!(target_pointer_width = "64") { + debug_assert!(e0 <= 16360); + } let nx = x.len(); -- cgit 1.4.1-3-g733a5 From f0b932e723f05035ced4f04ff069437d4015b3d1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 05:22:11 +0000 Subject: Rework the available Cargo profiles Currently the default release profile enables LTO and single CGU builds, which is very slow to build. Most tests are better run with optimizations enabled since it allows testing a much larger number of inputs, so it is inconvenient that building can sometimes take significantly longer than the tests. Remedy this by doing the following: * Move the existing `release` profile to `release-opt`. * With the above, the default `release` profile is untouched (16 CGUs and thin local LTO). * `release-checked` inherits `release`, so no LTO or single CGU. This means that the simple `cargo test --release` becomes much faster for local development. We are able to enable the other profiles as needed in CI. Tests should ideally still be run with `--profile release-checked` to ensure there are no debug assetions or unexpected wrapping math hit. `no-panic` still needs a single CGU, so must be run with `--profile release-opt`. Since it is not possible to detect CGU or profilel configuration from within build scripts, the `ENSURE_NO_PANIC` environment variable must now always be set. --- library/compiler-builtins/libm/Cargo.toml | 14 ++++++++------ library/compiler-builtins/libm/build.rs | 8 ++------ library/compiler-builtins/libm/ci/run.sh | 12 +++++++++++- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 7b6f9e1cecb..08342a92929 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -61,18 +61,20 @@ exclude = [ [dev-dependencies] no-panic = "0.1.33" -[profile.release] -# Options for no-panic to correctly detect the lack of panics -codegen-units = 1 -lto = "fat" +# The default release profile is unchanged. # Release mode with debug assertions [profile.release-checked] -codegen-units = 1 +inherits = "release" debug-assertions = true +overflow-checks = true + +# Release with maximum optimizations, which is very slow to build. This is also +# what is needed to check `no-panic`. +[profile.release-opt] inherits = "release" +codegen-units = 1 lto = "fat" -overflow-checks = true [profile.bench] # Required for iai-callgrind diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index caf5a108a26..7042b54d7e8 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -8,13 +8,9 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); - let lvl = env::var("OPT_LEVEL").unwrap(); - if lvl != "0" && !cfg!(debug_assertions) { + // If set, enable `no-panic`. Requires LTO (`release-opt` profile). + if env::var("ENSURE_NO_PANIC").is_ok() { println!("cargo:rustc-cfg=assert_no_panic"); - } else if env::var("ENSURE_NO_PANIC").is_ok() { - // Give us a defensive way of ensureing that no-panic is checked when we - // expect it to be. - panic!("`assert_no_panic `was not enabled"); } configure::emit_libm_config(&cfg); diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 296986d9727..a946d325ebd 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -117,4 +117,14 @@ $cmd "$profile" release-checked --features unstable-intrinsics $cmd "$profile" release-checked --features unstable-intrinsics --benches # Ensure that the routines do not panic. -ENSURE_NO_PANIC=1 cargo build -p libm --target "$target" --no-default-features --release +# +# `--tests` must be passed because no-panic is only enabled as a dev +# dependency. The `release-opt` profile must be used to enable LTO and a +# single CGU. +ENSURE_NO_PANIC=1 cargo build \ + -p libm \ + --target "$target" \ + --no-default-features \ + --features unstable-float \ + --tests \ + --profile release-opt -- cgit 1.4.1-3-g733a5 From 90c76ad3cb1663592d875d0e2468a84961187800 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 27 Jan 2025 11:37:01 +0000 Subject: Ignore specific `atan2` and `sin` tests on i586 There seems to be a case of unsoundness with the `i586` version of `atan2`. For the following test: assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI);atan2(2.0, -1.0) The output is optimization-dependent. The new `release-checked` profile produces the following failure: thread 'math::atan2::sanity_check' panicked at src/math/atan2.rs:123:5: assertion `left == right` failed left: 2.0344439357957027 right: 2.0344439357957027 Similarly, `sin::test_near_pi` fails with the following: thread 'math::sin::test_near_pi' panicked at src/math/sin.rs:91:5: assertion `left == right` failed left: 6.273720864039203e-7 right: 6.273720864039205e-7 Mark the tests ignored on `i586` for now. --- library/compiler-builtins/libm/src/math/atan2.rs | 22 ++++++++++++++-------- library/compiler-builtins/libm/src/math/sin.rs | 19 +++++++++++-------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index b9bf0da935b..c668731cf37 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -114,12 +114,18 @@ pub fn atan2(y: f64, x: f64) -> f64 { } } -#[test] -fn sanity_check() { - assert_eq!(atan2(0.0, 1.0), 0.0); - assert_eq!(atan2(0.0, -1.0), PI); - assert_eq!(atan2(-0.0, -1.0), -PI); - assert_eq!(atan2(3.0, 2.0), atan(3.0 / 2.0)); - assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI); - assert_eq!(atan2(-2.0, -1.0), atan(-2.0 / -1.0) - PI); +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg_attr(x86_no_sse, ignore = "FIXME(i586): possible incorrect rounding")] + fn sanity_check() { + assert_eq!(atan2(0.0, 1.0), 0.0); + assert_eq!(atan2(0.0, -1.0), PI); + assert_eq!(atan2(-0.0, -1.0), -PI); + assert_eq!(atan2(3.0, 2.0), atan(3.0 / 2.0)); + assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI); + assert_eq!(atan2(-2.0, -1.0), atan(-2.0 / -1.0) - PI); + } } diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index e04e0d6a09d..229fa4bef08 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -81,12 +81,15 @@ pub fn sin(x: f64) -> f64 { } } -#[test] -fn test_near_pi() { - let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 - let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 - let result = sin(x); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let result = force_eval!(result); - assert_eq!(result, sx); +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg_attr(x86_no_sse, ignore = "FIXME(i586): possible incorrect rounding")] + fn test_near_pi() { + let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 + let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 + assert_eq!(sin(x), sx); + } } -- cgit 1.4.1-3-g733a5 From 64e0a0a68da8a6f5a885e5034b4e4cf44a769d41 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 27 Jan 2025 12:56:15 +0000 Subject: Remove use of the `start` feature `#![feature(start)]` was removed in [1], but we make use of it in the intrinsics example. Replace use of this feature with `#[no_mangle]` applied to `#[main]`. We don't actually run this example so it is not a problem if this is not entirely accurate. Currently the example does not run to completion, instead invoking `rust_begin_unwind`. [1]: https://github.com/rust-lang/rust/pull/134299 --- library/compiler-builtins/examples/intrinsics.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index e13c0fb1fa2..59a70e20745 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -5,14 +5,13 @@ #![allow(unused_features)] #![allow(internal_features)] -#![cfg_attr(thumb, no_main)] #![deny(dead_code)] #![feature(allocator_api)] #![feature(f128)] #![feature(f16)] #![feature(lang_items)] -#![feature(start)] #![no_std] +#![no_main] extern crate panic_handler; @@ -630,11 +629,10 @@ fn run() { extern "C" { fn rust_begin_unwind(x: usize); } - // if bb(false) { + unsafe { rust_begin_unwind(0); } - // } } fn something_with_a_dtor(f: &dyn Fn()) { @@ -649,15 +647,15 @@ fn something_with_a_dtor(f: &dyn Fn()) { f(); } +#[no_mangle] #[cfg(not(thumb))] -#[start] -fn main(_: isize, _: *const *const u8) -> isize { +fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { run(); 0 } -#[cfg(thumb)] #[no_mangle] +#[cfg(thumb)] pub fn _start() -> ! { run(); loop {} -- cgit 1.4.1-3-g733a5 From 4e1b885595447386c925be1732cccfed9daf8807 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 08:45:56 +0000 Subject: Add a version to some FIXMEs that will be resolved in LLVM 20 --- library/compiler-builtins/configure.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index 87bc7a0eed3..fa3e302ea87 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -74,7 +74,7 @@ pub fn configure_f16_f128(target: &Target) { // Selection failure "s390x" => false, // Infinite recursion - // FIXME(llvm): loongarch fixed by + // FIXME(llvm20): loongarch fixed by "csky" => false, "hexagon" => false, "loongarch64" => false, @@ -91,7 +91,7 @@ pub fn configure_f16_f128(target: &Target) { "amdgpu" => false, // Unsupported "arm64ec" => false, - // Selection failure + // FIXME(llvm20): fixed by "mips64" | "mips64r6" => false, // Selection failure "nvptx64" => false, -- cgit 1.4.1-3-g733a5 From 259e544192999988c2ad7e4264e650c0db0524ce Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 27 Jan 2025 23:25:00 +0000 Subject: Switch musl from a script download to a submodule Rather than keeping a script that downloads the tarball, we can just add musl as a submodule and let git handle the synchronizatoin. Do so here. --- .../libm/.github/workflows/main.yaml | 18 ++++++++-------- library/compiler-builtins/libm/.gitignore | 1 - library/compiler-builtins/libm/.gitmodules | 4 ++++ library/compiler-builtins/libm/CONTRIBUTING.md | 4 ++++ library/compiler-builtins/libm/ci/download-musl.sh | 24 ---------------------- .../libm/crates/musl-math-sys/build.rs | 14 +++---------- .../libm/crates/musl-math-sys/musl | 1 + 7 files changed, 20 insertions(+), 46 deletions(-) create mode 100644 library/compiler-builtins/libm/.gitmodules delete mode 100755 library/compiler-builtins/libm/ci/download-musl.sh create mode 160000 library/compiler-builtins/libm/crates/musl-math-sys/musl diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 59955271170..e03d7ecd319 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -79,6 +79,8 @@ jobs: - name: Print runner information run: uname -a - uses: actions/checkout@v4 + with: + submodules: true - name: Install Rust (rustup) shell: bash run: | @@ -94,10 +96,6 @@ jobs: with: key: ${{ matrix.target }} - - name: Download musl source - run: ./ci/download-musl.sh - shell: bash - - name: Verify API list if: matrix.os == 'ubuntu-24.04' run: python3 etc/update-api-list.py --check @@ -126,14 +124,14 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@master + with: + submodules: true - name: Install Rust run: | rustup update nightly --no-self-update rustup default nightly rustup component add clippy - uses: Swatinem/rust-cache@v2 - - name: Download musl source - run: ./ci/download-musl.sh - run: cargo clippy --all --all-features --all-targets builtins: @@ -153,6 +151,8 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@master + with: + submodules: true - uses: taiki-e/install-action@cargo-binstall - name: Set up dependencies @@ -166,8 +166,6 @@ jobs: sudo apt-get install valgrind - uses: Swatinem/rust-cache@v2 - - name: Download musl source - run: ./ci/download-musl.sh - name: Run icount benchmarks env: @@ -259,13 +257,13 @@ jobs: CHANGED: ${{ matrix.changed }} steps: - uses: actions/checkout@v4 + with: + submodules: true - name: Install Rust run: | rustup update nightly --no-self-update rustup default nightly - uses: Swatinem/rust-cache@v2 - - name: Download musl source - run: ./ci/download-musl.sh - name: Run extensive tests run: | echo "Changed: '$CHANGED'" diff --git a/library/compiler-builtins/libm/.gitignore b/library/compiler-builtins/libm/.gitignore index a447c34cd0f..d5caba1a0f3 100644 --- a/library/compiler-builtins/libm/.gitignore +++ b/library/compiler-builtins/libm/.gitignore @@ -4,7 +4,6 @@ /math/src target Cargo.lock -musl/ **.tar.gz # Benchmark cache diff --git a/library/compiler-builtins/libm/.gitmodules b/library/compiler-builtins/libm/.gitmodules new file mode 100644 index 00000000000..35b269eadd4 --- /dev/null +++ b/library/compiler-builtins/libm/.gitmodules @@ -0,0 +1,4 @@ +[submodule "musl"] + path = crates/musl-math-sys/musl + url = https://git.musl-libc.org/git/musl + shallow = true diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index ba7f78ca014..dc40060357c 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -62,6 +62,10 @@ Check [PR #65] for an example. Normal tests can be executed with: ```sh +# Tests against musl require that the submodule is up to date. +git submodule init +git submodule update + # `--release` ables more test cases cargo test --release ``` diff --git a/library/compiler-builtins/libm/ci/download-musl.sh b/library/compiler-builtins/libm/ci/download-musl.sh deleted file mode 100755 index 8a8c58550bb..00000000000 --- a/library/compiler-builtins/libm/ci/download-musl.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# Download the expected version of musl to a directory `musl` - -set -eux - -fname=musl-1.2.5.tar.gz -sha=a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4 - -mkdir musl -curl -L "https://musl.libc.org/releases/$fname" -O --retry 5 - -case "$(uname -s)" in - MINGW*) - # Need to extract the second line because certutil does human output - fsha=$(certutil -hashfile "$fname" SHA256 | sed -n '2p') - [ "$sha" = "$fsha" ] || exit 1 - ;; - *) - echo "$sha $fname" | shasum -a 256 --check || exit 1 - ;; -esac - -tar -xzf "$fname" -C musl --strip-components 1 -rm "$fname" diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs index d75748159ca..f06d84ee267 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs +++ b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs @@ -79,17 +79,12 @@ impl Config { let target_features = env::var("CARGO_CFG_TARGET_FEATURE") .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) .unwrap_or_default(); - - // Default to the `{workspace_root}/musl` if not specified - let musl_dir = env::var("MUSL_SOURCE_DIR") - .map(PathBuf::from) - .unwrap_or_else(|_| manifest_dir.parent().unwrap().parent().unwrap().join("musl")); + let musl_dir = manifest_dir.join("musl"); let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); let musl_arch = if target_arch == "x86" { "i386".to_owned() } else { target_arch.clone() }; println!("cargo::rerun-if-changed={}/c_patches", manifest_dir.display()); - println!("cargo::rerun-if-env-changed=MUSL_SOURCE_DIR"); println!("cargo::rerun-if-changed={}", musl_dir.display()); Self { @@ -111,13 +106,10 @@ impl Config { /// Build musl math symbols to a static library fn build_musl_math(cfg: &Config) { let musl_dir = &cfg.musl_dir; - assert!( - musl_dir.exists(), - "musl source is missing. it can be downloaded with ./ci/download-musl.sh" - ); - let math = musl_dir.join("src/math"); let arch_dir = musl_dir.join("arch").join(&cfg.musl_arch); + assert!(math.exists(), "musl source not found. Is the submodule up to date?"); + let source_map = find_math_source(&math, cfg); let out_path = cfg.out_dir.join(format!("lib{LIB_NAME}.a")); diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/musl b/library/compiler-builtins/libm/crates/musl-math-sys/musl new file mode 160000 index 00000000000..0784374d561 --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-math-sys/musl @@ -0,0 +1 @@ +Subproject commit 0784374d561435f7c787a555aeab8ede699ed298 -- cgit 1.4.1-3-g733a5 From 176d22db1269f6a84277978ea28cefb66f76369e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 28 Jan 2025 10:31:33 +0000 Subject: Temporarily pin `indicatif` to 0.17.9 0.17.10 introduced a change that removes `Sync` from `ProgressStyle`, which makes it more difficult to share in a callback. Pin the dependency for now until we see if `indicatif` will change this back or if we need to find a workaround. --- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index dcbddb667e8..63e75260e86 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -31,7 +31,8 @@ anyhow = "1.0.95" # This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } iai-callgrind = { version = "0.14.0", optional = true } -indicatif = { version = "0.17.9", default-features = false } +# 0.17.10 made `ProgressStyle` non-`Sync` +indicatif = { version = "=0.17.9", default-features = false } libm = { path = "../..", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } -- cgit 1.4.1-3-g733a5 From ececfaba78f150818b846b897f0fe8151258dd3e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 28 Jan 2025 15:40:23 +0100 Subject: Don't build out of line atomics support code for uefi https://github.com/llvm/llvm-project/pull/116706 added Windows support to cpu_model. Compiling for UEFI also goes through that code path, because we treat it as a windows target. However, including windows.h is not actually going to work (and the used API would not be available in an UEFI environment). Disable building of cpu_model on UEFI to fix this. --- library/compiler-builtins/build.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index f512fc2e667..39cee311f85 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -644,9 +644,10 @@ mod c { // Include out-of-line atomics for aarch64, which are all generated by supplying different // sets of flags to the same source file. - // Note: Out-of-line aarch64 atomics are not supported by the msvc toolchain (#430). + // Note: Out-of-line aarch64 atomics are not supported by the msvc toolchain (#430) and + // on uefi. let src_dir = root.join("lib/builtins"); - if target.arch == "aarch64" && target.env != "msvc" { + if target.arch == "aarch64" && target.env != "msvc" && target.os != "uefi" { // See below for why we're building these as separate libraries. build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); -- cgit 1.4.1-3-g733a5 From 396725e1464564ae052cd6ad8191d4d8ab38d804 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 28 Jan 2025 13:54:26 -0600 Subject: Revert "Temporarily pin `indicatif` to 0.17.9" This reverts commit 1dacdabdb6186f97144c50f8952575576deb3730. --- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 63e75260e86..dcbddb667e8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -31,8 +31,7 @@ anyhow = "1.0.95" # This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } iai-callgrind = { version = "0.14.0", optional = true } -# 0.17.10 made `ProgressStyle` non-`Sync` -indicatif = { version = "=0.17.9", default-features = false } +indicatif = { version = "0.17.9", default-features = false } libm = { path = "../..", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } -- cgit 1.4.1-3-g733a5 From 99c1080556577145387a1a4cf75e17548eb78eaa Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 28 Jan 2025 09:50:21 +0000 Subject: Support parsing NaN and infinities from the `hf*` functions This isn't very useful for constants since the trait constants are available, but does enable roundtripping via hex float syntax. --- .../libm/crates/libm-test/src/f8_impl.rs | 6 +++ .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/src/math/support/hex_float.rs | 63 ++++++++++++++++++---- .../compiler-builtins/libm/src/math/support/mod.rs | 2 +- 4 files changed, 61 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index 96b78392453..5dce9be1891 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -3,6 +3,8 @@ use std::cmp::{self, Ordering}; use std::{fmt, ops}; +use libm::support::hex_float::parse_any; + use crate::Float; /// Sometimes verifying float logic is easiest when all values can quickly be checked exhaustively @@ -490,3 +492,7 @@ impl fmt::LowerHex for f8 { self.0.fmt(f) } } + +pub const fn hf8(s: &str) -> f8 { + f8(parse_any(s, 8, 3) as u8) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 78b011b1f23..d2fef232505 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -20,7 +20,7 @@ use std::path::PathBuf; use std::sync::LazyLock; use std::time::SystemTime; -pub use f8_impl::f8; +pub use f8_impl::{f8, hf8}; pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, linear_ints, logspace}; pub use op::{ diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index 949f21a57ff..6eb1bd67a99 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -26,17 +26,25 @@ pub const fn hf128(s: &str) -> f128 { f128::from_bits(parse_any(s, 128, 112)) } -const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 { +/// Parse any float from hex to its bitwise representation. +/// +/// `nan_repr` is passed rather than constructed so the platform-specific NaN is returned. +pub const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 { let exp_bits: u32 = bits - sig_bits - 1; let max_msb: i32 = (1 << (exp_bits - 1)) - 1; // The exponent of one ULP in the subnormals let min_lsb: i32 = 1 - max_msb - sig_bits as i32; - let (neg, mut sig, exp) = parse_hex(s.as_bytes()); + let exp_mask = ((1 << exp_bits) - 1) << sig_bits; - if sig == 0 { - return (neg as u128) << (bits - 1); - } + let (neg, mut sig, exp) = match parse_hex(s.as_bytes()) { + Parsed::Finite { neg, sig: 0, .. } => return (neg as u128) << (bits - 1), + Parsed::Finite { neg, sig, exp } => (neg, sig, exp), + Parsed::Infinite { neg } => return ((neg as u128) << (bits - 1)) | exp_mask, + Parsed::Nan { neg } => { + return ((neg as u128) << (bits - 1)) | exp_mask | 1 << (sig_bits - 1); + } + }; // exponents of the least and most significant bits in the value let lsb = sig.trailing_zeros() as i32; @@ -76,11 +84,24 @@ const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 { sig | ((neg as u128) << (bits - 1)) } +/// A parsed floating point number. +enum Parsed { + /// Absolute value sig * 2^e + Finite { + neg: bool, + sig: u128, + exp: i32, + }, + Infinite { + neg: bool, + }, + Nan { + neg: bool, + }, +} + /// Parse a hexadecimal float x -/// returns (s,n,e): -/// s == x.is_sign_negative() -/// n * 2^e == x.abs() -const fn parse_hex(mut b: &[u8]) -> (bool, u128, i32) { +const fn parse_hex(mut b: &[u8]) -> Parsed { let mut neg = false; let mut sig: u128 = 0; let mut exp: i32 = 0; @@ -90,6 +111,12 @@ const fn parse_hex(mut b: &[u8]) -> (bool, u128, i32) { neg = c == b'-'; } + match *b { + [b'i' | b'I', b'n' | b'N', b'f' | b'F'] => return Parsed::Infinite { neg }, + [b'n' | b'N', b'a' | b'A', b'n' | b'N'] => return Parsed::Nan { neg }, + _ => (), + } + if let &[b'0', b'x' | b'X', ref rest @ ..] = b { b = rest; } else { @@ -152,7 +179,7 @@ const fn parse_hex(mut b: &[u8]) -> (bool, u128, i32) { exp += pexp; } - (neg, sig, exp) + Parsed::Finite { neg, sig, exp } } const fn dec_digit(c: u8) -> u8 { @@ -272,6 +299,10 @@ mod tests { ("-0x1.998p-4", (-0.1f16).to_bits()), ("0x0.123p-12", 0x0123), ("0x1p-24", 0x0001), + ("nan", f16::NAN.to_bits()), + ("-nan", (-f16::NAN).to_bits()), + ("inf", f16::INFINITY.to_bits()), + ("-inf", f16::NEG_INFINITY.to_bits()), ]; for (s, exp) in checks { println!("parsing {s}"); @@ -322,6 +353,10 @@ mod tests { ("0x1.111114p-127", 0x00444445), ("0x1.23456p-130", 0x00091a2b), ("0x1p-149", 0x00000001), + ("nan", f32::NAN.to_bits()), + ("-nan", (-f32::NAN).to_bits()), + ("inf", f32::INFINITY.to_bits()), + ("-inf", f32::NEG_INFINITY.to_bits()), ]; for (s, exp) in checks { println!("parsing {s}"); @@ -360,6 +395,10 @@ mod tests { ("0x0.8000000000001p-1022", 0x0008000000000001), ("0x0.123456789abcdp-1022", 0x000123456789abcd), ("0x0.0000000000002p-1022", 0x0000000000000002), + ("nan", f64::NAN.to_bits()), + ("-nan", (-f64::NAN).to_bits()), + ("inf", f64::INFINITY.to_bits()), + ("-inf", f64::NEG_INFINITY.to_bits()), ]; for (s, exp) in checks { println!("parsing {s}"); @@ -401,6 +440,10 @@ mod tests { ("-0x1.999999999999999999999999999ap-4", (-0.1f128).to_bits()), ("0x0.abcdef0123456789abcdef012345p-16382", 0x0000abcdef0123456789abcdef012345), ("0x1p-16494", 0x00000000000000000000000000000001), + ("nan", f128::NAN.to_bits()), + ("-nan", (-f128::NAN).to_bits()), + ("inf", f128::INFINITY.to_bits()), + ("-inf", f128::NEG_INFINITY.to_bits()), ]; for (s, exp) in checks { println!("parsing {s}"); diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index da9e2c9ed62..b82a2ea0540 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -2,7 +2,7 @@ pub mod macros; mod big; mod float_traits; -mod hex_float; +pub mod hex_float; mod int_traits; #[allow(unused_imports)] -- cgit 1.4.1-3-g733a5 From f767b58ba4fad1e8184f699dad5eb83734a5346d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 28 Jan 2025 09:51:43 +0000 Subject: Introduce a wrapper type for IEEE hex float formatting --- .../libm/src/math/support/hex_float.rs | 183 ++++++++++++++++++++- .../compiler-builtins/libm/src/math/support/mod.rs | 2 +- 2 files changed, 181 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index 6eb1bd67a99..da41622f296 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -2,7 +2,9 @@ #![allow(dead_code)] // FIXME: remove once this gets used -use super::{f32_from_bits, f64_from_bits}; +use core::fmt; + +use super::{Float, f32_from_bits, f64_from_bits}; /// Construct a 16-bit float from hex float representation (C-style) #[cfg(f16_enabled)] @@ -42,7 +44,7 @@ pub const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 { Parsed::Finite { neg, sig, exp } => (neg, sig, exp), Parsed::Infinite { neg } => return ((neg as u128) << (bits - 1)) | exp_mask, Parsed::Nan { neg } => { - return ((neg as u128) << (bits - 1)) | exp_mask | 1 << (sig_bits - 1); + return ((neg as u128) << (bits - 1)) | exp_mask | (1 << (sig_bits - 1)); } }; @@ -206,8 +208,107 @@ const fn u128_ilog2(v: u128) -> u32 { u128::BITS - 1 - v.leading_zeros() } +/// Format a floating point number as its IEEE hex (`%a`) representation. +pub struct Hexf(pub F); + +// Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs +fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if x.is_sign_negative() { + write!(f, "-")?; + } + + if x.is_nan() { + return write!(f, "NaN"); + } else if x.is_infinite() { + return write!(f, "inf"); + } else if *x == F::ZERO { + return write!(f, "0x0p+0"); + } + + let mut exponent = x.exp_unbiased(); + let sig = x.to_bits() & F::SIG_MASK; + + let bias = F::EXP_BIAS as i32; + // The mantissa MSB needs to be shifted up to the nearest nibble. + let mshift = (4 - (F::SIG_BITS % 4)) % 4; + let sig = sig << mshift; + // The width is rounded up to the nearest char (4 bits) + let mwidth = (F::SIG_BITS as usize + 3) / 4; + let leading = if exponent == -bias { + // subnormal number means we shift our output by 1 bit. + exponent += 1; + "0." + } else { + "1." + }; + + write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") +} + +#[cfg(f16_enabled)] +impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt_any_hex(&self.0, f) + } +} + +impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt_any_hex(&self.0, f) + } +} + +impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt_any_hex(&self.0, f) + } +} + +#[cfg(f128_enabled)] +impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt_any_hex(&self.0, f) + } +} + +impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(&self.0, f) + } +} + +impl fmt::LowerHex for Hexf<(T1, T2)> +where + T1: Copy, + T2: Copy, + Hexf: fmt::LowerHex, + Hexf: fmt::LowerHex, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + } +} + +impl fmt::Debug for Hexf +where + Hexf: fmt::LowerHex, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(self, f) + } +} + +impl fmt::Display for Hexf +where + Hexf: fmt::LowerHex, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(self, f) + } +} + #[cfg(test)] -mod tests { +mod parse_tests { extern crate std; use std::{format, println}; @@ -666,3 +767,79 @@ mod tests_panicking { #[cfg(f128_enabled)] f128_tests!(); } + +#[cfg(test)] +mod print_tests { + extern crate std; + use std::string::ToString; + + use super::*; + + #[test] + #[cfg(f16_enabled)] + fn test_f16() { + use std::format; + // Exhaustively check that `f16` roundtrips. + for x in 0..=u16::MAX { + let f = f16::from_bits(x); + let s = format!("{}", Hexf(f)); + let from_s = hf16(&s); + + if f.is_nan() && from_s.is_nan() { + continue; + } + + assert_eq!( + f.to_bits(), + from_s.to_bits(), + "{f:?} formatted as {s} but parsed as {from_s:?}" + ); + } + } + + #[test] + fn spot_checks() { + assert_eq!(Hexf(f32::MAX).to_string(), "0x1.fffffep+127"); + assert_eq!(Hexf(f64::MAX).to_string(), "0x1.fffffffffffffp+1023"); + + assert_eq!(Hexf(f32::MIN).to_string(), "-0x1.fffffep+127"); + assert_eq!(Hexf(f64::MIN).to_string(), "-0x1.fffffffffffffp+1023"); + + assert_eq!(Hexf(f32::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hexf(f64::ZERO).to_string(), "0x0p+0"); + + assert_eq!(Hexf(f32::NEG_ZERO).to_string(), "-0x0p+0"); + assert_eq!(Hexf(f64::NEG_ZERO).to_string(), "-0x0p+0"); + + assert_eq!(Hexf(f32::NAN).to_string(), "NaN"); + assert_eq!(Hexf(f64::NAN).to_string(), "NaN"); + + assert_eq!(Hexf(f32::INFINITY).to_string(), "inf"); + assert_eq!(Hexf(f64::INFINITY).to_string(), "inf"); + + assert_eq!(Hexf(f32::NEG_INFINITY).to_string(), "-inf"); + assert_eq!(Hexf(f64::NEG_INFINITY).to_string(), "-inf"); + + #[cfg(f16_enabled)] + { + assert_eq!(Hexf(f16::MAX).to_string(), "0x1.ffcp+15"); + assert_eq!(Hexf(f16::MIN).to_string(), "-0x1.ffcp+15"); + assert_eq!(Hexf(f16::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hexf(f16::NEG_ZERO).to_string(), "-0x0p+0"); + assert_eq!(Hexf(f16::NAN).to_string(), "NaN"); + assert_eq!(Hexf(f16::INFINITY).to_string(), "inf"); + assert_eq!(Hexf(f16::NEG_INFINITY).to_string(), "-inf"); + } + + #[cfg(f128_enabled)] + { + assert_eq!(Hexf(f128::MAX).to_string(), "0x1.ffffffffffffffffffffffffffffp+16383"); + assert_eq!(Hexf(f128::MIN).to_string(), "-0x1.ffffffffffffffffffffffffffffp+16383"); + assert_eq!(Hexf(f128::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hexf(f128::NEG_ZERO).to_string(), "-0x0p+0"); + assert_eq!(Hexf(f128::NAN).to_string(), "NaN"); + assert_eq!(Hexf(f128::INFINITY).to_string(), "inf"); + assert_eq!(Hexf(f128::NEG_INFINITY).to_string(), "-inf"); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index b82a2ea0540..d471c5b7013 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -13,7 +13,7 @@ pub use hex_float::hf16; #[cfg(f128_enabled)] pub use hex_float::hf128; #[allow(unused_imports)] -pub use hex_float::{hf32, hf64}; +pub use hex_float::{Hexf, hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; /// Hint to the compiler that the current path is cold. -- cgit 1.4.1-3-g733a5 From e283c25602a7ab12ea8e4b62db1fe18c4678da1f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 28 Jan 2025 10:09:27 +0000 Subject: Util: also print the hex float format for outputs --- library/compiler-builtins/libm/crates/util/src/main.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 6ea1be3d9ae..357df6b4fe2 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -8,7 +8,7 @@ use std::env; use std::num::ParseIntError; use std::str::FromStr; -use libm::support::{hf32, hf64}; +use libm::support::{Hexf, hf32, hf64}; #[cfg(feature = "build-mpfr")] use libm_test::mpfloat::MpOp; use libm_test::{MathOp, TupleCall}; @@ -73,7 +73,7 @@ macro_rules! handle_call { } _ => panic!("unrecognized or disabled basis '{}'", $basis), }; - println!("{output:?}"); + println!("{output:?} {:x}", Hexf(output)); return; } }; @@ -303,6 +303,10 @@ impl FromStrRadix for i32 { #[cfg(f16_enabled)] impl FromStrRadix for f16 { fn from_str_radix(s: &str, radix: u32) -> Result { + if radix == 16 && s.contains("p") { + return Ok(libm::support::hf16(s)); + } + let s = strip_radix_prefix(s, radix); u16::from_str_radix(s, radix).map(Self::from_bits) } @@ -334,6 +338,9 @@ impl FromStrRadix for f64 { #[cfg(f128_enabled)] impl FromStrRadix for f128 { fn from_str_radix(s: &str, radix: u32) -> Result { + if radix == 16 && s.contains("p") { + return Ok(libm::support::hf128(s)); + } let s = strip_radix_prefix(s, radix); u128::from_str_radix(s, radix).map(Self::from_bits) } -- cgit 1.4.1-3-g733a5 From 7d674145aee6065c61f71f176fa8acc229f00953 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 30 Jan 2025 13:06:41 -0800 Subject: Specify license as just MIT Simplify the SPDX string to the user-facing version to make it easier for users and tooling to understand. Contributions must still be `MIT OR Apache-2.0`. [ add commit body with context - Trevor ] --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 08342a92929..f24f4423c7b 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -4,7 +4,7 @@ categories = ["no-std"] description = "libm in pure Rust" documentation = "https://docs.rs/libm" keywords = ["libm", "math"] -license = "MIT AND (MIT OR Apache-2.0)" +license = "MIT" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -- cgit 1.4.1-3-g733a5 From 8db5ff73e62605ad5d94bb0c17124475058b8b54 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 31 Jan 2025 12:31:35 +0000 Subject: Rename `EXP_MAX` to `EXP_SAT` `EXP_MAX` sounds like it would be the maximum value representable by that float type's exponent, rather than the maximum unsigned value of its bits. Clarify this by renaming to `EXP_SAT`, the "saturated" exponent representation. --- .../compiler-builtins/libm/src/math/generic/fmod.rs | 2 +- .../compiler-builtins/libm/src/math/generic/sqrt.rs | 4 ++-- .../libm/src/math/support/float_traits.rs | 21 ++++++++++++--------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs index 93da6c51e7e..ca1cda38323 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmod.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs @@ -13,7 +13,7 @@ pub fn fmod(x: F, y: F) -> F { let mut ey = y.exp().signed(); let sx = ix & F::SIGN_MASK; - if iy << 1 == zero || y.is_nan() || ex == F::EXP_MAX as i32 { + if iy << 1 == zero || y.is_nan() || ex == F::EXP_SAT as i32 { return (x * y) / (x * y); } diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index c20c0f20525..90d6c01e917 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -68,7 +68,7 @@ where (Exp::NoShift(()), special_case) } else { let top = u32::cast_from(ix >> F::SIG_BITS); - let special_case = top.wrapping_sub(1) >= F::EXP_MAX - 1; + let special_case = top.wrapping_sub(1) >= F::EXP_SAT - 1; (Exp::Shifted(top), special_case) }; @@ -119,7 +119,7 @@ where if even { m_u2 >>= 1; } - e = (e.wrapping_add(F::EXP_MAX >> 1)) >> 1; + e = (e.wrapping_add(F::EXP_SAT >> 1)) >> 1; (m_u2, Exp::Shifted(e)) } Exp::NoShift(()) => { diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 57e4aebecfc..1fe2cb424b9 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -48,11 +48,14 @@ pub trait Float: /// The bitwidth of the exponent const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; - /// The saturated value of the exponent (infinite representation), in the rightmost postiion. - const EXP_MAX: u32 = (1 << Self::EXP_BITS) - 1; + /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite + /// representation. + /// + /// This shifted fully right, use `EXP_MASK` for the shifted value. + const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; /// The exponent bias value - const EXP_BIAS: u32 = Self::EXP_MAX >> 1; + const EXP_BIAS: u32 = Self::EXP_SAT >> 1; /// A mask for the sign bit const SIGN_MASK: Self::Int; @@ -109,7 +112,7 @@ pub trait Float: /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. fn exp(self) -> u32 { - u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_MAX + u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_SAT } /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. @@ -135,7 +138,7 @@ pub trait Float: let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; Self::from_bits( (sign << (Self::BITS - 1)) - | (Self::Int::cast_from(exponent & Self::EXP_MAX) << Self::SIG_BITS) + | (Self::Int::cast_from(exponent & Self::EXP_SAT) << Self::SIG_BITS) | (significand & Self::SIG_MASK), ) } @@ -267,7 +270,7 @@ mod tests { #[cfg(f16_enabled)] fn check_f16() { // Constants - assert_eq!(f16::EXP_MAX, 0b11111); + assert_eq!(f16::EXP_SAT, 0b11111); assert_eq!(f16::EXP_BIAS, 15); // `exp_unbiased` @@ -289,7 +292,7 @@ mod tests { #[test] fn check_f32() { // Constants - assert_eq!(f32::EXP_MAX, 0b11111111); + assert_eq!(f32::EXP_SAT, 0b11111111); assert_eq!(f32::EXP_BIAS, 127); // `exp_unbiased` @@ -312,7 +315,7 @@ mod tests { #[test] fn check_f64() { // Constants - assert_eq!(f64::EXP_MAX, 0b11111111111); + assert_eq!(f64::EXP_SAT, 0b11111111111); assert_eq!(f64::EXP_BIAS, 1023); // `exp_unbiased` @@ -336,7 +339,7 @@ mod tests { #[cfg(f128_enabled)] fn check_f128() { // Constants - assert_eq!(f128::EXP_MAX, 0b111111111111111); + assert_eq!(f128::EXP_SAT, 0b111111111111111); assert_eq!(f128::EXP_BIAS, 16383); // `exp_unbiased` -- cgit 1.4.1-3-g733a5 From 5a5a5a39ad87a3a78e4a67da7bb7c53203381663 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Sat, 1 Feb 2025 02:14:22 +0300 Subject: Indentation fix to please clippy --- library/compiler-builtins/src/float/conv.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 83a181c37d4..4f52ac7120d 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -344,8 +344,7 @@ where /// /// Parameters: /// - `fbits`: `abg(f)` bitcasted to an integer. -/// - `map_inbounds`: apply this transformation to integers that are within range (add the sign -/// back). +/// - `map_inbounds`: apply this transformation to integers that are within range (add the sign back). /// - `out_of_bounds`: return value when out of range for `I`. fn float_to_int_inner( fbits: F::Int, -- cgit 1.4.1-3-g733a5 From 57572a583da932aed817b0677bf6a85d135dc920 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 4 Feb 2025 10:36:45 +0000 Subject: Revert "Eliminate the use of `public_test_dep!`" [1] has not gone forward, so this needs to be reverted again in order to unblock a compiler-builtins upgrade that is necessary for the LLVM 20 upgrade. This reverts commit a2494f14e99ae90c964f12bf0c059d63ccc07c2a. [1]: https://github.com/rust-lang/rust/pull/135501 --- library/compiler-builtins/src/float/mod.rs | 195 +++++++++- library/compiler-builtins/src/float/traits.rs | 189 --------- library/compiler-builtins/src/int/leading_zeros.rs | 227 ++++++----- library/compiler-builtins/src/int/mod.rs | 424 ++++++++++++++++++++- .../src/int/specialized_div_rem/delegate.rs | 4 +- .../compiler-builtins/src/int/trailing_zeros.rs | 69 ++-- library/compiler-builtins/src/int/traits.rs | 411 -------------------- library/compiler-builtins/src/macros.rs | 16 + 8 files changed, 772 insertions(+), 763 deletions(-) delete mode 100644 library/compiler-builtins/src/float/traits.rs delete mode 100644 library/compiler-builtins/src/int/traits.rs diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 41b308626b3..6ee55950e18 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,3 +1,7 @@ +use core::ops; + +use crate::int::{DInt, Int, MinInt}; + pub mod add; pub mod cmp; pub mod conv; @@ -6,11 +10,192 @@ pub mod extend; pub mod mul; pub mod pow; pub mod sub; -pub(crate) mod traits; pub mod trunc; -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use traits::{Float, HalfRep}; +/// Wrapper to extract the integer type half of the float's size +pub(crate) type HalfRep = <::Int as DInt>::H; + +public_test_dep! { +/// Trait for some basic operations on floats +#[allow(dead_code)] +pub(crate) trait Float: + Copy + + core::fmt::Debug + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::MulAssign + + ops::Add + + ops::Sub + + ops::Div + + ops::Rem +{ + /// A uint of the same width as the float + type Int: Int; + + /// A int of the same width as the float + type SignedInt: Int + MinInt; + + /// An int capable of containing the exponent bits plus a sign bit. This is signed. + type ExpInt: Int; + + const ZERO: Self; + const ONE: Self; + + /// The bitwidth of the float type. + const BITS: u32; + + /// The bitwidth of the significand. + const SIG_BITS: u32; + + /// The bitwidth of the exponent. + const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; + + /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite + /// representation. + /// + /// This is in the rightmost position, use `EXP_MASK` for the shifted value. + const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; + + /// The exponent bias value. + const EXP_BIAS: u32 = Self::EXP_SAT >> 1; + + /// A mask for the sign bit. + const SIGN_MASK: Self::Int; + + /// A mask for the significand. + const SIG_MASK: Self::Int; + + /// The implicit bit of the float format. + const IMPLICIT_BIT: Self::Int; + + /// A mask for the exponent. + const EXP_MASK: Self::Int; + + /// Returns `self` transmuted to `Self::Int` + fn to_bits(self) -> Self::Int; + + /// Returns `self` transmuted to `Self::SignedInt` + fn to_bits_signed(self) -> Self::SignedInt; + + /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be + /// represented in multiple different ways. This method returns `true` if two NaNs are + /// compared. + fn eq_repr(self, rhs: Self) -> bool; + + /// Returns true if the sign is negative + fn is_sign_negative(self) -> bool; + + /// Returns the exponent, not adjusting for bias. + fn exp(self) -> Self::ExpInt; + + /// Returns the significand with no implicit bit (or the "fractional" part) + fn frac(self) -> Self::Int; + + /// Returns the significand with implicit bit + fn imp_frac(self) -> Self::Int; + + /// Returns a `Self::Int` transmuted back to `Self` + fn from_bits(a: Self::Int) -> Self; + + /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self; + + fn abs(self) -> Self { + let abs_mask = !Self::SIGN_MASK ; + Self::from_bits(self.to_bits() & abs_mask) + } + + /// Returns (normalized exponent, normalized significand) + fn normalize(significand: Self::Int) -> (i32, Self::Int); + + /// Returns if `self` is subnormal + fn is_subnormal(self) -> bool; +} +} + +macro_rules! float_impl { + ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { + impl Float for $ty { + type Int = $ity; + type SignedInt = $sity; + type ExpInt = $expty; + + const ZERO: Self = 0.0; + const ONE: Self = 1.0; + + const BITS: u32 = $bits; + const SIG_BITS: u32 = $significand_bits; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; + const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); + + fn to_bits(self) -> Self::Int { + self.to_bits() + } + fn to_bits_signed(self) -> Self::SignedInt { + self.to_bits() as Self::SignedInt + } + fn eq_repr(self, rhs: Self) -> bool { + #[cfg(feature = "mangled-names")] + fn is_nan(x: $ty) -> bool { + // When using mangled-names, the "real" compiler-builtins might not have the + // necessary builtin (__unordtf2) to test whether `f128` is NaN. + // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin + // x is NaN if all the bits of the exponent are set and the significand is non-0 + x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 + } + #[cfg(not(feature = "mangled-names"))] + fn is_nan(x: $ty) -> bool { + x.is_nan() + } + if is_nan(self) && is_nan(rhs) { + true + } else { + self.to_bits() == rhs.to_bits() + } + } + fn is_sign_negative(self) -> bool { + self.is_sign_negative() + } + fn exp(self) -> Self::ExpInt { + ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt + } + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIG_MASK + } + fn imp_frac(self) -> Self::Int { + self.frac() | Self::IMPLICIT_BIT + } + fn from_bits(a: Self::Int) -> Self { + Self::from_bits(a) + } + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_bits( + ((negative as Self::Int) << (Self::BITS - 1)) + | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) + | (significand & Self::SIG_MASK), + ) + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); + ( + 1i32.wrapping_sub(shift as i32), + significand << shift as Self::Int, + ) + } + fn is_subnormal(self) -> bool { + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO + } + } + }; +} -#[cfg(feature = "public-test-deps")] -pub use traits::{Float, HalfRep}; +#[cfg(f16_enabled)] +float_impl!(f16, u16, i16, i8, 16, 10); +float_impl!(f32, u32, i32, i16, 32, 23); +float_impl!(f64, u64, i64, i16, 64, 52); +#[cfg(f128_enabled)] +float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/src/float/traits.rs deleted file mode 100644 index 8ccaa7bcbd7..00000000000 --- a/library/compiler-builtins/src/float/traits.rs +++ /dev/null @@ -1,189 +0,0 @@ -use core::ops; - -use crate::int::{DInt, Int, MinInt}; - -/// Wrapper to extract the integer type half of the float's size -pub type HalfRep = <::Int as DInt>::H; - -/// Trait for some basic operations on floats -#[allow(dead_code)] -pub trait Float: - Copy - + core::fmt::Debug - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::MulAssign - + ops::Add - + ops::Sub - + ops::Div - + ops::Rem -{ - /// A uint of the same width as the float - type Int: Int; - - /// A int of the same width as the float - type SignedInt: Int + MinInt; - - /// An int capable of containing the exponent bits plus a sign bit. This is signed. - type ExpInt: Int; - - const ZERO: Self; - const ONE: Self; - - /// The bitwidth of the float type. - const BITS: u32; - - /// The bitwidth of the significand. - const SIG_BITS: u32; - - /// The bitwidth of the exponent. - const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; - - /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite - /// representation. - /// - /// This is in the rightmost position, use `EXP_MASK` for the shifted value. - const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; - - /// The exponent bias value. - const EXP_BIAS: u32 = Self::EXP_SAT >> 1; - - /// A mask for the sign bit. - const SIGN_MASK: Self::Int; - - /// A mask for the significand. - const SIG_MASK: Self::Int; - - /// The implicit bit of the float format. - const IMPLICIT_BIT: Self::Int; - - /// A mask for the exponent. - const EXP_MASK: Self::Int; - - /// Returns `self` transmuted to `Self::Int` - fn to_bits(self) -> Self::Int; - - /// Returns `self` transmuted to `Self::SignedInt` - fn to_bits_signed(self) -> Self::SignedInt; - - /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. This method returns `true` if two NaNs are - /// compared. - fn eq_repr(self, rhs: Self) -> bool; - - /// Returns true if the sign is negative - fn is_sign_negative(self) -> bool; - - /// Returns the exponent, not adjusting for bias. - fn exp(self) -> Self::ExpInt; - - /// Returns the significand with no implicit bit (or the "fractional" part) - fn frac(self) -> Self::Int; - - /// Returns the significand with implicit bit - fn imp_frac(self) -> Self::Int; - - /// Returns a `Self::Int` transmuted back to `Self` - fn from_bits(a: Self::Int) -> Self; - - /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self; - - fn abs(self) -> Self { - let abs_mask = !Self::SIGN_MASK; - Self::from_bits(self.to_bits() & abs_mask) - } - - /// Returns (normalized exponent, normalized significand) - fn normalize(significand: Self::Int) -> (i32, Self::Int); - - /// Returns if `self` is subnormal - fn is_subnormal(self) -> bool; -} - -macro_rules! float_impl { - ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { - impl Float for $ty { - type Int = $ity; - type SignedInt = $sity; - type ExpInt = $expty; - - const ZERO: Self = 0.0; - const ONE: Self = 1.0; - - const BITS: u32 = $bits; - const SIG_BITS: u32 = $significand_bits; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; - const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); - - fn to_bits(self) -> Self::Int { - self.to_bits() - } - fn to_bits_signed(self) -> Self::SignedInt { - self.to_bits() as Self::SignedInt - } - fn eq_repr(self, rhs: Self) -> bool { - #[cfg(feature = "mangled-names")] - fn is_nan(x: $ty) -> bool { - // When using mangled-names, the "real" compiler-builtins might not have the - // necessary builtin (__unordtf2) to test whether `f128` is NaN. - // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin - // x is NaN if all the bits of the exponent are set and the significand is non-0 - x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 - } - #[cfg(not(feature = "mangled-names"))] - fn is_nan(x: $ty) -> bool { - x.is_nan() - } - if is_nan(self) && is_nan(rhs) { - true - } else { - self.to_bits() == rhs.to_bits() - } - } - fn is_sign_negative(self) -> bool { - self.is_sign_negative() - } - fn exp(self) -> Self::ExpInt { - ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt - } - fn frac(self) -> Self::Int { - self.to_bits() & Self::SIG_MASK - } - fn imp_frac(self) -> Self::Int { - self.frac() | Self::IMPLICIT_BIT - } - fn from_bits(a: Self::Int) -> Self { - Self::from_bits(a) - } - fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_bits( - ((negative as Self::Int) << (Self::BITS - 1)) - | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) - | (significand & Self::SIG_MASK), - ) - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); - ( - 1i32.wrapping_sub(shift as i32), - significand << shift as Self::Int, - ) - } - fn is_subnormal(self) -> bool { - (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO - } - } - }; -} - -#[cfg(f16_enabled)] -float_impl!(f16, u16, i16, i8, 16, 10); -float_impl!(f32, u32, i32, i16, 32, 23); -float_impl!(f64, u64, i64, i16, 64, 52); -#[cfg(f128_enabled)] -float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index ba735aa7462..1fee9fcf5d8 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -3,138 +3,135 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. -#[cfg(feature = "public-test-deps")] -pub use implementation::{leading_zeros_default, leading_zeros_riscv}; -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use implementation::{leading_zeros_default, leading_zeros_riscv}; +use crate::int::{CastInto, Int}; -mod implementation { - use crate::int::{CastInto, Int}; +public_test_dep! { +/// Returns the number of leading binary zeros in `x`. +#[allow(dead_code)] +pub(crate) fn leading_zeros_default>(x: T) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS as usize; + // a temporary + let mut t: T; - /// Returns the number of leading binary zeros in `x`. - #[allow(dead_code)] - pub fn leading_zeros_default>(x: T) -> usize { - // The basic idea is to test if the higher bits of `x` are zero and bisect the number - // of leading zeros. It is possible for all branches of the bisection to use the same - // code path by conditionally shifting the higher parts down to let the next bisection - // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` - // and adding to the number of zeros, it is slightly faster to start with - // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, - // because it simplifies the final bisection step. - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS as usize; - // a temporary - let mut t: T; - - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - t = x >> 32; - if t != T::ZERO { - z -= 32; - x = t; - } - } - if T::BITS >= 32 { - t = x >> 16; - if t != T::ZERO { - z -= 16; - x = t; - } - } - const { assert!(T::BITS >= 16) }; - t = x >> 8; + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + t = x >> 32; if t != T::ZERO { - z -= 8; + z -= 32; x = t; } - t = x >> 4; - if t != T::ZERO { - z -= 4; - x = t; - } - t = x >> 2; + } + if T::BITS >= 32 { + t = x >> 16; if t != T::ZERO { - z -= 2; + z -= 16; x = t; } - // the last two bisections are combined into one conditional - t = x >> 1; - if t != T::ZERO { - z - 2 - } else { - z - x.cast() - } - - // We could potentially save a few cycles by using the LUT trick from - // "https://embeddedgurus.com/state-space/2014/09/ - // fast-deterministic-and-portable-counting-leading-zeros/". - // However, 256 bytes for a LUT is too large for embedded use cases. We could remove - // the last 3 bisections and use this 16 byte LUT for the rest of the work: - //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; - //z -= LUT[x] as usize; - //z - // However, it ends up generating about the same number of instructions. When benchmarked - // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO - // execution effects. Changing to using a LUT and branching is risky for smaller cores. + } + const { assert!(T::BITS >= 16) }; + t = x >> 8; + if t != T::ZERO { + z -= 8; + x = t; + } + t = x >> 4; + if t != T::ZERO { + z -= 4; + x = t; + } + t = x >> 2; + if t != T::ZERO { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != T::ZERO { + z - 2 + } else { + z - x.cast() } - // The above method does not compile well on RISC-V (because of the lack of predicated - // instructions), producing code with many branches or using an excessively long - // branchless solution. This method takes advantage of the set-if-less-than instruction on - // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/ + // fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. +} +} - /// Returns the number of leading binary zeros in `x`. - #[allow(dead_code)] - pub fn leading_zeros_riscv>(x: T) -> usize { - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS; - // a temporary - let mut t: u32; +// The above method does not compile well on RISC-V (because of the lack of predicated +// instructions), producing code with many branches or using an excessively long +// branchless solution. This method takes advantage of the set-if-less-than instruction on +// RISC-V that allows `(x >= power-of-two) as usize` to be branchless. - // RISC-V does not have a set-if-greater-than-or-equal instruction and - // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is - // still the most optimal method. A conditional set can only be turned into a single - // immediate instruction if `x` is compared with an immediate `imm` (that can fit into - // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the - // right). If we try to save an instruction by using `x < imm` for each bisection, we - // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, - // but the immediate will never fit into 12 bits and never save an instruction. - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise - // `t` is set to 0. - t = ((x >= (T::ONE << 32)) as u32) << 5; - // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the - // next step to process. - x >>= t; - // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential - // leading zeros - z -= t; - } - if T::BITS >= 32 { - t = ((x >= (T::ONE << 16)) as u32) << 4; - x >>= t; - z -= t; - } - const { assert!(T::BITS >= 16) }; - t = ((x >= (T::ONE << 8)) as u32) << 3; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 4)) as u32) << 2; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 2)) as u32) << 1; +public_test_dep! { +/// Returns the number of leading binary zeros in `x`. +#[allow(dead_code)] +pub(crate) fn leading_zeros_riscv>(x: T) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS; + // a temporary + let mut t: u32; + + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (T::ONE << 32)) as u32) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros z -= t; - t = (x >= (T::ONE << 1)) as u32; + } + if T::BITS >= 32 { + t = ((x >= (T::ONE << 16)) as u32) << 4; x >>= t; z -= t; - // All bits except the LSB are guaranteed to be zero for this final bisection step. - // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. - z as usize - x.cast() } + const { assert!(T::BITS >= 16) }; + t = ((x >= (T::ONE << 8)) as u32) << 3; + x >>= t; + z -= t; + t = ((x >= (T::ONE << 4)) as u32) << 2; + x >>= t; + z -= t; + t = ((x >= (T::ONE << 2)) as u32) << 1; + x >>= t; + z -= t; + t = (x >= (T::ONE << 1)) as u32; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z as usize - x.cast() +} } intrinsics! { diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 1f1be711bbd..c0d5a6715e3 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,3 +1,5 @@ +use core::ops; + mod specialized_div_rem; pub mod addsub; @@ -8,13 +10,425 @@ pub mod mul; pub mod sdiv; pub mod shift; pub mod trailing_zeros; -mod traits; pub mod udiv; pub use big::{i256, u256}; -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; +public_test_dep! { +/// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] +pub(crate) trait MinInt: Copy + + core::fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type UnsignedInt: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} +} + +public_test_dep! { +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub(crate) trait Int: MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, + /// 112,119,120,125,126,127]. + const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); + + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; + + fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + fn unsigned_abs(self) -> Self::UnsignedInt; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} +} + +pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn unsigned(self) -> $uty { + self + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn unsigned_abs(self) -> Self { + self + } + + fn abs_diff(self, other: Self) -> Self { + self.abs_diff(other) + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn unsigned(self) -> $uty { + self as $uty + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn unsigned_abs(self) -> Self::UnsignedInt { + self.unsigned_abs() + } + + fn abs_diff(self, other: Self) -> $uty { + self.abs_diff(other) + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +public_test_dep! { +/// Trait for integers twice the bit width of another integer. This is implemented for all +/// primitives except for `u8`, because there is not a smaller primitive. +pub(crate) trait DInt: MinInt { + /// Integer that is half the bit width of the integer this trait is implemented for + type H: HInt; + + /// Returns the low half of `self` + fn lo(self) -> Self::H; + /// Returns the high half of `self` + fn hi(self) -> Self::H; + /// Returns the low and high halves of `self` as a tuple + fn lo_hi(self) -> (Self::H, Self::H) { + (self.lo(), self.hi()) + } + /// Constructs an integer using lower and higher half parts + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { + lo.zero_widen() | hi.widen_hi() + } +} +} + +public_test_dep! { +/// Trait for integers half the bit width of another integer. This is implemented for all +/// primitives except for `u128`, because it there is not a larger primitive. +pub(crate) trait HInt: Int { + /// Integer that is double the bit width of the integer this trait is implemented for + type D: DInt + MinInt; + + // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for + // unknown reasons this can cause infinite recursion when optimizations are disabled. See + // for context. + + /// Widens (using default extension) the integer to have double bit width + fn widen(self) -> Self::D; + /// Widens (zero extension only) the integer to have double bit width. This is needed to get + /// around problems with associated type bounds (such as `Int`) being unstable + fn zero_widen(self) -> Self::D; + /// Widens the integer to have double bit width and shifts the integer into the higher bits + fn widen_hi(self) -> Self::D; + /// Widening multiplication with zero widening. This cannot overflow. + fn zero_widen_mul(self, rhs: Self) -> Self::D; + /// Widening multiplication. This cannot overflow. + fn widen_mul(self, rhs: Self) -> Self::D; +} +} + +macro_rules! impl_d_int { + ($($X:ident $D:ident),*) => { + $( + impl DInt for $D { + type H = $X; + + fn lo(self) -> Self::H { + self as $X + } + fn hi(self) -> Self::H { + (self >> <$X as MinInt>::BITS) as $X + } + } + )* + }; +} + +macro_rules! impl_h_int { + ($($H:ident $uH:ident $X:ident),*) => { + $( + impl HInt for $H { + type D = $X; + + fn widen(self) -> Self::D { + self as $X + } + fn zero_widen(self) -> Self::D { + (self as $uH) as $X + } + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen().wrapping_mul(rhs.zero_widen()) + } + fn widen_mul(self, rhs: Self) -> Self::D { + self.widen().wrapping_mul(rhs.widen()) + } + fn widen_hi(self) -> Self::D { + (self as $X) << ::BITS + } + } + )* + }; +} + +impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); +impl_h_int!( + u8 u8 u16, + u16 u16 u32, + u32 u32 u64, + u64 u64 u128, + i8 u8 i16, + i16 u16 i32, + i32 u32 i64, + i64 u64 i128 +); + +public_test_dep! { +/// Trait to express (possibly lossy) casting of integers +pub(crate) trait CastInto: Copy { + fn cast(self) -> T; +} + +pub(crate) trait CastFrom:Copy { + fn cast_from(value: T) -> Self; +} +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} -#[cfg(feature = "public-test-deps")] -pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index f5c6e50239a..330c6e4f80b 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -185,6 +185,7 @@ macro_rules! impl_delegate { }; } +public_test_dep! { /// Returns `n / d` and sets `*rem = n % d`. /// /// This specialization exists because: @@ -194,7 +195,7 @@ macro_rules! impl_delegate { /// delegate algorithm strategy the only reasonably fast way to perform `u128` division. // used on SPARC #[allow(dead_code)] -pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { +pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { use super::*; let duo_lo = duo as u64; let duo_hi = (duo >> 64) as u64; @@ -315,3 +316,4 @@ pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { } } } +} diff --git a/library/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/src/int/trailing_zeros.rs index dbc0cce9fac..cea366b0754 100644 --- a/library/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/src/int/trailing_zeros.rs @@ -1,49 +1,44 @@ -#[cfg(feature = "public-test-deps")] -pub use implementation::trailing_zeros; -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use implementation::trailing_zeros; +use crate::int::{CastInto, Int}; -mod implementation { - use crate::int::{CastInto, Int}; +public_test_dep! { +/// Returns number of trailing binary zeros in `x`. +#[allow(dead_code)] +pub(crate) fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + let mut x = x; + let mut r: u32 = 0; + let mut t: u32; - /// Returns number of trailing binary zeros in `x`. - #[allow(dead_code)] - pub fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { - let mut x = x; - let mut r: u32 = 0; - let mut t: u32; - - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 - x >>= r; // remove 32 zero bits - } - - if T::BITS >= 32 { - t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 - r += t; - x >>= t; // x = [0 - 0xFFFF] + higher garbage bits - } + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + x >>= r; // remove 32 zero bits + } - const { assert!(T::BITS >= 16) }; - t = ((CastInto::::cast(x) == 0) as u32) << 3; - x >>= t; // x = [0 - 0xFF] + higher garbage bits + if T::BITS >= 32 { + t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 r += t; + x >>= t; // x = [0 - 0xFFFF] + higher garbage bits + } - let mut x: u8 = x.cast(); + const { assert!(T::BITS >= 16) }; + t = ((CastInto::::cast(x) == 0) as u32) << 3; + x >>= t; // x = [0 - 0xFF] + higher garbage bits + r += t; - t = (((x & 0x0F) == 0) as u32) << 2; - x >>= t; // x = [0 - 0xF] + higher garbage bits - r += t; + let mut x: u8 = x.cast(); - t = (((x & 0x3) == 0) as u32) << 1; - x >>= t; // x = [0 - 0x3] + higher garbage bits - r += t; + t = (((x & 0x0F) == 0) as u32) << 2; + x >>= t; // x = [0 - 0xF] + higher garbage bits + r += t; - x &= 3; + t = (((x & 0x3) == 0) as u32) << 1; + x >>= t; // x = [0 - 0x3] + higher garbage bits + r += t; - r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) - } + x &= 3; + + r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) +} } intrinsics! { diff --git a/library/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/src/int/traits.rs deleted file mode 100644 index 9b079e2aa59..00000000000 --- a/library/compiler-builtins/src/int/traits.rs +++ /dev/null @@ -1,411 +0,0 @@ -use core::ops; - -/// Minimal integer implementations needed on all integer types, including wide integers. -#[allow(dead_code)] -pub trait MinInt: - Copy - + core::fmt::Debug - + ops::BitOr - + ops::Not - + ops::Shl -{ - /// Type with the same width but other signedness - type OtherSign: MinInt; - /// Unsigned version of Self - type UnsignedInt: MinInt; - - /// If `Self` is a signed integer - const SIGNED: bool; - - /// The bitwidth of the int type - const BITS: u32; - - const ZERO: Self; - const ONE: Self; - const MIN: Self; - const MAX: Self; -} - -/// Trait for some basic operations on integers -#[allow(dead_code)] -pub trait Int: - MinInt - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Shr - + ops::BitXor - + ops::BitAnd -{ - /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing - /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, - /// 112,119,120,125,126,127]. - const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); - - /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. - const FUZZ_NUM: usize = { - let log2 = (::BITS - 1).count_ones() as usize; - if log2 == 3 { - // case for u8 - 6 - } else { - // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate - // boundaries. - 8 + (4 * (log2 - 4)) - } - }; - - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; - fn unsigned_abs(self) -> Self::UnsignedInt; - - fn from_bool(b: bool) -> Self; - - /// Prevents the need for excessive conversions between signed and unsigned - fn logical_shr(self, other: u32) -> Self; - - /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; - - // copied from primitive integers, but put in a trait - fn is_zero(self) -> bool; - fn wrapping_neg(self) -> Self; - fn wrapping_add(self, other: Self) -> Self; - fn wrapping_mul(self, other: Self) -> Self; - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - fn ilog2(self) -> u32; -} - -pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { - let mut v = [0u8; 20]; - v[0] = 0; - v[1] = 1; - v[2] = 2; // important for parity and the iX::MIN case when reversed - let mut i = 3; - - // No need for any more until the byte boundary, because there should be no algorithms - // that are sensitive to anything not next to byte boundaries after 2. We also scale - // in powers of two, which is important to prevent u128 corner tests from getting too - // big. - let mut l = 8; - loop { - if l >= ((bits / 2) as u8) { - break; - } - // get both sides of the byte boundary - v[i] = l - 1; - i += 1; - v[i] = l; - i += 1; - l *= 2; - } - - if bits != 8 { - // add the lower side of the middle boundary - v[i] = ((bits / 2) - 1) as u8; - i += 1; - } - - // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS - // boundary because of algorithms that split the high part up. We reverse the scaling - // as we go to Self::BITS. - let mid = i; - let mut j = 1; - loop { - v[i] = (bits as u8) - (v[mid - j]) - 1; - if j == mid { - break; - } - i += 1; - j += 1; - } - v -} - -macro_rules! int_impl_common { - ($ty:ty) => { - fn from_bool(b: bool) -> Self { - b as $ty - } - - fn logical_shr(self, other: u32) -> Self { - Self::from_unsigned(self.unsigned().wrapping_shr(other)) - } - - fn is_zero(self) -> bool { - self == Self::ZERO - } - - fn wrapping_neg(self) -> Self { - ::wrapping_neg(self) - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn wrapping_shr(self, other: u32) -> Self { - ::wrapping_shr(self, other) - } - - fn rotate_left(self, other: u32) -> Self { - ::rotate_left(self, other) - } - - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - - fn ilog2(self) -> u32 { - ::ilog2(self) - } - }; -} - -macro_rules! int_impl { - ($ity:ty, $uty:ty) => { - impl MinInt for $uty { - type OtherSign = $ity; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $uty { - fn unsigned(self) -> $uty { - self - } - - // It makes writing macros easier if this is implemented for both signed and unsigned - #[allow(clippy::wrong_self_convention)] - fn from_unsigned(me: $uty) -> Self { - me - } - - fn unsigned_abs(self) -> Self { - self - } - - fn abs_diff(self, other: Self) -> Self { - self.abs_diff(other) - } - - int_impl_common!($uty); - } - - impl MinInt for $ity { - type OtherSign = $uty; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $ity { - fn unsigned(self) -> $uty { - self as $uty - } - - fn from_unsigned(me: $uty) -> Self { - me as $ity - } - - fn unsigned_abs(self) -> Self::UnsignedInt { - self.unsigned_abs() - } - - fn abs_diff(self, other: Self) -> $uty { - self.abs_diff(other) - } - - int_impl_common!($ity); - } - }; -} - -int_impl!(isize, usize); -int_impl!(i8, u8); -int_impl!(i16, u16); -int_impl!(i32, u32); -int_impl!(i64, u64); -int_impl!(i128, u128); - -/// Trait for integers twice the bit width of another integer. This is implemented for all -/// primitives except for `u8`, because there is not a smaller primitive. -pub trait DInt: MinInt { - /// Integer that is half the bit width of the integer this trait is implemented for - type H: HInt; - - /// Returns the low half of `self` - fn lo(self) -> Self::H; - /// Returns the high half of `self` - fn hi(self) -> Self::H; - /// Returns the low and high halves of `self` as a tuple - fn lo_hi(self) -> (Self::H, Self::H) { - (self.lo(), self.hi()) - } - /// Constructs an integer using lower and higher half parts - fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { - lo.zero_widen() | hi.widen_hi() - } -} - -/// Trait for integers half the bit width of another integer. This is implemented for all -/// primitives except for `u128`, because it there is not a larger primitive. -pub trait HInt: Int { - /// Integer that is double the bit width of the integer this trait is implemented for - type D: DInt + MinInt; - - // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for - // unknown reasons this can cause infinite recursion when optimizations are disabled. See - // for context. - - /// Widens (using default extension) the integer to have double bit width - fn widen(self) -> Self::D; - /// Widens (zero extension only) the integer to have double bit width. This is needed to get - /// around problems with associated type bounds (such as `Int`) being unstable - fn zero_widen(self) -> Self::D; - /// Widens the integer to have double bit width and shifts the integer into the higher bits - fn widen_hi(self) -> Self::D; - /// Widening multiplication with zero widening. This cannot overflow. - fn zero_widen_mul(self, rhs: Self) -> Self::D; - /// Widening multiplication. This cannot overflow. - fn widen_mul(self, rhs: Self) -> Self::D; -} - -macro_rules! impl_d_int { - ($($X:ident $D:ident),*) => { - $( - impl DInt for $D { - type H = $X; - - fn lo(self) -> Self::H { - self as $X - } - fn hi(self) -> Self::H { - (self >> <$X as MinInt>::BITS) as $X - } - } - )* - }; -} - -macro_rules! impl_h_int { - ($($H:ident $uH:ident $X:ident),*) => { - $( - impl HInt for $H { - type D = $X; - - fn widen(self) -> Self::D { - self as $X - } - fn zero_widen(self) -> Self::D { - (self as $uH) as $X - } - fn zero_widen_mul(self, rhs: Self) -> Self::D { - self.zero_widen().wrapping_mul(rhs.zero_widen()) - } - fn widen_mul(self, rhs: Self) -> Self::D { - self.widen().wrapping_mul(rhs.widen()) - } - fn widen_hi(self) -> Self::D { - (self as $X) << ::BITS - } - } - )* - }; -} - -impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); -impl_h_int!( - u8 u8 u16, - u16 u16 u32, - u32 u32 u64, - u64 u64 u128, - i8 u8 i16, - i16 u16 i32, - i32 u32 i64, - i64 u64 i128 -); - -/// Trait to express (possibly lossy) casting of integers -pub trait CastInto: Copy { - fn cast(self) -> T; -} - -pub trait CastFrom: Copy { - fn cast_from(value: T) -> Self; -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - self as $into - } - } - )*}; -} - -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 91606d42be1..f51e49e9876 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,5 +1,21 @@ //! Macros shared throughout the compiler-builtins implementation +/// Changes the visibility to `pub` if feature "public-test-deps" is set +#[cfg(not(feature = "public-test-deps"))] +macro_rules! public_test_dep { + ($(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => { + $(#[$($meta)*])* pub(crate) $ident $($tokens)* + }; +} + +/// Changes the visibility to `pub` if feature "public-test-deps" is set +#[cfg(feature = "public-test-deps")] +macro_rules! public_test_dep { + {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*} => { + $(#[$($meta)*])* pub $ident $($tokens)* + }; +} + /// The "main macro" used for defining intrinsics. /// /// The compiler-builtins library is super platform-specific with tons of crazy -- cgit 1.4.1-3-g733a5 From dbd3032d42e322730394dd6662b9bb8db0329a17 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 10:46:49 +0000 Subject: chore: release v0.1.145 --- library/compiler-builtins/CHANGELOG.md | 10 ++++++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index a1f95d17870..ddebb78231c 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.145](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.144...compiler_builtins-v0.1.145) - 2025-02-04 + +### Other + +- Revert "Eliminate the use of `public_test_dep!`" +- Indentation fix to please clippy +- Don't build out of line atomics support code for uefi +- Add a version to some FIXMEs that will be resolved in LLVM 20 +- Remove use of the `start` feature + ## [0.1.144](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.143...compiler_builtins-v0.1.144) - 2025-01-15 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0b0b7c36528..fcbc602382a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.144" +version = "0.1.145" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 98bee053ef9741f8968441cb6d06b9b85f2c7c9b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 30 Jan 2025 12:52:35 +0000 Subject: Fix hex float trait recursion problem --- .../libm/src/math/support/hex_float.rs | 30 ++++------------------ 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index da41622f296..ebc4f7c64fa 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -245,29 +245,21 @@ fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") } -#[cfg(f16_enabled)] -impl fmt::LowerHex for Hexf { +impl fmt::LowerHex for Hexf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt_any_hex(&self.0, f) } } -impl fmt::LowerHex for Hexf { +impl fmt::LowerHex for Hexf<(F, F)> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_any_hex(&self.0, f) - } -} - -impl fmt::LowerHex for Hexf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_any_hex(&self.0, f) + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) } } -#[cfg(f128_enabled)] -impl fmt::LowerHex for Hexf { +impl fmt::LowerHex for Hexf<(F, i32)> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_any_hex(&self.0, f) + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) } } @@ -277,18 +269,6 @@ impl fmt::LowerHex for Hexf { } } -impl fmt::LowerHex for Hexf<(T1, T2)> -where - T1: Copy, - T2: Copy, - Hexf: fmt::LowerHex, - Hexf: fmt::LowerHex, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) - } -} - impl fmt::Debug for Hexf where Hexf: fmt::LowerHex, -- cgit 1.4.1-3-g733a5 From cc2874c9a9e6d58dbd487a543ece7fef68a92df5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 04:34:21 +0000 Subject: Add `scalbnf16`, `scalbnf128`, `ldexpf16`, and `ldexpf128` Use the generic `scalbn` to provide `f16` and `f128` versions, which also work for `ldexp`. This involves a new algorithm for `f16` because the default does not converge fast enough with a limited number of rounds. --- .../libm/crates/libm-macros/src/shared.rs | 14 ++++ .../libm/crates/libm-test/benches/icount.rs | 4 + .../libm/crates/libm-test/benches/random.rs | 4 + .../libm/crates/libm-test/src/mpfloat.rs | 61 +++++++++------- .../libm/crates/libm-test/src/precision.rs | 4 + .../crates/libm-test/tests/compare_built_musl.rs | 4 + .../compiler-builtins/libm/crates/util/src/main.rs | 4 + .../libm/etc/function-definitions.json | 26 +++++++ .../compiler-builtins/libm/etc/function-list.txt | 4 + .../libm/src/math/generic/scalbn.rs | 85 +++++++++++++++++++--- .../compiler-builtins/libm/src/math/ldexpf128.rs | 4 + .../compiler-builtins/libm/src/math/ldexpf16.rs | 4 + library/compiler-builtins/libm/src/math/mod.rs | 8 ++ .../compiler-builtins/libm/src/math/scalbnf128.rs | 4 + .../compiler-builtins/libm/src/math/scalbnf16.rs | 4 + 15 files changed, 195 insertions(+), 39 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/ldexpf128.rs create mode 100644 library/compiler-builtins/libm/src/math/ldexpf16.rs create mode 100644 library/compiler-builtins/libm/src/math/scalbnf128.rs create mode 100644 library/compiler-builtins/libm/src/math/scalbnf16.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index b1f4f46cc3b..4fd0834f662 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -134,6 +134,13 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] None, &["jn", "yn"], ), + ( + // `(f16, i32) -> f16` + FloatTy::F16, + Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16] }, + None, + &["scalbnf16", "ldexpf16"], + ), ( // `(f32, i32) -> f32` FloatTy::F32, @@ -148,6 +155,13 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] None, &["scalbn", "ldexp"], ), + ( + // `(f128, i32) -> f128` + FloatTy::F128, + Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128] }, + None, + &["scalbnf128", "ldexpf128"], + ), ( // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` FloatTy::F32, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index d5026f461b0..13de799c77f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -131,6 +131,8 @@ main!( icount_bench_jn_group, icount_bench_jnf_group, icount_bench_ldexp_group, + icount_bench_ldexpf128_group, + icount_bench_ldexpf16_group, icount_bench_ldexpf_group, icount_bench_lgamma_group, icount_bench_lgamma_r_group, @@ -163,6 +165,8 @@ main!( icount_bench_roundf16_group, icount_bench_roundf_group, icount_bench_scalbn_group, + icount_bench_scalbnf128_group, + icount_bench_scalbnf16_group, icount_bench_scalbnf_group, icount_bench_sin_group, icount_bench_sinf_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index ca9e86c10bf..56d288c332e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -133,10 +133,14 @@ libm_macros::for_each_function! { | fminf16 | fmodf128 | fmodf16 + | ldexpf128 + | ldexpf16 | rintf128 | rintf16 | roundf128 | roundf16 + | scalbnf128 + | scalbnf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 3d84740ccd7..e3211b91379 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -159,6 +159,8 @@ libm_macros::for_each_function! { jnf, ldexp, ldexpf, + ldexpf128, + ldexpf16, lgamma_r, lgammaf_r, modf, @@ -178,6 +180,8 @@ libm_macros::for_each_function! { roundf16, scalbn, scalbnf, + scalbnf128, + scalbnf16, sincos,sincosf, trunc, truncf, @@ -351,34 +355,6 @@ macro_rules! impl_op_for_ty { } } - // `ldexp` and `scalbn` are the same for binary floating point, so just forward all - // methods. - impl MpOp for crate::op::[]::Routine { - type MpTy = ]::Routine as MpOp>::MpTy; - - fn new_mp() -> Self::MpTy { - ]::Routine as MpOp>::new_mp() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - ]::Routine as MpOp>::run(this, input) - } - } - - impl MpOp for crate::op::[]::Routine { - type MpTy = MpFloat; - - fn new_mp() -> Self::MpTy { - new_mpfloat::() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.assign(input.0); - *this <<= input.1; - prep_retval::(this, Ordering::Equal) - } - } - impl MpOp for crate::op::[]::Routine { type MpTy = (MpFloat, MpFloat); @@ -464,6 +440,35 @@ macro_rules! impl_op_for_ty_all { this.1.assign(input.1); let ord = this.0.rem_assign_round(&this.1, Nearest); prep_retval::(&mut this.0, ord) + + } + } + + // `ldexp` and `scalbn` are the same for binary floating point, so just forward all + // methods. + impl MpOp for crate::op::[]::Routine { + type MpTy = ]::Routine as MpOp>::MpTy; + + fn new_mp() -> Self::MpTy { + ]::Routine as MpOp>::new_mp() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + ]::Routine as MpOp>::run(this, input) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + *this <<= input.1; + prep_retval::(this, Ordering::Equal) } } } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index ffb322e38ff..051960b7a55 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -551,8 +551,12 @@ fn int_float_common( DEFAULT } +#[cfg(f16_enabled)] +impl MaybeOverride<(f16, i32)> for SpecialCase {} impl MaybeOverride<(f32, i32)> for SpecialCase {} impl MaybeOverride<(f64, i32)> for SpecialCase {} +#[cfg(f128_enabled)] +impl MaybeOverride<(f128, i32)> for SpecialCase {} impl MaybeOverride<(f32, f32, f32)> for SpecialCase { fn check_float( diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 5466edf4f4c..191c7e69de3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -95,10 +95,14 @@ libm_macros::for_each_function! { fminf16, fmodf128, fmodf16, + ldexpf128, + ldexpf16, rintf128, rintf16, roundf128, roundf16, + scalbnf128, + scalbnf16, sqrtf128, sqrtf16, truncf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 357df6b4fe2..e5d6f374ad8 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -102,10 +102,14 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fminf16 | fmodf128 | fmodf16 + | ldexpf128 + | ldexpf16 | rintf128 | rintf16 | roundf128 | roundf16 + | scalbnf128 + | scalbnf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 574ffea2e50..e38dfd23663 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -554,6 +554,18 @@ ], "type": "f32" }, + "ldexpf128": { + "sources": [ + "src/math/ldexpf128.rs" + ], + "type": "f128" + }, + "ldexpf16": { + "sources": [ + "src/math/ldexpf16.rs" + ], + "type": "f16" + }, "lgamma": { "sources": [ "src/libm_helper.rs", @@ -774,6 +786,20 @@ ], "type": "f32" }, + "scalbnf128": { + "sources": [ + "src/math/generic/scalbn.rs", + "src/math/scalbnf128.rs" + ], + "type": "f128" + }, + "scalbnf16": { + "sources": [ + "src/math/generic/scalbn.rs", + "src/math/scalbnf16.rs" + ], + "type": "f16" + }, "sin": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index d82838b3233..c92eaf9e23e 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -79,6 +79,8 @@ jn jnf ldexp ldexpf +ldexpf128 +ldexpf16 lgamma lgamma_r lgammaf @@ -111,6 +113,8 @@ roundf128 roundf16 scalbn scalbnf +scalbnf128 +scalbnf16 sin sincos sincosf diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs index f036c15cc03..f15cb75d631 100644 --- a/library/compiler-builtins/libm/src/math/generic/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs @@ -31,16 +31,27 @@ where let exp_max: i32 = F::EXP_BIAS as i32; let exp_min = -(exp_max - 1); - // 2 ^ Emax, where Emax is the maximum biased exponent value (1023 for f64) + // 2 ^ Emax, maximum positive with null significand (0x1p1023 for f64) let f_exp_max = F::from_parts(false, F::EXP_BIAS << 1, zero); - // 2 ^ Emin, where Emin is the minimum biased exponent value (-1022 for f64) + // 2 ^ Emin, minimum positive normal with null significand (0x1p-1022 for f64) let f_exp_min = F::from_parts(false, 1, zero); - // 2 ^ sig_total_bits, representation of what can be accounted for with subnormals - let f_exp_subnorm = F::from_parts(false, sig_total_bits + F::EXP_BIAS, zero); + // 2 ^ sig_total_bits, moltiplier to normalize subnormals (0x1p53 for f64) + let f_pow_subnorm = F::from_parts(false, sig_total_bits + F::EXP_BIAS, zero); + + /* + * The goal is to multiply `x` by a scale factor that applies `n`. However, there are cases + * where `2^n` is not representable by `F` but the result should be, e.g. `x = 2^Emin` with + * `n = -EMin + 2` (one out of range of 2^Emax). To get around this, reduce the magnitude of + * the final scale operation by prescaling by the max/min power representable by `F`. + */ if n > exp_max { + // Worse case positive `n`: `x` is the minimum subnormal value, the result is `F::MAX`. + // This can be reached by three scaling multiplications (two here and one final). + debug_assert!(-exp_min + F::SIG_BITS as i32 + exp_max <= exp_max * 3); + x *= f_exp_max; n -= exp_max; if n > exp_max { @@ -51,21 +62,61 @@ where } } } else if n < exp_min { - let mul = f_exp_min * f_exp_subnorm; - let add = (exp_max - 1) - sig_total_bits as i32; + // When scaling toward 0, the prescaling is limited to a value that does not allow `x` to + // go subnormal. This avoids double rounding. + if F::BITS > 16 { + // `mul` s.t. `!(x * mul).is_subnormal() ∀ x` + let mul = f_exp_min * f_pow_subnorm; + let add = -exp_min - sig_total_bits as i32; + + // Worse case negative `n`: `x` is the maximum positive value, the result is `F::MIN`. + // This must be reachable by three scaling multiplications (two here and one final). + debug_assert!(-exp_min + F::SIG_BITS as i32 + exp_max <= add * 2 + -exp_min); - x *= mul; - n += add; - if n < exp_min { x *= mul; n += add; + if n < exp_min { - n = exp_min; + x *= mul; + n += add; + + if n < exp_min { + n = exp_min; + } + } + } else { + // `f16` is unique compared to other float types in that the difference between the + // minimum exponent and the significand bits (`add = -exp_min - sig_total_bits`) is + // small, only three. The above method depend on decrementing `n` by `add` two times; + // for other float types this works out because `add` is a substantial fraction of + // the exponent range. For `f16`, however, 3 is relatively small compared to the + // exponent range (which is 39), so that requires ~10 prescale rounds rather than two. + // + // Work aroudn this by using a different algorithm that calculates the prescale + // dynamically based on the maximum possible value. This adds more operations per round + // since it needs to construct the scale, but works better in the general case. + let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32); + let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero); + + x *= mul; + n += add; + + if n < exp_min { + let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32); + let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero); + + x *= mul; + n += add; + + if n < exp_min { + n = exp_min; + } } } } - x * F::from_parts(false, (F::EXP_BIAS as i32 + n) as u32, zero) + let scale = F::from_parts(false, (F::EXP_BIAS as i32 + n) as u32, zero); + x * scale } #[cfg(test)] @@ -111,6 +162,12 @@ mod tests { assert!(scalbn(-F::NAN, -10).is_nan()); } + #[test] + #[cfg(f16_enabled)] + fn spec_test_f16() { + spec_test::(); + } + #[test] fn spec_test_f32() { spec_test::(); @@ -120,4 +177,10 @@ mod tests { fn spec_test_f64() { spec_test::(); } + + #[test] + #[cfg(f128_enabled)] + fn spec_test_f128() { + spec_test::(); + } } diff --git a/library/compiler-builtins/libm/src/math/ldexpf128.rs b/library/compiler-builtins/libm/src/math/ldexpf128.rs new file mode 100644 index 00000000000..b35277d15fb --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ldexpf128.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf128(x: f128, n: i32) -> f128 { + super::scalbnf128(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/ldexpf16.rs b/library/compiler-builtins/libm/src/math/ldexpf16.rs new file mode 100644 index 00000000000..8de6cffd699 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ldexpf16.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf16(x: f16, n: i32) -> f16 { + super::scalbnf16(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 969c1bfd942..9b07dc8a75e 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -349,8 +349,10 @@ cfg_if! { mod fmaxf16; mod fminf16; mod fmodf16; + mod ldexpf16; mod rintf16; mod roundf16; + mod scalbnf16; mod sqrtf16; mod truncf16; @@ -362,8 +364,10 @@ cfg_if! { pub use self::fmaxf16::fmaxf16; pub use self::fminf16::fminf16; pub use self::fmodf16::fmodf16; + pub use self::ldexpf16::ldexpf16; pub use self::rintf16::rintf16; pub use self::roundf16::roundf16; + pub use self::scalbnf16::scalbnf16; pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; } @@ -379,8 +383,10 @@ cfg_if! { mod fmaxf128; mod fminf128; mod fmodf128; + mod ldexpf128; mod rintf128; mod roundf128; + mod scalbnf128; mod sqrtf128; mod truncf128; @@ -392,8 +398,10 @@ cfg_if! { pub use self::fmaxf128::fmaxf128; pub use self::fminf128::fminf128; pub use self::fmodf128::fmodf128; + pub use self::ldexpf128::ldexpf128; pub use self::rintf128::rintf128; pub use self::roundf128::roundf128; + pub use self::scalbnf128::scalbnf128; pub use self::sqrtf128::sqrtf128; pub use self::truncf128::truncf128; } diff --git a/library/compiler-builtins/libm/src/math/scalbnf128.rs b/library/compiler-builtins/libm/src/math/scalbnf128.rs new file mode 100644 index 00000000000..c1d2b485585 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/scalbnf128.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf128(x: f128, n: i32) -> f128 { + super::generic::scalbn(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/scalbnf16.rs b/library/compiler-builtins/libm/src/math/scalbnf16.rs new file mode 100644 index 00000000000..2209e1a1795 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/scalbnf16.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf16(x: f16, n: i32) -> f16 { + super::generic::scalbn(x, n) +} -- cgit 1.4.1-3-g733a5 From cc1a55a77ee02f23c0b138701c3e24eea247b523 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 5 Feb 2025 15:00:04 +0000 Subject: Add a check in the `shared.rs` that the function list is sorted --- .../libm/crates/libm-macros/src/shared.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 4fd0834f662..da16cd8e287 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -18,7 +18,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] None, &[ "acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf", - "coshf", "erff", "erfcf", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", + "coshf", "erfcf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", "j0f", "j1f", "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", "sinf", "sinhf", "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", "y0f", "y1f", ], @@ -30,8 +30,8 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] None, &[ "acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh", - "erf", "erfc", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", - "log10", "log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", + "erf", "erfc", "exp", "exp10", "exp2", "expm1", "fabs", "floor", "j0", "j1", "lgamma", + "log", "log10", "log1p", "log2", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", "tgamma", "trunc", "y0", "y1", ], ), @@ -139,28 +139,28 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16] }, None, - &["scalbnf16", "ldexpf16"], + &["ldexpf16", "scalbnf16"], ), ( // `(f32, i32) -> f32` FloatTy::F32, Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] }, None, - &["scalbnf", "ldexpf"], + &["ldexpf", "scalbnf"], ), ( // `(f64, i64) -> f64` FloatTy::F64, Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] }, None, - &["scalbn", "ldexp"], + &["ldexp", "scalbn"], ), ( // `(f128, i32) -> f128` FloatTy::F128, Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128] }, None, - &["scalbnf128", "ldexpf128"], + &["ldexpf128", "scalbnf128"], ), ( // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` @@ -312,6 +312,12 @@ pub static ALL_OPERATIONS: LazyLock> = LazyLock::new(|| { }; ret.push(api); } + + if !names.is_sorted() { + let mut sorted = (*names).to_owned(); + sorted.sort_unstable(); + panic!("names list is not sorted: {names:?}\nExpected: {sorted:?}"); + } } ret.sort_by_key(|item| item.name); -- cgit 1.4.1-3-g733a5 From f7765fae89b69f9a6c6727bb0af181ac9099f9b1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 5 Feb 2025 15:02:17 +0000 Subject: Do not add `libm_helper.rs` to the sources list This is just a collection of all functions and should not trigger extensive tests when changed. --- .../libm/etc/function-definitions.json | 57 ---------------------- .../compiler-builtins/libm/etc/update-api-list.py | 9 ++++ 2 files changed, 9 insertions(+), 57 deletions(-) diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index e38dfd23663..a1d3adf591f 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -2,7 +2,6 @@ "__comment": "Autogenerated by update-api-list.py. List of files that define a function with a given name. This file is checked in to make it obvious if refactoring breaks things", "acos": { "sources": [ - "src/libm_helper.rs", "src/math/acos.rs" ], "type": "f64" @@ -15,7 +14,6 @@ }, "acosh": { "sources": [ - "src/libm_helper.rs", "src/math/acosh.rs" ], "type": "f64" @@ -28,7 +26,6 @@ }, "asin": { "sources": [ - "src/libm_helper.rs", "src/math/asin.rs" ], "type": "f64" @@ -41,7 +38,6 @@ }, "asinh": { "sources": [ - "src/libm_helper.rs", "src/math/asinh.rs" ], "type": "f64" @@ -54,14 +50,12 @@ }, "atan": { "sources": [ - "src/libm_helper.rs", "src/math/atan.rs" ], "type": "f64" }, "atan2": { "sources": [ - "src/libm_helper.rs", "src/math/atan2.rs" ], "type": "f64" @@ -80,7 +74,6 @@ }, "atanh": { "sources": [ - "src/libm_helper.rs", "src/math/atanh.rs" ], "type": "f64" @@ -93,7 +86,6 @@ }, "cbrt": { "sources": [ - "src/libm_helper.rs", "src/math/cbrt.rs" ], "type": "f64" @@ -106,7 +98,6 @@ }, "ceil": { "sources": [ - "src/libm_helper.rs", "src/math/arch/i586.rs", "src/math/arch/wasm32.rs", "src/math/ceil.rs", @@ -138,7 +129,6 @@ }, "copysign": { "sources": [ - "src/libm_helper.rs", "src/math/copysign.rs", "src/math/generic/copysign.rs", "src/math/support/float_traits.rs" @@ -168,7 +158,6 @@ }, "cos": { "sources": [ - "src/libm_helper.rs", "src/math/cos.rs" ], "type": "f64" @@ -181,7 +170,6 @@ }, "cosh": { "sources": [ - "src/libm_helper.rs", "src/math/cosh.rs" ], "type": "f64" @@ -194,14 +182,12 @@ }, "erf": { "sources": [ - "src/libm_helper.rs", "src/math/erf.rs" ], "type": "f64" }, "erfc": { "sources": [ - "src/libm_helper.rs", "src/math/erf.rs" ], "type": "f64" @@ -220,7 +206,6 @@ }, "exp": { "sources": [ - "src/libm_helper.rs", "src/math/exp.rs", "src/math/support/float_traits.rs" ], @@ -228,7 +213,6 @@ }, "exp10": { "sources": [ - "src/libm_helper.rs", "src/math/exp10.rs" ], "type": "f64" @@ -241,7 +225,6 @@ }, "exp2": { "sources": [ - "src/libm_helper.rs", "src/math/exp2.rs" ], "type": "f64" @@ -260,7 +243,6 @@ }, "expm1": { "sources": [ - "src/libm_helper.rs", "src/math/expm1.rs" ], "type": "f64" @@ -273,7 +255,6 @@ }, "fabs": { "sources": [ - "src/libm_helper.rs", "src/math/arch/wasm32.rs", "src/math/fabs.rs", "src/math/generic/fabs.rs" @@ -304,7 +285,6 @@ }, "fdim": { "sources": [ - "src/libm_helper.rs", "src/math/fdim.rs", "src/math/generic/fdim.rs" ], @@ -333,7 +313,6 @@ }, "floor": { "sources": [ - "src/libm_helper.rs", "src/math/arch/i586.rs", "src/math/arch/wasm32.rs", "src/math/floor.rs", @@ -365,7 +344,6 @@ }, "fma": { "sources": [ - "src/libm_helper.rs", "src/math/fma.rs" ], "type": "f64" @@ -378,7 +356,6 @@ }, "fmax": { "sources": [ - "src/libm_helper.rs", "src/math/fmax.rs", "src/math/generic/fmax.rs" ], @@ -407,7 +384,6 @@ }, "fmin": { "sources": [ - "src/libm_helper.rs", "src/math/fmin.rs", "src/math/generic/fmin.rs" ], @@ -436,7 +412,6 @@ }, "fmod": { "sources": [ - "src/libm_helper.rs", "src/math/fmod.rs", "src/math/generic/fmod.rs" ], @@ -465,7 +440,6 @@ }, "frexp": { "sources": [ - "src/libm_helper.rs", "src/math/frexp.rs" ], "type": "f64" @@ -478,7 +452,6 @@ }, "hypot": { "sources": [ - "src/libm_helper.rs", "src/math/hypot.rs" ], "type": "f64" @@ -491,7 +464,6 @@ }, "ilogb": { "sources": [ - "src/libm_helper.rs", "src/math/ilogb.rs" ], "type": "f64" @@ -504,7 +476,6 @@ }, "j0": { "sources": [ - "src/libm_helper.rs", "src/math/j0.rs" ], "type": "f64" @@ -517,7 +488,6 @@ }, "j1": { "sources": [ - "src/libm_helper.rs", "src/math/j1.rs" ], "type": "f64" @@ -530,7 +500,6 @@ }, "jn": { "sources": [ - "src/libm_helper.rs", "src/math/jn.rs" ], "type": "f64" @@ -543,7 +512,6 @@ }, "ldexp": { "sources": [ - "src/libm_helper.rs", "src/math/ldexp.rs" ], "type": "f64" @@ -568,14 +536,12 @@ }, "lgamma": { "sources": [ - "src/libm_helper.rs", "src/math/lgamma.rs" ], "type": "f64" }, "lgamma_r": { "sources": [ - "src/libm_helper.rs", "src/math/lgamma_r.rs" ], "type": "f64" @@ -594,14 +560,12 @@ }, "log": { "sources": [ - "src/libm_helper.rs", "src/math/log.rs" ], "type": "f64" }, "log10": { "sources": [ - "src/libm_helper.rs", "src/math/log10.rs" ], "type": "f64" @@ -614,7 +578,6 @@ }, "log1p": { "sources": [ - "src/libm_helper.rs", "src/math/log1p.rs" ], "type": "f64" @@ -627,7 +590,6 @@ }, "log2": { "sources": [ - "src/libm_helper.rs", "src/math/log2.rs" ], "type": "f64" @@ -646,7 +608,6 @@ }, "modf": { "sources": [ - "src/libm_helper.rs", "src/math/modf.rs" ], "type": "f64" @@ -659,7 +620,6 @@ }, "nextafter": { "sources": [ - "src/libm_helper.rs", "src/math/nextafter.rs" ], "type": "f64" @@ -672,7 +632,6 @@ }, "pow": { "sources": [ - "src/libm_helper.rs", "src/math/pow.rs" ], "type": "f64" @@ -685,7 +644,6 @@ }, "remainder": { "sources": [ - "src/libm_helper.rs", "src/math/remainder.rs" ], "type": "f64" @@ -698,7 +656,6 @@ }, "remquo": { "sources": [ - "src/libm_helper.rs", "src/math/remquo.rs" ], "type": "f64" @@ -711,7 +668,6 @@ }, "rint": { "sources": [ - "src/libm_helper.rs", "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", "src/math/generic/rint.rs", @@ -744,7 +700,6 @@ }, "round": { "sources": [ - "src/libm_helper.rs", "src/math/generic/round.rs", "src/math/round.rs" ], @@ -773,7 +728,6 @@ }, "scalbn": { "sources": [ - "src/libm_helper.rs", "src/math/generic/scalbn.rs", "src/math/scalbn.rs" ], @@ -802,14 +756,12 @@ }, "sin": { "sources": [ - "src/libm_helper.rs", "src/math/sin.rs" ], "type": "f64" }, "sincos": { "sources": [ - "src/libm_helper.rs", "src/math/sincos.rs" ], "type": "f64" @@ -828,7 +780,6 @@ }, "sinh": { "sources": [ - "src/libm_helper.rs", "src/math/sinh.rs" ], "type": "f64" @@ -841,7 +792,6 @@ }, "sqrt": { "sources": [ - "src/libm_helper.rs", "src/math/arch/i686.rs", "src/math/arch/wasm32.rs", "src/math/generic/sqrt.rs", @@ -874,7 +824,6 @@ }, "tan": { "sources": [ - "src/libm_helper.rs", "src/math/tan.rs" ], "type": "f64" @@ -887,7 +836,6 @@ }, "tanh": { "sources": [ - "src/libm_helper.rs", "src/math/tanh.rs" ], "type": "f64" @@ -900,7 +848,6 @@ }, "tgamma": { "sources": [ - "src/libm_helper.rs", "src/math/tgamma.rs" ], "type": "f64" @@ -913,7 +860,6 @@ }, "trunc": { "sources": [ - "src/libm_helper.rs", "src/math/arch/wasm32.rs", "src/math/generic/trunc.rs", "src/math/trunc.rs" @@ -944,7 +890,6 @@ }, "y0": { "sources": [ - "src/libm_helper.rs", "src/math/j0.rs" ], "type": "f64" @@ -957,7 +902,6 @@ }, "y1": { "sources": [ - "src/libm_helper.rs", "src/math/j1.rs" ], "type": "f64" @@ -970,7 +914,6 @@ }, "yn": { "sources": [ - "src/libm_helper.rs", "src/math/jn.rs" ], "type": "f64" diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index 67f73e59cf1..54da1325795 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 """Create a text file listing all public API. This can be used to ensure that all functions are covered by our macros. + +This file additionally does tidy-esque checks that all functions are listed where +needed, or that lists are sorted. """ import difflib @@ -15,6 +18,9 @@ from typing import Any, TypeAlias ETC_DIR = Path(__file__).parent ROOT_DIR = ETC_DIR.parent +# These files do not trigger a retest. +IGNORED_SOURCES = ["src/libm_helper.rs"] + IndexTy: TypeAlias = dict[str, dict[str, Any]] """Type of the `index` item in rustdoc's JSON output""" @@ -120,6 +126,9 @@ class Crate: for src in (s for s in base_sources if "generic" in s): sources.add(src) + for src in IGNORED_SOURCES: + sources.discard(src) + # Sort the set self.defs = {k: sorted(v) for (k, v) in defs.items()} -- cgit 1.4.1-3-g733a5 From eee632ee1b75f2fcc6ee679d340169a7386a0604 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 5 Feb 2025 15:03:34 +0000 Subject: Add checks via annotation that lists are sorted or exhaustive This crate has a handful of lists that need to list all API and can't easily be verified. Additionally, some longer lists should be kept sorted so they are easier to look through. Resolve both of these by adding a check in `update-api-list.py` that looks for annotations and verifies the contents are as expected. Annotations are `verify-apilist-start`, `verify-apilist-end`, `verify-sorted-start`, and `verify-sorted-end`. This includes fixes for anything that did not meet the criteria. --- .../libm/crates/libm-test/benches/icount.rs | 9 +- .../libm/crates/libm-test/src/mpfloat.rs | 2 + .../crates/libm-test/tests/compare_built_musl.rs | 2 + .../compiler-builtins/libm/etc/update-api-list.py | 143 +++++++++++++++++++-- library/compiler-builtins/libm/src/libm_helper.rs | 44 ++++++- library/compiler-builtins/libm/src/math/mod.rs | 8 ++ 6 files changed, 187 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 13de799c77f..53ecb5a37c4 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -52,7 +52,10 @@ libm_macros::for_each_function! { } main!( - library_benchmark_groups = icount_bench_acos_group, + library_benchmark_groups = + // verify-apilist-start + // verify-sorted-start + icount_bench_acos_group, icount_bench_acosf_group, icount_bench_acosh_group, icount_bench_acoshf_group, @@ -169,6 +172,8 @@ main!( icount_bench_scalbnf16_group, icount_bench_scalbnf_group, icount_bench_sin_group, + icount_bench_sincos_group, + icount_bench_sincosf_group, icount_bench_sinf_group, icount_bench_sinh_group, icount_bench_sinhf_group, @@ -192,4 +197,6 @@ main!( icount_bench_y1f_group, icount_bench_yn_group, icount_bench_ynf_group, + // verify-sorted-end + // verify-apilist-end ); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index e3211b91379..ab77d541c81 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -132,6 +132,7 @@ libm_macros::for_each_function! { emit_types: [RustFn], skip: [ // Most of these need a manual implementation + // verify-sorted-start ceil, ceilf, ceilf128, @@ -188,6 +189,7 @@ libm_macros::for_each_function! { truncf128, truncf16,yn, ynf, + // verify-sorted-end ], fn_extra: match MACRO_FN_NAME { // Remap function names that are different between mpfr and libm diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 191c7e69de3..0b0a9f09721 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -79,6 +79,7 @@ libm_macros::for_each_function! { ynf, // Not provided by musl + // verify-sorted-start ceilf128, ceilf16, copysignf128, @@ -107,5 +108,6 @@ libm_macros::for_each_function! { sqrtf16, truncf128, truncf16, + // verify-sorted-end ], } diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index 54da1325795..9cf62555422 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -8,16 +8,21 @@ needed, or that lists are sorted. import difflib import json +import re import subprocess as sp import sys from dataclasses import dataclass -from glob import glob +from glob import glob, iglob from pathlib import Path -from typing import Any, TypeAlias +from typing import Any, Callable, TypeAlias -ETC_DIR = Path(__file__).parent +SELF_PATH = Path(__file__) +ETC_DIR = SELF_PATH.parent ROOT_DIR = ETC_DIR.parent +# Loose approximation of what gets checked in to git, without needing `git ls-files`. +DIRECTORIES = [".github", "ci", "crates", "etc", "src"] + # These files do not trigger a retest. IGNORED_SOURCES = ["src/libm_helper.rs"] @@ -25,6 +30,11 @@ IndexTy: TypeAlias = dict[str, dict[str, Any]] """Type of the `index` item in rustdoc's JSON output""" +def eprint(*args, **kwargs): + """Print to stderr.""" + print(*args, file=sys.stderr, **kwargs) + + @dataclass class Crate: """Representation of public interfaces and function defintion locations in @@ -146,7 +156,7 @@ class Crate: if check: with open(out_file, "r") as f: current = f.read() - diff_and_exit(current, output) + diff_and_exit(current, output, "function list") else: with open(out_file, "w") as f: f.write(output) @@ -171,18 +181,115 @@ class Crate: if check: with open(out_file, "r") as f: current = f.read() - diff_and_exit(current, output) + diff_and_exit(current, output, "source list") else: with open(out_file, "w") as f: f.write(output) + def tidy_lists(self) -> None: + """In each file, check annotations indicating blocks of code should be sorted or should + include all public API. + """ + for dirname in DIRECTORIES: + dir = ROOT_DIR.joinpath(dirname) + for fname in iglob("**", root_dir=dir, recursive=True): + fpath = dir.joinpath(fname) + if fpath.is_dir() or fpath == SELF_PATH: + continue + + lines = fpath.read_text().splitlines() + + validate_delimited_block( + fpath, + lines, + "verify-sorted-start", + "verify-sorted-end", + ensure_sorted, + ) + + validate_delimited_block( + fpath, + lines, + "verify-apilist-start", + "verify-apilist-end", + lambda p, n, lines: self.ensure_contains_api(p, n, lines), + ) + + def ensure_contains_api(self, fpath: Path, line_num: int, lines: list[str]): + """Given a list of strings, ensure that each public function we have is named + somewhere. + """ + not_found = [] + for func in self.public_functions: + # The function name may be on its own or somewhere in a snake case string. + pat = re.compile(rf"(\b|_){func}(\b|_)") + found = next((line for line in lines if pat.search(line)), None) + + if found is None: + not_found.append(func) + + if len(not_found) == 0: + return + + relpath = fpath.relative_to(ROOT_DIR) + eprint(f"functions not found at {relpath}:{line_num}: {not_found}") + exit(1) + + +def validate_delimited_block( + fpath: Path, + lines: list[str], + start: str, + end: str, + validate: Callable[[Path, int, list[str]], None], +) -> None: + """Identify blocks of code wrapped within `start` and `end`, collect their contents + to a list of strings, and call `validate` for each of those lists. + """ + relpath = fpath.relative_to(ROOT_DIR) + block_lines = [] + block_start_line: None | int = None + for line_num, line in enumerate(lines): + line_num += 1 + + if start in line: + block_start_line = line_num + continue + + if end in line: + if block_start_line is None: + eprint(f"`{end}` without `{start}` at {relpath}:{line_num}") + exit(1) + + validate(fpath, block_start_line, block_lines) + block_lines = [] + block_start_line = None + continue + + if block_start_line is not None: + block_lines.append(line) + + if block_start_line is not None: + eprint(f"`{start}` without `{end}` at {relpath}:{block_start_line}") + exit(1) + + +def ensure_sorted(fpath: Path, block_start_line: int, lines: list[str]) -> None: + """Ensure that a list of lines is sorted, otherwise print a diff and exit.""" + relpath = fpath.relative_to(ROOT_DIR) + diff_and_exit( + "".join(lines), + "".join(sorted(lines)), + f"sorted block at {relpath}:{block_start_line}", + ) -def diff_and_exit(actual: str, expected: str): + +def diff_and_exit(actual: str, expected: str, name: str): """If the two strings are different, print a diff between them and then exit with an error. """ if actual == expected: - print("output matches expected; success") + print(f"{name} output matches expected; success") return a = [f"{line}\n" for line in actual.splitlines()] @@ -190,7 +297,7 @@ def diff_and_exit(actual: str, expected: str): diff = difflib.unified_diff(a, b, "actual", "expected") sys.stdout.writelines(diff) - print("mismatched function list") + print(f"mismatched {name}") exit(1) @@ -223,23 +330,31 @@ def base_name(name: str) -> tuple[str, str]: return (name, "f64") +def ensure_updated_list(check: bool) -> None: + """Runner to update the function list and JSON, or check that it is already up + to date. + """ + crate = Crate() + crate.write_function_list(check) + crate.write_function_defs(check) + + if check: + crate.tidy_lists() + + def main(): """By default overwrite the file. If `--check` is passed, print a diff instead and error if the files are different. """ match sys.argv: case [_]: - check = False + ensure_updated_list(False) case [_, "--check"]: - check = True + ensure_updated_list(True) case _: print("unrecognized arguments") exit(1) - crate = Crate() - crate.write_function_list(check) - crate.write_function_defs(check) - if __name__ == "__main__": main() diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index 73bae456761..0768839c779 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -44,9 +44,11 @@ macro_rules! libm_helper { }; } +// verify-apilist-start libm_helper! { f32, funcs: { + // verify-sorted-start (fn acos(x: f32) -> (f32); => acosf); (fn acosh(x: f32) -> (f32); => acoshf); (fn asin(x: f32) -> (f32); => asinf); @@ -62,8 +64,8 @@ libm_helper! { (fn erf(x: f32) -> (f32); => erff); (fn erfc(x: f32) -> (f32); => erfcf); (fn exp(x: f32) -> (f32); => expf); - (fn exp2(x: f32) -> (f32); => exp2f); (fn exp10(x: f32) -> (f32); => exp10f); + (fn exp2(x: f32) -> (f32); => exp2f); (fn expm1(x: f32) -> (f32); => expm1f); (fn fabs(x: f32) -> (f32); => fabsf); (fn fdim(x: f32, y: f32) -> (f32); => fdimf); @@ -79,12 +81,12 @@ libm_helper! { (fn j1(x: f32) -> (f32); => j1f); (fn jn(n: i32, x: f32) -> (f32); => jnf); (fn ldexp(x: f32, n: i32) -> (f32); => ldexpf); - (fn lgamma_r(x: f32) -> (f32, i32); => lgammaf_r); (fn lgamma(x: f32) -> (f32); => lgammaf); + (fn lgamma_r(x: f32) -> (f32, i32); => lgammaf_r); (fn log(x: f32) -> (f32); => logf); + (fn log10(x: f32) -> (f32); => log10f); (fn log1p(x: f32) -> (f32); => log1pf); (fn log2(x: f32) -> (f32); => log2f); - (fn log10(x: f32) -> (f32); => log10f); (fn modf(x: f32) -> (f32, f32); => modff); (fn nextafter(x: f32, y: f32) -> (f32); => nextafterf); (fn pow(x: f32, y: f32) -> (f32); => powf); @@ -104,12 +106,14 @@ libm_helper! { (fn y0(x: f32) -> (f32); => y0f); (fn y1(x: f32) -> (f32); => y1f); (fn yn(n: i32, x: f32) -> (f32); => ynf); + // verify-sorted-end } } libm_helper! { f64, funcs: { + // verify-sorted-start (fn acos(x: f64) -> (f64); => acos); (fn acosh(x: f64) -> (f64); => acosh); (fn asin(x: f64) -> (f64); => asin); @@ -125,8 +129,8 @@ libm_helper! { (fn erf(x: f64) -> (f64); => erf); (fn erfc(x: f64) -> (f64); => erfc); (fn exp(x: f64) -> (f64); => exp); - (fn exp2(x: f64) -> (f64); => exp2); (fn exp10(x: f64) -> (f64); => exp10); + (fn exp2(x: f64) -> (f64); => exp2); (fn expm1(x: f64) -> (f64); => expm1); (fn fabs(x: f64) -> (f64); => fabs); (fn fdim(x: f64, y: f64) -> (f64); => fdim); @@ -142,12 +146,12 @@ libm_helper! { (fn j1(x: f64) -> (f64); => j1); (fn jn(n: i32, x: f64) -> (f64); => jn); (fn ldexp(x: f64, n: i32) -> (f64); => ldexp); - (fn lgamma_r(x: f64) -> (f64, i32); => lgamma_r); (fn lgamma(x: f64) -> (f64); => lgamma); + (fn lgamma_r(x: f64) -> (f64, i32); => lgamma_r); (fn log(x: f64) -> (f64); => log); + (fn log10(x: f64) -> (f64); => log10); (fn log1p(x: f64) -> (f64); => log1p); (fn log2(x: f64) -> (f64); => log2); - (fn log10(x: f64) -> (f64); => log10); (fn modf(x: f64) -> (f64, f64); => modf); (fn nextafter(x: f64, y: f64) -> (f64); => nextafter); (fn pow(x: f64, y: f64) -> (f64); => pow); @@ -167,6 +171,7 @@ libm_helper! { (fn y0(x: f64) -> (f64); => y0); (fn y1(x: f64) -> (f64); => y1); (fn yn(n: i32, x: f64) -> (f64); => yn); + // verify-sorted-end } } @@ -174,9 +179,22 @@ libm_helper! { libm_helper! { f16, funcs: { + // verify-sorted-start + (fn ceilf(x: f16) -> (f16); => ceilf16); (fn copysign(x: f16, y: f16) -> (f16); => copysignf16); (fn fabs(x: f16) -> (f16); => fabsf16); (fn fdim(x: f16, y: f16) -> (f16); => fdimf16); + (fn floorf(x: f16) -> (f16); => floorf16); + (fn fmaxf(x: f16, y: f16) -> (f16); => fmaxf16); + (fn fminf(x: f16, y: f16) -> (f16); => fminf16); + (fn fmodf(x: f16, y: f16) -> (f16); => fmodf16); + (fn ldexpf16(x: f16, n: i32) -> (f16); => ldexpf16); + (fn rintf(x: f16) -> (f16); => rintf16); + (fn roundf(x: f16) -> (f16); => roundf16); + (fn scalbnf16(x: f16, n: i32) -> (f16); => ldexpf16); + (fn sqrtf(x: f16) -> (f16); => sqrtf16); + (fn truncf(x: f16) -> (f16); => truncf16); + // verify-sorted-end } } @@ -184,8 +202,22 @@ libm_helper! { libm_helper! { f128, funcs: { + // verify-sorted-start + (fn ceil(x: f128) -> (f128); => ceilf128); (fn copysign(x: f128, y: f128) -> (f128); => copysignf128); (fn fabs(x: f128) -> (f128); => fabsf128); (fn fdim(x: f128, y: f128) -> (f128); => fdimf128); + (fn floor(x: f128) -> (f128); => floorf128); + (fn fmax(x: f128, y: f128) -> (f128); => fmaxf128); + (fn fmin(x: f128, y: f128) -> (f128); => fminf128); + (fn fmod(x: f128, y: f128) -> (f128); => fmodf128); + (fn ldexpf128(x: f128, n: i32) -> (f128); => ldexpf128); + (fn rint(x: f128) -> (f128); => rintf128); + (fn round(x: f128) -> (f128); => roundf128); + (fn scalbnf128(x: f128, n: i32) -> (f128); => ldexpf128); + (fn sqrt(x: f128) -> (f128); => sqrtf128); + (fn trunc(x: f128) -> (f128); => truncf128); + // verify-sorted-end } } +// verify-apilist-end diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 9b07dc8a75e..f0698ad02eb 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -341,6 +341,7 @@ pub use self::truncf::truncf; cfg_if! { if #[cfg(f16_enabled)] { + // verify-sorted-start mod ceilf16; mod copysignf16; mod fabsf16; @@ -355,7 +356,9 @@ cfg_if! { mod scalbnf16; mod sqrtf16; mod truncf16; + // verify-sorted-end + // verify-sorted-start pub use self::ceilf16::ceilf16; pub use self::copysignf16::copysignf16; pub use self::fabsf16::fabsf16; @@ -370,11 +373,13 @@ cfg_if! { pub use self::scalbnf16::scalbnf16; pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; + // verify-sorted-end } } cfg_if! { if #[cfg(f128_enabled)] { + // verify-sorted-start mod ceilf128; mod copysignf128; mod fabsf128; @@ -389,7 +394,9 @@ cfg_if! { mod scalbnf128; mod sqrtf128; mod truncf128; + // verify-sorted-end + // verify-sorted-start pub use self::ceilf128::ceilf128; pub use self::copysignf128::copysignf128; pub use self::fabsf128::fabsf128; @@ -404,6 +411,7 @@ cfg_if! { pub use self::scalbnf128::scalbnf128; pub use self::sqrtf128::sqrtf128; pub use self::truncf128::truncf128; + // verify-sorted-end } } -- cgit 1.4.1-3-g733a5 From 9458abd20439c75584bd1b33a1ef7b6891ab5e8a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 23 Jan 2025 08:28:58 +0000 Subject: Start converting `fma` to a generic function This is the first step toward making `fma` usable for `f128`, and possibly `f32` on platforms where growing to `f64` is not fast. This does not yet work for anything other than `f64`. --- .../libm/etc/function-definitions.json | 6 +- library/compiler-builtins/libm/src/math/fma.rs | 192 +---------------- .../compiler-builtins/libm/src/math/generic/fma.rs | 227 +++++++++++++++++++++ .../compiler-builtins/libm/src/math/generic/mod.rs | 2 + .../libm/src/math/support/float_traits.rs | 4 +- .../libm/src/math/support/int_traits.rs | 39 ++++ 6 files changed, 278 insertions(+), 192 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/fma.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index a1d3adf591f..243862075ff 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -344,13 +344,15 @@ }, "fma": { "sources": [ - "src/math/fma.rs" + "src/math/fma.rs", + "src/math/generic/fma.rs" ], "type": "f64" }, "fmaf": { "sources": [ - "src/math/fmaf.rs" + "src/math/fmaf.rs", + "src/math/generic/fma.rs" ], "type": "f32" }, diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 826143d5a47..69cc3eb6726 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -1,195 +1,9 @@ -use core::{f32, f64}; - -use super::scalbn; - -const ZEROINFNAN: i32 = 0x7ff - 0x3ff - 52 - 1; - -struct Num { - m: u64, - e: i32, - sign: i32, -} - -fn normalize(x: f64) -> Num { - let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 - - let mut ix: u64 = x.to_bits(); - let mut e: i32 = (ix >> 52) as i32; - let sign: i32 = e & 0x800; - e &= 0x7ff; - if e == 0 { - ix = (x * x1p63).to_bits(); - e = (ix >> 52) as i32 & 0x7ff; - e = if e != 0 { e - 63 } else { 0x800 }; - } - ix &= (1 << 52) - 1; - ix |= 1 << 52; - ix <<= 1; - e -= 0x3ff + 52 + 1; - Num { m: ix, e, sign } -} - -#[inline] -fn mul(x: u64, y: u64) -> (u64, u64) { - let t = (x as u128).wrapping_mul(y as u128); - ((t >> 64) as u64, t as u64) -} - -/// Floating multiply add (f64) +/// Fused multiply add (f64) /// -/// Computes `(x*y)+z`, rounded as one ternary operation: -/// Computes the value (as if) to infinite precision and rounds once to the result format, -/// according to the rounding mode characterized by the value of FLT_ROUNDS. +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fma(x: f64, y: f64, z: f64) -> f64 { - let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 - let x0_ffffff8p_63 = f64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63 - - /* normalize so top 10bits and last bit are 0 */ - let nx = normalize(x); - let ny = normalize(y); - let nz = normalize(z); - - if nx.e >= ZEROINFNAN || ny.e >= ZEROINFNAN { - return x * y + z; - } - if nz.e >= ZEROINFNAN { - if nz.e > ZEROINFNAN { - /* z==0 */ - return x * y + z; - } - return z; - } - - /* mul: r = x*y */ - let zhi: u64; - let zlo: u64; - let (mut rhi, mut rlo) = mul(nx.m, ny.m); - /* either top 20 or 21 bits of rhi and last 2 bits of rlo are 0 */ - - /* align exponents */ - let mut e: i32 = nx.e + ny.e; - let mut d: i32 = nz.e - e; - /* shift bits z<<=kz, r>>=kr, so kz+kr == d, set e = e+kr (== ez-kz) */ - if d > 0 { - if d < 64 { - zlo = nz.m << d; - zhi = nz.m >> (64 - d); - } else { - zlo = 0; - zhi = nz.m; - e = nz.e - 64; - d -= 64; - if d == 0 { - } else if d < 64 { - rlo = (rhi << (64 - d)) | (rlo >> d) | ((rlo << (64 - d)) != 0) as u64; - rhi = rhi >> d; - } else { - rlo = 1; - rhi = 0; - } - } - } else { - zhi = 0; - d = -d; - if d == 0 { - zlo = nz.m; - } else if d < 64 { - zlo = (nz.m >> d) | ((nz.m << (64 - d)) != 0) as u64; - } else { - zlo = 1; - } - } - - /* add */ - let mut sign: i32 = nx.sign ^ ny.sign; - let samesign: bool = (sign ^ nz.sign) == 0; - let mut nonzero: i32 = 1; - if samesign { - /* r += z */ - rlo = rlo.wrapping_add(zlo); - rhi += zhi + (rlo < zlo) as u64; - } else { - /* r -= z */ - let (res, borrow) = rlo.overflowing_sub(zlo); - rlo = res; - rhi = rhi.wrapping_sub(zhi.wrapping_add(borrow as u64)); - if (rhi >> 63) != 0 { - rlo = (rlo as i64).wrapping_neg() as u64; - rhi = (rhi as i64).wrapping_neg() as u64 - (rlo != 0) as u64; - sign = (sign == 0) as i32; - } - nonzero = (rhi != 0) as i32; - } - - /* set rhi to top 63bit of the result (last bit is sticky) */ - if nonzero != 0 { - e += 64; - d = rhi.leading_zeros() as i32 - 1; - /* note: d > 0 */ - rhi = (rhi << d) | (rlo >> (64 - d)) | ((rlo << d) != 0) as u64; - } else if rlo != 0 { - d = rlo.leading_zeros() as i32 - 1; - if d < 0 { - rhi = (rlo >> 1) | (rlo & 1); - } else { - rhi = rlo << d; - } - } else { - /* exact +-0 */ - return x * y + z; - } - e -= d; - - /* convert to double */ - let mut i: i64 = rhi as i64; /* i is in [1<<62,(1<<63)-1] */ - if sign != 0 { - i = -i; - } - let mut r: f64 = i as f64; /* |r| is in [0x1p62,0x1p63] */ - - if e < -1022 - 62 { - /* result is subnormal before rounding */ - if e == -1022 - 63 { - let mut c: f64 = x1p63; - if sign != 0 { - c = -c; - } - if r == c { - /* min normal after rounding, underflow depends - on arch behaviour which can be imitated by - a double to float conversion */ - let fltmin: f32 = (x0_ffffff8p_63 * f32::MIN_POSITIVE as f64 * r) as f32; - return f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64; - } - /* one bit is lost when scaled, add another top bit to - only round once at conversion if it is inexact */ - if (rhi << 53) != 0 { - i = ((rhi >> 1) | (rhi & 1) | (1 << 62)) as i64; - if sign != 0 { - i = -i; - } - r = i as f64; - r = 2. * r - c; /* remove top bit */ - - /* raise underflow portably, such that it - cannot be optimized away */ - { - let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * r; - r += (tiny * tiny) * (r - r); - } - } - } else { - /* only round once when scaled */ - d = 10; - i = (((rhi >> d) | ((rhi << (64 - d)) != 0) as u64) << d) as i64; - if sign != 0 { - i = -i; - } - r = i as f64; - } - } - scalbn(r, e) + return super::generic::fma(x, y, z); } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs new file mode 100644 index 00000000000..3d5459f1a04 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -0,0 +1,227 @@ +use core::{f32, f64}; + +use super::super::support::{DInt, HInt, IntTy}; +use super::super::{CastFrom, CastInto, Float, Int, MinInt}; + +const ZEROINFNAN: i32 = 0x7ff - 0x3ff - 52 - 1; + +/// Fused multiply-add that works when there is not a larger float size available. Currently this +/// is still specialized only for `f64`. Computes `(x * y) + z`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fma(x: F, y: F, z: F) -> F +where + F: Float + FmaHelper, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, +{ + let one = IntTy::::ONE; + let zero = IntTy::::ZERO; + let magic = F::from_parts(false, F::BITS - 1 + F::EXP_BIAS, zero); + + /* normalize so top 10bits and last bit are 0 */ + let nx = Norm::from_float(x); + let ny = Norm::from_float(y); + let nz = Norm::from_float(z); + + if nx.e >= ZEROINFNAN || ny.e >= ZEROINFNAN { + return x * y + z; + } + if nz.e >= ZEROINFNAN { + if nz.e > ZEROINFNAN { + /* z==0 */ + return x * y + z; + } + return z; + } + + /* mul: r = x*y */ + let zhi: F::Int; + let zlo: F::Int; + let (mut rlo, mut rhi) = nx.m.widen_mul(ny.m).lo_hi(); + + /* either top 20 or 21 bits of rhi and last 2 bits of rlo are 0 */ + + /* align exponents */ + let mut e: i32 = nx.e + ny.e; + let mut d: i32 = nz.e - e; + let sbits = F::BITS as i32; + + /* shift bits z<<=kz, r>>=kr, so kz+kr == d, set e = e+kr (== ez-kz) */ + if d > 0 { + if d < sbits { + zlo = nz.m << d; + zhi = nz.m >> (sbits - d); + } else { + zlo = zero; + zhi = nz.m; + e = nz.e - sbits; + d -= sbits; + if d == 0 { + } else if d < sbits { + rlo = (rhi << (sbits - d)) + | (rlo >> d) + | IntTy::::from((rlo << (sbits - d)) != zero); + rhi = rhi >> d; + } else { + rlo = one; + rhi = zero; + } + } + } else { + zhi = zero; + d = -d; + if d == 0 { + zlo = nz.m; + } else if d < sbits { + zlo = (nz.m >> d) | IntTy::::from((nz.m << (sbits - d)) != zero); + } else { + zlo = one; + } + } + + /* add */ + let mut neg = nx.neg ^ ny.neg; + let samesign: bool = !neg ^ nz.neg; + let mut nonzero: i32 = 1; + if samesign { + /* r += z */ + rlo = rlo.wrapping_add(zlo); + rhi += zhi + IntTy::::from(rlo < zlo); + } else { + /* r -= z */ + let (res, borrow) = rlo.overflowing_sub(zlo); + rlo = res; + rhi = rhi.wrapping_sub(zhi.wrapping_add(IntTy::::from(borrow))); + if (rhi >> (F::BITS - 1)) != zero { + rlo = rlo.signed().wrapping_neg().unsigned(); + rhi = rhi.signed().wrapping_neg().unsigned() - IntTy::::from(rlo != zero); + neg = !neg; + } + nonzero = (rhi != zero) as i32; + } + + /* set rhi to top 63bit of the result (last bit is sticky) */ + if nonzero != 0 { + e += sbits; + d = rhi.leading_zeros() as i32 - 1; + /* note: d > 0 */ + rhi = (rhi << d) | (rlo >> (sbits - d)) | IntTy::::from((rlo << d) != zero); + } else if rlo != zero { + d = rlo.leading_zeros() as i32 - 1; + if d < 0 { + rhi = (rlo >> 1) | (rlo & one); + } else { + rhi = rlo << d; + } + } else { + /* exact +-0 */ + return x * y + z; + } + e -= d; + + /* convert to double */ + let mut i: F::SignedInt = rhi.signed(); /* i is in [1<<62,(1<<63)-1] */ + if neg { + i = -i; + } + + let mut r: F = F::cast_from_lossy(i); /* |r| is in [0x1p62,0x1p63] */ + + if e < -(F::EXP_BIAS as i32 - 1) - (sbits - 2) { + /* result is subnormal before rounding */ + if e == -(F::EXP_BIAS as i32 - 1) - (sbits - 1) { + let mut c: F = magic; + if neg { + c = -c; + } + if r == c { + /* min normal after rounding, underflow depends + * on arch behaviour which can be imitated by + * a double to float conversion */ + return r.raise_underflow(); + } + /* one bit is lost when scaled, add another top bit to + * only round once at conversion if it is inexact */ + if (rhi << F::SIG_BITS) != zero { + let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << 62); + i = iu.signed(); + if neg { + i = -i; + } + r = F::cast_from_lossy(i); + r = F::cast_from(2i8) * r - c; /* remove top bit */ + + /* raise underflow portably, such that it + * cannot be optimized away */ + r += r.raise_underflow2(); + } + } else { + /* only round once when scaled */ + d = 10; + i = (((rhi >> d) | IntTy::::from(rhi << (F::BITS as i32 - d) != zero)) << d) + .signed(); + if neg { + i = -i; + } + r = F::cast_from(i); + } + } + + super::scalbn(r, e) +} + +/// Representation of `F` that has handled subnormals. +struct Norm { + /// Normalized significand with one guard bit. + m: F::Int, + /// Unbiased exponent, normalized. + e: i32, + neg: bool, +} + +impl Norm { + fn from_float(x: F) -> Self { + let mut ix = x.to_bits(); + let mut e = x.exp() as i32; + let neg = x.is_sign_negative(); + if e == 0 { + // Normalize subnormals by multiplication + let magic = F::from_parts(false, F::BITS - 1 + F::EXP_BIAS, F::Int::ZERO); + let scaled = x * magic; + ix = scaled.to_bits(); + e = scaled.exp() as i32; + e = if e != 0 { e - (F::BITS as i32 - 1) } else { 0x800 }; + } + + e -= F::EXP_BIAS as i32 + 52 + 1; + + ix &= F::SIG_MASK; + ix |= F::IMPLICIT_BIT; + ix <<= 1; // add a guard bit + + Self { m: ix, e, neg } + } +} + +/// Type-specific helpers that are not needed outside of fma. +pub trait FmaHelper { + fn raise_underflow(self) -> Self; + fn raise_underflow2(self) -> Self; +} + +impl FmaHelper for f64 { + fn raise_underflow(self) -> Self { + let x0_ffffff8p_63 = f64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63 + let fltmin: f32 = (x0_ffffff8p_63 * f32::MIN_POSITIVE as f64 * self) as f32; + f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64 + } + + fn raise_underflow2(self) -> Self { + /* raise underflow portably, such that it + * cannot be optimized away */ + let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * self; + (tiny * tiny) * (self - self) + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 68686b0b255..e19cc83a9ac 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -3,6 +3,7 @@ mod copysign; mod fabs; mod fdim; mod floor; +mod fma; mod fmax; mod fmin; mod fmod; @@ -17,6 +18,7 @@ pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; +pub use fma::fma; pub use fmax::fmax; pub use fmin::fmin; pub use fmod::fmod; diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 1fe2cb424b9..24cf7d4b05c 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -23,7 +23,9 @@ pub trait Float: type Int: Int; /// A int of the same width as the float - type SignedInt: Int + MinInt; + type SignedInt: Int + + MinInt + + ops::Neg; const ZERO: Self; const NEG_ZERO: Self; diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index b403c658cb6..793a0f3069f 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -52,10 +52,14 @@ pub trait Int: + ops::Sub + ops::Mul + ops::Div + + ops::Shl + + ops::Shl + + ops::Shr + ops::Shr + ops::BitXor + ops::BitAnd + cmp::Ord + + From + CastFrom + CastFrom + CastFrom @@ -92,6 +96,7 @@ pub trait Int: fn wrapping_shr(self, other: u32) -> Self; fn rotate_left(self, other: u32) -> Self; fn overflowing_add(self, other: Self) -> (Self, bool); + fn overflowing_sub(self, other: Self) -> (Self, bool); fn leading_zeros(self) -> u32; fn ilog2(self) -> u32; } @@ -150,6 +155,10 @@ macro_rules! int_impl_common { ::overflowing_add(self, other) } + fn overflowing_sub(self, other: Self) -> (Self, bool) { + ::overflowing_sub(self, other) + } + fn leading_zeros(self) -> u32 { ::leading_zeros(self) } @@ -399,6 +408,30 @@ macro_rules! cast_into { )*}; } +macro_rules! cast_into_float { + ($ty:ty) => { + #[cfg(f16_enabled)] + cast_into_float!($ty; f16); + + cast_into_float!($ty; f32, f64); + + #[cfg(f128_enabled)] + cast_into_float!($ty; f128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + debug_assert_eq!(self as $into as $ty, self, "inexact float cast"); + self as $into + } + + fn cast_lossy(self) -> $into { + self as $into + } + } + )*}; +} + cast_into!(usize); cast_into!(isize); cast_into!(u8); @@ -411,3 +444,9 @@ cast_into!(u64); cast_into!(i64); cast_into!(u128); cast_into!(i128); + +cast_into_float!(i8); +cast_into_float!(i16); +cast_into_float!(i32); +cast_into_float!(i64); +cast_into_float!(i128); -- cgit 1.4.1-3-g733a5 From e01ce5d53a929019a8c9655c7dee4c74a911d465 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 5 Feb 2025 21:18:33 +0000 Subject: Commonize the signature for all instances of `get_test_cases` In order to make these more interchangeable in more places, always return `(impl Iterator, u64)`. This will facilitate using other generators for extensive tests. --- .../libm/crates/libm-test/benches/random.rs | 2 +- .../libm/crates/libm-test/examples/plot_domains.rs | 8 +++++- .../libm/crates/libm-test/src/gen/edge_cases.rs | 29 +++++++++++--------- .../libm/crates/libm-test/src/gen/random.rs | 31 ++++++++++++---------- .../crates/libm-test/tests/compare_built_musl.rs | 4 +-- .../libm/crates/libm-test/tests/multiprecision.rs | 4 +-- 6 files changed, 45 insertions(+), 33 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 56d288c332e..66486a56a2a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -54,7 +54,7 @@ where let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl, GeneratorKind::Random); let benchvec: Vec<_> = - random::get_test_cases::(&ctx).take(BENCH_ITER_ITEMS).collect(); + random::get_test_cases::(&ctx).0.take(BENCH_ITER_ITEMS).collect(); // Perform a sanity check that we are benchmarking the same thing // Don't test against musl if it is not available diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs index fb7b854df85..441889c6941 100644 --- a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs +++ b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs @@ -58,7 +58,13 @@ where let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::QuickSpaced); plot_one_generator(out_dir, &ctx, "logspace", config, spaced::get_test_cases::(&ctx).0); ctx.gen_kind = GeneratorKind::EdgeCases; - plot_one_generator(out_dir, &ctx, "edge_cases", config, edge_cases::get_test_cases::(&ctx)); + plot_one_generator( + out_dir, + &ctx, + "edge_cases", + config, + edge_cases::get_test_cases::(&ctx).0, + ); } /// Plot the output of a single generator. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs index d4014bdb360..8de954ae332 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs @@ -9,7 +9,7 @@ use crate::{CheckCtx, FloatExt, MathOp, test_log}; /// Generate a sequence of edge cases, e.g. numbers near zeroes and infiniteis. pub trait EdgeCaseInput { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator + Send; + fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); } /// Create a list of values around interesting points (infinities, zeroes, NaNs). @@ -140,10 +140,10 @@ macro_rules! impl_edge_case_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let (iter0, steps0) = float_edge_cases::(ctx, 0); let iter0 = iter0.map(|v| (v,)); - KnownSize::new(iter0, steps0) + (iter0, steps0) } } @@ -151,13 +151,13 @@ macro_rules! impl_edge_case_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let (iter0, steps0) = float_edge_cases::(ctx, 0); let (iter1, steps1) = float_edge_cases::(ctx, 1); let iter = iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); let count = steps0.checked_mul(steps1).unwrap(); - KnownSize::new(iter, count) + (iter, count) } } @@ -165,7 +165,7 @@ macro_rules! impl_edge_case_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let (iter0, steps0) = float_edge_cases::(ctx, 0); let (iter1, steps1) = float_edge_cases::(ctx, 1); let (iter2, steps2) = float_edge_cases::(ctx, 2); @@ -177,7 +177,7 @@ macro_rules! impl_edge_case_input { }); let count = steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); - KnownSize::new(iter, count) + (iter, count) } } @@ -185,7 +185,7 @@ macro_rules! impl_edge_case_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let (iter0, steps0) = int_edge_cases(ctx, 0); let (iter1, steps1) = float_edge_cases::(ctx, 1); @@ -193,7 +193,7 @@ macro_rules! impl_edge_case_input { iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); let count = steps0.checked_mul(steps1).unwrap(); - KnownSize::new(iter, count) + (iter, count) } } @@ -201,7 +201,7 @@ macro_rules! impl_edge_case_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let (iter0, steps0) = float_edge_cases::(ctx, 0); let (iter1, steps1) = int_edge_cases(ctx, 1); @@ -209,7 +209,7 @@ macro_rules! impl_edge_case_input { iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); let count = steps0.checked_mul(steps1).unwrap(); - KnownSize::new(iter, count) + (iter, count) } } }; @@ -224,10 +224,13 @@ impl_edge_case_input!(f128); pub fn get_test_cases( ctx: &CheckCtx, -) -> impl ExactSizeIterator + use<'_, Op> +) -> (impl Iterator + Send + use<'_, Op>, u64) where Op: MathOp, Op::RustArgs: EdgeCaseInput, { - Op::RustArgs::get_cases(ctx) + let (iter, count) = Op::RustArgs::get_cases(ctx); + + // Wrap in `KnownSize` so we get an assertion if the cuunt is wrong. + (KnownSize::new(iter, count), count) } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 56c39981a44..5b127f38d09 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -26,8 +26,8 @@ pub(crate) static SEED: LazyLock<[u8; 32]> = LazyLock::new(|| { }); /// Generate a sequence of random values of this type. -pub trait RandomInput { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator; +pub trait RandomInput: Sized { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); } /// Generate a sequence of deterministically random floats. @@ -51,25 +51,25 @@ fn random_ints(count: u64, range: RangeInclusive) -> impl Iterator { impl RandomInput for ($fty,) { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let count = iteration_count(ctx, 0); let iter = random_floats(count).map(|f: $fty| (f,)); - KnownSize::new(iter, count) + (iter, count) } } impl RandomInput for ($fty, $fty) { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let count0 = iteration_count(ctx, 0); let count1 = iteration_count(ctx, 1); let iter = random_floats(count0) .flat_map(move |f1: $fty| random_floats(count1).map(move |f2: $fty| (f1, f2))); - KnownSize::new(iter, count0 * count1) + (iter, count0 * count1) } } impl RandomInput for ($fty, $fty, $fty) { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let count0 = iteration_count(ctx, 0); let count1 = iteration_count(ctx, 1); let count2 = iteration_count(ctx, 2); @@ -78,30 +78,30 @@ macro_rules! impl_random_input { random_floats(count2).map(move |f3: $fty| (f1, f2, f3)) }) }); - KnownSize::new(iter, count0 * count1 * count2) + (iter, count0 * count1 * count2) } } impl RandomInput for (i32, $fty) { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let count0 = iteration_count(ctx, 0); let count1 = iteration_count(ctx, 1); let range0 = int_range(ctx, 0); let iter = random_ints(count0, range0) .flat_map(move |f1: i32| random_floats(count1).map(move |f2: $fty| (f1, f2))); - KnownSize::new(iter, count0 * count1) + (iter, count0 * count1) } } impl RandomInput for ($fty, i32) { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let count0 = iteration_count(ctx, 0); let count1 = iteration_count(ctx, 1); let range1 = int_range(ctx, 1); let iter = random_floats(count0).flat_map(move |f1: $fty| { random_ints(count1, range1.clone()).map(move |f2: i32| (f1, f2)) }); - KnownSize::new(iter, count0 * count1) + (iter, count0 * count1) } } }; @@ -117,6 +117,9 @@ impl_random_input!(f128); /// Create a test case iterator. pub fn get_test_cases( ctx: &CheckCtx, -) -> impl Iterator + use<'_, RustArgs> { - RustArgs::get_cases(ctx) +) -> (impl Iterator + Send + use<'_, RustArgs>, u64) { + let (iter, count) = RustArgs::get_cases(ctx); + + // Wrap in `KnownSize` so we get an assertion if the cuunt is wrong. + (KnownSize::new(iter, count), count) } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 0b0a9f09721..c8beaffc3af 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -39,7 +39,7 @@ macro_rules! musl_tests { fn [< musl_random_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Random); - let cases = random::get_test_cases::<::RustArgs>(&ctx); + let cases = random::get_test_cases::<::RustArgs>(&ctx).0; musl_runner::(&ctx, cases, musl_math_sys::$fn_name); } @@ -48,7 +48,7 @@ macro_rules! musl_tests { fn [< musl_edge_case_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::EdgeCases); - let cases = edge_cases::get_test_cases::(&ctx); + let cases = edge_cases::get_test_cases::(&ctx).0; musl_runner::(&ctx, cases, musl_math_sys::$fn_name); } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 761ca1f851e..0d5c5e60c20 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -29,7 +29,7 @@ macro_rules! mp_tests { fn [< mp_random_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Random); - let cases = random::get_test_cases::<::RustArgs>(&ctx); + let cases = random::get_test_cases::<::RustArgs>(&ctx).0; mp_runner::(&ctx, cases); } @@ -38,7 +38,7 @@ macro_rules! mp_tests { fn [< mp_edge_case_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::EdgeCases); - let cases = edge_cases::get_test_cases::(&ctx); + let cases = edge_cases::get_test_cases::(&ctx).0; mp_runner::(&ctx, cases); } -- cgit 1.4.1-3-g733a5 From 3fbe59f8503fb5eb151bc995ba2c1ebad80dcbb5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Feb 2025 00:02:00 +0000 Subject: Print the hex float format upon failure Now that we have a hex float formatter, make use of it for test output. This produces values that are easier to read than the bitwise hex representation. Example: thread 'mp_quickspace_fmaf128' panicked at crates/libm-test/tests/multiprecision.rs:17:48: called `Result::unwrap()` on an `Err` value: input: (0xe38d71c71c71c71c71c71c71c71c71c8, 0xe38d71c71c71c71c71c71c71c71c71c8, 0xffff0000000000000000000000000000) as hex: (-0x1.71c71c71c71c71c71c71c71c71c8p+9102, -0x1.71c71c71c71c71c71c71c71c71c8p+9102, -inf) as bits: (0xe38d71c71c71c71c71c71c71c71c71c8, 0xe38d71c71c71c71c71c71c71c71c71c8, 0xffff0000000000000000000000000000) expected: 0xffff0000000000000000000000000000 -inf 0xffff0000000000000000000000000000 actual: 0x7fff8000000000000000000000000000 NaN 0x7fff8000000000000000000000000000 Caused by: real value != NaN --- .../libm/crates/libm-test/src/test_traits.rs | 46 ++++++++++++++++++---- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index a5806943e11..1bd5bce162b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -9,6 +9,7 @@ use std::fmt; use anyhow::{Context, anyhow, bail, ensure}; +use libm::support::Hexf; use crate::precision::CheckAction; use crate::{CheckCtx, Float, Int, MaybeOverride, SpecialCase, TestResult}; @@ -35,7 +36,10 @@ pub trait CheckOutput: Sized { /// /// This is only used for printing errors so allocating is okay. pub trait Hex: Copy { + /// Hex integer syntax. fn hex(self) -> String; + /// Hex float syntax. + fn hexf(self) -> String; } /* implement `TupleCall` */ @@ -128,6 +132,10 @@ where fn hex(self) -> String { format!("({},)", self.0.hex()) } + + fn hexf(self) -> String { + format!("({},)", self.0.hexf()) + } } impl Hex for (T1, T2) @@ -138,6 +146,10 @@ where fn hex(self) -> String { format!("({}, {})", self.0.hex(), self.1.hex()) } + + fn hexf(self) -> String { + format!("({}, {})", self.0.hexf(), self.1.hexf()) + } } impl Hex for (T1, T2, T3) @@ -149,6 +161,10 @@ where fn hex(self) -> String { format!("({}, {}, {})", self.0.hex(), self.1.hex(), self.2.hex()) } + + fn hexf(self) -> String { + format!("({}, {}, {})", self.0.hexf(), self.1.hexf(), self.2.hexf()) + } } /* trait implementations for ints */ @@ -160,6 +176,10 @@ macro_rules! impl_int { fn hex(self) -> String { format!("{self:#0width$x}", width = ((Self::BITS / 4) + 2) as usize) } + + fn hexf(self) -> String { + String::new() + } } impl $crate::CheckOutput for $ty @@ -234,6 +254,10 @@ macro_rules! impl_float { width = ((Self::BITS / 4) + 2) as usize ) } + + fn hexf(self) -> String { + format!("{}", Hexf(self)) + } } impl $crate::CheckOutput for $ty @@ -324,13 +348,18 @@ where res.with_context(|| { format!( "\ - \n input: {input:?} {ibits}\ - \n expected: {expected:<22?} {expbits}\ - \n actual: {actual:<22?} {actbits}\ + \n input: {input:?}\ + \n as hex: {ihex}\ + \n as bits: {ibits}\ + \n expected: {expected:<22?} {exphex} {expbits}\ + \n actual: {actual:<22?} {acthex} {actbits}\ ", - actbits = actual.hex(), - expbits = expected.hex(), + ihex = input.hexf(), ibits = input.hex(), + exphex = expected.hexf(), + expbits = expected.hex(), + actbits = actual.hex(), + acthex = actual.hexf(), ) }) } @@ -365,12 +394,15 @@ macro_rules! impl_tuples { .with_context(|| format!( "full context:\ \n input: {input:?} {ibits}\ + \n as hex: {ihex}\ + \n as bits: {ibits}\ \n expected: {expected:?} {expbits}\ \n actual: {self:?} {actbits}\ ", - actbits = self.hex(), - expbits = expected.hex(), + ihex = input.hexf(), ibits = input.hex(), + expbits = expected.hex(), + actbits = self.hex(), )) } } -- cgit 1.4.1-3-g733a5 From 23989245ce549411b9d80323b89c9eb48fff53ec Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Feb 2025 00:34:56 +0000 Subject: fma: Ensure zero has the correct sign Currently, `fma(tiny, -tiny, 0.0)` returns 0.0 while the answer should be -0.0. This is because `-0.0 + 0.0 = +0.0` in the default rounding mode; however, the result should be negative. Musl has the same pattern but that version worked because the C compiler was contracting `x*y + z` to (ironically) `fmadd`. Musl was fixed in 9683bd6241 ("math: fix fma(x,y,0) when x*y rounds to -0"). Add the same fix here, which allows dropping the xfails. --- .../libm/crates/libm-test/src/precision.rs | 47 +--------------------- .../compiler-builtins/libm/src/math/generic/fma.rs | 2 +- 2 files changed, 3 insertions(+), 46 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 051960b7a55..596f91fe1ef 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -558,48 +558,5 @@ impl MaybeOverride<(f64, i32)> for SpecialCase {} #[cfg(f128_enabled)] impl MaybeOverride<(f128, i32)> for SpecialCase {} -impl MaybeOverride<(f32, f32, f32)> for SpecialCase { - fn check_float( - input: (f32, f32, f32), - actual: F, - expected: F, - ctx: &CheckCtx, - ) -> CheckAction { - ternop_common(input, actual, expected, ctx) - } -} -impl MaybeOverride<(f64, f64, f64)> for SpecialCase { - fn check_float( - input: (f64, f64, f64), - actual: F, - expected: F, - ctx: &CheckCtx, - ) -> CheckAction { - ternop_common(input, actual, expected, ctx) - } -} - -// F1 and F2 are always the same type, this is just to please generics -fn ternop_common( - input: (F1, F1, F1), - actual: F2, - expected: F2, - ctx: &CheckCtx, -) -> CheckAction { - // FIXME(fma): 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result - // of fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the - // exact result". Our implementation returns the wrong sign: - // fma(5e-324, -5e-324, 0.0) = 0.0 (should be -0.0) - if ctx.base_name == BaseName::Fma - && (input.0.is_sign_negative() ^ input.1.is_sign_negative()) - && input.0 != F1::ZERO - && input.1 != F1::ZERO - && input.2.biteq(F1::ZERO) - && expected.biteq(F2::NEG_ZERO) - && actual.biteq(F2::ZERO) - { - return XFAIL("fma sign"); - } - - DEFAULT -} +impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} +impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs index 3d5459f1a04..b0e2117ea09 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -31,7 +31,7 @@ where if nz.e >= ZEROINFNAN { if nz.e > ZEROINFNAN { /* z==0 */ - return x * y + z; + return x * y; } return z; } -- cgit 1.4.1-3-g733a5 From ada2d9ae1d8747cd6159fc090c4fa39b0c74d3bd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Feb 2025 01:59:44 +0000 Subject: Switch `musl` to track `master` A few bugs have been fixed, including the sign of `fma(tiny, -tiny, 0.0)`. Switch to tracking `master` rather than the latest tag so we don't need to xfail these tests. --- library/compiler-builtins/libm/crates/musl-math-sys/musl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/musl b/library/compiler-builtins/libm/crates/musl-math-sys/musl index 0784374d561..61399d4bd02 160000 --- a/library/compiler-builtins/libm/crates/musl-math-sys/musl +++ b/library/compiler-builtins/libm/crates/musl-math-sys/musl @@ -1 +1 @@ -Subproject commit 0784374d561435f7c787a555aeab8ede699ed298 +Subproject commit 61399d4bd02ae1ec03068445aa7ffe9174466bfd -- cgit 1.4.1-3-g733a5 From 4bf116f146b9f3d918e9d8be74616eb044fd5ead Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Feb 2025 04:03:11 +0000 Subject: Add an integration test that verifies a list of cases We need someplace to collect known failures, previous regressions, edge cases that are difficult to construct from generics, and similar. Introduce this here. --- .../libm/crates/libm-test/src/gen.rs | 1 + .../libm/crates/libm-test/src/gen/case_list.rs | 686 +++++++++++++++++++++ .../libm/crates/libm-test/src/run_cfg.rs | 8 +- .../crates/libm-test/tests/compare_built_musl.rs | 11 +- .../libm/crates/libm-test/tests/multiprecision.rs | 11 +- .../libm/crates/libm-test/tests/standalone.rs | 38 ++ 6 files changed, 750 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index e0a7f576680..89ca09a7a0b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -1,5 +1,6 @@ //! Different generators that can create random or systematic bit patterns. +pub mod case_list; pub mod edge_cases; pub mod random; pub mod spaced; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs new file mode 100644 index 00000000000..9720f68e961 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs @@ -0,0 +1,686 @@ +//! Test cases to verify specific values. +//! +//! Each routine can have a set of inputs and, optinoally, outputs. If an output is provided, it +//! will be used to check against. If only inputs are provided, the case will be checked against +//! a basis. +//! +//! This is useful for adding regression tests or expected failures. + +use crate::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; + +pub struct TestCase { + pub input: Op::RustArgs, + pub output: Option, +} + +impl TestCase { + #[expect(dead_code)] + fn append_inputs(v: &mut Vec, l: &[Op::RustArgs]) { + v.extend(l.iter().copied().map(|input| Self { input, output: None })); + } + + fn append_pairs(v: &mut Vec, l: &[(Op::RustArgs, Option)]) + where + Op::RustRet: Copy, + { + v.extend(l.iter().copied().map(|(input, output)| Self { input, output })); + } +} + +fn acos_cases() -> Vec> { + vec![] +} + +fn acosf_cases() -> Vec> { + vec![] +} + +fn acosh_cases() -> Vec> { + vec![] +} + +fn acoshf_cases() -> Vec> { + vec![] +} + +fn asin_cases() -> Vec> { + vec![] +} + +fn asinf_cases() -> Vec> { + vec![] +} + +fn asinh_cases() -> Vec> { + vec![] +} + +fn asinhf_cases() -> Vec> { + vec![] +} + +fn atan_cases() -> Vec> { + vec![] +} + +fn atan2_cases() -> Vec> { + vec![] +} + +fn atan2f_cases() -> Vec> { + vec![] +} + +fn atanf_cases() -> Vec> { + vec![] +} + +fn atanh_cases() -> Vec> { + vec![] +} + +fn atanhf_cases() -> Vec> { + vec![] +} + +fn cbrt_cases() -> Vec> { + vec![] +} + +fn cbrtf_cases() -> Vec> { + vec![] +} + +fn ceil_cases() -> Vec> { + vec![] +} + +fn ceilf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ceilf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn ceilf16_cases() -> Vec> { + vec![] +} + +fn copysign_cases() -> Vec> { + vec![] +} + +fn copysignf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn copysignf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn copysignf16_cases() -> Vec> { + vec![] +} + +fn cos_cases() -> Vec> { + vec![] +} + +fn cosf_cases() -> Vec> { + vec![] +} + +fn cosh_cases() -> Vec> { + vec![] +} + +fn coshf_cases() -> Vec> { + vec![] +} + +fn erf_cases() -> Vec> { + vec![] +} + +fn erfc_cases() -> Vec> { + vec![] +} + +fn erfcf_cases() -> Vec> { + vec![] +} + +fn erff_cases() -> Vec> { + vec![] +} + +fn exp_cases() -> Vec> { + vec![] +} + +fn exp10_cases() -> Vec> { + vec![] +} + +fn exp10f_cases() -> Vec> { + vec![] +} + +fn exp2_cases() -> Vec> { + vec![] +} + +fn exp2f_cases() -> Vec> { + vec![] +} + +fn expf_cases() -> Vec> { + vec![] +} + +fn expm1_cases() -> Vec> { + vec![] +} + +fn expm1f_cases() -> Vec> { + vec![] +} + +fn fabs_cases() -> Vec> { + vec![] +} + +fn fabsf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fabsf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fabsf16_cases() -> Vec> { + vec![] +} + +fn fdim_cases() -> Vec> { + vec![] +} + +fn fdimf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fdimf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fdimf16_cases() -> Vec> { + vec![] +} + +fn floor_cases() -> Vec> { + vec![] +} + +fn floorf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn floorf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn floorf16_cases() -> Vec> { + vec![] +} + +fn fma_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Previously failure with incorrect sign + ((5e-324, -5e-324, 0.0), Some(-0.0)), + ], + ); + v +} + +fn fmaf_cases() -> Vec> { + vec![] +} + +fn fmax_cases() -> Vec> { + vec![] +} + +fn fmaxf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmaxf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fmaxf16_cases() -> Vec> { + vec![] +} + +fn fmin_cases() -> Vec> { + vec![] +} + +fn fminf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fminf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fminf16_cases() -> Vec> { + vec![] +} + +fn fmod_cases() -> Vec> { + vec![] +} + +fn fmodf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmodf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fmodf16_cases() -> Vec> { + vec![] +} + +fn frexp_cases() -> Vec> { + vec![] +} + +fn frexpf_cases() -> Vec> { + vec![] +} + +fn hypot_cases() -> Vec> { + vec![] +} + +fn hypotf_cases() -> Vec> { + vec![] +} + +fn ilogb_cases() -> Vec> { + vec![] +} + +fn ilogbf_cases() -> Vec> { + vec![] +} + +fn j0_cases() -> Vec> { + vec![] +} + +fn j0f_cases() -> Vec> { + vec![] +} + +fn j1_cases() -> Vec> { + vec![] +} + +fn j1f_cases() -> Vec> { + vec![] +} + +fn jn_cases() -> Vec> { + vec![] +} + +fn jnf_cases() -> Vec> { + vec![] +} + +fn ldexp_cases() -> Vec> { + vec![] +} + +fn ldexpf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ldexpf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn ldexpf16_cases() -> Vec> { + vec![] +} + +fn lgamma_cases() -> Vec> { + vec![] +} + +fn lgamma_r_cases() -> Vec> { + vec![] +} + +fn lgammaf_cases() -> Vec> { + vec![] +} + +fn lgammaf_r_cases() -> Vec> { + vec![] +} + +fn log_cases() -> Vec> { + vec![] +} + +fn log10_cases() -> Vec> { + vec![] +} + +fn log10f_cases() -> Vec> { + vec![] +} + +fn log1p_cases() -> Vec> { + vec![] +} + +fn log1pf_cases() -> Vec> { + vec![] +} + +fn log2_cases() -> Vec> { + vec![] +} + +fn log2f_cases() -> Vec> { + vec![] +} + +fn logf_cases() -> Vec> { + vec![] +} + +fn modf_cases() -> Vec> { + vec![] +} + +fn modff_cases() -> Vec> { + vec![] +} + +fn nextafter_cases() -> Vec> { + vec![] +} + +fn nextafterf_cases() -> Vec> { + vec![] +} + +fn pow_cases() -> Vec> { + vec![] +} + +fn powf_cases() -> Vec> { + vec![] +} + +fn remainder_cases() -> Vec> { + vec![] +} + +fn remainderf_cases() -> Vec> { + vec![] +} + +fn remquo_cases() -> Vec> { + vec![] +} + +fn remquof_cases() -> Vec> { + vec![] +} + +fn rint_cases() -> Vec> { + vec![] +} + +fn rintf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn rintf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn rintf16_cases() -> Vec> { + vec![] +} + +fn round_cases() -> Vec> { + vec![] +} + +fn roundf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn roundf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn roundf16_cases() -> Vec> { + vec![] +} + +fn scalbn_cases() -> Vec> { + vec![] +} + +fn scalbnf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn scalbnf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn scalbnf16_cases() -> Vec> { + vec![] +} + +fn sin_cases() -> Vec> { + vec![] +} + +fn sincos_cases() -> Vec> { + vec![] +} + +fn sincosf_cases() -> Vec> { + vec![] +} + +fn sinf_cases() -> Vec> { + vec![] +} + +fn sinh_cases() -> Vec> { + vec![] +} + +fn sinhf_cases() -> Vec> { + vec![] +} + +fn sqrt_cases() -> Vec> { + vec![] +} + +fn sqrtf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn sqrtf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn sqrtf16_cases() -> Vec> { + vec![] +} + +fn tan_cases() -> Vec> { + vec![] +} + +fn tanf_cases() -> Vec> { + vec![] +} + +fn tanh_cases() -> Vec> { + vec![] +} + +fn tanhf_cases() -> Vec> { + vec![] +} + +fn tgamma_cases() -> Vec> { + vec![] +} + +fn tgammaf_cases() -> Vec> { + vec![] +} + +fn trunc_cases() -> Vec> { + vec![] +} + +fn truncf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn truncf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn truncf16_cases() -> Vec> { + vec![] +} + +fn y0_cases() -> Vec> { + vec![] +} + +fn y0f_cases() -> Vec> { + vec![] +} + +fn y1_cases() -> Vec> { + vec![] +} + +fn y1f_cases() -> Vec> { + vec![] +} + +fn yn_cases() -> Vec> { + vec![] +} + +fn ynf_cases() -> Vec> { + vec![] +} + +pub trait CaseListInput: MathOp + Sized { + fn get_cases() -> Vec>; +} + +macro_rules! impl_case_list { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + ) => { + paste::paste! { + $(#[$attr])* + impl CaseListInput for crate::op::$fn_name::Routine { + fn get_cases() -> Vec> { + [< $fn_name _cases >]() + } + } + } + }; +} + +libm_macros::for_each_function! { + callback: impl_case_list, +} + +/// This is the test generator for standalone tests, i.e. those with no basis. For this, it +/// only extracts tests with a known output. +pub fn get_test_cases_standalone( + ctx: &CheckCtx, +) -> impl Iterator + use<'_, Op> +where + Op: MathOp + CaseListInput, +{ + assert_eq!(ctx.basis, CheckBasis::None); + assert_eq!(ctx.gen_kind, GeneratorKind::List); + Op::get_cases().into_iter().filter_map(|x| x.output.map(|o| (x.input, o))) +} + +/// Opposite of the above; extract only test cases that don't have a known output, to be run +/// against a basis. +pub fn get_test_cases_basis( + ctx: &CheckCtx, +) -> (impl Iterator + use<'_, Op>, u64) +where + Op: MathOp + CaseListInput, +{ + assert_ne!(ctx.basis, CheckBasis::None); + assert_eq!(ctx.gen_kind, GeneratorKind::List); + + let cases = Op::get_cases(); + let count: u64 = cases.iter().filter(|case| case.output.is_none()).count().try_into().unwrap(); + + (cases.into_iter().filter(|x| x.output.is_none()).map(|x| x.input), count) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 783142e3783..5728c3b2e5b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -102,6 +102,7 @@ pub enum GeneratorKind { Extensive, QuickSpaced, Random, + List, } /// A list of all functions that should get extensive tests. @@ -219,8 +220,8 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { GeneratorKind::QuickSpaced => domain_iter_count, GeneratorKind::Random => random_iter_count, GeneratorKind::Extensive => extensive_max_iterations(), - GeneratorKind::EdgeCases => { - unimplemented!("edge case tests shoudn't need `iteration_count`") + GeneratorKind::EdgeCases | GeneratorKind::List => { + unimplemented!("shoudn't need `iteration_count` for {:?}", ctx.gen_kind) } }; @@ -269,7 +270,7 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { GeneratorKind::Random => { format!(" using `{SEED_ENV}={}`", str::from_utf8(SEED.as_slice()).unwrap()) } - GeneratorKind::EdgeCases => unreachable!(), + GeneratorKind::EdgeCases | GeneratorKind::List => unimplemented!(), }; test_log(&format!( @@ -310,6 +311,7 @@ pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { GeneratorKind::Extensive => extensive_range, GeneratorKind::QuickSpaced | GeneratorKind::Random => non_extensive_range, GeneratorKind::EdgeCases => extensive_range, + GeneratorKind::List => unimplemented!("shoudn't need range for {:?}", ctx.gen_kind), } } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index c8beaffc3af..927cb25afc4 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -9,7 +9,7 @@ // There are some targets we can't build musl for #![cfg(feature = "build-musl")] -use libm_test::gen::{edge_cases, random, spaced}; +use libm_test::gen::{case_list, edge_cases, random, spaced}; use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; const BASIS: CheckBasis = CheckBasis::Musl; @@ -34,6 +34,15 @@ macro_rules! musl_tests { attrs: [$($attr:meta),*], ) => { paste::paste! { + #[test] + $(#[$attr])* + fn [< musl_case_list_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::List); + let cases = case_list::get_test_cases_basis::(&ctx).0; + musl_runner::(&ctx, cases, musl_math_sys::$fn_name); + } + #[test] $(#[$attr])* fn [< musl_random_ $fn_name >]() { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 0d5c5e60c20..fd1f11610f5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -2,7 +2,7 @@ #![cfg(feature = "build-mpfr")] -use libm_test::gen::{edge_cases, random, spaced}; +use libm_test::gen::{case_list, edge_cases, random, spaced}; use libm_test::mpfloat::MpOp; use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; @@ -24,6 +24,15 @@ macro_rules! mp_tests { attrs: [$($attr:meta),*], ) => { paste::paste! { + #[test] + $(#[$attr])* + fn [< mp_case_list_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::List); + let cases = case_list::get_test_cases_basis::(&ctx).0; + mp_runner::(&ctx, cases); + } + #[test] $(#[$attr])* fn [< mp_random_ $fn_name >]() { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs b/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs new file mode 100644 index 00000000000..d6417acac2b --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs @@ -0,0 +1,38 @@ +//! Test cases that have both an input and an output, so do not require a basis. + +use libm_test::gen::case_list; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; + +const BASIS: CheckBasis = CheckBasis::None; + +fn standalone_runner( + ctx: &CheckCtx, + cases: impl Iterator, +) { + for (input, expected) in cases { + let crate_res = input.call(Op::ROUTINE); + crate_res.validate(expected, input, ctx).unwrap(); + } +} + +macro_rules! mp_tests { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + ) => { + paste::paste! { + #[test] + $(#[$attr])* + fn [< standalone_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::List); + let cases = case_list::get_test_cases_standalone::(&ctx); + standalone_runner::(&ctx, cases); + } + } + }; +} + +libm_macros::for_each_function! { + callback: mp_tests, +} -- cgit 1.4.1-3-g733a5 From 7f3bd59cdf5f833f848097ecf8ccac73b8ae650c Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Sat, 1 Feb 2025 02:10:59 +0300 Subject: Expose erf{,c}{,f} from libm --- library/compiler-builtins/src/math.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index da208239e83..21670f2434f 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -91,6 +91,11 @@ no_mangle! { fn fmod(x: f64, y: f64) -> f64; // `f32 % f32` fn fmodf(x: f32, y: f32) -> f32; + + fn erf(x: f64) -> f64; + fn erff(x: f32) -> f32; + fn erfc(x: f64) -> f64; + fn erfcf(x: f32) -> f32; } // allow for windows (and other targets) -- cgit 1.4.1-3-g733a5 From 84cb50e5b5e00d70679bccdc006350e5b1580996 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 20:55:26 +0000 Subject: chore: release v0.1.146 --- library/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index ddebb78231c..d6962dc5b5e 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.146](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.145...compiler_builtins-v0.1.146) - 2025-02-06 + +### Other + +- Expose erf{,c}{,f} from libm + ## [0.1.145](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.144...compiler_builtins-v0.1.145) - 2025-02-04 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index fcbc602382a..c93ca563c4e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.145" +version = "0.1.146" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 3aa4da2756bd5fcd3f8c7173d941bd5664b3efc7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Feb 2025 23:17:27 +0000 Subject: Improve tidy output Print a better diff when lists are unsorted, and always check tidy lists even if `--check` is not passed. --- library/compiler-builtins/libm/etc/update-api-list.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index 9cf62555422..c0b6e41d300 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -278,8 +278,8 @@ def ensure_sorted(fpath: Path, block_start_line: int, lines: list[str]) -> None: """Ensure that a list of lines is sorted, otherwise print a diff and exit.""" relpath = fpath.relative_to(ROOT_DIR) diff_and_exit( - "".join(lines), - "".join(sorted(lines)), + "\n".join(lines), + "\n".join(sorted(lines)), f"sorted block at {relpath}:{block_start_line}", ) @@ -338,8 +338,7 @@ def ensure_updated_list(check: bool) -> None: crate.write_function_list(check) crate.write_function_defs(check) - if check: - crate.tidy_lists() + crate.tidy_lists() def main(): -- cgit 1.4.1-3-g733a5 From bbdcc7ef899b57f6afa836f0cc4f0b7cb090c555 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Feb 2025 23:18:31 +0000 Subject: Make it possible to use `hf32!` and similar macros outside of `libm` Adjust paths such that these macros don't go through the private `math` module. `feature = "private-test-deps"` is still needed. Additionally, ensure that `cargo check` for this crate gets run in CI because `cargo test` does not seem to identify this problem. `compiler_builtins` will need to reexport the `support` module. --- library/compiler-builtins/libm/.github/workflows/main.yaml | 1 + .../libm/crates/compiler-builtins-smoke-test/src/lib.rs | 3 +++ library/compiler-builtins/libm/src/math/mod.rs | 2 +- .../compiler-builtins/libm/src/math/support/float_traits.rs | 2 +- library/compiler-builtins/libm/src/math/support/macros.rs | 12 ++++++++---- library/compiler-builtins/libm/src/math/support/mod.rs | 2 ++ 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index e03d7ecd319..e1d263deac1 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -143,6 +143,7 @@ jobs: - name: Install Rust run: rustup update nightly --no-self-update && rustup default nightly - uses: Swatinem/rust-cache@v2 + - run: cargo check --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml - run: cargo test --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml benchmarks: diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index ccd0642a20e..77a4666a102 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -17,6 +17,9 @@ pub mod libm; use core::ffi::c_int; +// Required for macro paths. +use libm::support; + /// Mark functions `#[no_mangle]` and with the C ABI. macro_rules! no_mangle { ($( $name:ident( $($tt:tt)+ ) -> $ret:ty; )+) => { diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index f0698ad02eb..7ad808cf752 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -81,7 +81,7 @@ pub mod support; #[macro_use] #[cfg(not(feature = "unstable-public-internals"))] -mod support; +pub(crate) mod support; cfg_if! { if #[cfg(feature = "unstable-public-internals")] { diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 24cf7d4b05c..328b7061061 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -107,7 +107,7 @@ pub trait Float: !self.is_sign_negative() } - /// Returns if `self` is subnormal + /// Returns if `self` is subnormal. fn is_subnormal(self) -> bool { (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO } diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index d8ba04cffe7..c80e7751159 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -90,10 +90,11 @@ macro_rules! select_implementation { /// Construct a 16-bit float from hex float representation (C-style), guaranteed to /// evaluate at compile time. #[cfg(f16_enabled)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] #[allow(unused_macros)] macro_rules! hf16 { ($s:literal) => {{ - const X: f16 = $crate::math::support::hf16($s); + const X: f16 = $crate::support::hf16($s); X }}; } @@ -101,9 +102,10 @@ macro_rules! hf16 { /// Construct a 32-bit float from hex float representation (C-style), guaranteed to /// evaluate at compile time. #[allow(unused_macros)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] macro_rules! hf32 { ($s:literal) => {{ - const X: f32 = $crate::math::support::hf32($s); + const X: f32 = $crate::support::hf32($s); X }}; } @@ -111,9 +113,10 @@ macro_rules! hf32 { /// Construct a 64-bit float from hex float representation (C-style), guaranteed to /// evaluate at compile time. #[allow(unused_macros)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] macro_rules! hf64 { ($s:literal) => {{ - const X: f64 = $crate::math::support::hf64($s); + const X: f64 = $crate::support::hf64($s); X }}; } @@ -122,9 +125,10 @@ macro_rules! hf64 { /// evaluate at compile time. #[cfg(f128_enabled)] #[allow(unused_macros)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] macro_rules! hf128 { ($s:literal) => {{ - const X: f128 = $crate::math::support::hf128($s); + const X: f128 = $crate::support::hf128($s); X }}; } diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index d471c5b7013..68f1e49e5c4 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -9,8 +9,10 @@ mod int_traits; pub use float_traits::{Float, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; #[cfg(f16_enabled)] +#[allow(unused_imports)] pub use hex_float::hf16; #[cfg(f128_enabled)] +#[allow(unused_imports)] pub use hex_float::hf128; #[allow(unused_imports)] pub use hex_float::{Hexf, hf32, hf64}; -- cgit 1.4.1-3-g733a5 From 9223d60dfa4c81e677c1c4d5b5ac8d8488fdbca0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 5 Feb 2025 23:45:14 +0000 Subject: Add `fmaf128` Resolve all remaining `f64`-specific items in the generic version of `fma`, then expose `fmaf128`. --- .../libm/crates/libm-macros/src/shared.rs | 7 + .../libm/crates/libm-test/benches/icount.rs | 1 + .../libm/crates/libm-test/benches/random.rs | 1 + .../libm/crates/libm-test/src/gen/case_list.rs | 23 +- .../libm/crates/libm-test/src/mpfloat.rs | 2 +- .../libm/crates/libm-test/src/precision.rs | 2 + .../crates/libm-test/tests/compare_built_musl.rs | 1 + .../compiler-builtins/libm/crates/util/src/main.rs | 1 + .../libm/etc/function-definitions.json | 7 + .../compiler-builtins/libm/etc/function-list.txt | 1 + library/compiler-builtins/libm/src/libm_helper.rs | 1 + library/compiler-builtins/libm/src/math/fmaf128.rs | 7 + .../compiler-builtins/libm/src/math/generic/fma.rs | 248 +++++++++++++++------ library/compiler-builtins/libm/src/math/mod.rs | 2 + 14 files changed, 237 insertions(+), 67 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fmaf128.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index da16cd8e287..48d19c50d19 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -106,6 +106,13 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] None, &["fma"], ), + ( + // `(f128, f128, f128) -> f128` + FloatTy::F128, + Signature { args: &[Ty::F128, Ty::F128, Ty::F128], returns: &[Ty::F128] }, + None, + &["fmaf128"], + ), ( // `(f32) -> i32` FloatTy::F32, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 53ecb5a37c4..c41cef24e54 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -108,6 +108,7 @@ main!( icount_bench_floorf16_group, icount_bench_floorf_group, icount_bench_fma_group, + icount_bench_fmaf128_group, icount_bench_fmaf_group, icount_bench_fmax_group, icount_bench_fmaxf128_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 66486a56a2a..6e8a334795a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -127,6 +127,7 @@ libm_macros::for_each_function! { | fdimf16 | floorf128 | floorf16 + | fmaf128 | fmaxf128 | fmaxf16 | fminf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs index 9720f68e961..302d5c39184 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs @@ -6,6 +6,9 @@ //! //! This is useful for adding regression tests or expected failures. +#[cfg(f128_enabled)] +use libm::hf128; + use crate::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; pub struct TestCase { @@ -250,7 +253,7 @@ fn fma_cases() -> Vec> { TestCase::append_pairs( &mut v, &[ - // Previously failure with incorrect sign + // Previous failure with incorrect sign ((5e-324, -5e-324, 0.0), Some(-0.0)), ], ); @@ -261,6 +264,24 @@ fn fmaf_cases() -> Vec> { vec![] } +#[cfg(f128_enabled)] +fn fmaf128_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[( + // Tricky rounding case that previously failed in extensive tests + ( + hf128!("-0x1.1966cc01966cc01966cc01966f06p-25"), + hf128!("-0x1.669933fe69933fe69933fe6997c9p-16358"), + hf128!("-0x0.000000000000000000000000048ap-16382"), + ), + Some(hf128!("0x0.c5171470a3ff5e0f68d751491b18p-16382")), + )], + ); + v +} + fn fmax_cases() -> Vec> { vec![] } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index ab77d541c81..f4a9ff7ffd5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -196,7 +196,7 @@ libm_macros::for_each_function! { expm1 | expm1f => exp_m1, fabs | fabsf => abs, fdim | fdimf | fdimf16 | fdimf128 => positive_diff, - fma | fmaf => mul_add, + fma | fmaf | fmaf128 => mul_add, fmax | fmaxf | fmaxf16 | fmaxf128 => max, fmin | fminf | fminf16 | fminf128 => min, lgamma | lgammaf => ln_gamma, diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 596f91fe1ef..20aa96b6aba 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -560,3 +560,5 @@ impl MaybeOverride<(f128, i32)> for SpecialCase {} impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} +#[cfg(f128_enabled)] +impl MaybeOverride<(f128, f128, f128)> for SpecialCase {} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 927cb25afc4..7fa77e832b1 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -99,6 +99,7 @@ libm_macros::for_each_function! { fdimf16, floorf128, floorf16, + fmaf128, fmaxf128, fmaxf16, fminf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index e5d6f374ad8..0f845a1c4d0 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -96,6 +96,7 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fdimf16 | floorf128 | floorf16 + | fmaf128 | fmaxf128 | fmaxf16 | fminf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 243862075ff..5742ed585f5 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -356,6 +356,13 @@ ], "type": "f32" }, + "fmaf128": { + "sources": [ + "src/math/fmaf128.rs", + "src/math/generic/fma.rs" + ], + "type": "f128" + }, "fmax": { "sources": [ "src/math/fmax.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index c92eaf9e23e..1c9c5e3bc33 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -53,6 +53,7 @@ floorf128 floorf16 fma fmaf +fmaf128 fmax fmaxf fmaxf128 diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index 0768839c779..68f1fb36266 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -208,6 +208,7 @@ libm_helper! { (fn fabs(x: f128) -> (f128); => fabsf128); (fn fdim(x: f128, y: f128) -> (f128); => fdimf128); (fn floor(x: f128) -> (f128); => floorf128); + (fn fmaf128(x: f128, y: f128, z: f128) -> (f128); => fmaf128); (fn fmax(x: f128, y: f128) -> (f128); => fmaxf128); (fn fmin(x: f128, y: f128) -> (f128); => fminf128); (fn fmod(x: f128, y: f128) -> (f128); => fmodf128); diff --git a/library/compiler-builtins/libm/src/math/fmaf128.rs b/library/compiler-builtins/libm/src/math/fmaf128.rs new file mode 100644 index 00000000000..50f7360deb4 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmaf128.rs @@ -0,0 +1,7 @@ +/// Fused multiply add (f128) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { + return super::generic::fma(x, y, z); +} diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs index b0e2117ea09..ac53acadfe1 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -1,10 +1,11 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ + use core::{f32, f64}; use super::super::support::{DInt, HInt, IntTy}; use super::super::{CastFrom, CastInto, Float, Int, MinInt}; -const ZEROINFNAN: i32 = 0x7ff - 0x3ff - 52 - 1; - /// Fused multiply-add that works when there is not a larger float size available. Currently this /// is still specialized only for `f64`. Computes `(x * y) + z`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -18,79 +19,99 @@ where { let one = IntTy::::ONE; let zero = IntTy::::ZERO; - let magic = F::from_parts(false, F::BITS - 1 + F::EXP_BIAS, zero); - /* normalize so top 10bits and last bit are 0 */ + // Normalize such that the top of the mantissa is zero and we have a guard bit. let nx = Norm::from_float(x); let ny = Norm::from_float(y); let nz = Norm::from_float(z); - if nx.e >= ZEROINFNAN || ny.e >= ZEROINFNAN { + if nx.is_zero_nan_inf() || ny.is_zero_nan_inf() { + // Value will overflow, defer to non-fused operations. return x * y + z; } - if nz.e >= ZEROINFNAN { - if nz.e > ZEROINFNAN { - /* z==0 */ + + if nz.is_zero_nan_inf() { + if nz.is_zero() { + // Empty add component means we only need to multiply. return x * y; } + // `z` is NaN or infinity, which sets the result. return z; } - /* mul: r = x*y */ + // multiply: r = x * y let zhi: F::Int; let zlo: F::Int; let (mut rlo, mut rhi) = nx.m.widen_mul(ny.m).lo_hi(); - /* either top 20 or 21 bits of rhi and last 2 bits of rlo are 0 */ - - /* align exponents */ + // Exponent result of multiplication let mut e: i32 = nx.e + ny.e; + // Needed shift to align `z` to the multiplication result let mut d: i32 = nz.e - e; let sbits = F::BITS as i32; - /* shift bits z<<=kz, r>>=kr, so kz+kr == d, set e = e+kr (== ez-kz) */ + // Scale `z`. Shift `z <<= kz`, `r >>= kr`, so `kz+kr == d`, set `e = e+kr` (== ez-kz) if d > 0 { + // The magnitude of `z` is larger than `x * y` if d < sbits { + // Maximum shift of one `F::BITS` means shifted `z` will fit into `2 * F::BITS`. Shift + // it into `(zhi, zlo)`. No exponent adjustment necessary. zlo = nz.m << d; zhi = nz.m >> (sbits - d); } else { + // Shift larger than `sbits`, `z` only needs the top half `zhi`. Place it there (acts + // as a shift by `sbits`). zlo = zero; zhi = nz.m; - e = nz.e - sbits; d -= sbits; + + // `z`'s exponent is large enough that it now needs to be taken into account. + e = nz.e - sbits; + if d == 0 { + // Exactly `sbits`, nothing to do } else if d < sbits { - rlo = (rhi << (sbits - d)) - | (rlo >> d) - | IntTy::::from((rlo << (sbits - d)) != zero); + // Remaining shift fits within `sbits`. Leave `z` in place, shift `x * y` + rlo = (rhi << (sbits - d)) | (rlo >> d); + // Set the sticky bit + rlo |= IntTy::::from((rlo << (sbits - d)) != zero); rhi = rhi >> d; } else { + // `z`'s magnitude is enough that `x * y` is irrelevant. It was nonzero, so set + // the sticky bit. rlo = one; rhi = zero; } } } else { + // `z`'s magnitude once shifted fits entirely within `zlo` zhi = zero; d = -d; if d == 0 { + // No shift needed zlo = nz.m; } else if d < sbits { - zlo = (nz.m >> d) | IntTy::::from((nz.m << (sbits - d)) != zero); + // Shift s.t. `nz.m` fits into `zlo` + let sticky = IntTy::::from((nz.m << (sbits - d)) != zero); + zlo = (nz.m >> d) | sticky; } else { + // Would be entirely shifted out, only set the sticky bit zlo = one; } } - /* add */ + /* addition */ + let mut neg = nx.neg ^ ny.neg; let samesign: bool = !neg ^ nz.neg; - let mut nonzero: i32 = 1; + let mut rhi_nonzero = true; + if samesign { - /* r += z */ + // r += z rlo = rlo.wrapping_add(zlo); rhi += zhi + IntTy::::from(rlo < zlo); } else { - /* r -= z */ + // r -= z let (res, borrow) = rlo.overflowing_sub(zlo); rlo = res; rhi = rhi.wrapping_sub(zhi.wrapping_add(IntTy::::from(borrow))); @@ -99,129 +120,226 @@ where rhi = rhi.signed().wrapping_neg().unsigned() - IntTy::::from(rlo != zero); neg = !neg; } - nonzero = (rhi != zero) as i32; + rhi_nonzero = rhi != zero; } - /* set rhi to top 63bit of the result (last bit is sticky) */ - if nonzero != 0 { + /* Construct result */ + + // Shift result into `rhi`, left-aligned. Last bit is sticky + if rhi_nonzero { + // `d` > 0, need to shift both `rhi` and `rlo` into result e += sbits; d = rhi.leading_zeros() as i32 - 1; - /* note: d > 0 */ - rhi = (rhi << d) | (rlo >> (sbits - d)) | IntTy::::from((rlo << d) != zero); + rhi = (rhi << d) | (rlo >> (sbits - d)); + // Update sticky + rhi |= IntTy::::from((rlo << d) != zero); } else if rlo != zero { + // `rhi` is zero, `rlo` is the entire result and needs to be shifted d = rlo.leading_zeros() as i32 - 1; if d < 0 { + // Shift and set sticky rhi = (rlo >> 1) | (rlo & one); } else { rhi = rlo << d; } } else { - /* exact +-0 */ + // exact +/- 0.0 return x * y + z; } e -= d; - /* convert to double */ - let mut i: F::SignedInt = rhi.signed(); /* i is in [1<<62,(1<<63)-1] */ + // Use int->float conversion to populate the significand. + // i is in [1 << (BITS - 2), (1 << (BITS - 1)) - 1] + let mut i: F::SignedInt = rhi.signed(); + if neg { i = -i; } - let mut r: F = F::cast_from_lossy(i); /* |r| is in [0x1p62,0x1p63] */ + // `|r|` is in `[0x1p62,0x1p63]` for `f64` + let mut r: F = F::cast_from_lossy(i); + + /* Account for subnormal and rounding */ + + // Unbiased exponent for the maximum value of `r` + let max_pow = F::BITS - 1 + F::EXP_BIAS; - if e < -(F::EXP_BIAS as i32 - 1) - (sbits - 2) { - /* result is subnormal before rounding */ - if e == -(F::EXP_BIAS as i32 - 1) - (sbits - 1) { - let mut c: F = magic; + if e < -(max_pow as i32 - 2) { + // Result is subnormal before rounding + if e == -(max_pow as i32 - 1) { + let mut c = F::from_parts(false, max_pow, zero); if neg { c = -c; } + if r == c { - /* min normal after rounding, underflow depends - * on arch behaviour which can be imitated by - * a double to float conversion */ - return r.raise_underflow(); + // Min normal after rounding, + return r.raise_underflow_ret_self(); } - /* one bit is lost when scaled, add another top bit to - * only round once at conversion if it is inexact */ - if (rhi << F::SIG_BITS) != zero { - let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << 62); + + if (rhi << (F::SIG_BITS + 1)) != zero { + // Account for truncated bits. One bit will be lost in the `scalbn` call, add + // another top bit to avoid double rounding if inexact. + let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << (F::BITS - 2)); i = iu.signed(); + if neg { i = -i; } + r = F::cast_from_lossy(i); - r = F::cast_from(2i8) * r - c; /* remove top bit */ - /* raise underflow portably, such that it - * cannot be optimized away */ - r += r.raise_underflow2(); + // Remove the top bit + r = F::cast_from(2i8) * r - c; + r += r.raise_underflow_ret_zero(); } } else { - /* only round once when scaled */ - d = 10; - i = (((rhi >> d) | IntTy::::from(rhi << (F::BITS as i32 - d) != zero)) << d) - .signed(); + // Only round once when scaled + d = F::EXP_BITS as i32 - 1; + let sticky = IntTy::::from(rhi << (F::BITS as i32 - d) != zero); + i = (((rhi >> d) | sticky) << d).signed(); + if neg { i = -i; } - r = F::cast_from(i); + + r = F::cast_from_lossy(i); } } + // Use our exponent to scale the final value. super::scalbn(r, e) } /// Representation of `F` that has handled subnormals. +#[derive(Clone, Copy, Debug)] struct Norm { - /// Normalized significand with one guard bit. + /// Normalized significand with one guard bit, unsigned. m: F::Int, - /// Unbiased exponent, normalized. + /// Exponent of the mantissa such that `m * 2^e = x`. Accounts for the shift in the mantissa + /// and the guard bit; that is, 1.0 will normalize as `m = 1 << 53` and `e = -53`. e: i32, neg: bool, } impl Norm { + /// Unbias the exponent and account for the mantissa's precision, including the guard bit. + const EXP_UNBIAS: u32 = F::EXP_BIAS + F::SIG_BITS + 1; + + /// Values greater than this had a saturated exponent (infinity or NaN), OR were zero and we + /// adjusted the exponent such that it exceeds this threashold. + const ZERO_INF_NAN: u32 = F::EXP_SAT - Self::EXP_UNBIAS; + fn from_float(x: F) -> Self { let mut ix = x.to_bits(); let mut e = x.exp() as i32; let neg = x.is_sign_negative(); if e == 0 { // Normalize subnormals by multiplication - let magic = F::from_parts(false, F::BITS - 1 + F::EXP_BIAS, F::Int::ZERO); - let scaled = x * magic; + let scale_i = F::BITS - 1; + let scale_f = F::from_parts(false, scale_i + F::EXP_BIAS, F::Int::ZERO); + let scaled = x * scale_f; ix = scaled.to_bits(); e = scaled.exp() as i32; - e = if e != 0 { e - (F::BITS as i32 - 1) } else { 0x800 }; + e = if e == 0 { + // If the exponent is still zero, the input was zero. Artifically set this value + // such that the final `e` will exceed `ZERO_INF_NAN`. + 1 << F::EXP_BITS + } else { + // Otherwise, account for the scaling we just did. + e - scale_i as i32 + }; } - e -= F::EXP_BIAS as i32 + 52 + 1; + e -= Self::EXP_UNBIAS as i32; + // Absolute value, set the implicit bit, and shift to create a guard bit ix &= F::SIG_MASK; ix |= F::IMPLICIT_BIT; - ix <<= 1; // add a guard bit + ix <<= 1; Self { m: ix, e, neg } } + + /// True if the value was zero, infinity, or NaN. + fn is_zero_nan_inf(self) -> bool { + self.e >= Self::ZERO_INF_NAN as i32 + } + + /// The only value we have + fn is_zero(self) -> bool { + // The only exponent that strictly exceeds this value is our sentinel value for zero. + self.e > Self::ZERO_INF_NAN as i32 + } } /// Type-specific helpers that are not needed outside of fma. pub trait FmaHelper { - fn raise_underflow(self) -> Self; - fn raise_underflow2(self) -> Self; + fn raise_underflow_ret_self(self) -> Self; + fn raise_underflow_ret_zero(self) -> Self; } impl FmaHelper for f64 { - fn raise_underflow(self) -> Self { - let x0_ffffff8p_63 = f64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63 - let fltmin: f32 = (x0_ffffff8p_63 * f32::MIN_POSITIVE as f64 * self) as f32; + fn raise_underflow_ret_self(self) -> Self { + /* min normal after rounding, underflow depends + * on arch behaviour which can be imitated by + * a double to float conversion */ + let fltmin: f32 = (hf64!("0x0.ffffff8p-63") * f32::MIN_POSITIVE as f64 * self) as f32; f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64 } - fn raise_underflow2(self) -> Self { + fn raise_underflow_ret_zero(self) -> Self { /* raise underflow portably, such that it * cannot be optimized away */ let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * self; (tiny * tiny) * (self - self) } } + +#[cfg(f128_enabled)] +impl FmaHelper for f128 { + fn raise_underflow_ret_self(self) -> Self { + self + } + + fn raise_underflow_ret_zero(self) -> Self { + f128::ZERO + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn spec_test() + where + F: Float + FmaHelper, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, + { + let x = F::from_bits(F::Int::ONE); + let y = F::from_bits(F::Int::ONE); + let z = F::ZERO; + + // 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of + // fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the + // exact result" + assert_biteq!(fma(x, y, z), F::ZERO); + assert_biteq!(fma(x, -y, z), F::NEG_ZERO); + assert_biteq!(fma(-x, y, z), F::NEG_ZERO); + assert_biteq!(fma(-x, -y, z), F::ZERO); + } + + #[test] + fn spec_test_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_test_f128() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 7ad808cf752..677ed8d6e93 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -385,6 +385,7 @@ cfg_if! { mod fabsf128; mod fdimf128; mod floorf128; + mod fmaf128; mod fmaxf128; mod fminf128; mod fmodf128; @@ -402,6 +403,7 @@ cfg_if! { pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; + pub use self::fmaf128::fmaf128; pub use self::fmaxf128::fmaxf128; pub use self::fminf128::fminf128; pub use self::fmodf128::fmodf128; -- cgit 1.4.1-3-g733a5 From aac4901953c475ba4ab911978661c7d478b32cff Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 00:47:00 +0000 Subject: Add better edge case testing for `scalbn` Include integer values around the minimum and maximum exponents which require different behavior in the scale functions. --- .../libm/crates/libm-test/src/gen/edge_cases.rs | 100 ++++++++++++++++----- .../libm/src/math/generic/scalbn.rs | 4 +- .../libm/src/math/support/float_traits.rs | 21 +++++ 3 files changed, 101 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs index 8de954ae332..8da635114d2 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs @@ -1,11 +1,11 @@ //! A generator that checks a handful of cases near infinities, zeros, asymptotes, and NaNs. -use libm::support::{Float, Int}; +use libm::support::{CastInto, Float, Int}; use crate::domain::get_domain; use crate::gen::KnownSize; use crate::run_cfg::{check_near_count, check_point_count}; -use crate::{CheckCtx, FloatExt, MathOp, test_log}; +use crate::{BaseName, CheckCtx, FloatExt, FloatTy, MathOp, test_log}; /// Generate a sequence of edge cases, e.g. numbers near zeroes and infiniteis. pub trait EdgeCaseInput { @@ -78,7 +78,7 @@ where (ret.into_iter(), count) } -/// Add `AROUND` values starting at and including `x` and counting up. Uses the smallest possible +/// Add `points` values starting at and including `x` and counting up. Uses the smallest possible /// increments (1 ULP). fn count_up(mut x: F, points: u64, values: &mut Vec) { assert!(!x.is_nan()); @@ -91,7 +91,7 @@ fn count_up(mut x: F, points: u64, values: &mut Vec) { } } -/// Add `AROUND` values starting at and including `x` and counting down. Uses the smallest possible +/// Add `points` values starting at and including `x` and counting down. Uses the smallest possible /// increments (1 ULP). fn count_down(mut x: F, points: u64, values: &mut Vec) { assert!(!x.is_nan()); @@ -107,31 +107,87 @@ fn count_down(mut x: F, points: u64, values: &mut Vec) { /// Create a list of values around interesting integer points (min, zero, max). pub fn int_edge_cases( ctx: &CheckCtx, - _argnum: usize, -) -> (impl Iterator + Clone, u64) { + argnum: usize, +) -> (impl Iterator + Clone, u64) +where + i32: CastInto, +{ let mut values = Vec::new(); let near_points = check_near_count(ctx); - for up_from in [I::MIN, I::ZERO] { - let mut x = up_from; - for _ in 0..near_points { - values.push(x); - x += I::ONE; - } - } - - for down_from in [I::ZERO, I::MAX] { - let mut x = down_from; - for _ in 0..near_points { - values.push(x); - x -= I::ONE; - } + // Check around max/min and zero + int_count_around(I::MIN, near_points, &mut values); + int_count_around(I::MAX, near_points, &mut values); + int_count_around(I::ZERO, near_points, &mut values); + int_count_around(I::ZERO, near_points, &mut values); + + if matches!(ctx.base_name, BaseName::Scalbn | BaseName::Ldexp) { + assert_eq!(argnum, 1, "scalbn integer argument should be arg1"); + let (emax, emin, emin_sn) = match ctx.fn_ident.math_op().float_ty { + FloatTy::F16 => { + #[cfg(not(f16_enabled))] + unreachable!(); + #[cfg(f16_enabled)] + (f16::EXP_MAX, f16::EXP_MIN, f16::EXP_MIN_SUBNORM) + } + FloatTy::F32 => (f32::EXP_MAX, f32::EXP_MIN, f32::EXP_MIN_SUBNORM), + FloatTy::F64 => (f64::EXP_MAX, f64::EXP_MIN, f64::EXP_MIN_SUBNORM), + FloatTy::F128 => { + #[cfg(not(f128_enabled))] + unreachable!(); + #[cfg(f128_enabled)] + (f128::EXP_MAX, f128::EXP_MIN, f128::EXP_MIN_SUBNORM) + } + }; + + // `scalbn`/`ldexp` have their trickiest behavior around exponent limits + int_count_around(emax.cast(), near_points, &mut values); + int_count_around(emin.cast(), near_points, &mut values); + int_count_around(emin_sn.cast(), near_points, &mut values); + int_count_around((-emin_sn).cast(), near_points, &mut values); + + // Also check values that cause the maximum possible difference in exponents + int_count_around((emax - emin).cast(), near_points, &mut values); + int_count_around((emin - emax).cast(), near_points, &mut values); + int_count_around((emax - emin_sn).cast(), near_points, &mut values); + int_count_around((emin_sn - emax).cast(), near_points, &mut values); } values.sort(); values.dedup(); - let len = values.len().try_into().unwrap(); - (values.into_iter(), len) + let count = values.len().try_into().unwrap(); + + test_log(&format!( + "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {count} edge cases", + gen_kind = ctx.gen_kind, + basis = ctx.basis, + fn_ident = ctx.fn_ident, + arg = argnum + 1, + args = ctx.input_count(), + )); + + (values.into_iter(), count) +} + +/// Add `points` values both up and down, starting at and including `x`. +fn int_count_around(x: I, points: u64, values: &mut Vec) { + let mut current = x; + for _ in 0..points { + values.push(current); + current = match current.checked_add(I::ONE) { + Some(v) => v, + None => break, + }; + } + + current = x; + for _ in 0..points { + values.push(current); + current = match current.checked_sub(I::ONE) { + Some(v) => v, + None => break, + }; + } } macro_rules! impl_edge_case_input { diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs index f15cb75d631..5ba7f2ab2d5 100644 --- a/library/compiler-builtins/libm/src/math/generic/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs @@ -28,8 +28,8 @@ where let sig_total_bits = F::SIG_BITS + 1; // Maximum and minimum values when biased - let exp_max: i32 = F::EXP_BIAS as i32; - let exp_min = -(exp_max - 1); + let exp_max = F::EXP_MAX; + let exp_min = F::EXP_MIN; // 2 ^ Emax, maximum positive with null significand (0x1p1023 for f64) let f_exp_max = F::from_parts(false, F::EXP_BIAS << 1, zero); diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 328b7061061..d6ce13f6907 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -59,6 +59,15 @@ pub trait Float: /// The exponent bias value const EXP_BIAS: u32 = Self::EXP_SAT >> 1; + /// Maximum unbiased exponent value. + const EXP_MAX: i32 = Self::EXP_BIAS as i32; + + /// Minimum *NORMAL* unbiased exponent value. + const EXP_MIN: i32 = -(Self::EXP_MAX - 1); + + /// Minimum subnormal exponent value. + const EXP_MIN_SUBNORM: i32 = Self::EXP_MIN - Self::SIG_BITS as i32; + /// A mask for the sign bit const SIGN_MASK: Self::Int; @@ -274,6 +283,9 @@ mod tests { // Constants assert_eq!(f16::EXP_SAT, 0b11111); assert_eq!(f16::EXP_BIAS, 15); + assert_eq!(f16::EXP_MAX, 15); + assert_eq!(f16::EXP_MIN, -14); + assert_eq!(f16::EXP_MIN_SUBNORM, -24); // `exp_unbiased` assert_eq!(f16::FRAC_PI_2.exp_unbiased(), 0); @@ -296,6 +308,9 @@ mod tests { // Constants assert_eq!(f32::EXP_SAT, 0b11111111); assert_eq!(f32::EXP_BIAS, 127); + assert_eq!(f32::EXP_MAX, 127); + assert_eq!(f32::EXP_MIN, -126); + assert_eq!(f32::EXP_MIN_SUBNORM, -149); // `exp_unbiased` assert_eq!(f32::FRAC_PI_2.exp_unbiased(), 0); @@ -319,6 +334,9 @@ mod tests { // Constants assert_eq!(f64::EXP_SAT, 0b11111111111); assert_eq!(f64::EXP_BIAS, 1023); + assert_eq!(f64::EXP_MAX, 1023); + assert_eq!(f64::EXP_MIN, -1022); + assert_eq!(f64::EXP_MIN_SUBNORM, -1074); // `exp_unbiased` assert_eq!(f64::FRAC_PI_2.exp_unbiased(), 0); @@ -343,6 +361,9 @@ mod tests { // Constants assert_eq!(f128::EXP_SAT, 0b111111111111111); assert_eq!(f128::EXP_BIAS, 16383); + assert_eq!(f128::EXP_MAX, 16383); + assert_eq!(f128::EXP_MIN, -16382); + assert_eq!(f128::EXP_MIN_SUBNORM, -16494); // `exp_unbiased` assert_eq!(f128::FRAC_PI_2.exp_unbiased(), 0); -- cgit 1.4.1-3-g733a5 From 69ebd750ccacd44fab4407501d568abd1e0801c1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 01:23:19 +0000 Subject: Run standard tests before running integration tests To ensure we don't waste time running extensive tests when there is an easily identifiable failure, run the normal test suite for relevant functions before starting extensive tests. --- library/compiler-builtins/libm/.github/workflows/main.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index e1d263deac1..de131639b56 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -273,6 +273,9 @@ jobs: exit fi + # Run the non-extensive tests first to catch any easy failures + cargo t --profile release-checked -- "$CHANGED" + LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \ --features build-mpfr,unstable,force-soft-floats \ --profile release-checked \ -- cgit 1.4.1-3-g733a5 From f028611faf62a9b87430ff782ab0bb91d5c63a8f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 01:05:38 +0000 Subject: Check more subnormal values during edge cases tests Add checks at the max subnormal value and a couple values scatted throughout the subnormal range. This helped identifiy a bug in `fmaf128`. As part of this, slightly reduce the amount of edge cases checked without optimizations because the change makes it become noticible. --- .../libm/crates/libm-test/src/gen/edge_cases.rs | 20 +++++++++++++++++++- .../libm/crates/libm-test/src/run_cfg.rs | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs index 8da635114d2..69b59a10567 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs @@ -1,9 +1,10 @@ //! A generator that checks a handful of cases near infinities, zeros, asymptotes, and NaNs. -use libm::support::{CastInto, Float, Int}; +use libm::support::{CastInto, Float, Int, MinInt}; use crate::domain::get_domain; use crate::gen::KnownSize; +use crate::op::OpITy; use crate::run_cfg::{check_near_count, check_point_count}; use crate::{BaseName, CheckCtx, FloatExt, FloatTy, MathOp, test_log}; @@ -21,6 +22,7 @@ where Op: MathOp, { let mut ret = Vec::new(); + let one = OpITy::::ONE; let values = &mut ret; let domain = get_domain::<_, i8>(ctx.fn_ident, argnum).unwrap_float(); let domain_start = domain.range_start(); @@ -51,6 +53,22 @@ where values.push(Op::FTy::NAN); values.extend(Op::FTy::consts().iter()); + // Check around the maximum subnormal value + let sub_max = Op::FTy::from_bits(Op::FTy::SIG_MASK); + count_up(sub_max, near_points, values); + count_down(sub_max, near_points, values); + count_up(-sub_max, near_points, values); + count_down(-sub_max, near_points, values); + + // Check a few values around the subnormal range + for shift in (0..Op::FTy::SIG_BITS).step_by(Op::FTy::SIG_BITS as usize / 5) { + let v = Op::FTy::from_bits(one << shift); + count_up(v, 2, values); + count_down(v, 2, values); + count_up(-v, 2, values); + count_down(-v, 2, values); + } + // Check around asymptotes if let Some(f) = domain.check_points { let iter = f(); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 5728c3b2e5b..4dd43bdf386 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -342,7 +342,7 @@ pub fn check_near_count(ctx: &CheckCtx) -> u64 { x => panic!("unexpected argument count {x}"), } } else { - 10 + 8 } } -- cgit 1.4.1-3-g733a5 From d35a44352750cc74f0ba49e3a0bd47d5310d90a5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 00:52:56 +0000 Subject: fmaf128: fix exponent calculation for subnormals When `fmaf128` was introduced in [1], it included a bug where `self` gets returned rather than the expected minimum positive value. Resolve this and add a regression test. [1]: https://github.com/rust-lang/libm/pull/494 --- .../libm/crates/libm-test/src/gen/case_list.rs | 25 ++++++++++++++++------ .../compiler-builtins/libm/src/math/generic/fma.rs | 13 ++++++----- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs index 302d5c39184..23226d5c251 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs @@ -269,15 +269,26 @@ fn fmaf128_cases() -> Vec> { let mut v = vec![]; TestCase::append_pairs( &mut v, - &[( - // Tricky rounding case that previously failed in extensive tests + &[ + ( + // Tricky rounding case that previously failed in extensive tests + ( + hf128!("-0x1.1966cc01966cc01966cc01966f06p-25"), + hf128!("-0x1.669933fe69933fe69933fe6997c9p-16358"), + hf128!("-0x0.000000000000000000000000048ap-16382"), + ), + Some(hf128!("0x0.c5171470a3ff5e0f68d751491b18p-16382")), + ), ( - hf128!("-0x1.1966cc01966cc01966cc01966f06p-25"), - hf128!("-0x1.669933fe69933fe69933fe6997c9p-16358"), - hf128!("-0x0.000000000000000000000000048ap-16382"), + // Subnormal edge case that caused a failure + ( + hf128!("0x0.7ffffffffffffffffffffffffff7p-16382"), + hf128!("0x1.ffffffffffffffffffffffffffffp-1"), + hf128!("0x0.8000000000000000000000000009p-16382"), + ), + Some(hf128!("0x1.0000000000000000000000000000p-16382")), ), - Some(hf128!("0x0.c5171470a3ff5e0f68d751491b18p-16382")), - )], + ], ); v } diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs index ac53acadfe1..4c6f1fad681 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -146,6 +146,7 @@ where // exact +/- 0.0 return x * y + z; } + e -= d; // Use int->float conversion to populate the significand. @@ -174,7 +175,7 @@ where if r == c { // Min normal after rounding, - return r.raise_underflow_ret_self(); + return r.raise_underflow_as_min_positive(); } if (rhi << (F::SIG_BITS + 1)) != zero { @@ -275,12 +276,14 @@ impl Norm { /// Type-specific helpers that are not needed outside of fma. pub trait FmaHelper { - fn raise_underflow_ret_self(self) -> Self; + /// Raise underflow and return the minimum positive normal value with the sign of `self`. + fn raise_underflow_as_min_positive(self) -> Self; + /// Raise underflow and return zero. fn raise_underflow_ret_zero(self) -> Self; } impl FmaHelper for f64 { - fn raise_underflow_ret_self(self) -> Self { + fn raise_underflow_as_min_positive(self) -> Self { /* min normal after rounding, underflow depends * on arch behaviour which can be imitated by * a double to float conversion */ @@ -298,8 +301,8 @@ impl FmaHelper for f64 { #[cfg(f128_enabled)] impl FmaHelper for f128 { - fn raise_underflow_ret_self(self) -> Self { - self + fn raise_underflow_as_min_positive(self) -> Self { + f128::MIN_POSITIVE.copysign(self) } fn raise_underflow_ret_zero(self) -> Self { -- cgit 1.4.1-3-g733a5 From 3e2de21344f2179016c6d04aaeb0668c21abaa52 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 02:36:58 +0000 Subject: Remove or reduce the scope of `allow(unused)` where possible Now that we have more in this crate making use of traits, try to be more specific about what is actually unused. --- .../libm/crates/libm-macros/tests/basic.rs | 13 +++---------- library/compiler-builtins/libm/src/math/support/big.rs | 11 +++++------ .../libm/src/math/support/float_traits.rs | 17 ++++++++++------- .../libm/src/math/support/int_traits.rs | 7 ++----- library/compiler-builtins/libm/src/math/support/mod.rs | 1 - 5 files changed, 20 insertions(+), 29 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs index 0aa417f13c8..5314e84bbb0 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs @@ -18,20 +18,14 @@ macro_rules! basic { fn_extra: $fn_extra:expr, ) => { $(#[$attr])* - mod $fn_name { - #[allow(unused)] + #[allow(dead_code)] + pub mod $fn_name { type FTy= $FTy; - #[allow(unused)] type CFnTy<'a> = $CFn; - #[allow(unused)] type RustFnTy = $RustFn; - #[allow(unused)] type RustArgsTy = $RustArgs; - #[allow(unused)] type RustRetTy = $RustRet; - #[allow(unused)] const A: &[&str] = &[$($extra_tt)*]; - #[allow(unused)] fn foo(a: f32) -> f32 { $fn_extra(a) } @@ -92,10 +86,9 @@ macro_rules! specified_types { attrs: [$($attr:meta),*], ) => { $(#[$attr])* + #[allow(dead_code)] mod $fn_name { - #[allow(unused)] type RustFnTy = $RustFn; - #[allow(unused)] type RustArgsTy = $RustArgs; } }; diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs index e0f5e52634e..bf47d200104 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -1,11 +1,9 @@ //! Integers used for wide operations, larger than `u128`. -#![allow(unused)] - #[cfg(test)] mod tests; -use core::{fmt, ops}; +use core::ops; use super::{DInt, HInt, Int, MinInt}; @@ -13,7 +11,6 @@ const WORD_LO_MASK: u64 = 0x00000000ffffffff; const WORD_HI_MASK: u64 = 0xffffffff00000000; const WORD_FULL_MASK: u64 = 0xffffffffffffffff; const U128_LO_MASK: u128 = u64::MAX as u128; -const U128_HI_MASK: u128 = (u64::MAX as u128) << 64; /// A 256-bit unsigned integer represented as 4 64-bit limbs. /// @@ -23,6 +20,7 @@ const U128_HI_MASK: u128 = (u64::MAX as u128) << 64; pub struct u256(pub [u64; 4]); impl u256 { + #[cfg(test)] pub const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX]); /// Reinterpret as a signed integer @@ -40,6 +38,7 @@ pub struct i256(pub [u64; 4]); impl i256 { /// Reinterpret as an unsigned integer + #[cfg(test)] pub fn unsigned(self) -> u256 { u256(self.0) } @@ -96,7 +95,7 @@ macro_rules! impl_common { impl ops::Shl for $ty { type Output = Self; - fn shl(self, rhs: u32) -> Self::Output { + fn shl(self, _rhs: u32) -> Self::Output { unimplemented!("only used to meet trait bounds") } } @@ -256,7 +255,7 @@ impl HInt for i128 { self.unsigned().zero_widen_mul(rhs.unsigned()).signed() } - fn widen_mul(self, rhs: Self) -> Self::D { + fn widen_mul(self, _rhs: Self) -> Self::D { unimplemented!("signed i128 widening multiply is not used") } diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index d6ce13f6907..3b27f8de50a 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -3,7 +3,7 @@ use core::{fmt, mem, ops}; use super::int_traits::{CastFrom, Int, MinInt}; /// Trait for some basic operations on floats -#[allow(dead_code)] +// #[allow(dead_code)] pub trait Float: Copy + fmt::Debug @@ -84,11 +84,13 @@ pub trait Float: fn to_bits(self) -> Self::Int; /// Returns `self` transmuted to `Self::SignedInt` + #[allow(dead_code)] fn to_bits_signed(self) -> Self::SignedInt { self.to_bits().signed() } /// Check bitwise equality. + #[allow(dead_code)] fn biteq(self, rhs: Self) -> bool { self.to_bits() == rhs.to_bits() } @@ -98,6 +100,7 @@ pub trait Float: /// /// This method returns `true` if two NaNs are compared. Use [`biteq`](Self::biteq) instead /// if `NaN` should not be treated separately. + #[allow(dead_code)] fn eq_repr(self, rhs: Self) -> bool { if self.is_nan() && rhs.is_nan() { true } else { self.biteq(rhs) } } @@ -117,6 +120,7 @@ pub trait Float: } /// Returns if `self` is subnormal. + #[allow(dead_code)] fn is_subnormal(self) -> bool { (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO } @@ -132,15 +136,11 @@ pub trait Float: } /// Returns the significand with no implicit bit (or the "fractional" part) + #[allow(dead_code)] fn frac(self) -> Self::Int { self.to_bits() & Self::SIG_MASK } - /// Returns the significand with implicit bit. - fn imp_frac(self) -> Self::Int { - self.frac() | Self::IMPLICIT_BIT - } - /// Returns a `Self::Int` transmuted back to `Self` fn from_bits(a: Self::Int) -> Self; @@ -154,22 +154,25 @@ pub trait Float: ) } + #[allow(dead_code)] fn abs(self) -> Self; /// Returns a number composed of the magnitude of self and the sign of sign. + #[allow(dead_code)] fn copysign(self, other: Self) -> Self; /// Returns (normalized exponent, normalized significand) + #[allow(dead_code)] fn normalize(significand: Self::Int) -> (i32, Self::Int); /// Returns a number that represents the sign of self. + #[allow(dead_code)] fn signum(self) -> Self { if self.is_nan() { self } else { Self::ONE.copysign(self) } } } /// Access the associated `Int` type from a float (helper to avoid ambiguous associated types). -#[allow(dead_code)] pub type IntTy = ::Int; macro_rules! float_impl { diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index 793a0f3069f..d34797764a0 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -1,7 +1,6 @@ use core::{cmp, fmt, ops}; /// Minimal integer implementations needed on all integer types, including wide integers. -#[allow(dead_code)] pub trait MinInt: Copy + fmt::Debug @@ -261,7 +260,6 @@ int_impl!(i128, u128); /// Trait for integers twice the bit width of another integer. This is implemented for all /// primitives except for `u8`, because there is not a smaller primitive. -#[allow(unused)] pub trait DInt: MinInt { /// Integer that is half the bit width of the integer this trait is implemented for type H: HInt; @@ -275,6 +273,7 @@ pub trait DInt: MinInt { (self.lo(), self.hi()) } /// Constructs an integer using lower and higher half parts + #[allow(unused)] fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { lo.zero_widen() | hi.widen_hi() } @@ -282,7 +281,6 @@ pub trait DInt: MinInt { /// Trait for integers half the bit width of another integer. This is implemented for all /// primitives except for `u128`, because it there is not a larger primitive. -#[allow(unused)] pub trait HInt: Int { /// Integer that is double the bit width of the integer this trait is implemented for type D: DInt + MinInt; @@ -297,6 +295,7 @@ pub trait HInt: Int { /// around problems with associated type bounds (such as `Int`) being unstable fn zero_widen(self) -> Self::D; /// Widens the integer to have double bit width and shifts the integer into the higher bits + #[allow(unused)] fn widen_hi(self) -> Self::D; /// Widening multiplication with zero widening. This cannot overflow. fn zero_widen_mul(self, rhs: Self) -> Self::D; @@ -360,7 +359,6 @@ impl_h_int!( ); /// Trait to express (possibly lossy) casting of integers -#[allow(unused)] pub trait CastInto: Copy { /// By default, casts should be exact. fn cast(self) -> T; @@ -369,7 +367,6 @@ pub trait CastInto: Copy { fn cast_lossy(self) -> T; } -#[allow(unused)] pub trait CastFrom: Copy { /// By default, casts should be exact. fn cast_from(value: T) -> Self; diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 68f1e49e5c4..d3c932b9771 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -5,7 +5,6 @@ mod float_traits; pub mod hex_float; mod int_traits; -#[allow(unused_imports)] pub use float_traits::{Float, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; #[cfg(f16_enabled)] -- cgit 1.4.1-3-g733a5 From aa4ae487d457b51e32081638b6603d1c75300d55 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 03:41:05 +0000 Subject: Convert `fmaf` to a generic implementation Introduce a version of generic `fma` that works when there is a larger hardware-backed float type available to compute the result with more precision. This is currently used only for `f32`, but with some minor adjustments it should work for `f16` as well. --- library/compiler-builtins/libm/src/math/fmaf.rs | 96 +--------------------- .../compiler-builtins/libm/src/math/generic/fma.rs | 67 ++++++++++++++- .../compiler-builtins/libm/src/math/generic/mod.rs | 2 +- library/compiler-builtins/libm/src/math/mod.rs | 2 +- .../libm/src/math/support/float_traits.rs | 58 +++++++++++++ .../compiler-builtins/libm/src/math/support/mod.rs | 3 +- 6 files changed, 129 insertions(+), 99 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index 79371c836c8..40d7f40d617 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -1,103 +1,11 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_fmaf.c */ -/*- - * Copyright (c) 2005-2011 David Schultz - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -use core::f32; -use core::ptr::read_volatile; - -use super::fenv::{ - FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, feclearexcept, fegetround, feraiseexcept, fetestexcept, -}; - -/* - * Fused multiply-add: Compute x * y + z with a single rounding error. - * - * A double has more than twice as much precision than a float, so - * direct double-precision arithmetic suffices, except where double - * rounding occurs. - */ - /// Floating multiply add (f32) /// /// Computes `(x*y)+z`, rounded as one ternary operation: /// Computes the value (as if) to infinite precision and rounds once to the result format, /// according to the rounding mode characterized by the value of FLT_ROUNDS. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { - let xy: f64; - let mut result: f64; - let mut ui: u64; - let e: i32; - - xy = x as f64 * y as f64; - result = xy + z as f64; - ui = result.to_bits(); - e = (ui >> 52) as i32 & 0x7ff; - /* Common case: The double precision result is fine. */ - if ( - /* not a halfway case */ - ui & 0x1fffffff) != 0x10000000 || - /* NaN */ - e == 0x7ff || - /* exact */ - (result - xy == z as f64 && result - z as f64 == xy) || - /* not round-to-nearest */ - fegetround() != FE_TONEAREST - { - /* - underflow may not be raised correctly, example: - fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) - */ - if ((0x3ff - 149)..(0x3ff - 126)).contains(&e) && fetestexcept(FE_INEXACT) != 0 { - feclearexcept(FE_INEXACT); - // prevent `xy + vz` from being CSE'd with `xy + z` above - let vz: f32 = unsafe { read_volatile(&z) }; - result = xy + vz as f64; - if fetestexcept(FE_INEXACT) != 0 { - feraiseexcept(FE_UNDERFLOW); - } else { - feraiseexcept(FE_INEXACT); - } - } - z = result as f32; - return z; - } - - /* - * If result is inexact, and exactly halfway between two float values, - * we need to adjust the low-order bit in the direction of the error. - */ - let neg = ui >> 63 != 0; - let err = if neg == (z as f64 > xy) { xy - result + z as f64 } else { z as f64 - result + xy }; - if neg == (err < 0.0) { - ui += 1; - } else { - ui -= 1; - } - f64::from_bits(ui) as f32 +pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { + super::generic::fma_wide(x, y, z) } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs index 4c6f1fad681..a40d7aaaf5e 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -1,10 +1,13 @@ /* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ +/* origin: musl src/math/{fma,fmaf}.c. Ported to generic Rust algorithm in 2025, TG. */ use core::{f32, f64}; +use super::super::fenv::{ + FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, feclearexcept, fegetround, feraiseexcept, fetestexcept, +}; use super::super::support::{DInt, HInt, IntTy}; -use super::super::{CastFrom, CastInto, Float, Int, MinInt}; +use super::super::{CastFrom, CastInto, DFloat, Float, HFloat, Int, MinInt}; /// Fused multiply-add that works when there is not a larger float size available. Currently this /// is still specialized only for `f64`. Computes `(x * y) + z`. @@ -212,6 +215,66 @@ where super::scalbn(r, e) } +/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, +/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. +pub fn fma_wide(x: F, y: F, z: F) -> F +where + F: Float + HFloat, + B: Float + DFloat, + B::Int: CastInto, + i32: CastFrom, +{ + let one = IntTy::::ONE; + + let xy: B = x.widen() * y.widen(); + let mut result: B = xy + z.widen(); + let mut ui: B::Int = result.to_bits(); + let re = result.exp(); + let zb: B = z.widen(); + + let prec_diff = B::SIG_BITS - F::SIG_BITS; + let excess_prec = ui & ((one << prec_diff) - one); + let halfway = one << (prec_diff - 1); + + // Common case: the larger precision is fine if... + // This is not a halfway case + if excess_prec != halfway + // Or the result is NaN + || re == B::EXP_SAT + // Or the result is exact + || (result - xy == zb && result - zb == xy) + // Or the mode is something other than round to nearest + || fegetround() != FE_TONEAREST + { + let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; + let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; + + if (min_inexact_exp..max_inexact_exp).contains(&re) && fetestexcept(FE_INEXACT) != 0 { + feclearexcept(FE_INEXACT); + // prevent `xy + vz` from being CSE'd with `xy + z` above + let vz: F = force_eval!(z); + result = xy + vz.widen(); + if fetestexcept(FE_INEXACT) != 0 { + feraiseexcept(FE_UNDERFLOW); + } else { + feraiseexcept(FE_INEXACT); + } + } + + return result.narrow(); + } + + let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; + let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy }; + if neg == (err < B::ZERO) { + ui += one; + } else { + ui -= one; + } + + B::from_bits(ui).narrow() +} + /// Representation of `F` that has handled subnormals. #[derive(Clone, Copy, Debug)] struct Norm { diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index e19cc83a9ac..b34d3dfae94 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -18,7 +18,7 @@ pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; -pub use fma::fma; +pub use fma::{fma, fma_wide}; pub use fmax::fmax; pub use fmin::fmin; pub use fmod::fmod; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 677ed8d6e93..e32045021da 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -121,7 +121,7 @@ use self::rem_pio2::rem_pio2; use self::rem_pio2_large::rem_pio2_large; use self::rem_pio2f::rem_pio2f; #[allow(unused_imports)] -use self::support::{CastFrom, CastInto, DInt, Float, HInt, Int, IntTy, MinInt}; +use self::support::{CastFrom, CastInto, DFloat, DInt, Float, HFloat, HInt, Int, IntTy, MinInt}; // Public modules mod acos; diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 3b27f8de50a..ee83c793da3 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -276,6 +276,64 @@ pub const fn f64_from_bits(bits: u64) -> f64 { unsafe { mem::transmute::(bits) } } +/// Trait for floats twice the bit width of another integer. +pub trait DFloat: Float { + /// Float that is half the bit width of the floatthis trait is implemented for. + type H: HFloat; + + /// Narrow the float type. + fn narrow(self) -> Self::H; +} + +/// Trait for floats half the bit width of another float. +pub trait HFloat: Float { + /// Float that is double the bit width of the float this trait is implemented for. + type D: DFloat; + + /// Widen the float type. + fn widen(self) -> Self::D; +} + +macro_rules! impl_d_float { + ($($X:ident $D:ident),*) => { + $( + impl DFloat for $D { + type H = $X; + + fn narrow(self) -> Self::H { + self as $X + } + } + )* + }; +} + +macro_rules! impl_h_float { + ($($H:ident $X:ident),*) => { + $( + impl HFloat for $H { + type D = $X; + + fn widen(self) -> Self::D { + self as $X + } + } + )* + }; +} + +impl_d_float!(f32 f64); +#[cfg(f16_enabled)] +impl_d_float!(f16 f32); +#[cfg(f128_enabled)] +impl_d_float!(f64 f128); + +impl_h_float!(f32 f64); +#[cfg(f16_enabled)] +impl_h_float!(f16 f32); +#[cfg(f128_enabled)] +impl_h_float!(f64 f128); + #[cfg(test)] mod tests { use super::*; diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index d3c932b9771..9eebd440371 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -5,7 +5,8 @@ mod float_traits; pub mod hex_float; mod int_traits; -pub use float_traits::{Float, IntTy}; +#[allow(unused_imports)] +pub use float_traits::{DFloat, Float, HFloat, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; #[cfg(f16_enabled)] #[allow(unused_imports)] -- cgit 1.4.1-3-g733a5 From 9169216f4126833868c5f15b034ae3d77ce7b3ac Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 21:25:03 +0000 Subject: Uncomment some hex float tests that should work now --- .../compiler-builtins/libm/src/math/support/hex_float.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index ebc4f7c64fa..99ad8bec377 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -1,7 +1,5 @@ //! Utilities for working with hex float formats. -#![allow(dead_code)] // FIXME: remove once this gets used - use core::fmt; use super::{Float, f32_from_bits, f64_from_bits}; @@ -13,6 +11,7 @@ pub const fn hf16(s: &str) -> f16 { } /// Construct a 32-bit float from hex float representation (C-style) +#[allow(unused)] pub const fn hf32(s: &str) -> f32 { f32_from_bits(parse_any(s, 32, 23) as u32) } @@ -548,14 +547,12 @@ mod parse_tests { #[test] fn test_macros() { - // FIXME(msrv): enable once parsing works - // #[cfg(f16_enabled)] - // assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); + #[cfg(f16_enabled)] + assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000_u32); assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000_u64); - // FIXME(msrv): enable once parsing works - // #[cfg(f128_enabled)] - // assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); + #[cfg(f128_enabled)] + assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); } } -- cgit 1.4.1-3-g733a5 From f45cc66e8e4b09ee447e3519e7d8e85f06a00001 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 22:28:19 +0000 Subject: Work arouind iai-callgrind apt failures Usually `cargo binstall iai-callgrind-runner` handles apt dependencies. However, the following has been happening: Err:11 mirror+file:/etc/apt/apt-mirrors.txt noble-updates/main amd64 libc6-dbg amd64 2.39-0ubuntu8.3 404 Not Found [IP: 40.81.13.82 80] E: Failed to fetch mirror+file:/etc/apt/apt-mirrors.txt/pool/main/g/glibc/libc6-dbg_2.39-0ubuntu8.3_amd64.deb 404 Not Found [IP: 40.81.13.82 80] Fetched 19.8 MB in 6s (3138 kB/s) E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing? Installing the dependencies manually seems to resolve the issue. --- library/compiler-builtins/libm/.github/workflows/main.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index de131639b56..265702965eb 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -158,6 +158,8 @@ jobs: - name: Set up dependencies run: | + sudo apt update + sudo apt install -y valgrind gdb libc6-dbg # Needed for iai-callgrind rustup update "$BENCHMARK_RUSTC" --no-self-update rustup default "$BENCHMARK_RUSTC" # Install the version of iai-callgrind-runner that is specified in Cargo.toml -- cgit 1.4.1-3-g733a5 From f1afc26b8a7691808f6be04493798620fe90e5fb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 00:29:04 +0000 Subject: Add an enum representation of rounding mode We only round using nearest, but some incoming code has more handling of rounding modes that would be nice to `match` on. Rather than checking integer values, add an enum representation. --- library/compiler-builtins/libm/src/math/fenv.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/fenv.rs b/library/compiler-builtins/libm/src/math/fenv.rs index c91272e8268..328c9f3467c 100644 --- a/library/compiler-builtins/libm/src/math/fenv.rs +++ b/library/compiler-builtins/libm/src/math/fenv.rs @@ -5,6 +5,9 @@ pub(crate) const FE_UNDERFLOW: i32 = 0; pub(crate) const FE_INEXACT: i32 = 0; pub(crate) const FE_TONEAREST: i32 = 0; +pub(crate) const FE_DOWNWARD: i32 = 1; +pub(crate) const FE_UPWARD: i32 = 2; +pub(crate) const FE_TOWARDZERO: i32 = 3; #[inline] pub(crate) fn feclearexcept(_mask: i32) -> i32 { @@ -25,3 +28,22 @@ pub(crate) fn fetestexcept(_mask: i32) -> i32 { pub(crate) fn fegetround() -> i32 { FE_TONEAREST } + +#[derive(Clone, Copy, Debug, PartialEq)] +pub(crate) enum Rounding { + Nearest = FE_TONEAREST as isize, + Downward = FE_DOWNWARD as isize, + Upward = FE_UPWARD as isize, + ToZero = FE_TOWARDZERO as isize, +} + +impl Rounding { + pub(crate) fn get() -> Self { + match fegetround() { + x if x == FE_DOWNWARD => Self::Downward, + x if x == FE_UPWARD => Self::Upward, + x if x == FE_TOWARDZERO => Self::ToZero, + _ => Self::Nearest, + } + } +} -- cgit 1.4.1-3-g733a5 From 2fa2b10ba4e0e5b89c9c17056459151129ee8cb1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 25 Oct 2024 03:56:09 -0500 Subject: Port the CORE-MATH version of `cbrt` Replace our current implementation with one that is correctly rounded. Source: https://gitlab.inria.fr/core-math/core-math/-/blob/81d447bb1c46592291bec3476bc24fa2c2688c67/src/binary64/cbrt/cbrt.c --- library/compiler-builtins/libm/src/math/cbrt.rs | 319 ++++++++++++++++-------- 1 file changed, 216 insertions(+), 103 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index b4e77eaa27c..fbf81f77d2e 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -1,113 +1,226 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrt.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - * - * Optimized by Bruce D. Evans. +/* SPDX-License-Identifier: MIT */ +/* origin: core-math/src/binary64/cbrt/cbrt.c + * Copyright (c) 2021-2022 Alexei Sibidanov. + * Ported to Rust in 2025 by Trevor Gross. */ -/* cbrt(x) - * Return cube root of x - */ - -use core::f64; -const B1: u32 = 715094163; /* B1 = (1023-1023/3-0.03306235651)*2**20 */ -const B2: u32 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */ +use super::Float; +use super::fenv::Rounding; +use super::support::cold_path; -/* |1/cbrt(x) - p(x)| < 2**-23.5 (~[-7.93e-8, 7.929e-8]). */ -const P0: f64 = 1.87595182427177009643; /* 0x3ffe03e6, 0x0f61e692 */ -const P1: f64 = -1.88497979543377169875; /* 0xbffe28e0, 0x92f02420 */ -const P2: f64 = 1.621429720105354466140; /* 0x3ff9f160, 0x4a49d6c2 */ -const P3: f64 = -0.758397934778766047437; /* 0xbfe844cb, 0xbee751d9 */ -const P4: f64 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ - -// Cube root (f64) -/// -/// Computes the cube root of the argument. +/// Compute the cube root of the argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrt(x: f64) -> f64 { - let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 - - let mut ui: u64 = x.to_bits(); - let mut r: f64; - let s: f64; - let mut t: f64; - let w: f64; - let mut hx: u32 = (ui >> 32) as u32 & 0x7fffffff; - - if hx >= 0x7ff00000 { - /* cbrt(NaN,INF) is itself */ - return x + x; + const ESCALE: [f64; 3] = [ + 1.0, + hf64!("0x1.428a2f98d728bp+0"), /* 2^(1/3) */ + hf64!("0x1.965fea53d6e3dp+0"), /* 2^(2/3) */ + ]; + + /* the polynomial c0+c1*x+c2*x^2+c3*x^3 approximates x^(1/3) on [1,2] + with maximal error < 9.2e-5 (attained at x=2) */ + const C: [f64; 4] = [ + hf64!("0x1.1b0babccfef9cp-1"), + hf64!("0x1.2c9a3e94d1da5p-1"), + hf64!("-0x1.4dc30b1a1ddbap-3"), + hf64!("0x1.7a8d3e4ec9b07p-6"), + ]; + + let u0: f64 = hf64!("0x1.5555555555555p-2"); + let u1: f64 = hf64!("0x1.c71c71c71c71cp-3"); + + let rsc = [1.0, -1.0, 0.5, -0.5, 0.25, -0.25]; + + let off = [hf64!("0x1p-53"), 0.0, 0.0, 0.0]; + + let rm = Rounding::get(); + + /* rm=0 for rounding to nearest, and other values for directed roundings */ + let hx: u64 = x.to_bits(); + let mut mant: u64 = hx & f64::SIG_MASK; + let sign: u64 = hx >> 63; + + let mut e: u32 = (hx >> f64::SIG_BITS) as u32 & f64::EXP_SAT; + + if ((e + 1) & f64::EXP_SAT) < 2 { + cold_path(); + + let ix: u64 = hx & !f64::SIGN_MASK; + + /* 0, inf, nan: we return x + x instead of simply x, + to that for x a signaling NaN, it correctly triggers + the invalid exception. */ + if e == f64::EXP_SAT || ix == 0 { + return x + x; + } + + let nz = ix.leading_zeros() - 11; /* subnormal */ + mant <<= nz; + mant &= f64::SIG_MASK; + e = e.wrapping_sub(nz - 1); + } + + e = e.wrapping_add(3072); + let cvt1: u64 = mant | (0x3ffu64 << 52); + let mut cvt5: u64 = cvt1; + + let et: u32 = e / 3; + let it: u32 = e % 3; + + /* 2^(3k+it) <= x < 2^(3k+it+1), with 0 <= it <= 3 */ + cvt5 += u64::from(it) << f64::SIG_BITS; + cvt5 |= sign << 63; + let zz: f64 = f64::from_bits(cvt5); + + /* cbrt(x) = cbrt(zz)*2^(et-1365) where 1 <= zz < 8 */ + let mut isc: u64 = ESCALE[it as usize].to_bits(); // todo: index + isc |= sign << 63; + let cvt2: u64 = isc; + let z: f64 = f64::from_bits(cvt1); + + /* cbrt(zz) = cbrt(z)*isc, where isc encodes 1, 2^(1/3) or 2^(2/3), + and 1 <= z < 2 */ + let r: f64 = 1.0 / z; + let rr: f64 = r * rsc[((it as usize) << 1) | sign as usize]; + let z2: f64 = z * z; + let c0: f64 = C[0] + z * C[1]; + let c2: f64 = C[2] + z * C[3]; + let mut y: f64 = c0 + z2 * c2; + let mut y2: f64 = y * y; + + /* y is an approximation of z^(1/3) */ + let mut h: f64 = y2 * (y * r) - 1.0; + + /* h determines the error between y and z^(1/3) */ + y -= (h * y) * (u0 - u1 * h); + + /* The correction y -= (h*y)*(u0 - u1*h) corresponds to a cubic variant + of Newton's method, with the function f(y) = 1-z/y^3. */ + y *= f64::from_bits(cvt2); + + /* Now y is an approximation of zz^(1/3), + * and rr an approximation of 1/zz. We now perform another iteration of + * Newton-Raphson, this time with a linear approximation only. */ + y2 = y * y; + let mut y2l: f64 = fmaf64(y, y, -y2); + + /* y2 + y2l = y^2 exactly */ + let mut y3: f64 = y2 * y; + let mut y3l: f64 = fmaf64(y, y2, -y3) + y * y2l; + + /* y3 + y3l approximates y^3 with about 106 bits of accuracy */ + h = ((y3 - zz) + y3l) * rr; + let mut dy: f64 = h * (y * u0); + + /* the approximation of zz^(1/3) is y - dy */ + let mut y1: f64 = y - dy; + dy = (y - y1) - dy; + + /* the approximation of zz^(1/3) is now y1 + dy, where |dy| < 1/2 ulp(y) + * (for rounding to nearest) */ + let mut ady: f64 = dy.abs(); + + /* For directed roundings, ady0 is tiny when dy is tiny, or ady0 is near + * from ulp(1); + * for rounding to nearest, ady0 is tiny when dy is near from 1/2 ulp(1), + * or from 3/2 ulp(1). */ + let mut ady0: f64 = (ady - off[rm as usize]).abs(); + let mut ady1: f64 = (ady - (hf64!("0x1p-52") + off[rm as usize])).abs(); + + if ady0 < hf64!("0x1p-75") || ady1 < hf64!("0x1p-75") { + cold_path(); + + y2 = y1 * y1; + y2l = fmaf64(y1, y1, -y2); + y3 = y2 * y1; + y3l = fmaf64(y1, y2, -y3) + y1 * y2l; + h = ((y3 - zz) + y3l) * rr; + dy = h * (y1 * u0); + y = y1 - dy; + dy = (y1 - y) - dy; + y1 = y; + ady = dy.abs(); + ady0 = (ady - off[rm as usize]).abs(); + ady1 = (ady - (hf64!("0x1p-52") + off[rm as usize])).abs(); + + if ady0 < hf64!("0x1p-98") || ady1 < hf64!("0x1p-98") { + cold_path(); + let azz: f64 = zz.abs(); + + // ~ 0x1.79d15d0e8d59b80000000000000ffc3dp+0 + if azz == hf64!("0x1.9b78223aa307cp+1") { + y1 = hf64!("0x1.79d15d0e8d59cp+0").copysign(zz); + } + + // ~ 0x1.de87aa837820e80000000000001c0f08p+0 + if azz == hf64!("0x1.a202bfc89ddffp+2") { + y1 = hf64!("0x1.de87aa837820fp+0").copysign(zz); + } + + if rm != Rounding::Nearest { + let wlist = [ + (hf64!("0x1.3a9ccd7f022dbp+0"), hf64!("0x1.1236160ba9b93p+0")), // ~ 0x1.1236160ba9b930000000000001e7e8fap+0 + (hf64!("0x1.7845d2faac6fep+0"), hf64!("0x1.23115e657e49cp+0")), // ~ 0x1.23115e657e49c0000000000001d7a799p+0 + (hf64!("0x1.d1ef81cbbbe71p+0"), hf64!("0x1.388fb44cdcf5ap+0")), // ~ 0x1.388fb44cdcf5a0000000000002202c55p+0 + (hf64!("0x1.0a2014f62987cp+1"), hf64!("0x1.46bcbf47dc1e8p+0")), // ~ 0x1.46bcbf47dc1e8000000000000303aa2dp+0 + (hf64!("0x1.fe18a044a5501p+1"), hf64!("0x1.95decfec9c904p+0")), // ~ 0x1.95decfec9c9040000000000000159e8ep+0 + (hf64!("0x1.a6bb8c803147bp+2"), hf64!("0x1.e05335a6401dep+0")), // ~ 0x1.e05335a6401de00000000000027ca017p+0 + (hf64!("0x1.ac8538a031cbdp+2"), hf64!("0x1.e281d87098de8p+0")), // ~ 0x1.e281d87098de80000000000000ee9314p+0 + ]; + + for (a, b) in wlist { + if azz == a { + let tmp = if rm as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 }; + y1 = (b + tmp).copysign(zz); + } + } + } + } + } + + let mut cvt3: u64 = y1.to_bits(); + cvt3 = cvt3.wrapping_add(((et.wrapping_sub(342).wrapping_sub(1023)) as u64) << 52); + let m0: u64 = cvt3 << 30; + let m1 = m0 >> 63; + + if (m0 ^ m1) <= (1u64 << 30) { + cold_path(); + + let mut cvt4: u64 = y1.to_bits(); + cvt4 = (cvt4 + (164 << 15)) & 0xffffffffffff0000u64; + + if ((f64::from_bits(cvt4) - y1) - dy).abs() < hf64!("0x1p-60") || (zz).abs() == 1.0 { + cvt3 = (cvt3 + (1u64 << 15)) & 0xffffffffffff0000u64; + } } - /* - * Rough cbrt to 5 bits: - * cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3) - * where e is integral and >= 0, m is real and in [0, 1), and "/" and - * "%" are integer division and modulus with rounding towards minus - * infinity. The RHS is always >= the LHS and has a maximum relative - * error of about 1 in 16. Adding a bias of -0.03306235651 to the - * (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE - * floating point representation, for finite positive normal values, - * ordinary integer divison of the value in bits magically gives - * almost exactly the RHS of the above provided we first subtract the - * exponent bias (1023 for doubles) and later add it back. We do the - * subtraction virtually to keep e >= 0 so that ordinary integer - * division rounds towards minus infinity; this is also efficient. - */ - if hx < 0x00100000 { - /* zero or subnormal? */ - ui = (x * x1p54).to_bits(); - hx = (ui >> 32) as u32 & 0x7fffffff; - if hx == 0 { - return x; /* cbrt(0) is itself */ + f64::from_bits(cvt3) +} + +fn fmaf64(x: f64, y: f64, z: f64) -> f64 { + #[cfg(intrinsics_enabled)] + { + return unsafe { core::intrinsics::fmaf64(x, y, z) }; + } + + #[cfg(not(intrinsics_enabled))] + { + return super::fma(x, y, z); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn spot_checks() { + if !cfg!(x86_no_sse) { + // Exposes a rounding mode problem. Ignored on i586 because of inaccurate FMA. + assert_biteq!( + cbrt(f64::from_bits(0xf7f792b28f600000)), + f64::from_bits(0xd29ce68655d962f3) + ); } - hx = hx / 3 + B2; - } else { - hx = hx / 3 + B1; } - ui &= 1 << 63; - ui |= (hx as u64) << 32; - t = f64::from_bits(ui); - - /* - * New cbrt to 23 bits: - * cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x) - * where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r) - * to within 2**-23.5 when |r - 1| < 1/10. The rough approximation - * has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this - * gives us bounds for r = t**3/x. - * - * Try to optimize for parallel evaluation as in __tanf.c. - */ - r = (t * t) * (t / x); - t = t * ((P0 + r * (P1 + r * P2)) + ((r * r) * r) * (P3 + r * P4)); - - /* - * Round t away from zero to 23 bits (sloppily except for ensuring that - * the result is larger in magnitude than cbrt(x) but not much more than - * 2 23-bit ulps larger). With rounding towards zero, the error bound - * would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps - * in the rounded t, the infinite-precision error in the Newton - * approximation barely affects third digit in the final error - * 0.667; the error in the rounded t can be up to about 3 23-bit ulps - * before the final error is larger than 0.667 ulps. - */ - ui = t.to_bits(); - ui = (ui + 0x80000000) & 0xffffffffc0000000; - t = f64::from_bits(ui); - - /* one step Newton iteration to 53 bits with error < 0.667 ulps */ - s = t * t; /* t*t is exact */ - r = x / s; /* error <= 0.5 ulps; |r| < |t| */ - w = t + t; /* t+t is exact */ - r = (r - t) / (w + r); /* r-t is exact; w+r ~= 3*t */ - t = t + t * r; /* error <= 0.5 + 0.5/3 + epsilon */ - t } -- cgit 1.4.1-3-g733a5 From 35c201c37f06f086d327de7a007e3bc97257351b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 00:31:49 +0000 Subject: Decrease the allowed error for `cbrt` With the correctly rounded implementation, we can reduce the ULP requirement for `cbrt` to zero. There is still an override required for `i586` because of the imprecise FMA. --- library/compiler-builtins/libm/crates/libm-test/src/precision.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 20aa96b6aba..a859965395c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -41,7 +41,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { | Bn::Trunc => 0, // Operations that aren't required to be exact, but our implementations are. - Bn::Cbrt if ctx.fn_ident != Id::Cbrt => 0, + Bn::Cbrt => 0, // Bessel functions have large inaccuracies. Bn::J0 | Bn::J1 | Bn::Y0 | Bn::Y1 | Bn::Jn | Bn::Yn => 8_000_000, @@ -54,7 +54,6 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Bn::Atan => 1, Bn::Atan2 => 2, Bn::Atanh => 2, - Bn::Cbrt => 1, Bn::Cos => 1, Bn::Cosh => 1, Bn::Erf => 1, @@ -92,6 +91,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { } match ctx.fn_ident { + Id::Cbrt => ulp = 2, // FIXME(#401): musl has an incorrect result here. Id::Fdim => ulp = 2, Id::Sincosf => ulp = 500, @@ -119,6 +119,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Id::Asinh => ulp = 3, Id::Asinhf => ulp = 3, + Id::Cbrt => ulp = 1, Id::Exp10 | Id::Exp10f => ulp = 1_000_000, Id::Exp2 | Id::Exp2f => ulp = 10_000_000, Id::Log1p | Id::Log1pf => ulp = 2, -- cgit 1.4.1-3-g733a5 From 0a43f24a30c4952eb6b990051b6b37800b79da26 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 8 Feb 2025 07:06:59 +0000 Subject: Add simple icount benchmarks for `u256` operations --- .../libm/crates/libm-test/benches/icount.rs | 101 +++++++++++++++++++++ .../compiler-builtins/libm/src/math/support/big.rs | 2 +- .../compiler-builtins/libm/src/math/support/mod.rs | 2 + 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index c41cef24e54..232a3de38aa 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -1,8 +1,10 @@ //! Benchmarks that use `iai-cachegrind` to be reasonably CI-stable. use std::hint::black_box; +use std::ops::Shr; use iai_callgrind::{library_benchmark, library_benchmark_group, main}; +use libm::support::{HInt, u256}; use libm_test::gen::spaced; use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, OpRustArgs, TupleCall, op}; @@ -51,8 +53,107 @@ libm_macros::for_each_function! { callback: icount_benches, } +fn setup_u128_mul() -> Vec<(u128, u128)> { + let step = u128::MAX / 300; + let mut x = 0u128; + let mut y = 0u128; + let mut v = Vec::new(); + + loop { + 'inner: loop { + match y.checked_add(step) { + Some(new) => y = new, + None => break 'inner, + } + + v.push((x, y)) + } + + match x.checked_add(step) { + Some(new) => x = new, + None => break, + } + } + + v +} + +/* +fn setup_u256_add() -> Vec<(u256, u256)> { + let mut v = Vec::new(); + for (x, y) in setup_u128_mul() { + // square the u128 inputs to cover most of the u256 range + v.push((x.widen_mul(x), y.widen_mul(y))); + } + // Doesn't get covered by `u128:MAX^2` + v.push((u256::MAX, u256::MAX)); + v +} +*/ + +fn setup_u256_shift() -> Vec<(u256, u32)> { + let mut v = Vec::new(); + + for (x, _) in setup_u128_mul() { + let x2 = x.widen_mul(x); + for y in 0u32..256 { + v.push((x2, y)); + } + } + + v +} + +#[library_benchmark] +#[bench::linspace(setup_u128_mul())] +fn icount_bench_u128_widen_mul(cases: Vec<(u128, u128)>) { + let f = black_box(u128::zero_widen_mul); + for (x, y) in cases.iter().copied() { + f(x, y); + } +} + +library_benchmark_group!( + name = icount_bench_u128_widen_mul_group; + benchmarks = icount_bench_u128_widen_mul +); + +/* Not yet implemented +#[library_benchmark] +#[bench::linspace(setup_u256_add())] +fn icount_bench_u256_add(cases: Vec<(u256, u256)>) { + let f = black_box(u256::add); + for (x, y) in cases.iter().copied() { + f(x, y); + } +} + +library_benchmark_group!( + name = icount_bench_u256_add_group; + benchmarks = icount_bench_u256_add +); +*/ + +#[library_benchmark] +#[bench::linspace(setup_u256_shift())] +fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) { + let f = black_box(u256::shr); + for (x, y) in cases.iter().copied() { + f(x, y); + } +} + +library_benchmark_group!( + name = icount_bench_u256_shr_group; + benchmarks = icount_bench_u256_shr +); + main!( library_benchmark_groups = + // u256-related benchmarks + icount_bench_u128_widen_mul_group, + // icount_bench_u256_add_group, + icount_bench_u256_shr_group, // verify-apilist-start // verify-sorted-start icount_bench_acos_group, diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs index bf47d200104..7a437b67ac4 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -20,7 +20,7 @@ const U128_LO_MASK: u128 = u64::MAX as u128; pub struct u256(pub [u64; 4]); impl u256 { - #[cfg(test)] + #[allow(unused)] pub const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX]); /// Reinterpret as a signed integer diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 9eebd440371..28e9fd4132f 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -5,6 +5,8 @@ mod float_traits; pub mod hex_float; mod int_traits; +#[allow(unused_imports)] +pub use big::{i256, u256}; #[allow(unused_imports)] pub use float_traits::{DFloat, Float, HFloat, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; -- cgit 1.4.1-3-g733a5 From 900b61f363e88aae7a1292e480c36a6cd8fcf3b9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 8 Feb 2025 09:39:05 +0000 Subject: Change how operators are `black_box`ed For some reason, the upcoming limb changes in [1] seem to ignore the black boxing when applied to the operator function. Changing to instead black box the inputs appears to fix this. [1]: https://github.com/rust-lang/libm/pull/503 --- .../compiler-builtins/libm/crates/libm-test/benches/icount.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 232a3de38aa..9fac52e0b85 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -1,7 +1,6 @@ //! Benchmarks that use `iai-cachegrind` to be reasonably CI-stable. use std::hint::black_box; -use std::ops::Shr; use iai_callgrind::{library_benchmark, library_benchmark_group, main}; use libm::support::{HInt, u256}; @@ -107,9 +106,8 @@ fn setup_u256_shift() -> Vec<(u256, u32)> { #[library_benchmark] #[bench::linspace(setup_u128_mul())] fn icount_bench_u128_widen_mul(cases: Vec<(u128, u128)>) { - let f = black_box(u128::zero_widen_mul); for (x, y) in cases.iter().copied() { - f(x, y); + black_box(black_box(x).zero_widen_mul(black_box(y))); } } @@ -122,9 +120,8 @@ library_benchmark_group!( #[library_benchmark] #[bench::linspace(setup_u256_add())] fn icount_bench_u256_add(cases: Vec<(u256, u256)>) { - let f = black_box(u256::add); for (x, y) in cases.iter().copied() { - f(x, y); + black_box(black_box(x) + black_box(y)); } } @@ -137,9 +134,8 @@ library_benchmark_group!( #[library_benchmark] #[bench::linspace(setup_u256_shift())] fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) { - let f = black_box(u256::shr); for (x, y) in cases.iter().copied() { - f(x, y); + black_box(black_box(x) >> black_box(y)); } } -- cgit 1.4.1-3-g733a5 From 017f1035f12c2b7740bdbd0b27203f45c9777338 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 8 Feb 2025 09:48:14 +0000 Subject: Replace an `assert!` with `debug_assert!` in `u256::shr` The implementation came from the `compiler_builtins` port but this should be weakened to match other integer types. --- .../compiler-builtins/libm/src/math/support/big.rs | 5 ++++- .../libm/src/math/support/big/tests.rs | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs index 7a437b67ac4..017e9455e40 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -109,7 +109,10 @@ impl ops::Shr for u256 { type Output = Self; fn shr(self, rhs: u32) -> Self::Output { - assert!(rhs < Self::BITS, "attempted to shift right with overflow"); + debug_assert!(rhs < Self::BITS, "attempted to shift right with overflow"); + if rhs >= Self::BITS { + return Self::ZERO; + } if rhs == 0 { return self; diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs index f95f8297316..815a62dfee8 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -108,3 +108,22 @@ fn shr_u128() { } assert!(errors.is_empty()); } + +#[test] +#[should_panic] +#[cfg(debug_assertions)] +// FIXME(ppc): ppc64le seems to have issues with `should_panic` tests. +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +fn shr_u256_overflow() { + // Like regular shr, panic on overflow with debug assertions + let _ = u256::MAX >> 256; +} + +#[test] +#[cfg(not(debug_assertions))] +fn shr_u256_overflow() { + // No panic without debug assertions + assert_eq!(u256::MAX >> 256, u256::ZERO); + assert_eq!(u256::MAX >> 257, u256::ZERO); + assert_eq!(u256::MAX >> u32::MAX, u256::ZERO); +} -- cgit 1.4.1-3-g733a5 From 1efdc9697400d19948d178f2d1db8f181f1ad836 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 02:05:41 +0000 Subject: Increase the tolerance for `jn` and `yn` These still fail random tests, e.g.: called `Result::unwrap()` on an `Err` value: jn Caused by: 0: input: (1068, -16013.98381387313) as hex: (, -0x1.f46fded9ced39p+13) as bits: (0x0000042c, 0xc0cf46fded9ced39) expected: 6.7603314308122506e-6 0x1.c5ad9c102d413p-18 0x3edc5ad9c102d413 actual: 6.7603314308006335e-6 0x1.c5ad9c1029e80p-18 0x3edc5ad9c1029e80 1: ulp 13715 > 4000 Caused by: 0: input: (195, 42147.94) as hex: (, 0x1.4947e2p+15) as bits: (0x000000c3, 0x4724a3f1) expected: -2.13669e-7 -0x1.cad9c6p-23 0xb4656ce3 actual: -2.1376937e-7 -0x1.cb10f4p-23 0xb465887a 1: ulp 7063 > 4000 Caused by: 0: input: (194, 740.1916) as hex: (, 0x1.721886p+9) as bits: (0x000000c2, 0x44390c43) expected: 1.212096e-6 0x1.455e9ap-20 0x35a2af4d actual: 1.2172386e-6 0x1.46c000p-20 0x35a36000 1: ulp 45235 > 10000 Increase allowed precision to avoid spurious failures. --- .../libm/crates/libm-test/src/precision.rs | 26 ++++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index a859965395c..2f55ad22ec7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -523,18 +523,7 @@ fn int_float_common( && actual == F2::ZERO && expected == F2::ZERO { - return XFAIL("mpfr b"); - } - - // Our bessel functions blow up with large N values - if ctx.basis == Musl && (ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn) { - if input.0 > 4000 { - return XFAIL_NOCHECK; - } else if input.0 > 2000 { - return CheckAction::AssertWithUlp(20_000); - } else if input.0 > 1000 { - return CheckAction::AssertWithUlp(4_000); - } + return XFAIL("we disagree with MPFR on the sign of zero"); } // Values near infinity sometimes get cut off for us. `ynf(681, 509.90924) = -inf` but should @@ -549,6 +538,19 @@ fn int_float_common( return XFAIL_NOCHECK; } + // Our bessel functions blow up with large N values + if ctx.basis == Musl && (ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn) { + if cfg!(x86_no_sse) { + // Precision is especially bad on i586, not worth checking. + return XFAIL_NOCHECK; + } + + if input.0 > 4000 { + return XFAIL_NOCHECK; + } else if input.0 > 100 { + return CheckAction::AssertWithUlp(1_000_000); + } + } DEFAULT } -- cgit 1.4.1-3-g733a5 From b7fdce0505cf015d4f983064adf2b6a31d52db69 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 9 Feb 2025 22:40:20 +0000 Subject: ci: Pin the nightly toolchain for i686-pc-windows-gnu Pin i686-pc-windows-gnu to nightly-2025-02-07 until [1] is resolved. [1]: https://github.com/rust-lang/rust/issues/136795 --- library/compiler-builtins/libm/.github/workflows/main.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 265702965eb..f066f4a8c1f 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -68,7 +68,8 @@ jobs: os: windows-2025 - target: i686-pc-windows-gnu os: windows-2025 - channel: nightly-i686-gnu + # FIXME: pinned due to https://github.com/rust-lang/rust/issues/136795 + channel: nightly-2025-02-07-i686-gnu - target: x86_64-pc-windows-gnu os: windows-2025 channel: nightly-x86_64-gnu -- cgit 1.4.1-3-g733a5 From 2f0685a9a2a72248b10cd70ca9d013c0ab9bf286 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 8 Feb 2025 04:09:59 +0000 Subject: Implement `u256` with two `u128`s rather than `u64` This produces better assembly, e.g. on aarch64: .globl libm::u128_wmul .p2align 2 libm::u128_wmul: Lfunc_begin124: .cfi_startproc mul x9, x2, x0 umulh x10, x2, x0 umulh x11, x3, x0 mul x12, x3, x0 umulh x13, x2, x1 mul x14, x2, x1 umulh x15, x3, x1 mul x16, x3, x1 adds x10, x10, x14 cinc x13, x13, hs adds x13, x13, x16 cinc x14, x15, hs adds x10, x10, x12 cinc x11, x11, hs adds x11, x13, x11 stp x9, x10, [x8] cinc x9, x14, hs stp x11, x9, [x8, rust-lang/libm#16] ret The original was ~70 instructions so the improvement is significant. With these changes, the result is reasonably close to what LLVM generates using `u256` operands [1]. [1]: https://llvm.godbolt.org/z/re1aGdaqY --- .../libm/crates/libm-test/benches/icount.rs | 6 +- .../libm/crates/libm-test/src/gen/random.rs | 2 +- .../libm/crates/libm-test/src/lib.rs | 5 +- .../libm/crates/libm-test/src/run_cfg.rs | 30 ++- .../libm/crates/libm-test/tests/u256.rs | 147 ++++++++++++++ .../compiler-builtins/libm/src/math/support/big.rs | 217 ++++++++------------- .../libm/src/math/support/big/tests.rs | 79 +++++--- 7 files changed, 298 insertions(+), 188 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/u256.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 9fac52e0b85..be85dd5676c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -77,7 +77,6 @@ fn setup_u128_mul() -> Vec<(u128, u128)> { v } -/* fn setup_u256_add() -> Vec<(u256, u256)> { let mut v = Vec::new(); for (x, y) in setup_u128_mul() { @@ -88,7 +87,6 @@ fn setup_u256_add() -> Vec<(u256, u256)> { v.push((u256::MAX, u256::MAX)); v } -*/ fn setup_u256_shift() -> Vec<(u256, u32)> { let mut v = Vec::new(); @@ -116,7 +114,6 @@ library_benchmark_group!( benchmarks = icount_bench_u128_widen_mul ); -/* Not yet implemented #[library_benchmark] #[bench::linspace(setup_u256_add())] fn icount_bench_u256_add(cases: Vec<(u256, u256)>) { @@ -129,7 +126,6 @@ library_benchmark_group!( name = icount_bench_u256_add_group; benchmarks = icount_bench_u256_add ); -*/ #[library_benchmark] #[bench::linspace(setup_u256_shift())] @@ -148,7 +144,7 @@ main!( library_benchmark_groups = // u256-related benchmarks icount_bench_u128_widen_mul_group, - // icount_bench_u256_add_group, + icount_bench_u256_add_group, icount_bench_u256_shr_group, // verify-apilist-start // verify-sorted-start diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 5b127f38d09..c2cd172d1ee 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -14,7 +14,7 @@ use crate::run_cfg::{int_range, iteration_count}; pub(crate) const SEED_ENV: &str = "LIBM_SEED"; -pub(crate) static SEED: LazyLock<[u8; 32]> = LazyLock::new(|| { +pub static SEED: LazyLock<[u8; 32]> = LazyLock::new(|| { let s = env::var(SEED_ENV).unwrap_or_else(|_| { let mut rng = rand::thread_rng(); (0..32).map(|_| rng.sample(Alphanumeric) as char).collect() diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index d2fef232505..824f09a3387 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -29,7 +29,10 @@ pub use op::{ }; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; use run_cfg::extensive_max_iterations; -pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, skip_extensive_test}; +pub use run_cfg::{ + CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, bigint_fuzz_iteration_count, + skip_extensive_test, +}; pub use test_traits::{CheckOutput, Hex, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 4dd43bdf386..6b268997666 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -158,14 +158,6 @@ impl TestEnv { let op = id.math_op(); let will_run_mp = cfg!(feature = "build-mpfr"); - - // Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run in QEMU. Start - // with a reduced number on these platforms. - let slow_on_ci = crate::emulated() - || usize::BITS < 64 - || cfg!(all(target_arch = "x86_64", target_vendor = "apple")); - let slow_platform = slow_on_ci && crate::ci(); - let large_float_ty = match op.float_ty { FloatTy::F16 | FloatTy::F32 => false, FloatTy::F64 | FloatTy::F128 => true, @@ -176,7 +168,7 @@ impl TestEnv { let input_count = op.rust_sig.args.len(); Self { - slow_platform, + slow_platform: slow_platform(), large_float_ty, should_run_extensive: will_run_extensive, mp_tests_enabled: will_run_mp, @@ -185,6 +177,17 @@ impl TestEnv { } } +/// Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run in QEMU. Start +/// with a reduced number on these platforms. +fn slow_platform() -> bool { + let slow_on_ci = crate::emulated() + || usize::BITS < 64 + || cfg!(all(target_arch = "x86_64", target_vendor = "apple")); + + // If not running in CI, there is no need to reduce iteration count. + slow_on_ci && crate::ci() +} + /// The number of iterations to run for a given test. pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { let t_env = TestEnv::from_env(ctx); @@ -351,3 +354,12 @@ pub fn skip_extensive_test(ctx: &CheckCtx) -> bool { let t_env = TestEnv::from_env(ctx); !t_env.should_run_extensive } + +/// The number of iterations to run for `u256` fuzz tests. +pub fn bigint_fuzz_iteration_count() -> u64 { + if !cfg!(optimizations_enabled) { + return 1000; + } + + if slow_platform() { 100_000 } else { 5_000_000 } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs b/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs new file mode 100644 index 00000000000..4174820c05b --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs @@ -0,0 +1,147 @@ +//! Test the u256 implementation. the ops already get exercised reasonably well through the `f128` +//! routines, so this only does a few million fuzz iterations against GMP. + +#![cfg(feature = "build-mpfr")] + +use std::sync::LazyLock; + +use libm::support::{HInt, u256}; +type BigInt = rug::Integer; + +use libm_test::bigint_fuzz_iteration_count; +use libm_test::gen::random::SEED; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; +use rug::Assign; +use rug::integer::Order; +use rug::ops::NotAssign; + +static BIGINT_U256_MAX: LazyLock = + LazyLock::new(|| BigInt::from_digits(&[u128::MAX, u128::MAX], Order::Lsf)); + +/// Copied from the test module. +fn hexu(v: u256) -> String { + format!("0x{:032x}{:032x}", v.hi, v.lo) +} + +fn random_u256(rng: &mut ChaCha8Rng) -> u256 { + let lo: u128 = rng.gen(); + let hi: u128 = rng.gen(); + u256 { lo, hi } +} + +fn assign_bigint(bx: &mut BigInt, x: u256) { + bx.assign_digits(&[x.lo, x.hi], Order::Lsf); +} + +fn from_bigint(bx: &mut BigInt) -> u256 { + // Truncate so the result fits into `[u128; 2]`. This makes all ops overflowing. + *bx &= &*BIGINT_U256_MAX; + let mut bres = [0u128, 0]; + bx.write_digits(&mut bres, Order::Lsf); + bx.assign(0); + u256 { lo: bres[0], hi: bres[1] } +} + +fn check_one( + x: impl FnOnce() -> String, + y: impl FnOnce() -> Option, + actual: u256, + expected: &mut BigInt, +) { + let expected = from_bigint(expected); + if actual != expected { + let xmsg = x(); + let ymsg = y().map(|y| format!("y: {y}\n")).unwrap_or_default(); + panic!( + "Results do not match\n\ + input: {xmsg}\n\ + {ymsg}\ + actual: {}\n\ + expected: {}\ + ", + hexu(actual), + hexu(expected), + ) + } +} + +#[test] +fn mp_u256_bitor() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + let mut by = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_u256(&mut rng); + let y = random_u256(&mut rng); + assign_bigint(&mut bx, x); + assign_bigint(&mut by, y); + let actual = x | y; + bx |= &by; + check_one(|| hexu(x), || Some(hexu(y)), actual, &mut bx); + } +} + +#[test] +fn mp_u256_not() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_u256(&mut rng); + assign_bigint(&mut bx, x); + let actual = !x; + bx.not_assign(); + check_one(|| hexu(x), || None, actual, &mut bx); + } +} + +#[test] +fn mp_u256_add() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + let mut by = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_u256(&mut rng); + let y = random_u256(&mut rng); + assign_bigint(&mut bx, x); + assign_bigint(&mut by, y); + let actual = x + y; + bx += &by; + check_one(|| hexu(x), || Some(hexu(y)), actual, &mut bx); + } +} + +#[test] +fn mp_u256_shr() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_u256(&mut rng); + let shift: u32 = rng.gen_range(0..255); + assign_bigint(&mut bx, x); + let actual = x >> shift; + bx >>= shift; + check_one(|| hexu(x), || Some(shift.to_string()), actual, &mut bx); + } +} + +#[test] +fn mp_u256_widen_mul() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + let mut by = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x: u128 = rng.gen(); + let y: u128 = rng.gen(); + bx.assign(x); + by.assign(y); + let actual = x.widen_mul(y); + bx *= &by; + check_one(|| format!("{x:#034x}"), || Some(format!("{y:#034x}")), actual, &mut bx); + } +} diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs index 017e9455e40..eae08238e09 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -7,40 +7,39 @@ use core::ops; use super::{DInt, HInt, Int, MinInt}; -const WORD_LO_MASK: u64 = 0x00000000ffffffff; -const WORD_HI_MASK: u64 = 0xffffffff00000000; -const WORD_FULL_MASK: u64 = 0xffffffffffffffff; const U128_LO_MASK: u128 = u64::MAX as u128; -/// A 256-bit unsigned integer represented as 4 64-bit limbs. -/// -/// Each limb is a native-endian number, but the array is little-limb-endian. +/// A 256-bit unsigned integer represented as two 128-bit native-endian limbs. #[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] -pub struct u256(pub [u64; 4]); +pub struct u256 { + pub lo: u128, + pub hi: u128, +} impl u256 { - #[allow(unused)] - pub const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX]); + #[cfg(any(test, feature = "unstable-public-internals"))] + pub const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX }; /// Reinterpret as a signed integer pub fn signed(self) -> i256 { - i256(self.0) + i256 { lo: self.lo, hi: self.hi } } } -/// A 256-bit signed integer represented as 4 64-bit limbs. -/// -/// Each limb is a native-endian number, but the array is little-limb-endian. +/// A 256-bit signed integer represented as two 128-bit native-endian limbs. #[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] -pub struct i256(pub [u64; 4]); +pub struct i256 { + pub lo: u128, + pub hi: u128, +} impl i256 { /// Reinterpret as an unsigned integer - #[cfg(test)] + #[cfg(any(test, feature = "unstable-public-internals"))] pub fn unsigned(self) -> u256 { - u256(self.0) + u256 { lo: self.lo, hi: self.hi } } } @@ -51,10 +50,10 @@ impl MinInt for u256 { const SIGNED: bool = false; const BITS: u32 = 256; - const ZERO: Self = Self([0u64; 4]); - const ONE: Self = Self([1, 0, 0, 0]); - const MIN: Self = Self([0u64; 4]); - const MAX: Self = Self([u64::MAX; 4]); + const ZERO: Self = Self { lo: 0, hi: 0 }; + const ONE: Self = Self { lo: 1, hi: 0 }; + const MIN: Self = Self { lo: 0, hi: 0 }; + const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX }; } impl MinInt for i256 { @@ -64,10 +63,10 @@ impl MinInt for i256 { const SIGNED: bool = false; const BITS: u32 = 256; - const ZERO: Self = Self([0u64; 4]); - const ONE: Self = Self([1, 0, 0, 0]); - const MIN: Self = Self([0, 0, 0, 1 << 63]); - const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX << 1]); + const ZERO: Self = Self { lo: 0, hi: 0 }; + const ONE: Self = Self { lo: 1, hi: 0 }; + const MIN: Self = Self { lo: 0, hi: 1 << 127 }; + const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX << 1 }; } macro_rules! impl_common { @@ -76,10 +75,8 @@ macro_rules! impl_common { type Output = Self; fn bitor(mut self, rhs: Self) -> Self::Output { - self.0[0] |= rhs.0[0]; - self.0[1] |= rhs.0[1]; - self.0[2] |= rhs.0[2]; - self.0[3] |= rhs.0[3]; + self.lo |= rhs.lo; + self.hi |= rhs.hi; self } } @@ -87,8 +84,10 @@ macro_rules! impl_common { impl ops::Not for $ty { type Output = Self; - fn not(self) -> Self::Output { - Self([!self.0[0], !self.0[1], !self.0[2], !self.0[3]]) + fn not(mut self) -> Self::Output { + self.lo = !self.lo; + self.hi = !self.hi; + self } } @@ -105,10 +104,21 @@ macro_rules! impl_common { impl_common!(i256); impl_common!(u256); +impl ops::Add for u256 { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + let (lo, carry) = self.lo.overflowing_add(rhs.lo); + let hi = self.hi.wrapping_add(carry as u128).wrapping_add(rhs.hi); + + Self { lo, hi } + } +} + impl ops::Shr for u256 { type Output = Self; - fn shr(self, rhs: u32) -> Self::Output { + fn shr(mut self, rhs: u32) -> Self::Output { debug_assert!(rhs < Self::BITS, "attempted to shift right with overflow"); if rhs >= Self::BITS { return Self::ZERO; @@ -118,57 +128,28 @@ impl ops::Shr for u256 { return self; } - let mut ret = self; - let byte_shift = rhs / 64; - let bit_shift = rhs % 64; - - for idx in 0..4 { - let base_idx = idx + byte_shift as usize; - - // FIXME(msrv): could be let...else. - let base = match ret.0.get(base_idx) { - Some(v) => v, - None => { - ret.0[idx] = 0; - continue; - } - }; - - let mut new_val = base >> bit_shift; - - if let Some(new) = ret.0.get(base_idx + 1) { - new_val |= new.overflowing_shl(64 - bit_shift).0; - } + if rhs < 128 { + self.lo >>= rhs; + self.lo |= self.hi << (128 - rhs); + } else { + self.lo = self.hi >> (rhs - 128); + } - ret.0[idx] = new_val; + if rhs < 128 { + self.hi >>= rhs; + } else { + self.hi = 0; } - ret + self } } -macro_rules! word { - (1, $val:expr) => { - (($val >> (32 * 3)) & Self::from(WORD_LO_MASK)) as u64 - }; - (2, $val:expr) => { - (($val >> (32 * 2)) & Self::from(WORD_LO_MASK)) as u64 - }; - (3, $val:expr) => { - (($val >> (32 * 1)) & Self::from(WORD_LO_MASK)) as u64 - }; - (4, $val:expr) => { - (($val >> (32 * 0)) & Self::from(WORD_LO_MASK)) as u64 - }; -} - impl HInt for u128 { type D = u256; fn widen(self) -> Self::D { - let w0 = self & u128::from(u64::MAX); - let w1 = (self >> u64::BITS) & u128::from(u64::MAX); - u256([w0 as u64, w1 as u64, 0, 0]) + u256 { lo: self, hi: 0 } } fn zero_widen(self) -> Self::D { @@ -176,57 +157,24 @@ impl HInt for u128 { } fn zero_widen_mul(self, rhs: Self) -> Self::D { - let product11: u64 = word!(1, self) * word!(1, rhs); - let product12: u64 = word!(1, self) * word!(2, rhs); - let product13: u64 = word!(1, self) * word!(3, rhs); - let product14: u64 = word!(1, self) * word!(4, rhs); - let product21: u64 = word!(2, self) * word!(1, rhs); - let product22: u64 = word!(2, self) * word!(2, rhs); - let product23: u64 = word!(2, self) * word!(3, rhs); - let product24: u64 = word!(2, self) * word!(4, rhs); - let product31: u64 = word!(3, self) * word!(1, rhs); - let product32: u64 = word!(3, self) * word!(2, rhs); - let product33: u64 = word!(3, self) * word!(3, rhs); - let product34: u64 = word!(3, self) * word!(4, rhs); - let product41: u64 = word!(4, self) * word!(1, rhs); - let product42: u64 = word!(4, self) * word!(2, rhs); - let product43: u64 = word!(4, self) * word!(3, rhs); - let product44: u64 = word!(4, self) * word!(4, rhs); - - let sum0: u128 = u128::from(product44); - let sum1: u128 = u128::from(product34) + u128::from(product43); - let sum2: u128 = u128::from(product24) + u128::from(product33) + u128::from(product42); - let sum3: u128 = u128::from(product14) - + u128::from(product23) - + u128::from(product32) - + u128::from(product41); - let sum4: u128 = u128::from(product13) + u128::from(product22) + u128::from(product31); - let sum5: u128 = u128::from(product12) + u128::from(product21); - let sum6: u128 = u128::from(product11); - - let r0: u128 = - (sum0 & u128::from(WORD_FULL_MASK)) + ((sum1 & u128::from(WORD_LO_MASK)) << 32); - let r1: u128 = (sum0 >> 64) - + ((sum1 >> 32) & u128::from(WORD_FULL_MASK)) - + (sum2 & u128::from(WORD_FULL_MASK)) - + ((sum3 << 32) & u128::from(WORD_HI_MASK)); - - let (lo, carry) = r0.overflowing_add(r1 << 64); - let hi = (r1 >> 64) - + (sum1 >> 96) - + (sum2 >> 64) - + (sum3 >> 32) - + sum4 - + (sum5 << 32) - + (sum6 << 64) - + u128::from(carry); - - u256([ - (lo & U128_LO_MASK) as u64, - ((lo >> 64) & U128_LO_MASK) as u64, - (hi & U128_LO_MASK) as u64, - ((hi >> 64) & U128_LO_MASK) as u64, - ]) + let l0 = self & U128_LO_MASK; + let l1 = rhs & U128_LO_MASK; + let h0 = self >> 64; + let h1 = rhs >> 64; + + let p_ll: u128 = l0.overflowing_mul(l1).0; + let p_lh: u128 = l0.overflowing_mul(h1).0; + let p_hl: u128 = h0.overflowing_mul(l1).0; + let p_hh: u128 = h0.overflowing_mul(h1).0; + + let s0 = p_hl + (p_ll >> 64); + let s1 = (p_ll & U128_LO_MASK) + (s0 << 64); + let s2 = p_lh + (s1 >> 64); + + let lo = (p_ll & U128_LO_MASK) + (s2 << 64); + let hi = p_hh + (s0 >> 64) + (s2 >> 64); + + u256 { lo, hi } } fn widen_mul(self, rhs: Self) -> Self::D { @@ -244,8 +192,7 @@ impl HInt for i128 { fn widen(self) -> Self::D { let mut ret = self.unsigned().zero_widen().signed(); if self.is_negative() { - ret.0[2] = u64::MAX; - ret.0[3] = u64::MAX; + ret.hi = u128::MAX; } ret } @@ -271,17 +218,11 @@ impl DInt for u256 { type H = u128; fn lo(self) -> Self::H { - let mut tmp = [0u8; 16]; - tmp[..8].copy_from_slice(&self.0[0].to_le_bytes()); - tmp[8..].copy_from_slice(&self.0[1].to_le_bytes()); - u128::from_le_bytes(tmp) + self.lo } fn hi(self) -> Self::H { - let mut tmp = [0u8; 16]; - tmp[..8].copy_from_slice(&self.0[2].to_le_bytes()); - tmp[8..].copy_from_slice(&self.0[3].to_le_bytes()); - u128::from_le_bytes(tmp) + self.hi } } @@ -289,16 +230,10 @@ impl DInt for i256 { type H = i128; fn lo(self) -> Self::H { - let mut tmp = [0u8; 16]; - tmp[..8].copy_from_slice(&self.0[0].to_le_bytes()); - tmp[8..].copy_from_slice(&self.0[1].to_le_bytes()); - i128::from_le_bytes(tmp) + self.lo as i128 } fn hi(self) -> Self::H { - let mut tmp = [0u8; 16]; - tmp[..8].copy_from_slice(&self.0[2].to_le_bytes()); - tmp[8..].copy_from_slice(&self.0[3].to_le_bytes()); - i128::from_le_bytes(tmp) + self.hi as i128 } } diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs index 815a62dfee8..6d06c700a5e 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -9,33 +9,30 @@ const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; /// Print a `u256` as hex since we can't add format implementations fn hexu(v: u256) -> String { - format!("0x{:016x}{:016x}{:016x}{:016x}", v.0[3], v.0[2], v.0[1], v.0[0]) + format!("0x{:032x}{:032x}", v.hi, v.lo) } #[test] fn widen_u128() { - assert_eq!(u128::MAX.widen(), u256([u64::MAX, u64::MAX, 0, 0])); - assert_eq!(LOHI_SPLIT.widen(), u256([u64::MAX, 0xaaaaaaaaaaaaaaaa, 0, 0])); + assert_eq!(u128::MAX.widen(), u256 { lo: u128::MAX, hi: 0 }); + assert_eq!(LOHI_SPLIT.widen(), u256 { lo: LOHI_SPLIT, hi: 0 }); } #[test] fn widen_i128() { assert_eq!((-1i128).widen(), u256::MAX.signed()); - assert_eq!( - (LOHI_SPLIT as i128).widen(), - i256([u64::MAX, 0xaaaaaaaaaaaaaaaa, u64::MAX, u64::MAX]) - ); + assert_eq!((LOHI_SPLIT as i128).widen(), i256 { lo: LOHI_SPLIT, hi: u128::MAX }); assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); } #[test] fn widen_mul_u128() { let tests = [ - (u128::MAX / 2, 2_u128, u256([u64::MAX - 1, u64::MAX, 0, 0])), - (u128::MAX, 2_u128, u256([u64::MAX - 1, u64::MAX, 1, 0])), - (u128::MAX, u128::MAX, u256([1, 0, u64::MAX - 1, u64::MAX])), - (u128::MIN, u128::MIN, u256::ZERO), - (1234, 0, u256::ZERO), + (u128::MAX / 2, 2_u128, u256 { lo: u128::MAX - 1, hi: 0 }), + (u128::MAX, 2_u128, u256 { lo: u128::MAX - 1, hi: 1 }), + (u128::MAX, u128::MAX, u256 { lo: 1, hi: u128::MAX - 1 }), + (0, 0, u256::ZERO), + (1234u128, 0, u256::ZERO), (0, 1234, u256::ZERO), ]; @@ -50,20 +47,27 @@ fn widen_mul_u128() { } for (i, a, b, exp, res) in &errors { - eprintln!("FAILURE ({i}): {a:#034x} * {b:#034x} = {} got {}", hexu(*exp), hexu(*res)); + eprintln!( + "\ + FAILURE ({i}): {a:#034x} * {b:#034x}\n\ + expected: {}\n\ + got: {}\ + ", + hexu(*exp), + hexu(*res) + ); } assert!(errors.is_empty()); } #[test] -fn not_u128() { +fn not_u256() { assert_eq!(!u256::ZERO, u256::MAX); } #[test] -fn shr_u128() { +fn shr_u256() { let only_low = [1, u16::MAX.into(), u32::MAX.into(), u64::MAX.into(), u128::MAX]; - let mut errors = Vec::new(); for a in only_low { @@ -80,20 +84,24 @@ fn shr_u128() { } let check = [ - (u256::MAX, 1, u256([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 1])), - (u256::MAX, 5, u256([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 5])), - (u256::MAX, 63, u256([u64::MAX, u64::MAX, u64::MAX, 1])), - (u256::MAX, 64, u256([u64::MAX, u64::MAX, u64::MAX, 0])), - (u256::MAX, 65, u256([u64::MAX, u64::MAX, u64::MAX >> 1, 0])), - (u256::MAX, 127, u256([u64::MAX, u64::MAX, 1, 0])), - (u256::MAX, 128, u256([u64::MAX, u64::MAX, 0, 0])), - (u256::MAX, 129, u256([u64::MAX, u64::MAX >> 1, 0, 0])), - (u256::MAX, 191, u256([u64::MAX, 1, 0, 0])), - (u256::MAX, 192, u256([u64::MAX, 0, 0, 0])), - (u256::MAX, 193, u256([u64::MAX >> 1, 0, 0, 0])), - (u256::MAX, 191, u256([u64::MAX, 1, 0, 0])), - (u256::MAX, 254, u256([0b11, 0, 0, 0])), - (u256::MAX, 255, u256([1, 0, 0, 0])), + (u256::MAX, 1, u256 { lo: u128::MAX, hi: u128::MAX >> 1 }), + (u256::MAX, 5, u256 { lo: u128::MAX, hi: u128::MAX >> 5 }), + (u256::MAX, 63, u256 { lo: u128::MAX, hi: u64::MAX as u128 | (1 << 64) }), + (u256::MAX, 64, u256 { lo: u128::MAX, hi: u64::MAX as u128 }), + (u256::MAX, 65, u256 { lo: u128::MAX, hi: (u64::MAX >> 1) as u128 }), + (u256::MAX, 127, u256 { lo: u128::MAX, hi: 1 }), + (u256::MAX, 128, u256 { lo: u128::MAX, hi: 0 }), + (u256::MAX, 129, u256 { lo: u128::MAX >> 1, hi: 0 }), + (u256::MAX, 191, u256 { lo: u64::MAX as u128 | 1 << 64, hi: 0 }), + (u256::MAX, 192, u256 { lo: u64::MAX as u128, hi: 0 }), + (u256::MAX, 193, u256 { lo: u64::MAX as u128 >> 1, hi: 0 }), + (u256::MAX, 254, u256 { lo: 0b11, hi: 0 }), + (u256::MAX, 255, u256 { lo: 1, hi: 0 }), + ( + u256 { hi: LOHI_SPLIT, lo: 0 }, + 64, + u256 { lo: 0xffffffffffffffff0000000000000000, hi: 0xaaaaaaaaaaaaaaaa }, + ), ]; for (input, shift, expected) in check { @@ -104,7 +112,16 @@ fn shr_u128() { } for (a, b, res, expected) in &errors { - eprintln!("FAILURE: {} >> {b} = {} got {}", hexu(*a), hexu(*expected), hexu(*res),); + eprintln!( + "\ + FAILURE: {} >> {b}\n\ + expected: {}\n\ + got: {}\ + ", + hexu(*a), + hexu(*expected), + hexu(*res) + ); } assert!(errors.is_empty()); } -- cgit 1.4.1-3-g733a5 From 35f5731d62049ab8dfb3686bd0328ee796e9f8c5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 08:17:57 +0000 Subject: Introduce a trait constant for the minimum positive normal value --- library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs | 1 + library/compiler-builtins/libm/src/math/support/float_traits.rs | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index 5dce9be1891..56ea0b72995 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -32,6 +32,7 @@ impl Float for f8 { const INFINITY: Self = Self(0b0_1111_000); const NEG_INFINITY: Self = Self(0b1_1111_000); const NAN: Self = Self(0b0_1111_100); + const MIN_POSITIVE_NORMAL: Self = Self(1 << Self::SIG_BITS); // FIXME: incorrect values const EPSILON: Self = Self::ZERO; const PI: Self = Self::ZERO; diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index ee83c793da3..42ce3148464 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -41,6 +41,8 @@ pub trait Float: const NEG_PI: Self; const FRAC_PI_2: Self; + const MIN_POSITIVE_NORMAL: Self; + /// The bitwidth of the float type const BITS: u32; @@ -200,6 +202,9 @@ macro_rules! float_impl { const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS)); const EPSILON: Self = <$ty>::EPSILON; + // Exponent is a 1 in the LSB + const MIN_POSITIVE_NORMAL: Self = $from_bits(1 << Self::SIG_BITS); + const PI: Self = core::$ty::consts::PI; const NEG_PI: Self = -Self::PI; const FRAC_PI_2: Self = core::$ty::consts::FRAC_PI_2; @@ -358,6 +363,7 @@ mod tests { // results for zero and subnormals. assert_eq!(f16::ZERO.exp_unbiased(), -15); assert_eq!(f16::from_bits(0x1).exp_unbiased(), -15); + assert_eq!(f16::MIN_POSITIVE, f16::MIN_POSITIVE_NORMAL); // `from_parts` assert_biteq!(f16::from_parts(true, f16::EXP_BIAS, 0), -1.0f16); @@ -383,6 +389,7 @@ mod tests { // results for zero and subnormals. assert_eq!(f32::ZERO.exp_unbiased(), -127); assert_eq!(f32::from_bits(0x1).exp_unbiased(), -127); + assert_eq!(f32::MIN_POSITIVE, f32::MIN_POSITIVE_NORMAL); // `from_parts` assert_biteq!(f32::from_parts(true, f32::EXP_BIAS, 0), -1.0f32); @@ -409,6 +416,7 @@ mod tests { // results for zero and subnormals. assert_eq!(f64::ZERO.exp_unbiased(), -1023); assert_eq!(f64::from_bits(0x1).exp_unbiased(), -1023); + assert_eq!(f64::MIN_POSITIVE, f64::MIN_POSITIVE_NORMAL); // `from_parts` assert_biteq!(f64::from_parts(true, f64::EXP_BIAS, 0), -1.0f64); @@ -436,6 +444,7 @@ mod tests { // results for zero and subnormals. assert_eq!(f128::ZERO.exp_unbiased(), -16383); assert_eq!(f128::from_bits(0x1).exp_unbiased(), -16383); + assert_eq!(f128::MIN_POSITIVE, f128::MIN_POSITIVE_NORMAL); // `from_parts` assert_biteq!(f128::from_parts(true, f128::EXP_BIAS, 0), -1.0f128); -- cgit 1.4.1-3-g733a5 From 105cd79578c5ad4326d83afa6ff1c962745d8d8a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 09:17:54 +0000 Subject: Migrate away from nonfunctional `fenv` stubs Many routines have some form of handling for rounding mode and floating point exceptions, which are implemented via a combination of stubs and `force_eval!` use. This is suboptimal, however, because: 1. Rust does not interact with the floating point environment, so most of this code does nothing. 2. The parts of the code that are not dead are not testable. 3. `force_eval!` blocks optimizations, which is unnecessary because we do not rely on its side effects. We cannot ensure correct rounding and exception handling in all cases without some form of arithmetic operations that are aware of this behavior. However, the cases where rounding mode is explicitly handled or exceptions are explicitly raised are testable. Make this possible here for functions that depend on `math::fenv` by moving the implementation to a nonpublic function that takes a `Round` and returns a `Status`. Link: https://github.com/rust-lang/libm/issues/480 --- library/compiler-builtins/libm/src/math/cbrt.rs | 25 ++-- library/compiler-builtins/libm/src/math/fenv.rs | 49 -------- .../compiler-builtins/libm/src/math/generic/fma.rs | 133 +++++++++++---------- .../libm/src/math/generic/sqrt.rs | 48 ++++++-- library/compiler-builtins/libm/src/math/mod.rs | 1 - .../compiler-builtins/libm/src/math/support/env.rs | 118 ++++++++++++++++++ .../compiler-builtins/libm/src/math/support/mod.rs | 7 +- 7 files changed, 240 insertions(+), 141 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/fenv.rs create mode 100644 library/compiler-builtins/libm/src/math/support/env.rs diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index fbf81f77d2e..8560d37abf3 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -5,12 +5,15 @@ */ use super::Float; -use super::fenv::Rounding; -use super::support::cold_path; +use super::support::{FpResult, Round, cold_path}; /// Compute the cube root of the argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrt(x: f64) -> f64 { + cbrt_round(x, Round::Nearest).val +} + +pub fn cbrt_round(x: f64, round: Round) -> FpResult { const ESCALE: [f64; 3] = [ 1.0, hf64!("0x1.428a2f98d728bp+0"), /* 2^(1/3) */ @@ -33,8 +36,6 @@ pub fn cbrt(x: f64) -> f64 { let off = [hf64!("0x1p-53"), 0.0, 0.0, 0.0]; - let rm = Rounding::get(); - /* rm=0 for rounding to nearest, and other values for directed roundings */ let hx: u64 = x.to_bits(); let mut mant: u64 = hx & f64::SIG_MASK; @@ -51,7 +52,7 @@ pub fn cbrt(x: f64) -> f64 { to that for x a signaling NaN, it correctly triggers the invalid exception. */ if e == f64::EXP_SAT || ix == 0 { - return x + x; + return FpResult::ok(x + x); } let nz = ix.leading_zeros() - 11; /* subnormal */ @@ -124,8 +125,8 @@ pub fn cbrt(x: f64) -> f64 { * from ulp(1); * for rounding to nearest, ady0 is tiny when dy is near from 1/2 ulp(1), * or from 3/2 ulp(1). */ - let mut ady0: f64 = (ady - off[rm as usize]).abs(); - let mut ady1: f64 = (ady - (hf64!("0x1p-52") + off[rm as usize])).abs(); + let mut ady0: f64 = (ady - off[round as usize]).abs(); + let mut ady1: f64 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs(); if ady0 < hf64!("0x1p-75") || ady1 < hf64!("0x1p-75") { cold_path(); @@ -140,8 +141,8 @@ pub fn cbrt(x: f64) -> f64 { dy = (y1 - y) - dy; y1 = y; ady = dy.abs(); - ady0 = (ady - off[rm as usize]).abs(); - ady1 = (ady - (hf64!("0x1p-52") + off[rm as usize])).abs(); + ady0 = (ady - off[round as usize]).abs(); + ady1 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs(); if ady0 < hf64!("0x1p-98") || ady1 < hf64!("0x1p-98") { cold_path(); @@ -157,7 +158,7 @@ pub fn cbrt(x: f64) -> f64 { y1 = hf64!("0x1.de87aa837820fp+0").copysign(zz); } - if rm != Rounding::Nearest { + if round != Round::Nearest { let wlist = [ (hf64!("0x1.3a9ccd7f022dbp+0"), hf64!("0x1.1236160ba9b93p+0")), // ~ 0x1.1236160ba9b930000000000001e7e8fap+0 (hf64!("0x1.7845d2faac6fep+0"), hf64!("0x1.23115e657e49cp+0")), // ~ 0x1.23115e657e49c0000000000001d7a799p+0 @@ -170,7 +171,7 @@ pub fn cbrt(x: f64) -> f64 { for (a, b) in wlist { if azz == a { - let tmp = if rm as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 }; + let tmp = if round as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 }; y1 = (b + tmp).copysign(zz); } } @@ -194,7 +195,7 @@ pub fn cbrt(x: f64) -> f64 { } } - f64::from_bits(cvt3) + FpResult::ok(f64::from_bits(cvt3)) } fn fmaf64(x: f64, y: f64, z: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/fenv.rs b/library/compiler-builtins/libm/src/math/fenv.rs deleted file mode 100644 index 328c9f3467c..00000000000 --- a/library/compiler-builtins/libm/src/math/fenv.rs +++ /dev/null @@ -1,49 +0,0 @@ -// src: musl/src/fenv/fenv.c -/* Dummy functions for archs lacking fenv implementation */ - -pub(crate) const FE_UNDERFLOW: i32 = 0; -pub(crate) const FE_INEXACT: i32 = 0; - -pub(crate) const FE_TONEAREST: i32 = 0; -pub(crate) const FE_DOWNWARD: i32 = 1; -pub(crate) const FE_UPWARD: i32 = 2; -pub(crate) const FE_TOWARDZERO: i32 = 3; - -#[inline] -pub(crate) fn feclearexcept(_mask: i32) -> i32 { - 0 -} - -#[inline] -pub(crate) fn feraiseexcept(_mask: i32) -> i32 { - 0 -} - -#[inline] -pub(crate) fn fetestexcept(_mask: i32) -> i32 { - 0 -} - -#[inline] -pub(crate) fn fegetround() -> i32 { - FE_TONEAREST -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub(crate) enum Rounding { - Nearest = FE_TONEAREST as isize, - Downward = FE_DOWNWARD as isize, - Upward = FE_UPWARD as isize, - ToZero = FE_TOWARDZERO as isize, -} - -impl Rounding { - pub(crate) fn get() -> Self { - match fegetround() { - x if x == FE_DOWNWARD => Self::Downward, - x if x == FE_UPWARD => Self::Upward, - x if x == FE_TOWARDZERO => Self::ToZero, - _ => Self::Nearest, - } - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs index a40d7aaaf5e..821aee09028 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -1,12 +1,7 @@ /* SPDX-License-Identifier: MIT */ /* origin: musl src/math/{fma,fmaf}.c. Ported to generic Rust algorithm in 2025, TG. */ -use core::{f32, f64}; - -use super::super::fenv::{ - FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, feclearexcept, fegetround, feraiseexcept, fetestexcept, -}; -use super::super::support::{DInt, HInt, IntTy}; +use super::super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; use super::super::{CastFrom, CastInto, DFloat, Float, HFloat, Int, MinInt}; /// Fused multiply-add that works when there is not a larger float size available. Currently this @@ -14,7 +9,18 @@ use super::super::{CastFrom, CastInto, DFloat, Float, HFloat, Int, MinInt}; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fma(x: F, y: F, z: F) -> F where - F: Float + FmaHelper, + F: Float, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, +{ + fma_round(x, y, z, Round::Nearest).val +} + +pub fn fma_round(x: F, y: F, z: F, _round: Round) -> FpResult +where + F: Float, F: CastFrom, F: CastFrom, F::Int: HInt, @@ -30,16 +36,16 @@ where if nx.is_zero_nan_inf() || ny.is_zero_nan_inf() { // Value will overflow, defer to non-fused operations. - return x * y + z; + return FpResult::ok(x * y + z); } if nz.is_zero_nan_inf() { if nz.is_zero() { // Empty add component means we only need to multiply. - return x * y; + return FpResult::ok(x * y); } // `z` is NaN or infinity, which sets the result. - return z; + return FpResult::ok(z); } // multiply: r = x * y @@ -147,7 +153,7 @@ where } } else { // exact +/- 0.0 - return x * y + z; + return FpResult::ok(x * y + z); } e -= d; @@ -168,6 +174,8 @@ where // Unbiased exponent for the maximum value of `r` let max_pow = F::BITS - 1 + F::EXP_BIAS; + let mut status = Status::OK; + if e < -(max_pow as i32 - 2) { // Result is subnormal before rounding if e == -(max_pow as i32 - 1) { @@ -178,7 +186,9 @@ where if r == c { // Min normal after rounding, - return r.raise_underflow_as_min_positive(); + status.set_underflow(true); + r = F::MIN_POSITIVE_NORMAL.copysign(r); + return FpResult::new(r, status); } if (rhi << (F::SIG_BITS + 1)) != zero { @@ -195,7 +205,7 @@ where // Remove the top bit r = F::cast_from(2i8) * r - c; - r += r.raise_underflow_ret_zero(); + status.set_underflow(true); } } else { // Only round once when scaled @@ -212,12 +222,22 @@ where } // Use our exponent to scale the final value. - super::scalbn(r, e) + FpResult::new(super::scalbn(r, e), status) } /// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, /// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. pub fn fma_wide(x: F, y: F, z: F) -> F +where + F: Float + HFloat, + B: Float + DFloat, + B::Int: CastInto, + i32: CastFrom, +{ + fma_wide_round(x, y, z, Round::Nearest).val +} + +pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult where F: Float + HFloat, B: Float + DFloat, @@ -244,24 +264,26 @@ where // Or the result is exact || (result - xy == zb && result - zb == xy) // Or the mode is something other than round to nearest - || fegetround() != FE_TONEAREST + || round != Round::Nearest { let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; - if (min_inexact_exp..max_inexact_exp).contains(&re) && fetestexcept(FE_INEXACT) != 0 { - feclearexcept(FE_INEXACT); - // prevent `xy + vz` from being CSE'd with `xy + z` above - let vz: F = force_eval!(z); - result = xy + vz.widen(); - if fetestexcept(FE_INEXACT) != 0 { - feraiseexcept(FE_UNDERFLOW); + let mut status = Status::OK; + + if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() { + // This branch is never hit; requires previous operations to set a status + status.set_inexact(false); + + result = xy + z.widen(); + if status.inexact() { + status.set_underflow(true); } else { - feraiseexcept(FE_INEXACT); + status.set_inexact(true); } } - return result.narrow(); + return FpResult { val: result.narrow(), status }; } let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; @@ -272,7 +294,7 @@ where ui -= one; } - B::from_bits(ui).narrow() + FpResult::ok(B::from_bits(ui).narrow()) } /// Representation of `F` that has handled subnormals. @@ -337,49 +359,13 @@ impl Norm { } } -/// Type-specific helpers that are not needed outside of fma. -pub trait FmaHelper { - /// Raise underflow and return the minimum positive normal value with the sign of `self`. - fn raise_underflow_as_min_positive(self) -> Self; - /// Raise underflow and return zero. - fn raise_underflow_ret_zero(self) -> Self; -} - -impl FmaHelper for f64 { - fn raise_underflow_as_min_positive(self) -> Self { - /* min normal after rounding, underflow depends - * on arch behaviour which can be imitated by - * a double to float conversion */ - let fltmin: f32 = (hf64!("0x0.ffffff8p-63") * f32::MIN_POSITIVE as f64 * self) as f32; - f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64 - } - - fn raise_underflow_ret_zero(self) -> Self { - /* raise underflow portably, such that it - * cannot be optimized away */ - let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * self; - (tiny * tiny) * (self - self) - } -} - -#[cfg(f128_enabled)] -impl FmaHelper for f128 { - fn raise_underflow_as_min_positive(self) -> Self { - f128::MIN_POSITIVE.copysign(self) - } - - fn raise_underflow_ret_zero(self) -> Self { - f128::ZERO - } -} - #[cfg(test)] mod tests { use super::*; fn spec_test() where - F: Float + FmaHelper, + F: Float, F: CastFrom, F: CastFrom, F::Int: HInt, @@ -401,6 +387,29 @@ mod tests { #[test] fn spec_test_f64() { spec_test::(); + + let expect_underflow = [ + ( + hf64!("0x1.0p-1070"), + hf64!("0x1.0p-1070"), + hf64!("0x1.ffffffffffffp-1023"), + hf64!("0x0.ffffffffffff8p-1022"), + ), + ( + // FIXME: we raise underflow but this should only be inexact (based on C and + // `rustc_apfloat`). + hf64!("0x1.0p-1070"), + hf64!("0x1.0p-1070"), + hf64!("-0x1.0p-1022"), + hf64!("-0x1.0p-1022"), + ), + ]; + + for (x, y, z, res) in expect_underflow { + let FpResult { val, status } = fma_round(x, y, z, Round::Nearest); + assert_biteq!(val, res); + assert_eq!(status, Status::UNDERFLOW); + } } #[test] diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index 90d6c01e917..fdd612493b7 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -41,10 +41,23 @@ //! Goldschmidt has the advantage over Newton-Raphson that `sqrt(x)` and `1/sqrt(x)` are //! computed at the same time, i.e. there is no need to calculate `1/sqrt(x)` and invert it. -use super::super::support::{IntTy, cold_path, raise_invalid}; +use super::super::support::{FpResult, IntTy, Round, Status, cold_path}; use super::super::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; pub fn sqrt(x: F) -> F +where + F: Float + SqrtHelper, + F::Int: HInt, + F::Int: From, + F::Int: From, + F::Int: CastInto, + F::Int: CastInto, + u32: CastInto, +{ + sqrt_round(x, Round::Nearest).val +} + +pub fn sqrt_round(x: F, _round: Round) -> FpResult where F: Float + SqrtHelper, F::Int: HInt, @@ -78,17 +91,17 @@ where // +/-0 if ix << 1 == zero { - return x; + return FpResult::ok(x); } // Positive infinity if ix == F::EXP_MASK { - return x; + return FpResult::ok(x); } // NaN or negative if ix > F::EXP_MASK { - return raise_invalid(x); + return FpResult::new(F::NAN, Status::INVALID); } // Normalize subnormals by multiplying by 1.0 << SIG_BITS (e.g. 0x1p52 for doubles). @@ -215,7 +228,7 @@ where y = y + t; } - y + FpResult::ok(y) } /// Multiply at the wider integer size, returning the high half. @@ -329,7 +342,7 @@ impl SqrtHelper for f128 { /// A U0.16 representation of `1/sqrt(x)`. /// -// / The index is a 7-bit number consisting of a single exponent bit and 6 bits of significand. +/// The index is a 7-bit number consisting of a single exponent bit and 6 bits of significand. #[rustfmt::skip] static RSQRT_TAB: [u16; 128] = [ 0xb451, 0xb2f0, 0xb196, 0xb044, 0xaef9, 0xadb6, 0xac79, 0xab43, @@ -354,7 +367,7 @@ static RSQRT_TAB: [u16; 128] = [ mod tests { use super::*; - /// Test against edge cases from https://en.cppreference.com/w/cpp/numeric/math/sqrt + /// Test behavior specified in IEEE 754 `squareRoot`. fn spec_test() where F: Float + SqrtHelper, @@ -365,11 +378,22 @@ mod tests { F::Int: CastInto, u32: CastInto, { - // Not Asserted: FE_INVALID exception is raised if argument is negative. - assert!(sqrt(F::NEG_ONE).is_nan()); - assert!(sqrt(F::NAN).is_nan()); - for f in [F::ZERO, F::NEG_ZERO, F::INFINITY].iter().copied() { - assert_biteq!(sqrt(f), f); + // Values that should return a NaN and raise invalid + let nan = [F::NEG_INFINITY, F::NEG_ONE, F::NAN, F::MIN]; + + // Values that return unaltered + let roundtrip = [F::ZERO, F::NEG_ZERO, F::INFINITY]; + + for x in nan { + let FpResult { val, status } = sqrt_round(x, Round::Nearest); + assert!(val.is_nan()); + assert!(status == Status::INVALID); + } + + for x in roundtrip { + let FpResult { val, status } = sqrt_round(x, Round::Nearest); + assert_biteq!(val, x); + assert!(status == Status::OK); } } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e32045021da..ae4a278f287 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -94,7 +94,6 @@ cfg_if! { // Private modules mod arch; mod expo2; -mod fenv; mod k_cos; mod k_cosf; mod k_expo2; diff --git a/library/compiler-builtins/libm/src/math/support/env.rs b/library/compiler-builtins/libm/src/math/support/env.rs new file mode 100644 index 00000000000..7244381dacc --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/env.rs @@ -0,0 +1,118 @@ +//! Support for rounding directions and status flags as specified by IEEE 754. +//! +//! Rust does not support the floating point environment so rounding mode is passed as an argument +//! and status flags are returned as part of the result. There is currently not much support for +//! this; most existing ports from musl use a form of `force_eval!` to raise exceptions, but this +//! has no side effects in Rust. Further, correct behavior relies on elementary operations making +//! use of the correct rounding and raising relevant exceptions, which is not the case for Rust. +//! +//! This module exists so no functionality is lost when porting algorithms that respect floating +//! point environment, and so that some functionality may be tested (that which does not rely on +//! side effects from elementary operations). Full support would require wrappers around basic +//! operations, but there is no plan to add this at the current time. + +/// A value combined with a floating point status. +pub struct FpResult { + pub val: T, + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub status: Status, +} + +impl FpResult { + pub fn new(val: T, status: Status) -> Self { + Self { val, status } + } + + /// Return `val` with `Status::OK`. + pub fn ok(val: T) -> Self { + Self { val, status: Status::OK } + } +} + +/// IEEE 754 rounding mode, excluding the optional `roundTiesToAway` version of nearest. +/// +/// Integer representation comes from what CORE-MATH uses for indexing. +#[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Round { + /// IEEE 754 nearest, `roundTiesToEven`. + Nearest = 0, + /// IEEE 754 `roundTowardNegative`. + Negative = 1, + /// IEEE 754 `roundTowardPositive`. + Positive = 2, + /// IEEE 754 `roundTowardZero`. + Zero = 3, +} + +/// IEEE 754 exception status flags. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Status(u8); + +impl Status { + /// Default status indicating no errors. + pub const OK: Self = Self(0); + + /// No definable result. + /// + /// Includes: + /// - Any ops on sNaN, with a few exceptions. + /// - `0 * inf`, `inf * 0`. + /// - `fma(0, inf, c)` or `fma(inf, 0, c)`, possibly excluding `c = qNaN`. + /// - `+inf + -inf` and similar (includes subtraction and fma). + /// - `0.0 / 0.0`, `inf / inf` + /// - `remainder(x, y)` if `y == 0.0` or `x == inf`, and neither is NaN. + /// - `sqrt(x)` with `x < 0.0`. + pub const INVALID: Self = Self(1); + + /// Division by zero. + /// + /// The default result for division is +/-inf based on operand sign. For `logB`, the default + /// result is -inf. + /// `x / y` when `x != 0.0` and `y == 0.0`, + + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub const DIVIDE_BY_ZERO: Self = Self(1 << 2); + + /// The result exceeds the maximum finite value. + /// + /// The default result depends on rounding mode. `Nearest*` rounds to +/- infinity, sign based + /// on the intermediate result. `Zero` rounds to the signed maximum finite. `Positive` and + /// `Negative` round to signed maximum finite in one direction, signed infinity in the other. + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub const OVERFLOW: Self = Self(1 << 3); + + /// The result is subnormal and lost precision. + pub const UNDERFLOW: Self = Self(1 << 4); + + /// The finite-precision result does not match that of infinite precision, and the reason + /// is not represented by one of the other flags. + pub const INEXACT: Self = Self(1 << 5); + + /// True if `UNDERFLOW` is set. + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub fn underflow(self) -> bool { + self.0 & Self::UNDERFLOW.0 != 0 + } + + pub fn set_underflow(&mut self, val: bool) { + self.set_flag(val, Self::UNDERFLOW); + } + + /// True if `INEXACT` is set. + pub fn inexact(self) -> bool { + self.0 & Self::INEXACT.0 != 0 + } + + pub fn set_inexact(&mut self, val: bool) { + self.set_flag(val, Self::INEXACT); + } + + fn set_flag(&mut self, val: bool, mask: Self) { + if val { + self.0 |= mask.0; + } else { + self.0 &= !mask.0; + } + } +} diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 28e9fd4132f..ee3f2bbdf02 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -1,12 +1,14 @@ #[macro_use] pub mod macros; mod big; +mod env; mod float_traits; pub mod hex_float; mod int_traits; #[allow(unused_imports)] pub use big::{i256, u256}; +pub use env::{FpResult, Round, Status}; #[allow(unused_imports)] pub use float_traits::{DFloat, Float, HFloat, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; @@ -25,8 +27,3 @@ pub fn cold_path() { #[cfg(intrinsics_enabled)] core::intrinsics::cold_path(); } - -/// Return `x`, first raising `FE_INVALID`. -pub fn raise_invalid(x: F) -> F { - (x - x) / (x - x) -} -- cgit 1.4.1-3-g733a5 From e94e9873999afed5948594569f049f20ebddd495 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 12:01:16 +0000 Subject: Eliminate the use of `force_eval!` in `ceil`, `floor`, and `trunc` --- .../libm/src/math/generic/ceil.rs | 91 ++++++++++++++++++---- .../libm/src/math/generic/floor.rs | 77 ++++++++++++++---- .../libm/src/math/generic/trunc.rs | 89 +++++++++++++++++++-- 3 files changed, 220 insertions(+), 37 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs index 971a4d3d8c5..bf7e1d8e210 100644 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -7,9 +7,14 @@ //! performance seems to be better (based on icount) and it does not seem to experience rounding //! errors on i386. +use super::super::support::{FpResult, Status}; use super::super::{Float, Int, IntTy, MinInt}; pub fn ceil(x: F) -> F { + ceil_status(x).val +} + +pub fn ceil_status(x: F) -> FpResult { let zero = IntTy::::ZERO; let mut ix = x.to_bits(); @@ -17,20 +22,20 @@ pub fn ceil(x: F) -> F { // If the represented value has no fractional part, no truncation is needed. if e >= F::SIG_BITS as i32 { - return x; + return FpResult::ok(x); } - if e >= 0 { + let status; + let res = if e >= 0 { // |x| >= 1.0 - let m = F::SIG_MASK >> e.unsigned(); if (ix & m) == zero { // Portion to be masked is already zero; no adjustment needed. - return x; + return FpResult::ok(x); } // Otherwise, raise an inexact exception. - force_eval!(x + F::MAX); + status = Status::INEXACT; if x.is_sign_positive() { ix += m; @@ -40,7 +45,11 @@ pub fn ceil(x: F) -> F { F::from_bits(ix) } else { // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). - force_eval!(x + F::MAX); + if ix & F::SIG_MASK == F::Int::ZERO { + status = Status::OK; + } else { + status = Status::INEXACT; + } if x.is_sign_negative() { // -1.0 < x <= -0.0; rounding up goes toward -0.0. @@ -52,18 +61,30 @@ pub fn ceil(x: F) -> F { // +0.0 remains unchanged x } - } + }; + + FpResult::new(res, status) } #[cfg(test)] mod tests { use super::*; + use crate::support::Hexf; /// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil - fn spec_test() { - // Not Asserted: that the current rounding mode has no effect. - for f in [F::ZERO, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY].iter().copied() { - assert_biteq!(ceil(f), f); + fn spec_test(cases: &[(F, F, Status)]) { + let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + + for x in roundtrip { + let FpResult { val, status } = ceil_status(x); + assert_biteq!(val, x, "{}", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = ceil_status(x); + assert_biteq!(val, res, "{}", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); } } @@ -72,7 +93,17 @@ mod tests { #[test] #[cfg(f16_enabled)] fn spec_tests_f16() { - spec_test::(); + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 2.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); } #[test] @@ -83,7 +114,17 @@ mod tests { #[test] fn spec_tests_f32() { - spec_test::(); + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 2.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); } #[test] @@ -94,12 +135,32 @@ mod tests { #[test] fn spec_tests_f64() { - spec_test::(); + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 2.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); } #[test] #[cfg(f128_enabled)] fn spec_tests_f128() { - spec_test::(); + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 2.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); } } diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs index 6754c08f870..7799551644f 100644 --- a/library/compiler-builtins/libm/src/math/generic/floor.rs +++ b/library/compiler-builtins/libm/src/math/generic/floor.rs @@ -7,9 +7,14 @@ //! performance seems to be better (based on icount) and it does not seem to experience rounding //! errors on i386. +use super::super::support::{FpResult, Status}; use super::super::{Float, Int, IntTy, MinInt}; pub fn floor(x: F) -> F { + floor_status(x).val +} + +pub fn floor_status(x: F) -> FpResult { let zero = IntTy::::ZERO; let mut ix = x.to_bits(); @@ -17,20 +22,20 @@ pub fn floor(x: F) -> F { // If the represented value has no fractional part, no truncation is needed. if e >= F::SIG_BITS as i32 { - return x; + return FpResult::ok(x); } - if e >= 0 { + let status; + let res = if e >= 0 { // |x| >= 1.0 - let m = F::SIG_MASK >> e.unsigned(); if ix & m == zero { // Portion to be masked is already zero; no adjustment needed. - return x; + return FpResult::ok(x); } // Otherwise, raise an inexact exception. - force_eval!(x + F::MAX); + status = Status::INEXACT; if x.is_sign_negative() { ix += m; @@ -39,8 +44,12 @@ pub fn floor(x: F) -> F { ix &= !m; F::from_bits(ix) } else { - // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). - force_eval!(x + F::MAX); + // |x| < 1.0, raise an inexact exception since truncation will happen. + if ix & F::SIG_MASK == F::Int::ZERO { + status = Status::OK; + } else { + status = Status::INEXACT; + } if x.is_sign_positive() { // 0.0 <= x < 1.0; rounding down goes toward +0.0. @@ -52,27 +61,40 @@ pub fn floor(x: F) -> F { // -0.0 remains unchanged x } - } + }; + + FpResult::new(res, status) } #[cfg(test)] mod tests { use super::*; + use crate::support::Hexf; /// Test against https://en.cppreference.com/w/cpp/numeric/math/floor - fn spec_test() { - // Not Asserted: that the current rounding mode has no effect. - for f in [F::ZERO, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY].iter().copied() { - assert_biteq!(floor(f), f); + fn spec_test(cases: &[(F, F, Status)]) { + let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + + for x in roundtrip { + let FpResult { val, status } = floor_status(x); + assert_biteq!(val, x, "{}", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = floor_status(x); + assert_biteq!(val, res, "{}", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); } } - /* Skipping f16 / f128 "sanity_check"s due to rejected literal lexing at MSRV */ + /* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */ #[test] #[cfg(f16_enabled)] fn spec_tests_f16() { - spec_test::(); + let cases = []; + spec_test::(&cases); } #[test] @@ -84,7 +106,17 @@ mod tests { #[test] fn spec_tests_f32() { - spec_test::(); + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -1.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -1.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -2.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -2.0, Status::INEXACT), + ]; + spec_test::(&cases); } #[test] @@ -95,12 +127,23 @@ mod tests { #[test] fn spec_tests_f64() { - spec_test::(); + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -1.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -1.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -2.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -2.0, Status::INEXACT), + ]; + spec_test::(&cases); } #[test] #[cfg(f128_enabled)] fn spec_tests_f128() { - spec_test::(); + let cases = []; + spec_test::(&cases); } } diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs index ca5f1bdd627..0fb3fa5ad3b 100644 --- a/library/compiler-builtins/libm/src/math/generic/trunc.rs +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -1,15 +1,20 @@ /* SPDX-License-Identifier: MIT * origin: musl src/math/trunc.c */ +use super::super::support::{FpResult, Status}; use super::super::{Float, Int, IntTy, MinInt}; pub fn trunc(x: F) -> F { + trunc_status(x).val +} + +pub fn trunc_status(x: F) -> FpResult { let mut xi: F::Int = x.to_bits(); let e: i32 = x.exp_unbiased(); // C1: The represented value has no fractional part, so no truncation is needed if e >= F::SIG_BITS as i32 { - return x; + return FpResult::ok(x); } let mask = if e < 0 { @@ -23,22 +28,68 @@ pub fn trunc(x: F) -> F { // C4: If the to-be-masked-out portion is already zero, we have an exact result if (xi & !mask) == IntTy::::ZERO { - return x; + return FpResult::ok(x); } // C5: Otherwise the result is inexact and we will truncate. Raise `FE_INEXACT`, mask the // result, and return. - force_eval!(x + F::MAX); + + let status = if xi & F::SIG_MASK == F::Int::ZERO { Status::OK } else { Status::INEXACT }; xi &= mask; - F::from_bits(xi) + FpResult::new(F::from_bits(xi), status) } #[cfg(test)] mod tests { use super::*; + use crate::support::Hexf; + + fn spec_test(cases: &[(F, F, Status)]) { + let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + + for x in roundtrip { + let FpResult { val, status } = trunc_status(x); + assert_biteq!(val, x, "{}", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = trunc_status(x); + assert_biteq!(val, res, "{}", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); + } + } + + /* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */ + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + let cases = []; + spec_test::(&cases); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(trunc(0.5f32), 0.0); + assert_eq!(trunc(1.1f32), 1.0); + assert_eq!(trunc(2.9f32), 2.0); + } #[test] - fn sanity_check() { + fn spec_tests_f32() { + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + assert_biteq!(trunc(1.1f32), 1.0); assert_biteq!(trunc(1.1f64), 1.0); @@ -54,4 +105,32 @@ mod tests { assert_biteq!(trunc(hf32!("-0x1p-1")), -0.0); assert_biteq!(trunc(hf64!("-0x1p-1")), -0.0); } + + #[test] + fn sanity_check_f64() { + assert_eq!(trunc(1.1f64), 1.0); + assert_eq!(trunc(2.9f64), 2.0); + } + + #[test] + fn spec_tests_f64() { + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + let cases = []; + spec_test::(&cases); + } } -- cgit 1.4.1-3-g733a5 From a6dd7980f1553511ed6c03213924f202ee77ae4d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 05:26:50 +0000 Subject: Small refactor of bigint tests Print errors immediately rather than deferring to the end, so any debug output shows up immediately before the relevant failed test. --- .../libm/src/math/support/big/tests.rs | 65 +++++++++++----------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs index 6d06c700a5e..2c71191ba53 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -1,6 +1,5 @@ extern crate std; use std::string::String; -use std::vec::Vec; use std::{eprintln, format}; use super::{HInt, MinInt, i256, u256}; @@ -36,28 +35,30 @@ fn widen_mul_u128() { (0, 1234, u256::ZERO), ]; - let mut errors = Vec::new(); - for (i, (a, b, exp)) in tests.iter().copied().enumerate() { - let res = a.widen_mul(b); - let res_z = a.zero_widen_mul(b); - assert_eq!(res, res_z); - if res != exp { - errors.push((i, a, b, exp, res)); - } - } - - for (i, a, b, exp, res) in &errors { + let mut has_errors = false; + let mut add_error = |i, a, b, expected, actual| { + has_errors = true; eprintln!( "\ FAILURE ({i}): {a:#034x} * {b:#034x}\n\ expected: {}\n\ got: {}\ ", - hexu(*exp), - hexu(*res) + hexu(expected), + hexu(actual) ); + }; + + for (i, (a, b, exp)) in tests.iter().copied().enumerate() { + let res = a.widen_mul(b); + let res_z = a.zero_widen_mul(b); + assert_eq!(res, res_z); + if res != exp { + add_error(i, a, b, exp, res); + } } - assert!(errors.is_empty()); + + assert!(!has_errors); } #[test] @@ -68,7 +69,21 @@ fn not_u256() { #[test] fn shr_u256() { let only_low = [1, u16::MAX.into(), u32::MAX.into(), u64::MAX.into(), u128::MAX]; - let mut errors = Vec::new(); + let mut has_errors = false; + + let mut add_error = |a, b, expected, actual| { + has_errors = true; + eprintln!( + "\ + FAILURE: {} >> {b}\n\ + expected: {}\n\ + actual: {}\ + ", + hexu(a), + hexu(expected), + hexu(actual), + ); + }; for a in only_low { for perturb in 0..10 { @@ -77,7 +92,7 @@ fn shr_u256() { let res = a.widen() >> shift; let expected = (a >> shift).widen(); if res != expected { - errors.push((a.widen(), shift, res, expected)); + add_error(a.widen(), shift, expected, res); } } } @@ -107,23 +122,11 @@ fn shr_u256() { for (input, shift, expected) in check { let res = input >> shift; if res != expected { - errors.push((input, shift, res, expected)); + add_error(input, shift, expected, res); } } - for (a, b, res, expected) in &errors { - eprintln!( - "\ - FAILURE: {} >> {b}\n\ - expected: {}\n\ - got: {}\ - ", - hexu(*a), - hexu(*expected), - hexu(*res) - ); - } - assert!(errors.is_empty()); + assert!(!has_errors); } #[test] -- cgit 1.4.1-3-g733a5 From 86ee1f99c9d361338017282810966efc33901c3d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 19:56:52 +0000 Subject: Combine `fmin{,f,f16,f128}` and `fmax{,f,f16,128}` into a single file These don't have much content since they now use the generic implementation. There will be more similar functions in the near future (fminimum, fmaximum, fminimum_num, fmaximum_num); start the pattern of combining similar functions now so we don't have to eventually maintain similar docs across 24 different files. --- .../libm/etc/function-definitions.json | 16 +++---- library/compiler-builtins/libm/src/math/fmax.rs | 5 --- library/compiler-builtins/libm/src/math/fmaxf.rs | 5 --- .../compiler-builtins/libm/src/math/fmaxf128.rs | 5 --- library/compiler-builtins/libm/src/math/fmaxf16.rs | 5 --- library/compiler-builtins/libm/src/math/fmin.rs | 5 --- .../compiler-builtins/libm/src/math/fmin_fmax.rs | 51 ++++++++++++++++++++++ library/compiler-builtins/libm/src/math/fminf.rs | 5 --- .../compiler-builtins/libm/src/math/fminf128.rs | 5 --- library/compiler-builtins/libm/src/math/fminf16.rs | 5 --- library/compiler-builtins/libm/src/math/mod.rs | 22 +++------- 11 files changed, 65 insertions(+), 64 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/fmax.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmaxf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmaxf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmaxf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmin.rs create mode 100644 library/compiler-builtins/libm/src/math/fmin_fmax.rs delete mode 100644 library/compiler-builtins/libm/src/math/fminf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fminf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fminf16.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 5742ed585f5..d3e51f29a07 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -365,56 +365,56 @@ }, "fmax": { "sources": [ - "src/math/fmax.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmax.rs" ], "type": "f64" }, "fmaxf": { "sources": [ - "src/math/fmaxf.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmax.rs" ], "type": "f32" }, "fmaxf128": { "sources": [ - "src/math/fmaxf128.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmax.rs" ], "type": "f128" }, "fmaxf16": { "sources": [ - "src/math/fmaxf16.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmax.rs" ], "type": "f16" }, "fmin": { "sources": [ - "src/math/fmin.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmin.rs" ], "type": "f64" }, "fminf": { "sources": [ - "src/math/fminf.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmin.rs" ], "type": "f32" }, "fminf128": { "sources": [ - "src/math/fminf128.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmin.rs" ], "type": "f128" }, "fminf16": { "sources": [ - "src/math/fminf16.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmin.rs" ], "type": "f16" diff --git a/library/compiler-builtins/libm/src/math/fmax.rs b/library/compiler-builtins/libm/src/math/fmax.rs deleted file mode 100644 index d5d9b513b84..00000000000 --- a/library/compiler-builtins/libm/src/math/fmax.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmax(x: f64, y: f64) -> f64 { - super::generic::fmax(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmaxf.rs b/library/compiler-builtins/libm/src/math/fmaxf.rs deleted file mode 100644 index 3197d5cf2ca..00000000000 --- a/library/compiler-builtins/libm/src/math/fmaxf.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaxf(x: f32, y: f32) -> f32 { - super::generic::fmax(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmaxf128.rs b/library/compiler-builtins/libm/src/math/fmaxf128.rs deleted file mode 100644 index bace9ab53f2..00000000000 --- a/library/compiler-builtins/libm/src/math/fmaxf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaxf128(x: f128, y: f128) -> f128 { - super::generic::fmax(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmaxf16.rs b/library/compiler-builtins/libm/src/math/fmaxf16.rs deleted file mode 100644 index fea15be8f14..00000000000 --- a/library/compiler-builtins/libm/src/math/fmaxf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaxf16(x: f16, y: f16) -> f16 { - super::generic::fmax(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmin.rs b/library/compiler-builtins/libm/src/math/fmin.rs deleted file mode 100644 index df8ff7c32e3..00000000000 --- a/library/compiler-builtins/libm/src/math/fmin.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmin(x: f64, y: f64) -> f64 { - super::generic::fmin(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/src/math/fmin_fmax.rs new file mode 100644 index 00000000000..97912e75826 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmin_fmax.rs @@ -0,0 +1,51 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf16(x: f16, y: f16) -> f16 { + super::generic::fmin(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf(x: f32, y: f32) -> f32 { + super::generic::fmin(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmin(x: f64, y: f64) -> f64 { + super::generic::fmin(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf128(x: f128, y: f128) -> f128 { + super::generic::fmin(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf16(x: f16, y: f16) -> f16 { + super::generic::fmax(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf(x: f32, y: f32) -> f32 { + super::generic::fmax(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmax(x: f64, y: f64) -> f64 { + super::generic::fmax(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf128(x: f128, y: f128) -> f128 { + super::generic::fmax(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fminf.rs b/library/compiler-builtins/libm/src/math/fminf.rs deleted file mode 100644 index b2cdfe89d64..00000000000 --- a/library/compiler-builtins/libm/src/math/fminf.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminf(x: f32, y: f32) -> f32 { - super::generic::fmin(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fminf128.rs b/library/compiler-builtins/libm/src/math/fminf128.rs deleted file mode 100644 index a9224c22aa5..00000000000 --- a/library/compiler-builtins/libm/src/math/fminf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminf128(x: f128, y: f128) -> f128 { - super::generic::fmin(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fminf16.rs b/library/compiler-builtins/libm/src/math/fminf16.rs deleted file mode 100644 index 6d936be347a..00000000000 --- a/library/compiler-builtins/libm/src/math/fminf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminf16(x: f16, y: f16) -> f16 { - super::generic::fmin(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index ae4a278f287..ba0b933f17c 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -165,10 +165,7 @@ mod floor; mod floorf; mod fma; mod fmaf; -mod fmax; -mod fmaxf; -mod fmin; -mod fminf; +mod fmin_fmax; mod fmod; mod fmodf; mod frexp; @@ -273,10 +270,7 @@ pub use self::floor::floor; pub use self::floorf::floorf; pub use self::fma::fma; pub use self::fmaf::fmaf; -pub use self::fmax::fmax; -pub use self::fmaxf::fmaxf; -pub use self::fmin::fmin; -pub use self::fminf::fminf; +pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; pub use self::fmod::fmod; pub use self::fmodf::fmodf; pub use self::frexp::frexp; @@ -346,8 +340,6 @@ cfg_if! { mod fabsf16; mod fdimf16; mod floorf16; - mod fmaxf16; - mod fminf16; mod fmodf16; mod ldexpf16; mod rintf16; @@ -363,8 +355,8 @@ cfg_if! { pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; pub use self::floorf16::floorf16; - pub use self::fmaxf16::fmaxf16; - pub use self::fminf16::fminf16; + pub use self::fmin_fmax::fmaxf16; + pub use self::fmin_fmax::fminf16; pub use self::fmodf16::fmodf16; pub use self::ldexpf16::ldexpf16; pub use self::rintf16::rintf16; @@ -385,8 +377,6 @@ cfg_if! { mod fdimf128; mod floorf128; mod fmaf128; - mod fmaxf128; - mod fminf128; mod fmodf128; mod ldexpf128; mod rintf128; @@ -403,8 +393,8 @@ cfg_if! { pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; pub use self::fmaf128::fmaf128; - pub use self::fmaxf128::fmaxf128; - pub use self::fminf128::fminf128; + pub use self::fmin_fmax::fmaxf128; + pub use self::fmin_fmax::fminf128; pub use self::fmodf128::fmodf128; pub use self::ldexpf128::ldexpf128; pub use self::rintf128::rintf128; -- cgit 1.4.1-3-g733a5 From 669731335e05705eae35f6ba16bdcce9fabf1e90 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 19:43:49 +0000 Subject: Add `fminimum`, `fmaximum`, `fminimum_num`, and `fmaximum_num` These functions represent new operations from IEEE 754-2019. Introduce them for all float sizes. --- .../libm/crates/libm-macros/src/shared.rs | 32 +++++- .../libm/crates/libm-test/benches/icount.rs | 16 +++ .../libm/crates/libm-test/benches/random.rs | 16 +++ .../libm/crates/libm-test/src/domain.rs | 4 + .../libm/crates/libm-test/src/gen/case_list.rs | 80 ++++++++++++++- .../libm/crates/libm-test/src/mpfloat.rs | 54 +++++++++- .../libm/crates/libm-test/src/precision.rs | 4 + .../crates/libm-test/tests/compare_built_musl.rs | 16 +++ .../compiler-builtins/libm/crates/util/src/main.rs | 16 +++ .../libm/etc/function-definitions.json | 112 +++++++++++++++++++++ .../compiler-builtins/libm/etc/function-list.txt | 16 +++ library/compiler-builtins/libm/src/libm_helper.rs | 18 +++- .../compiler-builtins/libm/src/math/fmin_fmax.rs | 24 +++++ .../libm/src/math/fminimum_fmaximum.rs | 67 ++++++++++++ .../libm/src/math/fminimum_fmaximum_num.rs | 67 ++++++++++++ .../libm/src/math/generic/fmax.rs | 77 ++++++++++++-- .../libm/src/math/generic/fmaximum.rs | 78 ++++++++++++++ .../libm/src/math/generic/fmaximum_num.rs | 77 ++++++++++++++ .../libm/src/math/generic/fmin.rs | 77 ++++++++++++-- .../libm/src/math/generic/fminimum.rs | 78 ++++++++++++++ .../libm/src/math/generic/fminimum_num.rs | 77 ++++++++++++++ .../compiler-builtins/libm/src/math/generic/mod.rs | 8 ++ library/compiler-builtins/libm/src/math/mod.rs | 14 ++- 23 files changed, 997 insertions(+), 31 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs create mode 100644 library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fmaximum.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fminimum.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fminimum_num.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 48d19c50d19..cb5a1d18734 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -47,7 +47,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, None, - &["copysignf16", "fdimf16", "fmaxf16", "fminf16", "fmodf16"], + &[ + "copysignf16", + "fdimf16", + "fmaxf16", + "fmaximum_numf16", + "fmaximumf16", + "fminf16", + "fminimum_numf16", + "fminimumf16", + "fmodf16", + ], ), ( // `(f32, f32) -> f32` @@ -59,7 +69,11 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "copysignf", "fdimf", "fmaxf", + "fmaximum_numf", + "fmaximumf", "fminf", + "fminimum_numf", + "fminimumf", "fmodf", "hypotf", "nextafterf", @@ -77,7 +91,11 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "copysign", "fdim", "fmax", + "fmaximum", + "fmaximum_num", "fmin", + "fminimum", + "fminimum_num", "fmod", "hypot", "nextafter", @@ -90,7 +108,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, None, - &["copysignf128", "fdimf128", "fmaxf128", "fminf128", "fmodf128"], + &[ + "copysignf128", + "fdimf128", + "fmaxf128", + "fmaximum_numf128", + "fmaximumf128", + "fminf128", + "fminimum_numf128", + "fminimumf128", + "fmodf128", + ], ), ( // `(f32, f32, f32) -> f32` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index be85dd5676c..e28f4973cb0 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -207,10 +207,26 @@ main!( icount_bench_fmaxf128_group, icount_bench_fmaxf16_group, icount_bench_fmaxf_group, + icount_bench_fmaximum_group, + icount_bench_fmaximum_num_group, + icount_bench_fmaximum_numf128_group, + icount_bench_fmaximum_numf16_group, + icount_bench_fmaximum_numf_group, + icount_bench_fmaximumf128_group, + icount_bench_fmaximumf16_group, + icount_bench_fmaximumf_group, icount_bench_fmin_group, icount_bench_fminf128_group, icount_bench_fminf16_group, icount_bench_fminf_group, + icount_bench_fminimum_group, + icount_bench_fminimum_num_group, + icount_bench_fminimum_numf128_group, + icount_bench_fminimum_numf16_group, + icount_bench_fminimum_numf_group, + icount_bench_fminimumf128_group, + icount_bench_fminimumf16_group, + icount_bench_fminimumf_group, icount_bench_fmod_group, icount_bench_fmodf128_group, icount_bench_fmodf16_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 6e8a334795a..6f6b05d9596 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -130,8 +130,24 @@ libm_macros::for_each_function! { | fmaf128 | fmaxf128 | fmaxf16 + | fmaximum + | fmaximum_num + | fmaximum_numf + | fmaximum_numf128 + | fmaximum_numf16 + | fmaximumf + | fmaximumf128 + | fmaximumf16 | fminf128 | fminf16 + | fminimum + | fminimum_num + | fminimum_numf + | fminimum_numf128 + | fminimum_numf16 + | fminimumf + | fminimumf128 + | fminimumf16 | fmodf128 | fmodf16 | ldexpf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index 5d650c00a3b..c662e95b4b4 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -221,7 +221,11 @@ pub fn get_domain( BaseName::Floor => &EitherPrim::UNBOUNDED1[..], BaseName::Fma => &EitherPrim::UNBOUNDED3[..], BaseName::Fmax => &EitherPrim::UNBOUNDED2[..], + BaseName::Fmaximum => &EitherPrim::UNBOUNDED2[..], + BaseName::FmaximumNum => &EitherPrim::UNBOUNDED2[..], BaseName::Fmin => &EitherPrim::UNBOUNDED2[..], + BaseName::Fminimum => &EitherPrim::UNBOUNDED2[..], + BaseName::FminimumNum => &EitherPrim::UNBOUNDED2[..], BaseName::Fmod => &EitherPrim::UNBOUNDED2[..], BaseName::Hypot => &EitherPrim::UNBOUNDED2[..], BaseName::Ilogb => &EitherPrim::UNBOUNDED1[..], diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs index 23226d5c251..49e731b88b7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs @@ -293,7 +293,8 @@ fn fmaf128_cases() -> Vec> { v } -fn fmax_cases() -> Vec> { +#[cfg(f16_enabled)] +fn fmaxf16_cases() -> Vec> { vec![] } @@ -301,17 +302,53 @@ fn fmaxf_cases() -> Vec> { vec![] } +fn fmax_cases() -> Vec> { + vec![] +} + #[cfg(f128_enabled)] fn fmaxf128_cases() -> Vec> { vec![] } #[cfg(f16_enabled)] -fn fmaxf16_cases() -> Vec> { +fn fmaximumf16_cases() -> Vec> { vec![] } -fn fmin_cases() -> Vec> { +fn fmaximumf_cases() -> Vec> { + vec![] +} + +fn fmaximum_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmaximumf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fmaximum_numf16_cases() -> Vec> { + vec![] +} + +fn fmaximum_numf_cases() -> Vec> { + vec![] +} + +fn fmaximum_num_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmaximum_numf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fminf16_cases() -> Vec> { vec![] } @@ -319,13 +356,48 @@ fn fminf_cases() -> Vec> { vec![] } +fn fmin_cases() -> Vec> { + vec![] +} + #[cfg(f128_enabled)] fn fminf128_cases() -> Vec> { vec![] } #[cfg(f16_enabled)] -fn fminf16_cases() -> Vec> { +fn fminimumf16_cases() -> Vec> { + vec![] +} + +fn fminimumf_cases() -> Vec> { + vec![] +} + +fn fminimum_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fminimumf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fminimum_numf16_cases() -> Vec> { + vec![] +} + +fn fminimum_numf_cases() -> Vec> { + vec![] +} + +fn fminimum_num_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fminimum_numf128_cases() -> Vec> { vec![] } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index f4a9ff7ffd5..63cdebe4eee 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -148,6 +148,14 @@ libm_macros::for_each_function! { floorf, floorf128, floorf16, + fmaximum, + fmaximumf, + fmaximumf128, + fmaximumf16, + fminimum, + fminimumf, + fminimumf128, + fminimumf16, fmod, fmodf, fmodf128, @@ -197,8 +205,10 @@ libm_macros::for_each_function! { fabs | fabsf => abs, fdim | fdimf | fdimf16 | fdimf128 => positive_diff, fma | fmaf | fmaf128 => mul_add, - fmax | fmaxf | fmaxf16 | fmaxf128 => max, - fmin | fminf | fminf16 | fminf128 => min, + fmax | fmaxf | fmaxf16 | fmaxf128 | + fmaximum_num | fmaximum_numf | fmaximum_numf16 | fmaximum_numf128 => max, + fmin | fminf | fminf16 | fminf128 | + fminimum_num | fminimum_numf | fminimum_numf16 | fminimum_numf128 => min, lgamma | lgammaf => ln_gamma, log | logf => ln, log1p | log1pf => ln_1p, @@ -446,6 +456,46 @@ macro_rules! impl_op_for_ty_all { } } + impl MpOp for crate::op::[< fmaximum $suffix >]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = if this.0.is_nan() || this.1.is_nan() { + this.0.assign($fty::NAN); + Ordering::Equal + } else { + this.0.max_round(&this.1, Nearest) + }; + prep_retval::(&mut this.0, ord) + } + } + + impl MpOp for crate::op::[< fminimum $suffix >]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = if this.0.is_nan() || this.1.is_nan() { + this.0.assign($fty::NAN); + Ordering::Equal + } else { + this.0.min_round(&this.1, Nearest) + }; + prep_retval::(&mut this.0, ord) + } + } + // `ldexp` and `scalbn` are the same for binary floating point, so just forward all // methods. impl MpOp for crate::op::[]::Routine { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 2f55ad22ec7..1d916e5726a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -25,7 +25,11 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { | Bn::Floor | Bn::Fma | Bn::Fmax + | Bn::Fmaximum + | Bn::FmaximumNum | Bn::Fmin + | Bn::Fminimum + | Bn::FminimumNum | Bn::Fmod | Bn::Frexp | Bn::Ilogb diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 7fa77e832b1..ffd7f1f60c6 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -102,8 +102,24 @@ libm_macros::for_each_function! { fmaf128, fmaxf128, fmaxf16, + fmaximum, + fmaximum_num, + fmaximum_numf, + fmaximum_numf128, + fmaximum_numf16, + fmaximumf, + fmaximumf128, + fmaximumf16, fminf128, fminf16, + fminimum, + fminimum_num, + fminimum_numf, + fminimum_numf128, + fminimum_numf16, + fminimumf, + fminimumf128, + fminimumf16, fmodf128, fmodf16, ldexpf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 0f845a1c4d0..a519713c0b1 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -99,8 +99,24 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fmaf128 | fmaxf128 | fmaxf16 + | fmaximum + | fmaximum_num + | fmaximum_numf + | fmaximum_numf128 + | fmaximum_numf16 + | fmaximumf + | fmaximumf128 + | fmaximumf16 | fminf128 | fminf16 + | fminimum + | fminimum_num + | fminimum_numf + | fminimum_numf128 + | fminimum_numf16 + | fminimumf + | fminimumf128 + | fminimumf16 | fmodf128 | fmodf16 | ldexpf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index d3e51f29a07..008a47df219 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -391,6 +391,62 @@ ], "type": "f16" }, + "fmaximum": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fmaximum.rs" + ], + "type": "f64" + }, + "fmaximum_num": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fmaximum_num.rs" + ], + "type": "f64" + }, + "fmaximum_numf": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fmaximum_num.rs" + ], + "type": "f32" + }, + "fmaximum_numf128": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fmaximum_num.rs" + ], + "type": "f128" + }, + "fmaximum_numf16": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fmaximum_num.rs" + ], + "type": "f16" + }, + "fmaximumf": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fmaximum.rs" + ], + "type": "f32" + }, + "fmaximumf128": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fmaximum.rs" + ], + "type": "f128" + }, + "fmaximumf16": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fmaximum.rs" + ], + "type": "f16" + }, "fmin": { "sources": [ "src/math/fmin_fmax.rs", @@ -419,6 +475,62 @@ ], "type": "f16" }, + "fminimum": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fminimum.rs" + ], + "type": "f64" + }, + "fminimum_num": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fminimum_num.rs" + ], + "type": "f64" + }, + "fminimum_numf": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fminimum_num.rs" + ], + "type": "f32" + }, + "fminimum_numf128": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fminimum_num.rs" + ], + "type": "f128" + }, + "fminimum_numf16": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fminimum_num.rs" + ], + "type": "f16" + }, + "fminimumf": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fminimum.rs" + ], + "type": "f32" + }, + "fminimumf128": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fminimum.rs" + ], + "type": "f128" + }, + "fminimumf16": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fminimum.rs" + ], + "type": "f16" + }, "fmod": { "sources": [ "src/math/fmod.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 1c9c5e3bc33..90ca8f34e62 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -58,10 +58,26 @@ fmax fmaxf fmaxf128 fmaxf16 +fmaximum +fmaximum_num +fmaximum_numf +fmaximum_numf128 +fmaximum_numf16 +fmaximumf +fmaximumf128 +fmaximumf16 fmin fminf fminf128 fminf16 +fminimum +fminimum_num +fminimum_numf +fminimum_numf128 +fminimum_numf16 +fminimumf +fminimumf128 +fminimumf16 fmod fmodf fmodf128 diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index 68f1fb36266..489dbc0d4df 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -137,7 +137,15 @@ libm_helper! { (fn floor(x: f64) -> (f64); => floor); (fn fma(x: f64, y: f64, z: f64) -> (f64); => fma); (fn fmax(x: f64, y: f64) -> (f64); => fmax); + (fn fmaximum(x: f64, y: f64) -> (f64); => fmaximum); + (fn fmaximum_num(x: f64, y: f64) -> (f64); => fmaximum_num); + (fn fmaximum_numf(x: f32, y: f32) -> (f32); => fmaximum_numf); + (fn fmaximumf(x: f32, y: f32) -> (f32); => fmaximumf); (fn fmin(x: f64, y: f64) -> (f64); => fmin); + (fn fminimum(x: f64, y: f64) -> (f64); => fminimum); + (fn fminimum_num(x: f64, y: f64) -> (f64); => fminimum_num); + (fn fminimum_numf(x: f32, y: f32) -> (f32); => fminimum_numf); + (fn fminimumf(x: f32, y: f32) -> (f32); => fminimumf); (fn fmod(x: f64, y: f64) -> (f64); => fmod); (fn frexp(x: f64) -> (f64, i32); => frexp); (fn hypot(x: f64, y: f64) -> (f64); => hypot); @@ -186,7 +194,11 @@ libm_helper! { (fn fdim(x: f16, y: f16) -> (f16); => fdimf16); (fn floorf(x: f16) -> (f16); => floorf16); (fn fmaxf(x: f16, y: f16) -> (f16); => fmaxf16); + (fn fmaximum_numf16(x: f16, y: f16) -> (f16); => fmaximum_numf16); + (fn fmaximumf16(x: f16, y: f16) -> (f16); => fmaximumf16); (fn fminf(x: f16, y: f16) -> (f16); => fminf16); + (fn fminimum_numf16(x: f16, y: f16) -> (f16); => fminimum_numf16); + (fn fminimumf16(x: f16, y: f16) -> (f16); => fminimumf16); (fn fmodf(x: f16, y: f16) -> (f16); => fmodf16); (fn ldexpf16(x: f16, n: i32) -> (f16); => ldexpf16); (fn rintf(x: f16) -> (f16); => rintf16); @@ -208,9 +220,13 @@ libm_helper! { (fn fabs(x: f128) -> (f128); => fabsf128); (fn fdim(x: f128, y: f128) -> (f128); => fdimf128); (fn floor(x: f128) -> (f128); => floorf128); - (fn fmaf128(x: f128, y: f128, z: f128) -> (f128); => fmaf128); + (fn fmaf128(x: f128, y: f128, z: f128) -> (f128); => fmaf128); (fn fmax(x: f128, y: f128) -> (f128); => fmaxf128); + (fn fmaximum_numf128(x: f128, y: f128) -> (f128); => fmaximum_numf128); + (fn fmaximumf128(x: f128, y: f128) -> (f128); => fmaximumf128); (fn fmin(x: f128, y: f128) -> (f128); => fminf128); + (fn fminimum_numf128(x: f128, y: f128) -> (f128); => fminimum_numf128); + (fn fminimumf128(x: f128, y: f128) -> (f128); => fminimumf128); (fn fmod(x: f128, y: f128) -> (f128); => fmodf128); (fn ldexpf128(x: f128, n: i32) -> (f128); => ldexpf128); (fn rint(x: f128) -> (f128); => rintf128); diff --git a/library/compiler-builtins/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/src/math/fmin_fmax.rs index 97912e75826..4f9136dbbcd 100644 --- a/library/compiler-builtins/libm/src/math/fmin_fmax.rs +++ b/library/compiler-builtins/libm/src/math/fmin_fmax.rs @@ -1,4 +1,7 @@ /// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg(f16_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fminf16(x: f16, y: f16) -> f16 { @@ -6,18 +9,27 @@ pub fn fminf16(x: f16, y: f16) -> f16 { } /// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fminf(x: f32, y: f32) -> f32 { super::generic::fmin(x, y) } /// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmin(x: f64, y: f64) -> f64 { super::generic::fmin(x, y) } /// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg(f128_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fminf128(x: f128, y: f128) -> f128 { @@ -25,6 +37,9 @@ pub fn fminf128(x: f128, y: f128) -> f128 { } /// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg(f16_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaxf16(x: f16, y: f16) -> f16 { @@ -32,18 +47,27 @@ pub fn fmaxf16(x: f16, y: f16) -> f16 { } /// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaxf(x: f32, y: f32) -> f32 { super::generic::fmax(x, y) } /// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmax(x: f64, y: f64) -> f64 { super::generic::fmax(x, y) } /// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg(f128_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaxf128(x: f128, y: f128) -> f128 { diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs new file mode 100644 index 00000000000..fd3c5ed1039 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs @@ -0,0 +1,67 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimumf16(x: f16, y: f16) -> f16 { + super::generic::fminimum(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum(x: f64, y: f64) -> f64 { + super::generic::fminimum(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimumf(x: f32, y: f32) -> f32 { + super::generic::fminimum(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimumf128(x: f128, y: f128) -> f128 { + super::generic::fminimum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximumf16(x: f16, y: f16) -> f16 { + super::generic::fmaximum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximumf(x: f32, y: f32) -> f32 { + super::generic::fmaximum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum(x: f64, y: f64) -> f64 { + super::generic::fmaximum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximumf128(x: f128, y: f128) -> f128 { + super::generic::fmaximum(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs new file mode 100644 index 00000000000..640ddfc9b66 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs @@ -0,0 +1,67 @@ +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_numf16(x: f16, y: f16) -> f16 { + super::generic::fminimum_num(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_numf(x: f32, y: f32) -> f32 { + super::generic::fminimum_num(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_num(x: f64, y: f64) -> f64 { + super::generic::fminimum_num(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_numf128(x: f128, y: f128) -> f128 { + super::generic::fminimum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_numf16(x: f16, y: f16) -> f16 { + super::generic::fmaximum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_numf(x: f32, y: f32) -> f32 { + super::generic::fmaximum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_num(x: f64, y: f64) -> f64 { + super::generic::fmaximum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_numf128(x: f128, y: f128) -> f128 { + super::generic::fmaximum_num(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs index 97803052bc2..32613a46b93 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmax.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmax.rs @@ -1,14 +1,73 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2011 `maxNum`. This has been superseded by IEEE 754-2019 `maximumNumber`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x > y` +//! - `y` if `y > x` +//! - The other number if one is NaN +//! - Otherwise, either `x` or `y`, canonicalized +//! - -0.0 and +0.0 may be disregarded (unlike newer operations) +//! +//! Excluded from our implementation is sNaN handling. +//! +//! More on the differences: [link]. +//! +//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf + use super::super::Float; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmax(x: F, y: F) -> F { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if x.is_nan() || x < y { y } else { x }) * F::ONE + let res = if x.is_nan() || x < y { y } else { x }; + // Canonicalize + res * F::ONE +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Hexf, Int}; + + fn spec_test() { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + ]; + + for (x, y, res) in cases { + let val = fmax(x, y); + assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } } diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs new file mode 100644 index 00000000000..5f653ce94e2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `maximum`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x > y` +//! - `y` if `y > x` +//! - qNaN if either operation is NaN +//! - Logic following +0.0 > -0.0 +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +pub fn fmaximum(x: F, y: F) -> F { + let res = if x.is_nan() { + x + } else if y.is_nan() { + y + } else if x > y || (y.to_bits() == F::NEG_ZERO.to_bits() && x.is_sign_positive()) { + x + } else { + y + }; + + // Canonicalize + res * F::ONE +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Hexf, Int}; + + fn spec_test() { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::NAN), + (F::ZERO, F::NAN, F::NAN), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::ZERO), + (F::NEG_ZERO, F::ZERO, F::ZERO), + ]; + + for (x, y, res) in cases { + let val = fmaximum(x, y); + assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs new file mode 100644 index 00000000000..22466012392 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `maximumNumber`. +//! +//! Per the spec, returns: +//! - `x` if `x > y` +//! - `y` if `y > x` +//! - Non-NaN if one operand is NaN +//! - Logic following +0.0 > -0.0 +//! - Either `x` or `y` if `x == y` and the signs are the same +//! - qNaN if either operand is a NaN +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +pub fn fmaximum_num(x: F, y: F) -> F { + let res = + if x.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { + y + } else { + x + }; + + // Canonicalize + res * F::ONE +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Hexf, Int}; + + fn spec_test() { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::ZERO), + (F::NEG_ZERO, F::ZERO, F::ZERO), + ]; + + for (x, y, res) in cases { + let val = fmaximum_num(x, y); + assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs index 697f7200486..5cc33e904ed 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmin.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmin.rs @@ -1,13 +1,72 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2008 `minNum`. This has been superseded by IEEE 754-2019 `minimumNumber`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x < y` +//! - `y` if `y < x` +//! - The other number if one is NaN +//! - Otherwise, either `x` or `y`, canonicalized +//! - -0.0 and +0.0 may be disregarded (unlike newer operations) +//! +//! Excluded from our implementation is sNaN handling. +//! +//! More on the differences: [link]. +//! +//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf + use super::super::Float; pub fn fmin(x: F, y: F) -> F { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if y.is_nan() || x < y { x } else { y }) * F::ONE + let res = if y.is_nan() || x < y { x } else { y }; + // Canonicalize + res * F::ONE +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Hexf, Int}; + + fn spec_test() { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + ]; + + for (x, y, res) in cases { + let val = fmin(x, y); + assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } } diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs new file mode 100644 index 00000000000..f566d9631d3 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fminimum.rs @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `minimum`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x < y` +//! - `y` if `y < x` +//! - qNaN if either operation is NaN +//! - Logic following +0.0 > -0.0 +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +pub fn fminimum(x: F, y: F) -> F { + let res = if x.is_nan() { + x + } else if y.is_nan() { + y + } else if x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { + x + } else { + y + }; + + // Canonicalize + res * F::ONE +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Hexf, Int}; + + fn spec_test() { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::NAN), + (F::ZERO, F::NAN, F::NAN), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + ]; + + for (x, y, res) in cases { + let val = fminimum(x, y); + assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs new file mode 100644 index 00000000000..e58a585c329 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `minimum`. +//! +//! Per the spec, returns: +//! - `x` if `x < y` +//! - `y` if `y < x` +//! - Non-NaN if one operand is NaN +//! - Logic following +0.0 > -0.0 +//! - Either `x` or `y` if `x == y` and the signs are the same +//! - qNaN if either operand is a NaN +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +pub fn fminimum_num(x: F, y: F) -> F { + let res = + if y.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { + x + } else { + y + }; + + // Canonicalize + res * F::ONE +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Hexf, Int}; + + fn spec_test() { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + ]; + + for (x, y, res) in cases { + let val = fminimum_num(x, y); + assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index b34d3dfae94..092f9317bc5 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -5,7 +5,11 @@ mod fdim; mod floor; mod fma; mod fmax; +mod fmaximum; +mod fmaximum_num; mod fmin; +mod fminimum; +mod fminimum_num; mod fmod; mod rint; mod round; @@ -20,7 +24,11 @@ pub use fdim::fdim; pub use floor::floor; pub use fma::{fma, fma_wide}; pub use fmax::fmax; +pub use fmaximum::fmaximum; +pub use fmaximum_num::fmaximum_num; pub use fmin::fmin; +pub use fminimum::fminimum; +pub use fminimum_num::fminimum_num; pub use fmod::fmod; pub use rint::rint; pub use round::round; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index ba0b933f17c..4e75292a6ef 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -166,6 +166,8 @@ mod floorf; mod fma; mod fmaf; mod fmin_fmax; +mod fminimum_fmaximum; +mod fminimum_fmaximum_num; mod fmod; mod fmodf; mod frexp; @@ -271,6 +273,8 @@ pub use self::floorf::floorf; pub use self::fma::fma; pub use self::fmaf::fmaf; pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; +pub use self::fminimum_fmaximum::{fmaximum, fmaximumf, fminimum, fminimumf}; +pub use self::fminimum_fmaximum_num::{fmaximum_num, fmaximum_numf, fminimum_num, fminimum_numf}; pub use self::fmod::fmod; pub use self::fmodf::fmodf; pub use self::frexp::frexp; @@ -355,8 +359,9 @@ cfg_if! { pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; pub use self::floorf16::floorf16; - pub use self::fmin_fmax::fmaxf16; - pub use self::fmin_fmax::fminf16; + pub use self::fmin_fmax::{fmaxf16, fminf16}; + pub use self::fminimum_fmaximum::{fmaximumf16, fminimumf16}; + pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16}; pub use self::fmodf16::fmodf16; pub use self::ldexpf16::ldexpf16; pub use self::rintf16::rintf16; @@ -393,8 +398,9 @@ cfg_if! { pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; pub use self::fmaf128::fmaf128; - pub use self::fmin_fmax::fmaxf128; - pub use self::fmin_fmax::fminf128; + pub use self::fmin_fmax::{fmaxf128, fminf128}; + pub use self::fminimum_fmaximum::{fmaximumf128, fminimumf128}; + pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; pub use self::fmodf128::fmodf128; pub use self::ldexpf128::ldexpf128; pub use self::rintf128::rintf128; -- cgit 1.4.1-3-g733a5 From e79fb05b2554aa641425e9e7aa5ec70e483b6427 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 21:42:26 +0000 Subject: Increase allowed offset from infinity for ynf Failed with called `Result::unwrap()` on an `Err` value: ynf Caused by: 0: input: (223, 116.89665) as hex: (, 0x1.d3962cp+6) as bits: (0x000000df, 0x42e9cb16) expected: -3.1836905e38 -0x1.df074cp+127 0xff6f83a6 actual: -inf -inf 0xff800000 1: mismatched infinities --- library/compiler-builtins/libm/crates/libm-test/src/precision.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 1d916e5726a..8b08925469e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -537,7 +537,7 @@ fn int_float_common( && !expected.is_infinite() && actual.is_infinite() && (expected.abs().to_bits().abs_diff(actual.abs().to_bits()) - < F2::Int::cast_from(1_000_000u32)) + < F2::Int::cast_from(10_000_000u32)) { return XFAIL_NOCHECK; } -- cgit 1.4.1-3-g733a5 From 2a3ef8b9a2365365aae80419a9bbac0bddf64c71 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 11 Feb 2025 02:17:06 +0000 Subject: Fix parsing of negative hex float literals in util --- library/compiler-builtins/libm/crates/util/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index a519713c0b1..710adbb1794 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -274,7 +274,7 @@ fn parse(input: &[&str], idx: usize) -> T { let msg = || format!("invalid {} input '{s}'", type_name::()); - if s.starts_with("0x") { + if s.starts_with("0x") || s.starts_with("-0x") { return T::from_str_radix(s, 16).unwrap_or_else(|_| panic!("{}", msg())); } -- cgit 1.4.1-3-g733a5 From 53a055049cde50f6a42cf3cb5a7826142ea396e0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 11 Feb 2025 00:17:32 +0000 Subject: Add `roundeven{,f,f16,f128}` C23 specifies a new set of `roundeven` functions that round to the nearest integral, with ties to even. It does not raise any floating point exceptions. This behavior is similar to two other functions: 1. `rint`, which rounds to the nearest integer respecting rounding mode and possibly raising exceptions. 2. `nearbyint`, which is identical to `rint` except it may not raise exceptions. Technically `rint`, `nearbyint`, and `roundeven` all behave the same in Rust because we assume default floating point environment. The backends are allowed to lower to `roundeven`, however, so we should provide it in case the fallback is needed. Add the `roundeven` family here and convert `rint` to a function that takes a rounding mode. This currently has no effect. --- .../libm/crates/libm-macros/src/shared.rs | 104 ++++++++++++++++++-- .../libm/crates/libm-test/benches/icount.rs | 4 + .../libm/crates/libm-test/benches/random.rs | 4 + .../libm/crates/libm-test/src/domain.rs | 1 + .../libm/crates/libm-test/src/gen/case_list.rs | 39 +++++++- .../libm/crates/libm-test/src/mpfloat.rs | 8 ++ .../libm/crates/libm-test/src/precision.rs | 3 +- .../crates/libm-test/tests/compare_built_musl.rs | 4 + .../compiler-builtins/libm/crates/util/src/main.rs | 4 + .../libm/etc/function-definitions.json | 34 +++++-- .../compiler-builtins/libm/etc/function-list.txt | 4 + library/compiler-builtins/libm/src/libm_helper.rs | 42 +++++---- .../compiler-builtins/libm/src/math/generic/mod.rs | 2 +- .../libm/src/math/generic/rint.rs | 105 +++++++++++++++------ library/compiler-builtins/libm/src/math/mod.rs | 14 +-- library/compiler-builtins/libm/src/math/rint.rs | 33 ++++++- library/compiler-builtins/libm/src/math/rintf.rs | 14 --- .../compiler-builtins/libm/src/math/rintf128.rs | 5 - library/compiler-builtins/libm/src/math/rintf16.rs | 5 - .../compiler-builtins/libm/src/math/roundeven.rs | 35 +++++++ 20 files changed, 363 insertions(+), 101 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/rintf.rs delete mode 100644 library/compiler-builtins/libm/src/math/rintf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/rintf16.rs create mode 100644 library/compiler-builtins/libm/src/math/roundeven.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index cb5a1d18734..5e58220eb39 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,16 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["ceilf16", "fabsf16", "floorf16", "rintf16", "roundf16", "sqrtf16", "truncf16"], + &[ + "ceilf16", + "fabsf16", + "floorf16", + "rintf16", + "roundevenf16", + "roundf16", + "sqrtf16", + "truncf16", + ], ), ( // `fn(f32) -> f32` @@ -17,10 +26,43 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] Signature { args: &[Ty::F32], returns: &[Ty::F32] }, None, &[ - "acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf", - "coshf", "erfcf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", - "j0f", "j1f", "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", - "sinf", "sinhf", "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", "y0f", "y1f", + "acosf", + "acoshf", + "asinf", + "asinhf", + "atanf", + "atanhf", + "cbrtf", + "ceilf", + "cosf", + "coshf", + "erfcf", + "erff", + "exp10f", + "exp2f", + "expf", + "expm1f", + "fabsf", + "floorf", + "j0f", + "j1f", + "lgammaf", + "log10f", + "log1pf", + "log2f", + "logf", + "rintf", + "roundevenf", + "roundf", + "sinf", + "sinhf", + "sqrtf", + "tanf", + "tanhf", + "tgammaf", + "truncf", + "y0f", + "y1f", ], ), ( @@ -29,10 +71,43 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] Signature { args: &[Ty::F64], returns: &[Ty::F64] }, None, &[ - "acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh", - "erf", "erfc", "exp", "exp10", "exp2", "expm1", "fabs", "floor", "j0", "j1", "lgamma", - "log", "log10", "log1p", "log2", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", - "tgamma", "trunc", "y0", "y1", + "acos", + "acosh", + "asin", + "asinh", + "atan", + "atanh", + "cbrt", + "ceil", + "cos", + "cosh", + "erf", + "erfc", + "exp", + "exp10", + "exp2", + "expm1", + "fabs", + "floor", + "j0", + "j1", + "lgamma", + "log", + "log10", + "log1p", + "log2", + "rint", + "round", + "roundeven", + "sin", + "sinh", + "sqrt", + "tan", + "tanh", + "tgamma", + "trunc", + "y0", + "y1", ], ), ( @@ -40,7 +115,16 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["ceilf128", "fabsf128", "floorf128", "rintf128", "roundf128", "sqrtf128", "truncf128"], + &[ + "ceilf128", + "fabsf128", + "floorf128", + "rintf128", + "roundevenf128", + "roundf128", + "sqrtf128", + "truncf128", + ], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index e28f4973cb0..4a10ec383ae 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -274,6 +274,10 @@ main!( icount_bench_rintf16_group, icount_bench_rintf_group, icount_bench_round_group, + icount_bench_roundeven_group, + icount_bench_roundevenf128_group, + icount_bench_roundevenf16_group, + icount_bench_roundevenf_group, icount_bench_roundf128_group, icount_bench_roundf16_group, icount_bench_roundf_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 6f6b05d9596..17e4e0d55fc 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -154,6 +154,10 @@ libm_macros::for_each_function! { | ldexpf16 | rintf128 | rintf16 + | roundeven + | roundevenf + | roundevenf128 + | roundevenf16 | roundf128 | roundf16 | scalbnf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index c662e95b4b4..41e94846163 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -246,6 +246,7 @@ pub fn get_domain( BaseName::Remquo => &EitherPrim::UNBOUNDED2[..], BaseName::Rint => &EitherPrim::UNBOUNDED1[..], BaseName::Round => &EitherPrim::UNBOUNDED1[..], + BaseName::Roundeven => &EitherPrim::UNBOUNDED1[..], BaseName::Scalbn => &EitherPrim::UNBOUNDED_F_I[..], BaseName::Sin => &EitherPrim::TRIG[..], BaseName::Sincos => &EitherPrim::TRIG[..], diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs index 49e731b88b7..8c7a735fa70 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs @@ -6,6 +6,7 @@ //! //! This is useful for adding regression tests or expected failures. +use libm::hf64; #[cfg(f128_enabled)] use libm::hf128; @@ -574,7 +575,15 @@ fn remquof_cases() -> Vec> { } fn rint_cases() -> Vec> { - vec![] + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Failure on i586 + ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), + ], + ); + v } fn rintf_cases() -> Vec> { @@ -591,6 +600,11 @@ fn rintf16_cases() -> Vec> { vec![] } +#[cfg(f16_enabled)] +fn roundf16_cases() -> Vec> { + vec![] +} + fn round_cases() -> Vec> { vec![] } @@ -605,7 +619,28 @@ fn roundf128_cases() -> Vec> { } #[cfg(f16_enabled)] -fn roundf16_cases() -> Vec> { +fn roundevenf16_cases() -> Vec> { + vec![] +} + +fn roundeven_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Failure on i586 + ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), + ], + ); + v +} + +fn roundevenf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn roundevenf128_cases() -> Vec> { vec![] } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 63cdebe4eee..9b51dc6051d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -184,6 +184,10 @@ libm_macros::for_each_function! { rintf128, rintf16, round, + roundeven, + roundevenf, + roundevenf128, + roundevenf16, roundf, roundf128, roundf16, @@ -253,6 +257,8 @@ impl_no_round! { rint => round_even_mut; // FIXME: respect rounding mode rintf => round_even_mut; // FIXME: respect rounding mode round => round_mut; + roundeven => round_even_mut; + roundevenf => round_even_mut; roundf => round_mut; trunc => trunc_mut; truncf => trunc_mut; @@ -265,6 +271,7 @@ impl_no_round! { floorf16 => floor_mut; rintf16 => round_even_mut; // FIXME: respect rounding mode roundf16 => round_mut; + roundevenf16 => round_even_mut; truncf16 => trunc_mut; } @@ -275,6 +282,7 @@ impl_no_round! { floorf128 => floor_mut; rintf128 => round_even_mut; // FIXME: respect rounding mode roundf128 => round_mut; + roundevenf128 => round_even_mut; truncf128 => trunc_mut; } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 8b08925469e..8916b43ab17 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -40,6 +40,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { | Bn::Remquo | Bn::Rint | Bn::Round + | Bn::Roundeven | Bn::Scalbn | Bn::Sqrt | Bn::Trunc => 0, @@ -282,7 +283,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { } if cfg!(x86_no_sse) - && ctx.base_name == BaseName::Rint + && (ctx.base_name == BaseName::Rint || ctx.base_name == BaseName::Roundeven) && (expected - actual).abs() <= F::ONE && (expected - actual).abs() > F::ZERO { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index ffd7f1f60c6..2b16b9aa091 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -126,6 +126,10 @@ libm_macros::for_each_function! { ldexpf16, rintf128, rintf16, + roundeven, + roundevenf, + roundevenf128, + roundevenf16, roundf128, roundf16, scalbnf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 710adbb1794..130ac45319b 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -123,6 +123,10 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | ldexpf16 | rintf128 | rintf16 + | roundeven + | roundevenf + | roundevenf128 + | roundevenf16 | roundf128 | roundf16 | scalbnf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 008a47df219..a47aaad57c7 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -791,7 +791,6 @@ "sources": [ "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", - "src/math/generic/rint.rs", "src/math/rint.rs" ], "type": "f64" @@ -800,22 +799,19 @@ "sources": [ "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", - "src/math/generic/rint.rs", - "src/math/rintf.rs" + "src/math/rint.rs" ], "type": "f32" }, "rintf128": { "sources": [ - "src/math/generic/rint.rs", - "src/math/rintf128.rs" + "src/math/rint.rs" ], "type": "f128" }, "rintf16": { "sources": [ - "src/math/generic/rint.rs", - "src/math/rintf16.rs" + "src/math/rint.rs" ], "type": "f16" }, @@ -826,6 +822,30 @@ ], "type": "f64" }, + "roundeven": { + "sources": [ + "src/math/roundeven.rs" + ], + "type": "f64" + }, + "roundevenf": { + "sources": [ + "src/math/roundeven.rs" + ], + "type": "f32" + }, + "roundevenf128": { + "sources": [ + "src/math/roundeven.rs" + ], + "type": "f128" + }, + "roundevenf16": { + "sources": [ + "src/math/roundeven.rs" + ], + "type": "f16" + }, "roundf": { "sources": [ "src/math/generic/round.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 90ca8f34e62..1f226c8c0ff 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -125,6 +125,10 @@ rintf rintf128 rintf16 round +roundeven +roundevenf +roundevenf128 +roundevenf16 roundf roundf128 roundf16 diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index 489dbc0d4df..dfa1ff77bf2 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -94,6 +94,7 @@ libm_helper! { (fn remquo(x: f32, y: f32) -> (f32, i32); => remquof); (fn rint(x: f32) -> (f32); => rintf); (fn round(x: f32) -> (f32); => roundf); + (fn roundeven(x: f32) -> (f32); => roundevenf); (fn scalbn(x: f32, n: i32) -> (f32); => scalbnf); (fn sin(x: f32) -> (f32); => sinf); (fn sincos(x: f32) -> (f32, f32); => sincosf); @@ -167,6 +168,7 @@ libm_helper! { (fn remquo(x: f64, y: f64) -> (f64, i32); => remquo); (fn rint(x: f64) -> (f64); => rint); (fn round(x: f64) -> (f64); => round); + (fn roundevem(x: f64) -> (f64); => roundeven); (fn scalbn(x: f64, n: i32) -> (f64); => scalbn); (fn sin(x: f64) -> (f64); => sin); (fn sincos(x: f64) -> (f64, f64); => sincos); @@ -188,22 +190,23 @@ libm_helper! { f16, funcs: { // verify-sorted-start - (fn ceilf(x: f16) -> (f16); => ceilf16); + (fn ceil(x: f16) -> (f16); => ceilf16); (fn copysign(x: f16, y: f16) -> (f16); => copysignf16); (fn fabs(x: f16) -> (f16); => fabsf16); (fn fdim(x: f16, y: f16) -> (f16); => fdimf16); - (fn floorf(x: f16) -> (f16); => floorf16); - (fn fmaxf(x: f16, y: f16) -> (f16); => fmaxf16); - (fn fmaximum_numf16(x: f16, y: f16) -> (f16); => fmaximum_numf16); + (fn floor(x: f16) -> (f16); => floorf16); + (fn fmax(x: f16, y: f16) -> (f16); => fmaxf16); + (fn fmaximum_num(x: f16, y: f16) -> (f16); => fmaximum_numf16); (fn fmaximumf16(x: f16, y: f16) -> (f16); => fmaximumf16); - (fn fminf(x: f16, y: f16) -> (f16); => fminf16); - (fn fminimum_numf16(x: f16, y: f16) -> (f16); => fminimum_numf16); - (fn fminimumf16(x: f16, y: f16) -> (f16); => fminimumf16); - (fn fmodf(x: f16, y: f16) -> (f16); => fmodf16); - (fn ldexpf16(x: f16, n: i32) -> (f16); => ldexpf16); - (fn rintf(x: f16) -> (f16); => rintf16); - (fn roundf(x: f16) -> (f16); => roundf16); - (fn scalbnf16(x: f16, n: i32) -> (f16); => ldexpf16); + (fn fmin(x: f16, y: f16) -> (f16); => fminf16); + (fn fminimum(x: f16, y: f16) -> (f16); => fminimumf16); + (fn fminimum_num(x: f16, y: f16) -> (f16); => fminimum_numf16); + (fn fmod(x: f16, y: f16) -> (f16); => fmodf16); + (fn ldexp(x: f16, n: i32) -> (f16); => ldexpf16); + (fn rint(x: f16) -> (f16); => rintf16); + (fn round(x: f16) -> (f16); => roundf16); + (fn roundeven(x: f16) -> (f16); => roundevenf16); + (fn scalbn(x: f16, n: i32) -> (f16); => scalbnf16); (fn sqrtf(x: f16) -> (f16); => sqrtf16); (fn truncf(x: f16) -> (f16); => truncf16); // verify-sorted-end @@ -220,18 +223,19 @@ libm_helper! { (fn fabs(x: f128) -> (f128); => fabsf128); (fn fdim(x: f128, y: f128) -> (f128); => fdimf128); (fn floor(x: f128) -> (f128); => floorf128); - (fn fmaf128(x: f128, y: f128, z: f128) -> (f128); => fmaf128); + (fn fma(x: f128, y: f128, z: f128) -> (f128); => fmaf128); (fn fmax(x: f128, y: f128) -> (f128); => fmaxf128); - (fn fmaximum_numf128(x: f128, y: f128) -> (f128); => fmaximum_numf128); - (fn fmaximumf128(x: f128, y: f128) -> (f128); => fmaximumf128); + (fn fmaximum(x: f128, y: f128) -> (f128); => fmaximumf128); + (fn fmaximum_num(x: f128, y: f128) -> (f128); => fmaximum_numf128); (fn fmin(x: f128, y: f128) -> (f128); => fminf128); - (fn fminimum_numf128(x: f128, y: f128) -> (f128); => fminimum_numf128); - (fn fminimumf128(x: f128, y: f128) -> (f128); => fminimumf128); + (fn fminimum(x: f128, y: f128) -> (f128); => fminimumf128); + (fn fminimum_num(x: f128, y: f128) -> (f128); => fminimum_numf128); (fn fmod(x: f128, y: f128) -> (f128); => fmodf128); - (fn ldexpf128(x: f128, n: i32) -> (f128); => ldexpf128); + (fn ldexp(x: f128, n: i32) -> (f128); => ldexpf128); (fn rint(x: f128) -> (f128); => rintf128); (fn round(x: f128) -> (f128); => roundf128); - (fn scalbnf128(x: f128, n: i32) -> (f128); => ldexpf128); + (fn roundeven(x: f128) -> (f128); => roundevenf128); + (fn scalbn(x: f128, n: i32) -> (f128); => scalbnf128); (fn sqrt(x: f128) -> (f128); => sqrtf128); (fn trunc(x: f128) -> (f128); => truncf128); // verify-sorted-end diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 092f9317bc5..f224eba731c 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -30,7 +30,7 @@ pub use fmin::fmin; pub use fminimum::fminimum; pub use fminimum_num::fminimum_num; pub use fmod::fmod; -pub use rint::rint; +pub use rint::rint_round; pub use round::round; pub use scalbn::scalbn; pub use sqrt::sqrt; diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index 80ba1faac31..04e8f332f22 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -2,27 +2,31 @@ /* origin: musl src/math/rint.c */ use super::super::Float; +use super::super::support::{FpResult, Round}; -pub fn rint(x: F) -> F { +/// IEEE 754-2019 `roundToIntegralExact`, which respects rounding mode and raises inexact if +/// applicable. +pub fn rint_round(x: F, _round: Round) -> FpResult { let toint = F::ONE / F::EPSILON; let e = x.exp(); let positive = x.is_sign_positive(); // On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise, // the excess precission from x87 would cause an incorrect final result. - let use_force = cfg!(x86_no_sse) && F::BITS == 32 || F::BITS == 64; + let force = |x| { + if cfg!(x86_no_sse) && (F::BITS == 32 || F::BITS == 64) { force_eval!(x) } else { x } + }; - if e >= F::EXP_BIAS + F::SIG_BITS { + let res = if e >= F::EXP_BIAS + F::SIG_BITS { // No fractional part; exact result can be returned. x } else { - // Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode. + // Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode. For + // Rust this is always nearest, but ideally it would take `round` into account. let y = if positive { - let tmp = if use_force { force_eval!(x) } else { x } + toint; - (if use_force { force_eval!(tmp) } else { tmp } - toint) + force(force(x) + toint) - toint } else { - let tmp = if use_force { force_eval!(x) } else { x } - toint; - (if use_force { force_eval!(tmp) } else { tmp } + toint) + force(force(x) - toint) + toint }; if y == F::ZERO { @@ -31,42 +35,85 @@ pub fn rint(x: F) -> F { } else { y } - } + }; + + FpResult::ok(res) } #[cfg(test)] mod tests { use super::*; + use crate::support::{Hexf, Int, Status}; + + fn spec_test(cases: &[(F, F, Status)]) { + let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + + for x in roundtrip { + let FpResult { val, status } = rint_round(x, Round::Nearest); + assert_biteq!(val, x, "rint_round({})", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = rint_round(x, Round::Nearest); + assert_biteq!(val, res, "rint_round({})", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); + } + } #[test] - fn zeroes_f32() { - assert_biteq!(rint(0.0_f32), 0.0_f32); - assert_biteq!(rint(-0.0_f32), -0.0_f32); + #[cfg(f16_enabled)] + fn spec_tests_f16() { + let cases = []; + spec_test::(&cases); } #[test] - fn sanity_check_f32() { - assert_biteq!(rint(-1.0_f32), -1.0); - assert_biteq!(rint(2.8_f32), 3.0); - assert_biteq!(rint(-0.5_f32), -0.0); - assert_biteq!(rint(0.5_f32), 0.0); - assert_biteq!(rint(-1.5_f32), -2.0); - assert_biteq!(rint(1.5_f32), 2.0); + fn spec_tests_f32() { + let cases = [ + (0.1, 0.0, Status::OK), + (-0.1, -0.0, Status::OK), + (0.5, 0.0, Status::OK), + (-0.5, -0.0, Status::OK), + (0.9, 1.0, Status::OK), + (-0.9, -1.0, Status::OK), + (1.1, 1.0, Status::OK), + (-1.1, -1.0, Status::OK), + (1.5, 2.0, Status::OK), + (-1.5, -2.0, Status::OK), + (1.9, 2.0, Status::OK), + (-1.9, -2.0, Status::OK), + (2.8, 3.0, Status::OK), + (-2.8, -3.0, Status::OK), + ]; + spec_test::(&cases); } #[test] - fn zeroes_f64() { - assert_biteq!(rint(0.0_f64), 0.0_f64); - assert_biteq!(rint(-0.0_f64), -0.0_f64); + fn spec_tests_f64() { + let cases = [ + (0.1, 0.0, Status::OK), + (-0.1, -0.0, Status::OK), + (0.5, 0.0, Status::OK), + (-0.5, -0.0, Status::OK), + (0.9, 1.0, Status::OK), + (-0.9, -1.0, Status::OK), + (1.1, 1.0, Status::OK), + (-1.1, -1.0, Status::OK), + (1.5, 2.0, Status::OK), + (-1.5, -2.0, Status::OK), + (1.9, 2.0, Status::OK), + (-1.9, -2.0, Status::OK), + (2.8, 3.0, Status::OK), + (-2.8, -3.0, Status::OK), + ]; + spec_test::(&cases); } #[test] - fn sanity_check_f64() { - assert_biteq!(rint(-1.0_f64), -1.0); - assert_biteq!(rint(2.8_f64), 3.0); - assert_biteq!(rint(-0.5_f64), -0.0); - assert_biteq!(rint(0.5_f64), 0.0); - assert_biteq!(rint(-1.5_f64), -2.0); - assert_biteq!(rint(1.5_f64), 2.0); + #[cfg(f128_enabled)] + fn spec_tests_f128() { + let cases = []; + spec_test::(&cases); } } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 4e75292a6ef..e58d79adc41 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -207,8 +207,8 @@ mod remainderf; mod remquo; mod remquof; mod rint; -mod rintf; mod round; +mod roundeven; mod roundf; mod scalbn; mod scalbnf; @@ -313,9 +313,9 @@ pub use self::remainder::remainder; pub use self::remainderf::remainderf; pub use self::remquo::remquo; pub use self::remquof::remquof; -pub use self::rint::rint; -pub use self::rintf::rintf; +pub use self::rint::{rint, rintf}; pub use self::round::round; +pub use self::roundeven::{roundeven, roundevenf}; pub use self::roundf::roundf; pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; @@ -346,7 +346,6 @@ cfg_if! { mod floorf16; mod fmodf16; mod ldexpf16; - mod rintf16; mod roundf16; mod scalbnf16; mod sqrtf16; @@ -364,7 +363,8 @@ cfg_if! { pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16}; pub use self::fmodf16::fmodf16; pub use self::ldexpf16::ldexpf16; - pub use self::rintf16::rintf16; + pub use self::rint::rintf16; + pub use self::roundeven::roundevenf16; pub use self::roundf16::roundf16; pub use self::scalbnf16::scalbnf16; pub use self::sqrtf16::sqrtf16; @@ -384,7 +384,6 @@ cfg_if! { mod fmaf128; mod fmodf128; mod ldexpf128; - mod rintf128; mod roundf128; mod scalbnf128; mod sqrtf128; @@ -403,7 +402,8 @@ cfg_if! { pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; pub use self::fmodf128::fmodf128; pub use self::ldexpf128::ldexpf128; - pub use self::rintf128::rintf128; + pub use self::rint::rintf128; + pub use self::roundeven::roundevenf128; pub use self::roundf128::roundf128; pub use self::scalbnf128::scalbnf128; pub use self::sqrtf128::sqrtf128; diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index f409ec2821d..8a5cbeab497 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -1,3 +1,27 @@ +use super::support::Round; + +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf16(x: f16) -> f16 { + super::generic::rint_round(x, Round::Nearest).val +} + +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf(x: f32) -> f32 { + select_implementation! { + name: rintf, + use_arch: any( + all(target_arch = "wasm32", intrinsics_enabled), + all(target_arch = "aarch64", target_feature = "neon", target_endian = "little"), + ), + args: x, + } + + super::generic::rint_round(x, Round::Nearest).val +} + /// Round `x` to the nearest integer, breaking ties toward even. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rint(x: f64) -> f64 { @@ -10,5 +34,12 @@ pub fn rint(x: f64) -> f64 { args: x, } - super::generic::rint(x) + super::generic::rint_round(x, Round::Nearest).val +} + +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf128(x: f128) -> f128 { + super::generic::rint_round(x, Round::Nearest).val } diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs deleted file mode 100644 index 5e9f5f71876..00000000000 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ /dev/null @@ -1,14 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties toward even. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rintf(x: f32) -> f32 { - select_implementation! { - name: rintf, - use_arch: any( - all(target_arch = "wasm32", intrinsics_enabled), - all(target_arch = "aarch64", target_feature = "neon", target_endian = "little"), - ), - args: x, - } - - super::generic::rint(x) -} diff --git a/library/compiler-builtins/libm/src/math/rintf128.rs b/library/compiler-builtins/libm/src/math/rintf128.rs deleted file mode 100644 index 6b16fcd841a..00000000000 --- a/library/compiler-builtins/libm/src/math/rintf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties toward even. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rintf128(x: f128) -> f128 { - super::generic::rint(x) -} diff --git a/library/compiler-builtins/libm/src/math/rintf16.rs b/library/compiler-builtins/libm/src/math/rintf16.rs deleted file mode 100644 index 84d792561f7..00000000000 --- a/library/compiler-builtins/libm/src/math/rintf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties toward even. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rintf16(x: f16) -> f16 { - super::generic::rint(x) -} diff --git a/library/compiler-builtins/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/src/math/roundeven.rs new file mode 100644 index 00000000000..ec1738285e6 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundeven.rs @@ -0,0 +1,35 @@ +use super::support::{Float, Round}; + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf16(x: f16) -> f16 { + roundeven_impl(x) +} + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf(x: f32) -> f32 { + roundeven_impl(x) +} + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundeven(x: f64) -> f64 { + roundeven_impl(x) +} + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf128(x: f128) -> f128 { + roundeven_impl(x) +} + +pub fn roundeven_impl(x: F) -> F { + super::generic::rint_round(x, Round::Nearest).val +} -- cgit 1.4.1-3-g733a5 From 7db47c741c173b94730b3017851924b1e7525dea Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 11 Feb 2025 07:45:14 +0000 Subject: Check exact values for specified cases Inputs in `case_list` shouldn't hit xfails or increased ULP tolerance. Ensure that overrides are skipped when testing against MPFR or a specified value and that NaNs, if any, are checked bitwise. --- .../libm/crates/libm-test/src/gen/case_list.rs | 10 ++++++++-- .../libm/crates/libm-test/src/test_traits.rs | 14 +++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs index 8c7a735fa70..7cb9897d8d2 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs @@ -579,8 +579,11 @@ fn rint_cases() -> Vec> { TestCase::append_pairs( &mut v, &[ - // Failure on i586 + // Known failure on i586 + #[cfg(not(x86_no_sse))] ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), + #[cfg(x86_no_sse)] + ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))), ], ); v @@ -628,8 +631,11 @@ fn roundeven_cases() -> Vec> { TestCase::append_pairs( &mut v, &[ - // Failure on i586 + // Known failure on i586 + #[cfg(not(x86_no_sse))] ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), + #[cfg(x86_no_sse)] + ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))), ], ); v diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 1bd5bce162b..bba1fca64e6 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -12,7 +12,9 @@ use anyhow::{Context, anyhow, bail, ensure}; use libm::support::Hexf; use crate::precision::CheckAction; -use crate::{CheckCtx, Float, Int, MaybeOverride, SpecialCase, TestResult}; +use crate::{ + CheckBasis, CheckCtx, Float, GeneratorKind, Int, MaybeOverride, SpecialCase, TestResult, +}; /// Trait for calling a function with a tuple as arguments. /// @@ -207,6 +209,8 @@ where SpecialCase: MaybeOverride, { let (result, xfail_msg) = match SpecialCase::check_int(input, actual, expected, ctx) { + // `require_biteq` forbids overrides. + _ if ctx.gen_kind == GeneratorKind::List => (actual == expected, None), CheckAction::AssertSuccess => (actual == expected, None), CheckAction::AssertFailure(msg) => (actual != expected, Some(msg)), CheckAction::Custom(res) => return res, @@ -291,7 +295,12 @@ where let mut inner = || -> TestResult { let mut allowed_ulp = ctx.ulp; + // Forbid overrides if the items came from an explicit list, as long as we are checking + // against either MPFR or the result itself. + let require_biteq = ctx.gen_kind == GeneratorKind::List && ctx.basis != CheckBasis::Musl; + match SpecialCase::check_float(input, actual, expected, ctx) { + _ if require_biteq => (), CheckAction::AssertSuccess => (), CheckAction::AssertFailure(msg) => assert_failure_msg = Some(msg), CheckAction::Custom(res) => return res, @@ -301,6 +310,9 @@ where // Check when both are NaNs if actual.is_nan() && expected.is_nan() { + if require_biteq && ctx.basis == CheckBasis::None { + ensure!(actual.to_bits() == expected.to_bits(), "mismatched NaN bitpatterns"); + } // By default, NaNs have nothing special to check. return Ok(()); } else if actual.is_nan() || expected.is_nan() { -- cgit 1.4.1-3-g733a5 From aa26cab257d34a8d8786f6c607b67fd70b467ce6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 11 Feb 2025 15:40:17 +0000 Subject: Rename `Float::exp` to `Float::ex` Our function to get the exponent conflicts with the inherent `exp` function for `e^x`. Rename `exp` to `ex` to avoid confusion and usage problems. --- library/compiler-builtins/libm/etc/function-definitions.json | 3 +-- library/compiler-builtins/libm/src/math/generic/fma.rs | 6 +++--- library/compiler-builtins/libm/src/math/generic/fmod.rs | 4 ++-- library/compiler-builtins/libm/src/math/generic/rint.rs | 2 +- library/compiler-builtins/libm/src/math/generic/sqrt.rs | 2 +- library/compiler-builtins/libm/src/math/support/float_traits.rs | 4 ++-- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index a47aaad57c7..63d9927ad6f 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -206,8 +206,7 @@ }, "exp": { "sources": [ - "src/math/exp.rs", - "src/math/support/float_traits.rs" + "src/math/exp.rs" ], "type": "f64" }, diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs index 821aee09028..cb1061cc38b 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -249,7 +249,7 @@ where let xy: B = x.widen() * y.widen(); let mut result: B = xy + z.widen(); let mut ui: B::Int = result.to_bits(); - let re = result.exp(); + let re = result.ex(); let zb: B = z.widen(); let prec_diff = B::SIG_BITS - F::SIG_BITS; @@ -318,7 +318,7 @@ impl Norm { fn from_float(x: F) -> Self { let mut ix = x.to_bits(); - let mut e = x.exp() as i32; + let mut e = x.ex() as i32; let neg = x.is_sign_negative(); if e == 0 { // Normalize subnormals by multiplication @@ -326,7 +326,7 @@ impl Norm { let scale_f = F::from_parts(false, scale_i + F::EXP_BIAS, F::Int::ZERO); let scaled = x * scale_f; ix = scaled.to_bits(); - e = scaled.exp() as i32; + e = scaled.ex() as i32; e = if e == 0 { // If the exponent is still zero, the input was zero. Artifically set this value // such that the final `e` will exceed `ZERO_INF_NAN`. diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs index ca1cda38323..c74b593d559 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmod.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs @@ -9,8 +9,8 @@ pub fn fmod(x: F, y: F) -> F { let one = F::Int::ONE; let mut ix = x.to_bits(); let mut iy = y.to_bits(); - let mut ex = x.exp().signed(); - let mut ey = y.exp().signed(); + let mut ex = x.ex().signed(); + let mut ey = y.ex().signed(); let sx = ix & F::SIGN_MASK; if iy << 1 == zero || y.is_nan() || ex == F::EXP_SAT as i32 { diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index 04e8f332f22..2f8b2b36591 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -8,7 +8,7 @@ use super::super::support::{FpResult, Round}; /// applicable. pub fn rint_round(x: F, _round: Round) -> FpResult { let toint = F::ONE / F::EPSILON; - let e = x.exp(); + let e = x.ex(); let positive = x.is_sign_positive(); // On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise, diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index fdd612493b7..5918025bc67 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -109,7 +109,7 @@ where ix = scaled.to_bits(); match top { Exp::Shifted(ref mut v) => { - *v = scaled.exp(); + *v = scaled.ex(); *v = (*v).wrapping_sub(F::SIG_BITS); } Exp::NoShift(()) => { diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 42ce3148464..534ca9a07fa 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -128,13 +128,13 @@ pub trait Float: } /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. - fn exp(self) -> u32 { + fn ex(self) -> u32 { u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_SAT } /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. fn exp_unbiased(self) -> i32 { - self.exp().signed() - (Self::EXP_BIAS as i32) + self.ex().signed() - (Self::EXP_BIAS as i32) } /// Returns the significand with no implicit bit (or the "fractional" part) -- cgit 1.4.1-3-g733a5 From e106d63516b7e1a75c3e2e8873ac805b8833b192 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Feb 2025 03:48:20 +0000 Subject: Add a way to print inputs on failure When there is a panic in an extensive test, tracing down where it came from can be difficult since no information is provides (messeges are e.g. "attempted to subtract with overflow"). Resolve this by calling the functions within `panic::catch_unwind`, printing the input, and continuing. --- .../compiler-builtins/libm/crates/libm-test/src/op.rs | 6 ++++-- .../libm/crates/libm-test/src/test_traits.rs | 19 ++++++++++++++++++- .../libm/crates/libm-test/tests/compare_built_musl.rs | 2 +- .../libm/crates/libm-test/tests/multiprecision.rs | 2 +- .../libm/crates/libm-test/tests/standalone.rs | 2 +- .../libm/crates/libm-test/tests/z_extensive/run.rs | 2 +- .../compiler-builtins/libm/crates/util/src/main.rs | 2 +- 7 files changed, 27 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index 239c9a3e1fd..47d72ae58b3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -14,6 +14,7 @@ //! level. `Op` is also used as the name for generic parameters since it is terse. use std::fmt; +use std::panic::{RefUnwindSafe, UnwindSafe}; pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; @@ -64,7 +65,7 @@ pub trait MathOp { type CRet; /// The signature of the Rust function as a `fn(...) -> ...` type. - type RustFn: Copy; + type RustFn: Copy + UnwindSafe; /// Arguments passed to the Rust library function as a tuple. /// @@ -72,7 +73,8 @@ pub trait MathOp { /// to the Rust function. type RustArgs: Copy + TupleCall - + TupleCall; + + TupleCall + + RefUnwindSafe; /// Type returned from the Rust function. type RustRet: CheckOutput; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index bba1fca64e6..c560dade884 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -6,7 +6,8 @@ //! - `CheckOutput`: implemented on anything that is an output type for validation against an //! expected value. -use std::fmt; +use std::panic::{RefUnwindSafe, UnwindSafe}; +use std::{fmt, panic}; use anyhow::{Context, anyhow, bail, ensure}; use libm::support::Hexf; @@ -23,6 +24,22 @@ use crate::{ pub trait TupleCall: fmt::Debug { type Output; fn call(self, f: Func) -> Self::Output; + + /// Intercept panics and print the input to stderr before continuing. + fn call_intercept_panics(self, f: Func) -> Self::Output + where + Self: RefUnwindSafe + Copy, + Func: UnwindSafe, + { + let res = panic::catch_unwind(|| self.call(f)); + match res { + Ok(v) => v, + Err(e) => { + eprintln!("panic with the following input: {self:?}"); + panic::resume_unwind(e) + } + } + } } /// A trait to implement on any output type so we can verify it in a generic way. diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 2b16b9aa091..897dfc26e8c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -21,7 +21,7 @@ fn musl_runner( ) { for input in cases { let musl_res = input.call(musl_fn); - let crate_res = input.call(Op::ROUTINE); + let crate_res = input.call_intercept_panics(Op::ROUTINE); crate_res.validate(musl_res, input, ctx).unwrap(); } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index fd1f11610f5..0ab4b64da81 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -12,7 +12,7 @@ fn mp_runner(ctx: &CheckCtx, cases: impl Iterator( cases: impl Iterator, ) { for (input, expected) in cases { - let crate_res = input.call(Op::ROUTINE); + let crate_res = input.call_intercept_panics(Op::ROUTINE); crate_res.validate(expected, input, ctx).unwrap(); } } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs index a323c9110ee..786546a9d6d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs @@ -113,7 +113,7 @@ where for input in input_vec { // Test the input. let mp_res = Op::run(mp_vals, input); - let crate_res = input.call(Op::ROUTINE); + let crate_res = input.call_intercept_panics(Op::ROUTINE); crate_res.validate(mp_res, input, ctx)?; let completed = completed.fetch_add(1, Ordering::Relaxed) + 1; diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 130ac45319b..ef70ec9035b 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -59,7 +59,7 @@ macro_rules! handle_call { let libm_fn: ::RustFn = libm::$fn_name; let output = match $basis { - "libm" => input.call(libm_fn), + "libm" => input.call_intercept_panics(libm_fn), #[cfg(feature = "build-musl")] "musl" => { let musl_fn: ::CFn = -- cgit 1.4.1-3-g733a5 From dea2ed3d1d2e43df597f72e097e8fd439143e956 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Feb 2025 09:25:16 +0000 Subject: Scale test iteration count at a later point Currently the argument multiplier and large float multiplier happen before selecting count based on generator. However, this means that bivariate and trivariate functions don't get scaled at all (except for the special cased fma). Move this scaling to a later point. --- .../libm/crates/libm-test/src/run_cfg.rs | 37 ++++++++++++---------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 6b268997666..8e4fff53cb2 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -23,8 +23,8 @@ static EXTENSIVE_ITER_OVERRIDE: LazyLock> = LazyLock::new(|| { /// /// Contains the itentifier+generator combo to match on, plus the factor to reduce by. const EXTEMELY_SLOW_TESTS: &[(Identifier, GeneratorKind, u64)] = &[ - (Identifier::Fmodf128, GeneratorKind::QuickSpaced, 40), - (Identifier::Fmodf128, GeneratorKind::Extensive, 40), + (Identifier::Fmodf128, GeneratorKind::QuickSpaced, 50), + (Identifier::Fmodf128, GeneratorKind::Extensive, 50), ]; /// Maximum number of iterations to run for a single routine. @@ -200,15 +200,6 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { domain_iter_count = 100_000; } - // Larger float types get more iterations. - if t_env.large_float_ty { - domain_iter_count *= 4; - } - - // Functions with more arguments get more iterations. - let arg_multiplier = 1 << (t_env.input_count - 1); - domain_iter_count *= arg_multiplier; - // If we will be running tests against MPFR, we don't need to test as much against musl. // However, there are some platforms where we have to test against musl since MPFR can't be // built. @@ -228,6 +219,25 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { } }; + // Larger float types get more iterations. + if t_env.large_float_ty && ctx.gen_kind != GeneratorKind::Extensive { + if ctx.gen_kind == GeneratorKind::Extensive { + // Extensive already has a pretty high test count. + total_iterations *= 2; + } else { + total_iterations *= 4; + } + } + + // Functions with more arguments get more iterations. + let arg_multiplier = 1 << (t_env.input_count - 1); + total_iterations *= arg_multiplier; + + // FMA has a huge domain but is reasonably fast to run, so increase another 1.5x. + if ctx.base_name == BaseName::Fma { + total_iterations = 3 * total_iterations / 2; + } + // Some tests are significantly slower than others and need to be further reduced. if let Some((_id, _gen, scale)) = EXTEMELY_SLOW_TESTS .iter() @@ -239,11 +249,6 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { } } - // FMA has a huge domain but is reasonably fast to run, so increase iterations. - if ctx.base_name == BaseName::Fma { - total_iterations *= 4; - } - if cfg!(optimizations_enabled) { // Always run at least 10,000 tests. total_iterations = total_iterations.max(10_000); -- cgit 1.4.1-3-g733a5 From 212d463e89b0b2db7560fde4216b0c48a5448f34 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Feb 2025 10:12:24 +0000 Subject: fma refactor 1/3: remove math/fma.rs Done in stages so git tracks the moved file correctly. --- library/compiler-builtins/libm/src/math/fma.rs | 40 -------------------------- 1 file changed, 40 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/fma.rs diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs deleted file mode 100644 index 69cc3eb6726..00000000000 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ /dev/null @@ -1,40 +0,0 @@ -/// Fused multiply add (f64) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fma(x: f64, y: f64, z: f64) -> f64 { - return super::generic::fma(x, y, z); -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn fma_segfault() { - // These two inputs cause fma to segfault on release due to overflow: - assert_eq!( - fma( - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313 - ), - -0.00000000000000022204460492503126, - ); - - let result = fma(-0.992, -0.992, -0.992); - //force rounding to storage format on x87 to prevent superious errors. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let result = force_eval!(result); - assert_eq!(result, -0.007936000000000007,); - } - - #[test] - fn fma_sbb() { - assert_eq!(fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), -3991680619069439e277); - } - - #[test] - fn fma_underflow() { - assert_eq!(fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), 0.0,); - } -} -- cgit 1.4.1-3-g733a5 From bcbdb0b74f0acb339fb49902fe0ebecc4f2c3509 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Feb 2025 10:12:24 +0000 Subject: fma refactor 2/3: move math/generic/fma.rs to math/fma.rs Done in stages so git tracks the moved file correctly. --- library/compiler-builtins/libm/src/math/fma.rs | 420 +++++++++++++++++++++ .../compiler-builtins/libm/src/math/generic/fma.rs | 420 --------------------- 2 files changed, 420 insertions(+), 420 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fma.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/fma.rs diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs new file mode 100644 index 00000000000..cb1061cc38b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -0,0 +1,420 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/{fma,fmaf}.c. Ported to generic Rust algorithm in 2025, TG. */ + +use super::super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; +use super::super::{CastFrom, CastInto, DFloat, Float, HFloat, Int, MinInt}; + +/// Fused multiply-add that works when there is not a larger float size available. Currently this +/// is still specialized only for `f64`. Computes `(x * y) + z`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fma(x: F, y: F, z: F) -> F +where + F: Float, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, +{ + fma_round(x, y, z, Round::Nearest).val +} + +pub fn fma_round(x: F, y: F, z: F, _round: Round) -> FpResult +where + F: Float, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, +{ + let one = IntTy::::ONE; + let zero = IntTy::::ZERO; + + // Normalize such that the top of the mantissa is zero and we have a guard bit. + let nx = Norm::from_float(x); + let ny = Norm::from_float(y); + let nz = Norm::from_float(z); + + if nx.is_zero_nan_inf() || ny.is_zero_nan_inf() { + // Value will overflow, defer to non-fused operations. + return FpResult::ok(x * y + z); + } + + if nz.is_zero_nan_inf() { + if nz.is_zero() { + // Empty add component means we only need to multiply. + return FpResult::ok(x * y); + } + // `z` is NaN or infinity, which sets the result. + return FpResult::ok(z); + } + + // multiply: r = x * y + let zhi: F::Int; + let zlo: F::Int; + let (mut rlo, mut rhi) = nx.m.widen_mul(ny.m).lo_hi(); + + // Exponent result of multiplication + let mut e: i32 = nx.e + ny.e; + // Needed shift to align `z` to the multiplication result + let mut d: i32 = nz.e - e; + let sbits = F::BITS as i32; + + // Scale `z`. Shift `z <<= kz`, `r >>= kr`, so `kz+kr == d`, set `e = e+kr` (== ez-kz) + if d > 0 { + // The magnitude of `z` is larger than `x * y` + if d < sbits { + // Maximum shift of one `F::BITS` means shifted `z` will fit into `2 * F::BITS`. Shift + // it into `(zhi, zlo)`. No exponent adjustment necessary. + zlo = nz.m << d; + zhi = nz.m >> (sbits - d); + } else { + // Shift larger than `sbits`, `z` only needs the top half `zhi`. Place it there (acts + // as a shift by `sbits`). + zlo = zero; + zhi = nz.m; + d -= sbits; + + // `z`'s exponent is large enough that it now needs to be taken into account. + e = nz.e - sbits; + + if d == 0 { + // Exactly `sbits`, nothing to do + } else if d < sbits { + // Remaining shift fits within `sbits`. Leave `z` in place, shift `x * y` + rlo = (rhi << (sbits - d)) | (rlo >> d); + // Set the sticky bit + rlo |= IntTy::::from((rlo << (sbits - d)) != zero); + rhi = rhi >> d; + } else { + // `z`'s magnitude is enough that `x * y` is irrelevant. It was nonzero, so set + // the sticky bit. + rlo = one; + rhi = zero; + } + } + } else { + // `z`'s magnitude once shifted fits entirely within `zlo` + zhi = zero; + d = -d; + if d == 0 { + // No shift needed + zlo = nz.m; + } else if d < sbits { + // Shift s.t. `nz.m` fits into `zlo` + let sticky = IntTy::::from((nz.m << (sbits - d)) != zero); + zlo = (nz.m >> d) | sticky; + } else { + // Would be entirely shifted out, only set the sticky bit + zlo = one; + } + } + + /* addition */ + + let mut neg = nx.neg ^ ny.neg; + let samesign: bool = !neg ^ nz.neg; + let mut rhi_nonzero = true; + + if samesign { + // r += z + rlo = rlo.wrapping_add(zlo); + rhi += zhi + IntTy::::from(rlo < zlo); + } else { + // r -= z + let (res, borrow) = rlo.overflowing_sub(zlo); + rlo = res; + rhi = rhi.wrapping_sub(zhi.wrapping_add(IntTy::::from(borrow))); + if (rhi >> (F::BITS - 1)) != zero { + rlo = rlo.signed().wrapping_neg().unsigned(); + rhi = rhi.signed().wrapping_neg().unsigned() - IntTy::::from(rlo != zero); + neg = !neg; + } + rhi_nonzero = rhi != zero; + } + + /* Construct result */ + + // Shift result into `rhi`, left-aligned. Last bit is sticky + if rhi_nonzero { + // `d` > 0, need to shift both `rhi` and `rlo` into result + e += sbits; + d = rhi.leading_zeros() as i32 - 1; + rhi = (rhi << d) | (rlo >> (sbits - d)); + // Update sticky + rhi |= IntTy::::from((rlo << d) != zero); + } else if rlo != zero { + // `rhi` is zero, `rlo` is the entire result and needs to be shifted + d = rlo.leading_zeros() as i32 - 1; + if d < 0 { + // Shift and set sticky + rhi = (rlo >> 1) | (rlo & one); + } else { + rhi = rlo << d; + } + } else { + // exact +/- 0.0 + return FpResult::ok(x * y + z); + } + + e -= d; + + // Use int->float conversion to populate the significand. + // i is in [1 << (BITS - 2), (1 << (BITS - 1)) - 1] + let mut i: F::SignedInt = rhi.signed(); + + if neg { + i = -i; + } + + // `|r|` is in `[0x1p62,0x1p63]` for `f64` + let mut r: F = F::cast_from_lossy(i); + + /* Account for subnormal and rounding */ + + // Unbiased exponent for the maximum value of `r` + let max_pow = F::BITS - 1 + F::EXP_BIAS; + + let mut status = Status::OK; + + if e < -(max_pow as i32 - 2) { + // Result is subnormal before rounding + if e == -(max_pow as i32 - 1) { + let mut c = F::from_parts(false, max_pow, zero); + if neg { + c = -c; + } + + if r == c { + // Min normal after rounding, + status.set_underflow(true); + r = F::MIN_POSITIVE_NORMAL.copysign(r); + return FpResult::new(r, status); + } + + if (rhi << (F::SIG_BITS + 1)) != zero { + // Account for truncated bits. One bit will be lost in the `scalbn` call, add + // another top bit to avoid double rounding if inexact. + let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << (F::BITS - 2)); + i = iu.signed(); + + if neg { + i = -i; + } + + r = F::cast_from_lossy(i); + + // Remove the top bit + r = F::cast_from(2i8) * r - c; + status.set_underflow(true); + } + } else { + // Only round once when scaled + d = F::EXP_BITS as i32 - 1; + let sticky = IntTy::::from(rhi << (F::BITS as i32 - d) != zero); + i = (((rhi >> d) | sticky) << d).signed(); + + if neg { + i = -i; + } + + r = F::cast_from_lossy(i); + } + } + + // Use our exponent to scale the final value. + FpResult::new(super::scalbn(r, e), status) +} + +/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, +/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. +pub fn fma_wide(x: F, y: F, z: F) -> F +where + F: Float + HFloat, + B: Float + DFloat, + B::Int: CastInto, + i32: CastFrom, +{ + fma_wide_round(x, y, z, Round::Nearest).val +} + +pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult +where + F: Float + HFloat, + B: Float + DFloat, + B::Int: CastInto, + i32: CastFrom, +{ + let one = IntTy::::ONE; + + let xy: B = x.widen() * y.widen(); + let mut result: B = xy + z.widen(); + let mut ui: B::Int = result.to_bits(); + let re = result.ex(); + let zb: B = z.widen(); + + let prec_diff = B::SIG_BITS - F::SIG_BITS; + let excess_prec = ui & ((one << prec_diff) - one); + let halfway = one << (prec_diff - 1); + + // Common case: the larger precision is fine if... + // This is not a halfway case + if excess_prec != halfway + // Or the result is NaN + || re == B::EXP_SAT + // Or the result is exact + || (result - xy == zb && result - zb == xy) + // Or the mode is something other than round to nearest + || round != Round::Nearest + { + let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; + let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; + + let mut status = Status::OK; + + if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() { + // This branch is never hit; requires previous operations to set a status + status.set_inexact(false); + + result = xy + z.widen(); + if status.inexact() { + status.set_underflow(true); + } else { + status.set_inexact(true); + } + } + + return FpResult { val: result.narrow(), status }; + } + + let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; + let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy }; + if neg == (err < B::ZERO) { + ui += one; + } else { + ui -= one; + } + + FpResult::ok(B::from_bits(ui).narrow()) +} + +/// Representation of `F` that has handled subnormals. +#[derive(Clone, Copy, Debug)] +struct Norm { + /// Normalized significand with one guard bit, unsigned. + m: F::Int, + /// Exponent of the mantissa such that `m * 2^e = x`. Accounts for the shift in the mantissa + /// and the guard bit; that is, 1.0 will normalize as `m = 1 << 53` and `e = -53`. + e: i32, + neg: bool, +} + +impl Norm { + /// Unbias the exponent and account for the mantissa's precision, including the guard bit. + const EXP_UNBIAS: u32 = F::EXP_BIAS + F::SIG_BITS + 1; + + /// Values greater than this had a saturated exponent (infinity or NaN), OR were zero and we + /// adjusted the exponent such that it exceeds this threashold. + const ZERO_INF_NAN: u32 = F::EXP_SAT - Self::EXP_UNBIAS; + + fn from_float(x: F) -> Self { + let mut ix = x.to_bits(); + let mut e = x.ex() as i32; + let neg = x.is_sign_negative(); + if e == 0 { + // Normalize subnormals by multiplication + let scale_i = F::BITS - 1; + let scale_f = F::from_parts(false, scale_i + F::EXP_BIAS, F::Int::ZERO); + let scaled = x * scale_f; + ix = scaled.to_bits(); + e = scaled.ex() as i32; + e = if e == 0 { + // If the exponent is still zero, the input was zero. Artifically set this value + // such that the final `e` will exceed `ZERO_INF_NAN`. + 1 << F::EXP_BITS + } else { + // Otherwise, account for the scaling we just did. + e - scale_i as i32 + }; + } + + e -= Self::EXP_UNBIAS as i32; + + // Absolute value, set the implicit bit, and shift to create a guard bit + ix &= F::SIG_MASK; + ix |= F::IMPLICIT_BIT; + ix <<= 1; + + Self { m: ix, e, neg } + } + + /// True if the value was zero, infinity, or NaN. + fn is_zero_nan_inf(self) -> bool { + self.e >= Self::ZERO_INF_NAN as i32 + } + + /// The only value we have + fn is_zero(self) -> bool { + // The only exponent that strictly exceeds this value is our sentinel value for zero. + self.e > Self::ZERO_INF_NAN as i32 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn spec_test() + where + F: Float, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, + { + let x = F::from_bits(F::Int::ONE); + let y = F::from_bits(F::Int::ONE); + let z = F::ZERO; + + // 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of + // fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the + // exact result" + assert_biteq!(fma(x, y, z), F::ZERO); + assert_biteq!(fma(x, -y, z), F::NEG_ZERO); + assert_biteq!(fma(-x, y, z), F::NEG_ZERO); + assert_biteq!(fma(-x, -y, z), F::ZERO); + } + + #[test] + fn spec_test_f64() { + spec_test::(); + + let expect_underflow = [ + ( + hf64!("0x1.0p-1070"), + hf64!("0x1.0p-1070"), + hf64!("0x1.ffffffffffffp-1023"), + hf64!("0x0.ffffffffffff8p-1022"), + ), + ( + // FIXME: we raise underflow but this should only be inexact (based on C and + // `rustc_apfloat`). + hf64!("0x1.0p-1070"), + hf64!("0x1.0p-1070"), + hf64!("-0x1.0p-1022"), + hf64!("-0x1.0p-1022"), + ), + ]; + + for (x, y, z, res) in expect_underflow { + let FpResult { val, status } = fma_round(x, y, z, Round::Nearest); + assert_biteq!(val, res); + assert_eq!(status, Status::UNDERFLOW); + } + } + + #[test] + #[cfg(f128_enabled)] + fn spec_test_f128() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs deleted file mode 100644 index cb1061cc38b..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ /dev/null @@ -1,420 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/{fma,fmaf}.c. Ported to generic Rust algorithm in 2025, TG. */ - -use super::super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; -use super::super::{CastFrom, CastInto, DFloat, Float, HFloat, Int, MinInt}; - -/// Fused multiply-add that works when there is not a larger float size available. Currently this -/// is still specialized only for `f64`. Computes `(x * y) + z`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fma(x: F, y: F, z: F) -> F -where - F: Float, - F: CastFrom, - F: CastFrom, - F::Int: HInt, - u32: CastInto, -{ - fma_round(x, y, z, Round::Nearest).val -} - -pub fn fma_round(x: F, y: F, z: F, _round: Round) -> FpResult -where - F: Float, - F: CastFrom, - F: CastFrom, - F::Int: HInt, - u32: CastInto, -{ - let one = IntTy::::ONE; - let zero = IntTy::::ZERO; - - // Normalize such that the top of the mantissa is zero and we have a guard bit. - let nx = Norm::from_float(x); - let ny = Norm::from_float(y); - let nz = Norm::from_float(z); - - if nx.is_zero_nan_inf() || ny.is_zero_nan_inf() { - // Value will overflow, defer to non-fused operations. - return FpResult::ok(x * y + z); - } - - if nz.is_zero_nan_inf() { - if nz.is_zero() { - // Empty add component means we only need to multiply. - return FpResult::ok(x * y); - } - // `z` is NaN or infinity, which sets the result. - return FpResult::ok(z); - } - - // multiply: r = x * y - let zhi: F::Int; - let zlo: F::Int; - let (mut rlo, mut rhi) = nx.m.widen_mul(ny.m).lo_hi(); - - // Exponent result of multiplication - let mut e: i32 = nx.e + ny.e; - // Needed shift to align `z` to the multiplication result - let mut d: i32 = nz.e - e; - let sbits = F::BITS as i32; - - // Scale `z`. Shift `z <<= kz`, `r >>= kr`, so `kz+kr == d`, set `e = e+kr` (== ez-kz) - if d > 0 { - // The magnitude of `z` is larger than `x * y` - if d < sbits { - // Maximum shift of one `F::BITS` means shifted `z` will fit into `2 * F::BITS`. Shift - // it into `(zhi, zlo)`. No exponent adjustment necessary. - zlo = nz.m << d; - zhi = nz.m >> (sbits - d); - } else { - // Shift larger than `sbits`, `z` only needs the top half `zhi`. Place it there (acts - // as a shift by `sbits`). - zlo = zero; - zhi = nz.m; - d -= sbits; - - // `z`'s exponent is large enough that it now needs to be taken into account. - e = nz.e - sbits; - - if d == 0 { - // Exactly `sbits`, nothing to do - } else if d < sbits { - // Remaining shift fits within `sbits`. Leave `z` in place, shift `x * y` - rlo = (rhi << (sbits - d)) | (rlo >> d); - // Set the sticky bit - rlo |= IntTy::::from((rlo << (sbits - d)) != zero); - rhi = rhi >> d; - } else { - // `z`'s magnitude is enough that `x * y` is irrelevant. It was nonzero, so set - // the sticky bit. - rlo = one; - rhi = zero; - } - } - } else { - // `z`'s magnitude once shifted fits entirely within `zlo` - zhi = zero; - d = -d; - if d == 0 { - // No shift needed - zlo = nz.m; - } else if d < sbits { - // Shift s.t. `nz.m` fits into `zlo` - let sticky = IntTy::::from((nz.m << (sbits - d)) != zero); - zlo = (nz.m >> d) | sticky; - } else { - // Would be entirely shifted out, only set the sticky bit - zlo = one; - } - } - - /* addition */ - - let mut neg = nx.neg ^ ny.neg; - let samesign: bool = !neg ^ nz.neg; - let mut rhi_nonzero = true; - - if samesign { - // r += z - rlo = rlo.wrapping_add(zlo); - rhi += zhi + IntTy::::from(rlo < zlo); - } else { - // r -= z - let (res, borrow) = rlo.overflowing_sub(zlo); - rlo = res; - rhi = rhi.wrapping_sub(zhi.wrapping_add(IntTy::::from(borrow))); - if (rhi >> (F::BITS - 1)) != zero { - rlo = rlo.signed().wrapping_neg().unsigned(); - rhi = rhi.signed().wrapping_neg().unsigned() - IntTy::::from(rlo != zero); - neg = !neg; - } - rhi_nonzero = rhi != zero; - } - - /* Construct result */ - - // Shift result into `rhi`, left-aligned. Last bit is sticky - if rhi_nonzero { - // `d` > 0, need to shift both `rhi` and `rlo` into result - e += sbits; - d = rhi.leading_zeros() as i32 - 1; - rhi = (rhi << d) | (rlo >> (sbits - d)); - // Update sticky - rhi |= IntTy::::from((rlo << d) != zero); - } else if rlo != zero { - // `rhi` is zero, `rlo` is the entire result and needs to be shifted - d = rlo.leading_zeros() as i32 - 1; - if d < 0 { - // Shift and set sticky - rhi = (rlo >> 1) | (rlo & one); - } else { - rhi = rlo << d; - } - } else { - // exact +/- 0.0 - return FpResult::ok(x * y + z); - } - - e -= d; - - // Use int->float conversion to populate the significand. - // i is in [1 << (BITS - 2), (1 << (BITS - 1)) - 1] - let mut i: F::SignedInt = rhi.signed(); - - if neg { - i = -i; - } - - // `|r|` is in `[0x1p62,0x1p63]` for `f64` - let mut r: F = F::cast_from_lossy(i); - - /* Account for subnormal and rounding */ - - // Unbiased exponent for the maximum value of `r` - let max_pow = F::BITS - 1 + F::EXP_BIAS; - - let mut status = Status::OK; - - if e < -(max_pow as i32 - 2) { - // Result is subnormal before rounding - if e == -(max_pow as i32 - 1) { - let mut c = F::from_parts(false, max_pow, zero); - if neg { - c = -c; - } - - if r == c { - // Min normal after rounding, - status.set_underflow(true); - r = F::MIN_POSITIVE_NORMAL.copysign(r); - return FpResult::new(r, status); - } - - if (rhi << (F::SIG_BITS + 1)) != zero { - // Account for truncated bits. One bit will be lost in the `scalbn` call, add - // another top bit to avoid double rounding if inexact. - let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << (F::BITS - 2)); - i = iu.signed(); - - if neg { - i = -i; - } - - r = F::cast_from_lossy(i); - - // Remove the top bit - r = F::cast_from(2i8) * r - c; - status.set_underflow(true); - } - } else { - // Only round once when scaled - d = F::EXP_BITS as i32 - 1; - let sticky = IntTy::::from(rhi << (F::BITS as i32 - d) != zero); - i = (((rhi >> d) | sticky) << d).signed(); - - if neg { - i = -i; - } - - r = F::cast_from_lossy(i); - } - } - - // Use our exponent to scale the final value. - FpResult::new(super::scalbn(r, e), status) -} - -/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, -/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. -pub fn fma_wide(x: F, y: F, z: F) -> F -where - F: Float + HFloat, - B: Float + DFloat, - B::Int: CastInto, - i32: CastFrom, -{ - fma_wide_round(x, y, z, Round::Nearest).val -} - -pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult -where - F: Float + HFloat, - B: Float + DFloat, - B::Int: CastInto, - i32: CastFrom, -{ - let one = IntTy::::ONE; - - let xy: B = x.widen() * y.widen(); - let mut result: B = xy + z.widen(); - let mut ui: B::Int = result.to_bits(); - let re = result.ex(); - let zb: B = z.widen(); - - let prec_diff = B::SIG_BITS - F::SIG_BITS; - let excess_prec = ui & ((one << prec_diff) - one); - let halfway = one << (prec_diff - 1); - - // Common case: the larger precision is fine if... - // This is not a halfway case - if excess_prec != halfway - // Or the result is NaN - || re == B::EXP_SAT - // Or the result is exact - || (result - xy == zb && result - zb == xy) - // Or the mode is something other than round to nearest - || round != Round::Nearest - { - let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; - let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; - - let mut status = Status::OK; - - if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() { - // This branch is never hit; requires previous operations to set a status - status.set_inexact(false); - - result = xy + z.widen(); - if status.inexact() { - status.set_underflow(true); - } else { - status.set_inexact(true); - } - } - - return FpResult { val: result.narrow(), status }; - } - - let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; - let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy }; - if neg == (err < B::ZERO) { - ui += one; - } else { - ui -= one; - } - - FpResult::ok(B::from_bits(ui).narrow()) -} - -/// Representation of `F` that has handled subnormals. -#[derive(Clone, Copy, Debug)] -struct Norm { - /// Normalized significand with one guard bit, unsigned. - m: F::Int, - /// Exponent of the mantissa such that `m * 2^e = x`. Accounts for the shift in the mantissa - /// and the guard bit; that is, 1.0 will normalize as `m = 1 << 53` and `e = -53`. - e: i32, - neg: bool, -} - -impl Norm { - /// Unbias the exponent and account for the mantissa's precision, including the guard bit. - const EXP_UNBIAS: u32 = F::EXP_BIAS + F::SIG_BITS + 1; - - /// Values greater than this had a saturated exponent (infinity or NaN), OR were zero and we - /// adjusted the exponent such that it exceeds this threashold. - const ZERO_INF_NAN: u32 = F::EXP_SAT - Self::EXP_UNBIAS; - - fn from_float(x: F) -> Self { - let mut ix = x.to_bits(); - let mut e = x.ex() as i32; - let neg = x.is_sign_negative(); - if e == 0 { - // Normalize subnormals by multiplication - let scale_i = F::BITS - 1; - let scale_f = F::from_parts(false, scale_i + F::EXP_BIAS, F::Int::ZERO); - let scaled = x * scale_f; - ix = scaled.to_bits(); - e = scaled.ex() as i32; - e = if e == 0 { - // If the exponent is still zero, the input was zero. Artifically set this value - // such that the final `e` will exceed `ZERO_INF_NAN`. - 1 << F::EXP_BITS - } else { - // Otherwise, account for the scaling we just did. - e - scale_i as i32 - }; - } - - e -= Self::EXP_UNBIAS as i32; - - // Absolute value, set the implicit bit, and shift to create a guard bit - ix &= F::SIG_MASK; - ix |= F::IMPLICIT_BIT; - ix <<= 1; - - Self { m: ix, e, neg } - } - - /// True if the value was zero, infinity, or NaN. - fn is_zero_nan_inf(self) -> bool { - self.e >= Self::ZERO_INF_NAN as i32 - } - - /// The only value we have - fn is_zero(self) -> bool { - // The only exponent that strictly exceeds this value is our sentinel value for zero. - self.e > Self::ZERO_INF_NAN as i32 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn spec_test() - where - F: Float, - F: CastFrom, - F: CastFrom, - F::Int: HInt, - u32: CastInto, - { - let x = F::from_bits(F::Int::ONE); - let y = F::from_bits(F::Int::ONE); - let z = F::ZERO; - - // 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of - // fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the - // exact result" - assert_biteq!(fma(x, y, z), F::ZERO); - assert_biteq!(fma(x, -y, z), F::NEG_ZERO); - assert_biteq!(fma(-x, y, z), F::NEG_ZERO); - assert_biteq!(fma(-x, -y, z), F::ZERO); - } - - #[test] - fn spec_test_f64() { - spec_test::(); - - let expect_underflow = [ - ( - hf64!("0x1.0p-1070"), - hf64!("0x1.0p-1070"), - hf64!("0x1.ffffffffffffp-1023"), - hf64!("0x0.ffffffffffff8p-1022"), - ), - ( - // FIXME: we raise underflow but this should only be inexact (based on C and - // `rustc_apfloat`). - hf64!("0x1.0p-1070"), - hf64!("0x1.0p-1070"), - hf64!("-0x1.0p-1022"), - hf64!("-0x1.0p-1022"), - ), - ]; - - for (x, y, z, res) in expect_underflow { - let FpResult { val, status } = fma_round(x, y, z, Round::Nearest); - assert_biteq!(val, res); - assert_eq!(status, Status::UNDERFLOW); - } - } - - #[test] - #[cfg(f128_enabled)] - fn spec_test_f128() { - spec_test::(); - } -} -- cgit 1.4.1-3-g733a5 From 720ba18931628f28fb690a2936e53a32233f88d5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Feb 2025 09:55:04 +0000 Subject: fma refactor 3/3: combine `fma` public API with its implementation Similar to other recent changes, just put public API in the same file as its generic implementation. To keep things slightly cleaner, split the default implementation from the `_wide` implementation. Also introduces a stub `fmaf16`. --- .../libm/etc/function-definitions.json | 9 +- library/compiler-builtins/libm/src/math/fma.rs | 140 ++++++++------------- .../compiler-builtins/libm/src/math/fma_wide.rs | 97 ++++++++++++++ library/compiler-builtins/libm/src/math/fmaf.rs | 21 ---- library/compiler-builtins/libm/src/math/fmaf128.rs | 7 -- .../compiler-builtins/libm/src/math/generic/mod.rs | 2 - library/compiler-builtins/libm/src/math/mod.rs | 10 +- 7 files changed, 161 insertions(+), 125 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fma_wide.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmaf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmaf128.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 63d9927ad6f..a966852b112 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -343,22 +343,19 @@ }, "fma": { "sources": [ - "src/math/fma.rs", - "src/math/generic/fma.rs" + "src/math/fma.rs" ], "type": "f64" }, "fmaf": { "sources": [ - "src/math/fmaf.rs", - "src/math/generic/fma.rs" + "src/math/fma_wide.rs" ], "type": "f32" }, "fmaf128": { "sources": [ - "src/math/fmaf128.rs", - "src/math/generic/fma.rs" + "src/math/fma.rs" ], "type": "f128" }, diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index cb1061cc38b..a54984c936b 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -1,23 +1,28 @@ /* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/{fma,fmaf}.c. Ported to generic Rust algorithm in 2025, TG. */ +/* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ use super::super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; -use super::super::{CastFrom, CastInto, DFloat, Float, HFloat, Int, MinInt}; +use super::{CastFrom, CastInto, Float, Int, MinInt}; -/// Fused multiply-add that works when there is not a larger float size available. Currently this -/// is still specialized only for `f64`. Computes `(x * y) + z`. +/// Fused multiply add (f64) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fma(x: F, y: F, z: F) -> F -where - F: Float, - F: CastFrom, - F: CastFrom, - F::Int: HInt, - u32: CastInto, -{ +pub fn fma(x: f64, y: f64, z: f64) -> f64 { + fma_round(x, y, z, Round::Nearest).val +} + +/// Fused multiply add (f128) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { fma_round(x, y, z, Round::Nearest).val } +/// Fused multiply-add that works when there is not a larger float size available. Computes +/// `(x * y) + z`. pub fn fma_round(x: F, y: F, z: F, _round: Round) -> FpResult where F: Float, @@ -222,79 +227,7 @@ where } // Use our exponent to scale the final value. - FpResult::new(super::scalbn(r, e), status) -} - -/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, -/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. -pub fn fma_wide(x: F, y: F, z: F) -> F -where - F: Float + HFloat, - B: Float + DFloat, - B::Int: CastInto, - i32: CastFrom, -{ - fma_wide_round(x, y, z, Round::Nearest).val -} - -pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult -where - F: Float + HFloat, - B: Float + DFloat, - B::Int: CastInto, - i32: CastFrom, -{ - let one = IntTy::::ONE; - - let xy: B = x.widen() * y.widen(); - let mut result: B = xy + z.widen(); - let mut ui: B::Int = result.to_bits(); - let re = result.ex(); - let zb: B = z.widen(); - - let prec_diff = B::SIG_BITS - F::SIG_BITS; - let excess_prec = ui & ((one << prec_diff) - one); - let halfway = one << (prec_diff - 1); - - // Common case: the larger precision is fine if... - // This is not a halfway case - if excess_prec != halfway - // Or the result is NaN - || re == B::EXP_SAT - // Or the result is exact - || (result - xy == zb && result - zb == xy) - // Or the mode is something other than round to nearest - || round != Round::Nearest - { - let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; - let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; - - let mut status = Status::OK; - - if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() { - // This branch is never hit; requires previous operations to set a status - status.set_inexact(false); - - result = xy + z.widen(); - if status.inexact() { - status.set_underflow(true); - } else { - status.set_inexact(true); - } - } - - return FpResult { val: result.narrow(), status }; - } - - let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; - let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy }; - if neg == (err < B::ZERO) { - ui += one; - } else { - ui -= one; - } - - FpResult::ok(B::from_bits(ui).narrow()) + FpResult::new(super::generic::scalbn(r, e), status) } /// Representation of `F` that has handled subnormals. @@ -363,6 +296,7 @@ impl Norm { mod tests { use super::*; + /// Test the generic `fma_round` algorithm for a given float. fn spec_test() where F: Float, @@ -375,6 +309,8 @@ mod tests { let y = F::from_bits(F::Int::ONE); let z = F::ZERO; + let fma = |x, y, z| fma_round(x, y, z, Round::Nearest).val; + // 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of // fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the // exact result" @@ -384,6 +320,11 @@ mod tests { assert_biteq!(fma(-x, -y, z), F::ZERO); } + #[test] + fn spec_test_f32() { + spec_test::(); + } + #[test] fn spec_test_f64() { spec_test::(); @@ -417,4 +358,33 @@ mod tests { fn spec_test_f128() { spec_test::(); } + + #[test] + fn fma_segfault() { + // These two inputs cause fma to segfault on release due to overflow: + assert_eq!( + fma( + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313 + ), + -0.00000000000000022204460492503126, + ); + + let result = fma(-0.992, -0.992, -0.992); + //force rounding to storage format on x87 to prevent superious errors. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let result = force_eval!(result); + assert_eq!(result, -0.007936000000000007,); + } + + #[test] + fn fma_sbb() { + assert_eq!(fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), -3991680619069439e277); + } + + #[test] + fn fma_underflow() { + assert_eq!(fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), 0.0,); + } } diff --git a/library/compiler-builtins/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/src/math/fma_wide.rs new file mode 100644 index 00000000000..a8c1a548879 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fma_wide.rs @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fmaf.c. Ported to generic Rust algorithm in 2025, TG. */ + +use super::super::support::{FpResult, IntTy, Round, Status}; +use super::{CastFrom, CastInto, DFloat, Float, HFloat, MinInt}; + +// Placeholder so we can have `fmaf16` in the `Float` trait. +#[allow(unused)] +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 { + unimplemented!() +} + +/// Floating multiply add (f32) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { + fma_wide_round(x, y, z, Round::Nearest).val +} + +/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, +/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. +pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult +where + F: Float + HFloat, + B: Float + DFloat, + B::Int: CastInto, + i32: CastFrom, +{ + let one = IntTy::::ONE; + + let xy: B = x.widen() * y.widen(); + let mut result: B = xy + z.widen(); + let mut ui: B::Int = result.to_bits(); + let re = result.ex(); + let zb: B = z.widen(); + + let prec_diff = B::SIG_BITS - F::SIG_BITS; + let excess_prec = ui & ((one << prec_diff) - one); + let halfway = one << (prec_diff - 1); + + // Common case: the larger precision is fine if... + // This is not a halfway case + if excess_prec != halfway + // Or the result is NaN + || re == B::EXP_SAT + // Or the result is exact + || (result - xy == zb && result - zb == xy) + // Or the mode is something other than round to nearest + || round != Round::Nearest + { + let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; + let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; + + let mut status = Status::OK; + + if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() { + // This branch is never hit; requires previous operations to set a status + status.set_inexact(false); + + result = xy + z.widen(); + if status.inexact() { + status.set_underflow(true); + } else { + status.set_inexact(true); + } + } + + return FpResult { val: result.narrow(), status }; + } + + let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; + let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy }; + if neg == (err < B::ZERO) { + ui += one; + } else { + ui -= one; + } + + FpResult::ok(B::from_bits(ui).narrow()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn issue_263() { + let a = f32::from_bits(1266679807); + let b = f32::from_bits(1300234242); + let c = f32::from_bits(1115553792); + let expected = f32::from_bits(1501560833); + assert_eq!(fmaf(a, b, c), expected); + } +} diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs deleted file mode 100644 index 40d7f40d617..00000000000 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ /dev/null @@ -1,21 +0,0 @@ -/// Floating multiply add (f32) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation: -/// Computes the value (as if) to infinite precision and rounds once to the result format, -/// according to the rounding mode characterized by the value of FLT_ROUNDS. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { - super::generic::fma_wide(x, y, z) -} - -#[cfg(test)] -mod tests { - #[test] - fn issue_263() { - let a = f32::from_bits(1266679807); - let b = f32::from_bits(1300234242); - let c = f32::from_bits(1115553792); - let expected = f32::from_bits(1501560833); - assert_eq!(super::fmaf(a, b, c), expected); - } -} diff --git a/library/compiler-builtins/libm/src/math/fmaf128.rs b/library/compiler-builtins/libm/src/math/fmaf128.rs deleted file mode 100644 index 50f7360deb4..00000000000 --- a/library/compiler-builtins/libm/src/math/fmaf128.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Fused multiply add (f128) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { - return super::generic::fma(x, y, z); -} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index f224eba731c..9be185f809f 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -3,7 +3,6 @@ mod copysign; mod fabs; mod fdim; mod floor; -mod fma; mod fmax; mod fmaximum; mod fmaximum_num; @@ -22,7 +21,6 @@ pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; -pub use fma::{fma, fma_wide}; pub use fmax::fmax; pub use fmaximum::fmaximum; pub use fmaximum_num::fmaximum_num; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e58d79adc41..5fc8fa0b3cd 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -164,7 +164,7 @@ mod fdimf; mod floor; mod floorf; mod fma; -mod fmaf; +mod fma_wide; mod fmin_fmax; mod fminimum_fmaximum; mod fminimum_fmaximum_num; @@ -271,7 +271,7 @@ pub use self::fdimf::fdimf; pub use self::floor::floor; pub use self::floorf::floorf; pub use self::fma::fma; -pub use self::fmaf::fmaf; +pub use self::fma_wide::fmaf; pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; pub use self::fminimum_fmaximum::{fmaximum, fmaximumf, fminimum, fminimumf}; pub use self::fminimum_fmaximum_num::{fmaximum_num, fmaximum_numf, fminimum_num, fminimum_numf}; @@ -370,6 +370,9 @@ cfg_if! { pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; // verify-sorted-end + + #[allow(unused_imports)] + pub(crate) use self::fma_wide::fmaf16; } } @@ -381,7 +384,6 @@ cfg_if! { mod fabsf128; mod fdimf128; mod floorf128; - mod fmaf128; mod fmodf128; mod ldexpf128; mod roundf128; @@ -396,7 +398,7 @@ cfg_if! { pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; - pub use self::fmaf128::fmaf128; + pub use self::fma::fmaf128; pub use self::fmin_fmax::{fmaxf128, fminf128}; pub use self::fminimum_fmaximum::{fmaximumf128, fminimumf128}; pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; -- cgit 1.4.1-3-g733a5 From c01153d29b1917d0d1c805f98a751f3ecaf5952b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Feb 2025 10:16:48 +0000 Subject: Make `fma` a trait method on `Float` --- .../libm/crates/libm-test/src/f8_impl.rs | 4 ++++ .../libm/etc/function-definitions.json | 3 +-- .../compiler-builtins/libm/etc/update-api-list.py | 2 +- library/compiler-builtins/libm/src/math/cbrt.rs | 20 ++++------------- .../libm/src/math/support/float_traits.rs | 26 +++++++++++++++++----- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index 56ea0b72995..0683d839266 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -78,6 +78,10 @@ impl Float for f8 { libm::generic::copysign(self, other) } + fn fma(self, _y: Self, _z: Self) -> Self { + unimplemented!() + } + fn normalize(_significand: Self::Int) -> (i32, Self::Int) { unimplemented!() } diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index a966852b112..64a775ba9f1 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -130,8 +130,7 @@ "copysign": { "sources": [ "src/math/copysign.rs", - "src/math/generic/copysign.rs", - "src/math/support/float_traits.rs" + "src/math/generic/copysign.rs" ], "type": "f64" }, diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index c0b6e41d300..67d1b050861 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -24,7 +24,7 @@ ROOT_DIR = ETC_DIR.parent DIRECTORIES = [".github", "ci", "crates", "etc", "src"] # These files do not trigger a retest. -IGNORED_SOURCES = ["src/libm_helper.rs"] +IGNORED_SOURCES = ["src/libm_helper.rs", "src/math/support/float_traits.rs"] IndexTy: TypeAlias = dict[str, dict[str, Any]] """Type of the `index` item in rustdoc's JSON output""" diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index 8560d37abf3..9d3311cd6a8 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -103,11 +103,11 @@ pub fn cbrt_round(x: f64, round: Round) -> FpResult { * and rr an approximation of 1/zz. We now perform another iteration of * Newton-Raphson, this time with a linear approximation only. */ y2 = y * y; - let mut y2l: f64 = fmaf64(y, y, -y2); + let mut y2l: f64 = y.fma(y, -y2); /* y2 + y2l = y^2 exactly */ let mut y3: f64 = y2 * y; - let mut y3l: f64 = fmaf64(y, y2, -y3) + y * y2l; + let mut y3l: f64 = y.fma(y2, -y3) + y * y2l; /* y3 + y3l approximates y^3 with about 106 bits of accuracy */ h = ((y3 - zz) + y3l) * rr; @@ -132,9 +132,9 @@ pub fn cbrt_round(x: f64, round: Round) -> FpResult { cold_path(); y2 = y1 * y1; - y2l = fmaf64(y1, y1, -y2); + y2l = y1.fma(y1, -y2); y3 = y2 * y1; - y3l = fmaf64(y1, y2, -y3) + y1 * y2l; + y3l = y1.fma(y2, -y3) + y1 * y2l; h = ((y3 - zz) + y3l) * rr; dy = h * (y1 * u0); y = y1 - dy; @@ -198,18 +198,6 @@ pub fn cbrt_round(x: f64, round: Round) -> FpResult { FpResult::ok(f64::from_bits(cvt3)) } -fn fmaf64(x: f64, y: f64, z: f64) -> f64 { - #[cfg(intrinsics_enabled)] - { - return unsafe { core::intrinsics::fmaf64(x, y, z) }; - } - - #[cfg(not(intrinsics_enabled))] - { - return super::fma(x, y, z); - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 534ca9a07fa..96c209c852b 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -160,9 +160,11 @@ pub trait Float: fn abs(self) -> Self; /// Returns a number composed of the magnitude of self and the sign of sign. - #[allow(dead_code)] fn copysign(self, other: Self) -> Self; + /// Fused multiply add, rounding once. + fn fma(self, y: Self, z: Self) -> Self; + /// Returns (normalized exponent, normalized significand) #[allow(dead_code)] fn normalize(significand: Self::Int) -> (i32, Self::Int); @@ -184,7 +186,9 @@ macro_rules! float_impl { $sity:ident, $bits:expr, $significand_bits:expr, - $from_bits:path + $from_bits:path, + $fma_fn:ident, + $fma_intrinsic:ident ) => { impl Float for $ty { type Int = $ity; @@ -252,6 +256,16 @@ macro_rules! float_impl { } } } + fn fma(self, y: Self, z: Self) -> Self { + cfg_if! { + // fma is not yet available in `core` + if #[cfg(intrinsics_enabled)] { + unsafe{ core::intrinsics::$fma_intrinsic(self, y, z) } + } else { + super::super::$fma_fn(self, y, z) + } + } + } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) @@ -261,11 +275,11 @@ macro_rules! float_impl { } #[cfg(f16_enabled)] -float_impl!(f16, u16, i16, 16, 10, f16::from_bits); -float_impl!(f32, u32, i32, 32, 23, f32_from_bits); -float_impl!(f64, u64, i64, 64, 52, f64_from_bits); +float_impl!(f16, u16, i16, 16, 10, f16::from_bits, fmaf16, fmaf16); +float_impl!(f32, u32, i32, 32, 23, f32_from_bits, fmaf, fmaf32); +float_impl!(f64, u64, i64, 64, 52, f64_from_bits, fma, fmaf64); #[cfg(f128_enabled)] -float_impl!(f128, u128, i128, 128, 112, f128::from_bits); +float_impl!(f128, u128, i128, 128, 112, f128::from_bits, fmaf128, fmaf128); /* FIXME(msrv): vendor some things that are not const stable at our MSRV */ -- cgit 1.4.1-3-g733a5 From bd41642818aa2f1ba3dea5a2ee0358bef3cd8f92 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Feb 2025 21:06:15 +0000 Subject: Use `git ls-files` rather than manually globbing for tidy This avoids matching build directories, ignored files, and submodules. --- .../compiler-builtins/libm/etc/update-api-list.py | 54 +++++++++++----------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index 67d1b050861..b4ce2c453ce 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -12,7 +12,7 @@ import re import subprocess as sp import sys from dataclasses import dataclass -from glob import glob, iglob +from glob import glob from pathlib import Path from typing import Any, Callable, TypeAlias @@ -20,9 +20,6 @@ SELF_PATH = Path(__file__) ETC_DIR = SELF_PATH.parent ROOT_DIR = ETC_DIR.parent -# Loose approximation of what gets checked in to git, without needing `git ls-files`. -DIRECTORIES = [".github", "ci", "crates", "etc", "src"] - # These files do not trigger a retest. IGNORED_SOURCES = ["src/libm_helper.rs", "src/math/support/float_traits.rs"] @@ -190,30 +187,31 @@ class Crate: """In each file, check annotations indicating blocks of code should be sorted or should include all public API. """ - for dirname in DIRECTORIES: - dir = ROOT_DIR.joinpath(dirname) - for fname in iglob("**", root_dir=dir, recursive=True): - fpath = dir.joinpath(fname) - if fpath.is_dir() or fpath == SELF_PATH: - continue - - lines = fpath.read_text().splitlines() - - validate_delimited_block( - fpath, - lines, - "verify-sorted-start", - "verify-sorted-end", - ensure_sorted, - ) - - validate_delimited_block( - fpath, - lines, - "verify-apilist-start", - "verify-apilist-end", - lambda p, n, lines: self.ensure_contains_api(p, n, lines), - ) + + flist = sp.check_output(["git", "ls-files"], cwd=ROOT_DIR, text=True) + + for path in flist.splitlines(): + fpath = ROOT_DIR.joinpath(path) + if fpath.is_dir() or fpath == SELF_PATH: + continue + + lines = fpath.read_text().splitlines() + + validate_delimited_block( + fpath, + lines, + "verify-sorted-start", + "verify-sorted-end", + ensure_sorted, + ) + + validate_delimited_block( + fpath, + lines, + "verify-apilist-start", + "verify-apilist-end", + lambda p, n, lines: self.ensure_contains_api(p, n, lines), + ) def ensure_contains_api(self, fpath: Path, line_num: int, lines: list[str]): """Given a list of strings, ensure that each public function we have is named -- cgit 1.4.1-3-g733a5 From 37da10edded0cd384769cbfc0c00e31a928bac66 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Feb 2025 15:39:18 -0500 Subject: ci: Update actions/cache to v4 Github has deprecated v2 so this needs to be bumped. --- library/compiler-builtins/.github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index fee5c45eaf0..a801f2722b5 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -117,7 +117,7 @@ jobs: with: key: ${{ matrix.target }} - name: Cache Docker layers - uses: actions/cache@v2 + uses: actions/cache@v4 if: matrix.os == 'ubuntu-latest' with: path: /tmp/.buildx-cache -- cgit 1.4.1-3-g733a5 From 4517c7ea90372047d5fbc7d84fcbf69e512b38a1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Feb 2025 15:48:46 -0500 Subject: ci: Pin the nightly toolchain for i686-pc-windows-gnu Pin i686-pc-windows-gnu to nightly-2025-02-07 until [1] is resolved. [1]: https://github.com/rust-lang/rust/issues/136795 --- library/compiler-builtins/.github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index a801f2722b5..1575730fe63 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -98,7 +98,8 @@ jobs: test_verbatim: 1 - target: i686-pc-windows-gnu os: windows-latest - rust: nightly-i686-gnu + # FIXME: pinned due to https://github.com/rust-lang/rust/issues/136795 + rust: nightly-2025-02-07-i686-gnu - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu -- cgit 1.4.1-3-g733a5 From bade6290c8530005f06703a2bc2c4d595917c183 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Feb 2025 15:26:07 -0500 Subject: ci: Pin the nightly toolchain for aarch64-unknown-linux-gnu Pin aarch64-unknown-linux-gnu to nightly-2025-02-07 until [1] is resolved. [1]: https://github.com/llvm/llvm-project/issues/127804 --- library/compiler-builtins/.github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 1575730fe63..c179a339127 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -20,7 +20,8 @@ jobs: rust: nightly - target: aarch64-unknown-linux-gnu os: ubuntu-latest - rust: nightly + # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 + rust: nightly-2025-02-07 - target: aarch64-pc-windows-msvc os: windows-latest rust: nightly -- cgit 1.4.1-3-g733a5 From 2b6de7a68fb00157be0a3aa72612008dfe774cf4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Feb 2025 14:29:37 +0100 Subject: remove win64_128bit_abi_hack --- library/compiler-builtins/src/float/conv.rs | 4 -- library/compiler-builtins/src/int/sdiv.rs | 4 +- library/compiler-builtins/src/int/udiv.rs | 3 -- library/compiler-builtins/src/macros.rs | 71 ----------------------------- 4 files changed, 2 insertions(+), 80 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 4f52ac7120d..42a526bd524 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -403,7 +403,6 @@ intrinsics! { float_to_unsigned_int(f) } - #[win64_128bit_abi_hack] pub extern "C" fn __fixunssfti(f: f32) -> u128 { float_to_unsigned_int(f) } @@ -418,7 +417,6 @@ intrinsics! { float_to_unsigned_int(f) } - #[win64_128bit_abi_hack] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { float_to_unsigned_int(f) } @@ -454,7 +452,6 @@ intrinsics! { float_to_signed_int(f) } - #[win64_128bit_abi_hack] pub extern "C" fn __fixsfti(f: f32) -> i128 { float_to_signed_int(f) } @@ -469,7 +466,6 @@ intrinsics! { float_to_signed_int(f) } - #[win64_128bit_abi_hack] pub extern "C" fn __fixdfti(f: f64) -> i128 { float_to_signed_int(f) } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 9d316c76eca..9630c7d7de3 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -165,5 +165,5 @@ sdivmod!( i128, maybe_use_optimized_c_shim ); -sdiv!(__udivti3, __divti3, u128, i128, win64_128bit_abi_hack); -smod!(__umodti3, __modti3, u128, i128, win64_128bit_abi_hack); +sdiv!(__udivti3, __divti3, u128, i128,); +smod!(__umodti3, __modti3, u128, i128,); diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index c891eede4b1..1fa761212b2 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -58,7 +58,6 @@ intrinsics! { // the existence of `u128_div_rem` to get 32-bit SPARC to compile, see `u128_divide_sparc` docs. #[avr_skip] - #[win64_128bit_abi_hack] /// Returns `n / d` pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { @@ -70,7 +69,6 @@ intrinsics! { } #[avr_skip] - #[win64_128bit_abi_hack] /// Returns `n % d` pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { @@ -84,7 +82,6 @@ intrinsics! { } #[avr_skip] - #[win64_128bit_abi_hack] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index f51e49e9876..88b54e82ca0 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -60,9 +60,6 @@ macro_rules! public_test_dep { /// the specified ABI everywhere else. /// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the /// `"unadjusted"` abi on Win64 and the specified abi elsewhere. -/// * `win64_128bit_abi_hack` - this attribute is used for 128-bit integer -/// intrinsics where the ABI is slightly tweaked on Windows platforms, but -/// it's a normal ABI elsewhere for returning a 128 bit integer. /// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM /// their otherwise typical names to other prefixed ones. /// * `ppc_alias` - changes the name of the symbol on PowerPC platforms without @@ -231,51 +228,6 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // Some intrinsics on win64 which return a 128-bit integer have an.. unusual - // calling convention. That's managed here with this "abi hack" which alters - // the generated symbol's ABI. - // - // This will still define a function in this crate with the given name and - // signature, but the actual symbol for the intrinsic may have a slightly - // different ABI on win64. - ( - #[win64_128bit_abi_hack] - $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - - #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64", not(feature = "mangled-names")))] - mod $name { - #[no_mangle] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] - extern $abi fn $name( $($argname: $ty),* ) - -> $crate::macros::win64_128bit_abi_hack::U64x2 - { - let e: $($ret)? = super::$name($($argname),*); - $crate::macros::win64_128bit_abi_hack::U64x2::from(e) - } - } - - #[cfg(not(all(any(windows, target_os = "uefi"), target_arch = "x86_64")))] - intrinsics! { - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - // `arm_aeabi_alias` would conflict with `f16_apple_{arg,ret}_abi` not handled here. Avoid macro ambiguity by combining in a // single `#[]`. ( @@ -576,26 +528,3 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); } - -// Hack for LLVM expectations for ABI on windows. This is used by the -// `#[win64_128bit_abi_hack]` attribute recognized above -#[cfg(all(any(windows, target_os = "uefi"), target_pointer_width = "64"))] -pub mod win64_128bit_abi_hack { - #[repr(simd)] - pub struct U64x2([u64; 2]); - - impl From for U64x2 { - fn from(i: i128) -> U64x2 { - use crate::int::DInt; - let j = i as u128; - U64x2([j.lo(), j.hi()]) - } - } - - impl From for U64x2 { - fn from(i: u128) -> U64x2 { - use crate::int::DInt; - U64x2([i.lo(), i.hi()]) - } - } -} -- cgit 1.4.1-3-g733a5 From f851256581d697ee1b211a57403ba4dd468d7f52 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 19 Feb 2025 20:45:07 +0000 Subject: chore: release v0.1.147 --- library/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index d6962dc5b5e..a3890c6ce73 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.147](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.146...compiler_builtins-v0.1.147) - 2025-02-19 + +### Other + +- remove win64_128bit_abi_hack + ## [0.1.146](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.145...compiler_builtins-v0.1.146) - 2025-02-06 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c93ca563c4e..ff1a10fc626 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.146" +version = "0.1.147" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 54e7ff15c08ee84db226d4e79ad703c689588ffc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 23 Feb 2025 08:21:22 +0000 Subject: Revert "ci: Pin the nightly toolchain for i686-pc-windows-gnu" Since [1], the issue should be resolved so the workaround can be dropped. This reverts commit 88e83b96ad09f3cf9e2d1b4543a7d43f9c5a77c0. [1]: https://github.com/rust-lang/compiler-builtins/pull/759 --- library/compiler-builtins/.github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index c179a339127..7336efc4224 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -99,8 +99,7 @@ jobs: test_verbatim: 1 - target: i686-pc-windows-gnu os: windows-latest - # FIXME: pinned due to https://github.com/rust-lang/rust/issues/136795 - rust: nightly-2025-02-07-i686-gnu + rust: nightly-i686-gnu - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu -- cgit 1.4.1-3-g733a5 From c32bc8398a546c0346dbb3e563c8658d1d772349 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 01:23:37 +0000 Subject: ci: Pin the nightly toolchain for aarch64 jobs Pin aarch64-unknown-linux-gnu and aarch64-apple-darwin to nightly-2025-02-07 until [1] makes it to a Rust nightly. [1]: https://github.com/llvm/llvm-project/issues/127804 --- library/compiler-builtins/libm/.github/workflows/main.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index f066f4a8c1f..e86f936f74f 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -22,8 +22,12 @@ jobs: include: - target: aarch64-apple-darwin os: macos-15 + # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 + channel: nightly-2025-02-07 - target: aarch64-unknown-linux-gnu os: ubuntu-24.04-arm + # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 + channel: nightly-2025-02-07 - target: aarch64-pc-windows-msvc os: windows-2025 build_only: 1 # Can't run on x86 hosts -- cgit 1.4.1-3-g733a5 From ba8f07282e233413ed34aaf7576690265aeed25f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 00:01:04 +0000 Subject: Make the compiler-builtins test more accurately mirror compiler-builtins In `compiler-builtins`, `libm` is contained within a `math` module. The smoke test in this repo has a slightly different layout so some things were passing that shouldn't be. Change module layouts in `compiler-builtins-smoke-test` to match `compiler-builtins` and update a few instances of broken paths. --- .../crates/compiler-builtins-smoke-test/src/lib.rs | 185 +-------------------- .../compiler-builtins-smoke-test/src/math.rs | 182 ++++++++++++++++++++ library/compiler-builtins/libm/src/math/fma.rs | 2 +- .../compiler-builtins/libm/src/math/fma_wide.rs | 2 +- 4 files changed, 186 insertions(+), 185 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index 77a4666a102..f9e6e75a870 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -10,187 +10,6 @@ #![allow(internal_features)] #![no_std] -#[allow(dead_code)] -#[allow(clippy::all)] // We don't get `libm`'s list of `allow`s, so just ignore Clippy. -#[path = "../../../src/math/mod.rs"] -pub mod libm; - -use core::ffi::c_int; - +mod math; // Required for macro paths. -use libm::support; - -/// Mark functions `#[no_mangle]` and with the C ABI. -macro_rules! no_mangle { - ($( $name:ident( $($tt:tt)+ ) -> $ret:ty; )+) => { - $( no_mangle!(@inner $name( $($tt)+ ) -> $ret); )+ - }; - - // Handle simple functions with single return types - (@inner $name:ident( $($arg:ident: $aty:ty),+ ) -> $ret:ty) => { - #[no_mangle] - extern "C" fn $name($($arg: $aty),+) -> $ret { - libm::$name($($arg),+) - } - }; - - - // Functions with `&mut` return values need to be handled differently, use `|` to - // separate inputs vs. outputs. - ( - @inner $name:ident( $($arg:ident: $aty:ty),+ | $($rarg:ident: $rty:ty),+) -> $ret:ty - ) => { - #[no_mangle] - extern "C" fn $name($($arg: $aty,)+ $($rarg: $rty),+) -> $ret { - let ret; - (ret, $(*$rarg),+) = libm::$name($($arg),+); - ret - } - }; -} - -no_mangle! { - frexp(x: f64 | y: &mut c_int) -> f64; - frexpf(x: f32 | y: &mut c_int) -> f32; - acos(x: f64) -> f64; - acosf(x: f32) -> f32; - acosh(x: f64) -> f64; - acoshf(x: f32) -> f32; - asin(x: f64) -> f64; - asinf(x: f32) -> f32; - asinh(x: f64) -> f64; - asinhf(x: f32) -> f32; - atan(x: f64) -> f64; - atan2(x: f64, y: f64) -> f64; - atan2f(x: f32, y: f32) -> f32; - atanf(x: f32) -> f32; - atanh(x: f64) -> f64; - atanhf(x: f32) -> f32; - cbrt(x: f64) -> f64; - cbrtf(x: f32) -> f32; - ceil(x: f64) -> f64; - ceilf(x: f32) -> f32; - ceilf128(x: f128) -> f128; - ceilf16(x: f16) -> f16; - copysign(x: f64, y: f64) -> f64; - copysignf(x: f32, y: f32) -> f32; - copysignf128(x: f128, y: f128) -> f128; - copysignf16(x: f16, y: f16) -> f16; - cos(x: f64) -> f64; - cosf(x: f32) -> f32; - cosh(x: f64) -> f64; - coshf(x: f32) -> f32; - erf(x: f64) -> f64; - erfc(x: f64) -> f64; - erfcf(x: f32) -> f32; - erff(x: f32) -> f32; - exp(x: f64) -> f64; - exp10(x: f64) -> f64; - exp10f(x: f32) -> f32; - exp2(x: f64) -> f64; - exp2f(x: f32) -> f32; - expf(x: f32) -> f32; - expm1(x: f64) -> f64; - expm1f(x: f32) -> f32; - fabs(x: f64) -> f64; - fabsf(x: f32) -> f32; - fabsf128(x: f128) -> f128; - fabsf16(x: f16) -> f16; - fdim(x: f64, y: f64) -> f64; - fdimf(x: f32, y: f32) -> f32; - fdimf128(x: f128, y: f128) -> f128; - fdimf16(x: f16, y: f16) -> f16; - floor(x: f64) -> f64; - floorf(x: f32) -> f32; - floorf128(x: f128) -> f128; - floorf16(x: f16) -> f16; - fma(x: f64, y: f64, z: f64) -> f64; - fmaf(x: f32, y: f32, z: f32) -> f32; - fmax(x: f64, y: f64) -> f64; - fmaxf(x: f32, y: f32) -> f32; - fmin(x: f64, y: f64) -> f64; - fminf(x: f32, y: f32) -> f32; - fmod(x: f64, y: f64) -> f64; - fmodf(x: f32, y: f32) -> f32; - hypot(x: f64, y: f64) -> f64; - hypotf(x: f32, y: f32) -> f32; - ilogb(x: f64) -> c_int; - ilogbf(x: f32) -> c_int; - j0(x: f64) -> f64; - j0f(x: f32) -> f32; - j1(x: f64) -> f64; - j1f(x: f32) -> f32; - jn(x: c_int, y: f64) -> f64; - jnf(x: c_int, y: f32) -> f32; - ldexp(x: f64, y: c_int) -> f64; - ldexpf(x: f32, y: c_int) -> f32; - lgamma(x: f64) -> f64; - lgamma_r(x: f64 | r: &mut c_int) -> f64; - lgammaf(x: f32) -> f32; - lgammaf_r(x: f32 | r: &mut c_int) -> f32; - log(x: f64) -> f64; - log10(x: f64) -> f64; - log10f(x: f32) -> f32; - log1p(x: f64) -> f64; - log1pf(x: f32) -> f32; - log2(x: f64) -> f64; - log2f(x: f32) -> f32; - logf(x: f32) -> f32; - modf(x: f64 | r: &mut f64) -> f64; - modff(x: f32 | r: &mut f32) -> f32; - nextafter(x: f64, y: f64) -> f64; - nextafterf(x: f32, y: f32) -> f32; - pow(x: f64, y: f64) -> f64; - powf(x: f32, y: f32) -> f32; - remainder(x: f64, y: f64) -> f64; - remainderf(x: f32, y: f32) -> f32; - remquo(x: f64, y: f64 | q: &mut c_int) -> f64; - remquof(x: f32, y: f32 | q: &mut c_int) -> f32; - rint(x: f64) -> f64; - rintf(x: f32) -> f32; - rintf128(x: f128) -> f128; - rintf16(x: f16) -> f16; - round(x: f64) -> f64; - roundf(x: f32) -> f32; - scalbn(x: f64, y: c_int) -> f64; - scalbnf(x: f32, y: c_int) -> f32; - sin(x: f64) -> f64; - sinf(x: f32) -> f32; - sinh(x: f64) -> f64; - sinhf(x: f32) -> f32; - sqrt(x: f64) -> f64; - sqrtf(x: f32) -> f32; - tan(x: f64) -> f64; - tanf(x: f32) -> f32; - tanh(x: f64) -> f64; - tanhf(x: f32) -> f32; - tgamma(x: f64) -> f64; - tgammaf(x: f32) -> f32; - trunc(x: f64) -> f64; - truncf(x: f32) -> f32; - truncf128(x: f128) -> f128; - truncf16(x: f16) -> f16; - y0(x: f64) -> f64; - y0f(x: f32) -> f32; - y1(x: f64) -> f64; - y1f(x: f32) -> f32; - yn(x: c_int, y: f64) -> f64; - ynf(x: c_int, y: f32) -> f32; -} - -/* sincos has no direct return type, not worth handling in the macro */ - -#[no_mangle] -extern "C" fn sincos(x: f64, s: &mut f64, c: &mut f64) { - (*s, *c) = libm::sincos(x); -} - -#[no_mangle] -extern "C" fn sincosf(x: f32, s: &mut f32, c: &mut f32) { - (*s, *c) = libm::sincosf(x); -} - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} +use math::libm::support; diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs new file mode 100644 index 00000000000..7e0146998aa --- /dev/null +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs @@ -0,0 +1,182 @@ +use core::ffi::c_int; + +#[allow(dead_code)] +#[allow(clippy::all)] // We don't get `libm`'s list of `allow`s, so just ignore Clippy. +#[allow(unused_imports)] +#[path = "../../../src/math/mod.rs"] +pub mod libm; + +/// Mark functions `#[no_mangle]` and with the C ABI. +macro_rules! no_mangle { + ($( $name:ident( $($tt:tt)+ ) -> $ret:ty; )+) => { + $( no_mangle!(@inner $name( $($tt)+ ) -> $ret); )+ + }; + + // Handle simple functions with single return types + (@inner $name:ident( $($arg:ident: $aty:ty),+ ) -> $ret:ty) => { + #[no_mangle] + extern "C" fn $name($($arg: $aty),+) -> $ret { + libm::$name($($arg),+) + } + }; + + + // Functions with `&mut` return values need to be handled differently, use `|` to + // separate inputs vs. outputs. + ( + @inner $name:ident( $($arg:ident: $aty:ty),+ | $($rarg:ident: $rty:ty),+) -> $ret:ty + ) => { + #[no_mangle] + extern "C" fn $name($($arg: $aty,)+ $($rarg: $rty),+) -> $ret { + let ret; + (ret, $(*$rarg),+) = libm::$name($($arg),+); + ret + } + }; +} + +no_mangle! { + frexp(x: f64 | y: &mut c_int) -> f64; + frexpf(x: f32 | y: &mut c_int) -> f32; + acos(x: f64) -> f64; + acosf(x: f32) -> f32; + acosh(x: f64) -> f64; + acoshf(x: f32) -> f32; + asin(x: f64) -> f64; + asinf(x: f32) -> f32; + asinh(x: f64) -> f64; + asinhf(x: f32) -> f32; + atan(x: f64) -> f64; + atan2(x: f64, y: f64) -> f64; + atan2f(x: f32, y: f32) -> f32; + atanf(x: f32) -> f32; + atanh(x: f64) -> f64; + atanhf(x: f32) -> f32; + cbrt(x: f64) -> f64; + cbrtf(x: f32) -> f32; + ceil(x: f64) -> f64; + ceilf(x: f32) -> f32; + ceilf128(x: f128) -> f128; + ceilf16(x: f16) -> f16; + copysign(x: f64, y: f64) -> f64; + copysignf(x: f32, y: f32) -> f32; + copysignf128(x: f128, y: f128) -> f128; + copysignf16(x: f16, y: f16) -> f16; + cos(x: f64) -> f64; + cosf(x: f32) -> f32; + cosh(x: f64) -> f64; + coshf(x: f32) -> f32; + erf(x: f64) -> f64; + erfc(x: f64) -> f64; + erfcf(x: f32) -> f32; + erff(x: f32) -> f32; + exp(x: f64) -> f64; + exp10(x: f64) -> f64; + exp10f(x: f32) -> f32; + exp2(x: f64) -> f64; + exp2f(x: f32) -> f32; + expf(x: f32) -> f32; + expm1(x: f64) -> f64; + expm1f(x: f32) -> f32; + fabs(x: f64) -> f64; + fabsf(x: f32) -> f32; + fabsf128(x: f128) -> f128; + fabsf16(x: f16) -> f16; + fdim(x: f64, y: f64) -> f64; + fdimf(x: f32, y: f32) -> f32; + fdimf128(x: f128, y: f128) -> f128; + fdimf16(x: f16, y: f16) -> f16; + floor(x: f64) -> f64; + floorf(x: f32) -> f32; + floorf128(x: f128) -> f128; + floorf16(x: f16) -> f16; + fma(x: f64, y: f64, z: f64) -> f64; + fmaf(x: f32, y: f32, z: f32) -> f32; + fmax(x: f64, y: f64) -> f64; + fmaxf(x: f32, y: f32) -> f32; + fmin(x: f64, y: f64) -> f64; + fminf(x: f32, y: f32) -> f32; + fmod(x: f64, y: f64) -> f64; + fmodf(x: f32, y: f32) -> f32; + hypot(x: f64, y: f64) -> f64; + hypotf(x: f32, y: f32) -> f32; + ilogb(x: f64) -> c_int; + ilogbf(x: f32) -> c_int; + j0(x: f64) -> f64; + j0f(x: f32) -> f32; + j1(x: f64) -> f64; + j1f(x: f32) -> f32; + jn(x: c_int, y: f64) -> f64; + jnf(x: c_int, y: f32) -> f32; + ldexp(x: f64, y: c_int) -> f64; + ldexpf(x: f32, y: c_int) -> f32; + lgamma(x: f64) -> f64; + lgamma_r(x: f64 | r: &mut c_int) -> f64; + lgammaf(x: f32) -> f32; + lgammaf_r(x: f32 | r: &mut c_int) -> f32; + log(x: f64) -> f64; + log10(x: f64) -> f64; + log10f(x: f32) -> f32; + log1p(x: f64) -> f64; + log1pf(x: f32) -> f32; + log2(x: f64) -> f64; + log2f(x: f32) -> f32; + logf(x: f32) -> f32; + modf(x: f64 | r: &mut f64) -> f64; + modff(x: f32 | r: &mut f32) -> f32; + nextafter(x: f64, y: f64) -> f64; + nextafterf(x: f32, y: f32) -> f32; + pow(x: f64, y: f64) -> f64; + powf(x: f32, y: f32) -> f32; + remainder(x: f64, y: f64) -> f64; + remainderf(x: f32, y: f32) -> f32; + remquo(x: f64, y: f64 | q: &mut c_int) -> f64; + remquof(x: f32, y: f32 | q: &mut c_int) -> f32; + rint(x: f64) -> f64; + rintf(x: f32) -> f32; + rintf128(x: f128) -> f128; + rintf16(x: f16) -> f16; + round(x: f64) -> f64; + roundf(x: f32) -> f32; + scalbn(x: f64, y: c_int) -> f64; + scalbnf(x: f32, y: c_int) -> f32; + sin(x: f64) -> f64; + sinf(x: f32) -> f32; + sinh(x: f64) -> f64; + sinhf(x: f32) -> f32; + sqrt(x: f64) -> f64; + sqrtf(x: f32) -> f32; + tan(x: f64) -> f64; + tanf(x: f32) -> f32; + tanh(x: f64) -> f64; + tanhf(x: f32) -> f32; + tgamma(x: f64) -> f64; + tgammaf(x: f32) -> f32; + trunc(x: f64) -> f64; + truncf(x: f32) -> f32; + truncf128(x: f128) -> f128; + truncf16(x: f16) -> f16; + y0(x: f64) -> f64; + y0f(x: f32) -> f32; + y1(x: f64) -> f64; + y1f(x: f32) -> f32; + yn(x: c_int, y: f64) -> f64; + ynf(x: c_int, y: f32) -> f32; +} + +/* sincos has no direct return type, not worth handling in the macro */ + +#[no_mangle] +extern "C" fn sincos(x: f64, s: &mut f64, c: &mut f64) { + (*s, *c) = libm::sincos(x); +} + +#[no_mangle] +extern "C" fn sincosf(x: f32, s: &mut f32, c: &mut f32) { + (*s, *c) = libm::sincosf(x); +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index a54984c936b..049f573cc92 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: MIT */ /* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ -use super::super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; +use super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; use super::{CastFrom, CastInto, Float, Int, MinInt}; /// Fused multiply add (f64) diff --git a/library/compiler-builtins/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/src/math/fma_wide.rs index a8c1a548879..d0cf33baf7a 100644 --- a/library/compiler-builtins/libm/src/math/fma_wide.rs +++ b/library/compiler-builtins/libm/src/math/fma_wide.rs @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: MIT */ /* origin: musl src/math/fmaf.c. Ported to generic Rust algorithm in 2025, TG. */ -use super::super::support::{FpResult, IntTy, Round, Status}; +use super::support::{FpResult, IntTy, Round, Status}; use super::{CastFrom, CastInto, DFloat, Float, HFloat, MinInt}; // Placeholder so we can have `fmaf16` in the `Float` trait. -- cgit 1.4.1-3-g733a5 From f42c9632a60fab39127fd0bbbfab5d4b0d1c7862 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 15 Jan 2025 05:27:14 +0000 Subject: Eliminate the use of `public_test_dep!` for a third time Replace `public_test_dep!` by placing optionally public items into new modules, then controlling what is exported with the `public-test-deps` feature. This is nicer for automatic formatting and diagnostics. This is a reland of 2e2a9255 ("Eliminate the use of `public_test_dep!`"), which was reverted in 47e50fd2 ('Revert "Eliminate the use of..."') due to a bug exposed at [1], reapplied in d4abaf4efa because the issue should have been fixed in [2], then reverted again in f6eef07f53 because [2] did not actually fix the issue. [3] has landed in rust-lang/rust since then, which should resolve the last problem remaining after [2]. So, apply this change for what is hopefully the final time. [1]: https://github.com/rust-lang/rust/pull/128691 [2]: https://github.com/rust-lang/rust/pull/135278 [3]: https://github.com/rust-lang/rust/pull/135501 --- library/compiler-builtins/src/float/mod.rs | 195 +--------- library/compiler-builtins/src/float/traits.rs | 189 +++++++++ library/compiler-builtins/src/int/leading_zeros.rs | 227 +++++------ library/compiler-builtins/src/int/mod.rs | 424 +-------------------- .../src/int/specialized_div_rem/delegate.rs | 4 +- .../compiler-builtins/src/int/trailing_zeros.rs | 69 ++-- library/compiler-builtins/src/int/traits.rs | 411 ++++++++++++++++++++ library/compiler-builtins/src/macros.rs | 16 - 8 files changed, 763 insertions(+), 772 deletions(-) create mode 100644 library/compiler-builtins/src/float/traits.rs create mode 100644 library/compiler-builtins/src/int/traits.rs diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 6ee55950e18..41b308626b3 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,7 +1,3 @@ -use core::ops; - -use crate::int::{DInt, Int, MinInt}; - pub mod add; pub mod cmp; pub mod conv; @@ -10,192 +6,11 @@ pub mod extend; pub mod mul; pub mod pow; pub mod sub; +pub(crate) mod traits; pub mod trunc; -/// Wrapper to extract the integer type half of the float's size -pub(crate) type HalfRep = <::Int as DInt>::H; - -public_test_dep! { -/// Trait for some basic operations on floats -#[allow(dead_code)] -pub(crate) trait Float: - Copy - + core::fmt::Debug - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::MulAssign - + ops::Add - + ops::Sub - + ops::Div - + ops::Rem -{ - /// A uint of the same width as the float - type Int: Int; - - /// A int of the same width as the float - type SignedInt: Int + MinInt; - - /// An int capable of containing the exponent bits plus a sign bit. This is signed. - type ExpInt: Int; - - const ZERO: Self; - const ONE: Self; - - /// The bitwidth of the float type. - const BITS: u32; - - /// The bitwidth of the significand. - const SIG_BITS: u32; - - /// The bitwidth of the exponent. - const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; - - /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite - /// representation. - /// - /// This is in the rightmost position, use `EXP_MASK` for the shifted value. - const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; - - /// The exponent bias value. - const EXP_BIAS: u32 = Self::EXP_SAT >> 1; - - /// A mask for the sign bit. - const SIGN_MASK: Self::Int; - - /// A mask for the significand. - const SIG_MASK: Self::Int; - - /// The implicit bit of the float format. - const IMPLICIT_BIT: Self::Int; - - /// A mask for the exponent. - const EXP_MASK: Self::Int; - - /// Returns `self` transmuted to `Self::Int` - fn to_bits(self) -> Self::Int; - - /// Returns `self` transmuted to `Self::SignedInt` - fn to_bits_signed(self) -> Self::SignedInt; - - /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. This method returns `true` if two NaNs are - /// compared. - fn eq_repr(self, rhs: Self) -> bool; - - /// Returns true if the sign is negative - fn is_sign_negative(self) -> bool; - - /// Returns the exponent, not adjusting for bias. - fn exp(self) -> Self::ExpInt; - - /// Returns the significand with no implicit bit (or the "fractional" part) - fn frac(self) -> Self::Int; - - /// Returns the significand with implicit bit - fn imp_frac(self) -> Self::Int; - - /// Returns a `Self::Int` transmuted back to `Self` - fn from_bits(a: Self::Int) -> Self; - - /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self; - - fn abs(self) -> Self { - let abs_mask = !Self::SIGN_MASK ; - Self::from_bits(self.to_bits() & abs_mask) - } - - /// Returns (normalized exponent, normalized significand) - fn normalize(significand: Self::Int) -> (i32, Self::Int); - - /// Returns if `self` is subnormal - fn is_subnormal(self) -> bool; -} -} - -macro_rules! float_impl { - ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { - impl Float for $ty { - type Int = $ity; - type SignedInt = $sity; - type ExpInt = $expty; - - const ZERO: Self = 0.0; - const ONE: Self = 1.0; - - const BITS: u32 = $bits; - const SIG_BITS: u32 = $significand_bits; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; - const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); - - fn to_bits(self) -> Self::Int { - self.to_bits() - } - fn to_bits_signed(self) -> Self::SignedInt { - self.to_bits() as Self::SignedInt - } - fn eq_repr(self, rhs: Self) -> bool { - #[cfg(feature = "mangled-names")] - fn is_nan(x: $ty) -> bool { - // When using mangled-names, the "real" compiler-builtins might not have the - // necessary builtin (__unordtf2) to test whether `f128` is NaN. - // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin - // x is NaN if all the bits of the exponent are set and the significand is non-0 - x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 - } - #[cfg(not(feature = "mangled-names"))] - fn is_nan(x: $ty) -> bool { - x.is_nan() - } - if is_nan(self) && is_nan(rhs) { - true - } else { - self.to_bits() == rhs.to_bits() - } - } - fn is_sign_negative(self) -> bool { - self.is_sign_negative() - } - fn exp(self) -> Self::ExpInt { - ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt - } - fn frac(self) -> Self::Int { - self.to_bits() & Self::SIG_MASK - } - fn imp_frac(self) -> Self::Int { - self.frac() | Self::IMPLICIT_BIT - } - fn from_bits(a: Self::Int) -> Self { - Self::from_bits(a) - } - fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_bits( - ((negative as Self::Int) << (Self::BITS - 1)) - | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) - | (significand & Self::SIG_MASK), - ) - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); - ( - 1i32.wrapping_sub(shift as i32), - significand << shift as Self::Int, - ) - } - fn is_subnormal(self) -> bool { - (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO - } - } - }; -} +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use traits::{Float, HalfRep}; -#[cfg(f16_enabled)] -float_impl!(f16, u16, i16, i8, 16, 10); -float_impl!(f32, u32, i32, i16, 32, 23); -float_impl!(f64, u64, i64, i16, 64, 52); -#[cfg(f128_enabled)] -float_impl!(f128, u128, i128, i16, 128, 112); +#[cfg(feature = "public-test-deps")] +pub use traits::{Float, HalfRep}; diff --git a/library/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/src/float/traits.rs new file mode 100644 index 00000000000..8ccaa7bcbd7 --- /dev/null +++ b/library/compiler-builtins/src/float/traits.rs @@ -0,0 +1,189 @@ +use core::ops; + +use crate::int::{DInt, Int, MinInt}; + +/// Wrapper to extract the integer type half of the float's size +pub type HalfRep = <::Int as DInt>::H; + +/// Trait for some basic operations on floats +#[allow(dead_code)] +pub trait Float: + Copy + + core::fmt::Debug + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::MulAssign + + ops::Add + + ops::Sub + + ops::Div + + ops::Rem +{ + /// A uint of the same width as the float + type Int: Int; + + /// A int of the same width as the float + type SignedInt: Int + MinInt; + + /// An int capable of containing the exponent bits plus a sign bit. This is signed. + type ExpInt: Int; + + const ZERO: Self; + const ONE: Self; + + /// The bitwidth of the float type. + const BITS: u32; + + /// The bitwidth of the significand. + const SIG_BITS: u32; + + /// The bitwidth of the exponent. + const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; + + /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite + /// representation. + /// + /// This is in the rightmost position, use `EXP_MASK` for the shifted value. + const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; + + /// The exponent bias value. + const EXP_BIAS: u32 = Self::EXP_SAT >> 1; + + /// A mask for the sign bit. + const SIGN_MASK: Self::Int; + + /// A mask for the significand. + const SIG_MASK: Self::Int; + + /// The implicit bit of the float format. + const IMPLICIT_BIT: Self::Int; + + /// A mask for the exponent. + const EXP_MASK: Self::Int; + + /// Returns `self` transmuted to `Self::Int` + fn to_bits(self) -> Self::Int; + + /// Returns `self` transmuted to `Self::SignedInt` + fn to_bits_signed(self) -> Self::SignedInt; + + /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be + /// represented in multiple different ways. This method returns `true` if two NaNs are + /// compared. + fn eq_repr(self, rhs: Self) -> bool; + + /// Returns true if the sign is negative + fn is_sign_negative(self) -> bool; + + /// Returns the exponent, not adjusting for bias. + fn exp(self) -> Self::ExpInt; + + /// Returns the significand with no implicit bit (or the "fractional" part) + fn frac(self) -> Self::Int; + + /// Returns the significand with implicit bit + fn imp_frac(self) -> Self::Int; + + /// Returns a `Self::Int` transmuted back to `Self` + fn from_bits(a: Self::Int) -> Self; + + /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self; + + fn abs(self) -> Self { + let abs_mask = !Self::SIGN_MASK; + Self::from_bits(self.to_bits() & abs_mask) + } + + /// Returns (normalized exponent, normalized significand) + fn normalize(significand: Self::Int) -> (i32, Self::Int); + + /// Returns if `self` is subnormal + fn is_subnormal(self) -> bool; +} + +macro_rules! float_impl { + ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { + impl Float for $ty { + type Int = $ity; + type SignedInt = $sity; + type ExpInt = $expty; + + const ZERO: Self = 0.0; + const ONE: Self = 1.0; + + const BITS: u32 = $bits; + const SIG_BITS: u32 = $significand_bits; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; + const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); + + fn to_bits(self) -> Self::Int { + self.to_bits() + } + fn to_bits_signed(self) -> Self::SignedInt { + self.to_bits() as Self::SignedInt + } + fn eq_repr(self, rhs: Self) -> bool { + #[cfg(feature = "mangled-names")] + fn is_nan(x: $ty) -> bool { + // When using mangled-names, the "real" compiler-builtins might not have the + // necessary builtin (__unordtf2) to test whether `f128` is NaN. + // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin + // x is NaN if all the bits of the exponent are set and the significand is non-0 + x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 + } + #[cfg(not(feature = "mangled-names"))] + fn is_nan(x: $ty) -> bool { + x.is_nan() + } + if is_nan(self) && is_nan(rhs) { + true + } else { + self.to_bits() == rhs.to_bits() + } + } + fn is_sign_negative(self) -> bool { + self.is_sign_negative() + } + fn exp(self) -> Self::ExpInt { + ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt + } + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIG_MASK + } + fn imp_frac(self) -> Self::Int { + self.frac() | Self::IMPLICIT_BIT + } + fn from_bits(a: Self::Int) -> Self { + Self::from_bits(a) + } + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_bits( + ((negative as Self::Int) << (Self::BITS - 1)) + | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) + | (significand & Self::SIG_MASK), + ) + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); + ( + 1i32.wrapping_sub(shift as i32), + significand << shift as Self::Int, + ) + } + fn is_subnormal(self) -> bool { + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO + } + } + }; +} + +#[cfg(f16_enabled)] +float_impl!(f16, u16, i16, i8, 16, 10); +float_impl!(f32, u32, i32, i16, 32, 23); +float_impl!(f64, u64, i64, i16, 64, 52); +#[cfg(f128_enabled)] +float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index 1fee9fcf5d8..ba735aa7462 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -3,135 +3,138 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. -use crate::int::{CastInto, Int}; +#[cfg(feature = "public-test-deps")] +pub use implementation::{leading_zeros_default, leading_zeros_riscv}; +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use implementation::{leading_zeros_default, leading_zeros_riscv}; -public_test_dep! { -/// Returns the number of leading binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn leading_zeros_default>(x: T) -> usize { - // The basic idea is to test if the higher bits of `x` are zero and bisect the number - // of leading zeros. It is possible for all branches of the bisection to use the same - // code path by conditionally shifting the higher parts down to let the next bisection - // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` - // and adding to the number of zeros, it is slightly faster to start with - // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, - // because it simplifies the final bisection step. - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS as usize; - // a temporary - let mut t: T; +mod implementation { + use crate::int::{CastInto, Int}; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - t = x >> 32; + /// Returns the number of leading binary zeros in `x`. + #[allow(dead_code)] + pub fn leading_zeros_default>(x: T) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS as usize; + // a temporary + let mut t: T; + + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + t = x >> 32; + if t != T::ZERO { + z -= 32; + x = t; + } + } + if T::BITS >= 32 { + t = x >> 16; + if t != T::ZERO { + z -= 16; + x = t; + } + } + const { assert!(T::BITS >= 16) }; + t = x >> 8; if t != T::ZERO { - z -= 32; + z -= 8; x = t; } - } - if T::BITS >= 32 { - t = x >> 16; + t = x >> 4; if t != T::ZERO { - z -= 16; + z -= 4; x = t; } - } - const { assert!(T::BITS >= 16) }; - t = x >> 8; - if t != T::ZERO { - z -= 8; - x = t; - } - t = x >> 4; - if t != T::ZERO { - z -= 4; - x = t; - } - t = x >> 2; - if t != T::ZERO { - z -= 2; - x = t; - } - // the last two bisections are combined into one conditional - t = x >> 1; - if t != T::ZERO { - z - 2 - } else { - z - x.cast() - } + t = x >> 2; + if t != T::ZERO { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != T::ZERO { + z - 2 + } else { + z - x.cast() + } - // We could potentially save a few cycles by using the LUT trick from - // "https://embeddedgurus.com/state-space/2014/09/ - // fast-deterministic-and-portable-counting-leading-zeros/". - // However, 256 bytes for a LUT is too large for embedded use cases. We could remove - // the last 3 bisections and use this 16 byte LUT for the rest of the work: - //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; - //z -= LUT[x] as usize; - //z - // However, it ends up generating about the same number of instructions. When benchmarked - // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO - // execution effects. Changing to using a LUT and branching is risky for smaller cores. -} -} + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/ + // fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. + } -// The above method does not compile well on RISC-V (because of the lack of predicated -// instructions), producing code with many branches or using an excessively long -// branchless solution. This method takes advantage of the set-if-less-than instruction on -// RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + // The above method does not compile well on RISC-V (because of the lack of predicated + // instructions), producing code with many branches or using an excessively long + // branchless solution. This method takes advantage of the set-if-less-than instruction on + // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. -public_test_dep! { -/// Returns the number of leading binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn leading_zeros_riscv>(x: T) -> usize { - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS; - // a temporary - let mut t: u32; + /// Returns the number of leading binary zeros in `x`. + #[allow(dead_code)] + pub fn leading_zeros_riscv>(x: T) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS; + // a temporary + let mut t: u32; - // RISC-V does not have a set-if-greater-than-or-equal instruction and - // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is - // still the most optimal method. A conditional set can only be turned into a single - // immediate instruction if `x` is compared with an immediate `imm` (that can fit into - // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the - // right). If we try to save an instruction by using `x < imm` for each bisection, we - // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, - // but the immediate will never fit into 12 bits and never save an instruction. - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise - // `t` is set to 0. - t = ((x >= (T::ONE << 32)) as u32) << 5; - // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the - // next step to process. + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (T::ONE << 32)) as u32) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. + x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros + z -= t; + } + if T::BITS >= 32 { + t = ((x >= (T::ONE << 16)) as u32) << 4; + x >>= t; + z -= t; + } + const { assert!(T::BITS >= 16) }; + t = ((x >= (T::ONE << 8)) as u32) << 3; x >>= t; - // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential - // leading zeros z -= t; - } - if T::BITS >= 32 { - t = ((x >= (T::ONE << 16)) as u32) << 4; + t = ((x >= (T::ONE << 4)) as u32) << 2; + x >>= t; + z -= t; + t = ((x >= (T::ONE << 2)) as u32) << 1; x >>= t; z -= t; + t = (x >= (T::ONE << 1)) as u32; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z as usize - x.cast() } - const { assert!(T::BITS >= 16) }; - t = ((x >= (T::ONE << 8)) as u32) << 3; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 4)) as u32) << 2; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 2)) as u32) << 1; - x >>= t; - z -= t; - t = (x >= (T::ONE << 1)) as u32; - x >>= t; - z -= t; - // All bits except the LSB are guaranteed to be zero for this final bisection step. - // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. - z as usize - x.cast() -} } intrinsics! { diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index c0d5a6715e3..1f1be711bbd 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,5 +1,3 @@ -use core::ops; - mod specialized_div_rem; pub mod addsub; @@ -10,425 +8,13 @@ pub mod mul; pub mod sdiv; pub mod shift; pub mod trailing_zeros; +mod traits; pub mod udiv; pub use big::{i256, u256}; -public_test_dep! { -/// Minimal integer implementations needed on all integer types, including wide integers. -#[allow(dead_code)] -pub(crate) trait MinInt: Copy - + core::fmt::Debug - + ops::BitOr - + ops::Not - + ops::Shl -{ - - /// Type with the same width but other signedness - type OtherSign: MinInt; - /// Unsigned version of Self - type UnsignedInt: MinInt; - - /// If `Self` is a signed integer - const SIGNED: bool; - - /// The bitwidth of the int type - const BITS: u32; - - const ZERO: Self; - const ONE: Self; - const MIN: Self; - const MAX: Self; -} -} - -public_test_dep! { -/// Trait for some basic operations on integers -#[allow(dead_code)] -pub(crate) trait Int: MinInt - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Shr - + ops::BitXor - + ops::BitAnd -{ - /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing - /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, - /// 112,119,120,125,126,127]. - const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); - - /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. - const FUZZ_NUM: usize = { - let log2 = (::BITS - 1).count_ones() as usize; - if log2 == 3 { - // case for u8 - 6 - } else { - // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate - // boundaries. - 8 + (4 * (log2 - 4)) - } - }; - - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; - fn unsigned_abs(self) -> Self::UnsignedInt; - - fn from_bool(b: bool) -> Self; - - /// Prevents the need for excessive conversions between signed and unsigned - fn logical_shr(self, other: u32) -> Self; - - /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; - - // copied from primitive integers, but put in a trait - fn is_zero(self) -> bool; - fn wrapping_neg(self) -> Self; - fn wrapping_add(self, other: Self) -> Self; - fn wrapping_mul(self, other: Self) -> Self; - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - fn ilog2(self) -> u32; -} -} - -pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { - let mut v = [0u8; 20]; - v[0] = 0; - v[1] = 1; - v[2] = 2; // important for parity and the iX::MIN case when reversed - let mut i = 3; - - // No need for any more until the byte boundary, because there should be no algorithms - // that are sensitive to anything not next to byte boundaries after 2. We also scale - // in powers of two, which is important to prevent u128 corner tests from getting too - // big. - let mut l = 8; - loop { - if l >= ((bits / 2) as u8) { - break; - } - // get both sides of the byte boundary - v[i] = l - 1; - i += 1; - v[i] = l; - i += 1; - l *= 2; - } - - if bits != 8 { - // add the lower side of the middle boundary - v[i] = ((bits / 2) - 1) as u8; - i += 1; - } - - // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS - // boundary because of algorithms that split the high part up. We reverse the scaling - // as we go to Self::BITS. - let mid = i; - let mut j = 1; - loop { - v[i] = (bits as u8) - (v[mid - j]) - 1; - if j == mid { - break; - } - i += 1; - j += 1; - } - v -} - -macro_rules! int_impl_common { - ($ty:ty) => { - fn from_bool(b: bool) -> Self { - b as $ty - } - - fn logical_shr(self, other: u32) -> Self { - Self::from_unsigned(self.unsigned().wrapping_shr(other)) - } - - fn is_zero(self) -> bool { - self == Self::ZERO - } - - fn wrapping_neg(self) -> Self { - ::wrapping_neg(self) - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn wrapping_shr(self, other: u32) -> Self { - ::wrapping_shr(self, other) - } - - fn rotate_left(self, other: u32) -> Self { - ::rotate_left(self, other) - } - - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - - fn ilog2(self) -> u32 { - ::ilog2(self) - } - }; -} - -macro_rules! int_impl { - ($ity:ty, $uty:ty) => { - impl MinInt for $uty { - type OtherSign = $ity; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $uty { - fn unsigned(self) -> $uty { - self - } - - // It makes writing macros easier if this is implemented for both signed and unsigned - #[allow(clippy::wrong_self_convention)] - fn from_unsigned(me: $uty) -> Self { - me - } - - fn unsigned_abs(self) -> Self { - self - } - - fn abs_diff(self, other: Self) -> Self { - self.abs_diff(other) - } - - int_impl_common!($uty); - } - - impl MinInt for $ity { - type OtherSign = $uty; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $ity { - fn unsigned(self) -> $uty { - self as $uty - } - - fn from_unsigned(me: $uty) -> Self { - me as $ity - } - - fn unsigned_abs(self) -> Self::UnsignedInt { - self.unsigned_abs() - } - - fn abs_diff(self, other: Self) -> $uty { - self.abs_diff(other) - } - - int_impl_common!($ity); - } - }; -} - -int_impl!(isize, usize); -int_impl!(i8, u8); -int_impl!(i16, u16); -int_impl!(i32, u32); -int_impl!(i64, u64); -int_impl!(i128, u128); - -public_test_dep! { -/// Trait for integers twice the bit width of another integer. This is implemented for all -/// primitives except for `u8`, because there is not a smaller primitive. -pub(crate) trait DInt: MinInt { - /// Integer that is half the bit width of the integer this trait is implemented for - type H: HInt; - - /// Returns the low half of `self` - fn lo(self) -> Self::H; - /// Returns the high half of `self` - fn hi(self) -> Self::H; - /// Returns the low and high halves of `self` as a tuple - fn lo_hi(self) -> (Self::H, Self::H) { - (self.lo(), self.hi()) - } - /// Constructs an integer using lower and higher half parts - fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { - lo.zero_widen() | hi.widen_hi() - } -} -} - -public_test_dep! { -/// Trait for integers half the bit width of another integer. This is implemented for all -/// primitives except for `u128`, because it there is not a larger primitive. -pub(crate) trait HInt: Int { - /// Integer that is double the bit width of the integer this trait is implemented for - type D: DInt + MinInt; - - // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for - // unknown reasons this can cause infinite recursion when optimizations are disabled. See - // for context. - - /// Widens (using default extension) the integer to have double bit width - fn widen(self) -> Self::D; - /// Widens (zero extension only) the integer to have double bit width. This is needed to get - /// around problems with associated type bounds (such as `Int`) being unstable - fn zero_widen(self) -> Self::D; - /// Widens the integer to have double bit width and shifts the integer into the higher bits - fn widen_hi(self) -> Self::D; - /// Widening multiplication with zero widening. This cannot overflow. - fn zero_widen_mul(self, rhs: Self) -> Self::D; - /// Widening multiplication. This cannot overflow. - fn widen_mul(self, rhs: Self) -> Self::D; -} -} - -macro_rules! impl_d_int { - ($($X:ident $D:ident),*) => { - $( - impl DInt for $D { - type H = $X; - - fn lo(self) -> Self::H { - self as $X - } - fn hi(self) -> Self::H { - (self >> <$X as MinInt>::BITS) as $X - } - } - )* - }; -} - -macro_rules! impl_h_int { - ($($H:ident $uH:ident $X:ident),*) => { - $( - impl HInt for $H { - type D = $X; - - fn widen(self) -> Self::D { - self as $X - } - fn zero_widen(self) -> Self::D { - (self as $uH) as $X - } - fn zero_widen_mul(self, rhs: Self) -> Self::D { - self.zero_widen().wrapping_mul(rhs.zero_widen()) - } - fn widen_mul(self, rhs: Self) -> Self::D { - self.widen().wrapping_mul(rhs.widen()) - } - fn widen_hi(self) -> Self::D { - (self as $X) << ::BITS - } - } - )* - }; -} - -impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); -impl_h_int!( - u8 u8 u16, - u16 u16 u32, - u32 u32 u64, - u64 u64 u128, - i8 u8 i16, - i16 u16 i32, - i32 u32 i64, - i64 u64 i128 -); - -public_test_dep! { -/// Trait to express (possibly lossy) casting of integers -pub(crate) trait CastInto: Copy { - fn cast(self) -> T; -} - -pub(crate) trait CastFrom:Copy { - fn cast_from(value: T) -> Self; -} -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - self as $into - } - } - )*}; -} +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); +#[cfg(feature = "public-test-deps")] +pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index 330c6e4f80b..f5c6e50239a 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -185,7 +185,6 @@ macro_rules! impl_delegate { }; } -public_test_dep! { /// Returns `n / d` and sets `*rem = n % d`. /// /// This specialization exists because: @@ -195,7 +194,7 @@ public_test_dep! { /// delegate algorithm strategy the only reasonably fast way to perform `u128` division. // used on SPARC #[allow(dead_code)] -pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { +pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { use super::*; let duo_lo = duo as u64; let duo_hi = (duo >> 64) as u64; @@ -316,4 +315,3 @@ pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { } } } -} diff --git a/library/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/src/int/trailing_zeros.rs index cea366b0754..dbc0cce9fac 100644 --- a/library/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/src/int/trailing_zeros.rs @@ -1,44 +1,49 @@ -use crate::int::{CastInto, Int}; +#[cfg(feature = "public-test-deps")] +pub use implementation::trailing_zeros; +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use implementation::trailing_zeros; -public_test_dep! { -/// Returns number of trailing binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { - let mut x = x; - let mut r: u32 = 0; - let mut t: u32; +mod implementation { + use crate::int::{CastInto, Int}; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 - x >>= r; // remove 32 zero bits - } + /// Returns number of trailing binary zeros in `x`. + #[allow(dead_code)] + pub fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + let mut x = x; + let mut r: u32 = 0; + let mut t: u32; - if T::BITS >= 32 { - t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 - r += t; - x >>= t; // x = [0 - 0xFFFF] + higher garbage bits - } + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + x >>= r; // remove 32 zero bits + } - const { assert!(T::BITS >= 16) }; - t = ((CastInto::::cast(x) == 0) as u32) << 3; - x >>= t; // x = [0 - 0xFF] + higher garbage bits - r += t; + if T::BITS >= 32 { + t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 + r += t; + x >>= t; // x = [0 - 0xFFFF] + higher garbage bits + } - let mut x: u8 = x.cast(); + const { assert!(T::BITS >= 16) }; + t = ((CastInto::::cast(x) == 0) as u32) << 3; + x >>= t; // x = [0 - 0xFF] + higher garbage bits + r += t; - t = (((x & 0x0F) == 0) as u32) << 2; - x >>= t; // x = [0 - 0xF] + higher garbage bits - r += t; + let mut x: u8 = x.cast(); - t = (((x & 0x3) == 0) as u32) << 1; - x >>= t; // x = [0 - 0x3] + higher garbage bits - r += t; + t = (((x & 0x0F) == 0) as u32) << 2; + x >>= t; // x = [0 - 0xF] + higher garbage bits + r += t; - x &= 3; + t = (((x & 0x3) == 0) as u32) << 1; + x >>= t; // x = [0 - 0x3] + higher garbage bits + r += t; - r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) -} + x &= 3; + + r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) + } } intrinsics! { diff --git a/library/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/src/int/traits.rs new file mode 100644 index 00000000000..9b079e2aa59 --- /dev/null +++ b/library/compiler-builtins/src/int/traits.rs @@ -0,0 +1,411 @@ +use core::ops; + +/// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] +pub trait MinInt: + Copy + + core::fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type UnsignedInt: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} + +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub trait Int: + MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, + /// 112,119,120,125,126,127]. + const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); + + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; + + fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + fn unsigned_abs(self) -> Self::UnsignedInt; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} + +pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn unsigned(self) -> $uty { + self + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn unsigned_abs(self) -> Self { + self + } + + fn abs_diff(self, other: Self) -> Self { + self.abs_diff(other) + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn unsigned(self) -> $uty { + self as $uty + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn unsigned_abs(self) -> Self::UnsignedInt { + self.unsigned_abs() + } + + fn abs_diff(self, other: Self) -> $uty { + self.abs_diff(other) + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +/// Trait for integers twice the bit width of another integer. This is implemented for all +/// primitives except for `u8`, because there is not a smaller primitive. +pub trait DInt: MinInt { + /// Integer that is half the bit width of the integer this trait is implemented for + type H: HInt; + + /// Returns the low half of `self` + fn lo(self) -> Self::H; + /// Returns the high half of `self` + fn hi(self) -> Self::H; + /// Returns the low and high halves of `self` as a tuple + fn lo_hi(self) -> (Self::H, Self::H) { + (self.lo(), self.hi()) + } + /// Constructs an integer using lower and higher half parts + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { + lo.zero_widen() | hi.widen_hi() + } +} + +/// Trait for integers half the bit width of another integer. This is implemented for all +/// primitives except for `u128`, because it there is not a larger primitive. +pub trait HInt: Int { + /// Integer that is double the bit width of the integer this trait is implemented for + type D: DInt + MinInt; + + // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for + // unknown reasons this can cause infinite recursion when optimizations are disabled. See + // for context. + + /// Widens (using default extension) the integer to have double bit width + fn widen(self) -> Self::D; + /// Widens (zero extension only) the integer to have double bit width. This is needed to get + /// around problems with associated type bounds (such as `Int`) being unstable + fn zero_widen(self) -> Self::D; + /// Widens the integer to have double bit width and shifts the integer into the higher bits + fn widen_hi(self) -> Self::D; + /// Widening multiplication with zero widening. This cannot overflow. + fn zero_widen_mul(self, rhs: Self) -> Self::D; + /// Widening multiplication. This cannot overflow. + fn widen_mul(self, rhs: Self) -> Self::D; +} + +macro_rules! impl_d_int { + ($($X:ident $D:ident),*) => { + $( + impl DInt for $D { + type H = $X; + + fn lo(self) -> Self::H { + self as $X + } + fn hi(self) -> Self::H { + (self >> <$X as MinInt>::BITS) as $X + } + } + )* + }; +} + +macro_rules! impl_h_int { + ($($H:ident $uH:ident $X:ident),*) => { + $( + impl HInt for $H { + type D = $X; + + fn widen(self) -> Self::D { + self as $X + } + fn zero_widen(self) -> Self::D { + (self as $uH) as $X + } + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen().wrapping_mul(rhs.zero_widen()) + } + fn widen_mul(self, rhs: Self) -> Self::D { + self.widen().wrapping_mul(rhs.widen()) + } + fn widen_hi(self) -> Self::D { + (self as $X) << ::BITS + } + } + )* + }; +} + +impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); +impl_h_int!( + u8 u8 u16, + u16 u16 u32, + u32 u32 u64, + u64 u64 u128, + i8 u8 i16, + i16 u16 i32, + i32 u32 i64, + i64 u64 i128 +); + +/// Trait to express (possibly lossy) casting of integers +pub trait CastInto: Copy { + fn cast(self) -> T; +} + +pub trait CastFrom: Copy { + fn cast_from(value: T) -> Self; +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} + +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 88b54e82ca0..5d9f5819757 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,21 +1,5 @@ //! Macros shared throughout the compiler-builtins implementation -/// Changes the visibility to `pub` if feature "public-test-deps" is set -#[cfg(not(feature = "public-test-deps"))] -macro_rules! public_test_dep { - ($(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => { - $(#[$($meta)*])* pub(crate) $ident $($tokens)* - }; -} - -/// Changes the visibility to `pub` if feature "public-test-deps" is set -#[cfg(feature = "public-test-deps")] -macro_rules! public_test_dep { - {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*} => { - $(#[$($meta)*])* pub $ident $($tokens)* - }; -} - /// The "main macro" used for defining intrinsics. /// /// The compiler-builtins library is super platform-specific with tons of crazy -- cgit 1.4.1-3-g733a5 From 49224fb9ed187db240912fb683613b795c9c0a45 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Tue, 18 Feb 2025 09:47:07 +0100 Subject: Enable `f16` for MIPS It seems as if `f16` works on MIPS now according to my testing on Rust master with LLVM 20, and I was asked to create PRs with my changes. I only tested on the flavour of `mipsel-unknown-linux-gnu` hardware that happens to be available to me, so I can't say anything about other MIPS hardware, but from a casual skimming of the LLVM code ([1], [2]) it seems like `f16` should work on all MIPS hardware. So enable it for all MIPS hardware. [1]: https://github.com/rust-lang/llvm-project/blob/rustc/20.1-2025-02-13/llvm/lib/Target/Mips/MipsISelLowering.h#L370 [2]: https://github.com/rust-lang/llvm-project/blob/rustc/20.1-2025-02-13/llvm/lib/CodeGen/TargetLoweringBase.cpp#L1367-L1388 --- library/compiler-builtins/configure.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index fa3e302ea87..ff52e88da0c 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -78,7 +78,6 @@ pub fn configure_f16_f128(target: &Target) { "csky" => false, "hexagon" => false, "loongarch64" => false, - "mips" | "mips64" | "mips32r6" | "mips64r6" => false, "powerpc" | "powerpc64" => false, "sparc" | "sparc64" => false, "wasm32" | "wasm64" => false, -- cgit 1.4.1-3-g733a5 From 9021b2820c8d4b1db425dd1b59a74911ceabce4b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 04:06:07 +0000 Subject: Resolve monomorphization errors in `compiler-builtins` `compiler-builtins` is not allowed to call anything from `core`; however, there are a couple of cases where we do so in `libm` for debug output. Gate relevant locations behind the `compiler-builtins` Cargo feature. --- library/compiler-builtins/libm/Cargo.toml | 7 +++++++ .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 1 + .../libm/crates/compiler-builtins-smoke-test/src/lib.rs | 2 ++ .../compiler-builtins/libm/src/math/support/hex_float.rs | 16 ++++++++++++++-- .../libm/src/math/support/int_traits.rs | 1 + 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index f24f4423c7b..eb133dada16 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -61,6 +61,13 @@ exclude = [ [dev-dependencies] no-panic = "0.1.33" + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = [ + # compiler-builtins sets this feature, but we use it in `libm` + 'cfg(feature, values("compiler-builtins"))', +] } + # The default release profile is unchanged. # Release mode with debug assertions diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 24b33645e97..6ef905ea759 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -22,6 +22,7 @@ unexpected_cfgs = { level = "warn", check-cfg = [ "cfg(arch_enabled)", "cfg(assert_no_panic)", "cfg(intrinsics_enabled)", + 'cfg(feature, values("compiler-builtins"))', 'cfg(feature, values("force-soft-floats"))', 'cfg(feature, values("unstable"))', 'cfg(feature, values("unstable-intrinsics"))', diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index f9e6e75a870..e70f6d9e04c 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -4,7 +4,9 @@ //! Additionally, it provides a `#[no_mangle]` C API that can be easier to inspect than the //! default `.rlib`. +#![compiler_builtins] #![feature(core_intrinsics)] +#![feature(compiler_builtins)] #![feature(f16)] #![feature(f128)] #![allow(internal_features)] diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index 99ad8bec377..2155d5c58bc 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -246,7 +246,13 @@ fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { impl fmt::LowerHex for Hexf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_any_hex(&self.0, f) + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + unreachable!() + } else { + fmt_any_hex(&self.0, f) + } + } } } @@ -264,7 +270,13 @@ impl fmt::LowerHex for Hexf<(F, i32)> { impl fmt::LowerHex for Hexf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::LowerHex::fmt(&self.0, f) + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + unreachable!() + } else { + fmt::LowerHex::fmt(&self.0, f) + } + } } } diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index d34797764a0..f19c8683521 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -418,6 +418,7 @@ macro_rules! cast_into_float { ($ty:ty; $($into:ty),*) => {$( impl CastInto<$into> for $ty { fn cast(self) -> $into { + #[cfg(not(feature = "compiler-builtins"))] debug_assert_eq!(self as $into as $ty, self, "inexact float cast"); self as $into } -- cgit 1.4.1-3-g733a5 From 3f6b08ac1ea7605c66a9c4c3f5c621267ace2883 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 04:55:38 +0000 Subject: Ignore unused variables when `compiler-builtins` is set --- .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 6 +++--- library/compiler-builtins/libm/src/math/support/hex_float.rs | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 6ef905ea759..38a5116690a 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -11,18 +11,18 @@ test = false bench = false [features] -default = ["arch", "unstable-float"] +default = ["arch", "compiler-builtins", "unstable-float"] # Copied from `libm`'s root `Cargo.toml`' -unstable-float = [] arch = [] +compiler-builtins = [] +unstable-float = [] [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ "cfg(arch_enabled)", "cfg(assert_no_panic)", "cfg(intrinsics_enabled)", - 'cfg(feature, values("compiler-builtins"))', 'cfg(feature, values("force-soft-floats"))', 'cfg(feature, values("unstable"))', 'cfg(feature, values("unstable-intrinsics"))', diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index 2155d5c58bc..0ecf616954f 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -248,7 +248,8 @@ impl fmt::LowerHex for Hexf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { cfg_if! { if #[cfg(feature = "compiler-builtins")] { - unreachable!() + let _ = f; + unimplemented!() } else { fmt_any_hex(&self.0, f) } @@ -272,7 +273,8 @@ impl fmt::LowerHex for Hexf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { cfg_if! { if #[cfg(feature = "compiler-builtins")] { - unreachable!() + let _ = f; + unimplemented!() } else { fmt::LowerHex::fmt(&self.0, f) } -- cgit 1.4.1-3-g733a5 From 2615971f55e24570805180b820e85457b74ba1be Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 05:45:41 +0000 Subject: Configure out remaining formatting when `compiler-builtins` is set These are still causing errors in the compiler-builtins CI. --- .../libm/src/math/support/hex_float.rs | 42 +++++++++++++++++++--- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index 0ecf616954f..be7d7607f91 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -211,6 +211,7 @@ const fn u128_ilog2(v: u128) -> u32 { pub struct Hexf(pub F); // Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs +#[cfg(not(feature = "compiler-builtins"))] fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { if x.is_sign_negative() { write!(f, "-")?; @@ -244,6 +245,11 @@ fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") } +#[cfg(feature = "compiler-builtins")] +fn fmt_any_hex(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() +} + impl fmt::LowerHex for Hexf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { cfg_if! { @@ -259,13 +265,27 @@ impl fmt::LowerHex for Hexf { impl fmt::LowerHex for Hexf<(F, F)> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + } + } } } impl fmt::LowerHex for Hexf<(F, i32)> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + } + } } } @@ -287,7 +307,14 @@ where Hexf: fmt::LowerHex, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::LowerHex::fmt(self, f) + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(self, f) + } + } } } @@ -296,7 +323,14 @@ where Hexf: fmt::LowerHex, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::LowerHex::fmt(self, f) + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(self, f) + } + } } } -- cgit 1.4.1-3-g733a5 From 17748827383d17e26cb222b4402976d1441378da Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 06:52:48 +0000 Subject: Gate another assertion behind `compiler-builtins` This is causing link errors on Windows. --- library/compiler-builtins/libm/src/math/support/int_traits.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index f19c8683521..491adb1f22c 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -394,6 +394,7 @@ macro_rules! cast_into { fn cast(self) -> $into { // All we can really do to enforce casting rules is check the rules when in // debug mode. + #[cfg(not(feature = "compiler-builtins"))] debug_assert!(<$into>::try_from(self).is_ok(), "failed cast from {self}"); self as $into } -- cgit 1.4.1-3-g733a5 From 7055198acf005b30f7516997dbf1f5f6fe6867a3 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 23 Feb 2025 23:43:26 +0000 Subject: Update the `libm` submodule This requires privately reexporting `libm`'s `support` module at crate root, where it is expected for macros. Once `libm` is made always available, the reexport can be simplified. This delta adds a lot of routines to `f16` and `f128`: * ceil * floor * fma (f128 only) * fmax * fmin * fmod * ldexp * rint * round * scalbn * sqrt Additionally, the following new API was added for all four float types: * fmaximum * fmaximum_num * fminimum * fminimum_num * roundeven There are also some significant performance improvements for `sqrt` and `sqrtf`, as well as precision improvements for `cbrt` (both `f32` and `f64` versions of this function are now always correctly rounded). --- library/compiler-builtins/libm | 2 +- library/compiler-builtins/src/lib.rs | 15 +++++++++++++++ library/compiler-builtins/src/math.rs | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 8e82616f154..69219c491ee 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 8e82616f154b06cf4ee9cdb82a4f56474a403d04 +Subproject commit 69219c491ee9f05761d2068fd6d4c7c0de6faa3a diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index ffcd3586ce7..533878137dc 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] +#![cfg_attr(all(target_family = "wasm"), feature(wasm_numeric_instr))] #![feature(abi_unadjusted)] #![feature(asm_experimental_arch)] #![feature(cfg_target_has_atomic)] @@ -58,6 +59,20 @@ pub mod int; all(target_family = "wasm", not(target_os = "unknown")) )))] pub mod math; + +// `libm` expects its `support` module to be available in the crate root. This config can be +// cleaned up once `libm` is made always available. +#[cfg(not(any( + all( + target_arch = "x86", + not(target_feature = "sse2"), + not(target_os = "uefi"), + ), + unix, + all(target_family = "wasm", not(target_os = "unknown")) +)))] +use math::libm::support; + pub mod mem; #[cfg(target_arch = "arm")] diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 21670f2434f..fef5358e323 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -3,7 +3,7 @@ #[allow(unused_imports)] #[allow(clippy::all)] #[path = "../libm/src/math/mod.rs"] -mod libm; +pub(crate) mod libm; #[allow(unused_macros)] macro_rules! no_mangle { -- cgit 1.4.1-3-g733a5 From 95a5ad5225b3abe02b99d84612c49bc8716033f3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 07:34:00 +0000 Subject: chore: release v0.1.148 --- library/compiler-builtins/CHANGELOG.md | 8 ++++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index a3890c6ce73..c1e1e73daf9 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.148](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.147...compiler_builtins-v0.1.148) - 2025-02-24 + +### Other + +- Update the `libm` submodule +- Enable `f16` for MIPS +- Eliminate the use of `public_test_dep!` for a third time + ## [0.1.147](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.146...compiler_builtins-v0.1.147) - 2025-02-19 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index ff1a10fc626..684a2a0b655 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.147" +version = "0.1.148" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 55bbda8ff8c53984e1b15b69c3d0f7ed529e8b16 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 13 Feb 2025 03:27:00 +0000 Subject: Make a subset of `libm` symbols weakly available on all platforms 018616e78b ("Always have math functions but with `weak` linking attribute if we can") made all math symbols available on platforms that support weak linkage. This caused some unexpected regressions, however, because our less accurate and sometimes slow routines were being selected over the system `libm`, which also tends to be weak [1]. Thus, 0fab77e8d7 ("Don't include `math` for `unix` and `wasi` targets") was applied to undo these changes on many platforms. Now that some improvements have been made to `libm`, add back a subset of these functions: * cbrt * ceil * copysign * fabs * fdim * floor * fma * fmax * fmaximum * fmin * fminimum * fmod * rint * round * roundeven * sqrt * trunc This list includes only functions that produce exact results (verified with exhaustive / extensive tests, and also required by IEEE in most cases), and for which benchmarks indicate performance similar to or better than Musl's soft float math routines [^1]. All except `cbrt` also have `f16` and `f128` implementations. Once more routines meet these criteria, we can move them from platform-specific availability to always available. Once this change makes it to rust-lang/rust, we will also be able to move the relevant functions from `std` to `core`. [^1]: We still rely on the backend to provide optimized assmebly routines when available. [1]: https://github.com/rust-lang/rust/issues/128386 --- library/compiler-builtins/src/lib.rs | 29 +--- library/compiler-builtins/src/math.rs | 259 ++++++++++++++++++++++------------ 2 files changed, 173 insertions(+), 115 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 533878137dc..6f5bd85981e 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -41,40 +41,13 @@ mod macros; pub mod float; pub mod int; - -// Disable for any of the following: -// - x86 without sse2 due to ABI issues -// - -// - but exclude UEFI since it is a soft-float target -// - -// - All unix targets (linux, macos, freebsd, android, etc) -// - wasm with known target_os -#[cfg(not(any( - all( - target_arch = "x86", - not(target_feature = "sse2"), - not(target_os = "uefi"), - ), - unix, - all(target_family = "wasm", not(target_os = "unknown")) -)))] pub mod math; +pub mod mem; // `libm` expects its `support` module to be available in the crate root. This config can be // cleaned up once `libm` is made always available. -#[cfg(not(any( - all( - target_arch = "x86", - not(target_feature = "sse2"), - not(target_os = "uefi"), - ), - unix, - all(target_family = "wasm", not(target_os = "unknown")) -)))] use math::libm::support; -pub mod mem; - #[cfg(target_arch = "arm")] pub mod arm; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index fef5358e323..ccd9c54216c 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -5,110 +5,195 @@ #[path = "../libm/src/math/mod.rs"] pub(crate) mod libm; -#[allow(unused_macros)] -macro_rules! no_mangle { +macro_rules! libm_intrinsics { ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { intrinsics! { $( pub extern "C" fn $fun($($iid: $ity),+) -> $oty { - self::libm::$fun($($iid),+) + $crate::math::libm::$fun($($iid),+) } )+ } } } -#[cfg(not(windows))] -no_mangle! { - fn acos(x: f64) -> f64; - fn asin(x: f64) -> f64; - fn cbrt(x: f64) -> f64; - fn expm1(x: f64) -> f64; - fn hypot(x: f64, y: f64) -> f64; - fn tan(x: f64) -> f64; - fn cos(x: f64) -> f64; - fn expf(x: f32) -> f32; - fn log2(x: f64) -> f64; - fn log2f(x: f32) -> f32; - fn log10(x: f64) -> f64; - fn log10f(x: f32) -> f32; - fn log(x: f64) -> f64; - fn logf(x: f32) -> f32; - fn round(x: f64) -> f64; - fn roundf(x: f32) -> f32; - fn rint(x: f64) -> f64; - fn rintf(x: f32) -> f32; - fn sin(x: f64) -> f64; - fn pow(x: f64, y: f64) -> f64; - fn powf(x: f32, y: f32) -> f32; - fn acosf(n: f32) -> f32; - fn atan2f(a: f32, b: f32) -> f32; - fn atanf(n: f32) -> f32; - fn coshf(n: f32) -> f32; - fn expm1f(n: f32) -> f32; - fn fdim(a: f64, b: f64) -> f64; - fn fdimf(a: f32, b: f32) -> f32; - fn log1pf(n: f32) -> f32; - fn sinhf(n: f32) -> f32; - fn tanhf(n: f32) -> f32; - fn ldexp(f: f64, n: i32) -> f64; - fn ldexpf(f: f32, n: i32) -> f32; - fn tgamma(x: f64) -> f64; - fn tgammaf(x: f32) -> f32; - fn atan(x: f64) -> f64; - fn atan2(x: f64, y: f64) -> f64; - fn cosh(x: f64) -> f64; - fn log1p(x: f64) -> f64; - fn sinh(x: f64) -> f64; - fn tanh(x: f64) -> f64; - fn cosf(x: f32) -> f32; - fn exp(x: f64) -> f64; - fn sinf(x: f32) -> f32; - fn exp2(x: f64) -> f64; - fn exp2f(x: f32) -> f32; - fn fma(x: f64, y: f64, z: f64) -> f64; - fn fmaf(x: f32, y: f32, z: f32) -> f32; - fn asinf(n: f32) -> f32; - fn cbrtf(n: f32) -> f32; - fn hypotf(x: f32, y: f32) -> f32; - fn tanf(n: f32) -> f32; +/// This set of functions is well tested in `libm` and known to provide similar performance to +/// system `libm`, as well as the same or better accuracy. +pub mod full_availability { + #[cfg(f16_enabled)] + libm_intrinsics! { + fn ceilf16(x: f16) -> f16; + fn copysignf16(x: f16, y: f16) -> f16; + fn fabsf16(x: f16) -> f16; + fn fdimf16(x: f16, y: f16) -> f16; + fn floorf16(x: f16) -> f16; + fn fmaxf16(x: f16, y: f16) -> f16; + fn fmaximumf16(x: f16, y: f16) -> f16; + fn fminf16(x: f16, y: f16) -> f16; + fn fminimumf16(x: f16, y: f16) -> f16; + fn fmodf16(x: f16, y: f16) -> f16; + fn rintf16(x: f16) -> f16; + fn roundevenf16(x: f16) -> f16; + fn roundf16(x: f16) -> f16; + fn sqrtf16(x: f16) -> f16; + fn truncf16(x: f16) -> f16; + } + + /* Weak linkage is unreliable on Windows and Apple, so we don't expose symbols that we know + * the system libc provides in order to avoid conflicts. */ - fn sqrtf(x: f32) -> f32; - fn sqrt(x: f64) -> f64; + #[cfg(all(not(windows), not(target_vendor = "apple")))] + libm_intrinsics! { + /* f32 */ + fn cbrtf(n: f32) -> f32; + fn ceilf(x: f32) -> f32; + fn copysignf(x: f32, y: f32) -> f32; + fn fabsf(x: f32) -> f32; + fn fdimf(a: f32, b: f32) -> f32; + fn floorf(x: f32) -> f32; + fn fmaf(x: f32, y: f32, z: f32) -> f32; + fn fmaxf(x: f32, y: f32) -> f32; + fn fminf(x: f32, y: f32) -> f32; + fn fmodf(x: f32, y: f32) -> f32; + fn rintf(x: f32) -> f32; + fn roundf(x: f32) -> f32; + fn sqrtf(x: f32) -> f32; + fn truncf(x: f32) -> f32; - fn ceil(x: f64) -> f64; - fn ceilf(x: f32) -> f32; - fn floor(x: f64) -> f64; - fn floorf(x: f32) -> f32; - fn trunc(x: f64) -> f64; - fn truncf(x: f32) -> f32; + /* f64 */ + fn cbrt(x: f64) -> f64; + fn ceil(x: f64) -> f64; + fn copysign(x: f64, y: f64) -> f64; + fn fabs(x: f64) -> f64; + fn fdim(a: f64, b: f64) -> f64; + fn floor(x: f64) -> f64; + fn fma(x: f64, y: f64, z: f64) -> f64; + fn fmax(x: f64, y: f64) -> f64; + fn fmin(x: f64, y: f64) -> f64; + fn fmod(x: f64, y: f64) -> f64; + fn rint(x: f64) -> f64; + fn round(x: f64) -> f64; + fn sqrt(x: f64) -> f64; + fn trunc(x: f64) -> f64; + } - fn fmin(x: f64, y: f64) -> f64; - fn fminf(x: f32, y: f32) -> f32; - fn fmax(x: f64, y: f64) -> f64; - fn fmaxf(x: f32, y: f32) -> f32; - // `f64 % f64` - fn fmod(x: f64, y: f64) -> f64; - // `f32 % f32` - fn fmodf(x: f32, y: f32) -> f32; + // Windows and MacOS do not yet expose roundeven and IEEE 754-2019 `maximum` / `minimum`, + // however, so we still provide a fallback. + libm_intrinsics! { + fn fmaximum(x: f64, y: f64) -> f64; + fn fmaximumf(x: f32, y: f32) -> f32; + fn fminimum(x: f64, y: f64) -> f64; + fn fminimumf(x: f32, y: f32) -> f32; + fn roundeven(x: f64) -> f64; + fn roundevenf(x: f32) -> f32; + } - fn erf(x: f64) -> f64; - fn erff(x: f32) -> f32; - fn erfc(x: f64) -> f64; - fn erfcf(x: f32) -> f32; + #[cfg(f128_enabled)] + libm_intrinsics! { + fn ceilf128(x: f128) -> f128; + fn copysignf128(x: f128, y: f128) -> f128; + fn fabsf128(x: f128) -> f128; + fn fdimf128(x: f128, y: f128) -> f128; + fn floorf128(x: f128) -> f128; + fn fmaf128(x: f128, y: f128, z: f128) -> f128; + fn fmaxf128(x: f128, y: f128) -> f128; + fn fmaximumf128(x: f128, y: f128) -> f128; + fn fminf128(x: f128, y: f128) -> f128; + fn fminimumf128(x: f128, y: f128) -> f128; + fn fmodf128(x: f128, y: f128) -> f128; + fn rintf128(x: f128) -> f128; + fn roundevenf128(x: f128) -> f128; + fn roundf128(x: f128) -> f128; + fn sqrtf128(x: f128) -> f128; + fn truncf128(x: f128) -> f128; + } } -// allow for windows (and other targets) -intrinsics! { - pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { - let r = self::libm::lgamma_r(x); - *s = r.1; - r.0 +/// This group of functions has more performance or precision issues than system versions, or +/// are otherwise less well tested. Provide them only on platforms that have problems with the +/// system `libm`. +/// +/// As `libm` improves, more functions will be moved from this group to the first group. +/// +/// Do not supply for any of the following: +/// - x86 without sse2 due to ABI issues +/// - +/// - but exclude UEFI since it is a soft-float target +/// - +/// - All unix targets (linux, macos, freebsd, android, etc) +/// - wasm with known target_os +#[cfg(not(any( + all( + target_arch = "x86", + not(target_feature = "sse2"), + not(target_os = "uefi"), + ), + unix, + all(target_family = "wasm", not(target_os = "unknown")) +)))] +pub mod partial_availability { + #[cfg(not(windows))] + libm_intrinsics! { + fn acos(x: f64) -> f64; + fn acosf(n: f32) -> f32; + fn asin(x: f64) -> f64; + fn asinf(n: f32) -> f32; + fn atan(x: f64) -> f64; + fn atan2(x: f64, y: f64) -> f64; + fn atan2f(a: f32, b: f32) -> f32; + fn atanf(n: f32) -> f32; + fn cos(x: f64) -> f64; + fn cosf(x: f32) -> f32; + fn cosh(x: f64) -> f64; + fn coshf(n: f32) -> f32; + fn erf(x: f64) -> f64; + fn erfc(x: f64) -> f64; + fn erfcf(x: f32) -> f32; + fn erff(x: f32) -> f32; + fn exp(x: f64) -> f64; + fn exp2(x: f64) -> f64; + fn exp2f(x: f32) -> f32; + fn expf(x: f32) -> f32; + fn expm1(x: f64) -> f64; + fn expm1f(n: f32) -> f32; + fn hypot(x: f64, y: f64) -> f64; + fn hypotf(x: f32, y: f32) -> f32; + fn ldexp(f: f64, n: i32) -> f64; + fn ldexpf(f: f32, n: i32) -> f32; + fn log(x: f64) -> f64; + fn log10(x: f64) -> f64; + fn log10f(x: f32) -> f32; + fn log1p(x: f64) -> f64; + fn log1pf(n: f32) -> f32; + fn log2(x: f64) -> f64; + fn log2f(x: f32) -> f32; + fn logf(x: f32) -> f32; + fn pow(x: f64, y: f64) -> f64; + fn powf(x: f32, y: f32) -> f32; + fn sin(x: f64) -> f64; + fn sinf(x: f32) -> f32; + fn sinh(x: f64) -> f64; + fn sinhf(n: f32) -> f32; + fn tan(x: f64) -> f64; + fn tanf(n: f32) -> f32; + fn tanh(x: f64) -> f64; + fn tanhf(n: f32) -> f32; + fn tgamma(x: f64) -> f64; + fn tgammaf(x: f32) -> f32; } - pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { - let r = self::libm::lgammaf_r(x); - *s = r.1; - r.0 + // allow for windows (and other targets) + intrinsics! { + pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { + let r = super::libm::lgamma_r(x); + *s = r.1; + r.0 + } + + pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { + let r = super::libm::lgammaf_r(x); + *s = r.1; + r.0 + } } } -- cgit 1.4.1-3-g733a5 From 45c4a1d1b58c247070ec61d8fea19b49518f5e83 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 25 Feb 2025 18:55:26 +0000 Subject: chore: release v0.1.149 --- library/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index c1e1e73daf9..9b8aaaa0809 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.149](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.148...compiler_builtins-v0.1.149) - 2025-02-25 + +### Other + +- Make a subset of `libm` symbols weakly available on all platforms + ## [0.1.148](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.147...compiler_builtins-v0.1.148) - 2025-02-24 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 684a2a0b655..d1575d6df8f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.148" +version = "0.1.149" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 60ea5815b26aff290dce9f8a17973c59dc276dc8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 26 Feb 2025 07:40:35 +0000 Subject: Update LLVM downloads to 20.1-2025-02-13 This matches the version used by rust-lang/rust. --- library/compiler-builtins/.github/workflows/main.yml | 2 +- library/compiler-builtins/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 7336efc4224..fd1f6d5327d 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -4,7 +4,7 @@ on: [push, pull_request] env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings - RUST_LLVM_VERSION: 19.1-2024-09-17 + RUST_LLVM_VERSION: 20.1-2025-02-13 RUST_COMPILER_RT_ROOT: ./compiler-rt jobs: diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index a2b38cce0ef..d91d88a8559 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -89,8 +89,8 @@ to test against, located in a directory called `compiler-rt`. This can be obtained with the following: ```sh -curl -L -o rustc-llvm-19.1.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/19.1-2024-09-17.tar.gz -tar xzf rustc-llvm-19.1.tar.gz --strip-components 1 llvm-project-rustc-19.1-2024-09-17/compiler-rt +curl -L -o rustc-llvm-20.1.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/20.1-2025-02-13.tar.gz +tar xzf rustc-llvm-20.1.tar.gz --strip-components 1 llvm-project-rustc-20.1-2025-02-13/compiler-rt ``` Local targets may also be tested with `./ci/run.sh [target]`. -- cgit 1.4.1-3-g733a5 From afea1c05553570f6766abf91766982d108e71f12 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 1 Mar 2025 19:32:06 +0000 Subject: Disable `f16` on AArch64 without the `neon` feature There is an LLVM regression that breaks some `f16`-related code when `fp-armv8` is disabled [1]. Since Rust ties that feature to `neon`, disable `f16` if `neon` is not available. [1]: https://github.com/llvm/llvm-project/issues/129394 --- library/compiler-builtins/configure.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index ff52e88da0c..2bb0f83832c 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -71,6 +71,8 @@ pub fn configure_f16_f128(target: &Target) { let f16_enabled = match target.arch.as_str() { // Unsupported "arm64ec" => false, + // Crash in LLVM20 + "aarch64" if !target.features.iter().any(|f| f == "neon") => false, // Selection failure "s390x" => false, // Infinite recursion -- cgit 1.4.1-3-g733a5 From 4b664fd2ef43c5b53d2e7c80fc77f9848a937fcd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 19:40:30 +0000 Subject: chore: release v0.1.150 --- library/compiler-builtins/CHANGELOG.md | 7 +++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index 9b8aaaa0809..087a912d705 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.150](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.149...compiler_builtins-v0.1.150) - 2025-03-01 + +### Other + +- Disable `f16` on AArch64 without the `neon` feature +- Update LLVM downloads to 20.1-2025-02-13 + ## [0.1.149](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.148...compiler_builtins-v0.1.149) - 2025-02-25 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d1575d6df8f..3bf9b8ddda8 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.149" +version = "0.1.150" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 41f1ad27320e44bfe4e359188f0a627143065494 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 1 Mar 2025 23:20:04 -0500 Subject: Remove outdated information from the readme --- library/compiler-builtins/README.md | 48 ++++--------------------------------- 1 file changed, 5 insertions(+), 43 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index d91d88a8559..d76bd289ba5 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,50 +1,12 @@ # `compiler-builtins` -> Porting `compiler-rt` intrinsics to Rust +This crate provides external symbols that the compiler expects to be available when +building Rust projects, typically software routines for basic operations that do not +have hardware support. It is largely a port of LLVM's [`compiler-rt`]. -See [rust-lang/rust#35437][0]. +It is distributed as part of Rust's sysroot. -[0]: https://github.com/rust-lang/rust/issues/35437 - -## When and how to use this crate? - -If you are working with a target that doesn't have binary releases of std -available via rustup (this probably means you are building the core crate -yourself) and need compiler-rt intrinsics (i.e. you are probably getting linker -errors when building an executable: `undefined reference to __aeabi_memcpy`), -you can use this crate to get those intrinsics and solve the linker errors. To -do that, add this crate somewhere in the dependency graph of the crate you are -building: - -```toml -# Cargo.toml -[dependencies] -compiler_builtins = { git = "https://github.com/rust-lang/compiler-builtins" } -``` - -```rust -extern crate compiler_builtins; - -// ... -``` - -If you still get an "undefined reference to $INTRINSIC" error after that change, -that means that we haven't ported `$INTRINSIC` to Rust yet! Please open [an -issue] with the name of the intrinsic and the LLVM triple (e.g. -thumbv7m-none-eabi) of the target you are using. That way we can prioritize -porting that particular intrinsic. - -If you've got a C compiler available for your target then while we implement -this intrinsic you can temporarily enable a fallback to the actual compiler-rt -implementation as well for unimplemented intrinsics: - -```toml -[dependencies.compiler_builtins] -git = "https://github.com/rust-lang/compiler-builtins" -features = ["c"] -``` - -[an issue]: https://github.com/rust-lang/compiler-builtins/issues +[`compiler-rt`]: https://github.com/llvm/llvm-project/tree/1b1dc505057322f4fa1110ef4f53c44347f52986/compiler-rt ## Contributing -- cgit 1.4.1-3-g733a5 From 2de09ac46a493569c6ef8cd2505c238f5469b781 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 4 Mar 2025 16:21:15 -0500 Subject: Add __extendhfdf2 and add __truncdfhf2 test LLVM doesn't seem to emit this intrinsic but it probably should, in some cases it lowers f16->f64 conversions as f16->f32->f64 with two libcalls. GCC provides this intrinsic so it is good to have anyway. Additionally, add a test for f64->f16 which was missing. [1]: https://rust.godbolt.org/z/xezM9PEnz --- library/compiler-builtins/src/float/extend.rs | 8 ++++++++ library/compiler-builtins/testcrate/Cargo.toml | 3 ++- .../testcrate/benches/float_extend.rs | 23 ++++++++++++++++++++++ .../testcrate/benches/float_trunc.rs | 2 +- library/compiler-builtins/testcrate/build.rs | 11 +++++++++++ library/compiler-builtins/testcrate/tests/conv.rs | 2 ++ 6 files changed, 47 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index a1a9b9720a8..f05e3a924c1 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -96,6 +96,14 @@ intrinsics! { extend(a) } + #[avr_skip] + #[aapcs_on_arm] + #[apple_f16_arg_abi] + #[cfg(f16_enabled)] + pub extern "C" fn __extendhfdf2(a: f16) -> f64 { + extend(a) + } + #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __extendhfkf2] diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 21cec170109..91e2f668fc7 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -43,8 +43,9 @@ no-sys-f128 = ["no-sys-f128-int-convert", "no-sys-f16-f128-convert"] # Some platforms have some f128 functions but everything except integer conversions no-sys-f128-int-convert = [] no-sys-f16-f128-convert = [] +no-sys-f16-f64-convert = [] # Skip tests that rely on f16 symbols being available on the system -no-sys-f16 = [] +no-sys-f16 = ["no-sys-f16-f64-convert"] # Enable report generation without bringing in more dependencies by default benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] diff --git a/library/compiler-builtins/testcrate/benches/float_extend.rs b/library/compiler-builtins/testcrate/benches/float_extend.rs index a0cdaf48aca..12f19598458 100644 --- a/library/compiler-builtins/testcrate/benches/float_extend.rs +++ b/library/compiler-builtins/testcrate/benches/float_extend.rs @@ -28,6 +28,28 @@ float_bench! { ], } +#[cfg(f16_enabled)] +float_bench! { + name: extend_f16_f64, + sig: (a: f16) -> f64, + crate_fn: extend::__extendhfdf2, + sys_fn: __extendhfdf2, + sys_available: not(feature = "no-sys-f16-f64-convert"), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "fcvt {ret:d}, {a:h}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + #[cfg(all(f16_enabled, f128_enabled))] float_bench! { name: extend_f16_f128, @@ -93,6 +115,7 @@ pub fn float_extend() { #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] { extend_f16_f32(&mut criterion); + extend_f16_f64(&mut criterion); #[cfg(f128_enabled)] extend_f16_f128(&mut criterion); diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs index de9b5bf8c0b..cb6aee13a79 100644 --- a/library/compiler-builtins/testcrate/benches/float_trunc.rs +++ b/library/compiler-builtins/testcrate/benches/float_trunc.rs @@ -33,7 +33,7 @@ float_bench! { sig: (a: f64) -> f16, crate_fn: trunc::__truncdfhf2, sys_fn: __truncdfhf2, - sys_available: not(feature = "no-sys-f16"), + sys_available: not(feature = "no-sys-f16-f64-convert"), asm: [ #[cfg(target_arch = "aarch64")] { let ret: f16; diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 6205c7ac6fe..3e5f780ac66 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -6,6 +6,7 @@ enum Feature { NoSysF128, NoSysF128IntConvert, NoSysF16, + NoSysF16F64Convert, NoSysF16F128Convert, } @@ -66,9 +67,15 @@ fn main() { || target.arch == "wasm64" { features.insert(Feature::NoSysF16); + features.insert(Feature::NoSysF16F64Convert); features.insert(Feature::NoSysF16F128Convert); } + // These platforms are missing either `__extendhfdf2` or `__truncdfhf2`. + if target.vendor == "apple" || target.os == "windows" { + features.insert(Feature::NoSysF16F64Convert); + } + for feature in features { let (name, warning) = match feature { Feature::NoSysF128 => ("no-sys-f128", "using apfloat fallback for f128"), @@ -76,6 +83,10 @@ fn main() { "no-sys-f128-int-convert", "using apfloat fallback for f128 <-> int conversions", ), + Feature::NoSysF16F64Convert => ( + "no-sys-f16-f64-convert", + "using apfloat fallback for f16 <-> f64 conversions", + ), Feature::NoSysF16F128Convert => ( "no-sys-f16-f128-convert", "using apfloat fallback for f16 <-> f128 conversions", diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index a08748af781..7f33d27cce0 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -311,6 +311,7 @@ mod extend { extend, f16 => f32, Half => Single, __extendhfsf2, not(feature = "no-sys-f16"); f16 => f32, Half => Single, __gnu_h2f_ieee, not(feature = "no-sys-f16"); + f16 => f64, Half => Double, __extendhfdf2, not(feature = "no-sys-f16-f64-convert"); f16 => f128, Half => Quad, __extendhftf2, not(feature = "no-sys-f16-f128-convert"); f32 => f128, Single => Quad, __extendsftf2, not(feature = "no-sys-f128"); f64 => f128, Double => Quad, __extenddftf2, not(feature = "no-sys-f128"); @@ -340,6 +341,7 @@ mod trunc { trunc, f32 => f16, Single => Half, __truncsfhf2, not(feature = "no-sys-f16"); f32 => f16, Single => Half, __gnu_f2h_ieee, not(feature = "no-sys-f16"); + f64 => f16, Double => Half, __truncdfhf2, not(feature = "no-sys-f16-f64-convert"); f128 => f16, Quad => Half, __trunctfhf2, not(feature = "no-sys-f16-f128-convert"); f128 => f32, Quad => Single, __trunctfsf2, not(feature = "no-sys-f128"); f128 => f64, Quad => Double, __trunctfdf2, not(feature = "no-sys-f128"); -- cgit 1.4.1-3-g733a5 From 340d3d4bd7b804e976c5196da26c2af60e6267c1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 4 Mar 2025 17:46:50 -0500 Subject: Simplify test crate build features Since we have a handful of different float-related configuration in testcrate, track a list of which are implied by others rather than repeating the config. --- .../testcrate/benches/float_conv.rs | 2 +- library/compiler-builtins/testcrate/build.rs | 31 +++++++++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/testcrate/benches/float_conv.rs b/library/compiler-builtins/testcrate/benches/float_conv.rs index 0625a1ae5dd..7d8549b4326 100644 --- a/library/compiler-builtins/testcrate/benches/float_conv.rs +++ b/library/compiler-builtins/testcrate/benches/float_conv.rs @@ -665,7 +665,7 @@ pub fn float_conv() { conv_f64_i64(&mut criterion); conv_f64_i128(&mut criterion); - #[cfg(all(f128_enabled))] + #[cfg(f128_enabled)] // FIXME: ppc64le has a sporadic overflow panic in the crate functions // #[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 3e5f780ac66..427fa799b8c 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -1,7 +1,11 @@ use std::collections::HashSet; +mod builtins_configure { + include!("../configure.rs"); +} + /// Features to enable -#[derive(Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] enum Feature { NoSysF128, NoSysF128IntConvert, @@ -10,8 +14,16 @@ enum Feature { NoSysF16F128Convert, } -mod builtins_configure { - include!("../configure.rs"); +impl Feature { + fn implies(self) -> &'static [Self] { + match self { + Self::NoSysF128 => [Self::NoSysF128IntConvert, Self::NoSysF16F128Convert].as_slice(), + Self::NoSysF128IntConvert => [].as_slice(), + Self::NoSysF16 => [Self::NoSysF16F64Convert, Self::NoSysF16F128Convert].as_slice(), + Self::NoSysF16F64Convert => [].as_slice(), + Self::NoSysF16F128Convert => [].as_slice(), + } + } } fn main() { @@ -40,8 +52,6 @@ fn main() { || target.arch == "powerpc64" { features.insert(Feature::NoSysF128); - features.insert(Feature::NoSysF128IntConvert); - features.insert(Feature::NoSysF16F128Convert); } if target.arch == "x86" { @@ -67,8 +77,6 @@ fn main() { || target.arch == "wasm64" { features.insert(Feature::NoSysF16); - features.insert(Feature::NoSysF16F64Convert); - features.insert(Feature::NoSysF16F128Convert); } // These platforms are missing either `__extendhfdf2` or `__truncdfhf2`. @@ -76,6 +84,15 @@ fn main() { features.insert(Feature::NoSysF16F64Convert); } + // Add implied features. Collection is required for borrows. + features.extend( + features + .iter() + .flat_map(|x| x.implies()) + .copied() + .collect::>(), + ); + for feature in features { let (name, warning) = match feature { Feature::NoSysF128 => ("no-sys-f128", "using apfloat fallback for f128"), -- cgit 1.4.1-3-g733a5 From 968a7d0b7cdc071e866711a28466ae94e7c2b166 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 4 Mar 2025 17:36:27 -0500 Subject: Add a test config for __gnu_h2f_ieee and __gnu_f2h_ieee Some targets do not provide these symbols since they always use __extendhfsf and __truncsfhf. Add a configuration option for this. --- library/compiler-builtins/testcrate/Cargo.toml | 3 ++- library/compiler-builtins/testcrate/build.rs | 18 +++++++++++++++++- library/compiler-builtins/testcrate/tests/conv.rs | 4 ++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 91e2f668fc7..e06864846fd 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -44,8 +44,9 @@ no-sys-f128 = ["no-sys-f128-int-convert", "no-sys-f16-f128-convert"] no-sys-f128-int-convert = [] no-sys-f16-f128-convert = [] no-sys-f16-f64-convert = [] +no-sys-f16-gnu-convert = [] # Skip tests that rely on f16 symbols being available on the system -no-sys-f16 = ["no-sys-f16-f64-convert"] +no-sys-f16 = ["no-sys-f16-f64-convert", "no-sys-f16-gnu-convert"] # Enable report generation without bringing in more dependencies by default benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 427fa799b8c..171c1d52114 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -12,6 +12,7 @@ enum Feature { NoSysF16, NoSysF16F64Convert, NoSysF16F128Convert, + NoSysF16GnuConvert, } impl Feature { @@ -19,9 +20,15 @@ impl Feature { match self { Self::NoSysF128 => [Self::NoSysF128IntConvert, Self::NoSysF16F128Convert].as_slice(), Self::NoSysF128IntConvert => [].as_slice(), - Self::NoSysF16 => [Self::NoSysF16F64Convert, Self::NoSysF16F128Convert].as_slice(), + Self::NoSysF16 => [ + Self::NoSysF16F64Convert, + Self::NoSysF16F128Convert, + Feature::NoSysF16GnuConvert, + ] + .as_slice(), Self::NoSysF16F64Convert => [].as_slice(), Self::NoSysF16F128Convert => [].as_slice(), + Self::NoSysF16GnuConvert => [].as_slice(), } } } @@ -84,6 +91,11 @@ fn main() { features.insert(Feature::NoSysF16F64Convert); } + // These platforms do not have `__gnu_f2h_ieee` or `__gnu_h2f_ieee`. + if false { + features.insert(Feature::NoSysF16GnuConvert); + } + // Add implied features. Collection is required for borrows. features.extend( features @@ -108,6 +120,10 @@ fn main() { "no-sys-f16-f128-convert", "using apfloat fallback for f16 <-> f128 conversions", ), + Feature::NoSysF16GnuConvert => ( + "no-sys-f16-gnu-convert", + "using apfloat fallback for __gnu f16", + ), Feature::NoSysF16 => ("no-sys-f16", "using apfloat fallback for f16"), }; println!("cargo:warning={warning}"); diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 7f33d27cce0..f94aaf17402 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -310,7 +310,7 @@ mod extend { f_to_f! { extend, f16 => f32, Half => Single, __extendhfsf2, not(feature = "no-sys-f16"); - f16 => f32, Half => Single, __gnu_h2f_ieee, not(feature = "no-sys-f16"); + f16 => f32, Half => Single, __gnu_h2f_ieee, not(feature = "no-sys-f16-gnu-convert"); f16 => f64, Half => Double, __extendhfdf2, not(feature = "no-sys-f16-f64-convert"); f16 => f128, Half => Quad, __extendhftf2, not(feature = "no-sys-f16-f128-convert"); f32 => f128, Single => Quad, __extendsftf2, not(feature = "no-sys-f128"); @@ -340,7 +340,7 @@ mod trunc { f_to_f! { trunc, f32 => f16, Single => Half, __truncsfhf2, not(feature = "no-sys-f16"); - f32 => f16, Single => Half, __gnu_f2h_ieee, not(feature = "no-sys-f16"); + f32 => f16, Single => Half, __gnu_f2h_ieee, not(feature = "no-sys-f16-gnu-convert"); f64 => f16, Double => Half, __truncdfhf2, not(feature = "no-sys-f16-f64-convert"); f128 => f16, Quad => Half, __trunctfhf2, not(feature = "no-sys-f16-f128-convert"); f128 => f32, Quad => Single, __trunctfsf2, not(feature = "no-sys-f128"); -- cgit 1.4.1-3-g733a5 From e4c1eb803dccfb1d3398d0a4ac7464e9d1d87f78 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 4 Mar 2025 22:06:35 -0500 Subject: Revert "ci: Pin the nightly toolchain for aarch64-unknown-linux-gnu" The fix to this issue was synced in [1] so we should no longer need to keep aarch64 pinned. This reverts commit b2bcfc838e2a4b72fa62b333e3eb91f250aa4539. [1]: https://github.com/rust-lang/rust/pull/137661 --- library/compiler-builtins/.github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index fd1f6d5327d..1c367a2d0da 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -20,8 +20,7 @@ jobs: rust: nightly - target: aarch64-unknown-linux-gnu os: ubuntu-latest - # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 - rust: nightly-2025-02-07 + rust: nightly - target: aarch64-pc-windows-msvc os: windows-latest rust: nightly -- cgit 1.4.1-3-g733a5 From 890cd1e0f99aabf36e09e1e31a21f9f7515c0073 Mon Sep 17 00:00:00 2001 From: hev Date: Wed, 5 Mar 2025 14:11:51 +0800 Subject: Enable `f16` for LoongArch (#770) [ the configured-out tests should be re-enabled once we have the symbols in nightly - Trevor ] --- library/compiler-builtins/configure.rs | 2 -- library/compiler-builtins/testcrate/build.rs | 1 + library/compiler-builtins/testcrate/tests/conv.rs | 12 ++++++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index 2bb0f83832c..931e9662939 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -76,10 +76,8 @@ pub fn configure_f16_f128(target: &Target) { // Selection failure "s390x" => false, // Infinite recursion - // FIXME(llvm20): loongarch fixed by "csky" => false, "hexagon" => false, - "loongarch64" => false, "powerpc" | "powerpc64" => false, "sparc" | "sparc64" => false, "wasm32" | "wasm64" => false, diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 171c1d52114..868d8700df3 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -75,6 +75,7 @@ fn main() { || target.arch == "powerpc" || target.arch == "powerpc64" || target.arch == "powerpc64le" + || target.arch == "loongarch64" || (target.arch == "x86" && !target.has_feature("sse")) || target.os == "windows" // Linking says "error: function signature mismatch: __extendhfsf2" and seems to diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index f94aaf17402..d706635408b 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -306,7 +306,11 @@ mod extend { } #[cfg(all(f16_enabled, f128_enabled))] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(not(any( + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "loongarch64" + )))] f_to_f! { extend, f16 => f32, Half => Single, __extendhfsf2, not(feature = "no-sys-f16"); @@ -336,7 +340,11 @@ mod trunc { } #[cfg(all(f16_enabled, f128_enabled))] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(not(any( + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "loongarch64" + )))] f_to_f! { trunc, f32 => f16, Single => Half, __truncsfhf2, not(feature = "no-sys-f16"); -- cgit 1.4.1-3-g733a5 From f5f09d2f4bbc4fc041554ea101a90cc5b23b3c62 Mon Sep 17 00:00:00 2001 From: 王宇逸 Date: Fri, 28 Feb 2025 23:17:56 +0800 Subject: Add cygwin support Co-authored-by: Ookiineko --- library/compiler-builtins/build.rs | 14 ++++++++------ library/compiler-builtins/examples/intrinsics.rs | 6 +++--- library/compiler-builtins/src/macros.rs | 18 +++++++++--------- library/compiler-builtins/src/probestack.rs | 4 ++-- library/compiler-builtins/src/x86_64.rs | 6 +++++- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 39cee311f85..3c04423f2d8 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -575,7 +575,7 @@ mod c { ("__fe_raise_inexact", "fp_mode.c"), ]); - if target.os != "windows" { + if target.os != "windows" && target.os != "cygwin" { sources.extend(&[("__multc3", "multc3.c")]); } } @@ -608,13 +608,15 @@ mod c { sources.remove(&["__aeabi_cdcmp", "__aeabi_cfcmp"]); } - // Android uses emulated TLS so we need a runtime support function. - if target.os == "android" { + // Android and Cygwin uses emulated TLS so we need a runtime support function. + if target.os == "android" || target.os == "cygwin" { sources.extend(&[("__emutls_get_address", "emutls.c")]); + } - // Work around a bug in the NDK headers (fixed in - // https://r.android.com/2038949 which will be released in a future - // NDK version) by providing a definition of LONG_BIT. + // Work around a bug in the NDK headers (fixed in + // https://r.android.com/2038949 which will be released in a future + // NDK version) by providing a definition of LONG_BIT. + if target.os == "android" { cfg.define("LONG_BIT", "(8 * sizeof(long))"); } diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 59a70e20745..e90cfb33dea 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -673,17 +673,17 @@ pub fn __aeabi_unwind_cpp_pr0() {} #[no_mangle] pub fn __aeabi_unwind_cpp_pr1() {} -#[cfg(not(windows))] +#[cfg(not(any(windows, target_os = "cygwin")))] #[allow(non_snake_case)] #[no_mangle] pub fn _Unwind_Resume() {} -#[cfg(not(windows))] +#[cfg(not(any(windows, target_os = "cygwin")))] #[lang = "eh_personality"] #[no_mangle] pub extern "C" fn eh_personality() {} -#[cfg(all(windows, target_env = "gnu"))] +#[cfg(any(all(windows, target_env = "gnu"), target_os = "cygwin"))] mod mingw_unwinding { #[no_mangle] pub fn rust_eh_personality() {} diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 5d9f5819757..b1b71379cc9 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -193,7 +193,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(any(windows, all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64"))] + #[cfg(all(any(windows, target_os = "cygwin", all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64"))] intrinsics! { $(#[$($attr)*])* pub extern "unadjusted" fn $name( $($argname: $ty),* ) $(-> $ret)? { @@ -201,7 +201,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(any(windows, all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64")))] + #[cfg(not(all(any(windows, target_os = "cygwin", all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64")))] intrinsics! { $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { @@ -257,7 +257,7 @@ macro_rules! intrinsics { #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] mod $name { #[no_mangle] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern $abi fn $name( $($argname: u16),* ) $(-> $ret)? { super::$name($(f16::from_bits($argname)),*) @@ -293,7 +293,7 @@ macro_rules! intrinsics { #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] mod $name { #[no_mangle] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern $abi fn $name( $($argname: $ty),* ) -> u16 { super::$name($($argname),*).to_bits() @@ -334,7 +334,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] mod $name { #[no_mangle] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) @@ -344,7 +344,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] mod $alias { #[no_mangle] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) @@ -411,7 +411,7 @@ macro_rules! intrinsics { mod $name { $(#[$($attr)*])* #[no_mangle] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -436,7 +436,7 @@ macro_rules! intrinsics { #[naked] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -503,7 +503,7 @@ macro_rules! intrinsics { mod $name { $(#[$($attr)*])* #[no_mangle] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 0c30384db38..5b6abd21a1d 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -42,8 +42,8 @@ //! be more than welcome to accept such a change! #![cfg(not(feature = "mangled-names"))] -// Windows already has builtins to do this. -#![cfg(not(windows))] +// Windows and Cygwin already has builtins to do this. +#![cfg(not(any(windows, target_os = "cygwin")))] // All these builtins require assembly #![cfg(not(feature = "no-asm"))] // We only define stack probing for these architectures today. diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 9c91a45561e..aae601f58bf 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -10,7 +10,11 @@ use core::intrinsics; intrinsics! { #[naked] #[cfg(all( - any(all(windows, target_env = "gnu"), target_os = "uefi"), + any( + all(windows, target_env = "gnu"), + target_os = "cygwin", + target_os = "uefi" + ), not(feature = "no-asm") ))] pub unsafe extern "C" fn ___chkstk_ms() { -- cgit 1.4.1-3-g733a5 From 795fa2f40a859514c20abb3be926ed430cf04907 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 06:18:13 +0000 Subject: chore: release v0.1.151 --- library/compiler-builtins/CHANGELOG.md | 9 +++++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index 087a912d705..763b0e10ed0 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.151](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.150...compiler_builtins-v0.1.151) - 2025-03-05 + +### Other + +- Add cygwin support +- Enable `f16` for LoongArch ([#770](https://github.com/rust-lang/compiler-builtins/pull/770)) +- Add __extendhfdf2 and add __truncdfhf2 test +- Remove outdated information from the readme + ## [0.1.150](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.149...compiler_builtins-v0.1.150) - 2025-03-01 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 3bf9b8ddda8..baef22aa75a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.150" +version = "0.1.151" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 4735ded783f3e6cf1b31a19c7f7f21baee61d41f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 5 Mar 2025 01:36:52 -0500 Subject: Revert "Add a test config for __gnu_h2f_ieee and __gnu_f2h_ieee" This turned out to not be useful, so remove it. This reverts commit b7b93103fb9293c0c502dc1ae34e2ad5c871bc39. --- library/compiler-builtins/testcrate/Cargo.toml | 3 +-- library/compiler-builtins/testcrate/build.rs | 18 +----------------- library/compiler-builtins/testcrate/tests/conv.rs | 4 ++-- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index e06864846fd..91e2f668fc7 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -44,9 +44,8 @@ no-sys-f128 = ["no-sys-f128-int-convert", "no-sys-f16-f128-convert"] no-sys-f128-int-convert = [] no-sys-f16-f128-convert = [] no-sys-f16-f64-convert = [] -no-sys-f16-gnu-convert = [] # Skip tests that rely on f16 symbols being available on the system -no-sys-f16 = ["no-sys-f16-f64-convert", "no-sys-f16-gnu-convert"] +no-sys-f16 = ["no-sys-f16-f64-convert"] # Enable report generation without bringing in more dependencies by default benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 868d8700df3..15e4e771ca0 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -12,7 +12,6 @@ enum Feature { NoSysF16, NoSysF16F64Convert, NoSysF16F128Convert, - NoSysF16GnuConvert, } impl Feature { @@ -20,15 +19,9 @@ impl Feature { match self { Self::NoSysF128 => [Self::NoSysF128IntConvert, Self::NoSysF16F128Convert].as_slice(), Self::NoSysF128IntConvert => [].as_slice(), - Self::NoSysF16 => [ - Self::NoSysF16F64Convert, - Self::NoSysF16F128Convert, - Feature::NoSysF16GnuConvert, - ] - .as_slice(), + Self::NoSysF16 => [Self::NoSysF16F64Convert, Self::NoSysF16F128Convert].as_slice(), Self::NoSysF16F64Convert => [].as_slice(), Self::NoSysF16F128Convert => [].as_slice(), - Self::NoSysF16GnuConvert => [].as_slice(), } } } @@ -92,11 +85,6 @@ fn main() { features.insert(Feature::NoSysF16F64Convert); } - // These platforms do not have `__gnu_f2h_ieee` or `__gnu_h2f_ieee`. - if false { - features.insert(Feature::NoSysF16GnuConvert); - } - // Add implied features. Collection is required for borrows. features.extend( features @@ -121,10 +109,6 @@ fn main() { "no-sys-f16-f128-convert", "using apfloat fallback for f16 <-> f128 conversions", ), - Feature::NoSysF16GnuConvert => ( - "no-sys-f16-gnu-convert", - "using apfloat fallback for __gnu f16", - ), Feature::NoSysF16 => ("no-sys-f16", "using apfloat fallback for f16"), }; println!("cargo:warning={warning}"); diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index d706635408b..db1493cae9a 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -314,7 +314,7 @@ mod extend { f_to_f! { extend, f16 => f32, Half => Single, __extendhfsf2, not(feature = "no-sys-f16"); - f16 => f32, Half => Single, __gnu_h2f_ieee, not(feature = "no-sys-f16-gnu-convert"); + f16 => f32, Half => Single, __gnu_h2f_ieee, not(feature = "no-sys-f16"); f16 => f64, Half => Double, __extendhfdf2, not(feature = "no-sys-f16-f64-convert"); f16 => f128, Half => Quad, __extendhftf2, not(feature = "no-sys-f16-f128-convert"); f32 => f128, Single => Quad, __extendsftf2, not(feature = "no-sys-f128"); @@ -348,7 +348,7 @@ mod trunc { f_to_f! { trunc, f32 => f16, Single => Half, __truncsfhf2, not(feature = "no-sys-f16"); - f32 => f16, Single => Half, __gnu_f2h_ieee, not(feature = "no-sys-f16-gnu-convert"); + f32 => f16, Single => Half, __gnu_f2h_ieee, not(feature = "no-sys-f16"); f64 => f16, Double => Half, __truncdfhf2, not(feature = "no-sys-f16-f64-convert"); f128 => f16, Quad => Half, __trunctfhf2, not(feature = "no-sys-f16-f128-convert"); f128 => f32, Quad => Single, __trunctfsf2, not(feature = "no-sys-f128"); -- cgit 1.4.1-3-g733a5 From 2d8c36296392290f168a024d7a18954be5979e07 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Mar 2025 08:50:35 +0000 Subject: Migrate `testcrate` and `panic-handler` to edition 2024 Includes `extern` -> `unsafe extern` blocks and formatting updates. --- library/compiler-builtins/crates/panic-handler/Cargo.toml | 2 +- library/compiler-builtins/testcrate/Cargo.toml | 2 +- library/compiler-builtins/testcrate/benches/float_add.rs | 2 +- library/compiler-builtins/testcrate/benches/float_cmp.rs | 2 +- library/compiler-builtins/testcrate/benches/float_conv.rs | 2 +- library/compiler-builtins/testcrate/benches/float_div.rs | 2 +- library/compiler-builtins/testcrate/benches/float_extend.rs | 2 +- library/compiler-builtins/testcrate/benches/float_mul.rs | 2 +- library/compiler-builtins/testcrate/benches/float_pow.rs | 2 +- library/compiler-builtins/testcrate/benches/float_sub.rs | 2 +- library/compiler-builtins/testcrate/benches/float_trunc.rs | 2 +- library/compiler-builtins/testcrate/benches/mem.rs | 2 +- library/compiler-builtins/testcrate/src/bench.rs | 7 ++++++- library/compiler-builtins/testcrate/src/lib.rs | 2 +- library/compiler-builtins/testcrate/tests/big.rs | 2 +- 15 files changed, 20 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/crates/panic-handler/Cargo.toml b/library/compiler-builtins/crates/panic-handler/Cargo.toml index 2ad85840900..96b83eaa226 100644 --- a/library/compiler-builtins/crates/panic-handler/Cargo.toml +++ b/library/compiler-builtins/crates/panic-handler/Cargo.toml @@ -2,7 +2,7 @@ name = "panic-handler" version = "0.1.0" authors = ["Alex Crichton "] -edition = "2021" +edition = "2024" publish = false [dependencies] diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 91e2f668fc7..71c461c578c 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -2,7 +2,7 @@ name = "testcrate" version = "0.1.0" authors = ["Alex Crichton "] -edition = "2021" +edition = "2024" publish = false [lib] diff --git a/library/compiler-builtins/testcrate/benches/float_add.rs b/library/compiler-builtins/testcrate/benches/float_add.rs index 3311e7b5b29..a578655f8f4 100644 --- a/library/compiler-builtins/testcrate/benches/float_add.rs +++ b/library/compiler-builtins/testcrate/benches/float_add.rs @@ -1,7 +1,7 @@ #![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::add; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; float_bench! { diff --git a/library/compiler-builtins/testcrate/benches/float_cmp.rs b/library/compiler-builtins/testcrate/benches/float_cmp.rs index 400c09b427a..4c269e4889c 100644 --- a/library/compiler-builtins/testcrate/benches/float_cmp.rs +++ b/library/compiler-builtins/testcrate/benches/float_cmp.rs @@ -1,6 +1,6 @@ #![cfg_attr(f128_enabled, feature(f128))] -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; use compiler_builtins::float::cmp; diff --git a/library/compiler-builtins/testcrate/benches/float_conv.rs b/library/compiler-builtins/testcrate/benches/float_conv.rs index 7d8549b4326..e3f2af86344 100644 --- a/library/compiler-builtins/testcrate/benches/float_conv.rs +++ b/library/compiler-builtins/testcrate/benches/float_conv.rs @@ -2,7 +2,7 @@ #![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::conv; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; /* unsigned int -> float */ diff --git a/library/compiler-builtins/testcrate/benches/float_div.rs b/library/compiler-builtins/testcrate/benches/float_div.rs index 6a039a82a93..c42f3f38671 100644 --- a/library/compiler-builtins/testcrate/benches/float_div.rs +++ b/library/compiler-builtins/testcrate/benches/float_div.rs @@ -1,7 +1,7 @@ #![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::div; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; float_bench! { diff --git a/library/compiler-builtins/testcrate/benches/float_extend.rs b/library/compiler-builtins/testcrate/benches/float_extend.rs index 12f19598458..1e7fedefe70 100644 --- a/library/compiler-builtins/testcrate/benches/float_extend.rs +++ b/library/compiler-builtins/testcrate/benches/float_extend.rs @@ -3,7 +3,7 @@ #![cfg_attr(f16_enabled, feature(f16))] use compiler_builtins::float::extend; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; #[cfg(f16_enabled)] diff --git a/library/compiler-builtins/testcrate/benches/float_mul.rs b/library/compiler-builtins/testcrate/benches/float_mul.rs index 6e30b7866c7..0857a68a22e 100644 --- a/library/compiler-builtins/testcrate/benches/float_mul.rs +++ b/library/compiler-builtins/testcrate/benches/float_mul.rs @@ -1,7 +1,7 @@ #![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::mul; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; float_bench! { diff --git a/library/compiler-builtins/testcrate/benches/float_pow.rs b/library/compiler-builtins/testcrate/benches/float_pow.rs index 46da3f25ceb..e84fee51ca9 100644 --- a/library/compiler-builtins/testcrate/benches/float_pow.rs +++ b/library/compiler-builtins/testcrate/benches/float_pow.rs @@ -1,7 +1,7 @@ #![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::pow; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; float_bench! { diff --git a/library/compiler-builtins/testcrate/benches/float_sub.rs b/library/compiler-builtins/testcrate/benches/float_sub.rs index cdb678eef05..7a6c05ea5c1 100644 --- a/library/compiler-builtins/testcrate/benches/float_sub.rs +++ b/library/compiler-builtins/testcrate/benches/float_sub.rs @@ -1,7 +1,7 @@ #![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::sub; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; float_bench! { diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs index cb6aee13a79..4ceb62ab06a 100644 --- a/library/compiler-builtins/testcrate/benches/float_trunc.rs +++ b/library/compiler-builtins/testcrate/benches/float_trunc.rs @@ -2,7 +2,7 @@ #![cfg_attr(f16_enabled, feature(f16))] use compiler_builtins::float::trunc; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; #[cfg(f16_enabled)] diff --git a/library/compiler-builtins/testcrate/benches/mem.rs b/library/compiler-builtins/testcrate/benches/mem.rs index 98a040958c4..3f83926b6c5 100644 --- a/library/compiler-builtins/testcrate/benches/mem.rs +++ b/library/compiler-builtins/testcrate/benches/mem.rs @@ -1,7 +1,7 @@ #![feature(test)] extern crate test; -use test::{black_box, Bencher}; +use test::{Bencher, black_box}; extern crate compiler_builtins; use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs index f5da1f3ae50..45a3a1ad467 100644 --- a/library/compiler-builtins/testcrate/src/bench.rs +++ b/library/compiler-builtins/testcrate/src/bench.rs @@ -89,6 +89,10 @@ pub fn skip_asm_checks(_test_name: &str) -> bool { /// Create a comparison of the system symbol, compiler_builtins, and optionally handwritten /// assembly. +/// +/// # Safety +/// +/// The signature must be correct and any assembly must be sound. #[macro_export] macro_rules! float_bench { ( @@ -120,8 +124,9 @@ macro_rules! float_bench { ] $(,)? ) => {paste::paste! { + // SAFETY: macro invocation must use the correct signature #[cfg($sys_available)] - extern "C" { + unsafe extern "C" { /// Binding for the system function #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] fn $sys_fn($($arg: $arg_ty),*) -> $ret_ty; diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 894c2782a45..c61618755e9 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -22,8 +22,8 @@ extern crate alloc; use compiler_builtins::float::Float; use compiler_builtins::int::{Int, MinInt}; -use rand_xoshiro::rand_core::{RngCore, SeedableRng}; use rand_xoshiro::Xoshiro128StarStar; +use rand_xoshiro::rand_core::{RngCore, SeedableRng}; /// Sets the number of fuzz iterations run for most tests. In practice, the vast majority of bugs /// are caught by the edge case testers. Most of the remaining bugs triggered by more complex diff --git a/library/compiler-builtins/testcrate/tests/big.rs b/library/compiler-builtins/testcrate/tests/big.rs index 595f6225607..d1ae88bd164 100644 --- a/library/compiler-builtins/testcrate/tests/big.rs +++ b/library/compiler-builtins/testcrate/tests/big.rs @@ -1,4 +1,4 @@ -use compiler_builtins::int::{i256, u256, HInt, MinInt}; +use compiler_builtins::int::{HInt, MinInt, i256, u256}; const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; -- cgit 1.4.1-3-g733a5 From 1112886edcfc515e4c3492dc60fa7234e5227caf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Mar 2025 08:57:10 +0000 Subject: Use the v2 resolver in the workspace --- library/compiler-builtins/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index baef22aa75a..9d144834206 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -76,6 +76,7 @@ name = "intrinsics" required-features = ["compiler-builtins"] [workspace] +resolver = "2" members = ["testcrate"] [profile.release] -- cgit 1.4.1-3-g733a5 From 1fb5e1a5ba8129c13790320a855623fb9e3170c3 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 8 Mar 2025 00:20:34 +0000 Subject: Replace some uses of `sign` with `sig` It seems like "sign" was used as a shortened version of "significand", but that is easy to confuse with "sign". Update these to use "sig" like most other places. --- library/compiler-builtins/src/float/extend.rs | 22 +++++++++++----------- library/compiler-builtins/src/float/trunc.rs | 8 ++++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index f05e3a924c1..ce00da31dc5 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -15,22 +15,22 @@ where let src_zero = F::Int::ZERO; let src_one = F::Int::ONE; let src_bits = F::BITS; - let src_sign_bits = F::SIG_BITS; + let src_sig_bits = F::SIG_BITS; let src_exp_bias = F::EXP_BIAS; let src_min_normal = F::IMPLICIT_BIT; let src_infinity = F::EXP_MASK; - let src_sign_mask = F::SIGN_MASK as F::Int; + let src_sign_mask = F::SIGN_MASK; let src_abs_mask = src_sign_mask - src_one; let src_qnan = F::SIG_MASK; let src_nan_code = src_qnan - src_one; let dst_bits = R::BITS; - let dst_sign_bits = R::SIG_BITS; + let dst_sig_bits = R::SIG_BITS; let dst_inf_exp = R::EXP_SAT; let dst_exp_bias = R::EXP_BIAS; let dst_min_normal = R::IMPLICIT_BIT; - let sign_bits_delta = dst_sign_bits - src_sign_bits; + let sig_bits_delta = dst_sig_bits - src_sig_bits; let exp_bias_delta = dst_exp_bias - src_exp_bias; let a_abs = a.to_bits() & src_abs_mask; let mut abs_result = R::Int::ZERO; @@ -41,8 +41,8 @@ where // exponent into the proper position and rebiasing the exponent. let abs_dst: R::Int = a_abs.cast(); let bias_dst: R::Int = exp_bias_delta.cast(); - abs_result = abs_dst.wrapping_shl(sign_bits_delta); - abs_result += bias_dst.wrapping_shl(dst_sign_bits); + abs_result = abs_dst.wrapping_shl(sig_bits_delta); + abs_result += bias_dst.wrapping_shl(dst_sig_bits); } else if a_abs >= src_infinity { // a is NaN or infinity. // Conjure the result by beginning with infinity, then setting the qNaN @@ -51,9 +51,9 @@ where let qnan_dst: R::Int = (a_abs & src_qnan).cast(); let nan_code_dst: R::Int = (a_abs & src_nan_code).cast(); let inf_exp_dst: R::Int = dst_inf_exp.cast(); - abs_result = inf_exp_dst.wrapping_shl(dst_sign_bits); - abs_result |= qnan_dst.wrapping_shl(sign_bits_delta); - abs_result |= nan_code_dst.wrapping_shl(sign_bits_delta); + abs_result = inf_exp_dst.wrapping_shl(dst_sig_bits); + abs_result |= qnan_dst.wrapping_shl(sig_bits_delta); + abs_result |= nan_code_dst.wrapping_shl(sig_bits_delta); } else if a_abs != src_zero { // a is denormal. // Renormalize the significand and clear the leading bit, then insert @@ -61,8 +61,8 @@ where let scale = a_abs.leading_zeros() - src_min_normal.leading_zeros(); let abs_dst: R::Int = a_abs.cast(); let bias_dst: R::Int = (exp_bias_delta - scale + 1).cast(); - abs_result = abs_dst.wrapping_shl(sign_bits_delta + scale); - abs_result = (abs_result ^ dst_min_normal) | (bias_dst.wrapping_shl(dst_sign_bits)); + abs_result = abs_dst.wrapping_shl(sig_bits_delta + scale); + abs_result = (abs_result ^ dst_min_normal) | (bias_dst.wrapping_shl(dst_sig_bits)); } let sign_result: R::Int = (a.to_bits() & src_sign_mask).cast(); diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 3759aa7dc43..928eba0c8ef 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -17,7 +17,7 @@ where let src_exp_bias = F::EXP_BIAS; let src_min_normal = F::IMPLICIT_BIT; - let src_significand_mask = F::SIG_MASK; + let src_sig_mask = F::SIG_MASK; let src_infinity = F::EXP_MASK; let src_sign_mask = F::SIGN_MASK; let src_abs_mask = src_sign_mask - src_one; @@ -40,7 +40,7 @@ where let dst_qnan = R::Int::ONE << (R::SIG_BITS - 1); let dst_nan_code = dst_qnan - dst_one; - let sign_bits_delta = F::SIG_BITS - R::SIG_BITS; + let sig_bits_delta = F::SIG_BITS - R::SIG_BITS; // Break a into a sign and representation of the absolute value. let a_abs = a.to_bits() & src_abs_mask; let sign = a.to_bits() & src_sign_mask; @@ -50,7 +50,7 @@ where // The exponent of a is within the range of normal numbers in the // destination format. We can convert by simply right-shifting with // rounding and adjusting the exponent. - abs_result = (a_abs >> sign_bits_delta).cast(); + abs_result = (a_abs >> sig_bits_delta).cast(); // Cast before shifting to prevent overflow. let bias_diff: R::Int = src_exp_bias.wrapping_sub(dst_exp_bias).cast(); let tmp = bias_diff << R::SIG_BITS; @@ -85,7 +85,7 @@ where let a_exp: u32 = (a_abs >> F::SIG_BITS).cast(); let shift = src_exp_bias - dst_exp_bias - a_exp + 1; - let significand = (a.to_bits() & src_significand_mask) | src_min_normal; + let significand = (a.to_bits() & src_sig_mask) | src_min_normal; // Right shift by the denormalization amount with sticky. if shift > F::SIG_BITS { -- cgit 1.4.1-3-g733a5 From 192206bfbb57ed2781ccc9319405038e5778c1a5 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Mon, 17 Mar 2025 02:41:53 +0100 Subject: Revert "Disable some PPC64 tests which are failing due to an LLVM(?) bug" This reverts commit 265fdacab9b3c63b2c17a42fb17c51996c703ef8. Fixes: https://github.com/rust-lang/rust/issues/99853 Signed-off-by: Jens Reidel --- library/compiler-builtins/testcrate/tests/mem.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs index 5099d69ed6c..48ac95adc17 100644 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -230,8 +230,6 @@ fn memmove_backward_aligned() { } } -// PowerPC tests are failing: https://github.com/rust-lang/rust/issues/99853 -#[cfg(not(target_arch = "powerpc64"))] #[test] fn memset_backward_misaligned_nonaligned_start() { let mut arr = gen_arr::<32>(); @@ -244,8 +242,6 @@ fn memset_backward_misaligned_nonaligned_start() { } } -// PowerPC tests are failing: https://github.com/rust-lang/rust/issues/99853 -#[cfg(not(target_arch = "powerpc64"))] #[test] fn memset_backward_misaligned_aligned_start() { let mut arr = gen_arr::<32>(); @@ -258,8 +254,6 @@ fn memset_backward_misaligned_aligned_start() { } } -// PowerPC tests are failing: https://github.com/rust-lang/rust/issues/99853 -#[cfg(not(target_arch = "powerpc64"))] #[test] fn memset_backward_aligned() { let mut arr = gen_arr::<32>(); -- cgit 1.4.1-3-g733a5 From 6d353134bccd7e14aaba2c3476fc754f1fc16a48 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Mon, 17 Mar 2025 21:59:56 +0100 Subject: Revert "Disable broken powerpc64 test due to https://github.com/rust-lang/rust/issues/88520" This reverts commit 55f6ecb6de9e2e10d9187b287b9e87b202d07d1e. Fixes: https://github.com/rust-lang/rust/issues/88520 Signed-off-by: Jens Reidel --- library/compiler-builtins/testcrate/tests/cmp.rs | 3 --- library/compiler-builtins/testcrate/tests/conv.rs | 2 -- 2 files changed, 5 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index e3161f37429..19d90c66493 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -2,11 +2,8 @@ #![allow(unreachable_code)] #![cfg_attr(f128_enabled, feature(f128))] -#[cfg(not(target_arch = "powerpc64"))] use testcrate::*; -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] mod float_comparisons { use super::*; diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index db1493cae9a..381d3e15578 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -141,8 +141,6 @@ mod i_to_f { } } -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] mod f_to_i { use super::*; -- cgit 1.4.1-3-g733a5 From 590a56483cc32e2cd38a6de76c71c319db997360 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Mar 2025 16:36:38 +0100 Subject: remove element_unordered_atomic intrinsics --- library/compiler-builtins/src/mem/mod.rs | 132 ------------------------------- 1 file changed, 132 deletions(-) diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index f10439e2d3f..ec160039d0d 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -8,10 +8,6 @@ type c_int = i16; #[cfg(not(target_pointer_width = "16"))] type c_int = i32; -use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, exact_div}; -use core::mem; -use core::ops::{BitOr, Shl}; - // memcpy/memmove/memset have optimized implementations on some architectures #[cfg_attr( all(not(feature = "no-asm"), target_arch = "x86_64"), @@ -60,131 +56,3 @@ intrinsics! { impls::c_string_length(s) } } - -// `bytes` must be a multiple of `mem::size_of::()` -#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] -fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { - unsafe { - let n = exact_div(bytes, mem::size_of::()); - let mut i = 0; - while i < n { - atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); - i += 1; - } - } -} - -// `bytes` must be a multiple of `mem::size_of::()` -#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] -fn memmove_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { - unsafe { - let n = exact_div(bytes, mem::size_of::()); - if src < dest as *const T { - // copy from end - let mut i = n; - while i != 0 { - i -= 1; - atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); - } - } else { - // copy from beginning - let mut i = 0; - while i < n { - atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); - i += 1; - } - } - } -} - -// `T` must be a primitive integer type, and `bytes` must be a multiple of `mem::size_of::()` -#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] -fn memset_element_unordered_atomic(s: *mut T, c: u8, bytes: usize) -where - T: Copy + From + Shl + BitOr, -{ - unsafe { - let n = exact_div(bytes, mem::size_of::()); - - // Construct a value of type `T` consisting of repeated `c` - // bytes, to let us ensure we write each `T` atomically. - let mut x = T::from(c); - let mut i = 1; - while i < mem::size_of::() { - x = (x << 8) | T::from(c); - i += 1; - } - - // Write it to `s` - let mut i = 0; - while i < n { - atomic_store_unordered(s.add(i), x); - i += 1; - } - } -} - -intrinsics! { - #[cfg(target_has_atomic_load_store = "8")] - pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "16")] - pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "32")] - pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "64")] - pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "128")] - pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - - #[cfg(target_has_atomic_load_store = "8")] - pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "16")] - pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "32")] - pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "64")] - pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "128")] - pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - - #[cfg(target_has_atomic_load_store = "8")] - pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } - #[cfg(target_has_atomic_load_store = "16")] - pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_2(s: *mut u16, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } - #[cfg(target_has_atomic_load_store = "32")] - pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_4(s: *mut u32, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } - #[cfg(target_has_atomic_load_store = "64")] - pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } - #[cfg(target_has_atomic_load_store = "128")] - pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } -} -- cgit 1.4.1-3-g733a5 From a179959e0bc8dc061bcf9ec841b6a8b8b516e683 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Mar 2025 10:13:47 +0000 Subject: Move `examples/intrinsics.rs` to its own crate Currently there is an interesting situation with the way features get enabled; `testcrate` enables `mangled-names`, but the `intrinsics.rs` example requires this feature be disabled (otherwise the test fails with missing symbols, as expected). This is also the reason that `testcrate` is not a default workspace member, meaning `cargo test` doesn't actually run `testcrate`'s tests; making it a default member would mean that `compiler-builtins/mangled-names` gets enabled when `examples/intrinsics.rs` gets built, due to the way features get unified. Simplify the situation by making moving the example to its own crate as `builtins-test-intrinsics`. This also means `testcrate` can become a default member so it is included in `cargo check` or `cargo test` when run at the workspace root. `testcrate` and `builtins-test-intrinsics` still can't be built at the same time since there isn't a straightforward way to have Cargo build `compiler-builtins` twice with different features. This is a side effect of us using non-additive features, but there isn't really a better option since enabling both mangled and unmangled names would render `builtins-test-intrinsics` useless. --- library/compiler-builtins/Cargo.toml | 17 +- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/build.rs | 17 +- .../builtins-test-intrinsics/Cargo.toml | 11 + .../builtins-test-intrinsics/build.rs | 11 + .../builtins-test-intrinsics/src/main.rs | 696 +++++++++++++++++++++ library/compiler-builtins/ci/run.sh | 18 +- library/compiler-builtins/configure.rs | 22 +- library/compiler-builtins/examples/intrinsics.rs | 696 --------------------- library/compiler-builtins/testcrate/build.rs | 1 + 10 files changed, 765 insertions(+), 728 deletions(-) create mode 100644 library/compiler-builtins/builtins-test-intrinsics/Cargo.toml create mode 100644 library/compiler-builtins/builtins-test-intrinsics/build.rs create mode 100644 library/compiler-builtins/builtins-test-intrinsics/src/main.rs delete mode 100644 library/compiler-builtins/examples/intrinsics.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 9d144834206..60de27758d8 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -71,13 +71,20 @@ rustc-dep-of-std = ['compiler-builtins', 'core'] # are not normally public but are required by the `testcrate` public-test-deps = [] -[[example]] -name = "intrinsics" -required-features = ["compiler-builtins"] - [workspace] resolver = "2" -members = ["testcrate"] +members = [ + # Note that builtins-test-intrinsics cannot be a default member because it + # needs the `mangled-names` feature disabled, while `testcrate` needs it + # enabled. + "builtins-test-intrinsics", + "testcrate", +] + +default-members = [ + ".", + "testcrate", +] [profile.release] panic = 'abort' diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index d76bd289ba5..e5350d58c3e 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -16,8 +16,8 @@ It is distributed as part of Rust's sysroot. [C implementation][2] to Rust. 4. Add a test to compare the behavior of the ported intrinsic(s) with their implementation on the testing host. -5. Add the intrinsic to `examples/intrinsics.rs` to verify it can be linked on - all targets. +5. Add the intrinsic to `builtins-test-intrinsics/src/main.rs` to verify it + can be linked on all targets. 6. Send a Pull Request (PR). 7. Once the PR passes our extensive testing infrastructure, we'll merge it! 8. Celebrate :tada: diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 3c04423f2d8..369354a1d52 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -2,7 +2,7 @@ use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering}; mod configure; -use configure::{configure_f16_f128, Target}; +use configure::{configure_aliases, configure_f16_f128, Target}; fn main() { println!("cargo::rerun-if-changed=build.rs"); @@ -13,6 +13,7 @@ fn main() { configure_check_cfg(); configure_f16_f128(&target); + configure_aliases(&target); configure_libm(&target); @@ -71,20 +72,6 @@ fn main() { } } - // To compile intrinsics.rs for thumb targets, where there is no libc - println!("cargo::rustc-check-cfg=cfg(thumb)"); - if llvm_target[0].starts_with("thumb") { - println!("cargo:rustc-cfg=thumb") - } - - // compiler-rt `cfg`s away some intrinsics for thumbv6m and thumbv8m.base because - // these targets do not have full Thumb-2 support but only original Thumb-1. - // We have to cfg our code accordingly. - println!("cargo::rustc-check-cfg=cfg(thumb_1)"); - if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { - println!("cargo:rustc-cfg=thumb_1") - } - // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. This // includes the old androideabi. It is deprecated but it is available as a // rustc target (arm-linux-androideabi). diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml new file mode 100644 index 00000000000..8c7cca4bd99 --- /dev/null +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "builtins-test-intrinsics" +version = "0.1.0" +edition = "2021" + +[dependencies] +compiler_builtins = { path = "../", features = ["compiler-builtins"]} +panic-handler = { path = '../crates/panic-handler' } + +[features] +c = ["compiler_builtins/c"] diff --git a/library/compiler-builtins/builtins-test-intrinsics/build.rs b/library/compiler-builtins/builtins-test-intrinsics/build.rs new file mode 100644 index 00000000000..a38c6c1ff71 --- /dev/null +++ b/library/compiler-builtins/builtins-test-intrinsics/build.rs @@ -0,0 +1,11 @@ +mod builtins_configure { + include!("../configure.rs"); +} + +fn main() { + println!("cargo::rerun-if-changed=../configure.rs"); + + let target = builtins_configure::Target::from_env(); + builtins_configure::configure_f16_f128(&target); + builtins_configure::configure_aliases(&target); +} diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs new file mode 100644 index 00000000000..e90cfb33dea --- /dev/null +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -0,0 +1,696 @@ +// By compiling this file we check that all the intrinsics we care about continue to be provided by +// the `compiler_builtins` crate regardless of the changes we make to it. If we, by mistake, stop +// compiling a C implementation and forget to implement that intrinsic in Rust, this file will fail +// to link due to the missing intrinsic (symbol). + +#![allow(unused_features)] +#![allow(internal_features)] +#![deny(dead_code)] +#![feature(allocator_api)] +#![feature(f128)] +#![feature(f16)] +#![feature(lang_items)] +#![no_std] +#![no_main] + +extern crate panic_handler; + +#[cfg(all(not(thumb), not(windows), not(target_arch = "wasm32")))] +#[link(name = "c")] +extern "C" {} + +// Every function in this module maps will be lowered to an intrinsic by LLVM, if the platform +// doesn't have native support for the operation used in the function. ARM has a naming convention +// convention for its intrinsics that's different from other architectures; that's why some function +// have an additional comment: the function name is the ARM name for the intrinsic and the comment +// in the non-ARM name for the intrinsic. +mod intrinsics { + /* f16 operations */ + + #[cfg(f16_enabled)] + pub fn extendhfsf(x: f16) -> f32 { + x as f32 + } + + #[cfg(f16_enabled)] + pub fn extendhfdf(x: f16) -> f64 { + x as f64 + } + + #[cfg(all( + f16_enabled, + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + pub fn extendhftf(x: f16) -> f128 { + x as f128 + } + + /* f32 operations */ + + #[cfg(f16_enabled)] + pub fn truncsfhf(x: f32) -> f16 { + x as f16 + } + + // extendsfdf2 + pub fn aeabi_f2d(x: f32) -> f64 { + x as f64 + } + + #[cfg(f128_enabled)] + pub fn extendsftf(x: f32) -> f128 { + x as f128 + } + + // fixsfsi + pub fn aeabi_f2iz(x: f32) -> i32 { + x as i32 + } + + // fixsfdi + pub fn aeabi_f2lz(x: f32) -> i64 { + x as i64 + } + + pub fn fixsfti(x: f32) -> i128 { + x as i128 + } + + // fixunssfsi + pub fn aeabi_f2uiz(x: f32) -> u32 { + x as u32 + } + + // fixunssfdi + pub fn aeabi_f2ulz(x: f32) -> u64 { + x as u64 + } + + pub fn fixunssfti(x: f32) -> u128 { + x as u128 + } + + // addsf3 + pub fn aeabi_fadd(a: f32, b: f32) -> f32 { + a + b + } + + // eqsf2 + pub fn aeabi_fcmpeq(a: f32, b: f32) -> bool { + a == b + } + + // gtsf2 + pub fn aeabi_fcmpgt(a: f32, b: f32) -> bool { + a > b + } + + // ltsf2 + pub fn aeabi_fcmplt(a: f32, b: f32) -> bool { + a < b + } + + // divsf3 + pub fn aeabi_fdiv(a: f32, b: f32) -> f32 { + a / b + } + + // mulsf3 + pub fn aeabi_fmul(a: f32, b: f32) -> f32 { + a * b + } + + // subsf3 + pub fn aeabi_fsub(a: f32, b: f32) -> f32 { + a - b + } + + /* f64 operations */ + + // truncdfsf2 + pub fn aeabi_d2f(x: f64) -> f32 { + x as f32 + } + + // fixdfsi + pub fn aeabi_d2i(x: f64) -> i32 { + x as i32 + } + + // fixdfdi + pub fn aeabi_d2l(x: f64) -> i64 { + x as i64 + } + + pub fn fixdfti(x: f64) -> i128 { + x as i128 + } + + // fixunsdfsi + pub fn aeabi_d2uiz(x: f64) -> u32 { + x as u32 + } + + // fixunsdfdi + pub fn aeabi_d2ulz(x: f64) -> u64 { + x as u64 + } + + pub fn fixunsdfti(x: f64) -> u128 { + x as u128 + } + + // adddf3 + pub fn aeabi_dadd(a: f64, b: f64) -> f64 { + a + b + } + + // eqdf2 + pub fn aeabi_dcmpeq(a: f64, b: f64) -> bool { + a == b + } + + // gtdf2 + pub fn aeabi_dcmpgt(a: f64, b: f64) -> bool { + a > b + } + + // ltdf2 + pub fn aeabi_dcmplt(a: f64, b: f64) -> bool { + a < b + } + + // divdf3 + pub fn aeabi_ddiv(a: f64, b: f64) -> f64 { + a / b + } + + // muldf3 + pub fn aeabi_dmul(a: f64, b: f64) -> f64 { + a * b + } + + // subdf3 + pub fn aeabi_dsub(a: f64, b: f64) -> f64 { + a - b + } + + /* f128 operations */ + + #[cfg(all( + f16_enabled, + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + pub fn trunctfhf(x: f128) -> f16 { + x as f16 + } + + #[cfg(f128_enabled)] + pub fn trunctfsf(x: f128) -> f32 { + x as f32 + } + + #[cfg(f128_enabled)] + pub fn trunctfdf(x: f128) -> f64 { + x as f64 + } + + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + pub fn fixtfsi(x: f128) -> i32 { + x as i32 + } + + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + pub fn fixtfdi(x: f128) -> i64 { + x as i64 + } + + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + pub fn fixtfti(x: f128) -> i128 { + x as i128 + } + + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + pub fn fixunstfsi(x: f128) -> u32 { + x as u32 + } + + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + pub fn fixunstfdi(x: f128) -> u64 { + x as u64 + } + + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + pub fn fixunstfti(x: f128) -> u128 { + x as u128 + } + + #[cfg(f128_enabled)] + pub fn addtf(a: f128, b: f128) -> f128 { + a + b + } + + #[cfg(f128_enabled)] + pub fn eqtf(a: f128, b: f128) -> bool { + a == b + } + + #[cfg(f128_enabled)] + pub fn gttf(a: f128, b: f128) -> bool { + a > b + } + + #[cfg(f128_enabled)] + pub fn lttf(a: f128, b: f128) -> bool { + a < b + } + + #[cfg(f128_enabled)] + pub fn multf(a: f128, b: f128) -> f128 { + a * b + } + + #[cfg(f128_enabled)] + pub fn divtf(a: f128, b: f128) -> f128 { + a / b + } + + #[cfg(f128_enabled)] + pub fn subtf(a: f128, b: f128) -> f128 { + a - b + } + + /* i32 operations */ + + // floatsisf + pub fn aeabi_i2f(x: i32) -> f32 { + x as f32 + } + + // floatsidf + pub fn aeabi_i2d(x: i32) -> f64 { + x as f64 + } + + #[cfg(f128_enabled)] + pub fn floatsitf(x: i32) -> f128 { + x as f128 + } + + pub fn aeabi_idiv(a: i32, b: i32) -> i32 { + a.wrapping_div(b) + } + + pub fn aeabi_idivmod(a: i32, b: i32) -> i32 { + a % b + } + + /* i64 operations */ + + // floatdisf + pub fn aeabi_l2f(x: i64) -> f32 { + x as f32 + } + + // floatdidf + pub fn aeabi_l2d(x: i64) -> f64 { + x as f64 + } + + #[cfg(f128_enabled)] + pub fn floatditf(x: i64) -> f128 { + x as f128 + } + + pub fn mulodi4(a: i64, b: i64) -> i64 { + a * b + } + + // divdi3 + pub fn aeabi_ldivmod(a: i64, b: i64) -> i64 { + a / b + } + + pub fn moddi3(a: i64, b: i64) -> i64 { + a % b + } + + // muldi3 + pub fn aeabi_lmul(a: i64, b: i64) -> i64 { + a.wrapping_mul(b) + } + + /* i128 operations */ + + pub fn floattisf(x: i128) -> f32 { + x as f32 + } + + pub fn floattidf(x: i128) -> f64 { + x as f64 + } + + #[cfg(f128_enabled)] + pub fn floattitf(x: i128) -> f128 { + x as f128 + } + + pub fn lshrti3(a: i128, b: usize) -> i128 { + a >> b + } + + pub fn divti3(a: i128, b: i128) -> i128 { + a / b + } + + pub fn modti3(a: i128, b: i128) -> i128 { + a % b + } + + /* u32 operations */ + + // floatunsisf + pub fn aeabi_ui2f(x: u32) -> f32 { + x as f32 + } + + // floatunsidf + pub fn aeabi_ui2d(x: u32) -> f64 { + x as f64 + } + + #[cfg(f128_enabled)] + pub fn floatunsitf(x: u32) -> f128 { + x as f128 + } + + pub fn aeabi_uidiv(a: u32, b: u32) -> u32 { + a / b + } + + pub fn aeabi_uidivmod(a: u32, b: u32) -> u32 { + a % b + } + + /* u64 operations */ + + // floatundisf + pub fn aeabi_ul2f(x: u64) -> f32 { + x as f32 + } + + // floatundidf + pub fn aeabi_ul2d(x: u64) -> f64 { + x as f64 + } + + #[cfg(f128_enabled)] + pub fn floatunditf(x: u64) -> f128 { + x as f128 + } + + // udivdi3 + pub fn aeabi_uldivmod(a: u64, b: u64) -> u64 { + a * b + } + + pub fn umoddi3(a: u64, b: u64) -> u64 { + a % b + } + + /* u128 operations */ + + pub fn floatuntisf(x: u128) -> f32 { + x as f32 + } + + pub fn floatuntidf(x: u128) -> f64 { + x as f64 + } + + #[cfg(f128_enabled)] + pub fn floatuntitf(x: u128) -> f128 { + x as f128 + } + + pub fn muloti4(a: u128, b: u128) -> Option { + a.checked_mul(b) + } + + pub fn multi3(a: u128, b: u128) -> u128 { + a.wrapping_mul(b) + } + + pub fn ashlti3(a: u128, b: usize) -> u128 { + a >> b + } + + pub fn ashrti3(a: u128, b: usize) -> u128 { + a << b + } + + pub fn udivti3(a: u128, b: u128) -> u128 { + a / b + } + + pub fn umodti3(a: u128, b: u128) -> u128 { + a % b + } +} + +fn run() { + use core::hint::black_box as bb; + use intrinsics::*; + + // FIXME(f16_f128): some PPC f128 <-> int conversion functions have the wrong names + + #[cfg(f128_enabled)] + bb(addtf(bb(2.), bb(2.))); + bb(aeabi_d2f(bb(2.))); + bb(aeabi_d2i(bb(2.))); + bb(aeabi_d2l(bb(2.))); + bb(aeabi_d2uiz(bb(2.))); + bb(aeabi_d2ulz(bb(2.))); + bb(aeabi_dadd(bb(2.), bb(3.))); + bb(aeabi_dcmpeq(bb(2.), bb(3.))); + bb(aeabi_dcmpgt(bb(2.), bb(3.))); + bb(aeabi_dcmplt(bb(2.), bb(3.))); + bb(aeabi_ddiv(bb(2.), bb(3.))); + bb(aeabi_dmul(bb(2.), bb(3.))); + bb(aeabi_dsub(bb(2.), bb(3.))); + bb(aeabi_f2d(bb(2.))); + bb(aeabi_f2iz(bb(2.))); + bb(aeabi_f2lz(bb(2.))); + bb(aeabi_f2uiz(bb(2.))); + bb(aeabi_f2ulz(bb(2.))); + bb(aeabi_fadd(bb(2.), bb(3.))); + bb(aeabi_fcmpeq(bb(2.), bb(3.))); + bb(aeabi_fcmpgt(bb(2.), bb(3.))); + bb(aeabi_fcmplt(bb(2.), bb(3.))); + bb(aeabi_fdiv(bb(2.), bb(3.))); + bb(aeabi_fmul(bb(2.), bb(3.))); + bb(aeabi_fsub(bb(2.), bb(3.))); + bb(aeabi_i2d(bb(2))); + bb(aeabi_i2f(bb(2))); + bb(aeabi_idiv(bb(2), bb(3))); + bb(aeabi_idivmod(bb(2), bb(3))); + bb(aeabi_l2d(bb(2))); + bb(aeabi_l2f(bb(2))); + bb(aeabi_ldivmod(bb(2), bb(3))); + bb(aeabi_lmul(bb(2), bb(3))); + bb(aeabi_ui2d(bb(2))); + bb(aeabi_ui2f(bb(2))); + bb(aeabi_uidiv(bb(2), bb(3))); + bb(aeabi_uidivmod(bb(2), bb(3))); + bb(aeabi_ul2d(bb(2))); + bb(aeabi_ul2f(bb(2))); + bb(aeabi_uldivmod(bb(2), bb(3))); + bb(ashlti3(bb(2), bb(2))); + bb(ashrti3(bb(2), bb(2))); + #[cfg(f128_enabled)] + bb(divtf(bb(2.), bb(2.))); + bb(divti3(bb(2), bb(2))); + #[cfg(f128_enabled)] + bb(eqtf(bb(2.), bb(2.))); + #[cfg(f16_enabled)] + bb(extendhfdf(bb(2.))); + #[cfg(f16_enabled)] + bb(extendhfsf(bb(2.))); + #[cfg(all( + f16_enabled, + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + bb(extendhftf(bb(2.))); + #[cfg(f128_enabled)] + bb(extendsftf(bb(2.))); + bb(fixdfti(bb(2.))); + bb(fixsfti(bb(2.))); + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + bb(fixtfdi(bb(2.))); + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + bb(fixtfsi(bb(2.))); + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + bb(fixtfti(bb(2.))); + bb(fixunsdfti(bb(2.))); + bb(fixunssfti(bb(2.))); + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + bb(fixunstfdi(bb(2.))); + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + bb(fixunstfsi(bb(2.))); + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + bb(fixunstfti(bb(2.))); + #[cfg(f128_enabled)] + bb(floatditf(bb(2))); + #[cfg(f128_enabled)] + bb(floatsitf(bb(2))); + bb(floattidf(bb(2))); + bb(floattisf(bb(2))); + #[cfg(f128_enabled)] + bb(floattitf(bb(2))); + #[cfg(f128_enabled)] + bb(floatunditf(bb(2))); + #[cfg(f128_enabled)] + bb(floatunsitf(bb(2))); + bb(floatuntidf(bb(2))); + bb(floatuntisf(bb(2))); + #[cfg(f128_enabled)] + bb(floatuntitf(bb(2))); + #[cfg(f128_enabled)] + bb(gttf(bb(2.), bb(2.))); + bb(lshrti3(bb(2), bb(2))); + #[cfg(f128_enabled)] + bb(lttf(bb(2.), bb(2.))); + bb(moddi3(bb(2), bb(3))); + bb(modti3(bb(2), bb(2))); + bb(mulodi4(bb(2), bb(3))); + bb(muloti4(bb(2), bb(2))); + #[cfg(f128_enabled)] + bb(multf(bb(2.), bb(2.))); + bb(multi3(bb(2), bb(2))); + #[cfg(f128_enabled)] + bb(subtf(bb(2.), bb(2.))); + #[cfg(f16_enabled)] + bb(truncsfhf(bb(2.))); + #[cfg(f128_enabled)] + bb(trunctfdf(bb(2.))); + #[cfg(all( + f16_enabled, + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] + bb(trunctfhf(bb(2.))); + #[cfg(f128_enabled)] + bb(trunctfsf(bb(2.))); + bb(udivti3(bb(2), bb(2))); + bb(umoddi3(bb(2), bb(3))); + bb(umodti3(bb(2), bb(2))); + + something_with_a_dtor(&|| assert_eq!(bb(1), 1)); + + extern "C" { + fn rust_begin_unwind(x: usize); + } + + unsafe { + rust_begin_unwind(0); + } +} + +fn something_with_a_dtor(f: &dyn Fn()) { + struct A<'a>(&'a (dyn Fn() + 'a)); + + impl Drop for A<'_> { + fn drop(&mut self) { + (self.0)(); + } + } + let _a = A(f); + f(); +} + +#[no_mangle] +#[cfg(not(thumb))] +fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { + run(); + 0 +} + +#[no_mangle] +#[cfg(thumb)] +pub fn _start() -> ! { + run(); + loop {} +} + +#[cfg(windows)] +#[link(name = "kernel32")] +#[link(name = "msvcrt")] +extern "C" {} + +// ARM targets need these symbols +#[no_mangle] +pub fn __aeabi_unwind_cpp_pr0() {} + +#[no_mangle] +pub fn __aeabi_unwind_cpp_pr1() {} + +#[cfg(not(any(windows, target_os = "cygwin")))] +#[allow(non_snake_case)] +#[no_mangle] +pub fn _Unwind_Resume() {} + +#[cfg(not(any(windows, target_os = "cygwin")))] +#[lang = "eh_personality"] +#[no_mangle] +pub extern "C" fn eh_personality() {} + +#[cfg(any(all(windows, target_env = "gnu"), target_os = "cygwin"))] +mod mingw_unwinding { + #[no_mangle] + pub fn rust_eh_personality() {} + #[no_mangle] + pub fn rust_eh_unwind_resume() {} + #[no_mangle] + pub fn rust_eh_register_frames() {} + #[no_mangle] + pub fn rust_eh_unregister_frames() {} +} diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 057cdb083f7..3625dde79ed 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -120,22 +120,22 @@ done rm -f "${rlib_paths[@]}" -build_intrinsics() { - cargo build --target "$target" -v --example intrinsics "$@" +build_intrinsics_test() { + cargo build --target "$target" -v --package builtins-test-intrinsics "$@" } -# Verify that we haven't drop any intrinsic/symbol -build_intrinsics -build_intrinsics --release -build_intrinsics --features c -build_intrinsics --features c --release +# Verify that we haven't dropped any intrinsics/symbols +build_intrinsics_test +build_intrinsics_test --release +build_intrinsics_test --features c +build_intrinsics_test --features c --release # Verify that there are no undefined symbols to `panic` within our # implementations CARGO_PROFILE_DEV_LTO=true \ - cargo build --target "$target" --example intrinsics + cargo build --target "$target" --package builtins-test-intrinsics CARGO_PROFILE_RELEASE_LTO=true \ - cargo build --target "$target" --example intrinsics --release + cargo build --target "$target" --package builtins-test-intrinsics --release # Ensure no references to any symbols from core update_rlib_paths diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index 931e9662939..2f134e57818 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -6,6 +6,7 @@ use std::env; #[allow(dead_code)] pub struct Target { pub triple: String, + pub triple_split: Vec, pub opt_level: String, pub cargo_features: Vec, pub os: String, @@ -19,6 +20,8 @@ pub struct Target { impl Target { pub fn from_env() -> Self { + let triple = env::var("TARGET").unwrap(); + let triple_split = triple.split('-').map(ToOwned::to_owned).collect(); let little_endian = match env::var("CARGO_CFG_TARGET_ENDIAN").unwrap().as_str() { "little" => true, "big" => false, @@ -30,7 +33,8 @@ impl Target { .collect(); Self { - triple: env::var("TARGET").unwrap(), + triple, + triple_split, os: env::var("CARGO_CFG_TARGET_OS").unwrap(), opt_level: env::var("OPT_LEVEL").unwrap(), cargo_features, @@ -56,6 +60,22 @@ impl Target { } } +pub fn configure_aliases(target: &Target) { + // To compile builtins-test-intrinsics for thumb targets, where there is no libc + println!("cargo::rustc-check-cfg=cfg(thumb)"); + if target.triple_split[0].starts_with("thumb") { + println!("cargo:rustc-cfg=thumb") + } + + // compiler-rt `cfg`s away some intrinsics for thumbv6m and thumbv8m.base because + // these targets do not have full Thumb-2 support but only original Thumb-1. + // We have to cfg our code accordingly. + println!("cargo::rustc-check-cfg=cfg(thumb_1)"); + if target.triple_split[0] == "thumbv6m" || target.triple_split[0] == "thumbv8m.base" { + println!("cargo:rustc-cfg=thumb_1") + } +} + /// Configure whether or not `f16` and `f128` support should be enabled. pub fn configure_f16_f128(target: &Target) { // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs deleted file mode 100644 index e90cfb33dea..00000000000 --- a/library/compiler-builtins/examples/intrinsics.rs +++ /dev/null @@ -1,696 +0,0 @@ -// By compiling this file we check that all the intrinsics we care about continue to be provided by -// the `compiler_builtins` crate regardless of the changes we make to it. If we, by mistake, stop -// compiling a C implementation and forget to implement that intrinsic in Rust, this file will fail -// to link due to the missing intrinsic (symbol). - -#![allow(unused_features)] -#![allow(internal_features)] -#![deny(dead_code)] -#![feature(allocator_api)] -#![feature(f128)] -#![feature(f16)] -#![feature(lang_items)] -#![no_std] -#![no_main] - -extern crate panic_handler; - -#[cfg(all(not(thumb), not(windows), not(target_arch = "wasm32")))] -#[link(name = "c")] -extern "C" {} - -// Every function in this module maps will be lowered to an intrinsic by LLVM, if the platform -// doesn't have native support for the operation used in the function. ARM has a naming convention -// convention for its intrinsics that's different from other architectures; that's why some function -// have an additional comment: the function name is the ARM name for the intrinsic and the comment -// in the non-ARM name for the intrinsic. -mod intrinsics { - /* f16 operations */ - - #[cfg(f16_enabled)] - pub fn extendhfsf(x: f16) -> f32 { - x as f32 - } - - #[cfg(f16_enabled)] - pub fn extendhfdf(x: f16) -> f64 { - x as f64 - } - - #[cfg(all( - f16_enabled, - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - pub fn extendhftf(x: f16) -> f128 { - x as f128 - } - - /* f32 operations */ - - #[cfg(f16_enabled)] - pub fn truncsfhf(x: f32) -> f16 { - x as f16 - } - - // extendsfdf2 - pub fn aeabi_f2d(x: f32) -> f64 { - x as f64 - } - - #[cfg(f128_enabled)] - pub fn extendsftf(x: f32) -> f128 { - x as f128 - } - - // fixsfsi - pub fn aeabi_f2iz(x: f32) -> i32 { - x as i32 - } - - // fixsfdi - pub fn aeabi_f2lz(x: f32) -> i64 { - x as i64 - } - - pub fn fixsfti(x: f32) -> i128 { - x as i128 - } - - // fixunssfsi - pub fn aeabi_f2uiz(x: f32) -> u32 { - x as u32 - } - - // fixunssfdi - pub fn aeabi_f2ulz(x: f32) -> u64 { - x as u64 - } - - pub fn fixunssfti(x: f32) -> u128 { - x as u128 - } - - // addsf3 - pub fn aeabi_fadd(a: f32, b: f32) -> f32 { - a + b - } - - // eqsf2 - pub fn aeabi_fcmpeq(a: f32, b: f32) -> bool { - a == b - } - - // gtsf2 - pub fn aeabi_fcmpgt(a: f32, b: f32) -> bool { - a > b - } - - // ltsf2 - pub fn aeabi_fcmplt(a: f32, b: f32) -> bool { - a < b - } - - // divsf3 - pub fn aeabi_fdiv(a: f32, b: f32) -> f32 { - a / b - } - - // mulsf3 - pub fn aeabi_fmul(a: f32, b: f32) -> f32 { - a * b - } - - // subsf3 - pub fn aeabi_fsub(a: f32, b: f32) -> f32 { - a - b - } - - /* f64 operations */ - - // truncdfsf2 - pub fn aeabi_d2f(x: f64) -> f32 { - x as f32 - } - - // fixdfsi - pub fn aeabi_d2i(x: f64) -> i32 { - x as i32 - } - - // fixdfdi - pub fn aeabi_d2l(x: f64) -> i64 { - x as i64 - } - - pub fn fixdfti(x: f64) -> i128 { - x as i128 - } - - // fixunsdfsi - pub fn aeabi_d2uiz(x: f64) -> u32 { - x as u32 - } - - // fixunsdfdi - pub fn aeabi_d2ulz(x: f64) -> u64 { - x as u64 - } - - pub fn fixunsdfti(x: f64) -> u128 { - x as u128 - } - - // adddf3 - pub fn aeabi_dadd(a: f64, b: f64) -> f64 { - a + b - } - - // eqdf2 - pub fn aeabi_dcmpeq(a: f64, b: f64) -> bool { - a == b - } - - // gtdf2 - pub fn aeabi_dcmpgt(a: f64, b: f64) -> bool { - a > b - } - - // ltdf2 - pub fn aeabi_dcmplt(a: f64, b: f64) -> bool { - a < b - } - - // divdf3 - pub fn aeabi_ddiv(a: f64, b: f64) -> f64 { - a / b - } - - // muldf3 - pub fn aeabi_dmul(a: f64, b: f64) -> f64 { - a * b - } - - // subdf3 - pub fn aeabi_dsub(a: f64, b: f64) -> f64 { - a - b - } - - /* f128 operations */ - - #[cfg(all( - f16_enabled, - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - pub fn trunctfhf(x: f128) -> f16 { - x as f16 - } - - #[cfg(f128_enabled)] - pub fn trunctfsf(x: f128) -> f32 { - x as f32 - } - - #[cfg(f128_enabled)] - pub fn trunctfdf(x: f128) -> f64 { - x as f64 - } - - #[cfg(all( - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - pub fn fixtfsi(x: f128) -> i32 { - x as i32 - } - - #[cfg(all( - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - pub fn fixtfdi(x: f128) -> i64 { - x as i64 - } - - #[cfg(all( - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - pub fn fixtfti(x: f128) -> i128 { - x as i128 - } - - #[cfg(all( - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - pub fn fixunstfsi(x: f128) -> u32 { - x as u32 - } - - #[cfg(all( - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - pub fn fixunstfdi(x: f128) -> u64 { - x as u64 - } - - #[cfg(all( - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - pub fn fixunstfti(x: f128) -> u128 { - x as u128 - } - - #[cfg(f128_enabled)] - pub fn addtf(a: f128, b: f128) -> f128 { - a + b - } - - #[cfg(f128_enabled)] - pub fn eqtf(a: f128, b: f128) -> bool { - a == b - } - - #[cfg(f128_enabled)] - pub fn gttf(a: f128, b: f128) -> bool { - a > b - } - - #[cfg(f128_enabled)] - pub fn lttf(a: f128, b: f128) -> bool { - a < b - } - - #[cfg(f128_enabled)] - pub fn multf(a: f128, b: f128) -> f128 { - a * b - } - - #[cfg(f128_enabled)] - pub fn divtf(a: f128, b: f128) -> f128 { - a / b - } - - #[cfg(f128_enabled)] - pub fn subtf(a: f128, b: f128) -> f128 { - a - b - } - - /* i32 operations */ - - // floatsisf - pub fn aeabi_i2f(x: i32) -> f32 { - x as f32 - } - - // floatsidf - pub fn aeabi_i2d(x: i32) -> f64 { - x as f64 - } - - #[cfg(f128_enabled)] - pub fn floatsitf(x: i32) -> f128 { - x as f128 - } - - pub fn aeabi_idiv(a: i32, b: i32) -> i32 { - a.wrapping_div(b) - } - - pub fn aeabi_idivmod(a: i32, b: i32) -> i32 { - a % b - } - - /* i64 operations */ - - // floatdisf - pub fn aeabi_l2f(x: i64) -> f32 { - x as f32 - } - - // floatdidf - pub fn aeabi_l2d(x: i64) -> f64 { - x as f64 - } - - #[cfg(f128_enabled)] - pub fn floatditf(x: i64) -> f128 { - x as f128 - } - - pub fn mulodi4(a: i64, b: i64) -> i64 { - a * b - } - - // divdi3 - pub fn aeabi_ldivmod(a: i64, b: i64) -> i64 { - a / b - } - - pub fn moddi3(a: i64, b: i64) -> i64 { - a % b - } - - // muldi3 - pub fn aeabi_lmul(a: i64, b: i64) -> i64 { - a.wrapping_mul(b) - } - - /* i128 operations */ - - pub fn floattisf(x: i128) -> f32 { - x as f32 - } - - pub fn floattidf(x: i128) -> f64 { - x as f64 - } - - #[cfg(f128_enabled)] - pub fn floattitf(x: i128) -> f128 { - x as f128 - } - - pub fn lshrti3(a: i128, b: usize) -> i128 { - a >> b - } - - pub fn divti3(a: i128, b: i128) -> i128 { - a / b - } - - pub fn modti3(a: i128, b: i128) -> i128 { - a % b - } - - /* u32 operations */ - - // floatunsisf - pub fn aeabi_ui2f(x: u32) -> f32 { - x as f32 - } - - // floatunsidf - pub fn aeabi_ui2d(x: u32) -> f64 { - x as f64 - } - - #[cfg(f128_enabled)] - pub fn floatunsitf(x: u32) -> f128 { - x as f128 - } - - pub fn aeabi_uidiv(a: u32, b: u32) -> u32 { - a / b - } - - pub fn aeabi_uidivmod(a: u32, b: u32) -> u32 { - a % b - } - - /* u64 operations */ - - // floatundisf - pub fn aeabi_ul2f(x: u64) -> f32 { - x as f32 - } - - // floatundidf - pub fn aeabi_ul2d(x: u64) -> f64 { - x as f64 - } - - #[cfg(f128_enabled)] - pub fn floatunditf(x: u64) -> f128 { - x as f128 - } - - // udivdi3 - pub fn aeabi_uldivmod(a: u64, b: u64) -> u64 { - a * b - } - - pub fn umoddi3(a: u64, b: u64) -> u64 { - a % b - } - - /* u128 operations */ - - pub fn floatuntisf(x: u128) -> f32 { - x as f32 - } - - pub fn floatuntidf(x: u128) -> f64 { - x as f64 - } - - #[cfg(f128_enabled)] - pub fn floatuntitf(x: u128) -> f128 { - x as f128 - } - - pub fn muloti4(a: u128, b: u128) -> Option { - a.checked_mul(b) - } - - pub fn multi3(a: u128, b: u128) -> u128 { - a.wrapping_mul(b) - } - - pub fn ashlti3(a: u128, b: usize) -> u128 { - a >> b - } - - pub fn ashrti3(a: u128, b: usize) -> u128 { - a << b - } - - pub fn udivti3(a: u128, b: u128) -> u128 { - a / b - } - - pub fn umodti3(a: u128, b: u128) -> u128 { - a % b - } -} - -fn run() { - use core::hint::black_box as bb; - use intrinsics::*; - - // FIXME(f16_f128): some PPC f128 <-> int conversion functions have the wrong names - - #[cfg(f128_enabled)] - bb(addtf(bb(2.), bb(2.))); - bb(aeabi_d2f(bb(2.))); - bb(aeabi_d2i(bb(2.))); - bb(aeabi_d2l(bb(2.))); - bb(aeabi_d2uiz(bb(2.))); - bb(aeabi_d2ulz(bb(2.))); - bb(aeabi_dadd(bb(2.), bb(3.))); - bb(aeabi_dcmpeq(bb(2.), bb(3.))); - bb(aeabi_dcmpgt(bb(2.), bb(3.))); - bb(aeabi_dcmplt(bb(2.), bb(3.))); - bb(aeabi_ddiv(bb(2.), bb(3.))); - bb(aeabi_dmul(bb(2.), bb(3.))); - bb(aeabi_dsub(bb(2.), bb(3.))); - bb(aeabi_f2d(bb(2.))); - bb(aeabi_f2iz(bb(2.))); - bb(aeabi_f2lz(bb(2.))); - bb(aeabi_f2uiz(bb(2.))); - bb(aeabi_f2ulz(bb(2.))); - bb(aeabi_fadd(bb(2.), bb(3.))); - bb(aeabi_fcmpeq(bb(2.), bb(3.))); - bb(aeabi_fcmpgt(bb(2.), bb(3.))); - bb(aeabi_fcmplt(bb(2.), bb(3.))); - bb(aeabi_fdiv(bb(2.), bb(3.))); - bb(aeabi_fmul(bb(2.), bb(3.))); - bb(aeabi_fsub(bb(2.), bb(3.))); - bb(aeabi_i2d(bb(2))); - bb(aeabi_i2f(bb(2))); - bb(aeabi_idiv(bb(2), bb(3))); - bb(aeabi_idivmod(bb(2), bb(3))); - bb(aeabi_l2d(bb(2))); - bb(aeabi_l2f(bb(2))); - bb(aeabi_ldivmod(bb(2), bb(3))); - bb(aeabi_lmul(bb(2), bb(3))); - bb(aeabi_ui2d(bb(2))); - bb(aeabi_ui2f(bb(2))); - bb(aeabi_uidiv(bb(2), bb(3))); - bb(aeabi_uidivmod(bb(2), bb(3))); - bb(aeabi_ul2d(bb(2))); - bb(aeabi_ul2f(bb(2))); - bb(aeabi_uldivmod(bb(2), bb(3))); - bb(ashlti3(bb(2), bb(2))); - bb(ashrti3(bb(2), bb(2))); - #[cfg(f128_enabled)] - bb(divtf(bb(2.), bb(2.))); - bb(divti3(bb(2), bb(2))); - #[cfg(f128_enabled)] - bb(eqtf(bb(2.), bb(2.))); - #[cfg(f16_enabled)] - bb(extendhfdf(bb(2.))); - #[cfg(f16_enabled)] - bb(extendhfsf(bb(2.))); - #[cfg(all( - f16_enabled, - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - bb(extendhftf(bb(2.))); - #[cfg(f128_enabled)] - bb(extendsftf(bb(2.))); - bb(fixdfti(bb(2.))); - bb(fixsfti(bb(2.))); - #[cfg(all( - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - bb(fixtfdi(bb(2.))); - #[cfg(all( - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - bb(fixtfsi(bb(2.))); - #[cfg(all( - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - bb(fixtfti(bb(2.))); - bb(fixunsdfti(bb(2.))); - bb(fixunssfti(bb(2.))); - #[cfg(all( - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - bb(fixunstfdi(bb(2.))); - #[cfg(all( - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - bb(fixunstfsi(bb(2.))); - #[cfg(all( - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - bb(fixunstfti(bb(2.))); - #[cfg(f128_enabled)] - bb(floatditf(bb(2))); - #[cfg(f128_enabled)] - bb(floatsitf(bb(2))); - bb(floattidf(bb(2))); - bb(floattisf(bb(2))); - #[cfg(f128_enabled)] - bb(floattitf(bb(2))); - #[cfg(f128_enabled)] - bb(floatunditf(bb(2))); - #[cfg(f128_enabled)] - bb(floatunsitf(bb(2))); - bb(floatuntidf(bb(2))); - bb(floatuntisf(bb(2))); - #[cfg(f128_enabled)] - bb(floatuntitf(bb(2))); - #[cfg(f128_enabled)] - bb(gttf(bb(2.), bb(2.))); - bb(lshrti3(bb(2), bb(2))); - #[cfg(f128_enabled)] - bb(lttf(bb(2.), bb(2.))); - bb(moddi3(bb(2), bb(3))); - bb(modti3(bb(2), bb(2))); - bb(mulodi4(bb(2), bb(3))); - bb(muloti4(bb(2), bb(2))); - #[cfg(f128_enabled)] - bb(multf(bb(2.), bb(2.))); - bb(multi3(bb(2), bb(2))); - #[cfg(f128_enabled)] - bb(subtf(bb(2.), bb(2.))); - #[cfg(f16_enabled)] - bb(truncsfhf(bb(2.))); - #[cfg(f128_enabled)] - bb(trunctfdf(bb(2.))); - #[cfg(all( - f16_enabled, - f128_enabled, - not(any(target_arch = "powerpc", target_arch = "powerpc64")) - ))] - bb(trunctfhf(bb(2.))); - #[cfg(f128_enabled)] - bb(trunctfsf(bb(2.))); - bb(udivti3(bb(2), bb(2))); - bb(umoddi3(bb(2), bb(3))); - bb(umodti3(bb(2), bb(2))); - - something_with_a_dtor(&|| assert_eq!(bb(1), 1)); - - extern "C" { - fn rust_begin_unwind(x: usize); - } - - unsafe { - rust_begin_unwind(0); - } -} - -fn something_with_a_dtor(f: &dyn Fn()) { - struct A<'a>(&'a (dyn Fn() + 'a)); - - impl Drop for A<'_> { - fn drop(&mut self) { - (self.0)(); - } - } - let _a = A(f); - f(); -} - -#[no_mangle] -#[cfg(not(thumb))] -fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { - run(); - 0 -} - -#[no_mangle] -#[cfg(thumb)] -pub fn _start() -> ! { - run(); - loop {} -} - -#[cfg(windows)] -#[link(name = "kernel32")] -#[link(name = "msvcrt")] -extern "C" {} - -// ARM targets need these symbols -#[no_mangle] -pub fn __aeabi_unwind_cpp_pr0() {} - -#[no_mangle] -pub fn __aeabi_unwind_cpp_pr1() {} - -#[cfg(not(any(windows, target_os = "cygwin")))] -#[allow(non_snake_case)] -#[no_mangle] -pub fn _Unwind_Resume() {} - -#[cfg(not(any(windows, target_os = "cygwin")))] -#[lang = "eh_personality"] -#[no_mangle] -pub extern "C" fn eh_personality() {} - -#[cfg(any(all(windows, target_env = "gnu"), target_os = "cygwin"))] -mod mingw_unwinding { - #[no_mangle] - pub fn rust_eh_personality() {} - #[no_mangle] - pub fn rust_eh_unwind_resume() {} - #[no_mangle] - pub fn rust_eh_register_frames() {} - #[no_mangle] - pub fn rust_eh_unregister_frames() {} -} diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 15e4e771ca0..566b985d246 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -115,5 +115,6 @@ fn main() { println!("cargo:rustc-cfg=feature=\"{name}\""); } + builtins_configure::configure_aliases(&target); builtins_configure::configure_f16_f128(&target); } -- cgit 1.4.1-3-g733a5 From afa3eed6f09151d763bdb11ec16fe84a400873fb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Mar 2025 10:39:26 +0000 Subject: Mark `builtins-test-intrinsics` as `publish = false` --- library/compiler-builtins/builtins-test-intrinsics/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 8c7cca4bd99..9b2e5bb7c8a 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -2,6 +2,7 @@ name = "builtins-test-intrinsics" version = "0.1.0" edition = "2021" +publish = false [dependencies] compiler_builtins = { path = "../", features = ["compiler-builtins"]} -- cgit 1.4.1-3-g733a5 From f8b03df54eb35ec8e0c1f5fbb0ae1eb2c08d88b0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Mar 2025 11:14:04 +0000 Subject: Add a script for downloading compiler-rt Rather than needing to copy the version and URL from the CI workflow, put this into a script that can be directly run locally. --- library/compiler-builtins/.github/workflows/main.yml | 7 ++----- library/compiler-builtins/build.rs | 5 ++++- library/compiler-builtins/ci/download-compiler-rt.sh | 10 ++++++++++ 3 files changed, 16 insertions(+), 6 deletions(-) create mode 100755 library/compiler-builtins/ci/download-compiler-rt.sh diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 1c367a2d0da..34742e34954 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -4,7 +4,6 @@ on: [push, pull_request] env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings - RUST_LLVM_VERSION: 20.1-2025-02-13 RUST_COMPILER_RT_ROOT: ./compiler-rt jobs: @@ -129,12 +128,10 @@ jobs: uses: actions/cache@v4 with: path: compiler-rt - key: ${{ runner.os }}-compiler-rt-${{ env.RUST_LLVM_VERSION }} + key: ${{ runner.os }}-compiler-rt-${{ hashFiles('ci/download-compiler-rt.sh') }} - name: Download compiler-rt reference sources if: steps.cache-compiler-rt.outputs.cache-hit != 'true' - run: | - curl -L -o code.tar.gz "https://github.com/rust-lang/llvm-project/archive/rustc/${RUST_LLVM_VERSION}.tar.gz" - tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-${RUST_LLVM_VERSION}/compiler-rt + run: ./ci/download-compiler-rt.sh shell: bash # Non-linux tests just use our raw script diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 369354a1d52..3003d51aff8 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -619,7 +619,10 @@ mod c { let root = match env::var_os("RUST_COMPILER_RT_ROOT") { Some(s) => PathBuf::from(s), None => { - panic!("RUST_COMPILER_RT_ROOT is not set. You may need to download compiler-rt.") + panic!( + "RUST_COMPILER_RT_ROOT is not set. You may need to run \ + `ci/download-compiler-rt.sh`." + ); } }; if !root.exists() { diff --git a/library/compiler-builtins/ci/download-compiler-rt.sh b/library/compiler-builtins/ci/download-compiler-rt.sh new file mode 100755 index 00000000000..bf7f8c24896 --- /dev/null +++ b/library/compiler-builtins/ci/download-compiler-rt.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# Download sources to build C versions of intrinsics. Once being run, +# `RUST_COMPILER_RT_ROOT` must be set. + +set -eux + +rust_llvm_version=20.1-2025-02-13 + +curl -L -o code.tar.gz "https://github.com/rust-lang/llvm-project/archive/rustc/${rust_llvm_version}.tar.gz" +tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-${rust_llvm_version}/compiler-rt -- cgit 1.4.1-3-g733a5 From 014f530f76917d21882be755571c58912a6ea409 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Mar 2025 22:24:20 +0100 Subject: nightlies without clippy are not a thing any more --- library/compiler-builtins/.github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 34742e34954..50844a66c43 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -178,10 +178,9 @@ jobs: with: submodules: true # Unlike rustfmt, stable clippy does not work on code with nightly features. - # This acquires the most recent nightly with a clippy component. - name: Install nightly `clippy` run: | - rustup set profile minimal && rustup default "nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/clippy)" && rustup component add clippy + rustup set profile minimal && rustup default nightly && rustup component add clippy - uses: Swatinem/rust-cache@v2 - run: cargo clippy -- -D clippy::all -- cgit 1.4.1-3-g733a5 From 725759602a1ca7bca8f2acf1b2cb13e7cb7fa01d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Mar 2025 23:51:19 +0000 Subject: Upgrade all dependencies to the latest This is mostly done to get the latest version of `rand`, which includes some breaking changes. --- library/compiler-builtins/libm/Cargo.toml | 3 +-- .../compiler-builtins/libm/crates/libm-macros/Cargo.toml | 6 +++--- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 14 +++++--------- .../libm/crates/libm-test/src/gen/random.rs | 10 +++++----- .../compiler-builtins/libm/crates/libm-test/tests/u256.rs | 10 +++++----- .../compiler-builtins/libm/crates/musl-math-sys/Cargo.toml | 2 +- 6 files changed, 20 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index eb133dada16..e0aeb07d527 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -59,8 +59,7 @@ exclude = [ ] [dev-dependencies] -no-panic = "0.1.33" - +no-panic = "0.1.35" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml index f0de0e17689..314f4ae3783 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml @@ -9,9 +9,9 @@ proc-macro = true [dependencies] heck = "0.5.0" -proc-macro2 = "1.0.93" -quote = "1.0.38" -syn = { version = "2.0.96", features = ["full", "extra-traits", "visit-mut"] } +proc-macro2 = "1.0.94" +quote = "1.0.40" +syn = { version = "2.0.100", features = ["full", "extra-traits", "visit-mut"] } [lints.rust] # Values used during testing diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index dcbddb667e8..98da73ceadc 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -27,26 +27,22 @@ icount = ["dep:iai-callgrind"] short-benchmarks = [] [dependencies] -anyhow = "1.0.95" +anyhow = "1.0.97" # This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } iai-callgrind = { version = "0.14.0", optional = true } -indicatif = { version = "0.17.9", default-features = false } +indicatif = { version = "0.17.11", default-features = false } libm = { path = "../..", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } paste = "1.0.15" -rand = "0.8.5" -rand_chacha = "0.3.1" +rand = "0.9.0" +rand_chacha = "0.9.0" rayon = "1.10.0" rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "integer", "std"] } -[target.'cfg(target_family = "wasm")'.dependencies] -# Enable randomness on WASM -getrandom = { version = "0.2", features = ["js"] } - [build-dependencies] -rand = { version = "0.8.5", optional = true } +rand = { version = "0.9.0", optional = true } [dev-dependencies] criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index c2cd172d1ee..e8a7ee9057e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -3,7 +3,7 @@ use std::ops::RangeInclusive; use std::sync::LazyLock; use libm::support::Float; -use rand::distributions::{Alphanumeric, Standard}; +use rand::distr::{Alphanumeric, StandardUniform}; use rand::prelude::Distribution; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; @@ -16,7 +16,7 @@ pub(crate) const SEED_ENV: &str = "LIBM_SEED"; pub static SEED: LazyLock<[u8; 32]> = LazyLock::new(|| { let s = env::var(SEED_ENV).unwrap_or_else(|_| { - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); (0..32).map(|_| rng.sample(Alphanumeric) as char).collect() }); @@ -33,19 +33,19 @@ pub trait RandomInput: Sized { /// Generate a sequence of deterministically random floats. fn random_floats(count: u64) -> impl Iterator where - Standard: Distribution, + StandardUniform: Distribution, { let mut rng = ChaCha8Rng::from_seed(*SEED); // Generate integers to get a full range of bitpatterns (including NaNs), then convert back // to the float type. - (0..count).map(move |_| F::from_bits(rng.gen::())) + (0..count).map(move |_| F::from_bits(rng.random::())) } /// Generate a sequence of deterministically random `i32`s within a specified range. fn random_ints(count: u64, range: RangeInclusive) -> impl Iterator { let mut rng = ChaCha8Rng::from_seed(*SEED); - (0..count).map(move |_| rng.gen_range::(range.clone())) + (0..count).map(move |_| rng.random_range::(range.clone())) } macro_rules! impl_random_input { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs b/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs index 4174820c05b..4603534248c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs @@ -25,8 +25,8 @@ fn hexu(v: u256) -> String { } fn random_u256(rng: &mut ChaCha8Rng) -> u256 { - let lo: u128 = rng.gen(); - let hi: u128 = rng.gen(); + let lo: u128 = rng.random(); + let hi: u128 = rng.random(); u256 { lo, hi } } @@ -121,7 +121,7 @@ fn mp_u256_shr() { for _ in 0..bigint_fuzz_iteration_count() { let x = random_u256(&mut rng); - let shift: u32 = rng.gen_range(0..255); + let shift: u32 = rng.random_range(0..255); assign_bigint(&mut bx, x); let actual = x >> shift; bx >>= shift; @@ -136,8 +136,8 @@ fn mp_u256_widen_mul() { let mut by = BigInt::new(); for _ in 0..bigint_fuzz_iteration_count() { - let x: u128 = rng.gen(); - let y: u128 = rng.gen(); + let x: u128 = rng.random(); + let y: u128 = rng.random(); bx.assign(x); by.assign(y); let actual = x.widen_mul(y); diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml index cde78fd3c97..34682b74c67 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml +++ b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml @@ -10,4 +10,4 @@ publish = false libm = { path = "../../" } [build-dependencies] -cc = "1.2.10" +cc = "1.2.16" -- cgit 1.4.1-3-g733a5 From 3167cbb6d01e247ca679712fd923c7cfbc45d7fc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Mar 2025 04:02:54 +0000 Subject: Temporarily disable the test call to `rust_begin_unwind` Since [1] this symbol is mangled, meaning it is not easy to call directly. A better fix will come in [2] but for now, just disable that portion of the test. [1]: https://github.com/rust-lang/rust/pull/127173 [2]: https://github.com/rust-lang/compiler-builtins/pull/802 --- .../builtins-test-intrinsics/src/main.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs index e90cfb33dea..21d0a083c71 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -626,13 +626,14 @@ fn run() { something_with_a_dtor(&|| assert_eq!(bb(1), 1)); - extern "C" { - fn rust_begin_unwind(x: usize); - } - - unsafe { - rust_begin_unwind(0); - } + // FIXME(#802): This should be re-enabled once a workaround is found. + // extern "C" { + // fn rust_begin_unwind(x: usize); + // } + + // unsafe { + // rust_begin_unwind(0); + // } } fn something_with_a_dtor(f: &dyn Fn()) { -- cgit 1.4.1-3-g733a5 From 683485cda22efc3514da4de730968e691e3a902f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Mar 2025 05:19:17 +0000 Subject: Switch repository layout to use a virtual manifest The current setup has the `Cargo.toml` for `compiler-builtins` at the repository root, which means all support crates and other files are located within the package root. This works for now but is not the cleanest setup since files that should or shouldn't be included in the package need to be configured in `Cargo.toml`. If we eventually merge `libm` development into this repository, it would be nice to make this separation more straightforward. Begin cleaning things up by moving the crate source to a new `compiler-builtins` directory and adding a virtual manifest. For now the `libm` submodule is also moved, but in the future it can likely move back to the top level (ideally `compiler-builtins/src` would contain a symlink to `libm/src/math`, but unfortunately it seems like Cargo does not like something about the submodule + symlink combination). --- .../compiler-builtins/.github/workflows/main.yml | 3 +- .../.github/workflows/publish.yml | 2 +- library/compiler-builtins/.gitmodules | 4 +- library/compiler-builtins/Cargo.toml | 80 +-- library/compiler-builtins/build.rs | 714 --------------------- .../builtins-test-intrinsics/Cargo.toml | 2 +- .../builtins-test-intrinsics/build.rs | 2 +- library/compiler-builtins/ci/run-docker.sh | 2 +- library/compiler-builtins/ci/run.sh | 4 +- .../compiler-builtins/compiler-builtins/Cargo.toml | 72 +++ .../compiler-builtins/compiler-builtins/build.rs | 714 +++++++++++++++++++++ .../compiler-builtins/configure.rs | 138 ++++ library/compiler-builtins/compiler-builtins/libm | 1 + .../compiler-builtins/src/aarch64.rs | 21 + .../compiler-builtins/src/aarch64_linux.rs | 273 ++++++++ .../compiler-builtins/compiler-builtins/src/arm.rs | 165 +++++ .../compiler-builtins/src/arm_linux.rs | 250 ++++++++ .../compiler-builtins/src/float/add.rs | 211 ++++++ .../compiler-builtins/src/float/cmp.rs | 261 ++++++++ .../compiler-builtins/src/float/conv.rs | 490 ++++++++++++++ .../compiler-builtins/src/float/div.rs | 637 ++++++++++++++++++ .../compiler-builtins/src/float/extend.rs | 130 ++++ .../compiler-builtins/src/float/mod.rs | 16 + .../compiler-builtins/src/float/mul.rs | 202 ++++++ .../compiler-builtins/src/float/pow.rs | 47 ++ .../compiler-builtins/src/float/sub.rs | 26 + .../compiler-builtins/src/float/traits.rs | 189 ++++++ .../compiler-builtins/src/float/trunc.rs | 176 +++++ .../compiler-builtins/src/hexagon.rs | 55 ++ .../compiler-builtins/src/hexagon/dfaddsub.s | 321 +++++++++ .../compiler-builtins/src/hexagon/dfdiv.s | 372 +++++++++++ .../compiler-builtins/src/hexagon/dffma.s | 534 +++++++++++++++ .../compiler-builtins/src/hexagon/dfminmax.s | 45 ++ .../compiler-builtins/src/hexagon/dfmul.s | 309 +++++++++ .../compiler-builtins/src/hexagon/dfsqrt.s | 277 ++++++++ .../compiler-builtins/src/hexagon/divdi3.s | 64 ++ .../compiler-builtins/src/hexagon/divsi3.s | 53 ++ .../src/hexagon/fastmath2_dlib_asm.s | 266 ++++++++ .../src/hexagon/fastmath2_ldlib_asm.s | 187 ++++++ .../compiler-builtins/src/hexagon/func_macro.s | 12 + .../src/hexagon/memcpy_forward_vp4cp4n2.s | 91 +++ .../src/hexagon/memcpy_likely_aligned.s | 42 ++ .../compiler-builtins/src/hexagon/moddi3.s | 63 ++ .../compiler-builtins/src/hexagon/modsi3.s | 44 ++ .../compiler-builtins/src/hexagon/sfdiv_opt.s | 42 ++ .../compiler-builtins/src/hexagon/sfsqrt_opt.s | 49 ++ .../compiler-builtins/src/hexagon/udivdi3.s | 50 ++ .../compiler-builtins/src/hexagon/udivmoddi4.s | 50 ++ .../compiler-builtins/src/hexagon/udivmodsi4.s | 39 ++ .../compiler-builtins/src/hexagon/udivsi3.s | 36 ++ .../compiler-builtins/src/hexagon/umoddi3.s | 53 ++ .../compiler-builtins/src/hexagon/umodsi3.s | 34 + .../compiler-builtins/src/int/addsub.rs | 104 +++ .../compiler-builtins/src/int/big.rs | 294 +++++++++ .../compiler-builtins/src/int/bswap.rs | 22 + .../compiler-builtins/src/int/leading_zeros.rs | 168 +++++ .../compiler-builtins/src/int/mod.rs | 20 + .../compiler-builtins/src/int/mul.rs | 142 ++++ .../compiler-builtins/src/int/sdiv.rs | 169 +++++ .../compiler-builtins/src/int/shift.rs | 125 ++++ .../src/int/specialized_div_rem/asymmetric.rs | 69 ++ .../src/int/specialized_div_rem/binary_long.rs | 552 ++++++++++++++++ .../src/int/specialized_div_rem/delegate.rs | 317 +++++++++ .../src/int/specialized_div_rem/mod.rs | 321 +++++++++ .../src/int/specialized_div_rem/norm_shift.rs | 106 +++ .../src/int/specialized_div_rem/trifecta.rs | 386 +++++++++++ .../compiler-builtins/src/int/trailing_zeros.rs | 69 ++ .../compiler-builtins/src/int/traits.rs | 411 ++++++++++++ .../compiler-builtins/src/int/udiv.rs | 103 +++ .../compiler-builtins/src/lib.miri.rs | 5 + .../compiler-builtins/compiler-builtins/src/lib.rs | 78 +++ .../compiler-builtins/src/macros.rs | 514 +++++++++++++++ .../compiler-builtins/src/math.rs | 199 ++++++ .../compiler-builtins/src/mem/impls.rs | 308 +++++++++ .../compiler-builtins/src/mem/mod.rs | 58 ++ .../compiler-builtins/src/mem/x86_64.rs | 314 +++++++++ .../compiler-builtins/src/probestack.rs | 350 ++++++++++ .../compiler-builtins/src/riscv.rs | 50 ++ .../compiler-builtins/compiler-builtins/src/x86.rs | 53 ++ .../compiler-builtins/src/x86_64.rs | 51 ++ library/compiler-builtins/configure.rs | 138 ---- .../crates/panic-handler/Cargo.toml | 4 + library/compiler-builtins/libm | 1 - library/compiler-builtins/src/aarch64.rs | 21 - library/compiler-builtins/src/aarch64_linux.rs | 273 -------- library/compiler-builtins/src/arm.rs | 165 ----- library/compiler-builtins/src/arm_linux.rs | 250 -------- library/compiler-builtins/src/float/add.rs | 211 ------ library/compiler-builtins/src/float/cmp.rs | 261 -------- library/compiler-builtins/src/float/conv.rs | 490 -------------- library/compiler-builtins/src/float/div.rs | 637 ------------------ library/compiler-builtins/src/float/extend.rs | 130 ---- library/compiler-builtins/src/float/mod.rs | 16 - library/compiler-builtins/src/float/mul.rs | 202 ------ library/compiler-builtins/src/float/pow.rs | 47 -- library/compiler-builtins/src/float/sub.rs | 26 - library/compiler-builtins/src/float/traits.rs | 189 ------ library/compiler-builtins/src/float/trunc.rs | 176 ----- library/compiler-builtins/src/hexagon.rs | 55 -- library/compiler-builtins/src/hexagon/dfaddsub.s | 321 --------- library/compiler-builtins/src/hexagon/dfdiv.s | 372 ----------- library/compiler-builtins/src/hexagon/dffma.s | 534 --------------- library/compiler-builtins/src/hexagon/dfminmax.s | 45 -- library/compiler-builtins/src/hexagon/dfmul.s | 309 --------- library/compiler-builtins/src/hexagon/dfsqrt.s | 277 -------- library/compiler-builtins/src/hexagon/divdi3.s | 64 -- library/compiler-builtins/src/hexagon/divsi3.s | 53 -- .../src/hexagon/fastmath2_dlib_asm.s | 266 -------- .../src/hexagon/fastmath2_ldlib_asm.s | 187 ------ library/compiler-builtins/src/hexagon/func_macro.s | 12 - .../src/hexagon/memcpy_forward_vp4cp4n2.s | 91 --- .../src/hexagon/memcpy_likely_aligned.s | 42 -- library/compiler-builtins/src/hexagon/moddi3.s | 63 -- library/compiler-builtins/src/hexagon/modsi3.s | 44 -- library/compiler-builtins/src/hexagon/sfdiv_opt.s | 42 -- library/compiler-builtins/src/hexagon/sfsqrt_opt.s | 49 -- library/compiler-builtins/src/hexagon/udivdi3.s | 50 -- library/compiler-builtins/src/hexagon/udivmoddi4.s | 50 -- library/compiler-builtins/src/hexagon/udivmodsi4.s | 39 -- library/compiler-builtins/src/hexagon/udivsi3.s | 36 -- library/compiler-builtins/src/hexagon/umoddi3.s | 53 -- library/compiler-builtins/src/hexagon/umodsi3.s | 34 - library/compiler-builtins/src/int/addsub.rs | 104 --- library/compiler-builtins/src/int/big.rs | 294 --------- library/compiler-builtins/src/int/bswap.rs | 22 - library/compiler-builtins/src/int/leading_zeros.rs | 168 ----- library/compiler-builtins/src/int/mod.rs | 20 - library/compiler-builtins/src/int/mul.rs | 142 ---- library/compiler-builtins/src/int/sdiv.rs | 169 ----- library/compiler-builtins/src/int/shift.rs | 125 ---- .../src/int/specialized_div_rem/asymmetric.rs | 69 -- .../src/int/specialized_div_rem/binary_long.rs | 552 ---------------- .../src/int/specialized_div_rem/delegate.rs | 317 --------- .../src/int/specialized_div_rem/mod.rs | 321 --------- .../src/int/specialized_div_rem/norm_shift.rs | 106 --- .../src/int/specialized_div_rem/trifecta.rs | 386 ----------- .../compiler-builtins/src/int/trailing_zeros.rs | 69 -- library/compiler-builtins/src/int/traits.rs | 411 ------------ library/compiler-builtins/src/int/udiv.rs | 103 --- library/compiler-builtins/src/lib.miri.rs | 5 - library/compiler-builtins/src/lib.rs | 79 --- library/compiler-builtins/src/macros.rs | 514 --------------- library/compiler-builtins/src/math.rs | 199 ------ library/compiler-builtins/src/mem/impls.rs | 308 --------- library/compiler-builtins/src/mem/mod.rs | 58 -- library/compiler-builtins/src/mem/x86_64.rs | 314 --------- library/compiler-builtins/src/probestack.rs | 350 ---------- library/compiler-builtins/src/riscv.rs | 50 -- library/compiler-builtins/src/x86.rs | 53 -- library/compiler-builtins/src/x86_64.rs | 51 -- library/compiler-builtins/testcrate/Cargo.toml | 2 +- library/compiler-builtins/testcrate/build.rs | 2 +- 152 files changed, 12485 insertions(+), 12481 deletions(-) delete mode 100644 library/compiler-builtins/build.rs create mode 100644 library/compiler-builtins/compiler-builtins/Cargo.toml create mode 100644 library/compiler-builtins/compiler-builtins/build.rs create mode 100644 library/compiler-builtins/compiler-builtins/configure.rs create mode 160000 library/compiler-builtins/compiler-builtins/libm create mode 100644 library/compiler-builtins/compiler-builtins/src/aarch64.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/arm.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/arm_linux.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/float/add.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/float/cmp.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/float/conv.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/float/div.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/float/extend.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/float/mod.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/float/mul.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/float/pow.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/float/sub.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/float/traits.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/float/trunc.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/dfaddsub.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/dfdiv.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/dffma.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/dfminmax.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/dfmul.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/dfsqrt.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/divdi3.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/divsi3.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/func_macro.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_likely_aligned.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/moddi3.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/modsi3.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/sfdiv_opt.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/sfsqrt_opt.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/udivdi3.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/udivmoddi4.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/udivmodsi4.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/udivsi3.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/umoddi3.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/umodsi3.s create mode 100644 library/compiler-builtins/compiler-builtins/src/int/addsub.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/big.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/bswap.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/mod.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/mul.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/sdiv.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/shift.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/binary_long.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/delegate.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/trifecta.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/traits.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/int/udiv.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/lib.miri.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/lib.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/macros.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/math.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/mem/impls.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/mem/mod.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/probestack.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/riscv.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/x86.rs create mode 100644 library/compiler-builtins/compiler-builtins/src/x86_64.rs delete mode 100644 library/compiler-builtins/configure.rs delete mode 160000 library/compiler-builtins/libm delete mode 100644 library/compiler-builtins/src/aarch64.rs delete mode 100644 library/compiler-builtins/src/aarch64_linux.rs delete mode 100644 library/compiler-builtins/src/arm.rs delete mode 100644 library/compiler-builtins/src/arm_linux.rs delete mode 100644 library/compiler-builtins/src/float/add.rs delete mode 100644 library/compiler-builtins/src/float/cmp.rs delete mode 100644 library/compiler-builtins/src/float/conv.rs delete mode 100644 library/compiler-builtins/src/float/div.rs delete mode 100644 library/compiler-builtins/src/float/extend.rs delete mode 100644 library/compiler-builtins/src/float/mod.rs delete mode 100644 library/compiler-builtins/src/float/mul.rs delete mode 100644 library/compiler-builtins/src/float/pow.rs delete mode 100644 library/compiler-builtins/src/float/sub.rs delete mode 100644 library/compiler-builtins/src/float/traits.rs delete mode 100644 library/compiler-builtins/src/float/trunc.rs delete mode 100644 library/compiler-builtins/src/hexagon.rs delete mode 100644 library/compiler-builtins/src/hexagon/dfaddsub.s delete mode 100644 library/compiler-builtins/src/hexagon/dfdiv.s delete mode 100644 library/compiler-builtins/src/hexagon/dffma.s delete mode 100644 library/compiler-builtins/src/hexagon/dfminmax.s delete mode 100644 library/compiler-builtins/src/hexagon/dfmul.s delete mode 100644 library/compiler-builtins/src/hexagon/dfsqrt.s delete mode 100644 library/compiler-builtins/src/hexagon/divdi3.s delete mode 100644 library/compiler-builtins/src/hexagon/divsi3.s delete mode 100644 library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s delete mode 100644 library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s delete mode 100644 library/compiler-builtins/src/hexagon/func_macro.s delete mode 100644 library/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s delete mode 100644 library/compiler-builtins/src/hexagon/memcpy_likely_aligned.s delete mode 100644 library/compiler-builtins/src/hexagon/moddi3.s delete mode 100644 library/compiler-builtins/src/hexagon/modsi3.s delete mode 100644 library/compiler-builtins/src/hexagon/sfdiv_opt.s delete mode 100644 library/compiler-builtins/src/hexagon/sfsqrt_opt.s delete mode 100644 library/compiler-builtins/src/hexagon/udivdi3.s delete mode 100644 library/compiler-builtins/src/hexagon/udivmoddi4.s delete mode 100644 library/compiler-builtins/src/hexagon/udivmodsi4.s delete mode 100644 library/compiler-builtins/src/hexagon/udivsi3.s delete mode 100644 library/compiler-builtins/src/hexagon/umoddi3.s delete mode 100644 library/compiler-builtins/src/hexagon/umodsi3.s delete mode 100644 library/compiler-builtins/src/int/addsub.rs delete mode 100644 library/compiler-builtins/src/int/big.rs delete mode 100644 library/compiler-builtins/src/int/bswap.rs delete mode 100644 library/compiler-builtins/src/int/leading_zeros.rs delete mode 100644 library/compiler-builtins/src/int/mod.rs delete mode 100644 library/compiler-builtins/src/int/mul.rs delete mode 100644 library/compiler-builtins/src/int/sdiv.rs delete mode 100644 library/compiler-builtins/src/int/shift.rs delete mode 100644 library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs delete mode 100644 library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs delete mode 100644 library/compiler-builtins/src/int/specialized_div_rem/delegate.rs delete mode 100644 library/compiler-builtins/src/int/specialized_div_rem/mod.rs delete mode 100644 library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs delete mode 100644 library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs delete mode 100644 library/compiler-builtins/src/int/trailing_zeros.rs delete mode 100644 library/compiler-builtins/src/int/traits.rs delete mode 100644 library/compiler-builtins/src/int/udiv.rs delete mode 100644 library/compiler-builtins/src/lib.miri.rs delete mode 100644 library/compiler-builtins/src/lib.rs delete mode 100644 library/compiler-builtins/src/macros.rs delete mode 100644 library/compiler-builtins/src/math.rs delete mode 100644 library/compiler-builtins/src/mem/impls.rs delete mode 100644 library/compiler-builtins/src/mem/mod.rs delete mode 100644 library/compiler-builtins/src/mem/x86_64.rs delete mode 100644 library/compiler-builtins/src/probestack.rs delete mode 100644 library/compiler-builtins/src/riscv.rs delete mode 100644 library/compiler-builtins/src/x86.rs delete mode 100644 library/compiler-builtins/src/x86_64.rs diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 50844a66c43..c337c26a272 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -4,7 +4,6 @@ on: [push, pull_request] env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings - RUST_COMPILER_RT_ROOT: ./compiler-rt jobs: test: @@ -133,6 +132,8 @@ jobs: if: steps.cache-compiler-rt.outputs.cache-hit != 'true' run: ./ci/download-compiler-rt.sh shell: bash + - run: echo "RUST_COMPILER_RT_ROOT=$(realpath ./compiler-rt)" >> "$GITHUB_ENV" + shell: bash # Non-linux tests just use our raw script - run: ./ci/run.sh ${{ matrix.target }} diff --git a/library/compiler-builtins/.github/workflows/publish.yml b/library/compiler-builtins/.github/workflows/publish.yml index d568f375738..7d6a8df0305 100644 --- a/library/compiler-builtins/.github/workflows/publish.yml +++ b/library/compiler-builtins/.github/workflows/publish.yml @@ -22,7 +22,7 @@ jobs: - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly - name: Publish `libm` as part of builtins, rather than its own crate - run: rm libm/Cargo.toml + run: rm compiler-builtins/libm/Cargo.toml - name: Run release-plz uses: MarcoIeni/release-plz-action@v0.5 env: diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index 726b1c5c67c..a0b0d021dea 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ -[submodule "libm"] - path = libm +[submodule "compiler-builtins/libm"] + path = compiler-builtins/libm url = https://github.com/rust-lang/libm.git diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 60de27758d8..db4c45dfa4b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,88 +1,16 @@ -[package] -authors = ["Jorge Aparicio "] -name = "compiler_builtins" -version = "0.1.151" -license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" -readme = "README.md" -repository = "https://github.com/rust-lang/compiler-builtins" -homepage = "https://github.com/rust-lang/compiler-builtins" -documentation = "https://docs.rs/compiler_builtins" -edition = "2021" -description = """ -Compiler intrinsics used by the Rust compiler. Also available for other targets -if necessary! -""" -include = [ - '/Cargo.toml', - '/build.rs', - '/configure.rs', - '/src/*', - '/examples/*', - '/LICENSE.txt', - '/README.md', - '/compiler-rt/*', - '/libm/src/math/*', -] -links = 'compiler-rt' - -[lib] -test = false - -[dependencies] -# For more information on this dependency see -# https://github.com/rust-lang/rust/tree/master/library/rustc-std-workspace-core -core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } - -[build-dependencies] -cc = { optional = true, version = "1.0" } - -[dev-dependencies] -panic-handler = { path = 'crates/panic-handler' } - -[features] -default = ["compiler-builtins"] - -# Enable compilation of C code in compiler-rt, filling in some more optimized -# implementations and also filling in unimplemented intrinsics -c = ["cc"] - -# Workaround for the Cranelift codegen backend. Disables any implementations -# which use inline assembly and fall back to pure Rust versions (if avalible). -no-asm = [] - -# Workaround for codegen backends which haven't yet implemented `f16` and -# `f128` support. Disabled any intrinsics which use those types. -no-f16-f128 = [] - -# Flag this library as the unstable compiler-builtins lib -compiler-builtins = [] - -# Generate memory-related intrinsics like memcpy -mem = [] - -# Mangle all names so this can be linked in with other versions or other -# compiler-rt implementations. Also used for testing -mangled-names = [] - -# Only used in the compiler's build system -rustc-dep-of-std = ['compiler-builtins', 'core'] - -# This makes certain traits and function specializations public that -# are not normally public but are required by the `testcrate` -public-test-deps = [] - [workspace] -resolver = "2" +resolver = "3" members = [ - # Note that builtins-test-intrinsics cannot be a default member because it + # Note that builtins-test-intrinsics cannot be a default member because it # needs the `mangled-names` feature disabled, while `testcrate` needs it # enabled. "builtins-test-intrinsics", + "compiler-builtins", "testcrate", ] default-members = [ - ".", + "compiler-builtins", "testcrate", ] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs deleted file mode 100644 index 3003d51aff8..00000000000 --- a/library/compiler-builtins/build.rs +++ /dev/null @@ -1,714 +0,0 @@ -use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering}; - -mod configure; - -use configure::{configure_aliases, configure_f16_f128, Target}; - -fn main() { - println!("cargo::rerun-if-changed=build.rs"); - println!("cargo::rerun-if-changed=configure.rs"); - - let target = Target::from_env(); - let cwd = env::current_dir().unwrap(); - - configure_check_cfg(); - configure_f16_f128(&target); - configure_aliases(&target); - - configure_libm(&target); - - println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); - - // Emscripten's runtime includes all the builtins - if target.os == "emscripten" { - return; - } - - // OpenBSD provides compiler_rt by default, use it instead of rebuilding it from source - if target.os == "openbsd" { - println!("cargo:rustc-link-search=native=/usr/lib"); - println!("cargo:rustc-link-lib=compiler_rt"); - return; - } - - // Forcibly enable memory intrinsics on wasm & SGX as we don't have a libc to - // provide them. - if (target.triple.contains("wasm") && !target.triple.contains("wasi")) - || (target.triple.contains("sgx") && target.triple.contains("fortanix")) - || target.triple.contains("-none") - || target.triple.contains("nvptx") - || target.triple.contains("uefi") - || target.triple.contains("xous") - { - println!("cargo:rustc-cfg=feature=\"mem\""); - } - - // These targets have hardware unaligned access support. - println!("cargo::rustc-check-cfg=cfg(feature, values(\"mem-unaligned\"))"); - if target.arch.contains("x86_64") - || target.arch.contains("x86") - || target.arch.contains("aarch64") - || target.arch.contains("bpf") - { - println!("cargo:rustc-cfg=feature=\"mem-unaligned\""); - } - - // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the - // target triple. This is usually correct for our built-in targets but can break in presence of - // custom targets, which can have arbitrary names. - let llvm_target = target.triple.split('-').collect::>(); - - // Build missing intrinsics from compiler-rt C source code. If we're - // mangling names though we assume that we're also in test mode so we don't - // build anything and we rely on the upstream implementation of compiler-rt - // functions - if !cfg!(feature = "mangled-names") && cfg!(feature = "c") { - // Don't use a C compiler for these targets: - // - // * nvptx - everything is bitcode, not compatible with mixed C/Rust - if !target.arch.contains("nvptx") { - #[cfg(feature = "c")] - c::compile(&llvm_target, &target); - } - } - - // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. This - // includes the old androideabi. It is deprecated but it is available as a - // rustc target (arm-linux-androideabi). - println!("cargo::rustc-check-cfg=cfg(kernel_user_helpers)"); - if llvm_target[0] == "armv4t" - || llvm_target[0] == "armv5te" - || target.triple == "arm-linux-androideabi" - { - println!("cargo:rustc-cfg=kernel_user_helpers") - } - - if llvm_target[0].starts_with("aarch64") { - generate_aarch64_outlined_atomics(); - } -} - -/// Run configuration for `libm` since it is included directly. -/// -/// Much of this is copied from `libm/configure.rs`. -fn configure_libm(target: &Target) { - println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)"); - println!("cargo:rustc-check-cfg=cfg(arch_enabled)"); - println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); - println!("cargo:rustc-check-cfg=cfg(feature, values(\"unstable-public-internals\"))"); - - // Always use intrinsics - println!("cargo:rustc-cfg=intrinsics_enabled"); - - // The arch module may contain assembly. - if cfg!(feature = "no-asm") { - println!("cargo:rustc-cfg=feature=\"force-soft-floats\""); - } else { - println!("cargo:rustc-cfg=arch_enabled"); - } - - println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); - if !matches!(target.opt_level.as_str(), "0" | "1") { - println!("cargo:rustc-cfg=optimizations_enabled"); - } - - // Config shorthands - println!("cargo:rustc-check-cfg=cfg(x86_no_sse)"); - if target.arch == "x86" && !target.features.iter().any(|f| f == "sse") { - // Shorthand to detect i586 targets - println!("cargo:rustc-cfg=x86_no_sse"); - } - - println!( - "cargo:rustc-env=CFG_CARGO_FEATURES={:?}", - target.cargo_features - ); - println!("cargo:rustc-env=CFG_OPT_LEVEL={}", target.opt_level); - println!("cargo:rustc-env=CFG_TARGET_FEATURES={:?}", target.features); - - // Activate libm's unstable features to make full use of Nightly. - println!("cargo:rustc-cfg=feature=\"unstable-intrinsics\""); -} - -fn aarch64_symbol(ordering: Ordering) -> &'static str { - match ordering { - Ordering::Relaxed => "relax", - Ordering::Acquire => "acq", - Ordering::Release => "rel", - Ordering::AcqRel => "acq_rel", - _ => panic!("unknown symbol for {:?}", ordering), - } -} - -/// The `concat_idents` macro is extremely annoying and doesn't allow us to define new items. -/// Define them from the build script instead. -/// Note that the majority of the code is still defined in `aarch64.rs` through inline macros. -fn generate_aarch64_outlined_atomics() { - use std::fmt::Write; - // #[macro_export] so that we can use this in tests - let gen_macro = - |name| format!("#[macro_export] macro_rules! foreach_{name} {{ ($macro:path) => {{\n"); - - // Generate different macros for add/clr/eor/set so that we can test them separately. - let sym_names = ["cas", "ldadd", "ldclr", "ldeor", "ldset", "swp"]; - let mut macros = BTreeMap::new(); - for sym in sym_names { - macros.insert(sym, gen_macro(sym)); - } - - // Only CAS supports 16 bytes, and it has a different implementation that uses a different macro. - let mut cas16 = gen_macro("cas16"); - - for ordering in [ - Ordering::Relaxed, - Ordering::Acquire, - Ordering::Release, - Ordering::AcqRel, - ] { - let sym_ordering = aarch64_symbol(ordering); - for size in [1, 2, 4, 8] { - for (sym, macro_) in &mut macros { - let name = format!("__aarch64_{sym}{size}_{sym_ordering}"); - writeln!(macro_, "$macro!( {ordering:?}, {size}, {name} );").unwrap(); - } - } - let name = format!("__aarch64_cas16_{sym_ordering}"); - writeln!(cas16, "$macro!( {ordering:?}, {name} );").unwrap(); - } - - let mut buf = String::new(); - for macro_def in macros.values().chain(std::iter::once(&cas16)) { - buf += macro_def; - buf += "}; }\n"; - } - let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); - std::fs::write(out_dir.join("outlined_atomics.rs"), buf).unwrap(); -} - -/// Emit directives for features we expect to support that aren't in `Cargo.toml`. -/// -/// These are mostly cfg elements emitted by this `build.rs`. -fn configure_check_cfg() { - // Functions where we can set the "optimized-c" flag - const HAS_OPTIMIZED_C: &[&str] = &[ - "__ashldi3", - "__ashlsi3", - "__ashrdi3", - "__ashrsi3", - "__bswapsi2", - "__bswapdi2", - "__bswapti2", - "__divdi3", - "__divsi3", - "__divmoddi4", - "__divmodsi4", - "__divmodsi4", - "__divmodti4", - "__lshrdi3", - "__lshrsi3", - "__moddi3", - "__modsi3", - "__muldi3", - "__udivdi3", - "__udivmoddi4", - "__udivmodsi4", - "__udivsi3", - "__umoddi3", - "__umodsi3", - ]; - - // Build a list of all aarch64 atomic operation functions - let mut aarch_atomic = Vec::new(); - for aarch_op in ["cas", "ldadd", "ldclr", "ldeor", "ldset", "swp"] { - let op_sizes = if aarch_op == "cas" { - [1, 2, 4, 8, 16].as_slice() - } else { - [1, 2, 4, 8].as_slice() - }; - - for op_size in op_sizes { - for ordering in ["relax", "acq", "rel", "acq_rel"] { - aarch_atomic.push(format!("__aarch64_{}{}_{}", aarch_op, op_size, ordering)); - } - } - } - - for fn_name in HAS_OPTIMIZED_C - .iter() - .copied() - .chain(aarch_atomic.iter().map(|s| s.as_str())) - { - println!( - "cargo::rustc-check-cfg=cfg({}, values(\"optimized-c\"))", - fn_name - ); - } - - // Rustc is unaware of sparc target features, but this does show up from - // `rustc --print target-features --target sparc64-unknown-linux-gnu`. - println!("cargo::rustc-check-cfg=cfg(target_feature, values(\"vis3\"))"); - - // FIXME: these come from libm and should be changed there - println!("cargo::rustc-check-cfg=cfg(feature, values(\"checked\"))"); - println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); -} - -#[cfg(feature = "c")] -mod c { - use std::collections::{BTreeMap, HashSet}; - use std::env; - use std::fs::{self, File}; - use std::io::Write; - use std::path::{Path, PathBuf}; - - use super::Target; - - struct Sources { - // SYMBOL -> PATH TO SOURCE - map: BTreeMap<&'static str, &'static str>, - } - - impl Sources { - fn new() -> Sources { - Sources { - map: BTreeMap::new(), - } - } - - fn extend(&mut self, sources: &[(&'static str, &'static str)]) { - // NOTE Some intrinsics have both a generic implementation (e.g. - // `floatdidf.c`) and an arch optimized implementation - // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized - // implementation and discard the generic implementation. If we don't - // and keep both implementations, the linker will yell at us about - // duplicate symbols! - for (symbol, src) in sources { - if src.contains("/") { - // Arch-optimized implementation (preferred) - self.map.insert(symbol, src); - } else { - // Generic implementation - if !self.map.contains_key(symbol) { - self.map.insert(symbol, src); - } - } - } - } - - fn remove(&mut self, symbols: &[&str]) { - for symbol in symbols { - self.map.remove(*symbol).unwrap(); - } - } - } - - /// Compile intrinsics from the compiler-rt C source code - pub fn compile(llvm_target: &[&str], target: &Target) { - let mut consider_float_intrinsics = true; - let cfg = &mut cc::Build::new(); - - // AArch64 GCCs exit with an error condition when they encounter any kind of floating point - // code if the `nofp` and/or `nosimd` compiler flags have been set. - // - // Therefore, evaluate if those flags are present and set a boolean that causes any - // compiler-rt intrinsics that contain floating point source to be excluded for this target. - if target.arch == "aarch64" { - let cflags_key = String::from("CFLAGS_") + &(target.triple.replace("-", "_")); - if let Ok(cflags_value) = env::var(cflags_key) { - if cflags_value.contains("+nofp") || cflags_value.contains("+nosimd") { - consider_float_intrinsics = false; - } - } - } - - // `compiler-rt` requires `COMPILER_RT_HAS_FLOAT16` to be defined to make it use the - // `_Float16` type for `f16` intrinsics. This shouldn't matter as all existing `f16` - // intrinsics have been ported to Rust in `compiler-builtins` as C compilers don't - // support `_Float16` on all targets (whereas Rust does). However, define the macro - // anyway to prevent issues like rust#118813 and rust#123885 silently reoccuring if more - // `f16` intrinsics get accidentally added here in the future. - cfg.define("COMPILER_RT_HAS_FLOAT16", None); - - cfg.warnings(false); - - if target.env == "msvc" { - // Don't pull in extra libraries on MSVC - cfg.flag("/Zl"); - - // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP - cfg.define("__func__", Some("__FUNCTION__")); - } else { - // Turn off various features of gcc and such, mostly copying - // compiler-rt's build system already - cfg.flag("-fno-builtin"); - cfg.flag("-fvisibility=hidden"); - cfg.flag("-ffreestanding"); - // Avoid the following warning appearing once **per file**: - // clang: warning: optimization flag '-fomit-frame-pointer' is not supported for target 'armv7' [-Wignored-optimization-argument] - // - // Note that compiler-rt's build system also checks - // - // `check_cxx_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG)` - // - // in https://github.com/rust-lang/compiler-rt/blob/c8fbcb3/cmake/config-ix.cmake#L19. - cfg.flag_if_supported("-fomit-frame-pointer"); - cfg.define("VISIBILITY_HIDDEN", None); - - if let "aarch64" | "arm64ec" = target.arch.as_str() { - // FIXME(llvm20): Older GCCs on A64 fail to build with - // -Werror=implicit-function-declaration due to a compiler-rt bug. - // With a newer LLVM we should be able to enable the flag everywhere. - // https://github.com/llvm/llvm-project/commit/8aa9d6206ce55bdaaf422839c351fbd63f033b89 - } else { - // Avoid implicitly creating references to undefined functions - cfg.flag("-Werror=implicit-function-declaration"); - } - } - - // int_util.c tries to include stdlib.h if `_WIN32` is defined, - // which it is when compiling UEFI targets with clang. This is - // at odds with compiling with `-ffreestanding`, as the header - // may be incompatible or not present. Create a minimal stub - // header to use instead. - if target.os == "uefi" { - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let include_dir = out_dir.join("include"); - if !include_dir.exists() { - fs::create_dir(&include_dir).unwrap(); - } - fs::write(include_dir.join("stdlib.h"), "#include ").unwrap(); - cfg.flag(&format!("-I{}", include_dir.to_str().unwrap())); - } - - let mut sources = Sources::new(); - sources.extend(&[ - ("__absvdi2", "absvdi2.c"), - ("__absvsi2", "absvsi2.c"), - ("__addvdi3", "addvdi3.c"), - ("__addvsi3", "addvsi3.c"), - ("__cmpdi2", "cmpdi2.c"), - ("__int_util", "int_util.c"), - ("__mulvdi3", "mulvdi3.c"), - ("__mulvsi3", "mulvsi3.c"), - ("__negdi2", "negdi2.c"), - ("__negvdi2", "negvdi2.c"), - ("__negvsi2", "negvsi2.c"), - ("__paritydi2", "paritydi2.c"), - ("__paritysi2", "paritysi2.c"), - ("__popcountdi2", "popcountdi2.c"), - ("__popcountsi2", "popcountsi2.c"), - ("__subvdi3", "subvdi3.c"), - ("__subvsi3", "subvsi3.c"), - ("__ucmpdi2", "ucmpdi2.c"), - ]); - - if consider_float_intrinsics { - sources.extend(&[ - ("__divdc3", "divdc3.c"), - ("__divsc3", "divsc3.c"), - ("__muldc3", "muldc3.c"), - ("__mulsc3", "mulsc3.c"), - ("__negdf2", "negdf2.c"), - ("__negsf2", "negsf2.c"), - ]); - } - - // On iOS and 32-bit OSX these are all just empty intrinsics, no need to - // include them. - if target.vendor != "apple" || target.arch != "x86" { - sources.extend(&[ - ("__absvti2", "absvti2.c"), - ("__addvti3", "addvti3.c"), - ("__cmpti2", "cmpti2.c"), - ("__ffsti2", "ffsti2.c"), - ("__mulvti3", "mulvti3.c"), - ("__negti2", "negti2.c"), - ("__parityti2", "parityti2.c"), - ("__popcountti2", "popcountti2.c"), - ("__subvti3", "subvti3.c"), - ("__ucmpti2", "ucmpti2.c"), - ]); - - if consider_float_intrinsics { - sources.extend(&[("__negvti2", "negvti2.c")]); - } - } - - if target.vendor == "apple" { - sources.extend(&[ - ("atomic_flag_clear", "atomic_flag_clear.c"), - ("atomic_flag_clear_explicit", "atomic_flag_clear_explicit.c"), - ("atomic_flag_test_and_set", "atomic_flag_test_and_set.c"), - ( - "atomic_flag_test_and_set_explicit", - "atomic_flag_test_and_set_explicit.c", - ), - ("atomic_signal_fence", "atomic_signal_fence.c"), - ("atomic_thread_fence", "atomic_thread_fence.c"), - ]); - } - - if target.env != "msvc" { - if target.arch == "x86" { - sources.extend(&[ - ("__ashldi3", "i386/ashldi3.S"), - ("__ashrdi3", "i386/ashrdi3.S"), - ("__divdi3", "i386/divdi3.S"), - ("__lshrdi3", "i386/lshrdi3.S"), - ("__moddi3", "i386/moddi3.S"), - ("__muldi3", "i386/muldi3.S"), - ("__udivdi3", "i386/udivdi3.S"), - ("__umoddi3", "i386/umoddi3.S"), - ]); - } - } - - if target.arch == "arm" && target.vendor != "apple" && target.env != "msvc" { - sources.extend(&[ - ("__aeabi_div0", "arm/aeabi_div0.c"), - ("__aeabi_drsub", "arm/aeabi_drsub.c"), - ("__aeabi_frsub", "arm/aeabi_frsub.c"), - ("__bswapdi2", "arm/bswapdi2.S"), - ("__bswapsi2", "arm/bswapsi2.S"), - ("__divmodsi4", "arm/divmodsi4.S"), - ("__divsi3", "arm/divsi3.S"), - ("__modsi3", "arm/modsi3.S"), - ("__switch16", "arm/switch16.S"), - ("__switch32", "arm/switch32.S"), - ("__switch8", "arm/switch8.S"), - ("__switchu8", "arm/switchu8.S"), - ("__sync_synchronize", "arm/sync_synchronize.S"), - ("__udivmodsi4", "arm/udivmodsi4.S"), - ("__udivsi3", "arm/udivsi3.S"), - ("__umodsi3", "arm/umodsi3.S"), - ]); - - if target.os == "freebsd" { - sources.extend(&[("__clear_cache", "clear_cache.c")]); - } - - // First of all aeabi_cdcmp and aeabi_cfcmp are never called by LLVM. - // Second are little-endian only, so build fail on big-endian targets. - // Temporally workaround: exclude these files for big-endian targets. - if !llvm_target[0].starts_with("thumbeb") && !llvm_target[0].starts_with("armeb") { - sources.extend(&[ - ("__aeabi_cdcmp", "arm/aeabi_cdcmp.S"), - ("__aeabi_cdcmpeq_check_nan", "arm/aeabi_cdcmpeq_check_nan.c"), - ("__aeabi_cfcmp", "arm/aeabi_cfcmp.S"), - ("__aeabi_cfcmpeq_check_nan", "arm/aeabi_cfcmpeq_check_nan.c"), - ]); - } - } - - if llvm_target[0] == "armv7" { - sources.extend(&[ - ("__sync_fetch_and_add_4", "arm/sync_fetch_and_add_4.S"), - ("__sync_fetch_and_add_8", "arm/sync_fetch_and_add_8.S"), - ("__sync_fetch_and_and_4", "arm/sync_fetch_and_and_4.S"), - ("__sync_fetch_and_and_8", "arm/sync_fetch_and_and_8.S"), - ("__sync_fetch_and_max_4", "arm/sync_fetch_and_max_4.S"), - ("__sync_fetch_and_max_8", "arm/sync_fetch_and_max_8.S"), - ("__sync_fetch_and_min_4", "arm/sync_fetch_and_min_4.S"), - ("__sync_fetch_and_min_8", "arm/sync_fetch_and_min_8.S"), - ("__sync_fetch_and_nand_4", "arm/sync_fetch_and_nand_4.S"), - ("__sync_fetch_and_nand_8", "arm/sync_fetch_and_nand_8.S"), - ("__sync_fetch_and_or_4", "arm/sync_fetch_and_or_4.S"), - ("__sync_fetch_and_or_8", "arm/sync_fetch_and_or_8.S"), - ("__sync_fetch_and_sub_4", "arm/sync_fetch_and_sub_4.S"), - ("__sync_fetch_and_sub_8", "arm/sync_fetch_and_sub_8.S"), - ("__sync_fetch_and_umax_4", "arm/sync_fetch_and_umax_4.S"), - ("__sync_fetch_and_umax_8", "arm/sync_fetch_and_umax_8.S"), - ("__sync_fetch_and_umin_4", "arm/sync_fetch_and_umin_4.S"), - ("__sync_fetch_and_umin_8", "arm/sync_fetch_and_umin_8.S"), - ("__sync_fetch_and_xor_4", "arm/sync_fetch_and_xor_4.S"), - ("__sync_fetch_and_xor_8", "arm/sync_fetch_and_xor_8.S"), - ]); - } - - if llvm_target.last().unwrap().ends_with("eabihf") { - if !llvm_target[0].starts_with("thumbv7em") - && !llvm_target[0].starts_with("thumbv8m.main") - { - // The FPU option chosen for these architectures in cc-rs, ie: - // -mfpu=fpv4-sp-d16 for thumbv7em - // -mfpu=fpv5-sp-d16 for thumbv8m.main - // do not support double precision floating points conversions so the files - // that include such instructions are not included for these targets. - sources.extend(&[ - ("__fixdfsivfp", "arm/fixdfsivfp.S"), - ("__fixunsdfsivfp", "arm/fixunsdfsivfp.S"), - ("__floatsidfvfp", "arm/floatsidfvfp.S"), - ("__floatunssidfvfp", "arm/floatunssidfvfp.S"), - ]); - } - - sources.extend(&[ - ("__fixsfsivfp", "arm/fixsfsivfp.S"), - ("__fixunssfsivfp", "arm/fixunssfsivfp.S"), - ("__floatsisfvfp", "arm/floatsisfvfp.S"), - ("__floatunssisfvfp", "arm/floatunssisfvfp.S"), - ("__floatunssisfvfp", "arm/floatunssisfvfp.S"), - ("__restore_vfp_d8_d15_regs", "arm/restore_vfp_d8_d15_regs.S"), - ("__save_vfp_d8_d15_regs", "arm/save_vfp_d8_d15_regs.S"), - ("__negdf2vfp", "arm/negdf2vfp.S"), - ("__negsf2vfp", "arm/negsf2vfp.S"), - ]); - } - - if (target.arch == "aarch64" || target.arch == "arm64ec") && consider_float_intrinsics { - sources.extend(&[ - ("__comparetf2", "comparetf2.c"), - ("__fe_getround", "fp_mode.c"), - ("__fe_raise_inexact", "fp_mode.c"), - ]); - - if target.os != "windows" && target.os != "cygwin" { - sources.extend(&[("__multc3", "multc3.c")]); - } - } - - if target.arch == "mips" || target.arch == "riscv32" || target.arch == "riscv64" { - sources.extend(&[("__bswapsi2", "bswapsi2.c")]); - } - - if target.arch == "mips64" { - sources.extend(&[("__netf2", "comparetf2.c"), ("__fe_getround", "fp_mode.c")]); - } - - if target.arch == "loongarch64" { - sources.extend(&[("__netf2", "comparetf2.c"), ("__fe_getround", "fp_mode.c")]); - } - - // Remove the assembly implementations that won't compile for the target - if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" || target.os == "uefi" - { - let mut to_remove = Vec::new(); - for (k, v) in sources.map.iter() { - if v.ends_with(".S") { - to_remove.push(*k); - } - } - sources.remove(&to_remove); - } - - if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { - sources.remove(&["__aeabi_cdcmp", "__aeabi_cfcmp"]); - } - - // Android and Cygwin uses emulated TLS so we need a runtime support function. - if target.os == "android" || target.os == "cygwin" { - sources.extend(&[("__emutls_get_address", "emutls.c")]); - } - - // Work around a bug in the NDK headers (fixed in - // https://r.android.com/2038949 which will be released in a future - // NDK version) by providing a definition of LONG_BIT. - if target.os == "android" { - cfg.define("LONG_BIT", "(8 * sizeof(long))"); - } - - // OpenHarmony also uses emulated TLS. - if target.env == "ohos" { - sources.extend(&[("__emutls_get_address", "emutls.c")]); - } - - // When compiling the C code we require the user to tell us where the - // source code is, and this is largely done so when we're compiling as - // part of rust-lang/rust we can use the same llvm-project repository as - // rust-lang/rust. - let root = match env::var_os("RUST_COMPILER_RT_ROOT") { - Some(s) => PathBuf::from(s), - None => { - panic!( - "RUST_COMPILER_RT_ROOT is not set. You may need to run \ - `ci/download-compiler-rt.sh`." - ); - } - }; - if !root.exists() { - panic!("RUST_COMPILER_RT_ROOT={} does not exist", root.display()); - } - - // Support deterministic builds by remapping the __FILE__ prefix if the - // compiler supports it. This fixes the nondeterminism caused by the - // use of that macro in lib/builtins/int_util.h in compiler-rt. - cfg.flag_if_supported(&format!("-ffile-prefix-map={}=.", root.display())); - - // Include out-of-line atomics for aarch64, which are all generated by supplying different - // sets of flags to the same source file. - // Note: Out-of-line aarch64 atomics are not supported by the msvc toolchain (#430) and - // on uefi. - let src_dir = root.join("lib/builtins"); - if target.arch == "aarch64" && target.env != "msvc" && target.os != "uefi" { - // See below for why we're building these as separate libraries. - build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); - - // Some run-time CPU feature detection is necessary, as well. - let cpu_model_src = if src_dir.join("cpu_model.c").exists() { - "cpu_model.c" - } else { - "cpu_model/aarch64.c" - }; - sources.extend(&[("__aarch64_have_lse_atomics", cpu_model_src)]); - } - - let mut added_sources = HashSet::new(); - for (sym, src) in sources.map.iter() { - let src = src_dir.join(src); - if added_sources.insert(src.clone()) { - cfg.file(&src); - println!("cargo:rerun-if-changed={}", src.display()); - } - println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); - } - - cfg.compile("libcompiler-rt.a"); - } - - fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &mut cc::Build) { - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let outlined_atomics_file = builtins_dir.join("aarch64").join("lse.S"); - println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); - - cfg.include(&builtins_dir); - - for instruction_type in &["cas", "swp", "ldadd", "ldclr", "ldeor", "ldset"] { - for size in &[1, 2, 4, 8, 16] { - if *size == 16 && *instruction_type != "cas" { - continue; - } - - for (model_number, model_name) in - &[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")] - { - // The original compiler-rt build system compiles the same - // source file multiple times with different compiler - // options. Here we do something slightly different: we - // create multiple .S files with the proper #defines and - // then include the original file. - // - // This is needed because the cc crate doesn't allow us to - // override the name of object files and libtool requires - // all objects in an archive to have unique names. - let path = - out_dir.join(format!("lse_{}{}_{}.S", instruction_type, size, model_name)); - let mut file = File::create(&path).unwrap(); - writeln!(file, "#define L_{}", instruction_type).unwrap(); - writeln!(file, "#define SIZE {}", size).unwrap(); - writeln!(file, "#define MODEL {}", model_number).unwrap(); - writeln!( - file, - "#include \"{}\"", - outlined_atomics_file.canonicalize().unwrap().display() - ) - .unwrap(); - drop(file); - cfg.file(path); - - let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); - println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); - } - } - } - } -} diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 9b2e5bb7c8a..9dbd3c32f96 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -compiler_builtins = { path = "../", features = ["compiler-builtins"]} +compiler_builtins = { path = "../compiler-builtins", features = ["compiler-builtins"]} panic-handler = { path = '../crates/panic-handler' } [features] diff --git a/library/compiler-builtins/builtins-test-intrinsics/build.rs b/library/compiler-builtins/builtins-test-intrinsics/build.rs index a38c6c1ff71..89b126ff2b2 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/build.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/build.rs @@ -1,5 +1,5 @@ mod builtins_configure { - include!("../configure.rs"); + include!("../compiler-builtins/configure.rs"); } fn main() { diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 215ad71a3c1..5e19cf4d0cb 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -38,7 +38,7 @@ run() { fi if [ -d compiler-rt ]; then - export RUST_COMPILER_RT_ROOT=./compiler-rt + export RUST_COMPILER_RT_ROOT="/checkout/compiler-rt" fi if [ "${GITHUB_ACTIONS:-}" = "true" ]; then diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 3625dde79ed..9abbf25a7e7 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -23,7 +23,7 @@ fi if [ "${NO_STD:-}" = "1" ]; then echo "nothing to do for no_std" else - run="cargo test --manifest-path testcrate/Cargo.toml --no-fail-fast --target $target" + run="cargo test --package testcrate --no-fail-fast --target $target" $run $run --release $run --features c @@ -38,7 +38,7 @@ fi if [ "${TEST_VERBATIM:-}" = "1" ]; then verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\testcrate\\target2) - cargo build --manifest-path testcrate/Cargo.toml \ + cargo build --package testcrate \ --target "$target" --target-dir "$verb_path" --features c fi diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml new file mode 100644 index 00000000000..9797b5e65b5 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -0,0 +1,72 @@ +[package] +authors = ["Jorge Aparicio "] +name = "compiler_builtins" +version = "0.1.151" +license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" +readme = "../README.md" +repository = "https://github.com/rust-lang/compiler-builtins" +homepage = "https://github.com/rust-lang/compiler-builtins" +documentation = "https://docs.rs/compiler_builtins" +edition = "2021" +description = """ +Compiler intrinsics used by the Rust compiler. Also available for other targets +if necessary! +""" +include = [ + '/Cargo.toml', + '/build.rs', + '/configure.rs', + '/src/*', + '../LICENSE.txt', + '../README.md', + '../compiler-rt/*', + 'libm/src/math/*', +] +links = 'compiler-rt' + +[lib] +test = false +bench = false + +[dependencies] +# For more information on this dependency see +# https://github.com/rust-lang/rust/tree/master/library/rustc-std-workspace-core +core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } + +[build-dependencies] +cc = { optional = true, version = "1.0" } + +[dev-dependencies] +panic-handler = { path = '../crates/panic-handler' } + +[features] +default = ["compiler-builtins"] + +# Enable compilation of C code in compiler-rt, filling in some more optimized +# implementations and also filling in unimplemented intrinsics +c = ["cc"] + +# Workaround for the Cranelift codegen backend. Disables any implementations +# which use inline assembly and fall back to pure Rust versions (if avalible). +no-asm = [] + +# Workaround for codegen backends which haven't yet implemented `f16` and +# `f128` support. Disabled any intrinsics which use those types. +no-f16-f128 = [] + +# Flag this library as the unstable compiler-builtins lib +compiler-builtins = [] + +# Generate memory-related intrinsics like memcpy +mem = [] + +# Mangle all names so this can be linked in with other versions or other +# compiler-rt implementations. Also used for testing +mangled-names = [] + +# Only used in the compiler's build system +rustc-dep-of-std = ['compiler-builtins', 'core'] + +# This makes certain traits and function specializations public that +# are not normally public but are required by the `testcrate` +public-test-deps = [] diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs new file mode 100644 index 00000000000..fdfb61b17df --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -0,0 +1,714 @@ +mod configure; + +use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering}; + +use configure::{configure_aliases, configure_f16_f128, Target}; + +fn main() { + println!("cargo::rerun-if-changed=build.rs"); + println!("cargo::rerun-if-changed=configure.rs"); + + let target = Target::from_env(); + let cwd = env::current_dir().unwrap(); + + configure_check_cfg(); + configure_f16_f128(&target); + configure_aliases(&target); + + configure_libm(&target); + + println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); + + // Emscripten's runtime includes all the builtins + if target.os == "emscripten" { + return; + } + + // OpenBSD provides compiler_rt by default, use it instead of rebuilding it from source + if target.os == "openbsd" { + println!("cargo:rustc-link-search=native=/usr/lib"); + println!("cargo:rustc-link-lib=compiler_rt"); + return; + } + + // Forcibly enable memory intrinsics on wasm & SGX as we don't have a libc to + // provide them. + if (target.triple.contains("wasm") && !target.triple.contains("wasi")) + || (target.triple.contains("sgx") && target.triple.contains("fortanix")) + || target.triple.contains("-none") + || target.triple.contains("nvptx") + || target.triple.contains("uefi") + || target.triple.contains("xous") + { + println!("cargo:rustc-cfg=feature=\"mem\""); + } + + // These targets have hardware unaligned access support. + println!("cargo::rustc-check-cfg=cfg(feature, values(\"mem-unaligned\"))"); + if target.arch.contains("x86_64") + || target.arch.contains("x86") + || target.arch.contains("aarch64") + || target.arch.contains("bpf") + { + println!("cargo:rustc-cfg=feature=\"mem-unaligned\""); + } + + // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the + // target triple. This is usually correct for our built-in targets but can break in presence of + // custom targets, which can have arbitrary names. + let llvm_target = target.triple.split('-').collect::>(); + + // Build missing intrinsics from compiler-rt C source code. If we're + // mangling names though we assume that we're also in test mode so we don't + // build anything and we rely on the upstream implementation of compiler-rt + // functions + if !cfg!(feature = "mangled-names") && cfg!(feature = "c") { + // Don't use a C compiler for these targets: + // + // * nvptx - everything is bitcode, not compatible with mixed C/Rust + if !target.arch.contains("nvptx") { + #[cfg(feature = "c")] + c::compile(&llvm_target, &target); + } + } + + // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. This + // includes the old androideabi. It is deprecated but it is available as a + // rustc target (arm-linux-androideabi). + println!("cargo::rustc-check-cfg=cfg(kernel_user_helpers)"); + if llvm_target[0] == "armv4t" + || llvm_target[0] == "armv5te" + || target.triple == "arm-linux-androideabi" + { + println!("cargo:rustc-cfg=kernel_user_helpers") + } + + if llvm_target[0].starts_with("aarch64") { + generate_aarch64_outlined_atomics(); + } +} + +/// Run configuration for `libm` since it is included directly. +/// +/// Much of this is copied from `libm/configure.rs`. +fn configure_libm(target: &Target) { + println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)"); + println!("cargo:rustc-check-cfg=cfg(arch_enabled)"); + println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); + println!("cargo:rustc-check-cfg=cfg(feature, values(\"unstable-public-internals\"))"); + + // Always use intrinsics + println!("cargo:rustc-cfg=intrinsics_enabled"); + + // The arch module may contain assembly. + if cfg!(feature = "no-asm") { + println!("cargo:rustc-cfg=feature=\"force-soft-floats\""); + } else { + println!("cargo:rustc-cfg=arch_enabled"); + } + + println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); + if !matches!(target.opt_level.as_str(), "0" | "1") { + println!("cargo:rustc-cfg=optimizations_enabled"); + } + + // Config shorthands + println!("cargo:rustc-check-cfg=cfg(x86_no_sse)"); + if target.arch == "x86" && !target.features.iter().any(|f| f == "sse") { + // Shorthand to detect i586 targets + println!("cargo:rustc-cfg=x86_no_sse"); + } + + println!( + "cargo:rustc-env=CFG_CARGO_FEATURES={:?}", + target.cargo_features + ); + println!("cargo:rustc-env=CFG_OPT_LEVEL={}", target.opt_level); + println!("cargo:rustc-env=CFG_TARGET_FEATURES={:?}", target.features); + + // Activate libm's unstable features to make full use of Nightly. + println!("cargo:rustc-cfg=feature=\"unstable-intrinsics\""); +} + +fn aarch64_symbol(ordering: Ordering) -> &'static str { + match ordering { + Ordering::Relaxed => "relax", + Ordering::Acquire => "acq", + Ordering::Release => "rel", + Ordering::AcqRel => "acq_rel", + _ => panic!("unknown symbol for {:?}", ordering), + } +} + +/// The `concat_idents` macro is extremely annoying and doesn't allow us to define new items. +/// Define them from the build script instead. +/// Note that the majority of the code is still defined in `aarch64.rs` through inline macros. +fn generate_aarch64_outlined_atomics() { + use std::fmt::Write; + // #[macro_export] so that we can use this in tests + let gen_macro = + |name| format!("#[macro_export] macro_rules! foreach_{name} {{ ($macro:path) => {{\n"); + + // Generate different macros for add/clr/eor/set so that we can test them separately. + let sym_names = ["cas", "ldadd", "ldclr", "ldeor", "ldset", "swp"]; + let mut macros = BTreeMap::new(); + for sym in sym_names { + macros.insert(sym, gen_macro(sym)); + } + + // Only CAS supports 16 bytes, and it has a different implementation that uses a different macro. + let mut cas16 = gen_macro("cas16"); + + for ordering in [ + Ordering::Relaxed, + Ordering::Acquire, + Ordering::Release, + Ordering::AcqRel, + ] { + let sym_ordering = aarch64_symbol(ordering); + for size in [1, 2, 4, 8] { + for (sym, macro_) in &mut macros { + let name = format!("__aarch64_{sym}{size}_{sym_ordering}"); + writeln!(macro_, "$macro!( {ordering:?}, {size}, {name} );").unwrap(); + } + } + let name = format!("__aarch64_cas16_{sym_ordering}"); + writeln!(cas16, "$macro!( {ordering:?}, {name} );").unwrap(); + } + + let mut buf = String::new(); + for macro_def in macros.values().chain(std::iter::once(&cas16)) { + buf += macro_def; + buf += "}; }\n"; + } + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); + std::fs::write(out_dir.join("outlined_atomics.rs"), buf).unwrap(); +} + +/// Emit directives for features we expect to support that aren't in `Cargo.toml`. +/// +/// These are mostly cfg elements emitted by this `build.rs`. +fn configure_check_cfg() { + // Functions where we can set the "optimized-c" flag + const HAS_OPTIMIZED_C: &[&str] = &[ + "__ashldi3", + "__ashlsi3", + "__ashrdi3", + "__ashrsi3", + "__bswapsi2", + "__bswapdi2", + "__bswapti2", + "__divdi3", + "__divsi3", + "__divmoddi4", + "__divmodsi4", + "__divmodsi4", + "__divmodti4", + "__lshrdi3", + "__lshrsi3", + "__moddi3", + "__modsi3", + "__muldi3", + "__udivdi3", + "__udivmoddi4", + "__udivmodsi4", + "__udivsi3", + "__umoddi3", + "__umodsi3", + ]; + + // Build a list of all aarch64 atomic operation functions + let mut aarch_atomic = Vec::new(); + for aarch_op in ["cas", "ldadd", "ldclr", "ldeor", "ldset", "swp"] { + let op_sizes = if aarch_op == "cas" { + [1, 2, 4, 8, 16].as_slice() + } else { + [1, 2, 4, 8].as_slice() + }; + + for op_size in op_sizes { + for ordering in ["relax", "acq", "rel", "acq_rel"] { + aarch_atomic.push(format!("__aarch64_{}{}_{}", aarch_op, op_size, ordering)); + } + } + } + + for fn_name in HAS_OPTIMIZED_C + .iter() + .copied() + .chain(aarch_atomic.iter().map(|s| s.as_str())) + { + println!( + "cargo::rustc-check-cfg=cfg({}, values(\"optimized-c\"))", + fn_name + ); + } + + // Rustc is unaware of sparc target features, but this does show up from + // `rustc --print target-features --target sparc64-unknown-linux-gnu`. + println!("cargo::rustc-check-cfg=cfg(target_feature, values(\"vis3\"))"); + + // FIXME: these come from libm and should be changed there + println!("cargo::rustc-check-cfg=cfg(feature, values(\"checked\"))"); + println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); +} + +#[cfg(feature = "c")] +mod c { + use std::collections::{BTreeMap, HashSet}; + use std::env; + use std::fs::{self, File}; + use std::io::Write; + use std::path::{Path, PathBuf}; + + use super::Target; + + struct Sources { + // SYMBOL -> PATH TO SOURCE + map: BTreeMap<&'static str, &'static str>, + } + + impl Sources { + fn new() -> Sources { + Sources { + map: BTreeMap::new(), + } + } + + fn extend(&mut self, sources: &[(&'static str, &'static str)]) { + // NOTE Some intrinsics have both a generic implementation (e.g. + // `floatdidf.c`) and an arch optimized implementation + // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized + // implementation and discard the generic implementation. If we don't + // and keep both implementations, the linker will yell at us about + // duplicate symbols! + for (symbol, src) in sources { + if src.contains("/") { + // Arch-optimized implementation (preferred) + self.map.insert(symbol, src); + } else { + // Generic implementation + if !self.map.contains_key(symbol) { + self.map.insert(symbol, src); + } + } + } + } + + fn remove(&mut self, symbols: &[&str]) { + for symbol in symbols { + self.map.remove(*symbol).unwrap(); + } + } + } + + /// Compile intrinsics from the compiler-rt C source code + pub fn compile(llvm_target: &[&str], target: &Target) { + let mut consider_float_intrinsics = true; + let cfg = &mut cc::Build::new(); + + // AArch64 GCCs exit with an error condition when they encounter any kind of floating point + // code if the `nofp` and/or `nosimd` compiler flags have been set. + // + // Therefore, evaluate if those flags are present and set a boolean that causes any + // compiler-rt intrinsics that contain floating point source to be excluded for this target. + if target.arch == "aarch64" { + let cflags_key = String::from("CFLAGS_") + &(target.triple.replace("-", "_")); + if let Ok(cflags_value) = env::var(cflags_key) { + if cflags_value.contains("+nofp") || cflags_value.contains("+nosimd") { + consider_float_intrinsics = false; + } + } + } + + // `compiler-rt` requires `COMPILER_RT_HAS_FLOAT16` to be defined to make it use the + // `_Float16` type for `f16` intrinsics. This shouldn't matter as all existing `f16` + // intrinsics have been ported to Rust in `compiler-builtins` as C compilers don't + // support `_Float16` on all targets (whereas Rust does). However, define the macro + // anyway to prevent issues like rust#118813 and rust#123885 silently reoccuring if more + // `f16` intrinsics get accidentally added here in the future. + cfg.define("COMPILER_RT_HAS_FLOAT16", None); + + cfg.warnings(false); + + if target.env == "msvc" { + // Don't pull in extra libraries on MSVC + cfg.flag("/Zl"); + + // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP + cfg.define("__func__", Some("__FUNCTION__")); + } else { + // Turn off various features of gcc and such, mostly copying + // compiler-rt's build system already + cfg.flag("-fno-builtin"); + cfg.flag("-fvisibility=hidden"); + cfg.flag("-ffreestanding"); + // Avoid the following warning appearing once **per file**: + // clang: warning: optimization flag '-fomit-frame-pointer' is not supported for target 'armv7' [-Wignored-optimization-argument] + // + // Note that compiler-rt's build system also checks + // + // `check_cxx_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG)` + // + // in https://github.com/rust-lang/compiler-rt/blob/c8fbcb3/cmake/config-ix.cmake#L19. + cfg.flag_if_supported("-fomit-frame-pointer"); + cfg.define("VISIBILITY_HIDDEN", None); + + if let "aarch64" | "arm64ec" = target.arch.as_str() { + // FIXME(llvm20): Older GCCs on A64 fail to build with + // -Werror=implicit-function-declaration due to a compiler-rt bug. + // With a newer LLVM we should be able to enable the flag everywhere. + // https://github.com/llvm/llvm-project/commit/8aa9d6206ce55bdaaf422839c351fbd63f033b89 + } else { + // Avoid implicitly creating references to undefined functions + cfg.flag("-Werror=implicit-function-declaration"); + } + } + + // int_util.c tries to include stdlib.h if `_WIN32` is defined, + // which it is when compiling UEFI targets with clang. This is + // at odds with compiling with `-ffreestanding`, as the header + // may be incompatible or not present. Create a minimal stub + // header to use instead. + if target.os == "uefi" { + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let include_dir = out_dir.join("include"); + if !include_dir.exists() { + fs::create_dir(&include_dir).unwrap(); + } + fs::write(include_dir.join("stdlib.h"), "#include ").unwrap(); + cfg.flag(&format!("-I{}", include_dir.to_str().unwrap())); + } + + let mut sources = Sources::new(); + sources.extend(&[ + ("__absvdi2", "absvdi2.c"), + ("__absvsi2", "absvsi2.c"), + ("__addvdi3", "addvdi3.c"), + ("__addvsi3", "addvsi3.c"), + ("__cmpdi2", "cmpdi2.c"), + ("__int_util", "int_util.c"), + ("__mulvdi3", "mulvdi3.c"), + ("__mulvsi3", "mulvsi3.c"), + ("__negdi2", "negdi2.c"), + ("__negvdi2", "negvdi2.c"), + ("__negvsi2", "negvsi2.c"), + ("__paritydi2", "paritydi2.c"), + ("__paritysi2", "paritysi2.c"), + ("__popcountdi2", "popcountdi2.c"), + ("__popcountsi2", "popcountsi2.c"), + ("__subvdi3", "subvdi3.c"), + ("__subvsi3", "subvsi3.c"), + ("__ucmpdi2", "ucmpdi2.c"), + ]); + + if consider_float_intrinsics { + sources.extend(&[ + ("__divdc3", "divdc3.c"), + ("__divsc3", "divsc3.c"), + ("__muldc3", "muldc3.c"), + ("__mulsc3", "mulsc3.c"), + ("__negdf2", "negdf2.c"), + ("__negsf2", "negsf2.c"), + ]); + } + + // On iOS and 32-bit OSX these are all just empty intrinsics, no need to + // include them. + if target.vendor != "apple" || target.arch != "x86" { + sources.extend(&[ + ("__absvti2", "absvti2.c"), + ("__addvti3", "addvti3.c"), + ("__cmpti2", "cmpti2.c"), + ("__ffsti2", "ffsti2.c"), + ("__mulvti3", "mulvti3.c"), + ("__negti2", "negti2.c"), + ("__parityti2", "parityti2.c"), + ("__popcountti2", "popcountti2.c"), + ("__subvti3", "subvti3.c"), + ("__ucmpti2", "ucmpti2.c"), + ]); + + if consider_float_intrinsics { + sources.extend(&[("__negvti2", "negvti2.c")]); + } + } + + if target.vendor == "apple" { + sources.extend(&[ + ("atomic_flag_clear", "atomic_flag_clear.c"), + ("atomic_flag_clear_explicit", "atomic_flag_clear_explicit.c"), + ("atomic_flag_test_and_set", "atomic_flag_test_and_set.c"), + ( + "atomic_flag_test_and_set_explicit", + "atomic_flag_test_and_set_explicit.c", + ), + ("atomic_signal_fence", "atomic_signal_fence.c"), + ("atomic_thread_fence", "atomic_thread_fence.c"), + ]); + } + + if target.env != "msvc" { + if target.arch == "x86" { + sources.extend(&[ + ("__ashldi3", "i386/ashldi3.S"), + ("__ashrdi3", "i386/ashrdi3.S"), + ("__divdi3", "i386/divdi3.S"), + ("__lshrdi3", "i386/lshrdi3.S"), + ("__moddi3", "i386/moddi3.S"), + ("__muldi3", "i386/muldi3.S"), + ("__udivdi3", "i386/udivdi3.S"), + ("__umoddi3", "i386/umoddi3.S"), + ]); + } + } + + if target.arch == "arm" && target.vendor != "apple" && target.env != "msvc" { + sources.extend(&[ + ("__aeabi_div0", "arm/aeabi_div0.c"), + ("__aeabi_drsub", "arm/aeabi_drsub.c"), + ("__aeabi_frsub", "arm/aeabi_frsub.c"), + ("__bswapdi2", "arm/bswapdi2.S"), + ("__bswapsi2", "arm/bswapsi2.S"), + ("__divmodsi4", "arm/divmodsi4.S"), + ("__divsi3", "arm/divsi3.S"), + ("__modsi3", "arm/modsi3.S"), + ("__switch16", "arm/switch16.S"), + ("__switch32", "arm/switch32.S"), + ("__switch8", "arm/switch8.S"), + ("__switchu8", "arm/switchu8.S"), + ("__sync_synchronize", "arm/sync_synchronize.S"), + ("__udivmodsi4", "arm/udivmodsi4.S"), + ("__udivsi3", "arm/udivsi3.S"), + ("__umodsi3", "arm/umodsi3.S"), + ]); + + if target.os == "freebsd" { + sources.extend(&[("__clear_cache", "clear_cache.c")]); + } + + // First of all aeabi_cdcmp and aeabi_cfcmp are never called by LLVM. + // Second are little-endian only, so build fail on big-endian targets. + // Temporally workaround: exclude these files for big-endian targets. + if !llvm_target[0].starts_with("thumbeb") && !llvm_target[0].starts_with("armeb") { + sources.extend(&[ + ("__aeabi_cdcmp", "arm/aeabi_cdcmp.S"), + ("__aeabi_cdcmpeq_check_nan", "arm/aeabi_cdcmpeq_check_nan.c"), + ("__aeabi_cfcmp", "arm/aeabi_cfcmp.S"), + ("__aeabi_cfcmpeq_check_nan", "arm/aeabi_cfcmpeq_check_nan.c"), + ]); + } + } + + if llvm_target[0] == "armv7" { + sources.extend(&[ + ("__sync_fetch_and_add_4", "arm/sync_fetch_and_add_4.S"), + ("__sync_fetch_and_add_8", "arm/sync_fetch_and_add_8.S"), + ("__sync_fetch_and_and_4", "arm/sync_fetch_and_and_4.S"), + ("__sync_fetch_and_and_8", "arm/sync_fetch_and_and_8.S"), + ("__sync_fetch_and_max_4", "arm/sync_fetch_and_max_4.S"), + ("__sync_fetch_and_max_8", "arm/sync_fetch_and_max_8.S"), + ("__sync_fetch_and_min_4", "arm/sync_fetch_and_min_4.S"), + ("__sync_fetch_and_min_8", "arm/sync_fetch_and_min_8.S"), + ("__sync_fetch_and_nand_4", "arm/sync_fetch_and_nand_4.S"), + ("__sync_fetch_and_nand_8", "arm/sync_fetch_and_nand_8.S"), + ("__sync_fetch_and_or_4", "arm/sync_fetch_and_or_4.S"), + ("__sync_fetch_and_or_8", "arm/sync_fetch_and_or_8.S"), + ("__sync_fetch_and_sub_4", "arm/sync_fetch_and_sub_4.S"), + ("__sync_fetch_and_sub_8", "arm/sync_fetch_and_sub_8.S"), + ("__sync_fetch_and_umax_4", "arm/sync_fetch_and_umax_4.S"), + ("__sync_fetch_and_umax_8", "arm/sync_fetch_and_umax_8.S"), + ("__sync_fetch_and_umin_4", "arm/sync_fetch_and_umin_4.S"), + ("__sync_fetch_and_umin_8", "arm/sync_fetch_and_umin_8.S"), + ("__sync_fetch_and_xor_4", "arm/sync_fetch_and_xor_4.S"), + ("__sync_fetch_and_xor_8", "arm/sync_fetch_and_xor_8.S"), + ]); + } + + if llvm_target.last().unwrap().ends_with("eabihf") { + if !llvm_target[0].starts_with("thumbv7em") + && !llvm_target[0].starts_with("thumbv8m.main") + { + // The FPU option chosen for these architectures in cc-rs, ie: + // -mfpu=fpv4-sp-d16 for thumbv7em + // -mfpu=fpv5-sp-d16 for thumbv8m.main + // do not support double precision floating points conversions so the files + // that include such instructions are not included for these targets. + sources.extend(&[ + ("__fixdfsivfp", "arm/fixdfsivfp.S"), + ("__fixunsdfsivfp", "arm/fixunsdfsivfp.S"), + ("__floatsidfvfp", "arm/floatsidfvfp.S"), + ("__floatunssidfvfp", "arm/floatunssidfvfp.S"), + ]); + } + + sources.extend(&[ + ("__fixsfsivfp", "arm/fixsfsivfp.S"), + ("__fixunssfsivfp", "arm/fixunssfsivfp.S"), + ("__floatsisfvfp", "arm/floatsisfvfp.S"), + ("__floatunssisfvfp", "arm/floatunssisfvfp.S"), + ("__floatunssisfvfp", "arm/floatunssisfvfp.S"), + ("__restore_vfp_d8_d15_regs", "arm/restore_vfp_d8_d15_regs.S"), + ("__save_vfp_d8_d15_regs", "arm/save_vfp_d8_d15_regs.S"), + ("__negdf2vfp", "arm/negdf2vfp.S"), + ("__negsf2vfp", "arm/negsf2vfp.S"), + ]); + } + + if (target.arch == "aarch64" || target.arch == "arm64ec") && consider_float_intrinsics { + sources.extend(&[ + ("__comparetf2", "comparetf2.c"), + ("__fe_getround", "fp_mode.c"), + ("__fe_raise_inexact", "fp_mode.c"), + ]); + + if target.os != "windows" && target.os != "cygwin" { + sources.extend(&[("__multc3", "multc3.c")]); + } + } + + if target.arch == "mips" || target.arch == "riscv32" || target.arch == "riscv64" { + sources.extend(&[("__bswapsi2", "bswapsi2.c")]); + } + + if target.arch == "mips64" { + sources.extend(&[("__netf2", "comparetf2.c"), ("__fe_getround", "fp_mode.c")]); + } + + if target.arch == "loongarch64" { + sources.extend(&[("__netf2", "comparetf2.c"), ("__fe_getround", "fp_mode.c")]); + } + + // Remove the assembly implementations that won't compile for the target + if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" || target.os == "uefi" + { + let mut to_remove = Vec::new(); + for (k, v) in sources.map.iter() { + if v.ends_with(".S") { + to_remove.push(*k); + } + } + sources.remove(&to_remove); + } + + if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { + sources.remove(&["__aeabi_cdcmp", "__aeabi_cfcmp"]); + } + + // Android and Cygwin uses emulated TLS so we need a runtime support function. + if target.os == "android" || target.os == "cygwin" { + sources.extend(&[("__emutls_get_address", "emutls.c")]); + } + + // Work around a bug in the NDK headers (fixed in + // https://r.android.com/2038949 which will be released in a future + // NDK version) by providing a definition of LONG_BIT. + if target.os == "android" { + cfg.define("LONG_BIT", "(8 * sizeof(long))"); + } + + // OpenHarmony also uses emulated TLS. + if target.env == "ohos" { + sources.extend(&[("__emutls_get_address", "emutls.c")]); + } + + // When compiling the C code we require the user to tell us where the + // source code is, and this is largely done so when we're compiling as + // part of rust-lang/rust we can use the same llvm-project repository as + // rust-lang/rust. + let root = match env::var_os("RUST_COMPILER_RT_ROOT") { + Some(s) => PathBuf::from(s), + None => { + panic!( + "RUST_COMPILER_RT_ROOT is not set. You may need to run \ + `ci/download-compiler-rt.sh`." + ); + } + }; + if !root.exists() { + panic!("RUST_COMPILER_RT_ROOT={} does not exist", root.display()); + } + + // Support deterministic builds by remapping the __FILE__ prefix if the + // compiler supports it. This fixes the nondeterminism caused by the + // use of that macro in lib/builtins/int_util.h in compiler-rt. + cfg.flag_if_supported(&format!("-ffile-prefix-map={}=.", root.display())); + + // Include out-of-line atomics for aarch64, which are all generated by supplying different + // sets of flags to the same source file. + // Note: Out-of-line aarch64 atomics are not supported by the msvc toolchain (#430) and + // on uefi. + let src_dir = root.join("lib/builtins"); + if target.arch == "aarch64" && target.env != "msvc" && target.os != "uefi" { + // See below for why we're building these as separate libraries. + build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); + + // Some run-time CPU feature detection is necessary, as well. + let cpu_model_src = if src_dir.join("cpu_model.c").exists() { + "cpu_model.c" + } else { + "cpu_model/aarch64.c" + }; + sources.extend(&[("__aarch64_have_lse_atomics", cpu_model_src)]); + } + + let mut added_sources = HashSet::new(); + for (sym, src) in sources.map.iter() { + let src = src_dir.join(src); + if added_sources.insert(src.clone()) { + cfg.file(&src); + println!("cargo:rerun-if-changed={}", src.display()); + } + println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); + } + + cfg.compile("libcompiler-rt.a"); + } + + fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &mut cc::Build) { + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let outlined_atomics_file = builtins_dir.join("aarch64").join("lse.S"); + println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); + + cfg.include(&builtins_dir); + + for instruction_type in &["cas", "swp", "ldadd", "ldclr", "ldeor", "ldset"] { + for size in &[1, 2, 4, 8, 16] { + if *size == 16 && *instruction_type != "cas" { + continue; + } + + for (model_number, model_name) in + &[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")] + { + // The original compiler-rt build system compiles the same + // source file multiple times with different compiler + // options. Here we do something slightly different: we + // create multiple .S files with the proper #defines and + // then include the original file. + // + // This is needed because the cc crate doesn't allow us to + // override the name of object files and libtool requires + // all objects in an archive to have unique names. + let path = + out_dir.join(format!("lse_{}{}_{}.S", instruction_type, size, model_name)); + let mut file = File::create(&path).unwrap(); + writeln!(file, "#define L_{}", instruction_type).unwrap(); + writeln!(file, "#define SIZE {}", size).unwrap(); + writeln!(file, "#define MODEL {}", model_number).unwrap(); + writeln!( + file, + "#include \"{}\"", + outlined_atomics_file.canonicalize().unwrap().display() + ) + .unwrap(); + drop(file); + cfg.file(path); + + let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); + println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); + } + } + } + } +} diff --git a/library/compiler-builtins/compiler-builtins/configure.rs b/library/compiler-builtins/compiler-builtins/configure.rs new file mode 100644 index 00000000000..2f134e57818 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/configure.rs @@ -0,0 +1,138 @@ +// Configuration that is shared between `compiler_builtins` and `testcrate`. + +use std::env; + +#[derive(Debug)] +#[allow(dead_code)] +pub struct Target { + pub triple: String, + pub triple_split: Vec, + pub opt_level: String, + pub cargo_features: Vec, + pub os: String, + pub arch: String, + pub vendor: String, + pub env: String, + pub pointer_width: u8, + pub little_endian: bool, + pub features: Vec, +} + +impl Target { + pub fn from_env() -> Self { + let triple = env::var("TARGET").unwrap(); + let triple_split = triple.split('-').map(ToOwned::to_owned).collect(); + let little_endian = match env::var("CARGO_CFG_TARGET_ENDIAN").unwrap().as_str() { + "little" => true, + "big" => false, + x => panic!("unknown endian {x}"), + }; + let cargo_features = env::vars() + .filter_map(|(name, _value)| name.strip_prefix("CARGO_FEATURE_").map(ToOwned::to_owned)) + .map(|s| s.to_lowercase().replace("_", "-")) + .collect(); + + Self { + triple, + triple_split, + os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + opt_level: env::var("OPT_LEVEL").unwrap(), + cargo_features, + arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), + vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), + env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), + pointer_width: env::var("CARGO_CFG_TARGET_POINTER_WIDTH") + .unwrap() + .parse() + .unwrap(), + little_endian, + features: env::var("CARGO_CFG_TARGET_FEATURE") + .unwrap_or_default() + .split(",") + .map(ToOwned::to_owned) + .collect(), + } + } + + #[allow(dead_code)] + pub fn has_feature(&self, feature: &str) -> bool { + self.features.iter().any(|f| f == feature) + } +} + +pub fn configure_aliases(target: &Target) { + // To compile builtins-test-intrinsics for thumb targets, where there is no libc + println!("cargo::rustc-check-cfg=cfg(thumb)"); + if target.triple_split[0].starts_with("thumb") { + println!("cargo:rustc-cfg=thumb") + } + + // compiler-rt `cfg`s away some intrinsics for thumbv6m and thumbv8m.base because + // these targets do not have full Thumb-2 support but only original Thumb-1. + // We have to cfg our code accordingly. + println!("cargo::rustc-check-cfg=cfg(thumb_1)"); + if target.triple_split[0] == "thumbv6m" || target.triple_split[0] == "thumbv8m.base" { + println!("cargo:rustc-cfg=thumb_1") + } +} + +/// Configure whether or not `f16` and `f128` support should be enabled. +pub fn configure_f16_f128(target: &Target) { + // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means + // that the backend will not crash when using these types and generates code that can be called + // without crashing (no infinite recursion). This does not mean that the platform doesn't have + // ABI or other bugs. + // + // We do this here rather than in `rust-lang/rust` because configuring via cargo features is + // not straightforward. + // + // Original source of this list: + // + let f16_enabled = match target.arch.as_str() { + // Unsupported + "arm64ec" => false, + // Crash in LLVM20 + "aarch64" if !target.features.iter().any(|f| f == "neon") => false, + // Selection failure + "s390x" => false, + // Infinite recursion + "csky" => false, + "hexagon" => false, + "powerpc" | "powerpc64" => false, + "sparc" | "sparc64" => false, + "wasm32" | "wasm64" => false, + // Most everything else works as of LLVM 19 + _ => true, + }; + + let f128_enabled = match target.arch.as_str() { + // Unsupported (libcall is not supported) + "amdgpu" => false, + // Unsupported + "arm64ec" => false, + // FIXME(llvm20): fixed by + "mips64" | "mips64r6" => false, + // Selection failure + "nvptx64" => false, + // Selection failure + "powerpc64" if &target.os == "aix" => false, + // Selection failure + "sparc" => false, + // Most everything else works as of LLVM 19 + _ => true, + }; + + // If the feature is set, disable these types. + let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); + + println!("cargo::rustc-check-cfg=cfg(f16_enabled)"); + println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); + + if f16_enabled && !disable_both { + println!("cargo::rustc-cfg=f16_enabled"); + } + + if f128_enabled && !disable_both { + println!("cargo::rustc-cfg=f128_enabled"); + } +} diff --git a/library/compiler-builtins/compiler-builtins/libm b/library/compiler-builtins/compiler-builtins/libm new file mode 160000 index 00000000000..69219c491ee --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/libm @@ -0,0 +1 @@ +Subproject commit 69219c491ee9f05761d2068fd6d4c7c0de6faa3a diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/compiler-builtins/src/aarch64.rs new file mode 100644 index 00000000000..cce485c4682 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/aarch64.rs @@ -0,0 +1,21 @@ +#![allow(unused_imports)] + +use core::intrinsics; + +intrinsics! { + #[naked] + #[cfg(all(target_os = "uefi", not(feature = "no-asm")))] + pub unsafe extern "C" fn __chkstk() { + core::arch::naked_asm!( + ".p2align 2", + "lsl x16, x15, #4", + "mov x17, sp", + "1:", + "sub x17, x17, 4096", + "subs x16, x16, 4096", + "ldr xzr, [x17]", + "b.gt 1b", + "ret", + ); + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs b/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs new file mode 100644 index 00000000000..caac3e6025d --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs @@ -0,0 +1,273 @@ +//! Aarch64 targets have two possible implementations for atomics: +//! 1. Load-Locked, Store-Conditional (LL/SC), older and slower. +//! 2. Large System Extensions (LSE), newer and faster. +//! To avoid breaking backwards compat, C toolchains introduced a concept of "outlined atomics", +//! where atomic operations call into the compiler runtime to dispatch between two depending on +//! which is supported on the current CPU. +//! See https://community.arm.com/arm-community-blogs/b/tools-software-ides-blog/posts/making-the-most-of-the-arm-architecture-in-gcc-10#:~:text=out%20of%20line%20atomics for more discussion. +//! +//! Currently we only support LL/SC, because LSE requires `getauxval` from libc in order to do runtime detection. +//! Use the `compiler-rt` intrinsics if you want LSE support. +//! +//! Ported from `aarch64/lse.S` in LLVM's compiler-rt. +//! +//! Generate functions for each of the following symbols: +//! __aarch64_casM_ORDER +//! __aarch64_swpN_ORDER +//! __aarch64_ldaddN_ORDER +//! __aarch64_ldclrN_ORDER +//! __aarch64_ldeorN_ORDER +//! __aarch64_ldsetN_ORDER +//! for N = {1, 2, 4, 8}, M = {1, 2, 4, 8, 16}, ORDER = { relax, acq, rel, acq_rel } +//! +//! The original `lse.S` has some truly horrifying code that expects to be compiled multiple times with different constants. +//! We do something similar, but with macro arguments. +#![cfg_attr(feature = "c", allow(unused_macros))] // avoid putting the macros into a submodule + +// We don't do runtime dispatch so we don't have to worry about the `__aarch64_have_lse_atomics` global ctor. + +/// Translate a byte size to a Rust type. +#[rustfmt::skip] +macro_rules! int_ty { + (1) => { i8 }; + (2) => { i16 }; + (4) => { i32 }; + (8) => { i64 }; + (16) => { i128 }; +} + +/// Given a byte size and a register number, return a register of the appropriate size. +/// +/// See . +#[rustfmt::skip] +macro_rules! reg { + (1, $num:literal) => { concat!("w", $num) }; + (2, $num:literal) => { concat!("w", $num) }; + (4, $num:literal) => { concat!("w", $num) }; + (8, $num:literal) => { concat!("x", $num) }; +} + +/// Given an atomic ordering, translate it to the acquire suffix for the lxdr aarch64 ASM instruction. +#[rustfmt::skip] +macro_rules! acquire { + (Relaxed) => { "" }; + (Acquire) => { "a" }; + (Release) => { "" }; + (AcqRel) => { "a" }; +} + +/// Given an atomic ordering, translate it to the release suffix for the stxr aarch64 ASM instruction. +#[rustfmt::skip] +macro_rules! release { + (Relaxed) => { "" }; + (Acquire) => { "" }; + (Release) => { "l" }; + (AcqRel) => { "l" }; +} + +/// Given a size in bytes, translate it to the byte suffix for an aarch64 ASM instruction. +#[rustfmt::skip] +macro_rules! size { + (1) => { "b" }; + (2) => { "h" }; + (4) => { "" }; + (8) => { "" }; + (16) => { "" }; +} + +/// Given a byte size, translate it to an Unsigned eXTend instruction +/// with the correct semantics. +/// +/// See +#[rustfmt::skip] +macro_rules! uxt { + (1) => { "uxtb" }; + (2) => { "uxth" }; + ($_:tt) => { "mov" }; +} + +/// Given an atomic ordering and byte size, translate it to a LoaD eXclusive Register instruction +/// with the correct semantics. +/// +/// See . +macro_rules! ldxr { + ($ordering:ident, $bytes:tt) => { + concat!("ld", acquire!($ordering), "xr", size!($bytes)) + }; +} + +/// Given an atomic ordering and byte size, translate it to a STore eXclusive Register instruction +/// with the correct semantics. +/// +/// See . +macro_rules! stxr { + ($ordering:ident, $bytes:tt) => { + concat!("st", release!($ordering), "xr", size!($bytes)) + }; +} + +/// Given an atomic ordering and byte size, translate it to a LoaD eXclusive Pair of registers instruction +/// with the correct semantics. +/// +/// See +macro_rules! ldxp { + ($ordering:ident) => { + concat!("ld", acquire!($ordering), "xp") + }; +} + +/// Given an atomic ordering and byte size, translate it to a STore eXclusive Pair of registers instruction +/// with the correct semantics. +/// +/// See . +macro_rules! stxp { + ($ordering:ident) => { + concat!("st", release!($ordering), "xp") + }; +} + +/// See . +macro_rules! compare_and_swap { + ($ordering:ident, $bytes:tt, $name:ident) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub unsafe extern "C" fn $name ( + expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes) + ) -> int_ty!($bytes) { + // We can't use `AtomicI8::compare_and_swap`; we *are* compare_and_swap. + unsafe { core::arch::naked_asm! { + // UXT s(tmp0), s(0) + concat!(uxt!($bytes), " ", reg!($bytes, 16), ", ", reg!($bytes, 0)), + "0:", + // LDXR s(0), [x2] + concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x2]"), + // cmp s(0), s(tmp0) + concat!("cmp ", reg!($bytes, 0), ", ", reg!($bytes, 16)), + "bne 1f", + // STXR w(tmp1), s(1), [x2] + concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 1), ", [x2]"), + "cbnz w17, 0b", + "1:", + "ret", + } } + } + } + }; +} + +// i128 uses a completely different impl, so it has its own macro. +macro_rules! compare_and_swap_i128 { + ($ordering:ident, $name:ident) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub unsafe extern "C" fn $name ( + expected: i128, desired: i128, ptr: *mut i128 + ) -> i128 { + unsafe { core::arch::naked_asm! { + "mov x16, x0", + "mov x17, x1", + "0:", + // LDXP x0, x1, [x4] + concat!(ldxp!($ordering), " x0, x1, [x4]"), + "cmp x0, x16", + "ccmp x1, x17, #0, eq", + "bne 1f", + // STXP w(tmp2), x2, x3, [x4] + concat!(stxp!($ordering), " w15, x2, x3, [x4]"), + "cbnz w15, 0b", + "1:", + "ret", + } } + } + } + }; +} + +/// See . +macro_rules! swap { + ($ordering:ident, $bytes:tt, $name:ident) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub unsafe extern "C" fn $name ( + left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes) + ) -> int_ty!($bytes) { + unsafe { core::arch::naked_asm! { + // mov s(tmp0), s(0) + concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), + "0:", + // LDXR s(0), [x1] + concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x1]"), + // STXR w(tmp1), s(tmp0), [x1] + concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 16), ", [x1]"), + "cbnz w17, 0b", + "ret", + } } + } + } + }; +} + +/// See (e.g.) . +macro_rules! fetch_op { + ($ordering:ident, $bytes:tt, $name:ident, $op:literal) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub unsafe extern "C" fn $name ( + val: int_ty!($bytes), ptr: *mut int_ty!($bytes) + ) -> int_ty!($bytes) { + unsafe { core::arch::naked_asm! { + // mov s(tmp0), s(0) + concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), + "0:", + // LDXR s(0), [x1] + concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x1]"), + // OP s(tmp1), s(0), s(tmp0) + concat!($op, " ", reg!($bytes, 17), ", ", reg!($bytes, 0), ", ", reg!($bytes, 16)), + // STXR w(tmp2), s(tmp1), [x1] + concat!(stxr!($ordering, $bytes), " w15, ", reg!($bytes, 17), ", [x1]"), + "cbnz w15, 0b", + "ret", + } } + } + } + } +} + +// We need a single macro to pass to `foreach_ldadd`. +macro_rules! add { + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "add" } + }; +} + +macro_rules! and { + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "bic" } + }; +} + +macro_rules! xor { + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "eor" } + }; +} + +macro_rules! or { + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "orr" } + }; +} + +// See `generate_aarch64_outlined_atomics` in build.rs. +include!(concat!(env!("OUT_DIR"), "/outlined_atomics.rs")); +foreach_cas!(compare_and_swap); +foreach_cas16!(compare_and_swap_i128); +foreach_swp!(swap); +foreach_ldadd!(add); +foreach_ldclr!(and); +foreach_ldeor!(xor); +foreach_ldset!(or); diff --git a/library/compiler-builtins/compiler-builtins/src/arm.rs b/library/compiler-builtins/compiler-builtins/src/arm.rs new file mode 100644 index 00000000000..9e6608397a8 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/arm.rs @@ -0,0 +1,165 @@ +#![cfg(not(feature = "no-asm"))] +#![allow(unused_imports)] + +use core::intrinsics; + +// Apple symbols have a leading underscore. +#[cfg(target_vendor = "apple")] +macro_rules! bl { + ($func:literal) => { + concat!("bl _", $func) + }; +} +#[cfg(not(target_vendor = "apple"))] +macro_rules! bl { + ($func:literal) => { + concat!("bl ", $func) + }; +} + +intrinsics! { + // NOTE This function and the ones below are implemented using assembly because they are using a + // custom calling convention which can't be implemented using a normal Rust function. + #[naked] + #[cfg(not(target_env = "msvc"))] + pub unsafe extern "C" fn __aeabi_uidivmod() { + core::arch::naked_asm!( + "push {{lr}}", + "sub sp, sp, #4", + "mov r2, sp", + bl!("__udivmodsi4"), + "ldr r1, [sp]", + "add sp, sp, #4", + "pop {{pc}}", + ); + } + + #[naked] + pub unsafe extern "C" fn __aeabi_uldivmod() { + core::arch::naked_asm!( + "push {{r4, lr}}", + "sub sp, sp, #16", + "add r4, sp, #8", + "str r4, [sp]", + bl!("__udivmoddi4"), + "ldr r2, [sp, #8]", + "ldr r3, [sp, #12]", + "add sp, sp, #16", + "pop {{r4, pc}}", + ); + } + + #[naked] + pub unsafe extern "C" fn __aeabi_idivmod() { + core::arch::naked_asm!( + "push {{r0, r1, r4, lr}}", + bl!("__aeabi_idiv"), + "pop {{r1, r2}}", + "muls r2, r2, r0", + "subs r1, r1, r2", + "pop {{r4, pc}}", + ); + } + + #[naked] + pub unsafe extern "C" fn __aeabi_ldivmod() { + core::arch::naked_asm!( + "push {{r4, lr}}", + "sub sp, sp, #16", + "add r4, sp, #8", + "str r4, [sp]", + bl!("__divmoddi4"), + "ldr r2, [sp, #8]", + "ldr r3, [sp, #12]", + "add sp, sp, #16", + "pop {{r4, pc}}", + ); + } + + // FIXME: The `*4` and `*8` variants should be defined as aliases. + + #[cfg(not(target_vendor = "apple"))] + pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { + crate::mem::memcpy(dest, src, n); + } + + #[cfg(not(target_vendor = "apple"))] + pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { + // We are guaranteed 4-alignment, so accessing at u32 is okay. + let mut dest = dest as *mut u32; + let mut src = src as *mut u32; + let mut n = n; + + while n >= 4 { + *dest = *src; + dest = dest.offset(1); + src = src.offset(1); + n -= 4; + } + + __aeabi_memcpy(dest as *mut u8, src as *const u8, n); + } + + #[cfg(not(target_vendor = "apple"))] + pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { + __aeabi_memcpy4(dest, src, n); + } + + #[cfg(not(target_vendor = "apple"))] + pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { + crate::mem::memmove(dest, src, n); + } + + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] + pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { + __aeabi_memmove(dest, src, n); + } + + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] + pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { + __aeabi_memmove(dest, src, n); + } + + #[cfg(not(target_vendor = "apple"))] + pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { + // Note the different argument order + crate::mem::memset(dest, c, n); + } + + #[cfg(not(target_vendor = "apple"))] + pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { + let mut dest = dest as *mut u32; + let mut n = n; + + let byte = (c as u32) & 0xff; + let c = (byte << 24) | (byte << 16) | (byte << 8) | byte; + + while n >= 4 { + *dest = c; + dest = dest.offset(1); + n -= 4; + } + + __aeabi_memset(dest as *mut u8, n, byte as i32); + } + + #[cfg(not(target_vendor = "apple"))] + pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { + __aeabi_memset4(dest, n, c); + } + + #[cfg(not(target_vendor = "apple"))] + pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { + __aeabi_memset(dest, n, 0); + } + + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] + pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { + __aeabi_memset4(dest, n, 0); + } + + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] + pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { + __aeabi_memset4(dest, n, 0); + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/compiler-builtins/src/arm_linux.rs new file mode 100644 index 00000000000..8f22eb62866 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/arm_linux.rs @@ -0,0 +1,250 @@ +use core::intrinsics; +use core::mem; + +// Kernel-provided user-mode helper functions: +// https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt +unsafe fn __kuser_cmpxchg(oldval: u32, newval: u32, ptr: *mut u32) -> bool { + let f: extern "C" fn(u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0usize as *const ()); + f(oldval, newval, ptr) == 0 +} +unsafe fn __kuser_memory_barrier() { + let f: extern "C" fn() = mem::transmute(0xffff0fa0usize as *const ()); + f(); +} + +// Word-align a pointer +fn align_ptr(ptr: *mut T) -> *mut u32 { + // This gives us a mask of 0 when T == u32 since the pointer is already + // supposed to be aligned, which avoids any masking in that case. + let ptr_mask = 3 & (4 - mem::size_of::()); + (ptr as usize & !ptr_mask) as *mut u32 +} + +// Calculate the shift and mask of a value inside an aligned word +fn get_shift_mask(ptr: *mut T) -> (u32, u32) { + // Mask to get the low byte/halfword/word + let mask = match mem::size_of::() { + 1 => 0xff, + 2 => 0xffff, + 4 => 0xffffffff, + _ => unreachable!(), + }; + + // If we are on big-endian then we need to adjust the shift accordingly + let endian_adjust = if cfg!(target_endian = "little") { + 0 + } else { + 4 - mem::size_of::() as u32 + }; + + // Shift to get the desired element in the word + let ptr_mask = 3 & (4 - mem::size_of::()); + let shift = ((ptr as usize & ptr_mask) as u32 ^ endian_adjust) * 8; + + (shift, mask) +} + +// Extract a value from an aligned word +fn extract_aligned(aligned: u32, shift: u32, mask: u32) -> u32 { + (aligned >> shift) & mask +} + +// Insert a value into an aligned word +fn insert_aligned(aligned: u32, val: u32, shift: u32, mask: u32) -> u32 { + (aligned & !(mask << shift)) | ((val & mask) << shift) +} + +// Generic atomic read-modify-write operation +unsafe fn atomic_rmw u32, G: Fn(u32, u32) -> u32>(ptr: *mut T, f: F, g: G) -> u32 { + let aligned_ptr = align_ptr(ptr); + let (shift, mask) = get_shift_mask(ptr); + + loop { + let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr); + let curval = extract_aligned(curval_aligned, shift, mask); + let newval = f(curval); + let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask); + if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) { + return g(curval, newval); + } + } +} + +// Generic atomic compare-exchange operation +unsafe fn atomic_cmpxchg(ptr: *mut T, oldval: u32, newval: u32) -> u32 { + let aligned_ptr = align_ptr(ptr); + let (shift, mask) = get_shift_mask(ptr); + + loop { + let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr); + let curval = extract_aligned(curval_aligned, shift, mask); + if curval != oldval { + return curval; + } + let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask); + if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) { + return oldval; + } + } +} + +macro_rules! atomic_rmw { + ($name:ident, $ty:ty, $op:expr, $fetch:expr) => { + intrinsics! { + pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty { + atomic_rmw(ptr, |x| $op(x as $ty, val) as u32, |old, new| $fetch(old, new)) as $ty + } + } + }; + + (@old $name:ident, $ty:ty, $op:expr) => { + atomic_rmw!($name, $ty, $op, |old, _| old); + }; + + (@new $name:ident, $ty:ty, $op:expr) => { + atomic_rmw!($name, $ty, $op, |_, new| new); + }; +} +macro_rules! atomic_cmpxchg { + ($name:ident, $ty:ty) => { + intrinsics! { + pub unsafe extern "C" fn $name(ptr: *mut $ty, oldval: $ty, newval: $ty) -> $ty { + atomic_cmpxchg(ptr, oldval as u32, newval as u32) as $ty + } + } + }; +} + +atomic_rmw!(@old __sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b)); +atomic_rmw!(@old __sync_fetch_and_add_2, u16, |a: u16, b: u16| a + .wrapping_add(b)); +atomic_rmw!(@old __sync_fetch_and_add_4, u32, |a: u32, b: u32| a + .wrapping_add(b)); + +atomic_rmw!(@new __sync_add_and_fetch_1, u8, |a: u8, b: u8| a.wrapping_add(b)); +atomic_rmw!(@new __sync_add_and_fetch_2, u16, |a: u16, b: u16| a + .wrapping_add(b)); +atomic_rmw!(@new __sync_add_and_fetch_4, u32, |a: u32, b: u32| a + .wrapping_add(b)); + +atomic_rmw!(@old __sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); +atomic_rmw!(@old __sync_fetch_and_sub_2, u16, |a: u16, b: u16| a + .wrapping_sub(b)); +atomic_rmw!(@old __sync_fetch_and_sub_4, u32, |a: u32, b: u32| a + .wrapping_sub(b)); + +atomic_rmw!(@new __sync_sub_and_fetch_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); +atomic_rmw!(@new __sync_sub_and_fetch_2, u16, |a: u16, b: u16| a + .wrapping_sub(b)); +atomic_rmw!(@new __sync_sub_and_fetch_4, u32, |a: u32, b: u32| a + .wrapping_sub(b)); + +atomic_rmw!(@old __sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b); +atomic_rmw!(@old __sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b); +atomic_rmw!(@old __sync_fetch_and_and_4, u32, |a: u32, b: u32| a & b); + +atomic_rmw!(@new __sync_and_and_fetch_1, u8, |a: u8, b: u8| a & b); +atomic_rmw!(@new __sync_and_and_fetch_2, u16, |a: u16, b: u16| a & b); +atomic_rmw!(@new __sync_and_and_fetch_4, u32, |a: u32, b: u32| a & b); + +atomic_rmw!(@old __sync_fetch_and_or_1, u8, |a: u8, b: u8| a | b); +atomic_rmw!(@old __sync_fetch_and_or_2, u16, |a: u16, b: u16| a | b); +atomic_rmw!(@old __sync_fetch_and_or_4, u32, |a: u32, b: u32| a | b); + +atomic_rmw!(@new __sync_or_and_fetch_1, u8, |a: u8, b: u8| a | b); +atomic_rmw!(@new __sync_or_and_fetch_2, u16, |a: u16, b: u16| a | b); +atomic_rmw!(@new __sync_or_and_fetch_4, u32, |a: u32, b: u32| a | b); + +atomic_rmw!(@old __sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b); +atomic_rmw!(@old __sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b); +atomic_rmw!(@old __sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b); + +atomic_rmw!(@new __sync_xor_and_fetch_1, u8, |a: u8, b: u8| a ^ b); +atomic_rmw!(@new __sync_xor_and_fetch_2, u16, |a: u16, b: u16| a ^ b); +atomic_rmw!(@new __sync_xor_and_fetch_4, u32, |a: u32, b: u32| a ^ b); + +atomic_rmw!(@old __sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b)); +atomic_rmw!(@old __sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b)); +atomic_rmw!(@old __sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b)); + +atomic_rmw!(@new __sync_nand_and_fetch_1, u8, |a: u8, b: u8| !(a & b)); +atomic_rmw!(@new __sync_nand_and_fetch_2, u16, |a: u16, b: u16| !(a & b)); +atomic_rmw!(@new __sync_nand_and_fetch_4, u32, |a: u32, b: u32| !(a & b)); + +atomic_rmw!(@old __sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { + a +} else { + b +}); +atomic_rmw!(@old __sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { + a +} else { + b +}); +atomic_rmw!(@old __sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { + a +} else { + b +}); + +atomic_rmw!(@old __sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { + a +} else { + b +}); +atomic_rmw!(@old __sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { + a +} else { + b +}); +atomic_rmw!(@old __sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { + a +} else { + b +}); + +atomic_rmw!(@old __sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { + a +} else { + b +}); +atomic_rmw!(@old __sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { + a +} else { + b +}); +atomic_rmw!(@old __sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { + a +} else { + b +}); + +atomic_rmw!(@old __sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { + a +} else { + b +}); +atomic_rmw!(@old __sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { + a +} else { + b +}); +atomic_rmw!(@old __sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { + a +} else { + b +}); + +atomic_rmw!(@old __sync_lock_test_and_set_1, u8, |_: u8, b: u8| b); +atomic_rmw!(@old __sync_lock_test_and_set_2, u16, |_: u16, b: u16| b); +atomic_rmw!(@old __sync_lock_test_and_set_4, u32, |_: u32, b: u32| b); + +atomic_cmpxchg!(__sync_val_compare_and_swap_1, u8); +atomic_cmpxchg!(__sync_val_compare_and_swap_2, u16); +atomic_cmpxchg!(__sync_val_compare_and_swap_4, u32); + +intrinsics! { + pub unsafe extern "C" fn __sync_synchronize() { + __kuser_memory_barrier(); + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/float/add.rs b/library/compiler-builtins/compiler-builtins/src/float/add.rs new file mode 100644 index 00000000000..ef04ddc165c --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/float/add.rs @@ -0,0 +1,211 @@ +use crate::float::Float; +use crate::int::{CastInto, Int, MinInt}; + +/// Returns `a + b` +fn add(a: F, b: F) -> F +where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, +{ + let one = F::Int::ONE; + let zero = F::Int::ZERO; + + let bits = F::BITS.cast(); + let significand_bits = F::SIG_BITS; + let max_exponent = F::EXP_SAT; + + let implicit_bit = F::IMPLICIT_BIT; + let significand_mask = F::SIG_MASK; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXP_MASK; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + + let mut a_rep = a.to_bits(); + let mut b_rep = b.to_bits(); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // Detect if a or b is zero, infinity, or NaN. + if a_abs.wrapping_sub(one) >= inf_rep - one || b_abs.wrapping_sub(one) >= inf_rep - one { + // NaN + anything = qNaN + if a_abs > inf_rep { + return F::from_bits(a_abs | quiet_bit); + } + // anything + NaN = qNaN + if b_abs > inf_rep { + return F::from_bits(b_abs | quiet_bit); + } + + if a_abs == inf_rep { + // +/-infinity + -/+infinity = qNaN + if (a.to_bits() ^ b.to_bits()) == sign_bit { + return F::from_bits(qnan_rep); + } else { + // +/-infinity + anything remaining = +/- infinity + return a; + } + } + + // anything remaining + +/-infinity = +/-infinity + if b_abs == inf_rep { + return b; + } + + // zero + anything = anything + if a_abs == MinInt::ZERO { + // but we need to get the sign right for zero + zero + if b_abs == MinInt::ZERO { + return F::from_bits(a.to_bits() & b.to_bits()); + } else { + return b; + } + } + + // anything + zero = anything + if b_abs == MinInt::ZERO { + return a; + } + } + + // Swap a and b if necessary so that a has the larger absolute value. + if b_abs > a_abs { + // Don't use mem::swap because it may generate references to memcpy in unoptimized code. + let tmp = a_rep; + a_rep = b_rep; + b_rep = tmp; + } + + // Extract the exponent and significand from the (possibly swapped) a and b. + let mut a_exponent: i32 = ((a_rep & exponent_mask) >> significand_bits).cast(); + let mut b_exponent: i32 = ((b_rep & exponent_mask) >> significand_bits).cast(); + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + + // normalize any denormals, and adjust the exponent accordingly. + if a_exponent == 0 { + let (exponent, significand) = F::normalize(a_significand); + a_exponent = exponent; + a_significand = significand; + } + if b_exponent == 0 { + let (exponent, significand) = F::normalize(b_significand); + b_exponent = exponent; + b_significand = significand; + } + + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + let result_sign = a_rep & sign_bit; + let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize(), but setting it twice won't hurt + // anything.) + a_significand = (a_significand | implicit_bit) << 3; + b_significand = (b_significand | implicit_bit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + let align = a_exponent.wrapping_sub(b_exponent).cast(); + if align != MinInt::ZERO { + if align < bits { + let sticky = + F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != MinInt::ZERO); + b_significand = (b_significand >> align.cast()) | sticky; + } else { + b_significand = one; // sticky; b is known to be non-zero. + } + } + if subtraction { + a_significand = a_significand.wrapping_sub(b_significand); + // If a == -b, return +zero. + if a_significand == MinInt::ZERO { + return F::from_bits(MinInt::ZERO); + } + + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if a_significand < implicit_bit << 3 { + let shift = + a_significand.leading_zeros() as i32 - (implicit_bit << 3).leading_zeros() as i32; + a_significand <<= shift; + a_exponent -= shift; + } + } else { + // addition + a_significand += b_significand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if a_significand & (implicit_bit << 4) != MinInt::ZERO { + let sticky = F::Int::from_bool(a_significand & one != MinInt::ZERO); + a_significand = (a_significand >> 1) | sticky; + a_exponent += 1; + } + } + + // If we have overflowed the type, return +/- infinity: + if a_exponent >= max_exponent as i32 { + return F::from_bits(inf_rep | result_sign); + } + + if a_exponent <= 0 { + // Result is denormal before rounding; the exponent is zero and we + // need to shift the significand. + let shift = (1 - a_exponent).cast(); + let sticky = + F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != MinInt::ZERO); + a_significand = (a_significand >> shift.cast()) | sticky; + a_exponent = 0; + } + + // Low three bits are round, guard, and sticky. + let a_significand_i32: i32 = a_significand.cast(); + let round_guard_sticky: i32 = a_significand_i32 & 0x7; + + // Shift the significand into place, and mask off the implicit bit. + let mut result = (a_significand >> 3) & significand_mask; + + // Insert the exponent and sign. + result |= a_exponent.cast() << significand_bits; + result |= result_sign; + + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if round_guard_sticky > 0x4 { + result += one; + } + if round_guard_sticky == 0x4 { + result += result & one; + } + + F::from_bits(result) +} + +intrinsics! { + #[avr_skip] + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_fadd] + pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 { + add(a, b) + } + + #[avr_skip] + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_dadd] + pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 { + add(a, b) + } + + #[ppc_alias = __addkf3] + #[cfg(f128_enabled)] + pub extern "C" fn __addtf3(a: f128, b: f128) -> f128 { + add(a, b) + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs new file mode 100644 index 00000000000..b9b4d0114b7 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs @@ -0,0 +1,261 @@ +#![allow(unreachable_code)] + +use crate::float::Float; +use crate::int::MinInt; + +#[derive(Clone, Copy)] +enum Result { + Less, + Equal, + Greater, + Unordered, +} + +impl Result { + fn to_le_abi(self) -> i32 { + match self { + Result::Less => -1, + Result::Equal => 0, + Result::Greater => 1, + Result::Unordered => 1, + } + } + + fn to_ge_abi(self) -> i32 { + match self { + Result::Less => -1, + Result::Equal => 0, + Result::Greater => 1, + Result::Unordered => -1, + } + } +} + +fn cmp(a: F, b: F) -> Result { + let one = F::Int::ONE; + let zero = F::Int::ZERO; + let szero = F::SignedInt::ZERO; + + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXP_MASK; + let inf_rep = exponent_mask; + + let a_rep = a.to_bits(); + let b_rep = b.to_bits(); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // If either a or b is NaN, they are unordered. + if a_abs > inf_rep || b_abs > inf_rep { + return Result::Unordered; + } + + // If a and b are both zeros, they are equal. + if a_abs | b_abs == zero { + return Result::Equal; + } + + let a_srep = a.to_bits_signed(); + let b_srep = b.to_bits_signed(); + + // If at least one of a and b is positive, we get the same result comparing + // a and b as signed integers as we would with a fp_ting-point compare. + if a_srep & b_srep >= szero { + if a_srep < b_srep { + Result::Less + } else if a_srep == b_srep { + Result::Equal + } else { + Result::Greater + } + // Otherwise, both are negative, so we need to flip the sense of the + // comparison to get the correct result. (This assumes a twos- or ones- + // complement integer representation; if integers are represented in a + // sign-magnitude representation, then this flip is incorrect). + } else if a_srep > b_srep { + Result::Less + } else if a_srep == b_srep { + Result::Equal + } else { + Result::Greater + } +} + +fn unord(a: F, b: F) -> bool { + let one = F::Int::ONE; + + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXP_MASK; + let inf_rep = exponent_mask; + + let a_rep = a.to_bits(); + let b_rep = b.to_bits(); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + a_abs > inf_rep || b_abs > inf_rep +} + +intrinsics! { + #[avr_skip] + pub extern "C" fn __lesf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __gesf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_ge_abi() + } + + #[avr_skip] + #[arm_aeabi_alias = __aeabi_fcmpun] + pub extern "C" fn __unordsf2(a: f32, b: f32) -> i32 { + unord(a, b) as i32 + } + + #[avr_skip] + pub extern "C" fn __eqsf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __ltsf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __nesf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __gtsf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_ge_abi() + } + + #[avr_skip] + pub extern "C" fn __ledf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __gedf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_ge_abi() + } + + #[avr_skip] + #[arm_aeabi_alias = __aeabi_dcmpun] + pub extern "C" fn __unorddf2(a: f64, b: f64) -> i32 { + unord(a, b) as i32 + } + + #[avr_skip] + pub extern "C" fn __eqdf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __ltdf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __nedf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __gtdf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_ge_abi() + } +} + +#[cfg(f128_enabled)] +intrinsics! { + #[avr_skip] + #[ppc_alias = __lekf2] + pub extern "C" fn __letf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + #[ppc_alias = __gekf2] + pub extern "C" fn __getf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_ge_abi() + } + + #[avr_skip] + #[ppc_alias = __unordkf2] + pub extern "C" fn __unordtf2(a: f128, b: f128) -> i32 { + unord(a, b) as i32 + } + + #[avr_skip] + #[ppc_alias = __eqkf2] + pub extern "C" fn __eqtf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + #[ppc_alias = __ltkf2] + pub extern "C" fn __lttf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + #[ppc_alias = __nekf2] + pub extern "C" fn __netf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + #[ppc_alias = __gtkf2] + pub extern "C" fn __gttf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_ge_abi() + } +} + +#[cfg(target_arch = "arm")] +intrinsics! { + pub extern "aapcs" fn __aeabi_fcmple(a: f32, b: f32) -> i32 { + (__lesf2(a, b) <= 0) as i32 + } + + pub extern "aapcs" fn __aeabi_fcmpge(a: f32, b: f32) -> i32 { + (__gesf2(a, b) >= 0) as i32 + } + + pub extern "aapcs" fn __aeabi_fcmpeq(a: f32, b: f32) -> i32 { + (__eqsf2(a, b) == 0) as i32 + } + + pub extern "aapcs" fn __aeabi_fcmplt(a: f32, b: f32) -> i32 { + (__ltsf2(a, b) < 0) as i32 + } + + pub extern "aapcs" fn __aeabi_fcmpgt(a: f32, b: f32) -> i32 { + (__gtsf2(a, b) > 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmple(a: f64, b: f64) -> i32 { + (__ledf2(a, b) <= 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmpge(a: f64, b: f64) -> i32 { + (__gedf2(a, b) >= 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmpeq(a: f64, b: f64) -> i32 { + (__eqdf2(a, b) == 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmplt(a: f64, b: f64) -> i32 { + (__ltdf2(a, b) < 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmpgt(a: f64, b: f64) -> i32 { + (__gtdf2(a, b) > 0) as i32 + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/compiler-builtins/src/float/conv.rs new file mode 100644 index 00000000000..42a526bd524 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/float/conv.rs @@ -0,0 +1,490 @@ +use core::ops::Neg; + +use crate::int::{CastFrom, CastInto, Int, MinInt}; + +use super::Float; + +/// Conversions from integers to floats. +/// +/// The algorithm is explained here: . It roughly does the following: +/// - Calculate a base mantissa by shifting the integer into mantissa position. This gives us a +/// mantissa _with the implicit bit set_! +/// - Figure out if rounding needs to occur by classifying the bits that are to be truncated. Some +/// patterns are used to simplify this. Adjust the mantissa with the result if needed. +/// - Calculate the exponent based on the base-2 logarithm of `i` (leading zeros). Subtract one. +/// - Shift the exponent and add the mantissa to create the final representation. Subtracting one +/// from the exponent (above) accounts for the explicit bit being set in the mantissa. +/// +/// # Terminology +/// +/// - `i`: the original integer +/// - `i_m`: the integer, shifted fully left (no leading zeros) +/// - `n`: number of leading zeroes +/// - `e`: the resulting exponent. Usually 1 is subtracted to offset the mantissa implicit bit. +/// - `m_base`: the mantissa before adjusting for truncated bits. Implicit bit is usually set. +/// - `adj`: the bits that will be truncated, possibly compressed in some way. +/// - `m`: the resulting mantissa. Implicit bit is usually set. +mod int_to_float { + use super::*; + + /// Calculate the exponent from the number of leading zeros. + /// + /// Usually 1 is subtracted from this function's result, so that a mantissa with the implicit + /// bit set can be added back later. + fn exp>>(n: u32) -> F::Int { + F::Int::cast_from(F::EXP_BIAS - 1 + I::BITS - n) + } + + /// Adjust a mantissa with dropped bits to perform correct rounding. + /// + /// The dropped bits should be exactly the bits that get truncated (left-aligned), but they + /// can be combined or compressed in some way that simplifies operations. + fn m_adj(m_base: F::Int, dropped_bits: F::Int) -> F::Int { + // Branchlessly extract a `1` if rounding up should happen, 0 otherwise + // This accounts for rounding to even. + let adj = (dropped_bits - ((dropped_bits >> (F::BITS - 1)) & !m_base)) >> (F::BITS - 1); + + // Add one when we need to round up. Break ties to even. + m_base + adj + } + + /// Shift the exponent to its position and add the mantissa. + /// + /// If the mantissa has the implicit bit set, the exponent should be one less than its actual + /// value to cancel it out. + fn repr(e: F::Int, m: F::Int) -> F::Int { + // + rather than | so the mantissa can overflow into the exponent + (e << F::SIG_BITS) + m + } + + /// Shift distance from a left-aligned integer to a smaller float. + fn shift_f_lt_i() -> u32 { + (I::BITS - F::BITS) + F::EXP_BITS + } + + /// Shift distance from an integer with `n` leading zeros to a smaller float. + fn shift_f_gt_i(n: u32) -> u32 { + F::SIG_BITS - I::BITS + 1 + n + } + + /// Perform a signed operation as unsigned, then add the sign back. + pub fn signed(i: I, conv: Conv) -> F + where + F: Float, + I: Int, + F::Int: CastFrom, + Conv: Fn(I::UnsignedInt) -> F::Int, + { + let sign_bit = F::Int::cast_from(i >> (I::BITS - 1)) << (F::BITS - 1); + F::from_bits(conv(i.unsigned_abs()) | sign_bit) + } + + pub fn u32_to_f32_bits(i: u32) -> u32 { + if i == 0 { + return 0; + } + let n = i.leading_zeros(); + // Mantissa with implicit bit set (significant bits) + let m_base = (i << n) >> f32::EXP_BITS; + // Bits that will be dropped (insignificant bits) + let adj = (i << n) << (f32::SIG_BITS + 1); + let m = m_adj::(m_base, adj); + let e = exp::(n) - 1; + repr::(e, m) + } + + pub fn u32_to_f64_bits(i: u32) -> u64 { + if i == 0 { + return 0; + } + let n = i.leading_zeros(); + // Mantissa with implicit bit set + let m = (i as u64) << shift_f_gt_i::(n); + let e = exp::(n) - 1; + repr::(e, m) + } + + #[cfg(f128_enabled)] + pub fn u32_to_f128_bits(i: u32) -> u128 { + if i == 0 { + return 0; + } + let n = i.leading_zeros(); + + // Shift into mantissa position that is correct for the type, but shifted into the lower + // 64 bits over so can can avoid 128-bit math. + let m = (i as u64) << (shift_f_gt_i::(n) - 64); + let e = exp::(n) as u64 - 1; + // High 64 bits of f128 representation. + let h = (e << (f128::SIG_BITS - 64)) + m; + + // Shift back to the high bits, the rest of the mantissa will always be 0. + (h as u128) << 64 + } + + pub fn u64_to_f32_bits(i: u64) -> u32 { + let n = i.leading_zeros(); + let i_m = i.wrapping_shl(n); + // Mantissa with implicit bit set + let m_base: u32 = (i_m >> shift_f_lt_i::()) as u32; + // The entire lower half of `i` will be truncated (masked portion), plus the + // next `EXP_BITS` bits. + let adj = ((i_m >> f32::EXP_BITS) | i_m & 0xFFFF) as u32; + let m = m_adj::(m_base, adj); + let e = if i == 0 { 0 } else { exp::(n) - 1 }; + repr::(e, m) + } + + pub fn u64_to_f64_bits(i: u64) -> u64 { + if i == 0 { + return 0; + } + let n = i.leading_zeros(); + // Mantissa with implicit bit set + let m_base = (i << n) >> f64::EXP_BITS; + let adj = (i << n) << (f64::SIG_BITS + 1); + let m = m_adj::(m_base, adj); + let e = exp::(n) - 1; + repr::(e, m) + } + + #[cfg(f128_enabled)] + pub fn u64_to_f128_bits(i: u64) -> u128 { + if i == 0 { + return 0; + } + let n = i.leading_zeros(); + // Mantissa with implicit bit set + let m = (i as u128) << shift_f_gt_i::(n); + let e = exp::(n) - 1; + repr::(e, m) + } + + pub fn u128_to_f32_bits(i: u128) -> u32 { + let n = i.leading_zeros(); + let i_m = i.wrapping_shl(n); // Mantissa, shifted so the first bit is nonzero + let m_base: u32 = (i_m >> shift_f_lt_i::()) as u32; + + // Within the upper `F::BITS`, everything except for the signifcand + // gets truncated + let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIG_BITS - 1)).cast(); + + // The entire rest of `i_m` gets truncated. Zero the upper `F::BITS` then just + // check if it is nonzero. + let d2: u32 = (i_m << f32::BITS >> f32::BITS != 0).into(); + let adj = d1 | d2; + + // Mantissa with implicit bit set + let m = m_adj::(m_base, adj); + let e = if i == 0 { 0 } else { exp::(n) - 1 }; + repr::(e, m) + } + + pub fn u128_to_f64_bits(i: u128) -> u64 { + let n = i.leading_zeros(); + let i_m = i.wrapping_shl(n); + // Mantissa with implicit bit set + let m_base: u64 = (i_m >> shift_f_lt_i::()) as u64; + // The entire lower half of `i` will be truncated (masked portion), plus the + // next `EXP_BITS` bits. + let adj = ((i_m >> f64::EXP_BITS) | i_m & 0xFFFF_FFFF) as u64; + let m = m_adj::(m_base, adj); + let e = if i == 0 { 0 } else { exp::(n) - 1 }; + repr::(e, m) + } + + #[cfg(f128_enabled)] + pub fn u128_to_f128_bits(i: u128) -> u128 { + if i == 0 { + return 0; + } + let n = i.leading_zeros(); + // Mantissa with implicit bit set + let m_base = (i << n) >> f128::EXP_BITS; + let adj = (i << n) << (f128::SIG_BITS + 1); + let m = m_adj::(m_base, adj); + let e = exp::(n) - 1; + repr::(e, m) + } +} + +// Conversions from unsigned integers to floats. +intrinsics! { + #[arm_aeabi_alias = __aeabi_ui2f] + pub extern "C" fn __floatunsisf(i: u32) -> f32 { + f32::from_bits(int_to_float::u32_to_f32_bits(i)) + } + + #[arm_aeabi_alias = __aeabi_ui2d] + pub extern "C" fn __floatunsidf(i: u32) -> f64 { + f64::from_bits(int_to_float::u32_to_f64_bits(i)) + } + + #[arm_aeabi_alias = __aeabi_ul2f] + pub extern "C" fn __floatundisf(i: u64) -> f32 { + f32::from_bits(int_to_float::u64_to_f32_bits(i)) + } + + #[arm_aeabi_alias = __aeabi_ul2d] + pub extern "C" fn __floatundidf(i: u64) -> f64 { + f64::from_bits(int_to_float::u64_to_f64_bits(i)) + } + + #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] + pub extern "C" fn __floatuntisf(i: u128) -> f32 { + f32::from_bits(int_to_float::u128_to_f32_bits(i)) + } + + #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] + pub extern "C" fn __floatuntidf(i: u128) -> f64 { + f64::from_bits(int_to_float::u128_to_f64_bits(i)) + } + + #[ppc_alias = __floatunsikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatunsitf(i: u32) -> f128 { + f128::from_bits(int_to_float::u32_to_f128_bits(i)) + } + + #[ppc_alias = __floatundikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatunditf(i: u64) -> f128 { + f128::from_bits(int_to_float::u64_to_f128_bits(i)) + } + + #[ppc_alias = __floatuntikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatuntitf(i: u128) -> f128 { + f128::from_bits(int_to_float::u128_to_f128_bits(i)) + } +} + +// Conversions from signed integers to floats. +intrinsics! { + #[arm_aeabi_alias = __aeabi_i2f] + pub extern "C" fn __floatsisf(i: i32) -> f32 { + int_to_float::signed(i, int_to_float::u32_to_f32_bits) + } + + #[arm_aeabi_alias = __aeabi_i2d] + pub extern "C" fn __floatsidf(i: i32) -> f64 { + int_to_float::signed(i, int_to_float::u32_to_f64_bits) + } + + #[arm_aeabi_alias = __aeabi_l2f] + pub extern "C" fn __floatdisf(i: i64) -> f32 { + int_to_float::signed(i, int_to_float::u64_to_f32_bits) + } + + #[arm_aeabi_alias = __aeabi_l2d] + pub extern "C" fn __floatdidf(i: i64) -> f64 { + int_to_float::signed(i, int_to_float::u64_to_f64_bits) + } + + #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] + pub extern "C" fn __floattisf(i: i128) -> f32 { + int_to_float::signed(i, int_to_float::u128_to_f32_bits) + } + + #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] + pub extern "C" fn __floattidf(i: i128) -> f64 { + int_to_float::signed(i, int_to_float::u128_to_f64_bits) + } + + #[ppc_alias = __floatsikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatsitf(i: i32) -> f128 { + int_to_float::signed(i, int_to_float::u32_to_f128_bits) + } + + #[ppc_alias = __floatdikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatditf(i: i64) -> f128 { + int_to_float::signed(i, int_to_float::u64_to_f128_bits) + } + + #[ppc_alias = __floattikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floattitf(i: i128) -> f128 { + int_to_float::signed(i, int_to_float::u128_to_f128_bits) + } +} + +/// Generic float to unsigned int conversions. +fn float_to_unsigned_int(f: F) -> U +where + F: Float, + U: Int, + F::Int: CastInto, + F::Int: CastFrom, + F::Int: CastInto, + u32: CastFrom, +{ + float_to_int_inner::(f.to_bits(), |i: U| i, || U::MAX) +} + +/// Generic float to signed int conversions. +fn float_to_signed_int(f: F) -> I +where + F: Float, + I: Int + Neg, + I::UnsignedInt: Int, + F::Int: CastInto, + F::Int: CastFrom, + u32: CastFrom, +{ + float_to_int_inner::( + f.to_bits() & !F::SIGN_MASK, + |i: I| if f.is_sign_negative() { -i } else { i }, + || if f.is_sign_negative() { I::MIN } else { I::MAX }, + ) +} + +/// Float to int conversions, generic for both signed and unsigned. +/// +/// Parameters: +/// - `fbits`: `abg(f)` bitcasted to an integer. +/// - `map_inbounds`: apply this transformation to integers that are within range (add the sign back). +/// - `out_of_bounds`: return value when out of range for `I`. +fn float_to_int_inner( + fbits: F::Int, + map_inbounds: FnFoo, + out_of_bounds: FnOob, +) -> I +where + F: Float, + I: Int, + FnFoo: FnOnce(I) -> I, + FnOob: FnOnce() -> I, + I::UnsignedInt: Int, + F::Int: CastInto, + F::Int: CastFrom, + u32: CastFrom, +{ + let int_max_exp = F::EXP_BIAS + I::MAX.ilog2() + 1; + let foobar = F::EXP_BIAS + I::UnsignedInt::BITS - 1; + + if fbits < F::ONE.to_bits() { + // < 0 gets rounded to 0 + I::ZERO + } else if fbits < F::Int::cast_from(int_max_exp) << F::SIG_BITS { + // >= 1, < integer max + let m_base = if I::UnsignedInt::BITS >= F::Int::BITS { + I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIG_BITS - 1) + } else { + I::UnsignedInt::cast_from(fbits >> (F::SIG_BITS - I::BITS + 1)) + }; + + // Set the implicit 1-bit. + let m: I::UnsignedInt = (I::UnsignedInt::ONE << (I::BITS - 1)) | m_base; + + // Shift based on the exponent and bias. + let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIG_BITS); + + let unsigned = m >> s; + map_inbounds(I::from_unsigned(unsigned)) + } else if fbits <= F::EXP_MASK { + // >= max (incl. inf) + out_of_bounds() + } else { + I::ZERO + } +} + +// Conversions from floats to unsigned integers. +intrinsics! { + #[arm_aeabi_alias = __aeabi_f2uiz] + pub extern "C" fn __fixunssfsi(f: f32) -> u32 { + float_to_unsigned_int(f) + } + + #[arm_aeabi_alias = __aeabi_f2ulz] + pub extern "C" fn __fixunssfdi(f: f32) -> u64 { + float_to_unsigned_int(f) + } + + pub extern "C" fn __fixunssfti(f: f32) -> u128 { + float_to_unsigned_int(f) + } + + #[arm_aeabi_alias = __aeabi_d2uiz] + pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { + float_to_unsigned_int(f) + } + + #[arm_aeabi_alias = __aeabi_d2ulz] + pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { + float_to_unsigned_int(f) + } + + pub extern "C" fn __fixunsdfti(f: f64) -> u128 { + float_to_unsigned_int(f) + } + + #[ppc_alias = __fixunskfsi] + #[cfg(f128_enabled)] + pub extern "C" fn __fixunstfsi(f: f128) -> u32 { + float_to_unsigned_int(f) + } + + #[ppc_alias = __fixunskfdi] + #[cfg(f128_enabled)] + pub extern "C" fn __fixunstfdi(f: f128) -> u64 { + float_to_unsigned_int(f) + } + + #[ppc_alias = __fixunskfti] + #[cfg(f128_enabled)] + pub extern "C" fn __fixunstfti(f: f128) -> u128 { + float_to_unsigned_int(f) + } +} + +// Conversions from floats to signed integers. +intrinsics! { + #[arm_aeabi_alias = __aeabi_f2iz] + pub extern "C" fn __fixsfsi(f: f32) -> i32 { + float_to_signed_int(f) + } + + #[arm_aeabi_alias = __aeabi_f2lz] + pub extern "C" fn __fixsfdi(f: f32) -> i64 { + float_to_signed_int(f) + } + + pub extern "C" fn __fixsfti(f: f32) -> i128 { + float_to_signed_int(f) + } + + #[arm_aeabi_alias = __aeabi_d2iz] + pub extern "C" fn __fixdfsi(f: f64) -> i32 { + float_to_signed_int(f) + } + + #[arm_aeabi_alias = __aeabi_d2lz] + pub extern "C" fn __fixdfdi(f: f64) -> i64 { + float_to_signed_int(f) + } + + pub extern "C" fn __fixdfti(f: f64) -> i128 { + float_to_signed_int(f) + } + + #[ppc_alias = __fixkfsi] + #[cfg(f128_enabled)] + pub extern "C" fn __fixtfsi(f: f128) -> i32 { + float_to_signed_int(f) + } + + #[ppc_alias = __fixkfdi] + #[cfg(f128_enabled)] + pub extern "C" fn __fixtfdi(f: f128) -> i64 { + float_to_signed_int(f) + } + + #[ppc_alias = __fixkfti] + #[cfg(f128_enabled)] + pub extern "C" fn __fixtfti(f: f128) -> i128 { + float_to_signed_int(f) + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/float/div.rs b/library/compiler-builtins/compiler-builtins/src/float/div.rs new file mode 100644 index 00000000000..21c757dd639 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/float/div.rs @@ -0,0 +1,637 @@ +//! Floating point division routines. +//! +//! This module documentation gives an overview of the method used. More documentation is inline. +//! +//! # Relevant notation +//! +//! - `m_a`: the mantissa of `a`, in base 2 +//! - `p_a`: the exponent of `a`, in base 2. I.e. `a = m_a * 2^p_a` +//! - `uqN` (e.g. `uq1`): this refers to Q notation for fixed-point numbers. UQ1.31 is an unsigned +//! fixed-point number with 1 integral bit, and 31 decimal bits. A `uqN` variable of type `uM` +//! will have N bits of integer and M-N bits of fraction. +//! - `hw`: half width, i.e. for `f64` this will be a `u32`. +//! - `x` is the best estimate of `1/m_b` +//! +//! # Method Overview +//! +//! Division routines must solve for `a / b`, which is `res = m_a*2^p_a / m_b*2^p_b`. The basic +//! process is as follows: +//! +//! - Rearange the exponent and significand to simplify the operations: +//! `res = (m_a / m_b) * 2^{p_a - p_b}`. +//! - Check for early exits (infinity, zero, etc). +//! - If `a` or `b` are subnormal, normalize by shifting the mantissa and adjusting the exponent. +//! - Set the implicit bit so math is correct. +//! - Shift mantissa significant digits (with implicit bit) fully left such that fixed-point UQ1 +//! or UQ0 numbers can be used for mantissa math. These will have greater precision than the +//! actual mantissa, which is important for correct rounding. +//! - Calculate the reciprocal of `m_b`, `x`. +//! - Use the reciprocal to multiply rather than divide: `res = m_a * x_b * 2^{p_a - p_b}`. +//! - Reapply rounding. +//! +//! # Reciprocal calculation +//! +//! Calculating the reciprocal is the most complicated part of this process. It uses the +//! [Newton-Raphson method], which picks an initial estimation (of the reciprocal) and performs +//! a number of iterations to increase its precision. +//! +//! In general, Newton's method takes the following form: +//! +//! ```text +//! `x_n` is a guess or the result of a previous iteration. Increasing `n` converges to the +//! desired result. +//! +//! The result approaches a zero of `f(x)` by applying a correction to the previous gues. +//! +//! x_{n+1} = x_n - f(x_n) / f'(x_n) +//! ``` +//! +//! Applying this to find the reciprocal: +//! +//! ```text +//! 1 / x = b +//! +//! Rearrange so we can solve by finding a zero +//! 0 = (1 / x) - b = f(x) +//! +//! f'(x) = -x^{-2} +//! +//! x_{n+1} = 2*x_n - b*x_n^2 +//! ``` +//! +//! This is a process that can be repeated to calculate the reciprocal with enough precision to +//! achieve a correctly rounded result for the overall division operation. The maximum required +//! number of iterations is known since precision doubles with each iteration. +//! +//! # Half-width operations +//! +//! Calculating the reciprocal requires widening multiplication and performing arithmetic on the +//! results, meaning that emulated integer arithmetic on `u128` (for `f64`) and `u256` (for `f128`) +//! gets used instead of native math. +//! +//! To make this more efficient, all but the final operation can be computed using half-width +//! integers. For example, rather than computing four iterations using 128-bit integers for `f64`, +//! we can instead perform three iterations using native 64-bit integers and only one final +//! iteration using the full 128 bits. +//! +//! This works because of precision doubling. Some leeway is allowed here because the fixed-point +//! number has more bits than the final mantissa will. +//! +//! [Newton-Raphson method]: https://en.wikipedia.org/wiki/Newton%27s_method + +use super::HalfRep; +use crate::float::Float; +use crate::int::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; +use core::mem::size_of; +use core::ops; + +fn div(a: F, b: F) -> F +where + F::Int: CastInto, + F::Int: From>, + F::Int: From, + F::Int: HInt + DInt, + ::D: ops::Shr::D>, + F::Int: From, + u16: CastInto, + i32: CastInto, + u32: CastInto, + u128: CastInto>, +{ + let one = F::Int::ONE; + let zero = F::Int::ZERO; + let one_hw = HalfRep::::ONE; + let zero_hw = HalfRep::::ZERO; + let hw = F::BITS / 2; + let lo_mask = F::Int::MAX >> hw; + + let significand_bits = F::SIG_BITS; + // Saturated exponent, representing infinity + let exponent_sat: F::Int = F::EXP_SAT.cast(); + + let exponent_bias = F::EXP_BIAS; + let implicit_bit = F::IMPLICIT_BIT; + let significand_mask = F::SIG_MASK; + let sign_bit = F::SIGN_MASK; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXP_MASK; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + let (mut half_iterations, full_iterations) = get_iterations::(); + let recip_precision = reciprocal_precision::(); + + if F::BITS == 128 { + // FIXME(tgross35): f128 seems to require one more half iteration than expected + half_iterations += 1; + } + + let a_rep = a.to_bits(); + let b_rep = b.to_bits(); + + // Exponent numeric representationm not accounting for bias + let a_exponent = (a_rep >> significand_bits) & exponent_sat; + let b_exponent = (b_rep >> significand_bits) & exponent_sat; + let quotient_sign = (a_rep ^ b_rep) & sign_bit; + + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + + // The exponent of our final result in its encoded form + let mut res_exponent: i32 = + i32::cast_from(a_exponent) - i32::cast_from(b_exponent) + (exponent_bias as i32); + + // Detect if a or b is zero, denormal, infinity, or NaN. + if a_exponent.wrapping_sub(one) >= (exponent_sat - one) + || b_exponent.wrapping_sub(one) >= (exponent_sat - one) + { + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // NaN / anything = qNaN + if a_abs > inf_rep { + return F::from_bits(a_rep | quiet_bit); + } + + // anything / NaN = qNaN + if b_abs > inf_rep { + return F::from_bits(b_rep | quiet_bit); + } + + if a_abs == inf_rep { + if b_abs == inf_rep { + // infinity / infinity = NaN + return F::from_bits(qnan_rep); + } else { + // infinity / anything else = +/- infinity + return F::from_bits(a_abs | quotient_sign); + } + } + + // anything else / infinity = +/- 0 + if b_abs == inf_rep { + return F::from_bits(quotient_sign); + } + + if a_abs == zero { + if b_abs == zero { + // zero / zero = NaN + return F::from_bits(qnan_rep); + } else { + // zero / anything else = +/- zero + return F::from_bits(quotient_sign); + } + } + + // anything else / zero = +/- infinity + if b_abs == zero { + return F::from_bits(inf_rep | quotient_sign); + } + + // a is denormal. Renormalize it and set the scale to include the necessary exponent + // adjustment. + if a_abs < implicit_bit { + let (exponent, significand) = F::normalize(a_significand); + res_exponent += exponent; + a_significand = significand; + } + + // b is denormal. Renormalize it and set the scale to include the necessary exponent + // adjustment. + if b_abs < implicit_bit { + let (exponent, significand) = F::normalize(b_significand); + res_exponent -= exponent; + b_significand = significand; + } + } + + // Set the implicit significand bit. If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything. + a_significand |= implicit_bit; + b_significand |= implicit_bit; + + // Transform to a fixed-point representation by shifting the significand to the high bits. We + // know this is in the range [1.0, 2.0] since the implicit bit is set to 1 above. + let b_uq1 = b_significand << (F::BITS - significand_bits - 1); + + // Align the significand of b as a UQ1.(n-1) fixed-point number in the range + // [1.0, 2.0) and get a UQ0.n approximate reciprocal using a small minimax + // polynomial approximation: x0 = 3/4 + 1/sqrt(2) - b/2. + // The max error for this approximation is achieved at endpoints, so + // abs(x0(b) - 1/b) <= abs(x0(1) - 1/1) = 3/4 - 1/sqrt(2) = 0.04289..., + // which is about 4.5 bits. + // The initial approximation is between x0(1.0) = 0.9571... and x0(2.0) = 0.4571... + // + // Then, refine the reciprocal estimate using a quadratically converging + // Newton-Raphson iteration: + // x_{n+1} = x_n * (2 - x_n * b) + // + // Let b be the original divisor considered "in infinite precision" and + // obtained from IEEE754 representation of function argument (with the + // implicit bit set). Corresponds to rep_t-sized b_UQ1 represented in + // UQ1.(W-1). + // + // Let b_hw be an infinitely precise number obtained from the highest (HW-1) + // bits of divisor significand (with the implicit bit set). Corresponds to + // half_rep_t-sized b_UQ1_hw represented in UQ1.(HW-1) that is a **truncated** + // version of b_UQ1. + // + // Let e_n := x_n - 1/b_hw + // E_n := x_n - 1/b + // abs(E_n) <= abs(e_n) + (1/b_hw - 1/b) + // = abs(e_n) + (b - b_hw) / (b*b_hw) + // <= abs(e_n) + 2 * 2^-HW + // + // rep_t-sized iterations may be slower than the corresponding half-width + // variant depending on the handware and whether single/double/quad precision + // is selected. + // + // NB: Using half-width iterations increases computation errors due to + // rounding, so error estimations have to be computed taking the selected + // mode into account! + let mut x_uq0 = if half_iterations > 0 { + // Starting with (n-1) half-width iterations + let b_uq1_hw: HalfRep = b_uq1.hi(); + + // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW + // with W0 being either 16 or 32 and W0 <= HW. + // That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from which + // b/2 is subtracted to obtain x0) wrapped to [0, 1) range. + let c_hw = c_hw::(); + + // Check that the top bit is set, i.e. value is within `[1, 2)`. + debug_assert!(b_uq1_hw & (one_hw << (HalfRep::::BITS - 1)) > zero_hw); + + // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, + // so x0 fits to UQ0.HW without wrapping. + let mut x_uq0_hw: HalfRep = + c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); + + // An e_0 error is comprised of errors due to + // * x0 being an inherently imprecise first approximation of 1/b_hw + // * C_hw being some (irrational) number **truncated** to W0 bits + // Please note that e_0 is calculated against the infinitely precise + // reciprocal of b_hw (that is, **truncated** version of b). + // + // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0 + // + // By construction, 1 <= b < 2 + // f(x) = x * (2 - b*x) = 2*x - b*x^2 + // f'(x) = 2 * (1 - b*x) + // + // On the [0, 1] interval, f(0) = 0, + // then it increses until f(1/b) = 1 / b, maximum on (0, 1), + // then it decreses to f(1) = 2 - b + // + // Let g(x) = x - f(x) = b*x^2 - x. + // On (0, 1/b), g(x) < 0 <=> f(x) > x + // On (1/b, 1], g(x) > 0 <=> f(x) < x + // + // For half-width iterations, b_hw is used instead of b. + for _ in 0..half_iterations { + // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp + // of corr_UQ1_hw. + // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1). + // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided + // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is + // expected to be strictly positive because b_UQ1_hw has its highest bit set + // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). + // + // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally + // obtaining an UQ1.(HW-1) number and proving its highest bit could be + // considered to be 0 to be able to represent it in UQ0.HW. + // From the above analysis of f(x), if corr_UQ1_hw would be represented + // without any intermediate loss of precision (that is, in twice_rep_t) + // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly + // less otherwise. On the other hand, to obtain [1.]000..., one have to pass + // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due + // to 1.0 being not representable as UQ0.HW). + // The fact corr_UQ1_hw was virtually round up (due to result of + // multiplication being **first** truncated, then negated - to improve + // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. + // + // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t + // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after + // any number of iterations, so just subtract 2 from the reciprocal + // approximation after last iteration. + // + // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW: + // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1 + // = 1 - e_n * b_hw + 2*eps1 + // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2 + // = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2 + // = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw + // \------ >0 -------/ \-- >0 ---/ + // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U) + x_uq0_hw = next_guess(x_uq0_hw, b_uq1_hw); + } + + // For initial half-width iterations, U = 2^-HW + // Let abs(e_n) <= u_n * U, + // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U) + // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2) + // + // Account for possible overflow (see above). For an overflow to occur for the + // first time, for "ideal" corr_UQ1_hw (that is, without intermediate + // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum + // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to + // be not below that value (see g(x) above), so it is safe to decrement just + // once after the final iteration. On the other hand, an effective value of + // divisor changes after this point (from b_hw to b), so adjust here. + x_uq0_hw = x_uq0_hw.wrapping_sub(one_hw); + + // Error estimations for full-precision iterations are calculated just + // as above, but with U := 2^-W and taking extra decrementing into account. + // We need at least one such iteration. + // + // Simulating operations on a twice_rep_t to perform a single final full-width + // iteration. Using ad-hoc multiplication implementations to take advantage + // of particular structure of operands. + let blo: F::Int = b_uq1 & lo_mask; + + // x_UQ0 = x_UQ0_hw * 2^HW - 1 + // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1 + // + // <--- higher half ---><--- lower half ---> + // [x_UQ0_hw * b_UQ1_hw] + // + [ x_UQ0_hw * blo ] + // - [ b_UQ1 ] + // = [ result ][.... discarded ...] + let corr_uq1: F::Int = (F::Int::from(x_uq0_hw) * F::Int::from(b_uq1_hw) + + ((F::Int::from(x_uq0_hw) * blo) >> hw)) + .wrapping_sub(one) + .wrapping_neg(); // account for *possible* carry + + let lo_corr: F::Int = corr_uq1 & lo_mask; + let hi_corr: F::Int = corr_uq1 >> hw; + + // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1 + let mut x_uq0: F::Int = ((F::Int::from(x_uq0_hw) * hi_corr) << 1) + .wrapping_add((F::Int::from(x_uq0_hw) * lo_corr) >> (hw - 1)) + // 1 to account for the highest bit of corr_UQ1 can be 1 + // 1 to account for possible carry + // Just like the case of half-width iterations but with possibility + // of overflowing by one extra Ulp of x_UQ0. + .wrapping_sub(F::Int::from(2u8)); + + x_uq0 -= one; + // ... and then traditional fixup by 2 should work + + // On error estimation: + // abs(E_{N-1}) <= (u_{N-1} + 2 /* due to conversion e_n -> E_n */) * 2^-HW + // + (2^-HW + 2^-W)) + // abs(E_{N-1}) <= (u_{N-1} + 3.01) * 2^-HW + // + // Then like for the half-width iterations: + // With 0 <= eps1, eps2 < 2^-W + // E_N = 4 * E_{N-1} * eps1 - (E_{N-1}^2 * b + 4 * eps2) + 4 * eps1 / b + // abs(E_N) <= 2^-W * [ 4 * abs(E_{N-1}) + max(2 * abs(E_{N-1})^2 * 2^W + 4, 8)) ] + // abs(E_N) <= 2^-W * [ 4 * (u_{N-1} + 3.01) * 2^-HW + max(4 + 2 * (u_{N-1} + 3.01)^2, 8) ] + x_uq0 + } else { + // C is (3/4 + 1/sqrt(2)) - 1 truncated to 64 fractional bits as UQ0.n + let c: F::Int = F::Int::from(0x7504F333u32) << (F::BITS - 32); + let mut x_uq0: F::Int = c.wrapping_sub(b_uq1); + + // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-64 + // x_uq0 + for _ in 0..full_iterations { + x_uq0 = next_guess(x_uq0, b_uq1); + } + + x_uq0 + }; + + // Finally, account for possible overflow, as explained above. + x_uq0 = x_uq0.wrapping_sub(2.cast()); + + // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W + x_uq0 -= recip_precision.cast(); + + // Now 1/b - (2*P) * 2^-W < x < 1/b + // FIXME Is x_UQ0 still >= 0.5? + + let mut quotient_uq1: F::Int = x_uq0.widen_mul(a_significand << 1).hi(); + // Now, a/b - 4*P * 2^-W < q < a/b for q= in UQ1.(SB+1+W). + + // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1), + // adjust it to be in [1.0, 2.0) as UQ1.SB. + let mut residual_lo = if quotient_uq1 < (implicit_bit << 1) { + // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB, + // effectively doubling its value as well as its error estimation. + let residual_lo = (a_significand << (significand_bits + 1)) + .wrapping_sub(quotient_uq1.wrapping_mul(b_significand)); + res_exponent -= 1; + a_significand <<= 1; + residual_lo + } else { + // Highest bit is 1 (the UQ1.(SB+1) value is in [1, 2)), convert it + // to UQ1.SB by right shifting by 1. Least significant bit is omitted. + quotient_uq1 >>= 1; + (a_significand << significand_bits).wrapping_sub(quotient_uq1.wrapping_mul(b_significand)) + }; + + // drop mutability + let quotient = quotient_uq1; + + // NB: residualLo is calculated above for the normal result case. + // It is re-computed on denormal path that is expected to be not so + // performance-sensitive. + // + // Now, q cannot be greater than a/b and can differ by at most 8*P * 2^-W + 2^-SB + // Each NextAfter() increments the floating point value by at least 2^-SB + // (more, if exponent was incremented). + // Different cases (<---> is of 2^-SB length, * = a/b that is shown as a midpoint): + // q + // | | * | | | | | + // <---> 2^t + // | | | | | * | | + // q + // To require at most one NextAfter(), an error should be less than 1.5 * 2^-SB. + // (8*P) * 2^-W + 2^-SB < 1.5 * 2^-SB + // (8*P) * 2^-W < 0.5 * 2^-SB + // P < 2^(W-4-SB) + // Generally, for at most R NextAfter() to be enough, + // P < (2*R - 1) * 2^(W-4-SB) + // For f32 (0+3): 10 < 32 (OK) + // For f32 (2+1): 32 < 74 < 32 * 3, so two NextAfter() are required + // For f64: 220 < 256 (OK) + // For f128: 4096 * 3 < 13922 < 4096 * 5 (three NextAfter() are required) + // + // If we have overflowed the exponent, return infinity + if res_exponent >= i32::cast_from(exponent_sat) { + return F::from_bits(inf_rep | quotient_sign); + } + + // Now, quotient <= the correctly-rounded result + // and may need taking NextAfter() up to 3 times (see error estimates above) + // r = a - b * q + let mut abs_result = if res_exponent > 0 { + let mut ret = quotient & significand_mask; + ret |= F::Int::from(res_exponent as u32) << significand_bits; + residual_lo <<= 1; + ret + } else { + if ((significand_bits as i32) + res_exponent) < 0 { + return F::from_bits(quotient_sign); + } + + let ret = quotient.wrapping_shr(u32::cast_from(res_exponent.wrapping_neg()) + 1); + residual_lo = a_significand + .wrapping_shl(significand_bits.wrapping_add(CastInto::::cast(res_exponent))) + .wrapping_sub(ret.wrapping_mul(b_significand) << 1); + ret + }; + + residual_lo += abs_result & one; // tie to even + // conditionally turns the below LT comparison into LTE + abs_result += u8::from(residual_lo > b_significand).into(); + + if F::BITS == 128 || (F::BITS == 32 && half_iterations > 0) { + // Do not round Infinity to NaN + abs_result += + u8::from(abs_result < inf_rep && residual_lo > (2 + 1).cast() * b_significand).into(); + } + + if F::BITS == 128 { + abs_result += + u8::from(abs_result < inf_rep && residual_lo > (4 + 1).cast() * b_significand).into(); + } + + F::from_bits(abs_result | quotient_sign) +} + +/// Calculate the number of iterations required for a float type's precision. +/// +/// This returns `(h, f)` where `h` is the number of iterations to be done using integers at half +/// the float's bit width, and `f` is the number of iterations done using integers of the float's +/// full width. This is further explained in the module documentation. +/// +/// # Requirements +/// +/// The initial estimate should have at least 8 bits of precision. If this is not true, results +/// will be inaccurate. +const fn get_iterations() -> (usize, usize) { + // Precision doubles with each iteration. Assume we start with 8 bits of precision. + let total_iterations = F::BITS.ilog2() as usize - 2; + + if 2 * size_of::() <= size_of::<*const ()>() { + // If widening multiplication will be efficient (uses word-sized integers), there is no + // reason to use half-sized iterations. + (0, total_iterations) + } else { + // Otherwise, do as many iterations as possible at half width. + (total_iterations - 1, 1) + } +} + +/// `u_n` for different precisions (with N-1 half-width iterations). +/// +/// W0 is the precision of C +/// u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW +/// +/// Estimated with bc: +/// +/// ```text +/// define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; } +/// define half2(un) { return 2.0 * un / 2.0^hw + 2.0; } +/// define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; } +/// define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; } +/// +/// | f32 (0 + 3) | f32 (2 + 1) | f64 (3 + 1) | f128 (4 + 1) +/// u_0 | < 184224974 | < 2812.1 | < 184224974 | < 791240234244348797 +/// u_1 | < 15804007 | < 242.7 | < 15804007 | < 67877681371350440 +/// u_2 | < 116308 | < 2.81 | < 116308 | < 499533100252317 +/// u_3 | < 7.31 | | < 7.31 | < 27054456580 +/// u_4 | | | | < 80.4 +/// Final (U_N) | same as u_3 | < 72 | < 218 | < 13920 +/// ```` +/// +/// Add 2 to `U_N` due to final decrement. +const fn reciprocal_precision() -> u16 { + let (half_iterations, full_iterations) = get_iterations::(); + + if full_iterations < 1 { + panic!("Must have at least one full iteration"); + } + + // FIXME(tgross35): calculate this programmatically + if F::BITS == 32 && half_iterations == 2 && full_iterations == 1 { + 74u16 + } else if F::BITS == 32 && half_iterations == 0 && full_iterations == 3 { + 10 + } else if F::BITS == 64 && half_iterations == 3 && full_iterations == 1 { + 220 + } else if F::BITS == 128 && half_iterations == 4 && full_iterations == 1 { + 13922 + } else { + panic!("Invalid number of iterations") + } +} + +/// The value of `C` adjusted to half width. +/// +/// C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW with W0 being either +/// 16 or 32 and W0 <= HW. That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from +/// which b/2 is subtracted to obtain x0) wrapped to [0, 1) range. +fn c_hw() -> HalfRep +where + F::Int: DInt, + u128: CastInto>, +{ + const C_U128: u128 = 0x7504f333f9de6108b2fb1366eaa6a542; + const { C_U128 >> (u128::BITS - >::BITS) }.cast() +} + +/// Perform one iteration at any width to approach `1/b`, given previous guess `x`. Returns +/// the next `x` as a UQ0 number. +/// +/// This is the `x_{n+1} = 2*x_n - b*x_n^2` algorithm, implemented as `x_n * (2 - b*x_n)`. It +/// uses widening multiplication to calculate the result with necessary precision. +fn next_guess(x_uq0: I, b_uq1: I) -> I +where + I: Int + HInt, + ::D: ops::Shr::D>, +{ + // `corr = 2 - b*x_n` + // + // This looks like `0 - b*x_n`. However, this works - in `UQ1`, `0.0 - x = 2.0 - x`. + let corr_uq1: I = I::ZERO.wrapping_sub(x_uq0.widen_mul(b_uq1).hi()); + + // `x_n * corr = x_n * (2 - b*x_n)` + (x_uq0.widen_mul(corr_uq1) >> (I::BITS - 1)).lo() +} + +intrinsics! { + #[avr_skip] + #[arm_aeabi_alias = __aeabi_fdiv] + pub extern "C" fn __divsf3(a: f32, b: f32) -> f32 { + div(a, b) + } + + #[avr_skip] + #[arm_aeabi_alias = __aeabi_ddiv] + pub extern "C" fn __divdf3(a: f64, b: f64) -> f64 { + div(a, b) + } + + #[avr_skip] + #[ppc_alias = __divkf3] + #[cfg(f128_enabled)] + pub extern "C" fn __divtf3(a: f128, b: f128) -> f128 { + div(a, b) + } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __divsf3vfp(a: f32, b: f32) -> f32 { + a / b + } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __divdf3vfp(a: f64, b: f64) -> f64 { + a / b + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/compiler-builtins/src/float/extend.rs new file mode 100644 index 00000000000..ce00da31dc5 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/float/extend.rs @@ -0,0 +1,130 @@ +use crate::float::Float; +use crate::int::{CastInto, Int, MinInt}; + +/// Generic conversion from a narrower to a wider IEEE-754 floating-point type +fn extend(a: F) -> R +where + F::Int: CastInto, + u64: CastInto, + u32: CastInto, + R::Int: CastInto, + R::Int: CastInto, + u64: CastInto, + F::Int: CastInto, +{ + let src_zero = F::Int::ZERO; + let src_one = F::Int::ONE; + let src_bits = F::BITS; + let src_sig_bits = F::SIG_BITS; + let src_exp_bias = F::EXP_BIAS; + let src_min_normal = F::IMPLICIT_BIT; + let src_infinity = F::EXP_MASK; + let src_sign_mask = F::SIGN_MASK; + let src_abs_mask = src_sign_mask - src_one; + let src_qnan = F::SIG_MASK; + let src_nan_code = src_qnan - src_one; + + let dst_bits = R::BITS; + let dst_sig_bits = R::SIG_BITS; + let dst_inf_exp = R::EXP_SAT; + let dst_exp_bias = R::EXP_BIAS; + let dst_min_normal = R::IMPLICIT_BIT; + + let sig_bits_delta = dst_sig_bits - src_sig_bits; + let exp_bias_delta = dst_exp_bias - src_exp_bias; + let a_abs = a.to_bits() & src_abs_mask; + let mut abs_result = R::Int::ZERO; + + if a_abs.wrapping_sub(src_min_normal) < src_infinity.wrapping_sub(src_min_normal) { + // a is a normal number. + // Extend to the destination type by shifting the significand and + // exponent into the proper position and rebiasing the exponent. + let abs_dst: R::Int = a_abs.cast(); + let bias_dst: R::Int = exp_bias_delta.cast(); + abs_result = abs_dst.wrapping_shl(sig_bits_delta); + abs_result += bias_dst.wrapping_shl(dst_sig_bits); + } else if a_abs >= src_infinity { + // a is NaN or infinity. + // Conjure the result by beginning with infinity, then setting the qNaN + // bit (if needed) and right-aligning the rest of the trailing NaN + // payload field. + let qnan_dst: R::Int = (a_abs & src_qnan).cast(); + let nan_code_dst: R::Int = (a_abs & src_nan_code).cast(); + let inf_exp_dst: R::Int = dst_inf_exp.cast(); + abs_result = inf_exp_dst.wrapping_shl(dst_sig_bits); + abs_result |= qnan_dst.wrapping_shl(sig_bits_delta); + abs_result |= nan_code_dst.wrapping_shl(sig_bits_delta); + } else if a_abs != src_zero { + // a is denormal. + // Renormalize the significand and clear the leading bit, then insert + // the correct adjusted exponent in the destination type. + let scale = a_abs.leading_zeros() - src_min_normal.leading_zeros(); + let abs_dst: R::Int = a_abs.cast(); + let bias_dst: R::Int = (exp_bias_delta - scale + 1).cast(); + abs_result = abs_dst.wrapping_shl(sig_bits_delta + scale); + abs_result = (abs_result ^ dst_min_normal) | (bias_dst.wrapping_shl(dst_sig_bits)); + } + + let sign_result: R::Int = (a.to_bits() & src_sign_mask).cast(); + R::from_bits(abs_result | (sign_result.wrapping_shl(dst_bits - src_bits))) +} + +intrinsics! { + #[avr_skip] + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_f2d] + pub extern "C" fn __extendsfdf2(a: f32) -> f64 { + extend(a) + } +} + +intrinsics! { + #[avr_skip] + #[aapcs_on_arm] + #[apple_f16_arg_abi] + #[arm_aeabi_alias = __aeabi_h2f] + #[cfg(f16_enabled)] + pub extern "C" fn __extendhfsf2(a: f16) -> f32 { + extend(a) + } + + #[avr_skip] + #[aapcs_on_arm] + #[apple_f16_arg_abi] + #[cfg(f16_enabled)] + pub extern "C" fn __gnu_h2f_ieee(a: f16) -> f32 { + extend(a) + } + + #[avr_skip] + #[aapcs_on_arm] + #[apple_f16_arg_abi] + #[cfg(f16_enabled)] + pub extern "C" fn __extendhfdf2(a: f16) -> f64 { + extend(a) + } + + #[avr_skip] + #[aapcs_on_arm] + #[ppc_alias = __extendhfkf2] + #[cfg(all(f16_enabled, f128_enabled))] + pub extern "C" fn __extendhftf2(a: f16) -> f128 { + extend(a) + } + + #[avr_skip] + #[aapcs_on_arm] + #[ppc_alias = __extendsfkf2] + #[cfg(f128_enabled)] + pub extern "C" fn __extendsftf2(a: f32) -> f128 { + extend(a) + } + + #[avr_skip] + #[aapcs_on_arm] + #[ppc_alias = __extenddfkf2] + #[cfg(f128_enabled)] + pub extern "C" fn __extenddftf2(a: f64) -> f128 { + extend(a) + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/compiler-builtins/src/float/mod.rs new file mode 100644 index 00000000000..41b308626b3 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/float/mod.rs @@ -0,0 +1,16 @@ +pub mod add; +pub mod cmp; +pub mod conv; +pub mod div; +pub mod extend; +pub mod mul; +pub mod pow; +pub mod sub; +pub(crate) mod traits; +pub mod trunc; + +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use traits::{Float, HalfRep}; + +#[cfg(feature = "public-test-deps")] +pub use traits::{Float, HalfRep}; diff --git a/library/compiler-builtins/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/compiler-builtins/src/float/mul.rs new file mode 100644 index 00000000000..58636cb5ebe --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/float/mul.rs @@ -0,0 +1,202 @@ +use crate::float::Float; +use crate::int::{CastInto, DInt, HInt, Int, MinInt}; + +fn mul(a: F, b: F) -> F +where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, + F::Int: HInt, +{ + let one = F::Int::ONE; + let zero = F::Int::ZERO; + + let bits = F::BITS; + let significand_bits = F::SIG_BITS; + let max_exponent = F::EXP_SAT; + + let exponent_bias = F::EXP_BIAS; + + let implicit_bit = F::IMPLICIT_BIT; + let significand_mask = F::SIG_MASK; + let sign_bit = F::SIGN_MASK; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXP_MASK; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + let exponent_bits = F::EXP_BITS; + + let a_rep = a.to_bits(); + let b_rep = b.to_bits(); + + let a_exponent = (a_rep >> significand_bits) & max_exponent.cast(); + let b_exponent = (b_rep >> significand_bits) & max_exponent.cast(); + let product_sign = (a_rep ^ b_rep) & sign_bit; + + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + let mut scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if a_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + || b_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + { + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // NaN + anything = qNaN + if a_abs > inf_rep { + return F::from_bits(a_rep | quiet_bit); + } + // anything + NaN = qNaN + if b_abs > inf_rep { + return F::from_bits(b_rep | quiet_bit); + } + + if a_abs == inf_rep { + if b_abs != zero { + // infinity * non-zero = +/- infinity + return F::from_bits(a_abs | product_sign); + } else { + // infinity * zero = NaN + return F::from_bits(qnan_rep); + } + } + + if b_abs == inf_rep { + if a_abs != zero { + // infinity * non-zero = +/- infinity + return F::from_bits(b_abs | product_sign); + } else { + // infinity * zero = NaN + return F::from_bits(qnan_rep); + } + } + + // zero * anything = +/- zero + if a_abs == zero { + return F::from_bits(product_sign); + } + + // anything * zero = +/- zero + if b_abs == zero { + return F::from_bits(product_sign); + } + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if a_abs < implicit_bit { + let (exponent, significand) = F::normalize(a_significand); + scale += exponent; + a_significand = significand; + } + + if b_abs < implicit_bit { + let (exponent, significand) = F::normalize(b_significand); + scale += exponent; + b_significand = significand; + } + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + a_significand |= implicit_bit; + b_significand |= implicit_bit; + + // Get the significand of a*b. Before multiplying the significands, shift + // one of them left to left-align it in the field. Thus, the product will + // have (exponentBits + 2) integral digits, all but two of which must be + // zero. Normalizing this result is just a conditional left-shift by one + // and bumping the exponent accordingly. + let (mut product_low, mut product_high) = a_significand + .widen_mul(b_significand << exponent_bits) + .lo_hi(); + + let a_exponent_i32: i32 = a_exponent.cast(); + let b_exponent_i32: i32 = b_exponent.cast(); + let mut product_exponent: i32 = a_exponent_i32 + .wrapping_add(b_exponent_i32) + .wrapping_add(scale) + .wrapping_sub(exponent_bias as i32); + + // Normalize the significand, adjust exponent if needed. + if (product_high & implicit_bit) != zero { + product_exponent = product_exponent.wrapping_add(1); + } else { + product_high = (product_high << 1) | (product_low >> (bits - 1)); + product_low <<= 1; + } + + // If we have overflowed the type, return +/- infinity. + if product_exponent >= max_exponent as i32 { + return F::from_bits(inf_rep | product_sign); + } + + if product_exponent <= 0 { + // Result is denormal before rounding + // + // If the result is so small that it just underflows to zero, return + // a zero of the appropriate sign. Mathematically there is no need to + // handle this case separately, but we make it a special case to + // simplify the shift logic. + let shift = one.wrapping_sub(product_exponent.cast()).cast(); + if shift >= bits { + return F::from_bits(product_sign); + } + + // Otherwise, shift the significand of the result so that the round + // bit is the high bit of `product_low`. + // Ensure one of the non-highest bits in `product_low` is set if the shifted out bit are + // not all zero so that the result is correctly rounded below. + let sticky = product_low << (bits - shift) != zero; + product_low = + (product_high << (bits - shift)) | (product_low >> shift) | (sticky as u32).cast(); + product_high >>= shift; + } else { + // Result is normal before rounding; insert the exponent. + product_high &= significand_mask; + product_high |= product_exponent.cast() << significand_bits; + } + + // Insert the sign of the result: + product_high |= product_sign; + + // Final rounding. The final result may overflow to infinity, or underflow + // to zero, but those are the correct results in those cases. We use the + // default IEEE-754 round-to-nearest, ties-to-even rounding mode. + if product_low > sign_bit { + product_high += one; + } + + if product_low == sign_bit { + product_high += product_high & one; + } + + F::from_bits(product_high) +} + +intrinsics! { + #[avr_skip] + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_fmul] + pub extern "C" fn __mulsf3(a: f32, b: f32) -> f32 { + mul(a, b) + } + + #[avr_skip] + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_dmul] + pub extern "C" fn __muldf3(a: f64, b: f64) -> f64 { + mul(a, b) + } + + #[ppc_alias = __mulkf3] + #[cfg(f128_enabled)] + pub extern "C" fn __multf3(a: f128, b: f128) -> f128 { + mul(a, b) + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/compiler-builtins/src/float/pow.rs new file mode 100644 index 00000000000..dac768f7be3 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/float/pow.rs @@ -0,0 +1,47 @@ +use crate::float::Float; +use crate::int::Int; + +/// Returns `a` raised to the power `b` +fn pow(a: F, b: i32) -> F { + let mut a = a; + let recip = b < 0; + let mut pow = Int::abs_diff(b, 0); + let mut mul = F::ONE; + loop { + if (pow & 1) != 0 { + mul *= a; + } + pow >>= 1; + if pow == 0 { + break; + } + a *= a; + } + + if recip { + F::ONE / mul + } else { + mul + } +} + +intrinsics! { + #[avr_skip] + pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 { + pow(a, b) + } + + #[avr_skip] + pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 { + pow(a, b) + } + + #[avr_skip] + #[ppc_alias = __powikf2] + #[cfg(f128_enabled)] + // FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly. + #[cfg(not(target_env = "msvc"))] + pub extern "C" fn __powitf2(a: f128, b: i32) -> f128 { + pow(a, b) + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/compiler-builtins/src/float/sub.rs new file mode 100644 index 00000000000..175b3a16500 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/float/sub.rs @@ -0,0 +1,26 @@ +use crate::float::Float; + +intrinsics! { + #[avr_skip] + #[arm_aeabi_alias = __aeabi_fsub] + pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { + crate::float::add::__addsf3(a, f32::from_bits(b.to_bits() ^ f32::SIGN_MASK)) + } + + #[avr_skip] + #[arm_aeabi_alias = __aeabi_dsub] + pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { + crate::float::add::__adddf3(a, f64::from_bits(b.to_bits() ^ f64::SIGN_MASK)) + } + + #[ppc_alias = __subkf3] + #[cfg(f128_enabled)] + pub extern "C" fn __subtf3(a: f128, b: f128) -> f128 { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + use crate::float::add::__addkf3 as __addtf3; + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + use crate::float::add::__addtf3; + + __addtf3(a, f128::from_bits(b.to_bits() ^ f128::SIGN_MASK)) + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/compiler-builtins/src/float/traits.rs new file mode 100644 index 00000000000..8ccaa7bcbd7 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/float/traits.rs @@ -0,0 +1,189 @@ +use core::ops; + +use crate::int::{DInt, Int, MinInt}; + +/// Wrapper to extract the integer type half of the float's size +pub type HalfRep = <::Int as DInt>::H; + +/// Trait for some basic operations on floats +#[allow(dead_code)] +pub trait Float: + Copy + + core::fmt::Debug + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::MulAssign + + ops::Add + + ops::Sub + + ops::Div + + ops::Rem +{ + /// A uint of the same width as the float + type Int: Int; + + /// A int of the same width as the float + type SignedInt: Int + MinInt; + + /// An int capable of containing the exponent bits plus a sign bit. This is signed. + type ExpInt: Int; + + const ZERO: Self; + const ONE: Self; + + /// The bitwidth of the float type. + const BITS: u32; + + /// The bitwidth of the significand. + const SIG_BITS: u32; + + /// The bitwidth of the exponent. + const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; + + /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite + /// representation. + /// + /// This is in the rightmost position, use `EXP_MASK` for the shifted value. + const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; + + /// The exponent bias value. + const EXP_BIAS: u32 = Self::EXP_SAT >> 1; + + /// A mask for the sign bit. + const SIGN_MASK: Self::Int; + + /// A mask for the significand. + const SIG_MASK: Self::Int; + + /// The implicit bit of the float format. + const IMPLICIT_BIT: Self::Int; + + /// A mask for the exponent. + const EXP_MASK: Self::Int; + + /// Returns `self` transmuted to `Self::Int` + fn to_bits(self) -> Self::Int; + + /// Returns `self` transmuted to `Self::SignedInt` + fn to_bits_signed(self) -> Self::SignedInt; + + /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be + /// represented in multiple different ways. This method returns `true` if two NaNs are + /// compared. + fn eq_repr(self, rhs: Self) -> bool; + + /// Returns true if the sign is negative + fn is_sign_negative(self) -> bool; + + /// Returns the exponent, not adjusting for bias. + fn exp(self) -> Self::ExpInt; + + /// Returns the significand with no implicit bit (or the "fractional" part) + fn frac(self) -> Self::Int; + + /// Returns the significand with implicit bit + fn imp_frac(self) -> Self::Int; + + /// Returns a `Self::Int` transmuted back to `Self` + fn from_bits(a: Self::Int) -> Self; + + /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self; + + fn abs(self) -> Self { + let abs_mask = !Self::SIGN_MASK; + Self::from_bits(self.to_bits() & abs_mask) + } + + /// Returns (normalized exponent, normalized significand) + fn normalize(significand: Self::Int) -> (i32, Self::Int); + + /// Returns if `self` is subnormal + fn is_subnormal(self) -> bool; +} + +macro_rules! float_impl { + ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { + impl Float for $ty { + type Int = $ity; + type SignedInt = $sity; + type ExpInt = $expty; + + const ZERO: Self = 0.0; + const ONE: Self = 1.0; + + const BITS: u32 = $bits; + const SIG_BITS: u32 = $significand_bits; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; + const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); + + fn to_bits(self) -> Self::Int { + self.to_bits() + } + fn to_bits_signed(self) -> Self::SignedInt { + self.to_bits() as Self::SignedInt + } + fn eq_repr(self, rhs: Self) -> bool { + #[cfg(feature = "mangled-names")] + fn is_nan(x: $ty) -> bool { + // When using mangled-names, the "real" compiler-builtins might not have the + // necessary builtin (__unordtf2) to test whether `f128` is NaN. + // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin + // x is NaN if all the bits of the exponent are set and the significand is non-0 + x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 + } + #[cfg(not(feature = "mangled-names"))] + fn is_nan(x: $ty) -> bool { + x.is_nan() + } + if is_nan(self) && is_nan(rhs) { + true + } else { + self.to_bits() == rhs.to_bits() + } + } + fn is_sign_negative(self) -> bool { + self.is_sign_negative() + } + fn exp(self) -> Self::ExpInt { + ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt + } + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIG_MASK + } + fn imp_frac(self) -> Self::Int { + self.frac() | Self::IMPLICIT_BIT + } + fn from_bits(a: Self::Int) -> Self { + Self::from_bits(a) + } + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_bits( + ((negative as Self::Int) << (Self::BITS - 1)) + | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) + | (significand & Self::SIG_MASK), + ) + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); + ( + 1i32.wrapping_sub(shift as i32), + significand << shift as Self::Int, + ) + } + fn is_subnormal(self) -> bool { + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO + } + } + }; +} + +#[cfg(f16_enabled)] +float_impl!(f16, u16, i16, i8, 16, 10); +float_impl!(f32, u32, i32, i16, 32, 23); +float_impl!(f64, u64, i64, i16, 64, 52); +#[cfg(f128_enabled)] +float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs new file mode 100644 index 00000000000..928eba0c8ef --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs @@ -0,0 +1,176 @@ +use crate::float::Float; +use crate::int::{CastInto, Int, MinInt}; + +fn trunc(a: F) -> R +where + F::Int: CastInto, + F::Int: CastInto, + u64: CastInto, + u32: CastInto, + R::Int: CastInto, + u32: CastInto, + F::Int: CastInto, +{ + let src_zero = F::Int::ZERO; + let src_one = F::Int::ONE; + let src_bits = F::BITS; + let src_exp_bias = F::EXP_BIAS; + + let src_min_normal = F::IMPLICIT_BIT; + let src_sig_mask = F::SIG_MASK; + let src_infinity = F::EXP_MASK; + let src_sign_mask = F::SIGN_MASK; + let src_abs_mask = src_sign_mask - src_one; + let round_mask = (src_one << (F::SIG_BITS - R::SIG_BITS)) - src_one; + let halfway = src_one << (F::SIG_BITS - R::SIG_BITS - 1); + let src_qnan = src_one << (F::SIG_BITS - 1); + let src_nan_code = src_qnan - src_one; + + let dst_zero = R::Int::ZERO; + let dst_one = R::Int::ONE; + let dst_bits = R::BITS; + let dst_inf_exp = R::EXP_SAT; + let dst_exp_bias = R::EXP_BIAS; + + let underflow_exponent: F::Int = (src_exp_bias + 1 - dst_exp_bias).cast(); + let overflow_exponent: F::Int = (src_exp_bias + dst_inf_exp - dst_exp_bias).cast(); + let underflow: F::Int = underflow_exponent << F::SIG_BITS; + let overflow: F::Int = overflow_exponent << F::SIG_BITS; + + let dst_qnan = R::Int::ONE << (R::SIG_BITS - 1); + let dst_nan_code = dst_qnan - dst_one; + + let sig_bits_delta = F::SIG_BITS - R::SIG_BITS; + // Break a into a sign and representation of the absolute value. + let a_abs = a.to_bits() & src_abs_mask; + let sign = a.to_bits() & src_sign_mask; + let mut abs_result: R::Int; + + if a_abs.wrapping_sub(underflow) < a_abs.wrapping_sub(overflow) { + // The exponent of a is within the range of normal numbers in the + // destination format. We can convert by simply right-shifting with + // rounding and adjusting the exponent. + abs_result = (a_abs >> sig_bits_delta).cast(); + // Cast before shifting to prevent overflow. + let bias_diff: R::Int = src_exp_bias.wrapping_sub(dst_exp_bias).cast(); + let tmp = bias_diff << R::SIG_BITS; + abs_result = abs_result.wrapping_sub(tmp); + + let round_bits = a_abs & round_mask; + if round_bits > halfway { + // Round to nearest. + abs_result += dst_one; + } else if round_bits == halfway { + // Tie to even. + abs_result += abs_result & dst_one; + }; + } else if a_abs > src_infinity { + // a is NaN. + // Conjure the result by beginning with infinity, setting the qNaN + // bit and inserting the (truncated) trailing NaN field. + // Cast before shifting to prevent overflow. + let dst_inf_exp: R::Int = dst_inf_exp.cast(); + abs_result = dst_inf_exp << R::SIG_BITS; + abs_result |= dst_qnan; + abs_result |= dst_nan_code & ((a_abs & src_nan_code) >> (F::SIG_BITS - R::SIG_BITS)).cast(); + } else if a_abs >= overflow { + // a overflows to infinity. + // Cast before shifting to prevent overflow. + let dst_inf_exp: R::Int = dst_inf_exp.cast(); + abs_result = dst_inf_exp << R::SIG_BITS; + } else { + // a underflows on conversion to the destination type or is an exact + // zero. The result may be a denormal or zero. Extract the exponent + // to get the shift amount for the denormalization. + let a_exp: u32 = (a_abs >> F::SIG_BITS).cast(); + let shift = src_exp_bias - dst_exp_bias - a_exp + 1; + + let significand = (a.to_bits() & src_sig_mask) | src_min_normal; + + // Right shift by the denormalization amount with sticky. + if shift > F::SIG_BITS { + abs_result = dst_zero; + } else { + let sticky = if (significand << (src_bits - shift)) != src_zero { + src_one + } else { + src_zero + }; + let denormalized_significand: F::Int = (significand >> shift) | sticky; + abs_result = (denormalized_significand >> (F::SIG_BITS - R::SIG_BITS)).cast(); + let round_bits = denormalized_significand & round_mask; + // Round to nearest + if round_bits > halfway { + abs_result += dst_one; + } + // Ties to even + else if round_bits == halfway { + abs_result += abs_result & dst_one; + }; + } + } + + // Apply the signbit to the absolute value. + R::from_bits(abs_result | sign.wrapping_shr(src_bits - dst_bits).cast()) +} + +intrinsics! { + #[avr_skip] + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_d2f] + pub extern "C" fn __truncdfsf2(a: f64) -> f32 { + trunc(a) + } +} + +intrinsics! { + #[avr_skip] + #[aapcs_on_arm] + #[apple_f16_ret_abi] + #[arm_aeabi_alias = __aeabi_f2h] + #[cfg(f16_enabled)] + pub extern "C" fn __truncsfhf2(a: f32) -> f16 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + #[apple_f16_ret_abi] + #[cfg(f16_enabled)] + pub extern "C" fn __gnu_f2h_ieee(a: f32) -> f16 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + #[apple_f16_ret_abi] + #[arm_aeabi_alias = __aeabi_d2h] + #[cfg(f16_enabled)] + pub extern "C" fn __truncdfhf2(a: f64) -> f16 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + #[ppc_alias = __trunckfhf2] + #[cfg(all(f16_enabled, f128_enabled))] + pub extern "C" fn __trunctfhf2(a: f128) -> f16 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + #[ppc_alias = __trunckfsf2] + #[cfg(f128_enabled)] + pub extern "C" fn __trunctfsf2(a: f128) -> f32 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + #[ppc_alias = __trunckfdf2] + #[cfg(f128_enabled)] + pub extern "C" fn __trunctfdf2(a: f128) -> f64 { + trunc(a) + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon.rs b/library/compiler-builtins/compiler-builtins/src/hexagon.rs new file mode 100644 index 00000000000..91cf91c3142 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon.rs @@ -0,0 +1,55 @@ +#![cfg(not(feature = "no-asm"))] + +use core::arch::global_asm; + +global_asm!(include_str!("hexagon/func_macro.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfaddsub.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfdiv.s"), options(raw)); + +global_asm!(include_str!("hexagon/dffma.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfminmax.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfmul.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfsqrt.s"), options(raw)); + +global_asm!(include_str!("hexagon/divdi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/divsi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/fastmath2_dlib_asm.s"), options(raw)); + +global_asm!(include_str!("hexagon/fastmath2_ldlib_asm.s"), options(raw)); + +global_asm!( + include_str!("hexagon/memcpy_forward_vp4cp4n2.s"), + options(raw) +); + +global_asm!( + include_str!("hexagon/memcpy_likely_aligned.s"), + options(raw) +); + +global_asm!(include_str!("hexagon/moddi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/modsi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/sfdiv_opt.s"), options(raw)); + +global_asm!(include_str!("hexagon/sfsqrt_opt.s"), options(raw)); + +global_asm!(include_str!("hexagon/udivdi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/udivmoddi4.s"), options(raw)); + +global_asm!(include_str!("hexagon/udivmodsi4.s"), options(raw)); + +global_asm!(include_str!("hexagon/udivsi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/umoddi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/umodsi3.s"), options(raw)); diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/dfaddsub.s b/library/compiler-builtins/compiler-builtins/src/hexagon/dfaddsub.s new file mode 100644 index 00000000000..1f59e460be6 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/dfaddsub.s @@ -0,0 +1,321 @@ + .text + .global __hexagon_adddf3 + .global __hexagon_subdf3 + .type __hexagon_adddf3, @function + .type __hexagon_subdf3, @function + +.global __qdsp_adddf3 ; .set __qdsp_adddf3, __hexagon_adddf3 +.global __hexagon_fast_adddf3 ; .set __hexagon_fast_adddf3, __hexagon_adddf3 +.global __hexagon_fast2_adddf3 ; .set __hexagon_fast2_adddf3, __hexagon_adddf3 +.global __qdsp_subdf3 ; .set __qdsp_subdf3, __hexagon_subdf3 +.global __hexagon_fast_subdf3 ; .set __hexagon_fast_subdf3, __hexagon_subdf3 +.global __hexagon_fast2_subdf3 ; .set __hexagon_fast2_subdf3, __hexagon_subdf3 + + .p2align 5 +__hexagon_adddf3: + { + r4 = extractu(r1,#11,#20) + r5 = extractu(r3,#11,#20) + r13:12 = combine(##0x20000000,#0) + } + { + p3 = dfclass(r1:0,#2) + p3 = dfclass(r3:2,#2) + r9:8 = r13:12 + p2 = cmp.gtu(r5,r4) + } + { + if (!p3) jump .Ladd_abnormal + if (p2) r1:0 = r3:2 + if (p2) r3:2 = r1:0 + if (p2) r5:4 = combine(r4,r5) + } + { + r13:12 = insert(r1:0,#52,#11 -2) + r9:8 = insert(r3:2,#52,#11 -2) + r15 = sub(r4,r5) + r7:6 = combine(#62,#1) + } + + + + + +.Ladd_continue: + { + r15 = min(r15,r7) + + r11:10 = neg(r13:12) + p2 = cmp.gt(r1,#-1) + r14 = #0 + } + { + if (!p2) r13:12 = r11:10 + r11:10 = extractu(r9:8,r15:14) + r9:8 = ASR(r9:8,r15) + + + + + r15:14 = #0 + } + { + p1 = cmp.eq(r11:10,r15:14) + if (!p1.new) r8 = or(r8,r6) + r5 = add(r4,#-1024 -60) + p3 = cmp.gt(r3,#-1) + } + { + r13:12 = add(r13:12,r9:8) + r11:10 = sub(r13:12,r9:8) + r7:6 = combine(#54,##2045) + } + { + p0 = cmp.gtu(r4,r7) + p0 = !cmp.gtu(r4,r6) + if (!p0.new) jump:nt .Ladd_ovf_unf + if (!p3) r13:12 = r11:10 + } + { + r1:0 = convert_d2df(r13:12) + p0 = cmp.eq(r13,#0) + p0 = cmp.eq(r12,#0) + if (p0.new) jump:nt .Ladd_zero + } + { + r1 += asl(r5,#20) + jumpr r31 + } + .falign +__hexagon_subdf3: + { + r3 = togglebit(r3,#31) + jump __qdsp_adddf3 + } + + + .falign +.Ladd_zero: + + + { + r28 = USR + r1:0 = #0 + r3 = #1 + } + { + r28 = extractu(r28,#2,#22) + r3 = asl(r3,#31) + } + { + p0 = cmp.eq(r28,#2) + if (p0.new) r1 = xor(r1,r3) + jumpr r31 + } + .falign +.Ladd_ovf_unf: + { + r1:0 = convert_d2df(r13:12) + p0 = cmp.eq(r13,#0) + p0 = cmp.eq(r12,#0) + if (p0.new) jump:nt .Ladd_zero + } + { + r28 = extractu(r1,#11,#20) + r1 += asl(r5,#20) + } + { + r5 = add(r5,r28) + r3:2 = combine(##0x00100000,#0) + } + { + p0 = cmp.gt(r5,##1024 +1024 -2) + if (p0.new) jump:nt .Ladd_ovf + } + { + p0 = cmp.gt(r5,#0) + if (p0.new) jumpr:t r31 + r28 = sub(#1,r5) + } + { + r3:2 = insert(r1:0,#52,#0) + r1:0 = r13:12 + } + { + r3:2 = lsr(r3:2,r28) + } + { + r1:0 = insert(r3:2,#63,#0) + jumpr r31 + } + .falign +.Ladd_ovf: + + { + r1:0 = r13:12 + r28 = USR + r13:12 = combine(##0x7fefffff,#-1) + } + { + r5 = extractu(r28,#2,#22) + r28 = or(r28,#0x28) + r9:8 = combine(##0x7ff00000,#0) + } + { + USR = r28 + r5 ^= lsr(r1,#31) + r28 = r5 + } + { + p0 = !cmp.eq(r28,#1) + p0 = !cmp.eq(r5,#2) + if (p0.new) r13:12 = r9:8 + } + { + r1:0 = insert(r13:12,#63,#0) + } + { + p0 = dfcmp.eq(r1:0,r1:0) + jumpr r31 + } + +.Ladd_abnormal: + { + r13:12 = extractu(r1:0,#63,#0) + r9:8 = extractu(r3:2,#63,#0) + } + { + p3 = cmp.gtu(r13:12,r9:8) + if (!p3.new) r1:0 = r3:2 + if (!p3.new) r3:2 = r1:0 + } + { + + p0 = dfclass(r1:0,#0x0f) + if (!p0.new) jump:nt .Linvalid_nan_add + if (!p3) r13:12 = r9:8 + if (!p3) r9:8 = r13:12 + } + { + + + p1 = dfclass(r1:0,#0x08) + if (p1.new) jump:nt .Linf_add + } + { + p2 = dfclass(r3:2,#0x01) + if (p2.new) jump:nt .LB_zero + r13:12 = #0 + } + + { + p0 = dfclass(r1:0,#4) + if (p0.new) jump:nt .Ladd_two_subnormal + r13:12 = combine(##0x20000000,#0) + } + { + r4 = extractu(r1,#11,#20) + r5 = #1 + + r9:8 = asl(r9:8,#11 -2) + } + + + + { + r13:12 = insert(r1:0,#52,#11 -2) + r15 = sub(r4,r5) + r7:6 = combine(#62,#1) + jump .Ladd_continue + } + +.Ladd_two_subnormal: + { + r13:12 = extractu(r1:0,#63,#0) + r9:8 = extractu(r3:2,#63,#0) + } + { + r13:12 = neg(r13:12) + r9:8 = neg(r9:8) + p0 = cmp.gt(r1,#-1) + p1 = cmp.gt(r3,#-1) + } + { + if (p0) r13:12 = r1:0 + if (p1) r9:8 = r3:2 + } + { + r13:12 = add(r13:12,r9:8) + } + { + r9:8 = neg(r13:12) + p0 = cmp.gt(r13,#-1) + r3:2 = #0 + } + { + if (!p0) r1:0 = r9:8 + if (p0) r1:0 = r13:12 + r3 = ##0x80000000 + } + { + if (!p0) r1 = or(r1,r3) + p0 = dfcmp.eq(r1:0,r3:2) + if (p0.new) jump:nt .Lzero_plus_zero + } + { + jumpr r31 + } + +.Linvalid_nan_add: + { + r28 = convert_df2sf(r1:0) + p0 = dfclass(r3:2,#0x0f) + if (p0.new) r3:2 = r1:0 + } + { + r2 = convert_df2sf(r3:2) + r1:0 = #-1 + jumpr r31 + } + .falign +.LB_zero: + { + p0 = dfcmp.eq(r13:12,r1:0) + if (!p0.new) jumpr:t r31 + } + + + + +.Lzero_plus_zero: + { + p0 = cmp.eq(r1:0,r3:2) + if (p0.new) jumpr:t r31 + } + { + r28 = USR + } + { + r28 = extractu(r28,#2,#22) + r1:0 = #0 + } + { + p0 = cmp.eq(r28,#2) + if (p0.new) r1 = ##0x80000000 + jumpr r31 + } +.Linf_add: + + { + p0 = !cmp.eq(r1,r3) + p0 = dfclass(r3:2,#8) + if (!p0.new) jumpr:t r31 + } + { + r2 = ##0x7f800001 + } + { + r1:0 = convert_sf2df(r2) + jumpr r31 + } +.size __hexagon_adddf3,.-__hexagon_adddf3 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/dfdiv.s b/library/compiler-builtins/compiler-builtins/src/hexagon/dfdiv.s new file mode 100644 index 00000000000..6d65dbfc4df --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/dfdiv.s @@ -0,0 +1,372 @@ + .text + .global __hexagon_divdf3 + .type __hexagon_divdf3,@function + .global __qdsp_divdf3 ; .set __qdsp_divdf3, __hexagon_divdf3 + .global __hexagon_fast_divdf3 ; .set __hexagon_fast_divdf3, __hexagon_divdf3 + .global __hexagon_fast2_divdf3 ; .set __hexagon_fast2_divdf3, __hexagon_divdf3 + .p2align 5 +__hexagon_divdf3: + { + p2 = dfclass(r1:0,#0x02) + p2 = dfclass(r3:2,#0x02) + r13:12 = combine(r3,r1) + r28 = xor(r1,r3) + } + { + if (!p2) jump .Ldiv_abnormal + r7:6 = extractu(r3:2,#23,#52 -23) + r8 = ##0x3f800001 + } + { + r9 = or(r8,r6) + r13 = extractu(r13,#11,#52 -32) + r12 = extractu(r12,#11,#52 -32) + p3 = cmp.gt(r28,#-1) + } + + +.Ldenorm_continue: + { + r11,p0 = sfrecipa(r8,r9) + r10 = and(r8,#-2) + r28 = #1 + r12 = sub(r12,r13) + } + + + { + r10 -= sfmpy(r11,r9):lib + r1 = insert(r28,#11 +1,#52 -32) + r13 = ##0x00800000 << 3 + } + { + r11 += sfmpy(r11,r10):lib + r3 = insert(r28,#11 +1,#52 -32) + r10 = and(r8,#-2) + } + { + r10 -= sfmpy(r11,r9):lib + r5 = #-0x3ff +1 + r4 = #0x3ff -1 + } + { + r11 += sfmpy(r11,r10):lib + p1 = cmp.gt(r12,r5) + p1 = !cmp.gt(r12,r4) + } + { + r13 = insert(r11,#23,#3) + r5:4 = #0 + r12 = add(r12,#-61) + } + + + + + { + r13 = add(r13,#((-3) << 3)) + } + { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASL(r7:6, # ( 14 )); r1:0 -= asl(r15:14, # 32); } + { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASR(r7:6, # ( 1 )); r1:0 -= asl(r15:14, # 32); } + { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASR(r7:6, # ( 16 )); r1:0 -= asl(r15:14, # 32); } + { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASR(r7:6, # ( 31 )); r1:0 -= asl(r15:14, # 32); r7:6=# ( 0 ); } + + + + + + + + { + + r15:14 = sub(r1:0,r3:2) + p0 = cmp.gtu(r3:2,r1:0) + + if (!p0.new) r6 = #2 + } + { + r5:4 = add(r5:4,r7:6) + if (!p0) r1:0 = r15:14 + r15:14 = #0 + } + { + p0 = cmp.eq(r1:0,r15:14) + if (!p0.new) r4 = or(r4,r28) + } + { + r7:6 = neg(r5:4) + } + { + if (!p3) r5:4 = r7:6 + } + { + r1:0 = convert_d2df(r5:4) + if (!p1) jump .Ldiv_ovf_unf + } + { + r1 += asl(r12,#52 -32) + jumpr r31 + } + +.Ldiv_ovf_unf: + { + r1 += asl(r12,#52 -32) + r13 = extractu(r1,#11,#52 -32) + } + { + r7:6 = abs(r5:4) + r12 = add(r12,r13) + } + { + p0 = cmp.gt(r12,##0x3ff +0x3ff) + if (p0.new) jump:nt .Ldiv_ovf + } + { + p0 = cmp.gt(r12,#0) + if (p0.new) jump:nt .Lpossible_unf2 + } + { + r13 = add(clb(r7:6),#-1) + r12 = sub(#7,r12) + r10 = USR + r11 = #63 + } + { + r13 = min(r12,r11) + r11 = or(r10,#0x030) + r7:6 = asl(r7:6,r13) + r12 = #0 + } + { + r15:14 = extractu(r7:6,r13:12) + r7:6 = lsr(r7:6,r13) + r3:2 = #1 + } + { + p0 = cmp.gtu(r3:2,r15:14) + if (!p0.new) r6 = or(r2,r6) + r7 = setbit(r7,#52 -32+4) + } + { + r5:4 = neg(r7:6) + p0 = bitsclr(r6,#(1<<4)-1) + if (!p0.new) r10 = r11 + } + { + USR = r10 + if (p3) r5:4 = r7:6 + r10 = #-0x3ff -(52 +4) + } + { + r1:0 = convert_d2df(r5:4) + } + { + r1 += asl(r10,#52 -32) + jumpr r31 + } + + +.Lpossible_unf2: + + + { + r3:2 = extractu(r1:0,#63,#0) + r15:14 = combine(##0x00100000,#0) + r10 = #0x7FFF + } + { + p0 = dfcmp.eq(r15:14,r3:2) + p0 = bitsset(r7,r10) + } + + + + + + + { + if (!p0) jumpr r31 + r10 = USR + } + + { + r10 = or(r10,#0x30) + } + { + USR = r10 + } + { + p0 = dfcmp.eq(r1:0,r1:0) + jumpr r31 + } + +.Ldiv_ovf: + + + + { + r10 = USR + r3:2 = combine(##0x7fefffff,#-1) + r1 = mux(p3,#0,#-1) + } + { + r7:6 = combine(##0x7ff00000,#0) + r5 = extractu(r10,#2,#22) + r10 = or(r10,#0x28) + } + { + USR = r10 + r5 ^= lsr(r1,#31) + r4 = r5 + } + { + p0 = !cmp.eq(r4,#1) + p0 = !cmp.eq(r5,#2) + if (p0.new) r3:2 = r7:6 + p0 = dfcmp.eq(r3:2,r3:2) + } + { + r1:0 = insert(r3:2,#63,#0) + jumpr r31 + } + + + + + + + +.Ldiv_abnormal: + { + p0 = dfclass(r1:0,#0x0F) + p0 = dfclass(r3:2,#0x0F) + p3 = cmp.gt(r28,#-1) + } + { + p1 = dfclass(r1:0,#0x08) + p1 = dfclass(r3:2,#0x08) + } + { + p2 = dfclass(r1:0,#0x01) + p2 = dfclass(r3:2,#0x01) + } + { + if (!p0) jump .Ldiv_nan + if (p1) jump .Ldiv_invalid + } + { + if (p2) jump .Ldiv_invalid + } + { + p2 = dfclass(r1:0,#(0x0F ^ 0x01)) + p2 = dfclass(r3:2,#(0x0F ^ 0x08)) + } + { + p1 = dfclass(r1:0,#(0x0F ^ 0x08)) + p1 = dfclass(r3:2,#(0x0F ^ 0x01)) + } + { + if (!p2) jump .Ldiv_zero_result + if (!p1) jump .Ldiv_inf_result + } + + + + + + { + p0 = dfclass(r1:0,#0x02) + p1 = dfclass(r3:2,#0x02) + r10 = ##0x00100000 + } + { + r13:12 = combine(r3,r1) + r1 = insert(r10,#11 +1,#52 -32) + r3 = insert(r10,#11 +1,#52 -32) + } + { + if (p0) r1 = or(r1,r10) + if (p1) r3 = or(r3,r10) + } + { + r5 = add(clb(r1:0),#-11) + r4 = add(clb(r3:2),#-11) + r10 = #1 + } + { + r12 = extractu(r12,#11,#52 -32) + r13 = extractu(r13,#11,#52 -32) + } + { + r1:0 = asl(r1:0,r5) + r3:2 = asl(r3:2,r4) + if (!p0) r12 = sub(r10,r5) + if (!p1) r13 = sub(r10,r4) + } + { + r7:6 = extractu(r3:2,#23,#52 -23) + } + { + r9 = or(r8,r6) + jump .Ldenorm_continue + } + +.Ldiv_zero_result: + { + r1 = xor(r1,r3) + r3:2 = #0 + } + { + r1:0 = insert(r3:2,#63,#0) + jumpr r31 + } +.Ldiv_inf_result: + { + p2 = dfclass(r3:2,#0x01) + p2 = dfclass(r1:0,#(0x0F ^ 0x08)) + } + { + r10 = USR + if (!p2) jump 1f + r1 = xor(r1,r3) + } + { + r10 = or(r10,#0x04) + } + { + USR = r10 + } +1: + { + r3:2 = combine(##0x7ff00000,#0) + p0 = dfcmp.uo(r3:2,r3:2) + } + { + r1:0 = insert(r3:2,#63,#0) + jumpr r31 + } +.Ldiv_nan: + { + p0 = dfclass(r1:0,#0x10) + p1 = dfclass(r3:2,#0x10) + if (!p0.new) r1:0 = r3:2 + if (!p1.new) r3:2 = r1:0 + } + { + r5 = convert_df2sf(r1:0) + r4 = convert_df2sf(r3:2) + } + { + r1:0 = #-1 + jumpr r31 + } + +.Ldiv_invalid: + { + r10 = ##0x7f800001 + } + { + r1:0 = convert_sf2df(r10) + jumpr r31 + } +.size __hexagon_divdf3,.-__hexagon_divdf3 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/dffma.s b/library/compiler-builtins/compiler-builtins/src/hexagon/dffma.s new file mode 100644 index 00000000000..97d05eb1839 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/dffma.s @@ -0,0 +1,534 @@ + .text + .global __hexagon_fmadf4 + .type __hexagon_fmadf4,@function + .global __hexagon_fmadf5 + .type __hexagon_fmadf5,@function + .global __qdsp_fmadf5 ; .set __qdsp_fmadf5, __hexagon_fmadf5 + .p2align 5 +__hexagon_fmadf4: +__hexagon_fmadf5: +fma: + { + p0 = dfclass(r1:0,#2) + p0 = dfclass(r3:2,#2) + r13:12 = #0 + r15:14 = #0 + } + { + r13:12 = insert(r1:0,#52,#11 -3) + r15:14 = insert(r3:2,#52,#11 -3) + r7 = ##0x10000000 + allocframe(#32) + } + { + r9:8 = mpyu(r12,r14) + if (!p0) jump .Lfma_abnormal_ab + r13 = or(r13,r7) + r15 = or(r15,r7) + } + { + p0 = dfclass(r5:4,#2) + if (!p0.new) jump:nt .Lfma_abnormal_c + r11:10 = combine(r7,#0) + r7:6 = combine(#0,r9) + } +.Lfma_abnormal_c_restart: + { + r7:6 += mpyu(r14,r13) + r11:10 = insert(r5:4,#52,#11 -3) + memd(r29+#0) = r17:16 + memd(r29+#8) = r19:18 + } + { + r7:6 += mpyu(r12,r15) + r19:18 = neg(r11:10) + p0 = cmp.gt(r5,#-1) + r28 = xor(r1,r3) + } + { + r18 = extractu(r1,#11,#20) + r19 = extractu(r3,#11,#20) + r17:16 = combine(#0,r7) + if (!p0) r11:10 = r19:18 + } + { + r17:16 += mpyu(r13,r15) + r9:8 = combine(r6,r8) + r18 = add(r18,r19) + + + + + r19 = extractu(r5,#11,#20) + } + { + r18 = add(r18,#-1023 +(4)) + p3 = !cmp.gt(r28,#-1) + r7:6 = #0 + r15:14 = #0 + } + { + r7:6 = sub(r7:6,r9:8,p3):carry + p0 = !cmp.gt(r28,#-1) + p1 = cmp.gt(r19,r18) + if (p1.new) r19:18 = combine(r18,r19) + } + { + r15:14 = sub(r15:14,r17:16,p3):carry + if (p0) r9:8 = r7:6 + + + + + r7:6 = #0 + r19 = sub(r18,r19) + } + { + if (p0) r17:16 = r15:14 + p0 = cmp.gt(r19,#63) + if (p1) r9:8 = r7:6 + if (p1) r7:6 = r9:8 + } + + + + + + + + { + if (p1) r17:16 = r11:10 + if (p1) r11:10 = r17:16 + if (p0) r19 = add(r19,#-64) + r28 = #63 + } + { + + if (p0) r7:6 = r11:10 + r28 = asr(r11,#31) + r13 = min(r19,r28) + r12 = #0 + } + + + + + + + { + if (p0) r11:10 = combine(r28,r28) + r5:4 = extract(r7:6,r13:12) + r7:6 = lsr(r7:6,r13) + r12 = sub(#64,r13) + } + { + r15:14 = #0 + r28 = #-2 + r7:6 |= lsl(r11:10,r12) + r11:10 = asr(r11:10,r13) + } + { + p3 = cmp.gtu(r5:4,r15:14) + if (p3.new) r6 = and(r6,r28) + + + + r15:14 = #1 + r5:4 = #0 + } + { + r9:8 = add(r7:6,r9:8,p3):carry + } + { + r17:16 = add(r11:10,r17:16,p3):carry + r28 = #62 + } + + + + + + + + { + r12 = add(clb(r17:16),#-2) + if (!cmp.eq(r12.new,r28)) jump:t 1f + } + + { + r11:10 = extractu(r9:8,#62,#2) + r9:8 = asl(r9:8,#62) + r18 = add(r18,#-62) + } + { + r17:16 = insert(r11:10,#62,#0) + } + { + r12 = add(clb(r17:16),#-2) + } + .falign +1: + { + r11:10 = asl(r17:16,r12) + r5:4 |= asl(r9:8,r12) + r13 = sub(#64,r12) + r18 = sub(r18,r12) + } + { + r11:10 |= lsr(r9:8,r13) + p2 = cmp.gtu(r15:14,r5:4) + r28 = #1023 +1023 -2 + } + { + if (!p2) r10 = or(r10,r14) + + p0 = !cmp.gt(r18,r28) + p0 = cmp.gt(r18,#1) + if (!p0.new) jump:nt .Lfma_ovf_unf + } + { + + p0 = cmp.gtu(r15:14,r11:10) + r1:0 = convert_d2df(r11:10) + r18 = add(r18,#-1023 -60) + r17:16 = memd(r29+#0) + } + { + r1 += asl(r18,#20) + r19:18 = memd(r29+#8) + if (!p0) dealloc_return + } +.Ladd_yields_zero: + + { + r28 = USR + r1:0 = #0 + } + { + r28 = extractu(r28,#2,#22) + r17:16 = memd(r29+#0) + r19:18 = memd(r29+#8) + } + { + p0 = cmp.eq(r28,#2) + if (p0.new) r1 = ##0x80000000 + dealloc_return + } +.Lfma_ovf_unf: + { + p0 = cmp.gtu(r15:14,r11:10) + if (p0.new) jump:nt .Ladd_yields_zero + } + { + r1:0 = convert_d2df(r11:10) + r18 = add(r18,#-1023 -60) + r28 = r18 + } + + + { + r1 += asl(r18,#20) + r7 = extractu(r1,#11,#20) + } + { + r6 = add(r18,r7) + r17:16 = memd(r29+#0) + r19:18 = memd(r29+#8) + r9:8 = abs(r11:10) + } + { + p0 = cmp.gt(r6,##1023 +1023) + if (p0.new) jump:nt .Lfma_ovf + } + { + p0 = cmp.gt(r6,#0) + if (p0.new) jump:nt .Lpossible_unf0 + } + { + + + + r7 = add(clb(r9:8),#-2) + r6 = sub(#1+5,r28) + p3 = cmp.gt(r11,#-1) + } + + + + { + r6 = add(r6,r7) + r9:8 = asl(r9:8,r7) + r1 = USR + r28 = #63 + } + { + r7 = min(r6,r28) + r6 = #0 + r0 = #0x0030 + } + { + r3:2 = extractu(r9:8,r7:6) + r9:8 = asr(r9:8,r7) + } + { + p0 = cmp.gtu(r15:14,r3:2) + if (!p0.new) r8 = or(r8,r14) + r9 = setbit(r9,#20 +3) + } + { + r11:10 = neg(r9:8) + p1 = bitsclr(r8,#(1<<3)-1) + if (!p1.new) r1 = or(r1,r0) + r3:2 = #0 + } + { + if (p3) r11:10 = r9:8 + USR = r1 + r28 = #-1023 -(52 +3) + } + { + r1:0 = convert_d2df(r11:10) + } + { + r1 += asl(r28,#20) + dealloc_return + } +.Lpossible_unf0: + { + r28 = ##0x7fefffff + r9:8 = abs(r11:10) + } + { + p0 = cmp.eq(r0,#0) + p0 = bitsclr(r1,r28) + if (!p0.new) dealloc_return:t + r28 = #0x7fff + } + { + p0 = bitsset(r9,r28) + r3 = USR + r2 = #0x0030 + } + { + if (p0) r3 = or(r3,r2) + } + { + USR = r3 + } + { + p0 = dfcmp.eq(r1:0,r1:0) + dealloc_return + } +.Lfma_ovf: + { + r28 = USR + r11:10 = combine(##0x7fefffff,#-1) + r1:0 = r11:10 + } + { + r9:8 = combine(##0x7ff00000,#0) + r3 = extractu(r28,#2,#22) + r28 = or(r28,#0x28) + } + { + USR = r28 + r3 ^= lsr(r1,#31) + r2 = r3 + } + { + p0 = !cmp.eq(r2,#1) + p0 = !cmp.eq(r3,#2) + } + { + p0 = dfcmp.eq(r9:8,r9:8) + if (p0.new) r11:10 = r9:8 + } + { + r1:0 = insert(r11:10,#63,#0) + dealloc_return + } +.Lfma_abnormal_ab: + { + r9:8 = extractu(r1:0,#63,#0) + r11:10 = extractu(r3:2,#63,#0) + deallocframe + } + { + p3 = cmp.gtu(r9:8,r11:10) + if (!p3.new) r1:0 = r3:2 + if (!p3.new) r3:2 = r1:0 + } + { + p0 = dfclass(r1:0,#0x0f) + if (!p0.new) jump:nt .Lnan + if (!p3) r9:8 = r11:10 + if (!p3) r11:10 = r9:8 + } + { + p1 = dfclass(r1:0,#0x08) + p1 = dfclass(r3:2,#0x0e) + } + { + p0 = dfclass(r1:0,#0x08) + p0 = dfclass(r3:2,#0x01) + } + { + if (p1) jump .Lab_inf + p2 = dfclass(r3:2,#0x01) + } + { + if (p0) jump .Linvalid + if (p2) jump .Lab_true_zero + r28 = ##0x7c000000 + } + + + + + + { + p0 = bitsclr(r1,r28) + if (p0.new) jump:nt .Lfma_ab_tiny + } + { + r28 = add(clb(r11:10),#-11) + } + { + r11:10 = asl(r11:10,r28) + } + { + r3:2 = insert(r11:10,#63,#0) + r1 -= asl(r28,#20) + } + jump fma + +.Lfma_ab_tiny: + r9:8 = combine(##0x00100000,#0) + { + r1:0 = insert(r9:8,#63,#0) + r3:2 = insert(r9:8,#63,#0) + } + jump fma + +.Lab_inf: + { + r3:2 = lsr(r3:2,#63) + p0 = dfclass(r5:4,#0x10) + } + { + r1:0 ^= asl(r3:2,#63) + if (p0) jump .Lnan + } + { + p1 = dfclass(r5:4,#0x08) + if (p1.new) jump:nt .Lfma_inf_plus_inf + } + + { + jumpr r31 + } + .falign +.Lfma_inf_plus_inf: + { + p0 = dfcmp.eq(r1:0,r5:4) + if (!p0.new) jump:nt .Linvalid + } + { + jumpr r31 + } + +.Lnan: + { + p0 = dfclass(r3:2,#0x10) + p1 = dfclass(r5:4,#0x10) + if (!p0.new) r3:2 = r1:0 + if (!p1.new) r5:4 = r1:0 + } + { + r3 = convert_df2sf(r3:2) + r2 = convert_df2sf(r5:4) + } + { + r3 = convert_df2sf(r1:0) + r1:0 = #-1 + jumpr r31 + } + +.Linvalid: + { + r28 = ##0x7f800001 + } + { + r1:0 = convert_sf2df(r28) + jumpr r31 + } + +.Lab_true_zero: + + { + p0 = dfclass(r5:4,#0x10) + if (p0.new) jump:nt .Lnan + if (p0.new) r1:0 = r5:4 + } + { + p0 = dfcmp.eq(r3:2,r5:4) + r1 = lsr(r1,#31) + } + { + r3 ^= asl(r1,#31) + if (!p0) r1:0 = r5:4 + if (!p0) jumpr r31 + } + + { + p0 = cmp.eq(r3:2,r5:4) + if (p0.new) jumpr:t r31 + r1:0 = r3:2 + } + { + r28 = USR + } + { + r28 = extractu(r28,#2,#22) + r1:0 = #0 + } + { + p0 = cmp.eq(r28,#2) + if (p0.new) r1 = ##0x80000000 + jumpr r31 + } + + + + + .falign +.Lfma_abnormal_c: + + + { + p0 = dfclass(r5:4,#0x10) + if (p0.new) jump:nt .Lnan + if (p0.new) r1:0 = r5:4 + deallocframe + } + { + p0 = dfclass(r5:4,#0x08) + if (p0.new) r1:0 = r5:4 + if (p0.new) jumpr:nt r31 + } + + + { + p0 = dfclass(r5:4,#0x01) + if (p0.new) jump:nt __hexagon_muldf3 + r28 = #1 + } + + + { + allocframe(#32) + r11:10 = #0 + r5 = insert(r28,#11,#20) + jump .Lfma_abnormal_c_restart + } +.size fma,.-fma diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/dfminmax.s b/library/compiler-builtins/compiler-builtins/src/hexagon/dfminmax.s new file mode 100644 index 00000000000..953e773bf19 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/dfminmax.s @@ -0,0 +1,45 @@ + .text + .global __hexagon_mindf3 + .global __hexagon_maxdf3 + .type __hexagon_mindf3,@function + .type __hexagon_maxdf3,@function + .global __qdsp_mindf3 ; .set __qdsp_mindf3, __hexagon_mindf3 + .global __qdsp_maxdf3 ; .set __qdsp_maxdf3, __hexagon_maxdf3 + .p2align 5 +__hexagon_mindf3: + { + p0 = dfclass(r1:0,#0x10) + p1 = dfcmp.gt(r1:0,r3:2) + r5:4 = r1:0 + } + { + if (p0) r1:0 = r3:2 + if (p1) r1:0 = r3:2 + p2 = dfcmp.eq(r1:0,r3:2) + if (!p2.new) jumpr:t r31 + } + + { + r1:0 = or(r5:4,r3:2) + jumpr r31 + } +.size __hexagon_mindf3,.-__hexagon_mindf3 + .falign +__hexagon_maxdf3: + { + p0 = dfclass(r1:0,#0x10) + p1 = dfcmp.gt(r3:2,r1:0) + r5:4 = r1:0 + } + { + if (p0) r1:0 = r3:2 + if (p1) r1:0 = r3:2 + p2 = dfcmp.eq(r1:0,r3:2) + if (!p2.new) jumpr:t r31 + } + + { + r1:0 = and(r5:4,r3:2) + jumpr r31 + } +.size __hexagon_maxdf3,.-__hexagon_maxdf3 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/dfmul.s b/library/compiler-builtins/compiler-builtins/src/hexagon/dfmul.s new file mode 100644 index 00000000000..32fc674f975 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/dfmul.s @@ -0,0 +1,309 @@ + .text + .global __hexagon_muldf3 + .type __hexagon_muldf3,@function + .global __qdsp_muldf3 ; .set __qdsp_muldf3, __hexagon_muldf3 + .global __hexagon_fast_muldf3 ; .set __hexagon_fast_muldf3, __hexagon_muldf3 + .global __hexagon_fast2_muldf3 ; .set __hexagon_fast2_muldf3, __hexagon_muldf3 + .p2align 5 +__hexagon_muldf3: + { + p0 = dfclass(r1:0,#2) + p0 = dfclass(r3:2,#2) + r13:12 = combine(##0x40000000,#0) + } + { + r13:12 = insert(r1:0,#52,#11 -1) + r5:4 = asl(r3:2,#11 -1) + r28 = #-1024 + r9:8 = #1 + } + { + r7:6 = mpyu(r4,r13) + r5:4 = insert(r9:8,#2,#62) + } + + + + + { + r15:14 = mpyu(r12,r4) + r7:6 += mpyu(r12,r5) + } + { + r7:6 += lsr(r15:14,#32) + r11:10 = mpyu(r13,r5) + r5:4 = combine(##1024 +1024 -4,#0) + } + { + r11:10 += lsr(r7:6,#32) + if (!p0) jump .Lmul_abnormal + p1 = cmp.eq(r14,#0) + p1 = cmp.eq(r6,#0) + } + { + if (!p1) r10 = or(r10,r8) + r6 = extractu(r1,#11,#20) + r7 = extractu(r3,#11,#20) + } + { + r15:14 = neg(r11:10) + r6 += add(r28,r7) + r28 = xor(r1,r3) + } + { + if (!p2.new) r11:10 = r15:14 + p2 = cmp.gt(r28,#-1) + p0 = !cmp.gt(r6,r5) + p0 = cmp.gt(r6,r4) + if (!p0.new) jump:nt .Lmul_ovf_unf + } + { + r1:0 = convert_d2df(r11:10) + r6 = add(r6,#-1024 -58) + } + { + r1 += asl(r6,#20) + jumpr r31 + } + + .falign +.Lpossible_unf1: + { + p0 = cmp.eq(r0,#0) + p0 = bitsclr(r1,r4) + if (!p0.new) jumpr:t r31 + r5 = #0x7fff + } + { + p0 = bitsset(r13,r5) + r4 = USR + r5 = #0x030 + } + { + if (p0) r4 = or(r4,r5) + } + { + USR = r4 + } + { + p0 = dfcmp.eq(r1:0,r1:0) + jumpr r31 + } + .falign +.Lmul_ovf_unf: + { + r1:0 = convert_d2df(r11:10) + r13:12 = abs(r11:10) + r7 = add(r6,#-1024 -58) + } + { + r1 += asl(r7,#20) + r7 = extractu(r1,#11,#20) + r4 = ##0x7FEFFFFF + } + { + r7 += add(r6,##-1024 -58) + + r5 = #0 + } + { + p0 = cmp.gt(r7,##1024 +1024 -2) + if (p0.new) jump:nt .Lmul_ovf + } + { + p0 = cmp.gt(r7,#0) + if (p0.new) jump:nt .Lpossible_unf1 + r5 = sub(r6,r5) + r28 = #63 + } + { + r4 = #0 + r5 = sub(#5,r5) + } + { + p3 = cmp.gt(r11,#-1) + r5 = min(r5,r28) + r11:10 = r13:12 + } + { + r28 = USR + r15:14 = extractu(r11:10,r5:4) + } + { + r11:10 = asr(r11:10,r5) + r4 = #0x0030 + r1 = insert(r9,#11,#20) + } + { + p0 = cmp.gtu(r9:8,r15:14) + if (!p0.new) r10 = or(r10,r8) + r11 = setbit(r11,#20 +3) + } + { + r15:14 = neg(r11:10) + p1 = bitsclr(r10,#0x7) + if (!p1.new) r28 = or(r4,r28) + } + { + if (!p3) r11:10 = r15:14 + USR = r28 + } + { + r1:0 = convert_d2df(r11:10) + p0 = dfcmp.eq(r1:0,r1:0) + } + { + r1 = insert(r9,#11 -1,#20 +1) + jumpr r31 + } + .falign +.Lmul_ovf: + + { + r28 = USR + r13:12 = combine(##0x7fefffff,#-1) + r1:0 = r11:10 + } + { + r14 = extractu(r28,#2,#22) + r28 = or(r28,#0x28) + r5:4 = combine(##0x7ff00000,#0) + } + { + USR = r28 + r14 ^= lsr(r1,#31) + r28 = r14 + } + { + p0 = !cmp.eq(r28,#1) + p0 = !cmp.eq(r14,#2) + if (p0.new) r13:12 = r5:4 + p0 = dfcmp.eq(r1:0,r1:0) + } + { + r1:0 = insert(r13:12,#63,#0) + jumpr r31 + } + +.Lmul_abnormal: + { + r13:12 = extractu(r1:0,#63,#0) + r5:4 = extractu(r3:2,#63,#0) + } + { + p3 = cmp.gtu(r13:12,r5:4) + if (!p3.new) r1:0 = r3:2 + if (!p3.new) r3:2 = r1:0 + } + { + + p0 = dfclass(r1:0,#0x0f) + if (!p0.new) jump:nt .Linvalid_nan + if (!p3) r13:12 = r5:4 + if (!p3) r5:4 = r13:12 + } + { + + p1 = dfclass(r1:0,#0x08) + p1 = dfclass(r3:2,#0x0e) + } + { + + + p0 = dfclass(r1:0,#0x08) + p0 = dfclass(r3:2,#0x01) + } + { + if (p1) jump .Ltrue_inf + p2 = dfclass(r3:2,#0x01) + } + { + if (p0) jump .Linvalid_zeroinf + if (p2) jump .Ltrue_zero + r28 = ##0x7c000000 + } + + + + + + { + p0 = bitsclr(r1,r28) + if (p0.new) jump:nt .Lmul_tiny + } + { + r28 = cl0(r5:4) + } + { + r28 = add(r28,#-11) + } + { + r5:4 = asl(r5:4,r28) + } + { + r3:2 = insert(r5:4,#63,#0) + r1 -= asl(r28,#20) + } + jump __hexagon_muldf3 +.Lmul_tiny: + { + r28 = USR + r1:0 = xor(r1:0,r3:2) + } + { + r28 = or(r28,#0x30) + r1:0 = insert(r9:8,#63,#0) + r5 = extractu(r28,#2,#22) + } + { + USR = r28 + p0 = cmp.gt(r5,#1) + if (!p0.new) r0 = #0 + r5 ^= lsr(r1,#31) + } + { + p0 = cmp.eq(r5,#3) + if (!p0.new) r0 = #0 + jumpr r31 + } +.Linvalid_zeroinf: + { + r28 = USR + } + { + r1:0 = #-1 + r28 = or(r28,#2) + } + { + USR = r28 + } + { + p0 = dfcmp.uo(r1:0,r1:0) + jumpr r31 + } +.Linvalid_nan: + { + p0 = dfclass(r3:2,#0x0f) + r28 = convert_df2sf(r1:0) + if (p0.new) r3:2 = r1:0 + } + { + r2 = convert_df2sf(r3:2) + r1:0 = #-1 + jumpr r31 + } + .falign +.Ltrue_zero: + { + r1:0 = r3:2 + r3:2 = r1:0 + } +.Ltrue_inf: + { + r3 = extract(r3,#1,#31) + } + { + r1 ^= asl(r3,#31) + jumpr r31 + } +.size __hexagon_muldf3,.-__hexagon_muldf3 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/dfsqrt.s b/library/compiler-builtins/compiler-builtins/src/hexagon/dfsqrt.s new file mode 100644 index 00000000000..14f584a1133 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/dfsqrt.s @@ -0,0 +1,277 @@ + .text + .global __hexagon_sqrtdf2 + .type __hexagon_sqrtdf2,@function + .global __hexagon_sqrt + .type __hexagon_sqrt,@function + .global __qdsp_sqrtdf2 ; .set __qdsp_sqrtdf2, __hexagon_sqrtdf2; .type __qdsp_sqrtdf2,@function + .global __qdsp_sqrt ; .set __qdsp_sqrt, __hexagon_sqrt; .type __qdsp_sqrt,@function + .global __hexagon_fast_sqrtdf2 ; .set __hexagon_fast_sqrtdf2, __hexagon_sqrtdf2; .type __hexagon_fast_sqrtdf2,@function + .global __hexagon_fast_sqrt ; .set __hexagon_fast_sqrt, __hexagon_sqrt; .type __hexagon_fast_sqrt,@function + .global __hexagon_fast2_sqrtdf2 ; .set __hexagon_fast2_sqrtdf2, __hexagon_sqrtdf2; .type __hexagon_fast2_sqrtdf2,@function + .global __hexagon_fast2_sqrt ; .set __hexagon_fast2_sqrt, __hexagon_sqrt; .type __hexagon_fast2_sqrt,@function + .type sqrt,@function + .p2align 5 +__hexagon_sqrtdf2: +__hexagon_sqrt: + { + r15:14 = extractu(r1:0,#23 +1,#52 -23) + r28 = extractu(r1,#11,#52 -32) + r5:4 = combine(##0x3f000004,#1) + } + { + p2 = dfclass(r1:0,#0x02) + p2 = cmp.gt(r1,#-1) + if (!p2.new) jump:nt .Lsqrt_abnormal + r9 = or(r5,r14) + } + +.Ldenormal_restart: + { + r11:10 = r1:0 + r7,p0 = sfinvsqrta(r9) + r5 = and(r5,#-16) + r3:2 = #0 + } + { + r3 += sfmpy(r7,r9):lib + r2 += sfmpy(r7,r5):lib + r6 = r5 + + + r9 = and(r28,#1) + } + { + r6 -= sfmpy(r3,r2):lib + r11 = insert(r4,#11 +1,#52 -32) + p1 = cmp.gtu(r9,#0) + } + { + r3 += sfmpy(r3,r6):lib + r2 += sfmpy(r2,r6):lib + r6 = r5 + r9 = mux(p1,#8,#9) + } + { + r6 -= sfmpy(r3,r2):lib + r11:10 = asl(r11:10,r9) + r9 = mux(p1,#3,#2) + } + { + r2 += sfmpy(r2,r6):lib + + r15:14 = asl(r11:10,r9) + } + { + r2 = and(r2,##0x007fffff) + } + { + r2 = add(r2,##0x00800000 - 3) + r9 = mux(p1,#7,#8) + } + { + r8 = asl(r2,r9) + r9 = mux(p1,#15-(1+1),#15-(1+0)) + } + { + r13:12 = mpyu(r8,r15) + } + { + r1:0 = asl(r11:10,#15) + r15:14 = mpyu(r13,r13) + p1 = cmp.eq(r0,r0) + } + { + r1:0 -= asl(r15:14,#15) + r15:14 = mpyu(r13,r12) + p2 = cmp.eq(r0,r0) + } + { + r1:0 -= lsr(r15:14,#16) + p3 = cmp.eq(r0,r0) + } + { + r1:0 = mpyu(r1,r8) + } + { + r13:12 += lsr(r1:0,r9) + r9 = add(r9,#16) + r1:0 = asl(r11:10,#31) + } + + { + r15:14 = mpyu(r13,r13) + r1:0 -= mpyu(r13,r12) + } + { + r1:0 -= asl(r15:14,#31) + r15:14 = mpyu(r12,r12) + } + { + r1:0 -= lsr(r15:14,#33) + } + { + r1:0 = mpyu(r1,r8) + } + { + r13:12 += lsr(r1:0,r9) + r9 = add(r9,#16) + r1:0 = asl(r11:10,#47) + } + + { + r15:14 = mpyu(r13,r13) + } + { + r1:0 -= asl(r15:14,#47) + r15:14 = mpyu(r13,r12) + } + { + r1:0 -= asl(r15:14,#16) + r15:14 = mpyu(r12,r12) + } + { + r1:0 -= lsr(r15:14,#17) + } + { + r1:0 = mpyu(r1,r8) + } + { + r13:12 += lsr(r1:0,r9) + } + { + r3:2 = mpyu(r13,r12) + r5:4 = mpyu(r12,r12) + r15:14 = #0 + r1:0 = #0 + } + { + r3:2 += lsr(r5:4,#33) + r5:4 += asl(r3:2,#33) + p1 = cmp.eq(r0,r0) + } + { + r7:6 = mpyu(r13,r13) + r1:0 = sub(r1:0,r5:4,p1):carry + r9:8 = #1 + } + { + r7:6 += lsr(r3:2,#31) + r9:8 += asl(r13:12,#1) + } + + + + + + { + r15:14 = sub(r11:10,r7:6,p1):carry + r5:4 = sub(r1:0,r9:8,p2):carry + + + + + r7:6 = #1 + r11:10 = #0 + } + { + r3:2 = sub(r15:14,r11:10,p2):carry + r7:6 = add(r13:12,r7:6) + r28 = add(r28,#-0x3ff) + } + { + + if (p2) r13:12 = r7:6 + if (p2) r1:0 = r5:4 + if (p2) r15:14 = r3:2 + } + { + r5:4 = sub(r1:0,r9:8,p3):carry + r7:6 = #1 + r28 = asr(r28,#1) + } + { + r3:2 = sub(r15:14,r11:10,p3):carry + r7:6 = add(r13:12,r7:6) + } + { + if (p3) r13:12 = r7:6 + if (p3) r1:0 = r5:4 + + + + + + r2 = #1 + } + { + p0 = cmp.eq(r1:0,r11:10) + if (!p0.new) r12 = or(r12,r2) + r3 = cl0(r13:12) + r28 = add(r28,#-63) + } + + + + { + r1:0 = convert_ud2df(r13:12) + r28 = add(r28,r3) + } + { + r1 += asl(r28,#52 -32) + jumpr r31 + } +.Lsqrt_abnormal: + { + p0 = dfclass(r1:0,#0x01) + if (p0.new) jumpr:t r31 + } + { + p0 = dfclass(r1:0,#0x10) + if (p0.new) jump:nt .Lsqrt_nan + } + { + p0 = cmp.gt(r1,#-1) + if (!p0.new) jump:nt .Lsqrt_invalid_neg + if (!p0.new) r28 = ##0x7F800001 + } + { + p0 = dfclass(r1:0,#0x08) + if (p0.new) jumpr:nt r31 + } + + + { + r1:0 = extractu(r1:0,#52,#0) + } + { + r28 = add(clb(r1:0),#-11) + } + { + r1:0 = asl(r1:0,r28) + r28 = sub(#1,r28) + } + { + r1 = insert(r28,#1,#52 -32) + } + { + r3:2 = extractu(r1:0,#23 +1,#52 -23) + r5 = ##0x3f000004 + } + { + r9 = or(r5,r2) + r5 = and(r5,#-16) + jump .Ldenormal_restart + } +.Lsqrt_nan: + { + r28 = convert_df2sf(r1:0) + r1:0 = #-1 + jumpr r31 + } +.Lsqrt_invalid_neg: + { + r1:0 = convert_sf2df(r28) + jumpr r31 + } +.size __hexagon_sqrt,.-__hexagon_sqrt +.size __hexagon_sqrtdf2,.-__hexagon_sqrtdf2 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/divdi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/divdi3.s new file mode 100644 index 00000000000..0fee6e70f06 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/divdi3.s @@ -0,0 +1,64 @@ + +FUNCTION_BEGIN __hexagon_divdi3 + { + p2 = tstbit(r1,#31) + p3 = tstbit(r3,#31) + } + { + r1:0 = abs(r1:0) + r3:2 = abs(r3:2) + } + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + p3 = xor(p2,p3) + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jump .hexagon_divdi3_return + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + +.hexagon_divdi3_return: + { + r3:2 = neg(r1:0) + } + { + r1:0 = vmux(p3,r3:2,r1:0) + jumpr r31 + } +FUNCTION_END __hexagon_divdi3 + + .globl __qdsp_divdi3 + .set __qdsp_divdi3, __hexagon_divdi3 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/divsi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/divsi3.s new file mode 100644 index 00000000000..fc957a43146 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/divsi3.s @@ -0,0 +1,53 @@ + +FUNCTION_BEGIN __hexagon_divsi3 + { + p0 = cmp.ge(r0,#0) + p1 = cmp.ge(r1,#0) + r1 = abs(r0) + r2 = abs(r1) + } + { + r3 = cl0(r1) + r4 = cl0(r2) + r5 = sub(r1,r2) + p2 = cmp.gtu(r2,r1) + } + { + r0 = #0 + p1 = xor(p0,p1) + p0 = cmp.gtu(r2,r5) + if (p2) jumpr r31 + } + + { + r0 = mux(p1,#-1,#1) + if (p0) jumpr r31 + r4 = sub(r4,r3) + r3 = #1 + } + { + r0 = #0 + r3:2 = vlslw(r3:2,r4) + loop0(1f,r4) + } + .falign +1: + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r1 = sub(r1,r2) + if (!p0.new) r0 = add(r0,r3) + r3:2 = vlsrw(r3:2,#1) + }:endloop0 + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r0 = add(r0,r3) + if (!p1) jumpr r31 + } + { + r0 = neg(r0) + jumpr r31 + } +FUNCTION_END __hexagon_divsi3 + + .globl __qdsp_divsi3 + .set __qdsp_divsi3, __hexagon_divsi3 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s b/library/compiler-builtins/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s new file mode 100644 index 00000000000..e77b7db0332 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s @@ -0,0 +1,266 @@ + .text + .global __hexagon_fast2_dadd_asm + .type __hexagon_fast2_dadd_asm, @function +__hexagon_fast2_dadd_asm: + .falign + { + R7:6 = VABSDIFFH(R1:0, R3:2) + R9 = #62 + R4 = SXTH(R0) + R5 = SXTH(R2) + } { + R6 = SXTH(R6) + P0 = CMP.GT(R4, R5); + if ( P0.new) R8 = add(R4, #1) + if (!P0.new) R8 = add(R5, #1) + } { + if ( P0) R4 = #1 + if (!P0) R5 = #1 + R0.L = #0 + R6 = MIN(R6, R9) + } { + if (!P0) R4 = add(R6, #1) + if ( P0) R5 = add(R6, #1) + R2.L = #0 + R11:10 = #0 + } { + R1:0 = ASR(R1:0, R4) + R3:2 = ASR(R3:2, R5) + } { + R1:0 = add(R1:0, R3:2) + R10.L = #0x8001 + } { + R4 = clb(R1:0) + R9 = #58 + } { + R4 = add(R4, #-1) + p0 = cmp.gt(R4, R9) + } { + R1:0 = ASL(R1:0, R4) + R8 = SUB(R8, R4) + if(p0) jump .Ldenorma + } { + R0 = insert(R8, #16, #0) + jumpr r31 + } +.Ldenorma: + { + R1:0 = R11:10 + jumpr r31 + } + .text + .global __hexagon_fast2_dsub_asm + .type __hexagon_fast2_dsub_asm, @function +__hexagon_fast2_dsub_asm: + .falign + { + R7:6 = VABSDIFFH(R1:0, R3:2) + R9 = #62 + R4 = SXTH(R0) + R5 = SXTH(R2) + } { + R6 = SXTH(R6) + P0 = CMP.GT(R4, R5); + if ( P0.new) R8 = add(R4, #1) + if (!P0.new) R8 = add(R5, #1) + } { + if ( P0) R4 = #1 + if (!P0) R5 = #1 + R0.L = #0 + R6 = MIN(R6, R9) + } { + if (!P0) R4 = add(R6, #1) + if ( P0) R5 = add(R6, #1) + R2.L = #0 + R11:10 = #0 + } { + R1:0 = ASR(R1:0, R4) + R3:2 = ASR(R3:2, R5) + } { + R1:0 = sub(R1:0, R3:2) + R10.L = #0x8001 + } { + R4 = clb(R1:0) + R9 = #58 + } { + R4 = add(R4, #-1) + p0 = cmp.gt(R4, R9) + } { + R1:0 = ASL(R1:0, R4) + R8 = SUB(R8, R4) + if(p0) jump .Ldenorm + } { + R0 = insert(R8, #16, #0) + jumpr r31 + } +.Ldenorm: + { + R1:0 = R11:10 + jumpr r31 + } + .text + .global __hexagon_fast2_dmpy_asm + .type __hexagon_fast2_dmpy_asm, @function +__hexagon_fast2_dmpy_asm: + .falign + { + R13= lsr(R2, #16) + R5 = sxth(R2) + R4 = sxth(R0) + R12= lsr(R0, #16) + } + { + R11:10 = mpy(R1, R3) + R7:6 = mpy(R1, R13) + R0.L = #0x0 + R15:14 = #0 + } + { + R11:10 = add(R11:10, R11:10) + R7:6 += mpy(R3, R12) + R2.L = #0x0 + R15.H = #0x8000 + } + { + R7:6 = asr(R7:6, #15) + R12.L = #0x8001 + p1 = cmp.eq(R1:0, R3:2) + } + { + R7:6 = add(R7:6, R11:10) + R8 = add(R4, R5) + p2 = cmp.eq(R1:0, R15:14) + } + { + R9 = clb(R7:6) + R3:2 = abs(R7:6) + R11 = #58 + } + { + p1 = and(p1, p2) + R8 = sub(R8, R9) + R9 = add(R9, #-1) + p0 = cmp.gt(R9, R11) + } + { + R8 = add(R8, #1) + R1:0 = asl(R7:6, R9) + if(p1) jump .Lsat + } + { + R0 = insert(R8,#16, #0) + if(!p0) jumpr r31 + } + { + R0 = insert(R12,#16, #0) + jumpr r31 + } +.Lsat: + { + R1:0 = #-1 + } + { + R1:0 = lsr(R1:0, #1) + } + { + R0 = insert(R8,#16, #0) + jumpr r31 + } + .text + .global __hexagon_fast2_qd2f_asm + .type __hexagon_fast2_qd2f_asm, @function +__hexagon_fast2_qd2f_asm: + .falign + { + R3 = abs(R1):sat + R4 = sxth(R0) + R5 = #0x40 + R6.L = #0xffc0 + } + { + R0 = extractu(R3, #8, #0) + p2 = cmp.gt(R4, #126) + p3 = cmp.ge(R4, #-126) + R6.H = #0x7fff + } + { + p1 = cmp.eq(R0,#0x40) + if(p1.new) R5 = #0 + R4 = add(R4, #126) + if(!p3) jump .Lmin + } + { + p0 = bitsset(R3, R6) + R0.L = #0x0000 + R2 = add(R3, R5) + R7 = lsr(R6, #8) + } + { + if(p0) R4 = add(R4, #1) + if(p0) R3 = #0 + R2 = lsr(R2, #7) + R0.H = #0x8000 + } + { + R0 = and(R0, R1) + R6 &= asl(R4, #23) + if(!p0) R3 = and(R2, R7) + if(p2) jump .Lmax + } + { + R0 += add(R6, R3) + jumpr r31 + } +.Lmax: + { + R0.L = #0xffff; + } + { + R0.H = #0x7f7f; + jumpr r31 + } +.Lmin: + { + R0 = #0x0 + jumpr r31 + } + .text + .global __hexagon_fast2_f2qd_asm + .type __hexagon_fast2_f2qd_asm, @function +__hexagon_fast2_f2qd_asm: + + + + + + + + .falign + { + R1 = asl(R0, #7) + p0 = tstbit(R0, #31) + R5:4 = #0 + R3 = add(R0,R0) + } + { + R1 = setbit(R1, #30) + R0= extractu(R0,#8,#23) + R4.L = #0x8001 + p1 = cmp.eq(R3, #0) + } + { + R1= extractu(R1, #31, #0) + R0= add(R0, #-126) + R2 = #0 + if(p1) jump .Lminqd + } + { + R0 = zxth(R0) + if(p0) R1= sub(R2, R1) + jumpr r31 + } +.Lminqd: + { + R1:0 = R5:4 + jumpr r31 + } diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s b/library/compiler-builtins/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s new file mode 100644 index 00000000000..3251057d78c --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s @@ -0,0 +1,187 @@ + .text + .global __hexagon_fast2ldadd_asm + .type __hexagon_fast2ldadd_asm, @function +__hexagon_fast2ldadd_asm: + .falign + { + R4 = memw(r29+#8) + R5 = memw(r29+#24) + r7 = r0 + } + { + R6 = sub(R4, R5):sat + P0 = CMP.GT(R4, R5); + if ( P0.new) R8 = add(R4, #1) + if (!P0.new) R8 = add(R5, #1) + } { + R6 = abs(R6):sat + if ( P0) R4 = #1 + if (!P0) R5 = #1 + R9 = #62 + } { + R6 = MIN(R6, R9) + R1:0 = memd(r29+#0) + R3:2 = memd(r29+#16) + } { + if (!P0) R4 = add(R6, #1) + if ( P0) R5 = add(R6, #1) + } { + R1:0 = ASR(R1:0, R4) + R3:2 = ASR(R3:2, R5) + } { + R1:0 = add(R1:0, R3:2) + R3:2 = #0 + } { + R4 = clb(R1:0) + R9.L =#0x0001 + } { + R8 -= add(R4, #-1) + R4 = add(R4, #-1) + p0 = cmp.gt(R4, #58) + R9.H =#0x8000 + } { + if(!p0)memw(r7+#8) = R8 + R1:0 = ASL(R1:0, R4) + if(p0) jump .Ldenorma1 + } { + memd(r7+#0) = R1:0 + jumpr r31 + } +.Ldenorma1: + memd(r7+#0) = R3:2 + { + memw(r7+#8) = R9 + jumpr r31 + } + .text + .global __hexagon_fast2ldsub_asm + .type __hexagon_fast2ldsub_asm, @function +__hexagon_fast2ldsub_asm: + .falign + { + R4 = memw(r29+#8) + R5 = memw(r29+#24) + r7 = r0 + } + { + R6 = sub(R4, R5):sat + P0 = CMP.GT(R4, R5); + if ( P0.new) R8 = add(R4, #1) + if (!P0.new) R8 = add(R5, #1) + } { + R6 = abs(R6):sat + if ( P0) R4 = #1 + if (!P0) R5 = #1 + R9 = #62 + } { + R6 = min(R6, R9) + R1:0 = memd(r29+#0) + R3:2 = memd(r29+#16) + } { + if (!P0) R4 = add(R6, #1) + if ( P0) R5 = add(R6, #1) + } { + R1:0 = ASR(R1:0, R4) + R3:2 = ASR(R3:2, R5) + } { + R1:0 = sub(R1:0, R3:2) + R3:2 = #0 + } { + R4 = clb(R1:0) + R9.L =#0x0001 + } { + R8 -= add(R4, #-1) + R4 = add(R4, #-1) + p0 = cmp.gt(R4, #58) + R9.H =#0x8000 + } { + if(!p0)memw(r7+#8) = R8 + R1:0 = asl(R1:0, R4) + if(p0) jump .Ldenorma_s + } { + memd(r7+#0) = R1:0 + jumpr r31 + } +.Ldenorma_s: + memd(r7+#0) = R3:2 + { + memw(r7+#8) = R9 + jumpr r31 + } + .text + .global __hexagon_fast2ldmpy_asm + .type __hexagon_fast2ldmpy_asm, @function +__hexagon_fast2ldmpy_asm: + .falign + { + R15:14 = memd(r29+#0) + R3:2 = memd(r29+#16) + R13:12 = #0 + } + { + R8= extractu(R2, #31, #1) + R9= extractu(R14, #31, #1) + R13.H = #0x8000 + } + { + R11:10 = mpy(R15, R3) + R7:6 = mpy(R15, R8) + R4 = memw(r29+#8) + R5 = memw(r29+#24) + } + { + R11:10 = add(R11:10, R11:10) + R7:6 += mpy(R3, R9) + } + { + R7:6 = asr(R7:6, #30) + R8.L = #0x0001 + p1 = cmp.eq(R15:14, R3:2) + } + { + R7:6 = add(R7:6, R11:10) + R4= add(R4, R5) + p2 = cmp.eq(R3:2, R13:12) + } + { + R9 = clb(R7:6) + R8.H = #0x8000 + p1 = and(p1, p2) + } + { + R4-= add(R9, #-1) + R9 = add(R9, #-1) + if(p1) jump .Lsat1 + } + { + R7:6 = asl(R7:6, R9) + memw(R0+#8) = R4 + p0 = cmp.gt(R9, #58) + if(p0.new) jump:NT .Ldenorm1 + } + { + memd(R0+#0) = R7:6 + jumpr r31 + } +.Lsat1: + { + R13:12 = #0 + R4+= add(R9, #1) + } + { + R13.H = #0x4000 + memw(R0+#8) = R4 + } + { + memd(R0+#0) = R13:12 + jumpr r31 + } +.Ldenorm1: + { + memw(R0+#8) = R8 + R15:14 = #0 + } + { + memd(R0+#0) = R15:14 + jumpr r31 + } diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/func_macro.s b/library/compiler-builtins/compiler-builtins/src/hexagon/func_macro.s new file mode 100644 index 00000000000..9a1e11aebcb --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/func_macro.s @@ -0,0 +1,12 @@ + .macro FUNCTION_BEGIN name + .text + .p2align 5 + .globl \name + .type \name, @function +\name: + .endm + + .macro FUNCTION_END name + .size \name, . - \name + .endm + diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s b/library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s new file mode 100644 index 00000000000..89f69010aa4 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s @@ -0,0 +1,91 @@ + .text + + + + + + + .globl hexagon_memcpy_forward_vp4cp4n2 + .balign 32 + .type hexagon_memcpy_forward_vp4cp4n2,@function +hexagon_memcpy_forward_vp4cp4n2: + + + + + { + r3 = sub(##4096, r1) + r5 = lsr(r2, #3) + } + { + + + r3 = extractu(r3, #10, #2) + r4 = extractu(r3, #7, #5) + } + { + r3 = minu(r2, r3) + r4 = minu(r5, r4) + } + { + r4 = or(r4, ##2105344) + p0 = cmp.eq(r3, #0) + if (p0.new) jump:nt .Lskipprolog + } + l2fetch(r1, r4) + { + loop0(.Lprolog, r3) + r2 = sub(r2, r3) + } + .falign +.Lprolog: + { + r4 = memw(r1++#4) + memw(r0++#4) = r4.new + } :endloop0 +.Lskipprolog: + { + + r3 = lsr(r2, #10) + if (cmp.eq(r3.new, #0)) jump:nt .Lskipmain + } + { + loop1(.Lout, r3) + r2 = extractu(r2, #10, #0) + r3 = ##2105472 + } + + .falign +.Lout: + + l2fetch(r1, r3) + loop0(.Lpage, #512) + .falign +.Lpage: + r5:4 = memd(r1++#8) + { + memw(r0++#8) = r4 + memw(r0+#4) = r5 + } :endloop0:endloop1 +.Lskipmain: + { + r3 = ##2105344 + r4 = lsr(r2, #3) + p0 = cmp.eq(r2, #0) + if (p0.new) jumpr:nt r31 + } + { + r3 = or(r3, r4) + loop0(.Lepilog, r2) + } + l2fetch(r1, r3) + .falign +.Lepilog: + { + r4 = memw(r1++#4) + memw(r0++#4) = r4.new + } :endloop0 + + jumpr r31 + +.size hexagon_memcpy_forward_vp4cp4n2, . - hexagon_memcpy_forward_vp4cp4n2 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_likely_aligned.s b/library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_likely_aligned.s new file mode 100644 index 00000000000..7e9b62f6a79 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_likely_aligned.s @@ -0,0 +1,42 @@ + +FUNCTION_BEGIN __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes + { + p0 = bitsclr(r1,#7) + p0 = bitsclr(r0,#7) + if (p0.new) r5:4 = memd(r1) + r3 = #-3 + } + { + if (!p0) jump .Lmemcpy_call + if (p0) memd(r0++#8) = r5:4 + if (p0) r5:4 = memd(r1+#8) + r3 += lsr(r2,#3) + } + { + memd(r0++#8) = r5:4 + r5:4 = memd(r1+#16) + r1 = add(r1,#24) + loop0(1f,r3) + } + .falign +1: + { + memd(r0++#8) = r5:4 + r5:4 = memd(r1++#8) + }:endloop0 + { + memd(r0) = r5:4 + r0 -= add(r2,#-8) + jumpr r31 + } +FUNCTION_END __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes + +.Lmemcpy_call: + + jump memcpy@PLT + + + + + .globl __qdsp_memcpy_likely_aligned_min32bytes_mult8bytes + .set __qdsp_memcpy_likely_aligned_min32bytes_mult8bytes, __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/moddi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/moddi3.s new file mode 100644 index 00000000000..53ea6d52a58 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/moddi3.s @@ -0,0 +1,63 @@ + + +FUNCTION_BEGIN __hexagon_moddi3 + { + p3 = tstbit(r1,#31) + } + { + r1:0 = abs(r1:0) + r3:2 = abs(r3:2) + } + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jump .hexagon_moddi3_return + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + +.hexagon_moddi3_return: + { + r1:0 = neg(r3:2) + } + { + r1:0 = vmux(p3,r1:0,r3:2) + jumpr r31 + } +FUNCTION_END __hexagon_moddi3 + + .globl __qdsp_moddi3 + .set __qdsp_moddi3, __hexagon_moddi3 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/modsi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/modsi3.s new file mode 100644 index 00000000000..c4ae7e59edc --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/modsi3.s @@ -0,0 +1,44 @@ + + +FUNCTION_BEGIN __hexagon_modsi3 + { + p2 = cmp.ge(r0,#0) + r2 = abs(r0) + r1 = abs(r1) + } + { + r3 = cl0(r2) + r4 = cl0(r1) + p0 = cmp.gtu(r1,r2) + } + { + r3 = sub(r4,r3) + if (p0) jumpr r31 + } + { + p1 = cmp.eq(r3,#0) + loop0(1f,r3) + r0 = r2 + r2 = lsl(r1,r3) + } + .falign +1: + { + p0 = cmp.gtu(r2,r0) + if (!p0.new) r0 = sub(r0,r2) + r2 = lsr(r2,#1) + if (p1) r1 = #0 + }:endloop0 + { + p0 = cmp.gtu(r2,r0) + if (!p0.new) r0 = sub(r0,r1) + if (p2) jumpr r31 + } + { + r0 = neg(r0) + jumpr r31 + } +FUNCTION_END __hexagon_modsi3 + + .globl __qdsp_modsi3 + .set __qdsp_modsi3, __hexagon_modsi3 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/sfdiv_opt.s b/library/compiler-builtins/compiler-builtins/src/hexagon/sfdiv_opt.s new file mode 100644 index 00000000000..26c91f15cbb --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/sfdiv_opt.s @@ -0,0 +1,42 @@ + +FUNCTION_BEGIN __hexagon_divsf3 + { + r2,p0 = sfrecipa(r0,r1) + r4 = sffixupd(r0,r1) + r3 = ##0x3f800000 + } + { + r5 = sffixupn(r0,r1) + r3 -= sfmpy(r4,r2):lib + r6 = ##0x80000000 + r7 = r3 + } + { + r2 += sfmpy(r3,r2):lib + r3 = r7 + r6 = r5 + r0 = and(r6,r5) + } + { + r3 -= sfmpy(r4,r2):lib + r0 += sfmpy(r5,r2):lib + } + { + r2 += sfmpy(r3,r2):lib + r6 -= sfmpy(r0,r4):lib + } + { + r0 += sfmpy(r6,r2):lib + } + { + r5 -= sfmpy(r0,r4):lib + } + { + r0 += sfmpy(r5,r2,p0):scale + jumpr r31 + } +FUNCTION_END __hexagon_divsf3 + +.global __qdsp_divsf3 ; .set __qdsp_divsf3, __hexagon_divsf3 +.global __hexagon_fast_divsf3 ; .set __hexagon_fast_divsf3, __hexagon_divsf3 +.global __hexagon_fast2_divsf3 ; .set __hexagon_fast2_divsf3, __hexagon_divsf3 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/sfsqrt_opt.s b/library/compiler-builtins/compiler-builtins/src/hexagon/sfsqrt_opt.s new file mode 100644 index 00000000000..c90af179754 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/sfsqrt_opt.s @@ -0,0 +1,49 @@ +FUNCTION_BEGIN __hexagon_sqrtf + { + r3,p0 = sfinvsqrta(r0) + r5 = sffixupr(r0) + r4 = ##0x3f000000 + r1:0 = combine(#0,#0) + } + { + r0 += sfmpy(r3,r5):lib + r1 += sfmpy(r3,r4):lib + r2 = r4 + r3 = r5 + } + { + r2 -= sfmpy(r0,r1):lib + p1 = sfclass(r5,#1) + + } + { + r0 += sfmpy(r0,r2):lib + r1 += sfmpy(r1,r2):lib + r2 = r4 + r3 = r5 + } + { + r2 -= sfmpy(r0,r1):lib + r3 -= sfmpy(r0,r0):lib + } + { + r0 += sfmpy(r1,r3):lib + r1 += sfmpy(r1,r2):lib + r2 = r4 + r3 = r5 + } + { + + r3 -= sfmpy(r0,r0):lib + if (p1) r0 = or(r0,r5) + } + { + r0 += sfmpy(r1,r3,p0):scale + jumpr r31 + } + +FUNCTION_END __hexagon_sqrtf + +.global __qdsp_sqrtf ; .set __qdsp_sqrtf, __hexagon_sqrtf +.global __hexagon_fast_sqrtf ; .set __hexagon_fast_sqrtf, __hexagon_sqrtf +.global __hexagon_fast2_sqrtf ; .set __hexagon_fast2_sqrtf, __hexagon_sqrtf diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/udivdi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/udivdi3.s new file mode 100644 index 00000000000..f0fffc23df0 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/udivdi3.s @@ -0,0 +1,50 @@ + + +FUNCTION_BEGIN __hexagon_udivdi3 + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jumpr r31 + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + { + jumpr r31 + } +FUNCTION_END __hexagon_udivdi3 + + .globl __qdsp_udivdi3 + .set __qdsp_udivdi3, __hexagon_udivdi3 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/udivmoddi4.s b/library/compiler-builtins/compiler-builtins/src/hexagon/udivmoddi4.s new file mode 100644 index 00000000000..cbfb3987dd2 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/udivmoddi4.s @@ -0,0 +1,50 @@ + + +FUNCTION_BEGIN __hexagon_udivmoddi4 + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jumpr r31 + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + { + jumpr r31 + } +FUNCTION_END __hexagon_udivmoddi4 + + .globl __qdsp_udivmoddi4 + .set __qdsp_udivmoddi4, __hexagon_udivmoddi4 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/udivmodsi4.s b/library/compiler-builtins/compiler-builtins/src/hexagon/udivmodsi4.s new file mode 100644 index 00000000000..83489c51431 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/udivmodsi4.s @@ -0,0 +1,39 @@ + + +FUNCTION_BEGIN __hexagon_udivmodsi4 + { + r2 = cl0(r0) + r3 = cl0(r1) + r5:4 = combine(#1,#0) + p0 = cmp.gtu(r1,r0) + } + { + r6 = sub(r3,r2) + r4 = r1 + r1:0 = combine(r0,r4) + if (p0) jumpr r31 + } + { + r3:2 = vlslw(r5:4,r6) + loop0(1f,r6) + p0 = cmp.eq(r6,#0) + if (p0.new) r4 = #0 + } + .falign +1: + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r1 = sub(r1,r2) + if (!p0.new) r0 = add(r0,r3) + r3:2 = vlsrw(r3:2,#1) + }:endloop0 + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r1 = sub(r1,r4) + if (!p0.new) r0 = add(r0,r3) + jumpr r31 + } +FUNCTION_END __hexagon_udivmodsi4 + + .globl __qdsp_udivmodsi4 + .set __qdsp_udivmodsi4, __hexagon_udivmodsi4 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/udivsi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/udivsi3.s new file mode 100644 index 00000000000..e0b94aa9982 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/udivsi3.s @@ -0,0 +1,36 @@ + + +FUNCTION_BEGIN __hexagon_udivsi3 + { + r2 = cl0(r0) + r3 = cl0(r1) + r5:4 = combine(#1,#0) + p0 = cmp.gtu(r1,r0) + } + { + r6 = sub(r3,r2) + r4 = r1 + r1:0 = combine(r0,r4) + if (p0) jumpr r31 + } + { + r3:2 = vlslw(r5:4,r6) + loop0(1f,r6) + } + .falign +1: + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r1 = sub(r1,r2) + if (!p0.new) r0 = add(r0,r3) + r3:2 = vlsrw(r3:2,#1) + }:endloop0 + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r0 = add(r0,r3) + jumpr r31 + } +FUNCTION_END __hexagon_udivsi3 + + .globl __qdsp_udivsi3 + .set __qdsp_udivsi3, __hexagon_udivsi3 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/umoddi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/umoddi3.s new file mode 100644 index 00000000000..c76011c3e7a --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/umoddi3.s @@ -0,0 +1,53 @@ + + +FUNCTION_BEGIN __hexagon_umoddi3 + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jump .hexagon_umoddi3_return + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + +.hexagon_umoddi3_return: + { + r1:0 = r3:2 + jumpr r31 + } +FUNCTION_END __hexagon_umoddi3 + + .globl __qdsp_umoddi3 + .set __qdsp_umoddi3, __hexagon_umoddi3 diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/umodsi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/umodsi3.s new file mode 100644 index 00000000000..1b592a7c561 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/umodsi3.s @@ -0,0 +1,34 @@ + + +FUNCTION_BEGIN __hexagon_umodsi3 + { + r2 = cl0(r0) + r3 = cl0(r1) + p0 = cmp.gtu(r1,r0) + } + { + r2 = sub(r3,r2) + if (p0) jumpr r31 + } + { + loop0(1f,r2) + p1 = cmp.eq(r2,#0) + r2 = lsl(r1,r2) + } + .falign +1: + { + p0 = cmp.gtu(r2,r0) + if (!p0.new) r0 = sub(r0,r2) + r2 = lsr(r2,#1) + if (p1) r1 = #0 + }:endloop0 + { + p0 = cmp.gtu(r2,r0) + if (!p0.new) r0 = sub(r0,r1) + jumpr r31 + } +FUNCTION_END __hexagon_umodsi3 + + .globl __qdsp_umodsi3 + .set __qdsp_umodsi3, __hexagon_umodsi3 diff --git a/library/compiler-builtins/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/compiler-builtins/src/int/addsub.rs new file mode 100644 index 00000000000..1f84e8eb1e1 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/addsub.rs @@ -0,0 +1,104 @@ +use crate::int::{DInt, Int, MinInt}; + +trait UAddSub: DInt + Int { + fn uadd(self, other: Self) -> Self { + let (lo, carry) = self.lo().overflowing_add(other.lo()); + let hi = self.hi().wrapping_add(other.hi()); + let carry = if carry { Self::H::ONE } else { Self::H::ZERO }; + Self::from_lo_hi(lo, hi.wrapping_add(carry)) + } + fn uadd_one(self) -> Self { + let (lo, carry) = self.lo().overflowing_add(Self::H::ONE); + let carry = if carry { Self::H::ONE } else { Self::H::ZERO }; + Self::from_lo_hi(lo, self.hi().wrapping_add(carry)) + } + fn usub(self, other: Self) -> Self { + let uneg = (!other).uadd_one(); + self.uadd(uneg) + } +} + +impl UAddSub for u128 {} + +trait AddSub: Int +where + ::UnsignedInt: UAddSub, +{ + fn add(self, other: Self) -> Self { + Self::from_unsigned(self.unsigned().uadd(other.unsigned())) + } + fn sub(self, other: Self) -> Self { + Self::from_unsigned(self.unsigned().usub(other.unsigned())) + } +} + +impl AddSub for u128 {} +impl AddSub for i128 {} + +trait Addo: AddSub +where + ::UnsignedInt: UAddSub, +{ + fn addo(self, other: Self) -> (Self, bool) { + let sum = AddSub::add(self, other); + (sum, (other < Self::ZERO) != (sum < self)) + } +} + +impl Addo for i128 {} +impl Addo for u128 {} + +trait Subo: AddSub +where + ::UnsignedInt: UAddSub, +{ + fn subo(self, other: Self) -> (Self, bool) { + let sum = AddSub::sub(self, other); + (sum, (other < Self::ZERO) != (self < sum)) + } +} + +impl Subo for i128 {} +impl Subo for u128 {} + +intrinsics! { + pub extern "C" fn __rust_i128_add(a: i128, b: i128) -> i128 { + AddSub::add(a,b) + } + + pub extern "C" fn __rust_i128_addo(a: i128, b: i128, oflow: &mut i32) -> i128 { + let (add, o) = a.addo(b); + *oflow = o.into(); + add + } + + pub extern "C" fn __rust_u128_add(a: u128, b: u128) -> u128 { + AddSub::add(a,b) + } + + pub extern "C" fn __rust_u128_addo(a: u128, b: u128, oflow: &mut i32) -> u128 { + let (add, o) = a.addo(b); + *oflow = o.into(); + add + } + + pub extern "C" fn __rust_i128_sub(a: i128, b: i128) -> i128 { + AddSub::sub(a,b) + } + + pub extern "C" fn __rust_i128_subo(a: i128, b: i128, oflow: &mut i32) -> i128 { + let (sub, o) = a.subo(b); + *oflow = o.into(); + sub + } + + pub extern "C" fn __rust_u128_sub(a: u128, b: u128) -> u128 { + AddSub::sub(a,b) + } + + pub extern "C" fn __rust_u128_subo(a: u128, b: u128, oflow: &mut i32) -> u128 { + let (sub, o) = a.subo(b); + *oflow = o.into(); + sub + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/int/big.rs b/library/compiler-builtins/compiler-builtins/src/int/big.rs new file mode 100644 index 00000000000..0ef3caaedff --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/big.rs @@ -0,0 +1,294 @@ +//! Integers used for wide operations, larger than `u128`. + +#![allow(unused)] + +use crate::int::{DInt, HInt, Int, MinInt}; +use core::{fmt, ops}; + +const WORD_LO_MASK: u64 = 0x00000000ffffffff; +const WORD_HI_MASK: u64 = 0xffffffff00000000; +const WORD_FULL_MASK: u64 = 0xffffffffffffffff; +const U128_LO_MASK: u128 = u64::MAX as u128; +const U128_HI_MASK: u128 = (u64::MAX as u128) << 64; + +/// A 256-bit unsigned integer represented as 4 64-bit limbs. +/// +/// Each limb is a native-endian number, but the array is little-limb-endian. +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +pub struct u256(pub [u64; 4]); + +impl u256 { + pub const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX]); + + /// Reinterpret as a signed integer + pub fn signed(self) -> i256 { + i256(self.0) + } +} + +/// A 256-bit signed integer represented as 4 64-bit limbs. +/// +/// Each limb is a native-endian number, but the array is little-limb-endian. +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +pub struct i256(pub [u64; 4]); + +impl i256 { + /// Reinterpret as an unsigned integer + pub fn unsigned(self) -> u256 { + u256(self.0) + } +} + +impl MinInt for u256 { + type OtherSign = i256; + + type UnsignedInt = u256; + + const SIGNED: bool = false; + const BITS: u32 = 256; + const ZERO: Self = Self([0u64; 4]); + const ONE: Self = Self([1, 0, 0, 0]); + const MIN: Self = Self([0u64; 4]); + const MAX: Self = Self([u64::MAX; 4]); +} + +impl MinInt for i256 { + type OtherSign = u256; + + type UnsignedInt = u256; + + const SIGNED: bool = false; + const BITS: u32 = 256; + const ZERO: Self = Self([0u64; 4]); + const ONE: Self = Self([1, 0, 0, 0]); + const MIN: Self = Self([0, 0, 0, 1 << 63]); + const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX << 1]); +} + +macro_rules! impl_common { + ($ty:ty) => { + impl ops::BitOr for $ty { + type Output = Self; + + fn bitor(mut self, rhs: Self) -> Self::Output { + self.0[0] |= rhs.0[0]; + self.0[1] |= rhs.0[1]; + self.0[2] |= rhs.0[2]; + self.0[3] |= rhs.0[3]; + self + } + } + + impl ops::Not for $ty { + type Output = Self; + + fn not(self) -> Self::Output { + Self([!self.0[0], !self.0[1], !self.0[2], !self.0[3]]) + } + } + + impl ops::Shl for $ty { + type Output = Self; + + fn shl(self, rhs: u32) -> Self::Output { + unimplemented!("only used to meet trait bounds") + } + } + }; +} + +impl_common!(i256); +impl_common!(u256); + +impl ops::Shr for u256 { + type Output = Self; + + fn shr(self, rhs: u32) -> Self::Output { + assert!(rhs < Self::BITS, "attempted to shift right with overflow"); + + if rhs == 0 { + return self; + } + + let mut ret = self; + let byte_shift = rhs / 64; + let bit_shift = rhs % 64; + + for idx in 0..4 { + let base_idx = idx + byte_shift as usize; + + let Some(base) = ret.0.get(base_idx) else { + ret.0[idx] = 0; + continue; + }; + + let mut new_val = base >> bit_shift; + + if let Some(new) = ret.0.get(base_idx + 1) { + new_val |= new.overflowing_shl(64 - bit_shift).0; + } + + ret.0[idx] = new_val; + } + + ret + } +} + +macro_rules! word { + (1, $val:expr) => { + (($val >> (32 * 3)) & Self::from(WORD_LO_MASK)) as u64 + }; + (2, $val:expr) => { + (($val >> (32 * 2)) & Self::from(WORD_LO_MASK)) as u64 + }; + (3, $val:expr) => { + (($val >> (32 * 1)) & Self::from(WORD_LO_MASK)) as u64 + }; + (4, $val:expr) => { + (($val >> (32 * 0)) & Self::from(WORD_LO_MASK)) as u64 + }; +} + +impl HInt for u128 { + type D = u256; + + fn widen(self) -> Self::D { + let w0 = self & u128::from(u64::MAX); + let w1 = (self >> u64::BITS) & u128::from(u64::MAX); + u256([w0 as u64, w1 as u64, 0, 0]) + } + + fn zero_widen(self) -> Self::D { + self.widen() + } + + fn zero_widen_mul(self, rhs: Self) -> Self::D { + let product11: u64 = word!(1, self) * word!(1, rhs); + let product12: u64 = word!(1, self) * word!(2, rhs); + let product13: u64 = word!(1, self) * word!(3, rhs); + let product14: u64 = word!(1, self) * word!(4, rhs); + let product21: u64 = word!(2, self) * word!(1, rhs); + let product22: u64 = word!(2, self) * word!(2, rhs); + let product23: u64 = word!(2, self) * word!(3, rhs); + let product24: u64 = word!(2, self) * word!(4, rhs); + let product31: u64 = word!(3, self) * word!(1, rhs); + let product32: u64 = word!(3, self) * word!(2, rhs); + let product33: u64 = word!(3, self) * word!(3, rhs); + let product34: u64 = word!(3, self) * word!(4, rhs); + let product41: u64 = word!(4, self) * word!(1, rhs); + let product42: u64 = word!(4, self) * word!(2, rhs); + let product43: u64 = word!(4, self) * word!(3, rhs); + let product44: u64 = word!(4, self) * word!(4, rhs); + + let sum0: u128 = u128::from(product44); + let sum1: u128 = u128::from(product34) + u128::from(product43); + let sum2: u128 = u128::from(product24) + u128::from(product33) + u128::from(product42); + let sum3: u128 = u128::from(product14) + + u128::from(product23) + + u128::from(product32) + + u128::from(product41); + let sum4: u128 = u128::from(product13) + u128::from(product22) + u128::from(product31); + let sum5: u128 = u128::from(product12) + u128::from(product21); + let sum6: u128 = u128::from(product11); + + let r0: u128 = + (sum0 & u128::from(WORD_FULL_MASK)) + ((sum1 & u128::from(WORD_LO_MASK)) << 32); + let r1: u128 = (sum0 >> 64) + + ((sum1 >> 32) & u128::from(WORD_FULL_MASK)) + + (sum2 & u128::from(WORD_FULL_MASK)) + + ((sum3 << 32) & u128::from(WORD_HI_MASK)); + + let (lo, carry) = r0.overflowing_add(r1 << 64); + let hi = (r1 >> 64) + + (sum1 >> 96) + + (sum2 >> 64) + + (sum3 >> 32) + + sum4 + + (sum5 << 32) + + (sum6 << 64) + + u128::from(carry); + + u256([ + (lo & U128_LO_MASK) as u64, + ((lo >> 64) & U128_LO_MASK) as u64, + (hi & U128_LO_MASK) as u64, + ((hi >> 64) & U128_LO_MASK) as u64, + ]) + } + + fn widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen_mul(rhs) + } + + fn widen_hi(self) -> Self::D { + self.widen() << ::BITS + } +} + +impl HInt for i128 { + type D = i256; + + fn widen(self) -> Self::D { + let mut ret = self.unsigned().zero_widen().signed(); + if self.is_negative() { + ret.0[2] = u64::MAX; + ret.0[3] = u64::MAX; + } + ret + } + + fn zero_widen(self) -> Self::D { + self.unsigned().zero_widen().signed() + } + + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.unsigned().zero_widen_mul(rhs.unsigned()).signed() + } + + fn widen_mul(self, rhs: Self) -> Self::D { + unimplemented!("signed i128 widening multiply is not used") + } + + fn widen_hi(self) -> Self::D { + self.widen() << ::BITS + } +} + +impl DInt for u256 { + type H = u128; + + fn lo(self) -> Self::H { + let mut tmp = [0u8; 16]; + tmp[..8].copy_from_slice(&self.0[0].to_le_bytes()); + tmp[8..].copy_from_slice(&self.0[1].to_le_bytes()); + u128::from_le_bytes(tmp) + } + + fn hi(self) -> Self::H { + let mut tmp = [0u8; 16]; + tmp[..8].copy_from_slice(&self.0[2].to_le_bytes()); + tmp[8..].copy_from_slice(&self.0[3].to_le_bytes()); + u128::from_le_bytes(tmp) + } +} + +impl DInt for i256 { + type H = i128; + + fn lo(self) -> Self::H { + let mut tmp = [0u8; 16]; + tmp[..8].copy_from_slice(&self.0[0].to_le_bytes()); + tmp[8..].copy_from_slice(&self.0[1].to_le_bytes()); + i128::from_le_bytes(tmp) + } + + fn hi(self) -> Self::H { + let mut tmp = [0u8; 16]; + tmp[..8].copy_from_slice(&self.0[2].to_le_bytes()); + tmp[8..].copy_from_slice(&self.0[3].to_le_bytes()); + i128::from_le_bytes(tmp) + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/int/bswap.rs b/library/compiler-builtins/compiler-builtins/src/int/bswap.rs new file mode 100644 index 00000000000..9df80204d0e --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/bswap.rs @@ -0,0 +1,22 @@ +intrinsics! { + #[maybe_use_optimized_c_shim] + #[avr_skip] + /// Swaps bytes in 32-bit number + pub extern "C" fn __bswapsi2(x: u32) -> u32 { + x.swap_bytes() + } + + #[maybe_use_optimized_c_shim] + #[avr_skip] + /// Swaps bytes in 64-bit number + pub extern "C" fn __bswapdi2(x: u64) -> u64 { + x.swap_bytes() + } + + #[maybe_use_optimized_c_shim] + #[avr_skip] + /// Swaps bytes in 128-bit number + pub extern "C" fn __bswapti2(x: u128) -> u128 { + x.swap_bytes() + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs new file mode 100644 index 00000000000..ba735aa7462 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs @@ -0,0 +1,168 @@ +// Note: these functions happen to produce the correct `usize::leading_zeros(0)` value +// without a explicit zero check. Zero is probably common enough that it could warrant +// adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. +// Compilers will insert the check for zero in cases where it is needed. + +#[cfg(feature = "public-test-deps")] +pub use implementation::{leading_zeros_default, leading_zeros_riscv}; +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use implementation::{leading_zeros_default, leading_zeros_riscv}; + +mod implementation { + use crate::int::{CastInto, Int}; + + /// Returns the number of leading binary zeros in `x`. + #[allow(dead_code)] + pub fn leading_zeros_default>(x: T) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS as usize; + // a temporary + let mut t: T; + + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + t = x >> 32; + if t != T::ZERO { + z -= 32; + x = t; + } + } + if T::BITS >= 32 { + t = x >> 16; + if t != T::ZERO { + z -= 16; + x = t; + } + } + const { assert!(T::BITS >= 16) }; + t = x >> 8; + if t != T::ZERO { + z -= 8; + x = t; + } + t = x >> 4; + if t != T::ZERO { + z -= 4; + x = t; + } + t = x >> 2; + if t != T::ZERO { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != T::ZERO { + z - 2 + } else { + z - x.cast() + } + + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/ + // fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. + } + + // The above method does not compile well on RISC-V (because of the lack of predicated + // instructions), producing code with many branches or using an excessively long + // branchless solution. This method takes advantage of the set-if-less-than instruction on + // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + + /// Returns the number of leading binary zeros in `x`. + #[allow(dead_code)] + pub fn leading_zeros_riscv>(x: T) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS; + // a temporary + let mut t: u32; + + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (T::ONE << 32)) as u32) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. + x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros + z -= t; + } + if T::BITS >= 32 { + t = ((x >= (T::ONE << 16)) as u32) << 4; + x >>= t; + z -= t; + } + const { assert!(T::BITS >= 16) }; + t = ((x >= (T::ONE << 8)) as u32) << 3; + x >>= t; + z -= t; + t = ((x >= (T::ONE << 4)) as u32) << 2; + x >>= t; + z -= t; + t = ((x >= (T::ONE << 2)) as u32) << 1; + x >>= t; + z -= t; + t = (x >= (T::ONE << 1)) as u32; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z as usize - x.cast() + } +} + +intrinsics! { + /// Returns the number of leading binary zeros in `x` + pub extern "C" fn __clzsi2(x: u32) -> usize { + if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { + leading_zeros_riscv(x) + } else { + leading_zeros_default(x) + } + } + + /// Returns the number of leading binary zeros in `x` + pub extern "C" fn __clzdi2(x: u64) -> usize { + if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { + leading_zeros_riscv(x) + } else { + leading_zeros_default(x) + } + } + + /// Returns the number of leading binary zeros in `x` + pub extern "C" fn __clzti2(x: u128) -> usize { + let hi = (x >> 64) as u64; + if hi == 0 { + 64 + __clzdi2(x as u64) + } else { + __clzdi2(hi) + } + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/compiler-builtins/src/int/mod.rs new file mode 100644 index 00000000000..1f1be711bbd --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/mod.rs @@ -0,0 +1,20 @@ +mod specialized_div_rem; + +pub mod addsub; +mod big; +pub mod bswap; +pub mod leading_zeros; +pub mod mul; +pub mod sdiv; +pub mod shift; +pub mod trailing_zeros; +mod traits; +pub mod udiv; + +pub use big::{i256, u256}; + +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; + +#[cfg(feature = "public-test-deps")] +pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; diff --git a/library/compiler-builtins/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/compiler-builtins/src/int/mul.rs new file mode 100644 index 00000000000..040c69342d1 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/mul.rs @@ -0,0 +1,142 @@ +use crate::int::{DInt, HInt, Int}; + +trait Mul: DInt + Int +where + Self::H: DInt, +{ + fn mul(self, rhs: Self) -> Self { + // In order to prevent infinite recursion, we cannot use the `widen_mul` in this: + //self.lo().widen_mul(rhs.lo()) + // .wrapping_add(self.lo().wrapping_mul(rhs.hi()).widen_hi()) + // .wrapping_add(self.hi().wrapping_mul(rhs.lo()).widen_hi()) + + let lhs_lo = self.lo(); + let rhs_lo = rhs.lo(); + // construct the widening multiplication using only `Self::H` sized multiplications + let tmp_0 = lhs_lo.lo().zero_widen_mul(rhs_lo.lo()); + let tmp_1 = lhs_lo.lo().zero_widen_mul(rhs_lo.hi()); + let tmp_2 = lhs_lo.hi().zero_widen_mul(rhs_lo.lo()); + let tmp_3 = lhs_lo.hi().zero_widen_mul(rhs_lo.hi()); + // sum up all widening partials + let mul = Self::from_lo_hi(tmp_0, tmp_3) + .wrapping_add(tmp_1.zero_widen() << (Self::BITS / 4)) + .wrapping_add(tmp_2.zero_widen() << (Self::BITS / 4)); + // add the higher partials + mul.wrapping_add(lhs_lo.wrapping_mul(rhs.hi()).widen_hi()) + .wrapping_add(self.hi().wrapping_mul(rhs_lo).widen_hi()) + } +} + +impl Mul for u64 {} +impl Mul for i128 {} + +pub(crate) trait UMulo: DInt + Int { + fn mulo(self, rhs: Self) -> (Self, bool) { + match (self.hi().is_zero(), rhs.hi().is_zero()) { + // overflow is guaranteed + (false, false) => (self.wrapping_mul(rhs), true), + (true, false) => { + let mul_lo = self.lo().widen_mul(rhs.lo()); + let mul_hi = self.lo().widen_mul(rhs.hi()); + let (mul, o) = mul_lo.overflowing_add(mul_hi.lo().widen_hi()); + (mul, o || !mul_hi.hi().is_zero()) + } + (false, true) => { + let mul_lo = rhs.lo().widen_mul(self.lo()); + let mul_hi = rhs.lo().widen_mul(self.hi()); + let (mul, o) = mul_lo.overflowing_add(mul_hi.lo().widen_hi()); + (mul, o || !mul_hi.hi().is_zero()) + } + // overflow is guaranteed to not happen, and use a smaller widening multiplication + (true, true) => (self.lo().widen_mul(rhs.lo()), false), + } + } +} + +impl UMulo for u32 {} +impl UMulo for u64 {} +impl UMulo for u128 {} + +macro_rules! impl_signed_mulo { + ($fn:ident, $iD:ident, $uD:ident) => { + fn $fn(lhs: $iD, rhs: $iD) -> ($iD, bool) { + let mut lhs = lhs; + let mut rhs = rhs; + // the test against `mul_neg` below fails without this early return + if lhs == 0 || rhs == 0 { + return (0, false); + } + + let lhs_neg = lhs < 0; + let rhs_neg = rhs < 0; + if lhs_neg { + lhs = lhs.wrapping_neg(); + } + if rhs_neg { + rhs = rhs.wrapping_neg(); + } + let mul_neg = lhs_neg != rhs_neg; + + let (mul, o) = (lhs as $uD).mulo(rhs as $uD); + let mut mul = mul as $iD; + + if mul_neg { + mul = mul.wrapping_neg(); + } + if (mul < 0) != mul_neg { + // this one check happens to catch all edge cases related to `$iD::MIN` + (mul, true) + } else { + (mul, o) + } + } + }; +} + +impl_signed_mulo!(i32_overflowing_mul, i32, u32); +impl_signed_mulo!(i64_overflowing_mul, i64, u64); +impl_signed_mulo!(i128_overflowing_mul, i128, u128); + +intrinsics! { + #[maybe_use_optimized_c_shim] + #[arm_aeabi_alias = __aeabi_lmul] + #[cfg(any(not(any(target_arch = "riscv32", target_arch = "riscv64")), target_feature = "m"))] + pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { + a.mul(b) + } + + pub extern "C" fn __multi3(a: i128, b: i128) -> i128 { + a.mul(b) + } + + pub extern "C" fn __mulosi4(a: i32, b: i32, oflow: &mut i32) -> i32 { + let (mul, o) = i32_overflowing_mul(a, b); + *oflow = o as i32; + mul + } + + pub extern "C" fn __mulodi4(a: i64, b: i64, oflow: &mut i32) -> i64 { + let (mul, o) = i64_overflowing_mul(a, b); + *oflow = o as i32; + mul + } + + #[unadjusted_on_win64] + pub extern "C" fn __muloti4(a: i128, b: i128, oflow: &mut i32) -> i128 { + let (mul, o) = i128_overflowing_mul(a, b); + *oflow = o as i32; + mul + } + + pub extern "C" fn __rust_i128_mulo(a: i128, b: i128, oflow: &mut i32) -> i128 { + let (mul, o) = i128_overflowing_mul(a, b); + *oflow = o.into(); + mul + } + + pub extern "C" fn __rust_u128_mulo(a: u128, b: u128, oflow: &mut i32) -> u128 { + let (mul, o) = a.mulo(b); + *oflow = o.into(); + mul + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/compiler-builtins/src/int/sdiv.rs new file mode 100644 index 00000000000..9630c7d7de3 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/sdiv.rs @@ -0,0 +1,169 @@ +use crate::int::udiv::*; + +macro_rules! sdivmod { + ( + $unsigned_fn:ident, // name of the unsigned division function + $signed_fn:ident, // name of the signed division function + $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($attr:tt),* // attributes + ) => { + intrinsics! { + #[avr_skip] + $( + #[$attr] + )* + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn $signed_fn(a: $iX, b: $iX, rem: &mut $iX) -> $iX { + let a_neg = a < 0; + let b_neg = b < 0; + let mut a = a; + let mut b = b; + if a_neg { + a = a.wrapping_neg(); + } + if b_neg { + b = b.wrapping_neg(); + } + let mut r = *rem as $uX; + let t = $unsigned_fn(a as $uX, b as $uX, Some(&mut r)) as $iX; + let mut r = r as $iX; + if a_neg { + r = r.wrapping_neg(); + } + *rem = r; + if a_neg != b_neg { + t.wrapping_neg() + } else { + t + } + } + } + } +} + +macro_rules! sdiv { + ( + $unsigned_fn:ident, // name of the unsigned division function + $signed_fn:ident, // name of the signed division function + $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($attr:tt),* // attributes + ) => { + intrinsics! { + #[avr_skip] + $( + #[$attr] + )* + /// Returns `n / d` + pub extern "C" fn $signed_fn(a: $iX, b: $iX) -> $iX { + let a_neg = a < 0; + let b_neg = b < 0; + let mut a = a; + let mut b = b; + if a_neg { + a = a.wrapping_neg(); + } + if b_neg { + b = b.wrapping_neg(); + } + let t = $unsigned_fn(a as $uX, b as $uX) as $iX; + if a_neg != b_neg { + t.wrapping_neg() + } else { + t + } + } + } + } +} + +macro_rules! smod { + ( + $unsigned_fn:ident, // name of the unsigned division function + $signed_fn:ident, // name of the signed division function + $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($attr:tt),* // attributes + ) => { + intrinsics! { + #[avr_skip] + $( + #[$attr] + )* + /// Returns `n % d` + pub extern "C" fn $signed_fn(a: $iX, b: $iX) -> $iX { + let a_neg = a < 0; + let b_neg = b < 0; + let mut a = a; + let mut b = b; + if a_neg { + a = a.wrapping_neg(); + } + if b_neg { + b = b.wrapping_neg(); + } + let r = $unsigned_fn(a as $uX, b as $uX) as $iX; + if a_neg { + r.wrapping_neg() + } else { + r + } + } + } + } +} + +sdivmod!( + __udivmodsi4, + __divmodsi4, + u32, + i32, + maybe_use_optimized_c_shim +); +// The `#[arm_aeabi_alias = __aeabi_idiv]` attribute cannot be made to work with `intrinsics!` in macros +intrinsics! { + #[maybe_use_optimized_c_shim] + #[arm_aeabi_alias = __aeabi_idiv] + /// Returns `n / d` + pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { + let a_neg = a < 0; + let b_neg = b < 0; + let mut a = a; + let mut b = b; + if a_neg { + a = a.wrapping_neg(); + } + if b_neg { + b = b.wrapping_neg(); + } + let t = __udivsi3(a as u32, b as u32) as i32; + if a_neg != b_neg { + t.wrapping_neg() + } else { + t + } + } +} +smod!(__umodsi3, __modsi3, u32, i32, maybe_use_optimized_c_shim); + +sdivmod!( + __udivmoddi4, + __divmoddi4, + u64, + i64, + maybe_use_optimized_c_shim +); +sdiv!(__udivdi3, __divdi3, u64, i64, maybe_use_optimized_c_shim); +smod!(__umoddi3, __moddi3, u64, i64, maybe_use_optimized_c_shim); + +// LLVM does not currently have a `__divmodti4` function, but GCC does +sdivmod!( + __udivmodti4, + __divmodti4, + u128, + i128, + maybe_use_optimized_c_shim +); +sdiv!(__udivti3, __divti3, u128, i128,); +smod!(__umodti3, __modti3, u128, i128,); diff --git a/library/compiler-builtins/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/compiler-builtins/src/int/shift.rs new file mode 100644 index 00000000000..317272988ce --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/shift.rs @@ -0,0 +1,125 @@ +use crate::int::{DInt, HInt, Int, MinInt}; + +trait Ashl: DInt { + /// Returns `a << b`, requires `b < Self::BITS` + fn ashl(self, shl: u32) -> Self { + let n_h = Self::H::BITS; + if shl & n_h != 0 { + // we only need `self.lo()` because `self.hi()` will be shifted out entirely + self.lo().wrapping_shl(shl - n_h).widen_hi() + } else if shl == 0 { + self + } else { + Self::from_lo_hi( + self.lo().wrapping_shl(shl), + self.lo().logical_shr(n_h.wrapping_sub(shl)) | self.hi().wrapping_shl(shl), + ) + } + } +} + +impl Ashl for u32 {} +impl Ashl for u64 {} +impl Ashl for u128 {} + +trait Ashr: DInt { + /// Returns arithmetic `a >> b`, requires `b < Self::BITS` + fn ashr(self, shr: u32) -> Self { + let n_h = Self::H::BITS; + if shr & n_h != 0 { + Self::from_lo_hi( + self.hi().wrapping_shr(shr - n_h), + // smear the sign bit + self.hi().wrapping_shr(n_h - 1), + ) + } else if shr == 0 { + self + } else { + Self::from_lo_hi( + self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h.wrapping_sub(shr)), + self.hi().wrapping_shr(shr), + ) + } + } +} + +impl Ashr for i32 {} +impl Ashr for i64 {} +impl Ashr for i128 {} + +trait Lshr: DInt { + /// Returns logical `a >> b`, requires `b < Self::BITS` + fn lshr(self, shr: u32) -> Self { + let n_h = Self::H::BITS; + if shr & n_h != 0 { + self.hi().logical_shr(shr - n_h).zero_widen() + } else if shr == 0 { + self + } else { + Self::from_lo_hi( + self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h.wrapping_sub(shr)), + self.hi().logical_shr(shr), + ) + } + } +} + +impl Lshr for u32 {} +impl Lshr for u64 {} +impl Lshr for u128 {} + +intrinsics! { + #[avr_skip] + #[maybe_use_optimized_c_shim] + pub extern "C" fn __ashlsi3(a: u32, b: u32) -> u32 { + a.ashl(b) + } + + #[avr_skip] + #[maybe_use_optimized_c_shim] + #[arm_aeabi_alias = __aeabi_llsl] + pub extern "C" fn __ashldi3(a: u64, b: core::ffi::c_uint) -> u64 { + a.ashl(b as u32) + } + + #[avr_skip] + pub extern "C" fn __ashlti3(a: u128, b: u32) -> u128 { + a.ashl(b) + } + + #[avr_skip] + #[maybe_use_optimized_c_shim] + pub extern "C" fn __ashrsi3(a: i32, b: u32) -> i32 { + a.ashr(b) + } + + #[avr_skip] + #[maybe_use_optimized_c_shim] + #[arm_aeabi_alias = __aeabi_lasr] + pub extern "C" fn __ashrdi3(a: i64, b: core::ffi::c_uint) -> i64 { + a.ashr(b as u32) + } + + #[avr_skip] + pub extern "C" fn __ashrti3(a: i128, b: u32) -> i128 { + a.ashr(b) + } + + #[avr_skip] + #[maybe_use_optimized_c_shim] + pub extern "C" fn __lshrsi3(a: u32, b: u32) -> u32 { + a.lshr(b) + } + + #[avr_skip] + #[maybe_use_optimized_c_shim] + #[arm_aeabi_alias = __aeabi_llsr] + pub extern "C" fn __lshrdi3(a: u64, b: core::ffi::c_uint) -> u64 { + a.lshr(b as u32) + } + + #[avr_skip] + pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 { + a.lshr(b) + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs new file mode 100644 index 00000000000..56ce188a373 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs @@ -0,0 +1,69 @@ +/// Creates an unsigned division function optimized for dividing integers with the same +/// bitwidth as the largest operand in an asymmetrically sized division. For example, x86-64 has an +/// assembly instruction that can divide a 128 bit integer by a 64 bit integer if the quotient fits +/// in 64 bits. The 128 bit version of this algorithm would use that fast hardware division to +/// construct a full 128 bit by 128 bit division. +#[allow(unused_macros)] +macro_rules! impl_asymmetric { + ( + $fn:ident, // name of the unsigned division function + $zero_div_fn:ident, // function called when division by zero is attempted + $half_division:ident, // function for division of a $uX by a $uX + $asymmetric_division:ident, // function for division of a $uD by a $uX + $n_h:expr, // the number of bits in a $iH or $uH + $uH:ident, // unsigned integer with half the bit width of $uX + $uX:ident, // unsigned integer with half the bit width of $uD + $uD:ident // unsigned integer type for the inputs and outputs of `$fn` + ) => { + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + pub fn $fn(duo: $uD, div: $uD) -> ($uD, $uD) { + let n: u32 = $n_h * 2; + + let duo_lo = duo as $uX; + let duo_hi = (duo >> n) as $uX; + let div_lo = div as $uX; + let div_hi = (div >> n) as $uX; + if div_hi == 0 { + if div_lo == 0 { + $zero_div_fn() + } + if duo_hi < div_lo { + // `$uD` by `$uX` division with a quotient that will fit into a `$uX` + let (quo, rem) = unsafe { $asymmetric_division(duo, div_lo) }; + return (quo as $uD, rem as $uD); + } else { + // Short division using the $uD by $uX division + let (quo_hi, rem_hi) = $half_division(duo_hi, div_lo); + let tmp = unsafe { + $asymmetric_division((duo_lo as $uD) | ((rem_hi as $uD) << n), div_lo) + }; + return ((tmp.0 as $uD) | ((quo_hi as $uD) << n), tmp.1 as $uD); + } + } + + // This has been adapted from + // https://www.codeproject.com/tips/785014/uint-division-modulus which was in turn + // adapted from Hacker's Delight. This is similar to the two possibility algorithm + // in that it uses only more significant parts of `duo` and `div` to divide a large + // integer with a smaller division instruction. + let div_lz = div_hi.leading_zeros(); + let div_extra = n - div_lz; + let div_sig_n = (div >> div_extra) as $uX; + let tmp = unsafe { $asymmetric_division(duo >> 1, div_sig_n) }; + + let mut quo = tmp.0 >> ((n - 1) - div_lz); + if quo != 0 { + quo -= 1; + } + + // Note that this is a full `$uD` multiplication being used here + let mut rem = duo - (quo as $uD).wrapping_mul(div); + if div <= rem { + quo += 1; + rem -= div; + } + return (quo as $uD, rem); + } + }; +} diff --git a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/binary_long.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/binary_long.rs new file mode 100644 index 00000000000..2c61a45e06e --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/binary_long.rs @@ -0,0 +1,552 @@ +/// Creates an unsigned division function that uses binary long division, designed for +/// computer architectures without division instructions. These functions have good performance for +/// microarchitectures with large branch miss penalties and architectures without the ability to +/// predicate instructions. For architectures with predicated instructions, one of the algorithms +/// described in the documentation of these functions probably has higher performance, and a custom +/// assembly routine should be used instead. +#[allow(unused_macros)] +macro_rules! impl_binary_long { + ( + $fn:ident, // name of the unsigned division function + $zero_div_fn:ident, // function called when division by zero is attempted + $normalization_shift:ident, // function for finding the normalization shift + $n:tt, // the number of bits in a $iX or $uX + $uX:ident, // unsigned integer type for the inputs and outputs of `$fn` + $iX:ident // signed integer type with same bitwidth as `$uX` + $(, $fun_attr:meta)* // attributes for the function + ) => { + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$fun_attr] + )* + pub fn $fn(duo: $uX, div: $uX) -> ($uX, $uX) { + let mut duo = duo; + // handle edge cases before calling `$normalization_shift` + if div == 0 { + $zero_div_fn() + } + if duo < div { + return (0, duo); + } + + // There are many variations of binary division algorithm that could be used. This + // documentation gives a tour of different methods so that future readers wanting to + // optimize further do not have to painstakingly derive them. The SWAR variation is + // especially hard to understand without reading the less convoluted methods first. + + // You may notice that a `duo < div_original` check is included in many these + // algorithms. A critical optimization that many algorithms miss is handling of + // quotients that will turn out to have many trailing zeros or many leading zeros. This + // happens in cases of exact or close-to-exact divisions, divisions by power of two, and + // in cases where the quotient is small. The `duo < div_original` check handles these + // cases of early returns and ends up replacing other kinds of mundane checks that + // normally terminate a binary division algorithm. + // + // Something you may see in other algorithms that is not special-cased here is checks + // for division by powers of two. The `duo < div_original` check handles this case and + // more, however it can be checked up front before the bisection using the + // `((div > 0) && ((div & (div - 1)) == 0))` trick. This is not special-cased because + // compilers should handle most cases where divisions by power of two occur, and we do + // not want to add on a few cycles for every division operation just to save a few + // cycles rarely. + + // The following example is the most straightforward translation from the way binary + // long division is typically visualized: + // Dividing 178u8 (0b10110010) by 6u8 (0b110). `div` is shifted left by 5, according to + // the result from `$normalization_shift(duo, div, false)`. + // + // Step 0: `sub` is negative, so there is not full normalization, so no `quo` bit is set + // and `duo` is kept unchanged. + // duo:10110010, div_shifted:11000000, sub:11110010, quo:00000000, shl:5 + // + // Step 1: `sub` is positive, set a `quo` bit and update `duo` for next step. + // duo:10110010, div_shifted:01100000, sub:01010010, quo:00010000, shl:4 + // + // Step 2: Continue based on `sub`. The `quo` bits start accumulating. + // duo:01010010, div_shifted:00110000, sub:00100010, quo:00011000, shl:3 + // duo:00100010, div_shifted:00011000, sub:00001010, quo:00011100, shl:2 + // duo:00001010, div_shifted:00001100, sub:11111110, quo:00011100, shl:1 + // duo:00001010, div_shifted:00000110, sub:00000100, quo:00011100, shl:0 + // The `duo < div_original` check terminates the algorithm with the correct quotient of + // 29u8 and remainder of 4u8 + /* + let div_original = div; + let mut shl = $normalization_shift(duo, div, false); + let mut quo = 0; + loop { + let div_shifted = div << shl; + let sub = duo.wrapping_sub(div_shifted); + // it is recommended to use `println!`s like this if functionality is unclear + /* + println!("duo:{:08b}, div_shifted:{:08b}, sub:{:08b}, quo:{:08b}, shl:{}", + duo, + div_shifted, + sub, + quo, + shl + ); + */ + if 0 <= (sub as $iX) { + duo = sub; + quo += 1 << shl; + if duo < div_original { + // this branch is optional + return (quo, duo) + } + } + if shl == 0 { + return (quo, duo) + } + shl -= 1; + } + */ + + // This restoring binary long division algorithm reduces the number of operations + // overall via: + // - `pow` can be shifted right instead of recalculating from `shl` + // - starting `div` shifted left and shifting it right for each step instead of + // recalculating from `shl` + // - The `duo < div_original` branch is used to terminate the algorithm instead of the + // `shl == 0` branch. This check is strong enough to prevent set bits of `pow` and + // `div` from being shifted off the end. This check also only occurs on half of steps + // on average, since it is behind the `(sub as $iX) >= 0` branch. + // - `shl` is now not needed by any aspect of of the loop and thus only 3 variables are + // being updated between steps + // + // There are many variations of this algorithm, but this encompases the largest number + // of architectures and does not rely on carry flags, add-with-carry, or SWAR + // complications to be decently fast. + /* + let div_original = div; + let shl = $normalization_shift(duo, div, false); + let mut div: $uX = div << shl; + let mut pow: $uX = 1 << shl; + let mut quo: $uX = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as $iX) { + duo = sub; + quo |= pow; + if duo < div_original { + return (quo, duo) + } + } + div >>= 1; + pow >>= 1; + } + */ + + // If the architecture has flags and predicated arithmetic instructions, it is possible + // to do binary long division without branching and in only 3 or 4 instructions. This is + // a variation of a 3 instruction central loop from + // http://www.chiark.greenend.org.uk/~theom/riscos/docs/ultimate/a252div.txt. + // + // What allows doing division in only 3 instructions is realizing that instead of + // keeping `duo` in place and shifting `div` right to align bits, `div` can be kept in + // place and `duo` can be shifted left. This means `div` does not have to be updated, + // but causes edge case problems and makes `duo < div_original` tests harder. Some + // architectures have an option to shift an argument in an arithmetic operation, which + // means `duo` can be shifted left and subtracted from in one instruction. The other two + // instructions are updating `quo` and undoing the subtraction if it turns out things + // were not normalized. + + /* + // Perform one binary long division step on the already normalized arguments, because + // the main. Note that this does a full normalization since the central loop needs + // `duo.leading_zeros()` to be at least 1 more than `div.leading_zeros()`. The original + // variation only did normalization to the nearest 4 steps, but this makes handling edge + // cases much harder. We do a full normalization and perform a binary long division + // step. In the edge case where the msbs of `duo` and `div` are set, it clears the msb + // of `duo`, then the edge case handler shifts `div` right and does another long + // division step to always insure `duo.leading_zeros() + 1 >= div.leading_zeros()`. + let div_original = div; + let mut shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + let mut quo: $uX = 1; + duo = duo.wrapping_sub(div); + if duo < div_original { + return (1 << shl, duo); + } + let div_neg: $uX; + if (div as $iX) < 0 { + // A very ugly edge case where the most significant bit of `div` is set (after + // shifting to match `duo` when its most significant bit is at the sign bit), which + // leads to the sign bit of `div_neg` being cut off and carries not happening when + // they should. This branch performs a long division step that keeps `duo` in place + // and shifts `div` down. + div >>= 1; + div_neg = div.wrapping_neg(); + let (sub, carry) = duo.overflowing_add(div_neg); + duo = sub; + quo = quo.wrapping_add(quo).wrapping_add(carry as $uX); + if !carry { + duo = duo.wrapping_add(div); + } + shl -= 1; + } else { + div_neg = div.wrapping_neg(); + } + // The add-with-carry that updates `quo` needs to have the carry set when a normalized + // subtract happens. Using `duo.wrapping_shl(1).overflowing_sub(div)` to do the + // subtraction generates a carry when an unnormalized subtract happens, which is the + // opposite of what we want. Instead, we use + // `duo.wrapping_shl(1).overflowing_add(div_neg)`, where `div_neg` is negative `div`. + let mut i = shl; + loop { + if i == 0 { + break; + } + i -= 1; + // `ADDS duo, div, duo, LSL #1` + // (add `div` to `duo << 1` and set flags) + let (sub, carry) = duo.wrapping_shl(1).overflowing_add(div_neg); + duo = sub; + // `ADC quo, quo, quo` + // (add with carry). Effectively shifts `quo` left by 1 and sets the least + // significant bit to the carry. + quo = quo.wrapping_add(quo).wrapping_add(carry as $uX); + // `ADDCC duo, duo, div` + // (add if carry clear). Undoes the subtraction if no carry was generated. + if !carry { + duo = duo.wrapping_add(div); + } + } + return (quo, duo >> shl); + */ + + // This is the SWAR (SIMD within in a register) restoring division algorithm. + // This combines several ideas of the above algorithms: + // - If `duo` is shifted left instead of shifting `div` right like in the 3 instruction + // restoring division algorithm, some architectures can do the shifting and + // subtraction step in one instruction. + // - `quo` can be constructed by adding powers-of-two to it or shifting it left by one + // and adding one. + // - Every time `duo` is shifted left, there is another unused 0 bit shifted into the + // LSB, so what if we use those bits to store `quo`? + // Through a complex setup, it is possible to manage `duo` and `quo` in the same + // register, and perform one step with 2 or 3 instructions. The only major downsides are + // that there is significant setup (it is only saves instructions if `shl` is + // approximately more than 4), `duo < div_original` checks are impractical once SWAR is + // initiated, and the number of division steps taken has to be exact (we cannot do more + // division steps than `shl`, because it introduces edge cases where quotient bits in + // `duo` start to collide with the real part of `div`. + /* + // first step. The quotient bit is stored in `quo` for now + let div_original = div; + let mut shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + duo = duo.wrapping_sub(div); + let mut quo: $uX = 1 << shl; + if duo < div_original { + return (quo, duo); + } + + let mask: $uX; + if (div as $iX) < 0 { + // deal with same edge case as the 3 instruction restoring division algorithm, but + // the quotient bit from this step also has to be stored in `quo` + div >>= 1; + shl -= 1; + let tmp = 1 << shl; + mask = tmp - 1; + let sub = duo.wrapping_sub(div); + if (sub as $iX) >= 0 { + // restore + duo = sub; + quo |= tmp; + } + if duo < div_original { + return (quo, duo); + } + } else { + mask = quo - 1; + } + // There is now room for quotient bits in `duo`. + + // Note that `div` is already shifted left and has `shl` unset bits. We subtract 1 from + // `div` and end up with the subset of `shl` bits being all being set. This subset acts + // just like a two's complement negative one. The subset of `div` containing the divisor + // had 1 subtracted from it, but a carry will always be generated from the `shl` subset + // as long as the quotient stays positive. + // + // When the modified `div` is subtracted from `duo.wrapping_shl(1)`, the `shl` subset + // adds a quotient bit to the least significant bit. + // For example, 89 (0b01011001) divided by 3 (0b11): + // + // shl:4, div:0b00110000 + // first step: + // duo:0b01011001 + // + div_neg:0b11010000 + // ____________________ + // 0b00101001 + // quo is set to 0b00010000 and mask is set to 0b00001111 for later + // + // 1 is subtracted from `div`. I will differentiate the `shl` part of `div` and the + // quotient part of `duo` with `^`s. + // chars. + // div:0b00110000 + // ^^^^ + // + 0b11111111 + // ________________ + // 0b00101111 + // ^^^^ + // div_neg:0b11010001 + // + // first SWAR step: + // duo_shl1:0b01010010 + // ^ + // + div_neg:0b11010001 + // ____________________ + // 0b00100011 + // ^ + // second: + // duo_shl1:0b01000110 + // ^^ + // + div_neg:0b11010001 + // ____________________ + // 0b00010111 + // ^^ + // third: + // duo_shl1:0b00101110 + // ^^^ + // + div_neg:0b11010001 + // ____________________ + // 0b11111111 + // ^^^ + // 3 steps resulted in the quotient with 3 set bits as expected, but currently the real + // part of `duo` is negative and the third step was an unnormalized step. The restore + // branch then restores `duo`. Note that the restore branch does not shift `duo` left. + // + // duo:0b11111111 + // ^^^ + // + div:0b00101111 + // ^^^^ + // ________________ + // 0b00101110 + // ^^^ + // `duo` is now back in the `duo_shl1` state it was at in the the third step, with an + // unset quotient bit. + // + // final step (`shl` was 4, so exactly 4 steps must be taken) + // duo_shl1:0b01011100 + // ^^^^ + // + div_neg:0b11010001 + // ____________________ + // 0b00101101 + // ^^^^ + // The quotient includes the `^` bits added with the `quo` bits from the beginning that + // contained the first step and potential edge case step, + // `quo:0b00010000 + (duo:0b00101101 & mask:0b00001111) == 0b00011101 == 29u8`. + // The remainder is the bits remaining in `duo` that are not part of the quotient bits, + // `duo:0b00101101 >> shl == 0b0010 == 2u8`. + let div: $uX = div.wrapping_sub(1); + let mut i = shl; + loop { + if i == 0 { + break; + } + i -= 1; + duo = duo.wrapping_shl(1).wrapping_sub(div); + if (duo as $iX) < 0 { + // restore + duo = duo.wrapping_add(div); + } + } + // unpack the results of SWAR + return ((duo & mask) | quo, duo >> shl); + */ + + // The problem with the conditional restoring SWAR algorithm above is that, in practice, + // it requires assembly code to bring out its full unrolled potential (It seems that + // LLVM can't use unrolled conditionals optimally and ends up erasing all the benefit + // that my algorithm intends. On architectures without predicated instructions, the code + // gen is especially bad. We need a default software division algorithm that is + // guaranteed to get decent code gen for the central loop. + + // For non-SWAR algorithms, there is a way to do binary long division without + // predication or even branching. This involves creating a mask from the sign bit and + // performing different kinds of steps using that. + /* + let shl = $normalization_shift(duo, div, true); + let mut div: $uX = div << shl; + let mut pow: $uX = 1 << shl; + let mut quo: $uX = 0; + loop { + let sub = duo.wrapping_sub(div); + let sign_mask = !((sub as $iX).wrapping_shr($n - 1) as $uX); + duo -= div & sign_mask; + quo |= pow & sign_mask; + div >>= 1; + pow >>= 1; + if pow == 0 { + break; + } + } + return (quo, duo); + */ + // However, it requires about 4 extra operations (smearing the sign bit, negating the + // mask, and applying the mask twice) on top of the operations done by the actual + // algorithm. With SWAR however, just 2 extra operations are needed, making it + // practical and even the most optimal algorithm for some architectures. + + // What we do is use custom assembly for predicated architectures that need software + // division, and for the default algorithm use a mask based restoring SWAR algorithm + // without conditionals or branches. On almost all architectures, this Rust code is + // guaranteed to compile down to 5 assembly instructions or less for each step, and LLVM + // will unroll it in a decent way. + + // standard opening for SWAR algorithm with first step and edge case handling + let div_original = div; + let mut shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + duo = duo.wrapping_sub(div); + let mut quo: $uX = 1 << shl; + if duo < div_original { + return (quo, duo); + } + let mask: $uX; + if (div as $iX) < 0 { + div >>= 1; + shl -= 1; + let tmp = 1 << shl; + mask = tmp - 1; + let sub = duo.wrapping_sub(div); + if (sub as $iX) >= 0 { + duo = sub; + quo |= tmp; + } + if duo < div_original { + return (quo, duo); + } + } else { + mask = quo - 1; + } + + // central loop + div = div.wrapping_sub(1); + let mut i = shl; + loop { + if i == 0 { + break; + } + i -= 1; + // shift left 1 and subtract + duo = duo.wrapping_shl(1).wrapping_sub(div); + // create mask + let mask = (duo as $iX).wrapping_shr($n - 1) as $uX; + // restore + duo = duo.wrapping_add(div & mask); + } + // unpack + return ((duo & mask) | quo, duo >> shl); + + // miscellanious binary long division algorithms that might be better for specific + // architectures + + // Another kind of long division uses an interesting fact that `div` and `pow` can be + // negated when `duo` is negative to perform a "negated" division step that works in + // place of any normalization mechanism. This is a non-restoring division algorithm that + // is very similar to the non-restoring division algorithms that can be found on the + // internet, except there is only one test for `duo < 0`. The subtraction from `quo` can + // be viewed as shifting the least significant set bit right (e.x. if we enter a series + // of negated binary long division steps starting with `quo == 0b1011_0000` and + // `pow == 0b0000_1000`, `quo` will progress like this: 0b1010_1000, 0b1010_0100, + // 0b1010_0010, 0b1010_0001). + /* + let div_original = div; + let shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + let mut pow: $uX = 1 << shl; + let mut quo: $uX = pow; + duo = duo.wrapping_sub(div); + if duo < div_original { + return (quo, duo); + } + div >>= 1; + pow >>= 1; + loop { + if (duo as $iX) < 0 { + // Negated binary long division step. + duo = duo.wrapping_add(div); + quo = quo.wrapping_sub(pow); + } else { + // Normal long division step. + if duo < div_original { + return (quo, duo) + } + duo = duo.wrapping_sub(div); + quo = quo.wrapping_add(pow); + } + pow >>= 1; + div >>= 1; + } + */ + + // This is the Nonrestoring SWAR algorithm, combining the nonrestoring algorithm with + // SWAR techniques that makes the only difference between steps be negation of `div`. + // If there was an architecture with an instruction that negated inputs to an adder + // based on conditionals, and in place shifting (or a three input addition operation + // that can have `duo` as two of the inputs to effectively shift it left by 1), then a + // single instruction central loop is possible. Microarchitectures often have inputs to + // their ALU that can invert the arguments and carry in of adders, but the architectures + // unfortunately do not have an instruction to dynamically invert this input based on + // conditionals. + /* + // SWAR opening + let div_original = div; + let mut shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + duo = duo.wrapping_sub(div); + let mut quo: $uX = 1 << shl; + if duo < div_original { + return (quo, duo); + } + let mask: $uX; + if (div as $iX) < 0 { + div >>= 1; + shl -= 1; + let tmp = 1 << shl; + let sub = duo.wrapping_sub(div); + if (sub as $iX) >= 0 { + // restore + duo = sub; + quo |= tmp; + } + if duo < div_original { + return (quo, duo); + } + mask = tmp - 1; + } else { + mask = quo - 1; + } + + // central loop + let div: $uX = div.wrapping_sub(1); + let mut i = shl; + loop { + if i == 0 { + break; + } + i -= 1; + // note: the `wrapping_shl(1)` can be factored out, but would require another + // restoring division step to prevent `(duo as $iX)` from overflowing + if (duo as $iX) < 0 { + // Negated binary long division step. + duo = duo.wrapping_shl(1).wrapping_add(div); + } else { + // Normal long division step. + duo = duo.wrapping_shl(1).wrapping_sub(div); + } + } + if (duo as $iX) < 0 { + // Restore. This was not needed in the original nonrestoring algorithm because of + // the `duo < div_original` checks. + duo = duo.wrapping_add(div); + } + // unpack + return ((duo & mask) | quo, duo >> shl); + */ + } + }; +} diff --git a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/delegate.rs new file mode 100644 index 00000000000..f5c6e50239a --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -0,0 +1,317 @@ +/// Creates an unsigned division function that uses a combination of hardware division and +/// binary long division to divide integers larger than what hardware division by itself can do. This +/// function is intended for microarchitectures that have division hardware, but not fast enough +/// multiplication hardware for `impl_trifecta` to be faster. +#[allow(unused_macros)] +macro_rules! impl_delegate { + ( + $fn:ident, // name of the unsigned division function + $zero_div_fn:ident, // function called when division by zero is attempted + $half_normalization_shift:ident, // function for finding the normalization shift of $uX + $half_division:ident, // function for division of a $uX by a $uX + $n_h:expr, // the number of bits in $iH or $uH + $uH:ident, // unsigned integer with half the bit width of $uX + $uX:ident, // unsigned integer with half the bit width of $uD. + $uD:ident, // unsigned integer type for the inputs and outputs of `$fn` + $iD:ident // signed integer type with the same bitwidth as `$uD` + ) => { + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + pub fn $fn(duo: $uD, div: $uD) -> ($uD, $uD) { + // The two possibility algorithm, undersubtracting long division algorithm, or any kind + // of reciprocal based algorithm will not be fastest, because they involve large + // multiplications that we assume to not be fast enough relative to the divisions to + // outweigh setup times. + + // the number of bits in a $uX + let n = $n_h * 2; + + let duo_lo = duo as $uX; + let duo_hi = (duo >> n) as $uX; + let div_lo = div as $uX; + let div_hi = (div >> n) as $uX; + + match (div_lo == 0, div_hi == 0, duo_hi == 0) { + (true, true, _) => $zero_div_fn(), + (_, false, true) => { + // `duo` < `div` + return (0, duo); + } + (false, true, true) => { + // delegate to smaller division + let tmp = $half_division(duo_lo, div_lo); + return (tmp.0 as $uD, tmp.1 as $uD); + } + (false, true, false) => { + if duo_hi < div_lo { + // `quo_hi` will always be 0. This performs a binary long division algorithm + // to zero `duo_hi` followed by a half division. + + // We can calculate the normalization shift using only `$uX` size functions. + // If we calculated the normalization shift using + // `$half_normalization_shift(duo_hi, div_lo false)`, it would break the + // assumption the function has that the first argument is more than the + // second argument. If the arguments are switched, the assumption holds true + // since `duo_hi < div_lo`. + let norm_shift = $half_normalization_shift(div_lo, duo_hi, false); + let shl = if norm_shift == 0 { + // Consider what happens if the msbs of `duo_hi` and `div_lo` align with + // no shifting. The normalization shift will always return + // `norm_shift == 0` regardless of whether it is fully normalized, + // because `duo_hi < div_lo`. In that edge case, `n - norm_shift` would + // result in shift overflow down the line. For the edge case, because + // both `duo_hi < div_lo` and we are comparing all the significant bits + // of `duo_hi` and `div`, we can make `shl = n - 1`. + n - 1 + } else { + // We also cannot just use `shl = n - norm_shift - 1` in the general + // case, because when we are not in the edge case comparing all the + // significant bits, then the full `duo < div` may not be true and thus + // breaks the division algorithm. + n - norm_shift + }; + + // The 3 variable restoring division algorithm (see binary_long.rs) is ideal + // for this task, since `pow` and `quo` can be `$uX` and the delegation + // check is simple. + let mut div: $uD = div << shl; + let mut pow_lo: $uX = 1 << shl; + let mut quo_lo: $uX = 0; + let mut duo = duo; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as $iD) { + duo = sub; + quo_lo |= pow_lo; + let duo_hi = (duo >> n) as $uX; + if duo_hi == 0 { + // Delegate to get the rest of the quotient. Note that the + // `div_lo` here is the original unshifted `div`. + let tmp = $half_division(duo as $uX, div_lo); + return ((quo_lo | tmp.0) as $uD, tmp.1 as $uD); + } + } + div >>= 1; + pow_lo >>= 1; + } + } else if duo_hi == div_lo { + // `quo_hi == 1`. This branch is cheap and helps with edge cases. + let tmp = $half_division(duo as $uX, div as $uX); + return ((1 << n) | (tmp.0 as $uD), tmp.1 as $uD); + } else { + // `div_lo < duo_hi` + // `rem_hi == 0` + if (div_lo >> $n_h) == 0 { + // Short division of $uD by a $uH, using $uX by $uX division + let div_0 = div_lo as $uH as $uX; + let (quo_hi, rem_3) = $half_division(duo_hi, div_0); + + let duo_mid = ((duo >> $n_h) as $uH as $uX) | (rem_3 << $n_h); + let (quo_1, rem_2) = $half_division(duo_mid, div_0); + + let duo_lo = (duo as $uH as $uX) | (rem_2 << $n_h); + let (quo_0, rem_1) = $half_division(duo_lo, div_0); + + return ( + (quo_0 as $uD) | ((quo_1 as $uD) << $n_h) | ((quo_hi as $uD) << n), + rem_1 as $uD, + ); + } + + // This is basically a short division composed of a half division for the hi + // part, specialized 3 variable binary long division in the middle, and + // another half division for the lo part. + let duo_lo = duo as $uX; + let tmp = $half_division(duo_hi, div_lo); + let quo_hi = tmp.0; + let mut duo = (duo_lo as $uD) | ((tmp.1 as $uD) << n); + // This check is required to avoid breaking the long division below. + if duo < div { + return ((quo_hi as $uD) << n, duo); + } + + // The half division handled all shift alignments down to `n`, so this + // division can continue with a shift of `n - 1`. + let mut div: $uD = div << (n - 1); + let mut pow_lo: $uX = 1 << (n - 1); + let mut quo_lo: $uX = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as $iD) { + duo = sub; + quo_lo |= pow_lo; + let duo_hi = (duo >> n) as $uX; + if duo_hi == 0 { + // Delegate to get the rest of the quotient. Note that the + // `div_lo` here is the original unshifted `div`. + let tmp = $half_division(duo as $uX, div_lo); + return ( + (tmp.0) as $uD | (quo_lo as $uD) | ((quo_hi as $uD) << n), + tmp.1 as $uD, + ); + } + } + div >>= 1; + pow_lo >>= 1; + } + } + } + (_, false, false) => { + // Full $uD by $uD binary long division. `quo_hi` will always be 0. + if duo < div { + return (0, duo); + } + let div_original = div; + let shl = $half_normalization_shift(duo_hi, div_hi, false); + let mut duo = duo; + let mut div: $uD = div << shl; + let mut pow_lo: $uX = 1 << shl; + let mut quo_lo: $uX = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as $iD) { + duo = sub; + quo_lo |= pow_lo; + if duo < div_original { + return (quo_lo as $uD, duo); + } + } + div >>= 1; + pow_lo >>= 1; + } + } + } + } + }; +} + +/// Returns `n / d` and sets `*rem = n % d`. +/// +/// This specialization exists because: +/// - The LLVM backend for 32-bit SPARC cannot compile functions that return `(u128, u128)`, +/// so we have to use an old fashioned `&mut u128` argument to return the remainder. +/// - 64-bit SPARC does not have u64 * u64 => u128 widening multiplication, which makes the +/// delegate algorithm strategy the only reasonably fast way to perform `u128` division. +// used on SPARC +#[allow(dead_code)] +pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { + use super::*; + let duo_lo = duo as u64; + let duo_hi = (duo >> 64) as u64; + let div_lo = div as u64; + let div_hi = (div >> 64) as u64; + + match (div_lo == 0, div_hi == 0, duo_hi == 0) { + (true, true, _) => zero_div_fn(), + (_, false, true) => { + *rem = duo; + return 0; + } + (false, true, true) => { + let tmp = u64_by_u64_div_rem(duo_lo, div_lo); + *rem = tmp.1 as u128; + return tmp.0 as u128; + } + (false, true, false) => { + if duo_hi < div_lo { + let norm_shift = u64_normalization_shift(div_lo, duo_hi, false); + let shl = if norm_shift == 0 { + 64 - 1 + } else { + 64 - norm_shift + }; + + let mut div: u128 = div << shl; + let mut pow_lo: u64 = 1 << shl; + let mut quo_lo: u64 = 0; + let mut duo = duo; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as i128) { + duo = sub; + quo_lo |= pow_lo; + let duo_hi = (duo >> 64) as u64; + if duo_hi == 0 { + let tmp = u64_by_u64_div_rem(duo as u64, div_lo); + *rem = tmp.1 as u128; + return (quo_lo | tmp.0) as u128; + } + } + div >>= 1; + pow_lo >>= 1; + } + } else if duo_hi == div_lo { + let tmp = u64_by_u64_div_rem(duo as u64, div as u64); + *rem = tmp.1 as u128; + return (1 << 64) | (tmp.0 as u128); + } else { + if (div_lo >> 32) == 0 { + let div_0 = div_lo as u32 as u64; + let (quo_hi, rem_3) = u64_by_u64_div_rem(duo_hi, div_0); + + let duo_mid = ((duo >> 32) as u32 as u64) | (rem_3 << 32); + let (quo_1, rem_2) = u64_by_u64_div_rem(duo_mid, div_0); + + let duo_lo = (duo as u32 as u64) | (rem_2 << 32); + let (quo_0, rem_1) = u64_by_u64_div_rem(duo_lo, div_0); + + *rem = rem_1 as u128; + return (quo_0 as u128) | ((quo_1 as u128) << 32) | ((quo_hi as u128) << 64); + } + + let duo_lo = duo as u64; + let tmp = u64_by_u64_div_rem(duo_hi, div_lo); + let quo_hi = tmp.0; + let mut duo = (duo_lo as u128) | ((tmp.1 as u128) << 64); + if duo < div { + *rem = duo; + return (quo_hi as u128) << 64; + } + + let mut div: u128 = div << (64 - 1); + let mut pow_lo: u64 = 1 << (64 - 1); + let mut quo_lo: u64 = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as i128) { + duo = sub; + quo_lo |= pow_lo; + let duo_hi = (duo >> 64) as u64; + if duo_hi == 0 { + let tmp = u64_by_u64_div_rem(duo as u64, div_lo); + *rem = tmp.1 as u128; + return (tmp.0) as u128 | (quo_lo as u128) | ((quo_hi as u128) << 64); + } + } + div >>= 1; + pow_lo >>= 1; + } + } + } + (_, false, false) => { + if duo < div { + *rem = duo; + return 0; + } + let div_original = div; + let shl = u64_normalization_shift(duo_hi, div_hi, false); + let mut duo = duo; + let mut div: u128 = div << shl; + let mut pow_lo: u64 = 1 << shl; + let mut quo_lo: u64 = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as i128) { + duo = sub; + quo_lo |= pow_lo; + if duo < div_original { + *rem = duo; + return quo_lo as u128; + } + } + div >>= 1; + pow_lo >>= 1; + } + } + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs new file mode 100644 index 00000000000..a91fe6632ee --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -0,0 +1,321 @@ +// TODO: when `unsafe_block_in_unsafe_fn` is stabilized, remove this +#![allow(unused_unsafe)] +// The functions are complex with many branches, and explicit +// `return`s makes it clear where function exit points are +#![allow(clippy::needless_return)] +#![allow(clippy::comparison_chain)] +// Clippy is confused by the complex configuration +#![allow(clippy::if_same_then_else)] +#![allow(clippy::needless_bool)] + +//! This `specialized_div_rem` module is originally from version 1.0.0 of the +//! `specialized-div-rem` crate. Note that `for` loops with ranges are not used in this +//! module, since unoptimized compilation may generate references to `memcpy`. +//! +//! The purpose of these macros is to easily change the both the division algorithm used +//! for a given integer size and the half division used by that algorithm. The way +//! functions call each other is also constructed such that linkers will find the chain of +//! software and hardware divisions needed for every size of signed and unsigned division. +//! For example, most target compilations do the following: +//! +//! - Many 128 bit division functions like `u128::wrapping_div` use +//! `std::intrinsics::unchecked_div`, which gets replaced by `__udivti3` because there +//! is not a 128 bit by 128 bit hardware division function in most architectures. +//! `__udivti3` uses `u128_div_rem` (this extra level of function calls exists because +//! `__umodti3` and `__udivmodti4` also exist, and `specialized_div_rem` supplies just +//! one function to calculate both the quotient and remainder. If configuration flags +//! enable it, `impl_trifecta!` defines `u128_div_rem` to use the trifecta algorithm, +//! which requires the half sized division `u64_by_u64_div_rem`. If the architecture +//! supplies a 64 bit hardware division instruction, `u64_by_u64_div_rem` will be +//! reduced to those instructions. Note that we do not specify the half size division +//! directly to be `__udivdi3`, because hardware division would never be introduced. +//! - If the architecture does not supply a 64 bit hardware division instruction, u64 +//! divisions will use functions such as `__udivdi3`. This will call `u64_div_rem` +//! which is defined by `impl_delegate!`. The half division for this algorithm is +//! `u32_by_u32_div_rem` which in turn becomes hardware division instructions or more +//! software division algorithms. +//! - If the architecture does not supply a 32 bit hardware instruction, linkers will +//! look for `__udivsi3`. `impl_binary_long!` is used, but this algorithm uses no half +//! division, so the chain of calls ends here. +//! +//! On some architectures like x86_64, an asymmetrically sized division is supplied, in +//! which 128 bit numbers can be divided by 64 bit numbers. `impl_asymmetric!` is used to +//! extend the 128 by 64 bit division to a full 128 by 128 bit division. + +// `allow(dead_code)` is used in various places, because the configuration code would otherwise be +// ridiculously complex + +#[macro_use] +mod norm_shift; + +#[macro_use] +mod binary_long; + +#[macro_use] +mod delegate; + +// used on SPARC +#[allow(unused_imports)] +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use self::delegate::u128_divide_sparc; + +#[cfg(feature = "public-test-deps")] +pub use self::delegate::u128_divide_sparc; + +#[macro_use] +mod trifecta; + +#[macro_use] +mod asymmetric; + +/// The behavior of all divisions by zero is controlled by this function. This function should be +/// impossible to reach by Rust users, unless `compiler-builtins` public division functions or +/// `core/std::unchecked_div/rem` are directly used without a zero check in front. +fn zero_div_fn() -> ! { + // Calling the intrinsic directly, to avoid the `assert_unsafe_precondition` that cannot be used + // here because it involves non-`inline` functions + // (https://github.com/rust-lang/compiler-builtins/issues/491). + unsafe { core::intrinsics::unreachable() } +} + +const USE_LZ: bool = { + if cfg!(target_arch = "arm") { + if cfg!(target_feature = "thumb-mode") { + // ARM thumb targets have CLZ instructions if the instruction set of ARMv6T2 is + // supported. This is needed to successfully differentiate between targets like + // `thumbv8.base` and `thumbv8.main`. + cfg!(target_feature = "v6t2") + } else { + // Regular ARM targets have CLZ instructions if the ARMv5TE instruction set is + // supported. Technically, ARMv5T was the first to have CLZ, but the "v5t" target + // feature does not seem to work. + cfg!(target_feature = "v5te") + } + } else if cfg!(any(target_arch = "sparc", target_arch = "sparc64")) { + // LZD or LZCNT on SPARC only exists for the VIS 3 extension and later. + cfg!(target_feature = "vis3") + } else if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { + // The 'Zbb' Basic Bit-Manipulation extension on RISC-V + // determines if a CLZ assembly instruction exists + cfg!(target_feature = "zbb") + } else { + // All other common targets Rust supports should have CLZ instructions + true + } +}; + +impl_normalization_shift!( + u32_normalization_shift, + USE_LZ, + 32, + u32, + i32, + allow(dead_code) +); +impl_normalization_shift!( + u64_normalization_shift, + USE_LZ, + 64, + u64, + i64, + allow(dead_code) +); + +/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. +/// `checked_div` and `checked_rem` are used to avoid bringing in panic function +/// dependencies. +#[inline] +fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { + if let Some(quo) = duo.checked_div(div) { + if let Some(rem) = duo.checked_rem(div) { + return (quo, rem); + } + } + zero_div_fn() +} + +// Whether `trifecta` or `delegate` is faster for 128 bit division depends on the speed at which a +// microarchitecture can multiply and divide. We decide to be optimistic and assume `trifecta` is +// faster if the target pointer width is at least 64. Note that this +// implementation is additionally included on WebAssembly despite the typical +// pointer width there being 32 because it's typically run on a 64-bit machine +// that has access to faster 64-bit operations. +#[cfg(all( + any( + target_family = "wasm", + not(any(target_pointer_width = "16", target_pointer_width = "32")), + ), + not(all(not(feature = "no-asm"), target_arch = "x86_64")), + not(any(target_arch = "sparc", target_arch = "sparc64")) +))] +impl_trifecta!( + u128_div_rem, + zero_div_fn, + u64_by_u64_div_rem, + 32, + u32, + u64, + u128 +); + +// If the pointer width less than 64 and this isn't wasm, then the target +// architecture almost certainly does not have the fast 64 to 128 bit widening +// multiplication needed for `trifecta` to be faster. +#[cfg(all( + not(any( + target_family = "wasm", + not(any(target_pointer_width = "16", target_pointer_width = "32")), + )), + not(all(not(feature = "no-asm"), target_arch = "x86_64")), + not(any(target_arch = "sparc", target_arch = "sparc64")) +))] +impl_delegate!( + u128_div_rem, + zero_div_fn, + u64_normalization_shift, + u64_by_u64_div_rem, + 32, + u32, + u64, + u128, + i128 +); + +/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. +/// +/// # Safety +/// +/// If the quotient does not fit in a `u64`, a floating point exception occurs. +/// If `div == 0`, then a division by zero exception occurs. +#[cfg(all(not(feature = "no-asm"), target_arch = "x86_64"))] +#[inline] +unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { + let duo_lo = duo as u64; + let duo_hi = (duo >> 64) as u64; + let quo: u64; + let rem: u64; + unsafe { + // divides the combined registers rdx:rax (`duo` is split into two 64 bit parts to do this) + // by `div`. The quotient is stored in rax and the remainder in rdx. + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. + core::arch::asm!( + "div {0}", + in(reg) div, + inlateout("rax") duo_lo => quo, + inlateout("rdx") duo_hi => rem, + options(att_syntax, pure, nomem, nostack) + ); + } + (quo, rem) +} + +// use `asymmetric` instead of `trifecta` on x86_64 +#[cfg(all(not(feature = "no-asm"), target_arch = "x86_64"))] +impl_asymmetric!( + u128_div_rem, + zero_div_fn, + u64_by_u64_div_rem, + u128_by_u64_div_rem, + 32, + u32, + u64, + u128 +); + +/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. +/// `checked_div` and `checked_rem` are used to avoid bringing in panic function +/// dependencies. +#[inline] +#[allow(dead_code)] +fn u32_by_u32_div_rem(duo: u32, div: u32) -> (u32, u32) { + if let Some(quo) = duo.checked_div(div) { + if let Some(rem) = duo.checked_rem(div) { + return (quo, rem); + } + } + zero_div_fn() +} + +// When not on x86 and the pointer width is not 64, use `delegate` since the division size is larger +// than register size. +#[cfg(all( + not(all(not(feature = "no-asm"), target_arch = "x86")), + not(target_pointer_width = "64") +))] +impl_delegate!( + u64_div_rem, + zero_div_fn, + u32_normalization_shift, + u32_by_u32_div_rem, + 16, + u16, + u32, + u64, + i64 +); + +// When not on x86 and the pointer width is 64, use `binary_long`. +#[cfg(all( + not(all(not(feature = "no-asm"), target_arch = "x86")), + target_pointer_width = "64" +))] +impl_binary_long!( + u64_div_rem, + zero_div_fn, + u64_normalization_shift, + 64, + u64, + i64 +); + +/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. +/// +/// # Safety +/// +/// If the quotient does not fit in a `u32`, a floating point exception occurs. +/// If `div == 0`, then a division by zero exception occurs. +#[cfg(all(not(feature = "no-asm"), target_arch = "x86"))] +#[inline] +unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { + let duo_lo = duo as u32; + let duo_hi = (duo >> 32) as u32; + let quo: u32; + let rem: u32; + unsafe { + // divides the combined registers rdx:rax (`duo` is split into two 32 bit parts to do this) + // by `div`. The quotient is stored in rax and the remainder in rdx. + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. + core::arch::asm!( + "div {0}", + in(reg) div, + inlateout("rax") duo_lo => quo, + inlateout("rdx") duo_hi => rem, + options(att_syntax, pure, nomem, nostack) + ); + } + (quo, rem) +} + +// use `asymmetric` instead of `delegate` on x86 +#[cfg(all(not(feature = "no-asm"), target_arch = "x86"))] +impl_asymmetric!( + u64_div_rem, + zero_div_fn, + u32_by_u32_div_rem, + u64_by_u32_div_rem, + 16, + u16, + u32, + u64 +); + +// 32 bits is the smallest division used by `compiler-builtins`, so we end with binary long division +impl_binary_long!( + u32_div_rem, + zero_div_fn, + u32_normalization_shift, + 32, + u32, + i32, + allow(dead_code) +); diff --git a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs new file mode 100644 index 00000000000..61b67b6bc3d --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs @@ -0,0 +1,106 @@ +/// Creates a function used by some division algorithms to compute the "normalization shift". +#[allow(unused_macros)] +macro_rules! impl_normalization_shift { + ( + $name:ident, // name of the normalization shift function + // boolean for if `$uX::leading_zeros` should be used (if an architecture does not have a + // hardware instruction for `usize::leading_zeros`, then this should be `true`) + $use_lz:ident, + $n:tt, // the number of bits in a $iX or $uX + $uX:ident, // unsigned integer type for the inputs of `$name` + $iX:ident, // signed integer type for the inputs of `$name` + $($unsigned_attr:meta),* // attributes for the function + ) => { + /// Finds the shift left that the divisor `div` would need to be normalized for a binary + /// long division step with the dividend `duo`. NOTE: This function assumes that these edge + /// cases have been handled before reaching it: + /// ` + /// if div == 0 { + /// panic!("attempt to divide by zero") + /// } + /// if duo < div { + /// return (0, duo) + /// } + /// ` + /// + /// Normalization is defined as (where `shl` is the output of this function): + /// ` + /// if duo.leading_zeros() != (div << shl).leading_zeros() { + /// // If the most significant bits of `duo` and `div << shl` are not in the same place, + /// // then `div << shl` has one more leading zero than `duo`. + /// assert_eq!(duo.leading_zeros() + 1, (div << shl).leading_zeros()); + /// // Also, `2*(div << shl)` is not more than `duo` (otherwise the first division step + /// // would not be able to clear the msb of `duo`) + /// assert!(duo < (div << (shl + 1))); + /// } + /// if full_normalization { + /// // Some algorithms do not need "full" normalization, which means that `duo` is + /// // larger than `div << shl` when the most significant bits are aligned. + /// assert!((div << shl) <= duo); + /// } + /// ` + /// + /// Note: If the software bisection algorithm is being used in this function, it happens + /// that full normalization always occurs, so be careful that new algorithms are not + /// invisibly depending on this invariant when `full_normalization` is set to `false`. + $( + #[$unsigned_attr] + )* + fn $name(duo: $uX, div: $uX, full_normalization: bool) -> usize { + // We have to find the leading zeros of `div` to know where its msb (most significant + // set bit) is to even begin binary long division. It is also good to know where the msb + // of `duo` is so that useful work can be started instead of shifting `div` for all + // possible quotients (many division steps are wasted if `duo.leading_zeros()` is large + // and `div` starts out being shifted all the way to the msb). Aligning the msbs of + // `div` and `duo` could be done by shifting `div` left by + // `div.leading_zeros() - duo.leading_zeros()`, but some CPUs without division hardware + // also do not have single instructions for calculating `leading_zeros`. Instead of + // software doing two bisections to find the two `leading_zeros`, we do one bisection to + // find `div.leading_zeros() - duo.leading_zeros()` without actually knowing either of + // the leading zeros values. + + let mut shl: usize; + if $use_lz { + shl = (div.leading_zeros() - duo.leading_zeros()) as usize; + if full_normalization { + if duo < (div << shl) { + // when the msb of `duo` and `div` are aligned, the resulting `div` may be + // larger than `duo`, so we decrease the shift by 1. + shl -= 1; + } + } + } else { + let mut test = duo; + shl = 0usize; + let mut lvl = $n >> 1; + loop { + let tmp = test >> lvl; + // It happens that a final `duo < (div << shl)` check is not needed, because the + // `div <= tmp` check insures that the msb of `test` never passes the msb of + // `div`, and any set bits shifted off the end of `test` would still keep + // `div <= tmp` true. + if div <= tmp { + test = tmp; + shl += lvl; + } + // narrow down bisection + lvl >>= 1; + if lvl == 0 { + break + } + } + } + // tests the invariants that should hold before beginning binary long division + /* + if full_normalization { + assert!((div << shl) <= duo); + } + if duo.leading_zeros() != (div << shl).leading_zeros() { + assert_eq!(duo.leading_zeros() + 1, (div << shl).leading_zeros()); + assert!(duo < (div << (shl + 1))); + } + */ + shl + } + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/trifecta.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/trifecta.rs new file mode 100644 index 00000000000..7e104053b8b --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/trifecta.rs @@ -0,0 +1,386 @@ +/// Creates an unsigned division function optimized for division of integers with bitwidths +/// larger than the largest hardware integer division supported. These functions use large radix +/// division algorithms that require both fast division and very fast widening multiplication on the +/// target microarchitecture. Otherwise, `impl_delegate` should be used instead. +#[allow(unused_macros)] +macro_rules! impl_trifecta { + ( + $fn:ident, // name of the unsigned division function + $zero_div_fn:ident, // function called when division by zero is attempted + $half_division:ident, // function for division of a $uX by a $uX + $n_h:expr, // the number of bits in $iH or $uH + $uH:ident, // unsigned integer with half the bit width of $uX + $uX:ident, // unsigned integer with half the bit width of $uD + $uD:ident // unsigned integer type for the inputs and outputs of `$unsigned_name` + ) => { + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + pub fn $fn(duo: $uD, div: $uD) -> ($uD, $uD) { + // This is called the trifecta algorithm because it uses three main algorithms: short + // division for small divisors, the two possibility algorithm for large divisors, and an + // undersubtracting long division algorithm for intermediate cases. + + // This replicates `carrying_mul` (rust-lang rfc #2417). LLVM correctly optimizes this + // to use a widening multiply to 128 bits on the relevant architectures. + fn carrying_mul(lhs: $uX, rhs: $uX) -> ($uX, $uX) { + let tmp = (lhs as $uD).wrapping_mul(rhs as $uD); + (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) + } + fn carrying_mul_add(lhs: $uX, mul: $uX, add: $uX) -> ($uX, $uX) { + let tmp = (lhs as $uD) + .wrapping_mul(mul as $uD) + .wrapping_add(add as $uD); + (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) + } + + // the number of bits in a $uX + let n = $n_h * 2; + + if div == 0 { + $zero_div_fn() + } + + // Trying to use a normalization shift function will cause inelegancies in the code and + // inefficiencies for architectures with a native count leading zeros instruction. The + // undersubtracting algorithm needs both values (keeping the original `div_lz` but + // updating `duo_lz` multiple times), so we assume hardware support for fast + // `leading_zeros` calculation. + let div_lz = div.leading_zeros(); + let mut duo_lz = duo.leading_zeros(); + + // the possible ranges of `duo` and `div` at this point: + // `0 <= duo < 2^n_d` + // `1 <= div < 2^n_d` + + // quotient is 0 or 1 branch + if div_lz <= duo_lz { + // The quotient cannot be more than 1. The highest set bit of `duo` needs to be at + // least one place higher than `div` for the quotient to be more than 1. + if duo >= div { + return (1, duo - div); + } else { + return (0, duo); + } + } + + // `_sb` is the number of significant bits (from the ones place to the highest set bit) + // `{2, 2^div_sb} <= duo < 2^n_d` + // `1 <= div < {2^duo_sb, 2^(n_d - 1)}` + // smaller division branch + if duo_lz >= n { + // `duo < 2^n` so it will fit in a $uX. `div` will also fit in a $uX (because of the + // `div_lz <= duo_lz` branch) so no numerical error. + let (quo, rem) = $half_division(duo as $uX, div as $uX); + return (quo as $uD, rem as $uD); + } + + // `{2^n, 2^div_sb} <= duo < 2^n_d` + // `1 <= div < {2^duo_sb, 2^(n_d - 1)}` + // short division branch + if div_lz >= (n + $n_h) { + // `1 <= div < {2^duo_sb, 2^n_h}` + + // It is barely possible to improve the performance of this by calculating the + // reciprocal and removing one `$half_division`, but only if the CPU can do fast + // multiplications in parallel. Other reciprocal based methods can remove two + // `$half_division`s, but have multiplications that cannot be done in parallel and + // reduce performance. I have decided to use this trivial short division method and + // rely on the CPU having quick divisions. + + let duo_hi = (duo >> n) as $uX; + let div_0 = div as $uH as $uX; + let (quo_hi, rem_3) = $half_division(duo_hi, div_0); + + let duo_mid = ((duo >> $n_h) as $uH as $uX) | (rem_3 << $n_h); + let (quo_1, rem_2) = $half_division(duo_mid, div_0); + + let duo_lo = (duo as $uH as $uX) | (rem_2 << $n_h); + let (quo_0, rem_1) = $half_division(duo_lo, div_0); + + return ( + (quo_0 as $uD) | ((quo_1 as $uD) << $n_h) | ((quo_hi as $uD) << n), + rem_1 as $uD, + ); + } + + // relative leading significant bits, cannot overflow because of above branches + let lz_diff = div_lz - duo_lz; + + // `{2^n, 2^div_sb} <= duo < 2^n_d` + // `2^n_h <= div < {2^duo_sb, 2^(n_d - 1)}` + // `mul` or `mul - 1` branch + if lz_diff < $n_h { + // Two possibility division algorithm + + // The most significant bits of `duo` and `div` are within `$n_h` bits of each + // other. If we take the `n` most significant bits of `duo` and divide them by the + // corresponding bits in `div`, it produces a quotient value `quo`. It happens that + // `quo` or `quo - 1` will always be the correct quotient for the whole number. In + // other words, the bits less significant than the `n` most significant bits of + // `duo` and `div` can only influence the quotient to be one of two values. + // Because there are only two possibilities, there only needs to be one `$uH` sized + // division, a `$uH` by `$uD` multiplication, and only one branch with a few simple + // operations. + // + // Proof that the true quotient can only be `quo` or `quo - 1`. + // All `/` operators here are floored divisions. + // + // `shift` is the number of bits not in the higher `n` significant bits of `duo`. + // (definitions) + // 0. shift = n - duo_lz + // 1. duo_sig_n == duo / 2^shift + // 2. div_sig_n == div / 2^shift + // 3. quo == duo_sig_n / div_sig_n + // + // + // We are trying to find the true quotient, `true_quo`. + // 4. true_quo = duo / div. (definition) + // + // This is true because of the bits that are cut off during the bit shift. + // 5. duo_sig_n * 2^shift <= duo < (duo_sig_n + 1) * 2^shift. + // 6. div_sig_n * 2^shift <= div < (div_sig_n + 1) * 2^shift. + // + // Dividing each bound of (5) by each bound of (6) gives 4 possibilities for what + // `true_quo == duo / div` is bounded by: + // (duo_sig_n * 2^shift) / (div_sig_n * 2^shift) + // (duo_sig_n * 2^shift) / ((div_sig_n + 1) * 2^shift) + // ((duo_sig_n + 1) * 2^shift) / (div_sig_n * 2^shift) + // ((duo_sig_n + 1) * 2^shift) / ((div_sig_n + 1) * 2^shift) + // + // Simplifying each of these four: + // duo_sig_n / div_sig_n + // duo_sig_n / (div_sig_n + 1) + // (duo_sig_n + 1) / div_sig_n + // (duo_sig_n + 1) / (div_sig_n + 1) + // + // Taking the smallest and the largest of these as the low and high bounds + // and replacing `duo / div` with `true_quo`: + // 7. duo_sig_n / (div_sig_n + 1) <= true_quo < (duo_sig_n + 1) / div_sig_n + // + // The `lz_diff < n_h` conditional on this branch makes sure that `div_sig_n` is at + // least `2^n_h`, and the `div_lz <= duo_lz` branch makes sure that the highest bit + // of `div_sig_n` is not the `2^(n - 1)` bit. + // 8. `2^(n - 1) <= duo_sig_n < 2^n` + // 9. `2^n_h <= div_sig_n < 2^(n - 1)` + // + // We want to prove that either + // `(duo_sig_n + 1) / div_sig_n == duo_sig_n / (div_sig_n + 1)` or that + // `(duo_sig_n + 1) / div_sig_n == duo_sig_n / (div_sig_n + 1) + 1`. + // + // We also want to prove that `quo` is one of these: + // `duo_sig_n / div_sig_n == duo_sig_n / (div_sig_n + 1)` or + // `duo_sig_n / div_sig_n == (duo_sig_n + 1) / div_sig_n`. + // + // When 1 is added to the numerator of `duo_sig_n / div_sig_n` to produce + // `(duo_sig_n + 1) / div_sig_n`, it is not possible that the value increases by + // more than 1 with floored integer arithmetic and `div_sig_n != 0`. Consider + // `x/y + 1 < (x + 1)/y` <=> `x/y + 1 < x/y + 1/y` <=> `1 < 1/y` <=> `y < 1`. + // `div_sig_n` is a nonzero integer. Thus, + // 10. `duo_sig_n / div_sig_n == (duo_sig_n + 1) / div_sig_n` or + // `(duo_sig_n / div_sig_n) + 1 == (duo_sig_n + 1) / div_sig_n. + // + // When 1 is added to the denominator of `duo_sig_n / div_sig_n` to produce + // `duo_sig_n / (div_sig_n + 1)`, it is not possible that the value decreases by + // more than 1 with the bounds (8) and (9). Consider `x/y - 1 <= x/(y + 1)` <=> + // `(x - y)/y < x/(y + 1)` <=> `(y + 1)*(x - y) < x*y` <=> `x*y - y*y + x - y < x*y` + // <=> `x < y*y + y`. The smallest value of `div_sig_n` is `2^n_h` and the largest + // value of `duo_sig_n` is `2^n - 1`. Substituting reveals `2^n - 1 < 2^n + 2^n_h`. + // Thus, + // 11. `duo_sig_n / div_sig_n == duo_sig_n / (div_sig_n + 1)` or + // `(duo_sig_n / div_sig_n) - 1` == duo_sig_n / (div_sig_n + 1)` + // + // Combining both (10) and (11), we know that + // `quo - 1 <= duo_sig_n / (div_sig_n + 1) <= true_quo + // < (duo_sig_n + 1) / div_sig_n <= quo + 1` and therefore: + // 12. quo - 1 <= true_quo < quo + 1 + // + // In a lot of division algorithms using smaller divisions to construct a larger + // division, we often encounter a situation where the approximate `quo` value + // calculated from a smaller division is multiple increments away from the true + // `quo` value. In those algorithms, multiple correction steps have to be applied. + // Those correction steps may need more multiplications to test `duo - (quo*div)` + // again. Because of the fact that our `quo` can only be one of two values, we can + // see if `duo - (quo*div)` overflows. If it did overflow, then we know that we have + // the larger of the two values (since the true quotient is unique, and any larger + // quotient will cause `duo - (quo*div)` to be negative). Also because there is only + // one correction needed, we can calculate the remainder `duo - (true_quo*div) == + // duo - ((quo - 1)*div) == duo - (quo*div - div) == duo + div - quo*div`. + // If `duo - (quo*div)` did not overflow, then we have the correct answer. + let shift = n - duo_lz; + let duo_sig_n = (duo >> shift) as $uX; + let div_sig_n = (div >> shift) as $uX; + let quo = $half_division(duo_sig_n, div_sig_n).0; + + // The larger `quo` value can overflow `$uD` in the right circumstances. This is a + // manual `carrying_mul_add` with overflow checking. + let div_lo = div as $uX; + let div_hi = (div >> n) as $uX; + let (tmp_lo, carry) = carrying_mul(quo, div_lo); + let (tmp_hi, overflow) = carrying_mul_add(quo, div_hi, carry); + let tmp = (tmp_lo as $uD) | ((tmp_hi as $uD) << n); + if (overflow != 0) || (duo < tmp) { + return ( + (quo - 1) as $uD, + // Both the addition and subtraction can overflow, but when combined end up + // as a correct positive number. + duo.wrapping_add(div).wrapping_sub(tmp), + ); + } else { + return (quo as $uD, duo - tmp); + } + } + + // Undersubtracting long division algorithm. + // Instead of clearing a minimum of 1 bit from `duo` per iteration via binary long + // division, `n_h - 1` bits are cleared per iteration with this algorithm. It is a more + // complicated version of regular long division. Most integer division algorithms tend + // to guess a part of the quotient, and may have a larger quotient than the true + // quotient (which when multiplied by `div` will "oversubtract" the original dividend). + // They then check if the quotient was in fact too large and then have to correct it. + // This long division algorithm has been carefully constructed to always underguess the + // quotient by slim margins. This allows different subalgorithms to be blindly jumped to + // without needing an extra correction step. + // + // The only problem is that this subalgorithm will not work for many ranges of `duo` and + // `div`. Fortunately, the short division, two possibility algorithm, and other simple + // cases happen to exactly fill these gaps. + // + // For an example, consider the division of 76543210 by 213 and assume that `n_h` is + // equal to two decimal digits (note: we are working with base 10 here for readability). + // The first `sig_n_h` part of the divisor (21) is taken and is incremented by 1 to + // prevent oversubtraction. We also record the number of extra places not a part of + // the `sig_n` or `sig_n_h` parts. + // + // sig_n_h == 2 digits, sig_n == 4 digits + // + // vvvv <- `duo_sig_n` + // 76543210 + // ^^^^ <- extra places in duo, `duo_extra == 4` + // + // vv <- `div_sig_n_h` + // 213 + // ^ <- extra places in div, `div_extra == 1` + // + // The difference in extra places, `duo_extra - div_extra == extra_shl == 3`, is used + // for shifting partial sums in the long division. + // + // In the first step, the first `sig_n` part of duo (7654) is divided by + // `div_sig_n_h_add_1` (22), which results in a partial quotient of 347. This is + // multiplied by the whole divisor to make 73911, which is shifted left by `extra_shl` + // and subtracted from duo. The partial quotient is also shifted left by `extra_shl` to + // be added to `quo`. + // + // 347 + // ________ + // |76543210 + // -73911 + // 2632210 + // + // Variables dependent on duo have to be updated: + // + // vvvv <- `duo_sig_n == 2632` + // 2632210 + // ^^^ <- `duo_extra == 3` + // + // `extra_shl == 2` + // + // Two more steps are taken after this and then duo fits into `n` bits, and then a final + // normal long division step is made. The partial quotients are all progressively added + // to each other in the actual algorithm, but here I have left them all in a tower that + // can be added together to produce the quotient, 359357. + // + // 14 + // 443 + // 119 + // 347 + // ________ + // |76543210 + // -73911 + // 2632210 + // -25347 + // 97510 + // -94359 + // 3151 + // -2982 + // 169 <- the remainder + + let mut duo = duo; + let mut quo: $uD = 0; + + // The number of lesser significant bits not a part of `div_sig_n_h` + let div_extra = (n + $n_h) - div_lz; + + // The most significant `n_h` bits of div + let div_sig_n_h = (div >> div_extra) as $uH; + + // This needs to be a `$uX` in case of overflow from the increment + let div_sig_n_h_add1 = (div_sig_n_h as $uX) + 1; + + // `{2^n, 2^(div_sb + n_h)} <= duo < 2^n_d` + // `2^n_h <= div < {2^(duo_sb - n_h), 2^n}` + loop { + // The number of lesser significant bits not a part of `duo_sig_n` + let duo_extra = n - duo_lz; + + // The most significant `n` bits of `duo` + let duo_sig_n = (duo >> duo_extra) as $uX; + + // the two possibility algorithm requires that the difference between msbs is less + // than `n_h`, so the comparison is `<=` here. + if div_extra <= duo_extra { + // Undersubtracting long division step + let quo_part = $half_division(duo_sig_n, div_sig_n_h_add1).0 as $uD; + let extra_shl = duo_extra - div_extra; + + // Addition to the quotient. + quo += (quo_part << extra_shl); + + // Subtraction from `duo`. At least `n_h - 1` bits are cleared from `duo` here. + duo -= (div.wrapping_mul(quo_part) << extra_shl); + } else { + // Two possibility algorithm + let shift = n - duo_lz; + let duo_sig_n = (duo >> shift) as $uX; + let div_sig_n = (div >> shift) as $uX; + let quo_part = $half_division(duo_sig_n, div_sig_n).0; + let div_lo = div as $uX; + let div_hi = (div >> n) as $uX; + + let (tmp_lo, carry) = carrying_mul(quo_part, div_lo); + // The undersubtracting long division algorithm has already run once, so + // overflow beyond `$uD` bits is not possible here + let (tmp_hi, _) = carrying_mul_add(quo_part, div_hi, carry); + let tmp = (tmp_lo as $uD) | ((tmp_hi as $uD) << n); + + if duo < tmp { + return ( + quo + ((quo_part - 1) as $uD), + duo.wrapping_add(div).wrapping_sub(tmp), + ); + } else { + return (quo + (quo_part as $uD), duo - tmp); + } + } + + duo_lz = duo.leading_zeros(); + + if div_lz <= duo_lz { + // quotient can have 0 or 1 added to it + if div <= duo { + return (quo + 1, duo - div); + } else { + return (quo, duo); + } + } + + // This can only happen if `div_sd < n` (because of previous "quo = 0 or 1" + // branches), but it is not worth it to unroll further. + if n <= duo_lz { + // simple division and addition + let tmp = $half_division(duo as $uX, div as $uX); + return (quo + (tmp.0 as $uD), tmp.1 as $uD); + } + } + } + }; +} diff --git a/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs new file mode 100644 index 00000000000..dbc0cce9fac --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs @@ -0,0 +1,69 @@ +#[cfg(feature = "public-test-deps")] +pub use implementation::trailing_zeros; +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use implementation::trailing_zeros; + +mod implementation { + use crate::int::{CastInto, Int}; + + /// Returns number of trailing binary zeros in `x`. + #[allow(dead_code)] + pub fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + let mut x = x; + let mut r: u32 = 0; + let mut t: u32; + + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + x >>= r; // remove 32 zero bits + } + + if T::BITS >= 32 { + t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 + r += t; + x >>= t; // x = [0 - 0xFFFF] + higher garbage bits + } + + const { assert!(T::BITS >= 16) }; + t = ((CastInto::::cast(x) == 0) as u32) << 3; + x >>= t; // x = [0 - 0xFF] + higher garbage bits + r += t; + + let mut x: u8 = x.cast(); + + t = (((x & 0x0F) == 0) as u32) << 2; + x >>= t; // x = [0 - 0xF] + higher garbage bits + r += t; + + t = (((x & 0x3) == 0) as u32) << 1; + x >>= t; // x = [0 - 0x3] + higher garbage bits + r += t; + + x &= 3; + + r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) + } +} + +intrinsics! { + /// Returns the number of trailing binary zeros in `x` (32 bit version). + pub extern "C" fn __ctzsi2(x: u32) -> usize { + trailing_zeros(x) + } + + /// Returns the number of trailing binary zeros in `x` (64 bit version). + pub extern "C" fn __ctzdi2(x: u64) -> usize { + trailing_zeros(x) + } + + /// Returns the number of trailing binary zeros in `x` (128 bit version). + pub extern "C" fn __ctzti2(x: u128) -> usize { + let lo = x as u64; + if lo == 0 { + 64 + __ctzdi2((x >> 64) as u64) + } else { + __ctzdi2(lo) + } + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/compiler-builtins/src/int/traits.rs new file mode 100644 index 00000000000..9b079e2aa59 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/traits.rs @@ -0,0 +1,411 @@ +use core::ops; + +/// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] +pub trait MinInt: + Copy + + core::fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type UnsignedInt: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} + +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub trait Int: + MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, + /// 112,119,120,125,126,127]. + const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); + + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; + + fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + fn unsigned_abs(self) -> Self::UnsignedInt; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} + +pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn unsigned(self) -> $uty { + self + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn unsigned_abs(self) -> Self { + self + } + + fn abs_diff(self, other: Self) -> Self { + self.abs_diff(other) + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn unsigned(self) -> $uty { + self as $uty + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn unsigned_abs(self) -> Self::UnsignedInt { + self.unsigned_abs() + } + + fn abs_diff(self, other: Self) -> $uty { + self.abs_diff(other) + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +/// Trait for integers twice the bit width of another integer. This is implemented for all +/// primitives except for `u8`, because there is not a smaller primitive. +pub trait DInt: MinInt { + /// Integer that is half the bit width of the integer this trait is implemented for + type H: HInt; + + /// Returns the low half of `self` + fn lo(self) -> Self::H; + /// Returns the high half of `self` + fn hi(self) -> Self::H; + /// Returns the low and high halves of `self` as a tuple + fn lo_hi(self) -> (Self::H, Self::H) { + (self.lo(), self.hi()) + } + /// Constructs an integer using lower and higher half parts + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { + lo.zero_widen() | hi.widen_hi() + } +} + +/// Trait for integers half the bit width of another integer. This is implemented for all +/// primitives except for `u128`, because it there is not a larger primitive. +pub trait HInt: Int { + /// Integer that is double the bit width of the integer this trait is implemented for + type D: DInt + MinInt; + + // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for + // unknown reasons this can cause infinite recursion when optimizations are disabled. See + // for context. + + /// Widens (using default extension) the integer to have double bit width + fn widen(self) -> Self::D; + /// Widens (zero extension only) the integer to have double bit width. This is needed to get + /// around problems with associated type bounds (such as `Int`) being unstable + fn zero_widen(self) -> Self::D; + /// Widens the integer to have double bit width and shifts the integer into the higher bits + fn widen_hi(self) -> Self::D; + /// Widening multiplication with zero widening. This cannot overflow. + fn zero_widen_mul(self, rhs: Self) -> Self::D; + /// Widening multiplication. This cannot overflow. + fn widen_mul(self, rhs: Self) -> Self::D; +} + +macro_rules! impl_d_int { + ($($X:ident $D:ident),*) => { + $( + impl DInt for $D { + type H = $X; + + fn lo(self) -> Self::H { + self as $X + } + fn hi(self) -> Self::H { + (self >> <$X as MinInt>::BITS) as $X + } + } + )* + }; +} + +macro_rules! impl_h_int { + ($($H:ident $uH:ident $X:ident),*) => { + $( + impl HInt for $H { + type D = $X; + + fn widen(self) -> Self::D { + self as $X + } + fn zero_widen(self) -> Self::D { + (self as $uH) as $X + } + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen().wrapping_mul(rhs.zero_widen()) + } + fn widen_mul(self, rhs: Self) -> Self::D { + self.widen().wrapping_mul(rhs.widen()) + } + fn widen_hi(self) -> Self::D { + (self as $X) << ::BITS + } + } + )* + }; +} + +impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); +impl_h_int!( + u8 u8 u16, + u16 u16 u32, + u32 u32 u64, + u64 u64 u128, + i8 u8 i16, + i16 u16 i32, + i32 u32 i64, + i64 u64 i128 +); + +/// Trait to express (possibly lossy) casting of integers +pub trait CastInto: Copy { + fn cast(self) -> T; +} + +pub trait CastFrom: Copy { + fn cast_from(value: T) -> Self; +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} + +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); diff --git a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs new file mode 100644 index 00000000000..1fa761212b2 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs @@ -0,0 +1,103 @@ +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use crate::int::specialized_div_rem::*; + +#[cfg(feature = "public-test-deps")] +pub use crate::int::specialized_div_rem::*; + +intrinsics! { + #[maybe_use_optimized_c_shim] + #[arm_aeabi_alias = __aeabi_uidiv] + /// Returns `n / d` + pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { + u32_div_rem(n, d).0 + } + + #[maybe_use_optimized_c_shim] + /// Returns `n % d` + pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { + u32_div_rem(n, d).1 + } + + #[avr_skip] + #[maybe_use_optimized_c_shim] + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { + let quo_rem = u32_div_rem(n, d); + if let Some(rem) = rem { + *rem = quo_rem.1; + } + quo_rem.0 + } + + #[avr_skip] + #[maybe_use_optimized_c_shim] + /// Returns `n / d` + pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { + u64_div_rem(n, d).0 + } + + #[avr_skip] + #[maybe_use_optimized_c_shim] + /// Returns `n % d` + pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { + u64_div_rem(n, d).1 + } + + #[avr_skip] + #[maybe_use_optimized_c_shim] + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { + let quo_rem = u64_div_rem(n, d); + if let Some(rem) = rem { + *rem = quo_rem.1; + } + quo_rem.0 + } + + // Note: we use block configuration and not `if cfg!(...)`, because we need to entirely disable + // the existence of `u128_div_rem` to get 32-bit SPARC to compile, see `u128_divide_sparc` docs. + + #[avr_skip] + /// Returns `n / d` + pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { + #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { + u128_div_rem(n, d).0 + } + #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] { + u128_divide_sparc(n, d, &mut 0) + } + } + + #[avr_skip] + /// Returns `n % d` + pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { + #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { + u128_div_rem(n, d).1 + } + #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] { + let mut rem = 0; + u128_divide_sparc(n, d, &mut rem); + rem + } + } + + #[avr_skip] + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { + #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { + let quo_rem = u128_div_rem(n, d); + if let Some(rem) = rem { + *rem = quo_rem.1; + } + quo_rem.0 + } + #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] { + let mut tmp = 0; + let quo = u128_divide_sparc(n, d, &mut tmp); + if let Some(rem) = rem { + *rem = tmp; + } + quo + } + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/lib.miri.rs b/library/compiler-builtins/compiler-builtins/src/lib.miri.rs new file mode 100644 index 00000000000..17288058e5e --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/lib.miri.rs @@ -0,0 +1,5 @@ +//! Grep bootstrap for `MIRI_REPLACE_LIBRS_IF_NOT_TEST` to learn what this is about. +#![no_std] +#![feature(rustc_private)] +extern crate compiler_builtins as real; +pub use real::*; diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs new file mode 100644 index 00000000000..16de96b4da0 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -0,0 +1,78 @@ +#![cfg_attr(feature = "compiler-builtins", compiler_builtins)] +#![cfg_attr(all(target_family = "wasm"), feature(wasm_numeric_instr))] +#![feature(abi_unadjusted)] +#![feature(asm_experimental_arch)] +#![feature(cfg_target_has_atomic)] +#![feature(compiler_builtins)] +#![feature(core_intrinsics)] +#![feature(linkage)] +#![feature(naked_functions)] +#![feature(repr_simd)] +#![cfg_attr(f16_enabled, feature(f16))] +#![cfg_attr(f128_enabled, feature(f128))] +#![no_builtins] +#![no_std] +#![allow(unused_features)] +#![allow(internal_features)] +// We use `u128` in a whole bunch of places which we currently agree with the +// compiler on ABIs and such, so we should be "good enough" for now and changes +// to the `u128` ABI will be reflected here. +#![allow(improper_ctypes, improper_ctypes_definitions)] +// `mem::swap` cannot be used because it may generate references to memcpy in unoptimized code. +#![allow(clippy::manual_swap)] +// Support compiling on both stage0 and stage1 which may differ in supported stable features. +#![allow(stable_features)] + +// We disable #[no_mangle] for tests so that we can verify the test results +// against the native compiler-rt implementations of the builtins. + +// NOTE cfg(all(feature = "c", ..)) indicate that compiler-rt provides an arch optimized +// implementation of that intrinsic and we'll prefer to use that + +// NOTE(aapcs, aeabi, arm) ARM targets use intrinsics named __aeabi_* instead of the intrinsics +// that follow "x86 naming convention" (e.g. addsf3). Those aeabi intrinsics must adhere to the +// AAPCS calling convention (`extern "aapcs"`) because that's how LLVM will call them. + +#[cfg(test)] +extern crate core; + +#[macro_use] +mod macros; + +pub mod float; +pub mod int; +pub mod math; +pub mod mem; + +// `libm` expects its `support` module to be available in the crate root. +use math::libm::support; + +#[cfg(target_arch = "arm")] +pub mod arm; + +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] +pub mod aarch64; + +#[cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm"),))] +pub mod aarch64_linux; + +#[cfg(all( + kernel_user_helpers, + any(target_os = "linux", target_os = "android"), + target_arch = "arm" +))] +pub mod arm_linux; + +#[cfg(target_arch = "hexagon")] +pub mod hexagon; + +#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] +pub mod riscv; + +#[cfg(target_arch = "x86")] +pub mod x86; + +#[cfg(target_arch = "x86_64")] +pub mod x86_64; + +pub mod probestack; diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs new file mode 100644 index 00000000000..b1b71379cc9 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -0,0 +1,514 @@ +//! Macros shared throughout the compiler-builtins implementation + +/// The "main macro" used for defining intrinsics. +/// +/// The compiler-builtins library is super platform-specific with tons of crazy +/// little tweaks for various platforms. As a result it *could* involve a lot of +/// #[cfg] and macro soup, but the intention is that this macro alleviates a lot +/// of that complexity. Ideally this macro has all the weird ABI things +/// platforms need and elsewhere in this library it just looks like normal Rust +/// code. +/// +/// All intrinsics functions are marked with #[linkage = "weak"] when +/// `not(windows) and not(target_vendor = "apple")`. +/// `weak` linkage attribute is used so that these functions can be replaced +/// by another implementation at link time. This is particularly useful for mixed +/// Rust/C++ binaries that want to use the C++ intrinsics, otherwise linking against +/// the Rust stdlib will replace those from the compiler-rt library. +/// +/// This macro is structured to be invoked with a bunch of functions that looks +/// like: +/// ```ignore +/// intrinsics! { +/// pub extern "C" fn foo(a: i32) -> u32 { +/// // ... +/// } +/// +/// #[nonstandard_attribute] +/// pub extern "C" fn bar(a: i32) -> u32 { +/// // ... +/// } +/// } +/// ``` +/// +/// Each function is defined in a manner that looks like a normal Rust function. +/// The macro then accepts a few nonstandard attributes that can decorate +/// various functions. Each of the attributes is documented below with what it +/// can do, and each of them slightly tweaks how further expansion happens. +/// +/// A quick overview of attributes supported right now are: +/// +/// * `maybe_use_optimized_c_shim` - indicates that the Rust implementation is +/// ignored if an optimized C version was compiled. +/// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and +/// the specified ABI everywhere else. +/// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the +/// `"unadjusted"` abi on Win64 and the specified abi elsewhere. +/// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM +/// their otherwise typical names to other prefixed ones. +/// * `ppc_alias` - changes the name of the symbol on PowerPC platforms without +/// changing any other behavior. This is mostly for `f128`, which is `tf` on +/// most platforms but `kf` on PowerPC. +macro_rules! intrinsics { + () => (); + + // Support cfg_attr: + ( + #[cfg_attr($e:meta, $($attr:tt)*)] + $(#[$($attrs:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + $($rest:tt)* + ) => ( + #[cfg($e)] + intrinsics! { + #[$($attr)*] + $(#[$($attrs)*])* + pub extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { + $($body)* + } + } + + #[cfg(not($e))] + intrinsics! { + $(#[$($attrs)*])* + pub extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + // Same as above but for unsafe. + ( + #[cfg_attr($e:meta, $($attr:tt)*)] + $(#[$($attrs:tt)*])* + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + $($rest:tt)* + ) => ( + #[cfg($e)] + intrinsics! { + #[$($attr)*] + $(#[$($attrs)*])* + pub unsafe extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { + $($body)* + } + } + + #[cfg(not($e))] + intrinsics! { + $(#[$($attrs)*])* + pub unsafe extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // Right now there's a bunch of architecture-optimized intrinsics in the + // stock compiler-rt implementation. Not all of these have been ported over + // to Rust yet so when the `c` feature of this crate is enabled we fall back + // to the architecture-specific versions which should be more optimized. The + // purpose of this macro is to easily allow specifying this. + // + // The `#[maybe_use_optimized_c_shim]` attribute indicates that this + // intrinsic may have an optimized C version. In these situations the build + // script, if the C code is enabled and compiled, will emit a cfg directive + // to get passed to rustc for our compilation. If that cfg is set we skip + // the Rust implementation, but if the attribute is not enabled then we + // compile in the Rust implementation. + ( + #[maybe_use_optimized_c_shim] + $(#[$($attr:tt)*])* + pub $(unsafe $(@ $empty:tt)? )? extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg($name = "optimized-c")] + pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + extern $abi { + fn $name($($argname: $ty),*) $(-> $ret)?; + } + unsafe { + $name($($argname),*) + } + } + + #[cfg(not($name = "optimized-c"))] + intrinsics! { + $(#[$($attr)*])* + pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // We recognize the `#[aapcs_on_arm]` attribute here and generate the + // same intrinsic but force it to have the `"aapcs"` calling convention on + // ARM and `"C"` elsewhere. + ( + #[aapcs_on_arm] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(target_arch = "arm")] + intrinsics! { + $(#[$($attr)*])* + pub extern "aapcs" fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + #[cfg(not(target_arch = "arm"))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // Like aapcs above we recognize an attribute for the "unadjusted" abi on + // win64 for some methods. + ( + #[unadjusted_on_win64] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(all(any(windows, target_os = "cygwin", all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64"))] + intrinsics! { + $(#[$($attr)*])* + pub extern "unadjusted" fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + #[cfg(not(all(any(windows, target_os = "cygwin", all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64")))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // `arm_aeabi_alias` would conflict with `f16_apple_{arg,ret}_abi` not handled here. Avoid macro ambiguity by combining in a + // single `#[]`. + ( + #[apple_f16_arg_abi] + #[arm_aeabi_alias = $alias:ident] + $($t:tt)* + ) => { + intrinsics! { + #[apple_f16_arg_abi, arm_aeabi_alias = $alias] + $($t)* + } + }; + ( + #[apple_f16_ret_abi] + #[arm_aeabi_alias = $alias:ident] + $($t:tt)* + ) => { + intrinsics! { + #[apple_f16_ret_abi, arm_aeabi_alias = $alias] + $($t)* + } + }; + + // On x86 (32-bit and 64-bit) Apple platforms, `f16` is passed and returned like a `u16` unless + // the builtin involves `f128`. + ( + // `arm_aeabi_alias` would conflict if not handled here. Avoid macro ambiguity by combining + // in a single `#[]`. + #[apple_f16_arg_abi $(, arm_aeabi_alias = $alias:ident)?] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64")))] + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + + #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] + mod $name { + #[no_mangle] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] + $(#[$($attr)*])* + extern $abi fn $name( $($argname: u16),* ) $(-> $ret)? { + super::$name($(f16::from_bits($argname)),*) + } + } + + #[cfg(not(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"))))] + intrinsics! { + $(#[arm_aeabi_alias = $alias])? + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + ( + #[apple_f16_ret_abi $(, arm_aeabi_alias = $alias:ident)?] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64")))] + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + + #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] + mod $name { + #[no_mangle] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] + $(#[$($attr)*])* + extern $abi fn $name( $($argname: $ty),* ) -> u16 { + super::$name($($argname),*).to_bits() + } + } + + #[cfg(not(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"))))] + intrinsics! { + $(#[arm_aeabi_alias = $alias])? + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // A bunch of intrinsics on ARM are aliased in the standard compiler-rt + // build under `__aeabi_*` aliases, and LLVM will call these instead of the + // original function. The aliasing here is used to generate these symbols in + // the object file. + ( + #[arm_aeabi_alias = $alias:ident] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(target_arch = "arm")] + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + + #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] + mod $name { + #[no_mangle] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] + $(#[$($attr)*])* + extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + super::$name($($argname),*) + } + } + + #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] + mod $alias { + #[no_mangle] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] + $(#[$($attr)*])* + extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { + super::$name($($argname),*) + } + } + + #[cfg(not(target_arch = "arm"))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // PowerPC usually uses `kf` rather than `tf` for `f128`. This is just an easy + // way to add an alias on those targets. + ( + #[ppc_alias = $alias:ident] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $alias( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // C mem* functions are only generated when the "mem" feature is enabled. + ( + #[mem_builtin] + $(#[$($attr:tt)*])* + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + $(#[$($attr)*])* + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + + #[cfg(all(feature = "mem", not(feature = "mangled-names")))] + mod $name { + $(#[$($attr)*])* + #[no_mangle] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] + unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + super::$name($($argname),*) + } + } + + intrinsics!($($rest)*); + ); + + // Naked functions are special: we can't generate wrappers for them since + // they use a custom calling convention. + ( + #[naked] + $(#[$($attr:tt)*])* + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + // `#[naked]` definitions are referenced by other places, so we can't use `cfg` like the others + pub mod $name { + #[naked] + $(#[$($attr)*])* + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // For some intrinsics, AVR uses a custom calling convention¹ that does not + // match our definitions here. Ideally we would just use hand-written naked + // functions, but that's quite a lot of code to port² - so for the time + // being we are just ignoring the problematic functions, letting avr-gcc + // (which is required to compile to AVR anyway) link them from libgcc. + // + // ¹ https://gcc.gnu.org/wiki/avr-gcc (see "Exceptions to the Calling + // Convention") + // ² https://github.com/gcc-mirror/gcc/blob/31048012db98f5ec9c2ba537bfd850374bdd771f/libgcc/config/avr/lib1funcs.S + ( + #[avr_skip] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(not(target_arch = "avr"))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // This is the final catch-all rule. At this point we generate an + // intrinsic with a conditional `#[no_mangle]` directive to avoid + // interfering with duplicate symbols and whatnot during testing. + // + // The implementation is placed in a separate module, to take advantage + // of the fact that rustc partitions functions into code generation + // units based on module they are defined in. As a result we will have + // a separate object file for each intrinsic. For further details see + // corresponding PR in rustc https://github.com/rust-lang/rust/pull/70846 + // + // After the intrinsic is defined we just continue with the rest of the + // input we were given. + ( + $(#[$($attr:tt)*])* + pub $(unsafe $(@ $empty:tt)?)? extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + $(#[$($attr)*])* + pub $(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + + #[cfg(not(feature = "mangled-names"))] + mod $name { + $(#[$($attr)*])* + #[no_mangle] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] + $(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + super::$name($($argname),*) + } + } + + intrinsics!($($rest)*); + ); +} diff --git a/library/compiler-builtins/compiler-builtins/src/math.rs b/library/compiler-builtins/compiler-builtins/src/math.rs new file mode 100644 index 00000000000..ccd9c54216c --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/math.rs @@ -0,0 +1,199 @@ +#[rustfmt::skip] +#[allow(dead_code)] +#[allow(unused_imports)] +#[allow(clippy::all)] +#[path = "../libm/src/math/mod.rs"] +pub(crate) mod libm; + +macro_rules! libm_intrinsics { + ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { + intrinsics! { + $( + pub extern "C" fn $fun($($iid: $ity),+) -> $oty { + $crate::math::libm::$fun($($iid),+) + } + )+ + } + } +} + +/// This set of functions is well tested in `libm` and known to provide similar performance to +/// system `libm`, as well as the same or better accuracy. +pub mod full_availability { + #[cfg(f16_enabled)] + libm_intrinsics! { + fn ceilf16(x: f16) -> f16; + fn copysignf16(x: f16, y: f16) -> f16; + fn fabsf16(x: f16) -> f16; + fn fdimf16(x: f16, y: f16) -> f16; + fn floorf16(x: f16) -> f16; + fn fmaxf16(x: f16, y: f16) -> f16; + fn fmaximumf16(x: f16, y: f16) -> f16; + fn fminf16(x: f16, y: f16) -> f16; + fn fminimumf16(x: f16, y: f16) -> f16; + fn fmodf16(x: f16, y: f16) -> f16; + fn rintf16(x: f16) -> f16; + fn roundevenf16(x: f16) -> f16; + fn roundf16(x: f16) -> f16; + fn sqrtf16(x: f16) -> f16; + fn truncf16(x: f16) -> f16; + } + + /* Weak linkage is unreliable on Windows and Apple, so we don't expose symbols that we know + * the system libc provides in order to avoid conflicts. */ + + #[cfg(all(not(windows), not(target_vendor = "apple")))] + libm_intrinsics! { + /* f32 */ + fn cbrtf(n: f32) -> f32; + fn ceilf(x: f32) -> f32; + fn copysignf(x: f32, y: f32) -> f32; + fn fabsf(x: f32) -> f32; + fn fdimf(a: f32, b: f32) -> f32; + fn floorf(x: f32) -> f32; + fn fmaf(x: f32, y: f32, z: f32) -> f32; + fn fmaxf(x: f32, y: f32) -> f32; + fn fminf(x: f32, y: f32) -> f32; + fn fmodf(x: f32, y: f32) -> f32; + fn rintf(x: f32) -> f32; + fn roundf(x: f32) -> f32; + fn sqrtf(x: f32) -> f32; + fn truncf(x: f32) -> f32; + + /* f64 */ + fn cbrt(x: f64) -> f64; + fn ceil(x: f64) -> f64; + fn copysign(x: f64, y: f64) -> f64; + fn fabs(x: f64) -> f64; + fn fdim(a: f64, b: f64) -> f64; + fn floor(x: f64) -> f64; + fn fma(x: f64, y: f64, z: f64) -> f64; + fn fmax(x: f64, y: f64) -> f64; + fn fmin(x: f64, y: f64) -> f64; + fn fmod(x: f64, y: f64) -> f64; + fn rint(x: f64) -> f64; + fn round(x: f64) -> f64; + fn sqrt(x: f64) -> f64; + fn trunc(x: f64) -> f64; + } + + // Windows and MacOS do not yet expose roundeven and IEEE 754-2019 `maximum` / `minimum`, + // however, so we still provide a fallback. + libm_intrinsics! { + fn fmaximum(x: f64, y: f64) -> f64; + fn fmaximumf(x: f32, y: f32) -> f32; + fn fminimum(x: f64, y: f64) -> f64; + fn fminimumf(x: f32, y: f32) -> f32; + fn roundeven(x: f64) -> f64; + fn roundevenf(x: f32) -> f32; + } + + #[cfg(f128_enabled)] + libm_intrinsics! { + fn ceilf128(x: f128) -> f128; + fn copysignf128(x: f128, y: f128) -> f128; + fn fabsf128(x: f128) -> f128; + fn fdimf128(x: f128, y: f128) -> f128; + fn floorf128(x: f128) -> f128; + fn fmaf128(x: f128, y: f128, z: f128) -> f128; + fn fmaxf128(x: f128, y: f128) -> f128; + fn fmaximumf128(x: f128, y: f128) -> f128; + fn fminf128(x: f128, y: f128) -> f128; + fn fminimumf128(x: f128, y: f128) -> f128; + fn fmodf128(x: f128, y: f128) -> f128; + fn rintf128(x: f128) -> f128; + fn roundevenf128(x: f128) -> f128; + fn roundf128(x: f128) -> f128; + fn sqrtf128(x: f128) -> f128; + fn truncf128(x: f128) -> f128; + } +} + +/// This group of functions has more performance or precision issues than system versions, or +/// are otherwise less well tested. Provide them only on platforms that have problems with the +/// system `libm`. +/// +/// As `libm` improves, more functions will be moved from this group to the first group. +/// +/// Do not supply for any of the following: +/// - x86 without sse2 due to ABI issues +/// - +/// - but exclude UEFI since it is a soft-float target +/// - +/// - All unix targets (linux, macos, freebsd, android, etc) +/// - wasm with known target_os +#[cfg(not(any( + all( + target_arch = "x86", + not(target_feature = "sse2"), + not(target_os = "uefi"), + ), + unix, + all(target_family = "wasm", not(target_os = "unknown")) +)))] +pub mod partial_availability { + #[cfg(not(windows))] + libm_intrinsics! { + fn acos(x: f64) -> f64; + fn acosf(n: f32) -> f32; + fn asin(x: f64) -> f64; + fn asinf(n: f32) -> f32; + fn atan(x: f64) -> f64; + fn atan2(x: f64, y: f64) -> f64; + fn atan2f(a: f32, b: f32) -> f32; + fn atanf(n: f32) -> f32; + fn cos(x: f64) -> f64; + fn cosf(x: f32) -> f32; + fn cosh(x: f64) -> f64; + fn coshf(n: f32) -> f32; + fn erf(x: f64) -> f64; + fn erfc(x: f64) -> f64; + fn erfcf(x: f32) -> f32; + fn erff(x: f32) -> f32; + fn exp(x: f64) -> f64; + fn exp2(x: f64) -> f64; + fn exp2f(x: f32) -> f32; + fn expf(x: f32) -> f32; + fn expm1(x: f64) -> f64; + fn expm1f(n: f32) -> f32; + fn hypot(x: f64, y: f64) -> f64; + fn hypotf(x: f32, y: f32) -> f32; + fn ldexp(f: f64, n: i32) -> f64; + fn ldexpf(f: f32, n: i32) -> f32; + fn log(x: f64) -> f64; + fn log10(x: f64) -> f64; + fn log10f(x: f32) -> f32; + fn log1p(x: f64) -> f64; + fn log1pf(n: f32) -> f32; + fn log2(x: f64) -> f64; + fn log2f(x: f32) -> f32; + fn logf(x: f32) -> f32; + fn pow(x: f64, y: f64) -> f64; + fn powf(x: f32, y: f32) -> f32; + fn sin(x: f64) -> f64; + fn sinf(x: f32) -> f32; + fn sinh(x: f64) -> f64; + fn sinhf(n: f32) -> f32; + fn tan(x: f64) -> f64; + fn tanf(n: f32) -> f32; + fn tanh(x: f64) -> f64; + fn tanhf(n: f32) -> f32; + fn tgamma(x: f64) -> f64; + fn tgammaf(x: f32) -> f32; + } + + // allow for windows (and other targets) + intrinsics! { + pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { + let r = super::libm::lgamma_r(x); + *s = r.1; + r.0 + } + + pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { + let r = super::libm::lgammaf_r(x); + *s = r.1; + r.0 + } + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs new file mode 100644 index 00000000000..c602a67dbd7 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs @@ -0,0 +1,308 @@ +// In C and Rust it is UB to read or write to usize::MAX because if an allocation extends to the +// last byte of address space (there must be an allocation to do the read or write), in C computing +// its one-past-the-end pointer would be equal to NULL and in Rust computing the address of a +// trailing ZST member with a safe place projection would wrap (place projection address computation +// is non-wrapping). +// +// However, some embedded systems have special memory at usize::MAX, and need to access that +// memory. If they do that with the intrinsics provided by compiler-builtins (such as memcpy!), the +// ptr::add in these loops will wrap. And if compiler-builtins is compiled with cfg(ub_checks), +// this will fail a UB check at runtime. +// +// Since this scenario is UB, we are within our rights hit this check and halt execution... +// But we are also within our rights to try to make it work. +// We use wrapping_add/wrapping_sub for pointer arithmetic in this module in an attempt to support +// this use. Of course this is not a guarantee that such use will work, it just means that this +// crate doing wrapping pointer arithmetic with a method that must not wrap won't be the problem if +// something does go wrong at runtime. +use core::intrinsics::likely; + +const WORD_SIZE: usize = core::mem::size_of::(); +const WORD_MASK: usize = WORD_SIZE - 1; + +// If the number of bytes involved exceed this threshold we will opt in word-wise copy. +// The value here selected is max(2 * WORD_SIZE, 16): +// * We need at least 2 * WORD_SIZE bytes to guarantee that at least 1 word will be copied through +// word-wise copy. +// * The word-wise copy logic needs to perform some checks so it has some small overhead. +// ensures that even on 32-bit platforms we have copied at least 8 bytes through +// word-wise copy so the saving of word-wise copy outweighs the fixed overhead. +const WORD_COPY_THRESHOLD: usize = if 2 * WORD_SIZE > 16 { + 2 * WORD_SIZE +} else { + 16 +}; + +#[cfg(feature = "mem-unaligned")] +unsafe fn read_usize_unaligned(x: *const usize) -> usize { + // Do not use `core::ptr::read_unaligned` here, since it calls `copy_nonoverlapping` which + // is translated to memcpy in LLVM. + let x_read = (x as *const [u8; core::mem::size_of::()]).read(); + core::mem::transmute(x_read) +} + +#[inline(always)] +pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) { + #[inline(always)] + unsafe fn copy_forward_bytes(mut dest: *mut u8, mut src: *const u8, n: usize) { + let dest_end = dest.wrapping_add(n); + while dest < dest_end { + *dest = *src; + dest = dest.wrapping_add(1); + src = src.wrapping_add(1); + } + } + + #[inline(always)] + unsafe fn copy_forward_aligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let mut src_usize = src as *mut usize; + let dest_end = dest.wrapping_add(n) as *mut usize; + + while dest_usize < dest_end { + *dest_usize = *src_usize; + dest_usize = dest_usize.wrapping_add(1); + src_usize = src_usize.wrapping_add(1); + } + } + + #[cfg(not(feature = "mem-unaligned"))] + #[inline(always)] + unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let dest_end = dest.wrapping_add(n) as *mut usize; + + // Calculate the misalignment offset and shift needed to reassemble value. + let offset = src as usize & WORD_MASK; + let shift = offset * 8; + + // Realign src + let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; + // This will read (but won't use) bytes out of bound. + // cfg needed because not all targets will have atomic loads that can be lowered + // (e.g. BPF, MSP430), or provided by an external library (e.g. RV32I) + #[cfg(target_has_atomic_load_store = "ptr")] + let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); + #[cfg(not(target_has_atomic_load_store = "ptr"))] + let mut prev_word = core::ptr::read_volatile(src_aligned); + + while dest_usize < dest_end { + src_aligned = src_aligned.wrapping_add(1); + let cur_word = *src_aligned; + #[cfg(target_endian = "little")] + let resembled = prev_word >> shift | cur_word << (WORD_SIZE * 8 - shift); + #[cfg(target_endian = "big")] + let resembled = prev_word << shift | cur_word >> (WORD_SIZE * 8 - shift); + prev_word = cur_word; + + *dest_usize = resembled; + dest_usize = dest_usize.wrapping_add(1); + } + } + + #[cfg(feature = "mem-unaligned")] + #[inline(always)] + unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let mut src_usize = src as *mut usize; + let dest_end = dest.wrapping_add(n) as *mut usize; + + while dest_usize < dest_end { + *dest_usize = read_usize_unaligned(src_usize); + dest_usize = dest_usize.wrapping_add(1); + src_usize = src_usize.wrapping_add(1); + } + } + + if n >= WORD_COPY_THRESHOLD { + // Align dest + // Because of n >= 2 * WORD_SIZE, dst_misalignment < n + let dest_misalignment = (dest as usize).wrapping_neg() & WORD_MASK; + copy_forward_bytes(dest, src, dest_misalignment); + dest = dest.wrapping_add(dest_misalignment); + src = src.wrapping_add(dest_misalignment); + n -= dest_misalignment; + + let n_words = n & !WORD_MASK; + let src_misalignment = src as usize & WORD_MASK; + if likely(src_misalignment == 0) { + copy_forward_aligned_words(dest, src, n_words); + } else { + copy_forward_misaligned_words(dest, src, n_words); + } + dest = dest.wrapping_add(n_words); + src = src.wrapping_add(n_words); + n -= n_words; + } + copy_forward_bytes(dest, src, n); +} + +#[inline(always)] +pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { + // The following backward copy helper functions uses the pointers past the end + // as their inputs instead of pointers to the start! + #[inline(always)] + unsafe fn copy_backward_bytes(mut dest: *mut u8, mut src: *const u8, n: usize) { + let dest_start = dest.wrapping_sub(n); + while dest_start < dest { + dest = dest.wrapping_sub(1); + src = src.wrapping_sub(1); + *dest = *src; + } + } + + #[inline(always)] + unsafe fn copy_backward_aligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let mut src_usize = src as *mut usize; + let dest_start = dest.wrapping_sub(n) as *mut usize; + + while dest_start < dest_usize { + dest_usize = dest_usize.wrapping_sub(1); + src_usize = src_usize.wrapping_sub(1); + *dest_usize = *src_usize; + } + } + + #[cfg(not(feature = "mem-unaligned"))] + #[inline(always)] + unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let dest_start = dest.wrapping_sub(n) as *mut usize; + + // Calculate the misalignment offset and shift needed to reassemble value. + let offset = src as usize & WORD_MASK; + let shift = offset * 8; + + // Realign src_aligned + let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; + // This will read (but won't use) bytes out of bound. + // cfg needed because not all targets will have atomic loads that can be lowered + // (e.g. BPF, MSP430), or provided by an external library (e.g. RV32I) + #[cfg(target_has_atomic_load_store = "ptr")] + let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); + #[cfg(not(target_has_atomic_load_store = "ptr"))] + let mut prev_word = core::ptr::read_volatile(src_aligned); + + while dest_start < dest_usize { + src_aligned = src_aligned.wrapping_sub(1); + let cur_word = *src_aligned; + #[cfg(target_endian = "little")] + let resembled = prev_word << (WORD_SIZE * 8 - shift) | cur_word >> shift; + #[cfg(target_endian = "big")] + let resembled = prev_word >> (WORD_SIZE * 8 - shift) | cur_word << shift; + prev_word = cur_word; + + dest_usize = dest_usize.wrapping_sub(1); + *dest_usize = resembled; + } + } + + #[cfg(feature = "mem-unaligned")] + #[inline(always)] + unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let mut src_usize = src as *mut usize; + let dest_start = dest.wrapping_sub(n) as *mut usize; + + while dest_start < dest_usize { + dest_usize = dest_usize.wrapping_sub(1); + src_usize = src_usize.wrapping_sub(1); + *dest_usize = read_usize_unaligned(src_usize); + } + } + + let mut dest = dest.wrapping_add(n); + let mut src = src.wrapping_add(n); + + if n >= WORD_COPY_THRESHOLD { + // Align dest + // Because of n >= 2 * WORD_SIZE, dst_misalignment < n + let dest_misalignment = dest as usize & WORD_MASK; + copy_backward_bytes(dest, src, dest_misalignment); + dest = dest.wrapping_sub(dest_misalignment); + src = src.wrapping_sub(dest_misalignment); + n -= dest_misalignment; + + let n_words = n & !WORD_MASK; + let src_misalignment = src as usize & WORD_MASK; + if likely(src_misalignment == 0) { + copy_backward_aligned_words(dest, src, n_words); + } else { + copy_backward_misaligned_words(dest, src, n_words); + } + dest = dest.wrapping_sub(n_words); + src = src.wrapping_sub(n_words); + n -= n_words; + } + copy_backward_bytes(dest, src, n); +} + +#[inline(always)] +pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { + #[inline(always)] + pub unsafe fn set_bytes_bytes(mut s: *mut u8, c: u8, n: usize) { + let end = s.wrapping_add(n); + while s < end { + *s = c; + s = s.wrapping_add(1); + } + } + + #[inline(always)] + pub unsafe fn set_bytes_words(s: *mut u8, c: u8, n: usize) { + let mut broadcast = c as usize; + let mut bits = 8; + while bits < WORD_SIZE * 8 { + broadcast |= broadcast << bits; + bits *= 2; + } + + let mut s_usize = s as *mut usize; + let end = s.wrapping_add(n) as *mut usize; + + while s_usize < end { + *s_usize = broadcast; + s_usize = s_usize.wrapping_add(1); + } + } + + if likely(n >= WORD_COPY_THRESHOLD) { + // Align s + // Because of n >= 2 * WORD_SIZE, dst_misalignment < n + let misalignment = (s as usize).wrapping_neg() & WORD_MASK; + set_bytes_bytes(s, c, misalignment); + s = s.wrapping_add(misalignment); + n -= misalignment; + + let n_words = n & !WORD_MASK; + set_bytes_words(s, c, n_words); + s = s.wrapping_add(n_words); + n -= n_words; + } + set_bytes_bytes(s, c, n); +} + +#[inline(always)] +pub unsafe fn compare_bytes(s1: *const u8, s2: *const u8, n: usize) -> i32 { + let mut i = 0; + while i < n { + let a = *s1.wrapping_add(i); + let b = *s2.wrapping_add(i); + if a != b { + return a as i32 - b as i32; + } + i += 1; + } + 0 +} + +#[inline(always)] +pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { + let mut n = 0; + while *s != 0 { + n += 1; + s = s.wrapping_add(1); + } + n +} diff --git a/library/compiler-builtins/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/compiler-builtins/src/mem/mod.rs new file mode 100644 index 00000000000..ec160039d0d --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/mem/mod.rs @@ -0,0 +1,58 @@ +// Trying to satisfy clippy here is hopeless +#![allow(clippy::style)] + +#[allow(warnings)] +#[cfg(target_pointer_width = "16")] +type c_int = i16; +#[allow(warnings)] +#[cfg(not(target_pointer_width = "16"))] +type c_int = i32; + +// memcpy/memmove/memset have optimized implementations on some architectures +#[cfg_attr( + all(not(feature = "no-asm"), target_arch = "x86_64"), + path = "x86_64.rs" +)] +mod impls; + +intrinsics! { + #[mem_builtin] + pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + impls::copy_forward(dest, src, n); + dest + } + + #[mem_builtin] + pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + let delta = (dest as usize).wrapping_sub(src as usize); + if delta >= n { + // We can copy forwards because either dest is far enough ahead of src, + // or src is ahead of dest (and delta overflowed). + impls::copy_forward(dest, src, n); + } else { + impls::copy_backward(dest, src, n); + } + dest + } + + #[mem_builtin] + pub unsafe extern "C" fn memset(s: *mut u8, c: crate::mem::c_int, n: usize) -> *mut u8 { + impls::set_bytes(s, c as u8, n); + s + } + + #[mem_builtin] + pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + impls::compare_bytes(s1, s2, n) + } + + #[mem_builtin] + pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + memcmp(s1, s2, n) + } + + #[mem_builtin] + pub unsafe extern "C" fn strlen(s: *const core::ffi::c_char) -> usize { + impls::c_string_length(s) + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs new file mode 100644 index 00000000000..40b67093f51 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs @@ -0,0 +1,314 @@ +// On most modern Intel and AMD processors, "rep movsq" and "rep stosq" have +// been enhanced to perform better than an simple qword loop, making them ideal +// for implementing memcpy/memset. Note that "rep cmps" has received no such +// enhancement, so it is not used to implement memcmp. +// +// On certain recent Intel processors, "rep movsb" and "rep stosb" have been +// further enhanced to automatically select the best microarchitectural +// implementation based on length and alignment. See the following features from +// the "Intel® 64 and IA-32 Architectures Optimization Reference Manual": +// - ERMSB - Enhanced REP MOVSB and STOSB (Ivy Bridge and later) +// - FSRM - Fast Short REP MOV (Ice Lake and later) +// - Fast Zero-Length MOVSB (On no current hardware) +// - Fast Short STOSB (On no current hardware) +// +// To simplify things, we switch to using the byte-based variants if the "ermsb" +// feature is present at compile-time. We don't bother detecting other features. +// Note that ERMSB does not enhance the backwards (DF=1) "rep movsb". + +use core::arch::asm; +use core::intrinsics; +use core::mem; + +#[inline(always)] +#[cfg(target_feature = "ermsb")] +pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. + core::arch::asm!( + "repe movsb (%rsi), (%rdi)", + inout("rcx") count => _, + inout("rdi") dest => _, + inout("rsi") src => _, + options(att_syntax, nostack, preserves_flags) + ); +} + +#[inline(always)] +#[cfg(not(target_feature = "ermsb"))] +pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) { + let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); + // Separating the blocks gives the compiler more freedom to reorder instructions. + asm!( + "rep movsb", + inout("ecx") pre_byte_count => _, + inout("rdi") dest => dest, + inout("rsi") src => src, + options(att_syntax, nostack, preserves_flags) + ); + asm!( + "rep movsq", + inout("rcx") qword_count => _, + inout("rdi") dest => dest, + inout("rsi") src => src, + options(att_syntax, nostack, preserves_flags) + ); + asm!( + "rep movsb", + inout("ecx") byte_count => _, + inout("rdi") dest => _, + inout("rsi") src => _, + options(att_syntax, nostack, preserves_flags) + ); +} + +#[inline(always)] +pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { + let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); + // We can't separate this block due to std/cld + asm!( + "std", + "rep movsb", + "sub $7, %rsi", + "sub $7, %rdi", + "mov {qword_count}, %rcx", + "rep movsq", + "test {pre_byte_count:e}, {pre_byte_count:e}", + "add $7, %rsi", + "add $7, %rdi", + "mov {pre_byte_count:e}, %ecx", + "rep movsb", + "cld", + pre_byte_count = in(reg) pre_byte_count, + qword_count = in(reg) qword_count, + inout("ecx") byte_count => _, + inout("rdi") dest.add(count - 1) => _, + inout("rsi") src.add(count - 1) => _, + // We modify flags, but we restore it afterwards + options(att_syntax, nostack, preserves_flags) + ); +} + +#[inline(always)] +#[cfg(target_feature = "ermsb")] +pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. + core::arch::asm!( + "repe stosb %al, (%rdi)", + inout("rcx") count => _, + inout("rdi") dest => _, + inout("al") c => _, + options(att_syntax, nostack, preserves_flags) + ) +} + +#[inline(always)] +#[cfg(not(target_feature = "ermsb"))] +pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { + let c = c as u64 * 0x0101_0101_0101_0101; + let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); + // Separating the blocks gives the compiler more freedom to reorder instructions. + asm!( + "rep stosb", + inout("ecx") pre_byte_count => _, + inout("rdi") dest => dest, + in("rax") c, + options(att_syntax, nostack, preserves_flags) + ); + asm!( + "rep stosq", + inout("rcx") qword_count => _, + inout("rdi") dest => dest, + in("rax") c, + options(att_syntax, nostack, preserves_flags) + ); + asm!( + "rep stosb", + inout("ecx") byte_count => _, + inout("rdi") dest => _, + in("rax") c, + options(att_syntax, nostack, preserves_flags) + ); +} + +#[inline(always)] +pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { + #[inline(always)] + unsafe fn cmp(mut a: *const T, mut b: *const T, n: usize, f: F) -> i32 + where + T: Clone + Copy + Eq, + U: Clone + Copy + Eq, + F: FnOnce(*const U, *const U, usize) -> i32, + { + // Ensure T is not a ZST. + const { assert!(mem::size_of::() != 0) }; + + let end = a.add(intrinsics::unchecked_div(n, mem::size_of::())); + while a != end { + if a.read_unaligned() != b.read_unaligned() { + return f(a.cast(), b.cast(), mem::size_of::()); + } + a = a.add(1); + b = b.add(1); + } + f( + a.cast(), + b.cast(), + intrinsics::unchecked_rem(n, mem::size_of::()), + ) + } + let c1 = |mut a: *const u8, mut b: *const u8, n| { + for _ in 0..n { + if a.read() != b.read() { + return i32::from(a.read()) - i32::from(b.read()); + } + a = a.add(1); + b = b.add(1); + } + 0 + }; + let c2 = |a: *const u16, b, n| cmp(a, b, n, c1); + let c4 = |a: *const u32, b, n| cmp(a, b, n, c2); + let c8 = |a: *const u64, b, n| cmp(a, b, n, c4); + let c16 = |a: *const u128, b, n| cmp(a, b, n, c8); + c16(a.cast(), b.cast(), n) +} + +// In order to process more than on byte simultaneously when executing strlen, +// two things must be considered: +// * An n byte read with an n-byte aligned address will never cross +// a page boundary and will always succeed. Any smaller alignment +// may result in a read that will cross a page boundary, which may +// trigger an access violation. +// * Surface Rust considers any kind of out-of-bounds read as undefined +// behaviour. To dodge this, memory access operations are written +// using inline assembly. + +#[cfg(target_feature = "sse2")] +#[inline(always)] +pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { + use core::arch::x86_64::{__m128i, _mm_cmpeq_epi8, _mm_movemask_epi8, _mm_set1_epi8}; + + let mut n = 0; + + // The use of _mm_movemask_epi8 and company allow for speedups, + // but they aren't cheap by themselves. Thus, possibly small strings + // are handled in simple loops. + + for _ in 0..4 { + if *s == 0 { + return n; + } + + n += 1; + s = s.add(1); + } + + // Shave of the least significand bits to align the address to a 16 + // byte boundary. The shaved of bits are used to correct the first iteration. + + let align = s as usize & 15; + let mut s = ((s as usize) - align) as *const __m128i; + let zero = _mm_set1_epi8(0); + + let x = { + let r; + asm!( + "movdqa ({addr}), {dest}", + addr = in(reg) s, + dest = out(xmm_reg) r, + options(att_syntax, nostack), + ); + r + }; + let cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(x, zero)) >> align; + + if cmp != 0 { + return n + cmp.trailing_zeros() as usize; + } + + n += 16 - align; + s = s.add(1); + + loop { + let x = { + let r; + asm!( + "movdqa ({addr}), {dest}", + addr = in(reg) s, + dest = out(xmm_reg) r, + options(att_syntax, nostack), + ); + r + }; + let cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(x, zero)) as u32; + if cmp == 0 { + n += 16; + s = s.add(1); + } else { + return n + cmp.trailing_zeros() as usize; + } + } +} + +// Provided for scenarios like kernel development, where SSE might not +// be available. +#[cfg(not(target_feature = "sse2"))] +#[inline(always)] +pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { + let mut n = 0; + + // Check bytes in steps of one until + // either a zero byte is discovered or + // pointer is aligned to an eight byte boundary. + + while s as usize & 7 != 0 { + if *s == 0 { + return n; + } + n += 1; + s = s.add(1); + } + + // Check bytes in steps of eight until a zero + // byte is discovered. + + let mut s = s as *const u64; + + loop { + let mut cs = { + let r: u64; + asm!( + "mov ({addr}), {dest}", + addr = in(reg) s, + dest = out(reg) r, + options(att_syntax, nostack), + ); + r + }; + // Detect if a word has a zero byte, taken from + // https://graphics.stanford.edu/~seander/bithacks.html + if (cs.wrapping_sub(0x0101010101010101) & !cs & 0x8080808080808080) != 0 { + loop { + if cs & 255 == 0 { + return n; + } else { + cs >>= 8; + n += 1; + } + } + } else { + n += 8; + s = s.add(1); + } + } +} + +/// Determine optimal parameters for a `rep` instruction. +fn rep_param(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { + // Unaligned writes are still slow on modern processors, so align the destination address. + let pre_byte_count = ((8 - (dest as usize & 0b111)) & 0b111).min(count); + count -= pre_byte_count; + let qword_count = count >> 3; + let byte_count = count & 0b111; + (pre_byte_count, qword_count, byte_count) +} diff --git a/library/compiler-builtins/compiler-builtins/src/probestack.rs b/library/compiler-builtins/compiler-builtins/src/probestack.rs new file mode 100644 index 00000000000..5b6abd21a1d --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/probestack.rs @@ -0,0 +1,350 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module defines the `__rust_probestack` intrinsic which is used in the +//! implementation of "stack probes" on certain platforms. +//! +//! The purpose of a stack probe is to provide a static guarantee that if a +//! thread has a guard page then a stack overflow is guaranteed to hit that +//! guard page. If a function did not have a stack probe then there's a risk of +//! having a stack frame *larger* than the guard page, so a function call could +//! skip over the guard page entirely and then later hit maybe the heap or +//! another thread, possibly leading to security vulnerabilities such as [The +//! Stack Clash], for example. +//! +//! [The Stack Clash]: https://blog.qualys.com/securitylabs/2017/06/19/the-stack-clash +//! +//! The `__rust_probestack` is called in the prologue of functions whose stack +//! size is larger than the guard page, for example larger than 4096 bytes on +//! x86. This function is then responsible for "touching" all pages relevant to +//! the stack to ensure that that if any of them are the guard page we'll hit +//! them guaranteed. +//! +//! The precise ABI for how this function operates is defined by LLVM. There's +//! no real documentation as to what this is, so you'd basically need to read +//! the LLVM source code for reference. Often though the test cases can be +//! illuminating as to the ABI that's generated, or just looking at the output +//! of `llc`. +//! +//! Note that `#[naked]` is typically used here for the stack probe because the +//! ABI corresponds to no actual ABI. +//! +//! Finally it's worth noting that at the time of this writing LLVM only has +//! support for stack probes on x86 and x86_64. There's no support for stack +//! probes on any other architecture like ARM or PowerPC64. LLVM I'm sure would +//! be more than welcome to accept such a change! + +#![cfg(not(feature = "mangled-names"))] +// Windows and Cygwin already has builtins to do this. +#![cfg(not(any(windows, target_os = "cygwin")))] +// All these builtins require assembly +#![cfg(not(feature = "no-asm"))] +// We only define stack probing for these architectures today. +#![cfg(any(target_arch = "x86_64", target_arch = "x86"))] + +extern "C" { + pub fn __rust_probestack(); +} + +// A wrapper for our implementation of __rust_probestack, which allows us to +// keep the assembly inline while controlling all CFI directives in the assembly +// emitted for the function. +// +// This is the ELF version. +#[cfg(not(any(target_vendor = "apple", target_os = "uefi")))] +macro_rules! define_rust_probestack { + ($body: expr) => { + concat!( + " + .pushsection .text.__rust_probestack + .globl __rust_probestack + .type __rust_probestack, @function + .hidden __rust_probestack + __rust_probestack: + ", + $body, + " + .size __rust_probestack, . - __rust_probestack + .popsection + " + ) + }; +} + +#[cfg(all(target_os = "uefi", target_arch = "x86_64"))] +macro_rules! define_rust_probestack { + ($body: expr) => { + concat!( + " + .globl __rust_probestack + __rust_probestack: + ", + $body + ) + }; +} + +// Same as above, but for Mach-O. Note that the triple underscore +// is deliberate +#[cfg(target_vendor = "apple")] +macro_rules! define_rust_probestack { + ($body: expr) => { + concat!( + " + .globl ___rust_probestack + ___rust_probestack: + ", + $body + ) + }; +} + +// In UEFI x86 arch, triple underscore is deliberate. +#[cfg(all(target_os = "uefi", target_arch = "x86"))] +macro_rules! define_rust_probestack { + ($body: expr) => { + concat!( + " + .globl ___rust_probestack + ___rust_probestack: + ", + $body + ) + }; +} + +// Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, +// ensuring that if any pages are unmapped we'll make a page fault. +// +// The ABI here is that the stack frame size is located in `%rax`. Upon +// return we're not supposed to modify `%rsp` or `%rax`. +// +// Any changes to this function should be replicated to the SGX version below. +#[cfg(all( + target_arch = "x86_64", + not(all(target_env = "sgx", target_vendor = "fortanix")) +))] +core::arch::global_asm!( + define_rust_probestack!( + " + .cfi_startproc + pushq %rbp + .cfi_adjust_cfa_offset 8 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + + mov %rax,%r11 // duplicate %rax as we're clobbering %r11 + + // Main loop, taken in one page increments. We're decrementing rsp by + // a page each time until there's less than a page remaining. We're + // guaranteed that this function isn't called unless there's more than a + // page needed. + // + // Note that we're also testing against `8(%rsp)` to account for the 8 + // bytes pushed on the stack orginally with our return address. Using + // `8(%rsp)` simulates us testing the stack pointer in the caller's + // context. + + // It's usually called when %rax >= 0x1000, but that's not always true. + // Dynamic stack allocation, which is needed to implement unsized + // rvalues, triggers stackprobe even if %rax < 0x1000. + // Thus we have to check %r11 first to avoid segfault. + cmp $0x1000,%r11 + jna 3f +2: + sub $0x1000,%rsp + test %rsp,8(%rsp) + sub $0x1000,%r11 + cmp $0x1000,%r11 + ja 2b + +3: + // Finish up the last remaining stack space requested, getting the last + // bits out of r11 + sub %r11,%rsp + test %rsp,8(%rsp) + + // Restore the stack pointer to what it previously was when entering + // this function. The caller will readjust the stack pointer after we + // return. + add %rax,%rsp + + leave + .cfi_def_cfa_register %rsp + .cfi_adjust_cfa_offset -8 + ret + .cfi_endproc + " + ), + options(att_syntax) +); + +// This function is the same as above, except that some instructions are +// [manually patched for LVI]. +// +// [manually patched for LVI]: https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions +#[cfg(all( + target_arch = "x86_64", + all(target_env = "sgx", target_vendor = "fortanix") +))] +core::arch::global_asm!( + define_rust_probestack!( + " + .cfi_startproc + pushq %rbp + .cfi_adjust_cfa_offset 8 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + + mov %rax,%r11 // duplicate %rax as we're clobbering %r11 + + // Main loop, taken in one page increments. We're decrementing rsp by + // a page each time until there's less than a page remaining. We're + // guaranteed that this function isn't called unless there's more than a + // page needed. + // + // Note that we're also testing against `8(%rsp)` to account for the 8 + // bytes pushed on the stack orginally with our return address. Using + // `8(%rsp)` simulates us testing the stack pointer in the caller's + // context. + + // It's usually called when %rax >= 0x1000, but that's not always true. + // Dynamic stack allocation, which is needed to implement unsized + // rvalues, triggers stackprobe even if %rax < 0x1000. + // Thus we have to check %r11 first to avoid segfault. + cmp $0x1000,%r11 + jna 3f +2: + sub $0x1000,%rsp + test %rsp,8(%rsp) + sub $0x1000,%r11 + cmp $0x1000,%r11 + ja 2b + +3: + // Finish up the last remaining stack space requested, getting the last + // bits out of r11 + sub %r11,%rsp + test %rsp,8(%rsp) + + // Restore the stack pointer to what it previously was when entering + // this function. The caller will readjust the stack pointer after we + // return. + add %rax,%rsp + + leave + .cfi_def_cfa_register %rsp + .cfi_adjust_cfa_offset -8 + pop %r11 + lfence + jmp *%r11 + .cfi_endproc + " + ), + options(att_syntax) +); + +#[cfg(all(target_arch = "x86", not(target_os = "uefi")))] +// This is the same as x86_64 above, only translated for 32-bit sizes. Note +// that on Unix we're expected to restore everything as it was, this +// function basically can't tamper with anything. +// +// The ABI here is the same as x86_64, except everything is 32-bits large. +core::arch::global_asm!( + define_rust_probestack!( + " + .cfi_startproc + push %ebp + .cfi_adjust_cfa_offset 4 + .cfi_offset %ebp, -8 + mov %esp, %ebp + .cfi_def_cfa_register %ebp + push %ecx + mov %eax,%ecx + + cmp $0x1000,%ecx + jna 3f +2: + sub $0x1000,%esp + test %esp,8(%esp) + sub $0x1000,%ecx + cmp $0x1000,%ecx + ja 2b + +3: + sub %ecx,%esp + test %esp,8(%esp) + + add %eax,%esp + pop %ecx + leave + .cfi_def_cfa_register %esp + .cfi_adjust_cfa_offset -4 + ret + .cfi_endproc + " + ), + options(att_syntax) +); + +#[cfg(all(target_arch = "x86", target_os = "uefi"))] +// UEFI target is windows like target. LLVM will do _chkstk things like windows. +// probestack function will also do things like _chkstk in MSVC. +// So we need to sub %ax %sp in probestack when arch is x86. +// +// REF: Rust commit(74e80468347) +// rust\src\llvm-project\llvm\lib\Target\X86\X86FrameLowering.cpp: 805 +// Comments in LLVM: +// MSVC x32's _chkstk and cygwin/mingw's _alloca adjust %esp themselves. +// MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp +// themselves. +core::arch::global_asm!( + define_rust_probestack!( + " + .cfi_startproc + push %ebp + .cfi_adjust_cfa_offset 4 + .cfi_offset %ebp, -8 + mov %esp, %ebp + .cfi_def_cfa_register %ebp + push %ecx + push %edx + mov %eax,%ecx + + cmp $0x1000,%ecx + jna 3f +2: + sub $0x1000,%esp + test %esp,8(%esp) + sub $0x1000,%ecx + cmp $0x1000,%ecx + ja 2b + +3: + sub %ecx,%esp + test %esp,8(%esp) + mov 4(%ebp),%edx + mov %edx, 12(%esp) + add %eax,%esp + pop %edx + pop %ecx + leave + + sub %eax, %esp + .cfi_def_cfa_register %esp + .cfi_adjust_cfa_offset -4 + ret + .cfi_endproc + " + ), + options(att_syntax) +); diff --git a/library/compiler-builtins/compiler-builtins/src/riscv.rs b/library/compiler-builtins/compiler-builtins/src/riscv.rs new file mode 100644 index 00000000000..bf312553341 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/riscv.rs @@ -0,0 +1,50 @@ +intrinsics! { + // Ancient Egyptian/Ethiopian/Russian multiplication method + // see https://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication + // + // This is a long-available stock algorithm; e.g. it is documented in + // Knuth's "The Art of Computer Programming" volume 2 (under the section + // "Evaluation of Powers") since at least the 2nd edition (1981). + // + // The main attraction of this method is that it implements (software) + // multiplication atop four simple operations: doubling, halving, checking + // if a value is even/odd, and addition. This is *not* considered to be the + // fastest multiplication method, but it may be amongst the simplest (and + // smallest with respect to code size). + // + // for reference, see also implementation from gcc + // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c + // + // and from LLVM (in relatively readable RISC-V assembly): + // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/riscv/int_mul_impl.inc + pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { + let (mut a, mut b) = (a, b); + let mut r: u32 = 0; + + while a > 0 { + if a & 1 > 0 { + r = r.wrapping_add(b); + } + a >>= 1; + b <<= 1; + } + + r + } + + #[cfg(not(target_feature = "m"))] + pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { + let (mut a, mut b) = (a, b); + let mut r: u64 = 0; + + while a > 0 { + if a & 1 > 0 { + r = r.wrapping_add(b); + } + a >>= 1; + b <<= 1; + } + + r + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/x86.rs b/library/compiler-builtins/compiler-builtins/src/x86.rs new file mode 100644 index 00000000000..ad04d2108ea --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/x86.rs @@ -0,0 +1,53 @@ +#![allow(unused_imports)] + +use core::intrinsics; + +// NOTE These functions are implemented using assembly because they using a custom +// calling convention which can't be implemented using a normal Rust function + +// NOTE These functions are never mangled as they are not tested against compiler-rt + +intrinsics! { + #[naked] + #[cfg(all( + any(all(windows, target_env = "gnu"), target_os = "uefi"), + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn __chkstk() { + core::arch::naked_asm!( + "jmp __alloca", // Jump to __alloca since fallthrough may be unreliable" + options(att_syntax) + ); + } + + #[naked] + #[cfg(all( + any(all(windows, target_env = "gnu"), target_os = "uefi"), + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn _alloca() { + // __chkstk and _alloca are the same function + core::arch::naked_asm!( + "push %ecx", + "cmp $0x1000,%eax", + "lea 8(%esp),%ecx", // esp before calling this routine -> ecx + "jb 1f", + "2:", + "sub $0x1000,%ecx", + "test %ecx,(%ecx)", + "sub $0x1000,%eax", + "cmp $0x1000,%eax", + "ja 2b", + "1:", + "sub %eax,%ecx", + "test %ecx,(%ecx)", + "lea 4(%esp),%eax", // load pointer to the return address into eax + "mov %ecx,%esp", // install the new top of stack pointer into esp + "mov -4(%eax),%ecx", // restore ecx + "push (%eax)", // push return address onto the stack + "sub %esp,%eax", // restore the original value in eax + "ret", + options(att_syntax) + ); + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/x86_64.rs new file mode 100644 index 00000000000..aae601f58bf --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/x86_64.rs @@ -0,0 +1,51 @@ +#![allow(unused_imports)] + +use core::intrinsics; + +// NOTE These functions are implemented using assembly because they using a custom +// calling convention which can't be implemented using a normal Rust function + +// NOTE These functions are never mangled as they are not tested against compiler-rt + +intrinsics! { + #[naked] + #[cfg(all( + any( + all(windows, target_env = "gnu"), + target_os = "cygwin", + target_os = "uefi" + ), + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn ___chkstk_ms() { + core::arch::naked_asm!( + "push %rcx", + "push %rax", + "cmp $0x1000,%rax", + "lea 24(%rsp),%rcx", + "jb 1f", + "2:", + "sub $0x1000,%rcx", + "test %rcx,(%rcx)", + "sub $0x1000,%rax", + "cmp $0x1000,%rax", + "ja 2b", + "1:", + "sub %rax,%rcx", + "test %rcx,(%rcx)", + "pop %rax", + "pop %rcx", + "ret", + options(att_syntax) + ); + } +} + +// HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM +// support unless we emit the _fltused +mod _fltused { + #[no_mangle] + #[used] + #[cfg(target_os = "uefi")] + static _fltused: i32 = 0; +} diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs deleted file mode 100644 index 2f134e57818..00000000000 --- a/library/compiler-builtins/configure.rs +++ /dev/null @@ -1,138 +0,0 @@ -// Configuration that is shared between `compiler_builtins` and `testcrate`. - -use std::env; - -#[derive(Debug)] -#[allow(dead_code)] -pub struct Target { - pub triple: String, - pub triple_split: Vec, - pub opt_level: String, - pub cargo_features: Vec, - pub os: String, - pub arch: String, - pub vendor: String, - pub env: String, - pub pointer_width: u8, - pub little_endian: bool, - pub features: Vec, -} - -impl Target { - pub fn from_env() -> Self { - let triple = env::var("TARGET").unwrap(); - let triple_split = triple.split('-').map(ToOwned::to_owned).collect(); - let little_endian = match env::var("CARGO_CFG_TARGET_ENDIAN").unwrap().as_str() { - "little" => true, - "big" => false, - x => panic!("unknown endian {x}"), - }; - let cargo_features = env::vars() - .filter_map(|(name, _value)| name.strip_prefix("CARGO_FEATURE_").map(ToOwned::to_owned)) - .map(|s| s.to_lowercase().replace("_", "-")) - .collect(); - - Self { - triple, - triple_split, - os: env::var("CARGO_CFG_TARGET_OS").unwrap(), - opt_level: env::var("OPT_LEVEL").unwrap(), - cargo_features, - arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), - vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), - env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), - pointer_width: env::var("CARGO_CFG_TARGET_POINTER_WIDTH") - .unwrap() - .parse() - .unwrap(), - little_endian, - features: env::var("CARGO_CFG_TARGET_FEATURE") - .unwrap_or_default() - .split(",") - .map(ToOwned::to_owned) - .collect(), - } - } - - #[allow(dead_code)] - pub fn has_feature(&self, feature: &str) -> bool { - self.features.iter().any(|f| f == feature) - } -} - -pub fn configure_aliases(target: &Target) { - // To compile builtins-test-intrinsics for thumb targets, where there is no libc - println!("cargo::rustc-check-cfg=cfg(thumb)"); - if target.triple_split[0].starts_with("thumb") { - println!("cargo:rustc-cfg=thumb") - } - - // compiler-rt `cfg`s away some intrinsics for thumbv6m and thumbv8m.base because - // these targets do not have full Thumb-2 support but only original Thumb-1. - // We have to cfg our code accordingly. - println!("cargo::rustc-check-cfg=cfg(thumb_1)"); - if target.triple_split[0] == "thumbv6m" || target.triple_split[0] == "thumbv8m.base" { - println!("cargo:rustc-cfg=thumb_1") - } -} - -/// Configure whether or not `f16` and `f128` support should be enabled. -pub fn configure_f16_f128(target: &Target) { - // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means - // that the backend will not crash when using these types and generates code that can be called - // without crashing (no infinite recursion). This does not mean that the platform doesn't have - // ABI or other bugs. - // - // We do this here rather than in `rust-lang/rust` because configuring via cargo features is - // not straightforward. - // - // Original source of this list: - // - let f16_enabled = match target.arch.as_str() { - // Unsupported - "arm64ec" => false, - // Crash in LLVM20 - "aarch64" if !target.features.iter().any(|f| f == "neon") => false, - // Selection failure - "s390x" => false, - // Infinite recursion - "csky" => false, - "hexagon" => false, - "powerpc" | "powerpc64" => false, - "sparc" | "sparc64" => false, - "wasm32" | "wasm64" => false, - // Most everything else works as of LLVM 19 - _ => true, - }; - - let f128_enabled = match target.arch.as_str() { - // Unsupported (libcall is not supported) - "amdgpu" => false, - // Unsupported - "arm64ec" => false, - // FIXME(llvm20): fixed by - "mips64" | "mips64r6" => false, - // Selection failure - "nvptx64" => false, - // Selection failure - "powerpc64" if &target.os == "aix" => false, - // Selection failure - "sparc" => false, - // Most everything else works as of LLVM 19 - _ => true, - }; - - // If the feature is set, disable these types. - let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); - - println!("cargo::rustc-check-cfg=cfg(f16_enabled)"); - println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); - - if f16_enabled && !disable_both { - println!("cargo::rustc-cfg=f16_enabled"); - } - - if f128_enabled && !disable_both { - println!("cargo::rustc-cfg=f128_enabled"); - } -} diff --git a/library/compiler-builtins/crates/panic-handler/Cargo.toml b/library/compiler-builtins/crates/panic-handler/Cargo.toml index 96b83eaa226..a6764fc481b 100644 --- a/library/compiler-builtins/crates/panic-handler/Cargo.toml +++ b/library/compiler-builtins/crates/panic-handler/Cargo.toml @@ -5,4 +5,8 @@ authors = ["Alex Crichton "] edition = "2024" publish = false +[lib] +test = false +bench = false + [dependencies] diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm deleted file mode 160000 index 69219c491ee..00000000000 --- a/library/compiler-builtins/libm +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 69219c491ee9f05761d2068fd6d4c7c0de6faa3a diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64.rs deleted file mode 100644 index cce485c4682..00000000000 --- a/library/compiler-builtins/src/aarch64.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![allow(unused_imports)] - -use core::intrinsics; - -intrinsics! { - #[naked] - #[cfg(all(target_os = "uefi", not(feature = "no-asm")))] - pub unsafe extern "C" fn __chkstk() { - core::arch::naked_asm!( - ".p2align 2", - "lsl x16, x15, #4", - "mov x17, sp", - "1:", - "sub x17, x17, 4096", - "subs x16, x16, 4096", - "ldr xzr, [x17]", - "b.gt 1b", - "ret", - ); - } -} diff --git a/library/compiler-builtins/src/aarch64_linux.rs b/library/compiler-builtins/src/aarch64_linux.rs deleted file mode 100644 index caac3e6025d..00000000000 --- a/library/compiler-builtins/src/aarch64_linux.rs +++ /dev/null @@ -1,273 +0,0 @@ -//! Aarch64 targets have two possible implementations for atomics: -//! 1. Load-Locked, Store-Conditional (LL/SC), older and slower. -//! 2. Large System Extensions (LSE), newer and faster. -//! To avoid breaking backwards compat, C toolchains introduced a concept of "outlined atomics", -//! where atomic operations call into the compiler runtime to dispatch between two depending on -//! which is supported on the current CPU. -//! See https://community.arm.com/arm-community-blogs/b/tools-software-ides-blog/posts/making-the-most-of-the-arm-architecture-in-gcc-10#:~:text=out%20of%20line%20atomics for more discussion. -//! -//! Currently we only support LL/SC, because LSE requires `getauxval` from libc in order to do runtime detection. -//! Use the `compiler-rt` intrinsics if you want LSE support. -//! -//! Ported from `aarch64/lse.S` in LLVM's compiler-rt. -//! -//! Generate functions for each of the following symbols: -//! __aarch64_casM_ORDER -//! __aarch64_swpN_ORDER -//! __aarch64_ldaddN_ORDER -//! __aarch64_ldclrN_ORDER -//! __aarch64_ldeorN_ORDER -//! __aarch64_ldsetN_ORDER -//! for N = {1, 2, 4, 8}, M = {1, 2, 4, 8, 16}, ORDER = { relax, acq, rel, acq_rel } -//! -//! The original `lse.S` has some truly horrifying code that expects to be compiled multiple times with different constants. -//! We do something similar, but with macro arguments. -#![cfg_attr(feature = "c", allow(unused_macros))] // avoid putting the macros into a submodule - -// We don't do runtime dispatch so we don't have to worry about the `__aarch64_have_lse_atomics` global ctor. - -/// Translate a byte size to a Rust type. -#[rustfmt::skip] -macro_rules! int_ty { - (1) => { i8 }; - (2) => { i16 }; - (4) => { i32 }; - (8) => { i64 }; - (16) => { i128 }; -} - -/// Given a byte size and a register number, return a register of the appropriate size. -/// -/// See . -#[rustfmt::skip] -macro_rules! reg { - (1, $num:literal) => { concat!("w", $num) }; - (2, $num:literal) => { concat!("w", $num) }; - (4, $num:literal) => { concat!("w", $num) }; - (8, $num:literal) => { concat!("x", $num) }; -} - -/// Given an atomic ordering, translate it to the acquire suffix for the lxdr aarch64 ASM instruction. -#[rustfmt::skip] -macro_rules! acquire { - (Relaxed) => { "" }; - (Acquire) => { "a" }; - (Release) => { "" }; - (AcqRel) => { "a" }; -} - -/// Given an atomic ordering, translate it to the release suffix for the stxr aarch64 ASM instruction. -#[rustfmt::skip] -macro_rules! release { - (Relaxed) => { "" }; - (Acquire) => { "" }; - (Release) => { "l" }; - (AcqRel) => { "l" }; -} - -/// Given a size in bytes, translate it to the byte suffix for an aarch64 ASM instruction. -#[rustfmt::skip] -macro_rules! size { - (1) => { "b" }; - (2) => { "h" }; - (4) => { "" }; - (8) => { "" }; - (16) => { "" }; -} - -/// Given a byte size, translate it to an Unsigned eXTend instruction -/// with the correct semantics. -/// -/// See -#[rustfmt::skip] -macro_rules! uxt { - (1) => { "uxtb" }; - (2) => { "uxth" }; - ($_:tt) => { "mov" }; -} - -/// Given an atomic ordering and byte size, translate it to a LoaD eXclusive Register instruction -/// with the correct semantics. -/// -/// See . -macro_rules! ldxr { - ($ordering:ident, $bytes:tt) => { - concat!("ld", acquire!($ordering), "xr", size!($bytes)) - }; -} - -/// Given an atomic ordering and byte size, translate it to a STore eXclusive Register instruction -/// with the correct semantics. -/// -/// See . -macro_rules! stxr { - ($ordering:ident, $bytes:tt) => { - concat!("st", release!($ordering), "xr", size!($bytes)) - }; -} - -/// Given an atomic ordering and byte size, translate it to a LoaD eXclusive Pair of registers instruction -/// with the correct semantics. -/// -/// See -macro_rules! ldxp { - ($ordering:ident) => { - concat!("ld", acquire!($ordering), "xp") - }; -} - -/// Given an atomic ordering and byte size, translate it to a STore eXclusive Pair of registers instruction -/// with the correct semantics. -/// -/// See . -macro_rules! stxp { - ($ordering:ident) => { - concat!("st", release!($ordering), "xp") - }; -} - -/// See . -macro_rules! compare_and_swap { - ($ordering:ident, $bytes:tt, $name:ident) => { - intrinsics! { - #[maybe_use_optimized_c_shim] - #[naked] - pub unsafe extern "C" fn $name ( - expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes) - ) -> int_ty!($bytes) { - // We can't use `AtomicI8::compare_and_swap`; we *are* compare_and_swap. - unsafe { core::arch::naked_asm! { - // UXT s(tmp0), s(0) - concat!(uxt!($bytes), " ", reg!($bytes, 16), ", ", reg!($bytes, 0)), - "0:", - // LDXR s(0), [x2] - concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x2]"), - // cmp s(0), s(tmp0) - concat!("cmp ", reg!($bytes, 0), ", ", reg!($bytes, 16)), - "bne 1f", - // STXR w(tmp1), s(1), [x2] - concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 1), ", [x2]"), - "cbnz w17, 0b", - "1:", - "ret", - } } - } - } - }; -} - -// i128 uses a completely different impl, so it has its own macro. -macro_rules! compare_and_swap_i128 { - ($ordering:ident, $name:ident) => { - intrinsics! { - #[maybe_use_optimized_c_shim] - #[naked] - pub unsafe extern "C" fn $name ( - expected: i128, desired: i128, ptr: *mut i128 - ) -> i128 { - unsafe { core::arch::naked_asm! { - "mov x16, x0", - "mov x17, x1", - "0:", - // LDXP x0, x1, [x4] - concat!(ldxp!($ordering), " x0, x1, [x4]"), - "cmp x0, x16", - "ccmp x1, x17, #0, eq", - "bne 1f", - // STXP w(tmp2), x2, x3, [x4] - concat!(stxp!($ordering), " w15, x2, x3, [x4]"), - "cbnz w15, 0b", - "1:", - "ret", - } } - } - } - }; -} - -/// See . -macro_rules! swap { - ($ordering:ident, $bytes:tt, $name:ident) => { - intrinsics! { - #[maybe_use_optimized_c_shim] - #[naked] - pub unsafe extern "C" fn $name ( - left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes) - ) -> int_ty!($bytes) { - unsafe { core::arch::naked_asm! { - // mov s(tmp0), s(0) - concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), - "0:", - // LDXR s(0), [x1] - concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x1]"), - // STXR w(tmp1), s(tmp0), [x1] - concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 16), ", [x1]"), - "cbnz w17, 0b", - "ret", - } } - } - } - }; -} - -/// See (e.g.) . -macro_rules! fetch_op { - ($ordering:ident, $bytes:tt, $name:ident, $op:literal) => { - intrinsics! { - #[maybe_use_optimized_c_shim] - #[naked] - pub unsafe extern "C" fn $name ( - val: int_ty!($bytes), ptr: *mut int_ty!($bytes) - ) -> int_ty!($bytes) { - unsafe { core::arch::naked_asm! { - // mov s(tmp0), s(0) - concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), - "0:", - // LDXR s(0), [x1] - concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x1]"), - // OP s(tmp1), s(0), s(tmp0) - concat!($op, " ", reg!($bytes, 17), ", ", reg!($bytes, 0), ", ", reg!($bytes, 16)), - // STXR w(tmp2), s(tmp1), [x1] - concat!(stxr!($ordering, $bytes), " w15, ", reg!($bytes, 17), ", [x1]"), - "cbnz w15, 0b", - "ret", - } } - } - } - } -} - -// We need a single macro to pass to `foreach_ldadd`. -macro_rules! add { - ($ordering:ident, $bytes:tt, $name:ident) => { - fetch_op! { $ordering, $bytes, $name, "add" } - }; -} - -macro_rules! and { - ($ordering:ident, $bytes:tt, $name:ident) => { - fetch_op! { $ordering, $bytes, $name, "bic" } - }; -} - -macro_rules! xor { - ($ordering:ident, $bytes:tt, $name:ident) => { - fetch_op! { $ordering, $bytes, $name, "eor" } - }; -} - -macro_rules! or { - ($ordering:ident, $bytes:tt, $name:ident) => { - fetch_op! { $ordering, $bytes, $name, "orr" } - }; -} - -// See `generate_aarch64_outlined_atomics` in build.rs. -include!(concat!(env!("OUT_DIR"), "/outlined_atomics.rs")); -foreach_cas!(compare_and_swap); -foreach_cas16!(compare_and_swap_i128); -foreach_swp!(swap); -foreach_ldadd!(add); -foreach_ldclr!(and); -foreach_ldeor!(xor); -foreach_ldset!(or); diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs deleted file mode 100644 index 9e6608397a8..00000000000 --- a/library/compiler-builtins/src/arm.rs +++ /dev/null @@ -1,165 +0,0 @@ -#![cfg(not(feature = "no-asm"))] -#![allow(unused_imports)] - -use core::intrinsics; - -// Apple symbols have a leading underscore. -#[cfg(target_vendor = "apple")] -macro_rules! bl { - ($func:literal) => { - concat!("bl _", $func) - }; -} -#[cfg(not(target_vendor = "apple"))] -macro_rules! bl { - ($func:literal) => { - concat!("bl ", $func) - }; -} - -intrinsics! { - // NOTE This function and the ones below are implemented using assembly because they are using a - // custom calling convention which can't be implemented using a normal Rust function. - #[naked] - #[cfg(not(target_env = "msvc"))] - pub unsafe extern "C" fn __aeabi_uidivmod() { - core::arch::naked_asm!( - "push {{lr}}", - "sub sp, sp, #4", - "mov r2, sp", - bl!("__udivmodsi4"), - "ldr r1, [sp]", - "add sp, sp, #4", - "pop {{pc}}", - ); - } - - #[naked] - pub unsafe extern "C" fn __aeabi_uldivmod() { - core::arch::naked_asm!( - "push {{r4, lr}}", - "sub sp, sp, #16", - "add r4, sp, #8", - "str r4, [sp]", - bl!("__udivmoddi4"), - "ldr r2, [sp, #8]", - "ldr r3, [sp, #12]", - "add sp, sp, #16", - "pop {{r4, pc}}", - ); - } - - #[naked] - pub unsafe extern "C" fn __aeabi_idivmod() { - core::arch::naked_asm!( - "push {{r0, r1, r4, lr}}", - bl!("__aeabi_idiv"), - "pop {{r1, r2}}", - "muls r2, r2, r0", - "subs r1, r1, r2", - "pop {{r4, pc}}", - ); - } - - #[naked] - pub unsafe extern "C" fn __aeabi_ldivmod() { - core::arch::naked_asm!( - "push {{r4, lr}}", - "sub sp, sp, #16", - "add r4, sp, #8", - "str r4, [sp]", - bl!("__divmoddi4"), - "ldr r2, [sp, #8]", - "ldr r3, [sp, #12]", - "add sp, sp, #16", - "pop {{r4, pc}}", - ); - } - - // FIXME: The `*4` and `*8` variants should be defined as aliases. - - #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { - crate::mem::memcpy(dest, src, n); - } - - #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { - // We are guaranteed 4-alignment, so accessing at u32 is okay. - let mut dest = dest as *mut u32; - let mut src = src as *mut u32; - let mut n = n; - - while n >= 4 { - *dest = *src; - dest = dest.offset(1); - src = src.offset(1); - n -= 4; - } - - __aeabi_memcpy(dest as *mut u8, src as *const u8, n); - } - - #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memcpy4(dest, src, n); - } - - #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { - crate::mem::memmove(dest, src, n); - } - - #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memmove(dest, src, n); - } - - #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memmove(dest, src, n); - } - - #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { - // Note the different argument order - crate::mem::memset(dest, c, n); - } - - #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { - let mut dest = dest as *mut u32; - let mut n = n; - - let byte = (c as u32) & 0xff; - let c = (byte << 24) | (byte << 16) | (byte << 8) | byte; - - while n >= 4 { - *dest = c; - dest = dest.offset(1); - n -= 4; - } - - __aeabi_memset(dest as *mut u8, n, byte as i32); - } - - #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { - __aeabi_memset4(dest, n, c); - } - - #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { - __aeabi_memset(dest, n, 0); - } - - #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { - __aeabi_memset4(dest, n, 0); - } - - #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { - __aeabi_memset4(dest, n, 0); - } -} diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs deleted file mode 100644 index 8f22eb62866..00000000000 --- a/library/compiler-builtins/src/arm_linux.rs +++ /dev/null @@ -1,250 +0,0 @@ -use core::intrinsics; -use core::mem; - -// Kernel-provided user-mode helper functions: -// https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt -unsafe fn __kuser_cmpxchg(oldval: u32, newval: u32, ptr: *mut u32) -> bool { - let f: extern "C" fn(u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0usize as *const ()); - f(oldval, newval, ptr) == 0 -} -unsafe fn __kuser_memory_barrier() { - let f: extern "C" fn() = mem::transmute(0xffff0fa0usize as *const ()); - f(); -} - -// Word-align a pointer -fn align_ptr(ptr: *mut T) -> *mut u32 { - // This gives us a mask of 0 when T == u32 since the pointer is already - // supposed to be aligned, which avoids any masking in that case. - let ptr_mask = 3 & (4 - mem::size_of::()); - (ptr as usize & !ptr_mask) as *mut u32 -} - -// Calculate the shift and mask of a value inside an aligned word -fn get_shift_mask(ptr: *mut T) -> (u32, u32) { - // Mask to get the low byte/halfword/word - let mask = match mem::size_of::() { - 1 => 0xff, - 2 => 0xffff, - 4 => 0xffffffff, - _ => unreachable!(), - }; - - // If we are on big-endian then we need to adjust the shift accordingly - let endian_adjust = if cfg!(target_endian = "little") { - 0 - } else { - 4 - mem::size_of::() as u32 - }; - - // Shift to get the desired element in the word - let ptr_mask = 3 & (4 - mem::size_of::()); - let shift = ((ptr as usize & ptr_mask) as u32 ^ endian_adjust) * 8; - - (shift, mask) -} - -// Extract a value from an aligned word -fn extract_aligned(aligned: u32, shift: u32, mask: u32) -> u32 { - (aligned >> shift) & mask -} - -// Insert a value into an aligned word -fn insert_aligned(aligned: u32, val: u32, shift: u32, mask: u32) -> u32 { - (aligned & !(mask << shift)) | ((val & mask) << shift) -} - -// Generic atomic read-modify-write operation -unsafe fn atomic_rmw u32, G: Fn(u32, u32) -> u32>(ptr: *mut T, f: F, g: G) -> u32 { - let aligned_ptr = align_ptr(ptr); - let (shift, mask) = get_shift_mask(ptr); - - loop { - let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr); - let curval = extract_aligned(curval_aligned, shift, mask); - let newval = f(curval); - let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask); - if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) { - return g(curval, newval); - } - } -} - -// Generic atomic compare-exchange operation -unsafe fn atomic_cmpxchg(ptr: *mut T, oldval: u32, newval: u32) -> u32 { - let aligned_ptr = align_ptr(ptr); - let (shift, mask) = get_shift_mask(ptr); - - loop { - let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr); - let curval = extract_aligned(curval_aligned, shift, mask); - if curval != oldval { - return curval; - } - let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask); - if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) { - return oldval; - } - } -} - -macro_rules! atomic_rmw { - ($name:ident, $ty:ty, $op:expr, $fetch:expr) => { - intrinsics! { - pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty { - atomic_rmw(ptr, |x| $op(x as $ty, val) as u32, |old, new| $fetch(old, new)) as $ty - } - } - }; - - (@old $name:ident, $ty:ty, $op:expr) => { - atomic_rmw!($name, $ty, $op, |old, _| old); - }; - - (@new $name:ident, $ty:ty, $op:expr) => { - atomic_rmw!($name, $ty, $op, |_, new| new); - }; -} -macro_rules! atomic_cmpxchg { - ($name:ident, $ty:ty) => { - intrinsics! { - pub unsafe extern "C" fn $name(ptr: *mut $ty, oldval: $ty, newval: $ty) -> $ty { - atomic_cmpxchg(ptr, oldval as u32, newval as u32) as $ty - } - } - }; -} - -atomic_rmw!(@old __sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b)); -atomic_rmw!(@old __sync_fetch_and_add_2, u16, |a: u16, b: u16| a - .wrapping_add(b)); -atomic_rmw!(@old __sync_fetch_and_add_4, u32, |a: u32, b: u32| a - .wrapping_add(b)); - -atomic_rmw!(@new __sync_add_and_fetch_1, u8, |a: u8, b: u8| a.wrapping_add(b)); -atomic_rmw!(@new __sync_add_and_fetch_2, u16, |a: u16, b: u16| a - .wrapping_add(b)); -atomic_rmw!(@new __sync_add_and_fetch_4, u32, |a: u32, b: u32| a - .wrapping_add(b)); - -atomic_rmw!(@old __sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); -atomic_rmw!(@old __sync_fetch_and_sub_2, u16, |a: u16, b: u16| a - .wrapping_sub(b)); -atomic_rmw!(@old __sync_fetch_and_sub_4, u32, |a: u32, b: u32| a - .wrapping_sub(b)); - -atomic_rmw!(@new __sync_sub_and_fetch_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); -atomic_rmw!(@new __sync_sub_and_fetch_2, u16, |a: u16, b: u16| a - .wrapping_sub(b)); -atomic_rmw!(@new __sync_sub_and_fetch_4, u32, |a: u32, b: u32| a - .wrapping_sub(b)); - -atomic_rmw!(@old __sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b); -atomic_rmw!(@old __sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b); -atomic_rmw!(@old __sync_fetch_and_and_4, u32, |a: u32, b: u32| a & b); - -atomic_rmw!(@new __sync_and_and_fetch_1, u8, |a: u8, b: u8| a & b); -atomic_rmw!(@new __sync_and_and_fetch_2, u16, |a: u16, b: u16| a & b); -atomic_rmw!(@new __sync_and_and_fetch_4, u32, |a: u32, b: u32| a & b); - -atomic_rmw!(@old __sync_fetch_and_or_1, u8, |a: u8, b: u8| a | b); -atomic_rmw!(@old __sync_fetch_and_or_2, u16, |a: u16, b: u16| a | b); -atomic_rmw!(@old __sync_fetch_and_or_4, u32, |a: u32, b: u32| a | b); - -atomic_rmw!(@new __sync_or_and_fetch_1, u8, |a: u8, b: u8| a | b); -atomic_rmw!(@new __sync_or_and_fetch_2, u16, |a: u16, b: u16| a | b); -atomic_rmw!(@new __sync_or_and_fetch_4, u32, |a: u32, b: u32| a | b); - -atomic_rmw!(@old __sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b); -atomic_rmw!(@old __sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b); -atomic_rmw!(@old __sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b); - -atomic_rmw!(@new __sync_xor_and_fetch_1, u8, |a: u8, b: u8| a ^ b); -atomic_rmw!(@new __sync_xor_and_fetch_2, u16, |a: u16, b: u16| a ^ b); -atomic_rmw!(@new __sync_xor_and_fetch_4, u32, |a: u32, b: u32| a ^ b); - -atomic_rmw!(@old __sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b)); -atomic_rmw!(@old __sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b)); -atomic_rmw!(@old __sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b)); - -atomic_rmw!(@new __sync_nand_and_fetch_1, u8, |a: u8, b: u8| !(a & b)); -atomic_rmw!(@new __sync_nand_and_fetch_2, u16, |a: u16, b: u16| !(a & b)); -atomic_rmw!(@new __sync_nand_and_fetch_4, u32, |a: u32, b: u32| !(a & b)); - -atomic_rmw!(@old __sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { - a -} else { - b -}); -atomic_rmw!(@old __sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { - a -} else { - b -}); -atomic_rmw!(@old __sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { - a -} else { - b -}); - -atomic_rmw!(@old __sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { - a -} else { - b -}); -atomic_rmw!(@old __sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { - a -} else { - b -}); -atomic_rmw!(@old __sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { - a -} else { - b -}); - -atomic_rmw!(@old __sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { - a -} else { - b -}); -atomic_rmw!(@old __sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { - a -} else { - b -}); -atomic_rmw!(@old __sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { - a -} else { - b -}); - -atomic_rmw!(@old __sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { - a -} else { - b -}); -atomic_rmw!(@old __sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { - a -} else { - b -}); -atomic_rmw!(@old __sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { - a -} else { - b -}); - -atomic_rmw!(@old __sync_lock_test_and_set_1, u8, |_: u8, b: u8| b); -atomic_rmw!(@old __sync_lock_test_and_set_2, u16, |_: u16, b: u16| b); -atomic_rmw!(@old __sync_lock_test_and_set_4, u32, |_: u32, b: u32| b); - -atomic_cmpxchg!(__sync_val_compare_and_swap_1, u8); -atomic_cmpxchg!(__sync_val_compare_and_swap_2, u16); -atomic_cmpxchg!(__sync_val_compare_and_swap_4, u32); - -intrinsics! { - pub unsafe extern "C" fn __sync_synchronize() { - __kuser_memory_barrier(); - } -} diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs deleted file mode 100644 index ef04ddc165c..00000000000 --- a/library/compiler-builtins/src/float/add.rs +++ /dev/null @@ -1,211 +0,0 @@ -use crate::float::Float; -use crate::int::{CastInto, Int, MinInt}; - -/// Returns `a + b` -fn add(a: F, b: F) -> F -where - u32: CastInto, - F::Int: CastInto, - i32: CastInto, - F::Int: CastInto, -{ - let one = F::Int::ONE; - let zero = F::Int::ZERO; - - let bits = F::BITS.cast(); - let significand_bits = F::SIG_BITS; - let max_exponent = F::EXP_SAT; - - let implicit_bit = F::IMPLICIT_BIT; - let significand_mask = F::SIG_MASK; - let sign_bit = F::SIGN_MASK as F::Int; - let abs_mask = sign_bit - one; - let exponent_mask = F::EXP_MASK; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; - - let mut a_rep = a.to_bits(); - let mut b_rep = b.to_bits(); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; - - // Detect if a or b is zero, infinity, or NaN. - if a_abs.wrapping_sub(one) >= inf_rep - one || b_abs.wrapping_sub(one) >= inf_rep - one { - // NaN + anything = qNaN - if a_abs > inf_rep { - return F::from_bits(a_abs | quiet_bit); - } - // anything + NaN = qNaN - if b_abs > inf_rep { - return F::from_bits(b_abs | quiet_bit); - } - - if a_abs == inf_rep { - // +/-infinity + -/+infinity = qNaN - if (a.to_bits() ^ b.to_bits()) == sign_bit { - return F::from_bits(qnan_rep); - } else { - // +/-infinity + anything remaining = +/- infinity - return a; - } - } - - // anything remaining + +/-infinity = +/-infinity - if b_abs == inf_rep { - return b; - } - - // zero + anything = anything - if a_abs == MinInt::ZERO { - // but we need to get the sign right for zero + zero - if b_abs == MinInt::ZERO { - return F::from_bits(a.to_bits() & b.to_bits()); - } else { - return b; - } - } - - // anything + zero = anything - if b_abs == MinInt::ZERO { - return a; - } - } - - // Swap a and b if necessary so that a has the larger absolute value. - if b_abs > a_abs { - // Don't use mem::swap because it may generate references to memcpy in unoptimized code. - let tmp = a_rep; - a_rep = b_rep; - b_rep = tmp; - } - - // Extract the exponent and significand from the (possibly swapped) a and b. - let mut a_exponent: i32 = ((a_rep & exponent_mask) >> significand_bits).cast(); - let mut b_exponent: i32 = ((b_rep & exponent_mask) >> significand_bits).cast(); - let mut a_significand = a_rep & significand_mask; - let mut b_significand = b_rep & significand_mask; - - // normalize any denormals, and adjust the exponent accordingly. - if a_exponent == 0 { - let (exponent, significand) = F::normalize(a_significand); - a_exponent = exponent; - a_significand = significand; - } - if b_exponent == 0 { - let (exponent, significand) = F::normalize(b_significand); - b_exponent = exponent; - b_significand = significand; - } - - // The sign of the result is the sign of the larger operand, a. If they - // have opposite signs, we are performing a subtraction; otherwise addition. - let result_sign = a_rep & sign_bit; - let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero; - - // Shift the significands to give us round, guard and sticky, and or in the - // implicit significand bit. (If we fell through from the denormal path it - // was already set by normalize(), but setting it twice won't hurt - // anything.) - a_significand = (a_significand | implicit_bit) << 3; - b_significand = (b_significand | implicit_bit) << 3; - - // Shift the significand of b by the difference in exponents, with a sticky - // bottom bit to get rounding correct. - let align = a_exponent.wrapping_sub(b_exponent).cast(); - if align != MinInt::ZERO { - if align < bits { - let sticky = - F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != MinInt::ZERO); - b_significand = (b_significand >> align.cast()) | sticky; - } else { - b_significand = one; // sticky; b is known to be non-zero. - } - } - if subtraction { - a_significand = a_significand.wrapping_sub(b_significand); - // If a == -b, return +zero. - if a_significand == MinInt::ZERO { - return F::from_bits(MinInt::ZERO); - } - - // If partial cancellation occured, we need to left-shift the result - // and adjust the exponent: - if a_significand < implicit_bit << 3 { - let shift = - a_significand.leading_zeros() as i32 - (implicit_bit << 3).leading_zeros() as i32; - a_significand <<= shift; - a_exponent -= shift; - } - } else { - // addition - a_significand += b_significand; - - // If the addition carried up, we need to right-shift the result and - // adjust the exponent: - if a_significand & (implicit_bit << 4) != MinInt::ZERO { - let sticky = F::Int::from_bool(a_significand & one != MinInt::ZERO); - a_significand = (a_significand >> 1) | sticky; - a_exponent += 1; - } - } - - // If we have overflowed the type, return +/- infinity: - if a_exponent >= max_exponent as i32 { - return F::from_bits(inf_rep | result_sign); - } - - if a_exponent <= 0 { - // Result is denormal before rounding; the exponent is zero and we - // need to shift the significand. - let shift = (1 - a_exponent).cast(); - let sticky = - F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != MinInt::ZERO); - a_significand = (a_significand >> shift.cast()) | sticky; - a_exponent = 0; - } - - // Low three bits are round, guard, and sticky. - let a_significand_i32: i32 = a_significand.cast(); - let round_guard_sticky: i32 = a_significand_i32 & 0x7; - - // Shift the significand into place, and mask off the implicit bit. - let mut result = (a_significand >> 3) & significand_mask; - - // Insert the exponent and sign. - result |= a_exponent.cast() << significand_bits; - result |= result_sign; - - // Final rounding. The result may overflow to infinity, but that is the - // correct result in that case. - if round_guard_sticky > 0x4 { - result += one; - } - if round_guard_sticky == 0x4 { - result += result & one; - } - - F::from_bits(result) -} - -intrinsics! { - #[avr_skip] - #[aapcs_on_arm] - #[arm_aeabi_alias = __aeabi_fadd] - pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 { - add(a, b) - } - - #[avr_skip] - #[aapcs_on_arm] - #[arm_aeabi_alias = __aeabi_dadd] - pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 { - add(a, b) - } - - #[ppc_alias = __addkf3] - #[cfg(f128_enabled)] - pub extern "C" fn __addtf3(a: f128, b: f128) -> f128 { - add(a, b) - } -} diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs deleted file mode 100644 index b9b4d0114b7..00000000000 --- a/library/compiler-builtins/src/float/cmp.rs +++ /dev/null @@ -1,261 +0,0 @@ -#![allow(unreachable_code)] - -use crate::float::Float; -use crate::int::MinInt; - -#[derive(Clone, Copy)] -enum Result { - Less, - Equal, - Greater, - Unordered, -} - -impl Result { - fn to_le_abi(self) -> i32 { - match self { - Result::Less => -1, - Result::Equal => 0, - Result::Greater => 1, - Result::Unordered => 1, - } - } - - fn to_ge_abi(self) -> i32 { - match self { - Result::Less => -1, - Result::Equal => 0, - Result::Greater => 1, - Result::Unordered => -1, - } - } -} - -fn cmp(a: F, b: F) -> Result { - let one = F::Int::ONE; - let zero = F::Int::ZERO; - let szero = F::SignedInt::ZERO; - - let sign_bit = F::SIGN_MASK as F::Int; - let abs_mask = sign_bit - one; - let exponent_mask = F::EXP_MASK; - let inf_rep = exponent_mask; - - let a_rep = a.to_bits(); - let b_rep = b.to_bits(); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; - - // If either a or b is NaN, they are unordered. - if a_abs > inf_rep || b_abs > inf_rep { - return Result::Unordered; - } - - // If a and b are both zeros, they are equal. - if a_abs | b_abs == zero { - return Result::Equal; - } - - let a_srep = a.to_bits_signed(); - let b_srep = b.to_bits_signed(); - - // If at least one of a and b is positive, we get the same result comparing - // a and b as signed integers as we would with a fp_ting-point compare. - if a_srep & b_srep >= szero { - if a_srep < b_srep { - Result::Less - } else if a_srep == b_srep { - Result::Equal - } else { - Result::Greater - } - // Otherwise, both are negative, so we need to flip the sense of the - // comparison to get the correct result. (This assumes a twos- or ones- - // complement integer representation; if integers are represented in a - // sign-magnitude representation, then this flip is incorrect). - } else if a_srep > b_srep { - Result::Less - } else if a_srep == b_srep { - Result::Equal - } else { - Result::Greater - } -} - -fn unord(a: F, b: F) -> bool { - let one = F::Int::ONE; - - let sign_bit = F::SIGN_MASK as F::Int; - let abs_mask = sign_bit - one; - let exponent_mask = F::EXP_MASK; - let inf_rep = exponent_mask; - - let a_rep = a.to_bits(); - let b_rep = b.to_bits(); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; - - a_abs > inf_rep || b_abs > inf_rep -} - -intrinsics! { - #[avr_skip] - pub extern "C" fn __lesf2(a: f32, b: f32) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __gesf2(a: f32, b: f32) -> i32 { - cmp(a, b).to_ge_abi() - } - - #[avr_skip] - #[arm_aeabi_alias = __aeabi_fcmpun] - pub extern "C" fn __unordsf2(a: f32, b: f32) -> i32 { - unord(a, b) as i32 - } - - #[avr_skip] - pub extern "C" fn __eqsf2(a: f32, b: f32) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __ltsf2(a: f32, b: f32) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __nesf2(a: f32, b: f32) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __gtsf2(a: f32, b: f32) -> i32 { - cmp(a, b).to_ge_abi() - } - - #[avr_skip] - pub extern "C" fn __ledf2(a: f64, b: f64) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __gedf2(a: f64, b: f64) -> i32 { - cmp(a, b).to_ge_abi() - } - - #[avr_skip] - #[arm_aeabi_alias = __aeabi_dcmpun] - pub extern "C" fn __unorddf2(a: f64, b: f64) -> i32 { - unord(a, b) as i32 - } - - #[avr_skip] - pub extern "C" fn __eqdf2(a: f64, b: f64) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __ltdf2(a: f64, b: f64) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __nedf2(a: f64, b: f64) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __gtdf2(a: f64, b: f64) -> i32 { - cmp(a, b).to_ge_abi() - } -} - -#[cfg(f128_enabled)] -intrinsics! { - #[avr_skip] - #[ppc_alias = __lekf2] - pub extern "C" fn __letf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - #[ppc_alias = __gekf2] - pub extern "C" fn __getf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_ge_abi() - } - - #[avr_skip] - #[ppc_alias = __unordkf2] - pub extern "C" fn __unordtf2(a: f128, b: f128) -> i32 { - unord(a, b) as i32 - } - - #[avr_skip] - #[ppc_alias = __eqkf2] - pub extern "C" fn __eqtf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - #[ppc_alias = __ltkf2] - pub extern "C" fn __lttf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - #[ppc_alias = __nekf2] - pub extern "C" fn __netf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - #[ppc_alias = __gtkf2] - pub extern "C" fn __gttf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_ge_abi() - } -} - -#[cfg(target_arch = "arm")] -intrinsics! { - pub extern "aapcs" fn __aeabi_fcmple(a: f32, b: f32) -> i32 { - (__lesf2(a, b) <= 0) as i32 - } - - pub extern "aapcs" fn __aeabi_fcmpge(a: f32, b: f32) -> i32 { - (__gesf2(a, b) >= 0) as i32 - } - - pub extern "aapcs" fn __aeabi_fcmpeq(a: f32, b: f32) -> i32 { - (__eqsf2(a, b) == 0) as i32 - } - - pub extern "aapcs" fn __aeabi_fcmplt(a: f32, b: f32) -> i32 { - (__ltsf2(a, b) < 0) as i32 - } - - pub extern "aapcs" fn __aeabi_fcmpgt(a: f32, b: f32) -> i32 { - (__gtsf2(a, b) > 0) as i32 - } - - pub extern "aapcs" fn __aeabi_dcmple(a: f64, b: f64) -> i32 { - (__ledf2(a, b) <= 0) as i32 - } - - pub extern "aapcs" fn __aeabi_dcmpge(a: f64, b: f64) -> i32 { - (__gedf2(a, b) >= 0) as i32 - } - - pub extern "aapcs" fn __aeabi_dcmpeq(a: f64, b: f64) -> i32 { - (__eqdf2(a, b) == 0) as i32 - } - - pub extern "aapcs" fn __aeabi_dcmplt(a: f64, b: f64) -> i32 { - (__ltdf2(a, b) < 0) as i32 - } - - pub extern "aapcs" fn __aeabi_dcmpgt(a: f64, b: f64) -> i32 { - (__gtdf2(a, b) > 0) as i32 - } -} diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs deleted file mode 100644 index 42a526bd524..00000000000 --- a/library/compiler-builtins/src/float/conv.rs +++ /dev/null @@ -1,490 +0,0 @@ -use core::ops::Neg; - -use crate::int::{CastFrom, CastInto, Int, MinInt}; - -use super::Float; - -/// Conversions from integers to floats. -/// -/// The algorithm is explained here: . It roughly does the following: -/// - Calculate a base mantissa by shifting the integer into mantissa position. This gives us a -/// mantissa _with the implicit bit set_! -/// - Figure out if rounding needs to occur by classifying the bits that are to be truncated. Some -/// patterns are used to simplify this. Adjust the mantissa with the result if needed. -/// - Calculate the exponent based on the base-2 logarithm of `i` (leading zeros). Subtract one. -/// - Shift the exponent and add the mantissa to create the final representation. Subtracting one -/// from the exponent (above) accounts for the explicit bit being set in the mantissa. -/// -/// # Terminology -/// -/// - `i`: the original integer -/// - `i_m`: the integer, shifted fully left (no leading zeros) -/// - `n`: number of leading zeroes -/// - `e`: the resulting exponent. Usually 1 is subtracted to offset the mantissa implicit bit. -/// - `m_base`: the mantissa before adjusting for truncated bits. Implicit bit is usually set. -/// - `adj`: the bits that will be truncated, possibly compressed in some way. -/// - `m`: the resulting mantissa. Implicit bit is usually set. -mod int_to_float { - use super::*; - - /// Calculate the exponent from the number of leading zeros. - /// - /// Usually 1 is subtracted from this function's result, so that a mantissa with the implicit - /// bit set can be added back later. - fn exp>>(n: u32) -> F::Int { - F::Int::cast_from(F::EXP_BIAS - 1 + I::BITS - n) - } - - /// Adjust a mantissa with dropped bits to perform correct rounding. - /// - /// The dropped bits should be exactly the bits that get truncated (left-aligned), but they - /// can be combined or compressed in some way that simplifies operations. - fn m_adj(m_base: F::Int, dropped_bits: F::Int) -> F::Int { - // Branchlessly extract a `1` if rounding up should happen, 0 otherwise - // This accounts for rounding to even. - let adj = (dropped_bits - ((dropped_bits >> (F::BITS - 1)) & !m_base)) >> (F::BITS - 1); - - // Add one when we need to round up. Break ties to even. - m_base + adj - } - - /// Shift the exponent to its position and add the mantissa. - /// - /// If the mantissa has the implicit bit set, the exponent should be one less than its actual - /// value to cancel it out. - fn repr(e: F::Int, m: F::Int) -> F::Int { - // + rather than | so the mantissa can overflow into the exponent - (e << F::SIG_BITS) + m - } - - /// Shift distance from a left-aligned integer to a smaller float. - fn shift_f_lt_i() -> u32 { - (I::BITS - F::BITS) + F::EXP_BITS - } - - /// Shift distance from an integer with `n` leading zeros to a smaller float. - fn shift_f_gt_i(n: u32) -> u32 { - F::SIG_BITS - I::BITS + 1 + n - } - - /// Perform a signed operation as unsigned, then add the sign back. - pub fn signed(i: I, conv: Conv) -> F - where - F: Float, - I: Int, - F::Int: CastFrom, - Conv: Fn(I::UnsignedInt) -> F::Int, - { - let sign_bit = F::Int::cast_from(i >> (I::BITS - 1)) << (F::BITS - 1); - F::from_bits(conv(i.unsigned_abs()) | sign_bit) - } - - pub fn u32_to_f32_bits(i: u32) -> u32 { - if i == 0 { - return 0; - } - let n = i.leading_zeros(); - // Mantissa with implicit bit set (significant bits) - let m_base = (i << n) >> f32::EXP_BITS; - // Bits that will be dropped (insignificant bits) - let adj = (i << n) << (f32::SIG_BITS + 1); - let m = m_adj::(m_base, adj); - let e = exp::(n) - 1; - repr::(e, m) - } - - pub fn u32_to_f64_bits(i: u32) -> u64 { - if i == 0 { - return 0; - } - let n = i.leading_zeros(); - // Mantissa with implicit bit set - let m = (i as u64) << shift_f_gt_i::(n); - let e = exp::(n) - 1; - repr::(e, m) - } - - #[cfg(f128_enabled)] - pub fn u32_to_f128_bits(i: u32) -> u128 { - if i == 0 { - return 0; - } - let n = i.leading_zeros(); - - // Shift into mantissa position that is correct for the type, but shifted into the lower - // 64 bits over so can can avoid 128-bit math. - let m = (i as u64) << (shift_f_gt_i::(n) - 64); - let e = exp::(n) as u64 - 1; - // High 64 bits of f128 representation. - let h = (e << (f128::SIG_BITS - 64)) + m; - - // Shift back to the high bits, the rest of the mantissa will always be 0. - (h as u128) << 64 - } - - pub fn u64_to_f32_bits(i: u64) -> u32 { - let n = i.leading_zeros(); - let i_m = i.wrapping_shl(n); - // Mantissa with implicit bit set - let m_base: u32 = (i_m >> shift_f_lt_i::()) as u32; - // The entire lower half of `i` will be truncated (masked portion), plus the - // next `EXP_BITS` bits. - let adj = ((i_m >> f32::EXP_BITS) | i_m & 0xFFFF) as u32; - let m = m_adj::(m_base, adj); - let e = if i == 0 { 0 } else { exp::(n) - 1 }; - repr::(e, m) - } - - pub fn u64_to_f64_bits(i: u64) -> u64 { - if i == 0 { - return 0; - } - let n = i.leading_zeros(); - // Mantissa with implicit bit set - let m_base = (i << n) >> f64::EXP_BITS; - let adj = (i << n) << (f64::SIG_BITS + 1); - let m = m_adj::(m_base, adj); - let e = exp::(n) - 1; - repr::(e, m) - } - - #[cfg(f128_enabled)] - pub fn u64_to_f128_bits(i: u64) -> u128 { - if i == 0 { - return 0; - } - let n = i.leading_zeros(); - // Mantissa with implicit bit set - let m = (i as u128) << shift_f_gt_i::(n); - let e = exp::(n) - 1; - repr::(e, m) - } - - pub fn u128_to_f32_bits(i: u128) -> u32 { - let n = i.leading_zeros(); - let i_m = i.wrapping_shl(n); // Mantissa, shifted so the first bit is nonzero - let m_base: u32 = (i_m >> shift_f_lt_i::()) as u32; - - // Within the upper `F::BITS`, everything except for the signifcand - // gets truncated - let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIG_BITS - 1)).cast(); - - // The entire rest of `i_m` gets truncated. Zero the upper `F::BITS` then just - // check if it is nonzero. - let d2: u32 = (i_m << f32::BITS >> f32::BITS != 0).into(); - let adj = d1 | d2; - - // Mantissa with implicit bit set - let m = m_adj::(m_base, adj); - let e = if i == 0 { 0 } else { exp::(n) - 1 }; - repr::(e, m) - } - - pub fn u128_to_f64_bits(i: u128) -> u64 { - let n = i.leading_zeros(); - let i_m = i.wrapping_shl(n); - // Mantissa with implicit bit set - let m_base: u64 = (i_m >> shift_f_lt_i::()) as u64; - // The entire lower half of `i` will be truncated (masked portion), plus the - // next `EXP_BITS` bits. - let adj = ((i_m >> f64::EXP_BITS) | i_m & 0xFFFF_FFFF) as u64; - let m = m_adj::(m_base, adj); - let e = if i == 0 { 0 } else { exp::(n) - 1 }; - repr::(e, m) - } - - #[cfg(f128_enabled)] - pub fn u128_to_f128_bits(i: u128) -> u128 { - if i == 0 { - return 0; - } - let n = i.leading_zeros(); - // Mantissa with implicit bit set - let m_base = (i << n) >> f128::EXP_BITS; - let adj = (i << n) << (f128::SIG_BITS + 1); - let m = m_adj::(m_base, adj); - let e = exp::(n) - 1; - repr::(e, m) - } -} - -// Conversions from unsigned integers to floats. -intrinsics! { - #[arm_aeabi_alias = __aeabi_ui2f] - pub extern "C" fn __floatunsisf(i: u32) -> f32 { - f32::from_bits(int_to_float::u32_to_f32_bits(i)) - } - - #[arm_aeabi_alias = __aeabi_ui2d] - pub extern "C" fn __floatunsidf(i: u32) -> f64 { - f64::from_bits(int_to_float::u32_to_f64_bits(i)) - } - - #[arm_aeabi_alias = __aeabi_ul2f] - pub extern "C" fn __floatundisf(i: u64) -> f32 { - f32::from_bits(int_to_float::u64_to_f32_bits(i)) - } - - #[arm_aeabi_alias = __aeabi_ul2d] - pub extern "C" fn __floatundidf(i: u64) -> f64 { - f64::from_bits(int_to_float::u64_to_f64_bits(i)) - } - - #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] - pub extern "C" fn __floatuntisf(i: u128) -> f32 { - f32::from_bits(int_to_float::u128_to_f32_bits(i)) - } - - #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] - pub extern "C" fn __floatuntidf(i: u128) -> f64 { - f64::from_bits(int_to_float::u128_to_f64_bits(i)) - } - - #[ppc_alias = __floatunsikf] - #[cfg(f128_enabled)] - pub extern "C" fn __floatunsitf(i: u32) -> f128 { - f128::from_bits(int_to_float::u32_to_f128_bits(i)) - } - - #[ppc_alias = __floatundikf] - #[cfg(f128_enabled)] - pub extern "C" fn __floatunditf(i: u64) -> f128 { - f128::from_bits(int_to_float::u64_to_f128_bits(i)) - } - - #[ppc_alias = __floatuntikf] - #[cfg(f128_enabled)] - pub extern "C" fn __floatuntitf(i: u128) -> f128 { - f128::from_bits(int_to_float::u128_to_f128_bits(i)) - } -} - -// Conversions from signed integers to floats. -intrinsics! { - #[arm_aeabi_alias = __aeabi_i2f] - pub extern "C" fn __floatsisf(i: i32) -> f32 { - int_to_float::signed(i, int_to_float::u32_to_f32_bits) - } - - #[arm_aeabi_alias = __aeabi_i2d] - pub extern "C" fn __floatsidf(i: i32) -> f64 { - int_to_float::signed(i, int_to_float::u32_to_f64_bits) - } - - #[arm_aeabi_alias = __aeabi_l2f] - pub extern "C" fn __floatdisf(i: i64) -> f32 { - int_to_float::signed(i, int_to_float::u64_to_f32_bits) - } - - #[arm_aeabi_alias = __aeabi_l2d] - pub extern "C" fn __floatdidf(i: i64) -> f64 { - int_to_float::signed(i, int_to_float::u64_to_f64_bits) - } - - #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] - pub extern "C" fn __floattisf(i: i128) -> f32 { - int_to_float::signed(i, int_to_float::u128_to_f32_bits) - } - - #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] - pub extern "C" fn __floattidf(i: i128) -> f64 { - int_to_float::signed(i, int_to_float::u128_to_f64_bits) - } - - #[ppc_alias = __floatsikf] - #[cfg(f128_enabled)] - pub extern "C" fn __floatsitf(i: i32) -> f128 { - int_to_float::signed(i, int_to_float::u32_to_f128_bits) - } - - #[ppc_alias = __floatdikf] - #[cfg(f128_enabled)] - pub extern "C" fn __floatditf(i: i64) -> f128 { - int_to_float::signed(i, int_to_float::u64_to_f128_bits) - } - - #[ppc_alias = __floattikf] - #[cfg(f128_enabled)] - pub extern "C" fn __floattitf(i: i128) -> f128 { - int_to_float::signed(i, int_to_float::u128_to_f128_bits) - } -} - -/// Generic float to unsigned int conversions. -fn float_to_unsigned_int(f: F) -> U -where - F: Float, - U: Int, - F::Int: CastInto, - F::Int: CastFrom, - F::Int: CastInto, - u32: CastFrom, -{ - float_to_int_inner::(f.to_bits(), |i: U| i, || U::MAX) -} - -/// Generic float to signed int conversions. -fn float_to_signed_int(f: F) -> I -where - F: Float, - I: Int + Neg, - I::UnsignedInt: Int, - F::Int: CastInto, - F::Int: CastFrom, - u32: CastFrom, -{ - float_to_int_inner::( - f.to_bits() & !F::SIGN_MASK, - |i: I| if f.is_sign_negative() { -i } else { i }, - || if f.is_sign_negative() { I::MIN } else { I::MAX }, - ) -} - -/// Float to int conversions, generic for both signed and unsigned. -/// -/// Parameters: -/// - `fbits`: `abg(f)` bitcasted to an integer. -/// - `map_inbounds`: apply this transformation to integers that are within range (add the sign back). -/// - `out_of_bounds`: return value when out of range for `I`. -fn float_to_int_inner( - fbits: F::Int, - map_inbounds: FnFoo, - out_of_bounds: FnOob, -) -> I -where - F: Float, - I: Int, - FnFoo: FnOnce(I) -> I, - FnOob: FnOnce() -> I, - I::UnsignedInt: Int, - F::Int: CastInto, - F::Int: CastFrom, - u32: CastFrom, -{ - let int_max_exp = F::EXP_BIAS + I::MAX.ilog2() + 1; - let foobar = F::EXP_BIAS + I::UnsignedInt::BITS - 1; - - if fbits < F::ONE.to_bits() { - // < 0 gets rounded to 0 - I::ZERO - } else if fbits < F::Int::cast_from(int_max_exp) << F::SIG_BITS { - // >= 1, < integer max - let m_base = if I::UnsignedInt::BITS >= F::Int::BITS { - I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIG_BITS - 1) - } else { - I::UnsignedInt::cast_from(fbits >> (F::SIG_BITS - I::BITS + 1)) - }; - - // Set the implicit 1-bit. - let m: I::UnsignedInt = (I::UnsignedInt::ONE << (I::BITS - 1)) | m_base; - - // Shift based on the exponent and bias. - let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIG_BITS); - - let unsigned = m >> s; - map_inbounds(I::from_unsigned(unsigned)) - } else if fbits <= F::EXP_MASK { - // >= max (incl. inf) - out_of_bounds() - } else { - I::ZERO - } -} - -// Conversions from floats to unsigned integers. -intrinsics! { - #[arm_aeabi_alias = __aeabi_f2uiz] - pub extern "C" fn __fixunssfsi(f: f32) -> u32 { - float_to_unsigned_int(f) - } - - #[arm_aeabi_alias = __aeabi_f2ulz] - pub extern "C" fn __fixunssfdi(f: f32) -> u64 { - float_to_unsigned_int(f) - } - - pub extern "C" fn __fixunssfti(f: f32) -> u128 { - float_to_unsigned_int(f) - } - - #[arm_aeabi_alias = __aeabi_d2uiz] - pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { - float_to_unsigned_int(f) - } - - #[arm_aeabi_alias = __aeabi_d2ulz] - pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { - float_to_unsigned_int(f) - } - - pub extern "C" fn __fixunsdfti(f: f64) -> u128 { - float_to_unsigned_int(f) - } - - #[ppc_alias = __fixunskfsi] - #[cfg(f128_enabled)] - pub extern "C" fn __fixunstfsi(f: f128) -> u32 { - float_to_unsigned_int(f) - } - - #[ppc_alias = __fixunskfdi] - #[cfg(f128_enabled)] - pub extern "C" fn __fixunstfdi(f: f128) -> u64 { - float_to_unsigned_int(f) - } - - #[ppc_alias = __fixunskfti] - #[cfg(f128_enabled)] - pub extern "C" fn __fixunstfti(f: f128) -> u128 { - float_to_unsigned_int(f) - } -} - -// Conversions from floats to signed integers. -intrinsics! { - #[arm_aeabi_alias = __aeabi_f2iz] - pub extern "C" fn __fixsfsi(f: f32) -> i32 { - float_to_signed_int(f) - } - - #[arm_aeabi_alias = __aeabi_f2lz] - pub extern "C" fn __fixsfdi(f: f32) -> i64 { - float_to_signed_int(f) - } - - pub extern "C" fn __fixsfti(f: f32) -> i128 { - float_to_signed_int(f) - } - - #[arm_aeabi_alias = __aeabi_d2iz] - pub extern "C" fn __fixdfsi(f: f64) -> i32 { - float_to_signed_int(f) - } - - #[arm_aeabi_alias = __aeabi_d2lz] - pub extern "C" fn __fixdfdi(f: f64) -> i64 { - float_to_signed_int(f) - } - - pub extern "C" fn __fixdfti(f: f64) -> i128 { - float_to_signed_int(f) - } - - #[ppc_alias = __fixkfsi] - #[cfg(f128_enabled)] - pub extern "C" fn __fixtfsi(f: f128) -> i32 { - float_to_signed_int(f) - } - - #[ppc_alias = __fixkfdi] - #[cfg(f128_enabled)] - pub extern "C" fn __fixtfdi(f: f128) -> i64 { - float_to_signed_int(f) - } - - #[ppc_alias = __fixkfti] - #[cfg(f128_enabled)] - pub extern "C" fn __fixtfti(f: f128) -> i128 { - float_to_signed_int(f) - } -} diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs deleted file mode 100644 index 21c757dd639..00000000000 --- a/library/compiler-builtins/src/float/div.rs +++ /dev/null @@ -1,637 +0,0 @@ -//! Floating point division routines. -//! -//! This module documentation gives an overview of the method used. More documentation is inline. -//! -//! # Relevant notation -//! -//! - `m_a`: the mantissa of `a`, in base 2 -//! - `p_a`: the exponent of `a`, in base 2. I.e. `a = m_a * 2^p_a` -//! - `uqN` (e.g. `uq1`): this refers to Q notation for fixed-point numbers. UQ1.31 is an unsigned -//! fixed-point number with 1 integral bit, and 31 decimal bits. A `uqN` variable of type `uM` -//! will have N bits of integer and M-N bits of fraction. -//! - `hw`: half width, i.e. for `f64` this will be a `u32`. -//! - `x` is the best estimate of `1/m_b` -//! -//! # Method Overview -//! -//! Division routines must solve for `a / b`, which is `res = m_a*2^p_a / m_b*2^p_b`. The basic -//! process is as follows: -//! -//! - Rearange the exponent and significand to simplify the operations: -//! `res = (m_a / m_b) * 2^{p_a - p_b}`. -//! - Check for early exits (infinity, zero, etc). -//! - If `a` or `b` are subnormal, normalize by shifting the mantissa and adjusting the exponent. -//! - Set the implicit bit so math is correct. -//! - Shift mantissa significant digits (with implicit bit) fully left such that fixed-point UQ1 -//! or UQ0 numbers can be used for mantissa math. These will have greater precision than the -//! actual mantissa, which is important for correct rounding. -//! - Calculate the reciprocal of `m_b`, `x`. -//! - Use the reciprocal to multiply rather than divide: `res = m_a * x_b * 2^{p_a - p_b}`. -//! - Reapply rounding. -//! -//! # Reciprocal calculation -//! -//! Calculating the reciprocal is the most complicated part of this process. It uses the -//! [Newton-Raphson method], which picks an initial estimation (of the reciprocal) and performs -//! a number of iterations to increase its precision. -//! -//! In general, Newton's method takes the following form: -//! -//! ```text -//! `x_n` is a guess or the result of a previous iteration. Increasing `n` converges to the -//! desired result. -//! -//! The result approaches a zero of `f(x)` by applying a correction to the previous gues. -//! -//! x_{n+1} = x_n - f(x_n) / f'(x_n) -//! ``` -//! -//! Applying this to find the reciprocal: -//! -//! ```text -//! 1 / x = b -//! -//! Rearrange so we can solve by finding a zero -//! 0 = (1 / x) - b = f(x) -//! -//! f'(x) = -x^{-2} -//! -//! x_{n+1} = 2*x_n - b*x_n^2 -//! ``` -//! -//! This is a process that can be repeated to calculate the reciprocal with enough precision to -//! achieve a correctly rounded result for the overall division operation. The maximum required -//! number of iterations is known since precision doubles with each iteration. -//! -//! # Half-width operations -//! -//! Calculating the reciprocal requires widening multiplication and performing arithmetic on the -//! results, meaning that emulated integer arithmetic on `u128` (for `f64`) and `u256` (for `f128`) -//! gets used instead of native math. -//! -//! To make this more efficient, all but the final operation can be computed using half-width -//! integers. For example, rather than computing four iterations using 128-bit integers for `f64`, -//! we can instead perform three iterations using native 64-bit integers and only one final -//! iteration using the full 128 bits. -//! -//! This works because of precision doubling. Some leeway is allowed here because the fixed-point -//! number has more bits than the final mantissa will. -//! -//! [Newton-Raphson method]: https://en.wikipedia.org/wiki/Newton%27s_method - -use super::HalfRep; -use crate::float::Float; -use crate::int::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -use core::mem::size_of; -use core::ops; - -fn div(a: F, b: F) -> F -where - F::Int: CastInto, - F::Int: From>, - F::Int: From, - F::Int: HInt + DInt, - ::D: ops::Shr::D>, - F::Int: From, - u16: CastInto, - i32: CastInto, - u32: CastInto, - u128: CastInto>, -{ - let one = F::Int::ONE; - let zero = F::Int::ZERO; - let one_hw = HalfRep::::ONE; - let zero_hw = HalfRep::::ZERO; - let hw = F::BITS / 2; - let lo_mask = F::Int::MAX >> hw; - - let significand_bits = F::SIG_BITS; - // Saturated exponent, representing infinity - let exponent_sat: F::Int = F::EXP_SAT.cast(); - - let exponent_bias = F::EXP_BIAS; - let implicit_bit = F::IMPLICIT_BIT; - let significand_mask = F::SIG_MASK; - let sign_bit = F::SIGN_MASK; - let abs_mask = sign_bit - one; - let exponent_mask = F::EXP_MASK; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; - let (mut half_iterations, full_iterations) = get_iterations::(); - let recip_precision = reciprocal_precision::(); - - if F::BITS == 128 { - // FIXME(tgross35): f128 seems to require one more half iteration than expected - half_iterations += 1; - } - - let a_rep = a.to_bits(); - let b_rep = b.to_bits(); - - // Exponent numeric representationm not accounting for bias - let a_exponent = (a_rep >> significand_bits) & exponent_sat; - let b_exponent = (b_rep >> significand_bits) & exponent_sat; - let quotient_sign = (a_rep ^ b_rep) & sign_bit; - - let mut a_significand = a_rep & significand_mask; - let mut b_significand = b_rep & significand_mask; - - // The exponent of our final result in its encoded form - let mut res_exponent: i32 = - i32::cast_from(a_exponent) - i32::cast_from(b_exponent) + (exponent_bias as i32); - - // Detect if a or b is zero, denormal, infinity, or NaN. - if a_exponent.wrapping_sub(one) >= (exponent_sat - one) - || b_exponent.wrapping_sub(one) >= (exponent_sat - one) - { - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; - - // NaN / anything = qNaN - if a_abs > inf_rep { - return F::from_bits(a_rep | quiet_bit); - } - - // anything / NaN = qNaN - if b_abs > inf_rep { - return F::from_bits(b_rep | quiet_bit); - } - - if a_abs == inf_rep { - if b_abs == inf_rep { - // infinity / infinity = NaN - return F::from_bits(qnan_rep); - } else { - // infinity / anything else = +/- infinity - return F::from_bits(a_abs | quotient_sign); - } - } - - // anything else / infinity = +/- 0 - if b_abs == inf_rep { - return F::from_bits(quotient_sign); - } - - if a_abs == zero { - if b_abs == zero { - // zero / zero = NaN - return F::from_bits(qnan_rep); - } else { - // zero / anything else = +/- zero - return F::from_bits(quotient_sign); - } - } - - // anything else / zero = +/- infinity - if b_abs == zero { - return F::from_bits(inf_rep | quotient_sign); - } - - // a is denormal. Renormalize it and set the scale to include the necessary exponent - // adjustment. - if a_abs < implicit_bit { - let (exponent, significand) = F::normalize(a_significand); - res_exponent += exponent; - a_significand = significand; - } - - // b is denormal. Renormalize it and set the scale to include the necessary exponent - // adjustment. - if b_abs < implicit_bit { - let (exponent, significand) = F::normalize(b_significand); - res_exponent -= exponent; - b_significand = significand; - } - } - - // Set the implicit significand bit. If we fell through from the - // denormal path it was already set by normalize( ), but setting it twice - // won't hurt anything. - a_significand |= implicit_bit; - b_significand |= implicit_bit; - - // Transform to a fixed-point representation by shifting the significand to the high bits. We - // know this is in the range [1.0, 2.0] since the implicit bit is set to 1 above. - let b_uq1 = b_significand << (F::BITS - significand_bits - 1); - - // Align the significand of b as a UQ1.(n-1) fixed-point number in the range - // [1.0, 2.0) and get a UQ0.n approximate reciprocal using a small minimax - // polynomial approximation: x0 = 3/4 + 1/sqrt(2) - b/2. - // The max error for this approximation is achieved at endpoints, so - // abs(x0(b) - 1/b) <= abs(x0(1) - 1/1) = 3/4 - 1/sqrt(2) = 0.04289..., - // which is about 4.5 bits. - // The initial approximation is between x0(1.0) = 0.9571... and x0(2.0) = 0.4571... - // - // Then, refine the reciprocal estimate using a quadratically converging - // Newton-Raphson iteration: - // x_{n+1} = x_n * (2 - x_n * b) - // - // Let b be the original divisor considered "in infinite precision" and - // obtained from IEEE754 representation of function argument (with the - // implicit bit set). Corresponds to rep_t-sized b_UQ1 represented in - // UQ1.(W-1). - // - // Let b_hw be an infinitely precise number obtained from the highest (HW-1) - // bits of divisor significand (with the implicit bit set). Corresponds to - // half_rep_t-sized b_UQ1_hw represented in UQ1.(HW-1) that is a **truncated** - // version of b_UQ1. - // - // Let e_n := x_n - 1/b_hw - // E_n := x_n - 1/b - // abs(E_n) <= abs(e_n) + (1/b_hw - 1/b) - // = abs(e_n) + (b - b_hw) / (b*b_hw) - // <= abs(e_n) + 2 * 2^-HW - // - // rep_t-sized iterations may be slower than the corresponding half-width - // variant depending on the handware and whether single/double/quad precision - // is selected. - // - // NB: Using half-width iterations increases computation errors due to - // rounding, so error estimations have to be computed taking the selected - // mode into account! - let mut x_uq0 = if half_iterations > 0 { - // Starting with (n-1) half-width iterations - let b_uq1_hw: HalfRep = b_uq1.hi(); - - // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW - // with W0 being either 16 or 32 and W0 <= HW. - // That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from which - // b/2 is subtracted to obtain x0) wrapped to [0, 1) range. - let c_hw = c_hw::(); - - // Check that the top bit is set, i.e. value is within `[1, 2)`. - debug_assert!(b_uq1_hw & (one_hw << (HalfRep::::BITS - 1)) > zero_hw); - - // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, - // so x0 fits to UQ0.HW without wrapping. - let mut x_uq0_hw: HalfRep = - c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); - - // An e_0 error is comprised of errors due to - // * x0 being an inherently imprecise first approximation of 1/b_hw - // * C_hw being some (irrational) number **truncated** to W0 bits - // Please note that e_0 is calculated against the infinitely precise - // reciprocal of b_hw (that is, **truncated** version of b). - // - // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0 - // - // By construction, 1 <= b < 2 - // f(x) = x * (2 - b*x) = 2*x - b*x^2 - // f'(x) = 2 * (1 - b*x) - // - // On the [0, 1] interval, f(0) = 0, - // then it increses until f(1/b) = 1 / b, maximum on (0, 1), - // then it decreses to f(1) = 2 - b - // - // Let g(x) = x - f(x) = b*x^2 - x. - // On (0, 1/b), g(x) < 0 <=> f(x) > x - // On (1/b, 1], g(x) > 0 <=> f(x) < x - // - // For half-width iterations, b_hw is used instead of b. - for _ in 0..half_iterations { - // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp - // of corr_UQ1_hw. - // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1). - // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided - // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is - // expected to be strictly positive because b_UQ1_hw has its highest bit set - // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). - // - // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally - // obtaining an UQ1.(HW-1) number and proving its highest bit could be - // considered to be 0 to be able to represent it in UQ0.HW. - // From the above analysis of f(x), if corr_UQ1_hw would be represented - // without any intermediate loss of precision (that is, in twice_rep_t) - // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly - // less otherwise. On the other hand, to obtain [1.]000..., one have to pass - // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due - // to 1.0 being not representable as UQ0.HW). - // The fact corr_UQ1_hw was virtually round up (due to result of - // multiplication being **first** truncated, then negated - to improve - // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. - // - // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t - // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after - // any number of iterations, so just subtract 2 from the reciprocal - // approximation after last iteration. - // - // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW: - // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1 - // = 1 - e_n * b_hw + 2*eps1 - // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2 - // = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2 - // = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2 - // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2 - // = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw - // \------ >0 -------/ \-- >0 ---/ - // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U) - x_uq0_hw = next_guess(x_uq0_hw, b_uq1_hw); - } - - // For initial half-width iterations, U = 2^-HW - // Let abs(e_n) <= u_n * U, - // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U) - // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2) - // - // Account for possible overflow (see above). For an overflow to occur for the - // first time, for "ideal" corr_UQ1_hw (that is, without intermediate - // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum - // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to - // be not below that value (see g(x) above), so it is safe to decrement just - // once after the final iteration. On the other hand, an effective value of - // divisor changes after this point (from b_hw to b), so adjust here. - x_uq0_hw = x_uq0_hw.wrapping_sub(one_hw); - - // Error estimations for full-precision iterations are calculated just - // as above, but with U := 2^-W and taking extra decrementing into account. - // We need at least one such iteration. - // - // Simulating operations on a twice_rep_t to perform a single final full-width - // iteration. Using ad-hoc multiplication implementations to take advantage - // of particular structure of operands. - let blo: F::Int = b_uq1 & lo_mask; - - // x_UQ0 = x_UQ0_hw * 2^HW - 1 - // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1 - // - // <--- higher half ---><--- lower half ---> - // [x_UQ0_hw * b_UQ1_hw] - // + [ x_UQ0_hw * blo ] - // - [ b_UQ1 ] - // = [ result ][.... discarded ...] - let corr_uq1: F::Int = (F::Int::from(x_uq0_hw) * F::Int::from(b_uq1_hw) - + ((F::Int::from(x_uq0_hw) * blo) >> hw)) - .wrapping_sub(one) - .wrapping_neg(); // account for *possible* carry - - let lo_corr: F::Int = corr_uq1 & lo_mask; - let hi_corr: F::Int = corr_uq1 >> hw; - - // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1 - let mut x_uq0: F::Int = ((F::Int::from(x_uq0_hw) * hi_corr) << 1) - .wrapping_add((F::Int::from(x_uq0_hw) * lo_corr) >> (hw - 1)) - // 1 to account for the highest bit of corr_UQ1 can be 1 - // 1 to account for possible carry - // Just like the case of half-width iterations but with possibility - // of overflowing by one extra Ulp of x_UQ0. - .wrapping_sub(F::Int::from(2u8)); - - x_uq0 -= one; - // ... and then traditional fixup by 2 should work - - // On error estimation: - // abs(E_{N-1}) <= (u_{N-1} + 2 /* due to conversion e_n -> E_n */) * 2^-HW - // + (2^-HW + 2^-W)) - // abs(E_{N-1}) <= (u_{N-1} + 3.01) * 2^-HW - // - // Then like for the half-width iterations: - // With 0 <= eps1, eps2 < 2^-W - // E_N = 4 * E_{N-1} * eps1 - (E_{N-1}^2 * b + 4 * eps2) + 4 * eps1 / b - // abs(E_N) <= 2^-W * [ 4 * abs(E_{N-1}) + max(2 * abs(E_{N-1})^2 * 2^W + 4, 8)) ] - // abs(E_N) <= 2^-W * [ 4 * (u_{N-1} + 3.01) * 2^-HW + max(4 + 2 * (u_{N-1} + 3.01)^2, 8) ] - x_uq0 - } else { - // C is (3/4 + 1/sqrt(2)) - 1 truncated to 64 fractional bits as UQ0.n - let c: F::Int = F::Int::from(0x7504F333u32) << (F::BITS - 32); - let mut x_uq0: F::Int = c.wrapping_sub(b_uq1); - - // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-64 - // x_uq0 - for _ in 0..full_iterations { - x_uq0 = next_guess(x_uq0, b_uq1); - } - - x_uq0 - }; - - // Finally, account for possible overflow, as explained above. - x_uq0 = x_uq0.wrapping_sub(2.cast()); - - // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W - x_uq0 -= recip_precision.cast(); - - // Now 1/b - (2*P) * 2^-W < x < 1/b - // FIXME Is x_UQ0 still >= 0.5? - - let mut quotient_uq1: F::Int = x_uq0.widen_mul(a_significand << 1).hi(); - // Now, a/b - 4*P * 2^-W < q < a/b for q= in UQ1.(SB+1+W). - - // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1), - // adjust it to be in [1.0, 2.0) as UQ1.SB. - let mut residual_lo = if quotient_uq1 < (implicit_bit << 1) { - // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB, - // effectively doubling its value as well as its error estimation. - let residual_lo = (a_significand << (significand_bits + 1)) - .wrapping_sub(quotient_uq1.wrapping_mul(b_significand)); - res_exponent -= 1; - a_significand <<= 1; - residual_lo - } else { - // Highest bit is 1 (the UQ1.(SB+1) value is in [1, 2)), convert it - // to UQ1.SB by right shifting by 1. Least significant bit is omitted. - quotient_uq1 >>= 1; - (a_significand << significand_bits).wrapping_sub(quotient_uq1.wrapping_mul(b_significand)) - }; - - // drop mutability - let quotient = quotient_uq1; - - // NB: residualLo is calculated above for the normal result case. - // It is re-computed on denormal path that is expected to be not so - // performance-sensitive. - // - // Now, q cannot be greater than a/b and can differ by at most 8*P * 2^-W + 2^-SB - // Each NextAfter() increments the floating point value by at least 2^-SB - // (more, if exponent was incremented). - // Different cases (<---> is of 2^-SB length, * = a/b that is shown as a midpoint): - // q - // | | * | | | | | - // <---> 2^t - // | | | | | * | | - // q - // To require at most one NextAfter(), an error should be less than 1.5 * 2^-SB. - // (8*P) * 2^-W + 2^-SB < 1.5 * 2^-SB - // (8*P) * 2^-W < 0.5 * 2^-SB - // P < 2^(W-4-SB) - // Generally, for at most R NextAfter() to be enough, - // P < (2*R - 1) * 2^(W-4-SB) - // For f32 (0+3): 10 < 32 (OK) - // For f32 (2+1): 32 < 74 < 32 * 3, so two NextAfter() are required - // For f64: 220 < 256 (OK) - // For f128: 4096 * 3 < 13922 < 4096 * 5 (three NextAfter() are required) - // - // If we have overflowed the exponent, return infinity - if res_exponent >= i32::cast_from(exponent_sat) { - return F::from_bits(inf_rep | quotient_sign); - } - - // Now, quotient <= the correctly-rounded result - // and may need taking NextAfter() up to 3 times (see error estimates above) - // r = a - b * q - let mut abs_result = if res_exponent > 0 { - let mut ret = quotient & significand_mask; - ret |= F::Int::from(res_exponent as u32) << significand_bits; - residual_lo <<= 1; - ret - } else { - if ((significand_bits as i32) + res_exponent) < 0 { - return F::from_bits(quotient_sign); - } - - let ret = quotient.wrapping_shr(u32::cast_from(res_exponent.wrapping_neg()) + 1); - residual_lo = a_significand - .wrapping_shl(significand_bits.wrapping_add(CastInto::::cast(res_exponent))) - .wrapping_sub(ret.wrapping_mul(b_significand) << 1); - ret - }; - - residual_lo += abs_result & one; // tie to even - // conditionally turns the below LT comparison into LTE - abs_result += u8::from(residual_lo > b_significand).into(); - - if F::BITS == 128 || (F::BITS == 32 && half_iterations > 0) { - // Do not round Infinity to NaN - abs_result += - u8::from(abs_result < inf_rep && residual_lo > (2 + 1).cast() * b_significand).into(); - } - - if F::BITS == 128 { - abs_result += - u8::from(abs_result < inf_rep && residual_lo > (4 + 1).cast() * b_significand).into(); - } - - F::from_bits(abs_result | quotient_sign) -} - -/// Calculate the number of iterations required for a float type's precision. -/// -/// This returns `(h, f)` where `h` is the number of iterations to be done using integers at half -/// the float's bit width, and `f` is the number of iterations done using integers of the float's -/// full width. This is further explained in the module documentation. -/// -/// # Requirements -/// -/// The initial estimate should have at least 8 bits of precision. If this is not true, results -/// will be inaccurate. -const fn get_iterations() -> (usize, usize) { - // Precision doubles with each iteration. Assume we start with 8 bits of precision. - let total_iterations = F::BITS.ilog2() as usize - 2; - - if 2 * size_of::() <= size_of::<*const ()>() { - // If widening multiplication will be efficient (uses word-sized integers), there is no - // reason to use half-sized iterations. - (0, total_iterations) - } else { - // Otherwise, do as many iterations as possible at half width. - (total_iterations - 1, 1) - } -} - -/// `u_n` for different precisions (with N-1 half-width iterations). -/// -/// W0 is the precision of C -/// u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW -/// -/// Estimated with bc: -/// -/// ```text -/// define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; } -/// define half2(un) { return 2.0 * un / 2.0^hw + 2.0; } -/// define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; } -/// define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; } -/// -/// | f32 (0 + 3) | f32 (2 + 1) | f64 (3 + 1) | f128 (4 + 1) -/// u_0 | < 184224974 | < 2812.1 | < 184224974 | < 791240234244348797 -/// u_1 | < 15804007 | < 242.7 | < 15804007 | < 67877681371350440 -/// u_2 | < 116308 | < 2.81 | < 116308 | < 499533100252317 -/// u_3 | < 7.31 | | < 7.31 | < 27054456580 -/// u_4 | | | | < 80.4 -/// Final (U_N) | same as u_3 | < 72 | < 218 | < 13920 -/// ```` -/// -/// Add 2 to `U_N` due to final decrement. -const fn reciprocal_precision() -> u16 { - let (half_iterations, full_iterations) = get_iterations::(); - - if full_iterations < 1 { - panic!("Must have at least one full iteration"); - } - - // FIXME(tgross35): calculate this programmatically - if F::BITS == 32 && half_iterations == 2 && full_iterations == 1 { - 74u16 - } else if F::BITS == 32 && half_iterations == 0 && full_iterations == 3 { - 10 - } else if F::BITS == 64 && half_iterations == 3 && full_iterations == 1 { - 220 - } else if F::BITS == 128 && half_iterations == 4 && full_iterations == 1 { - 13922 - } else { - panic!("Invalid number of iterations") - } -} - -/// The value of `C` adjusted to half width. -/// -/// C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW with W0 being either -/// 16 or 32 and W0 <= HW. That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from -/// which b/2 is subtracted to obtain x0) wrapped to [0, 1) range. -fn c_hw() -> HalfRep -where - F::Int: DInt, - u128: CastInto>, -{ - const C_U128: u128 = 0x7504f333f9de6108b2fb1366eaa6a542; - const { C_U128 >> (u128::BITS - >::BITS) }.cast() -} - -/// Perform one iteration at any width to approach `1/b`, given previous guess `x`. Returns -/// the next `x` as a UQ0 number. -/// -/// This is the `x_{n+1} = 2*x_n - b*x_n^2` algorithm, implemented as `x_n * (2 - b*x_n)`. It -/// uses widening multiplication to calculate the result with necessary precision. -fn next_guess(x_uq0: I, b_uq1: I) -> I -where - I: Int + HInt, - ::D: ops::Shr::D>, -{ - // `corr = 2 - b*x_n` - // - // This looks like `0 - b*x_n`. However, this works - in `UQ1`, `0.0 - x = 2.0 - x`. - let corr_uq1: I = I::ZERO.wrapping_sub(x_uq0.widen_mul(b_uq1).hi()); - - // `x_n * corr = x_n * (2 - b*x_n)` - (x_uq0.widen_mul(corr_uq1) >> (I::BITS - 1)).lo() -} - -intrinsics! { - #[avr_skip] - #[arm_aeabi_alias = __aeabi_fdiv] - pub extern "C" fn __divsf3(a: f32, b: f32) -> f32 { - div(a, b) - } - - #[avr_skip] - #[arm_aeabi_alias = __aeabi_ddiv] - pub extern "C" fn __divdf3(a: f64, b: f64) -> f64 { - div(a, b) - } - - #[avr_skip] - #[ppc_alias = __divkf3] - #[cfg(f128_enabled)] - pub extern "C" fn __divtf3(a: f128, b: f128) -> f128 { - div(a, b) - } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __divsf3vfp(a: f32, b: f32) -> f32 { - a / b - } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __divdf3vfp(a: f64, b: f64) -> f64 { - a / b - } -} diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs deleted file mode 100644 index ce00da31dc5..00000000000 --- a/library/compiler-builtins/src/float/extend.rs +++ /dev/null @@ -1,130 +0,0 @@ -use crate::float::Float; -use crate::int::{CastInto, Int, MinInt}; - -/// Generic conversion from a narrower to a wider IEEE-754 floating-point type -fn extend(a: F) -> R -where - F::Int: CastInto, - u64: CastInto, - u32: CastInto, - R::Int: CastInto, - R::Int: CastInto, - u64: CastInto, - F::Int: CastInto, -{ - let src_zero = F::Int::ZERO; - let src_one = F::Int::ONE; - let src_bits = F::BITS; - let src_sig_bits = F::SIG_BITS; - let src_exp_bias = F::EXP_BIAS; - let src_min_normal = F::IMPLICIT_BIT; - let src_infinity = F::EXP_MASK; - let src_sign_mask = F::SIGN_MASK; - let src_abs_mask = src_sign_mask - src_one; - let src_qnan = F::SIG_MASK; - let src_nan_code = src_qnan - src_one; - - let dst_bits = R::BITS; - let dst_sig_bits = R::SIG_BITS; - let dst_inf_exp = R::EXP_SAT; - let dst_exp_bias = R::EXP_BIAS; - let dst_min_normal = R::IMPLICIT_BIT; - - let sig_bits_delta = dst_sig_bits - src_sig_bits; - let exp_bias_delta = dst_exp_bias - src_exp_bias; - let a_abs = a.to_bits() & src_abs_mask; - let mut abs_result = R::Int::ZERO; - - if a_abs.wrapping_sub(src_min_normal) < src_infinity.wrapping_sub(src_min_normal) { - // a is a normal number. - // Extend to the destination type by shifting the significand and - // exponent into the proper position and rebiasing the exponent. - let abs_dst: R::Int = a_abs.cast(); - let bias_dst: R::Int = exp_bias_delta.cast(); - abs_result = abs_dst.wrapping_shl(sig_bits_delta); - abs_result += bias_dst.wrapping_shl(dst_sig_bits); - } else if a_abs >= src_infinity { - // a is NaN or infinity. - // Conjure the result by beginning with infinity, then setting the qNaN - // bit (if needed) and right-aligning the rest of the trailing NaN - // payload field. - let qnan_dst: R::Int = (a_abs & src_qnan).cast(); - let nan_code_dst: R::Int = (a_abs & src_nan_code).cast(); - let inf_exp_dst: R::Int = dst_inf_exp.cast(); - abs_result = inf_exp_dst.wrapping_shl(dst_sig_bits); - abs_result |= qnan_dst.wrapping_shl(sig_bits_delta); - abs_result |= nan_code_dst.wrapping_shl(sig_bits_delta); - } else if a_abs != src_zero { - // a is denormal. - // Renormalize the significand and clear the leading bit, then insert - // the correct adjusted exponent in the destination type. - let scale = a_abs.leading_zeros() - src_min_normal.leading_zeros(); - let abs_dst: R::Int = a_abs.cast(); - let bias_dst: R::Int = (exp_bias_delta - scale + 1).cast(); - abs_result = abs_dst.wrapping_shl(sig_bits_delta + scale); - abs_result = (abs_result ^ dst_min_normal) | (bias_dst.wrapping_shl(dst_sig_bits)); - } - - let sign_result: R::Int = (a.to_bits() & src_sign_mask).cast(); - R::from_bits(abs_result | (sign_result.wrapping_shl(dst_bits - src_bits))) -} - -intrinsics! { - #[avr_skip] - #[aapcs_on_arm] - #[arm_aeabi_alias = __aeabi_f2d] - pub extern "C" fn __extendsfdf2(a: f32) -> f64 { - extend(a) - } -} - -intrinsics! { - #[avr_skip] - #[aapcs_on_arm] - #[apple_f16_arg_abi] - #[arm_aeabi_alias = __aeabi_h2f] - #[cfg(f16_enabled)] - pub extern "C" fn __extendhfsf2(a: f16) -> f32 { - extend(a) - } - - #[avr_skip] - #[aapcs_on_arm] - #[apple_f16_arg_abi] - #[cfg(f16_enabled)] - pub extern "C" fn __gnu_h2f_ieee(a: f16) -> f32 { - extend(a) - } - - #[avr_skip] - #[aapcs_on_arm] - #[apple_f16_arg_abi] - #[cfg(f16_enabled)] - pub extern "C" fn __extendhfdf2(a: f16) -> f64 { - extend(a) - } - - #[avr_skip] - #[aapcs_on_arm] - #[ppc_alias = __extendhfkf2] - #[cfg(all(f16_enabled, f128_enabled))] - pub extern "C" fn __extendhftf2(a: f16) -> f128 { - extend(a) - } - - #[avr_skip] - #[aapcs_on_arm] - #[ppc_alias = __extendsfkf2] - #[cfg(f128_enabled)] - pub extern "C" fn __extendsftf2(a: f32) -> f128 { - extend(a) - } - - #[avr_skip] - #[aapcs_on_arm] - #[ppc_alias = __extenddfkf2] - #[cfg(f128_enabled)] - pub extern "C" fn __extenddftf2(a: f64) -> f128 { - extend(a) - } -} diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs deleted file mode 100644 index 41b308626b3..00000000000 --- a/library/compiler-builtins/src/float/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub mod add; -pub mod cmp; -pub mod conv; -pub mod div; -pub mod extend; -pub mod mul; -pub mod pow; -pub mod sub; -pub(crate) mod traits; -pub mod trunc; - -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use traits::{Float, HalfRep}; - -#[cfg(feature = "public-test-deps")] -pub use traits::{Float, HalfRep}; diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs deleted file mode 100644 index 58636cb5ebe..00000000000 --- a/library/compiler-builtins/src/float/mul.rs +++ /dev/null @@ -1,202 +0,0 @@ -use crate::float::Float; -use crate::int::{CastInto, DInt, HInt, Int, MinInt}; - -fn mul(a: F, b: F) -> F -where - u32: CastInto, - F::Int: CastInto, - i32: CastInto, - F::Int: CastInto, - F::Int: HInt, -{ - let one = F::Int::ONE; - let zero = F::Int::ZERO; - - let bits = F::BITS; - let significand_bits = F::SIG_BITS; - let max_exponent = F::EXP_SAT; - - let exponent_bias = F::EXP_BIAS; - - let implicit_bit = F::IMPLICIT_BIT; - let significand_mask = F::SIG_MASK; - let sign_bit = F::SIGN_MASK; - let abs_mask = sign_bit - one; - let exponent_mask = F::EXP_MASK; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; - let exponent_bits = F::EXP_BITS; - - let a_rep = a.to_bits(); - let b_rep = b.to_bits(); - - let a_exponent = (a_rep >> significand_bits) & max_exponent.cast(); - let b_exponent = (b_rep >> significand_bits) & max_exponent.cast(); - let product_sign = (a_rep ^ b_rep) & sign_bit; - - let mut a_significand = a_rep & significand_mask; - let mut b_significand = b_rep & significand_mask; - let mut scale = 0; - - // Detect if a or b is zero, denormal, infinity, or NaN. - if a_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() - || b_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() - { - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; - - // NaN + anything = qNaN - if a_abs > inf_rep { - return F::from_bits(a_rep | quiet_bit); - } - // anything + NaN = qNaN - if b_abs > inf_rep { - return F::from_bits(b_rep | quiet_bit); - } - - if a_abs == inf_rep { - if b_abs != zero { - // infinity * non-zero = +/- infinity - return F::from_bits(a_abs | product_sign); - } else { - // infinity * zero = NaN - return F::from_bits(qnan_rep); - } - } - - if b_abs == inf_rep { - if a_abs != zero { - // infinity * non-zero = +/- infinity - return F::from_bits(b_abs | product_sign); - } else { - // infinity * zero = NaN - return F::from_bits(qnan_rep); - } - } - - // zero * anything = +/- zero - if a_abs == zero { - return F::from_bits(product_sign); - } - - // anything * zero = +/- zero - if b_abs == zero { - return F::from_bits(product_sign); - } - - // one or both of a or b is denormal, the other (if applicable) is a - // normal number. Renormalize one or both of a and b, and set scale to - // include the necessary exponent adjustment. - if a_abs < implicit_bit { - let (exponent, significand) = F::normalize(a_significand); - scale += exponent; - a_significand = significand; - } - - if b_abs < implicit_bit { - let (exponent, significand) = F::normalize(b_significand); - scale += exponent; - b_significand = significand; - } - } - - // Or in the implicit significand bit. (If we fell through from the - // denormal path it was already set by normalize( ), but setting it twice - // won't hurt anything.) - a_significand |= implicit_bit; - b_significand |= implicit_bit; - - // Get the significand of a*b. Before multiplying the significands, shift - // one of them left to left-align it in the field. Thus, the product will - // have (exponentBits + 2) integral digits, all but two of which must be - // zero. Normalizing this result is just a conditional left-shift by one - // and bumping the exponent accordingly. - let (mut product_low, mut product_high) = a_significand - .widen_mul(b_significand << exponent_bits) - .lo_hi(); - - let a_exponent_i32: i32 = a_exponent.cast(); - let b_exponent_i32: i32 = b_exponent.cast(); - let mut product_exponent: i32 = a_exponent_i32 - .wrapping_add(b_exponent_i32) - .wrapping_add(scale) - .wrapping_sub(exponent_bias as i32); - - // Normalize the significand, adjust exponent if needed. - if (product_high & implicit_bit) != zero { - product_exponent = product_exponent.wrapping_add(1); - } else { - product_high = (product_high << 1) | (product_low >> (bits - 1)); - product_low <<= 1; - } - - // If we have overflowed the type, return +/- infinity. - if product_exponent >= max_exponent as i32 { - return F::from_bits(inf_rep | product_sign); - } - - if product_exponent <= 0 { - // Result is denormal before rounding - // - // If the result is so small that it just underflows to zero, return - // a zero of the appropriate sign. Mathematically there is no need to - // handle this case separately, but we make it a special case to - // simplify the shift logic. - let shift = one.wrapping_sub(product_exponent.cast()).cast(); - if shift >= bits { - return F::from_bits(product_sign); - } - - // Otherwise, shift the significand of the result so that the round - // bit is the high bit of `product_low`. - // Ensure one of the non-highest bits in `product_low` is set if the shifted out bit are - // not all zero so that the result is correctly rounded below. - let sticky = product_low << (bits - shift) != zero; - product_low = - (product_high << (bits - shift)) | (product_low >> shift) | (sticky as u32).cast(); - product_high >>= shift; - } else { - // Result is normal before rounding; insert the exponent. - product_high &= significand_mask; - product_high |= product_exponent.cast() << significand_bits; - } - - // Insert the sign of the result: - product_high |= product_sign; - - // Final rounding. The final result may overflow to infinity, or underflow - // to zero, but those are the correct results in those cases. We use the - // default IEEE-754 round-to-nearest, ties-to-even rounding mode. - if product_low > sign_bit { - product_high += one; - } - - if product_low == sign_bit { - product_high += product_high & one; - } - - F::from_bits(product_high) -} - -intrinsics! { - #[avr_skip] - #[aapcs_on_arm] - #[arm_aeabi_alias = __aeabi_fmul] - pub extern "C" fn __mulsf3(a: f32, b: f32) -> f32 { - mul(a, b) - } - - #[avr_skip] - #[aapcs_on_arm] - #[arm_aeabi_alias = __aeabi_dmul] - pub extern "C" fn __muldf3(a: f64, b: f64) -> f64 { - mul(a, b) - } - - #[ppc_alias = __mulkf3] - #[cfg(f128_enabled)] - pub extern "C" fn __multf3(a: f128, b: f128) -> f128 { - mul(a, b) - } -} diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs deleted file mode 100644 index dac768f7be3..00000000000 --- a/library/compiler-builtins/src/float/pow.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::float::Float; -use crate::int::Int; - -/// Returns `a` raised to the power `b` -fn pow(a: F, b: i32) -> F { - let mut a = a; - let recip = b < 0; - let mut pow = Int::abs_diff(b, 0); - let mut mul = F::ONE; - loop { - if (pow & 1) != 0 { - mul *= a; - } - pow >>= 1; - if pow == 0 { - break; - } - a *= a; - } - - if recip { - F::ONE / mul - } else { - mul - } -} - -intrinsics! { - #[avr_skip] - pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 { - pow(a, b) - } - - #[avr_skip] - pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 { - pow(a, b) - } - - #[avr_skip] - #[ppc_alias = __powikf2] - #[cfg(f128_enabled)] - // FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly. - #[cfg(not(target_env = "msvc"))] - pub extern "C" fn __powitf2(a: f128, b: i32) -> f128 { - pow(a, b) - } -} diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs deleted file mode 100644 index 175b3a16500..00000000000 --- a/library/compiler-builtins/src/float/sub.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::float::Float; - -intrinsics! { - #[avr_skip] - #[arm_aeabi_alias = __aeabi_fsub] - pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { - crate::float::add::__addsf3(a, f32::from_bits(b.to_bits() ^ f32::SIGN_MASK)) - } - - #[avr_skip] - #[arm_aeabi_alias = __aeabi_dsub] - pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { - crate::float::add::__adddf3(a, f64::from_bits(b.to_bits() ^ f64::SIGN_MASK)) - } - - #[ppc_alias = __subkf3] - #[cfg(f128_enabled)] - pub extern "C" fn __subtf3(a: f128, b: f128) -> f128 { - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - use crate::float::add::__addkf3 as __addtf3; - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - use crate::float::add::__addtf3; - - __addtf3(a, f128::from_bits(b.to_bits() ^ f128::SIGN_MASK)) - } -} diff --git a/library/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/src/float/traits.rs deleted file mode 100644 index 8ccaa7bcbd7..00000000000 --- a/library/compiler-builtins/src/float/traits.rs +++ /dev/null @@ -1,189 +0,0 @@ -use core::ops; - -use crate::int::{DInt, Int, MinInt}; - -/// Wrapper to extract the integer type half of the float's size -pub type HalfRep = <::Int as DInt>::H; - -/// Trait for some basic operations on floats -#[allow(dead_code)] -pub trait Float: - Copy - + core::fmt::Debug - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::MulAssign - + ops::Add - + ops::Sub - + ops::Div - + ops::Rem -{ - /// A uint of the same width as the float - type Int: Int; - - /// A int of the same width as the float - type SignedInt: Int + MinInt; - - /// An int capable of containing the exponent bits plus a sign bit. This is signed. - type ExpInt: Int; - - const ZERO: Self; - const ONE: Self; - - /// The bitwidth of the float type. - const BITS: u32; - - /// The bitwidth of the significand. - const SIG_BITS: u32; - - /// The bitwidth of the exponent. - const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; - - /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite - /// representation. - /// - /// This is in the rightmost position, use `EXP_MASK` for the shifted value. - const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; - - /// The exponent bias value. - const EXP_BIAS: u32 = Self::EXP_SAT >> 1; - - /// A mask for the sign bit. - const SIGN_MASK: Self::Int; - - /// A mask for the significand. - const SIG_MASK: Self::Int; - - /// The implicit bit of the float format. - const IMPLICIT_BIT: Self::Int; - - /// A mask for the exponent. - const EXP_MASK: Self::Int; - - /// Returns `self` transmuted to `Self::Int` - fn to_bits(self) -> Self::Int; - - /// Returns `self` transmuted to `Self::SignedInt` - fn to_bits_signed(self) -> Self::SignedInt; - - /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. This method returns `true` if two NaNs are - /// compared. - fn eq_repr(self, rhs: Self) -> bool; - - /// Returns true if the sign is negative - fn is_sign_negative(self) -> bool; - - /// Returns the exponent, not adjusting for bias. - fn exp(self) -> Self::ExpInt; - - /// Returns the significand with no implicit bit (or the "fractional" part) - fn frac(self) -> Self::Int; - - /// Returns the significand with implicit bit - fn imp_frac(self) -> Self::Int; - - /// Returns a `Self::Int` transmuted back to `Self` - fn from_bits(a: Self::Int) -> Self; - - /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self; - - fn abs(self) -> Self { - let abs_mask = !Self::SIGN_MASK; - Self::from_bits(self.to_bits() & abs_mask) - } - - /// Returns (normalized exponent, normalized significand) - fn normalize(significand: Self::Int) -> (i32, Self::Int); - - /// Returns if `self` is subnormal - fn is_subnormal(self) -> bool; -} - -macro_rules! float_impl { - ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { - impl Float for $ty { - type Int = $ity; - type SignedInt = $sity; - type ExpInt = $expty; - - const ZERO: Self = 0.0; - const ONE: Self = 1.0; - - const BITS: u32 = $bits; - const SIG_BITS: u32 = $significand_bits; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; - const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); - - fn to_bits(self) -> Self::Int { - self.to_bits() - } - fn to_bits_signed(self) -> Self::SignedInt { - self.to_bits() as Self::SignedInt - } - fn eq_repr(self, rhs: Self) -> bool { - #[cfg(feature = "mangled-names")] - fn is_nan(x: $ty) -> bool { - // When using mangled-names, the "real" compiler-builtins might not have the - // necessary builtin (__unordtf2) to test whether `f128` is NaN. - // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin - // x is NaN if all the bits of the exponent are set and the significand is non-0 - x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 - } - #[cfg(not(feature = "mangled-names"))] - fn is_nan(x: $ty) -> bool { - x.is_nan() - } - if is_nan(self) && is_nan(rhs) { - true - } else { - self.to_bits() == rhs.to_bits() - } - } - fn is_sign_negative(self) -> bool { - self.is_sign_negative() - } - fn exp(self) -> Self::ExpInt { - ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt - } - fn frac(self) -> Self::Int { - self.to_bits() & Self::SIG_MASK - } - fn imp_frac(self) -> Self::Int { - self.frac() | Self::IMPLICIT_BIT - } - fn from_bits(a: Self::Int) -> Self { - Self::from_bits(a) - } - fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_bits( - ((negative as Self::Int) << (Self::BITS - 1)) - | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) - | (significand & Self::SIG_MASK), - ) - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); - ( - 1i32.wrapping_sub(shift as i32), - significand << shift as Self::Int, - ) - } - fn is_subnormal(self) -> bool { - (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO - } - } - }; -} - -#[cfg(f16_enabled)] -float_impl!(f16, u16, i16, i8, 16, 10); -float_impl!(f32, u32, i32, i16, 32, 23); -float_impl!(f64, u64, i64, i16, 64, 52); -#[cfg(f128_enabled)] -float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs deleted file mode 100644 index 928eba0c8ef..00000000000 --- a/library/compiler-builtins/src/float/trunc.rs +++ /dev/null @@ -1,176 +0,0 @@ -use crate::float::Float; -use crate::int::{CastInto, Int, MinInt}; - -fn trunc(a: F) -> R -where - F::Int: CastInto, - F::Int: CastInto, - u64: CastInto, - u32: CastInto, - R::Int: CastInto, - u32: CastInto, - F::Int: CastInto, -{ - let src_zero = F::Int::ZERO; - let src_one = F::Int::ONE; - let src_bits = F::BITS; - let src_exp_bias = F::EXP_BIAS; - - let src_min_normal = F::IMPLICIT_BIT; - let src_sig_mask = F::SIG_MASK; - let src_infinity = F::EXP_MASK; - let src_sign_mask = F::SIGN_MASK; - let src_abs_mask = src_sign_mask - src_one; - let round_mask = (src_one << (F::SIG_BITS - R::SIG_BITS)) - src_one; - let halfway = src_one << (F::SIG_BITS - R::SIG_BITS - 1); - let src_qnan = src_one << (F::SIG_BITS - 1); - let src_nan_code = src_qnan - src_one; - - let dst_zero = R::Int::ZERO; - let dst_one = R::Int::ONE; - let dst_bits = R::BITS; - let dst_inf_exp = R::EXP_SAT; - let dst_exp_bias = R::EXP_BIAS; - - let underflow_exponent: F::Int = (src_exp_bias + 1 - dst_exp_bias).cast(); - let overflow_exponent: F::Int = (src_exp_bias + dst_inf_exp - dst_exp_bias).cast(); - let underflow: F::Int = underflow_exponent << F::SIG_BITS; - let overflow: F::Int = overflow_exponent << F::SIG_BITS; - - let dst_qnan = R::Int::ONE << (R::SIG_BITS - 1); - let dst_nan_code = dst_qnan - dst_one; - - let sig_bits_delta = F::SIG_BITS - R::SIG_BITS; - // Break a into a sign and representation of the absolute value. - let a_abs = a.to_bits() & src_abs_mask; - let sign = a.to_bits() & src_sign_mask; - let mut abs_result: R::Int; - - if a_abs.wrapping_sub(underflow) < a_abs.wrapping_sub(overflow) { - // The exponent of a is within the range of normal numbers in the - // destination format. We can convert by simply right-shifting with - // rounding and adjusting the exponent. - abs_result = (a_abs >> sig_bits_delta).cast(); - // Cast before shifting to prevent overflow. - let bias_diff: R::Int = src_exp_bias.wrapping_sub(dst_exp_bias).cast(); - let tmp = bias_diff << R::SIG_BITS; - abs_result = abs_result.wrapping_sub(tmp); - - let round_bits = a_abs & round_mask; - if round_bits > halfway { - // Round to nearest. - abs_result += dst_one; - } else if round_bits == halfway { - // Tie to even. - abs_result += abs_result & dst_one; - }; - } else if a_abs > src_infinity { - // a is NaN. - // Conjure the result by beginning with infinity, setting the qNaN - // bit and inserting the (truncated) trailing NaN field. - // Cast before shifting to prevent overflow. - let dst_inf_exp: R::Int = dst_inf_exp.cast(); - abs_result = dst_inf_exp << R::SIG_BITS; - abs_result |= dst_qnan; - abs_result |= dst_nan_code & ((a_abs & src_nan_code) >> (F::SIG_BITS - R::SIG_BITS)).cast(); - } else if a_abs >= overflow { - // a overflows to infinity. - // Cast before shifting to prevent overflow. - let dst_inf_exp: R::Int = dst_inf_exp.cast(); - abs_result = dst_inf_exp << R::SIG_BITS; - } else { - // a underflows on conversion to the destination type or is an exact - // zero. The result may be a denormal or zero. Extract the exponent - // to get the shift amount for the denormalization. - let a_exp: u32 = (a_abs >> F::SIG_BITS).cast(); - let shift = src_exp_bias - dst_exp_bias - a_exp + 1; - - let significand = (a.to_bits() & src_sig_mask) | src_min_normal; - - // Right shift by the denormalization amount with sticky. - if shift > F::SIG_BITS { - abs_result = dst_zero; - } else { - let sticky = if (significand << (src_bits - shift)) != src_zero { - src_one - } else { - src_zero - }; - let denormalized_significand: F::Int = (significand >> shift) | sticky; - abs_result = (denormalized_significand >> (F::SIG_BITS - R::SIG_BITS)).cast(); - let round_bits = denormalized_significand & round_mask; - // Round to nearest - if round_bits > halfway { - abs_result += dst_one; - } - // Ties to even - else if round_bits == halfway { - abs_result += abs_result & dst_one; - }; - } - } - - // Apply the signbit to the absolute value. - R::from_bits(abs_result | sign.wrapping_shr(src_bits - dst_bits).cast()) -} - -intrinsics! { - #[avr_skip] - #[aapcs_on_arm] - #[arm_aeabi_alias = __aeabi_d2f] - pub extern "C" fn __truncdfsf2(a: f64) -> f32 { - trunc(a) - } -} - -intrinsics! { - #[avr_skip] - #[aapcs_on_arm] - #[apple_f16_ret_abi] - #[arm_aeabi_alias = __aeabi_f2h] - #[cfg(f16_enabled)] - pub extern "C" fn __truncsfhf2(a: f32) -> f16 { - trunc(a) - } - - #[avr_skip] - #[aapcs_on_arm] - #[apple_f16_ret_abi] - #[cfg(f16_enabled)] - pub extern "C" fn __gnu_f2h_ieee(a: f32) -> f16 { - trunc(a) - } - - #[avr_skip] - #[aapcs_on_arm] - #[apple_f16_ret_abi] - #[arm_aeabi_alias = __aeabi_d2h] - #[cfg(f16_enabled)] - pub extern "C" fn __truncdfhf2(a: f64) -> f16 { - trunc(a) - } - - #[avr_skip] - #[aapcs_on_arm] - #[ppc_alias = __trunckfhf2] - #[cfg(all(f16_enabled, f128_enabled))] - pub extern "C" fn __trunctfhf2(a: f128) -> f16 { - trunc(a) - } - - #[avr_skip] - #[aapcs_on_arm] - #[ppc_alias = __trunckfsf2] - #[cfg(f128_enabled)] - pub extern "C" fn __trunctfsf2(a: f128) -> f32 { - trunc(a) - } - - #[avr_skip] - #[aapcs_on_arm] - #[ppc_alias = __trunckfdf2] - #[cfg(f128_enabled)] - pub extern "C" fn __trunctfdf2(a: f128) -> f64 { - trunc(a) - } -} diff --git a/library/compiler-builtins/src/hexagon.rs b/library/compiler-builtins/src/hexagon.rs deleted file mode 100644 index 91cf91c3142..00000000000 --- a/library/compiler-builtins/src/hexagon.rs +++ /dev/null @@ -1,55 +0,0 @@ -#![cfg(not(feature = "no-asm"))] - -use core::arch::global_asm; - -global_asm!(include_str!("hexagon/func_macro.s"), options(raw)); - -global_asm!(include_str!("hexagon/dfaddsub.s"), options(raw)); - -global_asm!(include_str!("hexagon/dfdiv.s"), options(raw)); - -global_asm!(include_str!("hexagon/dffma.s"), options(raw)); - -global_asm!(include_str!("hexagon/dfminmax.s"), options(raw)); - -global_asm!(include_str!("hexagon/dfmul.s"), options(raw)); - -global_asm!(include_str!("hexagon/dfsqrt.s"), options(raw)); - -global_asm!(include_str!("hexagon/divdi3.s"), options(raw)); - -global_asm!(include_str!("hexagon/divsi3.s"), options(raw)); - -global_asm!(include_str!("hexagon/fastmath2_dlib_asm.s"), options(raw)); - -global_asm!(include_str!("hexagon/fastmath2_ldlib_asm.s"), options(raw)); - -global_asm!( - include_str!("hexagon/memcpy_forward_vp4cp4n2.s"), - options(raw) -); - -global_asm!( - include_str!("hexagon/memcpy_likely_aligned.s"), - options(raw) -); - -global_asm!(include_str!("hexagon/moddi3.s"), options(raw)); - -global_asm!(include_str!("hexagon/modsi3.s"), options(raw)); - -global_asm!(include_str!("hexagon/sfdiv_opt.s"), options(raw)); - -global_asm!(include_str!("hexagon/sfsqrt_opt.s"), options(raw)); - -global_asm!(include_str!("hexagon/udivdi3.s"), options(raw)); - -global_asm!(include_str!("hexagon/udivmoddi4.s"), options(raw)); - -global_asm!(include_str!("hexagon/udivmodsi4.s"), options(raw)); - -global_asm!(include_str!("hexagon/udivsi3.s"), options(raw)); - -global_asm!(include_str!("hexagon/umoddi3.s"), options(raw)); - -global_asm!(include_str!("hexagon/umodsi3.s"), options(raw)); diff --git a/library/compiler-builtins/src/hexagon/dfaddsub.s b/library/compiler-builtins/src/hexagon/dfaddsub.s deleted file mode 100644 index 1f59e460be6..00000000000 --- a/library/compiler-builtins/src/hexagon/dfaddsub.s +++ /dev/null @@ -1,321 +0,0 @@ - .text - .global __hexagon_adddf3 - .global __hexagon_subdf3 - .type __hexagon_adddf3, @function - .type __hexagon_subdf3, @function - -.global __qdsp_adddf3 ; .set __qdsp_adddf3, __hexagon_adddf3 -.global __hexagon_fast_adddf3 ; .set __hexagon_fast_adddf3, __hexagon_adddf3 -.global __hexagon_fast2_adddf3 ; .set __hexagon_fast2_adddf3, __hexagon_adddf3 -.global __qdsp_subdf3 ; .set __qdsp_subdf3, __hexagon_subdf3 -.global __hexagon_fast_subdf3 ; .set __hexagon_fast_subdf3, __hexagon_subdf3 -.global __hexagon_fast2_subdf3 ; .set __hexagon_fast2_subdf3, __hexagon_subdf3 - - .p2align 5 -__hexagon_adddf3: - { - r4 = extractu(r1,#11,#20) - r5 = extractu(r3,#11,#20) - r13:12 = combine(##0x20000000,#0) - } - { - p3 = dfclass(r1:0,#2) - p3 = dfclass(r3:2,#2) - r9:8 = r13:12 - p2 = cmp.gtu(r5,r4) - } - { - if (!p3) jump .Ladd_abnormal - if (p2) r1:0 = r3:2 - if (p2) r3:2 = r1:0 - if (p2) r5:4 = combine(r4,r5) - } - { - r13:12 = insert(r1:0,#52,#11 -2) - r9:8 = insert(r3:2,#52,#11 -2) - r15 = sub(r4,r5) - r7:6 = combine(#62,#1) - } - - - - - -.Ladd_continue: - { - r15 = min(r15,r7) - - r11:10 = neg(r13:12) - p2 = cmp.gt(r1,#-1) - r14 = #0 - } - { - if (!p2) r13:12 = r11:10 - r11:10 = extractu(r9:8,r15:14) - r9:8 = ASR(r9:8,r15) - - - - - r15:14 = #0 - } - { - p1 = cmp.eq(r11:10,r15:14) - if (!p1.new) r8 = or(r8,r6) - r5 = add(r4,#-1024 -60) - p3 = cmp.gt(r3,#-1) - } - { - r13:12 = add(r13:12,r9:8) - r11:10 = sub(r13:12,r9:8) - r7:6 = combine(#54,##2045) - } - { - p0 = cmp.gtu(r4,r7) - p0 = !cmp.gtu(r4,r6) - if (!p0.new) jump:nt .Ladd_ovf_unf - if (!p3) r13:12 = r11:10 - } - { - r1:0 = convert_d2df(r13:12) - p0 = cmp.eq(r13,#0) - p0 = cmp.eq(r12,#0) - if (p0.new) jump:nt .Ladd_zero - } - { - r1 += asl(r5,#20) - jumpr r31 - } - .falign -__hexagon_subdf3: - { - r3 = togglebit(r3,#31) - jump __qdsp_adddf3 - } - - - .falign -.Ladd_zero: - - - { - r28 = USR - r1:0 = #0 - r3 = #1 - } - { - r28 = extractu(r28,#2,#22) - r3 = asl(r3,#31) - } - { - p0 = cmp.eq(r28,#2) - if (p0.new) r1 = xor(r1,r3) - jumpr r31 - } - .falign -.Ladd_ovf_unf: - { - r1:0 = convert_d2df(r13:12) - p0 = cmp.eq(r13,#0) - p0 = cmp.eq(r12,#0) - if (p0.new) jump:nt .Ladd_zero - } - { - r28 = extractu(r1,#11,#20) - r1 += asl(r5,#20) - } - { - r5 = add(r5,r28) - r3:2 = combine(##0x00100000,#0) - } - { - p0 = cmp.gt(r5,##1024 +1024 -2) - if (p0.new) jump:nt .Ladd_ovf - } - { - p0 = cmp.gt(r5,#0) - if (p0.new) jumpr:t r31 - r28 = sub(#1,r5) - } - { - r3:2 = insert(r1:0,#52,#0) - r1:0 = r13:12 - } - { - r3:2 = lsr(r3:2,r28) - } - { - r1:0 = insert(r3:2,#63,#0) - jumpr r31 - } - .falign -.Ladd_ovf: - - { - r1:0 = r13:12 - r28 = USR - r13:12 = combine(##0x7fefffff,#-1) - } - { - r5 = extractu(r28,#2,#22) - r28 = or(r28,#0x28) - r9:8 = combine(##0x7ff00000,#0) - } - { - USR = r28 - r5 ^= lsr(r1,#31) - r28 = r5 - } - { - p0 = !cmp.eq(r28,#1) - p0 = !cmp.eq(r5,#2) - if (p0.new) r13:12 = r9:8 - } - { - r1:0 = insert(r13:12,#63,#0) - } - { - p0 = dfcmp.eq(r1:0,r1:0) - jumpr r31 - } - -.Ladd_abnormal: - { - r13:12 = extractu(r1:0,#63,#0) - r9:8 = extractu(r3:2,#63,#0) - } - { - p3 = cmp.gtu(r13:12,r9:8) - if (!p3.new) r1:0 = r3:2 - if (!p3.new) r3:2 = r1:0 - } - { - - p0 = dfclass(r1:0,#0x0f) - if (!p0.new) jump:nt .Linvalid_nan_add - if (!p3) r13:12 = r9:8 - if (!p3) r9:8 = r13:12 - } - { - - - p1 = dfclass(r1:0,#0x08) - if (p1.new) jump:nt .Linf_add - } - { - p2 = dfclass(r3:2,#0x01) - if (p2.new) jump:nt .LB_zero - r13:12 = #0 - } - - { - p0 = dfclass(r1:0,#4) - if (p0.new) jump:nt .Ladd_two_subnormal - r13:12 = combine(##0x20000000,#0) - } - { - r4 = extractu(r1,#11,#20) - r5 = #1 - - r9:8 = asl(r9:8,#11 -2) - } - - - - { - r13:12 = insert(r1:0,#52,#11 -2) - r15 = sub(r4,r5) - r7:6 = combine(#62,#1) - jump .Ladd_continue - } - -.Ladd_two_subnormal: - { - r13:12 = extractu(r1:0,#63,#0) - r9:8 = extractu(r3:2,#63,#0) - } - { - r13:12 = neg(r13:12) - r9:8 = neg(r9:8) - p0 = cmp.gt(r1,#-1) - p1 = cmp.gt(r3,#-1) - } - { - if (p0) r13:12 = r1:0 - if (p1) r9:8 = r3:2 - } - { - r13:12 = add(r13:12,r9:8) - } - { - r9:8 = neg(r13:12) - p0 = cmp.gt(r13,#-1) - r3:2 = #0 - } - { - if (!p0) r1:0 = r9:8 - if (p0) r1:0 = r13:12 - r3 = ##0x80000000 - } - { - if (!p0) r1 = or(r1,r3) - p0 = dfcmp.eq(r1:0,r3:2) - if (p0.new) jump:nt .Lzero_plus_zero - } - { - jumpr r31 - } - -.Linvalid_nan_add: - { - r28 = convert_df2sf(r1:0) - p0 = dfclass(r3:2,#0x0f) - if (p0.new) r3:2 = r1:0 - } - { - r2 = convert_df2sf(r3:2) - r1:0 = #-1 - jumpr r31 - } - .falign -.LB_zero: - { - p0 = dfcmp.eq(r13:12,r1:0) - if (!p0.new) jumpr:t r31 - } - - - - -.Lzero_plus_zero: - { - p0 = cmp.eq(r1:0,r3:2) - if (p0.new) jumpr:t r31 - } - { - r28 = USR - } - { - r28 = extractu(r28,#2,#22) - r1:0 = #0 - } - { - p0 = cmp.eq(r28,#2) - if (p0.new) r1 = ##0x80000000 - jumpr r31 - } -.Linf_add: - - { - p0 = !cmp.eq(r1,r3) - p0 = dfclass(r3:2,#8) - if (!p0.new) jumpr:t r31 - } - { - r2 = ##0x7f800001 - } - { - r1:0 = convert_sf2df(r2) - jumpr r31 - } -.size __hexagon_adddf3,.-__hexagon_adddf3 diff --git a/library/compiler-builtins/src/hexagon/dfdiv.s b/library/compiler-builtins/src/hexagon/dfdiv.s deleted file mode 100644 index 6d65dbfc4df..00000000000 --- a/library/compiler-builtins/src/hexagon/dfdiv.s +++ /dev/null @@ -1,372 +0,0 @@ - .text - .global __hexagon_divdf3 - .type __hexagon_divdf3,@function - .global __qdsp_divdf3 ; .set __qdsp_divdf3, __hexagon_divdf3 - .global __hexagon_fast_divdf3 ; .set __hexagon_fast_divdf3, __hexagon_divdf3 - .global __hexagon_fast2_divdf3 ; .set __hexagon_fast2_divdf3, __hexagon_divdf3 - .p2align 5 -__hexagon_divdf3: - { - p2 = dfclass(r1:0,#0x02) - p2 = dfclass(r3:2,#0x02) - r13:12 = combine(r3,r1) - r28 = xor(r1,r3) - } - { - if (!p2) jump .Ldiv_abnormal - r7:6 = extractu(r3:2,#23,#52 -23) - r8 = ##0x3f800001 - } - { - r9 = or(r8,r6) - r13 = extractu(r13,#11,#52 -32) - r12 = extractu(r12,#11,#52 -32) - p3 = cmp.gt(r28,#-1) - } - - -.Ldenorm_continue: - { - r11,p0 = sfrecipa(r8,r9) - r10 = and(r8,#-2) - r28 = #1 - r12 = sub(r12,r13) - } - - - { - r10 -= sfmpy(r11,r9):lib - r1 = insert(r28,#11 +1,#52 -32) - r13 = ##0x00800000 << 3 - } - { - r11 += sfmpy(r11,r10):lib - r3 = insert(r28,#11 +1,#52 -32) - r10 = and(r8,#-2) - } - { - r10 -= sfmpy(r11,r9):lib - r5 = #-0x3ff +1 - r4 = #0x3ff -1 - } - { - r11 += sfmpy(r11,r10):lib - p1 = cmp.gt(r12,r5) - p1 = !cmp.gt(r12,r4) - } - { - r13 = insert(r11,#23,#3) - r5:4 = #0 - r12 = add(r12,#-61) - } - - - - - { - r13 = add(r13,#((-3) << 3)) - } - { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASL(r7:6, # ( 14 )); r1:0 -= asl(r15:14, # 32); } - { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASR(r7:6, # ( 1 )); r1:0 -= asl(r15:14, # 32); } - { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASR(r7:6, # ( 16 )); r1:0 -= asl(r15:14, # 32); } - { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASR(r7:6, # ( 31 )); r1:0 -= asl(r15:14, # 32); r7:6=# ( 0 ); } - - - - - - - - { - - r15:14 = sub(r1:0,r3:2) - p0 = cmp.gtu(r3:2,r1:0) - - if (!p0.new) r6 = #2 - } - { - r5:4 = add(r5:4,r7:6) - if (!p0) r1:0 = r15:14 - r15:14 = #0 - } - { - p0 = cmp.eq(r1:0,r15:14) - if (!p0.new) r4 = or(r4,r28) - } - { - r7:6 = neg(r5:4) - } - { - if (!p3) r5:4 = r7:6 - } - { - r1:0 = convert_d2df(r5:4) - if (!p1) jump .Ldiv_ovf_unf - } - { - r1 += asl(r12,#52 -32) - jumpr r31 - } - -.Ldiv_ovf_unf: - { - r1 += asl(r12,#52 -32) - r13 = extractu(r1,#11,#52 -32) - } - { - r7:6 = abs(r5:4) - r12 = add(r12,r13) - } - { - p0 = cmp.gt(r12,##0x3ff +0x3ff) - if (p0.new) jump:nt .Ldiv_ovf - } - { - p0 = cmp.gt(r12,#0) - if (p0.new) jump:nt .Lpossible_unf2 - } - { - r13 = add(clb(r7:6),#-1) - r12 = sub(#7,r12) - r10 = USR - r11 = #63 - } - { - r13 = min(r12,r11) - r11 = or(r10,#0x030) - r7:6 = asl(r7:6,r13) - r12 = #0 - } - { - r15:14 = extractu(r7:6,r13:12) - r7:6 = lsr(r7:6,r13) - r3:2 = #1 - } - { - p0 = cmp.gtu(r3:2,r15:14) - if (!p0.new) r6 = or(r2,r6) - r7 = setbit(r7,#52 -32+4) - } - { - r5:4 = neg(r7:6) - p0 = bitsclr(r6,#(1<<4)-1) - if (!p0.new) r10 = r11 - } - { - USR = r10 - if (p3) r5:4 = r7:6 - r10 = #-0x3ff -(52 +4) - } - { - r1:0 = convert_d2df(r5:4) - } - { - r1 += asl(r10,#52 -32) - jumpr r31 - } - - -.Lpossible_unf2: - - - { - r3:2 = extractu(r1:0,#63,#0) - r15:14 = combine(##0x00100000,#0) - r10 = #0x7FFF - } - { - p0 = dfcmp.eq(r15:14,r3:2) - p0 = bitsset(r7,r10) - } - - - - - - - { - if (!p0) jumpr r31 - r10 = USR - } - - { - r10 = or(r10,#0x30) - } - { - USR = r10 - } - { - p0 = dfcmp.eq(r1:0,r1:0) - jumpr r31 - } - -.Ldiv_ovf: - - - - { - r10 = USR - r3:2 = combine(##0x7fefffff,#-1) - r1 = mux(p3,#0,#-1) - } - { - r7:6 = combine(##0x7ff00000,#0) - r5 = extractu(r10,#2,#22) - r10 = or(r10,#0x28) - } - { - USR = r10 - r5 ^= lsr(r1,#31) - r4 = r5 - } - { - p0 = !cmp.eq(r4,#1) - p0 = !cmp.eq(r5,#2) - if (p0.new) r3:2 = r7:6 - p0 = dfcmp.eq(r3:2,r3:2) - } - { - r1:0 = insert(r3:2,#63,#0) - jumpr r31 - } - - - - - - - -.Ldiv_abnormal: - { - p0 = dfclass(r1:0,#0x0F) - p0 = dfclass(r3:2,#0x0F) - p3 = cmp.gt(r28,#-1) - } - { - p1 = dfclass(r1:0,#0x08) - p1 = dfclass(r3:2,#0x08) - } - { - p2 = dfclass(r1:0,#0x01) - p2 = dfclass(r3:2,#0x01) - } - { - if (!p0) jump .Ldiv_nan - if (p1) jump .Ldiv_invalid - } - { - if (p2) jump .Ldiv_invalid - } - { - p2 = dfclass(r1:0,#(0x0F ^ 0x01)) - p2 = dfclass(r3:2,#(0x0F ^ 0x08)) - } - { - p1 = dfclass(r1:0,#(0x0F ^ 0x08)) - p1 = dfclass(r3:2,#(0x0F ^ 0x01)) - } - { - if (!p2) jump .Ldiv_zero_result - if (!p1) jump .Ldiv_inf_result - } - - - - - - { - p0 = dfclass(r1:0,#0x02) - p1 = dfclass(r3:2,#0x02) - r10 = ##0x00100000 - } - { - r13:12 = combine(r3,r1) - r1 = insert(r10,#11 +1,#52 -32) - r3 = insert(r10,#11 +1,#52 -32) - } - { - if (p0) r1 = or(r1,r10) - if (p1) r3 = or(r3,r10) - } - { - r5 = add(clb(r1:0),#-11) - r4 = add(clb(r3:2),#-11) - r10 = #1 - } - { - r12 = extractu(r12,#11,#52 -32) - r13 = extractu(r13,#11,#52 -32) - } - { - r1:0 = asl(r1:0,r5) - r3:2 = asl(r3:2,r4) - if (!p0) r12 = sub(r10,r5) - if (!p1) r13 = sub(r10,r4) - } - { - r7:6 = extractu(r3:2,#23,#52 -23) - } - { - r9 = or(r8,r6) - jump .Ldenorm_continue - } - -.Ldiv_zero_result: - { - r1 = xor(r1,r3) - r3:2 = #0 - } - { - r1:0 = insert(r3:2,#63,#0) - jumpr r31 - } -.Ldiv_inf_result: - { - p2 = dfclass(r3:2,#0x01) - p2 = dfclass(r1:0,#(0x0F ^ 0x08)) - } - { - r10 = USR - if (!p2) jump 1f - r1 = xor(r1,r3) - } - { - r10 = or(r10,#0x04) - } - { - USR = r10 - } -1: - { - r3:2 = combine(##0x7ff00000,#0) - p0 = dfcmp.uo(r3:2,r3:2) - } - { - r1:0 = insert(r3:2,#63,#0) - jumpr r31 - } -.Ldiv_nan: - { - p0 = dfclass(r1:0,#0x10) - p1 = dfclass(r3:2,#0x10) - if (!p0.new) r1:0 = r3:2 - if (!p1.new) r3:2 = r1:0 - } - { - r5 = convert_df2sf(r1:0) - r4 = convert_df2sf(r3:2) - } - { - r1:0 = #-1 - jumpr r31 - } - -.Ldiv_invalid: - { - r10 = ##0x7f800001 - } - { - r1:0 = convert_sf2df(r10) - jumpr r31 - } -.size __hexagon_divdf3,.-__hexagon_divdf3 diff --git a/library/compiler-builtins/src/hexagon/dffma.s b/library/compiler-builtins/src/hexagon/dffma.s deleted file mode 100644 index 97d05eb1839..00000000000 --- a/library/compiler-builtins/src/hexagon/dffma.s +++ /dev/null @@ -1,534 +0,0 @@ - .text - .global __hexagon_fmadf4 - .type __hexagon_fmadf4,@function - .global __hexagon_fmadf5 - .type __hexagon_fmadf5,@function - .global __qdsp_fmadf5 ; .set __qdsp_fmadf5, __hexagon_fmadf5 - .p2align 5 -__hexagon_fmadf4: -__hexagon_fmadf5: -fma: - { - p0 = dfclass(r1:0,#2) - p0 = dfclass(r3:2,#2) - r13:12 = #0 - r15:14 = #0 - } - { - r13:12 = insert(r1:0,#52,#11 -3) - r15:14 = insert(r3:2,#52,#11 -3) - r7 = ##0x10000000 - allocframe(#32) - } - { - r9:8 = mpyu(r12,r14) - if (!p0) jump .Lfma_abnormal_ab - r13 = or(r13,r7) - r15 = or(r15,r7) - } - { - p0 = dfclass(r5:4,#2) - if (!p0.new) jump:nt .Lfma_abnormal_c - r11:10 = combine(r7,#0) - r7:6 = combine(#0,r9) - } -.Lfma_abnormal_c_restart: - { - r7:6 += mpyu(r14,r13) - r11:10 = insert(r5:4,#52,#11 -3) - memd(r29+#0) = r17:16 - memd(r29+#8) = r19:18 - } - { - r7:6 += mpyu(r12,r15) - r19:18 = neg(r11:10) - p0 = cmp.gt(r5,#-1) - r28 = xor(r1,r3) - } - { - r18 = extractu(r1,#11,#20) - r19 = extractu(r3,#11,#20) - r17:16 = combine(#0,r7) - if (!p0) r11:10 = r19:18 - } - { - r17:16 += mpyu(r13,r15) - r9:8 = combine(r6,r8) - r18 = add(r18,r19) - - - - - r19 = extractu(r5,#11,#20) - } - { - r18 = add(r18,#-1023 +(4)) - p3 = !cmp.gt(r28,#-1) - r7:6 = #0 - r15:14 = #0 - } - { - r7:6 = sub(r7:6,r9:8,p3):carry - p0 = !cmp.gt(r28,#-1) - p1 = cmp.gt(r19,r18) - if (p1.new) r19:18 = combine(r18,r19) - } - { - r15:14 = sub(r15:14,r17:16,p3):carry - if (p0) r9:8 = r7:6 - - - - - r7:6 = #0 - r19 = sub(r18,r19) - } - { - if (p0) r17:16 = r15:14 - p0 = cmp.gt(r19,#63) - if (p1) r9:8 = r7:6 - if (p1) r7:6 = r9:8 - } - - - - - - - - { - if (p1) r17:16 = r11:10 - if (p1) r11:10 = r17:16 - if (p0) r19 = add(r19,#-64) - r28 = #63 - } - { - - if (p0) r7:6 = r11:10 - r28 = asr(r11,#31) - r13 = min(r19,r28) - r12 = #0 - } - - - - - - - { - if (p0) r11:10 = combine(r28,r28) - r5:4 = extract(r7:6,r13:12) - r7:6 = lsr(r7:6,r13) - r12 = sub(#64,r13) - } - { - r15:14 = #0 - r28 = #-2 - r7:6 |= lsl(r11:10,r12) - r11:10 = asr(r11:10,r13) - } - { - p3 = cmp.gtu(r5:4,r15:14) - if (p3.new) r6 = and(r6,r28) - - - - r15:14 = #1 - r5:4 = #0 - } - { - r9:8 = add(r7:6,r9:8,p3):carry - } - { - r17:16 = add(r11:10,r17:16,p3):carry - r28 = #62 - } - - - - - - - - { - r12 = add(clb(r17:16),#-2) - if (!cmp.eq(r12.new,r28)) jump:t 1f - } - - { - r11:10 = extractu(r9:8,#62,#2) - r9:8 = asl(r9:8,#62) - r18 = add(r18,#-62) - } - { - r17:16 = insert(r11:10,#62,#0) - } - { - r12 = add(clb(r17:16),#-2) - } - .falign -1: - { - r11:10 = asl(r17:16,r12) - r5:4 |= asl(r9:8,r12) - r13 = sub(#64,r12) - r18 = sub(r18,r12) - } - { - r11:10 |= lsr(r9:8,r13) - p2 = cmp.gtu(r15:14,r5:4) - r28 = #1023 +1023 -2 - } - { - if (!p2) r10 = or(r10,r14) - - p0 = !cmp.gt(r18,r28) - p0 = cmp.gt(r18,#1) - if (!p0.new) jump:nt .Lfma_ovf_unf - } - { - - p0 = cmp.gtu(r15:14,r11:10) - r1:0 = convert_d2df(r11:10) - r18 = add(r18,#-1023 -60) - r17:16 = memd(r29+#0) - } - { - r1 += asl(r18,#20) - r19:18 = memd(r29+#8) - if (!p0) dealloc_return - } -.Ladd_yields_zero: - - { - r28 = USR - r1:0 = #0 - } - { - r28 = extractu(r28,#2,#22) - r17:16 = memd(r29+#0) - r19:18 = memd(r29+#8) - } - { - p0 = cmp.eq(r28,#2) - if (p0.new) r1 = ##0x80000000 - dealloc_return - } -.Lfma_ovf_unf: - { - p0 = cmp.gtu(r15:14,r11:10) - if (p0.new) jump:nt .Ladd_yields_zero - } - { - r1:0 = convert_d2df(r11:10) - r18 = add(r18,#-1023 -60) - r28 = r18 - } - - - { - r1 += asl(r18,#20) - r7 = extractu(r1,#11,#20) - } - { - r6 = add(r18,r7) - r17:16 = memd(r29+#0) - r19:18 = memd(r29+#8) - r9:8 = abs(r11:10) - } - { - p0 = cmp.gt(r6,##1023 +1023) - if (p0.new) jump:nt .Lfma_ovf - } - { - p0 = cmp.gt(r6,#0) - if (p0.new) jump:nt .Lpossible_unf0 - } - { - - - - r7 = add(clb(r9:8),#-2) - r6 = sub(#1+5,r28) - p3 = cmp.gt(r11,#-1) - } - - - - { - r6 = add(r6,r7) - r9:8 = asl(r9:8,r7) - r1 = USR - r28 = #63 - } - { - r7 = min(r6,r28) - r6 = #0 - r0 = #0x0030 - } - { - r3:2 = extractu(r9:8,r7:6) - r9:8 = asr(r9:8,r7) - } - { - p0 = cmp.gtu(r15:14,r3:2) - if (!p0.new) r8 = or(r8,r14) - r9 = setbit(r9,#20 +3) - } - { - r11:10 = neg(r9:8) - p1 = bitsclr(r8,#(1<<3)-1) - if (!p1.new) r1 = or(r1,r0) - r3:2 = #0 - } - { - if (p3) r11:10 = r9:8 - USR = r1 - r28 = #-1023 -(52 +3) - } - { - r1:0 = convert_d2df(r11:10) - } - { - r1 += asl(r28,#20) - dealloc_return - } -.Lpossible_unf0: - { - r28 = ##0x7fefffff - r9:8 = abs(r11:10) - } - { - p0 = cmp.eq(r0,#0) - p0 = bitsclr(r1,r28) - if (!p0.new) dealloc_return:t - r28 = #0x7fff - } - { - p0 = bitsset(r9,r28) - r3 = USR - r2 = #0x0030 - } - { - if (p0) r3 = or(r3,r2) - } - { - USR = r3 - } - { - p0 = dfcmp.eq(r1:0,r1:0) - dealloc_return - } -.Lfma_ovf: - { - r28 = USR - r11:10 = combine(##0x7fefffff,#-1) - r1:0 = r11:10 - } - { - r9:8 = combine(##0x7ff00000,#0) - r3 = extractu(r28,#2,#22) - r28 = or(r28,#0x28) - } - { - USR = r28 - r3 ^= lsr(r1,#31) - r2 = r3 - } - { - p0 = !cmp.eq(r2,#1) - p0 = !cmp.eq(r3,#2) - } - { - p0 = dfcmp.eq(r9:8,r9:8) - if (p0.new) r11:10 = r9:8 - } - { - r1:0 = insert(r11:10,#63,#0) - dealloc_return - } -.Lfma_abnormal_ab: - { - r9:8 = extractu(r1:0,#63,#0) - r11:10 = extractu(r3:2,#63,#0) - deallocframe - } - { - p3 = cmp.gtu(r9:8,r11:10) - if (!p3.new) r1:0 = r3:2 - if (!p3.new) r3:2 = r1:0 - } - { - p0 = dfclass(r1:0,#0x0f) - if (!p0.new) jump:nt .Lnan - if (!p3) r9:8 = r11:10 - if (!p3) r11:10 = r9:8 - } - { - p1 = dfclass(r1:0,#0x08) - p1 = dfclass(r3:2,#0x0e) - } - { - p0 = dfclass(r1:0,#0x08) - p0 = dfclass(r3:2,#0x01) - } - { - if (p1) jump .Lab_inf - p2 = dfclass(r3:2,#0x01) - } - { - if (p0) jump .Linvalid - if (p2) jump .Lab_true_zero - r28 = ##0x7c000000 - } - - - - - - { - p0 = bitsclr(r1,r28) - if (p0.new) jump:nt .Lfma_ab_tiny - } - { - r28 = add(clb(r11:10),#-11) - } - { - r11:10 = asl(r11:10,r28) - } - { - r3:2 = insert(r11:10,#63,#0) - r1 -= asl(r28,#20) - } - jump fma - -.Lfma_ab_tiny: - r9:8 = combine(##0x00100000,#0) - { - r1:0 = insert(r9:8,#63,#0) - r3:2 = insert(r9:8,#63,#0) - } - jump fma - -.Lab_inf: - { - r3:2 = lsr(r3:2,#63) - p0 = dfclass(r5:4,#0x10) - } - { - r1:0 ^= asl(r3:2,#63) - if (p0) jump .Lnan - } - { - p1 = dfclass(r5:4,#0x08) - if (p1.new) jump:nt .Lfma_inf_plus_inf - } - - { - jumpr r31 - } - .falign -.Lfma_inf_plus_inf: - { - p0 = dfcmp.eq(r1:0,r5:4) - if (!p0.new) jump:nt .Linvalid - } - { - jumpr r31 - } - -.Lnan: - { - p0 = dfclass(r3:2,#0x10) - p1 = dfclass(r5:4,#0x10) - if (!p0.new) r3:2 = r1:0 - if (!p1.new) r5:4 = r1:0 - } - { - r3 = convert_df2sf(r3:2) - r2 = convert_df2sf(r5:4) - } - { - r3 = convert_df2sf(r1:0) - r1:0 = #-1 - jumpr r31 - } - -.Linvalid: - { - r28 = ##0x7f800001 - } - { - r1:0 = convert_sf2df(r28) - jumpr r31 - } - -.Lab_true_zero: - - { - p0 = dfclass(r5:4,#0x10) - if (p0.new) jump:nt .Lnan - if (p0.new) r1:0 = r5:4 - } - { - p0 = dfcmp.eq(r3:2,r5:4) - r1 = lsr(r1,#31) - } - { - r3 ^= asl(r1,#31) - if (!p0) r1:0 = r5:4 - if (!p0) jumpr r31 - } - - { - p0 = cmp.eq(r3:2,r5:4) - if (p0.new) jumpr:t r31 - r1:0 = r3:2 - } - { - r28 = USR - } - { - r28 = extractu(r28,#2,#22) - r1:0 = #0 - } - { - p0 = cmp.eq(r28,#2) - if (p0.new) r1 = ##0x80000000 - jumpr r31 - } - - - - - .falign -.Lfma_abnormal_c: - - - { - p0 = dfclass(r5:4,#0x10) - if (p0.new) jump:nt .Lnan - if (p0.new) r1:0 = r5:4 - deallocframe - } - { - p0 = dfclass(r5:4,#0x08) - if (p0.new) r1:0 = r5:4 - if (p0.new) jumpr:nt r31 - } - - - { - p0 = dfclass(r5:4,#0x01) - if (p0.new) jump:nt __hexagon_muldf3 - r28 = #1 - } - - - { - allocframe(#32) - r11:10 = #0 - r5 = insert(r28,#11,#20) - jump .Lfma_abnormal_c_restart - } -.size fma,.-fma diff --git a/library/compiler-builtins/src/hexagon/dfminmax.s b/library/compiler-builtins/src/hexagon/dfminmax.s deleted file mode 100644 index 953e773bf19..00000000000 --- a/library/compiler-builtins/src/hexagon/dfminmax.s +++ /dev/null @@ -1,45 +0,0 @@ - .text - .global __hexagon_mindf3 - .global __hexagon_maxdf3 - .type __hexagon_mindf3,@function - .type __hexagon_maxdf3,@function - .global __qdsp_mindf3 ; .set __qdsp_mindf3, __hexagon_mindf3 - .global __qdsp_maxdf3 ; .set __qdsp_maxdf3, __hexagon_maxdf3 - .p2align 5 -__hexagon_mindf3: - { - p0 = dfclass(r1:0,#0x10) - p1 = dfcmp.gt(r1:0,r3:2) - r5:4 = r1:0 - } - { - if (p0) r1:0 = r3:2 - if (p1) r1:0 = r3:2 - p2 = dfcmp.eq(r1:0,r3:2) - if (!p2.new) jumpr:t r31 - } - - { - r1:0 = or(r5:4,r3:2) - jumpr r31 - } -.size __hexagon_mindf3,.-__hexagon_mindf3 - .falign -__hexagon_maxdf3: - { - p0 = dfclass(r1:0,#0x10) - p1 = dfcmp.gt(r3:2,r1:0) - r5:4 = r1:0 - } - { - if (p0) r1:0 = r3:2 - if (p1) r1:0 = r3:2 - p2 = dfcmp.eq(r1:0,r3:2) - if (!p2.new) jumpr:t r31 - } - - { - r1:0 = and(r5:4,r3:2) - jumpr r31 - } -.size __hexagon_maxdf3,.-__hexagon_maxdf3 diff --git a/library/compiler-builtins/src/hexagon/dfmul.s b/library/compiler-builtins/src/hexagon/dfmul.s deleted file mode 100644 index 32fc674f975..00000000000 --- a/library/compiler-builtins/src/hexagon/dfmul.s +++ /dev/null @@ -1,309 +0,0 @@ - .text - .global __hexagon_muldf3 - .type __hexagon_muldf3,@function - .global __qdsp_muldf3 ; .set __qdsp_muldf3, __hexagon_muldf3 - .global __hexagon_fast_muldf3 ; .set __hexagon_fast_muldf3, __hexagon_muldf3 - .global __hexagon_fast2_muldf3 ; .set __hexagon_fast2_muldf3, __hexagon_muldf3 - .p2align 5 -__hexagon_muldf3: - { - p0 = dfclass(r1:0,#2) - p0 = dfclass(r3:2,#2) - r13:12 = combine(##0x40000000,#0) - } - { - r13:12 = insert(r1:0,#52,#11 -1) - r5:4 = asl(r3:2,#11 -1) - r28 = #-1024 - r9:8 = #1 - } - { - r7:6 = mpyu(r4,r13) - r5:4 = insert(r9:8,#2,#62) - } - - - - - { - r15:14 = mpyu(r12,r4) - r7:6 += mpyu(r12,r5) - } - { - r7:6 += lsr(r15:14,#32) - r11:10 = mpyu(r13,r5) - r5:4 = combine(##1024 +1024 -4,#0) - } - { - r11:10 += lsr(r7:6,#32) - if (!p0) jump .Lmul_abnormal - p1 = cmp.eq(r14,#0) - p1 = cmp.eq(r6,#0) - } - { - if (!p1) r10 = or(r10,r8) - r6 = extractu(r1,#11,#20) - r7 = extractu(r3,#11,#20) - } - { - r15:14 = neg(r11:10) - r6 += add(r28,r7) - r28 = xor(r1,r3) - } - { - if (!p2.new) r11:10 = r15:14 - p2 = cmp.gt(r28,#-1) - p0 = !cmp.gt(r6,r5) - p0 = cmp.gt(r6,r4) - if (!p0.new) jump:nt .Lmul_ovf_unf - } - { - r1:0 = convert_d2df(r11:10) - r6 = add(r6,#-1024 -58) - } - { - r1 += asl(r6,#20) - jumpr r31 - } - - .falign -.Lpossible_unf1: - { - p0 = cmp.eq(r0,#0) - p0 = bitsclr(r1,r4) - if (!p0.new) jumpr:t r31 - r5 = #0x7fff - } - { - p0 = bitsset(r13,r5) - r4 = USR - r5 = #0x030 - } - { - if (p0) r4 = or(r4,r5) - } - { - USR = r4 - } - { - p0 = dfcmp.eq(r1:0,r1:0) - jumpr r31 - } - .falign -.Lmul_ovf_unf: - { - r1:0 = convert_d2df(r11:10) - r13:12 = abs(r11:10) - r7 = add(r6,#-1024 -58) - } - { - r1 += asl(r7,#20) - r7 = extractu(r1,#11,#20) - r4 = ##0x7FEFFFFF - } - { - r7 += add(r6,##-1024 -58) - - r5 = #0 - } - { - p0 = cmp.gt(r7,##1024 +1024 -2) - if (p0.new) jump:nt .Lmul_ovf - } - { - p0 = cmp.gt(r7,#0) - if (p0.new) jump:nt .Lpossible_unf1 - r5 = sub(r6,r5) - r28 = #63 - } - { - r4 = #0 - r5 = sub(#5,r5) - } - { - p3 = cmp.gt(r11,#-1) - r5 = min(r5,r28) - r11:10 = r13:12 - } - { - r28 = USR - r15:14 = extractu(r11:10,r5:4) - } - { - r11:10 = asr(r11:10,r5) - r4 = #0x0030 - r1 = insert(r9,#11,#20) - } - { - p0 = cmp.gtu(r9:8,r15:14) - if (!p0.new) r10 = or(r10,r8) - r11 = setbit(r11,#20 +3) - } - { - r15:14 = neg(r11:10) - p1 = bitsclr(r10,#0x7) - if (!p1.new) r28 = or(r4,r28) - } - { - if (!p3) r11:10 = r15:14 - USR = r28 - } - { - r1:0 = convert_d2df(r11:10) - p0 = dfcmp.eq(r1:0,r1:0) - } - { - r1 = insert(r9,#11 -1,#20 +1) - jumpr r31 - } - .falign -.Lmul_ovf: - - { - r28 = USR - r13:12 = combine(##0x7fefffff,#-1) - r1:0 = r11:10 - } - { - r14 = extractu(r28,#2,#22) - r28 = or(r28,#0x28) - r5:4 = combine(##0x7ff00000,#0) - } - { - USR = r28 - r14 ^= lsr(r1,#31) - r28 = r14 - } - { - p0 = !cmp.eq(r28,#1) - p0 = !cmp.eq(r14,#2) - if (p0.new) r13:12 = r5:4 - p0 = dfcmp.eq(r1:0,r1:0) - } - { - r1:0 = insert(r13:12,#63,#0) - jumpr r31 - } - -.Lmul_abnormal: - { - r13:12 = extractu(r1:0,#63,#0) - r5:4 = extractu(r3:2,#63,#0) - } - { - p3 = cmp.gtu(r13:12,r5:4) - if (!p3.new) r1:0 = r3:2 - if (!p3.new) r3:2 = r1:0 - } - { - - p0 = dfclass(r1:0,#0x0f) - if (!p0.new) jump:nt .Linvalid_nan - if (!p3) r13:12 = r5:4 - if (!p3) r5:4 = r13:12 - } - { - - p1 = dfclass(r1:0,#0x08) - p1 = dfclass(r3:2,#0x0e) - } - { - - - p0 = dfclass(r1:0,#0x08) - p0 = dfclass(r3:2,#0x01) - } - { - if (p1) jump .Ltrue_inf - p2 = dfclass(r3:2,#0x01) - } - { - if (p0) jump .Linvalid_zeroinf - if (p2) jump .Ltrue_zero - r28 = ##0x7c000000 - } - - - - - - { - p0 = bitsclr(r1,r28) - if (p0.new) jump:nt .Lmul_tiny - } - { - r28 = cl0(r5:4) - } - { - r28 = add(r28,#-11) - } - { - r5:4 = asl(r5:4,r28) - } - { - r3:2 = insert(r5:4,#63,#0) - r1 -= asl(r28,#20) - } - jump __hexagon_muldf3 -.Lmul_tiny: - { - r28 = USR - r1:0 = xor(r1:0,r3:2) - } - { - r28 = or(r28,#0x30) - r1:0 = insert(r9:8,#63,#0) - r5 = extractu(r28,#2,#22) - } - { - USR = r28 - p0 = cmp.gt(r5,#1) - if (!p0.new) r0 = #0 - r5 ^= lsr(r1,#31) - } - { - p0 = cmp.eq(r5,#3) - if (!p0.new) r0 = #0 - jumpr r31 - } -.Linvalid_zeroinf: - { - r28 = USR - } - { - r1:0 = #-1 - r28 = or(r28,#2) - } - { - USR = r28 - } - { - p0 = dfcmp.uo(r1:0,r1:0) - jumpr r31 - } -.Linvalid_nan: - { - p0 = dfclass(r3:2,#0x0f) - r28 = convert_df2sf(r1:0) - if (p0.new) r3:2 = r1:0 - } - { - r2 = convert_df2sf(r3:2) - r1:0 = #-1 - jumpr r31 - } - .falign -.Ltrue_zero: - { - r1:0 = r3:2 - r3:2 = r1:0 - } -.Ltrue_inf: - { - r3 = extract(r3,#1,#31) - } - { - r1 ^= asl(r3,#31) - jumpr r31 - } -.size __hexagon_muldf3,.-__hexagon_muldf3 diff --git a/library/compiler-builtins/src/hexagon/dfsqrt.s b/library/compiler-builtins/src/hexagon/dfsqrt.s deleted file mode 100644 index 14f584a1133..00000000000 --- a/library/compiler-builtins/src/hexagon/dfsqrt.s +++ /dev/null @@ -1,277 +0,0 @@ - .text - .global __hexagon_sqrtdf2 - .type __hexagon_sqrtdf2,@function - .global __hexagon_sqrt - .type __hexagon_sqrt,@function - .global __qdsp_sqrtdf2 ; .set __qdsp_sqrtdf2, __hexagon_sqrtdf2; .type __qdsp_sqrtdf2,@function - .global __qdsp_sqrt ; .set __qdsp_sqrt, __hexagon_sqrt; .type __qdsp_sqrt,@function - .global __hexagon_fast_sqrtdf2 ; .set __hexagon_fast_sqrtdf2, __hexagon_sqrtdf2; .type __hexagon_fast_sqrtdf2,@function - .global __hexagon_fast_sqrt ; .set __hexagon_fast_sqrt, __hexagon_sqrt; .type __hexagon_fast_sqrt,@function - .global __hexagon_fast2_sqrtdf2 ; .set __hexagon_fast2_sqrtdf2, __hexagon_sqrtdf2; .type __hexagon_fast2_sqrtdf2,@function - .global __hexagon_fast2_sqrt ; .set __hexagon_fast2_sqrt, __hexagon_sqrt; .type __hexagon_fast2_sqrt,@function - .type sqrt,@function - .p2align 5 -__hexagon_sqrtdf2: -__hexagon_sqrt: - { - r15:14 = extractu(r1:0,#23 +1,#52 -23) - r28 = extractu(r1,#11,#52 -32) - r5:4 = combine(##0x3f000004,#1) - } - { - p2 = dfclass(r1:0,#0x02) - p2 = cmp.gt(r1,#-1) - if (!p2.new) jump:nt .Lsqrt_abnormal - r9 = or(r5,r14) - } - -.Ldenormal_restart: - { - r11:10 = r1:0 - r7,p0 = sfinvsqrta(r9) - r5 = and(r5,#-16) - r3:2 = #0 - } - { - r3 += sfmpy(r7,r9):lib - r2 += sfmpy(r7,r5):lib - r6 = r5 - - - r9 = and(r28,#1) - } - { - r6 -= sfmpy(r3,r2):lib - r11 = insert(r4,#11 +1,#52 -32) - p1 = cmp.gtu(r9,#0) - } - { - r3 += sfmpy(r3,r6):lib - r2 += sfmpy(r2,r6):lib - r6 = r5 - r9 = mux(p1,#8,#9) - } - { - r6 -= sfmpy(r3,r2):lib - r11:10 = asl(r11:10,r9) - r9 = mux(p1,#3,#2) - } - { - r2 += sfmpy(r2,r6):lib - - r15:14 = asl(r11:10,r9) - } - { - r2 = and(r2,##0x007fffff) - } - { - r2 = add(r2,##0x00800000 - 3) - r9 = mux(p1,#7,#8) - } - { - r8 = asl(r2,r9) - r9 = mux(p1,#15-(1+1),#15-(1+0)) - } - { - r13:12 = mpyu(r8,r15) - } - { - r1:0 = asl(r11:10,#15) - r15:14 = mpyu(r13,r13) - p1 = cmp.eq(r0,r0) - } - { - r1:0 -= asl(r15:14,#15) - r15:14 = mpyu(r13,r12) - p2 = cmp.eq(r0,r0) - } - { - r1:0 -= lsr(r15:14,#16) - p3 = cmp.eq(r0,r0) - } - { - r1:0 = mpyu(r1,r8) - } - { - r13:12 += lsr(r1:0,r9) - r9 = add(r9,#16) - r1:0 = asl(r11:10,#31) - } - - { - r15:14 = mpyu(r13,r13) - r1:0 -= mpyu(r13,r12) - } - { - r1:0 -= asl(r15:14,#31) - r15:14 = mpyu(r12,r12) - } - { - r1:0 -= lsr(r15:14,#33) - } - { - r1:0 = mpyu(r1,r8) - } - { - r13:12 += lsr(r1:0,r9) - r9 = add(r9,#16) - r1:0 = asl(r11:10,#47) - } - - { - r15:14 = mpyu(r13,r13) - } - { - r1:0 -= asl(r15:14,#47) - r15:14 = mpyu(r13,r12) - } - { - r1:0 -= asl(r15:14,#16) - r15:14 = mpyu(r12,r12) - } - { - r1:0 -= lsr(r15:14,#17) - } - { - r1:0 = mpyu(r1,r8) - } - { - r13:12 += lsr(r1:0,r9) - } - { - r3:2 = mpyu(r13,r12) - r5:4 = mpyu(r12,r12) - r15:14 = #0 - r1:0 = #0 - } - { - r3:2 += lsr(r5:4,#33) - r5:4 += asl(r3:2,#33) - p1 = cmp.eq(r0,r0) - } - { - r7:6 = mpyu(r13,r13) - r1:0 = sub(r1:0,r5:4,p1):carry - r9:8 = #1 - } - { - r7:6 += lsr(r3:2,#31) - r9:8 += asl(r13:12,#1) - } - - - - - - { - r15:14 = sub(r11:10,r7:6,p1):carry - r5:4 = sub(r1:0,r9:8,p2):carry - - - - - r7:6 = #1 - r11:10 = #0 - } - { - r3:2 = sub(r15:14,r11:10,p2):carry - r7:6 = add(r13:12,r7:6) - r28 = add(r28,#-0x3ff) - } - { - - if (p2) r13:12 = r7:6 - if (p2) r1:0 = r5:4 - if (p2) r15:14 = r3:2 - } - { - r5:4 = sub(r1:0,r9:8,p3):carry - r7:6 = #1 - r28 = asr(r28,#1) - } - { - r3:2 = sub(r15:14,r11:10,p3):carry - r7:6 = add(r13:12,r7:6) - } - { - if (p3) r13:12 = r7:6 - if (p3) r1:0 = r5:4 - - - - - - r2 = #1 - } - { - p0 = cmp.eq(r1:0,r11:10) - if (!p0.new) r12 = or(r12,r2) - r3 = cl0(r13:12) - r28 = add(r28,#-63) - } - - - - { - r1:0 = convert_ud2df(r13:12) - r28 = add(r28,r3) - } - { - r1 += asl(r28,#52 -32) - jumpr r31 - } -.Lsqrt_abnormal: - { - p0 = dfclass(r1:0,#0x01) - if (p0.new) jumpr:t r31 - } - { - p0 = dfclass(r1:0,#0x10) - if (p0.new) jump:nt .Lsqrt_nan - } - { - p0 = cmp.gt(r1,#-1) - if (!p0.new) jump:nt .Lsqrt_invalid_neg - if (!p0.new) r28 = ##0x7F800001 - } - { - p0 = dfclass(r1:0,#0x08) - if (p0.new) jumpr:nt r31 - } - - - { - r1:0 = extractu(r1:0,#52,#0) - } - { - r28 = add(clb(r1:0),#-11) - } - { - r1:0 = asl(r1:0,r28) - r28 = sub(#1,r28) - } - { - r1 = insert(r28,#1,#52 -32) - } - { - r3:2 = extractu(r1:0,#23 +1,#52 -23) - r5 = ##0x3f000004 - } - { - r9 = or(r5,r2) - r5 = and(r5,#-16) - jump .Ldenormal_restart - } -.Lsqrt_nan: - { - r28 = convert_df2sf(r1:0) - r1:0 = #-1 - jumpr r31 - } -.Lsqrt_invalid_neg: - { - r1:0 = convert_sf2df(r28) - jumpr r31 - } -.size __hexagon_sqrt,.-__hexagon_sqrt -.size __hexagon_sqrtdf2,.-__hexagon_sqrtdf2 diff --git a/library/compiler-builtins/src/hexagon/divdi3.s b/library/compiler-builtins/src/hexagon/divdi3.s deleted file mode 100644 index 0fee6e70f06..00000000000 --- a/library/compiler-builtins/src/hexagon/divdi3.s +++ /dev/null @@ -1,64 +0,0 @@ - -FUNCTION_BEGIN __hexagon_divdi3 - { - p2 = tstbit(r1,#31) - p3 = tstbit(r3,#31) - } - { - r1:0 = abs(r1:0) - r3:2 = abs(r3:2) - } - { - r6 = cl0(r1:0) - r7 = cl0(r3:2) - r5:4 = r3:2 - r3:2 = r1:0 - } - { - p3 = xor(p2,p3) - r10 = sub(r7,r6) - r1:0 = #0 - r15:14 = #1 - } - { - r11 = add(r10,#1) - r13:12 = lsl(r5:4,r10) - r15:14 = lsl(r15:14,r10) - } - { - p0 = cmp.gtu(r5:4,r3:2) - loop0(1f,r11) - } - { - if (p0) jump .hexagon_divdi3_return - } - .falign -1: - { - p0 = cmp.gtu(r13:12,r3:2) - } - { - r7:6 = sub(r3:2, r13:12) - r9:8 = add(r1:0, r15:14) - } - { - r1:0 = vmux(p0, r1:0, r9:8) - r3:2 = vmux(p0, r3:2, r7:6) - } - { - r15:14 = lsr(r15:14, #1) - r13:12 = lsr(r13:12, #1) - }:endloop0 - -.hexagon_divdi3_return: - { - r3:2 = neg(r1:0) - } - { - r1:0 = vmux(p3,r3:2,r1:0) - jumpr r31 - } -FUNCTION_END __hexagon_divdi3 - - .globl __qdsp_divdi3 - .set __qdsp_divdi3, __hexagon_divdi3 diff --git a/library/compiler-builtins/src/hexagon/divsi3.s b/library/compiler-builtins/src/hexagon/divsi3.s deleted file mode 100644 index fc957a43146..00000000000 --- a/library/compiler-builtins/src/hexagon/divsi3.s +++ /dev/null @@ -1,53 +0,0 @@ - -FUNCTION_BEGIN __hexagon_divsi3 - { - p0 = cmp.ge(r0,#0) - p1 = cmp.ge(r1,#0) - r1 = abs(r0) - r2 = abs(r1) - } - { - r3 = cl0(r1) - r4 = cl0(r2) - r5 = sub(r1,r2) - p2 = cmp.gtu(r2,r1) - } - { - r0 = #0 - p1 = xor(p0,p1) - p0 = cmp.gtu(r2,r5) - if (p2) jumpr r31 - } - - { - r0 = mux(p1,#-1,#1) - if (p0) jumpr r31 - r4 = sub(r4,r3) - r3 = #1 - } - { - r0 = #0 - r3:2 = vlslw(r3:2,r4) - loop0(1f,r4) - } - .falign -1: - { - p0 = cmp.gtu(r2,r1) - if (!p0.new) r1 = sub(r1,r2) - if (!p0.new) r0 = add(r0,r3) - r3:2 = vlsrw(r3:2,#1) - }:endloop0 - { - p0 = cmp.gtu(r2,r1) - if (!p0.new) r0 = add(r0,r3) - if (!p1) jumpr r31 - } - { - r0 = neg(r0) - jumpr r31 - } -FUNCTION_END __hexagon_divsi3 - - .globl __qdsp_divsi3 - .set __qdsp_divsi3, __hexagon_divsi3 diff --git a/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s b/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s deleted file mode 100644 index e77b7db0332..00000000000 --- a/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s +++ /dev/null @@ -1,266 +0,0 @@ - .text - .global __hexagon_fast2_dadd_asm - .type __hexagon_fast2_dadd_asm, @function -__hexagon_fast2_dadd_asm: - .falign - { - R7:6 = VABSDIFFH(R1:0, R3:2) - R9 = #62 - R4 = SXTH(R0) - R5 = SXTH(R2) - } { - R6 = SXTH(R6) - P0 = CMP.GT(R4, R5); - if ( P0.new) R8 = add(R4, #1) - if (!P0.new) R8 = add(R5, #1) - } { - if ( P0) R4 = #1 - if (!P0) R5 = #1 - R0.L = #0 - R6 = MIN(R6, R9) - } { - if (!P0) R4 = add(R6, #1) - if ( P0) R5 = add(R6, #1) - R2.L = #0 - R11:10 = #0 - } { - R1:0 = ASR(R1:0, R4) - R3:2 = ASR(R3:2, R5) - } { - R1:0 = add(R1:0, R3:2) - R10.L = #0x8001 - } { - R4 = clb(R1:0) - R9 = #58 - } { - R4 = add(R4, #-1) - p0 = cmp.gt(R4, R9) - } { - R1:0 = ASL(R1:0, R4) - R8 = SUB(R8, R4) - if(p0) jump .Ldenorma - } { - R0 = insert(R8, #16, #0) - jumpr r31 - } -.Ldenorma: - { - R1:0 = R11:10 - jumpr r31 - } - .text - .global __hexagon_fast2_dsub_asm - .type __hexagon_fast2_dsub_asm, @function -__hexagon_fast2_dsub_asm: - .falign - { - R7:6 = VABSDIFFH(R1:0, R3:2) - R9 = #62 - R4 = SXTH(R0) - R5 = SXTH(R2) - } { - R6 = SXTH(R6) - P0 = CMP.GT(R4, R5); - if ( P0.new) R8 = add(R4, #1) - if (!P0.new) R8 = add(R5, #1) - } { - if ( P0) R4 = #1 - if (!P0) R5 = #1 - R0.L = #0 - R6 = MIN(R6, R9) - } { - if (!P0) R4 = add(R6, #1) - if ( P0) R5 = add(R6, #1) - R2.L = #0 - R11:10 = #0 - } { - R1:0 = ASR(R1:0, R4) - R3:2 = ASR(R3:2, R5) - } { - R1:0 = sub(R1:0, R3:2) - R10.L = #0x8001 - } { - R4 = clb(R1:0) - R9 = #58 - } { - R4 = add(R4, #-1) - p0 = cmp.gt(R4, R9) - } { - R1:0 = ASL(R1:0, R4) - R8 = SUB(R8, R4) - if(p0) jump .Ldenorm - } { - R0 = insert(R8, #16, #0) - jumpr r31 - } -.Ldenorm: - { - R1:0 = R11:10 - jumpr r31 - } - .text - .global __hexagon_fast2_dmpy_asm - .type __hexagon_fast2_dmpy_asm, @function -__hexagon_fast2_dmpy_asm: - .falign - { - R13= lsr(R2, #16) - R5 = sxth(R2) - R4 = sxth(R0) - R12= lsr(R0, #16) - } - { - R11:10 = mpy(R1, R3) - R7:6 = mpy(R1, R13) - R0.L = #0x0 - R15:14 = #0 - } - { - R11:10 = add(R11:10, R11:10) - R7:6 += mpy(R3, R12) - R2.L = #0x0 - R15.H = #0x8000 - } - { - R7:6 = asr(R7:6, #15) - R12.L = #0x8001 - p1 = cmp.eq(R1:0, R3:2) - } - { - R7:6 = add(R7:6, R11:10) - R8 = add(R4, R5) - p2 = cmp.eq(R1:0, R15:14) - } - { - R9 = clb(R7:6) - R3:2 = abs(R7:6) - R11 = #58 - } - { - p1 = and(p1, p2) - R8 = sub(R8, R9) - R9 = add(R9, #-1) - p0 = cmp.gt(R9, R11) - } - { - R8 = add(R8, #1) - R1:0 = asl(R7:6, R9) - if(p1) jump .Lsat - } - { - R0 = insert(R8,#16, #0) - if(!p0) jumpr r31 - } - { - R0 = insert(R12,#16, #0) - jumpr r31 - } -.Lsat: - { - R1:0 = #-1 - } - { - R1:0 = lsr(R1:0, #1) - } - { - R0 = insert(R8,#16, #0) - jumpr r31 - } - .text - .global __hexagon_fast2_qd2f_asm - .type __hexagon_fast2_qd2f_asm, @function -__hexagon_fast2_qd2f_asm: - .falign - { - R3 = abs(R1):sat - R4 = sxth(R0) - R5 = #0x40 - R6.L = #0xffc0 - } - { - R0 = extractu(R3, #8, #0) - p2 = cmp.gt(R4, #126) - p3 = cmp.ge(R4, #-126) - R6.H = #0x7fff - } - { - p1 = cmp.eq(R0,#0x40) - if(p1.new) R5 = #0 - R4 = add(R4, #126) - if(!p3) jump .Lmin - } - { - p0 = bitsset(R3, R6) - R0.L = #0x0000 - R2 = add(R3, R5) - R7 = lsr(R6, #8) - } - { - if(p0) R4 = add(R4, #1) - if(p0) R3 = #0 - R2 = lsr(R2, #7) - R0.H = #0x8000 - } - { - R0 = and(R0, R1) - R6 &= asl(R4, #23) - if(!p0) R3 = and(R2, R7) - if(p2) jump .Lmax - } - { - R0 += add(R6, R3) - jumpr r31 - } -.Lmax: - { - R0.L = #0xffff; - } - { - R0.H = #0x7f7f; - jumpr r31 - } -.Lmin: - { - R0 = #0x0 - jumpr r31 - } - .text - .global __hexagon_fast2_f2qd_asm - .type __hexagon_fast2_f2qd_asm, @function -__hexagon_fast2_f2qd_asm: - - - - - - - - .falign - { - R1 = asl(R0, #7) - p0 = tstbit(R0, #31) - R5:4 = #0 - R3 = add(R0,R0) - } - { - R1 = setbit(R1, #30) - R0= extractu(R0,#8,#23) - R4.L = #0x8001 - p1 = cmp.eq(R3, #0) - } - { - R1= extractu(R1, #31, #0) - R0= add(R0, #-126) - R2 = #0 - if(p1) jump .Lminqd - } - { - R0 = zxth(R0) - if(p0) R1= sub(R2, R1) - jumpr r31 - } -.Lminqd: - { - R1:0 = R5:4 - jumpr r31 - } diff --git a/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s b/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s deleted file mode 100644 index 3251057d78c..00000000000 --- a/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s +++ /dev/null @@ -1,187 +0,0 @@ - .text - .global __hexagon_fast2ldadd_asm - .type __hexagon_fast2ldadd_asm, @function -__hexagon_fast2ldadd_asm: - .falign - { - R4 = memw(r29+#8) - R5 = memw(r29+#24) - r7 = r0 - } - { - R6 = sub(R4, R5):sat - P0 = CMP.GT(R4, R5); - if ( P0.new) R8 = add(R4, #1) - if (!P0.new) R8 = add(R5, #1) - } { - R6 = abs(R6):sat - if ( P0) R4 = #1 - if (!P0) R5 = #1 - R9 = #62 - } { - R6 = MIN(R6, R9) - R1:0 = memd(r29+#0) - R3:2 = memd(r29+#16) - } { - if (!P0) R4 = add(R6, #1) - if ( P0) R5 = add(R6, #1) - } { - R1:0 = ASR(R1:0, R4) - R3:2 = ASR(R3:2, R5) - } { - R1:0 = add(R1:0, R3:2) - R3:2 = #0 - } { - R4 = clb(R1:0) - R9.L =#0x0001 - } { - R8 -= add(R4, #-1) - R4 = add(R4, #-1) - p0 = cmp.gt(R4, #58) - R9.H =#0x8000 - } { - if(!p0)memw(r7+#8) = R8 - R1:0 = ASL(R1:0, R4) - if(p0) jump .Ldenorma1 - } { - memd(r7+#0) = R1:0 - jumpr r31 - } -.Ldenorma1: - memd(r7+#0) = R3:2 - { - memw(r7+#8) = R9 - jumpr r31 - } - .text - .global __hexagon_fast2ldsub_asm - .type __hexagon_fast2ldsub_asm, @function -__hexagon_fast2ldsub_asm: - .falign - { - R4 = memw(r29+#8) - R5 = memw(r29+#24) - r7 = r0 - } - { - R6 = sub(R4, R5):sat - P0 = CMP.GT(R4, R5); - if ( P0.new) R8 = add(R4, #1) - if (!P0.new) R8 = add(R5, #1) - } { - R6 = abs(R6):sat - if ( P0) R4 = #1 - if (!P0) R5 = #1 - R9 = #62 - } { - R6 = min(R6, R9) - R1:0 = memd(r29+#0) - R3:2 = memd(r29+#16) - } { - if (!P0) R4 = add(R6, #1) - if ( P0) R5 = add(R6, #1) - } { - R1:0 = ASR(R1:0, R4) - R3:2 = ASR(R3:2, R5) - } { - R1:0 = sub(R1:0, R3:2) - R3:2 = #0 - } { - R4 = clb(R1:0) - R9.L =#0x0001 - } { - R8 -= add(R4, #-1) - R4 = add(R4, #-1) - p0 = cmp.gt(R4, #58) - R9.H =#0x8000 - } { - if(!p0)memw(r7+#8) = R8 - R1:0 = asl(R1:0, R4) - if(p0) jump .Ldenorma_s - } { - memd(r7+#0) = R1:0 - jumpr r31 - } -.Ldenorma_s: - memd(r7+#0) = R3:2 - { - memw(r7+#8) = R9 - jumpr r31 - } - .text - .global __hexagon_fast2ldmpy_asm - .type __hexagon_fast2ldmpy_asm, @function -__hexagon_fast2ldmpy_asm: - .falign - { - R15:14 = memd(r29+#0) - R3:2 = memd(r29+#16) - R13:12 = #0 - } - { - R8= extractu(R2, #31, #1) - R9= extractu(R14, #31, #1) - R13.H = #0x8000 - } - { - R11:10 = mpy(R15, R3) - R7:6 = mpy(R15, R8) - R4 = memw(r29+#8) - R5 = memw(r29+#24) - } - { - R11:10 = add(R11:10, R11:10) - R7:6 += mpy(R3, R9) - } - { - R7:6 = asr(R7:6, #30) - R8.L = #0x0001 - p1 = cmp.eq(R15:14, R3:2) - } - { - R7:6 = add(R7:6, R11:10) - R4= add(R4, R5) - p2 = cmp.eq(R3:2, R13:12) - } - { - R9 = clb(R7:6) - R8.H = #0x8000 - p1 = and(p1, p2) - } - { - R4-= add(R9, #-1) - R9 = add(R9, #-1) - if(p1) jump .Lsat1 - } - { - R7:6 = asl(R7:6, R9) - memw(R0+#8) = R4 - p0 = cmp.gt(R9, #58) - if(p0.new) jump:NT .Ldenorm1 - } - { - memd(R0+#0) = R7:6 - jumpr r31 - } -.Lsat1: - { - R13:12 = #0 - R4+= add(R9, #1) - } - { - R13.H = #0x4000 - memw(R0+#8) = R4 - } - { - memd(R0+#0) = R13:12 - jumpr r31 - } -.Ldenorm1: - { - memw(R0+#8) = R8 - R15:14 = #0 - } - { - memd(R0+#0) = R15:14 - jumpr r31 - } diff --git a/library/compiler-builtins/src/hexagon/func_macro.s b/library/compiler-builtins/src/hexagon/func_macro.s deleted file mode 100644 index 9a1e11aebcb..00000000000 --- a/library/compiler-builtins/src/hexagon/func_macro.s +++ /dev/null @@ -1,12 +0,0 @@ - .macro FUNCTION_BEGIN name - .text - .p2align 5 - .globl \name - .type \name, @function -\name: - .endm - - .macro FUNCTION_END name - .size \name, . - \name - .endm - diff --git a/library/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s b/library/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s deleted file mode 100644 index 89f69010aa4..00000000000 --- a/library/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s +++ /dev/null @@ -1,91 +0,0 @@ - .text - - - - - - - .globl hexagon_memcpy_forward_vp4cp4n2 - .balign 32 - .type hexagon_memcpy_forward_vp4cp4n2,@function -hexagon_memcpy_forward_vp4cp4n2: - - - - - { - r3 = sub(##4096, r1) - r5 = lsr(r2, #3) - } - { - - - r3 = extractu(r3, #10, #2) - r4 = extractu(r3, #7, #5) - } - { - r3 = minu(r2, r3) - r4 = minu(r5, r4) - } - { - r4 = or(r4, ##2105344) - p0 = cmp.eq(r3, #0) - if (p0.new) jump:nt .Lskipprolog - } - l2fetch(r1, r4) - { - loop0(.Lprolog, r3) - r2 = sub(r2, r3) - } - .falign -.Lprolog: - { - r4 = memw(r1++#4) - memw(r0++#4) = r4.new - } :endloop0 -.Lskipprolog: - { - - r3 = lsr(r2, #10) - if (cmp.eq(r3.new, #0)) jump:nt .Lskipmain - } - { - loop1(.Lout, r3) - r2 = extractu(r2, #10, #0) - r3 = ##2105472 - } - - .falign -.Lout: - - l2fetch(r1, r3) - loop0(.Lpage, #512) - .falign -.Lpage: - r5:4 = memd(r1++#8) - { - memw(r0++#8) = r4 - memw(r0+#4) = r5 - } :endloop0:endloop1 -.Lskipmain: - { - r3 = ##2105344 - r4 = lsr(r2, #3) - p0 = cmp.eq(r2, #0) - if (p0.new) jumpr:nt r31 - } - { - r3 = or(r3, r4) - loop0(.Lepilog, r2) - } - l2fetch(r1, r3) - .falign -.Lepilog: - { - r4 = memw(r1++#4) - memw(r0++#4) = r4.new - } :endloop0 - - jumpr r31 - -.size hexagon_memcpy_forward_vp4cp4n2, . - hexagon_memcpy_forward_vp4cp4n2 diff --git a/library/compiler-builtins/src/hexagon/memcpy_likely_aligned.s b/library/compiler-builtins/src/hexagon/memcpy_likely_aligned.s deleted file mode 100644 index 7e9b62f6a79..00000000000 --- a/library/compiler-builtins/src/hexagon/memcpy_likely_aligned.s +++ /dev/null @@ -1,42 +0,0 @@ - -FUNCTION_BEGIN __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes - { - p0 = bitsclr(r1,#7) - p0 = bitsclr(r0,#7) - if (p0.new) r5:4 = memd(r1) - r3 = #-3 - } - { - if (!p0) jump .Lmemcpy_call - if (p0) memd(r0++#8) = r5:4 - if (p0) r5:4 = memd(r1+#8) - r3 += lsr(r2,#3) - } - { - memd(r0++#8) = r5:4 - r5:4 = memd(r1+#16) - r1 = add(r1,#24) - loop0(1f,r3) - } - .falign -1: - { - memd(r0++#8) = r5:4 - r5:4 = memd(r1++#8) - }:endloop0 - { - memd(r0) = r5:4 - r0 -= add(r2,#-8) - jumpr r31 - } -FUNCTION_END __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes - -.Lmemcpy_call: - - jump memcpy@PLT - - - - - .globl __qdsp_memcpy_likely_aligned_min32bytes_mult8bytes - .set __qdsp_memcpy_likely_aligned_min32bytes_mult8bytes, __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes diff --git a/library/compiler-builtins/src/hexagon/moddi3.s b/library/compiler-builtins/src/hexagon/moddi3.s deleted file mode 100644 index 53ea6d52a58..00000000000 --- a/library/compiler-builtins/src/hexagon/moddi3.s +++ /dev/null @@ -1,63 +0,0 @@ - - -FUNCTION_BEGIN __hexagon_moddi3 - { - p3 = tstbit(r1,#31) - } - { - r1:0 = abs(r1:0) - r3:2 = abs(r3:2) - } - { - r6 = cl0(r1:0) - r7 = cl0(r3:2) - r5:4 = r3:2 - r3:2 = r1:0 - } - { - r10 = sub(r7,r6) - r1:0 = #0 - r15:14 = #1 - } - { - r11 = add(r10,#1) - r13:12 = lsl(r5:4,r10) - r15:14 = lsl(r15:14,r10) - } - { - p0 = cmp.gtu(r5:4,r3:2) - loop0(1f,r11) - } - { - if (p0) jump .hexagon_moddi3_return - } - .falign -1: - { - p0 = cmp.gtu(r13:12,r3:2) - } - { - r7:6 = sub(r3:2, r13:12) - r9:8 = add(r1:0, r15:14) - } - { - r1:0 = vmux(p0, r1:0, r9:8) - r3:2 = vmux(p0, r3:2, r7:6) - } - { - r15:14 = lsr(r15:14, #1) - r13:12 = lsr(r13:12, #1) - }:endloop0 - -.hexagon_moddi3_return: - { - r1:0 = neg(r3:2) - } - { - r1:0 = vmux(p3,r1:0,r3:2) - jumpr r31 - } -FUNCTION_END __hexagon_moddi3 - - .globl __qdsp_moddi3 - .set __qdsp_moddi3, __hexagon_moddi3 diff --git a/library/compiler-builtins/src/hexagon/modsi3.s b/library/compiler-builtins/src/hexagon/modsi3.s deleted file mode 100644 index c4ae7e59edc..00000000000 --- a/library/compiler-builtins/src/hexagon/modsi3.s +++ /dev/null @@ -1,44 +0,0 @@ - - -FUNCTION_BEGIN __hexagon_modsi3 - { - p2 = cmp.ge(r0,#0) - r2 = abs(r0) - r1 = abs(r1) - } - { - r3 = cl0(r2) - r4 = cl0(r1) - p0 = cmp.gtu(r1,r2) - } - { - r3 = sub(r4,r3) - if (p0) jumpr r31 - } - { - p1 = cmp.eq(r3,#0) - loop0(1f,r3) - r0 = r2 - r2 = lsl(r1,r3) - } - .falign -1: - { - p0 = cmp.gtu(r2,r0) - if (!p0.new) r0 = sub(r0,r2) - r2 = lsr(r2,#1) - if (p1) r1 = #0 - }:endloop0 - { - p0 = cmp.gtu(r2,r0) - if (!p0.new) r0 = sub(r0,r1) - if (p2) jumpr r31 - } - { - r0 = neg(r0) - jumpr r31 - } -FUNCTION_END __hexagon_modsi3 - - .globl __qdsp_modsi3 - .set __qdsp_modsi3, __hexagon_modsi3 diff --git a/library/compiler-builtins/src/hexagon/sfdiv_opt.s b/library/compiler-builtins/src/hexagon/sfdiv_opt.s deleted file mode 100644 index 26c91f15cbb..00000000000 --- a/library/compiler-builtins/src/hexagon/sfdiv_opt.s +++ /dev/null @@ -1,42 +0,0 @@ - -FUNCTION_BEGIN __hexagon_divsf3 - { - r2,p0 = sfrecipa(r0,r1) - r4 = sffixupd(r0,r1) - r3 = ##0x3f800000 - } - { - r5 = sffixupn(r0,r1) - r3 -= sfmpy(r4,r2):lib - r6 = ##0x80000000 - r7 = r3 - } - { - r2 += sfmpy(r3,r2):lib - r3 = r7 - r6 = r5 - r0 = and(r6,r5) - } - { - r3 -= sfmpy(r4,r2):lib - r0 += sfmpy(r5,r2):lib - } - { - r2 += sfmpy(r3,r2):lib - r6 -= sfmpy(r0,r4):lib - } - { - r0 += sfmpy(r6,r2):lib - } - { - r5 -= sfmpy(r0,r4):lib - } - { - r0 += sfmpy(r5,r2,p0):scale - jumpr r31 - } -FUNCTION_END __hexagon_divsf3 - -.global __qdsp_divsf3 ; .set __qdsp_divsf3, __hexagon_divsf3 -.global __hexagon_fast_divsf3 ; .set __hexagon_fast_divsf3, __hexagon_divsf3 -.global __hexagon_fast2_divsf3 ; .set __hexagon_fast2_divsf3, __hexagon_divsf3 diff --git a/library/compiler-builtins/src/hexagon/sfsqrt_opt.s b/library/compiler-builtins/src/hexagon/sfsqrt_opt.s deleted file mode 100644 index c90af179754..00000000000 --- a/library/compiler-builtins/src/hexagon/sfsqrt_opt.s +++ /dev/null @@ -1,49 +0,0 @@ -FUNCTION_BEGIN __hexagon_sqrtf - { - r3,p0 = sfinvsqrta(r0) - r5 = sffixupr(r0) - r4 = ##0x3f000000 - r1:0 = combine(#0,#0) - } - { - r0 += sfmpy(r3,r5):lib - r1 += sfmpy(r3,r4):lib - r2 = r4 - r3 = r5 - } - { - r2 -= sfmpy(r0,r1):lib - p1 = sfclass(r5,#1) - - } - { - r0 += sfmpy(r0,r2):lib - r1 += sfmpy(r1,r2):lib - r2 = r4 - r3 = r5 - } - { - r2 -= sfmpy(r0,r1):lib - r3 -= sfmpy(r0,r0):lib - } - { - r0 += sfmpy(r1,r3):lib - r1 += sfmpy(r1,r2):lib - r2 = r4 - r3 = r5 - } - { - - r3 -= sfmpy(r0,r0):lib - if (p1) r0 = or(r0,r5) - } - { - r0 += sfmpy(r1,r3,p0):scale - jumpr r31 - } - -FUNCTION_END __hexagon_sqrtf - -.global __qdsp_sqrtf ; .set __qdsp_sqrtf, __hexagon_sqrtf -.global __hexagon_fast_sqrtf ; .set __hexagon_fast_sqrtf, __hexagon_sqrtf -.global __hexagon_fast2_sqrtf ; .set __hexagon_fast2_sqrtf, __hexagon_sqrtf diff --git a/library/compiler-builtins/src/hexagon/udivdi3.s b/library/compiler-builtins/src/hexagon/udivdi3.s deleted file mode 100644 index f0fffc23df0..00000000000 --- a/library/compiler-builtins/src/hexagon/udivdi3.s +++ /dev/null @@ -1,50 +0,0 @@ - - -FUNCTION_BEGIN __hexagon_udivdi3 - { - r6 = cl0(r1:0) - r7 = cl0(r3:2) - r5:4 = r3:2 - r3:2 = r1:0 - } - { - r10 = sub(r7,r6) - r1:0 = #0 - r15:14 = #1 - } - { - r11 = add(r10,#1) - r13:12 = lsl(r5:4,r10) - r15:14 = lsl(r15:14,r10) - } - { - p0 = cmp.gtu(r5:4,r3:2) - loop0(1f,r11) - } - { - if (p0) jumpr r31 - } - .falign -1: - { - p0 = cmp.gtu(r13:12,r3:2) - } - { - r7:6 = sub(r3:2, r13:12) - r9:8 = add(r1:0, r15:14) - } - { - r1:0 = vmux(p0, r1:0, r9:8) - r3:2 = vmux(p0, r3:2, r7:6) - } - { - r15:14 = lsr(r15:14, #1) - r13:12 = lsr(r13:12, #1) - }:endloop0 - { - jumpr r31 - } -FUNCTION_END __hexagon_udivdi3 - - .globl __qdsp_udivdi3 - .set __qdsp_udivdi3, __hexagon_udivdi3 diff --git a/library/compiler-builtins/src/hexagon/udivmoddi4.s b/library/compiler-builtins/src/hexagon/udivmoddi4.s deleted file mode 100644 index cbfb3987dd2..00000000000 --- a/library/compiler-builtins/src/hexagon/udivmoddi4.s +++ /dev/null @@ -1,50 +0,0 @@ - - -FUNCTION_BEGIN __hexagon_udivmoddi4 - { - r6 = cl0(r1:0) - r7 = cl0(r3:2) - r5:4 = r3:2 - r3:2 = r1:0 - } - { - r10 = sub(r7,r6) - r1:0 = #0 - r15:14 = #1 - } - { - r11 = add(r10,#1) - r13:12 = lsl(r5:4,r10) - r15:14 = lsl(r15:14,r10) - } - { - p0 = cmp.gtu(r5:4,r3:2) - loop0(1f,r11) - } - { - if (p0) jumpr r31 - } - .falign -1: - { - p0 = cmp.gtu(r13:12,r3:2) - } - { - r7:6 = sub(r3:2, r13:12) - r9:8 = add(r1:0, r15:14) - } - { - r1:0 = vmux(p0, r1:0, r9:8) - r3:2 = vmux(p0, r3:2, r7:6) - } - { - r15:14 = lsr(r15:14, #1) - r13:12 = lsr(r13:12, #1) - }:endloop0 - { - jumpr r31 - } -FUNCTION_END __hexagon_udivmoddi4 - - .globl __qdsp_udivmoddi4 - .set __qdsp_udivmoddi4, __hexagon_udivmoddi4 diff --git a/library/compiler-builtins/src/hexagon/udivmodsi4.s b/library/compiler-builtins/src/hexagon/udivmodsi4.s deleted file mode 100644 index 83489c51431..00000000000 --- a/library/compiler-builtins/src/hexagon/udivmodsi4.s +++ /dev/null @@ -1,39 +0,0 @@ - - -FUNCTION_BEGIN __hexagon_udivmodsi4 - { - r2 = cl0(r0) - r3 = cl0(r1) - r5:4 = combine(#1,#0) - p0 = cmp.gtu(r1,r0) - } - { - r6 = sub(r3,r2) - r4 = r1 - r1:0 = combine(r0,r4) - if (p0) jumpr r31 - } - { - r3:2 = vlslw(r5:4,r6) - loop0(1f,r6) - p0 = cmp.eq(r6,#0) - if (p0.new) r4 = #0 - } - .falign -1: - { - p0 = cmp.gtu(r2,r1) - if (!p0.new) r1 = sub(r1,r2) - if (!p0.new) r0 = add(r0,r3) - r3:2 = vlsrw(r3:2,#1) - }:endloop0 - { - p0 = cmp.gtu(r2,r1) - if (!p0.new) r1 = sub(r1,r4) - if (!p0.new) r0 = add(r0,r3) - jumpr r31 - } -FUNCTION_END __hexagon_udivmodsi4 - - .globl __qdsp_udivmodsi4 - .set __qdsp_udivmodsi4, __hexagon_udivmodsi4 diff --git a/library/compiler-builtins/src/hexagon/udivsi3.s b/library/compiler-builtins/src/hexagon/udivsi3.s deleted file mode 100644 index e0b94aa9982..00000000000 --- a/library/compiler-builtins/src/hexagon/udivsi3.s +++ /dev/null @@ -1,36 +0,0 @@ - - -FUNCTION_BEGIN __hexagon_udivsi3 - { - r2 = cl0(r0) - r3 = cl0(r1) - r5:4 = combine(#1,#0) - p0 = cmp.gtu(r1,r0) - } - { - r6 = sub(r3,r2) - r4 = r1 - r1:0 = combine(r0,r4) - if (p0) jumpr r31 - } - { - r3:2 = vlslw(r5:4,r6) - loop0(1f,r6) - } - .falign -1: - { - p0 = cmp.gtu(r2,r1) - if (!p0.new) r1 = sub(r1,r2) - if (!p0.new) r0 = add(r0,r3) - r3:2 = vlsrw(r3:2,#1) - }:endloop0 - { - p0 = cmp.gtu(r2,r1) - if (!p0.new) r0 = add(r0,r3) - jumpr r31 - } -FUNCTION_END __hexagon_udivsi3 - - .globl __qdsp_udivsi3 - .set __qdsp_udivsi3, __hexagon_udivsi3 diff --git a/library/compiler-builtins/src/hexagon/umoddi3.s b/library/compiler-builtins/src/hexagon/umoddi3.s deleted file mode 100644 index c76011c3e7a..00000000000 --- a/library/compiler-builtins/src/hexagon/umoddi3.s +++ /dev/null @@ -1,53 +0,0 @@ - - -FUNCTION_BEGIN __hexagon_umoddi3 - { - r6 = cl0(r1:0) - r7 = cl0(r3:2) - r5:4 = r3:2 - r3:2 = r1:0 - } - { - r10 = sub(r7,r6) - r1:0 = #0 - r15:14 = #1 - } - { - r11 = add(r10,#1) - r13:12 = lsl(r5:4,r10) - r15:14 = lsl(r15:14,r10) - } - { - p0 = cmp.gtu(r5:4,r3:2) - loop0(1f,r11) - } - { - if (p0) jump .hexagon_umoddi3_return - } - .falign -1: - { - p0 = cmp.gtu(r13:12,r3:2) - } - { - r7:6 = sub(r3:2, r13:12) - r9:8 = add(r1:0, r15:14) - } - { - r1:0 = vmux(p0, r1:0, r9:8) - r3:2 = vmux(p0, r3:2, r7:6) - } - { - r15:14 = lsr(r15:14, #1) - r13:12 = lsr(r13:12, #1) - }:endloop0 - -.hexagon_umoddi3_return: - { - r1:0 = r3:2 - jumpr r31 - } -FUNCTION_END __hexagon_umoddi3 - - .globl __qdsp_umoddi3 - .set __qdsp_umoddi3, __hexagon_umoddi3 diff --git a/library/compiler-builtins/src/hexagon/umodsi3.s b/library/compiler-builtins/src/hexagon/umodsi3.s deleted file mode 100644 index 1b592a7c561..00000000000 --- a/library/compiler-builtins/src/hexagon/umodsi3.s +++ /dev/null @@ -1,34 +0,0 @@ - - -FUNCTION_BEGIN __hexagon_umodsi3 - { - r2 = cl0(r0) - r3 = cl0(r1) - p0 = cmp.gtu(r1,r0) - } - { - r2 = sub(r3,r2) - if (p0) jumpr r31 - } - { - loop0(1f,r2) - p1 = cmp.eq(r2,#0) - r2 = lsl(r1,r2) - } - .falign -1: - { - p0 = cmp.gtu(r2,r0) - if (!p0.new) r0 = sub(r0,r2) - r2 = lsr(r2,#1) - if (p1) r1 = #0 - }:endloop0 - { - p0 = cmp.gtu(r2,r0) - if (!p0.new) r0 = sub(r0,r1) - jumpr r31 - } -FUNCTION_END __hexagon_umodsi3 - - .globl __qdsp_umodsi3 - .set __qdsp_umodsi3, __hexagon_umodsi3 diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs deleted file mode 100644 index 1f84e8eb1e1..00000000000 --- a/library/compiler-builtins/src/int/addsub.rs +++ /dev/null @@ -1,104 +0,0 @@ -use crate::int::{DInt, Int, MinInt}; - -trait UAddSub: DInt + Int { - fn uadd(self, other: Self) -> Self { - let (lo, carry) = self.lo().overflowing_add(other.lo()); - let hi = self.hi().wrapping_add(other.hi()); - let carry = if carry { Self::H::ONE } else { Self::H::ZERO }; - Self::from_lo_hi(lo, hi.wrapping_add(carry)) - } - fn uadd_one(self) -> Self { - let (lo, carry) = self.lo().overflowing_add(Self::H::ONE); - let carry = if carry { Self::H::ONE } else { Self::H::ZERO }; - Self::from_lo_hi(lo, self.hi().wrapping_add(carry)) - } - fn usub(self, other: Self) -> Self { - let uneg = (!other).uadd_one(); - self.uadd(uneg) - } -} - -impl UAddSub for u128 {} - -trait AddSub: Int -where - ::UnsignedInt: UAddSub, -{ - fn add(self, other: Self) -> Self { - Self::from_unsigned(self.unsigned().uadd(other.unsigned())) - } - fn sub(self, other: Self) -> Self { - Self::from_unsigned(self.unsigned().usub(other.unsigned())) - } -} - -impl AddSub for u128 {} -impl AddSub for i128 {} - -trait Addo: AddSub -where - ::UnsignedInt: UAddSub, -{ - fn addo(self, other: Self) -> (Self, bool) { - let sum = AddSub::add(self, other); - (sum, (other < Self::ZERO) != (sum < self)) - } -} - -impl Addo for i128 {} -impl Addo for u128 {} - -trait Subo: AddSub -where - ::UnsignedInt: UAddSub, -{ - fn subo(self, other: Self) -> (Self, bool) { - let sum = AddSub::sub(self, other); - (sum, (other < Self::ZERO) != (self < sum)) - } -} - -impl Subo for i128 {} -impl Subo for u128 {} - -intrinsics! { - pub extern "C" fn __rust_i128_add(a: i128, b: i128) -> i128 { - AddSub::add(a,b) - } - - pub extern "C" fn __rust_i128_addo(a: i128, b: i128, oflow: &mut i32) -> i128 { - let (add, o) = a.addo(b); - *oflow = o.into(); - add - } - - pub extern "C" fn __rust_u128_add(a: u128, b: u128) -> u128 { - AddSub::add(a,b) - } - - pub extern "C" fn __rust_u128_addo(a: u128, b: u128, oflow: &mut i32) -> u128 { - let (add, o) = a.addo(b); - *oflow = o.into(); - add - } - - pub extern "C" fn __rust_i128_sub(a: i128, b: i128) -> i128 { - AddSub::sub(a,b) - } - - pub extern "C" fn __rust_i128_subo(a: i128, b: i128, oflow: &mut i32) -> i128 { - let (sub, o) = a.subo(b); - *oflow = o.into(); - sub - } - - pub extern "C" fn __rust_u128_sub(a: u128, b: u128) -> u128 { - AddSub::sub(a,b) - } - - pub extern "C" fn __rust_u128_subo(a: u128, b: u128, oflow: &mut i32) -> u128 { - let (sub, o) = a.subo(b); - *oflow = o.into(); - sub - } -} diff --git a/library/compiler-builtins/src/int/big.rs b/library/compiler-builtins/src/int/big.rs deleted file mode 100644 index 0ef3caaedff..00000000000 --- a/library/compiler-builtins/src/int/big.rs +++ /dev/null @@ -1,294 +0,0 @@ -//! Integers used for wide operations, larger than `u128`. - -#![allow(unused)] - -use crate::int::{DInt, HInt, Int, MinInt}; -use core::{fmt, ops}; - -const WORD_LO_MASK: u64 = 0x00000000ffffffff; -const WORD_HI_MASK: u64 = 0xffffffff00000000; -const WORD_FULL_MASK: u64 = 0xffffffffffffffff; -const U128_LO_MASK: u128 = u64::MAX as u128; -const U128_HI_MASK: u128 = (u64::MAX as u128) << 64; - -/// A 256-bit unsigned integer represented as 4 64-bit limbs. -/// -/// Each limb is a native-endian number, but the array is little-limb-endian. -#[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] -pub struct u256(pub [u64; 4]); - -impl u256 { - pub const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX]); - - /// Reinterpret as a signed integer - pub fn signed(self) -> i256 { - i256(self.0) - } -} - -/// A 256-bit signed integer represented as 4 64-bit limbs. -/// -/// Each limb is a native-endian number, but the array is little-limb-endian. -#[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] -pub struct i256(pub [u64; 4]); - -impl i256 { - /// Reinterpret as an unsigned integer - pub fn unsigned(self) -> u256 { - u256(self.0) - } -} - -impl MinInt for u256 { - type OtherSign = i256; - - type UnsignedInt = u256; - - const SIGNED: bool = false; - const BITS: u32 = 256; - const ZERO: Self = Self([0u64; 4]); - const ONE: Self = Self([1, 0, 0, 0]); - const MIN: Self = Self([0u64; 4]); - const MAX: Self = Self([u64::MAX; 4]); -} - -impl MinInt for i256 { - type OtherSign = u256; - - type UnsignedInt = u256; - - const SIGNED: bool = false; - const BITS: u32 = 256; - const ZERO: Self = Self([0u64; 4]); - const ONE: Self = Self([1, 0, 0, 0]); - const MIN: Self = Self([0, 0, 0, 1 << 63]); - const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX << 1]); -} - -macro_rules! impl_common { - ($ty:ty) => { - impl ops::BitOr for $ty { - type Output = Self; - - fn bitor(mut self, rhs: Self) -> Self::Output { - self.0[0] |= rhs.0[0]; - self.0[1] |= rhs.0[1]; - self.0[2] |= rhs.0[2]; - self.0[3] |= rhs.0[3]; - self - } - } - - impl ops::Not for $ty { - type Output = Self; - - fn not(self) -> Self::Output { - Self([!self.0[0], !self.0[1], !self.0[2], !self.0[3]]) - } - } - - impl ops::Shl for $ty { - type Output = Self; - - fn shl(self, rhs: u32) -> Self::Output { - unimplemented!("only used to meet trait bounds") - } - } - }; -} - -impl_common!(i256); -impl_common!(u256); - -impl ops::Shr for u256 { - type Output = Self; - - fn shr(self, rhs: u32) -> Self::Output { - assert!(rhs < Self::BITS, "attempted to shift right with overflow"); - - if rhs == 0 { - return self; - } - - let mut ret = self; - let byte_shift = rhs / 64; - let bit_shift = rhs % 64; - - for idx in 0..4 { - let base_idx = idx + byte_shift as usize; - - let Some(base) = ret.0.get(base_idx) else { - ret.0[idx] = 0; - continue; - }; - - let mut new_val = base >> bit_shift; - - if let Some(new) = ret.0.get(base_idx + 1) { - new_val |= new.overflowing_shl(64 - bit_shift).0; - } - - ret.0[idx] = new_val; - } - - ret - } -} - -macro_rules! word { - (1, $val:expr) => { - (($val >> (32 * 3)) & Self::from(WORD_LO_MASK)) as u64 - }; - (2, $val:expr) => { - (($val >> (32 * 2)) & Self::from(WORD_LO_MASK)) as u64 - }; - (3, $val:expr) => { - (($val >> (32 * 1)) & Self::from(WORD_LO_MASK)) as u64 - }; - (4, $val:expr) => { - (($val >> (32 * 0)) & Self::from(WORD_LO_MASK)) as u64 - }; -} - -impl HInt for u128 { - type D = u256; - - fn widen(self) -> Self::D { - let w0 = self & u128::from(u64::MAX); - let w1 = (self >> u64::BITS) & u128::from(u64::MAX); - u256([w0 as u64, w1 as u64, 0, 0]) - } - - fn zero_widen(self) -> Self::D { - self.widen() - } - - fn zero_widen_mul(self, rhs: Self) -> Self::D { - let product11: u64 = word!(1, self) * word!(1, rhs); - let product12: u64 = word!(1, self) * word!(2, rhs); - let product13: u64 = word!(1, self) * word!(3, rhs); - let product14: u64 = word!(1, self) * word!(4, rhs); - let product21: u64 = word!(2, self) * word!(1, rhs); - let product22: u64 = word!(2, self) * word!(2, rhs); - let product23: u64 = word!(2, self) * word!(3, rhs); - let product24: u64 = word!(2, self) * word!(4, rhs); - let product31: u64 = word!(3, self) * word!(1, rhs); - let product32: u64 = word!(3, self) * word!(2, rhs); - let product33: u64 = word!(3, self) * word!(3, rhs); - let product34: u64 = word!(3, self) * word!(4, rhs); - let product41: u64 = word!(4, self) * word!(1, rhs); - let product42: u64 = word!(4, self) * word!(2, rhs); - let product43: u64 = word!(4, self) * word!(3, rhs); - let product44: u64 = word!(4, self) * word!(4, rhs); - - let sum0: u128 = u128::from(product44); - let sum1: u128 = u128::from(product34) + u128::from(product43); - let sum2: u128 = u128::from(product24) + u128::from(product33) + u128::from(product42); - let sum3: u128 = u128::from(product14) - + u128::from(product23) - + u128::from(product32) - + u128::from(product41); - let sum4: u128 = u128::from(product13) + u128::from(product22) + u128::from(product31); - let sum5: u128 = u128::from(product12) + u128::from(product21); - let sum6: u128 = u128::from(product11); - - let r0: u128 = - (sum0 & u128::from(WORD_FULL_MASK)) + ((sum1 & u128::from(WORD_LO_MASK)) << 32); - let r1: u128 = (sum0 >> 64) - + ((sum1 >> 32) & u128::from(WORD_FULL_MASK)) - + (sum2 & u128::from(WORD_FULL_MASK)) - + ((sum3 << 32) & u128::from(WORD_HI_MASK)); - - let (lo, carry) = r0.overflowing_add(r1 << 64); - let hi = (r1 >> 64) - + (sum1 >> 96) - + (sum2 >> 64) - + (sum3 >> 32) - + sum4 - + (sum5 << 32) - + (sum6 << 64) - + u128::from(carry); - - u256([ - (lo & U128_LO_MASK) as u64, - ((lo >> 64) & U128_LO_MASK) as u64, - (hi & U128_LO_MASK) as u64, - ((hi >> 64) & U128_LO_MASK) as u64, - ]) - } - - fn widen_mul(self, rhs: Self) -> Self::D { - self.zero_widen_mul(rhs) - } - - fn widen_hi(self) -> Self::D { - self.widen() << ::BITS - } -} - -impl HInt for i128 { - type D = i256; - - fn widen(self) -> Self::D { - let mut ret = self.unsigned().zero_widen().signed(); - if self.is_negative() { - ret.0[2] = u64::MAX; - ret.0[3] = u64::MAX; - } - ret - } - - fn zero_widen(self) -> Self::D { - self.unsigned().zero_widen().signed() - } - - fn zero_widen_mul(self, rhs: Self) -> Self::D { - self.unsigned().zero_widen_mul(rhs.unsigned()).signed() - } - - fn widen_mul(self, rhs: Self) -> Self::D { - unimplemented!("signed i128 widening multiply is not used") - } - - fn widen_hi(self) -> Self::D { - self.widen() << ::BITS - } -} - -impl DInt for u256 { - type H = u128; - - fn lo(self) -> Self::H { - let mut tmp = [0u8; 16]; - tmp[..8].copy_from_slice(&self.0[0].to_le_bytes()); - tmp[8..].copy_from_slice(&self.0[1].to_le_bytes()); - u128::from_le_bytes(tmp) - } - - fn hi(self) -> Self::H { - let mut tmp = [0u8; 16]; - tmp[..8].copy_from_slice(&self.0[2].to_le_bytes()); - tmp[8..].copy_from_slice(&self.0[3].to_le_bytes()); - u128::from_le_bytes(tmp) - } -} - -impl DInt for i256 { - type H = i128; - - fn lo(self) -> Self::H { - let mut tmp = [0u8; 16]; - tmp[..8].copy_from_slice(&self.0[0].to_le_bytes()); - tmp[8..].copy_from_slice(&self.0[1].to_le_bytes()); - i128::from_le_bytes(tmp) - } - - fn hi(self) -> Self::H { - let mut tmp = [0u8; 16]; - tmp[..8].copy_from_slice(&self.0[2].to_le_bytes()); - tmp[8..].copy_from_slice(&self.0[3].to_le_bytes()); - i128::from_le_bytes(tmp) - } -} diff --git a/library/compiler-builtins/src/int/bswap.rs b/library/compiler-builtins/src/int/bswap.rs deleted file mode 100644 index 9df80204d0e..00000000000 --- a/library/compiler-builtins/src/int/bswap.rs +++ /dev/null @@ -1,22 +0,0 @@ -intrinsics! { - #[maybe_use_optimized_c_shim] - #[avr_skip] - /// Swaps bytes in 32-bit number - pub extern "C" fn __bswapsi2(x: u32) -> u32 { - x.swap_bytes() - } - - #[maybe_use_optimized_c_shim] - #[avr_skip] - /// Swaps bytes in 64-bit number - pub extern "C" fn __bswapdi2(x: u64) -> u64 { - x.swap_bytes() - } - - #[maybe_use_optimized_c_shim] - #[avr_skip] - /// Swaps bytes in 128-bit number - pub extern "C" fn __bswapti2(x: u128) -> u128 { - x.swap_bytes() - } -} diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs deleted file mode 100644 index ba735aa7462..00000000000 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ /dev/null @@ -1,168 +0,0 @@ -// Note: these functions happen to produce the correct `usize::leading_zeros(0)` value -// without a explicit zero check. Zero is probably common enough that it could warrant -// adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. -// Compilers will insert the check for zero in cases where it is needed. - -#[cfg(feature = "public-test-deps")] -pub use implementation::{leading_zeros_default, leading_zeros_riscv}; -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use implementation::{leading_zeros_default, leading_zeros_riscv}; - -mod implementation { - use crate::int::{CastInto, Int}; - - /// Returns the number of leading binary zeros in `x`. - #[allow(dead_code)] - pub fn leading_zeros_default>(x: T) -> usize { - // The basic idea is to test if the higher bits of `x` are zero and bisect the number - // of leading zeros. It is possible for all branches of the bisection to use the same - // code path by conditionally shifting the higher parts down to let the next bisection - // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` - // and adding to the number of zeros, it is slightly faster to start with - // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, - // because it simplifies the final bisection step. - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS as usize; - // a temporary - let mut t: T; - - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - t = x >> 32; - if t != T::ZERO { - z -= 32; - x = t; - } - } - if T::BITS >= 32 { - t = x >> 16; - if t != T::ZERO { - z -= 16; - x = t; - } - } - const { assert!(T::BITS >= 16) }; - t = x >> 8; - if t != T::ZERO { - z -= 8; - x = t; - } - t = x >> 4; - if t != T::ZERO { - z -= 4; - x = t; - } - t = x >> 2; - if t != T::ZERO { - z -= 2; - x = t; - } - // the last two bisections are combined into one conditional - t = x >> 1; - if t != T::ZERO { - z - 2 - } else { - z - x.cast() - } - - // We could potentially save a few cycles by using the LUT trick from - // "https://embeddedgurus.com/state-space/2014/09/ - // fast-deterministic-and-portable-counting-leading-zeros/". - // However, 256 bytes for a LUT is too large for embedded use cases. We could remove - // the last 3 bisections and use this 16 byte LUT for the rest of the work: - //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; - //z -= LUT[x] as usize; - //z - // However, it ends up generating about the same number of instructions. When benchmarked - // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO - // execution effects. Changing to using a LUT and branching is risky for smaller cores. - } - - // The above method does not compile well on RISC-V (because of the lack of predicated - // instructions), producing code with many branches or using an excessively long - // branchless solution. This method takes advantage of the set-if-less-than instruction on - // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. - - /// Returns the number of leading binary zeros in `x`. - #[allow(dead_code)] - pub fn leading_zeros_riscv>(x: T) -> usize { - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS; - // a temporary - let mut t: u32; - - // RISC-V does not have a set-if-greater-than-or-equal instruction and - // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is - // still the most optimal method. A conditional set can only be turned into a single - // immediate instruction if `x` is compared with an immediate `imm` (that can fit into - // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the - // right). If we try to save an instruction by using `x < imm` for each bisection, we - // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, - // but the immediate will never fit into 12 bits and never save an instruction. - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise - // `t` is set to 0. - t = ((x >= (T::ONE << 32)) as u32) << 5; - // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the - // next step to process. - x >>= t; - // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential - // leading zeros - z -= t; - } - if T::BITS >= 32 { - t = ((x >= (T::ONE << 16)) as u32) << 4; - x >>= t; - z -= t; - } - const { assert!(T::BITS >= 16) }; - t = ((x >= (T::ONE << 8)) as u32) << 3; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 4)) as u32) << 2; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 2)) as u32) << 1; - x >>= t; - z -= t; - t = (x >= (T::ONE << 1)) as u32; - x >>= t; - z -= t; - // All bits except the LSB are guaranteed to be zero for this final bisection step. - // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. - z as usize - x.cast() - } -} - -intrinsics! { - /// Returns the number of leading binary zeros in `x` - pub extern "C" fn __clzsi2(x: u32) -> usize { - if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { - leading_zeros_riscv(x) - } else { - leading_zeros_default(x) - } - } - - /// Returns the number of leading binary zeros in `x` - pub extern "C" fn __clzdi2(x: u64) -> usize { - if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { - leading_zeros_riscv(x) - } else { - leading_zeros_default(x) - } - } - - /// Returns the number of leading binary zeros in `x` - pub extern "C" fn __clzti2(x: u128) -> usize { - let hi = (x >> 64) as u64; - if hi == 0 { - 64 + __clzdi2(x as u64) - } else { - __clzdi2(hi) - } - } -} diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs deleted file mode 100644 index 1f1be711bbd..00000000000 --- a/library/compiler-builtins/src/int/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -mod specialized_div_rem; - -pub mod addsub; -mod big; -pub mod bswap; -pub mod leading_zeros; -pub mod mul; -pub mod sdiv; -pub mod shift; -pub mod trailing_zeros; -mod traits; -pub mod udiv; - -pub use big::{i256, u256}; - -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; - -#[cfg(feature = "public-test-deps")] -pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs deleted file mode 100644 index 040c69342d1..00000000000 --- a/library/compiler-builtins/src/int/mul.rs +++ /dev/null @@ -1,142 +0,0 @@ -use crate::int::{DInt, HInt, Int}; - -trait Mul: DInt + Int -where - Self::H: DInt, -{ - fn mul(self, rhs: Self) -> Self { - // In order to prevent infinite recursion, we cannot use the `widen_mul` in this: - //self.lo().widen_mul(rhs.lo()) - // .wrapping_add(self.lo().wrapping_mul(rhs.hi()).widen_hi()) - // .wrapping_add(self.hi().wrapping_mul(rhs.lo()).widen_hi()) - - let lhs_lo = self.lo(); - let rhs_lo = rhs.lo(); - // construct the widening multiplication using only `Self::H` sized multiplications - let tmp_0 = lhs_lo.lo().zero_widen_mul(rhs_lo.lo()); - let tmp_1 = lhs_lo.lo().zero_widen_mul(rhs_lo.hi()); - let tmp_2 = lhs_lo.hi().zero_widen_mul(rhs_lo.lo()); - let tmp_3 = lhs_lo.hi().zero_widen_mul(rhs_lo.hi()); - // sum up all widening partials - let mul = Self::from_lo_hi(tmp_0, tmp_3) - .wrapping_add(tmp_1.zero_widen() << (Self::BITS / 4)) - .wrapping_add(tmp_2.zero_widen() << (Self::BITS / 4)); - // add the higher partials - mul.wrapping_add(lhs_lo.wrapping_mul(rhs.hi()).widen_hi()) - .wrapping_add(self.hi().wrapping_mul(rhs_lo).widen_hi()) - } -} - -impl Mul for u64 {} -impl Mul for i128 {} - -pub(crate) trait UMulo: DInt + Int { - fn mulo(self, rhs: Self) -> (Self, bool) { - match (self.hi().is_zero(), rhs.hi().is_zero()) { - // overflow is guaranteed - (false, false) => (self.wrapping_mul(rhs), true), - (true, false) => { - let mul_lo = self.lo().widen_mul(rhs.lo()); - let mul_hi = self.lo().widen_mul(rhs.hi()); - let (mul, o) = mul_lo.overflowing_add(mul_hi.lo().widen_hi()); - (mul, o || !mul_hi.hi().is_zero()) - } - (false, true) => { - let mul_lo = rhs.lo().widen_mul(self.lo()); - let mul_hi = rhs.lo().widen_mul(self.hi()); - let (mul, o) = mul_lo.overflowing_add(mul_hi.lo().widen_hi()); - (mul, o || !mul_hi.hi().is_zero()) - } - // overflow is guaranteed to not happen, and use a smaller widening multiplication - (true, true) => (self.lo().widen_mul(rhs.lo()), false), - } - } -} - -impl UMulo for u32 {} -impl UMulo for u64 {} -impl UMulo for u128 {} - -macro_rules! impl_signed_mulo { - ($fn:ident, $iD:ident, $uD:ident) => { - fn $fn(lhs: $iD, rhs: $iD) -> ($iD, bool) { - let mut lhs = lhs; - let mut rhs = rhs; - // the test against `mul_neg` below fails without this early return - if lhs == 0 || rhs == 0 { - return (0, false); - } - - let lhs_neg = lhs < 0; - let rhs_neg = rhs < 0; - if lhs_neg { - lhs = lhs.wrapping_neg(); - } - if rhs_neg { - rhs = rhs.wrapping_neg(); - } - let mul_neg = lhs_neg != rhs_neg; - - let (mul, o) = (lhs as $uD).mulo(rhs as $uD); - let mut mul = mul as $iD; - - if mul_neg { - mul = mul.wrapping_neg(); - } - if (mul < 0) != mul_neg { - // this one check happens to catch all edge cases related to `$iD::MIN` - (mul, true) - } else { - (mul, o) - } - } - }; -} - -impl_signed_mulo!(i32_overflowing_mul, i32, u32); -impl_signed_mulo!(i64_overflowing_mul, i64, u64); -impl_signed_mulo!(i128_overflowing_mul, i128, u128); - -intrinsics! { - #[maybe_use_optimized_c_shim] - #[arm_aeabi_alias = __aeabi_lmul] - #[cfg(any(not(any(target_arch = "riscv32", target_arch = "riscv64")), target_feature = "m"))] - pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { - a.mul(b) - } - - pub extern "C" fn __multi3(a: i128, b: i128) -> i128 { - a.mul(b) - } - - pub extern "C" fn __mulosi4(a: i32, b: i32, oflow: &mut i32) -> i32 { - let (mul, o) = i32_overflowing_mul(a, b); - *oflow = o as i32; - mul - } - - pub extern "C" fn __mulodi4(a: i64, b: i64, oflow: &mut i32) -> i64 { - let (mul, o) = i64_overflowing_mul(a, b); - *oflow = o as i32; - mul - } - - #[unadjusted_on_win64] - pub extern "C" fn __muloti4(a: i128, b: i128, oflow: &mut i32) -> i128 { - let (mul, o) = i128_overflowing_mul(a, b); - *oflow = o as i32; - mul - } - - pub extern "C" fn __rust_i128_mulo(a: i128, b: i128, oflow: &mut i32) -> i128 { - let (mul, o) = i128_overflowing_mul(a, b); - *oflow = o.into(); - mul - } - - pub extern "C" fn __rust_u128_mulo(a: u128, b: u128, oflow: &mut i32) -> u128 { - let (mul, o) = a.mulo(b); - *oflow = o.into(); - mul - } -} diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs deleted file mode 100644 index 9630c7d7de3..00000000000 --- a/library/compiler-builtins/src/int/sdiv.rs +++ /dev/null @@ -1,169 +0,0 @@ -use crate::int::udiv::*; - -macro_rules! sdivmod { - ( - $unsigned_fn:ident, // name of the unsigned division function - $signed_fn:ident, // name of the signed division function - $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` - $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` - $($attr:tt),* // attributes - ) => { - intrinsics! { - #[avr_skip] - $( - #[$attr] - )* - /// Returns `n / d` and sets `*rem = n % d` - pub extern "C" fn $signed_fn(a: $iX, b: $iX, rem: &mut $iX) -> $iX { - let a_neg = a < 0; - let b_neg = b < 0; - let mut a = a; - let mut b = b; - if a_neg { - a = a.wrapping_neg(); - } - if b_neg { - b = b.wrapping_neg(); - } - let mut r = *rem as $uX; - let t = $unsigned_fn(a as $uX, b as $uX, Some(&mut r)) as $iX; - let mut r = r as $iX; - if a_neg { - r = r.wrapping_neg(); - } - *rem = r; - if a_neg != b_neg { - t.wrapping_neg() - } else { - t - } - } - } - } -} - -macro_rules! sdiv { - ( - $unsigned_fn:ident, // name of the unsigned division function - $signed_fn:ident, // name of the signed division function - $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` - $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` - $($attr:tt),* // attributes - ) => { - intrinsics! { - #[avr_skip] - $( - #[$attr] - )* - /// Returns `n / d` - pub extern "C" fn $signed_fn(a: $iX, b: $iX) -> $iX { - let a_neg = a < 0; - let b_neg = b < 0; - let mut a = a; - let mut b = b; - if a_neg { - a = a.wrapping_neg(); - } - if b_neg { - b = b.wrapping_neg(); - } - let t = $unsigned_fn(a as $uX, b as $uX) as $iX; - if a_neg != b_neg { - t.wrapping_neg() - } else { - t - } - } - } - } -} - -macro_rules! smod { - ( - $unsigned_fn:ident, // name of the unsigned division function - $signed_fn:ident, // name of the signed division function - $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` - $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` - $($attr:tt),* // attributes - ) => { - intrinsics! { - #[avr_skip] - $( - #[$attr] - )* - /// Returns `n % d` - pub extern "C" fn $signed_fn(a: $iX, b: $iX) -> $iX { - let a_neg = a < 0; - let b_neg = b < 0; - let mut a = a; - let mut b = b; - if a_neg { - a = a.wrapping_neg(); - } - if b_neg { - b = b.wrapping_neg(); - } - let r = $unsigned_fn(a as $uX, b as $uX) as $iX; - if a_neg { - r.wrapping_neg() - } else { - r - } - } - } - } -} - -sdivmod!( - __udivmodsi4, - __divmodsi4, - u32, - i32, - maybe_use_optimized_c_shim -); -// The `#[arm_aeabi_alias = __aeabi_idiv]` attribute cannot be made to work with `intrinsics!` in macros -intrinsics! { - #[maybe_use_optimized_c_shim] - #[arm_aeabi_alias = __aeabi_idiv] - /// Returns `n / d` - pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { - let a_neg = a < 0; - let b_neg = b < 0; - let mut a = a; - let mut b = b; - if a_neg { - a = a.wrapping_neg(); - } - if b_neg { - b = b.wrapping_neg(); - } - let t = __udivsi3(a as u32, b as u32) as i32; - if a_neg != b_neg { - t.wrapping_neg() - } else { - t - } - } -} -smod!(__umodsi3, __modsi3, u32, i32, maybe_use_optimized_c_shim); - -sdivmod!( - __udivmoddi4, - __divmoddi4, - u64, - i64, - maybe_use_optimized_c_shim -); -sdiv!(__udivdi3, __divdi3, u64, i64, maybe_use_optimized_c_shim); -smod!(__umoddi3, __moddi3, u64, i64, maybe_use_optimized_c_shim); - -// LLVM does not currently have a `__divmodti4` function, but GCC does -sdivmod!( - __udivmodti4, - __divmodti4, - u128, - i128, - maybe_use_optimized_c_shim -); -sdiv!(__udivti3, __divti3, u128, i128,); -smod!(__umodti3, __modti3, u128, i128,); diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs deleted file mode 100644 index 317272988ce..00000000000 --- a/library/compiler-builtins/src/int/shift.rs +++ /dev/null @@ -1,125 +0,0 @@ -use crate::int::{DInt, HInt, Int, MinInt}; - -trait Ashl: DInt { - /// Returns `a << b`, requires `b < Self::BITS` - fn ashl(self, shl: u32) -> Self { - let n_h = Self::H::BITS; - if shl & n_h != 0 { - // we only need `self.lo()` because `self.hi()` will be shifted out entirely - self.lo().wrapping_shl(shl - n_h).widen_hi() - } else if shl == 0 { - self - } else { - Self::from_lo_hi( - self.lo().wrapping_shl(shl), - self.lo().logical_shr(n_h.wrapping_sub(shl)) | self.hi().wrapping_shl(shl), - ) - } - } -} - -impl Ashl for u32 {} -impl Ashl for u64 {} -impl Ashl for u128 {} - -trait Ashr: DInt { - /// Returns arithmetic `a >> b`, requires `b < Self::BITS` - fn ashr(self, shr: u32) -> Self { - let n_h = Self::H::BITS; - if shr & n_h != 0 { - Self::from_lo_hi( - self.hi().wrapping_shr(shr - n_h), - // smear the sign bit - self.hi().wrapping_shr(n_h - 1), - ) - } else if shr == 0 { - self - } else { - Self::from_lo_hi( - self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h.wrapping_sub(shr)), - self.hi().wrapping_shr(shr), - ) - } - } -} - -impl Ashr for i32 {} -impl Ashr for i64 {} -impl Ashr for i128 {} - -trait Lshr: DInt { - /// Returns logical `a >> b`, requires `b < Self::BITS` - fn lshr(self, shr: u32) -> Self { - let n_h = Self::H::BITS; - if shr & n_h != 0 { - self.hi().logical_shr(shr - n_h).zero_widen() - } else if shr == 0 { - self - } else { - Self::from_lo_hi( - self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h.wrapping_sub(shr)), - self.hi().logical_shr(shr), - ) - } - } -} - -impl Lshr for u32 {} -impl Lshr for u64 {} -impl Lshr for u128 {} - -intrinsics! { - #[avr_skip] - #[maybe_use_optimized_c_shim] - pub extern "C" fn __ashlsi3(a: u32, b: u32) -> u32 { - a.ashl(b) - } - - #[avr_skip] - #[maybe_use_optimized_c_shim] - #[arm_aeabi_alias = __aeabi_llsl] - pub extern "C" fn __ashldi3(a: u64, b: core::ffi::c_uint) -> u64 { - a.ashl(b as u32) - } - - #[avr_skip] - pub extern "C" fn __ashlti3(a: u128, b: u32) -> u128 { - a.ashl(b) - } - - #[avr_skip] - #[maybe_use_optimized_c_shim] - pub extern "C" fn __ashrsi3(a: i32, b: u32) -> i32 { - a.ashr(b) - } - - #[avr_skip] - #[maybe_use_optimized_c_shim] - #[arm_aeabi_alias = __aeabi_lasr] - pub extern "C" fn __ashrdi3(a: i64, b: core::ffi::c_uint) -> i64 { - a.ashr(b as u32) - } - - #[avr_skip] - pub extern "C" fn __ashrti3(a: i128, b: u32) -> i128 { - a.ashr(b) - } - - #[avr_skip] - #[maybe_use_optimized_c_shim] - pub extern "C" fn __lshrsi3(a: u32, b: u32) -> u32 { - a.lshr(b) - } - - #[avr_skip] - #[maybe_use_optimized_c_shim] - #[arm_aeabi_alias = __aeabi_llsr] - pub extern "C" fn __lshrdi3(a: u64, b: core::ffi::c_uint) -> u64 { - a.lshr(b as u32) - } - - #[avr_skip] - pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 { - a.lshr(b) - } -} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs deleted file mode 100644 index 56ce188a373..00000000000 --- a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs +++ /dev/null @@ -1,69 +0,0 @@ -/// Creates an unsigned division function optimized for dividing integers with the same -/// bitwidth as the largest operand in an asymmetrically sized division. For example, x86-64 has an -/// assembly instruction that can divide a 128 bit integer by a 64 bit integer if the quotient fits -/// in 64 bits. The 128 bit version of this algorithm would use that fast hardware division to -/// construct a full 128 bit by 128 bit division. -#[allow(unused_macros)] -macro_rules! impl_asymmetric { - ( - $fn:ident, // name of the unsigned division function - $zero_div_fn:ident, // function called when division by zero is attempted - $half_division:ident, // function for division of a $uX by a $uX - $asymmetric_division:ident, // function for division of a $uD by a $uX - $n_h:expr, // the number of bits in a $iH or $uH - $uH:ident, // unsigned integer with half the bit width of $uX - $uX:ident, // unsigned integer with half the bit width of $uD - $uD:ident // unsigned integer type for the inputs and outputs of `$fn` - ) => { - /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a - /// tuple. - pub fn $fn(duo: $uD, div: $uD) -> ($uD, $uD) { - let n: u32 = $n_h * 2; - - let duo_lo = duo as $uX; - let duo_hi = (duo >> n) as $uX; - let div_lo = div as $uX; - let div_hi = (div >> n) as $uX; - if div_hi == 0 { - if div_lo == 0 { - $zero_div_fn() - } - if duo_hi < div_lo { - // `$uD` by `$uX` division with a quotient that will fit into a `$uX` - let (quo, rem) = unsafe { $asymmetric_division(duo, div_lo) }; - return (quo as $uD, rem as $uD); - } else { - // Short division using the $uD by $uX division - let (quo_hi, rem_hi) = $half_division(duo_hi, div_lo); - let tmp = unsafe { - $asymmetric_division((duo_lo as $uD) | ((rem_hi as $uD) << n), div_lo) - }; - return ((tmp.0 as $uD) | ((quo_hi as $uD) << n), tmp.1 as $uD); - } - } - - // This has been adapted from - // https://www.codeproject.com/tips/785014/uint-division-modulus which was in turn - // adapted from Hacker's Delight. This is similar to the two possibility algorithm - // in that it uses only more significant parts of `duo` and `div` to divide a large - // integer with a smaller division instruction. - let div_lz = div_hi.leading_zeros(); - let div_extra = n - div_lz; - let div_sig_n = (div >> div_extra) as $uX; - let tmp = unsafe { $asymmetric_division(duo >> 1, div_sig_n) }; - - let mut quo = tmp.0 >> ((n - 1) - div_lz); - if quo != 0 { - quo -= 1; - } - - // Note that this is a full `$uD` multiplication being used here - let mut rem = duo - (quo as $uD).wrapping_mul(div); - if div <= rem { - quo += 1; - rem -= div; - } - return (quo as $uD, rem); - } - }; -} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs deleted file mode 100644 index 2c61a45e06e..00000000000 --- a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs +++ /dev/null @@ -1,552 +0,0 @@ -/// Creates an unsigned division function that uses binary long division, designed for -/// computer architectures without division instructions. These functions have good performance for -/// microarchitectures with large branch miss penalties and architectures without the ability to -/// predicate instructions. For architectures with predicated instructions, one of the algorithms -/// described in the documentation of these functions probably has higher performance, and a custom -/// assembly routine should be used instead. -#[allow(unused_macros)] -macro_rules! impl_binary_long { - ( - $fn:ident, // name of the unsigned division function - $zero_div_fn:ident, // function called when division by zero is attempted - $normalization_shift:ident, // function for finding the normalization shift - $n:tt, // the number of bits in a $iX or $uX - $uX:ident, // unsigned integer type for the inputs and outputs of `$fn` - $iX:ident // signed integer type with same bitwidth as `$uX` - $(, $fun_attr:meta)* // attributes for the function - ) => { - /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a - /// tuple. - $( - #[$fun_attr] - )* - pub fn $fn(duo: $uX, div: $uX) -> ($uX, $uX) { - let mut duo = duo; - // handle edge cases before calling `$normalization_shift` - if div == 0 { - $zero_div_fn() - } - if duo < div { - return (0, duo); - } - - // There are many variations of binary division algorithm that could be used. This - // documentation gives a tour of different methods so that future readers wanting to - // optimize further do not have to painstakingly derive them. The SWAR variation is - // especially hard to understand without reading the less convoluted methods first. - - // You may notice that a `duo < div_original` check is included in many these - // algorithms. A critical optimization that many algorithms miss is handling of - // quotients that will turn out to have many trailing zeros or many leading zeros. This - // happens in cases of exact or close-to-exact divisions, divisions by power of two, and - // in cases where the quotient is small. The `duo < div_original` check handles these - // cases of early returns and ends up replacing other kinds of mundane checks that - // normally terminate a binary division algorithm. - // - // Something you may see in other algorithms that is not special-cased here is checks - // for division by powers of two. The `duo < div_original` check handles this case and - // more, however it can be checked up front before the bisection using the - // `((div > 0) && ((div & (div - 1)) == 0))` trick. This is not special-cased because - // compilers should handle most cases where divisions by power of two occur, and we do - // not want to add on a few cycles for every division operation just to save a few - // cycles rarely. - - // The following example is the most straightforward translation from the way binary - // long division is typically visualized: - // Dividing 178u8 (0b10110010) by 6u8 (0b110). `div` is shifted left by 5, according to - // the result from `$normalization_shift(duo, div, false)`. - // - // Step 0: `sub` is negative, so there is not full normalization, so no `quo` bit is set - // and `duo` is kept unchanged. - // duo:10110010, div_shifted:11000000, sub:11110010, quo:00000000, shl:5 - // - // Step 1: `sub` is positive, set a `quo` bit and update `duo` for next step. - // duo:10110010, div_shifted:01100000, sub:01010010, quo:00010000, shl:4 - // - // Step 2: Continue based on `sub`. The `quo` bits start accumulating. - // duo:01010010, div_shifted:00110000, sub:00100010, quo:00011000, shl:3 - // duo:00100010, div_shifted:00011000, sub:00001010, quo:00011100, shl:2 - // duo:00001010, div_shifted:00001100, sub:11111110, quo:00011100, shl:1 - // duo:00001010, div_shifted:00000110, sub:00000100, quo:00011100, shl:0 - // The `duo < div_original` check terminates the algorithm with the correct quotient of - // 29u8 and remainder of 4u8 - /* - let div_original = div; - let mut shl = $normalization_shift(duo, div, false); - let mut quo = 0; - loop { - let div_shifted = div << shl; - let sub = duo.wrapping_sub(div_shifted); - // it is recommended to use `println!`s like this if functionality is unclear - /* - println!("duo:{:08b}, div_shifted:{:08b}, sub:{:08b}, quo:{:08b}, shl:{}", - duo, - div_shifted, - sub, - quo, - shl - ); - */ - if 0 <= (sub as $iX) { - duo = sub; - quo += 1 << shl; - if duo < div_original { - // this branch is optional - return (quo, duo) - } - } - if shl == 0 { - return (quo, duo) - } - shl -= 1; - } - */ - - // This restoring binary long division algorithm reduces the number of operations - // overall via: - // - `pow` can be shifted right instead of recalculating from `shl` - // - starting `div` shifted left and shifting it right for each step instead of - // recalculating from `shl` - // - The `duo < div_original` branch is used to terminate the algorithm instead of the - // `shl == 0` branch. This check is strong enough to prevent set bits of `pow` and - // `div` from being shifted off the end. This check also only occurs on half of steps - // on average, since it is behind the `(sub as $iX) >= 0` branch. - // - `shl` is now not needed by any aspect of of the loop and thus only 3 variables are - // being updated between steps - // - // There are many variations of this algorithm, but this encompases the largest number - // of architectures and does not rely on carry flags, add-with-carry, or SWAR - // complications to be decently fast. - /* - let div_original = div; - let shl = $normalization_shift(duo, div, false); - let mut div: $uX = div << shl; - let mut pow: $uX = 1 << shl; - let mut quo: $uX = 0; - loop { - let sub = duo.wrapping_sub(div); - if 0 <= (sub as $iX) { - duo = sub; - quo |= pow; - if duo < div_original { - return (quo, duo) - } - } - div >>= 1; - pow >>= 1; - } - */ - - // If the architecture has flags and predicated arithmetic instructions, it is possible - // to do binary long division without branching and in only 3 or 4 instructions. This is - // a variation of a 3 instruction central loop from - // http://www.chiark.greenend.org.uk/~theom/riscos/docs/ultimate/a252div.txt. - // - // What allows doing division in only 3 instructions is realizing that instead of - // keeping `duo` in place and shifting `div` right to align bits, `div` can be kept in - // place and `duo` can be shifted left. This means `div` does not have to be updated, - // but causes edge case problems and makes `duo < div_original` tests harder. Some - // architectures have an option to shift an argument in an arithmetic operation, which - // means `duo` can be shifted left and subtracted from in one instruction. The other two - // instructions are updating `quo` and undoing the subtraction if it turns out things - // were not normalized. - - /* - // Perform one binary long division step on the already normalized arguments, because - // the main. Note that this does a full normalization since the central loop needs - // `duo.leading_zeros()` to be at least 1 more than `div.leading_zeros()`. The original - // variation only did normalization to the nearest 4 steps, but this makes handling edge - // cases much harder. We do a full normalization and perform a binary long division - // step. In the edge case where the msbs of `duo` and `div` are set, it clears the msb - // of `duo`, then the edge case handler shifts `div` right and does another long - // division step to always insure `duo.leading_zeros() + 1 >= div.leading_zeros()`. - let div_original = div; - let mut shl = $normalization_shift(duo, div, true); - let mut div: $uX = (div << shl); - let mut quo: $uX = 1; - duo = duo.wrapping_sub(div); - if duo < div_original { - return (1 << shl, duo); - } - let div_neg: $uX; - if (div as $iX) < 0 { - // A very ugly edge case where the most significant bit of `div` is set (after - // shifting to match `duo` when its most significant bit is at the sign bit), which - // leads to the sign bit of `div_neg` being cut off and carries not happening when - // they should. This branch performs a long division step that keeps `duo` in place - // and shifts `div` down. - div >>= 1; - div_neg = div.wrapping_neg(); - let (sub, carry) = duo.overflowing_add(div_neg); - duo = sub; - quo = quo.wrapping_add(quo).wrapping_add(carry as $uX); - if !carry { - duo = duo.wrapping_add(div); - } - shl -= 1; - } else { - div_neg = div.wrapping_neg(); - } - // The add-with-carry that updates `quo` needs to have the carry set when a normalized - // subtract happens. Using `duo.wrapping_shl(1).overflowing_sub(div)` to do the - // subtraction generates a carry when an unnormalized subtract happens, which is the - // opposite of what we want. Instead, we use - // `duo.wrapping_shl(1).overflowing_add(div_neg)`, where `div_neg` is negative `div`. - let mut i = shl; - loop { - if i == 0 { - break; - } - i -= 1; - // `ADDS duo, div, duo, LSL #1` - // (add `div` to `duo << 1` and set flags) - let (sub, carry) = duo.wrapping_shl(1).overflowing_add(div_neg); - duo = sub; - // `ADC quo, quo, quo` - // (add with carry). Effectively shifts `quo` left by 1 and sets the least - // significant bit to the carry. - quo = quo.wrapping_add(quo).wrapping_add(carry as $uX); - // `ADDCC duo, duo, div` - // (add if carry clear). Undoes the subtraction if no carry was generated. - if !carry { - duo = duo.wrapping_add(div); - } - } - return (quo, duo >> shl); - */ - - // This is the SWAR (SIMD within in a register) restoring division algorithm. - // This combines several ideas of the above algorithms: - // - If `duo` is shifted left instead of shifting `div` right like in the 3 instruction - // restoring division algorithm, some architectures can do the shifting and - // subtraction step in one instruction. - // - `quo` can be constructed by adding powers-of-two to it or shifting it left by one - // and adding one. - // - Every time `duo` is shifted left, there is another unused 0 bit shifted into the - // LSB, so what if we use those bits to store `quo`? - // Through a complex setup, it is possible to manage `duo` and `quo` in the same - // register, and perform one step with 2 or 3 instructions. The only major downsides are - // that there is significant setup (it is only saves instructions if `shl` is - // approximately more than 4), `duo < div_original` checks are impractical once SWAR is - // initiated, and the number of division steps taken has to be exact (we cannot do more - // division steps than `shl`, because it introduces edge cases where quotient bits in - // `duo` start to collide with the real part of `div`. - /* - // first step. The quotient bit is stored in `quo` for now - let div_original = div; - let mut shl = $normalization_shift(duo, div, true); - let mut div: $uX = (div << shl); - duo = duo.wrapping_sub(div); - let mut quo: $uX = 1 << shl; - if duo < div_original { - return (quo, duo); - } - - let mask: $uX; - if (div as $iX) < 0 { - // deal with same edge case as the 3 instruction restoring division algorithm, but - // the quotient bit from this step also has to be stored in `quo` - div >>= 1; - shl -= 1; - let tmp = 1 << shl; - mask = tmp - 1; - let sub = duo.wrapping_sub(div); - if (sub as $iX) >= 0 { - // restore - duo = sub; - quo |= tmp; - } - if duo < div_original { - return (quo, duo); - } - } else { - mask = quo - 1; - } - // There is now room for quotient bits in `duo`. - - // Note that `div` is already shifted left and has `shl` unset bits. We subtract 1 from - // `div` and end up with the subset of `shl` bits being all being set. This subset acts - // just like a two's complement negative one. The subset of `div` containing the divisor - // had 1 subtracted from it, but a carry will always be generated from the `shl` subset - // as long as the quotient stays positive. - // - // When the modified `div` is subtracted from `duo.wrapping_shl(1)`, the `shl` subset - // adds a quotient bit to the least significant bit. - // For example, 89 (0b01011001) divided by 3 (0b11): - // - // shl:4, div:0b00110000 - // first step: - // duo:0b01011001 - // + div_neg:0b11010000 - // ____________________ - // 0b00101001 - // quo is set to 0b00010000 and mask is set to 0b00001111 for later - // - // 1 is subtracted from `div`. I will differentiate the `shl` part of `div` and the - // quotient part of `duo` with `^`s. - // chars. - // div:0b00110000 - // ^^^^ - // + 0b11111111 - // ________________ - // 0b00101111 - // ^^^^ - // div_neg:0b11010001 - // - // first SWAR step: - // duo_shl1:0b01010010 - // ^ - // + div_neg:0b11010001 - // ____________________ - // 0b00100011 - // ^ - // second: - // duo_shl1:0b01000110 - // ^^ - // + div_neg:0b11010001 - // ____________________ - // 0b00010111 - // ^^ - // third: - // duo_shl1:0b00101110 - // ^^^ - // + div_neg:0b11010001 - // ____________________ - // 0b11111111 - // ^^^ - // 3 steps resulted in the quotient with 3 set bits as expected, but currently the real - // part of `duo` is negative and the third step was an unnormalized step. The restore - // branch then restores `duo`. Note that the restore branch does not shift `duo` left. - // - // duo:0b11111111 - // ^^^ - // + div:0b00101111 - // ^^^^ - // ________________ - // 0b00101110 - // ^^^ - // `duo` is now back in the `duo_shl1` state it was at in the the third step, with an - // unset quotient bit. - // - // final step (`shl` was 4, so exactly 4 steps must be taken) - // duo_shl1:0b01011100 - // ^^^^ - // + div_neg:0b11010001 - // ____________________ - // 0b00101101 - // ^^^^ - // The quotient includes the `^` bits added with the `quo` bits from the beginning that - // contained the first step and potential edge case step, - // `quo:0b00010000 + (duo:0b00101101 & mask:0b00001111) == 0b00011101 == 29u8`. - // The remainder is the bits remaining in `duo` that are not part of the quotient bits, - // `duo:0b00101101 >> shl == 0b0010 == 2u8`. - let div: $uX = div.wrapping_sub(1); - let mut i = shl; - loop { - if i == 0 { - break; - } - i -= 1; - duo = duo.wrapping_shl(1).wrapping_sub(div); - if (duo as $iX) < 0 { - // restore - duo = duo.wrapping_add(div); - } - } - // unpack the results of SWAR - return ((duo & mask) | quo, duo >> shl); - */ - - // The problem with the conditional restoring SWAR algorithm above is that, in practice, - // it requires assembly code to bring out its full unrolled potential (It seems that - // LLVM can't use unrolled conditionals optimally and ends up erasing all the benefit - // that my algorithm intends. On architectures without predicated instructions, the code - // gen is especially bad. We need a default software division algorithm that is - // guaranteed to get decent code gen for the central loop. - - // For non-SWAR algorithms, there is a way to do binary long division without - // predication or even branching. This involves creating a mask from the sign bit and - // performing different kinds of steps using that. - /* - let shl = $normalization_shift(duo, div, true); - let mut div: $uX = div << shl; - let mut pow: $uX = 1 << shl; - let mut quo: $uX = 0; - loop { - let sub = duo.wrapping_sub(div); - let sign_mask = !((sub as $iX).wrapping_shr($n - 1) as $uX); - duo -= div & sign_mask; - quo |= pow & sign_mask; - div >>= 1; - pow >>= 1; - if pow == 0 { - break; - } - } - return (quo, duo); - */ - // However, it requires about 4 extra operations (smearing the sign bit, negating the - // mask, and applying the mask twice) on top of the operations done by the actual - // algorithm. With SWAR however, just 2 extra operations are needed, making it - // practical and even the most optimal algorithm for some architectures. - - // What we do is use custom assembly for predicated architectures that need software - // division, and for the default algorithm use a mask based restoring SWAR algorithm - // without conditionals or branches. On almost all architectures, this Rust code is - // guaranteed to compile down to 5 assembly instructions or less for each step, and LLVM - // will unroll it in a decent way. - - // standard opening for SWAR algorithm with first step and edge case handling - let div_original = div; - let mut shl = $normalization_shift(duo, div, true); - let mut div: $uX = (div << shl); - duo = duo.wrapping_sub(div); - let mut quo: $uX = 1 << shl; - if duo < div_original { - return (quo, duo); - } - let mask: $uX; - if (div as $iX) < 0 { - div >>= 1; - shl -= 1; - let tmp = 1 << shl; - mask = tmp - 1; - let sub = duo.wrapping_sub(div); - if (sub as $iX) >= 0 { - duo = sub; - quo |= tmp; - } - if duo < div_original { - return (quo, duo); - } - } else { - mask = quo - 1; - } - - // central loop - div = div.wrapping_sub(1); - let mut i = shl; - loop { - if i == 0 { - break; - } - i -= 1; - // shift left 1 and subtract - duo = duo.wrapping_shl(1).wrapping_sub(div); - // create mask - let mask = (duo as $iX).wrapping_shr($n - 1) as $uX; - // restore - duo = duo.wrapping_add(div & mask); - } - // unpack - return ((duo & mask) | quo, duo >> shl); - - // miscellanious binary long division algorithms that might be better for specific - // architectures - - // Another kind of long division uses an interesting fact that `div` and `pow` can be - // negated when `duo` is negative to perform a "negated" division step that works in - // place of any normalization mechanism. This is a non-restoring division algorithm that - // is very similar to the non-restoring division algorithms that can be found on the - // internet, except there is only one test for `duo < 0`. The subtraction from `quo` can - // be viewed as shifting the least significant set bit right (e.x. if we enter a series - // of negated binary long division steps starting with `quo == 0b1011_0000` and - // `pow == 0b0000_1000`, `quo` will progress like this: 0b1010_1000, 0b1010_0100, - // 0b1010_0010, 0b1010_0001). - /* - let div_original = div; - let shl = $normalization_shift(duo, div, true); - let mut div: $uX = (div << shl); - let mut pow: $uX = 1 << shl; - let mut quo: $uX = pow; - duo = duo.wrapping_sub(div); - if duo < div_original { - return (quo, duo); - } - div >>= 1; - pow >>= 1; - loop { - if (duo as $iX) < 0 { - // Negated binary long division step. - duo = duo.wrapping_add(div); - quo = quo.wrapping_sub(pow); - } else { - // Normal long division step. - if duo < div_original { - return (quo, duo) - } - duo = duo.wrapping_sub(div); - quo = quo.wrapping_add(pow); - } - pow >>= 1; - div >>= 1; - } - */ - - // This is the Nonrestoring SWAR algorithm, combining the nonrestoring algorithm with - // SWAR techniques that makes the only difference between steps be negation of `div`. - // If there was an architecture with an instruction that negated inputs to an adder - // based on conditionals, and in place shifting (or a three input addition operation - // that can have `duo` as two of the inputs to effectively shift it left by 1), then a - // single instruction central loop is possible. Microarchitectures often have inputs to - // their ALU that can invert the arguments and carry in of adders, but the architectures - // unfortunately do not have an instruction to dynamically invert this input based on - // conditionals. - /* - // SWAR opening - let div_original = div; - let mut shl = $normalization_shift(duo, div, true); - let mut div: $uX = (div << shl); - duo = duo.wrapping_sub(div); - let mut quo: $uX = 1 << shl; - if duo < div_original { - return (quo, duo); - } - let mask: $uX; - if (div as $iX) < 0 { - div >>= 1; - shl -= 1; - let tmp = 1 << shl; - let sub = duo.wrapping_sub(div); - if (sub as $iX) >= 0 { - // restore - duo = sub; - quo |= tmp; - } - if duo < div_original { - return (quo, duo); - } - mask = tmp - 1; - } else { - mask = quo - 1; - } - - // central loop - let div: $uX = div.wrapping_sub(1); - let mut i = shl; - loop { - if i == 0 { - break; - } - i -= 1; - // note: the `wrapping_shl(1)` can be factored out, but would require another - // restoring division step to prevent `(duo as $iX)` from overflowing - if (duo as $iX) < 0 { - // Negated binary long division step. - duo = duo.wrapping_shl(1).wrapping_add(div); - } else { - // Normal long division step. - duo = duo.wrapping_shl(1).wrapping_sub(div); - } - } - if (duo as $iX) < 0 { - // Restore. This was not needed in the original nonrestoring algorithm because of - // the `duo < div_original` checks. - duo = duo.wrapping_add(div); - } - // unpack - return ((duo & mask) | quo, duo >> shl); - */ - } - }; -} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs deleted file mode 100644 index f5c6e50239a..00000000000 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ /dev/null @@ -1,317 +0,0 @@ -/// Creates an unsigned division function that uses a combination of hardware division and -/// binary long division to divide integers larger than what hardware division by itself can do. This -/// function is intended for microarchitectures that have division hardware, but not fast enough -/// multiplication hardware for `impl_trifecta` to be faster. -#[allow(unused_macros)] -macro_rules! impl_delegate { - ( - $fn:ident, // name of the unsigned division function - $zero_div_fn:ident, // function called when division by zero is attempted - $half_normalization_shift:ident, // function for finding the normalization shift of $uX - $half_division:ident, // function for division of a $uX by a $uX - $n_h:expr, // the number of bits in $iH or $uH - $uH:ident, // unsigned integer with half the bit width of $uX - $uX:ident, // unsigned integer with half the bit width of $uD. - $uD:ident, // unsigned integer type for the inputs and outputs of `$fn` - $iD:ident // signed integer type with the same bitwidth as `$uD` - ) => { - /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a - /// tuple. - pub fn $fn(duo: $uD, div: $uD) -> ($uD, $uD) { - // The two possibility algorithm, undersubtracting long division algorithm, or any kind - // of reciprocal based algorithm will not be fastest, because they involve large - // multiplications that we assume to not be fast enough relative to the divisions to - // outweigh setup times. - - // the number of bits in a $uX - let n = $n_h * 2; - - let duo_lo = duo as $uX; - let duo_hi = (duo >> n) as $uX; - let div_lo = div as $uX; - let div_hi = (div >> n) as $uX; - - match (div_lo == 0, div_hi == 0, duo_hi == 0) { - (true, true, _) => $zero_div_fn(), - (_, false, true) => { - // `duo` < `div` - return (0, duo); - } - (false, true, true) => { - // delegate to smaller division - let tmp = $half_division(duo_lo, div_lo); - return (tmp.0 as $uD, tmp.1 as $uD); - } - (false, true, false) => { - if duo_hi < div_lo { - // `quo_hi` will always be 0. This performs a binary long division algorithm - // to zero `duo_hi` followed by a half division. - - // We can calculate the normalization shift using only `$uX` size functions. - // If we calculated the normalization shift using - // `$half_normalization_shift(duo_hi, div_lo false)`, it would break the - // assumption the function has that the first argument is more than the - // second argument. If the arguments are switched, the assumption holds true - // since `duo_hi < div_lo`. - let norm_shift = $half_normalization_shift(div_lo, duo_hi, false); - let shl = if norm_shift == 0 { - // Consider what happens if the msbs of `duo_hi` and `div_lo` align with - // no shifting. The normalization shift will always return - // `norm_shift == 0` regardless of whether it is fully normalized, - // because `duo_hi < div_lo`. In that edge case, `n - norm_shift` would - // result in shift overflow down the line. For the edge case, because - // both `duo_hi < div_lo` and we are comparing all the significant bits - // of `duo_hi` and `div`, we can make `shl = n - 1`. - n - 1 - } else { - // We also cannot just use `shl = n - norm_shift - 1` in the general - // case, because when we are not in the edge case comparing all the - // significant bits, then the full `duo < div` may not be true and thus - // breaks the division algorithm. - n - norm_shift - }; - - // The 3 variable restoring division algorithm (see binary_long.rs) is ideal - // for this task, since `pow` and `quo` can be `$uX` and the delegation - // check is simple. - let mut div: $uD = div << shl; - let mut pow_lo: $uX = 1 << shl; - let mut quo_lo: $uX = 0; - let mut duo = duo; - loop { - let sub = duo.wrapping_sub(div); - if 0 <= (sub as $iD) { - duo = sub; - quo_lo |= pow_lo; - let duo_hi = (duo >> n) as $uX; - if duo_hi == 0 { - // Delegate to get the rest of the quotient. Note that the - // `div_lo` here is the original unshifted `div`. - let tmp = $half_division(duo as $uX, div_lo); - return ((quo_lo | tmp.0) as $uD, tmp.1 as $uD); - } - } - div >>= 1; - pow_lo >>= 1; - } - } else if duo_hi == div_lo { - // `quo_hi == 1`. This branch is cheap and helps with edge cases. - let tmp = $half_division(duo as $uX, div as $uX); - return ((1 << n) | (tmp.0 as $uD), tmp.1 as $uD); - } else { - // `div_lo < duo_hi` - // `rem_hi == 0` - if (div_lo >> $n_h) == 0 { - // Short division of $uD by a $uH, using $uX by $uX division - let div_0 = div_lo as $uH as $uX; - let (quo_hi, rem_3) = $half_division(duo_hi, div_0); - - let duo_mid = ((duo >> $n_h) as $uH as $uX) | (rem_3 << $n_h); - let (quo_1, rem_2) = $half_division(duo_mid, div_0); - - let duo_lo = (duo as $uH as $uX) | (rem_2 << $n_h); - let (quo_0, rem_1) = $half_division(duo_lo, div_0); - - return ( - (quo_0 as $uD) | ((quo_1 as $uD) << $n_h) | ((quo_hi as $uD) << n), - rem_1 as $uD, - ); - } - - // This is basically a short division composed of a half division for the hi - // part, specialized 3 variable binary long division in the middle, and - // another half division for the lo part. - let duo_lo = duo as $uX; - let tmp = $half_division(duo_hi, div_lo); - let quo_hi = tmp.0; - let mut duo = (duo_lo as $uD) | ((tmp.1 as $uD) << n); - // This check is required to avoid breaking the long division below. - if duo < div { - return ((quo_hi as $uD) << n, duo); - } - - // The half division handled all shift alignments down to `n`, so this - // division can continue with a shift of `n - 1`. - let mut div: $uD = div << (n - 1); - let mut pow_lo: $uX = 1 << (n - 1); - let mut quo_lo: $uX = 0; - loop { - let sub = duo.wrapping_sub(div); - if 0 <= (sub as $iD) { - duo = sub; - quo_lo |= pow_lo; - let duo_hi = (duo >> n) as $uX; - if duo_hi == 0 { - // Delegate to get the rest of the quotient. Note that the - // `div_lo` here is the original unshifted `div`. - let tmp = $half_division(duo as $uX, div_lo); - return ( - (tmp.0) as $uD | (quo_lo as $uD) | ((quo_hi as $uD) << n), - tmp.1 as $uD, - ); - } - } - div >>= 1; - pow_lo >>= 1; - } - } - } - (_, false, false) => { - // Full $uD by $uD binary long division. `quo_hi` will always be 0. - if duo < div { - return (0, duo); - } - let div_original = div; - let shl = $half_normalization_shift(duo_hi, div_hi, false); - let mut duo = duo; - let mut div: $uD = div << shl; - let mut pow_lo: $uX = 1 << shl; - let mut quo_lo: $uX = 0; - loop { - let sub = duo.wrapping_sub(div); - if 0 <= (sub as $iD) { - duo = sub; - quo_lo |= pow_lo; - if duo < div_original { - return (quo_lo as $uD, duo); - } - } - div >>= 1; - pow_lo >>= 1; - } - } - } - } - }; -} - -/// Returns `n / d` and sets `*rem = n % d`. -/// -/// This specialization exists because: -/// - The LLVM backend for 32-bit SPARC cannot compile functions that return `(u128, u128)`, -/// so we have to use an old fashioned `&mut u128` argument to return the remainder. -/// - 64-bit SPARC does not have u64 * u64 => u128 widening multiplication, which makes the -/// delegate algorithm strategy the only reasonably fast way to perform `u128` division. -// used on SPARC -#[allow(dead_code)] -pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { - use super::*; - let duo_lo = duo as u64; - let duo_hi = (duo >> 64) as u64; - let div_lo = div as u64; - let div_hi = (div >> 64) as u64; - - match (div_lo == 0, div_hi == 0, duo_hi == 0) { - (true, true, _) => zero_div_fn(), - (_, false, true) => { - *rem = duo; - return 0; - } - (false, true, true) => { - let tmp = u64_by_u64_div_rem(duo_lo, div_lo); - *rem = tmp.1 as u128; - return tmp.0 as u128; - } - (false, true, false) => { - if duo_hi < div_lo { - let norm_shift = u64_normalization_shift(div_lo, duo_hi, false); - let shl = if norm_shift == 0 { - 64 - 1 - } else { - 64 - norm_shift - }; - - let mut div: u128 = div << shl; - let mut pow_lo: u64 = 1 << shl; - let mut quo_lo: u64 = 0; - let mut duo = duo; - loop { - let sub = duo.wrapping_sub(div); - if 0 <= (sub as i128) { - duo = sub; - quo_lo |= pow_lo; - let duo_hi = (duo >> 64) as u64; - if duo_hi == 0 { - let tmp = u64_by_u64_div_rem(duo as u64, div_lo); - *rem = tmp.1 as u128; - return (quo_lo | tmp.0) as u128; - } - } - div >>= 1; - pow_lo >>= 1; - } - } else if duo_hi == div_lo { - let tmp = u64_by_u64_div_rem(duo as u64, div as u64); - *rem = tmp.1 as u128; - return (1 << 64) | (tmp.0 as u128); - } else { - if (div_lo >> 32) == 0 { - let div_0 = div_lo as u32 as u64; - let (quo_hi, rem_3) = u64_by_u64_div_rem(duo_hi, div_0); - - let duo_mid = ((duo >> 32) as u32 as u64) | (rem_3 << 32); - let (quo_1, rem_2) = u64_by_u64_div_rem(duo_mid, div_0); - - let duo_lo = (duo as u32 as u64) | (rem_2 << 32); - let (quo_0, rem_1) = u64_by_u64_div_rem(duo_lo, div_0); - - *rem = rem_1 as u128; - return (quo_0 as u128) | ((quo_1 as u128) << 32) | ((quo_hi as u128) << 64); - } - - let duo_lo = duo as u64; - let tmp = u64_by_u64_div_rem(duo_hi, div_lo); - let quo_hi = tmp.0; - let mut duo = (duo_lo as u128) | ((tmp.1 as u128) << 64); - if duo < div { - *rem = duo; - return (quo_hi as u128) << 64; - } - - let mut div: u128 = div << (64 - 1); - let mut pow_lo: u64 = 1 << (64 - 1); - let mut quo_lo: u64 = 0; - loop { - let sub = duo.wrapping_sub(div); - if 0 <= (sub as i128) { - duo = sub; - quo_lo |= pow_lo; - let duo_hi = (duo >> 64) as u64; - if duo_hi == 0 { - let tmp = u64_by_u64_div_rem(duo as u64, div_lo); - *rem = tmp.1 as u128; - return (tmp.0) as u128 | (quo_lo as u128) | ((quo_hi as u128) << 64); - } - } - div >>= 1; - pow_lo >>= 1; - } - } - } - (_, false, false) => { - if duo < div { - *rem = duo; - return 0; - } - let div_original = div; - let shl = u64_normalization_shift(duo_hi, div_hi, false); - let mut duo = duo; - let mut div: u128 = div << shl; - let mut pow_lo: u64 = 1 << shl; - let mut quo_lo: u64 = 0; - loop { - let sub = duo.wrapping_sub(div); - if 0 <= (sub as i128) { - duo = sub; - quo_lo |= pow_lo; - if duo < div_original { - *rem = duo; - return quo_lo as u128; - } - } - div >>= 1; - pow_lo >>= 1; - } - } - } -} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs deleted file mode 100644 index a91fe6632ee..00000000000 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ /dev/null @@ -1,321 +0,0 @@ -// TODO: when `unsafe_block_in_unsafe_fn` is stabilized, remove this -#![allow(unused_unsafe)] -// The functions are complex with many branches, and explicit -// `return`s makes it clear where function exit points are -#![allow(clippy::needless_return)] -#![allow(clippy::comparison_chain)] -// Clippy is confused by the complex configuration -#![allow(clippy::if_same_then_else)] -#![allow(clippy::needless_bool)] - -//! This `specialized_div_rem` module is originally from version 1.0.0 of the -//! `specialized-div-rem` crate. Note that `for` loops with ranges are not used in this -//! module, since unoptimized compilation may generate references to `memcpy`. -//! -//! The purpose of these macros is to easily change the both the division algorithm used -//! for a given integer size and the half division used by that algorithm. The way -//! functions call each other is also constructed such that linkers will find the chain of -//! software and hardware divisions needed for every size of signed and unsigned division. -//! For example, most target compilations do the following: -//! -//! - Many 128 bit division functions like `u128::wrapping_div` use -//! `std::intrinsics::unchecked_div`, which gets replaced by `__udivti3` because there -//! is not a 128 bit by 128 bit hardware division function in most architectures. -//! `__udivti3` uses `u128_div_rem` (this extra level of function calls exists because -//! `__umodti3` and `__udivmodti4` also exist, and `specialized_div_rem` supplies just -//! one function to calculate both the quotient and remainder. If configuration flags -//! enable it, `impl_trifecta!` defines `u128_div_rem` to use the trifecta algorithm, -//! which requires the half sized division `u64_by_u64_div_rem`. If the architecture -//! supplies a 64 bit hardware division instruction, `u64_by_u64_div_rem` will be -//! reduced to those instructions. Note that we do not specify the half size division -//! directly to be `__udivdi3`, because hardware division would never be introduced. -//! - If the architecture does not supply a 64 bit hardware division instruction, u64 -//! divisions will use functions such as `__udivdi3`. This will call `u64_div_rem` -//! which is defined by `impl_delegate!`. The half division for this algorithm is -//! `u32_by_u32_div_rem` which in turn becomes hardware division instructions or more -//! software division algorithms. -//! - If the architecture does not supply a 32 bit hardware instruction, linkers will -//! look for `__udivsi3`. `impl_binary_long!` is used, but this algorithm uses no half -//! division, so the chain of calls ends here. -//! -//! On some architectures like x86_64, an asymmetrically sized division is supplied, in -//! which 128 bit numbers can be divided by 64 bit numbers. `impl_asymmetric!` is used to -//! extend the 128 by 64 bit division to a full 128 by 128 bit division. - -// `allow(dead_code)` is used in various places, because the configuration code would otherwise be -// ridiculously complex - -#[macro_use] -mod norm_shift; - -#[macro_use] -mod binary_long; - -#[macro_use] -mod delegate; - -// used on SPARC -#[allow(unused_imports)] -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use self::delegate::u128_divide_sparc; - -#[cfg(feature = "public-test-deps")] -pub use self::delegate::u128_divide_sparc; - -#[macro_use] -mod trifecta; - -#[macro_use] -mod asymmetric; - -/// The behavior of all divisions by zero is controlled by this function. This function should be -/// impossible to reach by Rust users, unless `compiler-builtins` public division functions or -/// `core/std::unchecked_div/rem` are directly used without a zero check in front. -fn zero_div_fn() -> ! { - // Calling the intrinsic directly, to avoid the `assert_unsafe_precondition` that cannot be used - // here because it involves non-`inline` functions - // (https://github.com/rust-lang/compiler-builtins/issues/491). - unsafe { core::intrinsics::unreachable() } -} - -const USE_LZ: bool = { - if cfg!(target_arch = "arm") { - if cfg!(target_feature = "thumb-mode") { - // ARM thumb targets have CLZ instructions if the instruction set of ARMv6T2 is - // supported. This is needed to successfully differentiate between targets like - // `thumbv8.base` and `thumbv8.main`. - cfg!(target_feature = "v6t2") - } else { - // Regular ARM targets have CLZ instructions if the ARMv5TE instruction set is - // supported. Technically, ARMv5T was the first to have CLZ, but the "v5t" target - // feature does not seem to work. - cfg!(target_feature = "v5te") - } - } else if cfg!(any(target_arch = "sparc", target_arch = "sparc64")) { - // LZD or LZCNT on SPARC only exists for the VIS 3 extension and later. - cfg!(target_feature = "vis3") - } else if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { - // The 'Zbb' Basic Bit-Manipulation extension on RISC-V - // determines if a CLZ assembly instruction exists - cfg!(target_feature = "zbb") - } else { - // All other common targets Rust supports should have CLZ instructions - true - } -}; - -impl_normalization_shift!( - u32_normalization_shift, - USE_LZ, - 32, - u32, - i32, - allow(dead_code) -); -impl_normalization_shift!( - u64_normalization_shift, - USE_LZ, - 64, - u64, - i64, - allow(dead_code) -); - -/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. -/// `checked_div` and `checked_rem` are used to avoid bringing in panic function -/// dependencies. -#[inline] -fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { - if let Some(quo) = duo.checked_div(div) { - if let Some(rem) = duo.checked_rem(div) { - return (quo, rem); - } - } - zero_div_fn() -} - -// Whether `trifecta` or `delegate` is faster for 128 bit division depends on the speed at which a -// microarchitecture can multiply and divide. We decide to be optimistic and assume `trifecta` is -// faster if the target pointer width is at least 64. Note that this -// implementation is additionally included on WebAssembly despite the typical -// pointer width there being 32 because it's typically run on a 64-bit machine -// that has access to faster 64-bit operations. -#[cfg(all( - any( - target_family = "wasm", - not(any(target_pointer_width = "16", target_pointer_width = "32")), - ), - not(all(not(feature = "no-asm"), target_arch = "x86_64")), - not(any(target_arch = "sparc", target_arch = "sparc64")) -))] -impl_trifecta!( - u128_div_rem, - zero_div_fn, - u64_by_u64_div_rem, - 32, - u32, - u64, - u128 -); - -// If the pointer width less than 64 and this isn't wasm, then the target -// architecture almost certainly does not have the fast 64 to 128 bit widening -// multiplication needed for `trifecta` to be faster. -#[cfg(all( - not(any( - target_family = "wasm", - not(any(target_pointer_width = "16", target_pointer_width = "32")), - )), - not(all(not(feature = "no-asm"), target_arch = "x86_64")), - not(any(target_arch = "sparc", target_arch = "sparc64")) -))] -impl_delegate!( - u128_div_rem, - zero_div_fn, - u64_normalization_shift, - u64_by_u64_div_rem, - 32, - u32, - u64, - u128, - i128 -); - -/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. -/// -/// # Safety -/// -/// If the quotient does not fit in a `u64`, a floating point exception occurs. -/// If `div == 0`, then a division by zero exception occurs. -#[cfg(all(not(feature = "no-asm"), target_arch = "x86_64"))] -#[inline] -unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { - let duo_lo = duo as u64; - let duo_hi = (duo >> 64) as u64; - let quo: u64; - let rem: u64; - unsafe { - // divides the combined registers rdx:rax (`duo` is split into two 64 bit parts to do this) - // by `div`. The quotient is stored in rax and the remainder in rdx. - // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - core::arch::asm!( - "div {0}", - in(reg) div, - inlateout("rax") duo_lo => quo, - inlateout("rdx") duo_hi => rem, - options(att_syntax, pure, nomem, nostack) - ); - } - (quo, rem) -} - -// use `asymmetric` instead of `trifecta` on x86_64 -#[cfg(all(not(feature = "no-asm"), target_arch = "x86_64"))] -impl_asymmetric!( - u128_div_rem, - zero_div_fn, - u64_by_u64_div_rem, - u128_by_u64_div_rem, - 32, - u32, - u64, - u128 -); - -/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. -/// `checked_div` and `checked_rem` are used to avoid bringing in panic function -/// dependencies. -#[inline] -#[allow(dead_code)] -fn u32_by_u32_div_rem(duo: u32, div: u32) -> (u32, u32) { - if let Some(quo) = duo.checked_div(div) { - if let Some(rem) = duo.checked_rem(div) { - return (quo, rem); - } - } - zero_div_fn() -} - -// When not on x86 and the pointer width is not 64, use `delegate` since the division size is larger -// than register size. -#[cfg(all( - not(all(not(feature = "no-asm"), target_arch = "x86")), - not(target_pointer_width = "64") -))] -impl_delegate!( - u64_div_rem, - zero_div_fn, - u32_normalization_shift, - u32_by_u32_div_rem, - 16, - u16, - u32, - u64, - i64 -); - -// When not on x86 and the pointer width is 64, use `binary_long`. -#[cfg(all( - not(all(not(feature = "no-asm"), target_arch = "x86")), - target_pointer_width = "64" -))] -impl_binary_long!( - u64_div_rem, - zero_div_fn, - u64_normalization_shift, - 64, - u64, - i64 -); - -/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. -/// -/// # Safety -/// -/// If the quotient does not fit in a `u32`, a floating point exception occurs. -/// If `div == 0`, then a division by zero exception occurs. -#[cfg(all(not(feature = "no-asm"), target_arch = "x86"))] -#[inline] -unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { - let duo_lo = duo as u32; - let duo_hi = (duo >> 32) as u32; - let quo: u32; - let rem: u32; - unsafe { - // divides the combined registers rdx:rax (`duo` is split into two 32 bit parts to do this) - // by `div`. The quotient is stored in rax and the remainder in rdx. - // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - core::arch::asm!( - "div {0}", - in(reg) div, - inlateout("rax") duo_lo => quo, - inlateout("rdx") duo_hi => rem, - options(att_syntax, pure, nomem, nostack) - ); - } - (quo, rem) -} - -// use `asymmetric` instead of `delegate` on x86 -#[cfg(all(not(feature = "no-asm"), target_arch = "x86"))] -impl_asymmetric!( - u64_div_rem, - zero_div_fn, - u32_by_u32_div_rem, - u64_by_u32_div_rem, - 16, - u16, - u32, - u64 -); - -// 32 bits is the smallest division used by `compiler-builtins`, so we end with binary long division -impl_binary_long!( - u32_div_rem, - zero_div_fn, - u32_normalization_shift, - 32, - u32, - i32, - allow(dead_code) -); diff --git a/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs b/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs deleted file mode 100644 index 61b67b6bc3d..00000000000 --- a/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs +++ /dev/null @@ -1,106 +0,0 @@ -/// Creates a function used by some division algorithms to compute the "normalization shift". -#[allow(unused_macros)] -macro_rules! impl_normalization_shift { - ( - $name:ident, // name of the normalization shift function - // boolean for if `$uX::leading_zeros` should be used (if an architecture does not have a - // hardware instruction for `usize::leading_zeros`, then this should be `true`) - $use_lz:ident, - $n:tt, // the number of bits in a $iX or $uX - $uX:ident, // unsigned integer type for the inputs of `$name` - $iX:ident, // signed integer type for the inputs of `$name` - $($unsigned_attr:meta),* // attributes for the function - ) => { - /// Finds the shift left that the divisor `div` would need to be normalized for a binary - /// long division step with the dividend `duo`. NOTE: This function assumes that these edge - /// cases have been handled before reaching it: - /// ` - /// if div == 0 { - /// panic!("attempt to divide by zero") - /// } - /// if duo < div { - /// return (0, duo) - /// } - /// ` - /// - /// Normalization is defined as (where `shl` is the output of this function): - /// ` - /// if duo.leading_zeros() != (div << shl).leading_zeros() { - /// // If the most significant bits of `duo` and `div << shl` are not in the same place, - /// // then `div << shl` has one more leading zero than `duo`. - /// assert_eq!(duo.leading_zeros() + 1, (div << shl).leading_zeros()); - /// // Also, `2*(div << shl)` is not more than `duo` (otherwise the first division step - /// // would not be able to clear the msb of `duo`) - /// assert!(duo < (div << (shl + 1))); - /// } - /// if full_normalization { - /// // Some algorithms do not need "full" normalization, which means that `duo` is - /// // larger than `div << shl` when the most significant bits are aligned. - /// assert!((div << shl) <= duo); - /// } - /// ` - /// - /// Note: If the software bisection algorithm is being used in this function, it happens - /// that full normalization always occurs, so be careful that new algorithms are not - /// invisibly depending on this invariant when `full_normalization` is set to `false`. - $( - #[$unsigned_attr] - )* - fn $name(duo: $uX, div: $uX, full_normalization: bool) -> usize { - // We have to find the leading zeros of `div` to know where its msb (most significant - // set bit) is to even begin binary long division. It is also good to know where the msb - // of `duo` is so that useful work can be started instead of shifting `div` for all - // possible quotients (many division steps are wasted if `duo.leading_zeros()` is large - // and `div` starts out being shifted all the way to the msb). Aligning the msbs of - // `div` and `duo` could be done by shifting `div` left by - // `div.leading_zeros() - duo.leading_zeros()`, but some CPUs without division hardware - // also do not have single instructions for calculating `leading_zeros`. Instead of - // software doing two bisections to find the two `leading_zeros`, we do one bisection to - // find `div.leading_zeros() - duo.leading_zeros()` without actually knowing either of - // the leading zeros values. - - let mut shl: usize; - if $use_lz { - shl = (div.leading_zeros() - duo.leading_zeros()) as usize; - if full_normalization { - if duo < (div << shl) { - // when the msb of `duo` and `div` are aligned, the resulting `div` may be - // larger than `duo`, so we decrease the shift by 1. - shl -= 1; - } - } - } else { - let mut test = duo; - shl = 0usize; - let mut lvl = $n >> 1; - loop { - let tmp = test >> lvl; - // It happens that a final `duo < (div << shl)` check is not needed, because the - // `div <= tmp` check insures that the msb of `test` never passes the msb of - // `div`, and any set bits shifted off the end of `test` would still keep - // `div <= tmp` true. - if div <= tmp { - test = tmp; - shl += lvl; - } - // narrow down bisection - lvl >>= 1; - if lvl == 0 { - break - } - } - } - // tests the invariants that should hold before beginning binary long division - /* - if full_normalization { - assert!((div << shl) <= duo); - } - if duo.leading_zeros() != (div << shl).leading_zeros() { - assert_eq!(duo.leading_zeros() + 1, (div << shl).leading_zeros()); - assert!(duo < (div << (shl + 1))); - } - */ - shl - } - } -} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs deleted file mode 100644 index 7e104053b8b..00000000000 --- a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs +++ /dev/null @@ -1,386 +0,0 @@ -/// Creates an unsigned division function optimized for division of integers with bitwidths -/// larger than the largest hardware integer division supported. These functions use large radix -/// division algorithms that require both fast division and very fast widening multiplication on the -/// target microarchitecture. Otherwise, `impl_delegate` should be used instead. -#[allow(unused_macros)] -macro_rules! impl_trifecta { - ( - $fn:ident, // name of the unsigned division function - $zero_div_fn:ident, // function called when division by zero is attempted - $half_division:ident, // function for division of a $uX by a $uX - $n_h:expr, // the number of bits in $iH or $uH - $uH:ident, // unsigned integer with half the bit width of $uX - $uX:ident, // unsigned integer with half the bit width of $uD - $uD:ident // unsigned integer type for the inputs and outputs of `$unsigned_name` - ) => { - /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a - /// tuple. - pub fn $fn(duo: $uD, div: $uD) -> ($uD, $uD) { - // This is called the trifecta algorithm because it uses three main algorithms: short - // division for small divisors, the two possibility algorithm for large divisors, and an - // undersubtracting long division algorithm for intermediate cases. - - // This replicates `carrying_mul` (rust-lang rfc #2417). LLVM correctly optimizes this - // to use a widening multiply to 128 bits on the relevant architectures. - fn carrying_mul(lhs: $uX, rhs: $uX) -> ($uX, $uX) { - let tmp = (lhs as $uD).wrapping_mul(rhs as $uD); - (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) - } - fn carrying_mul_add(lhs: $uX, mul: $uX, add: $uX) -> ($uX, $uX) { - let tmp = (lhs as $uD) - .wrapping_mul(mul as $uD) - .wrapping_add(add as $uD); - (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) - } - - // the number of bits in a $uX - let n = $n_h * 2; - - if div == 0 { - $zero_div_fn() - } - - // Trying to use a normalization shift function will cause inelegancies in the code and - // inefficiencies for architectures with a native count leading zeros instruction. The - // undersubtracting algorithm needs both values (keeping the original `div_lz` but - // updating `duo_lz` multiple times), so we assume hardware support for fast - // `leading_zeros` calculation. - let div_lz = div.leading_zeros(); - let mut duo_lz = duo.leading_zeros(); - - // the possible ranges of `duo` and `div` at this point: - // `0 <= duo < 2^n_d` - // `1 <= div < 2^n_d` - - // quotient is 0 or 1 branch - if div_lz <= duo_lz { - // The quotient cannot be more than 1. The highest set bit of `duo` needs to be at - // least one place higher than `div` for the quotient to be more than 1. - if duo >= div { - return (1, duo - div); - } else { - return (0, duo); - } - } - - // `_sb` is the number of significant bits (from the ones place to the highest set bit) - // `{2, 2^div_sb} <= duo < 2^n_d` - // `1 <= div < {2^duo_sb, 2^(n_d - 1)}` - // smaller division branch - if duo_lz >= n { - // `duo < 2^n` so it will fit in a $uX. `div` will also fit in a $uX (because of the - // `div_lz <= duo_lz` branch) so no numerical error. - let (quo, rem) = $half_division(duo as $uX, div as $uX); - return (quo as $uD, rem as $uD); - } - - // `{2^n, 2^div_sb} <= duo < 2^n_d` - // `1 <= div < {2^duo_sb, 2^(n_d - 1)}` - // short division branch - if div_lz >= (n + $n_h) { - // `1 <= div < {2^duo_sb, 2^n_h}` - - // It is barely possible to improve the performance of this by calculating the - // reciprocal and removing one `$half_division`, but only if the CPU can do fast - // multiplications in parallel. Other reciprocal based methods can remove two - // `$half_division`s, but have multiplications that cannot be done in parallel and - // reduce performance. I have decided to use this trivial short division method and - // rely on the CPU having quick divisions. - - let duo_hi = (duo >> n) as $uX; - let div_0 = div as $uH as $uX; - let (quo_hi, rem_3) = $half_division(duo_hi, div_0); - - let duo_mid = ((duo >> $n_h) as $uH as $uX) | (rem_3 << $n_h); - let (quo_1, rem_2) = $half_division(duo_mid, div_0); - - let duo_lo = (duo as $uH as $uX) | (rem_2 << $n_h); - let (quo_0, rem_1) = $half_division(duo_lo, div_0); - - return ( - (quo_0 as $uD) | ((quo_1 as $uD) << $n_h) | ((quo_hi as $uD) << n), - rem_1 as $uD, - ); - } - - // relative leading significant bits, cannot overflow because of above branches - let lz_diff = div_lz - duo_lz; - - // `{2^n, 2^div_sb} <= duo < 2^n_d` - // `2^n_h <= div < {2^duo_sb, 2^(n_d - 1)}` - // `mul` or `mul - 1` branch - if lz_diff < $n_h { - // Two possibility division algorithm - - // The most significant bits of `duo` and `div` are within `$n_h` bits of each - // other. If we take the `n` most significant bits of `duo` and divide them by the - // corresponding bits in `div`, it produces a quotient value `quo`. It happens that - // `quo` or `quo - 1` will always be the correct quotient for the whole number. In - // other words, the bits less significant than the `n` most significant bits of - // `duo` and `div` can only influence the quotient to be one of two values. - // Because there are only two possibilities, there only needs to be one `$uH` sized - // division, a `$uH` by `$uD` multiplication, and only one branch with a few simple - // operations. - // - // Proof that the true quotient can only be `quo` or `quo - 1`. - // All `/` operators here are floored divisions. - // - // `shift` is the number of bits not in the higher `n` significant bits of `duo`. - // (definitions) - // 0. shift = n - duo_lz - // 1. duo_sig_n == duo / 2^shift - // 2. div_sig_n == div / 2^shift - // 3. quo == duo_sig_n / div_sig_n - // - // - // We are trying to find the true quotient, `true_quo`. - // 4. true_quo = duo / div. (definition) - // - // This is true because of the bits that are cut off during the bit shift. - // 5. duo_sig_n * 2^shift <= duo < (duo_sig_n + 1) * 2^shift. - // 6. div_sig_n * 2^shift <= div < (div_sig_n + 1) * 2^shift. - // - // Dividing each bound of (5) by each bound of (6) gives 4 possibilities for what - // `true_quo == duo / div` is bounded by: - // (duo_sig_n * 2^shift) / (div_sig_n * 2^shift) - // (duo_sig_n * 2^shift) / ((div_sig_n + 1) * 2^shift) - // ((duo_sig_n + 1) * 2^shift) / (div_sig_n * 2^shift) - // ((duo_sig_n + 1) * 2^shift) / ((div_sig_n + 1) * 2^shift) - // - // Simplifying each of these four: - // duo_sig_n / div_sig_n - // duo_sig_n / (div_sig_n + 1) - // (duo_sig_n + 1) / div_sig_n - // (duo_sig_n + 1) / (div_sig_n + 1) - // - // Taking the smallest and the largest of these as the low and high bounds - // and replacing `duo / div` with `true_quo`: - // 7. duo_sig_n / (div_sig_n + 1) <= true_quo < (duo_sig_n + 1) / div_sig_n - // - // The `lz_diff < n_h` conditional on this branch makes sure that `div_sig_n` is at - // least `2^n_h`, and the `div_lz <= duo_lz` branch makes sure that the highest bit - // of `div_sig_n` is not the `2^(n - 1)` bit. - // 8. `2^(n - 1) <= duo_sig_n < 2^n` - // 9. `2^n_h <= div_sig_n < 2^(n - 1)` - // - // We want to prove that either - // `(duo_sig_n + 1) / div_sig_n == duo_sig_n / (div_sig_n + 1)` or that - // `(duo_sig_n + 1) / div_sig_n == duo_sig_n / (div_sig_n + 1) + 1`. - // - // We also want to prove that `quo` is one of these: - // `duo_sig_n / div_sig_n == duo_sig_n / (div_sig_n + 1)` or - // `duo_sig_n / div_sig_n == (duo_sig_n + 1) / div_sig_n`. - // - // When 1 is added to the numerator of `duo_sig_n / div_sig_n` to produce - // `(duo_sig_n + 1) / div_sig_n`, it is not possible that the value increases by - // more than 1 with floored integer arithmetic and `div_sig_n != 0`. Consider - // `x/y + 1 < (x + 1)/y` <=> `x/y + 1 < x/y + 1/y` <=> `1 < 1/y` <=> `y < 1`. - // `div_sig_n` is a nonzero integer. Thus, - // 10. `duo_sig_n / div_sig_n == (duo_sig_n + 1) / div_sig_n` or - // `(duo_sig_n / div_sig_n) + 1 == (duo_sig_n + 1) / div_sig_n. - // - // When 1 is added to the denominator of `duo_sig_n / div_sig_n` to produce - // `duo_sig_n / (div_sig_n + 1)`, it is not possible that the value decreases by - // more than 1 with the bounds (8) and (9). Consider `x/y - 1 <= x/(y + 1)` <=> - // `(x - y)/y < x/(y + 1)` <=> `(y + 1)*(x - y) < x*y` <=> `x*y - y*y + x - y < x*y` - // <=> `x < y*y + y`. The smallest value of `div_sig_n` is `2^n_h` and the largest - // value of `duo_sig_n` is `2^n - 1`. Substituting reveals `2^n - 1 < 2^n + 2^n_h`. - // Thus, - // 11. `duo_sig_n / div_sig_n == duo_sig_n / (div_sig_n + 1)` or - // `(duo_sig_n / div_sig_n) - 1` == duo_sig_n / (div_sig_n + 1)` - // - // Combining both (10) and (11), we know that - // `quo - 1 <= duo_sig_n / (div_sig_n + 1) <= true_quo - // < (duo_sig_n + 1) / div_sig_n <= quo + 1` and therefore: - // 12. quo - 1 <= true_quo < quo + 1 - // - // In a lot of division algorithms using smaller divisions to construct a larger - // division, we often encounter a situation where the approximate `quo` value - // calculated from a smaller division is multiple increments away from the true - // `quo` value. In those algorithms, multiple correction steps have to be applied. - // Those correction steps may need more multiplications to test `duo - (quo*div)` - // again. Because of the fact that our `quo` can only be one of two values, we can - // see if `duo - (quo*div)` overflows. If it did overflow, then we know that we have - // the larger of the two values (since the true quotient is unique, and any larger - // quotient will cause `duo - (quo*div)` to be negative). Also because there is only - // one correction needed, we can calculate the remainder `duo - (true_quo*div) == - // duo - ((quo - 1)*div) == duo - (quo*div - div) == duo + div - quo*div`. - // If `duo - (quo*div)` did not overflow, then we have the correct answer. - let shift = n - duo_lz; - let duo_sig_n = (duo >> shift) as $uX; - let div_sig_n = (div >> shift) as $uX; - let quo = $half_division(duo_sig_n, div_sig_n).0; - - // The larger `quo` value can overflow `$uD` in the right circumstances. This is a - // manual `carrying_mul_add` with overflow checking. - let div_lo = div as $uX; - let div_hi = (div >> n) as $uX; - let (tmp_lo, carry) = carrying_mul(quo, div_lo); - let (tmp_hi, overflow) = carrying_mul_add(quo, div_hi, carry); - let tmp = (tmp_lo as $uD) | ((tmp_hi as $uD) << n); - if (overflow != 0) || (duo < tmp) { - return ( - (quo - 1) as $uD, - // Both the addition and subtraction can overflow, but when combined end up - // as a correct positive number. - duo.wrapping_add(div).wrapping_sub(tmp), - ); - } else { - return (quo as $uD, duo - tmp); - } - } - - // Undersubtracting long division algorithm. - // Instead of clearing a minimum of 1 bit from `duo` per iteration via binary long - // division, `n_h - 1` bits are cleared per iteration with this algorithm. It is a more - // complicated version of regular long division. Most integer division algorithms tend - // to guess a part of the quotient, and may have a larger quotient than the true - // quotient (which when multiplied by `div` will "oversubtract" the original dividend). - // They then check if the quotient was in fact too large and then have to correct it. - // This long division algorithm has been carefully constructed to always underguess the - // quotient by slim margins. This allows different subalgorithms to be blindly jumped to - // without needing an extra correction step. - // - // The only problem is that this subalgorithm will not work for many ranges of `duo` and - // `div`. Fortunately, the short division, two possibility algorithm, and other simple - // cases happen to exactly fill these gaps. - // - // For an example, consider the division of 76543210 by 213 and assume that `n_h` is - // equal to two decimal digits (note: we are working with base 10 here for readability). - // The first `sig_n_h` part of the divisor (21) is taken and is incremented by 1 to - // prevent oversubtraction. We also record the number of extra places not a part of - // the `sig_n` or `sig_n_h` parts. - // - // sig_n_h == 2 digits, sig_n == 4 digits - // - // vvvv <- `duo_sig_n` - // 76543210 - // ^^^^ <- extra places in duo, `duo_extra == 4` - // - // vv <- `div_sig_n_h` - // 213 - // ^ <- extra places in div, `div_extra == 1` - // - // The difference in extra places, `duo_extra - div_extra == extra_shl == 3`, is used - // for shifting partial sums in the long division. - // - // In the first step, the first `sig_n` part of duo (7654) is divided by - // `div_sig_n_h_add_1` (22), which results in a partial quotient of 347. This is - // multiplied by the whole divisor to make 73911, which is shifted left by `extra_shl` - // and subtracted from duo. The partial quotient is also shifted left by `extra_shl` to - // be added to `quo`. - // - // 347 - // ________ - // |76543210 - // -73911 - // 2632210 - // - // Variables dependent on duo have to be updated: - // - // vvvv <- `duo_sig_n == 2632` - // 2632210 - // ^^^ <- `duo_extra == 3` - // - // `extra_shl == 2` - // - // Two more steps are taken after this and then duo fits into `n` bits, and then a final - // normal long division step is made. The partial quotients are all progressively added - // to each other in the actual algorithm, but here I have left them all in a tower that - // can be added together to produce the quotient, 359357. - // - // 14 - // 443 - // 119 - // 347 - // ________ - // |76543210 - // -73911 - // 2632210 - // -25347 - // 97510 - // -94359 - // 3151 - // -2982 - // 169 <- the remainder - - let mut duo = duo; - let mut quo: $uD = 0; - - // The number of lesser significant bits not a part of `div_sig_n_h` - let div_extra = (n + $n_h) - div_lz; - - // The most significant `n_h` bits of div - let div_sig_n_h = (div >> div_extra) as $uH; - - // This needs to be a `$uX` in case of overflow from the increment - let div_sig_n_h_add1 = (div_sig_n_h as $uX) + 1; - - // `{2^n, 2^(div_sb + n_h)} <= duo < 2^n_d` - // `2^n_h <= div < {2^(duo_sb - n_h), 2^n}` - loop { - // The number of lesser significant bits not a part of `duo_sig_n` - let duo_extra = n - duo_lz; - - // The most significant `n` bits of `duo` - let duo_sig_n = (duo >> duo_extra) as $uX; - - // the two possibility algorithm requires that the difference between msbs is less - // than `n_h`, so the comparison is `<=` here. - if div_extra <= duo_extra { - // Undersubtracting long division step - let quo_part = $half_division(duo_sig_n, div_sig_n_h_add1).0 as $uD; - let extra_shl = duo_extra - div_extra; - - // Addition to the quotient. - quo += (quo_part << extra_shl); - - // Subtraction from `duo`. At least `n_h - 1` bits are cleared from `duo` here. - duo -= (div.wrapping_mul(quo_part) << extra_shl); - } else { - // Two possibility algorithm - let shift = n - duo_lz; - let duo_sig_n = (duo >> shift) as $uX; - let div_sig_n = (div >> shift) as $uX; - let quo_part = $half_division(duo_sig_n, div_sig_n).0; - let div_lo = div as $uX; - let div_hi = (div >> n) as $uX; - - let (tmp_lo, carry) = carrying_mul(quo_part, div_lo); - // The undersubtracting long division algorithm has already run once, so - // overflow beyond `$uD` bits is not possible here - let (tmp_hi, _) = carrying_mul_add(quo_part, div_hi, carry); - let tmp = (tmp_lo as $uD) | ((tmp_hi as $uD) << n); - - if duo < tmp { - return ( - quo + ((quo_part - 1) as $uD), - duo.wrapping_add(div).wrapping_sub(tmp), - ); - } else { - return (quo + (quo_part as $uD), duo - tmp); - } - } - - duo_lz = duo.leading_zeros(); - - if div_lz <= duo_lz { - // quotient can have 0 or 1 added to it - if div <= duo { - return (quo + 1, duo - div); - } else { - return (quo, duo); - } - } - - // This can only happen if `div_sd < n` (because of previous "quo = 0 or 1" - // branches), but it is not worth it to unroll further. - if n <= duo_lz { - // simple division and addition - let tmp = $half_division(duo as $uX, div as $uX); - return (quo + (tmp.0 as $uD), tmp.1 as $uD); - } - } - } - }; -} diff --git a/library/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/src/int/trailing_zeros.rs deleted file mode 100644 index dbc0cce9fac..00000000000 --- a/library/compiler-builtins/src/int/trailing_zeros.rs +++ /dev/null @@ -1,69 +0,0 @@ -#[cfg(feature = "public-test-deps")] -pub use implementation::trailing_zeros; -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use implementation::trailing_zeros; - -mod implementation { - use crate::int::{CastInto, Int}; - - /// Returns number of trailing binary zeros in `x`. - #[allow(dead_code)] - pub fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { - let mut x = x; - let mut r: u32 = 0; - let mut t: u32; - - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 - x >>= r; // remove 32 zero bits - } - - if T::BITS >= 32 { - t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 - r += t; - x >>= t; // x = [0 - 0xFFFF] + higher garbage bits - } - - const { assert!(T::BITS >= 16) }; - t = ((CastInto::::cast(x) == 0) as u32) << 3; - x >>= t; // x = [0 - 0xFF] + higher garbage bits - r += t; - - let mut x: u8 = x.cast(); - - t = (((x & 0x0F) == 0) as u32) << 2; - x >>= t; // x = [0 - 0xF] + higher garbage bits - r += t; - - t = (((x & 0x3) == 0) as u32) << 1; - x >>= t; // x = [0 - 0x3] + higher garbage bits - r += t; - - x &= 3; - - r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) - } -} - -intrinsics! { - /// Returns the number of trailing binary zeros in `x` (32 bit version). - pub extern "C" fn __ctzsi2(x: u32) -> usize { - trailing_zeros(x) - } - - /// Returns the number of trailing binary zeros in `x` (64 bit version). - pub extern "C" fn __ctzdi2(x: u64) -> usize { - trailing_zeros(x) - } - - /// Returns the number of trailing binary zeros in `x` (128 bit version). - pub extern "C" fn __ctzti2(x: u128) -> usize { - let lo = x as u64; - if lo == 0 { - 64 + __ctzdi2((x >> 64) as u64) - } else { - __ctzdi2(lo) - } - } -} diff --git a/library/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/src/int/traits.rs deleted file mode 100644 index 9b079e2aa59..00000000000 --- a/library/compiler-builtins/src/int/traits.rs +++ /dev/null @@ -1,411 +0,0 @@ -use core::ops; - -/// Minimal integer implementations needed on all integer types, including wide integers. -#[allow(dead_code)] -pub trait MinInt: - Copy - + core::fmt::Debug - + ops::BitOr - + ops::Not - + ops::Shl -{ - /// Type with the same width but other signedness - type OtherSign: MinInt; - /// Unsigned version of Self - type UnsignedInt: MinInt; - - /// If `Self` is a signed integer - const SIGNED: bool; - - /// The bitwidth of the int type - const BITS: u32; - - const ZERO: Self; - const ONE: Self; - const MIN: Self; - const MAX: Self; -} - -/// Trait for some basic operations on integers -#[allow(dead_code)] -pub trait Int: - MinInt - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Shr - + ops::BitXor - + ops::BitAnd -{ - /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing - /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, - /// 112,119,120,125,126,127]. - const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); - - /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. - const FUZZ_NUM: usize = { - let log2 = (::BITS - 1).count_ones() as usize; - if log2 == 3 { - // case for u8 - 6 - } else { - // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate - // boundaries. - 8 + (4 * (log2 - 4)) - } - }; - - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; - fn unsigned_abs(self) -> Self::UnsignedInt; - - fn from_bool(b: bool) -> Self; - - /// Prevents the need for excessive conversions between signed and unsigned - fn logical_shr(self, other: u32) -> Self; - - /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; - - // copied from primitive integers, but put in a trait - fn is_zero(self) -> bool; - fn wrapping_neg(self) -> Self; - fn wrapping_add(self, other: Self) -> Self; - fn wrapping_mul(self, other: Self) -> Self; - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - fn ilog2(self) -> u32; -} - -pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { - let mut v = [0u8; 20]; - v[0] = 0; - v[1] = 1; - v[2] = 2; // important for parity and the iX::MIN case when reversed - let mut i = 3; - - // No need for any more until the byte boundary, because there should be no algorithms - // that are sensitive to anything not next to byte boundaries after 2. We also scale - // in powers of two, which is important to prevent u128 corner tests from getting too - // big. - let mut l = 8; - loop { - if l >= ((bits / 2) as u8) { - break; - } - // get both sides of the byte boundary - v[i] = l - 1; - i += 1; - v[i] = l; - i += 1; - l *= 2; - } - - if bits != 8 { - // add the lower side of the middle boundary - v[i] = ((bits / 2) - 1) as u8; - i += 1; - } - - // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS - // boundary because of algorithms that split the high part up. We reverse the scaling - // as we go to Self::BITS. - let mid = i; - let mut j = 1; - loop { - v[i] = (bits as u8) - (v[mid - j]) - 1; - if j == mid { - break; - } - i += 1; - j += 1; - } - v -} - -macro_rules! int_impl_common { - ($ty:ty) => { - fn from_bool(b: bool) -> Self { - b as $ty - } - - fn logical_shr(self, other: u32) -> Self { - Self::from_unsigned(self.unsigned().wrapping_shr(other)) - } - - fn is_zero(self) -> bool { - self == Self::ZERO - } - - fn wrapping_neg(self) -> Self { - ::wrapping_neg(self) - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn wrapping_shr(self, other: u32) -> Self { - ::wrapping_shr(self, other) - } - - fn rotate_left(self, other: u32) -> Self { - ::rotate_left(self, other) - } - - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - - fn ilog2(self) -> u32 { - ::ilog2(self) - } - }; -} - -macro_rules! int_impl { - ($ity:ty, $uty:ty) => { - impl MinInt for $uty { - type OtherSign = $ity; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $uty { - fn unsigned(self) -> $uty { - self - } - - // It makes writing macros easier if this is implemented for both signed and unsigned - #[allow(clippy::wrong_self_convention)] - fn from_unsigned(me: $uty) -> Self { - me - } - - fn unsigned_abs(self) -> Self { - self - } - - fn abs_diff(self, other: Self) -> Self { - self.abs_diff(other) - } - - int_impl_common!($uty); - } - - impl MinInt for $ity { - type OtherSign = $uty; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $ity { - fn unsigned(self) -> $uty { - self as $uty - } - - fn from_unsigned(me: $uty) -> Self { - me as $ity - } - - fn unsigned_abs(self) -> Self::UnsignedInt { - self.unsigned_abs() - } - - fn abs_diff(self, other: Self) -> $uty { - self.abs_diff(other) - } - - int_impl_common!($ity); - } - }; -} - -int_impl!(isize, usize); -int_impl!(i8, u8); -int_impl!(i16, u16); -int_impl!(i32, u32); -int_impl!(i64, u64); -int_impl!(i128, u128); - -/// Trait for integers twice the bit width of another integer. This is implemented for all -/// primitives except for `u8`, because there is not a smaller primitive. -pub trait DInt: MinInt { - /// Integer that is half the bit width of the integer this trait is implemented for - type H: HInt; - - /// Returns the low half of `self` - fn lo(self) -> Self::H; - /// Returns the high half of `self` - fn hi(self) -> Self::H; - /// Returns the low and high halves of `self` as a tuple - fn lo_hi(self) -> (Self::H, Self::H) { - (self.lo(), self.hi()) - } - /// Constructs an integer using lower and higher half parts - fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { - lo.zero_widen() | hi.widen_hi() - } -} - -/// Trait for integers half the bit width of another integer. This is implemented for all -/// primitives except for `u128`, because it there is not a larger primitive. -pub trait HInt: Int { - /// Integer that is double the bit width of the integer this trait is implemented for - type D: DInt + MinInt; - - // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for - // unknown reasons this can cause infinite recursion when optimizations are disabled. See - // for context. - - /// Widens (using default extension) the integer to have double bit width - fn widen(self) -> Self::D; - /// Widens (zero extension only) the integer to have double bit width. This is needed to get - /// around problems with associated type bounds (such as `Int`) being unstable - fn zero_widen(self) -> Self::D; - /// Widens the integer to have double bit width and shifts the integer into the higher bits - fn widen_hi(self) -> Self::D; - /// Widening multiplication with zero widening. This cannot overflow. - fn zero_widen_mul(self, rhs: Self) -> Self::D; - /// Widening multiplication. This cannot overflow. - fn widen_mul(self, rhs: Self) -> Self::D; -} - -macro_rules! impl_d_int { - ($($X:ident $D:ident),*) => { - $( - impl DInt for $D { - type H = $X; - - fn lo(self) -> Self::H { - self as $X - } - fn hi(self) -> Self::H { - (self >> <$X as MinInt>::BITS) as $X - } - } - )* - }; -} - -macro_rules! impl_h_int { - ($($H:ident $uH:ident $X:ident),*) => { - $( - impl HInt for $H { - type D = $X; - - fn widen(self) -> Self::D { - self as $X - } - fn zero_widen(self) -> Self::D { - (self as $uH) as $X - } - fn zero_widen_mul(self, rhs: Self) -> Self::D { - self.zero_widen().wrapping_mul(rhs.zero_widen()) - } - fn widen_mul(self, rhs: Self) -> Self::D { - self.widen().wrapping_mul(rhs.widen()) - } - fn widen_hi(self) -> Self::D { - (self as $X) << ::BITS - } - } - )* - }; -} - -impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); -impl_h_int!( - u8 u8 u16, - u16 u16 u32, - u32 u32 u64, - u64 u64 u128, - i8 u8 i16, - i16 u16 i32, - i32 u32 i64, - i64 u64 i128 -); - -/// Trait to express (possibly lossy) casting of integers -pub trait CastInto: Copy { - fn cast(self) -> T; -} - -pub trait CastFrom: Copy { - fn cast_from(value: T) -> Self; -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - self as $into - } - } - )*}; -} - -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs deleted file mode 100644 index 1fa761212b2..00000000000 --- a/library/compiler-builtins/src/int/udiv.rs +++ /dev/null @@ -1,103 +0,0 @@ -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use crate::int::specialized_div_rem::*; - -#[cfg(feature = "public-test-deps")] -pub use crate::int::specialized_div_rem::*; - -intrinsics! { - #[maybe_use_optimized_c_shim] - #[arm_aeabi_alias = __aeabi_uidiv] - /// Returns `n / d` - pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { - u32_div_rem(n, d).0 - } - - #[maybe_use_optimized_c_shim] - /// Returns `n % d` - pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { - u32_div_rem(n, d).1 - } - - #[avr_skip] - #[maybe_use_optimized_c_shim] - /// Returns `n / d` and sets `*rem = n % d` - pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { - let quo_rem = u32_div_rem(n, d); - if let Some(rem) = rem { - *rem = quo_rem.1; - } - quo_rem.0 - } - - #[avr_skip] - #[maybe_use_optimized_c_shim] - /// Returns `n / d` - pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { - u64_div_rem(n, d).0 - } - - #[avr_skip] - #[maybe_use_optimized_c_shim] - /// Returns `n % d` - pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { - u64_div_rem(n, d).1 - } - - #[avr_skip] - #[maybe_use_optimized_c_shim] - /// Returns `n / d` and sets `*rem = n % d` - pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { - let quo_rem = u64_div_rem(n, d); - if let Some(rem) = rem { - *rem = quo_rem.1; - } - quo_rem.0 - } - - // Note: we use block configuration and not `if cfg!(...)`, because we need to entirely disable - // the existence of `u128_div_rem` to get 32-bit SPARC to compile, see `u128_divide_sparc` docs. - - #[avr_skip] - /// Returns `n / d` - pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { - #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { - u128_div_rem(n, d).0 - } - #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] { - u128_divide_sparc(n, d, &mut 0) - } - } - - #[avr_skip] - /// Returns `n % d` - pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { - #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { - u128_div_rem(n, d).1 - } - #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] { - let mut rem = 0; - u128_divide_sparc(n, d, &mut rem); - rem - } - } - - #[avr_skip] - /// Returns `n / d` and sets `*rem = n % d` - pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { - #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { - let quo_rem = u128_div_rem(n, d); - if let Some(rem) = rem { - *rem = quo_rem.1; - } - quo_rem.0 - } - #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] { - let mut tmp = 0; - let quo = u128_divide_sparc(n, d, &mut tmp); - if let Some(rem) = rem { - *rem = tmp; - } - quo - } - } -} diff --git a/library/compiler-builtins/src/lib.miri.rs b/library/compiler-builtins/src/lib.miri.rs deleted file mode 100644 index 17288058e5e..00000000000 --- a/library/compiler-builtins/src/lib.miri.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! Grep bootstrap for `MIRI_REPLACE_LIBRS_IF_NOT_TEST` to learn what this is about. -#![no_std] -#![feature(rustc_private)] -extern crate compiler_builtins as real; -pub use real::*; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs deleted file mode 100644 index 6f5bd85981e..00000000000 --- a/library/compiler-builtins/src/lib.rs +++ /dev/null @@ -1,79 +0,0 @@ -#![cfg_attr(feature = "compiler-builtins", compiler_builtins)] -#![cfg_attr(all(target_family = "wasm"), feature(wasm_numeric_instr))] -#![feature(abi_unadjusted)] -#![feature(asm_experimental_arch)] -#![feature(cfg_target_has_atomic)] -#![feature(compiler_builtins)] -#![feature(core_intrinsics)] -#![feature(linkage)] -#![feature(naked_functions)] -#![feature(repr_simd)] -#![cfg_attr(f16_enabled, feature(f16))] -#![cfg_attr(f128_enabled, feature(f128))] -#![no_builtins] -#![no_std] -#![allow(unused_features)] -#![allow(internal_features)] -// We use `u128` in a whole bunch of places which we currently agree with the -// compiler on ABIs and such, so we should be "good enough" for now and changes -// to the `u128` ABI will be reflected here. -#![allow(improper_ctypes, improper_ctypes_definitions)] -// `mem::swap` cannot be used because it may generate references to memcpy in unoptimized code. -#![allow(clippy::manual_swap)] -// Support compiling on both stage0 and stage1 which may differ in supported stable features. -#![allow(stable_features)] - -// We disable #[no_mangle] for tests so that we can verify the test results -// against the native compiler-rt implementations of the builtins. - -// NOTE cfg(all(feature = "c", ..)) indicate that compiler-rt provides an arch optimized -// implementation of that intrinsic and we'll prefer to use that - -// NOTE(aapcs, aeabi, arm) ARM targets use intrinsics named __aeabi_* instead of the intrinsics -// that follow "x86 naming convention" (e.g. addsf3). Those aeabi intrinsics must adhere to the -// AAPCS calling convention (`extern "aapcs"`) because that's how LLVM will call them. - -#[cfg(test)] -extern crate core; - -#[macro_use] -mod macros; - -pub mod float; -pub mod int; -pub mod math; -pub mod mem; - -// `libm` expects its `support` module to be available in the crate root. This config can be -// cleaned up once `libm` is made always available. -use math::libm::support; - -#[cfg(target_arch = "arm")] -pub mod arm; - -#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] -pub mod aarch64; - -#[cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm"),))] -pub mod aarch64_linux; - -#[cfg(all( - kernel_user_helpers, - any(target_os = "linux", target_os = "android"), - target_arch = "arm" -))] -pub mod arm_linux; - -#[cfg(target_arch = "hexagon")] -pub mod hexagon; - -#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] -pub mod riscv; - -#[cfg(target_arch = "x86")] -pub mod x86; - -#[cfg(target_arch = "x86_64")] -pub mod x86_64; - -pub mod probestack; diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs deleted file mode 100644 index b1b71379cc9..00000000000 --- a/library/compiler-builtins/src/macros.rs +++ /dev/null @@ -1,514 +0,0 @@ -//! Macros shared throughout the compiler-builtins implementation - -/// The "main macro" used for defining intrinsics. -/// -/// The compiler-builtins library is super platform-specific with tons of crazy -/// little tweaks for various platforms. As a result it *could* involve a lot of -/// #[cfg] and macro soup, but the intention is that this macro alleviates a lot -/// of that complexity. Ideally this macro has all the weird ABI things -/// platforms need and elsewhere in this library it just looks like normal Rust -/// code. -/// -/// All intrinsics functions are marked with #[linkage = "weak"] when -/// `not(windows) and not(target_vendor = "apple")`. -/// `weak` linkage attribute is used so that these functions can be replaced -/// by another implementation at link time. This is particularly useful for mixed -/// Rust/C++ binaries that want to use the C++ intrinsics, otherwise linking against -/// the Rust stdlib will replace those from the compiler-rt library. -/// -/// This macro is structured to be invoked with a bunch of functions that looks -/// like: -/// ```ignore -/// intrinsics! { -/// pub extern "C" fn foo(a: i32) -> u32 { -/// // ... -/// } -/// -/// #[nonstandard_attribute] -/// pub extern "C" fn bar(a: i32) -> u32 { -/// // ... -/// } -/// } -/// ``` -/// -/// Each function is defined in a manner that looks like a normal Rust function. -/// The macro then accepts a few nonstandard attributes that can decorate -/// various functions. Each of the attributes is documented below with what it -/// can do, and each of them slightly tweaks how further expansion happens. -/// -/// A quick overview of attributes supported right now are: -/// -/// * `maybe_use_optimized_c_shim` - indicates that the Rust implementation is -/// ignored if an optimized C version was compiled. -/// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and -/// the specified ABI everywhere else. -/// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the -/// `"unadjusted"` abi on Win64 and the specified abi elsewhere. -/// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM -/// their otherwise typical names to other prefixed ones. -/// * `ppc_alias` - changes the name of the symbol on PowerPC platforms without -/// changing any other behavior. This is mostly for `f128`, which is `tf` on -/// most platforms but `kf` on PowerPC. -macro_rules! intrinsics { - () => (); - - // Support cfg_attr: - ( - #[cfg_attr($e:meta, $($attr:tt)*)] - $(#[$($attrs:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - $($rest:tt)* - ) => ( - #[cfg($e)] - intrinsics! { - #[$($attr)*] - $(#[$($attrs)*])* - pub extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { - $($body)* - } - } - - #[cfg(not($e))] - intrinsics! { - $(#[$($attrs)*])* - pub extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - // Same as above but for unsafe. - ( - #[cfg_attr($e:meta, $($attr:tt)*)] - $(#[$($attrs:tt)*])* - pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - $($rest:tt)* - ) => ( - #[cfg($e)] - intrinsics! { - #[$($attr)*] - $(#[$($attrs)*])* - pub unsafe extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { - $($body)* - } - } - - #[cfg(not($e))] - intrinsics! { - $(#[$($attrs)*])* - pub unsafe extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - - // Right now there's a bunch of architecture-optimized intrinsics in the - // stock compiler-rt implementation. Not all of these have been ported over - // to Rust yet so when the `c` feature of this crate is enabled we fall back - // to the architecture-specific versions which should be more optimized. The - // purpose of this macro is to easily allow specifying this. - // - // The `#[maybe_use_optimized_c_shim]` attribute indicates that this - // intrinsic may have an optimized C version. In these situations the build - // script, if the C code is enabled and compiled, will emit a cfg directive - // to get passed to rustc for our compilation. If that cfg is set we skip - // the Rust implementation, but if the attribute is not enabled then we - // compile in the Rust implementation. - ( - #[maybe_use_optimized_c_shim] - $(#[$($attr:tt)*])* - pub $(unsafe $(@ $empty:tt)? )? extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg($name = "optimized-c")] - pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - extern $abi { - fn $name($($argname: $ty),*) $(-> $ret)?; - } - unsafe { - $name($($argname),*) - } - } - - #[cfg(not($name = "optimized-c"))] - intrinsics! { - $(#[$($attr)*])* - pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - - // We recognize the `#[aapcs_on_arm]` attribute here and generate the - // same intrinsic but force it to have the `"aapcs"` calling convention on - // ARM and `"C"` elsewhere. - ( - #[aapcs_on_arm] - $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(target_arch = "arm")] - intrinsics! { - $(#[$($attr)*])* - pub extern "aapcs" fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - #[cfg(not(target_arch = "arm"))] - intrinsics! { - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - - // Like aapcs above we recognize an attribute for the "unadjusted" abi on - // win64 for some methods. - ( - #[unadjusted_on_win64] - $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(all(any(windows, target_os = "cygwin", all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64"))] - intrinsics! { - $(#[$($attr)*])* - pub extern "unadjusted" fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - #[cfg(not(all(any(windows, target_os = "cygwin", all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64")))] - intrinsics! { - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - - // `arm_aeabi_alias` would conflict with `f16_apple_{arg,ret}_abi` not handled here. Avoid macro ambiguity by combining in a - // single `#[]`. - ( - #[apple_f16_arg_abi] - #[arm_aeabi_alias = $alias:ident] - $($t:tt)* - ) => { - intrinsics! { - #[apple_f16_arg_abi, arm_aeabi_alias = $alias] - $($t)* - } - }; - ( - #[apple_f16_ret_abi] - #[arm_aeabi_alias = $alias:ident] - $($t:tt)* - ) => { - intrinsics! { - #[apple_f16_ret_abi, arm_aeabi_alias = $alias] - $($t)* - } - }; - - // On x86 (32-bit and 64-bit) Apple platforms, `f16` is passed and returned like a `u16` unless - // the builtin involves `f128`. - ( - // `arm_aeabi_alias` would conflict if not handled here. Avoid macro ambiguity by combining - // in a single `#[]`. - #[apple_f16_arg_abi $(, arm_aeabi_alias = $alias:ident)?] - $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64")))] - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - - #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] - mod $name { - #[no_mangle] - #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] - $(#[$($attr)*])* - extern $abi fn $name( $($argname: u16),* ) $(-> $ret)? { - super::$name($(f16::from_bits($argname)),*) - } - } - - #[cfg(not(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"))))] - intrinsics! { - $(#[arm_aeabi_alias = $alias])? - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - ( - #[apple_f16_ret_abi $(, arm_aeabi_alias = $alias:ident)?] - $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64")))] - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - - #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] - mod $name { - #[no_mangle] - #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] - $(#[$($attr)*])* - extern $abi fn $name( $($argname: $ty),* ) -> u16 { - super::$name($($argname),*).to_bits() - } - } - - #[cfg(not(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"))))] - intrinsics! { - $(#[arm_aeabi_alias = $alias])? - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - - // A bunch of intrinsics on ARM are aliased in the standard compiler-rt - // build under `__aeabi_*` aliases, and LLVM will call these instead of the - // original function. The aliasing here is used to generate these symbols in - // the object file. - ( - #[arm_aeabi_alias = $alias:ident] - $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(target_arch = "arm")] - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - - #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] - mod $name { - #[no_mangle] - #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] - $(#[$($attr)*])* - extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - super::$name($($argname),*) - } - } - - #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] - mod $alias { - #[no_mangle] - #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] - $(#[$($attr)*])* - extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { - super::$name($($argname),*) - } - } - - #[cfg(not(target_arch = "arm"))] - intrinsics! { - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - - // PowerPC usually uses `kf` rather than `tf` for `f128`. This is just an easy - // way to add an alias on those targets. - ( - #[ppc_alias = $alias:ident] - $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - intrinsics! { - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - intrinsics! { - $(#[$($attr)*])* - pub extern $abi fn $alias( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - - // C mem* functions are only generated when the "mem" feature is enabled. - ( - #[mem_builtin] - $(#[$($attr:tt)*])* - pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - $(#[$($attr)*])* - pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - - #[cfg(all(feature = "mem", not(feature = "mangled-names")))] - mod $name { - $(#[$($attr)*])* - #[no_mangle] - #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] - unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - super::$name($($argname),*) - } - } - - intrinsics!($($rest)*); - ); - - // Naked functions are special: we can't generate wrappers for them since - // they use a custom calling convention. - ( - #[naked] - $(#[$($attr:tt)*])* - pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - // `#[naked]` definitions are referenced by other places, so we can't use `cfg` like the others - pub mod $name { - #[naked] - $(#[$($attr)*])* - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] - pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - - // For some intrinsics, AVR uses a custom calling convention¹ that does not - // match our definitions here. Ideally we would just use hand-written naked - // functions, but that's quite a lot of code to port² - so for the time - // being we are just ignoring the problematic functions, letting avr-gcc - // (which is required to compile to AVR anyway) link them from libgcc. - // - // ¹ https://gcc.gnu.org/wiki/avr-gcc (see "Exceptions to the Calling - // Convention") - // ² https://github.com/gcc-mirror/gcc/blob/31048012db98f5ec9c2ba537bfd850374bdd771f/libgcc/config/avr/lib1funcs.S - ( - #[avr_skip] - $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(not(target_arch = "avr"))] - intrinsics! { - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - - // This is the final catch-all rule. At this point we generate an - // intrinsic with a conditional `#[no_mangle]` directive to avoid - // interfering with duplicate symbols and whatnot during testing. - // - // The implementation is placed in a separate module, to take advantage - // of the fact that rustc partitions functions into code generation - // units based on module they are defined in. As a result we will have - // a separate object file for each intrinsic. For further details see - // corresponding PR in rustc https://github.com/rust-lang/rust/pull/70846 - // - // After the intrinsic is defined we just continue with the rest of the - // input we were given. - ( - $(#[$($attr:tt)*])* - pub $(unsafe $(@ $empty:tt)?)? extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - $(#[$($attr)*])* - pub $(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - - #[cfg(not(feature = "mangled-names"))] - mod $name { - $(#[$($attr)*])* - #[no_mangle] - #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] - $(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - super::$name($($argname),*) - } - } - - intrinsics!($($rest)*); - ); -} diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs deleted file mode 100644 index ccd9c54216c..00000000000 --- a/library/compiler-builtins/src/math.rs +++ /dev/null @@ -1,199 +0,0 @@ -#[rustfmt::skip] -#[allow(dead_code)] -#[allow(unused_imports)] -#[allow(clippy::all)] -#[path = "../libm/src/math/mod.rs"] -pub(crate) mod libm; - -macro_rules! libm_intrinsics { - ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { - intrinsics! { - $( - pub extern "C" fn $fun($($iid: $ity),+) -> $oty { - $crate::math::libm::$fun($($iid),+) - } - )+ - } - } -} - -/// This set of functions is well tested in `libm` and known to provide similar performance to -/// system `libm`, as well as the same or better accuracy. -pub mod full_availability { - #[cfg(f16_enabled)] - libm_intrinsics! { - fn ceilf16(x: f16) -> f16; - fn copysignf16(x: f16, y: f16) -> f16; - fn fabsf16(x: f16) -> f16; - fn fdimf16(x: f16, y: f16) -> f16; - fn floorf16(x: f16) -> f16; - fn fmaxf16(x: f16, y: f16) -> f16; - fn fmaximumf16(x: f16, y: f16) -> f16; - fn fminf16(x: f16, y: f16) -> f16; - fn fminimumf16(x: f16, y: f16) -> f16; - fn fmodf16(x: f16, y: f16) -> f16; - fn rintf16(x: f16) -> f16; - fn roundevenf16(x: f16) -> f16; - fn roundf16(x: f16) -> f16; - fn sqrtf16(x: f16) -> f16; - fn truncf16(x: f16) -> f16; - } - - /* Weak linkage is unreliable on Windows and Apple, so we don't expose symbols that we know - * the system libc provides in order to avoid conflicts. */ - - #[cfg(all(not(windows), not(target_vendor = "apple")))] - libm_intrinsics! { - /* f32 */ - fn cbrtf(n: f32) -> f32; - fn ceilf(x: f32) -> f32; - fn copysignf(x: f32, y: f32) -> f32; - fn fabsf(x: f32) -> f32; - fn fdimf(a: f32, b: f32) -> f32; - fn floorf(x: f32) -> f32; - fn fmaf(x: f32, y: f32, z: f32) -> f32; - fn fmaxf(x: f32, y: f32) -> f32; - fn fminf(x: f32, y: f32) -> f32; - fn fmodf(x: f32, y: f32) -> f32; - fn rintf(x: f32) -> f32; - fn roundf(x: f32) -> f32; - fn sqrtf(x: f32) -> f32; - fn truncf(x: f32) -> f32; - - /* f64 */ - fn cbrt(x: f64) -> f64; - fn ceil(x: f64) -> f64; - fn copysign(x: f64, y: f64) -> f64; - fn fabs(x: f64) -> f64; - fn fdim(a: f64, b: f64) -> f64; - fn floor(x: f64) -> f64; - fn fma(x: f64, y: f64, z: f64) -> f64; - fn fmax(x: f64, y: f64) -> f64; - fn fmin(x: f64, y: f64) -> f64; - fn fmod(x: f64, y: f64) -> f64; - fn rint(x: f64) -> f64; - fn round(x: f64) -> f64; - fn sqrt(x: f64) -> f64; - fn trunc(x: f64) -> f64; - } - - // Windows and MacOS do not yet expose roundeven and IEEE 754-2019 `maximum` / `minimum`, - // however, so we still provide a fallback. - libm_intrinsics! { - fn fmaximum(x: f64, y: f64) -> f64; - fn fmaximumf(x: f32, y: f32) -> f32; - fn fminimum(x: f64, y: f64) -> f64; - fn fminimumf(x: f32, y: f32) -> f32; - fn roundeven(x: f64) -> f64; - fn roundevenf(x: f32) -> f32; - } - - #[cfg(f128_enabled)] - libm_intrinsics! { - fn ceilf128(x: f128) -> f128; - fn copysignf128(x: f128, y: f128) -> f128; - fn fabsf128(x: f128) -> f128; - fn fdimf128(x: f128, y: f128) -> f128; - fn floorf128(x: f128) -> f128; - fn fmaf128(x: f128, y: f128, z: f128) -> f128; - fn fmaxf128(x: f128, y: f128) -> f128; - fn fmaximumf128(x: f128, y: f128) -> f128; - fn fminf128(x: f128, y: f128) -> f128; - fn fminimumf128(x: f128, y: f128) -> f128; - fn fmodf128(x: f128, y: f128) -> f128; - fn rintf128(x: f128) -> f128; - fn roundevenf128(x: f128) -> f128; - fn roundf128(x: f128) -> f128; - fn sqrtf128(x: f128) -> f128; - fn truncf128(x: f128) -> f128; - } -} - -/// This group of functions has more performance or precision issues than system versions, or -/// are otherwise less well tested. Provide them only on platforms that have problems with the -/// system `libm`. -/// -/// As `libm` improves, more functions will be moved from this group to the first group. -/// -/// Do not supply for any of the following: -/// - x86 without sse2 due to ABI issues -/// - -/// - but exclude UEFI since it is a soft-float target -/// - -/// - All unix targets (linux, macos, freebsd, android, etc) -/// - wasm with known target_os -#[cfg(not(any( - all( - target_arch = "x86", - not(target_feature = "sse2"), - not(target_os = "uefi"), - ), - unix, - all(target_family = "wasm", not(target_os = "unknown")) -)))] -pub mod partial_availability { - #[cfg(not(windows))] - libm_intrinsics! { - fn acos(x: f64) -> f64; - fn acosf(n: f32) -> f32; - fn asin(x: f64) -> f64; - fn asinf(n: f32) -> f32; - fn atan(x: f64) -> f64; - fn atan2(x: f64, y: f64) -> f64; - fn atan2f(a: f32, b: f32) -> f32; - fn atanf(n: f32) -> f32; - fn cos(x: f64) -> f64; - fn cosf(x: f32) -> f32; - fn cosh(x: f64) -> f64; - fn coshf(n: f32) -> f32; - fn erf(x: f64) -> f64; - fn erfc(x: f64) -> f64; - fn erfcf(x: f32) -> f32; - fn erff(x: f32) -> f32; - fn exp(x: f64) -> f64; - fn exp2(x: f64) -> f64; - fn exp2f(x: f32) -> f32; - fn expf(x: f32) -> f32; - fn expm1(x: f64) -> f64; - fn expm1f(n: f32) -> f32; - fn hypot(x: f64, y: f64) -> f64; - fn hypotf(x: f32, y: f32) -> f32; - fn ldexp(f: f64, n: i32) -> f64; - fn ldexpf(f: f32, n: i32) -> f32; - fn log(x: f64) -> f64; - fn log10(x: f64) -> f64; - fn log10f(x: f32) -> f32; - fn log1p(x: f64) -> f64; - fn log1pf(n: f32) -> f32; - fn log2(x: f64) -> f64; - fn log2f(x: f32) -> f32; - fn logf(x: f32) -> f32; - fn pow(x: f64, y: f64) -> f64; - fn powf(x: f32, y: f32) -> f32; - fn sin(x: f64) -> f64; - fn sinf(x: f32) -> f32; - fn sinh(x: f64) -> f64; - fn sinhf(n: f32) -> f32; - fn tan(x: f64) -> f64; - fn tanf(n: f32) -> f32; - fn tanh(x: f64) -> f64; - fn tanhf(n: f32) -> f32; - fn tgamma(x: f64) -> f64; - fn tgammaf(x: f32) -> f32; - } - - // allow for windows (and other targets) - intrinsics! { - pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { - let r = super::libm::lgamma_r(x); - *s = r.1; - r.0 - } - - pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { - let r = super::libm::lgammaf_r(x); - *s = r.1; - r.0 - } - } -} diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs deleted file mode 100644 index c602a67dbd7..00000000000 --- a/library/compiler-builtins/src/mem/impls.rs +++ /dev/null @@ -1,308 +0,0 @@ -// In C and Rust it is UB to read or write to usize::MAX because if an allocation extends to the -// last byte of address space (there must be an allocation to do the read or write), in C computing -// its one-past-the-end pointer would be equal to NULL and in Rust computing the address of a -// trailing ZST member with a safe place projection would wrap (place projection address computation -// is non-wrapping). -// -// However, some embedded systems have special memory at usize::MAX, and need to access that -// memory. If they do that with the intrinsics provided by compiler-builtins (such as memcpy!), the -// ptr::add in these loops will wrap. And if compiler-builtins is compiled with cfg(ub_checks), -// this will fail a UB check at runtime. -// -// Since this scenario is UB, we are within our rights hit this check and halt execution... -// But we are also within our rights to try to make it work. -// We use wrapping_add/wrapping_sub for pointer arithmetic in this module in an attempt to support -// this use. Of course this is not a guarantee that such use will work, it just means that this -// crate doing wrapping pointer arithmetic with a method that must not wrap won't be the problem if -// something does go wrong at runtime. -use core::intrinsics::likely; - -const WORD_SIZE: usize = core::mem::size_of::(); -const WORD_MASK: usize = WORD_SIZE - 1; - -// If the number of bytes involved exceed this threshold we will opt in word-wise copy. -// The value here selected is max(2 * WORD_SIZE, 16): -// * We need at least 2 * WORD_SIZE bytes to guarantee that at least 1 word will be copied through -// word-wise copy. -// * The word-wise copy logic needs to perform some checks so it has some small overhead. -// ensures that even on 32-bit platforms we have copied at least 8 bytes through -// word-wise copy so the saving of word-wise copy outweighs the fixed overhead. -const WORD_COPY_THRESHOLD: usize = if 2 * WORD_SIZE > 16 { - 2 * WORD_SIZE -} else { - 16 -}; - -#[cfg(feature = "mem-unaligned")] -unsafe fn read_usize_unaligned(x: *const usize) -> usize { - // Do not use `core::ptr::read_unaligned` here, since it calls `copy_nonoverlapping` which - // is translated to memcpy in LLVM. - let x_read = (x as *const [u8; core::mem::size_of::()]).read(); - core::mem::transmute(x_read) -} - -#[inline(always)] -pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) { - #[inline(always)] - unsafe fn copy_forward_bytes(mut dest: *mut u8, mut src: *const u8, n: usize) { - let dest_end = dest.wrapping_add(n); - while dest < dest_end { - *dest = *src; - dest = dest.wrapping_add(1); - src = src.wrapping_add(1); - } - } - - #[inline(always)] - unsafe fn copy_forward_aligned_words(dest: *mut u8, src: *const u8, n: usize) { - let mut dest_usize = dest as *mut usize; - let mut src_usize = src as *mut usize; - let dest_end = dest.wrapping_add(n) as *mut usize; - - while dest_usize < dest_end { - *dest_usize = *src_usize; - dest_usize = dest_usize.wrapping_add(1); - src_usize = src_usize.wrapping_add(1); - } - } - - #[cfg(not(feature = "mem-unaligned"))] - #[inline(always)] - unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { - let mut dest_usize = dest as *mut usize; - let dest_end = dest.wrapping_add(n) as *mut usize; - - // Calculate the misalignment offset and shift needed to reassemble value. - let offset = src as usize & WORD_MASK; - let shift = offset * 8; - - // Realign src - let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; - // This will read (but won't use) bytes out of bound. - // cfg needed because not all targets will have atomic loads that can be lowered - // (e.g. BPF, MSP430), or provided by an external library (e.g. RV32I) - #[cfg(target_has_atomic_load_store = "ptr")] - let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); - #[cfg(not(target_has_atomic_load_store = "ptr"))] - let mut prev_word = core::ptr::read_volatile(src_aligned); - - while dest_usize < dest_end { - src_aligned = src_aligned.wrapping_add(1); - let cur_word = *src_aligned; - #[cfg(target_endian = "little")] - let resembled = prev_word >> shift | cur_word << (WORD_SIZE * 8 - shift); - #[cfg(target_endian = "big")] - let resembled = prev_word << shift | cur_word >> (WORD_SIZE * 8 - shift); - prev_word = cur_word; - - *dest_usize = resembled; - dest_usize = dest_usize.wrapping_add(1); - } - } - - #[cfg(feature = "mem-unaligned")] - #[inline(always)] - unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { - let mut dest_usize = dest as *mut usize; - let mut src_usize = src as *mut usize; - let dest_end = dest.wrapping_add(n) as *mut usize; - - while dest_usize < dest_end { - *dest_usize = read_usize_unaligned(src_usize); - dest_usize = dest_usize.wrapping_add(1); - src_usize = src_usize.wrapping_add(1); - } - } - - if n >= WORD_COPY_THRESHOLD { - // Align dest - // Because of n >= 2 * WORD_SIZE, dst_misalignment < n - let dest_misalignment = (dest as usize).wrapping_neg() & WORD_MASK; - copy_forward_bytes(dest, src, dest_misalignment); - dest = dest.wrapping_add(dest_misalignment); - src = src.wrapping_add(dest_misalignment); - n -= dest_misalignment; - - let n_words = n & !WORD_MASK; - let src_misalignment = src as usize & WORD_MASK; - if likely(src_misalignment == 0) { - copy_forward_aligned_words(dest, src, n_words); - } else { - copy_forward_misaligned_words(dest, src, n_words); - } - dest = dest.wrapping_add(n_words); - src = src.wrapping_add(n_words); - n -= n_words; - } - copy_forward_bytes(dest, src, n); -} - -#[inline(always)] -pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { - // The following backward copy helper functions uses the pointers past the end - // as their inputs instead of pointers to the start! - #[inline(always)] - unsafe fn copy_backward_bytes(mut dest: *mut u8, mut src: *const u8, n: usize) { - let dest_start = dest.wrapping_sub(n); - while dest_start < dest { - dest = dest.wrapping_sub(1); - src = src.wrapping_sub(1); - *dest = *src; - } - } - - #[inline(always)] - unsafe fn copy_backward_aligned_words(dest: *mut u8, src: *const u8, n: usize) { - let mut dest_usize = dest as *mut usize; - let mut src_usize = src as *mut usize; - let dest_start = dest.wrapping_sub(n) as *mut usize; - - while dest_start < dest_usize { - dest_usize = dest_usize.wrapping_sub(1); - src_usize = src_usize.wrapping_sub(1); - *dest_usize = *src_usize; - } - } - - #[cfg(not(feature = "mem-unaligned"))] - #[inline(always)] - unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { - let mut dest_usize = dest as *mut usize; - let dest_start = dest.wrapping_sub(n) as *mut usize; - - // Calculate the misalignment offset and shift needed to reassemble value. - let offset = src as usize & WORD_MASK; - let shift = offset * 8; - - // Realign src_aligned - let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; - // This will read (but won't use) bytes out of bound. - // cfg needed because not all targets will have atomic loads that can be lowered - // (e.g. BPF, MSP430), or provided by an external library (e.g. RV32I) - #[cfg(target_has_atomic_load_store = "ptr")] - let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); - #[cfg(not(target_has_atomic_load_store = "ptr"))] - let mut prev_word = core::ptr::read_volatile(src_aligned); - - while dest_start < dest_usize { - src_aligned = src_aligned.wrapping_sub(1); - let cur_word = *src_aligned; - #[cfg(target_endian = "little")] - let resembled = prev_word << (WORD_SIZE * 8 - shift) | cur_word >> shift; - #[cfg(target_endian = "big")] - let resembled = prev_word >> (WORD_SIZE * 8 - shift) | cur_word << shift; - prev_word = cur_word; - - dest_usize = dest_usize.wrapping_sub(1); - *dest_usize = resembled; - } - } - - #[cfg(feature = "mem-unaligned")] - #[inline(always)] - unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { - let mut dest_usize = dest as *mut usize; - let mut src_usize = src as *mut usize; - let dest_start = dest.wrapping_sub(n) as *mut usize; - - while dest_start < dest_usize { - dest_usize = dest_usize.wrapping_sub(1); - src_usize = src_usize.wrapping_sub(1); - *dest_usize = read_usize_unaligned(src_usize); - } - } - - let mut dest = dest.wrapping_add(n); - let mut src = src.wrapping_add(n); - - if n >= WORD_COPY_THRESHOLD { - // Align dest - // Because of n >= 2 * WORD_SIZE, dst_misalignment < n - let dest_misalignment = dest as usize & WORD_MASK; - copy_backward_bytes(dest, src, dest_misalignment); - dest = dest.wrapping_sub(dest_misalignment); - src = src.wrapping_sub(dest_misalignment); - n -= dest_misalignment; - - let n_words = n & !WORD_MASK; - let src_misalignment = src as usize & WORD_MASK; - if likely(src_misalignment == 0) { - copy_backward_aligned_words(dest, src, n_words); - } else { - copy_backward_misaligned_words(dest, src, n_words); - } - dest = dest.wrapping_sub(n_words); - src = src.wrapping_sub(n_words); - n -= n_words; - } - copy_backward_bytes(dest, src, n); -} - -#[inline(always)] -pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { - #[inline(always)] - pub unsafe fn set_bytes_bytes(mut s: *mut u8, c: u8, n: usize) { - let end = s.wrapping_add(n); - while s < end { - *s = c; - s = s.wrapping_add(1); - } - } - - #[inline(always)] - pub unsafe fn set_bytes_words(s: *mut u8, c: u8, n: usize) { - let mut broadcast = c as usize; - let mut bits = 8; - while bits < WORD_SIZE * 8 { - broadcast |= broadcast << bits; - bits *= 2; - } - - let mut s_usize = s as *mut usize; - let end = s.wrapping_add(n) as *mut usize; - - while s_usize < end { - *s_usize = broadcast; - s_usize = s_usize.wrapping_add(1); - } - } - - if likely(n >= WORD_COPY_THRESHOLD) { - // Align s - // Because of n >= 2 * WORD_SIZE, dst_misalignment < n - let misalignment = (s as usize).wrapping_neg() & WORD_MASK; - set_bytes_bytes(s, c, misalignment); - s = s.wrapping_add(misalignment); - n -= misalignment; - - let n_words = n & !WORD_MASK; - set_bytes_words(s, c, n_words); - s = s.wrapping_add(n_words); - n -= n_words; - } - set_bytes_bytes(s, c, n); -} - -#[inline(always)] -pub unsafe fn compare_bytes(s1: *const u8, s2: *const u8, n: usize) -> i32 { - let mut i = 0; - while i < n { - let a = *s1.wrapping_add(i); - let b = *s2.wrapping_add(i); - if a != b { - return a as i32 - b as i32; - } - i += 1; - } - 0 -} - -#[inline(always)] -pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { - let mut n = 0; - while *s != 0 { - n += 1; - s = s.wrapping_add(1); - } - n -} diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs deleted file mode 100644 index ec160039d0d..00000000000 --- a/library/compiler-builtins/src/mem/mod.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Trying to satisfy clippy here is hopeless -#![allow(clippy::style)] - -#[allow(warnings)] -#[cfg(target_pointer_width = "16")] -type c_int = i16; -#[allow(warnings)] -#[cfg(not(target_pointer_width = "16"))] -type c_int = i32; - -// memcpy/memmove/memset have optimized implementations on some architectures -#[cfg_attr( - all(not(feature = "no-asm"), target_arch = "x86_64"), - path = "x86_64.rs" -)] -mod impls; - -intrinsics! { - #[mem_builtin] - pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - impls::copy_forward(dest, src, n); - dest - } - - #[mem_builtin] - pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - let delta = (dest as usize).wrapping_sub(src as usize); - if delta >= n { - // We can copy forwards because either dest is far enough ahead of src, - // or src is ahead of dest (and delta overflowed). - impls::copy_forward(dest, src, n); - } else { - impls::copy_backward(dest, src, n); - } - dest - } - - #[mem_builtin] - pub unsafe extern "C" fn memset(s: *mut u8, c: crate::mem::c_int, n: usize) -> *mut u8 { - impls::set_bytes(s, c as u8, n); - s - } - - #[mem_builtin] - pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - impls::compare_bytes(s1, s2, n) - } - - #[mem_builtin] - pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - memcmp(s1, s2, n) - } - - #[mem_builtin] - pub unsafe extern "C" fn strlen(s: *const core::ffi::c_char) -> usize { - impls::c_string_length(s) - } -} diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs deleted file mode 100644 index 40b67093f51..00000000000 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ /dev/null @@ -1,314 +0,0 @@ -// On most modern Intel and AMD processors, "rep movsq" and "rep stosq" have -// been enhanced to perform better than an simple qword loop, making them ideal -// for implementing memcpy/memset. Note that "rep cmps" has received no such -// enhancement, so it is not used to implement memcmp. -// -// On certain recent Intel processors, "rep movsb" and "rep stosb" have been -// further enhanced to automatically select the best microarchitectural -// implementation based on length and alignment. See the following features from -// the "Intel® 64 and IA-32 Architectures Optimization Reference Manual": -// - ERMSB - Enhanced REP MOVSB and STOSB (Ivy Bridge and later) -// - FSRM - Fast Short REP MOV (Ice Lake and later) -// - Fast Zero-Length MOVSB (On no current hardware) -// - Fast Short STOSB (On no current hardware) -// -// To simplify things, we switch to using the byte-based variants if the "ermsb" -// feature is present at compile-time. We don't bother detecting other features. -// Note that ERMSB does not enhance the backwards (DF=1) "rep movsb". - -use core::arch::asm; -use core::intrinsics; -use core::mem; - -#[inline(always)] -#[cfg(target_feature = "ermsb")] -pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { - // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - core::arch::asm!( - "repe movsb (%rsi), (%rdi)", - inout("rcx") count => _, - inout("rdi") dest => _, - inout("rsi") src => _, - options(att_syntax, nostack, preserves_flags) - ); -} - -#[inline(always)] -#[cfg(not(target_feature = "ermsb"))] -pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) { - let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); - // Separating the blocks gives the compiler more freedom to reorder instructions. - asm!( - "rep movsb", - inout("ecx") pre_byte_count => _, - inout("rdi") dest => dest, - inout("rsi") src => src, - options(att_syntax, nostack, preserves_flags) - ); - asm!( - "rep movsq", - inout("rcx") qword_count => _, - inout("rdi") dest => dest, - inout("rsi") src => src, - options(att_syntax, nostack, preserves_flags) - ); - asm!( - "rep movsb", - inout("ecx") byte_count => _, - inout("rdi") dest => _, - inout("rsi") src => _, - options(att_syntax, nostack, preserves_flags) - ); -} - -#[inline(always)] -pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { - let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); - // We can't separate this block due to std/cld - asm!( - "std", - "rep movsb", - "sub $7, %rsi", - "sub $7, %rdi", - "mov {qword_count}, %rcx", - "rep movsq", - "test {pre_byte_count:e}, {pre_byte_count:e}", - "add $7, %rsi", - "add $7, %rdi", - "mov {pre_byte_count:e}, %ecx", - "rep movsb", - "cld", - pre_byte_count = in(reg) pre_byte_count, - qword_count = in(reg) qword_count, - inout("ecx") byte_count => _, - inout("rdi") dest.add(count - 1) => _, - inout("rsi") src.add(count - 1) => _, - // We modify flags, but we restore it afterwards - options(att_syntax, nostack, preserves_flags) - ); -} - -#[inline(always)] -#[cfg(target_feature = "ermsb")] -pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { - // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - core::arch::asm!( - "repe stosb %al, (%rdi)", - inout("rcx") count => _, - inout("rdi") dest => _, - inout("al") c => _, - options(att_syntax, nostack, preserves_flags) - ) -} - -#[inline(always)] -#[cfg(not(target_feature = "ermsb"))] -pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { - let c = c as u64 * 0x0101_0101_0101_0101; - let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); - // Separating the blocks gives the compiler more freedom to reorder instructions. - asm!( - "rep stosb", - inout("ecx") pre_byte_count => _, - inout("rdi") dest => dest, - in("rax") c, - options(att_syntax, nostack, preserves_flags) - ); - asm!( - "rep stosq", - inout("rcx") qword_count => _, - inout("rdi") dest => dest, - in("rax") c, - options(att_syntax, nostack, preserves_flags) - ); - asm!( - "rep stosb", - inout("ecx") byte_count => _, - inout("rdi") dest => _, - in("rax") c, - options(att_syntax, nostack, preserves_flags) - ); -} - -#[inline(always)] -pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { - #[inline(always)] - unsafe fn cmp(mut a: *const T, mut b: *const T, n: usize, f: F) -> i32 - where - T: Clone + Copy + Eq, - U: Clone + Copy + Eq, - F: FnOnce(*const U, *const U, usize) -> i32, - { - // Ensure T is not a ZST. - const { assert!(mem::size_of::() != 0) }; - - let end = a.add(intrinsics::unchecked_div(n, mem::size_of::())); - while a != end { - if a.read_unaligned() != b.read_unaligned() { - return f(a.cast(), b.cast(), mem::size_of::()); - } - a = a.add(1); - b = b.add(1); - } - f( - a.cast(), - b.cast(), - intrinsics::unchecked_rem(n, mem::size_of::()), - ) - } - let c1 = |mut a: *const u8, mut b: *const u8, n| { - for _ in 0..n { - if a.read() != b.read() { - return i32::from(a.read()) - i32::from(b.read()); - } - a = a.add(1); - b = b.add(1); - } - 0 - }; - let c2 = |a: *const u16, b, n| cmp(a, b, n, c1); - let c4 = |a: *const u32, b, n| cmp(a, b, n, c2); - let c8 = |a: *const u64, b, n| cmp(a, b, n, c4); - let c16 = |a: *const u128, b, n| cmp(a, b, n, c8); - c16(a.cast(), b.cast(), n) -} - -// In order to process more than on byte simultaneously when executing strlen, -// two things must be considered: -// * An n byte read with an n-byte aligned address will never cross -// a page boundary and will always succeed. Any smaller alignment -// may result in a read that will cross a page boundary, which may -// trigger an access violation. -// * Surface Rust considers any kind of out-of-bounds read as undefined -// behaviour. To dodge this, memory access operations are written -// using inline assembly. - -#[cfg(target_feature = "sse2")] -#[inline(always)] -pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { - use core::arch::x86_64::{__m128i, _mm_cmpeq_epi8, _mm_movemask_epi8, _mm_set1_epi8}; - - let mut n = 0; - - // The use of _mm_movemask_epi8 and company allow for speedups, - // but they aren't cheap by themselves. Thus, possibly small strings - // are handled in simple loops. - - for _ in 0..4 { - if *s == 0 { - return n; - } - - n += 1; - s = s.add(1); - } - - // Shave of the least significand bits to align the address to a 16 - // byte boundary. The shaved of bits are used to correct the first iteration. - - let align = s as usize & 15; - let mut s = ((s as usize) - align) as *const __m128i; - let zero = _mm_set1_epi8(0); - - let x = { - let r; - asm!( - "movdqa ({addr}), {dest}", - addr = in(reg) s, - dest = out(xmm_reg) r, - options(att_syntax, nostack), - ); - r - }; - let cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(x, zero)) >> align; - - if cmp != 0 { - return n + cmp.trailing_zeros() as usize; - } - - n += 16 - align; - s = s.add(1); - - loop { - let x = { - let r; - asm!( - "movdqa ({addr}), {dest}", - addr = in(reg) s, - dest = out(xmm_reg) r, - options(att_syntax, nostack), - ); - r - }; - let cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(x, zero)) as u32; - if cmp == 0 { - n += 16; - s = s.add(1); - } else { - return n + cmp.trailing_zeros() as usize; - } - } -} - -// Provided for scenarios like kernel development, where SSE might not -// be available. -#[cfg(not(target_feature = "sse2"))] -#[inline(always)] -pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { - let mut n = 0; - - // Check bytes in steps of one until - // either a zero byte is discovered or - // pointer is aligned to an eight byte boundary. - - while s as usize & 7 != 0 { - if *s == 0 { - return n; - } - n += 1; - s = s.add(1); - } - - // Check bytes in steps of eight until a zero - // byte is discovered. - - let mut s = s as *const u64; - - loop { - let mut cs = { - let r: u64; - asm!( - "mov ({addr}), {dest}", - addr = in(reg) s, - dest = out(reg) r, - options(att_syntax, nostack), - ); - r - }; - // Detect if a word has a zero byte, taken from - // https://graphics.stanford.edu/~seander/bithacks.html - if (cs.wrapping_sub(0x0101010101010101) & !cs & 0x8080808080808080) != 0 { - loop { - if cs & 255 == 0 { - return n; - } else { - cs >>= 8; - n += 1; - } - } - } else { - n += 8; - s = s.add(1); - } - } -} - -/// Determine optimal parameters for a `rep` instruction. -fn rep_param(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { - // Unaligned writes are still slow on modern processors, so align the destination address. - let pre_byte_count = ((8 - (dest as usize & 0b111)) & 0b111).min(count); - count -= pre_byte_count; - let qword_count = count >> 3; - let byte_count = count & 0b111; - (pre_byte_count, qword_count, byte_count) -} diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs deleted file mode 100644 index 5b6abd21a1d..00000000000 --- a/library/compiler-builtins/src/probestack.rs +++ /dev/null @@ -1,350 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! This module defines the `__rust_probestack` intrinsic which is used in the -//! implementation of "stack probes" on certain platforms. -//! -//! The purpose of a stack probe is to provide a static guarantee that if a -//! thread has a guard page then a stack overflow is guaranteed to hit that -//! guard page. If a function did not have a stack probe then there's a risk of -//! having a stack frame *larger* than the guard page, so a function call could -//! skip over the guard page entirely and then later hit maybe the heap or -//! another thread, possibly leading to security vulnerabilities such as [The -//! Stack Clash], for example. -//! -//! [The Stack Clash]: https://blog.qualys.com/securitylabs/2017/06/19/the-stack-clash -//! -//! The `__rust_probestack` is called in the prologue of functions whose stack -//! size is larger than the guard page, for example larger than 4096 bytes on -//! x86. This function is then responsible for "touching" all pages relevant to -//! the stack to ensure that that if any of them are the guard page we'll hit -//! them guaranteed. -//! -//! The precise ABI for how this function operates is defined by LLVM. There's -//! no real documentation as to what this is, so you'd basically need to read -//! the LLVM source code for reference. Often though the test cases can be -//! illuminating as to the ABI that's generated, or just looking at the output -//! of `llc`. -//! -//! Note that `#[naked]` is typically used here for the stack probe because the -//! ABI corresponds to no actual ABI. -//! -//! Finally it's worth noting that at the time of this writing LLVM only has -//! support for stack probes on x86 and x86_64. There's no support for stack -//! probes on any other architecture like ARM or PowerPC64. LLVM I'm sure would -//! be more than welcome to accept such a change! - -#![cfg(not(feature = "mangled-names"))] -// Windows and Cygwin already has builtins to do this. -#![cfg(not(any(windows, target_os = "cygwin")))] -// All these builtins require assembly -#![cfg(not(feature = "no-asm"))] -// We only define stack probing for these architectures today. -#![cfg(any(target_arch = "x86_64", target_arch = "x86"))] - -extern "C" { - pub fn __rust_probestack(); -} - -// A wrapper for our implementation of __rust_probestack, which allows us to -// keep the assembly inline while controlling all CFI directives in the assembly -// emitted for the function. -// -// This is the ELF version. -#[cfg(not(any(target_vendor = "apple", target_os = "uefi")))] -macro_rules! define_rust_probestack { - ($body: expr) => { - concat!( - " - .pushsection .text.__rust_probestack - .globl __rust_probestack - .type __rust_probestack, @function - .hidden __rust_probestack - __rust_probestack: - ", - $body, - " - .size __rust_probestack, . - __rust_probestack - .popsection - " - ) - }; -} - -#[cfg(all(target_os = "uefi", target_arch = "x86_64"))] -macro_rules! define_rust_probestack { - ($body: expr) => { - concat!( - " - .globl __rust_probestack - __rust_probestack: - ", - $body - ) - }; -} - -// Same as above, but for Mach-O. Note that the triple underscore -// is deliberate -#[cfg(target_vendor = "apple")] -macro_rules! define_rust_probestack { - ($body: expr) => { - concat!( - " - .globl ___rust_probestack - ___rust_probestack: - ", - $body - ) - }; -} - -// In UEFI x86 arch, triple underscore is deliberate. -#[cfg(all(target_os = "uefi", target_arch = "x86"))] -macro_rules! define_rust_probestack { - ($body: expr) => { - concat!( - " - .globl ___rust_probestack - ___rust_probestack: - ", - $body - ) - }; -} - -// Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, -// ensuring that if any pages are unmapped we'll make a page fault. -// -// The ABI here is that the stack frame size is located in `%rax`. Upon -// return we're not supposed to modify `%rsp` or `%rax`. -// -// Any changes to this function should be replicated to the SGX version below. -#[cfg(all( - target_arch = "x86_64", - not(all(target_env = "sgx", target_vendor = "fortanix")) -))] -core::arch::global_asm!( - define_rust_probestack!( - " - .cfi_startproc - pushq %rbp - .cfi_adjust_cfa_offset 8 - .cfi_offset %rbp, -16 - movq %rsp, %rbp - .cfi_def_cfa_register %rbp - - mov %rax,%r11 // duplicate %rax as we're clobbering %r11 - - // Main loop, taken in one page increments. We're decrementing rsp by - // a page each time until there's less than a page remaining. We're - // guaranteed that this function isn't called unless there's more than a - // page needed. - // - // Note that we're also testing against `8(%rsp)` to account for the 8 - // bytes pushed on the stack orginally with our return address. Using - // `8(%rsp)` simulates us testing the stack pointer in the caller's - // context. - - // It's usually called when %rax >= 0x1000, but that's not always true. - // Dynamic stack allocation, which is needed to implement unsized - // rvalues, triggers stackprobe even if %rax < 0x1000. - // Thus we have to check %r11 first to avoid segfault. - cmp $0x1000,%r11 - jna 3f -2: - sub $0x1000,%rsp - test %rsp,8(%rsp) - sub $0x1000,%r11 - cmp $0x1000,%r11 - ja 2b - -3: - // Finish up the last remaining stack space requested, getting the last - // bits out of r11 - sub %r11,%rsp - test %rsp,8(%rsp) - - // Restore the stack pointer to what it previously was when entering - // this function. The caller will readjust the stack pointer after we - // return. - add %rax,%rsp - - leave - .cfi_def_cfa_register %rsp - .cfi_adjust_cfa_offset -8 - ret - .cfi_endproc - " - ), - options(att_syntax) -); - -// This function is the same as above, except that some instructions are -// [manually patched for LVI]. -// -// [manually patched for LVI]: https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions -#[cfg(all( - target_arch = "x86_64", - all(target_env = "sgx", target_vendor = "fortanix") -))] -core::arch::global_asm!( - define_rust_probestack!( - " - .cfi_startproc - pushq %rbp - .cfi_adjust_cfa_offset 8 - .cfi_offset %rbp, -16 - movq %rsp, %rbp - .cfi_def_cfa_register %rbp - - mov %rax,%r11 // duplicate %rax as we're clobbering %r11 - - // Main loop, taken in one page increments. We're decrementing rsp by - // a page each time until there's less than a page remaining. We're - // guaranteed that this function isn't called unless there's more than a - // page needed. - // - // Note that we're also testing against `8(%rsp)` to account for the 8 - // bytes pushed on the stack orginally with our return address. Using - // `8(%rsp)` simulates us testing the stack pointer in the caller's - // context. - - // It's usually called when %rax >= 0x1000, but that's not always true. - // Dynamic stack allocation, which is needed to implement unsized - // rvalues, triggers stackprobe even if %rax < 0x1000. - // Thus we have to check %r11 first to avoid segfault. - cmp $0x1000,%r11 - jna 3f -2: - sub $0x1000,%rsp - test %rsp,8(%rsp) - sub $0x1000,%r11 - cmp $0x1000,%r11 - ja 2b - -3: - // Finish up the last remaining stack space requested, getting the last - // bits out of r11 - sub %r11,%rsp - test %rsp,8(%rsp) - - // Restore the stack pointer to what it previously was when entering - // this function. The caller will readjust the stack pointer after we - // return. - add %rax,%rsp - - leave - .cfi_def_cfa_register %rsp - .cfi_adjust_cfa_offset -8 - pop %r11 - lfence - jmp *%r11 - .cfi_endproc - " - ), - options(att_syntax) -); - -#[cfg(all(target_arch = "x86", not(target_os = "uefi")))] -// This is the same as x86_64 above, only translated for 32-bit sizes. Note -// that on Unix we're expected to restore everything as it was, this -// function basically can't tamper with anything. -// -// The ABI here is the same as x86_64, except everything is 32-bits large. -core::arch::global_asm!( - define_rust_probestack!( - " - .cfi_startproc - push %ebp - .cfi_adjust_cfa_offset 4 - .cfi_offset %ebp, -8 - mov %esp, %ebp - .cfi_def_cfa_register %ebp - push %ecx - mov %eax,%ecx - - cmp $0x1000,%ecx - jna 3f -2: - sub $0x1000,%esp - test %esp,8(%esp) - sub $0x1000,%ecx - cmp $0x1000,%ecx - ja 2b - -3: - sub %ecx,%esp - test %esp,8(%esp) - - add %eax,%esp - pop %ecx - leave - .cfi_def_cfa_register %esp - .cfi_adjust_cfa_offset -4 - ret - .cfi_endproc - " - ), - options(att_syntax) -); - -#[cfg(all(target_arch = "x86", target_os = "uefi"))] -// UEFI target is windows like target. LLVM will do _chkstk things like windows. -// probestack function will also do things like _chkstk in MSVC. -// So we need to sub %ax %sp in probestack when arch is x86. -// -// REF: Rust commit(74e80468347) -// rust\src\llvm-project\llvm\lib\Target\X86\X86FrameLowering.cpp: 805 -// Comments in LLVM: -// MSVC x32's _chkstk and cygwin/mingw's _alloca adjust %esp themselves. -// MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp -// themselves. -core::arch::global_asm!( - define_rust_probestack!( - " - .cfi_startproc - push %ebp - .cfi_adjust_cfa_offset 4 - .cfi_offset %ebp, -8 - mov %esp, %ebp - .cfi_def_cfa_register %ebp - push %ecx - push %edx - mov %eax,%ecx - - cmp $0x1000,%ecx - jna 3f -2: - sub $0x1000,%esp - test %esp,8(%esp) - sub $0x1000,%ecx - cmp $0x1000,%ecx - ja 2b - -3: - sub %ecx,%esp - test %esp,8(%esp) - mov 4(%ebp),%edx - mov %edx, 12(%esp) - add %eax,%esp - pop %edx - pop %ecx - leave - - sub %eax, %esp - .cfi_def_cfa_register %esp - .cfi_adjust_cfa_offset -4 - ret - .cfi_endproc - " - ), - options(att_syntax) -); diff --git a/library/compiler-builtins/src/riscv.rs b/library/compiler-builtins/src/riscv.rs deleted file mode 100644 index bf312553341..00000000000 --- a/library/compiler-builtins/src/riscv.rs +++ /dev/null @@ -1,50 +0,0 @@ -intrinsics! { - // Ancient Egyptian/Ethiopian/Russian multiplication method - // see https://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication - // - // This is a long-available stock algorithm; e.g. it is documented in - // Knuth's "The Art of Computer Programming" volume 2 (under the section - // "Evaluation of Powers") since at least the 2nd edition (1981). - // - // The main attraction of this method is that it implements (software) - // multiplication atop four simple operations: doubling, halving, checking - // if a value is even/odd, and addition. This is *not* considered to be the - // fastest multiplication method, but it may be amongst the simplest (and - // smallest with respect to code size). - // - // for reference, see also implementation from gcc - // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c - // - // and from LLVM (in relatively readable RISC-V assembly): - // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/riscv/int_mul_impl.inc - pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { - let (mut a, mut b) = (a, b); - let mut r: u32 = 0; - - while a > 0 { - if a & 1 > 0 { - r = r.wrapping_add(b); - } - a >>= 1; - b <<= 1; - } - - r - } - - #[cfg(not(target_feature = "m"))] - pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { - let (mut a, mut b) = (a, b); - let mut r: u64 = 0; - - while a > 0 { - if a & 1 > 0 { - r = r.wrapping_add(b); - } - a >>= 1; - b <<= 1; - } - - r - } -} diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs deleted file mode 100644 index ad04d2108ea..00000000000 --- a/library/compiler-builtins/src/x86.rs +++ /dev/null @@ -1,53 +0,0 @@ -#![allow(unused_imports)] - -use core::intrinsics; - -// NOTE These functions are implemented using assembly because they using a custom -// calling convention which can't be implemented using a normal Rust function - -// NOTE These functions are never mangled as they are not tested against compiler-rt - -intrinsics! { - #[naked] - #[cfg(all( - any(all(windows, target_env = "gnu"), target_os = "uefi"), - not(feature = "no-asm") - ))] - pub unsafe extern "C" fn __chkstk() { - core::arch::naked_asm!( - "jmp __alloca", // Jump to __alloca since fallthrough may be unreliable" - options(att_syntax) - ); - } - - #[naked] - #[cfg(all( - any(all(windows, target_env = "gnu"), target_os = "uefi"), - not(feature = "no-asm") - ))] - pub unsafe extern "C" fn _alloca() { - // __chkstk and _alloca are the same function - core::arch::naked_asm!( - "push %ecx", - "cmp $0x1000,%eax", - "lea 8(%esp),%ecx", // esp before calling this routine -> ecx - "jb 1f", - "2:", - "sub $0x1000,%ecx", - "test %ecx,(%ecx)", - "sub $0x1000,%eax", - "cmp $0x1000,%eax", - "ja 2b", - "1:", - "sub %eax,%ecx", - "test %ecx,(%ecx)", - "lea 4(%esp),%eax", // load pointer to the return address into eax - "mov %ecx,%esp", // install the new top of stack pointer into esp - "mov -4(%eax),%ecx", // restore ecx - "push (%eax)", // push return address onto the stack - "sub %esp,%eax", // restore the original value in eax - "ret", - options(att_syntax) - ); - } -} diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs deleted file mode 100644 index aae601f58bf..00000000000 --- a/library/compiler-builtins/src/x86_64.rs +++ /dev/null @@ -1,51 +0,0 @@ -#![allow(unused_imports)] - -use core::intrinsics; - -// NOTE These functions are implemented using assembly because they using a custom -// calling convention which can't be implemented using a normal Rust function - -// NOTE These functions are never mangled as they are not tested against compiler-rt - -intrinsics! { - #[naked] - #[cfg(all( - any( - all(windows, target_env = "gnu"), - target_os = "cygwin", - target_os = "uefi" - ), - not(feature = "no-asm") - ))] - pub unsafe extern "C" fn ___chkstk_ms() { - core::arch::naked_asm!( - "push %rcx", - "push %rax", - "cmp $0x1000,%rax", - "lea 24(%rsp),%rcx", - "jb 1f", - "2:", - "sub $0x1000,%rcx", - "test %rcx,(%rcx)", - "sub $0x1000,%rax", - "cmp $0x1000,%rax", - "ja 2b", - "1:", - "sub %rax,%rcx", - "test %rcx,(%rcx)", - "pop %rax", - "pop %rcx", - "ret", - options(att_syntax) - ); - } -} - -// HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM -// support unless we emit the _fltused -mod _fltused { - #[no_mangle] - #[used] - #[cfg(target_os = "uefi")] - static _fltused: i32 = 0; -} diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 71c461c578c..be60e694fa9 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -18,7 +18,7 @@ rand_xoshiro = "0.6" rustc_apfloat = "0.2.1" [dependencies.compiler_builtins] -path = ".." +path = "../compiler-builtins" default-features = false features = ["public-test-deps"] diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 566b985d246..e8f4eb4dd22 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; mod builtins_configure { - include!("../configure.rs"); + include!("../compiler-builtins/configure.rs"); } /// Features to enable -- cgit 1.4.1-3-g733a5 From fc1b87da4a8ebe90f9203b6b8b2ac1c9d857edd9 Mon Sep 17 00:00:00 2001 From: beetrees Date: Wed, 12 Mar 2025 18:02:51 +0000 Subject: Remove use of `atomic_load_unordered` and undefined behaviour from `arm_linux.rs` --- .../compiler-builtins/src/arm_linux.rs | 47 ++++++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/compiler-builtins/src/arm_linux.rs index 8f22eb62866..aeb3ff3e506 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm_linux.rs @@ -1,5 +1,6 @@ -use core::intrinsics; +use core::arch; use core::mem; +use core::sync::atomic::{AtomicU32, Ordering}; // Kernel-provided user-mode helper functions: // https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt @@ -7,6 +8,7 @@ unsafe fn __kuser_cmpxchg(oldval: u32, newval: u32, ptr: *mut u32) -> bool { let f: extern "C" fn(u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0usize as *const ()); f(oldval, newval, ptr) == 0 } + unsafe fn __kuser_memory_barrier() { let f: extern "C" fn() = mem::transmute(0xffff0fa0usize as *const ()); f(); @@ -54,13 +56,52 @@ fn insert_aligned(aligned: u32, val: u32, shift: u32, mask: u32) -> u32 { (aligned & !(mask << shift)) | ((val & mask) << shift) } +/// Performs a relaxed atomic load of 4 bytes at `ptr`. Some of the bytes are allowed to be out of +/// bounds as long as `size_of::()` bytes are in bounds. +/// +/// # Safety +/// +/// - `ptr` must be 4-aligned. +/// - `size_of::()` must be at most 4. +/// - if `size_of::() == 1`, `ptr` or `ptr` offset by 1, 2 or 3 bytes must be valid for a relaxed +/// atomic read of 1 byte. +/// - if `size_of::() == 2`, `ptr` or `ptr` offset by 2 bytes must be valid for a relaxed atomic +/// read of 2 bytes. +/// - if `size_of::() == 4`, `ptr` must be valid for a relaxed atomic read of 4 bytes. +unsafe fn atomic_load_aligned(ptr: *mut u32) -> u32 { + if mem::size_of::() == 4 { + // SAFETY: As `T` has a size of 4, the caller garantees this is sound. + unsafe { AtomicU32::from_ptr(ptr).load(Ordering::Relaxed) } + } else { + // SAFETY: + // As all 4 bytes pointed to by `ptr` might not be dereferenceable due to being out of + // bounds when doing atomic operations on a `u8`/`i8`/`u16`/`i16`, inline ASM is used to + // avoid causing undefined behaviour. However, as `ptr` is 4-aligned and at least 1 byte of + // `ptr` is dereferencable, the load won't cause a segfault as the page size is always + // larger than 4 bytes. + // The `ldr` instruction does not touch the stack or flags, or write to memory, so + // `nostack`, `preserves_flags` and `readonly` are sound. The caller garantees that `ptr` is + // 4-aligned, as required by `ldr`. + unsafe { + let res: u32; + arch::asm!( + "ldr {res}, [{ptr}]", + ptr = in(reg) ptr, + res = lateout(reg) res, + options(nostack, preserves_flags, readonly) + ); + res + } + } +} + // Generic atomic read-modify-write operation unsafe fn atomic_rmw u32, G: Fn(u32, u32) -> u32>(ptr: *mut T, f: F, g: G) -> u32 { let aligned_ptr = align_ptr(ptr); let (shift, mask) = get_shift_mask(ptr); loop { - let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr); + let curval_aligned = atomic_load_aligned::(aligned_ptr); let curval = extract_aligned(curval_aligned, shift, mask); let newval = f(curval); let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask); @@ -76,7 +117,7 @@ unsafe fn atomic_cmpxchg(ptr: *mut T, oldval: u32, newval: u32) -> u32 { let (shift, mask) = get_shift_mask(ptr); loop { - let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr); + let curval_aligned = atomic_load_aligned::(aligned_ptr); let curval = extract_aligned(curval_aligned, shift, mask); if curval != oldval { return curval; -- cgit 1.4.1-3-g733a5 From a0d40f287acc5604d225fee0bb7b09b4817a5f80 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 02:02:43 +0000 Subject: chore: release v0.1.152 --- library/compiler-builtins/compiler-builtins/CHANGELOG.md | 15 +++++++++++++++ library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/compiler-builtins/CHANGELOG.md diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md new file mode 100644 index 00000000000..987f8771307 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.152](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.151...compiler_builtins-v0.1.152) - 2025-03-20 + +### Other + +- Remove use of `atomic_load_unordered` and undefined behaviour from `arm_linux.rs` +- Switch repository layout to use a virtual manifest diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 9797b5e65b5..8de8bce6a12 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.151" +version = "0.1.152" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "../README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From f0f9cfa46304b025f23a10cc1103b186669fdc01 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 20 Mar 2025 11:19:09 +0000 Subject: Add benchmarks using `iai-callgrind` This crate [1] makes it reasonably easy to get instruction count performance metrics that are stable enough to run in CI, and has worked out well since integrating it with `libm`. Add new benchmarks for `mem` functions using `iai-callgrind`, modeling them off of the existing benchmarks. [1]: https://github.com/iai-callgrind/iai-callgrind --- library/compiler-builtins/testcrate/Cargo.toml | 14 + .../testcrate/benches/mem_icount.rs | 474 +++++++++++++++++++++ 2 files changed, 488 insertions(+) create mode 100644 library/compiler-builtins/testcrate/benches/mem_icount.rs diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index be60e694fa9..bda2b641d6f 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -16,6 +16,8 @@ doctest = false rand_xoshiro = "0.6" # To compare float builtins against rustc_apfloat = "0.2.1" +# Really a dev dependency, but dev dependencies can't be optional +iai-callgrind = { version = "0.14.0", optional = true } [dependencies.compiler_builtins] path = "../compiler-builtins" @@ -47,9 +49,16 @@ no-sys-f16-f64-convert = [] # Skip tests that rely on f16 symbols being available on the system no-sys-f16 = ["no-sys-f16-f64-convert"] +# Enable icount benchmarks (requires iai-callgrind and valgrind) +icount = ["dep:iai-callgrind"] + # Enable report generation without bringing in more dependencies by default benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] +# NOTE: benchmarks must be run with `--no-default-features` or with +# `-p testcrate`, otherwise the default `compiler-builtins` feature of the +# `compiler_builtins` crate gets activated, resulting in linker errors. + [[bench]] name = "float_add" harness = false @@ -85,3 +94,8 @@ harness = false [[bench]] name = "float_pow" harness = false + +[[bench]] +name = "mem_icount" +harness = false +required-features = ["icount"] diff --git a/library/compiler-builtins/testcrate/benches/mem_icount.rs b/library/compiler-builtins/testcrate/benches/mem_icount.rs new file mode 100644 index 00000000000..be3d13dffdf --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/mem_icount.rs @@ -0,0 +1,474 @@ +//! Benchmarks that use Callgrind (via `iai_callgrind`) to report instruction count metrics. This +//! is stable enough to be tested in CI. + +use std::hint::black_box; +use std::{ops, slice}; + +use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; +use iai_callgrind::{library_benchmark, library_benchmark_group, main}; + +const PAGE_SIZE: usize = 0x1000; + +#[derive(Clone)] +#[repr(C, align(0x1000))] +struct Page([u8; PAGE_SIZE]); + +/// A buffer that is page-aligned by default, with an optional offset to create a +/// misalignment. +struct AlignedSlice { + buf: Box<[Page]>, + len: usize, + offset: usize, +} + +impl AlignedSlice { + /// Allocate a slice aligned to ALIGN with at least `len` items, with `offset` from + /// page alignment. + fn new_zeroed(len: usize, offset: usize) -> Self { + assert!(offset < PAGE_SIZE); + let total_len = len + offset; + let items = (total_len / PAGE_SIZE) + if total_len % PAGE_SIZE > 0 { 1 } else { 0 }; + let buf = vec![Page([0u8; PAGE_SIZE]); items].into_boxed_slice(); + AlignedSlice { buf, len, offset } + } +} + +impl ops::Deref for AlignedSlice { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + unsafe { slice::from_raw_parts(self.buf.as_ptr().cast::().add(self.offset), self.len) } + } +} + +impl ops::DerefMut for AlignedSlice { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + slice::from_raw_parts_mut( + self.buf.as_mut_ptr().cast::().add(self.offset), + self.len, + ) + } + } +} + +mod mcpy { + use super::*; + + struct Cfg { + len: usize, + s_off: usize, + d_off: usize, + } + + fn setup(cfg: Cfg) -> (usize, AlignedSlice, AlignedSlice) { + let Cfg { len, s_off, d_off } = cfg; + println!("{len} bytes, {s_off} src offset, {d_off} dst offset"); + let mut src = AlignedSlice::new_zeroed(len, s_off); + let dst = AlignedSlice::new_zeroed(len, d_off); + src.fill(1); + (len, src, dst) + } + + #[library_benchmark] + #[benches::aligned( + args = [ + Cfg { len: 16, s_off: 0, d_off: 0 }, + Cfg { len: 16, s_off: 0, d_off: 0 }, + Cfg { len: 28, s_off: 0, d_off: 0 }, + Cfg { len: 32, s_off: 0, d_off: 0 }, + Cfg { len: 36, s_off: 0, d_off: 0 }, + Cfg { len: 60, s_off: 0, d_off: 0 }, + Cfg { len: 64, s_off: 0, d_off: 0 }, + Cfg { len: 68, s_off: 0, d_off: 0 }, + Cfg { len: 128, s_off: 0, d_off: 0 }, + Cfg { len: 256, s_off: 0, d_off: 0 }, + Cfg { len: 512, s_off: 0, d_off: 0 }, + Cfg { len: 1024, s_off: 0, d_off: 0 }, + Cfg { len: 4096, s_off: 0, d_off: 0 }, + Cfg { len: 1048576, s_off: 0, d_off: 0 }, + ], + setup = setup, + )] + #[benches::offset( + args = [ + Cfg { len: 16, s_off: 65, d_off: 65 }, + Cfg { len: 28, s_off: 65, d_off: 65 }, + Cfg { len: 32, s_off: 65, d_off: 65 }, + Cfg { len: 36, s_off: 65, d_off: 65 }, + Cfg { len: 60, s_off: 65, d_off: 65 }, + Cfg { len: 64, s_off: 65, d_off: 65 }, + Cfg { len: 68, s_off: 65, d_off: 65 }, + Cfg { len: 128, s_off: 65, d_off: 65 }, + Cfg { len: 256, s_off: 65, d_off: 65 }, + Cfg { len: 512, s_off: 65, d_off: 65 }, + Cfg { len: 1024, s_off: 65, d_off: 65 }, + Cfg { len: 4096, s_off: 65, d_off: 65 }, + Cfg { len: 1048576, s_off: 65, d_off: 65 }, + ], + setup = setup, + )] + #[benches::misaligned( + args = [ + Cfg { len: 16, s_off: 65, d_off: 66 }, + Cfg { len: 28, s_off: 65, d_off: 66 }, + Cfg { len: 32, s_off: 65, d_off: 66 }, + Cfg { len: 36, s_off: 65, d_off: 66 }, + Cfg { len: 60, s_off: 65, d_off: 66 }, + Cfg { len: 64, s_off: 65, d_off: 66 }, + Cfg { len: 68, s_off: 65, d_off: 66 }, + Cfg { len: 128, s_off: 65, d_off: 66 }, + Cfg { len: 256, s_off: 65, d_off: 66 }, + Cfg { len: 512, s_off: 65, d_off: 66 }, + Cfg { len: 1024, s_off: 65, d_off: 66 }, + Cfg { len: 4096, s_off: 65, d_off: 66 }, + Cfg { len: 1048576, s_off: 65, d_off: 66 }, + ], + setup = setup, + )] + fn bench((len, mut dst, src): (usize, AlignedSlice, AlignedSlice)) { + unsafe { + black_box(memcpy( + black_box(dst.as_mut_ptr()), + black_box(src.as_ptr()), + black_box(len), + )); + } + } + + library_benchmark_group!(name = memcpy; benchmarks = bench); +} + +mod mset { + use super::*; + + struct Cfg { + len: usize, + offset: usize, + } + + fn setup(Cfg { len, offset }: Cfg) -> (usize, AlignedSlice) { + println!("{len} bytes, {offset} offset"); + (len, AlignedSlice::new_zeroed(len, offset)) + } + + #[library_benchmark] + #[benches::aligned( + args = [ + Cfg { len: 16, offset: 0 }, + Cfg { len: 32, offset: 0 }, + Cfg { len: 64, offset: 0 }, + Cfg { len: 512, offset: 0 }, + Cfg { len: 4096, offset: 0 }, + Cfg { len: 1048576, offset: 0 }, + ], + setup = setup, + )] + #[benches::offset( + args = [ + Cfg { len: 16, offset: 65 }, + Cfg { len: 32, offset: 65 }, + Cfg { len: 64, offset: 65 }, + Cfg { len: 512, offset: 65 }, + Cfg { len: 4096, offset: 65 }, + Cfg { len: 1048576, offset: 65 }, + ], + setup = setup, + )] + fn bench((len, mut dst): (usize, AlignedSlice)) { + unsafe { + black_box(memset( + black_box(dst.as_mut_ptr()), + black_box(27), + black_box(len), + )); + } + } + + library_benchmark_group!(name = memset; benchmarks = bench); +} + +mod mcmp { + use super::*; + + struct Cfg { + len: usize, + s_off: usize, + d_off: usize, + } + + fn setup(cfg: Cfg) -> (usize, AlignedSlice, AlignedSlice) { + let Cfg { len, s_off, d_off } = cfg; + println!("{len} bytes, {s_off} src offset, {d_off} dst offset"); + let b1 = AlignedSlice::new_zeroed(len, s_off); + let mut b2 = AlignedSlice::new_zeroed(len, d_off); + b2[len - 1] = 1; + (len, b1, b2) + } + + #[library_benchmark] + #[benches::aligned( + args = [ + Cfg { len: 16, s_off: 0, d_off: 0 }, + Cfg { len: 32, s_off: 0, d_off: 0 }, + Cfg { len: 64, s_off: 0, d_off: 0 }, + Cfg { len: 512, s_off: 0, d_off: 0 }, + Cfg { len: 4096, s_off: 0, d_off: 0 }, + Cfg { len: 1048576, s_off: 0, d_off: 0 }, + ], + setup = setup + )] + #[benches::offset( + args = [ + Cfg { len: 16, s_off: 65, d_off: 65 }, + Cfg { len: 32, s_off: 65, d_off: 65 }, + Cfg { len: 64, s_off: 65, d_off: 65 }, + Cfg { len: 512, s_off: 65, d_off: 65 }, + Cfg { len: 4096, s_off: 65, d_off: 65 }, + Cfg { len: 1048576, s_off: 65, d_off: 65 }, + ], + setup = setup + )] + #[benches::misaligned( + args = [ + Cfg { len: 16, s_off: 65, d_off: 66 }, + Cfg { len: 32, s_off: 65, d_off: 66 }, + Cfg { len: 64, s_off: 65, d_off: 66 }, + Cfg { len: 512, s_off: 65, d_off: 66 }, + Cfg { len: 4096, s_off: 65, d_off: 66 }, + Cfg { len: 1048576, s_off: 65, d_off: 66 }, + ], + setup = setup + )] + fn bench((len, mut dst, src): (usize, AlignedSlice, AlignedSlice)) { + unsafe { + black_box(memcmp( + black_box(dst.as_mut_ptr()), + black_box(src.as_ptr()), + black_box(len), + )); + } + } + + library_benchmark_group!(name = memcmp; benchmarks = bench); +} + +mod mmove { + use super::*; + use Spread::{Large, Medium, Small}; + + struct Cfg { + len: usize, + spread: Spread, + off: usize, + } + + enum Spread { + /// `src` and `dst` are close. + Small, + /// `src` and `dst` are halfway offset in the buffer. + Medium, + /// `src` and `dst` only overlap by a single byte. + Large, + } + + fn calculate_spread(len: usize, spread: Spread) -> usize { + match spread { + Small => 1, + Medium => len / 2, + Large => len - 1, + } + } + + fn setup_forward(cfg: Cfg) -> (usize, usize, AlignedSlice) { + let Cfg { len, spread, off } = cfg; + let spread = calculate_spread(len, spread); + println!("{len} bytes, {spread} spread, {off} offset"); + assert!(spread < len, "otherwise this just tests memcpy"); + let mut buf = AlignedSlice::new_zeroed(len + spread, off); + let mut fill: usize = 0; + buf[..len].fill_with(|| { + fill += 1; + fill as u8 + }); + (len, spread, buf) + } + + fn setup_backward(cfg: Cfg) -> (usize, usize, AlignedSlice) { + let Cfg { len, spread, off } = cfg; + let spread = calculate_spread(len, spread); + println!("{len} bytes, {spread} spread, {off} offset"); + assert!(spread < len, "otherwise this just tests memcpy"); + let mut buf = AlignedSlice::new_zeroed(len + spread, off); + let mut fill: usize = 0; + buf[spread..].fill_with(|| { + fill += 1; + fill as u8 + }); + (len, spread, buf) + } + + #[library_benchmark] + #[benches::small_spread( + args = [ + Cfg { len: 16, spread: Small, off: 0 }, + Cfg { len: 32, spread: Small, off: 0 }, + Cfg { len: 64, spread: Small, off: 0 }, + Cfg { len: 512, spread: Small, off: 0 }, + Cfg { len: 4096, spread: Small, off: 0 }, + Cfg { len: 1048576, spread: Small, off: 0 }, + ], + setup = setup_forward + )] + #[benches::medium_spread( + args = [ + Cfg { len: 16, spread: Medium, off: 0 }, + Cfg { len: 32, spread: Medium, off: 0 }, + Cfg { len: 64, spread: Medium, off: 0 }, + Cfg { len: 512, spread: Medium, off: 0 }, + Cfg { len: 4096, spread: Medium, off: 0 }, + Cfg { len: 1048576, spread: Medium, off: 0 }, + ], + setup = setup_forward + )] + #[benches::large_spread( + args = [ + Cfg { len: 16, spread: Large, off: 0 }, + Cfg { len: 32, spread: Large, off: 0 }, + Cfg { len: 64, spread: Large, off: 0 }, + Cfg { len: 512, spread: Large, off: 0 }, + Cfg { len: 4096, spread: Large, off: 0 }, + Cfg { len: 1048576, spread: Large, off: 0 }, + ], + setup = setup_forward + )] + #[benches::small_spread_offset( + args = [ + Cfg { len: 16, spread: Small, off: 63 }, + Cfg { len: 32, spread: Small, off: 63 }, + Cfg { len: 64, spread: Small, off: 63 }, + Cfg { len: 512, spread: Small, off: 63 }, + Cfg { len: 4096, spread: Small, off: 63 }, + Cfg { len: 1048576, spread: Small, off: 63 }, + ], + setup = setup_forward + )] + #[benches::medium_spread_offset( + args = [ + Cfg { len: 16, spread: Medium, off: 63 }, + Cfg { len: 32, spread: Medium, off: 63 }, + Cfg { len: 64, spread: Medium, off: 63 }, + Cfg { len: 512, spread: Medium, off: 63 }, + Cfg { len: 4096, spread: Medium, off: 63 }, + Cfg { len: 1048576, spread: Medium, off: 63 }, + ], + setup = setup_forward + )] + #[benches::large_spread_offset( + args = [ + Cfg { len: 16, spread: Large, off: 63 }, + Cfg { len: 32, spread: Large, off: 63 }, + Cfg { len: 64, spread: Large, off: 63 }, + Cfg { len: 512, spread: Large, off: 63 }, + Cfg { len: 4096, spread: Large, off: 63 }, + Cfg { len: 1048576, spread: Large, off: 63 }, + ], + setup = setup_forward + )] + fn forward((len, spread, mut buf): (usize, usize, AlignedSlice)) { + // Test moving from the start of the buffer toward the end + unsafe { + black_box(memmove( + black_box(buf[spread..].as_mut_ptr()), + black_box(buf.as_ptr()), + black_box(len), + )); + } + } + + #[library_benchmark] + #[benches::small_spread( + args = [ + Cfg { len: 16, spread: Small, off: 0 }, + Cfg { len: 32, spread: Small, off: 0 }, + Cfg { len: 64, spread: Small, off: 0 }, + Cfg { len: 512, spread: Small, off: 0 }, + Cfg { len: 4096, spread: Small, off: 0 }, + Cfg { len: 1048576, spread: Small, off: 0 }, + ], + setup = setup_backward + )] + #[benches::middle( + args = [ + Cfg { len: 16, spread: Medium, off: 0 }, + Cfg { len: 32, spread: Medium, off: 0 }, + Cfg { len: 64, spread: Medium, off: 0 }, + Cfg { len: 512, spread: Medium, off: 0 }, + Cfg { len: 4096, spread: Medium, off: 0 }, + Cfg { len: 1048576, spread: Medium, off: 0 }, + ], + setup = setup_backward + )] + #[benches::large_spread( + args = [ + Cfg { len: 16, spread: Large, off: 0 }, + Cfg { len: 32, spread: Large, off: 0 }, + Cfg { len: 64, spread: Large, off: 0 }, + Cfg { len: 512, spread: Large, off: 0 }, + Cfg { len: 4096, spread: Large, off: 0 }, + Cfg { len: 1048576, spread: Large, off: 0 }, + ], + setup = setup_backward + )] + #[benches::small_spread_off( + args = [ + Cfg { len: 16, spread: Small, off: 63 }, + Cfg { len: 32, spread: Small, off: 63 }, + Cfg { len: 64, spread: Small, off: 63 }, + Cfg { len: 512, spread: Small, off: 63 }, + Cfg { len: 4096, spread: Small, off: 63 }, + Cfg { len: 1048576, spread: Small, off: 63 }, + ], + setup = setup_backward + )] + #[benches::middle_off( + args = [ + Cfg { len: 16, spread: Medium, off: 63 }, + Cfg { len: 32, spread: Medium, off: 63 }, + Cfg { len: 64, spread: Medium, off: 63 }, + Cfg { len: 512, spread: Medium, off: 63 }, + Cfg { len: 4096, spread: Medium, off: 63 }, + Cfg { len: 1048576, spread: Medium, off: 63 }, + ], + setup = setup_backward + )] + #[benches::large_spread_off( + args = [ + Cfg { len: 16, spread: Large, off: 63 }, + Cfg { len: 32, spread: Large, off: 63 }, + Cfg { len: 64, spread: Large, off: 63 }, + Cfg { len: 512, spread: Large, off: 63 }, + Cfg { len: 4096, spread: Large, off: 63 }, + Cfg { len: 1048576, spread: Large, off: 63 }, + ], + setup = setup_backward + )] + fn backward((len, spread, mut buf): (usize, usize, AlignedSlice)) { + // Test moving from the end of the buffer toward the start + unsafe { + black_box(memmove( + black_box(buf.as_mut_ptr()), + black_box(buf[spread..].as_ptr()), + black_box(len), + )); + } + } + + library_benchmark_group!(name = memmove; benchmarks = forward, backward); +} + +use mcmp::memcmp; +use mcpy::memcpy; +use mmove::memmove; +use mset::memset; + +main!(library_benchmark_groups = memcpy, memset, memcmp, memmove); -- cgit 1.4.1-3-g733a5 From 7b674e5a7568ef990d5ebc487be42a40d46bc36e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 22 Mar 2025 05:03:03 +0000 Subject: Clean up icount benchmarks * Delete some memcpy tests that were a bit excessive * Always use the same offset of 65 * Add a memmove test with aligned source and destination * Improve printing output and add more comments * Use a constant for 1 MiB so it shows up in the benchmark logs --- .../testcrate/benches/mem_icount.rs | 199 ++++++++++++--------- 1 file changed, 112 insertions(+), 87 deletions(-) diff --git a/library/compiler-builtins/testcrate/benches/mem_icount.rs b/library/compiler-builtins/testcrate/benches/mem_icount.rs index be3d13dffdf..63045f6e1ec 100644 --- a/library/compiler-builtins/testcrate/benches/mem_icount.rs +++ b/library/compiler-builtins/testcrate/benches/mem_icount.rs @@ -7,7 +7,9 @@ use std::{ops, slice}; use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; use iai_callgrind::{library_benchmark, library_benchmark_group, main}; -const PAGE_SIZE: usize = 0x1000; +const PAGE_SIZE: usize = 0x1000; // 4 kiB +const MAX_ALIGN: usize = 512; // assume we may use avx512 operations one day +const MEG1: usize = 1 << 20; // 1 MiB #[derive(Clone)] #[repr(C, align(0x1000))] @@ -62,7 +64,7 @@ mod mcpy { fn setup(cfg: Cfg) -> (usize, AlignedSlice, AlignedSlice) { let Cfg { len, s_off, d_off } = cfg; - println!("{len} bytes, {s_off} src offset, {d_off} dst offset"); + println!("bytes: {len} bytes, src offset: {s_off}, dst offset: {d_off}"); let mut src = AlignedSlice::new_zeroed(len, s_off); let dst = AlignedSlice::new_zeroed(len, d_off); src.fill(1); @@ -71,57 +73,38 @@ mod mcpy { #[library_benchmark] #[benches::aligned( + // Both aligned args = [ Cfg { len: 16, s_off: 0, d_off: 0 }, - Cfg { len: 16, s_off: 0, d_off: 0 }, - Cfg { len: 28, s_off: 0, d_off: 0 }, Cfg { len: 32, s_off: 0, d_off: 0 }, - Cfg { len: 36, s_off: 0, d_off: 0 }, - Cfg { len: 60, s_off: 0, d_off: 0 }, Cfg { len: 64, s_off: 0, d_off: 0 }, - Cfg { len: 68, s_off: 0, d_off: 0 }, - Cfg { len: 128, s_off: 0, d_off: 0 }, - Cfg { len: 256, s_off: 0, d_off: 0 }, Cfg { len: 512, s_off: 0, d_off: 0 }, - Cfg { len: 1024, s_off: 0, d_off: 0 }, Cfg { len: 4096, s_off: 0, d_off: 0 }, - Cfg { len: 1048576, s_off: 0, d_off: 0 }, + Cfg { len: MEG1, s_off: 0, d_off: 0 }, ], setup = setup, )] #[benches::offset( + // Both at the same offset args = [ Cfg { len: 16, s_off: 65, d_off: 65 }, - Cfg { len: 28, s_off: 65, d_off: 65 }, Cfg { len: 32, s_off: 65, d_off: 65 }, - Cfg { len: 36, s_off: 65, d_off: 65 }, - Cfg { len: 60, s_off: 65, d_off: 65 }, Cfg { len: 64, s_off: 65, d_off: 65 }, - Cfg { len: 68, s_off: 65, d_off: 65 }, - Cfg { len: 128, s_off: 65, d_off: 65 }, - Cfg { len: 256, s_off: 65, d_off: 65 }, Cfg { len: 512, s_off: 65, d_off: 65 }, - Cfg { len: 1024, s_off: 65, d_off: 65 }, Cfg { len: 4096, s_off: 65, d_off: 65 }, - Cfg { len: 1048576, s_off: 65, d_off: 65 }, + Cfg { len: MEG1, s_off: 65, d_off: 65 }, ], setup = setup, )] #[benches::misaligned( + // `src` and `dst` both misaligned by different amounts args = [ Cfg { len: 16, s_off: 65, d_off: 66 }, - Cfg { len: 28, s_off: 65, d_off: 66 }, Cfg { len: 32, s_off: 65, d_off: 66 }, - Cfg { len: 36, s_off: 65, d_off: 66 }, - Cfg { len: 60, s_off: 65, d_off: 66 }, Cfg { len: 64, s_off: 65, d_off: 66 }, - Cfg { len: 68, s_off: 65, d_off: 66 }, - Cfg { len: 128, s_off: 65, d_off: 66 }, - Cfg { len: 256, s_off: 65, d_off: 66 }, Cfg { len: 512, s_off: 65, d_off: 66 }, - Cfg { len: 1024, s_off: 65, d_off: 66 }, Cfg { len: 4096, s_off: 65, d_off: 66 }, - Cfg { len: 1048576, s_off: 65, d_off: 66 }, + Cfg { len: MEG1, s_off: 65, d_off: 66 }, ], setup = setup, )] @@ -147,7 +130,7 @@ mod mset { } fn setup(Cfg { len, offset }: Cfg) -> (usize, AlignedSlice) { - println!("{len} bytes, {offset} offset"); + println!("bytes: {len}, offset: {offset}"); (len, AlignedSlice::new_zeroed(len, offset)) } @@ -159,7 +142,7 @@ mod mset { Cfg { len: 64, offset: 0 }, Cfg { len: 512, offset: 0 }, Cfg { len: 4096, offset: 0 }, - Cfg { len: 1048576, offset: 0 }, + Cfg { len: MEG1, offset: 0 }, ], setup = setup, )] @@ -170,7 +153,7 @@ mod mset { Cfg { len: 64, offset: 65 }, Cfg { len: 512, offset: 65 }, Cfg { len: 4096, offset: 65 }, - Cfg { len: 1048576, offset: 65 }, + Cfg { len: MEG1, offset: 65 }, ], setup = setup, )] @@ -198,7 +181,7 @@ mod mcmp { fn setup(cfg: Cfg) -> (usize, AlignedSlice, AlignedSlice) { let Cfg { len, s_off, d_off } = cfg; - println!("{len} bytes, {s_off} src offset, {d_off} dst offset"); + println!("bytes: {len}, src offset: {s_off}, dst offset: {d_off}"); let b1 = AlignedSlice::new_zeroed(len, s_off); let mut b2 = AlignedSlice::new_zeroed(len, d_off); b2[len - 1] = 1; @@ -207,35 +190,38 @@ mod mcmp { #[library_benchmark] #[benches::aligned( + // Both aligned args = [ Cfg { len: 16, s_off: 0, d_off: 0 }, Cfg { len: 32, s_off: 0, d_off: 0 }, Cfg { len: 64, s_off: 0, d_off: 0 }, Cfg { len: 512, s_off: 0, d_off: 0 }, Cfg { len: 4096, s_off: 0, d_off: 0 }, - Cfg { len: 1048576, s_off: 0, d_off: 0 }, + Cfg { len: MEG1, s_off: 0, d_off: 0 }, ], setup = setup )] #[benches::offset( + // Both at the same offset args = [ Cfg { len: 16, s_off: 65, d_off: 65 }, Cfg { len: 32, s_off: 65, d_off: 65 }, Cfg { len: 64, s_off: 65, d_off: 65 }, Cfg { len: 512, s_off: 65, d_off: 65 }, Cfg { len: 4096, s_off: 65, d_off: 65 }, - Cfg { len: 1048576, s_off: 65, d_off: 65 }, + Cfg { len: MEG1, s_off: 65, d_off: 65 }, ], setup = setup )] #[benches::misaligned( + // `src` and `dst` both misaligned by different amounts args = [ Cfg { len: 16, s_off: 65, d_off: 66 }, Cfg { len: 32, s_off: 65, d_off: 66 }, Cfg { len: 64, s_off: 65, d_off: 66 }, Cfg { len: 512, s_off: 65, d_off: 66 }, Cfg { len: 4096, s_off: 65, d_off: 66 }, - Cfg { len: 1048576, s_off: 65, d_off: 66 }, + Cfg { len: MEG1, s_off: 65, d_off: 66 }, ], setup = setup )] @@ -254,7 +240,7 @@ mod mcmp { mod mmove { use super::*; - use Spread::{Large, Medium, Small}; + use Spread::{Aligned, Large, Medium, Small}; struct Cfg { len: usize, @@ -263,6 +249,8 @@ mod mmove { } enum Spread { + /// `src` and `dst` are close and have the same alignment (or offset). + Aligned, /// `src` and `dst` are close. Small, /// `src` and `dst` are halfway offset in the buffer. @@ -271,10 +259,16 @@ mod mmove { Large, } + // Note that small and large are fn calculate_spread(len: usize, spread: Spread) -> usize { match spread { + // Note that this test doesn't make sense for lengths less than len=128 + Aligned => { + assert!(len > MAX_ALIGN, "aligned memset would have no overlap"); + MAX_ALIGN + } Small => 1, - Medium => len / 2, + Medium => (len / 2) + 1, // add 1 so all are misaligned Large => len - 1, } } @@ -282,8 +276,8 @@ mod mmove { fn setup_forward(cfg: Cfg) -> (usize, usize, AlignedSlice) { let Cfg { len, spread, off } = cfg; let spread = calculate_spread(len, spread); - println!("{len} bytes, {spread} spread, {off} offset"); - assert!(spread < len, "otherwise this just tests memcpy"); + println!("bytes: {len}, spread: {spread}, offset: {off}, forward"); + assert!(spread < len, "memmove tests should have some overlap"); let mut buf = AlignedSlice::new_zeroed(len + spread, off); let mut fill: usize = 0; buf[..len].fill_with(|| { @@ -296,8 +290,8 @@ mod mmove { fn setup_backward(cfg: Cfg) -> (usize, usize, AlignedSlice) { let Cfg { len, spread, off } = cfg; let spread = calculate_spread(len, spread); - println!("{len} bytes, {spread} spread, {off} offset"); - assert!(spread < len, "otherwise this just tests memcpy"); + println!("bytes: {len}, spread: {spread}, offset: {off}, backward"); + assert!(spread < len, "memmove tests should have some overlap"); let mut buf = AlignedSlice::new_zeroed(len + spread, off); let mut fill: usize = 0; buf[spread..].fill_with(|| { @@ -308,6 +302,14 @@ mod mmove { } #[library_benchmark] + #[benches::aligned( + args = [ + // Don't test small spreads since there is no overlap + Cfg { len: 4096, spread: Aligned, off: 0 }, + Cfg { len: MEG1, spread: Aligned, off: 0 }, + ], + setup = setup_forward + )] #[benches::small_spread( args = [ Cfg { len: 16, spread: Small, off: 0 }, @@ -315,7 +317,7 @@ mod mmove { Cfg { len: 64, spread: Small, off: 0 }, Cfg { len: 512, spread: Small, off: 0 }, Cfg { len: 4096, spread: Small, off: 0 }, - Cfg { len: 1048576, spread: Small, off: 0 }, + Cfg { len: MEG1, spread: Small, off: 0 }, ], setup = setup_forward )] @@ -326,7 +328,7 @@ mod mmove { Cfg { len: 64, spread: Medium, off: 0 }, Cfg { len: 512, spread: Medium, off: 0 }, Cfg { len: 4096, spread: Medium, off: 0 }, - Cfg { len: 1048576, spread: Medium, off: 0 }, + Cfg { len: MEG1, spread: Medium, off: 0 }, ], setup = setup_forward )] @@ -337,40 +339,47 @@ mod mmove { Cfg { len: 64, spread: Large, off: 0 }, Cfg { len: 512, spread: Large, off: 0 }, Cfg { len: 4096, spread: Large, off: 0 }, - Cfg { len: 1048576, spread: Large, off: 0 }, + Cfg { len: MEG1, spread: Large, off: 0 }, ], setup = setup_forward )] - #[benches::small_spread_offset( + #[benches::aligned_off( + args = [ + Cfg { len: 4096, spread: Aligned, off: 65 }, + Cfg { len: MEG1, spread: Aligned, off: 65 }, + ], + setup = setup_forward + )] + #[benches::small_spread_off( args = [ - Cfg { len: 16, spread: Small, off: 63 }, - Cfg { len: 32, spread: Small, off: 63 }, - Cfg { len: 64, spread: Small, off: 63 }, - Cfg { len: 512, spread: Small, off: 63 }, - Cfg { len: 4096, spread: Small, off: 63 }, - Cfg { len: 1048576, spread: Small, off: 63 }, + Cfg { len: 16, spread: Small, off: 65 }, + Cfg { len: 32, spread: Small, off: 65 }, + Cfg { len: 64, spread: Small, off: 65 }, + Cfg { len: 512, spread: Small, off: 65 }, + Cfg { len: 4096, spread: Small, off: 65 }, + Cfg { len: MEG1, spread: Small, off: 65 }, ], setup = setup_forward )] - #[benches::medium_spread_offset( + #[benches::medium_spread_off( args = [ - Cfg { len: 16, spread: Medium, off: 63 }, - Cfg { len: 32, spread: Medium, off: 63 }, - Cfg { len: 64, spread: Medium, off: 63 }, - Cfg { len: 512, spread: Medium, off: 63 }, - Cfg { len: 4096, spread: Medium, off: 63 }, - Cfg { len: 1048576, spread: Medium, off: 63 }, + Cfg { len: 16, spread: Medium, off: 65 }, + Cfg { len: 32, spread: Medium, off: 65 }, + Cfg { len: 64, spread: Medium, off: 65 }, + Cfg { len: 512, spread: Medium, off: 65 }, + Cfg { len: 4096, spread: Medium, off: 65 }, + Cfg { len: MEG1, spread: Medium, off: 65 }, ], setup = setup_forward )] - #[benches::large_spread_offset( + #[benches::large_spread_off( args = [ - Cfg { len: 16, spread: Large, off: 63 }, - Cfg { len: 32, spread: Large, off: 63 }, - Cfg { len: 64, spread: Large, off: 63 }, - Cfg { len: 512, spread: Large, off: 63 }, - Cfg { len: 4096, spread: Large, off: 63 }, - Cfg { len: 1048576, spread: Large, off: 63 }, + Cfg { len: 16, spread: Large, off: 65 }, + Cfg { len: 32, spread: Large, off: 65 }, + Cfg { len: 64, spread: Large, off: 65 }, + Cfg { len: 512, spread: Large, off: 65 }, + Cfg { len: 4096, spread: Large, off: 65 }, + Cfg { len: MEG1, spread: Large, off: 65 }, ], setup = setup_forward )] @@ -386,6 +395,14 @@ mod mmove { } #[library_benchmark] + #[benches::aligned( + args = [ + // Don't test small spreads since there is no overlap + Cfg { len: 4096, spread: Aligned, off: 0 }, + Cfg { len: MEG1, spread: Aligned, off: 0 }, + ], + setup = setup_backward + )] #[benches::small_spread( args = [ Cfg { len: 16, spread: Small, off: 0 }, @@ -393,18 +410,18 @@ mod mmove { Cfg { len: 64, spread: Small, off: 0 }, Cfg { len: 512, spread: Small, off: 0 }, Cfg { len: 4096, spread: Small, off: 0 }, - Cfg { len: 1048576, spread: Small, off: 0 }, + Cfg { len: MEG1, spread: Small, off: 0 }, ], setup = setup_backward )] - #[benches::middle( + #[benches::medium_spread( args = [ Cfg { len: 16, spread: Medium, off: 0 }, Cfg { len: 32, spread: Medium, off: 0 }, Cfg { len: 64, spread: Medium, off: 0 }, Cfg { len: 512, spread: Medium, off: 0 }, Cfg { len: 4096, spread: Medium, off: 0 }, - Cfg { len: 1048576, spread: Medium, off: 0 }, + Cfg { len: MEG1, spread: Medium, off: 0 }, ], setup = setup_backward )] @@ -415,40 +432,48 @@ mod mmove { Cfg { len: 64, spread: Large, off: 0 }, Cfg { len: 512, spread: Large, off: 0 }, Cfg { len: 4096, spread: Large, off: 0 }, - Cfg { len: 1048576, spread: Large, off: 0 }, + Cfg { len: MEG1, spread: Large, off: 0 }, + ], + setup = setup_backward + )] + #[benches::aligned_off( + args = [ + // Don't test small spreads since there is no overlap + Cfg { len: 4096, spread: Aligned, off: 65 }, + Cfg { len: MEG1, spread: Aligned, off: 65 }, ], setup = setup_backward )] #[benches::small_spread_off( args = [ - Cfg { len: 16, spread: Small, off: 63 }, - Cfg { len: 32, spread: Small, off: 63 }, - Cfg { len: 64, spread: Small, off: 63 }, - Cfg { len: 512, spread: Small, off: 63 }, - Cfg { len: 4096, spread: Small, off: 63 }, - Cfg { len: 1048576, spread: Small, off: 63 }, + Cfg { len: 16, spread: Small, off: 65 }, + Cfg { len: 32, spread: Small, off: 65 }, + Cfg { len: 64, spread: Small, off: 65 }, + Cfg { len: 512, spread: Small, off: 65 }, + Cfg { len: 4096, spread: Small, off: 65 }, + Cfg { len: MEG1, spread: Small, off: 65 }, ], setup = setup_backward )] - #[benches::middle_off( + #[benches::medium_spread_off( args = [ - Cfg { len: 16, spread: Medium, off: 63 }, - Cfg { len: 32, spread: Medium, off: 63 }, - Cfg { len: 64, spread: Medium, off: 63 }, - Cfg { len: 512, spread: Medium, off: 63 }, - Cfg { len: 4096, spread: Medium, off: 63 }, - Cfg { len: 1048576, spread: Medium, off: 63 }, + Cfg { len: 16, spread: Medium, off: 65 }, + Cfg { len: 32, spread: Medium, off: 65 }, + Cfg { len: 64, spread: Medium, off: 65 }, + Cfg { len: 512, spread: Medium, off: 65 }, + Cfg { len: 4096, spread: Medium, off: 65 }, + Cfg { len: MEG1, spread: Medium, off: 65 }, ], setup = setup_backward )] #[benches::large_spread_off( args = [ - Cfg { len: 16, spread: Large, off: 63 }, - Cfg { len: 32, spread: Large, off: 63 }, - Cfg { len: 64, spread: Large, off: 63 }, - Cfg { len: 512, spread: Large, off: 63 }, - Cfg { len: 4096, spread: Large, off: 63 }, - Cfg { len: 1048576, spread: Large, off: 63 }, + Cfg { len: 16, spread: Large, off: 65 }, + Cfg { len: 32, spread: Large, off: 65 }, + Cfg { len: 64, spread: Large, off: 65 }, + Cfg { len: 512, spread: Large, off: 65 }, + Cfg { len: 4096, spread: Large, off: 65 }, + Cfg { len: MEG1, spread: Large, off: 65 }, ], setup = setup_backward )] -- cgit 1.4.1-3-g733a5 From 5cf993880ae20a79eef9af486479dcfbbb26d848 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Mar 2025 06:36:40 +0100 Subject: copy_misaligned_words: avoid out-of-bounds accesses (#799) * copy_misaligned_words: avoid out-of-bounds accesses * add test to make Miri able to detect OOB in memmove * run Miri on CI --- .../compiler-builtins/.github/workflows/main.yml | 16 +++ library/compiler-builtins/ci/miri.sh | 16 +++ .../compiler-builtins/src/mem/impls.rs | 160 +++++++++++++++++---- library/compiler-builtins/testcrate/tests/mem.rs | 23 ++- 4 files changed, 183 insertions(+), 32 deletions(-) create mode 100755 library/compiler-builtins/ci/miri.sh diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index c337c26a272..003102d5943 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -160,6 +160,21 @@ jobs: rm -rf /tmp/.buildx-cache mv /tmp/.buildx-cache-new /tmp/.buildx-cache + miri: + name: Miri + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Install Rust (rustup) + run: rustup update nightly --no-self-update && rustup default nightly + shell: bash + - run: rustup component add miri + - run: cargo miri setup + - uses: Swatinem/rust-cache@v2 + - run: ./ci/miri.sh + rustfmt: name: Rustfmt runs-on: ubuntu-latest @@ -190,6 +205,7 @@ jobs: - test - rustfmt - clippy + - miri runs-on: ubuntu-latest # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its diff --git a/library/compiler-builtins/ci/miri.sh b/library/compiler-builtins/ci/miri.sh new file mode 100755 index 00000000000..f9a1240a465 --- /dev/null +++ b/library/compiler-builtins/ci/miri.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -ex + +# We need Tree Borrows as some of our raw pointer patterns are not +# compatible with Stacked Borrows. +export MIRIFLAGS="-Zmiri-tree-borrows" + +# One target that sets `mem-unaligned` and one that does not, +# and a big-endian target. +TARGETS=(x86_64-unknown-linux-gnu + armv7-unknown-linux-gnueabihf + s390x-unknown-linux-gnu) +for TARGET in "${TARGETS[@]}"; do + # Only run the `mem` tests to avoid this taking too long. + cargo miri test --manifest-path testcrate/Cargo.toml --features no-asm --target $TARGET -- mem +done diff --git a/library/compiler-builtins/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs index c602a67dbd7..dc12d69969c 100644 --- a/library/compiler-builtins/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs @@ -41,6 +41,72 @@ unsafe fn read_usize_unaligned(x: *const usize) -> usize { core::mem::transmute(x_read) } +/// Loads a `T`-sized chunk from `src` into `dst` at offset `offset`, if that does not exceed +/// `load_sz`. The offset pointers must both be `T`-aligned. Returns the new offset, advanced by the +/// chunk size if a load happened. +#[cfg(not(feature = "mem-unaligned"))] +#[inline(always)] +unsafe fn load_chunk_aligned( + src: *const usize, + dst: *mut usize, + load_sz: usize, + offset: usize, +) -> usize { + let chunk_sz = core::mem::size_of::(); + if (load_sz & chunk_sz) != 0 { + *dst.wrapping_byte_add(offset).cast::() = *src.wrapping_byte_add(offset).cast::(); + offset | chunk_sz + } else { + offset + } +} + +/// Load `load_sz` many bytes from `src`, which must be usize-aligned. Acts as if we did a `usize` +/// read with the out-of-bounds part filled with 0s. +/// `load_sz` be strictly less than `WORD_SIZE`. +#[cfg(not(feature = "mem-unaligned"))] +#[inline(always)] +unsafe fn load_aligned_partial(src: *const usize, load_sz: usize) -> usize { + debug_assert!(load_sz < WORD_SIZE); + // We can read up to 7 bytes here, which is enough for WORD_SIZE of 8 + // (since `load_sz < WORD_SIZE`). + const { assert!(WORD_SIZE <= 8) }; + + let mut i = 0; + let mut out = 0usize; + // We load in decreasing order, so the pointers remain sufficiently aligned for the next step. + i = load_chunk_aligned::(src, &raw mut out, load_sz, i); + i = load_chunk_aligned::(src, &raw mut out, load_sz, i); + i = load_chunk_aligned::(src, &raw mut out, load_sz, i); + debug_assert!(i == load_sz); + out +} + +/// Load `load_sz` many bytes from `src.wrapping_byte_add(WORD_SIZE - load_sz)`. `src` must be +/// `usize`-aligned. The bytes are returned as the *last* bytes of the return value, i.e., this acts +/// as if we had done a `usize` read from `src`, with the out-of-bounds part filled with 0s. +/// `load_sz` be strictly less than `WORD_SIZE`. +#[cfg(not(feature = "mem-unaligned"))] +#[inline(always)] +unsafe fn load_aligned_end_partial(src: *const usize, load_sz: usize) -> usize { + debug_assert!(load_sz < WORD_SIZE); + // We can read up to 7 bytes here, which is enough for WORD_SIZE of 8 + // (since `load_sz < WORD_SIZE`). + const { assert!(WORD_SIZE <= 8) }; + + let mut i = 0; + let mut out = 0usize; + // Obtain pointers pointing to the beginning of the range we want to load. + let src_shifted = src.wrapping_byte_add(WORD_SIZE - load_sz); + let out_shifted = (&raw mut out).wrapping_byte_add(WORD_SIZE - load_sz); + // We load in increasing order, so by the time we reach `u16` things are 2-aligned etc. + i = load_chunk_aligned::(src_shifted, out_shifted, load_sz, i); + i = load_chunk_aligned::(src_shifted, out_shifted, load_sz, i); + i = load_chunk_aligned::(src_shifted, out_shifted, load_sz, i); + debug_assert!(i == load_sz); + out +} + #[inline(always)] pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) { #[inline(always)] @@ -66,40 +132,57 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) } } + /// `n` is in units of bytes, but must be a multiple of the word size and must not be 0. + /// `src` *must not* be `usize`-aligned. #[cfg(not(feature = "mem-unaligned"))] #[inline(always)] unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { + debug_assert!(n > 0 && n % WORD_SIZE == 0); + debug_assert!(src.addr() % WORD_SIZE != 0); + let mut dest_usize = dest as *mut usize; let dest_end = dest.wrapping_add(n) as *mut usize; // Calculate the misalignment offset and shift needed to reassemble value. + // Since `src` is definitely not aligned, `offset` is in the range 1..WORD_SIZE. let offset = src as usize & WORD_MASK; let shift = offset * 8; // Realign src - let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; - // This will read (but won't use) bytes out of bound. - // cfg needed because not all targets will have atomic loads that can be lowered - // (e.g. BPF, MSP430), or provided by an external library (e.g. RV32I) - #[cfg(target_has_atomic_load_store = "ptr")] - let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); - #[cfg(not(target_has_atomic_load_store = "ptr"))] - let mut prev_word = core::ptr::read_volatile(src_aligned); + let mut src_aligned = src.wrapping_byte_sub(offset) as *mut usize; + let mut prev_word = load_aligned_end_partial(src_aligned, WORD_SIZE - offset); - while dest_usize < dest_end { + while dest_usize.wrapping_add(1) < dest_end { src_aligned = src_aligned.wrapping_add(1); let cur_word = *src_aligned; - #[cfg(target_endian = "little")] - let resembled = prev_word >> shift | cur_word << (WORD_SIZE * 8 - shift); - #[cfg(target_endian = "big")] - let resembled = prev_word << shift | cur_word >> (WORD_SIZE * 8 - shift); + let reassembled = if cfg!(target_endian = "little") { + prev_word >> shift | cur_word << (WORD_SIZE * 8 - shift) + } else { + prev_word << shift | cur_word >> (WORD_SIZE * 8 - shift) + }; prev_word = cur_word; - *dest_usize = resembled; + *dest_usize = reassembled; dest_usize = dest_usize.wrapping_add(1); } + + // There's one more element left to go, and we can't use the loop for that as on the `src` side, + // it is partially out-of-bounds. + src_aligned = src_aligned.wrapping_add(1); + let cur_word = load_aligned_partial(src_aligned, offset); + let reassembled = if cfg!(target_endian = "little") { + prev_word >> shift | cur_word << (WORD_SIZE * 8 - shift) + } else { + prev_word << shift | cur_word >> (WORD_SIZE * 8 - shift) + }; + // prev_word does not matter any more + + *dest_usize = reassembled; + // dest_usize does not matter any more } + /// `n` is in units of bytes, but must be a multiple of the word size and must not be 0. + /// `src` *must not* be `usize`-aligned. #[cfg(feature = "mem-unaligned")] #[inline(always)] unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { @@ -164,40 +247,57 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { } } + /// `n` is in units of bytes, but must be a multiple of the word size and must not be 0. + /// `src` *must not* be `usize`-aligned. #[cfg(not(feature = "mem-unaligned"))] #[inline(always)] unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { + debug_assert!(n > 0 && n % WORD_SIZE == 0); + debug_assert!(src.addr() % WORD_SIZE != 0); + let mut dest_usize = dest as *mut usize; - let dest_start = dest.wrapping_sub(n) as *mut usize; + let dest_start = dest.wrapping_sub(n) as *mut usize; // we're moving towards the start // Calculate the misalignment offset and shift needed to reassemble value. + // Since `src` is definitely not aligned, `offset` is in the range 1..WORD_SIZE. let offset = src as usize & WORD_MASK; let shift = offset * 8; - // Realign src_aligned - let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; - // This will read (but won't use) bytes out of bound. - // cfg needed because not all targets will have atomic loads that can be lowered - // (e.g. BPF, MSP430), or provided by an external library (e.g. RV32I) - #[cfg(target_has_atomic_load_store = "ptr")] - let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); - #[cfg(not(target_has_atomic_load_store = "ptr"))] - let mut prev_word = core::ptr::read_volatile(src_aligned); + // Realign src + let mut src_aligned = src.wrapping_byte_sub(offset) as *mut usize; + let mut prev_word = load_aligned_partial(src_aligned, offset); - while dest_start < dest_usize { + while dest_start.wrapping_add(1) < dest_usize { src_aligned = src_aligned.wrapping_sub(1); let cur_word = *src_aligned; - #[cfg(target_endian = "little")] - let resembled = prev_word << (WORD_SIZE * 8 - shift) | cur_word >> shift; - #[cfg(target_endian = "big")] - let resembled = prev_word >> (WORD_SIZE * 8 - shift) | cur_word << shift; + let reassembled = if cfg!(target_endian = "little") { + prev_word << (WORD_SIZE * 8 - shift) | cur_word >> shift + } else { + prev_word >> (WORD_SIZE * 8 - shift) | cur_word << shift + }; prev_word = cur_word; dest_usize = dest_usize.wrapping_sub(1); - *dest_usize = resembled; + *dest_usize = reassembled; } + + // There's one more element left to go, and we can't use the loop for that as on the `src` side, + // it is partially out-of-bounds. + src_aligned = src_aligned.wrapping_sub(1); + let cur_word = load_aligned_end_partial(src_aligned, WORD_SIZE - offset); + let reassembled = if cfg!(target_endian = "little") { + prev_word << (WORD_SIZE * 8 - shift) | cur_word >> shift + } else { + prev_word >> (WORD_SIZE * 8 - shift) | cur_word << shift + }; + // prev_word does not matter any more + + dest_usize = dest_usize.wrapping_sub(1); + *dest_usize = reassembled; } + /// `n` is in units of bytes, but must be a multiple of the word size and must not be 0. + /// `src` *must not* be `usize`-aligned. #[cfg(feature = "mem-unaligned")] #[inline(always)] unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs index 48ac95adc17..d838ef159a0 100644 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -128,11 +128,13 @@ fn memcmp_eq() { #[test] fn memcmp_ne() { let arr1 @ arr2 = gen_arr::<256>(); - for i in 0..256 { + // Reduce iteration count in Miri as it is too slow otherwise. + let limit = if cfg!(miri) { 64 } else { 256 }; + for i in 0..limit { let mut diff_arr = arr1; diff_arr.0[i] = 127; let expect = diff_arr.0[i].cmp(&arr2.0[i]); - for k in i + 1..256 { + for k in i + 1..limit { let result = unsafe { memcmp(diff_arr.0.as_ptr(), arr2.0.as_ptr(), k) }; assert_eq!(expect, result.cmp(&0)); } @@ -230,6 +232,23 @@ fn memmove_backward_aligned() { } } +#[test] +fn memmove_misaligned_bounds() { + // The above test have the downside that the addresses surrounding the range-to-copy are all + // still in-bounds, so Miri would not actually complain about OOB accesses. So we also test with + // an array that has just the right size. We test a few times to avoid it being accidentally + // aligned. + for _ in 0..8 { + let mut arr1 = [0u8; 17]; + let mut arr2 = [0u8; 17]; + unsafe { + // Copy both ways so we hit both the forward and backward cases. + memmove(arr1.as_mut_ptr(), arr2.as_mut_ptr(), 17); + memmove(arr2.as_mut_ptr(), arr1.as_mut_ptr(), 17); + } + } +} + #[test] fn memset_backward_misaligned_nonaligned_start() { let mut arr = gen_arr::<32>(); -- cgit 1.4.1-3-g733a5 From 30c128006a71eb9f0c2039a7389c4b636c1ce018 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Sun, 23 Mar 2025 08:44:22 +0100 Subject: avr: Skip No More! --- .../compiler-builtins/src/float/add.rs | 2 - .../compiler-builtins/src/float/cmp.rs | 81 +++++++++------------- .../compiler-builtins/src/float/div.rs | 3 - .../compiler-builtins/src/float/extend.rs | 7 -- .../compiler-builtins/src/float/mul.rs | 2 - .../compiler-builtins/src/float/pow.rs | 3 - .../compiler-builtins/src/float/sub.rs | 2 - .../compiler-builtins/src/float/trunc.rs | 7 -- .../compiler-builtins/src/int/bswap.rs | 3 - .../compiler-builtins/src/int/sdiv.rs | 42 ++++++++++- .../compiler-builtins/src/int/shift.rs | 9 --- .../compiler-builtins/src/int/udiv.rs | 25 +++++-- .../compiler-builtins/src/macros.rs | 29 -------- library/compiler-builtins/testcrate/tests/misc.rs | 1 - 14 files changed, 91 insertions(+), 125 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/float/add.rs b/library/compiler-builtins/compiler-builtins/src/float/add.rs index ef04ddc165c..0426c9cc44f 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/add.rs @@ -189,14 +189,12 @@ where } intrinsics! { - #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_fadd] pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 { add(a, b) } - #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_dadd] pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 { diff --git a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs index b9b4d0114b7..296952821cb 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs @@ -3,6 +3,14 @@ use crate::float::Float; use crate::int::MinInt; +// https://github.com/llvm/llvm-project/blob/1e6ba3cd2fe96be00b6ed6ba28b3d9f9271d784d/compiler-rt/lib/builtins/fp_compare_impl.inc#L22 +#[cfg(target_arch = "avr")] +pub type CmpResult = i8; + +// https://github.com/llvm/llvm-project/blob/1e6ba3cd2fe96be00b6ed6ba28b3d9f9271d784d/compiler-rt/lib/builtins/fp_compare_impl.inc#L25 +#[cfg(not(target_arch = "avr"))] +pub type CmpResult = i32; + #[derive(Clone, Copy)] enum Result { Less, @@ -12,7 +20,7 @@ enum Result { } impl Result { - fn to_le_abi(self) -> i32 { + fn to_le_abi(self) -> CmpResult { match self { Result::Less => -1, Result::Equal => 0, @@ -21,7 +29,7 @@ impl Result { } } - fn to_ge_abi(self) -> i32 { + fn to_ge_abi(self) -> CmpResult { match self { Result::Less => -1, Result::Equal => 0, @@ -99,120 +107,99 @@ fn unord(a: F, b: F) -> bool { } intrinsics! { - #[avr_skip] - pub extern "C" fn __lesf2(a: f32, b: f32) -> i32 { + pub extern "C" fn __lesf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __gesf2(a: f32, b: f32) -> i32 { + pub extern "C" fn __gesf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { cmp(a, b).to_ge_abi() } - #[avr_skip] #[arm_aeabi_alias = __aeabi_fcmpun] - pub extern "C" fn __unordsf2(a: f32, b: f32) -> i32 { - unord(a, b) as i32 + pub extern "C" fn __unordsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { + unord(a, b) as crate::float::cmp::CmpResult } - #[avr_skip] - pub extern "C" fn __eqsf2(a: f32, b: f32) -> i32 { + pub extern "C" fn __eqsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __ltsf2(a: f32, b: f32) -> i32 { + pub extern "C" fn __ltsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __nesf2(a: f32, b: f32) -> i32 { + pub extern "C" fn __nesf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __gtsf2(a: f32, b: f32) -> i32 { + pub extern "C" fn __gtsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { cmp(a, b).to_ge_abi() } - #[avr_skip] - pub extern "C" fn __ledf2(a: f64, b: f64) -> i32 { + pub extern "C" fn __ledf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __gedf2(a: f64, b: f64) -> i32 { + pub extern "C" fn __gedf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { cmp(a, b).to_ge_abi() } - #[avr_skip] #[arm_aeabi_alias = __aeabi_dcmpun] - pub extern "C" fn __unorddf2(a: f64, b: f64) -> i32 { - unord(a, b) as i32 + pub extern "C" fn __unorddf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { + unord(a, b) as crate::float::cmp::CmpResult } - #[avr_skip] - pub extern "C" fn __eqdf2(a: f64, b: f64) -> i32 { + pub extern "C" fn __eqdf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __ltdf2(a: f64, b: f64) -> i32 { + pub extern "C" fn __ltdf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __nedf2(a: f64, b: f64) -> i32 { + pub extern "C" fn __nedf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __gtdf2(a: f64, b: f64) -> i32 { + pub extern "C" fn __gtdf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { cmp(a, b).to_ge_abi() } } #[cfg(f128_enabled)] intrinsics! { - #[avr_skip] #[ppc_alias = __lekf2] - pub extern "C" fn __letf2(a: f128, b: f128) -> i32 { + pub extern "C" fn __letf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] #[ppc_alias = __gekf2] - pub extern "C" fn __getf2(a: f128, b: f128) -> i32 { + pub extern "C" fn __getf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { cmp(a, b).to_ge_abi() } - #[avr_skip] #[ppc_alias = __unordkf2] - pub extern "C" fn __unordtf2(a: f128, b: f128) -> i32 { - unord(a, b) as i32 + pub extern "C" fn __unordtf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { + unord(a, b) as crate::float::cmp::CmpResult } - #[avr_skip] #[ppc_alias = __eqkf2] - pub extern "C" fn __eqtf2(a: f128, b: f128) -> i32 { + pub extern "C" fn __eqtf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] #[ppc_alias = __ltkf2] - pub extern "C" fn __lttf2(a: f128, b: f128) -> i32 { + pub extern "C" fn __lttf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] #[ppc_alias = __nekf2] - pub extern "C" fn __netf2(a: f128, b: f128) -> i32 { + pub extern "C" fn __netf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] #[ppc_alias = __gtkf2] - pub extern "C" fn __gttf2(a: f128, b: f128) -> i32 { + pub extern "C" fn __gttf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { cmp(a, b).to_ge_abi() } } diff --git a/library/compiler-builtins/compiler-builtins/src/float/div.rs b/library/compiler-builtins/compiler-builtins/src/float/div.rs index 21c757dd639..929f2919787 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/div.rs @@ -606,19 +606,16 @@ where } intrinsics! { - #[avr_skip] #[arm_aeabi_alias = __aeabi_fdiv] pub extern "C" fn __divsf3(a: f32, b: f32) -> f32 { div(a, b) } - #[avr_skip] #[arm_aeabi_alias = __aeabi_ddiv] pub extern "C" fn __divdf3(a: f64, b: f64) -> f64 { div(a, b) } - #[avr_skip] #[ppc_alias = __divkf3] #[cfg(f128_enabled)] pub extern "C" fn __divtf3(a: f128, b: f128) -> f128 { diff --git a/library/compiler-builtins/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/compiler-builtins/src/float/extend.rs index ce00da31dc5..c4f1fe30e0e 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/extend.rs @@ -70,7 +70,6 @@ where } intrinsics! { - #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_f2d] pub extern "C" fn __extendsfdf2(a: f32) -> f64 { @@ -79,7 +78,6 @@ intrinsics! { } intrinsics! { - #[avr_skip] #[aapcs_on_arm] #[apple_f16_arg_abi] #[arm_aeabi_alias = __aeabi_h2f] @@ -88,7 +86,6 @@ intrinsics! { extend(a) } - #[avr_skip] #[aapcs_on_arm] #[apple_f16_arg_abi] #[cfg(f16_enabled)] @@ -96,7 +93,6 @@ intrinsics! { extend(a) } - #[avr_skip] #[aapcs_on_arm] #[apple_f16_arg_abi] #[cfg(f16_enabled)] @@ -104,7 +100,6 @@ intrinsics! { extend(a) } - #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __extendhfkf2] #[cfg(all(f16_enabled, f128_enabled))] @@ -112,7 +107,6 @@ intrinsics! { extend(a) } - #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __extendsfkf2] #[cfg(f128_enabled)] @@ -120,7 +114,6 @@ intrinsics! { extend(a) } - #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __extenddfkf2] #[cfg(f128_enabled)] diff --git a/library/compiler-builtins/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/compiler-builtins/src/float/mul.rs index 58636cb5ebe..7f1f19d9bd7 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/mul.rs @@ -180,14 +180,12 @@ where } intrinsics! { - #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_fmul] pub extern "C" fn __mulsf3(a: f32, b: f32) -> f32 { mul(a, b) } - #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_dmul] pub extern "C" fn __muldf3(a: f64, b: f64) -> f64 { diff --git a/library/compiler-builtins/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/compiler-builtins/src/float/pow.rs index dac768f7be3..fe76060e0fa 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/pow.rs @@ -26,17 +26,14 @@ fn pow(a: F, b: i32) -> F { } intrinsics! { - #[avr_skip] pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 { pow(a, b) } - #[avr_skip] pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 { pow(a, b) } - #[avr_skip] #[ppc_alias = __powikf2] #[cfg(f128_enabled)] // FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly. diff --git a/library/compiler-builtins/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/compiler-builtins/src/float/sub.rs index 175b3a16500..a0fd9dff97f 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/sub.rs @@ -1,13 +1,11 @@ use crate::float::Float; intrinsics! { - #[avr_skip] #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { crate::float::add::__addsf3(a, f32::from_bits(b.to_bits() ^ f32::SIGN_MASK)) } - #[avr_skip] #[arm_aeabi_alias = __aeabi_dsub] pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { crate::float::add::__adddf3(a, f64::from_bits(b.to_bits() ^ f64::SIGN_MASK)) diff --git a/library/compiler-builtins/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs index 928eba0c8ef..ca8a0f368b5 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs @@ -115,7 +115,6 @@ where } intrinsics! { - #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_d2f] pub extern "C" fn __truncdfsf2(a: f64) -> f32 { @@ -124,7 +123,6 @@ intrinsics! { } intrinsics! { - #[avr_skip] #[aapcs_on_arm] #[apple_f16_ret_abi] #[arm_aeabi_alias = __aeabi_f2h] @@ -133,7 +131,6 @@ intrinsics! { trunc(a) } - #[avr_skip] #[aapcs_on_arm] #[apple_f16_ret_abi] #[cfg(f16_enabled)] @@ -141,7 +138,6 @@ intrinsics! { trunc(a) } - #[avr_skip] #[aapcs_on_arm] #[apple_f16_ret_abi] #[arm_aeabi_alias = __aeabi_d2h] @@ -150,7 +146,6 @@ intrinsics! { trunc(a) } - #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __trunckfhf2] #[cfg(all(f16_enabled, f128_enabled))] @@ -158,7 +153,6 @@ intrinsics! { trunc(a) } - #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __trunckfsf2] #[cfg(f128_enabled)] @@ -166,7 +160,6 @@ intrinsics! { trunc(a) } - #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __trunckfdf2] #[cfg(f128_enabled)] diff --git a/library/compiler-builtins/compiler-builtins/src/int/bswap.rs b/library/compiler-builtins/compiler-builtins/src/int/bswap.rs index 9df80204d0e..3ede08882dc 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/bswap.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/bswap.rs @@ -1,20 +1,17 @@ intrinsics! { #[maybe_use_optimized_c_shim] - #[avr_skip] /// Swaps bytes in 32-bit number pub extern "C" fn __bswapsi2(x: u32) -> u32 { x.swap_bytes() } #[maybe_use_optimized_c_shim] - #[avr_skip] /// Swaps bytes in 64-bit number pub extern "C" fn __bswapdi2(x: u64) -> u64 { x.swap_bytes() } #[maybe_use_optimized_c_shim] - #[avr_skip] /// Swaps bytes in 128-bit number pub extern "C" fn __bswapti2(x: u128) -> u128 { x.swap_bytes() diff --git a/library/compiler-builtins/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/compiler-builtins/src/int/sdiv.rs index 9630c7d7de3..6a9029de7f2 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/sdiv.rs @@ -9,7 +9,6 @@ macro_rules! sdivmod { $($attr:tt),* // attributes ) => { intrinsics! { - #[avr_skip] $( #[$attr] )* @@ -19,15 +18,18 @@ macro_rules! sdivmod { let b_neg = b < 0; let mut a = a; let mut b = b; + if a_neg { a = a.wrapping_neg(); } if b_neg { b = b.wrapping_neg(); } + let mut r = *rem as $uX; let t = $unsigned_fn(a as $uX, b as $uX, Some(&mut r)) as $iX; let mut r = r as $iX; + if a_neg { r = r.wrapping_neg(); } @@ -51,7 +53,6 @@ macro_rules! sdiv { $($attr:tt),* // attributes ) => { intrinsics! { - #[avr_skip] $( #[$attr] )* @@ -87,7 +88,6 @@ macro_rules! smod { $($attr:tt),* // attributes ) => { intrinsics! { - #[avr_skip] $( #[$attr] )* @@ -114,6 +114,7 @@ macro_rules! smod { } } +#[cfg(not(target_arch = "avr"))] sdivmod!( __udivmodsi4, __divmodsi4, @@ -121,6 +122,41 @@ sdivmod!( i32, maybe_use_optimized_c_shim ); + +#[cfg(target_arch = "avr")] +intrinsics! { + /// Returns `a / b` and `a % b` packed together. + /// + /// Ideally we'd use `-> (u32, u32)` or some kind of a packed struct, but + /// both force a stack allocation, while our result has to be in R18:R26. + pub extern "C" fn __divmodsi4(a: i32, b: i32) -> u64 { + let a_neg = a < 0; + let b_neg = b < 0; + let mut a = a; + let mut b = b; + + if a_neg { + a = a.wrapping_neg(); + } + if b_neg { + b = b.wrapping_neg(); + } + + let tr = __udivmodsi4(a as u32, b as u32); + let mut t = tr as u32 as i32; + let mut r = (tr >> 32) as u32 as i32; + + if a_neg { + r = r.wrapping_neg(); + } + if a_neg != b_neg { + t = t.wrapping_neg(); + } + + ((r as u32 as u64) << 32) | (t as u32 as u64) + } +} + // The `#[arm_aeabi_alias = __aeabi_idiv]` attribute cannot be made to work with `intrinsics!` in macros intrinsics! { #[maybe_use_optimized_c_shim] diff --git a/library/compiler-builtins/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/compiler-builtins/src/int/shift.rs index 317272988ce..a85c1b33d67 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/shift.rs @@ -69,56 +69,47 @@ impl Lshr for u64 {} impl Lshr for u128 {} intrinsics! { - #[avr_skip] #[maybe_use_optimized_c_shim] pub extern "C" fn __ashlsi3(a: u32, b: u32) -> u32 { a.ashl(b) } - #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsl] pub extern "C" fn __ashldi3(a: u64, b: core::ffi::c_uint) -> u64 { a.ashl(b as u32) } - #[avr_skip] pub extern "C" fn __ashlti3(a: u128, b: u32) -> u128 { a.ashl(b) } - #[avr_skip] #[maybe_use_optimized_c_shim] pub extern "C" fn __ashrsi3(a: i32, b: u32) -> i32 { a.ashr(b) } - #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lasr] pub extern "C" fn __ashrdi3(a: i64, b: core::ffi::c_uint) -> i64 { a.ashr(b as u32) } - #[avr_skip] pub extern "C" fn __ashrti3(a: i128, b: u32) -> i128 { a.ashr(b) } - #[avr_skip] #[maybe_use_optimized_c_shim] pub extern "C" fn __lshrsi3(a: u32, b: u32) -> u32 { a.lshr(b) } - #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsr] pub extern "C" fn __lshrdi3(a: u64, b: core::ffi::c_uint) -> u64 { a.lshr(b as u32) } - #[avr_skip] pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 { a.lshr(b) } diff --git a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs index 1fa761212b2..a5c16040a52 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs @@ -17,8 +17,10 @@ intrinsics! { pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { u32_div_rem(n, d).1 } +} - #[avr_skip] +#[cfg(not(target_arch = "avr"))] +intrinsics! { #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { @@ -28,22 +30,34 @@ intrinsics! { } quo_rem.0 } +} + +#[cfg(target_arch = "avr")] +intrinsics! { + /// Returns `n / d` and `n % d` packed together. + /// + /// Ideally we'd use `-> (u32, u32)` or some kind of a packed struct, but + /// both force a stack allocation, while our result has to be in R18:R26. + pub extern "C" fn __udivmodsi4(n: u32, d: u32) -> u64 { + let (div, rem) = u32_div_rem(n, d); - #[avr_skip] + ((rem as u64) << 32) | (div as u64) + } +} + +intrinsics! { #[maybe_use_optimized_c_shim] /// Returns `n / d` pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { u64_div_rem(n, d).0 } - #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { u64_div_rem(n, d).1 } - #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { @@ -57,7 +71,6 @@ intrinsics! { // Note: we use block configuration and not `if cfg!(...)`, because we need to entirely disable // the existence of `u128_div_rem` to get 32-bit SPARC to compile, see `u128_divide_sparc` docs. - #[avr_skip] /// Returns `n / d` pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { @@ -68,7 +81,6 @@ intrinsics! { } } - #[avr_skip] /// Returns `n % d` pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { @@ -81,7 +93,6 @@ intrinsics! { } } - #[avr_skip] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index b1b71379cc9..0397e4551fb 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -445,35 +445,6 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // For some intrinsics, AVR uses a custom calling convention¹ that does not - // match our definitions here. Ideally we would just use hand-written naked - // functions, but that's quite a lot of code to port² - so for the time - // being we are just ignoring the problematic functions, letting avr-gcc - // (which is required to compile to AVR anyway) link them from libgcc. - // - // ¹ https://gcc.gnu.org/wiki/avr-gcc (see "Exceptions to the Calling - // Convention") - // ² https://github.com/gcc-mirror/gcc/blob/31048012db98f5ec9c2ba537bfd850374bdd771f/libgcc/config/avr/lib1funcs.S - ( - #[avr_skip] - $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(not(target_arch = "avr"))] - intrinsics! { - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - // This is the final catch-all rule. At this point we generate an // intrinsic with a conditional `#[no_mangle]` directive to avoid // interfering with duplicate symbols and whatnot during testing. diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index f5ac2ab7da1..edbd3684d47 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -175,7 +175,6 @@ fn trailing_zeros() { } #[test] -#[cfg(not(target_arch = "avr"))] fn bswap() { use compiler_builtins::int::bswap::{__bswapdi2, __bswapsi2}; fuzz(N, |x: u32| { -- cgit 1.4.1-3-g733a5 From 9b8ccf67c691dd9ed1f1ba2b39608fdd03ce75dd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 2 Apr 2025 19:19:43 +0000 Subject: Revert "Disable `f16` on AArch64 without the `neon` feature" The LLVM issue [1] was resolved and the fix was synced to rust-lang/rust in [2]. This reverts commit 5cf417a9e92bb48e4e55756a645826fd167b9f3a. [1]: https://github.com/llvm/llvm-project/issues/129394 [2]: https://github.com/rust-lang/rust/pull/138695 --- library/compiler-builtins/compiler-builtins/configure.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/configure.rs b/library/compiler-builtins/compiler-builtins/configure.rs index 2f134e57818..4be0b3ca23c 100644 --- a/library/compiler-builtins/compiler-builtins/configure.rs +++ b/library/compiler-builtins/compiler-builtins/configure.rs @@ -91,8 +91,6 @@ pub fn configure_f16_f128(target: &Target) { let f16_enabled = match target.arch.as_str() { // Unsupported "arm64ec" => false, - // Crash in LLVM20 - "aarch64" if !target.features.iter().any(|f| f == "neon") => false, // Selection failure "s390x" => false, // Infinite recursion -- cgit 1.4.1-3-g733a5 From 87595c5d825a62219964752b2c63918ee97c5ab9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 9 Apr 2025 02:40:43 +0000 Subject: Remove a mention of `force-soft-float` in `build.rs` `libm` no longer uses this directly in `cfg`, it is only for setting other configuration in the `libm` `build.rs`. Clean up this configuration in `compiler-builtins` since it is unused. --- library/compiler-builtins/compiler-builtins/build.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index fdfb61b17df..d627121f348 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -101,9 +101,7 @@ fn configure_libm(target: &Target) { println!("cargo:rustc-cfg=intrinsics_enabled"); // The arch module may contain assembly. - if cfg!(feature = "no-asm") { - println!("cargo:rustc-cfg=feature=\"force-soft-floats\""); - } else { + if !cfg!(feature = "no-asm") { println!("cargo:rustc-cfg=arch_enabled"); } -- cgit 1.4.1-3-g733a5 From 4e5cbbeda169377e5025a979105d0dac31bf560a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 9 Apr 2025 01:56:14 +0000 Subject: Replace calls to `core::arch` intrinsics with assembly Some backends may replace calls to `core::arch` with multiple calls to `sqrt` [1], which becomes recursive. Help mitigate this by replacing the call with assembly. Results in the same assembly as the current implementation when built with optimizations. [1]: https://github.com/rust-lang/compiler-builtins/issues/649 --- .../compiler-builtins/libm/src/math/arch/i686.rs | 35 ++++++++++++---------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/arch/i686.rs b/library/compiler-builtins/libm/src/math/arch/i686.rs index ad54d8b61d7..3e1d19bfab6 100644 --- a/library/compiler-builtins/libm/src/math/arch/i686.rs +++ b/library/compiler-builtins/libm/src/math/arch/i686.rs @@ -1,22 +1,27 @@ //! Architecture-specific support for x86-32 and x86-64 with SSE2 -#[cfg(target_arch = "x86")] -use core::arch::x86::*; -#[cfg(target_arch = "x86_64")] -use core::arch::x86_64::*; - -pub fn sqrtf(x: f32) -> f32 { +pub fn sqrtf(mut x: f32) -> f32 { + // SAFETY: `sqrtss` is part of `sse2`, which this module is gated behind. It has no memory + // access or side effects. unsafe { - let m = _mm_set_ss(x); - let m_sqrt = _mm_sqrt_ss(m); - _mm_cvtss_f32(m_sqrt) - } + core::arch::asm!( + "sqrtss {x}, {x}", + x = inout(xmm_reg) x, + options(nostack, nomem, pure), + ) + }; + x } -pub fn sqrt(x: f64) -> f64 { +pub fn sqrt(mut x: f64) -> f64 { + // SAFETY: `sqrtsd` is part of `sse2`, which this module is gated behind. It has no memory + // access or side effects. unsafe { - let m = _mm_set_sd(x); - let m_sqrt = _mm_sqrt_pd(m); - _mm_cvtsd_f64(m_sqrt) - } + core::arch::asm!( + "sqrtsd {x}, {x}", + x = inout(xmm_reg) x, + options(nostack, nomem, pure), + ) + }; + x } -- cgit 1.4.1-3-g733a5 From 375cb5402fb1aa6bf8b4c513921b5f087decb3ca Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 9 Apr 2025 02:22:15 +0000 Subject: Resolve small errors identified by recent clippy --- library/compiler-builtins/libm/crates/libm-test/src/precision.rs | 1 + library/compiler-builtins/libm/src/math/support/env.rs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 8916b43ab17..f5fb5f6707b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -13,6 +13,7 @@ use crate::{BaseName, CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; pub struct SpecialCase; /// ULP allowed to differ from the results returned by a test basis. +#[allow(clippy::single_match)] pub fn default_ulp(ctx: &CheckCtx) -> u32 { // ULP compared to the infinite (MPFR) result. let mut ulp = match ctx.base_name { diff --git a/library/compiler-builtins/libm/src/math/support/env.rs b/library/compiler-builtins/libm/src/math/support/env.rs index 7244381dacc..c05890d9851 100644 --- a/library/compiler-builtins/libm/src/math/support/env.rs +++ b/library/compiler-builtins/libm/src/math/support/env.rs @@ -70,7 +70,6 @@ impl Status { /// The default result for division is +/-inf based on operand sign. For `logB`, the default /// result is -inf. /// `x / y` when `x != 0.0` and `y == 0.0`, - #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] pub const DIVIDE_BY_ZERO: Self = Self(1 << 2); -- cgit 1.4.1-3-g733a5 From 28b6df86036aeeb231e2ea09c78ea33645aa4325 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 23 Jan 2025 01:46:24 +0000 Subject: Add assembly version of simple operations on aarch64 Replace `core::arch` versions of the following with handwritten assembly, which avoids recursion issues (cg_gcc using `rint` as a fallback) as well as problems with `aarch64be`. * `rint` * `rintf` Additionally, add assembly versions of the following: * `fma` * `fmaf` * `sqrt` * `sqrtf` If the `fp16` target feature is available, which implies `neon`, also include the following: * `rintf16` * `sqrtf16` `sqrt` is added to match the implementation for `x86`. `fma` is included since it is used by many other routines. There are a handful of other operations that have assembly implementations. They are omitted here because we should have basic float math routines available in `core` in the near future, which will allow us to defer to LLVM for assembly lowering rather than implementing these ourselves. --- .../libm/etc/function-definitions.json | 6 + .../libm/src/math/arch/aarch64.rs | 126 +++++++++++++++++---- .../compiler-builtins/libm/src/math/arch/mod.rs | 21 +++- library/compiler-builtins/libm/src/math/fma.rs | 6 + .../compiler-builtins/libm/src/math/fma_wide.rs | 6 + library/compiler-builtins/libm/src/math/rint.rs | 10 +- library/compiler-builtins/libm/src/math/sqrt.rs | 1 + library/compiler-builtins/libm/src/math/sqrtf.rs | 1 + library/compiler-builtins/libm/src/math/sqrtf16.rs | 6 + 9 files changed, 155 insertions(+), 28 deletions(-) diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 64a775ba9f1..bca58402f4e 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -342,12 +342,14 @@ }, "fma": { "sources": [ + "src/math/arch/aarch64.rs", "src/math/fma.rs" ], "type": "f64" }, "fmaf": { "sources": [ + "src/math/arch/aarch64.rs", "src/math/fma_wide.rs" ], "type": "f32" @@ -806,6 +808,7 @@ }, "rintf16": { "sources": [ + "src/math/arch/aarch64.rs", "src/math/rint.rs" ], "type": "f16" @@ -928,6 +931,7 @@ }, "sqrt": { "sources": [ + "src/math/arch/aarch64.rs", "src/math/arch/i686.rs", "src/math/arch/wasm32.rs", "src/math/generic/sqrt.rs", @@ -937,6 +941,7 @@ }, "sqrtf": { "sources": [ + "src/math/arch/aarch64.rs", "src/math/arch/i686.rs", "src/math/arch/wasm32.rs", "src/math/generic/sqrt.rs", @@ -953,6 +958,7 @@ }, "sqrtf16": { "sources": [ + "src/math/arch/aarch64.rs", "src/math/generic/sqrt.rs", "src/math/sqrtf16.rs" ], diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64.rs b/library/compiler-builtins/libm/src/math/arch/aarch64.rs index 374ec11bfec..020bb731cdc 100644 --- a/library/compiler-builtins/libm/src/math/arch/aarch64.rs +++ b/library/compiler-builtins/libm/src/math/arch/aarch64.rs @@ -1,33 +1,115 @@ -use core::arch::aarch64::{ - float32x2_t, float64x1_t, vdup_n_f32, vdup_n_f64, vget_lane_f32, vget_lane_f64, vrndn_f32, - vrndn_f64, -}; +//! Architecture-specific support for aarch64 with neon. -pub fn rint(x: f64) -> f64 { - // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. - let x_vec: float64x1_t = unsafe { vdup_n_f64(x) }; +use core::arch::asm; - // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. - let result_vec: float64x1_t = unsafe { vrndn_f64(x_vec) }; +pub fn fma(mut x: f64, y: f64, z: f64) -> f64 { + // SAFETY: `fmadd` is available with neon and has no side effects. + unsafe { + asm!( + "fmadd {x:d}, {x:d}, {y:d}, {z:d}", + x = inout(vreg) x, + y = in(vreg) y, + z = in(vreg) z, + options(nomem, nostack, pure) + ); + } + x +} - // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. - let result: f64 = unsafe { vget_lane_f64::<0>(result_vec) }; +pub fn fmaf(mut x: f32, y: f32, z: f32) -> f32 { + // SAFETY: `fmadd` is available with neon and has no side effects. + unsafe { + asm!( + "fmadd {x:s}, {x:s}, {y:s}, {z:s}", + x = inout(vreg) x, + y = in(vreg) y, + z = in(vreg) z, + options(nomem, nostack, pure) + ); + } + x +} - result +pub fn rint(mut x: f64) -> f64 { + // SAFETY: `frintn` is available with neon and has no side effects. + // + // `frintn` is always round-to-nearest which does not match the C specification, but Rust does + // not support rounding modes. + unsafe { + asm!( + "frintn {x:d}, {x:d}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x } -pub fn rintf(x: f32) -> f32 { - // There's a scalar form of this instruction (FRINTN) but core::arch doesn't expose it, so we - // have to use the vector form and drop the other lanes afterwards. +pub fn rintf(mut x: f32) -> f32 { + // SAFETY: `frintn` is available with neon and has no side effects. + // + // `frintn` is always round-to-nearest which does not match the C specification, but Rust does + // not support rounding modes. + unsafe { + asm!( + "frintn {x:s}, {x:s}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} - // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. - let x_vec: float32x2_t = unsafe { vdup_n_f32(x) }; +#[cfg(all(f16_enabled, target_feature = "fp16"))] +pub fn rintf16(mut x: f16) -> f16 { + // SAFETY: `frintn` is available for `f16` with `fp16` (implies `neon`) and has no side effects. + // + // `frintn` is always round-to-nearest which does not match the C specification, but Rust does + // not support rounding modes. + unsafe { + asm!( + "frintn {x:h}, {x:h}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} - // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. - let result_vec: float32x2_t = unsafe { vrndn_f32(x_vec) }; +pub fn sqrt(mut x: f64) -> f64 { + // SAFETY: `fsqrt` is available with neon and has no side effects. + unsafe { + asm!( + "fsqrt {x:d}, {x:d}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} - // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. - let result: f32 = unsafe { vget_lane_f32::<0>(result_vec) }; +pub fn sqrtf(mut x: f32) -> f32 { + // SAFETY: `fsqrt` is available with neon and has no side effects. + unsafe { + asm!( + "fsqrt {x:s}, {x:s}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} - result +#[cfg(all(f16_enabled, target_feature = "fp16"))] +pub fn sqrtf16(mut x: f16) -> f16 { + // SAFETY: `fsqrt` is available for `f16` with `fp16` (implies `neon`) and has no + // side effects. + unsafe { + asm!( + "fsqrt {x:h}, {x:h}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x } diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index 091d7650a5a..d9f2aad66d4 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -18,12 +18,25 @@ cfg_if! { mod i686; pub use i686::{sqrt, sqrtf}; } else if #[cfg(all( - target_arch = "aarch64", // TODO: also arm64ec? - target_feature = "neon", - target_endian = "little", // see https://github.com/rust-lang/stdarch/issues/1484 + any(target_arch = "aarch64", target_arch = "arm64ec"), + target_feature = "neon" ))] { mod aarch64; - pub use aarch64::{rint, rintf}; + + pub use aarch64::{ + fma, + fmaf, + rint, + rintf, + sqrt, + sqrtf, + }; + + #[cfg(all(f16_enabled, target_feature = "fp16"))] + pub use aarch64::{ + rintf16, + sqrtf16, + }; } } diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 049f573cc92..789b0836afb 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -9,6 +9,12 @@ use super::{CastFrom, CastInto, Float, Int, MinInt}; /// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fma(x: f64, y: f64, z: f64) -> f64 { + select_implementation! { + name: fma, + use_arch: all(target_arch = "aarch64", target_feature = "neon"), + args: x, y, z, + } + fma_round(x, y, z, Round::Nearest).val } diff --git a/library/compiler-builtins/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/src/math/fma_wide.rs index d0cf33baf7a..8e908a14f21 100644 --- a/library/compiler-builtins/libm/src/math/fma_wide.rs +++ b/library/compiler-builtins/libm/src/math/fma_wide.rs @@ -17,6 +17,12 @@ pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 { /// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { + select_implementation! { + name: fmaf, + use_arch: all(target_arch = "aarch64", target_feature = "neon"), + args: x, y, z, + } + fma_wide_round(x, y, z, Round::Nearest).val } diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 8a5cbeab497..e1c32c94355 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -4,6 +4,12 @@ use super::support::Round; #[cfg(f16_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rintf16(x: f16) -> f16 { + select_implementation! { + name: rintf16, + use_arch: all(target_arch = "aarch64", target_feature = "fp16"), + args: x, + } + super::generic::rint_round(x, Round::Nearest).val } @@ -13,8 +19,8 @@ pub fn rintf(x: f32) -> f32 { select_implementation! { name: rintf, use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), all(target_arch = "wasm32", intrinsics_enabled), - all(target_arch = "aarch64", target_feature = "neon", target_endian = "little"), ), args: x, } @@ -28,8 +34,8 @@ pub fn rint(x: f64) -> f64 { select_implementation! { name: rint, use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), all(target_arch = "wasm32", intrinsics_enabled), - all(target_arch = "aarch64", target_feature = "neon", target_endian = "little"), ), args: x, } diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 0e1d0cd2c1c..2bfc42bcfed 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -4,6 +4,7 @@ pub fn sqrt(x: f64) -> f64 { select_implementation! { name: sqrt, use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), all(target_arch = "wasm32", intrinsics_enabled), target_feature = "sse2" ), diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 2e69a4b6694..c28a705e378 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -4,6 +4,7 @@ pub fn sqrtf(x: f32) -> f32 { select_implementation! { name: sqrtf, use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), all(target_arch = "wasm32", intrinsics_enabled), target_feature = "sse2" ), diff --git a/library/compiler-builtins/libm/src/math/sqrtf16.rs b/library/compiler-builtins/libm/src/math/sqrtf16.rs index 549bf902c72..7bedb7f8bbb 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf16.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf16.rs @@ -1,5 +1,11 @@ /// The square root of `x` (f16). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf16(x: f16) -> f16 { + select_implementation! { + name: sqrtf16, + use_arch: all(target_arch = "aarch64", target_feature = "fp16"), + args: x, + } + return super::generic::sqrt(x); } -- cgit 1.4.1-3-g733a5 From 571a3dce9e5c599119d113f95027698a1e921599 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 9 Apr 2025 17:44:37 +0000 Subject: Update the `libm` submodule Includes [1] and [2], which should resolve problems cg_gcc has using scalar math operations as a fallback for vector operations. [1]: https://github.com/rust-lang/libm/pull/459 [2]: https://github.com/rust-lang/libm/pull/534 --- library/compiler-builtins/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/libm b/library/compiler-builtins/compiler-builtins/libm index 69219c491ee..96d1400326f 160000 --- a/library/compiler-builtins/compiler-builtins/libm +++ b/library/compiler-builtins/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 69219c491ee9f05761d2068fd6d4c7c0de6faa3a +Subproject commit 96d1400326f47381858f8149451a2b2fd8de2ea4 -- cgit 1.4.1-3-g733a5 From 73a04443bdd2e5d9945f03438a0424996059837d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 9 Apr 2025 17:52:23 +0000 Subject: chore: release v0.1.153 --- library/compiler-builtins/compiler-builtins/CHANGELOG.md | 9 +++++++++ library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index 987f8771307..517ba7859a9 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.153](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.152...compiler_builtins-v0.1.153) - 2025-04-09 + +### Other + +- Remove a mention of `force-soft-float` in `build.rs` +- Revert "Disable `f16` on AArch64 without the `neon` feature" +- Skip No More! +- avoid out-of-bounds accesses ([#799](https://github.com/rust-lang/compiler-builtins/pull/799)) + ## [0.1.152](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.151...compiler_builtins-v0.1.152) - 2025-03-20 ### Other diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 8de8bce6a12..c0c40b5e17a 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.152" +version = "0.1.153" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "../README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From b955cc691e07cbfca8000389cdbeaf587a0be19a Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Tue, 15 Apr 2025 03:46:12 +0300 Subject: Implement rounding for the hex float parsing and prepare to improve error handling Parsing errors are now bubbled up part of the way, but that needs some more work. Rounding should be correct, and the `Status` returned by `parse_any` should have the correct bits set. These are used for the current (unchanged) behavior of the surface level functions like `hf64`: panic on invalid inputs, or values that aren't exactly representable. --- .../libm/crates/libm-test/src/f8_impl.rs | 5 +- .../compiler-builtins/libm/src/math/support/env.rs | 16 +- .../libm/src/math/support/hex_float.rs | 495 ++++++++++++++++----- 3 files changed, 405 insertions(+), 111 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index 0683d839266..6772e092caa 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -3,8 +3,6 @@ use std::cmp::{self, Ordering}; use std::{fmt, ops}; -use libm::support::hex_float::parse_any; - use crate::Float; /// Sometimes verifying float logic is easiest when all values can quickly be checked exhaustively @@ -499,5 +497,6 @@ impl fmt::LowerHex for f8 { } pub const fn hf8(s: &str) -> f8 { - f8(parse_any(s, 8, 3) as u8) + let Ok(bits) = libm::support::hex_float::parse_hex_exact(s, 8, 3) else { panic!() }; + f8(bits as u8) } diff --git a/library/compiler-builtins/libm/src/math/support/env.rs b/library/compiler-builtins/libm/src/math/support/env.rs index c05890d9851..796309372a5 100644 --- a/library/compiler-builtins/libm/src/math/support/env.rs +++ b/library/compiler-builtins/libm/src/math/support/env.rs @@ -46,7 +46,7 @@ pub enum Round { } /// IEEE 754 exception status flags. -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Status(u8); impl Status { @@ -90,16 +90,22 @@ impl Status { /// True if `UNDERFLOW` is set. #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] - pub fn underflow(self) -> bool { + pub const fn underflow(self) -> bool { self.0 & Self::UNDERFLOW.0 != 0 } + /// True if `OVERFLOW` is set. + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub const fn overflow(self) -> bool { + self.0 & Self::OVERFLOW.0 != 0 + } + pub fn set_underflow(&mut self, val: bool) { self.set_flag(val, Self::UNDERFLOW); } /// True if `INEXACT` is set. - pub fn inexact(self) -> bool { + pub const fn inexact(self) -> bool { self.0 & Self::INEXACT.0 != 0 } @@ -114,4 +120,8 @@ impl Status { self.0 &= !mask.0; } } + + pub(crate) const fn with(self, rhs: Self) -> Self { + Self(self.0 | rhs.0) + } } diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index be7d7607f91..819e2f56e36 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -2,149 +2,260 @@ use core::fmt; -use super::{Float, f32_from_bits, f64_from_bits}; +use super::{Float, Round, Status, f32_from_bits, f64_from_bits}; /// Construct a 16-bit float from hex float representation (C-style) #[cfg(f16_enabled)] pub const fn hf16(s: &str) -> f16 { - f16::from_bits(parse_any(s, 16, 10) as u16) + match parse_hex_exact(s, 16, 10) { + Ok(bits) => f16::from_bits(bits as u16), + Err(HexFloatParseError(s)) => panic!("{}", s), + } } /// Construct a 32-bit float from hex float representation (C-style) #[allow(unused)] pub const fn hf32(s: &str) -> f32 { - f32_from_bits(parse_any(s, 32, 23) as u32) + match parse_hex_exact(s, 32, 23) { + Ok(bits) => f32_from_bits(bits as u32), + Err(HexFloatParseError(s)) => panic!("{}", s), + } } /// Construct a 64-bit float from hex float representation (C-style) pub const fn hf64(s: &str) -> f64 { - f64_from_bits(parse_any(s, 64, 52) as u64) + match parse_hex_exact(s, 64, 52) { + Ok(bits) => f64_from_bits(bits as u64), + Err(HexFloatParseError(s)) => panic!("{}", s), + } } /// Construct a 128-bit float from hex float representation (C-style) #[cfg(f128_enabled)] pub const fn hf128(s: &str) -> f128 { - f128::from_bits(parse_any(s, 128, 112)) + match parse_hex_exact(s, 128, 112) { + Ok(bits) => f128::from_bits(bits), + Err(HexFloatParseError(s)) => panic!("{}", s), + } +} +#[derive(Copy, Clone, Debug)] +pub struct HexFloatParseError(&'static str); + +/// Parses any float to its bitwise representation, returning an error if it cannot be represented exactly +pub const fn parse_hex_exact( + s: &str, + bits: u32, + sig_bits: u32, +) -> Result { + match parse_any(s, bits, sig_bits, Round::Nearest) { + Err(e) => Err(e), + Ok((bits, Status::OK)) => Ok(bits), + Ok((_, status)) if status.overflow() => Err(HexFloatParseError("the value is too huge")), + Ok((_, status)) if status.underflow() => Err(HexFloatParseError("the value is too tiny")), + Ok((_, status)) if status.inexact() => Err(HexFloatParseError("the value is too precise")), + Ok(_) => unreachable!(), + } } /// Parse any float from hex to its bitwise representation. -/// -/// `nan_repr` is passed rather than constructed so the platform-specific NaN is returned. -pub const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 { +pub const fn parse_any( + s: &str, + bits: u32, + sig_bits: u32, + round: Round, +) -> Result<(u128, Status), HexFloatParseError> { + let mut b = s.as_bytes(); + + if sig_bits > 119 || bits > 128 || bits < sig_bits + 3 || bits > sig_bits + 30 { + return Err(HexFloatParseError("unsupported target float configuration")); + } + + let neg = matches!(b, [b'-', ..]); + if let &[b'-' | b'+', ref rest @ ..] = b { + b = rest; + } + + let sign_bit = 1 << (bits - 1); + let quiet_bit = 1 << (sig_bits - 1); + let nan = sign_bit - quiet_bit; + let inf = nan - quiet_bit; + + let (mut x, status) = match *b { + [b'i' | b'I', b'n' | b'N', b'f' | b'F'] => (inf, Status::OK), + [b'n' | b'N', b'a' | b'A', b'n' | b'N'] => (nan, Status::OK), + [b'0', b'x' | b'X', ref rest @ ..] => { + let round = match (neg, round) { + // parse("-x", Round::Positive) == -parse("x", Round::Negative) + (true, Round::Positive) => Round::Negative, + (true, Round::Negative) => Round::Positive, + // rounding toward nearest or zero are symmetric + (true, Round::Nearest | Round::Zero) | (false, _) => round, + }; + match parse_finite(rest, bits, sig_bits, round) { + Err(e) => return Err(e), + Ok(res) => res, + } + } + _ => return Err(HexFloatParseError("no hex indicator")), + }; + + if neg { + x ^= sign_bit; + } + + Ok((x, status)) +} + +const fn parse_finite( + b: &[u8], + bits: u32, + sig_bits: u32, + rounding_mode: Round, +) -> Result<(u128, Status), HexFloatParseError> { let exp_bits: u32 = bits - sig_bits - 1; let max_msb: i32 = (1 << (exp_bits - 1)) - 1; // The exponent of one ULP in the subnormals let min_lsb: i32 = 1 - max_msb - sig_bits as i32; - let exp_mask = ((1 << exp_bits) - 1) << sig_bits; + let (mut sig, mut exp) = match parse_hex(b) { + Err(e) => return Err(e), + Ok(Parsed { sig: 0, .. }) => return Ok((0, Status::OK)), + Ok(Parsed { sig, exp }) => (sig, exp), + }; + + let mut round_bits = u128_ilog2(sig) as i32 - sig_bits as i32; + + // Round at least up to min_lsb + if exp < min_lsb - round_bits { + round_bits = min_lsb - exp; + } + + let mut status = Status::OK; - let (neg, mut sig, exp) = match parse_hex(s.as_bytes()) { - Parsed::Finite { neg, sig: 0, .. } => return (neg as u128) << (bits - 1), - Parsed::Finite { neg, sig, exp } => (neg, sig, exp), - Parsed::Infinite { neg } => return ((neg as u128) << (bits - 1)) | exp_mask, - Parsed::Nan { neg } => { - return ((neg as u128) << (bits - 1)) | exp_mask | (1 << (sig_bits - 1)); + exp += round_bits; + + if round_bits > 0 { + // first, prepare for rounding exactly two bits + if round_bits == 1 { + sig <<= 1; + } else if round_bits > 2 { + sig = shr_odd_rounding(sig, (round_bits - 2) as u32); } - }; - // exponents of the least and most significant bits in the value - let lsb = sig.trailing_zeros() as i32; - let msb = u128_ilog2(sig) as i32; - let sig_bits = sig_bits as i32; + if sig & 0b11 != 0 { + status = Status::INEXACT; + } - assert!(msb - lsb <= sig_bits, "the value is too precise"); - assert!(msb + exp <= max_msb, "the value is too huge"); - assert!(lsb + exp >= min_lsb, "the value is too tiny"); + sig = shr2_round(sig, rounding_mode); + } else if round_bits < 0 { + sig <<= -round_bits; + } // The parsed value is X = sig * 2^exp // Expressed as a multiple U of the smallest subnormal value: // X = U * 2^min_lsb, so U = sig * 2^(exp-min_lsb) - let mut uexp = exp - min_lsb; + let uexp = (exp - min_lsb) as u128; + let uexp = uexp << sig_bits; - let shift = if uexp + msb >= sig_bits { - // normal, shift msb to position sig_bits - sig_bits - msb - } else { - // subnormal, shift so that uexp becomes 0 - uexp + // Note that it is possible for the exponent bits to equal 2 here + // if the value rounded up, but that means the mantissa is all zeroes + // so the value is still correct + debug_assert!(sig <= 2 << sig_bits); + + let inf = ((1 << exp_bits) - 1) << sig_bits; + + let bits = match sig.checked_add(uexp) { + Some(bits) if bits < inf => { + // inexact subnormal or zero? + if status.inexact() && bits < (1 << sig_bits) { + status = status.with(Status::UNDERFLOW); + } + bits + } + _ => { + // overflow to infinity + status = status.with(Status::OVERFLOW).with(Status::INEXACT); + match rounding_mode { + Round::Positive | Round::Nearest => inf, + Round::Negative | Round::Zero => inf - 1, + } + } }; + Ok((bits, status)) +} - if shift >= 0 { - sig <<= shift; +/// Shift right, rounding all inexact divisions to the nearest odd number +/// E.g. (0 >> 4) -> 0, (1..=31 >> 4) -> 1, (32 >> 4) -> 2, ... +/// +/// Useful for reducing a number before rounding the last two bits, since +/// the result of the final rounding is preserved for all rounding modes. +const fn shr_odd_rounding(x: u128, k: u32) -> u128 { + if k < 128 { + let inexact = x.trailing_zeros() < k; + (x >> k) | (inexact as u128) } else { - sig >>= -shift; + (x != 0) as u128 } - uexp -= shift; - - // the most significant bit is like having 1 in the exponent bits - // add any leftover exponent to that - assert!(uexp >= 0 && uexp < (1 << exp_bits) - 2); - sig += (uexp as u128) << sig_bits; +} - // finally, set the sign bit if necessary - sig | ((neg as u128) << (bits - 1)) +/// Divide by 4, rounding with the given mode +const fn shr2_round(mut x: u128, round: Round) -> u128 { + let t = (x as u32) & 0b111; + x >>= 2; + match round { + // Look-up-table on the last three bits for when to round up + Round::Nearest => x + ((0b11001000_u8 >> t) & 1) as u128, + + Round::Negative => x, + Round::Zero => x, + Round::Positive => x + (t & 0b11 != 0) as u128, + } } -/// A parsed floating point number. -enum Parsed { - /// Absolute value sig * 2^e - Finite { - neg: bool, - sig: u128, - exp: i32, - }, - Infinite { - neg: bool, - }, - Nan { - neg: bool, - }, +/// A parsed finite and unsigned floating point number. +struct Parsed { + /// Absolute value sig * 2^exp + sig: u128, + exp: i32, } /// Parse a hexadecimal float x -const fn parse_hex(mut b: &[u8]) -> Parsed { - let mut neg = false; +const fn parse_hex(mut b: &[u8]) -> Result { let mut sig: u128 = 0; let mut exp: i32 = 0; - if let &[c @ (b'-' | b'+'), ref rest @ ..] = b { - b = rest; - neg = c == b'-'; - } - - match *b { - [b'i' | b'I', b'n' | b'N', b'f' | b'F'] => return Parsed::Infinite { neg }, - [b'n' | b'N', b'a' | b'A', b'n' | b'N'] => return Parsed::Nan { neg }, - _ => (), - } - - if let &[b'0', b'x' | b'X', ref rest @ ..] = b { - b = rest; - } else { - panic!("no hex indicator"); - } - let mut seen_point = false; let mut some_digits = false; + let mut inexact = false; while let &[c, ref rest @ ..] = b { b = rest; match c { b'.' => { - assert!(!seen_point); + if seen_point { + return Err(HexFloatParseError("unexpected '.' parsing fractional digits")); + } seen_point = true; continue; } b'p' | b'P' => break, c => { - let digit = hex_digit(c); + let digit = match hex_digit(c) { + Some(d) => d, + None => return Err(HexFloatParseError("expected hexadecimal digit")), + }; some_digits = true; - let of; - (sig, of) = sig.overflowing_mul(16); - assert!(!of, "too many digits"); - sig |= digit as u128; - // up until the fractional point, the value grows + + if (sig >> 124) == 0 { + sig <<= 4; + sig |= digit as u128; + } else { + // FIXME: it is technically possible for exp to overflow if parsing a string with >500M digits + exp += 4; + inexact |= digit != 0; + } + // Up until the fractional point, the value grows // with more digits, but after it the exponent is // compensated to match. if seen_point { @@ -153,49 +264,79 @@ const fn parse_hex(mut b: &[u8]) -> Parsed { } } } - assert!(some_digits, "at least one digit is required"); + // If we've set inexact, the exact value has more than 125 + // significant bits, and lies somewhere between sig and sig + 1. + // Because we'll round off at least two of the trailing bits, + // setting the last bit gives correct rounding for inexact values. + sig |= inexact as u128; + + if !some_digits { + return Err(HexFloatParseError("at least one digit is required")); + }; + some_digits = false; - let mut negate_exp = false; - if let &[c @ (b'-' | b'+'), ref rest @ ..] = b { + let negate_exp = matches!(b, [b'-', ..]); + if let &[b'-' | b'+', ref rest @ ..] = b { b = rest; - negate_exp = c == b'-'; } - let mut pexp: i32 = 0; + let mut pexp: u32 = 0; while let &[c, ref rest @ ..] = b { b = rest; - let digit = dec_digit(c); + let digit = match dec_digit(c) { + Some(d) => d, + None => return Err(HexFloatParseError("expected decimal digit")), + }; some_digits = true; - let of; - (pexp, of) = pexp.overflowing_mul(10); - assert!(!of, "too many exponent digits"); - pexp += digit as i32; + pexp = pexp.saturating_mul(10); + pexp += digit as u32; } - assert!(some_digits, "at least one exponent digit is required"); + if !some_digits { + return Err(HexFloatParseError("at least one exponent digit is required")); + }; + + { + let e; + if negate_exp { + e = (exp as i64) - (pexp as i64); + } else { + e = (exp as i64) + (pexp as i64); + }; + + exp = if e < i32::MIN as i64 { + i32::MIN + } else if e > i32::MAX as i64 { + i32::MAX + } else { + e as i32 + }; + } + /* FIXME(msrv): once MSRV >= 1.66, replace the above workaround block with: if negate_exp { - exp -= pexp; + exp = exp.saturating_sub_unsigned(pexp); } else { - exp += pexp; - } + exp = exp.saturating_add_unsigned(pexp); + }; + */ - Parsed::Finite { neg, sig, exp } + Ok(Parsed { sig, exp }) } -const fn dec_digit(c: u8) -> u8 { +const fn dec_digit(c: u8) -> Option { match c { - b'0'..=b'9' => c - b'0', - _ => panic!("bad char"), + b'0'..=b'9' => Some(c - b'0'), + _ => None, } } -const fn hex_digit(c: u8) -> u8 { +const fn hex_digit(c: u8) -> Option { match c { - b'0'..=b'9' => c - b'0', - b'a'..=b'f' => c - b'a' + 10, - b'A'..=b'F' => c - b'A' + 10, - _ => panic!("bad char"), + b'0'..=b'9' => Some(c - b'0'), + b'a'..=b'f' => Some(c - b'a' + 10), + b'A'..=b'F' => Some(c - b'A' + 10), + _ => None, } } @@ -341,6 +482,61 @@ mod parse_tests { use super::*; + #[cfg(f16_enabled)] + fn rounding_properties(s: &str) -> Result<(), HexFloatParseError> { + let (xd, s0) = parse_any(s, 16, 10, Round::Negative)?; + let (xu, s1) = parse_any(s, 16, 10, Round::Positive)?; + let (xz, s2) = parse_any(s, 16, 10, Round::Zero)?; + let (xn, s3) = parse_any(s, 16, 10, Round::Nearest)?; + + // FIXME: A value between the least normal and largest subnormal + // could have underflow status depend on rounding mode. + + if let Status::OK = s0 { + // an exact result is the same for all rounding modes + assert_eq!(s0, s1); + assert_eq!(s0, s2); + assert_eq!(s0, s3); + + assert_eq!(xd, xu); + assert_eq!(xd, xz); + assert_eq!(xd, xn); + } else { + assert!([s0, s1, s2, s3].into_iter().all(Status::inexact)); + + let xd = f16::from_bits(xd as u16); + let xu = f16::from_bits(xu as u16); + let xz = f16::from_bits(xz as u16); + let xn = f16::from_bits(xn as u16); + + assert_biteq!(xd.next_up(), xu, "s={s}, xd={xd:?}, xu={xu:?}"); + + let signs = [xd, xu, xz, xn].map(f16::is_sign_negative); + + if signs == [true; 4] { + assert_biteq!(xz, xu); + } else { + assert_eq!(signs, [false; 4]); + assert_biteq!(xz, xd); + } + + if xn.to_bits() != xd.to_bits() { + assert_biteq!(xn, xu); + } + } + Ok(()) + } + #[test] + #[cfg(f16_enabled)] + fn test_rounding() { + let n = 1_i32 << 14; + for i in -n..n { + let u = i.rotate_right(11) as u32; + let s = format!("{}", Hexf(f32::from_bits(u))); + assert!(rounding_properties(&s).is_ok()); + } + } + #[test] fn test_parse_any() { for k in -149..=127 { @@ -397,6 +593,48 @@ mod parse_tests { } } + // FIXME: this test is causing failures that are likely UB on various platforms + #[cfg(all(target_arch = "x86_64", target_os = "linux"))] + #[test] + #[cfg(f128_enabled)] + fn rounding() { + let pi = std::f128::consts::PI; + let s = format!("{}", Hexf(pi)); + + for k in 0..=111 { + let (bits, status) = parse_any(&s, 128 - k, 112 - k, Round::Nearest).unwrap(); + let scale = (1u128 << (112 - k - 1)) as f128; + let expected = (pi * scale).round_ties_even() / scale; + assert_eq!(bits << k, expected.to_bits(), "k = {k}, s = {s}"); + assert_eq!(expected != pi, status.inexact()); + } + } + #[test] + fn rounding_extreme_underflow() { + for k in 1..1000 { + let s = format!("0x1p{}", -149 - k); + let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; + assert_eq!(bits, 0, "{s} should round to zero, got bits={bits}"); + assert!(status.underflow(), "should indicate underflow when parsing {s}"); + assert!(status.inexact(), "should indicate inexact when parsing {s}"); + } + } + #[test] + fn long_tail() { + for k in 1..1000 { + let s = format!("0x1.{}p0", "0".repeat(k)); + let Ok(bits) = parse_hex_exact(&s, 32, 23) else { panic!("parsing {s} failed") }; + assert_eq!(f32::from_bits(bits as u32), 1.0); + + let s = format!("0x1.{}1p0", "0".repeat(k)); + let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; + if status.inexact() { + assert!(1.0 == f32::from_bits(bits as u32)); + } else { + assert!(1.0 < f32::from_bits(bits as u32)); + } + } + } // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to // hide them from the AST. #[cfg(f16_enabled)] @@ -434,6 +672,7 @@ mod parse_tests { ]; for (s, exp) in checks { println!("parsing {s}"); + assert!(rounding_properties(s).is_ok()); let act = hf16(s).to_bits(); assert_eq!( act, exp, @@ -749,7 +988,13 @@ mod tests_panicking { #[test] #[should_panic(expected = "the value is too precise")] fn test_f128_extra_precision() { - // One bit more than the above. + // Just below the maximum finite. + hf128("0x1.fffffffffffffffffffffffffffe8p+16383"); + } + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f128_extra_precision_overflow() { + // One bit more than the above. Should overflow. hf128("0x1.ffffffffffffffffffffffffffff8p+16383"); } @@ -822,6 +1067,46 @@ mod print_tests { } } + #[test] + #[cfg(f16_enabled)] + fn test_f16_to_f32() { + use std::format; + // Exhaustively check that these are equivalent for all `f16`: + // - `f16 -> f32` + // - `f16 -> str -> f32` + // - `f16 -> f32 -> str -> f32` + // - `f16 -> f32 -> str -> f16 -> f32` + for x in 0..=u16::MAX { + let f16 = f16::from_bits(x); + let s16 = format!("{}", Hexf(f16)); + let f32 = f16 as f32; + let s32 = format!("{}", Hexf(f32)); + + let a = hf32(&s16); + let b = hf32(&s32); + let c = hf16(&s32); + + if f32.is_nan() && a.is_nan() && b.is_nan() && c.is_nan() { + continue; + } + + assert_eq!( + f32.to_bits(), + a.to_bits(), + "{f16:?} : f16 formatted as {s16} which parsed as {a:?} : f16" + ); + assert_eq!( + f32.to_bits(), + b.to_bits(), + "{f32:?} : f32 formatted as {s32} which parsed as {b:?} : f32" + ); + assert_eq!( + f32.to_bits(), + (c as f32).to_bits(), + "{f32:?} : f32 formatted as {s32} which parsed as {c:?} : f16" + ); + } + } #[test] fn spot_checks() { assert_eq!(Hexf(f32::MAX).to_string(), "0x1.fffffep+127"); -- cgit 1.4.1-3-g733a5 From b8083bd87d863b901bd713405e466db34c46b90d Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 13 Apr 2025 19:07:27 +0200 Subject: turn #[naked] into an unsafe attribute --- library/compiler-builtins/compiler-builtins/src/aarch64.rs | 2 +- library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs | 8 ++++---- library/compiler-builtins/compiler-builtins/src/arm.rs | 8 ++++---- library/compiler-builtins/compiler-builtins/src/macros.rs | 4 ++-- library/compiler-builtins/compiler-builtins/src/x86.rs | 4 ++-- library/compiler-builtins/compiler-builtins/src/x86_64.rs | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/compiler-builtins/src/aarch64.rs index cce485c4682..80392187c89 100644 --- a/library/compiler-builtins/compiler-builtins/src/aarch64.rs +++ b/library/compiler-builtins/compiler-builtins/src/aarch64.rs @@ -3,7 +3,7 @@ use core::intrinsics; intrinsics! { - #[naked] + #[unsafe(naked)] #[cfg(all(target_os = "uefi", not(feature = "no-asm")))] pub unsafe extern "C" fn __chkstk() { core::arch::naked_asm!( diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs b/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs index caac3e6025d..5515dbfc43a 100644 --- a/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs +++ b/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs @@ -131,7 +131,7 @@ macro_rules! compare_and_swap { ($ordering:ident, $bytes:tt, $name:ident) => { intrinsics! { #[maybe_use_optimized_c_shim] - #[naked] + #[unsafe(naked)] pub unsafe extern "C" fn $name ( expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { @@ -161,7 +161,7 @@ macro_rules! compare_and_swap_i128 { ($ordering:ident, $name:ident) => { intrinsics! { #[maybe_use_optimized_c_shim] - #[naked] + #[unsafe(naked)] pub unsafe extern "C" fn $name ( expected: i128, desired: i128, ptr: *mut i128 ) -> i128 { @@ -190,7 +190,7 @@ macro_rules! swap { ($ordering:ident, $bytes:tt, $name:ident) => { intrinsics! { #[maybe_use_optimized_c_shim] - #[naked] + #[unsafe(naked)] pub unsafe extern "C" fn $name ( left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { @@ -215,7 +215,7 @@ macro_rules! fetch_op { ($ordering:ident, $bytes:tt, $name:ident, $op:literal) => { intrinsics! { #[maybe_use_optimized_c_shim] - #[naked] + #[unsafe(naked)] pub unsafe extern "C" fn $name ( val: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { diff --git a/library/compiler-builtins/compiler-builtins/src/arm.rs b/library/compiler-builtins/compiler-builtins/src/arm.rs index 9e6608397a8..878bb8c4331 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm.rs @@ -20,7 +20,7 @@ macro_rules! bl { intrinsics! { // NOTE This function and the ones below are implemented using assembly because they are using a // custom calling convention which can't be implemented using a normal Rust function. - #[naked] + #[unsafe(naked)] #[cfg(not(target_env = "msvc"))] pub unsafe extern "C" fn __aeabi_uidivmod() { core::arch::naked_asm!( @@ -34,7 +34,7 @@ intrinsics! { ); } - #[naked] + #[unsafe(naked)] pub unsafe extern "C" fn __aeabi_uldivmod() { core::arch::naked_asm!( "push {{r4, lr}}", @@ -49,7 +49,7 @@ intrinsics! { ); } - #[naked] + #[unsafe(naked)] pub unsafe extern "C" fn __aeabi_idivmod() { core::arch::naked_asm!( "push {{r0, r1, r4, lr}}", @@ -61,7 +61,7 @@ intrinsics! { ); } - #[naked] + #[unsafe(naked)] pub unsafe extern "C" fn __aeabi_ldivmod() { core::arch::naked_asm!( "push {{r4, lr}}", diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index 0397e4551fb..13c8ecee32d 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -423,7 +423,7 @@ macro_rules! intrinsics { // Naked functions are special: we can't generate wrappers for them since // they use a custom calling convention. ( - #[naked] + #[unsafe(naked)] $(#[$($attr:tt)*])* pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* @@ -433,7 +433,7 @@ macro_rules! intrinsics { ) => ( // `#[naked]` definitions are referenced by other places, so we can't use `cfg` like the others pub mod $name { - #[naked] + #[unsafe(naked)] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] diff --git a/library/compiler-builtins/compiler-builtins/src/x86.rs b/library/compiler-builtins/compiler-builtins/src/x86.rs index ad04d2108ea..01152d9c798 100644 --- a/library/compiler-builtins/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/compiler-builtins/src/x86.rs @@ -8,7 +8,7 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt intrinsics! { - #[naked] + #[unsafe(naked)] #[cfg(all( any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") @@ -20,7 +20,7 @@ intrinsics! { ); } - #[naked] + #[unsafe(naked)] #[cfg(all( any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") diff --git a/library/compiler-builtins/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/x86_64.rs index aae601f58bf..af67e66e28d 100644 --- a/library/compiler-builtins/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/compiler-builtins/src/x86_64.rs @@ -8,7 +8,7 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt intrinsics! { - #[naked] + #[unsafe(naked)] #[cfg(all( any( all(windows, target_env = "gnu"), -- cgit 1.4.1-3-g733a5 From 377b08cc297cd9ae82bfa3e2604eaf64e426b7e6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 18:23:30 +0000 Subject: chore: release v0.1.154 --- library/compiler-builtins/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index 517ba7859a9..1dbccf38ec6 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.154](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.153...compiler_builtins-v0.1.154) - 2025-04-16 + +### Other + +- turn #[naked] into an unsafe attribute + ## [0.1.153](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.152...compiler_builtins-v0.1.153) - 2025-04-09 ### Other diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index c0c40b5e17a..bd17885a109 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.153" +version = "0.1.154" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "../README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 14ab2453f235ce66074d54e4040ce06febfe54f4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 15 Apr 2025 04:20:17 +0000 Subject: fmod: Add regression tests for subnormal issue From discussion at [1] our loop count calculation is incorrect, causing an issue with subnormal numbers. Add test cases for known failures. [1]: https://github.com/rust-lang/libm/pull/469#discussion_r2012473920 --- .../libm/crates/libm-test/src/gen/case_list.rs | 26 ++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs index 7cb9897d8d2..e3628d51c9a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs @@ -403,11 +403,33 @@ fn fminimum_numf128_cases() -> Vec> { } fn fmod_cases() -> Vec> { - vec![] + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Previous failure with incorrect loop iteration + // + ((2.1, 3.123e-320), Some(2.0696e-320)), + ((2.1, 2.253547e-318), Some(1.772535e-318)), + ], + ); + v } fn fmodf_cases() -> Vec> { - vec![] + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Previous failure with incorrect loop iteration + // + ((2.1, 8.858e-42), Some(8.085e-42)), + ((2.1, 6.39164e-40), Some(6.1636e-40)), + ((5.5, 6.39164e-40), Some(4.77036e-40)), + ((-151.189, 6.39164e-40), Some(-5.64734e-40)), + ], + ); + v } #[cfg(f128_enabled)] -- cgit 1.4.1-3-g733a5 From e4d716c84801d1d91d473aaa28692f595f352b34 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Apr 2025 18:43:25 +0000 Subject: fmod: Correct the normalization of subnormals Discussed at [1], there was an off-by-one mistake when converting from the loop routine to using `leading_zeros` for normalization. Currently, using `EXP_BITS` has the effect that `ix` after the branch has its MSB _one bit to the left_ of the implicit bit's position, whereas a shift by `EXP_BITS + 1` ensures that the MSB is exactly at the implicit bit's position, matching what is done for normals (where the implicit bit is set to be explicit). This doesn't seem to have any effect in our implementation since the failing test cases from [1] appear to still have correct results. Since the result of using `EXP_BITS + 1` is more consistent with what is done for normals, apply this here. [1]: https://github.com/rust-lang/libm/pull/469#discussion_r2012473920 --- library/compiler-builtins/libm/src/math/generic/fmod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs index c74b593d559..cd23350ea3a 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmod.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs @@ -26,7 +26,7 @@ pub fn fmod(x: F, y: F) -> F { /* normalize x and y */ if ex == 0 { - let i = ix << F::EXP_BITS; + let i = ix << (F::EXP_BITS + 1); ex -= i.leading_zeros() as i32; ix <<= -ex + 1; } else { @@ -35,7 +35,7 @@ pub fn fmod(x: F, y: F) -> F { } if ey == 0 { - let i = iy << F::EXP_BITS; + let i = iy << (F::EXP_BITS + 1); ey -= i.leading_zeros() as i32; iy <<= -ey + 1; } else { -- cgit 1.4.1-3-g733a5 From 7fb882c3fdf78bc1e3fe06c869e2d62ca64f3810 Mon Sep 17 00:00:00 2001 From: Paul Sbarra Date: Sat, 12 Apr 2025 16:14:24 -0500 Subject: avr: __udivmod(h|q)i4 --- .../compiler-builtins/src/int/udiv.rs | 86 ++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs index a5c16040a52..f18537b006b 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs @@ -43,6 +43,92 @@ intrinsics! { ((rem as u64) << 32) | (div as u64) } + + #[unsafe(naked)] + pub unsafe extern "C" fn __udivmodqi4() { + // compute unsigned 8-bit `n / d` and `n % d`. + // + // Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function. + // Inputs: + // R24: dividend + // R22: divisor + // Outputs: + // R24: quotient (dividend / divisor) + // R25: remainder (dividend % divisor) + // Clobbers: + // R23: loop counter + core::arch::naked_asm!( + // This assembly routine implements the [long division](https://en.wikipedia.org/wiki/Division_algorithm#Long_division) algorithm. + // Bits shift out of the dividend and into the quotient, so R24 is used for both. + "clr R25", // remainder = 0 + + "ldi R23, 8", // for each bit + "1:", + "lsl R24", // shift the dividend MSb + "rol R25", // into the remainder LSb + + "cp R25, R22", // if remainder >= divisor + "brlo 2f", + "sub R25, R22", // remainder -= divisor + "sbr R24, 1", // quotient |= 1 + "2:", + + "dec R23", // end loop + "brne 1b", + "ret", + ); + } + + #[unsafe(naked)] + pub unsafe extern "C" fn __udivmodhi4() { + // compute unsigned 16-bit `n / d` and `n % d`. + // + // Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function. + // Inputs: + // R24: dividend [low] + // R25: dividend [high] + // R22: divisor [low] + // R23: divisor [high] + // Outputs: + // R22: quotient [low] (dividend / divisor) + // R23: quotient [high] + // R24: remainder [low] (dividend % divisor) + // R25: remainder [high] + // Clobbers: + // R21: loop counter + // R26: divisor [low] + // R27: divisor [high] + core::arch::naked_asm!( + // This assembly routine implements the [long division](https://en.wikipedia.org/wiki/Division_algorithm#Long_division) algorithm. + // Bits shift out of the dividend and into the quotient, so R24+R25 are used for both. + "mov R26, R22", // move divisor to make room for quotient + "mov R27, R23", + "mov R22, R24", // move dividend to output location (becomes quotient) + "mov R23, R25", + "clr R24", // remainder = 0 + "clr R25", + + "ldi R21, 16", // for each bit + "1:", + "lsl R22", // shift the dividend MSb + "rol R23", + "rol R24", // into the remainder LSb + "rol R25", + + "cp R24, R26", // if remainder >= divisor + "cpc R25, R27", + "brlo 2f", + "sub R24, R26", // remainder -= divisor + "sbc R25, R27", + "sbr R22, 1", // quotient |= 1 + "2:", + + "dec R21", // end loop + "brne 1b", + "ret", + ); + } + } intrinsics! { -- cgit 1.4.1-3-g733a5 From 92725845336bf8dc4ceb1c2e5f04a6839b6dc5f5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 17 Apr 2025 08:19:50 +0000 Subject: Replace the `bl!` macro with `asm_sym` `bl!` is being used to add a leading underscore on Apple targets. `asm_sym` has been around since 2022 and handles platform-specific symbol names automatically, so make use of this instead. I have verified that `armv7s-apple-ios` still builds correctly. --- .../compiler-builtins/compiler-builtins/src/arm.rs | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/arm.rs b/library/compiler-builtins/compiler-builtins/src/arm.rs index 878bb8c4331..7859b51207c 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm.rs @@ -1,20 +1,16 @@ #![cfg(not(feature = "no-asm"))] -#![allow(unused_imports)] -use core::intrinsics; - -// Apple symbols have a leading underscore. -#[cfg(target_vendor = "apple")] -macro_rules! bl { - ($func:literal) => { - concat!("bl _", $func) - }; +// Interfaces used by naked trampolines. +extern "C" { + fn __udivmodsi4(a: u32, b: u32, rem: *mut u32) -> u32; + fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64; + fn __divmoddi4(a: i64, b: i64, rem: *mut i64) -> i64; } -#[cfg(not(target_vendor = "apple"))] -macro_rules! bl { - ($func:literal) => { - concat!("bl ", $func) - }; + +extern "aapcs" { + // AAPCS is not always the correct ABI for these intrinsics, but we only use this to + // forward another `__aeabi_` call so it doesn't matter. + fn __aeabi_idiv(a: i32, b: i32) -> i32; } intrinsics! { @@ -27,10 +23,11 @@ intrinsics! { "push {{lr}}", "sub sp, sp, #4", "mov r2, sp", - bl!("__udivmodsi4"), + "bl {trampoline}", "ldr r1, [sp]", "add sp, sp, #4", "pop {{pc}}", + trampoline = sym crate::arm::__udivmodsi4 ); } @@ -41,11 +38,12 @@ intrinsics! { "sub sp, sp, #16", "add r4, sp, #8", "str r4, [sp]", - bl!("__udivmoddi4"), + "bl {trampoline}", "ldr r2, [sp, #8]", "ldr r3, [sp, #12]", "add sp, sp, #16", "pop {{r4, pc}}", + trampoline = sym crate::arm::__udivmoddi4 ); } @@ -53,11 +51,12 @@ intrinsics! { pub unsafe extern "C" fn __aeabi_idivmod() { core::arch::naked_asm!( "push {{r0, r1, r4, lr}}", - bl!("__aeabi_idiv"), + "bl {trampoline}", "pop {{r1, r2}}", "muls r2, r2, r0", "subs r1, r1, r2", "pop {{r4, pc}}", + trampoline = sym crate::arm::__aeabi_idiv, ); } @@ -68,11 +67,12 @@ intrinsics! { "sub sp, sp, #16", "add r4, sp, #8", "str r4, [sp]", - bl!("__divmoddi4"), + "bl {trampoline}", "ldr r2, [sp, #8]", "ldr r3, [sp, #12]", "add sp, sp, #16", "pop {{r4, pc}}", + trampoline = sym crate::arm::__divmoddi4, ); } -- cgit 1.4.1-3-g733a5 From ec74a38b250387fb67acbb1cecca4f4c81b966cb Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 17 Apr 2025 12:27:35 +0200 Subject: use `#[cfg(bootstrap)]` for rustc sync --- library/compiler-builtins/compiler-builtins/Cargo.toml | 3 +++ library/compiler-builtins/compiler-builtins/src/macros.rs | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index bd17885a109..f5bbf4cd4d5 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -70,3 +70,6 @@ rustc-dep-of-std = ['compiler-builtins', 'core'] # This makes certain traits and function specializations public that # are not normally public but are required by the `testcrate` public-test-deps = [] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)'] } diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index 13c8ecee32d..b83414ce2b7 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -433,6 +433,17 @@ macro_rules! intrinsics { ) => ( // `#[naked]` definitions are referenced by other places, so we can't use `cfg` like the others pub mod $name { + // FIXME: when bootstrap supports `#[unsafe(naked)]` this duplication can be removed + #[cfg(bootstrap)] + #[naked] + $(#[$($attr)*])* + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + + #[cfg(not(bootstrap))] #[unsafe(naked)] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -- cgit 1.4.1-3-g733a5 From 3ea9f849d54b6fee2bdacea04cad4d15d68b3fb5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Apr 2025 18:57:23 +0000 Subject: chore: release v0.1.155 --- library/compiler-builtins/compiler-builtins/CHANGELOG.md | 8 ++++++++ library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index 1dbccf38ec6..9916f2986e9 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.155](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.154...compiler_builtins-v0.1.155) - 2025-04-17 + +### Other + +- use `#[cfg(bootstrap)]` for rustc sync +- Replace the `bl!` macro with `asm_sym` +- __udivmod(h|q)i4 + ## [0.1.154](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.153...compiler_builtins-v0.1.154) - 2025-04-16 ### Other diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index f5bbf4cd4d5..eb5b2b9cc88 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.154" +version = "0.1.155" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "../README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From f88b7c8a46c6c129696a6c42d126388ec02ed0bf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 00:18:12 +0000 Subject: Add `NEG_NAN` to `Float` Introduce a constant representing NaN with a negative sign bit for use with testing. There isn't really any guarantee that `F::NAN` is positive but in practice it always is, which is good enough for testing purposes. --- .../libm/crates/libm-test/src/f8_impl.rs | 1 + .../libm/src/math/support/float_traits.rs | 25 ++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index 6772e092caa..ddb7bf90e7f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -30,6 +30,7 @@ impl Float for f8 { const INFINITY: Self = Self(0b0_1111_000); const NEG_INFINITY: Self = Self(0b1_1111_000); const NAN: Self = Self(0b0_1111_100); + const NEG_NAN: Self = Self(0b1_1111_100); const MIN_POSITIVE_NORMAL: Self = Self(1 << Self::SIG_BITS); // FIXME: incorrect values const EPSILON: Self = Self::ZERO; diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 96c209c852b..fac10483237 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -34,6 +34,7 @@ pub trait Float: const INFINITY: Self; const NEG_INFINITY: Self; const NAN: Self; + const NEG_NAN: Self; const MAX: Self; const MIN: Self; const EPSILON: Self; @@ -187,6 +188,7 @@ macro_rules! float_impl { $bits:expr, $significand_bits:expr, $from_bits:path, + $to_bits:path, $fma_fn:ident, $fma_intrinsic:ident ) => { @@ -201,6 +203,9 @@ macro_rules! float_impl { const INFINITY: Self = Self::INFINITY; const NEG_INFINITY: Self = Self::NEG_INFINITY; const NAN: Self = Self::NAN; + // NAN isn't guaranteed to be positive but it usually is. We only use this for + // tests. + const NEG_NAN: Self = $from_bits($to_bits(Self::NAN) | Self::SIGN_MASK); const MAX: Self = -Self::MIN; // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS)); @@ -275,11 +280,11 @@ macro_rules! float_impl { } #[cfg(f16_enabled)] -float_impl!(f16, u16, i16, 16, 10, f16::from_bits, fmaf16, fmaf16); -float_impl!(f32, u32, i32, 32, 23, f32_from_bits, fmaf, fmaf32); -float_impl!(f64, u64, i64, 64, 52, f64_from_bits, fma, fmaf64); +float_impl!(f16, u16, i16, 16, 10, f16::from_bits, f16::to_bits, fmaf16, fmaf16); +float_impl!(f32, u32, i32, 32, 23, f32_from_bits, f32_to_bits, fmaf, fmaf32); +float_impl!(f64, u64, i64, 64, 52, f64_from_bits, f64_to_bits, fma, fmaf64); #[cfg(f128_enabled)] -float_impl!(f128, u128, i128, 128, 112, f128::from_bits, fmaf128, fmaf128); +float_impl!(f128, u128, i128, 128, 112, f128::from_bits, f128::to_bits, fmaf128, fmaf128); /* FIXME(msrv): vendor some things that are not const stable at our MSRV */ @@ -289,12 +294,24 @@ pub const fn f32_from_bits(bits: u32) -> f32 { unsafe { mem::transmute::(bits) } } +/// `f32::to_bits` +pub const fn f32_to_bits(x: f32) -> u32 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(x) } +} + /// `f64::from_bits` pub const fn f64_from_bits(bits: u64) -> f64 { // SAFETY: POD cast with no preconditions unsafe { mem::transmute::(bits) } } +/// `f64::to_bits` +pub const fn f64_to_bits(x: f64) -> u64 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(x) } +} + /// Trait for floats twice the bit width of another integer. pub trait DFloat: Float { /// Float that is half the bit width of the floatthis trait is implemented for. -- cgit 1.4.1-3-g733a5 From 579627ddd58a620cfc7eeef65afdb7a5cae3c58b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 00:22:38 +0000 Subject: Make `assert_biteq!` not rely on having `Int` in scope --- library/compiler-builtins/libm/src/math/generic/fmax.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fmaximum.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fmin.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fminimum.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fminimum_num.rs | 2 +- library/compiler-builtins/libm/src/math/generic/rint.rs | 2 +- library/compiler-builtins/libm/src/math/generic/scalbn.rs | 1 - library/compiler-builtins/libm/src/math/support/macros.rs | 3 ++- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs index 32613a46b93..039ffce9ff5 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmax.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmax.rs @@ -26,7 +26,7 @@ pub fn fmax(x: F, y: F) -> F { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Int}; + use crate::support::Hexf; fn spec_test() { let cases = [ diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs index 5f653ce94e2..b0fde88e8b4 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs @@ -29,7 +29,7 @@ pub fn fmaximum(x: F, y: F) -> F { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Int}; + use crate::support::Hexf; fn spec_test() { let cases = [ diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs index 22466012392..68b03109d7b 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs @@ -28,7 +28,7 @@ pub fn fmaximum_num(x: F, y: F) -> F { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Int}; + use crate::support::Hexf; fn spec_test() { let cases = [ diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs index 5cc33e904ed..2aa7f6af7a0 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmin.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmin.rs @@ -25,7 +25,7 @@ pub fn fmin(x: F, y: F) -> F { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Int}; + use crate::support::Hexf; fn spec_test() { let cases = [ diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs index f566d9631d3..e01c886464f 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum.rs @@ -29,7 +29,7 @@ pub fn fminimum(x: F, y: F) -> F { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Int}; + use crate::support::Hexf; fn spec_test() { let cases = [ diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs index e58a585c329..3e97b893b31 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs @@ -28,7 +28,7 @@ pub fn fminimum_num(x: F, y: F) -> F { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Int}; + use crate::support::Hexf; fn spec_test() { let cases = [ diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index 2f8b2b36591..45d2f313866 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -43,7 +43,7 @@ pub fn rint_round(x: F, _round: Round) -> FpResult { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Int, Status}; + use crate::support::{Hexf, Status}; fn spec_test(cases: &[(F, F, Status)]) { let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs index 5ba7f2ab2d5..aaa243933d4 100644 --- a/library/compiler-builtins/libm/src/math/generic/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs @@ -121,7 +121,6 @@ where #[cfg(test)] mod tests { - use super::super::super::Int; use super::*; // Tests against N3220 diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index c80e7751159..0b72db0e46e 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -137,9 +137,10 @@ macro_rules! hf128 { #[cfg(test)] macro_rules! assert_biteq { ($left:expr, $right:expr, $($tt:tt)*) => {{ + use $crate::support::Int; let l = $left; let r = $right; - let bits = (l.to_bits() - l.to_bits()).leading_zeros(); // hack to get the width from the value + let bits = Int::leading_zeros(l.to_bits() - l.to_bits()); // hack to get the width from the value assert!( l.biteq(r), "{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", -- cgit 1.4.1-3-g733a5 From a15c8c9a3d51cc917c09ba4be59f27ac17dd8664 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 00:22:21 +0000 Subject: Combine the source files for more generic implementations Splitting into different source files by float size doesn't have any benefit when the only content is a small function that forwards to the generic implementation. Combine the source files for all width versions of: * ceil * copysign * fabs * fdim * floor * fmaximum * fmaximum_num * fminimum * fminimum_num * ldexp * scalbn * sqrt * truc fmod is excluded to avoid conflicts with an open PR. As part of this change move unit tests out of the generic module, instead testing the type-specific functions (e.g. `ceilf16` rather than `ceil::()`). This ensures that unit tests are validating whatever we expose, such as arch-specific implementations via `select_implementation!`, which would otherwise be skipped. (They are still covered by integration tests). --- .../libm/etc/function-definitions.json | 60 ++++++------ library/compiler-builtins/libm/src/math/acosf.rs | 2 +- library/compiler-builtins/libm/src/math/asinf.rs | 4 +- library/compiler-builtins/libm/src/math/ceil.rs | 32 +++++++ library/compiler-builtins/libm/src/math/ceilf.rs | 13 --- .../compiler-builtins/libm/src/math/ceilf128.rs | 7 -- library/compiler-builtins/libm/src/math/ceilf16.rs | 7 -- .../compiler-builtins/libm/src/math/copysign.rs | 80 ++++++++++++++++ .../compiler-builtins/libm/src/math/copysignf.rs | 8 -- .../libm/src/math/copysignf128.rs | 8 -- .../compiler-builtins/libm/src/math/copysignf16.rs | 8 -- library/compiler-builtins/libm/src/math/fabs.rs | 103 ++++++++++++++++++--- library/compiler-builtins/libm/src/math/fabsf.rs | 39 -------- .../compiler-builtins/libm/src/math/fabsf128.rs | 31 ------- library/compiler-builtins/libm/src/math/fabsf16.rs | 31 ------- library/compiler-builtins/libm/src/math/fdim.rs | 41 ++++++++ library/compiler-builtins/libm/src/math/fdimf.rs | 12 --- .../compiler-builtins/libm/src/math/fdimf128.rs | 12 --- library/compiler-builtins/libm/src/math/fdimf16.rs | 12 --- library/compiler-builtins/libm/src/math/floor.rs | 32 +++++++ library/compiler-builtins/libm/src/math/floorf.rs | 13 --- .../compiler-builtins/libm/src/math/floorf128.rs | 7 -- .../compiler-builtins/libm/src/math/floorf16.rs | 7 -- .../compiler-builtins/libm/src/math/fmin_fmax.rs | 92 ++++++++++++++++++ .../libm/src/math/fminimum_fmaximum.rs | 96 +++++++++++++++++++ .../libm/src/math/fminimum_fmaximum_num.rs | 96 +++++++++++++++++++ .../libm/src/math/generic/fmax.rs | 49 ---------- .../libm/src/math/generic/fmaximum.rs | 51 ---------- .../libm/src/math/generic/fmaximum_num.rs | 51 ---------- .../libm/src/math/generic/fmin.rs | 49 ---------- .../libm/src/math/generic/fminimum.rs | 51 ---------- .../libm/src/math/generic/fminimum_num.rs | 51 ---------- .../libm/src/math/generic/scalbn.rs | 65 ------------- library/compiler-builtins/libm/src/math/ldexp.rs | 17 ++++ library/compiler-builtins/libm/src/math/ldexpf.rs | 4 - .../compiler-builtins/libm/src/math/ldexpf128.rs | 4 - .../compiler-builtins/libm/src/math/ldexpf16.rs | 4 - library/compiler-builtins/libm/src/math/mod.rs | 100 ++++++-------------- library/compiler-builtins/libm/src/math/round.rs | 20 ++++ library/compiler-builtins/libm/src/math/roundf.rs | 5 - .../compiler-builtins/libm/src/math/roundf128.rs | 5 - .../compiler-builtins/libm/src/math/roundf16.rs | 5 - library/compiler-builtins/libm/src/math/scalbn.rs | 83 +++++++++++++++++ library/compiler-builtins/libm/src/math/scalbnf.rs | 4 - .../compiler-builtins/libm/src/math/scalbnf128.rs | 4 - .../compiler-builtins/libm/src/math/scalbnf16.rs | 4 - library/compiler-builtins/libm/src/math/sqrt.rs | 36 +++++++ library/compiler-builtins/libm/src/math/sqrtf.rs | 15 --- .../compiler-builtins/libm/src/math/sqrtf128.rs | 5 - library/compiler-builtins/libm/src/math/sqrtf16.rs | 11 --- library/compiler-builtins/libm/src/math/trunc.rs | 40 ++++++++ library/compiler-builtins/libm/src/math/truncf.rs | 23 ----- .../compiler-builtins/libm/src/math/truncf128.rs | 7 -- .../compiler-builtins/libm/src/math/truncf16.rs | 7 -- 54 files changed, 819 insertions(+), 804 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/ceilf.rs delete mode 100644 library/compiler-builtins/libm/src/math/ceilf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/ceilf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/copysignf.rs delete mode 100644 library/compiler-builtins/libm/src/math/copysignf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/copysignf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/fabsf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fabsf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fabsf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/fdimf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fdimf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fdimf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/floorf.rs delete mode 100644 library/compiler-builtins/libm/src/math/floorf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/floorf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/ldexpf.rs delete mode 100644 library/compiler-builtins/libm/src/math/ldexpf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/ldexpf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundf.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/scalbnf.rs delete mode 100644 library/compiler-builtins/libm/src/math/scalbnf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/scalbnf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/sqrtf.rs delete mode 100644 library/compiler-builtins/libm/src/math/sqrtf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/sqrtf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/truncf.rs delete mode 100644 library/compiler-builtins/libm/src/math/truncf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/truncf16.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index bca58402f4e..801e74b22a5 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -108,21 +108,21 @@ "ceilf": { "sources": [ "src/math/arch/wasm32.rs", - "src/math/ceilf.rs", + "src/math/ceil.rs", "src/math/generic/ceil.rs" ], "type": "f32" }, "ceilf128": { "sources": [ - "src/math/ceilf128.rs", + "src/math/ceil.rs", "src/math/generic/ceil.rs" ], "type": "f128" }, "ceilf16": { "sources": [ - "src/math/ceilf16.rs", + "src/math/ceil.rs", "src/math/generic/ceil.rs" ], "type": "f16" @@ -136,21 +136,21 @@ }, "copysignf": { "sources": [ - "src/math/copysignf.rs", + "src/math/copysign.rs", "src/math/generic/copysign.rs" ], "type": "f32" }, "copysignf128": { "sources": [ - "src/math/copysignf128.rs", + "src/math/copysign.rs", "src/math/generic/copysign.rs" ], "type": "f128" }, "copysignf16": { "sources": [ - "src/math/copysignf16.rs", + "src/math/copysign.rs", "src/math/generic/copysign.rs" ], "type": "f16" @@ -262,21 +262,21 @@ "fabsf": { "sources": [ "src/math/arch/wasm32.rs", - "src/math/fabsf.rs", + "src/math/fabs.rs", "src/math/generic/fabs.rs" ], "type": "f32" }, "fabsf128": { "sources": [ - "src/math/fabsf128.rs", + "src/math/fabs.rs", "src/math/generic/fabs.rs" ], "type": "f128" }, "fabsf16": { "sources": [ - "src/math/fabsf16.rs", + "src/math/fabs.rs", "src/math/generic/fabs.rs" ], "type": "f16" @@ -290,21 +290,21 @@ }, "fdimf": { "sources": [ - "src/math/fdimf.rs", + "src/math/fdim.rs", "src/math/generic/fdim.rs" ], "type": "f32" }, "fdimf128": { "sources": [ - "src/math/fdimf128.rs", + "src/math/fdim.rs", "src/math/generic/fdim.rs" ], "type": "f128" }, "fdimf16": { "sources": [ - "src/math/fdimf16.rs", + "src/math/fdim.rs", "src/math/generic/fdim.rs" ], "type": "f16" @@ -321,21 +321,21 @@ "floorf": { "sources": [ "src/math/arch/wasm32.rs", - "src/math/floorf.rs", + "src/math/floor.rs", "src/math/generic/floor.rs" ], "type": "f32" }, "floorf128": { "sources": [ - "src/math/floorf128.rs", + "src/math/floor.rs", "src/math/generic/floor.rs" ], "type": "f128" }, "floorf16": { "sources": [ - "src/math/floorf16.rs", + "src/math/floor.rs", "src/math/generic/floor.rs" ], "type": "f16" @@ -636,19 +636,19 @@ }, "ldexpf": { "sources": [ - "src/math/ldexpf.rs" + "src/math/ldexp.rs" ], "type": "f32" }, "ldexpf128": { "sources": [ - "src/math/ldexpf128.rs" + "src/math/ldexp.rs" ], "type": "f128" }, "ldexpf16": { "sources": [ - "src/math/ldexpf16.rs" + "src/math/ldexp.rs" ], "type": "f16" }, @@ -847,21 +847,21 @@ "roundf": { "sources": [ "src/math/generic/round.rs", - "src/math/roundf.rs" + "src/math/round.rs" ], "type": "f32" }, "roundf128": { "sources": [ "src/math/generic/round.rs", - "src/math/roundf128.rs" + "src/math/round.rs" ], "type": "f128" }, "roundf16": { "sources": [ "src/math/generic/round.rs", - "src/math/roundf16.rs" + "src/math/round.rs" ], "type": "f16" }, @@ -875,21 +875,21 @@ "scalbnf": { "sources": [ "src/math/generic/scalbn.rs", - "src/math/scalbnf.rs" + "src/math/scalbn.rs" ], "type": "f32" }, "scalbnf128": { "sources": [ "src/math/generic/scalbn.rs", - "src/math/scalbnf128.rs" + "src/math/scalbn.rs" ], "type": "f128" }, "scalbnf16": { "sources": [ "src/math/generic/scalbn.rs", - "src/math/scalbnf16.rs" + "src/math/scalbn.rs" ], "type": "f16" }, @@ -945,14 +945,14 @@ "src/math/arch/i686.rs", "src/math/arch/wasm32.rs", "src/math/generic/sqrt.rs", - "src/math/sqrtf.rs" + "src/math/sqrt.rs" ], "type": "f32" }, "sqrtf128": { "sources": [ "src/math/generic/sqrt.rs", - "src/math/sqrtf128.rs" + "src/math/sqrt.rs" ], "type": "f128" }, @@ -960,7 +960,7 @@ "sources": [ "src/math/arch/aarch64.rs", "src/math/generic/sqrt.rs", - "src/math/sqrtf16.rs" + "src/math/sqrt.rs" ], "type": "f16" }, @@ -1012,21 +1012,21 @@ "sources": [ "src/math/arch/wasm32.rs", "src/math/generic/trunc.rs", - "src/math/truncf.rs" + "src/math/trunc.rs" ], "type": "f32" }, "truncf128": { "sources": [ "src/math/generic/trunc.rs", - "src/math/truncf128.rs" + "src/math/trunc.rs" ], "type": "f128" }, "truncf16": { "sources": [ "src/math/generic/trunc.rs", - "src/math/truncf16.rs" + "src/math/trunc.rs" ], "type": "f16" }, diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index 1a60479e32a..dd88eea5b13 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -13,7 +13,7 @@ * ==================================================== */ -use super::sqrtf::sqrtf; +use super::sqrt::sqrtf; const PIO2_HI: f32 = 1.5707962513e+00; /* 0x3fc90fda */ const PIO2_LO: f32 = 7.5497894159e-08; /* 0x33a22168 */ diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index 0ea49c0767c..ed685556730 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -13,8 +13,8 @@ * ==================================================== */ -use super::fabsf::fabsf; use super::sqrt::sqrt; +use super::support::Float; const PIO2: f64 = 1.570796326794896558e+00; @@ -61,7 +61,7 @@ pub fn asinf(mut x: f32) -> f32 { } /* 1 > |x| >= 0.5 */ - let z = (1. - fabsf(x)) * 0.5; + let z = (1. - Float::abs(x)) * 0.5; let s = sqrt(z as f64); x = (PIO2 - 2. * (s + s * (r(z) as f64))) as f32; if (hx >> 31) != 0 { -x } else { x } diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 535f434ac24..4e103545727 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -1,3 +1,26 @@ +/// Ceil (f16) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf16(x: f16) -> f16 { + super::generic::ceil(x) +} + +/// Ceil (f32) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf(x: f32) -> f32 { + select_implementation! { + name: ceilf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::ceil(x) +} + /// Ceil (f64) /// /// Finds the nearest integer greater than or equal to `x`. @@ -12,3 +35,12 @@ pub fn ceil(x: f64) -> f64 { super::generic::ceil(x) } + +/// Ceil (f128) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf128(x: f128) -> f128 { + super::generic::ceil(x) +} diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs deleted file mode 100644 index 66d44189c92..00000000000 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ /dev/null @@ -1,13 +0,0 @@ -/// Ceil (f32) -/// -/// Finds the nearest integer greater than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceilf(x: f32) -> f32 { - select_implementation! { - name: ceilf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::ceil(x) -} diff --git a/library/compiler-builtins/libm/src/math/ceilf128.rs b/library/compiler-builtins/libm/src/math/ceilf128.rs deleted file mode 100644 index 89980858eb5..00000000000 --- a/library/compiler-builtins/libm/src/math/ceilf128.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Ceil (f128) -/// -/// Finds the nearest integer greater than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceilf128(x: f128) -> f128 { - super::generic::ceil(x) -} diff --git a/library/compiler-builtins/libm/src/math/ceilf16.rs b/library/compiler-builtins/libm/src/math/ceilf16.rs deleted file mode 100644 index 2af67eff0d2..00000000000 --- a/library/compiler-builtins/libm/src/math/ceilf16.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Ceil (f16) -/// -/// Finds the nearest integer greater than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceilf16(x: f16) -> f16 { - super::generic::ceil(x) -} diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs index 552bf3975b8..d2a86e7fd54 100644 --- a/library/compiler-builtins/libm/src/math/copysign.rs +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -1,3 +1,22 @@ +/// Sign of Y, magnitude of X (f16) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf16(x: f16, y: f16) -> f16 { + super::generic::copysign(x, y) +} + +/// Sign of Y, magnitude of X (f32) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf(x: f32, y: f32) -> f32 { + super::generic::copysign(x, y) +} + /// Sign of Y, magnitude of X (f64) /// /// Constructs a number with the magnitude (absolute value) of its @@ -6,3 +25,64 @@ pub fn copysign(x: f64, y: f64) -> f64 { super::generic::copysign(x, y) } + +/// Sign of Y, magnitude of X (f128) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf128(x: f128, y: f128) -> f128 { + super::generic::copysign(x, y) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::Float; + + fn spec_test(f: impl Fn(F, F) -> F) { + assert_biteq!(f(F::ZERO, F::ZERO), F::ZERO); + assert_biteq!(f(F::NEG_ZERO, F::ZERO), F::ZERO); + assert_biteq!(f(F::ZERO, F::NEG_ZERO), F::NEG_ZERO); + assert_biteq!(f(F::NEG_ZERO, F::NEG_ZERO), F::NEG_ZERO); + + assert_biteq!(f(F::ONE, F::ONE), F::ONE); + assert_biteq!(f(F::NEG_ONE, F::ONE), F::ONE); + assert_biteq!(f(F::ONE, F::NEG_ONE), F::NEG_ONE); + assert_biteq!(f(F::NEG_ONE, F::NEG_ONE), F::NEG_ONE); + + assert_biteq!(f(F::INFINITY, F::INFINITY), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY, F::INFINITY), F::INFINITY); + assert_biteq!(f(F::INFINITY, F::NEG_INFINITY), F::NEG_INFINITY); + assert_biteq!(f(F::NEG_INFINITY, F::NEG_INFINITY), F::NEG_INFINITY); + + // Not required but we expect it + assert_biteq!(f(F::NAN, F::NAN), F::NAN); + assert_biteq!(f(F::NEG_NAN, F::NAN), F::NAN); + assert_biteq!(f(F::NAN, F::NEG_NAN), F::NEG_NAN); + assert_biteq!(f(F::NEG_NAN, F::NEG_NAN), F::NEG_NAN); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(copysignf16); + } + + #[test] + fn spec_tests_f32() { + spec_test::(copysignf); + } + + #[test] + fn spec_tests_f64() { + spec_test::(copysign); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(copysignf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs deleted file mode 100644 index 8b9bed4c0c4..00000000000 --- a/library/compiler-builtins/libm/src/math/copysignf.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f32) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf(x: f32, y: f32) -> f32 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/copysignf128.rs b/library/compiler-builtins/libm/src/math/copysignf128.rs deleted file mode 100644 index 7bd81d42b2e..00000000000 --- a/library/compiler-builtins/libm/src/math/copysignf128.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f128) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf128(x: f128, y: f128) -> f128 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/copysignf16.rs b/library/compiler-builtins/libm/src/math/copysignf16.rs deleted file mode 100644 index 82065868601..00000000000 --- a/library/compiler-builtins/libm/src/math/copysignf16.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f16) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf16(x: f16, y: f16) -> f16 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 22867fab056..0050a309fee 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -1,3 +1,28 @@ +/// Absolute value (magnitude) (f16) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf16(x: f16) -> f16 { + super::generic::fabs(x) +} + +/// Absolute value (magnitude) (f32) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf(x: f32) -> f32 { + select_implementation! { + name: fabsf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::fabs(x) +} + /// Absolute value (magnitude) (f64) /// /// Calculates the absolute value (magnitude) of the argument `x`, @@ -13,25 +38,79 @@ pub fn fabs(x: f64) -> f64 { super::generic::fabs(x) } +/// Absolute value (magnitude) (f128) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf128(x: f128) -> f128 { + super::generic::fabs(x) +} + #[cfg(test)] mod tests { use super::*; + use crate::support::Float; + + /// Based on https://en.cppreference.com/w/cpp/numeric/math/fabs + fn spec_test(f: impl Fn(F) -> F) { + assert_biteq!(f(F::ZERO), F::ZERO); + assert_biteq!(f(F::NEG_ZERO), F::ZERO); + assert_biteq!(f(F::INFINITY), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY), F::INFINITY); + assert!(f(F::NAN).is_nan()); + + // Not spec rewquired but we expect it + assert!(f(F::NAN).is_sign_positive()); + assert!(f(F::from_bits(F::NAN.to_bits() | F::SIGN_MASK)).is_sign_positive()); + } + + #[test] + #[cfg(f16_enabled)] + fn sanity_check_f16() { + assert_eq!(fabsf16(-1.0f16), 1.0); + assert_eq!(fabsf16(2.8f16), 2.8); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(fabsf16); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(fabsf(-1.0f32), 1.0); + assert_eq!(fabsf(2.8f32), 2.8); + } + + #[test] + fn spec_tests_f32() { + spec_test::(fabsf); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(fabs(-1.0f64), 1.0); + assert_eq!(fabs(2.8f64), 2.8); + } + + #[test] + fn spec_tests_f64() { + spec_test::(fabs); + } #[test] - fn sanity_check() { - assert_eq!(fabs(-1.0), 1.0); - assert_eq!(fabs(2.8), 2.8); + #[cfg(f128_enabled)] + fn sanity_check_f128() { + assert_eq!(fabsf128(-1.0f128), 1.0); + assert_eq!(fabsf128(2.8f128), 2.8); } - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs #[test] - fn spec_tests() { - assert!(fabs(f64::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabs(f), 0.0); - } - for f in [f64::INFINITY, f64::NEG_INFINITY].iter().copied() { - assert_eq!(fabs(f), f64::INFINITY); - } + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(fabsf128); } } diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs deleted file mode 100644 index e5820a26c52..00000000000 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ /dev/null @@ -1,39 +0,0 @@ -/// Absolute value (magnitude) (f32) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf(x: f32) -> f32 { - select_implementation! { - name: fabsf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::fabs(x) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf(-1.0), 1.0); - assert_eq!(fabsf(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf(f32::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf(f), 0.0); - } - for f in [f32::INFINITY, f32::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf(f), f32::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/fabsf128.rs b/library/compiler-builtins/libm/src/math/fabsf128.rs deleted file mode 100644 index 46429ca4940..00000000000 --- a/library/compiler-builtins/libm/src/math/fabsf128.rs +++ /dev/null @@ -1,31 +0,0 @@ -/// Absolute value (magnitude) (f128) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf128(x: f128) -> f128 { - super::generic::fabs(x) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf128(-1.0), 1.0); - assert_eq!(fabsf128(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf128(f128::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf128(f), 0.0); - } - for f in [f128::INFINITY, f128::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf128(f), f128::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/fabsf16.rs b/library/compiler-builtins/libm/src/math/fabsf16.rs deleted file mode 100644 index eee42ac6a3c..00000000000 --- a/library/compiler-builtins/libm/src/math/fabsf16.rs +++ /dev/null @@ -1,31 +0,0 @@ -/// Absolute value (magnitude) (f16) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf16(x: f16) -> f16 { - super::generic::fabs(x) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf16(-1.0), 1.0); - assert_eq!(fabsf16(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf16(f16::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf16(f), 0.0); - } - for f in [f16::INFINITY, f16::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf16(f), f16::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index 10ffa2881dd..082c5478b2a 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -1,3 +1,30 @@ +/// Positive difference (f16) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf16(x: f16, y: f16) -> f16 { + super::generic::fdim(x, y) +} + +/// Positive difference (f32) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf(x: f32, y: f32) -> f32 { + super::generic::fdim(x, y) +} + /// Positive difference (f64) /// /// Determines the positive difference between arguments, returning: @@ -10,3 +37,17 @@ pub fn fdim(x: f64, y: f64) -> f64 { super::generic::fdim(x, y) } + +/// Positive difference (f128) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf128(x: f128, y: f128) -> f128 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs deleted file mode 100644 index 367ef517c63..00000000000 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f32) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf(x: f32, y: f32) -> f32 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fdimf128.rs b/library/compiler-builtins/libm/src/math/fdimf128.rs deleted file mode 100644 index 6f3d1d0ff1d..00000000000 --- a/library/compiler-builtins/libm/src/math/fdimf128.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f128) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf128(x: f128, y: f128) -> f128 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fdimf16.rs b/library/compiler-builtins/libm/src/math/fdimf16.rs deleted file mode 100644 index 37bd6885817..00000000000 --- a/library/compiler-builtins/libm/src/math/fdimf16.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f16) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf16(x: f16, y: f16) -> f16 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index b4f02abc491..3c5eab101d1 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -1,3 +1,12 @@ +/// Floor (f16) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf16(x: f16) -> f16 { + return super::generic::floor(x); +} + /// Floor (f64) /// /// Finds the nearest integer less than or equal to `x`. @@ -12,3 +21,26 @@ pub fn floor(x: f64) -> f64 { return super::generic::floor(x); } + +/// Floor (f32) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf(x: f32) -> f32 { + select_implementation! { + name: floorf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + return super::generic::floor(x); +} + +/// Floor (f128) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf128(x: f128) -> f128 { + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs deleted file mode 100644 index 16957b7f355..00000000000 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ /dev/null @@ -1,13 +0,0 @@ -/// Floor (f32) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf(x: f32) -> f32 { - select_implementation! { - name: floorf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/src/math/floorf128.rs b/library/compiler-builtins/libm/src/math/floorf128.rs deleted file mode 100644 index 9a9fe415115..00000000000 --- a/library/compiler-builtins/libm/src/math/floorf128.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Floor (f128) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf128(x: f128) -> f128 { - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/src/math/floorf16.rs b/library/compiler-builtins/libm/src/math/floorf16.rs deleted file mode 100644 index f9b868e0410..00000000000 --- a/library/compiler-builtins/libm/src/math/floorf16.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Floor (f16) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf16(x: f16) -> f16 { - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/src/math/fmin_fmax.rs index 4f9136dbbcd..2947b783e2f 100644 --- a/library/compiler-builtins/libm/src/math/fmin_fmax.rs +++ b/library/compiler-builtins/libm/src/math/fmin_fmax.rs @@ -73,3 +73,95 @@ pub fn fmax(x: f64, y: f64) -> f64 { pub fn fmaxf128(x: f128, y: f128) -> f128 { super::generic::fmax(x, y) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, Hexf}; + + fn fmin_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmin_spec_tests_f16() { + fmin_spec_test::(fminf16); + } + + #[test] + fn fmin_spec_tests_f32() { + fmin_spec_test::(fminf); + } + + #[test] + fn fmin_spec_tests_f64() { + fmin_spec_test::(fmin); + } + + #[test] + #[cfg(f128_enabled)] + fn fmin_spec_tests_f128() { + fmin_spec_test::(fminf128); + } + + fn fmax_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmax_spec_tests_f16() { + fmax_spec_test::(fmaxf16); + } + + #[test] + fn fmax_spec_tests_f32() { + fmax_spec_test::(fmaxf); + } + + #[test] + fn fmax_spec_tests_f64() { + fmax_spec_test::(fmax); + } + + #[test] + #[cfg(f128_enabled)] + fn fmax_spec_tests_f128() { + fmax_spec_test::(fmaxf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs index fd3c5ed1039..b7999e27392 100644 --- a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs @@ -65,3 +65,99 @@ pub fn fmaximum(x: f64, y: f64) -> f64 { pub fn fmaximumf128(x: f128, y: f128) -> f128 { super::generic::fmaximum(x, y) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, Hexf}; + + fn fminimum_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::NAN), + (F::ZERO, F::NAN, F::NAN), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fminimum_spec_tests_f16() { + fminimum_spec_test::(fminimumf16); + } + + #[test] + fn fminimum_spec_tests_f32() { + fminimum_spec_test::(fminimumf); + } + + #[test] + fn fminimum_spec_tests_f64() { + fminimum_spec_test::(fminimum); + } + + #[test] + #[cfg(f128_enabled)] + fn fminimum_spec_tests_f128() { + fminimum_spec_test::(fminimumf128); + } + + fn fmaximum_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::NAN), + (F::ZERO, F::NAN, F::NAN), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::ZERO), + (F::NEG_ZERO, F::ZERO, F::ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmaximum_spec_tests_f16() { + fmaximum_spec_test::(fmaximumf16); + } + + #[test] + fn fmaximum_spec_tests_f32() { + fmaximum_spec_test::(fmaximumf); + } + + #[test] + fn fmaximum_spec_tests_f64() { + fmaximum_spec_test::(fmaximum); + } + + #[test] + #[cfg(f128_enabled)] + fn fmaximum_spec_tests_f128() { + fmaximum_spec_test::(fmaximumf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs index 640ddfc9b66..180d21f72b7 100644 --- a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs @@ -65,3 +65,99 @@ pub fn fmaximum_num(x: f64, y: f64) -> f64 { pub fn fmaximum_numf128(x: f128, y: f128) -> f128 { super::generic::fmaximum_num(x, y) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, Hexf}; + + fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fminimum_num_spec_tests_f16() { + fminimum_num_spec_test::(fminimum_numf16); + } + + #[test] + fn fminimum_num_spec_tests_f32() { + fminimum_num_spec_test::(fminimum_numf); + } + + #[test] + fn fminimum_num_spec_tests_f64() { + fminimum_num_spec_test::(fminimum_num); + } + + #[test] + #[cfg(f128_enabled)] + fn fminimum_num_spec_tests_f128() { + fminimum_num_spec_test::(fminimum_numf128); + } + + fn fmaximum_num_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::ZERO), + (F::NEG_ZERO, F::ZERO, F::ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmaximum_num_spec_tests_f16() { + fmaximum_num_spec_test::(fmaximum_numf16); + } + + #[test] + fn fmaximum_num_spec_tests_f32() { + fmaximum_num_spec_test::(fmaximum_numf); + } + + #[test] + fn fmaximum_num_spec_tests_f64() { + fmaximum_num_spec_test::(fmaximum_num); + } + + #[test] + #[cfg(f128_enabled)] + fn fmaximum_num_spec_tests_f128() { + fmaximum_num_spec_test::(fmaximum_numf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs index 039ffce9ff5..29a03110057 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmax.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmax.rs @@ -22,52 +22,3 @@ pub fn fmax(x: F, y: F) -> F { // Canonicalize res * F::ONE } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - fn spec_test() { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), - (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - ]; - - for (x, y, res) in cases { - let val = fmax(x, y); - assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs index b0fde88e8b4..9e8d1739f67 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs @@ -25,54 +25,3 @@ pub fn fmaximum(x: F, y: F) -> F { // Canonicalize res * F::ONE } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - fn spec_test() { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), - (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::NAN), - (F::ZERO, F::NAN, F::NAN), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::ZERO), - (F::NEG_ZERO, F::ZERO, F::ZERO), - ]; - - for (x, y, res) in cases { - let val = fmaximum(x, y); - assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs index 68b03109d7b..756ef5d9f6d 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs @@ -24,54 +24,3 @@ pub fn fmaximum_num(x: F, y: F) -> F { // Canonicalize res * F::ONE } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - fn spec_test() { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), - (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::ZERO), - (F::NEG_ZERO, F::ZERO, F::ZERO), - ]; - - for (x, y, res) in cases { - let val = fmaximum_num(x, y); - assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs index 2aa7f6af7a0..69fbf85a194 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmin.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmin.rs @@ -21,52 +21,3 @@ pub fn fmin(x: F, y: F) -> F { // Canonicalize res * F::ONE } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - fn spec_test() { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), - (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - ]; - - for (x, y, res) in cases { - let val = fmin(x, y); - assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs index e01c886464f..ee5493880eb 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum.rs @@ -25,54 +25,3 @@ pub fn fminimum(x: F, y: F) -> F { // Canonicalize res * F::ONE } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - fn spec_test() { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), - (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::NAN), - (F::ZERO, F::NAN, F::NAN), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), - (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), - ]; - - for (x, y, res) in cases { - let val = fminimum(x, y); - assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs index 3e97b893b31..96661832824 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs @@ -24,54 +24,3 @@ pub fn fminimum_num(x: F, y: F) -> F { // Canonicalize res * F::ONE } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - fn spec_test() { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), - (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), - (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), - ]; - - for (x, y, res) in cases { - let val = fminimum_num(x, y); - assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs index aaa243933d4..b2696e5cc9f 100644 --- a/library/compiler-builtins/libm/src/math/generic/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs @@ -118,68 +118,3 @@ where let scale = F::from_parts(false, (F::EXP_BIAS as i32 + n) as u32, zero); x * scale } - -#[cfg(test)] -mod tests { - use super::*; - - // Tests against N3220 - fn spec_test() - where - u32: CastInto, - F::Int: CastFrom, - F::Int: CastFrom, - { - // `scalbn(±0, n)` returns `±0`. - assert_biteq!(scalbn(F::NEG_ZERO, 10), F::NEG_ZERO); - assert_biteq!(scalbn(F::NEG_ZERO, 0), F::NEG_ZERO); - assert_biteq!(scalbn(F::NEG_ZERO, -10), F::NEG_ZERO); - assert_biteq!(scalbn(F::ZERO, 10), F::ZERO); - assert_biteq!(scalbn(F::ZERO, 0), F::ZERO); - assert_biteq!(scalbn(F::ZERO, -10), F::ZERO); - - // `scalbn(x, 0)` returns `x`. - assert_biteq!(scalbn(F::MIN, 0), F::MIN); - assert_biteq!(scalbn(F::MAX, 0), F::MAX); - assert_biteq!(scalbn(F::INFINITY, 0), F::INFINITY); - assert_biteq!(scalbn(F::NEG_INFINITY, 0), F::NEG_INFINITY); - assert_biteq!(scalbn(F::ZERO, 0), F::ZERO); - assert_biteq!(scalbn(F::NEG_ZERO, 0), F::NEG_ZERO); - - // `scalbn(±∞, n)` returns `±∞`. - assert_biteq!(scalbn(F::INFINITY, 10), F::INFINITY); - assert_biteq!(scalbn(F::INFINITY, -10), F::INFINITY); - assert_biteq!(scalbn(F::NEG_INFINITY, 10), F::NEG_INFINITY); - assert_biteq!(scalbn(F::NEG_INFINITY, -10), F::NEG_INFINITY); - - // NaN should remain NaNs. - assert!(scalbn(F::NAN, 10).is_nan()); - assert!(scalbn(F::NAN, 0).is_nan()); - assert!(scalbn(F::NAN, -10).is_nan()); - assert!(scalbn(-F::NAN, 10).is_nan()); - assert!(scalbn(-F::NAN, 0).is_nan()); - assert!(scalbn(-F::NAN, -10).is_nan()); - } - - #[test] - #[cfg(f16_enabled)] - fn spec_test_f16() { - spec_test::(); - } - - #[test] - fn spec_test_f32() { - spec_test::(); - } - - #[test] - fn spec_test_f64() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_test_f128() { - spec_test::(); - } -} diff --git a/library/compiler-builtins/libm/src/math/ldexp.rs b/library/compiler-builtins/libm/src/math/ldexp.rs index e46242e55b2..24899ba306a 100644 --- a/library/compiler-builtins/libm/src/math/ldexp.rs +++ b/library/compiler-builtins/libm/src/math/ldexp.rs @@ -1,4 +1,21 @@ +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf16(x: f16, n: i32) -> f16 { + super::scalbnf16(x, n) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf(x: f32, n: i32) -> f32 { + super::scalbnf(x, n) +} + #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ldexp(x: f64, n: i32) -> f64 { super::scalbn(x, n) } + +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf128(x: f128, n: i32) -> f128 { + super::scalbnf128(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/ldexpf.rs b/library/compiler-builtins/libm/src/math/ldexpf.rs deleted file mode 100644 index 95b27fc49d2..00000000000 --- a/library/compiler-builtins/libm/src/math/ldexpf.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf(x: f32, n: i32) -> f32 { - super::scalbnf(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/ldexpf128.rs b/library/compiler-builtins/libm/src/math/ldexpf128.rs deleted file mode 100644 index b35277d15fb..00000000000 --- a/library/compiler-builtins/libm/src/math/ldexpf128.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf128(x: f128, n: i32) -> f128 { - super::scalbnf128(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/ldexpf16.rs b/library/compiler-builtins/libm/src/math/ldexpf16.rs deleted file mode 100644 index 8de6cffd699..00000000000 --- a/library/compiler-builtins/libm/src/math/ldexpf16.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf16(x: f16, n: i32) -> f16 { - super::scalbnf16(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 5fc8fa0b3cd..023cf67a306 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -140,9 +140,7 @@ mod atanhf; mod cbrt; mod cbrtf; mod ceil; -mod ceilf; mod copysign; -mod copysignf; mod cos; mod cosf; mod cosh; @@ -158,11 +156,8 @@ mod expf; mod expm1; mod expm1f; mod fabs; -mod fabsf; mod fdim; -mod fdimf; mod floor; -mod floorf; mod fma; mod fma_wide; mod fmin_fmax; @@ -183,7 +178,6 @@ mod j1f; mod jn; mod jnf; mod ldexp; -mod ldexpf; mod lgamma; mod lgamma_r; mod lgammaf; @@ -209,9 +203,7 @@ mod remquof; mod rint; mod round; mod roundeven; -mod roundf; mod scalbn; -mod scalbnf; mod sin; mod sincos; mod sincosf; @@ -219,7 +211,6 @@ mod sinf; mod sinh; mod sinhf; mod sqrt; -mod sqrtf; mod tan; mod tanf; mod tanh; @@ -227,7 +218,6 @@ mod tanhf; mod tgamma; mod tgammaf; mod trunc; -mod truncf; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; @@ -246,10 +236,8 @@ pub use self::atanh::atanh; pub use self::atanhf::atanhf; pub use self::cbrt::cbrt; pub use self::cbrtf::cbrtf; -pub use self::ceil::ceil; -pub use self::ceilf::ceilf; -pub use self::copysign::copysign; -pub use self::copysignf::copysignf; +pub use self::ceil::{ceil, ceilf}; +pub use self::copysign::{copysign, copysignf}; pub use self::cos::cos; pub use self::cosf::cosf; pub use self::cosh::cosh; @@ -264,12 +252,9 @@ pub use self::exp10f::exp10f; pub use self::expf::expf; pub use self::expm1::expm1; pub use self::expm1f::expm1f; -pub use self::fabs::fabs; -pub use self::fabsf::fabsf; -pub use self::fdim::fdim; -pub use self::fdimf::fdimf; -pub use self::floor::floor; -pub use self::floorf::floorf; +pub use self::fabs::{fabs, fabsf}; +pub use self::fdim::{fdim, fdimf}; +pub use self::floor::{floor, floorf}; pub use self::fma::fma; pub use self::fma_wide::fmaf; pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; @@ -289,8 +274,7 @@ pub use self::j1::{j1, y1}; pub use self::j1f::{j1f, y1f}; pub use self::jn::{jn, yn}; pub use self::jnf::{jnf, ynf}; -pub use self::ldexp::ldexp; -pub use self::ldexpf::ldexpf; +pub use self::ldexp::{ldexp, ldexpf}; pub use self::lgamma::lgamma; pub use self::lgamma_r::lgamma_r; pub use self::lgammaf::lgammaf; @@ -314,61 +298,47 @@ pub use self::remainderf::remainderf; pub use self::remquo::remquo; pub use self::remquof::remquof; pub use self::rint::{rint, rintf}; -pub use self::round::round; +pub use self::round::{round, roundf}; pub use self::roundeven::{roundeven, roundevenf}; -pub use self::roundf::roundf; -pub use self::scalbn::scalbn; -pub use self::scalbnf::scalbnf; +pub use self::scalbn::{scalbn, scalbnf}; pub use self::sin::sin; pub use self::sincos::sincos; pub use self::sincosf::sincosf; pub use self::sinf::sinf; pub use self::sinh::sinh; pub use self::sinhf::sinhf; -pub use self::sqrt::sqrt; -pub use self::sqrtf::sqrtf; +pub use self::sqrt::{sqrt, sqrtf}; pub use self::tan::tan; pub use self::tanf::tanf; pub use self::tanh::tanh; pub use self::tanhf::tanhf; pub use self::tgamma::tgamma; pub use self::tgammaf::tgammaf; -pub use self::trunc::trunc; -pub use self::truncf::truncf; +pub use self::trunc::{trunc, truncf}; cfg_if! { if #[cfg(f16_enabled)] { // verify-sorted-start - mod ceilf16; - mod copysignf16; - mod fabsf16; - mod fdimf16; - mod floorf16; mod fmodf16; - mod ldexpf16; - mod roundf16; - mod scalbnf16; - mod sqrtf16; - mod truncf16; // verify-sorted-end // verify-sorted-start - pub use self::ceilf16::ceilf16; - pub use self::copysignf16::copysignf16; - pub use self::fabsf16::fabsf16; - pub use self::fdimf16::fdimf16; - pub use self::floorf16::floorf16; + pub use self::ceil::ceilf16; + pub use self::copysign::copysignf16; + pub use self::fabs::fabsf16; + pub use self::fdim::fdimf16; + pub use self::floor::floorf16; pub use self::fmin_fmax::{fmaxf16, fminf16}; pub use self::fminimum_fmaximum::{fmaximumf16, fminimumf16}; pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16}; pub use self::fmodf16::fmodf16; - pub use self::ldexpf16::ldexpf16; + pub use self::ldexp::ldexpf16; pub use self::rint::rintf16; + pub use self::round::roundf16; pub use self::roundeven::roundevenf16; - pub use self::roundf16::roundf16; - pub use self::scalbnf16::scalbnf16; - pub use self::sqrtf16::sqrtf16; - pub use self::truncf16::truncf16; + pub use self::scalbn::scalbnf16; + pub use self::sqrt::sqrtf16; + pub use self::trunc::truncf16; // verify-sorted-end #[allow(unused_imports)] @@ -379,37 +349,27 @@ cfg_if! { cfg_if! { if #[cfg(f128_enabled)] { // verify-sorted-start - mod ceilf128; - mod copysignf128; - mod fabsf128; - mod fdimf128; - mod floorf128; mod fmodf128; - mod ldexpf128; - mod roundf128; - mod scalbnf128; - mod sqrtf128; - mod truncf128; // verify-sorted-end // verify-sorted-start - pub use self::ceilf128::ceilf128; - pub use self::copysignf128::copysignf128; - pub use self::fabsf128::fabsf128; - pub use self::fdimf128::fdimf128; - pub use self::floorf128::floorf128; + pub use self::ceil::ceilf128; + pub use self::copysign::copysignf128; + pub use self::fabs::fabsf128; + pub use self::fdim::fdimf128; + pub use self::floor::floorf128; pub use self::fma::fmaf128; pub use self::fmin_fmax::{fmaxf128, fminf128}; pub use self::fminimum_fmaximum::{fmaximumf128, fminimumf128}; pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; pub use self::fmodf128::fmodf128; - pub use self::ldexpf128::ldexpf128; + pub use self::ldexp::ldexpf128; pub use self::rint::rintf128; + pub use self::round::roundf128; pub use self::roundeven::roundevenf128; - pub use self::roundf128::roundf128; - pub use self::scalbnf128::scalbnf128; - pub use self::sqrtf128::sqrtf128; - pub use self::truncf128::truncf128; + pub use self::scalbn::scalbnf128; + pub use self::sqrt::sqrtf128; + pub use self::trunc::truncf128; // verify-sorted-end } } diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 36e0eb1f2ed..6cd091cd73c 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -1,5 +1,25 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf16(x: f16) -> f16 { + super::generic::round(x) +} + +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf(x: f32) -> f32 { + super::generic::round(x) +} + /// Round `x` to the nearest integer, breaking ties away from zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn round(x: f64) -> f64 { super::generic::round(x) } + +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf128(x: f128) -> f128 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs deleted file mode 100644 index b5d7c9d693e..00000000000 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf(x: f32) -> f32 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/src/math/roundf128.rs b/library/compiler-builtins/libm/src/math/roundf128.rs deleted file mode 100644 index fc3164929fe..00000000000 --- a/library/compiler-builtins/libm/src/math/roundf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf128(x: f128) -> f128 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/src/math/roundf16.rs b/library/compiler-builtins/libm/src/math/roundf16.rs deleted file mode 100644 index 8b356eaabee..00000000000 --- a/library/compiler-builtins/libm/src/math/roundf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf16(x: f16) -> f16 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs index f809dad518a..ed73c3f94f0 100644 --- a/library/compiler-builtins/libm/src/math/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -1,4 +1,87 @@ +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf16(x: f16, n: i32) -> f16 { + super::generic::scalbn(x, n) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf(x: f32, n: i32) -> f32 { + super::generic::scalbn(x, n) +} + #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbn(x: f64, n: i32) -> f64 { super::generic::scalbn(x, n) } + +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf128(x: f128, n: i32) -> f128 { + super::generic::scalbn(x, n) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{CastFrom, CastInto, Float}; + + // Tests against N3220 + fn spec_test(f: impl Fn(F, i32) -> F) + where + u32: CastInto, + F::Int: CastFrom, + F::Int: CastFrom, + { + // `scalbn(±0, n)` returns `±0`. + assert_biteq!(f(F::NEG_ZERO, 10), F::NEG_ZERO); + assert_biteq!(f(F::NEG_ZERO, 0), F::NEG_ZERO); + assert_biteq!(f(F::NEG_ZERO, -10), F::NEG_ZERO); + assert_biteq!(f(F::ZERO, 10), F::ZERO); + assert_biteq!(f(F::ZERO, 0), F::ZERO); + assert_biteq!(f(F::ZERO, -10), F::ZERO); + + // `scalbn(x, 0)` returns `x`. + assert_biteq!(f(F::MIN, 0), F::MIN); + assert_biteq!(f(F::MAX, 0), F::MAX); + assert_biteq!(f(F::INFINITY, 0), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY, 0), F::NEG_INFINITY); + assert_biteq!(f(F::ZERO, 0), F::ZERO); + assert_biteq!(f(F::NEG_ZERO, 0), F::NEG_ZERO); + + // `scalbn(±∞, n)` returns `±∞`. + assert_biteq!(f(F::INFINITY, 10), F::INFINITY); + assert_biteq!(f(F::INFINITY, -10), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY, 10), F::NEG_INFINITY); + assert_biteq!(f(F::NEG_INFINITY, -10), F::NEG_INFINITY); + + // NaN should remain NaNs. + assert!(f(F::NAN, 10).is_nan()); + assert!(f(F::NAN, 0).is_nan()); + assert!(f(F::NAN, -10).is_nan()); + assert!(f(-F::NAN, 10).is_nan()); + assert!(f(-F::NAN, 0).is_nan()); + assert!(f(-F::NAN, -10).is_nan()); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_test_f16() { + spec_test::(scalbnf16); + } + + #[test] + fn spec_test_f32() { + spec_test::(scalbnf); + } + + #[test] + fn spec_test_f64() { + spec_test::(scalbn); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_test_f128() { + spec_test::(scalbnf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs deleted file mode 100644 index 57e7ba76f60..00000000000 --- a/library/compiler-builtins/libm/src/math/scalbnf.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf(x: f32, n: i32) -> f32 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/scalbnf128.rs b/library/compiler-builtins/libm/src/math/scalbnf128.rs deleted file mode 100644 index c1d2b485585..00000000000 --- a/library/compiler-builtins/libm/src/math/scalbnf128.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf128(x: f128, n: i32) -> f128 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/scalbnf16.rs b/library/compiler-builtins/libm/src/math/scalbnf16.rs deleted file mode 100644 index 2209e1a1795..00000000000 --- a/library/compiler-builtins/libm/src/math/scalbnf16.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf16(x: f16, n: i32) -> f16 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 2bfc42bcfed..76bc240cf01 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -1,3 +1,32 @@ +/// The square root of `x` (f16). +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf16(x: f16) -> f16 { + select_implementation! { + name: sqrtf16, + use_arch: all(target_arch = "aarch64", target_feature = "fp16"), + args: x, + } + + return super::generic::sqrt(x); +} + +/// The square root of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf(x: f32) -> f32 { + select_implementation! { + name: sqrtf, + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + all(target_arch = "wasm32", intrinsics_enabled), + target_feature = "sse2" + ), + args: x, + } + + super::generic::sqrt(x) +} + /// The square root of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { @@ -13,3 +42,10 @@ pub fn sqrt(x: f64) -> f64 { super::generic::sqrt(x) } + +/// The square root of `x` (f128). +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf128(x: f128) -> f128 { + return super::generic::sqrt(x); +} diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs deleted file mode 100644 index c28a705e378..00000000000 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ /dev/null @@ -1,15 +0,0 @@ -/// The square root of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf(x: f32) -> f32 { - select_implementation! { - name: sqrtf, - use_arch: any( - all(target_arch = "aarch64", target_feature = "neon"), - all(target_arch = "wasm32", intrinsics_enabled), - target_feature = "sse2" - ), - args: x, - } - - super::generic::sqrt(x) -} diff --git a/library/compiler-builtins/libm/src/math/sqrtf128.rs b/library/compiler-builtins/libm/src/math/sqrtf128.rs deleted file mode 100644 index eaef6ae0c1c..00000000000 --- a/library/compiler-builtins/libm/src/math/sqrtf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// The square root of `x` (f128). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf128(x: f128) -> f128 { - return super::generic::sqrt(x); -} diff --git a/library/compiler-builtins/libm/src/math/sqrtf16.rs b/library/compiler-builtins/libm/src/math/sqrtf16.rs deleted file mode 100644 index 7bedb7f8bbb..00000000000 --- a/library/compiler-builtins/libm/src/math/sqrtf16.rs +++ /dev/null @@ -1,11 +0,0 @@ -/// The square root of `x` (f16). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf16(x: f16) -> f16 { - select_implementation! { - name: sqrtf16, - use_arch: all(target_arch = "aarch64", target_feature = "fp16"), - args: x, - } - - return super::generic::sqrt(x); -} diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 2cc8aaa7e8f..fa50d55e136 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -1,3 +1,26 @@ +/// Rounds the number toward 0 to the closest integral value (f16). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf16(x: f16) -> f16 { + super::generic::trunc(x) +} + +/// Rounds the number toward 0 to the closest integral value (f32). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf(x: f32) -> f32 { + select_implementation! { + name: truncf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::trunc(x) +} + /// Rounds the number toward 0 to the closest integral value (f64). /// /// This effectively removes the decimal part of the number, leaving the integral part. @@ -11,3 +34,20 @@ pub fn trunc(x: f64) -> f64 { super::generic::trunc(x) } + +/// Rounds the number toward 0 to the closest integral value (f128). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf128(x: f128) -> f128 { + super::generic::trunc(x) +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::truncf(1.1), 1.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs deleted file mode 100644 index 14533a26706..00000000000 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ /dev/null @@ -1,23 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f32). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf(x: f32) -> f32 { - select_implementation! { - name: truncf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::trunc(x) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::truncf(1.1), 1.0); - } -} diff --git a/library/compiler-builtins/libm/src/math/truncf128.rs b/library/compiler-builtins/libm/src/math/truncf128.rs deleted file mode 100644 index 9dccc0d0e9d..00000000000 --- a/library/compiler-builtins/libm/src/math/truncf128.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f128). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf128(x: f128) -> f128 { - super::generic::trunc(x) -} diff --git a/library/compiler-builtins/libm/src/math/truncf16.rs b/library/compiler-builtins/libm/src/math/truncf16.rs deleted file mode 100644 index d7c3d225cf9..00000000000 --- a/library/compiler-builtins/libm/src/math/truncf16.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f16). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf16(x: f16) -> f16 { - super::generic::trunc(x) -} -- cgit 1.4.1-3-g733a5 From 014c3e4ccbb8afc3740acf5658c07e5783e3d848 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 03:22:13 +0000 Subject: ci: Cancel jobs when a new push happens Jobs should just cancel automatically, it isn't ideal that extensive jobs can continue running for multiple hours after code has been updated. Use a solution from [1] to do this. [1]: https://stackoverflow.com/a/72408109/5380651 --- library/compiler-builtins/libm/.github/workflows/main.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index e86f936f74f..93c56c9d40f 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -5,6 +5,11 @@ on: - master pull_request: +concurrency: + # Make sure that new pushes cancel running jobs + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always RUSTDOCFLAGS: -Dwarnings -- cgit 1.4.1-3-g733a5 From cad0d6f1875031a3f8c53815c38d3042b20f2f74 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 01:58:05 +0000 Subject: ci: Allow skipping extensive tests with `ci: skip-extensive` Sometimes we do refactoring that moves things around and triggers an extensive test, even though the implementation didn't change. There isn't any need to run full extensive CI in these cases, so add a way to skip it from the PR message. --- .../libm/.github/workflows/main.yaml | 15 ++-- library/compiler-builtins/libm/ci/ci-util.py | 88 ++++++++++++++++------ 2 files changed, 73 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 93c56c9d40f..2b2891ab226 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -239,6 +239,9 @@ jobs: name: Calculate job matrix runs-on: ubuntu-24.04 timeout-minutes: 10 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} outputs: matrix: ${{ steps.script.outputs.matrix }} steps: @@ -267,7 +270,7 @@ jobs: # this is not currently possible https://github.com/actions/runner/issues/1985. include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }} env: - CHANGED: ${{ matrix.changed }} + TO_TEST: ${{ matrix.to_test }} steps: - uses: actions/checkout@v4 with: @@ -279,16 +282,18 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Run extensive tests run: | - echo "Changed: '$CHANGED'" - if [ -z "$CHANGED" ]; then + echo "Tests to run: '$TO_TEST'" + if [ -z "$TO_TEST" ]; then echo "No tests to run, exiting." exit fi + set -x + # Run the non-extensive tests first to catch any easy failures - cargo t --profile release-checked -- "$CHANGED" + cargo t --profile release-checked -- "$TO_TEST" - LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \ + LIBM_EXTENSIVE_TESTS="$TO_TEST" cargo t \ --features build-mpfr,unstable,force-soft-floats \ --profile release-checked \ -- extensive diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index 7464fd42595..8b07dde3172 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -6,6 +6,7 @@ git history. """ import json +import os import subprocess as sp import sys from dataclasses import dataclass @@ -13,7 +14,7 @@ from glob import glob, iglob from inspect import cleandoc from os import getenv from pathlib import Path -from typing import TypedDict +from typing import TypedDict, Self USAGE = cleandoc( """ @@ -51,6 +52,8 @@ WORKFLOW_NAME = "CI" # Workflow that generates the benchmark artifacts ARTIFACT_GLOB = "baseline-icount*" # Place this in a PR body to skip regression checks (must be at the start of a line). REGRESSION_DIRECTIVE = "ci: allow-regressions" +# Place this in a PR body to skip extensive tests +SKIP_EXTENSIVE_DIRECTIVE = "ci: skip-extensive" # Don't run exhaustive tests if these files change, even if they contaiin a function # definition. @@ -68,6 +71,39 @@ def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) +@dataclass +class PrInfo: + """GitHub response for PR query""" + + body: str + commits: list[str] + created_at: str + number: int + + @classmethod + def load(cls, pr_number: int | str) -> Self: + """For a given PR number, query the body and commit list""" + pr_info = sp.check_output( + [ + "gh", + "pr", + "view", + str(pr_number), + "--json=number,commits,body,createdAt", + # Flatten the commit list to only hashes, change a key to snake naming + "--jq=.commits |= map(.oid) | .created_at = .createdAt | del(.createdAt)", + ], + text=True, + ) + eprint("PR info:", json.dumps(pr_info, indent=4)) + return cls(**json.loads(pr_info)) + + def contains_directive(self, directive: str) -> bool: + """Return true if the provided directive is on a line in the PR body""" + lines = self.body.splitlines() + return any(line.startswith(directive) for line in lines) + + class FunctionDef(TypedDict): """Type for an entry in `function-definitions.json`""" @@ -149,7 +185,7 @@ class Context: eprint(f"changed files for {name}: {changed}") routines.add(name) - ret = {} + ret: dict[str, list[str]] = {} for r in sorted(routines): ret.setdefault(self.defs[r]["type"], []).append(r) @@ -159,13 +195,27 @@ class Context: """Create a JSON object a list items for each type's changed files, if any did change, and the routines that were affected by the change. """ + + pr_number = os.environ.get("PR_NUMBER") + skip_tests = False + + if pr_number is not None: + pr = PrInfo.load(pr_number) + skip_tests = pr.contains_directive(SKIP_EXTENSIVE_DIRECTIVE) + + if skip_tests: + eprint("Skipping all extensive tests") + changed = self.changed_routines() ret = [] for ty in TYPES: ty_changed = changed.get(ty, []) + changed_str = ",".join(ty_changed) + item = { "ty": ty, - "changed": ",".join(ty_changed), + "changed": changed_str, + "to_test": "" if skip_tests else changed_str, } ret.append(item) output = json.dumps({"matrix": ret}, separators=(",", ":")) @@ -266,13 +316,13 @@ def check_iai_regressions(args: list[str]): found. """ - iai_home = "iai-home" - pr_number = False + iai_home_str = "iai-home" + pr_number = None while len(args) > 0: match args: case ["--home", home, *rest]: - iai_home = home + iai_home_str = home args = rest case ["--allow-pr-override", pr_num, *rest]: pr_number = pr_num @@ -281,10 +331,10 @@ def check_iai_regressions(args: list[str]): eprint(USAGE) exit(1) - iai_home = Path(iai_home) + iai_home = Path(iai_home_str) found_summaries = False - regressions = [] + regressions: list[dict] = [] for summary_path in iglob("**/summary.json", root_dir=iai_home, recursive=True): found_summaries = True with open(iai_home / summary_path, "r") as f: @@ -292,7 +342,9 @@ def check_iai_regressions(args: list[str]): summary_regs = [] run = summary["callgrind_summary"]["callgrind_run"] - name_entry = {"name": f"{summary["function_name"]}.{summary["id"]}"} + fname = summary["function_name"] + id = summary["id"] + name_entry = {"name": f"{fname}.{id}"} for segment in run["segments"]: summary_regs.extend(segment["regressions"]) @@ -312,22 +364,8 @@ def check_iai_regressions(args: list[str]): eprint("Found regressions:", json.dumps(regressions, indent=4)) if pr_number is not None: - pr_info = sp.check_output( - [ - "gh", - "pr", - "view", - str(pr_number), - "--json=number,commits,body,createdAt", - "--jq=.commits |= map(.oid)", - ], - text=True, - ) - pr = json.loads(pr_info) - eprint("PR info:", json.dumps(pr, indent=4)) - - lines = pr["body"].splitlines() - if any(line.startswith(REGRESSION_DIRECTIVE) for line in lines): + pr = PrInfo.load(pr_number) + if pr.contains_directive(REGRESSION_DIRECTIVE): eprint("PR allows regressions, returning") return -- cgit 1.4.1-3-g733a5 From a0e5a7a6360f78826757f7bb5e48350fbb3ff353 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 02:20:21 +0000 Subject: ci: Require `ci: allow-many-extensive` if a threshold is exceeded Error out when too many extensive tests would be run unless `ci: allow-many-extensive` is in the PR description. This allows us to set a much higher CI timeout with less risk that a 4+ hour job gets started by accident. --- library/compiler-builtins/libm/ci/ci-util.py | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index 8b07dde3172..aae791d0f16 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -54,6 +54,11 @@ ARTIFACT_GLOB = "baseline-icount*" REGRESSION_DIRECTIVE = "ci: allow-regressions" # Place this in a PR body to skip extensive tests SKIP_EXTENSIVE_DIRECTIVE = "ci: skip-extensive" +# Place this in a PR body to allow running a large number of extensive tests. If not +# set, this script will error out if a threshold is exceeded in order to avoid +# accidentally spending huge amounts of CI time. +ALLOW_MANY_EXTENSIVE_DIRECTIVE = "ci: allow-many-extensive" +MANY_EXTENSIVE_THRESHOLD = 20 # Don't run exhaustive tests if these files change, even if they contaiin a function # definition. @@ -198,28 +203,45 @@ class Context: pr_number = os.environ.get("PR_NUMBER") skip_tests = False + error_on_many_tests = False if pr_number is not None: pr = PrInfo.load(pr_number) skip_tests = pr.contains_directive(SKIP_EXTENSIVE_DIRECTIVE) + error_on_many_tests = not pr.contains_directive( + ALLOW_MANY_EXTENSIVE_DIRECTIVE + ) if skip_tests: eprint("Skipping all extensive tests") changed = self.changed_routines() ret = [] + total_to_test = 0 + for ty in TYPES: ty_changed = changed.get(ty, []) - changed_str = ",".join(ty_changed) + ty_to_test = [] if skip_tests else ty_changed + total_to_test += len(ty_to_test) item = { "ty": ty, - "changed": changed_str, - "to_test": "" if skip_tests else changed_str, + "changed": ",".join(ty_changed), + "to_test": ",".join(ty_to_test), } + ret.append(item) output = json.dumps({"matrix": ret}, separators=(",", ":")) eprint(f"output: {output}") + eprint(f"total extensive tests: {total_to_test}") + + if error_on_many_tests and total_to_test > MANY_EXTENSIVE_THRESHOLD: + eprint( + f"More than {MANY_EXTENSIVE_THRESHOLD} tests would be run; add" + f" `{ALLOW_MANY_EXTENSIVE_DIRECTIVE}` to the PR body if this is intentional" + ) + exit(1) + return output -- cgit 1.4.1-3-g733a5 From 1cb17773f66493364d07ae13fd8e0d50ca44cfe0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 01:24:38 +0000 Subject: ci: Increase the timeout for extensive tests The reorganization PR has caused this to fail once before because every file shows up as changed. Increase the timeout so this doesn't happen. We now cancel the job if too many extensive tests are run unless `ci: allow-many-extensive` is in the PR description, so this helps prevent the limit being hit by accident. --- library/compiler-builtins/libm/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 2b2891ab226..c925e63aa59 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -261,7 +261,7 @@ jobs: - clippy - calculate_extensive_matrix runs-on: ubuntu-24.04 - timeout-minutes: 180 + timeout-minutes: 240 # 4 hours strategy: matrix: # Use the output from `calculate_extensive_matrix` to calculate the matrix -- cgit 1.4.1-3-g733a5 From 2585a57dc742265f8400eaafb91a6990b6c7dc07 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 06:15:10 +0000 Subject: Ensure configure.rs changes trigger rebuilds --- .../compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs | 1 + library/compiler-builtins/libm/crates/libm-test/build.rs | 1 + library/compiler-builtins/libm/crates/util/build.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs index 401b7e1eb3a..4ee5ab585d5 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs @@ -2,6 +2,7 @@ mod configure; fn main() { + println!("cargo:rerun-if-changed=../../configure.rs"); let cfg = configure::Config::from_env(); configure::emit_libm_config(&cfg); } diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index 134fb11ceeb..d2d0df9cbe9 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -3,6 +3,7 @@ mod configure; use configure::Config; fn main() { + println!("cargo:rerun-if-changed=../../configure.rs"); let cfg = Config::from_env(); configure::emit_test_config(&cfg); } diff --git a/library/compiler-builtins/libm/crates/util/build.rs b/library/compiler-builtins/libm/crates/util/build.rs index 0745ef3dd6f..b6cceb5f11b 100644 --- a/library/compiler-builtins/libm/crates/util/build.rs +++ b/library/compiler-builtins/libm/crates/util/build.rs @@ -4,6 +4,7 @@ mod configure; fn main() { + println!("cargo:rerun-if-changed=../../configure.rs"); let cfg = configure::Config::from_env(); configure::emit_libm_config(&cfg); } -- cgit 1.4.1-3-g733a5 From 2db05de8fdf0d8b92df083a088ebde412bf6d75c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 06:43:19 +0000 Subject: ci: Account for `PR_NUMBER` being set to an empty string This is the case for CI after merge that is no longer associated with a pull request. --- library/compiler-builtins/libm/ci/ci-util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index aae791d0f16..7468fd690cb 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -205,7 +205,7 @@ class Context: skip_tests = False error_on_many_tests = False - if pr_number is not None: + if pr_number is not None and len(pr_number) > 0: pr = PrInfo.load(pr_number) skip_tests = pr.contains_directive(SKIP_EXTENSIVE_DIRECTIVE) error_on_many_tests = not pr.contains_directive( -- cgit 1.4.1-3-g733a5 From 8da1290f04eec03298b4a905091a4ad4f7b1c4eb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 07:05:13 +0000 Subject: Ensure all public functions are marked `no_panic` Fixes: https://github.com/rust-lang/libm/issues/201 --- library/compiler-builtins/libm/src/math/frexpf.rs | 1 + library/compiler-builtins/libm/src/math/j0.rs | 2 ++ library/compiler-builtins/libm/src/math/j0f.rs | 2 ++ library/compiler-builtins/libm/src/math/j1.rs | 2 ++ library/compiler-builtins/libm/src/math/j1f.rs | 2 ++ library/compiler-builtins/libm/src/math/jn.rs | 2 ++ library/compiler-builtins/libm/src/math/jnf.rs | 2 ++ library/compiler-builtins/libm/src/math/modf.rs | 1 + library/compiler-builtins/libm/src/math/modff.rs | 1 + 9 files changed, 15 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/frexpf.rs b/library/compiler-builtins/libm/src/math/frexpf.rs index 2919c0ab022..0ec91c2d350 100644 --- a/library/compiler-builtins/libm/src/math/frexpf.rs +++ b/library/compiler-builtins/libm/src/math/frexpf.rs @@ -1,3 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn frexpf(x: f32) -> (f32, i32) { let mut y = x.to_bits(); let ee: i32 = ((y >> 23) & 0xff) as i32; diff --git a/library/compiler-builtins/libm/src/math/j0.rs b/library/compiler-builtins/libm/src/math/j0.rs index 5e5e839f81a..99d656f0d08 100644 --- a/library/compiler-builtins/libm/src/math/j0.rs +++ b/library/compiler-builtins/libm/src/math/j0.rs @@ -110,6 +110,7 @@ const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ /// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn j0(mut x: f64) -> f64 { let z: f64; let r: f64; @@ -164,6 +165,7 @@ const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ /// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn y0(x: f64) -> f64 { let z: f64; let u: f64; diff --git a/library/compiler-builtins/libm/src/math/j0f.rs b/library/compiler-builtins/libm/src/math/j0f.rs index afb6ee9ba8b..25e5b325c8c 100644 --- a/library/compiler-builtins/libm/src/math/j0f.rs +++ b/library/compiler-builtins/libm/src/math/j0f.rs @@ -63,6 +63,7 @@ const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ /// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn j0f(mut x: f32) -> f32 { let z: f32; let r: f32; @@ -109,6 +110,7 @@ const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ /// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn y0f(x: f32) -> f32 { let z: f32; let u: f32; diff --git a/library/compiler-builtins/libm/src/math/j1.rs b/library/compiler-builtins/libm/src/math/j1.rs index 578ae59d3ab..9b604d9e46e 100644 --- a/library/compiler-builtins/libm/src/math/j1.rs +++ b/library/compiler-builtins/libm/src/math/j1.rs @@ -114,6 +114,7 @@ const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ /// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn j1(x: f64) -> f64 { let mut z: f64; let r: f64; @@ -160,6 +161,7 @@ const V0: [f64; 5] = [ ]; /// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn y1(x: f64) -> f64 { let z: f64; let u: f64; diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 02a3efd2435..a47472401ee 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -64,6 +64,7 @@ const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ /// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn j1f(x: f32) -> f32 { let mut z: f32; let r: f32; @@ -109,6 +110,7 @@ const V0: [f32; 5] = [ ]; /// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn y1f(x: f32) -> f32 { let z: f32; let u: f32; diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs index d228781d12a..31f8d9c5382 100644 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -39,6 +39,7 @@ use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ /// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn jn(n: i32, mut x: f64) -> f64 { let mut ix: u32; let lx: u32; @@ -248,6 +249,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { } /// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn yn(n: i32, x: f64) -> f64 { let mut ix: u32; let lx: u32; diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs index 754f8f33b5a..52cf7d8a8bd 100644 --- a/library/compiler-builtins/libm/src/math/jnf.rs +++ b/library/compiler-builtins/libm/src/math/jnf.rs @@ -16,6 +16,7 @@ use super::{fabsf, j0f, j1f, logf, y0f, y1f}; /// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn jnf(n: i32, mut x: f32) -> f32 { let mut ix: u32; let mut nm1: i32; @@ -191,6 +192,7 @@ pub fn jnf(n: i32, mut x: f32) -> f32 { } /// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ynf(n: i32, x: f32) -> f32 { let mut ix: u32; let mut ib: u32; diff --git a/library/compiler-builtins/libm/src/math/modf.rs b/library/compiler-builtins/libm/src/math/modf.rs index e29e80ccf5f..6541862cdd9 100644 --- a/library/compiler-builtins/libm/src/math/modf.rs +++ b/library/compiler-builtins/libm/src/math/modf.rs @@ -1,3 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn modf(x: f64) -> (f64, f64) { let rv2: f64; let mut u = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/modff.rs b/library/compiler-builtins/libm/src/math/modff.rs index fac60abaa55..90c6bca7d8d 100644 --- a/library/compiler-builtins/libm/src/math/modff.rs +++ b/library/compiler-builtins/libm/src/math/modff.rs @@ -1,3 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn modff(x: f32) -> (f32, f32) { let rv2: f32; let mut u: u32 = x.to_bits(); -- cgit 1.4.1-3-g733a5 From 3cecf22e0c20853675aad5d3977cb3712729a1f6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 07:15:26 +0000 Subject: Combine the source files for `fmod` Since `fmod` is generic, there isn't any need to have the small wrappers in separate files. Most operations was done in [1] but `fmod` was omitted until now. [1]: https://github.com/rust-lang/libm/pull/537 --- .../libm/etc/function-definitions.json | 6 +++--- library/compiler-builtins/libm/src/math/fmod.rs | 20 ++++++++++++++++++++ library/compiler-builtins/libm/src/math/fmodf.rs | 5 ----- library/compiler-builtins/libm/src/math/fmodf128.rs | 5 ----- library/compiler-builtins/libm/src/math/fmodf16.rs | 5 ----- library/compiler-builtins/libm/src/math/frexp.rs | 1 + library/compiler-builtins/libm/src/math/mod.rs | 16 +++------------- 7 files changed, 27 insertions(+), 31 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/fmodf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmodf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmodf16.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 801e74b22a5..ead1f807fc9 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -537,21 +537,21 @@ }, "fmodf": { "sources": [ - "src/math/fmodf.rs", + "src/math/fmod.rs", "src/math/generic/fmod.rs" ], "type": "f32" }, "fmodf128": { "sources": [ - "src/math/fmodf128.rs", + "src/math/fmod.rs", "src/math/generic/fmod.rs" ], "type": "f128" }, "fmodf16": { "sources": [ - "src/math/fmodf16.rs", + "src/math/fmod.rs", "src/math/generic/fmod.rs" ], "type": "f16" diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs index d9786b53d71..c4752b92578 100644 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -1,5 +1,25 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf16(x: f16, y: f16) -> f16 { + super::generic::fmod(x, y) +} + +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf(x: f32, y: f32) -> f32 { + super::generic::fmod(x, y) +} + /// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmod(x: f64, y: f64) -> f64 { super::generic::fmod(x, y) } + +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf128(x: f128, y: f128) -> f128 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs deleted file mode 100644 index 4e95696e20d..00000000000 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf(x: f32, y: f32) -> f32 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmodf128.rs b/library/compiler-builtins/libm/src/math/fmodf128.rs deleted file mode 100644 index ff0e0493e26..00000000000 --- a/library/compiler-builtins/libm/src/math/fmodf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf128(x: f128, y: f128) -> f128 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmodf16.rs b/library/compiler-builtins/libm/src/math/fmodf16.rs deleted file mode 100644 index 11972a7de4f..00000000000 --- a/library/compiler-builtins/libm/src/math/fmodf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf16(x: f16, y: f16) -> f16 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/frexp.rs b/library/compiler-builtins/libm/src/math/frexp.rs index badad786aa3..de7a64fdae1 100644 --- a/library/compiler-builtins/libm/src/math/frexp.rs +++ b/library/compiler-builtins/libm/src/math/frexp.rs @@ -1,3 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn frexp(x: f64) -> (f64, i32) { let mut y = x.to_bits(); let ee = ((y >> 52) & 0x7ff) as i32; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 023cf67a306..949c18b4000 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -164,7 +164,6 @@ mod fmin_fmax; mod fminimum_fmaximum; mod fminimum_fmaximum_num; mod fmod; -mod fmodf; mod frexp; mod frexpf; mod hypot; @@ -260,8 +259,7 @@ pub use self::fma_wide::fmaf; pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; pub use self::fminimum_fmaximum::{fmaximum, fmaximumf, fminimum, fminimumf}; pub use self::fminimum_fmaximum_num::{fmaximum_num, fmaximum_numf, fminimum_num, fminimum_numf}; -pub use self::fmod::fmod; -pub use self::fmodf::fmodf; +pub use self::fmod::{fmod, fmodf}; pub use self::frexp::frexp; pub use self::frexpf::frexpf; pub use self::hypot::hypot; @@ -318,10 +316,6 @@ pub use self::trunc::{trunc, truncf}; cfg_if! { if #[cfg(f16_enabled)] { - // verify-sorted-start - mod fmodf16; - // verify-sorted-end - // verify-sorted-start pub use self::ceil::ceilf16; pub use self::copysign::copysignf16; @@ -331,7 +325,7 @@ cfg_if! { pub use self::fmin_fmax::{fmaxf16, fminf16}; pub use self::fminimum_fmaximum::{fmaximumf16, fminimumf16}; pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16}; - pub use self::fmodf16::fmodf16; + pub use self::fmod::fmodf16; pub use self::ldexp::ldexpf16; pub use self::rint::rintf16; pub use self::round::roundf16; @@ -348,10 +342,6 @@ cfg_if! { cfg_if! { if #[cfg(f128_enabled)] { - // verify-sorted-start - mod fmodf128; - // verify-sorted-end - // verify-sorted-start pub use self::ceil::ceilf128; pub use self::copysign::copysignf128; @@ -362,7 +352,7 @@ cfg_if! { pub use self::fmin_fmax::{fmaxf128, fminf128}; pub use self::fminimum_fmaximum::{fmaximumf128, fminimumf128}; pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; - pub use self::fmodf128::fmodf128; + pub use self::fmod::fmodf128; pub use self::ldexp::ldexpf128; pub use self::rint::rintf128; pub use self::round::roundf128; -- cgit 1.4.1-3-g733a5 From 88dcaf20b5400e023024daae6a3c927a32fa36ab Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 19:19:24 +0000 Subject: Mark generic functions `#[inline]` Benchmarks for [1] seemed to indicate that repository organization for some reason had an effect on performance, even though the exact same rustc commands were running (though some with a different order). After investigating more, it appears that dependencies may have an affect on inlining thresholds for generic functions. It is surprising that this happens, we more or less expect that public functions will be standalone but everything they call will be inlined. To help ensure this, mark all generic functions `#[inline]` if they should be merged into the public function. Zulip discussion at [2]. [1]: https://github.com/rust-lang/libm/pull/533 [2]: https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/Dependencies.20affecting.20codegen/with/513079387 --- library/compiler-builtins/libm/src/math/fma.rs | 1 + library/compiler-builtins/libm/src/math/fma_wide.rs | 1 + library/compiler-builtins/libm/src/math/generic/ceil.rs | 2 ++ library/compiler-builtins/libm/src/math/generic/copysign.rs | 1 + library/compiler-builtins/libm/src/math/generic/fabs.rs | 1 + library/compiler-builtins/libm/src/math/generic/fdim.rs | 1 + library/compiler-builtins/libm/src/math/generic/floor.rs | 2 ++ library/compiler-builtins/libm/src/math/generic/fmax.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fmaximum.rs | 1 + library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs | 1 + library/compiler-builtins/libm/src/math/generic/fmin.rs | 1 + library/compiler-builtins/libm/src/math/generic/fminimum.rs | 1 + library/compiler-builtins/libm/src/math/generic/fminimum_num.rs | 1 + library/compiler-builtins/libm/src/math/generic/fmod.rs | 2 +- library/compiler-builtins/libm/src/math/generic/mod.rs | 3 +++ library/compiler-builtins/libm/src/math/generic/rint.rs | 1 + library/compiler-builtins/libm/src/math/generic/round.rs | 1 + library/compiler-builtins/libm/src/math/generic/scalbn.rs | 1 + library/compiler-builtins/libm/src/math/generic/sqrt.rs | 2 ++ library/compiler-builtins/libm/src/math/generic/trunc.rs | 2 ++ library/compiler-builtins/libm/src/math/roundeven.rs | 1 + 21 files changed, 27 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 789b0836afb..e0b3347acf8 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -29,6 +29,7 @@ pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { /// Fused multiply-add that works when there is not a larger float size available. Computes /// `(x * y) + z`. +#[inline] pub fn fma_round(x: F, y: F, z: F, _round: Round) -> FpResult where F: Float, diff --git a/library/compiler-builtins/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/src/math/fma_wide.rs index 8e908a14f21..08b78b02264 100644 --- a/library/compiler-builtins/libm/src/math/fma_wide.rs +++ b/library/compiler-builtins/libm/src/math/fma_wide.rs @@ -28,6 +28,7 @@ pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { /// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, /// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. +#[inline] pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult where F: Float + HFloat, diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs index bf7e1d8e210..5c5bb47638f 100644 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -10,10 +10,12 @@ use super::super::support::{FpResult, Status}; use super::super::{Float, Int, IntTy, MinInt}; +#[inline] pub fn ceil(x: F) -> F { ceil_status(x).val } +#[inline] pub fn ceil_status(x: F) -> FpResult { let zero = IntTy::::ZERO; diff --git a/library/compiler-builtins/libm/src/math/generic/copysign.rs b/library/compiler-builtins/libm/src/math/generic/copysign.rs index 04864a35905..a61af22f04a 100644 --- a/library/compiler-builtins/libm/src/math/generic/copysign.rs +++ b/library/compiler-builtins/libm/src/math/generic/copysign.rs @@ -1,6 +1,7 @@ use super::super::Float; /// Copy the sign of `y` to `x`. +#[inline] pub fn copysign(x: F, y: F) -> F { let mut ux = x.to_bits(); let uy = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/generic/fabs.rs b/library/compiler-builtins/libm/src/math/generic/fabs.rs index 75b473107c6..0fa0edf9b87 100644 --- a/library/compiler-builtins/libm/src/math/generic/fabs.rs +++ b/library/compiler-builtins/libm/src/math/generic/fabs.rs @@ -1,6 +1,7 @@ use super::super::Float; /// Absolute value. +#[inline] pub fn fabs(x: F) -> F { let abs_mask = !F::SIGN_MASK; F::from_bits(x.to_bits() & abs_mask) diff --git a/library/compiler-builtins/libm/src/math/generic/fdim.rs b/library/compiler-builtins/libm/src/math/generic/fdim.rs index bf971cd7d18..a63007b191c 100644 --- a/library/compiler-builtins/libm/src/math/generic/fdim.rs +++ b/library/compiler-builtins/libm/src/math/generic/fdim.rs @@ -1,5 +1,6 @@ use super::super::Float; +#[inline] pub fn fdim(x: F, y: F) -> F { if x <= y { F::ZERO } else { x - y } } diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs index 7799551644f..2438046254f 100644 --- a/library/compiler-builtins/libm/src/math/generic/floor.rs +++ b/library/compiler-builtins/libm/src/math/generic/floor.rs @@ -10,10 +10,12 @@ use super::super::support::{FpResult, Status}; use super::super::{Float, Int, IntTy, MinInt}; +#[inline] pub fn floor(x: F) -> F { floor_status(x).val } +#[inline] pub fn floor_status(x: F) -> FpResult { let zero = IntTy::::ZERO; diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs index 29a03110057..bf3f847e89b 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmax.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmax.rs @@ -16,7 +16,7 @@ use super::super::Float; -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[inline] pub fn fmax(x: F, y: F) -> F { let res = if x.is_nan() || x < y { y } else { x }; // Canonicalize diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs index 9e8d1739f67..387055af29c 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs @@ -11,6 +11,7 @@ use super::super::Float; +#[inline] pub fn fmaximum(x: F, y: F) -> F { let res = if x.is_nan() { x diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs index 756ef5d9f6d..f7efdde80ea 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs @@ -13,6 +13,7 @@ use super::super::Float; +#[inline] pub fn fmaximum_num(x: F, y: F) -> F { let res = if x.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs index 69fbf85a194..cd3caeee4f2 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmin.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmin.rs @@ -16,6 +16,7 @@ use super::super::Float; +#[inline] pub fn fmin(x: F, y: F) -> F { let res = if y.is_nan() || x < y { x } else { y }; // Canonicalize diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs index ee5493880eb..4ddb3645506 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum.rs @@ -11,6 +11,7 @@ use super::super::Float; +#[inline] pub fn fminimum(x: F, y: F) -> F { let res = if x.is_nan() { x diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs index 96661832824..441c204a921 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs @@ -13,6 +13,7 @@ use super::super::Float; +#[inline] pub fn fminimum_num(x: F, y: F) -> F { let res = if y.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs index cd23350ea3a..6414bbd2508 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmod.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs @@ -3,7 +3,7 @@ use super::super::{CastFrom, Float, Int, MinInt}; -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[inline] pub fn fmod(x: F, y: F) -> F { let zero = F::Int::ZERO; let one = F::Int::ONE; diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 9be185f809f..35846351a6e 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -1,3 +1,6 @@ +// Note: generic functions are marked `#[inline]` because, even though generic functions are +// typically inlined, this does not seem to always be the case. + mod ceil; mod copysign; mod fabs; diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index 45d2f313866..9cdeb1185a8 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -6,6 +6,7 @@ use super::super::support::{FpResult, Round}; /// IEEE 754-2019 `roundToIntegralExact`, which respects rounding mode and raises inexact if /// applicable. +#[inline] pub fn rint_round(x: F, _round: Round) -> FpResult { let toint = F::ONE / F::EPSILON; let e = x.ex(); diff --git a/library/compiler-builtins/libm/src/math/generic/round.rs b/library/compiler-builtins/libm/src/math/generic/round.rs index 8b51381880c..01314ac70c2 100644 --- a/library/compiler-builtins/libm/src/math/generic/round.rs +++ b/library/compiler-builtins/libm/src/math/generic/round.rs @@ -1,6 +1,7 @@ use super::super::{Float, MinInt}; use super::{copysign, trunc}; +#[inline] pub fn round(x: F) -> F { let f0p5 = F::from_parts(false, F::EXP_BIAS - 1, F::Int::ZERO); // 0.5 let f0p25 = F::from_parts(false, F::EXP_BIAS - 2, F::Int::ZERO); // 0.25 diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs index b2696e5cc9f..a45db1b4a02 100644 --- a/library/compiler-builtins/libm/src/math/generic/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs @@ -16,6 +16,7 @@ use super::super::{CastFrom, CastInto, Float, IntTy, MinInt}; /// > /// > If the calculation does not overflow or underflow, the returned value is exact and /// > independent of the current rounding direction mode. +#[inline] pub fn scalbn(mut x: F, mut n: i32) -> F where u32: CastInto, diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index 5918025bc67..ec9ff22df20 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -44,6 +44,7 @@ use super::super::support::{FpResult, IntTy, Round, Status, cold_path}; use super::super::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; +#[inline] pub fn sqrt(x: F) -> F where F: Float + SqrtHelper, @@ -57,6 +58,7 @@ where sqrt_round(x, Round::Nearest).val } +#[inline] pub fn sqrt_round(x: F, _round: Round) -> FpResult where F: Float + SqrtHelper, diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs index 0fb3fa5ad3b..25414ecf426 100644 --- a/library/compiler-builtins/libm/src/math/generic/trunc.rs +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -4,10 +4,12 @@ use super::super::support::{FpResult, Status}; use super::super::{Float, Int, IntTy, MinInt}; +#[inline] pub fn trunc(x: F) -> F { trunc_status(x).val } +#[inline] pub fn trunc_status(x: F) -> FpResult { let mut xi: F::Int = x.to_bits(); let e: i32 = x.exp_unbiased(); diff --git a/library/compiler-builtins/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/src/math/roundeven.rs index ec1738285e6..6e621d7628f 100644 --- a/library/compiler-builtins/libm/src/math/roundeven.rs +++ b/library/compiler-builtins/libm/src/math/roundeven.rs @@ -30,6 +30,7 @@ pub fn roundevenf128(x: f128) -> f128 { roundeven_impl(x) } +#[inline] pub fn roundeven_impl(x: F) -> F { super::generic::rint_round(x, Round::Nearest).val } -- cgit 1.4.1-3-g733a5 From 7077daa6ad9fecd1cb5fa10a431ac86273abbb20 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 9 Apr 2025 01:21:33 +0000 Subject: refactor: Move the `libm` crate to a subdirectory In preparation for switching to a virtual manifest, move the `libm` crate into a subdirectory and update paths to match. Updating `Cargo.toml` is done in the next commit so git tracks the moved file correctly. --- .../libm/.github/workflows/main.yaml | 2 +- library/compiler-builtins/libm/Cargo.toml | 87 -- library/compiler-builtins/libm/build.rs | 17 - library/compiler-builtins/libm/ci/ci-util.py | 6 +- library/compiler-builtins/libm/configure.rs | 183 ---- .../crates/compiler-builtins-smoke-test/build.rs | 4 +- .../compiler-builtins-smoke-test/src/math.rs | 2 +- .../libm/crates/libm-test/Cargo.toml | 2 +- .../libm/crates/libm-test/build.rs | 4 +- .../libm/crates/musl-math-sys/Cargo.toml | 2 +- .../compiler-builtins/libm/crates/util/Cargo.toml | 2 +- .../compiler-builtins/libm/crates/util/build.rs | 4 +- .../compiler-builtins/libm/etc/update-api-list.py | 18 +- library/compiler-builtins/libm/libm/Cargo.toml | 87 ++ library/compiler-builtins/libm/libm/build.rs | 18 + library/compiler-builtins/libm/libm/configure.rs | 183 ++++ library/compiler-builtins/libm/libm/src/lib.rs | 28 + .../compiler-builtins/libm/libm/src/libm_helper.rs | 244 +++++ .../compiler-builtins/libm/libm/src/math/acos.rs | 112 ++ .../compiler-builtins/libm/libm/src/math/acosf.rs | 79 ++ .../compiler-builtins/libm/libm/src/math/acosh.rs | 27 + .../compiler-builtins/libm/libm/src/math/acoshf.rs | 26 + .../libm/libm/src/math/arch/aarch64.rs | 115 ++ .../libm/libm/src/math/arch/i586.rs | 37 + .../libm/libm/src/math/arch/i686.rs | 27 + .../libm/libm/src/math/arch/mod.rs | 50 + .../libm/libm/src/math/arch/wasm32.rs | 50 + .../compiler-builtins/libm/libm/src/math/asin.rs | 115 ++ .../compiler-builtins/libm/libm/src/math/asinf.rs | 68 ++ .../compiler-builtins/libm/libm/src/math/asinh.rs | 36 + .../compiler-builtins/libm/libm/src/math/asinhf.rs | 35 + .../compiler-builtins/libm/libm/src/math/atan.rs | 182 +++ .../compiler-builtins/libm/libm/src/math/atan2.rs | 131 +++ .../compiler-builtins/libm/libm/src/math/atan2f.rs | 90 ++ .../compiler-builtins/libm/libm/src/math/atanf.rs | 103 ++ .../compiler-builtins/libm/libm/src/math/atanh.rs | 33 + .../compiler-builtins/libm/libm/src/math/atanhf.rs | 33 + .../compiler-builtins/libm/libm/src/math/cbrt.rs | 215 ++++ .../compiler-builtins/libm/libm/src/math/cbrtf.rs | 75 ++ .../compiler-builtins/libm/libm/src/math/ceil.rs | 46 + .../libm/libm/src/math/copysign.rs | 88 ++ .../libm/libm/src/math/copysignf.rs | 8 + .../libm/libm/src/math/copysignf128.rs | 8 + .../libm/libm/src/math/copysignf16.rs | 8 + .../compiler-builtins/libm/libm/src/math/cos.rs | 77 ++ .../compiler-builtins/libm/libm/src/math/cosf.rs | 86 ++ .../compiler-builtins/libm/libm/src/math/cosh.rs | 36 + .../compiler-builtins/libm/libm/src/math/coshf.rs | 36 + .../compiler-builtins/libm/libm/src/math/erf.rs | 310 ++++++ .../compiler-builtins/libm/libm/src/math/erff.rs | 222 ++++ .../compiler-builtins/libm/libm/src/math/exp.rs | 150 +++ .../compiler-builtins/libm/libm/src/math/exp10.rs | 23 + .../compiler-builtins/libm/libm/src/math/exp10f.rs | 22 + .../compiler-builtins/libm/libm/src/math/exp2.rs | 394 +++++++ .../compiler-builtins/libm/libm/src/math/exp2f.rs | 135 +++ .../compiler-builtins/libm/libm/src/math/expf.rs | 97 ++ .../compiler-builtins/libm/libm/src/math/expm1.rs | 144 +++ .../compiler-builtins/libm/libm/src/math/expm1f.rs | 130 +++ .../compiler-builtins/libm/libm/src/math/expo2.rs | 14 + .../compiler-builtins/libm/libm/src/math/fabs.rs | 116 ++ .../compiler-builtins/libm/libm/src/math/fabsf.rs | 39 + .../libm/libm/src/math/fabsf128.rs | 31 + .../libm/libm/src/math/fabsf16.rs | 31 + .../compiler-builtins/libm/libm/src/math/fdim.rs | 53 + .../compiler-builtins/libm/libm/src/math/fdimf.rs | 12 + .../libm/libm/src/math/fdimf128.rs | 12 + .../libm/libm/src/math/fdimf16.rs | 12 + .../compiler-builtins/libm/libm/src/math/floor.rs | 46 + .../compiler-builtins/libm/libm/src/math/floorf.rs | 13 + .../libm/libm/src/math/floorf128.rs | 7 + .../libm/libm/src/math/floorf16.rs | 7 + .../compiler-builtins/libm/libm/src/math/fma.rs | 397 +++++++ .../libm/libm/src/math/fma_wide.rs | 104 ++ .../libm/libm/src/math/fmin_fmax.rs | 167 +++ .../libm/libm/src/math/fminimum_fmaximum.rs | 163 +++ .../libm/libm/src/math/fminimum_fmaximum_num.rs | 163 +++ .../compiler-builtins/libm/libm/src/math/fmod.rs | 25 + .../compiler-builtins/libm/libm/src/math/fmodf.rs | 5 + .../libm/libm/src/math/fmodf128.rs | 5 + .../libm/libm/src/math/fmodf16.rs | 5 + .../compiler-builtins/libm/libm/src/math/frexp.rs | 21 + .../compiler-builtins/libm/libm/src/math/frexpf.rs | 22 + .../libm/libm/src/math/generic/ceil.rs | 168 +++ .../libm/libm/src/math/generic/copysign.rs | 11 + .../libm/libm/src/math/generic/fabs.rs | 8 + .../libm/libm/src/math/generic/fdim.rs | 6 + .../libm/libm/src/math/generic/floor.rs | 151 +++ .../libm/libm/src/math/generic/fmax.rs | 24 + .../libm/libm/src/math/generic/fmaximum.rs | 28 + .../libm/libm/src/math/generic/fmaximum_num.rs | 27 + .../libm/libm/src/math/generic/fmin.rs | 24 + .../libm/libm/src/math/generic/fminimum.rs | 28 + .../libm/libm/src/math/generic/fminimum_num.rs | 27 + .../libm/libm/src/math/generic/fmod.rs | 84 ++ .../libm/libm/src/math/generic/mod.rs | 38 + .../libm/libm/src/math/generic/rint.rs | 120 ++ .../libm/libm/src/math/generic/round.rs | 83 ++ .../libm/libm/src/math/generic/scalbn.rs | 121 ++ .../libm/libm/src/math/generic/sqrt.rs | 537 +++++++++ .../libm/libm/src/math/generic/trunc.rs | 138 +++ .../compiler-builtins/libm/libm/src/math/hypot.rs | 74 ++ .../compiler-builtins/libm/libm/src/math/hypotf.rs | 43 + .../compiler-builtins/libm/libm/src/math/ilogb.rs | 28 + .../compiler-builtins/libm/libm/src/math/ilogbf.rs | 28 + library/compiler-builtins/libm/libm/src/math/j0.rs | 426 ++++++++ .../compiler-builtins/libm/libm/src/math/j0f.rs | 363 ++++++ library/compiler-builtins/libm/libm/src/math/j1.rs | 418 +++++++ .../compiler-builtins/libm/libm/src/math/j1f.rs | 384 +++++++ library/compiler-builtins/libm/libm/src/math/jn.rs | 339 ++++++ .../compiler-builtins/libm/libm/src/math/jnf.rs | 253 +++++ .../compiler-builtins/libm/libm/src/math/k_cos.rs | 62 ++ .../compiler-builtins/libm/libm/src/math/k_cosf.rs | 29 + .../libm/libm/src/math/k_expo2.rs | 14 + .../libm/libm/src/math/k_expo2f.rs | 14 + .../compiler-builtins/libm/libm/src/math/k_sin.rs | 53 + .../compiler-builtins/libm/libm/src/math/k_sinf.rs | 30 + .../compiler-builtins/libm/libm/src/math/k_tan.rs | 105 ++ .../compiler-builtins/libm/libm/src/math/k_tanf.rs | 46 + .../compiler-builtins/libm/libm/src/math/ldexp.rs | 21 + .../compiler-builtins/libm/libm/src/math/ldexpf.rs | 4 + .../libm/libm/src/math/ldexpf128.rs | 4 + .../libm/libm/src/math/ldexpf16.rs | 4 + .../compiler-builtins/libm/libm/src/math/lgamma.rs | 8 + .../libm/libm/src/math/lgamma_r.rs | 321 ++++++ .../libm/libm/src/math/lgammaf.rs | 8 + .../libm/libm/src/math/lgammaf_r.rs | 256 +++++ .../compiler-builtins/libm/libm/src/math/log.rs | 118 ++ .../compiler-builtins/libm/libm/src/math/log10.rs | 118 ++ .../compiler-builtins/libm/libm/src/math/log10f.rs | 92 ++ .../compiler-builtins/libm/libm/src/math/log1p.rs | 140 +++ .../compiler-builtins/libm/libm/src/math/log1pf.rs | 95 ++ .../compiler-builtins/libm/libm/src/math/log2.rs | 107 ++ .../compiler-builtins/libm/libm/src/math/log2f.rs | 88 ++ .../compiler-builtins/libm/libm/src/math/logf.rs | 66 ++ .../compiler-builtins/libm/libm/src/math/mod.rs | 396 +++++++ .../compiler-builtins/libm/libm/src/math/modf.rs | 35 + .../compiler-builtins/libm/libm/src/math/modff.rs | 34 + .../libm/libm/src/math/nextafter.rs | 37 + .../libm/libm/src/math/nextafterf.rs | 37 + .../compiler-builtins/libm/libm/src/math/pow.rs | 607 ++++++++++ .../compiler-builtins/libm/libm/src/math/powf.rs | 335 ++++++ .../libm/libm/src/math/rem_pio2.rs | 223 ++++ .../libm/libm/src/math/rem_pio2_large.rs | 468 ++++++++ .../libm/libm/src/math/rem_pio2f.rs | 67 ++ .../libm/libm/src/math/remainder.rs | 5 + .../libm/libm/src/math/remainderf.rs | 5 + .../compiler-builtins/libm/libm/src/math/remquo.rs | 106 ++ .../libm/libm/src/math/remquof.rs | 93 ++ .../compiler-builtins/libm/libm/src/math/rint.rs | 51 + .../compiler-builtins/libm/libm/src/math/round.rs | 25 + .../libm/libm/src/math/roundeven.rs | 36 + .../compiler-builtins/libm/libm/src/math/roundf.rs | 5 + .../libm/libm/src/math/roundf128.rs | 5 + .../libm/libm/src/math/roundf16.rs | 5 + .../compiler-builtins/libm/libm/src/math/scalbn.rs | 87 ++ .../libm/libm/src/math/scalbnf.rs | 4 + .../libm/libm/src/math/scalbnf128.rs | 4 + .../libm/libm/src/math/scalbnf16.rs | 4 + .../compiler-builtins/libm/libm/src/math/sin.rs | 95 ++ .../compiler-builtins/libm/libm/src/math/sincos.rs | 137 +++ .../libm/libm/src/math/sincosf.rs | 176 +++ .../compiler-builtins/libm/libm/src/math/sinf.rs | 88 ++ .../compiler-builtins/libm/libm/src/math/sinh.rs | 51 + .../compiler-builtins/libm/libm/src/math/sinhf.rs | 30 + .../compiler-builtins/libm/libm/src/math/sqrt.rs | 51 + .../compiler-builtins/libm/libm/src/math/sqrtf.rs | 15 + .../libm/libm/src/math/sqrtf128.rs | 5 + .../libm/libm/src/math/sqrtf16.rs | 11 + .../libm/libm/src/math/support/big.rs | 239 ++++ .../libm/libm/src/math/support/big/tests.rs | 149 +++ .../libm/libm/src/math/support/env.rs | 127 +++ .../libm/libm/src/math/support/float_traits.rs | 484 ++++++++ .../libm/libm/src/math/support/hex_float.rs | 1155 ++++++++++++++++++++ .../libm/libm/src/math/support/int_traits.rs | 451 ++++++++ .../libm/libm/src/math/support/macros.rs | 157 +++ .../libm/libm/src/math/support/mod.rs | 29 + .../compiler-builtins/libm/libm/src/math/tan.rs | 70 ++ .../compiler-builtins/libm/libm/src/math/tanf.rs | 77 ++ .../compiler-builtins/libm/libm/src/math/tanh.rs | 53 + .../compiler-builtins/libm/libm/src/math/tanhf.rs | 38 + .../compiler-builtins/libm/libm/src/math/tgamma.rs | 209 ++++ .../libm/libm/src/math/tgammaf.rs | 7 + .../compiler-builtins/libm/libm/src/math/trunc.rs | 53 + .../compiler-builtins/libm/libm/src/math/truncf.rs | 23 + .../libm/libm/src/math/truncf128.rs | 7 + .../libm/libm/src/math/truncf16.rs | 7 + library/compiler-builtins/libm/src/lib.rs | 28 - library/compiler-builtins/libm/src/libm_helper.rs | 244 ----- library/compiler-builtins/libm/src/math/acos.rs | 112 -- library/compiler-builtins/libm/src/math/acosf.rs | 79 -- library/compiler-builtins/libm/src/math/acosh.rs | 27 - library/compiler-builtins/libm/src/math/acoshf.rs | 26 - .../libm/src/math/arch/aarch64.rs | 115 -- .../compiler-builtins/libm/src/math/arch/i586.rs | 37 - .../compiler-builtins/libm/src/math/arch/i686.rs | 27 - .../compiler-builtins/libm/src/math/arch/mod.rs | 50 - .../compiler-builtins/libm/src/math/arch/wasm32.rs | 50 - library/compiler-builtins/libm/src/math/asin.rs | 115 -- library/compiler-builtins/libm/src/math/asinf.rs | 68 -- library/compiler-builtins/libm/src/math/asinh.rs | 36 - library/compiler-builtins/libm/src/math/asinhf.rs | 35 - library/compiler-builtins/libm/src/math/atan.rs | 182 --- library/compiler-builtins/libm/src/math/atan2.rs | 131 --- library/compiler-builtins/libm/src/math/atan2f.rs | 90 -- library/compiler-builtins/libm/src/math/atanf.rs | 103 -- library/compiler-builtins/libm/src/math/atanh.rs | 33 - library/compiler-builtins/libm/src/math/atanhf.rs | 33 - library/compiler-builtins/libm/src/math/cbrt.rs | 215 ---- library/compiler-builtins/libm/src/math/cbrtf.rs | 75 -- library/compiler-builtins/libm/src/math/ceil.rs | 46 - .../compiler-builtins/libm/src/math/copysign.rs | 88 -- library/compiler-builtins/libm/src/math/cos.rs | 77 -- library/compiler-builtins/libm/src/math/cosf.rs | 86 -- library/compiler-builtins/libm/src/math/cosh.rs | 36 - library/compiler-builtins/libm/src/math/coshf.rs | 36 - library/compiler-builtins/libm/src/math/erf.rs | 310 ------ library/compiler-builtins/libm/src/math/erff.rs | 222 ---- library/compiler-builtins/libm/src/math/exp.rs | 150 --- library/compiler-builtins/libm/src/math/exp10.rs | 23 - library/compiler-builtins/libm/src/math/exp10f.rs | 22 - library/compiler-builtins/libm/src/math/exp2.rs | 394 ------- library/compiler-builtins/libm/src/math/exp2f.rs | 135 --- library/compiler-builtins/libm/src/math/expf.rs | 97 -- library/compiler-builtins/libm/src/math/expm1.rs | 144 --- library/compiler-builtins/libm/src/math/expm1f.rs | 130 --- library/compiler-builtins/libm/src/math/expo2.rs | 14 - library/compiler-builtins/libm/src/math/fabs.rs | 116 -- library/compiler-builtins/libm/src/math/fdim.rs | 53 - library/compiler-builtins/libm/src/math/floor.rs | 46 - library/compiler-builtins/libm/src/math/fma.rs | 397 ------- .../compiler-builtins/libm/src/math/fma_wide.rs | 104 -- .../compiler-builtins/libm/src/math/fmin_fmax.rs | 167 --- .../libm/src/math/fminimum_fmaximum.rs | 163 --- .../libm/src/math/fminimum_fmaximum_num.rs | 163 --- library/compiler-builtins/libm/src/math/fmod.rs | 25 - library/compiler-builtins/libm/src/math/frexp.rs | 21 - library/compiler-builtins/libm/src/math/frexpf.rs | 22 - .../libm/src/math/generic/ceil.rs | 168 --- .../libm/src/math/generic/copysign.rs | 11 - .../libm/src/math/generic/fabs.rs | 8 - .../libm/src/math/generic/fdim.rs | 6 - .../libm/src/math/generic/floor.rs | 151 --- .../libm/src/math/generic/fmax.rs | 24 - .../libm/src/math/generic/fmaximum.rs | 28 - .../libm/src/math/generic/fmaximum_num.rs | 27 - .../libm/src/math/generic/fmin.rs | 24 - .../libm/src/math/generic/fminimum.rs | 28 - .../libm/src/math/generic/fminimum_num.rs | 27 - .../libm/src/math/generic/fmod.rs | 84 -- .../compiler-builtins/libm/src/math/generic/mod.rs | 38 - .../libm/src/math/generic/rint.rs | 120 -- .../libm/src/math/generic/round.rs | 83 -- .../libm/src/math/generic/scalbn.rs | 121 -- .../libm/src/math/generic/sqrt.rs | 537 --------- .../libm/src/math/generic/trunc.rs | 138 --- library/compiler-builtins/libm/src/math/hypot.rs | 74 -- library/compiler-builtins/libm/src/math/hypotf.rs | 43 - library/compiler-builtins/libm/src/math/ilogb.rs | 28 - library/compiler-builtins/libm/src/math/ilogbf.rs | 28 - library/compiler-builtins/libm/src/math/j0.rs | 426 -------- library/compiler-builtins/libm/src/math/j0f.rs | 363 ------ library/compiler-builtins/libm/src/math/j1.rs | 418 ------- library/compiler-builtins/libm/src/math/j1f.rs | 384 ------- library/compiler-builtins/libm/src/math/jn.rs | 339 ------ library/compiler-builtins/libm/src/math/jnf.rs | 253 ----- library/compiler-builtins/libm/src/math/k_cos.rs | 62 -- library/compiler-builtins/libm/src/math/k_cosf.rs | 29 - library/compiler-builtins/libm/src/math/k_expo2.rs | 14 - .../compiler-builtins/libm/src/math/k_expo2f.rs | 14 - library/compiler-builtins/libm/src/math/k_sin.rs | 53 - library/compiler-builtins/libm/src/math/k_sinf.rs | 30 - library/compiler-builtins/libm/src/math/k_tan.rs | 105 -- library/compiler-builtins/libm/src/math/k_tanf.rs | 46 - library/compiler-builtins/libm/src/math/ldexp.rs | 21 - library/compiler-builtins/libm/src/math/lgamma.rs | 8 - .../compiler-builtins/libm/src/math/lgamma_r.rs | 321 ------ library/compiler-builtins/libm/src/math/lgammaf.rs | 8 - .../compiler-builtins/libm/src/math/lgammaf_r.rs | 256 ----- library/compiler-builtins/libm/src/math/log.rs | 118 -- library/compiler-builtins/libm/src/math/log10.rs | 118 -- library/compiler-builtins/libm/src/math/log10f.rs | 92 -- library/compiler-builtins/libm/src/math/log1p.rs | 140 --- library/compiler-builtins/libm/src/math/log1pf.rs | 95 -- library/compiler-builtins/libm/src/math/log2.rs | 107 -- library/compiler-builtins/libm/src/math/log2f.rs | 88 -- library/compiler-builtins/libm/src/math/logf.rs | 66 -- library/compiler-builtins/libm/src/math/mod.rs | 396 ------- library/compiler-builtins/libm/src/math/modf.rs | 35 - library/compiler-builtins/libm/src/math/modff.rs | 34 - .../compiler-builtins/libm/src/math/nextafter.rs | 37 - .../compiler-builtins/libm/src/math/nextafterf.rs | 37 - library/compiler-builtins/libm/src/math/pow.rs | 607 ---------- library/compiler-builtins/libm/src/math/powf.rs | 335 ------ .../compiler-builtins/libm/src/math/rem_pio2.rs | 223 ---- .../libm/src/math/rem_pio2_large.rs | 468 -------- .../compiler-builtins/libm/src/math/rem_pio2f.rs | 67 -- .../compiler-builtins/libm/src/math/remainder.rs | 5 - .../compiler-builtins/libm/src/math/remainderf.rs | 5 - library/compiler-builtins/libm/src/math/remquo.rs | 106 -- library/compiler-builtins/libm/src/math/remquof.rs | 93 -- library/compiler-builtins/libm/src/math/rint.rs | 51 - library/compiler-builtins/libm/src/math/round.rs | 25 - .../compiler-builtins/libm/src/math/roundeven.rs | 36 - library/compiler-builtins/libm/src/math/scalbn.rs | 87 -- library/compiler-builtins/libm/src/math/sin.rs | 95 -- library/compiler-builtins/libm/src/math/sincos.rs | 137 --- library/compiler-builtins/libm/src/math/sincosf.rs | 176 --- library/compiler-builtins/libm/src/math/sinf.rs | 88 -- library/compiler-builtins/libm/src/math/sinh.rs | 51 - library/compiler-builtins/libm/src/math/sinhf.rs | 30 - library/compiler-builtins/libm/src/math/sqrt.rs | 51 - .../compiler-builtins/libm/src/math/support/big.rs | 239 ---- .../libm/src/math/support/big/tests.rs | 149 --- .../compiler-builtins/libm/src/math/support/env.rs | 127 --- .../libm/src/math/support/float_traits.rs | 484 -------- .../libm/src/math/support/hex_float.rs | 1155 -------------------- .../libm/src/math/support/int_traits.rs | 451 -------- .../libm/src/math/support/macros.rs | 157 --- .../compiler-builtins/libm/src/math/support/mod.rs | 29 - library/compiler-builtins/libm/src/math/tan.rs | 70 -- library/compiler-builtins/libm/src/math/tanf.rs | 77 -- library/compiler-builtins/libm/src/math/tanh.rs | 53 - library/compiler-builtins/libm/src/math/tanhf.rs | 38 - library/compiler-builtins/libm/src/math/tgamma.rs | 209 ---- library/compiler-builtins/libm/src/math/tgammaf.rs | 7 - library/compiler-builtins/libm/src/math/trunc.rs | 53 - 326 files changed, 18162 insertions(+), 17851 deletions(-) delete mode 100644 library/compiler-builtins/libm/Cargo.toml delete mode 100644 library/compiler-builtins/libm/build.rs delete mode 100644 library/compiler-builtins/libm/configure.rs create mode 100644 library/compiler-builtins/libm/libm/Cargo.toml create mode 100644 library/compiler-builtins/libm/libm/build.rs create mode 100644 library/compiler-builtins/libm/libm/configure.rs create mode 100644 library/compiler-builtins/libm/libm/src/lib.rs create mode 100644 library/compiler-builtins/libm/libm/src/libm_helper.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/acos.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/acosf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/acosh.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/acoshf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/arch/aarch64.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/arch/i586.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/arch/i686.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/arch/mod.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/arch/wasm32.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/asin.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/asinf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/asinh.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/asinhf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/atan.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/atan2.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/atan2f.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/atanf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/atanh.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/atanhf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/cbrt.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/cbrtf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/ceil.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/copysign.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/copysignf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/copysignf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/copysignf16.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/cos.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/cosf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/cosh.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/coshf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/erf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/erff.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/exp.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/exp10.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/exp10f.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/exp2.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/exp2f.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/expf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/expm1.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/expm1f.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/expo2.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fabs.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fabsf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fabsf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fabsf16.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fdim.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fdimf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fdimf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fdimf16.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/floor.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/floorf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/floorf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/floorf16.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fma.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fma_wide.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fmin_fmax.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum_num.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fmod.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fmodf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fmodf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fmodf16.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/frexp.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/frexpf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/ceil.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/copysign.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fabs.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fdim.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/floor.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fmax.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fmaximum.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fmaximum_num.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fmin.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fminimum.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fminimum_num.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fmod.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/mod.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/rint.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/round.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/scalbn.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/sqrt.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/generic/trunc.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/hypot.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/hypotf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/ilogb.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/ilogbf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/j0.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/j0f.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/j1.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/j1f.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/jn.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/jnf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/k_cos.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/k_cosf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/k_expo2.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/k_expo2f.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/k_sin.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/k_sinf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/k_tan.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/k_tanf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/ldexp.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/ldexpf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/ldexpf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/ldexpf16.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/lgamma.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/lgamma_r.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/lgammaf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/lgammaf_r.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/log.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/log10.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/log10f.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/log1p.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/log1pf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/log2.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/log2f.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/logf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/mod.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/modf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/modff.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/nextafter.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/nextafterf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/pow.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/powf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/rem_pio2.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/rem_pio2_large.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/rem_pio2f.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/remainder.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/remainderf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/remquo.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/remquof.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/rint.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/round.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/roundeven.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/roundf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/roundf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/roundf16.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/scalbn.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/scalbnf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/scalbnf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/scalbnf16.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/sin.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/sincos.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/sincosf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/sinf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/sinh.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/sinhf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/sqrt.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/sqrtf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/sqrtf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/sqrtf16.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/support/big.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/support/big/tests.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/support/env.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/support/float_traits.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/support/hex_float.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/support/int_traits.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/support/macros.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/support/mod.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/tan.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/tanf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/tanh.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/tanhf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/tgamma.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/tgammaf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/trunc.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/truncf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/truncf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/truncf16.rs delete mode 100644 library/compiler-builtins/libm/src/lib.rs delete mode 100644 library/compiler-builtins/libm/src/libm_helper.rs delete mode 100644 library/compiler-builtins/libm/src/math/acos.rs delete mode 100644 library/compiler-builtins/libm/src/math/acosf.rs delete mode 100644 library/compiler-builtins/libm/src/math/acosh.rs delete mode 100644 library/compiler-builtins/libm/src/math/acoshf.rs delete mode 100644 library/compiler-builtins/libm/src/math/arch/aarch64.rs delete mode 100644 library/compiler-builtins/libm/src/math/arch/i586.rs delete mode 100644 library/compiler-builtins/libm/src/math/arch/i686.rs delete mode 100644 library/compiler-builtins/libm/src/math/arch/mod.rs delete mode 100644 library/compiler-builtins/libm/src/math/arch/wasm32.rs delete mode 100644 library/compiler-builtins/libm/src/math/asin.rs delete mode 100644 library/compiler-builtins/libm/src/math/asinf.rs delete mode 100644 library/compiler-builtins/libm/src/math/asinh.rs delete mode 100644 library/compiler-builtins/libm/src/math/asinhf.rs delete mode 100644 library/compiler-builtins/libm/src/math/atan.rs delete mode 100644 library/compiler-builtins/libm/src/math/atan2.rs delete mode 100644 library/compiler-builtins/libm/src/math/atan2f.rs delete mode 100644 library/compiler-builtins/libm/src/math/atanf.rs delete mode 100644 library/compiler-builtins/libm/src/math/atanh.rs delete mode 100644 library/compiler-builtins/libm/src/math/atanhf.rs delete mode 100644 library/compiler-builtins/libm/src/math/cbrt.rs delete mode 100644 library/compiler-builtins/libm/src/math/cbrtf.rs delete mode 100644 library/compiler-builtins/libm/src/math/ceil.rs delete mode 100644 library/compiler-builtins/libm/src/math/copysign.rs delete mode 100644 library/compiler-builtins/libm/src/math/cos.rs delete mode 100644 library/compiler-builtins/libm/src/math/cosf.rs delete mode 100644 library/compiler-builtins/libm/src/math/cosh.rs delete mode 100644 library/compiler-builtins/libm/src/math/coshf.rs delete mode 100644 library/compiler-builtins/libm/src/math/erf.rs delete mode 100644 library/compiler-builtins/libm/src/math/erff.rs delete mode 100644 library/compiler-builtins/libm/src/math/exp.rs delete mode 100644 library/compiler-builtins/libm/src/math/exp10.rs delete mode 100644 library/compiler-builtins/libm/src/math/exp10f.rs delete mode 100644 library/compiler-builtins/libm/src/math/exp2.rs delete mode 100644 library/compiler-builtins/libm/src/math/exp2f.rs delete mode 100644 library/compiler-builtins/libm/src/math/expf.rs delete mode 100644 library/compiler-builtins/libm/src/math/expm1.rs delete mode 100644 library/compiler-builtins/libm/src/math/expm1f.rs delete mode 100644 library/compiler-builtins/libm/src/math/expo2.rs delete mode 100644 library/compiler-builtins/libm/src/math/fabs.rs delete mode 100644 library/compiler-builtins/libm/src/math/fdim.rs delete mode 100644 library/compiler-builtins/libm/src/math/floor.rs delete mode 100644 library/compiler-builtins/libm/src/math/fma.rs delete mode 100644 library/compiler-builtins/libm/src/math/fma_wide.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmin_fmax.rs delete mode 100644 library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs delete mode 100644 library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmod.rs delete mode 100644 library/compiler-builtins/libm/src/math/frexp.rs delete mode 100644 library/compiler-builtins/libm/src/math/frexpf.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/ceil.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/copysign.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/fabs.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/fdim.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/floor.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/fmax.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/fmaximum.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/fmin.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/fminimum.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/fminimum_num.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/fmod.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/mod.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/rint.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/round.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/scalbn.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/sqrt.rs delete mode 100644 library/compiler-builtins/libm/src/math/generic/trunc.rs delete mode 100644 library/compiler-builtins/libm/src/math/hypot.rs delete mode 100644 library/compiler-builtins/libm/src/math/hypotf.rs delete mode 100644 library/compiler-builtins/libm/src/math/ilogb.rs delete mode 100644 library/compiler-builtins/libm/src/math/ilogbf.rs delete mode 100644 library/compiler-builtins/libm/src/math/j0.rs delete mode 100644 library/compiler-builtins/libm/src/math/j0f.rs delete mode 100644 library/compiler-builtins/libm/src/math/j1.rs delete mode 100644 library/compiler-builtins/libm/src/math/j1f.rs delete mode 100644 library/compiler-builtins/libm/src/math/jn.rs delete mode 100644 library/compiler-builtins/libm/src/math/jnf.rs delete mode 100644 library/compiler-builtins/libm/src/math/k_cos.rs delete mode 100644 library/compiler-builtins/libm/src/math/k_cosf.rs delete mode 100644 library/compiler-builtins/libm/src/math/k_expo2.rs delete mode 100644 library/compiler-builtins/libm/src/math/k_expo2f.rs delete mode 100644 library/compiler-builtins/libm/src/math/k_sin.rs delete mode 100644 library/compiler-builtins/libm/src/math/k_sinf.rs delete mode 100644 library/compiler-builtins/libm/src/math/k_tan.rs delete mode 100644 library/compiler-builtins/libm/src/math/k_tanf.rs delete mode 100644 library/compiler-builtins/libm/src/math/ldexp.rs delete mode 100644 library/compiler-builtins/libm/src/math/lgamma.rs delete mode 100644 library/compiler-builtins/libm/src/math/lgamma_r.rs delete mode 100644 library/compiler-builtins/libm/src/math/lgammaf.rs delete mode 100644 library/compiler-builtins/libm/src/math/lgammaf_r.rs delete mode 100644 library/compiler-builtins/libm/src/math/log.rs delete mode 100644 library/compiler-builtins/libm/src/math/log10.rs delete mode 100644 library/compiler-builtins/libm/src/math/log10f.rs delete mode 100644 library/compiler-builtins/libm/src/math/log1p.rs delete mode 100644 library/compiler-builtins/libm/src/math/log1pf.rs delete mode 100644 library/compiler-builtins/libm/src/math/log2.rs delete mode 100644 library/compiler-builtins/libm/src/math/log2f.rs delete mode 100644 library/compiler-builtins/libm/src/math/logf.rs delete mode 100644 library/compiler-builtins/libm/src/math/mod.rs delete mode 100644 library/compiler-builtins/libm/src/math/modf.rs delete mode 100644 library/compiler-builtins/libm/src/math/modff.rs delete mode 100644 library/compiler-builtins/libm/src/math/nextafter.rs delete mode 100644 library/compiler-builtins/libm/src/math/nextafterf.rs delete mode 100644 library/compiler-builtins/libm/src/math/pow.rs delete mode 100644 library/compiler-builtins/libm/src/math/powf.rs delete mode 100644 library/compiler-builtins/libm/src/math/rem_pio2.rs delete mode 100644 library/compiler-builtins/libm/src/math/rem_pio2_large.rs delete mode 100644 library/compiler-builtins/libm/src/math/rem_pio2f.rs delete mode 100644 library/compiler-builtins/libm/src/math/remainder.rs delete mode 100644 library/compiler-builtins/libm/src/math/remainderf.rs delete mode 100644 library/compiler-builtins/libm/src/math/remquo.rs delete mode 100644 library/compiler-builtins/libm/src/math/remquof.rs delete mode 100644 library/compiler-builtins/libm/src/math/rint.rs delete mode 100644 library/compiler-builtins/libm/src/math/round.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundeven.rs delete mode 100644 library/compiler-builtins/libm/src/math/scalbn.rs delete mode 100644 library/compiler-builtins/libm/src/math/sin.rs delete mode 100644 library/compiler-builtins/libm/src/math/sincos.rs delete mode 100644 library/compiler-builtins/libm/src/math/sincosf.rs delete mode 100644 library/compiler-builtins/libm/src/math/sinf.rs delete mode 100644 library/compiler-builtins/libm/src/math/sinh.rs delete mode 100644 library/compiler-builtins/libm/src/math/sinhf.rs delete mode 100644 library/compiler-builtins/libm/src/math/sqrt.rs delete mode 100644 library/compiler-builtins/libm/src/math/support/big.rs delete mode 100644 library/compiler-builtins/libm/src/math/support/big/tests.rs delete mode 100644 library/compiler-builtins/libm/src/math/support/env.rs delete mode 100644 library/compiler-builtins/libm/src/math/support/float_traits.rs delete mode 100644 library/compiler-builtins/libm/src/math/support/hex_float.rs delete mode 100644 library/compiler-builtins/libm/src/math/support/int_traits.rs delete mode 100644 library/compiler-builtins/libm/src/math/support/macros.rs delete mode 100644 library/compiler-builtins/libm/src/math/support/mod.rs delete mode 100644 library/compiler-builtins/libm/src/math/tan.rs delete mode 100644 library/compiler-builtins/libm/src/math/tanf.rs delete mode 100644 library/compiler-builtins/libm/src/math/tanh.rs delete mode 100644 library/compiler-builtins/libm/src/math/tanhf.rs delete mode 100644 library/compiler-builtins/libm/src/math/tgamma.rs delete mode 100644 library/compiler-builtins/libm/src/math/tgammaf.rs delete mode 100644 library/compiler-builtins/libm/src/math/trunc.rs diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index c925e63aa59..a717c3ea8f8 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -213,7 +213,7 @@ jobs: steps: - uses: actions/checkout@master - run: | - msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' Cargo.toml)" + msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' libm/Cargo.toml)" echo "MSRV: $msrv" echo "MSRV=$msrv" >> "$GITHUB_ENV" - name: Install Rust diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml deleted file mode 100644 index e0aeb07d527..00000000000 --- a/library/compiler-builtins/libm/Cargo.toml +++ /dev/null @@ -1,87 +0,0 @@ -[package] -authors = ["Jorge Aparicio "] -categories = ["no-std"] -description = "libm in pure Rust" -documentation = "https://docs.rs/libm" -keywords = ["libm", "math"] -license = "MIT" -name = "libm" -readme = "README.md" -repository = "https://github.com/rust-lang/libm" -version = "0.2.11" -edition = "2021" -exclude = ["/ci/", "/.github/workflows/"] -rust-version = "1.63" - -[features] -default = ["arch"] - -# Enable architecture-specific features such as SIMD or assembly routines. -arch = [] - -# This tells the compiler to assume that a Nightly toolchain is being used and -# that it should activate any useful Nightly things accordingly. -unstable = ["unstable-intrinsics", "unstable-float"] - -# Enable calls to functions in `core::intrinsics` -unstable-intrinsics = [] - -# Make some internal things public for testing. -unstable-public-internals = [] - -# Enable the nightly-only `f16` and `f128`. -unstable-float = [] - -# Used to prevent using any intrinsics or arch-specific code. -# -# HACK: this is a negative feature which is generally a bad idea in Cargo, but -# we need it to be able to forbid other features when this crate is used in -# Rust dependencies. Setting this overrides all features that may enable -# hard float operations. -force-soft-floats = [] - -[workspace] -resolver = "2" -members = [ - "crates/libm-macros", - "crates/libm-test", - "crates/musl-math-sys", - "crates/util", -] -default-members = [ - ".", - "crates/libm-macros", - "crates/libm-test", -] -exclude = [ - # Requires `panic = abort` so can't be a member of the workspace - "crates/compiler-builtins-smoke-test", -] - -[dev-dependencies] -no-panic = "0.1.35" - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = [ - # compiler-builtins sets this feature, but we use it in `libm` - 'cfg(feature, values("compiler-builtins"))', -] } - -# The default release profile is unchanged. - -# Release mode with debug assertions -[profile.release-checked] -inherits = "release" -debug-assertions = true -overflow-checks = true - -# Release with maximum optimizations, which is very slow to build. This is also -# what is needed to check `no-panic`. -[profile.release-opt] -inherits = "release" -codegen-units = 1 -lto = "fat" - -[profile.bench] -# Required for iai-callgrind -debug = true diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs deleted file mode 100644 index 7042b54d7e8..00000000000 --- a/library/compiler-builtins/libm/build.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::env; - -mod configure; - -fn main() { - let cfg = configure::Config::from_env(); - - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); - - // If set, enable `no-panic`. Requires LTO (`release-opt` profile). - if env::var("ENSURE_NO_PANIC").is_ok() { - println!("cargo:rustc-cfg=assert_no_panic"); - } - - configure::emit_libm_config(&cfg); -} diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index 7468fd690cb..ed63d6deea1 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -63,9 +63,9 @@ MANY_EXTENSIVE_THRESHOLD = 20 # Don't run exhaustive tests if these files change, even if they contaiin a function # definition. IGNORE_FILES = [ - "src/math/support/", - "src/libm_helper.rs", - "src/math/arch/intrinsics.rs", + "libm/src/math/support/", + "libm/src/libm_helper.rs", + "libm/src/math/arch/intrinsics.rs", ] TYPES = ["f16", "f32", "f64", "f128"] diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs deleted file mode 100644 index 8b8ba981565..00000000000 --- a/library/compiler-builtins/libm/configure.rs +++ /dev/null @@ -1,183 +0,0 @@ -// Configuration shared with both libm and libm-test - -use std::env; -use std::path::PathBuf; - -#[allow(dead_code)] -pub struct Config { - pub manifest_dir: PathBuf, - pub out_dir: PathBuf, - pub opt_level: String, - pub cargo_features: Vec, - pub target_arch: String, - pub target_env: String, - pub target_family: Option, - pub target_os: String, - pub target_string: String, - pub target_vendor: String, - pub target_features: Vec, -} - -impl Config { - pub fn from_env() -> Self { - let target_features = env::var("CARGO_CFG_TARGET_FEATURE") - .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) - .unwrap_or_default(); - let cargo_features = env::vars() - .filter_map(|(name, _value)| name.strip_prefix("CARGO_FEATURE_").map(ToOwned::to_owned)) - .map(|s| s.to_lowercase().replace("_", "-")) - .collect(); - - Self { - manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()), - out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), - opt_level: env::var("OPT_LEVEL").unwrap(), - cargo_features, - target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), - target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), - target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(), - target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), - target_string: env::var("TARGET").unwrap(), - target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), - target_features, - } - } -} - -/// Libm gets most config options made available. -#[allow(dead_code)] -pub fn emit_libm_config(cfg: &Config) { - emit_intrinsics_cfg(); - emit_arch_cfg(); - emit_optimization_cfg(cfg); - emit_cfg_shorthands(cfg); - emit_cfg_env(cfg); - emit_f16_f128_cfg(cfg); -} - -/// Tests don't need most feature-related config. -#[allow(dead_code)] -pub fn emit_test_config(cfg: &Config) { - emit_optimization_cfg(cfg); - emit_cfg_shorthands(cfg); - emit_cfg_env(cfg); - emit_f16_f128_cfg(cfg); -} - -/// Simplify the feature logic for enabling intrinsics so code only needs to use -/// `cfg(intrinsics_enabled)`. -fn emit_intrinsics_cfg() { - println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)"); - - // Disabled by default; `unstable-intrinsics` enables again; `force-soft-floats` overrides - // to disable. - if cfg!(feature = "unstable-intrinsics") && !cfg!(feature = "force-soft-floats") { - println!("cargo:rustc-cfg=intrinsics_enabled"); - } -} - -/// Simplify the feature logic for enabling arch-specific features so code only needs to use -/// `cfg(arch_enabled)`. -fn emit_arch_cfg() { - println!("cargo:rustc-check-cfg=cfg(arch_enabled)"); - - // Enabled by default via the "arch" feature, `force-soft-floats` overrides to disable. - if cfg!(feature = "arch") && !cfg!(feature = "force-soft-floats") { - println!("cargo:rustc-cfg=arch_enabled"); - } -} - -/// Some tests are extremely slow. Emit a config option based on optimization level. -fn emit_optimization_cfg(cfg: &Config) { - println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); - - if !matches!(cfg.opt_level.as_str(), "0" | "1") { - println!("cargo:rustc-cfg=optimizations_enabled"); - } -} - -/// Provide an alias for common longer config combinations. -fn emit_cfg_shorthands(cfg: &Config) { - println!("cargo:rustc-check-cfg=cfg(x86_no_sse)"); - if cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse") { - // Shorthand to detect i586 targets - println!("cargo:rustc-cfg=x86_no_sse"); - } -} - -/// Reemit config that we make use of for test logging. -fn emit_cfg_env(cfg: &Config) { - println!("cargo:rustc-env=CFG_CARGO_FEATURES={:?}", cfg.cargo_features); - println!("cargo:rustc-env=CFG_OPT_LEVEL={}", cfg.opt_level); - println!("cargo:rustc-env=CFG_TARGET_FEATURES={:?}", cfg.target_features); -} - -/// Configure whether or not `f16` and `f128` support should be enabled. -fn emit_f16_f128_cfg(cfg: &Config) { - println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); - println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); - - // `unstable-float` enables these features. - if !cfg!(feature = "unstable-float") { - return; - } - - // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means - // that the backend will not crash when using these types and generates code that can be called - // without crashing (no infinite recursion). This does not mean that the platform doesn't have - // ABI or other bugs. - // - // We do this here rather than in `rust-lang/rust` because configuring via cargo features is - // not straightforward. - // - // Original source of this list: - // - let f16_enabled = match cfg.target_arch.as_str() { - // Unsupported - "arm64ec" => false, - // Selection failure - "s390x" => false, - // Infinite recursion - // FIXME(llvm): loongarch fixed by - "csky" => false, - "hexagon" => false, - "loongarch64" => false, - "mips" | "mips64" | "mips32r6" | "mips64r6" => false, - "powerpc" | "powerpc64" => false, - "sparc" | "sparc64" => false, - "wasm32" | "wasm64" => false, - // Most everything else works as of LLVM 19 - _ => true, - }; - - let f128_enabled = match cfg.target_arch.as_str() { - // Unsupported (libcall is not supported) - "amdgpu" => false, - // Unsupported - "arm64ec" => false, - // Selection failure - "mips64" | "mips64r6" => false, - // Selection failure - "nvptx64" => false, - // Selection failure - "powerpc64" if &cfg.target_os == "aix" => false, - // Selection failure - "sparc" => false, - // Most everything else works as of LLVM 19 - _ => true, - }; - - // If the feature is set, disable these types. - let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); - - println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); - println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); - - if f16_enabled && !disable_both { - println!("cargo:rustc-cfg=f16_enabled"); - } - - if f128_enabled && !disable_both { - println!("cargo:rustc-cfg=f128_enabled"); - } -} diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs index 4ee5ab585d5..ef8d613c9f4 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs @@ -1,8 +1,8 @@ -#[path = "../../configure.rs"] +#[path = "../../libm/configure.rs"] mod configure; fn main() { - println!("cargo:rerun-if-changed=../../configure.rs"); + println!("cargo:rerun-if-changed=../../libm/configure.rs"); let cfg = configure::Config::from_env(); configure::emit_libm_config(&cfg); } diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs index 7e0146998aa..f17fc123168 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs @@ -3,7 +3,7 @@ use core::ffi::c_int; #[allow(dead_code)] #[allow(clippy::all)] // We don't get `libm`'s list of `allow`s, so just ignore Clippy. #[allow(unused_imports)] -#[path = "../../../src/math/mod.rs"] +#[path = "../../../libm/src/math/mod.rs"] pub mod libm; /// Mark functions `#[no_mangle]` and with the C ABI. diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 98da73ceadc..1bcc163ed1b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -32,7 +32,7 @@ anyhow = "1.0.97" gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } iai-callgrind = { version = "0.14.0", optional = true } indicatif = { version = "0.17.11", default-features = false } -libm = { path = "../..", features = ["unstable-public-internals"] } +libm = { path = "../../libm", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } paste = "1.0.15" diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index d2d0df9cbe9..f75e3dda5ff 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -1,9 +1,9 @@ -#[path = "../../configure.rs"] +#[path = "../../libm/configure.rs"] mod configure; use configure::Config; fn main() { - println!("cargo:rerun-if-changed=../../configure.rs"); + println!("cargo:rerun-if-changed=../../libm/configure.rs"); let cfg = Config::from_env(); configure::emit_test_config(&cfg); } diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml index 34682b74c67..ad73578d8b8 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml +++ b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] [dev-dependencies] -libm = { path = "../../" } +libm = { path = "../../libm" } [build-dependencies] cc = "1.2.16" diff --git a/library/compiler-builtins/libm/crates/util/Cargo.toml b/library/compiler-builtins/libm/crates/util/Cargo.toml index 8005459dbf9..94c7f103340 100644 --- a/library/compiler-builtins/libm/crates/util/Cargo.toml +++ b/library/compiler-builtins/libm/crates/util/Cargo.toml @@ -11,7 +11,7 @@ build-mpfr = ["libm-test/build-mpfr", "dep:rug"] unstable-float = ["libm/unstable-float", "libm-test/unstable-float", "rug?/nightly-float"] [dependencies] -libm = { path = "../..", default-features = false } +libm = { path = "../../libm", default-features = false } libm-macros = { path = "../libm-macros" } libm-test = { path = "../libm-test", default-features = false } musl-math-sys = { path = "../musl-math-sys", optional = true } diff --git a/library/compiler-builtins/libm/crates/util/build.rs b/library/compiler-builtins/libm/crates/util/build.rs index b6cceb5f11b..a1be4127527 100644 --- a/library/compiler-builtins/libm/crates/util/build.rs +++ b/library/compiler-builtins/libm/crates/util/build.rs @@ -1,10 +1,10 @@ #![allow(unexpected_cfgs)] -#[path = "../../configure.rs"] +#[path = "../../libm/configure.rs"] mod configure; fn main() { - println!("cargo:rerun-if-changed=../../configure.rs"); + println!("cargo:rerun-if-changed=../../libm/configure.rs"); let cfg = configure::Config::from_env(); configure::emit_libm_config(&cfg); } diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index b4ce2c453ce..950824fc442 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -18,7 +18,7 @@ from typing import Any, Callable, TypeAlias SELF_PATH = Path(__file__) ETC_DIR = SELF_PATH.parent -ROOT_DIR = ETC_DIR.parent +LIBM_DIR = ETC_DIR.parent.joinpath("libm") # These files do not trigger a retest. IGNORED_SOURCES = ["src/libm_helper.rs", "src/math/support/float_traits.rs"] @@ -75,7 +75,7 @@ class Crate: "-Zunstable-options", "-o-", ], - cwd=ROOT_DIR, + cwd=LIBM_DIR, text=True, ) j = json.loads(j) @@ -121,8 +121,8 @@ class Crate: # A lot of the `arch` module is often configured out so doesn't show up in docs. Use # string matching as a fallback. - for fname in glob("src/math/arch/**.rs", root_dir=ROOT_DIR): - contents = (ROOT_DIR.joinpath(fname)).read_text() + for fname in glob("src/math/arch/**.rs", root_dir=LIBM_DIR): + contents = (LIBM_DIR.joinpath(fname)).read_text() for name in self.public_functions: if f"fn {name}" in contents: @@ -188,10 +188,10 @@ class Crate: include all public API. """ - flist = sp.check_output(["git", "ls-files"], cwd=ROOT_DIR, text=True) + flist = sp.check_output(["git", "ls-files"], cwd=LIBM_DIR, text=True) for path in flist.splitlines(): - fpath = ROOT_DIR.joinpath(path) + fpath = LIBM_DIR.joinpath(path) if fpath.is_dir() or fpath == SELF_PATH: continue @@ -229,7 +229,7 @@ class Crate: if len(not_found) == 0: return - relpath = fpath.relative_to(ROOT_DIR) + relpath = fpath.relative_to(LIBM_DIR) eprint(f"functions not found at {relpath}:{line_num}: {not_found}") exit(1) @@ -244,7 +244,7 @@ def validate_delimited_block( """Identify blocks of code wrapped within `start` and `end`, collect their contents to a list of strings, and call `validate` for each of those lists. """ - relpath = fpath.relative_to(ROOT_DIR) + relpath = fpath.relative_to(LIBM_DIR) block_lines = [] block_start_line: None | int = None for line_num, line in enumerate(lines): @@ -274,7 +274,7 @@ def validate_delimited_block( def ensure_sorted(fpath: Path, block_start_line: int, lines: list[str]) -> None: """Ensure that a list of lines is sorted, otherwise print a diff and exit.""" - relpath = fpath.relative_to(ROOT_DIR) + relpath = fpath.relative_to(LIBM_DIR) diff_and_exit( "\n".join(lines), "\n".join(sorted(lines)), diff --git a/library/compiler-builtins/libm/libm/Cargo.toml b/library/compiler-builtins/libm/libm/Cargo.toml new file mode 100644 index 00000000000..e0aeb07d527 --- /dev/null +++ b/library/compiler-builtins/libm/libm/Cargo.toml @@ -0,0 +1,87 @@ +[package] +authors = ["Jorge Aparicio "] +categories = ["no-std"] +description = "libm in pure Rust" +documentation = "https://docs.rs/libm" +keywords = ["libm", "math"] +license = "MIT" +name = "libm" +readme = "README.md" +repository = "https://github.com/rust-lang/libm" +version = "0.2.11" +edition = "2021" +exclude = ["/ci/", "/.github/workflows/"] +rust-version = "1.63" + +[features] +default = ["arch"] + +# Enable architecture-specific features such as SIMD or assembly routines. +arch = [] + +# This tells the compiler to assume that a Nightly toolchain is being used and +# that it should activate any useful Nightly things accordingly. +unstable = ["unstable-intrinsics", "unstable-float"] + +# Enable calls to functions in `core::intrinsics` +unstable-intrinsics = [] + +# Make some internal things public for testing. +unstable-public-internals = [] + +# Enable the nightly-only `f16` and `f128`. +unstable-float = [] + +# Used to prevent using any intrinsics or arch-specific code. +# +# HACK: this is a negative feature which is generally a bad idea in Cargo, but +# we need it to be able to forbid other features when this crate is used in +# Rust dependencies. Setting this overrides all features that may enable +# hard float operations. +force-soft-floats = [] + +[workspace] +resolver = "2" +members = [ + "crates/libm-macros", + "crates/libm-test", + "crates/musl-math-sys", + "crates/util", +] +default-members = [ + ".", + "crates/libm-macros", + "crates/libm-test", +] +exclude = [ + # Requires `panic = abort` so can't be a member of the workspace + "crates/compiler-builtins-smoke-test", +] + +[dev-dependencies] +no-panic = "0.1.35" + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = [ + # compiler-builtins sets this feature, but we use it in `libm` + 'cfg(feature, values("compiler-builtins"))', +] } + +# The default release profile is unchanged. + +# Release mode with debug assertions +[profile.release-checked] +inherits = "release" +debug-assertions = true +overflow-checks = true + +# Release with maximum optimizations, which is very slow to build. This is also +# what is needed to check `no-panic`. +[profile.release-opt] +inherits = "release" +codegen-units = 1 +lto = "fat" + +[profile.bench] +# Required for iai-callgrind +debug = true diff --git a/library/compiler-builtins/libm/libm/build.rs b/library/compiler-builtins/libm/libm/build.rs new file mode 100644 index 00000000000..07d08ed4364 --- /dev/null +++ b/library/compiler-builtins/libm/libm/build.rs @@ -0,0 +1,18 @@ +use std::env; + +mod configure; + +fn main() { + let cfg = configure::Config::from_env(); + + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=configure.rs"); + println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); + + // If set, enable `no-panic`. Requires LTO (`release-opt` profile). + if env::var("ENSURE_NO_PANIC").is_ok() { + println!("cargo:rustc-cfg=assert_no_panic"); + } + + configure::emit_libm_config(&cfg); +} diff --git a/library/compiler-builtins/libm/libm/configure.rs b/library/compiler-builtins/libm/libm/configure.rs new file mode 100644 index 00000000000..8b8ba981565 --- /dev/null +++ b/library/compiler-builtins/libm/libm/configure.rs @@ -0,0 +1,183 @@ +// Configuration shared with both libm and libm-test + +use std::env; +use std::path::PathBuf; + +#[allow(dead_code)] +pub struct Config { + pub manifest_dir: PathBuf, + pub out_dir: PathBuf, + pub opt_level: String, + pub cargo_features: Vec, + pub target_arch: String, + pub target_env: String, + pub target_family: Option, + pub target_os: String, + pub target_string: String, + pub target_vendor: String, + pub target_features: Vec, +} + +impl Config { + pub fn from_env() -> Self { + let target_features = env::var("CARGO_CFG_TARGET_FEATURE") + .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) + .unwrap_or_default(); + let cargo_features = env::vars() + .filter_map(|(name, _value)| name.strip_prefix("CARGO_FEATURE_").map(ToOwned::to_owned)) + .map(|s| s.to_lowercase().replace("_", "-")) + .collect(); + + Self { + manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()), + out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), + opt_level: env::var("OPT_LEVEL").unwrap(), + cargo_features, + target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), + target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), + target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(), + target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + target_string: env::var("TARGET").unwrap(), + target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), + target_features, + } + } +} + +/// Libm gets most config options made available. +#[allow(dead_code)] +pub fn emit_libm_config(cfg: &Config) { + emit_intrinsics_cfg(); + emit_arch_cfg(); + emit_optimization_cfg(cfg); + emit_cfg_shorthands(cfg); + emit_cfg_env(cfg); + emit_f16_f128_cfg(cfg); +} + +/// Tests don't need most feature-related config. +#[allow(dead_code)] +pub fn emit_test_config(cfg: &Config) { + emit_optimization_cfg(cfg); + emit_cfg_shorthands(cfg); + emit_cfg_env(cfg); + emit_f16_f128_cfg(cfg); +} + +/// Simplify the feature logic for enabling intrinsics so code only needs to use +/// `cfg(intrinsics_enabled)`. +fn emit_intrinsics_cfg() { + println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)"); + + // Disabled by default; `unstable-intrinsics` enables again; `force-soft-floats` overrides + // to disable. + if cfg!(feature = "unstable-intrinsics") && !cfg!(feature = "force-soft-floats") { + println!("cargo:rustc-cfg=intrinsics_enabled"); + } +} + +/// Simplify the feature logic for enabling arch-specific features so code only needs to use +/// `cfg(arch_enabled)`. +fn emit_arch_cfg() { + println!("cargo:rustc-check-cfg=cfg(arch_enabled)"); + + // Enabled by default via the "arch" feature, `force-soft-floats` overrides to disable. + if cfg!(feature = "arch") && !cfg!(feature = "force-soft-floats") { + println!("cargo:rustc-cfg=arch_enabled"); + } +} + +/// Some tests are extremely slow. Emit a config option based on optimization level. +fn emit_optimization_cfg(cfg: &Config) { + println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); + + if !matches!(cfg.opt_level.as_str(), "0" | "1") { + println!("cargo:rustc-cfg=optimizations_enabled"); + } +} + +/// Provide an alias for common longer config combinations. +fn emit_cfg_shorthands(cfg: &Config) { + println!("cargo:rustc-check-cfg=cfg(x86_no_sse)"); + if cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse") { + // Shorthand to detect i586 targets + println!("cargo:rustc-cfg=x86_no_sse"); + } +} + +/// Reemit config that we make use of for test logging. +fn emit_cfg_env(cfg: &Config) { + println!("cargo:rustc-env=CFG_CARGO_FEATURES={:?}", cfg.cargo_features); + println!("cargo:rustc-env=CFG_OPT_LEVEL={}", cfg.opt_level); + println!("cargo:rustc-env=CFG_TARGET_FEATURES={:?}", cfg.target_features); +} + +/// Configure whether or not `f16` and `f128` support should be enabled. +fn emit_f16_f128_cfg(cfg: &Config) { + println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); + println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); + + // `unstable-float` enables these features. + if !cfg!(feature = "unstable-float") { + return; + } + + // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means + // that the backend will not crash when using these types and generates code that can be called + // without crashing (no infinite recursion). This does not mean that the platform doesn't have + // ABI or other bugs. + // + // We do this here rather than in `rust-lang/rust` because configuring via cargo features is + // not straightforward. + // + // Original source of this list: + // + let f16_enabled = match cfg.target_arch.as_str() { + // Unsupported + "arm64ec" => false, + // Selection failure + "s390x" => false, + // Infinite recursion + // FIXME(llvm): loongarch fixed by + "csky" => false, + "hexagon" => false, + "loongarch64" => false, + "mips" | "mips64" | "mips32r6" | "mips64r6" => false, + "powerpc" | "powerpc64" => false, + "sparc" | "sparc64" => false, + "wasm32" | "wasm64" => false, + // Most everything else works as of LLVM 19 + _ => true, + }; + + let f128_enabled = match cfg.target_arch.as_str() { + // Unsupported (libcall is not supported) + "amdgpu" => false, + // Unsupported + "arm64ec" => false, + // Selection failure + "mips64" | "mips64r6" => false, + // Selection failure + "nvptx64" => false, + // Selection failure + "powerpc64" if &cfg.target_os == "aix" => false, + // Selection failure + "sparc" => false, + // Most everything else works as of LLVM 19 + _ => true, + }; + + // If the feature is set, disable these types. + let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); + + println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); + println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); + + if f16_enabled && !disable_both { + println!("cargo:rustc-cfg=f16_enabled"); + } + + if f128_enabled && !disable_both { + println!("cargo:rustc-cfg=f128_enabled"); + } +} diff --git a/library/compiler-builtins/libm/libm/src/lib.rs b/library/compiler-builtins/libm/libm/src/lib.rs new file mode 100644 index 00000000000..b0e4312110f --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/lib.rs @@ -0,0 +1,28 @@ +//! libm in pure Rust +#![no_std] +#![cfg_attr(intrinsics_enabled, allow(internal_features))] +#![cfg_attr(intrinsics_enabled, feature(core_intrinsics))] +#![cfg_attr(all(intrinsics_enabled, target_family = "wasm"), feature(wasm_numeric_instr))] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] +#![allow(clippy::assign_op_pattern)] +#![allow(clippy::deprecated_cfg_attr)] +#![allow(clippy::eq_op)] +#![allow(clippy::excessive_precision)] +#![allow(clippy::float_cmp)] +#![allow(clippy::int_plus_one)] +#![allow(clippy::many_single_char_names)] +#![allow(clippy::mixed_case_hex_literals)] +#![allow(clippy::needless_late_init)] +#![allow(clippy::needless_return)] +#![allow(clippy::unreadable_literal)] +#![allow(clippy::zero_divided_by_zero)] + +mod libm_helper; +mod math; + +use core::{f32, f64}; + +pub use libm_helper::*; + +pub use self::math::*; diff --git a/library/compiler-builtins/libm/libm/src/libm_helper.rs b/library/compiler-builtins/libm/libm/src/libm_helper.rs new file mode 100644 index 00000000000..dfa1ff77bf2 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/libm_helper.rs @@ -0,0 +1,244 @@ +use core::marker::PhantomData; + +use crate::*; + +/// Generic helper for libm functions, abstracting over f32 and f64.
+/// # Type Parameter: +/// - `T`: Either `f32` or `f64` +/// +/// # Examples +/// ```rust +/// use libm::{self, Libm}; +/// +/// const PI_F32: f32 = 3.1415927410e+00; +/// const PI_F64: f64 = 3.1415926535897931160e+00; +/// +/// assert!(Libm::::cos(0.0f32) == libm::cosf(0.0)); +/// assert!(Libm::::sin(PI_F32) == libm::sinf(PI_F32)); +/// +/// assert!(Libm::::cos(0.0f64) == libm::cos(0.0)); +/// assert!(Libm::::sin(PI_F64) == libm::sin(PI_F64)); +/// ``` +pub struct Libm(PhantomData); + +macro_rules! libm_helper { + ($t:ident, funcs: $funcs:tt) => { + impl Libm<$t> { + #![allow(unused_parens)] + + libm_helper! { $funcs } + } + }; + + ({$($func:tt;)*}) => { + $( + libm_helper! { $func } + )* + }; + + ((fn $func:ident($($arg:ident: $arg_typ:ty),*) -> ($($ret_typ:ty),*); => $libm_fn:ident)) => { + #[inline(always)] + pub fn $func($($arg: $arg_typ),*) -> ($($ret_typ),*) { + $libm_fn($($arg),*) + } + }; +} + +// verify-apilist-start +libm_helper! { + f32, + funcs: { + // verify-sorted-start + (fn acos(x: f32) -> (f32); => acosf); + (fn acosh(x: f32) -> (f32); => acoshf); + (fn asin(x: f32) -> (f32); => asinf); + (fn asinh(x: f32) -> (f32); => asinhf); + (fn atan(x: f32) -> (f32); => atanf); + (fn atan2(y: f32, x: f32) -> (f32); => atan2f); + (fn atanh(x: f32) -> (f32); => atanhf); + (fn cbrt(x: f32) -> (f32); => cbrtf); + (fn ceil(x: f32) -> (f32); => ceilf); + (fn copysign(x: f32, y: f32) -> (f32); => copysignf); + (fn cos(x: f32) -> (f32); => cosf); + (fn cosh(x: f32) -> (f32); => coshf); + (fn erf(x: f32) -> (f32); => erff); + (fn erfc(x: f32) -> (f32); => erfcf); + (fn exp(x: f32) -> (f32); => expf); + (fn exp10(x: f32) -> (f32); => exp10f); + (fn exp2(x: f32) -> (f32); => exp2f); + (fn expm1(x: f32) -> (f32); => expm1f); + (fn fabs(x: f32) -> (f32); => fabsf); + (fn fdim(x: f32, y: f32) -> (f32); => fdimf); + (fn floor(x: f32) -> (f32); => floorf); + (fn fma(x: f32, y: f32, z: f32) -> (f32); => fmaf); + (fn fmax(x: f32, y: f32) -> (f32); => fmaxf); + (fn fmin(x: f32, y: f32) -> (f32); => fminf); + (fn fmod(x: f32, y: f32) -> (f32); => fmodf); + (fn frexp(x: f32) -> (f32, i32); => frexpf); + (fn hypot(x: f32, y: f32) -> (f32); => hypotf); + (fn ilogb(x: f32) -> (i32); => ilogbf); + (fn j0(x: f32) -> (f32); => j0f); + (fn j1(x: f32) -> (f32); => j1f); + (fn jn(n: i32, x: f32) -> (f32); => jnf); + (fn ldexp(x: f32, n: i32) -> (f32); => ldexpf); + (fn lgamma(x: f32) -> (f32); => lgammaf); + (fn lgamma_r(x: f32) -> (f32, i32); => lgammaf_r); + (fn log(x: f32) -> (f32); => logf); + (fn log10(x: f32) -> (f32); => log10f); + (fn log1p(x: f32) -> (f32); => log1pf); + (fn log2(x: f32) -> (f32); => log2f); + (fn modf(x: f32) -> (f32, f32); => modff); + (fn nextafter(x: f32, y: f32) -> (f32); => nextafterf); + (fn pow(x: f32, y: f32) -> (f32); => powf); + (fn remainder(x: f32, y: f32) -> (f32); => remainderf); + (fn remquo(x: f32, y: f32) -> (f32, i32); => remquof); + (fn rint(x: f32) -> (f32); => rintf); + (fn round(x: f32) -> (f32); => roundf); + (fn roundeven(x: f32) -> (f32); => roundevenf); + (fn scalbn(x: f32, n: i32) -> (f32); => scalbnf); + (fn sin(x: f32) -> (f32); => sinf); + (fn sincos(x: f32) -> (f32, f32); => sincosf); + (fn sinh(x: f32) -> (f32); => sinhf); + (fn sqrt(x: f32) -> (f32); => sqrtf); + (fn tan(x: f32) -> (f32); => tanf); + (fn tanh(x: f32) -> (f32); => tanhf); + (fn tgamma(x: f32) -> (f32); => tgammaf); + (fn trunc(x: f32) -> (f32); => truncf); + (fn y0(x: f32) -> (f32); => y0f); + (fn y1(x: f32) -> (f32); => y1f); + (fn yn(n: i32, x: f32) -> (f32); => ynf); + // verify-sorted-end + } +} + +libm_helper! { + f64, + funcs: { + // verify-sorted-start + (fn acos(x: f64) -> (f64); => acos); + (fn acosh(x: f64) -> (f64); => acosh); + (fn asin(x: f64) -> (f64); => asin); + (fn asinh(x: f64) -> (f64); => asinh); + (fn atan(x: f64) -> (f64); => atan); + (fn atan2(y: f64, x: f64) -> (f64); => atan2); + (fn atanh(x: f64) -> (f64); => atanh); + (fn cbrt(x: f64) -> (f64); => cbrt); + (fn ceil(x: f64) -> (f64); => ceil); + (fn copysign(x: f64, y: f64) -> (f64); => copysign); + (fn cos(x: f64) -> (f64); => cos); + (fn cosh(x: f64) -> (f64); => cosh); + (fn erf(x: f64) -> (f64); => erf); + (fn erfc(x: f64) -> (f64); => erfc); + (fn exp(x: f64) -> (f64); => exp); + (fn exp10(x: f64) -> (f64); => exp10); + (fn exp2(x: f64) -> (f64); => exp2); + (fn expm1(x: f64) -> (f64); => expm1); + (fn fabs(x: f64) -> (f64); => fabs); + (fn fdim(x: f64, y: f64) -> (f64); => fdim); + (fn floor(x: f64) -> (f64); => floor); + (fn fma(x: f64, y: f64, z: f64) -> (f64); => fma); + (fn fmax(x: f64, y: f64) -> (f64); => fmax); + (fn fmaximum(x: f64, y: f64) -> (f64); => fmaximum); + (fn fmaximum_num(x: f64, y: f64) -> (f64); => fmaximum_num); + (fn fmaximum_numf(x: f32, y: f32) -> (f32); => fmaximum_numf); + (fn fmaximumf(x: f32, y: f32) -> (f32); => fmaximumf); + (fn fmin(x: f64, y: f64) -> (f64); => fmin); + (fn fminimum(x: f64, y: f64) -> (f64); => fminimum); + (fn fminimum_num(x: f64, y: f64) -> (f64); => fminimum_num); + (fn fminimum_numf(x: f32, y: f32) -> (f32); => fminimum_numf); + (fn fminimumf(x: f32, y: f32) -> (f32); => fminimumf); + (fn fmod(x: f64, y: f64) -> (f64); => fmod); + (fn frexp(x: f64) -> (f64, i32); => frexp); + (fn hypot(x: f64, y: f64) -> (f64); => hypot); + (fn ilogb(x: f64) -> (i32); => ilogb); + (fn j0(x: f64) -> (f64); => j0); + (fn j1(x: f64) -> (f64); => j1); + (fn jn(n: i32, x: f64) -> (f64); => jn); + (fn ldexp(x: f64, n: i32) -> (f64); => ldexp); + (fn lgamma(x: f64) -> (f64); => lgamma); + (fn lgamma_r(x: f64) -> (f64, i32); => lgamma_r); + (fn log(x: f64) -> (f64); => log); + (fn log10(x: f64) -> (f64); => log10); + (fn log1p(x: f64) -> (f64); => log1p); + (fn log2(x: f64) -> (f64); => log2); + (fn modf(x: f64) -> (f64, f64); => modf); + (fn nextafter(x: f64, y: f64) -> (f64); => nextafter); + (fn pow(x: f64, y: f64) -> (f64); => pow); + (fn remainder(x: f64, y: f64) -> (f64); => remainder); + (fn remquo(x: f64, y: f64) -> (f64, i32); => remquo); + (fn rint(x: f64) -> (f64); => rint); + (fn round(x: f64) -> (f64); => round); + (fn roundevem(x: f64) -> (f64); => roundeven); + (fn scalbn(x: f64, n: i32) -> (f64); => scalbn); + (fn sin(x: f64) -> (f64); => sin); + (fn sincos(x: f64) -> (f64, f64); => sincos); + (fn sinh(x: f64) -> (f64); => sinh); + (fn sqrt(x: f64) -> (f64); => sqrt); + (fn tan(x: f64) -> (f64); => tan); + (fn tanh(x: f64) -> (f64); => tanh); + (fn tgamma(x: f64) -> (f64); => tgamma); + (fn trunc(x: f64) -> (f64); => trunc); + (fn y0(x: f64) -> (f64); => y0); + (fn y1(x: f64) -> (f64); => y1); + (fn yn(n: i32, x: f64) -> (f64); => yn); + // verify-sorted-end + } +} + +#[cfg(f16_enabled)] +libm_helper! { + f16, + funcs: { + // verify-sorted-start + (fn ceil(x: f16) -> (f16); => ceilf16); + (fn copysign(x: f16, y: f16) -> (f16); => copysignf16); + (fn fabs(x: f16) -> (f16); => fabsf16); + (fn fdim(x: f16, y: f16) -> (f16); => fdimf16); + (fn floor(x: f16) -> (f16); => floorf16); + (fn fmax(x: f16, y: f16) -> (f16); => fmaxf16); + (fn fmaximum_num(x: f16, y: f16) -> (f16); => fmaximum_numf16); + (fn fmaximumf16(x: f16, y: f16) -> (f16); => fmaximumf16); + (fn fmin(x: f16, y: f16) -> (f16); => fminf16); + (fn fminimum(x: f16, y: f16) -> (f16); => fminimumf16); + (fn fminimum_num(x: f16, y: f16) -> (f16); => fminimum_numf16); + (fn fmod(x: f16, y: f16) -> (f16); => fmodf16); + (fn ldexp(x: f16, n: i32) -> (f16); => ldexpf16); + (fn rint(x: f16) -> (f16); => rintf16); + (fn round(x: f16) -> (f16); => roundf16); + (fn roundeven(x: f16) -> (f16); => roundevenf16); + (fn scalbn(x: f16, n: i32) -> (f16); => scalbnf16); + (fn sqrtf(x: f16) -> (f16); => sqrtf16); + (fn truncf(x: f16) -> (f16); => truncf16); + // verify-sorted-end + } +} + +#[cfg(f128_enabled)] +libm_helper! { + f128, + funcs: { + // verify-sorted-start + (fn ceil(x: f128) -> (f128); => ceilf128); + (fn copysign(x: f128, y: f128) -> (f128); => copysignf128); + (fn fabs(x: f128) -> (f128); => fabsf128); + (fn fdim(x: f128, y: f128) -> (f128); => fdimf128); + (fn floor(x: f128) -> (f128); => floorf128); + (fn fma(x: f128, y: f128, z: f128) -> (f128); => fmaf128); + (fn fmax(x: f128, y: f128) -> (f128); => fmaxf128); + (fn fmaximum(x: f128, y: f128) -> (f128); => fmaximumf128); + (fn fmaximum_num(x: f128, y: f128) -> (f128); => fmaximum_numf128); + (fn fmin(x: f128, y: f128) -> (f128); => fminf128); + (fn fminimum(x: f128, y: f128) -> (f128); => fminimumf128); + (fn fminimum_num(x: f128, y: f128) -> (f128); => fminimum_numf128); + (fn fmod(x: f128, y: f128) -> (f128); => fmodf128); + (fn ldexp(x: f128, n: i32) -> (f128); => ldexpf128); + (fn rint(x: f128) -> (f128); => rintf128); + (fn round(x: f128) -> (f128); => roundf128); + (fn roundeven(x: f128) -> (f128); => roundevenf128); + (fn scalbn(x: f128, n: i32) -> (f128); => scalbnf128); + (fn sqrt(x: f128) -> (f128); => sqrtf128); + (fn trunc(x: f128) -> (f128); => truncf128); + // verify-sorted-end + } +} +// verify-apilist-end diff --git a/library/compiler-builtins/libm/libm/src/math/acos.rs b/library/compiler-builtins/libm/libm/src/math/acos.rs new file mode 100644 index 00000000000..23b13251ee2 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/acos.rs @@ -0,0 +1,112 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* acos(x) + * Method : + * acos(x) = pi/2 - asin(x) + * acos(-x) = pi/2 + asin(x) + * For |x|<=0.5 + * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) + * For x>0.5 + * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) + * = 2asin(sqrt((1-x)/2)) + * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) + * = 2f + (2c + 2s*z*R(z)) + * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term + * for f so that f+c ~ sqrt(z). + * For x<-0.5 + * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) + * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + * Function needed: sqrt + */ + +use super::sqrt; + +const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ +const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ +const PS0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ +const PS1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ +const PS2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ +const PS3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ +const PS4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ +const PS5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ +const QS1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ +const QS2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ +const QS3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ +const QS4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +fn r(z: f64) -> f64 { + let p: f64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); + let q: f64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); + p / q +} + +/// Arccosine (f64) +/// +/// Computes the inverse cosine (arc cosine) of the input value. +/// Arguments must be in the range -1 to 1. +/// Returns values in radians, in the range of 0 to pi. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn acos(x: f64) -> f64 { + let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120 + let z: f64; + let w: f64; + let s: f64; + let c: f64; + let df: f64; + let hx: u32; + let ix: u32; + + hx = (x.to_bits() >> 32) as u32; + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3ff00000 { + let lx: u32 = x.to_bits() as u32; + + if ((ix - 0x3ff00000) | lx) == 0 { + /* acos(1)=0, acos(-1)=pi */ + if (hx >> 31) != 0 { + return 2. * PIO2_HI + x1p_120f; + } + return 0.; + } + return 0. / (x - x); + } + /* |x| < 0.5 */ + if ix < 0x3fe00000 { + if ix <= 0x3c600000 { + /* |x| < 2**-57 */ + return PIO2_HI + x1p_120f; + } + return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); + } + /* x < -0.5 */ + if (hx >> 31) != 0 { + z = (1.0 + x) * 0.5; + s = sqrt(z); + w = r(z) * s - PIO2_LO; + return 2. * (PIO2_HI - (s + w)); + } + /* x > 0.5 */ + z = (1.0 - x) * 0.5; + s = sqrt(z); + // Set the low 4 bytes to zero + df = f64::from_bits(s.to_bits() & 0xff_ff_ff_ff_00_00_00_00); + + c = (z - df * df) / (s + df); + w = r(z) * s + c; + 2. * (df + w) +} diff --git a/library/compiler-builtins/libm/libm/src/math/acosf.rs b/library/compiler-builtins/libm/libm/src/math/acosf.rs new file mode 100644 index 00000000000..dd88eea5b13 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/acosf.rs @@ -0,0 +1,79 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::sqrt::sqrtf; + +const PIO2_HI: f32 = 1.5707962513e+00; /* 0x3fc90fda */ +const PIO2_LO: f32 = 7.5497894159e-08; /* 0x33a22168 */ +const P_S0: f32 = 1.6666586697e-01; +const P_S1: f32 = -4.2743422091e-02; +const P_S2: f32 = -8.6563630030e-03; +const Q_S1: f32 = -7.0662963390e-01; + +fn r(z: f32) -> f32 { + let p = z * (P_S0 + z * (P_S1 + z * P_S2)); + let q = 1. + z * Q_S1; + p / q +} + +/// Arccosine (f32) +/// +/// Computes the inverse cosine (arc cosine) of the input value. +/// Arguments must be in the range -1 to 1. +/// Returns values in radians, in the range of 0 to pi. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn acosf(x: f32) -> f32 { + let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) + + let z: f32; + let w: f32; + let s: f32; + + let mut hx = x.to_bits(); + let ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3f800000 { + if ix == 0x3f800000 { + if (hx >> 31) != 0 { + return 2. * PIO2_HI + x1p_120; + } + return 0.; + } + return 0. / (x - x); + } + /* |x| < 0.5 */ + if ix < 0x3f000000 { + if ix <= 0x32800000 { + /* |x| < 2**-26 */ + return PIO2_HI + x1p_120; + } + return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); + } + /* x < -0.5 */ + if (hx >> 31) != 0 { + z = (1. + x) * 0.5; + s = sqrtf(z); + w = r(z) * s - PIO2_LO; + return 2. * (PIO2_HI - (s + w)); + } + /* x > 0.5 */ + z = (1. - x) * 0.5; + s = sqrtf(z); + hx = s.to_bits(); + let df = f32::from_bits(hx & 0xfffff000); + let c = (z - df * df) / (s + df); + w = r(z) * s + c; + 2. * (df + w) +} diff --git a/library/compiler-builtins/libm/libm/src/math/acosh.rs b/library/compiler-builtins/libm/libm/src/math/acosh.rs new file mode 100644 index 00000000000..d1f5b9fa937 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/acosh.rs @@ -0,0 +1,27 @@ +use super::{log, log1p, sqrt}; + +const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ + +/// Inverse hyperbolic cosine (f64) +/// +/// Calculates the inverse hyperbolic cosine of `x`. +/// Is defined as `log(x + sqrt(x*x-1))`. +/// `x` must be a number greater than or equal to 1. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn acosh(x: f64) -> f64 { + let u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + + /* x < 1 domain error is handled in the called functions */ + + if e < 0x3ff + 1 { + /* |x| < 2, up to 2ulp error in [1,1.125] */ + return log1p(x - 1.0 + sqrt((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); + } + if e < 0x3ff + 26 { + /* |x| < 0x1p26 */ + return log(2.0 * x - 1.0 / (x + sqrt(x * x - 1.0))); + } + /* |x| >= 0x1p26 or nan */ + return log(x) + LN2; +} diff --git a/library/compiler-builtins/libm/libm/src/math/acoshf.rs b/library/compiler-builtins/libm/libm/src/math/acoshf.rs new file mode 100644 index 00000000000..ad3455fdd48 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/acoshf.rs @@ -0,0 +1,26 @@ +use super::{log1pf, logf, sqrtf}; + +const LN2: f32 = 0.693147180559945309417232121458176568; + +/// Inverse hyperbolic cosine (f32) +/// +/// Calculates the inverse hyperbolic cosine of `x`. +/// Is defined as `log(x + sqrt(x*x-1))`. +/// `x` must be a number greater than or equal to 1. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn acoshf(x: f32) -> f32 { + let u = x.to_bits(); + let a = u & 0x7fffffff; + + if a < 0x3f800000 + (1 << 23) { + /* |x| < 2, invalid if x < 1 or nan */ + /* up to 2ulp error in [1,1.125] */ + return log1pf(x - 1.0 + sqrtf((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); + } + if a < 0x3f800000 + (12 << 23) { + /* |x| < 0x1p12 */ + return logf(2.0 * x - 1.0 / (x + sqrtf(x * x - 1.0))); + } + /* x >= 0x1p12 */ + return logf(x) + LN2; +} diff --git a/library/compiler-builtins/libm/libm/src/math/arch/aarch64.rs b/library/compiler-builtins/libm/libm/src/math/arch/aarch64.rs new file mode 100644 index 00000000000..020bb731cdc --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/arch/aarch64.rs @@ -0,0 +1,115 @@ +//! Architecture-specific support for aarch64 with neon. + +use core::arch::asm; + +pub fn fma(mut x: f64, y: f64, z: f64) -> f64 { + // SAFETY: `fmadd` is available with neon and has no side effects. + unsafe { + asm!( + "fmadd {x:d}, {x:d}, {y:d}, {z:d}", + x = inout(vreg) x, + y = in(vreg) y, + z = in(vreg) z, + options(nomem, nostack, pure) + ); + } + x +} + +pub fn fmaf(mut x: f32, y: f32, z: f32) -> f32 { + // SAFETY: `fmadd` is available with neon and has no side effects. + unsafe { + asm!( + "fmadd {x:s}, {x:s}, {y:s}, {z:s}", + x = inout(vreg) x, + y = in(vreg) y, + z = in(vreg) z, + options(nomem, nostack, pure) + ); + } + x +} + +pub fn rint(mut x: f64) -> f64 { + // SAFETY: `frintn` is available with neon and has no side effects. + // + // `frintn` is always round-to-nearest which does not match the C specification, but Rust does + // not support rounding modes. + unsafe { + asm!( + "frintn {x:d}, {x:d}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} + +pub fn rintf(mut x: f32) -> f32 { + // SAFETY: `frintn` is available with neon and has no side effects. + // + // `frintn` is always round-to-nearest which does not match the C specification, but Rust does + // not support rounding modes. + unsafe { + asm!( + "frintn {x:s}, {x:s}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} + +#[cfg(all(f16_enabled, target_feature = "fp16"))] +pub fn rintf16(mut x: f16) -> f16 { + // SAFETY: `frintn` is available for `f16` with `fp16` (implies `neon`) and has no side effects. + // + // `frintn` is always round-to-nearest which does not match the C specification, but Rust does + // not support rounding modes. + unsafe { + asm!( + "frintn {x:h}, {x:h}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} + +pub fn sqrt(mut x: f64) -> f64 { + // SAFETY: `fsqrt` is available with neon and has no side effects. + unsafe { + asm!( + "fsqrt {x:d}, {x:d}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} + +pub fn sqrtf(mut x: f32) -> f32 { + // SAFETY: `fsqrt` is available with neon and has no side effects. + unsafe { + asm!( + "fsqrt {x:s}, {x:s}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} + +#[cfg(all(f16_enabled, target_feature = "fp16"))] +pub fn sqrtf16(mut x: f16) -> f16 { + // SAFETY: `fsqrt` is available for `f16` with `fp16` (implies `neon`) and has no + // side effects. + unsafe { + asm!( + "fsqrt {x:h}, {x:h}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} diff --git a/library/compiler-builtins/libm/libm/src/math/arch/i586.rs b/library/compiler-builtins/libm/libm/src/math/arch/i586.rs new file mode 100644 index 00000000000..f92b9a2af71 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/arch/i586.rs @@ -0,0 +1,37 @@ +//! Architecture-specific support for x86-32 without SSE2 + +use super::super::fabs; + +/// Use an alternative implementation on x86, because the +/// main implementation fails with the x87 FPU used by +/// debian i386, probably due to excess precision issues. +/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219. +pub fn ceil(x: f64) -> f64 { + if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated < x { + return truncated + 1.0; + } else { + return truncated; + } + } else { + return x; + } +} + +/// Use an alternative implementation on x86, because the +/// main implementation fails with the x87 FPU used by +/// debian i386, probably due to excess precision issues. +/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219. +pub fn floor(x: f64) -> f64 { + if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated > x { + return truncated - 1.0; + } else { + return truncated; + } + } else { + return x; + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/arch/i686.rs b/library/compiler-builtins/libm/libm/src/math/arch/i686.rs new file mode 100644 index 00000000000..3e1d19bfab6 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/arch/i686.rs @@ -0,0 +1,27 @@ +//! Architecture-specific support for x86-32 and x86-64 with SSE2 + +pub fn sqrtf(mut x: f32) -> f32 { + // SAFETY: `sqrtss` is part of `sse2`, which this module is gated behind. It has no memory + // access or side effects. + unsafe { + core::arch::asm!( + "sqrtss {x}, {x}", + x = inout(xmm_reg) x, + options(nostack, nomem, pure), + ) + }; + x +} + +pub fn sqrt(mut x: f64) -> f64 { + // SAFETY: `sqrtsd` is part of `sse2`, which this module is gated behind. It has no memory + // access or side effects. + unsafe { + core::arch::asm!( + "sqrtsd {x}, {x}", + x = inout(xmm_reg) x, + options(nostack, nomem, pure), + ) + }; + x +} diff --git a/library/compiler-builtins/libm/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/libm/src/math/arch/mod.rs new file mode 100644 index 00000000000..d9f2aad66d4 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/arch/mod.rs @@ -0,0 +1,50 @@ +//! Architecture-specific routines and operations. +//! +//! LLVM will already optimize calls to some of these in cases that there are hardware +//! instructions. Providing an implementation here just ensures that the faster implementation +//! is used when calling the function directly. This helps anyone who uses `libm` directly, as +//! well as improving things when these routines are called as part of other implementations. + +// Most implementations should be defined here, to ensure they are not made available when +// soft floats are required. +#[cfg(arch_enabled)] +cfg_if! { + if #[cfg(all(target_arch = "wasm32", intrinsics_enabled))] { + mod wasm32; + pub use wasm32::{ + ceil, ceilf, fabs, fabsf, floor, floorf, rint, rintf, sqrt, sqrtf, trunc, truncf, + }; + } else if #[cfg(target_feature = "sse2")] { + mod i686; + pub use i686::{sqrt, sqrtf}; + } else if #[cfg(all( + any(target_arch = "aarch64", target_arch = "arm64ec"), + target_feature = "neon" + ))] { + mod aarch64; + + pub use aarch64::{ + fma, + fmaf, + rint, + rintf, + sqrt, + sqrtf, + }; + + #[cfg(all(f16_enabled, target_feature = "fp16"))] + pub use aarch64::{ + rintf16, + sqrtf16, + }; + } +} + +// There are certain architecture-specific implementations that are needed for correctness +// even with `force-soft-float`. These are configured here. +cfg_if! { + if #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] { + mod i586; + pub use i586::{ceil, floor}; + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/arch/wasm32.rs b/library/compiler-builtins/libm/libm/src/math/arch/wasm32.rs new file mode 100644 index 00000000000..de80c8a5817 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/arch/wasm32.rs @@ -0,0 +1,50 @@ +//! Wasm has builtins for simple float operations. Use the unstable `core::arch` intrinsics which +//! are significantly faster than soft float operations. + +pub fn ceil(x: f64) -> f64 { + core::arch::wasm32::f64_ceil(x) +} + +pub fn ceilf(x: f32) -> f32 { + core::arch::wasm32::f32_ceil(x) +} + +pub fn fabs(x: f64) -> f64 { + x.abs() +} + +pub fn fabsf(x: f32) -> f32 { + x.abs() +} + +pub fn floor(x: f64) -> f64 { + core::arch::wasm32::f64_floor(x) +} + +pub fn floorf(x: f32) -> f32 { + core::arch::wasm32::f32_floor(x) +} + +pub fn rint(x: f64) -> f64 { + core::arch::wasm32::f64_nearest(x) +} + +pub fn rintf(x: f32) -> f32 { + core::arch::wasm32::f32_nearest(x) +} + +pub fn sqrt(x: f64) -> f64 { + core::arch::wasm32::f64_sqrt(x) +} + +pub fn sqrtf(x: f32) -> f32 { + core::arch::wasm32::f32_sqrt(x) +} + +pub fn trunc(x: f64) -> f64 { + core::arch::wasm32::f64_trunc(x) +} + +pub fn truncf(x: f32) -> f32 { + core::arch::wasm32::f32_trunc(x) +} diff --git a/library/compiler-builtins/libm/libm/src/math/asin.rs b/library/compiler-builtins/libm/libm/src/math/asin.rs new file mode 100644 index 00000000000..12d0cd35fa5 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/asin.rs @@ -0,0 +1,115 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* asin(x) + * Method : + * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... + * we approximate asin(x) on [0,0.5] by + * asin(x) = x + x*x^2*R(x^2) + * where + * R(x^2) is a rational approximation of (asin(x)-x)/x^3 + * and its remez error is bounded by + * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) + * + * For x in [0.5,1] + * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) + * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; + * then for x>0.98 + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) + * For x<=0.98, let pio4_hi = pio2_hi/2, then + * f = hi part of s; + * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) + * and + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) + * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + */ + +use super::{fabs, get_high_word, get_low_word, sqrt, with_set_low_word}; + +const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ +const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ +/* coefficients for R(x^2) */ +const P_S0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ +const P_S1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ +const P_S2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ +const P_S3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ +const P_S4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ +const P_S5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ +const Q_S1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ +const Q_S2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ +const Q_S3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ +const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +fn comp_r(z: f64) -> f64 { + let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); + let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); + p / q +} + +/// Arcsine (f64) +/// +/// Computes the inverse sine (arc sine) of the argument `x`. +/// Arguments to asin must be in the range -1 to 1. +/// Returns values in radians, in the range of -pi/2 to pi/2. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn asin(mut x: f64) -> f64 { + let z: f64; + let r: f64; + let s: f64; + let hx: u32; + let ix: u32; + + hx = get_high_word(x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3ff00000 { + let lx: u32; + lx = get_low_word(x); + if ((ix - 0x3ff00000) | lx) == 0 { + /* asin(1) = +-pi/2 with inexact */ + return x * PIO2_HI + f64::from_bits(0x3870000000000000); + } else { + return 0.0 / (x - x); + } + } + /* |x| < 0.5 */ + if ix < 0x3fe00000 { + /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ + if (0x00100000..0x3e500000).contains(&ix) { + return x; + } else { + return x + x * comp_r(x * x); + } + } + /* 1 > |x| >= 0.5 */ + z = (1.0 - fabs(x)) * 0.5; + s = sqrt(z); + r = comp_r(z); + if ix >= 0x3fef3333 { + /* if |x| > 0.975 */ + x = PIO2_HI - (2. * (s + s * r) - PIO2_LO); + } else { + let f: f64; + let c: f64; + /* f+c = sqrt(z) */ + f = with_set_low_word(s, 0); + c = (z - f * f) / (s + f); + x = 0.5 * PIO2_HI - (2.0 * s * r - (PIO2_LO - 2.0 * c) - (0.5 * PIO2_HI - 2.0 * f)); + } + if hx >> 31 != 0 { -x } else { x } +} diff --git a/library/compiler-builtins/libm/libm/src/math/asinf.rs b/library/compiler-builtins/libm/libm/src/math/asinf.rs new file mode 100644 index 00000000000..ed685556730 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/asinf.rs @@ -0,0 +1,68 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::sqrt::sqrt; +use super::support::Float; + +const PIO2: f64 = 1.570796326794896558e+00; + +/* coefficients for R(x^2) */ +const P_S0: f32 = 1.6666586697e-01; +const P_S1: f32 = -4.2743422091e-02; +const P_S2: f32 = -8.6563630030e-03; +const Q_S1: f32 = -7.0662963390e-01; + +fn r(z: f32) -> f32 { + let p = z * (P_S0 + z * (P_S1 + z * P_S2)); + let q = 1. + z * Q_S1; + p / q +} + +/// Arcsine (f32) +/// +/// Computes the inverse sine (arc sine) of the argument `x`. +/// Arguments to asin must be in the range -1 to 1. +/// Returns values in radians, in the range of -pi/2 to pi/2. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn asinf(mut x: f32) -> f32 { + let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120) + + let hx = x.to_bits(); + let ix = hx & 0x7fffffff; + + if ix >= 0x3f800000 { + /* |x| >= 1 */ + if ix == 0x3f800000 { + /* |x| == 1 */ + return ((x as f64) * PIO2 + x1p_120) as f32; /* asin(+-1) = +-pi/2 with inexact */ + } + return 0. / (x - x); /* asin(|x|>1) is NaN */ + } + + if ix < 0x3f000000 { + /* |x| < 0.5 */ + /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ + if (0x00800000..0x39800000).contains(&ix) { + return x; + } + return x + x * r(x * x); + } + + /* 1 > |x| >= 0.5 */ + let z = (1. - Float::abs(x)) * 0.5; + let s = sqrt(z as f64); + x = (PIO2 - 2. * (s + s * (r(z) as f64))) as f32; + if (hx >> 31) != 0 { -x } else { x } +} diff --git a/library/compiler-builtins/libm/libm/src/math/asinh.rs b/library/compiler-builtins/libm/libm/src/math/asinh.rs new file mode 100644 index 00000000000..75d3c3ad462 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/asinh.rs @@ -0,0 +1,36 @@ +use super::{log, log1p, sqrt}; + +const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +/// Inverse hyperbolic sine (f64) +/// +/// Calculates the inverse hyperbolic sine of `x`. +/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn asinh(mut x: f64) -> f64 { + let mut u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + let sign = (u >> 63) != 0; + + /* |x| */ + u &= (!0) >> 1; + x = f64::from_bits(u); + + if e >= 0x3ff + 26 { + /* |x| >= 0x1p26 or inf or nan */ + x = log(x) + LN2; + } else if e >= 0x3ff + 1 { + /* |x| >= 2 */ + x = log(2.0 * x + 1.0 / (sqrt(x * x + 1.0) + x)); + } else if e >= 0x3ff - 26 { + /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ + x = log1p(x + x * x / (sqrt(x * x + 1.0) + 1.0)); + } else { + /* |x| < 0x1p-26, raise inexact if x != 0 */ + let x1p120 = f64::from_bits(0x4770000000000000); + force_eval!(x + x1p120); + } + + if sign { -x } else { x } +} diff --git a/library/compiler-builtins/libm/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/libm/src/math/asinhf.rs new file mode 100644 index 00000000000..27ed9dd372d --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/asinhf.rs @@ -0,0 +1,35 @@ +use super::{log1pf, logf, sqrtf}; + +const LN2: f32 = 0.693147180559945309417232121458176568; + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +/// Inverse hyperbolic sine (f32) +/// +/// Calculates the inverse hyperbolic sine of `x`. +/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn asinhf(mut x: f32) -> f32 { + let u = x.to_bits(); + let i = u & 0x7fffffff; + let sign = (u >> 31) != 0; + + /* |x| */ + x = f32::from_bits(i); + + if i >= 0x3f800000 + (12 << 23) { + /* |x| >= 0x1p12 or inf or nan */ + x = logf(x) + LN2; + } else if i >= 0x3f800000 + (1 << 23) { + /* |x| >= 2 */ + x = logf(2.0 * x + 1.0 / (sqrtf(x * x + 1.0) + x)); + } else if i >= 0x3f800000 - (12 << 23) { + /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ + x = log1pf(x + x * x / (sqrtf(x * x + 1.0) + 1.0)); + } else { + /* |x| < 0x1p-12, raise inexact if x!=0 */ + let x1p120 = f32::from_bits(0x7b800000); + force_eval!(x + x1p120); + } + + if sign { -x } else { x } +} diff --git a/library/compiler-builtins/libm/libm/src/math/atan.rs b/library/compiler-builtins/libm/libm/src/math/atan.rs new file mode 100644 index 00000000000..4ca5cc91a1e --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/atan.rs @@ -0,0 +1,182 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* atan(x) + * Method + * 1. Reduce x to positive by atan(x) = -atan(-x). + * 2. According to the integer k=4t+0.25 chopped, t=x, the argument + * is further reduced to one of the following intervals and the + * arctangent of t is evaluated by the corresponding formula: + * + * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) + * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) + * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) + * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) + * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +use core::f64; + +use super::fabs; + +const ATANHI: [f64; 4] = [ + 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ + 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ + 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ + 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ +]; + +const ATANLO: [f64; 4] = [ + 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ + 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ + 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ + 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ +]; + +const AT: [f64; 11] = [ + 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ + -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ + 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ + -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ + 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ + -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ + 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ + -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ + 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ + -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ + 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ +]; + +/// Arctangent (f64) +/// +/// Computes the inverse tangent (arc tangent) of the input value. +/// Returns a value in radians, in the range of -pi/2 to pi/2. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atan(x: f64) -> f64 { + let mut x = x; + let mut ix = (x.to_bits() >> 32) as u32; + let sign = ix >> 31; + ix &= 0x7fff_ffff; + if ix >= 0x4410_0000 { + if x.is_nan() { + return x; + } + + let z = ATANHI[3] + f64::from_bits(0x0380_0000); // 0x1p-120f + return if sign != 0 { -z } else { z }; + } + + let id = if ix < 0x3fdc_0000 { + /* |x| < 0.4375 */ + if ix < 0x3e40_0000 { + /* |x| < 2^-27 */ + if ix < 0x0010_0000 { + /* raise underflow for subnormal x */ + force_eval!(x as f32); + } + + return x; + } + + -1 + } else { + x = fabs(x); + if ix < 0x3ff30000 { + /* |x| < 1.1875 */ + if ix < 0x3fe60000 { + /* 7/16 <= |x| < 11/16 */ + x = (2. * x - 1.) / (2. + x); + 0 + } else { + /* 11/16 <= |x| < 19/16 */ + x = (x - 1.) / (x + 1.); + 1 + } + } else if ix < 0x40038000 { + /* |x| < 2.4375 */ + x = (x - 1.5) / (1. + 1.5 * x); + 2 + } else { + /* 2.4375 <= |x| < 2^66 */ + x = -1. / x; + 3 + } + }; + + let z = x * x; + let w = z * z; + /* break sum from i=0 to 10 AT[i]z**(i+1) into odd and even poly */ + let s1 = z * (AT[0] + w * (AT[2] + w * (AT[4] + w * (AT[6] + w * (AT[8] + w * AT[10]))))); + let s2 = w * (AT[1] + w * (AT[3] + w * (AT[5] + w * (AT[7] + w * AT[9])))); + + if id < 0 { + return x - x * (s1 + s2); + } + + let z = i!(ATANHI, id as usize) - (x * (s1 + s2) - i!(ATANLO, id as usize) - x); + + if sign != 0 { -z } else { z } +} + +#[cfg(test)] +mod tests { + use core::f64; + + use super::atan; + + #[test] + fn sanity_check() { + for (input, answer) in [ + (3.0_f64.sqrt() / 3.0, f64::consts::FRAC_PI_6), + (1.0, f64::consts::FRAC_PI_4), + (3.0_f64.sqrt(), f64::consts::FRAC_PI_3), + (-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6), + (-1.0, -f64::consts::FRAC_PI_4), + (-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3), + ] + .iter() + { + assert!( + (atan(*input) - answer) / answer < 1e-5, + "\natan({:.4}/16) = {:.4}, actual: {}", + input * 16.0, + answer, + atan(*input) + ); + } + } + + #[test] + fn zero() { + assert_eq!(atan(0.0), 0.0); + } + + #[test] + fn infinity() { + assert_eq!(atan(f64::INFINITY), f64::consts::FRAC_PI_2); + } + + #[test] + fn minus_infinity() { + assert_eq!(atan(f64::NEG_INFINITY), -f64::consts::FRAC_PI_2); + } + + #[test] + fn nan() { + assert!(atan(f64::NAN).is_nan()); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/atan2.rs b/library/compiler-builtins/libm/libm/src/math/atan2.rs new file mode 100644 index 00000000000..c668731cf37 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/atan2.rs @@ -0,0 +1,131 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* atan2(y,x) + * Method : + * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). + * 2. Reduce x to positive by (if x and y are unexceptional): + * ARG (x+iy) = arctan(y/x) ... if x > 0, + * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, + * + * Special cases: + * + * ATAN2((anything), NaN ) is NaN; + * ATAN2(NAN , (anything) ) is NaN; + * ATAN2(+-0, +(anything but NaN)) is +-0 ; + * ATAN2(+-0, -(anything but NaN)) is +-pi ; + * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; + * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; + * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; + * ATAN2(+-INF,+INF ) is +-pi/4 ; + * ATAN2(+-INF,-INF ) is +-3pi/4; + * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +use super::{atan, fabs}; + +const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ +const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +/// Arctangent of y/x (f64) +/// +/// Computes the inverse tangent (arc tangent) of `y/x`. +/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). +/// Returns a value in radians, in the range of -pi to pi. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atan2(y: f64, x: f64) -> f64 { + if x.is_nan() || y.is_nan() { + return x + y; + } + let mut ix = (x.to_bits() >> 32) as u32; + let lx = x.to_bits() as u32; + let mut iy = (y.to_bits() >> 32) as u32; + let ly = y.to_bits() as u32; + if ((ix.wrapping_sub(0x3ff00000)) | lx) == 0 { + /* x = 1.0 */ + return atan(y); + } + let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if (iy | ly) == 0 { + return match m { + 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ + 2 => PI, /* atan(+0,-anything) = PI */ + _ => -PI, /* atan(-0,-anything) =-PI */ + }; + } + /* when x = 0 */ + if (ix | lx) == 0 { + return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; + } + /* when x is INF */ + if ix == 0x7ff00000 { + if iy == 0x7ff00000 { + return match m { + 0 => PI / 4.0, /* atan(+INF,+INF) */ + 1 => -PI / 4.0, /* atan(-INF,+INF) */ + 2 => 3.0 * PI / 4.0, /* atan(+INF,-INF) */ + _ => -3.0 * PI / 4.0, /* atan(-INF,-INF) */ + }; + } else { + return match m { + 0 => 0.0, /* atan(+...,+INF) */ + 1 => -0.0, /* atan(-...,+INF) */ + 2 => PI, /* atan(+...,-INF) */ + _ => -PI, /* atan(-...,-INF) */ + }; + } + } + /* |y/x| > 0x1p64 */ + if ix.wrapping_add(64 << 20) < iy || iy == 0x7ff00000 { + return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; + } + + /* z = atan(|y/x|) without spurious underflow */ + let z = if (m & 2 != 0) && iy.wrapping_add(64 << 20) < ix { + /* |y/x| < 0x1p-64, x<0 */ + 0.0 + } else { + atan(fabs(y / x)) + }; + match m { + 0 => z, /* atan(+,+) */ + 1 => -z, /* atan(-,+) */ + 2 => PI - (z - PI_LO), /* atan(+,-) */ + _ => (z - PI_LO) - PI, /* atan(-,-) */ + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg_attr(x86_no_sse, ignore = "FIXME(i586): possible incorrect rounding")] + fn sanity_check() { + assert_eq!(atan2(0.0, 1.0), 0.0); + assert_eq!(atan2(0.0, -1.0), PI); + assert_eq!(atan2(-0.0, -1.0), -PI); + assert_eq!(atan2(3.0, 2.0), atan(3.0 / 2.0)); + assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI); + assert_eq!(atan2(-2.0, -1.0), atan(-2.0 / -1.0) - PI); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/libm/src/math/atan2f.rs new file mode 100644 index 00000000000..95b466fff4e --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/atan2f.rs @@ -0,0 +1,90 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{atanf, fabsf}; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ + +/// Arctangent of y/x (f32) +/// +/// Computes the inverse tangent (arc tangent) of `y/x`. +/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). +/// Returns a value in radians, in the range of -pi to pi. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atan2f(y: f32, x: f32) -> f32 { + if x.is_nan() || y.is_nan() { + return x + y; + } + let mut ix = x.to_bits(); + let mut iy = y.to_bits(); + + if ix == 0x3f800000 { + /* x=1.0 */ + return atanf(y); + } + let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if iy == 0 { + return match m { + 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ + 2 => PI, /* atan(+0,-anything) = pi */ + _ => -PI, /* atan(-0,-anything) =-pi */ + }; + } + /* when x = 0 */ + if ix == 0 { + return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; + } + /* when x is INF */ + if ix == 0x7f800000 { + return if iy == 0x7f800000 { + match m { + 0 => PI / 4., /* atan(+INF,+INF) */ + 1 => -PI / 4., /* atan(-INF,+INF) */ + 2 => 3. * PI / 4., /* atan(+INF,-INF)*/ + _ => -3. * PI / 4., /* atan(-INF,-INF)*/ + } + } else { + match m { + 0 => 0., /* atan(+...,+INF) */ + 1 => -0., /* atan(-...,+INF) */ + 2 => PI, /* atan(+...,-INF) */ + _ => -PI, /* atan(-...,-INF) */ + } + }; + } + /* |y/x| > 0x1p26 */ + if (ix + (26 << 23) < iy) || (iy == 0x7f800000) { + return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; + } + + /* z = atan(|y/x|) with correct underflow */ + let z = if (m & 2 != 0) && (iy + (26 << 23) < ix) { + /*|y/x| < 0x1p-26, x < 0 */ + 0. + } else { + atanf(fabsf(y / x)) + }; + match m { + 0 => z, /* atan(+,+) */ + 1 => -z, /* atan(-,+) */ + 2 => PI - (z - PI_LO), /* atan(+,-) */ + _ => (z - PI_LO) - PI, /* case 3 */ /* atan(-,-) */ + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/atanf.rs b/library/compiler-builtins/libm/libm/src/math/atanf.rs new file mode 100644 index 00000000000..eb3d401cd96 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/atanf.rs @@ -0,0 +1,103 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::fabsf; + +const ATAN_HI: [f32; 4] = [ + 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ + 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ + 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ + 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ +]; + +const ATAN_LO: [f32; 4] = [ + 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ + 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ + 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ + 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ +]; + +const A_T: [f32; 5] = + [3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, -1.0648017377e-01, 6.1687607318e-02]; + +/// Arctangent (f32) +/// +/// Computes the inverse tangent (arc tangent) of the input value. +/// Returns a value in radians, in the range of -pi/2 to pi/2. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atanf(mut x: f32) -> f32 { + let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) + + let z: f32; + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix >= 0x4c800000 { + /* if |x| >= 2**26 */ + if x.is_nan() { + return x; + } + z = i!(ATAN_HI, 3) + x1p_120; + return if sign { -z } else { z }; + } + let id = if ix < 0x3ee00000 { + /* |x| < 0.4375 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + if ix < 0x00800000 { + /* raise underflow for subnormal x */ + force_eval!(x * x); + } + return x; + } + -1 + } else { + x = fabsf(x); + if ix < 0x3f980000 { + /* |x| < 1.1875 */ + if ix < 0x3f300000 { + /* 7/16 <= |x| < 11/16 */ + x = (2. * x - 1.) / (2. + x); + 0 + } else { + /* 11/16 <= |x| < 19/16 */ + x = (x - 1.) / (x + 1.); + 1 + } + } else if ix < 0x401c0000 { + /* |x| < 2.4375 */ + x = (x - 1.5) / (1. + 1.5 * x); + 2 + } else { + /* 2.4375 <= |x| < 2**26 */ + x = -1. / x; + 3 + } + }; + /* end of argument reduction */ + z = x * x; + let w = z * z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + let s1 = z * (i!(A_T, 0) + w * (i!(A_T, 2) + w * i!(A_T, 4))); + let s2 = w * (i!(A_T, 1) + w * i!(A_T, 3)); + if id < 0 { + return x - x * (s1 + s2); + } + let id = id as usize; + let z = i!(ATAN_HI, id) - ((x * (s1 + s2) - i!(ATAN_LO, id)) - x); + if sign { -z } else { z } +} diff --git a/library/compiler-builtins/libm/libm/src/math/atanh.rs b/library/compiler-builtins/libm/libm/src/math/atanh.rs new file mode 100644 index 00000000000..9dc826f5605 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/atanh.rs @@ -0,0 +1,33 @@ +use super::log1p; + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +/// Inverse hyperbolic tangent (f64) +/// +/// Calculates the inverse hyperbolic tangent of `x`. +/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atanh(x: f64) -> f64 { + let u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + let sign = (u >> 63) != 0; + + /* |x| */ + let mut y = f64::from_bits(u & 0x7fff_ffff_ffff_ffff); + + if e < 0x3ff - 1 { + if e < 0x3ff - 32 { + /* handle underflow */ + if e == 0 { + force_eval!(y as f32); + } + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5 * log1p(2.0 * y + 2.0 * y * y / (1.0 - y)); + } + } else { + /* avoid overflow */ + y = 0.5 * log1p(2.0 * (y / (1.0 - y))); + } + + if sign { -y } else { y } +} diff --git a/library/compiler-builtins/libm/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/libm/src/math/atanhf.rs new file mode 100644 index 00000000000..80ccec1f67f --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/atanhf.rs @@ -0,0 +1,33 @@ +use super::log1pf; + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +/// Inverse hyperbolic tangent (f32) +/// +/// Calculates the inverse hyperbolic tangent of `x`. +/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atanhf(mut x: f32) -> f32 { + let mut u = x.to_bits(); + let sign = (u >> 31) != 0; + + /* |x| */ + u &= 0x7fffffff; + x = f32::from_bits(u); + + if u < 0x3f800000 - (1 << 23) { + if u < 0x3f800000 - (32 << 23) { + /* handle underflow */ + if u < (1 << 23) { + force_eval!(x * x); + } + } else { + /* |x| < 0.5, up to 1.7ulp error */ + x = 0.5 * log1pf(2.0 * x + 2.0 * x * x / (1.0 - x)); + } + } else { + /* avoid overflow */ + x = 0.5 * log1pf(2.0 * (x / (1.0 - x))); + } + + if sign { -x } else { x } +} diff --git a/library/compiler-builtins/libm/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/libm/src/math/cbrt.rs new file mode 100644 index 00000000000..9d3311cd6a8 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/cbrt.rs @@ -0,0 +1,215 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: core-math/src/binary64/cbrt/cbrt.c + * Copyright (c) 2021-2022 Alexei Sibidanov. + * Ported to Rust in 2025 by Trevor Gross. + */ + +use super::Float; +use super::support::{FpResult, Round, cold_path}; + +/// Compute the cube root of the argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cbrt(x: f64) -> f64 { + cbrt_round(x, Round::Nearest).val +} + +pub fn cbrt_round(x: f64, round: Round) -> FpResult { + const ESCALE: [f64; 3] = [ + 1.0, + hf64!("0x1.428a2f98d728bp+0"), /* 2^(1/3) */ + hf64!("0x1.965fea53d6e3dp+0"), /* 2^(2/3) */ + ]; + + /* the polynomial c0+c1*x+c2*x^2+c3*x^3 approximates x^(1/3) on [1,2] + with maximal error < 9.2e-5 (attained at x=2) */ + const C: [f64; 4] = [ + hf64!("0x1.1b0babccfef9cp-1"), + hf64!("0x1.2c9a3e94d1da5p-1"), + hf64!("-0x1.4dc30b1a1ddbap-3"), + hf64!("0x1.7a8d3e4ec9b07p-6"), + ]; + + let u0: f64 = hf64!("0x1.5555555555555p-2"); + let u1: f64 = hf64!("0x1.c71c71c71c71cp-3"); + + let rsc = [1.0, -1.0, 0.5, -0.5, 0.25, -0.25]; + + let off = [hf64!("0x1p-53"), 0.0, 0.0, 0.0]; + + /* rm=0 for rounding to nearest, and other values for directed roundings */ + let hx: u64 = x.to_bits(); + let mut mant: u64 = hx & f64::SIG_MASK; + let sign: u64 = hx >> 63; + + let mut e: u32 = (hx >> f64::SIG_BITS) as u32 & f64::EXP_SAT; + + if ((e + 1) & f64::EXP_SAT) < 2 { + cold_path(); + + let ix: u64 = hx & !f64::SIGN_MASK; + + /* 0, inf, nan: we return x + x instead of simply x, + to that for x a signaling NaN, it correctly triggers + the invalid exception. */ + if e == f64::EXP_SAT || ix == 0 { + return FpResult::ok(x + x); + } + + let nz = ix.leading_zeros() - 11; /* subnormal */ + mant <<= nz; + mant &= f64::SIG_MASK; + e = e.wrapping_sub(nz - 1); + } + + e = e.wrapping_add(3072); + let cvt1: u64 = mant | (0x3ffu64 << 52); + let mut cvt5: u64 = cvt1; + + let et: u32 = e / 3; + let it: u32 = e % 3; + + /* 2^(3k+it) <= x < 2^(3k+it+1), with 0 <= it <= 3 */ + cvt5 += u64::from(it) << f64::SIG_BITS; + cvt5 |= sign << 63; + let zz: f64 = f64::from_bits(cvt5); + + /* cbrt(x) = cbrt(zz)*2^(et-1365) where 1 <= zz < 8 */ + let mut isc: u64 = ESCALE[it as usize].to_bits(); // todo: index + isc |= sign << 63; + let cvt2: u64 = isc; + let z: f64 = f64::from_bits(cvt1); + + /* cbrt(zz) = cbrt(z)*isc, where isc encodes 1, 2^(1/3) or 2^(2/3), + and 1 <= z < 2 */ + let r: f64 = 1.0 / z; + let rr: f64 = r * rsc[((it as usize) << 1) | sign as usize]; + let z2: f64 = z * z; + let c0: f64 = C[0] + z * C[1]; + let c2: f64 = C[2] + z * C[3]; + let mut y: f64 = c0 + z2 * c2; + let mut y2: f64 = y * y; + + /* y is an approximation of z^(1/3) */ + let mut h: f64 = y2 * (y * r) - 1.0; + + /* h determines the error between y and z^(1/3) */ + y -= (h * y) * (u0 - u1 * h); + + /* The correction y -= (h*y)*(u0 - u1*h) corresponds to a cubic variant + of Newton's method, with the function f(y) = 1-z/y^3. */ + y *= f64::from_bits(cvt2); + + /* Now y is an approximation of zz^(1/3), + * and rr an approximation of 1/zz. We now perform another iteration of + * Newton-Raphson, this time with a linear approximation only. */ + y2 = y * y; + let mut y2l: f64 = y.fma(y, -y2); + + /* y2 + y2l = y^2 exactly */ + let mut y3: f64 = y2 * y; + let mut y3l: f64 = y.fma(y2, -y3) + y * y2l; + + /* y3 + y3l approximates y^3 with about 106 bits of accuracy */ + h = ((y3 - zz) + y3l) * rr; + let mut dy: f64 = h * (y * u0); + + /* the approximation of zz^(1/3) is y - dy */ + let mut y1: f64 = y - dy; + dy = (y - y1) - dy; + + /* the approximation of zz^(1/3) is now y1 + dy, where |dy| < 1/2 ulp(y) + * (for rounding to nearest) */ + let mut ady: f64 = dy.abs(); + + /* For directed roundings, ady0 is tiny when dy is tiny, or ady0 is near + * from ulp(1); + * for rounding to nearest, ady0 is tiny when dy is near from 1/2 ulp(1), + * or from 3/2 ulp(1). */ + let mut ady0: f64 = (ady - off[round as usize]).abs(); + let mut ady1: f64 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs(); + + if ady0 < hf64!("0x1p-75") || ady1 < hf64!("0x1p-75") { + cold_path(); + + y2 = y1 * y1; + y2l = y1.fma(y1, -y2); + y3 = y2 * y1; + y3l = y1.fma(y2, -y3) + y1 * y2l; + h = ((y3 - zz) + y3l) * rr; + dy = h * (y1 * u0); + y = y1 - dy; + dy = (y1 - y) - dy; + y1 = y; + ady = dy.abs(); + ady0 = (ady - off[round as usize]).abs(); + ady1 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs(); + + if ady0 < hf64!("0x1p-98") || ady1 < hf64!("0x1p-98") { + cold_path(); + let azz: f64 = zz.abs(); + + // ~ 0x1.79d15d0e8d59b80000000000000ffc3dp+0 + if azz == hf64!("0x1.9b78223aa307cp+1") { + y1 = hf64!("0x1.79d15d0e8d59cp+0").copysign(zz); + } + + // ~ 0x1.de87aa837820e80000000000001c0f08p+0 + if azz == hf64!("0x1.a202bfc89ddffp+2") { + y1 = hf64!("0x1.de87aa837820fp+0").copysign(zz); + } + + if round != Round::Nearest { + let wlist = [ + (hf64!("0x1.3a9ccd7f022dbp+0"), hf64!("0x1.1236160ba9b93p+0")), // ~ 0x1.1236160ba9b930000000000001e7e8fap+0 + (hf64!("0x1.7845d2faac6fep+0"), hf64!("0x1.23115e657e49cp+0")), // ~ 0x1.23115e657e49c0000000000001d7a799p+0 + (hf64!("0x1.d1ef81cbbbe71p+0"), hf64!("0x1.388fb44cdcf5ap+0")), // ~ 0x1.388fb44cdcf5a0000000000002202c55p+0 + (hf64!("0x1.0a2014f62987cp+1"), hf64!("0x1.46bcbf47dc1e8p+0")), // ~ 0x1.46bcbf47dc1e8000000000000303aa2dp+0 + (hf64!("0x1.fe18a044a5501p+1"), hf64!("0x1.95decfec9c904p+0")), // ~ 0x1.95decfec9c9040000000000000159e8ep+0 + (hf64!("0x1.a6bb8c803147bp+2"), hf64!("0x1.e05335a6401dep+0")), // ~ 0x1.e05335a6401de00000000000027ca017p+0 + (hf64!("0x1.ac8538a031cbdp+2"), hf64!("0x1.e281d87098de8p+0")), // ~ 0x1.e281d87098de80000000000000ee9314p+0 + ]; + + for (a, b) in wlist { + if azz == a { + let tmp = if round as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 }; + y1 = (b + tmp).copysign(zz); + } + } + } + } + } + + let mut cvt3: u64 = y1.to_bits(); + cvt3 = cvt3.wrapping_add(((et.wrapping_sub(342).wrapping_sub(1023)) as u64) << 52); + let m0: u64 = cvt3 << 30; + let m1 = m0 >> 63; + + if (m0 ^ m1) <= (1u64 << 30) { + cold_path(); + + let mut cvt4: u64 = y1.to_bits(); + cvt4 = (cvt4 + (164 << 15)) & 0xffffffffffff0000u64; + + if ((f64::from_bits(cvt4) - y1) - dy).abs() < hf64!("0x1p-60") || (zz).abs() == 1.0 { + cvt3 = (cvt3 + (1u64 << 15)) & 0xffffffffffff0000u64; + } + } + + FpResult::ok(f64::from_bits(cvt3)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn spot_checks() { + if !cfg!(x86_no_sse) { + // Exposes a rounding mode problem. Ignored on i586 because of inaccurate FMA. + assert_biteq!( + cbrt(f64::from_bits(0xf7f792b28f600000)), + f64::from_bits(0xd29ce68655d962f3) + ); + } + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/cbrtf.rs b/library/compiler-builtins/libm/libm/src/math/cbrtf.rs new file mode 100644 index 00000000000..9d70305c647 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/cbrtf.rs @@ -0,0 +1,75 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* cbrtf(x) + * Return cube root of x + */ + +use core::f32; + +const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ +const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ + +/// Cube root (f32) +/// +/// Computes the cube root of the argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cbrtf(x: f32) -> f32 { + let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 + + let mut r: f64; + let mut t: f64; + let mut ui: u32 = x.to_bits(); + let mut hx: u32 = ui & 0x7fffffff; + + if hx >= 0x7f800000 { + /* cbrt(NaN,INF) is itself */ + return x + x; + } + + /* rough cbrt to 5 bits */ + if hx < 0x00800000 { + /* zero or subnormal? */ + if hx == 0 { + return x; /* cbrt(+-0) is itself */ + } + ui = (x * x1p24).to_bits(); + hx = ui & 0x7fffffff; + hx = hx / 3 + B2; + } else { + hx = hx / 3 + B1; + } + ui &= 0x80000000; + ui |= hx; + + /* + * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In + * double precision so that its terms can be arranged for efficiency + * without causing overflow or underflow. + */ + t = f32::from_bits(ui) as f64; + r = t * t * t; + t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); + + /* + * Second step Newton iteration to 47 bits. In double precision for + * efficiency and accuracy. + */ + r = t * t * t; + t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); + + /* rounding to 24 bits is perfect in round-to-nearest mode */ + t as f32 +} diff --git a/library/compiler-builtins/libm/libm/src/math/ceil.rs b/library/compiler-builtins/libm/libm/src/math/ceil.rs new file mode 100644 index 00000000000..4e103545727 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/ceil.rs @@ -0,0 +1,46 @@ +/// Ceil (f16) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf16(x: f16) -> f16 { + super::generic::ceil(x) +} + +/// Ceil (f32) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf(x: f32) -> f32 { + select_implementation! { + name: ceilf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::ceil(x) +} + +/// Ceil (f64) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceil(x: f64) -> f64 { + select_implementation! { + name: ceil, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), + args: x, + } + + super::generic::ceil(x) +} + +/// Ceil (f128) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf128(x: f128) -> f128 { + super::generic::ceil(x) +} diff --git a/library/compiler-builtins/libm/libm/src/math/copysign.rs b/library/compiler-builtins/libm/libm/src/math/copysign.rs new file mode 100644 index 00000000000..d2a86e7fd54 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/copysign.rs @@ -0,0 +1,88 @@ +/// Sign of Y, magnitude of X (f16) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf16(x: f16, y: f16) -> f16 { + super::generic::copysign(x, y) +} + +/// Sign of Y, magnitude of X (f32) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf(x: f32, y: f32) -> f32 { + super::generic::copysign(x, y) +} + +/// Sign of Y, magnitude of X (f64) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysign(x: f64, y: f64) -> f64 { + super::generic::copysign(x, y) +} + +/// Sign of Y, magnitude of X (f128) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf128(x: f128, y: f128) -> f128 { + super::generic::copysign(x, y) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::Float; + + fn spec_test(f: impl Fn(F, F) -> F) { + assert_biteq!(f(F::ZERO, F::ZERO), F::ZERO); + assert_biteq!(f(F::NEG_ZERO, F::ZERO), F::ZERO); + assert_biteq!(f(F::ZERO, F::NEG_ZERO), F::NEG_ZERO); + assert_biteq!(f(F::NEG_ZERO, F::NEG_ZERO), F::NEG_ZERO); + + assert_biteq!(f(F::ONE, F::ONE), F::ONE); + assert_biteq!(f(F::NEG_ONE, F::ONE), F::ONE); + assert_biteq!(f(F::ONE, F::NEG_ONE), F::NEG_ONE); + assert_biteq!(f(F::NEG_ONE, F::NEG_ONE), F::NEG_ONE); + + assert_biteq!(f(F::INFINITY, F::INFINITY), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY, F::INFINITY), F::INFINITY); + assert_biteq!(f(F::INFINITY, F::NEG_INFINITY), F::NEG_INFINITY); + assert_biteq!(f(F::NEG_INFINITY, F::NEG_INFINITY), F::NEG_INFINITY); + + // Not required but we expect it + assert_biteq!(f(F::NAN, F::NAN), F::NAN); + assert_biteq!(f(F::NEG_NAN, F::NAN), F::NAN); + assert_biteq!(f(F::NAN, F::NEG_NAN), F::NEG_NAN); + assert_biteq!(f(F::NEG_NAN, F::NEG_NAN), F::NEG_NAN); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(copysignf16); + } + + #[test] + fn spec_tests_f32() { + spec_test::(copysignf); + } + + #[test] + fn spec_tests_f64() { + spec_test::(copysign); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(copysignf128); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/libm/src/math/copysignf.rs new file mode 100644 index 00000000000..8b9bed4c0c4 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/copysignf.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f32) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf(x: f32, y: f32) -> f32 { + super::generic::copysign(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/copysignf128.rs b/library/compiler-builtins/libm/libm/src/math/copysignf128.rs new file mode 100644 index 00000000000..7bd81d42b2e --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/copysignf128.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f128) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf128(x: f128, y: f128) -> f128 { + super::generic::copysign(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/copysignf16.rs b/library/compiler-builtins/libm/libm/src/math/copysignf16.rs new file mode 100644 index 00000000000..82065868601 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/copysignf16.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f16) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf16(x: f16, y: f16) -> f16 { + super::generic::copysign(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/cos.rs b/library/compiler-builtins/libm/libm/src/math/cos.rs new file mode 100644 index 00000000000..de99cd4c5e4 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/cos.rs @@ -0,0 +1,77 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */ +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +use super::{k_cos, k_sin, rem_pio2}; + +// cos(x) +// Return cosine function of x. +// +// kernel function: +// k_sin ... sine function on [-pi/4,pi/4] +// k_cos ... cosine function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded +// + +/// The cosine of `x` (f64). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cos(x: f64) -> f64 { + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e46a09e { + /* if x < 2**-27 * sqrt(2) */ + /* raise inexact if x != 0 */ + if x as i32 == 0 { + return 1.0; + } + } + return k_cos(x, 0.0); + } + + /* cos(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + match n & 3 { + 0 => k_cos(y0, y1), + 1 => -k_sin(y0, y1, 1), + 2 => -k_cos(y0, y1), + _ => k_sin(y0, y1, 1), + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/cosf.rs b/library/compiler-builtins/libm/libm/src/math/cosf.rs new file mode 100644 index 00000000000..27c2fc3b994 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/cosf.rs @@ -0,0 +1,86 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f64::consts::FRAC_PI_2; + +use super::{k_cosf, k_sinf, rem_pio2f}; + +/* Small multiples of pi/2 rounded to double precision. */ +const C1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +/// The cosine of `x` (f32). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cosf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + /* raise inexact if x != 0 */ + force_eval!(x + x1p120); + return 1.; + } + return k_cosf(x64); + } + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix > 0x4016cbe3 { + /* |x| ~> 3*pi/4 */ + return -k_cosf(if sign { x64 + C2_PIO2 } else { x64 - C2_PIO2 }); + } else if sign { + return k_sinf(x64 + C1_PIO2); + } else { + return k_sinf(C1_PIO2 - x64); + } + } + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix > 0x40afeddf { + /* |x| ~> 7*pi/4 */ + return k_cosf(if sign { x64 + C4_PIO2 } else { x64 - C4_PIO2 }); + } else if sign { + return k_sinf(-x64 - C3_PIO2); + } else { + return k_sinf(x64 - C3_PIO2); + } + } + + /* cos(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x - x; + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + match n & 3 { + 0 => k_cosf(y), + 1 => k_sinf(-y), + 2 => -k_cosf(y), + _ => k_sinf(y), + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/cosh.rs b/library/compiler-builtins/libm/libm/src/math/cosh.rs new file mode 100644 index 00000000000..d2e43fd6cb6 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/cosh.rs @@ -0,0 +1,36 @@ +use super::{exp, expm1, k_expo2}; + +/// Hyperbolic cosine (f64) +/// +/// Computes the hyperbolic cosine of the argument x. +/// Is defined as `(exp(x) + exp(-x))/2` +/// Angles are specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cosh(mut x: f64) -> f64 { + /* |x| */ + let mut ix = x.to_bits(); + ix &= 0x7fffffffffffffff; + x = f64::from_bits(ix); + let w = ix >> 32; + + /* |x| < log(2) */ + if w < 0x3fe62e42 { + if w < 0x3ff00000 - (26 << 20) { + let x1p120 = f64::from_bits(0x4770000000000000); + force_eval!(x + x1p120); + return 1.; + } + let t = expm1(x); // exponential minus 1 + return 1. + t * t / (2. * (1. + t)); + } + + /* |x| < log(DBL_MAX) */ + if w < 0x40862e42 { + let t = exp(x); + /* note: if x>log(0x1p26) then the 1/t is not needed */ + return 0.5 * (t + 1. / t); + } + + /* |x| > log(DBL_MAX) or nan */ + k_expo2(x) +} diff --git a/library/compiler-builtins/libm/libm/src/math/coshf.rs b/library/compiler-builtins/libm/libm/src/math/coshf.rs new file mode 100644 index 00000000000..567a24410e7 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/coshf.rs @@ -0,0 +1,36 @@ +use super::{expf, expm1f, k_expo2f}; + +/// Hyperbolic cosine (f64) +/// +/// Computes the hyperbolic cosine of the argument x. +/// Is defined as `(exp(x) + exp(-x))/2` +/// Angles are specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn coshf(mut x: f32) -> f32 { + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + /* |x| */ + let mut ix = x.to_bits(); + ix &= 0x7fffffff; + x = f32::from_bits(ix); + let w = ix; + + /* |x| < log(2) */ + if w < 0x3f317217 { + if w < (0x3f800000 - (12 << 23)) { + force_eval!(x + x1p120); + return 1.; + } + let t = expm1f(x); + return 1. + t * t / (2. * (1. + t)); + } + + /* |x| < log(FLT_MAX) */ + if w < 0x42b17217 { + let t = expf(x); + return 0.5 * (t + 1. / t); + } + + /* |x| > log(FLT_MAX) or nan */ + k_expo2f(x) +} diff --git a/library/compiler-builtins/libm/libm/src/math/erf.rs b/library/compiler-builtins/libm/libm/src/math/erf.rs new file mode 100644 index 00000000000..1b634abec6b --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/erf.rs @@ -0,0 +1,310 @@ +use super::{exp, fabs, get_high_word, with_set_low_word}; +/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * where R = P/Q where P is an odd poly of degree 8 and + * Q is an odd poly of degree 10. + * -57.90 + * | R - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + * erf(x) = 1 - erfc(x) + * where + * R1(z) = degree 7 poly in z, (z=1/x^2) + * S1(z) = degree 8 poly in z + * + * 4. For x in [1/0.35,28] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +const ERX: f64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +const EFX8: f64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ +const PP0: f64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ +const PP1: f64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ +const PP2: f64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */ +const PP3: f64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */ +const PP4: f64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */ +const QQ1: f64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */ +const QQ2: f64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ +const QQ3: f64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ +const QQ4: f64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ +const QQ5: f64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +const PA0: f64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ +const PA1: f64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ +const PA2: f64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ +const PA3: f64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */ +const PA4: f64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */ +const PA5: f64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */ +const PA6: f64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */ +const QA1: f64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */ +const QA2: f64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */ +const QA3: f64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ +const QA4: f64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ +const QA5: f64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ +const QA6: f64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +const RA0: f64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ +const RA1: f64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ +const RA2: f64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ +const RA3: f64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */ +const RA4: f64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */ +const RA5: f64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */ +const RA6: f64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */ +const RA7: f64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */ +const SA1: f64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */ +const SA2: f64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */ +const SA3: f64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */ +const SA4: f64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */ +const SA5: f64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ +const SA6: f64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ +const SA7: f64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ +const SA8: f64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +const RB0: f64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ +const RB1: f64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ +const RB2: f64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ +const RB3: f64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */ +const RB4: f64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */ +const RB5: f64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */ +const RB6: f64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */ +const SB1: f64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */ +const SB2: f64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */ +const SB3: f64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */ +const SB4: f64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ +const SB5: f64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ +const SB6: f64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ +const SB7: f64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +fn erfc1(x: f64) -> f64 { + let s: f64; + let p: f64; + let q: f64; + + s = fabs(x) - 1.0; + p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); + q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); + + 1.0 - ERX - p / q +} + +fn erfc2(ix: u32, mut x: f64) -> f64 { + let s: f64; + let r: f64; + let big_s: f64; + let z: f64; + + if ix < 0x3ff40000 { + /* |x| < 1.25 */ + return erfc1(x); + } + + x = fabs(x); + s = 1.0 / (x * x); + if ix < 0x4006db6d { + /* |x| < 1/.35 ~ 2.85714 */ + r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); + big_s = 1.0 + + s * (SA1 + + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); + } else { + /* |x| > 1/.35 */ + r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); + big_s = + 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); + } + z = with_set_low_word(x, 0); + + exp(-z * z - 0.5625) * exp((z - x) * (z + x) + r / big_s) / x +} + +/// Error function (f64) +/// +/// Calculates an approximation to the “error function”, which estimates +/// the probability that an observation will fall within x standard +/// deviations of the mean (assuming a normal distribution). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn erf(x: f64) -> f64 { + let r: f64; + let s: f64; + let z: f64; + let y: f64; + let mut ix: u32; + let sign: usize; + + ix = get_high_word(x); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1.0 - 2.0 * (sign as f64) + 1.0 / x; + } + if ix < 0x3feb0000 { + /* |x| < 0.84375 */ + if ix < 0x3e300000 { + /* |x| < 2**-28 */ + /* avoid underflow */ + return 0.125 * (8.0 * x + EFX8 * x); + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + return x + x * y; + } + if ix < 0x40180000 { + /* 0.84375 <= |x| < 6 */ + y = 1.0 - erfc2(ix, x); + } else { + let x1p_1022 = f64::from_bits(0x0010000000000000); + y = 1.0 - x1p_1022; + } + + if sign != 0 { -y } else { y } +} + +/// Complementary error function (f64) +/// +/// Calculates the complementary probability. +/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid +/// the loss of precision that would result from subtracting +/// large probabilities (on large `x`) from 1. +pub fn erfc(x: f64) -> f64 { + let r: f64; + let s: f64; + let z: f64; + let y: f64; + let mut ix: u32; + let sign: usize; + + ix = get_high_word(x); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2.0 * (sign as f64) + 1.0 / x; + } + if ix < 0x3feb0000 { + /* |x| < 0.84375 */ + if ix < 0x3c700000 { + /* |x| < 2**-56 */ + return 1.0 - x; + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + if sign != 0 || ix < 0x3fd00000 { + /* x < 1/4 */ + return 1.0 - (x + x * y); + } + return 0.5 - (x - 0.5 + x * y); + } + if ix < 0x403c0000 { + /* 0.84375 <= |x| < 28 */ + if sign != 0 { + return 2.0 - erfc2(ix, x); + } else { + return erfc2(ix, x); + } + } + + let x1p_1022 = f64::from_bits(0x0010000000000000); + if sign != 0 { 2.0 - x1p_1022 } else { x1p_1022 * x1p_1022 } +} diff --git a/library/compiler-builtins/libm/libm/src/math/erff.rs b/library/compiler-builtins/libm/libm/src/math/erff.rs new file mode 100644 index 00000000000..2e41183bfc0 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/erff.rs @@ -0,0 +1,222 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{expf, fabsf}; + +const ERX: f32 = 8.4506291151e-01; /* 0x3f58560b */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +const EFX8: f32 = 1.0270333290e+00; /* 0x3f8375d4 */ +const PP0: f32 = 1.2837916613e-01; /* 0x3e0375d4 */ +const PP1: f32 = -3.2504209876e-01; /* 0xbea66beb */ +const PP2: f32 = -2.8481749818e-02; /* 0xbce9528f */ +const PP3: f32 = -5.7702702470e-03; /* 0xbbbd1489 */ +const PP4: f32 = -2.3763017452e-05; /* 0xb7c756b1 */ +const QQ1: f32 = 3.9791721106e-01; /* 0x3ecbbbce */ +const QQ2: f32 = 6.5022252500e-02; /* 0x3d852a63 */ +const QQ3: f32 = 5.0813062117e-03; /* 0x3ba68116 */ +const QQ4: f32 = 1.3249473704e-04; /* 0x390aee49 */ +const QQ5: f32 = -3.9602282413e-06; /* 0xb684e21a */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +const PA0: f32 = -2.3621185683e-03; /* 0xbb1acdc6 */ +const PA1: f32 = 4.1485610604e-01; /* 0x3ed46805 */ +const PA2: f32 = -3.7220788002e-01; /* 0xbebe9208 */ +const PA3: f32 = 3.1834661961e-01; /* 0x3ea2fe54 */ +const PA4: f32 = -1.1089469492e-01; /* 0xbde31cc2 */ +const PA5: f32 = 3.5478305072e-02; /* 0x3d1151b3 */ +const PA6: f32 = -2.1663755178e-03; /* 0xbb0df9c0 */ +const QA1: f32 = 1.0642088205e-01; /* 0x3dd9f331 */ +const QA2: f32 = 5.4039794207e-01; /* 0x3f0a5785 */ +const QA3: f32 = 7.1828655899e-02; /* 0x3d931ae7 */ +const QA4: f32 = 1.2617121637e-01; /* 0x3e013307 */ +const QA5: f32 = 1.3637083583e-02; /* 0x3c5f6e13 */ +const QA6: f32 = 1.1984500103e-02; /* 0x3c445aa3 */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +const RA0: f32 = -9.8649440333e-03; /* 0xbc21a093 */ +const RA1: f32 = -6.9385856390e-01; /* 0xbf31a0b7 */ +const RA2: f32 = -1.0558626175e+01; /* 0xc128f022 */ +const RA3: f32 = -6.2375331879e+01; /* 0xc2798057 */ +const RA4: f32 = -1.6239666748e+02; /* 0xc322658c */ +const RA5: f32 = -1.8460508728e+02; /* 0xc3389ae7 */ +const RA6: f32 = -8.1287437439e+01; /* 0xc2a2932b */ +const RA7: f32 = -9.8143291473e+00; /* 0xc11d077e */ +const SA1: f32 = 1.9651271820e+01; /* 0x419d35ce */ +const SA2: f32 = 1.3765776062e+02; /* 0x4309a863 */ +const SA3: f32 = 4.3456588745e+02; /* 0x43d9486f */ +const SA4: f32 = 6.4538726807e+02; /* 0x442158c9 */ +const SA5: f32 = 4.2900814819e+02; /* 0x43d6810b */ +const SA6: f32 = 1.0863500214e+02; /* 0x42d9451f */ +const SA7: f32 = 6.5702495575e+00; /* 0x40d23f7c */ +const SA8: f32 = -6.0424413532e-02; /* 0xbd777f97 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +const RB0: f32 = -9.8649431020e-03; /* 0xbc21a092 */ +const RB1: f32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ +const RB2: f32 = -1.7757955551e+01; /* 0xc18e104b */ +const RB3: f32 = -1.6063638306e+02; /* 0xc320a2ea */ +const RB4: f32 = -6.3756646729e+02; /* 0xc41f6441 */ +const RB5: f32 = -1.0250950928e+03; /* 0xc480230b */ +const RB6: f32 = -4.8351919556e+02; /* 0xc3f1c275 */ +const SB1: f32 = 3.0338060379e+01; /* 0x41f2b459 */ +const SB2: f32 = 3.2579251099e+02; /* 0x43a2e571 */ +const SB3: f32 = 1.5367296143e+03; /* 0x44c01759 */ +const SB4: f32 = 3.1998581543e+03; /* 0x4547fdbb */ +const SB5: f32 = 2.5530502930e+03; /* 0x451f90ce */ +const SB6: f32 = 4.7452853394e+02; /* 0x43ed43a7 */ +const SB7: f32 = -2.2440952301e+01; /* 0xc1b38712 */ + +fn erfc1(x: f32) -> f32 { + let s: f32; + let p: f32; + let q: f32; + + s = fabsf(x) - 1.0; + p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); + q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); + return 1.0 - ERX - p / q; +} + +fn erfc2(mut ix: u32, mut x: f32) -> f32 { + let s: f32; + let r: f32; + let big_s: f32; + let z: f32; + + if ix < 0x3fa00000 { + /* |x| < 1.25 */ + return erfc1(x); + } + + x = fabsf(x); + s = 1.0 / (x * x); + if ix < 0x4036db6d { + /* |x| < 1/0.35 */ + r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); + big_s = 1.0 + + s * (SA1 + + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); + } else { + /* |x| >= 1/0.35 */ + r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); + big_s = + 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); + } + ix = x.to_bits(); + z = f32::from_bits(ix & 0xffffe000); + + expf(-z * z - 0.5625) * expf((z - x) * (z + x) + r / big_s) / x +} + +/// Error function (f32) +/// +/// Calculates an approximation to the “error function”, which estimates +/// the probability that an observation will fall within x standard +/// deviations of the mean (assuming a normal distribution). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn erff(x: f32) -> f32 { + let r: f32; + let s: f32; + let z: f32; + let y: f32; + let mut ix: u32; + let sign: usize; + + ix = x.to_bits(); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1.0 - 2.0 * (sign as f32) + 1.0 / x; + } + if ix < 0x3f580000 { + /* |x| < 0.84375 */ + if ix < 0x31800000 { + /* |x| < 2**-28 */ + /*avoid underflow */ + return 0.125 * (8.0 * x + EFX8 * x); + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + return x + x * y; + } + if ix < 0x40c00000 { + /* |x| < 6 */ + y = 1.0 - erfc2(ix, x); + } else { + let x1p_120 = f32::from_bits(0x03800000); + y = 1.0 - x1p_120; + } + + if sign != 0 { -y } else { y } +} + +/// Complementary error function (f32) +/// +/// Calculates the complementary probability. +/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid +/// the loss of precision that would result from subtracting +/// large probabilities (on large `x`) from 1. +pub fn erfcf(x: f32) -> f32 { + let r: f32; + let s: f32; + let z: f32; + let y: f32; + let mut ix: u32; + let sign: usize; + + ix = x.to_bits(); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2.0 * (sign as f32) + 1.0 / x; + } + + if ix < 0x3f580000 { + /* |x| < 0.84375 */ + if ix < 0x23800000 { + /* |x| < 2**-56 */ + return 1.0 - x; + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + if sign != 0 || ix < 0x3e800000 { + /* x < 1/4 */ + return 1.0 - (x + x * y); + } + return 0.5 - (x - 0.5 + x * y); + } + if ix < 0x41e00000 { + /* |x| < 28 */ + if sign != 0 { + return 2.0 - erfc2(ix, x); + } else { + return erfc2(ix, x); + } + } + + let x1p_120 = f32::from_bits(0x03800000); + if sign != 0 { 2.0 - x1p_120 } else { x1p_120 * x1p_120 } +} diff --git a/library/compiler-builtins/libm/libm/src/math/exp.rs b/library/compiler-builtins/libm/libm/src/math/exp.rs new file mode 100644 index 00000000000..782042b62cd --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/exp.rs @@ -0,0 +1,150 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* exp(x) + * Returns the exponential of x. + * + * Method + * 1. Argument reduction: + * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2. + * + * Here r will be represented as r = hi-lo for better + * accuracy. + * + * 2. Approximation of exp(r) by a special rational function on + * the interval [0,0.34658]: + * Write + * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... + * We use a special Remez algorithm on [0,0.34658] to generate + * a polynomial of degree 5 to approximate R. The maximum error + * of this polynomial approximation is bounded by 2**-59. In + * other words, + * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 + * (where z=r*r, and the values of P1 to P5 are listed below) + * and + * | 5 | -59 + * | 2.0+P1*z+...+P5*z - R(z) | <= 2 + * | | + * The computation of exp(r) thus becomes + * 2*r + * exp(r) = 1 + ---------- + * R(r) - r + * r*c(r) + * = 1 + r + ----------- (for better accuracy) + * 2 - c(r) + * where + * 2 4 10 + * c(r) = r - (P1*r + P2*r + ... + P5*r ). + * + * 3. Scale back to obtain exp(x): + * From step 1, we have + * exp(x) = 2^k * exp(r) + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF) is 0, and + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 709.782712893383973096 then exp(x) overflows + * if x < -745.133219101941108420 then exp(x) underflows + */ + +use super::scalbn; + +const HALF: [f64; 2] = [0.5, -0.5]; +const LN2HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ +const LN2LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ +const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ +const P1: f64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */ +const P2: f64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ +const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ +const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ +const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +/// Exponential, base *e* (f64) +/// +/// Calculate the exponential of `x`, that is, *e* raised to the power `x` +/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp(mut x: f64) -> f64 { + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 + let x1p_149 = f64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149 + + let hi: f64; + let lo: f64; + let c: f64; + let xx: f64; + let y: f64; + let k: i32; + let sign: i32; + let mut hx: u32; + + hx = (x.to_bits() >> 32) as u32; + sign = (hx >> 31) as i32; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if hx >= 0x4086232b { + /* if |x| >= 708.39... */ + if x.is_nan() { + return x; + } + if x > 709.782712893383973096 { + /* overflow if x!=inf */ + x *= x1p1023; + return x; + } + if x < -708.39641853226410622 { + /* underflow if x!=-inf */ + force_eval!((-x1p_149 / x) as f32); + if x < -745.13321910194110842 { + return 0.; + } + } + } + + /* argument reduction */ + if hx > 0x3fd62e42 { + /* if |x| > 0.5 ln2 */ + if hx >= 0x3ff0a2b2 { + /* if |x| >= 1.5 ln2 */ + k = (INVLN2 * x + i!(HALF, sign as usize)) as i32; + } else { + k = 1 - sign - sign; + } + hi = x - k as f64 * LN2HI; /* k*ln2hi is exact here */ + lo = k as f64 * LN2LO; + x = hi - lo; + } else if hx > 0x3e300000 { + /* if |x| > 2**-28 */ + k = 0; + hi = x; + lo = 0.; + } else { + /* inexact if x!=0 */ + force_eval!(x1p1023 + x); + return 1. + x; + } + + /* x is now in primary range */ + xx = x * x; + c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); + y = 1. + (x * c / (2. - c) - lo + hi); + if k == 0 { y } else { scalbn(y, k) } +} diff --git a/library/compiler-builtins/libm/libm/src/math/exp10.rs b/library/compiler-builtins/libm/libm/src/math/exp10.rs new file mode 100644 index 00000000000..7c33c92b603 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/exp10.rs @@ -0,0 +1,23 @@ +use super::{exp2, modf, pow}; + +const LN10: f64 = 3.32192809488736234787031942948939; +const P10: &[f64] = &[ + 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, +]; + +/// Calculates 10 raised to the power of `x` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp10(x: f64) -> f64 { + let (mut y, n) = modf(x); + let u: u64 = n.to_bits(); + /* fabs(n) < 16 without raising invalid on nan */ + if ((u >> 52) & 0x7ff) < 0x3ff + 4 { + if y == 0.0 { + return i!(P10, ((n as isize) + 15) as usize); + } + y = exp2(LN10 * y); + return y * i!(P10, ((n as isize) + 15) as usize); + } + return pow(10.0, x); +} diff --git a/library/compiler-builtins/libm/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/libm/src/math/exp10f.rs new file mode 100644 index 00000000000..0520a41f2e9 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/exp10f.rs @@ -0,0 +1,22 @@ +use super::{exp2, exp2f, modff}; + +const LN10_F32: f32 = 3.32192809488736234787031942948939; +const LN10_F64: f64 = 3.32192809488736234787031942948939; +const P10: &[f32] = + &[1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7]; + +/// Calculates 10 raised to the power of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp10f(x: f32) -> f32 { + let (mut y, n) = modff(x); + let u = n.to_bits(); + /* fabsf(n) < 8 without raising invalid on nan */ + if ((u >> 23) & 0xff) < 0x7f + 3 { + if y == 0.0 { + return i!(P10, ((n as isize) + 7) as usize); + } + y = exp2f(LN10_F32 * y); + return y * i!(P10, ((n as isize) + 7) as usize); + } + return exp2(LN10_F64 * (x as f64)) as f32; +} diff --git a/library/compiler-builtins/libm/libm/src/math/exp2.rs b/library/compiler-builtins/libm/libm/src/math/exp2.rs new file mode 100644 index 00000000000..6e98d066cbf --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/exp2.rs @@ -0,0 +1,394 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */ +//- +// Copyright (c) 2005 David Schultz +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +use super::scalbn; + +const TBLSIZE: usize = 256; + +#[rustfmt::skip] +static TBL: [u64; TBLSIZE * 2] = [ + // exp2(z + eps) eps + 0x3fe6a09e667f3d5d, 0x3d39880000000000, + 0x3fe6b052fa751744, 0x3cd8000000000000, + 0x3fe6c012750bd9fe, 0xbd28780000000000, + 0x3fe6cfdcddd476bf, 0x3d1ec00000000000, + 0x3fe6dfb23c651a29, 0xbcd8000000000000, + 0x3fe6ef9298593ae3, 0xbcbc000000000000, + 0x3fe6ff7df9519386, 0xbd2fd80000000000, + 0x3fe70f7466f42da3, 0xbd2c880000000000, + 0x3fe71f75e8ec5fc3, 0x3d13c00000000000, + 0x3fe72f8286eacf05, 0xbd38300000000000, + 0x3fe73f9a48a58152, 0xbd00c00000000000, + 0x3fe74fbd35d7ccfc, 0x3d2f880000000000, + 0x3fe75feb564267f1, 0x3d03e00000000000, + 0x3fe77024b1ab6d48, 0xbd27d00000000000, + 0x3fe780694fde5d38, 0xbcdd000000000000, + 0x3fe790b938ac1d00, 0x3ce3000000000000, + 0x3fe7a11473eb0178, 0xbced000000000000, + 0x3fe7b17b0976d060, 0x3d20400000000000, + 0x3fe7c1ed0130c133, 0x3ca0000000000000, + 0x3fe7d26a62ff8636, 0xbd26900000000000, + 0x3fe7e2f336cf4e3b, 0xbd02e00000000000, + 0x3fe7f3878491c3e8, 0xbd24580000000000, + 0x3fe80427543e1b4e, 0x3d33000000000000, + 0x3fe814d2add1071a, 0x3d0f000000000000, + 0x3fe82589994ccd7e, 0xbd21c00000000000, + 0x3fe8364c1eb942d0, 0x3d29d00000000000, + 0x3fe8471a4623cab5, 0x3d47100000000000, + 0x3fe857f4179f5bbc, 0x3d22600000000000, + 0x3fe868d99b4491af, 0xbd32c40000000000, + 0x3fe879cad931a395, 0xbd23000000000000, + 0x3fe88ac7d98a65b8, 0xbd2a800000000000, + 0x3fe89bd0a4785800, 0xbced000000000000, + 0x3fe8ace5422aa223, 0x3d33280000000000, + 0x3fe8be05bad619fa, 0x3d42b40000000000, + 0x3fe8cf3216b54383, 0xbd2ed00000000000, + 0x3fe8e06a5e08664c, 0xbd20500000000000, + 0x3fe8f1ae99157807, 0x3d28280000000000, + 0x3fe902fed0282c0e, 0xbd1cb00000000000, + 0x3fe9145b0b91ff96, 0xbd05e00000000000, + 0x3fe925c353aa2ff9, 0x3cf5400000000000, + 0x3fe93737b0cdc64a, 0x3d17200000000000, + 0x3fe948b82b5f98ae, 0xbd09000000000000, + 0x3fe95a44cbc852cb, 0x3d25680000000000, + 0x3fe96bdd9a766f21, 0xbd36d00000000000, + 0x3fe97d829fde4e2a, 0xbd01000000000000, + 0x3fe98f33e47a23a3, 0x3d2d000000000000, + 0x3fe9a0f170ca0604, 0xbd38a40000000000, + 0x3fe9b2bb4d53ff89, 0x3d355c0000000000, + 0x3fe9c49182a3f15b, 0x3d26b80000000000, + 0x3fe9d674194bb8c5, 0xbcec000000000000, + 0x3fe9e86319e3238e, 0x3d17d00000000000, + 0x3fe9fa5e8d07f302, 0x3d16400000000000, + 0x3fea0c667b5de54d, 0xbcf5000000000000, + 0x3fea1e7aed8eb8f6, 0x3d09e00000000000, + 0x3fea309bec4a2e27, 0x3d2ad80000000000, + 0x3fea42c980460a5d, 0xbd1af00000000000, + 0x3fea5503b23e259b, 0x3d0b600000000000, + 0x3fea674a8af46213, 0x3d38880000000000, + 0x3fea799e1330b3a7, 0x3d11200000000000, + 0x3fea8bfe53c12e8d, 0x3d06c00000000000, + 0x3fea9e6b5579fcd2, 0xbd29b80000000000, + 0x3feab0e521356fb8, 0x3d2b700000000000, + 0x3feac36bbfd3f381, 0x3cd9000000000000, + 0x3fead5ff3a3c2780, 0x3ce4000000000000, + 0x3feae89f995ad2a3, 0xbd2c900000000000, + 0x3feafb4ce622f367, 0x3d16500000000000, + 0x3feb0e07298db790, 0x3d2fd40000000000, + 0x3feb20ce6c9a89a9, 0x3d12700000000000, + 0x3feb33a2b84f1a4b, 0x3d4d470000000000, + 0x3feb468415b747e7, 0xbd38380000000000, + 0x3feb59728de5593a, 0x3c98000000000000, + 0x3feb6c6e29f1c56a, 0x3d0ad00000000000, + 0x3feb7f76f2fb5e50, 0x3cde800000000000, + 0x3feb928cf22749b2, 0xbd04c00000000000, + 0x3feba5b030a10603, 0xbd0d700000000000, + 0x3febb8e0b79a6f66, 0x3d0d900000000000, + 0x3febcc1e904bc1ff, 0x3d02a00000000000, + 0x3febdf69c3f3a16f, 0xbd1f780000000000, + 0x3febf2c25bd71db8, 0xbd10a00000000000, + 0x3fec06286141b2e9, 0xbd11400000000000, + 0x3fec199bdd8552e0, 0x3d0be00000000000, + 0x3fec2d1cd9fa64ee, 0xbd09400000000000, + 0x3fec40ab5fffd02f, 0xbd0ed00000000000, + 0x3fec544778fafd15, 0x3d39660000000000, + 0x3fec67f12e57d0cb, 0xbd1a100000000000, + 0x3fec7ba88988c1b6, 0xbd58458000000000, + 0x3fec8f6d9406e733, 0xbd1a480000000000, + 0x3feca3405751c4df, 0x3ccb000000000000, + 0x3fecb720dcef9094, 0x3d01400000000000, + 0x3feccb0f2e6d1689, 0x3cf0200000000000, + 0x3fecdf0b555dc412, 0x3cf3600000000000, + 0x3fecf3155b5bab3b, 0xbd06900000000000, + 0x3fed072d4a0789bc, 0x3d09a00000000000, + 0x3fed1b532b08c8fa, 0xbd15e00000000000, + 0x3fed2f87080d8a85, 0x3d1d280000000000, + 0x3fed43c8eacaa203, 0x3d01a00000000000, + 0x3fed5818dcfba491, 0x3cdf000000000000, + 0x3fed6c76e862e6a1, 0xbd03a00000000000, + 0x3fed80e316c9834e, 0xbd0cd80000000000, + 0x3fed955d71ff6090, 0x3cf4c00000000000, + 0x3feda9e603db32ae, 0x3cff900000000000, + 0x3fedbe7cd63a8325, 0x3ce9800000000000, + 0x3fedd321f301b445, 0xbcf5200000000000, + 0x3fede7d5641c05bf, 0xbd1d700000000000, + 0x3fedfc97337b9aec, 0xbd16140000000000, + 0x3fee11676b197d5e, 0x3d0b480000000000, + 0x3fee264614f5a3e7, 0x3d40ce0000000000, + 0x3fee3b333b16ee5c, 0x3d0c680000000000, + 0x3fee502ee78b3fb4, 0xbd09300000000000, + 0x3fee653924676d68, 0xbce5000000000000, + 0x3fee7a51fbc74c44, 0xbd07f80000000000, + 0x3fee8f7977cdb726, 0xbcf3700000000000, + 0x3feea4afa2a490e8, 0x3ce5d00000000000, + 0x3feeb9f4867ccae4, 0x3d161a0000000000, + 0x3feecf482d8e680d, 0x3cf5500000000000, + 0x3feee4aaa2188514, 0x3cc6400000000000, + 0x3feefa1bee615a13, 0xbcee800000000000, + 0x3fef0f9c1cb64106, 0xbcfa880000000000, + 0x3fef252b376bb963, 0xbd2c900000000000, + 0x3fef3ac948dd7275, 0x3caa000000000000, + 0x3fef50765b6e4524, 0xbcf4f00000000000, + 0x3fef6632798844fd, 0x3cca800000000000, + 0x3fef7bfdad9cbe38, 0x3cfabc0000000000, + 0x3fef91d802243c82, 0xbcd4600000000000, + 0x3fefa7c1819e908e, 0xbd0b0c0000000000, + 0x3fefbdba3692d511, 0xbcc0e00000000000, + 0x3fefd3c22b8f7194, 0xbd10de8000000000, + 0x3fefe9d96b2a23ee, 0x3cee430000000000, + 0x3ff0000000000000, 0x0, + 0x3ff00b1afa5abcbe, 0xbcb3400000000000, + 0x3ff0163da9fb3303, 0xbd12170000000000, + 0x3ff02168143b0282, 0x3cba400000000000, + 0x3ff02c9a3e77806c, 0x3cef980000000000, + 0x3ff037d42e11bbca, 0xbcc7400000000000, + 0x3ff04315e86e7f89, 0x3cd8300000000000, + 0x3ff04e5f72f65467, 0xbd1a3f0000000000, + 0x3ff059b0d315855a, 0xbd02840000000000, + 0x3ff0650a0e3c1f95, 0x3cf1600000000000, + 0x3ff0706b29ddf71a, 0x3d15240000000000, + 0x3ff07bd42b72a82d, 0xbce9a00000000000, + 0x3ff0874518759bd0, 0x3ce6400000000000, + 0x3ff092bdf66607c8, 0xbd00780000000000, + 0x3ff09e3ecac6f383, 0xbc98000000000000, + 0x3ff0a9c79b1f3930, 0x3cffa00000000000, + 0x3ff0b5586cf988fc, 0xbcfac80000000000, + 0x3ff0c0f145e46c8a, 0x3cd9c00000000000, + 0x3ff0cc922b724816, 0x3d05200000000000, + 0x3ff0d83b23395dd8, 0xbcfad00000000000, + 0x3ff0e3ec32d3d1f3, 0x3d1bac0000000000, + 0x3ff0efa55fdfa9a6, 0xbd04e80000000000, + 0x3ff0fb66affed2f0, 0xbd0d300000000000, + 0x3ff1073028d7234b, 0x3cf1500000000000, + 0x3ff11301d0125b5b, 0x3cec000000000000, + 0x3ff11edbab5e2af9, 0x3d16bc0000000000, + 0x3ff12abdc06c31d5, 0x3ce8400000000000, + 0x3ff136a814f2047d, 0xbd0ed00000000000, + 0x3ff1429aaea92de9, 0x3ce8e00000000000, + 0x3ff14e95934f3138, 0x3ceb400000000000, + 0x3ff15a98c8a58e71, 0x3d05300000000000, + 0x3ff166a45471c3df, 0x3d03380000000000, + 0x3ff172b83c7d5211, 0x3d28d40000000000, + 0x3ff17ed48695bb9f, 0xbd05d00000000000, + 0x3ff18af9388c8d93, 0xbd1c880000000000, + 0x3ff1972658375d66, 0x3d11f00000000000, + 0x3ff1a35beb6fcba7, 0x3d10480000000000, + 0x3ff1af99f81387e3, 0xbd47390000000000, + 0x3ff1bbe084045d54, 0x3d24e40000000000, + 0x3ff1c82f95281c43, 0xbd0a200000000000, + 0x3ff1d4873168b9b2, 0x3ce3800000000000, + 0x3ff1e0e75eb44031, 0x3ceac00000000000, + 0x3ff1ed5022fcd938, 0x3d01900000000000, + 0x3ff1f9c18438cdf7, 0xbd1b780000000000, + 0x3ff2063b88628d8f, 0x3d2d940000000000, + 0x3ff212be3578a81e, 0x3cd8000000000000, + 0x3ff21f49917ddd41, 0x3d2b340000000000, + 0x3ff22bdda2791323, 0x3d19f80000000000, + 0x3ff2387a6e7561e7, 0xbd19c80000000000, + 0x3ff2451ffb821427, 0x3d02300000000000, + 0x3ff251ce4fb2a602, 0xbd13480000000000, + 0x3ff25e85711eceb0, 0x3d12700000000000, + 0x3ff26b4565e27d16, 0x3d11d00000000000, + 0x3ff2780e341de00f, 0x3d31ee0000000000, + 0x3ff284dfe1f5633e, 0xbd14c00000000000, + 0x3ff291ba7591bb30, 0xbd13d80000000000, + 0x3ff29e9df51fdf09, 0x3d08b00000000000, + 0x3ff2ab8a66d10e9b, 0xbd227c0000000000, + 0x3ff2b87fd0dada3a, 0x3d2a340000000000, + 0x3ff2c57e39771af9, 0xbd10800000000000, + 0x3ff2d285a6e402d9, 0xbd0ed00000000000, + 0x3ff2df961f641579, 0xbcf4200000000000, + 0x3ff2ecafa93e2ecf, 0xbd24980000000000, + 0x3ff2f9d24abd8822, 0xbd16300000000000, + 0x3ff306fe0a31b625, 0xbd32360000000000, + 0x3ff31432edeea50b, 0xbd70df8000000000, + 0x3ff32170fc4cd7b8, 0xbd22480000000000, + 0x3ff32eb83ba8e9a2, 0xbd25980000000000, + 0x3ff33c08b2641766, 0x3d1ed00000000000, + 0x3ff3496266e3fa27, 0xbcdc000000000000, + 0x3ff356c55f929f0f, 0xbd30d80000000000, + 0x3ff36431a2de88b9, 0x3d22c80000000000, + 0x3ff371a7373aaa39, 0x3d20600000000000, + 0x3ff37f26231e74fe, 0xbd16600000000000, + 0x3ff38cae6d05d838, 0xbd0ae00000000000, + 0x3ff39a401b713ec3, 0xbd44720000000000, + 0x3ff3a7db34e5a020, 0x3d08200000000000, + 0x3ff3b57fbfec6e95, 0x3d3e800000000000, + 0x3ff3c32dc313a8f2, 0x3cef800000000000, + 0x3ff3d0e544ede122, 0xbd17a00000000000, + 0x3ff3dea64c1234bb, 0x3d26300000000000, + 0x3ff3ec70df1c4ecc, 0xbd48a60000000000, + 0x3ff3fa4504ac7e8c, 0xbd3cdc0000000000, + 0x3ff40822c367a0bb, 0x3d25b80000000000, + 0x3ff4160a21f72e95, 0x3d1ec00000000000, + 0x3ff423fb27094646, 0xbd13600000000000, + 0x3ff431f5d950a920, 0x3d23980000000000, + 0x3ff43ffa3f84b9eb, 0x3cfa000000000000, + 0x3ff44e0860618919, 0xbcf6c00000000000, + 0x3ff45c2042a7d201, 0xbd0bc00000000000, + 0x3ff46a41ed1d0016, 0xbd12800000000000, + 0x3ff4786d668b3326, 0x3d30e00000000000, + 0x3ff486a2b5c13c00, 0xbd2d400000000000, + 0x3ff494e1e192af04, 0x3d0c200000000000, + 0x3ff4a32af0d7d372, 0xbd1e500000000000, + 0x3ff4b17dea6db801, 0x3d07800000000000, + 0x3ff4bfdad53629e1, 0xbd13800000000000, + 0x3ff4ce41b817c132, 0x3d00800000000000, + 0x3ff4dcb299fddddb, 0x3d2c700000000000, + 0x3ff4eb2d81d8ab96, 0xbd1ce00000000000, + 0x3ff4f9b2769d2d02, 0x3d19200000000000, + 0x3ff508417f4531c1, 0xbd08c00000000000, + 0x3ff516daa2cf662a, 0xbcfa000000000000, + 0x3ff5257de83f51ea, 0x3d4a080000000000, + 0x3ff5342b569d4eda, 0xbd26d80000000000, + 0x3ff542e2f4f6ac1a, 0xbd32440000000000, + 0x3ff551a4ca5d94db, 0x3d483c0000000000, + 0x3ff56070dde9116b, 0x3d24b00000000000, + 0x3ff56f4736b529de, 0x3d415a0000000000, + 0x3ff57e27dbe2c40e, 0xbd29e00000000000, + 0x3ff58d12d497c76f, 0xbd23080000000000, + 0x3ff59c0827ff0b4c, 0x3d4dec0000000000, + 0x3ff5ab07dd485427, 0xbcc4000000000000, + 0x3ff5ba11fba87af4, 0x3d30080000000000, + 0x3ff5c9268a59460b, 0xbd26c80000000000, + 0x3ff5d84590998e3f, 0x3d469a0000000000, + 0x3ff5e76f15ad20e1, 0xbd1b400000000000, + 0x3ff5f6a320dcebca, 0x3d17700000000000, + 0x3ff605e1b976dcb8, 0x3d26f80000000000, + 0x3ff6152ae6cdf715, 0x3d01000000000000, + 0x3ff6247eb03a5531, 0xbd15d00000000000, + 0x3ff633dd1d1929b5, 0xbd12d00000000000, + 0x3ff6434634ccc313, 0xbcea800000000000, + 0x3ff652b9febc8efa, 0xbd28600000000000, + 0x3ff6623882553397, 0x3d71fe0000000000, + 0x3ff671c1c708328e, 0xbd37200000000000, + 0x3ff68155d44ca97e, 0x3ce6800000000000, + 0x3ff690f4b19e9471, 0xbd29780000000000, +]; + +// exp2(x): compute the base 2 exponential of x +// +// Accuracy: Peak error < 0.503 ulp for normalized results. +// +// Method: (accurate tables) +// +// Reduce x: +// x = k + y, for integer k and |y| <= 1/2. +// Thus we have exp2(x) = 2**k * exp2(y). +// +// Reduce y: +// y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. +// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), +// with |z - eps[i]| <= 2**-9 + 2**-39 for the table used. +// +// We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via +// a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61. +// The values in exp2t[] and eps[] are chosen such that +// exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such +// that exp2t[i] is accurate to 2**-64. +// +// Note that the range of i is +-TBLSIZE/2, so we actually index the tables +// by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are +// virtual tables, interleaved in the real table tbl[]. +// +// This method is due to Gal, with many details due to Gal and Bachelis: +// +// Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library +// for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + +/// Exponential, base 2 (f64) +/// +/// Calculate `2^x`, that is, 2 raised to the power `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp2(mut x: f64) -> f64 { + let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64; + let p1 = f64::from_bits(0x3fe62e42fefa39ef); + let p2 = f64::from_bits(0x3fcebfbdff82c575); + let p3 = f64::from_bits(0x3fac6b08d704a0a6); + let p4 = f64::from_bits(0x3f83b2ab88f70400); + let p5 = f64::from_bits(0x3f55d88003875c74); + + // double_t r, t, z; + // uint32_t ix, i0; + // union {double f; uint64_t i;} u = {x}; + // union {uint32_t u; int32_t i;} k; + let x1p1023 = f64::from_bits(0x7fe0000000000000); + let x1p52 = f64::from_bits(0x4330000000000000); + let _0x1p_149 = f64::from_bits(0xb6a0000000000000); + + /* Filter out exceptional cases. */ + let ui = f64::to_bits(x); + let ix = (ui >> 32) & 0x7fffffff; + if ix >= 0x408ff000 { + /* |x| >= 1022 or nan */ + if ix >= 0x40900000 && ui >> 63 == 0 { + /* x >= 1024 or nan */ + /* overflow */ + x *= x1p1023; + return x; + } + if ix >= 0x7ff00000 { + /* -inf or -nan */ + return -1.0 / x; + } + if ui >> 63 != 0 { + /* x <= -1022 */ + /* underflow */ + if x <= -1075.0 || x - x1p52 + x1p52 != x { + force_eval!((_0x1p_149 / x) as f32); + } + if x <= -1075.0 { + return 0.0; + } + } + } else if ix < 0x3c900000 { + /* |x| < 0x1p-54 */ + return 1.0 + x; + } + + /* Reduce x, computing z, i0, and k. */ + let ui = f64::to_bits(x + redux); + let mut i0 = ui as u32; + i0 = i0.wrapping_add(TBLSIZE as u32 / 2); + let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32; + let ki = div!(ku as i32, TBLSIZE as i32); + i0 %= TBLSIZE as u32; + let uf = f64::from_bits(ui) - redux; + let mut z = x - uf; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + let t = f64::from_bits(i!(TBL, 2 * i0 as usize)); /* exp2t[i0] */ + z -= f64::from_bits(i!(TBL, 2 * i0 as usize + 1)); /* eps[i0] */ + let r = t + t * z * (p1 + z * (p2 + z * (p3 + z * (p4 + z * p5)))); + + scalbn(r, ki) +} + +#[test] +fn i0_wrap_test() { + let x = -3.0 / 256.0; + assert_eq!(exp2(x), f64::from_bits(0x3fefbdba3692d514)); +} diff --git a/library/compiler-builtins/libm/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/libm/src/math/exp2f.rs new file mode 100644 index 00000000000..f452b6a20f8 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/exp2f.rs @@ -0,0 +1,135 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c +//- +// Copyright (c) 2005 David Schultz +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +const TBLSIZE: usize = 16; + +static EXP2FT: [u64; TBLSIZE] = [ + 0x3fe6a09e667f3bcd, + 0x3fe7a11473eb0187, + 0x3fe8ace5422aa0db, + 0x3fe9c49182a3f090, + 0x3feae89f995ad3ad, + 0x3fec199bdd85529c, + 0x3fed5818dcfba487, + 0x3feea4afa2a490da, + 0x3ff0000000000000, + 0x3ff0b5586cf9890f, + 0x3ff172b83c7d517b, + 0x3ff2387a6e756238, + 0x3ff306fe0a31b715, + 0x3ff3dea64c123422, + 0x3ff4bfdad5362a27, + 0x3ff5ab07dd485429, +]; + +// exp2f(x): compute the base 2 exponential of x +// +// Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. +// +// Method: (equally-spaced tables) +// +// Reduce x: +// x = k + y, for integer k and |y| <= 1/2. +// Thus we have exp2f(x) = 2**k * exp2(y). +// +// Reduce y: +// y = i/TBLSIZE + z for integer i near y * TBLSIZE. +// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), +// with |z| <= 2**-(TBLSIZE+1). +// +// We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a +// degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. +// Using double precision for everything except the reduction makes +// roundoff error insignificant and simplifies the scaling step. +// +// This method is due to Tang, but I do not use his suggested parameters: +// +// Tang, P. Table-driven Implementation of the Exponential Function +// in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). + +/// Exponential, base 2 (f32) +/// +/// Calculate `2^x`, that is, 2 raised to the power `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp2f(mut x: f32) -> f32 { + let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; + let p1 = f32::from_bits(0x3f317218); + let p2 = f32::from_bits(0x3e75fdf0); + let p3 = f32::from_bits(0x3d6359a4); + let p4 = f32::from_bits(0x3c1d964e); + + // double_t t, r, z; + // uint32_t ix, i0, k; + + let x1p127 = f32::from_bits(0x7f000000); + + /* Filter out exceptional cases. */ + let ui = f32::to_bits(x); + let ix = ui & 0x7fffffff; + if ix > 0x42fc0000 { + /* |x| > 126 */ + if ix > 0x7f800000 { + /* NaN */ + return x; + } + if (0x43000000..0x80000000).contains(&ui) { + /* x >= 128 */ + x *= x1p127; + return x; + } + if ui >= 0x80000000 { + /* x < -126 */ + if ui >= 0xc3160000 || (ui & 0x0000ffff != 0) { + force_eval!(f32::from_bits(0x80000001) / x); + } + if ui >= 0xc3160000 { + /* x <= -150 */ + return 0.0; + } + } + } else if ix <= 0x33000000 { + /* |x| <= 0x1p-25 */ + return 1.0 + x; + } + + /* Reduce x, computing z, i0, and k. */ + let ui = f32::to_bits(x + redux); + let mut i0 = ui; + i0 += TBLSIZE as u32 / 2; + let k = i0 / TBLSIZE as u32; + let ukf = f64::from_bits(((0x3ff + k) as u64) << 52); + i0 &= TBLSIZE as u32 - 1; + let mut uf = f32::from_bits(ui); + uf -= redux; + let z: f64 = (x - uf) as f64; + /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ + let r: f64 = f64::from_bits(i!(EXP2FT, i0 as usize)); + let t: f64 = r * z; + let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64); + + /* Scale by 2**k */ + (r * ukf) as f32 +} diff --git a/library/compiler-builtins/libm/libm/src/math/expf.rs b/library/compiler-builtins/libm/libm/src/math/expf.rs new file mode 100644 index 00000000000..8dc067ab084 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/expf.rs @@ -0,0 +1,97 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::scalbnf; + +const HALF: [f32; 2] = [0.5, -0.5]; +const LN2_HI: f32 = 6.9314575195e-01; /* 0x3f317200 */ +const LN2_LO: f32 = 1.4286067653e-06; /* 0x35bfbe8e */ +const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: + * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 + */ +const P1: f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ +const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ + +/// Exponential, base *e* (f32) +/// +/// Calculate the exponential of `x`, that is, *e* raised to the power `x` +/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn expf(mut x: f32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ + let mut hx = x.to_bits(); + let sign = (hx >> 31) as i32; /* sign bit of x */ + let signb: bool = sign != 0; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if hx >= 0x42aeac50 { + /* if |x| >= -87.33655f or NaN */ + if hx > 0x7f800000 { + /* NaN */ + return x; + } + if (hx >= 0x42b17218) && (!signb) { + /* x >= 88.722839f */ + /* overflow */ + x *= x1p127; + return x; + } + if signb { + /* underflow */ + force_eval!(-x1p_126 / x); + if hx >= 0x42cff1b5 { + /* x <= -103.972084f */ + return 0.; + } + } + } + + /* argument reduction */ + let k: i32; + let hi: f32; + let lo: f32; + if hx > 0x3eb17218 { + /* if |x| > 0.5 ln2 */ + if hx > 0x3f851592 { + /* if |x| > 1.5 ln2 */ + k = (INV_LN2 * x + i!(HALF, sign as usize)) as i32; + } else { + k = 1 - sign - sign; + } + let kf = k as f32; + hi = x - kf * LN2_HI; /* k*ln2hi is exact here */ + lo = kf * LN2_LO; + x = hi - lo; + } else if hx > 0x39000000 { + /* |x| > 2**-14 */ + k = 0; + hi = x; + lo = 0.; + } else { + /* raise inexact */ + force_eval!(x1p127 + x); + return 1. + x; + } + + /* x is now in primary range */ + let xx = x * x; + let c = x - xx * (P1 + xx * P2); + let y = 1. + (x * c / (2. - c) - lo + hi); + if k == 0 { y } else { scalbnf(y, k) } +} diff --git a/library/compiler-builtins/libm/libm/src/math/expm1.rs b/library/compiler-builtins/libm/libm/src/math/expm1.rs new file mode 100644 index 00000000000..f25153f32a3 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/expm1.rs @@ -0,0 +1,144 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f64; + +const O_THRESHOLD: f64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ +const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ +/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ +const Q1: f64 = -3.33333333333331316428e-02; /* BFA11111 111110F4 */ +const Q2: f64 = 1.58730158725481460165e-03; /* 3F5A01A0 19FE5585 */ +const Q3: f64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ +const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ +const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ + +/// Exponential, base *e*, of x-1 (f64) +/// +/// Calculates the exponential of `x` and subtract 1, that is, *e* raised +/// to the power `x` minus 1 (where *e* is the base of the natural +/// system of logarithms, approximately 2.71828). +/// The result is accurate even for small values of `x`, +/// where using `exp(x)-1` would lose many significant digits. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn expm1(mut x: f64) -> f64 { + let hi: f64; + let lo: f64; + let k: i32; + let c: f64; + let mut t: f64; + let mut y: f64; + + let mut ui = x.to_bits(); + let hx = ((ui >> 32) & 0x7fffffff) as u32; + let sign = (ui >> 63) as i32; + + /* filter out huge and non-finite argument */ + if hx >= 0x4043687A { + /* if |x|>=56*ln2 */ + if x.is_nan() { + return x; + } + if sign != 0 { + return -1.0; + } + if x > O_THRESHOLD { + x *= f64::from_bits(0x7fe0000000000000); + return x; + } + } + + /* argument reduction */ + if hx > 0x3fd62e42 { + /* if |x| > 0.5 ln2 */ + if hx < 0x3FF0A2B2 { + /* and |x| < 1.5 ln2 */ + if sign == 0 { + hi = x - LN2_HI; + lo = LN2_LO; + k = 1; + } else { + hi = x + LN2_HI; + lo = -LN2_LO; + k = -1; + } + } else { + k = (INVLN2 * x + if sign != 0 { -0.5 } else { 0.5 }) as i32; + t = k as f64; + hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ + lo = t * LN2_LO; + } + x = hi - lo; + c = (hi - x) - lo; + } else if hx < 0x3c900000 { + /* |x| < 2**-54, return x */ + if hx < 0x00100000 { + force_eval!(x); + } + return x; + } else { + c = 0.0; + k = 0; + } + + /* x is now in primary range */ + let hfx = 0.5 * x; + let hxs = x * hfx; + let r1 = 1.0 + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5)))); + t = 3.0 - r1 * hfx; + let mut e = hxs * ((r1 - t) / (6.0 - x * t)); + if k == 0 { + /* c is 0 */ + return x - (x * e - hxs); + } + e = x * (e - c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if k == -1 { + return 0.5 * (x - e) - 0.5; + } + if k == 1 { + if x < -0.25 { + return -2.0 * (e - (x + 0.5)); + } + return 1.0 + 2.0 * (x - e); + } + ui = ((0x3ff + k) as u64) << 52; /* 2^k */ + let twopk = f64::from_bits(ui); + if !(0..=56).contains(&k) { + /* suffice to return exp(x)-1 */ + y = x - e + 1.0; + if k == 1024 { + y = y * 2.0 * f64::from_bits(0x7fe0000000000000); + } else { + y = y * twopk; + } + return y - 1.0; + } + ui = ((0x3ff - k) as u64) << 52; /* 2^-k */ + let uf = f64::from_bits(ui); + if k < 20 { + y = (x - e + (1.0 - uf)) * twopk; + } else { + y = (x - (e + uf) + 1.0) * twopk; + } + y +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::expm1(1.1), 2.0041660239464334); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/libm/src/math/expm1f.rs new file mode 100644 index 00000000000..12c6f532b96 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/expm1f.rs @@ -0,0 +1,130 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +const O_THRESHOLD: f32 = 8.8721679688e+01; /* 0x42b17180 */ +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: + * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 + * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): + */ +const Q1: f32 = -3.3333212137e-2; /* -0x888868.0p-28 */ +const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ + +/// Exponential, base *e*, of x-1 (f32) +/// +/// Calculates the exponential of `x` and subtract 1, that is, *e* raised +/// to the power `x` minus 1 (where *e* is the base of the natural +/// system of logarithms, approximately 2.71828). +/// The result is accurate even for small values of `x`, +/// where using `exp(x)-1` would lose many significant digits. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn expm1f(mut x: f32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + + let mut hx = x.to_bits(); + let sign = (hx >> 31) != 0; + hx &= 0x7fffffff; + + /* filter out huge and non-finite argument */ + if hx >= 0x4195b844 { + /* if |x|>=27*ln2 */ + if hx > 0x7f800000 { + /* NaN */ + return x; + } + if sign { + return -1.; + } + if x > O_THRESHOLD { + x *= x1p127; + return x; + } + } + + let k: i32; + let hi: f32; + let lo: f32; + let mut c = 0f32; + /* argument reduction */ + if hx > 0x3eb17218 { + /* if |x| > 0.5 ln2 */ + if hx < 0x3F851592 { + /* and |x| < 1.5 ln2 */ + if !sign { + hi = x - LN2_HI; + lo = LN2_LO; + k = 1; + } else { + hi = x + LN2_HI; + lo = -LN2_LO; + k = -1; + } + } else { + k = (INV_LN2 * x + (if sign { -0.5 } else { 0.5 })) as i32; + let t = k as f32; + hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ + lo = t * LN2_LO; + } + x = hi - lo; + c = (hi - x) - lo; + } else if hx < 0x33000000 { + /* when |x|<2**-25, return x */ + if hx < 0x00800000 { + force_eval!(x * x); + } + return x; + } else { + k = 0; + } + + /* x is now in primary range */ + let hfx = 0.5 * x; + let hxs = x * hfx; + let r1 = 1. + hxs * (Q1 + hxs * Q2); + let t = 3. - r1 * hfx; + let mut e = hxs * ((r1 - t) / (6. - x * t)); + if k == 0 { + /* c is 0 */ + return x - (x * e - hxs); + } + e = x * (e - c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if k == -1 { + return 0.5 * (x - e) - 0.5; + } + if k == 1 { + if x < -0.25 { + return -2. * (e - (x + 0.5)); + } + return 1. + 2. * (x - e); + } + let twopk = f32::from_bits(((0x7f + k) << 23) as u32); /* 2^k */ + if !(0..=56).contains(&k) { + /* suffice to return exp(x)-1 */ + let mut y = x - e + 1.; + if k == 128 { + y = y * 2. * x1p127; + } else { + y = y * twopk; + } + return y - 1.; + } + let uf = f32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */ + if k < 23 { (x - e + (1. - uf)) * twopk } else { (x - (e + uf) + 1.) * twopk } +} diff --git a/library/compiler-builtins/libm/libm/src/math/expo2.rs b/library/compiler-builtins/libm/libm/src/math/expo2.rs new file mode 100644 index 00000000000..82e9b360a76 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/expo2.rs @@ -0,0 +1,14 @@ +use super::{combine_words, exp}; + +/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn expo2(x: f64) -> f64 { + /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ + const K: i32 = 2043; + let kln2 = f64::from_bits(0x40962066151add8b); + + /* note that k is odd and scale*scale overflows */ + let scale = combine_words(((0x3ff + K / 2) as u32) << 20, 0); + /* exp(x - k ln2) * 2**(k-1) */ + exp(x - kln2) * scale * scale +} diff --git a/library/compiler-builtins/libm/libm/src/math/fabs.rs b/library/compiler-builtins/libm/libm/src/math/fabs.rs new file mode 100644 index 00000000000..0050a309fee --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fabs.rs @@ -0,0 +1,116 @@ +/// Absolute value (magnitude) (f16) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf16(x: f16) -> f16 { + super::generic::fabs(x) +} + +/// Absolute value (magnitude) (f32) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf(x: f32) -> f32 { + select_implementation! { + name: fabsf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::fabs(x) +} + +/// Absolute value (magnitude) (f64) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabs(x: f64) -> f64 { + select_implementation! { + name: fabs, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::fabs(x) +} + +/// Absolute value (magnitude) (f128) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf128(x: f128) -> f128 { + super::generic::fabs(x) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::Float; + + /// Based on https://en.cppreference.com/w/cpp/numeric/math/fabs + fn spec_test(f: impl Fn(F) -> F) { + assert_biteq!(f(F::ZERO), F::ZERO); + assert_biteq!(f(F::NEG_ZERO), F::ZERO); + assert_biteq!(f(F::INFINITY), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY), F::INFINITY); + assert!(f(F::NAN).is_nan()); + + // Not spec rewquired but we expect it + assert!(f(F::NAN).is_sign_positive()); + assert!(f(F::from_bits(F::NAN.to_bits() | F::SIGN_MASK)).is_sign_positive()); + } + + #[test] + #[cfg(f16_enabled)] + fn sanity_check_f16() { + assert_eq!(fabsf16(-1.0f16), 1.0); + assert_eq!(fabsf16(2.8f16), 2.8); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(fabsf16); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(fabsf(-1.0f32), 1.0); + assert_eq!(fabsf(2.8f32), 2.8); + } + + #[test] + fn spec_tests_f32() { + spec_test::(fabsf); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(fabs(-1.0f64), 1.0); + assert_eq!(fabs(2.8f64), 2.8); + } + + #[test] + fn spec_tests_f64() { + spec_test::(fabs); + } + + #[test] + #[cfg(f128_enabled)] + fn sanity_check_f128() { + assert_eq!(fabsf128(-1.0f128), 1.0); + assert_eq!(fabsf128(2.8f128), 2.8); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(fabsf128); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/libm/src/math/fabsf.rs new file mode 100644 index 00000000000..e5820a26c52 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fabsf.rs @@ -0,0 +1,39 @@ +/// Absolute value (magnitude) (f32) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf(x: f32) -> f32 { + select_implementation! { + name: fabsf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::fabs(x) +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf(-1.0), 1.0); + assert_eq!(fabsf(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf(f32::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf(f), 0.0); + } + for f in [f32::INFINITY, f32::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf(f), f32::INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/fabsf128.rs b/library/compiler-builtins/libm/libm/src/math/fabsf128.rs new file mode 100644 index 00000000000..46429ca4940 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fabsf128.rs @@ -0,0 +1,31 @@ +/// Absolute value (magnitude) (f128) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf128(x: f128) -> f128 { + super::generic::fabs(x) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf128(-1.0), 1.0); + assert_eq!(fabsf128(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf128(f128::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf128(f), 0.0); + } + for f in [f128::INFINITY, f128::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf128(f), f128::INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/fabsf16.rs b/library/compiler-builtins/libm/libm/src/math/fabsf16.rs new file mode 100644 index 00000000000..eee42ac6a3c --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fabsf16.rs @@ -0,0 +1,31 @@ +/// Absolute value (magnitude) (f16) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf16(x: f16) -> f16 { + super::generic::fabs(x) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf16(-1.0), 1.0); + assert_eq!(fabsf16(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf16(f16::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf16(f), 0.0); + } + for f in [f16::INFINITY, f16::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf16(f), f16::INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/fdim.rs b/library/compiler-builtins/libm/libm/src/math/fdim.rs new file mode 100644 index 00000000000..082c5478b2a --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fdim.rs @@ -0,0 +1,53 @@ +/// Positive difference (f16) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf16(x: f16, y: f16) -> f16 { + super::generic::fdim(x, y) +} + +/// Positive difference (f32) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf(x: f32, y: f32) -> f32 { + super::generic::fdim(x, y) +} + +/// Positive difference (f64) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdim(x: f64, y: f64) -> f64 { + super::generic::fdim(x, y) +} + +/// Positive difference (f128) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf128(x: f128, y: f128) -> f128 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/libm/src/math/fdimf.rs new file mode 100644 index 00000000000..367ef517c63 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fdimf.rs @@ -0,0 +1,12 @@ +/// Positive difference (f32) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf(x: f32, y: f32) -> f32 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/fdimf128.rs b/library/compiler-builtins/libm/libm/src/math/fdimf128.rs new file mode 100644 index 00000000000..6f3d1d0ff1d --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fdimf128.rs @@ -0,0 +1,12 @@ +/// Positive difference (f128) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf128(x: f128, y: f128) -> f128 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/fdimf16.rs b/library/compiler-builtins/libm/libm/src/math/fdimf16.rs new file mode 100644 index 00000000000..37bd6885817 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fdimf16.rs @@ -0,0 +1,12 @@ +/// Positive difference (f16) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf16(x: f16, y: f16) -> f16 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/floor.rs b/library/compiler-builtins/libm/libm/src/math/floor.rs new file mode 100644 index 00000000000..3c5eab101d1 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/floor.rs @@ -0,0 +1,46 @@ +/// Floor (f16) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf16(x: f16) -> f16 { + return super::generic::floor(x); +} + +/// Floor (f64) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floor(x: f64) -> f64 { + select_implementation! { + name: floor, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), + args: x, + } + + return super::generic::floor(x); +} + +/// Floor (f32) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf(x: f32) -> f32 { + select_implementation! { + name: floorf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + return super::generic::floor(x); +} + +/// Floor (f128) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf128(x: f128) -> f128 { + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/libm/src/math/floorf.rs b/library/compiler-builtins/libm/libm/src/math/floorf.rs new file mode 100644 index 00000000000..16957b7f355 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/floorf.rs @@ -0,0 +1,13 @@ +/// Floor (f32) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf(x: f32) -> f32 { + select_implementation! { + name: floorf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/libm/src/math/floorf128.rs b/library/compiler-builtins/libm/libm/src/math/floorf128.rs new file mode 100644 index 00000000000..9a9fe415115 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/floorf128.rs @@ -0,0 +1,7 @@ +/// Floor (f128) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf128(x: f128) -> f128 { + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/libm/src/math/floorf16.rs b/library/compiler-builtins/libm/libm/src/math/floorf16.rs new file mode 100644 index 00000000000..f9b868e0410 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/floorf16.rs @@ -0,0 +1,7 @@ +/// Floor (f16) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf16(x: f16) -> f16 { + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/libm/src/math/fma.rs b/library/compiler-builtins/libm/libm/src/math/fma.rs new file mode 100644 index 00000000000..e0b3347acf8 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fma.rs @@ -0,0 +1,397 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ + +use super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; +use super::{CastFrom, CastInto, Float, Int, MinInt}; + +/// Fused multiply add (f64) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fma(x: f64, y: f64, z: f64) -> f64 { + select_implementation! { + name: fma, + use_arch: all(target_arch = "aarch64", target_feature = "neon"), + args: x, y, z, + } + + fma_round(x, y, z, Round::Nearest).val +} + +/// Fused multiply add (f128) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { + fma_round(x, y, z, Round::Nearest).val +} + +/// Fused multiply-add that works when there is not a larger float size available. Computes +/// `(x * y) + z`. +#[inline] +pub fn fma_round(x: F, y: F, z: F, _round: Round) -> FpResult +where + F: Float, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, +{ + let one = IntTy::::ONE; + let zero = IntTy::::ZERO; + + // Normalize such that the top of the mantissa is zero and we have a guard bit. + let nx = Norm::from_float(x); + let ny = Norm::from_float(y); + let nz = Norm::from_float(z); + + if nx.is_zero_nan_inf() || ny.is_zero_nan_inf() { + // Value will overflow, defer to non-fused operations. + return FpResult::ok(x * y + z); + } + + if nz.is_zero_nan_inf() { + if nz.is_zero() { + // Empty add component means we only need to multiply. + return FpResult::ok(x * y); + } + // `z` is NaN or infinity, which sets the result. + return FpResult::ok(z); + } + + // multiply: r = x * y + let zhi: F::Int; + let zlo: F::Int; + let (mut rlo, mut rhi) = nx.m.widen_mul(ny.m).lo_hi(); + + // Exponent result of multiplication + let mut e: i32 = nx.e + ny.e; + // Needed shift to align `z` to the multiplication result + let mut d: i32 = nz.e - e; + let sbits = F::BITS as i32; + + // Scale `z`. Shift `z <<= kz`, `r >>= kr`, so `kz+kr == d`, set `e = e+kr` (== ez-kz) + if d > 0 { + // The magnitude of `z` is larger than `x * y` + if d < sbits { + // Maximum shift of one `F::BITS` means shifted `z` will fit into `2 * F::BITS`. Shift + // it into `(zhi, zlo)`. No exponent adjustment necessary. + zlo = nz.m << d; + zhi = nz.m >> (sbits - d); + } else { + // Shift larger than `sbits`, `z` only needs the top half `zhi`. Place it there (acts + // as a shift by `sbits`). + zlo = zero; + zhi = nz.m; + d -= sbits; + + // `z`'s exponent is large enough that it now needs to be taken into account. + e = nz.e - sbits; + + if d == 0 { + // Exactly `sbits`, nothing to do + } else if d < sbits { + // Remaining shift fits within `sbits`. Leave `z` in place, shift `x * y` + rlo = (rhi << (sbits - d)) | (rlo >> d); + // Set the sticky bit + rlo |= IntTy::::from((rlo << (sbits - d)) != zero); + rhi = rhi >> d; + } else { + // `z`'s magnitude is enough that `x * y` is irrelevant. It was nonzero, so set + // the sticky bit. + rlo = one; + rhi = zero; + } + } + } else { + // `z`'s magnitude once shifted fits entirely within `zlo` + zhi = zero; + d = -d; + if d == 0 { + // No shift needed + zlo = nz.m; + } else if d < sbits { + // Shift s.t. `nz.m` fits into `zlo` + let sticky = IntTy::::from((nz.m << (sbits - d)) != zero); + zlo = (nz.m >> d) | sticky; + } else { + // Would be entirely shifted out, only set the sticky bit + zlo = one; + } + } + + /* addition */ + + let mut neg = nx.neg ^ ny.neg; + let samesign: bool = !neg ^ nz.neg; + let mut rhi_nonzero = true; + + if samesign { + // r += z + rlo = rlo.wrapping_add(zlo); + rhi += zhi + IntTy::::from(rlo < zlo); + } else { + // r -= z + let (res, borrow) = rlo.overflowing_sub(zlo); + rlo = res; + rhi = rhi.wrapping_sub(zhi.wrapping_add(IntTy::::from(borrow))); + if (rhi >> (F::BITS - 1)) != zero { + rlo = rlo.signed().wrapping_neg().unsigned(); + rhi = rhi.signed().wrapping_neg().unsigned() - IntTy::::from(rlo != zero); + neg = !neg; + } + rhi_nonzero = rhi != zero; + } + + /* Construct result */ + + // Shift result into `rhi`, left-aligned. Last bit is sticky + if rhi_nonzero { + // `d` > 0, need to shift both `rhi` and `rlo` into result + e += sbits; + d = rhi.leading_zeros() as i32 - 1; + rhi = (rhi << d) | (rlo >> (sbits - d)); + // Update sticky + rhi |= IntTy::::from((rlo << d) != zero); + } else if rlo != zero { + // `rhi` is zero, `rlo` is the entire result and needs to be shifted + d = rlo.leading_zeros() as i32 - 1; + if d < 0 { + // Shift and set sticky + rhi = (rlo >> 1) | (rlo & one); + } else { + rhi = rlo << d; + } + } else { + // exact +/- 0.0 + return FpResult::ok(x * y + z); + } + + e -= d; + + // Use int->float conversion to populate the significand. + // i is in [1 << (BITS - 2), (1 << (BITS - 1)) - 1] + let mut i: F::SignedInt = rhi.signed(); + + if neg { + i = -i; + } + + // `|r|` is in `[0x1p62,0x1p63]` for `f64` + let mut r: F = F::cast_from_lossy(i); + + /* Account for subnormal and rounding */ + + // Unbiased exponent for the maximum value of `r` + let max_pow = F::BITS - 1 + F::EXP_BIAS; + + let mut status = Status::OK; + + if e < -(max_pow as i32 - 2) { + // Result is subnormal before rounding + if e == -(max_pow as i32 - 1) { + let mut c = F::from_parts(false, max_pow, zero); + if neg { + c = -c; + } + + if r == c { + // Min normal after rounding, + status.set_underflow(true); + r = F::MIN_POSITIVE_NORMAL.copysign(r); + return FpResult::new(r, status); + } + + if (rhi << (F::SIG_BITS + 1)) != zero { + // Account for truncated bits. One bit will be lost in the `scalbn` call, add + // another top bit to avoid double rounding if inexact. + let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << (F::BITS - 2)); + i = iu.signed(); + + if neg { + i = -i; + } + + r = F::cast_from_lossy(i); + + // Remove the top bit + r = F::cast_from(2i8) * r - c; + status.set_underflow(true); + } + } else { + // Only round once when scaled + d = F::EXP_BITS as i32 - 1; + let sticky = IntTy::::from(rhi << (F::BITS as i32 - d) != zero); + i = (((rhi >> d) | sticky) << d).signed(); + + if neg { + i = -i; + } + + r = F::cast_from_lossy(i); + } + } + + // Use our exponent to scale the final value. + FpResult::new(super::generic::scalbn(r, e), status) +} + +/// Representation of `F` that has handled subnormals. +#[derive(Clone, Copy, Debug)] +struct Norm { + /// Normalized significand with one guard bit, unsigned. + m: F::Int, + /// Exponent of the mantissa such that `m * 2^e = x`. Accounts for the shift in the mantissa + /// and the guard bit; that is, 1.0 will normalize as `m = 1 << 53` and `e = -53`. + e: i32, + neg: bool, +} + +impl Norm { + /// Unbias the exponent and account for the mantissa's precision, including the guard bit. + const EXP_UNBIAS: u32 = F::EXP_BIAS + F::SIG_BITS + 1; + + /// Values greater than this had a saturated exponent (infinity or NaN), OR were zero and we + /// adjusted the exponent such that it exceeds this threashold. + const ZERO_INF_NAN: u32 = F::EXP_SAT - Self::EXP_UNBIAS; + + fn from_float(x: F) -> Self { + let mut ix = x.to_bits(); + let mut e = x.ex() as i32; + let neg = x.is_sign_negative(); + if e == 0 { + // Normalize subnormals by multiplication + let scale_i = F::BITS - 1; + let scale_f = F::from_parts(false, scale_i + F::EXP_BIAS, F::Int::ZERO); + let scaled = x * scale_f; + ix = scaled.to_bits(); + e = scaled.ex() as i32; + e = if e == 0 { + // If the exponent is still zero, the input was zero. Artifically set this value + // such that the final `e` will exceed `ZERO_INF_NAN`. + 1 << F::EXP_BITS + } else { + // Otherwise, account for the scaling we just did. + e - scale_i as i32 + }; + } + + e -= Self::EXP_UNBIAS as i32; + + // Absolute value, set the implicit bit, and shift to create a guard bit + ix &= F::SIG_MASK; + ix |= F::IMPLICIT_BIT; + ix <<= 1; + + Self { m: ix, e, neg } + } + + /// True if the value was zero, infinity, or NaN. + fn is_zero_nan_inf(self) -> bool { + self.e >= Self::ZERO_INF_NAN as i32 + } + + /// The only value we have + fn is_zero(self) -> bool { + // The only exponent that strictly exceeds this value is our sentinel value for zero. + self.e > Self::ZERO_INF_NAN as i32 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Test the generic `fma_round` algorithm for a given float. + fn spec_test() + where + F: Float, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, + { + let x = F::from_bits(F::Int::ONE); + let y = F::from_bits(F::Int::ONE); + let z = F::ZERO; + + let fma = |x, y, z| fma_round(x, y, z, Round::Nearest).val; + + // 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of + // fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the + // exact result" + assert_biteq!(fma(x, y, z), F::ZERO); + assert_biteq!(fma(x, -y, z), F::NEG_ZERO); + assert_biteq!(fma(-x, y, z), F::NEG_ZERO); + assert_biteq!(fma(-x, -y, z), F::ZERO); + } + + #[test] + fn spec_test_f32() { + spec_test::(); + } + + #[test] + fn spec_test_f64() { + spec_test::(); + + let expect_underflow = [ + ( + hf64!("0x1.0p-1070"), + hf64!("0x1.0p-1070"), + hf64!("0x1.ffffffffffffp-1023"), + hf64!("0x0.ffffffffffff8p-1022"), + ), + ( + // FIXME: we raise underflow but this should only be inexact (based on C and + // `rustc_apfloat`). + hf64!("0x1.0p-1070"), + hf64!("0x1.0p-1070"), + hf64!("-0x1.0p-1022"), + hf64!("-0x1.0p-1022"), + ), + ]; + + for (x, y, z, res) in expect_underflow { + let FpResult { val, status } = fma_round(x, y, z, Round::Nearest); + assert_biteq!(val, res); + assert_eq!(status, Status::UNDERFLOW); + } + } + + #[test] + #[cfg(f128_enabled)] + fn spec_test_f128() { + spec_test::(); + } + + #[test] + fn fma_segfault() { + // These two inputs cause fma to segfault on release due to overflow: + assert_eq!( + fma( + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313 + ), + -0.00000000000000022204460492503126, + ); + + let result = fma(-0.992, -0.992, -0.992); + //force rounding to storage format on x87 to prevent superious errors. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let result = force_eval!(result); + assert_eq!(result, -0.007936000000000007,); + } + + #[test] + fn fma_sbb() { + assert_eq!(fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), -3991680619069439e277); + } + + #[test] + fn fma_underflow() { + assert_eq!(fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), 0.0,); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/libm/src/math/fma_wide.rs new file mode 100644 index 00000000000..08b78b02264 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fma_wide.rs @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fmaf.c. Ported to generic Rust algorithm in 2025, TG. */ + +use super::support::{FpResult, IntTy, Round, Status}; +use super::{CastFrom, CastInto, DFloat, Float, HFloat, MinInt}; + +// Placeholder so we can have `fmaf16` in the `Float` trait. +#[allow(unused)] +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 { + unimplemented!() +} + +/// Floating multiply add (f32) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { + select_implementation! { + name: fmaf, + use_arch: all(target_arch = "aarch64", target_feature = "neon"), + args: x, y, z, + } + + fma_wide_round(x, y, z, Round::Nearest).val +} + +/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, +/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. +#[inline] +pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult +where + F: Float + HFloat, + B: Float + DFloat, + B::Int: CastInto, + i32: CastFrom, +{ + let one = IntTy::::ONE; + + let xy: B = x.widen() * y.widen(); + let mut result: B = xy + z.widen(); + let mut ui: B::Int = result.to_bits(); + let re = result.ex(); + let zb: B = z.widen(); + + let prec_diff = B::SIG_BITS - F::SIG_BITS; + let excess_prec = ui & ((one << prec_diff) - one); + let halfway = one << (prec_diff - 1); + + // Common case: the larger precision is fine if... + // This is not a halfway case + if excess_prec != halfway + // Or the result is NaN + || re == B::EXP_SAT + // Or the result is exact + || (result - xy == zb && result - zb == xy) + // Or the mode is something other than round to nearest + || round != Round::Nearest + { + let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; + let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; + + let mut status = Status::OK; + + if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() { + // This branch is never hit; requires previous operations to set a status + status.set_inexact(false); + + result = xy + z.widen(); + if status.inexact() { + status.set_underflow(true); + } else { + status.set_inexact(true); + } + } + + return FpResult { val: result.narrow(), status }; + } + + let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; + let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy }; + if neg == (err < B::ZERO) { + ui += one; + } else { + ui -= one; + } + + FpResult::ok(B::from_bits(ui).narrow()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn issue_263() { + let a = f32::from_bits(1266679807); + let b = f32::from_bits(1300234242); + let c = f32::from_bits(1115553792); + let expected = f32::from_bits(1501560833); + assert_eq!(fmaf(a, b, c), expected); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/libm/src/math/fmin_fmax.rs new file mode 100644 index 00000000000..2947b783e2f --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fmin_fmax.rs @@ -0,0 +1,167 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf16(x: f16, y: f16) -> f16 { + super::generic::fmin(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf(x: f32, y: f32) -> f32 { + super::generic::fmin(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmin(x: f64, y: f64) -> f64 { + super::generic::fmin(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf128(x: f128, y: f128) -> f128 { + super::generic::fmin(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf16(x: f16, y: f16) -> f16 { + super::generic::fmax(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf(x: f32, y: f32) -> f32 { + super::generic::fmax(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmax(x: f64, y: f64) -> f64 { + super::generic::fmax(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf128(x: f128, y: f128) -> f128 { + super::generic::fmax(x, y) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, Hexf}; + + fn fmin_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmin_spec_tests_f16() { + fmin_spec_test::(fminf16); + } + + #[test] + fn fmin_spec_tests_f32() { + fmin_spec_test::(fminf); + } + + #[test] + fn fmin_spec_tests_f64() { + fmin_spec_test::(fmin); + } + + #[test] + #[cfg(f128_enabled)] + fn fmin_spec_tests_f128() { + fmin_spec_test::(fminf128); + } + + fn fmax_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmax_spec_tests_f16() { + fmax_spec_test::(fmaxf16); + } + + #[test] + fn fmax_spec_tests_f32() { + fmax_spec_test::(fmaxf); + } + + #[test] + fn fmax_spec_tests_f64() { + fmax_spec_test::(fmax); + } + + #[test] + #[cfg(f128_enabled)] + fn fmax_spec_tests_f128() { + fmax_spec_test::(fmaxf128); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum.rs b/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum.rs new file mode 100644 index 00000000000..b7999e27392 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum.rs @@ -0,0 +1,163 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimumf16(x: f16, y: f16) -> f16 { + super::generic::fminimum(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum(x: f64, y: f64) -> f64 { + super::generic::fminimum(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimumf(x: f32, y: f32) -> f32 { + super::generic::fminimum(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimumf128(x: f128, y: f128) -> f128 { + super::generic::fminimum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximumf16(x: f16, y: f16) -> f16 { + super::generic::fmaximum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximumf(x: f32, y: f32) -> f32 { + super::generic::fmaximum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum(x: f64, y: f64) -> f64 { + super::generic::fmaximum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximumf128(x: f128, y: f128) -> f128 { + super::generic::fmaximum(x, y) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, Hexf}; + + fn fminimum_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::NAN), + (F::ZERO, F::NAN, F::NAN), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fminimum_spec_tests_f16() { + fminimum_spec_test::(fminimumf16); + } + + #[test] + fn fminimum_spec_tests_f32() { + fminimum_spec_test::(fminimumf); + } + + #[test] + fn fminimum_spec_tests_f64() { + fminimum_spec_test::(fminimum); + } + + #[test] + #[cfg(f128_enabled)] + fn fminimum_spec_tests_f128() { + fminimum_spec_test::(fminimumf128); + } + + fn fmaximum_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::NAN), + (F::ZERO, F::NAN, F::NAN), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::ZERO), + (F::NEG_ZERO, F::ZERO, F::ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmaximum_spec_tests_f16() { + fmaximum_spec_test::(fmaximumf16); + } + + #[test] + fn fmaximum_spec_tests_f32() { + fmaximum_spec_test::(fmaximumf); + } + + #[test] + fn fmaximum_spec_tests_f64() { + fmaximum_spec_test::(fmaximum); + } + + #[test] + #[cfg(f128_enabled)] + fn fmaximum_spec_tests_f128() { + fmaximum_spec_test::(fmaximumf128); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum_num.rs b/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum_num.rs new file mode 100644 index 00000000000..180d21f72b7 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum_num.rs @@ -0,0 +1,163 @@ +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_numf16(x: f16, y: f16) -> f16 { + super::generic::fminimum_num(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_numf(x: f32, y: f32) -> f32 { + super::generic::fminimum_num(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_num(x: f64, y: f64) -> f64 { + super::generic::fminimum_num(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_numf128(x: f128, y: f128) -> f128 { + super::generic::fminimum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_numf16(x: f16, y: f16) -> f16 { + super::generic::fmaximum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_numf(x: f32, y: f32) -> f32 { + super::generic::fmaximum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_num(x: f64, y: f64) -> f64 { + super::generic::fmaximum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_numf128(x: f128, y: f128) -> f128 { + super::generic::fmaximum_num(x, y) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, Hexf}; + + fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fminimum_num_spec_tests_f16() { + fminimum_num_spec_test::(fminimum_numf16); + } + + #[test] + fn fminimum_num_spec_tests_f32() { + fminimum_num_spec_test::(fminimum_numf); + } + + #[test] + fn fminimum_num_spec_tests_f64() { + fminimum_num_spec_test::(fminimum_num); + } + + #[test] + #[cfg(f128_enabled)] + fn fminimum_num_spec_tests_f128() { + fminimum_num_spec_test::(fminimum_numf128); + } + + fn fmaximum_num_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::ZERO), + (F::NEG_ZERO, F::ZERO, F::ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmaximum_num_spec_tests_f16() { + fmaximum_num_spec_test::(fmaximum_numf16); + } + + #[test] + fn fmaximum_num_spec_tests_f32() { + fmaximum_num_spec_test::(fmaximum_numf); + } + + #[test] + fn fmaximum_num_spec_tests_f64() { + fmaximum_num_spec_test::(fmaximum_num); + } + + #[test] + #[cfg(f128_enabled)] + fn fmaximum_num_spec_tests_f128() { + fmaximum_num_spec_test::(fmaximum_numf128); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/fmod.rs b/library/compiler-builtins/libm/libm/src/math/fmod.rs new file mode 100644 index 00000000000..c4752b92578 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fmod.rs @@ -0,0 +1,25 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf16(x: f16, y: f16) -> f16 { + super::generic::fmod(x, y) +} + +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf(x: f32, y: f32) -> f32 { + super::generic::fmod(x, y) +} + +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmod(x: f64, y: f64) -> f64 { + super::generic::fmod(x, y) +} + +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf128(x: f128, y: f128) -> f128 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/libm/src/math/fmodf.rs new file mode 100644 index 00000000000..4e95696e20d --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fmodf.rs @@ -0,0 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf(x: f32, y: f32) -> f32 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/fmodf128.rs b/library/compiler-builtins/libm/libm/src/math/fmodf128.rs new file mode 100644 index 00000000000..ff0e0493e26 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fmodf128.rs @@ -0,0 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf128(x: f128, y: f128) -> f128 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/fmodf16.rs b/library/compiler-builtins/libm/libm/src/math/fmodf16.rs new file mode 100644 index 00000000000..11972a7de4f --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fmodf16.rs @@ -0,0 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf16(x: f16, y: f16) -> f16 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/frexp.rs b/library/compiler-builtins/libm/libm/src/math/frexp.rs new file mode 100644 index 00000000000..de7a64fdae1 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/frexp.rs @@ -0,0 +1,21 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn frexp(x: f64) -> (f64, i32) { + let mut y = x.to_bits(); + let ee = ((y >> 52) & 0x7ff) as i32; + + if ee == 0 { + if x != 0.0 { + let x1p64 = f64::from_bits(0x43f0000000000000); + let (x, e) = frexp(x * x1p64); + return (x, e - 64); + } + return (x, 0); + } else if ee == 0x7ff { + return (x, 0); + } + + let e = ee - 0x3fe; + y &= 0x800fffffffffffff; + y |= 0x3fe0000000000000; + return (f64::from_bits(y), e); +} diff --git a/library/compiler-builtins/libm/libm/src/math/frexpf.rs b/library/compiler-builtins/libm/libm/src/math/frexpf.rs new file mode 100644 index 00000000000..0ec91c2d350 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/frexpf.rs @@ -0,0 +1,22 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn frexpf(x: f32) -> (f32, i32) { + let mut y = x.to_bits(); + let ee: i32 = ((y >> 23) & 0xff) as i32; + + if ee == 0 { + if x != 0.0 { + let x1p64 = f32::from_bits(0x5f800000); + let (x, e) = frexpf(x * x1p64); + return (x, e - 64); + } else { + return (x, 0); + } + } else if ee == 0xff { + return (x, 0); + } + + let e = ee - 0x7e; + y &= 0x807fffff; + y |= 0x3f000000; + (f32::from_bits(y), e) +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/libm/src/math/generic/ceil.rs new file mode 100644 index 00000000000..5c5bb47638f --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/ceil.rs @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/ceilf.c */ + +//! Generic `ceil` algorithm. +//! +//! Note that this uses the algorithm from musl's `ceilf` rather than `ceil` or `ceill` because +//! performance seems to be better (based on icount) and it does not seem to experience rounding +//! errors on i386. + +use super::super::support::{FpResult, Status}; +use super::super::{Float, Int, IntTy, MinInt}; + +#[inline] +pub fn ceil(x: F) -> F { + ceil_status(x).val +} + +#[inline] +pub fn ceil_status(x: F) -> FpResult { + let zero = IntTy::::ZERO; + + let mut ix = x.to_bits(); + let e = x.exp_unbiased(); + + // If the represented value has no fractional part, no truncation is needed. + if e >= F::SIG_BITS as i32 { + return FpResult::ok(x); + } + + let status; + let res = if e >= 0 { + // |x| >= 1.0 + let m = F::SIG_MASK >> e.unsigned(); + if (ix & m) == zero { + // Portion to be masked is already zero; no adjustment needed. + return FpResult::ok(x); + } + + // Otherwise, raise an inexact exception. + status = Status::INEXACT; + + if x.is_sign_positive() { + ix += m; + } + + ix &= !m; + F::from_bits(ix) + } else { + // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). + if ix & F::SIG_MASK == F::Int::ZERO { + status = Status::OK; + } else { + status = Status::INEXACT; + } + + if x.is_sign_negative() { + // -1.0 < x <= -0.0; rounding up goes toward -0.0. + F::NEG_ZERO + } else if ix << 1 != zero { + // 0.0 < x < 1.0; rounding up goes toward +1.0. + F::ONE + } else { + // +0.0 remains unchanged + x + } + }; + + FpResult::new(res, status) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::Hexf; + + /// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil + fn spec_test(cases: &[(F, F, Status)]) { + let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + + for x in roundtrip { + let FpResult { val, status } = ceil_status(x); + assert_biteq!(val, x, "{}", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = ceil_status(x); + assert_biteq!(val, res, "{}", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); + } + } + + /* Skipping f16 / f128 "sanity_check"s due to rejected literal lexing at MSRV */ + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 2.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(ceil(1.1f32), 2.0); + assert_eq!(ceil(2.9f32), 3.0); + } + + #[test] + fn spec_tests_f32() { + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 2.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(ceil(1.1f64), 2.0); + assert_eq!(ceil(2.9f64), 3.0); + } + + #[test] + fn spec_tests_f64() { + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 2.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 2.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/copysign.rs b/library/compiler-builtins/libm/libm/src/math/generic/copysign.rs new file mode 100644 index 00000000000..a61af22f04a --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/copysign.rs @@ -0,0 +1,11 @@ +use super::super::Float; + +/// Copy the sign of `y` to `x`. +#[inline] +pub fn copysign(x: F, y: F) -> F { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= !F::SIGN_MASK; + ux |= uy & F::SIGN_MASK; + F::from_bits(ux) +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fabs.rs b/library/compiler-builtins/libm/libm/src/math/generic/fabs.rs new file mode 100644 index 00000000000..0fa0edf9b87 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/fabs.rs @@ -0,0 +1,8 @@ +use super::super::Float; + +/// Absolute value. +#[inline] +pub fn fabs(x: F) -> F { + let abs_mask = !F::SIGN_MASK; + F::from_bits(x.to_bits() & abs_mask) +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fdim.rs b/library/compiler-builtins/libm/libm/src/math/generic/fdim.rs new file mode 100644 index 00000000000..a63007b191c --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/fdim.rs @@ -0,0 +1,6 @@ +use super::super::Float; + +#[inline] +pub fn fdim(x: F, y: F) -> F { + if x <= y { F::ZERO } else { x - y } +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/libm/src/math/generic/floor.rs new file mode 100644 index 00000000000..2438046254f --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/floor.rs @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: MIT + * origin: musl src/math/floor.c */ + +//! Generic `floor` algorithm. +//! +//! Note that this uses the algorithm from musl's `floorf` rather than `floor` or `floorl` because +//! performance seems to be better (based on icount) and it does not seem to experience rounding +//! errors on i386. + +use super::super::support::{FpResult, Status}; +use super::super::{Float, Int, IntTy, MinInt}; + +#[inline] +pub fn floor(x: F) -> F { + floor_status(x).val +} + +#[inline] +pub fn floor_status(x: F) -> FpResult { + let zero = IntTy::::ZERO; + + let mut ix = x.to_bits(); + let e = x.exp_unbiased(); + + // If the represented value has no fractional part, no truncation is needed. + if e >= F::SIG_BITS as i32 { + return FpResult::ok(x); + } + + let status; + let res = if e >= 0 { + // |x| >= 1.0 + let m = F::SIG_MASK >> e.unsigned(); + if ix & m == zero { + // Portion to be masked is already zero; no adjustment needed. + return FpResult::ok(x); + } + + // Otherwise, raise an inexact exception. + status = Status::INEXACT; + + if x.is_sign_negative() { + ix += m; + } + + ix &= !m; + F::from_bits(ix) + } else { + // |x| < 1.0, raise an inexact exception since truncation will happen. + if ix & F::SIG_MASK == F::Int::ZERO { + status = Status::OK; + } else { + status = Status::INEXACT; + } + + if x.is_sign_positive() { + // 0.0 <= x < 1.0; rounding down goes toward +0.0. + F::ZERO + } else if ix << 1 != zero { + // -1.0 < x < 0.0; rounding down goes toward -1.0. + F::NEG_ONE + } else { + // -0.0 remains unchanged + x + } + }; + + FpResult::new(res, status) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::Hexf; + + /// Test against https://en.cppreference.com/w/cpp/numeric/math/floor + fn spec_test(cases: &[(F, F, Status)]) { + let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + + for x in roundtrip { + let FpResult { val, status } = floor_status(x); + assert_biteq!(val, x, "{}", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = floor_status(x); + assert_biteq!(val, res, "{}", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); + } + } + + /* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */ + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + let cases = []; + spec_test::(&cases); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(floor(0.5f32), 0.0); + assert_eq!(floor(1.1f32), 1.0); + assert_eq!(floor(2.9f32), 2.0); + } + + #[test] + fn spec_tests_f32() { + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -1.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -1.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -2.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -2.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(floor(1.1f64), 1.0); + assert_eq!(floor(2.9f64), 2.0); + } + + #[test] + fn spec_tests_f64() { + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -1.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -1.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -2.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -2.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + let cases = []; + spec_test::(&cases); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmax.rs new file mode 100644 index 00000000000..bf3f847e89b --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/fmax.rs @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2011 `maxNum`. This has been superseded by IEEE 754-2019 `maximumNumber`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x > y` +//! - `y` if `y > x` +//! - The other number if one is NaN +//! - Otherwise, either `x` or `y`, canonicalized +//! - -0.0 and +0.0 may be disregarded (unlike newer operations) +//! +//! Excluded from our implementation is sNaN handling. +//! +//! More on the differences: [link]. +//! +//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf + +use super::super::Float; + +#[inline] +pub fn fmax(x: F, y: F) -> F { + let res = if x.is_nan() || x < y { y } else { x }; + // Canonicalize + res * F::ONE +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmaximum.rs new file mode 100644 index 00000000000..387055af29c --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/fmaximum.rs @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `maximum`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x > y` +//! - `y` if `y > x` +//! - qNaN if either operation is NaN +//! - Logic following +0.0 > -0.0 +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +#[inline] +pub fn fmaximum(x: F, y: F) -> F { + let res = if x.is_nan() { + x + } else if y.is_nan() { + y + } else if x > y || (y.to_bits() == F::NEG_ZERO.to_bits() && x.is_sign_positive()) { + x + } else { + y + }; + + // Canonicalize + res * F::ONE +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmaximum_num.rs new file mode 100644 index 00000000000..f7efdde80ea --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/fmaximum_num.rs @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `maximumNumber`. +//! +//! Per the spec, returns: +//! - `x` if `x > y` +//! - `y` if `y > x` +//! - Non-NaN if one operand is NaN +//! - Logic following +0.0 > -0.0 +//! - Either `x` or `y` if `x == y` and the signs are the same +//! - qNaN if either operand is a NaN +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +#[inline] +pub fn fmaximum_num(x: F, y: F) -> F { + let res = + if x.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { + y + } else { + x + }; + + // Canonicalize + res * F::ONE +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmin.rs new file mode 100644 index 00000000000..cd3caeee4f2 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/fmin.rs @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2008 `minNum`. This has been superseded by IEEE 754-2019 `minimumNumber`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x < y` +//! - `y` if `y < x` +//! - The other number if one is NaN +//! - Otherwise, either `x` or `y`, canonicalized +//! - -0.0 and +0.0 may be disregarded (unlike newer operations) +//! +//! Excluded from our implementation is sNaN handling. +//! +//! More on the differences: [link]. +//! +//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf + +use super::super::Float; + +#[inline] +pub fn fmin(x: F, y: F) -> F { + let res = if y.is_nan() || x < y { x } else { y }; + // Canonicalize + res * F::ONE +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/libm/src/math/generic/fminimum.rs new file mode 100644 index 00000000000..4ddb3645506 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/fminimum.rs @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `minimum`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x < y` +//! - `y` if `y < x` +//! - qNaN if either operation is NaN +//! - Logic following +0.0 > -0.0 +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +#[inline] +pub fn fminimum(x: F, y: F) -> F { + let res = if x.is_nan() { + x + } else if y.is_nan() { + y + } else if x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { + x + } else { + y + }; + + // Canonicalize + res * F::ONE +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/libm/src/math/generic/fminimum_num.rs new file mode 100644 index 00000000000..441c204a921 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/fminimum_num.rs @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `minimum`. +//! +//! Per the spec, returns: +//! - `x` if `x < y` +//! - `y` if `y < x` +//! - Non-NaN if one operand is NaN +//! - Logic following +0.0 > -0.0 +//! - Either `x` or `y` if `x == y` and the signs are the same +//! - qNaN if either operand is a NaN +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +#[inline] +pub fn fminimum_num(x: F, y: F) -> F { + let res = + if y.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { + x + } else { + y + }; + + // Canonicalize + res * F::ONE +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmod.rs new file mode 100644 index 00000000000..6414bbd2508 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/fmod.rs @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fmod.c. Ported to generic Rust algorithm in 2025, TG. */ + +use super::super::{CastFrom, Float, Int, MinInt}; + +#[inline] +pub fn fmod(x: F, y: F) -> F { + let zero = F::Int::ZERO; + let one = F::Int::ONE; + let mut ix = x.to_bits(); + let mut iy = y.to_bits(); + let mut ex = x.ex().signed(); + let mut ey = y.ex().signed(); + let sx = ix & F::SIGN_MASK; + + if iy << 1 == zero || y.is_nan() || ex == F::EXP_SAT as i32 { + return (x * y) / (x * y); + } + + if ix << 1 <= iy << 1 { + if ix << 1 == iy << 1 { + return F::ZERO * x; + } + return x; + } + + /* normalize x and y */ + if ex == 0 { + let i = ix << (F::EXP_BITS + 1); + ex -= i.leading_zeros() as i32; + ix <<= -ex + 1; + } else { + ix &= F::Int::MAX >> F::EXP_BITS; + ix |= one << F::SIG_BITS; + } + + if ey == 0 { + let i = iy << (F::EXP_BITS + 1); + ey -= i.leading_zeros() as i32; + iy <<= -ey + 1; + } else { + iy &= F::Int::MAX >> F::EXP_BITS; + iy |= one << F::SIG_BITS; + } + + /* x mod y */ + while ex > ey { + let i = ix.wrapping_sub(iy); + if i >> (F::BITS - 1) == zero { + if i == zero { + return F::ZERO * x; + } + ix = i; + } + + ix <<= 1; + ex -= 1; + } + + let i = ix.wrapping_sub(iy); + if i >> (F::BITS - 1) == zero { + if i == zero { + return F::ZERO * x; + } + + ix = i; + } + + let shift = ix.leading_zeros().saturating_sub(F::EXP_BITS); + ix <<= shift; + ex -= shift as i32; + + /* scale result */ + if ex > 0 { + ix -= one << F::SIG_BITS; + ix |= F::Int::cast_from(ex) << F::SIG_BITS; + } else { + ix >>= -ex + 1; + } + + ix |= sx; + + F::from_bits(ix) +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/libm/src/math/generic/mod.rs new file mode 100644 index 00000000000..35846351a6e --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/mod.rs @@ -0,0 +1,38 @@ +// Note: generic functions are marked `#[inline]` because, even though generic functions are +// typically inlined, this does not seem to always be the case. + +mod ceil; +mod copysign; +mod fabs; +mod fdim; +mod floor; +mod fmax; +mod fmaximum; +mod fmaximum_num; +mod fmin; +mod fminimum; +mod fminimum_num; +mod fmod; +mod rint; +mod round; +mod scalbn; +mod sqrt; +mod trunc; + +pub use ceil::ceil; +pub use copysign::copysign; +pub use fabs::fabs; +pub use fdim::fdim; +pub use floor::floor; +pub use fmax::fmax; +pub use fmaximum::fmaximum; +pub use fmaximum_num::fmaximum_num; +pub use fmin::fmin; +pub use fminimum::fminimum; +pub use fminimum_num::fminimum_num; +pub use fmod::fmod; +pub use rint::rint_round; +pub use round::round; +pub use scalbn::scalbn; +pub use sqrt::sqrt; +pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/libm/src/math/generic/rint.rs new file mode 100644 index 00000000000..9cdeb1185a8 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/rint.rs @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/rint.c */ + +use super::super::Float; +use super::super::support::{FpResult, Round}; + +/// IEEE 754-2019 `roundToIntegralExact`, which respects rounding mode and raises inexact if +/// applicable. +#[inline] +pub fn rint_round(x: F, _round: Round) -> FpResult { + let toint = F::ONE / F::EPSILON; + let e = x.ex(); + let positive = x.is_sign_positive(); + + // On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise, + // the excess precission from x87 would cause an incorrect final result. + let force = |x| { + if cfg!(x86_no_sse) && (F::BITS == 32 || F::BITS == 64) { force_eval!(x) } else { x } + }; + + let res = if e >= F::EXP_BIAS + F::SIG_BITS { + // No fractional part; exact result can be returned. + x + } else { + // Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode. For + // Rust this is always nearest, but ideally it would take `round` into account. + let y = if positive { + force(force(x) + toint) - toint + } else { + force(force(x) - toint) + toint + }; + + if y == F::ZERO { + // A zero result takes the sign of the input. + if positive { F::ZERO } else { F::NEG_ZERO } + } else { + y + } + }; + + FpResult::ok(res) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Hexf, Status}; + + fn spec_test(cases: &[(F, F, Status)]) { + let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + + for x in roundtrip { + let FpResult { val, status } = rint_round(x, Round::Nearest); + assert_biteq!(val, x, "rint_round({})", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = rint_round(x, Round::Nearest); + assert_biteq!(val, res, "rint_round({})", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + let cases = []; + spec_test::(&cases); + } + + #[test] + fn spec_tests_f32() { + let cases = [ + (0.1, 0.0, Status::OK), + (-0.1, -0.0, Status::OK), + (0.5, 0.0, Status::OK), + (-0.5, -0.0, Status::OK), + (0.9, 1.0, Status::OK), + (-0.9, -1.0, Status::OK), + (1.1, 1.0, Status::OK), + (-1.1, -1.0, Status::OK), + (1.5, 2.0, Status::OK), + (-1.5, -2.0, Status::OK), + (1.9, 2.0, Status::OK), + (-1.9, -2.0, Status::OK), + (2.8, 3.0, Status::OK), + (-2.8, -3.0, Status::OK), + ]; + spec_test::(&cases); + } + + #[test] + fn spec_tests_f64() { + let cases = [ + (0.1, 0.0, Status::OK), + (-0.1, -0.0, Status::OK), + (0.5, 0.0, Status::OK), + (-0.5, -0.0, Status::OK), + (0.9, 1.0, Status::OK), + (-0.9, -1.0, Status::OK), + (1.1, 1.0, Status::OK), + (-1.1, -1.0, Status::OK), + (1.5, 2.0, Status::OK), + (-1.5, -2.0, Status::OK), + (1.9, 2.0, Status::OK), + (-1.9, -2.0, Status::OK), + (2.8, 3.0, Status::OK), + (-2.8, -3.0, Status::OK), + ]; + spec_test::(&cases); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + let cases = []; + spec_test::(&cases); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/round.rs b/library/compiler-builtins/libm/libm/src/math/generic/round.rs new file mode 100644 index 00000000000..01314ac70c2 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/round.rs @@ -0,0 +1,83 @@ +use super::super::{Float, MinInt}; +use super::{copysign, trunc}; + +#[inline] +pub fn round(x: F) -> F { + let f0p5 = F::from_parts(false, F::EXP_BIAS - 1, F::Int::ZERO); // 0.5 + let f0p25 = F::from_parts(false, F::EXP_BIAS - 2, F::Int::ZERO); // 0.25 + + trunc(x + copysign(f0p5 - f0p25 * F::EPSILON, x)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(f16_enabled)] + fn zeroes_f16() { + assert_biteq!(round(0.0_f16), 0.0_f16); + assert_biteq!(round(-0.0_f16), -0.0_f16); + } + + #[test] + #[cfg(f16_enabled)] + fn sanity_check_f16() { + assert_eq!(round(-1.0_f16), -1.0); + assert_eq!(round(2.8_f16), 3.0); + assert_eq!(round(-0.5_f16), -1.0); + assert_eq!(round(0.5_f16), 1.0); + assert_eq!(round(-1.5_f16), -2.0); + assert_eq!(round(1.5_f16), 2.0); + } + + #[test] + fn zeroes_f32() { + assert_biteq!(round(0.0_f32), 0.0_f32); + assert_biteq!(round(-0.0_f32), -0.0_f32); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(round(-1.0_f32), -1.0); + assert_eq!(round(2.8_f32), 3.0); + assert_eq!(round(-0.5_f32), -1.0); + assert_eq!(round(0.5_f32), 1.0); + assert_eq!(round(-1.5_f32), -2.0); + assert_eq!(round(1.5_f32), 2.0); + } + + #[test] + fn zeroes_f64() { + assert_biteq!(round(0.0_f64), 0.0_f64); + assert_biteq!(round(-0.0_f64), -0.0_f64); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(round(-1.0_f64), -1.0); + assert_eq!(round(2.8_f64), 3.0); + assert_eq!(round(-0.5_f64), -1.0); + assert_eq!(round(0.5_f64), 1.0); + assert_eq!(round(-1.5_f64), -2.0); + assert_eq!(round(1.5_f64), 2.0); + } + + #[test] + #[cfg(f128_enabled)] + fn zeroes_f128() { + assert_biteq!(round(0.0_f128), 0.0_f128); + assert_biteq!(round(-0.0_f128), -0.0_f128); + } + + #[test] + #[cfg(f128_enabled)] + fn sanity_check_f128() { + assert_eq!(round(-1.0_f128), -1.0); + assert_eq!(round(2.8_f128), 3.0); + assert_eq!(round(-0.5_f128), -1.0); + assert_eq!(round(0.5_f128), 1.0); + assert_eq!(round(-1.5_f128), -2.0); + assert_eq!(round(1.5_f128), 2.0); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/libm/src/math/generic/scalbn.rs new file mode 100644 index 00000000000..a45db1b4a02 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/scalbn.rs @@ -0,0 +1,121 @@ +use super::super::{CastFrom, CastInto, Float, IntTy, MinInt}; + +/// Scale the exponent. +/// +/// From N3220: +/// +/// > The scalbn and scalbln functions compute `x * b^n`, where `b = FLT_RADIX` if the return type +/// > of the function is a standard floating type, or `b = 10` if the return type of the function +/// > is a decimal floating type. A range error occurs for some finite x, depending on n. +/// > +/// > [...] +/// > +/// > * `scalbn(±0, n)` returns `±0`. +/// > * `scalbn(x, 0)` returns `x`. +/// > * `scalbn(±∞, n)` returns `±∞`. +/// > +/// > If the calculation does not overflow or underflow, the returned value is exact and +/// > independent of the current rounding direction mode. +#[inline] +pub fn scalbn(mut x: F, mut n: i32) -> F +where + u32: CastInto, + F::Int: CastFrom, + F::Int: CastFrom, +{ + let zero = IntTy::::ZERO; + + // Bits including the implicit bit + let sig_total_bits = F::SIG_BITS + 1; + + // Maximum and minimum values when biased + let exp_max = F::EXP_MAX; + let exp_min = F::EXP_MIN; + + // 2 ^ Emax, maximum positive with null significand (0x1p1023 for f64) + let f_exp_max = F::from_parts(false, F::EXP_BIAS << 1, zero); + + // 2 ^ Emin, minimum positive normal with null significand (0x1p-1022 for f64) + let f_exp_min = F::from_parts(false, 1, zero); + + // 2 ^ sig_total_bits, moltiplier to normalize subnormals (0x1p53 for f64) + let f_pow_subnorm = F::from_parts(false, sig_total_bits + F::EXP_BIAS, zero); + + /* + * The goal is to multiply `x` by a scale factor that applies `n`. However, there are cases + * where `2^n` is not representable by `F` but the result should be, e.g. `x = 2^Emin` with + * `n = -EMin + 2` (one out of range of 2^Emax). To get around this, reduce the magnitude of + * the final scale operation by prescaling by the max/min power representable by `F`. + */ + + if n > exp_max { + // Worse case positive `n`: `x` is the minimum subnormal value, the result is `F::MAX`. + // This can be reached by three scaling multiplications (two here and one final). + debug_assert!(-exp_min + F::SIG_BITS as i32 + exp_max <= exp_max * 3); + + x *= f_exp_max; + n -= exp_max; + if n > exp_max { + x *= f_exp_max; + n -= exp_max; + if n > exp_max { + n = exp_max; + } + } + } else if n < exp_min { + // When scaling toward 0, the prescaling is limited to a value that does not allow `x` to + // go subnormal. This avoids double rounding. + if F::BITS > 16 { + // `mul` s.t. `!(x * mul).is_subnormal() ∀ x` + let mul = f_exp_min * f_pow_subnorm; + let add = -exp_min - sig_total_bits as i32; + + // Worse case negative `n`: `x` is the maximum positive value, the result is `F::MIN`. + // This must be reachable by three scaling multiplications (two here and one final). + debug_assert!(-exp_min + F::SIG_BITS as i32 + exp_max <= add * 2 + -exp_min); + + x *= mul; + n += add; + + if n < exp_min { + x *= mul; + n += add; + + if n < exp_min { + n = exp_min; + } + } + } else { + // `f16` is unique compared to other float types in that the difference between the + // minimum exponent and the significand bits (`add = -exp_min - sig_total_bits`) is + // small, only three. The above method depend on decrementing `n` by `add` two times; + // for other float types this works out because `add` is a substantial fraction of + // the exponent range. For `f16`, however, 3 is relatively small compared to the + // exponent range (which is 39), so that requires ~10 prescale rounds rather than two. + // + // Work aroudn this by using a different algorithm that calculates the prescale + // dynamically based on the maximum possible value. This adds more operations per round + // since it needs to construct the scale, but works better in the general case. + let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32); + let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero); + + x *= mul; + n += add; + + if n < exp_min { + let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32); + let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero); + + x *= mul; + n += add; + + if n < exp_min { + n = exp_min; + } + } + } + } + + let scale = F::from_parts(false, (F::EXP_BIAS as i32 + n) as u32, zero); + x * scale +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/libm/src/math/generic/sqrt.rs new file mode 100644 index 00000000000..ec9ff22df20 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/sqrt.rs @@ -0,0 +1,537 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/sqrt.c. Ported to generic Rust algorithm in 2025, TG. */ + +//! Generic square root algorithm. +//! +//! This routine operates around `m_u2`, a U.2 (fixed point with two integral bits) mantissa +//! within the range [1, 4). A table lookup provides an initial estimate, then goldschmidt +//! iterations at various widths are used to approach the real values. +//! +//! For the iterations, `r` is a U0 number that approaches `1/sqrt(m_u2)`, and `s` is a U2 number +//! that approaches `sqrt(m_u2)`. Recall that m_u2 ∈ [1, 4). +//! +//! With Newton-Raphson iterations, this would be: +//! +//! - `w = r * r w ~ 1 / m` +//! - `u = 3 - m * w u ~ 3 - m * w = 3 - m / m = 2` +//! - `r = r * u / 2 r ~ r` +//! +//! (Note that the righthand column does not show anything analytically meaningful (i.e. r ~ r), +//! since the value of performing one iteration is in reducing the error representable by `~`). +//! +//! Instead of Newton-Raphson iterations, Goldschmidt iterations are used to calculate +//! `s = m * r`: +//! +//! - `s = m * r s ~ m / sqrt(m)` +//! - `u = 3 - s * r u ~ 3 - (m / sqrt(m)) * (1 / sqrt(m)) = 3 - m / m = 2` +//! - `r = r * u / 2 r ~ r` +//! - `s = s * u / 2 s ~ s` +//! +//! The above is precise because it uses the original value `m`. There is also a faster version +//! that performs fewer steps but does not use `m`: +//! +//! - `u = 3 - s * r u ~ 3 - 1` +//! - `r = r * u / 2 r ~ r` +//! - `s = s * u / 2 s ~ s` +//! +//! Rounding errors accumulate faster with the second version, so it is only used for subsequent +//! iterations within the same width integer. The first version is always used for the first +//! iteration at a new width in order to avoid this accumulation. +//! +//! Goldschmidt has the advantage over Newton-Raphson that `sqrt(x)` and `1/sqrt(x)` are +//! computed at the same time, i.e. there is no need to calculate `1/sqrt(x)` and invert it. + +use super::super::support::{FpResult, IntTy, Round, Status, cold_path}; +use super::super::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; + +#[inline] +pub fn sqrt(x: F) -> F +where + F: Float + SqrtHelper, + F::Int: HInt, + F::Int: From, + F::Int: From, + F::Int: CastInto, + F::Int: CastInto, + u32: CastInto, +{ + sqrt_round(x, Round::Nearest).val +} + +#[inline] +pub fn sqrt_round(x: F, _round: Round) -> FpResult +where + F: Float + SqrtHelper, + F::Int: HInt, + F::Int: From, + F::Int: From, + F::Int: CastInto, + F::Int: CastInto, + u32: CastInto, +{ + let zero = IntTy::::ZERO; + let one = IntTy::::ONE; + + let mut ix = x.to_bits(); + + // Top is the exponent and sign, which may or may not be shifted. If the float fits into a + // `u32`, we can get by without paying shifting costs. + let noshift = F::BITS <= u32::BITS; + let (mut top, special_case) = if noshift { + let exp_lsb = one << F::SIG_BITS; + let special_case = ix.wrapping_sub(exp_lsb) >= F::EXP_MASK - exp_lsb; + (Exp::NoShift(()), special_case) + } else { + let top = u32::cast_from(ix >> F::SIG_BITS); + let special_case = top.wrapping_sub(1) >= F::EXP_SAT - 1; + (Exp::Shifted(top), special_case) + }; + + // Handle NaN, zero, and out of domain (<= 0) + if special_case { + cold_path(); + + // +/-0 + if ix << 1 == zero { + return FpResult::ok(x); + } + + // Positive infinity + if ix == F::EXP_MASK { + return FpResult::ok(x); + } + + // NaN or negative + if ix > F::EXP_MASK { + return FpResult::new(F::NAN, Status::INVALID); + } + + // Normalize subnormals by multiplying by 1.0 << SIG_BITS (e.g. 0x1p52 for doubles). + let scaled = x * F::from_parts(false, F::SIG_BITS + F::EXP_BIAS, zero); + ix = scaled.to_bits(); + match top { + Exp::Shifted(ref mut v) => { + *v = scaled.ex(); + *v = (*v).wrapping_sub(F::SIG_BITS); + } + Exp::NoShift(()) => { + ix = ix.wrapping_sub((F::SIG_BITS << F::SIG_BITS).cast()); + } + } + } + + // Reduce arguments such that `x = 4^e * m`: + // + // - m_u2 ∈ [1, 4), a fixed point U2.BITS number + // - 2^e is the exponent part of the result + let (m_u2, exp) = match top { + Exp::Shifted(top) => { + // We now know `x` is positive, so `top` is just its (biased) exponent + let mut e = top; + // Construct a fixed point representation of the mantissa. + let mut m_u2 = (ix | F::IMPLICIT_BIT) << F::EXP_BITS; + let even = (e & 1) != 0; + if even { + m_u2 >>= 1; + } + e = (e.wrapping_add(F::EXP_SAT >> 1)) >> 1; + (m_u2, Exp::Shifted(e)) + } + Exp::NoShift(()) => { + let even = ix & (one << F::SIG_BITS) != zero; + + // Exponent part of the return value + let mut e_noshift = ix >> 1; + // ey &= (F::EXP_MASK << 2) >> 2; // clear the top exponent bit (result = 1.0) + e_noshift += (F::EXP_MASK ^ (F::SIGN_MASK >> 1)) >> 1; + e_noshift &= F::EXP_MASK; + + let m1 = (ix << F::EXP_BITS) | F::SIGN_MASK; + let m0 = (ix << (F::EXP_BITS - 1)) & !F::SIGN_MASK; + let m_u2 = if even { m0 } else { m1 }; + + (m_u2, Exp::NoShift(e_noshift)) + } + }; + + // Extract the top 6 bits of the significand with the lowest bit of the exponent. + let i = usize::cast_from(ix >> (F::SIG_BITS - 6)) & 0b1111111; + + // Start with an initial guess for `r = 1 / sqrt(m)` from the table, and shift `m` as an + // initial value for `s = sqrt(m)`. See the module documentation for details. + let r1_u0: F::ISet1 = F::ISet1::cast_from(RSQRT_TAB[i]) << (F::ISet1::BITS - 16); + let s1_u2: F::ISet1 = ((m_u2) >> (F::BITS - F::ISet1::BITS)).cast(); + + // Perform iterations, if any, at quarter width (used for `f128`). + let (r1_u0, _s1_u2) = goldschmidt::(r1_u0, s1_u2, F::SET1_ROUNDS, false); + + // Widen values and perform iterations at half width (used for `f64` and `f128`). + let r2_u0: F::ISet2 = F::ISet2::from(r1_u0) << (F::ISet2::BITS - F::ISet1::BITS); + let s2_u2: F::ISet2 = ((m_u2) >> (F::BITS - F::ISet2::BITS)).cast(); + let (r2_u0, _s2_u2) = goldschmidt::(r2_u0, s2_u2, F::SET2_ROUNDS, false); + + // Perform final iterations at full width (used for all float types). + let r_u0: F::Int = F::Int::from(r2_u0) << (F::BITS - F::ISet2::BITS); + let s_u2: F::Int = m_u2; + let (_r_u0, s_u2) = goldschmidt::(r_u0, s_u2, F::FINAL_ROUNDS, true); + + // Shift back to mantissa position. + let mut m = s_u2 >> (F::EXP_BITS - 2); + + // The musl source includes the following comment (with literals replaced): + // + // > s < sqrt(m) < s + 0x1.09p-SIG_BITS + // > compute nearest rounded result: the nearest result to SIG_BITS bits is either s or + // > s+0x1p-SIG_BITS, we can decide by comparing (2^SIG_BITS s + 0.5)^2 to 2^(2*SIG_BITS) m. + // + // Expanding this with , with `SIG_BITS = p` and adjusting based on the operations done to + // `d0` and `d1`: + // + // - `2^(2p)m ≟ ((2^p)m + 0.5)^2` + // - `2^(2p)m ≟ 2^(2p)m^2 + (2^p)m + 0.25` + // - `2^(2p)m - m^2 ≟ (2^(2p) - 1)m^2 + (2^p)m + 0.25` + // - `(1 - 2^(2p))m + m^2 ≟ (1 - 2^(2p))m^2 + (1 - 2^p)m + 0.25` (?) + // + // I do not follow how the rounding bit is extracted from this comparison with the below + // operations. In any case, the algorithm is well tested. + + // The value needed to shift `m_u2` by to create `m*2^(2p)`. `2p = 2 * F::SIG_BITS`, + // `F::BITS - 2` accounts for the offset that `m_u2` already has. + let shift = 2 * F::SIG_BITS - (F::BITS - 2); + + // `2^(2p)m - m^2` + let d0 = (m_u2 << shift).wrapping_sub(m.wrapping_mul(m)); + // `m - 2^(2p)m + m^2` + let d1 = m.wrapping_sub(d0); + m += d1 >> (F::BITS - 1); + m &= F::SIG_MASK; + + match exp { + Exp::Shifted(e) => m |= IntTy::::cast_from(e) << F::SIG_BITS, + Exp::NoShift(e) => m |= e, + }; + + let mut y = F::from_bits(m); + + // FIXME(f16): the fenv math does not work for `f16` + if F::BITS > 16 { + // Handle rounding and inexact. `(m + 1)^2 == 2^shift m` is exact; for all other cases, add + // a tiny value to cause fenv effects. + let d2 = d1.wrapping_add(m).wrapping_add(one); + let mut tiny = if d2 == zero { + cold_path(); + zero + } else { + F::IMPLICIT_BIT + }; + + tiny |= (d1 ^ d2) & F::SIGN_MASK; + let t = F::from_bits(tiny); + y = y + t; + } + + FpResult::ok(y) +} + +/// Multiply at the wider integer size, returning the high half. +fn wmulh(a: I, b: I) -> I { + a.widen_mul(b).hi() +} + +/// Perform `count` goldschmidt iterations, returning `(r_u0, s_u?)`. +/// +/// - `r_u0` is the reciprocal `r ~ 1 / sqrt(m)`, as U0. +/// - `s_u2` is the square root, `s ~ sqrt(m)`, as U2. +/// - `count` is the number of iterations to perform. +/// - `final_set` should be true if this is the last round (same-sized integer). If so, the +/// returned `s` will be U3, for later shifting. Otherwise, the returned `s` is U2. +/// +/// Note that performance relies on the optimizer being able to unroll these loops (reasonably +/// trivial, `count` is a constant when called). +#[inline] +fn goldschmidt(mut r_u0: I, mut s_u2: I, count: u32, final_set: bool) -> (I, I) +where + F: SqrtHelper, + I: HInt + From, +{ + let three_u2 = I::from(0b11u8) << (I::BITS - 2); + let mut u_u0 = r_u0; + + for i in 0..count { + // First iteration: `s = m*r` (`u_u0 = r_u0` set above) + // Subsequent iterations: `s=s*u/2` + s_u2 = wmulh(s_u2, u_u0); + + // Perform `s /= 2` if: + // + // 1. This is not the first iteration (the first iteration is `s = m*r`)... + // 2. ... and this is not the last set of iterations + // 3. ... or, if this is the last set, it is not the last iteration + // + // This step is not performed for the final iteration because the shift is combined with + // a later shift (moving `s` into the mantissa). + if i > 0 && (!final_set || i + 1 < count) { + s_u2 <<= 1; + } + + // u = 3 - s*r + let d_u2 = wmulh(s_u2, r_u0); + u_u0 = three_u2.wrapping_sub(d_u2); + + // r = r*u/2 + r_u0 = wmulh(r_u0, u_u0) << 1; + } + + (r_u0, s_u2) +} + +/// Representation of whether we shift the exponent into a `u32`, or modify it in place to save +/// the shift operations. +enum Exp { + /// The exponent has been shifted to a `u32` and is LSB-aligned. + Shifted(u32), + /// The exponent is in its natural position in integer repr. + NoShift(T), +} + +/// Size-specific constants related to the square root routine. +pub trait SqrtHelper: Float { + /// Integer for the first set of rounds. If unused, set to the same type as the next set. + type ISet1: HInt + Into + CastFrom + From; + /// Integer for the second set of rounds. If unused, set to the same type as the next set. + type ISet2: HInt + From + From; + + /// Number of rounds at `ISet1`. + const SET1_ROUNDS: u32 = 0; + /// Number of rounds at `ISet2`. + const SET2_ROUNDS: u32 = 0; + /// Number of rounds at `Self::Int`. + const FINAL_ROUNDS: u32; +} + +#[cfg(f16_enabled)] +impl SqrtHelper for f16 { + type ISet1 = u16; // unused + type ISet2 = u16; // unused + + const FINAL_ROUNDS: u32 = 2; +} + +impl SqrtHelper for f32 { + type ISet1 = u32; // unused + type ISet2 = u32; // unused + + const FINAL_ROUNDS: u32 = 3; +} + +impl SqrtHelper for f64 { + type ISet1 = u32; // unused + type ISet2 = u32; + + const SET2_ROUNDS: u32 = 2; + const FINAL_ROUNDS: u32 = 2; +} + +#[cfg(f128_enabled)] +impl SqrtHelper for f128 { + type ISet1 = u32; + type ISet2 = u64; + + const SET1_ROUNDS: u32 = 1; + const SET2_ROUNDS: u32 = 2; + const FINAL_ROUNDS: u32 = 2; +} + +/// A U0.16 representation of `1/sqrt(x)`. +/// +/// The index is a 7-bit number consisting of a single exponent bit and 6 bits of significand. +#[rustfmt::skip] +static RSQRT_TAB: [u16; 128] = [ + 0xb451, 0xb2f0, 0xb196, 0xb044, 0xaef9, 0xadb6, 0xac79, 0xab43, + 0xaa14, 0xa8eb, 0xa7c8, 0xa6aa, 0xa592, 0xa480, 0xa373, 0xa26b, + 0xa168, 0xa06a, 0x9f70, 0x9e7b, 0x9d8a, 0x9c9d, 0x9bb5, 0x9ad1, + 0x99f0, 0x9913, 0x983a, 0x9765, 0x9693, 0x95c4, 0x94f8, 0x9430, + 0x936b, 0x92a9, 0x91ea, 0x912e, 0x9075, 0x8fbe, 0x8f0a, 0x8e59, + 0x8daa, 0x8cfe, 0x8c54, 0x8bac, 0x8b07, 0x8a64, 0x89c4, 0x8925, + 0x8889, 0x87ee, 0x8756, 0x86c0, 0x862b, 0x8599, 0x8508, 0x8479, + 0x83ec, 0x8361, 0x82d8, 0x8250, 0x81c9, 0x8145, 0x80c2, 0x8040, + 0xff02, 0xfd0e, 0xfb25, 0xf947, 0xf773, 0xf5aa, 0xf3ea, 0xf234, + 0xf087, 0xeee3, 0xed47, 0xebb3, 0xea27, 0xe8a3, 0xe727, 0xe5b2, + 0xe443, 0xe2dc, 0xe17a, 0xe020, 0xdecb, 0xdd7d, 0xdc34, 0xdaf1, + 0xd9b3, 0xd87b, 0xd748, 0xd61a, 0xd4f1, 0xd3cd, 0xd2ad, 0xd192, + 0xd07b, 0xcf69, 0xce5b, 0xcd51, 0xcc4a, 0xcb48, 0xca4a, 0xc94f, + 0xc858, 0xc764, 0xc674, 0xc587, 0xc49d, 0xc3b7, 0xc2d4, 0xc1f4, + 0xc116, 0xc03c, 0xbf65, 0xbe90, 0xbdbe, 0xbcef, 0xbc23, 0xbb59, + 0xba91, 0xb9cc, 0xb90a, 0xb84a, 0xb78c, 0xb6d0, 0xb617, 0xb560, +]; + +#[cfg(test)] +mod tests { + use super::*; + + /// Test behavior specified in IEEE 754 `squareRoot`. + fn spec_test() + where + F: Float + SqrtHelper, + F::Int: HInt, + F::Int: From, + F::Int: From, + F::Int: CastInto, + F::Int: CastInto, + u32: CastInto, + { + // Values that should return a NaN and raise invalid + let nan = [F::NEG_INFINITY, F::NEG_ONE, F::NAN, F::MIN]; + + // Values that return unaltered + let roundtrip = [F::ZERO, F::NEG_ZERO, F::INFINITY]; + + for x in nan { + let FpResult { val, status } = sqrt_round(x, Round::Nearest); + assert!(val.is_nan()); + assert!(status == Status::INVALID); + } + + for x in roundtrip { + let FpResult { val, status } = sqrt_round(x, Round::Nearest); + assert_biteq!(val, x); + assert!(status == Status::OK); + } + } + + #[test] + #[cfg(f16_enabled)] + fn sanity_check_f16() { + assert_biteq!(sqrt(100.0f16), 10.0); + assert_biteq!(sqrt(4.0f16), 2.0); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + #[cfg(f16_enabled)] + #[allow(clippy::approx_constant)] + fn conformance_tests_f16() { + let cases = [ + (f16::PI, 0x3f17_u16), + // 10_000.0, using a hex literal for MSRV hack (Rust < 1.67 checks literal widths as + // part of the AST, so the `cfg` is irrelevant here). + (f16::from_bits(0x70e2), 0x5640_u16), + (f16::from_bits(0x0000000f), 0x13bf_u16), + (f16::INFINITY, f16::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrt(input), + f16::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } + + #[test] + fn sanity_check_f32() { + assert_biteq!(sqrt(100.0f32), 10.0); + assert_biteq!(sqrt(4.0f32), 2.0); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + #[allow(clippy::approx_constant)] + fn conformance_tests_f32() { + let cases = [ + (f32::PI, 0x3fe2dfc5_u32), + (10000.0f32, 0x42c80000_u32), + (f32::from_bits(0x0000000f), 0x1b2f456f_u32), + (f32::INFINITY, f32::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrt(input), + f32::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } + + #[test] + fn sanity_check_f64() { + assert_biteq!(sqrt(100.0f64), 10.0); + assert_biteq!(sqrt(4.0f64), 2.0); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[allow(clippy::approx_constant)] + fn conformance_tests_f64() { + let cases = [ + (f64::PI, 0x3ffc5bf891b4ef6a_u64), + (10000.0, 0x4059000000000000_u64), + (f64::from_bits(0x0000000f), 0x1e7efbdeb14f4eda_u64), + (f64::INFINITY, f64::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrt(input), + f64::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } + + #[test] + #[cfg(f128_enabled)] + fn sanity_check_f128() { + assert_biteq!(sqrt(100.0f128), 10.0); + assert_biteq!(sqrt(4.0f128), 2.0); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + #[allow(clippy::approx_constant)] + fn conformance_tests_f128() { + let cases = [ + (f128::PI, 0x3fffc5bf891b4ef6aa79c3b0520d5db9_u128), + // 10_000.0, see `f16` for reasoning. + ( + f128::from_bits(0x400c3880000000000000000000000000), + 0x40059000000000000000000000000000_u128, + ), + (f128::from_bits(0x0000000f), 0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128), + (f128::INFINITY, f128::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrt(input), + f128::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/libm/src/math/generic/trunc.rs new file mode 100644 index 00000000000..25414ecf426 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/generic/trunc.rs @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: MIT + * origin: musl src/math/trunc.c */ + +use super::super::support::{FpResult, Status}; +use super::super::{Float, Int, IntTy, MinInt}; + +#[inline] +pub fn trunc(x: F) -> F { + trunc_status(x).val +} + +#[inline] +pub fn trunc_status(x: F) -> FpResult { + let mut xi: F::Int = x.to_bits(); + let e: i32 = x.exp_unbiased(); + + // C1: The represented value has no fractional part, so no truncation is needed + if e >= F::SIG_BITS as i32 { + return FpResult::ok(x); + } + + let mask = if e < 0 { + // C2: If the exponent is negative, the result will be zero so we mask out everything + // except the sign. + F::SIGN_MASK + } else { + // C3: Otherwise, we mask out the last `e` bits of the significand. + !(F::SIG_MASK >> e.unsigned()) + }; + + // C4: If the to-be-masked-out portion is already zero, we have an exact result + if (xi & !mask) == IntTy::::ZERO { + return FpResult::ok(x); + } + + // C5: Otherwise the result is inexact and we will truncate. Raise `FE_INEXACT`, mask the + // result, and return. + + let status = if xi & F::SIG_MASK == F::Int::ZERO { Status::OK } else { Status::INEXACT }; + xi &= mask; + FpResult::new(F::from_bits(xi), status) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::Hexf; + + fn spec_test(cases: &[(F, F, Status)]) { + let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + + for x in roundtrip { + let FpResult { val, status } = trunc_status(x); + assert_biteq!(val, x, "{}", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = trunc_status(x); + assert_biteq!(val, res, "{}", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); + } + } + + /* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */ + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + let cases = []; + spec_test::(&cases); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(trunc(0.5f32), 0.0); + assert_eq!(trunc(1.1f32), 1.0); + assert_eq!(trunc(2.9f32), 2.0); + } + + #[test] + fn spec_tests_f32() { + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + + assert_biteq!(trunc(1.1f32), 1.0); + assert_biteq!(trunc(1.1f64), 1.0); + + // C1 + assert_biteq!(trunc(hf32!("0x1p23")), hf32!("0x1p23")); + assert_biteq!(trunc(hf64!("0x1p52")), hf64!("0x1p52")); + assert_biteq!(trunc(hf32!("-0x1p23")), hf32!("-0x1p23")); + assert_biteq!(trunc(hf64!("-0x1p52")), hf64!("-0x1p52")); + + // C2 + assert_biteq!(trunc(hf32!("0x1p-1")), 0.0); + assert_biteq!(trunc(hf64!("0x1p-1")), 0.0); + assert_biteq!(trunc(hf32!("-0x1p-1")), -0.0); + assert_biteq!(trunc(hf64!("-0x1p-1")), -0.0); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(trunc(1.1f64), 1.0); + assert_eq!(trunc(2.9f64), 2.0); + } + + #[test] + fn spec_tests_f64() { + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + let cases = []; + spec_test::(&cases); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/hypot.rs b/library/compiler-builtins/libm/libm/src/math/hypot.rs new file mode 100644 index 00000000000..da458ea1d05 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/hypot.rs @@ -0,0 +1,74 @@ +use core::f64; + +use super::sqrt; + +const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 + +fn sq(x: f64) -> (f64, f64) { + let xh: f64; + let xl: f64; + let xc: f64; + + xc = x * SPLIT; + xh = x - xc + xc; + xl = x - xh; + let hi = x * x; + let lo = xh * xh - hi + 2. * xh * xl + xl * xl; + (hi, lo) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn hypot(mut x: f64, mut y: f64) -> f64 { + let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700 + let x1p_700 = f64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700 + + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let uti; + let ex: i64; + let ey: i64; + let mut z: f64; + + /* arrange |x| >= |y| */ + uxi &= -1i64 as u64 >> 1; + uyi &= -1i64 as u64 >> 1; + if uxi < uyi { + uti = uxi; + uxi = uyi; + uyi = uti; + } + + /* special cases */ + ex = (uxi >> 52) as i64; + ey = (uyi >> 52) as i64; + x = f64::from_bits(uxi); + y = f64::from_bits(uyi); + /* note: hypot(inf,nan) == inf */ + if ey == 0x7ff { + return y; + } + if ex == 0x7ff || uyi == 0 { + return x; + } + /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ + /* 64 difference is enough for ld80 double_t */ + if ex - ey > 64 { + return x + y; + } + + /* precise sqrt argument in nearest rounding mode without overflow */ + /* xh*xh must not overflow and xl*xl must not underflow in sq */ + z = 1.; + if ex > 0x3ff + 510 { + z = x1p700; + x *= x1p_700; + y *= x1p_700; + } else if ey < 0x3ff - 450 { + z = x1p_700; + x *= x1p700; + y *= x1p700; + } + let (hx, lx) = sq(x); + let (hy, ly) = sq(y); + z * sqrt(ly + lx + hy + hx) +} diff --git a/library/compiler-builtins/libm/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/libm/src/math/hypotf.rs new file mode 100644 index 00000000000..576eebb3343 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/hypotf.rs @@ -0,0 +1,43 @@ +use core::f32; + +use super::sqrtf; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn hypotf(mut x: f32, mut y: f32) -> f32 { + let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90 + let x1p_90 = f32::from_bits(0x12800000); // 0x1p-90f === 2 ^ -90 + + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let uti; + let mut z: f32; + + uxi &= -1i32 as u32 >> 1; + uyi &= -1i32 as u32 >> 1; + if uxi < uyi { + uti = uxi; + uxi = uyi; + uyi = uti; + } + + x = f32::from_bits(uxi); + y = f32::from_bits(uyi); + if uyi == 0xff << 23 { + return y; + } + if uxi >= 0xff << 23 || uyi == 0 || uxi - uyi >= 25 << 23 { + return x + y; + } + + z = 1.; + if uxi >= (0x7f + 60) << 23 { + z = x1p90; + x *= x1p_90; + y *= x1p_90; + } else if uyi < (0x7f - 60) << 23 { + z = x1p_90; + x *= x1p90; + y *= x1p90; + } + z * sqrtf((x as f64 * x as f64 + y as f64 * y as f64) as f32) +} diff --git a/library/compiler-builtins/libm/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/libm/src/math/ilogb.rs new file mode 100644 index 00000000000..ccc4914be2b --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/ilogb.rs @@ -0,0 +1,28 @@ +const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; +const FP_ILOGB0: i32 = FP_ILOGBNAN; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ilogb(x: f64) -> i32 { + let mut i: u64 = x.to_bits(); + let e = ((i >> 52) & 0x7ff) as i32; + + if e == 0 { + i <<= 12; + if i == 0 { + force_eval!(0.0 / 0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -0x3ff; + while (i >> 63) == 0 { + e -= 1; + i <<= 1; + } + e + } else if e == 0x7ff { + force_eval!(0.0 / 0.0); + if (i << 12) != 0 { FP_ILOGBNAN } else { i32::MAX } + } else { + e - 0x3ff + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/libm/src/math/ilogbf.rs new file mode 100644 index 00000000000..3585d6d36f1 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/ilogbf.rs @@ -0,0 +1,28 @@ +const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; +const FP_ILOGB0: i32 = FP_ILOGBNAN; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ilogbf(x: f32) -> i32 { + let mut i = x.to_bits(); + let e = ((i >> 23) & 0xff) as i32; + + if e == 0 { + i <<= 9; + if i == 0 { + force_eval!(0.0 / 0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -0x7f; + while (i >> 31) == 0 { + e -= 1; + i <<= 1; + } + e + } else if e == 0xff { + force_eval!(0.0 / 0.0); + if (i << 9) != 0 { FP_ILOGBNAN } else { i32::MAX } + } else { + e - 0x7f + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/j0.rs b/library/compiler-builtins/libm/libm/src/math/j0.rs new file mode 100644 index 00000000000..99d656f0d08 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/j0.rs @@ -0,0 +1,426 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j0(x), y0(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j0(x): + * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... + * 2. Reduce x to |x| since j0(x)=j0(-x), and + * for x in (0,2) + * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; + * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) + * for x in (2,inf) + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * as follow: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (cos(x) + sin(x)) + * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j0(nan)= nan + * j0(0) = 1 + * j0(inf) = 0 + * + * Method -- y0(x): + * 1. For x<2. + * Since + * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) + * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. + * We use the following function to approximate y0, + * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 + * where + * U(z) = u00 + u01*z + ... + u06*z^6 + * V(z) = 1 + v01*z + ... + v04*z^4 + * with absolute approximation error bounded by 2**-72. + * Note: For tiny x, U/V = u0 and j0(x)~1, hence + * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) + * 2. For x>=2. + * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * by the method mentioned above. + * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. + */ + +use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +/* common method when |x|>=2 */ +fn common(ix: u32, x: f64, y0: bool) -> f64 { + let s: f64; + let mut c: f64; + let mut ss: f64; + let mut cc: f64; + let z: f64; + + /* + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) + * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) + * + * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) + * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + c = cos(x); + if y0 { + c = -c; + } + cc = s + c; + /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ + if ix < 0x7fe00000 { + ss = s - c; + z = -cos(2.0 * x); + if s * c < 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x48000000 { + if y0 { + ss = -ss; + } + cc = pzero(x) * cc - qzero(x) * ss; + } + } + return INVSQRTPI * cc / sqrt(x); +} + +/* R0/S0 on [0, 2.00] */ +const R02: f64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ +const R03: f64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ +const R04: f64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ +const R05: f64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */ +const S01: f64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ +const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ +const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ +const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ + +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn j0(mut x: f64) -> f64 { + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + + /* j0(+-inf)=0, j0(nan)=nan */ + if ix >= 0x7ff00000 { + return 1.0 / (x * x); + } + x = fabs(x); + + if ix >= 0x40000000 { + /* |x| >= 2 */ + /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ + return common(ix, x, false); + } + + /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ + if ix >= 0x3f200000 { + /* |x| >= 2**-13 */ + /* up to 4ulp error close to 2 */ + z = x * x; + r = z * (R02 + z * (R03 + z * (R04 + z * R05))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); + return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); + } + + /* 1 - x*x/4 */ + /* prevent underflow */ + /* inexact should be raised when x!=0, this is not done correctly */ + if ix >= 0x38000000 { + /* |x| >= 2**-127 */ + x = 0.25 * x * x; + } + return 1.0 - x; +} + +const U00: f64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ +const U01: f64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ +const U02: f64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ +const U03: f64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */ +const U04: f64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */ +const U05: f64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */ +const U06: f64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */ +const V01: f64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ +const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ +const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ +const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ + +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn y0(x: f64) -> f64 { + let z: f64; + let u: f64; + let v: f64; + let ix: u32; + let lx: u32; + + ix = get_high_word(x); + lx = get_low_word(x); + + /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ + if ((ix << 1) | lx) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7ff00000 { + return 1.0 / x; + } + + if ix >= 0x40000000 { + /* x >= 2 */ + /* large ulp errors near zeros: 3.958, 7.086,.. */ + return common(ix, x, true); + } + + /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ + if ix >= 0x3e400000 { + /* x >= 2**-27 */ + /* large ulp error near the first zero, x ~= 0.89 */ + z = x * x; + u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); + v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); + return u / v + TPI * (j0(x) * log(x)); + } + return U00 + TPI * log(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +const PR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ + -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ + -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ + -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ + -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ +]; +const PS8: [f64; 5] = [ + 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ + 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ + 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ + 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ + 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ +]; + +const PR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ + -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ + -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ + -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ + -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ + -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ +]; +const PS5: [f64; 5] = [ + 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ + 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ + 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ + 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ + 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ +]; + +const PR3: [f64; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ + -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ + -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ + -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ + -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ + -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ +]; +const PS3: [f64; 5] = [ + 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ + 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ + 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ + 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ + 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ +]; + +const PR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ + -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ + -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ + -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ + -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ + -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ +]; +const PS2: [f64; 5] = [ + 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ + 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ + 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ + 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ + 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ +]; + +fn pzero(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 5]; + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x40122E8B { + p = &PR5; + q = &PS5; + } else if ix >= 0x4006DB6D { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +const QR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ + 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ + 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ + 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ + 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ +]; +const QS8: [f64; 6] = [ + 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ + 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ + 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ + 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ + 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ + -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ +]; + +const QR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ + 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ + 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ + 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ + 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ + 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ +]; +const QS5: [f64; 6] = [ + 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ + 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ + 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ + 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ + 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ + -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ +]; + +const QR3: [f64; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ + 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ + 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ + 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ + 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ + 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ +]; +const QS3: [f64; 6] = [ + 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ + 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ + 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ + 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ + 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ + -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ +]; + +const QR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ + 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ + 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ + 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ + 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ + 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ +]; +const QS2: [f64; 6] = [ + 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ + 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ + 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ + 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ + 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ + -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ +]; + +fn qzero(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 6]; + let s: f64; + let r: f64; + let z: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x40122E8B { + p = &QR5; + q = &QS5; + } else if ix >= 0x4006DB6D { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (-0.125 + r / s) / x; +} diff --git a/library/compiler-builtins/libm/libm/src/math/j0f.rs b/library/compiler-builtins/libm/libm/src/math/j0f.rs new file mode 100644 index 00000000000..25e5b325c8c --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/j0f.rs @@ -0,0 +1,363 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{cosf, fabsf, logf, sinf, sqrtf}; + +const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ + +fn common(ix: u32, x: f32, y0: bool) -> f32 { + let z: f32; + let s: f32; + let mut c: f32; + let mut ss: f32; + let mut cc: f32; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + s = sinf(x); + c = cosf(x); + if y0 { + c = -c; + } + cc = s + c; + if ix < 0x7f000000 { + ss = s - c; + z = -cosf(2.0 * x); + if s * c < 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x58800000 { + if y0 { + ss = -ss; + } + cc = pzerof(x) * cc - qzerof(x) * ss; + } + } + return INVSQRTPI * cc / sqrtf(x); +} + +/* R0/S0 on [0, 2.00] */ +const R02: f32 = 1.5625000000e-02; /* 0x3c800000 */ +const R03: f32 = -1.8997929874e-04; /* 0xb947352e */ +const R04: f32 = 1.8295404516e-06; /* 0x35f58e88 */ +const R05: f32 = -4.6183270541e-09; /* 0xb19eaf3c */ +const S01: f32 = 1.5619102865e-02; /* 0x3c7fe744 */ +const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ +const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ +const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ + +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn j0f(mut x: f32) -> f32 { + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + return 1.0 / (x * x); + } + x = fabsf(x); + + if ix >= 0x40000000 { + /* |x| >= 2 */ + /* large ulp error near zeros */ + return common(ix, x, false); + } + if ix >= 0x3a000000 { + /* |x| >= 2**-11 */ + /* up to 4ulp error near 2 */ + z = x * x; + r = z * (R02 + z * (R03 + z * (R04 + z * R05))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); + return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); + } + if ix >= 0x21800000 { + /* |x| >= 2**-60 */ + x = 0.25 * x * x; + } + return 1.0 - x; +} + +const U00: f32 = -7.3804296553e-02; /* 0xbd9726b5 */ +const U01: f32 = 1.7666645348e-01; /* 0x3e34e80d */ +const U02: f32 = -1.3818567619e-02; /* 0xbc626746 */ +const U03: f32 = 3.4745343146e-04; /* 0x39b62a69 */ +const U04: f32 = -3.8140706238e-06; /* 0xb67ff53c */ +const U05: f32 = 1.9559013964e-08; /* 0x32a802ba */ +const U06: f32 = -3.9820518410e-11; /* 0xae2f21eb */ +const V01: f32 = 1.2730483897e-02; /* 0x3c509385 */ +const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ +const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ +const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ + +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn y0f(x: f32) -> f32 { + let z: f32; + let u: f32; + let v: f32; + let ix: u32; + + ix = x.to_bits(); + if (ix & 0x7fffffff) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7f800000 { + return 1.0 / x; + } + if ix >= 0x40000000 { + /* |x| >= 2.0 */ + /* large ulp error near zeros */ + return common(ix, x, true); + } + if ix >= 0x39000000 { + /* x >= 2**-13 */ + /* large ulp error at x ~= 0.89 */ + z = x * x; + u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); + v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); + return u / v + TPI * (j0f(x) * logf(x)); + } + return U00 + TPI * logf(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +const PR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -7.0312500000e-02, /* 0xbd900000 */ + -8.0816707611e+00, /* 0xc1014e86 */ + -2.5706311035e+02, /* 0xc3808814 */ + -2.4852163086e+03, /* 0xc51b5376 */ + -5.2530439453e+03, /* 0xc5a4285a */ +]; +const PS8: [f32; 5] = [ + 1.1653436279e+02, /* 0x42e91198 */ + 3.8337448730e+03, /* 0x456f9beb */ + 4.0597855469e+04, /* 0x471e95db */ + 1.1675296875e+05, /* 0x47e4087c */ + 4.7627726562e+04, /* 0x473a0bba */ +]; +const PR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.1412546255e-11, /* 0xad48c58a */ + -7.0312492549e-02, /* 0xbd8fffff */ + -4.1596107483e+00, /* 0xc0851b88 */ + -6.7674766541e+01, /* 0xc287597b */ + -3.3123129272e+02, /* 0xc3a59d9b */ + -3.4643338013e+02, /* 0xc3ad3779 */ +]; +const PS5: [f32; 5] = [ + 6.0753936768e+01, /* 0x42730408 */ + 1.0512523193e+03, /* 0x44836813 */ + 5.9789707031e+03, /* 0x45bad7c4 */ + 9.6254453125e+03, /* 0x461665c8 */ + 2.4060581055e+03, /* 0x451660ee */ +]; + +const PR3: [f32; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.5470459075e-09, /* 0xb12f081b */ + -7.0311963558e-02, /* 0xbd8fffb8 */ + -2.4090321064e+00, /* 0xc01a2d95 */ + -2.1965976715e+01, /* 0xc1afba52 */ + -5.8079170227e+01, /* 0xc2685112 */ + -3.1447946548e+01, /* 0xc1fb9565 */ +]; +const PS3: [f32; 5] = [ + 3.5856033325e+01, /* 0x420f6c94 */ + 3.6151397705e+02, /* 0x43b4c1ca */ + 1.1936077881e+03, /* 0x44953373 */ + 1.1279968262e+03, /* 0x448cffe6 */ + 1.7358093262e+02, /* 0x432d94b8 */ +]; + +const PR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.8753431271e-08, /* 0xb3be98b7 */ + -7.0303097367e-02, /* 0xbd8ffb12 */ + -1.4507384300e+00, /* 0xbfb9b1cc */ + -7.6356959343e+00, /* 0xc0f4579f */ + -1.1193166733e+01, /* 0xc1331736 */ + -3.2336456776e+00, /* 0xc04ef40d */ +]; +const PS2: [f32; 5] = [ + 2.2220300674e+01, /* 0x41b1c32d */ + 1.3620678711e+02, /* 0x430834f0 */ + 2.7047027588e+02, /* 0x43873c32 */ + 1.5387539673e+02, /* 0x4319e01a */ + 1.4657617569e+01, /* 0x416a859a */ +]; + +fn pzerof(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 5]; + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x409173eb { + p = &PR5; + q = &PS5; + } else if ix >= 0x4036d917 { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +const QR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 7.3242187500e-02, /* 0x3d960000 */ + 1.1768206596e+01, /* 0x413c4a93 */ + 5.5767340088e+02, /* 0x440b6b19 */ + 8.8591972656e+03, /* 0x460a6cca */ + 3.7014625000e+04, /* 0x471096a0 */ +]; +const QS8: [f32; 6] = [ + 1.6377603149e+02, /* 0x4323c6aa */ + 8.0983447266e+03, /* 0x45fd12c2 */ + 1.4253829688e+05, /* 0x480b3293 */ + 8.0330925000e+05, /* 0x49441ed4 */ + 8.4050156250e+05, /* 0x494d3359 */ + -3.4389928125e+05, /* 0xc8a7eb69 */ +]; + +const QR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.8408595828e-11, /* 0x2da1ec79 */ + 7.3242180049e-02, /* 0x3d95ffff */ + 5.8356351852e+00, /* 0x40babd86 */ + 1.3511157227e+02, /* 0x43071c90 */ + 1.0272437744e+03, /* 0x448067cd */ + 1.9899779053e+03, /* 0x44f8bf4b */ +]; +const QS5: [f32; 6] = [ + 8.2776611328e+01, /* 0x42a58da0 */ + 2.0778142090e+03, /* 0x4501dd07 */ + 1.8847289062e+04, /* 0x46933e94 */ + 5.6751113281e+04, /* 0x475daf1d */ + 3.5976753906e+04, /* 0x470c88c1 */ + -5.3543427734e+03, /* 0xc5a752be */ +]; + +const QR3: [f32; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.3774099900e-09, /* 0x3196681b */ + 7.3241114616e-02, /* 0x3d95ff70 */ + 3.3442313671e+00, /* 0x405607e3 */ + 4.2621845245e+01, /* 0x422a7cc5 */ + 1.7080809021e+02, /* 0x432acedf */ + 1.6673394775e+02, /* 0x4326bbe4 */ +]; +const QS3: [f32; 6] = [ + 4.8758872986e+01, /* 0x42430916 */ + 7.0968920898e+02, /* 0x44316c1c */ + 3.7041481934e+03, /* 0x4567825f */ + 6.4604252930e+03, /* 0x45c9e367 */ + 2.5163337402e+03, /* 0x451d4557 */ + -1.4924745178e+02, /* 0xc3153f59 */ +]; + +const QR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.5044444979e-07, /* 0x342189db */ + 7.3223426938e-02, /* 0x3d95f62a */ + 1.9981917143e+00, /* 0x3fffc4bf */ + 1.4495602608e+01, /* 0x4167edfd */ + 3.1666231155e+01, /* 0x41fd5471 */ + 1.6252708435e+01, /* 0x4182058c */ +]; +const QS2: [f32; 6] = [ + 3.0365585327e+01, /* 0x41f2ecb8 */ + 2.6934811401e+02, /* 0x4386ac8f */ + 8.4478375244e+02, /* 0x44533229 */ + 8.8293585205e+02, /* 0x445cbbe5 */ + 2.1266638184e+02, /* 0x4354aa98 */ + -5.3109550476e+00, /* 0xc0a9f358 */ +]; + +fn qzerof(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 6]; + let s: f32; + let r: f32; + let z: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x409173eb { + p = &QR5; + q = &QS5; + } else if ix >= 0x4036d917 { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (-0.125 + r / s) / x; +} diff --git a/library/compiler-builtins/libm/libm/src/math/j1.rs b/library/compiler-builtins/libm/libm/src/math/j1.rs new file mode 100644 index 00000000000..9b604d9e46e --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/j1.rs @@ -0,0 +1,418 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j1(x), y1(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j1(x): + * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... + * 2. Reduce x to |x| since j1(x)=-j1(-x), and + * for x in (0,2) + * j1(x) = x/2 + x*z*R0/S0, where z = x*x; + * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) + * for x in (2,inf) + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * as follow: + * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (sin(x) + cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j1(nan)= nan + * j1(0) = 0 + * j1(inf) = 0 + * + * Method -- y1(x): + * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN + * 2. For x<2. + * Since + * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) + * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. + * We use the following function to approximate y1, + * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 + * where for x in [0,2] (abs err less than 2**-65.89) + * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 + * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 + * Note: For tiny x, 1/x dominate y1 and hence + * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) + * 3. For x>=2. + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * by method mentioned above. + */ + +use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; + +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +fn common(ix: u32, x: f64, y1: bool, sign: bool) -> f64 { + let z: f64; + let mut s: f64; + let c: f64; + let mut ss: f64; + let mut cc: f64; + + /* + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) + * + * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) + * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + if y1 { + s = -s; + } + c = cos(x); + cc = s - c; + if ix < 0x7fe00000 { + /* avoid overflow in 2*x */ + ss = -s - c; + z = cos(2.0 * x); + if s * c > 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x48000000 { + if y1 { + ss = -ss; + } + cc = pone(x) * cc - qone(x) * ss; + } + } + if sign { + cc = -cc; + } + return INVSQRTPI * cc / sqrt(x); +} + +/* R0/S0 on [0,2] */ +const R00: f64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ +const R01: f64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ +const R02: f64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ +const R03: f64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ +const S01: f64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ +const S02: f64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ +const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ +const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ +const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ + +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn j1(x: f64) -> f64 { + let mut z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + let sign: bool; + + ix = get_high_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + return 1.0 / (x * x); + } + if ix >= 0x40000000 { + /* |x| >= 2 */ + return common(ix, fabs(x), false, sign); + } + if ix >= 0x38000000 { + /* |x| >= 2**-127 */ + z = x * x; + r = z * (R00 + z * (R01 + z * (R02 + z * R03))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); + z = r / s; + } else { + /* avoid underflow, raise inexact if x!=0 */ + z = x; + } + return (0.5 + z) * x; +} + +const U0: [f64; 5] = [ + -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ + 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ + 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ +]; +const V0: [f64; 5] = [ + 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ + 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ +]; + +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn y1(x: f64) -> f64 { + let z: f64; + let u: f64; + let v: f64; + let ix: u32; + let lx: u32; + + ix = get_high_word(x); + lx = get_low_word(x); + + /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ + if (ix << 1) | lx == 0 { + return -1.0 / 0.0; + } + if ix >> 31 != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7ff00000 { + return 1.0 / x; + } + + if ix >= 0x40000000 { + /* x >= 2 */ + return common(ix, x, true, false); + } + if ix < 0x3c900000 { + /* x < 2**-54 */ + return -TPI / x; + } + z = x * x; + u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + return x * (u / v) + TPI * (j1(x) * log(x) - 1.0 / x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +const PR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ + 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ + 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ + 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ +]; +const PS8: [f64; 5] = [ + 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ + 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ + 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ + 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ + 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ +]; + +const PR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ + 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ + 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ + 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ +]; +const PS5: [f64; 5] = [ + 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ + 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ + 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ + 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ +]; + +const PR3: [f64; 6] = [ + 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ + 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ + 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ + 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ +]; +const PS3: [f64; 5] = [ + 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ + 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ + 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ + 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ + 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ +]; + +const PR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ + 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ + 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ + 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ +]; +const PS2: [f64; 5] = [ + 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ + 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ + 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ + 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ +]; + +fn pone(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 5]; + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x40122E8B { + p = &PR5; + q = &PS5; + } else if ix >= 0x4006DB6D { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +const QR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ + -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ + -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ + -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ + -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ +]; +const QS8: [f64; 6] = [ + 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ + 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ + 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ + 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ + 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ + -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ +]; + +const QR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ + -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ + -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ + -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ + -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ + -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ +]; +const QS5: [f64; 6] = [ + 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ + 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ + 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ + 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ + 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ + -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ +]; + +const QR3: [f64; 6] = [ + -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ + -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ + -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ + -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ + -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ + -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ +]; +const QS3: [f64; 6] = [ + 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ + 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ + 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ + 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ + 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ + -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ +]; + +const QR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ + -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ + -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ + -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ + -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ + -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ +]; +const QS2: [f64; 6] = [ + 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ + 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ + 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ + 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ + 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ + -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ +]; + +fn qone(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 6]; + let s: f64; + let r: f64; + let z: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x40122E8B { + p = &QR5; + q = &QS5; + } else if ix >= 0x4006DB6D { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (0.375 + r / s) / x; +} diff --git a/library/compiler-builtins/libm/libm/src/math/j1f.rs b/library/compiler-builtins/libm/libm/src/math/j1f.rs new file mode 100644 index 00000000000..a47472401ee --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/j1f.rs @@ -0,0 +1,384 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{cosf, fabsf, logf, sinf, sqrtf}; + +const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ + +fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 { + let z: f64; + let mut s: f64; + let c: f64; + let mut ss: f64; + let mut cc: f64; + + s = sinf(x) as f64; + if y1 { + s = -s; + } + c = cosf(x) as f64; + cc = s - c; + if ix < 0x7f000000 { + ss = -s - c; + z = cosf(2.0 * x) as f64; + if s * c > 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x58800000 { + if y1 { + ss = -ss; + } + cc = (ponef(x) as f64) * cc - (qonef(x) as f64) * ss; + } + } + if sign { + cc = -cc; + } + return (((INVSQRTPI as f64) * cc) / (sqrtf(x) as f64)) as f32; +} + +/* R0/S0 on [0,2] */ +const R00: f32 = -6.2500000000e-02; /* 0xbd800000 */ +const R01: f32 = 1.4070566976e-03; /* 0x3ab86cfd */ +const R02: f32 = -1.5995563444e-05; /* 0xb7862e36 */ +const R03: f32 = 4.9672799207e-08; /* 0x335557d2 */ +const S01: f32 = 1.9153760746e-02; /* 0x3c9ce859 */ +const S02: f32 = 1.8594678841e-04; /* 0x3942fab6 */ +const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ +const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ +const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ + +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn j1f(x: f32) -> f32 { + let mut z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + let sign: bool; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + return 1.0 / (x * x); + } + if ix >= 0x40000000 { + /* |x| >= 2 */ + return common(ix, fabsf(x), false, sign); + } + if ix >= 0x39000000 { + /* |x| >= 2**-13 */ + z = x * x; + r = z * (R00 + z * (R01 + z * (R02 + z * R03))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); + z = 0.5 + r / s; + } else { + z = 0.5; + } + return z * x; +} + +const U0: [f32; 5] = [ + -1.9605709612e-01, /* 0xbe48c331 */ + 5.0443872809e-02, /* 0x3d4e9e3c */ + -1.9125689287e-03, /* 0xbafaaf2a */ + 2.3525259166e-05, /* 0x37c5581c */ + -9.1909917899e-08, /* 0xb3c56003 */ +]; +const V0: [f32; 5] = [ + 1.9916731864e-02, /* 0x3ca3286a */ + 2.0255257550e-04, /* 0x3954644b */ + 1.3560879779e-06, /* 0x35b602d4 */ + 6.2274145840e-09, /* 0x31d5f8eb */ + 1.6655924903e-11, /* 0x2d9281cf */ +]; + +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn y1f(x: f32) -> f32 { + let z: f32; + let u: f32; + let v: f32; + let ix: u32; + + ix = x.to_bits(); + if (ix & 0x7fffffff) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7f800000 { + return 1.0 / x; + } + if ix >= 0x40000000 { + /* |x| >= 2.0 */ + return common(ix, x, true, false); + } + if ix < 0x33000000 { + /* x < 2**-25 */ + return -TPI / x; + } + z = x * x; + u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + return x * (u / v) + TPI * (j1f(x) * logf(x) - 1.0 / x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +const PR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 1.1718750000e-01, /* 0x3df00000 */ + 1.3239480972e+01, /* 0x4153d4ea */ + 4.1205184937e+02, /* 0x43ce06a3 */ + 3.8747453613e+03, /* 0x45722bed */ + 7.9144794922e+03, /* 0x45f753d6 */ +]; +const PS8: [f32; 5] = [ + 1.1420736694e+02, /* 0x42e46a2c */ + 3.6509309082e+03, /* 0x45642ee5 */ + 3.6956207031e+04, /* 0x47105c35 */ + 9.7602796875e+04, /* 0x47bea166 */ + 3.0804271484e+04, /* 0x46f0a88b */ +]; + +const PR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.3199052094e-11, /* 0x2d68333f */ + 1.1718749255e-01, /* 0x3defffff */ + 6.8027510643e+00, /* 0x40d9b023 */ + 1.0830818176e+02, /* 0x42d89dca */ + 5.1763616943e+02, /* 0x440168b7 */ + 5.2871520996e+02, /* 0x44042dc6 */ +]; +const PS5: [f32; 5] = [ + 5.9280597687e+01, /* 0x426d1f55 */ + 9.9140142822e+02, /* 0x4477d9b1 */ + 5.3532670898e+03, /* 0x45a74a23 */ + 7.8446904297e+03, /* 0x45f52586 */ + 1.5040468750e+03, /* 0x44bc0180 */ +]; + +const PR3: [f32; 6] = [ + 3.0250391081e-09, /* 0x314fe10d */ + 1.1718686670e-01, /* 0x3defffab */ + 3.9329774380e+00, /* 0x407bb5e7 */ + 3.5119403839e+01, /* 0x420c7a45 */ + 9.1055007935e+01, /* 0x42b61c2a */ + 4.8559066772e+01, /* 0x42423c7c */ +]; +const PS3: [f32; 5] = [ + 3.4791309357e+01, /* 0x420b2a4d */ + 3.3676245117e+02, /* 0x43a86198 */ + 1.0468714600e+03, /* 0x4482dbe3 */ + 8.9081134033e+02, /* 0x445eb3ed */ + 1.0378793335e+02, /* 0x42cf936c */ +]; + +const PR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.0771083225e-07, /* 0x33e74ea8 */ + 1.1717621982e-01, /* 0x3deffa16 */ + 2.3685150146e+00, /* 0x401795c0 */ + 1.2242610931e+01, /* 0x4143e1bc */ + 1.7693971634e+01, /* 0x418d8d41 */ + 5.0735230446e+00, /* 0x40a25a4d */ +]; +const PS2: [f32; 5] = [ + 2.1436485291e+01, /* 0x41ab7dec */ + 1.2529022980e+02, /* 0x42fa9499 */ + 2.3227647400e+02, /* 0x436846c7 */ + 1.1767937469e+02, /* 0x42eb5bd7 */ + 8.3646392822e+00, /* 0x4105d590 */ +]; + +fn ponef(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 5]; + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x409173eb { + p = &PR5; + q = &PS5; + } else if ix >= 0x4036d917 { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +const QR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -1.0253906250e-01, /* 0xbdd20000 */ + -1.6271753311e+01, /* 0xc1822c8d */ + -7.5960174561e+02, /* 0xc43de683 */ + -1.1849806641e+04, /* 0xc639273a */ + -4.8438511719e+04, /* 0xc73d3683 */ +]; +const QS8: [f32; 6] = [ + 1.6139537048e+02, /* 0x43216537 */ + 7.8253862305e+03, /* 0x45f48b17 */ + 1.3387534375e+05, /* 0x4802bcd6 */ + 7.1965775000e+05, /* 0x492fb29c */ + 6.6660125000e+05, /* 0x4922be94 */ + -2.9449025000e+05, /* 0xc88fcb48 */ +]; + +const QR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.0897993405e-11, /* 0xadb7d219 */ + -1.0253904760e-01, /* 0xbdd1fffe */ + -8.0564479828e+00, /* 0xc100e736 */ + -1.8366960144e+02, /* 0xc337ab6b */ + -1.3731937256e+03, /* 0xc4aba633 */ + -2.6124443359e+03, /* 0xc523471c */ +]; +const QS5: [f32; 6] = [ + 8.1276550293e+01, /* 0x42a28d98 */ + 1.9917987061e+03, /* 0x44f8f98f */ + 1.7468484375e+04, /* 0x468878f8 */ + 4.9851425781e+04, /* 0x4742bb6d */ + 2.7948074219e+04, /* 0x46da5826 */ + -4.7191835938e+03, /* 0xc5937978 */ +]; + +const QR3: [f32; 6] = [ + -5.0783124372e-09, /* 0xb1ae7d4f */ + -1.0253783315e-01, /* 0xbdd1ff5b */ + -4.6101160049e+00, /* 0xc0938612 */ + -5.7847221375e+01, /* 0xc267638e */ + -2.2824453735e+02, /* 0xc3643e9a */ + -2.1921012878e+02, /* 0xc35b35cb */ +]; +const QS3: [f32; 6] = [ + 4.7665153503e+01, /* 0x423ea91e */ + 6.7386511230e+02, /* 0x4428775e */ + 3.3801528320e+03, /* 0x45534272 */ + 5.5477290039e+03, /* 0x45ad5dd5 */ + 1.9031191406e+03, /* 0x44ede3d0 */ + -1.3520118713e+02, /* 0xc3073381 */ +]; + +const QR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.7838172539e-07, /* 0xb43f8932 */ + -1.0251704603e-01, /* 0xbdd1f475 */ + -2.7522056103e+00, /* 0xc0302423 */ + -1.9663616180e+01, /* 0xc19d4f16 */ + -4.2325313568e+01, /* 0xc2294d1f */ + -2.1371921539e+01, /* 0xc1aaf9b2 */ +]; +const QS2: [f32; 6] = [ + 2.9533363342e+01, /* 0x41ec4454 */ + 2.5298155212e+02, /* 0x437cfb47 */ + 7.5750280762e+02, /* 0x443d602e */ + 7.3939318848e+02, /* 0x4438d92a */ + 1.5594900513e+02, /* 0x431bf2f2 */ + -4.9594988823e+00, /* 0xc09eb437 */ +]; + +fn qonef(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 6]; + let s: f32; + let r: f32; + let z: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x409173eb { + p = &QR5; + q = &QS5; + } else if ix >= 0x4036d917 { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (0.375 + r / s) / x; +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::{j1f, y1f}; + #[test] + fn test_j1f_2488() { + // 0x401F3E49 + assert_eq!(j1f(2.4881766_f32), 0.49999475_f32); + } + #[test] + fn test_y1f_2002() { + //allow slightly different result on x87 + let res = y1f(2.0000002_f32); + if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && (res == -0.10703231_f32) + { + return; + } + assert_eq!(res, -0.10703229_f32); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/jn.rs b/library/compiler-builtins/libm/libm/src/math/jn.rs new file mode 100644 index 00000000000..31f8d9c5382 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/jn.rs @@ -0,0 +1,339 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * jn(n, x), yn(n, x) + * floating point Bessel's function of the 1st and 2nd kind + * of order n + * + * Special cases: + * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; + * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. + * Note 2. About jn(n,x), yn(n,x) + * For n=0, j0(x) is called, + * for n=1, j1(x) is called, + * for n<=x, forward recursion is used starting + * from values of j0(x) and j1(x). + * for n>x, a continued fraction approximation to + * j(n,x)/j(n-1,x) is evaluated and then backward + * recursion is used starting from a supposed value + * for j(n,x). The resulting value of j(0,x) is + * compared with the actual value to correct the + * supposed value of j(n,x). + * + * yn(n,x) is similar in all respects, except + * that forward recursion is used for all + * values of n>1. + */ + +use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, y1}; + +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ + +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn jn(n: i32, mut x: f64) -> f64 { + let mut ix: u32; + let lx: u32; + let nm1: i32; + let mut i: i32; + let mut sign: bool; + let mut a: f64; + let mut b: f64; + let mut temp: f64; + + ix = get_high_word(x); + lx = get_low_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + // -lx == !lx + 1 + if ix | ((lx | (!lx).wrapping_add(1)) >> 31) > 0x7ff00000 { + /* nan */ + return x; + } + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ + if n == 0 { + return j0(x); + } + if n < 0 { + nm1 = -(n + 1); + x = -x; + sign = !sign; + } else { + nm1 = n - 1; + } + if nm1 == 0 { + return j1(x); + } + + sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabs(x); + if (ix | lx) == 0 || ix == 0x7ff00000 { + /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as f64) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + if ix >= 0x52d00000 { + /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + temp = match nm1 & 3 { + 0 => -cos(x) + sin(x), + 1 => -cos(x) - sin(x), + 2 => cos(x) - sin(x), + // 3 + _ => cos(x) + sin(x), + }; + b = INVSQRTPI * temp / sqrt(x); + } else { + a = j0(x); + b = j1(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b * (2.0 * (i as f64) / x) - a; /* avoid underflow */ + a = temp; + } + } + } else if ix < 0x3e100000 { + /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 32 { + /* underflow */ + b = 0.0; + } else { + temp = x * 0.5; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f64; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f64; + let mut q0: f64; + let mut q1: f64; + let mut w: f64; + let h: f64; + let mut z: f64; + let mut tmp: f64; + let nf: f64; + + let mut k: i32; + + nf = (nm1 as f64) + 1.0; + w = 2.0 * nf / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e9 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as f64) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * log(fabs(w)); + if tmp < 7.09782712893383973096e+02 { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as f64)) / x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as f64)) / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 + if b > x1p500 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0(x); + w = j1(x); + if fabs(z) >= fabs(w) { + b = t * z / b; + } else { + b = t * w / a; + } + } + + if sign { -b } else { b } +} + +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn yn(n: i32, x: f64) -> f64 { + let mut ix: u32; + let lx: u32; + let mut ib: u32; + let nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f64; + let mut b: f64; + let mut temp: f64; + + ix = get_high_word(x); + lx = get_low_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + // -lx == !lx + 1 + if ix | ((lx | (!lx).wrapping_add(1)) >> 31) > 0x7ff00000 { + /* nan */ + return x; + } + if sign && (ix | lx) != 0 { + /* x < 0 */ + return 0.0 / 0.0; + } + if ix == 0x7ff00000 { + return 0.0; + } + + if n == 0 { + return y0(x); + } + if n < 0 { + nm1 = -(n + 1); + sign = (n & 1) != 0; + } else { + nm1 = n - 1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1(x); + } else { + return y1(x); + } + } + + if ix >= 0x52d00000 { + /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + temp = match nm1 & 3 { + 0 => -sin(x) - cos(x), + 1 => -sin(x) + cos(x), + 2 => sin(x) + cos(x), + // 3 + _ => sin(x) - cos(x), + }; + b = INVSQRTPI * temp / sqrt(x); + } else { + a = y0(x); + b = y1(x); + /* quit if b is -inf */ + ib = get_high_word(b); + i = 0; + while i < nm1 && ib != 0xfff00000 { + i += 1; + temp = b; + b = (2.0 * (i as f64) / x) * b - a; + ib = get_high_word(b); + a = temp; + } + } + + if sign { -b } else { b } +} diff --git a/library/compiler-builtins/libm/libm/src/math/jnf.rs b/library/compiler-builtins/libm/libm/src/math/jnf.rs new file mode 100644 index 00000000000..52cf7d8a8bd --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/jnf.rs @@ -0,0 +1,253 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{fabsf, j0f, j1f, logf, y0f, y1f}; + +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn jnf(n: i32, mut x: f32) -> f32 { + let mut ix: u32; + let mut nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f32; + let mut b: f32; + let mut temp: f32; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { + /* nan */ + return x; + } + + /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ + if n == 0 { + return j0f(x); + } + if n < 0 { + nm1 = -(n + 1); + x = -x; + sign = !sign; + } else { + nm1 = n - 1; + } + if nm1 == 0 { + return j1f(x); + } + + sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabsf(x); + if ix == 0 || ix == 0x7f800000 { + /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as f32) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + a = j0f(x); + b = j1f(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b * (2.0 * (i as f32) / x) - a; + a = temp; + } + } else if ix < 0x35800000 { + /* x < 2**-20 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 8 { + /* underflow */ + nm1 = 8; + } + temp = 0.5 * x; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f32; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f32; + let mut q0: f32; + let mut q1: f32; + let mut w: f32; + let h: f32; + let mut z: f32; + let mut tmp: f32; + let nf: f32; + let mut k: i32; + + nf = (nm1 as f32) + 1.0; + w = 2.0 * nf / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e4 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as f32) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * logf(fabsf(w)); + if tmp < 88.721679688 { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as f32) * b / x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as f32) * b / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 + if b > x1p60 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0f(x); + w = j1f(x); + if fabsf(z) >= fabsf(w) { + b = t * z / b; + } else { + b = t * w / a; + } + } + + if sign { -b } else { b } +} + +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ynf(n: i32, x: f32) -> f32 { + let mut ix: u32; + let mut ib: u32; + let nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f32; + let mut b: f32; + let mut temp: f32; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { + /* nan */ + return x; + } + if sign && ix != 0 { + /* x < 0 */ + return 0.0 / 0.0; + } + if ix == 0x7f800000 { + return 0.0; + } + + if n == 0 { + return y0f(x); + } + if n < 0 { + nm1 = -(n + 1); + sign = (n & 1) != 0; + } else { + nm1 = n - 1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1f(x); + } else { + return y1f(x); + } + } + + a = y0f(x); + b = y1f(x); + /* quit if b is -inf */ + ib = b.to_bits(); + i = 0; + while i < nm1 && ib != 0xff800000 { + i += 1; + temp = b; + b = (2.0 * (i as f32) / x) * b - a; + ib = b.to_bits(); + a = temp; + } + + if sign { -b } else { b } +} diff --git a/library/compiler-builtins/libm/libm/src/math/k_cos.rs b/library/compiler-builtins/libm/libm/src/math/k_cos.rs new file mode 100644 index 00000000000..49b2fc64d86 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/k_cos.rs @@ -0,0 +1,62 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_cos.c +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunSoft, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +const C1: f64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ +const C2: f64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ +const C3: f64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ +const C4: f64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ +const C5: f64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ +const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// +// Algorithm +// 1. Since cos(-x) = cos(x), we need only to consider positive x. +// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. +// 3. cos(x) is approximated by a polynomial of degree 14 on +// [0,pi/4] +// 4 14 +// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x +// where the remez error is +// +// | 2 4 6 8 10 12 14 | -58 +// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 +// | | +// +// 4 6 8 10 12 14 +// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then +// cos(x) ~ 1 - x*x/2 + r +// since cos(x+y) ~ cos(x) - sin(x)*y +// ~ cos(x) - x*y, +// a correction term is necessary in cos(x) and hence +// cos(x+y) = 1 - (x*x/2 - (r - x*y)) +// For better accuracy, rearrange to +// cos(x+y) ~ w + (tmp + (r-x*y)) +// where w = 1 - x*x/2 and tmp is a tiny correction term +// (1 - x*x/2 == w + tmp exactly in infinite precision). +// The exactness of w + tmp in infinite precision depends on w +// and tmp having the same precision as x. If they have extra +// precision due to compiler bugs, then the extra precision is +// only good provided it is retained in all terms of the final +// expression for cos(). Retention happens in all cases tested +// under FreeBSD, so don't pessimize things by forcibly clipping +// any extra precision in w. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_cos(x: f64, y: f64) -> f64 { + let z = x * x; + let w = z * z; + let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); + let hz = 0.5 * z; + let w = 1.0 - hz; + w + (((1.0 - w) - hz) + (z * r - x * y)) +} diff --git a/library/compiler-builtins/libm/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/libm/src/math/k_cosf.rs new file mode 100644 index 00000000000..e99f2348c00 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/k_cosf.rs @@ -0,0 +1,29 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +const C0: f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ +const C1: f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ +const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ +const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_cosf(x: f64) -> f32 { + let z = x * x; + let w = z * z; + let r = C2 + z * C3; + (((1.0 + z * C0) + w * C1) + (w * z) * r) as f32 +} diff --git a/library/compiler-builtins/libm/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/libm/src/math/k_expo2.rs new file mode 100644 index 00000000000..7345075f376 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/k_expo2.rs @@ -0,0 +1,14 @@ +use super::exp; + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +const K: i32 = 2043; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_expo2(x: f64) -> f64 { + let k_ln2 = f64::from_bits(0x40962066151add8b); + /* note that k is odd and scale*scale overflows */ + let scale = f64::from_bits(((((0x3ff + K / 2) as u32) << 20) as u64) << 32); + /* exp(x - k ln2) * 2**(k-1) */ + exp(x - k_ln2) * scale * scale +} diff --git a/library/compiler-builtins/libm/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/libm/src/math/k_expo2f.rs new file mode 100644 index 00000000000..fbd7b27d583 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/k_expo2f.rs @@ -0,0 +1,14 @@ +use super::expf; + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +const K: i32 = 235; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_expo2f(x: f32) -> f32 { + let k_ln2 = f32::from_bits(0x4322e3bc); + /* note that k is odd and scale*scale overflows */ + let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); + /* exp(x - k ln2) * 2**(k-1) */ + expf(x - k_ln2) * scale * scale +} diff --git a/library/compiler-builtins/libm/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/libm/src/math/k_sin.rs new file mode 100644 index 00000000000..42441455ff3 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/k_sin.rs @@ -0,0 +1,53 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_sin.c +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunSoft, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +const S1: f64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ +const S2: f64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ +const S3: f64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ +const S4: f64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ +const S5: f64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ +const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// Input iy indicates whether y is 0. (if iy=0, y assume to be 0). +// +// Algorithm +// 1. Since sin(-x) = -sin(x), we need only to consider positive x. +// 2. Callers must return sin(-0) = -0 without calling here since our +// odd polynomial is not evaluated in a way that preserves -0. +// Callers may do the optimization sin(x) ~ x for tiny x. +// 3. sin(x) is approximated by a polynomial of degree 13 on +// [0,pi/4] +// 3 13 +// sin(x) ~ x + S1*x + ... + S6*x +// where +// +// |sin(x) 2 4 6 8 10 12 | -58 +// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 +// | x | +// +// 4. sin(x+y) = sin(x) + sin'(x')*y +// ~ sin(x) + (1-x*x/2)*y +// For better accuracy, let +// 3 2 2 2 2 +// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) +// then 3 2 +// sin(x) = x + (S1*x + (x *(r-y/2)+y)) +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { + let z = x * x; + let w = z * z; + let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); + let v = z * x; + if iy == 0 { x + v * (S1 + z * r) } else { x - ((z * (0.5 * y - v * r) - y) - v * S1) } +} diff --git a/library/compiler-builtins/libm/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/libm/src/math/k_sinf.rs new file mode 100644 index 00000000000..88d10cababc --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/k_sinf.rs @@ -0,0 +1,30 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +const S1: f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ +const S2: f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ +const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ +const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_sinf(x: f64) -> f32 { + let z = x * x; + let w = z * z; + let r = S3 + z * S4; + let s = z * x; + ((x + s * (S1 + z * S2)) + s * w * r) as f32 +} diff --git a/library/compiler-builtins/libm/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/libm/src/math/k_tan.rs new file mode 100644 index 00000000000..d177010bb0a --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/k_tan.rs @@ -0,0 +1,105 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ +// +// ==================================================== +// Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. +// +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +// kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. +// +// Algorithm +// 1. Since tan(-x) = -tan(x), we need only to consider positive x. +// 2. Callers must return tan(-0) = -0 without calling here since our +// odd polynomial is not evaluated in a way that preserves -0. +// Callers may do the optimization tan(x) ~ x for tiny x. +// 3. tan(x) is approximated by a odd polynomial of degree 27 on +// [0,0.67434] +// 3 27 +// tan(x) ~ x + T1*x + ... + T13*x +// where +// +// |tan(x) 2 4 26 | -59.2 +// |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 +// | x | +// +// Note: tan(x+y) = tan(x) + tan'(x)*y +// ~ tan(x) + (1+x*x)*y +// Therefore, for better accuracy in computing tan(x+y), let +// 3 2 2 2 2 +// r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) +// then +// 3 2 +// tan(x+y) = x + (T1*x + (x *(r+y)+y)) +// +// 4. For x in [0.67434,pi/4], let y = pi/4 - x, then +// tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) +// = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) +static T: [f64; 13] = [ + 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ + 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ + 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ + 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ + 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ + 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ + 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ + 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ + 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ + 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ + 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ + -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ + 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ +]; +const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ +const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { + let hx = (f64::to_bits(x) >> 32) as u32; + let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ + if big { + let sign = hx >> 31; + if sign != 0 { + x = -x; + y = -y; + } + x = (PIO4 - x) + (PIO4_LO - y); + y = 0.0; + } + let z = x * x; + let w = z * z; + /* + * Break x^5*(T[1]+x^2*T[2]+...) into + * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + + * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) + */ + let r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11])))); + let v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12]))))); + let s = z * x; + let r = y + z * (s * (r + v) + y) + s * T[0]; + let w = x + r; + if big { + let sign = hx >> 31; + let s = 1.0 - 2.0 * odd as f64; + let v = s - 2.0 * (x + (r - w * w / (w + s))); + return if sign != 0 { -v } else { v }; + } + if odd == 0 { + return w; + } + /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */ + let w0 = zero_low_word(w); + let v = r - (w0 - x); /* w0+v = r+x */ + let a = -1.0 / w; + let a0 = zero_low_word(a); + a0 + a * (1.0 + a0 * w0 + a0 * v) +} + +fn zero_low_word(x: f64) -> f64 { + f64::from_bits(f64::to_bits(x) & 0xFFFF_FFFF_0000_0000) +} diff --git a/library/compiler-builtins/libm/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/libm/src/math/k_tanf.rs new file mode 100644 index 00000000000..af8db539dad --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/k_tanf.rs @@ -0,0 +1,46 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ +const T: [f64; 6] = [ + 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ + 0.133392002712976742718, /* 0x1112fd38999f72.0p-55 */ + 0.0533812378445670393523, /* 0x1b54c91d865afe.0p-57 */ + 0.0245283181166547278873, /* 0x191df3908c33ce.0p-58 */ + 0.00297435743359967304927, /* 0x185dadfcecf44e.0p-61 */ + 0.00946564784943673166728, /* 0x1362b9bf971bcd.0p-59 */ +]; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { + let z = x * x; + /* + * Split up the polynomial into small independent terms to give + * opportunities for parallel evaluation. The chosen splitting is + * micro-optimized for Athlons (XP, X64). It costs 2 multiplications + * relative to Horner's method on sequential machines. + * + * We add the small terms from lowest degree up for efficiency on + * non-sequential machines (the lowest degree terms tend to be ready + * earlier). Apart from this, we don't care about order of + * operations, and don't need to to care since we have precision to + * spare. However, the chosen splitting is good for accuracy too, + * and would give results as accurate as Horner's method if the + * small terms were added from highest degree down. + */ + let mut r = T[4] + z * T[5]; + let t = T[2] + z * T[3]; + let w = z * z; + let s = z * x; + let u = T[0] + z * T[1]; + r = (x + s * u) + (s * w) * (t + w * r); + (if odd { -1. / r } else { r }) as f32 +} diff --git a/library/compiler-builtins/libm/libm/src/math/ldexp.rs b/library/compiler-builtins/libm/libm/src/math/ldexp.rs new file mode 100644 index 00000000000..24899ba306a --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/ldexp.rs @@ -0,0 +1,21 @@ +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf16(x: f16, n: i32) -> f16 { + super::scalbnf16(x, n) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf(x: f32, n: i32) -> f32 { + super::scalbnf(x, n) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexp(x: f64, n: i32) -> f64 { + super::scalbn(x, n) +} + +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf128(x: f128, n: i32) -> f128 { + super::scalbnf128(x, n) +} diff --git a/library/compiler-builtins/libm/libm/src/math/ldexpf.rs b/library/compiler-builtins/libm/libm/src/math/ldexpf.rs new file mode 100644 index 00000000000..95b27fc49d2 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/ldexpf.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf(x: f32, n: i32) -> f32 { + super::scalbnf(x, n) +} diff --git a/library/compiler-builtins/libm/libm/src/math/ldexpf128.rs b/library/compiler-builtins/libm/libm/src/math/ldexpf128.rs new file mode 100644 index 00000000000..b35277d15fb --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/ldexpf128.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf128(x: f128, n: i32) -> f128 { + super::scalbnf128(x, n) +} diff --git a/library/compiler-builtins/libm/libm/src/math/ldexpf16.rs b/library/compiler-builtins/libm/libm/src/math/ldexpf16.rs new file mode 100644 index 00000000000..8de6cffd699 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/ldexpf16.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf16(x: f16, n: i32) -> f16 { + super::scalbnf16(x, n) +} diff --git a/library/compiler-builtins/libm/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/libm/src/math/lgamma.rs new file mode 100644 index 00000000000..8312dc18648 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/lgamma.rs @@ -0,0 +1,8 @@ +use super::lgamma_r; + +/// The natural logarithm of the +/// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn lgamma(x: f64) -> f64 { + lgamma_r(x).0 +} diff --git a/library/compiler-builtins/libm/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/libm/src/math/lgamma_r.rs new file mode 100644 index 00000000000..6becaad2ce9 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/lgamma_r.rs @@ -0,0 +1,321 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = PI/sin(PI*x), + * we have + * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(PI*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); + * Note: one should avoid compute PI*(-x) directly in the + * computation of sin(PI*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +use super::{floor, k_cos, k_sin, log}; + +const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ +const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ +const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ +const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ +const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ +const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ +const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ +const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ +const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ +const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ +const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ +const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ +const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ +const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ +const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of TF) */ +const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ +const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ +const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ +const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ +const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ +const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ +const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ +const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ +const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ +const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ +const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ +const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ +const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ +const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ +const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ +const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ +const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ +const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ +const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ +const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ +const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ +const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ +const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ +const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ +const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ +const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ +const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ +const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ +const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ +const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ +const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ +const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ +const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ +const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ +const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ +const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ +const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ +const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ +const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ +const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ +const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ +const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ +const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ +const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ +const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f64) -> f64 { + let mut n: i32; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ + + n = (x * 4.0) as i32; + n = div!(n + 1, 2); + x -= (n as f64) * 0.5; + x *= PI; + + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + // 0 + _ => k_sin(x, 0.0, 0), + } +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn lgamma_r(mut x: f64) -> (f64, i32) { + let u: u64 = x.to_bits(); + let mut t: f64; + let y: f64; + let mut z: f64; + let nadj: f64; + let p: f64; + let p1: f64; + let p2: f64; + let p3: f64; + let q: f64; + let mut r: f64; + let w: f64; + let ix: u32; + let sign: bool; + let i: i32; + let mut signgam: i32; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u >> 63) != 0; + ix = ((u >> 32) as u32) & 0x7fffffff; + if ix >= 0x7ff00000 { + return (x * x, signgam); + } + if ix < (0x3ff - 70) << 20 { + /* |x|<2**-70, return -log(|x|) */ + if sign { + x = -x; + signgam = -1; + } + return (-log(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { + /* -integer */ + return (1.0 / (x - x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = log(PI / (t * x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3feccccc { + /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -log(x); + if ix >= 0x3FE76944 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3FCDA661 { + y = x - (TC - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3FFBB4C3 { + /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3FF3B4C4 { + /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y * y; + p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); + p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); + p = y * p1 + p2; + r += p - 0.5 * y; + } + 1 => { + z = y * y; + w = z * y; + p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ + p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); + p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); + p = z * p1 - (TT - w * (p2 + y * p3)); + r += TF + p; + } + 2 => { + p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); + p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); + r += -0.5 * y + p1 / p2; + } + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => {} + } + } else if ix < 0x40200000 { + /* x < 8.0 */ + i = x as i32; + y = x - (i as f64); + p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); + q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { + z *= y + 6.0; + } + if i >= 6 { + z *= y + 5.0; + } + if i >= 5 { + z *= y + 4.0; + } + if i >= 4 { + z *= y + 3.0; + } + if i >= 3 { + z *= y + 2.0; + r += log(z); + } + } else if ix < 0x43900000 { + /* 8.0 <= x < 2**58 */ + t = log(x); + z = 1.0 / x; + y = z * z; + w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else { + /* 2**58 <= x <= inf */ + r = x * (log(x) - 1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/libm/src/math/lgammaf.rs new file mode 100644 index 00000000000..d37512397cb --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/lgammaf.rs @@ -0,0 +1,8 @@ +use super::lgammaf_r; + +/// The natural logarithm of the +/// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn lgammaf(x: f32) -> f32 { + lgammaf_r(x).0 +} diff --git a/library/compiler-builtins/libm/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/libm/src/math/lgammaf_r.rs new file mode 100644 index 00000000000..10cecee541c --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/lgammaf_r.rs @@ -0,0 +1,256 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{floorf, k_cosf, k_sinf, logf}; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ +const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ +const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ +const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ +const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ +const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ +const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ +const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ +const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ +const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ +const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ +const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ +const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ +const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ +/* TT = -(tail of TF) */ +const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ +const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ +const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ +const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ +const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ +const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ +const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ +const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ +const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ +const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ +const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ +const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ +const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ +const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ +const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ +const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ +const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ +const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ +const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ +const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ +const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ +const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ +const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ +const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ +const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ +const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ +const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ +const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ +const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ +const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ +const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ +const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ +const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ +const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ +const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ +const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ +const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ +const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ +const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ +const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ +const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ +const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ +const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ +const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f32) -> f32 { + let mut y: f64; + let mut n: isize; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ + + n = (x * 4.0) as isize; + n = div!(n + 1, 2); + y = (x as f64) - (n as f64) * 0.5; + y *= 3.14159265358979323846; + match n { + 1 => k_cosf(y), + 2 => k_sinf(-y), + 3 => -k_cosf(y), + // 0 + _ => k_sinf(y), + } +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn lgammaf_r(mut x: f32) -> (f32, i32) { + let u = x.to_bits(); + let mut t: f32; + let y: f32; + let mut z: f32; + let nadj: f32; + let p: f32; + let p1: f32; + let p2: f32; + let p3: f32; + let q: f32; + let mut r: f32; + let w: f32; + let ix: u32; + let i: i32; + let sign: bool; + let mut signgam: i32; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u >> 31) != 0; + ix = u & 0x7fffffff; + if ix >= 0x7f800000 { + return (x * x, signgam); + } + if ix < 0x35000000 { + /* |x| < 2**-21, return -log(|x|) */ + if sign { + signgam = -1; + x = -x; + } + return (-logf(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { + /* -integer */ + return (1.0 / (x - x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = logf(PI / (t * x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if ix == 0x3f800000 || ix == 0x40000000 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3f666666 { + /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -logf(x); + if ix >= 0x3f3b4a20 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3e6d3308 { + y = x - (TC - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3fdda618 { + /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3F9da620 { + /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y * y; + p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); + p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); + p = y * p1 + p2; + r += p - 0.5 * y; + } + 1 => { + z = y * y; + w = z * y; + p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ + p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); + p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); + p = z * p1 - (TT - w * (p2 + y * p3)); + r += TF + p; + } + 2 => { + p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); + p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); + r += -0.5 * y + p1 / p2; + } + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => {} + } + } else if ix < 0x41000000 { + /* x < 8.0 */ + i = x as i32; + y = x - (i as f32); + p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); + q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { + z *= y + 6.0; + } + if i >= 6 { + z *= y + 5.0; + } + if i >= 5 { + z *= y + 4.0; + } + if i >= 4 { + z *= y + 3.0; + } + if i >= 3 { + z *= y + 2.0; + r += logf(z); + } + } else if ix < 0x5c800000 { + /* 8.0 <= x < 2**58 */ + t = logf(x); + z = 1.0 / x; + y = z * z; + w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else { + /* 2**58 <= x <= inf */ + r = x * (logf(x) - 1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/libm/src/math/log.rs b/library/compiler-builtins/libm/libm/src/math/log.rs new file mode 100644 index 00000000000..f2dc47ec5cc --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/log.rs @@ -0,0 +1,118 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* log(x) + * Return the logarithm of x + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Remez algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +/// The natural logarithm of `x` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui = x.to_bits(); + let mut hx: u32 = (ui >> 32) as u32; + let mut k: i32 = 0; + + if (hx < 0x00100000) || ((hx >> 31) != 0) { + /* x < 2**-126 */ + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if hx >> 31 != 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += ((hx >> 20) as i32) - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = ((hx as u64) << 32) | (ui & 0xffffffff); + x = f64::from_bits(ui); + + let f: f64 = x - 1.0; + let hfsq: f64 = 0.5 * f * f; + let s: f64 = f / (2.0 + f); + let z: f64 = s * s; + let w: f64 = z * z; + let t1: f64 = w * (LG2 + w * (LG4 + w * LG6)); + let t2: f64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + let r: f64 = t2 + t1; + let dk: f64 = k as f64; + s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI +} diff --git a/library/compiler-builtins/libm/libm/src/math/log10.rs b/library/compiler-builtins/libm/libm/src/math/log10.rs new file mode 100644 index 00000000000..8c9d68c492d --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/log10.rs @@ -0,0 +1,118 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 10 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) + */ + +use core::f64; + +const IVLN10HI: f64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ +const IVLN10LO: f64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ +const LOG10_2HI: f64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ +const LOG10_2LO: f64 = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +/// The base 10 logarithm of `x` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log10(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let f: f64; + let s: f64; + let z: f64; + let r: f64; + let mut w: f64; + let t1: f64; + let t2: f64; + let dk: f64; + let y: f64; + let mut hi: f64; + let lo: f64; + let mut val_hi: f64; + let mut val_lo: f64; + let mut hx: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 0; + if hx < 0x00100000 || (hx >> 31) > 0 { + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (hx >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (hx >> 20) as i32 - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = ((hx as u64) << 32) | (ui & 0xffffffff); + x = f64::from_bits(ui); + + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + + /* See log2.c for details. */ + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + ui = hi.to_bits(); + ui &= (-1i64 as u64) << 32; + hi = f64::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + + /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ + val_hi = hi * IVLN10HI; + dk = k as f64; + y = dk * LOG10_2HI; + val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI; + + /* + * Extra precision in for adding y is not strictly needed + * since there is no very large cancellation near x = sqrt(2) or + * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs + * with some parallelism and it reduces the error for many args. + */ + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + val_lo + val_hi +} diff --git a/library/compiler-builtins/libm/libm/src/math/log10f.rs b/library/compiler-builtins/libm/libm/src/math/log10f.rs new file mode 100644 index 00000000000..18bf8fcc832 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/log10f.rs @@ -0,0 +1,92 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log10.c. + */ + +use core::f32; + +const IVLN10HI: f32 = 4.3432617188e-01; /* 0x3ede6000 */ +const IVLN10LO: f32 = -3.1689971365e-05; /* 0xb804ead9 */ +const LOG10_2HI: f32 = 3.0102920532e-01; /* 0x3e9a2080 */ +const LOG10_2LO: f32 = 7.9034151668e-07; /* 0x355427db */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +/// The base 10 logarithm of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log10f(mut x: f32) -> f32 { + let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 + + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let f: f32; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let dk: f32; + let mut hi: f32; + let lo: f32; + let mut ix: u32; + let mut k: i32; + + ix = ui; + k = 0; + if ix < 0x00800000 || (ix >> 31) > 0 { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (ix >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25f; + ui = x.to_bits(); + ix = ui; + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (ix >> 23) as i32 - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + ui = ix; + x = f32::from_bits(ui); + + f = x - 1.0; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + + hi = f - hfsq; + ui = hi.to_bits(); + ui &= 0xfffff000; + hi = f32::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + dk = k as f32; + dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI +} diff --git a/library/compiler-builtins/libm/libm/src/math/log1p.rs b/library/compiler-builtins/libm/libm/src/math/log1p.rs new file mode 100644 index 00000000000..b7f3fb09e15 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/log1p.rs @@ -0,0 +1,140 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double log1p(double x) + * Return the natural logarithm of 1+x. + * + * Method : + * 1. Argument Reduction: find k and f such that + * 1+x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * Note. If k=0, then f=x is exact. However, if k!=0, then f + * may not be representable exactly. In that case, a correction + * term is need. Let u=1+x rounded. Let c = (1+x)-u, then + * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), + * and add back the correction term c/u. + * (Note: when x > 2**53, one can simply return log(x)) + * + * 2. Approximation of log(1+f): See log.c + * + * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c + * + * Special cases: + * log1p(x) is NaN with signal if x < -1 (including -INF) ; + * log1p(+INF) is +INF; log1p(-1) is -INF with signal; + * log1p(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + * + * Note: Assuming log() return accurate answer, the following + * algorithm can be used to compute log1p(x) to within a few ULP: + * + * u = 1+x; + * if(u==1.0) return x ; else + * return log(u)*(x/(u-1.0)); + * + * See HP-15C Advanced Functions Handbook, p.193. + */ + +use core::f64; + +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +/// The natural logarithm of 1+`x` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log1p(x: f64) -> f64 { + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let mut f: f64 = 0.; + let mut c: f64 = 0.; + let s: f64; + let z: f64; + let r: f64; + let w: f64; + let t1: f64; + let t2: f64; + let dk: f64; + let hx: u32; + let mut hu: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 1; + if hx < 0x3fda827a || (hx >> 31) > 0 { + /* 1+x < sqrt(2)+ */ + if hx >= 0xbff00000 { + /* x <= -1.0 */ + if x == -1. { + return x / 0.0; /* log1p(-1) = -inf */ + } + return (x - x) / 0.0; /* log1p(x<-1) = NaN */ + } + if hx << 1 < 0x3ca00000 << 1 { + /* |x| < 2**-53 */ + /* underflow if subnormal */ + if (hx & 0x7ff00000) == 0 { + force_eval!(x as f32); + } + return x; + } + if hx <= 0xbfd2bec4 { + /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0.; + f = x; + } + } else if hx >= 0x7ff00000 { + return x; + } + if k > 0 { + ui = (1. + x).to_bits(); + hu = (ui >> 32) as u32; + hu += 0x3ff00000 - 0x3fe6a09e; + k = (hu >> 20) as i32 - 0x3ff; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if k < 54 { + c = if k >= 2 { 1. - (f64::from_bits(ui) - x) } else { x - (f64::from_bits(ui) - 1.) }; + c /= f64::from_bits(ui); + } else { + c = 0.; + } + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + hu = (hu & 0x000fffff) + 0x3fe6a09e; + ui = ((hu as u64) << 32) | (ui & 0xffffffff); + f = f64::from_bits(ui) - 1.; + } + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + dk = k as f64; + s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI +} diff --git a/library/compiler-builtins/libm/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/libm/src/math/log1pf.rs new file mode 100644 index 00000000000..bba5b8a2f21 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/log1pf.rs @@ -0,0 +1,95 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f32; + +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +/// The natural logarithm of 1+`x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log1pf(x: f32) -> f32 { + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let mut f: f32 = 0.; + let mut c: f32 = 0.; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let dk: f32; + let ix: u32; + let mut iu: u32; + let mut k: i32; + + ix = ui; + k = 1; + if ix < 0x3ed413d0 || (ix >> 31) > 0 { + /* 1+x < sqrt(2)+ */ + if ix >= 0xbf800000 { + /* x <= -1.0 */ + if x == -1. { + return x / 0.0; /* log1p(-1)=+inf */ + } + return (x - x) / 0.0; /* log1p(x<-1)=NaN */ + } + if ix << 1 < 0x33800000 << 1 { + /* |x| < 2**-24 */ + /* underflow if subnormal */ + if (ix & 0x7f800000) == 0 { + force_eval!(x * x); + } + return x; + } + if ix <= 0xbe95f619 { + /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0.; + f = x; + } + } else if ix >= 0x7f800000 { + return x; + } + if k > 0 { + ui = (1. + x).to_bits(); + iu = ui; + iu += 0x3f800000 - 0x3f3504f3; + k = (iu >> 23) as i32 - 0x7f; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if k < 25 { + c = if k >= 2 { 1. - (f32::from_bits(ui) - x) } else { x - (f32::from_bits(ui) - 1.) }; + c /= f32::from_bits(ui); + } else { + c = 0.; + } + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + iu = (iu & 0x007fffff) + 0x3f3504f3; + ui = iu; + f = f32::from_bits(ui) - 1.; + } + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + dk = k as f32; + s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI +} diff --git a/library/compiler-builtins/libm/libm/src/math/log2.rs b/library/compiler-builtins/libm/libm/src/math/log2.rs new file mode 100644 index 00000000000..701f63c25e7 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/log2.rs @@ -0,0 +1,107 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 2 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log2(x) = (f - f*f/2 + r)/log(2) + k + */ + +use core::f64; + +const IVLN2HI: f64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ +const IVLN2LO: f64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +/// The base 2 logarithm of `x` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log2(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let f: f64; + let s: f64; + let z: f64; + let r: f64; + let mut w: f64; + let t1: f64; + let t2: f64; + let y: f64; + let mut hi: f64; + let lo: f64; + let mut val_hi: f64; + let mut val_lo: f64; + let mut hx: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 0; + if hx < 0x00100000 || (hx >> 31) > 0 { + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (hx >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (hx >> 20) as i32 - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = ((hx as u64) << 32) | (ui & 0xffffffff); + x = f64::from_bits(ui); + + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + ui = hi.to_bits(); + ui &= (-1i64 as u64) << 32; + hi = f64::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + + val_hi = hi * IVLN2HI; + val_lo = (lo + hi) * IVLN2LO + lo * IVLN2HI; + + /* spadd(val_hi, val_lo, y), except for not using double_t: */ + y = k.into(); + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + val_lo + val_hi +} diff --git a/library/compiler-builtins/libm/libm/src/math/log2f.rs b/library/compiler-builtins/libm/libm/src/math/log2f.rs new file mode 100644 index 00000000000..5ba2427d1d4 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/log2f.rs @@ -0,0 +1,88 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log2.c. + */ + +use core::f32; + +const IVLN2HI: f32 = 1.4428710938e+00; /* 0x3fb8b000 */ +const IVLN2LO: f32 = -1.7605285393e-04; /* 0xb9389ad4 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +/// The base 2 logarithm of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log2f(mut x: f32) -> f32 { + let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 + + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let f: f32; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let mut hi: f32; + let lo: f32; + let mut ix: u32; + let mut k: i32; + + ix = ui; + k = 0; + if ix < 0x00800000 || (ix >> 31) > 0 { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (ix >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25f; + ui = x.to_bits(); + ix = ui; + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (ix >> 23) as i32 - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + ui = ix; + x = f32::from_bits(ui); + + f = x - 1.0; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + + hi = f - hfsq; + ui = hi.to_bits(); + ui &= 0xfffff000; + hi = f32::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as f32 +} diff --git a/library/compiler-builtins/libm/libm/src/math/logf.rs b/library/compiler-builtins/libm/libm/src/math/logf.rs new file mode 100644 index 00000000000..68d1943025e --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/logf.rs @@ -0,0 +1,66 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +/// The natural logarithm of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn logf(mut x: f32) -> f32 { + let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 + + let mut ix = x.to_bits(); + let mut k = 0i32; + + if (ix < 0x00800000) || ((ix >> 31) != 0) { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (ix >> 31) != 0 { + return (x - x) / 0.; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25; + ix = x.to_bits(); + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += ((ix >> 23) as i32) - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + x = f32::from_bits(ix); + + let f = x - 1.; + let s = f / (2. + f); + let z = s * s; + let w = z * z; + let t1 = w * (LG2 + w * LG4); + let t2 = z * (LG1 + w * LG3); + let r = t2 + t1; + let hfsq = 0.5 * f * f; + let dk = k as f32; + s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI +} diff --git a/library/compiler-builtins/libm/libm/src/math/mod.rs b/library/compiler-builtins/libm/libm/src/math/mod.rs new file mode 100644 index 00000000000..949c18b4000 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/mod.rs @@ -0,0 +1,396 @@ +macro_rules! force_eval { + ($e:expr) => { + unsafe { ::core::ptr::read_volatile(&$e) } + }; +} + +#[cfg(not(debug_assertions))] +macro_rules! i { + ($array:expr, $index:expr) => { + unsafe { *$array.get_unchecked($index) } + }; + ($array:expr, $index:expr, = , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) = $rhs; + } + }; + ($array:expr, $index:expr, += , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) += $rhs; + } + }; + ($array:expr, $index:expr, -= , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) -= $rhs; + } + }; + ($array:expr, $index:expr, &= , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) &= $rhs; + } + }; + ($array:expr, $index:expr, == , $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) == $rhs } + }; +} + +#[cfg(debug_assertions)] +macro_rules! i { + ($array:expr, $index:expr) => { + *$array.get($index).unwrap() + }; + ($array:expr, $index:expr, = , $rhs:expr) => { + *$array.get_mut($index).unwrap() = $rhs; + }; + ($array:expr, $index:expr, -= , $rhs:expr) => { + *$array.get_mut($index).unwrap() -= $rhs; + }; + ($array:expr, $index:expr, += , $rhs:expr) => { + *$array.get_mut($index).unwrap() += $rhs; + }; + ($array:expr, $index:expr, &= , $rhs:expr) => { + *$array.get_mut($index).unwrap() &= $rhs; + }; + ($array:expr, $index:expr, == , $rhs:expr) => { + *$array.get_mut($index).unwrap() == $rhs + }; +} + +// Temporary macro to avoid panic codegen for division (in debug mode too). At +// the time of this writing this is only used in a few places, and once +// rust-lang/rust#72751 is fixed then this macro will no longer be necessary and +// the native `/` operator can be used and panics won't be codegen'd. +#[cfg(any(debug_assertions, not(intrinsics_enabled)))] +macro_rules! div { + ($a:expr, $b:expr) => { + $a / $b + }; +} + +#[cfg(all(not(debug_assertions), intrinsics_enabled))] +macro_rules! div { + ($a:expr, $b:expr) => { + unsafe { core::intrinsics::unchecked_div($a, $b) } + }; +} + +// `support` may be public for testing +#[macro_use] +#[cfg(feature = "unstable-public-internals")] +pub mod support; + +#[macro_use] +#[cfg(not(feature = "unstable-public-internals"))] +pub(crate) mod support; + +cfg_if! { + if #[cfg(feature = "unstable-public-internals")] { + pub mod generic; + } else { + mod generic; + } +} + +// Private modules +mod arch; +mod expo2; +mod k_cos; +mod k_cosf; +mod k_expo2; +mod k_expo2f; +mod k_sin; +mod k_sinf; +mod k_tan; +mod k_tanf; +mod rem_pio2; +mod rem_pio2_large; +mod rem_pio2f; + +// Private re-imports +use self::expo2::expo2; +use self::k_cos::k_cos; +use self::k_cosf::k_cosf; +use self::k_expo2::k_expo2; +use self::k_expo2f::k_expo2f; +use self::k_sin::k_sin; +use self::k_sinf::k_sinf; +use self::k_tan::k_tan; +use self::k_tanf::k_tanf; +use self::rem_pio2::rem_pio2; +use self::rem_pio2_large::rem_pio2_large; +use self::rem_pio2f::rem_pio2f; +#[allow(unused_imports)] +use self::support::{CastFrom, CastInto, DFloat, DInt, Float, HFloat, HInt, Int, IntTy, MinInt}; + +// Public modules +mod acos; +mod acosf; +mod acosh; +mod acoshf; +mod asin; +mod asinf; +mod asinh; +mod asinhf; +mod atan; +mod atan2; +mod atan2f; +mod atanf; +mod atanh; +mod atanhf; +mod cbrt; +mod cbrtf; +mod ceil; +mod copysign; +mod cos; +mod cosf; +mod cosh; +mod coshf; +mod erf; +mod erff; +mod exp; +mod exp10; +mod exp10f; +mod exp2; +mod exp2f; +mod expf; +mod expm1; +mod expm1f; +mod fabs; +mod fdim; +mod floor; +mod fma; +mod fma_wide; +mod fmin_fmax; +mod fminimum_fmaximum; +mod fminimum_fmaximum_num; +mod fmod; +mod frexp; +mod frexpf; +mod hypot; +mod hypotf; +mod ilogb; +mod ilogbf; +mod j0; +mod j0f; +mod j1; +mod j1f; +mod jn; +mod jnf; +mod ldexp; +mod lgamma; +mod lgamma_r; +mod lgammaf; +mod lgammaf_r; +mod log; +mod log10; +mod log10f; +mod log1p; +mod log1pf; +mod log2; +mod log2f; +mod logf; +mod modf; +mod modff; +mod nextafter; +mod nextafterf; +mod pow; +mod powf; +mod remainder; +mod remainderf; +mod remquo; +mod remquof; +mod rint; +mod round; +mod roundeven; +mod scalbn; +mod sin; +mod sincos; +mod sincosf; +mod sinf; +mod sinh; +mod sinhf; +mod sqrt; +mod tan; +mod tanf; +mod tanh; +mod tanhf; +mod tgamma; +mod tgammaf; +mod trunc; + +// Use separated imports instead of {}-grouped imports for easier merging. +pub use self::acos::acos; +pub use self::acosf::acosf; +pub use self::acosh::acosh; +pub use self::acoshf::acoshf; +pub use self::asin::asin; +pub use self::asinf::asinf; +pub use self::asinh::asinh; +pub use self::asinhf::asinhf; +pub use self::atan::atan; +pub use self::atan2::atan2; +pub use self::atan2f::atan2f; +pub use self::atanf::atanf; +pub use self::atanh::atanh; +pub use self::atanhf::atanhf; +pub use self::cbrt::cbrt; +pub use self::cbrtf::cbrtf; +pub use self::ceil::{ceil, ceilf}; +pub use self::copysign::{copysign, copysignf}; +pub use self::cos::cos; +pub use self::cosf::cosf; +pub use self::cosh::cosh; +pub use self::coshf::coshf; +pub use self::erf::{erf, erfc}; +pub use self::erff::{erfcf, erff}; +pub use self::exp::exp; +pub use self::exp2::exp2; +pub use self::exp2f::exp2f; +pub use self::exp10::exp10; +pub use self::exp10f::exp10f; +pub use self::expf::expf; +pub use self::expm1::expm1; +pub use self::expm1f::expm1f; +pub use self::fabs::{fabs, fabsf}; +pub use self::fdim::{fdim, fdimf}; +pub use self::floor::{floor, floorf}; +pub use self::fma::fma; +pub use self::fma_wide::fmaf; +pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; +pub use self::fminimum_fmaximum::{fmaximum, fmaximumf, fminimum, fminimumf}; +pub use self::fminimum_fmaximum_num::{fmaximum_num, fmaximum_numf, fminimum_num, fminimum_numf}; +pub use self::fmod::{fmod, fmodf}; +pub use self::frexp::frexp; +pub use self::frexpf::frexpf; +pub use self::hypot::hypot; +pub use self::hypotf::hypotf; +pub use self::ilogb::ilogb; +pub use self::ilogbf::ilogbf; +pub use self::j0::{j0, y0}; +pub use self::j0f::{j0f, y0f}; +pub use self::j1::{j1, y1}; +pub use self::j1f::{j1f, y1f}; +pub use self::jn::{jn, yn}; +pub use self::jnf::{jnf, ynf}; +pub use self::ldexp::{ldexp, ldexpf}; +pub use self::lgamma::lgamma; +pub use self::lgamma_r::lgamma_r; +pub use self::lgammaf::lgammaf; +pub use self::lgammaf_r::lgammaf_r; +pub use self::log::log; +pub use self::log1p::log1p; +pub use self::log1pf::log1pf; +pub use self::log2::log2; +pub use self::log2f::log2f; +pub use self::log10::log10; +pub use self::log10f::log10f; +pub use self::logf::logf; +pub use self::modf::modf; +pub use self::modff::modff; +pub use self::nextafter::nextafter; +pub use self::nextafterf::nextafterf; +pub use self::pow::pow; +pub use self::powf::powf; +pub use self::remainder::remainder; +pub use self::remainderf::remainderf; +pub use self::remquo::remquo; +pub use self::remquof::remquof; +pub use self::rint::{rint, rintf}; +pub use self::round::{round, roundf}; +pub use self::roundeven::{roundeven, roundevenf}; +pub use self::scalbn::{scalbn, scalbnf}; +pub use self::sin::sin; +pub use self::sincos::sincos; +pub use self::sincosf::sincosf; +pub use self::sinf::sinf; +pub use self::sinh::sinh; +pub use self::sinhf::sinhf; +pub use self::sqrt::{sqrt, sqrtf}; +pub use self::tan::tan; +pub use self::tanf::tanf; +pub use self::tanh::tanh; +pub use self::tanhf::tanhf; +pub use self::tgamma::tgamma; +pub use self::tgammaf::tgammaf; +pub use self::trunc::{trunc, truncf}; + +cfg_if! { + if #[cfg(f16_enabled)] { + // verify-sorted-start + pub use self::ceil::ceilf16; + pub use self::copysign::copysignf16; + pub use self::fabs::fabsf16; + pub use self::fdim::fdimf16; + pub use self::floor::floorf16; + pub use self::fmin_fmax::{fmaxf16, fminf16}; + pub use self::fminimum_fmaximum::{fmaximumf16, fminimumf16}; + pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16}; + pub use self::fmod::fmodf16; + pub use self::ldexp::ldexpf16; + pub use self::rint::rintf16; + pub use self::round::roundf16; + pub use self::roundeven::roundevenf16; + pub use self::scalbn::scalbnf16; + pub use self::sqrt::sqrtf16; + pub use self::trunc::truncf16; + // verify-sorted-end + + #[allow(unused_imports)] + pub(crate) use self::fma_wide::fmaf16; + } +} + +cfg_if! { + if #[cfg(f128_enabled)] { + // verify-sorted-start + pub use self::ceil::ceilf128; + pub use self::copysign::copysignf128; + pub use self::fabs::fabsf128; + pub use self::fdim::fdimf128; + pub use self::floor::floorf128; + pub use self::fma::fmaf128; + pub use self::fmin_fmax::{fmaxf128, fminf128}; + pub use self::fminimum_fmaximum::{fmaximumf128, fminimumf128}; + pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; + pub use self::fmod::fmodf128; + pub use self::ldexp::ldexpf128; + pub use self::rint::rintf128; + pub use self::round::roundf128; + pub use self::roundeven::roundevenf128; + pub use self::scalbn::scalbnf128; + pub use self::sqrt::sqrtf128; + pub use self::trunc::truncf128; + // verify-sorted-end + } +} + +#[inline] +fn get_high_word(x: f64) -> u32 { + (x.to_bits() >> 32) as u32 +} + +#[inline] +fn get_low_word(x: f64) -> u32 { + x.to_bits() as u32 +} + +#[inline] +fn with_set_high_word(f: f64, hi: u32) -> f64 { + let mut tmp = f.to_bits(); + tmp &= 0x00000000_ffffffff; + tmp |= (hi as u64) << 32; + f64::from_bits(tmp) +} + +#[inline] +fn with_set_low_word(f: f64, lo: u32) -> f64 { + let mut tmp = f.to_bits(); + tmp &= 0xffffffff_00000000; + tmp |= lo as u64; + f64::from_bits(tmp) +} + +#[inline] +fn combine_words(hi: u32, lo: u32) -> f64 { + f64::from_bits(((hi as u64) << 32) | lo as u64) +} diff --git a/library/compiler-builtins/libm/libm/src/math/modf.rs b/library/compiler-builtins/libm/libm/src/math/modf.rs new file mode 100644 index 00000000000..6541862cdd9 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/modf.rs @@ -0,0 +1,35 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn modf(x: f64) -> (f64, f64) { + let rv2: f64; + let mut u = x.to_bits(); + let mask: u64; + let e = (((u >> 52) & 0x7ff) as i32) - 0x3ff; + + /* no fractional part */ + if e >= 52 { + rv2 = x; + if e == 0x400 && (u << 12) != 0 { + /* nan */ + return (x, rv2); + } + u &= 1 << 63; + return (f64::from_bits(u), rv2); + } + + /* no integral part*/ + if e < 0 { + u &= 1 << 63; + rv2 = f64::from_bits(u); + return (x, rv2); + } + + mask = ((!0) >> 12) >> e; + if (u & mask) == 0 { + rv2 = x; + u &= 1 << 63; + return (f64::from_bits(u), rv2); + } + u &= !mask; + rv2 = f64::from_bits(u); + return (x - rv2, rv2); +} diff --git a/library/compiler-builtins/libm/libm/src/math/modff.rs b/library/compiler-builtins/libm/libm/src/math/modff.rs new file mode 100644 index 00000000000..90c6bca7d8d --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/modff.rs @@ -0,0 +1,34 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn modff(x: f32) -> (f32, f32) { + let rv2: f32; + let mut u: u32 = x.to_bits(); + let mask: u32; + let e = (((u >> 23) & 0xff) as i32) - 0x7f; + + /* no fractional part */ + if e >= 23 { + rv2 = x; + if e == 0x80 && (u << 9) != 0 { + /* nan */ + return (x, rv2); + } + u &= 0x80000000; + return (f32::from_bits(u), rv2); + } + /* no integral part */ + if e < 0 { + u &= 0x80000000; + rv2 = f32::from_bits(u); + return (x, rv2); + } + + mask = 0x007fffff >> e; + if (u & mask) == 0 { + rv2 = x; + u &= 0x80000000; + return (f32::from_bits(u), rv2); + } + u &= !mask; + rv2 = f32::from_bits(u); + return (x - rv2, rv2); +} diff --git a/library/compiler-builtins/libm/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/libm/src/math/nextafter.rs new file mode 100644 index 00000000000..c991ff6f233 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/nextafter.rs @@ -0,0 +1,37 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn nextafter(x: f64, y: f64) -> f64 { + if x.is_nan() || y.is_nan() { + return x + y; + } + + let mut ux_i = x.to_bits(); + let uy_i = y.to_bits(); + if ux_i == uy_i { + return y; + } + + let ax = ux_i & (!1_u64 / 2); + let ay = uy_i & (!1_u64 / 2); + if ax == 0 { + if ay == 0 { + return y; + } + ux_i = (uy_i & (1_u64 << 63)) | 1; + } else if ax > ay || ((ux_i ^ uy_i) & (1_u64 << 63)) != 0 { + ux_i -= 1; + } else { + ux_i += 1; + } + + let e = (ux_i >> 52) & 0x7ff; + // raise overflow if ux.f is infinite and x is finite + if e == 0x7ff { + force_eval!(x + x); + } + let ux_f = f64::from_bits(ux_i); + // raise underflow if ux.f is subnormal or zero + if e == 0 { + force_eval!(x * x + ux_f * ux_f); + } + ux_f +} diff --git a/library/compiler-builtins/libm/libm/src/math/nextafterf.rs b/library/compiler-builtins/libm/libm/src/math/nextafterf.rs new file mode 100644 index 00000000000..8ba3833562f --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/nextafterf.rs @@ -0,0 +1,37 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn nextafterf(x: f32, y: f32) -> f32 { + if x.is_nan() || y.is_nan() { + return x + y; + } + + let mut ux_i = x.to_bits(); + let uy_i = y.to_bits(); + if ux_i == uy_i { + return y; + } + + let ax = ux_i & 0x7fff_ffff_u32; + let ay = uy_i & 0x7fff_ffff_u32; + if ax == 0 { + if ay == 0 { + return y; + } + ux_i = (uy_i & 0x8000_0000_u32) | 1; + } else if ax > ay || ((ux_i ^ uy_i) & 0x8000_0000_u32) != 0 { + ux_i -= 1; + } else { + ux_i += 1; + } + + let e = ux_i & 0x7f80_0000_u32; + // raise overflow if ux_f is infinite and x is finite + if e == 0x7f80_0000_u32 { + force_eval!(x + x); + } + let ux_f = f32::from_bits(ux_i); + // raise underflow if ux_f is subnormal or zero + if e == 0 { + force_eval!(x * x + ux_f * ux_f); + } + ux_f +} diff --git a/library/compiler-builtins/libm/libm/src/math/pow.rs b/library/compiler-builtins/libm/libm/src/math/pow.rs new file mode 100644 index 00000000000..80b2a24999c --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/pow.rs @@ -0,0 +1,607 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +// pow(x,y) return x**y +// +// n +// Method: Let x = 2 * (1+f) +// 1. Compute and return log2(x) in two pieces: +// log2(x) = w1 + w2, +// where w1 has 53-24 = 29 bit trailing zeros. +// 2. Perform y*log2(x) = n+y' by simulating multi-precision +// arithmetic, where |y'|<=0.5. +// 3. Return x**y = 2**n*exp(y'*log2) +// +// Special cases: +// 1. (anything) ** 0 is 1 +// 2. 1 ** (anything) is 1 +// 3. (anything except 1) ** NAN is NAN +// 4. NAN ** (anything except 0) is NAN +// 5. +-(|x| > 1) ** +INF is +INF +// 6. +-(|x| > 1) ** -INF is +0 +// 7. +-(|x| < 1) ** +INF is +0 +// 8. +-(|x| < 1) ** -INF is +INF +// 9. -1 ** +-INF is 1 +// 10. +0 ** (+anything except 0, NAN) is +0 +// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 +// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero +// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero +// 14. -0 ** (+odd integer) is -0 +// 15. -0 ** (-odd integer) is -INF, raise divbyzero +// 16. +INF ** (+anything except 0,NAN) is +INF +// 17. +INF ** (-anything except 0,NAN) is +0 +// 18. -INF ** (+odd integer) is -INF +// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) +// 20. (anything) ** 1 is (anything) +// 21. (anything) ** -1 is 1/(anything) +// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) +// 23. (-anything except 0 and inf) ** (non-integer) is NAN +// +// Accuracy: +// pow(x,y) returns x**y nearly rounded. In particular +// pow(integer,integer) +// always returns the correct integer provided it is +// representable. +// +// Constants : +// The hexadecimal values are the intended ones for the following +// constants. The decimal values may be used, provided that the +// compiler will convert from decimal to binary accurately enough +// to produce the hexadecimal values shown. +// +use super::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; + +const BP: [f64; 2] = [1.0, 1.5]; +const DP_H: [f64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ +const DP_L: [f64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ +const TWO53: f64 = 9007199254740992.0; /* 0x43400000_00000000 */ +const HUGE: f64 = 1.0e300; +const TINY: f64 = 1.0e-300; + +// poly coefs for (3/2)*(log(x)-2s-2/3*s**3: +const L1: f64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ +const L2: f64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ +const L3: f64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ +const L4: f64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ +const L5: f64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ +const L6: f64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ +const P1: f64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ +const P2: f64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ +const P3: f64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ +const P4: f64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ +const P5: f64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ +const LG2: f64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ +const LG2_H: f64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ +const LG2_L: f64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ +const OVT: f64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ +const CP: f64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ +const CP_H: f64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ +const CP_L: f64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ +const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ +const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ +const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ + +/// Returns `x` to the power of `y` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn pow(x: f64, y: f64) -> f64 { + let t1: f64; + let t2: f64; + + let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); + let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); + + let mut ix: i32 = hx & 0x7fffffff_i32; + let iy: i32 = hy & 0x7fffffff_i32; + + /* x**0 = 1, even if x is NaN */ + if ((iy as u32) | ly) == 0 { + return 1.0; + } + + /* 1**y = 1, even if y is NaN */ + if hx == 0x3ff00000 && lx == 0 { + return 1.0; + } + + /* NaN if either arg is NaN */ + if ix > 0x7ff00000 + || (ix == 0x7ff00000 && lx != 0) + || iy > 0x7ff00000 + || (iy == 0x7ff00000 && ly != 0) + { + return x + y; + } + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + let mut yisint: i32 = 0; + let mut k: i32; + let mut j: i32; + if hx < 0 { + if iy >= 0x43400000 { + yisint = 2; /* even integer y */ + } else if iy >= 0x3ff00000 { + k = (iy >> 20) - 0x3ff; /* exponent */ + + if k > 20 { + j = (ly >> (52 - k)) as i32; + + if (j << (52 - k)) == (ly as i32) { + yisint = 2 - (j & 1); + } + } else if ly == 0 { + j = iy >> (20 - k); + + if (j << (20 - k)) == iy { + yisint = 2 - (j & 1); + } + } + } + } + + if ly == 0 { + /* special value of y */ + if iy == 0x7ff00000 { + /* y is +-inf */ + + return if ((ix - 0x3ff00000) | (lx as i32)) == 0 { + /* (-1)**+-inf is 1 */ + 1.0 + } else if ix >= 0x3ff00000 { + /* (|x|>1)**+-inf = inf,0 */ + if hy >= 0 { y } else { 0.0 } + } else { + /* (|x|<1)**+-inf = 0,inf */ + if hy >= 0 { 0.0 } else { -y } + }; + } + + if iy == 0x3ff00000 { + /* y is +-1 */ + return if hy >= 0 { x } else { 1.0 / x }; + } + + if hy == 0x40000000 { + /* y is 2 */ + return x * x; + } + + if hy == 0x3fe00000 { + /* y is 0.5 */ + if hx >= 0 { + /* x >= +0 */ + return sqrt(x); + } + } + } + + let mut ax: f64 = fabs(x); + if lx == 0 { + /* special value of x */ + if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { + /* x is +-0,+-inf,+-1 */ + let mut z: f64 = ax; + + if hy < 0 { + /* z = (1/|x|) */ + z = 1.0 / z; + } + + if hx < 0 { + if ((ix - 0x3ff00000) | yisint) == 0 { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } else if yisint == 1 { + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + } + + return z; + } + } + + let mut s: f64 = 1.0; /* sign of result */ + if hx < 0 { + if yisint == 0 { + /* (x<0)**(non-int) is NaN */ + return (x - x) / (x - x); + } + + if yisint == 1 { + /* (x<0)**(odd int) */ + s = -1.0; + } + } + + /* |y| is HUGE */ + if iy > 0x41e00000 { + /* if |y| > 2**31 */ + if iy > 0x43f00000 { + /* if |y| > 2**64, must o/uflow */ + if ix <= 0x3fefffff { + return if hy < 0 { HUGE * HUGE } else { TINY * TINY }; + } + + if ix >= 0x3ff00000 { + return if hy > 0 { HUGE * HUGE } else { TINY * TINY }; + } + } + + /* over/underflow if x is not close to one */ + if ix < 0x3fefffff { + return if hy < 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + } + if ix > 0x3ff00000 { + return if hy > 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + } + + /* now |1-x| is TINY <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ + let w: f64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); + let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ + let v: f64 = t * IVLN2_L - w * IVLN2; + t1 = with_set_low_word(u + v, 0); + t2 = v - (t1 - u); + } else { + // double ss,s2,s_h,s_l,t_h,t_l; + let mut n: i32 = 0; + + if ix < 0x00100000 { + /* take care subnormal number */ + ax *= TWO53; + n -= 53; + ix = get_high_word(ax) as i32; + } + + n += (ix >> 20) - 0x3ff; + j = ix & 0x000fffff; + + /* determine interval */ + let k: i32; + ix = j | 0x3ff00000; /* normalize ix */ + if j <= 0x3988E { + /* |x|> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18), + ); + let t_l: f64 = ax - (t_h - i!(BP, k as usize)); + let s_l: f64 = v * ((u - s_h * t_h) - s_h * t_l); + + /* compute log(ax) */ + let s2: f64 = ss * ss; + let mut r: f64 = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); + r += s_l * (s_h + ss); + let s2: f64 = s_h * s_h; + let t_h: f64 = with_set_low_word(3.0 + s2 + r, 0); + let t_l: f64 = r - ((t_h - 3.0) - s2); + + /* u+v = ss*(1+...) */ + let u: f64 = s_h * t_h; + let v: f64 = s_l * t_h + t_l * ss; + + /* 2/(3log2)*(ss+...) */ + let p_h: f64 = with_set_low_word(u + v, 0); + let p_l = v - (p_h - u); + let z_h: f64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ + let z_l: f64 = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); + + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + let t: f64 = n as f64; + t1 = with_set_low_word(((z_h + z_l) + i!(DP_H, k as usize)) + t, 0); + t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + let y1: f64 = with_set_low_word(y, 0); + let p_l: f64 = (y - y1) * t1 + y * t2; + let mut p_h: f64 = y1 * t1; + let z: f64 = p_l + p_h; + let mut j: i32 = (z.to_bits() >> 32) as i32; + let i: i32 = z.to_bits() as i32; + // let (j, i): (i32, i32) = ((z.to_bits() >> 32) as i32, z.to_bits() as i32); + + if j >= 0x40900000 { + /* z >= 1024 */ + if (j - 0x40900000) | i != 0 { + /* if z > 1024 */ + return s * HUGE * HUGE; /* overflow */ + } + + if p_l + OVT > z - p_h { + return s * HUGE * HUGE; /* overflow */ + } + } else if (j & 0x7fffffff) >= 0x4090cc00 { + /* z <= -1075 */ + // FIXME: instead of abs(j) use unsigned j + + if (((j as u32) - 0xc090cc00) | (i as u32)) != 0 { + /* z < -1075 */ + return s * TINY * TINY; /* underflow */ + } + + if p_l <= z - p_h { + return s * TINY * TINY; /* underflow */ + } + } + + /* compute 2**(p_h+p_l) */ + let i: i32 = j & 0x7fffffff_i32; + k = (i >> 20) - 0x3ff; + let mut n: i32 = 0; + + if i > 0x3fe00000 { + /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00100000 >> (k + 1)); + k = ((n & 0x7fffffff) >> 20) - 0x3ff; /* new k for n */ + let t: f64 = with_set_high_word(0.0, (n & !(0x000fffff >> k)) as u32); + n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); + if j < 0 { + n = -n; + } + p_h -= t; + } + + let t: f64 = with_set_low_word(p_l + p_h, 0); + let u: f64 = t * LG2_H; + let v: f64 = (p_l - (t - p_h)) * LG2 + t * LG2_L; + let mut z: f64 = u + v; + let w: f64 = v - (z - u); + let t: f64 = z * z; + let t1: f64 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + let r: f64 = (z * t1) / (t1 - 2.0) - (w + z * w); + z = 1.0 - (r - z); + j = get_high_word(z) as i32; + j += n << 20; + + if (j >> 20) <= 0 { + /* subnormal output */ + z = scalbn(z, n); + } else { + z = with_set_high_word(z, j as u32); + } + + s * z +} + +#[cfg(test)] +mod tests { + extern crate core; + + use self::core::f64::consts::{E, PI}; + use super::pow; + + const POS_ZERO: &[f64] = &[0.0]; + const NEG_ZERO: &[f64] = &[-0.0]; + const POS_ONE: &[f64] = &[1.0]; + const NEG_ONE: &[f64] = &[-1.0]; + const POS_FLOATS: &[f64] = &[99.0 / 70.0, E, PI]; + const NEG_FLOATS: &[f64] = &[-99.0 / 70.0, -E, -PI]; + const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), f64::MIN_POSITIVE, f64::EPSILON]; + const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -f64::MIN_POSITIVE, -f64::EPSILON]; + const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, f64::MAX]; + const NEG_EVENS: &[f64] = &[f64::MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; + const POS_ODDS: &[f64] = &[3.0, 7.0]; + const NEG_ODDS: &[f64] = &[-7.0, -3.0]; + const NANS: &[f64] = &[f64::NAN]; + const POS_INF: &[f64] = &[f64::INFINITY]; + const NEG_INF: &[f64] = &[f64::NEG_INFINITY]; + + const ALL: &[&[f64]] = &[ + POS_ZERO, + NEG_ZERO, + NANS, + NEG_SMALL_FLOATS, + POS_SMALL_FLOATS, + NEG_FLOATS, + POS_FLOATS, + NEG_EVENS, + POS_EVENS, + NEG_ODDS, + POS_ODDS, + NEG_INF, + POS_INF, + NEG_ONE, + POS_ONE, + ]; + const POS: &[&[f64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF]; + const NEG: &[&[f64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF]; + + fn pow_test(base: f64, exponent: f64, expected: f64) { + let res = pow(base, exponent); + assert!( + if expected.is_nan() { res.is_nan() } else { pow(base, exponent) == expected }, + "{} ** {} was {} instead of {}", + base, + exponent, + res, + expected + ); + } + + fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { + sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); + } + + fn test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) { + sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); + } + + fn test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) { + sets.iter().for_each(|s| { + s.iter().for_each(|val| { + let exp = expected(*val); + let res = computed(*val); + + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let exp = force_eval!(exp); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let res = force_eval!(res); + assert!( + if exp.is_nan() { res.is_nan() } else { exp == res }, + "test for {} was {} instead of {}", + val, + res, + exp + ); + }) + }); + } + + #[test] + fn zero_as_exponent() { + test_sets_as_base(ALL, 0.0, 1.0); + test_sets_as_base(ALL, -0.0, 1.0); + } + + #[test] + fn one_as_base() { + test_sets_as_exponent(1.0, ALL, 1.0); + } + + #[test] + fn nan_inputs() { + // NAN as the base: + // (f64::NAN ^ anything *but 0* should be f64::NAN) + test_sets_as_exponent(f64::NAN, &ALL[2..], f64::NAN); + + // f64::NAN as the exponent: + // (anything *but 1* ^ f64::NAN should be f64::NAN) + test_sets_as_base(&ALL[..(ALL.len() - 2)], f64::NAN, f64::NAN); + } + + #[test] + fn infinity_as_base() { + // Positive Infinity as the base: + // (+Infinity ^ positive anything but 0 and f64::NAN should be +Infinity) + test_sets_as_exponent(f64::INFINITY, &POS[1..], f64::INFINITY); + + // (+Infinity ^ negative anything except 0 and f64::NAN should be 0.0) + test_sets_as_exponent(f64::INFINITY, &NEG[1..], 0.0); + + // Negative Infinity as the base: + // (-Infinity ^ positive odd ints should be -Infinity) + test_sets_as_exponent(f64::NEG_INFINITY, &[POS_ODDS], f64::NEG_INFINITY); + + // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) + // We can lump in pos/neg odd ints here because they don't seem to + // cause panics (div by zero) in release mode (I think). + test_sets(ALL, &|v: f64| pow(f64::NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); + } + + #[test] + fn infinity_as_exponent() { + // Positive/Negative base greater than 1: + // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes f64::NAN as the base) + test_sets_as_base(&ALL[5..(ALL.len() - 2)], f64::INFINITY, f64::INFINITY); + + // (pos/neg > 1 ^ -Infinity should be 0.0) + test_sets_as_base(&ALL[5..ALL.len() - 2], f64::NEG_INFINITY, 0.0); + + // Positive/Negative base less than 1: + let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS]; + + // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes f64::NAN as the base) + test_sets_as_base(base_below_one, f64::INFINITY, 0.0); + + // (pos/neg < 1 ^ -Infinity should be Infinity) + test_sets_as_base(base_below_one, f64::NEG_INFINITY, f64::INFINITY); + + // Positive/Negative 1 as the base: + // (pos/neg 1 ^ Infinity should be 1) + test_sets_as_base(&[NEG_ONE, POS_ONE], f64::INFINITY, 1.0); + + // (pos/neg 1 ^ -Infinity should be 1) + test_sets_as_base(&[NEG_ONE, POS_ONE], f64::NEG_INFINITY, 1.0); + } + + #[test] + fn zero_as_base() { + // Positive Zero as the base: + // (+0 ^ anything positive but 0 and f64::NAN should be +0) + test_sets_as_exponent(0.0, &POS[1..], 0.0); + + // (+0 ^ anything negative but 0 and f64::NAN should be Infinity) + // (this should panic because we're dividing by zero) + test_sets_as_exponent(0.0, &NEG[1..], f64::INFINITY); + + // Negative Zero as the base: + // (-0 ^ anything positive but 0, f64::NAN, and odd ints should be +0) + test_sets_as_exponent(-0.0, &POS[3..], 0.0); + + // (-0 ^ anything negative but 0, f64::NAN, and odd ints should be Infinity) + // (should panic because of divide by zero) + test_sets_as_exponent(-0.0, &NEG[3..], f64::INFINITY); + + // (-0 ^ positive odd ints should be -0) + test_sets_as_exponent(-0.0, &[POS_ODDS], -0.0); + + // (-0 ^ negative odd ints should be -Infinity) + // (should panic because of divide by zero) + test_sets_as_exponent(-0.0, &[NEG_ODDS], f64::NEG_INFINITY); + } + + #[test] + fn special_cases() { + // One as the exponent: + // (anything ^ 1 should be anything - i.e. the base) + test_sets(ALL, &|v: f64| pow(v, 1.0), &|v: f64| v); + + // Negative One as the exponent: + // (anything ^ -1 should be 1/anything) + test_sets(ALL, &|v: f64| pow(v, -1.0), &|v: f64| 1.0 / v); + + // Factoring -1 out: + // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) + [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| { + int_set.iter().for_each(|int| { + test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| pow(-1.0, *int) * pow(v, *int)); + }) + }); + + // Negative base (imaginary results): + // (-anything except 0 and Infinity ^ non-integer should be NAN) + NEG[1..(NEG.len() - 1)].iter().for_each(|set| { + set.iter().for_each(|val| { + test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| f64::NAN); + }) + }); + } + + #[test] + fn normal_cases() { + assert_eq!(pow(2.0, 20.0), (1 << 20) as f64); + assert_eq!(pow(-1.0, 9.0), -1.0); + assert!(pow(-1.0, 2.2).is_nan()); + assert!(pow(-1.0, -1.14).is_nan()); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/powf.rs b/library/compiler-builtins/libm/libm/src/math/powf.rs new file mode 100644 index 00000000000..839c6c23d43 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/powf.rs @@ -0,0 +1,335 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::cmp::Ordering; + +use super::{fabsf, scalbnf, sqrtf}; + +const BP: [f32; 2] = [1.0, 1.5]; +const DP_H: [f32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ +const DP_L: [f32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ +const TWO24: f32 = 16777216.0; /* 0x4b800000 */ +const HUGE: f32 = 1.0e30; +const TINY: f32 = 1.0e-30; +const L1: f32 = 6.0000002384e-01; /* 0x3f19999a */ +const L2: f32 = 4.2857143283e-01; /* 0x3edb6db7 */ +const L3: f32 = 3.3333334327e-01; /* 0x3eaaaaab */ +const L4: f32 = 2.7272811532e-01; /* 0x3e8ba305 */ +const L5: f32 = 2.3066075146e-01; /* 0x3e6c3255 */ +const L6: f32 = 2.0697501302e-01; /* 0x3e53f142 */ +const P1: f32 = 1.6666667163e-01; /* 0x3e2aaaab */ +const P2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const P3: f32 = 6.6137559770e-05; /* 0x388ab355 */ +const P4: f32 = -1.6533901999e-06; /* 0xb5ddea0e */ +const P5: f32 = 4.1381369442e-08; /* 0x3331bb4c */ +const LG2: f32 = 6.9314718246e-01; /* 0x3f317218 */ +const LG2_H: f32 = 6.93145752e-01; /* 0x3f317200 */ +const LG2_L: f32 = 1.42860654e-06; /* 0x35bfbe8c */ +const OVT: f32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ +const CP: f32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ +const CP_H: f32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ +const CP_L: f32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ +const IVLN2: f32 = 1.4426950216e+00; +const IVLN2_H: f32 = 1.4426879883e+00; +const IVLN2_L: f32 = 7.0526075433e-06; + +/// Returns `x` to the power of `y` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn powf(x: f32, y: f32) -> f32 { + let mut z: f32; + let mut ax: f32; + let z_h: f32; + let z_l: f32; + let mut p_h: f32; + let mut p_l: f32; + let y1: f32; + let mut t1: f32; + let t2: f32; + let mut r: f32; + let s: f32; + let mut sn: f32; + let mut t: f32; + let mut u: f32; + let mut v: f32; + let mut w: f32; + let i: i32; + let mut j: i32; + let mut k: i32; + let mut yisint: i32; + let mut n: i32; + let hx: i32; + let hy: i32; + let mut ix: i32; + let iy: i32; + let mut is: i32; + + hx = x.to_bits() as i32; + hy = y.to_bits() as i32; + + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if iy == 0 { + return 1.0; + } + + /* 1**y = 1, even if y is NaN */ + if hx == 0x3f800000 { + return 1.0; + } + + /* NaN if either arg is NaN */ + if ix > 0x7f800000 || iy > 0x7f800000 { + return x + y; + } + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if hx < 0 { + if iy >= 0x4b800000 { + yisint = 2; /* even integer y */ + } else if iy >= 0x3f800000 { + k = (iy >> 23) - 0x7f; /* exponent */ + j = iy >> (23 - k); + if (j << (23 - k)) == iy { + yisint = 2 - (j & 1); + } + } + } + + /* special value of y */ + if iy == 0x7f800000 { + /* y is +-inf */ + match ix.cmp(&0x3f800000) { + /* (-1)**+-inf is 1 */ + Ordering::Equal => return 1.0, + /* (|x|>1)**+-inf = inf,0 */ + Ordering::Greater => return if hy >= 0 { y } else { 0.0 }, + /* (|x|<1)**+-inf = 0,inf */ + Ordering::Less => return if hy >= 0 { 0.0 } else { -y }, + } + } + if iy == 0x3f800000 { + /* y is +-1 */ + return if hy >= 0 { x } else { 1.0 / x }; + } + + if hy == 0x40000000 { + /* y is 2 */ + return x * x; + } + + if hy == 0x3f000000 + /* y is 0.5 */ + && hx >= 0 + { + /* x >= +0 */ + return sqrtf(x); + } + + ax = fabsf(x); + /* special value of x */ + if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 { + /* x is +-0,+-inf,+-1 */ + z = ax; + if hy < 0 { + /* z = (1/|x|) */ + z = 1.0 / z; + } + + if hx < 0 { + if ((ix - 0x3f800000) | yisint) == 0 { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } else if yisint == 1 { + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + } + return z; + } + + sn = 1.0; /* sign of result */ + if hx < 0 { + if yisint == 0 { + /* (x<0)**(non-int) is NaN */ + return (x - x) / (x - x); + } + + if yisint == 1 { + /* (x<0)**(odd int) */ + sn = -1.0; + } + } + + /* |y| is HUGE */ + if iy > 0x4d000000 { + /* if |y| > 2**27 */ + /* over/underflow if x is not close to one */ + if ix < 0x3f7ffff8 { + return if hy < 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; + } + + if ix > 0x3f800007 { + return if hy > 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; + } + + /* now |1-x| is TINY <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1.; /* t has 20 trailing zeros */ + w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); + u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ + v = t * IVLN2_L - w * IVLN2; + t1 = u + v; + is = t1.to_bits() as i32; + t1 = f32::from_bits(is as u32 & 0xfffff000); + t2 = v - (t1 - u); + } else { + let mut s2: f32; + let mut s_h: f32; + let s_l: f32; + let mut t_h: f32; + let mut t_l: f32; + + n = 0; + /* take care subnormal number */ + if ix < 0x00800000 { + ax *= TWO24; + n -= 24; + ix = ax.to_bits() as i32; + } + n += ((ix) >> 23) - 0x7f; + j = ix & 0x007fffff; + /* determine interval */ + ix = j | 0x3f800000; /* normalize ix */ + if j <= 0x1cc471 { + /* |x|> 1) & 0xfffff000) | 0x20000000) as i32; + t_h = f32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); + t_l = ax - (t_h - i!(BP, k as usize)); + s_l = v * ((u - s_h * t_h) - s_h * t_l); + /* compute log(ax) */ + s2 = s * s; + r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); + r += s_l * (s_h + s); + s2 = s_h * s_h; + t_h = 3.0 + s2 + r; + is = t_h.to_bits() as i32; + t_h = f32::from_bits(is as u32 & 0xfffff000); + t_l = r - ((t_h - 3.0) - s2); + /* u+v = s*(1+...) */ + u = s_h * t_h; + v = s_l * t_h + t_l * s; + /* 2/(3log2)*(s+...) */ + p_h = u + v; + is = p_h.to_bits() as i32; + p_h = f32::from_bits(is as u32 & 0xfffff000); + p_l = v - (p_h - u); + z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = n as f32; + t1 = ((z_h + z_l) + i!(DP_H, k as usize)) + t; + is = t1.to_bits() as i32; + t1 = f32::from_bits(is as u32 & 0xfffff000); + t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); + }; + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + is = y.to_bits() as i32; + y1 = f32::from_bits(is as u32 & 0xfffff000); + p_l = (y - y1) * t1 + y * t2; + p_h = y1 * t1; + z = p_l + p_h; + j = z.to_bits() as i32; + if j > 0x43000000 { + /* if z > 128 */ + return sn * HUGE * HUGE; /* overflow */ + } else if j == 0x43000000 { + /* if z == 128 */ + if p_l + OVT > z - p_h { + return sn * HUGE * HUGE; /* overflow */ + } + } else if (j & 0x7fffffff) > 0x43160000 { + /* z < -150 */ + // FIXME: check should be (uint32_t)j > 0xc3160000 + return sn * TINY * TINY; /* underflow */ + } else if j as u32 == 0xc3160000 + /* z == -150 */ + && p_l <= z - p_h + { + return sn * TINY * TINY; /* underflow */ + } + + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i >> 23) - 0x7f; + n = 0; + if i > 0x3f000000 { + /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00800000 >> (k + 1)); + k = ((n & 0x7fffffff) >> 23) - 0x7f; /* new k for n */ + t = f32::from_bits(n as u32 & !(0x007fffff >> k)); + n = ((n & 0x007fffff) | 0x00800000) >> (23 - k); + if j < 0 { + n = -n; + } + p_h -= t; + } + t = p_l + p_h; + is = t.to_bits() as i32; + t = f32::from_bits(is as u32 & 0xffff8000); + u = t * LG2_H; + v = (p_l - (t - p_h)) * LG2 + t * LG2_L; + z = u + v; + w = v - (z - u); + t = z * z; + t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + r = (z * t1) / (t1 - 2.0) - (w + z * w); + z = 1.0 - (r - z); + j = z.to_bits() as i32; + j += n << 23; + if (j >> 23) <= 0 { + /* subnormal output */ + z = scalbnf(z, n); + } else { + z = f32::from_bits(j as u32); + } + sn * z +} diff --git a/library/compiler-builtins/libm/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/libm/src/math/rem_pio2.rs new file mode 100644 index 00000000000..917e90819a5 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/rem_pio2.rs @@ -0,0 +1,223 @@ +// origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== +// +// Optimized by Bruce D. Evans. */ +use super::rem_pio2_large; + +// #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +// #define EPS DBL_EPSILON +const EPS: f64 = 2.2204460492503131e-16; +// #elif FLT_EVAL_METHOD==2 +// #define EPS LDBL_EPSILON +// #endif + +// TODO: Support FLT_EVAL_METHOD? + +const TO_INT: f64 = 1.5 / EPS; +/// 53 bits of 2/pi +const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +/// first 33 bits of pi/2 +const PIO2_1: f64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ +/// pi/2 - PIO2_1 +const PIO2_1T: f64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ +/// second 33 bits of pi/2 +const PIO2_2: f64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ +/// pi/2 - (PIO2_1+PIO2_2) +const PIO2_2T: f64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ +/// third 33 bits of pi/2 +const PIO2_3: f64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ +/// pi/2 - (PIO2_1+PIO2_2+PIO2_3) +const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +// return the remainder of x rem pi/2 in y[0]+y[1] +// use rem_pio2_large() for large x +// +// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { + let x1p24 = f64::from_bits(0x4170000000000000); + + let sign = (f64::to_bits(x) >> 63) as i32; + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + fn medium(x: f64, ix: u32) -> (i32, f64, f64) { + /* rint(x/(pi/2)), Assume round-to-nearest. */ + let tmp = x * INV_PIO2 + TO_INT; + // force rounding of tmp to it's storage format on x87 to avoid + // excess precision issues. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let tmp = force_eval!(tmp); + let f_n = tmp - TO_INT; + let n = f_n as i32; + let mut r = x - f_n * PIO2_1; + let mut w = f_n * PIO2_1T; /* 1st round, good to 85 bits */ + let mut y0 = r - w; + let ui = f64::to_bits(y0); + let ey = (ui >> 52) as i32 & 0x7ff; + let ex = (ix >> 20) as i32; + if ex - ey > 16 { + /* 2nd round, good to 118 bits */ + let t = r; + w = f_n * PIO2_2; + r = t - w; + w = f_n * PIO2_2T - ((t - r) - w); + y0 = r - w; + let ey = (f64::to_bits(y0) >> 52) as i32 & 0x7ff; + if ex - ey > 49 { + /* 3rd round, good to 151 bits, covers all cases */ + let t = r; + w = f_n * PIO2_3; + r = t - w; + w = f_n * PIO2_3T - ((t - r) - w); + y0 = r - w; + } + } + let y1 = (r - y0) - w; + (n, y0, y1) + } + + if ix <= 0x400f6a7a { + /* |x| ~<= 5pi/4 */ + if (ix & 0xfffff) == 0x921fb { + /* |x| ~= pi/2 or 2pi/2 */ + return medium(x, ix); /* cancellation -- use medium case */ + } + if ix <= 0x4002d97c { + /* |x| ~<= 3pi/4 */ + if sign == 0 { + let z = x - PIO2_1; /* one round good to 85 bits */ + let y0 = z - PIO2_1T; + let y1 = (z - y0) - PIO2_1T; + return (1, y0, y1); + } else { + let z = x + PIO2_1; + let y0 = z + PIO2_1T; + let y1 = (z - y0) + PIO2_1T; + return (-1, y0, y1); + } + } else if sign == 0 { + let z = x - 2.0 * PIO2_1; + let y0 = z - 2.0 * PIO2_1T; + let y1 = (z - y0) - 2.0 * PIO2_1T; + return (2, y0, y1); + } else { + let z = x + 2.0 * PIO2_1; + let y0 = z + 2.0 * PIO2_1T; + let y1 = (z - y0) + 2.0 * PIO2_1T; + return (-2, y0, y1); + } + } + if ix <= 0x401c463b { + /* |x| ~<= 9pi/4 */ + if ix <= 0x4015fdbc { + /* |x| ~<= 7pi/4 */ + if ix == 0x4012d97c { + /* |x| ~= 3pi/2 */ + return medium(x, ix); + } + if sign == 0 { + let z = x - 3.0 * PIO2_1; + let y0 = z - 3.0 * PIO2_1T; + let y1 = (z - y0) - 3.0 * PIO2_1T; + return (3, y0, y1); + } else { + let z = x + 3.0 * PIO2_1; + let y0 = z + 3.0 * PIO2_1T; + let y1 = (z - y0) + 3.0 * PIO2_1T; + return (-3, y0, y1); + } + } else { + if ix == 0x401921fb { + /* |x| ~= 4pi/2 */ + return medium(x, ix); + } + if sign == 0 { + let z = x - 4.0 * PIO2_1; + let y0 = z - 4.0 * PIO2_1T; + let y1 = (z - y0) - 4.0 * PIO2_1T; + return (4, y0, y1); + } else { + let z = x + 4.0 * PIO2_1; + let y0 = z + 4.0 * PIO2_1T; + let y1 = (z - y0) + 4.0 * PIO2_1T; + return (-4, y0, y1); + } + } + } + if ix < 0x413921fb { + /* |x| ~< 2^20*(pi/2), medium size */ + return medium(x, ix); + } + /* + * all other (large) arguments + */ + if ix >= 0x7ff00000 { + /* x is inf or NaN */ + let y0 = x - x; + let y1 = y0; + return (0, y0, y1); + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + let mut ui = f64::to_bits(x); + ui &= (!1) >> 12; + ui |= (0x3ff + 23) << 52; + let mut z = f64::from_bits(ui); + let mut tx = [0.0; 3]; + for i in 0..2 { + i!(tx,i, =, z as i32 as f64); + z = (z - i!(tx, i)) * x1p24; + } + i!(tx,2, =, z); + /* skip zero terms, first term is non-zero */ + let mut i = 2; + while i != 0 && i!(tx, i) == 0.0 { + i -= 1; + } + let mut ty = [0.0; 3]; + let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix as i32) >> 20) - (0x3ff + 23), 1); + if sign != 0 { + return (-n, -i!(ty, 0), -i!(ty, 1)); + } + (n, i!(ty, 0), i!(ty, 1)) +} + +#[cfg(test)] +mod tests { + use super::rem_pio2; + + #[test] + // FIXME(correctness): inaccurate results on i586 + #[cfg_attr(all(target_arch = "x86", not(target_feature = "sse")), ignore)] + fn test_near_pi() { + let arg = 3.141592025756836; + let arg = force_eval!(arg); + assert_eq!(rem_pio2(arg), (2, -6.278329573009626e-7, -2.1125998133974653e-23)); + let arg = 3.141592033207416; + let arg = force_eval!(arg); + assert_eq!(rem_pio2(arg), (2, -6.20382377148128e-7, -2.1125998133974653e-23)); + let arg = 3.141592144966125; + let arg = force_eval!(arg); + assert_eq!(rem_pio2(arg), (2, -5.086236681942706e-7, -2.1125998133974653e-23)); + let arg = 3.141592979431152; + let arg = force_eval!(arg); + assert_eq!(rem_pio2(arg), (2, 3.2584135866119817e-7, -2.1125998133974653e-23)); + } + + #[test] + fn test_overflow_b9b847() { + let _ = rem_pio2(-3054214.5490637687); + } + + #[test] + fn test_overflow_4747b9() { + let _ = rem_pio2(917340800458.2274); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/libm/src/math/rem_pio2_large.rs new file mode 100644 index 00000000000..6d679bbe98c --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/rem_pio2_large.rs @@ -0,0 +1,468 @@ +#![allow(unused_unsafe)] +/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{floor, scalbn}; + +// initial value for jk +const INIT_JK: [usize; 4] = [3, 4, 4, 6]; + +// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi +// +// integer array, contains the (24*i)-th to (24*i+23)-th +// bit of 2/pi after binary point. The corresponding +// floating value is +// +// ipio2[i] * 2^(-24(i+1)). +// +// NB: This table must have at least (e0-3)/24 + jk terms. +// For quad precision (e0 <= 16360, jk = 6), this is 686. +#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] +const IPIO2: [i32; 66] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, + 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, + 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, + 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, + 0x73A8C9, 0x60E27B, 0xC08C6B, +]; + +#[cfg(target_pointer_width = "64")] +const IPIO2: [i32; 690] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, + 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, + 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, + 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, + 0x73A8C9, 0x60E27B, 0xC08C6B, 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, + 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, 0xDE4F98, 0x327DBB, 0xC33D26, + 0xEF6B1E, 0x5EF89F, 0x3A1F35, 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, + 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, 0x467D86, 0x2D71E3, 0x9AC69B, + 0x006233, 0x7CD2B4, 0x97A7B4, 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, + 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, 0xCB2324, 0x778AD6, 0x23545A, + 0xB91F00, 0x1B0AF1, 0xDFCE19, 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, + 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, 0xDE3B58, 0x929BDE, 0x2822D2, + 0xE88628, 0x4D58E2, 0x32CAC6, 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, + 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, 0xD36710, 0xD8DDAA, 0x425FAE, + 0xCE616A, 0xA4280A, 0xB499D3, 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, + 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, 0x36D9CA, 0xD2A828, 0x8D61C2, + 0x77C912, 0x142604, 0x9B4612, 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, + 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, 0xC3E7B3, 0x28F8C7, 0x940593, + 0x3E71C1, 0xB3092E, 0xF3450B, 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, + 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, 0x9794E8, 0x84E6E2, 0x973199, + 0x6BED88, 0x365F5F, 0x0EFDBB, 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, + 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, 0x90AA47, 0x02E774, 0x24D6BD, + 0xA67DF7, 0x72486E, 0xEF169F, 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, + 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, 0x10D86D, 0x324832, 0x754C5B, + 0xD4714E, 0x6E5445, 0xC1090B, 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, + 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, 0x6AE290, 0x89D988, 0x50722C, + 0xBEA404, 0x940777, 0x7030F3, 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, + 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, 0x3BDF08, 0x2B3715, 0xA0805C, + 0x93805A, 0x921110, 0xD8E80F, 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, + 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, 0xAA140A, 0x2F2689, 0x768364, + 0x333B09, 0x1A940E, 0xAA3A51, 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, + 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, 0x5BC3D8, 0xC492F5, 0x4BADC6, + 0xA5CA4E, 0xCD37A7, 0x36A9E6, 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, + 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, 0x306529, 0xBF5657, 0x3AFF47, + 0xB9F96A, 0xF3BE75, 0xDF9328, 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, + 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, 0xA8654F, 0xA5C1D2, 0x0F3F0B, + 0xCD785B, 0x76F923, 0x048B7B, 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, + 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, 0xDA4886, 0xA05DF7, 0xF480C6, + 0x2FF0AC, 0x9AECDD, 0xBC5C3F, 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, + 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, 0x2A1216, 0x2DB7DC, 0xFDE5FA, + 0xFEDB89, 0xFDBE89, 0x6C76E4, 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, + 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, 0x48D784, 0x16DF30, 0x432DC7, + 0x356125, 0xCE70C9, 0xB8CB30, 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, + 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, 0xC4F133, 0x5F6E13, 0xE4305D, + 0xA92E85, 0xC3B21D, 0x3632A1, 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, + 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, 0xCBDA11, 0xD0BE7D, 0xC1DB9B, + 0xBD17AB, 0x81A2CA, 0x5C6A08, 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, + 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, 0x4F6A68, 0xA82A4A, 0x5AC44F, + 0xBCF82D, 0x985AD7, 0x95C7F4, 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, + 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, 0xD0C0B2, 0x485551, 0x0EFB1E, + 0xC37295, 0x3B06A3, 0x3540C0, 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, + 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, 0x3C3ABA, 0x461846, 0x5F7555, + 0xF5BDD2, 0xC6926E, 0x5D2EAC, 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, + 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, 0x745D7C, 0xB2AD6B, 0x9D6ECD, + 0x7B723E, 0x6A11C6, 0xA9CFF7, 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, + 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, 0xBEFDFD, 0xEF4556, 0x367ED9, + 0x13D9EC, 0xB9BA8B, 0xFC97C4, 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, + 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, 0x9C2A3E, 0xCC5F11, 0x4A0BFD, + 0xFBF4E1, 0x6D3B8E, 0x2C86E2, 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, + 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, 0xCC2254, 0xDC552A, 0xD6C6C0, + 0x96190B, 0xB8701A, 0x649569, 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, + 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, 0x9B5861, 0xBC57E1, 0xC68351, + 0x103ED8, 0x4871DD, 0xDD1C2D, 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, + 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, 0x382682, 0x9BE7CA, 0xA40D51, + 0xB13399, 0x0ED7A9, 0x480569, 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, + 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, 0x5FD45E, 0xA4677B, 0x7AACBA, + 0xA2F655, 0x23882B, 0x55BA41, 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, + 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, 0xAE5ADB, 0x86C547, 0x624385, + 0x3B8621, 0x94792C, 0x876110, 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, + 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, 0xB1933D, 0x0B7CBD, 0xDC51A4, + 0x63DD27, 0xDDE169, 0x19949A, 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, + 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, 0x4D7E6F, 0x5119A5, 0xABF9B5, + 0xD6DF82, 0x61DD96, 0x023616, 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, + 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, +]; + +const PIO2: [f64; 8] = [ + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +]; + +// fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 +// +// Input parameters: +// x[] The input value (must be positive) is broken into nx +// pieces of 24-bit integers in double precision format. +// x[i] will be the i-th 24 bit of x. The scaled exponent +// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 +// match x's up to 24 bits. +// +// Example of breaking a double positive z into x[0]+x[1]+x[2]: +// e0 = ilogb(z)-23 +// z = scalbn(z,-e0) +// for i = 0,1,2 +// x[i] = floor(z) +// z = (z-x[i])*2**24 +// +// y[] ouput result in an array of double precision numbers. +// The dimension of y[] is: +// 24-bit precision 1 +// 53-bit precision 2 +// 64-bit precision 2 +// 113-bit precision 3 +// The actual value is the sum of them. Thus for 113-bit +// precison, one may have to do something like: +// +// long double t,w,r_head, r_tail; +// t = (long double)y[2] + (long double)y[1]; +// w = (long double)y[0]; +// r_head = t+w; +// r_tail = w - (r_head - t); +// +// e0 The exponent of x[0]. Must be <= 16360 or you need to +// expand the ipio2 table. +// +// prec an integer indicating the precision: +// 0 24 bits (single) +// 1 53 bits (double) +// 2 64 bits (extended) +// 3 113 bits (quad) +// +// Here is the description of some local variables: +// +// jk jk+1 is the initial number of terms of ipio2[] needed +// in the computation. The minimum and recommended value +// for jk is 3,4,4,6 for single, double, extended, and quad. +// jk+1 must be 2 larger than you might expect so that our +// recomputation test works. (Up to 24 bits in the integer +// part (the 24 bits of it that we compute) and 23 bits in +// the fraction part may be lost to cancelation before we +// recompute.) +// +// jz local integer variable indicating the number of +// terms of ipio2[] used. +// +// jx nx - 1 +// +// jv index for pointing to the suitable ipio2[] for the +// computation. In general, we want +// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 +// is an integer. Thus +// e0-3-24*jv >= 0 or (e0-3)/24 >= jv +// Hence jv = max(0,(e0-3)/24). +// +// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. +// +// q[] double array with integral value, representing the +// 24-bits chunk of the product of x and 2/pi. +// +// q0 the corresponding exponent of q[0]. Note that the +// exponent for q[i] would be q0-24*i. +// +// PIo2[] double precision array, obtained by cutting pi/2 +// into 24 bits chunks. +// +// f[] ipio2[] in floating point +// +// iq[] integer array by breaking up q[] in 24-bits chunk. +// +// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] +// +// ih integer. If >0 it indicates q[] is >= 0.5, hence +// it also indicates the *sign* of the result. + +/// Return the last three digits of N with y = x - N*pi/2 +/// so that |y| < pi/2. +/// +/// The method is to compute the integer (mod 8) and fraction parts of +/// (2/pi)*x without doing the full multiplication. In general we +/// skip the part of the product that are known to be a huge integer ( +/// more accurately, = 0 mod 8 ). Thus the number of operations are +/// independent of the exponent of the input. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { + let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 + let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) + + if cfg!(target_pointer_width = "64") { + debug_assert!(e0 <= 16360); + } + + let nx = x.len(); + + let mut fw: f64; + let mut n: i32; + let mut ih: i32; + let mut z: f64; + let mut f: [f64; 20] = [0.; 20]; + let mut fq: [f64; 20] = [0.; 20]; + let mut q: [f64; 20] = [0.; 20]; + let mut iq: [i32; 20] = [0; 20]; + + /* initialize jk*/ + let jk = i!(INIT_JK, prec); + let jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + let jx = nx - 1; + let mut jv = div!(e0 - 3, 24); + if jv < 0 { + jv = 0; + } + let mut q0 = e0 - 24 * (jv + 1); + let jv = jv as usize; + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + let mut j = (jv as i32) - (jx as i32); + let m = jx + jk; + for i in 0..=m { + i!(f, i, =, if j < 0 { + 0. + } else { + i!(IPIO2, j as usize) as f64 + }); + j += 1; + } + + /* compute q[0],q[1],...q[jk] */ + for i in 0..=jk { + fw = 0f64; + for j in 0..=jx { + fw += i!(x, j) * i!(f, jx + i - j); + } + i!(q, i, =, fw); + } + + let mut jz = jk; + + 'recompute: loop { + /* distill q[] into iq[] reversingly */ + let mut i = 0i32; + z = i!(q, jz); + for j in (1..=jz).rev() { + fw = (x1p_24 * z) as i32 as f64; + i!(iq, i as usize, =, (z - x1p24 * fw) as i32); + z = i!(q, j - 1) + fw; + i += 1; + } + + /* compute n */ + z = scalbn(z, q0); /* actual value of z */ + z -= 8.0 * floor(z * 0.125); /* trim off integer >= 8 */ + n = z as i32; + z -= n as f64; + ih = 0; + if q0 > 0 { + /* need iq[jz-1] to determine n */ + i = i!(iq, jz - 1) >> (24 - q0); + n += i; + i!(iq, jz - 1, -=, i << (24 - q0)); + ih = i!(iq, jz - 1) >> (23 - q0); + } else if q0 == 0 { + ih = i!(iq, jz - 1) >> 23; + } else if z >= 0.5 { + ih = 2; + } + + if ih > 0 { + /* q > 0.5 */ + n += 1; + let mut carry = 0i32; + for i in 0..jz { + /* compute 1-q */ + let j = i!(iq, i); + if carry == 0 { + if j != 0 { + carry = 1; + i!(iq, i, =, 0x1000000 - j); + } + } else { + i!(iq, i, =, 0xffffff - j); + } + } + if q0 > 0 { + /* rare case: chance is 1 in 12 */ + match q0 { + 1 => { + i!(iq, jz - 1, &=, 0x7fffff); + } + 2 => { + i!(iq, jz - 1, &=, 0x3fffff); + } + _ => {} + } + } + if ih == 2 { + z = 1. - z; + if carry != 0 { + z -= scalbn(1., q0); + } + } + } + + /* check if recomputation is needed */ + if z == 0. { + let mut j = 0; + for i in (jk..=jz - 1).rev() { + j |= i!(iq, i); + } + if j == 0 { + /* need recomputation */ + let mut k = 1; + while i!(iq, jk - k, ==, 0) { + k += 1; /* k = no. of terms needed */ + } + + for i in (jz + 1)..=(jz + k) { + /* add q[jz+1] to q[jz+k] */ + i!(f, jx + i, =, i!(IPIO2, jv + i) as f64); + fw = 0f64; + for j in 0..=jx { + fw += i!(x, j) * i!(f, jx + i - j); + } + i!(q, i, =, fw); + } + jz += k; + continue 'recompute; + } + } + + break; + } + + /* chop off zero terms */ + if z == 0. { + jz -= 1; + q0 -= 24; + while i!(iq, jz) == 0 { + jz -= 1; + q0 -= 24; + } + } else { + /* break z into 24-bit if necessary */ + z = scalbn(z, -q0); + if z >= x1p24 { + fw = (x1p_24 * z) as i32 as f64; + i!(iq, jz, =, (z - x1p24 * fw) as i32); + jz += 1; + q0 += 24; + i!(iq, jz, =, fw as i32); + } else { + i!(iq, jz, =, z as i32); + } + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(1., q0); + for i in (0..=jz).rev() { + i!(q, i, =, fw * (i!(iq, i) as f64)); + fw *= x1p_24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for i in (0..=jz).rev() { + fw = 0f64; + let mut k = 0; + while (k <= jp) && (k <= jz - i) { + fw += i!(PIO2, k) * i!(q, i + k); + k += 1; + } + i!(fq, jz - i, =, fw); + } + + /* compress fq[] into y[] */ + match prec { + 0 => { + fw = 0f64; + for i in (0..=jz).rev() { + fw += i!(fq, i); + } + i!(y, 0, =, if ih == 0 { fw } else { -fw }); + } + 1 | 2 => { + fw = 0f64; + for i in (0..=jz).rev() { + fw += i!(fq, i); + } + i!(y, 0, =, if ih == 0 { fw } else { -fw }); + fw = i!(fq, 0) - fw; + for i in 1..=jz { + fw += i!(fq, i); + } + i!(y, 1, =, if ih == 0 { fw } else { -fw }); + } + 3 => { + /* painful */ + for i in (1..=jz).rev() { + fw = i!(fq, i - 1) + i!(fq, i); + i!(fq, i, +=, i!(fq, i - 1) - fw); + i!(fq, i - 1, =, fw); + } + for i in (2..=jz).rev() { + fw = i!(fq, i - 1) + i!(fq, i); + i!(fq, i, +=, i!(fq, i - 1) - fw); + i!(fq, i - 1, =, fw); + } + fw = 0f64; + for i in (2..=jz).rev() { + fw += i!(fq, i); + } + if ih == 0 { + i!(y, 0, =, i!(fq, 0)); + i!(y, 1, =, i!(fq, 1)); + i!(y, 2, =, fw); + } else { + i!(y, 0, =, -i!(fq, 0)); + i!(y, 1, =, -i!(fq, 1)); + i!(y, 2, =, -fw); + } + } + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => {} + } + n & 7 +} diff --git a/library/compiler-builtins/libm/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/libm/src/math/rem_pio2f.rs new file mode 100644 index 00000000000..3c658fe3dbc --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/rem_pio2f.rs @@ -0,0 +1,67 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f64; + +use super::rem_pio2_large; + +const TOINT: f64 = 1.5 / f64::EPSILON; + +/// 53 bits of 2/pi +const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +/// first 25 bits of pi/2 +const PIO2_1: f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ +/// pi/2 - pio2_1 +const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + +/// Return the remainder of x rem pi/2 in *y +/// +/// use double precision for everything except passing x +/// use __rem_pio2_large() for large x +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { + let x64 = x as f64; + + let mut tx: [f64; 1] = [0.]; + let mut ty: [f64; 1] = [0.]; + + let ix = x.to_bits() & 0x7fffffff; + /* 25+53 bit pi is good enough for medium size */ + if ix < 0x4dc90fdb { + /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + let tmp = x64 * INV_PIO2 + TOINT; + // force rounding of tmp to it's storage format on x87 to avoid + // excess precision issues. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let tmp = force_eval!(tmp); + let f_n = tmp - TOINT; + return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); + } + if ix >= 0x7f800000 { + /* x is inf or NaN */ + return (0, x64 - x64); + } + /* scale x into [2^23, 2^24-1] */ + let sign = (x.to_bits() >> 31) != 0; + let e0 = ((ix >> 23) - (0x7f + 23)) as i32; /* e0 = ilogb(|x|)-23, positive */ + tx[0] = f32::from_bits(ix - (e0 << 23) as u32) as f64; + let n = rem_pio2_large(&tx, &mut ty, e0, 0); + if sign { + return (-n, -ty[0]); + } + (n, ty[0]) +} diff --git a/library/compiler-builtins/libm/libm/src/math/remainder.rs b/library/compiler-builtins/libm/libm/src/math/remainder.rs new file mode 100644 index 00000000000..9e966c9ed7f --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/remainder.rs @@ -0,0 +1,5 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remainder(x: f64, y: f64) -> f64 { + let (result, _) = super::remquo(x, y); + result +} diff --git a/library/compiler-builtins/libm/libm/src/math/remainderf.rs b/library/compiler-builtins/libm/libm/src/math/remainderf.rs new file mode 100644 index 00000000000..b1407cf2ace --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/remainderf.rs @@ -0,0 +1,5 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remainderf(x: f32, y: f32) -> f32 { + let (result, _) = super::remquof(x, y); + result +} diff --git a/library/compiler-builtins/libm/libm/src/math/remquo.rs b/library/compiler-builtins/libm/libm/src/math/remquo.rs new file mode 100644 index 00000000000..4c11e848746 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/remquo.rs @@ -0,0 +1,106 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { + let ux: u64 = x.to_bits(); + let mut uy: u64 = y.to_bits(); + let mut ex = ((ux >> 52) & 0x7ff) as i32; + let mut ey = ((uy >> 52) & 0x7ff) as i32; + let sx = (ux >> 63) != 0; + let sy = (uy >> 63) != 0; + let mut q: u32; + let mut i: u64; + let mut uxi: u64 = ux; + + if (uy << 1) == 0 || y.is_nan() || ex == 0x7ff { + return ((x * y) / (x * y), 0); + } + if (ux << 1) == 0 { + return (x, 0); + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 12; + while (i >> 63) == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= (!0) >> 12; + uxi |= 1 << 52; + } + if ey == 0 { + i = uy << 12; + while (i >> 63) == 0 { + ey -= 1; + i <<= 1; + } + uy <<= -ey + 1; + } else { + uy &= (!0) >> 12; + uy |= 1 << 52; + } + + q = 0; + + if ex + 1 != ey { + if ex < ey { + return (x, 0); + } + /* x mod y */ + while ex > ey { + i = uxi.wrapping_sub(uy); + if (i >> 63) == 0 { + uxi = i; + q += 1; + } + uxi <<= 1; + q <<= 1; + ex -= 1; + } + i = uxi.wrapping_sub(uy); + if (i >> 63) == 0 { + uxi = i; + q += 1; + } + if uxi == 0 { + ex = -60; + } else { + while (uxi >> 52) == 0 { + uxi <<= 1; + ex -= 1; + } + } + } + + /* scale result and decide between |x| and |x|-|y| */ + if ex > 0 { + uxi -= 1 << 52; + uxi |= (ex as u64) << 52; + } else { + uxi >>= -ex + 1; + } + x = f64::from_bits(uxi); + if sy { + y = -y; + } + if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { + x -= y; + // TODO: this matches musl behavior, but it is incorrect + q = q.wrapping_add(1); + } + q &= 0x7fffffff; + let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; + if sx { (-x, quo) } else { (x, quo) } +} + +#[cfg(test)] +mod tests { + use super::remquo; + + #[test] + fn test_q_overflow() { + // 0xc000000000000001, 0x04c0000000000004 + let _ = remquo(-2.0000000000000004, 8.406091369059082e-286); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/remquof.rs b/library/compiler-builtins/libm/libm/src/math/remquof.rs new file mode 100644 index 00000000000..b0e85ca6611 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/remquof.rs @@ -0,0 +1,93 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { + let ux: u32 = x.to_bits(); + let mut uy: u32 = y.to_bits(); + let mut ex = ((ux >> 23) & 0xff) as i32; + let mut ey = ((uy >> 23) & 0xff) as i32; + let sx = (ux >> 31) != 0; + let sy = (uy >> 31) != 0; + let mut q: u32; + let mut i: u32; + let mut uxi: u32 = ux; + + if (uy << 1) == 0 || y.is_nan() || ex == 0xff { + return ((x * y) / (x * y), 0); + } + if (ux << 1) == 0 { + return (x, 0); + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 9; + while (i >> 31) == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= (!0) >> 9; + uxi |= 1 << 23; + } + if ey == 0 { + i = uy << 9; + while (i >> 31) == 0 { + ey -= 1; + i <<= 1; + } + uy <<= -ey + 1; + } else { + uy &= (!0) >> 9; + uy |= 1 << 23; + } + + q = 0; + if ex + 1 != ey { + if ex < ey { + return (x, 0); + } + /* x mod y */ + while ex > ey { + i = uxi.wrapping_sub(uy); + if (i >> 31) == 0 { + uxi = i; + q += 1; + } + uxi <<= 1; + q <<= 1; + ex -= 1; + } + i = uxi.wrapping_sub(uy); + if (i >> 31) == 0 { + uxi = i; + q += 1; + } + if uxi == 0 { + ex = -30; + } else { + while (uxi >> 23) == 0 { + uxi <<= 1; + ex -= 1; + } + } + } + + /* scale result and decide between |x| and |x|-|y| */ + if ex > 0 { + uxi -= 1 << 23; + uxi |= (ex as u32) << 23; + } else { + uxi >>= -ex + 1; + } + x = f32::from_bits(uxi); + if sy { + y = -y; + } + if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { + x -= y; + q += 1; + } + q &= 0x7fffffff; + let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; + if sx { (-x, quo) } else { (x, quo) } +} diff --git a/library/compiler-builtins/libm/libm/src/math/rint.rs b/library/compiler-builtins/libm/libm/src/math/rint.rs new file mode 100644 index 00000000000..e1c32c94355 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/rint.rs @@ -0,0 +1,51 @@ +use super::support::Round; + +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf16(x: f16) -> f16 { + select_implementation! { + name: rintf16, + use_arch: all(target_arch = "aarch64", target_feature = "fp16"), + args: x, + } + + super::generic::rint_round(x, Round::Nearest).val +} + +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf(x: f32) -> f32 { + select_implementation! { + name: rintf, + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + all(target_arch = "wasm32", intrinsics_enabled), + ), + args: x, + } + + super::generic::rint_round(x, Round::Nearest).val +} + +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rint(x: f64) -> f64 { + select_implementation! { + name: rint, + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + all(target_arch = "wasm32", intrinsics_enabled), + ), + args: x, + } + + super::generic::rint_round(x, Round::Nearest).val +} + +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf128(x: f128) -> f128 { + super::generic::rint_round(x, Round::Nearest).val +} diff --git a/library/compiler-builtins/libm/libm/src/math/round.rs b/library/compiler-builtins/libm/libm/src/math/round.rs new file mode 100644 index 00000000000..6cd091cd73c --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/round.rs @@ -0,0 +1,25 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf16(x: f16) -> f16 { + super::generic::round(x) +} + +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf(x: f32) -> f32 { + super::generic::round(x) +} + +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn round(x: f64) -> f64 { + super::generic::round(x) +} + +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf128(x: f128) -> f128 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/libm/src/math/roundeven.rs new file mode 100644 index 00000000000..6e621d7628f --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/roundeven.rs @@ -0,0 +1,36 @@ +use super::support::{Float, Round}; + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf16(x: f16) -> f16 { + roundeven_impl(x) +} + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf(x: f32) -> f32 { + roundeven_impl(x) +} + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundeven(x: f64) -> f64 { + roundeven_impl(x) +} + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf128(x: f128) -> f128 { + roundeven_impl(x) +} + +#[inline] +pub fn roundeven_impl(x: F) -> F { + super::generic::rint_round(x, Round::Nearest).val +} diff --git a/library/compiler-builtins/libm/libm/src/math/roundf.rs b/library/compiler-builtins/libm/libm/src/math/roundf.rs new file mode 100644 index 00000000000..b5d7c9d693e --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/roundf.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf(x: f32) -> f32 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/libm/src/math/roundf128.rs b/library/compiler-builtins/libm/libm/src/math/roundf128.rs new file mode 100644 index 00000000000..fc3164929fe --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/roundf128.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf128(x: f128) -> f128 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/libm/src/math/roundf16.rs b/library/compiler-builtins/libm/libm/src/math/roundf16.rs new file mode 100644 index 00000000000..8b356eaabee --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/roundf16.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf16(x: f16) -> f16 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/libm/src/math/scalbn.rs new file mode 100644 index 00000000000..ed73c3f94f0 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/scalbn.rs @@ -0,0 +1,87 @@ +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf16(x: f16, n: i32) -> f16 { + super::generic::scalbn(x, n) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf(x: f32, n: i32) -> f32 { + super::generic::scalbn(x, n) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbn(x: f64, n: i32) -> f64 { + super::generic::scalbn(x, n) +} + +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf128(x: f128, n: i32) -> f128 { + super::generic::scalbn(x, n) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{CastFrom, CastInto, Float}; + + // Tests against N3220 + fn spec_test(f: impl Fn(F, i32) -> F) + where + u32: CastInto, + F::Int: CastFrom, + F::Int: CastFrom, + { + // `scalbn(±0, n)` returns `±0`. + assert_biteq!(f(F::NEG_ZERO, 10), F::NEG_ZERO); + assert_biteq!(f(F::NEG_ZERO, 0), F::NEG_ZERO); + assert_biteq!(f(F::NEG_ZERO, -10), F::NEG_ZERO); + assert_biteq!(f(F::ZERO, 10), F::ZERO); + assert_biteq!(f(F::ZERO, 0), F::ZERO); + assert_biteq!(f(F::ZERO, -10), F::ZERO); + + // `scalbn(x, 0)` returns `x`. + assert_biteq!(f(F::MIN, 0), F::MIN); + assert_biteq!(f(F::MAX, 0), F::MAX); + assert_biteq!(f(F::INFINITY, 0), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY, 0), F::NEG_INFINITY); + assert_biteq!(f(F::ZERO, 0), F::ZERO); + assert_biteq!(f(F::NEG_ZERO, 0), F::NEG_ZERO); + + // `scalbn(±∞, n)` returns `±∞`. + assert_biteq!(f(F::INFINITY, 10), F::INFINITY); + assert_biteq!(f(F::INFINITY, -10), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY, 10), F::NEG_INFINITY); + assert_biteq!(f(F::NEG_INFINITY, -10), F::NEG_INFINITY); + + // NaN should remain NaNs. + assert!(f(F::NAN, 10).is_nan()); + assert!(f(F::NAN, 0).is_nan()); + assert!(f(F::NAN, -10).is_nan()); + assert!(f(-F::NAN, 10).is_nan()); + assert!(f(-F::NAN, 0).is_nan()); + assert!(f(-F::NAN, -10).is_nan()); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_test_f16() { + spec_test::(scalbnf16); + } + + #[test] + fn spec_test_f32() { + spec_test::(scalbnf); + } + + #[test] + fn spec_test_f64() { + spec_test::(scalbn); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_test_f128() { + spec_test::(scalbnf128); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/libm/src/math/scalbnf.rs new file mode 100644 index 00000000000..57e7ba76f60 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/scalbnf.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf(x: f32, n: i32) -> f32 { + super::generic::scalbn(x, n) +} diff --git a/library/compiler-builtins/libm/libm/src/math/scalbnf128.rs b/library/compiler-builtins/libm/libm/src/math/scalbnf128.rs new file mode 100644 index 00000000000..c1d2b485585 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/scalbnf128.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf128(x: f128, n: i32) -> f128 { + super::generic::scalbn(x, n) +} diff --git a/library/compiler-builtins/libm/libm/src/math/scalbnf16.rs b/library/compiler-builtins/libm/libm/src/math/scalbnf16.rs new file mode 100644 index 00000000000..2209e1a1795 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/scalbnf16.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf16(x: f16, n: i32) -> f16 { + super::generic::scalbn(x, n) +} diff --git a/library/compiler-builtins/libm/libm/src/math/sin.rs b/library/compiler-builtins/libm/libm/src/math/sin.rs new file mode 100644 index 00000000000..229fa4bef08 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/sin.rs @@ -0,0 +1,95 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +use super::{k_cos, k_sin, rem_pio2}; + +// sin(x) +// Return sine function of x. +// +// kernel function: +// k_sin ... sine function on [-pi/4,pi/4] +// k_cos ... cose function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded + +/// The sine of `x` (f64). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sin(x: f64) -> f64 { + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 + + /* High word of x. */ + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e500000 { + /* |x| < 2**-26 */ + /* raise inexact if x != 0 and underflow if subnormal*/ + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return x; + } + return k_sin(x, 0.0, 0); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + match n & 3 { + 0 => k_sin(y0, y1, 1), + 1 => k_cos(y0, y1), + 2 => -k_sin(y0, y1, 1), + _ => -k_cos(y0, y1), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg_attr(x86_no_sse, ignore = "FIXME(i586): possible incorrect rounding")] + fn test_near_pi() { + let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 + let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 + assert_eq!(sin(x), sx); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/sincos.rs b/library/compiler-builtins/libm/libm/src/math/sincos.rs new file mode 100644 index 00000000000..ebf482f2df3 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/sincos.rs @@ -0,0 +1,137 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{get_high_word, k_cos, k_sin, rem_pio2}; + +/// Both the sine and cosine of `x` (f64). +/// +/// `x` is specified in radians and the return value is (sin(x), cos(x)). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sincos(x: f64) -> (f64, f64) { + let s: f64; + let c: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + /* if |x| < 2**-27 * sqrt(2) */ + if ix < 0x3e46a09e { + /* raise inexact if x!=0 and underflow if subnormal */ + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return (x, 1.0); + } + return (k_sin(x, 0.0, 0), k_cos(x, 0.0)); + } + + /* sincos(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + let rv = x - x; + return (rv, rv); + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + s = k_sin(y0, y1, 1); + c = k_cos(y0, y1); + match n & 3 { + 0 => (s, c), + 1 => (c, -s), + 2 => (-s, -c), + 3 => (-c, s), + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => (0.0, 1.0), + } +} + +// These tests are based on those from sincosf.rs +#[cfg(test)] +mod tests { + use super::sincos; + + const TOLERANCE: f64 = 1e-6; + + #[test] + fn with_pi() { + let (s, c) = sincos(core::f64::consts::PI); + assert!( + (s - 0.0).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + 0.0, + (s - 0.0).abs(), + TOLERANCE + ); + assert!( + (c + 1.0).abs() < TOLERANCE, + "|{} + {}| = {} >= {}", + c, + 1.0, + (s + 1.0).abs(), + TOLERANCE + ); + } + + #[test] + fn rotational_symmetry() { + use core::f64::consts::PI; + const N: usize = 24; + for n in 0..N { + let theta = 2. * PI * (n as f64) / (N as f64); + let (s, c) = sincos(theta); + let (s_plus, c_plus) = sincos(theta + 2. * PI); + let (s_minus, c_minus) = sincos(theta - 2. * PI); + + assert!( + (s - s_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_plus, + (s - s_plus).abs(), + TOLERANCE + ); + assert!( + (s - s_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_minus, + (s - s_minus).abs(), + TOLERANCE + ); + assert!( + (c - c_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_plus, + (c - c_plus).abs(), + TOLERANCE + ); + assert!( + (c - c_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_minus, + (c - c_minus).abs(), + TOLERANCE + ); + } + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/libm/src/math/sincosf.rs new file mode 100644 index 00000000000..f3360767683 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/sincosf.rs @@ -0,0 +1,176 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{k_cosf, k_sinf, rem_pio2f}; + +/* Small multiples of pi/2 rounded to double precision. */ +const PI_2: f64 = 0.5 * 3.1415926535897931160E+00; +const S1PIO2: f64 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2PIO2: f64 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ +const S3PIO2: f64 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4PIO2: f64 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ + +/// Both the sine and cosine of `x` (f32). +/// +/// `x` is specified in radians and the return value is (sin(x), cos(x)). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sincosf(x: f32) -> (f32, f32) { + let s: f32; + let c: f32; + let mut ix: u32; + let sign: bool; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + /* |x| ~<= pi/4 */ + if ix <= 0x3f490fda { + /* |x| < 2**-12 */ + if ix < 0x39800000 { + /* raise inexact if x!=0 and underflow if subnormal */ + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120 == 2^120 + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return (x, 1.0); + } + return (k_sinf(x as f64), k_cosf(x as f64)); + } + + /* |x| ~<= 5*pi/4 */ + if ix <= 0x407b53d1 { + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + if sign { + s = -k_cosf(x as f64 + S1PIO2); + c = k_sinf(x as f64 + S1PIO2); + } else { + s = k_cosf(S1PIO2 - x as f64); + c = k_sinf(S1PIO2 - x as f64); + } + } + /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ + else if sign { + s = -k_sinf(x as f64 + S2PIO2); + c = -k_cosf(x as f64 + S2PIO2); + } else { + s = -k_sinf(x as f64 - S2PIO2); + c = -k_cosf(x as f64 - S2PIO2); + } + + return (s, c); + } + + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40e231d5 { + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + if sign { + s = k_cosf(x as f64 + S3PIO2); + c = -k_sinf(x as f64 + S3PIO2); + } else { + s = -k_cosf(x as f64 - S3PIO2); + c = k_sinf(x as f64 - S3PIO2); + } + } else if sign { + s = k_sinf(x as f64 + S4PIO2); + c = k_cosf(x as f64 + S4PIO2); + } else { + s = k_sinf(x as f64 - S4PIO2); + c = k_cosf(x as f64 - S4PIO2); + } + + return (s, c); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + let rv = x - x; + return (rv, rv); + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + s = k_sinf(y); + c = k_cosf(y); + match n & 3 { + 0 => (s, c), + 1 => (c, -s), + 2 => (-s, -c), + 3 => (-c, s), + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => (0.0, 1.0), + } +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::sincosf; + + #[test] + fn rotational_symmetry() { + use core::f32::consts::PI; + const N: usize = 24; + for n in 0..N { + let theta = 2. * PI * (n as f32) / (N as f32); + let (s, c) = sincosf(theta); + let (s_plus, c_plus) = sincosf(theta + 2. * PI); + let (s_minus, c_minus) = sincosf(theta - 2. * PI); + + const TOLERANCE: f32 = 1e-6; + assert!( + (s - s_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_plus, + (s - s_plus).abs(), + TOLERANCE + ); + assert!( + (s - s_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_minus, + (s - s_minus).abs(), + TOLERANCE + ); + assert!( + (c - c_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_plus, + (c - c_plus).abs(), + TOLERANCE + ); + assert!( + (c - c_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_minus, + (c - c_minus).abs(), + TOLERANCE + ); + } + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/sinf.rs b/library/compiler-builtins/libm/libm/src/math/sinf.rs new file mode 100644 index 00000000000..b8fae2c9801 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/sinf.rs @@ -0,0 +1,88 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f64::consts::FRAC_PI_2; + +use super::{k_cosf, k_sinf, rem_pio2f}; + +/* Small multiples of pi/2 rounded to double precision. */ +const S1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +/// The sine of `x` (f32). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sinf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); + return x; + } + return k_sinf(x64); + } + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + if sign { + return -k_cosf(x64 + S1_PIO2); + } else { + return k_cosf(x64 - S1_PIO2); + } + } + return k_sinf(if sign { -(x64 + S2_PIO2) } else { -(x64 - S2_PIO2) }); + } + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + if sign { + return k_cosf(x64 + S3_PIO2); + } else { + return -k_cosf(x64 - S3_PIO2); + } + } + return k_sinf(if sign { x64 + S4_PIO2 } else { x64 - S4_PIO2 }); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x - x; + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + match n & 3 { + 0 => k_sinf(y), + 1 => k_cosf(y), + 2 => k_sinf(-y), + _ => -k_cosf(y), + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/sinh.rs b/library/compiler-builtins/libm/libm/src/math/sinh.rs new file mode 100644 index 00000000000..79184198263 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/sinh.rs @@ -0,0 +1,51 @@ +use super::{expm1, expo2}; + +// sinh(x) = (exp(x) - 1/exp(x))/2 +// = (exp(x)-1 + (exp(x)-1)/exp(x))/2 +// = x + x^3/6 + o(x^5) +// + +/// The hyperbolic sine of `x` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sinh(x: f64) -> f64 { + // union {double f; uint64_t i;} u = {.f = x}; + // uint32_t w; + // double t, h, absx; + + let mut uf: f64 = x; + let mut ui: u64 = f64::to_bits(uf); + let w: u32; + let t: f64; + let mut h: f64; + let absx: f64; + + h = 0.5; + if ui >> 63 != 0 { + h = -h; + } + /* |x| */ + ui &= !1 / 2; + uf = f64::from_bits(ui); + absx = uf; + w = (ui >> 32) as u32; + + /* |x| < log(DBL_MAX) */ + if w < 0x40862e42 { + t = expm1(absx); + if w < 0x3ff00000 { + if w < 0x3ff00000 - (26 << 20) { + /* note: inexact and underflow are raised by expm1 */ + /* note: this branch avoids spurious underflow */ + return x; + } + return h * (2.0 * t - t * t / (t + 1.0)); + } + /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ + return h * (t + t / (t + 1.0)); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = 2.0 * h * expo2(absx); + t +} diff --git a/library/compiler-builtins/libm/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/libm/src/math/sinhf.rs new file mode 100644 index 00000000000..44d2e3560d5 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/sinhf.rs @@ -0,0 +1,30 @@ +use super::{expm1f, k_expo2f}; + +/// The hyperbolic sine of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sinhf(x: f32) -> f32 { + let mut h = 0.5f32; + let mut ix = x.to_bits(); + if (ix >> 31) != 0 { + h = -h; + } + /* |x| */ + ix &= 0x7fffffff; + let absx = f32::from_bits(ix); + let w = ix; + + /* |x| < log(FLT_MAX) */ + if w < 0x42b17217 { + let t = expm1f(absx); + if w < 0x3f800000 { + if w < (0x3f800000 - (12 << 23)) { + return x; + } + return h * (2. * t - t * t / (t + 1.)); + } + return h * (t + t / (t + 1.)); + } + + /* |x| > logf(FLT_MAX) or nan */ + 2. * h * k_expo2f(absx) +} diff --git a/library/compiler-builtins/libm/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/libm/src/math/sqrt.rs new file mode 100644 index 00000000000..76bc240cf01 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/sqrt.rs @@ -0,0 +1,51 @@ +/// The square root of `x` (f16). +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf16(x: f16) -> f16 { + select_implementation! { + name: sqrtf16, + use_arch: all(target_arch = "aarch64", target_feature = "fp16"), + args: x, + } + + return super::generic::sqrt(x); +} + +/// The square root of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf(x: f32) -> f32 { + select_implementation! { + name: sqrtf, + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + all(target_arch = "wasm32", intrinsics_enabled), + target_feature = "sse2" + ), + args: x, + } + + super::generic::sqrt(x) +} + +/// The square root of `x` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrt(x: f64) -> f64 { + select_implementation! { + name: sqrt, + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + all(target_arch = "wasm32", intrinsics_enabled), + target_feature = "sse2" + ), + args: x, + } + + super::generic::sqrt(x) +} + +/// The square root of `x` (f128). +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf128(x: f128) -> f128 { + return super::generic::sqrt(x); +} diff --git a/library/compiler-builtins/libm/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/libm/src/math/sqrtf.rs new file mode 100644 index 00000000000..c28a705e378 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/sqrtf.rs @@ -0,0 +1,15 @@ +/// The square root of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf(x: f32) -> f32 { + select_implementation! { + name: sqrtf, + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + all(target_arch = "wasm32", intrinsics_enabled), + target_feature = "sse2" + ), + args: x, + } + + super::generic::sqrt(x) +} diff --git a/library/compiler-builtins/libm/libm/src/math/sqrtf128.rs b/library/compiler-builtins/libm/libm/src/math/sqrtf128.rs new file mode 100644 index 00000000000..eaef6ae0c1c --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/sqrtf128.rs @@ -0,0 +1,5 @@ +/// The square root of `x` (f128). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf128(x: f128) -> f128 { + return super::generic::sqrt(x); +} diff --git a/library/compiler-builtins/libm/libm/src/math/sqrtf16.rs b/library/compiler-builtins/libm/libm/src/math/sqrtf16.rs new file mode 100644 index 00000000000..7bedb7f8bbb --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/sqrtf16.rs @@ -0,0 +1,11 @@ +/// The square root of `x` (f16). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf16(x: f16) -> f16 { + select_implementation! { + name: sqrtf16, + use_arch: all(target_arch = "aarch64", target_feature = "fp16"), + args: x, + } + + return super::generic::sqrt(x); +} diff --git a/library/compiler-builtins/libm/libm/src/math/support/big.rs b/library/compiler-builtins/libm/libm/src/math/support/big.rs new file mode 100644 index 00000000000..eae08238e09 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/support/big.rs @@ -0,0 +1,239 @@ +//! Integers used for wide operations, larger than `u128`. + +#[cfg(test)] +mod tests; + +use core::ops; + +use super::{DInt, HInt, Int, MinInt}; + +const U128_LO_MASK: u128 = u64::MAX as u128; + +/// A 256-bit unsigned integer represented as two 128-bit native-endian limbs. +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +pub struct u256 { + pub lo: u128, + pub hi: u128, +} + +impl u256 { + #[cfg(any(test, feature = "unstable-public-internals"))] + pub const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX }; + + /// Reinterpret as a signed integer + pub fn signed(self) -> i256 { + i256 { lo: self.lo, hi: self.hi } + } +} + +/// A 256-bit signed integer represented as two 128-bit native-endian limbs. +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +pub struct i256 { + pub lo: u128, + pub hi: u128, +} + +impl i256 { + /// Reinterpret as an unsigned integer + #[cfg(any(test, feature = "unstable-public-internals"))] + pub fn unsigned(self) -> u256 { + u256 { lo: self.lo, hi: self.hi } + } +} + +impl MinInt for u256 { + type OtherSign = i256; + + type Unsigned = u256; + + const SIGNED: bool = false; + const BITS: u32 = 256; + const ZERO: Self = Self { lo: 0, hi: 0 }; + const ONE: Self = Self { lo: 1, hi: 0 }; + const MIN: Self = Self { lo: 0, hi: 0 }; + const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX }; +} + +impl MinInt for i256 { + type OtherSign = u256; + + type Unsigned = u256; + + const SIGNED: bool = false; + const BITS: u32 = 256; + const ZERO: Self = Self { lo: 0, hi: 0 }; + const ONE: Self = Self { lo: 1, hi: 0 }; + const MIN: Self = Self { lo: 0, hi: 1 << 127 }; + const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX << 1 }; +} + +macro_rules! impl_common { + ($ty:ty) => { + impl ops::BitOr for $ty { + type Output = Self; + + fn bitor(mut self, rhs: Self) -> Self::Output { + self.lo |= rhs.lo; + self.hi |= rhs.hi; + self + } + } + + impl ops::Not for $ty { + type Output = Self; + + fn not(mut self) -> Self::Output { + self.lo = !self.lo; + self.hi = !self.hi; + self + } + } + + impl ops::Shl for $ty { + type Output = Self; + + fn shl(self, _rhs: u32) -> Self::Output { + unimplemented!("only used to meet trait bounds") + } + } + }; +} + +impl_common!(i256); +impl_common!(u256); + +impl ops::Add for u256 { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + let (lo, carry) = self.lo.overflowing_add(rhs.lo); + let hi = self.hi.wrapping_add(carry as u128).wrapping_add(rhs.hi); + + Self { lo, hi } + } +} + +impl ops::Shr for u256 { + type Output = Self; + + fn shr(mut self, rhs: u32) -> Self::Output { + debug_assert!(rhs < Self::BITS, "attempted to shift right with overflow"); + if rhs >= Self::BITS { + return Self::ZERO; + } + + if rhs == 0 { + return self; + } + + if rhs < 128 { + self.lo >>= rhs; + self.lo |= self.hi << (128 - rhs); + } else { + self.lo = self.hi >> (rhs - 128); + } + + if rhs < 128 { + self.hi >>= rhs; + } else { + self.hi = 0; + } + + self + } +} + +impl HInt for u128 { + type D = u256; + + fn widen(self) -> Self::D { + u256 { lo: self, hi: 0 } + } + + fn zero_widen(self) -> Self::D { + self.widen() + } + + fn zero_widen_mul(self, rhs: Self) -> Self::D { + let l0 = self & U128_LO_MASK; + let l1 = rhs & U128_LO_MASK; + let h0 = self >> 64; + let h1 = rhs >> 64; + + let p_ll: u128 = l0.overflowing_mul(l1).0; + let p_lh: u128 = l0.overflowing_mul(h1).0; + let p_hl: u128 = h0.overflowing_mul(l1).0; + let p_hh: u128 = h0.overflowing_mul(h1).0; + + let s0 = p_hl + (p_ll >> 64); + let s1 = (p_ll & U128_LO_MASK) + (s0 << 64); + let s2 = p_lh + (s1 >> 64); + + let lo = (p_ll & U128_LO_MASK) + (s2 << 64); + let hi = p_hh + (s0 >> 64) + (s2 >> 64); + + u256 { lo, hi } + } + + fn widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen_mul(rhs) + } + + fn widen_hi(self) -> Self::D { + self.widen() << ::BITS + } +} + +impl HInt for i128 { + type D = i256; + + fn widen(self) -> Self::D { + let mut ret = self.unsigned().zero_widen().signed(); + if self.is_negative() { + ret.hi = u128::MAX; + } + ret + } + + fn zero_widen(self) -> Self::D { + self.unsigned().zero_widen().signed() + } + + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.unsigned().zero_widen_mul(rhs.unsigned()).signed() + } + + fn widen_mul(self, _rhs: Self) -> Self::D { + unimplemented!("signed i128 widening multiply is not used") + } + + fn widen_hi(self) -> Self::D { + self.widen() << ::BITS + } +} + +impl DInt for u256 { + type H = u128; + + fn lo(self) -> Self::H { + self.lo + } + + fn hi(self) -> Self::H { + self.hi + } +} + +impl DInt for i256 { + type H = i128; + + fn lo(self) -> Self::H { + self.lo as i128 + } + + fn hi(self) -> Self::H { + self.hi as i128 + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/libm/src/math/support/big/tests.rs new file mode 100644 index 00000000000..2c71191ba53 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/support/big/tests.rs @@ -0,0 +1,149 @@ +extern crate std; +use std::string::String; +use std::{eprintln, format}; + +use super::{HInt, MinInt, i256, u256}; + +const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; + +/// Print a `u256` as hex since we can't add format implementations +fn hexu(v: u256) -> String { + format!("0x{:032x}{:032x}", v.hi, v.lo) +} + +#[test] +fn widen_u128() { + assert_eq!(u128::MAX.widen(), u256 { lo: u128::MAX, hi: 0 }); + assert_eq!(LOHI_SPLIT.widen(), u256 { lo: LOHI_SPLIT, hi: 0 }); +} + +#[test] +fn widen_i128() { + assert_eq!((-1i128).widen(), u256::MAX.signed()); + assert_eq!((LOHI_SPLIT as i128).widen(), i256 { lo: LOHI_SPLIT, hi: u128::MAX }); + assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); +} + +#[test] +fn widen_mul_u128() { + let tests = [ + (u128::MAX / 2, 2_u128, u256 { lo: u128::MAX - 1, hi: 0 }), + (u128::MAX, 2_u128, u256 { lo: u128::MAX - 1, hi: 1 }), + (u128::MAX, u128::MAX, u256 { lo: 1, hi: u128::MAX - 1 }), + (0, 0, u256::ZERO), + (1234u128, 0, u256::ZERO), + (0, 1234, u256::ZERO), + ]; + + let mut has_errors = false; + let mut add_error = |i, a, b, expected, actual| { + has_errors = true; + eprintln!( + "\ + FAILURE ({i}): {a:#034x} * {b:#034x}\n\ + expected: {}\n\ + got: {}\ + ", + hexu(expected), + hexu(actual) + ); + }; + + for (i, (a, b, exp)) in tests.iter().copied().enumerate() { + let res = a.widen_mul(b); + let res_z = a.zero_widen_mul(b); + assert_eq!(res, res_z); + if res != exp { + add_error(i, a, b, exp, res); + } + } + + assert!(!has_errors); +} + +#[test] +fn not_u256() { + assert_eq!(!u256::ZERO, u256::MAX); +} + +#[test] +fn shr_u256() { + let only_low = [1, u16::MAX.into(), u32::MAX.into(), u64::MAX.into(), u128::MAX]; + let mut has_errors = false; + + let mut add_error = |a, b, expected, actual| { + has_errors = true; + eprintln!( + "\ + FAILURE: {} >> {b}\n\ + expected: {}\n\ + actual: {}\ + ", + hexu(a), + hexu(expected), + hexu(actual), + ); + }; + + for a in only_low { + for perturb in 0..10 { + let a = a.saturating_add(perturb); + for shift in 0..128 { + let res = a.widen() >> shift; + let expected = (a >> shift).widen(); + if res != expected { + add_error(a.widen(), shift, expected, res); + } + } + } + } + + let check = [ + (u256::MAX, 1, u256 { lo: u128::MAX, hi: u128::MAX >> 1 }), + (u256::MAX, 5, u256 { lo: u128::MAX, hi: u128::MAX >> 5 }), + (u256::MAX, 63, u256 { lo: u128::MAX, hi: u64::MAX as u128 | (1 << 64) }), + (u256::MAX, 64, u256 { lo: u128::MAX, hi: u64::MAX as u128 }), + (u256::MAX, 65, u256 { lo: u128::MAX, hi: (u64::MAX >> 1) as u128 }), + (u256::MAX, 127, u256 { lo: u128::MAX, hi: 1 }), + (u256::MAX, 128, u256 { lo: u128::MAX, hi: 0 }), + (u256::MAX, 129, u256 { lo: u128::MAX >> 1, hi: 0 }), + (u256::MAX, 191, u256 { lo: u64::MAX as u128 | 1 << 64, hi: 0 }), + (u256::MAX, 192, u256 { lo: u64::MAX as u128, hi: 0 }), + (u256::MAX, 193, u256 { lo: u64::MAX as u128 >> 1, hi: 0 }), + (u256::MAX, 254, u256 { lo: 0b11, hi: 0 }), + (u256::MAX, 255, u256 { lo: 1, hi: 0 }), + ( + u256 { hi: LOHI_SPLIT, lo: 0 }, + 64, + u256 { lo: 0xffffffffffffffff0000000000000000, hi: 0xaaaaaaaaaaaaaaaa }, + ), + ]; + + for (input, shift, expected) in check { + let res = input >> shift; + if res != expected { + add_error(input, shift, expected, res); + } + } + + assert!(!has_errors); +} + +#[test] +#[should_panic] +#[cfg(debug_assertions)] +// FIXME(ppc): ppc64le seems to have issues with `should_panic` tests. +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +fn shr_u256_overflow() { + // Like regular shr, panic on overflow with debug assertions + let _ = u256::MAX >> 256; +} + +#[test] +#[cfg(not(debug_assertions))] +fn shr_u256_overflow() { + // No panic without debug assertions + assert_eq!(u256::MAX >> 256, u256::ZERO); + assert_eq!(u256::MAX >> 257, u256::ZERO); + assert_eq!(u256::MAX >> u32::MAX, u256::ZERO); +} diff --git a/library/compiler-builtins/libm/libm/src/math/support/env.rs b/library/compiler-builtins/libm/libm/src/math/support/env.rs new file mode 100644 index 00000000000..796309372a5 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/support/env.rs @@ -0,0 +1,127 @@ +//! Support for rounding directions and status flags as specified by IEEE 754. +//! +//! Rust does not support the floating point environment so rounding mode is passed as an argument +//! and status flags are returned as part of the result. There is currently not much support for +//! this; most existing ports from musl use a form of `force_eval!` to raise exceptions, but this +//! has no side effects in Rust. Further, correct behavior relies on elementary operations making +//! use of the correct rounding and raising relevant exceptions, which is not the case for Rust. +//! +//! This module exists so no functionality is lost when porting algorithms that respect floating +//! point environment, and so that some functionality may be tested (that which does not rely on +//! side effects from elementary operations). Full support would require wrappers around basic +//! operations, but there is no plan to add this at the current time. + +/// A value combined with a floating point status. +pub struct FpResult { + pub val: T, + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub status: Status, +} + +impl FpResult { + pub fn new(val: T, status: Status) -> Self { + Self { val, status } + } + + /// Return `val` with `Status::OK`. + pub fn ok(val: T) -> Self { + Self { val, status: Status::OK } + } +} + +/// IEEE 754 rounding mode, excluding the optional `roundTiesToAway` version of nearest. +/// +/// Integer representation comes from what CORE-MATH uses for indexing. +#[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Round { + /// IEEE 754 nearest, `roundTiesToEven`. + Nearest = 0, + /// IEEE 754 `roundTowardNegative`. + Negative = 1, + /// IEEE 754 `roundTowardPositive`. + Positive = 2, + /// IEEE 754 `roundTowardZero`. + Zero = 3, +} + +/// IEEE 754 exception status flags. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Status(u8); + +impl Status { + /// Default status indicating no errors. + pub const OK: Self = Self(0); + + /// No definable result. + /// + /// Includes: + /// - Any ops on sNaN, with a few exceptions. + /// - `0 * inf`, `inf * 0`. + /// - `fma(0, inf, c)` or `fma(inf, 0, c)`, possibly excluding `c = qNaN`. + /// - `+inf + -inf` and similar (includes subtraction and fma). + /// - `0.0 / 0.0`, `inf / inf` + /// - `remainder(x, y)` if `y == 0.0` or `x == inf`, and neither is NaN. + /// - `sqrt(x)` with `x < 0.0`. + pub const INVALID: Self = Self(1); + + /// Division by zero. + /// + /// The default result for division is +/-inf based on operand sign. For `logB`, the default + /// result is -inf. + /// `x / y` when `x != 0.0` and `y == 0.0`, + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub const DIVIDE_BY_ZERO: Self = Self(1 << 2); + + /// The result exceeds the maximum finite value. + /// + /// The default result depends on rounding mode. `Nearest*` rounds to +/- infinity, sign based + /// on the intermediate result. `Zero` rounds to the signed maximum finite. `Positive` and + /// `Negative` round to signed maximum finite in one direction, signed infinity in the other. + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub const OVERFLOW: Self = Self(1 << 3); + + /// The result is subnormal and lost precision. + pub const UNDERFLOW: Self = Self(1 << 4); + + /// The finite-precision result does not match that of infinite precision, and the reason + /// is not represented by one of the other flags. + pub const INEXACT: Self = Self(1 << 5); + + /// True if `UNDERFLOW` is set. + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub const fn underflow(self) -> bool { + self.0 & Self::UNDERFLOW.0 != 0 + } + + /// True if `OVERFLOW` is set. + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub const fn overflow(self) -> bool { + self.0 & Self::OVERFLOW.0 != 0 + } + + pub fn set_underflow(&mut self, val: bool) { + self.set_flag(val, Self::UNDERFLOW); + } + + /// True if `INEXACT` is set. + pub const fn inexact(self) -> bool { + self.0 & Self::INEXACT.0 != 0 + } + + pub fn set_inexact(&mut self, val: bool) { + self.set_flag(val, Self::INEXACT); + } + + fn set_flag(&mut self, val: bool, mask: Self) { + if val { + self.0 |= mask.0; + } else { + self.0 &= !mask.0; + } + } + + pub(crate) const fn with(self, rhs: Self) -> Self { + Self(self.0 | rhs.0) + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/libm/src/math/support/float_traits.rs new file mode 100644 index 00000000000..fac10483237 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/support/float_traits.rs @@ -0,0 +1,484 @@ +use core::{fmt, mem, ops}; + +use super::int_traits::{CastFrom, Int, MinInt}; + +/// Trait for some basic operations on floats +// #[allow(dead_code)] +pub trait Float: + Copy + + fmt::Debug + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::MulAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Rem + + ops::Neg + + 'static +{ + /// A uint of the same width as the float + type Int: Int; + + /// A int of the same width as the float + type SignedInt: Int + + MinInt + + ops::Neg; + + const ZERO: Self; + const NEG_ZERO: Self; + const ONE: Self; + const NEG_ONE: Self; + const INFINITY: Self; + const NEG_INFINITY: Self; + const NAN: Self; + const NEG_NAN: Self; + const MAX: Self; + const MIN: Self; + const EPSILON: Self; + const PI: Self; + const NEG_PI: Self; + const FRAC_PI_2: Self; + + const MIN_POSITIVE_NORMAL: Self; + + /// The bitwidth of the float type + const BITS: u32; + + /// The bitwidth of the significand + const SIG_BITS: u32; + + /// The bitwidth of the exponent + const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; + + /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite + /// representation. + /// + /// This shifted fully right, use `EXP_MASK` for the shifted value. + const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; + + /// The exponent bias value + const EXP_BIAS: u32 = Self::EXP_SAT >> 1; + + /// Maximum unbiased exponent value. + const EXP_MAX: i32 = Self::EXP_BIAS as i32; + + /// Minimum *NORMAL* unbiased exponent value. + const EXP_MIN: i32 = -(Self::EXP_MAX - 1); + + /// Minimum subnormal exponent value. + const EXP_MIN_SUBNORM: i32 = Self::EXP_MIN - Self::SIG_BITS as i32; + + /// A mask for the sign bit + const SIGN_MASK: Self::Int; + + /// A mask for the significand + const SIG_MASK: Self::Int; + + /// A mask for the exponent + const EXP_MASK: Self::Int; + + /// The implicit bit of the float format + const IMPLICIT_BIT: Self::Int; + + /// Returns `self` transmuted to `Self::Int` + fn to_bits(self) -> Self::Int; + + /// Returns `self` transmuted to `Self::SignedInt` + #[allow(dead_code)] + fn to_bits_signed(self) -> Self::SignedInt { + self.to_bits().signed() + } + + /// Check bitwise equality. + #[allow(dead_code)] + fn biteq(self, rhs: Self) -> bool { + self.to_bits() == rhs.to_bits() + } + + /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be + /// represented in multiple different ways. + /// + /// This method returns `true` if two NaNs are compared. Use [`biteq`](Self::biteq) instead + /// if `NaN` should not be treated separately. + #[allow(dead_code)] + fn eq_repr(self, rhs: Self) -> bool { + if self.is_nan() && rhs.is_nan() { true } else { self.biteq(rhs) } + } + + /// Returns true if the value is NaN. + fn is_nan(self) -> bool; + + /// Returns true if the value is +inf or -inf. + fn is_infinite(self) -> bool; + + /// Returns true if the sign is negative. Extracts the sign bit regardless of zero or NaN. + fn is_sign_negative(self) -> bool; + + /// Returns true if the sign is positive. Extracts the sign bit regardless of zero or NaN. + fn is_sign_positive(self) -> bool { + !self.is_sign_negative() + } + + /// Returns if `self` is subnormal. + #[allow(dead_code)] + fn is_subnormal(self) -> bool { + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO + } + + /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. + fn ex(self) -> u32 { + u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_SAT + } + + /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. + fn exp_unbiased(self) -> i32 { + self.ex().signed() - (Self::EXP_BIAS as i32) + } + + /// Returns the significand with no implicit bit (or the "fractional" part) + #[allow(dead_code)] + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIG_MASK + } + + /// Returns a `Self::Int` transmuted back to `Self` + fn from_bits(a: Self::Int) -> Self; + + /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. + fn from_parts(negative: bool, exponent: u32, significand: Self::Int) -> Self { + let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; + Self::from_bits( + (sign << (Self::BITS - 1)) + | (Self::Int::cast_from(exponent & Self::EXP_SAT) << Self::SIG_BITS) + | (significand & Self::SIG_MASK), + ) + } + + #[allow(dead_code)] + fn abs(self) -> Self; + + /// Returns a number composed of the magnitude of self and the sign of sign. + fn copysign(self, other: Self) -> Self; + + /// Fused multiply add, rounding once. + fn fma(self, y: Self, z: Self) -> Self; + + /// Returns (normalized exponent, normalized significand) + #[allow(dead_code)] + fn normalize(significand: Self::Int) -> (i32, Self::Int); + + /// Returns a number that represents the sign of self. + #[allow(dead_code)] + fn signum(self) -> Self { + if self.is_nan() { self } else { Self::ONE.copysign(self) } + } +} + +/// Access the associated `Int` type from a float (helper to avoid ambiguous associated types). +pub type IntTy = ::Int; + +macro_rules! float_impl { + ( + $ty:ident, + $ity:ident, + $sity:ident, + $bits:expr, + $significand_bits:expr, + $from_bits:path, + $to_bits:path, + $fma_fn:ident, + $fma_intrinsic:ident + ) => { + impl Float for $ty { + type Int = $ity; + type SignedInt = $sity; + + const ZERO: Self = 0.0; + const NEG_ZERO: Self = -0.0; + const ONE: Self = 1.0; + const NEG_ONE: Self = -1.0; + const INFINITY: Self = Self::INFINITY; + const NEG_INFINITY: Self = Self::NEG_INFINITY; + const NAN: Self = Self::NAN; + // NAN isn't guaranteed to be positive but it usually is. We only use this for + // tests. + const NEG_NAN: Self = $from_bits($to_bits(Self::NAN) | Self::SIGN_MASK); + const MAX: Self = -Self::MIN; + // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed + const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS)); + const EPSILON: Self = <$ty>::EPSILON; + + // Exponent is a 1 in the LSB + const MIN_POSITIVE_NORMAL: Self = $from_bits(1 << Self::SIG_BITS); + + const PI: Self = core::$ty::consts::PI; + const NEG_PI: Self = -Self::PI; + const FRAC_PI_2: Self = core::$ty::consts::FRAC_PI_2; + + const BITS: u32 = $bits; + const SIG_BITS: u32 = $significand_bits; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; + const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); + const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; + + fn to_bits(self) -> Self::Int { + self.to_bits() + } + fn is_nan(self) -> bool { + self.is_nan() + } + fn is_infinite(self) -> bool { + self.is_infinite() + } + fn is_sign_negative(self) -> bool { + self.is_sign_negative() + } + fn from_bits(a: Self::Int) -> Self { + Self::from_bits(a) + } + fn abs(self) -> Self { + cfg_if! { + // FIXME(msrv): `abs` is available in `core` starting with 1.85. + if #[cfg(intrinsics_enabled)] { + self.abs() + } else { + super::super::generic::fabs(self) + } + } + } + fn copysign(self, other: Self) -> Self { + cfg_if! { + // FIXME(msrv): `copysign` is available in `core` starting with 1.85. + if #[cfg(intrinsics_enabled)] { + self.copysign(other) + } else { + super::super::generic::copysign(self, other) + } + } + } + fn fma(self, y: Self, z: Self) -> Self { + cfg_if! { + // fma is not yet available in `core` + if #[cfg(intrinsics_enabled)] { + unsafe{ core::intrinsics::$fma_intrinsic(self, y, z) } + } else { + super::super::$fma_fn(self, y, z) + } + } + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); + (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) + } + } + }; +} + +#[cfg(f16_enabled)] +float_impl!(f16, u16, i16, 16, 10, f16::from_bits, f16::to_bits, fmaf16, fmaf16); +float_impl!(f32, u32, i32, 32, 23, f32_from_bits, f32_to_bits, fmaf, fmaf32); +float_impl!(f64, u64, i64, 64, 52, f64_from_bits, f64_to_bits, fma, fmaf64); +#[cfg(f128_enabled)] +float_impl!(f128, u128, i128, 128, 112, f128::from_bits, f128::to_bits, fmaf128, fmaf128); + +/* FIXME(msrv): vendor some things that are not const stable at our MSRV */ + +/// `f32::from_bits` +pub const fn f32_from_bits(bits: u32) -> f32 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(bits) } +} + +/// `f32::to_bits` +pub const fn f32_to_bits(x: f32) -> u32 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(x) } +} + +/// `f64::from_bits` +pub const fn f64_from_bits(bits: u64) -> f64 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(bits) } +} + +/// `f64::to_bits` +pub const fn f64_to_bits(x: f64) -> u64 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(x) } +} + +/// Trait for floats twice the bit width of another integer. +pub trait DFloat: Float { + /// Float that is half the bit width of the floatthis trait is implemented for. + type H: HFloat; + + /// Narrow the float type. + fn narrow(self) -> Self::H; +} + +/// Trait for floats half the bit width of another float. +pub trait HFloat: Float { + /// Float that is double the bit width of the float this trait is implemented for. + type D: DFloat; + + /// Widen the float type. + fn widen(self) -> Self::D; +} + +macro_rules! impl_d_float { + ($($X:ident $D:ident),*) => { + $( + impl DFloat for $D { + type H = $X; + + fn narrow(self) -> Self::H { + self as $X + } + } + )* + }; +} + +macro_rules! impl_h_float { + ($($H:ident $X:ident),*) => { + $( + impl HFloat for $H { + type D = $X; + + fn widen(self) -> Self::D { + self as $X + } + } + )* + }; +} + +impl_d_float!(f32 f64); +#[cfg(f16_enabled)] +impl_d_float!(f16 f32); +#[cfg(f128_enabled)] +impl_d_float!(f64 f128); + +impl_h_float!(f32 f64); +#[cfg(f16_enabled)] +impl_h_float!(f16 f32); +#[cfg(f128_enabled)] +impl_h_float!(f64 f128); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(f16_enabled)] + fn check_f16() { + // Constants + assert_eq!(f16::EXP_SAT, 0b11111); + assert_eq!(f16::EXP_BIAS, 15); + assert_eq!(f16::EXP_MAX, 15); + assert_eq!(f16::EXP_MIN, -14); + assert_eq!(f16::EXP_MIN_SUBNORM, -24); + + // `exp_unbiased` + assert_eq!(f16::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f16 / 2.0).exp_unbiased(), -1); + assert_eq!(f16::MAX.exp_unbiased(), 15); + assert_eq!(f16::MIN.exp_unbiased(), 15); + assert_eq!(f16::MIN_POSITIVE.exp_unbiased(), -14); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f16::ZERO.exp_unbiased(), -15); + assert_eq!(f16::from_bits(0x1).exp_unbiased(), -15); + assert_eq!(f16::MIN_POSITIVE, f16::MIN_POSITIVE_NORMAL); + + // `from_parts` + assert_biteq!(f16::from_parts(true, f16::EXP_BIAS, 0), -1.0f16); + assert_biteq!(f16::from_parts(false, 0, 1), f16::from_bits(0x1)); + } + + #[test] + fn check_f32() { + // Constants + assert_eq!(f32::EXP_SAT, 0b11111111); + assert_eq!(f32::EXP_BIAS, 127); + assert_eq!(f32::EXP_MAX, 127); + assert_eq!(f32::EXP_MIN, -126); + assert_eq!(f32::EXP_MIN_SUBNORM, -149); + + // `exp_unbiased` + assert_eq!(f32::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f32 / 2.0).exp_unbiased(), -1); + assert_eq!(f32::MAX.exp_unbiased(), 127); + assert_eq!(f32::MIN.exp_unbiased(), 127); + assert_eq!(f32::MIN_POSITIVE.exp_unbiased(), -126); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f32::ZERO.exp_unbiased(), -127); + assert_eq!(f32::from_bits(0x1).exp_unbiased(), -127); + assert_eq!(f32::MIN_POSITIVE, f32::MIN_POSITIVE_NORMAL); + + // `from_parts` + assert_biteq!(f32::from_parts(true, f32::EXP_BIAS, 0), -1.0f32); + assert_biteq!(f32::from_parts(false, 10 + f32::EXP_BIAS, 0), hf32!("0x1p10")); + assert_biteq!(f32::from_parts(false, 0, 1), f32::from_bits(0x1)); + } + + #[test] + fn check_f64() { + // Constants + assert_eq!(f64::EXP_SAT, 0b11111111111); + assert_eq!(f64::EXP_BIAS, 1023); + assert_eq!(f64::EXP_MAX, 1023); + assert_eq!(f64::EXP_MIN, -1022); + assert_eq!(f64::EXP_MIN_SUBNORM, -1074); + + // `exp_unbiased` + assert_eq!(f64::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f64 / 2.0).exp_unbiased(), -1); + assert_eq!(f64::MAX.exp_unbiased(), 1023); + assert_eq!(f64::MIN.exp_unbiased(), 1023); + assert_eq!(f64::MIN_POSITIVE.exp_unbiased(), -1022); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f64::ZERO.exp_unbiased(), -1023); + assert_eq!(f64::from_bits(0x1).exp_unbiased(), -1023); + assert_eq!(f64::MIN_POSITIVE, f64::MIN_POSITIVE_NORMAL); + + // `from_parts` + assert_biteq!(f64::from_parts(true, f64::EXP_BIAS, 0), -1.0f64); + assert_biteq!(f64::from_parts(false, 10 + f64::EXP_BIAS, 0), hf64!("0x1p10")); + assert_biteq!(f64::from_parts(false, 0, 1), f64::from_bits(0x1)); + } + + #[test] + #[cfg(f128_enabled)] + fn check_f128() { + // Constants + assert_eq!(f128::EXP_SAT, 0b111111111111111); + assert_eq!(f128::EXP_BIAS, 16383); + assert_eq!(f128::EXP_MAX, 16383); + assert_eq!(f128::EXP_MIN, -16382); + assert_eq!(f128::EXP_MIN_SUBNORM, -16494); + + // `exp_unbiased` + assert_eq!(f128::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f128 / 2.0).exp_unbiased(), -1); + assert_eq!(f128::MAX.exp_unbiased(), 16383); + assert_eq!(f128::MIN.exp_unbiased(), 16383); + assert_eq!(f128::MIN_POSITIVE.exp_unbiased(), -16382); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f128::ZERO.exp_unbiased(), -16383); + assert_eq!(f128::from_bits(0x1).exp_unbiased(), -16383); + assert_eq!(f128::MIN_POSITIVE, f128::MIN_POSITIVE_NORMAL); + + // `from_parts` + assert_biteq!(f128::from_parts(true, f128::EXP_BIAS, 0), -1.0f128); + assert_biteq!(f128::from_parts(false, 0, 1), f128::from_bits(0x1)); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/libm/src/math/support/hex_float.rs new file mode 100644 index 00000000000..819e2f56e36 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/support/hex_float.rs @@ -0,0 +1,1155 @@ +//! Utilities for working with hex float formats. + +use core::fmt; + +use super::{Float, Round, Status, f32_from_bits, f64_from_bits}; + +/// Construct a 16-bit float from hex float representation (C-style) +#[cfg(f16_enabled)] +pub const fn hf16(s: &str) -> f16 { + match parse_hex_exact(s, 16, 10) { + Ok(bits) => f16::from_bits(bits as u16), + Err(HexFloatParseError(s)) => panic!("{}", s), + } +} + +/// Construct a 32-bit float from hex float representation (C-style) +#[allow(unused)] +pub const fn hf32(s: &str) -> f32 { + match parse_hex_exact(s, 32, 23) { + Ok(bits) => f32_from_bits(bits as u32), + Err(HexFloatParseError(s)) => panic!("{}", s), + } +} + +/// Construct a 64-bit float from hex float representation (C-style) +pub const fn hf64(s: &str) -> f64 { + match parse_hex_exact(s, 64, 52) { + Ok(bits) => f64_from_bits(bits as u64), + Err(HexFloatParseError(s)) => panic!("{}", s), + } +} + +/// Construct a 128-bit float from hex float representation (C-style) +#[cfg(f128_enabled)] +pub const fn hf128(s: &str) -> f128 { + match parse_hex_exact(s, 128, 112) { + Ok(bits) => f128::from_bits(bits), + Err(HexFloatParseError(s)) => panic!("{}", s), + } +} +#[derive(Copy, Clone, Debug)] +pub struct HexFloatParseError(&'static str); + +/// Parses any float to its bitwise representation, returning an error if it cannot be represented exactly +pub const fn parse_hex_exact( + s: &str, + bits: u32, + sig_bits: u32, +) -> Result { + match parse_any(s, bits, sig_bits, Round::Nearest) { + Err(e) => Err(e), + Ok((bits, Status::OK)) => Ok(bits), + Ok((_, status)) if status.overflow() => Err(HexFloatParseError("the value is too huge")), + Ok((_, status)) if status.underflow() => Err(HexFloatParseError("the value is too tiny")), + Ok((_, status)) if status.inexact() => Err(HexFloatParseError("the value is too precise")), + Ok(_) => unreachable!(), + } +} + +/// Parse any float from hex to its bitwise representation. +pub const fn parse_any( + s: &str, + bits: u32, + sig_bits: u32, + round: Round, +) -> Result<(u128, Status), HexFloatParseError> { + let mut b = s.as_bytes(); + + if sig_bits > 119 || bits > 128 || bits < sig_bits + 3 || bits > sig_bits + 30 { + return Err(HexFloatParseError("unsupported target float configuration")); + } + + let neg = matches!(b, [b'-', ..]); + if let &[b'-' | b'+', ref rest @ ..] = b { + b = rest; + } + + let sign_bit = 1 << (bits - 1); + let quiet_bit = 1 << (sig_bits - 1); + let nan = sign_bit - quiet_bit; + let inf = nan - quiet_bit; + + let (mut x, status) = match *b { + [b'i' | b'I', b'n' | b'N', b'f' | b'F'] => (inf, Status::OK), + [b'n' | b'N', b'a' | b'A', b'n' | b'N'] => (nan, Status::OK), + [b'0', b'x' | b'X', ref rest @ ..] => { + let round = match (neg, round) { + // parse("-x", Round::Positive) == -parse("x", Round::Negative) + (true, Round::Positive) => Round::Negative, + (true, Round::Negative) => Round::Positive, + // rounding toward nearest or zero are symmetric + (true, Round::Nearest | Round::Zero) | (false, _) => round, + }; + match parse_finite(rest, bits, sig_bits, round) { + Err(e) => return Err(e), + Ok(res) => res, + } + } + _ => return Err(HexFloatParseError("no hex indicator")), + }; + + if neg { + x ^= sign_bit; + } + + Ok((x, status)) +} + +const fn parse_finite( + b: &[u8], + bits: u32, + sig_bits: u32, + rounding_mode: Round, +) -> Result<(u128, Status), HexFloatParseError> { + let exp_bits: u32 = bits - sig_bits - 1; + let max_msb: i32 = (1 << (exp_bits - 1)) - 1; + // The exponent of one ULP in the subnormals + let min_lsb: i32 = 1 - max_msb - sig_bits as i32; + + let (mut sig, mut exp) = match parse_hex(b) { + Err(e) => return Err(e), + Ok(Parsed { sig: 0, .. }) => return Ok((0, Status::OK)), + Ok(Parsed { sig, exp }) => (sig, exp), + }; + + let mut round_bits = u128_ilog2(sig) as i32 - sig_bits as i32; + + // Round at least up to min_lsb + if exp < min_lsb - round_bits { + round_bits = min_lsb - exp; + } + + let mut status = Status::OK; + + exp += round_bits; + + if round_bits > 0 { + // first, prepare for rounding exactly two bits + if round_bits == 1 { + sig <<= 1; + } else if round_bits > 2 { + sig = shr_odd_rounding(sig, (round_bits - 2) as u32); + } + + if sig & 0b11 != 0 { + status = Status::INEXACT; + } + + sig = shr2_round(sig, rounding_mode); + } else if round_bits < 0 { + sig <<= -round_bits; + } + + // The parsed value is X = sig * 2^exp + // Expressed as a multiple U of the smallest subnormal value: + // X = U * 2^min_lsb, so U = sig * 2^(exp-min_lsb) + let uexp = (exp - min_lsb) as u128; + let uexp = uexp << sig_bits; + + // Note that it is possible for the exponent bits to equal 2 here + // if the value rounded up, but that means the mantissa is all zeroes + // so the value is still correct + debug_assert!(sig <= 2 << sig_bits); + + let inf = ((1 << exp_bits) - 1) << sig_bits; + + let bits = match sig.checked_add(uexp) { + Some(bits) if bits < inf => { + // inexact subnormal or zero? + if status.inexact() && bits < (1 << sig_bits) { + status = status.with(Status::UNDERFLOW); + } + bits + } + _ => { + // overflow to infinity + status = status.with(Status::OVERFLOW).with(Status::INEXACT); + match rounding_mode { + Round::Positive | Round::Nearest => inf, + Round::Negative | Round::Zero => inf - 1, + } + } + }; + Ok((bits, status)) +} + +/// Shift right, rounding all inexact divisions to the nearest odd number +/// E.g. (0 >> 4) -> 0, (1..=31 >> 4) -> 1, (32 >> 4) -> 2, ... +/// +/// Useful for reducing a number before rounding the last two bits, since +/// the result of the final rounding is preserved for all rounding modes. +const fn shr_odd_rounding(x: u128, k: u32) -> u128 { + if k < 128 { + let inexact = x.trailing_zeros() < k; + (x >> k) | (inexact as u128) + } else { + (x != 0) as u128 + } +} + +/// Divide by 4, rounding with the given mode +const fn shr2_round(mut x: u128, round: Round) -> u128 { + let t = (x as u32) & 0b111; + x >>= 2; + match round { + // Look-up-table on the last three bits for when to round up + Round::Nearest => x + ((0b11001000_u8 >> t) & 1) as u128, + + Round::Negative => x, + Round::Zero => x, + Round::Positive => x + (t & 0b11 != 0) as u128, + } +} + +/// A parsed finite and unsigned floating point number. +struct Parsed { + /// Absolute value sig * 2^exp + sig: u128, + exp: i32, +} + +/// Parse a hexadecimal float x +const fn parse_hex(mut b: &[u8]) -> Result { + let mut sig: u128 = 0; + let mut exp: i32 = 0; + + let mut seen_point = false; + let mut some_digits = false; + let mut inexact = false; + + while let &[c, ref rest @ ..] = b { + b = rest; + + match c { + b'.' => { + if seen_point { + return Err(HexFloatParseError("unexpected '.' parsing fractional digits")); + } + seen_point = true; + continue; + } + b'p' | b'P' => break, + c => { + let digit = match hex_digit(c) { + Some(d) => d, + None => return Err(HexFloatParseError("expected hexadecimal digit")), + }; + some_digits = true; + + if (sig >> 124) == 0 { + sig <<= 4; + sig |= digit as u128; + } else { + // FIXME: it is technically possible for exp to overflow if parsing a string with >500M digits + exp += 4; + inexact |= digit != 0; + } + // Up until the fractional point, the value grows + // with more digits, but after it the exponent is + // compensated to match. + if seen_point { + exp -= 4; + } + } + } + } + // If we've set inexact, the exact value has more than 125 + // significant bits, and lies somewhere between sig and sig + 1. + // Because we'll round off at least two of the trailing bits, + // setting the last bit gives correct rounding for inexact values. + sig |= inexact as u128; + + if !some_digits { + return Err(HexFloatParseError("at least one digit is required")); + }; + + some_digits = false; + + let negate_exp = matches!(b, [b'-', ..]); + if let &[b'-' | b'+', ref rest @ ..] = b { + b = rest; + } + + let mut pexp: u32 = 0; + while let &[c, ref rest @ ..] = b { + b = rest; + let digit = match dec_digit(c) { + Some(d) => d, + None => return Err(HexFloatParseError("expected decimal digit")), + }; + some_digits = true; + pexp = pexp.saturating_mul(10); + pexp += digit as u32; + } + + if !some_digits { + return Err(HexFloatParseError("at least one exponent digit is required")); + }; + + { + let e; + if negate_exp { + e = (exp as i64) - (pexp as i64); + } else { + e = (exp as i64) + (pexp as i64); + }; + + exp = if e < i32::MIN as i64 { + i32::MIN + } else if e > i32::MAX as i64 { + i32::MAX + } else { + e as i32 + }; + } + /* FIXME(msrv): once MSRV >= 1.66, replace the above workaround block with: + if negate_exp { + exp = exp.saturating_sub_unsigned(pexp); + } else { + exp = exp.saturating_add_unsigned(pexp); + }; + */ + + Ok(Parsed { sig, exp }) +} + +const fn dec_digit(c: u8) -> Option { + match c { + b'0'..=b'9' => Some(c - b'0'), + _ => None, + } +} + +const fn hex_digit(c: u8) -> Option { + match c { + b'0'..=b'9' => Some(c - b'0'), + b'a'..=b'f' => Some(c - b'a' + 10), + b'A'..=b'F' => Some(c - b'A' + 10), + _ => None, + } +} + +/* FIXME(msrv): vendor some things that are not const stable at our MSRV */ + +/// `u128::ilog2` +const fn u128_ilog2(v: u128) -> u32 { + assert!(v != 0); + u128::BITS - 1 - v.leading_zeros() +} + +/// Format a floating point number as its IEEE hex (`%a`) representation. +pub struct Hexf(pub F); + +// Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs +#[cfg(not(feature = "compiler-builtins"))] +fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if x.is_sign_negative() { + write!(f, "-")?; + } + + if x.is_nan() { + return write!(f, "NaN"); + } else if x.is_infinite() { + return write!(f, "inf"); + } else if *x == F::ZERO { + return write!(f, "0x0p+0"); + } + + let mut exponent = x.exp_unbiased(); + let sig = x.to_bits() & F::SIG_MASK; + + let bias = F::EXP_BIAS as i32; + // The mantissa MSB needs to be shifted up to the nearest nibble. + let mshift = (4 - (F::SIG_BITS % 4)) % 4; + let sig = sig << mshift; + // The width is rounded up to the nearest char (4 bits) + let mwidth = (F::SIG_BITS as usize + 3) / 4; + let leading = if exponent == -bias { + // subnormal number means we shift our output by 1 bit. + exponent += 1; + "0." + } else { + "1." + }; + + write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") +} + +#[cfg(feature = "compiler-builtins")] +fn fmt_any_hex(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() +} + +impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt_any_hex(&self.0, f) + } + } + } +} + +impl fmt::LowerHex for Hexf<(F, F)> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + } + } + } +} + +impl fmt::LowerHex for Hexf<(F, i32)> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + } + } + } +} + +impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(&self.0, f) + } + } + } +} + +impl fmt::Debug for Hexf +where + Hexf: fmt::LowerHex, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(self, f) + } + } + } +} + +impl fmt::Display for Hexf +where + Hexf: fmt::LowerHex, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(self, f) + } + } + } +} + +#[cfg(test)] +mod parse_tests { + extern crate std; + use std::{format, println}; + + use super::*; + + #[cfg(f16_enabled)] + fn rounding_properties(s: &str) -> Result<(), HexFloatParseError> { + let (xd, s0) = parse_any(s, 16, 10, Round::Negative)?; + let (xu, s1) = parse_any(s, 16, 10, Round::Positive)?; + let (xz, s2) = parse_any(s, 16, 10, Round::Zero)?; + let (xn, s3) = parse_any(s, 16, 10, Round::Nearest)?; + + // FIXME: A value between the least normal and largest subnormal + // could have underflow status depend on rounding mode. + + if let Status::OK = s0 { + // an exact result is the same for all rounding modes + assert_eq!(s0, s1); + assert_eq!(s0, s2); + assert_eq!(s0, s3); + + assert_eq!(xd, xu); + assert_eq!(xd, xz); + assert_eq!(xd, xn); + } else { + assert!([s0, s1, s2, s3].into_iter().all(Status::inexact)); + + let xd = f16::from_bits(xd as u16); + let xu = f16::from_bits(xu as u16); + let xz = f16::from_bits(xz as u16); + let xn = f16::from_bits(xn as u16); + + assert_biteq!(xd.next_up(), xu, "s={s}, xd={xd:?}, xu={xu:?}"); + + let signs = [xd, xu, xz, xn].map(f16::is_sign_negative); + + if signs == [true; 4] { + assert_biteq!(xz, xu); + } else { + assert_eq!(signs, [false; 4]); + assert_biteq!(xz, xd); + } + + if xn.to_bits() != xd.to_bits() { + assert_biteq!(xn, xu); + } + } + Ok(()) + } + #[test] + #[cfg(f16_enabled)] + fn test_rounding() { + let n = 1_i32 << 14; + for i in -n..n { + let u = i.rotate_right(11) as u32; + let s = format!("{}", Hexf(f32::from_bits(u))); + assert!(rounding_properties(&s).is_ok()); + } + } + + #[test] + fn test_parse_any() { + for k in -149..=127 { + let s = format!("0x1p{k}"); + let x = hf32(&s); + let y = if k < 0 { 0.5f32.powi(-k) } else { 2.0f32.powi(k) }; + assert_eq!(x, y); + } + + let mut s = *b"0x.0000000p-121"; + for e in 0..40 { + for k in 0..(1 << 15) { + let expected = f32::from_bits(k) * 2.0f32.powi(e); + let x = hf32(std::str::from_utf8(&s).unwrap()); + assert_eq!( + x.to_bits(), + expected.to_bits(), + "\ + e={e}\n\ + k={k}\n\ + x={x}\n\ + expected={expected}\n\ + s={}\n\ + f32::from_bits(k)={}\n\ + 2.0f32.powi(e)={}\ + ", + std::str::from_utf8(&s).unwrap(), + f32::from_bits(k), + 2.0f32.powi(e), + ); + for i in (3..10).rev() { + if s[i] == b'f' { + s[i] = b'0'; + } else if s[i] == b'9' { + s[i] = b'a'; + break; + } else { + s[i] += 1; + break; + } + } + } + for i in (12..15).rev() { + if s[i] == b'0' { + s[i] = b'9'; + } else { + s[i] -= 1; + break; + } + } + for i in (3..10).rev() { + s[i] = b'0'; + } + } + } + + // FIXME: this test is causing failures that are likely UB on various platforms + #[cfg(all(target_arch = "x86_64", target_os = "linux"))] + #[test] + #[cfg(f128_enabled)] + fn rounding() { + let pi = std::f128::consts::PI; + let s = format!("{}", Hexf(pi)); + + for k in 0..=111 { + let (bits, status) = parse_any(&s, 128 - k, 112 - k, Round::Nearest).unwrap(); + let scale = (1u128 << (112 - k - 1)) as f128; + let expected = (pi * scale).round_ties_even() / scale; + assert_eq!(bits << k, expected.to_bits(), "k = {k}, s = {s}"); + assert_eq!(expected != pi, status.inexact()); + } + } + #[test] + fn rounding_extreme_underflow() { + for k in 1..1000 { + let s = format!("0x1p{}", -149 - k); + let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; + assert_eq!(bits, 0, "{s} should round to zero, got bits={bits}"); + assert!(status.underflow(), "should indicate underflow when parsing {s}"); + assert!(status.inexact(), "should indicate inexact when parsing {s}"); + } + } + #[test] + fn long_tail() { + for k in 1..1000 { + let s = format!("0x1.{}p0", "0".repeat(k)); + let Ok(bits) = parse_hex_exact(&s, 32, 23) else { panic!("parsing {s} failed") }; + assert_eq!(f32::from_bits(bits as u32), 1.0); + + let s = format!("0x1.{}1p0", "0".repeat(k)); + let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; + if status.inexact() { + assert!(1.0 == f32::from_bits(bits as u32)); + } else { + assert!(1.0 < f32::from_bits(bits as u32)); + } + } + } + // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to + // hide them from the AST. + #[cfg(f16_enabled)] + macro_rules! f16_tests { + () => { + #[test] + fn test_f16() { + let checks = [ + ("0x.1234p+16", (0x1234 as f16).to_bits()), + ("0x1.234p+12", (0x1234 as f16).to_bits()), + ("0x12.34p+8", (0x1234 as f16).to_bits()), + ("0x123.4p+4", (0x1234 as f16).to_bits()), + ("0x1234p+0", (0x1234 as f16).to_bits()), + ("0x1234.p+0", (0x1234 as f16).to_bits()), + ("0x1234.0p+0", (0x1234 as f16).to_bits()), + ("0x1.ffcp+15", f16::MAX.to_bits()), + ("0x1.0p+1", 2.0f16.to_bits()), + ("0x1.0p+0", 1.0f16.to_bits()), + ("0x1.ffp+8", 0x5ffc), + ("+0x1.ffp+8", 0x5ffc), + ("0x1p+0", 0x3c00), + ("0x1.998p-4", 0x2e66), + ("0x1.9p+6", 0x5640), + ("0x0.0p0", 0.0f16.to_bits()), + ("-0x0.0p0", (-0.0f16).to_bits()), + ("0x1.0p0", 1.0f16.to_bits()), + ("0x1.998p-4", (0.1f16).to_bits()), + ("-0x1.998p-4", (-0.1f16).to_bits()), + ("0x0.123p-12", 0x0123), + ("0x1p-24", 0x0001), + ("nan", f16::NAN.to_bits()), + ("-nan", (-f16::NAN).to_bits()), + ("inf", f16::INFINITY.to_bits()), + ("-inf", f16::NEG_INFINITY.to_bits()), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + assert!(rounding_properties(s).is_ok()); + let act = hf16(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#06x} != {exp:#06x}\nact: {act:#018b}\nexp: {exp:#018b}" + ); + } + } + + #[test] + fn test_macros_f16() { + assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); + } + }; + } + + #[cfg(f16_enabled)] + f16_tests!(); + + #[test] + fn test_f32() { + let checks = [ + ("0x.1234p+16", (0x1234 as f32).to_bits()), + ("0x1.234p+12", (0x1234 as f32).to_bits()), + ("0x12.34p+8", (0x1234 as f32).to_bits()), + ("0x123.4p+4", (0x1234 as f32).to_bits()), + ("0x1234p+0", (0x1234 as f32).to_bits()), + ("0x1234.p+0", (0x1234 as f32).to_bits()), + ("0x1234.0p+0", (0x1234 as f32).to_bits()), + ("0x1.fffffep+127", f32::MAX.to_bits()), + ("0x1.0p+1", 2.0f32.to_bits()), + ("0x1.0p+0", 1.0f32.to_bits()), + ("0x1.ffep+8", 0x43fff000), + ("+0x1.ffep+8", 0x43fff000), + ("0x1p+0", 0x3f800000), + ("0x1.99999ap-4", 0x3dcccccd), + ("0x1.9p+6", 0x42c80000), + ("0x1.2d5ed2p+20", 0x4996af69), + ("-0x1.348eb8p+10", 0xc49a475c), + ("-0x1.33dcfep-33", 0xaf19ee7f), + ("0x0.0p0", 0.0f32.to_bits()), + ("-0x0.0p0", (-0.0f32).to_bits()), + ("0x1.0p0", 1.0f32.to_bits()), + ("0x1.99999ap-4", (0.1f32).to_bits()), + ("-0x1.99999ap-4", (-0.1f32).to_bits()), + ("0x1.111114p-127", 0x00444445), + ("0x1.23456p-130", 0x00091a2b), + ("0x1p-149", 0x00000001), + ("nan", f32::NAN.to_bits()), + ("-nan", (-f32::NAN).to_bits()), + ("inf", f32::INFINITY.to_bits()), + ("-inf", f32::NEG_INFINITY.to_bits()), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + let act = hf32(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#010x} != {exp:#010x}\nact: {act:#034b}\nexp: {exp:#034b}" + ); + } + } + + #[test] + fn test_f64() { + let checks = [ + ("0x.1234p+16", (0x1234 as f64).to_bits()), + ("0x1.234p+12", (0x1234 as f64).to_bits()), + ("0x12.34p+8", (0x1234 as f64).to_bits()), + ("0x123.4p+4", (0x1234 as f64).to_bits()), + ("0x1234p+0", (0x1234 as f64).to_bits()), + ("0x1234.p+0", (0x1234 as f64).to_bits()), + ("0x1234.0p+0", (0x1234 as f64).to_bits()), + ("0x1.ffep+8", 0x407ffe0000000000), + ("0x1p+0", 0x3ff0000000000000), + ("0x1.999999999999ap-4", 0x3fb999999999999a), + ("0x1.9p+6", 0x4059000000000000), + ("0x1.2d5ed1fe1da7bp+20", 0x4132d5ed1fe1da7b), + ("-0x1.348eb851eb852p+10", 0xc09348eb851eb852), + ("-0x1.33dcfe54a3803p-33", 0xbde33dcfe54a3803), + ("0x1.0p0", 1.0f64.to_bits()), + ("0x0.0p0", 0.0f64.to_bits()), + ("-0x0.0p0", (-0.0f64).to_bits()), + ("0x1.999999999999ap-4", 0.1f64.to_bits()), + ("0x1.999999999998ap-4", (0.1f64 - f64::EPSILON).to_bits()), + ("-0x1.999999999999ap-4", (-0.1f64).to_bits()), + ("-0x1.999999999998ap-4", (-0.1f64 + f64::EPSILON).to_bits()), + ("0x0.8000000000001p-1022", 0x0008000000000001), + ("0x0.123456789abcdp-1022", 0x000123456789abcd), + ("0x0.0000000000002p-1022", 0x0000000000000002), + ("nan", f64::NAN.to_bits()), + ("-nan", (-f64::NAN).to_bits()), + ("inf", f64::INFINITY.to_bits()), + ("-inf", f64::NEG_INFINITY.to_bits()), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + let act = hf64(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#018x} != {exp:#018x}\nact: {act:#066b}\nexp: {exp:#066b}" + ); + } + } + + // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to + // hide them from the AST. + #[cfg(f128_enabled)] + macro_rules! f128_tests { + () => { + #[test] + fn test_f128() { + let checks = [ + ("0x.1234p+16", (0x1234 as f128).to_bits()), + ("0x1.234p+12", (0x1234 as f128).to_bits()), + ("0x12.34p+8", (0x1234 as f128).to_bits()), + ("0x123.4p+4", (0x1234 as f128).to_bits()), + ("0x1234p+0", (0x1234 as f128).to_bits()), + ("0x1234.p+0", (0x1234 as f128).to_bits()), + ("0x1234.0p+0", (0x1234 as f128).to_bits()), + ("0x1.ffffffffffffffffffffffffffffp+16383", f128::MAX.to_bits()), + ("0x1.0p+1", 2.0f128.to_bits()), + ("0x1.0p+0", 1.0f128.to_bits()), + ("0x1.ffep+8", 0x4007ffe0000000000000000000000000), + ("+0x1.ffep+8", 0x4007ffe0000000000000000000000000), + ("0x1p+0", 0x3fff0000000000000000000000000000), + ("0x1.999999999999999999999999999ap-4", 0x3ffb999999999999999999999999999a), + ("0x1.9p+6", 0x40059000000000000000000000000000), + ("0x0.0p0", 0.0f128.to_bits()), + ("-0x0.0p0", (-0.0f128).to_bits()), + ("0x1.0p0", 1.0f128.to_bits()), + ("0x1.999999999999999999999999999ap-4", (0.1f128).to_bits()), + ("-0x1.999999999999999999999999999ap-4", (-0.1f128).to_bits()), + ("0x0.abcdef0123456789abcdef012345p-16382", 0x0000abcdef0123456789abcdef012345), + ("0x1p-16494", 0x00000000000000000000000000000001), + ("nan", f128::NAN.to_bits()), + ("-nan", (-f128::NAN).to_bits()), + ("inf", f128::INFINITY.to_bits()), + ("-inf", f128::NEG_INFINITY.to_bits()), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + let act = hf128(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#034x} != {exp:#034x}\nact: {act:#0130b}\nexp: {exp:#0130b}" + ); + } + } + + #[test] + fn test_macros_f128() { + assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); + } + } + } + + #[cfg(f128_enabled)] + f128_tests!(); + + #[test] + fn test_macros() { + #[cfg(f16_enabled)] + assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); + assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000_u32); + assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000_u64); + #[cfg(f128_enabled)] + assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); + } +} + +#[cfg(test)] +// FIXME(ppc): something with `should_panic` tests cause a SIGILL with ppc64le +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +mod tests_panicking { + extern crate std; + use super::*; + + // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to + // hide them from the AST. + #[cfg(f16_enabled)] + macro_rules! f16_tests { + () => { + #[test] + fn test_f16_almost_extra_precision() { + // Exact maximum precision allowed + hf16("0x1.ffcp+0"); + } + + #[test] + #[should_panic(expected = "the value is too precise")] + fn test_f16_extra_precision() { + // One bit more than the above. + hf16("0x1.ffdp+0"); + } + + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f16_overflow() { + // One bit more than the above. + hf16("0x1p+16"); + } + + #[test] + fn test_f16_tiniest() { + let x = hf16("0x1.p-24"); + let y = hf16("0x0.001p-12"); + let z = hf16("0x0.8p-23"); + assert_eq!(x, y); + assert_eq!(x, z); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f16_too_tiny() { + hf16("0x1.p-25"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f16_also_too_tiny() { + hf16("0x0.8p-24"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f16_again_too_tiny() { + hf16("0x0.001p-13"); + } + }; + } + + #[cfg(f16_enabled)] + f16_tests!(); + + #[test] + fn test_f32_almost_extra_precision() { + // Exact maximum precision allowed + hf32("0x1.abcdeep+0"); + } + + #[test] + #[should_panic] + fn test_f32_extra_precision2() { + // One bit more than the above. + hf32("0x1.ffffffp+127"); + } + + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f32_overflow() { + // One bit more than the above. + hf32("0x1p+128"); + } + + #[test] + #[should_panic(expected = "the value is too precise")] + fn test_f32_extra_precision() { + // One bit more than the above. + hf32("0x1.abcdefp+0"); + } + + #[test] + fn test_f32_tiniest() { + let x = hf32("0x1.p-149"); + let y = hf32("0x0.0000000000000001p-85"); + let z = hf32("0x0.8p-148"); + assert_eq!(x, y); + assert_eq!(x, z); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f32_too_tiny() { + hf32("0x1.p-150"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f32_also_too_tiny() { + hf32("0x0.8p-149"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f32_again_too_tiny() { + hf32("0x0.0000000000000001p-86"); + } + + #[test] + fn test_f64_almost_extra_precision() { + // Exact maximum precision allowed + hf64("0x1.abcdabcdabcdfp+0"); + } + + #[test] + #[should_panic(expected = "the value is too precise")] + fn test_f64_extra_precision() { + // One bit more than the above. + hf64("0x1.abcdabcdabcdf8p+0"); + } + + // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to + // hide them from the AST. + #[cfg(f128_enabled)] + macro_rules! f128_tests { + () => { + #[test] + fn test_f128_almost_extra_precision() { + // Exact maximum precision allowed + hf128("0x1.ffffffffffffffffffffffffffffp+16383"); + } + + #[test] + #[should_panic(expected = "the value is too precise")] + fn test_f128_extra_precision() { + // Just below the maximum finite. + hf128("0x1.fffffffffffffffffffffffffffe8p+16383"); + } + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f128_extra_precision_overflow() { + // One bit more than the above. Should overflow. + hf128("0x1.ffffffffffffffffffffffffffff8p+16383"); + } + + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f128_overflow() { + // One bit more than the above. + hf128("0x1p+16384"); + } + + #[test] + fn test_f128_tiniest() { + let x = hf128("0x1.p-16494"); + let y = hf128("0x0.0000000000000001p-16430"); + let z = hf128("0x0.8p-16493"); + assert_eq!(x, y); + assert_eq!(x, z); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f128_too_tiny() { + hf128("0x1.p-16495"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f128_again_too_tiny() { + hf128("0x0.0000000000000001p-16431"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f128_also_too_tiny() { + hf128("0x0.8p-16494"); + } + }; + } + + #[cfg(f128_enabled)] + f128_tests!(); +} + +#[cfg(test)] +mod print_tests { + extern crate std; + use std::string::ToString; + + use super::*; + + #[test] + #[cfg(f16_enabled)] + fn test_f16() { + use std::format; + // Exhaustively check that `f16` roundtrips. + for x in 0..=u16::MAX { + let f = f16::from_bits(x); + let s = format!("{}", Hexf(f)); + let from_s = hf16(&s); + + if f.is_nan() && from_s.is_nan() { + continue; + } + + assert_eq!( + f.to_bits(), + from_s.to_bits(), + "{f:?} formatted as {s} but parsed as {from_s:?}" + ); + } + } + + #[test] + #[cfg(f16_enabled)] + fn test_f16_to_f32() { + use std::format; + // Exhaustively check that these are equivalent for all `f16`: + // - `f16 -> f32` + // - `f16 -> str -> f32` + // - `f16 -> f32 -> str -> f32` + // - `f16 -> f32 -> str -> f16 -> f32` + for x in 0..=u16::MAX { + let f16 = f16::from_bits(x); + let s16 = format!("{}", Hexf(f16)); + let f32 = f16 as f32; + let s32 = format!("{}", Hexf(f32)); + + let a = hf32(&s16); + let b = hf32(&s32); + let c = hf16(&s32); + + if f32.is_nan() && a.is_nan() && b.is_nan() && c.is_nan() { + continue; + } + + assert_eq!( + f32.to_bits(), + a.to_bits(), + "{f16:?} : f16 formatted as {s16} which parsed as {a:?} : f16" + ); + assert_eq!( + f32.to_bits(), + b.to_bits(), + "{f32:?} : f32 formatted as {s32} which parsed as {b:?} : f32" + ); + assert_eq!( + f32.to_bits(), + (c as f32).to_bits(), + "{f32:?} : f32 formatted as {s32} which parsed as {c:?} : f16" + ); + } + } + #[test] + fn spot_checks() { + assert_eq!(Hexf(f32::MAX).to_string(), "0x1.fffffep+127"); + assert_eq!(Hexf(f64::MAX).to_string(), "0x1.fffffffffffffp+1023"); + + assert_eq!(Hexf(f32::MIN).to_string(), "-0x1.fffffep+127"); + assert_eq!(Hexf(f64::MIN).to_string(), "-0x1.fffffffffffffp+1023"); + + assert_eq!(Hexf(f32::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hexf(f64::ZERO).to_string(), "0x0p+0"); + + assert_eq!(Hexf(f32::NEG_ZERO).to_string(), "-0x0p+0"); + assert_eq!(Hexf(f64::NEG_ZERO).to_string(), "-0x0p+0"); + + assert_eq!(Hexf(f32::NAN).to_string(), "NaN"); + assert_eq!(Hexf(f64::NAN).to_string(), "NaN"); + + assert_eq!(Hexf(f32::INFINITY).to_string(), "inf"); + assert_eq!(Hexf(f64::INFINITY).to_string(), "inf"); + + assert_eq!(Hexf(f32::NEG_INFINITY).to_string(), "-inf"); + assert_eq!(Hexf(f64::NEG_INFINITY).to_string(), "-inf"); + + #[cfg(f16_enabled)] + { + assert_eq!(Hexf(f16::MAX).to_string(), "0x1.ffcp+15"); + assert_eq!(Hexf(f16::MIN).to_string(), "-0x1.ffcp+15"); + assert_eq!(Hexf(f16::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hexf(f16::NEG_ZERO).to_string(), "-0x0p+0"); + assert_eq!(Hexf(f16::NAN).to_string(), "NaN"); + assert_eq!(Hexf(f16::INFINITY).to_string(), "inf"); + assert_eq!(Hexf(f16::NEG_INFINITY).to_string(), "-inf"); + } + + #[cfg(f128_enabled)] + { + assert_eq!(Hexf(f128::MAX).to_string(), "0x1.ffffffffffffffffffffffffffffp+16383"); + assert_eq!(Hexf(f128::MIN).to_string(), "-0x1.ffffffffffffffffffffffffffffp+16383"); + assert_eq!(Hexf(f128::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hexf(f128::NEG_ZERO).to_string(), "-0x0p+0"); + assert_eq!(Hexf(f128::NAN).to_string(), "NaN"); + assert_eq!(Hexf(f128::INFINITY).to_string(), "inf"); + assert_eq!(Hexf(f128::NEG_INFINITY).to_string(), "-inf"); + } + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/libm/src/math/support/int_traits.rs new file mode 100644 index 00000000000..491adb1f22c --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/support/int_traits.rs @@ -0,0 +1,451 @@ +use core::{cmp, fmt, ops}; + +/// Minimal integer implementations needed on all integer types, including wide integers. +pub trait MinInt: + Copy + + fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type Unsigned: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} + +/// Access the associated `OtherSign` type from an int (helper to avoid ambiguous associated +/// types). +pub type OtherSign = ::OtherSign; + +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub trait Int: + MinInt + + fmt::Display + + fmt::Binary + + fmt::LowerHex + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shl + + ops::Shl + + ops::Shr + + ops::Shr + + ops::BitXor + + ops::BitAnd + + cmp::Ord + + From + + CastFrom + + CastFrom + + CastFrom + + CastFrom + + CastFrom + + CastInto + + CastInto + + CastInto + + CastInto + + CastInto +{ + fn signed(self) -> OtherSign; + fn unsigned(self) -> Self::Unsigned; + fn from_unsigned(unsigned: Self::Unsigned) -> Self; + fn abs(self) -> Self; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::Unsigned; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn checked_add(self, other: Self) -> Option; + fn checked_sub(self, other: Self) -> Option; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn overflowing_sub(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn checked_add(self, other: Self) -> Option { + self.checked_add(other) + } + + fn checked_sub(self, other: Self) -> Option { + self.checked_sub(other) + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn overflowing_sub(self, other: Self) -> (Self, bool) { + ::overflowing_sub(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + // On our older MSRV, this resolves to the trait method. Which won't actually work, + // but this is only called behind other gates. + #[allow(clippy::incompatible_msrv)] + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type Unsigned = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn signed(self) -> $ity { + self as $ity + } + + fn unsigned(self) -> Self { + self + } + + fn abs(self) -> Self { + unimplemented!() + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn abs_diff(self, other: Self) -> Self { + self.abs_diff(other) + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type Unsigned = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn signed(self) -> Self { + self + } + + fn unsigned(self) -> $uty { + self as $uty + } + + fn abs(self) -> Self { + self.abs() + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn abs_diff(self, other: Self) -> $uty { + self.abs_diff(other) + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +/// Trait for integers twice the bit width of another integer. This is implemented for all +/// primitives except for `u8`, because there is not a smaller primitive. +pub trait DInt: MinInt { + /// Integer that is half the bit width of the integer this trait is implemented for + type H: HInt; + + /// Returns the low half of `self` + fn lo(self) -> Self::H; + /// Returns the high half of `self` + fn hi(self) -> Self::H; + /// Returns the low and high halves of `self` as a tuple + fn lo_hi(self) -> (Self::H, Self::H) { + (self.lo(), self.hi()) + } + /// Constructs an integer using lower and higher half parts + #[allow(unused)] + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { + lo.zero_widen() | hi.widen_hi() + } +} + +/// Trait for integers half the bit width of another integer. This is implemented for all +/// primitives except for `u128`, because it there is not a larger primitive. +pub trait HInt: Int { + /// Integer that is double the bit width of the integer this trait is implemented for + type D: DInt + MinInt; + + // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for + // unknown reasons this can cause infinite recursion when optimizations are disabled. See + // for context. + + /// Widens (using default extension) the integer to have double bit width + fn widen(self) -> Self::D; + /// Widens (zero extension only) the integer to have double bit width. This is needed to get + /// around problems with associated type bounds (such as `Int`) being unstable + fn zero_widen(self) -> Self::D; + /// Widens the integer to have double bit width and shifts the integer into the higher bits + #[allow(unused)] + fn widen_hi(self) -> Self::D; + /// Widening multiplication with zero widening. This cannot overflow. + fn zero_widen_mul(self, rhs: Self) -> Self::D; + /// Widening multiplication. This cannot overflow. + fn widen_mul(self, rhs: Self) -> Self::D; +} + +macro_rules! impl_d_int { + ($($X:ident $D:ident),*) => { + $( + impl DInt for $D { + type H = $X; + + fn lo(self) -> Self::H { + self as $X + } + fn hi(self) -> Self::H { + (self >> <$X as MinInt>::BITS) as $X + } + } + )* + }; +} + +macro_rules! impl_h_int { + ($($H:ident $uH:ident $X:ident),*) => { + $( + impl HInt for $H { + type D = $X; + + fn widen(self) -> Self::D { + self as $X + } + fn zero_widen(self) -> Self::D { + (self as $uH) as $X + } + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen().wrapping_mul(rhs.zero_widen()) + } + fn widen_mul(self, rhs: Self) -> Self::D { + self.widen().wrapping_mul(rhs.widen()) + } + fn widen_hi(self) -> Self::D { + (self as $X) << ::BITS + } + } + )* + }; +} + +impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); +impl_h_int!( + u8 u8 u16, + u16 u16 u32, + u32 u32 u64, + u64 u64 u128, + i8 u8 i16, + i16 u16 i32, + i32 u32 i64, + i64 u64 i128 +); + +/// Trait to express (possibly lossy) casting of integers +pub trait CastInto: Copy { + /// By default, casts should be exact. + fn cast(self) -> T; + + /// Call for casts that are expected to truncate. + fn cast_lossy(self) -> T; +} + +pub trait CastFrom: Copy { + /// By default, casts should be exact. + fn cast_from(value: T) -> Self; + + /// Call for casts that are expected to truncate. + fn cast_from_lossy(value: T) -> Self; +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } + + fn cast_from_lossy(value: U) -> Self { + value.cast_lossy() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + // All we can really do to enforce casting rules is check the rules when in + // debug mode. + #[cfg(not(feature = "compiler-builtins"))] + debug_assert!(<$into>::try_from(self).is_ok(), "failed cast from {self}"); + self as $into + } + + fn cast_lossy(self) -> $into { + self as $into + } + } + )*}; +} + +macro_rules! cast_into_float { + ($ty:ty) => { + #[cfg(f16_enabled)] + cast_into_float!($ty; f16); + + cast_into_float!($ty; f32, f64); + + #[cfg(f128_enabled)] + cast_into_float!($ty; f128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + #[cfg(not(feature = "compiler-builtins"))] + debug_assert_eq!(self as $into as $ty, self, "inexact float cast"); + self as $into + } + + fn cast_lossy(self) -> $into { + self as $into + } + } + )*}; +} + +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); + +cast_into_float!(i8); +cast_into_float!(i16); +cast_into_float!(i32); +cast_into_float!(i64); +cast_into_float!(i128); diff --git a/library/compiler-builtins/libm/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/libm/src/math/support/macros.rs new file mode 100644 index 00000000000..0b72db0e46e --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/support/macros.rs @@ -0,0 +1,157 @@ +/// `libm` cannot have dependencies, so this is vendored directly from the `cfg-if` crate +/// (with some comments stripped for compactness). +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($meta:meta)] { $($tokens:tt)* } + ) else * else { + $($tokens2:tt)* + }) => { + cfg_if! { @__items () ; $( ( ($meta) ($($tokens)*) ), )* ( () ($($tokens2)*) ), } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($i_met:meta)] { $($i_tokens:tt)* } + $( else if #[cfg($e_met:meta)] { $($e_tokens:tt)* } )* + ) => { + cfg_if! { + @__items + () ; + ( ($i_met) ($($i_tokens)*) ), + $( ( ($e_met) ($($e_tokens)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($tokens:tt)*) ), $($rest:tt)*) => { + #[cfg(all($($m,)* not(any($($not),*))))] cfg_if! { @__identity $($tokens)* } + cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to make __apply work out right for different match types, + // because of how macros matching/expand stuff. + (@__identity $($tokens:tt)*) => { $($tokens)* }; +} + +/// Choose between using an arch-specific implementation and the function body. Returns directly +/// if the arch implementation is used, otherwise continue with the rest of the function. +/// +/// Specify a `use_arch` meta field if an architecture-specific implementation is provided. +/// These live in the `math::arch::some_target_arch` module. +/// +/// Specify a `use_arch_required` meta field if something architecture-specific must be used +/// regardless of feature configuration (`force-soft-floats`). +/// +/// The passed meta options do not need to account for the `arch` target feature. +macro_rules! select_implementation { + ( + name: $fn_name:ident, + // Configuration meta for when to use arch-specific implementation that requires hard + // float ops + $( use_arch: $use_arch:meta, )? + // Configuration meta for when to use the arch module regardless of whether softfloats + // have been requested. + $( use_arch_required: $use_arch_required:meta, )? + args: $($arg:ident),+ , + ) => { + // FIXME: these use paths that are a pretty fragile (`super`). We should figure out + // something better w.r.t. how this is vendored into compiler-builtins. + + // However, we do need a few things from `arch` that are used even with soft floats. + select_implementation! { + @cfg $($use_arch_required)?; + if true { + return super::arch::$fn_name( $($arg),+ ); + } + } + + // By default, never use arch-specific implementations if we have force-soft-floats + #[cfg(arch_enabled)] + select_implementation! { + @cfg $($use_arch)?; + // Wrap in `if true` to avoid unused warnings + if true { + return super::arch::$fn_name( $($arg),+ ); + } + } + }; + + // Coalesce helper to construct an expression only if a config is provided + (@cfg ; $ex:expr) => { }; + (@cfg $provided:meta; $ex:expr) => { #[cfg($provided)] $ex }; +} + +/// Construct a 16-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[cfg(f16_enabled)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] +#[allow(unused_macros)] +macro_rules! hf16 { + ($s:literal) => {{ + const X: f16 = $crate::support::hf16($s); + X + }}; +} + +/// Construct a 32-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[allow(unused_macros)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] +macro_rules! hf32 { + ($s:literal) => {{ + const X: f32 = $crate::support::hf32($s); + X + }}; +} + +/// Construct a 64-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[allow(unused_macros)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] +macro_rules! hf64 { + ($s:literal) => {{ + const X: f64 = $crate::support::hf64($s); + X + }}; +} + +/// Construct a 128-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[cfg(f128_enabled)] +#[allow(unused_macros)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] +macro_rules! hf128 { + ($s:literal) => {{ + const X: f128 = $crate::support::hf128($s); + X + }}; +} + +/// Assert `F::biteq` with better messages. +#[cfg(test)] +macro_rules! assert_biteq { + ($left:expr, $right:expr, $($tt:tt)*) => {{ + use $crate::support::Int; + let l = $left; + let r = $right; + let bits = Int::leading_zeros(l.to_bits() - l.to_bits()); // hack to get the width from the value + assert!( + l.biteq(r), + "{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", + format_args!($($tt)*), + lb = l.to_bits(), + rb = r.to_bits(), + width = ((bits / 4) + 2) as usize, + + ); + }}; + ($left:expr, $right:expr $(,)?) => { + assert_biteq!($left, $right, "") + }; +} diff --git a/library/compiler-builtins/libm/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/libm/src/math/support/mod.rs new file mode 100644 index 00000000000..ee3f2bbdf02 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/support/mod.rs @@ -0,0 +1,29 @@ +#[macro_use] +pub mod macros; +mod big; +mod env; +mod float_traits; +pub mod hex_float; +mod int_traits; + +#[allow(unused_imports)] +pub use big::{i256, u256}; +pub use env::{FpResult, Round, Status}; +#[allow(unused_imports)] +pub use float_traits::{DFloat, Float, HFloat, IntTy}; +pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; +#[cfg(f16_enabled)] +#[allow(unused_imports)] +pub use hex_float::hf16; +#[cfg(f128_enabled)] +#[allow(unused_imports)] +pub use hex_float::hf128; +#[allow(unused_imports)] +pub use hex_float::{Hexf, hf32, hf64}; +pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; + +/// Hint to the compiler that the current path is cold. +pub fn cold_path() { + #[cfg(intrinsics_enabled)] + core::intrinsics::cold_path(); +} diff --git a/library/compiler-builtins/libm/libm/src/math/tan.rs b/library/compiler-builtins/libm/libm/src/math/tan.rs new file mode 100644 index 00000000000..a074ca5540a --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/tan.rs @@ -0,0 +1,70 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */ +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +use super::{k_tan, rem_pio2}; + +// tan(x) +// Return tangent function of x. +// +// kernel function: +// k_tan ... tangent function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded + +/// The tangent of `x` (f64). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tan(x: f64) -> f64 { + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e400000 { + /* |x| < 2**-27 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00100000 { x / x1p120 as f64 } else { x + x1p120 as f64 }); + return x; + } + return k_tan(x, 0.0, 0); + } + + /* tan(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction */ + let (n, y0, y1) = rem_pio2(x); + k_tan(y0, y1, n & 1) +} diff --git a/library/compiler-builtins/libm/libm/src/math/tanf.rs b/library/compiler-builtins/libm/libm/src/math/tanf.rs new file mode 100644 index 00000000000..7586aae4c7e --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/tanf.rs @@ -0,0 +1,77 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_tanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f64::consts::FRAC_PI_2; + +use super::{k_tanf, rem_pio2f}; + +/* Small multiples of pi/2 rounded to double precision. */ +const T1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +/// The tangent of `x` (f32). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tanf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); + return x; + } + return k_tanf(x64, false); + } + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + return k_tanf(if sign { x64 + T1_PIO2 } else { x64 - T1_PIO2 }, true); + } else { + return k_tanf(if sign { x64 + T2_PIO2 } else { x64 - T2_PIO2 }, false); + } + } + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + return k_tanf(if sign { x64 + T3_PIO2 } else { x64 - T3_PIO2 }, true); + } else { + return k_tanf(if sign { x64 + T4_PIO2 } else { x64 - T4_PIO2 }, false); + } + } + + /* tan(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x - x; + } + + /* argument reduction */ + let (n, y) = rem_pio2f(x); + k_tanf(y, n & 1 != 0) +} diff --git a/library/compiler-builtins/libm/libm/src/math/tanh.rs b/library/compiler-builtins/libm/libm/src/math/tanh.rs new file mode 100644 index 00000000000..cc0abe4fcb2 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/tanh.rs @@ -0,0 +1,53 @@ +use super::expm1; + +/* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) + * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) + * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) + */ + +/// The hyperbolic tangent of `x` (f64). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tanh(mut x: f64) -> f64 { + let mut uf: f64 = x; + let mut ui: u64 = f64::to_bits(uf); + + let w: u32; + let sign: bool; + let mut t: f64; + + /* x = |x| */ + sign = ui >> 63 != 0; + ui &= !1 / 2; + uf = f64::from_bits(ui); + x = uf; + w = (ui >> 32) as u32; + + if w > 0x3fe193ea { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if w > 0x40340000 { + /* |x| > 20 or nan */ + /* note: this branch avoids raising overflow */ + t = 1.0 - 0.0 / x; + } else { + t = expm1(2.0 * x); + t = 1.0 - 2.0 / (t + 2.0); + } + } else if w > 0x3fd058ae { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1(2.0 * x); + t = t / (t + 2.0); + } else if w >= 0x00100000 { + /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ + t = expm1(-2.0 * x); + t = -t / (t + 2.0); + } else { + /* |x| is subnormal */ + /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ + force_eval!(x as f32); + t = x; + } + + if sign { -t } else { t } +} diff --git a/library/compiler-builtins/libm/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/libm/src/math/tanhf.rs new file mode 100644 index 00000000000..fffbba6c6ec --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/tanhf.rs @@ -0,0 +1,38 @@ +use super::expm1f; + +/// The hyperbolic tangent of `x` (f32). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tanhf(mut x: f32) -> f32 { + /* x = |x| */ + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + x = f32::from_bits(ix); + let w = ix; + + let tt = if w > 0x3f0c9f54 { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if w > 0x41200000 { + /* |x| > 10 */ + 1. + 0. / x + } else { + let t = expm1f(2. * x); + 1. - 2. / (t + 2.) + } + } else if w > 0x3e82c578 { + /* |x| > log(5/3)/2 ~= 0.2554 */ + let t = expm1f(2. * x); + t / (t + 2.) + } else if w >= 0x00800000 { + /* |x| >= 0x1p-126 */ + let t = expm1f(-2. * x); + -t / (t + 2.) + } else { + /* |x| is subnormal */ + force_eval!(x * x); + x + }; + if sign { -tt } else { tt } +} diff --git a/library/compiler-builtins/libm/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/libm/src/math/tgamma.rs new file mode 100644 index 00000000000..3059860646a --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/tgamma.rs @@ -0,0 +1,209 @@ +/* +"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) +"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) +"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) + +approximation method: + + (x - 0.5) S(x) +Gamma(x) = (x + g - 0.5) * ---------------- + exp(x + g - 0.5) + +with + a1 a2 a3 aN +S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] + x + 1 x + 2 x + 3 x + N + +with a0, a1, a2, a3,.. aN constants which depend on g. + +for x < 0 the following reflection formula is used: + +Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) + +most ideas and constants are from boost and python +*/ +use super::{exp, floor, k_cos, k_sin, pow}; + +const PI: f64 = 3.141592653589793238462643383279502884; + +/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ +fn sinpi(mut x: f64) -> f64 { + let mut n: isize; + + /* argument reduction: x = |x| mod 2 */ + /* spurious inexact when x is odd int */ + x = x * 0.5; + x = 2.0 * (x - floor(x)); + + /* reduce x into [-.25,.25] */ + n = (4.0 * x) as isize; + n = div!(n + 1, 2); + x -= (n as f64) * 0.5; + + x *= PI; + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + // 0 + _ => k_sin(x, 0.0, 0), + } +} + +const N: usize = 12; +//static const double g = 6.024680040776729583740234375; +const GMHALF: f64 = 5.524680040776729583740234375; +const SNUM: [f64; N + 1] = [ + 23531376880.410759688572007674451636754734846804940, + 42919803642.649098768957899047001988850926355848959, + 35711959237.355668049440185451547166705960488635843, + 17921034426.037209699919755754458931112671403265390, + 6039542586.3520280050642916443072979210699388420708, + 1439720407.3117216736632230727949123939715485786772, + 248874557.86205415651146038641322942321632125127801, + 31426415.585400194380614231628318205362874684987640, + 2876370.6289353724412254090516208496135991145378768, + 186056.26539522349504029498971604569928220784236328, + 8071.6720023658162106380029022722506138218516325024, + 210.82427775157934587250973392071336271166969580291, + 2.5066282746310002701649081771338373386264310793408, +]; +const SDEN: [f64; N + 1] = [ + 0.0, + 39916800.0, + 120543840.0, + 150917976.0, + 105258076.0, + 45995730.0, + 13339535.0, + 2637558.0, + 357423.0, + 32670.0, + 1925.0, + 66.0, + 1.0, +]; +/* n! for small integer n */ +const FACT: [f64; 23] = [ + 1.0, + 1.0, + 2.0, + 6.0, + 24.0, + 120.0, + 720.0, + 5040.0, + 40320.0, + 362880.0, + 3628800.0, + 39916800.0, + 479001600.0, + 6227020800.0, + 87178291200.0, + 1307674368000.0, + 20922789888000.0, + 355687428096000.0, + 6402373705728000.0, + 121645100408832000.0, + 2432902008176640000.0, + 51090942171709440000.0, + 1124000727777607680000.0, +]; + +/* S(x) rational function for positive x */ +fn s(x: f64) -> f64 { + let mut num: f64 = 0.0; + let mut den: f64 = 0.0; + + /* to avoid overflow handle large x differently */ + if x < 8.0 { + for i in (0..=N).rev() { + num = num * x + i!(SNUM, i); + den = den * x + i!(SDEN, i); + } + } else { + for i in 0..=N { + num = num / x + i!(SNUM, i); + den = den / x + i!(SDEN, i); + } + } + return num / den; +} + +/// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tgamma(mut x: f64) -> f64 { + let u: u64 = x.to_bits(); + let absx: f64; + let mut y: f64; + let mut dy: f64; + let mut z: f64; + let mut r: f64; + let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; + let sign: bool = (u >> 63) != 0; + + /* special cases */ + if ix >= 0x7ff00000 { + /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ + return x + f64::INFINITY; + } + if ix < ((0x3ff - 54) << 20) { + /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ + return 1.0 / x; + } + + /* integer arguments */ + /* raise inexact when non-integer */ + if x == floor(x) { + if sign { + return 0.0 / 0.0; + } + if x <= FACT.len() as f64 { + return i!(FACT, (x as usize) - 1); + } + } + + /* x >= 172: tgamma(x)=inf with overflow */ + /* x =< -184: tgamma(x)=+-0 with underflow */ + if ix >= 0x40670000 { + /* |x| >= 184 */ + if sign { + let x1p_126 = f64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 + force_eval!((x1p_126 / x) as f32); + if floor(x) * 0.5 == floor(x * 0.5) { + return 0.0; + } else { + return -0.0; + } + } + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 + x *= x1p1023; + return x; + } + + absx = if sign { -x } else { x }; + + /* handle the error of x + g - 0.5 */ + y = absx + GMHALF; + if absx > GMHALF { + dy = y - absx; + dy -= GMHALF; + } else { + dy = y - GMHALF; + dy -= absx; + } + + z = absx - 0.5; + r = s(absx) * exp(-y); + if x < 0.0 { + /* reflection formula for negative x */ + /* sinpi(absx) is not 0, integers are already handled */ + r = -PI / (sinpi(absx) * absx * r); + dy = -dy; + z = -z; + } + r += dy * (GMHALF + 0.5) * r / y; + z = pow(y, 0.5 * z); + y = r * z * z; + return y; +} diff --git a/library/compiler-builtins/libm/libm/src/math/tgammaf.rs b/library/compiler-builtins/libm/libm/src/math/tgammaf.rs new file mode 100644 index 00000000000..fe178f7a3c0 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/tgammaf.rs @@ -0,0 +1,7 @@ +use super::tgamma; + +/// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tgammaf(x: f32) -> f32 { + tgamma(x as f64) as f32 +} diff --git a/library/compiler-builtins/libm/libm/src/math/trunc.rs b/library/compiler-builtins/libm/libm/src/math/trunc.rs new file mode 100644 index 00000000000..fa50d55e136 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/trunc.rs @@ -0,0 +1,53 @@ +/// Rounds the number toward 0 to the closest integral value (f16). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf16(x: f16) -> f16 { + super::generic::trunc(x) +} + +/// Rounds the number toward 0 to the closest integral value (f32). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf(x: f32) -> f32 { + select_implementation! { + name: truncf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::trunc(x) +} + +/// Rounds the number toward 0 to the closest integral value (f64). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn trunc(x: f64) -> f64 { + select_implementation! { + name: trunc, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::trunc(x) +} + +/// Rounds the number toward 0 to the closest integral value (f128). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf128(x: f128) -> f128 { + super::generic::trunc(x) +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::truncf(1.1), 1.0); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/truncf.rs b/library/compiler-builtins/libm/libm/src/math/truncf.rs new file mode 100644 index 00000000000..14533a26706 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/truncf.rs @@ -0,0 +1,23 @@ +/// Rounds the number toward 0 to the closest integral value (f32). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf(x: f32) -> f32 { + select_implementation! { + name: truncf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::trunc(x) +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::truncf(1.1), 1.0); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/truncf128.rs b/library/compiler-builtins/libm/libm/src/math/truncf128.rs new file mode 100644 index 00000000000..9dccc0d0e9d --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/truncf128.rs @@ -0,0 +1,7 @@ +/// Rounds the number toward 0 to the closest integral value (f128). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf128(x: f128) -> f128 { + super::generic::trunc(x) +} diff --git a/library/compiler-builtins/libm/libm/src/math/truncf16.rs b/library/compiler-builtins/libm/libm/src/math/truncf16.rs new file mode 100644 index 00000000000..d7c3d225cf9 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/truncf16.rs @@ -0,0 +1,7 @@ +/// Rounds the number toward 0 to the closest integral value (f16). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf16(x: f16) -> f16 { + super::generic::trunc(x) +} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs deleted file mode 100644 index b0e4312110f..00000000000 --- a/library/compiler-builtins/libm/src/lib.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! libm in pure Rust -#![no_std] -#![cfg_attr(intrinsics_enabled, allow(internal_features))] -#![cfg_attr(intrinsics_enabled, feature(core_intrinsics))] -#![cfg_attr(all(intrinsics_enabled, target_family = "wasm"), feature(wasm_numeric_instr))] -#![cfg_attr(f128_enabled, feature(f128))] -#![cfg_attr(f16_enabled, feature(f16))] -#![allow(clippy::assign_op_pattern)] -#![allow(clippy::deprecated_cfg_attr)] -#![allow(clippy::eq_op)] -#![allow(clippy::excessive_precision)] -#![allow(clippy::float_cmp)] -#![allow(clippy::int_plus_one)] -#![allow(clippy::many_single_char_names)] -#![allow(clippy::mixed_case_hex_literals)] -#![allow(clippy::needless_late_init)] -#![allow(clippy::needless_return)] -#![allow(clippy::unreadable_literal)] -#![allow(clippy::zero_divided_by_zero)] - -mod libm_helper; -mod math; - -use core::{f32, f64}; - -pub use libm_helper::*; - -pub use self::math::*; diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs deleted file mode 100644 index dfa1ff77bf2..00000000000 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ /dev/null @@ -1,244 +0,0 @@ -use core::marker::PhantomData; - -use crate::*; - -/// Generic helper for libm functions, abstracting over f32 and f64.
-/// # Type Parameter: -/// - `T`: Either `f32` or `f64` -/// -/// # Examples -/// ```rust -/// use libm::{self, Libm}; -/// -/// const PI_F32: f32 = 3.1415927410e+00; -/// const PI_F64: f64 = 3.1415926535897931160e+00; -/// -/// assert!(Libm::::cos(0.0f32) == libm::cosf(0.0)); -/// assert!(Libm::::sin(PI_F32) == libm::sinf(PI_F32)); -/// -/// assert!(Libm::::cos(0.0f64) == libm::cos(0.0)); -/// assert!(Libm::::sin(PI_F64) == libm::sin(PI_F64)); -/// ``` -pub struct Libm(PhantomData); - -macro_rules! libm_helper { - ($t:ident, funcs: $funcs:tt) => { - impl Libm<$t> { - #![allow(unused_parens)] - - libm_helper! { $funcs } - } - }; - - ({$($func:tt;)*}) => { - $( - libm_helper! { $func } - )* - }; - - ((fn $func:ident($($arg:ident: $arg_typ:ty),*) -> ($($ret_typ:ty),*); => $libm_fn:ident)) => { - #[inline(always)] - pub fn $func($($arg: $arg_typ),*) -> ($($ret_typ),*) { - $libm_fn($($arg),*) - } - }; -} - -// verify-apilist-start -libm_helper! { - f32, - funcs: { - // verify-sorted-start - (fn acos(x: f32) -> (f32); => acosf); - (fn acosh(x: f32) -> (f32); => acoshf); - (fn asin(x: f32) -> (f32); => asinf); - (fn asinh(x: f32) -> (f32); => asinhf); - (fn atan(x: f32) -> (f32); => atanf); - (fn atan2(y: f32, x: f32) -> (f32); => atan2f); - (fn atanh(x: f32) -> (f32); => atanhf); - (fn cbrt(x: f32) -> (f32); => cbrtf); - (fn ceil(x: f32) -> (f32); => ceilf); - (fn copysign(x: f32, y: f32) -> (f32); => copysignf); - (fn cos(x: f32) -> (f32); => cosf); - (fn cosh(x: f32) -> (f32); => coshf); - (fn erf(x: f32) -> (f32); => erff); - (fn erfc(x: f32) -> (f32); => erfcf); - (fn exp(x: f32) -> (f32); => expf); - (fn exp10(x: f32) -> (f32); => exp10f); - (fn exp2(x: f32) -> (f32); => exp2f); - (fn expm1(x: f32) -> (f32); => expm1f); - (fn fabs(x: f32) -> (f32); => fabsf); - (fn fdim(x: f32, y: f32) -> (f32); => fdimf); - (fn floor(x: f32) -> (f32); => floorf); - (fn fma(x: f32, y: f32, z: f32) -> (f32); => fmaf); - (fn fmax(x: f32, y: f32) -> (f32); => fmaxf); - (fn fmin(x: f32, y: f32) -> (f32); => fminf); - (fn fmod(x: f32, y: f32) -> (f32); => fmodf); - (fn frexp(x: f32) -> (f32, i32); => frexpf); - (fn hypot(x: f32, y: f32) -> (f32); => hypotf); - (fn ilogb(x: f32) -> (i32); => ilogbf); - (fn j0(x: f32) -> (f32); => j0f); - (fn j1(x: f32) -> (f32); => j1f); - (fn jn(n: i32, x: f32) -> (f32); => jnf); - (fn ldexp(x: f32, n: i32) -> (f32); => ldexpf); - (fn lgamma(x: f32) -> (f32); => lgammaf); - (fn lgamma_r(x: f32) -> (f32, i32); => lgammaf_r); - (fn log(x: f32) -> (f32); => logf); - (fn log10(x: f32) -> (f32); => log10f); - (fn log1p(x: f32) -> (f32); => log1pf); - (fn log2(x: f32) -> (f32); => log2f); - (fn modf(x: f32) -> (f32, f32); => modff); - (fn nextafter(x: f32, y: f32) -> (f32); => nextafterf); - (fn pow(x: f32, y: f32) -> (f32); => powf); - (fn remainder(x: f32, y: f32) -> (f32); => remainderf); - (fn remquo(x: f32, y: f32) -> (f32, i32); => remquof); - (fn rint(x: f32) -> (f32); => rintf); - (fn round(x: f32) -> (f32); => roundf); - (fn roundeven(x: f32) -> (f32); => roundevenf); - (fn scalbn(x: f32, n: i32) -> (f32); => scalbnf); - (fn sin(x: f32) -> (f32); => sinf); - (fn sincos(x: f32) -> (f32, f32); => sincosf); - (fn sinh(x: f32) -> (f32); => sinhf); - (fn sqrt(x: f32) -> (f32); => sqrtf); - (fn tan(x: f32) -> (f32); => tanf); - (fn tanh(x: f32) -> (f32); => tanhf); - (fn tgamma(x: f32) -> (f32); => tgammaf); - (fn trunc(x: f32) -> (f32); => truncf); - (fn y0(x: f32) -> (f32); => y0f); - (fn y1(x: f32) -> (f32); => y1f); - (fn yn(n: i32, x: f32) -> (f32); => ynf); - // verify-sorted-end - } -} - -libm_helper! { - f64, - funcs: { - // verify-sorted-start - (fn acos(x: f64) -> (f64); => acos); - (fn acosh(x: f64) -> (f64); => acosh); - (fn asin(x: f64) -> (f64); => asin); - (fn asinh(x: f64) -> (f64); => asinh); - (fn atan(x: f64) -> (f64); => atan); - (fn atan2(y: f64, x: f64) -> (f64); => atan2); - (fn atanh(x: f64) -> (f64); => atanh); - (fn cbrt(x: f64) -> (f64); => cbrt); - (fn ceil(x: f64) -> (f64); => ceil); - (fn copysign(x: f64, y: f64) -> (f64); => copysign); - (fn cos(x: f64) -> (f64); => cos); - (fn cosh(x: f64) -> (f64); => cosh); - (fn erf(x: f64) -> (f64); => erf); - (fn erfc(x: f64) -> (f64); => erfc); - (fn exp(x: f64) -> (f64); => exp); - (fn exp10(x: f64) -> (f64); => exp10); - (fn exp2(x: f64) -> (f64); => exp2); - (fn expm1(x: f64) -> (f64); => expm1); - (fn fabs(x: f64) -> (f64); => fabs); - (fn fdim(x: f64, y: f64) -> (f64); => fdim); - (fn floor(x: f64) -> (f64); => floor); - (fn fma(x: f64, y: f64, z: f64) -> (f64); => fma); - (fn fmax(x: f64, y: f64) -> (f64); => fmax); - (fn fmaximum(x: f64, y: f64) -> (f64); => fmaximum); - (fn fmaximum_num(x: f64, y: f64) -> (f64); => fmaximum_num); - (fn fmaximum_numf(x: f32, y: f32) -> (f32); => fmaximum_numf); - (fn fmaximumf(x: f32, y: f32) -> (f32); => fmaximumf); - (fn fmin(x: f64, y: f64) -> (f64); => fmin); - (fn fminimum(x: f64, y: f64) -> (f64); => fminimum); - (fn fminimum_num(x: f64, y: f64) -> (f64); => fminimum_num); - (fn fminimum_numf(x: f32, y: f32) -> (f32); => fminimum_numf); - (fn fminimumf(x: f32, y: f32) -> (f32); => fminimumf); - (fn fmod(x: f64, y: f64) -> (f64); => fmod); - (fn frexp(x: f64) -> (f64, i32); => frexp); - (fn hypot(x: f64, y: f64) -> (f64); => hypot); - (fn ilogb(x: f64) -> (i32); => ilogb); - (fn j0(x: f64) -> (f64); => j0); - (fn j1(x: f64) -> (f64); => j1); - (fn jn(n: i32, x: f64) -> (f64); => jn); - (fn ldexp(x: f64, n: i32) -> (f64); => ldexp); - (fn lgamma(x: f64) -> (f64); => lgamma); - (fn lgamma_r(x: f64) -> (f64, i32); => lgamma_r); - (fn log(x: f64) -> (f64); => log); - (fn log10(x: f64) -> (f64); => log10); - (fn log1p(x: f64) -> (f64); => log1p); - (fn log2(x: f64) -> (f64); => log2); - (fn modf(x: f64) -> (f64, f64); => modf); - (fn nextafter(x: f64, y: f64) -> (f64); => nextafter); - (fn pow(x: f64, y: f64) -> (f64); => pow); - (fn remainder(x: f64, y: f64) -> (f64); => remainder); - (fn remquo(x: f64, y: f64) -> (f64, i32); => remquo); - (fn rint(x: f64) -> (f64); => rint); - (fn round(x: f64) -> (f64); => round); - (fn roundevem(x: f64) -> (f64); => roundeven); - (fn scalbn(x: f64, n: i32) -> (f64); => scalbn); - (fn sin(x: f64) -> (f64); => sin); - (fn sincos(x: f64) -> (f64, f64); => sincos); - (fn sinh(x: f64) -> (f64); => sinh); - (fn sqrt(x: f64) -> (f64); => sqrt); - (fn tan(x: f64) -> (f64); => tan); - (fn tanh(x: f64) -> (f64); => tanh); - (fn tgamma(x: f64) -> (f64); => tgamma); - (fn trunc(x: f64) -> (f64); => trunc); - (fn y0(x: f64) -> (f64); => y0); - (fn y1(x: f64) -> (f64); => y1); - (fn yn(n: i32, x: f64) -> (f64); => yn); - // verify-sorted-end - } -} - -#[cfg(f16_enabled)] -libm_helper! { - f16, - funcs: { - // verify-sorted-start - (fn ceil(x: f16) -> (f16); => ceilf16); - (fn copysign(x: f16, y: f16) -> (f16); => copysignf16); - (fn fabs(x: f16) -> (f16); => fabsf16); - (fn fdim(x: f16, y: f16) -> (f16); => fdimf16); - (fn floor(x: f16) -> (f16); => floorf16); - (fn fmax(x: f16, y: f16) -> (f16); => fmaxf16); - (fn fmaximum_num(x: f16, y: f16) -> (f16); => fmaximum_numf16); - (fn fmaximumf16(x: f16, y: f16) -> (f16); => fmaximumf16); - (fn fmin(x: f16, y: f16) -> (f16); => fminf16); - (fn fminimum(x: f16, y: f16) -> (f16); => fminimumf16); - (fn fminimum_num(x: f16, y: f16) -> (f16); => fminimum_numf16); - (fn fmod(x: f16, y: f16) -> (f16); => fmodf16); - (fn ldexp(x: f16, n: i32) -> (f16); => ldexpf16); - (fn rint(x: f16) -> (f16); => rintf16); - (fn round(x: f16) -> (f16); => roundf16); - (fn roundeven(x: f16) -> (f16); => roundevenf16); - (fn scalbn(x: f16, n: i32) -> (f16); => scalbnf16); - (fn sqrtf(x: f16) -> (f16); => sqrtf16); - (fn truncf(x: f16) -> (f16); => truncf16); - // verify-sorted-end - } -} - -#[cfg(f128_enabled)] -libm_helper! { - f128, - funcs: { - // verify-sorted-start - (fn ceil(x: f128) -> (f128); => ceilf128); - (fn copysign(x: f128, y: f128) -> (f128); => copysignf128); - (fn fabs(x: f128) -> (f128); => fabsf128); - (fn fdim(x: f128, y: f128) -> (f128); => fdimf128); - (fn floor(x: f128) -> (f128); => floorf128); - (fn fma(x: f128, y: f128, z: f128) -> (f128); => fmaf128); - (fn fmax(x: f128, y: f128) -> (f128); => fmaxf128); - (fn fmaximum(x: f128, y: f128) -> (f128); => fmaximumf128); - (fn fmaximum_num(x: f128, y: f128) -> (f128); => fmaximum_numf128); - (fn fmin(x: f128, y: f128) -> (f128); => fminf128); - (fn fminimum(x: f128, y: f128) -> (f128); => fminimumf128); - (fn fminimum_num(x: f128, y: f128) -> (f128); => fminimum_numf128); - (fn fmod(x: f128, y: f128) -> (f128); => fmodf128); - (fn ldexp(x: f128, n: i32) -> (f128); => ldexpf128); - (fn rint(x: f128) -> (f128); => rintf128); - (fn round(x: f128) -> (f128); => roundf128); - (fn roundeven(x: f128) -> (f128); => roundevenf128); - (fn scalbn(x: f128, n: i32) -> (f128); => scalbnf128); - (fn sqrt(x: f128) -> (f128); => sqrtf128); - (fn trunc(x: f128) -> (f128); => truncf128); - // verify-sorted-end - } -} -// verify-apilist-end diff --git a/library/compiler-builtins/libm/src/math/acos.rs b/library/compiler-builtins/libm/src/math/acos.rs deleted file mode 100644 index 23b13251ee2..00000000000 --- a/library/compiler-builtins/libm/src/math/acos.rs +++ /dev/null @@ -1,112 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* acos(x) - * Method : - * acos(x) = pi/2 - asin(x) - * acos(-x) = pi/2 + asin(x) - * For |x|<=0.5 - * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) - * For x>0.5 - * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) - * = 2asin(sqrt((1-x)/2)) - * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) - * = 2f + (2c + 2s*z*R(z)) - * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term - * for f so that f+c ~ sqrt(z). - * For x<-0.5 - * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) - * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) - * - * Special cases: - * if x is NaN, return x itself; - * if |x|>1, return NaN with invalid signal. - * - * Function needed: sqrt - */ - -use super::sqrt; - -const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ -const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ -const PS0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ -const PS1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ -const PS2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ -const PS3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ -const PS4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ -const PS5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ -const QS1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ -const QS2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ -const QS3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ -const QS4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ - -fn r(z: f64) -> f64 { - let p: f64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); - let q: f64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); - p / q -} - -/// Arccosine (f64) -/// -/// Computes the inverse cosine (arc cosine) of the input value. -/// Arguments must be in the range -1 to 1. -/// Returns values in radians, in the range of 0 to pi. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn acos(x: f64) -> f64 { - let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120 - let z: f64; - let w: f64; - let s: f64; - let c: f64; - let df: f64; - let hx: u32; - let ix: u32; - - hx = (x.to_bits() >> 32) as u32; - ix = hx & 0x7fffffff; - /* |x| >= 1 or nan */ - if ix >= 0x3ff00000 { - let lx: u32 = x.to_bits() as u32; - - if ((ix - 0x3ff00000) | lx) == 0 { - /* acos(1)=0, acos(-1)=pi */ - if (hx >> 31) != 0 { - return 2. * PIO2_HI + x1p_120f; - } - return 0.; - } - return 0. / (x - x); - } - /* |x| < 0.5 */ - if ix < 0x3fe00000 { - if ix <= 0x3c600000 { - /* |x| < 2**-57 */ - return PIO2_HI + x1p_120f; - } - return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); - } - /* x < -0.5 */ - if (hx >> 31) != 0 { - z = (1.0 + x) * 0.5; - s = sqrt(z); - w = r(z) * s - PIO2_LO; - return 2. * (PIO2_HI - (s + w)); - } - /* x > 0.5 */ - z = (1.0 - x) * 0.5; - s = sqrt(z); - // Set the low 4 bytes to zero - df = f64::from_bits(s.to_bits() & 0xff_ff_ff_ff_00_00_00_00); - - c = (z - df * df) / (s + df); - w = r(z) * s + c; - 2. * (df + w) -} diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs deleted file mode 100644 index dd88eea5b13..00000000000 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ /dev/null @@ -1,79 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::sqrt::sqrtf; - -const PIO2_HI: f32 = 1.5707962513e+00; /* 0x3fc90fda */ -const PIO2_LO: f32 = 7.5497894159e-08; /* 0x33a22168 */ -const P_S0: f32 = 1.6666586697e-01; -const P_S1: f32 = -4.2743422091e-02; -const P_S2: f32 = -8.6563630030e-03; -const Q_S1: f32 = -7.0662963390e-01; - -fn r(z: f32) -> f32 { - let p = z * (P_S0 + z * (P_S1 + z * P_S2)); - let q = 1. + z * Q_S1; - p / q -} - -/// Arccosine (f32) -/// -/// Computes the inverse cosine (arc cosine) of the input value. -/// Arguments must be in the range -1 to 1. -/// Returns values in radians, in the range of 0 to pi. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn acosf(x: f32) -> f32 { - let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) - - let z: f32; - let w: f32; - let s: f32; - - let mut hx = x.to_bits(); - let ix = hx & 0x7fffffff; - /* |x| >= 1 or nan */ - if ix >= 0x3f800000 { - if ix == 0x3f800000 { - if (hx >> 31) != 0 { - return 2. * PIO2_HI + x1p_120; - } - return 0.; - } - return 0. / (x - x); - } - /* |x| < 0.5 */ - if ix < 0x3f000000 { - if ix <= 0x32800000 { - /* |x| < 2**-26 */ - return PIO2_HI + x1p_120; - } - return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); - } - /* x < -0.5 */ - if (hx >> 31) != 0 { - z = (1. + x) * 0.5; - s = sqrtf(z); - w = r(z) * s - PIO2_LO; - return 2. * (PIO2_HI - (s + w)); - } - /* x > 0.5 */ - z = (1. - x) * 0.5; - s = sqrtf(z); - hx = s.to_bits(); - let df = f32::from_bits(hx & 0xfffff000); - let c = (z - df * df) / (s + df); - w = r(z) * s + c; - 2. * (df + w) -} diff --git a/library/compiler-builtins/libm/src/math/acosh.rs b/library/compiler-builtins/libm/src/math/acosh.rs deleted file mode 100644 index d1f5b9fa937..00000000000 --- a/library/compiler-builtins/libm/src/math/acosh.rs +++ /dev/null @@ -1,27 +0,0 @@ -use super::{log, log1p, sqrt}; - -const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ - -/// Inverse hyperbolic cosine (f64) -/// -/// Calculates the inverse hyperbolic cosine of `x`. -/// Is defined as `log(x + sqrt(x*x-1))`. -/// `x` must be a number greater than or equal to 1. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn acosh(x: f64) -> f64 { - let u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - - /* x < 1 domain error is handled in the called functions */ - - if e < 0x3ff + 1 { - /* |x| < 2, up to 2ulp error in [1,1.125] */ - return log1p(x - 1.0 + sqrt((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); - } - if e < 0x3ff + 26 { - /* |x| < 0x1p26 */ - return log(2.0 * x - 1.0 / (x + sqrt(x * x - 1.0))); - } - /* |x| >= 0x1p26 or nan */ - return log(x) + LN2; -} diff --git a/library/compiler-builtins/libm/src/math/acoshf.rs b/library/compiler-builtins/libm/src/math/acoshf.rs deleted file mode 100644 index ad3455fdd48..00000000000 --- a/library/compiler-builtins/libm/src/math/acoshf.rs +++ /dev/null @@ -1,26 +0,0 @@ -use super::{log1pf, logf, sqrtf}; - -const LN2: f32 = 0.693147180559945309417232121458176568; - -/// Inverse hyperbolic cosine (f32) -/// -/// Calculates the inverse hyperbolic cosine of `x`. -/// Is defined as `log(x + sqrt(x*x-1))`. -/// `x` must be a number greater than or equal to 1. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn acoshf(x: f32) -> f32 { - let u = x.to_bits(); - let a = u & 0x7fffffff; - - if a < 0x3f800000 + (1 << 23) { - /* |x| < 2, invalid if x < 1 or nan */ - /* up to 2ulp error in [1,1.125] */ - return log1pf(x - 1.0 + sqrtf((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); - } - if a < 0x3f800000 + (12 << 23) { - /* |x| < 0x1p12 */ - return logf(2.0 * x - 1.0 / (x + sqrtf(x * x - 1.0))); - } - /* x >= 0x1p12 */ - return logf(x) + LN2; -} diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64.rs b/library/compiler-builtins/libm/src/math/arch/aarch64.rs deleted file mode 100644 index 020bb731cdc..00000000000 --- a/library/compiler-builtins/libm/src/math/arch/aarch64.rs +++ /dev/null @@ -1,115 +0,0 @@ -//! Architecture-specific support for aarch64 with neon. - -use core::arch::asm; - -pub fn fma(mut x: f64, y: f64, z: f64) -> f64 { - // SAFETY: `fmadd` is available with neon and has no side effects. - unsafe { - asm!( - "fmadd {x:d}, {x:d}, {y:d}, {z:d}", - x = inout(vreg) x, - y = in(vreg) y, - z = in(vreg) z, - options(nomem, nostack, pure) - ); - } - x -} - -pub fn fmaf(mut x: f32, y: f32, z: f32) -> f32 { - // SAFETY: `fmadd` is available with neon and has no side effects. - unsafe { - asm!( - "fmadd {x:s}, {x:s}, {y:s}, {z:s}", - x = inout(vreg) x, - y = in(vreg) y, - z = in(vreg) z, - options(nomem, nostack, pure) - ); - } - x -} - -pub fn rint(mut x: f64) -> f64 { - // SAFETY: `frintn` is available with neon and has no side effects. - // - // `frintn` is always round-to-nearest which does not match the C specification, but Rust does - // not support rounding modes. - unsafe { - asm!( - "frintn {x:d}, {x:d}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} - -pub fn rintf(mut x: f32) -> f32 { - // SAFETY: `frintn` is available with neon and has no side effects. - // - // `frintn` is always round-to-nearest which does not match the C specification, but Rust does - // not support rounding modes. - unsafe { - asm!( - "frintn {x:s}, {x:s}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} - -#[cfg(all(f16_enabled, target_feature = "fp16"))] -pub fn rintf16(mut x: f16) -> f16 { - // SAFETY: `frintn` is available for `f16` with `fp16` (implies `neon`) and has no side effects. - // - // `frintn` is always round-to-nearest which does not match the C specification, but Rust does - // not support rounding modes. - unsafe { - asm!( - "frintn {x:h}, {x:h}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} - -pub fn sqrt(mut x: f64) -> f64 { - // SAFETY: `fsqrt` is available with neon and has no side effects. - unsafe { - asm!( - "fsqrt {x:d}, {x:d}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} - -pub fn sqrtf(mut x: f32) -> f32 { - // SAFETY: `fsqrt` is available with neon and has no side effects. - unsafe { - asm!( - "fsqrt {x:s}, {x:s}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} - -#[cfg(all(f16_enabled, target_feature = "fp16"))] -pub fn sqrtf16(mut x: f16) -> f16 { - // SAFETY: `fsqrt` is available for `f16` with `fp16` (implies `neon`) and has no - // side effects. - unsafe { - asm!( - "fsqrt {x:h}, {x:h}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} diff --git a/library/compiler-builtins/libm/src/math/arch/i586.rs b/library/compiler-builtins/libm/src/math/arch/i586.rs deleted file mode 100644 index f92b9a2af71..00000000000 --- a/library/compiler-builtins/libm/src/math/arch/i586.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! Architecture-specific support for x86-32 without SSE2 - -use super::super::fabs; - -/// Use an alternative implementation on x86, because the -/// main implementation fails with the x87 FPU used by -/// debian i386, probably due to excess precision issues. -/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219. -pub fn ceil(x: f64) -> f64 { - if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { - let truncated = x as i64 as f64; - if truncated < x { - return truncated + 1.0; - } else { - return truncated; - } - } else { - return x; - } -} - -/// Use an alternative implementation on x86, because the -/// main implementation fails with the x87 FPU used by -/// debian i386, probably due to excess precision issues. -/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219. -pub fn floor(x: f64) -> f64 { - if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { - let truncated = x as i64 as f64; - if truncated > x { - return truncated - 1.0; - } else { - return truncated; - } - } else { - return x; - } -} diff --git a/library/compiler-builtins/libm/src/math/arch/i686.rs b/library/compiler-builtins/libm/src/math/arch/i686.rs deleted file mode 100644 index 3e1d19bfab6..00000000000 --- a/library/compiler-builtins/libm/src/math/arch/i686.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Architecture-specific support for x86-32 and x86-64 with SSE2 - -pub fn sqrtf(mut x: f32) -> f32 { - // SAFETY: `sqrtss` is part of `sse2`, which this module is gated behind. It has no memory - // access or side effects. - unsafe { - core::arch::asm!( - "sqrtss {x}, {x}", - x = inout(xmm_reg) x, - options(nostack, nomem, pure), - ) - }; - x -} - -pub fn sqrt(mut x: f64) -> f64 { - // SAFETY: `sqrtsd` is part of `sse2`, which this module is gated behind. It has no memory - // access or side effects. - unsafe { - core::arch::asm!( - "sqrtsd {x}, {x}", - x = inout(xmm_reg) x, - options(nostack, nomem, pure), - ) - }; - x -} diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs deleted file mode 100644 index d9f2aad66d4..00000000000 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! Architecture-specific routines and operations. -//! -//! LLVM will already optimize calls to some of these in cases that there are hardware -//! instructions. Providing an implementation here just ensures that the faster implementation -//! is used when calling the function directly. This helps anyone who uses `libm` directly, as -//! well as improving things when these routines are called as part of other implementations. - -// Most implementations should be defined here, to ensure they are not made available when -// soft floats are required. -#[cfg(arch_enabled)] -cfg_if! { - if #[cfg(all(target_arch = "wasm32", intrinsics_enabled))] { - mod wasm32; - pub use wasm32::{ - ceil, ceilf, fabs, fabsf, floor, floorf, rint, rintf, sqrt, sqrtf, trunc, truncf, - }; - } else if #[cfg(target_feature = "sse2")] { - mod i686; - pub use i686::{sqrt, sqrtf}; - } else if #[cfg(all( - any(target_arch = "aarch64", target_arch = "arm64ec"), - target_feature = "neon" - ))] { - mod aarch64; - - pub use aarch64::{ - fma, - fmaf, - rint, - rintf, - sqrt, - sqrtf, - }; - - #[cfg(all(f16_enabled, target_feature = "fp16"))] - pub use aarch64::{ - rintf16, - sqrtf16, - }; - } -} - -// There are certain architecture-specific implementations that are needed for correctness -// even with `force-soft-float`. These are configured here. -cfg_if! { - if #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] { - mod i586; - pub use i586::{ceil, floor}; - } -} diff --git a/library/compiler-builtins/libm/src/math/arch/wasm32.rs b/library/compiler-builtins/libm/src/math/arch/wasm32.rs deleted file mode 100644 index de80c8a5817..00000000000 --- a/library/compiler-builtins/libm/src/math/arch/wasm32.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! Wasm has builtins for simple float operations. Use the unstable `core::arch` intrinsics which -//! are significantly faster than soft float operations. - -pub fn ceil(x: f64) -> f64 { - core::arch::wasm32::f64_ceil(x) -} - -pub fn ceilf(x: f32) -> f32 { - core::arch::wasm32::f32_ceil(x) -} - -pub fn fabs(x: f64) -> f64 { - x.abs() -} - -pub fn fabsf(x: f32) -> f32 { - x.abs() -} - -pub fn floor(x: f64) -> f64 { - core::arch::wasm32::f64_floor(x) -} - -pub fn floorf(x: f32) -> f32 { - core::arch::wasm32::f32_floor(x) -} - -pub fn rint(x: f64) -> f64 { - core::arch::wasm32::f64_nearest(x) -} - -pub fn rintf(x: f32) -> f32 { - core::arch::wasm32::f32_nearest(x) -} - -pub fn sqrt(x: f64) -> f64 { - core::arch::wasm32::f64_sqrt(x) -} - -pub fn sqrtf(x: f32) -> f32 { - core::arch::wasm32::f32_sqrt(x) -} - -pub fn trunc(x: f64) -> f64 { - core::arch::wasm32::f64_trunc(x) -} - -pub fn truncf(x: f32) -> f32 { - core::arch::wasm32::f32_trunc(x) -} diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs deleted file mode 100644 index 12d0cd35fa5..00000000000 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ /dev/null @@ -1,115 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* asin(x) - * Method : - * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... - * we approximate asin(x) on [0,0.5] by - * asin(x) = x + x*x^2*R(x^2) - * where - * R(x^2) is a rational approximation of (asin(x)-x)/x^3 - * and its remez error is bounded by - * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) - * - * For x in [0.5,1] - * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) - * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; - * then for x>0.98 - * asin(x) = pi/2 - 2*(s+s*z*R(z)) - * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) - * For x<=0.98, let pio4_hi = pio2_hi/2, then - * f = hi part of s; - * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) - * and - * asin(x) = pi/2 - 2*(s+s*z*R(z)) - * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) - * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) - * - * Special cases: - * if x is NaN, return x itself; - * if |x|>1, return NaN with invalid signal. - * - */ - -use super::{fabs, get_high_word, get_low_word, sqrt, with_set_low_word}; - -const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ -const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ -/* coefficients for R(x^2) */ -const P_S0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ -const P_S1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ -const P_S2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ -const P_S3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ -const P_S4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ -const P_S5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ -const Q_S1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ -const Q_S2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ -const Q_S3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ -const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ - -fn comp_r(z: f64) -> f64 { - let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); - let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); - p / q -} - -/// Arcsine (f64) -/// -/// Computes the inverse sine (arc sine) of the argument `x`. -/// Arguments to asin must be in the range -1 to 1. -/// Returns values in radians, in the range of -pi/2 to pi/2. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn asin(mut x: f64) -> f64 { - let z: f64; - let r: f64; - let s: f64; - let hx: u32; - let ix: u32; - - hx = get_high_word(x); - ix = hx & 0x7fffffff; - /* |x| >= 1 or nan */ - if ix >= 0x3ff00000 { - let lx: u32; - lx = get_low_word(x); - if ((ix - 0x3ff00000) | lx) == 0 { - /* asin(1) = +-pi/2 with inexact */ - return x * PIO2_HI + f64::from_bits(0x3870000000000000); - } else { - return 0.0 / (x - x); - } - } - /* |x| < 0.5 */ - if ix < 0x3fe00000 { - /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ - if (0x00100000..0x3e500000).contains(&ix) { - return x; - } else { - return x + x * comp_r(x * x); - } - } - /* 1 > |x| >= 0.5 */ - z = (1.0 - fabs(x)) * 0.5; - s = sqrt(z); - r = comp_r(z); - if ix >= 0x3fef3333 { - /* if |x| > 0.975 */ - x = PIO2_HI - (2. * (s + s * r) - PIO2_LO); - } else { - let f: f64; - let c: f64; - /* f+c = sqrt(z) */ - f = with_set_low_word(s, 0); - c = (z - f * f) / (s + f); - x = 0.5 * PIO2_HI - (2.0 * s * r - (PIO2_LO - 2.0 * c) - (0.5 * PIO2_HI - 2.0 * f)); - } - if hx >> 31 != 0 { -x } else { x } -} diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs deleted file mode 100644 index ed685556730..00000000000 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ /dev/null @@ -1,68 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::sqrt::sqrt; -use super::support::Float; - -const PIO2: f64 = 1.570796326794896558e+00; - -/* coefficients for R(x^2) */ -const P_S0: f32 = 1.6666586697e-01; -const P_S1: f32 = -4.2743422091e-02; -const P_S2: f32 = -8.6563630030e-03; -const Q_S1: f32 = -7.0662963390e-01; - -fn r(z: f32) -> f32 { - let p = z * (P_S0 + z * (P_S1 + z * P_S2)); - let q = 1. + z * Q_S1; - p / q -} - -/// Arcsine (f32) -/// -/// Computes the inverse sine (arc sine) of the argument `x`. -/// Arguments to asin must be in the range -1 to 1. -/// Returns values in radians, in the range of -pi/2 to pi/2. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn asinf(mut x: f32) -> f32 { - let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120) - - let hx = x.to_bits(); - let ix = hx & 0x7fffffff; - - if ix >= 0x3f800000 { - /* |x| >= 1 */ - if ix == 0x3f800000 { - /* |x| == 1 */ - return ((x as f64) * PIO2 + x1p_120) as f32; /* asin(+-1) = +-pi/2 with inexact */ - } - return 0. / (x - x); /* asin(|x|>1) is NaN */ - } - - if ix < 0x3f000000 { - /* |x| < 0.5 */ - /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ - if (0x00800000..0x39800000).contains(&ix) { - return x; - } - return x + x * r(x * x); - } - - /* 1 > |x| >= 0.5 */ - let z = (1. - Float::abs(x)) * 0.5; - let s = sqrt(z as f64); - x = (PIO2 - 2. * (s + s * (r(z) as f64))) as f32; - if (hx >> 31) != 0 { -x } else { x } -} diff --git a/library/compiler-builtins/libm/src/math/asinh.rs b/library/compiler-builtins/libm/src/math/asinh.rs deleted file mode 100644 index 75d3c3ad462..00000000000 --- a/library/compiler-builtins/libm/src/math/asinh.rs +++ /dev/null @@ -1,36 +0,0 @@ -use super::{log, log1p, sqrt}; - -const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ - -/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ -/// Inverse hyperbolic sine (f64) -/// -/// Calculates the inverse hyperbolic sine of `x`. -/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn asinh(mut x: f64) -> f64 { - let mut u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - let sign = (u >> 63) != 0; - - /* |x| */ - u &= (!0) >> 1; - x = f64::from_bits(u); - - if e >= 0x3ff + 26 { - /* |x| >= 0x1p26 or inf or nan */ - x = log(x) + LN2; - } else if e >= 0x3ff + 1 { - /* |x| >= 2 */ - x = log(2.0 * x + 1.0 / (sqrt(x * x + 1.0) + x)); - } else if e >= 0x3ff - 26 { - /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ - x = log1p(x + x * x / (sqrt(x * x + 1.0) + 1.0)); - } else { - /* |x| < 0x1p-26, raise inexact if x != 0 */ - let x1p120 = f64::from_bits(0x4770000000000000); - force_eval!(x + x1p120); - } - - if sign { -x } else { x } -} diff --git a/library/compiler-builtins/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/src/math/asinhf.rs deleted file mode 100644 index 27ed9dd372d..00000000000 --- a/library/compiler-builtins/libm/src/math/asinhf.rs +++ /dev/null @@ -1,35 +0,0 @@ -use super::{log1pf, logf, sqrtf}; - -const LN2: f32 = 0.693147180559945309417232121458176568; - -/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ -/// Inverse hyperbolic sine (f32) -/// -/// Calculates the inverse hyperbolic sine of `x`. -/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn asinhf(mut x: f32) -> f32 { - let u = x.to_bits(); - let i = u & 0x7fffffff; - let sign = (u >> 31) != 0; - - /* |x| */ - x = f32::from_bits(i); - - if i >= 0x3f800000 + (12 << 23) { - /* |x| >= 0x1p12 or inf or nan */ - x = logf(x) + LN2; - } else if i >= 0x3f800000 + (1 << 23) { - /* |x| >= 2 */ - x = logf(2.0 * x + 1.0 / (sqrtf(x * x + 1.0) + x)); - } else if i >= 0x3f800000 - (12 << 23) { - /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ - x = log1pf(x + x * x / (sqrtf(x * x + 1.0) + 1.0)); - } else { - /* |x| < 0x1p-12, raise inexact if x!=0 */ - let x1p120 = f32::from_bits(0x7b800000); - force_eval!(x + x1p120); - } - - if sign { -x } else { x } -} diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs deleted file mode 100644 index 4ca5cc91a1e..00000000000 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ /dev/null @@ -1,182 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* atan(x) - * Method - * 1. Reduce x to positive by atan(x) = -atan(-x). - * 2. According to the integer k=4t+0.25 chopped, t=x, the argument - * is further reduced to one of the following intervals and the - * arctangent of t is evaluated by the corresponding formula: - * - * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) - * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) - * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) - * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) - * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) - * - * Constants: - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. - */ - -use core::f64; - -use super::fabs; - -const ATANHI: [f64; 4] = [ - 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ - 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ - 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ - 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ -]; - -const ATANLO: [f64; 4] = [ - 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ - 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ - 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ - 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ -]; - -const AT: [f64; 11] = [ - 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ - -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ - 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ - -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ - 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ - -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ - 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ - -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ - 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ - -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ - 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ -]; - -/// Arctangent (f64) -/// -/// Computes the inverse tangent (arc tangent) of the input value. -/// Returns a value in radians, in the range of -pi/2 to pi/2. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atan(x: f64) -> f64 { - let mut x = x; - let mut ix = (x.to_bits() >> 32) as u32; - let sign = ix >> 31; - ix &= 0x7fff_ffff; - if ix >= 0x4410_0000 { - if x.is_nan() { - return x; - } - - let z = ATANHI[3] + f64::from_bits(0x0380_0000); // 0x1p-120f - return if sign != 0 { -z } else { z }; - } - - let id = if ix < 0x3fdc_0000 { - /* |x| < 0.4375 */ - if ix < 0x3e40_0000 { - /* |x| < 2^-27 */ - if ix < 0x0010_0000 { - /* raise underflow for subnormal x */ - force_eval!(x as f32); - } - - return x; - } - - -1 - } else { - x = fabs(x); - if ix < 0x3ff30000 { - /* |x| < 1.1875 */ - if ix < 0x3fe60000 { - /* 7/16 <= |x| < 11/16 */ - x = (2. * x - 1.) / (2. + x); - 0 - } else { - /* 11/16 <= |x| < 19/16 */ - x = (x - 1.) / (x + 1.); - 1 - } - } else if ix < 0x40038000 { - /* |x| < 2.4375 */ - x = (x - 1.5) / (1. + 1.5 * x); - 2 - } else { - /* 2.4375 <= |x| < 2^66 */ - x = -1. / x; - 3 - } - }; - - let z = x * x; - let w = z * z; - /* break sum from i=0 to 10 AT[i]z**(i+1) into odd and even poly */ - let s1 = z * (AT[0] + w * (AT[2] + w * (AT[4] + w * (AT[6] + w * (AT[8] + w * AT[10]))))); - let s2 = w * (AT[1] + w * (AT[3] + w * (AT[5] + w * (AT[7] + w * AT[9])))); - - if id < 0 { - return x - x * (s1 + s2); - } - - let z = i!(ATANHI, id as usize) - (x * (s1 + s2) - i!(ATANLO, id as usize) - x); - - if sign != 0 { -z } else { z } -} - -#[cfg(test)] -mod tests { - use core::f64; - - use super::atan; - - #[test] - fn sanity_check() { - for (input, answer) in [ - (3.0_f64.sqrt() / 3.0, f64::consts::FRAC_PI_6), - (1.0, f64::consts::FRAC_PI_4), - (3.0_f64.sqrt(), f64::consts::FRAC_PI_3), - (-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6), - (-1.0, -f64::consts::FRAC_PI_4), - (-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3), - ] - .iter() - { - assert!( - (atan(*input) - answer) / answer < 1e-5, - "\natan({:.4}/16) = {:.4}, actual: {}", - input * 16.0, - answer, - atan(*input) - ); - } - } - - #[test] - fn zero() { - assert_eq!(atan(0.0), 0.0); - } - - #[test] - fn infinity() { - assert_eq!(atan(f64::INFINITY), f64::consts::FRAC_PI_2); - } - - #[test] - fn minus_infinity() { - assert_eq!(atan(f64::NEG_INFINITY), -f64::consts::FRAC_PI_2); - } - - #[test] - fn nan() { - assert!(atan(f64::NAN).is_nan()); - } -} diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs deleted file mode 100644 index c668731cf37..00000000000 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ /dev/null @@ -1,131 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - * - */ -/* atan2(y,x) - * Method : - * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). - * 2. Reduce x to positive by (if x and y are unexceptional): - * ARG (x+iy) = arctan(y/x) ... if x > 0, - * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, - * - * Special cases: - * - * ATAN2((anything), NaN ) is NaN; - * ATAN2(NAN , (anything) ) is NaN; - * ATAN2(+-0, +(anything but NaN)) is +-0 ; - * ATAN2(+-0, -(anything but NaN)) is +-pi ; - * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; - * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; - * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; - * ATAN2(+-INF,+INF ) is +-pi/4 ; - * ATAN2(+-INF,-INF ) is +-3pi/4; - * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; - * - * Constants: - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. - */ - -use super::{atan, fabs}; - -const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ -const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ - -/// Arctangent of y/x (f64) -/// -/// Computes the inverse tangent (arc tangent) of `y/x`. -/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). -/// Returns a value in radians, in the range of -pi to pi. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atan2(y: f64, x: f64) -> f64 { - if x.is_nan() || y.is_nan() { - return x + y; - } - let mut ix = (x.to_bits() >> 32) as u32; - let lx = x.to_bits() as u32; - let mut iy = (y.to_bits() >> 32) as u32; - let ly = y.to_bits() as u32; - if ((ix.wrapping_sub(0x3ff00000)) | lx) == 0 { - /* x = 1.0 */ - return atan(y); - } - let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ - ix &= 0x7fffffff; - iy &= 0x7fffffff; - - /* when y = 0 */ - if (iy | ly) == 0 { - return match m { - 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ - 2 => PI, /* atan(+0,-anything) = PI */ - _ => -PI, /* atan(-0,-anything) =-PI */ - }; - } - /* when x = 0 */ - if (ix | lx) == 0 { - return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; - } - /* when x is INF */ - if ix == 0x7ff00000 { - if iy == 0x7ff00000 { - return match m { - 0 => PI / 4.0, /* atan(+INF,+INF) */ - 1 => -PI / 4.0, /* atan(-INF,+INF) */ - 2 => 3.0 * PI / 4.0, /* atan(+INF,-INF) */ - _ => -3.0 * PI / 4.0, /* atan(-INF,-INF) */ - }; - } else { - return match m { - 0 => 0.0, /* atan(+...,+INF) */ - 1 => -0.0, /* atan(-...,+INF) */ - 2 => PI, /* atan(+...,-INF) */ - _ => -PI, /* atan(-...,-INF) */ - }; - } - } - /* |y/x| > 0x1p64 */ - if ix.wrapping_add(64 << 20) < iy || iy == 0x7ff00000 { - return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; - } - - /* z = atan(|y/x|) without spurious underflow */ - let z = if (m & 2 != 0) && iy.wrapping_add(64 << 20) < ix { - /* |y/x| < 0x1p-64, x<0 */ - 0.0 - } else { - atan(fabs(y / x)) - }; - match m { - 0 => z, /* atan(+,+) */ - 1 => -z, /* atan(-,+) */ - 2 => PI - (z - PI_LO), /* atan(+,-) */ - _ => (z - PI_LO) - PI, /* atan(-,-) */ - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[cfg_attr(x86_no_sse, ignore = "FIXME(i586): possible incorrect rounding")] - fn sanity_check() { - assert_eq!(atan2(0.0, 1.0), 0.0); - assert_eq!(atan2(0.0, -1.0), PI); - assert_eq!(atan2(-0.0, -1.0), -PI); - assert_eq!(atan2(3.0, 2.0), atan(3.0 / 2.0)); - assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI); - assert_eq!(atan2(-2.0, -1.0), atan(-2.0 / -1.0) - PI); - } -} diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs deleted file mode 100644 index 95b466fff4e..00000000000 --- a/library/compiler-builtins/libm/src/math/atan2f.rs +++ /dev/null @@ -1,90 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{atanf, fabsf}; - -const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ -const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ - -/// Arctangent of y/x (f32) -/// -/// Computes the inverse tangent (arc tangent) of `y/x`. -/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). -/// Returns a value in radians, in the range of -pi to pi. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atan2f(y: f32, x: f32) -> f32 { - if x.is_nan() || y.is_nan() { - return x + y; - } - let mut ix = x.to_bits(); - let mut iy = y.to_bits(); - - if ix == 0x3f800000 { - /* x=1.0 */ - return atanf(y); - } - let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ - ix &= 0x7fffffff; - iy &= 0x7fffffff; - - /* when y = 0 */ - if iy == 0 { - return match m { - 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ - 2 => PI, /* atan(+0,-anything) = pi */ - _ => -PI, /* atan(-0,-anything) =-pi */ - }; - } - /* when x = 0 */ - if ix == 0 { - return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; - } - /* when x is INF */ - if ix == 0x7f800000 { - return if iy == 0x7f800000 { - match m { - 0 => PI / 4., /* atan(+INF,+INF) */ - 1 => -PI / 4., /* atan(-INF,+INF) */ - 2 => 3. * PI / 4., /* atan(+INF,-INF)*/ - _ => -3. * PI / 4., /* atan(-INF,-INF)*/ - } - } else { - match m { - 0 => 0., /* atan(+...,+INF) */ - 1 => -0., /* atan(-...,+INF) */ - 2 => PI, /* atan(+...,-INF) */ - _ => -PI, /* atan(-...,-INF) */ - } - }; - } - /* |y/x| > 0x1p26 */ - if (ix + (26 << 23) < iy) || (iy == 0x7f800000) { - return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; - } - - /* z = atan(|y/x|) with correct underflow */ - let z = if (m & 2 != 0) && (iy + (26 << 23) < ix) { - /*|y/x| < 0x1p-26, x < 0 */ - 0. - } else { - atanf(fabsf(y / x)) - }; - match m { - 0 => z, /* atan(+,+) */ - 1 => -z, /* atan(-,+) */ - 2 => PI - (z - PI_LO), /* atan(+,-) */ - _ => (z - PI_LO) - PI, /* case 3 */ /* atan(-,-) */ - } -} diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs deleted file mode 100644 index eb3d401cd96..00000000000 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ /dev/null @@ -1,103 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::fabsf; - -const ATAN_HI: [f32; 4] = [ - 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ - 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ - 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ - 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ -]; - -const ATAN_LO: [f32; 4] = [ - 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ - 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ - 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ - 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ -]; - -const A_T: [f32; 5] = - [3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, -1.0648017377e-01, 6.1687607318e-02]; - -/// Arctangent (f32) -/// -/// Computes the inverse tangent (arc tangent) of the input value. -/// Returns a value in radians, in the range of -pi/2 to pi/2. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atanf(mut x: f32) -> f32 { - let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) - - let z: f32; - - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - if ix >= 0x4c800000 { - /* if |x| >= 2**26 */ - if x.is_nan() { - return x; - } - z = i!(ATAN_HI, 3) + x1p_120; - return if sign { -z } else { z }; - } - let id = if ix < 0x3ee00000 { - /* |x| < 0.4375 */ - if ix < 0x39800000 { - /* |x| < 2**-12 */ - if ix < 0x00800000 { - /* raise underflow for subnormal x */ - force_eval!(x * x); - } - return x; - } - -1 - } else { - x = fabsf(x); - if ix < 0x3f980000 { - /* |x| < 1.1875 */ - if ix < 0x3f300000 { - /* 7/16 <= |x| < 11/16 */ - x = (2. * x - 1.) / (2. + x); - 0 - } else { - /* 11/16 <= |x| < 19/16 */ - x = (x - 1.) / (x + 1.); - 1 - } - } else if ix < 0x401c0000 { - /* |x| < 2.4375 */ - x = (x - 1.5) / (1. + 1.5 * x); - 2 - } else { - /* 2.4375 <= |x| < 2**26 */ - x = -1. / x; - 3 - } - }; - /* end of argument reduction */ - z = x * x; - let w = z * z; - /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ - let s1 = z * (i!(A_T, 0) + w * (i!(A_T, 2) + w * i!(A_T, 4))); - let s2 = w * (i!(A_T, 1) + w * i!(A_T, 3)); - if id < 0 { - return x - x * (s1 + s2); - } - let id = id as usize; - let z = i!(ATAN_HI, id) - ((x * (s1 + s2) - i!(ATAN_LO, id)) - x); - if sign { -z } else { z } -} diff --git a/library/compiler-builtins/libm/src/math/atanh.rs b/library/compiler-builtins/libm/src/math/atanh.rs deleted file mode 100644 index 9dc826f5605..00000000000 --- a/library/compiler-builtins/libm/src/math/atanh.rs +++ /dev/null @@ -1,33 +0,0 @@ -use super::log1p; - -/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ -/// Inverse hyperbolic tangent (f64) -/// -/// Calculates the inverse hyperbolic tangent of `x`. -/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atanh(x: f64) -> f64 { - let u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - let sign = (u >> 63) != 0; - - /* |x| */ - let mut y = f64::from_bits(u & 0x7fff_ffff_ffff_ffff); - - if e < 0x3ff - 1 { - if e < 0x3ff - 32 { - /* handle underflow */ - if e == 0 { - force_eval!(y as f32); - } - } else { - /* |x| < 0.5, up to 1.7ulp error */ - y = 0.5 * log1p(2.0 * y + 2.0 * y * y / (1.0 - y)); - } - } else { - /* avoid overflow */ - y = 0.5 * log1p(2.0 * (y / (1.0 - y))); - } - - if sign { -y } else { y } -} diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs deleted file mode 100644 index 80ccec1f67f..00000000000 --- a/library/compiler-builtins/libm/src/math/atanhf.rs +++ /dev/null @@ -1,33 +0,0 @@ -use super::log1pf; - -/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ -/// Inverse hyperbolic tangent (f32) -/// -/// Calculates the inverse hyperbolic tangent of `x`. -/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atanhf(mut x: f32) -> f32 { - let mut u = x.to_bits(); - let sign = (u >> 31) != 0; - - /* |x| */ - u &= 0x7fffffff; - x = f32::from_bits(u); - - if u < 0x3f800000 - (1 << 23) { - if u < 0x3f800000 - (32 << 23) { - /* handle underflow */ - if u < (1 << 23) { - force_eval!(x * x); - } - } else { - /* |x| < 0.5, up to 1.7ulp error */ - x = 0.5 * log1pf(2.0 * x + 2.0 * x * x / (1.0 - x)); - } - } else { - /* avoid overflow */ - x = 0.5 * log1pf(2.0 * (x / (1.0 - x))); - } - - if sign { -x } else { x } -} diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs deleted file mode 100644 index 9d3311cd6a8..00000000000 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ /dev/null @@ -1,215 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: core-math/src/binary64/cbrt/cbrt.c - * Copyright (c) 2021-2022 Alexei Sibidanov. - * Ported to Rust in 2025 by Trevor Gross. - */ - -use super::Float; -use super::support::{FpResult, Round, cold_path}; - -/// Compute the cube root of the argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cbrt(x: f64) -> f64 { - cbrt_round(x, Round::Nearest).val -} - -pub fn cbrt_round(x: f64, round: Round) -> FpResult { - const ESCALE: [f64; 3] = [ - 1.0, - hf64!("0x1.428a2f98d728bp+0"), /* 2^(1/3) */ - hf64!("0x1.965fea53d6e3dp+0"), /* 2^(2/3) */ - ]; - - /* the polynomial c0+c1*x+c2*x^2+c3*x^3 approximates x^(1/3) on [1,2] - with maximal error < 9.2e-5 (attained at x=2) */ - const C: [f64; 4] = [ - hf64!("0x1.1b0babccfef9cp-1"), - hf64!("0x1.2c9a3e94d1da5p-1"), - hf64!("-0x1.4dc30b1a1ddbap-3"), - hf64!("0x1.7a8d3e4ec9b07p-6"), - ]; - - let u0: f64 = hf64!("0x1.5555555555555p-2"); - let u1: f64 = hf64!("0x1.c71c71c71c71cp-3"); - - let rsc = [1.0, -1.0, 0.5, -0.5, 0.25, -0.25]; - - let off = [hf64!("0x1p-53"), 0.0, 0.0, 0.0]; - - /* rm=0 for rounding to nearest, and other values for directed roundings */ - let hx: u64 = x.to_bits(); - let mut mant: u64 = hx & f64::SIG_MASK; - let sign: u64 = hx >> 63; - - let mut e: u32 = (hx >> f64::SIG_BITS) as u32 & f64::EXP_SAT; - - if ((e + 1) & f64::EXP_SAT) < 2 { - cold_path(); - - let ix: u64 = hx & !f64::SIGN_MASK; - - /* 0, inf, nan: we return x + x instead of simply x, - to that for x a signaling NaN, it correctly triggers - the invalid exception. */ - if e == f64::EXP_SAT || ix == 0 { - return FpResult::ok(x + x); - } - - let nz = ix.leading_zeros() - 11; /* subnormal */ - mant <<= nz; - mant &= f64::SIG_MASK; - e = e.wrapping_sub(nz - 1); - } - - e = e.wrapping_add(3072); - let cvt1: u64 = mant | (0x3ffu64 << 52); - let mut cvt5: u64 = cvt1; - - let et: u32 = e / 3; - let it: u32 = e % 3; - - /* 2^(3k+it) <= x < 2^(3k+it+1), with 0 <= it <= 3 */ - cvt5 += u64::from(it) << f64::SIG_BITS; - cvt5 |= sign << 63; - let zz: f64 = f64::from_bits(cvt5); - - /* cbrt(x) = cbrt(zz)*2^(et-1365) where 1 <= zz < 8 */ - let mut isc: u64 = ESCALE[it as usize].to_bits(); // todo: index - isc |= sign << 63; - let cvt2: u64 = isc; - let z: f64 = f64::from_bits(cvt1); - - /* cbrt(zz) = cbrt(z)*isc, where isc encodes 1, 2^(1/3) or 2^(2/3), - and 1 <= z < 2 */ - let r: f64 = 1.0 / z; - let rr: f64 = r * rsc[((it as usize) << 1) | sign as usize]; - let z2: f64 = z * z; - let c0: f64 = C[0] + z * C[1]; - let c2: f64 = C[2] + z * C[3]; - let mut y: f64 = c0 + z2 * c2; - let mut y2: f64 = y * y; - - /* y is an approximation of z^(1/3) */ - let mut h: f64 = y2 * (y * r) - 1.0; - - /* h determines the error between y and z^(1/3) */ - y -= (h * y) * (u0 - u1 * h); - - /* The correction y -= (h*y)*(u0 - u1*h) corresponds to a cubic variant - of Newton's method, with the function f(y) = 1-z/y^3. */ - y *= f64::from_bits(cvt2); - - /* Now y is an approximation of zz^(1/3), - * and rr an approximation of 1/zz. We now perform another iteration of - * Newton-Raphson, this time with a linear approximation only. */ - y2 = y * y; - let mut y2l: f64 = y.fma(y, -y2); - - /* y2 + y2l = y^2 exactly */ - let mut y3: f64 = y2 * y; - let mut y3l: f64 = y.fma(y2, -y3) + y * y2l; - - /* y3 + y3l approximates y^3 with about 106 bits of accuracy */ - h = ((y3 - zz) + y3l) * rr; - let mut dy: f64 = h * (y * u0); - - /* the approximation of zz^(1/3) is y - dy */ - let mut y1: f64 = y - dy; - dy = (y - y1) - dy; - - /* the approximation of zz^(1/3) is now y1 + dy, where |dy| < 1/2 ulp(y) - * (for rounding to nearest) */ - let mut ady: f64 = dy.abs(); - - /* For directed roundings, ady0 is tiny when dy is tiny, or ady0 is near - * from ulp(1); - * for rounding to nearest, ady0 is tiny when dy is near from 1/2 ulp(1), - * or from 3/2 ulp(1). */ - let mut ady0: f64 = (ady - off[round as usize]).abs(); - let mut ady1: f64 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs(); - - if ady0 < hf64!("0x1p-75") || ady1 < hf64!("0x1p-75") { - cold_path(); - - y2 = y1 * y1; - y2l = y1.fma(y1, -y2); - y3 = y2 * y1; - y3l = y1.fma(y2, -y3) + y1 * y2l; - h = ((y3 - zz) + y3l) * rr; - dy = h * (y1 * u0); - y = y1 - dy; - dy = (y1 - y) - dy; - y1 = y; - ady = dy.abs(); - ady0 = (ady - off[round as usize]).abs(); - ady1 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs(); - - if ady0 < hf64!("0x1p-98") || ady1 < hf64!("0x1p-98") { - cold_path(); - let azz: f64 = zz.abs(); - - // ~ 0x1.79d15d0e8d59b80000000000000ffc3dp+0 - if azz == hf64!("0x1.9b78223aa307cp+1") { - y1 = hf64!("0x1.79d15d0e8d59cp+0").copysign(zz); - } - - // ~ 0x1.de87aa837820e80000000000001c0f08p+0 - if azz == hf64!("0x1.a202bfc89ddffp+2") { - y1 = hf64!("0x1.de87aa837820fp+0").copysign(zz); - } - - if round != Round::Nearest { - let wlist = [ - (hf64!("0x1.3a9ccd7f022dbp+0"), hf64!("0x1.1236160ba9b93p+0")), // ~ 0x1.1236160ba9b930000000000001e7e8fap+0 - (hf64!("0x1.7845d2faac6fep+0"), hf64!("0x1.23115e657e49cp+0")), // ~ 0x1.23115e657e49c0000000000001d7a799p+0 - (hf64!("0x1.d1ef81cbbbe71p+0"), hf64!("0x1.388fb44cdcf5ap+0")), // ~ 0x1.388fb44cdcf5a0000000000002202c55p+0 - (hf64!("0x1.0a2014f62987cp+1"), hf64!("0x1.46bcbf47dc1e8p+0")), // ~ 0x1.46bcbf47dc1e8000000000000303aa2dp+0 - (hf64!("0x1.fe18a044a5501p+1"), hf64!("0x1.95decfec9c904p+0")), // ~ 0x1.95decfec9c9040000000000000159e8ep+0 - (hf64!("0x1.a6bb8c803147bp+2"), hf64!("0x1.e05335a6401dep+0")), // ~ 0x1.e05335a6401de00000000000027ca017p+0 - (hf64!("0x1.ac8538a031cbdp+2"), hf64!("0x1.e281d87098de8p+0")), // ~ 0x1.e281d87098de80000000000000ee9314p+0 - ]; - - for (a, b) in wlist { - if azz == a { - let tmp = if round as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 }; - y1 = (b + tmp).copysign(zz); - } - } - } - } - } - - let mut cvt3: u64 = y1.to_bits(); - cvt3 = cvt3.wrapping_add(((et.wrapping_sub(342).wrapping_sub(1023)) as u64) << 52); - let m0: u64 = cvt3 << 30; - let m1 = m0 >> 63; - - if (m0 ^ m1) <= (1u64 << 30) { - cold_path(); - - let mut cvt4: u64 = y1.to_bits(); - cvt4 = (cvt4 + (164 << 15)) & 0xffffffffffff0000u64; - - if ((f64::from_bits(cvt4) - y1) - dy).abs() < hf64!("0x1p-60") || (zz).abs() == 1.0 { - cvt3 = (cvt3 + (1u64 << 15)) & 0xffffffffffff0000u64; - } - } - - FpResult::ok(f64::from_bits(cvt3)) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn spot_checks() { - if !cfg!(x86_no_sse) { - // Exposes a rounding mode problem. Ignored on i586 because of inaccurate FMA. - assert_biteq!( - cbrt(f64::from_bits(0xf7f792b28f600000)), - f64::from_bits(0xd29ce68655d962f3) - ); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/cbrtf.rs b/library/compiler-builtins/libm/src/math/cbrtf.rs deleted file mode 100644 index 9d70305c647..00000000000 --- a/library/compiler-builtins/libm/src/math/cbrtf.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Debugged and optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* cbrtf(x) - * Return cube root of x - */ - -use core::f32; - -const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ -const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ - -/// Cube root (f32) -/// -/// Computes the cube root of the argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cbrtf(x: f32) -> f32 { - let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 - - let mut r: f64; - let mut t: f64; - let mut ui: u32 = x.to_bits(); - let mut hx: u32 = ui & 0x7fffffff; - - if hx >= 0x7f800000 { - /* cbrt(NaN,INF) is itself */ - return x + x; - } - - /* rough cbrt to 5 bits */ - if hx < 0x00800000 { - /* zero or subnormal? */ - if hx == 0 { - return x; /* cbrt(+-0) is itself */ - } - ui = (x * x1p24).to_bits(); - hx = ui & 0x7fffffff; - hx = hx / 3 + B2; - } else { - hx = hx / 3 + B1; - } - ui &= 0x80000000; - ui |= hx; - - /* - * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In - * double precision so that its terms can be arranged for efficiency - * without causing overflow or underflow. - */ - t = f32::from_bits(ui) as f64; - r = t * t * t; - t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); - - /* - * Second step Newton iteration to 47 bits. In double precision for - * efficiency and accuracy. - */ - r = t * t * t; - t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); - - /* rounding to 24 bits is perfect in round-to-nearest mode */ - t as f32 -} diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs deleted file mode 100644 index 4e103545727..00000000000 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ /dev/null @@ -1,46 +0,0 @@ -/// Ceil (f16) -/// -/// Finds the nearest integer greater than or equal to `x`. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceilf16(x: f16) -> f16 { - super::generic::ceil(x) -} - -/// Ceil (f32) -/// -/// Finds the nearest integer greater than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceilf(x: f32) -> f32 { - select_implementation! { - name: ceilf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::ceil(x) -} - -/// Ceil (f64) -/// -/// Finds the nearest integer greater than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceil(x: f64) -> f64 { - select_implementation! { - name: ceil, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), - args: x, - } - - super::generic::ceil(x) -} - -/// Ceil (f128) -/// -/// Finds the nearest integer greater than or equal to `x`. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceilf128(x: f128) -> f128 { - super::generic::ceil(x) -} diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs deleted file mode 100644 index d2a86e7fd54..00000000000 --- a/library/compiler-builtins/libm/src/math/copysign.rs +++ /dev/null @@ -1,88 +0,0 @@ -/// Sign of Y, magnitude of X (f16) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf16(x: f16, y: f16) -> f16 { - super::generic::copysign(x, y) -} - -/// Sign of Y, magnitude of X (f32) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf(x: f32, y: f32) -> f32 { - super::generic::copysign(x, y) -} - -/// Sign of Y, magnitude of X (f64) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysign(x: f64, y: f64) -> f64 { - super::generic::copysign(x, y) -} - -/// Sign of Y, magnitude of X (f128) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf128(x: f128, y: f128) -> f128 { - super::generic::copysign(x, y) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Float; - - fn spec_test(f: impl Fn(F, F) -> F) { - assert_biteq!(f(F::ZERO, F::ZERO), F::ZERO); - assert_biteq!(f(F::NEG_ZERO, F::ZERO), F::ZERO); - assert_biteq!(f(F::ZERO, F::NEG_ZERO), F::NEG_ZERO); - assert_biteq!(f(F::NEG_ZERO, F::NEG_ZERO), F::NEG_ZERO); - - assert_biteq!(f(F::ONE, F::ONE), F::ONE); - assert_biteq!(f(F::NEG_ONE, F::ONE), F::ONE); - assert_biteq!(f(F::ONE, F::NEG_ONE), F::NEG_ONE); - assert_biteq!(f(F::NEG_ONE, F::NEG_ONE), F::NEG_ONE); - - assert_biteq!(f(F::INFINITY, F::INFINITY), F::INFINITY); - assert_biteq!(f(F::NEG_INFINITY, F::INFINITY), F::INFINITY); - assert_biteq!(f(F::INFINITY, F::NEG_INFINITY), F::NEG_INFINITY); - assert_biteq!(f(F::NEG_INFINITY, F::NEG_INFINITY), F::NEG_INFINITY); - - // Not required but we expect it - assert_biteq!(f(F::NAN, F::NAN), F::NAN); - assert_biteq!(f(F::NEG_NAN, F::NAN), F::NAN); - assert_biteq!(f(F::NAN, F::NEG_NAN), F::NEG_NAN); - assert_biteq!(f(F::NEG_NAN, F::NEG_NAN), F::NEG_NAN); - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(copysignf16); - } - - #[test] - fn spec_tests_f32() { - spec_test::(copysignf); - } - - #[test] - fn spec_tests_f64() { - spec_test::(copysign); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(copysignf128); - } -} diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs deleted file mode 100644 index de99cd4c5e4..00000000000 --- a/library/compiler-builtins/libm/src/math/cos.rs +++ /dev/null @@ -1,77 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */ -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunPro, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -use super::{k_cos, k_sin, rem_pio2}; - -// cos(x) -// Return cosine function of x. -// -// kernel function: -// k_sin ... sine function on [-pi/4,pi/4] -// k_cos ... cosine function on [-pi/4,pi/4] -// rem_pio2 ... argument reduction routine -// -// Method. -// Let S,C and T denote the sin, cos and tan respectively on -// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 -// in [-pi/4 , +pi/4], and let n = k mod 4. -// We have -// -// n sin(x) cos(x) tan(x) -// ---------------------------------------------------------- -// 0 S C T -// 1 C -S -1/T -// 2 -S -C T -// 3 -C S -1/T -// ---------------------------------------------------------- -// -// Special cases: -// Let trig be any of sin, cos, or tan. -// trig(+-INF) is NaN, with signals; -// trig(NaN) is that NaN; -// -// Accuracy: -// TRIG(x) returns trig(x) nearly rounded -// - -/// The cosine of `x` (f64). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cos(x: f64) -> f64 { - let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; - - /* |x| ~< pi/4 */ - if ix <= 0x3fe921fb { - if ix < 0x3e46a09e { - /* if x < 2**-27 * sqrt(2) */ - /* raise inexact if x != 0 */ - if x as i32 == 0 { - return 1.0; - } - } - return k_cos(x, 0.0); - } - - /* cos(Inf or NaN) is NaN */ - if ix >= 0x7ff00000 { - return x - x; - } - - /* argument reduction needed */ - let (n, y0, y1) = rem_pio2(x); - match n & 3 { - 0 => k_cos(y0, y1), - 1 => -k_sin(y0, y1, 1), - 2 => -k_cos(y0, y1), - _ => k_sin(y0, y1, 1), - } -} diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs deleted file mode 100644 index 27c2fc3b994..00000000000 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ /dev/null @@ -1,86 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::f64::consts::FRAC_PI_2; - -use super::{k_cosf, k_sinf, rem_pio2f}; - -/* Small multiples of pi/2 rounded to double precision. */ -const C1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ -const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ - -/// The cosine of `x` (f32). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cosf(x: f32) -> f32 { - let x64 = x as f64; - - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - if ix <= 0x3f490fda { - /* |x| ~<= pi/4 */ - if ix < 0x39800000 { - /* |x| < 2**-12 */ - /* raise inexact if x != 0 */ - force_eval!(x + x1p120); - return 1.; - } - return k_cosf(x64); - } - if ix <= 0x407b53d1 { - /* |x| ~<= 5*pi/4 */ - if ix > 0x4016cbe3 { - /* |x| ~> 3*pi/4 */ - return -k_cosf(if sign { x64 + C2_PIO2 } else { x64 - C2_PIO2 }); - } else if sign { - return k_sinf(x64 + C1_PIO2); - } else { - return k_sinf(C1_PIO2 - x64); - } - } - if ix <= 0x40e231d5 { - /* |x| ~<= 9*pi/4 */ - if ix > 0x40afeddf { - /* |x| ~> 7*pi/4 */ - return k_cosf(if sign { x64 + C4_PIO2 } else { x64 - C4_PIO2 }); - } else if sign { - return k_sinf(-x64 - C3_PIO2); - } else { - return k_sinf(x64 - C3_PIO2); - } - } - - /* cos(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - return x - x; - } - - /* general argument reduction needed */ - let (n, y) = rem_pio2f(x); - match n & 3 { - 0 => k_cosf(y), - 1 => k_sinf(-y), - 2 => -k_cosf(y), - _ => k_sinf(y), - } -} diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs deleted file mode 100644 index d2e43fd6cb6..00000000000 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ /dev/null @@ -1,36 +0,0 @@ -use super::{exp, expm1, k_expo2}; - -/// Hyperbolic cosine (f64) -/// -/// Computes the hyperbolic cosine of the argument x. -/// Is defined as `(exp(x) + exp(-x))/2` -/// Angles are specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cosh(mut x: f64) -> f64 { - /* |x| */ - let mut ix = x.to_bits(); - ix &= 0x7fffffffffffffff; - x = f64::from_bits(ix); - let w = ix >> 32; - - /* |x| < log(2) */ - if w < 0x3fe62e42 { - if w < 0x3ff00000 - (26 << 20) { - let x1p120 = f64::from_bits(0x4770000000000000); - force_eval!(x + x1p120); - return 1.; - } - let t = expm1(x); // exponential minus 1 - return 1. + t * t / (2. * (1. + t)); - } - - /* |x| < log(DBL_MAX) */ - if w < 0x40862e42 { - let t = exp(x); - /* note: if x>log(0x1p26) then the 1/t is not needed */ - return 0.5 * (t + 1. / t); - } - - /* |x| > log(DBL_MAX) or nan */ - k_expo2(x) -} diff --git a/library/compiler-builtins/libm/src/math/coshf.rs b/library/compiler-builtins/libm/src/math/coshf.rs deleted file mode 100644 index 567a24410e7..00000000000 --- a/library/compiler-builtins/libm/src/math/coshf.rs +++ /dev/null @@ -1,36 +0,0 @@ -use super::{expf, expm1f, k_expo2f}; - -/// Hyperbolic cosine (f64) -/// -/// Computes the hyperbolic cosine of the argument x. -/// Is defined as `(exp(x) + exp(-x))/2` -/// Angles are specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn coshf(mut x: f32) -> f32 { - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - /* |x| */ - let mut ix = x.to_bits(); - ix &= 0x7fffffff; - x = f32::from_bits(ix); - let w = ix; - - /* |x| < log(2) */ - if w < 0x3f317217 { - if w < (0x3f800000 - (12 << 23)) { - force_eval!(x + x1p120); - return 1.; - } - let t = expm1f(x); - return 1. + t * t / (2. * (1. + t)); - } - - /* |x| < log(FLT_MAX) */ - if w < 0x42b17217 { - let t = expf(x); - return 0.5 * (t + 1. / t); - } - - /* |x| > log(FLT_MAX) or nan */ - k_expo2f(x) -} diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs deleted file mode 100644 index 1b634abec6b..00000000000 --- a/library/compiler-builtins/libm/src/math/erf.rs +++ /dev/null @@ -1,310 +0,0 @@ -use super::{exp, fabs, get_high_word, with_set_low_word}; -/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* double erf(double x) - * double erfc(double x) - * x - * 2 |\ - * erf(x) = --------- | exp(-t*t)dt - * sqrt(pi) \| - * 0 - * - * erfc(x) = 1-erf(x) - * Note that - * erf(-x) = -erf(x) - * erfc(-x) = 2 - erfc(x) - * - * Method: - * 1. For |x| in [0, 0.84375] - * erf(x) = x + x*R(x^2) - * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] - * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] - * where R = P/Q where P is an odd poly of degree 8 and - * Q is an odd poly of degree 10. - * -57.90 - * | R - (erf(x)-x)/x | <= 2 - * - * - * Remark. The formula is derived by noting - * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) - * and that - * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 - * is close to one. The interval is chosen because the fix - * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is - * near 0.6174), and by some experiment, 0.84375 is chosen to - * guarantee the error is less than one ulp for erf. - * - * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and - * c = 0.84506291151 rounded to single (24 bits) - * erf(x) = sign(x) * (c + P1(s)/Q1(s)) - * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 - * 1+(c+P1(s)/Q1(s)) if x < 0 - * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 - * Remark: here we use the taylor series expansion at x=1. - * erf(1+s) = erf(1) + s*Poly(s) - * = 0.845.. + P1(s)/Q1(s) - * That is, we use rational approximation to approximate - * erf(1+s) - (c = (single)0.84506291151) - * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] - * where - * P1(s) = degree 6 poly in s - * Q1(s) = degree 6 poly in s - * - * 3. For x in [1.25,1/0.35(~2.857143)], - * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) - * erf(x) = 1 - erfc(x) - * where - * R1(z) = degree 7 poly in z, (z=1/x^2) - * S1(z) = degree 8 poly in z - * - * 4. For x in [1/0.35,28] - * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 - * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 - * erf(x) = sign(x) *(1 - tiny) (raise inexact) - * erfc(x) = tiny*tiny (raise underflow) if x > 0 - * = 2 - tiny if x<0 - * - * 7. Special case: - * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, - * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, - * erfc/erf(NaN) is NaN - */ - -const ERX: f64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ -/* - * Coefficients for approximation to erf on [0,0.84375] - */ -const EFX8: f64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ -const PP0: f64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ -const PP1: f64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ -const PP2: f64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */ -const PP3: f64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */ -const PP4: f64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */ -const QQ1: f64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */ -const QQ2: f64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ -const QQ3: f64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ -const QQ4: f64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ -const QQ5: f64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ -/* - * Coefficients for approximation to erf in [0.84375,1.25] - */ -const PA0: f64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ -const PA1: f64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ -const PA2: f64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ -const PA3: f64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */ -const PA4: f64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */ -const PA5: f64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */ -const PA6: f64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */ -const QA1: f64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */ -const QA2: f64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */ -const QA3: f64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ -const QA4: f64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ -const QA5: f64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ -const QA6: f64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ -/* - * Coefficients for approximation to erfc in [1.25,1/0.35] - */ -const RA0: f64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ -const RA1: f64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ -const RA2: f64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ -const RA3: f64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */ -const RA4: f64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */ -const RA5: f64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */ -const RA6: f64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */ -const RA7: f64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */ -const SA1: f64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */ -const SA2: f64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */ -const SA3: f64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */ -const SA4: f64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */ -const SA5: f64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ -const SA6: f64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ -const SA7: f64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ -const SA8: f64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ -/* - * Coefficients for approximation to erfc in [1/.35,28] - */ -const RB0: f64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ -const RB1: f64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ -const RB2: f64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ -const RB3: f64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */ -const RB4: f64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */ -const RB5: f64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */ -const RB6: f64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */ -const SB1: f64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */ -const SB2: f64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */ -const SB3: f64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */ -const SB4: f64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ -const SB5: f64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ -const SB6: f64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ -const SB7: f64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ - -fn erfc1(x: f64) -> f64 { - let s: f64; - let p: f64; - let q: f64; - - s = fabs(x) - 1.0; - p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); - q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); - - 1.0 - ERX - p / q -} - -fn erfc2(ix: u32, mut x: f64) -> f64 { - let s: f64; - let r: f64; - let big_s: f64; - let z: f64; - - if ix < 0x3ff40000 { - /* |x| < 1.25 */ - return erfc1(x); - } - - x = fabs(x); - s = 1.0 / (x * x); - if ix < 0x4006db6d { - /* |x| < 1/.35 ~ 2.85714 */ - r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); - big_s = 1.0 - + s * (SA1 - + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); - } else { - /* |x| > 1/.35 */ - r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); - big_s = - 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); - } - z = with_set_low_word(x, 0); - - exp(-z * z - 0.5625) * exp((z - x) * (z + x) + r / big_s) / x -} - -/// Error function (f64) -/// -/// Calculates an approximation to the “error function”, which estimates -/// the probability that an observation will fall within x standard -/// deviations of the mean (assuming a normal distribution). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn erf(x: f64) -> f64 { - let r: f64; - let s: f64; - let z: f64; - let y: f64; - let mut ix: u32; - let sign: usize; - - ix = get_high_word(x); - sign = (ix >> 31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - /* erf(nan)=nan, erf(+-inf)=+-1 */ - return 1.0 - 2.0 * (sign as f64) + 1.0 / x; - } - if ix < 0x3feb0000 { - /* |x| < 0.84375 */ - if ix < 0x3e300000 { - /* |x| < 2**-28 */ - /* avoid underflow */ - return 0.125 * (8.0 * x + EFX8 * x); - } - z = x * x; - r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); - s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); - y = r / s; - return x + x * y; - } - if ix < 0x40180000 { - /* 0.84375 <= |x| < 6 */ - y = 1.0 - erfc2(ix, x); - } else { - let x1p_1022 = f64::from_bits(0x0010000000000000); - y = 1.0 - x1p_1022; - } - - if sign != 0 { -y } else { y } -} - -/// Complementary error function (f64) -/// -/// Calculates the complementary probability. -/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid -/// the loss of precision that would result from subtracting -/// large probabilities (on large `x`) from 1. -pub fn erfc(x: f64) -> f64 { - let r: f64; - let s: f64; - let z: f64; - let y: f64; - let mut ix: u32; - let sign: usize; - - ix = get_high_word(x); - sign = (ix >> 31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - /* erfc(nan)=nan, erfc(+-inf)=0,2 */ - return 2.0 * (sign as f64) + 1.0 / x; - } - if ix < 0x3feb0000 { - /* |x| < 0.84375 */ - if ix < 0x3c700000 { - /* |x| < 2**-56 */ - return 1.0 - x; - } - z = x * x; - r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); - s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); - y = r / s; - if sign != 0 || ix < 0x3fd00000 { - /* x < 1/4 */ - return 1.0 - (x + x * y); - } - return 0.5 - (x - 0.5 + x * y); - } - if ix < 0x403c0000 { - /* 0.84375 <= |x| < 28 */ - if sign != 0 { - return 2.0 - erfc2(ix, x); - } else { - return erfc2(ix, x); - } - } - - let x1p_1022 = f64::from_bits(0x0010000000000000); - if sign != 0 { 2.0 - x1p_1022 } else { x1p_1022 * x1p_1022 } -} diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs deleted file mode 100644 index 2e41183bfc0..00000000000 --- a/library/compiler-builtins/libm/src/math/erff.rs +++ /dev/null @@ -1,222 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{expf, fabsf}; - -const ERX: f32 = 8.4506291151e-01; /* 0x3f58560b */ -/* - * Coefficients for approximation to erf on [0,0.84375] - */ -const EFX8: f32 = 1.0270333290e+00; /* 0x3f8375d4 */ -const PP0: f32 = 1.2837916613e-01; /* 0x3e0375d4 */ -const PP1: f32 = -3.2504209876e-01; /* 0xbea66beb */ -const PP2: f32 = -2.8481749818e-02; /* 0xbce9528f */ -const PP3: f32 = -5.7702702470e-03; /* 0xbbbd1489 */ -const PP4: f32 = -2.3763017452e-05; /* 0xb7c756b1 */ -const QQ1: f32 = 3.9791721106e-01; /* 0x3ecbbbce */ -const QQ2: f32 = 6.5022252500e-02; /* 0x3d852a63 */ -const QQ3: f32 = 5.0813062117e-03; /* 0x3ba68116 */ -const QQ4: f32 = 1.3249473704e-04; /* 0x390aee49 */ -const QQ5: f32 = -3.9602282413e-06; /* 0xb684e21a */ -/* - * Coefficients for approximation to erf in [0.84375,1.25] - */ -const PA0: f32 = -2.3621185683e-03; /* 0xbb1acdc6 */ -const PA1: f32 = 4.1485610604e-01; /* 0x3ed46805 */ -const PA2: f32 = -3.7220788002e-01; /* 0xbebe9208 */ -const PA3: f32 = 3.1834661961e-01; /* 0x3ea2fe54 */ -const PA4: f32 = -1.1089469492e-01; /* 0xbde31cc2 */ -const PA5: f32 = 3.5478305072e-02; /* 0x3d1151b3 */ -const PA6: f32 = -2.1663755178e-03; /* 0xbb0df9c0 */ -const QA1: f32 = 1.0642088205e-01; /* 0x3dd9f331 */ -const QA2: f32 = 5.4039794207e-01; /* 0x3f0a5785 */ -const QA3: f32 = 7.1828655899e-02; /* 0x3d931ae7 */ -const QA4: f32 = 1.2617121637e-01; /* 0x3e013307 */ -const QA5: f32 = 1.3637083583e-02; /* 0x3c5f6e13 */ -const QA6: f32 = 1.1984500103e-02; /* 0x3c445aa3 */ -/* - * Coefficients for approximation to erfc in [1.25,1/0.35] - */ -const RA0: f32 = -9.8649440333e-03; /* 0xbc21a093 */ -const RA1: f32 = -6.9385856390e-01; /* 0xbf31a0b7 */ -const RA2: f32 = -1.0558626175e+01; /* 0xc128f022 */ -const RA3: f32 = -6.2375331879e+01; /* 0xc2798057 */ -const RA4: f32 = -1.6239666748e+02; /* 0xc322658c */ -const RA5: f32 = -1.8460508728e+02; /* 0xc3389ae7 */ -const RA6: f32 = -8.1287437439e+01; /* 0xc2a2932b */ -const RA7: f32 = -9.8143291473e+00; /* 0xc11d077e */ -const SA1: f32 = 1.9651271820e+01; /* 0x419d35ce */ -const SA2: f32 = 1.3765776062e+02; /* 0x4309a863 */ -const SA3: f32 = 4.3456588745e+02; /* 0x43d9486f */ -const SA4: f32 = 6.4538726807e+02; /* 0x442158c9 */ -const SA5: f32 = 4.2900814819e+02; /* 0x43d6810b */ -const SA6: f32 = 1.0863500214e+02; /* 0x42d9451f */ -const SA7: f32 = 6.5702495575e+00; /* 0x40d23f7c */ -const SA8: f32 = -6.0424413532e-02; /* 0xbd777f97 */ -/* - * Coefficients for approximation to erfc in [1/.35,28] - */ -const RB0: f32 = -9.8649431020e-03; /* 0xbc21a092 */ -const RB1: f32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ -const RB2: f32 = -1.7757955551e+01; /* 0xc18e104b */ -const RB3: f32 = -1.6063638306e+02; /* 0xc320a2ea */ -const RB4: f32 = -6.3756646729e+02; /* 0xc41f6441 */ -const RB5: f32 = -1.0250950928e+03; /* 0xc480230b */ -const RB6: f32 = -4.8351919556e+02; /* 0xc3f1c275 */ -const SB1: f32 = 3.0338060379e+01; /* 0x41f2b459 */ -const SB2: f32 = 3.2579251099e+02; /* 0x43a2e571 */ -const SB3: f32 = 1.5367296143e+03; /* 0x44c01759 */ -const SB4: f32 = 3.1998581543e+03; /* 0x4547fdbb */ -const SB5: f32 = 2.5530502930e+03; /* 0x451f90ce */ -const SB6: f32 = 4.7452853394e+02; /* 0x43ed43a7 */ -const SB7: f32 = -2.2440952301e+01; /* 0xc1b38712 */ - -fn erfc1(x: f32) -> f32 { - let s: f32; - let p: f32; - let q: f32; - - s = fabsf(x) - 1.0; - p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); - q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); - return 1.0 - ERX - p / q; -} - -fn erfc2(mut ix: u32, mut x: f32) -> f32 { - let s: f32; - let r: f32; - let big_s: f32; - let z: f32; - - if ix < 0x3fa00000 { - /* |x| < 1.25 */ - return erfc1(x); - } - - x = fabsf(x); - s = 1.0 / (x * x); - if ix < 0x4036db6d { - /* |x| < 1/0.35 */ - r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); - big_s = 1.0 - + s * (SA1 - + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); - } else { - /* |x| >= 1/0.35 */ - r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); - big_s = - 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); - } - ix = x.to_bits(); - z = f32::from_bits(ix & 0xffffe000); - - expf(-z * z - 0.5625) * expf((z - x) * (z + x) + r / big_s) / x -} - -/// Error function (f32) -/// -/// Calculates an approximation to the “error function”, which estimates -/// the probability that an observation will fall within x standard -/// deviations of the mean (assuming a normal distribution). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn erff(x: f32) -> f32 { - let r: f32; - let s: f32; - let z: f32; - let y: f32; - let mut ix: u32; - let sign: usize; - - ix = x.to_bits(); - sign = (ix >> 31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - /* erf(nan)=nan, erf(+-inf)=+-1 */ - return 1.0 - 2.0 * (sign as f32) + 1.0 / x; - } - if ix < 0x3f580000 { - /* |x| < 0.84375 */ - if ix < 0x31800000 { - /* |x| < 2**-28 */ - /*avoid underflow */ - return 0.125 * (8.0 * x + EFX8 * x); - } - z = x * x; - r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); - s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); - y = r / s; - return x + x * y; - } - if ix < 0x40c00000 { - /* |x| < 6 */ - y = 1.0 - erfc2(ix, x); - } else { - let x1p_120 = f32::from_bits(0x03800000); - y = 1.0 - x1p_120; - } - - if sign != 0 { -y } else { y } -} - -/// Complementary error function (f32) -/// -/// Calculates the complementary probability. -/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid -/// the loss of precision that would result from subtracting -/// large probabilities (on large `x`) from 1. -pub fn erfcf(x: f32) -> f32 { - let r: f32; - let s: f32; - let z: f32; - let y: f32; - let mut ix: u32; - let sign: usize; - - ix = x.to_bits(); - sign = (ix >> 31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - /* erfc(nan)=nan, erfc(+-inf)=0,2 */ - return 2.0 * (sign as f32) + 1.0 / x; - } - - if ix < 0x3f580000 { - /* |x| < 0.84375 */ - if ix < 0x23800000 { - /* |x| < 2**-56 */ - return 1.0 - x; - } - z = x * x; - r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); - s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); - y = r / s; - if sign != 0 || ix < 0x3e800000 { - /* x < 1/4 */ - return 1.0 - (x + x * y); - } - return 0.5 - (x - 0.5 + x * y); - } - if ix < 0x41e00000 { - /* |x| < 28 */ - if sign != 0 { - return 2.0 - erfc2(ix, x); - } else { - return erfc2(ix, x); - } - } - - let x1p_120 = f32::from_bits(0x03800000); - if sign != 0 { 2.0 - x1p_120 } else { x1p_120 * x1p_120 } -} diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs deleted file mode 100644 index 782042b62cd..00000000000 --- a/library/compiler-builtins/libm/src/math/exp.rs +++ /dev/null @@ -1,150 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */ -/* - * ==================================================== - * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. - * - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* exp(x) - * Returns the exponential of x. - * - * Method - * 1. Argument reduction: - * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. - * Given x, find r and integer k such that - * - * x = k*ln2 + r, |r| <= 0.5*ln2. - * - * Here r will be represented as r = hi-lo for better - * accuracy. - * - * 2. Approximation of exp(r) by a special rational function on - * the interval [0,0.34658]: - * Write - * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... - * We use a special Remez algorithm on [0,0.34658] to generate - * a polynomial of degree 5 to approximate R. The maximum error - * of this polynomial approximation is bounded by 2**-59. In - * other words, - * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 - * (where z=r*r, and the values of P1 to P5 are listed below) - * and - * | 5 | -59 - * | 2.0+P1*z+...+P5*z - R(z) | <= 2 - * | | - * The computation of exp(r) thus becomes - * 2*r - * exp(r) = 1 + ---------- - * R(r) - r - * r*c(r) - * = 1 + r + ----------- (for better accuracy) - * 2 - c(r) - * where - * 2 4 10 - * c(r) = r - (P1*r + P2*r + ... + P5*r ). - * - * 3. Scale back to obtain exp(x): - * From step 1, we have - * exp(x) = 2^k * exp(r) - * - * Special cases: - * exp(INF) is INF, exp(NaN) is NaN; - * exp(-INF) is 0, and - * for finite argument, only exp(0)=1 is exact. - * - * Accuracy: - * according to an error analysis, the error is always less than - * 1 ulp (unit in the last place). - * - * Misc. info. - * For IEEE double - * if x > 709.782712893383973096 then exp(x) overflows - * if x < -745.133219101941108420 then exp(x) underflows - */ - -use super::scalbn; - -const HALF: [f64; 2] = [0.5, -0.5]; -const LN2HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ -const LN2LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ -const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ -const P1: f64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */ -const P2: f64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ -const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ -const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ -const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ - -/// Exponential, base *e* (f64) -/// -/// Calculate the exponential of `x`, that is, *e* raised to the power `x` -/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp(mut x: f64) -> f64 { - let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 - let x1p_149 = f64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149 - - let hi: f64; - let lo: f64; - let c: f64; - let xx: f64; - let y: f64; - let k: i32; - let sign: i32; - let mut hx: u32; - - hx = (x.to_bits() >> 32) as u32; - sign = (hx >> 31) as i32; - hx &= 0x7fffffff; /* high word of |x| */ - - /* special cases */ - if hx >= 0x4086232b { - /* if |x| >= 708.39... */ - if x.is_nan() { - return x; - } - if x > 709.782712893383973096 { - /* overflow if x!=inf */ - x *= x1p1023; - return x; - } - if x < -708.39641853226410622 { - /* underflow if x!=-inf */ - force_eval!((-x1p_149 / x) as f32); - if x < -745.13321910194110842 { - return 0.; - } - } - } - - /* argument reduction */ - if hx > 0x3fd62e42 { - /* if |x| > 0.5 ln2 */ - if hx >= 0x3ff0a2b2 { - /* if |x| >= 1.5 ln2 */ - k = (INVLN2 * x + i!(HALF, sign as usize)) as i32; - } else { - k = 1 - sign - sign; - } - hi = x - k as f64 * LN2HI; /* k*ln2hi is exact here */ - lo = k as f64 * LN2LO; - x = hi - lo; - } else if hx > 0x3e300000 { - /* if |x| > 2**-28 */ - k = 0; - hi = x; - lo = 0.; - } else { - /* inexact if x!=0 */ - force_eval!(x1p1023 + x); - return 1. + x; - } - - /* x is now in primary range */ - xx = x * x; - c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); - y = 1. + (x * c / (2. - c) - lo + hi); - if k == 0 { y } else { scalbn(y, k) } -} diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs deleted file mode 100644 index 7c33c92b603..00000000000 --- a/library/compiler-builtins/libm/src/math/exp10.rs +++ /dev/null @@ -1,23 +0,0 @@ -use super::{exp2, modf, pow}; - -const LN10: f64 = 3.32192809488736234787031942948939; -const P10: &[f64] = &[ - 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, -]; - -/// Calculates 10 raised to the power of `x` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp10(x: f64) -> f64 { - let (mut y, n) = modf(x); - let u: u64 = n.to_bits(); - /* fabs(n) < 16 without raising invalid on nan */ - if ((u >> 52) & 0x7ff) < 0x3ff + 4 { - if y == 0.0 { - return i!(P10, ((n as isize) + 15) as usize); - } - y = exp2(LN10 * y); - return y * i!(P10, ((n as isize) + 15) as usize); - } - return pow(10.0, x); -} diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs deleted file mode 100644 index 0520a41f2e9..00000000000 --- a/library/compiler-builtins/libm/src/math/exp10f.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{exp2, exp2f, modff}; - -const LN10_F32: f32 = 3.32192809488736234787031942948939; -const LN10_F64: f64 = 3.32192809488736234787031942948939; -const P10: &[f32] = - &[1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7]; - -/// Calculates 10 raised to the power of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp10f(x: f32) -> f32 { - let (mut y, n) = modff(x); - let u = n.to_bits(); - /* fabsf(n) < 8 without raising invalid on nan */ - if ((u >> 23) & 0xff) < 0x7f + 3 { - if y == 0.0 { - return i!(P10, ((n as isize) + 7) as usize); - } - y = exp2f(LN10_F32 * y); - return y * i!(P10, ((n as isize) + 7) as usize); - } - return exp2(LN10_F64 * (x as f64)) as f32; -} diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs deleted file mode 100644 index 6e98d066cbf..00000000000 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ /dev/null @@ -1,394 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */ -//- -// Copyright (c) 2005 David Schultz -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. - -use super::scalbn; - -const TBLSIZE: usize = 256; - -#[rustfmt::skip] -static TBL: [u64; TBLSIZE * 2] = [ - // exp2(z + eps) eps - 0x3fe6a09e667f3d5d, 0x3d39880000000000, - 0x3fe6b052fa751744, 0x3cd8000000000000, - 0x3fe6c012750bd9fe, 0xbd28780000000000, - 0x3fe6cfdcddd476bf, 0x3d1ec00000000000, - 0x3fe6dfb23c651a29, 0xbcd8000000000000, - 0x3fe6ef9298593ae3, 0xbcbc000000000000, - 0x3fe6ff7df9519386, 0xbd2fd80000000000, - 0x3fe70f7466f42da3, 0xbd2c880000000000, - 0x3fe71f75e8ec5fc3, 0x3d13c00000000000, - 0x3fe72f8286eacf05, 0xbd38300000000000, - 0x3fe73f9a48a58152, 0xbd00c00000000000, - 0x3fe74fbd35d7ccfc, 0x3d2f880000000000, - 0x3fe75feb564267f1, 0x3d03e00000000000, - 0x3fe77024b1ab6d48, 0xbd27d00000000000, - 0x3fe780694fde5d38, 0xbcdd000000000000, - 0x3fe790b938ac1d00, 0x3ce3000000000000, - 0x3fe7a11473eb0178, 0xbced000000000000, - 0x3fe7b17b0976d060, 0x3d20400000000000, - 0x3fe7c1ed0130c133, 0x3ca0000000000000, - 0x3fe7d26a62ff8636, 0xbd26900000000000, - 0x3fe7e2f336cf4e3b, 0xbd02e00000000000, - 0x3fe7f3878491c3e8, 0xbd24580000000000, - 0x3fe80427543e1b4e, 0x3d33000000000000, - 0x3fe814d2add1071a, 0x3d0f000000000000, - 0x3fe82589994ccd7e, 0xbd21c00000000000, - 0x3fe8364c1eb942d0, 0x3d29d00000000000, - 0x3fe8471a4623cab5, 0x3d47100000000000, - 0x3fe857f4179f5bbc, 0x3d22600000000000, - 0x3fe868d99b4491af, 0xbd32c40000000000, - 0x3fe879cad931a395, 0xbd23000000000000, - 0x3fe88ac7d98a65b8, 0xbd2a800000000000, - 0x3fe89bd0a4785800, 0xbced000000000000, - 0x3fe8ace5422aa223, 0x3d33280000000000, - 0x3fe8be05bad619fa, 0x3d42b40000000000, - 0x3fe8cf3216b54383, 0xbd2ed00000000000, - 0x3fe8e06a5e08664c, 0xbd20500000000000, - 0x3fe8f1ae99157807, 0x3d28280000000000, - 0x3fe902fed0282c0e, 0xbd1cb00000000000, - 0x3fe9145b0b91ff96, 0xbd05e00000000000, - 0x3fe925c353aa2ff9, 0x3cf5400000000000, - 0x3fe93737b0cdc64a, 0x3d17200000000000, - 0x3fe948b82b5f98ae, 0xbd09000000000000, - 0x3fe95a44cbc852cb, 0x3d25680000000000, - 0x3fe96bdd9a766f21, 0xbd36d00000000000, - 0x3fe97d829fde4e2a, 0xbd01000000000000, - 0x3fe98f33e47a23a3, 0x3d2d000000000000, - 0x3fe9a0f170ca0604, 0xbd38a40000000000, - 0x3fe9b2bb4d53ff89, 0x3d355c0000000000, - 0x3fe9c49182a3f15b, 0x3d26b80000000000, - 0x3fe9d674194bb8c5, 0xbcec000000000000, - 0x3fe9e86319e3238e, 0x3d17d00000000000, - 0x3fe9fa5e8d07f302, 0x3d16400000000000, - 0x3fea0c667b5de54d, 0xbcf5000000000000, - 0x3fea1e7aed8eb8f6, 0x3d09e00000000000, - 0x3fea309bec4a2e27, 0x3d2ad80000000000, - 0x3fea42c980460a5d, 0xbd1af00000000000, - 0x3fea5503b23e259b, 0x3d0b600000000000, - 0x3fea674a8af46213, 0x3d38880000000000, - 0x3fea799e1330b3a7, 0x3d11200000000000, - 0x3fea8bfe53c12e8d, 0x3d06c00000000000, - 0x3fea9e6b5579fcd2, 0xbd29b80000000000, - 0x3feab0e521356fb8, 0x3d2b700000000000, - 0x3feac36bbfd3f381, 0x3cd9000000000000, - 0x3fead5ff3a3c2780, 0x3ce4000000000000, - 0x3feae89f995ad2a3, 0xbd2c900000000000, - 0x3feafb4ce622f367, 0x3d16500000000000, - 0x3feb0e07298db790, 0x3d2fd40000000000, - 0x3feb20ce6c9a89a9, 0x3d12700000000000, - 0x3feb33a2b84f1a4b, 0x3d4d470000000000, - 0x3feb468415b747e7, 0xbd38380000000000, - 0x3feb59728de5593a, 0x3c98000000000000, - 0x3feb6c6e29f1c56a, 0x3d0ad00000000000, - 0x3feb7f76f2fb5e50, 0x3cde800000000000, - 0x3feb928cf22749b2, 0xbd04c00000000000, - 0x3feba5b030a10603, 0xbd0d700000000000, - 0x3febb8e0b79a6f66, 0x3d0d900000000000, - 0x3febcc1e904bc1ff, 0x3d02a00000000000, - 0x3febdf69c3f3a16f, 0xbd1f780000000000, - 0x3febf2c25bd71db8, 0xbd10a00000000000, - 0x3fec06286141b2e9, 0xbd11400000000000, - 0x3fec199bdd8552e0, 0x3d0be00000000000, - 0x3fec2d1cd9fa64ee, 0xbd09400000000000, - 0x3fec40ab5fffd02f, 0xbd0ed00000000000, - 0x3fec544778fafd15, 0x3d39660000000000, - 0x3fec67f12e57d0cb, 0xbd1a100000000000, - 0x3fec7ba88988c1b6, 0xbd58458000000000, - 0x3fec8f6d9406e733, 0xbd1a480000000000, - 0x3feca3405751c4df, 0x3ccb000000000000, - 0x3fecb720dcef9094, 0x3d01400000000000, - 0x3feccb0f2e6d1689, 0x3cf0200000000000, - 0x3fecdf0b555dc412, 0x3cf3600000000000, - 0x3fecf3155b5bab3b, 0xbd06900000000000, - 0x3fed072d4a0789bc, 0x3d09a00000000000, - 0x3fed1b532b08c8fa, 0xbd15e00000000000, - 0x3fed2f87080d8a85, 0x3d1d280000000000, - 0x3fed43c8eacaa203, 0x3d01a00000000000, - 0x3fed5818dcfba491, 0x3cdf000000000000, - 0x3fed6c76e862e6a1, 0xbd03a00000000000, - 0x3fed80e316c9834e, 0xbd0cd80000000000, - 0x3fed955d71ff6090, 0x3cf4c00000000000, - 0x3feda9e603db32ae, 0x3cff900000000000, - 0x3fedbe7cd63a8325, 0x3ce9800000000000, - 0x3fedd321f301b445, 0xbcf5200000000000, - 0x3fede7d5641c05bf, 0xbd1d700000000000, - 0x3fedfc97337b9aec, 0xbd16140000000000, - 0x3fee11676b197d5e, 0x3d0b480000000000, - 0x3fee264614f5a3e7, 0x3d40ce0000000000, - 0x3fee3b333b16ee5c, 0x3d0c680000000000, - 0x3fee502ee78b3fb4, 0xbd09300000000000, - 0x3fee653924676d68, 0xbce5000000000000, - 0x3fee7a51fbc74c44, 0xbd07f80000000000, - 0x3fee8f7977cdb726, 0xbcf3700000000000, - 0x3feea4afa2a490e8, 0x3ce5d00000000000, - 0x3feeb9f4867ccae4, 0x3d161a0000000000, - 0x3feecf482d8e680d, 0x3cf5500000000000, - 0x3feee4aaa2188514, 0x3cc6400000000000, - 0x3feefa1bee615a13, 0xbcee800000000000, - 0x3fef0f9c1cb64106, 0xbcfa880000000000, - 0x3fef252b376bb963, 0xbd2c900000000000, - 0x3fef3ac948dd7275, 0x3caa000000000000, - 0x3fef50765b6e4524, 0xbcf4f00000000000, - 0x3fef6632798844fd, 0x3cca800000000000, - 0x3fef7bfdad9cbe38, 0x3cfabc0000000000, - 0x3fef91d802243c82, 0xbcd4600000000000, - 0x3fefa7c1819e908e, 0xbd0b0c0000000000, - 0x3fefbdba3692d511, 0xbcc0e00000000000, - 0x3fefd3c22b8f7194, 0xbd10de8000000000, - 0x3fefe9d96b2a23ee, 0x3cee430000000000, - 0x3ff0000000000000, 0x0, - 0x3ff00b1afa5abcbe, 0xbcb3400000000000, - 0x3ff0163da9fb3303, 0xbd12170000000000, - 0x3ff02168143b0282, 0x3cba400000000000, - 0x3ff02c9a3e77806c, 0x3cef980000000000, - 0x3ff037d42e11bbca, 0xbcc7400000000000, - 0x3ff04315e86e7f89, 0x3cd8300000000000, - 0x3ff04e5f72f65467, 0xbd1a3f0000000000, - 0x3ff059b0d315855a, 0xbd02840000000000, - 0x3ff0650a0e3c1f95, 0x3cf1600000000000, - 0x3ff0706b29ddf71a, 0x3d15240000000000, - 0x3ff07bd42b72a82d, 0xbce9a00000000000, - 0x3ff0874518759bd0, 0x3ce6400000000000, - 0x3ff092bdf66607c8, 0xbd00780000000000, - 0x3ff09e3ecac6f383, 0xbc98000000000000, - 0x3ff0a9c79b1f3930, 0x3cffa00000000000, - 0x3ff0b5586cf988fc, 0xbcfac80000000000, - 0x3ff0c0f145e46c8a, 0x3cd9c00000000000, - 0x3ff0cc922b724816, 0x3d05200000000000, - 0x3ff0d83b23395dd8, 0xbcfad00000000000, - 0x3ff0e3ec32d3d1f3, 0x3d1bac0000000000, - 0x3ff0efa55fdfa9a6, 0xbd04e80000000000, - 0x3ff0fb66affed2f0, 0xbd0d300000000000, - 0x3ff1073028d7234b, 0x3cf1500000000000, - 0x3ff11301d0125b5b, 0x3cec000000000000, - 0x3ff11edbab5e2af9, 0x3d16bc0000000000, - 0x3ff12abdc06c31d5, 0x3ce8400000000000, - 0x3ff136a814f2047d, 0xbd0ed00000000000, - 0x3ff1429aaea92de9, 0x3ce8e00000000000, - 0x3ff14e95934f3138, 0x3ceb400000000000, - 0x3ff15a98c8a58e71, 0x3d05300000000000, - 0x3ff166a45471c3df, 0x3d03380000000000, - 0x3ff172b83c7d5211, 0x3d28d40000000000, - 0x3ff17ed48695bb9f, 0xbd05d00000000000, - 0x3ff18af9388c8d93, 0xbd1c880000000000, - 0x3ff1972658375d66, 0x3d11f00000000000, - 0x3ff1a35beb6fcba7, 0x3d10480000000000, - 0x3ff1af99f81387e3, 0xbd47390000000000, - 0x3ff1bbe084045d54, 0x3d24e40000000000, - 0x3ff1c82f95281c43, 0xbd0a200000000000, - 0x3ff1d4873168b9b2, 0x3ce3800000000000, - 0x3ff1e0e75eb44031, 0x3ceac00000000000, - 0x3ff1ed5022fcd938, 0x3d01900000000000, - 0x3ff1f9c18438cdf7, 0xbd1b780000000000, - 0x3ff2063b88628d8f, 0x3d2d940000000000, - 0x3ff212be3578a81e, 0x3cd8000000000000, - 0x3ff21f49917ddd41, 0x3d2b340000000000, - 0x3ff22bdda2791323, 0x3d19f80000000000, - 0x3ff2387a6e7561e7, 0xbd19c80000000000, - 0x3ff2451ffb821427, 0x3d02300000000000, - 0x3ff251ce4fb2a602, 0xbd13480000000000, - 0x3ff25e85711eceb0, 0x3d12700000000000, - 0x3ff26b4565e27d16, 0x3d11d00000000000, - 0x3ff2780e341de00f, 0x3d31ee0000000000, - 0x3ff284dfe1f5633e, 0xbd14c00000000000, - 0x3ff291ba7591bb30, 0xbd13d80000000000, - 0x3ff29e9df51fdf09, 0x3d08b00000000000, - 0x3ff2ab8a66d10e9b, 0xbd227c0000000000, - 0x3ff2b87fd0dada3a, 0x3d2a340000000000, - 0x3ff2c57e39771af9, 0xbd10800000000000, - 0x3ff2d285a6e402d9, 0xbd0ed00000000000, - 0x3ff2df961f641579, 0xbcf4200000000000, - 0x3ff2ecafa93e2ecf, 0xbd24980000000000, - 0x3ff2f9d24abd8822, 0xbd16300000000000, - 0x3ff306fe0a31b625, 0xbd32360000000000, - 0x3ff31432edeea50b, 0xbd70df8000000000, - 0x3ff32170fc4cd7b8, 0xbd22480000000000, - 0x3ff32eb83ba8e9a2, 0xbd25980000000000, - 0x3ff33c08b2641766, 0x3d1ed00000000000, - 0x3ff3496266e3fa27, 0xbcdc000000000000, - 0x3ff356c55f929f0f, 0xbd30d80000000000, - 0x3ff36431a2de88b9, 0x3d22c80000000000, - 0x3ff371a7373aaa39, 0x3d20600000000000, - 0x3ff37f26231e74fe, 0xbd16600000000000, - 0x3ff38cae6d05d838, 0xbd0ae00000000000, - 0x3ff39a401b713ec3, 0xbd44720000000000, - 0x3ff3a7db34e5a020, 0x3d08200000000000, - 0x3ff3b57fbfec6e95, 0x3d3e800000000000, - 0x3ff3c32dc313a8f2, 0x3cef800000000000, - 0x3ff3d0e544ede122, 0xbd17a00000000000, - 0x3ff3dea64c1234bb, 0x3d26300000000000, - 0x3ff3ec70df1c4ecc, 0xbd48a60000000000, - 0x3ff3fa4504ac7e8c, 0xbd3cdc0000000000, - 0x3ff40822c367a0bb, 0x3d25b80000000000, - 0x3ff4160a21f72e95, 0x3d1ec00000000000, - 0x3ff423fb27094646, 0xbd13600000000000, - 0x3ff431f5d950a920, 0x3d23980000000000, - 0x3ff43ffa3f84b9eb, 0x3cfa000000000000, - 0x3ff44e0860618919, 0xbcf6c00000000000, - 0x3ff45c2042a7d201, 0xbd0bc00000000000, - 0x3ff46a41ed1d0016, 0xbd12800000000000, - 0x3ff4786d668b3326, 0x3d30e00000000000, - 0x3ff486a2b5c13c00, 0xbd2d400000000000, - 0x3ff494e1e192af04, 0x3d0c200000000000, - 0x3ff4a32af0d7d372, 0xbd1e500000000000, - 0x3ff4b17dea6db801, 0x3d07800000000000, - 0x3ff4bfdad53629e1, 0xbd13800000000000, - 0x3ff4ce41b817c132, 0x3d00800000000000, - 0x3ff4dcb299fddddb, 0x3d2c700000000000, - 0x3ff4eb2d81d8ab96, 0xbd1ce00000000000, - 0x3ff4f9b2769d2d02, 0x3d19200000000000, - 0x3ff508417f4531c1, 0xbd08c00000000000, - 0x3ff516daa2cf662a, 0xbcfa000000000000, - 0x3ff5257de83f51ea, 0x3d4a080000000000, - 0x3ff5342b569d4eda, 0xbd26d80000000000, - 0x3ff542e2f4f6ac1a, 0xbd32440000000000, - 0x3ff551a4ca5d94db, 0x3d483c0000000000, - 0x3ff56070dde9116b, 0x3d24b00000000000, - 0x3ff56f4736b529de, 0x3d415a0000000000, - 0x3ff57e27dbe2c40e, 0xbd29e00000000000, - 0x3ff58d12d497c76f, 0xbd23080000000000, - 0x3ff59c0827ff0b4c, 0x3d4dec0000000000, - 0x3ff5ab07dd485427, 0xbcc4000000000000, - 0x3ff5ba11fba87af4, 0x3d30080000000000, - 0x3ff5c9268a59460b, 0xbd26c80000000000, - 0x3ff5d84590998e3f, 0x3d469a0000000000, - 0x3ff5e76f15ad20e1, 0xbd1b400000000000, - 0x3ff5f6a320dcebca, 0x3d17700000000000, - 0x3ff605e1b976dcb8, 0x3d26f80000000000, - 0x3ff6152ae6cdf715, 0x3d01000000000000, - 0x3ff6247eb03a5531, 0xbd15d00000000000, - 0x3ff633dd1d1929b5, 0xbd12d00000000000, - 0x3ff6434634ccc313, 0xbcea800000000000, - 0x3ff652b9febc8efa, 0xbd28600000000000, - 0x3ff6623882553397, 0x3d71fe0000000000, - 0x3ff671c1c708328e, 0xbd37200000000000, - 0x3ff68155d44ca97e, 0x3ce6800000000000, - 0x3ff690f4b19e9471, 0xbd29780000000000, -]; - -// exp2(x): compute the base 2 exponential of x -// -// Accuracy: Peak error < 0.503 ulp for normalized results. -// -// Method: (accurate tables) -// -// Reduce x: -// x = k + y, for integer k and |y| <= 1/2. -// Thus we have exp2(x) = 2**k * exp2(y). -// -// Reduce y: -// y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. -// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), -// with |z - eps[i]| <= 2**-9 + 2**-39 for the table used. -// -// We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via -// a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61. -// The values in exp2t[] and eps[] are chosen such that -// exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such -// that exp2t[i] is accurate to 2**-64. -// -// Note that the range of i is +-TBLSIZE/2, so we actually index the tables -// by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are -// virtual tables, interleaved in the real table tbl[]. -// -// This method is due to Gal, with many details due to Gal and Bachelis: -// -// Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library -// for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). - -/// Exponential, base 2 (f64) -/// -/// Calculate `2^x`, that is, 2 raised to the power `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp2(mut x: f64) -> f64 { - let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64; - let p1 = f64::from_bits(0x3fe62e42fefa39ef); - let p2 = f64::from_bits(0x3fcebfbdff82c575); - let p3 = f64::from_bits(0x3fac6b08d704a0a6); - let p4 = f64::from_bits(0x3f83b2ab88f70400); - let p5 = f64::from_bits(0x3f55d88003875c74); - - // double_t r, t, z; - // uint32_t ix, i0; - // union {double f; uint64_t i;} u = {x}; - // union {uint32_t u; int32_t i;} k; - let x1p1023 = f64::from_bits(0x7fe0000000000000); - let x1p52 = f64::from_bits(0x4330000000000000); - let _0x1p_149 = f64::from_bits(0xb6a0000000000000); - - /* Filter out exceptional cases. */ - let ui = f64::to_bits(x); - let ix = (ui >> 32) & 0x7fffffff; - if ix >= 0x408ff000 { - /* |x| >= 1022 or nan */ - if ix >= 0x40900000 && ui >> 63 == 0 { - /* x >= 1024 or nan */ - /* overflow */ - x *= x1p1023; - return x; - } - if ix >= 0x7ff00000 { - /* -inf or -nan */ - return -1.0 / x; - } - if ui >> 63 != 0 { - /* x <= -1022 */ - /* underflow */ - if x <= -1075.0 || x - x1p52 + x1p52 != x { - force_eval!((_0x1p_149 / x) as f32); - } - if x <= -1075.0 { - return 0.0; - } - } - } else if ix < 0x3c900000 { - /* |x| < 0x1p-54 */ - return 1.0 + x; - } - - /* Reduce x, computing z, i0, and k. */ - let ui = f64::to_bits(x + redux); - let mut i0 = ui as u32; - i0 = i0.wrapping_add(TBLSIZE as u32 / 2); - let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32; - let ki = div!(ku as i32, TBLSIZE as i32); - i0 %= TBLSIZE as u32; - let uf = f64::from_bits(ui) - redux; - let mut z = x - uf; - - /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ - let t = f64::from_bits(i!(TBL, 2 * i0 as usize)); /* exp2t[i0] */ - z -= f64::from_bits(i!(TBL, 2 * i0 as usize + 1)); /* eps[i0] */ - let r = t + t * z * (p1 + z * (p2 + z * (p3 + z * (p4 + z * p5)))); - - scalbn(r, ki) -} - -#[test] -fn i0_wrap_test() { - let x = -3.0 / 256.0; - assert_eq!(exp2(x), f64::from_bits(0x3fefbdba3692d514)); -} diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs deleted file mode 100644 index f452b6a20f8..00000000000 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ /dev/null @@ -1,135 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c -//- -// Copyright (c) 2005 David Schultz -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. - -const TBLSIZE: usize = 16; - -static EXP2FT: [u64; TBLSIZE] = [ - 0x3fe6a09e667f3bcd, - 0x3fe7a11473eb0187, - 0x3fe8ace5422aa0db, - 0x3fe9c49182a3f090, - 0x3feae89f995ad3ad, - 0x3fec199bdd85529c, - 0x3fed5818dcfba487, - 0x3feea4afa2a490da, - 0x3ff0000000000000, - 0x3ff0b5586cf9890f, - 0x3ff172b83c7d517b, - 0x3ff2387a6e756238, - 0x3ff306fe0a31b715, - 0x3ff3dea64c123422, - 0x3ff4bfdad5362a27, - 0x3ff5ab07dd485429, -]; - -// exp2f(x): compute the base 2 exponential of x -// -// Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. -// -// Method: (equally-spaced tables) -// -// Reduce x: -// x = k + y, for integer k and |y| <= 1/2. -// Thus we have exp2f(x) = 2**k * exp2(y). -// -// Reduce y: -// y = i/TBLSIZE + z for integer i near y * TBLSIZE. -// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), -// with |z| <= 2**-(TBLSIZE+1). -// -// We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a -// degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. -// Using double precision for everything except the reduction makes -// roundoff error insignificant and simplifies the scaling step. -// -// This method is due to Tang, but I do not use his suggested parameters: -// -// Tang, P. Table-driven Implementation of the Exponential Function -// in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). - -/// Exponential, base 2 (f32) -/// -/// Calculate `2^x`, that is, 2 raised to the power `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp2f(mut x: f32) -> f32 { - let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; - let p1 = f32::from_bits(0x3f317218); - let p2 = f32::from_bits(0x3e75fdf0); - let p3 = f32::from_bits(0x3d6359a4); - let p4 = f32::from_bits(0x3c1d964e); - - // double_t t, r, z; - // uint32_t ix, i0, k; - - let x1p127 = f32::from_bits(0x7f000000); - - /* Filter out exceptional cases. */ - let ui = f32::to_bits(x); - let ix = ui & 0x7fffffff; - if ix > 0x42fc0000 { - /* |x| > 126 */ - if ix > 0x7f800000 { - /* NaN */ - return x; - } - if (0x43000000..0x80000000).contains(&ui) { - /* x >= 128 */ - x *= x1p127; - return x; - } - if ui >= 0x80000000 { - /* x < -126 */ - if ui >= 0xc3160000 || (ui & 0x0000ffff != 0) { - force_eval!(f32::from_bits(0x80000001) / x); - } - if ui >= 0xc3160000 { - /* x <= -150 */ - return 0.0; - } - } - } else if ix <= 0x33000000 { - /* |x| <= 0x1p-25 */ - return 1.0 + x; - } - - /* Reduce x, computing z, i0, and k. */ - let ui = f32::to_bits(x + redux); - let mut i0 = ui; - i0 += TBLSIZE as u32 / 2; - let k = i0 / TBLSIZE as u32; - let ukf = f64::from_bits(((0x3ff + k) as u64) << 52); - i0 &= TBLSIZE as u32 - 1; - let mut uf = f32::from_bits(ui); - uf -= redux; - let z: f64 = (x - uf) as f64; - /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ - let r: f64 = f64::from_bits(i!(EXP2FT, i0 as usize)); - let t: f64 = r * z; - let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64); - - /* Scale by 2**k */ - (r * ukf) as f32 -} diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs deleted file mode 100644 index 8dc067ab084..00000000000 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ /dev/null @@ -1,97 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::scalbnf; - -const HALF: [f32; 2] = [0.5, -0.5]; -const LN2_HI: f32 = 6.9314575195e-01; /* 0x3f317200 */ -const LN2_LO: f32 = 1.4286067653e-06; /* 0x35bfbe8e */ -const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ -/* - * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: - * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 - */ -const P1: f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ -const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ - -/// Exponential, base *e* (f32) -/// -/// Calculate the exponential of `x`, that is, *e* raised to the power `x` -/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn expf(mut x: f32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ - let mut hx = x.to_bits(); - let sign = (hx >> 31) as i32; /* sign bit of x */ - let signb: bool = sign != 0; - hx &= 0x7fffffff; /* high word of |x| */ - - /* special cases */ - if hx >= 0x42aeac50 { - /* if |x| >= -87.33655f or NaN */ - if hx > 0x7f800000 { - /* NaN */ - return x; - } - if (hx >= 0x42b17218) && (!signb) { - /* x >= 88.722839f */ - /* overflow */ - x *= x1p127; - return x; - } - if signb { - /* underflow */ - force_eval!(-x1p_126 / x); - if hx >= 0x42cff1b5 { - /* x <= -103.972084f */ - return 0.; - } - } - } - - /* argument reduction */ - let k: i32; - let hi: f32; - let lo: f32; - if hx > 0x3eb17218 { - /* if |x| > 0.5 ln2 */ - if hx > 0x3f851592 { - /* if |x| > 1.5 ln2 */ - k = (INV_LN2 * x + i!(HALF, sign as usize)) as i32; - } else { - k = 1 - sign - sign; - } - let kf = k as f32; - hi = x - kf * LN2_HI; /* k*ln2hi is exact here */ - lo = kf * LN2_LO; - x = hi - lo; - } else if hx > 0x39000000 { - /* |x| > 2**-14 */ - k = 0; - hi = x; - lo = 0.; - } else { - /* raise inexact */ - force_eval!(x1p127 + x); - return 1. + x; - } - - /* x is now in primary range */ - let xx = x * x; - let c = x - xx * (P1 + xx * P2); - let y = 1. + (x * c / (2. - c) - lo + hi); - if k == 0 { y } else { scalbnf(y, k) } -} diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs deleted file mode 100644 index f25153f32a3..00000000000 --- a/library/compiler-builtins/libm/src/math/expm1.rs +++ /dev/null @@ -1,144 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::f64; - -const O_THRESHOLD: f64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ -const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ -const LN2_LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ -const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ -/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ -const Q1: f64 = -3.33333333333331316428e-02; /* BFA11111 111110F4 */ -const Q2: f64 = 1.58730158725481460165e-03; /* 3F5A01A0 19FE5585 */ -const Q3: f64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ -const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ -const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ - -/// Exponential, base *e*, of x-1 (f64) -/// -/// Calculates the exponential of `x` and subtract 1, that is, *e* raised -/// to the power `x` minus 1 (where *e* is the base of the natural -/// system of logarithms, approximately 2.71828). -/// The result is accurate even for small values of `x`, -/// where using `exp(x)-1` would lose many significant digits. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn expm1(mut x: f64) -> f64 { - let hi: f64; - let lo: f64; - let k: i32; - let c: f64; - let mut t: f64; - let mut y: f64; - - let mut ui = x.to_bits(); - let hx = ((ui >> 32) & 0x7fffffff) as u32; - let sign = (ui >> 63) as i32; - - /* filter out huge and non-finite argument */ - if hx >= 0x4043687A { - /* if |x|>=56*ln2 */ - if x.is_nan() { - return x; - } - if sign != 0 { - return -1.0; - } - if x > O_THRESHOLD { - x *= f64::from_bits(0x7fe0000000000000); - return x; - } - } - - /* argument reduction */ - if hx > 0x3fd62e42 { - /* if |x| > 0.5 ln2 */ - if hx < 0x3FF0A2B2 { - /* and |x| < 1.5 ln2 */ - if sign == 0 { - hi = x - LN2_HI; - lo = LN2_LO; - k = 1; - } else { - hi = x + LN2_HI; - lo = -LN2_LO; - k = -1; - } - } else { - k = (INVLN2 * x + if sign != 0 { -0.5 } else { 0.5 }) as i32; - t = k as f64; - hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ - lo = t * LN2_LO; - } - x = hi - lo; - c = (hi - x) - lo; - } else if hx < 0x3c900000 { - /* |x| < 2**-54, return x */ - if hx < 0x00100000 { - force_eval!(x); - } - return x; - } else { - c = 0.0; - k = 0; - } - - /* x is now in primary range */ - let hfx = 0.5 * x; - let hxs = x * hfx; - let r1 = 1.0 + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5)))); - t = 3.0 - r1 * hfx; - let mut e = hxs * ((r1 - t) / (6.0 - x * t)); - if k == 0 { - /* c is 0 */ - return x - (x * e - hxs); - } - e = x * (e - c) - c; - e -= hxs; - /* exp(x) ~ 2^k (x_reduced - e + 1) */ - if k == -1 { - return 0.5 * (x - e) - 0.5; - } - if k == 1 { - if x < -0.25 { - return -2.0 * (e - (x + 0.5)); - } - return 1.0 + 2.0 * (x - e); - } - ui = ((0x3ff + k) as u64) << 52; /* 2^k */ - let twopk = f64::from_bits(ui); - if !(0..=56).contains(&k) { - /* suffice to return exp(x)-1 */ - y = x - e + 1.0; - if k == 1024 { - y = y * 2.0 * f64::from_bits(0x7fe0000000000000); - } else { - y = y * twopk; - } - return y - 1.0; - } - ui = ((0x3ff - k) as u64) << 52; /* 2^-k */ - let uf = f64::from_bits(ui); - if k < 20 { - y = (x - e + (1.0 - uf)) * twopk; - } else { - y = (x - (e + uf) + 1.0) * twopk; - } - y -} - -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::expm1(1.1), 2.0041660239464334); - } -} diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs deleted file mode 100644 index 12c6f532b96..00000000000 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ /dev/null @@ -1,130 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -const O_THRESHOLD: f32 = 8.8721679688e+01; /* 0x42b17180 */ -const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ -const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ -/* - * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: - * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 - * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): - */ -const Q1: f32 = -3.3333212137e-2; /* -0x888868.0p-28 */ -const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ - -/// Exponential, base *e*, of x-1 (f32) -/// -/// Calculates the exponential of `x` and subtract 1, that is, *e* raised -/// to the power `x` minus 1 (where *e* is the base of the natural -/// system of logarithms, approximately 2.71828). -/// The result is accurate even for small values of `x`, -/// where using `exp(x)-1` would lose many significant digits. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn expm1f(mut x: f32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - - let mut hx = x.to_bits(); - let sign = (hx >> 31) != 0; - hx &= 0x7fffffff; - - /* filter out huge and non-finite argument */ - if hx >= 0x4195b844 { - /* if |x|>=27*ln2 */ - if hx > 0x7f800000 { - /* NaN */ - return x; - } - if sign { - return -1.; - } - if x > O_THRESHOLD { - x *= x1p127; - return x; - } - } - - let k: i32; - let hi: f32; - let lo: f32; - let mut c = 0f32; - /* argument reduction */ - if hx > 0x3eb17218 { - /* if |x| > 0.5 ln2 */ - if hx < 0x3F851592 { - /* and |x| < 1.5 ln2 */ - if !sign { - hi = x - LN2_HI; - lo = LN2_LO; - k = 1; - } else { - hi = x + LN2_HI; - lo = -LN2_LO; - k = -1; - } - } else { - k = (INV_LN2 * x + (if sign { -0.5 } else { 0.5 })) as i32; - let t = k as f32; - hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ - lo = t * LN2_LO; - } - x = hi - lo; - c = (hi - x) - lo; - } else if hx < 0x33000000 { - /* when |x|<2**-25, return x */ - if hx < 0x00800000 { - force_eval!(x * x); - } - return x; - } else { - k = 0; - } - - /* x is now in primary range */ - let hfx = 0.5 * x; - let hxs = x * hfx; - let r1 = 1. + hxs * (Q1 + hxs * Q2); - let t = 3. - r1 * hfx; - let mut e = hxs * ((r1 - t) / (6. - x * t)); - if k == 0 { - /* c is 0 */ - return x - (x * e - hxs); - } - e = x * (e - c) - c; - e -= hxs; - /* exp(x) ~ 2^k (x_reduced - e + 1) */ - if k == -1 { - return 0.5 * (x - e) - 0.5; - } - if k == 1 { - if x < -0.25 { - return -2. * (e - (x + 0.5)); - } - return 1. + 2. * (x - e); - } - let twopk = f32::from_bits(((0x7f + k) << 23) as u32); /* 2^k */ - if !(0..=56).contains(&k) { - /* suffice to return exp(x)-1 */ - let mut y = x - e + 1.; - if k == 128 { - y = y * 2. * x1p127; - } else { - y = y * twopk; - } - return y - 1.; - } - let uf = f32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */ - if k < 23 { (x - e + (1. - uf)) * twopk } else { (x - (e + uf) + 1.) * twopk } -} diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs deleted file mode 100644 index 82e9b360a76..00000000000 --- a/library/compiler-builtins/libm/src/math/expo2.rs +++ /dev/null @@ -1,14 +0,0 @@ -use super::{combine_words, exp}; - -/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn expo2(x: f64) -> f64 { - /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ - const K: i32 = 2043; - let kln2 = f64::from_bits(0x40962066151add8b); - - /* note that k is odd and scale*scale overflows */ - let scale = combine_words(((0x3ff + K / 2) as u32) << 20, 0); - /* exp(x - k ln2) * 2**(k-1) */ - exp(x - kln2) * scale * scale -} diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs deleted file mode 100644 index 0050a309fee..00000000000 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ /dev/null @@ -1,116 +0,0 @@ -/// Absolute value (magnitude) (f16) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf16(x: f16) -> f16 { - super::generic::fabs(x) -} - -/// Absolute value (magnitude) (f32) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf(x: f32) -> f32 { - select_implementation! { - name: fabsf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::fabs(x) -} - -/// Absolute value (magnitude) (f64) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabs(x: f64) -> f64 { - select_implementation! { - name: fabs, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::fabs(x) -} - -/// Absolute value (magnitude) (f128) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf128(x: f128) -> f128 { - super::generic::fabs(x) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Float; - - /// Based on https://en.cppreference.com/w/cpp/numeric/math/fabs - fn spec_test(f: impl Fn(F) -> F) { - assert_biteq!(f(F::ZERO), F::ZERO); - assert_biteq!(f(F::NEG_ZERO), F::ZERO); - assert_biteq!(f(F::INFINITY), F::INFINITY); - assert_biteq!(f(F::NEG_INFINITY), F::INFINITY); - assert!(f(F::NAN).is_nan()); - - // Not spec rewquired but we expect it - assert!(f(F::NAN).is_sign_positive()); - assert!(f(F::from_bits(F::NAN.to_bits() | F::SIGN_MASK)).is_sign_positive()); - } - - #[test] - #[cfg(f16_enabled)] - fn sanity_check_f16() { - assert_eq!(fabsf16(-1.0f16), 1.0); - assert_eq!(fabsf16(2.8f16), 2.8); - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(fabsf16); - } - - #[test] - fn sanity_check_f32() { - assert_eq!(fabsf(-1.0f32), 1.0); - assert_eq!(fabsf(2.8f32), 2.8); - } - - #[test] - fn spec_tests_f32() { - spec_test::(fabsf); - } - - #[test] - fn sanity_check_f64() { - assert_eq!(fabs(-1.0f64), 1.0); - assert_eq!(fabs(2.8f64), 2.8); - } - - #[test] - fn spec_tests_f64() { - spec_test::(fabs); - } - - #[test] - #[cfg(f128_enabled)] - fn sanity_check_f128() { - assert_eq!(fabsf128(-1.0f128), 1.0); - assert_eq!(fabsf128(2.8f128), 2.8); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(fabsf128); - } -} diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs deleted file mode 100644 index 082c5478b2a..00000000000 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ /dev/null @@ -1,53 +0,0 @@ -/// Positive difference (f16) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf16(x: f16, y: f16) -> f16 { - super::generic::fdim(x, y) -} - -/// Positive difference (f32) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf(x: f32, y: f32) -> f32 { - super::generic::fdim(x, y) -} - -/// Positive difference (f64) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdim(x: f64, y: f64) -> f64 { - super::generic::fdim(x, y) -} - -/// Positive difference (f128) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf128(x: f128, y: f128) -> f128 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs deleted file mode 100644 index 3c5eab101d1..00000000000 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ /dev/null @@ -1,46 +0,0 @@ -/// Floor (f16) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf16(x: f16) -> f16 { - return super::generic::floor(x); -} - -/// Floor (f64) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floor(x: f64) -> f64 { - select_implementation! { - name: floor, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), - args: x, - } - - return super::generic::floor(x); -} - -/// Floor (f32) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf(x: f32) -> f32 { - select_implementation! { - name: floorf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - return super::generic::floor(x); -} - -/// Floor (f128) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf128(x: f128) -> f128 { - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs deleted file mode 100644 index e0b3347acf8..00000000000 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ /dev/null @@ -1,397 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ - -use super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; -use super::{CastFrom, CastInto, Float, Int, MinInt}; - -/// Fused multiply add (f64) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fma(x: f64, y: f64, z: f64) -> f64 { - select_implementation! { - name: fma, - use_arch: all(target_arch = "aarch64", target_feature = "neon"), - args: x, y, z, - } - - fma_round(x, y, z, Round::Nearest).val -} - -/// Fused multiply add (f128) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { - fma_round(x, y, z, Round::Nearest).val -} - -/// Fused multiply-add that works when there is not a larger float size available. Computes -/// `(x * y) + z`. -#[inline] -pub fn fma_round(x: F, y: F, z: F, _round: Round) -> FpResult -where - F: Float, - F: CastFrom, - F: CastFrom, - F::Int: HInt, - u32: CastInto, -{ - let one = IntTy::::ONE; - let zero = IntTy::::ZERO; - - // Normalize such that the top of the mantissa is zero and we have a guard bit. - let nx = Norm::from_float(x); - let ny = Norm::from_float(y); - let nz = Norm::from_float(z); - - if nx.is_zero_nan_inf() || ny.is_zero_nan_inf() { - // Value will overflow, defer to non-fused operations. - return FpResult::ok(x * y + z); - } - - if nz.is_zero_nan_inf() { - if nz.is_zero() { - // Empty add component means we only need to multiply. - return FpResult::ok(x * y); - } - // `z` is NaN or infinity, which sets the result. - return FpResult::ok(z); - } - - // multiply: r = x * y - let zhi: F::Int; - let zlo: F::Int; - let (mut rlo, mut rhi) = nx.m.widen_mul(ny.m).lo_hi(); - - // Exponent result of multiplication - let mut e: i32 = nx.e + ny.e; - // Needed shift to align `z` to the multiplication result - let mut d: i32 = nz.e - e; - let sbits = F::BITS as i32; - - // Scale `z`. Shift `z <<= kz`, `r >>= kr`, so `kz+kr == d`, set `e = e+kr` (== ez-kz) - if d > 0 { - // The magnitude of `z` is larger than `x * y` - if d < sbits { - // Maximum shift of one `F::BITS` means shifted `z` will fit into `2 * F::BITS`. Shift - // it into `(zhi, zlo)`. No exponent adjustment necessary. - zlo = nz.m << d; - zhi = nz.m >> (sbits - d); - } else { - // Shift larger than `sbits`, `z` only needs the top half `zhi`. Place it there (acts - // as a shift by `sbits`). - zlo = zero; - zhi = nz.m; - d -= sbits; - - // `z`'s exponent is large enough that it now needs to be taken into account. - e = nz.e - sbits; - - if d == 0 { - // Exactly `sbits`, nothing to do - } else if d < sbits { - // Remaining shift fits within `sbits`. Leave `z` in place, shift `x * y` - rlo = (rhi << (sbits - d)) | (rlo >> d); - // Set the sticky bit - rlo |= IntTy::::from((rlo << (sbits - d)) != zero); - rhi = rhi >> d; - } else { - // `z`'s magnitude is enough that `x * y` is irrelevant. It was nonzero, so set - // the sticky bit. - rlo = one; - rhi = zero; - } - } - } else { - // `z`'s magnitude once shifted fits entirely within `zlo` - zhi = zero; - d = -d; - if d == 0 { - // No shift needed - zlo = nz.m; - } else if d < sbits { - // Shift s.t. `nz.m` fits into `zlo` - let sticky = IntTy::::from((nz.m << (sbits - d)) != zero); - zlo = (nz.m >> d) | sticky; - } else { - // Would be entirely shifted out, only set the sticky bit - zlo = one; - } - } - - /* addition */ - - let mut neg = nx.neg ^ ny.neg; - let samesign: bool = !neg ^ nz.neg; - let mut rhi_nonzero = true; - - if samesign { - // r += z - rlo = rlo.wrapping_add(zlo); - rhi += zhi + IntTy::::from(rlo < zlo); - } else { - // r -= z - let (res, borrow) = rlo.overflowing_sub(zlo); - rlo = res; - rhi = rhi.wrapping_sub(zhi.wrapping_add(IntTy::::from(borrow))); - if (rhi >> (F::BITS - 1)) != zero { - rlo = rlo.signed().wrapping_neg().unsigned(); - rhi = rhi.signed().wrapping_neg().unsigned() - IntTy::::from(rlo != zero); - neg = !neg; - } - rhi_nonzero = rhi != zero; - } - - /* Construct result */ - - // Shift result into `rhi`, left-aligned. Last bit is sticky - if rhi_nonzero { - // `d` > 0, need to shift both `rhi` and `rlo` into result - e += sbits; - d = rhi.leading_zeros() as i32 - 1; - rhi = (rhi << d) | (rlo >> (sbits - d)); - // Update sticky - rhi |= IntTy::::from((rlo << d) != zero); - } else if rlo != zero { - // `rhi` is zero, `rlo` is the entire result and needs to be shifted - d = rlo.leading_zeros() as i32 - 1; - if d < 0 { - // Shift and set sticky - rhi = (rlo >> 1) | (rlo & one); - } else { - rhi = rlo << d; - } - } else { - // exact +/- 0.0 - return FpResult::ok(x * y + z); - } - - e -= d; - - // Use int->float conversion to populate the significand. - // i is in [1 << (BITS - 2), (1 << (BITS - 1)) - 1] - let mut i: F::SignedInt = rhi.signed(); - - if neg { - i = -i; - } - - // `|r|` is in `[0x1p62,0x1p63]` for `f64` - let mut r: F = F::cast_from_lossy(i); - - /* Account for subnormal and rounding */ - - // Unbiased exponent for the maximum value of `r` - let max_pow = F::BITS - 1 + F::EXP_BIAS; - - let mut status = Status::OK; - - if e < -(max_pow as i32 - 2) { - // Result is subnormal before rounding - if e == -(max_pow as i32 - 1) { - let mut c = F::from_parts(false, max_pow, zero); - if neg { - c = -c; - } - - if r == c { - // Min normal after rounding, - status.set_underflow(true); - r = F::MIN_POSITIVE_NORMAL.copysign(r); - return FpResult::new(r, status); - } - - if (rhi << (F::SIG_BITS + 1)) != zero { - // Account for truncated bits. One bit will be lost in the `scalbn` call, add - // another top bit to avoid double rounding if inexact. - let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << (F::BITS - 2)); - i = iu.signed(); - - if neg { - i = -i; - } - - r = F::cast_from_lossy(i); - - // Remove the top bit - r = F::cast_from(2i8) * r - c; - status.set_underflow(true); - } - } else { - // Only round once when scaled - d = F::EXP_BITS as i32 - 1; - let sticky = IntTy::::from(rhi << (F::BITS as i32 - d) != zero); - i = (((rhi >> d) | sticky) << d).signed(); - - if neg { - i = -i; - } - - r = F::cast_from_lossy(i); - } - } - - // Use our exponent to scale the final value. - FpResult::new(super::generic::scalbn(r, e), status) -} - -/// Representation of `F` that has handled subnormals. -#[derive(Clone, Copy, Debug)] -struct Norm { - /// Normalized significand with one guard bit, unsigned. - m: F::Int, - /// Exponent of the mantissa such that `m * 2^e = x`. Accounts for the shift in the mantissa - /// and the guard bit; that is, 1.0 will normalize as `m = 1 << 53` and `e = -53`. - e: i32, - neg: bool, -} - -impl Norm { - /// Unbias the exponent and account for the mantissa's precision, including the guard bit. - const EXP_UNBIAS: u32 = F::EXP_BIAS + F::SIG_BITS + 1; - - /// Values greater than this had a saturated exponent (infinity or NaN), OR were zero and we - /// adjusted the exponent such that it exceeds this threashold. - const ZERO_INF_NAN: u32 = F::EXP_SAT - Self::EXP_UNBIAS; - - fn from_float(x: F) -> Self { - let mut ix = x.to_bits(); - let mut e = x.ex() as i32; - let neg = x.is_sign_negative(); - if e == 0 { - // Normalize subnormals by multiplication - let scale_i = F::BITS - 1; - let scale_f = F::from_parts(false, scale_i + F::EXP_BIAS, F::Int::ZERO); - let scaled = x * scale_f; - ix = scaled.to_bits(); - e = scaled.ex() as i32; - e = if e == 0 { - // If the exponent is still zero, the input was zero. Artifically set this value - // such that the final `e` will exceed `ZERO_INF_NAN`. - 1 << F::EXP_BITS - } else { - // Otherwise, account for the scaling we just did. - e - scale_i as i32 - }; - } - - e -= Self::EXP_UNBIAS as i32; - - // Absolute value, set the implicit bit, and shift to create a guard bit - ix &= F::SIG_MASK; - ix |= F::IMPLICIT_BIT; - ix <<= 1; - - Self { m: ix, e, neg } - } - - /// True if the value was zero, infinity, or NaN. - fn is_zero_nan_inf(self) -> bool { - self.e >= Self::ZERO_INF_NAN as i32 - } - - /// The only value we have - fn is_zero(self) -> bool { - // The only exponent that strictly exceeds this value is our sentinel value for zero. - self.e > Self::ZERO_INF_NAN as i32 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - /// Test the generic `fma_round` algorithm for a given float. - fn spec_test() - where - F: Float, - F: CastFrom, - F: CastFrom, - F::Int: HInt, - u32: CastInto, - { - let x = F::from_bits(F::Int::ONE); - let y = F::from_bits(F::Int::ONE); - let z = F::ZERO; - - let fma = |x, y, z| fma_round(x, y, z, Round::Nearest).val; - - // 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of - // fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the - // exact result" - assert_biteq!(fma(x, y, z), F::ZERO); - assert_biteq!(fma(x, -y, z), F::NEG_ZERO); - assert_biteq!(fma(-x, y, z), F::NEG_ZERO); - assert_biteq!(fma(-x, -y, z), F::ZERO); - } - - #[test] - fn spec_test_f32() { - spec_test::(); - } - - #[test] - fn spec_test_f64() { - spec_test::(); - - let expect_underflow = [ - ( - hf64!("0x1.0p-1070"), - hf64!("0x1.0p-1070"), - hf64!("0x1.ffffffffffffp-1023"), - hf64!("0x0.ffffffffffff8p-1022"), - ), - ( - // FIXME: we raise underflow but this should only be inexact (based on C and - // `rustc_apfloat`). - hf64!("0x1.0p-1070"), - hf64!("0x1.0p-1070"), - hf64!("-0x1.0p-1022"), - hf64!("-0x1.0p-1022"), - ), - ]; - - for (x, y, z, res) in expect_underflow { - let FpResult { val, status } = fma_round(x, y, z, Round::Nearest); - assert_biteq!(val, res); - assert_eq!(status, Status::UNDERFLOW); - } - } - - #[test] - #[cfg(f128_enabled)] - fn spec_test_f128() { - spec_test::(); - } - - #[test] - fn fma_segfault() { - // These two inputs cause fma to segfault on release due to overflow: - assert_eq!( - fma( - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313 - ), - -0.00000000000000022204460492503126, - ); - - let result = fma(-0.992, -0.992, -0.992); - //force rounding to storage format on x87 to prevent superious errors. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let result = force_eval!(result); - assert_eq!(result, -0.007936000000000007,); - } - - #[test] - fn fma_sbb() { - assert_eq!(fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), -3991680619069439e277); - } - - #[test] - fn fma_underflow() { - assert_eq!(fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), 0.0,); - } -} diff --git a/library/compiler-builtins/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/src/math/fma_wide.rs deleted file mode 100644 index 08b78b02264..00000000000 --- a/library/compiler-builtins/libm/src/math/fma_wide.rs +++ /dev/null @@ -1,104 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/fmaf.c. Ported to generic Rust algorithm in 2025, TG. */ - -use super::support::{FpResult, IntTy, Round, Status}; -use super::{CastFrom, CastInto, DFloat, Float, HFloat, MinInt}; - -// Placeholder so we can have `fmaf16` in the `Float` trait. -#[allow(unused)] -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 { - unimplemented!() -} - -/// Floating multiply add (f32) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { - select_implementation! { - name: fmaf, - use_arch: all(target_arch = "aarch64", target_feature = "neon"), - args: x, y, z, - } - - fma_wide_round(x, y, z, Round::Nearest).val -} - -/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, -/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. -#[inline] -pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult -where - F: Float + HFloat, - B: Float + DFloat, - B::Int: CastInto, - i32: CastFrom, -{ - let one = IntTy::::ONE; - - let xy: B = x.widen() * y.widen(); - let mut result: B = xy + z.widen(); - let mut ui: B::Int = result.to_bits(); - let re = result.ex(); - let zb: B = z.widen(); - - let prec_diff = B::SIG_BITS - F::SIG_BITS; - let excess_prec = ui & ((one << prec_diff) - one); - let halfway = one << (prec_diff - 1); - - // Common case: the larger precision is fine if... - // This is not a halfway case - if excess_prec != halfway - // Or the result is NaN - || re == B::EXP_SAT - // Or the result is exact - || (result - xy == zb && result - zb == xy) - // Or the mode is something other than round to nearest - || round != Round::Nearest - { - let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; - let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; - - let mut status = Status::OK; - - if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() { - // This branch is never hit; requires previous operations to set a status - status.set_inexact(false); - - result = xy + z.widen(); - if status.inexact() { - status.set_underflow(true); - } else { - status.set_inexact(true); - } - } - - return FpResult { val: result.narrow(), status }; - } - - let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; - let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy }; - if neg == (err < B::ZERO) { - ui += one; - } else { - ui -= one; - } - - FpResult::ok(B::from_bits(ui).narrow()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn issue_263() { - let a = f32::from_bits(1266679807); - let b = f32::from_bits(1300234242); - let c = f32::from_bits(1115553792); - let expected = f32::from_bits(1501560833); - assert_eq!(fmaf(a, b, c), expected); - } -} diff --git a/library/compiler-builtins/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/src/math/fmin_fmax.rs deleted file mode 100644 index 2947b783e2f..00000000000 --- a/library/compiler-builtins/libm/src/math/fmin_fmax.rs +++ /dev/null @@ -1,167 +0,0 @@ -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminf16(x: f16, y: f16) -> f16 { - super::generic::fmin(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminf(x: f32, y: f32) -> f32 { - super::generic::fmin(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmin(x: f64, y: f64) -> f64 { - super::generic::fmin(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminf128(x: f128, y: f128) -> f128 { - super::generic::fmin(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaxf16(x: f16, y: f16) -> f16 { - super::generic::fmax(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaxf(x: f32, y: f32) -> f32 { - super::generic::fmax(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmax(x: f64, y: f64) -> f64 { - super::generic::fmax(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaxf128(x: f128, y: f128) -> f128 { - super::generic::fmax(x, y) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::{Float, Hexf}; - - fn fmin_spec_test(f: impl Fn(F, F) -> F) { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), - (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - ]; - - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn fmin_spec_tests_f16() { - fmin_spec_test::(fminf16); - } - - #[test] - fn fmin_spec_tests_f32() { - fmin_spec_test::(fminf); - } - - #[test] - fn fmin_spec_tests_f64() { - fmin_spec_test::(fmin); - } - - #[test] - #[cfg(f128_enabled)] - fn fmin_spec_tests_f128() { - fmin_spec_test::(fminf128); - } - - fn fmax_spec_test(f: impl Fn(F, F) -> F) { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), - (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - ]; - - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn fmax_spec_tests_f16() { - fmax_spec_test::(fmaxf16); - } - - #[test] - fn fmax_spec_tests_f32() { - fmax_spec_test::(fmaxf); - } - - #[test] - fn fmax_spec_tests_f64() { - fmax_spec_test::(fmax); - } - - #[test] - #[cfg(f128_enabled)] - fn fmax_spec_tests_f128() { - fmax_spec_test::(fmaxf128); - } -} diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs deleted file mode 100644 index b7999e27392..00000000000 --- a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs +++ /dev/null @@ -1,163 +0,0 @@ -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimumf16(x: f16, y: f16) -> f16 { - super::generic::fminimum(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimum(x: f64, y: f64) -> f64 { - super::generic::fminimum(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimumf(x: f32, y: f32) -> f32 { - super::generic::fminimum(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimumf128(x: f128, y: f128) -> f128 { - super::generic::fminimum(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximumf16(x: f16, y: f16) -> f16 { - super::generic::fmaximum(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximumf(x: f32, y: f32) -> f32 { - super::generic::fmaximum(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximum(x: f64, y: f64) -> f64 { - super::generic::fmaximum(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximumf128(x: f128, y: f128) -> f128 { - super::generic::fmaximum(x, y) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::{Float, Hexf}; - - fn fminimum_spec_test(f: impl Fn(F, F) -> F) { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), - (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::NAN), - (F::ZERO, F::NAN, F::NAN), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), - (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), - ]; - - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn fminimum_spec_tests_f16() { - fminimum_spec_test::(fminimumf16); - } - - #[test] - fn fminimum_spec_tests_f32() { - fminimum_spec_test::(fminimumf); - } - - #[test] - fn fminimum_spec_tests_f64() { - fminimum_spec_test::(fminimum); - } - - #[test] - #[cfg(f128_enabled)] - fn fminimum_spec_tests_f128() { - fminimum_spec_test::(fminimumf128); - } - - fn fmaximum_spec_test(f: impl Fn(F, F) -> F) { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), - (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::NAN), - (F::ZERO, F::NAN, F::NAN), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::ZERO), - (F::NEG_ZERO, F::ZERO, F::ZERO), - ]; - - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn fmaximum_spec_tests_f16() { - fmaximum_spec_test::(fmaximumf16); - } - - #[test] - fn fmaximum_spec_tests_f32() { - fmaximum_spec_test::(fmaximumf); - } - - #[test] - fn fmaximum_spec_tests_f64() { - fmaximum_spec_test::(fmaximum); - } - - #[test] - #[cfg(f128_enabled)] - fn fmaximum_spec_tests_f128() { - fmaximum_spec_test::(fmaximumf128); - } -} diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs deleted file mode 100644 index 180d21f72b7..00000000000 --- a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs +++ /dev/null @@ -1,163 +0,0 @@ -/// Return the lesser of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimum_numf16(x: f16, y: f16) -> f16 { - super::generic::fminimum_num(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimum_numf(x: f32, y: f32) -> f32 { - super::generic::fminimum_num(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimum_num(x: f64, y: f64) -> f64 { - super::generic::fminimum_num(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimum_numf128(x: f128, y: f128) -> f128 { - super::generic::fminimum_num(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximum_numf16(x: f16, y: f16) -> f16 { - super::generic::fmaximum_num(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximum_numf(x: f32, y: f32) -> f32 { - super::generic::fmaximum_num(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximum_num(x: f64, y: f64) -> f64 { - super::generic::fmaximum_num(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximum_numf128(x: f128, y: f128) -> f128 { - super::generic::fmaximum_num(x, y) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::{Float, Hexf}; - - fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), - (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), - (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), - ]; - - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn fminimum_num_spec_tests_f16() { - fminimum_num_spec_test::(fminimum_numf16); - } - - #[test] - fn fminimum_num_spec_tests_f32() { - fminimum_num_spec_test::(fminimum_numf); - } - - #[test] - fn fminimum_num_spec_tests_f64() { - fminimum_num_spec_test::(fminimum_num); - } - - #[test] - #[cfg(f128_enabled)] - fn fminimum_num_spec_tests_f128() { - fminimum_num_spec_test::(fminimum_numf128); - } - - fn fmaximum_num_spec_test(f: impl Fn(F, F) -> F) { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), - (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::ZERO), - (F::NEG_ZERO, F::ZERO, F::ZERO), - ]; - - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn fmaximum_num_spec_tests_f16() { - fmaximum_num_spec_test::(fmaximum_numf16); - } - - #[test] - fn fmaximum_num_spec_tests_f32() { - fmaximum_num_spec_test::(fmaximum_numf); - } - - #[test] - fn fmaximum_num_spec_tests_f64() { - fmaximum_num_spec_test::(fmaximum_num); - } - - #[test] - #[cfg(f128_enabled)] - fn fmaximum_num_spec_tests_f128() { - fmaximum_num_spec_test::(fmaximum_numf128); - } -} diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs deleted file mode 100644 index c4752b92578..00000000000 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ /dev/null @@ -1,25 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf16(x: f16, y: f16) -> f16 { - super::generic::fmod(x, y) -} - -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf(x: f32, y: f32) -> f32 { - super::generic::fmod(x, y) -} - -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmod(x: f64, y: f64) -> f64 { - super::generic::fmod(x, y) -} - -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf128(x: f128, y: f128) -> f128 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/frexp.rs b/library/compiler-builtins/libm/src/math/frexp.rs deleted file mode 100644 index de7a64fdae1..00000000000 --- a/library/compiler-builtins/libm/src/math/frexp.rs +++ /dev/null @@ -1,21 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn frexp(x: f64) -> (f64, i32) { - let mut y = x.to_bits(); - let ee = ((y >> 52) & 0x7ff) as i32; - - if ee == 0 { - if x != 0.0 { - let x1p64 = f64::from_bits(0x43f0000000000000); - let (x, e) = frexp(x * x1p64); - return (x, e - 64); - } - return (x, 0); - } else if ee == 0x7ff { - return (x, 0); - } - - let e = ee - 0x3fe; - y &= 0x800fffffffffffff; - y |= 0x3fe0000000000000; - return (f64::from_bits(y), e); -} diff --git a/library/compiler-builtins/libm/src/math/frexpf.rs b/library/compiler-builtins/libm/src/math/frexpf.rs deleted file mode 100644 index 0ec91c2d350..00000000000 --- a/library/compiler-builtins/libm/src/math/frexpf.rs +++ /dev/null @@ -1,22 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn frexpf(x: f32) -> (f32, i32) { - let mut y = x.to_bits(); - let ee: i32 = ((y >> 23) & 0xff) as i32; - - if ee == 0 { - if x != 0.0 { - let x1p64 = f32::from_bits(0x5f800000); - let (x, e) = frexpf(x * x1p64); - return (x, e - 64); - } else { - return (x, 0); - } - } else if ee == 0xff { - return (x, 0); - } - - let e = ee - 0x7e; - y &= 0x807fffff; - y |= 0x3f000000; - (f32::from_bits(y), e) -} diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs deleted file mode 100644 index 5c5bb47638f..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ /dev/null @@ -1,168 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/ceilf.c */ - -//! Generic `ceil` algorithm. -//! -//! Note that this uses the algorithm from musl's `ceilf` rather than `ceil` or `ceill` because -//! performance seems to be better (based on icount) and it does not seem to experience rounding -//! errors on i386. - -use super::super::support::{FpResult, Status}; -use super::super::{Float, Int, IntTy, MinInt}; - -#[inline] -pub fn ceil(x: F) -> F { - ceil_status(x).val -} - -#[inline] -pub fn ceil_status(x: F) -> FpResult { - let zero = IntTy::::ZERO; - - let mut ix = x.to_bits(); - let e = x.exp_unbiased(); - - // If the represented value has no fractional part, no truncation is needed. - if e >= F::SIG_BITS as i32 { - return FpResult::ok(x); - } - - let status; - let res = if e >= 0 { - // |x| >= 1.0 - let m = F::SIG_MASK >> e.unsigned(); - if (ix & m) == zero { - // Portion to be masked is already zero; no adjustment needed. - return FpResult::ok(x); - } - - // Otherwise, raise an inexact exception. - status = Status::INEXACT; - - if x.is_sign_positive() { - ix += m; - } - - ix &= !m; - F::from_bits(ix) - } else { - // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). - if ix & F::SIG_MASK == F::Int::ZERO { - status = Status::OK; - } else { - status = Status::INEXACT; - } - - if x.is_sign_negative() { - // -1.0 < x <= -0.0; rounding up goes toward -0.0. - F::NEG_ZERO - } else if ix << 1 != zero { - // 0.0 < x < 1.0; rounding up goes toward +1.0. - F::ONE - } else { - // +0.0 remains unchanged - x - } - }; - - FpResult::new(res, status) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - /// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil - fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; - - for x in roundtrip { - let FpResult { val, status } = ceil_status(x); - assert_biteq!(val, x, "{}", Hexf(x)); - assert_eq!(status, Status::OK, "{}", Hexf(x)); - } - - for &(x, res, res_stat) in cases { - let FpResult { val, status } = ceil_status(x); - assert_biteq!(val, res, "{}", Hexf(x)); - assert_eq!(status, res_stat, "{}", Hexf(x)); - } - } - - /* Skipping f16 / f128 "sanity_check"s due to rejected literal lexing at MSRV */ - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - let cases = [ - (0.1, 1.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 2.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); - } - - #[test] - fn sanity_check_f32() { - assert_eq!(ceil(1.1f32), 2.0); - assert_eq!(ceil(2.9f32), 3.0); - } - - #[test] - fn spec_tests_f32() { - let cases = [ - (0.1, 1.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 2.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); - } - - #[test] - fn sanity_check_f64() { - assert_eq!(ceil(1.1f64), 2.0); - assert_eq!(ceil(2.9f64), 3.0); - } - - #[test] - fn spec_tests_f64() { - let cases = [ - (0.1, 1.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 2.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - let cases = [ - (0.1, 1.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 2.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/copysign.rs b/library/compiler-builtins/libm/src/math/generic/copysign.rs deleted file mode 100644 index a61af22f04a..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/copysign.rs +++ /dev/null @@ -1,11 +0,0 @@ -use super::super::Float; - -/// Copy the sign of `y` to `x`. -#[inline] -pub fn copysign(x: F, y: F) -> F { - let mut ux = x.to_bits(); - let uy = y.to_bits(); - ux &= !F::SIGN_MASK; - ux |= uy & F::SIGN_MASK; - F::from_bits(ux) -} diff --git a/library/compiler-builtins/libm/src/math/generic/fabs.rs b/library/compiler-builtins/libm/src/math/generic/fabs.rs deleted file mode 100644 index 0fa0edf9b87..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/fabs.rs +++ /dev/null @@ -1,8 +0,0 @@ -use super::super::Float; - -/// Absolute value. -#[inline] -pub fn fabs(x: F) -> F { - let abs_mask = !F::SIGN_MASK; - F::from_bits(x.to_bits() & abs_mask) -} diff --git a/library/compiler-builtins/libm/src/math/generic/fdim.rs b/library/compiler-builtins/libm/src/math/generic/fdim.rs deleted file mode 100644 index a63007b191c..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/fdim.rs +++ /dev/null @@ -1,6 +0,0 @@ -use super::super::Float; - -#[inline] -pub fn fdim(x: F, y: F) -> F { - if x <= y { F::ZERO } else { x - y } -} diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs deleted file mode 100644 index 2438046254f..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/floor.rs +++ /dev/null @@ -1,151 +0,0 @@ -/* SPDX-License-Identifier: MIT - * origin: musl src/math/floor.c */ - -//! Generic `floor` algorithm. -//! -//! Note that this uses the algorithm from musl's `floorf` rather than `floor` or `floorl` because -//! performance seems to be better (based on icount) and it does not seem to experience rounding -//! errors on i386. - -use super::super::support::{FpResult, Status}; -use super::super::{Float, Int, IntTy, MinInt}; - -#[inline] -pub fn floor(x: F) -> F { - floor_status(x).val -} - -#[inline] -pub fn floor_status(x: F) -> FpResult { - let zero = IntTy::::ZERO; - - let mut ix = x.to_bits(); - let e = x.exp_unbiased(); - - // If the represented value has no fractional part, no truncation is needed. - if e >= F::SIG_BITS as i32 { - return FpResult::ok(x); - } - - let status; - let res = if e >= 0 { - // |x| >= 1.0 - let m = F::SIG_MASK >> e.unsigned(); - if ix & m == zero { - // Portion to be masked is already zero; no adjustment needed. - return FpResult::ok(x); - } - - // Otherwise, raise an inexact exception. - status = Status::INEXACT; - - if x.is_sign_negative() { - ix += m; - } - - ix &= !m; - F::from_bits(ix) - } else { - // |x| < 1.0, raise an inexact exception since truncation will happen. - if ix & F::SIG_MASK == F::Int::ZERO { - status = Status::OK; - } else { - status = Status::INEXACT; - } - - if x.is_sign_positive() { - // 0.0 <= x < 1.0; rounding down goes toward +0.0. - F::ZERO - } else if ix << 1 != zero { - // -1.0 < x < 0.0; rounding down goes toward -1.0. - F::NEG_ONE - } else { - // -0.0 remains unchanged - x - } - }; - - FpResult::new(res, status) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - /// Test against https://en.cppreference.com/w/cpp/numeric/math/floor - fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; - - for x in roundtrip { - let FpResult { val, status } = floor_status(x); - assert_biteq!(val, x, "{}", Hexf(x)); - assert_eq!(status, Status::OK, "{}", Hexf(x)); - } - - for &(x, res, res_stat) in cases { - let FpResult { val, status } = floor_status(x); - assert_biteq!(val, res, "{}", Hexf(x)); - assert_eq!(status, res_stat, "{}", Hexf(x)); - } - } - - /* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */ - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - let cases = []; - spec_test::(&cases); - } - - #[test] - fn sanity_check_f32() { - assert_eq!(floor(0.5f32), 0.0); - assert_eq!(floor(1.1f32), 1.0); - assert_eq!(floor(2.9f32), 2.0); - } - - #[test] - fn spec_tests_f32() { - let cases = [ - (0.1, 0.0, Status::INEXACT), - (-0.1, -1.0, Status::INEXACT), - (0.9, 0.0, Status::INEXACT), - (-0.9, -1.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -2.0, Status::INEXACT), - (1.9, 1.0, Status::INEXACT), - (-1.9, -2.0, Status::INEXACT), - ]; - spec_test::(&cases); - } - - #[test] - fn sanity_check_f64() { - assert_eq!(floor(1.1f64), 1.0); - assert_eq!(floor(2.9f64), 2.0); - } - - #[test] - fn spec_tests_f64() { - let cases = [ - (0.1, 0.0, Status::INEXACT), - (-0.1, -1.0, Status::INEXACT), - (0.9, 0.0, Status::INEXACT), - (-0.9, -1.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -2.0, Status::INEXACT), - (1.9, 1.0, Status::INEXACT), - (-1.9, -2.0, Status::INEXACT), - ]; - spec_test::(&cases); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - let cases = []; - spec_test::(&cases); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs deleted file mode 100644 index bf3f847e89b..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/fmax.rs +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: MIT OR Apache-2.0 */ -//! IEEE 754-2011 `maxNum`. This has been superseded by IEEE 754-2019 `maximumNumber`. -//! -//! Per the spec, returns the canonicalized result of: -//! - `x` if `x > y` -//! - `y` if `y > x` -//! - The other number if one is NaN -//! - Otherwise, either `x` or `y`, canonicalized -//! - -0.0 and +0.0 may be disregarded (unlike newer operations) -//! -//! Excluded from our implementation is sNaN handling. -//! -//! More on the differences: [link]. -//! -//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf - -use super::super::Float; - -#[inline] -pub fn fmax(x: F, y: F) -> F { - let res = if x.is_nan() || x < y { y } else { x }; - // Canonicalize - res * F::ONE -} diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs deleted file mode 100644 index 387055af29c..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: MIT OR Apache-2.0 */ -//! IEEE 754-2019 `maximum`. -//! -//! Per the spec, returns the canonicalized result of: -//! - `x` if `x > y` -//! - `y` if `y > x` -//! - qNaN if either operation is NaN -//! - Logic following +0.0 > -0.0 -//! -//! Excluded from our implementation is sNaN handling. - -use super::super::Float; - -#[inline] -pub fn fmaximum(x: F, y: F) -> F { - let res = if x.is_nan() { - x - } else if y.is_nan() { - y - } else if x > y || (y.to_bits() == F::NEG_ZERO.to_bits() && x.is_sign_positive()) { - x - } else { - y - }; - - // Canonicalize - res * F::ONE -} diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs deleted file mode 100644 index f7efdde80ea..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: MIT OR Apache-2.0 */ -//! IEEE 754-2019 `maximumNumber`. -//! -//! Per the spec, returns: -//! - `x` if `x > y` -//! - `y` if `y > x` -//! - Non-NaN if one operand is NaN -//! - Logic following +0.0 > -0.0 -//! - Either `x` or `y` if `x == y` and the signs are the same -//! - qNaN if either operand is a NaN -//! -//! Excluded from our implementation is sNaN handling. - -use super::super::Float; - -#[inline] -pub fn fmaximum_num(x: F, y: F) -> F { - let res = - if x.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { - y - } else { - x - }; - - // Canonicalize - res * F::ONE -} diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs deleted file mode 100644 index cd3caeee4f2..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/fmin.rs +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: MIT OR Apache-2.0 */ -//! IEEE 754-2008 `minNum`. This has been superseded by IEEE 754-2019 `minimumNumber`. -//! -//! Per the spec, returns the canonicalized result of: -//! - `x` if `x < y` -//! - `y` if `y < x` -//! - The other number if one is NaN -//! - Otherwise, either `x` or `y`, canonicalized -//! - -0.0 and +0.0 may be disregarded (unlike newer operations) -//! -//! Excluded from our implementation is sNaN handling. -//! -//! More on the differences: [link]. -//! -//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf - -use super::super::Float; - -#[inline] -pub fn fmin(x: F, y: F) -> F { - let res = if y.is_nan() || x < y { x } else { y }; - // Canonicalize - res * F::ONE -} diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs deleted file mode 100644 index 4ddb3645506..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/fminimum.rs +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: MIT OR Apache-2.0 */ -//! IEEE 754-2019 `minimum`. -//! -//! Per the spec, returns the canonicalized result of: -//! - `x` if `x < y` -//! - `y` if `y < x` -//! - qNaN if either operation is NaN -//! - Logic following +0.0 > -0.0 -//! -//! Excluded from our implementation is sNaN handling. - -use super::super::Float; - -#[inline] -pub fn fminimum(x: F, y: F) -> F { - let res = if x.is_nan() { - x - } else if y.is_nan() { - y - } else if x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { - x - } else { - y - }; - - // Canonicalize - res * F::ONE -} diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs deleted file mode 100644 index 441c204a921..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: MIT OR Apache-2.0 */ -//! IEEE 754-2019 `minimum`. -//! -//! Per the spec, returns: -//! - `x` if `x < y` -//! - `y` if `y < x` -//! - Non-NaN if one operand is NaN -//! - Logic following +0.0 > -0.0 -//! - Either `x` or `y` if `x == y` and the signs are the same -//! - qNaN if either operand is a NaN -//! -//! Excluded from our implementation is sNaN handling. - -use super::super::Float; - -#[inline] -pub fn fminimum_num(x: F, y: F) -> F { - let res = - if y.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { - x - } else { - y - }; - - // Canonicalize - res * F::ONE -} diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs deleted file mode 100644 index 6414bbd2508..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/fmod.rs +++ /dev/null @@ -1,84 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/fmod.c. Ported to generic Rust algorithm in 2025, TG. */ - -use super::super::{CastFrom, Float, Int, MinInt}; - -#[inline] -pub fn fmod(x: F, y: F) -> F { - let zero = F::Int::ZERO; - let one = F::Int::ONE; - let mut ix = x.to_bits(); - let mut iy = y.to_bits(); - let mut ex = x.ex().signed(); - let mut ey = y.ex().signed(); - let sx = ix & F::SIGN_MASK; - - if iy << 1 == zero || y.is_nan() || ex == F::EXP_SAT as i32 { - return (x * y) / (x * y); - } - - if ix << 1 <= iy << 1 { - if ix << 1 == iy << 1 { - return F::ZERO * x; - } - return x; - } - - /* normalize x and y */ - if ex == 0 { - let i = ix << (F::EXP_BITS + 1); - ex -= i.leading_zeros() as i32; - ix <<= -ex + 1; - } else { - ix &= F::Int::MAX >> F::EXP_BITS; - ix |= one << F::SIG_BITS; - } - - if ey == 0 { - let i = iy << (F::EXP_BITS + 1); - ey -= i.leading_zeros() as i32; - iy <<= -ey + 1; - } else { - iy &= F::Int::MAX >> F::EXP_BITS; - iy |= one << F::SIG_BITS; - } - - /* x mod y */ - while ex > ey { - let i = ix.wrapping_sub(iy); - if i >> (F::BITS - 1) == zero { - if i == zero { - return F::ZERO * x; - } - ix = i; - } - - ix <<= 1; - ex -= 1; - } - - let i = ix.wrapping_sub(iy); - if i >> (F::BITS - 1) == zero { - if i == zero { - return F::ZERO * x; - } - - ix = i; - } - - let shift = ix.leading_zeros().saturating_sub(F::EXP_BITS); - ix <<= shift; - ex -= shift as i32; - - /* scale result */ - if ex > 0 { - ix -= one << F::SIG_BITS; - ix |= F::Int::cast_from(ex) << F::SIG_BITS; - } else { - ix >>= -ex + 1; - } - - ix |= sx; - - F::from_bits(ix) -} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs deleted file mode 100644 index 35846351a6e..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Note: generic functions are marked `#[inline]` because, even though generic functions are -// typically inlined, this does not seem to always be the case. - -mod ceil; -mod copysign; -mod fabs; -mod fdim; -mod floor; -mod fmax; -mod fmaximum; -mod fmaximum_num; -mod fmin; -mod fminimum; -mod fminimum_num; -mod fmod; -mod rint; -mod round; -mod scalbn; -mod sqrt; -mod trunc; - -pub use ceil::ceil; -pub use copysign::copysign; -pub use fabs::fabs; -pub use fdim::fdim; -pub use floor::floor; -pub use fmax::fmax; -pub use fmaximum::fmaximum; -pub use fmaximum_num::fmaximum_num; -pub use fmin::fmin; -pub use fminimum::fminimum; -pub use fminimum_num::fminimum_num; -pub use fmod::fmod; -pub use rint::rint_round; -pub use round::round; -pub use scalbn::scalbn; -pub use sqrt::sqrt; -pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs deleted file mode 100644 index 9cdeb1185a8..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ /dev/null @@ -1,120 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/rint.c */ - -use super::super::Float; -use super::super::support::{FpResult, Round}; - -/// IEEE 754-2019 `roundToIntegralExact`, which respects rounding mode and raises inexact if -/// applicable. -#[inline] -pub fn rint_round(x: F, _round: Round) -> FpResult { - let toint = F::ONE / F::EPSILON; - let e = x.ex(); - let positive = x.is_sign_positive(); - - // On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise, - // the excess precission from x87 would cause an incorrect final result. - let force = |x| { - if cfg!(x86_no_sse) && (F::BITS == 32 || F::BITS == 64) { force_eval!(x) } else { x } - }; - - let res = if e >= F::EXP_BIAS + F::SIG_BITS { - // No fractional part; exact result can be returned. - x - } else { - // Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode. For - // Rust this is always nearest, but ideally it would take `round` into account. - let y = if positive { - force(force(x) + toint) - toint - } else { - force(force(x) - toint) + toint - }; - - if y == F::ZERO { - // A zero result takes the sign of the input. - if positive { F::ZERO } else { F::NEG_ZERO } - } else { - y - } - }; - - FpResult::ok(res) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::{Hexf, Status}; - - fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; - - for x in roundtrip { - let FpResult { val, status } = rint_round(x, Round::Nearest); - assert_biteq!(val, x, "rint_round({})", Hexf(x)); - assert_eq!(status, Status::OK, "{}", Hexf(x)); - } - - for &(x, res, res_stat) in cases { - let FpResult { val, status } = rint_round(x, Round::Nearest); - assert_biteq!(val, res, "rint_round({})", Hexf(x)); - assert_eq!(status, res_stat, "{}", Hexf(x)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - let cases = []; - spec_test::(&cases); - } - - #[test] - fn spec_tests_f32() { - let cases = [ - (0.1, 0.0, Status::OK), - (-0.1, -0.0, Status::OK), - (0.5, 0.0, Status::OK), - (-0.5, -0.0, Status::OK), - (0.9, 1.0, Status::OK), - (-0.9, -1.0, Status::OK), - (1.1, 1.0, Status::OK), - (-1.1, -1.0, Status::OK), - (1.5, 2.0, Status::OK), - (-1.5, -2.0, Status::OK), - (1.9, 2.0, Status::OK), - (-1.9, -2.0, Status::OK), - (2.8, 3.0, Status::OK), - (-2.8, -3.0, Status::OK), - ]; - spec_test::(&cases); - } - - #[test] - fn spec_tests_f64() { - let cases = [ - (0.1, 0.0, Status::OK), - (-0.1, -0.0, Status::OK), - (0.5, 0.0, Status::OK), - (-0.5, -0.0, Status::OK), - (0.9, 1.0, Status::OK), - (-0.9, -1.0, Status::OK), - (1.1, 1.0, Status::OK), - (-1.1, -1.0, Status::OK), - (1.5, 2.0, Status::OK), - (-1.5, -2.0, Status::OK), - (1.9, 2.0, Status::OK), - (-1.9, -2.0, Status::OK), - (2.8, 3.0, Status::OK), - (-2.8, -3.0, Status::OK), - ]; - spec_test::(&cases); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - let cases = []; - spec_test::(&cases); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/round.rs b/library/compiler-builtins/libm/src/math/generic/round.rs deleted file mode 100644 index 01314ac70c2..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/round.rs +++ /dev/null @@ -1,83 +0,0 @@ -use super::super::{Float, MinInt}; -use super::{copysign, trunc}; - -#[inline] -pub fn round(x: F) -> F { - let f0p5 = F::from_parts(false, F::EXP_BIAS - 1, F::Int::ZERO); // 0.5 - let f0p25 = F::from_parts(false, F::EXP_BIAS - 2, F::Int::ZERO); // 0.25 - - trunc(x + copysign(f0p5 - f0p25 * F::EPSILON, x)) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[cfg(f16_enabled)] - fn zeroes_f16() { - assert_biteq!(round(0.0_f16), 0.0_f16); - assert_biteq!(round(-0.0_f16), -0.0_f16); - } - - #[test] - #[cfg(f16_enabled)] - fn sanity_check_f16() { - assert_eq!(round(-1.0_f16), -1.0); - assert_eq!(round(2.8_f16), 3.0); - assert_eq!(round(-0.5_f16), -1.0); - assert_eq!(round(0.5_f16), 1.0); - assert_eq!(round(-1.5_f16), -2.0); - assert_eq!(round(1.5_f16), 2.0); - } - - #[test] - fn zeroes_f32() { - assert_biteq!(round(0.0_f32), 0.0_f32); - assert_biteq!(round(-0.0_f32), -0.0_f32); - } - - #[test] - fn sanity_check_f32() { - assert_eq!(round(-1.0_f32), -1.0); - assert_eq!(round(2.8_f32), 3.0); - assert_eq!(round(-0.5_f32), -1.0); - assert_eq!(round(0.5_f32), 1.0); - assert_eq!(round(-1.5_f32), -2.0); - assert_eq!(round(1.5_f32), 2.0); - } - - #[test] - fn zeroes_f64() { - assert_biteq!(round(0.0_f64), 0.0_f64); - assert_biteq!(round(-0.0_f64), -0.0_f64); - } - - #[test] - fn sanity_check_f64() { - assert_eq!(round(-1.0_f64), -1.0); - assert_eq!(round(2.8_f64), 3.0); - assert_eq!(round(-0.5_f64), -1.0); - assert_eq!(round(0.5_f64), 1.0); - assert_eq!(round(-1.5_f64), -2.0); - assert_eq!(round(1.5_f64), 2.0); - } - - #[test] - #[cfg(f128_enabled)] - fn zeroes_f128() { - assert_biteq!(round(0.0_f128), 0.0_f128); - assert_biteq!(round(-0.0_f128), -0.0_f128); - } - - #[test] - #[cfg(f128_enabled)] - fn sanity_check_f128() { - assert_eq!(round(-1.0_f128), -1.0); - assert_eq!(round(2.8_f128), 3.0); - assert_eq!(round(-0.5_f128), -1.0); - assert_eq!(round(0.5_f128), 1.0); - assert_eq!(round(-1.5_f128), -2.0); - assert_eq!(round(1.5_f128), 2.0); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs deleted file mode 100644 index a45db1b4a02..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/scalbn.rs +++ /dev/null @@ -1,121 +0,0 @@ -use super::super::{CastFrom, CastInto, Float, IntTy, MinInt}; - -/// Scale the exponent. -/// -/// From N3220: -/// -/// > The scalbn and scalbln functions compute `x * b^n`, where `b = FLT_RADIX` if the return type -/// > of the function is a standard floating type, or `b = 10` if the return type of the function -/// > is a decimal floating type. A range error occurs for some finite x, depending on n. -/// > -/// > [...] -/// > -/// > * `scalbn(±0, n)` returns `±0`. -/// > * `scalbn(x, 0)` returns `x`. -/// > * `scalbn(±∞, n)` returns `±∞`. -/// > -/// > If the calculation does not overflow or underflow, the returned value is exact and -/// > independent of the current rounding direction mode. -#[inline] -pub fn scalbn(mut x: F, mut n: i32) -> F -where - u32: CastInto, - F::Int: CastFrom, - F::Int: CastFrom, -{ - let zero = IntTy::::ZERO; - - // Bits including the implicit bit - let sig_total_bits = F::SIG_BITS + 1; - - // Maximum and minimum values when biased - let exp_max = F::EXP_MAX; - let exp_min = F::EXP_MIN; - - // 2 ^ Emax, maximum positive with null significand (0x1p1023 for f64) - let f_exp_max = F::from_parts(false, F::EXP_BIAS << 1, zero); - - // 2 ^ Emin, minimum positive normal with null significand (0x1p-1022 for f64) - let f_exp_min = F::from_parts(false, 1, zero); - - // 2 ^ sig_total_bits, moltiplier to normalize subnormals (0x1p53 for f64) - let f_pow_subnorm = F::from_parts(false, sig_total_bits + F::EXP_BIAS, zero); - - /* - * The goal is to multiply `x` by a scale factor that applies `n`. However, there are cases - * where `2^n` is not representable by `F` but the result should be, e.g. `x = 2^Emin` with - * `n = -EMin + 2` (one out of range of 2^Emax). To get around this, reduce the magnitude of - * the final scale operation by prescaling by the max/min power representable by `F`. - */ - - if n > exp_max { - // Worse case positive `n`: `x` is the minimum subnormal value, the result is `F::MAX`. - // This can be reached by three scaling multiplications (two here and one final). - debug_assert!(-exp_min + F::SIG_BITS as i32 + exp_max <= exp_max * 3); - - x *= f_exp_max; - n -= exp_max; - if n > exp_max { - x *= f_exp_max; - n -= exp_max; - if n > exp_max { - n = exp_max; - } - } - } else if n < exp_min { - // When scaling toward 0, the prescaling is limited to a value that does not allow `x` to - // go subnormal. This avoids double rounding. - if F::BITS > 16 { - // `mul` s.t. `!(x * mul).is_subnormal() ∀ x` - let mul = f_exp_min * f_pow_subnorm; - let add = -exp_min - sig_total_bits as i32; - - // Worse case negative `n`: `x` is the maximum positive value, the result is `F::MIN`. - // This must be reachable by three scaling multiplications (two here and one final). - debug_assert!(-exp_min + F::SIG_BITS as i32 + exp_max <= add * 2 + -exp_min); - - x *= mul; - n += add; - - if n < exp_min { - x *= mul; - n += add; - - if n < exp_min { - n = exp_min; - } - } - } else { - // `f16` is unique compared to other float types in that the difference between the - // minimum exponent and the significand bits (`add = -exp_min - sig_total_bits`) is - // small, only three. The above method depend on decrementing `n` by `add` two times; - // for other float types this works out because `add` is a substantial fraction of - // the exponent range. For `f16`, however, 3 is relatively small compared to the - // exponent range (which is 39), so that requires ~10 prescale rounds rather than two. - // - // Work aroudn this by using a different algorithm that calculates the prescale - // dynamically based on the maximum possible value. This adds more operations per round - // since it needs to construct the scale, but works better in the general case. - let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32); - let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero); - - x *= mul; - n += add; - - if n < exp_min { - let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32); - let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero); - - x *= mul; - n += add; - - if n < exp_min { - n = exp_min; - } - } - } - } - - let scale = F::from_parts(false, (F::EXP_BIAS as i32 + n) as u32, zero); - x * scale -} diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs deleted file mode 100644 index ec9ff22df20..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ /dev/null @@ -1,537 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/sqrt.c. Ported to generic Rust algorithm in 2025, TG. */ - -//! Generic square root algorithm. -//! -//! This routine operates around `m_u2`, a U.2 (fixed point with two integral bits) mantissa -//! within the range [1, 4). A table lookup provides an initial estimate, then goldschmidt -//! iterations at various widths are used to approach the real values. -//! -//! For the iterations, `r` is a U0 number that approaches `1/sqrt(m_u2)`, and `s` is a U2 number -//! that approaches `sqrt(m_u2)`. Recall that m_u2 ∈ [1, 4). -//! -//! With Newton-Raphson iterations, this would be: -//! -//! - `w = r * r w ~ 1 / m` -//! - `u = 3 - m * w u ~ 3 - m * w = 3 - m / m = 2` -//! - `r = r * u / 2 r ~ r` -//! -//! (Note that the righthand column does not show anything analytically meaningful (i.e. r ~ r), -//! since the value of performing one iteration is in reducing the error representable by `~`). -//! -//! Instead of Newton-Raphson iterations, Goldschmidt iterations are used to calculate -//! `s = m * r`: -//! -//! - `s = m * r s ~ m / sqrt(m)` -//! - `u = 3 - s * r u ~ 3 - (m / sqrt(m)) * (1 / sqrt(m)) = 3 - m / m = 2` -//! - `r = r * u / 2 r ~ r` -//! - `s = s * u / 2 s ~ s` -//! -//! The above is precise because it uses the original value `m`. There is also a faster version -//! that performs fewer steps but does not use `m`: -//! -//! - `u = 3 - s * r u ~ 3 - 1` -//! - `r = r * u / 2 r ~ r` -//! - `s = s * u / 2 s ~ s` -//! -//! Rounding errors accumulate faster with the second version, so it is only used for subsequent -//! iterations within the same width integer. The first version is always used for the first -//! iteration at a new width in order to avoid this accumulation. -//! -//! Goldschmidt has the advantage over Newton-Raphson that `sqrt(x)` and `1/sqrt(x)` are -//! computed at the same time, i.e. there is no need to calculate `1/sqrt(x)` and invert it. - -use super::super::support::{FpResult, IntTy, Round, Status, cold_path}; -use super::super::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; - -#[inline] -pub fn sqrt(x: F) -> F -where - F: Float + SqrtHelper, - F::Int: HInt, - F::Int: From, - F::Int: From, - F::Int: CastInto, - F::Int: CastInto, - u32: CastInto, -{ - sqrt_round(x, Round::Nearest).val -} - -#[inline] -pub fn sqrt_round(x: F, _round: Round) -> FpResult -where - F: Float + SqrtHelper, - F::Int: HInt, - F::Int: From, - F::Int: From, - F::Int: CastInto, - F::Int: CastInto, - u32: CastInto, -{ - let zero = IntTy::::ZERO; - let one = IntTy::::ONE; - - let mut ix = x.to_bits(); - - // Top is the exponent and sign, which may or may not be shifted. If the float fits into a - // `u32`, we can get by without paying shifting costs. - let noshift = F::BITS <= u32::BITS; - let (mut top, special_case) = if noshift { - let exp_lsb = one << F::SIG_BITS; - let special_case = ix.wrapping_sub(exp_lsb) >= F::EXP_MASK - exp_lsb; - (Exp::NoShift(()), special_case) - } else { - let top = u32::cast_from(ix >> F::SIG_BITS); - let special_case = top.wrapping_sub(1) >= F::EXP_SAT - 1; - (Exp::Shifted(top), special_case) - }; - - // Handle NaN, zero, and out of domain (<= 0) - if special_case { - cold_path(); - - // +/-0 - if ix << 1 == zero { - return FpResult::ok(x); - } - - // Positive infinity - if ix == F::EXP_MASK { - return FpResult::ok(x); - } - - // NaN or negative - if ix > F::EXP_MASK { - return FpResult::new(F::NAN, Status::INVALID); - } - - // Normalize subnormals by multiplying by 1.0 << SIG_BITS (e.g. 0x1p52 for doubles). - let scaled = x * F::from_parts(false, F::SIG_BITS + F::EXP_BIAS, zero); - ix = scaled.to_bits(); - match top { - Exp::Shifted(ref mut v) => { - *v = scaled.ex(); - *v = (*v).wrapping_sub(F::SIG_BITS); - } - Exp::NoShift(()) => { - ix = ix.wrapping_sub((F::SIG_BITS << F::SIG_BITS).cast()); - } - } - } - - // Reduce arguments such that `x = 4^e * m`: - // - // - m_u2 ∈ [1, 4), a fixed point U2.BITS number - // - 2^e is the exponent part of the result - let (m_u2, exp) = match top { - Exp::Shifted(top) => { - // We now know `x` is positive, so `top` is just its (biased) exponent - let mut e = top; - // Construct a fixed point representation of the mantissa. - let mut m_u2 = (ix | F::IMPLICIT_BIT) << F::EXP_BITS; - let even = (e & 1) != 0; - if even { - m_u2 >>= 1; - } - e = (e.wrapping_add(F::EXP_SAT >> 1)) >> 1; - (m_u2, Exp::Shifted(e)) - } - Exp::NoShift(()) => { - let even = ix & (one << F::SIG_BITS) != zero; - - // Exponent part of the return value - let mut e_noshift = ix >> 1; - // ey &= (F::EXP_MASK << 2) >> 2; // clear the top exponent bit (result = 1.0) - e_noshift += (F::EXP_MASK ^ (F::SIGN_MASK >> 1)) >> 1; - e_noshift &= F::EXP_MASK; - - let m1 = (ix << F::EXP_BITS) | F::SIGN_MASK; - let m0 = (ix << (F::EXP_BITS - 1)) & !F::SIGN_MASK; - let m_u2 = if even { m0 } else { m1 }; - - (m_u2, Exp::NoShift(e_noshift)) - } - }; - - // Extract the top 6 bits of the significand with the lowest bit of the exponent. - let i = usize::cast_from(ix >> (F::SIG_BITS - 6)) & 0b1111111; - - // Start with an initial guess for `r = 1 / sqrt(m)` from the table, and shift `m` as an - // initial value for `s = sqrt(m)`. See the module documentation for details. - let r1_u0: F::ISet1 = F::ISet1::cast_from(RSQRT_TAB[i]) << (F::ISet1::BITS - 16); - let s1_u2: F::ISet1 = ((m_u2) >> (F::BITS - F::ISet1::BITS)).cast(); - - // Perform iterations, if any, at quarter width (used for `f128`). - let (r1_u0, _s1_u2) = goldschmidt::(r1_u0, s1_u2, F::SET1_ROUNDS, false); - - // Widen values and perform iterations at half width (used for `f64` and `f128`). - let r2_u0: F::ISet2 = F::ISet2::from(r1_u0) << (F::ISet2::BITS - F::ISet1::BITS); - let s2_u2: F::ISet2 = ((m_u2) >> (F::BITS - F::ISet2::BITS)).cast(); - let (r2_u0, _s2_u2) = goldschmidt::(r2_u0, s2_u2, F::SET2_ROUNDS, false); - - // Perform final iterations at full width (used for all float types). - let r_u0: F::Int = F::Int::from(r2_u0) << (F::BITS - F::ISet2::BITS); - let s_u2: F::Int = m_u2; - let (_r_u0, s_u2) = goldschmidt::(r_u0, s_u2, F::FINAL_ROUNDS, true); - - // Shift back to mantissa position. - let mut m = s_u2 >> (F::EXP_BITS - 2); - - // The musl source includes the following comment (with literals replaced): - // - // > s < sqrt(m) < s + 0x1.09p-SIG_BITS - // > compute nearest rounded result: the nearest result to SIG_BITS bits is either s or - // > s+0x1p-SIG_BITS, we can decide by comparing (2^SIG_BITS s + 0.5)^2 to 2^(2*SIG_BITS) m. - // - // Expanding this with , with `SIG_BITS = p` and adjusting based on the operations done to - // `d0` and `d1`: - // - // - `2^(2p)m ≟ ((2^p)m + 0.5)^2` - // - `2^(2p)m ≟ 2^(2p)m^2 + (2^p)m + 0.25` - // - `2^(2p)m - m^2 ≟ (2^(2p) - 1)m^2 + (2^p)m + 0.25` - // - `(1 - 2^(2p))m + m^2 ≟ (1 - 2^(2p))m^2 + (1 - 2^p)m + 0.25` (?) - // - // I do not follow how the rounding bit is extracted from this comparison with the below - // operations. In any case, the algorithm is well tested. - - // The value needed to shift `m_u2` by to create `m*2^(2p)`. `2p = 2 * F::SIG_BITS`, - // `F::BITS - 2` accounts for the offset that `m_u2` already has. - let shift = 2 * F::SIG_BITS - (F::BITS - 2); - - // `2^(2p)m - m^2` - let d0 = (m_u2 << shift).wrapping_sub(m.wrapping_mul(m)); - // `m - 2^(2p)m + m^2` - let d1 = m.wrapping_sub(d0); - m += d1 >> (F::BITS - 1); - m &= F::SIG_MASK; - - match exp { - Exp::Shifted(e) => m |= IntTy::::cast_from(e) << F::SIG_BITS, - Exp::NoShift(e) => m |= e, - }; - - let mut y = F::from_bits(m); - - // FIXME(f16): the fenv math does not work for `f16` - if F::BITS > 16 { - // Handle rounding and inexact. `(m + 1)^2 == 2^shift m` is exact; for all other cases, add - // a tiny value to cause fenv effects. - let d2 = d1.wrapping_add(m).wrapping_add(one); - let mut tiny = if d2 == zero { - cold_path(); - zero - } else { - F::IMPLICIT_BIT - }; - - tiny |= (d1 ^ d2) & F::SIGN_MASK; - let t = F::from_bits(tiny); - y = y + t; - } - - FpResult::ok(y) -} - -/// Multiply at the wider integer size, returning the high half. -fn wmulh(a: I, b: I) -> I { - a.widen_mul(b).hi() -} - -/// Perform `count` goldschmidt iterations, returning `(r_u0, s_u?)`. -/// -/// - `r_u0` is the reciprocal `r ~ 1 / sqrt(m)`, as U0. -/// - `s_u2` is the square root, `s ~ sqrt(m)`, as U2. -/// - `count` is the number of iterations to perform. -/// - `final_set` should be true if this is the last round (same-sized integer). If so, the -/// returned `s` will be U3, for later shifting. Otherwise, the returned `s` is U2. -/// -/// Note that performance relies on the optimizer being able to unroll these loops (reasonably -/// trivial, `count` is a constant when called). -#[inline] -fn goldschmidt(mut r_u0: I, mut s_u2: I, count: u32, final_set: bool) -> (I, I) -where - F: SqrtHelper, - I: HInt + From, -{ - let three_u2 = I::from(0b11u8) << (I::BITS - 2); - let mut u_u0 = r_u0; - - for i in 0..count { - // First iteration: `s = m*r` (`u_u0 = r_u0` set above) - // Subsequent iterations: `s=s*u/2` - s_u2 = wmulh(s_u2, u_u0); - - // Perform `s /= 2` if: - // - // 1. This is not the first iteration (the first iteration is `s = m*r`)... - // 2. ... and this is not the last set of iterations - // 3. ... or, if this is the last set, it is not the last iteration - // - // This step is not performed for the final iteration because the shift is combined with - // a later shift (moving `s` into the mantissa). - if i > 0 && (!final_set || i + 1 < count) { - s_u2 <<= 1; - } - - // u = 3 - s*r - let d_u2 = wmulh(s_u2, r_u0); - u_u0 = three_u2.wrapping_sub(d_u2); - - // r = r*u/2 - r_u0 = wmulh(r_u0, u_u0) << 1; - } - - (r_u0, s_u2) -} - -/// Representation of whether we shift the exponent into a `u32`, or modify it in place to save -/// the shift operations. -enum Exp { - /// The exponent has been shifted to a `u32` and is LSB-aligned. - Shifted(u32), - /// The exponent is in its natural position in integer repr. - NoShift(T), -} - -/// Size-specific constants related to the square root routine. -pub trait SqrtHelper: Float { - /// Integer for the first set of rounds. If unused, set to the same type as the next set. - type ISet1: HInt + Into + CastFrom + From; - /// Integer for the second set of rounds. If unused, set to the same type as the next set. - type ISet2: HInt + From + From; - - /// Number of rounds at `ISet1`. - const SET1_ROUNDS: u32 = 0; - /// Number of rounds at `ISet2`. - const SET2_ROUNDS: u32 = 0; - /// Number of rounds at `Self::Int`. - const FINAL_ROUNDS: u32; -} - -#[cfg(f16_enabled)] -impl SqrtHelper for f16 { - type ISet1 = u16; // unused - type ISet2 = u16; // unused - - const FINAL_ROUNDS: u32 = 2; -} - -impl SqrtHelper for f32 { - type ISet1 = u32; // unused - type ISet2 = u32; // unused - - const FINAL_ROUNDS: u32 = 3; -} - -impl SqrtHelper for f64 { - type ISet1 = u32; // unused - type ISet2 = u32; - - const SET2_ROUNDS: u32 = 2; - const FINAL_ROUNDS: u32 = 2; -} - -#[cfg(f128_enabled)] -impl SqrtHelper for f128 { - type ISet1 = u32; - type ISet2 = u64; - - const SET1_ROUNDS: u32 = 1; - const SET2_ROUNDS: u32 = 2; - const FINAL_ROUNDS: u32 = 2; -} - -/// A U0.16 representation of `1/sqrt(x)`. -/// -/// The index is a 7-bit number consisting of a single exponent bit and 6 bits of significand. -#[rustfmt::skip] -static RSQRT_TAB: [u16; 128] = [ - 0xb451, 0xb2f0, 0xb196, 0xb044, 0xaef9, 0xadb6, 0xac79, 0xab43, - 0xaa14, 0xa8eb, 0xa7c8, 0xa6aa, 0xa592, 0xa480, 0xa373, 0xa26b, - 0xa168, 0xa06a, 0x9f70, 0x9e7b, 0x9d8a, 0x9c9d, 0x9bb5, 0x9ad1, - 0x99f0, 0x9913, 0x983a, 0x9765, 0x9693, 0x95c4, 0x94f8, 0x9430, - 0x936b, 0x92a9, 0x91ea, 0x912e, 0x9075, 0x8fbe, 0x8f0a, 0x8e59, - 0x8daa, 0x8cfe, 0x8c54, 0x8bac, 0x8b07, 0x8a64, 0x89c4, 0x8925, - 0x8889, 0x87ee, 0x8756, 0x86c0, 0x862b, 0x8599, 0x8508, 0x8479, - 0x83ec, 0x8361, 0x82d8, 0x8250, 0x81c9, 0x8145, 0x80c2, 0x8040, - 0xff02, 0xfd0e, 0xfb25, 0xf947, 0xf773, 0xf5aa, 0xf3ea, 0xf234, - 0xf087, 0xeee3, 0xed47, 0xebb3, 0xea27, 0xe8a3, 0xe727, 0xe5b2, - 0xe443, 0xe2dc, 0xe17a, 0xe020, 0xdecb, 0xdd7d, 0xdc34, 0xdaf1, - 0xd9b3, 0xd87b, 0xd748, 0xd61a, 0xd4f1, 0xd3cd, 0xd2ad, 0xd192, - 0xd07b, 0xcf69, 0xce5b, 0xcd51, 0xcc4a, 0xcb48, 0xca4a, 0xc94f, - 0xc858, 0xc764, 0xc674, 0xc587, 0xc49d, 0xc3b7, 0xc2d4, 0xc1f4, - 0xc116, 0xc03c, 0xbf65, 0xbe90, 0xbdbe, 0xbcef, 0xbc23, 0xbb59, - 0xba91, 0xb9cc, 0xb90a, 0xb84a, 0xb78c, 0xb6d0, 0xb617, 0xb560, -]; - -#[cfg(test)] -mod tests { - use super::*; - - /// Test behavior specified in IEEE 754 `squareRoot`. - fn spec_test() - where - F: Float + SqrtHelper, - F::Int: HInt, - F::Int: From, - F::Int: From, - F::Int: CastInto, - F::Int: CastInto, - u32: CastInto, - { - // Values that should return a NaN and raise invalid - let nan = [F::NEG_INFINITY, F::NEG_ONE, F::NAN, F::MIN]; - - // Values that return unaltered - let roundtrip = [F::ZERO, F::NEG_ZERO, F::INFINITY]; - - for x in nan { - let FpResult { val, status } = sqrt_round(x, Round::Nearest); - assert!(val.is_nan()); - assert!(status == Status::INVALID); - } - - for x in roundtrip { - let FpResult { val, status } = sqrt_round(x, Round::Nearest); - assert_biteq!(val, x); - assert!(status == Status::OK); - } - } - - #[test] - #[cfg(f16_enabled)] - fn sanity_check_f16() { - assert_biteq!(sqrt(100.0f16), 10.0); - assert_biteq!(sqrt(4.0f16), 2.0); - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - #[cfg(f16_enabled)] - #[allow(clippy::approx_constant)] - fn conformance_tests_f16() { - let cases = [ - (f16::PI, 0x3f17_u16), - // 10_000.0, using a hex literal for MSRV hack (Rust < 1.67 checks literal widths as - // part of the AST, so the `cfg` is irrelevant here). - (f16::from_bits(0x70e2), 0x5640_u16), - (f16::from_bits(0x0000000f), 0x13bf_u16), - (f16::INFINITY, f16::INFINITY.to_bits()), - ]; - - for (input, output) in cases { - assert_biteq!( - sqrt(input), - f16::from_bits(output), - "input: {input:?} ({:#018x})", - input.to_bits() - ); - } - } - - #[test] - fn sanity_check_f32() { - assert_biteq!(sqrt(100.0f32), 10.0); - assert_biteq!(sqrt(4.0f32), 2.0); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - #[allow(clippy::approx_constant)] - fn conformance_tests_f32() { - let cases = [ - (f32::PI, 0x3fe2dfc5_u32), - (10000.0f32, 0x42c80000_u32), - (f32::from_bits(0x0000000f), 0x1b2f456f_u32), - (f32::INFINITY, f32::INFINITY.to_bits()), - ]; - - for (input, output) in cases { - assert_biteq!( - sqrt(input), - f32::from_bits(output), - "input: {input:?} ({:#018x})", - input.to_bits() - ); - } - } - - #[test] - fn sanity_check_f64() { - assert_biteq!(sqrt(100.0f64), 10.0); - assert_biteq!(sqrt(4.0f64), 2.0); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[allow(clippy::approx_constant)] - fn conformance_tests_f64() { - let cases = [ - (f64::PI, 0x3ffc5bf891b4ef6a_u64), - (10000.0, 0x4059000000000000_u64), - (f64::from_bits(0x0000000f), 0x1e7efbdeb14f4eda_u64), - (f64::INFINITY, f64::INFINITY.to_bits()), - ]; - - for (input, output) in cases { - assert_biteq!( - sqrt(input), - f64::from_bits(output), - "input: {input:?} ({:#018x})", - input.to_bits() - ); - } - } - - #[test] - #[cfg(f128_enabled)] - fn sanity_check_f128() { - assert_biteq!(sqrt(100.0f128), 10.0); - assert_biteq!(sqrt(4.0f128), 2.0); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - #[allow(clippy::approx_constant)] - fn conformance_tests_f128() { - let cases = [ - (f128::PI, 0x3fffc5bf891b4ef6aa79c3b0520d5db9_u128), - // 10_000.0, see `f16` for reasoning. - ( - f128::from_bits(0x400c3880000000000000000000000000), - 0x40059000000000000000000000000000_u128, - ), - (f128::from_bits(0x0000000f), 0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128), - (f128::INFINITY, f128::INFINITY.to_bits()), - ]; - - for (input, output) in cases { - assert_biteq!( - sqrt(input), - f128::from_bits(output), - "input: {input:?} ({:#018x})", - input.to_bits() - ); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs deleted file mode 100644 index 25414ecf426..00000000000 --- a/library/compiler-builtins/libm/src/math/generic/trunc.rs +++ /dev/null @@ -1,138 +0,0 @@ -/* SPDX-License-Identifier: MIT - * origin: musl src/math/trunc.c */ - -use super::super::support::{FpResult, Status}; -use super::super::{Float, Int, IntTy, MinInt}; - -#[inline] -pub fn trunc(x: F) -> F { - trunc_status(x).val -} - -#[inline] -pub fn trunc_status(x: F) -> FpResult { - let mut xi: F::Int = x.to_bits(); - let e: i32 = x.exp_unbiased(); - - // C1: The represented value has no fractional part, so no truncation is needed - if e >= F::SIG_BITS as i32 { - return FpResult::ok(x); - } - - let mask = if e < 0 { - // C2: If the exponent is negative, the result will be zero so we mask out everything - // except the sign. - F::SIGN_MASK - } else { - // C3: Otherwise, we mask out the last `e` bits of the significand. - !(F::SIG_MASK >> e.unsigned()) - }; - - // C4: If the to-be-masked-out portion is already zero, we have an exact result - if (xi & !mask) == IntTy::::ZERO { - return FpResult::ok(x); - } - - // C5: Otherwise the result is inexact and we will truncate. Raise `FE_INEXACT`, mask the - // result, and return. - - let status = if xi & F::SIG_MASK == F::Int::ZERO { Status::OK } else { Status::INEXACT }; - xi &= mask; - FpResult::new(F::from_bits(xi), status) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; - - for x in roundtrip { - let FpResult { val, status } = trunc_status(x); - assert_biteq!(val, x, "{}", Hexf(x)); - assert_eq!(status, Status::OK, "{}", Hexf(x)); - } - - for &(x, res, res_stat) in cases { - let FpResult { val, status } = trunc_status(x); - assert_biteq!(val, res, "{}", Hexf(x)); - assert_eq!(status, res_stat, "{}", Hexf(x)); - } - } - - /* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */ - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - let cases = []; - spec_test::(&cases); - } - - #[test] - fn sanity_check_f32() { - assert_eq!(trunc(0.5f32), 0.0); - assert_eq!(trunc(1.1f32), 1.0); - assert_eq!(trunc(2.9f32), 2.0); - } - - #[test] - fn spec_tests_f32() { - let cases = [ - (0.1, 0.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 0.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 1.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); - - assert_biteq!(trunc(1.1f32), 1.0); - assert_biteq!(trunc(1.1f64), 1.0); - - // C1 - assert_biteq!(trunc(hf32!("0x1p23")), hf32!("0x1p23")); - assert_biteq!(trunc(hf64!("0x1p52")), hf64!("0x1p52")); - assert_biteq!(trunc(hf32!("-0x1p23")), hf32!("-0x1p23")); - assert_biteq!(trunc(hf64!("-0x1p52")), hf64!("-0x1p52")); - - // C2 - assert_biteq!(trunc(hf32!("0x1p-1")), 0.0); - assert_biteq!(trunc(hf64!("0x1p-1")), 0.0); - assert_biteq!(trunc(hf32!("-0x1p-1")), -0.0); - assert_biteq!(trunc(hf64!("-0x1p-1")), -0.0); - } - - #[test] - fn sanity_check_f64() { - assert_eq!(trunc(1.1f64), 1.0); - assert_eq!(trunc(2.9f64), 2.0); - } - - #[test] - fn spec_tests_f64() { - let cases = [ - (0.1, 0.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 0.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 1.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - let cases = []; - spec_test::(&cases); - } -} diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs deleted file mode 100644 index da458ea1d05..00000000000 --- a/library/compiler-builtins/libm/src/math/hypot.rs +++ /dev/null @@ -1,74 +0,0 @@ -use core::f64; - -use super::sqrt; - -const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 - -fn sq(x: f64) -> (f64, f64) { - let xh: f64; - let xl: f64; - let xc: f64; - - xc = x * SPLIT; - xh = x - xc + xc; - xl = x - xh; - let hi = x * x; - let lo = xh * xh - hi + 2. * xh * xl + xl * xl; - (hi, lo) -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn hypot(mut x: f64, mut y: f64) -> f64 { - let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700 - let x1p_700 = f64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700 - - let mut uxi = x.to_bits(); - let mut uyi = y.to_bits(); - let uti; - let ex: i64; - let ey: i64; - let mut z: f64; - - /* arrange |x| >= |y| */ - uxi &= -1i64 as u64 >> 1; - uyi &= -1i64 as u64 >> 1; - if uxi < uyi { - uti = uxi; - uxi = uyi; - uyi = uti; - } - - /* special cases */ - ex = (uxi >> 52) as i64; - ey = (uyi >> 52) as i64; - x = f64::from_bits(uxi); - y = f64::from_bits(uyi); - /* note: hypot(inf,nan) == inf */ - if ey == 0x7ff { - return y; - } - if ex == 0x7ff || uyi == 0 { - return x; - } - /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ - /* 64 difference is enough for ld80 double_t */ - if ex - ey > 64 { - return x + y; - } - - /* precise sqrt argument in nearest rounding mode without overflow */ - /* xh*xh must not overflow and xl*xl must not underflow in sq */ - z = 1.; - if ex > 0x3ff + 510 { - z = x1p700; - x *= x1p_700; - y *= x1p_700; - } else if ey < 0x3ff - 450 { - z = x1p_700; - x *= x1p700; - y *= x1p700; - } - let (hx, lx) = sq(x); - let (hy, ly) = sq(y); - z * sqrt(ly + lx + hy + hx) -} diff --git a/library/compiler-builtins/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/src/math/hypotf.rs deleted file mode 100644 index 576eebb3343..00000000000 --- a/library/compiler-builtins/libm/src/math/hypotf.rs +++ /dev/null @@ -1,43 +0,0 @@ -use core::f32; - -use super::sqrtf; - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn hypotf(mut x: f32, mut y: f32) -> f32 { - let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90 - let x1p_90 = f32::from_bits(0x12800000); // 0x1p-90f === 2 ^ -90 - - let mut uxi = x.to_bits(); - let mut uyi = y.to_bits(); - let uti; - let mut z: f32; - - uxi &= -1i32 as u32 >> 1; - uyi &= -1i32 as u32 >> 1; - if uxi < uyi { - uti = uxi; - uxi = uyi; - uyi = uti; - } - - x = f32::from_bits(uxi); - y = f32::from_bits(uyi); - if uyi == 0xff << 23 { - return y; - } - if uxi >= 0xff << 23 || uyi == 0 || uxi - uyi >= 25 << 23 { - return x + y; - } - - z = 1.; - if uxi >= (0x7f + 60) << 23 { - z = x1p90; - x *= x1p_90; - y *= x1p_90; - } else if uyi < (0x7f - 60) << 23 { - z = x1p_90; - x *= x1p90; - y *= x1p90; - } - z * sqrtf((x as f64 * x as f64 + y as f64 * y as f64) as f32) -} diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs deleted file mode 100644 index ccc4914be2b..00000000000 --- a/library/compiler-builtins/libm/src/math/ilogb.rs +++ /dev/null @@ -1,28 +0,0 @@ -const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; -const FP_ILOGB0: i32 = FP_ILOGBNAN; - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ilogb(x: f64) -> i32 { - let mut i: u64 = x.to_bits(); - let e = ((i >> 52) & 0x7ff) as i32; - - if e == 0 { - i <<= 12; - if i == 0 { - force_eval!(0.0 / 0.0); - return FP_ILOGB0; - } - /* subnormal x */ - let mut e = -0x3ff; - while (i >> 63) == 0 { - e -= 1; - i <<= 1; - } - e - } else if e == 0x7ff { - force_eval!(0.0 / 0.0); - if (i << 12) != 0 { FP_ILOGBNAN } else { i32::MAX } - } else { - e - 0x3ff - } -} diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs deleted file mode 100644 index 3585d6d36f1..00000000000 --- a/library/compiler-builtins/libm/src/math/ilogbf.rs +++ /dev/null @@ -1,28 +0,0 @@ -const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; -const FP_ILOGB0: i32 = FP_ILOGBNAN; - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ilogbf(x: f32) -> i32 { - let mut i = x.to_bits(); - let e = ((i >> 23) & 0xff) as i32; - - if e == 0 { - i <<= 9; - if i == 0 { - force_eval!(0.0 / 0.0); - return FP_ILOGB0; - } - /* subnormal x */ - let mut e = -0x7f; - while (i >> 31) == 0 { - e -= 1; - i <<= 1; - } - e - } else if e == 0xff { - force_eval!(0.0 / 0.0); - if (i << 9) != 0 { FP_ILOGBNAN } else { i32::MAX } - } else { - e - 0x7f - } -} diff --git a/library/compiler-builtins/libm/src/math/j0.rs b/library/compiler-builtins/libm/src/math/j0.rs deleted file mode 100644 index 99d656f0d08..00000000000 --- a/library/compiler-builtins/libm/src/math/j0.rs +++ /dev/null @@ -1,426 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* j0(x), y0(x) - * Bessel function of the first and second kinds of order zero. - * Method -- j0(x): - * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... - * 2. Reduce x to |x| since j0(x)=j0(-x), and - * for x in (0,2) - * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; - * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) - * for x in (2,inf) - * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) - * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) - * as follow: - * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) - * = 1/sqrt(2) * (cos(x) + sin(x)) - * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) - * = 1/sqrt(2) * (sin(x) - cos(x)) - * (To avoid cancellation, use - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - * to compute the worse one.) - * - * 3 Special cases - * j0(nan)= nan - * j0(0) = 1 - * j0(inf) = 0 - * - * Method -- y0(x): - * 1. For x<2. - * Since - * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) - * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. - * We use the following function to approximate y0, - * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 - * where - * U(z) = u00 + u01*z + ... + u06*z^6 - * V(z) = 1 + v01*z + ... + v04*z^4 - * with absolute approximation error bounded by 2**-72. - * Note: For tiny x, U/V = u0 and j0(x)~1, hence - * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) - * 2. For x>=2. - * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) - * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) - * by the method mentioned above. - * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. - */ - -use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ -const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ - -/* common method when |x|>=2 */ -fn common(ix: u32, x: f64, y0: bool) -> f64 { - let s: f64; - let mut c: f64; - let mut ss: f64; - let mut cc: f64; - let z: f64; - - /* - * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) - * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) - * - * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) - * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - */ - s = sin(x); - c = cos(x); - if y0 { - c = -c; - } - cc = s + c; - /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ - if ix < 0x7fe00000 { - ss = s - c; - z = -cos(2.0 * x); - if s * c < 0.0 { - cc = z / ss; - } else { - ss = z / cc; - } - if ix < 0x48000000 { - if y0 { - ss = -ss; - } - cc = pzero(x) * cc - qzero(x) * ss; - } - } - return INVSQRTPI * cc / sqrt(x); -} - -/* R0/S0 on [0, 2.00] */ -const R02: f64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ -const R03: f64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ -const R04: f64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ -const R05: f64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */ -const S01: f64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ -const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ -const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ -const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ - -/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn j0(mut x: f64) -> f64 { - let z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - - /* j0(+-inf)=0, j0(nan)=nan */ - if ix >= 0x7ff00000 { - return 1.0 / (x * x); - } - x = fabs(x); - - if ix >= 0x40000000 { - /* |x| >= 2 */ - /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ - return common(ix, x, false); - } - - /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ - if ix >= 0x3f200000 { - /* |x| >= 2**-13 */ - /* up to 4ulp error close to 2 */ - z = x * x; - r = z * (R02 + z * (R03 + z * (R04 + z * R05))); - s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); - return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); - } - - /* 1 - x*x/4 */ - /* prevent underflow */ - /* inexact should be raised when x!=0, this is not done correctly */ - if ix >= 0x38000000 { - /* |x| >= 2**-127 */ - x = 0.25 * x * x; - } - return 1.0 - x; -} - -const U00: f64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ -const U01: f64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ -const U02: f64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ -const U03: f64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */ -const U04: f64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */ -const U05: f64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */ -const U06: f64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */ -const V01: f64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ -const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ -const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ -const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ - -/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn y0(x: f64) -> f64 { - let z: f64; - let u: f64; - let v: f64; - let ix: u32; - let lx: u32; - - ix = get_high_word(x); - lx = get_low_word(x); - - /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ - if ((ix << 1) | lx) == 0 { - return -1.0 / 0.0; - } - if (ix >> 31) != 0 { - return 0.0 / 0.0; - } - if ix >= 0x7ff00000 { - return 1.0 / x; - } - - if ix >= 0x40000000 { - /* x >= 2 */ - /* large ulp errors near zeros: 3.958, 7.086,.. */ - return common(ix, x, true); - } - - /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ - if ix >= 0x3e400000 { - /* x >= 2**-27 */ - /* large ulp error near the first zero, x ~= 0.89 */ - z = x * x; - u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); - v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); - return u / v + TPI * (j0(x) * log(x)); - } - return U00 + TPI * log(x); -} - -/* The asymptotic expansions of pzero is - * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. - * For x >= 2, We approximate pzero by - * pzero(x) = 1 + (R/S) - * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 - * S = 1 + pS0*s^2 + ... + pS4*s^10 - * and - * | pzero(x)-1-R/S | <= 2 ** ( -60.26) - */ -const PR8: [f64; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ - -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ - -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ - -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ - -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ -]; -const PS8: [f64; 5] = [ - 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ - 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ - 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ - 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ - 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ -]; - -const PR5: [f64; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ - -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ - -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ - -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ - -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ - -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ -]; -const PS5: [f64; 5] = [ - 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ - 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ - 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ - 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ - 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ -]; - -const PR3: [f64; 6] = [ - /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ - -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ - -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ - -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ - -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ - -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ -]; -const PS3: [f64; 5] = [ - 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ - 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ - 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ - 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ - 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ -]; - -const PR2: [f64; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ - -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ - -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ - -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ - -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ - -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ -]; -const PS2: [f64; 5] = [ - 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ - 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ - 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ - 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ - 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ -]; - -fn pzero(x: f64) -> f64 { - let p: &[f64; 6]; - let q: &[f64; 5]; - let z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 { - p = &PR8; - q = &PS8; - } else if ix >= 0x40122E8B { - p = &PR5; - q = &PS5; - } else if ix >= 0x4006DB6D { - p = &PR3; - q = &PS3; - } else - /*ix >= 0x40000000*/ - { - p = &PR2; - q = &PS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); - return 1.0 + r / s; -} - -/* For x >= 8, the asymptotic expansions of qzero is - * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. - * We approximate pzero by - * qzero(x) = s*(-1.25 + (R/S)) - * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 - * S = 1 + qS0*s^2 + ... + qS5*s^12 - * and - * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) - */ -const QR8: [f64; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ - 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ - 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ - 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ - 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ -]; -const QS8: [f64; 6] = [ - 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ - 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ - 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ - 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ - 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ - -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ -]; - -const QR5: [f64; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ - 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ - 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ - 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ - 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ - 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ -]; -const QS5: [f64; 6] = [ - 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ - 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ - 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ - 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ - 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ - -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ -]; - -const QR3: [f64; 6] = [ - /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ - 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ - 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ - 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ - 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ - 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ -]; -const QS3: [f64; 6] = [ - 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ - 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ - 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ - 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ - 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ - -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ -]; - -const QR2: [f64; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ - 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ - 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ - 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ - 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ - 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ -]; -const QS2: [f64; 6] = [ - 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ - 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ - 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ - 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ - 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ - -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ -]; - -fn qzero(x: f64) -> f64 { - let p: &[f64; 6]; - let q: &[f64; 6]; - let s: f64; - let r: f64; - let z: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 { - p = &QR8; - q = &QS8; - } else if ix >= 0x40122E8B { - p = &QR5; - q = &QS5; - } else if ix >= 0x4006DB6D { - p = &QR3; - q = &QS3; - } else - /*ix >= 0x40000000*/ - { - p = &QR2; - q = &QS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); - return (-0.125 + r / s) / x; -} diff --git a/library/compiler-builtins/libm/src/math/j0f.rs b/library/compiler-builtins/libm/src/math/j0f.rs deleted file mode 100644 index 25e5b325c8c..00000000000 --- a/library/compiler-builtins/libm/src/math/j0f.rs +++ /dev/null @@ -1,363 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{cosf, fabsf, logf, sinf, sqrtf}; - -const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ -const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ - -fn common(ix: u32, x: f32, y0: bool) -> f32 { - let z: f32; - let s: f32; - let mut c: f32; - let mut ss: f32; - let mut cc: f32; - /* - * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) - * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) - */ - s = sinf(x); - c = cosf(x); - if y0 { - c = -c; - } - cc = s + c; - if ix < 0x7f000000 { - ss = s - c; - z = -cosf(2.0 * x); - if s * c < 0.0 { - cc = z / ss; - } else { - ss = z / cc; - } - if ix < 0x58800000 { - if y0 { - ss = -ss; - } - cc = pzerof(x) * cc - qzerof(x) * ss; - } - } - return INVSQRTPI * cc / sqrtf(x); -} - -/* R0/S0 on [0, 2.00] */ -const R02: f32 = 1.5625000000e-02; /* 0x3c800000 */ -const R03: f32 = -1.8997929874e-04; /* 0xb947352e */ -const R04: f32 = 1.8295404516e-06; /* 0x35f58e88 */ -const R05: f32 = -4.6183270541e-09; /* 0xb19eaf3c */ -const S01: f32 = 1.5619102865e-02; /* 0x3c7fe744 */ -const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ -const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ -const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ - -/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn j0f(mut x: f32) -> f32 { - let z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - return 1.0 / (x * x); - } - x = fabsf(x); - - if ix >= 0x40000000 { - /* |x| >= 2 */ - /* large ulp error near zeros */ - return common(ix, x, false); - } - if ix >= 0x3a000000 { - /* |x| >= 2**-11 */ - /* up to 4ulp error near 2 */ - z = x * x; - r = z * (R02 + z * (R03 + z * (R04 + z * R05))); - s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); - return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); - } - if ix >= 0x21800000 { - /* |x| >= 2**-60 */ - x = 0.25 * x * x; - } - return 1.0 - x; -} - -const U00: f32 = -7.3804296553e-02; /* 0xbd9726b5 */ -const U01: f32 = 1.7666645348e-01; /* 0x3e34e80d */ -const U02: f32 = -1.3818567619e-02; /* 0xbc626746 */ -const U03: f32 = 3.4745343146e-04; /* 0x39b62a69 */ -const U04: f32 = -3.8140706238e-06; /* 0xb67ff53c */ -const U05: f32 = 1.9559013964e-08; /* 0x32a802ba */ -const U06: f32 = -3.9820518410e-11; /* 0xae2f21eb */ -const V01: f32 = 1.2730483897e-02; /* 0x3c509385 */ -const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ -const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ -const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ - -/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn y0f(x: f32) -> f32 { - let z: f32; - let u: f32; - let v: f32; - let ix: u32; - - ix = x.to_bits(); - if (ix & 0x7fffffff) == 0 { - return -1.0 / 0.0; - } - if (ix >> 31) != 0 { - return 0.0 / 0.0; - } - if ix >= 0x7f800000 { - return 1.0 / x; - } - if ix >= 0x40000000 { - /* |x| >= 2.0 */ - /* large ulp error near zeros */ - return common(ix, x, true); - } - if ix >= 0x39000000 { - /* x >= 2**-13 */ - /* large ulp error at x ~= 0.89 */ - z = x * x; - u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); - v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); - return u / v + TPI * (j0f(x) * logf(x)); - } - return U00 + TPI * logf(x); -} - -/* The asymptotic expansions of pzero is - * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. - * For x >= 2, We approximate pzero by - * pzero(x) = 1 + (R/S) - * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 - * S = 1 + pS0*s^2 + ... + pS4*s^10 - * and - * | pzero(x)-1-R/S | <= 2 ** ( -60.26) - */ -const PR8: [f32; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - -7.0312500000e-02, /* 0xbd900000 */ - -8.0816707611e+00, /* 0xc1014e86 */ - -2.5706311035e+02, /* 0xc3808814 */ - -2.4852163086e+03, /* 0xc51b5376 */ - -5.2530439453e+03, /* 0xc5a4285a */ -]; -const PS8: [f32; 5] = [ - 1.1653436279e+02, /* 0x42e91198 */ - 3.8337448730e+03, /* 0x456f9beb */ - 4.0597855469e+04, /* 0x471e95db */ - 1.1675296875e+05, /* 0x47e4087c */ - 4.7627726562e+04, /* 0x473a0bba */ -]; -const PR5: [f32; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -1.1412546255e-11, /* 0xad48c58a */ - -7.0312492549e-02, /* 0xbd8fffff */ - -4.1596107483e+00, /* 0xc0851b88 */ - -6.7674766541e+01, /* 0xc287597b */ - -3.3123129272e+02, /* 0xc3a59d9b */ - -3.4643338013e+02, /* 0xc3ad3779 */ -]; -const PS5: [f32; 5] = [ - 6.0753936768e+01, /* 0x42730408 */ - 1.0512523193e+03, /* 0x44836813 */ - 5.9789707031e+03, /* 0x45bad7c4 */ - 9.6254453125e+03, /* 0x461665c8 */ - 2.4060581055e+03, /* 0x451660ee */ -]; - -const PR3: [f32; 6] = [ - /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - -2.5470459075e-09, /* 0xb12f081b */ - -7.0311963558e-02, /* 0xbd8fffb8 */ - -2.4090321064e+00, /* 0xc01a2d95 */ - -2.1965976715e+01, /* 0xc1afba52 */ - -5.8079170227e+01, /* 0xc2685112 */ - -3.1447946548e+01, /* 0xc1fb9565 */ -]; -const PS3: [f32; 5] = [ - 3.5856033325e+01, /* 0x420f6c94 */ - 3.6151397705e+02, /* 0x43b4c1ca */ - 1.1936077881e+03, /* 0x44953373 */ - 1.1279968262e+03, /* 0x448cffe6 */ - 1.7358093262e+02, /* 0x432d94b8 */ -]; - -const PR2: [f32; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -8.8753431271e-08, /* 0xb3be98b7 */ - -7.0303097367e-02, /* 0xbd8ffb12 */ - -1.4507384300e+00, /* 0xbfb9b1cc */ - -7.6356959343e+00, /* 0xc0f4579f */ - -1.1193166733e+01, /* 0xc1331736 */ - -3.2336456776e+00, /* 0xc04ef40d */ -]; -const PS2: [f32; 5] = [ - 2.2220300674e+01, /* 0x41b1c32d */ - 1.3620678711e+02, /* 0x430834f0 */ - 2.7047027588e+02, /* 0x43873c32 */ - 1.5387539673e+02, /* 0x4319e01a */ - 1.4657617569e+01, /* 0x416a859a */ -]; - -fn pzerof(x: f32) -> f32 { - let p: &[f32; 6]; - let q: &[f32; 5]; - let z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 { - p = &PR8; - q = &PS8; - } else if ix >= 0x409173eb { - p = &PR5; - q = &PS5; - } else if ix >= 0x4036d917 { - p = &PR3; - q = &PS3; - } else - /*ix >= 0x40000000*/ - { - p = &PR2; - q = &PS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); - return 1.0 + r / s; -} - -/* For x >= 8, the asymptotic expansions of qzero is - * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. - * We approximate pzero by - * qzero(x) = s*(-1.25 + (R/S)) - * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 - * S = 1 + qS0*s^2 + ... + qS5*s^12 - * and - * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) - */ -const QR8: [f32; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - 7.3242187500e-02, /* 0x3d960000 */ - 1.1768206596e+01, /* 0x413c4a93 */ - 5.5767340088e+02, /* 0x440b6b19 */ - 8.8591972656e+03, /* 0x460a6cca */ - 3.7014625000e+04, /* 0x471096a0 */ -]; -const QS8: [f32; 6] = [ - 1.6377603149e+02, /* 0x4323c6aa */ - 8.0983447266e+03, /* 0x45fd12c2 */ - 1.4253829688e+05, /* 0x480b3293 */ - 8.0330925000e+05, /* 0x49441ed4 */ - 8.4050156250e+05, /* 0x494d3359 */ - -3.4389928125e+05, /* 0xc8a7eb69 */ -]; - -const QR5: [f32; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.8408595828e-11, /* 0x2da1ec79 */ - 7.3242180049e-02, /* 0x3d95ffff */ - 5.8356351852e+00, /* 0x40babd86 */ - 1.3511157227e+02, /* 0x43071c90 */ - 1.0272437744e+03, /* 0x448067cd */ - 1.9899779053e+03, /* 0x44f8bf4b */ -]; -const QS5: [f32; 6] = [ - 8.2776611328e+01, /* 0x42a58da0 */ - 2.0778142090e+03, /* 0x4501dd07 */ - 1.8847289062e+04, /* 0x46933e94 */ - 5.6751113281e+04, /* 0x475daf1d */ - 3.5976753906e+04, /* 0x470c88c1 */ - -5.3543427734e+03, /* 0xc5a752be */ -]; - -const QR3: [f32; 6] = [ - /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - 4.3774099900e-09, /* 0x3196681b */ - 7.3241114616e-02, /* 0x3d95ff70 */ - 3.3442313671e+00, /* 0x405607e3 */ - 4.2621845245e+01, /* 0x422a7cc5 */ - 1.7080809021e+02, /* 0x432acedf */ - 1.6673394775e+02, /* 0x4326bbe4 */ -]; -const QS3: [f32; 6] = [ - 4.8758872986e+01, /* 0x42430916 */ - 7.0968920898e+02, /* 0x44316c1c */ - 3.7041481934e+03, /* 0x4567825f */ - 6.4604252930e+03, /* 0x45c9e367 */ - 2.5163337402e+03, /* 0x451d4557 */ - -1.4924745178e+02, /* 0xc3153f59 */ -]; - -const QR2: [f32; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.5044444979e-07, /* 0x342189db */ - 7.3223426938e-02, /* 0x3d95f62a */ - 1.9981917143e+00, /* 0x3fffc4bf */ - 1.4495602608e+01, /* 0x4167edfd */ - 3.1666231155e+01, /* 0x41fd5471 */ - 1.6252708435e+01, /* 0x4182058c */ -]; -const QS2: [f32; 6] = [ - 3.0365585327e+01, /* 0x41f2ecb8 */ - 2.6934811401e+02, /* 0x4386ac8f */ - 8.4478375244e+02, /* 0x44533229 */ - 8.8293585205e+02, /* 0x445cbbe5 */ - 2.1266638184e+02, /* 0x4354aa98 */ - -5.3109550476e+00, /* 0xc0a9f358 */ -]; - -fn qzerof(x: f32) -> f32 { - let p: &[f32; 6]; - let q: &[f32; 6]; - let s: f32; - let r: f32; - let z: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 { - p = &QR8; - q = &QS8; - } else if ix >= 0x409173eb { - p = &QR5; - q = &QS5; - } else if ix >= 0x4036d917 { - p = &QR3; - q = &QS3; - } else - /*ix >= 0x40000000*/ - { - p = &QR2; - q = &QS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); - return (-0.125 + r / s) / x; -} diff --git a/library/compiler-builtins/libm/src/math/j1.rs b/library/compiler-builtins/libm/src/math/j1.rs deleted file mode 100644 index 9b604d9e46e..00000000000 --- a/library/compiler-builtins/libm/src/math/j1.rs +++ /dev/null @@ -1,418 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* j1(x), y1(x) - * Bessel function of the first and second kinds of order zero. - * Method -- j1(x): - * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... - * 2. Reduce x to |x| since j1(x)=-j1(-x), and - * for x in (0,2) - * j1(x) = x/2 + x*z*R0/S0, where z = x*x; - * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) - * for x in (2,inf) - * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) - * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) - * as follow: - * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) - * = 1/sqrt(2) * (sin(x) - cos(x)) - * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) - * = -1/sqrt(2) * (sin(x) + cos(x)) - * (To avoid cancellation, use - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - * to compute the worse one.) - * - * 3 Special cases - * j1(nan)= nan - * j1(0) = 0 - * j1(inf) = 0 - * - * Method -- y1(x): - * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN - * 2. For x<2. - * Since - * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) - * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. - * We use the following function to approximate y1, - * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 - * where for x in [0,2] (abs err less than 2**-65.89) - * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 - * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 - * Note: For tiny x, 1/x dominate y1 and hence - * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) - * 3. For x>=2. - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) - * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) - * by method mentioned above. - */ - -use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; - -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ -const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ - -fn common(ix: u32, x: f64, y1: bool, sign: bool) -> f64 { - let z: f64; - let mut s: f64; - let c: f64; - let mut ss: f64; - let mut cc: f64; - - /* - * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) - * - * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) - * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - */ - s = sin(x); - if y1 { - s = -s; - } - c = cos(x); - cc = s - c; - if ix < 0x7fe00000 { - /* avoid overflow in 2*x */ - ss = -s - c; - z = cos(2.0 * x); - if s * c > 0.0 { - cc = z / ss; - } else { - ss = z / cc; - } - if ix < 0x48000000 { - if y1 { - ss = -ss; - } - cc = pone(x) * cc - qone(x) * ss; - } - } - if sign { - cc = -cc; - } - return INVSQRTPI * cc / sqrt(x); -} - -/* R0/S0 on [0,2] */ -const R00: f64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ -const R01: f64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ -const R02: f64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ -const R03: f64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ -const S01: f64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ -const S02: f64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ -const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ -const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ -const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ - -/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn j1(x: f64) -> f64 { - let mut z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - let sign: bool; - - ix = get_high_word(x); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - return 1.0 / (x * x); - } - if ix >= 0x40000000 { - /* |x| >= 2 */ - return common(ix, fabs(x), false, sign); - } - if ix >= 0x38000000 { - /* |x| >= 2**-127 */ - z = x * x; - r = z * (R00 + z * (R01 + z * (R02 + z * R03))); - s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); - z = r / s; - } else { - /* avoid underflow, raise inexact if x!=0 */ - z = x; - } - return (0.5 + z) * x; -} - -const U0: [f64; 5] = [ - -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ - 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ - -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ - 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ - -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ -]; -const V0: [f64; 5] = [ - 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ - 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ - 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ - 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ - 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ -]; - -/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn y1(x: f64) -> f64 { - let z: f64; - let u: f64; - let v: f64; - let ix: u32; - let lx: u32; - - ix = get_high_word(x); - lx = get_low_word(x); - - /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ - if (ix << 1) | lx == 0 { - return -1.0 / 0.0; - } - if ix >> 31 != 0 { - return 0.0 / 0.0; - } - if ix >= 0x7ff00000 { - return 1.0 / x; - } - - if ix >= 0x40000000 { - /* x >= 2 */ - return common(ix, x, true, false); - } - if ix < 0x3c900000 { - /* x < 2**-54 */ - return -TPI / x; - } - z = x * x; - u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); - v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); - return x * (u / v) + TPI * (j1(x) * log(x) - 1.0 / x); -} - -/* For x >= 8, the asymptotic expansions of pone is - * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. - * We approximate pone by - * pone(x) = 1 + (R/S) - * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 - * S = 1 + ps0*s^2 + ... + ps4*s^10 - * and - * | pone(x)-1-R/S | <= 2 ** ( -60.06) - */ - -const PR8: [f64; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ - 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ - 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ - 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ - 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ -]; -const PS8: [f64; 5] = [ - 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ - 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ - 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ - 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ - 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ -]; - -const PR5: [f64; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ - 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ - 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ - 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ - 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ - 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ -]; -const PS5: [f64; 5] = [ - 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ - 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ - 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ - 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ - 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ -]; - -const PR3: [f64; 6] = [ - 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ - 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ - 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ - 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ - 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ - 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ -]; -const PS3: [f64; 5] = [ - 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ - 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ - 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ - 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ - 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ -]; - -const PR2: [f64; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ - 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ - 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ - 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ - 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ - 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ -]; -const PS2: [f64; 5] = [ - 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ - 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ - 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ - 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ - 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ -]; - -fn pone(x: f64) -> f64 { - let p: &[f64; 6]; - let q: &[f64; 5]; - let z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 { - p = &PR8; - q = &PS8; - } else if ix >= 0x40122E8B { - p = &PR5; - q = &PS5; - } else if ix >= 0x4006DB6D { - p = &PR3; - q = &PS3; - } else - /*ix >= 0x40000000*/ - { - p = &PR2; - q = &PS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); - return 1.0 + r / s; -} - -/* For x >= 8, the asymptotic expansions of qone is - * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. - * We approximate pone by - * qone(x) = s*(0.375 + (R/S)) - * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 - * S = 1 + qs1*s^2 + ... + qs6*s^12 - * and - * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) - */ - -const QR8: [f64; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ - -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ - -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ - -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ - -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ -]; -const QS8: [f64; 6] = [ - 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ - 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ - 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ - 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ - 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ - -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ -]; - -const QR5: [f64; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ - -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ - -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ - -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ - -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ - -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ -]; -const QS5: [f64; 6] = [ - 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ - 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ - 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ - 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ - 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ - -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ -]; - -const QR3: [f64; 6] = [ - -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ - -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ - -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ - -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ - -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ - -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ -]; -const QS3: [f64; 6] = [ - 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ - 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ - 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ - 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ - 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ - -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ -]; - -const QR2: [f64; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ - -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ - -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ - -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ - -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ - -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ -]; -const QS2: [f64; 6] = [ - 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ - 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ - 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ - 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ - 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ - -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ -]; - -fn qone(x: f64) -> f64 { - let p: &[f64; 6]; - let q: &[f64; 6]; - let s: f64; - let r: f64; - let z: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 { - p = &QR8; - q = &QS8; - } else if ix >= 0x40122E8B { - p = &QR5; - q = &QS5; - } else if ix >= 0x4006DB6D { - p = &QR3; - q = &QS3; - } else - /*ix >= 0x40000000*/ - { - p = &QR2; - q = &QS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); - return (0.375 + r / s) / x; -} diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs deleted file mode 100644 index a47472401ee..00000000000 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ /dev/null @@ -1,384 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{cosf, fabsf, logf, sinf, sqrtf}; - -const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ -const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ - -fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 { - let z: f64; - let mut s: f64; - let c: f64; - let mut ss: f64; - let mut cc: f64; - - s = sinf(x) as f64; - if y1 { - s = -s; - } - c = cosf(x) as f64; - cc = s - c; - if ix < 0x7f000000 { - ss = -s - c; - z = cosf(2.0 * x) as f64; - if s * c > 0.0 { - cc = z / ss; - } else { - ss = z / cc; - } - if ix < 0x58800000 { - if y1 { - ss = -ss; - } - cc = (ponef(x) as f64) * cc - (qonef(x) as f64) * ss; - } - } - if sign { - cc = -cc; - } - return (((INVSQRTPI as f64) * cc) / (sqrtf(x) as f64)) as f32; -} - -/* R0/S0 on [0,2] */ -const R00: f32 = -6.2500000000e-02; /* 0xbd800000 */ -const R01: f32 = 1.4070566976e-03; /* 0x3ab86cfd */ -const R02: f32 = -1.5995563444e-05; /* 0xb7862e36 */ -const R03: f32 = 4.9672799207e-08; /* 0x335557d2 */ -const S01: f32 = 1.9153760746e-02; /* 0x3c9ce859 */ -const S02: f32 = 1.8594678841e-04; /* 0x3942fab6 */ -const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ -const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ -const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ - -/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn j1f(x: f32) -> f32 { - let mut z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - let sign: bool; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - return 1.0 / (x * x); - } - if ix >= 0x40000000 { - /* |x| >= 2 */ - return common(ix, fabsf(x), false, sign); - } - if ix >= 0x39000000 { - /* |x| >= 2**-13 */ - z = x * x; - r = z * (R00 + z * (R01 + z * (R02 + z * R03))); - s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); - z = 0.5 + r / s; - } else { - z = 0.5; - } - return z * x; -} - -const U0: [f32; 5] = [ - -1.9605709612e-01, /* 0xbe48c331 */ - 5.0443872809e-02, /* 0x3d4e9e3c */ - -1.9125689287e-03, /* 0xbafaaf2a */ - 2.3525259166e-05, /* 0x37c5581c */ - -9.1909917899e-08, /* 0xb3c56003 */ -]; -const V0: [f32; 5] = [ - 1.9916731864e-02, /* 0x3ca3286a */ - 2.0255257550e-04, /* 0x3954644b */ - 1.3560879779e-06, /* 0x35b602d4 */ - 6.2274145840e-09, /* 0x31d5f8eb */ - 1.6655924903e-11, /* 0x2d9281cf */ -]; - -/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn y1f(x: f32) -> f32 { - let z: f32; - let u: f32; - let v: f32; - let ix: u32; - - ix = x.to_bits(); - if (ix & 0x7fffffff) == 0 { - return -1.0 / 0.0; - } - if (ix >> 31) != 0 { - return 0.0 / 0.0; - } - if ix >= 0x7f800000 { - return 1.0 / x; - } - if ix >= 0x40000000 { - /* |x| >= 2.0 */ - return common(ix, x, true, false); - } - if ix < 0x33000000 { - /* x < 2**-25 */ - return -TPI / x; - } - z = x * x; - u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); - v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); - return x * (u / v) + TPI * (j1f(x) * logf(x) - 1.0 / x); -} - -/* For x >= 8, the asymptotic expansions of pone is - * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. - * We approximate pone by - * pone(x) = 1 + (R/S) - * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 - * S = 1 + ps0*s^2 + ... + ps4*s^10 - * and - * | pone(x)-1-R/S | <= 2 ** ( -60.06) - */ - -const PR8: [f32; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - 1.1718750000e-01, /* 0x3df00000 */ - 1.3239480972e+01, /* 0x4153d4ea */ - 4.1205184937e+02, /* 0x43ce06a3 */ - 3.8747453613e+03, /* 0x45722bed */ - 7.9144794922e+03, /* 0x45f753d6 */ -]; -const PS8: [f32; 5] = [ - 1.1420736694e+02, /* 0x42e46a2c */ - 3.6509309082e+03, /* 0x45642ee5 */ - 3.6956207031e+04, /* 0x47105c35 */ - 9.7602796875e+04, /* 0x47bea166 */ - 3.0804271484e+04, /* 0x46f0a88b */ -]; - -const PR5: [f32; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.3199052094e-11, /* 0x2d68333f */ - 1.1718749255e-01, /* 0x3defffff */ - 6.8027510643e+00, /* 0x40d9b023 */ - 1.0830818176e+02, /* 0x42d89dca */ - 5.1763616943e+02, /* 0x440168b7 */ - 5.2871520996e+02, /* 0x44042dc6 */ -]; -const PS5: [f32; 5] = [ - 5.9280597687e+01, /* 0x426d1f55 */ - 9.9140142822e+02, /* 0x4477d9b1 */ - 5.3532670898e+03, /* 0x45a74a23 */ - 7.8446904297e+03, /* 0x45f52586 */ - 1.5040468750e+03, /* 0x44bc0180 */ -]; - -const PR3: [f32; 6] = [ - 3.0250391081e-09, /* 0x314fe10d */ - 1.1718686670e-01, /* 0x3defffab */ - 3.9329774380e+00, /* 0x407bb5e7 */ - 3.5119403839e+01, /* 0x420c7a45 */ - 9.1055007935e+01, /* 0x42b61c2a */ - 4.8559066772e+01, /* 0x42423c7c */ -]; -const PS3: [f32; 5] = [ - 3.4791309357e+01, /* 0x420b2a4d */ - 3.3676245117e+02, /* 0x43a86198 */ - 1.0468714600e+03, /* 0x4482dbe3 */ - 8.9081134033e+02, /* 0x445eb3ed */ - 1.0378793335e+02, /* 0x42cf936c */ -]; - -const PR2: [f32; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.0771083225e-07, /* 0x33e74ea8 */ - 1.1717621982e-01, /* 0x3deffa16 */ - 2.3685150146e+00, /* 0x401795c0 */ - 1.2242610931e+01, /* 0x4143e1bc */ - 1.7693971634e+01, /* 0x418d8d41 */ - 5.0735230446e+00, /* 0x40a25a4d */ -]; -const PS2: [f32; 5] = [ - 2.1436485291e+01, /* 0x41ab7dec */ - 1.2529022980e+02, /* 0x42fa9499 */ - 2.3227647400e+02, /* 0x436846c7 */ - 1.1767937469e+02, /* 0x42eb5bd7 */ - 8.3646392822e+00, /* 0x4105d590 */ -]; - -fn ponef(x: f32) -> f32 { - let p: &[f32; 6]; - let q: &[f32; 5]; - let z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 { - p = &PR8; - q = &PS8; - } else if ix >= 0x409173eb { - p = &PR5; - q = &PS5; - } else if ix >= 0x4036d917 { - p = &PR3; - q = &PS3; - } else - /*ix >= 0x40000000*/ - { - p = &PR2; - q = &PS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); - return 1.0 + r / s; -} - -/* For x >= 8, the asymptotic expansions of qone is - * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. - * We approximate pone by - * qone(x) = s*(0.375 + (R/S)) - * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 - * S = 1 + qs1*s^2 + ... + qs6*s^12 - * and - * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) - */ - -const QR8: [f32; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - -1.0253906250e-01, /* 0xbdd20000 */ - -1.6271753311e+01, /* 0xc1822c8d */ - -7.5960174561e+02, /* 0xc43de683 */ - -1.1849806641e+04, /* 0xc639273a */ - -4.8438511719e+04, /* 0xc73d3683 */ -]; -const QS8: [f32; 6] = [ - 1.6139537048e+02, /* 0x43216537 */ - 7.8253862305e+03, /* 0x45f48b17 */ - 1.3387534375e+05, /* 0x4802bcd6 */ - 7.1965775000e+05, /* 0x492fb29c */ - 6.6660125000e+05, /* 0x4922be94 */ - -2.9449025000e+05, /* 0xc88fcb48 */ -]; - -const QR5: [f32; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -2.0897993405e-11, /* 0xadb7d219 */ - -1.0253904760e-01, /* 0xbdd1fffe */ - -8.0564479828e+00, /* 0xc100e736 */ - -1.8366960144e+02, /* 0xc337ab6b */ - -1.3731937256e+03, /* 0xc4aba633 */ - -2.6124443359e+03, /* 0xc523471c */ -]; -const QS5: [f32; 6] = [ - 8.1276550293e+01, /* 0x42a28d98 */ - 1.9917987061e+03, /* 0x44f8f98f */ - 1.7468484375e+04, /* 0x468878f8 */ - 4.9851425781e+04, /* 0x4742bb6d */ - 2.7948074219e+04, /* 0x46da5826 */ - -4.7191835938e+03, /* 0xc5937978 */ -]; - -const QR3: [f32; 6] = [ - -5.0783124372e-09, /* 0xb1ae7d4f */ - -1.0253783315e-01, /* 0xbdd1ff5b */ - -4.6101160049e+00, /* 0xc0938612 */ - -5.7847221375e+01, /* 0xc267638e */ - -2.2824453735e+02, /* 0xc3643e9a */ - -2.1921012878e+02, /* 0xc35b35cb */ -]; -const QS3: [f32; 6] = [ - 4.7665153503e+01, /* 0x423ea91e */ - 6.7386511230e+02, /* 0x4428775e */ - 3.3801528320e+03, /* 0x45534272 */ - 5.5477290039e+03, /* 0x45ad5dd5 */ - 1.9031191406e+03, /* 0x44ede3d0 */ - -1.3520118713e+02, /* 0xc3073381 */ -]; - -const QR2: [f32; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -1.7838172539e-07, /* 0xb43f8932 */ - -1.0251704603e-01, /* 0xbdd1f475 */ - -2.7522056103e+00, /* 0xc0302423 */ - -1.9663616180e+01, /* 0xc19d4f16 */ - -4.2325313568e+01, /* 0xc2294d1f */ - -2.1371921539e+01, /* 0xc1aaf9b2 */ -]; -const QS2: [f32; 6] = [ - 2.9533363342e+01, /* 0x41ec4454 */ - 2.5298155212e+02, /* 0x437cfb47 */ - 7.5750280762e+02, /* 0x443d602e */ - 7.3939318848e+02, /* 0x4438d92a */ - 1.5594900513e+02, /* 0x431bf2f2 */ - -4.9594988823e+00, /* 0xc09eb437 */ -]; - -fn qonef(x: f32) -> f32 { - let p: &[f32; 6]; - let q: &[f32; 6]; - let s: f32; - let r: f32; - let z: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 { - p = &QR8; - q = &QS8; - } else if ix >= 0x409173eb { - p = &QR5; - q = &QS5; - } else if ix >= 0x4036d917 { - p = &QR3; - q = &QS3; - } else - /*ix >= 0x40000000*/ - { - p = &QR2; - q = &QS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); - return (0.375 + r / s) / x; -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::{j1f, y1f}; - #[test] - fn test_j1f_2488() { - // 0x401F3E49 - assert_eq!(j1f(2.4881766_f32), 0.49999475_f32); - } - #[test] - fn test_y1f_2002() { - //allow slightly different result on x87 - let res = y1f(2.0000002_f32); - if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && (res == -0.10703231_f32) - { - return; - } - assert_eq!(res, -0.10703229_f32); - } -} diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs deleted file mode 100644 index 31f8d9c5382..00000000000 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ /dev/null @@ -1,339 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* - * jn(n, x), yn(n, x) - * floating point Bessel's function of the 1st and 2nd kind - * of order n - * - * Special cases: - * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; - * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. - * Note 2. About jn(n,x), yn(n,x) - * For n=0, j0(x) is called, - * for n=1, j1(x) is called, - * for n<=x, forward recursion is used starting - * from values of j0(x) and j1(x). - * for n>x, a continued fraction approximation to - * j(n,x)/j(n-1,x) is evaluated and then backward - * recursion is used starting from a supposed value - * for j(n,x). The resulting value of j(0,x) is - * compared with the actual value to correct the - * supposed value of j(n,x). - * - * yn(n,x) is similar in all respects, except - * that forward recursion is used for all - * values of n>1. - */ - -use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, y1}; - -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ - -/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn jn(n: i32, mut x: f64) -> f64 { - let mut ix: u32; - let lx: u32; - let nm1: i32; - let mut i: i32; - let mut sign: bool; - let mut a: f64; - let mut b: f64; - let mut temp: f64; - - ix = get_high_word(x); - lx = get_low_word(x); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - // -lx == !lx + 1 - if ix | ((lx | (!lx).wrapping_add(1)) >> 31) > 0x7ff00000 { - /* nan */ - return x; - } - - /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) - * Thus, J(-n,x) = J(n,-x) - */ - /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ - if n == 0 { - return j0(x); - } - if n < 0 { - nm1 = -(n + 1); - x = -x; - sign = !sign; - } else { - nm1 = n - 1; - } - if nm1 == 0 { - return j1(x); - } - - sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ - x = fabs(x); - if (ix | lx) == 0 || ix == 0x7ff00000 { - /* if x is 0 or inf */ - b = 0.0; - } else if (nm1 as f64) < x { - /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ - if ix >= 0x52d00000 { - /* x > 2**302 */ - /* (x >> n**2) - * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Let s=sin(x), c=cos(x), - * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then - * - * n sin(xn)*sqt2 cos(xn)*sqt2 - * ---------------------------------- - * 0 s-c c+s - * 1 -s-c -c+s - * 2 -s+c -c-s - * 3 s+c c-s - */ - temp = match nm1 & 3 { - 0 => -cos(x) + sin(x), - 1 => -cos(x) - sin(x), - 2 => cos(x) - sin(x), - // 3 - _ => cos(x) + sin(x), - }; - b = INVSQRTPI * temp / sqrt(x); - } else { - a = j0(x); - b = j1(x); - i = 0; - while i < nm1 { - i += 1; - temp = b; - b = b * (2.0 * (i as f64) / x) - a; /* avoid underflow */ - a = temp; - } - } - } else if ix < 0x3e100000 { - /* x < 2**-29 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 32 { - /* underflow */ - b = 0.0; - } else { - temp = x * 0.5; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as f64; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } - } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: f64; - let mut q0: f64; - let mut q1: f64; - let mut w: f64; - let h: f64; - let mut z: f64; - let mut tmp: f64; - let nf: f64; - - let mut k: i32; - - nf = (nm1 as f64) + 1.0; - w = 2.0 * nf / x; - h = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e9 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as f64) + nf) / x - t); - i -= 1; - } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf * log(fabs(w)); - if tmp < 7.09782712893383973096e+02 { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as f64)) / x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as f64)) / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 - if b > x1p500 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; - } - } - z = j0(x); - w = j1(x); - if fabs(z) >= fabs(w) { - b = t * z / b; - } else { - b = t * w / a; - } - } - - if sign { -b } else { b } -} - -/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn yn(n: i32, x: f64) -> f64 { - let mut ix: u32; - let lx: u32; - let mut ib: u32; - let nm1: i32; - let mut sign: bool; - let mut i: i32; - let mut a: f64; - let mut b: f64; - let mut temp: f64; - - ix = get_high_word(x); - lx = get_low_word(x); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - // -lx == !lx + 1 - if ix | ((lx | (!lx).wrapping_add(1)) >> 31) > 0x7ff00000 { - /* nan */ - return x; - } - if sign && (ix | lx) != 0 { - /* x < 0 */ - return 0.0 / 0.0; - } - if ix == 0x7ff00000 { - return 0.0; - } - - if n == 0 { - return y0(x); - } - if n < 0 { - nm1 = -(n + 1); - sign = (n & 1) != 0; - } else { - nm1 = n - 1; - sign = false; - } - if nm1 == 0 { - if sign { - return -y1(x); - } else { - return y1(x); - } - } - - if ix >= 0x52d00000 { - /* x > 2**302 */ - /* (x >> n**2) - * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Let s=sin(x), c=cos(x), - * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then - * - * n sin(xn)*sqt2 cos(xn)*sqt2 - * ---------------------------------- - * 0 s-c c+s - * 1 -s-c -c+s - * 2 -s+c -c-s - * 3 s+c c-s - */ - temp = match nm1 & 3 { - 0 => -sin(x) - cos(x), - 1 => -sin(x) + cos(x), - 2 => sin(x) + cos(x), - // 3 - _ => sin(x) - cos(x), - }; - b = INVSQRTPI * temp / sqrt(x); - } else { - a = y0(x); - b = y1(x); - /* quit if b is -inf */ - ib = get_high_word(b); - i = 0; - while i < nm1 && ib != 0xfff00000 { - i += 1; - temp = b; - b = (2.0 * (i as f64) / x) * b - a; - ib = get_high_word(b); - a = temp; - } - } - - if sign { -b } else { b } -} diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs deleted file mode 100644 index 52cf7d8a8bd..00000000000 --- a/library/compiler-builtins/libm/src/math/jnf.rs +++ /dev/null @@ -1,253 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{fabsf, j0f, j1f, logf, y0f, y1f}; - -/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn jnf(n: i32, mut x: f32) -> f32 { - let mut ix: u32; - let mut nm1: i32; - let mut sign: bool; - let mut i: i32; - let mut a: f32; - let mut b: f32; - let mut temp: f32; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - if ix > 0x7f800000 { - /* nan */ - return x; - } - - /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ - if n == 0 { - return j0f(x); - } - if n < 0 { - nm1 = -(n + 1); - x = -x; - sign = !sign; - } else { - nm1 = n - 1; - } - if nm1 == 0 { - return j1f(x); - } - - sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ - x = fabsf(x); - if ix == 0 || ix == 0x7f800000 { - /* if x is 0 or inf */ - b = 0.0; - } else if (nm1 as f32) < x { - /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ - a = j0f(x); - b = j1f(x); - i = 0; - while i < nm1 { - i += 1; - temp = b; - b = b * (2.0 * (i as f32) / x) - a; - a = temp; - } - } else if ix < 0x35800000 { - /* x < 2**-20 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 8 { - /* underflow */ - nm1 = 8; - } - temp = 0.5 * x; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as f32; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: f32; - let mut q0: f32; - let mut q1: f32; - let mut w: f32; - let h: f32; - let mut z: f32; - let mut tmp: f32; - let nf: f32; - let mut k: i32; - - nf = (nm1 as f32) + 1.0; - w = 2.0 * nf / x; - h = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e4 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as f32) + nf) / x - t); - i -= 1; - } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf * logf(fabsf(w)); - if tmp < 88.721679688 { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as f32) * b / x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as f32) * b / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 - if b > x1p60 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; - } - } - z = j0f(x); - w = j1f(x); - if fabsf(z) >= fabsf(w) { - b = t * z / b; - } else { - b = t * w / a; - } - } - - if sign { -b } else { b } -} - -/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ynf(n: i32, x: f32) -> f32 { - let mut ix: u32; - let mut ib: u32; - let nm1: i32; - let mut sign: bool; - let mut i: i32; - let mut a: f32; - let mut b: f32; - let mut temp: f32; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - if ix > 0x7f800000 { - /* nan */ - return x; - } - if sign && ix != 0 { - /* x < 0 */ - return 0.0 / 0.0; - } - if ix == 0x7f800000 { - return 0.0; - } - - if n == 0 { - return y0f(x); - } - if n < 0 { - nm1 = -(n + 1); - sign = (n & 1) != 0; - } else { - nm1 = n - 1; - sign = false; - } - if nm1 == 0 { - if sign { - return -y1f(x); - } else { - return y1f(x); - } - } - - a = y0f(x); - b = y1f(x); - /* quit if b is -inf */ - ib = b.to_bits(); - i = 0; - while i < nm1 && ib != 0xff800000 { - i += 1; - temp = b; - b = (2.0 * (i as f32) / x) * b - a; - ib = b.to_bits(); - a = temp; - } - - if sign { -b } else { b } -} diff --git a/library/compiler-builtins/libm/src/math/k_cos.rs b/library/compiler-builtins/libm/src/math/k_cos.rs deleted file mode 100644 index 49b2fc64d86..00000000000 --- a/library/compiler-builtins/libm/src/math/k_cos.rs +++ /dev/null @@ -1,62 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/k_cos.c -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunSoft, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -const C1: f64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ -const C2: f64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ -const C3: f64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ -const C4: f64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ -const C5: f64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ -const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ - -// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 -// Input x is assumed to be bounded by ~pi/4 in magnitude. -// Input y is the tail of x. -// -// Algorithm -// 1. Since cos(-x) = cos(x), we need only to consider positive x. -// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. -// 3. cos(x) is approximated by a polynomial of degree 14 on -// [0,pi/4] -// 4 14 -// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x -// where the remez error is -// -// | 2 4 6 8 10 12 14 | -58 -// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 -// | | -// -// 4 6 8 10 12 14 -// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then -// cos(x) ~ 1 - x*x/2 + r -// since cos(x+y) ~ cos(x) - sin(x)*y -// ~ cos(x) - x*y, -// a correction term is necessary in cos(x) and hence -// cos(x+y) = 1 - (x*x/2 - (r - x*y)) -// For better accuracy, rearrange to -// cos(x+y) ~ w + (tmp + (r-x*y)) -// where w = 1 - x*x/2 and tmp is a tiny correction term -// (1 - x*x/2 == w + tmp exactly in infinite precision). -// The exactness of w + tmp in infinite precision depends on w -// and tmp having the same precision as x. If they have extra -// precision due to compiler bugs, then the extra precision is -// only good provided it is retained in all terms of the final -// expression for cos(). Retention happens in all cases tested -// under FreeBSD, so don't pessimize things by forcibly clipping -// any extra precision in w. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_cos(x: f64, y: f64) -> f64 { - let z = x * x; - let w = z * z; - let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); - let hz = 0.5 * z; - let w = 1.0 - hz; - w + (((1.0 - w) - hz) + (z * r - x * y)) -} diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs deleted file mode 100644 index e99f2348c00..00000000000 --- a/library/compiler-builtins/libm/src/math/k_cosf.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Debugged and optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ -const C0: f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ -const C1: f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ -const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ -const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_cosf(x: f64) -> f32 { - let z = x * x; - let w = z * z; - let r = C2 + z * C3; - (((1.0 + z * C0) + w * C1) + (w * z) * r) as f32 -} diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs deleted file mode 100644 index 7345075f376..00000000000 --- a/library/compiler-builtins/libm/src/math/k_expo2.rs +++ /dev/null @@ -1,14 +0,0 @@ -use super::exp; - -/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ -const K: i32 = 2043; - -/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_expo2(x: f64) -> f64 { - let k_ln2 = f64::from_bits(0x40962066151add8b); - /* note that k is odd and scale*scale overflows */ - let scale = f64::from_bits(((((0x3ff + K / 2) as u32) << 20) as u64) << 32); - /* exp(x - k ln2) * 2**(k-1) */ - exp(x - k_ln2) * scale * scale -} diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs deleted file mode 100644 index fbd7b27d583..00000000000 --- a/library/compiler-builtins/libm/src/math/k_expo2f.rs +++ /dev/null @@ -1,14 +0,0 @@ -use super::expf; - -/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ -const K: i32 = 235; - -/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_expo2f(x: f32) -> f32 { - let k_ln2 = f32::from_bits(0x4322e3bc); - /* note that k is odd and scale*scale overflows */ - let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); - /* exp(x - k ln2) * 2**(k-1) */ - expf(x - k_ln2) * scale * scale -} diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs deleted file mode 100644 index 42441455ff3..00000000000 --- a/library/compiler-builtins/libm/src/math/k_sin.rs +++ /dev/null @@ -1,53 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/k_sin.c -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunSoft, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -const S1: f64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ -const S2: f64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ -const S3: f64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ -const S4: f64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ -const S5: f64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ -const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ - -// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 -// Input x is assumed to be bounded by ~pi/4 in magnitude. -// Input y is the tail of x. -// Input iy indicates whether y is 0. (if iy=0, y assume to be 0). -// -// Algorithm -// 1. Since sin(-x) = -sin(x), we need only to consider positive x. -// 2. Callers must return sin(-0) = -0 without calling here since our -// odd polynomial is not evaluated in a way that preserves -0. -// Callers may do the optimization sin(x) ~ x for tiny x. -// 3. sin(x) is approximated by a polynomial of degree 13 on -// [0,pi/4] -// 3 13 -// sin(x) ~ x + S1*x + ... + S6*x -// where -// -// |sin(x) 2 4 6 8 10 12 | -58 -// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 -// | x | -// -// 4. sin(x+y) = sin(x) + sin'(x')*y -// ~ sin(x) + (1-x*x/2)*y -// For better accuracy, let -// 3 2 2 2 2 -// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) -// then 3 2 -// sin(x) = x + (S1*x + (x *(r-y/2)+y)) -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { - let z = x * x; - let w = z * z; - let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); - let v = z * x; - if iy == 0 { x + v * (S1 + z * r) } else { x - ((z * (0.5 * y - v * r) - y) - v * S1) } -} diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs deleted file mode 100644 index 88d10cababc..00000000000 --- a/library/compiler-builtins/libm/src/math/k_sinf.rs +++ /dev/null @@ -1,30 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ -const S1: f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ -const S2: f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ -const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ -const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_sinf(x: f64) -> f32 { - let z = x * x; - let w = z * z; - let r = S3 + z * S4; - let s = z * x; - ((x + s * (S1 + z * S2)) + s * w * r) as f32 -} diff --git a/library/compiler-builtins/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/src/math/k_tan.rs deleted file mode 100644 index d177010bb0a..00000000000 --- a/library/compiler-builtins/libm/src/math/k_tan.rs +++ /dev/null @@ -1,105 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ -// -// ==================================================== -// Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. -// -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -// kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 -// Input x is assumed to be bounded by ~pi/4 in magnitude. -// Input y is the tail of x. -// Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. -// -// Algorithm -// 1. Since tan(-x) = -tan(x), we need only to consider positive x. -// 2. Callers must return tan(-0) = -0 without calling here since our -// odd polynomial is not evaluated in a way that preserves -0. -// Callers may do the optimization tan(x) ~ x for tiny x. -// 3. tan(x) is approximated by a odd polynomial of degree 27 on -// [0,0.67434] -// 3 27 -// tan(x) ~ x + T1*x + ... + T13*x -// where -// -// |tan(x) 2 4 26 | -59.2 -// |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 -// | x | -// -// Note: tan(x+y) = tan(x) + tan'(x)*y -// ~ tan(x) + (1+x*x)*y -// Therefore, for better accuracy in computing tan(x+y), let -// 3 2 2 2 2 -// r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) -// then -// 3 2 -// tan(x+y) = x + (T1*x + (x *(r+y)+y)) -// -// 4. For x in [0.67434,pi/4], let y = pi/4 - x, then -// tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) -// = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) -static T: [f64; 13] = [ - 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ - 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ - 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ - 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ - 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ - 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ - 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ - 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ - 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ - 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ - 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ - -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ - 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ -]; -const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ -const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { - let hx = (f64::to_bits(x) >> 32) as u32; - let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ - if big { - let sign = hx >> 31; - if sign != 0 { - x = -x; - y = -y; - } - x = (PIO4 - x) + (PIO4_LO - y); - y = 0.0; - } - let z = x * x; - let w = z * z; - /* - * Break x^5*(T[1]+x^2*T[2]+...) into - * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + - * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) - */ - let r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11])))); - let v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12]))))); - let s = z * x; - let r = y + z * (s * (r + v) + y) + s * T[0]; - let w = x + r; - if big { - let sign = hx >> 31; - let s = 1.0 - 2.0 * odd as f64; - let v = s - 2.0 * (x + (r - w * w / (w + s))); - return if sign != 0 { -v } else { v }; - } - if odd == 0 { - return w; - } - /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */ - let w0 = zero_low_word(w); - let v = r - (w0 - x); /* w0+v = r+x */ - let a = -1.0 / w; - let a0 = zero_low_word(a); - a0 + a * (1.0 + a0 * w0 + a0 * v) -} - -fn zero_low_word(x: f64) -> f64 { - f64::from_bits(f64::to_bits(x) & 0xFFFF_FFFF_0000_0000) -} diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs deleted file mode 100644 index af8db539dad..00000000000 --- a/library/compiler-builtins/libm/src/math/k_tanf.rs +++ /dev/null @@ -1,46 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ -/* - * ==================================================== - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. - * - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ -const T: [f64; 6] = [ - 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ - 0.133392002712976742718, /* 0x1112fd38999f72.0p-55 */ - 0.0533812378445670393523, /* 0x1b54c91d865afe.0p-57 */ - 0.0245283181166547278873, /* 0x191df3908c33ce.0p-58 */ - 0.00297435743359967304927, /* 0x185dadfcecf44e.0p-61 */ - 0.00946564784943673166728, /* 0x1362b9bf971bcd.0p-59 */ -]; - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { - let z = x * x; - /* - * Split up the polynomial into small independent terms to give - * opportunities for parallel evaluation. The chosen splitting is - * micro-optimized for Athlons (XP, X64). It costs 2 multiplications - * relative to Horner's method on sequential machines. - * - * We add the small terms from lowest degree up for efficiency on - * non-sequential machines (the lowest degree terms tend to be ready - * earlier). Apart from this, we don't care about order of - * operations, and don't need to to care since we have precision to - * spare. However, the chosen splitting is good for accuracy too, - * and would give results as accurate as Horner's method if the - * small terms were added from highest degree down. - */ - let mut r = T[4] + z * T[5]; - let t = T[2] + z * T[3]; - let w = z * z; - let s = z * x; - let u = T[0] + z * T[1]; - r = (x + s * u) + (s * w) * (t + w * r); - (if odd { -1. / r } else { r }) as f32 -} diff --git a/library/compiler-builtins/libm/src/math/ldexp.rs b/library/compiler-builtins/libm/src/math/ldexp.rs deleted file mode 100644 index 24899ba306a..00000000000 --- a/library/compiler-builtins/libm/src/math/ldexp.rs +++ /dev/null @@ -1,21 +0,0 @@ -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf16(x: f16, n: i32) -> f16 { - super::scalbnf16(x, n) -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf(x: f32, n: i32) -> f32 { - super::scalbnf(x, n) -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexp(x: f64, n: i32) -> f64 { - super::scalbn(x, n) -} - -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf128(x: f128, n: i32) -> f128 { - super::scalbnf128(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/src/math/lgamma.rs deleted file mode 100644 index 8312dc18648..00000000000 --- a/library/compiler-builtins/libm/src/math/lgamma.rs +++ /dev/null @@ -1,8 +0,0 @@ -use super::lgamma_r; - -/// The natural logarithm of the -/// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgamma(x: f64) -> f64 { - lgamma_r(x).0 -} diff --git a/library/compiler-builtins/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/src/math/lgamma_r.rs deleted file mode 100644 index 6becaad2ce9..00000000000 --- a/library/compiler-builtins/libm/src/math/lgamma_r.rs +++ /dev/null @@ -1,321 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - * - */ -/* lgamma_r(x, signgamp) - * Reentrant version of the logarithm of the Gamma function - * with user provide pointer for the sign of Gamma(x). - * - * Method: - * 1. Argument Reduction for 0 < x <= 8 - * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may - * reduce x to a number in [1.5,2.5] by - * lgamma(1+s) = log(s) + lgamma(s) - * for example, - * lgamma(7.3) = log(6.3) + lgamma(6.3) - * = log(6.3*5.3) + lgamma(5.3) - * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) - * 2. Polynomial approximation of lgamma around its - * minimun ymin=1.461632144968362245 to maintain monotonicity. - * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use - * Let z = x-ymin; - * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) - * where - * poly(z) is a 14 degree polynomial. - * 2. Rational approximation in the primary interval [2,3] - * We use the following approximation: - * s = x-2.0; - * lgamma(x) = 0.5*s + s*P(s)/Q(s) - * with accuracy - * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 - * Our algorithms are based on the following observation - * - * zeta(2)-1 2 zeta(3)-1 3 - * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... - * 2 3 - * - * where Euler = 0.5771... is the Euler constant, which is very - * close to 0.5. - * - * 3. For x>=8, we have - * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... - * (better formula: - * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) - * Let z = 1/x, then we approximation - * f(z) = lgamma(x) - (x-0.5)(log(x)-1) - * by - * 3 5 11 - * w = w0 + w1*z + w2*z + w3*z + ... + w6*z - * where - * |w - f(z)| < 2**-58.74 - * - * 4. For negative x, since (G is gamma function) - * -x*G(-x)*G(x) = PI/sin(PI*x), - * we have - * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) - * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 - * Hence, for x<0, signgam = sign(sin(PI*x)) and - * lgamma(x) = log(|Gamma(x)|) - * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); - * Note: one should avoid compute PI*(-x) directly in the - * computation of sin(PI*(-x)). - * - * 5. Special Cases - * lgamma(2+s) ~ s*(1-Euler) for tiny s - * lgamma(1) = lgamma(2) = 0 - * lgamma(x) ~ -log(|x|) for tiny x - * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero - * lgamma(inf) = inf - * lgamma(-inf) = inf (bug for bug compatible with C99!?) - * - */ - -use super::{floor, k_cos, k_sin, log}; - -const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ -const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ -const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ -const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ -const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ -const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ -const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ -const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ -const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ -const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ -const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ -const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ -const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ -const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ -const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ -/* tt = -(tail of TF) */ -const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ -const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ -const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ -const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ -const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ -const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ -const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ -const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ -const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ -const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ -const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ -const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ -const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ -const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ -const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ -const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ -const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ -const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ -const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ -const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ -const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ -const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ -const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ -const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ -const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ -const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ -const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ -const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ -const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ -const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ -const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ -const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ -const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ -const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ -const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ -const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ -const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ -const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ -const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ -const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ -const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ -const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ -const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ -const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ -const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ - -/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: f64) -> f64 { - let mut n: i32; - - /* spurious inexact if odd int */ - x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ - - n = (x * 4.0) as i32; - n = div!(n + 1, 2); - x -= (n as f64) * 0.5; - x *= PI; - - match n { - 1 => k_cos(x, 0.0), - 2 => k_sin(-x, 0.0, 0), - 3 => -k_cos(x, 0.0), - // 0 - _ => k_sin(x, 0.0, 0), - } -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgamma_r(mut x: f64) -> (f64, i32) { - let u: u64 = x.to_bits(); - let mut t: f64; - let y: f64; - let mut z: f64; - let nadj: f64; - let p: f64; - let p1: f64; - let p2: f64; - let p3: f64; - let q: f64; - let mut r: f64; - let w: f64; - let ix: u32; - let sign: bool; - let i: i32; - let mut signgam: i32; - - /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - signgam = 1; - sign = (u >> 63) != 0; - ix = ((u >> 32) as u32) & 0x7fffffff; - if ix >= 0x7ff00000 { - return (x * x, signgam); - } - if ix < (0x3ff - 70) << 20 { - /* |x|<2**-70, return -log(|x|) */ - if sign { - x = -x; - signgam = -1; - } - return (-log(x), signgam); - } - if sign { - x = -x; - t = sin_pi(x); - if t == 0.0 { - /* -integer */ - return (1.0 / (x - x), signgam); - } - if t > 0.0 { - signgam = -1; - } else { - t = -t; - } - nadj = log(PI / (t * x)); - } else { - nadj = 0.0; - } - - /* purge off 1 and 2 */ - if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { - r = 0.0; - } - /* for x < 2.0 */ - else if ix < 0x40000000 { - if ix <= 0x3feccccc { - /* lgamma(x) = lgamma(x+1)-log(x) */ - r = -log(x); - if ix >= 0x3FE76944 { - y = 1.0 - x; - i = 0; - } else if ix >= 0x3FCDA661 { - y = x - (TC - 1.0); - i = 1; - } else { - y = x; - i = 2; - } - } else { - r = 0.0; - if ix >= 0x3FFBB4C3 { - /* [1.7316,2] */ - y = 2.0 - x; - i = 0; - } else if ix >= 0x3FF3B4C4 { - /* [1.23,1.73] */ - y = x - TC; - i = 1; - } else { - y = x - 1.0; - i = 2; - } - } - match i { - 0 => { - z = y * y; - p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); - p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); - p = y * p1 + p2; - r += p - 0.5 * y; - } - 1 => { - z = y * y; - w = z * y; - p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ - p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); - p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); - p = z * p1 - (TT - w * (p2 + y * p3)); - r += TF + p; - } - 2 => { - p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); - p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); - r += -0.5 * y + p1 / p2; - } - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => {} - } - } else if ix < 0x40200000 { - /* x < 8.0 */ - i = x as i32; - y = x - (i as f64); - p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); - q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); - r = 0.5 * y + p / q; - z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ - // TODO: In C, this was implemented using switch jumps with fallthrough. - // Does this implementation have performance problems? - if i >= 7 { - z *= y + 6.0; - } - if i >= 6 { - z *= y + 5.0; - } - if i >= 5 { - z *= y + 4.0; - } - if i >= 4 { - z *= y + 3.0; - } - if i >= 3 { - z *= y + 2.0; - r += log(z); - } - } else if ix < 0x43900000 { - /* 8.0 <= x < 2**58 */ - t = log(x); - z = 1.0 / x; - y = z * z; - w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); - r = (x - 0.5) * (t - 1.0) + w; - } else { - /* 2**58 <= x <= inf */ - r = x * (log(x) - 1.0); - } - if sign { - r = nadj - r; - } - return (r, signgam); -} diff --git a/library/compiler-builtins/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/src/math/lgammaf.rs deleted file mode 100644 index d37512397cb..00000000000 --- a/library/compiler-builtins/libm/src/math/lgammaf.rs +++ /dev/null @@ -1,8 +0,0 @@ -use super::lgammaf_r; - -/// The natural logarithm of the -/// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgammaf(x: f32) -> f32 { - lgammaf_r(x).0 -} diff --git a/library/compiler-builtins/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/src/math/lgammaf_r.rs deleted file mode 100644 index 10cecee541c..00000000000 --- a/library/compiler-builtins/libm/src/math/lgammaf_r.rs +++ /dev/null @@ -1,256 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{floorf, k_cosf, k_sinf, logf}; - -const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ -const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ -const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ -const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ -const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ -const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ -const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ -const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ -const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ -const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ -const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ -const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ -const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ -const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ -const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ -/* TT = -(tail of TF) */ -const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ -const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ -const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ -const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ -const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ -const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ -const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ -const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ -const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ -const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ -const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ -const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ -const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ -const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ -const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ -const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ -const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ -const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ -const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ -const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ -const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ -const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ -const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ -const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ -const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ -const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ -const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ -const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ -const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ -const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ -const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ -const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ -const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ -const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ -const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ -const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ -const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ -const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ -const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ -const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ -const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ -const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ -const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ -const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ -const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ -const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ -const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ - -/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: f32) -> f32 { - let mut y: f64; - let mut n: isize; - - /* spurious inexact if odd int */ - x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ - - n = (x * 4.0) as isize; - n = div!(n + 1, 2); - y = (x as f64) - (n as f64) * 0.5; - y *= 3.14159265358979323846; - match n { - 1 => k_cosf(y), - 2 => k_sinf(-y), - 3 => -k_cosf(y), - // 0 - _ => k_sinf(y), - } -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgammaf_r(mut x: f32) -> (f32, i32) { - let u = x.to_bits(); - let mut t: f32; - let y: f32; - let mut z: f32; - let nadj: f32; - let p: f32; - let p1: f32; - let p2: f32; - let p3: f32; - let q: f32; - let mut r: f32; - let w: f32; - let ix: u32; - let i: i32; - let sign: bool; - let mut signgam: i32; - - /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - signgam = 1; - sign = (u >> 31) != 0; - ix = u & 0x7fffffff; - if ix >= 0x7f800000 { - return (x * x, signgam); - } - if ix < 0x35000000 { - /* |x| < 2**-21, return -log(|x|) */ - if sign { - signgam = -1; - x = -x; - } - return (-logf(x), signgam); - } - if sign { - x = -x; - t = sin_pi(x); - if t == 0.0 { - /* -integer */ - return (1.0 / (x - x), signgam); - } - if t > 0.0 { - signgam = -1; - } else { - t = -t; - } - nadj = logf(PI / (t * x)); - } else { - nadj = 0.0; - } - - /* purge off 1 and 2 */ - if ix == 0x3f800000 || ix == 0x40000000 { - r = 0.0; - } - /* for x < 2.0 */ - else if ix < 0x40000000 { - if ix <= 0x3f666666 { - /* lgamma(x) = lgamma(x+1)-log(x) */ - r = -logf(x); - if ix >= 0x3f3b4a20 { - y = 1.0 - x; - i = 0; - } else if ix >= 0x3e6d3308 { - y = x - (TC - 1.0); - i = 1; - } else { - y = x; - i = 2; - } - } else { - r = 0.0; - if ix >= 0x3fdda618 { - /* [1.7316,2] */ - y = 2.0 - x; - i = 0; - } else if ix >= 0x3F9da620 { - /* [1.23,1.73] */ - y = x - TC; - i = 1; - } else { - y = x - 1.0; - i = 2; - } - } - match i { - 0 => { - z = y * y; - p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); - p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); - p = y * p1 + p2; - r += p - 0.5 * y; - } - 1 => { - z = y * y; - w = z * y; - p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ - p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); - p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); - p = z * p1 - (TT - w * (p2 + y * p3)); - r += TF + p; - } - 2 => { - p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); - p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); - r += -0.5 * y + p1 / p2; - } - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => {} - } - } else if ix < 0x41000000 { - /* x < 8.0 */ - i = x as i32; - y = x - (i as f32); - p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); - q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); - r = 0.5 * y + p / q; - z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ - // TODO: In C, this was implemented using switch jumps with fallthrough. - // Does this implementation have performance problems? - if i >= 7 { - z *= y + 6.0; - } - if i >= 6 { - z *= y + 5.0; - } - if i >= 5 { - z *= y + 4.0; - } - if i >= 4 { - z *= y + 3.0; - } - if i >= 3 { - z *= y + 2.0; - r += logf(z); - } - } else if ix < 0x5c800000 { - /* 8.0 <= x < 2**58 */ - t = logf(x); - z = 1.0 / x; - y = z * z; - w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); - r = (x - 0.5) * (t - 1.0) + w; - } else { - /* 2**58 <= x <= inf */ - r = x * (logf(x) - 1.0); - } - if sign { - r = nadj - r; - } - return (r, signgam); -} diff --git a/library/compiler-builtins/libm/src/math/log.rs b/library/compiler-builtins/libm/src/math/log.rs deleted file mode 100644 index f2dc47ec5cc..00000000000 --- a/library/compiler-builtins/libm/src/math/log.rs +++ /dev/null @@ -1,118 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* log(x) - * Return the logarithm of x - * - * Method : - * 1. Argument Reduction: find k and f such that - * x = 2^k * (1+f), - * where sqrt(2)/2 < 1+f < sqrt(2) . - * - * 2. Approximation of log(1+f). - * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) - * = 2s + 2/3 s**3 + 2/5 s**5 + ....., - * = 2s + s*R - * We use a special Remez algorithm on [0,0.1716] to generate - * a polynomial of degree 14 to approximate R The maximum error - * of this polynomial approximation is bounded by 2**-58.45. In - * other words, - * 2 4 6 8 10 12 14 - * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s - * (the values of Lg1 to Lg7 are listed in the program) - * and - * | 2 14 | -58.45 - * | Lg1*s +...+Lg7*s - R(z) | <= 2 - * | | - * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. - * In order to guarantee error in log below 1ulp, we compute log - * by - * log(1+f) = f - s*(f - R) (if f is not too large) - * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) - * - * 3. Finally, log(x) = k*ln2 + log(1+f). - * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) - * Here ln2 is split into two floating point number: - * ln2_hi + ln2_lo, - * where n*ln2_hi is always exact for |n| < 2000. - * - * Special cases: - * log(x) is NaN with signal if x < 0 (including -INF) ; - * log(+INF) is +INF; log(0) is -INF with signal; - * log(NaN) is that NaN with no signal. - * - * Accuracy: - * according to an error analysis, the error is always less than - * 1 ulp (unit in the last place). - * - * Constants: - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. - */ - -const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ -const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ -const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ - -/// The natural logarithm of `x` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log(mut x: f64) -> f64 { - let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 - - let mut ui = x.to_bits(); - let mut hx: u32 = (ui >> 32) as u32; - let mut k: i32 = 0; - - if (hx < 0x00100000) || ((hx >> 31) != 0) { - /* x < 2**-126 */ - if ui << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if hx >> 31 != 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale x up */ - k -= 54; - x *= x1p54; - ui = x.to_bits(); - hx = (ui >> 32) as u32; - } else if hx >= 0x7ff00000 { - return x; - } else if hx == 0x3ff00000 && ui << 32 == 0 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - hx += 0x3ff00000 - 0x3fe6a09e; - k += ((hx >> 20) as i32) - 0x3ff; - hx = (hx & 0x000fffff) + 0x3fe6a09e; - ui = ((hx as u64) << 32) | (ui & 0xffffffff); - x = f64::from_bits(ui); - - let f: f64 = x - 1.0; - let hfsq: f64 = 0.5 * f * f; - let s: f64 = f / (2.0 + f); - let z: f64 = s * s; - let w: f64 = z * z; - let t1: f64 = w * (LG2 + w * (LG4 + w * LG6)); - let t2: f64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - let r: f64 = t2 + t1; - let dk: f64 = k as f64; - s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI -} diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs deleted file mode 100644 index 8c9d68c492d..00000000000 --- a/library/compiler-builtins/libm/src/math/log10.rs +++ /dev/null @@ -1,118 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* - * Return the base 10 logarithm of x. See log.c for most comments. - * - * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 - * as in log.c, then combine and scale in extra precision: - * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) - */ - -use core::f64; - -const IVLN10HI: f64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ -const IVLN10LO: f64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ -const LOG10_2HI: f64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ -const LOG10_2LO: f64 = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ -const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ - -/// The base 10 logarithm of `x` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log10(mut x: f64) -> f64 { - let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 - - let mut ui: u64 = x.to_bits(); - let hfsq: f64; - let f: f64; - let s: f64; - let z: f64; - let r: f64; - let mut w: f64; - let t1: f64; - let t2: f64; - let dk: f64; - let y: f64; - let mut hi: f64; - let lo: f64; - let mut val_hi: f64; - let mut val_lo: f64; - let mut hx: u32; - let mut k: i32; - - hx = (ui >> 32) as u32; - k = 0; - if hx < 0x00100000 || (hx >> 31) > 0 { - if ui << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (hx >> 31) > 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale x up */ - k -= 54; - x *= x1p54; - ui = x.to_bits(); - hx = (ui >> 32) as u32; - } else if hx >= 0x7ff00000 { - return x; - } else if hx == 0x3ff00000 && ui << 32 == 0 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - hx += 0x3ff00000 - 0x3fe6a09e; - k += (hx >> 20) as i32 - 0x3ff; - hx = (hx & 0x000fffff) + 0x3fe6a09e; - ui = ((hx as u64) << 32) | (ui & 0xffffffff); - x = f64::from_bits(ui); - - f = x - 1.0; - hfsq = 0.5 * f * f; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * (LG4 + w * LG6)); - t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - r = t2 + t1; - - /* See log2.c for details. */ - /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ - hi = f - hfsq; - ui = hi.to_bits(); - ui &= (-1i64 as u64) << 32; - hi = f64::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); - - /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ - val_hi = hi * IVLN10HI; - dk = k as f64; - y = dk * LOG10_2HI; - val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI; - - /* - * Extra precision in for adding y is not strictly needed - * since there is no very large cancellation near x = sqrt(2) or - * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs - * with some parallelism and it reduces the error for many args. - */ - w = y + val_hi; - val_lo += (y - w) + val_hi; - val_hi = w; - - val_lo + val_hi -} diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs deleted file mode 100644 index 18bf8fcc832..00000000000 --- a/library/compiler-builtins/libm/src/math/log10f.rs +++ /dev/null @@ -1,92 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* - * See comments in log10.c. - */ - -use core::f32; - -const IVLN10HI: f32 = 4.3432617188e-01; /* 0x3ede6000 */ -const IVLN10LO: f32 = -3.1689971365e-05; /* 0xb804ead9 */ -const LOG10_2HI: f32 = 3.0102920532e-01; /* 0x3e9a2080 */ -const LOG10_2LO: f32 = 7.9034151668e-07; /* 0x355427db */ -/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ - -/// The base 10 logarithm of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log10f(mut x: f32) -> f32 { - let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 - - let mut ui: u32 = x.to_bits(); - let hfsq: f32; - let f: f32; - let s: f32; - let z: f32; - let r: f32; - let w: f32; - let t1: f32; - let t2: f32; - let dk: f32; - let mut hi: f32; - let lo: f32; - let mut ix: u32; - let mut k: i32; - - ix = ui; - k = 0; - if ix < 0x00800000 || (ix >> 31) > 0 { - /* x < 2**-126 */ - if ix << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (ix >> 31) > 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale up x */ - k -= 25; - x *= x1p25f; - ui = x.to_bits(); - ix = ui; - } else if ix >= 0x7f800000 { - return x; - } else if ix == 0x3f800000 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - ix += 0x3f800000 - 0x3f3504f3; - k += (ix >> 23) as i32 - 0x7f; - ix = (ix & 0x007fffff) + 0x3f3504f3; - ui = ix; - x = f32::from_bits(ui); - - f = x - 1.0; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * LG4); - t2 = z * (LG1 + w * LG3); - r = t2 + t1; - hfsq = 0.5 * f * f; - - hi = f - hfsq; - ui = hi.to_bits(); - ui &= 0xfffff000; - hi = f32::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); - dk = k as f32; - dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI -} diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs deleted file mode 100644 index b7f3fb09e15..00000000000 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ /dev/null @@ -1,140 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* double log1p(double x) - * Return the natural logarithm of 1+x. - * - * Method : - * 1. Argument Reduction: find k and f such that - * 1+x = 2^k * (1+f), - * where sqrt(2)/2 < 1+f < sqrt(2) . - * - * Note. If k=0, then f=x is exact. However, if k!=0, then f - * may not be representable exactly. In that case, a correction - * term is need. Let u=1+x rounded. Let c = (1+x)-u, then - * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), - * and add back the correction term c/u. - * (Note: when x > 2**53, one can simply return log(x)) - * - * 2. Approximation of log(1+f): See log.c - * - * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c - * - * Special cases: - * log1p(x) is NaN with signal if x < -1 (including -INF) ; - * log1p(+INF) is +INF; log1p(-1) is -INF with signal; - * log1p(NaN) is that NaN with no signal. - * - * Accuracy: - * according to an error analysis, the error is always less than - * 1 ulp (unit in the last place). - * - * Constants: - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. - * - * Note: Assuming log() return accurate answer, the following - * algorithm can be used to compute log1p(x) to within a few ULP: - * - * u = 1+x; - * if(u==1.0) return x ; else - * return log(u)*(x/(u-1.0)); - * - * See HP-15C Advanced Functions Handbook, p.193. - */ - -use core::f64; - -const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ -const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ -const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ - -/// The natural logarithm of 1+`x` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log1p(x: f64) -> f64 { - let mut ui: u64 = x.to_bits(); - let hfsq: f64; - let mut f: f64 = 0.; - let mut c: f64 = 0.; - let s: f64; - let z: f64; - let r: f64; - let w: f64; - let t1: f64; - let t2: f64; - let dk: f64; - let hx: u32; - let mut hu: u32; - let mut k: i32; - - hx = (ui >> 32) as u32; - k = 1; - if hx < 0x3fda827a || (hx >> 31) > 0 { - /* 1+x < sqrt(2)+ */ - if hx >= 0xbff00000 { - /* x <= -1.0 */ - if x == -1. { - return x / 0.0; /* log1p(-1) = -inf */ - } - return (x - x) / 0.0; /* log1p(x<-1) = NaN */ - } - if hx << 1 < 0x3ca00000 << 1 { - /* |x| < 2**-53 */ - /* underflow if subnormal */ - if (hx & 0x7ff00000) == 0 { - force_eval!(x as f32); - } - return x; - } - if hx <= 0xbfd2bec4 { - /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ - k = 0; - c = 0.; - f = x; - } - } else if hx >= 0x7ff00000 { - return x; - } - if k > 0 { - ui = (1. + x).to_bits(); - hu = (ui >> 32) as u32; - hu += 0x3ff00000 - 0x3fe6a09e; - k = (hu >> 20) as i32 - 0x3ff; - /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ - if k < 54 { - c = if k >= 2 { 1. - (f64::from_bits(ui) - x) } else { x - (f64::from_bits(ui) - 1.) }; - c /= f64::from_bits(ui); - } else { - c = 0.; - } - /* reduce u into [sqrt(2)/2, sqrt(2)] */ - hu = (hu & 0x000fffff) + 0x3fe6a09e; - ui = ((hu as u64) << 32) | (ui & 0xffffffff); - f = f64::from_bits(ui) - 1.; - } - hfsq = 0.5 * f * f; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * (LG4 + w * LG6)); - t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - r = t2 + t1; - dk = k as f64; - s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI -} diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs deleted file mode 100644 index bba5b8a2f21..00000000000 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ /dev/null @@ -1,95 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::f32; - -const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ -/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ - -/// The natural logarithm of 1+`x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log1pf(x: f32) -> f32 { - let mut ui: u32 = x.to_bits(); - let hfsq: f32; - let mut f: f32 = 0.; - let mut c: f32 = 0.; - let s: f32; - let z: f32; - let r: f32; - let w: f32; - let t1: f32; - let t2: f32; - let dk: f32; - let ix: u32; - let mut iu: u32; - let mut k: i32; - - ix = ui; - k = 1; - if ix < 0x3ed413d0 || (ix >> 31) > 0 { - /* 1+x < sqrt(2)+ */ - if ix >= 0xbf800000 { - /* x <= -1.0 */ - if x == -1. { - return x / 0.0; /* log1p(-1)=+inf */ - } - return (x - x) / 0.0; /* log1p(x<-1)=NaN */ - } - if ix << 1 < 0x33800000 << 1 { - /* |x| < 2**-24 */ - /* underflow if subnormal */ - if (ix & 0x7f800000) == 0 { - force_eval!(x * x); - } - return x; - } - if ix <= 0xbe95f619 { - /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ - k = 0; - c = 0.; - f = x; - } - } else if ix >= 0x7f800000 { - return x; - } - if k > 0 { - ui = (1. + x).to_bits(); - iu = ui; - iu += 0x3f800000 - 0x3f3504f3; - k = (iu >> 23) as i32 - 0x7f; - /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ - if k < 25 { - c = if k >= 2 { 1. - (f32::from_bits(ui) - x) } else { x - (f32::from_bits(ui) - 1.) }; - c /= f32::from_bits(ui); - } else { - c = 0.; - } - /* reduce u into [sqrt(2)/2, sqrt(2)] */ - iu = (iu & 0x007fffff) + 0x3f3504f3; - ui = iu; - f = f32::from_bits(ui) - 1.; - } - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * LG4); - t2 = z * (LG1 + w * LG3); - r = t2 + t1; - hfsq = 0.5 * f * f; - dk = k as f32; - s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI -} diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs deleted file mode 100644 index 701f63c25e7..00000000000 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ /dev/null @@ -1,107 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* - * Return the base 2 logarithm of x. See log.c for most comments. - * - * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 - * as in log.c, then combine and scale in extra precision: - * log2(x) = (f - f*f/2 + r)/log(2) + k - */ - -use core::f64; - -const IVLN2HI: f64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ -const IVLN2LO: f64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ -const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ - -/// The base 2 logarithm of `x` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log2(mut x: f64) -> f64 { - let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 - - let mut ui: u64 = x.to_bits(); - let hfsq: f64; - let f: f64; - let s: f64; - let z: f64; - let r: f64; - let mut w: f64; - let t1: f64; - let t2: f64; - let y: f64; - let mut hi: f64; - let lo: f64; - let mut val_hi: f64; - let mut val_lo: f64; - let mut hx: u32; - let mut k: i32; - - hx = (ui >> 32) as u32; - k = 0; - if hx < 0x00100000 || (hx >> 31) > 0 { - if ui << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (hx >> 31) > 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale x up */ - k -= 54; - x *= x1p54; - ui = x.to_bits(); - hx = (ui >> 32) as u32; - } else if hx >= 0x7ff00000 { - return x; - } else if hx == 0x3ff00000 && ui << 32 == 0 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - hx += 0x3ff00000 - 0x3fe6a09e; - k += (hx >> 20) as i32 - 0x3ff; - hx = (hx & 0x000fffff) + 0x3fe6a09e; - ui = ((hx as u64) << 32) | (ui & 0xffffffff); - x = f64::from_bits(ui); - - f = x - 1.0; - hfsq = 0.5 * f * f; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * (LG4 + w * LG6)); - t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - r = t2 + t1; - - /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ - hi = f - hfsq; - ui = hi.to_bits(); - ui &= (-1i64 as u64) << 32; - hi = f64::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); - - val_hi = hi * IVLN2HI; - val_lo = (lo + hi) * IVLN2LO + lo * IVLN2HI; - - /* spadd(val_hi, val_lo, y), except for not using double_t: */ - y = k.into(); - w = y + val_hi; - val_lo += (y - w) + val_hi; - val_hi = w; - - val_lo + val_hi -} diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs deleted file mode 100644 index 5ba2427d1d4..00000000000 --- a/library/compiler-builtins/libm/src/math/log2f.rs +++ /dev/null @@ -1,88 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* - * See comments in log2.c. - */ - -use core::f32; - -const IVLN2HI: f32 = 1.4428710938e+00; /* 0x3fb8b000 */ -const IVLN2LO: f32 = -1.7605285393e-04; /* 0xb9389ad4 */ -/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ - -/// The base 2 logarithm of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log2f(mut x: f32) -> f32 { - let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 - - let mut ui: u32 = x.to_bits(); - let hfsq: f32; - let f: f32; - let s: f32; - let z: f32; - let r: f32; - let w: f32; - let t1: f32; - let t2: f32; - let mut hi: f32; - let lo: f32; - let mut ix: u32; - let mut k: i32; - - ix = ui; - k = 0; - if ix < 0x00800000 || (ix >> 31) > 0 { - /* x < 2**-126 */ - if ix << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (ix >> 31) > 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale up x */ - k -= 25; - x *= x1p25f; - ui = x.to_bits(); - ix = ui; - } else if ix >= 0x7f800000 { - return x; - } else if ix == 0x3f800000 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - ix += 0x3f800000 - 0x3f3504f3; - k += (ix >> 23) as i32 - 0x7f; - ix = (ix & 0x007fffff) + 0x3f3504f3; - ui = ix; - x = f32::from_bits(ui); - - f = x - 1.0; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * LG4); - t2 = z * (LG1 + w * LG3); - r = t2 + t1; - hfsq = 0.5 * f * f; - - hi = f - hfsq; - ui = hi.to_bits(); - ui &= 0xfffff000; - hi = f32::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); - (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as f32 -} diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs deleted file mode 100644 index 68d1943025e..00000000000 --- a/library/compiler-builtins/libm/src/math/logf.rs +++ /dev/null @@ -1,66 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ -/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ -const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ - -/// The natural logarithm of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn logf(mut x: f32) -> f32 { - let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 - - let mut ix = x.to_bits(); - let mut k = 0i32; - - if (ix < 0x00800000) || ((ix >> 31) != 0) { - /* x < 2**-126 */ - if ix << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (ix >> 31) != 0 { - return (x - x) / 0.; /* log(-#) = NaN */ - } - /* subnormal number, scale up x */ - k -= 25; - x *= x1p25; - ix = x.to_bits(); - } else if ix >= 0x7f800000 { - return x; - } else if ix == 0x3f800000 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - ix += 0x3f800000 - 0x3f3504f3; - k += ((ix >> 23) as i32) - 0x7f; - ix = (ix & 0x007fffff) + 0x3f3504f3; - x = f32::from_bits(ix); - - let f = x - 1.; - let s = f / (2. + f); - let z = s * s; - let w = z * z; - let t1 = w * (LG2 + w * LG4); - let t2 = z * (LG1 + w * LG3); - let r = t2 + t1; - let hfsq = 0.5 * f * f; - let dk = k as f32; - s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI -} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs deleted file mode 100644 index 949c18b4000..00000000000 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ /dev/null @@ -1,396 +0,0 @@ -macro_rules! force_eval { - ($e:expr) => { - unsafe { ::core::ptr::read_volatile(&$e) } - }; -} - -#[cfg(not(debug_assertions))] -macro_rules! i { - ($array:expr, $index:expr) => { - unsafe { *$array.get_unchecked($index) } - }; - ($array:expr, $index:expr, = , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) = $rhs; - } - }; - ($array:expr, $index:expr, += , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) += $rhs; - } - }; - ($array:expr, $index:expr, -= , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) -= $rhs; - } - }; - ($array:expr, $index:expr, &= , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) &= $rhs; - } - }; - ($array:expr, $index:expr, == , $rhs:expr) => { - unsafe { *$array.get_unchecked_mut($index) == $rhs } - }; -} - -#[cfg(debug_assertions)] -macro_rules! i { - ($array:expr, $index:expr) => { - *$array.get($index).unwrap() - }; - ($array:expr, $index:expr, = , $rhs:expr) => { - *$array.get_mut($index).unwrap() = $rhs; - }; - ($array:expr, $index:expr, -= , $rhs:expr) => { - *$array.get_mut($index).unwrap() -= $rhs; - }; - ($array:expr, $index:expr, += , $rhs:expr) => { - *$array.get_mut($index).unwrap() += $rhs; - }; - ($array:expr, $index:expr, &= , $rhs:expr) => { - *$array.get_mut($index).unwrap() &= $rhs; - }; - ($array:expr, $index:expr, == , $rhs:expr) => { - *$array.get_mut($index).unwrap() == $rhs - }; -} - -// Temporary macro to avoid panic codegen for division (in debug mode too). At -// the time of this writing this is only used in a few places, and once -// rust-lang/rust#72751 is fixed then this macro will no longer be necessary and -// the native `/` operator can be used and panics won't be codegen'd. -#[cfg(any(debug_assertions, not(intrinsics_enabled)))] -macro_rules! div { - ($a:expr, $b:expr) => { - $a / $b - }; -} - -#[cfg(all(not(debug_assertions), intrinsics_enabled))] -macro_rules! div { - ($a:expr, $b:expr) => { - unsafe { core::intrinsics::unchecked_div($a, $b) } - }; -} - -// `support` may be public for testing -#[macro_use] -#[cfg(feature = "unstable-public-internals")] -pub mod support; - -#[macro_use] -#[cfg(not(feature = "unstable-public-internals"))] -pub(crate) mod support; - -cfg_if! { - if #[cfg(feature = "unstable-public-internals")] { - pub mod generic; - } else { - mod generic; - } -} - -// Private modules -mod arch; -mod expo2; -mod k_cos; -mod k_cosf; -mod k_expo2; -mod k_expo2f; -mod k_sin; -mod k_sinf; -mod k_tan; -mod k_tanf; -mod rem_pio2; -mod rem_pio2_large; -mod rem_pio2f; - -// Private re-imports -use self::expo2::expo2; -use self::k_cos::k_cos; -use self::k_cosf::k_cosf; -use self::k_expo2::k_expo2; -use self::k_expo2f::k_expo2f; -use self::k_sin::k_sin; -use self::k_sinf::k_sinf; -use self::k_tan::k_tan; -use self::k_tanf::k_tanf; -use self::rem_pio2::rem_pio2; -use self::rem_pio2_large::rem_pio2_large; -use self::rem_pio2f::rem_pio2f; -#[allow(unused_imports)] -use self::support::{CastFrom, CastInto, DFloat, DInt, Float, HFloat, HInt, Int, IntTy, MinInt}; - -// Public modules -mod acos; -mod acosf; -mod acosh; -mod acoshf; -mod asin; -mod asinf; -mod asinh; -mod asinhf; -mod atan; -mod atan2; -mod atan2f; -mod atanf; -mod atanh; -mod atanhf; -mod cbrt; -mod cbrtf; -mod ceil; -mod copysign; -mod cos; -mod cosf; -mod cosh; -mod coshf; -mod erf; -mod erff; -mod exp; -mod exp10; -mod exp10f; -mod exp2; -mod exp2f; -mod expf; -mod expm1; -mod expm1f; -mod fabs; -mod fdim; -mod floor; -mod fma; -mod fma_wide; -mod fmin_fmax; -mod fminimum_fmaximum; -mod fminimum_fmaximum_num; -mod fmod; -mod frexp; -mod frexpf; -mod hypot; -mod hypotf; -mod ilogb; -mod ilogbf; -mod j0; -mod j0f; -mod j1; -mod j1f; -mod jn; -mod jnf; -mod ldexp; -mod lgamma; -mod lgamma_r; -mod lgammaf; -mod lgammaf_r; -mod log; -mod log10; -mod log10f; -mod log1p; -mod log1pf; -mod log2; -mod log2f; -mod logf; -mod modf; -mod modff; -mod nextafter; -mod nextafterf; -mod pow; -mod powf; -mod remainder; -mod remainderf; -mod remquo; -mod remquof; -mod rint; -mod round; -mod roundeven; -mod scalbn; -mod sin; -mod sincos; -mod sincosf; -mod sinf; -mod sinh; -mod sinhf; -mod sqrt; -mod tan; -mod tanf; -mod tanh; -mod tanhf; -mod tgamma; -mod tgammaf; -mod trunc; - -// Use separated imports instead of {}-grouped imports for easier merging. -pub use self::acos::acos; -pub use self::acosf::acosf; -pub use self::acosh::acosh; -pub use self::acoshf::acoshf; -pub use self::asin::asin; -pub use self::asinf::asinf; -pub use self::asinh::asinh; -pub use self::asinhf::asinhf; -pub use self::atan::atan; -pub use self::atan2::atan2; -pub use self::atan2f::atan2f; -pub use self::atanf::atanf; -pub use self::atanh::atanh; -pub use self::atanhf::atanhf; -pub use self::cbrt::cbrt; -pub use self::cbrtf::cbrtf; -pub use self::ceil::{ceil, ceilf}; -pub use self::copysign::{copysign, copysignf}; -pub use self::cos::cos; -pub use self::cosf::cosf; -pub use self::cosh::cosh; -pub use self::coshf::coshf; -pub use self::erf::{erf, erfc}; -pub use self::erff::{erfcf, erff}; -pub use self::exp::exp; -pub use self::exp2::exp2; -pub use self::exp2f::exp2f; -pub use self::exp10::exp10; -pub use self::exp10f::exp10f; -pub use self::expf::expf; -pub use self::expm1::expm1; -pub use self::expm1f::expm1f; -pub use self::fabs::{fabs, fabsf}; -pub use self::fdim::{fdim, fdimf}; -pub use self::floor::{floor, floorf}; -pub use self::fma::fma; -pub use self::fma_wide::fmaf; -pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; -pub use self::fminimum_fmaximum::{fmaximum, fmaximumf, fminimum, fminimumf}; -pub use self::fminimum_fmaximum_num::{fmaximum_num, fmaximum_numf, fminimum_num, fminimum_numf}; -pub use self::fmod::{fmod, fmodf}; -pub use self::frexp::frexp; -pub use self::frexpf::frexpf; -pub use self::hypot::hypot; -pub use self::hypotf::hypotf; -pub use self::ilogb::ilogb; -pub use self::ilogbf::ilogbf; -pub use self::j0::{j0, y0}; -pub use self::j0f::{j0f, y0f}; -pub use self::j1::{j1, y1}; -pub use self::j1f::{j1f, y1f}; -pub use self::jn::{jn, yn}; -pub use self::jnf::{jnf, ynf}; -pub use self::ldexp::{ldexp, ldexpf}; -pub use self::lgamma::lgamma; -pub use self::lgamma_r::lgamma_r; -pub use self::lgammaf::lgammaf; -pub use self::lgammaf_r::lgammaf_r; -pub use self::log::log; -pub use self::log1p::log1p; -pub use self::log1pf::log1pf; -pub use self::log2::log2; -pub use self::log2f::log2f; -pub use self::log10::log10; -pub use self::log10f::log10f; -pub use self::logf::logf; -pub use self::modf::modf; -pub use self::modff::modff; -pub use self::nextafter::nextafter; -pub use self::nextafterf::nextafterf; -pub use self::pow::pow; -pub use self::powf::powf; -pub use self::remainder::remainder; -pub use self::remainderf::remainderf; -pub use self::remquo::remquo; -pub use self::remquof::remquof; -pub use self::rint::{rint, rintf}; -pub use self::round::{round, roundf}; -pub use self::roundeven::{roundeven, roundevenf}; -pub use self::scalbn::{scalbn, scalbnf}; -pub use self::sin::sin; -pub use self::sincos::sincos; -pub use self::sincosf::sincosf; -pub use self::sinf::sinf; -pub use self::sinh::sinh; -pub use self::sinhf::sinhf; -pub use self::sqrt::{sqrt, sqrtf}; -pub use self::tan::tan; -pub use self::tanf::tanf; -pub use self::tanh::tanh; -pub use self::tanhf::tanhf; -pub use self::tgamma::tgamma; -pub use self::tgammaf::tgammaf; -pub use self::trunc::{trunc, truncf}; - -cfg_if! { - if #[cfg(f16_enabled)] { - // verify-sorted-start - pub use self::ceil::ceilf16; - pub use self::copysign::copysignf16; - pub use self::fabs::fabsf16; - pub use self::fdim::fdimf16; - pub use self::floor::floorf16; - pub use self::fmin_fmax::{fmaxf16, fminf16}; - pub use self::fminimum_fmaximum::{fmaximumf16, fminimumf16}; - pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16}; - pub use self::fmod::fmodf16; - pub use self::ldexp::ldexpf16; - pub use self::rint::rintf16; - pub use self::round::roundf16; - pub use self::roundeven::roundevenf16; - pub use self::scalbn::scalbnf16; - pub use self::sqrt::sqrtf16; - pub use self::trunc::truncf16; - // verify-sorted-end - - #[allow(unused_imports)] - pub(crate) use self::fma_wide::fmaf16; - } -} - -cfg_if! { - if #[cfg(f128_enabled)] { - // verify-sorted-start - pub use self::ceil::ceilf128; - pub use self::copysign::copysignf128; - pub use self::fabs::fabsf128; - pub use self::fdim::fdimf128; - pub use self::floor::floorf128; - pub use self::fma::fmaf128; - pub use self::fmin_fmax::{fmaxf128, fminf128}; - pub use self::fminimum_fmaximum::{fmaximumf128, fminimumf128}; - pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; - pub use self::fmod::fmodf128; - pub use self::ldexp::ldexpf128; - pub use self::rint::rintf128; - pub use self::round::roundf128; - pub use self::roundeven::roundevenf128; - pub use self::scalbn::scalbnf128; - pub use self::sqrt::sqrtf128; - pub use self::trunc::truncf128; - // verify-sorted-end - } -} - -#[inline] -fn get_high_word(x: f64) -> u32 { - (x.to_bits() >> 32) as u32 -} - -#[inline] -fn get_low_word(x: f64) -> u32 { - x.to_bits() as u32 -} - -#[inline] -fn with_set_high_word(f: f64, hi: u32) -> f64 { - let mut tmp = f.to_bits(); - tmp &= 0x00000000_ffffffff; - tmp |= (hi as u64) << 32; - f64::from_bits(tmp) -} - -#[inline] -fn with_set_low_word(f: f64, lo: u32) -> f64 { - let mut tmp = f.to_bits(); - tmp &= 0xffffffff_00000000; - tmp |= lo as u64; - f64::from_bits(tmp) -} - -#[inline] -fn combine_words(hi: u32, lo: u32) -> f64 { - f64::from_bits(((hi as u64) << 32) | lo as u64) -} diff --git a/library/compiler-builtins/libm/src/math/modf.rs b/library/compiler-builtins/libm/src/math/modf.rs deleted file mode 100644 index 6541862cdd9..00000000000 --- a/library/compiler-builtins/libm/src/math/modf.rs +++ /dev/null @@ -1,35 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn modf(x: f64) -> (f64, f64) { - let rv2: f64; - let mut u = x.to_bits(); - let mask: u64; - let e = (((u >> 52) & 0x7ff) as i32) - 0x3ff; - - /* no fractional part */ - if e >= 52 { - rv2 = x; - if e == 0x400 && (u << 12) != 0 { - /* nan */ - return (x, rv2); - } - u &= 1 << 63; - return (f64::from_bits(u), rv2); - } - - /* no integral part*/ - if e < 0 { - u &= 1 << 63; - rv2 = f64::from_bits(u); - return (x, rv2); - } - - mask = ((!0) >> 12) >> e; - if (u & mask) == 0 { - rv2 = x; - u &= 1 << 63; - return (f64::from_bits(u), rv2); - } - u &= !mask; - rv2 = f64::from_bits(u); - return (x - rv2, rv2); -} diff --git a/library/compiler-builtins/libm/src/math/modff.rs b/library/compiler-builtins/libm/src/math/modff.rs deleted file mode 100644 index 90c6bca7d8d..00000000000 --- a/library/compiler-builtins/libm/src/math/modff.rs +++ /dev/null @@ -1,34 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn modff(x: f32) -> (f32, f32) { - let rv2: f32; - let mut u: u32 = x.to_bits(); - let mask: u32; - let e = (((u >> 23) & 0xff) as i32) - 0x7f; - - /* no fractional part */ - if e >= 23 { - rv2 = x; - if e == 0x80 && (u << 9) != 0 { - /* nan */ - return (x, rv2); - } - u &= 0x80000000; - return (f32::from_bits(u), rv2); - } - /* no integral part */ - if e < 0 { - u &= 0x80000000; - rv2 = f32::from_bits(u); - return (x, rv2); - } - - mask = 0x007fffff >> e; - if (u & mask) == 0 { - rv2 = x; - u &= 0x80000000; - return (f32::from_bits(u), rv2); - } - u &= !mask; - rv2 = f32::from_bits(u); - return (x - rv2, rv2); -} diff --git a/library/compiler-builtins/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/src/math/nextafter.rs deleted file mode 100644 index c991ff6f233..00000000000 --- a/library/compiler-builtins/libm/src/math/nextafter.rs +++ /dev/null @@ -1,37 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn nextafter(x: f64, y: f64) -> f64 { - if x.is_nan() || y.is_nan() { - return x + y; - } - - let mut ux_i = x.to_bits(); - let uy_i = y.to_bits(); - if ux_i == uy_i { - return y; - } - - let ax = ux_i & (!1_u64 / 2); - let ay = uy_i & (!1_u64 / 2); - if ax == 0 { - if ay == 0 { - return y; - } - ux_i = (uy_i & (1_u64 << 63)) | 1; - } else if ax > ay || ((ux_i ^ uy_i) & (1_u64 << 63)) != 0 { - ux_i -= 1; - } else { - ux_i += 1; - } - - let e = (ux_i >> 52) & 0x7ff; - // raise overflow if ux.f is infinite and x is finite - if e == 0x7ff { - force_eval!(x + x); - } - let ux_f = f64::from_bits(ux_i); - // raise underflow if ux.f is subnormal or zero - if e == 0 { - force_eval!(x * x + ux_f * ux_f); - } - ux_f -} diff --git a/library/compiler-builtins/libm/src/math/nextafterf.rs b/library/compiler-builtins/libm/src/math/nextafterf.rs deleted file mode 100644 index 8ba3833562f..00000000000 --- a/library/compiler-builtins/libm/src/math/nextafterf.rs +++ /dev/null @@ -1,37 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn nextafterf(x: f32, y: f32) -> f32 { - if x.is_nan() || y.is_nan() { - return x + y; - } - - let mut ux_i = x.to_bits(); - let uy_i = y.to_bits(); - if ux_i == uy_i { - return y; - } - - let ax = ux_i & 0x7fff_ffff_u32; - let ay = uy_i & 0x7fff_ffff_u32; - if ax == 0 { - if ay == 0 { - return y; - } - ux_i = (uy_i & 0x8000_0000_u32) | 1; - } else if ax > ay || ((ux_i ^ uy_i) & 0x8000_0000_u32) != 0 { - ux_i -= 1; - } else { - ux_i += 1; - } - - let e = ux_i & 0x7f80_0000_u32; - // raise overflow if ux_f is infinite and x is finite - if e == 0x7f80_0000_u32 { - force_eval!(x + x); - } - let ux_f = f32::from_bits(ux_i); - // raise underflow if ux_f is subnormal or zero - if e == 0 { - force_eval!(x * x + ux_f * ux_f); - } - ux_f -} diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs deleted file mode 100644 index 80b2a24999c..00000000000 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ /dev/null @@ -1,607 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ -/* - * ==================================================== - * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. - * - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -// pow(x,y) return x**y -// -// n -// Method: Let x = 2 * (1+f) -// 1. Compute and return log2(x) in two pieces: -// log2(x) = w1 + w2, -// where w1 has 53-24 = 29 bit trailing zeros. -// 2. Perform y*log2(x) = n+y' by simulating multi-precision -// arithmetic, where |y'|<=0.5. -// 3. Return x**y = 2**n*exp(y'*log2) -// -// Special cases: -// 1. (anything) ** 0 is 1 -// 2. 1 ** (anything) is 1 -// 3. (anything except 1) ** NAN is NAN -// 4. NAN ** (anything except 0) is NAN -// 5. +-(|x| > 1) ** +INF is +INF -// 6. +-(|x| > 1) ** -INF is +0 -// 7. +-(|x| < 1) ** +INF is +0 -// 8. +-(|x| < 1) ** -INF is +INF -// 9. -1 ** +-INF is 1 -// 10. +0 ** (+anything except 0, NAN) is +0 -// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 -// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero -// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero -// 14. -0 ** (+odd integer) is -0 -// 15. -0 ** (-odd integer) is -INF, raise divbyzero -// 16. +INF ** (+anything except 0,NAN) is +INF -// 17. +INF ** (-anything except 0,NAN) is +0 -// 18. -INF ** (+odd integer) is -INF -// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) -// 20. (anything) ** 1 is (anything) -// 21. (anything) ** -1 is 1/(anything) -// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) -// 23. (-anything except 0 and inf) ** (non-integer) is NAN -// -// Accuracy: -// pow(x,y) returns x**y nearly rounded. In particular -// pow(integer,integer) -// always returns the correct integer provided it is -// representable. -// -// Constants : -// The hexadecimal values are the intended ones for the following -// constants. The decimal values may be used, provided that the -// compiler will convert from decimal to binary accurately enough -// to produce the hexadecimal values shown. -// -use super::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; - -const BP: [f64; 2] = [1.0, 1.5]; -const DP_H: [f64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ -const DP_L: [f64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ -const TWO53: f64 = 9007199254740992.0; /* 0x43400000_00000000 */ -const HUGE: f64 = 1.0e300; -const TINY: f64 = 1.0e-300; - -// poly coefs for (3/2)*(log(x)-2s-2/3*s**3: -const L1: f64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ -const L2: f64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ -const L3: f64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ -const L4: f64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ -const L5: f64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ -const L6: f64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ -const P1: f64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ -const P2: f64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ -const P3: f64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ -const P4: f64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ -const P5: f64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ -const LG2: f64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ -const LG2_H: f64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ -const LG2_L: f64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ -const OVT: f64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ -const CP: f64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ -const CP_H: f64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ -const CP_L: f64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ -const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ -const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ -const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ - -/// Returns `x` to the power of `y` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn pow(x: f64, y: f64) -> f64 { - let t1: f64; - let t2: f64; - - let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); - let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); - - let mut ix: i32 = hx & 0x7fffffff_i32; - let iy: i32 = hy & 0x7fffffff_i32; - - /* x**0 = 1, even if x is NaN */ - if ((iy as u32) | ly) == 0 { - return 1.0; - } - - /* 1**y = 1, even if y is NaN */ - if hx == 0x3ff00000 && lx == 0 { - return 1.0; - } - - /* NaN if either arg is NaN */ - if ix > 0x7ff00000 - || (ix == 0x7ff00000 && lx != 0) - || iy > 0x7ff00000 - || (iy == 0x7ff00000 && ly != 0) - { - return x + y; - } - - /* determine if y is an odd int when x < 0 - * yisint = 0 ... y is not an integer - * yisint = 1 ... y is an odd int - * yisint = 2 ... y is an even int - */ - let mut yisint: i32 = 0; - let mut k: i32; - let mut j: i32; - if hx < 0 { - if iy >= 0x43400000 { - yisint = 2; /* even integer y */ - } else if iy >= 0x3ff00000 { - k = (iy >> 20) - 0x3ff; /* exponent */ - - if k > 20 { - j = (ly >> (52 - k)) as i32; - - if (j << (52 - k)) == (ly as i32) { - yisint = 2 - (j & 1); - } - } else if ly == 0 { - j = iy >> (20 - k); - - if (j << (20 - k)) == iy { - yisint = 2 - (j & 1); - } - } - } - } - - if ly == 0 { - /* special value of y */ - if iy == 0x7ff00000 { - /* y is +-inf */ - - return if ((ix - 0x3ff00000) | (lx as i32)) == 0 { - /* (-1)**+-inf is 1 */ - 1.0 - } else if ix >= 0x3ff00000 { - /* (|x|>1)**+-inf = inf,0 */ - if hy >= 0 { y } else { 0.0 } - } else { - /* (|x|<1)**+-inf = 0,inf */ - if hy >= 0 { 0.0 } else { -y } - }; - } - - if iy == 0x3ff00000 { - /* y is +-1 */ - return if hy >= 0 { x } else { 1.0 / x }; - } - - if hy == 0x40000000 { - /* y is 2 */ - return x * x; - } - - if hy == 0x3fe00000 { - /* y is 0.5 */ - if hx >= 0 { - /* x >= +0 */ - return sqrt(x); - } - } - } - - let mut ax: f64 = fabs(x); - if lx == 0 { - /* special value of x */ - if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { - /* x is +-0,+-inf,+-1 */ - let mut z: f64 = ax; - - if hy < 0 { - /* z = (1/|x|) */ - z = 1.0 / z; - } - - if hx < 0 { - if ((ix - 0x3ff00000) | yisint) == 0 { - z = (z - z) / (z - z); /* (-1)**non-int is NaN */ - } else if yisint == 1 { - z = -z; /* (x<0)**odd = -(|x|**odd) */ - } - } - - return z; - } - } - - let mut s: f64 = 1.0; /* sign of result */ - if hx < 0 { - if yisint == 0 { - /* (x<0)**(non-int) is NaN */ - return (x - x) / (x - x); - } - - if yisint == 1 { - /* (x<0)**(odd int) */ - s = -1.0; - } - } - - /* |y| is HUGE */ - if iy > 0x41e00000 { - /* if |y| > 2**31 */ - if iy > 0x43f00000 { - /* if |y| > 2**64, must o/uflow */ - if ix <= 0x3fefffff { - return if hy < 0 { HUGE * HUGE } else { TINY * TINY }; - } - - if ix >= 0x3ff00000 { - return if hy > 0 { HUGE * HUGE } else { TINY * TINY }; - } - } - - /* over/underflow if x is not close to one */ - if ix < 0x3fefffff { - return if hy < 0 { s * HUGE * HUGE } else { s * TINY * TINY }; - } - if ix > 0x3ff00000 { - return if hy > 0 { s * HUGE * HUGE } else { s * TINY * TINY }; - } - - /* now |1-x| is TINY <= 2**-20, suffice to compute - log(x) by x-x^2/2+x^3/3-x^4/4 */ - let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ - let w: f64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); - let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ - let v: f64 = t * IVLN2_L - w * IVLN2; - t1 = with_set_low_word(u + v, 0); - t2 = v - (t1 - u); - } else { - // double ss,s2,s_h,s_l,t_h,t_l; - let mut n: i32 = 0; - - if ix < 0x00100000 { - /* take care subnormal number */ - ax *= TWO53; - n -= 53; - ix = get_high_word(ax) as i32; - } - - n += (ix >> 20) - 0x3ff; - j = ix & 0x000fffff; - - /* determine interval */ - let k: i32; - ix = j | 0x3ff00000; /* normalize ix */ - if j <= 0x3988E { - /* |x|> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18), - ); - let t_l: f64 = ax - (t_h - i!(BP, k as usize)); - let s_l: f64 = v * ((u - s_h * t_h) - s_h * t_l); - - /* compute log(ax) */ - let s2: f64 = ss * ss; - let mut r: f64 = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); - r += s_l * (s_h + ss); - let s2: f64 = s_h * s_h; - let t_h: f64 = with_set_low_word(3.0 + s2 + r, 0); - let t_l: f64 = r - ((t_h - 3.0) - s2); - - /* u+v = ss*(1+...) */ - let u: f64 = s_h * t_h; - let v: f64 = s_l * t_h + t_l * ss; - - /* 2/(3log2)*(ss+...) */ - let p_h: f64 = with_set_low_word(u + v, 0); - let p_l = v - (p_h - u); - let z_h: f64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ - let z_l: f64 = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); - - /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ - let t: f64 = n as f64; - t1 = with_set_low_word(((z_h + z_l) + i!(DP_H, k as usize)) + t, 0); - t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); - } - - /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ - let y1: f64 = with_set_low_word(y, 0); - let p_l: f64 = (y - y1) * t1 + y * t2; - let mut p_h: f64 = y1 * t1; - let z: f64 = p_l + p_h; - let mut j: i32 = (z.to_bits() >> 32) as i32; - let i: i32 = z.to_bits() as i32; - // let (j, i): (i32, i32) = ((z.to_bits() >> 32) as i32, z.to_bits() as i32); - - if j >= 0x40900000 { - /* z >= 1024 */ - if (j - 0x40900000) | i != 0 { - /* if z > 1024 */ - return s * HUGE * HUGE; /* overflow */ - } - - if p_l + OVT > z - p_h { - return s * HUGE * HUGE; /* overflow */ - } - } else if (j & 0x7fffffff) >= 0x4090cc00 { - /* z <= -1075 */ - // FIXME: instead of abs(j) use unsigned j - - if (((j as u32) - 0xc090cc00) | (i as u32)) != 0 { - /* z < -1075 */ - return s * TINY * TINY; /* underflow */ - } - - if p_l <= z - p_h { - return s * TINY * TINY; /* underflow */ - } - } - - /* compute 2**(p_h+p_l) */ - let i: i32 = j & 0x7fffffff_i32; - k = (i >> 20) - 0x3ff; - let mut n: i32 = 0; - - if i > 0x3fe00000 { - /* if |z| > 0.5, set n = [z+0.5] */ - n = j + (0x00100000 >> (k + 1)); - k = ((n & 0x7fffffff) >> 20) - 0x3ff; /* new k for n */ - let t: f64 = with_set_high_word(0.0, (n & !(0x000fffff >> k)) as u32); - n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); - if j < 0 { - n = -n; - } - p_h -= t; - } - - let t: f64 = with_set_low_word(p_l + p_h, 0); - let u: f64 = t * LG2_H; - let v: f64 = (p_l - (t - p_h)) * LG2 + t * LG2_L; - let mut z: f64 = u + v; - let w: f64 = v - (z - u); - let t: f64 = z * z; - let t1: f64 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); - let r: f64 = (z * t1) / (t1 - 2.0) - (w + z * w); - z = 1.0 - (r - z); - j = get_high_word(z) as i32; - j += n << 20; - - if (j >> 20) <= 0 { - /* subnormal output */ - z = scalbn(z, n); - } else { - z = with_set_high_word(z, j as u32); - } - - s * z -} - -#[cfg(test)] -mod tests { - extern crate core; - - use self::core::f64::consts::{E, PI}; - use super::pow; - - const POS_ZERO: &[f64] = &[0.0]; - const NEG_ZERO: &[f64] = &[-0.0]; - const POS_ONE: &[f64] = &[1.0]; - const NEG_ONE: &[f64] = &[-1.0]; - const POS_FLOATS: &[f64] = &[99.0 / 70.0, E, PI]; - const NEG_FLOATS: &[f64] = &[-99.0 / 70.0, -E, -PI]; - const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), f64::MIN_POSITIVE, f64::EPSILON]; - const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -f64::MIN_POSITIVE, -f64::EPSILON]; - const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, f64::MAX]; - const NEG_EVENS: &[f64] = &[f64::MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; - const POS_ODDS: &[f64] = &[3.0, 7.0]; - const NEG_ODDS: &[f64] = &[-7.0, -3.0]; - const NANS: &[f64] = &[f64::NAN]; - const POS_INF: &[f64] = &[f64::INFINITY]; - const NEG_INF: &[f64] = &[f64::NEG_INFINITY]; - - const ALL: &[&[f64]] = &[ - POS_ZERO, - NEG_ZERO, - NANS, - NEG_SMALL_FLOATS, - POS_SMALL_FLOATS, - NEG_FLOATS, - POS_FLOATS, - NEG_EVENS, - POS_EVENS, - NEG_ODDS, - POS_ODDS, - NEG_INF, - POS_INF, - NEG_ONE, - POS_ONE, - ]; - const POS: &[&[f64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF]; - const NEG: &[&[f64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF]; - - fn pow_test(base: f64, exponent: f64, expected: f64) { - let res = pow(base, exponent); - assert!( - if expected.is_nan() { res.is_nan() } else { pow(base, exponent) == expected }, - "{} ** {} was {} instead of {}", - base, - exponent, - res, - expected - ); - } - - fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { - sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); - } - - fn test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) { - sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); - } - - fn test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) { - sets.iter().for_each(|s| { - s.iter().for_each(|val| { - let exp = expected(*val); - let res = computed(*val); - - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let exp = force_eval!(exp); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let res = force_eval!(res); - assert!( - if exp.is_nan() { res.is_nan() } else { exp == res }, - "test for {} was {} instead of {}", - val, - res, - exp - ); - }) - }); - } - - #[test] - fn zero_as_exponent() { - test_sets_as_base(ALL, 0.0, 1.0); - test_sets_as_base(ALL, -0.0, 1.0); - } - - #[test] - fn one_as_base() { - test_sets_as_exponent(1.0, ALL, 1.0); - } - - #[test] - fn nan_inputs() { - // NAN as the base: - // (f64::NAN ^ anything *but 0* should be f64::NAN) - test_sets_as_exponent(f64::NAN, &ALL[2..], f64::NAN); - - // f64::NAN as the exponent: - // (anything *but 1* ^ f64::NAN should be f64::NAN) - test_sets_as_base(&ALL[..(ALL.len() - 2)], f64::NAN, f64::NAN); - } - - #[test] - fn infinity_as_base() { - // Positive Infinity as the base: - // (+Infinity ^ positive anything but 0 and f64::NAN should be +Infinity) - test_sets_as_exponent(f64::INFINITY, &POS[1..], f64::INFINITY); - - // (+Infinity ^ negative anything except 0 and f64::NAN should be 0.0) - test_sets_as_exponent(f64::INFINITY, &NEG[1..], 0.0); - - // Negative Infinity as the base: - // (-Infinity ^ positive odd ints should be -Infinity) - test_sets_as_exponent(f64::NEG_INFINITY, &[POS_ODDS], f64::NEG_INFINITY); - - // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) - // We can lump in pos/neg odd ints here because they don't seem to - // cause panics (div by zero) in release mode (I think). - test_sets(ALL, &|v: f64| pow(f64::NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); - } - - #[test] - fn infinity_as_exponent() { - // Positive/Negative base greater than 1: - // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes f64::NAN as the base) - test_sets_as_base(&ALL[5..(ALL.len() - 2)], f64::INFINITY, f64::INFINITY); - - // (pos/neg > 1 ^ -Infinity should be 0.0) - test_sets_as_base(&ALL[5..ALL.len() - 2], f64::NEG_INFINITY, 0.0); - - // Positive/Negative base less than 1: - let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS]; - - // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes f64::NAN as the base) - test_sets_as_base(base_below_one, f64::INFINITY, 0.0); - - // (pos/neg < 1 ^ -Infinity should be Infinity) - test_sets_as_base(base_below_one, f64::NEG_INFINITY, f64::INFINITY); - - // Positive/Negative 1 as the base: - // (pos/neg 1 ^ Infinity should be 1) - test_sets_as_base(&[NEG_ONE, POS_ONE], f64::INFINITY, 1.0); - - // (pos/neg 1 ^ -Infinity should be 1) - test_sets_as_base(&[NEG_ONE, POS_ONE], f64::NEG_INFINITY, 1.0); - } - - #[test] - fn zero_as_base() { - // Positive Zero as the base: - // (+0 ^ anything positive but 0 and f64::NAN should be +0) - test_sets_as_exponent(0.0, &POS[1..], 0.0); - - // (+0 ^ anything negative but 0 and f64::NAN should be Infinity) - // (this should panic because we're dividing by zero) - test_sets_as_exponent(0.0, &NEG[1..], f64::INFINITY); - - // Negative Zero as the base: - // (-0 ^ anything positive but 0, f64::NAN, and odd ints should be +0) - test_sets_as_exponent(-0.0, &POS[3..], 0.0); - - // (-0 ^ anything negative but 0, f64::NAN, and odd ints should be Infinity) - // (should panic because of divide by zero) - test_sets_as_exponent(-0.0, &NEG[3..], f64::INFINITY); - - // (-0 ^ positive odd ints should be -0) - test_sets_as_exponent(-0.0, &[POS_ODDS], -0.0); - - // (-0 ^ negative odd ints should be -Infinity) - // (should panic because of divide by zero) - test_sets_as_exponent(-0.0, &[NEG_ODDS], f64::NEG_INFINITY); - } - - #[test] - fn special_cases() { - // One as the exponent: - // (anything ^ 1 should be anything - i.e. the base) - test_sets(ALL, &|v: f64| pow(v, 1.0), &|v: f64| v); - - // Negative One as the exponent: - // (anything ^ -1 should be 1/anything) - test_sets(ALL, &|v: f64| pow(v, -1.0), &|v: f64| 1.0 / v); - - // Factoring -1 out: - // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| { - int_set.iter().for_each(|int| { - test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| pow(-1.0, *int) * pow(v, *int)); - }) - }); - - // Negative base (imaginary results): - // (-anything except 0 and Infinity ^ non-integer should be NAN) - NEG[1..(NEG.len() - 1)].iter().for_each(|set| { - set.iter().for_each(|val| { - test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| f64::NAN); - }) - }); - } - - #[test] - fn normal_cases() { - assert_eq!(pow(2.0, 20.0), (1 << 20) as f64); - assert_eq!(pow(-1.0, 9.0), -1.0); - assert!(pow(-1.0, 2.2).is_nan()); - assert!(pow(-1.0, -1.14).is_nan()); - } -} diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs deleted file mode 100644 index 839c6c23d43..00000000000 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ /dev/null @@ -1,335 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::cmp::Ordering; - -use super::{fabsf, scalbnf, sqrtf}; - -const BP: [f32; 2] = [1.0, 1.5]; -const DP_H: [f32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ -const DP_L: [f32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ -const TWO24: f32 = 16777216.0; /* 0x4b800000 */ -const HUGE: f32 = 1.0e30; -const TINY: f32 = 1.0e-30; -const L1: f32 = 6.0000002384e-01; /* 0x3f19999a */ -const L2: f32 = 4.2857143283e-01; /* 0x3edb6db7 */ -const L3: f32 = 3.3333334327e-01; /* 0x3eaaaaab */ -const L4: f32 = 2.7272811532e-01; /* 0x3e8ba305 */ -const L5: f32 = 2.3066075146e-01; /* 0x3e6c3255 */ -const L6: f32 = 2.0697501302e-01; /* 0x3e53f142 */ -const P1: f32 = 1.6666667163e-01; /* 0x3e2aaaab */ -const P2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ -const P3: f32 = 6.6137559770e-05; /* 0x388ab355 */ -const P4: f32 = -1.6533901999e-06; /* 0xb5ddea0e */ -const P5: f32 = 4.1381369442e-08; /* 0x3331bb4c */ -const LG2: f32 = 6.9314718246e-01; /* 0x3f317218 */ -const LG2_H: f32 = 6.93145752e-01; /* 0x3f317200 */ -const LG2_L: f32 = 1.42860654e-06; /* 0x35bfbe8c */ -const OVT: f32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ -const CP: f32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ -const CP_H: f32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ -const CP_L: f32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ -const IVLN2: f32 = 1.4426950216e+00; -const IVLN2_H: f32 = 1.4426879883e+00; -const IVLN2_L: f32 = 7.0526075433e-06; - -/// Returns `x` to the power of `y` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn powf(x: f32, y: f32) -> f32 { - let mut z: f32; - let mut ax: f32; - let z_h: f32; - let z_l: f32; - let mut p_h: f32; - let mut p_l: f32; - let y1: f32; - let mut t1: f32; - let t2: f32; - let mut r: f32; - let s: f32; - let mut sn: f32; - let mut t: f32; - let mut u: f32; - let mut v: f32; - let mut w: f32; - let i: i32; - let mut j: i32; - let mut k: i32; - let mut yisint: i32; - let mut n: i32; - let hx: i32; - let hy: i32; - let mut ix: i32; - let iy: i32; - let mut is: i32; - - hx = x.to_bits() as i32; - hy = y.to_bits() as i32; - - ix = hx & 0x7fffffff; - iy = hy & 0x7fffffff; - - /* x**0 = 1, even if x is NaN */ - if iy == 0 { - return 1.0; - } - - /* 1**y = 1, even if y is NaN */ - if hx == 0x3f800000 { - return 1.0; - } - - /* NaN if either arg is NaN */ - if ix > 0x7f800000 || iy > 0x7f800000 { - return x + y; - } - - /* determine if y is an odd int when x < 0 - * yisint = 0 ... y is not an integer - * yisint = 1 ... y is an odd int - * yisint = 2 ... y is an even int - */ - yisint = 0; - if hx < 0 { - if iy >= 0x4b800000 { - yisint = 2; /* even integer y */ - } else if iy >= 0x3f800000 { - k = (iy >> 23) - 0x7f; /* exponent */ - j = iy >> (23 - k); - if (j << (23 - k)) == iy { - yisint = 2 - (j & 1); - } - } - } - - /* special value of y */ - if iy == 0x7f800000 { - /* y is +-inf */ - match ix.cmp(&0x3f800000) { - /* (-1)**+-inf is 1 */ - Ordering::Equal => return 1.0, - /* (|x|>1)**+-inf = inf,0 */ - Ordering::Greater => return if hy >= 0 { y } else { 0.0 }, - /* (|x|<1)**+-inf = 0,inf */ - Ordering::Less => return if hy >= 0 { 0.0 } else { -y }, - } - } - if iy == 0x3f800000 { - /* y is +-1 */ - return if hy >= 0 { x } else { 1.0 / x }; - } - - if hy == 0x40000000 { - /* y is 2 */ - return x * x; - } - - if hy == 0x3f000000 - /* y is 0.5 */ - && hx >= 0 - { - /* x >= +0 */ - return sqrtf(x); - } - - ax = fabsf(x); - /* special value of x */ - if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 { - /* x is +-0,+-inf,+-1 */ - z = ax; - if hy < 0 { - /* z = (1/|x|) */ - z = 1.0 / z; - } - - if hx < 0 { - if ((ix - 0x3f800000) | yisint) == 0 { - z = (z - z) / (z - z); /* (-1)**non-int is NaN */ - } else if yisint == 1 { - z = -z; /* (x<0)**odd = -(|x|**odd) */ - } - } - return z; - } - - sn = 1.0; /* sign of result */ - if hx < 0 { - if yisint == 0 { - /* (x<0)**(non-int) is NaN */ - return (x - x) / (x - x); - } - - if yisint == 1 { - /* (x<0)**(odd int) */ - sn = -1.0; - } - } - - /* |y| is HUGE */ - if iy > 0x4d000000 { - /* if |y| > 2**27 */ - /* over/underflow if x is not close to one */ - if ix < 0x3f7ffff8 { - return if hy < 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; - } - - if ix > 0x3f800007 { - return if hy > 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; - } - - /* now |1-x| is TINY <= 2**-20, suffice to compute - log(x) by x-x^2/2+x^3/3-x^4/4 */ - t = ax - 1.; /* t has 20 trailing zeros */ - w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); - u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ - v = t * IVLN2_L - w * IVLN2; - t1 = u + v; - is = t1.to_bits() as i32; - t1 = f32::from_bits(is as u32 & 0xfffff000); - t2 = v - (t1 - u); - } else { - let mut s2: f32; - let mut s_h: f32; - let s_l: f32; - let mut t_h: f32; - let mut t_l: f32; - - n = 0; - /* take care subnormal number */ - if ix < 0x00800000 { - ax *= TWO24; - n -= 24; - ix = ax.to_bits() as i32; - } - n += ((ix) >> 23) - 0x7f; - j = ix & 0x007fffff; - /* determine interval */ - ix = j | 0x3f800000; /* normalize ix */ - if j <= 0x1cc471 { - /* |x|> 1) & 0xfffff000) | 0x20000000) as i32; - t_h = f32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); - t_l = ax - (t_h - i!(BP, k as usize)); - s_l = v * ((u - s_h * t_h) - s_h * t_l); - /* compute log(ax) */ - s2 = s * s; - r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); - r += s_l * (s_h + s); - s2 = s_h * s_h; - t_h = 3.0 + s2 + r; - is = t_h.to_bits() as i32; - t_h = f32::from_bits(is as u32 & 0xfffff000); - t_l = r - ((t_h - 3.0) - s2); - /* u+v = s*(1+...) */ - u = s_h * t_h; - v = s_l * t_h + t_l * s; - /* 2/(3log2)*(s+...) */ - p_h = u + v; - is = p_h.to_bits() as i32; - p_h = f32::from_bits(is as u32 & 0xfffff000); - p_l = v - (p_h - u); - z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ - z_l = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); - /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ - t = n as f32; - t1 = ((z_h + z_l) + i!(DP_H, k as usize)) + t; - is = t1.to_bits() as i32; - t1 = f32::from_bits(is as u32 & 0xfffff000); - t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); - }; - - /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ - is = y.to_bits() as i32; - y1 = f32::from_bits(is as u32 & 0xfffff000); - p_l = (y - y1) * t1 + y * t2; - p_h = y1 * t1; - z = p_l + p_h; - j = z.to_bits() as i32; - if j > 0x43000000 { - /* if z > 128 */ - return sn * HUGE * HUGE; /* overflow */ - } else if j == 0x43000000 { - /* if z == 128 */ - if p_l + OVT > z - p_h { - return sn * HUGE * HUGE; /* overflow */ - } - } else if (j & 0x7fffffff) > 0x43160000 { - /* z < -150 */ - // FIXME: check should be (uint32_t)j > 0xc3160000 - return sn * TINY * TINY; /* underflow */ - } else if j as u32 == 0xc3160000 - /* z == -150 */ - && p_l <= z - p_h - { - return sn * TINY * TINY; /* underflow */ - } - - /* - * compute 2**(p_h+p_l) - */ - i = j & 0x7fffffff; - k = (i >> 23) - 0x7f; - n = 0; - if i > 0x3f000000 { - /* if |z| > 0.5, set n = [z+0.5] */ - n = j + (0x00800000 >> (k + 1)); - k = ((n & 0x7fffffff) >> 23) - 0x7f; /* new k for n */ - t = f32::from_bits(n as u32 & !(0x007fffff >> k)); - n = ((n & 0x007fffff) | 0x00800000) >> (23 - k); - if j < 0 { - n = -n; - } - p_h -= t; - } - t = p_l + p_h; - is = t.to_bits() as i32; - t = f32::from_bits(is as u32 & 0xffff8000); - u = t * LG2_H; - v = (p_l - (t - p_h)) * LG2 + t * LG2_L; - z = u + v; - w = v - (z - u); - t = z * z; - t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); - r = (z * t1) / (t1 - 2.0) - (w + z * w); - z = 1.0 - (r - z); - j = z.to_bits() as i32; - j += n << 23; - if (j >> 23) <= 0 { - /* subnormal output */ - z = scalbnf(z, n); - } else { - z = f32::from_bits(j as u32); - } - sn * z -} diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs deleted file mode 100644 index 917e90819a5..00000000000 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ /dev/null @@ -1,223 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunPro, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== -// -// Optimized by Bruce D. Evans. */ -use super::rem_pio2_large; - -// #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 -// #define EPS DBL_EPSILON -const EPS: f64 = 2.2204460492503131e-16; -// #elif FLT_EVAL_METHOD==2 -// #define EPS LDBL_EPSILON -// #endif - -// TODO: Support FLT_EVAL_METHOD? - -const TO_INT: f64 = 1.5 / EPS; -/// 53 bits of 2/pi -const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ -/// first 33 bits of pi/2 -const PIO2_1: f64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ -/// pi/2 - PIO2_1 -const PIO2_1T: f64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ -/// second 33 bits of pi/2 -const PIO2_2: f64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ -/// pi/2 - (PIO2_1+PIO2_2) -const PIO2_2T: f64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ -/// third 33 bits of pi/2 -const PIO2_3: f64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ -/// pi/2 - (PIO2_1+PIO2_2+PIO2_3) -const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ - -// return the remainder of x rem pi/2 in y[0]+y[1] -// use rem_pio2_large() for large x -// -// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { - let x1p24 = f64::from_bits(0x4170000000000000); - - let sign = (f64::to_bits(x) >> 63) as i32; - let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; - - fn medium(x: f64, ix: u32) -> (i32, f64, f64) { - /* rint(x/(pi/2)), Assume round-to-nearest. */ - let tmp = x * INV_PIO2 + TO_INT; - // force rounding of tmp to it's storage format on x87 to avoid - // excess precision issues. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let tmp = force_eval!(tmp); - let f_n = tmp - TO_INT; - let n = f_n as i32; - let mut r = x - f_n * PIO2_1; - let mut w = f_n * PIO2_1T; /* 1st round, good to 85 bits */ - let mut y0 = r - w; - let ui = f64::to_bits(y0); - let ey = (ui >> 52) as i32 & 0x7ff; - let ex = (ix >> 20) as i32; - if ex - ey > 16 { - /* 2nd round, good to 118 bits */ - let t = r; - w = f_n * PIO2_2; - r = t - w; - w = f_n * PIO2_2T - ((t - r) - w); - y0 = r - w; - let ey = (f64::to_bits(y0) >> 52) as i32 & 0x7ff; - if ex - ey > 49 { - /* 3rd round, good to 151 bits, covers all cases */ - let t = r; - w = f_n * PIO2_3; - r = t - w; - w = f_n * PIO2_3T - ((t - r) - w); - y0 = r - w; - } - } - let y1 = (r - y0) - w; - (n, y0, y1) - } - - if ix <= 0x400f6a7a { - /* |x| ~<= 5pi/4 */ - if (ix & 0xfffff) == 0x921fb { - /* |x| ~= pi/2 or 2pi/2 */ - return medium(x, ix); /* cancellation -- use medium case */ - } - if ix <= 0x4002d97c { - /* |x| ~<= 3pi/4 */ - if sign == 0 { - let z = x - PIO2_1; /* one round good to 85 bits */ - let y0 = z - PIO2_1T; - let y1 = (z - y0) - PIO2_1T; - return (1, y0, y1); - } else { - let z = x + PIO2_1; - let y0 = z + PIO2_1T; - let y1 = (z - y0) + PIO2_1T; - return (-1, y0, y1); - } - } else if sign == 0 { - let z = x - 2.0 * PIO2_1; - let y0 = z - 2.0 * PIO2_1T; - let y1 = (z - y0) - 2.0 * PIO2_1T; - return (2, y0, y1); - } else { - let z = x + 2.0 * PIO2_1; - let y0 = z + 2.0 * PIO2_1T; - let y1 = (z - y0) + 2.0 * PIO2_1T; - return (-2, y0, y1); - } - } - if ix <= 0x401c463b { - /* |x| ~<= 9pi/4 */ - if ix <= 0x4015fdbc { - /* |x| ~<= 7pi/4 */ - if ix == 0x4012d97c { - /* |x| ~= 3pi/2 */ - return medium(x, ix); - } - if sign == 0 { - let z = x - 3.0 * PIO2_1; - let y0 = z - 3.0 * PIO2_1T; - let y1 = (z - y0) - 3.0 * PIO2_1T; - return (3, y0, y1); - } else { - let z = x + 3.0 * PIO2_1; - let y0 = z + 3.0 * PIO2_1T; - let y1 = (z - y0) + 3.0 * PIO2_1T; - return (-3, y0, y1); - } - } else { - if ix == 0x401921fb { - /* |x| ~= 4pi/2 */ - return medium(x, ix); - } - if sign == 0 { - let z = x - 4.0 * PIO2_1; - let y0 = z - 4.0 * PIO2_1T; - let y1 = (z - y0) - 4.0 * PIO2_1T; - return (4, y0, y1); - } else { - let z = x + 4.0 * PIO2_1; - let y0 = z + 4.0 * PIO2_1T; - let y1 = (z - y0) + 4.0 * PIO2_1T; - return (-4, y0, y1); - } - } - } - if ix < 0x413921fb { - /* |x| ~< 2^20*(pi/2), medium size */ - return medium(x, ix); - } - /* - * all other (large) arguments - */ - if ix >= 0x7ff00000 { - /* x is inf or NaN */ - let y0 = x - x; - let y1 = y0; - return (0, y0, y1); - } - /* set z = scalbn(|x|,-ilogb(x)+23) */ - let mut ui = f64::to_bits(x); - ui &= (!1) >> 12; - ui |= (0x3ff + 23) << 52; - let mut z = f64::from_bits(ui); - let mut tx = [0.0; 3]; - for i in 0..2 { - i!(tx,i, =, z as i32 as f64); - z = (z - i!(tx, i)) * x1p24; - } - i!(tx,2, =, z); - /* skip zero terms, first term is non-zero */ - let mut i = 2; - while i != 0 && i!(tx, i) == 0.0 { - i -= 1; - } - let mut ty = [0.0; 3]; - let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix as i32) >> 20) - (0x3ff + 23), 1); - if sign != 0 { - return (-n, -i!(ty, 0), -i!(ty, 1)); - } - (n, i!(ty, 0), i!(ty, 1)) -} - -#[cfg(test)] -mod tests { - use super::rem_pio2; - - #[test] - // FIXME(correctness): inaccurate results on i586 - #[cfg_attr(all(target_arch = "x86", not(target_feature = "sse")), ignore)] - fn test_near_pi() { - let arg = 3.141592025756836; - let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, -6.278329573009626e-7, -2.1125998133974653e-23)); - let arg = 3.141592033207416; - let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, -6.20382377148128e-7, -2.1125998133974653e-23)); - let arg = 3.141592144966125; - let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, -5.086236681942706e-7, -2.1125998133974653e-23)); - let arg = 3.141592979431152; - let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, 3.2584135866119817e-7, -2.1125998133974653e-23)); - } - - #[test] - fn test_overflow_b9b847() { - let _ = rem_pio2(-3054214.5490637687); - } - - #[test] - fn test_overflow_4747b9() { - let _ = rem_pio2(917340800458.2274); - } -} diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs deleted file mode 100644 index 6d679bbe98c..00000000000 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ /dev/null @@ -1,468 +0,0 @@ -#![allow(unused_unsafe)] -/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{floor, scalbn}; - -// initial value for jk -const INIT_JK: [usize; 4] = [3, 4, 4, 6]; - -// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi -// -// integer array, contains the (24*i)-th to (24*i+23)-th -// bit of 2/pi after binary point. The corresponding -// floating value is -// -// ipio2[i] * 2^(-24(i+1)). -// -// NB: This table must have at least (e0-3)/24 + jk terms. -// For quad precision (e0 <= 16360, jk = 6), this is 686. -#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] -const IPIO2: [i32; 66] = [ - 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, - 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, - 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, - 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, - 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, - 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, - 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, - 0x73A8C9, 0x60E27B, 0xC08C6B, -]; - -#[cfg(target_pointer_width = "64")] -const IPIO2: [i32; 690] = [ - 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, - 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, - 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, - 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, - 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, - 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, - 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, - 0x73A8C9, 0x60E27B, 0xC08C6B, 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, - 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, 0xDE4F98, 0x327DBB, 0xC33D26, - 0xEF6B1E, 0x5EF89F, 0x3A1F35, 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, - 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, 0x467D86, 0x2D71E3, 0x9AC69B, - 0x006233, 0x7CD2B4, 0x97A7B4, 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, - 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, 0xCB2324, 0x778AD6, 0x23545A, - 0xB91F00, 0x1B0AF1, 0xDFCE19, 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, - 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, 0xDE3B58, 0x929BDE, 0x2822D2, - 0xE88628, 0x4D58E2, 0x32CAC6, 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, - 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, 0xD36710, 0xD8DDAA, 0x425FAE, - 0xCE616A, 0xA4280A, 0xB499D3, 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, - 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, 0x36D9CA, 0xD2A828, 0x8D61C2, - 0x77C912, 0x142604, 0x9B4612, 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, - 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, 0xC3E7B3, 0x28F8C7, 0x940593, - 0x3E71C1, 0xB3092E, 0xF3450B, 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, - 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, 0x9794E8, 0x84E6E2, 0x973199, - 0x6BED88, 0x365F5F, 0x0EFDBB, 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, - 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, 0x90AA47, 0x02E774, 0x24D6BD, - 0xA67DF7, 0x72486E, 0xEF169F, 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, - 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, 0x10D86D, 0x324832, 0x754C5B, - 0xD4714E, 0x6E5445, 0xC1090B, 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, - 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, 0x6AE290, 0x89D988, 0x50722C, - 0xBEA404, 0x940777, 0x7030F3, 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, - 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, 0x3BDF08, 0x2B3715, 0xA0805C, - 0x93805A, 0x921110, 0xD8E80F, 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, - 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, 0xAA140A, 0x2F2689, 0x768364, - 0x333B09, 0x1A940E, 0xAA3A51, 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, - 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, 0x5BC3D8, 0xC492F5, 0x4BADC6, - 0xA5CA4E, 0xCD37A7, 0x36A9E6, 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, - 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, 0x306529, 0xBF5657, 0x3AFF47, - 0xB9F96A, 0xF3BE75, 0xDF9328, 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, - 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, 0xA8654F, 0xA5C1D2, 0x0F3F0B, - 0xCD785B, 0x76F923, 0x048B7B, 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, - 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, 0xDA4886, 0xA05DF7, 0xF480C6, - 0x2FF0AC, 0x9AECDD, 0xBC5C3F, 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, - 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, 0x2A1216, 0x2DB7DC, 0xFDE5FA, - 0xFEDB89, 0xFDBE89, 0x6C76E4, 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, - 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, 0x48D784, 0x16DF30, 0x432DC7, - 0x356125, 0xCE70C9, 0xB8CB30, 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, - 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, 0xC4F133, 0x5F6E13, 0xE4305D, - 0xA92E85, 0xC3B21D, 0x3632A1, 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, - 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, 0xCBDA11, 0xD0BE7D, 0xC1DB9B, - 0xBD17AB, 0x81A2CA, 0x5C6A08, 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, - 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, 0x4F6A68, 0xA82A4A, 0x5AC44F, - 0xBCF82D, 0x985AD7, 0x95C7F4, 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, - 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, 0xD0C0B2, 0x485551, 0x0EFB1E, - 0xC37295, 0x3B06A3, 0x3540C0, 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, - 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, 0x3C3ABA, 0x461846, 0x5F7555, - 0xF5BDD2, 0xC6926E, 0x5D2EAC, 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, - 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, 0x745D7C, 0xB2AD6B, 0x9D6ECD, - 0x7B723E, 0x6A11C6, 0xA9CFF7, 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, - 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, 0xBEFDFD, 0xEF4556, 0x367ED9, - 0x13D9EC, 0xB9BA8B, 0xFC97C4, 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, - 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, 0x9C2A3E, 0xCC5F11, 0x4A0BFD, - 0xFBF4E1, 0x6D3B8E, 0x2C86E2, 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, - 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, 0xCC2254, 0xDC552A, 0xD6C6C0, - 0x96190B, 0xB8701A, 0x649569, 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, - 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, 0x9B5861, 0xBC57E1, 0xC68351, - 0x103ED8, 0x4871DD, 0xDD1C2D, 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, - 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, 0x382682, 0x9BE7CA, 0xA40D51, - 0xB13399, 0x0ED7A9, 0x480569, 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, - 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, 0x5FD45E, 0xA4677B, 0x7AACBA, - 0xA2F655, 0x23882B, 0x55BA41, 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, - 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, 0xAE5ADB, 0x86C547, 0x624385, - 0x3B8621, 0x94792C, 0x876110, 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, - 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, 0xB1933D, 0x0B7CBD, 0xDC51A4, - 0x63DD27, 0xDDE169, 0x19949A, 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, - 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, 0x4D7E6F, 0x5119A5, 0xABF9B5, - 0xD6DF82, 0x61DD96, 0x023616, 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, - 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, -]; - -const PIO2: [f64; 8] = [ - 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ - 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ - 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ - 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ - 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ - 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ - 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ - 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ -]; - -// fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 -// -// Input parameters: -// x[] The input value (must be positive) is broken into nx -// pieces of 24-bit integers in double precision format. -// x[i] will be the i-th 24 bit of x. The scaled exponent -// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 -// match x's up to 24 bits. -// -// Example of breaking a double positive z into x[0]+x[1]+x[2]: -// e0 = ilogb(z)-23 -// z = scalbn(z,-e0) -// for i = 0,1,2 -// x[i] = floor(z) -// z = (z-x[i])*2**24 -// -// y[] ouput result in an array of double precision numbers. -// The dimension of y[] is: -// 24-bit precision 1 -// 53-bit precision 2 -// 64-bit precision 2 -// 113-bit precision 3 -// The actual value is the sum of them. Thus for 113-bit -// precison, one may have to do something like: -// -// long double t,w,r_head, r_tail; -// t = (long double)y[2] + (long double)y[1]; -// w = (long double)y[0]; -// r_head = t+w; -// r_tail = w - (r_head - t); -// -// e0 The exponent of x[0]. Must be <= 16360 or you need to -// expand the ipio2 table. -// -// prec an integer indicating the precision: -// 0 24 bits (single) -// 1 53 bits (double) -// 2 64 bits (extended) -// 3 113 bits (quad) -// -// Here is the description of some local variables: -// -// jk jk+1 is the initial number of terms of ipio2[] needed -// in the computation. The minimum and recommended value -// for jk is 3,4,4,6 for single, double, extended, and quad. -// jk+1 must be 2 larger than you might expect so that our -// recomputation test works. (Up to 24 bits in the integer -// part (the 24 bits of it that we compute) and 23 bits in -// the fraction part may be lost to cancelation before we -// recompute.) -// -// jz local integer variable indicating the number of -// terms of ipio2[] used. -// -// jx nx - 1 -// -// jv index for pointing to the suitable ipio2[] for the -// computation. In general, we want -// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 -// is an integer. Thus -// e0-3-24*jv >= 0 or (e0-3)/24 >= jv -// Hence jv = max(0,(e0-3)/24). -// -// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. -// -// q[] double array with integral value, representing the -// 24-bits chunk of the product of x and 2/pi. -// -// q0 the corresponding exponent of q[0]. Note that the -// exponent for q[i] would be q0-24*i. -// -// PIo2[] double precision array, obtained by cutting pi/2 -// into 24 bits chunks. -// -// f[] ipio2[] in floating point -// -// iq[] integer array by breaking up q[] in 24-bits chunk. -// -// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] -// -// ih integer. If >0 it indicates q[] is >= 0.5, hence -// it also indicates the *sign* of the result. - -/// Return the last three digits of N with y = x - N*pi/2 -/// so that |y| < pi/2. -/// -/// The method is to compute the integer (mod 8) and fraction parts of -/// (2/pi)*x without doing the full multiplication. In general we -/// skip the part of the product that are known to be a huge integer ( -/// more accurately, = 0 mod 8 ). Thus the number of operations are -/// independent of the exponent of the input. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { - let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 - let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) - - if cfg!(target_pointer_width = "64") { - debug_assert!(e0 <= 16360); - } - - let nx = x.len(); - - let mut fw: f64; - let mut n: i32; - let mut ih: i32; - let mut z: f64; - let mut f: [f64; 20] = [0.; 20]; - let mut fq: [f64; 20] = [0.; 20]; - let mut q: [f64; 20] = [0.; 20]; - let mut iq: [i32; 20] = [0; 20]; - - /* initialize jk*/ - let jk = i!(INIT_JK, prec); - let jp = jk; - - /* determine jx,jv,q0, note that 3>q0 */ - let jx = nx - 1; - let mut jv = div!(e0 - 3, 24); - if jv < 0 { - jv = 0; - } - let mut q0 = e0 - 24 * (jv + 1); - let jv = jv as usize; - - /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ - let mut j = (jv as i32) - (jx as i32); - let m = jx + jk; - for i in 0..=m { - i!(f, i, =, if j < 0 { - 0. - } else { - i!(IPIO2, j as usize) as f64 - }); - j += 1; - } - - /* compute q[0],q[1],...q[jk] */ - for i in 0..=jk { - fw = 0f64; - for j in 0..=jx { - fw += i!(x, j) * i!(f, jx + i - j); - } - i!(q, i, =, fw); - } - - let mut jz = jk; - - 'recompute: loop { - /* distill q[] into iq[] reversingly */ - let mut i = 0i32; - z = i!(q, jz); - for j in (1..=jz).rev() { - fw = (x1p_24 * z) as i32 as f64; - i!(iq, i as usize, =, (z - x1p24 * fw) as i32); - z = i!(q, j - 1) + fw; - i += 1; - } - - /* compute n */ - z = scalbn(z, q0); /* actual value of z */ - z -= 8.0 * floor(z * 0.125); /* trim off integer >= 8 */ - n = z as i32; - z -= n as f64; - ih = 0; - if q0 > 0 { - /* need iq[jz-1] to determine n */ - i = i!(iq, jz - 1) >> (24 - q0); - n += i; - i!(iq, jz - 1, -=, i << (24 - q0)); - ih = i!(iq, jz - 1) >> (23 - q0); - } else if q0 == 0 { - ih = i!(iq, jz - 1) >> 23; - } else if z >= 0.5 { - ih = 2; - } - - if ih > 0 { - /* q > 0.5 */ - n += 1; - let mut carry = 0i32; - for i in 0..jz { - /* compute 1-q */ - let j = i!(iq, i); - if carry == 0 { - if j != 0 { - carry = 1; - i!(iq, i, =, 0x1000000 - j); - } - } else { - i!(iq, i, =, 0xffffff - j); - } - } - if q0 > 0 { - /* rare case: chance is 1 in 12 */ - match q0 { - 1 => { - i!(iq, jz - 1, &=, 0x7fffff); - } - 2 => { - i!(iq, jz - 1, &=, 0x3fffff); - } - _ => {} - } - } - if ih == 2 { - z = 1. - z; - if carry != 0 { - z -= scalbn(1., q0); - } - } - } - - /* check if recomputation is needed */ - if z == 0. { - let mut j = 0; - for i in (jk..=jz - 1).rev() { - j |= i!(iq, i); - } - if j == 0 { - /* need recomputation */ - let mut k = 1; - while i!(iq, jk - k, ==, 0) { - k += 1; /* k = no. of terms needed */ - } - - for i in (jz + 1)..=(jz + k) { - /* add q[jz+1] to q[jz+k] */ - i!(f, jx + i, =, i!(IPIO2, jv + i) as f64); - fw = 0f64; - for j in 0..=jx { - fw += i!(x, j) * i!(f, jx + i - j); - } - i!(q, i, =, fw); - } - jz += k; - continue 'recompute; - } - } - - break; - } - - /* chop off zero terms */ - if z == 0. { - jz -= 1; - q0 -= 24; - while i!(iq, jz) == 0 { - jz -= 1; - q0 -= 24; - } - } else { - /* break z into 24-bit if necessary */ - z = scalbn(z, -q0); - if z >= x1p24 { - fw = (x1p_24 * z) as i32 as f64; - i!(iq, jz, =, (z - x1p24 * fw) as i32); - jz += 1; - q0 += 24; - i!(iq, jz, =, fw as i32); - } else { - i!(iq, jz, =, z as i32); - } - } - - /* convert integer "bit" chunk to floating-point value */ - fw = scalbn(1., q0); - for i in (0..=jz).rev() { - i!(q, i, =, fw * (i!(iq, i) as f64)); - fw *= x1p_24; - } - - /* compute PIo2[0,...,jp]*q[jz,...,0] */ - for i in (0..=jz).rev() { - fw = 0f64; - let mut k = 0; - while (k <= jp) && (k <= jz - i) { - fw += i!(PIO2, k) * i!(q, i + k); - k += 1; - } - i!(fq, jz - i, =, fw); - } - - /* compress fq[] into y[] */ - match prec { - 0 => { - fw = 0f64; - for i in (0..=jz).rev() { - fw += i!(fq, i); - } - i!(y, 0, =, if ih == 0 { fw } else { -fw }); - } - 1 | 2 => { - fw = 0f64; - for i in (0..=jz).rev() { - fw += i!(fq, i); - } - i!(y, 0, =, if ih == 0 { fw } else { -fw }); - fw = i!(fq, 0) - fw; - for i in 1..=jz { - fw += i!(fq, i); - } - i!(y, 1, =, if ih == 0 { fw } else { -fw }); - } - 3 => { - /* painful */ - for i in (1..=jz).rev() { - fw = i!(fq, i - 1) + i!(fq, i); - i!(fq, i, +=, i!(fq, i - 1) - fw); - i!(fq, i - 1, =, fw); - } - for i in (2..=jz).rev() { - fw = i!(fq, i - 1) + i!(fq, i); - i!(fq, i, +=, i!(fq, i - 1) - fw); - i!(fq, i - 1, =, fw); - } - fw = 0f64; - for i in (2..=jz).rev() { - fw += i!(fq, i); - } - if ih == 0 { - i!(y, 0, =, i!(fq, 0)); - i!(y, 1, =, i!(fq, 1)); - i!(y, 2, =, fw); - } else { - i!(y, 0, =, -i!(fq, 0)); - i!(y, 1, =, -i!(fq, 1)); - i!(y, 2, =, -fw); - } - } - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => {} - } - n & 7 -} diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs deleted file mode 100644 index 3c658fe3dbc..00000000000 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ /dev/null @@ -1,67 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Debugged and optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::f64; - -use super::rem_pio2_large; - -const TOINT: f64 = 1.5 / f64::EPSILON; - -/// 53 bits of 2/pi -const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ -/// first 25 bits of pi/2 -const PIO2_1: f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ -/// pi/2 - pio2_1 -const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ - -/// Return the remainder of x rem pi/2 in *y -/// -/// use double precision for everything except passing x -/// use __rem_pio2_large() for large x -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { - let x64 = x as f64; - - let mut tx: [f64; 1] = [0.]; - let mut ty: [f64; 1] = [0.]; - - let ix = x.to_bits() & 0x7fffffff; - /* 25+53 bit pi is good enough for medium size */ - if ix < 0x4dc90fdb { - /* |x| ~< 2^28*(pi/2), medium size */ - /* Use a specialized rint() to get fn. Assume round-to-nearest. */ - let tmp = x64 * INV_PIO2 + TOINT; - // force rounding of tmp to it's storage format on x87 to avoid - // excess precision issues. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let tmp = force_eval!(tmp); - let f_n = tmp - TOINT; - return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); - } - if ix >= 0x7f800000 { - /* x is inf or NaN */ - return (0, x64 - x64); - } - /* scale x into [2^23, 2^24-1] */ - let sign = (x.to_bits() >> 31) != 0; - let e0 = ((ix >> 23) - (0x7f + 23)) as i32; /* e0 = ilogb(|x|)-23, positive */ - tx[0] = f32::from_bits(ix - (e0 << 23) as u32) as f64; - let n = rem_pio2_large(&tx, &mut ty, e0, 0); - if sign { - return (-n, -ty[0]); - } - (n, ty[0]) -} diff --git a/library/compiler-builtins/libm/src/math/remainder.rs b/library/compiler-builtins/libm/src/math/remainder.rs deleted file mode 100644 index 9e966c9ed7f..00000000000 --- a/library/compiler-builtins/libm/src/math/remainder.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remainder(x: f64, y: f64) -> f64 { - let (result, _) = super::remquo(x, y); - result -} diff --git a/library/compiler-builtins/libm/src/math/remainderf.rs b/library/compiler-builtins/libm/src/math/remainderf.rs deleted file mode 100644 index b1407cf2ace..00000000000 --- a/library/compiler-builtins/libm/src/math/remainderf.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remainderf(x: f32, y: f32) -> f32 { - let (result, _) = super::remquof(x, y); - result -} diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs deleted file mode 100644 index 4c11e848746..00000000000 --- a/library/compiler-builtins/libm/src/math/remquo.rs +++ /dev/null @@ -1,106 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { - let ux: u64 = x.to_bits(); - let mut uy: u64 = y.to_bits(); - let mut ex = ((ux >> 52) & 0x7ff) as i32; - let mut ey = ((uy >> 52) & 0x7ff) as i32; - let sx = (ux >> 63) != 0; - let sy = (uy >> 63) != 0; - let mut q: u32; - let mut i: u64; - let mut uxi: u64 = ux; - - if (uy << 1) == 0 || y.is_nan() || ex == 0x7ff { - return ((x * y) / (x * y), 0); - } - if (ux << 1) == 0 { - return (x, 0); - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 12; - while (i >> 63) == 0 { - ex -= 1; - i <<= 1; - } - uxi <<= -ex + 1; - } else { - uxi &= (!0) >> 12; - uxi |= 1 << 52; - } - if ey == 0 { - i = uy << 12; - while (i >> 63) == 0 { - ey -= 1; - i <<= 1; - } - uy <<= -ey + 1; - } else { - uy &= (!0) >> 12; - uy |= 1 << 52; - } - - q = 0; - - if ex + 1 != ey { - if ex < ey { - return (x, 0); - } - /* x mod y */ - while ex > ey { - i = uxi.wrapping_sub(uy); - if (i >> 63) == 0 { - uxi = i; - q += 1; - } - uxi <<= 1; - q <<= 1; - ex -= 1; - } - i = uxi.wrapping_sub(uy); - if (i >> 63) == 0 { - uxi = i; - q += 1; - } - if uxi == 0 { - ex = -60; - } else { - while (uxi >> 52) == 0 { - uxi <<= 1; - ex -= 1; - } - } - } - - /* scale result and decide between |x| and |x|-|y| */ - if ex > 0 { - uxi -= 1 << 52; - uxi |= (ex as u64) << 52; - } else { - uxi >>= -ex + 1; - } - x = f64::from_bits(uxi); - if sy { - y = -y; - } - if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { - x -= y; - // TODO: this matches musl behavior, but it is incorrect - q = q.wrapping_add(1); - } - q &= 0x7fffffff; - let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; - if sx { (-x, quo) } else { (x, quo) } -} - -#[cfg(test)] -mod tests { - use super::remquo; - - #[test] - fn test_q_overflow() { - // 0xc000000000000001, 0x04c0000000000004 - let _ = remquo(-2.0000000000000004, 8.406091369059082e-286); - } -} diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs deleted file mode 100644 index b0e85ca6611..00000000000 --- a/library/compiler-builtins/libm/src/math/remquof.rs +++ /dev/null @@ -1,93 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { - let ux: u32 = x.to_bits(); - let mut uy: u32 = y.to_bits(); - let mut ex = ((ux >> 23) & 0xff) as i32; - let mut ey = ((uy >> 23) & 0xff) as i32; - let sx = (ux >> 31) != 0; - let sy = (uy >> 31) != 0; - let mut q: u32; - let mut i: u32; - let mut uxi: u32 = ux; - - if (uy << 1) == 0 || y.is_nan() || ex == 0xff { - return ((x * y) / (x * y), 0); - } - if (ux << 1) == 0 { - return (x, 0); - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 9; - while (i >> 31) == 0 { - ex -= 1; - i <<= 1; - } - uxi <<= -ex + 1; - } else { - uxi &= (!0) >> 9; - uxi |= 1 << 23; - } - if ey == 0 { - i = uy << 9; - while (i >> 31) == 0 { - ey -= 1; - i <<= 1; - } - uy <<= -ey + 1; - } else { - uy &= (!0) >> 9; - uy |= 1 << 23; - } - - q = 0; - if ex + 1 != ey { - if ex < ey { - return (x, 0); - } - /* x mod y */ - while ex > ey { - i = uxi.wrapping_sub(uy); - if (i >> 31) == 0 { - uxi = i; - q += 1; - } - uxi <<= 1; - q <<= 1; - ex -= 1; - } - i = uxi.wrapping_sub(uy); - if (i >> 31) == 0 { - uxi = i; - q += 1; - } - if uxi == 0 { - ex = -30; - } else { - while (uxi >> 23) == 0 { - uxi <<= 1; - ex -= 1; - } - } - } - - /* scale result and decide between |x| and |x|-|y| */ - if ex > 0 { - uxi -= 1 << 23; - uxi |= (ex as u32) << 23; - } else { - uxi >>= -ex + 1; - } - x = f32::from_bits(uxi); - if sy { - y = -y; - } - if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { - x -= y; - q += 1; - } - q &= 0x7fffffff; - let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; - if sx { (-x, quo) } else { (x, quo) } -} diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs deleted file mode 100644 index e1c32c94355..00000000000 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ /dev/null @@ -1,51 +0,0 @@ -use super::support::Round; - -/// Round `x` to the nearest integer, breaking ties toward even. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rintf16(x: f16) -> f16 { - select_implementation! { - name: rintf16, - use_arch: all(target_arch = "aarch64", target_feature = "fp16"), - args: x, - } - - super::generic::rint_round(x, Round::Nearest).val -} - -/// Round `x` to the nearest integer, breaking ties toward even. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rintf(x: f32) -> f32 { - select_implementation! { - name: rintf, - use_arch: any( - all(target_arch = "aarch64", target_feature = "neon"), - all(target_arch = "wasm32", intrinsics_enabled), - ), - args: x, - } - - super::generic::rint_round(x, Round::Nearest).val -} - -/// Round `x` to the nearest integer, breaking ties toward even. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rint(x: f64) -> f64 { - select_implementation! { - name: rint, - use_arch: any( - all(target_arch = "aarch64", target_feature = "neon"), - all(target_arch = "wasm32", intrinsics_enabled), - ), - args: x, - } - - super::generic::rint_round(x, Round::Nearest).val -} - -/// Round `x` to the nearest integer, breaking ties toward even. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rintf128(x: f128) -> f128 { - super::generic::rint_round(x, Round::Nearest).val -} diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs deleted file mode 100644 index 6cd091cd73c..00000000000 --- a/library/compiler-builtins/libm/src/math/round.rs +++ /dev/null @@ -1,25 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf16(x: f16) -> f16 { - super::generic::round(x) -} - -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf(x: f32) -> f32 { - super::generic::round(x) -} - -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn round(x: f64) -> f64 { - super::generic::round(x) -} - -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf128(x: f128) -> f128 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/src/math/roundeven.rs deleted file mode 100644 index 6e621d7628f..00000000000 --- a/library/compiler-builtins/libm/src/math/roundeven.rs +++ /dev/null @@ -1,36 +0,0 @@ -use super::support::{Float, Round}; - -/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 -/// `roundToIntegralTiesToEven`. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundevenf16(x: f16) -> f16 { - roundeven_impl(x) -} - -/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 -/// `roundToIntegralTiesToEven`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundevenf(x: f32) -> f32 { - roundeven_impl(x) -} - -/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 -/// `roundToIntegralTiesToEven`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundeven(x: f64) -> f64 { - roundeven_impl(x) -} - -/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 -/// `roundToIntegralTiesToEven`. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundevenf128(x: f128) -> f128 { - roundeven_impl(x) -} - -#[inline] -pub fn roundeven_impl(x: F) -> F { - super::generic::rint_round(x, Round::Nearest).val -} diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs deleted file mode 100644 index ed73c3f94f0..00000000000 --- a/library/compiler-builtins/libm/src/math/scalbn.rs +++ /dev/null @@ -1,87 +0,0 @@ -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf16(x: f16, n: i32) -> f16 { - super::generic::scalbn(x, n) -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf(x: f32, n: i32) -> f32 { - super::generic::scalbn(x, n) -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbn(x: f64, n: i32) -> f64 { - super::generic::scalbn(x, n) -} - -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf128(x: f128, n: i32) -> f128 { - super::generic::scalbn(x, n) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::{CastFrom, CastInto, Float}; - - // Tests against N3220 - fn spec_test(f: impl Fn(F, i32) -> F) - where - u32: CastInto, - F::Int: CastFrom, - F::Int: CastFrom, - { - // `scalbn(±0, n)` returns `±0`. - assert_biteq!(f(F::NEG_ZERO, 10), F::NEG_ZERO); - assert_biteq!(f(F::NEG_ZERO, 0), F::NEG_ZERO); - assert_biteq!(f(F::NEG_ZERO, -10), F::NEG_ZERO); - assert_biteq!(f(F::ZERO, 10), F::ZERO); - assert_biteq!(f(F::ZERO, 0), F::ZERO); - assert_biteq!(f(F::ZERO, -10), F::ZERO); - - // `scalbn(x, 0)` returns `x`. - assert_biteq!(f(F::MIN, 0), F::MIN); - assert_biteq!(f(F::MAX, 0), F::MAX); - assert_biteq!(f(F::INFINITY, 0), F::INFINITY); - assert_biteq!(f(F::NEG_INFINITY, 0), F::NEG_INFINITY); - assert_biteq!(f(F::ZERO, 0), F::ZERO); - assert_biteq!(f(F::NEG_ZERO, 0), F::NEG_ZERO); - - // `scalbn(±∞, n)` returns `±∞`. - assert_biteq!(f(F::INFINITY, 10), F::INFINITY); - assert_biteq!(f(F::INFINITY, -10), F::INFINITY); - assert_biteq!(f(F::NEG_INFINITY, 10), F::NEG_INFINITY); - assert_biteq!(f(F::NEG_INFINITY, -10), F::NEG_INFINITY); - - // NaN should remain NaNs. - assert!(f(F::NAN, 10).is_nan()); - assert!(f(F::NAN, 0).is_nan()); - assert!(f(F::NAN, -10).is_nan()); - assert!(f(-F::NAN, 10).is_nan()); - assert!(f(-F::NAN, 0).is_nan()); - assert!(f(-F::NAN, -10).is_nan()); - } - - #[test] - #[cfg(f16_enabled)] - fn spec_test_f16() { - spec_test::(scalbnf16); - } - - #[test] - fn spec_test_f32() { - spec_test::(scalbnf); - } - - #[test] - fn spec_test_f64() { - spec_test::(scalbn); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_test_f128() { - spec_test::(scalbnf128); - } -} diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs deleted file mode 100644 index 229fa4bef08..00000000000 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ /dev/null @@ -1,95 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunPro, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -use super::{k_cos, k_sin, rem_pio2}; - -// sin(x) -// Return sine function of x. -// -// kernel function: -// k_sin ... sine function on [-pi/4,pi/4] -// k_cos ... cose function on [-pi/4,pi/4] -// rem_pio2 ... argument reduction routine -// -// Method. -// Let S,C and T denote the sin, cos and tan respectively on -// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 -// in [-pi/4 , +pi/4], and let n = k mod 4. -// We have -// -// n sin(x) cos(x) tan(x) -// ---------------------------------------------------------- -// 0 S C T -// 1 C -S -1/T -// 2 -S -C T -// 3 -C S -1/T -// ---------------------------------------------------------- -// -// Special cases: -// Let trig be any of sin, cos, or tan. -// trig(+-INF) is NaN, with signals; -// trig(NaN) is that NaN; -// -// Accuracy: -// TRIG(x) returns trig(x) nearly rounded - -/// The sine of `x` (f64). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sin(x: f64) -> f64 { - let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 - - /* High word of x. */ - let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; - - /* |x| ~< pi/4 */ - if ix <= 0x3fe921fb { - if ix < 0x3e500000 { - /* |x| < 2**-26 */ - /* raise inexact if x != 0 and underflow if subnormal*/ - if ix < 0x00100000 { - force_eval!(x / x1p120); - } else { - force_eval!(x + x1p120); - } - return x; - } - return k_sin(x, 0.0, 0); - } - - /* sin(Inf or NaN) is NaN */ - if ix >= 0x7ff00000 { - return x - x; - } - - /* argument reduction needed */ - let (n, y0, y1) = rem_pio2(x); - match n & 3 { - 0 => k_sin(y0, y1, 1), - 1 => k_cos(y0, y1), - 2 => -k_sin(y0, y1, 1), - _ => -k_cos(y0, y1), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[cfg_attr(x86_no_sse, ignore = "FIXME(i586): possible incorrect rounding")] - fn test_near_pi() { - let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 - let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 - assert_eq!(sin(x), sx); - } -} diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs deleted file mode 100644 index ebf482f2df3..00000000000 --- a/library/compiler-builtins/libm/src/math/sincos.rs +++ /dev/null @@ -1,137 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{get_high_word, k_cos, k_sin, rem_pio2}; - -/// Both the sine and cosine of `x` (f64). -/// -/// `x` is specified in radians and the return value is (sin(x), cos(x)). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sincos(x: f64) -> (f64, f64) { - let s: f64; - let c: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - - /* |x| ~< pi/4 */ - if ix <= 0x3fe921fb { - /* if |x| < 2**-27 * sqrt(2) */ - if ix < 0x3e46a09e { - /* raise inexact if x!=0 and underflow if subnormal */ - let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 - if ix < 0x00100000 { - force_eval!(x / x1p120); - } else { - force_eval!(x + x1p120); - } - return (x, 1.0); - } - return (k_sin(x, 0.0, 0), k_cos(x, 0.0)); - } - - /* sincos(Inf or NaN) is NaN */ - if ix >= 0x7ff00000 { - let rv = x - x; - return (rv, rv); - } - - /* argument reduction needed */ - let (n, y0, y1) = rem_pio2(x); - s = k_sin(y0, y1, 1); - c = k_cos(y0, y1); - match n & 3 { - 0 => (s, c), - 1 => (c, -s), - 2 => (-s, -c), - 3 => (-c, s), - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => (0.0, 1.0), - } -} - -// These tests are based on those from sincosf.rs -#[cfg(test)] -mod tests { - use super::sincos; - - const TOLERANCE: f64 = 1e-6; - - #[test] - fn with_pi() { - let (s, c) = sincos(core::f64::consts::PI); - assert!( - (s - 0.0).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - 0.0, - (s - 0.0).abs(), - TOLERANCE - ); - assert!( - (c + 1.0).abs() < TOLERANCE, - "|{} + {}| = {} >= {}", - c, - 1.0, - (s + 1.0).abs(), - TOLERANCE - ); - } - - #[test] - fn rotational_symmetry() { - use core::f64::consts::PI; - const N: usize = 24; - for n in 0..N { - let theta = 2. * PI * (n as f64) / (N as f64); - let (s, c) = sincos(theta); - let (s_plus, c_plus) = sincos(theta + 2. * PI); - let (s_minus, c_minus) = sincos(theta - 2. * PI); - - assert!( - (s - s_plus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - s_plus, - (s - s_plus).abs(), - TOLERANCE - ); - assert!( - (s - s_minus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - s_minus, - (s - s_minus).abs(), - TOLERANCE - ); - assert!( - (c - c_plus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - c, - c_plus, - (c - c_plus).abs(), - TOLERANCE - ); - assert!( - (c - c_minus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - c, - c_minus, - (c - c_minus).abs(), - TOLERANCE - ); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs deleted file mode 100644 index f3360767683..00000000000 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ /dev/null @@ -1,176 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{k_cosf, k_sinf, rem_pio2f}; - -/* Small multiples of pi/2 rounded to double precision. */ -const PI_2: f64 = 0.5 * 3.1415926535897931160E+00; -const S1PIO2: f64 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ -const S2PIO2: f64 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ -const S3PIO2: f64 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const S4PIO2: f64 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ - -/// Both the sine and cosine of `x` (f32). -/// -/// `x` is specified in radians and the return value is (sin(x), cos(x)). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sincosf(x: f32) -> (f32, f32) { - let s: f32; - let c: f32; - let mut ix: u32; - let sign: bool; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - /* |x| ~<= pi/4 */ - if ix <= 0x3f490fda { - /* |x| < 2**-12 */ - if ix < 0x39800000 { - /* raise inexact if x!=0 and underflow if subnormal */ - - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120 == 2^120 - if ix < 0x00100000 { - force_eval!(x / x1p120); - } else { - force_eval!(x + x1p120); - } - return (x, 1.0); - } - return (k_sinf(x as f64), k_cosf(x as f64)); - } - - /* |x| ~<= 5*pi/4 */ - if ix <= 0x407b53d1 { - if ix <= 0x4016cbe3 { - /* |x| ~<= 3pi/4 */ - if sign { - s = -k_cosf(x as f64 + S1PIO2); - c = k_sinf(x as f64 + S1PIO2); - } else { - s = k_cosf(S1PIO2 - x as f64); - c = k_sinf(S1PIO2 - x as f64); - } - } - /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ - else if sign { - s = -k_sinf(x as f64 + S2PIO2); - c = -k_cosf(x as f64 + S2PIO2); - } else { - s = -k_sinf(x as f64 - S2PIO2); - c = -k_cosf(x as f64 - S2PIO2); - } - - return (s, c); - } - - /* |x| ~<= 9*pi/4 */ - if ix <= 0x40e231d5 { - if ix <= 0x40afeddf { - /* |x| ~<= 7*pi/4 */ - if sign { - s = k_cosf(x as f64 + S3PIO2); - c = -k_sinf(x as f64 + S3PIO2); - } else { - s = -k_cosf(x as f64 - S3PIO2); - c = k_sinf(x as f64 - S3PIO2); - } - } else if sign { - s = k_sinf(x as f64 + S4PIO2); - c = k_cosf(x as f64 + S4PIO2); - } else { - s = k_sinf(x as f64 - S4PIO2); - c = k_cosf(x as f64 - S4PIO2); - } - - return (s, c); - } - - /* sin(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - let rv = x - x; - return (rv, rv); - } - - /* general argument reduction needed */ - let (n, y) = rem_pio2f(x); - s = k_sinf(y); - c = k_cosf(y); - match n & 3 { - 0 => (s, c), - 1 => (c, -s), - 2 => (-s, -c), - 3 => (-c, s), - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => (0.0, 1.0), - } -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::sincosf; - - #[test] - fn rotational_symmetry() { - use core::f32::consts::PI; - const N: usize = 24; - for n in 0..N { - let theta = 2. * PI * (n as f32) / (N as f32); - let (s, c) = sincosf(theta); - let (s_plus, c_plus) = sincosf(theta + 2. * PI); - let (s_minus, c_minus) = sincosf(theta - 2. * PI); - - const TOLERANCE: f32 = 1e-6; - assert!( - (s - s_plus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - s_plus, - (s - s_plus).abs(), - TOLERANCE - ); - assert!( - (s - s_minus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - s_minus, - (s - s_minus).abs(), - TOLERANCE - ); - assert!( - (c - c_plus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - c, - c_plus, - (c - c_plus).abs(), - TOLERANCE - ); - assert!( - (c - c_minus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - c, - c_minus, - (c - c_minus).abs(), - TOLERANCE - ); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs deleted file mode 100644 index b8fae2c9801..00000000000 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ /dev/null @@ -1,88 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::f64::consts::FRAC_PI_2; - -use super::{k_cosf, k_sinf, rem_pio2f}; - -/* Small multiples of pi/2 rounded to double precision. */ -const S1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ -const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ - -/// The sine of `x` (f32). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sinf(x: f32) -> f32 { - let x64 = x as f64; - - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - if ix <= 0x3f490fda { - /* |x| ~<= pi/4 */ - if ix < 0x39800000 { - /* |x| < 2**-12 */ - /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); - return x; - } - return k_sinf(x64); - } - if ix <= 0x407b53d1 { - /* |x| ~<= 5*pi/4 */ - if ix <= 0x4016cbe3 { - /* |x| ~<= 3pi/4 */ - if sign { - return -k_cosf(x64 + S1_PIO2); - } else { - return k_cosf(x64 - S1_PIO2); - } - } - return k_sinf(if sign { -(x64 + S2_PIO2) } else { -(x64 - S2_PIO2) }); - } - if ix <= 0x40e231d5 { - /* |x| ~<= 9*pi/4 */ - if ix <= 0x40afeddf { - /* |x| ~<= 7*pi/4 */ - if sign { - return k_cosf(x64 + S3_PIO2); - } else { - return -k_cosf(x64 - S3_PIO2); - } - } - return k_sinf(if sign { x64 + S4_PIO2 } else { x64 - S4_PIO2 }); - } - - /* sin(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - return x - x; - } - - /* general argument reduction needed */ - let (n, y) = rem_pio2f(x); - match n & 3 { - 0 => k_sinf(y), - 1 => k_cosf(y), - 2 => k_sinf(-y), - _ => -k_cosf(y), - } -} diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs deleted file mode 100644 index 79184198263..00000000000 --- a/library/compiler-builtins/libm/src/math/sinh.rs +++ /dev/null @@ -1,51 +0,0 @@ -use super::{expm1, expo2}; - -// sinh(x) = (exp(x) - 1/exp(x))/2 -// = (exp(x)-1 + (exp(x)-1)/exp(x))/2 -// = x + x^3/6 + o(x^5) -// - -/// The hyperbolic sine of `x` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sinh(x: f64) -> f64 { - // union {double f; uint64_t i;} u = {.f = x}; - // uint32_t w; - // double t, h, absx; - - let mut uf: f64 = x; - let mut ui: u64 = f64::to_bits(uf); - let w: u32; - let t: f64; - let mut h: f64; - let absx: f64; - - h = 0.5; - if ui >> 63 != 0 { - h = -h; - } - /* |x| */ - ui &= !1 / 2; - uf = f64::from_bits(ui); - absx = uf; - w = (ui >> 32) as u32; - - /* |x| < log(DBL_MAX) */ - if w < 0x40862e42 { - t = expm1(absx); - if w < 0x3ff00000 { - if w < 0x3ff00000 - (26 << 20) { - /* note: inexact and underflow are raised by expm1 */ - /* note: this branch avoids spurious underflow */ - return x; - } - return h * (2.0 * t - t * t / (t + 1.0)); - } - /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ - return h * (t + t / (t + 1.0)); - } - - /* |x| > log(DBL_MAX) or nan */ - /* note: the result is stored to handle overflow */ - t = 2.0 * h * expo2(absx); - t -} diff --git a/library/compiler-builtins/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/src/math/sinhf.rs deleted file mode 100644 index 44d2e3560d5..00000000000 --- a/library/compiler-builtins/libm/src/math/sinhf.rs +++ /dev/null @@ -1,30 +0,0 @@ -use super::{expm1f, k_expo2f}; - -/// The hyperbolic sine of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sinhf(x: f32) -> f32 { - let mut h = 0.5f32; - let mut ix = x.to_bits(); - if (ix >> 31) != 0 { - h = -h; - } - /* |x| */ - ix &= 0x7fffffff; - let absx = f32::from_bits(ix); - let w = ix; - - /* |x| < log(FLT_MAX) */ - if w < 0x42b17217 { - let t = expm1f(absx); - if w < 0x3f800000 { - if w < (0x3f800000 - (12 << 23)) { - return x; - } - return h * (2. * t - t * t / (t + 1.)); - } - return h * (t + t / (t + 1.)); - } - - /* |x| > logf(FLT_MAX) or nan */ - 2. * h * k_expo2f(absx) -} diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs deleted file mode 100644 index 76bc240cf01..00000000000 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ /dev/null @@ -1,51 +0,0 @@ -/// The square root of `x` (f16). -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf16(x: f16) -> f16 { - select_implementation! { - name: sqrtf16, - use_arch: all(target_arch = "aarch64", target_feature = "fp16"), - args: x, - } - - return super::generic::sqrt(x); -} - -/// The square root of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf(x: f32) -> f32 { - select_implementation! { - name: sqrtf, - use_arch: any( - all(target_arch = "aarch64", target_feature = "neon"), - all(target_arch = "wasm32", intrinsics_enabled), - target_feature = "sse2" - ), - args: x, - } - - super::generic::sqrt(x) -} - -/// The square root of `x` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrt(x: f64) -> f64 { - select_implementation! { - name: sqrt, - use_arch: any( - all(target_arch = "aarch64", target_feature = "neon"), - all(target_arch = "wasm32", intrinsics_enabled), - target_feature = "sse2" - ), - args: x, - } - - super::generic::sqrt(x) -} - -/// The square root of `x` (f128). -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf128(x: f128) -> f128 { - return super::generic::sqrt(x); -} diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs deleted file mode 100644 index eae08238e09..00000000000 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ /dev/null @@ -1,239 +0,0 @@ -//! Integers used for wide operations, larger than `u128`. - -#[cfg(test)] -mod tests; - -use core::ops; - -use super::{DInt, HInt, Int, MinInt}; - -const U128_LO_MASK: u128 = u64::MAX as u128; - -/// A 256-bit unsigned integer represented as two 128-bit native-endian limbs. -#[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] -pub struct u256 { - pub lo: u128, - pub hi: u128, -} - -impl u256 { - #[cfg(any(test, feature = "unstable-public-internals"))] - pub const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX }; - - /// Reinterpret as a signed integer - pub fn signed(self) -> i256 { - i256 { lo: self.lo, hi: self.hi } - } -} - -/// A 256-bit signed integer represented as two 128-bit native-endian limbs. -#[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] -pub struct i256 { - pub lo: u128, - pub hi: u128, -} - -impl i256 { - /// Reinterpret as an unsigned integer - #[cfg(any(test, feature = "unstable-public-internals"))] - pub fn unsigned(self) -> u256 { - u256 { lo: self.lo, hi: self.hi } - } -} - -impl MinInt for u256 { - type OtherSign = i256; - - type Unsigned = u256; - - const SIGNED: bool = false; - const BITS: u32 = 256; - const ZERO: Self = Self { lo: 0, hi: 0 }; - const ONE: Self = Self { lo: 1, hi: 0 }; - const MIN: Self = Self { lo: 0, hi: 0 }; - const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX }; -} - -impl MinInt for i256 { - type OtherSign = u256; - - type Unsigned = u256; - - const SIGNED: bool = false; - const BITS: u32 = 256; - const ZERO: Self = Self { lo: 0, hi: 0 }; - const ONE: Self = Self { lo: 1, hi: 0 }; - const MIN: Self = Self { lo: 0, hi: 1 << 127 }; - const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX << 1 }; -} - -macro_rules! impl_common { - ($ty:ty) => { - impl ops::BitOr for $ty { - type Output = Self; - - fn bitor(mut self, rhs: Self) -> Self::Output { - self.lo |= rhs.lo; - self.hi |= rhs.hi; - self - } - } - - impl ops::Not for $ty { - type Output = Self; - - fn not(mut self) -> Self::Output { - self.lo = !self.lo; - self.hi = !self.hi; - self - } - } - - impl ops::Shl for $ty { - type Output = Self; - - fn shl(self, _rhs: u32) -> Self::Output { - unimplemented!("only used to meet trait bounds") - } - } - }; -} - -impl_common!(i256); -impl_common!(u256); - -impl ops::Add for u256 { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - let (lo, carry) = self.lo.overflowing_add(rhs.lo); - let hi = self.hi.wrapping_add(carry as u128).wrapping_add(rhs.hi); - - Self { lo, hi } - } -} - -impl ops::Shr for u256 { - type Output = Self; - - fn shr(mut self, rhs: u32) -> Self::Output { - debug_assert!(rhs < Self::BITS, "attempted to shift right with overflow"); - if rhs >= Self::BITS { - return Self::ZERO; - } - - if rhs == 0 { - return self; - } - - if rhs < 128 { - self.lo >>= rhs; - self.lo |= self.hi << (128 - rhs); - } else { - self.lo = self.hi >> (rhs - 128); - } - - if rhs < 128 { - self.hi >>= rhs; - } else { - self.hi = 0; - } - - self - } -} - -impl HInt for u128 { - type D = u256; - - fn widen(self) -> Self::D { - u256 { lo: self, hi: 0 } - } - - fn zero_widen(self) -> Self::D { - self.widen() - } - - fn zero_widen_mul(self, rhs: Self) -> Self::D { - let l0 = self & U128_LO_MASK; - let l1 = rhs & U128_LO_MASK; - let h0 = self >> 64; - let h1 = rhs >> 64; - - let p_ll: u128 = l0.overflowing_mul(l1).0; - let p_lh: u128 = l0.overflowing_mul(h1).0; - let p_hl: u128 = h0.overflowing_mul(l1).0; - let p_hh: u128 = h0.overflowing_mul(h1).0; - - let s0 = p_hl + (p_ll >> 64); - let s1 = (p_ll & U128_LO_MASK) + (s0 << 64); - let s2 = p_lh + (s1 >> 64); - - let lo = (p_ll & U128_LO_MASK) + (s2 << 64); - let hi = p_hh + (s0 >> 64) + (s2 >> 64); - - u256 { lo, hi } - } - - fn widen_mul(self, rhs: Self) -> Self::D { - self.zero_widen_mul(rhs) - } - - fn widen_hi(self) -> Self::D { - self.widen() << ::BITS - } -} - -impl HInt for i128 { - type D = i256; - - fn widen(self) -> Self::D { - let mut ret = self.unsigned().zero_widen().signed(); - if self.is_negative() { - ret.hi = u128::MAX; - } - ret - } - - fn zero_widen(self) -> Self::D { - self.unsigned().zero_widen().signed() - } - - fn zero_widen_mul(self, rhs: Self) -> Self::D { - self.unsigned().zero_widen_mul(rhs.unsigned()).signed() - } - - fn widen_mul(self, _rhs: Self) -> Self::D { - unimplemented!("signed i128 widening multiply is not used") - } - - fn widen_hi(self) -> Self::D { - self.widen() << ::BITS - } -} - -impl DInt for u256 { - type H = u128; - - fn lo(self) -> Self::H { - self.lo - } - - fn hi(self) -> Self::H { - self.hi - } -} - -impl DInt for i256 { - type H = i128; - - fn lo(self) -> Self::H { - self.lo as i128 - } - - fn hi(self) -> Self::H { - self.hi as i128 - } -} diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs deleted file mode 100644 index 2c71191ba53..00000000000 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ /dev/null @@ -1,149 +0,0 @@ -extern crate std; -use std::string::String; -use std::{eprintln, format}; - -use super::{HInt, MinInt, i256, u256}; - -const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; - -/// Print a `u256` as hex since we can't add format implementations -fn hexu(v: u256) -> String { - format!("0x{:032x}{:032x}", v.hi, v.lo) -} - -#[test] -fn widen_u128() { - assert_eq!(u128::MAX.widen(), u256 { lo: u128::MAX, hi: 0 }); - assert_eq!(LOHI_SPLIT.widen(), u256 { lo: LOHI_SPLIT, hi: 0 }); -} - -#[test] -fn widen_i128() { - assert_eq!((-1i128).widen(), u256::MAX.signed()); - assert_eq!((LOHI_SPLIT as i128).widen(), i256 { lo: LOHI_SPLIT, hi: u128::MAX }); - assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); -} - -#[test] -fn widen_mul_u128() { - let tests = [ - (u128::MAX / 2, 2_u128, u256 { lo: u128::MAX - 1, hi: 0 }), - (u128::MAX, 2_u128, u256 { lo: u128::MAX - 1, hi: 1 }), - (u128::MAX, u128::MAX, u256 { lo: 1, hi: u128::MAX - 1 }), - (0, 0, u256::ZERO), - (1234u128, 0, u256::ZERO), - (0, 1234, u256::ZERO), - ]; - - let mut has_errors = false; - let mut add_error = |i, a, b, expected, actual| { - has_errors = true; - eprintln!( - "\ - FAILURE ({i}): {a:#034x} * {b:#034x}\n\ - expected: {}\n\ - got: {}\ - ", - hexu(expected), - hexu(actual) - ); - }; - - for (i, (a, b, exp)) in tests.iter().copied().enumerate() { - let res = a.widen_mul(b); - let res_z = a.zero_widen_mul(b); - assert_eq!(res, res_z); - if res != exp { - add_error(i, a, b, exp, res); - } - } - - assert!(!has_errors); -} - -#[test] -fn not_u256() { - assert_eq!(!u256::ZERO, u256::MAX); -} - -#[test] -fn shr_u256() { - let only_low = [1, u16::MAX.into(), u32::MAX.into(), u64::MAX.into(), u128::MAX]; - let mut has_errors = false; - - let mut add_error = |a, b, expected, actual| { - has_errors = true; - eprintln!( - "\ - FAILURE: {} >> {b}\n\ - expected: {}\n\ - actual: {}\ - ", - hexu(a), - hexu(expected), - hexu(actual), - ); - }; - - for a in only_low { - for perturb in 0..10 { - let a = a.saturating_add(perturb); - for shift in 0..128 { - let res = a.widen() >> shift; - let expected = (a >> shift).widen(); - if res != expected { - add_error(a.widen(), shift, expected, res); - } - } - } - } - - let check = [ - (u256::MAX, 1, u256 { lo: u128::MAX, hi: u128::MAX >> 1 }), - (u256::MAX, 5, u256 { lo: u128::MAX, hi: u128::MAX >> 5 }), - (u256::MAX, 63, u256 { lo: u128::MAX, hi: u64::MAX as u128 | (1 << 64) }), - (u256::MAX, 64, u256 { lo: u128::MAX, hi: u64::MAX as u128 }), - (u256::MAX, 65, u256 { lo: u128::MAX, hi: (u64::MAX >> 1) as u128 }), - (u256::MAX, 127, u256 { lo: u128::MAX, hi: 1 }), - (u256::MAX, 128, u256 { lo: u128::MAX, hi: 0 }), - (u256::MAX, 129, u256 { lo: u128::MAX >> 1, hi: 0 }), - (u256::MAX, 191, u256 { lo: u64::MAX as u128 | 1 << 64, hi: 0 }), - (u256::MAX, 192, u256 { lo: u64::MAX as u128, hi: 0 }), - (u256::MAX, 193, u256 { lo: u64::MAX as u128 >> 1, hi: 0 }), - (u256::MAX, 254, u256 { lo: 0b11, hi: 0 }), - (u256::MAX, 255, u256 { lo: 1, hi: 0 }), - ( - u256 { hi: LOHI_SPLIT, lo: 0 }, - 64, - u256 { lo: 0xffffffffffffffff0000000000000000, hi: 0xaaaaaaaaaaaaaaaa }, - ), - ]; - - for (input, shift, expected) in check { - let res = input >> shift; - if res != expected { - add_error(input, shift, expected, res); - } - } - - assert!(!has_errors); -} - -#[test] -#[should_panic] -#[cfg(debug_assertions)] -// FIXME(ppc): ppc64le seems to have issues with `should_panic` tests. -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] -fn shr_u256_overflow() { - // Like regular shr, panic on overflow with debug assertions - let _ = u256::MAX >> 256; -} - -#[test] -#[cfg(not(debug_assertions))] -fn shr_u256_overflow() { - // No panic without debug assertions - assert_eq!(u256::MAX >> 256, u256::ZERO); - assert_eq!(u256::MAX >> 257, u256::ZERO); - assert_eq!(u256::MAX >> u32::MAX, u256::ZERO); -} diff --git a/library/compiler-builtins/libm/src/math/support/env.rs b/library/compiler-builtins/libm/src/math/support/env.rs deleted file mode 100644 index 796309372a5..00000000000 --- a/library/compiler-builtins/libm/src/math/support/env.rs +++ /dev/null @@ -1,127 +0,0 @@ -//! Support for rounding directions and status flags as specified by IEEE 754. -//! -//! Rust does not support the floating point environment so rounding mode is passed as an argument -//! and status flags are returned as part of the result. There is currently not much support for -//! this; most existing ports from musl use a form of `force_eval!` to raise exceptions, but this -//! has no side effects in Rust. Further, correct behavior relies on elementary operations making -//! use of the correct rounding and raising relevant exceptions, which is not the case for Rust. -//! -//! This module exists so no functionality is lost when porting algorithms that respect floating -//! point environment, and so that some functionality may be tested (that which does not rely on -//! side effects from elementary operations). Full support would require wrappers around basic -//! operations, but there is no plan to add this at the current time. - -/// A value combined with a floating point status. -pub struct FpResult { - pub val: T, - #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] - pub status: Status, -} - -impl FpResult { - pub fn new(val: T, status: Status) -> Self { - Self { val, status } - } - - /// Return `val` with `Status::OK`. - pub fn ok(val: T) -> Self { - Self { val, status: Status::OK } - } -} - -/// IEEE 754 rounding mode, excluding the optional `roundTiesToAway` version of nearest. -/// -/// Integer representation comes from what CORE-MATH uses for indexing. -#[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum Round { - /// IEEE 754 nearest, `roundTiesToEven`. - Nearest = 0, - /// IEEE 754 `roundTowardNegative`. - Negative = 1, - /// IEEE 754 `roundTowardPositive`. - Positive = 2, - /// IEEE 754 `roundTowardZero`. - Zero = 3, -} - -/// IEEE 754 exception status flags. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Status(u8); - -impl Status { - /// Default status indicating no errors. - pub const OK: Self = Self(0); - - /// No definable result. - /// - /// Includes: - /// - Any ops on sNaN, with a few exceptions. - /// - `0 * inf`, `inf * 0`. - /// - `fma(0, inf, c)` or `fma(inf, 0, c)`, possibly excluding `c = qNaN`. - /// - `+inf + -inf` and similar (includes subtraction and fma). - /// - `0.0 / 0.0`, `inf / inf` - /// - `remainder(x, y)` if `y == 0.0` or `x == inf`, and neither is NaN. - /// - `sqrt(x)` with `x < 0.0`. - pub const INVALID: Self = Self(1); - - /// Division by zero. - /// - /// The default result for division is +/-inf based on operand sign. For `logB`, the default - /// result is -inf. - /// `x / y` when `x != 0.0` and `y == 0.0`, - #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] - pub const DIVIDE_BY_ZERO: Self = Self(1 << 2); - - /// The result exceeds the maximum finite value. - /// - /// The default result depends on rounding mode. `Nearest*` rounds to +/- infinity, sign based - /// on the intermediate result. `Zero` rounds to the signed maximum finite. `Positive` and - /// `Negative` round to signed maximum finite in one direction, signed infinity in the other. - #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] - pub const OVERFLOW: Self = Self(1 << 3); - - /// The result is subnormal and lost precision. - pub const UNDERFLOW: Self = Self(1 << 4); - - /// The finite-precision result does not match that of infinite precision, and the reason - /// is not represented by one of the other flags. - pub const INEXACT: Self = Self(1 << 5); - - /// True if `UNDERFLOW` is set. - #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] - pub const fn underflow(self) -> bool { - self.0 & Self::UNDERFLOW.0 != 0 - } - - /// True if `OVERFLOW` is set. - #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] - pub const fn overflow(self) -> bool { - self.0 & Self::OVERFLOW.0 != 0 - } - - pub fn set_underflow(&mut self, val: bool) { - self.set_flag(val, Self::UNDERFLOW); - } - - /// True if `INEXACT` is set. - pub const fn inexact(self) -> bool { - self.0 & Self::INEXACT.0 != 0 - } - - pub fn set_inexact(&mut self, val: bool) { - self.set_flag(val, Self::INEXACT); - } - - fn set_flag(&mut self, val: bool, mask: Self) { - if val { - self.0 |= mask.0; - } else { - self.0 &= !mask.0; - } - } - - pub(crate) const fn with(self, rhs: Self) -> Self { - Self(self.0 | rhs.0) - } -} diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs deleted file mode 100644 index fac10483237..00000000000 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ /dev/null @@ -1,484 +0,0 @@ -use core::{fmt, mem, ops}; - -use super::int_traits::{CastFrom, Int, MinInt}; - -/// Trait for some basic operations on floats -// #[allow(dead_code)] -pub trait Float: - Copy - + fmt::Debug - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::MulAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Rem - + ops::Neg - + 'static -{ - /// A uint of the same width as the float - type Int: Int; - - /// A int of the same width as the float - type SignedInt: Int - + MinInt - + ops::Neg; - - const ZERO: Self; - const NEG_ZERO: Self; - const ONE: Self; - const NEG_ONE: Self; - const INFINITY: Self; - const NEG_INFINITY: Self; - const NAN: Self; - const NEG_NAN: Self; - const MAX: Self; - const MIN: Self; - const EPSILON: Self; - const PI: Self; - const NEG_PI: Self; - const FRAC_PI_2: Self; - - const MIN_POSITIVE_NORMAL: Self; - - /// The bitwidth of the float type - const BITS: u32; - - /// The bitwidth of the significand - const SIG_BITS: u32; - - /// The bitwidth of the exponent - const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; - - /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite - /// representation. - /// - /// This shifted fully right, use `EXP_MASK` for the shifted value. - const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; - - /// The exponent bias value - const EXP_BIAS: u32 = Self::EXP_SAT >> 1; - - /// Maximum unbiased exponent value. - const EXP_MAX: i32 = Self::EXP_BIAS as i32; - - /// Minimum *NORMAL* unbiased exponent value. - const EXP_MIN: i32 = -(Self::EXP_MAX - 1); - - /// Minimum subnormal exponent value. - const EXP_MIN_SUBNORM: i32 = Self::EXP_MIN - Self::SIG_BITS as i32; - - /// A mask for the sign bit - const SIGN_MASK: Self::Int; - - /// A mask for the significand - const SIG_MASK: Self::Int; - - /// A mask for the exponent - const EXP_MASK: Self::Int; - - /// The implicit bit of the float format - const IMPLICIT_BIT: Self::Int; - - /// Returns `self` transmuted to `Self::Int` - fn to_bits(self) -> Self::Int; - - /// Returns `self` transmuted to `Self::SignedInt` - #[allow(dead_code)] - fn to_bits_signed(self) -> Self::SignedInt { - self.to_bits().signed() - } - - /// Check bitwise equality. - #[allow(dead_code)] - fn biteq(self, rhs: Self) -> bool { - self.to_bits() == rhs.to_bits() - } - - /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. - /// - /// This method returns `true` if two NaNs are compared. Use [`biteq`](Self::biteq) instead - /// if `NaN` should not be treated separately. - #[allow(dead_code)] - fn eq_repr(self, rhs: Self) -> bool { - if self.is_nan() && rhs.is_nan() { true } else { self.biteq(rhs) } - } - - /// Returns true if the value is NaN. - fn is_nan(self) -> bool; - - /// Returns true if the value is +inf or -inf. - fn is_infinite(self) -> bool; - - /// Returns true if the sign is negative. Extracts the sign bit regardless of zero or NaN. - fn is_sign_negative(self) -> bool; - - /// Returns true if the sign is positive. Extracts the sign bit regardless of zero or NaN. - fn is_sign_positive(self) -> bool { - !self.is_sign_negative() - } - - /// Returns if `self` is subnormal. - #[allow(dead_code)] - fn is_subnormal(self) -> bool { - (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO - } - - /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. - fn ex(self) -> u32 { - u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_SAT - } - - /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. - fn exp_unbiased(self) -> i32 { - self.ex().signed() - (Self::EXP_BIAS as i32) - } - - /// Returns the significand with no implicit bit (or the "fractional" part) - #[allow(dead_code)] - fn frac(self) -> Self::Int { - self.to_bits() & Self::SIG_MASK - } - - /// Returns a `Self::Int` transmuted back to `Self` - fn from_bits(a: Self::Int) -> Self; - - /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(negative: bool, exponent: u32, significand: Self::Int) -> Self { - let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; - Self::from_bits( - (sign << (Self::BITS - 1)) - | (Self::Int::cast_from(exponent & Self::EXP_SAT) << Self::SIG_BITS) - | (significand & Self::SIG_MASK), - ) - } - - #[allow(dead_code)] - fn abs(self) -> Self; - - /// Returns a number composed of the magnitude of self and the sign of sign. - fn copysign(self, other: Self) -> Self; - - /// Fused multiply add, rounding once. - fn fma(self, y: Self, z: Self) -> Self; - - /// Returns (normalized exponent, normalized significand) - #[allow(dead_code)] - fn normalize(significand: Self::Int) -> (i32, Self::Int); - - /// Returns a number that represents the sign of self. - #[allow(dead_code)] - fn signum(self) -> Self { - if self.is_nan() { self } else { Self::ONE.copysign(self) } - } -} - -/// Access the associated `Int` type from a float (helper to avoid ambiguous associated types). -pub type IntTy = ::Int; - -macro_rules! float_impl { - ( - $ty:ident, - $ity:ident, - $sity:ident, - $bits:expr, - $significand_bits:expr, - $from_bits:path, - $to_bits:path, - $fma_fn:ident, - $fma_intrinsic:ident - ) => { - impl Float for $ty { - type Int = $ity; - type SignedInt = $sity; - - const ZERO: Self = 0.0; - const NEG_ZERO: Self = -0.0; - const ONE: Self = 1.0; - const NEG_ONE: Self = -1.0; - const INFINITY: Self = Self::INFINITY; - const NEG_INFINITY: Self = Self::NEG_INFINITY; - const NAN: Self = Self::NAN; - // NAN isn't guaranteed to be positive but it usually is. We only use this for - // tests. - const NEG_NAN: Self = $from_bits($to_bits(Self::NAN) | Self::SIGN_MASK); - const MAX: Self = -Self::MIN; - // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed - const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS)); - const EPSILON: Self = <$ty>::EPSILON; - - // Exponent is a 1 in the LSB - const MIN_POSITIVE_NORMAL: Self = $from_bits(1 << Self::SIG_BITS); - - const PI: Self = core::$ty::consts::PI; - const NEG_PI: Self = -Self::PI; - const FRAC_PI_2: Self = core::$ty::consts::FRAC_PI_2; - - const BITS: u32 = $bits; - const SIG_BITS: u32 = $significand_bits; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; - const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); - const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; - - fn to_bits(self) -> Self::Int { - self.to_bits() - } - fn is_nan(self) -> bool { - self.is_nan() - } - fn is_infinite(self) -> bool { - self.is_infinite() - } - fn is_sign_negative(self) -> bool { - self.is_sign_negative() - } - fn from_bits(a: Self::Int) -> Self { - Self::from_bits(a) - } - fn abs(self) -> Self { - cfg_if! { - // FIXME(msrv): `abs` is available in `core` starting with 1.85. - if #[cfg(intrinsics_enabled)] { - self.abs() - } else { - super::super::generic::fabs(self) - } - } - } - fn copysign(self, other: Self) -> Self { - cfg_if! { - // FIXME(msrv): `copysign` is available in `core` starting with 1.85. - if #[cfg(intrinsics_enabled)] { - self.copysign(other) - } else { - super::super::generic::copysign(self, other) - } - } - } - fn fma(self, y: Self, z: Self) -> Self { - cfg_if! { - // fma is not yet available in `core` - if #[cfg(intrinsics_enabled)] { - unsafe{ core::intrinsics::$fma_intrinsic(self, y, z) } - } else { - super::super::$fma_fn(self, y, z) - } - } - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); - (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) - } - } - }; -} - -#[cfg(f16_enabled)] -float_impl!(f16, u16, i16, 16, 10, f16::from_bits, f16::to_bits, fmaf16, fmaf16); -float_impl!(f32, u32, i32, 32, 23, f32_from_bits, f32_to_bits, fmaf, fmaf32); -float_impl!(f64, u64, i64, 64, 52, f64_from_bits, f64_to_bits, fma, fmaf64); -#[cfg(f128_enabled)] -float_impl!(f128, u128, i128, 128, 112, f128::from_bits, f128::to_bits, fmaf128, fmaf128); - -/* FIXME(msrv): vendor some things that are not const stable at our MSRV */ - -/// `f32::from_bits` -pub const fn f32_from_bits(bits: u32) -> f32 { - // SAFETY: POD cast with no preconditions - unsafe { mem::transmute::(bits) } -} - -/// `f32::to_bits` -pub const fn f32_to_bits(x: f32) -> u32 { - // SAFETY: POD cast with no preconditions - unsafe { mem::transmute::(x) } -} - -/// `f64::from_bits` -pub const fn f64_from_bits(bits: u64) -> f64 { - // SAFETY: POD cast with no preconditions - unsafe { mem::transmute::(bits) } -} - -/// `f64::to_bits` -pub const fn f64_to_bits(x: f64) -> u64 { - // SAFETY: POD cast with no preconditions - unsafe { mem::transmute::(x) } -} - -/// Trait for floats twice the bit width of another integer. -pub trait DFloat: Float { - /// Float that is half the bit width of the floatthis trait is implemented for. - type H: HFloat; - - /// Narrow the float type. - fn narrow(self) -> Self::H; -} - -/// Trait for floats half the bit width of another float. -pub trait HFloat: Float { - /// Float that is double the bit width of the float this trait is implemented for. - type D: DFloat; - - /// Widen the float type. - fn widen(self) -> Self::D; -} - -macro_rules! impl_d_float { - ($($X:ident $D:ident),*) => { - $( - impl DFloat for $D { - type H = $X; - - fn narrow(self) -> Self::H { - self as $X - } - } - )* - }; -} - -macro_rules! impl_h_float { - ($($H:ident $X:ident),*) => { - $( - impl HFloat for $H { - type D = $X; - - fn widen(self) -> Self::D { - self as $X - } - } - )* - }; -} - -impl_d_float!(f32 f64); -#[cfg(f16_enabled)] -impl_d_float!(f16 f32); -#[cfg(f128_enabled)] -impl_d_float!(f64 f128); - -impl_h_float!(f32 f64); -#[cfg(f16_enabled)] -impl_h_float!(f16 f32); -#[cfg(f128_enabled)] -impl_h_float!(f64 f128); - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[cfg(f16_enabled)] - fn check_f16() { - // Constants - assert_eq!(f16::EXP_SAT, 0b11111); - assert_eq!(f16::EXP_BIAS, 15); - assert_eq!(f16::EXP_MAX, 15); - assert_eq!(f16::EXP_MIN, -14); - assert_eq!(f16::EXP_MIN_SUBNORM, -24); - - // `exp_unbiased` - assert_eq!(f16::FRAC_PI_2.exp_unbiased(), 0); - assert_eq!((1.0f16 / 2.0).exp_unbiased(), -1); - assert_eq!(f16::MAX.exp_unbiased(), 15); - assert_eq!(f16::MIN.exp_unbiased(), 15); - assert_eq!(f16::MIN_POSITIVE.exp_unbiased(), -14); - // This is a convenience method and not ldexp, `exp_unbiased` does not return correct - // results for zero and subnormals. - assert_eq!(f16::ZERO.exp_unbiased(), -15); - assert_eq!(f16::from_bits(0x1).exp_unbiased(), -15); - assert_eq!(f16::MIN_POSITIVE, f16::MIN_POSITIVE_NORMAL); - - // `from_parts` - assert_biteq!(f16::from_parts(true, f16::EXP_BIAS, 0), -1.0f16); - assert_biteq!(f16::from_parts(false, 0, 1), f16::from_bits(0x1)); - } - - #[test] - fn check_f32() { - // Constants - assert_eq!(f32::EXP_SAT, 0b11111111); - assert_eq!(f32::EXP_BIAS, 127); - assert_eq!(f32::EXP_MAX, 127); - assert_eq!(f32::EXP_MIN, -126); - assert_eq!(f32::EXP_MIN_SUBNORM, -149); - - // `exp_unbiased` - assert_eq!(f32::FRAC_PI_2.exp_unbiased(), 0); - assert_eq!((1.0f32 / 2.0).exp_unbiased(), -1); - assert_eq!(f32::MAX.exp_unbiased(), 127); - assert_eq!(f32::MIN.exp_unbiased(), 127); - assert_eq!(f32::MIN_POSITIVE.exp_unbiased(), -126); - // This is a convenience method and not ldexp, `exp_unbiased` does not return correct - // results for zero and subnormals. - assert_eq!(f32::ZERO.exp_unbiased(), -127); - assert_eq!(f32::from_bits(0x1).exp_unbiased(), -127); - assert_eq!(f32::MIN_POSITIVE, f32::MIN_POSITIVE_NORMAL); - - // `from_parts` - assert_biteq!(f32::from_parts(true, f32::EXP_BIAS, 0), -1.0f32); - assert_biteq!(f32::from_parts(false, 10 + f32::EXP_BIAS, 0), hf32!("0x1p10")); - assert_biteq!(f32::from_parts(false, 0, 1), f32::from_bits(0x1)); - } - - #[test] - fn check_f64() { - // Constants - assert_eq!(f64::EXP_SAT, 0b11111111111); - assert_eq!(f64::EXP_BIAS, 1023); - assert_eq!(f64::EXP_MAX, 1023); - assert_eq!(f64::EXP_MIN, -1022); - assert_eq!(f64::EXP_MIN_SUBNORM, -1074); - - // `exp_unbiased` - assert_eq!(f64::FRAC_PI_2.exp_unbiased(), 0); - assert_eq!((1.0f64 / 2.0).exp_unbiased(), -1); - assert_eq!(f64::MAX.exp_unbiased(), 1023); - assert_eq!(f64::MIN.exp_unbiased(), 1023); - assert_eq!(f64::MIN_POSITIVE.exp_unbiased(), -1022); - // This is a convenience method and not ldexp, `exp_unbiased` does not return correct - // results for zero and subnormals. - assert_eq!(f64::ZERO.exp_unbiased(), -1023); - assert_eq!(f64::from_bits(0x1).exp_unbiased(), -1023); - assert_eq!(f64::MIN_POSITIVE, f64::MIN_POSITIVE_NORMAL); - - // `from_parts` - assert_biteq!(f64::from_parts(true, f64::EXP_BIAS, 0), -1.0f64); - assert_biteq!(f64::from_parts(false, 10 + f64::EXP_BIAS, 0), hf64!("0x1p10")); - assert_biteq!(f64::from_parts(false, 0, 1), f64::from_bits(0x1)); - } - - #[test] - #[cfg(f128_enabled)] - fn check_f128() { - // Constants - assert_eq!(f128::EXP_SAT, 0b111111111111111); - assert_eq!(f128::EXP_BIAS, 16383); - assert_eq!(f128::EXP_MAX, 16383); - assert_eq!(f128::EXP_MIN, -16382); - assert_eq!(f128::EXP_MIN_SUBNORM, -16494); - - // `exp_unbiased` - assert_eq!(f128::FRAC_PI_2.exp_unbiased(), 0); - assert_eq!((1.0f128 / 2.0).exp_unbiased(), -1); - assert_eq!(f128::MAX.exp_unbiased(), 16383); - assert_eq!(f128::MIN.exp_unbiased(), 16383); - assert_eq!(f128::MIN_POSITIVE.exp_unbiased(), -16382); - // This is a convenience method and not ldexp, `exp_unbiased` does not return correct - // results for zero and subnormals. - assert_eq!(f128::ZERO.exp_unbiased(), -16383); - assert_eq!(f128::from_bits(0x1).exp_unbiased(), -16383); - assert_eq!(f128::MIN_POSITIVE, f128::MIN_POSITIVE_NORMAL); - - // `from_parts` - assert_biteq!(f128::from_parts(true, f128::EXP_BIAS, 0), -1.0f128); - assert_biteq!(f128::from_parts(false, 0, 1), f128::from_bits(0x1)); - } -} diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs deleted file mode 100644 index 819e2f56e36..00000000000 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ /dev/null @@ -1,1155 +0,0 @@ -//! Utilities for working with hex float formats. - -use core::fmt; - -use super::{Float, Round, Status, f32_from_bits, f64_from_bits}; - -/// Construct a 16-bit float from hex float representation (C-style) -#[cfg(f16_enabled)] -pub const fn hf16(s: &str) -> f16 { - match parse_hex_exact(s, 16, 10) { - Ok(bits) => f16::from_bits(bits as u16), - Err(HexFloatParseError(s)) => panic!("{}", s), - } -} - -/// Construct a 32-bit float from hex float representation (C-style) -#[allow(unused)] -pub const fn hf32(s: &str) -> f32 { - match parse_hex_exact(s, 32, 23) { - Ok(bits) => f32_from_bits(bits as u32), - Err(HexFloatParseError(s)) => panic!("{}", s), - } -} - -/// Construct a 64-bit float from hex float representation (C-style) -pub const fn hf64(s: &str) -> f64 { - match parse_hex_exact(s, 64, 52) { - Ok(bits) => f64_from_bits(bits as u64), - Err(HexFloatParseError(s)) => panic!("{}", s), - } -} - -/// Construct a 128-bit float from hex float representation (C-style) -#[cfg(f128_enabled)] -pub const fn hf128(s: &str) -> f128 { - match parse_hex_exact(s, 128, 112) { - Ok(bits) => f128::from_bits(bits), - Err(HexFloatParseError(s)) => panic!("{}", s), - } -} -#[derive(Copy, Clone, Debug)] -pub struct HexFloatParseError(&'static str); - -/// Parses any float to its bitwise representation, returning an error if it cannot be represented exactly -pub const fn parse_hex_exact( - s: &str, - bits: u32, - sig_bits: u32, -) -> Result { - match parse_any(s, bits, sig_bits, Round::Nearest) { - Err(e) => Err(e), - Ok((bits, Status::OK)) => Ok(bits), - Ok((_, status)) if status.overflow() => Err(HexFloatParseError("the value is too huge")), - Ok((_, status)) if status.underflow() => Err(HexFloatParseError("the value is too tiny")), - Ok((_, status)) if status.inexact() => Err(HexFloatParseError("the value is too precise")), - Ok(_) => unreachable!(), - } -} - -/// Parse any float from hex to its bitwise representation. -pub const fn parse_any( - s: &str, - bits: u32, - sig_bits: u32, - round: Round, -) -> Result<(u128, Status), HexFloatParseError> { - let mut b = s.as_bytes(); - - if sig_bits > 119 || bits > 128 || bits < sig_bits + 3 || bits > sig_bits + 30 { - return Err(HexFloatParseError("unsupported target float configuration")); - } - - let neg = matches!(b, [b'-', ..]); - if let &[b'-' | b'+', ref rest @ ..] = b { - b = rest; - } - - let sign_bit = 1 << (bits - 1); - let quiet_bit = 1 << (sig_bits - 1); - let nan = sign_bit - quiet_bit; - let inf = nan - quiet_bit; - - let (mut x, status) = match *b { - [b'i' | b'I', b'n' | b'N', b'f' | b'F'] => (inf, Status::OK), - [b'n' | b'N', b'a' | b'A', b'n' | b'N'] => (nan, Status::OK), - [b'0', b'x' | b'X', ref rest @ ..] => { - let round = match (neg, round) { - // parse("-x", Round::Positive) == -parse("x", Round::Negative) - (true, Round::Positive) => Round::Negative, - (true, Round::Negative) => Round::Positive, - // rounding toward nearest or zero are symmetric - (true, Round::Nearest | Round::Zero) | (false, _) => round, - }; - match parse_finite(rest, bits, sig_bits, round) { - Err(e) => return Err(e), - Ok(res) => res, - } - } - _ => return Err(HexFloatParseError("no hex indicator")), - }; - - if neg { - x ^= sign_bit; - } - - Ok((x, status)) -} - -const fn parse_finite( - b: &[u8], - bits: u32, - sig_bits: u32, - rounding_mode: Round, -) -> Result<(u128, Status), HexFloatParseError> { - let exp_bits: u32 = bits - sig_bits - 1; - let max_msb: i32 = (1 << (exp_bits - 1)) - 1; - // The exponent of one ULP in the subnormals - let min_lsb: i32 = 1 - max_msb - sig_bits as i32; - - let (mut sig, mut exp) = match parse_hex(b) { - Err(e) => return Err(e), - Ok(Parsed { sig: 0, .. }) => return Ok((0, Status::OK)), - Ok(Parsed { sig, exp }) => (sig, exp), - }; - - let mut round_bits = u128_ilog2(sig) as i32 - sig_bits as i32; - - // Round at least up to min_lsb - if exp < min_lsb - round_bits { - round_bits = min_lsb - exp; - } - - let mut status = Status::OK; - - exp += round_bits; - - if round_bits > 0 { - // first, prepare for rounding exactly two bits - if round_bits == 1 { - sig <<= 1; - } else if round_bits > 2 { - sig = shr_odd_rounding(sig, (round_bits - 2) as u32); - } - - if sig & 0b11 != 0 { - status = Status::INEXACT; - } - - sig = shr2_round(sig, rounding_mode); - } else if round_bits < 0 { - sig <<= -round_bits; - } - - // The parsed value is X = sig * 2^exp - // Expressed as a multiple U of the smallest subnormal value: - // X = U * 2^min_lsb, so U = sig * 2^(exp-min_lsb) - let uexp = (exp - min_lsb) as u128; - let uexp = uexp << sig_bits; - - // Note that it is possible for the exponent bits to equal 2 here - // if the value rounded up, but that means the mantissa is all zeroes - // so the value is still correct - debug_assert!(sig <= 2 << sig_bits); - - let inf = ((1 << exp_bits) - 1) << sig_bits; - - let bits = match sig.checked_add(uexp) { - Some(bits) if bits < inf => { - // inexact subnormal or zero? - if status.inexact() && bits < (1 << sig_bits) { - status = status.with(Status::UNDERFLOW); - } - bits - } - _ => { - // overflow to infinity - status = status.with(Status::OVERFLOW).with(Status::INEXACT); - match rounding_mode { - Round::Positive | Round::Nearest => inf, - Round::Negative | Round::Zero => inf - 1, - } - } - }; - Ok((bits, status)) -} - -/// Shift right, rounding all inexact divisions to the nearest odd number -/// E.g. (0 >> 4) -> 0, (1..=31 >> 4) -> 1, (32 >> 4) -> 2, ... -/// -/// Useful for reducing a number before rounding the last two bits, since -/// the result of the final rounding is preserved for all rounding modes. -const fn shr_odd_rounding(x: u128, k: u32) -> u128 { - if k < 128 { - let inexact = x.trailing_zeros() < k; - (x >> k) | (inexact as u128) - } else { - (x != 0) as u128 - } -} - -/// Divide by 4, rounding with the given mode -const fn shr2_round(mut x: u128, round: Round) -> u128 { - let t = (x as u32) & 0b111; - x >>= 2; - match round { - // Look-up-table on the last three bits for when to round up - Round::Nearest => x + ((0b11001000_u8 >> t) & 1) as u128, - - Round::Negative => x, - Round::Zero => x, - Round::Positive => x + (t & 0b11 != 0) as u128, - } -} - -/// A parsed finite and unsigned floating point number. -struct Parsed { - /// Absolute value sig * 2^exp - sig: u128, - exp: i32, -} - -/// Parse a hexadecimal float x -const fn parse_hex(mut b: &[u8]) -> Result { - let mut sig: u128 = 0; - let mut exp: i32 = 0; - - let mut seen_point = false; - let mut some_digits = false; - let mut inexact = false; - - while let &[c, ref rest @ ..] = b { - b = rest; - - match c { - b'.' => { - if seen_point { - return Err(HexFloatParseError("unexpected '.' parsing fractional digits")); - } - seen_point = true; - continue; - } - b'p' | b'P' => break, - c => { - let digit = match hex_digit(c) { - Some(d) => d, - None => return Err(HexFloatParseError("expected hexadecimal digit")), - }; - some_digits = true; - - if (sig >> 124) == 0 { - sig <<= 4; - sig |= digit as u128; - } else { - // FIXME: it is technically possible for exp to overflow if parsing a string with >500M digits - exp += 4; - inexact |= digit != 0; - } - // Up until the fractional point, the value grows - // with more digits, but after it the exponent is - // compensated to match. - if seen_point { - exp -= 4; - } - } - } - } - // If we've set inexact, the exact value has more than 125 - // significant bits, and lies somewhere between sig and sig + 1. - // Because we'll round off at least two of the trailing bits, - // setting the last bit gives correct rounding for inexact values. - sig |= inexact as u128; - - if !some_digits { - return Err(HexFloatParseError("at least one digit is required")); - }; - - some_digits = false; - - let negate_exp = matches!(b, [b'-', ..]); - if let &[b'-' | b'+', ref rest @ ..] = b { - b = rest; - } - - let mut pexp: u32 = 0; - while let &[c, ref rest @ ..] = b { - b = rest; - let digit = match dec_digit(c) { - Some(d) => d, - None => return Err(HexFloatParseError("expected decimal digit")), - }; - some_digits = true; - pexp = pexp.saturating_mul(10); - pexp += digit as u32; - } - - if !some_digits { - return Err(HexFloatParseError("at least one exponent digit is required")); - }; - - { - let e; - if negate_exp { - e = (exp as i64) - (pexp as i64); - } else { - e = (exp as i64) + (pexp as i64); - }; - - exp = if e < i32::MIN as i64 { - i32::MIN - } else if e > i32::MAX as i64 { - i32::MAX - } else { - e as i32 - }; - } - /* FIXME(msrv): once MSRV >= 1.66, replace the above workaround block with: - if negate_exp { - exp = exp.saturating_sub_unsigned(pexp); - } else { - exp = exp.saturating_add_unsigned(pexp); - }; - */ - - Ok(Parsed { sig, exp }) -} - -const fn dec_digit(c: u8) -> Option { - match c { - b'0'..=b'9' => Some(c - b'0'), - _ => None, - } -} - -const fn hex_digit(c: u8) -> Option { - match c { - b'0'..=b'9' => Some(c - b'0'), - b'a'..=b'f' => Some(c - b'a' + 10), - b'A'..=b'F' => Some(c - b'A' + 10), - _ => None, - } -} - -/* FIXME(msrv): vendor some things that are not const stable at our MSRV */ - -/// `u128::ilog2` -const fn u128_ilog2(v: u128) -> u32 { - assert!(v != 0); - u128::BITS - 1 - v.leading_zeros() -} - -/// Format a floating point number as its IEEE hex (`%a`) representation. -pub struct Hexf(pub F); - -// Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs -#[cfg(not(feature = "compiler-builtins"))] -fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if x.is_sign_negative() { - write!(f, "-")?; - } - - if x.is_nan() { - return write!(f, "NaN"); - } else if x.is_infinite() { - return write!(f, "inf"); - } else if *x == F::ZERO { - return write!(f, "0x0p+0"); - } - - let mut exponent = x.exp_unbiased(); - let sig = x.to_bits() & F::SIG_MASK; - - let bias = F::EXP_BIAS as i32; - // The mantissa MSB needs to be shifted up to the nearest nibble. - let mshift = (4 - (F::SIG_BITS % 4)) % 4; - let sig = sig << mshift; - // The width is rounded up to the nearest char (4 bits) - let mwidth = (F::SIG_BITS as usize + 3) / 4; - let leading = if exponent == -bias { - // subnormal number means we shift our output by 1 bit. - exponent += 1; - "0." - } else { - "1." - }; - - write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") -} - -#[cfg(feature = "compiler-builtins")] -fn fmt_any_hex(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() -} - -impl fmt::LowerHex for Hexf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt_any_hex(&self.0, f) - } - } - } -} - -impl fmt::LowerHex for Hexf<(F, F)> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) - } - } - } -} - -impl fmt::LowerHex for Hexf<(F, i32)> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) - } - } - } -} - -impl fmt::LowerHex for Hexf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(&self.0, f) - } - } - } -} - -impl fmt::Debug for Hexf -where - Hexf: fmt::LowerHex, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(self, f) - } - } - } -} - -impl fmt::Display for Hexf -where - Hexf: fmt::LowerHex, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(self, f) - } - } - } -} - -#[cfg(test)] -mod parse_tests { - extern crate std; - use std::{format, println}; - - use super::*; - - #[cfg(f16_enabled)] - fn rounding_properties(s: &str) -> Result<(), HexFloatParseError> { - let (xd, s0) = parse_any(s, 16, 10, Round::Negative)?; - let (xu, s1) = parse_any(s, 16, 10, Round::Positive)?; - let (xz, s2) = parse_any(s, 16, 10, Round::Zero)?; - let (xn, s3) = parse_any(s, 16, 10, Round::Nearest)?; - - // FIXME: A value between the least normal and largest subnormal - // could have underflow status depend on rounding mode. - - if let Status::OK = s0 { - // an exact result is the same for all rounding modes - assert_eq!(s0, s1); - assert_eq!(s0, s2); - assert_eq!(s0, s3); - - assert_eq!(xd, xu); - assert_eq!(xd, xz); - assert_eq!(xd, xn); - } else { - assert!([s0, s1, s2, s3].into_iter().all(Status::inexact)); - - let xd = f16::from_bits(xd as u16); - let xu = f16::from_bits(xu as u16); - let xz = f16::from_bits(xz as u16); - let xn = f16::from_bits(xn as u16); - - assert_biteq!(xd.next_up(), xu, "s={s}, xd={xd:?}, xu={xu:?}"); - - let signs = [xd, xu, xz, xn].map(f16::is_sign_negative); - - if signs == [true; 4] { - assert_biteq!(xz, xu); - } else { - assert_eq!(signs, [false; 4]); - assert_biteq!(xz, xd); - } - - if xn.to_bits() != xd.to_bits() { - assert_biteq!(xn, xu); - } - } - Ok(()) - } - #[test] - #[cfg(f16_enabled)] - fn test_rounding() { - let n = 1_i32 << 14; - for i in -n..n { - let u = i.rotate_right(11) as u32; - let s = format!("{}", Hexf(f32::from_bits(u))); - assert!(rounding_properties(&s).is_ok()); - } - } - - #[test] - fn test_parse_any() { - for k in -149..=127 { - let s = format!("0x1p{k}"); - let x = hf32(&s); - let y = if k < 0 { 0.5f32.powi(-k) } else { 2.0f32.powi(k) }; - assert_eq!(x, y); - } - - let mut s = *b"0x.0000000p-121"; - for e in 0..40 { - for k in 0..(1 << 15) { - let expected = f32::from_bits(k) * 2.0f32.powi(e); - let x = hf32(std::str::from_utf8(&s).unwrap()); - assert_eq!( - x.to_bits(), - expected.to_bits(), - "\ - e={e}\n\ - k={k}\n\ - x={x}\n\ - expected={expected}\n\ - s={}\n\ - f32::from_bits(k)={}\n\ - 2.0f32.powi(e)={}\ - ", - std::str::from_utf8(&s).unwrap(), - f32::from_bits(k), - 2.0f32.powi(e), - ); - for i in (3..10).rev() { - if s[i] == b'f' { - s[i] = b'0'; - } else if s[i] == b'9' { - s[i] = b'a'; - break; - } else { - s[i] += 1; - break; - } - } - } - for i in (12..15).rev() { - if s[i] == b'0' { - s[i] = b'9'; - } else { - s[i] -= 1; - break; - } - } - for i in (3..10).rev() { - s[i] = b'0'; - } - } - } - - // FIXME: this test is causing failures that are likely UB on various platforms - #[cfg(all(target_arch = "x86_64", target_os = "linux"))] - #[test] - #[cfg(f128_enabled)] - fn rounding() { - let pi = std::f128::consts::PI; - let s = format!("{}", Hexf(pi)); - - for k in 0..=111 { - let (bits, status) = parse_any(&s, 128 - k, 112 - k, Round::Nearest).unwrap(); - let scale = (1u128 << (112 - k - 1)) as f128; - let expected = (pi * scale).round_ties_even() / scale; - assert_eq!(bits << k, expected.to_bits(), "k = {k}, s = {s}"); - assert_eq!(expected != pi, status.inexact()); - } - } - #[test] - fn rounding_extreme_underflow() { - for k in 1..1000 { - let s = format!("0x1p{}", -149 - k); - let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; - assert_eq!(bits, 0, "{s} should round to zero, got bits={bits}"); - assert!(status.underflow(), "should indicate underflow when parsing {s}"); - assert!(status.inexact(), "should indicate inexact when parsing {s}"); - } - } - #[test] - fn long_tail() { - for k in 1..1000 { - let s = format!("0x1.{}p0", "0".repeat(k)); - let Ok(bits) = parse_hex_exact(&s, 32, 23) else { panic!("parsing {s} failed") }; - assert_eq!(f32::from_bits(bits as u32), 1.0); - - let s = format!("0x1.{}1p0", "0".repeat(k)); - let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; - if status.inexact() { - assert!(1.0 == f32::from_bits(bits as u32)); - } else { - assert!(1.0 < f32::from_bits(bits as u32)); - } - } - } - // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to - // hide them from the AST. - #[cfg(f16_enabled)] - macro_rules! f16_tests { - () => { - #[test] - fn test_f16() { - let checks = [ - ("0x.1234p+16", (0x1234 as f16).to_bits()), - ("0x1.234p+12", (0x1234 as f16).to_bits()), - ("0x12.34p+8", (0x1234 as f16).to_bits()), - ("0x123.4p+4", (0x1234 as f16).to_bits()), - ("0x1234p+0", (0x1234 as f16).to_bits()), - ("0x1234.p+0", (0x1234 as f16).to_bits()), - ("0x1234.0p+0", (0x1234 as f16).to_bits()), - ("0x1.ffcp+15", f16::MAX.to_bits()), - ("0x1.0p+1", 2.0f16.to_bits()), - ("0x1.0p+0", 1.0f16.to_bits()), - ("0x1.ffp+8", 0x5ffc), - ("+0x1.ffp+8", 0x5ffc), - ("0x1p+0", 0x3c00), - ("0x1.998p-4", 0x2e66), - ("0x1.9p+6", 0x5640), - ("0x0.0p0", 0.0f16.to_bits()), - ("-0x0.0p0", (-0.0f16).to_bits()), - ("0x1.0p0", 1.0f16.to_bits()), - ("0x1.998p-4", (0.1f16).to_bits()), - ("-0x1.998p-4", (-0.1f16).to_bits()), - ("0x0.123p-12", 0x0123), - ("0x1p-24", 0x0001), - ("nan", f16::NAN.to_bits()), - ("-nan", (-f16::NAN).to_bits()), - ("inf", f16::INFINITY.to_bits()), - ("-inf", f16::NEG_INFINITY.to_bits()), - ]; - for (s, exp) in checks { - println!("parsing {s}"); - assert!(rounding_properties(s).is_ok()); - let act = hf16(s).to_bits(); - assert_eq!( - act, exp, - "parsing {s}: {act:#06x} != {exp:#06x}\nact: {act:#018b}\nexp: {exp:#018b}" - ); - } - } - - #[test] - fn test_macros_f16() { - assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); - } - }; - } - - #[cfg(f16_enabled)] - f16_tests!(); - - #[test] - fn test_f32() { - let checks = [ - ("0x.1234p+16", (0x1234 as f32).to_bits()), - ("0x1.234p+12", (0x1234 as f32).to_bits()), - ("0x12.34p+8", (0x1234 as f32).to_bits()), - ("0x123.4p+4", (0x1234 as f32).to_bits()), - ("0x1234p+0", (0x1234 as f32).to_bits()), - ("0x1234.p+0", (0x1234 as f32).to_bits()), - ("0x1234.0p+0", (0x1234 as f32).to_bits()), - ("0x1.fffffep+127", f32::MAX.to_bits()), - ("0x1.0p+1", 2.0f32.to_bits()), - ("0x1.0p+0", 1.0f32.to_bits()), - ("0x1.ffep+8", 0x43fff000), - ("+0x1.ffep+8", 0x43fff000), - ("0x1p+0", 0x3f800000), - ("0x1.99999ap-4", 0x3dcccccd), - ("0x1.9p+6", 0x42c80000), - ("0x1.2d5ed2p+20", 0x4996af69), - ("-0x1.348eb8p+10", 0xc49a475c), - ("-0x1.33dcfep-33", 0xaf19ee7f), - ("0x0.0p0", 0.0f32.to_bits()), - ("-0x0.0p0", (-0.0f32).to_bits()), - ("0x1.0p0", 1.0f32.to_bits()), - ("0x1.99999ap-4", (0.1f32).to_bits()), - ("-0x1.99999ap-4", (-0.1f32).to_bits()), - ("0x1.111114p-127", 0x00444445), - ("0x1.23456p-130", 0x00091a2b), - ("0x1p-149", 0x00000001), - ("nan", f32::NAN.to_bits()), - ("-nan", (-f32::NAN).to_bits()), - ("inf", f32::INFINITY.to_bits()), - ("-inf", f32::NEG_INFINITY.to_bits()), - ]; - for (s, exp) in checks { - println!("parsing {s}"); - let act = hf32(s).to_bits(); - assert_eq!( - act, exp, - "parsing {s}: {act:#010x} != {exp:#010x}\nact: {act:#034b}\nexp: {exp:#034b}" - ); - } - } - - #[test] - fn test_f64() { - let checks = [ - ("0x.1234p+16", (0x1234 as f64).to_bits()), - ("0x1.234p+12", (0x1234 as f64).to_bits()), - ("0x12.34p+8", (0x1234 as f64).to_bits()), - ("0x123.4p+4", (0x1234 as f64).to_bits()), - ("0x1234p+0", (0x1234 as f64).to_bits()), - ("0x1234.p+0", (0x1234 as f64).to_bits()), - ("0x1234.0p+0", (0x1234 as f64).to_bits()), - ("0x1.ffep+8", 0x407ffe0000000000), - ("0x1p+0", 0x3ff0000000000000), - ("0x1.999999999999ap-4", 0x3fb999999999999a), - ("0x1.9p+6", 0x4059000000000000), - ("0x1.2d5ed1fe1da7bp+20", 0x4132d5ed1fe1da7b), - ("-0x1.348eb851eb852p+10", 0xc09348eb851eb852), - ("-0x1.33dcfe54a3803p-33", 0xbde33dcfe54a3803), - ("0x1.0p0", 1.0f64.to_bits()), - ("0x0.0p0", 0.0f64.to_bits()), - ("-0x0.0p0", (-0.0f64).to_bits()), - ("0x1.999999999999ap-4", 0.1f64.to_bits()), - ("0x1.999999999998ap-4", (0.1f64 - f64::EPSILON).to_bits()), - ("-0x1.999999999999ap-4", (-0.1f64).to_bits()), - ("-0x1.999999999998ap-4", (-0.1f64 + f64::EPSILON).to_bits()), - ("0x0.8000000000001p-1022", 0x0008000000000001), - ("0x0.123456789abcdp-1022", 0x000123456789abcd), - ("0x0.0000000000002p-1022", 0x0000000000000002), - ("nan", f64::NAN.to_bits()), - ("-nan", (-f64::NAN).to_bits()), - ("inf", f64::INFINITY.to_bits()), - ("-inf", f64::NEG_INFINITY.to_bits()), - ]; - for (s, exp) in checks { - println!("parsing {s}"); - let act = hf64(s).to_bits(); - assert_eq!( - act, exp, - "parsing {s}: {act:#018x} != {exp:#018x}\nact: {act:#066b}\nexp: {exp:#066b}" - ); - } - } - - // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to - // hide them from the AST. - #[cfg(f128_enabled)] - macro_rules! f128_tests { - () => { - #[test] - fn test_f128() { - let checks = [ - ("0x.1234p+16", (0x1234 as f128).to_bits()), - ("0x1.234p+12", (0x1234 as f128).to_bits()), - ("0x12.34p+8", (0x1234 as f128).to_bits()), - ("0x123.4p+4", (0x1234 as f128).to_bits()), - ("0x1234p+0", (0x1234 as f128).to_bits()), - ("0x1234.p+0", (0x1234 as f128).to_bits()), - ("0x1234.0p+0", (0x1234 as f128).to_bits()), - ("0x1.ffffffffffffffffffffffffffffp+16383", f128::MAX.to_bits()), - ("0x1.0p+1", 2.0f128.to_bits()), - ("0x1.0p+0", 1.0f128.to_bits()), - ("0x1.ffep+8", 0x4007ffe0000000000000000000000000), - ("+0x1.ffep+8", 0x4007ffe0000000000000000000000000), - ("0x1p+0", 0x3fff0000000000000000000000000000), - ("0x1.999999999999999999999999999ap-4", 0x3ffb999999999999999999999999999a), - ("0x1.9p+6", 0x40059000000000000000000000000000), - ("0x0.0p0", 0.0f128.to_bits()), - ("-0x0.0p0", (-0.0f128).to_bits()), - ("0x1.0p0", 1.0f128.to_bits()), - ("0x1.999999999999999999999999999ap-4", (0.1f128).to_bits()), - ("-0x1.999999999999999999999999999ap-4", (-0.1f128).to_bits()), - ("0x0.abcdef0123456789abcdef012345p-16382", 0x0000abcdef0123456789abcdef012345), - ("0x1p-16494", 0x00000000000000000000000000000001), - ("nan", f128::NAN.to_bits()), - ("-nan", (-f128::NAN).to_bits()), - ("inf", f128::INFINITY.to_bits()), - ("-inf", f128::NEG_INFINITY.to_bits()), - ]; - for (s, exp) in checks { - println!("parsing {s}"); - let act = hf128(s).to_bits(); - assert_eq!( - act, exp, - "parsing {s}: {act:#034x} != {exp:#034x}\nact: {act:#0130b}\nexp: {exp:#0130b}" - ); - } - } - - #[test] - fn test_macros_f128() { - assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); - } - } - } - - #[cfg(f128_enabled)] - f128_tests!(); - - #[test] - fn test_macros() { - #[cfg(f16_enabled)] - assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); - assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000_u32); - assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000_u64); - #[cfg(f128_enabled)] - assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); - } -} - -#[cfg(test)] -// FIXME(ppc): something with `should_panic` tests cause a SIGILL with ppc64le -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] -mod tests_panicking { - extern crate std; - use super::*; - - // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to - // hide them from the AST. - #[cfg(f16_enabled)] - macro_rules! f16_tests { - () => { - #[test] - fn test_f16_almost_extra_precision() { - // Exact maximum precision allowed - hf16("0x1.ffcp+0"); - } - - #[test] - #[should_panic(expected = "the value is too precise")] - fn test_f16_extra_precision() { - // One bit more than the above. - hf16("0x1.ffdp+0"); - } - - #[test] - #[should_panic(expected = "the value is too huge")] - fn test_f16_overflow() { - // One bit more than the above. - hf16("0x1p+16"); - } - - #[test] - fn test_f16_tiniest() { - let x = hf16("0x1.p-24"); - let y = hf16("0x0.001p-12"); - let z = hf16("0x0.8p-23"); - assert_eq!(x, y); - assert_eq!(x, z); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f16_too_tiny() { - hf16("0x1.p-25"); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f16_also_too_tiny() { - hf16("0x0.8p-24"); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f16_again_too_tiny() { - hf16("0x0.001p-13"); - } - }; - } - - #[cfg(f16_enabled)] - f16_tests!(); - - #[test] - fn test_f32_almost_extra_precision() { - // Exact maximum precision allowed - hf32("0x1.abcdeep+0"); - } - - #[test] - #[should_panic] - fn test_f32_extra_precision2() { - // One bit more than the above. - hf32("0x1.ffffffp+127"); - } - - #[test] - #[should_panic(expected = "the value is too huge")] - fn test_f32_overflow() { - // One bit more than the above. - hf32("0x1p+128"); - } - - #[test] - #[should_panic(expected = "the value is too precise")] - fn test_f32_extra_precision() { - // One bit more than the above. - hf32("0x1.abcdefp+0"); - } - - #[test] - fn test_f32_tiniest() { - let x = hf32("0x1.p-149"); - let y = hf32("0x0.0000000000000001p-85"); - let z = hf32("0x0.8p-148"); - assert_eq!(x, y); - assert_eq!(x, z); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f32_too_tiny() { - hf32("0x1.p-150"); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f32_also_too_tiny() { - hf32("0x0.8p-149"); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f32_again_too_tiny() { - hf32("0x0.0000000000000001p-86"); - } - - #[test] - fn test_f64_almost_extra_precision() { - // Exact maximum precision allowed - hf64("0x1.abcdabcdabcdfp+0"); - } - - #[test] - #[should_panic(expected = "the value is too precise")] - fn test_f64_extra_precision() { - // One bit more than the above. - hf64("0x1.abcdabcdabcdf8p+0"); - } - - // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to - // hide them from the AST. - #[cfg(f128_enabled)] - macro_rules! f128_tests { - () => { - #[test] - fn test_f128_almost_extra_precision() { - // Exact maximum precision allowed - hf128("0x1.ffffffffffffffffffffffffffffp+16383"); - } - - #[test] - #[should_panic(expected = "the value is too precise")] - fn test_f128_extra_precision() { - // Just below the maximum finite. - hf128("0x1.fffffffffffffffffffffffffffe8p+16383"); - } - #[test] - #[should_panic(expected = "the value is too huge")] - fn test_f128_extra_precision_overflow() { - // One bit more than the above. Should overflow. - hf128("0x1.ffffffffffffffffffffffffffff8p+16383"); - } - - #[test] - #[should_panic(expected = "the value is too huge")] - fn test_f128_overflow() { - // One bit more than the above. - hf128("0x1p+16384"); - } - - #[test] - fn test_f128_tiniest() { - let x = hf128("0x1.p-16494"); - let y = hf128("0x0.0000000000000001p-16430"); - let z = hf128("0x0.8p-16493"); - assert_eq!(x, y); - assert_eq!(x, z); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f128_too_tiny() { - hf128("0x1.p-16495"); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f128_again_too_tiny() { - hf128("0x0.0000000000000001p-16431"); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f128_also_too_tiny() { - hf128("0x0.8p-16494"); - } - }; - } - - #[cfg(f128_enabled)] - f128_tests!(); -} - -#[cfg(test)] -mod print_tests { - extern crate std; - use std::string::ToString; - - use super::*; - - #[test] - #[cfg(f16_enabled)] - fn test_f16() { - use std::format; - // Exhaustively check that `f16` roundtrips. - for x in 0..=u16::MAX { - let f = f16::from_bits(x); - let s = format!("{}", Hexf(f)); - let from_s = hf16(&s); - - if f.is_nan() && from_s.is_nan() { - continue; - } - - assert_eq!( - f.to_bits(), - from_s.to_bits(), - "{f:?} formatted as {s} but parsed as {from_s:?}" - ); - } - } - - #[test] - #[cfg(f16_enabled)] - fn test_f16_to_f32() { - use std::format; - // Exhaustively check that these are equivalent for all `f16`: - // - `f16 -> f32` - // - `f16 -> str -> f32` - // - `f16 -> f32 -> str -> f32` - // - `f16 -> f32 -> str -> f16 -> f32` - for x in 0..=u16::MAX { - let f16 = f16::from_bits(x); - let s16 = format!("{}", Hexf(f16)); - let f32 = f16 as f32; - let s32 = format!("{}", Hexf(f32)); - - let a = hf32(&s16); - let b = hf32(&s32); - let c = hf16(&s32); - - if f32.is_nan() && a.is_nan() && b.is_nan() && c.is_nan() { - continue; - } - - assert_eq!( - f32.to_bits(), - a.to_bits(), - "{f16:?} : f16 formatted as {s16} which parsed as {a:?} : f16" - ); - assert_eq!( - f32.to_bits(), - b.to_bits(), - "{f32:?} : f32 formatted as {s32} which parsed as {b:?} : f32" - ); - assert_eq!( - f32.to_bits(), - (c as f32).to_bits(), - "{f32:?} : f32 formatted as {s32} which parsed as {c:?} : f16" - ); - } - } - #[test] - fn spot_checks() { - assert_eq!(Hexf(f32::MAX).to_string(), "0x1.fffffep+127"); - assert_eq!(Hexf(f64::MAX).to_string(), "0x1.fffffffffffffp+1023"); - - assert_eq!(Hexf(f32::MIN).to_string(), "-0x1.fffffep+127"); - assert_eq!(Hexf(f64::MIN).to_string(), "-0x1.fffffffffffffp+1023"); - - assert_eq!(Hexf(f32::ZERO).to_string(), "0x0p+0"); - assert_eq!(Hexf(f64::ZERO).to_string(), "0x0p+0"); - - assert_eq!(Hexf(f32::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hexf(f64::NEG_ZERO).to_string(), "-0x0p+0"); - - assert_eq!(Hexf(f32::NAN).to_string(), "NaN"); - assert_eq!(Hexf(f64::NAN).to_string(), "NaN"); - - assert_eq!(Hexf(f32::INFINITY).to_string(), "inf"); - assert_eq!(Hexf(f64::INFINITY).to_string(), "inf"); - - assert_eq!(Hexf(f32::NEG_INFINITY).to_string(), "-inf"); - assert_eq!(Hexf(f64::NEG_INFINITY).to_string(), "-inf"); - - #[cfg(f16_enabled)] - { - assert_eq!(Hexf(f16::MAX).to_string(), "0x1.ffcp+15"); - assert_eq!(Hexf(f16::MIN).to_string(), "-0x1.ffcp+15"); - assert_eq!(Hexf(f16::ZERO).to_string(), "0x0p+0"); - assert_eq!(Hexf(f16::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hexf(f16::NAN).to_string(), "NaN"); - assert_eq!(Hexf(f16::INFINITY).to_string(), "inf"); - assert_eq!(Hexf(f16::NEG_INFINITY).to_string(), "-inf"); - } - - #[cfg(f128_enabled)] - { - assert_eq!(Hexf(f128::MAX).to_string(), "0x1.ffffffffffffffffffffffffffffp+16383"); - assert_eq!(Hexf(f128::MIN).to_string(), "-0x1.ffffffffffffffffffffffffffffp+16383"); - assert_eq!(Hexf(f128::ZERO).to_string(), "0x0p+0"); - assert_eq!(Hexf(f128::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hexf(f128::NAN).to_string(), "NaN"); - assert_eq!(Hexf(f128::INFINITY).to_string(), "inf"); - assert_eq!(Hexf(f128::NEG_INFINITY).to_string(), "-inf"); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs deleted file mode 100644 index 491adb1f22c..00000000000 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ /dev/null @@ -1,451 +0,0 @@ -use core::{cmp, fmt, ops}; - -/// Minimal integer implementations needed on all integer types, including wide integers. -pub trait MinInt: - Copy - + fmt::Debug - + ops::BitOr - + ops::Not - + ops::Shl -{ - /// Type with the same width but other signedness - type OtherSign: MinInt; - /// Unsigned version of Self - type Unsigned: MinInt; - - /// If `Self` is a signed integer - const SIGNED: bool; - - /// The bitwidth of the int type - const BITS: u32; - - const ZERO: Self; - const ONE: Self; - const MIN: Self; - const MAX: Self; -} - -/// Access the associated `OtherSign` type from an int (helper to avoid ambiguous associated -/// types). -pub type OtherSign = ::OtherSign; - -/// Trait for some basic operations on integers -#[allow(dead_code)] -pub trait Int: - MinInt - + fmt::Display - + fmt::Binary - + fmt::LowerHex - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Shl - + ops::Shl - + ops::Shr - + ops::Shr - + ops::BitXor - + ops::BitAnd - + cmp::Ord - + From - + CastFrom - + CastFrom - + CastFrom - + CastFrom - + CastFrom - + CastInto - + CastInto - + CastInto - + CastInto - + CastInto -{ - fn signed(self) -> OtherSign; - fn unsigned(self) -> Self::Unsigned; - fn from_unsigned(unsigned: Self::Unsigned) -> Self; - fn abs(self) -> Self; - - fn from_bool(b: bool) -> Self; - - /// Prevents the need for excessive conversions between signed and unsigned - fn logical_shr(self, other: u32) -> Self; - - /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::Unsigned; - - // copied from primitive integers, but put in a trait - fn is_zero(self) -> bool; - fn checked_add(self, other: Self) -> Option; - fn checked_sub(self, other: Self) -> Option; - fn wrapping_neg(self) -> Self; - fn wrapping_add(self, other: Self) -> Self; - fn wrapping_mul(self, other: Self) -> Self; - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn overflowing_sub(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - fn ilog2(self) -> u32; -} - -macro_rules! int_impl_common { - ($ty:ty) => { - fn from_bool(b: bool) -> Self { - b as $ty - } - - fn logical_shr(self, other: u32) -> Self { - Self::from_unsigned(self.unsigned().wrapping_shr(other)) - } - - fn is_zero(self) -> bool { - self == Self::ZERO - } - - fn checked_add(self, other: Self) -> Option { - self.checked_add(other) - } - - fn checked_sub(self, other: Self) -> Option { - self.checked_sub(other) - } - - fn wrapping_neg(self) -> Self { - ::wrapping_neg(self) - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn wrapping_shr(self, other: u32) -> Self { - ::wrapping_shr(self, other) - } - - fn rotate_left(self, other: u32) -> Self { - ::rotate_left(self, other) - } - - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } - - fn overflowing_sub(self, other: Self) -> (Self, bool) { - ::overflowing_sub(self, other) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - - fn ilog2(self) -> u32 { - // On our older MSRV, this resolves to the trait method. Which won't actually work, - // but this is only called behind other gates. - #[allow(clippy::incompatible_msrv)] - ::ilog2(self) - } - }; -} - -macro_rules! int_impl { - ($ity:ty, $uty:ty) => { - impl MinInt for $uty { - type OtherSign = $ity; - type Unsigned = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $uty { - fn signed(self) -> $ity { - self as $ity - } - - fn unsigned(self) -> Self { - self - } - - fn abs(self) -> Self { - unimplemented!() - } - - // It makes writing macros easier if this is implemented for both signed and unsigned - #[allow(clippy::wrong_self_convention)] - fn from_unsigned(me: $uty) -> Self { - me - } - - fn abs_diff(self, other: Self) -> Self { - self.abs_diff(other) - } - - int_impl_common!($uty); - } - - impl MinInt for $ity { - type OtherSign = $uty; - type Unsigned = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $ity { - fn signed(self) -> Self { - self - } - - fn unsigned(self) -> $uty { - self as $uty - } - - fn abs(self) -> Self { - self.abs() - } - - fn from_unsigned(me: $uty) -> Self { - me as $ity - } - - fn abs_diff(self, other: Self) -> $uty { - self.abs_diff(other) - } - - int_impl_common!($ity); - } - }; -} - -int_impl!(isize, usize); -int_impl!(i8, u8); -int_impl!(i16, u16); -int_impl!(i32, u32); -int_impl!(i64, u64); -int_impl!(i128, u128); - -/// Trait for integers twice the bit width of another integer. This is implemented for all -/// primitives except for `u8`, because there is not a smaller primitive. -pub trait DInt: MinInt { - /// Integer that is half the bit width of the integer this trait is implemented for - type H: HInt; - - /// Returns the low half of `self` - fn lo(self) -> Self::H; - /// Returns the high half of `self` - fn hi(self) -> Self::H; - /// Returns the low and high halves of `self` as a tuple - fn lo_hi(self) -> (Self::H, Self::H) { - (self.lo(), self.hi()) - } - /// Constructs an integer using lower and higher half parts - #[allow(unused)] - fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { - lo.zero_widen() | hi.widen_hi() - } -} - -/// Trait for integers half the bit width of another integer. This is implemented for all -/// primitives except for `u128`, because it there is not a larger primitive. -pub trait HInt: Int { - /// Integer that is double the bit width of the integer this trait is implemented for - type D: DInt + MinInt; - - // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for - // unknown reasons this can cause infinite recursion when optimizations are disabled. See - // for context. - - /// Widens (using default extension) the integer to have double bit width - fn widen(self) -> Self::D; - /// Widens (zero extension only) the integer to have double bit width. This is needed to get - /// around problems with associated type bounds (such as `Int`) being unstable - fn zero_widen(self) -> Self::D; - /// Widens the integer to have double bit width and shifts the integer into the higher bits - #[allow(unused)] - fn widen_hi(self) -> Self::D; - /// Widening multiplication with zero widening. This cannot overflow. - fn zero_widen_mul(self, rhs: Self) -> Self::D; - /// Widening multiplication. This cannot overflow. - fn widen_mul(self, rhs: Self) -> Self::D; -} - -macro_rules! impl_d_int { - ($($X:ident $D:ident),*) => { - $( - impl DInt for $D { - type H = $X; - - fn lo(self) -> Self::H { - self as $X - } - fn hi(self) -> Self::H { - (self >> <$X as MinInt>::BITS) as $X - } - } - )* - }; -} - -macro_rules! impl_h_int { - ($($H:ident $uH:ident $X:ident),*) => { - $( - impl HInt for $H { - type D = $X; - - fn widen(self) -> Self::D { - self as $X - } - fn zero_widen(self) -> Self::D { - (self as $uH) as $X - } - fn zero_widen_mul(self, rhs: Self) -> Self::D { - self.zero_widen().wrapping_mul(rhs.zero_widen()) - } - fn widen_mul(self, rhs: Self) -> Self::D { - self.widen().wrapping_mul(rhs.widen()) - } - fn widen_hi(self) -> Self::D { - (self as $X) << ::BITS - } - } - )* - }; -} - -impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); -impl_h_int!( - u8 u8 u16, - u16 u16 u32, - u32 u32 u64, - u64 u64 u128, - i8 u8 i16, - i16 u16 i32, - i32 u32 i64, - i64 u64 i128 -); - -/// Trait to express (possibly lossy) casting of integers -pub trait CastInto: Copy { - /// By default, casts should be exact. - fn cast(self) -> T; - - /// Call for casts that are expected to truncate. - fn cast_lossy(self) -> T; -} - -pub trait CastFrom: Copy { - /// By default, casts should be exact. - fn cast_from(value: T) -> Self; - - /// Call for casts that are expected to truncate. - fn cast_from_lossy(value: T) -> Self; -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } - - fn cast_from_lossy(value: U) -> Self { - value.cast_lossy() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - // All we can really do to enforce casting rules is check the rules when in - // debug mode. - #[cfg(not(feature = "compiler-builtins"))] - debug_assert!(<$into>::try_from(self).is_ok(), "failed cast from {self}"); - self as $into - } - - fn cast_lossy(self) -> $into { - self as $into - } - } - )*}; -} - -macro_rules! cast_into_float { - ($ty:ty) => { - #[cfg(f16_enabled)] - cast_into_float!($ty; f16); - - cast_into_float!($ty; f32, f64); - - #[cfg(f128_enabled)] - cast_into_float!($ty; f128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - #[cfg(not(feature = "compiler-builtins"))] - debug_assert_eq!(self as $into as $ty, self, "inexact float cast"); - self as $into - } - - fn cast_lossy(self) -> $into { - self as $into - } - } - )*}; -} - -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); - -cast_into_float!(i8); -cast_into_float!(i16); -cast_into_float!(i32); -cast_into_float!(i64); -cast_into_float!(i128); diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs deleted file mode 100644 index 0b72db0e46e..00000000000 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ /dev/null @@ -1,157 +0,0 @@ -/// `libm` cannot have dependencies, so this is vendored directly from the `cfg-if` crate -/// (with some comments stripped for compactness). -macro_rules! cfg_if { - // match if/else chains with a final `else` - ($( - if #[cfg($meta:meta)] { $($tokens:tt)* } - ) else * else { - $($tokens2:tt)* - }) => { - cfg_if! { @__items () ; $( ( ($meta) ($($tokens)*) ), )* ( () ($($tokens2)*) ), } - }; - - // match if/else chains lacking a final `else` - ( - if #[cfg($i_met:meta)] { $($i_tokens:tt)* } - $( else if #[cfg($e_met:meta)] { $($e_tokens:tt)* } )* - ) => { - cfg_if! { - @__items - () ; - ( ($i_met) ($($i_tokens)*) ), - $( ( ($e_met) ($($e_tokens)*) ), )* - ( () () ), - } - }; - - // Internal and recursive macro to emit all the items - // - // Collects all the negated cfgs in a list at the beginning and after the - // semicolon is all the remaining items - (@__items ($($not:meta,)*) ; ) => {}; - (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($tokens:tt)*) ), $($rest:tt)*) => { - #[cfg(all($($m,)* not(any($($not),*))))] cfg_if! { @__identity $($tokens)* } - cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } - }; - - // Internal macro to make __apply work out right for different match types, - // because of how macros matching/expand stuff. - (@__identity $($tokens:tt)*) => { $($tokens)* }; -} - -/// Choose between using an arch-specific implementation and the function body. Returns directly -/// if the arch implementation is used, otherwise continue with the rest of the function. -/// -/// Specify a `use_arch` meta field if an architecture-specific implementation is provided. -/// These live in the `math::arch::some_target_arch` module. -/// -/// Specify a `use_arch_required` meta field if something architecture-specific must be used -/// regardless of feature configuration (`force-soft-floats`). -/// -/// The passed meta options do not need to account for the `arch` target feature. -macro_rules! select_implementation { - ( - name: $fn_name:ident, - // Configuration meta for when to use arch-specific implementation that requires hard - // float ops - $( use_arch: $use_arch:meta, )? - // Configuration meta for when to use the arch module regardless of whether softfloats - // have been requested. - $( use_arch_required: $use_arch_required:meta, )? - args: $($arg:ident),+ , - ) => { - // FIXME: these use paths that are a pretty fragile (`super`). We should figure out - // something better w.r.t. how this is vendored into compiler-builtins. - - // However, we do need a few things from `arch` that are used even with soft floats. - select_implementation! { - @cfg $($use_arch_required)?; - if true { - return super::arch::$fn_name( $($arg),+ ); - } - } - - // By default, never use arch-specific implementations if we have force-soft-floats - #[cfg(arch_enabled)] - select_implementation! { - @cfg $($use_arch)?; - // Wrap in `if true` to avoid unused warnings - if true { - return super::arch::$fn_name( $($arg),+ ); - } - } - }; - - // Coalesce helper to construct an expression only if a config is provided - (@cfg ; $ex:expr) => { }; - (@cfg $provided:meta; $ex:expr) => { #[cfg($provided)] $ex }; -} - -/// Construct a 16-bit float from hex float representation (C-style), guaranteed to -/// evaluate at compile time. -#[cfg(f16_enabled)] -#[cfg_attr(feature = "unstable-public-internals", macro_export)] -#[allow(unused_macros)] -macro_rules! hf16 { - ($s:literal) => {{ - const X: f16 = $crate::support::hf16($s); - X - }}; -} - -/// Construct a 32-bit float from hex float representation (C-style), guaranteed to -/// evaluate at compile time. -#[allow(unused_macros)] -#[cfg_attr(feature = "unstable-public-internals", macro_export)] -macro_rules! hf32 { - ($s:literal) => {{ - const X: f32 = $crate::support::hf32($s); - X - }}; -} - -/// Construct a 64-bit float from hex float representation (C-style), guaranteed to -/// evaluate at compile time. -#[allow(unused_macros)] -#[cfg_attr(feature = "unstable-public-internals", macro_export)] -macro_rules! hf64 { - ($s:literal) => {{ - const X: f64 = $crate::support::hf64($s); - X - }}; -} - -/// Construct a 128-bit float from hex float representation (C-style), guaranteed to -/// evaluate at compile time. -#[cfg(f128_enabled)] -#[allow(unused_macros)] -#[cfg_attr(feature = "unstable-public-internals", macro_export)] -macro_rules! hf128 { - ($s:literal) => {{ - const X: f128 = $crate::support::hf128($s); - X - }}; -} - -/// Assert `F::biteq` with better messages. -#[cfg(test)] -macro_rules! assert_biteq { - ($left:expr, $right:expr, $($tt:tt)*) => {{ - use $crate::support::Int; - let l = $left; - let r = $right; - let bits = Int::leading_zeros(l.to_bits() - l.to_bits()); // hack to get the width from the value - assert!( - l.biteq(r), - "{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", - format_args!($($tt)*), - lb = l.to_bits(), - rb = r.to_bits(), - width = ((bits / 4) + 2) as usize, - - ); - }}; - ($left:expr, $right:expr $(,)?) => { - assert_biteq!($left, $right, "") - }; -} diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs deleted file mode 100644 index ee3f2bbdf02..00000000000 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -#[macro_use] -pub mod macros; -mod big; -mod env; -mod float_traits; -pub mod hex_float; -mod int_traits; - -#[allow(unused_imports)] -pub use big::{i256, u256}; -pub use env::{FpResult, Round, Status}; -#[allow(unused_imports)] -pub use float_traits::{DFloat, Float, HFloat, IntTy}; -pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; -#[cfg(f16_enabled)] -#[allow(unused_imports)] -pub use hex_float::hf16; -#[cfg(f128_enabled)] -#[allow(unused_imports)] -pub use hex_float::hf128; -#[allow(unused_imports)] -pub use hex_float::{Hexf, hf32, hf64}; -pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; - -/// Hint to the compiler that the current path is cold. -pub fn cold_path() { - #[cfg(intrinsics_enabled)] - core::intrinsics::cold_path(); -} diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs deleted file mode 100644 index a074ca5540a..00000000000 --- a/library/compiler-builtins/libm/src/math/tan.rs +++ /dev/null @@ -1,70 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */ -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunPro, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -use super::{k_tan, rem_pio2}; - -// tan(x) -// Return tangent function of x. -// -// kernel function: -// k_tan ... tangent function on [-pi/4,pi/4] -// rem_pio2 ... argument reduction routine -// -// Method. -// Let S,C and T denote the sin, cos and tan respectively on -// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 -// in [-pi/4 , +pi/4], and let n = k mod 4. -// We have -// -// n sin(x) cos(x) tan(x) -// ---------------------------------------------------------- -// 0 S C T -// 1 C -S -1/T -// 2 -S -C T -// 3 -C S -1/T -// ---------------------------------------------------------- -// -// Special cases: -// Let trig be any of sin, cos, or tan. -// trig(+-INF) is NaN, with signals; -// trig(NaN) is that NaN; -// -// Accuracy: -// TRIG(x) returns trig(x) nearly rounded - -/// The tangent of `x` (f64). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tan(x: f64) -> f64 { - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; - /* |x| ~< pi/4 */ - if ix <= 0x3fe921fb { - if ix < 0x3e400000 { - /* |x| < 2**-27 */ - /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00100000 { x / x1p120 as f64 } else { x + x1p120 as f64 }); - return x; - } - return k_tan(x, 0.0, 0); - } - - /* tan(Inf or NaN) is NaN */ - if ix >= 0x7ff00000 { - return x - x; - } - - /* argument reduction */ - let (n, y0, y1) = rem_pio2(x); - k_tan(y0, y1, n & 1) -} diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs deleted file mode 100644 index 7586aae4c7e..00000000000 --- a/library/compiler-builtins/libm/src/math/tanf.rs +++ /dev/null @@ -1,77 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_tanf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::f64::consts::FRAC_PI_2; - -use super::{k_tanf, rem_pio2f}; - -/* Small multiples of pi/2 rounded to double precision. */ -const T1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ -const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ - -/// The tangent of `x` (f32). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tanf(x: f32) -> f32 { - let x64 = x as f64; - - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - if ix <= 0x3f490fda { - /* |x| ~<= pi/4 */ - if ix < 0x39800000 { - /* |x| < 2**-12 */ - /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); - return x; - } - return k_tanf(x64, false); - } - if ix <= 0x407b53d1 { - /* |x| ~<= 5*pi/4 */ - if ix <= 0x4016cbe3 { - /* |x| ~<= 3pi/4 */ - return k_tanf(if sign { x64 + T1_PIO2 } else { x64 - T1_PIO2 }, true); - } else { - return k_tanf(if sign { x64 + T2_PIO2 } else { x64 - T2_PIO2 }, false); - } - } - if ix <= 0x40e231d5 { - /* |x| ~<= 9*pi/4 */ - if ix <= 0x40afeddf { - /* |x| ~<= 7*pi/4 */ - return k_tanf(if sign { x64 + T3_PIO2 } else { x64 - T3_PIO2 }, true); - } else { - return k_tanf(if sign { x64 + T4_PIO2 } else { x64 - T4_PIO2 }, false); - } - } - - /* tan(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - return x - x; - } - - /* argument reduction */ - let (n, y) = rem_pio2f(x); - k_tanf(y, n & 1 != 0) -} diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs deleted file mode 100644 index cc0abe4fcb2..00000000000 --- a/library/compiler-builtins/libm/src/math/tanh.rs +++ /dev/null @@ -1,53 +0,0 @@ -use super::expm1; - -/* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) - * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) - * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) - */ - -/// The hyperbolic tangent of `x` (f64). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tanh(mut x: f64) -> f64 { - let mut uf: f64 = x; - let mut ui: u64 = f64::to_bits(uf); - - let w: u32; - let sign: bool; - let mut t: f64; - - /* x = |x| */ - sign = ui >> 63 != 0; - ui &= !1 / 2; - uf = f64::from_bits(ui); - x = uf; - w = (ui >> 32) as u32; - - if w > 0x3fe193ea { - /* |x| > log(3)/2 ~= 0.5493 or nan */ - if w > 0x40340000 { - /* |x| > 20 or nan */ - /* note: this branch avoids raising overflow */ - t = 1.0 - 0.0 / x; - } else { - t = expm1(2.0 * x); - t = 1.0 - 2.0 / (t + 2.0); - } - } else if w > 0x3fd058ae { - /* |x| > log(5/3)/2 ~= 0.2554 */ - t = expm1(2.0 * x); - t = t / (t + 2.0); - } else if w >= 0x00100000 { - /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ - t = expm1(-2.0 * x); - t = -t / (t + 2.0); - } else { - /* |x| is subnormal */ - /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ - force_eval!(x as f32); - t = x; - } - - if sign { -t } else { t } -} diff --git a/library/compiler-builtins/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/src/math/tanhf.rs deleted file mode 100644 index fffbba6c6ec..00000000000 --- a/library/compiler-builtins/libm/src/math/tanhf.rs +++ /dev/null @@ -1,38 +0,0 @@ -use super::expm1f; - -/// The hyperbolic tangent of `x` (f32). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tanhf(mut x: f32) -> f32 { - /* x = |x| */ - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - x = f32::from_bits(ix); - let w = ix; - - let tt = if w > 0x3f0c9f54 { - /* |x| > log(3)/2 ~= 0.5493 or nan */ - if w > 0x41200000 { - /* |x| > 10 */ - 1. + 0. / x - } else { - let t = expm1f(2. * x); - 1. - 2. / (t + 2.) - } - } else if w > 0x3e82c578 { - /* |x| > log(5/3)/2 ~= 0.2554 */ - let t = expm1f(2. * x); - t / (t + 2.) - } else if w >= 0x00800000 { - /* |x| >= 0x1p-126 */ - let t = expm1f(-2. * x); - -t / (t + 2.) - } else { - /* |x| is subnormal */ - force_eval!(x * x); - x - }; - if sign { -tt } else { tt } -} diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs deleted file mode 100644 index 3059860646a..00000000000 --- a/library/compiler-builtins/libm/src/math/tgamma.rs +++ /dev/null @@ -1,209 +0,0 @@ -/* -"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) -"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) -"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) - -approximation method: - - (x - 0.5) S(x) -Gamma(x) = (x + g - 0.5) * ---------------- - exp(x + g - 0.5) - -with - a1 a2 a3 aN -S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] - x + 1 x + 2 x + 3 x + N - -with a0, a1, a2, a3,.. aN constants which depend on g. - -for x < 0 the following reflection formula is used: - -Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) - -most ideas and constants are from boost and python -*/ -use super::{exp, floor, k_cos, k_sin, pow}; - -const PI: f64 = 3.141592653589793238462643383279502884; - -/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ -fn sinpi(mut x: f64) -> f64 { - let mut n: isize; - - /* argument reduction: x = |x| mod 2 */ - /* spurious inexact when x is odd int */ - x = x * 0.5; - x = 2.0 * (x - floor(x)); - - /* reduce x into [-.25,.25] */ - n = (4.0 * x) as isize; - n = div!(n + 1, 2); - x -= (n as f64) * 0.5; - - x *= PI; - match n { - 1 => k_cos(x, 0.0), - 2 => k_sin(-x, 0.0, 0), - 3 => -k_cos(x, 0.0), - // 0 - _ => k_sin(x, 0.0, 0), - } -} - -const N: usize = 12; -//static const double g = 6.024680040776729583740234375; -const GMHALF: f64 = 5.524680040776729583740234375; -const SNUM: [f64; N + 1] = [ - 23531376880.410759688572007674451636754734846804940, - 42919803642.649098768957899047001988850926355848959, - 35711959237.355668049440185451547166705960488635843, - 17921034426.037209699919755754458931112671403265390, - 6039542586.3520280050642916443072979210699388420708, - 1439720407.3117216736632230727949123939715485786772, - 248874557.86205415651146038641322942321632125127801, - 31426415.585400194380614231628318205362874684987640, - 2876370.6289353724412254090516208496135991145378768, - 186056.26539522349504029498971604569928220784236328, - 8071.6720023658162106380029022722506138218516325024, - 210.82427775157934587250973392071336271166969580291, - 2.5066282746310002701649081771338373386264310793408, -]; -const SDEN: [f64; N + 1] = [ - 0.0, - 39916800.0, - 120543840.0, - 150917976.0, - 105258076.0, - 45995730.0, - 13339535.0, - 2637558.0, - 357423.0, - 32670.0, - 1925.0, - 66.0, - 1.0, -]; -/* n! for small integer n */ -const FACT: [f64; 23] = [ - 1.0, - 1.0, - 2.0, - 6.0, - 24.0, - 120.0, - 720.0, - 5040.0, - 40320.0, - 362880.0, - 3628800.0, - 39916800.0, - 479001600.0, - 6227020800.0, - 87178291200.0, - 1307674368000.0, - 20922789888000.0, - 355687428096000.0, - 6402373705728000.0, - 121645100408832000.0, - 2432902008176640000.0, - 51090942171709440000.0, - 1124000727777607680000.0, -]; - -/* S(x) rational function for positive x */ -fn s(x: f64) -> f64 { - let mut num: f64 = 0.0; - let mut den: f64 = 0.0; - - /* to avoid overflow handle large x differently */ - if x < 8.0 { - for i in (0..=N).rev() { - num = num * x + i!(SNUM, i); - den = den * x + i!(SDEN, i); - } - } else { - for i in 0..=N { - num = num / x + i!(SNUM, i); - den = den / x + i!(SDEN, i); - } - } - return num / den; -} - -/// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tgamma(mut x: f64) -> f64 { - let u: u64 = x.to_bits(); - let absx: f64; - let mut y: f64; - let mut dy: f64; - let mut z: f64; - let mut r: f64; - let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; - let sign: bool = (u >> 63) != 0; - - /* special cases */ - if ix >= 0x7ff00000 { - /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ - return x + f64::INFINITY; - } - if ix < ((0x3ff - 54) << 20) { - /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ - return 1.0 / x; - } - - /* integer arguments */ - /* raise inexact when non-integer */ - if x == floor(x) { - if sign { - return 0.0 / 0.0; - } - if x <= FACT.len() as f64 { - return i!(FACT, (x as usize) - 1); - } - } - - /* x >= 172: tgamma(x)=inf with overflow */ - /* x =< -184: tgamma(x)=+-0 with underflow */ - if ix >= 0x40670000 { - /* |x| >= 184 */ - if sign { - let x1p_126 = f64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 - force_eval!((x1p_126 / x) as f32); - if floor(x) * 0.5 == floor(x * 0.5) { - return 0.0; - } else { - return -0.0; - } - } - let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 - x *= x1p1023; - return x; - } - - absx = if sign { -x } else { x }; - - /* handle the error of x + g - 0.5 */ - y = absx + GMHALF; - if absx > GMHALF { - dy = y - absx; - dy -= GMHALF; - } else { - dy = y - GMHALF; - dy -= absx; - } - - z = absx - 0.5; - r = s(absx) * exp(-y); - if x < 0.0 { - /* reflection formula for negative x */ - /* sinpi(absx) is not 0, integers are already handled */ - r = -PI / (sinpi(absx) * absx * r); - dy = -dy; - z = -z; - } - r += dy * (GMHALF + 0.5) * r / y; - z = pow(y, 0.5 * z); - y = r * z * z; - return y; -} diff --git a/library/compiler-builtins/libm/src/math/tgammaf.rs b/library/compiler-builtins/libm/src/math/tgammaf.rs deleted file mode 100644 index fe178f7a3c0..00000000000 --- a/library/compiler-builtins/libm/src/math/tgammaf.rs +++ /dev/null @@ -1,7 +0,0 @@ -use super::tgamma; - -/// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tgammaf(x: f32) -> f32 { - tgamma(x as f64) as f32 -} diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs deleted file mode 100644 index fa50d55e136..00000000000 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ /dev/null @@ -1,53 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f16). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf16(x: f16) -> f16 { - super::generic::trunc(x) -} - -/// Rounds the number toward 0 to the closest integral value (f32). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf(x: f32) -> f32 { - select_implementation! { - name: truncf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::trunc(x) -} - -/// Rounds the number toward 0 to the closest integral value (f64). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn trunc(x: f64) -> f64 { - select_implementation! { - name: trunc, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::trunc(x) -} - -/// Rounds the number toward 0 to the closest integral value (f128). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf128(x: f128) -> f128 { - super::generic::trunc(x) -} - -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::truncf(1.1), 1.0); - } -} -- cgit 1.4.1-3-g733a5 From 3a0b9c9f51ebfae460d1014080dfe20388fa9d29 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 9 Apr 2025 01:21:44 +0000 Subject: refactor: Introduce a virtual manifest Move the workspace configuration to a virtual manifest. This reorganization makes a more clear separation between package contents and support files that don't get distributed. It will also make it easier to merge this repository with `compiler-builtins` which is planned (builtins had a similar update done in [1]). LICENSE.txt and README.md are symlinkedinto the new directory to ensure they get included in the package. [1]: https://github.com/rust-lang/compiler-builtins/pull/702 --- library/compiler-builtins/libm/Cargo.toml | 37 ++ library/compiler-builtins/libm/ci/ci-util.py | 2 +- .../libm/etc/function-definitions.json | 502 ++++++++++----------- .../compiler-builtins/libm/etc/update-api-list.py | 26 +- library/compiler-builtins/libm/libm/Cargo.toml | 38 -- library/compiler-builtins/libm/libm/LICENSE.txt | 1 + library/compiler-builtins/libm/libm/README.md | 1 + 7 files changed, 305 insertions(+), 302 deletions(-) create mode 100644 library/compiler-builtins/libm/Cargo.toml create mode 120000 library/compiler-builtins/libm/libm/LICENSE.txt create mode 120000 library/compiler-builtins/libm/libm/README.md diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml new file mode 100644 index 00000000000..268b6fb0e6d --- /dev/null +++ b/library/compiler-builtins/libm/Cargo.toml @@ -0,0 +1,37 @@ +[workspace] +resolver = "2" +members = [ + "libm", + "crates/libm-macros", + "crates/libm-test", + "crates/musl-math-sys", + "crates/util", +] +default-members = [ + "libm", + "crates/libm-macros", + "crates/libm-test" +] +exclude = [ + # Requires `panic = abort` so can't be a member of the workspace + "crates/compiler-builtins-smoke-test", +] + +# The default release profile is unchanged. + +# Release mode with debug assertions +[profile.release-checked] +inherits = "release" +debug-assertions = true +overflow-checks = true + +# Release with maximum optimizations, which is very slow to build. This is also +# what is needed to check `no-panic`. +[profile.release-opt] +inherits = "release" +codegen-units = 1 +lto = "fat" + +[profile.bench] +# Required for iai-callgrind +debug = true diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index ed63d6deea1..d9e402d6bd7 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -25,7 +25,7 @@ USAGE = cleandoc( COMMAND: generate-matrix Calculate a matrix of which functions had source change, print that as - a JSON object. + a JSON object. locate-baseline [--download] [--extract] Locate the most recent benchmark baseline available in CI and, if flags diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index ead1f807fc9..3e33343c464 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -2,1067 +2,1067 @@ "__comment": "Autogenerated by update-api-list.py. List of files that define a function with a given name. This file is checked in to make it obvious if refactoring breaks things", "acos": { "sources": [ - "src/math/acos.rs" + "libm/src/math/acos.rs" ], "type": "f64" }, "acosf": { "sources": [ - "src/math/acosf.rs" + "libm/src/math/acosf.rs" ], "type": "f32" }, "acosh": { "sources": [ - "src/math/acosh.rs" + "libm/src/math/acosh.rs" ], "type": "f64" }, "acoshf": { "sources": [ - "src/math/acoshf.rs" + "libm/src/math/acoshf.rs" ], "type": "f32" }, "asin": { "sources": [ - "src/math/asin.rs" + "libm/src/math/asin.rs" ], "type": "f64" }, "asinf": { "sources": [ - "src/math/asinf.rs" + "libm/src/math/asinf.rs" ], "type": "f32" }, "asinh": { "sources": [ - "src/math/asinh.rs" + "libm/src/math/asinh.rs" ], "type": "f64" }, "asinhf": { "sources": [ - "src/math/asinhf.rs" + "libm/src/math/asinhf.rs" ], "type": "f32" }, "atan": { "sources": [ - "src/math/atan.rs" + "libm/src/math/atan.rs" ], "type": "f64" }, "atan2": { "sources": [ - "src/math/atan2.rs" + "libm/src/math/atan2.rs" ], "type": "f64" }, "atan2f": { "sources": [ - "src/math/atan2f.rs" + "libm/src/math/atan2f.rs" ], "type": "f32" }, "atanf": { "sources": [ - "src/math/atanf.rs" + "libm/src/math/atanf.rs" ], "type": "f32" }, "atanh": { "sources": [ - "src/math/atanh.rs" + "libm/src/math/atanh.rs" ], "type": "f64" }, "atanhf": { "sources": [ - "src/math/atanhf.rs" + "libm/src/math/atanhf.rs" ], "type": "f32" }, "cbrt": { "sources": [ - "src/math/cbrt.rs" + "libm/src/math/cbrt.rs" ], "type": "f64" }, "cbrtf": { "sources": [ - "src/math/cbrtf.rs" + "libm/src/math/cbrtf.rs" ], "type": "f32" }, "ceil": { "sources": [ - "src/math/arch/i586.rs", - "src/math/arch/wasm32.rs", - "src/math/ceil.rs", - "src/math/generic/ceil.rs" + "libm/src/math/arch/i586.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/ceil.rs", + "libm/src/math/generic/ceil.rs" ], "type": "f64" }, "ceilf": { "sources": [ - "src/math/arch/wasm32.rs", - "src/math/ceil.rs", - "src/math/generic/ceil.rs" + "libm/src/math/arch/wasm32.rs", + "libm/src/math/ceil.rs", + "libm/src/math/generic/ceil.rs" ], "type": "f32" }, "ceilf128": { "sources": [ - "src/math/ceil.rs", - "src/math/generic/ceil.rs" + "libm/src/math/ceil.rs", + "libm/src/math/generic/ceil.rs" ], "type": "f128" }, "ceilf16": { "sources": [ - "src/math/ceil.rs", - "src/math/generic/ceil.rs" + "libm/src/math/ceil.rs", + "libm/src/math/generic/ceil.rs" ], "type": "f16" }, "copysign": { "sources": [ - "src/math/copysign.rs", - "src/math/generic/copysign.rs" + "libm/src/math/copysign.rs", + "libm/src/math/generic/copysign.rs" ], "type": "f64" }, "copysignf": { "sources": [ - "src/math/copysign.rs", - "src/math/generic/copysign.rs" + "libm/src/math/copysign.rs", + "libm/src/math/generic/copysign.rs" ], "type": "f32" }, "copysignf128": { "sources": [ - "src/math/copysign.rs", - "src/math/generic/copysign.rs" + "libm/src/math/copysign.rs", + "libm/src/math/generic/copysign.rs" ], "type": "f128" }, "copysignf16": { "sources": [ - "src/math/copysign.rs", - "src/math/generic/copysign.rs" + "libm/src/math/copysign.rs", + "libm/src/math/generic/copysign.rs" ], "type": "f16" }, "cos": { "sources": [ - "src/math/cos.rs" + "libm/src/math/cos.rs" ], "type": "f64" }, "cosf": { "sources": [ - "src/math/cosf.rs" + "libm/src/math/cosf.rs" ], "type": "f32" }, "cosh": { "sources": [ - "src/math/cosh.rs" + "libm/src/math/cosh.rs" ], "type": "f64" }, "coshf": { "sources": [ - "src/math/coshf.rs" + "libm/src/math/coshf.rs" ], "type": "f32" }, "erf": { "sources": [ - "src/math/erf.rs" + "libm/src/math/erf.rs" ], "type": "f64" }, "erfc": { "sources": [ - "src/math/erf.rs" + "libm/src/math/erf.rs" ], "type": "f64" }, "erfcf": { "sources": [ - "src/math/erff.rs" + "libm/src/math/erff.rs" ], "type": "f32" }, "erff": { "sources": [ - "src/math/erff.rs" + "libm/src/math/erff.rs" ], "type": "f32" }, "exp": { "sources": [ - "src/math/exp.rs" + "libm/src/math/exp.rs" ], "type": "f64" }, "exp10": { "sources": [ - "src/math/exp10.rs" + "libm/src/math/exp10.rs" ], "type": "f64" }, "exp10f": { "sources": [ - "src/math/exp10f.rs" + "libm/src/math/exp10f.rs" ], "type": "f32" }, "exp2": { "sources": [ - "src/math/exp2.rs" + "libm/src/math/exp2.rs" ], "type": "f64" }, "exp2f": { "sources": [ - "src/math/exp2f.rs" + "libm/src/math/exp2f.rs" ], "type": "f32" }, "expf": { "sources": [ - "src/math/expf.rs" + "libm/src/math/expf.rs" ], "type": "f32" }, "expm1": { "sources": [ - "src/math/expm1.rs" + "libm/src/math/expm1.rs" ], "type": "f64" }, "expm1f": { "sources": [ - "src/math/expm1f.rs" + "libm/src/math/expm1f.rs" ], "type": "f32" }, "fabs": { "sources": [ - "src/math/arch/wasm32.rs", - "src/math/fabs.rs", - "src/math/generic/fabs.rs" + "libm/src/math/arch/wasm32.rs", + "libm/src/math/fabs.rs", + "libm/src/math/generic/fabs.rs" ], "type": "f64" }, "fabsf": { "sources": [ - "src/math/arch/wasm32.rs", - "src/math/fabs.rs", - "src/math/generic/fabs.rs" + "libm/src/math/arch/wasm32.rs", + "libm/src/math/fabs.rs", + "libm/src/math/generic/fabs.rs" ], "type": "f32" }, "fabsf128": { "sources": [ - "src/math/fabs.rs", - "src/math/generic/fabs.rs" + "libm/src/math/fabs.rs", + "libm/src/math/generic/fabs.rs" ], "type": "f128" }, "fabsf16": { "sources": [ - "src/math/fabs.rs", - "src/math/generic/fabs.rs" + "libm/src/math/fabs.rs", + "libm/src/math/generic/fabs.rs" ], "type": "f16" }, "fdim": { "sources": [ - "src/math/fdim.rs", - "src/math/generic/fdim.rs" + "libm/src/math/fdim.rs", + "libm/src/math/generic/fdim.rs" ], "type": "f64" }, "fdimf": { "sources": [ - "src/math/fdim.rs", - "src/math/generic/fdim.rs" + "libm/src/math/fdim.rs", + "libm/src/math/generic/fdim.rs" ], "type": "f32" }, "fdimf128": { "sources": [ - "src/math/fdim.rs", - "src/math/generic/fdim.rs" + "libm/src/math/fdim.rs", + "libm/src/math/generic/fdim.rs" ], "type": "f128" }, "fdimf16": { "sources": [ - "src/math/fdim.rs", - "src/math/generic/fdim.rs" + "libm/src/math/fdim.rs", + "libm/src/math/generic/fdim.rs" ], "type": "f16" }, "floor": { "sources": [ - "src/math/arch/i586.rs", - "src/math/arch/wasm32.rs", - "src/math/floor.rs", - "src/math/generic/floor.rs" + "libm/src/math/arch/i586.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/floor.rs", + "libm/src/math/generic/floor.rs" ], "type": "f64" }, "floorf": { "sources": [ - "src/math/arch/wasm32.rs", - "src/math/floor.rs", - "src/math/generic/floor.rs" + "libm/src/math/arch/wasm32.rs", + "libm/src/math/floor.rs", + "libm/src/math/generic/floor.rs" ], "type": "f32" }, "floorf128": { "sources": [ - "src/math/floor.rs", - "src/math/generic/floor.rs" + "libm/src/math/floor.rs", + "libm/src/math/generic/floor.rs" ], "type": "f128" }, "floorf16": { "sources": [ - "src/math/floor.rs", - "src/math/generic/floor.rs" + "libm/src/math/floor.rs", + "libm/src/math/generic/floor.rs" ], "type": "f16" }, "fma": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/fma.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/fma.rs" ], "type": "f64" }, "fmaf": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/fma_wide.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/fma_wide.rs" ], "type": "f32" }, "fmaf128": { "sources": [ - "src/math/fma.rs" + "libm/src/math/fma.rs" ], "type": "f128" }, "fmax": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmax.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmax.rs" ], "type": "f64" }, "fmaxf": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmax.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmax.rs" ], "type": "f32" }, "fmaxf128": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmax.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmax.rs" ], "type": "f128" }, "fmaxf16": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmax.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmax.rs" ], "type": "f16" }, "fmaximum": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fmaximum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fmaximum.rs" ], "type": "f64" }, "fmaximum_num": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fmaximum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fmaximum_num.rs" ], "type": "f64" }, "fmaximum_numf": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fmaximum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fmaximum_num.rs" ], "type": "f32" }, "fmaximum_numf128": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fmaximum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fmaximum_num.rs" ], "type": "f128" }, "fmaximum_numf16": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fmaximum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fmaximum_num.rs" ], "type": "f16" }, "fmaximumf": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fmaximum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fmaximum.rs" ], "type": "f32" }, "fmaximumf128": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fmaximum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fmaximum.rs" ], "type": "f128" }, "fmaximumf16": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fmaximum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fmaximum.rs" ], "type": "f16" }, "fmin": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmin.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmin.rs" ], "type": "f64" }, "fminf": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmin.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmin.rs" ], "type": "f32" }, "fminf128": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmin.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmin.rs" ], "type": "f128" }, "fminf16": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmin.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmin.rs" ], "type": "f16" }, "fminimum": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fminimum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fminimum.rs" ], "type": "f64" }, "fminimum_num": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fminimum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fminimum_num.rs" ], "type": "f64" }, "fminimum_numf": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fminimum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fminimum_num.rs" ], "type": "f32" }, "fminimum_numf128": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fminimum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fminimum_num.rs" ], "type": "f128" }, "fminimum_numf16": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fminimum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fminimum_num.rs" ], "type": "f16" }, "fminimumf": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fminimum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fminimum.rs" ], "type": "f32" }, "fminimumf128": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fminimum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fminimum.rs" ], "type": "f128" }, "fminimumf16": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fminimum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fminimum.rs" ], "type": "f16" }, "fmod": { "sources": [ - "src/math/fmod.rs", - "src/math/generic/fmod.rs" + "libm/src/math/fmod.rs", + "libm/src/math/generic/fmod.rs" ], "type": "f64" }, "fmodf": { "sources": [ - "src/math/fmod.rs", - "src/math/generic/fmod.rs" + "libm/src/math/fmod.rs", + "libm/src/math/generic/fmod.rs" ], "type": "f32" }, "fmodf128": { "sources": [ - "src/math/fmod.rs", - "src/math/generic/fmod.rs" + "libm/src/math/fmod.rs", + "libm/src/math/generic/fmod.rs" ], "type": "f128" }, "fmodf16": { "sources": [ - "src/math/fmod.rs", - "src/math/generic/fmod.rs" + "libm/src/math/fmod.rs", + "libm/src/math/generic/fmod.rs" ], "type": "f16" }, "frexp": { "sources": [ - "src/math/frexp.rs" + "libm/src/math/frexp.rs" ], "type": "f64" }, "frexpf": { "sources": [ - "src/math/frexpf.rs" + "libm/src/math/frexpf.rs" ], "type": "f32" }, "hypot": { "sources": [ - "src/math/hypot.rs" + "libm/src/math/hypot.rs" ], "type": "f64" }, "hypotf": { "sources": [ - "src/math/hypotf.rs" + "libm/src/math/hypotf.rs" ], "type": "f32" }, "ilogb": { "sources": [ - "src/math/ilogb.rs" + "libm/src/math/ilogb.rs" ], "type": "f64" }, "ilogbf": { "sources": [ - "src/math/ilogbf.rs" + "libm/src/math/ilogbf.rs" ], "type": "f32" }, "j0": { "sources": [ - "src/math/j0.rs" + "libm/src/math/j0.rs" ], "type": "f64" }, "j0f": { "sources": [ - "src/math/j0f.rs" + "libm/src/math/j0f.rs" ], "type": "f32" }, "j1": { "sources": [ - "src/math/j1.rs" + "libm/src/math/j1.rs" ], "type": "f64" }, "j1f": { "sources": [ - "src/math/j1f.rs" + "libm/src/math/j1f.rs" ], "type": "f32" }, "jn": { "sources": [ - "src/math/jn.rs" + "libm/src/math/jn.rs" ], "type": "f64" }, "jnf": { "sources": [ - "src/math/jnf.rs" + "libm/src/math/jnf.rs" ], "type": "f32" }, "ldexp": { "sources": [ - "src/math/ldexp.rs" + "libm/src/math/ldexp.rs" ], "type": "f64" }, "ldexpf": { "sources": [ - "src/math/ldexp.rs" + "libm/src/math/ldexp.rs" ], "type": "f32" }, "ldexpf128": { "sources": [ - "src/math/ldexp.rs" + "libm/src/math/ldexp.rs" ], "type": "f128" }, "ldexpf16": { "sources": [ - "src/math/ldexp.rs" + "libm/src/math/ldexp.rs" ], "type": "f16" }, "lgamma": { "sources": [ - "src/math/lgamma.rs" + "libm/src/math/lgamma.rs" ], "type": "f64" }, "lgamma_r": { "sources": [ - "src/math/lgamma_r.rs" + "libm/src/math/lgamma_r.rs" ], "type": "f64" }, "lgammaf": { "sources": [ - "src/math/lgammaf.rs" + "libm/src/math/lgammaf.rs" ], "type": "f32" }, "lgammaf_r": { "sources": [ - "src/math/lgammaf_r.rs" + "libm/src/math/lgammaf_r.rs" ], "type": "f32" }, "log": { "sources": [ - "src/math/log.rs" + "libm/src/math/log.rs" ], "type": "f64" }, "log10": { "sources": [ - "src/math/log10.rs" + "libm/src/math/log10.rs" ], "type": "f64" }, "log10f": { "sources": [ - "src/math/log10f.rs" + "libm/src/math/log10f.rs" ], "type": "f32" }, "log1p": { "sources": [ - "src/math/log1p.rs" + "libm/src/math/log1p.rs" ], "type": "f64" }, "log1pf": { "sources": [ - "src/math/log1pf.rs" + "libm/src/math/log1pf.rs" ], "type": "f32" }, "log2": { "sources": [ - "src/math/log2.rs" + "libm/src/math/log2.rs" ], "type": "f64" }, "log2f": { "sources": [ - "src/math/log2f.rs" + "libm/src/math/log2f.rs" ], "type": "f32" }, "logf": { "sources": [ - "src/math/logf.rs" + "libm/src/math/logf.rs" ], "type": "f32" }, "modf": { "sources": [ - "src/math/modf.rs" + "libm/src/math/modf.rs" ], "type": "f64" }, "modff": { "sources": [ - "src/math/modff.rs" + "libm/src/math/modff.rs" ], "type": "f32" }, "nextafter": { "sources": [ - "src/math/nextafter.rs" + "libm/src/math/nextafter.rs" ], "type": "f64" }, "nextafterf": { "sources": [ - "src/math/nextafterf.rs" + "libm/src/math/nextafterf.rs" ], "type": "f32" }, "pow": { "sources": [ - "src/math/pow.rs" + "libm/src/math/pow.rs" ], "type": "f64" }, "powf": { "sources": [ - "src/math/powf.rs" + "libm/src/math/powf.rs" ], "type": "f32" }, "remainder": { "sources": [ - "src/math/remainder.rs" + "libm/src/math/remainder.rs" ], "type": "f64" }, "remainderf": { "sources": [ - "src/math/remainderf.rs" + "libm/src/math/remainderf.rs" ], "type": "f32" }, "remquo": { "sources": [ - "src/math/remquo.rs" + "libm/src/math/remquo.rs" ], "type": "f64" }, "remquof": { "sources": [ - "src/math/remquof.rs" + "libm/src/math/remquof.rs" ], "type": "f32" }, "rint": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/arch/wasm32.rs", - "src/math/rint.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/rint.rs" ], "type": "f64" }, "rintf": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/arch/wasm32.rs", - "src/math/rint.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/rint.rs" ], "type": "f32" }, "rintf128": { "sources": [ - "src/math/rint.rs" + "libm/src/math/rint.rs" ], "type": "f128" }, "rintf16": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/rint.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/rint.rs" ], "type": "f16" }, "round": { "sources": [ - "src/math/generic/round.rs", - "src/math/round.rs" + "libm/src/math/generic/round.rs", + "libm/src/math/round.rs" ], "type": "f64" }, "roundeven": { "sources": [ - "src/math/roundeven.rs" + "libm/src/math/roundeven.rs" ], "type": "f64" }, "roundevenf": { "sources": [ - "src/math/roundeven.rs" + "libm/src/math/roundeven.rs" ], "type": "f32" }, "roundevenf128": { "sources": [ - "src/math/roundeven.rs" + "libm/src/math/roundeven.rs" ], "type": "f128" }, "roundevenf16": { "sources": [ - "src/math/roundeven.rs" + "libm/src/math/roundeven.rs" ], "type": "f16" }, "roundf": { "sources": [ - "src/math/generic/round.rs", - "src/math/round.rs" + "libm/src/math/generic/round.rs", + "libm/src/math/round.rs" ], "type": "f32" }, "roundf128": { "sources": [ - "src/math/generic/round.rs", - "src/math/round.rs" + "libm/src/math/generic/round.rs", + "libm/src/math/round.rs" ], "type": "f128" }, "roundf16": { "sources": [ - "src/math/generic/round.rs", - "src/math/round.rs" + "libm/src/math/generic/round.rs", + "libm/src/math/round.rs" ], "type": "f16" }, "scalbn": { "sources": [ - "src/math/generic/scalbn.rs", - "src/math/scalbn.rs" + "libm/src/math/generic/scalbn.rs", + "libm/src/math/scalbn.rs" ], "type": "f64" }, "scalbnf": { "sources": [ - "src/math/generic/scalbn.rs", - "src/math/scalbn.rs" + "libm/src/math/generic/scalbn.rs", + "libm/src/math/scalbn.rs" ], "type": "f32" }, "scalbnf128": { "sources": [ - "src/math/generic/scalbn.rs", - "src/math/scalbn.rs" + "libm/src/math/generic/scalbn.rs", + "libm/src/math/scalbn.rs" ], "type": "f128" }, "scalbnf16": { "sources": [ - "src/math/generic/scalbn.rs", - "src/math/scalbn.rs" + "libm/src/math/generic/scalbn.rs", + "libm/src/math/scalbn.rs" ], "type": "f16" }, "sin": { "sources": [ - "src/math/sin.rs" + "libm/src/math/sin.rs" ], "type": "f64" }, "sincos": { "sources": [ - "src/math/sincos.rs" + "libm/src/math/sincos.rs" ], "type": "f64" }, "sincosf": { "sources": [ - "src/math/sincosf.rs" + "libm/src/math/sincosf.rs" ], "type": "f32" }, "sinf": { "sources": [ - "src/math/sinf.rs" + "libm/src/math/sinf.rs" ], "type": "f32" }, "sinh": { "sources": [ - "src/math/sinh.rs" + "libm/src/math/sinh.rs" ], "type": "f64" }, "sinhf": { "sources": [ - "src/math/sinhf.rs" + "libm/src/math/sinhf.rs" ], "type": "f32" }, "sqrt": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/arch/i686.rs", - "src/math/arch/wasm32.rs", - "src/math/generic/sqrt.rs", - "src/math/sqrt.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/i686.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/generic/sqrt.rs", + "libm/src/math/sqrt.rs" ], "type": "f64" }, "sqrtf": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/arch/i686.rs", - "src/math/arch/wasm32.rs", - "src/math/generic/sqrt.rs", - "src/math/sqrt.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/i686.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/generic/sqrt.rs", + "libm/src/math/sqrt.rs" ], "type": "f32" }, "sqrtf128": { "sources": [ - "src/math/generic/sqrt.rs", - "src/math/sqrt.rs" + "libm/src/math/generic/sqrt.rs", + "libm/src/math/sqrt.rs" ], "type": "f128" }, "sqrtf16": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/generic/sqrt.rs", - "src/math/sqrt.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/generic/sqrt.rs", + "libm/src/math/sqrt.rs" ], "type": "f16" }, "tan": { "sources": [ - "src/math/tan.rs" + "libm/src/math/tan.rs" ], "type": "f64" }, "tanf": { "sources": [ - "src/math/tanf.rs" + "libm/src/math/tanf.rs" ], "type": "f32" }, "tanh": { "sources": [ - "src/math/tanh.rs" + "libm/src/math/tanh.rs" ], "type": "f64" }, "tanhf": { "sources": [ - "src/math/tanhf.rs" + "libm/src/math/tanhf.rs" ], "type": "f32" }, "tgamma": { "sources": [ - "src/math/tgamma.rs" + "libm/src/math/tgamma.rs" ], "type": "f64" }, "tgammaf": { "sources": [ - "src/math/tgammaf.rs" + "libm/src/math/tgammaf.rs" ], "type": "f32" }, "trunc": { "sources": [ - "src/math/arch/wasm32.rs", - "src/math/generic/trunc.rs", - "src/math/trunc.rs" + "libm/src/math/arch/wasm32.rs", + "libm/src/math/generic/trunc.rs", + "libm/src/math/trunc.rs" ], "type": "f64" }, "truncf": { "sources": [ - "src/math/arch/wasm32.rs", - "src/math/generic/trunc.rs", - "src/math/trunc.rs" + "libm/src/math/arch/wasm32.rs", + "libm/src/math/generic/trunc.rs", + "libm/src/math/trunc.rs" ], "type": "f32" }, "truncf128": { "sources": [ - "src/math/generic/trunc.rs", - "src/math/trunc.rs" + "libm/src/math/generic/trunc.rs", + "libm/src/math/trunc.rs" ], "type": "f128" }, "truncf16": { "sources": [ - "src/math/generic/trunc.rs", - "src/math/trunc.rs" + "libm/src/math/generic/trunc.rs", + "libm/src/math/trunc.rs" ], "type": "f16" }, "y0": { "sources": [ - "src/math/j0.rs" + "libm/src/math/j0.rs" ], "type": "f64" }, "y0f": { "sources": [ - "src/math/j0f.rs" + "libm/src/math/j0f.rs" ], "type": "f32" }, "y1": { "sources": [ - "src/math/j1.rs" + "libm/src/math/j1.rs" ], "type": "f64" }, "y1f": { "sources": [ - "src/math/j1f.rs" + "libm/src/math/j1f.rs" ], "type": "f32" }, "yn": { "sources": [ - "src/math/jn.rs" + "libm/src/math/jn.rs" ], "type": "f64" }, "ynf": { "sources": [ - "src/math/jnf.rs" + "libm/src/math/jnf.rs" ], "type": "f32" } diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index 950824fc442..0770a8b20fb 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -18,10 +18,10 @@ from typing import Any, Callable, TypeAlias SELF_PATH = Path(__file__) ETC_DIR = SELF_PATH.parent -LIBM_DIR = ETC_DIR.parent.joinpath("libm") +ROOT_DIR = ETC_DIR.parent # These files do not trigger a retest. -IGNORED_SOURCES = ["src/libm_helper.rs", "src/math/support/float_traits.rs"] +IGNORED_SOURCES = ["libm/src/libm_helper.rs", "libm/src/math/support/float_traits.rs"] IndexTy: TypeAlias = dict[str, dict[str, Any]] """Type of the `index` item in rustdoc's JSON output""" @@ -66,7 +66,7 @@ class Crate: j = sp.check_output( [ "rustdoc", - "src/lib.rs", + "libm/src/lib.rs", "--edition=2021", "--document-private-items", "--output-format=json", @@ -75,7 +75,7 @@ class Crate: "-Zunstable-options", "-o-", ], - cwd=LIBM_DIR, + cwd=ROOT_DIR, text=True, ) j = json.loads(j) @@ -94,7 +94,9 @@ class Crate: # Collect a list of source IDs for reexported items in `lib.rs` or `mod math`. use = (i for i in public if "use" in i["inner"]) use = ( - i for i in use if i["span"]["filename"] in ["src/math/mod.rs", "src/lib.rs"] + i + for i in use + if i["span"]["filename"] in ["libm/src/math/mod.rs", "libm/src/lib.rs"] ) reexported_ids = [item["inner"]["use"]["id"] for item in use] @@ -121,8 +123,8 @@ class Crate: # A lot of the `arch` module is often configured out so doesn't show up in docs. Use # string matching as a fallback. - for fname in glob("src/math/arch/**.rs", root_dir=LIBM_DIR): - contents = (LIBM_DIR.joinpath(fname)).read_text() + for fname in glob("libm/src/math/arch/**.rs", root_dir=ROOT_DIR): + contents = (ROOT_DIR.joinpath(fname)).read_text() for name in self.public_functions: if f"fn {name}" in contents: @@ -188,10 +190,10 @@ class Crate: include all public API. """ - flist = sp.check_output(["git", "ls-files"], cwd=LIBM_DIR, text=True) + flist = sp.check_output(["git", "ls-files"], cwd=ROOT_DIR, text=True) for path in flist.splitlines(): - fpath = LIBM_DIR.joinpath(path) + fpath = ROOT_DIR.joinpath(path) if fpath.is_dir() or fpath == SELF_PATH: continue @@ -229,7 +231,7 @@ class Crate: if len(not_found) == 0: return - relpath = fpath.relative_to(LIBM_DIR) + relpath = fpath.relative_to(ROOT_DIR) eprint(f"functions not found at {relpath}:{line_num}: {not_found}") exit(1) @@ -244,7 +246,7 @@ def validate_delimited_block( """Identify blocks of code wrapped within `start` and `end`, collect their contents to a list of strings, and call `validate` for each of those lists. """ - relpath = fpath.relative_to(LIBM_DIR) + relpath = fpath.relative_to(ROOT_DIR) block_lines = [] block_start_line: None | int = None for line_num, line in enumerate(lines): @@ -274,7 +276,7 @@ def validate_delimited_block( def ensure_sorted(fpath: Path, block_start_line: int, lines: list[str]) -> None: """Ensure that a list of lines is sorted, otherwise print a diff and exit.""" - relpath = fpath.relative_to(LIBM_DIR) + relpath = fpath.relative_to(ROOT_DIR) diff_and_exit( "\n".join(lines), "\n".join(sorted(lines)), diff --git a/library/compiler-builtins/libm/libm/Cargo.toml b/library/compiler-builtins/libm/libm/Cargo.toml index e0aeb07d527..44154c1a8f5 100644 --- a/library/compiler-builtins/libm/libm/Cargo.toml +++ b/library/compiler-builtins/libm/libm/Cargo.toml @@ -10,7 +10,6 @@ readme = "README.md" repository = "https://github.com/rust-lang/libm" version = "0.2.11" edition = "2021" -exclude = ["/ci/", "/.github/workflows/"] rust-version = "1.63" [features] @@ -40,24 +39,6 @@ unstable-float = [] # hard float operations. force-soft-floats = [] -[workspace] -resolver = "2" -members = [ - "crates/libm-macros", - "crates/libm-test", - "crates/musl-math-sys", - "crates/util", -] -default-members = [ - ".", - "crates/libm-macros", - "crates/libm-test", -] -exclude = [ - # Requires `panic = abort` so can't be a member of the workspace - "crates/compiler-builtins-smoke-test", -] - [dev-dependencies] no-panic = "0.1.35" @@ -66,22 +47,3 @@ unexpected_cfgs = { level = "warn", check-cfg = [ # compiler-builtins sets this feature, but we use it in `libm` 'cfg(feature, values("compiler-builtins"))', ] } - -# The default release profile is unchanged. - -# Release mode with debug assertions -[profile.release-checked] -inherits = "release" -debug-assertions = true -overflow-checks = true - -# Release with maximum optimizations, which is very slow to build. This is also -# what is needed to check `no-panic`. -[profile.release-opt] -inherits = "release" -codegen-units = 1 -lto = "fat" - -[profile.bench] -# Required for iai-callgrind -debug = true diff --git a/library/compiler-builtins/libm/libm/LICENSE.txt b/library/compiler-builtins/libm/libm/LICENSE.txt new file mode 120000 index 00000000000..4ab43736a83 --- /dev/null +++ b/library/compiler-builtins/libm/libm/LICENSE.txt @@ -0,0 +1 @@ +../LICENSE.txt \ No newline at end of file diff --git a/library/compiler-builtins/libm/libm/README.md b/library/compiler-builtins/libm/libm/README.md new file mode 120000 index 00000000000..32d46ee883b --- /dev/null +++ b/library/compiler-builtins/libm/libm/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file -- cgit 1.4.1-3-g733a5 From cd7c76aab3079191da631f80e58835c1356fe0d6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Mar 2025 00:11:39 +0000 Subject: Migrate all crates except `libm` to edition 2024 Unfortunately this means we lose use of the convenient name `gen`, so this includes a handful of renaming. We can't increase the edition for `libm` yet due to MSRV, but we can enable `unsafe_op_in_unsafe_fn` to help make that change smoother in the future. --- .../libm/.github/workflows/main.yaml | 13 +- .../compiler-builtins-smoke-test/src/math.rs | 8 +- .../libm/crates/libm-macros/Cargo.toml | 2 +- .../libm/crates/libm-test/Cargo.toml | 2 +- .../libm/crates/libm-test/benches/icount.rs | 2 +- .../libm/crates/libm-test/benches/random.rs | 4 +- .../libm/crates/libm-test/examples/plot_domains.rs | 8 +- .../libm/crates/libm-test/src/gen.rs | 43 -- .../libm/crates/libm-test/src/gen/case_list.rs | 853 --------------------- .../libm/crates/libm-test/src/gen/edge_cases.rs | 310 -------- .../libm/crates/libm-test/src/gen/random.rs | 125 --- .../libm/crates/libm-test/src/gen/spaced.rs | 253 ------ .../libm/crates/libm-test/src/generate.rs | 43 ++ .../crates/libm-test/src/generate/case_list.rs | 853 +++++++++++++++++++++ .../crates/libm-test/src/generate/edge_cases.rs | 310 ++++++++ .../libm/crates/libm-test/src/generate/random.rs | 125 +++ .../libm/crates/libm-test/src/generate/spaced.rs | 253 ++++++ .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/run_cfg.rs | 4 +- .../crates/libm-test/tests/compare_built_musl.rs | 2 +- .../libm/crates/libm-test/tests/multiprecision.rs | 2 +- .../libm/crates/libm-test/tests/standalone.rs | 2 +- .../libm/crates/libm-test/tests/u256.rs | 2 +- .../libm/crates/libm-test/tests/z_extensive/run.rs | 2 +- .../libm/crates/musl-math-sys/Cargo.toml | 2 +- .../libm/crates/musl-math-sys/src/lib.rs | 2 +- .../compiler-builtins/libm/crates/util/Cargo.toml | 2 +- library/compiler-builtins/libm/libm/src/lib.rs | 1 + 28 files changed, 1617 insertions(+), 1613 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/spaced.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/generate.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/generate/case_list.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/generate/edge_cases.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/generate/random.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/generate/spaced.rs diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index a717c3ea8f8..5ce0dbc26c8 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -212,14 +212,17 @@ jobs: RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` steps: - uses: actions/checkout@master - - run: | + - name: Install Rust + run: | msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' libm/Cargo.toml)" echo "MSRV: $msrv" - echo "MSRV=$msrv" >> "$GITHUB_ENV" - - name: Install Rust - run: rustup update "$MSRV" --no-self-update && rustup default "$MSRV" + rustup update "$msrv" --no-self-update && rustup default "$msrv" - uses: Swatinem/rust-cache@v2 - - run: cargo build -p libm + - run: | + # FIXME(msrv): Remove the workspace Cargo.toml so 1.63 cargo doesn't see + # `edition = "2024"` and get spooked. + rm Cargo.toml + cargo build --manifest-path libm/Cargo.toml rustfmt: name: Rustfmt diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs index f17fc123168..58a5bfbb90f 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs @@ -14,7 +14,7 @@ macro_rules! no_mangle { // Handle simple functions with single return types (@inner $name:ident( $($arg:ident: $aty:ty),+ ) -> $ret:ty) => { - #[no_mangle] + #[unsafe(no_mangle)] extern "C" fn $name($($arg: $aty),+) -> $ret { libm::$name($($arg),+) } @@ -26,7 +26,7 @@ macro_rules! no_mangle { ( @inner $name:ident( $($arg:ident: $aty:ty),+ | $($rarg:ident: $rty:ty),+) -> $ret:ty ) => { - #[no_mangle] + #[unsafe(no_mangle)] extern "C" fn $name($($arg: $aty,)+ $($rarg: $rty),+) -> $ret { let ret; (ret, $(*$rarg),+) = libm::$name($($arg),+); @@ -166,12 +166,12 @@ no_mangle! { /* sincos has no direct return type, not worth handling in the macro */ -#[no_mangle] +#[unsafe(no_mangle)] extern "C" fn sincos(x: f64, s: &mut f64, c: &mut f64) { (*s, *c) = libm::sincos(x); } -#[no_mangle] +#[unsafe(no_mangle)] extern "C" fn sincosf(x: f32, s: &mut f32, c: &mut f32) { (*s, *c) = libm::sincosf(x); } diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml index 314f4ae3783..50c869db7ff 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "libm-macros" version = "0.1.0" -edition = "2021" +edition = "2024" publish = false [lib] diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 1bcc163ed1b..5d150b4aeaa 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "libm-test" version = "0.1.0" -edition = "2021" +edition = "2024" publish = false [features] diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 4a10ec383ae..da8c6bfd15a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -4,7 +4,7 @@ use std::hint::black_box; use iai_callgrind::{library_benchmark, library_benchmark_group, main}; use libm::support::{HInt, u256}; -use libm_test::gen::spaced; +use libm_test::generate::spaced; use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, OpRustArgs, TupleCall, op}; const BENCH_ITER_ITEMS: u64 = 500; diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 17e4e0d55fc..63d7e5c6d20 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -2,8 +2,8 @@ use std::hint::black_box; use std::time::Duration; use criterion::{Criterion, criterion_main}; -use libm_test::gen::random; -use libm_test::gen::random::RandomInput; +use libm_test::generate::random; +use libm_test::generate::random::RandomInput; use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, TupleCall}; /// Benchmark with this many items to get a variety diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs index 441889c6941..78524761e2c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs +++ b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs @@ -12,8 +12,8 @@ use std::path::Path; use std::process::Command; use std::{env, fs}; -use libm_test::gen::spaced::SpacedInput; -use libm_test::gen::{edge_cases, spaced}; +use libm_test::generate::spaced::SpacedInput; +use libm_test::generate::{edge_cases, spaced}; use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; const JL_PLOT: &str = "examples/plot_file.jl"; @@ -73,7 +73,7 @@ fn plot_one_generator( ctx: &CheckCtx, gen_name: &str, config: &mut String, - gen: impl Iterator, + generator: impl Iterator, ) { let fn_name = ctx.base_name_str; let text_file = out_dir.join(format!("input-{fn_name}-{gen_name}.txt")); @@ -82,7 +82,7 @@ fn plot_one_generator( let mut w = BufWriter::new(f); let mut count = 0u64; - for input in gen { + for input in generator { writeln!(w, "{:e}", input.0).unwrap(); count += 1; } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs deleted file mode 100644 index 89ca09a7a0b..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Different generators that can create random or systematic bit patterns. - -pub mod case_list; -pub mod edge_cases; -pub mod random; -pub mod spaced; - -/// A wrapper to turn any iterator into an `ExactSizeIterator`. Asserts the final result to ensure -/// the provided size was correct. -#[derive(Debug)] -pub struct KnownSize { - total: u64, - current: u64, - iter: I, -} - -impl KnownSize { - pub fn new(iter: I, total: u64) -> Self { - Self { total, current: 0, iter } - } -} - -impl Iterator for KnownSize { - type Item = I::Item; - - fn next(&mut self) -> Option { - let next = self.iter.next(); - if next.is_some() { - self.current += 1; - return next; - } - - assert_eq!(self.current, self.total, "total items did not match expected"); - None - } - - fn size_hint(&self) -> (usize, Option) { - let remaining = usize::try_from(self.total - self.current).unwrap(); - (remaining, Some(remaining)) - } -} - -impl ExactSizeIterator for KnownSize {} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs deleted file mode 100644 index e3628d51c9a..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs +++ /dev/null @@ -1,853 +0,0 @@ -//! Test cases to verify specific values. -//! -//! Each routine can have a set of inputs and, optinoally, outputs. If an output is provided, it -//! will be used to check against. If only inputs are provided, the case will be checked against -//! a basis. -//! -//! This is useful for adding regression tests or expected failures. - -use libm::hf64; -#[cfg(f128_enabled)] -use libm::hf128; - -use crate::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; - -pub struct TestCase { - pub input: Op::RustArgs, - pub output: Option, -} - -impl TestCase { - #[expect(dead_code)] - fn append_inputs(v: &mut Vec, l: &[Op::RustArgs]) { - v.extend(l.iter().copied().map(|input| Self { input, output: None })); - } - - fn append_pairs(v: &mut Vec, l: &[(Op::RustArgs, Option)]) - where - Op::RustRet: Copy, - { - v.extend(l.iter().copied().map(|(input, output)| Self { input, output })); - } -} - -fn acos_cases() -> Vec> { - vec![] -} - -fn acosf_cases() -> Vec> { - vec![] -} - -fn acosh_cases() -> Vec> { - vec![] -} - -fn acoshf_cases() -> Vec> { - vec![] -} - -fn asin_cases() -> Vec> { - vec![] -} - -fn asinf_cases() -> Vec> { - vec![] -} - -fn asinh_cases() -> Vec> { - vec![] -} - -fn asinhf_cases() -> Vec> { - vec![] -} - -fn atan_cases() -> Vec> { - vec![] -} - -fn atan2_cases() -> Vec> { - vec![] -} - -fn atan2f_cases() -> Vec> { - vec![] -} - -fn atanf_cases() -> Vec> { - vec![] -} - -fn atanh_cases() -> Vec> { - vec![] -} - -fn atanhf_cases() -> Vec> { - vec![] -} - -fn cbrt_cases() -> Vec> { - vec![] -} - -fn cbrtf_cases() -> Vec> { - vec![] -} - -fn ceil_cases() -> Vec> { - vec![] -} - -fn ceilf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn ceilf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn ceilf16_cases() -> Vec> { - vec![] -} - -fn copysign_cases() -> Vec> { - vec![] -} - -fn copysignf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn copysignf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn copysignf16_cases() -> Vec> { - vec![] -} - -fn cos_cases() -> Vec> { - vec![] -} - -fn cosf_cases() -> Vec> { - vec![] -} - -fn cosh_cases() -> Vec> { - vec![] -} - -fn coshf_cases() -> Vec> { - vec![] -} - -fn erf_cases() -> Vec> { - vec![] -} - -fn erfc_cases() -> Vec> { - vec![] -} - -fn erfcf_cases() -> Vec> { - vec![] -} - -fn erff_cases() -> Vec> { - vec![] -} - -fn exp_cases() -> Vec> { - vec![] -} - -fn exp10_cases() -> Vec> { - vec![] -} - -fn exp10f_cases() -> Vec> { - vec![] -} - -fn exp2_cases() -> Vec> { - vec![] -} - -fn exp2f_cases() -> Vec> { - vec![] -} - -fn expf_cases() -> Vec> { - vec![] -} - -fn expm1_cases() -> Vec> { - vec![] -} - -fn expm1f_cases() -> Vec> { - vec![] -} - -fn fabs_cases() -> Vec> { - vec![] -} - -fn fabsf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fabsf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fabsf16_cases() -> Vec> { - vec![] -} - -fn fdim_cases() -> Vec> { - vec![] -} - -fn fdimf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fdimf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fdimf16_cases() -> Vec> { - vec![] -} - -fn floor_cases() -> Vec> { - vec![] -} - -fn floorf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn floorf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn floorf16_cases() -> Vec> { - vec![] -} - -fn fma_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Previous failure with incorrect sign - ((5e-324, -5e-324, 0.0), Some(-0.0)), - ], - ); - v -} - -fn fmaf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fmaf128_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - ( - // Tricky rounding case that previously failed in extensive tests - ( - hf128!("-0x1.1966cc01966cc01966cc01966f06p-25"), - hf128!("-0x1.669933fe69933fe69933fe6997c9p-16358"), - hf128!("-0x0.000000000000000000000000048ap-16382"), - ), - Some(hf128!("0x0.c5171470a3ff5e0f68d751491b18p-16382")), - ), - ( - // Subnormal edge case that caused a failure - ( - hf128!("0x0.7ffffffffffffffffffffffffff7p-16382"), - hf128!("0x1.ffffffffffffffffffffffffffffp-1"), - hf128!("0x0.8000000000000000000000000009p-16382"), - ), - Some(hf128!("0x1.0000000000000000000000000000p-16382")), - ), - ], - ); - v -} - -#[cfg(f16_enabled)] -fn fmaxf16_cases() -> Vec> { - vec![] -} - -fn fmaxf_cases() -> Vec> { - vec![] -} - -fn fmax_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fmaxf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fmaximumf16_cases() -> Vec> { - vec![] -} - -fn fmaximumf_cases() -> Vec> { - vec![] -} - -fn fmaximum_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fmaximumf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fmaximum_numf16_cases() -> Vec> { - vec![] -} - -fn fmaximum_numf_cases() -> Vec> { - vec![] -} - -fn fmaximum_num_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fmaximum_numf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fminf16_cases() -> Vec> { - vec![] -} - -fn fminf_cases() -> Vec> { - vec![] -} - -fn fmin_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fminf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fminimumf16_cases() -> Vec> { - vec![] -} - -fn fminimumf_cases() -> Vec> { - vec![] -} - -fn fminimum_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fminimumf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fminimum_numf16_cases() -> Vec> { - vec![] -} - -fn fminimum_numf_cases() -> Vec> { - vec![] -} - -fn fminimum_num_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fminimum_numf128_cases() -> Vec> { - vec![] -} - -fn fmod_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Previous failure with incorrect loop iteration - // - ((2.1, 3.123e-320), Some(2.0696e-320)), - ((2.1, 2.253547e-318), Some(1.772535e-318)), - ], - ); - v -} - -fn fmodf_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Previous failure with incorrect loop iteration - // - ((2.1, 8.858e-42), Some(8.085e-42)), - ((2.1, 6.39164e-40), Some(6.1636e-40)), - ((5.5, 6.39164e-40), Some(4.77036e-40)), - ((-151.189, 6.39164e-40), Some(-5.64734e-40)), - ], - ); - v -} - -#[cfg(f128_enabled)] -fn fmodf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fmodf16_cases() -> Vec> { - vec![] -} - -fn frexp_cases() -> Vec> { - vec![] -} - -fn frexpf_cases() -> Vec> { - vec![] -} - -fn hypot_cases() -> Vec> { - vec![] -} - -fn hypotf_cases() -> Vec> { - vec![] -} - -fn ilogb_cases() -> Vec> { - vec![] -} - -fn ilogbf_cases() -> Vec> { - vec![] -} - -fn j0_cases() -> Vec> { - vec![] -} - -fn j0f_cases() -> Vec> { - vec![] -} - -fn j1_cases() -> Vec> { - vec![] -} - -fn j1f_cases() -> Vec> { - vec![] -} - -fn jn_cases() -> Vec> { - vec![] -} - -fn jnf_cases() -> Vec> { - vec![] -} - -fn ldexp_cases() -> Vec> { - vec![] -} - -fn ldexpf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn ldexpf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn ldexpf16_cases() -> Vec> { - vec![] -} - -fn lgamma_cases() -> Vec> { - vec![] -} - -fn lgamma_r_cases() -> Vec> { - vec![] -} - -fn lgammaf_cases() -> Vec> { - vec![] -} - -fn lgammaf_r_cases() -> Vec> { - vec![] -} - -fn log_cases() -> Vec> { - vec![] -} - -fn log10_cases() -> Vec> { - vec![] -} - -fn log10f_cases() -> Vec> { - vec![] -} - -fn log1p_cases() -> Vec> { - vec![] -} - -fn log1pf_cases() -> Vec> { - vec![] -} - -fn log2_cases() -> Vec> { - vec![] -} - -fn log2f_cases() -> Vec> { - vec![] -} - -fn logf_cases() -> Vec> { - vec![] -} - -fn modf_cases() -> Vec> { - vec![] -} - -fn modff_cases() -> Vec> { - vec![] -} - -fn nextafter_cases() -> Vec> { - vec![] -} - -fn nextafterf_cases() -> Vec> { - vec![] -} - -fn pow_cases() -> Vec> { - vec![] -} - -fn powf_cases() -> Vec> { - vec![] -} - -fn remainder_cases() -> Vec> { - vec![] -} - -fn remainderf_cases() -> Vec> { - vec![] -} - -fn remquo_cases() -> Vec> { - vec![] -} - -fn remquof_cases() -> Vec> { - vec![] -} - -fn rint_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Known failure on i586 - #[cfg(not(x86_no_sse))] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), - #[cfg(x86_no_sse)] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))), - ], - ); - v -} - -fn rintf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn rintf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn rintf16_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn roundf16_cases() -> Vec> { - vec![] -} - -fn round_cases() -> Vec> { - vec![] -} - -fn roundf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn roundf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn roundevenf16_cases() -> Vec> { - vec![] -} - -fn roundeven_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Known failure on i586 - #[cfg(not(x86_no_sse))] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), - #[cfg(x86_no_sse)] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))), - ], - ); - v -} - -fn roundevenf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn roundevenf128_cases() -> Vec> { - vec![] -} - -fn scalbn_cases() -> Vec> { - vec![] -} - -fn scalbnf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn scalbnf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn scalbnf16_cases() -> Vec> { - vec![] -} - -fn sin_cases() -> Vec> { - vec![] -} - -fn sincos_cases() -> Vec> { - vec![] -} - -fn sincosf_cases() -> Vec> { - vec![] -} - -fn sinf_cases() -> Vec> { - vec![] -} - -fn sinh_cases() -> Vec> { - vec![] -} - -fn sinhf_cases() -> Vec> { - vec![] -} - -fn sqrt_cases() -> Vec> { - vec![] -} - -fn sqrtf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn sqrtf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn sqrtf16_cases() -> Vec> { - vec![] -} - -fn tan_cases() -> Vec> { - vec![] -} - -fn tanf_cases() -> Vec> { - vec![] -} - -fn tanh_cases() -> Vec> { - vec![] -} - -fn tanhf_cases() -> Vec> { - vec![] -} - -fn tgamma_cases() -> Vec> { - vec![] -} - -fn tgammaf_cases() -> Vec> { - vec![] -} - -fn trunc_cases() -> Vec> { - vec![] -} - -fn truncf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn truncf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn truncf16_cases() -> Vec> { - vec![] -} - -fn y0_cases() -> Vec> { - vec![] -} - -fn y0f_cases() -> Vec> { - vec![] -} - -fn y1_cases() -> Vec> { - vec![] -} - -fn y1f_cases() -> Vec> { - vec![] -} - -fn yn_cases() -> Vec> { - vec![] -} - -fn ynf_cases() -> Vec> { - vec![] -} - -pub trait CaseListInput: MathOp + Sized { - fn get_cases() -> Vec>; -} - -macro_rules! impl_case_list { - ( - fn_name: $fn_name:ident, - attrs: [$($attr:meta),*], - ) => { - paste::paste! { - $(#[$attr])* - impl CaseListInput for crate::op::$fn_name::Routine { - fn get_cases() -> Vec> { - [< $fn_name _cases >]() - } - } - } - }; -} - -libm_macros::for_each_function! { - callback: impl_case_list, -} - -/// This is the test generator for standalone tests, i.e. those with no basis. For this, it -/// only extracts tests with a known output. -pub fn get_test_cases_standalone( - ctx: &CheckCtx, -) -> impl Iterator + use<'_, Op> -where - Op: MathOp + CaseListInput, -{ - assert_eq!(ctx.basis, CheckBasis::None); - assert_eq!(ctx.gen_kind, GeneratorKind::List); - Op::get_cases().into_iter().filter_map(|x| x.output.map(|o| (x.input, o))) -} - -/// Opposite of the above; extract only test cases that don't have a known output, to be run -/// against a basis. -pub fn get_test_cases_basis( - ctx: &CheckCtx, -) -> (impl Iterator + use<'_, Op>, u64) -where - Op: MathOp + CaseListInput, -{ - assert_ne!(ctx.basis, CheckBasis::None); - assert_eq!(ctx.gen_kind, GeneratorKind::List); - - let cases = Op::get_cases(); - let count: u64 = cases.iter().filter(|case| case.output.is_none()).count().try_into().unwrap(); - - (cases.into_iter().filter(|x| x.output.is_none()).map(|x| x.input), count) -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs deleted file mode 100644 index 69b59a10567..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs +++ /dev/null @@ -1,310 +0,0 @@ -//! A generator that checks a handful of cases near infinities, zeros, asymptotes, and NaNs. - -use libm::support::{CastInto, Float, Int, MinInt}; - -use crate::domain::get_domain; -use crate::gen::KnownSize; -use crate::op::OpITy; -use crate::run_cfg::{check_near_count, check_point_count}; -use crate::{BaseName, CheckCtx, FloatExt, FloatTy, MathOp, test_log}; - -/// Generate a sequence of edge cases, e.g. numbers near zeroes and infiniteis. -pub trait EdgeCaseInput { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); -} - -/// Create a list of values around interesting points (infinities, zeroes, NaNs). -fn float_edge_cases( - ctx: &CheckCtx, - argnum: usize, -) -> (impl Iterator + Clone, u64) -where - Op: MathOp, -{ - let mut ret = Vec::new(); - let one = OpITy::::ONE; - let values = &mut ret; - let domain = get_domain::<_, i8>(ctx.fn_ident, argnum).unwrap_float(); - let domain_start = domain.range_start(); - let domain_end = domain.range_end(); - - let check_points = check_point_count(ctx); - let near_points = check_near_count(ctx); - - // Check near some notable constants - count_up(Op::FTy::ONE, near_points, values); - count_up(Op::FTy::ZERO, near_points, values); - count_up(Op::FTy::NEG_ONE, near_points, values); - count_down(Op::FTy::ONE, near_points, values); - count_down(Op::FTy::ZERO, near_points, values); - count_down(Op::FTy::NEG_ONE, near_points, values); - values.push(Op::FTy::NEG_ZERO); - - // Check values near the extremes - count_up(Op::FTy::NEG_INFINITY, near_points, values); - count_down(Op::FTy::INFINITY, near_points, values); - count_down(domain_end, near_points, values); - count_up(domain_start, near_points, values); - count_down(domain_start, near_points, values); - count_up(domain_end, near_points, values); - count_down(domain_end, near_points, values); - - // Check some special values that aren't included in the above ranges - values.push(Op::FTy::NAN); - values.extend(Op::FTy::consts().iter()); - - // Check around the maximum subnormal value - let sub_max = Op::FTy::from_bits(Op::FTy::SIG_MASK); - count_up(sub_max, near_points, values); - count_down(sub_max, near_points, values); - count_up(-sub_max, near_points, values); - count_down(-sub_max, near_points, values); - - // Check a few values around the subnormal range - for shift in (0..Op::FTy::SIG_BITS).step_by(Op::FTy::SIG_BITS as usize / 5) { - let v = Op::FTy::from_bits(one << shift); - count_up(v, 2, values); - count_down(v, 2, values); - count_up(-v, 2, values); - count_down(-v, 2, values); - } - - // Check around asymptotes - if let Some(f) = domain.check_points { - let iter = f(); - for x in iter.take(check_points) { - count_up(x, near_points, values); - count_down(x, near_points, values); - } - } - - // Some results may overlap so deduplicate the vector to save test cycles. - values.sort_by_key(|x| x.to_bits()); - values.dedup_by_key(|x| x.to_bits()); - - let count = ret.len().try_into().unwrap(); - - test_log(&format!( - "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {count} edge cases", - gen_kind = ctx.gen_kind, - basis = ctx.basis, - fn_ident = ctx.fn_ident, - arg = argnum + 1, - args = ctx.input_count(), - )); - - (ret.into_iter(), count) -} - -/// Add `points` values starting at and including `x` and counting up. Uses the smallest possible -/// increments (1 ULP). -fn count_up(mut x: F, points: u64, values: &mut Vec) { - assert!(!x.is_nan()); - - let mut count = 0; - while x < F::INFINITY && count < points { - values.push(x); - x = x.next_up(); - count += 1; - } -} - -/// Add `points` values starting at and including `x` and counting down. Uses the smallest possible -/// increments (1 ULP). -fn count_down(mut x: F, points: u64, values: &mut Vec) { - assert!(!x.is_nan()); - - let mut count = 0; - while x > F::NEG_INFINITY && count < points { - values.push(x); - x = x.next_down(); - count += 1; - } -} - -/// Create a list of values around interesting integer points (min, zero, max). -pub fn int_edge_cases( - ctx: &CheckCtx, - argnum: usize, -) -> (impl Iterator + Clone, u64) -where - i32: CastInto, -{ - let mut values = Vec::new(); - let near_points = check_near_count(ctx); - - // Check around max/min and zero - int_count_around(I::MIN, near_points, &mut values); - int_count_around(I::MAX, near_points, &mut values); - int_count_around(I::ZERO, near_points, &mut values); - int_count_around(I::ZERO, near_points, &mut values); - - if matches!(ctx.base_name, BaseName::Scalbn | BaseName::Ldexp) { - assert_eq!(argnum, 1, "scalbn integer argument should be arg1"); - let (emax, emin, emin_sn) = match ctx.fn_ident.math_op().float_ty { - FloatTy::F16 => { - #[cfg(not(f16_enabled))] - unreachable!(); - #[cfg(f16_enabled)] - (f16::EXP_MAX, f16::EXP_MIN, f16::EXP_MIN_SUBNORM) - } - FloatTy::F32 => (f32::EXP_MAX, f32::EXP_MIN, f32::EXP_MIN_SUBNORM), - FloatTy::F64 => (f64::EXP_MAX, f64::EXP_MIN, f64::EXP_MIN_SUBNORM), - FloatTy::F128 => { - #[cfg(not(f128_enabled))] - unreachable!(); - #[cfg(f128_enabled)] - (f128::EXP_MAX, f128::EXP_MIN, f128::EXP_MIN_SUBNORM) - } - }; - - // `scalbn`/`ldexp` have their trickiest behavior around exponent limits - int_count_around(emax.cast(), near_points, &mut values); - int_count_around(emin.cast(), near_points, &mut values); - int_count_around(emin_sn.cast(), near_points, &mut values); - int_count_around((-emin_sn).cast(), near_points, &mut values); - - // Also check values that cause the maximum possible difference in exponents - int_count_around((emax - emin).cast(), near_points, &mut values); - int_count_around((emin - emax).cast(), near_points, &mut values); - int_count_around((emax - emin_sn).cast(), near_points, &mut values); - int_count_around((emin_sn - emax).cast(), near_points, &mut values); - } - - values.sort(); - values.dedup(); - let count = values.len().try_into().unwrap(); - - test_log(&format!( - "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {count} edge cases", - gen_kind = ctx.gen_kind, - basis = ctx.basis, - fn_ident = ctx.fn_ident, - arg = argnum + 1, - args = ctx.input_count(), - )); - - (values.into_iter(), count) -} - -/// Add `points` values both up and down, starting at and including `x`. -fn int_count_around(x: I, points: u64, values: &mut Vec) { - let mut current = x; - for _ in 0..points { - values.push(current); - current = match current.checked_add(I::ONE) { - Some(v) => v, - None => break, - }; - } - - current = x; - for _ in 0..points { - values.push(current); - current = match current.checked_sub(I::ONE) { - Some(v) => v, - None => break, - }; - } -} - -macro_rules! impl_edge_case_input { - ($fty:ty) => { - impl EdgeCaseInput for ($fty,) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let (iter0, steps0) = float_edge_cases::(ctx, 0); - let iter0 = iter0.map(|v| (v,)); - (iter0, steps0) - } - } - - impl EdgeCaseInput for ($fty, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let (iter0, steps0) = float_edge_cases::(ctx, 0); - let (iter1, steps1) = float_edge_cases::(ctx, 1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); - (iter, count) - } - } - - impl EdgeCaseInput for ($fty, $fty, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let (iter0, steps0) = float_edge_cases::(ctx, 0); - let (iter1, steps1) = float_edge_cases::(ctx, 1); - let (iter2, steps2) = float_edge_cases::(ctx, 2); - - let iter = iter0 - .flat_map(move |first| iter1.clone().map(move |second| (first, second))) - .flat_map(move |(first, second)| { - iter2.clone().map(move |third| (first, second, third)) - }); - let count = steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); - - (iter, count) - } - } - - impl EdgeCaseInput for (i32, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let (iter0, steps0) = int_edge_cases(ctx, 0); - let (iter1, steps1) = float_edge_cases::(ctx, 1); - - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); - - (iter, count) - } - } - - impl EdgeCaseInput for ($fty, i32) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let (iter0, steps0) = float_edge_cases::(ctx, 0); - let (iter1, steps1) = int_edge_cases(ctx, 1); - - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); - - (iter, count) - } - } - }; -} - -#[cfg(f16_enabled)] -impl_edge_case_input!(f16); -impl_edge_case_input!(f32); -impl_edge_case_input!(f64); -#[cfg(f128_enabled)] -impl_edge_case_input!(f128); - -pub fn get_test_cases( - ctx: &CheckCtx, -) -> (impl Iterator + Send + use<'_, Op>, u64) -where - Op: MathOp, - Op::RustArgs: EdgeCaseInput, -{ - let (iter, count) = Op::RustArgs::get_cases(ctx); - - // Wrap in `KnownSize` so we get an assertion if the cuunt is wrong. - (KnownSize::new(iter, count), count) -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs deleted file mode 100644 index e8a7ee9057e..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ /dev/null @@ -1,125 +0,0 @@ -use std::env; -use std::ops::RangeInclusive; -use std::sync::LazyLock; - -use libm::support::Float; -use rand::distr::{Alphanumeric, StandardUniform}; -use rand::prelude::Distribution; -use rand::{Rng, SeedableRng}; -use rand_chacha::ChaCha8Rng; - -use super::KnownSize; -use crate::CheckCtx; -use crate::run_cfg::{int_range, iteration_count}; - -pub(crate) const SEED_ENV: &str = "LIBM_SEED"; - -pub static SEED: LazyLock<[u8; 32]> = LazyLock::new(|| { - let s = env::var(SEED_ENV).unwrap_or_else(|_| { - let mut rng = rand::rng(); - (0..32).map(|_| rng.sample(Alphanumeric) as char).collect() - }); - - s.as_bytes().try_into().unwrap_or_else(|_| { - panic!("Seed must be 32 characters, got `{s}`"); - }) -}); - -/// Generate a sequence of random values of this type. -pub trait RandomInput: Sized { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); -} - -/// Generate a sequence of deterministically random floats. -fn random_floats(count: u64) -> impl Iterator -where - StandardUniform: Distribution, -{ - let mut rng = ChaCha8Rng::from_seed(*SEED); - - // Generate integers to get a full range of bitpatterns (including NaNs), then convert back - // to the float type. - (0..count).map(move |_| F::from_bits(rng.random::())) -} - -/// Generate a sequence of deterministically random `i32`s within a specified range. -fn random_ints(count: u64, range: RangeInclusive) -> impl Iterator { - let mut rng = ChaCha8Rng::from_seed(*SEED); - (0..count).map(move |_| rng.random_range::(range.clone())) -} - -macro_rules! impl_random_input { - ($fty:ty) => { - impl RandomInput for ($fty,) { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let count = iteration_count(ctx, 0); - let iter = random_floats(count).map(|f: $fty| (f,)); - (iter, count) - } - } - - impl RandomInput for ($fty, $fty) { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let count0 = iteration_count(ctx, 0); - let count1 = iteration_count(ctx, 1); - let iter = random_floats(count0) - .flat_map(move |f1: $fty| random_floats(count1).map(move |f2: $fty| (f1, f2))); - (iter, count0 * count1) - } - } - - impl RandomInput for ($fty, $fty, $fty) { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let count0 = iteration_count(ctx, 0); - let count1 = iteration_count(ctx, 1); - let count2 = iteration_count(ctx, 2); - let iter = random_floats(count0).flat_map(move |f1: $fty| { - random_floats(count1).flat_map(move |f2: $fty| { - random_floats(count2).map(move |f3: $fty| (f1, f2, f3)) - }) - }); - (iter, count0 * count1 * count2) - } - } - - impl RandomInput for (i32, $fty) { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let count0 = iteration_count(ctx, 0); - let count1 = iteration_count(ctx, 1); - let range0 = int_range(ctx, 0); - let iter = random_ints(count0, range0) - .flat_map(move |f1: i32| random_floats(count1).map(move |f2: $fty| (f1, f2))); - (iter, count0 * count1) - } - } - - impl RandomInput for ($fty, i32) { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let count0 = iteration_count(ctx, 0); - let count1 = iteration_count(ctx, 1); - let range1 = int_range(ctx, 1); - let iter = random_floats(count0).flat_map(move |f1: $fty| { - random_ints(count1, range1.clone()).map(move |f2: i32| (f1, f2)) - }); - (iter, count0 * count1) - } - } - }; -} - -#[cfg(f16_enabled)] -impl_random_input!(f16); -impl_random_input!(f32); -impl_random_input!(f64); -#[cfg(f128_enabled)] -impl_random_input!(f128); - -/// Create a test case iterator. -pub fn get_test_cases( - ctx: &CheckCtx, -) -> (impl Iterator + Send + use<'_, RustArgs>, u64) { - let (iter, count) = RustArgs::get_cases(ctx); - - // Wrap in `KnownSize` so we get an assertion if the cuunt is wrong. - (KnownSize::new(iter, count), count) -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/spaced.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/spaced.rs deleted file mode 100644 index bea3f4c7e1b..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/spaced.rs +++ /dev/null @@ -1,253 +0,0 @@ -use std::fmt; -use std::ops::RangeInclusive; - -use libm::support::{Float, MinInt}; - -use crate::domain::get_domain; -use crate::op::OpITy; -use crate::run_cfg::{int_range, iteration_count}; -use crate::{CheckCtx, MathOp, linear_ints, logspace}; - -/// Generate a sequence of inputs that eiher cover the domain in completeness (for smaller float -/// types and single argument functions) or provide evenly spaced inputs across the domain with -/// approximately `u32::MAX` total iterations. -pub trait SpacedInput { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); -} - -/// Construct an iterator from `logspace` and also calculate the total number of steps expected -/// for that iterator. -fn logspace_steps( - ctx: &CheckCtx, - argnum: usize, - max_steps: u64, -) -> (impl Iterator + Clone, u64) -where - Op: MathOp, - OpITy: TryFrom, - u64: TryFrom, Error: fmt::Debug>, - RangeInclusive>: Iterator, -{ - // i8 is a dummy type here, it can be any integer. - let domain = get_domain::(ctx.fn_ident, argnum).unwrap_float(); - let start = domain.range_start(); - let end = domain.range_end(); - - let max_steps = OpITy::::try_from(max_steps).unwrap_or(OpITy::::MAX); - let (iter, steps) = logspace(start, end, max_steps); - - // `steps` will be <= the original `max_steps`, which is a `u64`. - (iter, steps.try_into().unwrap()) -} - -/// Represents the iterator in either `Left` or `Right`. -enum EitherIter { - A(A), - B(B), -} - -impl, B: Iterator> Iterator for EitherIter { - type Item = T; - - fn next(&mut self) -> Option { - match self { - Self::A(iter) => iter.next(), - Self::B(iter) => iter.next(), - } - } - - fn size_hint(&self) -> (usize, Option) { - match self { - Self::A(iter) => iter.size_hint(), - Self::B(iter) => iter.size_hint(), - } - } -} - -/// Gets the total number of possible values, returning `None` if that number doesn't fit in a -/// `u64`. -fn value_count() -> Option -where - u64: TryFrom, -{ - u64::try_from(F::Int::MAX).ok().and_then(|max| max.checked_add(1)) -} - -/// Returns an iterator of every possible value of type `F`. -fn all_values() -> impl Iterator -where - RangeInclusive: Iterator, -{ - (F::Int::MIN..=F::Int::MAX).map(|bits| F::from_bits(bits)) -} - -macro_rules! impl_spaced_input { - ($fty:ty) => { - impl SpacedInput for ($fty,) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, 0); - // `f16` and `f32` can have exhaustive tests. - match value_count::() { - Some(steps0) if steps0 <= max_steps0 => { - let iter0 = all_values(); - let iter0 = iter0.map(|v| (v,)); - (EitherIter::A(iter0), steps0) - } - _ => { - let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); - let iter0 = iter0.map(|v| (v,)); - (EitherIter::B(iter0), steps0) - } - } - } - } - - impl SpacedInput for ($fty, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, 0); - let max_steps1 = iteration_count(ctx, 1); - // `f16` can have exhaustive tests. - match value_count::() { - Some(count) if count <= max_steps0 && count <= max_steps1 => { - let iter = all_values() - .flat_map(|first| all_values().map(move |second| (first, second))); - (EitherIter::A(iter), count.checked_mul(count).unwrap()) - } - _ => { - let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); - let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); - let iter = iter0.flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = steps0.checked_mul(steps1).unwrap(); - (EitherIter::B(iter), count) - } - } - } - } - - impl SpacedInput for ($fty, $fty, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, 0); - let max_steps1 = iteration_count(ctx, 1); - let max_steps2 = iteration_count(ctx, 2); - // `f16` can be exhaustive tested if `LIBM_EXTENSIVE_TESTS` is incresed. - match value_count::() { - Some(count) - if count <= max_steps0 && count <= max_steps1 && count <= max_steps2 => - { - let iter = all_values().flat_map(|first| { - all_values().flat_map(move |second| { - all_values().map(move |third| (first, second, third)) - }) - }); - (EitherIter::A(iter), count.checked_pow(3).unwrap()) - } - _ => { - let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); - let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); - let (iter2, steps2) = logspace_steps::(ctx, 2, max_steps2); - - let iter = iter0 - .flat_map(move |first| iter1.clone().map(move |second| (first, second))) - .flat_map(move |(first, second)| { - iter2.clone().map(move |third| (first, second, third)) - }); - let count = - steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); - - (EitherIter::B(iter), count) - } - } - } - } - - impl SpacedInput for (i32, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let range0 = int_range(ctx, 0); - let max_steps0 = iteration_count(ctx, 0); - let max_steps1 = iteration_count(ctx, 1); - match value_count::() { - Some(count1) if count1 <= max_steps1 => { - let (iter0, steps0) = linear_ints(range0, max_steps0); - let iter = iter0 - .flat_map(move |first| all_values().map(move |second| (first, second))); - (EitherIter::A(iter), steps0.checked_mul(count1).unwrap()) - } - _ => { - let (iter0, steps0) = linear_ints(range0, max_steps0); - let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); - - let iter = iter0.flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = steps0.checked_mul(steps1).unwrap(); - - (EitherIter::B(iter), count) - } - } - } - } - - impl SpacedInput for ($fty, i32) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, 0); - let range1 = int_range(ctx, 1); - let max_steps1 = iteration_count(ctx, 1); - match value_count::() { - Some(count0) if count0 <= max_steps0 => { - let (iter1, steps1) = linear_ints(range1, max_steps1); - let iter = all_values().flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - (EitherIter::A(iter), count0.checked_mul(steps1).unwrap()) - } - _ => { - let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); - let (iter1, steps1) = linear_ints(range1, max_steps1); - - let iter = iter0.flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = steps0.checked_mul(steps1).unwrap(); - - (EitherIter::B(iter), count) - } - } - } - } - }; -} - -#[cfg(f16_enabled)] -impl_spaced_input!(f16); -impl_spaced_input!(f32); -impl_spaced_input!(f64); -#[cfg(f128_enabled)] -impl_spaced_input!(f128); - -/// Create a test case iterator for extensive inputs. Also returns the total test case count. -pub fn get_test_cases( - ctx: &CheckCtx, -) -> (impl Iterator + Send + use<'_, Op>, u64) -where - Op: MathOp, - Op::RustArgs: SpacedInput, -{ - Op::RustArgs::get_cases(ctx) -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate.rs new file mode 100644 index 00000000000..89ca09a7a0b --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/generate.rs @@ -0,0 +1,43 @@ +//! Different generators that can create random or systematic bit patterns. + +pub mod case_list; +pub mod edge_cases; +pub mod random; +pub mod spaced; + +/// A wrapper to turn any iterator into an `ExactSizeIterator`. Asserts the final result to ensure +/// the provided size was correct. +#[derive(Debug)] +pub struct KnownSize { + total: u64, + current: u64, + iter: I, +} + +impl KnownSize { + pub fn new(iter: I, total: u64) -> Self { + Self { total, current: 0, iter } + } +} + +impl Iterator for KnownSize { + type Item = I::Item; + + fn next(&mut self) -> Option { + let next = self.iter.next(); + if next.is_some() { + self.current += 1; + return next; + } + + assert_eq!(self.current, self.total, "total items did not match expected"); + None + } + + fn size_hint(&self) -> (usize, Option) { + let remaining = usize::try_from(self.total - self.current).unwrap(); + (remaining, Some(remaining)) + } +} + +impl ExactSizeIterator for KnownSize {} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate/case_list.rs new file mode 100644 index 00000000000..e3628d51c9a --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/generate/case_list.rs @@ -0,0 +1,853 @@ +//! Test cases to verify specific values. +//! +//! Each routine can have a set of inputs and, optinoally, outputs. If an output is provided, it +//! will be used to check against. If only inputs are provided, the case will be checked against +//! a basis. +//! +//! This is useful for adding regression tests or expected failures. + +use libm::hf64; +#[cfg(f128_enabled)] +use libm::hf128; + +use crate::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; + +pub struct TestCase { + pub input: Op::RustArgs, + pub output: Option, +} + +impl TestCase { + #[expect(dead_code)] + fn append_inputs(v: &mut Vec, l: &[Op::RustArgs]) { + v.extend(l.iter().copied().map(|input| Self { input, output: None })); + } + + fn append_pairs(v: &mut Vec, l: &[(Op::RustArgs, Option)]) + where + Op::RustRet: Copy, + { + v.extend(l.iter().copied().map(|(input, output)| Self { input, output })); + } +} + +fn acos_cases() -> Vec> { + vec![] +} + +fn acosf_cases() -> Vec> { + vec![] +} + +fn acosh_cases() -> Vec> { + vec![] +} + +fn acoshf_cases() -> Vec> { + vec![] +} + +fn asin_cases() -> Vec> { + vec![] +} + +fn asinf_cases() -> Vec> { + vec![] +} + +fn asinh_cases() -> Vec> { + vec![] +} + +fn asinhf_cases() -> Vec> { + vec![] +} + +fn atan_cases() -> Vec> { + vec![] +} + +fn atan2_cases() -> Vec> { + vec![] +} + +fn atan2f_cases() -> Vec> { + vec![] +} + +fn atanf_cases() -> Vec> { + vec![] +} + +fn atanh_cases() -> Vec> { + vec![] +} + +fn atanhf_cases() -> Vec> { + vec![] +} + +fn cbrt_cases() -> Vec> { + vec![] +} + +fn cbrtf_cases() -> Vec> { + vec![] +} + +fn ceil_cases() -> Vec> { + vec![] +} + +fn ceilf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ceilf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn ceilf16_cases() -> Vec> { + vec![] +} + +fn copysign_cases() -> Vec> { + vec![] +} + +fn copysignf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn copysignf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn copysignf16_cases() -> Vec> { + vec![] +} + +fn cos_cases() -> Vec> { + vec![] +} + +fn cosf_cases() -> Vec> { + vec![] +} + +fn cosh_cases() -> Vec> { + vec![] +} + +fn coshf_cases() -> Vec> { + vec![] +} + +fn erf_cases() -> Vec> { + vec![] +} + +fn erfc_cases() -> Vec> { + vec![] +} + +fn erfcf_cases() -> Vec> { + vec![] +} + +fn erff_cases() -> Vec> { + vec![] +} + +fn exp_cases() -> Vec> { + vec![] +} + +fn exp10_cases() -> Vec> { + vec![] +} + +fn exp10f_cases() -> Vec> { + vec![] +} + +fn exp2_cases() -> Vec> { + vec![] +} + +fn exp2f_cases() -> Vec> { + vec![] +} + +fn expf_cases() -> Vec> { + vec![] +} + +fn expm1_cases() -> Vec> { + vec![] +} + +fn expm1f_cases() -> Vec> { + vec![] +} + +fn fabs_cases() -> Vec> { + vec![] +} + +fn fabsf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fabsf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fabsf16_cases() -> Vec> { + vec![] +} + +fn fdim_cases() -> Vec> { + vec![] +} + +fn fdimf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fdimf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fdimf16_cases() -> Vec> { + vec![] +} + +fn floor_cases() -> Vec> { + vec![] +} + +fn floorf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn floorf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn floorf16_cases() -> Vec> { + vec![] +} + +fn fma_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Previous failure with incorrect sign + ((5e-324, -5e-324, 0.0), Some(-0.0)), + ], + ); + v +} + +fn fmaf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmaf128_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + ( + // Tricky rounding case that previously failed in extensive tests + ( + hf128!("-0x1.1966cc01966cc01966cc01966f06p-25"), + hf128!("-0x1.669933fe69933fe69933fe6997c9p-16358"), + hf128!("-0x0.000000000000000000000000048ap-16382"), + ), + Some(hf128!("0x0.c5171470a3ff5e0f68d751491b18p-16382")), + ), + ( + // Subnormal edge case that caused a failure + ( + hf128!("0x0.7ffffffffffffffffffffffffff7p-16382"), + hf128!("0x1.ffffffffffffffffffffffffffffp-1"), + hf128!("0x0.8000000000000000000000000009p-16382"), + ), + Some(hf128!("0x1.0000000000000000000000000000p-16382")), + ), + ], + ); + v +} + +#[cfg(f16_enabled)] +fn fmaxf16_cases() -> Vec> { + vec![] +} + +fn fmaxf_cases() -> Vec> { + vec![] +} + +fn fmax_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmaxf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fmaximumf16_cases() -> Vec> { + vec![] +} + +fn fmaximumf_cases() -> Vec> { + vec![] +} + +fn fmaximum_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmaximumf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fmaximum_numf16_cases() -> Vec> { + vec![] +} + +fn fmaximum_numf_cases() -> Vec> { + vec![] +} + +fn fmaximum_num_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmaximum_numf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fminf16_cases() -> Vec> { + vec![] +} + +fn fminf_cases() -> Vec> { + vec![] +} + +fn fmin_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fminf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fminimumf16_cases() -> Vec> { + vec![] +} + +fn fminimumf_cases() -> Vec> { + vec![] +} + +fn fminimum_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fminimumf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fminimum_numf16_cases() -> Vec> { + vec![] +} + +fn fminimum_numf_cases() -> Vec> { + vec![] +} + +fn fminimum_num_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fminimum_numf128_cases() -> Vec> { + vec![] +} + +fn fmod_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Previous failure with incorrect loop iteration + // + ((2.1, 3.123e-320), Some(2.0696e-320)), + ((2.1, 2.253547e-318), Some(1.772535e-318)), + ], + ); + v +} + +fn fmodf_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Previous failure with incorrect loop iteration + // + ((2.1, 8.858e-42), Some(8.085e-42)), + ((2.1, 6.39164e-40), Some(6.1636e-40)), + ((5.5, 6.39164e-40), Some(4.77036e-40)), + ((-151.189, 6.39164e-40), Some(-5.64734e-40)), + ], + ); + v +} + +#[cfg(f128_enabled)] +fn fmodf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fmodf16_cases() -> Vec> { + vec![] +} + +fn frexp_cases() -> Vec> { + vec![] +} + +fn frexpf_cases() -> Vec> { + vec![] +} + +fn hypot_cases() -> Vec> { + vec![] +} + +fn hypotf_cases() -> Vec> { + vec![] +} + +fn ilogb_cases() -> Vec> { + vec![] +} + +fn ilogbf_cases() -> Vec> { + vec![] +} + +fn j0_cases() -> Vec> { + vec![] +} + +fn j0f_cases() -> Vec> { + vec![] +} + +fn j1_cases() -> Vec> { + vec![] +} + +fn j1f_cases() -> Vec> { + vec![] +} + +fn jn_cases() -> Vec> { + vec![] +} + +fn jnf_cases() -> Vec> { + vec![] +} + +fn ldexp_cases() -> Vec> { + vec![] +} + +fn ldexpf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ldexpf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn ldexpf16_cases() -> Vec> { + vec![] +} + +fn lgamma_cases() -> Vec> { + vec![] +} + +fn lgamma_r_cases() -> Vec> { + vec![] +} + +fn lgammaf_cases() -> Vec> { + vec![] +} + +fn lgammaf_r_cases() -> Vec> { + vec![] +} + +fn log_cases() -> Vec> { + vec![] +} + +fn log10_cases() -> Vec> { + vec![] +} + +fn log10f_cases() -> Vec> { + vec![] +} + +fn log1p_cases() -> Vec> { + vec![] +} + +fn log1pf_cases() -> Vec> { + vec![] +} + +fn log2_cases() -> Vec> { + vec![] +} + +fn log2f_cases() -> Vec> { + vec![] +} + +fn logf_cases() -> Vec> { + vec![] +} + +fn modf_cases() -> Vec> { + vec![] +} + +fn modff_cases() -> Vec> { + vec![] +} + +fn nextafter_cases() -> Vec> { + vec![] +} + +fn nextafterf_cases() -> Vec> { + vec![] +} + +fn pow_cases() -> Vec> { + vec![] +} + +fn powf_cases() -> Vec> { + vec![] +} + +fn remainder_cases() -> Vec> { + vec![] +} + +fn remainderf_cases() -> Vec> { + vec![] +} + +fn remquo_cases() -> Vec> { + vec![] +} + +fn remquof_cases() -> Vec> { + vec![] +} + +fn rint_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Known failure on i586 + #[cfg(not(x86_no_sse))] + ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), + #[cfg(x86_no_sse)] + ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))), + ], + ); + v +} + +fn rintf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn rintf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn rintf16_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn roundf16_cases() -> Vec> { + vec![] +} + +fn round_cases() -> Vec> { + vec![] +} + +fn roundf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn roundf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn roundevenf16_cases() -> Vec> { + vec![] +} + +fn roundeven_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Known failure on i586 + #[cfg(not(x86_no_sse))] + ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), + #[cfg(x86_no_sse)] + ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))), + ], + ); + v +} + +fn roundevenf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn roundevenf128_cases() -> Vec> { + vec![] +} + +fn scalbn_cases() -> Vec> { + vec![] +} + +fn scalbnf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn scalbnf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn scalbnf16_cases() -> Vec> { + vec![] +} + +fn sin_cases() -> Vec> { + vec![] +} + +fn sincos_cases() -> Vec> { + vec![] +} + +fn sincosf_cases() -> Vec> { + vec![] +} + +fn sinf_cases() -> Vec> { + vec![] +} + +fn sinh_cases() -> Vec> { + vec![] +} + +fn sinhf_cases() -> Vec> { + vec![] +} + +fn sqrt_cases() -> Vec> { + vec![] +} + +fn sqrtf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn sqrtf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn sqrtf16_cases() -> Vec> { + vec![] +} + +fn tan_cases() -> Vec> { + vec![] +} + +fn tanf_cases() -> Vec> { + vec![] +} + +fn tanh_cases() -> Vec> { + vec![] +} + +fn tanhf_cases() -> Vec> { + vec![] +} + +fn tgamma_cases() -> Vec> { + vec![] +} + +fn tgammaf_cases() -> Vec> { + vec![] +} + +fn trunc_cases() -> Vec> { + vec![] +} + +fn truncf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn truncf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn truncf16_cases() -> Vec> { + vec![] +} + +fn y0_cases() -> Vec> { + vec![] +} + +fn y0f_cases() -> Vec> { + vec![] +} + +fn y1_cases() -> Vec> { + vec![] +} + +fn y1f_cases() -> Vec> { + vec![] +} + +fn yn_cases() -> Vec> { + vec![] +} + +fn ynf_cases() -> Vec> { + vec![] +} + +pub trait CaseListInput: MathOp + Sized { + fn get_cases() -> Vec>; +} + +macro_rules! impl_case_list { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + ) => { + paste::paste! { + $(#[$attr])* + impl CaseListInput for crate::op::$fn_name::Routine { + fn get_cases() -> Vec> { + [< $fn_name _cases >]() + } + } + } + }; +} + +libm_macros::for_each_function! { + callback: impl_case_list, +} + +/// This is the test generator for standalone tests, i.e. those with no basis. For this, it +/// only extracts tests with a known output. +pub fn get_test_cases_standalone( + ctx: &CheckCtx, +) -> impl Iterator + use<'_, Op> +where + Op: MathOp + CaseListInput, +{ + assert_eq!(ctx.basis, CheckBasis::None); + assert_eq!(ctx.gen_kind, GeneratorKind::List); + Op::get_cases().into_iter().filter_map(|x| x.output.map(|o| (x.input, o))) +} + +/// Opposite of the above; extract only test cases that don't have a known output, to be run +/// against a basis. +pub fn get_test_cases_basis( + ctx: &CheckCtx, +) -> (impl Iterator + use<'_, Op>, u64) +where + Op: MathOp + CaseListInput, +{ + assert_ne!(ctx.basis, CheckBasis::None); + assert_eq!(ctx.gen_kind, GeneratorKind::List); + + let cases = Op::get_cases(); + let count: u64 = cases.iter().filter(|case| case.output.is_none()).count().try_into().unwrap(); + + (cases.into_iter().filter(|x| x.output.is_none()).map(|x| x.input), count) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate/edge_cases.rs new file mode 100644 index 00000000000..56cc9fa9a70 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/generate/edge_cases.rs @@ -0,0 +1,310 @@ +//! A generator that checks a handful of cases near infinities, zeros, asymptotes, and NaNs. + +use libm::support::{CastInto, Float, Int, MinInt}; + +use crate::domain::get_domain; +use crate::generate::KnownSize; +use crate::op::OpITy; +use crate::run_cfg::{check_near_count, check_point_count}; +use crate::{BaseName, CheckCtx, FloatExt, FloatTy, MathOp, test_log}; + +/// Generate a sequence of edge cases, e.g. numbers near zeroes and infiniteis. +pub trait EdgeCaseInput { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); +} + +/// Create a list of values around interesting points (infinities, zeroes, NaNs). +fn float_edge_cases( + ctx: &CheckCtx, + argnum: usize, +) -> (impl Iterator + Clone, u64) +where + Op: MathOp, +{ + let mut ret = Vec::new(); + let one = OpITy::::ONE; + let values = &mut ret; + let domain = get_domain::<_, i8>(ctx.fn_ident, argnum).unwrap_float(); + let domain_start = domain.range_start(); + let domain_end = domain.range_end(); + + let check_points = check_point_count(ctx); + let near_points = check_near_count(ctx); + + // Check near some notable constants + count_up(Op::FTy::ONE, near_points, values); + count_up(Op::FTy::ZERO, near_points, values); + count_up(Op::FTy::NEG_ONE, near_points, values); + count_down(Op::FTy::ONE, near_points, values); + count_down(Op::FTy::ZERO, near_points, values); + count_down(Op::FTy::NEG_ONE, near_points, values); + values.push(Op::FTy::NEG_ZERO); + + // Check values near the extremes + count_up(Op::FTy::NEG_INFINITY, near_points, values); + count_down(Op::FTy::INFINITY, near_points, values); + count_down(domain_end, near_points, values); + count_up(domain_start, near_points, values); + count_down(domain_start, near_points, values); + count_up(domain_end, near_points, values); + count_down(domain_end, near_points, values); + + // Check some special values that aren't included in the above ranges + values.push(Op::FTy::NAN); + values.extend(Op::FTy::consts().iter()); + + // Check around the maximum subnormal value + let sub_max = Op::FTy::from_bits(Op::FTy::SIG_MASK); + count_up(sub_max, near_points, values); + count_down(sub_max, near_points, values); + count_up(-sub_max, near_points, values); + count_down(-sub_max, near_points, values); + + // Check a few values around the subnormal range + for shift in (0..Op::FTy::SIG_BITS).step_by(Op::FTy::SIG_BITS as usize / 5) { + let v = Op::FTy::from_bits(one << shift); + count_up(v, 2, values); + count_down(v, 2, values); + count_up(-v, 2, values); + count_down(-v, 2, values); + } + + // Check around asymptotes + if let Some(f) = domain.check_points { + let iter = f(); + for x in iter.take(check_points) { + count_up(x, near_points, values); + count_down(x, near_points, values); + } + } + + // Some results may overlap so deduplicate the vector to save test cycles. + values.sort_by_key(|x| x.to_bits()); + values.dedup_by_key(|x| x.to_bits()); + + let count = ret.len().try_into().unwrap(); + + test_log(&format!( + "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {count} edge cases", + gen_kind = ctx.gen_kind, + basis = ctx.basis, + fn_ident = ctx.fn_ident, + arg = argnum + 1, + args = ctx.input_count(), + )); + + (ret.into_iter(), count) +} + +/// Add `points` values starting at and including `x` and counting up. Uses the smallest possible +/// increments (1 ULP). +fn count_up(mut x: F, points: u64, values: &mut Vec) { + assert!(!x.is_nan()); + + let mut count = 0; + while x < F::INFINITY && count < points { + values.push(x); + x = x.next_up(); + count += 1; + } +} + +/// Add `points` values starting at and including `x` and counting down. Uses the smallest possible +/// increments (1 ULP). +fn count_down(mut x: F, points: u64, values: &mut Vec) { + assert!(!x.is_nan()); + + let mut count = 0; + while x > F::NEG_INFINITY && count < points { + values.push(x); + x = x.next_down(); + count += 1; + } +} + +/// Create a list of values around interesting integer points (min, zero, max). +pub fn int_edge_cases( + ctx: &CheckCtx, + argnum: usize, +) -> (impl Iterator + Clone, u64) +where + i32: CastInto, +{ + let mut values = Vec::new(); + let near_points = check_near_count(ctx); + + // Check around max/min and zero + int_count_around(I::MIN, near_points, &mut values); + int_count_around(I::MAX, near_points, &mut values); + int_count_around(I::ZERO, near_points, &mut values); + int_count_around(I::ZERO, near_points, &mut values); + + if matches!(ctx.base_name, BaseName::Scalbn | BaseName::Ldexp) { + assert_eq!(argnum, 1, "scalbn integer argument should be arg1"); + let (emax, emin, emin_sn) = match ctx.fn_ident.math_op().float_ty { + FloatTy::F16 => { + #[cfg(not(f16_enabled))] + unreachable!(); + #[cfg(f16_enabled)] + (f16::EXP_MAX, f16::EXP_MIN, f16::EXP_MIN_SUBNORM) + } + FloatTy::F32 => (f32::EXP_MAX, f32::EXP_MIN, f32::EXP_MIN_SUBNORM), + FloatTy::F64 => (f64::EXP_MAX, f64::EXP_MIN, f64::EXP_MIN_SUBNORM), + FloatTy::F128 => { + #[cfg(not(f128_enabled))] + unreachable!(); + #[cfg(f128_enabled)] + (f128::EXP_MAX, f128::EXP_MIN, f128::EXP_MIN_SUBNORM) + } + }; + + // `scalbn`/`ldexp` have their trickiest behavior around exponent limits + int_count_around(emax.cast(), near_points, &mut values); + int_count_around(emin.cast(), near_points, &mut values); + int_count_around(emin_sn.cast(), near_points, &mut values); + int_count_around((-emin_sn).cast(), near_points, &mut values); + + // Also check values that cause the maximum possible difference in exponents + int_count_around((emax - emin).cast(), near_points, &mut values); + int_count_around((emin - emax).cast(), near_points, &mut values); + int_count_around((emax - emin_sn).cast(), near_points, &mut values); + int_count_around((emin_sn - emax).cast(), near_points, &mut values); + } + + values.sort(); + values.dedup(); + let count = values.len().try_into().unwrap(); + + test_log(&format!( + "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {count} edge cases", + gen_kind = ctx.gen_kind, + basis = ctx.basis, + fn_ident = ctx.fn_ident, + arg = argnum + 1, + args = ctx.input_count(), + )); + + (values.into_iter(), count) +} + +/// Add `points` values both up and down, starting at and including `x`. +fn int_count_around(x: I, points: u64, values: &mut Vec) { + let mut current = x; + for _ in 0..points { + values.push(current); + current = match current.checked_add(I::ONE) { + Some(v) => v, + None => break, + }; + } + + current = x; + for _ in 0..points { + values.push(current); + current = match current.checked_sub(I::ONE) { + Some(v) => v, + None => break, + }; + } +} + +macro_rules! impl_edge_case_input { + ($fty:ty) => { + impl EdgeCaseInput for ($fty,) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let (iter0, steps0) = float_edge_cases::(ctx, 0); + let iter0 = iter0.map(|v| (v,)); + (iter0, steps0) + } + } + + impl EdgeCaseInput for ($fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let (iter0, steps0) = float_edge_cases::(ctx, 0); + let (iter1, steps1) = float_edge_cases::(ctx, 1); + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + (iter, count) + } + } + + impl EdgeCaseInput for ($fty, $fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let (iter0, steps0) = float_edge_cases::(ctx, 0); + let (iter1, steps1) = float_edge_cases::(ctx, 1); + let (iter2, steps2) = float_edge_cases::(ctx, 2); + + let iter = iter0 + .flat_map(move |first| iter1.clone().map(move |second| (first, second))) + .flat_map(move |(first, second)| { + iter2.clone().map(move |third| (first, second, third)) + }); + let count = steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); + + (iter, count) + } + } + + impl EdgeCaseInput for (i32, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let (iter0, steps0) = int_edge_cases(ctx, 0); + let (iter1, steps1) = float_edge_cases::(ctx, 1); + + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + + (iter, count) + } + } + + impl EdgeCaseInput for ($fty, i32) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let (iter0, steps0) = float_edge_cases::(ctx, 0); + let (iter1, steps1) = int_edge_cases(ctx, 1); + + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + + (iter, count) + } + } + }; +} + +#[cfg(f16_enabled)] +impl_edge_case_input!(f16); +impl_edge_case_input!(f32); +impl_edge_case_input!(f64); +#[cfg(f128_enabled)] +impl_edge_case_input!(f128); + +pub fn get_test_cases( + ctx: &CheckCtx, +) -> (impl Iterator + Send + use<'_, Op>, u64) +where + Op: MathOp, + Op::RustArgs: EdgeCaseInput, +{ + let (iter, count) = Op::RustArgs::get_cases(ctx); + + // Wrap in `KnownSize` so we get an assertion if the cuunt is wrong. + (KnownSize::new(iter, count), count) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate/random.rs new file mode 100644 index 00000000000..e8a7ee9057e --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/generate/random.rs @@ -0,0 +1,125 @@ +use std::env; +use std::ops::RangeInclusive; +use std::sync::LazyLock; + +use libm::support::Float; +use rand::distr::{Alphanumeric, StandardUniform}; +use rand::prelude::Distribution; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; + +use super::KnownSize; +use crate::CheckCtx; +use crate::run_cfg::{int_range, iteration_count}; + +pub(crate) const SEED_ENV: &str = "LIBM_SEED"; + +pub static SEED: LazyLock<[u8; 32]> = LazyLock::new(|| { + let s = env::var(SEED_ENV).unwrap_or_else(|_| { + let mut rng = rand::rng(); + (0..32).map(|_| rng.sample(Alphanumeric) as char).collect() + }); + + s.as_bytes().try_into().unwrap_or_else(|_| { + panic!("Seed must be 32 characters, got `{s}`"); + }) +}); + +/// Generate a sequence of random values of this type. +pub trait RandomInput: Sized { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); +} + +/// Generate a sequence of deterministically random floats. +fn random_floats(count: u64) -> impl Iterator +where + StandardUniform: Distribution, +{ + let mut rng = ChaCha8Rng::from_seed(*SEED); + + // Generate integers to get a full range of bitpatterns (including NaNs), then convert back + // to the float type. + (0..count).map(move |_| F::from_bits(rng.random::())) +} + +/// Generate a sequence of deterministically random `i32`s within a specified range. +fn random_ints(count: u64, range: RangeInclusive) -> impl Iterator { + let mut rng = ChaCha8Rng::from_seed(*SEED); + (0..count).map(move |_| rng.random_range::(range.clone())) +} + +macro_rules! impl_random_input { + ($fty:ty) => { + impl RandomInput for ($fty,) { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let count = iteration_count(ctx, 0); + let iter = random_floats(count).map(|f: $fty| (f,)); + (iter, count) + } + } + + impl RandomInput for ($fty, $fty) { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let iter = random_floats(count0) + .flat_map(move |f1: $fty| random_floats(count1).map(move |f2: $fty| (f1, f2))); + (iter, count0 * count1) + } + } + + impl RandomInput for ($fty, $fty, $fty) { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let count2 = iteration_count(ctx, 2); + let iter = random_floats(count0).flat_map(move |f1: $fty| { + random_floats(count1).flat_map(move |f2: $fty| { + random_floats(count2).map(move |f3: $fty| (f1, f2, f3)) + }) + }); + (iter, count0 * count1 * count2) + } + } + + impl RandomInput for (i32, $fty) { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let range0 = int_range(ctx, 0); + let iter = random_ints(count0, range0) + .flat_map(move |f1: i32| random_floats(count1).map(move |f2: $fty| (f1, f2))); + (iter, count0 * count1) + } + } + + impl RandomInput for ($fty, i32) { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let range1 = int_range(ctx, 1); + let iter = random_floats(count0).flat_map(move |f1: $fty| { + random_ints(count1, range1.clone()).map(move |f2: i32| (f1, f2)) + }); + (iter, count0 * count1) + } + } + }; +} + +#[cfg(f16_enabled)] +impl_random_input!(f16); +impl_random_input!(f32); +impl_random_input!(f64); +#[cfg(f128_enabled)] +impl_random_input!(f128); + +/// Create a test case iterator. +pub fn get_test_cases( + ctx: &CheckCtx, +) -> (impl Iterator + Send + use<'_, RustArgs>, u64) { + let (iter, count) = RustArgs::get_cases(ctx); + + // Wrap in `KnownSize` so we get an assertion if the cuunt is wrong. + (KnownSize::new(iter, count), count) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate/spaced.rs new file mode 100644 index 00000000000..bea3f4c7e1b --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/generate/spaced.rs @@ -0,0 +1,253 @@ +use std::fmt; +use std::ops::RangeInclusive; + +use libm::support::{Float, MinInt}; + +use crate::domain::get_domain; +use crate::op::OpITy; +use crate::run_cfg::{int_range, iteration_count}; +use crate::{CheckCtx, MathOp, linear_ints, logspace}; + +/// Generate a sequence of inputs that eiher cover the domain in completeness (for smaller float +/// types and single argument functions) or provide evenly spaced inputs across the domain with +/// approximately `u32::MAX` total iterations. +pub trait SpacedInput { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); +} + +/// Construct an iterator from `logspace` and also calculate the total number of steps expected +/// for that iterator. +fn logspace_steps( + ctx: &CheckCtx, + argnum: usize, + max_steps: u64, +) -> (impl Iterator + Clone, u64) +where + Op: MathOp, + OpITy: TryFrom, + u64: TryFrom, Error: fmt::Debug>, + RangeInclusive>: Iterator, +{ + // i8 is a dummy type here, it can be any integer. + let domain = get_domain::(ctx.fn_ident, argnum).unwrap_float(); + let start = domain.range_start(); + let end = domain.range_end(); + + let max_steps = OpITy::::try_from(max_steps).unwrap_or(OpITy::::MAX); + let (iter, steps) = logspace(start, end, max_steps); + + // `steps` will be <= the original `max_steps`, which is a `u64`. + (iter, steps.try_into().unwrap()) +} + +/// Represents the iterator in either `Left` or `Right`. +enum EitherIter { + A(A), + B(B), +} + +impl, B: Iterator> Iterator for EitherIter { + type Item = T; + + fn next(&mut self) -> Option { + match self { + Self::A(iter) => iter.next(), + Self::B(iter) => iter.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self { + Self::A(iter) => iter.size_hint(), + Self::B(iter) => iter.size_hint(), + } + } +} + +/// Gets the total number of possible values, returning `None` if that number doesn't fit in a +/// `u64`. +fn value_count() -> Option +where + u64: TryFrom, +{ + u64::try_from(F::Int::MAX).ok().and_then(|max| max.checked_add(1)) +} + +/// Returns an iterator of every possible value of type `F`. +fn all_values() -> impl Iterator +where + RangeInclusive: Iterator, +{ + (F::Int::MIN..=F::Int::MAX).map(|bits| F::from_bits(bits)) +} + +macro_rules! impl_spaced_input { + ($fty:ty) => { + impl SpacedInput for ($fty,) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, 0); + // `f16` and `f32` can have exhaustive tests. + match value_count::() { + Some(steps0) if steps0 <= max_steps0 => { + let iter0 = all_values(); + let iter0 = iter0.map(|v| (v,)); + (EitherIter::A(iter0), steps0) + } + _ => { + let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); + let iter0 = iter0.map(|v| (v,)); + (EitherIter::B(iter0), steps0) + } + } + } + } + + impl SpacedInput for ($fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, 0); + let max_steps1 = iteration_count(ctx, 1); + // `f16` can have exhaustive tests. + match value_count::() { + Some(count) if count <= max_steps0 && count <= max_steps1 => { + let iter = all_values() + .flat_map(|first| all_values().map(move |second| (first, second))); + (EitherIter::A(iter), count.checked_mul(count).unwrap()) + } + _ => { + let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); + let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); + (EitherIter::B(iter), count) + } + } + } + } + + impl SpacedInput for ($fty, $fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, 0); + let max_steps1 = iteration_count(ctx, 1); + let max_steps2 = iteration_count(ctx, 2); + // `f16` can be exhaustive tested if `LIBM_EXTENSIVE_TESTS` is incresed. + match value_count::() { + Some(count) + if count <= max_steps0 && count <= max_steps1 && count <= max_steps2 => + { + let iter = all_values().flat_map(|first| { + all_values().flat_map(move |second| { + all_values().map(move |third| (first, second, third)) + }) + }); + (EitherIter::A(iter), count.checked_pow(3).unwrap()) + } + _ => { + let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); + let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); + let (iter2, steps2) = logspace_steps::(ctx, 2, max_steps2); + + let iter = iter0 + .flat_map(move |first| iter1.clone().map(move |second| (first, second))) + .flat_map(move |(first, second)| { + iter2.clone().map(move |third| (first, second, third)) + }); + let count = + steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); + + (EitherIter::B(iter), count) + } + } + } + } + + impl SpacedInput for (i32, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let range0 = int_range(ctx, 0); + let max_steps0 = iteration_count(ctx, 0); + let max_steps1 = iteration_count(ctx, 1); + match value_count::() { + Some(count1) if count1 <= max_steps1 => { + let (iter0, steps0) = linear_ints(range0, max_steps0); + let iter = iter0 + .flat_map(move |first| all_values().map(move |second| (first, second))); + (EitherIter::A(iter), steps0.checked_mul(count1).unwrap()) + } + _ => { + let (iter0, steps0) = linear_ints(range0, max_steps0); + let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); + + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); + + (EitherIter::B(iter), count) + } + } + } + } + + impl SpacedInput for ($fty, i32) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, 0); + let range1 = int_range(ctx, 1); + let max_steps1 = iteration_count(ctx, 1); + match value_count::() { + Some(count0) if count0 <= max_steps0 => { + let (iter1, steps1) = linear_ints(range1, max_steps1); + let iter = all_values().flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + (EitherIter::A(iter), count0.checked_mul(steps1).unwrap()) + } + _ => { + let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); + let (iter1, steps1) = linear_ints(range1, max_steps1); + + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); + + (EitherIter::B(iter), count) + } + } + } + } + }; +} + +#[cfg(f16_enabled)] +impl_spaced_input!(f16); +impl_spaced_input!(f32); +impl_spaced_input!(f64); +#[cfg(f128_enabled)] +impl_spaced_input!(f128); + +/// Create a test case iterator for extensive inputs. Also returns the total test case count. +pub fn get_test_cases( + ctx: &CheckCtx, +) -> (impl Iterator + Send + use<'_, Op>, u64) +where + Op: MathOp, + Op::RustArgs: SpacedInput, +{ + Op::RustArgs::get_cases(ctx) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 824f09a3387..485c01a4782 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -4,7 +4,7 @@ pub mod domain; mod f8_impl; -pub mod gen; +pub mod generate; #[cfg(feature = "build-mpfr")] pub mod mpfloat; mod num; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 8e4fff53cb2..b36164b005f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -4,7 +4,7 @@ use std::ops::RangeInclusive; use std::sync::LazyLock; use std::{env, str}; -use crate::gen::random::{SEED, SEED_ENV}; +use crate::generate::random::{SEED, SEED_ENV}; use crate::{BaseName, FloatTy, Identifier, test_log}; /// The environment variable indicating which extensive tests should be run. @@ -241,7 +241,7 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { // Some tests are significantly slower than others and need to be further reduced. if let Some((_id, _gen, scale)) = EXTEMELY_SLOW_TESTS .iter() - .find(|(id, gen, _scale)| *id == ctx.fn_ident && *gen == ctx.gen_kind) + .find(|(id, generator, _scale)| *id == ctx.fn_ident && *generator == ctx.gen_kind) { // However, do not override if the extensive iteration count has been manually set. if !(ctx.gen_kind == GeneratorKind::Extensive && EXTENSIVE_ITER_OVERRIDE.is_some()) { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 897dfc26e8c..cbb4bd49b9c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -9,7 +9,7 @@ // There are some targets we can't build musl for #![cfg(feature = "build-musl")] -use libm_test::gen::{case_list, edge_cases, random, spaced}; +use libm_test::generate::{case_list, edge_cases, random, spaced}; use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; const BASIS: CheckBasis = CheckBasis::Musl; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 0ab4b64da81..80b2c78688e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -2,7 +2,7 @@ #![cfg(feature = "build-mpfr")] -use libm_test::gen::{case_list, edge_cases, random, spaced}; +use libm_test::generate::{case_list, edge_cases, random, spaced}; use libm_test::mpfloat::MpOp; use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs b/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs index 7d694843e9c..7b30a3b48d7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs @@ -1,6 +1,6 @@ //! Test cases that have both an input and an output, so do not require a basis. -use libm_test::gen::case_list; +use libm_test::generate::case_list; use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; const BASIS: CheckBasis = CheckBasis::None; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs b/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs index 4603534248c..4444036d0a4 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs @@ -9,7 +9,7 @@ use libm::support::{HInt, u256}; type BigInt = rug::Integer; use libm_test::bigint_fuzz_iteration_count; -use libm_test::gen::random::SEED; +use libm_test::generate::random::SEED; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; use rug::Assign; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs index 786546a9d6d..b10c231d183 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs @@ -6,7 +6,7 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::time::Duration; use indicatif::{ProgressBar, ProgressStyle}; -use libm_test::gen::spaced; +use libm_test::generate::spaced; use libm_test::mpfloat::MpOp; use libm_test::{ CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TestResult, TupleCall, diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml index ad73578d8b8..9e866a9704f 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml +++ b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "musl-math-sys" version = "0.1.0" -edition = "2021" +edition = "2024" publish = false [dependencies] diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs index 07277ef3e6e..6a4bf4859d9 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs +++ b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs @@ -10,7 +10,7 @@ macro_rules! functions { $( #[$meta:meta] )* $pfx_name:ident: $name:ident( $($arg:ident: $aty:ty),+ ) -> $rty:ty; )* ) => { - extern "C" { + unsafe extern "C" { $( fn $pfx_name( $($arg: $aty),+ ) -> $rty; )* } diff --git a/library/compiler-builtins/libm/crates/util/Cargo.toml b/library/compiler-builtins/libm/crates/util/Cargo.toml index 94c7f103340..4bcb9747297 100644 --- a/library/compiler-builtins/libm/crates/util/Cargo.toml +++ b/library/compiler-builtins/libm/crates/util/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "util" version = "0.1.0" -edition = "2021" +edition = "2024" publish = false [features] diff --git a/library/compiler-builtins/libm/libm/src/lib.rs b/library/compiler-builtins/libm/libm/src/lib.rs index b0e4312110f..7e56bd0796c 100644 --- a/library/compiler-builtins/libm/libm/src/lib.rs +++ b/library/compiler-builtins/libm/libm/src/lib.rs @@ -17,6 +17,7 @@ #![allow(clippy::needless_return)] #![allow(clippy::unreadable_literal)] #![allow(clippy::zero_divided_by_zero)] +#![forbid(unsafe_op_in_unsafe_fn)] mod libm_helper; mod math; -- cgit 1.4.1-3-g733a5 From 92b1e8454d7c4ea424ff970e6be283144584f812 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Mar 2025 09:52:53 +0000 Subject: Rename `testcrate` to `builtins-test` The repo will soon have `libm` as a top-level crate, so make it clear that this is only the test crate for `compiler-builtins`. --- library/compiler-builtins/Cargo.toml | 8 +- library/compiler-builtins/builtins-test/Cargo.toml | 102 +++ .../builtins-test/benches/float_add.rs | 93 +++ .../builtins-test/benches/float_cmp.rs | 208 +++++++ .../builtins-test/benches/float_conv.rs | 688 +++++++++++++++++++++ .../builtins-test/benches/float_div.rs | 93 +++ .../builtins-test/benches/float_extend.rs | 133 ++++ .../builtins-test/benches/float_mul.rs | 93 +++ .../builtins-test/benches/float_pow.rs | 49 ++ .../builtins-test/benches/float_sub.rs | 93 +++ .../builtins-test/benches/float_trunc.rs | 146 +++++ .../compiler-builtins/builtins-test/benches/mem.rs | 364 +++++++++++ .../builtins-test/benches/mem_icount.rs | 499 +++++++++++++++ library/compiler-builtins/builtins-test/build.rs | 120 ++++ .../compiler-builtins/builtins-test/src/bench.rs | 366 +++++++++++ library/compiler-builtins/builtins-test/src/lib.rs | 338 ++++++++++ .../builtins-test/tests/addsub.rs | 143 +++++ .../builtins-test/tests/aeabi_memclr.rs | 60 ++ .../builtins-test/tests/aeabi_memcpy.rs | 71 +++ .../builtins-test/tests/aeabi_memset.rs | 240 +++++++ .../compiler-builtins/builtins-test/tests/big.rs | 134 ++++ .../compiler-builtins/builtins-test/tests/cmp.rs | 185 ++++++ .../compiler-builtins/builtins-test/tests/conv.rs | 364 +++++++++++ .../builtins-test/tests/div_rem.rs | 165 +++++ .../builtins-test/tests/float_pow.rs | 72 +++ .../compiler-builtins/builtins-test/tests/lse.rs | 97 +++ .../compiler-builtins/builtins-test/tests/mem.rs | 286 +++++++++ .../compiler-builtins/builtins-test/tests/misc.rs | 208 +++++++ .../compiler-builtins/builtins-test/tests/mul.rs | 156 +++++ .../compiler-builtins/builtins-test/tests/shift.rs | 35 ++ library/compiler-builtins/ci/miri.sh | 2 +- library/compiler-builtins/ci/run.sh | 6 +- .../compiler-builtins/compiler-builtins/Cargo.toml | 2 +- .../compiler-builtins/configure.rs | 2 +- .../compiler-builtins/src/int/traits.rs | 4 +- library/compiler-builtins/testcrate/Cargo.toml | 101 --- .../testcrate/benches/float_add.rs | 93 --- .../testcrate/benches/float_cmp.rs | 208 ------- .../testcrate/benches/float_conv.rs | 688 --------------------- .../testcrate/benches/float_div.rs | 93 --- .../testcrate/benches/float_extend.rs | 133 ---- .../testcrate/benches/float_mul.rs | 93 --- .../testcrate/benches/float_pow.rs | 49 -- .../testcrate/benches/float_sub.rs | 93 --- .../testcrate/benches/float_trunc.rs | 146 ----- library/compiler-builtins/testcrate/benches/mem.rs | 364 ----------- .../testcrate/benches/mem_icount.rs | 499 --------------- library/compiler-builtins/testcrate/build.rs | 120 ---- library/compiler-builtins/testcrate/src/bench.rs | 366 ----------- library/compiler-builtins/testcrate/src/lib.rs | 338 ---------- .../compiler-builtins/testcrate/tests/addsub.rs | 143 ----- .../testcrate/tests/aeabi_memclr.rs | 60 -- .../testcrate/tests/aeabi_memcpy.rs | 71 --- .../testcrate/tests/aeabi_memset.rs | 240 ------- library/compiler-builtins/testcrate/tests/big.rs | 134 ---- library/compiler-builtins/testcrate/tests/cmp.rs | 185 ------ library/compiler-builtins/testcrate/tests/conv.rs | 364 ----------- .../compiler-builtins/testcrate/tests/div_rem.rs | 165 ----- .../compiler-builtins/testcrate/tests/float_pow.rs | 72 --- library/compiler-builtins/testcrate/tests/lse.rs | 97 --- library/compiler-builtins/testcrate/tests/mem.rs | 286 --------- library/compiler-builtins/testcrate/tests/misc.rs | 208 ------- library/compiler-builtins/testcrate/tests/mul.rs | 156 ----- library/compiler-builtins/testcrate/tests/shift.rs | 35 -- 64 files changed, 5613 insertions(+), 5612 deletions(-) create mode 100644 library/compiler-builtins/builtins-test/Cargo.toml create mode 100644 library/compiler-builtins/builtins-test/benches/float_add.rs create mode 100644 library/compiler-builtins/builtins-test/benches/float_cmp.rs create mode 100644 library/compiler-builtins/builtins-test/benches/float_conv.rs create mode 100644 library/compiler-builtins/builtins-test/benches/float_div.rs create mode 100644 library/compiler-builtins/builtins-test/benches/float_extend.rs create mode 100644 library/compiler-builtins/builtins-test/benches/float_mul.rs create mode 100644 library/compiler-builtins/builtins-test/benches/float_pow.rs create mode 100644 library/compiler-builtins/builtins-test/benches/float_sub.rs create mode 100644 library/compiler-builtins/builtins-test/benches/float_trunc.rs create mode 100644 library/compiler-builtins/builtins-test/benches/mem.rs create mode 100644 library/compiler-builtins/builtins-test/benches/mem_icount.rs create mode 100644 library/compiler-builtins/builtins-test/build.rs create mode 100644 library/compiler-builtins/builtins-test/src/bench.rs create mode 100644 library/compiler-builtins/builtins-test/src/lib.rs create mode 100644 library/compiler-builtins/builtins-test/tests/addsub.rs create mode 100644 library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs create mode 100644 library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs create mode 100644 library/compiler-builtins/builtins-test/tests/aeabi_memset.rs create mode 100644 library/compiler-builtins/builtins-test/tests/big.rs create mode 100644 library/compiler-builtins/builtins-test/tests/cmp.rs create mode 100644 library/compiler-builtins/builtins-test/tests/conv.rs create mode 100644 library/compiler-builtins/builtins-test/tests/div_rem.rs create mode 100644 library/compiler-builtins/builtins-test/tests/float_pow.rs create mode 100644 library/compiler-builtins/builtins-test/tests/lse.rs create mode 100644 library/compiler-builtins/builtins-test/tests/mem.rs create mode 100644 library/compiler-builtins/builtins-test/tests/misc.rs create mode 100644 library/compiler-builtins/builtins-test/tests/mul.rs create mode 100644 library/compiler-builtins/builtins-test/tests/shift.rs delete mode 100644 library/compiler-builtins/testcrate/Cargo.toml delete mode 100644 library/compiler-builtins/testcrate/benches/float_add.rs delete mode 100644 library/compiler-builtins/testcrate/benches/float_cmp.rs delete mode 100644 library/compiler-builtins/testcrate/benches/float_conv.rs delete mode 100644 library/compiler-builtins/testcrate/benches/float_div.rs delete mode 100644 library/compiler-builtins/testcrate/benches/float_extend.rs delete mode 100644 library/compiler-builtins/testcrate/benches/float_mul.rs delete mode 100644 library/compiler-builtins/testcrate/benches/float_pow.rs delete mode 100644 library/compiler-builtins/testcrate/benches/float_sub.rs delete mode 100644 library/compiler-builtins/testcrate/benches/float_trunc.rs delete mode 100644 library/compiler-builtins/testcrate/benches/mem.rs delete mode 100644 library/compiler-builtins/testcrate/benches/mem_icount.rs delete mode 100644 library/compiler-builtins/testcrate/build.rs delete mode 100644 library/compiler-builtins/testcrate/src/bench.rs delete mode 100644 library/compiler-builtins/testcrate/src/lib.rs delete mode 100644 library/compiler-builtins/testcrate/tests/addsub.rs delete mode 100644 library/compiler-builtins/testcrate/tests/aeabi_memclr.rs delete mode 100644 library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs delete mode 100644 library/compiler-builtins/testcrate/tests/aeabi_memset.rs delete mode 100644 library/compiler-builtins/testcrate/tests/big.rs delete mode 100644 library/compiler-builtins/testcrate/tests/cmp.rs delete mode 100644 library/compiler-builtins/testcrate/tests/conv.rs delete mode 100644 library/compiler-builtins/testcrate/tests/div_rem.rs delete mode 100644 library/compiler-builtins/testcrate/tests/float_pow.rs delete mode 100644 library/compiler-builtins/testcrate/tests/lse.rs delete mode 100644 library/compiler-builtins/testcrate/tests/mem.rs delete mode 100644 library/compiler-builtins/testcrate/tests/misc.rs delete mode 100644 library/compiler-builtins/testcrate/tests/mul.rs delete mode 100644 library/compiler-builtins/testcrate/tests/shift.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index db4c45dfa4b..2e17c303a5f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -2,16 +2,16 @@ resolver = "3" members = [ # Note that builtins-test-intrinsics cannot be a default member because it - # needs the `mangled-names` feature disabled, while `testcrate` needs it - # enabled. + # needs the `mangled-names` feature disabled, while `builtins-test` needs + # it enabled. + "builtins-test", "builtins-test-intrinsics", "compiler-builtins", - "testcrate", ] default-members = [ "compiler-builtins", - "testcrate", + "builtins-test", ] [profile.release] diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml new file mode 100644 index 00000000000..526e9b18af0 --- /dev/null +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -0,0 +1,102 @@ +[package] +name = "builtins-test" +version = "0.1.0" +authors = ["Alex Crichton "] +edition = "2024" +publish = false + +[lib] +test = false +doctest = false + +[dependencies] +# For fuzzing tests we want a deterministic seedable RNG. We also eliminate potential +# problems with system RNGs on the variety of platforms this crate is tested on. +# `xoshiro128**` is used for its quality, size, and speed at generating `u32` shift amounts. +rand_xoshiro = "0.6" +# To compare float builtins against +rustc_apfloat = "0.2.1" +# Really a dev dependency, but dev dependencies can't be optional +iai-callgrind = { version = "0.14.0", optional = true } + +[dependencies.compiler_builtins] +path = "../compiler-builtins" +default-features = false +features = ["public-test-deps"] + +[dev-dependencies] +criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } +paste = "1.0.15" + +[target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] +test = { git = "https://github.com/japaric/utest" } +utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japaric/utest" } +utest-macros = { git = "https://github.com/japaric/utest" } + +[features] +default = ["mangled-names"] +c = ["compiler_builtins/c"] +no-asm = ["compiler_builtins/no-asm"] +no-f16-f128 = ["compiler_builtins/no-f16-f128"] +mem = ["compiler_builtins/mem"] +mangled-names = ["compiler_builtins/mangled-names"] +# Skip tests that rely on f128 symbols being available on the system +no-sys-f128 = ["no-sys-f128-int-convert", "no-sys-f16-f128-convert"] +# Some platforms have some f128 functions but everything except integer conversions +no-sys-f128-int-convert = [] +no-sys-f16-f128-convert = [] +no-sys-f16-f64-convert = [] +# Skip tests that rely on f16 symbols being available on the system +no-sys-f16 = ["no-sys-f16-f64-convert"] + +# Enable icount benchmarks (requires iai-callgrind and valgrind) +icount = ["dep:iai-callgrind"] + +# Enable report generation without bringing in more dependencies by default +benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] + +# NOTE: benchmarks must be run with `--no-default-features` or with +# `-p builtins-test`, otherwise the default `compiler-builtins` feature +# of the `compiler_builtins` crate gets activated, resulting in linker +# errors. + +[[bench]] +name = "float_add" +harness = false + +[[bench]] +name = "float_sub" +harness = false + +[[bench]] +name = "float_mul" +harness = false + +[[bench]] +name = "float_div" +harness = false + +[[bench]] +name = "float_cmp" +harness = false + +[[bench]] +name = "float_conv" +harness = false + +[[bench]] +name = "float_extend" +harness = false + +[[bench]] +name = "float_trunc" +harness = false + +[[bench]] +name = "float_pow" +harness = false + +[[bench]] +name = "mem_icount" +harness = false +required-features = ["icount"] diff --git a/library/compiler-builtins/builtins-test/benches/float_add.rs b/library/compiler-builtins/builtins-test/benches/float_add.rs new file mode 100644 index 00000000000..197f90b319d --- /dev/null +++ b/library/compiler-builtins/builtins-test/benches/float_add.rs @@ -0,0 +1,93 @@ +#![cfg_attr(f128_enabled, feature(f128))] + +use builtins_test::float_bench; +use compiler_builtins::float::add; +use criterion::{Criterion, criterion_main}; + +float_bench! { + name: add_f32, + sig: (a: f32, b: f32) -> f32, + crate_fn: add::__addsf3, + sys_fn: __addsf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "addss {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fadd {a:s}, {a:s}, {b:s}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: add_f64, + sig: (a: f64, b: f64) -> f64, + crate_fn: add::__adddf3, + sys_fn: __adddf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "addsd {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fadd {a:d}, {a:d}, {b:d}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +#[cfg(f128_enabled)] +float_bench! { + name: add_f128, + sig: (a: f128, b: f128) -> f128, + crate_fn: add::__addtf3, + crate_fn_ppc: add::__addkf3, + sys_fn: __addtf3, + sys_fn_ppc: __addkf3, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +pub fn float_add() { + let mut criterion = Criterion::default().configure_from_args(); + + add_f32(&mut criterion); + add_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + add_f128(&mut criterion); + } +} + +criterion_main!(float_add); diff --git a/library/compiler-builtins/builtins-test/benches/float_cmp.rs b/library/compiler-builtins/builtins-test/benches/float_cmp.rs new file mode 100644 index 00000000000..4493765ec1b --- /dev/null +++ b/library/compiler-builtins/builtins-test/benches/float_cmp.rs @@ -0,0 +1,208 @@ +#![cfg_attr(f128_enabled, feature(f128))] + +use builtins_test::float_bench; +use criterion::{Criterion, criterion_main}; + +use compiler_builtins::float::cmp; + +/// `gt` symbols are allowed to return differing results, they just get compared +/// to 0. +fn gt_res_eq(a: i32, b: i32) -> bool { + let a_lt_0 = a <= 0; + let b_lt_0 = b <= 0; + (a_lt_0 && b_lt_0) || (!a_lt_0 && !b_lt_0) +} + +float_bench! { + name: cmp_f32_gt, + sig: (a: f32, b: f32) -> i32, + crate_fn: cmp::__gtsf2, + sys_fn: __gtsf2, + sys_available: all(), + output_eq: gt_res_eq, + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: i32; + asm!( + "xor {ret:e}, {ret:e}", + "ucomiss {a}, {b}", + "seta {ret:l}", + a = in(xmm_reg) a, + b = in(xmm_reg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcmp {a:s}, {b:s}", + "cset {ret:w}, gt", + a = in(vreg) a, + b = in(vreg) b, + ret = out(reg) ret, + options(nomem,nostack), + ); + + ret + }; + ], +} + +float_bench! { + name: cmp_f32_unord, + sig: (a: f32, b: f32) -> i32, + crate_fn: cmp::__unordsf2, + sys_fn: __unordsf2, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: i32; + asm!( + "xor {ret:e}, {ret:e}", + "ucomiss {a}, {b}", + "setp {ret:l}", + a = in(xmm_reg) a, + b = in(xmm_reg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcmp {a:s}, {b:s}", + "cset {ret:w}, vs", + a = in(vreg) a, + b = in(vreg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + ], +} + +float_bench! { + name: cmp_f64_gt, + sig: (a: f64, b: f64) -> i32, + crate_fn: cmp::__gtdf2, + sys_fn: __gtdf2, + sys_available: all(), + output_eq: gt_res_eq, + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: i32; + asm!( + "xor {ret:e}, {ret:e}", + "ucomisd {a}, {b}", + "seta {ret:l}", + a = in(xmm_reg) a, + b = in(xmm_reg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcmp {a:d}, {b:d}", + "cset {ret:w}, gt", + a = in(vreg) a, + b = in(vreg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + ], +} + +float_bench! { + name: cmp_f64_unord, + sig: (a: f64, b: f64) -> i32, + crate_fn: cmp::__unorddf2, + sys_fn: __unorddf2, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: i32; + asm!( + "xor {ret:e}, {ret:e}", + "ucomisd {a}, {b}", + "setp {ret:l}", + a = in(xmm_reg) a, + b = in(xmm_reg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcmp {a:d}, {b:d}", + "cset {ret:w}, vs", + a = in(vreg) a, + b = in(vreg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + ], +} + +float_bench! { + name: cmp_f128_gt, + sig: (a: f128, b: f128) -> i32, + crate_fn: cmp::__gttf2, + crate_fn_ppc: cmp::__gtkf2, + sys_fn: __gttf2, + sys_fn_ppc: __gtkf2, + sys_available: not(feature = "no-sys-f128"), + output_eq: gt_res_eq, + asm: [] +} + +float_bench! { + name: cmp_f128_unord, + sig: (a: f128, b: f128) -> i32, + crate_fn: cmp::__unordtf2, + crate_fn_ppc: cmp::__unordkf2, + sys_fn: __unordtf2, + sys_fn_ppc: __unordkf2, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +pub fn float_cmp() { + let mut criterion = Criterion::default().configure_from_args(); + + cmp_f32_gt(&mut criterion); + cmp_f32_unord(&mut criterion); + cmp_f64_gt(&mut criterion); + cmp_f64_unord(&mut criterion); + + #[cfg(f128_enabled)] + { + cmp_f128_gt(&mut criterion); + cmp_f128_unord(&mut criterion); + } +} + +criterion_main!(float_cmp); diff --git a/library/compiler-builtins/builtins-test/benches/float_conv.rs b/library/compiler-builtins/builtins-test/benches/float_conv.rs new file mode 100644 index 00000000000..d4a7346d1d5 --- /dev/null +++ b/library/compiler-builtins/builtins-test/benches/float_conv.rs @@ -0,0 +1,688 @@ +#![allow(improper_ctypes)] +#![cfg_attr(f128_enabled, feature(f128))] + +use builtins_test::float_bench; +use compiler_builtins::float::conv; +use criterion::{Criterion, criterion_main}; + +/* unsigned int -> float */ + +float_bench! { + name: conv_u32_f32, + sig: (a: u32) -> f32, + crate_fn: conv::__floatunsisf, + sys_fn: __floatunsisf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f32; + asm!( + "mov {tmp:e}, {a:e}", + "cvtsi2ss {ret}, {tmp}", + a = in(reg) a, + tmp = out(reg) _, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "ucvtf {ret:s}, {a:w}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_u32_f64, + sig: (a: u32) -> f64, + crate_fn: conv::__floatunsidf, + sys_fn: __floatunsidf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f64; + asm!( + "mov {tmp:e}, {a:e}", + "cvtsi2sd {ret}, {tmp}", + a = in(reg) a, + tmp = out(reg) _, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "ucvtf {ret:d}, {a:w}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_u32_f128, + sig: (a: u32) -> f128, + crate_fn: conv::__floatunsitf, + crate_fn_ppc: conv::__floatunsikf, + sys_fn: __floatunsitf, + sys_fn_ppc: __floatunsikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +float_bench! { + name: conv_u64_f32, + sig: (a: u64) -> f32, + crate_fn: conv::__floatundisf, + sys_fn: __floatundisf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "ucvtf {ret:s}, {a:x}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_u64_f64, + sig: (a: u64) -> f64, + crate_fn: conv::__floatundidf, + sys_fn: __floatundidf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "ucvtf {ret:d}, {a:x}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_u64_f128, + sig: (a: u64) -> f128, + crate_fn: conv::__floatunditf, + crate_fn_ppc: conv::__floatundikf, + sys_fn: __floatunditf, + sys_fn_ppc: __floatundikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +float_bench! { + name: conv_u128_f32, + sig: (a: u128) -> f32, + crate_fn: conv::__floatuntisf, + sys_fn: __floatuntisf, + sys_available: all(), + asm: [] +} + +float_bench! { + name: conv_u128_f64, + sig: (a: u128) -> f64, + crate_fn: conv::__floatuntidf, + sys_fn: __floatuntidf, + sys_available: all(), + asm: [] +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_u128_f128, + sig: (a: u128) -> f128, + crate_fn: conv::__floatuntitf, + crate_fn_ppc: conv::__floatuntikf, + sys_fn: __floatuntitf, + sys_fn_ppc: __floatuntikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +/* signed int -> float */ + +float_bench! { + name: conv_i32_f32, + sig: (a: i32) -> f32, + crate_fn: conv::__floatsisf, + sys_fn: __floatsisf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f32; + asm!( + "cvtsi2ss {ret}, {a:e}", + a = in(reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "scvtf {ret:s}, {a:w}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_i32_f64, + sig: (a: i32) -> f64, + crate_fn: conv::__floatsidf, + sys_fn: __floatsidf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f64; + asm!( + "cvtsi2sd {ret}, {a:e}", + a = in(reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "scvtf {ret:d}, {a:w}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_i32_f128, + sig: (a: i32) -> f128, + crate_fn: conv::__floatsitf, + crate_fn_ppc: conv::__floatsikf, + sys_fn: __floatsitf, + sys_fn_ppc: __floatsikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +float_bench! { + name: conv_i64_f32, + sig: (a: i64) -> f32, + crate_fn: conv::__floatdisf, + sys_fn: __floatdisf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f32; + asm!( + "cvtsi2ss {ret}, {a:r}", + a = in(reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "scvtf {ret:s}, {a:x}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_i64_f64, + sig: (a: i64) -> f64, + crate_fn: conv::__floatdidf, + sys_fn: __floatdidf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f64; + asm!( + "cvtsi2sd {ret}, {a:r}", + a = in(reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "scvtf {ret:d}, {a:x}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_i64_f128, + sig: (a: i64) -> f128, + crate_fn: conv::__floatditf, + crate_fn_ppc: conv::__floatdikf, + sys_fn: __floatditf, + sys_fn_ppc: __floatdikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +float_bench! { + name: conv_i128_f32, + sig: (a: i128) -> f32, + crate_fn: conv::__floattisf, + sys_fn: __floattisf, + sys_available: all(), + asm: [] +} + +float_bench! { + name: conv_i128_f64, + sig: (a: i128) -> f64, + crate_fn: conv::__floattidf, + sys_fn: __floattidf, + sys_available: all(), + asm: [] +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_i128_f128, + sig: (a: i128) -> f128, + crate_fn: conv::__floattitf, + crate_fn_ppc: conv::__floattikf, + sys_fn: __floattitf, + sys_fn_ppc: __floattikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +/* float -> unsigned int */ + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_u32, + sig: (a: f32) -> u32, + crate_fn: conv::__fixunssfsi, + sys_fn: __fixunssfsi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: u32; + asm!( + "fcvtzu {ret:w}, {a:s}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_u64, + sig: (a: f32) -> u64, + crate_fn: conv::__fixunssfdi, + sys_fn: __fixunssfdi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: u64; + asm!( + "fcvtzu {ret:x}, {a:s}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_u128, + sig: (a: f32) -> u128, + crate_fn: conv::__fixunssfti, + sys_fn: __fixunssfti, + sys_available: all(), + asm: [] +} + +float_bench! { + name: conv_f64_u32, + sig: (a: f64) -> u32, + crate_fn: conv::__fixunsdfsi, + sys_fn: __fixunsdfsi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: u32; + asm!( + "fcvtzu {ret:w}, {a:d}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_f64_u64, + sig: (a: f64) -> u64, + crate_fn: conv::__fixunsdfdi, + sys_fn: __fixunsdfdi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: u64; + asm!( + "fcvtzu {ret:x}, {a:d}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_f64_u128, + sig: (a: f64) -> u128, + crate_fn: conv::__fixunsdfti, + sys_fn: __fixunsdfti, + sys_available: all(), + asm: [] +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_u32, + sig: (a: f128) -> u32, + crate_fn: conv::__fixunstfsi, + crate_fn_ppc: conv::__fixunskfsi, + sys_fn: __fixunstfsi, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_u64, + sig: (a: f128) -> u64, + crate_fn: conv::__fixunstfdi, + crate_fn_ppc: conv::__fixunskfdi, + sys_fn: __fixunstfdi, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_u128, + sig: (a: f128) -> u128, + crate_fn: conv::__fixunstfti, + crate_fn_ppc: conv::__fixunskfti, + sys_fn: __fixunstfti, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +/* float -> signed int */ + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_i32, + sig: (a: f32) -> i32, + crate_fn: conv::__fixsfsi, + sys_fn: __fixsfsi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcvtzs {ret:w}, {a:s}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_i64, + sig: (a: f32) -> i64, + crate_fn: conv::__fixsfdi, + sys_fn: __fixsfdi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: i64; + asm!( + "fcvtzs {ret:x}, {a:s}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_i128, + sig: (a: f32) -> i128, + crate_fn: conv::__fixsfti, + sys_fn: __fixsfti, + sys_available: all(), + asm: [] +} + +float_bench! { + name: conv_f64_i32, + sig: (a: f64) -> i32, + crate_fn: conv::__fixdfsi, + sys_fn: __fixdfsi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcvtzs {ret:w}, {a:d}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_f64_i64, + sig: (a: f64) -> i64, + crate_fn: conv::__fixdfdi, + sys_fn: __fixdfdi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: i64; + asm!( + "fcvtzs {ret:x}, {a:d}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_f64_i128, + sig: (a: f64) -> i128, + crate_fn: conv::__fixdfti, + sys_fn: __fixdfti, + sys_available: all(), + asm: [] +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_i32, + sig: (a: f128) -> i32, + crate_fn: conv::__fixtfsi, + crate_fn_ppc: conv::__fixkfsi, + sys_fn: __fixtfsi, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_i64, + sig: (a: f128) -> i64, + crate_fn: conv::__fixtfdi, + crate_fn_ppc: conv::__fixkfdi, + sys_fn: __fixtfdi, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_i128, + sig: (a: f128) -> i128, + crate_fn: conv::__fixtfti, + crate_fn_ppc: conv::__fixkfti, + sys_fn: __fixtfti, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +pub fn float_conv() { + let mut criterion = Criterion::default().configure_from_args(); + + conv_u32_f32(&mut criterion); + conv_u32_f64(&mut criterion); + conv_u64_f32(&mut criterion); + conv_u64_f64(&mut criterion); + conv_u128_f32(&mut criterion); + conv_u128_f64(&mut criterion); + conv_i32_f32(&mut criterion); + conv_i32_f64(&mut criterion); + conv_i64_f32(&mut criterion); + conv_i64_f64(&mut criterion); + conv_i128_f32(&mut criterion); + conv_i128_f64(&mut criterion); + conv_f64_u32(&mut criterion); + conv_f64_u64(&mut criterion); + conv_f64_u128(&mut criterion); + conv_f64_i32(&mut criterion); + conv_f64_i64(&mut criterion); + conv_f64_i128(&mut criterion); + + #[cfg(f128_enabled)] + // FIXME: ppc64le has a sporadic overflow panic in the crate functions + // + #[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] + { + conv_u32_f128(&mut criterion); + conv_u64_f128(&mut criterion); + conv_u128_f128(&mut criterion); + conv_i32_f128(&mut criterion); + conv_i64_f128(&mut criterion); + conv_i128_f128(&mut criterion); + conv_f128_u32(&mut criterion); + conv_f128_u64(&mut criterion); + conv_f128_u128(&mut criterion); + conv_f128_i32(&mut criterion); + conv_f128_i64(&mut criterion); + conv_f128_i128(&mut criterion); + } +} + +criterion_main!(float_conv); diff --git a/library/compiler-builtins/builtins-test/benches/float_div.rs b/library/compiler-builtins/builtins-test/benches/float_div.rs new file mode 100644 index 00000000000..d5b0ad0fd40 --- /dev/null +++ b/library/compiler-builtins/builtins-test/benches/float_div.rs @@ -0,0 +1,93 @@ +#![cfg_attr(f128_enabled, feature(f128))] + +use builtins_test::float_bench; +use compiler_builtins::float::div; +use criterion::{Criterion, criterion_main}; + +float_bench! { + name: div_f32, + sig: (a: f32, b: f32) -> f32, + crate_fn: div::__divsf3, + sys_fn: __divsf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "divss {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fdiv {a:s}, {a:s}, {b:s}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: div_f64, + sig: (a: f64, b: f64) -> f64, + crate_fn: div::__divdf3, + sys_fn: __divdf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "divsd {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fdiv {a:d}, {a:d}, {b:d}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +#[cfg(f128_enabled)] +float_bench! { + name: div_f128, + sig: (a: f128, b: f128) -> f128, + crate_fn: div::__divtf3, + crate_fn_ppc: div::__divkf3, + sys_fn: __divtf3, + sys_fn_ppc: __divkf3, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +pub fn float_div() { + let mut criterion = Criterion::default().configure_from_args(); + + div_f32(&mut criterion); + div_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + div_f128(&mut criterion); + } +} + +criterion_main!(float_div); diff --git a/library/compiler-builtins/builtins-test/benches/float_extend.rs b/library/compiler-builtins/builtins-test/benches/float_extend.rs new file mode 100644 index 00000000000..fc44e80c9e1 --- /dev/null +++ b/library/compiler-builtins/builtins-test/benches/float_extend.rs @@ -0,0 +1,133 @@ +#![allow(unused_variables)] // "unused" f16 registers +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] + +use builtins_test::float_bench; +use compiler_builtins::float::extend; +use criterion::{Criterion, criterion_main}; + +#[cfg(f16_enabled)] +float_bench! { + name: extend_f16_f32, + sig: (a: f16) -> f32, + crate_fn: extend::__extendhfsf2, + sys_fn: __extendhfsf2, + sys_available: not(feature = "no-sys-f16"), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "fcvt {ret:s}, {a:h}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(f16_enabled)] +float_bench! { + name: extend_f16_f64, + sig: (a: f16) -> f64, + crate_fn: extend::__extendhfdf2, + sys_fn: __extendhfdf2, + sys_available: not(feature = "no-sys-f16-f64-convert"), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "fcvt {ret:d}, {a:h}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(all(f16_enabled, f128_enabled))] +float_bench! { + name: extend_f16_f128, + sig: (a: f16) -> f128, + crate_fn: extend::__extendhftf2, + crate_fn_ppc: extend::__extendhfkf2, + sys_fn: __extendhftf2, + sys_fn_ppc: __extendhfkf2, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [], +} + +float_bench! { + name: extend_f32_f64, + sig: (a: f32) -> f64, + crate_fn: extend::__extendsfdf2, + sys_fn: __extendsfdf2, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "fcvt {ret:d}, {a:s}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(f128_enabled)] +float_bench! { + name: extend_f32_f128, + sig: (a: f32) -> f128, + crate_fn: extend::__extendsftf2, + crate_fn_ppc: extend::__extendsfkf2, + sys_fn: __extendsftf2, + sys_fn_ppc: __extendsfkf2, + sys_available: not(feature = "no-sys-f128"), + asm: [], +} + +#[cfg(f128_enabled)] +float_bench! { + name: extend_f64_f128, + sig: (a: f64) -> f128, + crate_fn: extend::__extenddftf2, + crate_fn_ppc: extend::__extenddfkf2, + sys_fn: __extenddftf2, + sys_fn_ppc: __extenddfkf2, + sys_available: not(feature = "no-sys-f128"), + asm: [], +} + +pub fn float_extend() { + let mut criterion = Criterion::default().configure_from_args(); + + // FIXME(#655): `f16` tests disabled until we can bootstrap symbols + #[cfg(f16_enabled)] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + { + extend_f16_f32(&mut criterion); + extend_f16_f64(&mut criterion); + + #[cfg(f128_enabled)] + extend_f16_f128(&mut criterion); + } + + extend_f32_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + extend_f32_f128(&mut criterion); + extend_f64_f128(&mut criterion); + } +} + +criterion_main!(float_extend); diff --git a/library/compiler-builtins/builtins-test/benches/float_mul.rs b/library/compiler-builtins/builtins-test/benches/float_mul.rs new file mode 100644 index 00000000000..a7a2d34aa04 --- /dev/null +++ b/library/compiler-builtins/builtins-test/benches/float_mul.rs @@ -0,0 +1,93 @@ +#![cfg_attr(f128_enabled, feature(f128))] + +use builtins_test::float_bench; +use compiler_builtins::float::mul; +use criterion::{Criterion, criterion_main}; + +float_bench! { + name: mul_f32, + sig: (a: f32, b: f32) -> f32, + crate_fn: mul::__mulsf3, + sys_fn: __mulsf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "mulss {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fmul {a:s}, {a:s}, {b:s}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: mul_f64, + sig: (a: f64, b: f64) -> f64, + crate_fn: mul::__muldf3, + sys_fn: __muldf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "mulsd {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fmul {a:d}, {a:d}, {b:d}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +#[cfg(f128_enabled)] +float_bench! { + name: mul_f128, + sig: (a: f128, b: f128) -> f128, + crate_fn: mul::__multf3, + crate_fn_ppc: mul::__mulkf3, + sys_fn: __multf3, + sys_fn_ppc: __mulkf3, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +pub fn float_mul() { + let mut criterion = Criterion::default().configure_from_args(); + + mul_f32(&mut criterion); + mul_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + mul_f128(&mut criterion); + } +} + +criterion_main!(float_mul); diff --git a/library/compiler-builtins/builtins-test/benches/float_pow.rs b/library/compiler-builtins/builtins-test/benches/float_pow.rs new file mode 100644 index 00000000000..64e37dd3241 --- /dev/null +++ b/library/compiler-builtins/builtins-test/benches/float_pow.rs @@ -0,0 +1,49 @@ +#![cfg_attr(f128_enabled, feature(f128))] + +use builtins_test::float_bench; +use compiler_builtins::float::pow; +use criterion::{Criterion, criterion_main}; + +float_bench! { + name: powi_f32, + sig: (a: f32, b: i32) -> f32, + crate_fn: pow::__powisf2, + sys_fn: __powisf2, + sys_available: all(), + asm: [], +} + +float_bench! { + name: powi_f64, + sig: (a: f64, b: i32) -> f64, + crate_fn: pow::__powidf2, + sys_fn: __powidf2, + sys_available: all(), + asm: [], +} + +// FIXME(f16_f128): can be changed to only `f128_enabled` once `__multf3` and `__divtf3` are +// distributed by nightly. +#[cfg(all(f128_enabled, not(feature = "no-sys-f128")))] +float_bench! { + name: powi_f128, + sig: (a: f128, b: i32) -> f128, + crate_fn: pow::__powitf2, + crate_fn_ppc: pow::__powikf2, + sys_fn: __powitf2, + sys_fn_ppc: __powikf2, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +pub fn float_pow() { + let mut criterion = Criterion::default().configure_from_args(); + + powi_f32(&mut criterion); + powi_f64(&mut criterion); + + #[cfg(all(f128_enabled, not(feature = "no-sys-f128")))] + powi_f128(&mut criterion); +} + +criterion_main!(float_pow); diff --git a/library/compiler-builtins/builtins-test/benches/float_sub.rs b/library/compiler-builtins/builtins-test/benches/float_sub.rs new file mode 100644 index 00000000000..8bae294cd56 --- /dev/null +++ b/library/compiler-builtins/builtins-test/benches/float_sub.rs @@ -0,0 +1,93 @@ +#![cfg_attr(f128_enabled, feature(f128))] + +use builtins_test::float_bench; +use compiler_builtins::float::sub; +use criterion::{Criterion, criterion_main}; + +float_bench! { + name: sub_f32, + sig: (a: f32, b: f32) -> f32, + crate_fn: sub::__subsf3, + sys_fn: __subsf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "subss {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fsub {a:s}, {a:s}, {b:s}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: sub_f64, + sig: (a: f64, b: f64) -> f64, + crate_fn: sub::__subdf3, + sys_fn: __subdf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "subsd {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fsub {a:d}, {a:d}, {b:d}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +#[cfg(f128_enabled)] +float_bench! { + name: sub_f128, + sig: (a: f128, b: f128) -> f128, + crate_fn: sub::__subtf3, + crate_fn_ppc: sub::__subkf3, + sys_fn: __subtf3, + sys_fn_ppc: __subkf3, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +pub fn float_sub() { + let mut criterion = Criterion::default().configure_from_args(); + + sub_f32(&mut criterion); + sub_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + sub_f128(&mut criterion); + } +} + +criterion_main!(float_sub); diff --git a/library/compiler-builtins/builtins-test/benches/float_trunc.rs b/library/compiler-builtins/builtins-test/benches/float_trunc.rs new file mode 100644 index 00000000000..43310c7cfc8 --- /dev/null +++ b/library/compiler-builtins/builtins-test/benches/float_trunc.rs @@ -0,0 +1,146 @@ +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] + +use builtins_test::float_bench; +use compiler_builtins::float::trunc; +use criterion::{Criterion, criterion_main}; + +#[cfg(f16_enabled)] +float_bench! { + name: trunc_f32_f16, + sig: (a: f32) -> f16, + crate_fn: trunc::__truncsfhf2, + sys_fn: __truncsfhf2, + sys_available: not(feature = "no-sys-f16"), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f16; + asm!( + "fcvt {ret:h}, {a:s}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(f16_enabled)] +float_bench! { + name: trunc_f64_f16, + sig: (a: f64) -> f16, + crate_fn: trunc::__truncdfhf2, + sys_fn: __truncdfhf2, + sys_available: not(feature = "no-sys-f16-f64-convert"), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f16; + asm!( + "fcvt {ret:h}, {a:d}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: trunc_f64_f32, + sig: (a: f64) -> f32, + crate_fn: trunc::__truncdfsf2, + sys_fn: __truncdfsf2, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f32; + asm!( + "cvtsd2ss {ret}, {a}", + a = in(xmm_reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "fcvt {ret:s}, {a:d}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(all(f16_enabled, f128_enabled))] +float_bench! { + name: trunc_f128_f16, + sig: (a: f128) -> f16, + crate_fn: trunc::__trunctfhf2, + crate_fn_ppc: trunc::__trunckfhf2, + sys_fn: __trunctfhf2, + sys_fn_ppc: __trunckfhf2, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [], +} + +#[cfg(f128_enabled)] +float_bench! { + name: trunc_f128_f32, + sig: (a: f128) -> f32, + crate_fn: trunc::__trunctfsf2, + crate_fn_ppc: trunc::__trunckfsf2, + sys_fn: __trunctfsf2, + sys_fn_ppc: __trunckfsf2, + sys_available: not(feature = "no-sys-f128"), + asm: [], +} + +#[cfg(f128_enabled)] +float_bench! { + name: trunc_f128_f64, + sig: (a: f128) -> f64, + crate_fn: trunc::__trunctfdf2, + crate_fn_ppc: trunc::__trunckfdf2, + sys_fn: __trunctfdf2, + sys_fn_ppc: __trunckfdf2, + sys_available: not(feature = "no-sys-f128"), + asm: [], +} + +pub fn float_trunc() { + let mut criterion = Criterion::default().configure_from_args(); + + // FIXME(#655): `f16` tests disabled until we can bootstrap symbols + #[cfg(f16_enabled)] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + { + trunc_f32_f16(&mut criterion); + trunc_f64_f16(&mut criterion); + } + + trunc_f64_f32(&mut criterion); + + #[cfg(f128_enabled)] + { + // FIXME(#655): `f16` tests disabled until we can bootstrap symbols + #[cfg(f16_enabled)] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + trunc_f128_f16(&mut criterion); + + trunc_f128_f32(&mut criterion); + trunc_f128_f64(&mut criterion); + } +} + +criterion_main!(float_trunc); diff --git a/library/compiler-builtins/builtins-test/benches/mem.rs b/library/compiler-builtins/builtins-test/benches/mem.rs new file mode 100644 index 00000000000..3f83926b6c5 --- /dev/null +++ b/library/compiler-builtins/builtins-test/benches/mem.rs @@ -0,0 +1,364 @@ +#![feature(test)] + +extern crate test; +use test::{Bencher, black_box}; + +extern crate compiler_builtins; +use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; + +const WORD_SIZE: usize = core::mem::size_of::(); + +struct AlignedVec { + vec: Vec, + size: usize, +} + +impl AlignedVec { + fn new(fill: u8, size: usize) -> Self { + let mut broadcast = fill as usize; + let mut bits = 8; + while bits < WORD_SIZE * 8 { + broadcast |= broadcast << bits; + bits *= 2; + } + + let vec = vec![broadcast; (size + WORD_SIZE - 1) & !WORD_SIZE]; + AlignedVec { vec, size } + } +} + +impl core::ops::Deref for AlignedVec { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { core::slice::from_raw_parts(self.vec.as_ptr() as *const u8, self.size) } + } +} + +impl core::ops::DerefMut for AlignedVec { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { core::slice::from_raw_parts_mut(self.vec.as_mut_ptr() as *mut u8, self.size) } + } +} + +fn memcpy_builtin(b: &mut Bencher, n: usize, offset1: usize, offset2: usize) { + let v1 = AlignedVec::new(1, n + offset1); + let mut v2 = AlignedVec::new(0, n + offset2); + b.bytes = n as u64; + b.iter(|| { + let src: &[u8] = black_box(&v1[offset1..]); + let dst: &mut [u8] = black_box(&mut v2[offset2..]); + dst.copy_from_slice(src); + }) +} + +fn memcpy_rust(b: &mut Bencher, n: usize, offset1: usize, offset2: usize) { + let v1 = AlignedVec::new(1, n + offset1); + let mut v2 = AlignedVec::new(0, n + offset2); + b.bytes = n as u64; + b.iter(|| { + let src: &[u8] = black_box(&v1[offset1..]); + let dst: &mut [u8] = black_box(&mut v2[offset2..]); + unsafe { memcpy(dst.as_mut_ptr(), src.as_ptr(), n) } + }) +} + +fn memset_builtin(b: &mut Bencher, n: usize, offset: usize) { + let mut v1 = AlignedVec::new(0, n + offset); + b.bytes = n as u64; + b.iter(|| { + let dst: &mut [u8] = black_box(&mut v1[offset..]); + let val: u8 = black_box(27); + for b in dst { + *b = val; + } + }) +} + +fn memset_rust(b: &mut Bencher, n: usize, offset: usize) { + let mut v1 = AlignedVec::new(0, n + offset); + b.bytes = n as u64; + b.iter(|| { + let dst: &mut [u8] = black_box(&mut v1[offset..]); + let val = black_box(27); + unsafe { memset(dst.as_mut_ptr(), val, n) } + }) +} + +fn memcmp_builtin(b: &mut Bencher, n: usize) { + let v1 = AlignedVec::new(0, n); + let mut v2 = AlignedVec::new(0, n); + v2[n - 1] = 1; + b.bytes = n as u64; + b.iter(|| { + let s1: &[u8] = black_box(&v1); + let s2: &[u8] = black_box(&v2); + s1.cmp(s2) + }) +} + +fn memcmp_builtin_unaligned(b: &mut Bencher, n: usize) { + let v1 = AlignedVec::new(0, n); + let mut v2 = AlignedVec::new(0, n); + v2[n - 1] = 1; + b.bytes = n as u64; + b.iter(|| { + let s1: &[u8] = black_box(&v1[0..]); + let s2: &[u8] = black_box(&v2[1..]); + s1.cmp(s2) + }) +} + +fn memcmp_rust(b: &mut Bencher, n: usize) { + let v1 = AlignedVec::new(0, n); + let mut v2 = AlignedVec::new(0, n); + v2[n - 1] = 1; + b.bytes = n as u64; + b.iter(|| { + let s1: &[u8] = black_box(&v1); + let s2: &[u8] = black_box(&v2); + unsafe { memcmp(s1.as_ptr(), s2.as_ptr(), n) } + }) +} + +fn memcmp_rust_unaligned(b: &mut Bencher, n: usize) { + let v1 = AlignedVec::new(0, n); + let mut v2 = AlignedVec::new(0, n); + v2[n - 1] = 1; + b.bytes = n as u64; + b.iter(|| { + let s1: &[u8] = black_box(&v1[0..]); + let s2: &[u8] = black_box(&v2[1..]); + unsafe { memcmp(s1.as_ptr(), s2.as_ptr(), n - 1) } + }) +} + +fn memmove_builtin(b: &mut Bencher, n: usize, offset: usize) { + let mut v = AlignedVec::new(0, n + n / 2 + offset); + b.bytes = n as u64; + b.iter(|| { + let s: &mut [u8] = black_box(&mut v); + s.copy_within(0..n, n / 2 + offset); + }) +} + +fn memmove_rust(b: &mut Bencher, n: usize, offset: usize) { + let mut v = AlignedVec::new(0, n + n / 2 + offset); + b.bytes = n as u64; + b.iter(|| { + let dst: *mut u8 = black_box(&mut v[n / 2 + offset..]).as_mut_ptr(); + let src: *const u8 = black_box(&v).as_ptr(); + unsafe { memmove(dst, src, n) }; + }) +} + +#[bench] +fn memcpy_builtin_4096(b: &mut Bencher) { + memcpy_builtin(b, 4096, 0, 0) +} +#[bench] +fn memcpy_rust_4096(b: &mut Bencher) { + memcpy_rust(b, 4096, 0, 0) +} +#[bench] +fn memcpy_builtin_1048576(b: &mut Bencher) { + memcpy_builtin(b, 1048576, 0, 0) +} +#[bench] +fn memcpy_rust_1048576(b: &mut Bencher) { + memcpy_rust(b, 1048576, 0, 0) +} +#[bench] +fn memcpy_builtin_4096_offset(b: &mut Bencher) { + memcpy_builtin(b, 4096, 65, 65) +} +#[bench] +fn memcpy_rust_4096_offset(b: &mut Bencher) { + memcpy_rust(b, 4096, 65, 65) +} +#[bench] +fn memcpy_builtin_1048576_offset(b: &mut Bencher) { + memcpy_builtin(b, 1048576, 65, 65) +} +#[bench] +fn memcpy_rust_1048576_offset(b: &mut Bencher) { + memcpy_rust(b, 1048576, 65, 65) +} +#[bench] +fn memcpy_builtin_4096_misalign(b: &mut Bencher) { + memcpy_builtin(b, 4096, 65, 66) +} +#[bench] +fn memcpy_rust_4096_misalign(b: &mut Bencher) { + memcpy_rust(b, 4096, 65, 66) +} +#[bench] +fn memcpy_builtin_1048576_misalign(b: &mut Bencher) { + memcpy_builtin(b, 1048576, 65, 66) +} +#[bench] +fn memcpy_rust_1048576_misalign(b: &mut Bencher) { + memcpy_rust(b, 1048576, 65, 66) +} + +#[bench] +fn memset_builtin_4096(b: &mut Bencher) { + memset_builtin(b, 4096, 0) +} +#[bench] +fn memset_rust_4096(b: &mut Bencher) { + memset_rust(b, 4096, 0) +} +#[bench] +fn memset_builtin_1048576(b: &mut Bencher) { + memset_builtin(b, 1048576, 0) +} +#[bench] +fn memset_rust_1048576(b: &mut Bencher) { + memset_rust(b, 1048576, 0) +} +#[bench] +fn memset_builtin_4096_offset(b: &mut Bencher) { + memset_builtin(b, 4096, 65) +} +#[bench] +fn memset_rust_4096_offset(b: &mut Bencher) { + memset_rust(b, 4096, 65) +} +#[bench] +fn memset_builtin_1048576_offset(b: &mut Bencher) { + memset_builtin(b, 1048576, 65) +} +#[bench] +fn memset_rust_1048576_offset(b: &mut Bencher) { + memset_rust(b, 1048576, 65) +} + +#[bench] +fn memcmp_builtin_8(b: &mut Bencher) { + memcmp_builtin(b, 8) +} +#[bench] +fn memcmp_rust_8(b: &mut Bencher) { + memcmp_rust(b, 8) +} +#[bench] +fn memcmp_builtin_16(b: &mut Bencher) { + memcmp_builtin(b, 16) +} +#[bench] +fn memcmp_rust_16(b: &mut Bencher) { + memcmp_rust(b, 16) +} +#[bench] +fn memcmp_builtin_32(b: &mut Bencher) { + memcmp_builtin(b, 32) +} +#[bench] +fn memcmp_rust_32(b: &mut Bencher) { + memcmp_rust(b, 32) +} +#[bench] +fn memcmp_builtin_64(b: &mut Bencher) { + memcmp_builtin(b, 64) +} +#[bench] +fn memcmp_rust_64(b: &mut Bencher) { + memcmp_rust(b, 64) +} +#[bench] +fn memcmp_builtin_4096(b: &mut Bencher) { + memcmp_builtin(b, 4096) +} +#[bench] +fn memcmp_rust_4096(b: &mut Bencher) { + memcmp_rust(b, 4096) +} +#[bench] +fn memcmp_builtin_1048576(b: &mut Bencher) { + memcmp_builtin(b, 1048576) +} +#[bench] +fn memcmp_rust_1048576(b: &mut Bencher) { + memcmp_rust(b, 1048576) +} +#[bench] +fn memcmp_builtin_unaligned_7(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 8) +} +#[bench] +fn memcmp_rust_unaligned_7(b: &mut Bencher) { + memcmp_rust_unaligned(b, 8) +} +#[bench] +fn memcmp_builtin_unaligned_15(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 16) +} +#[bench] +fn memcmp_rust_unaligned_15(b: &mut Bencher) { + memcmp_rust_unaligned(b, 16) +} +#[bench] +fn memcmp_builtin_unaligned_31(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 32) +} +#[bench] +fn memcmp_rust_unaligned_31(b: &mut Bencher) { + memcmp_rust_unaligned(b, 32) +} +#[bench] +fn memcmp_builtin_unaligned_63(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 64) +} +#[bench] +fn memcmp_rust_unaligned_63(b: &mut Bencher) { + memcmp_rust_unaligned(b, 64) +} +#[bench] +fn memcmp_builtin_unaligned_4095(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 4096) +} +#[bench] +fn memcmp_rust_unaligned_4095(b: &mut Bencher) { + memcmp_rust_unaligned(b, 4096) +} +#[bench] +fn memcmp_builtin_unaligned_1048575(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 1048576) +} +#[bench] +fn memcmp_rust_unaligned_1048575(b: &mut Bencher) { + memcmp_rust_unaligned(b, 1048576) +} + +#[bench] +fn memmove_builtin_4096(b: &mut Bencher) { + memmove_builtin(b, 4096, 0) +} +#[bench] +fn memmove_rust_4096(b: &mut Bencher) { + memmove_rust(b, 4096, 0) +} +#[bench] +fn memmove_builtin_1048576(b: &mut Bencher) { + memmove_builtin(b, 1048576, 0) +} +#[bench] +fn memmove_rust_1048576(b: &mut Bencher) { + memmove_rust(b, 1048576, 0) +} +#[bench] +fn memmove_builtin_4096_misalign(b: &mut Bencher) { + memmove_builtin(b, 4096, 1) +} +#[bench] +fn memmove_rust_4096_misalign(b: &mut Bencher) { + memmove_rust(b, 4096, 1) +} +#[bench] +fn memmove_builtin_1048576_misalign(b: &mut Bencher) { + memmove_builtin(b, 1048576, 1) +} +#[bench] +fn memmove_rust_1048576_misalign(b: &mut Bencher) { + memmove_rust(b, 1048576, 1) +} diff --git a/library/compiler-builtins/builtins-test/benches/mem_icount.rs b/library/compiler-builtins/builtins-test/benches/mem_icount.rs new file mode 100644 index 00000000000..63045f6e1ec --- /dev/null +++ b/library/compiler-builtins/builtins-test/benches/mem_icount.rs @@ -0,0 +1,499 @@ +//! Benchmarks that use Callgrind (via `iai_callgrind`) to report instruction count metrics. This +//! is stable enough to be tested in CI. + +use std::hint::black_box; +use std::{ops, slice}; + +use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; +use iai_callgrind::{library_benchmark, library_benchmark_group, main}; + +const PAGE_SIZE: usize = 0x1000; // 4 kiB +const MAX_ALIGN: usize = 512; // assume we may use avx512 operations one day +const MEG1: usize = 1 << 20; // 1 MiB + +#[derive(Clone)] +#[repr(C, align(0x1000))] +struct Page([u8; PAGE_SIZE]); + +/// A buffer that is page-aligned by default, with an optional offset to create a +/// misalignment. +struct AlignedSlice { + buf: Box<[Page]>, + len: usize, + offset: usize, +} + +impl AlignedSlice { + /// Allocate a slice aligned to ALIGN with at least `len` items, with `offset` from + /// page alignment. + fn new_zeroed(len: usize, offset: usize) -> Self { + assert!(offset < PAGE_SIZE); + let total_len = len + offset; + let items = (total_len / PAGE_SIZE) + if total_len % PAGE_SIZE > 0 { 1 } else { 0 }; + let buf = vec![Page([0u8; PAGE_SIZE]); items].into_boxed_slice(); + AlignedSlice { buf, len, offset } + } +} + +impl ops::Deref for AlignedSlice { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + unsafe { slice::from_raw_parts(self.buf.as_ptr().cast::().add(self.offset), self.len) } + } +} + +impl ops::DerefMut for AlignedSlice { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + slice::from_raw_parts_mut( + self.buf.as_mut_ptr().cast::().add(self.offset), + self.len, + ) + } + } +} + +mod mcpy { + use super::*; + + struct Cfg { + len: usize, + s_off: usize, + d_off: usize, + } + + fn setup(cfg: Cfg) -> (usize, AlignedSlice, AlignedSlice) { + let Cfg { len, s_off, d_off } = cfg; + println!("bytes: {len} bytes, src offset: {s_off}, dst offset: {d_off}"); + let mut src = AlignedSlice::new_zeroed(len, s_off); + let dst = AlignedSlice::new_zeroed(len, d_off); + src.fill(1); + (len, src, dst) + } + + #[library_benchmark] + #[benches::aligned( + // Both aligned + args = [ + Cfg { len: 16, s_off: 0, d_off: 0 }, + Cfg { len: 32, s_off: 0, d_off: 0 }, + Cfg { len: 64, s_off: 0, d_off: 0 }, + Cfg { len: 512, s_off: 0, d_off: 0 }, + Cfg { len: 4096, s_off: 0, d_off: 0 }, + Cfg { len: MEG1, s_off: 0, d_off: 0 }, + ], + setup = setup, + )] + #[benches::offset( + // Both at the same offset + args = [ + Cfg { len: 16, s_off: 65, d_off: 65 }, + Cfg { len: 32, s_off: 65, d_off: 65 }, + Cfg { len: 64, s_off: 65, d_off: 65 }, + Cfg { len: 512, s_off: 65, d_off: 65 }, + Cfg { len: 4096, s_off: 65, d_off: 65 }, + Cfg { len: MEG1, s_off: 65, d_off: 65 }, + ], + setup = setup, + )] + #[benches::misaligned( + // `src` and `dst` both misaligned by different amounts + args = [ + Cfg { len: 16, s_off: 65, d_off: 66 }, + Cfg { len: 32, s_off: 65, d_off: 66 }, + Cfg { len: 64, s_off: 65, d_off: 66 }, + Cfg { len: 512, s_off: 65, d_off: 66 }, + Cfg { len: 4096, s_off: 65, d_off: 66 }, + Cfg { len: MEG1, s_off: 65, d_off: 66 }, + ], + setup = setup, + )] + fn bench((len, mut dst, src): (usize, AlignedSlice, AlignedSlice)) { + unsafe { + black_box(memcpy( + black_box(dst.as_mut_ptr()), + black_box(src.as_ptr()), + black_box(len), + )); + } + } + + library_benchmark_group!(name = memcpy; benchmarks = bench); +} + +mod mset { + use super::*; + + struct Cfg { + len: usize, + offset: usize, + } + + fn setup(Cfg { len, offset }: Cfg) -> (usize, AlignedSlice) { + println!("bytes: {len}, offset: {offset}"); + (len, AlignedSlice::new_zeroed(len, offset)) + } + + #[library_benchmark] + #[benches::aligned( + args = [ + Cfg { len: 16, offset: 0 }, + Cfg { len: 32, offset: 0 }, + Cfg { len: 64, offset: 0 }, + Cfg { len: 512, offset: 0 }, + Cfg { len: 4096, offset: 0 }, + Cfg { len: MEG1, offset: 0 }, + ], + setup = setup, + )] + #[benches::offset( + args = [ + Cfg { len: 16, offset: 65 }, + Cfg { len: 32, offset: 65 }, + Cfg { len: 64, offset: 65 }, + Cfg { len: 512, offset: 65 }, + Cfg { len: 4096, offset: 65 }, + Cfg { len: MEG1, offset: 65 }, + ], + setup = setup, + )] + fn bench((len, mut dst): (usize, AlignedSlice)) { + unsafe { + black_box(memset( + black_box(dst.as_mut_ptr()), + black_box(27), + black_box(len), + )); + } + } + + library_benchmark_group!(name = memset; benchmarks = bench); +} + +mod mcmp { + use super::*; + + struct Cfg { + len: usize, + s_off: usize, + d_off: usize, + } + + fn setup(cfg: Cfg) -> (usize, AlignedSlice, AlignedSlice) { + let Cfg { len, s_off, d_off } = cfg; + println!("bytes: {len}, src offset: {s_off}, dst offset: {d_off}"); + let b1 = AlignedSlice::new_zeroed(len, s_off); + let mut b2 = AlignedSlice::new_zeroed(len, d_off); + b2[len - 1] = 1; + (len, b1, b2) + } + + #[library_benchmark] + #[benches::aligned( + // Both aligned + args = [ + Cfg { len: 16, s_off: 0, d_off: 0 }, + Cfg { len: 32, s_off: 0, d_off: 0 }, + Cfg { len: 64, s_off: 0, d_off: 0 }, + Cfg { len: 512, s_off: 0, d_off: 0 }, + Cfg { len: 4096, s_off: 0, d_off: 0 }, + Cfg { len: MEG1, s_off: 0, d_off: 0 }, + ], + setup = setup + )] + #[benches::offset( + // Both at the same offset + args = [ + Cfg { len: 16, s_off: 65, d_off: 65 }, + Cfg { len: 32, s_off: 65, d_off: 65 }, + Cfg { len: 64, s_off: 65, d_off: 65 }, + Cfg { len: 512, s_off: 65, d_off: 65 }, + Cfg { len: 4096, s_off: 65, d_off: 65 }, + Cfg { len: MEG1, s_off: 65, d_off: 65 }, + ], + setup = setup + )] + #[benches::misaligned( + // `src` and `dst` both misaligned by different amounts + args = [ + Cfg { len: 16, s_off: 65, d_off: 66 }, + Cfg { len: 32, s_off: 65, d_off: 66 }, + Cfg { len: 64, s_off: 65, d_off: 66 }, + Cfg { len: 512, s_off: 65, d_off: 66 }, + Cfg { len: 4096, s_off: 65, d_off: 66 }, + Cfg { len: MEG1, s_off: 65, d_off: 66 }, + ], + setup = setup + )] + fn bench((len, mut dst, src): (usize, AlignedSlice, AlignedSlice)) { + unsafe { + black_box(memcmp( + black_box(dst.as_mut_ptr()), + black_box(src.as_ptr()), + black_box(len), + )); + } + } + + library_benchmark_group!(name = memcmp; benchmarks = bench); +} + +mod mmove { + use super::*; + use Spread::{Aligned, Large, Medium, Small}; + + struct Cfg { + len: usize, + spread: Spread, + off: usize, + } + + enum Spread { + /// `src` and `dst` are close and have the same alignment (or offset). + Aligned, + /// `src` and `dst` are close. + Small, + /// `src` and `dst` are halfway offset in the buffer. + Medium, + /// `src` and `dst` only overlap by a single byte. + Large, + } + + // Note that small and large are + fn calculate_spread(len: usize, spread: Spread) -> usize { + match spread { + // Note that this test doesn't make sense for lengths less than len=128 + Aligned => { + assert!(len > MAX_ALIGN, "aligned memset would have no overlap"); + MAX_ALIGN + } + Small => 1, + Medium => (len / 2) + 1, // add 1 so all are misaligned + Large => len - 1, + } + } + + fn setup_forward(cfg: Cfg) -> (usize, usize, AlignedSlice) { + let Cfg { len, spread, off } = cfg; + let spread = calculate_spread(len, spread); + println!("bytes: {len}, spread: {spread}, offset: {off}, forward"); + assert!(spread < len, "memmove tests should have some overlap"); + let mut buf = AlignedSlice::new_zeroed(len + spread, off); + let mut fill: usize = 0; + buf[..len].fill_with(|| { + fill += 1; + fill as u8 + }); + (len, spread, buf) + } + + fn setup_backward(cfg: Cfg) -> (usize, usize, AlignedSlice) { + let Cfg { len, spread, off } = cfg; + let spread = calculate_spread(len, spread); + println!("bytes: {len}, spread: {spread}, offset: {off}, backward"); + assert!(spread < len, "memmove tests should have some overlap"); + let mut buf = AlignedSlice::new_zeroed(len + spread, off); + let mut fill: usize = 0; + buf[spread..].fill_with(|| { + fill += 1; + fill as u8 + }); + (len, spread, buf) + } + + #[library_benchmark] + #[benches::aligned( + args = [ + // Don't test small spreads since there is no overlap + Cfg { len: 4096, spread: Aligned, off: 0 }, + Cfg { len: MEG1, spread: Aligned, off: 0 }, + ], + setup = setup_forward + )] + #[benches::small_spread( + args = [ + Cfg { len: 16, spread: Small, off: 0 }, + Cfg { len: 32, spread: Small, off: 0 }, + Cfg { len: 64, spread: Small, off: 0 }, + Cfg { len: 512, spread: Small, off: 0 }, + Cfg { len: 4096, spread: Small, off: 0 }, + Cfg { len: MEG1, spread: Small, off: 0 }, + ], + setup = setup_forward + )] + #[benches::medium_spread( + args = [ + Cfg { len: 16, spread: Medium, off: 0 }, + Cfg { len: 32, spread: Medium, off: 0 }, + Cfg { len: 64, spread: Medium, off: 0 }, + Cfg { len: 512, spread: Medium, off: 0 }, + Cfg { len: 4096, spread: Medium, off: 0 }, + Cfg { len: MEG1, spread: Medium, off: 0 }, + ], + setup = setup_forward + )] + #[benches::large_spread( + args = [ + Cfg { len: 16, spread: Large, off: 0 }, + Cfg { len: 32, spread: Large, off: 0 }, + Cfg { len: 64, spread: Large, off: 0 }, + Cfg { len: 512, spread: Large, off: 0 }, + Cfg { len: 4096, spread: Large, off: 0 }, + Cfg { len: MEG1, spread: Large, off: 0 }, + ], + setup = setup_forward + )] + #[benches::aligned_off( + args = [ + Cfg { len: 4096, spread: Aligned, off: 65 }, + Cfg { len: MEG1, spread: Aligned, off: 65 }, + ], + setup = setup_forward + )] + #[benches::small_spread_off( + args = [ + Cfg { len: 16, spread: Small, off: 65 }, + Cfg { len: 32, spread: Small, off: 65 }, + Cfg { len: 64, spread: Small, off: 65 }, + Cfg { len: 512, spread: Small, off: 65 }, + Cfg { len: 4096, spread: Small, off: 65 }, + Cfg { len: MEG1, spread: Small, off: 65 }, + ], + setup = setup_forward + )] + #[benches::medium_spread_off( + args = [ + Cfg { len: 16, spread: Medium, off: 65 }, + Cfg { len: 32, spread: Medium, off: 65 }, + Cfg { len: 64, spread: Medium, off: 65 }, + Cfg { len: 512, spread: Medium, off: 65 }, + Cfg { len: 4096, spread: Medium, off: 65 }, + Cfg { len: MEG1, spread: Medium, off: 65 }, + ], + setup = setup_forward + )] + #[benches::large_spread_off( + args = [ + Cfg { len: 16, spread: Large, off: 65 }, + Cfg { len: 32, spread: Large, off: 65 }, + Cfg { len: 64, spread: Large, off: 65 }, + Cfg { len: 512, spread: Large, off: 65 }, + Cfg { len: 4096, spread: Large, off: 65 }, + Cfg { len: MEG1, spread: Large, off: 65 }, + ], + setup = setup_forward + )] + fn forward((len, spread, mut buf): (usize, usize, AlignedSlice)) { + // Test moving from the start of the buffer toward the end + unsafe { + black_box(memmove( + black_box(buf[spread..].as_mut_ptr()), + black_box(buf.as_ptr()), + black_box(len), + )); + } + } + + #[library_benchmark] + #[benches::aligned( + args = [ + // Don't test small spreads since there is no overlap + Cfg { len: 4096, spread: Aligned, off: 0 }, + Cfg { len: MEG1, spread: Aligned, off: 0 }, + ], + setup = setup_backward + )] + #[benches::small_spread( + args = [ + Cfg { len: 16, spread: Small, off: 0 }, + Cfg { len: 32, spread: Small, off: 0 }, + Cfg { len: 64, spread: Small, off: 0 }, + Cfg { len: 512, spread: Small, off: 0 }, + Cfg { len: 4096, spread: Small, off: 0 }, + Cfg { len: MEG1, spread: Small, off: 0 }, + ], + setup = setup_backward + )] + #[benches::medium_spread( + args = [ + Cfg { len: 16, spread: Medium, off: 0 }, + Cfg { len: 32, spread: Medium, off: 0 }, + Cfg { len: 64, spread: Medium, off: 0 }, + Cfg { len: 512, spread: Medium, off: 0 }, + Cfg { len: 4096, spread: Medium, off: 0 }, + Cfg { len: MEG1, spread: Medium, off: 0 }, + ], + setup = setup_backward + )] + #[benches::large_spread( + args = [ + Cfg { len: 16, spread: Large, off: 0 }, + Cfg { len: 32, spread: Large, off: 0 }, + Cfg { len: 64, spread: Large, off: 0 }, + Cfg { len: 512, spread: Large, off: 0 }, + Cfg { len: 4096, spread: Large, off: 0 }, + Cfg { len: MEG1, spread: Large, off: 0 }, + ], + setup = setup_backward + )] + #[benches::aligned_off( + args = [ + // Don't test small spreads since there is no overlap + Cfg { len: 4096, spread: Aligned, off: 65 }, + Cfg { len: MEG1, spread: Aligned, off: 65 }, + ], + setup = setup_backward + )] + #[benches::small_spread_off( + args = [ + Cfg { len: 16, spread: Small, off: 65 }, + Cfg { len: 32, spread: Small, off: 65 }, + Cfg { len: 64, spread: Small, off: 65 }, + Cfg { len: 512, spread: Small, off: 65 }, + Cfg { len: 4096, spread: Small, off: 65 }, + Cfg { len: MEG1, spread: Small, off: 65 }, + ], + setup = setup_backward + )] + #[benches::medium_spread_off( + args = [ + Cfg { len: 16, spread: Medium, off: 65 }, + Cfg { len: 32, spread: Medium, off: 65 }, + Cfg { len: 64, spread: Medium, off: 65 }, + Cfg { len: 512, spread: Medium, off: 65 }, + Cfg { len: 4096, spread: Medium, off: 65 }, + Cfg { len: MEG1, spread: Medium, off: 65 }, + ], + setup = setup_backward + )] + #[benches::large_spread_off( + args = [ + Cfg { len: 16, spread: Large, off: 65 }, + Cfg { len: 32, spread: Large, off: 65 }, + Cfg { len: 64, spread: Large, off: 65 }, + Cfg { len: 512, spread: Large, off: 65 }, + Cfg { len: 4096, spread: Large, off: 65 }, + Cfg { len: MEG1, spread: Large, off: 65 }, + ], + setup = setup_backward + )] + fn backward((len, spread, mut buf): (usize, usize, AlignedSlice)) { + // Test moving from the end of the buffer toward the start + unsafe { + black_box(memmove( + black_box(buf.as_mut_ptr()), + black_box(buf[spread..].as_ptr()), + black_box(len), + )); + } + } + + library_benchmark_group!(name = memmove; benchmarks = forward, backward); +} + +use mcmp::memcmp; +use mcpy::memcpy; +use mmove::memmove; +use mset::memset; + +main!(library_benchmark_groups = memcpy, memset, memcmp, memmove); diff --git a/library/compiler-builtins/builtins-test/build.rs b/library/compiler-builtins/builtins-test/build.rs new file mode 100644 index 00000000000..e8f4eb4dd22 --- /dev/null +++ b/library/compiler-builtins/builtins-test/build.rs @@ -0,0 +1,120 @@ +use std::collections::HashSet; + +mod builtins_configure { + include!("../compiler-builtins/configure.rs"); +} + +/// Features to enable +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +enum Feature { + NoSysF128, + NoSysF128IntConvert, + NoSysF16, + NoSysF16F64Convert, + NoSysF16F128Convert, +} + +impl Feature { + fn implies(self) -> &'static [Self] { + match self { + Self::NoSysF128 => [Self::NoSysF128IntConvert, Self::NoSysF16F128Convert].as_slice(), + Self::NoSysF128IntConvert => [].as_slice(), + Self::NoSysF16 => [Self::NoSysF16F64Convert, Self::NoSysF16F128Convert].as_slice(), + Self::NoSysF16F64Convert => [].as_slice(), + Self::NoSysF16F128Convert => [].as_slice(), + } + } +} + +fn main() { + println!("cargo::rerun-if-changed=../configure.rs"); + + let target = builtins_configure::Target::from_env(); + let mut features = HashSet::new(); + + // These platforms do not have f128 symbols available in their system libraries, so + // skip related tests. + if target.arch == "arm" + || target.vendor == "apple" + || target.env == "msvc" + // GCC and LLVM disagree on the ABI of `f16` and `f128` with MinGW. See + // . + || (target.os == "windows" && target.env == "gnu") + // FIXME(llvm): There is an ABI incompatibility between GCC and Clang on 32-bit x86. + // See . + || target.arch == "x86" + // 32-bit PowerPC and 64-bit LE gets code generated that Qemu cannot handle. See + // . + || target.arch == "powerpc" + || target.arch == "powerpc64le" + // FIXME: We get different results from the builtin functions. See + // . + || target.arch == "powerpc64" + { + features.insert(Feature::NoSysF128); + } + + if target.arch == "x86" { + // 32-bit x86 does not have `__fixunstfti`/`__fixtfti` but does have everything else + features.insert(Feature::NoSysF128IntConvert); + // FIXME: 32-bit x86 has a bug in `f128 -> f16` system libraries + features.insert(Feature::NoSysF16F128Convert); + } + + // These platforms do not have f16 symbols available in their system libraries, so + // skip related tests. Most of these are missing `f16 <-> f32` conversion routines. + if (target.arch == "aarch64" && target.os == "linux") + || target.arch.starts_with("arm") + || target.arch == "powerpc" + || target.arch == "powerpc64" + || target.arch == "powerpc64le" + || target.arch == "loongarch64" + || (target.arch == "x86" && !target.has_feature("sse")) + || target.os == "windows" + // Linking says "error: function signature mismatch: __extendhfsf2" and seems to + // think the signature is either `(i32) -> f32` or `(f32) -> f32`. See + // . + || target.arch == "wasm32" + || target.arch == "wasm64" + { + features.insert(Feature::NoSysF16); + } + + // These platforms are missing either `__extendhfdf2` or `__truncdfhf2`. + if target.vendor == "apple" || target.os == "windows" { + features.insert(Feature::NoSysF16F64Convert); + } + + // Add implied features. Collection is required for borrows. + features.extend( + features + .iter() + .flat_map(|x| x.implies()) + .copied() + .collect::>(), + ); + + for feature in features { + let (name, warning) = match feature { + Feature::NoSysF128 => ("no-sys-f128", "using apfloat fallback for f128"), + Feature::NoSysF128IntConvert => ( + "no-sys-f128-int-convert", + "using apfloat fallback for f128 <-> int conversions", + ), + Feature::NoSysF16F64Convert => ( + "no-sys-f16-f64-convert", + "using apfloat fallback for f16 <-> f64 conversions", + ), + Feature::NoSysF16F128Convert => ( + "no-sys-f16-f128-convert", + "using apfloat fallback for f16 <-> f128 conversions", + ), + Feature::NoSysF16 => ("no-sys-f16", "using apfloat fallback for f16"), + }; + println!("cargo:warning={warning}"); + println!("cargo:rustc-cfg=feature=\"{name}\""); + } + + builtins_configure::configure_aliases(&target); + builtins_configure::configure_f16_f128(&target); +} diff --git a/library/compiler-builtins/builtins-test/src/bench.rs b/library/compiler-builtins/builtins-test/src/bench.rs new file mode 100644 index 00000000000..45a3a1ad467 --- /dev/null +++ b/library/compiler-builtins/builtins-test/src/bench.rs @@ -0,0 +1,366 @@ +use core::cell::RefCell; + +use alloc::vec::Vec; +use compiler_builtins::float::Float; + +/// Fuzz with these many items to ensure equal functions +pub const CHECK_ITER_ITEMS: u32 = 10_000; +/// Benchmark with this many items to get a variety +pub const BENCH_ITER_ITEMS: u32 = 500; + +/// Still run benchmarks/tests but don't check correctness between compiler-builtins and +/// builtin system functions functions +pub fn skip_sys_checks(test_name: &str) -> bool { + const ALWAYS_SKIPPED: &[&str] = &[ + // FIXME(f16_f128): system symbols have incorrect results + // + "extend_f16_f32", + "trunc_f32_f16", + "trunc_f64_f16", + // FIXME(#616): re-enable once fix is in nightly + // + "mul_f32", + "mul_f64", + ]; + + // FIXME(f16_f128): error on LE ppc64. There are more tests that are cfg-ed out completely + // in their benchmark modules due to runtime panics. + // + const PPC64LE_SKIPPED: &[&str] = &["extend_f32_f128"]; + + // FIXME(f16_f128): system symbols have incorrect results + // + const X86_NO_SSE_SKIPPED: &[&str] = &[ + "add_f128", "sub_f128", "mul_f128", "div_f128", "powi_f32", "powi_f64", + ]; + + // FIXME(f16_f128): Wide multiply carry bug in `compiler-rt`, re-enable when nightly no longer + // uses `compiler-rt` version. + // + const AARCH64_SKIPPED: &[&str] = &["mul_f128", "div_f128"]; + + // FIXME(llvm): system symbols have incorrect results on Windows + // + const WINDOWS_SKIPPED: &[&str] = &[ + "conv_f32_u128", + "conv_f32_i128", + "conv_f64_u128", + "conv_f64_i128", + ]; + + if cfg!(target_arch = "arm") { + // The Arm symbols need a different ABI that our macro doesn't handle, just skip it + return true; + } + + if ALWAYS_SKIPPED.contains(&test_name) { + return true; + } + + if cfg!(all(target_arch = "powerpc64", target_endian = "little")) + && PPC64LE_SKIPPED.contains(&test_name) + { + return true; + } + + if cfg!(all(target_arch = "x86", not(target_feature = "sse"))) + && X86_NO_SSE_SKIPPED.contains(&test_name) + { + return true; + } + + if cfg!(target_arch = "aarch64") && AARCH64_SKIPPED.contains(&test_name) { + return true; + } + + if cfg!(target_family = "windows") && WINDOWS_SKIPPED.contains(&test_name) { + return true; + } + + false +} + +/// Still run benchmarks/tests but don't check correctness between compiler-builtins and +/// assembly functions +pub fn skip_asm_checks(_test_name: &str) -> bool { + // Nothing to skip at this time + false +} + +/// Create a comparison of the system symbol, compiler_builtins, and optionally handwritten +/// assembly. +/// +/// # Safety +/// +/// The signature must be correct and any assembly must be sound. +#[macro_export] +macro_rules! float_bench { + ( + // Name of this benchmark + name: $name:ident, + // The function signature to be tested + sig: ($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty, + // Path to the crate in compiler_builtins + crate_fn: $crate_fn:path, + // Optional alias on ppc + $( crate_fn_ppc: $crate_fn_ppc:path, )? + // Name of the system symbol + sys_fn: $sys_fn:ident, + // Optional alias on ppc + $( sys_fn_ppc: $sys_fn_ppc:path, )? + // Meta saying whether the system symbol is available + sys_available: $sys_available:meta, + // An optional function to validate the results of two functions are equal, if not + // just `$ret_ty::check_eq` + $( output_eq: $output_eq:expr, )? + // Assembly implementations, if any. + asm: [ + $( + #[cfg($asm_meta:meta)] { + $($asm_tt:tt)* + } + );* + $(;)? + ] + $(,)? + ) => {paste::paste! { + // SAFETY: macro invocation must use the correct signature + #[cfg($sys_available)] + unsafe extern "C" { + /// Binding for the system function + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + fn $sys_fn($($arg: $arg_ty),*) -> $ret_ty; + + + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + float_bench! { @coalesce_fn $($sys_fn_ppc)? => + fn $sys_fn($($arg: $arg_ty),*) -> $ret_ty; + } + } + + fn $name(c: &mut Criterion) { + use core::hint::black_box; + use compiler_builtins::float::Float; + use $crate::bench::TestIO; + + #[inline(never)] // equalize with external calls + fn crate_fn($($arg: $arg_ty),*) -> $ret_ty { + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + let target_crate_fn = $crate_fn; + + // On PPC, use an alias if specified + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + let target_crate_fn = float_bench!(@coalesce $($crate_fn_ppc)?, $crate_fn); + + target_crate_fn( $($arg),* ) + } + + #[inline(always)] // already a branch + #[cfg($sys_available)] + fn sys_fn($($arg: $arg_ty),*) -> $ret_ty { + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + let target_sys_fn = $sys_fn; + + // On PPC, use an alias if specified + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + let target_sys_fn = float_bench!(@coalesce $($sys_fn_ppc)?, $sys_fn); + + unsafe { target_sys_fn( $($arg),* ) } + } + + #[inline(never)] // equalize with external calls + #[cfg(any( $($asm_meta),* ))] + fn asm_fn($(mut $arg: $arg_ty),*) -> $ret_ty { + use core::arch::asm; + $( + #[cfg($asm_meta)] + unsafe { $($asm_tt)* } + )* + } + + let testvec = <($($arg_ty),*)>::make_testvec($crate::bench::CHECK_ITER_ITEMS); + let benchvec = <($($arg_ty),*)>::make_testvec($crate::bench::BENCH_ITER_ITEMS); + let test_name = stringify!($name); + let check_eq = float_bench!(@coalesce $($output_eq)?, $ret_ty::check_eq); + + // Verify math lines up. We run the crate functions even if we don't validate the + // output here to make sure there are no panics or crashes. + + #[cfg($sys_available)] + for ($($arg),*) in testvec.iter().copied() { + let crate_res = crate_fn($($arg),*); + let sys_res = sys_fn($($arg),*); + + if $crate::bench::skip_sys_checks(test_name) { + continue; + } + + assert!( + check_eq(crate_res, sys_res), + "{test_name}{:?}: crate: {crate_res:?}, sys: {sys_res:?}", + ($($arg),* ,) + ); + } + + #[cfg(any( $($asm_meta),* ))] + { + for ($($arg),*) in testvec.iter().copied() { + let crate_res = crate_fn($($arg),*); + let asm_res = asm_fn($($arg),*); + + if $crate::bench::skip_asm_checks(test_name) { + continue; + } + + assert!( + check_eq(crate_res, asm_res), + "{test_name}{:?}: crate: {crate_res:?}, asm: {asm_res:?}", + ($($arg),* ,) + ); + } + } + + let mut group = c.benchmark_group(test_name); + group.bench_function("compiler-builtins", |b| b.iter(|| { + for ($($arg),*) in benchvec.iter().copied() { + black_box(crate_fn( $(black_box($arg)),* )); + } + })); + + #[cfg($sys_available)] + group.bench_function("system", |b| b.iter(|| { + for ($($arg),*) in benchvec.iter().copied() { + black_box(sys_fn( $(black_box($arg)),* )); + } + })); + + #[cfg(any( $($asm_meta),* ))] + group.bench_function(&format!( + "assembly ({} {})", std::env::consts::ARCH, std::env::consts::FAMILY + ), |b| b.iter(|| { + for ($($arg),*) in benchvec.iter().copied() { + black_box(asm_fn( $(black_box($arg)),* )); + } + })); + + group.finish(); + } + }}; + + // Allow overriding a default + (@coalesce $specified:expr, $default:expr) => { $specified }; + (@coalesce, $default:expr) => { $default }; + + // Allow overriding a function name + (@coalesce_fn $specified:ident => fn $default_name:ident $($tt:tt)+) => { + fn $specified $($tt)+ + }; + (@coalesce_fn => fn $default_name:ident $($tt:tt)+) => { + fn $default_name $($tt)+ + }; +} + +/// A type used as either an input or output to/from a benchmark function. +pub trait TestIO: Sized { + fn make_testvec(len: u32) -> Vec; + fn check_eq(a: Self, b: Self) -> bool; +} + +macro_rules! impl_testio { + (float $($f_ty:ty),+) => {$( + impl TestIO for $f_ty { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ret = RefCell::new(Vec::new()); + crate::fuzz_float(len, |a| ret.borrow_mut().push(a)); + ret.into_inner() + } + + fn check_eq(a: Self, b: Self) -> bool { + Float::eq_repr(a, b) + } + } + + impl TestIO for ($f_ty, $f_ty) { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ret = RefCell::new(Vec::new()); + crate::fuzz_float_2(len, |a, b| ret.borrow_mut().push((a, b))); + ret.into_inner() + } + + fn check_eq(_a: Self, _b: Self) -> bool { + unimplemented!() + } + } + )*}; + + (int $($i_ty:ty),+) => {$( + impl TestIO for $i_ty { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ret = RefCell::new(Vec::new()); + crate::fuzz(len, |a| ret.borrow_mut().push(a)); + ret.into_inner() + } + + fn check_eq(a: Self, b: Self) -> bool { + a == b + } + } + + impl TestIO for ($i_ty, $i_ty) { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ret = RefCell::new(Vec::new()); + crate::fuzz_2(len, |a, b| ret.borrow_mut().push((a, b))); + ret.into_inner() + } + + fn check_eq(_a: Self, _b: Self) -> bool { + unimplemented!() + } + } + )*}; + + ((float, int) ($f_ty:ty, $i_ty:ty)) => { + impl TestIO for ($f_ty, $i_ty) { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ivec = RefCell::new(Vec::new()); + let fvec = RefCell::new(Vec::new()); + + crate::fuzz(len.isqrt(), |a| ivec.borrow_mut().push(a)); + crate::fuzz_float(len.isqrt(), |a| fvec.borrow_mut().push(a)); + + let mut ret = Vec::new(); + let ivec = ivec.into_inner(); + let fvec = fvec.into_inner(); + + for f in fvec { + for i in &ivec { + ret.push((f, *i)); + } + } + + ret + } + + fn check_eq(_a: Self, _b: Self) -> bool { + unimplemented!() + } + } + } +} + +#[cfg(f16_enabled)] +impl_testio!(float f16); +impl_testio!(float f32, f64); +#[cfg(f128_enabled)] +impl_testio!(float f128); +impl_testio!(int i16, i32, i64, i128); +impl_testio!(int u16, u32, u64, u128); +impl_testio!((float, int)(f32, i32)); +impl_testio!((float, int)(f64, i32)); +#[cfg(f128_enabled)] +impl_testio!((float, int)(f128, i32)); diff --git a/library/compiler-builtins/builtins-test/src/lib.rs b/library/compiler-builtins/builtins-test/src/lib.rs new file mode 100644 index 00000000000..a83aea56206 --- /dev/null +++ b/library/compiler-builtins/builtins-test/src/lib.rs @@ -0,0 +1,338 @@ +//! This crate is for integration testing and fuzz testing of functions in `compiler-builtins`. This +//! includes publicly documented intrinsics and some internal alternative implementation functions +//! such as `usize_leading_zeros_riscv` (which are tested because they are configured for +//! architectures not tested by the CI). +//! +//! The general idea is to use a combination of edge case testing and randomized fuzz testing. The +//! edge case testing is crucial for checking cases like where both inputs are equal or equal to +//! special values such as `i128::MIN`, which is unlikely for the random fuzzer by itself to +//! encounter. The randomized fuzz testing is specially designed to cover wide swaths of search +//! space in as few iterations as possible. See `fuzz_values` in `builtins-test/tests/misc.rs` for +//! an example. +//! +//! Some floating point tests are disabled for specific architectures, because they do not have +//! correct rounding. +#![no_std] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] + +pub mod bench; +extern crate alloc; + +use compiler_builtins::float::Float; +use compiler_builtins::int::{Int, MinInt}; + +use rand_xoshiro::Xoshiro128StarStar; +use rand_xoshiro::rand_core::{RngCore, SeedableRng}; + +/// Sets the number of fuzz iterations run for most tests. In practice, the vast majority of bugs +/// are caught by the edge case testers. Most of the remaining bugs triggered by more complex +/// sequences are caught well within 10_000 fuzz iterations. For classes of algorithms like division +/// that are vulnerable to rare edge cases, we want 1_000_000 iterations to be more confident. In +/// practical CI, however, we only want to run the more strenuous test once to catch algorithmic +/// level bugs, and run the 10_000 iteration test on most targets. Target-dependent bugs are likely +/// to involve miscompilation and misconfiguration that is likely to break algorithms in quickly +/// caught ways. We choose to configure `N = 1_000_000` iterations for `x86_64` targets (and if +/// debug assertions are disabled. Tests without `--release` would take too long) which are likely +/// to have fast hardware, and run `N = 10_000` for all other targets. +pub const N: u32 = if cfg!(target_arch = "x86_64") && !cfg!(debug_assertions) { + 1_000_000 +} else { + 10_000 +}; + +/// Random fuzzing step. When run several times, it results in excellent fuzzing entropy such as: +/// 11110101010101011110111110011111 +/// 10110101010100001011101011001010 +/// 1000000000000000 +/// 10000000000000110111110000001010 +/// 1111011111111101010101111110101 +/// 101111111110100000000101000000 +/// 10000000110100000000100010101 +/// 1010101010101000 +fn fuzz_step(rng: &mut Xoshiro128StarStar, x: &mut I) { + let ones = !I::ZERO; + let bit_indexing_mask: u32 = I::BITS - 1; + // It happens that all the RNG we need can come from one call. 7 bits are needed to index a + // worst case 128 bit integer, and there are 4 indexes that need to be made plus 4 bits for + // selecting operations + let rng32 = rng.next_u32(); + + // Randomly OR, AND, and XOR randomly sized and shifted continuous strings of + // ones with `lhs` and `rhs`. + let r0 = bit_indexing_mask & rng32; + let r1 = bit_indexing_mask & (rng32 >> 7); + let mask = ones.wrapping_shl(r0).rotate_left(r1); + match (rng32 >> 14) % 4 { + 0 => *x |= mask, + 1 => *x &= mask, + // both 2 and 3 to make XORs as common as ORs and ANDs combined + _ => *x ^= mask, + } + + // Alternating ones and zeros (e.x. 0b1010101010101010). This catches second-order + // problems that might occur for algorithms with two modes of operation (potentially + // there is some invariant that can be broken and maintained via alternating between modes, + // breaking the algorithm when it reaches the end). + let mut alt_ones = I::ONE; + for _ in 0..(I::BITS / 2) { + alt_ones <<= 2; + alt_ones |= I::ONE; + } + let r0 = bit_indexing_mask & (rng32 >> 16); + let r1 = bit_indexing_mask & (rng32 >> 23); + let mask = alt_ones.wrapping_shl(r0).rotate_left(r1); + match rng32 >> 30 { + 0 => *x |= mask, + 1 => *x &= mask, + _ => *x ^= mask, + } +} + +// We need macros like this, because `#![no_std]` prevents us from using iterators +macro_rules! edge_cases { + ($I:ident, $case:ident, $inner:block) => { + for i0 in 0..$I::FUZZ_NUM { + let mask_lo = (!$I::UnsignedInt::ZERO).wrapping_shr($I::FUZZ_LENGTHS[i0] as u32); + for i1 in i0..I::FUZZ_NUM { + let mask_hi = + (!$I::UnsignedInt::ZERO).wrapping_shl($I::FUZZ_LENGTHS[i1 - i0] as u32); + let $case = I::from_unsigned(mask_lo & mask_hi); + $inner + } + } + }; +} + +/// Feeds a series of fuzzing inputs to `f`. The fuzzer first uses an algorithm designed to find +/// edge cases, followed by a more random fuzzer that runs `n` times. +pub fn fuzz(n: u32, mut f: F) +where + ::UnsignedInt: Int, +{ + // edge case tester. Calls `f` 210 times for u128. + // zero gets skipped by the loop + f(I::ZERO); + edge_cases!(I, case, { + f(case); + }); + + // random fuzzer + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x: I = MinInt::ZERO; + for _ in 0..n { + fuzz_step(&mut rng, &mut x); + f(x) + } +} + +/// The same as `fuzz`, except `f` has two inputs. +pub fn fuzz_2(n: u32, f: F) +where + ::UnsignedInt: Int, +{ + // Check cases where the first and second inputs are zero. Both call `f` 210 times for `u128`. + edge_cases!(I, case, { + f(I::ZERO, case); + }); + edge_cases!(I, case, { + f(case, I::ZERO); + }); + // Nested edge tester. Calls `f` 44100 times for `u128`. + edge_cases!(I, case0, { + edge_cases!(I, case1, { + f(case0, case1); + }) + }); + + // random fuzzer + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x: I = I::ZERO; + let mut y: I = I::ZERO; + for _ in 0..n { + fuzz_step(&mut rng, &mut x); + fuzz_step(&mut rng, &mut y); + f(x, y) + } +} + +/// Tester for shift functions +pub fn fuzz_shift(f: F) { + // Shift functions are very simple and do not need anything other than shifting a small + // set of random patterns for every fuzz length. + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x: I = MinInt::ZERO; + for i in 0..I::FUZZ_NUM { + fuzz_step(&mut rng, &mut x); + f(x, MinInt::ZERO); + f(x, I::FUZZ_LENGTHS[i] as u32); + } +} + +fn fuzz_float_step(rng: &mut Xoshiro128StarStar, f: &mut F) { + let rng32 = rng.next_u32(); + // we need to fuzz the different parts of the float separately, because the masking on larger + // significands will tend to set the exponent to all ones or all zeros frequently + + // sign bit fuzzing + let sign = (rng32 & 1) != 0; + + // exponent fuzzing. Only 4 bits for the selector needed. + let ones = (F::Int::ONE << F::EXP_BITS) - F::Int::ONE; + let r0 = (rng32 >> 1) % F::EXP_BITS; + let r1 = (rng32 >> 5) % F::EXP_BITS; + // custom rotate shift. Note that `F::Int` is unsigned, so we can shift right without smearing + // the sign bit. + let mask = if r1 == 0 { + ones.wrapping_shr(r0) + } else { + let tmp = ones.wrapping_shr(r0); + (tmp.wrapping_shl(r1) | tmp.wrapping_shr(F::EXP_BITS - r1)) & ones + }; + let mut exp = (f.to_bits() & F::EXP_MASK) >> F::SIG_BITS; + match (rng32 >> 9) % 4 { + 0 => exp |= mask, + 1 => exp &= mask, + _ => exp ^= mask, + } + + // significand fuzzing + let mut sig = f.to_bits() & F::SIG_MASK; + fuzz_step(rng, &mut sig); + sig &= F::SIG_MASK; + + *f = F::from_parts(sign, exp, sig); +} + +macro_rules! float_edge_cases { + ($F:ident, $case:ident, $inner:block) => { + for exponent in [ + F::Int::ZERO, + F::Int::ONE, + F::Int::ONE << (F::EXP_BITS / 2), + (F::Int::ONE << (F::EXP_BITS - 1)) - F::Int::ONE, + F::Int::ONE << (F::EXP_BITS - 1), + (F::Int::ONE << (F::EXP_BITS - 1)) + F::Int::ONE, + (F::Int::ONE << F::EXP_BITS) - F::Int::ONE, + ] + .iter() + { + for significand in [ + F::Int::ZERO, + F::Int::ONE, + F::Int::ONE << (F::SIG_BITS / 2), + (F::Int::ONE << (F::SIG_BITS - 1)) - F::Int::ONE, + F::Int::ONE << (F::SIG_BITS - 1), + (F::Int::ONE << (F::SIG_BITS - 1)) + F::Int::ONE, + (F::Int::ONE << F::SIG_BITS) - F::Int::ONE, + ] + .iter() + { + for sign in [false, true].iter() { + let $case = F::from_parts(*sign, *exponent, *significand); + $inner + } + } + } + }; +} + +pub fn fuzz_float(n: u32, f: E) { + float_edge_cases!(F, case, { + f(case); + }); + + // random fuzzer + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x = F::ZERO; + for _ in 0..n { + fuzz_float_step(&mut rng, &mut x); + f(x); + } +} + +pub fn fuzz_float_2(n: u32, f: E) { + float_edge_cases!(F, case0, { + float_edge_cases!(F, case1, { + f(case0, case1); + }); + }); + + // random fuzzer + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x = F::ZERO; + let mut y = F::ZERO; + for _ in 0..n { + fuzz_float_step(&mut rng, &mut x); + fuzz_float_step(&mut rng, &mut y); + f(x, y) + } +} + +/// Perform an operation using builtin types if available, falling back to apfloat if not. +#[macro_export] +macro_rules! apfloat_fallback { + ( + $float_ty:ty, + // Type name in `rustc_apfloat::ieee`. Not a full path, it automatically gets the prefix. + $apfloat_ty:ident, + // Cfg expression for when builtin system operations should be used + $sys_available:meta, + // The expression to run. This expression may use `FloatTy` for its signature. + // Optionally, the final conversion back to a float can be suppressed using + // `=> no_convert` (for e.g. operations that return a bool). + // + // If the apfloat needs a different operation, it can be provided here. + $op:expr $(=> $convert:ident)? $(; $apfloat_op:expr)?, + // Arguments that get passed to `$op` after converting to a float + $($arg:expr),+ + $(,)? + ) => {{ + #[cfg($sys_available)] + let ret = { + type FloatTy = $float_ty; + $op( $($arg),+ ) + }; + + #[cfg(not($sys_available))] + let ret = { + use rustc_apfloat::Float; + type FloatTy = rustc_apfloat::ieee::$apfloat_ty; + + apfloat_fallback!(@inner + fty: $float_ty, + // Apply a conversion to `FloatTy` to each arg, then pass all args to `$op` + op_res: $op( $(FloatTy::from_bits($arg.to_bits().into())),+ ), + $(apfloat_op: $apfloat_op, )? + $(conv_opts: $convert,)? + args: $($arg),+ + ) + }; + + ret + }}; + + // Operations that do not need converting back to a float + (@inner fty: $float_ty:ty, op_res: $val:expr, conv_opts: no_convert, args: $($_arg:expr),+) => { + $val + }; + + // Some apfloat operations return a `StatusAnd` that we need to extract the value from. This + // is the default. + (@inner fty: $float_ty:ty, op_res: $val:expr, args: $($_arg:expr),+) => {{ + // ignore the status, just get the value + let unwrapped = $val.value; + + <$float_ty>::from_bits(FloatTy::to_bits(unwrapped).try_into().unwrap()) + }}; + + // This is the case where we can't use the same expression for the default builtin and + // nonstandard apfloat fallback (e.g. `as` casts in std are normal functions in apfloat, so + // two separate expressions must be specified. + (@inner + fty: $float_ty:ty, op_res: $_val:expr, + apfloat_op: $apfloat_op:expr, args: $($arg:expr),+ + ) => {{ + $apfloat_op($($arg),+) + }}; +} diff --git a/library/compiler-builtins/builtins-test/tests/addsub.rs b/library/compiler-builtins/builtins-test/tests/addsub.rs new file mode 100644 index 00000000000..865b9e472ab --- /dev/null +++ b/library/compiler-builtins/builtins-test/tests/addsub.rs @@ -0,0 +1,143 @@ +#![allow(unused_macros)] +#![cfg_attr(f128_enabled, feature(f128))] + +use builtins_test::*; + +mod int_addsub { + use super::*; + + macro_rules! sum { + ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { + $( + #[test] + fn $fn_add() { + use compiler_builtins::int::addsub::{$fn_add, $fn_sub}; + + fuzz_2(N, |x: $i, y: $i| { + let add0 = x.wrapping_add(y); + let sub0 = x.wrapping_sub(y); + let add1: $i = $fn_add(x, y); + let sub1: $i = $fn_sub(x, y); + if add0 != add1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_add), x, y, add0, add1 + ); + } + if sub0 != sub1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_sub), x, y, sub0, sub1 + ); + } + }); + } + )* + }; + } + + macro_rules! overflowing_sum { + ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { + $( + #[test] + fn $fn_add() { + use compiler_builtins::int::addsub::{$fn_add, $fn_sub}; + + fuzz_2(N, |x: $i, y: $i| { + let (add0, add_o0)= x.overflowing_add(y); + let (sub0, sub_o0)= x.overflowing_sub(y); + let mut add_o1 = 0; + let mut sub_o1 = 0; + let add1: $i = $fn_add(x, y, &mut add_o1); + let sub1: $i = $fn_sub(x, y, &mut sub_o1); + if add0 != add1 || i32::from(add_o0) != add_o1 { + panic!( + "{}({}, {}): std: {:?}, builtins: {:?}", + stringify!($fn_add), x, y, (add0, add_o0) , (add1, add_o1) + ); + } + if sub0 != sub1 || i32::from(sub_o0) != sub_o1 { + panic!( + "{}({}, {}): std: {:?}, builtins: {:?}", + stringify!($fn_sub), x, y, (sub0, sub_o0) , (sub1, sub_o1) + ); + } + }); + } + )* + }; + } + + // Integer addition and subtraction is very simple, so 100 fuzzing passes should be plenty. + sum! { + u128, __rust_u128_add, __rust_u128_sub; + i128, __rust_i128_add, __rust_i128_sub; + } + + overflowing_sum! { + u128, __rust_u128_addo, __rust_u128_subo; + i128, __rust_i128_addo, __rust_i128_subo; + } +} + +macro_rules! float_sum { + ($($f:ty, $fn_add:ident, $fn_sub:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { + $( + #[test] + fn $fn_add() { + use core::ops::{Add, Sub}; + use compiler_builtins::float::{{add::$fn_add, sub::$fn_sub}, Float}; + + fuzz_float_2(N, |x: $f, y: $f| { + let add0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Add::add, x, y); + let sub0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Sub::sub, x, y); + let add1: $f = $fn_add(x, y); + let sub1: $f = $fn_sub(x, y); + if !Float::eq_repr(add0, add1) { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn_add), x, y, add0, add1 + ); + } + if !Float::eq_repr(sub0, sub1) { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn_sub), x, y, sub0, sub1 + ); + } + }); + } + )* + } +} + +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +mod float_addsub { + use super::*; + + float_sum! { + f32, __addsf3, __subsf3, Single, all(); + f64, __adddf3, __subdf3, Double, all(); + } +} + +#[cfg(f128_enabled)] +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] +mod float_addsub_f128 { + use super::*; + + float_sum! { + f128, __addtf3, __subtf3, Quad, not(feature = "no-sys-f128"); + } +} + +#[cfg(f128_enabled)] +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +mod float_addsub_f128_ppc { + use super::*; + + float_sum! { + f128, __addkf3, __subkf3, Quad, not(feature = "no-sys-f128"); + } +} diff --git a/library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs b/library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs new file mode 100644 index 00000000000..bfd15a391aa --- /dev/null +++ b/library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs @@ -0,0 +1,60 @@ +#![cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem" +))] +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; + +// test runner +extern crate utest_cortex_m_qemu; + +// overrides `panic!` +#[macro_use] +extern crate utest_macros; + +use core::mem; + +macro_rules! panic { + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} + +extern "C" { + fn __aeabi_memclr4(dest: *mut u8, n: usize); + fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); +} + +struct Aligned { + array: [u8; 8], + _alignment: [u32; 0], +} + +impl Aligned { + fn new() -> Self { + Aligned { + array: [0; 8], + _alignment: [], + } + } +} + +#[test] +fn memclr4() { + let mut aligned = Aligned::new(); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + + for n in 0..9 { + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, 0xff); + __aeabi_memclr4(xs.as_mut_ptr(), n); + } + + assert!(xs[0..n].iter().all(|x| *x == 0)); + } +} diff --git a/library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs b/library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs new file mode 100644 index 00000000000..c892c5aba0f --- /dev/null +++ b/library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs @@ -0,0 +1,71 @@ +#![cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem" +))] +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; + +// test runner +extern crate utest_cortex_m_qemu; + +// overrides `panic!` +#[macro_use] +extern crate utest_macros; + +macro_rules! panic { + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} + +extern "C" { + fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize); + fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize); +} + +struct Aligned { + array: [u8; 8], + _alignment: [u32; 0], +} + +impl Aligned { + fn new(array: [u8; 8]) -> Self { + Aligned { + array: array, + _alignment: [], + } + } +} + +#[test] +fn memcpy() { + let mut dest = [0; 4]; + let src = [0xde, 0xad, 0xbe, 0xef]; + + for n in 0..dest.len() { + dest.copy_from_slice(&[0; 4]); + + unsafe { __aeabi_memcpy(dest.as_mut_ptr(), src.as_ptr(), n) } + + assert_eq!(&dest[0..n], &src[0..n]) + } +} + +#[test] +fn memcpy4() { + let mut aligned = Aligned::new([0; 8]); + let dest = &mut aligned.array; + let src = [0xde, 0xad, 0xbe, 0xef, 0xba, 0xad, 0xf0, 0x0d]; + + for n in 0..dest.len() { + dest.copy_from_slice(&[0; 8]); + + unsafe { __aeabi_memcpy4(dest.as_mut_ptr(), src.as_ptr(), n) } + + assert_eq!(&dest[0..n], &src[0..n]) + } +} diff --git a/library/compiler-builtins/builtins-test/tests/aeabi_memset.rs b/library/compiler-builtins/builtins-test/tests/aeabi_memset.rs new file mode 100644 index 00000000000..34ab3acc78c --- /dev/null +++ b/library/compiler-builtins/builtins-test/tests/aeabi_memset.rs @@ -0,0 +1,240 @@ +#![cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem" +))] +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; + +// test runner +extern crate utest_cortex_m_qemu; + +// overrides `panic!` +#[macro_use] +extern crate utest_macros; + +use core::mem; + +macro_rules! panic { + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} + +extern "C" { + fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); +} + +struct Aligned { + array: [u8; 8], + _alignment: [u32; 0], +} + +impl Aligned { + fn new(array: [u8; 8]) -> Self { + Aligned { + array: array, + _alignment: [], + } + } +} + +#[test] +fn zero() { + let mut aligned = Aligned::new([0u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), 0, c) } + + assert_eq!(*xs, [0; 8]); + + let mut aligned = Aligned::new([1u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), 0, c) } + + assert_eq!(*xs, [1; 8]); +} + +#[test] +fn one() { + let mut aligned = Aligned::new([0u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 1; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0, 0, 0, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 1, 1, 1, 1, 1, 1, 1]); +} + +#[test] +fn two() { + let mut aligned = Aligned::new([0u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 2; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0xef, 0, 0, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0xef, 1, 1, 1, 1, 1, 1]); +} + +#[test] +fn three() { + let mut aligned = Aligned::new([0u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 3; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 1, 1, 1, 1, 1]); +} + +#[test] +fn four() { + let mut aligned = Aligned::new([0u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 4; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 1, 1, 1, 1]); +} + +#[test] +fn five() { + let mut aligned = Aligned::new([0u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 5; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 1, 1, 1]); +} + +#[test] +fn six() { + let mut aligned = Aligned::new([0u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 6; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1, 1]); +} + +#[test] +fn seven() { + let mut aligned = Aligned::new([0u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 7; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0]); + + let mut aligned = Aligned::new([1u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1]); +} + +#[test] +fn eight() { + let mut aligned = Aligned::new([0u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 8; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); + + let mut aligned = Aligned::new([1u8; 8]); + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); +} diff --git a/library/compiler-builtins/builtins-test/tests/big.rs b/library/compiler-builtins/builtins-test/tests/big.rs new file mode 100644 index 00000000000..d1ae88bd164 --- /dev/null +++ b/library/compiler-builtins/builtins-test/tests/big.rs @@ -0,0 +1,134 @@ +use compiler_builtins::int::{HInt, MinInt, i256, u256}; + +const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; + +/// Print a `u256` as hex since we can't add format implementations +fn hexu(v: u256) -> String { + format!( + "0x{:016x}{:016x}{:016x}{:016x}", + v.0[3], v.0[2], v.0[1], v.0[0] + ) +} + +#[test] +fn widen_u128() { + assert_eq!(u128::MAX.widen(), u256([u64::MAX, u64::MAX, 0, 0])); + assert_eq!( + LOHI_SPLIT.widen(), + u256([u64::MAX, 0xaaaaaaaaaaaaaaaa, 0, 0]) + ); +} + +#[test] +fn widen_i128() { + assert_eq!((-1i128).widen(), u256::MAX.signed()); + assert_eq!( + (LOHI_SPLIT as i128).widen(), + i256([u64::MAX, 0xaaaaaaaaaaaaaaaa, u64::MAX, u64::MAX]) + ); + assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); +} + +#[test] +fn widen_mul_u128() { + let tests = [ + (u128::MAX / 2, 2_u128, u256([u64::MAX - 1, u64::MAX, 0, 0])), + (u128::MAX, 2_u128, u256([u64::MAX - 1, u64::MAX, 1, 0])), + (u128::MAX, u128::MAX, u256([1, 0, u64::MAX - 1, u64::MAX])), + (u128::MIN, u128::MIN, u256::ZERO), + (1234, 0, u256::ZERO), + (0, 1234, u256::ZERO), + ]; + + let mut errors = Vec::new(); + for (i, (a, b, exp)) in tests.iter().copied().enumerate() { + let res = a.widen_mul(b); + let res_z = a.zero_widen_mul(b); + assert_eq!(res, res_z); + if res != exp { + errors.push((i, a, b, exp, res)); + } + } + + for (i, a, b, exp, res) in &errors { + eprintln!( + "FAILURE ({i}): {a:#034x} * {b:#034x} = {} got {}", + hexu(*exp), + hexu(*res) + ); + } + assert!(errors.is_empty()); +} + +#[test] +fn not_u128() { + assert_eq!(!u256::ZERO, u256::MAX); +} + +#[test] +fn shr_u128() { + let only_low = [ + 1, + u16::MAX.into(), + u32::MAX.into(), + u64::MAX.into(), + u128::MAX, + ]; + + let mut errors = Vec::new(); + + for a in only_low { + for perturb in 0..10 { + let a = a.saturating_add(perturb); + for shift in 0..128 { + let res = a.widen() >> shift; + let expected = (a >> shift).widen(); + if res != expected { + errors.push((a.widen(), shift, res, expected)); + } + } + } + } + + let check = [ + ( + u256::MAX, + 1, + u256([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 1]), + ), + ( + u256::MAX, + 5, + u256([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 5]), + ), + (u256::MAX, 63, u256([u64::MAX, u64::MAX, u64::MAX, 1])), + (u256::MAX, 64, u256([u64::MAX, u64::MAX, u64::MAX, 0])), + (u256::MAX, 65, u256([u64::MAX, u64::MAX, u64::MAX >> 1, 0])), + (u256::MAX, 127, u256([u64::MAX, u64::MAX, 1, 0])), + (u256::MAX, 128, u256([u64::MAX, u64::MAX, 0, 0])), + (u256::MAX, 129, u256([u64::MAX, u64::MAX >> 1, 0, 0])), + (u256::MAX, 191, u256([u64::MAX, 1, 0, 0])), + (u256::MAX, 192, u256([u64::MAX, 0, 0, 0])), + (u256::MAX, 193, u256([u64::MAX >> 1, 0, 0, 0])), + (u256::MAX, 191, u256([u64::MAX, 1, 0, 0])), + (u256::MAX, 254, u256([0b11, 0, 0, 0])), + (u256::MAX, 255, u256([1, 0, 0, 0])), + ]; + + for (input, shift, expected) in check { + let res = input >> shift; + if res != expected { + errors.push((input, shift, res, expected)); + } + } + + for (a, b, res, expected) in &errors { + eprintln!( + "FAILURE: {} >> {b} = {} got {}", + hexu(*a), + hexu(*expected), + hexu(*res), + ); + } + assert!(errors.is_empty()); +} diff --git a/library/compiler-builtins/builtins-test/tests/cmp.rs b/library/compiler-builtins/builtins-test/tests/cmp.rs new file mode 100644 index 00000000000..dbedd213e90 --- /dev/null +++ b/library/compiler-builtins/builtins-test/tests/cmp.rs @@ -0,0 +1,185 @@ +#![allow(unused_macros)] +#![allow(unreachable_code)] +#![cfg_attr(f128_enabled, feature(f128))] + +use builtins_test::*; + +mod float_comparisons { + use super::*; + + macro_rules! cmp { + ( + $f:ty, $x:ident, $y:ident, $apfloat_ty:ident, $sys_available:meta, + $($unordered_val:expr, $fn:ident);*; + ) => { + $( + let cmp0 = if apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |x: FloatTy| x.is_nan() => no_convert, + $x + ) || apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |y: FloatTy| y.is_nan() => no_convert, + $y + ) + { + $unordered_val + } else if apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |x, y| x < y => no_convert, + $x, $y + ) { + -1 + } else if apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |x, y| x == y => no_convert, + $x, $y + ) { + 0 + } else { + 1 + }; + + let cmp1 = $fn($x, $y); + if cmp0 != cmp1 { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), $x, $y, cmp0, cmp1 + ); + } + )* + }; + } + + #[test] + fn cmp_f32() { + use compiler_builtins::float::cmp::{ + __eqsf2, __gesf2, __gtsf2, __lesf2, __ltsf2, __nesf2, __unordsf2, + }; + + fuzz_float_2(N, |x: f32, y: f32| { + assert_eq!(__unordsf2(x, y) != 0, x.is_nan() || y.is_nan()); + cmp!(f32, x, y, Single, all(), + 1, __ltsf2; + 1, __lesf2; + 1, __eqsf2; + -1, __gesf2; + -1, __gtsf2; + 1, __nesf2; + ); + }); + } + + #[test] + fn cmp_f64() { + use compiler_builtins::float::cmp::{ + __eqdf2, __gedf2, __gtdf2, __ledf2, __ltdf2, __nedf2, __unorddf2, + }; + + fuzz_float_2(N, |x: f64, y: f64| { + assert_eq!(__unorddf2(x, y) != 0, x.is_nan() || y.is_nan()); + cmp!(f64, x, y, Double, all(), + 1, __ltdf2; + 1, __ledf2; + 1, __eqdf2; + -1, __gedf2; + -1, __gtdf2; + 1, __nedf2; + ); + }); + } + + #[test] + #[cfg(f128_enabled)] + fn cmp_f128() { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + use compiler_builtins::float::cmp::{ + __eqkf2 as __eqtf2, __gekf2 as __getf2, __gtkf2 as __gttf2, __lekf2 as __letf2, + __ltkf2 as __lttf2, __nekf2 as __netf2, __unordkf2 as __unordtf2, + }; + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + use compiler_builtins::float::cmp::{ + __eqtf2, __getf2, __gttf2, __letf2, __lttf2, __netf2, __unordtf2, + }; + + fuzz_float_2(N, |x: f128, y: f128| { + let x_is_nan = apfloat_fallback!( + f128, Quad, not(feature = "no-sys-f128"), + |x: FloatTy| x.is_nan() => no_convert, + x + ); + let y_is_nan = apfloat_fallback!( + f128, Quad, not(feature = "no-sys-f128"), + |x: FloatTy| x.is_nan() => no_convert, + y + ); + + assert_eq!(__unordtf2(x, y) != 0, x_is_nan || y_is_nan); + + cmp!(f128, x, y, Quad, not(feature = "no-sys-f128"), + 1, __lttf2; + 1, __letf2; + 1, __eqtf2; + -1, __getf2; + -1, __gttf2; + 1, __netf2; + ); + }); + } +} + +#[cfg(target_arch = "arm")] +mod float_comparisons_arm { + use super::*; + + macro_rules! cmp2 { + ($x:ident, $y:ident, $($unordered_val:expr, $fn_std:expr, $fn_builtins:ident);*;) => { + $( + let cmp0: i32 = if $x.is_nan() || $y.is_nan() { + $unordered_val + } else { + $fn_std as i32 + }; + let cmp1: i32 = $fn_builtins($x, $y); + if cmp0 != cmp1 { + panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1); + } + )* + }; + } + + #[test] + fn cmp_f32() { + use compiler_builtins::float::cmp::{ + __aeabi_fcmpeq, __aeabi_fcmpge, __aeabi_fcmpgt, __aeabi_fcmple, __aeabi_fcmplt, + }; + + fuzz_float_2(N, |x: f32, y: f32| { + cmp2!(x, y, + 0, x < y, __aeabi_fcmplt; + 0, x <= y, __aeabi_fcmple; + 0, x == y, __aeabi_fcmpeq; + 0, x >= y, __aeabi_fcmpge; + 0, x > y, __aeabi_fcmpgt; + ); + }); + } + + #[test] + fn cmp_f64() { + use compiler_builtins::float::cmp::{ + __aeabi_dcmpeq, __aeabi_dcmpge, __aeabi_dcmpgt, __aeabi_dcmple, __aeabi_dcmplt, + }; + + fuzz_float_2(N, |x: f64, y: f64| { + cmp2!(x, y, + 0, x < y, __aeabi_dcmplt; + 0, x <= y, __aeabi_dcmple; + 0, x == y, __aeabi_dcmpeq; + 0, x >= y, __aeabi_dcmpge; + 0, x > y, __aeabi_dcmpgt; + ); + }); + } +} diff --git a/library/compiler-builtins/builtins-test/tests/conv.rs b/library/compiler-builtins/builtins-test/tests/conv.rs new file mode 100644 index 00000000000..491915d9bb1 --- /dev/null +++ b/library/compiler-builtins/builtins-test/tests/conv.rs @@ -0,0 +1,364 @@ +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] +// makes configuration easier +#![allow(unused_macros)] +#![allow(unused_imports)] + +use builtins_test::*; +use compiler_builtins::float::Float; +use rustc_apfloat::{Float as _, FloatConvert as _}; + +mod i_to_f { + use super::*; + + macro_rules! i_to_f { + ($f_ty:ty, $apfloat_ty:ident, $sys_available:meta, $($i_ty:ty, $fn:ident);*;) => { + $( + #[test] + fn $fn() { + use compiler_builtins::float::conv::$fn; + use compiler_builtins::int::Int; + + fuzz(N, |x: $i_ty| { + let f0 = apfloat_fallback!( + $f_ty, $apfloat_ty, $sys_available, + |x| x as $f_ty; + // When the builtin is not available, we need to use a different conversion + // method (since apfloat doesn't support `as` casting). + |x: $i_ty| { + use compiler_builtins::int::MinInt; + + let apf = if <$i_ty>::SIGNED { + FloatTy::from_i128(x.try_into().unwrap()).value + } else { + FloatTy::from_u128(x.try_into().unwrap()).value + }; + + <$f_ty>::from_bits(apf.to_bits()) + }, + x + ); + let f1: $f_ty = $fn(x); + + #[cfg($sys_available)] { + // This makes sure that the conversion produced the best rounding possible, and does + // this independent of `x as $into` rounding correctly. + // This assumes that float to integer conversion is correct. + let y_minus_ulp = <$f_ty>::from_bits(f1.to_bits().wrapping_sub(1)) as $i_ty; + let y = f1 as $i_ty; + let y_plus_ulp = <$f_ty>::from_bits(f1.to_bits().wrapping_add(1)) as $i_ty; + let error_minus = <$i_ty as Int>::abs_diff(y_minus_ulp, x); + let error = <$i_ty as Int>::abs_diff(y, x); + let error_plus = <$i_ty as Int>::abs_diff(y_plus_ulp, x); + + // The first two conditions check that none of the two closest float values are + // strictly closer in representation to `x`. The second makes sure that rounding is + // towards even significand if two float values are equally close to the integer. + if error_minus < error + || error_plus < error + || ((error_minus == error || error_plus == error) + && ((f0.to_bits() & 1) != 0)) + { + if !cfg!(any( + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + panic!( + "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", + stringify!($fn), + x, + f1.to_bits(), + y_minus_ulp, + y, + y_plus_ulp, + error_minus, + error, + error_plus, + ); + } + } + } + + // Test against native conversion. We disable testing on all `x86` because of + // rounding bugs with `i686`. `powerpc` also has the same rounding bug. + if !Float::eq_repr(f0, f1) && !cfg!(any( + target_arch = "x86", + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + panic!( + "{}({}): std: {:?}, builtins: {:?}", + stringify!($fn), + x, + f0, + f1, + ); + } + }); + } + )* + }; + } + + i_to_f! { f32, Single, all(), + u32, __floatunsisf; + i32, __floatsisf; + u64, __floatundisf; + i64, __floatdisf; + u128, __floatuntisf; + i128, __floattisf; + } + + i_to_f! { f64, Double, all(), + u32, __floatunsidf; + i32, __floatsidf; + u64, __floatundidf; + i64, __floatdidf; + u128, __floatuntidf; + i128, __floattidf; + } + + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + i_to_f! { f128, Quad, not(feature = "no-sys-f128-int-convert"), + u32, __floatunsitf; + i32, __floatsitf; + u64, __floatunditf; + i64, __floatditf; + u128, __floatuntitf; + i128, __floattitf; + } + + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + i_to_f! { f128, Quad, not(feature = "no-sys-f128-int-convert"), + u32, __floatunsikf; + i32, __floatsikf; + u64, __floatundikf; + i64, __floatdikf; + u128, __floatuntikf; + i128, __floattikf; + } +} + +mod f_to_i { + use super::*; + + macro_rules! f_to_i { + ($x:ident, $f_ty:ty, $apfloat_ty:ident, $sys_available:meta, $($i_ty:ty, $fn:ident);*;) => { + $( + // it is undefined behavior in the first place to do conversions with NaNs + if !apfloat_fallback!( + $f_ty, $apfloat_ty, $sys_available, |x: FloatTy| x.is_nan() => no_convert, $x + ) { + let conv0 = apfloat_fallback!( + $f_ty, $apfloat_ty, $sys_available, + // Use an `as` cast when the builtin is available on the system. + |x| x as $i_ty; + // When the builtin is not available, we need to use a different conversion + // method (since apfloat doesn't support `as` casting). + |x: $f_ty| { + use compiler_builtins::int::MinInt; + + let apf = FloatTy::from_bits(x.to_bits().into()); + let bits: usize = <$i_ty>::BITS.try_into().unwrap(); + + let err_fn = || panic!( + "Unable to convert value {x:?} to type {}:", stringify!($i_ty) + ); + + if <$i_ty>::SIGNED { + <$i_ty>::try_from(apf.to_i128(bits).value).ok().unwrap_or_else(err_fn) + } else { + <$i_ty>::try_from(apf.to_u128(bits).value).ok().unwrap_or_else(err_fn) + } + }, + $x + ); + let conv1: $i_ty = $fn($x); + if conv0 != conv1 { + panic!("{}({:?}): std: {:?}, builtins: {:?}", stringify!($fn), $x, conv0, conv1); + } + } + )* + }; + } + + #[test] + fn f32_to_int() { + use compiler_builtins::float::conv::{ + __fixsfdi, __fixsfsi, __fixsfti, __fixunssfdi, __fixunssfsi, __fixunssfti, + }; + + fuzz_float(N, |x: f32| { + f_to_i!(x, f32, Single, all(), + u32, __fixunssfsi; + u64, __fixunssfdi; + u128, __fixunssfti; + i32, __fixsfsi; + i64, __fixsfdi; + i128, __fixsfti; + ); + }); + } + + #[test] + fn f64_to_int() { + use compiler_builtins::float::conv::{ + __fixdfdi, __fixdfsi, __fixdfti, __fixunsdfdi, __fixunsdfsi, __fixunsdfti, + }; + + fuzz_float(N, |x: f64| { + f_to_i!(x, f64, Double, all(), + u32, __fixunsdfsi; + u64, __fixunsdfdi; + u128, __fixunsdfti; + i32, __fixdfsi; + i64, __fixdfdi; + i128, __fixdfti; + ); + }); + } + + #[test] + #[cfg(f128_enabled)] + fn f128_to_int() { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + use compiler_builtins::float::conv::{ + __fixkfdi as __fixtfdi, __fixkfsi as __fixtfsi, __fixkfti as __fixtfti, + __fixunskfdi as __fixunstfdi, __fixunskfsi as __fixunstfsi, + __fixunskfti as __fixunstfti, + }; + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + use compiler_builtins::float::conv::{ + __fixtfdi, __fixtfsi, __fixtfti, __fixunstfdi, __fixunstfsi, __fixunstfti, + }; + + fuzz_float(N, |x: f128| { + f_to_i!( + x, + f128, + Quad, + not(feature = "no-sys-f128-int-convert"), + u32, __fixunstfsi; + u64, __fixunstfdi; + u128, __fixunstfti; + i32, __fixtfsi; + i64, __fixtfdi; + i128, __fixtfti; + ); + }); + } +} + +macro_rules! f_to_f { + ( + $mod:ident, + $( + $from_ty:ty => $to_ty:ty, + $from_ap_ty:ident => $to_ap_ty:ident, + $fn:ident, $sys_available:meta + );+; + ) => {$( + #[test] + fn $fn() { + use compiler_builtins::float::{$mod::$fn, Float}; + use rustc_apfloat::ieee::{$from_ap_ty, $to_ap_ty}; + + fuzz_float(N, |x: $from_ty| { + let tmp0: $to_ty = apfloat_fallback!( + $from_ty, + $from_ap_ty, + $sys_available, + |x: $from_ty| x as $to_ty; + |x: $from_ty| { + let from_apf = FloatTy::from_bits(x.to_bits().into()); + // Get `value` directly to ignore INVALID_OP + let to_apf: $to_ap_ty = from_apf.convert(&mut false).value; + <$to_ty>::from_bits(to_apf.to_bits().try_into().unwrap()) + }, + x + ); + let tmp1: $to_ty = $fn(x); + + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({:?}): std: {:?}, builtins: {:?}", + stringify!($fn), + x, + tmp0, + tmp1 + ); + } + }) + } + )+}; +} + +mod extend { + use super::*; + + f_to_f! { + extend, + f32 => f64, Single => Double, __extendsfdf2, all(); + } + + #[cfg(all(f16_enabled, f128_enabled))] + #[cfg(not(any( + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "loongarch64" + )))] + f_to_f! { + extend, + f16 => f32, Half => Single, __extendhfsf2, not(feature = "no-sys-f16"); + f16 => f32, Half => Single, __gnu_h2f_ieee, not(feature = "no-sys-f16"); + f16 => f64, Half => Double, __extendhfdf2, not(feature = "no-sys-f16-f64-convert"); + f16 => f128, Half => Quad, __extendhftf2, not(feature = "no-sys-f16-f128-convert"); + f32 => f128, Single => Quad, __extendsftf2, not(feature = "no-sys-f128"); + f64 => f128, Double => Quad, __extenddftf2, not(feature = "no-sys-f128"); + } + + #[cfg(f128_enabled)] + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + f_to_f! { + extend, + // FIXME(#655): `f16` tests disabled until we can bootstrap symbols + f32 => f128, Single => Quad, __extendsfkf2, not(feature = "no-sys-f128"); + f64 => f128, Double => Quad, __extenddfkf2, not(feature = "no-sys-f128"); + } +} + +mod trunc { + use super::*; + + f_to_f! { + trunc, + f64 => f32, Double => Single, __truncdfsf2, all(); + } + + #[cfg(all(f16_enabled, f128_enabled))] + #[cfg(not(any( + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "loongarch64" + )))] + f_to_f! { + trunc, + f32 => f16, Single => Half, __truncsfhf2, not(feature = "no-sys-f16"); + f32 => f16, Single => Half, __gnu_f2h_ieee, not(feature = "no-sys-f16"); + f64 => f16, Double => Half, __truncdfhf2, not(feature = "no-sys-f16-f64-convert"); + f128 => f16, Quad => Half, __trunctfhf2, not(feature = "no-sys-f16-f128-convert"); + f128 => f32, Quad => Single, __trunctfsf2, not(feature = "no-sys-f128"); + f128 => f64, Quad => Double, __trunctfdf2, not(feature = "no-sys-f128"); + } + + #[cfg(f128_enabled)] + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + f_to_f! { + trunc, + // FIXME(#655): `f16` tests disabled until we can bootstrap symbols + f128 => f32, Quad => Single, __trunckfsf2, not(feature = "no-sys-f128"); + f128 => f64, Quad => Double, __trunckfdf2, not(feature = "no-sys-f128"); + } +} diff --git a/library/compiler-builtins/builtins-test/tests/div_rem.rs b/library/compiler-builtins/builtins-test/tests/div_rem.rs new file mode 100644 index 00000000000..6c0280a3286 --- /dev/null +++ b/library/compiler-builtins/builtins-test/tests/div_rem.rs @@ -0,0 +1,165 @@ +#![feature(f128)] +#![allow(unused_macros)] + +use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; +use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc}; + +use builtins_test::*; + +// Division algorithms have by far the nastiest and largest number of edge cases, and experience shows +// that sometimes 100_000 iterations of the random fuzzer is needed. + +/// Creates intensive test functions for division functions of a certain size +macro_rules! test { + ( + $n:expr, // the number of bits in a $iX or $uX + $uX:ident, // unsigned integer that will be shifted + $iX:ident, // signed version of $uX + $test_name:ident, // name of the test function + $unsigned_name:ident, // unsigned division function + $signed_name:ident // signed division function + ) => { + #[test] + fn $test_name() { + fuzz_2(N, |lhs, rhs| { + if rhs == 0 { + return; + } + + let mut rem: $uX = 0; + let quo: $uX = $unsigned_name(lhs, rhs, Some(&mut rem)); + if rhs <= rem || (lhs != rhs.wrapping_mul(quo).wrapping_add(rem)) { + panic!( + "unsigned division function failed with lhs:{} rhs:{} \ + std:({}, {}) builtins:({}, {})", + lhs, + rhs, + lhs.wrapping_div(rhs), + lhs.wrapping_rem(rhs), + quo, + rem + ); + } + + // test the signed division function also + let lhs = lhs as $iX; + let rhs = rhs as $iX; + let mut rem: $iX = 0; + let quo: $iX = $signed_name(lhs, rhs, &mut rem); + // We cannot just test that + // `lhs == rhs.wrapping_mul(quo).wrapping_add(rem)`, but also + // need to make sure the remainder isn't larger than the divisor + // and has the correct sign. + let incorrect_rem = if rem == 0 { + false + } else if rhs == $iX::MIN { + // `rhs.wrapping_abs()` would overflow, so handle this case + // separately. + (lhs.is_negative() != rem.is_negative()) || (rem == $iX::MIN) + } else { + (lhs.is_negative() != rem.is_negative()) + || (rhs.wrapping_abs() <= rem.wrapping_abs()) + }; + if incorrect_rem || lhs != rhs.wrapping_mul(quo).wrapping_add(rem) { + panic!( + "signed division function failed with lhs:{} rhs:{} \ + std:({}, {}) builtins:({}, {})", + lhs, + rhs, + lhs.wrapping_div(rhs), + lhs.wrapping_rem(rhs), + quo, + rem + ); + } + }); + } + }; +} + +test!(32, u32, i32, div_rem_si4, __udivmodsi4, __divmodsi4); +test!(64, u64, i64, div_rem_di4, __udivmoddi4, __divmoddi4); +test!(128, u128, i128, div_rem_ti4, __udivmodti4, __divmodti4); + +#[test] +fn divide_sparc() { + fuzz_2(N, |lhs, rhs| { + if rhs == 0 { + return; + } + + let mut rem: u128 = 0; + let quo: u128 = u128_divide_sparc(lhs, rhs, &mut rem); + if rhs <= rem || (lhs != rhs.wrapping_mul(quo).wrapping_add(rem)) { + panic!( + "u128_divide_sparc({}, {}): \ + std:({}, {}), builtins:({}, {})", + lhs, + rhs, + lhs.wrapping_div(rhs), + lhs.wrapping_rem(rhs), + quo, + rem + ); + } + }); +} + +macro_rules! float { + ($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { + $( + #[test] + fn $fn() { + use compiler_builtins::float::{div::$fn, Float}; + use core::ops::Div; + + fuzz_float_2(N, |x: $f, y: $f| { + let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y); + let quo1: $f = $fn(x, y); + + // ARM SIMD instructions always flush subnormals to zero + if cfg!(target_arch = "arm") && + ((Float::is_subnormal(quo0)) || Float::is_subnormal(quo1)) { + return; + } + + if !Float::eq_repr(quo0, quo1) { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), + x, + y, + quo0, + quo1 + ); + } + }); + } + )* + }; +} + +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +mod float_div { + use super::*; + + float! { + f32, __divsf3, Single, all(); + f64, __divdf3, Double, all(); + } + + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + float! { + f128, __divtf3, Quad, + // FIXME(llvm): there is a bug in LLVM rt. + // See . + not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux"))); + } + + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + float! { + f128, __divkf3, Quad, not(feature = "no-sys-f128"); + } +} diff --git a/library/compiler-builtins/builtins-test/tests/float_pow.rs b/library/compiler-builtins/builtins-test/tests/float_pow.rs new file mode 100644 index 00000000000..8209543e666 --- /dev/null +++ b/library/compiler-builtins/builtins-test/tests/float_pow.rs @@ -0,0 +1,72 @@ +#![allow(unused_macros)] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] + +use builtins_test::*; + +// This is approximate because of issues related to +// https://github.com/rust-lang/rust/issues/73920. +// TODO how do we resolve this indeterminacy? +macro_rules! pow { + ($($f:ty, $tolerance:expr, $fn:ident, $sys_available:meta);*;) => { + $( + #[test] + // FIXME(apfloat): We skip tests if system symbols aren't available rather + // than providing a fallback, since `rustc_apfloat` does not provide `pow`. + #[cfg($sys_available)] + fn $fn() { + use compiler_builtins::float::pow::$fn; + use compiler_builtins::float::Float; + fuzz_float_2(N, |x: $f, y: $f| { + if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) { + let n = y.to_bits() & !<$f as Float>::SIG_MASK; + let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIG_BITS; + let n = n as i32; + let tmp0: $f = x.powi(n); + let tmp1: $f = $fn(x, n); + let (a, b) = if tmp0 < tmp1 { + (tmp0, tmp1) + } else { + (tmp1, tmp0) + }; + + let good = if a == b { + // handles infinity equality + true + } else if a < $tolerance { + b < $tolerance + } else { + let quo = b / a; + (quo < (1. + $tolerance)) && (quo > (1. - $tolerance)) + }; + + assert!( + good, + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), x, n, tmp0, tmp1 + ); + } + }); + } + )* + }; +} + +pow! { + f32, 1e-4, __powisf2, all(); + f64, 1e-12, __powidf2, all(); +} + +#[cfg(f128_enabled)] +// FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly. +#[cfg(not(target_env = "msvc"))] +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] +pow! { + f128, 1e-36, __powitf2, not(feature = "no-sys-f128"); +} + +#[cfg(f128_enabled)] +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +pow! { + f128, 1e-36, __powikf2, not(feature = "no-sys-f128"); +} diff --git a/library/compiler-builtins/builtins-test/tests/lse.rs b/library/compiler-builtins/builtins-test/tests/lse.rs new file mode 100644 index 00000000000..53167d98fc0 --- /dev/null +++ b/library/compiler-builtins/builtins-test/tests/lse.rs @@ -0,0 +1,97 @@ +#![feature(decl_macro)] // so we can use pub(super) +#![cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm")))] + +/// Translate a byte size to a Rust type. +macro int_ty { + (1) => { i8 }, + (2) => { i16 }, + (4) => { i32 }, + (8) => { i64 }, + (16) => { i128 } +} + +mod cas { + pub(super) macro test($_ordering:ident, $bytes:tt, $name:ident) { + #[test] + fn $name() { + builtins_test::fuzz_2(10000, |expected: super::int_ty!($bytes), new| { + let mut target = expected.wrapping_add(10); + assert_eq!( + unsafe { + compiler_builtins::aarch64_linux::$name::$name(expected, new, &mut target) + }, + expected.wrapping_add(10), + "return value should always be the previous value", + ); + assert_eq!( + target, + expected.wrapping_add(10), + "shouldn't have changed target" + ); + + target = expected; + assert_eq!( + unsafe { + compiler_builtins::aarch64_linux::$name::$name(expected, new, &mut target) + }, + expected + ); + assert_eq!(target, new, "should have updated target"); + }); + } + } +} + +macro test_cas16($_ordering:ident, $name:ident) { + cas::test!($_ordering, 16, $name); +} + +mod swap { + pub(super) macro test($_ordering:ident, $bytes:tt, $name:ident) { + #[test] + fn $name() { + builtins_test::fuzz_2(10000, |left: super::int_ty!($bytes), mut right| { + let orig_right = right; + assert_eq!( + unsafe { compiler_builtins::aarch64_linux::$name::$name(left, &mut right) }, + orig_right + ); + assert_eq!(left, right); + }); + } + } +} + +macro_rules! test_op { + ($mod:ident, $( $op:tt )* ) => { + mod $mod { + pub(super) macro test { + ($_ordering:ident, $bytes:tt, $name:ident) => { + #[test] + fn $name() { + builtins_test::fuzz_2(10000, |old, val| { + let mut target = old; + let op: fn(super::int_ty!($bytes), super::int_ty!($bytes)) -> _ = $($op)*; + let expected = op(old, val); + assert_eq!(old, unsafe { compiler_builtins::aarch64_linux::$name::$name(val, &mut target) }, "{} should return original value", stringify!($name)); + assert_eq!(expected, target, "{} should store to target", stringify!($name)); + }); + } + } + } + } + }; +} + +test_op!(add, |left, right| left.wrapping_add(right)); +test_op!(clr, |left, right| left & !right); +test_op!(xor, std::ops::BitXor::bitxor); +test_op!(or, std::ops::BitOr::bitor); + +compiler_builtins::foreach_cas!(cas::test); +compiler_builtins::foreach_cas16!(test_cas16); +compiler_builtins::foreach_swp!(swap::test); +compiler_builtins::foreach_ldadd!(add::test); +compiler_builtins::foreach_ldclr!(clr::test); +compiler_builtins::foreach_ldeor!(xor::test); +compiler_builtins::foreach_ldset!(or::test); diff --git a/library/compiler-builtins/builtins-test/tests/mem.rs b/library/compiler-builtins/builtins-test/tests/mem.rs new file mode 100644 index 00000000000..d838ef159a0 --- /dev/null +++ b/library/compiler-builtins/builtins-test/tests/mem.rs @@ -0,0 +1,286 @@ +extern crate compiler_builtins; +use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; + +const WORD_SIZE: usize = core::mem::size_of::(); + +#[test] +fn memcpy_3() { + let mut arr: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + unsafe { + let src = arr.as_ptr().offset(9); + let dst = arr.as_mut_ptr().offset(1); + assert_eq!(memcpy(dst, src, 3), dst); + assert_eq!(arr, [0, 9, 10, 11, 4, 5, 6, 7, 8, 9, 10, 11]); + } + arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + unsafe { + let src = arr.as_ptr().offset(1); + let dst = arr.as_mut_ptr().offset(9); + assert_eq!(memcpy(dst, src, 3), dst); + assert_eq!(arr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3]); + } +} + +#[test] +fn memcpy_10() { + let arr: [u8; 18] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]; + let mut dst: [u8; 12] = [0; 12]; + unsafe { + let src = arr.as_ptr().offset(1); + assert_eq!(memcpy(dst.as_mut_ptr(), src, 10), dst.as_mut_ptr()); + assert_eq!(dst, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0]); + } + unsafe { + let src = arr.as_ptr().offset(8); + assert_eq!(memcpy(dst.as_mut_ptr(), src, 10), dst.as_mut_ptr()); + assert_eq!(dst, [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0, 0]); + } +} + +#[test] +fn memcpy_big() { + // Make the arrays cross 3 pages + const SIZE: usize = 8193; + let src: [u8; SIZE] = [22; SIZE]; + struct Dst { + start: usize, + buf: [u8; SIZE], + end: usize, + } + + let mut dst = Dst { + start: 0, + buf: [0; SIZE], + end: 0, + }; + unsafe { + assert_eq!( + memcpy(dst.buf.as_mut_ptr(), src.as_ptr(), SIZE), + dst.buf.as_mut_ptr() + ); + assert_eq!(dst.start, 0); + assert_eq!(dst.buf, [22; SIZE]); + assert_eq!(dst.end, 0); + } +} + +#[test] +fn memmove_forward() { + let mut arr: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + unsafe { + let src = arr.as_ptr().offset(6); + let dst = arr.as_mut_ptr().offset(3); + assert_eq!(memmove(dst, src, 5), dst); + assert_eq!(arr, [0, 1, 2, 6, 7, 8, 9, 10, 8, 9, 10, 11]); + } +} + +#[test] +fn memmove_backward() { + let mut arr: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + unsafe { + let src = arr.as_ptr().offset(3); + let dst = arr.as_mut_ptr().offset(6); + assert_eq!(memmove(dst, src, 5), dst); + assert_eq!(arr, [0, 1, 2, 3, 4, 5, 3, 4, 5, 6, 7, 11]); + } +} + +#[test] +fn memset_zero() { + let mut arr: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; + unsafe { + let ptr = arr.as_mut_ptr().offset(5); + assert_eq!(memset(ptr, 0, 2), ptr); + assert_eq!(arr, [0, 1, 2, 3, 4, 0, 0, 7]); + + // Only the LSB matters for a memset + assert_eq!(memset(arr.as_mut_ptr(), 0x2000, 8), arr.as_mut_ptr()); + assert_eq!(arr, [0, 0, 0, 0, 0, 0, 0, 0]); + } +} + +#[test] +fn memset_nonzero() { + let mut arr: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; + unsafe { + let ptr = arr.as_mut_ptr().offset(2); + assert_eq!(memset(ptr, 22, 3), ptr); + assert_eq!(arr, [0, 1, 22, 22, 22, 5, 6, 7]); + + // Only the LSB matters for a memset + assert_eq!(memset(arr.as_mut_ptr(), 0x2009, 8), arr.as_mut_ptr()); + assert_eq!(arr, [9, 9, 9, 9, 9, 9, 9, 9]); + } +} + +#[test] +fn memcmp_eq() { + let arr1 @ arr2 = gen_arr::<256>(); + for i in 0..256 { + unsafe { + assert_eq!(memcmp(arr1.0.as_ptr(), arr2.0.as_ptr(), i), 0); + assert_eq!(memcmp(arr2.0.as_ptr(), arr1.0.as_ptr(), i), 0); + } + } +} + +#[test] +fn memcmp_ne() { + let arr1 @ arr2 = gen_arr::<256>(); + // Reduce iteration count in Miri as it is too slow otherwise. + let limit = if cfg!(miri) { 64 } else { 256 }; + for i in 0..limit { + let mut diff_arr = arr1; + diff_arr.0[i] = 127; + let expect = diff_arr.0[i].cmp(&arr2.0[i]); + for k in i + 1..limit { + let result = unsafe { memcmp(diff_arr.0.as_ptr(), arr2.0.as_ptr(), k) }; + assert_eq!(expect, result.cmp(&0)); + } + } +} + +#[derive(Clone, Copy)] +struct AlignedStorage([u8; N], [usize; 0]); + +fn gen_arr() -> AlignedStorage { + let mut ret = AlignedStorage::([0; N], []); + for i in 0..N { + ret.0[i] = i as u8; + } + ret +} + +#[test] +fn memmove_forward_misaligned_nonaligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().offset(6); + let dst = arr.0.as_mut_ptr().offset(3); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(6..6 + 17, 3); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_forward_misaligned_aligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().offset(6); + let dst = arr.0.as_mut_ptr().add(0); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(6..6 + 17, 0); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_forward_aligned() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().add(3 + WORD_SIZE); + let dst = arr.0.as_mut_ptr().add(3); + assert_eq!(memmove(dst, src, 17), dst); + reference + .0 + .copy_within(3 + WORD_SIZE..3 + WORD_SIZE + 17, 3); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_backward_misaligned_nonaligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().offset(3); + let dst = arr.0.as_mut_ptr().offset(6); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(3..3 + 17, 6); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_backward_misaligned_aligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().offset(3); + let dst = arr.0.as_mut_ptr().add(WORD_SIZE); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(3..3 + 17, WORD_SIZE); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_backward_aligned() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().add(3); + let dst = arr.0.as_mut_ptr().add(3 + WORD_SIZE); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(3..3 + 17, 3 + WORD_SIZE); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_misaligned_bounds() { + // The above test have the downside that the addresses surrounding the range-to-copy are all + // still in-bounds, so Miri would not actually complain about OOB accesses. So we also test with + // an array that has just the right size. We test a few times to avoid it being accidentally + // aligned. + for _ in 0..8 { + let mut arr1 = [0u8; 17]; + let mut arr2 = [0u8; 17]; + unsafe { + // Copy both ways so we hit both the forward and backward cases. + memmove(arr1.as_mut_ptr(), arr2.as_mut_ptr(), 17); + memmove(arr2.as_mut_ptr(), arr1.as_mut_ptr(), 17); + } + } +} + +#[test] +fn memset_backward_misaligned_nonaligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let ptr = arr.0.as_mut_ptr().offset(6); + assert_eq!(memset(ptr, 0xCC, 17), ptr); + core::ptr::write_bytes(reference.0.as_mut_ptr().add(6), 0xCC, 17); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memset_backward_misaligned_aligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let ptr = arr.0.as_mut_ptr().add(WORD_SIZE); + assert_eq!(memset(ptr, 0xCC, 17), ptr); + core::ptr::write_bytes(reference.0.as_mut_ptr().add(WORD_SIZE), 0xCC, 17); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memset_backward_aligned() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let ptr = arr.0.as_mut_ptr().add(3 + WORD_SIZE); + assert_eq!(memset(ptr, 0xCC, 17), ptr); + core::ptr::write_bytes(reference.0.as_mut_ptr().add(3 + WORD_SIZE), 0xCC, 17); + assert_eq!(arr.0, reference.0); + } +} diff --git a/library/compiler-builtins/builtins-test/tests/misc.rs b/library/compiler-builtins/builtins-test/tests/misc.rs new file mode 100644 index 00000000000..b8c75c02653 --- /dev/null +++ b/library/compiler-builtins/builtins-test/tests/misc.rs @@ -0,0 +1,208 @@ +// makes configuration easier +#![allow(unused_macros)] + +use builtins_test::*; + +/// Make sure that the the edge case tester and randomized tester don't break, and list examples of +/// fuzz values for documentation purposes. +#[test] +fn fuzz_values() { + const VALS: [u16; 47] = [ + 0b0, // edge cases + 0b1111111111111111, + 0b1111111111111110, + 0b1111111111111100, + 0b1111111110000000, + 0b1111111100000000, + 0b1110000000000000, + 0b1100000000000000, + 0b1000000000000000, + 0b111111111111111, + 0b111111111111110, + 0b111111111111100, + 0b111111110000000, + 0b111111100000000, + 0b110000000000000, + 0b100000000000000, + 0b11111111111111, + 0b11111111111110, + 0b11111111111100, + 0b11111110000000, + 0b11111100000000, + 0b10000000000000, + 0b111111111, + 0b111111110, + 0b111111100, + 0b110000000, + 0b100000000, + 0b11111111, + 0b11111110, + 0b11111100, + 0b10000000, + 0b111, + 0b110, + 0b100, + 0b11, + 0b10, + 0b1, + 0b1010110100000, // beginning of random fuzzing + 0b1100011001011010, + 0b1001100101001111, + 0b1101010100011010, + 0b100010001, + 0b1000000000000000, + 0b1100000000000101, + 0b1100111101010101, + 0b1100010111111111, + 0b1111110101111111, + ]; + let mut i = 0; + fuzz(10, |x: u16| { + assert_eq!(x, VALS[i]); + i += 1; + }); +} + +#[test] +fn leading_zeros() { + use compiler_builtins::int::leading_zeros::{leading_zeros_default, leading_zeros_riscv}; + { + use compiler_builtins::int::leading_zeros::__clzsi2; + fuzz(N, |x: u32| { + if x == 0 { + return; // undefined value for an intrinsic + } + let lz = x.leading_zeros() as usize; + let lz0 = __clzsi2(x); + let lz1 = leading_zeros_default(x); + let lz2 = leading_zeros_riscv(x); + if lz0 != lz { + panic!("__clzsi2({}): std: {}, builtins: {}", x, lz, lz0); + } + if lz1 != lz { + panic!( + "leading_zeros_default({}): std: {}, builtins: {}", + x, lz, lz1 + ); + } + if lz2 != lz { + panic!("leading_zeros_riscv({}): std: {}, builtins: {}", x, lz, lz2); + } + }); + } + + { + use compiler_builtins::int::leading_zeros::__clzdi2; + fuzz(N, |x: u64| { + if x == 0 { + return; // undefined value for an intrinsic + } + let lz = x.leading_zeros() as usize; + let lz0 = __clzdi2(x); + let lz1 = leading_zeros_default(x); + let lz2 = leading_zeros_riscv(x); + if lz0 != lz { + panic!("__clzdi2({}): std: {}, builtins: {}", x, lz, lz0); + } + if lz1 != lz { + panic!( + "leading_zeros_default({}): std: {}, builtins: {}", + x, lz, lz1 + ); + } + if lz2 != lz { + panic!("leading_zeros_riscv({}): std: {}, builtins: {}", x, lz, lz2); + } + }); + } + + { + use compiler_builtins::int::leading_zeros::__clzti2; + fuzz(N, |x: u128| { + if x == 0 { + return; // undefined value for an intrinsic + } + let lz = x.leading_zeros() as usize; + let lz0 = __clzti2(x); + if lz0 != lz { + panic!("__clzti2({}): std: {}, builtins: {}", x, lz, lz0); + } + }); + } +} + +#[test] +fn trailing_zeros() { + use compiler_builtins::int::trailing_zeros::{__ctzdi2, __ctzsi2, __ctzti2, trailing_zeros}; + fuzz(N, |x: u32| { + if x == 0 { + return; // undefined value for an intrinsic + } + let tz = x.trailing_zeros() as usize; + let tz0 = __ctzsi2(x); + let tz1 = trailing_zeros(x); + if tz0 != tz { + panic!("__ctzsi2({}): std: {}, builtins: {}", x, tz, tz0); + } + if tz1 != tz { + panic!("trailing_zeros({}): std: {}, builtins: {}", x, tz, tz1); + } + }); + fuzz(N, |x: u64| { + if x == 0 { + return; // undefined value for an intrinsic + } + let tz = x.trailing_zeros() as usize; + let tz0 = __ctzdi2(x); + let tz1 = trailing_zeros(x); + if tz0 != tz { + panic!("__ctzdi2({}): std: {}, builtins: {}", x, tz, tz0); + } + if tz1 != tz { + panic!("trailing_zeros({}): std: {}, builtins: {}", x, tz, tz1); + } + }); + fuzz(N, |x: u128| { + if x == 0 { + return; // undefined value for an intrinsic + } + let tz = x.trailing_zeros() as usize; + let tz0 = __ctzti2(x); + if tz0 != tz { + panic!("__ctzti2({}): std: {}, builtins: {}", x, tz, tz0); + } + }); +} + +#[test] +fn bswap() { + use compiler_builtins::int::bswap::{__bswapdi2, __bswapsi2}; + fuzz(N, |x: u32| { + assert_eq!(x.swap_bytes(), __bswapsi2(x)); + }); + fuzz(N, |x: u64| { + assert_eq!(x.swap_bytes(), __bswapdi2(x)); + }); + + assert_eq!(__bswapsi2(0x12345678u32), 0x78563412u32); + assert_eq!(__bswapsi2(0x00000001u32), 0x01000000u32); + assert_eq!(__bswapdi2(0x123456789ABCDEF0u64), 0xF0DEBC9A78563412u64); + assert_eq!(__bswapdi2(0x0200000001000000u64), 0x0000000100000002u64); + + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + use compiler_builtins::int::bswap::__bswapti2; + fuzz(N, |x: u128| { + assert_eq!(x.swap_bytes(), __bswapti2(x)); + }); + + assert_eq!( + __bswapti2(0x123456789ABCDEF013579BDF02468ACEu128), + 0xCE8A4602DF9B5713F0DEBC9A78563412u128 + ); + assert_eq!( + __bswapti2(0x04000000030000000200000001000000u128), + 0x00000001000000020000000300000004u128 + ); + } +} diff --git a/library/compiler-builtins/builtins-test/tests/mul.rs b/library/compiler-builtins/builtins-test/tests/mul.rs new file mode 100644 index 00000000000..198cacb3489 --- /dev/null +++ b/library/compiler-builtins/builtins-test/tests/mul.rs @@ -0,0 +1,156 @@ +#![allow(unused_macros)] +#![cfg_attr(f128_enabled, feature(f128))] + +use builtins_test::*; + +mod int_mul { + use super::*; + + macro_rules! mul { + ($($i:ty, $fn:ident);*;) => { + $( + #[test] + fn $fn() { + use compiler_builtins::int::mul::$fn; + + fuzz_2(N, |x: $i, y: $i| { + let mul0 = x.wrapping_mul(y); + let mul1: $i = $fn(x, y); + if mul0 != mul1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, mul0, mul1 + ); + } + }); + + } + )* + }; + } + + mul! { + u64, __muldi3; + i128, __multi3; + } +} + +mod int_overflowing_mul { + use super::*; + + macro_rules! overflowing_mul { + ($($i:ty, $fn:ident);*;) => { + $( + #[test] + fn $fn() { + use compiler_builtins::int::mul::$fn; + + fuzz_2(N, |x: $i, y: $i| { + let (mul0, o0) = x.overflowing_mul(y); + let mut o1 = 0i32; + let mul1: $i = $fn(x, y, &mut o1); + let o1 = o1 != 0; + if mul0 != mul1 || o0 != o1 { + panic!( + "{}({}, {}): std: ({}, {}), builtins: ({}, {})", + stringify!($fn), x, y, mul0, o0, mul1, o1 + ); + } + }); + } + )* + }; + } + + overflowing_mul! { + i32, __mulosi4; + i64, __mulodi4; + i128, __muloti4; + } + + #[test] + fn overflowing_mul_u128() { + use compiler_builtins::int::mul::{__rust_i128_mulo, __rust_u128_mulo}; + + fuzz_2(N, |x: u128, y: u128| { + let mut o1 = 0; + let (mul0, o0) = x.overflowing_mul(y); + let mul1 = __rust_u128_mulo(x, y, &mut o1); + if mul0 != mul1 || i32::from(o0) != o1 { + panic!( + "__rust_u128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", + x, y, mul0, o0, mul1, o1 + ); + } + let x = x as i128; + let y = y as i128; + let (mul0, o0) = x.overflowing_mul(y); + let mul1 = __rust_i128_mulo(x, y, &mut o1); + if mul0 != mul1 || i32::from(o0) != o1 { + panic!( + "__rust_i128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", + x, y, mul0, o0, mul1, o1 + ); + } + }); + } +} + +macro_rules! float_mul { + ($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { + $( + #[test] + fn $fn() { + use compiler_builtins::float::{mul::$fn, Float}; + use core::ops::Mul; + + fuzz_float_2(N, |x: $f, y: $f| { + let mul0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Mul::mul, x, y); + let mul1: $f = $fn(x, y); + if !Float::eq_repr(mul0, mul1) { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), x, y, mul0, mul1 + ); + } + }); + } + )* + }; +} + +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +mod float_mul { + use super::*; + + // FIXME(#616): Stop ignoring arches that don't have native support once fix for builtins is in + // nightly. + float_mul! { + f32, __mulsf3, Single, not(target_arch = "arm"); + f64, __muldf3, Double, not(target_arch = "arm"); + } +} + +#[cfg(f128_enabled)] +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] +mod float_mul_f128 { + use super::*; + + float_mul! { + f128, __multf3, Quad, + // FIXME(llvm): there is a bug in LLVM rt. + // See . + not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux"))); + } +} + +#[cfg(f128_enabled)] +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +mod float_mul_f128_ppc { + use super::*; + + float_mul! { + f128, __mulkf3, Quad, not(feature = "no-sys-f128"); + } +} diff --git a/library/compiler-builtins/builtins-test/tests/shift.rs b/library/compiler-builtins/builtins-test/tests/shift.rs new file mode 100644 index 00000000000..0f2483855e5 --- /dev/null +++ b/library/compiler-builtins/builtins-test/tests/shift.rs @@ -0,0 +1,35 @@ +use builtins_test::*; + +macro_rules! shift { + ($($i:ty, $fn_std:ident, $fn_builtins:ident);*;) => { + $( + #[test] + fn $fn_builtins() { + use compiler_builtins::int::shift::$fn_builtins; + + fuzz_shift(|x: $i, s: u32| { + let tmp0: $i = x.$fn_std(s); + let tmp1: $i = $fn_builtins(x, s); + if tmp0 != tmp1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_builtins), x, s, tmp0, tmp1 + ); + } + }); + } + )* + }; +} + +shift! { + u32, wrapping_shl, __ashlsi3; + u64, wrapping_shl, __ashldi3; + u128, wrapping_shl, __ashlti3; + i32, wrapping_shr, __ashrsi3; + i64, wrapping_shr, __ashrdi3; + i128, wrapping_shr, __ashrti3; + u32, wrapping_shr, __lshrsi3; + u64, wrapping_shr, __lshrdi3; + u128, wrapping_shr, __lshrti3; +} diff --git a/library/compiler-builtins/ci/miri.sh b/library/compiler-builtins/ci/miri.sh index f9a1240a465..79e660bab62 100755 --- a/library/compiler-builtins/ci/miri.sh +++ b/library/compiler-builtins/ci/miri.sh @@ -12,5 +12,5 @@ TARGETS=(x86_64-unknown-linux-gnu s390x-unknown-linux-gnu) for TARGET in "${TARGETS[@]}"; do # Only run the `mem` tests to avoid this taking too long. - cargo miri test --manifest-path testcrate/Cargo.toml --features no-asm --target $TARGET -- mem + cargo miri test --manifest-path builtins-test/Cargo.toml --features no-asm --target $TARGET -- mem done diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 9abbf25a7e7..8dcb139d493 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -23,7 +23,7 @@ fi if [ "${NO_STD:-}" = "1" ]; then echo "nothing to do for no_std" else - run="cargo test --package testcrate --no-fail-fast --target $target" + run="cargo test --package builtins-test --no-fail-fast --target $target" $run $run --release $run --features c @@ -37,8 +37,8 @@ else fi if [ "${TEST_VERBATIM:-}" = "1" ]; then - verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\testcrate\\target2) - cargo build --package testcrate \ + verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\builtins-test\\target2) + cargo build --package builtins-test \ --target "$target" --target-dir "$verb_path" --features c fi diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index eb5b2b9cc88..3151546ab8d 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -68,7 +68,7 @@ mangled-names = [] rustc-dep-of-std = ['compiler-builtins', 'core'] # This makes certain traits and function specializations public that -# are not normally public but are required by the `testcrate` +# are not normally public but are required by the `builtins-test` public-test-deps = [] [lints.rust] diff --git a/library/compiler-builtins/compiler-builtins/configure.rs b/library/compiler-builtins/compiler-builtins/configure.rs index 4be0b3ca23c..d825f35a9aa 100644 --- a/library/compiler-builtins/compiler-builtins/configure.rs +++ b/library/compiler-builtins/compiler-builtins/configure.rs @@ -1,4 +1,4 @@ -// Configuration that is shared between `compiler_builtins` and `testcrate`. +// Configuration that is shared between `compiler_builtins` and `builtins_test`. use std::env; diff --git a/library/compiler-builtins/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/compiler-builtins/src/int/traits.rs index 9b079e2aa59..152cb2eee2e 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/traits.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/traits.rs @@ -48,8 +48,8 @@ pub trait Int: + ops::BitAnd { /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing - /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, - /// 112,119,120,125,126,127]. + /// in `builtins-test`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96, + /// 111,112,119,120,125,126,127]. const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml deleted file mode 100644 index bda2b641d6f..00000000000 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ /dev/null @@ -1,101 +0,0 @@ -[package] -name = "testcrate" -version = "0.1.0" -authors = ["Alex Crichton "] -edition = "2024" -publish = false - -[lib] -test = false -doctest = false - -[dependencies] -# For fuzzing tests we want a deterministic seedable RNG. We also eliminate potential -# problems with system RNGs on the variety of platforms this crate is tested on. -# `xoshiro128**` is used for its quality, size, and speed at generating `u32` shift amounts. -rand_xoshiro = "0.6" -# To compare float builtins against -rustc_apfloat = "0.2.1" -# Really a dev dependency, but dev dependencies can't be optional -iai-callgrind = { version = "0.14.0", optional = true } - -[dependencies.compiler_builtins] -path = "../compiler-builtins" -default-features = false -features = ["public-test-deps"] - -[dev-dependencies] -criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } -paste = "1.0.15" - -[target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] -test = { git = "https://github.com/japaric/utest" } -utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japaric/utest" } -utest-macros = { git = "https://github.com/japaric/utest" } - -[features] -default = ["mangled-names"] -c = ["compiler_builtins/c"] -no-asm = ["compiler_builtins/no-asm"] -no-f16-f128 = ["compiler_builtins/no-f16-f128"] -mem = ["compiler_builtins/mem"] -mangled-names = ["compiler_builtins/mangled-names"] -# Skip tests that rely on f128 symbols being available on the system -no-sys-f128 = ["no-sys-f128-int-convert", "no-sys-f16-f128-convert"] -# Some platforms have some f128 functions but everything except integer conversions -no-sys-f128-int-convert = [] -no-sys-f16-f128-convert = [] -no-sys-f16-f64-convert = [] -# Skip tests that rely on f16 symbols being available on the system -no-sys-f16 = ["no-sys-f16-f64-convert"] - -# Enable icount benchmarks (requires iai-callgrind and valgrind) -icount = ["dep:iai-callgrind"] - -# Enable report generation without bringing in more dependencies by default -benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] - -# NOTE: benchmarks must be run with `--no-default-features` or with -# `-p testcrate`, otherwise the default `compiler-builtins` feature of the -# `compiler_builtins` crate gets activated, resulting in linker errors. - -[[bench]] -name = "float_add" -harness = false - -[[bench]] -name = "float_sub" -harness = false - -[[bench]] -name = "float_mul" -harness = false - -[[bench]] -name = "float_div" -harness = false - -[[bench]] -name = "float_cmp" -harness = false - -[[bench]] -name = "float_conv" -harness = false - -[[bench]] -name = "float_extend" -harness = false - -[[bench]] -name = "float_trunc" -harness = false - -[[bench]] -name = "float_pow" -harness = false - -[[bench]] -name = "mem_icount" -harness = false -required-features = ["icount"] diff --git a/library/compiler-builtins/testcrate/benches/float_add.rs b/library/compiler-builtins/testcrate/benches/float_add.rs deleted file mode 100644 index a578655f8f4..00000000000 --- a/library/compiler-builtins/testcrate/benches/float_add.rs +++ /dev/null @@ -1,93 +0,0 @@ -#![cfg_attr(f128_enabled, feature(f128))] - -use compiler_builtins::float::add; -use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; - -float_bench! { - name: add_f32, - sig: (a: f32, b: f32) -> f32, - crate_fn: add::__addsf3, - sys_fn: __addsf3, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - asm!( - "addss {a}, {b}", - a = inout(xmm_reg) a, - b = in(xmm_reg) b, - options(nomem, nostack, pure) - ); - - a - }; - - #[cfg(target_arch = "aarch64")] { - asm!( - "fadd {a:s}, {a:s}, {b:s}", - a = inout(vreg) a, - b = in(vreg) b, - options(nomem, nostack, pure) - ); - - a - }; - ], -} - -float_bench! { - name: add_f64, - sig: (a: f64, b: f64) -> f64, - crate_fn: add::__adddf3, - sys_fn: __adddf3, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - asm!( - "addsd {a}, {b}", - a = inout(xmm_reg) a, - b = in(xmm_reg) b, - options(nomem, nostack, pure) - ); - - a - }; - - #[cfg(target_arch = "aarch64")] { - asm!( - "fadd {a:d}, {a:d}, {b:d}", - a = inout(vreg) a, - b = in(vreg) b, - options(nomem, nostack, pure) - ); - - a - }; - ], -} - -#[cfg(f128_enabled)] -float_bench! { - name: add_f128, - sig: (a: f128, b: f128) -> f128, - crate_fn: add::__addtf3, - crate_fn_ppc: add::__addkf3, - sys_fn: __addtf3, - sys_fn_ppc: __addkf3, - sys_available: not(feature = "no-sys-f128"), - asm: [] -} - -pub fn float_add() { - let mut criterion = Criterion::default().configure_from_args(); - - add_f32(&mut criterion); - add_f64(&mut criterion); - - #[cfg(f128_enabled)] - { - add_f128(&mut criterion); - } -} - -criterion_main!(float_add); diff --git a/library/compiler-builtins/testcrate/benches/float_cmp.rs b/library/compiler-builtins/testcrate/benches/float_cmp.rs deleted file mode 100644 index 4c269e4889c..00000000000 --- a/library/compiler-builtins/testcrate/benches/float_cmp.rs +++ /dev/null @@ -1,208 +0,0 @@ -#![cfg_attr(f128_enabled, feature(f128))] - -use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; - -use compiler_builtins::float::cmp; - -/// `gt` symbols are allowed to return differing results, they just get compared -/// to 0. -fn gt_res_eq(a: i32, b: i32) -> bool { - let a_lt_0 = a <= 0; - let b_lt_0 = b <= 0; - (a_lt_0 && b_lt_0) || (!a_lt_0 && !b_lt_0) -} - -float_bench! { - name: cmp_f32_gt, - sig: (a: f32, b: f32) -> i32, - crate_fn: cmp::__gtsf2, - sys_fn: __gtsf2, - sys_available: all(), - output_eq: gt_res_eq, - asm: [ - #[cfg(target_arch = "x86_64")] { - let ret: i32; - asm!( - "xor {ret:e}, {ret:e}", - "ucomiss {a}, {b}", - "seta {ret:l}", - a = in(xmm_reg) a, - b = in(xmm_reg) b, - ret = out(reg) ret, - options(nomem, nostack, pure) - ); - - ret - }; - - #[cfg(target_arch = "aarch64")] { - let ret: i32; - asm!( - "fcmp {a:s}, {b:s}", - "cset {ret:w}, gt", - a = in(vreg) a, - b = in(vreg) b, - ret = out(reg) ret, - options(nomem,nostack), - ); - - ret - }; - ], -} - -float_bench! { - name: cmp_f32_unord, - sig: (a: f32, b: f32) -> i32, - crate_fn: cmp::__unordsf2, - sys_fn: __unordsf2, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - let ret: i32; - asm!( - "xor {ret:e}, {ret:e}", - "ucomiss {a}, {b}", - "setp {ret:l}", - a = in(xmm_reg) a, - b = in(xmm_reg) b, - ret = out(reg) ret, - options(nomem, nostack, pure) - ); - - ret - }; - - #[cfg(target_arch = "aarch64")] { - let ret: i32; - asm!( - "fcmp {a:s}, {b:s}", - "cset {ret:w}, vs", - a = in(vreg) a, - b = in(vreg) b, - ret = out(reg) ret, - options(nomem, nostack, pure) - ); - - ret - }; - ], -} - -float_bench! { - name: cmp_f64_gt, - sig: (a: f64, b: f64) -> i32, - crate_fn: cmp::__gtdf2, - sys_fn: __gtdf2, - sys_available: all(), - output_eq: gt_res_eq, - asm: [ - #[cfg(target_arch = "x86_64")] { - let ret: i32; - asm!( - "xor {ret:e}, {ret:e}", - "ucomisd {a}, {b}", - "seta {ret:l}", - a = in(xmm_reg) a, - b = in(xmm_reg) b, - ret = out(reg) ret, - options(nomem, nostack, pure) - ); - - ret - }; - - #[cfg(target_arch = "aarch64")] { - let ret: i32; - asm!( - "fcmp {a:d}, {b:d}", - "cset {ret:w}, gt", - a = in(vreg) a, - b = in(vreg) b, - ret = out(reg) ret, - options(nomem, nostack, pure) - ); - - ret - }; - ], -} - -float_bench! { - name: cmp_f64_unord, - sig: (a: f64, b: f64) -> i32, - crate_fn: cmp::__unorddf2, - sys_fn: __unorddf2, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - let ret: i32; - asm!( - "xor {ret:e}, {ret:e}", - "ucomisd {a}, {b}", - "setp {ret:l}", - a = in(xmm_reg) a, - b = in(xmm_reg) b, - ret = out(reg) ret, - options(nomem, nostack, pure) - ); - - ret - }; - - #[cfg(target_arch = "aarch64")] { - let ret: i32; - asm!( - "fcmp {a:d}, {b:d}", - "cset {ret:w}, vs", - a = in(vreg) a, - b = in(vreg) b, - ret = out(reg) ret, - options(nomem, nostack, pure) - ); - - ret - }; - ], -} - -float_bench! { - name: cmp_f128_gt, - sig: (a: f128, b: f128) -> i32, - crate_fn: cmp::__gttf2, - crate_fn_ppc: cmp::__gtkf2, - sys_fn: __gttf2, - sys_fn_ppc: __gtkf2, - sys_available: not(feature = "no-sys-f128"), - output_eq: gt_res_eq, - asm: [] -} - -float_bench! { - name: cmp_f128_unord, - sig: (a: f128, b: f128) -> i32, - crate_fn: cmp::__unordtf2, - crate_fn_ppc: cmp::__unordkf2, - sys_fn: __unordtf2, - sys_fn_ppc: __unordkf2, - sys_available: not(feature = "no-sys-f128"), - asm: [] -} - -pub fn float_cmp() { - let mut criterion = Criterion::default().configure_from_args(); - - cmp_f32_gt(&mut criterion); - cmp_f32_unord(&mut criterion); - cmp_f64_gt(&mut criterion); - cmp_f64_unord(&mut criterion); - - #[cfg(f128_enabled)] - { - cmp_f128_gt(&mut criterion); - cmp_f128_unord(&mut criterion); - } -} - -criterion_main!(float_cmp); diff --git a/library/compiler-builtins/testcrate/benches/float_conv.rs b/library/compiler-builtins/testcrate/benches/float_conv.rs deleted file mode 100644 index e3f2af86344..00000000000 --- a/library/compiler-builtins/testcrate/benches/float_conv.rs +++ /dev/null @@ -1,688 +0,0 @@ -#![allow(improper_ctypes)] -#![cfg_attr(f128_enabled, feature(f128))] - -use compiler_builtins::float::conv; -use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; - -/* unsigned int -> float */ - -float_bench! { - name: conv_u32_f32, - sig: (a: u32) -> f32, - crate_fn: conv::__floatunsisf, - sys_fn: __floatunsisf, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - let ret: f32; - asm!( - "mov {tmp:e}, {a:e}", - "cvtsi2ss {ret}, {tmp}", - a = in(reg) a, - tmp = out(reg) _, - ret = lateout(xmm_reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - - #[cfg(target_arch = "aarch64")] { - let ret: f32; - asm!( - "ucvtf {ret:s}, {a:w}", - a = in(reg) a, - ret = lateout(vreg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -float_bench! { - name: conv_u32_f64, - sig: (a: u32) -> f64, - crate_fn: conv::__floatunsidf, - sys_fn: __floatunsidf, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - let ret: f64; - asm!( - "mov {tmp:e}, {a:e}", - "cvtsi2sd {ret}, {tmp}", - a = in(reg) a, - tmp = out(reg) _, - ret = lateout(xmm_reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - - #[cfg(target_arch = "aarch64")] { - let ret: f64; - asm!( - "ucvtf {ret:d}, {a:w}", - a = in(reg) a, - ret = lateout(vreg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -#[cfg(f128_enabled)] -float_bench! { - name: conv_u32_f128, - sig: (a: u32) -> f128, - crate_fn: conv::__floatunsitf, - crate_fn_ppc: conv::__floatunsikf, - sys_fn: __floatunsitf, - sys_fn_ppc: __floatunsikf, - sys_available: not(feature = "no-sys-f16-f128-convert"), - asm: [] -} - -float_bench! { - name: conv_u64_f32, - sig: (a: u64) -> f32, - crate_fn: conv::__floatundisf, - sys_fn: __floatundisf, - sys_available: all(), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: f32; - asm!( - "ucvtf {ret:s}, {a:x}", - a = in(reg) a, - ret = lateout(vreg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -float_bench! { - name: conv_u64_f64, - sig: (a: u64) -> f64, - crate_fn: conv::__floatundidf, - sys_fn: __floatundidf, - sys_available: all(), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: f64; - asm!( - "ucvtf {ret:d}, {a:x}", - a = in(reg) a, - ret = lateout(vreg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -#[cfg(f128_enabled)] -float_bench! { - name: conv_u64_f128, - sig: (a: u64) -> f128, - crate_fn: conv::__floatunditf, - crate_fn_ppc: conv::__floatundikf, - sys_fn: __floatunditf, - sys_fn_ppc: __floatundikf, - sys_available: not(feature = "no-sys-f16-f128-convert"), - asm: [] -} - -float_bench! { - name: conv_u128_f32, - sig: (a: u128) -> f32, - crate_fn: conv::__floatuntisf, - sys_fn: __floatuntisf, - sys_available: all(), - asm: [] -} - -float_bench! { - name: conv_u128_f64, - sig: (a: u128) -> f64, - crate_fn: conv::__floatuntidf, - sys_fn: __floatuntidf, - sys_available: all(), - asm: [] -} - -#[cfg(f128_enabled)] -float_bench! { - name: conv_u128_f128, - sig: (a: u128) -> f128, - crate_fn: conv::__floatuntitf, - crate_fn_ppc: conv::__floatuntikf, - sys_fn: __floatuntitf, - sys_fn_ppc: __floatuntikf, - sys_available: not(feature = "no-sys-f16-f128-convert"), - asm: [] -} - -/* signed int -> float */ - -float_bench! { - name: conv_i32_f32, - sig: (a: i32) -> f32, - crate_fn: conv::__floatsisf, - sys_fn: __floatsisf, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - let ret: f32; - asm!( - "cvtsi2ss {ret}, {a:e}", - a = in(reg) a, - ret = lateout(xmm_reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - - #[cfg(target_arch = "aarch64")] { - let ret: f32; - asm!( - "scvtf {ret:s}, {a:w}", - a = in(reg) a, - ret = lateout(vreg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -float_bench! { - name: conv_i32_f64, - sig: (a: i32) -> f64, - crate_fn: conv::__floatsidf, - sys_fn: __floatsidf, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - let ret: f64; - asm!( - "cvtsi2sd {ret}, {a:e}", - a = in(reg) a, - ret = lateout(xmm_reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - - - #[cfg(target_arch = "aarch64")] { - let ret: f64; - asm!( - "scvtf {ret:d}, {a:w}", - a = in(reg) a, - ret = lateout(vreg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -#[cfg(f128_enabled)] -float_bench! { - name: conv_i32_f128, - sig: (a: i32) -> f128, - crate_fn: conv::__floatsitf, - crate_fn_ppc: conv::__floatsikf, - sys_fn: __floatsitf, - sys_fn_ppc: __floatsikf, - sys_available: not(feature = "no-sys-f16-f128-convert"), - asm: [] -} - -float_bench! { - name: conv_i64_f32, - sig: (a: i64) -> f32, - crate_fn: conv::__floatdisf, - sys_fn: __floatdisf, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - let ret: f32; - asm!( - "cvtsi2ss {ret}, {a:r}", - a = in(reg) a, - ret = lateout(xmm_reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - - #[cfg(target_arch = "aarch64")] { - let ret: f32; - asm!( - "scvtf {ret:s}, {a:x}", - a = in(reg) a, - ret = lateout(vreg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -float_bench! { - name: conv_i64_f64, - sig: (a: i64) -> f64, - crate_fn: conv::__floatdidf, - sys_fn: __floatdidf, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - let ret: f64; - asm!( - "cvtsi2sd {ret}, {a:r}", - a = in(reg) a, - ret = lateout(xmm_reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - - - #[cfg(target_arch = "aarch64")] { - let ret: f64; - asm!( - "scvtf {ret:d}, {a:x}", - a = in(reg) a, - ret = lateout(vreg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -#[cfg(f128_enabled)] -float_bench! { - name: conv_i64_f128, - sig: (a: i64) -> f128, - crate_fn: conv::__floatditf, - crate_fn_ppc: conv::__floatdikf, - sys_fn: __floatditf, - sys_fn_ppc: __floatdikf, - sys_available: not(feature = "no-sys-f16-f128-convert"), - asm: [] -} - -float_bench! { - name: conv_i128_f32, - sig: (a: i128) -> f32, - crate_fn: conv::__floattisf, - sys_fn: __floattisf, - sys_available: all(), - asm: [] -} - -float_bench! { - name: conv_i128_f64, - sig: (a: i128) -> f64, - crate_fn: conv::__floattidf, - sys_fn: __floattidf, - sys_available: all(), - asm: [] -} - -#[cfg(f128_enabled)] -float_bench! { - name: conv_i128_f128, - sig: (a: i128) -> f128, - crate_fn: conv::__floattitf, - crate_fn_ppc: conv::__floattikf, - sys_fn: __floattitf, - sys_fn_ppc: __floattikf, - sys_available: not(feature = "no-sys-f16-f128-convert"), - asm: [] -} - -/* float -> unsigned int */ - -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] -float_bench! { - name: conv_f32_u32, - sig: (a: f32) -> u32, - crate_fn: conv::__fixunssfsi, - sys_fn: __fixunssfsi, - sys_available: all(), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: u32; - asm!( - "fcvtzu {ret:w}, {a:s}", - a = in(vreg) a, - ret = lateout(reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] -float_bench! { - name: conv_f32_u64, - sig: (a: f32) -> u64, - crate_fn: conv::__fixunssfdi, - sys_fn: __fixunssfdi, - sys_available: all(), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: u64; - asm!( - "fcvtzu {ret:x}, {a:s}", - a = in(vreg) a, - ret = lateout(reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] -float_bench! { - name: conv_f32_u128, - sig: (a: f32) -> u128, - crate_fn: conv::__fixunssfti, - sys_fn: __fixunssfti, - sys_available: all(), - asm: [] -} - -float_bench! { - name: conv_f64_u32, - sig: (a: f64) -> u32, - crate_fn: conv::__fixunsdfsi, - sys_fn: __fixunsdfsi, - sys_available: all(), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: u32; - asm!( - "fcvtzu {ret:w}, {a:d}", - a = in(vreg) a, - ret = lateout(reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -float_bench! { - name: conv_f64_u64, - sig: (a: f64) -> u64, - crate_fn: conv::__fixunsdfdi, - sys_fn: __fixunsdfdi, - sys_available: all(), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: u64; - asm!( - "fcvtzu {ret:x}, {a:d}", - a = in(vreg) a, - ret = lateout(reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -float_bench! { - name: conv_f64_u128, - sig: (a: f64) -> u128, - crate_fn: conv::__fixunsdfti, - sys_fn: __fixunsdfti, - sys_available: all(), - asm: [] -} - -#[cfg(f128_enabled)] -float_bench! { - name: conv_f128_u32, - sig: (a: f128) -> u32, - crate_fn: conv::__fixunstfsi, - crate_fn_ppc: conv::__fixunskfsi, - sys_fn: __fixunstfsi, - sys_available: not(feature = "no-sys-f16-f128-convert"), - asm: [] -} - -#[cfg(f128_enabled)] -float_bench! { - name: conv_f128_u64, - sig: (a: f128) -> u64, - crate_fn: conv::__fixunstfdi, - crate_fn_ppc: conv::__fixunskfdi, - sys_fn: __fixunstfdi, - sys_available: not(feature = "no-sys-f16-f128-convert"), - asm: [] -} - -#[cfg(f128_enabled)] -float_bench! { - name: conv_f128_u128, - sig: (a: f128) -> u128, - crate_fn: conv::__fixunstfti, - crate_fn_ppc: conv::__fixunskfti, - sys_fn: __fixunstfti, - sys_available: not(feature = "no-sys-f16-f128-convert"), - asm: [] -} - -/* float -> signed int */ - -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] -float_bench! { - name: conv_f32_i32, - sig: (a: f32) -> i32, - crate_fn: conv::__fixsfsi, - sys_fn: __fixsfsi, - sys_available: all(), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: i32; - asm!( - "fcvtzs {ret:w}, {a:s}", - a = in(vreg) a, - ret = lateout(reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] -float_bench! { - name: conv_f32_i64, - sig: (a: f32) -> i64, - crate_fn: conv::__fixsfdi, - sys_fn: __fixsfdi, - sys_available: all(), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: i64; - asm!( - "fcvtzs {ret:x}, {a:s}", - a = in(vreg) a, - ret = lateout(reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] -float_bench! { - name: conv_f32_i128, - sig: (a: f32) -> i128, - crate_fn: conv::__fixsfti, - sys_fn: __fixsfti, - sys_available: all(), - asm: [] -} - -float_bench! { - name: conv_f64_i32, - sig: (a: f64) -> i32, - crate_fn: conv::__fixdfsi, - sys_fn: __fixdfsi, - sys_available: all(), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: i32; - asm!( - "fcvtzs {ret:w}, {a:d}", - a = in(vreg) a, - ret = lateout(reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -float_bench! { - name: conv_f64_i64, - sig: (a: f64) -> i64, - crate_fn: conv::__fixdfdi, - sys_fn: __fixdfdi, - sys_available: all(), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: i64; - asm!( - "fcvtzs {ret:x}, {a:d}", - a = in(vreg) a, - ret = lateout(reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -float_bench! { - name: conv_f64_i128, - sig: (a: f64) -> i128, - crate_fn: conv::__fixdfti, - sys_fn: __fixdfti, - sys_available: all(), - asm: [] -} - -#[cfg(f128_enabled)] -float_bench! { - name: conv_f128_i32, - sig: (a: f128) -> i32, - crate_fn: conv::__fixtfsi, - crate_fn_ppc: conv::__fixkfsi, - sys_fn: __fixtfsi, - sys_available: not(feature = "no-sys-f16-f128-convert"), - asm: [] -} - -#[cfg(f128_enabled)] -float_bench! { - name: conv_f128_i64, - sig: (a: f128) -> i64, - crate_fn: conv::__fixtfdi, - crate_fn_ppc: conv::__fixkfdi, - sys_fn: __fixtfdi, - sys_available: not(feature = "no-sys-f16-f128-convert"), - asm: [] -} - -#[cfg(f128_enabled)] -float_bench! { - name: conv_f128_i128, - sig: (a: f128) -> i128, - crate_fn: conv::__fixtfti, - crate_fn_ppc: conv::__fixkfti, - sys_fn: __fixtfti, - sys_available: not(feature = "no-sys-f16-f128-convert"), - asm: [] -} - -pub fn float_conv() { - let mut criterion = Criterion::default().configure_from_args(); - - conv_u32_f32(&mut criterion); - conv_u32_f64(&mut criterion); - conv_u64_f32(&mut criterion); - conv_u64_f64(&mut criterion); - conv_u128_f32(&mut criterion); - conv_u128_f64(&mut criterion); - conv_i32_f32(&mut criterion); - conv_i32_f64(&mut criterion); - conv_i64_f32(&mut criterion); - conv_i64_f64(&mut criterion); - conv_i128_f32(&mut criterion); - conv_i128_f64(&mut criterion); - conv_f64_u32(&mut criterion); - conv_f64_u64(&mut criterion); - conv_f64_u128(&mut criterion); - conv_f64_i32(&mut criterion); - conv_f64_i64(&mut criterion); - conv_f64_i128(&mut criterion); - - #[cfg(f128_enabled)] - // FIXME: ppc64le has a sporadic overflow panic in the crate functions - // - #[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] - { - conv_u32_f128(&mut criterion); - conv_u64_f128(&mut criterion); - conv_u128_f128(&mut criterion); - conv_i32_f128(&mut criterion); - conv_i64_f128(&mut criterion); - conv_i128_f128(&mut criterion); - conv_f128_u32(&mut criterion); - conv_f128_u64(&mut criterion); - conv_f128_u128(&mut criterion); - conv_f128_i32(&mut criterion); - conv_f128_i64(&mut criterion); - conv_f128_i128(&mut criterion); - } -} - -criterion_main!(float_conv); diff --git a/library/compiler-builtins/testcrate/benches/float_div.rs b/library/compiler-builtins/testcrate/benches/float_div.rs deleted file mode 100644 index c42f3f38671..00000000000 --- a/library/compiler-builtins/testcrate/benches/float_div.rs +++ /dev/null @@ -1,93 +0,0 @@ -#![cfg_attr(f128_enabled, feature(f128))] - -use compiler_builtins::float::div; -use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; - -float_bench! { - name: div_f32, - sig: (a: f32, b: f32) -> f32, - crate_fn: div::__divsf3, - sys_fn: __divsf3, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - asm!( - "divss {a}, {b}", - a = inout(xmm_reg) a, - b = in(xmm_reg) b, - options(nomem, nostack, pure) - ); - - a - }; - - #[cfg(target_arch = "aarch64")] { - asm!( - "fdiv {a:s}, {a:s}, {b:s}", - a = inout(vreg) a, - b = in(vreg) b, - options(nomem, nostack, pure) - ); - - a - }; - ], -} - -float_bench! { - name: div_f64, - sig: (a: f64, b: f64) -> f64, - crate_fn: div::__divdf3, - sys_fn: __divdf3, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - asm!( - "divsd {a}, {b}", - a = inout(xmm_reg) a, - b = in(xmm_reg) b, - options(nomem, nostack, pure) - ); - - a - }; - - #[cfg(target_arch = "aarch64")] { - asm!( - "fdiv {a:d}, {a:d}, {b:d}", - a = inout(vreg) a, - b = in(vreg) b, - options(nomem, nostack, pure) - ); - - a - }; - ], -} - -#[cfg(f128_enabled)] -float_bench! { - name: div_f128, - sig: (a: f128, b: f128) -> f128, - crate_fn: div::__divtf3, - crate_fn_ppc: div::__divkf3, - sys_fn: __divtf3, - sys_fn_ppc: __divkf3, - sys_available: not(feature = "no-sys-f128"), - asm: [] -} - -pub fn float_div() { - let mut criterion = Criterion::default().configure_from_args(); - - div_f32(&mut criterion); - div_f64(&mut criterion); - - #[cfg(f128_enabled)] - { - div_f128(&mut criterion); - } -} - -criterion_main!(float_div); diff --git a/library/compiler-builtins/testcrate/benches/float_extend.rs b/library/compiler-builtins/testcrate/benches/float_extend.rs deleted file mode 100644 index 1e7fedefe70..00000000000 --- a/library/compiler-builtins/testcrate/benches/float_extend.rs +++ /dev/null @@ -1,133 +0,0 @@ -#![allow(unused_variables)] // "unused" f16 registers -#![cfg_attr(f128_enabled, feature(f128))] -#![cfg_attr(f16_enabled, feature(f16))] - -use compiler_builtins::float::extend; -use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; - -#[cfg(f16_enabled)] -float_bench! { - name: extend_f16_f32, - sig: (a: f16) -> f32, - crate_fn: extend::__extendhfsf2, - sys_fn: __extendhfsf2, - sys_available: not(feature = "no-sys-f16"), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: f32; - asm!( - "fcvt {ret:s}, {a:h}", - a = in(vreg) a, - ret = lateout(vreg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -#[cfg(f16_enabled)] -float_bench! { - name: extend_f16_f64, - sig: (a: f16) -> f64, - crate_fn: extend::__extendhfdf2, - sys_fn: __extendhfdf2, - sys_available: not(feature = "no-sys-f16-f64-convert"), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: f64; - asm!( - "fcvt {ret:d}, {a:h}", - a = in(vreg) a, - ret = lateout(vreg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -#[cfg(all(f16_enabled, f128_enabled))] -float_bench! { - name: extend_f16_f128, - sig: (a: f16) -> f128, - crate_fn: extend::__extendhftf2, - crate_fn_ppc: extend::__extendhfkf2, - sys_fn: __extendhftf2, - sys_fn_ppc: __extendhfkf2, - sys_available: not(feature = "no-sys-f16-f128-convert"), - asm: [], -} - -float_bench! { - name: extend_f32_f64, - sig: (a: f32) -> f64, - crate_fn: extend::__extendsfdf2, - sys_fn: __extendsfdf2, - sys_available: all(), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: f64; - asm!( - "fcvt {ret:d}, {a:s}", - a = in(vreg) a, - ret = lateout(vreg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -#[cfg(f128_enabled)] -float_bench! { - name: extend_f32_f128, - sig: (a: f32) -> f128, - crate_fn: extend::__extendsftf2, - crate_fn_ppc: extend::__extendsfkf2, - sys_fn: __extendsftf2, - sys_fn_ppc: __extendsfkf2, - sys_available: not(feature = "no-sys-f128"), - asm: [], -} - -#[cfg(f128_enabled)] -float_bench! { - name: extend_f64_f128, - sig: (a: f64) -> f128, - crate_fn: extend::__extenddftf2, - crate_fn_ppc: extend::__extenddfkf2, - sys_fn: __extenddftf2, - sys_fn_ppc: __extenddfkf2, - sys_available: not(feature = "no-sys-f128"), - asm: [], -} - -pub fn float_extend() { - let mut criterion = Criterion::default().configure_from_args(); - - // FIXME(#655): `f16` tests disabled until we can bootstrap symbols - #[cfg(f16_enabled)] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - { - extend_f16_f32(&mut criterion); - extend_f16_f64(&mut criterion); - - #[cfg(f128_enabled)] - extend_f16_f128(&mut criterion); - } - - extend_f32_f64(&mut criterion); - - #[cfg(f128_enabled)] - { - extend_f32_f128(&mut criterion); - extend_f64_f128(&mut criterion); - } -} - -criterion_main!(float_extend); diff --git a/library/compiler-builtins/testcrate/benches/float_mul.rs b/library/compiler-builtins/testcrate/benches/float_mul.rs deleted file mode 100644 index 0857a68a22e..00000000000 --- a/library/compiler-builtins/testcrate/benches/float_mul.rs +++ /dev/null @@ -1,93 +0,0 @@ -#![cfg_attr(f128_enabled, feature(f128))] - -use compiler_builtins::float::mul; -use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; - -float_bench! { - name: mul_f32, - sig: (a: f32, b: f32) -> f32, - crate_fn: mul::__mulsf3, - sys_fn: __mulsf3, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - asm!( - "mulss {a}, {b}", - a = inout(xmm_reg) a, - b = in(xmm_reg) b, - options(nomem, nostack, pure) - ); - - a - }; - - #[cfg(target_arch = "aarch64")] { - asm!( - "fmul {a:s}, {a:s}, {b:s}", - a = inout(vreg) a, - b = in(vreg) b, - options(nomem, nostack, pure) - ); - - a - }; - ], -} - -float_bench! { - name: mul_f64, - sig: (a: f64, b: f64) -> f64, - crate_fn: mul::__muldf3, - sys_fn: __muldf3, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - asm!( - "mulsd {a}, {b}", - a = inout(xmm_reg) a, - b = in(xmm_reg) b, - options(nomem, nostack, pure) - ); - - a - }; - - #[cfg(target_arch = "aarch64")] { - asm!( - "fmul {a:d}, {a:d}, {b:d}", - a = inout(vreg) a, - b = in(vreg) b, - options(nomem, nostack, pure) - ); - - a - }; - ], -} - -#[cfg(f128_enabled)] -float_bench! { - name: mul_f128, - sig: (a: f128, b: f128) -> f128, - crate_fn: mul::__multf3, - crate_fn_ppc: mul::__mulkf3, - sys_fn: __multf3, - sys_fn_ppc: __mulkf3, - sys_available: not(feature = "no-sys-f128"), - asm: [] -} - -pub fn float_mul() { - let mut criterion = Criterion::default().configure_from_args(); - - mul_f32(&mut criterion); - mul_f64(&mut criterion); - - #[cfg(f128_enabled)] - { - mul_f128(&mut criterion); - } -} - -criterion_main!(float_mul); diff --git a/library/compiler-builtins/testcrate/benches/float_pow.rs b/library/compiler-builtins/testcrate/benches/float_pow.rs deleted file mode 100644 index e84fee51ca9..00000000000 --- a/library/compiler-builtins/testcrate/benches/float_pow.rs +++ /dev/null @@ -1,49 +0,0 @@ -#![cfg_attr(f128_enabled, feature(f128))] - -use compiler_builtins::float::pow; -use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; - -float_bench! { - name: powi_f32, - sig: (a: f32, b: i32) -> f32, - crate_fn: pow::__powisf2, - sys_fn: __powisf2, - sys_available: all(), - asm: [], -} - -float_bench! { - name: powi_f64, - sig: (a: f64, b: i32) -> f64, - crate_fn: pow::__powidf2, - sys_fn: __powidf2, - sys_available: all(), - asm: [], -} - -// FIXME(f16_f128): can be changed to only `f128_enabled` once `__multf3` and `__divtf3` are -// distributed by nightly. -#[cfg(all(f128_enabled, not(feature = "no-sys-f128")))] -float_bench! { - name: powi_f128, - sig: (a: f128, b: i32) -> f128, - crate_fn: pow::__powitf2, - crate_fn_ppc: pow::__powikf2, - sys_fn: __powitf2, - sys_fn_ppc: __powikf2, - sys_available: not(feature = "no-sys-f128"), - asm: [] -} - -pub fn float_pow() { - let mut criterion = Criterion::default().configure_from_args(); - - powi_f32(&mut criterion); - powi_f64(&mut criterion); - - #[cfg(all(f128_enabled, not(feature = "no-sys-f128")))] - powi_f128(&mut criterion); -} - -criterion_main!(float_pow); diff --git a/library/compiler-builtins/testcrate/benches/float_sub.rs b/library/compiler-builtins/testcrate/benches/float_sub.rs deleted file mode 100644 index 7a6c05ea5c1..00000000000 --- a/library/compiler-builtins/testcrate/benches/float_sub.rs +++ /dev/null @@ -1,93 +0,0 @@ -#![cfg_attr(f128_enabled, feature(f128))] - -use compiler_builtins::float::sub; -use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; - -float_bench! { - name: sub_f32, - sig: (a: f32, b: f32) -> f32, - crate_fn: sub::__subsf3, - sys_fn: __subsf3, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - asm!( - "subss {a}, {b}", - a = inout(xmm_reg) a, - b = in(xmm_reg) b, - options(nomem, nostack, pure) - ); - - a - }; - - #[cfg(target_arch = "aarch64")] { - asm!( - "fsub {a:s}, {a:s}, {b:s}", - a = inout(vreg) a, - b = in(vreg) b, - options(nomem, nostack, pure) - ); - - a - }; - ], -} - -float_bench! { - name: sub_f64, - sig: (a: f64, b: f64) -> f64, - crate_fn: sub::__subdf3, - sys_fn: __subdf3, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - asm!( - "subsd {a}, {b}", - a = inout(xmm_reg) a, - b = in(xmm_reg) b, - options(nomem, nostack, pure) - ); - - a - }; - - #[cfg(target_arch = "aarch64")] { - asm!( - "fsub {a:d}, {a:d}, {b:d}", - a = inout(vreg) a, - b = in(vreg) b, - options(nomem, nostack, pure) - ); - - a - }; - ], -} - -#[cfg(f128_enabled)] -float_bench! { - name: sub_f128, - sig: (a: f128, b: f128) -> f128, - crate_fn: sub::__subtf3, - crate_fn_ppc: sub::__subkf3, - sys_fn: __subtf3, - sys_fn_ppc: __subkf3, - sys_available: not(feature = "no-sys-f128"), - asm: [] -} - -pub fn float_sub() { - let mut criterion = Criterion::default().configure_from_args(); - - sub_f32(&mut criterion); - sub_f64(&mut criterion); - - #[cfg(f128_enabled)] - { - sub_f128(&mut criterion); - } -} - -criterion_main!(float_sub); diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs deleted file mode 100644 index 4ceb62ab06a..00000000000 --- a/library/compiler-builtins/testcrate/benches/float_trunc.rs +++ /dev/null @@ -1,146 +0,0 @@ -#![cfg_attr(f128_enabled, feature(f128))] -#![cfg_attr(f16_enabled, feature(f16))] - -use compiler_builtins::float::trunc; -use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; - -#[cfg(f16_enabled)] -float_bench! { - name: trunc_f32_f16, - sig: (a: f32) -> f16, - crate_fn: trunc::__truncsfhf2, - sys_fn: __truncsfhf2, - sys_available: not(feature = "no-sys-f16"), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: f16; - asm!( - "fcvt {ret:h}, {a:s}", - a = in(vreg) a, - ret = lateout(vreg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -#[cfg(f16_enabled)] -float_bench! { - name: trunc_f64_f16, - sig: (a: f64) -> f16, - crate_fn: trunc::__truncdfhf2, - sys_fn: __truncdfhf2, - sys_available: not(feature = "no-sys-f16-f64-convert"), - asm: [ - #[cfg(target_arch = "aarch64")] { - let ret: f16; - asm!( - "fcvt {ret:h}, {a:d}", - a = in(vreg) a, - ret = lateout(vreg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -float_bench! { - name: trunc_f64_f32, - sig: (a: f64) -> f32, - crate_fn: trunc::__truncdfsf2, - sys_fn: __truncdfsf2, - sys_available: all(), - asm: [ - #[cfg(target_arch = "x86_64")] { - let ret: f32; - asm!( - "cvtsd2ss {ret}, {a}", - a = in(xmm_reg) a, - ret = lateout(xmm_reg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - - #[cfg(target_arch = "aarch64")] { - let ret: f32; - asm!( - "fcvt {ret:s}, {a:d}", - a = in(vreg) a, - ret = lateout(vreg) ret, - options(nomem, nostack, pure), - ); - - ret - }; - ], -} - -#[cfg(all(f16_enabled, f128_enabled))] -float_bench! { - name: trunc_f128_f16, - sig: (a: f128) -> f16, - crate_fn: trunc::__trunctfhf2, - crate_fn_ppc: trunc::__trunckfhf2, - sys_fn: __trunctfhf2, - sys_fn_ppc: __trunckfhf2, - sys_available: not(feature = "no-sys-f16-f128-convert"), - asm: [], -} - -#[cfg(f128_enabled)] -float_bench! { - name: trunc_f128_f32, - sig: (a: f128) -> f32, - crate_fn: trunc::__trunctfsf2, - crate_fn_ppc: trunc::__trunckfsf2, - sys_fn: __trunctfsf2, - sys_fn_ppc: __trunckfsf2, - sys_available: not(feature = "no-sys-f128"), - asm: [], -} - -#[cfg(f128_enabled)] -float_bench! { - name: trunc_f128_f64, - sig: (a: f128) -> f64, - crate_fn: trunc::__trunctfdf2, - crate_fn_ppc: trunc::__trunckfdf2, - sys_fn: __trunctfdf2, - sys_fn_ppc: __trunckfdf2, - sys_available: not(feature = "no-sys-f128"), - asm: [], -} - -pub fn float_trunc() { - let mut criterion = Criterion::default().configure_from_args(); - - // FIXME(#655): `f16` tests disabled until we can bootstrap symbols - #[cfg(f16_enabled)] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - { - trunc_f32_f16(&mut criterion); - trunc_f64_f16(&mut criterion); - } - - trunc_f64_f32(&mut criterion); - - #[cfg(f128_enabled)] - { - // FIXME(#655): `f16` tests disabled until we can bootstrap symbols - #[cfg(f16_enabled)] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - trunc_f128_f16(&mut criterion); - - trunc_f128_f32(&mut criterion); - trunc_f128_f64(&mut criterion); - } -} - -criterion_main!(float_trunc); diff --git a/library/compiler-builtins/testcrate/benches/mem.rs b/library/compiler-builtins/testcrate/benches/mem.rs deleted file mode 100644 index 3f83926b6c5..00000000000 --- a/library/compiler-builtins/testcrate/benches/mem.rs +++ /dev/null @@ -1,364 +0,0 @@ -#![feature(test)] - -extern crate test; -use test::{Bencher, black_box}; - -extern crate compiler_builtins; -use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; - -const WORD_SIZE: usize = core::mem::size_of::(); - -struct AlignedVec { - vec: Vec, - size: usize, -} - -impl AlignedVec { - fn new(fill: u8, size: usize) -> Self { - let mut broadcast = fill as usize; - let mut bits = 8; - while bits < WORD_SIZE * 8 { - broadcast |= broadcast << bits; - bits *= 2; - } - - let vec = vec![broadcast; (size + WORD_SIZE - 1) & !WORD_SIZE]; - AlignedVec { vec, size } - } -} - -impl core::ops::Deref for AlignedVec { - type Target = [u8]; - fn deref(&self) -> &[u8] { - unsafe { core::slice::from_raw_parts(self.vec.as_ptr() as *const u8, self.size) } - } -} - -impl core::ops::DerefMut for AlignedVec { - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { core::slice::from_raw_parts_mut(self.vec.as_mut_ptr() as *mut u8, self.size) } - } -} - -fn memcpy_builtin(b: &mut Bencher, n: usize, offset1: usize, offset2: usize) { - let v1 = AlignedVec::new(1, n + offset1); - let mut v2 = AlignedVec::new(0, n + offset2); - b.bytes = n as u64; - b.iter(|| { - let src: &[u8] = black_box(&v1[offset1..]); - let dst: &mut [u8] = black_box(&mut v2[offset2..]); - dst.copy_from_slice(src); - }) -} - -fn memcpy_rust(b: &mut Bencher, n: usize, offset1: usize, offset2: usize) { - let v1 = AlignedVec::new(1, n + offset1); - let mut v2 = AlignedVec::new(0, n + offset2); - b.bytes = n as u64; - b.iter(|| { - let src: &[u8] = black_box(&v1[offset1..]); - let dst: &mut [u8] = black_box(&mut v2[offset2..]); - unsafe { memcpy(dst.as_mut_ptr(), src.as_ptr(), n) } - }) -} - -fn memset_builtin(b: &mut Bencher, n: usize, offset: usize) { - let mut v1 = AlignedVec::new(0, n + offset); - b.bytes = n as u64; - b.iter(|| { - let dst: &mut [u8] = black_box(&mut v1[offset..]); - let val: u8 = black_box(27); - for b in dst { - *b = val; - } - }) -} - -fn memset_rust(b: &mut Bencher, n: usize, offset: usize) { - let mut v1 = AlignedVec::new(0, n + offset); - b.bytes = n as u64; - b.iter(|| { - let dst: &mut [u8] = black_box(&mut v1[offset..]); - let val = black_box(27); - unsafe { memset(dst.as_mut_ptr(), val, n) } - }) -} - -fn memcmp_builtin(b: &mut Bencher, n: usize) { - let v1 = AlignedVec::new(0, n); - let mut v2 = AlignedVec::new(0, n); - v2[n - 1] = 1; - b.bytes = n as u64; - b.iter(|| { - let s1: &[u8] = black_box(&v1); - let s2: &[u8] = black_box(&v2); - s1.cmp(s2) - }) -} - -fn memcmp_builtin_unaligned(b: &mut Bencher, n: usize) { - let v1 = AlignedVec::new(0, n); - let mut v2 = AlignedVec::new(0, n); - v2[n - 1] = 1; - b.bytes = n as u64; - b.iter(|| { - let s1: &[u8] = black_box(&v1[0..]); - let s2: &[u8] = black_box(&v2[1..]); - s1.cmp(s2) - }) -} - -fn memcmp_rust(b: &mut Bencher, n: usize) { - let v1 = AlignedVec::new(0, n); - let mut v2 = AlignedVec::new(0, n); - v2[n - 1] = 1; - b.bytes = n as u64; - b.iter(|| { - let s1: &[u8] = black_box(&v1); - let s2: &[u8] = black_box(&v2); - unsafe { memcmp(s1.as_ptr(), s2.as_ptr(), n) } - }) -} - -fn memcmp_rust_unaligned(b: &mut Bencher, n: usize) { - let v1 = AlignedVec::new(0, n); - let mut v2 = AlignedVec::new(0, n); - v2[n - 1] = 1; - b.bytes = n as u64; - b.iter(|| { - let s1: &[u8] = black_box(&v1[0..]); - let s2: &[u8] = black_box(&v2[1..]); - unsafe { memcmp(s1.as_ptr(), s2.as_ptr(), n - 1) } - }) -} - -fn memmove_builtin(b: &mut Bencher, n: usize, offset: usize) { - let mut v = AlignedVec::new(0, n + n / 2 + offset); - b.bytes = n as u64; - b.iter(|| { - let s: &mut [u8] = black_box(&mut v); - s.copy_within(0..n, n / 2 + offset); - }) -} - -fn memmove_rust(b: &mut Bencher, n: usize, offset: usize) { - let mut v = AlignedVec::new(0, n + n / 2 + offset); - b.bytes = n as u64; - b.iter(|| { - let dst: *mut u8 = black_box(&mut v[n / 2 + offset..]).as_mut_ptr(); - let src: *const u8 = black_box(&v).as_ptr(); - unsafe { memmove(dst, src, n) }; - }) -} - -#[bench] -fn memcpy_builtin_4096(b: &mut Bencher) { - memcpy_builtin(b, 4096, 0, 0) -} -#[bench] -fn memcpy_rust_4096(b: &mut Bencher) { - memcpy_rust(b, 4096, 0, 0) -} -#[bench] -fn memcpy_builtin_1048576(b: &mut Bencher) { - memcpy_builtin(b, 1048576, 0, 0) -} -#[bench] -fn memcpy_rust_1048576(b: &mut Bencher) { - memcpy_rust(b, 1048576, 0, 0) -} -#[bench] -fn memcpy_builtin_4096_offset(b: &mut Bencher) { - memcpy_builtin(b, 4096, 65, 65) -} -#[bench] -fn memcpy_rust_4096_offset(b: &mut Bencher) { - memcpy_rust(b, 4096, 65, 65) -} -#[bench] -fn memcpy_builtin_1048576_offset(b: &mut Bencher) { - memcpy_builtin(b, 1048576, 65, 65) -} -#[bench] -fn memcpy_rust_1048576_offset(b: &mut Bencher) { - memcpy_rust(b, 1048576, 65, 65) -} -#[bench] -fn memcpy_builtin_4096_misalign(b: &mut Bencher) { - memcpy_builtin(b, 4096, 65, 66) -} -#[bench] -fn memcpy_rust_4096_misalign(b: &mut Bencher) { - memcpy_rust(b, 4096, 65, 66) -} -#[bench] -fn memcpy_builtin_1048576_misalign(b: &mut Bencher) { - memcpy_builtin(b, 1048576, 65, 66) -} -#[bench] -fn memcpy_rust_1048576_misalign(b: &mut Bencher) { - memcpy_rust(b, 1048576, 65, 66) -} - -#[bench] -fn memset_builtin_4096(b: &mut Bencher) { - memset_builtin(b, 4096, 0) -} -#[bench] -fn memset_rust_4096(b: &mut Bencher) { - memset_rust(b, 4096, 0) -} -#[bench] -fn memset_builtin_1048576(b: &mut Bencher) { - memset_builtin(b, 1048576, 0) -} -#[bench] -fn memset_rust_1048576(b: &mut Bencher) { - memset_rust(b, 1048576, 0) -} -#[bench] -fn memset_builtin_4096_offset(b: &mut Bencher) { - memset_builtin(b, 4096, 65) -} -#[bench] -fn memset_rust_4096_offset(b: &mut Bencher) { - memset_rust(b, 4096, 65) -} -#[bench] -fn memset_builtin_1048576_offset(b: &mut Bencher) { - memset_builtin(b, 1048576, 65) -} -#[bench] -fn memset_rust_1048576_offset(b: &mut Bencher) { - memset_rust(b, 1048576, 65) -} - -#[bench] -fn memcmp_builtin_8(b: &mut Bencher) { - memcmp_builtin(b, 8) -} -#[bench] -fn memcmp_rust_8(b: &mut Bencher) { - memcmp_rust(b, 8) -} -#[bench] -fn memcmp_builtin_16(b: &mut Bencher) { - memcmp_builtin(b, 16) -} -#[bench] -fn memcmp_rust_16(b: &mut Bencher) { - memcmp_rust(b, 16) -} -#[bench] -fn memcmp_builtin_32(b: &mut Bencher) { - memcmp_builtin(b, 32) -} -#[bench] -fn memcmp_rust_32(b: &mut Bencher) { - memcmp_rust(b, 32) -} -#[bench] -fn memcmp_builtin_64(b: &mut Bencher) { - memcmp_builtin(b, 64) -} -#[bench] -fn memcmp_rust_64(b: &mut Bencher) { - memcmp_rust(b, 64) -} -#[bench] -fn memcmp_builtin_4096(b: &mut Bencher) { - memcmp_builtin(b, 4096) -} -#[bench] -fn memcmp_rust_4096(b: &mut Bencher) { - memcmp_rust(b, 4096) -} -#[bench] -fn memcmp_builtin_1048576(b: &mut Bencher) { - memcmp_builtin(b, 1048576) -} -#[bench] -fn memcmp_rust_1048576(b: &mut Bencher) { - memcmp_rust(b, 1048576) -} -#[bench] -fn memcmp_builtin_unaligned_7(b: &mut Bencher) { - memcmp_builtin_unaligned(b, 8) -} -#[bench] -fn memcmp_rust_unaligned_7(b: &mut Bencher) { - memcmp_rust_unaligned(b, 8) -} -#[bench] -fn memcmp_builtin_unaligned_15(b: &mut Bencher) { - memcmp_builtin_unaligned(b, 16) -} -#[bench] -fn memcmp_rust_unaligned_15(b: &mut Bencher) { - memcmp_rust_unaligned(b, 16) -} -#[bench] -fn memcmp_builtin_unaligned_31(b: &mut Bencher) { - memcmp_builtin_unaligned(b, 32) -} -#[bench] -fn memcmp_rust_unaligned_31(b: &mut Bencher) { - memcmp_rust_unaligned(b, 32) -} -#[bench] -fn memcmp_builtin_unaligned_63(b: &mut Bencher) { - memcmp_builtin_unaligned(b, 64) -} -#[bench] -fn memcmp_rust_unaligned_63(b: &mut Bencher) { - memcmp_rust_unaligned(b, 64) -} -#[bench] -fn memcmp_builtin_unaligned_4095(b: &mut Bencher) { - memcmp_builtin_unaligned(b, 4096) -} -#[bench] -fn memcmp_rust_unaligned_4095(b: &mut Bencher) { - memcmp_rust_unaligned(b, 4096) -} -#[bench] -fn memcmp_builtin_unaligned_1048575(b: &mut Bencher) { - memcmp_builtin_unaligned(b, 1048576) -} -#[bench] -fn memcmp_rust_unaligned_1048575(b: &mut Bencher) { - memcmp_rust_unaligned(b, 1048576) -} - -#[bench] -fn memmove_builtin_4096(b: &mut Bencher) { - memmove_builtin(b, 4096, 0) -} -#[bench] -fn memmove_rust_4096(b: &mut Bencher) { - memmove_rust(b, 4096, 0) -} -#[bench] -fn memmove_builtin_1048576(b: &mut Bencher) { - memmove_builtin(b, 1048576, 0) -} -#[bench] -fn memmove_rust_1048576(b: &mut Bencher) { - memmove_rust(b, 1048576, 0) -} -#[bench] -fn memmove_builtin_4096_misalign(b: &mut Bencher) { - memmove_builtin(b, 4096, 1) -} -#[bench] -fn memmove_rust_4096_misalign(b: &mut Bencher) { - memmove_rust(b, 4096, 1) -} -#[bench] -fn memmove_builtin_1048576_misalign(b: &mut Bencher) { - memmove_builtin(b, 1048576, 1) -} -#[bench] -fn memmove_rust_1048576_misalign(b: &mut Bencher) { - memmove_rust(b, 1048576, 1) -} diff --git a/library/compiler-builtins/testcrate/benches/mem_icount.rs b/library/compiler-builtins/testcrate/benches/mem_icount.rs deleted file mode 100644 index 63045f6e1ec..00000000000 --- a/library/compiler-builtins/testcrate/benches/mem_icount.rs +++ /dev/null @@ -1,499 +0,0 @@ -//! Benchmarks that use Callgrind (via `iai_callgrind`) to report instruction count metrics. This -//! is stable enough to be tested in CI. - -use std::hint::black_box; -use std::{ops, slice}; - -use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; -use iai_callgrind::{library_benchmark, library_benchmark_group, main}; - -const PAGE_SIZE: usize = 0x1000; // 4 kiB -const MAX_ALIGN: usize = 512; // assume we may use avx512 operations one day -const MEG1: usize = 1 << 20; // 1 MiB - -#[derive(Clone)] -#[repr(C, align(0x1000))] -struct Page([u8; PAGE_SIZE]); - -/// A buffer that is page-aligned by default, with an optional offset to create a -/// misalignment. -struct AlignedSlice { - buf: Box<[Page]>, - len: usize, - offset: usize, -} - -impl AlignedSlice { - /// Allocate a slice aligned to ALIGN with at least `len` items, with `offset` from - /// page alignment. - fn new_zeroed(len: usize, offset: usize) -> Self { - assert!(offset < PAGE_SIZE); - let total_len = len + offset; - let items = (total_len / PAGE_SIZE) + if total_len % PAGE_SIZE > 0 { 1 } else { 0 }; - let buf = vec![Page([0u8; PAGE_SIZE]); items].into_boxed_slice(); - AlignedSlice { buf, len, offset } - } -} - -impl ops::Deref for AlignedSlice { - type Target = [u8]; - fn deref(&self) -> &Self::Target { - unsafe { slice::from_raw_parts(self.buf.as_ptr().cast::().add(self.offset), self.len) } - } -} - -impl ops::DerefMut for AlignedSlice { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { - slice::from_raw_parts_mut( - self.buf.as_mut_ptr().cast::().add(self.offset), - self.len, - ) - } - } -} - -mod mcpy { - use super::*; - - struct Cfg { - len: usize, - s_off: usize, - d_off: usize, - } - - fn setup(cfg: Cfg) -> (usize, AlignedSlice, AlignedSlice) { - let Cfg { len, s_off, d_off } = cfg; - println!("bytes: {len} bytes, src offset: {s_off}, dst offset: {d_off}"); - let mut src = AlignedSlice::new_zeroed(len, s_off); - let dst = AlignedSlice::new_zeroed(len, d_off); - src.fill(1); - (len, src, dst) - } - - #[library_benchmark] - #[benches::aligned( - // Both aligned - args = [ - Cfg { len: 16, s_off: 0, d_off: 0 }, - Cfg { len: 32, s_off: 0, d_off: 0 }, - Cfg { len: 64, s_off: 0, d_off: 0 }, - Cfg { len: 512, s_off: 0, d_off: 0 }, - Cfg { len: 4096, s_off: 0, d_off: 0 }, - Cfg { len: MEG1, s_off: 0, d_off: 0 }, - ], - setup = setup, - )] - #[benches::offset( - // Both at the same offset - args = [ - Cfg { len: 16, s_off: 65, d_off: 65 }, - Cfg { len: 32, s_off: 65, d_off: 65 }, - Cfg { len: 64, s_off: 65, d_off: 65 }, - Cfg { len: 512, s_off: 65, d_off: 65 }, - Cfg { len: 4096, s_off: 65, d_off: 65 }, - Cfg { len: MEG1, s_off: 65, d_off: 65 }, - ], - setup = setup, - )] - #[benches::misaligned( - // `src` and `dst` both misaligned by different amounts - args = [ - Cfg { len: 16, s_off: 65, d_off: 66 }, - Cfg { len: 32, s_off: 65, d_off: 66 }, - Cfg { len: 64, s_off: 65, d_off: 66 }, - Cfg { len: 512, s_off: 65, d_off: 66 }, - Cfg { len: 4096, s_off: 65, d_off: 66 }, - Cfg { len: MEG1, s_off: 65, d_off: 66 }, - ], - setup = setup, - )] - fn bench((len, mut dst, src): (usize, AlignedSlice, AlignedSlice)) { - unsafe { - black_box(memcpy( - black_box(dst.as_mut_ptr()), - black_box(src.as_ptr()), - black_box(len), - )); - } - } - - library_benchmark_group!(name = memcpy; benchmarks = bench); -} - -mod mset { - use super::*; - - struct Cfg { - len: usize, - offset: usize, - } - - fn setup(Cfg { len, offset }: Cfg) -> (usize, AlignedSlice) { - println!("bytes: {len}, offset: {offset}"); - (len, AlignedSlice::new_zeroed(len, offset)) - } - - #[library_benchmark] - #[benches::aligned( - args = [ - Cfg { len: 16, offset: 0 }, - Cfg { len: 32, offset: 0 }, - Cfg { len: 64, offset: 0 }, - Cfg { len: 512, offset: 0 }, - Cfg { len: 4096, offset: 0 }, - Cfg { len: MEG1, offset: 0 }, - ], - setup = setup, - )] - #[benches::offset( - args = [ - Cfg { len: 16, offset: 65 }, - Cfg { len: 32, offset: 65 }, - Cfg { len: 64, offset: 65 }, - Cfg { len: 512, offset: 65 }, - Cfg { len: 4096, offset: 65 }, - Cfg { len: MEG1, offset: 65 }, - ], - setup = setup, - )] - fn bench((len, mut dst): (usize, AlignedSlice)) { - unsafe { - black_box(memset( - black_box(dst.as_mut_ptr()), - black_box(27), - black_box(len), - )); - } - } - - library_benchmark_group!(name = memset; benchmarks = bench); -} - -mod mcmp { - use super::*; - - struct Cfg { - len: usize, - s_off: usize, - d_off: usize, - } - - fn setup(cfg: Cfg) -> (usize, AlignedSlice, AlignedSlice) { - let Cfg { len, s_off, d_off } = cfg; - println!("bytes: {len}, src offset: {s_off}, dst offset: {d_off}"); - let b1 = AlignedSlice::new_zeroed(len, s_off); - let mut b2 = AlignedSlice::new_zeroed(len, d_off); - b2[len - 1] = 1; - (len, b1, b2) - } - - #[library_benchmark] - #[benches::aligned( - // Both aligned - args = [ - Cfg { len: 16, s_off: 0, d_off: 0 }, - Cfg { len: 32, s_off: 0, d_off: 0 }, - Cfg { len: 64, s_off: 0, d_off: 0 }, - Cfg { len: 512, s_off: 0, d_off: 0 }, - Cfg { len: 4096, s_off: 0, d_off: 0 }, - Cfg { len: MEG1, s_off: 0, d_off: 0 }, - ], - setup = setup - )] - #[benches::offset( - // Both at the same offset - args = [ - Cfg { len: 16, s_off: 65, d_off: 65 }, - Cfg { len: 32, s_off: 65, d_off: 65 }, - Cfg { len: 64, s_off: 65, d_off: 65 }, - Cfg { len: 512, s_off: 65, d_off: 65 }, - Cfg { len: 4096, s_off: 65, d_off: 65 }, - Cfg { len: MEG1, s_off: 65, d_off: 65 }, - ], - setup = setup - )] - #[benches::misaligned( - // `src` and `dst` both misaligned by different amounts - args = [ - Cfg { len: 16, s_off: 65, d_off: 66 }, - Cfg { len: 32, s_off: 65, d_off: 66 }, - Cfg { len: 64, s_off: 65, d_off: 66 }, - Cfg { len: 512, s_off: 65, d_off: 66 }, - Cfg { len: 4096, s_off: 65, d_off: 66 }, - Cfg { len: MEG1, s_off: 65, d_off: 66 }, - ], - setup = setup - )] - fn bench((len, mut dst, src): (usize, AlignedSlice, AlignedSlice)) { - unsafe { - black_box(memcmp( - black_box(dst.as_mut_ptr()), - black_box(src.as_ptr()), - black_box(len), - )); - } - } - - library_benchmark_group!(name = memcmp; benchmarks = bench); -} - -mod mmove { - use super::*; - use Spread::{Aligned, Large, Medium, Small}; - - struct Cfg { - len: usize, - spread: Spread, - off: usize, - } - - enum Spread { - /// `src` and `dst` are close and have the same alignment (or offset). - Aligned, - /// `src` and `dst` are close. - Small, - /// `src` and `dst` are halfway offset in the buffer. - Medium, - /// `src` and `dst` only overlap by a single byte. - Large, - } - - // Note that small and large are - fn calculate_spread(len: usize, spread: Spread) -> usize { - match spread { - // Note that this test doesn't make sense for lengths less than len=128 - Aligned => { - assert!(len > MAX_ALIGN, "aligned memset would have no overlap"); - MAX_ALIGN - } - Small => 1, - Medium => (len / 2) + 1, // add 1 so all are misaligned - Large => len - 1, - } - } - - fn setup_forward(cfg: Cfg) -> (usize, usize, AlignedSlice) { - let Cfg { len, spread, off } = cfg; - let spread = calculate_spread(len, spread); - println!("bytes: {len}, spread: {spread}, offset: {off}, forward"); - assert!(spread < len, "memmove tests should have some overlap"); - let mut buf = AlignedSlice::new_zeroed(len + spread, off); - let mut fill: usize = 0; - buf[..len].fill_with(|| { - fill += 1; - fill as u8 - }); - (len, spread, buf) - } - - fn setup_backward(cfg: Cfg) -> (usize, usize, AlignedSlice) { - let Cfg { len, spread, off } = cfg; - let spread = calculate_spread(len, spread); - println!("bytes: {len}, spread: {spread}, offset: {off}, backward"); - assert!(spread < len, "memmove tests should have some overlap"); - let mut buf = AlignedSlice::new_zeroed(len + spread, off); - let mut fill: usize = 0; - buf[spread..].fill_with(|| { - fill += 1; - fill as u8 - }); - (len, spread, buf) - } - - #[library_benchmark] - #[benches::aligned( - args = [ - // Don't test small spreads since there is no overlap - Cfg { len: 4096, spread: Aligned, off: 0 }, - Cfg { len: MEG1, spread: Aligned, off: 0 }, - ], - setup = setup_forward - )] - #[benches::small_spread( - args = [ - Cfg { len: 16, spread: Small, off: 0 }, - Cfg { len: 32, spread: Small, off: 0 }, - Cfg { len: 64, spread: Small, off: 0 }, - Cfg { len: 512, spread: Small, off: 0 }, - Cfg { len: 4096, spread: Small, off: 0 }, - Cfg { len: MEG1, spread: Small, off: 0 }, - ], - setup = setup_forward - )] - #[benches::medium_spread( - args = [ - Cfg { len: 16, spread: Medium, off: 0 }, - Cfg { len: 32, spread: Medium, off: 0 }, - Cfg { len: 64, spread: Medium, off: 0 }, - Cfg { len: 512, spread: Medium, off: 0 }, - Cfg { len: 4096, spread: Medium, off: 0 }, - Cfg { len: MEG1, spread: Medium, off: 0 }, - ], - setup = setup_forward - )] - #[benches::large_spread( - args = [ - Cfg { len: 16, spread: Large, off: 0 }, - Cfg { len: 32, spread: Large, off: 0 }, - Cfg { len: 64, spread: Large, off: 0 }, - Cfg { len: 512, spread: Large, off: 0 }, - Cfg { len: 4096, spread: Large, off: 0 }, - Cfg { len: MEG1, spread: Large, off: 0 }, - ], - setup = setup_forward - )] - #[benches::aligned_off( - args = [ - Cfg { len: 4096, spread: Aligned, off: 65 }, - Cfg { len: MEG1, spread: Aligned, off: 65 }, - ], - setup = setup_forward - )] - #[benches::small_spread_off( - args = [ - Cfg { len: 16, spread: Small, off: 65 }, - Cfg { len: 32, spread: Small, off: 65 }, - Cfg { len: 64, spread: Small, off: 65 }, - Cfg { len: 512, spread: Small, off: 65 }, - Cfg { len: 4096, spread: Small, off: 65 }, - Cfg { len: MEG1, spread: Small, off: 65 }, - ], - setup = setup_forward - )] - #[benches::medium_spread_off( - args = [ - Cfg { len: 16, spread: Medium, off: 65 }, - Cfg { len: 32, spread: Medium, off: 65 }, - Cfg { len: 64, spread: Medium, off: 65 }, - Cfg { len: 512, spread: Medium, off: 65 }, - Cfg { len: 4096, spread: Medium, off: 65 }, - Cfg { len: MEG1, spread: Medium, off: 65 }, - ], - setup = setup_forward - )] - #[benches::large_spread_off( - args = [ - Cfg { len: 16, spread: Large, off: 65 }, - Cfg { len: 32, spread: Large, off: 65 }, - Cfg { len: 64, spread: Large, off: 65 }, - Cfg { len: 512, spread: Large, off: 65 }, - Cfg { len: 4096, spread: Large, off: 65 }, - Cfg { len: MEG1, spread: Large, off: 65 }, - ], - setup = setup_forward - )] - fn forward((len, spread, mut buf): (usize, usize, AlignedSlice)) { - // Test moving from the start of the buffer toward the end - unsafe { - black_box(memmove( - black_box(buf[spread..].as_mut_ptr()), - black_box(buf.as_ptr()), - black_box(len), - )); - } - } - - #[library_benchmark] - #[benches::aligned( - args = [ - // Don't test small spreads since there is no overlap - Cfg { len: 4096, spread: Aligned, off: 0 }, - Cfg { len: MEG1, spread: Aligned, off: 0 }, - ], - setup = setup_backward - )] - #[benches::small_spread( - args = [ - Cfg { len: 16, spread: Small, off: 0 }, - Cfg { len: 32, spread: Small, off: 0 }, - Cfg { len: 64, spread: Small, off: 0 }, - Cfg { len: 512, spread: Small, off: 0 }, - Cfg { len: 4096, spread: Small, off: 0 }, - Cfg { len: MEG1, spread: Small, off: 0 }, - ], - setup = setup_backward - )] - #[benches::medium_spread( - args = [ - Cfg { len: 16, spread: Medium, off: 0 }, - Cfg { len: 32, spread: Medium, off: 0 }, - Cfg { len: 64, spread: Medium, off: 0 }, - Cfg { len: 512, spread: Medium, off: 0 }, - Cfg { len: 4096, spread: Medium, off: 0 }, - Cfg { len: MEG1, spread: Medium, off: 0 }, - ], - setup = setup_backward - )] - #[benches::large_spread( - args = [ - Cfg { len: 16, spread: Large, off: 0 }, - Cfg { len: 32, spread: Large, off: 0 }, - Cfg { len: 64, spread: Large, off: 0 }, - Cfg { len: 512, spread: Large, off: 0 }, - Cfg { len: 4096, spread: Large, off: 0 }, - Cfg { len: MEG1, spread: Large, off: 0 }, - ], - setup = setup_backward - )] - #[benches::aligned_off( - args = [ - // Don't test small spreads since there is no overlap - Cfg { len: 4096, spread: Aligned, off: 65 }, - Cfg { len: MEG1, spread: Aligned, off: 65 }, - ], - setup = setup_backward - )] - #[benches::small_spread_off( - args = [ - Cfg { len: 16, spread: Small, off: 65 }, - Cfg { len: 32, spread: Small, off: 65 }, - Cfg { len: 64, spread: Small, off: 65 }, - Cfg { len: 512, spread: Small, off: 65 }, - Cfg { len: 4096, spread: Small, off: 65 }, - Cfg { len: MEG1, spread: Small, off: 65 }, - ], - setup = setup_backward - )] - #[benches::medium_spread_off( - args = [ - Cfg { len: 16, spread: Medium, off: 65 }, - Cfg { len: 32, spread: Medium, off: 65 }, - Cfg { len: 64, spread: Medium, off: 65 }, - Cfg { len: 512, spread: Medium, off: 65 }, - Cfg { len: 4096, spread: Medium, off: 65 }, - Cfg { len: MEG1, spread: Medium, off: 65 }, - ], - setup = setup_backward - )] - #[benches::large_spread_off( - args = [ - Cfg { len: 16, spread: Large, off: 65 }, - Cfg { len: 32, spread: Large, off: 65 }, - Cfg { len: 64, spread: Large, off: 65 }, - Cfg { len: 512, spread: Large, off: 65 }, - Cfg { len: 4096, spread: Large, off: 65 }, - Cfg { len: MEG1, spread: Large, off: 65 }, - ], - setup = setup_backward - )] - fn backward((len, spread, mut buf): (usize, usize, AlignedSlice)) { - // Test moving from the end of the buffer toward the start - unsafe { - black_box(memmove( - black_box(buf.as_mut_ptr()), - black_box(buf[spread..].as_ptr()), - black_box(len), - )); - } - } - - library_benchmark_group!(name = memmove; benchmarks = forward, backward); -} - -use mcmp::memcmp; -use mcpy::memcpy; -use mmove::memmove; -use mset::memset; - -main!(library_benchmark_groups = memcpy, memset, memcmp, memmove); diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs deleted file mode 100644 index e8f4eb4dd22..00000000000 --- a/library/compiler-builtins/testcrate/build.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::collections::HashSet; - -mod builtins_configure { - include!("../compiler-builtins/configure.rs"); -} - -/// Features to enable -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -enum Feature { - NoSysF128, - NoSysF128IntConvert, - NoSysF16, - NoSysF16F64Convert, - NoSysF16F128Convert, -} - -impl Feature { - fn implies(self) -> &'static [Self] { - match self { - Self::NoSysF128 => [Self::NoSysF128IntConvert, Self::NoSysF16F128Convert].as_slice(), - Self::NoSysF128IntConvert => [].as_slice(), - Self::NoSysF16 => [Self::NoSysF16F64Convert, Self::NoSysF16F128Convert].as_slice(), - Self::NoSysF16F64Convert => [].as_slice(), - Self::NoSysF16F128Convert => [].as_slice(), - } - } -} - -fn main() { - println!("cargo::rerun-if-changed=../configure.rs"); - - let target = builtins_configure::Target::from_env(); - let mut features = HashSet::new(); - - // These platforms do not have f128 symbols available in their system libraries, so - // skip related tests. - if target.arch == "arm" - || target.vendor == "apple" - || target.env == "msvc" - // GCC and LLVM disagree on the ABI of `f16` and `f128` with MinGW. See - // . - || (target.os == "windows" && target.env == "gnu") - // FIXME(llvm): There is an ABI incompatibility between GCC and Clang on 32-bit x86. - // See . - || target.arch == "x86" - // 32-bit PowerPC and 64-bit LE gets code generated that Qemu cannot handle. See - // . - || target.arch == "powerpc" - || target.arch == "powerpc64le" - // FIXME: We get different results from the builtin functions. See - // . - || target.arch == "powerpc64" - { - features.insert(Feature::NoSysF128); - } - - if target.arch == "x86" { - // 32-bit x86 does not have `__fixunstfti`/`__fixtfti` but does have everything else - features.insert(Feature::NoSysF128IntConvert); - // FIXME: 32-bit x86 has a bug in `f128 -> f16` system libraries - features.insert(Feature::NoSysF16F128Convert); - } - - // These platforms do not have f16 symbols available in their system libraries, so - // skip related tests. Most of these are missing `f16 <-> f32` conversion routines. - if (target.arch == "aarch64" && target.os == "linux") - || target.arch.starts_with("arm") - || target.arch == "powerpc" - || target.arch == "powerpc64" - || target.arch == "powerpc64le" - || target.arch == "loongarch64" - || (target.arch == "x86" && !target.has_feature("sse")) - || target.os == "windows" - // Linking says "error: function signature mismatch: __extendhfsf2" and seems to - // think the signature is either `(i32) -> f32` or `(f32) -> f32`. See - // . - || target.arch == "wasm32" - || target.arch == "wasm64" - { - features.insert(Feature::NoSysF16); - } - - // These platforms are missing either `__extendhfdf2` or `__truncdfhf2`. - if target.vendor == "apple" || target.os == "windows" { - features.insert(Feature::NoSysF16F64Convert); - } - - // Add implied features. Collection is required for borrows. - features.extend( - features - .iter() - .flat_map(|x| x.implies()) - .copied() - .collect::>(), - ); - - for feature in features { - let (name, warning) = match feature { - Feature::NoSysF128 => ("no-sys-f128", "using apfloat fallback for f128"), - Feature::NoSysF128IntConvert => ( - "no-sys-f128-int-convert", - "using apfloat fallback for f128 <-> int conversions", - ), - Feature::NoSysF16F64Convert => ( - "no-sys-f16-f64-convert", - "using apfloat fallback for f16 <-> f64 conversions", - ), - Feature::NoSysF16F128Convert => ( - "no-sys-f16-f128-convert", - "using apfloat fallback for f16 <-> f128 conversions", - ), - Feature::NoSysF16 => ("no-sys-f16", "using apfloat fallback for f16"), - }; - println!("cargo:warning={warning}"); - println!("cargo:rustc-cfg=feature=\"{name}\""); - } - - builtins_configure::configure_aliases(&target); - builtins_configure::configure_f16_f128(&target); -} diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs deleted file mode 100644 index 45a3a1ad467..00000000000 --- a/library/compiler-builtins/testcrate/src/bench.rs +++ /dev/null @@ -1,366 +0,0 @@ -use core::cell::RefCell; - -use alloc::vec::Vec; -use compiler_builtins::float::Float; - -/// Fuzz with these many items to ensure equal functions -pub const CHECK_ITER_ITEMS: u32 = 10_000; -/// Benchmark with this many items to get a variety -pub const BENCH_ITER_ITEMS: u32 = 500; - -/// Still run benchmarks/tests but don't check correctness between compiler-builtins and -/// builtin system functions functions -pub fn skip_sys_checks(test_name: &str) -> bool { - const ALWAYS_SKIPPED: &[&str] = &[ - // FIXME(f16_f128): system symbols have incorrect results - // - "extend_f16_f32", - "trunc_f32_f16", - "trunc_f64_f16", - // FIXME(#616): re-enable once fix is in nightly - // - "mul_f32", - "mul_f64", - ]; - - // FIXME(f16_f128): error on LE ppc64. There are more tests that are cfg-ed out completely - // in their benchmark modules due to runtime panics. - // - const PPC64LE_SKIPPED: &[&str] = &["extend_f32_f128"]; - - // FIXME(f16_f128): system symbols have incorrect results - // - const X86_NO_SSE_SKIPPED: &[&str] = &[ - "add_f128", "sub_f128", "mul_f128", "div_f128", "powi_f32", "powi_f64", - ]; - - // FIXME(f16_f128): Wide multiply carry bug in `compiler-rt`, re-enable when nightly no longer - // uses `compiler-rt` version. - // - const AARCH64_SKIPPED: &[&str] = &["mul_f128", "div_f128"]; - - // FIXME(llvm): system symbols have incorrect results on Windows - // - const WINDOWS_SKIPPED: &[&str] = &[ - "conv_f32_u128", - "conv_f32_i128", - "conv_f64_u128", - "conv_f64_i128", - ]; - - if cfg!(target_arch = "arm") { - // The Arm symbols need a different ABI that our macro doesn't handle, just skip it - return true; - } - - if ALWAYS_SKIPPED.contains(&test_name) { - return true; - } - - if cfg!(all(target_arch = "powerpc64", target_endian = "little")) - && PPC64LE_SKIPPED.contains(&test_name) - { - return true; - } - - if cfg!(all(target_arch = "x86", not(target_feature = "sse"))) - && X86_NO_SSE_SKIPPED.contains(&test_name) - { - return true; - } - - if cfg!(target_arch = "aarch64") && AARCH64_SKIPPED.contains(&test_name) { - return true; - } - - if cfg!(target_family = "windows") && WINDOWS_SKIPPED.contains(&test_name) { - return true; - } - - false -} - -/// Still run benchmarks/tests but don't check correctness between compiler-builtins and -/// assembly functions -pub fn skip_asm_checks(_test_name: &str) -> bool { - // Nothing to skip at this time - false -} - -/// Create a comparison of the system symbol, compiler_builtins, and optionally handwritten -/// assembly. -/// -/// # Safety -/// -/// The signature must be correct and any assembly must be sound. -#[macro_export] -macro_rules! float_bench { - ( - // Name of this benchmark - name: $name:ident, - // The function signature to be tested - sig: ($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty, - // Path to the crate in compiler_builtins - crate_fn: $crate_fn:path, - // Optional alias on ppc - $( crate_fn_ppc: $crate_fn_ppc:path, )? - // Name of the system symbol - sys_fn: $sys_fn:ident, - // Optional alias on ppc - $( sys_fn_ppc: $sys_fn_ppc:path, )? - // Meta saying whether the system symbol is available - sys_available: $sys_available:meta, - // An optional function to validate the results of two functions are equal, if not - // just `$ret_ty::check_eq` - $( output_eq: $output_eq:expr, )? - // Assembly implementations, if any. - asm: [ - $( - #[cfg($asm_meta:meta)] { - $($asm_tt:tt)* - } - );* - $(;)? - ] - $(,)? - ) => {paste::paste! { - // SAFETY: macro invocation must use the correct signature - #[cfg($sys_available)] - unsafe extern "C" { - /// Binding for the system function - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - fn $sys_fn($($arg: $arg_ty),*) -> $ret_ty; - - - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - float_bench! { @coalesce_fn $($sys_fn_ppc)? => - fn $sys_fn($($arg: $arg_ty),*) -> $ret_ty; - } - } - - fn $name(c: &mut Criterion) { - use core::hint::black_box; - use compiler_builtins::float::Float; - use $crate::bench::TestIO; - - #[inline(never)] // equalize with external calls - fn crate_fn($($arg: $arg_ty),*) -> $ret_ty { - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - let target_crate_fn = $crate_fn; - - // On PPC, use an alias if specified - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - let target_crate_fn = float_bench!(@coalesce $($crate_fn_ppc)?, $crate_fn); - - target_crate_fn( $($arg),* ) - } - - #[inline(always)] // already a branch - #[cfg($sys_available)] - fn sys_fn($($arg: $arg_ty),*) -> $ret_ty { - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - let target_sys_fn = $sys_fn; - - // On PPC, use an alias if specified - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - let target_sys_fn = float_bench!(@coalesce $($sys_fn_ppc)?, $sys_fn); - - unsafe { target_sys_fn( $($arg),* ) } - } - - #[inline(never)] // equalize with external calls - #[cfg(any( $($asm_meta),* ))] - fn asm_fn($(mut $arg: $arg_ty),*) -> $ret_ty { - use core::arch::asm; - $( - #[cfg($asm_meta)] - unsafe { $($asm_tt)* } - )* - } - - let testvec = <($($arg_ty),*)>::make_testvec($crate::bench::CHECK_ITER_ITEMS); - let benchvec = <($($arg_ty),*)>::make_testvec($crate::bench::BENCH_ITER_ITEMS); - let test_name = stringify!($name); - let check_eq = float_bench!(@coalesce $($output_eq)?, $ret_ty::check_eq); - - // Verify math lines up. We run the crate functions even if we don't validate the - // output here to make sure there are no panics or crashes. - - #[cfg($sys_available)] - for ($($arg),*) in testvec.iter().copied() { - let crate_res = crate_fn($($arg),*); - let sys_res = sys_fn($($arg),*); - - if $crate::bench::skip_sys_checks(test_name) { - continue; - } - - assert!( - check_eq(crate_res, sys_res), - "{test_name}{:?}: crate: {crate_res:?}, sys: {sys_res:?}", - ($($arg),* ,) - ); - } - - #[cfg(any( $($asm_meta),* ))] - { - for ($($arg),*) in testvec.iter().copied() { - let crate_res = crate_fn($($arg),*); - let asm_res = asm_fn($($arg),*); - - if $crate::bench::skip_asm_checks(test_name) { - continue; - } - - assert!( - check_eq(crate_res, asm_res), - "{test_name}{:?}: crate: {crate_res:?}, asm: {asm_res:?}", - ($($arg),* ,) - ); - } - } - - let mut group = c.benchmark_group(test_name); - group.bench_function("compiler-builtins", |b| b.iter(|| { - for ($($arg),*) in benchvec.iter().copied() { - black_box(crate_fn( $(black_box($arg)),* )); - } - })); - - #[cfg($sys_available)] - group.bench_function("system", |b| b.iter(|| { - for ($($arg),*) in benchvec.iter().copied() { - black_box(sys_fn( $(black_box($arg)),* )); - } - })); - - #[cfg(any( $($asm_meta),* ))] - group.bench_function(&format!( - "assembly ({} {})", std::env::consts::ARCH, std::env::consts::FAMILY - ), |b| b.iter(|| { - for ($($arg),*) in benchvec.iter().copied() { - black_box(asm_fn( $(black_box($arg)),* )); - } - })); - - group.finish(); - } - }}; - - // Allow overriding a default - (@coalesce $specified:expr, $default:expr) => { $specified }; - (@coalesce, $default:expr) => { $default }; - - // Allow overriding a function name - (@coalesce_fn $specified:ident => fn $default_name:ident $($tt:tt)+) => { - fn $specified $($tt)+ - }; - (@coalesce_fn => fn $default_name:ident $($tt:tt)+) => { - fn $default_name $($tt)+ - }; -} - -/// A type used as either an input or output to/from a benchmark function. -pub trait TestIO: Sized { - fn make_testvec(len: u32) -> Vec; - fn check_eq(a: Self, b: Self) -> bool; -} - -macro_rules! impl_testio { - (float $($f_ty:ty),+) => {$( - impl TestIO for $f_ty { - fn make_testvec(len: u32) -> Vec { - // refcell because fuzz_* takes a `Fn` - let ret = RefCell::new(Vec::new()); - crate::fuzz_float(len, |a| ret.borrow_mut().push(a)); - ret.into_inner() - } - - fn check_eq(a: Self, b: Self) -> bool { - Float::eq_repr(a, b) - } - } - - impl TestIO for ($f_ty, $f_ty) { - fn make_testvec(len: u32) -> Vec { - // refcell because fuzz_* takes a `Fn` - let ret = RefCell::new(Vec::new()); - crate::fuzz_float_2(len, |a, b| ret.borrow_mut().push((a, b))); - ret.into_inner() - } - - fn check_eq(_a: Self, _b: Self) -> bool { - unimplemented!() - } - } - )*}; - - (int $($i_ty:ty),+) => {$( - impl TestIO for $i_ty { - fn make_testvec(len: u32) -> Vec { - // refcell because fuzz_* takes a `Fn` - let ret = RefCell::new(Vec::new()); - crate::fuzz(len, |a| ret.borrow_mut().push(a)); - ret.into_inner() - } - - fn check_eq(a: Self, b: Self) -> bool { - a == b - } - } - - impl TestIO for ($i_ty, $i_ty) { - fn make_testvec(len: u32) -> Vec { - // refcell because fuzz_* takes a `Fn` - let ret = RefCell::new(Vec::new()); - crate::fuzz_2(len, |a, b| ret.borrow_mut().push((a, b))); - ret.into_inner() - } - - fn check_eq(_a: Self, _b: Self) -> bool { - unimplemented!() - } - } - )*}; - - ((float, int) ($f_ty:ty, $i_ty:ty)) => { - impl TestIO for ($f_ty, $i_ty) { - fn make_testvec(len: u32) -> Vec { - // refcell because fuzz_* takes a `Fn` - let ivec = RefCell::new(Vec::new()); - let fvec = RefCell::new(Vec::new()); - - crate::fuzz(len.isqrt(), |a| ivec.borrow_mut().push(a)); - crate::fuzz_float(len.isqrt(), |a| fvec.borrow_mut().push(a)); - - let mut ret = Vec::new(); - let ivec = ivec.into_inner(); - let fvec = fvec.into_inner(); - - for f in fvec { - for i in &ivec { - ret.push((f, *i)); - } - } - - ret - } - - fn check_eq(_a: Self, _b: Self) -> bool { - unimplemented!() - } - } - } -} - -#[cfg(f16_enabled)] -impl_testio!(float f16); -impl_testio!(float f32, f64); -#[cfg(f128_enabled)] -impl_testio!(float f128); -impl_testio!(int i16, i32, i64, i128); -impl_testio!(int u16, u32, u64, u128); -impl_testio!((float, int)(f32, i32)); -impl_testio!((float, int)(f64, i32)); -#[cfg(f128_enabled)] -impl_testio!((float, int)(f128, i32)); diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs deleted file mode 100644 index c61618755e9..00000000000 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ /dev/null @@ -1,338 +0,0 @@ -//! This crate is for integration testing and fuzz testing of functions in `compiler-builtins`. This -//! includes publicly documented intrinsics and some internal alternative implementation functions -//! such as `usize_leading_zeros_riscv` (which are tested because they are configured for -//! architectures not tested by the CI). -//! -//! The general idea is to use a combination of edge case testing and randomized fuzz testing. The -//! edge case testing is crucial for checking cases like where both inputs are equal or equal to -//! special values such as `i128::MIN`, which is unlikely for the random fuzzer by itself to -//! encounter. The randomized fuzz testing is specially designed to cover wide swaths of search -//! space in as few iterations as possible. See `fuzz_values` in `testcrate/tests/misc.rs` for an -//! example. -//! -//! Some floating point tests are disabled for specific architectures, because they do not have -//! correct rounding. -#![no_std] -#![cfg_attr(f128_enabled, feature(f128))] -#![cfg_attr(f16_enabled, feature(f16))] - -pub mod bench; -extern crate alloc; - -use compiler_builtins::float::Float; -use compiler_builtins::int::{Int, MinInt}; - -use rand_xoshiro::Xoshiro128StarStar; -use rand_xoshiro::rand_core::{RngCore, SeedableRng}; - -/// Sets the number of fuzz iterations run for most tests. In practice, the vast majority of bugs -/// are caught by the edge case testers. Most of the remaining bugs triggered by more complex -/// sequences are caught well within 10_000 fuzz iterations. For classes of algorithms like division -/// that are vulnerable to rare edge cases, we want 1_000_000 iterations to be more confident. In -/// practical CI, however, we only want to run the more strenuous test once to catch algorithmic -/// level bugs, and run the 10_000 iteration test on most targets. Target-dependent bugs are likely -/// to involve miscompilation and misconfiguration that is likely to break algorithms in quickly -/// caught ways. We choose to configure `N = 1_000_000` iterations for `x86_64` targets (and if -/// debug assertions are disabled. Tests without `--release` would take too long) which are likely -/// to have fast hardware, and run `N = 10_000` for all other targets. -pub const N: u32 = if cfg!(target_arch = "x86_64") && !cfg!(debug_assertions) { - 1_000_000 -} else { - 10_000 -}; - -/// Random fuzzing step. When run several times, it results in excellent fuzzing entropy such as: -/// 11110101010101011110111110011111 -/// 10110101010100001011101011001010 -/// 1000000000000000 -/// 10000000000000110111110000001010 -/// 1111011111111101010101111110101 -/// 101111111110100000000101000000 -/// 10000000110100000000100010101 -/// 1010101010101000 -fn fuzz_step(rng: &mut Xoshiro128StarStar, x: &mut I) { - let ones = !I::ZERO; - let bit_indexing_mask: u32 = I::BITS - 1; - // It happens that all the RNG we need can come from one call. 7 bits are needed to index a - // worst case 128 bit integer, and there are 4 indexes that need to be made plus 4 bits for - // selecting operations - let rng32 = rng.next_u32(); - - // Randomly OR, AND, and XOR randomly sized and shifted continuous strings of - // ones with `lhs` and `rhs`. - let r0 = bit_indexing_mask & rng32; - let r1 = bit_indexing_mask & (rng32 >> 7); - let mask = ones.wrapping_shl(r0).rotate_left(r1); - match (rng32 >> 14) % 4 { - 0 => *x |= mask, - 1 => *x &= mask, - // both 2 and 3 to make XORs as common as ORs and ANDs combined - _ => *x ^= mask, - } - - // Alternating ones and zeros (e.x. 0b1010101010101010). This catches second-order - // problems that might occur for algorithms with two modes of operation (potentially - // there is some invariant that can be broken and maintained via alternating between modes, - // breaking the algorithm when it reaches the end). - let mut alt_ones = I::ONE; - for _ in 0..(I::BITS / 2) { - alt_ones <<= 2; - alt_ones |= I::ONE; - } - let r0 = bit_indexing_mask & (rng32 >> 16); - let r1 = bit_indexing_mask & (rng32 >> 23); - let mask = alt_ones.wrapping_shl(r0).rotate_left(r1); - match rng32 >> 30 { - 0 => *x |= mask, - 1 => *x &= mask, - _ => *x ^= mask, - } -} - -// We need macros like this, because `#![no_std]` prevents us from using iterators -macro_rules! edge_cases { - ($I:ident, $case:ident, $inner:block) => { - for i0 in 0..$I::FUZZ_NUM { - let mask_lo = (!$I::UnsignedInt::ZERO).wrapping_shr($I::FUZZ_LENGTHS[i0] as u32); - for i1 in i0..I::FUZZ_NUM { - let mask_hi = - (!$I::UnsignedInt::ZERO).wrapping_shl($I::FUZZ_LENGTHS[i1 - i0] as u32); - let $case = I::from_unsigned(mask_lo & mask_hi); - $inner - } - } - }; -} - -/// Feeds a series of fuzzing inputs to `f`. The fuzzer first uses an algorithm designed to find -/// edge cases, followed by a more random fuzzer that runs `n` times. -pub fn fuzz(n: u32, mut f: F) -where - ::UnsignedInt: Int, -{ - // edge case tester. Calls `f` 210 times for u128. - // zero gets skipped by the loop - f(I::ZERO); - edge_cases!(I, case, { - f(case); - }); - - // random fuzzer - let mut rng = Xoshiro128StarStar::seed_from_u64(0); - let mut x: I = MinInt::ZERO; - for _ in 0..n { - fuzz_step(&mut rng, &mut x); - f(x) - } -} - -/// The same as `fuzz`, except `f` has two inputs. -pub fn fuzz_2(n: u32, f: F) -where - ::UnsignedInt: Int, -{ - // Check cases where the first and second inputs are zero. Both call `f` 210 times for `u128`. - edge_cases!(I, case, { - f(I::ZERO, case); - }); - edge_cases!(I, case, { - f(case, I::ZERO); - }); - // Nested edge tester. Calls `f` 44100 times for `u128`. - edge_cases!(I, case0, { - edge_cases!(I, case1, { - f(case0, case1); - }) - }); - - // random fuzzer - let mut rng = Xoshiro128StarStar::seed_from_u64(0); - let mut x: I = I::ZERO; - let mut y: I = I::ZERO; - for _ in 0..n { - fuzz_step(&mut rng, &mut x); - fuzz_step(&mut rng, &mut y); - f(x, y) - } -} - -/// Tester for shift functions -pub fn fuzz_shift(f: F) { - // Shift functions are very simple and do not need anything other than shifting a small - // set of random patterns for every fuzz length. - let mut rng = Xoshiro128StarStar::seed_from_u64(0); - let mut x: I = MinInt::ZERO; - for i in 0..I::FUZZ_NUM { - fuzz_step(&mut rng, &mut x); - f(x, MinInt::ZERO); - f(x, I::FUZZ_LENGTHS[i] as u32); - } -} - -fn fuzz_float_step(rng: &mut Xoshiro128StarStar, f: &mut F) { - let rng32 = rng.next_u32(); - // we need to fuzz the different parts of the float separately, because the masking on larger - // significands will tend to set the exponent to all ones or all zeros frequently - - // sign bit fuzzing - let sign = (rng32 & 1) != 0; - - // exponent fuzzing. Only 4 bits for the selector needed. - let ones = (F::Int::ONE << F::EXP_BITS) - F::Int::ONE; - let r0 = (rng32 >> 1) % F::EXP_BITS; - let r1 = (rng32 >> 5) % F::EXP_BITS; - // custom rotate shift. Note that `F::Int` is unsigned, so we can shift right without smearing - // the sign bit. - let mask = if r1 == 0 { - ones.wrapping_shr(r0) - } else { - let tmp = ones.wrapping_shr(r0); - (tmp.wrapping_shl(r1) | tmp.wrapping_shr(F::EXP_BITS - r1)) & ones - }; - let mut exp = (f.to_bits() & F::EXP_MASK) >> F::SIG_BITS; - match (rng32 >> 9) % 4 { - 0 => exp |= mask, - 1 => exp &= mask, - _ => exp ^= mask, - } - - // significand fuzzing - let mut sig = f.to_bits() & F::SIG_MASK; - fuzz_step(rng, &mut sig); - sig &= F::SIG_MASK; - - *f = F::from_parts(sign, exp, sig); -} - -macro_rules! float_edge_cases { - ($F:ident, $case:ident, $inner:block) => { - for exponent in [ - F::Int::ZERO, - F::Int::ONE, - F::Int::ONE << (F::EXP_BITS / 2), - (F::Int::ONE << (F::EXP_BITS - 1)) - F::Int::ONE, - F::Int::ONE << (F::EXP_BITS - 1), - (F::Int::ONE << (F::EXP_BITS - 1)) + F::Int::ONE, - (F::Int::ONE << F::EXP_BITS) - F::Int::ONE, - ] - .iter() - { - for significand in [ - F::Int::ZERO, - F::Int::ONE, - F::Int::ONE << (F::SIG_BITS / 2), - (F::Int::ONE << (F::SIG_BITS - 1)) - F::Int::ONE, - F::Int::ONE << (F::SIG_BITS - 1), - (F::Int::ONE << (F::SIG_BITS - 1)) + F::Int::ONE, - (F::Int::ONE << F::SIG_BITS) - F::Int::ONE, - ] - .iter() - { - for sign in [false, true].iter() { - let $case = F::from_parts(*sign, *exponent, *significand); - $inner - } - } - } - }; -} - -pub fn fuzz_float(n: u32, f: E) { - float_edge_cases!(F, case, { - f(case); - }); - - // random fuzzer - let mut rng = Xoshiro128StarStar::seed_from_u64(0); - let mut x = F::ZERO; - for _ in 0..n { - fuzz_float_step(&mut rng, &mut x); - f(x); - } -} - -pub fn fuzz_float_2(n: u32, f: E) { - float_edge_cases!(F, case0, { - float_edge_cases!(F, case1, { - f(case0, case1); - }); - }); - - // random fuzzer - let mut rng = Xoshiro128StarStar::seed_from_u64(0); - let mut x = F::ZERO; - let mut y = F::ZERO; - for _ in 0..n { - fuzz_float_step(&mut rng, &mut x); - fuzz_float_step(&mut rng, &mut y); - f(x, y) - } -} - -/// Perform an operation using builtin types if available, falling back to apfloat if not. -#[macro_export] -macro_rules! apfloat_fallback { - ( - $float_ty:ty, - // Type name in `rustc_apfloat::ieee`. Not a full path, it automatically gets the prefix. - $apfloat_ty:ident, - // Cfg expression for when builtin system operations should be used - $sys_available:meta, - // The expression to run. This expression may use `FloatTy` for its signature. - // Optionally, the final conversion back to a float can be suppressed using - // `=> no_convert` (for e.g. operations that return a bool). - // - // If the apfloat needs a different operation, it can be provided here. - $op:expr $(=> $convert:ident)? $(; $apfloat_op:expr)?, - // Arguments that get passed to `$op` after converting to a float - $($arg:expr),+ - $(,)? - ) => {{ - #[cfg($sys_available)] - let ret = { - type FloatTy = $float_ty; - $op( $($arg),+ ) - }; - - #[cfg(not($sys_available))] - let ret = { - use rustc_apfloat::Float; - type FloatTy = rustc_apfloat::ieee::$apfloat_ty; - - apfloat_fallback!(@inner - fty: $float_ty, - // Apply a conversion to `FloatTy` to each arg, then pass all args to `$op` - op_res: $op( $(FloatTy::from_bits($arg.to_bits().into())),+ ), - $(apfloat_op: $apfloat_op, )? - $(conv_opts: $convert,)? - args: $($arg),+ - ) - }; - - ret - }}; - - // Operations that do not need converting back to a float - (@inner fty: $float_ty:ty, op_res: $val:expr, conv_opts: no_convert, args: $($_arg:expr),+) => { - $val - }; - - // Some apfloat operations return a `StatusAnd` that we need to extract the value from. This - // is the default. - (@inner fty: $float_ty:ty, op_res: $val:expr, args: $($_arg:expr),+) => {{ - // ignore the status, just get the value - let unwrapped = $val.value; - - <$float_ty>::from_bits(FloatTy::to_bits(unwrapped).try_into().unwrap()) - }}; - - // This is the case where we can't use the same expression for the default builtin and - // nonstandard apfloat fallback (e.g. `as` casts in std are normal functions in apfloat, so - // two separate expressions must be specified. - (@inner - fty: $float_ty:ty, op_res: $_val:expr, - apfloat_op: $apfloat_op:expr, args: $($arg:expr),+ - ) => {{ - $apfloat_op($($arg),+) - }}; -} diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs deleted file mode 100644 index 3c0e20f77b1..00000000000 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ /dev/null @@ -1,143 +0,0 @@ -#![allow(unused_macros)] -#![cfg_attr(f128_enabled, feature(f128))] - -use testcrate::*; - -mod int_addsub { - use super::*; - - macro_rules! sum { - ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { - $( - #[test] - fn $fn_add() { - use compiler_builtins::int::addsub::{$fn_add, $fn_sub}; - - fuzz_2(N, |x: $i, y: $i| { - let add0 = x.wrapping_add(y); - let sub0 = x.wrapping_sub(y); - let add1: $i = $fn_add(x, y); - let sub1: $i = $fn_sub(x, y); - if add0 != add1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn_add), x, y, add0, add1 - ); - } - if sub0 != sub1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn_sub), x, y, sub0, sub1 - ); - } - }); - } - )* - }; - } - - macro_rules! overflowing_sum { - ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { - $( - #[test] - fn $fn_add() { - use compiler_builtins::int::addsub::{$fn_add, $fn_sub}; - - fuzz_2(N, |x: $i, y: $i| { - let (add0, add_o0)= x.overflowing_add(y); - let (sub0, sub_o0)= x.overflowing_sub(y); - let mut add_o1 = 0; - let mut sub_o1 = 0; - let add1: $i = $fn_add(x, y, &mut add_o1); - let sub1: $i = $fn_sub(x, y, &mut sub_o1); - if add0 != add1 || i32::from(add_o0) != add_o1 { - panic!( - "{}({}, {}): std: {:?}, builtins: {:?}", - stringify!($fn_add), x, y, (add0, add_o0) , (add1, add_o1) - ); - } - if sub0 != sub1 || i32::from(sub_o0) != sub_o1 { - panic!( - "{}({}, {}): std: {:?}, builtins: {:?}", - stringify!($fn_sub), x, y, (sub0, sub_o0) , (sub1, sub_o1) - ); - } - }); - } - )* - }; - } - - // Integer addition and subtraction is very simple, so 100 fuzzing passes should be plenty. - sum! { - u128, __rust_u128_add, __rust_u128_sub; - i128, __rust_i128_add, __rust_i128_sub; - } - - overflowing_sum! { - u128, __rust_u128_addo, __rust_u128_subo; - i128, __rust_i128_addo, __rust_i128_subo; - } -} - -macro_rules! float_sum { - ($($f:ty, $fn_add:ident, $fn_sub:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { - $( - #[test] - fn $fn_add() { - use core::ops::{Add, Sub}; - use compiler_builtins::float::{{add::$fn_add, sub::$fn_sub}, Float}; - - fuzz_float_2(N, |x: $f, y: $f| { - let add0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Add::add, x, y); - let sub0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Sub::sub, x, y); - let add1: $f = $fn_add(x, y); - let sub1: $f = $fn_sub(x, y); - if !Float::eq_repr(add0, add1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn_add), x, y, add0, add1 - ); - } - if !Float::eq_repr(sub0, sub1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn_sub), x, y, sub0, sub1 - ); - } - }); - } - )* - } -} - -#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -mod float_addsub { - use super::*; - - float_sum! { - f32, __addsf3, __subsf3, Single, all(); - f64, __adddf3, __subdf3, Double, all(); - } -} - -#[cfg(f128_enabled)] -#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] -mod float_addsub_f128 { - use super::*; - - float_sum! { - f128, __addtf3, __subtf3, Quad, not(feature = "no-sys-f128"); - } -} - -#[cfg(f128_enabled)] -#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] -mod float_addsub_f128_ppc { - use super::*; - - float_sum! { - f128, __addkf3, __subkf3, Quad, not(feature = "no-sys-f128"); - } -} diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs deleted file mode 100644 index bfd15a391aa..00000000000 --- a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs +++ /dev/null @@ -1,60 +0,0 @@ -#![cfg(all( - target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - feature = "mem" -))] -#![feature(compiler_builtins_lib)] -#![no_std] - -extern crate compiler_builtins; - -// test runner -extern crate utest_cortex_m_qemu; - -// overrides `panic!` -#[macro_use] -extern crate utest_macros; - -use core::mem; - -macro_rules! panic { - ($($tt:tt)*) => { - upanic!($($tt)*); - }; -} - -extern "C" { - fn __aeabi_memclr4(dest: *mut u8, n: usize); - fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); -} - -struct Aligned { - array: [u8; 8], - _alignment: [u32; 0], -} - -impl Aligned { - fn new() -> Self { - Aligned { - array: [0; 8], - _alignment: [], - } - } -} - -#[test] -fn memclr4() { - let mut aligned = Aligned::new(); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - - for n in 0..9 { - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, 0xff); - __aeabi_memclr4(xs.as_mut_ptr(), n); - } - - assert!(xs[0..n].iter().all(|x| *x == 0)); - } -} diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs deleted file mode 100644 index c892c5aba0f..00000000000 --- a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs +++ /dev/null @@ -1,71 +0,0 @@ -#![cfg(all( - target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - feature = "mem" -))] -#![feature(compiler_builtins_lib)] -#![no_std] - -extern crate compiler_builtins; - -// test runner -extern crate utest_cortex_m_qemu; - -// overrides `panic!` -#[macro_use] -extern crate utest_macros; - -macro_rules! panic { - ($($tt:tt)*) => { - upanic!($($tt)*); - }; -} - -extern "C" { - fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize); - fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize); -} - -struct Aligned { - array: [u8; 8], - _alignment: [u32; 0], -} - -impl Aligned { - fn new(array: [u8; 8]) -> Self { - Aligned { - array: array, - _alignment: [], - } - } -} - -#[test] -fn memcpy() { - let mut dest = [0; 4]; - let src = [0xde, 0xad, 0xbe, 0xef]; - - for n in 0..dest.len() { - dest.copy_from_slice(&[0; 4]); - - unsafe { __aeabi_memcpy(dest.as_mut_ptr(), src.as_ptr(), n) } - - assert_eq!(&dest[0..n], &src[0..n]) - } -} - -#[test] -fn memcpy4() { - let mut aligned = Aligned::new([0; 8]); - let dest = &mut aligned.array; - let src = [0xde, 0xad, 0xbe, 0xef, 0xba, 0xad, 0xf0, 0x0d]; - - for n in 0..dest.len() { - dest.copy_from_slice(&[0; 8]); - - unsafe { __aeabi_memcpy4(dest.as_mut_ptr(), src.as_ptr(), n) } - - assert_eq!(&dest[0..n], &src[0..n]) - } -} diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs deleted file mode 100644 index 34ab3acc78c..00000000000 --- a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs +++ /dev/null @@ -1,240 +0,0 @@ -#![cfg(all( - target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - feature = "mem" -))] -#![feature(compiler_builtins_lib)] -#![no_std] - -extern crate compiler_builtins; - -// test runner -extern crate utest_cortex_m_qemu; - -// overrides `panic!` -#[macro_use] -extern crate utest_macros; - -use core::mem; - -macro_rules! panic { - ($($tt:tt)*) => { - upanic!($($tt)*); - }; -} - -extern "C" { - fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); -} - -struct Aligned { - array: [u8; 8], - _alignment: [u32; 0], -} - -impl Aligned { - fn new(array: [u8; 8]) -> Self { - Aligned { - array: array, - _alignment: [], - } - } -} - -#[test] -fn zero() { - let mut aligned = Aligned::new([0u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), 0, c) } - - assert_eq!(*xs, [0; 8]); - - let mut aligned = Aligned::new([1u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), 0, c) } - - assert_eq!(*xs, [1; 8]); -} - -#[test] -fn one() { - let mut aligned = Aligned::new([0u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 1; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0, 0, 0, 0, 0, 0, 0]); - - let mut aligned = Aligned::new([1u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 1, 1, 1, 1, 1, 1, 1]); -} - -#[test] -fn two() { - let mut aligned = Aligned::new([0u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 2; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0xef, 0, 0, 0, 0, 0, 0]); - - let mut aligned = Aligned::new([1u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0xef, 1, 1, 1, 1, 1, 1]); -} - -#[test] -fn three() { - let mut aligned = Aligned::new([0u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 3; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0, 0, 0, 0, 0]); - - let mut aligned = Aligned::new([1u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 1, 1, 1, 1, 1]); -} - -#[test] -fn four() { - let mut aligned = Aligned::new([0u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 4; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0, 0, 0, 0]); - - let mut aligned = Aligned::new([1u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 1, 1, 1, 1]); -} - -#[test] -fn five() { - let mut aligned = Aligned::new([0u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 5; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0, 0, 0]); - - let mut aligned = Aligned::new([1u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 1, 1, 1]); -} - -#[test] -fn six() { - let mut aligned = Aligned::new([0u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 6; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0, 0]); - - let mut aligned = Aligned::new([1u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1, 1]); -} - -#[test] -fn seven() { - let mut aligned = Aligned::new([0u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 7; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0]); - - let mut aligned = Aligned::new([1u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1]); -} - -#[test] -fn eight() { - let mut aligned = Aligned::new([0u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let n = 8; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); - - let mut aligned = Aligned::new([1u8; 8]); - assert_eq!(mem::align_of_val(&aligned), 4); - let xs = &mut aligned.array; - let c = 0xdeadbeef; - - unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } - - assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); -} diff --git a/library/compiler-builtins/testcrate/tests/big.rs b/library/compiler-builtins/testcrate/tests/big.rs deleted file mode 100644 index d1ae88bd164..00000000000 --- a/library/compiler-builtins/testcrate/tests/big.rs +++ /dev/null @@ -1,134 +0,0 @@ -use compiler_builtins::int::{HInt, MinInt, i256, u256}; - -const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; - -/// Print a `u256` as hex since we can't add format implementations -fn hexu(v: u256) -> String { - format!( - "0x{:016x}{:016x}{:016x}{:016x}", - v.0[3], v.0[2], v.0[1], v.0[0] - ) -} - -#[test] -fn widen_u128() { - assert_eq!(u128::MAX.widen(), u256([u64::MAX, u64::MAX, 0, 0])); - assert_eq!( - LOHI_SPLIT.widen(), - u256([u64::MAX, 0xaaaaaaaaaaaaaaaa, 0, 0]) - ); -} - -#[test] -fn widen_i128() { - assert_eq!((-1i128).widen(), u256::MAX.signed()); - assert_eq!( - (LOHI_SPLIT as i128).widen(), - i256([u64::MAX, 0xaaaaaaaaaaaaaaaa, u64::MAX, u64::MAX]) - ); - assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); -} - -#[test] -fn widen_mul_u128() { - let tests = [ - (u128::MAX / 2, 2_u128, u256([u64::MAX - 1, u64::MAX, 0, 0])), - (u128::MAX, 2_u128, u256([u64::MAX - 1, u64::MAX, 1, 0])), - (u128::MAX, u128::MAX, u256([1, 0, u64::MAX - 1, u64::MAX])), - (u128::MIN, u128::MIN, u256::ZERO), - (1234, 0, u256::ZERO), - (0, 1234, u256::ZERO), - ]; - - let mut errors = Vec::new(); - for (i, (a, b, exp)) in tests.iter().copied().enumerate() { - let res = a.widen_mul(b); - let res_z = a.zero_widen_mul(b); - assert_eq!(res, res_z); - if res != exp { - errors.push((i, a, b, exp, res)); - } - } - - for (i, a, b, exp, res) in &errors { - eprintln!( - "FAILURE ({i}): {a:#034x} * {b:#034x} = {} got {}", - hexu(*exp), - hexu(*res) - ); - } - assert!(errors.is_empty()); -} - -#[test] -fn not_u128() { - assert_eq!(!u256::ZERO, u256::MAX); -} - -#[test] -fn shr_u128() { - let only_low = [ - 1, - u16::MAX.into(), - u32::MAX.into(), - u64::MAX.into(), - u128::MAX, - ]; - - let mut errors = Vec::new(); - - for a in only_low { - for perturb in 0..10 { - let a = a.saturating_add(perturb); - for shift in 0..128 { - let res = a.widen() >> shift; - let expected = (a >> shift).widen(); - if res != expected { - errors.push((a.widen(), shift, res, expected)); - } - } - } - } - - let check = [ - ( - u256::MAX, - 1, - u256([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 1]), - ), - ( - u256::MAX, - 5, - u256([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 5]), - ), - (u256::MAX, 63, u256([u64::MAX, u64::MAX, u64::MAX, 1])), - (u256::MAX, 64, u256([u64::MAX, u64::MAX, u64::MAX, 0])), - (u256::MAX, 65, u256([u64::MAX, u64::MAX, u64::MAX >> 1, 0])), - (u256::MAX, 127, u256([u64::MAX, u64::MAX, 1, 0])), - (u256::MAX, 128, u256([u64::MAX, u64::MAX, 0, 0])), - (u256::MAX, 129, u256([u64::MAX, u64::MAX >> 1, 0, 0])), - (u256::MAX, 191, u256([u64::MAX, 1, 0, 0])), - (u256::MAX, 192, u256([u64::MAX, 0, 0, 0])), - (u256::MAX, 193, u256([u64::MAX >> 1, 0, 0, 0])), - (u256::MAX, 191, u256([u64::MAX, 1, 0, 0])), - (u256::MAX, 254, u256([0b11, 0, 0, 0])), - (u256::MAX, 255, u256([1, 0, 0, 0])), - ]; - - for (input, shift, expected) in check { - let res = input >> shift; - if res != expected { - errors.push((input, shift, res, expected)); - } - } - - for (a, b, res, expected) in &errors { - eprintln!( - "FAILURE: {} >> {b} = {} got {}", - hexu(*a), - hexu(*expected), - hexu(*res), - ); - } - assert!(errors.is_empty()); -} diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs deleted file mode 100644 index 19d90c66493..00000000000 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ /dev/null @@ -1,185 +0,0 @@ -#![allow(unused_macros)] -#![allow(unreachable_code)] -#![cfg_attr(f128_enabled, feature(f128))] - -use testcrate::*; - -mod float_comparisons { - use super::*; - - macro_rules! cmp { - ( - $f:ty, $x:ident, $y:ident, $apfloat_ty:ident, $sys_available:meta, - $($unordered_val:expr, $fn:ident);*; - ) => { - $( - let cmp0 = if apfloat_fallback!( - $f, $apfloat_ty, $sys_available, - |x: FloatTy| x.is_nan() => no_convert, - $x - ) || apfloat_fallback!( - $f, $apfloat_ty, $sys_available, - |y: FloatTy| y.is_nan() => no_convert, - $y - ) - { - $unordered_val - } else if apfloat_fallback!( - $f, $apfloat_ty, $sys_available, - |x, y| x < y => no_convert, - $x, $y - ) { - -1 - } else if apfloat_fallback!( - $f, $apfloat_ty, $sys_available, - |x, y| x == y => no_convert, - $x, $y - ) { - 0 - } else { - 1 - }; - - let cmp1 = $fn($x, $y); - if cmp0 != cmp1 { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), $x, $y, cmp0, cmp1 - ); - } - )* - }; - } - - #[test] - fn cmp_f32() { - use compiler_builtins::float::cmp::{ - __eqsf2, __gesf2, __gtsf2, __lesf2, __ltsf2, __nesf2, __unordsf2, - }; - - fuzz_float_2(N, |x: f32, y: f32| { - assert_eq!(__unordsf2(x, y) != 0, x.is_nan() || y.is_nan()); - cmp!(f32, x, y, Single, all(), - 1, __ltsf2; - 1, __lesf2; - 1, __eqsf2; - -1, __gesf2; - -1, __gtsf2; - 1, __nesf2; - ); - }); - } - - #[test] - fn cmp_f64() { - use compiler_builtins::float::cmp::{ - __eqdf2, __gedf2, __gtdf2, __ledf2, __ltdf2, __nedf2, __unorddf2, - }; - - fuzz_float_2(N, |x: f64, y: f64| { - assert_eq!(__unorddf2(x, y) != 0, x.is_nan() || y.is_nan()); - cmp!(f64, x, y, Double, all(), - 1, __ltdf2; - 1, __ledf2; - 1, __eqdf2; - -1, __gedf2; - -1, __gtdf2; - 1, __nedf2; - ); - }); - } - - #[test] - #[cfg(f128_enabled)] - fn cmp_f128() { - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - use compiler_builtins::float::cmp::{ - __eqkf2 as __eqtf2, __gekf2 as __getf2, __gtkf2 as __gttf2, __lekf2 as __letf2, - __ltkf2 as __lttf2, __nekf2 as __netf2, __unordkf2 as __unordtf2, - }; - - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - use compiler_builtins::float::cmp::{ - __eqtf2, __getf2, __gttf2, __letf2, __lttf2, __netf2, __unordtf2, - }; - - fuzz_float_2(N, |x: f128, y: f128| { - let x_is_nan = apfloat_fallback!( - f128, Quad, not(feature = "no-sys-f128"), - |x: FloatTy| x.is_nan() => no_convert, - x - ); - let y_is_nan = apfloat_fallback!( - f128, Quad, not(feature = "no-sys-f128"), - |x: FloatTy| x.is_nan() => no_convert, - y - ); - - assert_eq!(__unordtf2(x, y) != 0, x_is_nan || y_is_nan); - - cmp!(f128, x, y, Quad, not(feature = "no-sys-f128"), - 1, __lttf2; - 1, __letf2; - 1, __eqtf2; - -1, __getf2; - -1, __gttf2; - 1, __netf2; - ); - }); - } -} - -#[cfg(target_arch = "arm")] -mod float_comparisons_arm { - use super::*; - - macro_rules! cmp2 { - ($x:ident, $y:ident, $($unordered_val:expr, $fn_std:expr, $fn_builtins:ident);*;) => { - $( - let cmp0: i32 = if $x.is_nan() || $y.is_nan() { - $unordered_val - } else { - $fn_std as i32 - }; - let cmp1: i32 = $fn_builtins($x, $y); - if cmp0 != cmp1 { - panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1); - } - )* - }; - } - - #[test] - fn cmp_f32() { - use compiler_builtins::float::cmp::{ - __aeabi_fcmpeq, __aeabi_fcmpge, __aeabi_fcmpgt, __aeabi_fcmple, __aeabi_fcmplt, - }; - - fuzz_float_2(N, |x: f32, y: f32| { - cmp2!(x, y, - 0, x < y, __aeabi_fcmplt; - 0, x <= y, __aeabi_fcmple; - 0, x == y, __aeabi_fcmpeq; - 0, x >= y, __aeabi_fcmpge; - 0, x > y, __aeabi_fcmpgt; - ); - }); - } - - #[test] - fn cmp_f64() { - use compiler_builtins::float::cmp::{ - __aeabi_dcmpeq, __aeabi_dcmpge, __aeabi_dcmpgt, __aeabi_dcmple, __aeabi_dcmplt, - }; - - fuzz_float_2(N, |x: f64, y: f64| { - cmp2!(x, y, - 0, x < y, __aeabi_dcmplt; - 0, x <= y, __aeabi_dcmple; - 0, x == y, __aeabi_dcmpeq; - 0, x >= y, __aeabi_dcmpge; - 0, x > y, __aeabi_dcmpgt; - ); - }); - } -} diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs deleted file mode 100644 index 381d3e15578..00000000000 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ /dev/null @@ -1,364 +0,0 @@ -#![cfg_attr(f128_enabled, feature(f128))] -#![cfg_attr(f16_enabled, feature(f16))] -// makes configuration easier -#![allow(unused_macros)] -#![allow(unused_imports)] - -use compiler_builtins::float::Float; -use rustc_apfloat::{Float as _, FloatConvert as _}; -use testcrate::*; - -mod i_to_f { - use super::*; - - macro_rules! i_to_f { - ($f_ty:ty, $apfloat_ty:ident, $sys_available:meta, $($i_ty:ty, $fn:ident);*;) => { - $( - #[test] - fn $fn() { - use compiler_builtins::float::conv::$fn; - use compiler_builtins::int::Int; - - fuzz(N, |x: $i_ty| { - let f0 = apfloat_fallback!( - $f_ty, $apfloat_ty, $sys_available, - |x| x as $f_ty; - // When the builtin is not available, we need to use a different conversion - // method (since apfloat doesn't support `as` casting). - |x: $i_ty| { - use compiler_builtins::int::MinInt; - - let apf = if <$i_ty>::SIGNED { - FloatTy::from_i128(x.try_into().unwrap()).value - } else { - FloatTy::from_u128(x.try_into().unwrap()).value - }; - - <$f_ty>::from_bits(apf.to_bits()) - }, - x - ); - let f1: $f_ty = $fn(x); - - #[cfg($sys_available)] { - // This makes sure that the conversion produced the best rounding possible, and does - // this independent of `x as $into` rounding correctly. - // This assumes that float to integer conversion is correct. - let y_minus_ulp = <$f_ty>::from_bits(f1.to_bits().wrapping_sub(1)) as $i_ty; - let y = f1 as $i_ty; - let y_plus_ulp = <$f_ty>::from_bits(f1.to_bits().wrapping_add(1)) as $i_ty; - let error_minus = <$i_ty as Int>::abs_diff(y_minus_ulp, x); - let error = <$i_ty as Int>::abs_diff(y, x); - let error_plus = <$i_ty as Int>::abs_diff(y_plus_ulp, x); - - // The first two conditions check that none of the two closest float values are - // strictly closer in representation to `x`. The second makes sure that rounding is - // towards even significand if two float values are equally close to the integer. - if error_minus < error - || error_plus < error - || ((error_minus == error || error_plus == error) - && ((f0.to_bits() & 1) != 0)) - { - if !cfg!(any( - target_arch = "powerpc", - target_arch = "powerpc64" - )) { - panic!( - "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", - stringify!($fn), - x, - f1.to_bits(), - y_minus_ulp, - y, - y_plus_ulp, - error_minus, - error, - error_plus, - ); - } - } - } - - // Test against native conversion. We disable testing on all `x86` because of - // rounding bugs with `i686`. `powerpc` also has the same rounding bug. - if !Float::eq_repr(f0, f1) && !cfg!(any( - target_arch = "x86", - target_arch = "powerpc", - target_arch = "powerpc64" - )) { - panic!( - "{}({}): std: {:?}, builtins: {:?}", - stringify!($fn), - x, - f0, - f1, - ); - } - }); - } - )* - }; - } - - i_to_f! { f32, Single, all(), - u32, __floatunsisf; - i32, __floatsisf; - u64, __floatundisf; - i64, __floatdisf; - u128, __floatuntisf; - i128, __floattisf; - } - - i_to_f! { f64, Double, all(), - u32, __floatunsidf; - i32, __floatsidf; - u64, __floatundidf; - i64, __floatdidf; - u128, __floatuntidf; - i128, __floattidf; - } - - #[cfg(not(feature = "no-f16-f128"))] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - i_to_f! { f128, Quad, not(feature = "no-sys-f128-int-convert"), - u32, __floatunsitf; - i32, __floatsitf; - u64, __floatunditf; - i64, __floatditf; - u128, __floatuntitf; - i128, __floattitf; - } - - #[cfg(not(feature = "no-f16-f128"))] - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - i_to_f! { f128, Quad, not(feature = "no-sys-f128-int-convert"), - u32, __floatunsikf; - i32, __floatsikf; - u64, __floatundikf; - i64, __floatdikf; - u128, __floatuntikf; - i128, __floattikf; - } -} - -mod f_to_i { - use super::*; - - macro_rules! f_to_i { - ($x:ident, $f_ty:ty, $apfloat_ty:ident, $sys_available:meta, $($i_ty:ty, $fn:ident);*;) => { - $( - // it is undefined behavior in the first place to do conversions with NaNs - if !apfloat_fallback!( - $f_ty, $apfloat_ty, $sys_available, |x: FloatTy| x.is_nan() => no_convert, $x - ) { - let conv0 = apfloat_fallback!( - $f_ty, $apfloat_ty, $sys_available, - // Use an `as` cast when the builtin is available on the system. - |x| x as $i_ty; - // When the builtin is not available, we need to use a different conversion - // method (since apfloat doesn't support `as` casting). - |x: $f_ty| { - use compiler_builtins::int::MinInt; - - let apf = FloatTy::from_bits(x.to_bits().into()); - let bits: usize = <$i_ty>::BITS.try_into().unwrap(); - - let err_fn = || panic!( - "Unable to convert value {x:?} to type {}:", stringify!($i_ty) - ); - - if <$i_ty>::SIGNED { - <$i_ty>::try_from(apf.to_i128(bits).value).ok().unwrap_or_else(err_fn) - } else { - <$i_ty>::try_from(apf.to_u128(bits).value).ok().unwrap_or_else(err_fn) - } - }, - $x - ); - let conv1: $i_ty = $fn($x); - if conv0 != conv1 { - panic!("{}({:?}): std: {:?}, builtins: {:?}", stringify!($fn), $x, conv0, conv1); - } - } - )* - }; - } - - #[test] - fn f32_to_int() { - use compiler_builtins::float::conv::{ - __fixsfdi, __fixsfsi, __fixsfti, __fixunssfdi, __fixunssfsi, __fixunssfti, - }; - - fuzz_float(N, |x: f32| { - f_to_i!(x, f32, Single, all(), - u32, __fixunssfsi; - u64, __fixunssfdi; - u128, __fixunssfti; - i32, __fixsfsi; - i64, __fixsfdi; - i128, __fixsfti; - ); - }); - } - - #[test] - fn f64_to_int() { - use compiler_builtins::float::conv::{ - __fixdfdi, __fixdfsi, __fixdfti, __fixunsdfdi, __fixunsdfsi, __fixunsdfti, - }; - - fuzz_float(N, |x: f64| { - f_to_i!(x, f64, Double, all(), - u32, __fixunsdfsi; - u64, __fixunsdfdi; - u128, __fixunsdfti; - i32, __fixdfsi; - i64, __fixdfdi; - i128, __fixdfti; - ); - }); - } - - #[test] - #[cfg(f128_enabled)] - fn f128_to_int() { - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - use compiler_builtins::float::conv::{ - __fixkfdi as __fixtfdi, __fixkfsi as __fixtfsi, __fixkfti as __fixtfti, - __fixunskfdi as __fixunstfdi, __fixunskfsi as __fixunstfsi, - __fixunskfti as __fixunstfti, - }; - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - use compiler_builtins::float::conv::{ - __fixtfdi, __fixtfsi, __fixtfti, __fixunstfdi, __fixunstfsi, __fixunstfti, - }; - - fuzz_float(N, |x: f128| { - f_to_i!( - x, - f128, - Quad, - not(feature = "no-sys-f128-int-convert"), - u32, __fixunstfsi; - u64, __fixunstfdi; - u128, __fixunstfti; - i32, __fixtfsi; - i64, __fixtfdi; - i128, __fixtfti; - ); - }); - } -} - -macro_rules! f_to_f { - ( - $mod:ident, - $( - $from_ty:ty => $to_ty:ty, - $from_ap_ty:ident => $to_ap_ty:ident, - $fn:ident, $sys_available:meta - );+; - ) => {$( - #[test] - fn $fn() { - use compiler_builtins::float::{$mod::$fn, Float}; - use rustc_apfloat::ieee::{$from_ap_ty, $to_ap_ty}; - - fuzz_float(N, |x: $from_ty| { - let tmp0: $to_ty = apfloat_fallback!( - $from_ty, - $from_ap_ty, - $sys_available, - |x: $from_ty| x as $to_ty; - |x: $from_ty| { - let from_apf = FloatTy::from_bits(x.to_bits().into()); - // Get `value` directly to ignore INVALID_OP - let to_apf: $to_ap_ty = from_apf.convert(&mut false).value; - <$to_ty>::from_bits(to_apf.to_bits().try_into().unwrap()) - }, - x - ); - let tmp1: $to_ty = $fn(x); - - if !Float::eq_repr(tmp0, tmp1) { - panic!( - "{}({:?}): std: {:?}, builtins: {:?}", - stringify!($fn), - x, - tmp0, - tmp1 - ); - } - }) - } - )+}; -} - -mod extend { - use super::*; - - f_to_f! { - extend, - f32 => f64, Single => Double, __extendsfdf2, all(); - } - - #[cfg(all(f16_enabled, f128_enabled))] - #[cfg(not(any( - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "loongarch64" - )))] - f_to_f! { - extend, - f16 => f32, Half => Single, __extendhfsf2, not(feature = "no-sys-f16"); - f16 => f32, Half => Single, __gnu_h2f_ieee, not(feature = "no-sys-f16"); - f16 => f64, Half => Double, __extendhfdf2, not(feature = "no-sys-f16-f64-convert"); - f16 => f128, Half => Quad, __extendhftf2, not(feature = "no-sys-f16-f128-convert"); - f32 => f128, Single => Quad, __extendsftf2, not(feature = "no-sys-f128"); - f64 => f128, Double => Quad, __extenddftf2, not(feature = "no-sys-f128"); - } - - #[cfg(f128_enabled)] - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - f_to_f! { - extend, - // FIXME(#655): `f16` tests disabled until we can bootstrap symbols - f32 => f128, Single => Quad, __extendsfkf2, not(feature = "no-sys-f128"); - f64 => f128, Double => Quad, __extenddfkf2, not(feature = "no-sys-f128"); - } -} - -mod trunc { - use super::*; - - f_to_f! { - trunc, - f64 => f32, Double => Single, __truncdfsf2, all(); - } - - #[cfg(all(f16_enabled, f128_enabled))] - #[cfg(not(any( - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "loongarch64" - )))] - f_to_f! { - trunc, - f32 => f16, Single => Half, __truncsfhf2, not(feature = "no-sys-f16"); - f32 => f16, Single => Half, __gnu_f2h_ieee, not(feature = "no-sys-f16"); - f64 => f16, Double => Half, __truncdfhf2, not(feature = "no-sys-f16-f64-convert"); - f128 => f16, Quad => Half, __trunctfhf2, not(feature = "no-sys-f16-f128-convert"); - f128 => f32, Quad => Single, __trunctfsf2, not(feature = "no-sys-f128"); - f128 => f64, Quad => Double, __trunctfdf2, not(feature = "no-sys-f128"); - } - - #[cfg(f128_enabled)] - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - f_to_f! { - trunc, - // FIXME(#655): `f16` tests disabled until we can bootstrap symbols - f128 => f32, Quad => Single, __trunckfsf2, not(feature = "no-sys-f128"); - f128 => f64, Quad => Double, __trunckfdf2, not(feature = "no-sys-f128"); - } -} diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs deleted file mode 100644 index ac87eb6302b..00000000000 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ /dev/null @@ -1,165 +0,0 @@ -#![feature(f128)] -#![allow(unused_macros)] - -use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; -use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc}; - -use testcrate::*; - -// Division algorithms have by far the nastiest and largest number of edge cases, and experience shows -// that sometimes 100_000 iterations of the random fuzzer is needed. - -/// Creates intensive test functions for division functions of a certain size -macro_rules! test { - ( - $n:expr, // the number of bits in a $iX or $uX - $uX:ident, // unsigned integer that will be shifted - $iX:ident, // signed version of $uX - $test_name:ident, // name of the test function - $unsigned_name:ident, // unsigned division function - $signed_name:ident // signed division function - ) => { - #[test] - fn $test_name() { - fuzz_2(N, |lhs, rhs| { - if rhs == 0 { - return; - } - - let mut rem: $uX = 0; - let quo: $uX = $unsigned_name(lhs, rhs, Some(&mut rem)); - if rhs <= rem || (lhs != rhs.wrapping_mul(quo).wrapping_add(rem)) { - panic!( - "unsigned division function failed with lhs:{} rhs:{} \ - std:({}, {}) builtins:({}, {})", - lhs, - rhs, - lhs.wrapping_div(rhs), - lhs.wrapping_rem(rhs), - quo, - rem - ); - } - - // test the signed division function also - let lhs = lhs as $iX; - let rhs = rhs as $iX; - let mut rem: $iX = 0; - let quo: $iX = $signed_name(lhs, rhs, &mut rem); - // We cannot just test that - // `lhs == rhs.wrapping_mul(quo).wrapping_add(rem)`, but also - // need to make sure the remainder isn't larger than the divisor - // and has the correct sign. - let incorrect_rem = if rem == 0 { - false - } else if rhs == $iX::MIN { - // `rhs.wrapping_abs()` would overflow, so handle this case - // separately. - (lhs.is_negative() != rem.is_negative()) || (rem == $iX::MIN) - } else { - (lhs.is_negative() != rem.is_negative()) - || (rhs.wrapping_abs() <= rem.wrapping_abs()) - }; - if incorrect_rem || lhs != rhs.wrapping_mul(quo).wrapping_add(rem) { - panic!( - "signed division function failed with lhs:{} rhs:{} \ - std:({}, {}) builtins:({}, {})", - lhs, - rhs, - lhs.wrapping_div(rhs), - lhs.wrapping_rem(rhs), - quo, - rem - ); - } - }); - } - }; -} - -test!(32, u32, i32, div_rem_si4, __udivmodsi4, __divmodsi4); -test!(64, u64, i64, div_rem_di4, __udivmoddi4, __divmoddi4); -test!(128, u128, i128, div_rem_ti4, __udivmodti4, __divmodti4); - -#[test] -fn divide_sparc() { - fuzz_2(N, |lhs, rhs| { - if rhs == 0 { - return; - } - - let mut rem: u128 = 0; - let quo: u128 = u128_divide_sparc(lhs, rhs, &mut rem); - if rhs <= rem || (lhs != rhs.wrapping_mul(quo).wrapping_add(rem)) { - panic!( - "u128_divide_sparc({}, {}): \ - std:({}, {}), builtins:({}, {})", - lhs, - rhs, - lhs.wrapping_div(rhs), - lhs.wrapping_rem(rhs), - quo, - rem - ); - } - }); -} - -macro_rules! float { - ($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { - $( - #[test] - fn $fn() { - use compiler_builtins::float::{div::$fn, Float}; - use core::ops::Div; - - fuzz_float_2(N, |x: $f, y: $f| { - let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y); - let quo1: $f = $fn(x, y); - - // ARM SIMD instructions always flush subnormals to zero - if cfg!(target_arch = "arm") && - ((Float::is_subnormal(quo0)) || Float::is_subnormal(quo1)) { - return; - } - - if !Float::eq_repr(quo0, quo1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), - x, - y, - quo0, - quo1 - ); - } - }); - } - )* - }; -} - -#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -mod float_div { - use super::*; - - float! { - f32, __divsf3, Single, all(); - f64, __divdf3, Double, all(); - } - - #[cfg(not(feature = "no-f16-f128"))] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - float! { - f128, __divtf3, Quad, - // FIXME(llvm): there is a bug in LLVM rt. - // See . - not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux"))); - } - - #[cfg(not(feature = "no-f16-f128"))] - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - float! { - f128, __divkf3, Quad, not(feature = "no-sys-f128"); - } -} diff --git a/library/compiler-builtins/testcrate/tests/float_pow.rs b/library/compiler-builtins/testcrate/tests/float_pow.rs deleted file mode 100644 index 8d86392f535..00000000000 --- a/library/compiler-builtins/testcrate/tests/float_pow.rs +++ /dev/null @@ -1,72 +0,0 @@ -#![allow(unused_macros)] -#![cfg_attr(f128_enabled, feature(f128))] -#![cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] - -use testcrate::*; - -// This is approximate because of issues related to -// https://github.com/rust-lang/rust/issues/73920. -// TODO how do we resolve this indeterminacy? -macro_rules! pow { - ($($f:ty, $tolerance:expr, $fn:ident, $sys_available:meta);*;) => { - $( - #[test] - // FIXME(apfloat): We skip tests if system symbols aren't available rather - // than providing a fallback, since `rustc_apfloat` does not provide `pow`. - #[cfg($sys_available)] - fn $fn() { - use compiler_builtins::float::pow::$fn; - use compiler_builtins::float::Float; - fuzz_float_2(N, |x: $f, y: $f| { - if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) { - let n = y.to_bits() & !<$f as Float>::SIG_MASK; - let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIG_BITS; - let n = n as i32; - let tmp0: $f = x.powi(n); - let tmp1: $f = $fn(x, n); - let (a, b) = if tmp0 < tmp1 { - (tmp0, tmp1) - } else { - (tmp1, tmp0) - }; - - let good = if a == b { - // handles infinity equality - true - } else if a < $tolerance { - b < $tolerance - } else { - let quo = b / a; - (quo < (1. + $tolerance)) && (quo > (1. - $tolerance)) - }; - - assert!( - good, - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), x, n, tmp0, tmp1 - ); - } - }); - } - )* - }; -} - -pow! { - f32, 1e-4, __powisf2, all(); - f64, 1e-12, __powidf2, all(); -} - -#[cfg(f128_enabled)] -// FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly. -#[cfg(not(target_env = "msvc"))] -#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] -pow! { - f128, 1e-36, __powitf2, not(feature = "no-sys-f128"); -} - -#[cfg(f128_enabled)] -#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] -pow! { - f128, 1e-36, __powikf2, not(feature = "no-sys-f128"); -} diff --git a/library/compiler-builtins/testcrate/tests/lse.rs b/library/compiler-builtins/testcrate/tests/lse.rs deleted file mode 100644 index cbecd6143e7..00000000000 --- a/library/compiler-builtins/testcrate/tests/lse.rs +++ /dev/null @@ -1,97 +0,0 @@ -#![feature(decl_macro)] // so we can use pub(super) -#![cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm")))] - -/// Translate a byte size to a Rust type. -macro int_ty { - (1) => { i8 }, - (2) => { i16 }, - (4) => { i32 }, - (8) => { i64 }, - (16) => { i128 } -} - -mod cas { - pub(super) macro test($_ordering:ident, $bytes:tt, $name:ident) { - #[test] - fn $name() { - testcrate::fuzz_2(10000, |expected: super::int_ty!($bytes), new| { - let mut target = expected.wrapping_add(10); - assert_eq!( - unsafe { - compiler_builtins::aarch64_linux::$name::$name(expected, new, &mut target) - }, - expected.wrapping_add(10), - "return value should always be the previous value", - ); - assert_eq!( - target, - expected.wrapping_add(10), - "shouldn't have changed target" - ); - - target = expected; - assert_eq!( - unsafe { - compiler_builtins::aarch64_linux::$name::$name(expected, new, &mut target) - }, - expected - ); - assert_eq!(target, new, "should have updated target"); - }); - } - } -} - -macro test_cas16($_ordering:ident, $name:ident) { - cas::test!($_ordering, 16, $name); -} - -mod swap { - pub(super) macro test($_ordering:ident, $bytes:tt, $name:ident) { - #[test] - fn $name() { - testcrate::fuzz_2(10000, |left: super::int_ty!($bytes), mut right| { - let orig_right = right; - assert_eq!( - unsafe { compiler_builtins::aarch64_linux::$name::$name(left, &mut right) }, - orig_right - ); - assert_eq!(left, right); - }); - } - } -} - -macro_rules! test_op { - ($mod:ident, $( $op:tt )* ) => { - mod $mod { - pub(super) macro test { - ($_ordering:ident, $bytes:tt, $name:ident) => { - #[test] - fn $name() { - testcrate::fuzz_2(10000, |old, val| { - let mut target = old; - let op: fn(super::int_ty!($bytes), super::int_ty!($bytes)) -> _ = $($op)*; - let expected = op(old, val); - assert_eq!(old, unsafe { compiler_builtins::aarch64_linux::$name::$name(val, &mut target) }, "{} should return original value", stringify!($name)); - assert_eq!(expected, target, "{} should store to target", stringify!($name)); - }); - } - } - } - } - }; -} - -test_op!(add, |left, right| left.wrapping_add(right)); -test_op!(clr, |left, right| left & !right); -test_op!(xor, std::ops::BitXor::bitxor); -test_op!(or, std::ops::BitOr::bitor); - -compiler_builtins::foreach_cas!(cas::test); -compiler_builtins::foreach_cas16!(test_cas16); -compiler_builtins::foreach_swp!(swap::test); -compiler_builtins::foreach_ldadd!(add::test); -compiler_builtins::foreach_ldclr!(clr::test); -compiler_builtins::foreach_ldeor!(xor::test); -compiler_builtins::foreach_ldset!(or::test); diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs deleted file mode 100644 index d838ef159a0..00000000000 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ /dev/null @@ -1,286 +0,0 @@ -extern crate compiler_builtins; -use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; - -const WORD_SIZE: usize = core::mem::size_of::(); - -#[test] -fn memcpy_3() { - let mut arr: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; - unsafe { - let src = arr.as_ptr().offset(9); - let dst = arr.as_mut_ptr().offset(1); - assert_eq!(memcpy(dst, src, 3), dst); - assert_eq!(arr, [0, 9, 10, 11, 4, 5, 6, 7, 8, 9, 10, 11]); - } - arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; - unsafe { - let src = arr.as_ptr().offset(1); - let dst = arr.as_mut_ptr().offset(9); - assert_eq!(memcpy(dst, src, 3), dst); - assert_eq!(arr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3]); - } -} - -#[test] -fn memcpy_10() { - let arr: [u8; 18] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]; - let mut dst: [u8; 12] = [0; 12]; - unsafe { - let src = arr.as_ptr().offset(1); - assert_eq!(memcpy(dst.as_mut_ptr(), src, 10), dst.as_mut_ptr()); - assert_eq!(dst, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0]); - } - unsafe { - let src = arr.as_ptr().offset(8); - assert_eq!(memcpy(dst.as_mut_ptr(), src, 10), dst.as_mut_ptr()); - assert_eq!(dst, [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0, 0]); - } -} - -#[test] -fn memcpy_big() { - // Make the arrays cross 3 pages - const SIZE: usize = 8193; - let src: [u8; SIZE] = [22; SIZE]; - struct Dst { - start: usize, - buf: [u8; SIZE], - end: usize, - } - - let mut dst = Dst { - start: 0, - buf: [0; SIZE], - end: 0, - }; - unsafe { - assert_eq!( - memcpy(dst.buf.as_mut_ptr(), src.as_ptr(), SIZE), - dst.buf.as_mut_ptr() - ); - assert_eq!(dst.start, 0); - assert_eq!(dst.buf, [22; SIZE]); - assert_eq!(dst.end, 0); - } -} - -#[test] -fn memmove_forward() { - let mut arr: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; - unsafe { - let src = arr.as_ptr().offset(6); - let dst = arr.as_mut_ptr().offset(3); - assert_eq!(memmove(dst, src, 5), dst); - assert_eq!(arr, [0, 1, 2, 6, 7, 8, 9, 10, 8, 9, 10, 11]); - } -} - -#[test] -fn memmove_backward() { - let mut arr: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; - unsafe { - let src = arr.as_ptr().offset(3); - let dst = arr.as_mut_ptr().offset(6); - assert_eq!(memmove(dst, src, 5), dst); - assert_eq!(arr, [0, 1, 2, 3, 4, 5, 3, 4, 5, 6, 7, 11]); - } -} - -#[test] -fn memset_zero() { - let mut arr: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; - unsafe { - let ptr = arr.as_mut_ptr().offset(5); - assert_eq!(memset(ptr, 0, 2), ptr); - assert_eq!(arr, [0, 1, 2, 3, 4, 0, 0, 7]); - - // Only the LSB matters for a memset - assert_eq!(memset(arr.as_mut_ptr(), 0x2000, 8), arr.as_mut_ptr()); - assert_eq!(arr, [0, 0, 0, 0, 0, 0, 0, 0]); - } -} - -#[test] -fn memset_nonzero() { - let mut arr: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; - unsafe { - let ptr = arr.as_mut_ptr().offset(2); - assert_eq!(memset(ptr, 22, 3), ptr); - assert_eq!(arr, [0, 1, 22, 22, 22, 5, 6, 7]); - - // Only the LSB matters for a memset - assert_eq!(memset(arr.as_mut_ptr(), 0x2009, 8), arr.as_mut_ptr()); - assert_eq!(arr, [9, 9, 9, 9, 9, 9, 9, 9]); - } -} - -#[test] -fn memcmp_eq() { - let arr1 @ arr2 = gen_arr::<256>(); - for i in 0..256 { - unsafe { - assert_eq!(memcmp(arr1.0.as_ptr(), arr2.0.as_ptr(), i), 0); - assert_eq!(memcmp(arr2.0.as_ptr(), arr1.0.as_ptr(), i), 0); - } - } -} - -#[test] -fn memcmp_ne() { - let arr1 @ arr2 = gen_arr::<256>(); - // Reduce iteration count in Miri as it is too slow otherwise. - let limit = if cfg!(miri) { 64 } else { 256 }; - for i in 0..limit { - let mut diff_arr = arr1; - diff_arr.0[i] = 127; - let expect = diff_arr.0[i].cmp(&arr2.0[i]); - for k in i + 1..limit { - let result = unsafe { memcmp(diff_arr.0.as_ptr(), arr2.0.as_ptr(), k) }; - assert_eq!(expect, result.cmp(&0)); - } - } -} - -#[derive(Clone, Copy)] -struct AlignedStorage([u8; N], [usize; 0]); - -fn gen_arr() -> AlignedStorage { - let mut ret = AlignedStorage::([0; N], []); - for i in 0..N { - ret.0[i] = i as u8; - } - ret -} - -#[test] -fn memmove_forward_misaligned_nonaligned_start() { - let mut arr = gen_arr::<32>(); - let mut reference = arr; - unsafe { - let src = arr.0.as_ptr().offset(6); - let dst = arr.0.as_mut_ptr().offset(3); - assert_eq!(memmove(dst, src, 17), dst); - reference.0.copy_within(6..6 + 17, 3); - assert_eq!(arr.0, reference.0); - } -} - -#[test] -fn memmove_forward_misaligned_aligned_start() { - let mut arr = gen_arr::<32>(); - let mut reference = arr; - unsafe { - let src = arr.0.as_ptr().offset(6); - let dst = arr.0.as_mut_ptr().add(0); - assert_eq!(memmove(dst, src, 17), dst); - reference.0.copy_within(6..6 + 17, 0); - assert_eq!(arr.0, reference.0); - } -} - -#[test] -fn memmove_forward_aligned() { - let mut arr = gen_arr::<32>(); - let mut reference = arr; - unsafe { - let src = arr.0.as_ptr().add(3 + WORD_SIZE); - let dst = arr.0.as_mut_ptr().add(3); - assert_eq!(memmove(dst, src, 17), dst); - reference - .0 - .copy_within(3 + WORD_SIZE..3 + WORD_SIZE + 17, 3); - assert_eq!(arr.0, reference.0); - } -} - -#[test] -fn memmove_backward_misaligned_nonaligned_start() { - let mut arr = gen_arr::<32>(); - let mut reference = arr; - unsafe { - let src = arr.0.as_ptr().offset(3); - let dst = arr.0.as_mut_ptr().offset(6); - assert_eq!(memmove(dst, src, 17), dst); - reference.0.copy_within(3..3 + 17, 6); - assert_eq!(arr.0, reference.0); - } -} - -#[test] -fn memmove_backward_misaligned_aligned_start() { - let mut arr = gen_arr::<32>(); - let mut reference = arr; - unsafe { - let src = arr.0.as_ptr().offset(3); - let dst = arr.0.as_mut_ptr().add(WORD_SIZE); - assert_eq!(memmove(dst, src, 17), dst); - reference.0.copy_within(3..3 + 17, WORD_SIZE); - assert_eq!(arr.0, reference.0); - } -} - -#[test] -fn memmove_backward_aligned() { - let mut arr = gen_arr::<32>(); - let mut reference = arr; - unsafe { - let src = arr.0.as_ptr().add(3); - let dst = arr.0.as_mut_ptr().add(3 + WORD_SIZE); - assert_eq!(memmove(dst, src, 17), dst); - reference.0.copy_within(3..3 + 17, 3 + WORD_SIZE); - assert_eq!(arr.0, reference.0); - } -} - -#[test] -fn memmove_misaligned_bounds() { - // The above test have the downside that the addresses surrounding the range-to-copy are all - // still in-bounds, so Miri would not actually complain about OOB accesses. So we also test with - // an array that has just the right size. We test a few times to avoid it being accidentally - // aligned. - for _ in 0..8 { - let mut arr1 = [0u8; 17]; - let mut arr2 = [0u8; 17]; - unsafe { - // Copy both ways so we hit both the forward and backward cases. - memmove(arr1.as_mut_ptr(), arr2.as_mut_ptr(), 17); - memmove(arr2.as_mut_ptr(), arr1.as_mut_ptr(), 17); - } - } -} - -#[test] -fn memset_backward_misaligned_nonaligned_start() { - let mut arr = gen_arr::<32>(); - let mut reference = arr; - unsafe { - let ptr = arr.0.as_mut_ptr().offset(6); - assert_eq!(memset(ptr, 0xCC, 17), ptr); - core::ptr::write_bytes(reference.0.as_mut_ptr().add(6), 0xCC, 17); - assert_eq!(arr.0, reference.0); - } -} - -#[test] -fn memset_backward_misaligned_aligned_start() { - let mut arr = gen_arr::<32>(); - let mut reference = arr; - unsafe { - let ptr = arr.0.as_mut_ptr().add(WORD_SIZE); - assert_eq!(memset(ptr, 0xCC, 17), ptr); - core::ptr::write_bytes(reference.0.as_mut_ptr().add(WORD_SIZE), 0xCC, 17); - assert_eq!(arr.0, reference.0); - } -} - -#[test] -fn memset_backward_aligned() { - let mut arr = gen_arr::<32>(); - let mut reference = arr; - unsafe { - let ptr = arr.0.as_mut_ptr().add(3 + WORD_SIZE); - assert_eq!(memset(ptr, 0xCC, 17), ptr); - core::ptr::write_bytes(reference.0.as_mut_ptr().add(3 + WORD_SIZE), 0xCC, 17); - assert_eq!(arr.0, reference.0); - } -} diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs deleted file mode 100644 index edbd3684d47..00000000000 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ /dev/null @@ -1,208 +0,0 @@ -// makes configuration easier -#![allow(unused_macros)] - -use testcrate::*; - -/// Make sure that the the edge case tester and randomized tester don't break, and list examples of -/// fuzz values for documentation purposes. -#[test] -fn fuzz_values() { - const VALS: [u16; 47] = [ - 0b0, // edge cases - 0b1111111111111111, - 0b1111111111111110, - 0b1111111111111100, - 0b1111111110000000, - 0b1111111100000000, - 0b1110000000000000, - 0b1100000000000000, - 0b1000000000000000, - 0b111111111111111, - 0b111111111111110, - 0b111111111111100, - 0b111111110000000, - 0b111111100000000, - 0b110000000000000, - 0b100000000000000, - 0b11111111111111, - 0b11111111111110, - 0b11111111111100, - 0b11111110000000, - 0b11111100000000, - 0b10000000000000, - 0b111111111, - 0b111111110, - 0b111111100, - 0b110000000, - 0b100000000, - 0b11111111, - 0b11111110, - 0b11111100, - 0b10000000, - 0b111, - 0b110, - 0b100, - 0b11, - 0b10, - 0b1, - 0b1010110100000, // beginning of random fuzzing - 0b1100011001011010, - 0b1001100101001111, - 0b1101010100011010, - 0b100010001, - 0b1000000000000000, - 0b1100000000000101, - 0b1100111101010101, - 0b1100010111111111, - 0b1111110101111111, - ]; - let mut i = 0; - fuzz(10, |x: u16| { - assert_eq!(x, VALS[i]); - i += 1; - }); -} - -#[test] -fn leading_zeros() { - use compiler_builtins::int::leading_zeros::{leading_zeros_default, leading_zeros_riscv}; - { - use compiler_builtins::int::leading_zeros::__clzsi2; - fuzz(N, |x: u32| { - if x == 0 { - return; // undefined value for an intrinsic - } - let lz = x.leading_zeros() as usize; - let lz0 = __clzsi2(x); - let lz1 = leading_zeros_default(x); - let lz2 = leading_zeros_riscv(x); - if lz0 != lz { - panic!("__clzsi2({}): std: {}, builtins: {}", x, lz, lz0); - } - if lz1 != lz { - panic!( - "leading_zeros_default({}): std: {}, builtins: {}", - x, lz, lz1 - ); - } - if lz2 != lz { - panic!("leading_zeros_riscv({}): std: {}, builtins: {}", x, lz, lz2); - } - }); - } - - { - use compiler_builtins::int::leading_zeros::__clzdi2; - fuzz(N, |x: u64| { - if x == 0 { - return; // undefined value for an intrinsic - } - let lz = x.leading_zeros() as usize; - let lz0 = __clzdi2(x); - let lz1 = leading_zeros_default(x); - let lz2 = leading_zeros_riscv(x); - if lz0 != lz { - panic!("__clzdi2({}): std: {}, builtins: {}", x, lz, lz0); - } - if lz1 != lz { - panic!( - "leading_zeros_default({}): std: {}, builtins: {}", - x, lz, lz1 - ); - } - if lz2 != lz { - panic!("leading_zeros_riscv({}): std: {}, builtins: {}", x, lz, lz2); - } - }); - } - - { - use compiler_builtins::int::leading_zeros::__clzti2; - fuzz(N, |x: u128| { - if x == 0 { - return; // undefined value for an intrinsic - } - let lz = x.leading_zeros() as usize; - let lz0 = __clzti2(x); - if lz0 != lz { - panic!("__clzti2({}): std: {}, builtins: {}", x, lz, lz0); - } - }); - } -} - -#[test] -fn trailing_zeros() { - use compiler_builtins::int::trailing_zeros::{__ctzdi2, __ctzsi2, __ctzti2, trailing_zeros}; - fuzz(N, |x: u32| { - if x == 0 { - return; // undefined value for an intrinsic - } - let tz = x.trailing_zeros() as usize; - let tz0 = __ctzsi2(x); - let tz1 = trailing_zeros(x); - if tz0 != tz { - panic!("__ctzsi2({}): std: {}, builtins: {}", x, tz, tz0); - } - if tz1 != tz { - panic!("trailing_zeros({}): std: {}, builtins: {}", x, tz, tz1); - } - }); - fuzz(N, |x: u64| { - if x == 0 { - return; // undefined value for an intrinsic - } - let tz = x.trailing_zeros() as usize; - let tz0 = __ctzdi2(x); - let tz1 = trailing_zeros(x); - if tz0 != tz { - panic!("__ctzdi2({}): std: {}, builtins: {}", x, tz, tz0); - } - if tz1 != tz { - panic!("trailing_zeros({}): std: {}, builtins: {}", x, tz, tz1); - } - }); - fuzz(N, |x: u128| { - if x == 0 { - return; // undefined value for an intrinsic - } - let tz = x.trailing_zeros() as usize; - let tz0 = __ctzti2(x); - if tz0 != tz { - panic!("__ctzti2({}): std: {}, builtins: {}", x, tz, tz0); - } - }); -} - -#[test] -fn bswap() { - use compiler_builtins::int::bswap::{__bswapdi2, __bswapsi2}; - fuzz(N, |x: u32| { - assert_eq!(x.swap_bytes(), __bswapsi2(x)); - }); - fuzz(N, |x: u64| { - assert_eq!(x.swap_bytes(), __bswapdi2(x)); - }); - - assert_eq!(__bswapsi2(0x12345678u32), 0x78563412u32); - assert_eq!(__bswapsi2(0x00000001u32), 0x01000000u32); - assert_eq!(__bswapdi2(0x123456789ABCDEF0u64), 0xF0DEBC9A78563412u64); - assert_eq!(__bswapdi2(0x0200000001000000u64), 0x0000000100000002u64); - - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { - use compiler_builtins::int::bswap::__bswapti2; - fuzz(N, |x: u128| { - assert_eq!(x.swap_bytes(), __bswapti2(x)); - }); - - assert_eq!( - __bswapti2(0x123456789ABCDEF013579BDF02468ACEu128), - 0xCE8A4602DF9B5713F0DEBC9A78563412u128 - ); - assert_eq!( - __bswapti2(0x04000000030000000200000001000000u128), - 0x00000001000000020000000300000004u128 - ); - } -} diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs deleted file mode 100644 index 2113b177db4..00000000000 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ /dev/null @@ -1,156 +0,0 @@ -#![allow(unused_macros)] -#![cfg_attr(f128_enabled, feature(f128))] - -use testcrate::*; - -mod int_mul { - use super::*; - - macro_rules! mul { - ($($i:ty, $fn:ident);*;) => { - $( - #[test] - fn $fn() { - use compiler_builtins::int::mul::$fn; - - fuzz_2(N, |x: $i, y: $i| { - let mul0 = x.wrapping_mul(y); - let mul1: $i = $fn(x, y); - if mul0 != mul1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, y, mul0, mul1 - ); - } - }); - - } - )* - }; - } - - mul! { - u64, __muldi3; - i128, __multi3; - } -} - -mod int_overflowing_mul { - use super::*; - - macro_rules! overflowing_mul { - ($($i:ty, $fn:ident);*;) => { - $( - #[test] - fn $fn() { - use compiler_builtins::int::mul::$fn; - - fuzz_2(N, |x: $i, y: $i| { - let (mul0, o0) = x.overflowing_mul(y); - let mut o1 = 0i32; - let mul1: $i = $fn(x, y, &mut o1); - let o1 = o1 != 0; - if mul0 != mul1 || o0 != o1 { - panic!( - "{}({}, {}): std: ({}, {}), builtins: ({}, {})", - stringify!($fn), x, y, mul0, o0, mul1, o1 - ); - } - }); - } - )* - }; - } - - overflowing_mul! { - i32, __mulosi4; - i64, __mulodi4; - i128, __muloti4; - } - - #[test] - fn overflowing_mul_u128() { - use compiler_builtins::int::mul::{__rust_i128_mulo, __rust_u128_mulo}; - - fuzz_2(N, |x: u128, y: u128| { - let mut o1 = 0; - let (mul0, o0) = x.overflowing_mul(y); - let mul1 = __rust_u128_mulo(x, y, &mut o1); - if mul0 != mul1 || i32::from(o0) != o1 { - panic!( - "__rust_u128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", - x, y, mul0, o0, mul1, o1 - ); - } - let x = x as i128; - let y = y as i128; - let (mul0, o0) = x.overflowing_mul(y); - let mul1 = __rust_i128_mulo(x, y, &mut o1); - if mul0 != mul1 || i32::from(o0) != o1 { - panic!( - "__rust_i128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", - x, y, mul0, o0, mul1, o1 - ); - } - }); - } -} - -macro_rules! float_mul { - ($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { - $( - #[test] - fn $fn() { - use compiler_builtins::float::{mul::$fn, Float}; - use core::ops::Mul; - - fuzz_float_2(N, |x: $f, y: $f| { - let mul0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Mul::mul, x, y); - let mul1: $f = $fn(x, y); - if !Float::eq_repr(mul0, mul1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), x, y, mul0, mul1 - ); - } - }); - } - )* - }; -} - -#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -mod float_mul { - use super::*; - - // FIXME(#616): Stop ignoring arches that don't have native support once fix for builtins is in - // nightly. - float_mul! { - f32, __mulsf3, Single, not(target_arch = "arm"); - f64, __muldf3, Double, not(target_arch = "arm"); - } -} - -#[cfg(f128_enabled)] -#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] -mod float_mul_f128 { - use super::*; - - float_mul! { - f128, __multf3, Quad, - // FIXME(llvm): there is a bug in LLVM rt. - // See . - not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux"))); - } -} - -#[cfg(f128_enabled)] -#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] -mod float_mul_f128_ppc { - use super::*; - - float_mul! { - f128, __mulkf3, Quad, not(feature = "no-sys-f128"); - } -} diff --git a/library/compiler-builtins/testcrate/tests/shift.rs b/library/compiler-builtins/testcrate/tests/shift.rs deleted file mode 100644 index 23e3395edc6..00000000000 --- a/library/compiler-builtins/testcrate/tests/shift.rs +++ /dev/null @@ -1,35 +0,0 @@ -use testcrate::*; - -macro_rules! shift { - ($($i:ty, $fn_std:ident, $fn_builtins:ident);*;) => { - $( - #[test] - fn $fn_builtins() { - use compiler_builtins::int::shift::$fn_builtins; - - fuzz_shift(|x: $i, s: u32| { - let tmp0: $i = x.$fn_std(s); - let tmp1: $i = $fn_builtins(x, s); - if tmp0 != tmp1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn_builtins), x, s, tmp0, tmp1 - ); - } - }); - } - )* - }; -} - -shift! { - u32, wrapping_shl, __ashlsi3; - u64, wrapping_shl, __ashldi3; - u128, wrapping_shl, __ashlti3; - i32, wrapping_shr, __ashrsi3; - i64, wrapping_shr, __ashrdi3; - i128, wrapping_shr, __ashrti3; - u32, wrapping_shr, __lshrsi3; - u64, wrapping_shr, __lshrdi3; - u128, wrapping_shr, __lshrti3; -} -- cgit 1.4.1-3-g733a5 From 01c58882462bb721b755c765507cdcd335b481d8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 03:16:02 +0000 Subject: ci: Make CI configuration more similar to `libm` Apply a handful of changes to reduce the diff between the two: * Cancel running jobs on new pushes * Enable log color and backtraces * Add timeouts * Specify CI runner versions * Add an armv7 job * Replace the name NO_STD with BUILD_ONLY * Update the extension to the canonical .yaml * Set AR_ and CC_ environments in docker * Install requirements to build MPFR --- .../compiler-builtins/.github/workflows/main.yaml | 204 +++++++++++++++++++ .../compiler-builtins/.github/workflows/main.yml | 217 --------------------- .../.github/workflows/publish.yaml | 30 +++ .../.github/workflows/publish.yml | 30 --- .../ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 9 +- .../ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 7 +- .../docker/arm-unknown-linux-gnueabihf/Dockerfile | 7 +- .../armv7-unknown-linux-gnueabihf/Dockerfile | 7 +- .../ci/docker/i586-unknown-linux-gnu/Dockerfile | 3 +- .../ci/docker/i686-unknown-linux-gnu/Dockerfile | 3 +- .../loongarch64-unknown-linux-gnu/Dockerfile | 1 + .../ci/docker/mips-unknown-linux-gnu/Dockerfile | 5 +- .../mips64-unknown-linux-gnuabi64/Dockerfile | 8 +- .../mips64el-unknown-linux-gnuabi64/Dockerfile | 8 +- .../ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 5 +- .../ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 5 +- .../docker/powerpc64-unknown-linux-gnu/Dockerfile | 6 +- .../powerpc64le-unknown-linux-gnu/Dockerfile | 5 +- .../docker/riscv64gc-unknown-linux-gnu/Dockerfile | 5 +- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 3 +- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 3 +- .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 3 +- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 3 +- .../ci/docker/wasm32-unknown-unknown/Dockerfile | 1 + .../ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 3 +- library/compiler-builtins/ci/run.sh | 7 +- 26 files changed, 315 insertions(+), 273 deletions(-) create mode 100644 library/compiler-builtins/.github/workflows/main.yaml delete mode 100644 library/compiler-builtins/.github/workflows/main.yml create mode 100644 library/compiler-builtins/.github/workflows/publish.yaml delete mode 100644 library/compiler-builtins/.github/workflows/publish.yml diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml new file mode 100644 index 00000000000..eec747a2436 --- /dev/null +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -0,0 +1,204 @@ +name: CI +on: + push: { branches: [master] } + pull_request: + +concurrency: + # Make sure that new pushes cancel running jobs + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + RUSTDOCFLAGS: -Dwarnings + RUSTFLAGS: -Dwarnings + RUST_BACKTRACE: full + +jobs: + test: + name: Build and test + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - target: aarch64-apple-darwin + os: macos-15 + - target: aarch64-unknown-linux-gnu + os: ubuntu-24.04-arm + - target: aarch64-pc-windows-msvc + os: windows-2025 + test_verbatim: 1 + build_only: 1 + - target: arm-unknown-linux-gnueabi + os: ubuntu-24.04 + - target: arm-unknown-linux-gnueabihf + os: ubuntu-24.04 + - target: armv7-unknown-linux-gnueabihf + os: ubuntu-24.04 + - target: i586-unknown-linux-gnu + os: ubuntu-24.04 + - target: i686-unknown-linux-gnu + os: ubuntu-24.04 + - target: loongarch64-unknown-linux-gnu + os: ubuntu-24.04 + - target: powerpc-unknown-linux-gnu + os: ubuntu-24.04 + - target: powerpc64-unknown-linux-gnu + os: ubuntu-24.04 + - target: powerpc64le-unknown-linux-gnu + os: ubuntu-24.04 + - target: riscv64gc-unknown-linux-gnu + os: ubuntu-24.04 + - target: thumbv6m-none-eabi + os: ubuntu-24.04 + - target: thumbv7em-none-eabi + os: ubuntu-24.04 + - target: thumbv7em-none-eabihf + os: ubuntu-24.04 + - target: thumbv7m-none-eabi + os: ubuntu-24.04 + - target: wasm32-unknown-unknown + os: ubuntu-24.04 + - target: x86_64-unknown-linux-gnu + os: ubuntu-24.04 + - target: x86_64-apple-darwin + os: macos-13 + - target: i686-pc-windows-msvc + os: windows-2025 + test_verbatim: 1 + - target: x86_64-pc-windows-msvc + os: windows-2025 + test_verbatim: 1 + - target: i686-pc-windows-gnu + os: windows-2025 + channel: nightly-i686-gnu + - target: x86_64-pc-windows-gnu + os: windows-2025 + channel: nightly-x86_64-gnu + runs-on: ${{ matrix.os }} + env: + BUILD_ONLY: ${{ matrix.build_only }} + TEST_VERBATIM: ${{ matrix.test_verbatim }} + steps: + - name: Print runner information + run: uname -a + - uses: actions/checkout@v4 + with: + submodules: true + - name: Install Rust (rustup) + shell: bash + run: | + channel="nightly" + # Account for channels that have required components (MinGW) + [ -n "${{ matrix.channel }}" ] && channel="${{ matrix.channel }}" + rustup update "$channel" --no-self-update + rustup default "$channel" + rustup target add "${{ matrix.target }}" + rustup component add llvm-tools-preview + - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} + - name: Cache Docker layers + uses: actions/cache@v4 + if: matrix.os == 'ubuntu-24.04' + with: + path: /tmp/.buildx-cache + key: ${{ matrix.target }}-buildx-${{ github.sha }} + restore-keys: ${{ matrix.target }}-buildx- + + - name: Cache compiler-rt + id: cache-compiler-rt + uses: actions/cache@v4 + with: + path: compiler-rt + key: ${{ runner.os }}-compiler-rt-${{ hashFiles('ci/download-compiler-rt.sh') }} + - name: Download compiler-rt reference sources + if: steps.cache-compiler-rt.outputs.cache-hit != 'true' + run: ./ci/download-compiler-rt.sh + shell: bash + - run: echo "RUST_COMPILER_RT_ROOT=$(realpath ./compiler-rt)" >> "$GITHUB_ENV" + shell: bash + + # Non-linux tests just use our raw script + - name: Run locally + if: matrix.os != 'ubuntu-24.04' + shell: bash + run: ./ci/run.sh ${{ matrix.target }} + + # Configure buildx to use Docker layer caching + - uses: docker/setup-buildx-action@v3 + if: matrix.os == 'ubuntu-24.04' + + # Otherwise we use our docker containers to run builds + - name: Run in Docker + if: matrix.os == 'ubuntu-24.04' + run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} + + # Workaround to keep Docker cache smaller + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + - name: Move Docker cache + if: matrix.os == 'ubuntu-24.04' + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache + + clippy: + name: Clippy + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + with: + submodules: true + # Unlike rustfmt, stable clippy does not work on code with nightly features. + - name: Install nightly `clippy` + run: | + rustup set profile minimal + rustup default nightly + rustup component add clippy + - uses: Swatinem/rust-cache@v2 + - run: cargo clippy -- -D clippy::all + + miri: + name: Miri + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Install Rust (rustup) + run: rustup update nightly --no-self-update && rustup default nightly + shell: bash + - run: rustup component add miri + - run: cargo miri setup + - uses: Swatinem/rust-cache@v2 + - run: ./ci/miri.sh + + rustfmt: + name: Rustfmt + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Install stable `rustfmt` + run: rustup set profile minimal && rustup default stable && rustup component add rustfmt + - run: cargo fmt -- --check + + success: + needs: + - test + - rustfmt + - clippy + - miri + runs-on: ubuntu-24.04 + # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency + # failed" as success. So we have to do some contortions to ensure the job fails if any of its + # dependencies fails. + if: always() # make sure this is never "skipped" + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: check if any dependency failed + run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml deleted file mode 100644 index 003102d5943..00000000000 --- a/library/compiler-builtins/.github/workflows/main.yml +++ /dev/null @@ -1,217 +0,0 @@ -name: CI -on: [push, pull_request] - -env: - RUSTDOCFLAGS: -Dwarnings - RUSTFLAGS: -Dwarnings - -jobs: - test: - name: Test - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - - target: aarch64-apple-darwin - os: macos-latest - rust: nightly - - target: aarch64-unknown-linux-gnu - os: ubuntu-latest - rust: nightly - - target: aarch64-pc-windows-msvc - os: windows-latest - rust: nightly - test_verbatim: 1 - no_std: 1 - - target: arm-unknown-linux-gnueabi - os: ubuntu-latest - rust: nightly - - target: arm-unknown-linux-gnueabihf - os: ubuntu-latest - rust: nightly - - target: i586-unknown-linux-gnu - os: ubuntu-latest - rust: nightly - - target: i686-unknown-linux-gnu - os: ubuntu-latest - rust: nightly - - target: loongarch64-unknown-linux-gnu - os: ubuntu-latest - rust: nightly - # MIPS targets disabled since they are dropped to tier 3. - # See https://github.com/rust-lang/compiler-team/issues/648 - #- target: mips-unknown-linux-gnu - # os: ubuntu-latest - # rust: nightly - #- target: mips64-unknown-linux-gnuabi64 - # os: ubuntu-latest - # rust: nightly - #- target: mips64el-unknown-linux-gnuabi64 - # os: ubuntu-latest - # rust: nightly - #- target: mipsel-unknown-linux-gnu - # os: ubuntu-latest - # rust: nightly - - target: powerpc-unknown-linux-gnu - os: ubuntu-latest - rust: nightly - - target: powerpc64-unknown-linux-gnu - os: ubuntu-latest - rust: nightly - - target: powerpc64le-unknown-linux-gnu - os: ubuntu-latest - rust: nightly - - target: riscv64gc-unknown-linux-gnu - os: ubuntu-latest - rust: nightly - - target: thumbv6m-none-eabi - os: ubuntu-latest - rust: nightly - - target: thumbv7em-none-eabi - os: ubuntu-latest - rust: nightly - - target: thumbv7em-none-eabihf - os: ubuntu-latest - rust: nightly - - target: thumbv7m-none-eabi - os: ubuntu-latest - rust: nightly - - target: wasm32-unknown-unknown - os: ubuntu-latest - rust: nightly - - target: x86_64-unknown-linux-gnu - os: ubuntu-latest - rust: nightly - - target: x86_64-apple-darwin - os: macos-13 - rust: nightly - - target: i686-pc-windows-msvc - os: windows-latest - rust: nightly - test_verbatim: 1 - - target: x86_64-pc-windows-msvc - os: windows-latest - rust: nightly - test_verbatim: 1 - - target: i686-pc-windows-gnu - os: windows-latest - rust: nightly-i686-gnu - - target: x86_64-pc-windows-gnu - os: windows-latest - rust: nightly-x86_64-gnu - steps: - - name: Print runner information - run: uname -a - - uses: actions/checkout@v4 - with: - submodules: true - - name: Install Rust (rustup) - run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} - shell: bash - - run: rustup target add ${{ matrix.target }} - - run: rustup component add llvm-tools-preview - - uses: Swatinem/rust-cache@v2 - with: - key: ${{ matrix.target }} - - name: Cache Docker layers - uses: actions/cache@v4 - if: matrix.os == 'ubuntu-latest' - with: - path: /tmp/.buildx-cache - key: ${{ matrix.target }}-buildx-${{ github.sha }} - restore-keys: ${{ matrix.target }}-buildx- - - - name: Cache compiler-rt - id: cache-compiler-rt - uses: actions/cache@v4 - with: - path: compiler-rt - key: ${{ runner.os }}-compiler-rt-${{ hashFiles('ci/download-compiler-rt.sh') }} - - name: Download compiler-rt reference sources - if: steps.cache-compiler-rt.outputs.cache-hit != 'true' - run: ./ci/download-compiler-rt.sh - shell: bash - - run: echo "RUST_COMPILER_RT_ROOT=$(realpath ./compiler-rt)" >> "$GITHUB_ENV" - shell: bash - - # Non-linux tests just use our raw script - - run: ./ci/run.sh ${{ matrix.target }} - if: matrix.os != 'ubuntu-latest' - shell: bash - env: - NO_STD: ${{ matrix.no_std }} - TEST_VERBATIM: ${{ matrix.test_verbatim }} - - # Configure buildx to use Docker layer caching - - uses: docker/setup-buildx-action@v3 - if: matrix.os == 'ubuntu-latest' - - # Otherwise we use our docker containers to run builds - - run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} - if: matrix.os == 'ubuntu-latest' - - # Workaround to keep Docker cache smaller - # https://github.com/docker/build-push-action/issues/252 - # https://github.com/moby/buildkit/issues/1896 - - name: Move Docker cache - if: matrix.os == 'ubuntu-latest' - run: | - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache - - miri: - name: Miri - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Install Rust (rustup) - run: rustup update nightly --no-self-update && rustup default nightly - shell: bash - - run: rustup component add miri - - run: cargo miri setup - - uses: Swatinem/rust-cache@v2 - - run: ./ci/miri.sh - - rustfmt: - name: Rustfmt - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Install stable `rustfmt` - run: rustup set profile minimal && rustup default stable && rustup component add rustfmt - - run: cargo fmt -- --check - - clippy: - name: Clippy - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - # Unlike rustfmt, stable clippy does not work on code with nightly features. - - name: Install nightly `clippy` - run: | - rustup set profile minimal && rustup default nightly && rustup component add clippy - - uses: Swatinem/rust-cache@v2 - - run: cargo clippy -- -D clippy::all - - success: - needs: - - test - - rustfmt - - clippy - - miri - runs-on: ubuntu-latest - # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency - # failed" as success. So we have to do some contortions to ensure the job fails if any of its - # dependencies fails. - if: always() # make sure this is never "skipped" - steps: - # Manually check the status of all dependencies. `if: failure()` does not work. - - name: check if any dependency failed - run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/library/compiler-builtins/.github/workflows/publish.yaml b/library/compiler-builtins/.github/workflows/publish.yaml new file mode 100644 index 00000000000..7d6a8df0305 --- /dev/null +++ b/library/compiler-builtins/.github/workflows/publish.yaml @@ -0,0 +1,30 @@ +name: Release-plz + +permissions: + pull-requests: write + contents: write + +on: + push: + branches: + - master + +jobs: + release-plz: + name: Release-plz + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: true + - name: Install Rust (rustup) + run: rustup update nightly --no-self-update && rustup default nightly + - name: Publish `libm` as part of builtins, rather than its own crate + run: rm compiler-builtins/libm/Cargo.toml + - name: Run release-plz + uses: MarcoIeni/release-plz-action@v0.5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/library/compiler-builtins/.github/workflows/publish.yml b/library/compiler-builtins/.github/workflows/publish.yml deleted file mode 100644 index 7d6a8df0305..00000000000 --- a/library/compiler-builtins/.github/workflows/publish.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Release-plz - -permissions: - pull-requests: write - contents: write - -on: - push: - branches: - - master - -jobs: - release-plz: - name: Release-plz - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - submodules: true - - name: Install Rust (rustup) - run: rustup update nightly --no-self-update && rustup default nightly - - name: Publish `libm` as part of builtins, rather than its own crate - run: rm compiler-builtins/libm/Cargo.toml - - name: Run release-plz - uses: MarcoIeni/release-plz-action@v0.5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index 1aef14a962d..df71804ba23 100644 --- a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -1,11 +1,16 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ - gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ + gcc-aarch64-linux-gnu m4 make libc6-dev-arm64-cross \ qemu-user-static -ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + +ENV TOOLCHAIN_PREFIX=aarch64-linux-gnu- +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-aarch64-static \ + AR_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile index fc9803777f8..38ad1a13623 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -1,10 +1,15 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabi- +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER=qemu-arm-static \ + AR_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"ar \ + CC_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile index a127f67cb73..ffead05d5f2 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -1,10 +1,15 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ + AR_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ + CC_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile index 67a3e51a964..9ab49e46ee3 100644 --- a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -1,10 +1,15 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static -ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- +ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ + AR_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ + CC_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile index 15285d9bb06..d12ced3257f 100644 --- a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -1,5 +1,6 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc-multilib libc6-dev ca-certificates + gcc-multilib m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile index 15285d9bb06..d12ced3257f 100644 --- a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -1,5 +1,6 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc-multilib libc6-dev ca-certificates + gcc-multilib m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile index 5107d20a2a8..62b43da9e70 100644 --- a/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile @@ -8,6 +8,7 @@ RUN apt-get update && \ ENV CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER=loongarch64-linux-gnu-gcc-14 \ CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-loongarch64-static \ + AR_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-ar \ CC_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-gcc-14 \ QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile index a47dd9f1931..c02a9467234 100644 --- a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -7,7 +7,10 @@ RUN apt-get update && \ gcc-mips-linux-gnu libc6-dev-mips-cross \ binfmt-support qemu-user-static qemu-system-mips -ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=mips-linux-gnu- +ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER=qemu-mips-static \ + AR_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mips-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile index 688aa1ab231..6d8b96069be 100644 --- a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -1,5 +1,6 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ @@ -9,8 +10,11 @@ RUN apt-get update && \ libc6-dev-mips64-cross \ qemu-user-static \ qemu-system-mips -ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ + +ENV TOOLCHAIN_PREFIX=mips64-linux-gnuabi64- +ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64-static \ - CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ + AR_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ + CC_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile index 27d032a1441..7e6ac7c3b8a 100644 --- a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -1,5 +1,6 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ @@ -8,8 +9,11 @@ RUN apt-get update && \ libc6-dev \ libc6-dev-mips64el-cross \ qemu-user-static -ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER=mips64el-linux-gnuabi64-gcc \ + +ENV TOOLCHAIN_PREFIX=mips64el-linux-gnuabi64- +ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64el-static \ - CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \ + AR_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ + CC_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile index 4d18a6edbc9..9feadc7b5ce 100644 --- a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -7,7 +7,10 @@ RUN apt-get update && \ gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ binfmt-support qemu-user-static -ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=mipsel-linux-gnu- +ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER=qemu-mipsel-static \ + AR_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile index 5225b833c0c..84dcaf47ed5 100644 --- a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -7,7 +7,10 @@ RUN apt-get update && \ gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ qemu-system-ppc -ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=powerpc-linux-gnu- +ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc-static \ + AR_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile index cbd78eac421..b90fd5ec545 100644 --- a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -7,8 +7,10 @@ RUN apt-get update && \ gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ binfmt-support qemu-user-static qemu-system-ppc -ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=powerpc64-linux-gnu- +ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64-static \ - CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ + AR_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile index bad064297c3..e6d1d1cd0b5 100644 --- a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -7,8 +7,11 @@ RUN apt-get update && \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ qemu-system-ppc -ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=powerpc64le-linux-gnu- +ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64le-static \ + AR_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_CPU=POWER8 \ QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile index 4d4a194fdc6..eeb4ed0193e 100644 --- a/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile @@ -7,7 +7,10 @@ RUN apt-get update && \ gcc-riscv64-linux-gnu libc6-dev-riscv64-cross \ qemu-system-riscv64 -ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER=riscv64-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=riscv64-linux-gnu- +ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER=qemu-riscv64-static \ + AR_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/riscv64-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index f966b2b9f2a..ad0d4351ea6 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -1,8 +1,9 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV NO_STD=1 +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index f966b2b9f2a..ad0d4351ea6 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -1,8 +1,9 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV NO_STD=1 +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index f966b2b9f2a..ad0d4351ea6 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -1,8 +1,9 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV NO_STD=1 +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index f966b2b9f2a..ad0d4351ea6 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -1,8 +1,9 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV NO_STD=1 +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile index 4d12b6ff426..2813d318670 100644 --- a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile +++ b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile @@ -1,5 +1,6 @@ ARG IMAGE=ubuntu:20.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc clang libc6-dev ca-certificates diff --git a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile index 670c2439764..c590adcddf6 100644 --- a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -1,5 +1,6 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates + gcc m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 8dcb139d493..49cc1628652 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -2,9 +2,10 @@ set -eux -target="${1:-}" - export RUST_BACKTRACE="${RUST_BACKTRACE:-full}" +export NEXTEST_STATUS_LEVEL=all + +target="${1:-}" if [ -z "$target" ]; then host_target=$(rustc -vV | awk '/^host/ { print $2 }') @@ -20,7 +21,7 @@ if [ "${USING_CONTAINER_RUSTC:-}" = 1 ]; then fi # Test our implementation -if [ "${NO_STD:-}" = "1" ]; then +if [ "${BUILD_ONLY:-}" = "1" ]; then echo "nothing to do for no_std" else run="cargo test --package builtins-test --no-fail-fast --target $target" -- cgit 1.4.1-3-g733a5 From b0d6024f203fbf80c090e829115b2dbf459a8464 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 04:55:59 +0000 Subject: ci: Update `ci/run-docker.sh` to match libm Prepare for having the repositories combined by ensuring EMULATED, RUST_BACKTRACE, and CI are set or forwarded as applicable. Also re-indent the file to four spaces and do some reorganization. --- library/compiler-builtins/ci/run-docker.sh | 124 ++++++++++++++++------------- 1 file changed, 69 insertions(+), 55 deletions(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 5e19cf4d0cb..2c27ab7955b 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -5,88 +5,102 @@ set -euxo pipefail +host_arch="$(uname -m | sed 's/arm64/aarch64/')" + run() { local target="$1" - echo "TESTING TARGET: $target" + echo "testing target: $target" + + emulated="" + target_arch="$(echo "$target" | cut -d'-' -f1)" + if [ "$target_arch" != "$host_arch" ]; then + emulated=1 + echo "target is emulated" + fi # This directory needs to exist before calling docker, otherwise docker will create it but it # will be owned by root mkdir -p target + run_cmd="HOME=/tmp" + + if [ "${GITHUB_ACTIONS:-}" = "true" ]; then + # Enable Docker image caching on GHA + build_cmd=("buildx" "build") + build_args=( + "--cache-from" "type=local,src=/tmp/.buildx-cache" + "--cache-to" "type=local,dest=/tmp/.buildx-cache-new" + # This is the beautiful bash syntax for expanding an array but neither + # raising an error nor returning an empty string if the array is empty. + "${build_args[@]:+"${build_args[@]}"}" + "--load" + ) + fi + if [ "$(uname -s)" = "Linux" ] && [ -z "${DOCKER_BASE_IMAGE:-}" ]; then - # Share the host rustc and target. Do this only on Linux and if the image - # isn't overridden - run_args=( - --user "$(id -u):$(id -g)" - -e "CARGO_HOME=/cargo" - -v "${HOME}/.cargo:/cargo" - -v "$(pwd)/target:/builtins-target" - -v "$(rustc --print sysroot):/rust:ro" - ) - run_cmd="HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" + # Share the host rustc and target. Do this only on Linux and if the image + # isn't overridden + run_args=( + --user "$(id -u):$(id -g)" + -e "CARGO_HOME=/cargo" + -v "${HOME}/.cargo:/cargo" + -v "$(pwd)/target:/builtins-target" + -v "$(rustc --print sysroot):/rust:ro" + ) + run_cmd="$run_cmd PATH=\$PATH:/rust/bin" else - # Use rustc provided by a docker image - docker volume create compiler-builtins-cache - build_args=( - "--build-arg" "IMAGE=${DOCKER_BASE_IMAGE:-rustlang/rust:nightly}" - ) - run_args=( - -v "compiler-builtins-cache:/builtins-target" - ) - run_cmd="HOME=/tmp USING_CONTAINER_RUSTC=1 ci/run.sh $target" + # Use rustc provided by a docker image + docker volume create compiler-builtins-cache + build_args=( + "--build-arg" "IMAGE=${DOCKER_BASE_IMAGE:-rustlang/rust:nightly}" + ) + run_args=(-v "compiler-builtins-cache:/builtins-target") + run_cmd="$run_cmd HOME=/tmp" "USING_CONTAINER_RUSTC=1" fi if [ -d compiler-rt ]; then - export RUST_COMPILER_RT_ROOT="/checkout/compiler-rt" + export RUST_COMPILER_RT_ROOT="/checkout/compiler-rt" fi - if [ "${GITHUB_ACTIONS:-}" = "true" ]; then - # Enable Docker image caching on GHA - - build_cmd=("buildx" "build") - build_args=( - "--cache-from" "type=local,src=/tmp/.buildx-cache" - "--cache-to" "type=local,dest=/tmp/.buildx-cache-new" - # This is the beautiful bash syntax for expanding an array but neither - # raising an error nor returning an empty string if the array is empty. - "${build_args[@]:+"${build_args[@]}"}" - "--load" - ) - fi + run_cmd="$run_cmd ci/run.sh $target" docker "${build_cmd[@]:-build}" \ - -t "builtins-$target" \ - "${build_args[@]:-}" \ - "ci/docker/$target" + -t "builtins-$target" \ + "${build_args[@]:-}" \ + "ci/docker/$target" docker run \ - --rm \ - -e RUST_COMPILER_RT_ROOT \ - -e RUSTFLAGS \ - -e "CARGO_TARGET_DIR=/builtins-target" \ - -v "$(pwd):/checkout:ro" \ - -w /checkout \ - "${run_args[@]:-}" \ - --init \ - "builtins-$target" \ - sh -c "$run_cmd" + --rm \ + -e CI \ + -e CARGO_TARGET_DIR=/builtins-target \ + -e CARGO_TERM_COLOR \ + -e RUSTFLAGS \ + -e RUST_BACKTRACE \ + -e RUST_COMPILER_RT_ROOT \ + -e "EMULATED=$emulated" \ + -v "$(pwd):/checkout:ro" \ + -w /checkout \ + "${run_args[@]:-}" \ + --init \ + "builtins-$target" \ + sh -c "$run_cmd" } if [ "${1:-}" = "--help" ] || [ "$#" -gt 1 ]; then - set +x - echo "\ + set +x + echo "\ usage: ./ci/run-docker.sh [target] you can also set DOCKER_BASE_IMAGE to use something other than the default ubuntu:24.04 (or rustlang/rust:nightly). - " - exit + " + exit fi if [ -z "${1:-}" ]; then - for d in ci/docker/*; do - run $(basename "$d") - done + for d in ci/docker/*; do + run $(basename "$d") + done else - run "$1" + run "$1" fi -- cgit 1.4.1-3-g733a5 From 1947f328a70b42aca3b6866c73ace5fe0e75deb2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 23:13:44 +0000 Subject: Remove the libm submodule --- library/compiler-builtins/.gitmodules | 3 --- library/compiler-builtins/compiler-builtins/libm | 1 - 2 files changed, 4 deletions(-) delete mode 160000 library/compiler-builtins/compiler-builtins/libm diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index a0b0d021dea..e69de29bb2d 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +0,0 @@ -[submodule "compiler-builtins/libm"] - path = compiler-builtins/libm - url = https://github.com/rust-lang/libm.git diff --git a/library/compiler-builtins/compiler-builtins/libm b/library/compiler-builtins/compiler-builtins/libm deleted file mode 160000 index 96d1400326f..00000000000 --- a/library/compiler-builtins/compiler-builtins/libm +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 96d1400326f47381858f8149451a2b2fd8de2ea4 -- cgit 1.4.1-3-g733a5 From d794bb3492edf7506d4b59e168cb38bc528051b6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 23:42:14 +0000 Subject: Update submodules after the `libm` merge --- library/compiler-builtins/.gitmodules | 4 ++++ library/compiler-builtins/libm/.gitmodules | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 library/compiler-builtins/libm/.gitmodules diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index e69de29bb2d..ee941a47e77 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -0,0 +1,4 @@ +[submodule "musl"] + path = libm/crates/musl-math-sys/musl + url = https://git.musl-libc.org/git/musl + shallow = true diff --git a/library/compiler-builtins/libm/.gitmodules b/library/compiler-builtins/libm/.gitmodules deleted file mode 100644 index 35b269eadd4..00000000000 --- a/library/compiler-builtins/libm/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "musl"] - path = crates/musl-math-sys/musl - url = https://git.musl-libc.org/git/musl - shallow = true -- cgit 1.4.1-3-g733a5 From 1af955be9a76d162abdf32125d0af88798104a09 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 23:44:45 +0000 Subject: Update path to libm after the merge --- library/compiler-builtins/compiler-builtins/src/math.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/src/math.rs b/library/compiler-builtins/compiler-builtins/src/math.rs index ccd9c54216c..bd52a749e39 100644 --- a/library/compiler-builtins/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/compiler-builtins/src/math.rs @@ -2,7 +2,7 @@ #[allow(dead_code)] #[allow(unused_imports)] #[allow(clippy::all)] -#[path = "../libm/src/math/mod.rs"] +#[path = "../../libm/libm/src/math/mod.rs"] pub(crate) mod libm; macro_rules! libm_intrinsics { -- cgit 1.4.1-3-g733a5 From 83a8482f9167e6a602e1ce95ee66831896dd8ec3 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 23:48:27 +0000 Subject: Update .git-blame-ignore-revs after the libm merge --- library/compiler-builtins/.git-blame-ignore-revs | 6 ++++++ library/compiler-builtins/libm/.git-blame-ignore-revs | 5 ----- 2 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/.git-blame-ignore-revs delete mode 100644 library/compiler-builtins/libm/.git-blame-ignore-revs diff --git a/library/compiler-builtins/.git-blame-ignore-revs b/library/compiler-builtins/.git-blame-ignore-revs new file mode 100644 index 00000000000..2ede10da53d --- /dev/null +++ b/library/compiler-builtins/.git-blame-ignore-revs @@ -0,0 +1,6 @@ +# Use `git config blame.ignorerevsfile .git-blame-ignore-revs` to make +# `git blame` ignore the following commits. + +# Reformat with a new `.rustfmt.toml` +# In rust-lang/libm this was 5882cabb83c30bf7c36023f9a55a80583636b0e8 +4bb07a6275cc628ef81c65ac971dc6479963322f diff --git a/library/compiler-builtins/libm/.git-blame-ignore-revs b/library/compiler-builtins/libm/.git-blame-ignore-revs deleted file mode 100644 index c1e43134f36..00000000000 --- a/library/compiler-builtins/libm/.git-blame-ignore-revs +++ /dev/null @@ -1,5 +0,0 @@ -# Use `git config blame.ignorerevsfile .git-blame-ignore-revs` to make -# `git blame` ignore the following commits. - -# Reformat with a new `.rustfmt.toml` -5882cabb83c30bf7c36023f9a55a80583636b0e8 -- cgit 1.4.1-3-g733a5 From 806bb4fa6e35f65e63e1b96953fab68bfe5a67b4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 20:44:21 +0000 Subject: libm: Remove compiler-builtins-smoke-test Since `libm` is now part of the `compiler-builtins` repo, the crate to test that they work together is no longer needed. --- .../crates/compiler-builtins-smoke-test/Cargo.toml | 38 ----- .../crates/compiler-builtins-smoke-test/build.rs | 8 - .../crates/compiler-builtins-smoke-test/src/lib.rs | 17 -- .../compiler-builtins-smoke-test/src/math.rs | 182 --------------------- 4 files changed, 245 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs delete mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs delete mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml deleted file mode 100644 index 38a5116690a..00000000000 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "cb" -version = "0.1.0" -authors = ["Jorge Aparicio "] -edition = "2021" -publish = false - -[lib] -crate-type = ["staticlib"] -test = false -bench = false - -[features] -default = ["arch", "compiler-builtins", "unstable-float"] - -# Copied from `libm`'s root `Cargo.toml`' -arch = [] -compiler-builtins = [] -unstable-float = [] - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = [ - "cfg(arch_enabled)", - "cfg(assert_no_panic)", - "cfg(intrinsics_enabled)", - 'cfg(feature, values("force-soft-floats"))', - 'cfg(feature, values("unstable"))', - 'cfg(feature, values("unstable-intrinsics"))', - 'cfg(feature, values("unstable-public-internals"))', -] } - -[profile.dev] -panic = "abort" - -[profile.release] -panic = "abort" -codegen-units = 1 -lto = "fat" diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs deleted file mode 100644 index ef8d613c9f4..00000000000 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[path = "../../libm/configure.rs"] -mod configure; - -fn main() { - println!("cargo:rerun-if-changed=../../libm/configure.rs"); - let cfg = configure::Config::from_env(); - configure::emit_libm_config(&cfg); -} diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs deleted file mode 100644 index e70f6d9e04c..00000000000 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Fake compiler-builtins crate -//! -//! This is used to test that we can source import `libm` into the compiler-builtins crate. -//! Additionally, it provides a `#[no_mangle]` C API that can be easier to inspect than the -//! default `.rlib`. - -#![compiler_builtins] -#![feature(core_intrinsics)] -#![feature(compiler_builtins)] -#![feature(f16)] -#![feature(f128)] -#![allow(internal_features)] -#![no_std] - -mod math; -// Required for macro paths. -use math::libm::support; diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs deleted file mode 100644 index 58a5bfbb90f..00000000000 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs +++ /dev/null @@ -1,182 +0,0 @@ -use core::ffi::c_int; - -#[allow(dead_code)] -#[allow(clippy::all)] // We don't get `libm`'s list of `allow`s, so just ignore Clippy. -#[allow(unused_imports)] -#[path = "../../../libm/src/math/mod.rs"] -pub mod libm; - -/// Mark functions `#[no_mangle]` and with the C ABI. -macro_rules! no_mangle { - ($( $name:ident( $($tt:tt)+ ) -> $ret:ty; )+) => { - $( no_mangle!(@inner $name( $($tt)+ ) -> $ret); )+ - }; - - // Handle simple functions with single return types - (@inner $name:ident( $($arg:ident: $aty:ty),+ ) -> $ret:ty) => { - #[unsafe(no_mangle)] - extern "C" fn $name($($arg: $aty),+) -> $ret { - libm::$name($($arg),+) - } - }; - - - // Functions with `&mut` return values need to be handled differently, use `|` to - // separate inputs vs. outputs. - ( - @inner $name:ident( $($arg:ident: $aty:ty),+ | $($rarg:ident: $rty:ty),+) -> $ret:ty - ) => { - #[unsafe(no_mangle)] - extern "C" fn $name($($arg: $aty,)+ $($rarg: $rty),+) -> $ret { - let ret; - (ret, $(*$rarg),+) = libm::$name($($arg),+); - ret - } - }; -} - -no_mangle! { - frexp(x: f64 | y: &mut c_int) -> f64; - frexpf(x: f32 | y: &mut c_int) -> f32; - acos(x: f64) -> f64; - acosf(x: f32) -> f32; - acosh(x: f64) -> f64; - acoshf(x: f32) -> f32; - asin(x: f64) -> f64; - asinf(x: f32) -> f32; - asinh(x: f64) -> f64; - asinhf(x: f32) -> f32; - atan(x: f64) -> f64; - atan2(x: f64, y: f64) -> f64; - atan2f(x: f32, y: f32) -> f32; - atanf(x: f32) -> f32; - atanh(x: f64) -> f64; - atanhf(x: f32) -> f32; - cbrt(x: f64) -> f64; - cbrtf(x: f32) -> f32; - ceil(x: f64) -> f64; - ceilf(x: f32) -> f32; - ceilf128(x: f128) -> f128; - ceilf16(x: f16) -> f16; - copysign(x: f64, y: f64) -> f64; - copysignf(x: f32, y: f32) -> f32; - copysignf128(x: f128, y: f128) -> f128; - copysignf16(x: f16, y: f16) -> f16; - cos(x: f64) -> f64; - cosf(x: f32) -> f32; - cosh(x: f64) -> f64; - coshf(x: f32) -> f32; - erf(x: f64) -> f64; - erfc(x: f64) -> f64; - erfcf(x: f32) -> f32; - erff(x: f32) -> f32; - exp(x: f64) -> f64; - exp10(x: f64) -> f64; - exp10f(x: f32) -> f32; - exp2(x: f64) -> f64; - exp2f(x: f32) -> f32; - expf(x: f32) -> f32; - expm1(x: f64) -> f64; - expm1f(x: f32) -> f32; - fabs(x: f64) -> f64; - fabsf(x: f32) -> f32; - fabsf128(x: f128) -> f128; - fabsf16(x: f16) -> f16; - fdim(x: f64, y: f64) -> f64; - fdimf(x: f32, y: f32) -> f32; - fdimf128(x: f128, y: f128) -> f128; - fdimf16(x: f16, y: f16) -> f16; - floor(x: f64) -> f64; - floorf(x: f32) -> f32; - floorf128(x: f128) -> f128; - floorf16(x: f16) -> f16; - fma(x: f64, y: f64, z: f64) -> f64; - fmaf(x: f32, y: f32, z: f32) -> f32; - fmax(x: f64, y: f64) -> f64; - fmaxf(x: f32, y: f32) -> f32; - fmin(x: f64, y: f64) -> f64; - fminf(x: f32, y: f32) -> f32; - fmod(x: f64, y: f64) -> f64; - fmodf(x: f32, y: f32) -> f32; - hypot(x: f64, y: f64) -> f64; - hypotf(x: f32, y: f32) -> f32; - ilogb(x: f64) -> c_int; - ilogbf(x: f32) -> c_int; - j0(x: f64) -> f64; - j0f(x: f32) -> f32; - j1(x: f64) -> f64; - j1f(x: f32) -> f32; - jn(x: c_int, y: f64) -> f64; - jnf(x: c_int, y: f32) -> f32; - ldexp(x: f64, y: c_int) -> f64; - ldexpf(x: f32, y: c_int) -> f32; - lgamma(x: f64) -> f64; - lgamma_r(x: f64 | r: &mut c_int) -> f64; - lgammaf(x: f32) -> f32; - lgammaf_r(x: f32 | r: &mut c_int) -> f32; - log(x: f64) -> f64; - log10(x: f64) -> f64; - log10f(x: f32) -> f32; - log1p(x: f64) -> f64; - log1pf(x: f32) -> f32; - log2(x: f64) -> f64; - log2f(x: f32) -> f32; - logf(x: f32) -> f32; - modf(x: f64 | r: &mut f64) -> f64; - modff(x: f32 | r: &mut f32) -> f32; - nextafter(x: f64, y: f64) -> f64; - nextafterf(x: f32, y: f32) -> f32; - pow(x: f64, y: f64) -> f64; - powf(x: f32, y: f32) -> f32; - remainder(x: f64, y: f64) -> f64; - remainderf(x: f32, y: f32) -> f32; - remquo(x: f64, y: f64 | q: &mut c_int) -> f64; - remquof(x: f32, y: f32 | q: &mut c_int) -> f32; - rint(x: f64) -> f64; - rintf(x: f32) -> f32; - rintf128(x: f128) -> f128; - rintf16(x: f16) -> f16; - round(x: f64) -> f64; - roundf(x: f32) -> f32; - scalbn(x: f64, y: c_int) -> f64; - scalbnf(x: f32, y: c_int) -> f32; - sin(x: f64) -> f64; - sinf(x: f32) -> f32; - sinh(x: f64) -> f64; - sinhf(x: f32) -> f32; - sqrt(x: f64) -> f64; - sqrtf(x: f32) -> f32; - tan(x: f64) -> f64; - tanf(x: f32) -> f32; - tanh(x: f64) -> f64; - tanhf(x: f32) -> f32; - tgamma(x: f64) -> f64; - tgammaf(x: f32) -> f32; - trunc(x: f64) -> f64; - truncf(x: f32) -> f32; - truncf128(x: f128) -> f128; - truncf16(x: f16) -> f16; - y0(x: f64) -> f64; - y0f(x: f32) -> f32; - y1(x: f64) -> f64; - y1f(x: f32) -> f32; - yn(x: c_int, y: f64) -> f64; - ynf(x: c_int, y: f32) -> f32; -} - -/* sincos has no direct return type, not worth handling in the macro */ - -#[unsafe(no_mangle)] -extern "C" fn sincos(x: f64, s: &mut f64, c: &mut f64) { - (*s, *c) = libm::sincos(x); -} - -#[unsafe(no_mangle)] -extern "C" fn sincosf(x: f32, s: &mut f32, c: &mut f32) { - (*s, *c) = libm::sincosf(x); -} - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} -- cgit 1.4.1-3-g733a5 From 911a70381a9e7c84400b156e3cbcd805f3e64034 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 20:58:25 +0000 Subject: libm: Reorganize into compiler-builtins Distribute everything from `libm/` to better locations in the repo. `libm/libm/*` has not moved yet to avoid Git seeing the move as an edit to `Cargo.toml`. Files that remain to be merged somehow are in `etc/libm`. --- .../crates/libm-macros/Cargo.toml | 21 + .../crates/libm-macros/src/enums.rs | 154 +++ .../crates/libm-macros/src/lib.rs | 446 ++++++++ .../crates/libm-macros/src/parse.rs | 258 +++++ .../crates/libm-macros/src/shared.rs | 444 ++++++++ .../crates/libm-macros/tests/basic.rs | 103 ++ .../crates/libm-macros/tests/enum.rs | 38 + .../crates/musl-math-sys/Cargo.toml | 13 + .../crates/musl-math-sys/build.rs | 319 ++++++ .../crates/musl-math-sys/c_patches/alias.c | 40 + .../crates/musl-math-sys/c_patches/features.h | 39 + .../crates/musl-math-sys/src/lib.rs | 287 ++++++ library/compiler-builtins/crates/util/Cargo.toml | 18 + library/compiler-builtins/crates/util/build.rs | 10 + library/compiler-builtins/crates/util/src/main.rs | 382 +++++++ .../etc/function-definitions.json | 1069 ++++++++++++++++++++ library/compiler-builtins/etc/function-list.txt | 164 +++ library/compiler-builtins/etc/libm/.editorconfig | 21 + .../etc/libm/.github/workflows/main.yaml | 324 ++++++ .../etc/libm/.github/workflows/publish.yaml | 27 + library/compiler-builtins/etc/libm/.gitignore | 11 + library/compiler-builtins/etc/libm/Cargo.toml | 37 + .../compiler-builtins/etc/libm/ci/bench-icount.sh | 58 ++ library/compiler-builtins/etc/libm/ci/ci-util.py | 416 ++++++++ .../ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 15 + .../ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 14 + .../docker/arm-unknown-linux-gnueabihf/Dockerfile | 14 + .../armv7-unknown-linux-gnueabihf/Dockerfile | 14 + .../ci/docker/i586-unknown-linux-gnu/Dockerfile | 5 + .../ci/docker/i686-unknown-linux-gnu/Dockerfile | 5 + .../loongarch64-unknown-linux-gnu/Dockerfile | 13 + .../ci/docker/mips-unknown-linux-gnu/Dockerfile | 15 + .../mips64-unknown-linux-gnuabi64/Dockerfile | 19 + .../mips64el-unknown-linux-gnuabi64/Dockerfile | 18 + .../ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 15 + .../ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 15 + .../docker/powerpc64-unknown-linux-gnu/Dockerfile | 15 + .../powerpc64le-unknown-linux-gnu/Dockerfile | 16 + .../docker/riscv64gc-unknown-linux-gnu/Dockerfile | 15 + .../libm/ci/docker/thumbv6m-none-eabi/Dockerfile | 9 + .../libm/ci/docker/thumbv7em-none-eabi/Dockerfile | 9 + .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 9 + .../libm/ci/docker/thumbv7m-none-eabi/Dockerfile | 9 + .../ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 5 + .../compiler-builtins/etc/libm/ci/run-docker.sh | 56 + library/compiler-builtins/etc/libm/ci/run.sh | 130 +++ library/compiler-builtins/etc/update-api-list.py | 359 +++++++ library/compiler-builtins/libm-test/Cargo.toml | 70 ++ .../compiler-builtins/libm-test/benches/icount.rs | 316 ++++++ .../compiler-builtins/libm-test/benches/random.rs | 207 ++++ library/compiler-builtins/libm-test/build.rs | 9 + .../libm-test/examples/plot_domains.rs | 103 ++ .../libm-test/examples/plot_file.jl | 171 ++++ library/compiler-builtins/libm-test/src/domain.rs | 265 +++++ library/compiler-builtins/libm-test/src/f8_impl.rs | 503 +++++++++ .../compiler-builtins/libm-test/src/generate.rs | 43 + .../libm-test/src/generate/case_list.rs | 853 ++++++++++++++++ .../libm-test/src/generate/edge_cases.rs | 310 ++++++ .../libm-test/src/generate/random.rs | 125 +++ .../libm-test/src/generate/spaced.rs | 253 +++++ library/compiler-builtins/libm-test/src/lib.rs | 105 ++ library/compiler-builtins/libm-test/src/mpfloat.rs | 603 +++++++++++ library/compiler-builtins/libm-test/src/num.rs | 529 ++++++++++ library/compiler-builtins/libm-test/src/op.rs | 151 +++ .../compiler-builtins/libm-test/src/precision.rs | 573 +++++++++++ library/compiler-builtins/libm-test/src/run_cfg.rs | 370 +++++++ .../compiler-builtins/libm-test/src/test_traits.rs | 447 ++++++++ .../libm-test/tests/check_coverage.rs | 61 ++ .../libm-test/tests/compare_built_musl.rs | 143 +++ .../libm-test/tests/multiprecision.rs | 79 ++ .../libm-test/tests/standalone.rs | 38 + library/compiler-builtins/libm-test/tests/u256.rs | 147 +++ .../libm-test/tests/z_extensive/main.rs | 14 + .../libm-test/tests/z_extensive/run.rs | 233 +++++ library/compiler-builtins/libm/.editorconfig | 21 - .../libm/.github/workflows/main.yaml | 324 ------ .../libm/.github/workflows/publish.yaml | 27 - library/compiler-builtins/libm/.gitignore | 11 - library/compiler-builtins/libm/Cargo.toml | 37 - library/compiler-builtins/libm/LICENSE.txt | 258 ----- library/compiler-builtins/libm/README.md | 56 - library/compiler-builtins/libm/ci/bench-icount.sh | 58 -- library/compiler-builtins/libm/ci/ci-util.py | 416 -------- .../ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 15 - .../ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 14 - .../docker/arm-unknown-linux-gnueabihf/Dockerfile | 14 - .../armv7-unknown-linux-gnueabihf/Dockerfile | 14 - .../ci/docker/i586-unknown-linux-gnu/Dockerfile | 5 - .../ci/docker/i686-unknown-linux-gnu/Dockerfile | 5 - .../loongarch64-unknown-linux-gnu/Dockerfile | 13 - .../ci/docker/mips-unknown-linux-gnu/Dockerfile | 15 - .../mips64-unknown-linux-gnuabi64/Dockerfile | 19 - .../mips64el-unknown-linux-gnuabi64/Dockerfile | 18 - .../ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 15 - .../ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 15 - .../docker/powerpc64-unknown-linux-gnu/Dockerfile | 15 - .../powerpc64le-unknown-linux-gnu/Dockerfile | 16 - .../docker/riscv64gc-unknown-linux-gnu/Dockerfile | 15 - .../libm/ci/docker/thumbv6m-none-eabi/Dockerfile | 9 - .../libm/ci/docker/thumbv7em-none-eabi/Dockerfile | 9 - .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 9 - .../libm/ci/docker/thumbv7m-none-eabi/Dockerfile | 9 - .../ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 5 - library/compiler-builtins/libm/ci/run-docker.sh | 56 - library/compiler-builtins/libm/ci/run.sh | 130 --- .../libm/crates/libm-macros/Cargo.toml | 21 - .../libm/crates/libm-macros/src/enums.rs | 154 --- .../libm/crates/libm-macros/src/lib.rs | 446 -------- .../libm/crates/libm-macros/src/parse.rs | 258 ----- .../libm/crates/libm-macros/src/shared.rs | 444 -------- .../libm/crates/libm-macros/tests/basic.rs | 103 -- .../libm/crates/libm-macros/tests/enum.rs | 38 - .../libm/crates/libm-test/Cargo.toml | 70 -- .../libm/crates/libm-test/benches/icount.rs | 316 ------ .../libm/crates/libm-test/benches/random.rs | 207 ---- .../libm/crates/libm-test/build.rs | 9 - .../libm/crates/libm-test/examples/plot_domains.rs | 103 -- .../libm/crates/libm-test/examples/plot_file.jl | 171 ---- .../libm/crates/libm-test/src/domain.rs | 265 ----- .../libm/crates/libm-test/src/f8_impl.rs | 503 --------- .../libm/crates/libm-test/src/generate.rs | 43 - .../crates/libm-test/src/generate/case_list.rs | 853 ---------------- .../crates/libm-test/src/generate/edge_cases.rs | 310 ------ .../libm/crates/libm-test/src/generate/random.rs | 125 --- .../libm/crates/libm-test/src/generate/spaced.rs | 253 ----- .../libm/crates/libm-test/src/lib.rs | 105 -- .../libm/crates/libm-test/src/mpfloat.rs | 603 ----------- .../libm/crates/libm-test/src/num.rs | 529 ---------- .../libm/crates/libm-test/src/op.rs | 151 --- .../libm/crates/libm-test/src/precision.rs | 573 ----------- .../libm/crates/libm-test/src/run_cfg.rs | 370 ------- .../libm/crates/libm-test/src/test_traits.rs | 447 -------- .../libm/crates/libm-test/tests/check_coverage.rs | 61 -- .../crates/libm-test/tests/compare_built_musl.rs | 143 --- .../libm/crates/libm-test/tests/multiprecision.rs | 79 -- .../libm/crates/libm-test/tests/standalone.rs | 38 - .../libm/crates/libm-test/tests/u256.rs | 147 --- .../crates/libm-test/tests/z_extensive/main.rs | 14 - .../libm/crates/libm-test/tests/z_extensive/run.rs | 233 ----- .../libm/crates/musl-math-sys/Cargo.toml | 13 - .../libm/crates/musl-math-sys/build.rs | 319 ------ .../libm/crates/musl-math-sys/c_patches/alias.c | 40 - .../libm/crates/musl-math-sys/c_patches/features.h | 39 - .../libm/crates/musl-math-sys/musl | 1 - .../libm/crates/musl-math-sys/src/lib.rs | 287 ------ .../compiler-builtins/libm/crates/util/Cargo.toml | 18 - .../compiler-builtins/libm/crates/util/build.rs | 10 - .../compiler-builtins/libm/crates/util/src/main.rs | 382 ------- .../libm/etc/function-definitions.json | 1069 -------------------- .../compiler-builtins/libm/etc/function-list.txt | 164 --- .../compiler-builtins/libm/etc/update-api-list.py | 359 ------- library/compiler-builtins/libm/libm/LICENSE.txt | 259 ++++- library/compiler-builtins/libm/libm/README.md | 57 +- 153 files changed, 12528 insertions(+), 12531 deletions(-) create mode 100644 library/compiler-builtins/crates/libm-macros/Cargo.toml create mode 100644 library/compiler-builtins/crates/libm-macros/src/enums.rs create mode 100644 library/compiler-builtins/crates/libm-macros/src/lib.rs create mode 100644 library/compiler-builtins/crates/libm-macros/src/parse.rs create mode 100644 library/compiler-builtins/crates/libm-macros/src/shared.rs create mode 100644 library/compiler-builtins/crates/libm-macros/tests/basic.rs create mode 100644 library/compiler-builtins/crates/libm-macros/tests/enum.rs create mode 100644 library/compiler-builtins/crates/musl-math-sys/Cargo.toml create mode 100644 library/compiler-builtins/crates/musl-math-sys/build.rs create mode 100644 library/compiler-builtins/crates/musl-math-sys/c_patches/alias.c create mode 100644 library/compiler-builtins/crates/musl-math-sys/c_patches/features.h create mode 100644 library/compiler-builtins/crates/musl-math-sys/src/lib.rs create mode 100644 library/compiler-builtins/crates/util/Cargo.toml create mode 100644 library/compiler-builtins/crates/util/build.rs create mode 100644 library/compiler-builtins/crates/util/src/main.rs create mode 100644 library/compiler-builtins/etc/function-definitions.json create mode 100644 library/compiler-builtins/etc/function-list.txt create mode 100644 library/compiler-builtins/etc/libm/.editorconfig create mode 100644 library/compiler-builtins/etc/libm/.github/workflows/main.yaml create mode 100644 library/compiler-builtins/etc/libm/.github/workflows/publish.yaml create mode 100644 library/compiler-builtins/etc/libm/.gitignore create mode 100644 library/compiler-builtins/etc/libm/Cargo.toml create mode 100755 library/compiler-builtins/etc/libm/ci/bench-icount.sh create mode 100755 library/compiler-builtins/etc/libm/ci/ci-util.py create mode 100644 library/compiler-builtins/etc/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/etc/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile create mode 100755 library/compiler-builtins/etc/libm/ci/run-docker.sh create mode 100755 library/compiler-builtins/etc/libm/ci/run.sh create mode 100755 library/compiler-builtins/etc/update-api-list.py create mode 100644 library/compiler-builtins/libm-test/Cargo.toml create mode 100644 library/compiler-builtins/libm-test/benches/icount.rs create mode 100644 library/compiler-builtins/libm-test/benches/random.rs create mode 100644 library/compiler-builtins/libm-test/build.rs create mode 100644 library/compiler-builtins/libm-test/examples/plot_domains.rs create mode 100644 library/compiler-builtins/libm-test/examples/plot_file.jl create mode 100644 library/compiler-builtins/libm-test/src/domain.rs create mode 100644 library/compiler-builtins/libm-test/src/f8_impl.rs create mode 100644 library/compiler-builtins/libm-test/src/generate.rs create mode 100644 library/compiler-builtins/libm-test/src/generate/case_list.rs create mode 100644 library/compiler-builtins/libm-test/src/generate/edge_cases.rs create mode 100644 library/compiler-builtins/libm-test/src/generate/random.rs create mode 100644 library/compiler-builtins/libm-test/src/generate/spaced.rs create mode 100644 library/compiler-builtins/libm-test/src/lib.rs create mode 100644 library/compiler-builtins/libm-test/src/mpfloat.rs create mode 100644 library/compiler-builtins/libm-test/src/num.rs create mode 100644 library/compiler-builtins/libm-test/src/op.rs create mode 100644 library/compiler-builtins/libm-test/src/precision.rs create mode 100644 library/compiler-builtins/libm-test/src/run_cfg.rs create mode 100644 library/compiler-builtins/libm-test/src/test_traits.rs create mode 100644 library/compiler-builtins/libm-test/tests/check_coverage.rs create mode 100644 library/compiler-builtins/libm-test/tests/compare_built_musl.rs create mode 100644 library/compiler-builtins/libm-test/tests/multiprecision.rs create mode 100644 library/compiler-builtins/libm-test/tests/standalone.rs create mode 100644 library/compiler-builtins/libm-test/tests/u256.rs create mode 100644 library/compiler-builtins/libm-test/tests/z_extensive/main.rs create mode 100644 library/compiler-builtins/libm-test/tests/z_extensive/run.rs delete mode 100644 library/compiler-builtins/libm/.editorconfig delete mode 100644 library/compiler-builtins/libm/.github/workflows/main.yaml delete mode 100644 library/compiler-builtins/libm/.github/workflows/publish.yaml delete mode 100644 library/compiler-builtins/libm/.gitignore delete mode 100644 library/compiler-builtins/libm/Cargo.toml delete mode 100644 library/compiler-builtins/libm/LICENSE.txt delete mode 100644 library/compiler-builtins/libm/README.md delete mode 100755 library/compiler-builtins/libm/ci/bench-icount.sh delete mode 100755 library/compiler-builtins/libm/ci/ci-util.py delete mode 100644 library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/thumbv6m-none-eabi/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabi/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/thumbv7m-none-eabi/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile delete mode 100755 library/compiler-builtins/libm/ci/run-docker.sh delete mode 100755 library/compiler-builtins/libm/ci/run.sh delete mode 100644 library/compiler-builtins/libm/crates/libm-macros/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/libm-macros/src/enums.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-macros/src/lib.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-macros/src/parse.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-macros/src/shared.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/libm-test/benches/icount.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/benches/random.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/build.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/domain.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/generate.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/generate/case_list.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/generate/edge_cases.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/generate/random.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/generate/spaced.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/lib.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/num.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/op.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/precision.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/u256.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs delete mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs delete mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/build.rs delete mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/c_patches/alias.c delete mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/c_patches/features.h delete mode 160000 library/compiler-builtins/libm/crates/musl-math-sys/musl delete mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs delete mode 100644 library/compiler-builtins/libm/crates/util/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/util/build.rs delete mode 100644 library/compiler-builtins/libm/crates/util/src/main.rs delete mode 100644 library/compiler-builtins/libm/etc/function-definitions.json delete mode 100644 library/compiler-builtins/libm/etc/function-list.txt delete mode 100755 library/compiler-builtins/libm/etc/update-api-list.py mode change 120000 => 100644 library/compiler-builtins/libm/libm/LICENSE.txt mode change 120000 => 100644 library/compiler-builtins/libm/libm/README.md diff --git a/library/compiler-builtins/crates/libm-macros/Cargo.toml b/library/compiler-builtins/crates/libm-macros/Cargo.toml new file mode 100644 index 00000000000..50c869db7ff --- /dev/null +++ b/library/compiler-builtins/crates/libm-macros/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "libm-macros" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +proc-macro = true + +[dependencies] +heck = "0.5.0" +proc-macro2 = "1.0.94" +quote = "1.0.40" +syn = { version = "2.0.100", features = ["full", "extra-traits", "visit-mut"] } + +[lints.rust] +# Values used during testing +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(f16_enabled)', + 'cfg(f128_enabled)', +] } diff --git a/library/compiler-builtins/crates/libm-macros/src/enums.rs b/library/compiler-builtins/crates/libm-macros/src/enums.rs new file mode 100644 index 00000000000..864b625eab3 --- /dev/null +++ b/library/compiler-builtins/crates/libm-macros/src/enums.rs @@ -0,0 +1,154 @@ +use heck::ToUpperCamelCase; +use proc_macro2 as pm2; +use proc_macro2::{Ident, Span}; +use quote::quote; +use syn::spanned::Spanned; +use syn::{Fields, ItemEnum, Variant}; + +use crate::{ALL_OPERATIONS, base_name}; + +/// Implement `#[function_enum]`, see documentation in `lib.rs`. +pub fn function_enum( + mut item: ItemEnum, + attributes: pm2::TokenStream, +) -> syn::Result { + expect_empty_enum(&item)?; + let attr_span = attributes.span(); + let mut attr = attributes.into_iter(); + + // Attribute should be the identifier of the `BaseName` enum. + let Some(tt) = attr.next() else { + return Err(syn::Error::new(attr_span, "expected one attribute")); + }; + + let pm2::TokenTree::Ident(base_enum) = tt else { + return Err(syn::Error::new(tt.span(), "expected an identifier")); + }; + + if let Some(tt) = attr.next() { + return Err(syn::Error::new(tt.span(), "unexpected token after identifier")); + } + + let enum_name = &item.ident; + let mut as_str_arms = Vec::new(); + let mut from_str_arms = Vec::new(); + let mut base_arms = Vec::new(); + + for func in ALL_OPERATIONS.iter() { + let fn_name = func.name; + let ident = Ident::new(&fn_name.to_upper_camel_case(), Span::call_site()); + let bname_ident = Ident::new(&base_name(fn_name).to_upper_camel_case(), Span::call_site()); + + // Match arm for `fn as_str(self)` matcher + as_str_arms.push(quote! { Self::#ident => #fn_name }); + from_str_arms.push(quote! { #fn_name => Self::#ident }); + + // Match arm for `fn base_name(self)` matcher + base_arms.push(quote! { Self::#ident => #base_enum::#bname_ident }); + + let variant = + Variant { attrs: Vec::new(), ident, fields: Fields::Unit, discriminant: None }; + + item.variants.push(variant); + } + + let variants = item.variants.iter(); + + let res = quote! { + // Instantiate the enum + #item + + impl #enum_name { + /// All variants of this enum. + pub const ALL: &[Self] = &[ + #( Self::#variants, )* + ]; + + /// The stringified version of this function name. + pub const fn as_str(self) -> &'static str { + match self { + #( #as_str_arms , )* + } + } + + /// If `s` is the name of a function, return it. + pub fn from_str(s: &str) -> Option { + let ret = match s { + #( #from_str_arms , )* + _ => return None, + }; + Some(ret) + } + + /// The base name enum for this function. + pub const fn base_name(self) -> #base_enum { + match self { + #( #base_arms, )* + } + } + + /// Return information about this operation. + pub fn math_op(self) -> &'static crate::op::MathOpInfo { + crate::op::ALL_OPERATIONS.iter().find(|op| op.name == self.as_str()).unwrap() + } + } + }; + + Ok(res) +} + +/// Implement `#[base_name_enum]`, see documentation in `lib.rs`. +pub fn base_name_enum( + mut item: ItemEnum, + attributes: pm2::TokenStream, +) -> syn::Result { + expect_empty_enum(&item)?; + if !attributes.is_empty() { + let sp = attributes.span(); + return Err(syn::Error::new(sp.span(), "no attributes expected")); + } + + let mut base_names: Vec<_> = ALL_OPERATIONS.iter().map(|func| base_name(func.name)).collect(); + base_names.sort_unstable(); + base_names.dedup(); + + let item_name = &item.ident; + let mut as_str_arms = Vec::new(); + + for base_name in base_names { + let ident = Ident::new(&base_name.to_upper_camel_case(), Span::call_site()); + + // Match arm for `fn as_str(self)` matcher + as_str_arms.push(quote! { Self::#ident => #base_name }); + + let variant = + Variant { attrs: Vec::new(), ident, fields: Fields::Unit, discriminant: None }; + + item.variants.push(variant); + } + + let res = quote! { + // Instantiate the enum + #item + + impl #item_name { + /// The stringified version of this base name. + pub const fn as_str(self) -> &'static str { + match self { + #( #as_str_arms ),* + } + } + } + }; + + Ok(res) +} + +/// Verify that an enum is empty, otherwise return an error +fn expect_empty_enum(item: &ItemEnum) -> syn::Result<()> { + if !item.variants.is_empty() { + Err(syn::Error::new(item.variants.span(), "expected an empty enum")) + } else { + Ok(()) + } +} diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs new file mode 100644 index 00000000000..3cee5385b62 --- /dev/null +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -0,0 +1,446 @@ +mod enums; +mod parse; +mod shared; + +use parse::{Invocation, StructuredInput}; +use proc_macro as pm; +use proc_macro2::{self as pm2, Span}; +use quote::{ToTokens, quote}; +pub(crate) use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; +use syn::spanned::Spanned; +use syn::visit_mut::VisitMut; +use syn::{Ident, ItemEnum}; + +const KNOWN_TYPES: &[&str] = &["FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet"]; + +/// Populate an enum with a variant representing function. Names are in upper camel case. +/// +/// Applied to an empty enum. Expects one attribute `#[function_enum(BaseName)]` that provides +/// the name of the `BaseName` enum. +#[proc_macro_attribute] +pub fn function_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> pm::TokenStream { + let item = syn::parse_macro_input!(tokens as ItemEnum); + let res = enums::function_enum(item, attributes.into()); + + match res { + Ok(ts) => ts, + Err(e) => e.into_compile_error(), + } + .into() +} + +/// Create an enum representing all possible base names, with names in upper camel case. +/// +/// Applied to an empty enum. +#[proc_macro_attribute] +pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> pm::TokenStream { + let item = syn::parse_macro_input!(tokens as ItemEnum); + let res = enums::base_name_enum(item, attributes.into()); + + match res { + Ok(ts) => ts, + Err(e) => e.into_compile_error(), + } + .into() +} + +/// Do something for each function present in this crate. +/// +/// Takes a callback macro and invokes it multiple times, once for each function that +/// this crate exports. This makes it easy to create generic tests, benchmarks, or other checks +/// and apply it to each symbol. +/// +/// Additionally, the `extra` and `fn_extra` patterns can make use of magic identifiers: +/// +/// - `MACRO_FN_NAME`: gets replaced with the name of the function on that invocation. +/// - `MACRO_FN_NAME_NORMALIZED`: similar to the above, but removes sufixes so e.g. `sinf` becomes +/// `sin`, `cosf128` becomes `cos`, etc. +/// +/// Invoke as: +/// +/// ``` +/// // Macro that is invoked once per function +/// macro_rules! callback_macro { +/// ( +/// // Name of that function +/// fn_name: $fn_name:ident, +/// // The basic float type for this function (e.g. `f32`, `f64`) +/// FTy: $FTy:ty, +/// // Function signature of the C version (e.g. `fn(f32, &mut f32) -> f32`) +/// CFn: $CFn:ty, +/// // A tuple representing the C version's arguments (e.g. `(f32, &mut f32)`) +/// CArgs: $CArgs:ty, +/// // The C version's return type (e.g. `f32`) +/// CRet: $CRet:ty, +/// // Function signature of the Rust version (e.g. `fn(f32) -> (f32, f32)`) +/// RustFn: $RustFn:ty, +/// // A tuple representing the Rust version's arguments (e.g. `(f32,)`) +/// RustArgs: $RustArgs:ty, +/// // The Rust version's return type (e.g. `(f32, f32)`) +/// RustRet: $RustRet:ty, +/// // Attributes for the current function, if any +/// attrs: [$($attr:meta),*], +/// // Extra tokens passed directly (if any) +/// extra: [$extra:ident], +/// // Extra function-tokens passed directly (if any) +/// fn_extra: $fn_extra:expr, +/// ) => { }; +/// } +/// +/// // All fields except for `callback` are optional. +/// libm_macros::for_each_function! { +/// // The macro to invoke as a callback +/// callback: callback_macro, +/// // Which types to include either as a list (`[CFn, RustFn, RustArgs]`) or "all" +/// emit_types: all, +/// // Functions to skip, i.e. `callback` shouldn't be called at all for these. +/// skip: [sin, cos], +/// // Attributes passed as `attrs` for specific functions. For example, here the invocation +/// // with `sinf` and that with `cosf` will both get `meta1` and `meta2`, but no others will. +/// // +/// // Note that `f16_enabled` and `f128_enabled` will always get emitted regardless of whether +/// // or not this is specified. +/// attributes: [ +/// #[meta1] +/// #[meta2] +/// [sinf, cosf], +/// ], +/// // Any tokens that should be passed directly to all invocations of the callback. This can +/// // be used to pass local variables or other things the macro needs access to. +/// extra: [foo], +/// // Similar to `extra`, but allow providing a pattern for only specific functions. Uses +/// // a simplified match-like syntax. +/// fn_extra: match MACRO_FN_NAME { +/// hypot | hypotf => |x| x.hypot(), +/// _ => |x| x, +/// }, +/// } +/// ``` +#[proc_macro] +pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream { + let input = syn::parse_macro_input!(tokens as Invocation); + + let res = StructuredInput::from_fields(input) + .and_then(|mut s_in| validate(&mut s_in).map(|fn_list| (s_in, fn_list))) + .and_then(|(s_in, fn_list)| expand(s_in, &fn_list)); + + match res { + Ok(ts) => ts.into(), + Err(e) => e.into_compile_error().into(), + } +} + +/// Check for any input that is structurally correct but has other problems. +/// +/// Returns the list of function names that we should expand for. +fn validate(input: &mut StructuredInput) -> syn::Result> { + // Collect lists of all functions that are provied as macro inputs in various fields (only, + // skip, attributes). + let attr_mentions = input + .attributes + .iter() + .flat_map(|map_list| map_list.iter()) + .flat_map(|attr_map| attr_map.names.iter()); + let only_mentions = input.only.iter().flat_map(|only_list| only_list.iter()); + let fn_extra_mentions = + input.fn_extra.iter().flat_map(|v| v.keys()).filter(|name| *name != "_"); + let all_mentioned_fns = + input.skip.iter().chain(only_mentions).chain(attr_mentions).chain(fn_extra_mentions); + + // Make sure that every function mentioned is a real function + for mentioned in all_mentioned_fns { + if !ALL_OPERATIONS.iter().any(|func| mentioned == func.name) { + let e = syn::Error::new( + mentioned.span(), + format!("unrecognized function name `{mentioned}`"), + ); + return Err(e); + } + } + + if !input.skip.is_empty() && input.only.is_some() { + let e = syn::Error::new( + input.only_span.unwrap(), + "only one of `skip` or `only` may be specified", + ); + return Err(e); + } + + // Construct a list of what we intend to expand + let mut fn_list = Vec::new(); + for func in ALL_OPERATIONS.iter() { + let fn_name = func.name; + // If we have an `only` list and it does _not_ contain this function name, skip it + if input.only.as_ref().is_some_and(|only| !only.iter().any(|o| o == fn_name)) { + continue; + } + + // If there is a `skip` list that contains this function name, skip it + if input.skip.iter().any(|s| s == fn_name) { + continue; + } + + // Run everything else + fn_list.push(func); + } + + // Types that the user would like us to provide in the macro + let mut add_all_types = false; + for ty in &input.emit_types { + let ty_name = ty.to_string(); + if ty_name == "all" { + add_all_types = true; + continue; + } + + // Check that all requested types are valid + if !KNOWN_TYPES.contains(&ty_name.as_str()) { + let e = syn::Error::new( + ty_name.span(), + format!("unrecognized type identifier `{ty_name}`"), + ); + return Err(e); + } + } + + if add_all_types { + // Ensure that if `all` was specified that nothing else was + if input.emit_types.len() > 1 { + let e = syn::Error::new( + input.emit_types_span.unwrap(), + "if `all` is specified, no other type identifiers may be given", + ); + return Err(e); + } + + // ...and then add all types + input.emit_types.clear(); + for ty in KNOWN_TYPES { + let ident = Ident::new(ty, Span::call_site()); + input.emit_types.push(ident); + } + } + + if let Some(map) = &input.fn_extra { + if !map.keys().any(|key| key == "_") { + // No default provided; make sure every expected function is covered + let mut fns_not_covered = Vec::new(); + for func in &fn_list { + if !map.keys().any(|key| key == func.name) { + // `name` was not mentioned in the `match` statement + fns_not_covered.push(func); + } + } + + if !fns_not_covered.is_empty() { + let e = syn::Error::new( + input.fn_extra_span.unwrap(), + format!( + "`fn_extra`: no default `_` pattern specified and the following \ + patterns are not covered: {fns_not_covered:#?}" + ), + ); + return Err(e); + } + } + }; + + Ok(fn_list) +} + +/// Expand our structured macro input into invocations of the callback macro. +fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result { + let mut out = pm2::TokenStream::new(); + let default_ident = Ident::new("_", Span::call_site()); + let callback = input.callback; + + for func in fn_list { + let fn_name = Ident::new(func.name, Span::call_site()); + + // Prepare attributes in an `attrs: ...` field + let mut meta_fields = Vec::new(); + if let Some(attrs) = &input.attributes { + let meta_iter = attrs + .iter() + .filter(|map| map.names.contains(&fn_name)) + .flat_map(|map| &map.meta) + .map(|v| v.into_token_stream()); + + meta_fields.extend(meta_iter); + } + + // Always emit f16 and f128 meta so this doesn't need to be repeated everywhere + if func.rust_sig.args.contains(&Ty::F16) || func.rust_sig.returns.contains(&Ty::F16) { + let ts = quote! { cfg(f16_enabled) }; + meta_fields.push(ts); + } + if func.rust_sig.args.contains(&Ty::F128) || func.rust_sig.returns.contains(&Ty::F128) { + let ts = quote! { cfg(f128_enabled) }; + meta_fields.push(ts); + } + + let meta_field = quote! { attrs: [ #( #meta_fields ),* ], }; + + // Prepare extra in an `extra: ...` field, running the replacer + let extra_field = match input.extra.clone() { + Some(mut extra) => { + let mut v = MacroReplace::new(func.name); + v.visit_expr_mut(&mut extra); + v.finish()?; + + quote! { extra: #extra, } + } + None => pm2::TokenStream::new(), + }; + + // Prepare function-specific extra in a `fn_extra: ...` field, running the replacer + let fn_extra_field = match input.fn_extra { + Some(ref map) => { + let mut fn_extra = + map.get(&fn_name).or_else(|| map.get(&default_ident)).unwrap().clone(); + + let mut v = MacroReplace::new(func.name); + v.visit_expr_mut(&mut fn_extra); + v.finish()?; + + quote! { fn_extra: #fn_extra, } + } + None => pm2::TokenStream::new(), + }; + + let base_fty = func.float_ty; + let c_args = &func.c_sig.args; + let c_ret = &func.c_sig.returns; + let rust_args = &func.rust_sig.args; + let rust_ret = &func.rust_sig.returns; + + let mut ty_fields = Vec::new(); + for ty in &input.emit_types { + let field = match ty.to_string().as_str() { + "FTy" => quote! { FTy: #base_fty, }, + "CFn" => quote! { CFn: fn( #(#c_args),* ,) -> ( #(#c_ret),* ), }, + "CArgs" => quote! { CArgs: ( #(#c_args),* ,), }, + "CRet" => quote! { CRet: ( #(#c_ret),* ), }, + "RustFn" => quote! { RustFn: fn( #(#rust_args),* ,) -> ( #(#rust_ret),* ), }, + "RustArgs" => quote! { RustArgs: ( #(#rust_args),* ,), }, + "RustRet" => quote! { RustRet: ( #(#rust_ret),* ), }, + _ => unreachable!("checked in validation"), + }; + ty_fields.push(field); + } + + let new = quote! { + #callback! { + fn_name: #fn_name, + #( #ty_fields )* + #meta_field + #extra_field + #fn_extra_field + } + }; + + out.extend(new); + } + + Ok(out) +} + +/// Visitor to replace "magic" identifiers that we allow: `MACRO_FN_NAME` and +/// `MACRO_FN_NAME_NORMALIZED`. +struct MacroReplace { + fn_name: &'static str, + /// Remove the trailing `f` or `f128` to make + norm_name: String, + error: Option, +} + +impl MacroReplace { + fn new(name: &'static str) -> Self { + let norm_name = base_name(name); + Self { fn_name: name, norm_name: norm_name.to_owned(), error: None } + } + + fn finish(self) -> syn::Result<()> { + match self.error { + Some(e) => Err(e), + None => Ok(()), + } + } + + fn visit_ident_inner(&mut self, i: &mut Ident) { + let s = i.to_string(); + if !s.starts_with("MACRO") || self.error.is_some() { + return; + } + + match s.as_str() { + "MACRO_FN_NAME" => *i = Ident::new(self.fn_name, i.span()), + "MACRO_FN_NAME_NORMALIZED" => *i = Ident::new(&self.norm_name, i.span()), + _ => { + self.error = + Some(syn::Error::new(i.span(), format!("unrecognized meta expression `{s}`"))); + } + } + } +} + +impl VisitMut for MacroReplace { + fn visit_ident_mut(&mut self, i: &mut Ident) { + self.visit_ident_inner(i); + syn::visit_mut::visit_ident_mut(self, i); + } +} + +/// Return the unsuffixed version of a function name; e.g. `abs` and `absf` both return `abs`, +/// `lgamma_r` and `lgammaf_r` both return `lgamma_r`. +fn base_name(name: &str) -> &str { + let known_mappings = &[ + ("erff", "erf"), + ("erf", "erf"), + ("lgammaf_r", "lgamma_r"), + ("modff", "modf"), + ("modf", "modf"), + ]; + + match known_mappings.iter().find(|known| known.0 == name) { + Some(found) => found.1, + None => name + .strip_suffix("f") + .or_else(|| name.strip_suffix("f16")) + .or_else(|| name.strip_suffix("f128")) + .unwrap_or(name), + } +} + +impl ToTokens for Ty { + fn to_tokens(&self, tokens: &mut pm2::TokenStream) { + let ts = match self { + Ty::F16 => quote! { f16 }, + Ty::F32 => quote! { f32 }, + Ty::F64 => quote! { f64 }, + Ty::F128 => quote! { f128 }, + Ty::I32 => quote! { i32 }, + Ty::CInt => quote! { ::core::ffi::c_int }, + Ty::MutF16 => quote! { &'a mut f16 }, + Ty::MutF32 => quote! { &'a mut f32 }, + Ty::MutF64 => quote! { &'a mut f64 }, + Ty::MutF128 => quote! { &'a mut f128 }, + Ty::MutI32 => quote! { &'a mut i32 }, + Ty::MutCInt => quote! { &'a mut core::ffi::c_int }, + }; + + tokens.extend(ts); + } +} +impl ToTokens for FloatTy { + fn to_tokens(&self, tokens: &mut pm2::TokenStream) { + let ts = match self { + FloatTy::F16 => quote! { f16 }, + FloatTy::F32 => quote! { f32 }, + FloatTy::F64 => quote! { f64 }, + FloatTy::F128 => quote! { f128 }, + }; + + tokens.extend(ts); + } +} diff --git a/library/compiler-builtins/crates/libm-macros/src/parse.rs b/library/compiler-builtins/crates/libm-macros/src/parse.rs new file mode 100644 index 00000000000..369bbae2f4f --- /dev/null +++ b/library/compiler-builtins/crates/libm-macros/src/parse.rs @@ -0,0 +1,258 @@ +use std::collections::BTreeMap; + +use proc_macro2::Span; +use quote::ToTokens; +use syn::parse::{Parse, ParseStream, Parser}; +use syn::punctuated::Punctuated; +use syn::spanned::Spanned; +use syn::token::{self, Comma}; +use syn::{Arm, Attribute, Expr, ExprMatch, Ident, Meta, Token, bracketed}; + +/// The input to our macro; just a list of `field: value` items. +#[derive(Debug)] +pub struct Invocation { + fields: Punctuated, +} + +impl Parse for Invocation { + fn parse(input: ParseStream) -> syn::Result { + Ok(Self { fields: input.parse_terminated(Mapping::parse, Token![,])? }) + } +} + +/// A `key: expression` mapping with nothing else. Basically a simplified `syn::Field`. +#[derive(Debug)] +struct Mapping { + name: Ident, + _sep: Token![:], + expr: Expr, +} + +impl Parse for Mapping { + fn parse(input: ParseStream) -> syn::Result { + Ok(Self { name: input.parse()?, _sep: input.parse()?, expr: input.parse()? }) + } +} + +/// The input provided to our proc macro, after parsing into the form we expect. +#[derive(Debug)] +pub struct StructuredInput { + /// Macro to invoke once per function + pub callback: Ident, + /// Whether or not to provide `CFn` `CArgs` `RustFn` etc. This is really only needed + /// once for crate to set up the main trait. + pub emit_types: Vec, + /// Skip these functions + pub skip: Vec, + /// Invoke only for these functions + pub only: Option>, + /// Attributes that get applied to specific functions + pub attributes: Option>, + /// Extra expressions to pass to all invocations of the macro + pub extra: Option, + /// Per-function extra expressions to pass to the macro + pub fn_extra: Option>, + // For diagnostics + pub emit_types_span: Option, + pub only_span: Option, + pub fn_extra_span: Option, +} + +impl StructuredInput { + pub fn from_fields(input: Invocation) -> syn::Result { + let mut map: Vec<_> = input.fields.into_iter().collect(); + let cb_expr = expect_field(&mut map, "callback")?; + let emit_types_expr = expect_field(&mut map, "emit_types").ok(); + let skip_expr = expect_field(&mut map, "skip").ok(); + let only_expr = expect_field(&mut map, "only").ok(); + let attr_expr = expect_field(&mut map, "attributes").ok(); + let extra = expect_field(&mut map, "extra").ok(); + let fn_extra = expect_field(&mut map, "fn_extra").ok(); + + if !map.is_empty() { + Err(syn::Error::new( + map.first().unwrap().name.span(), + format!("unexpected fields {map:?}"), + ))?; + } + + let emit_types_span = emit_types_expr.as_ref().map(|expr| expr.span()); + let emit_types = match emit_types_expr { + Some(expr) => Parser::parse2(parse_ident_or_array, expr.into_token_stream())?, + None => Vec::new(), + }; + + let skip = match skip_expr { + Some(expr) => Parser::parse2(parse_ident_array, expr.into_token_stream())?, + None => Vec::new(), + }; + + let only_span = only_expr.as_ref().map(|expr| expr.span()); + let only = match only_expr { + Some(expr) => Some(Parser::parse2(parse_ident_array, expr.into_token_stream())?), + None => None, + }; + + let attributes = match attr_expr { + Some(expr) => { + let mut attributes = Vec::new(); + let attr_exprs = Parser::parse2(parse_expr_array, expr.into_token_stream())?; + + for attr in attr_exprs { + attributes.push(syn::parse2(attr.into_token_stream())?); + } + Some(attributes) + } + None => None, + }; + + let fn_extra_span = fn_extra.as_ref().map(|expr| expr.span()); + let fn_extra = match fn_extra { + Some(expr) => Some(extract_fn_extra_field(expr)?), + None => None, + }; + + Ok(Self { + callback: expect_ident(cb_expr)?, + emit_types, + skip, + only, + only_span, + attributes, + extra, + fn_extra, + fn_extra_span, + emit_types_span, + }) + } +} + +fn extract_fn_extra_field(expr: Expr) -> syn::Result> { + let Expr::Match(mexpr) = expr else { + let e = syn::Error::new(expr.span(), "`fn_extra` expects a match expression"); + return Err(e); + }; + + let ExprMatch { attrs, match_token: _, expr, brace_token: _, arms } = mexpr; + + expect_empty_attrs(&attrs)?; + + let match_on = expect_ident(*expr)?; + if match_on != "MACRO_FN_NAME" { + let e = syn::Error::new(match_on.span(), "only allowed to match on `MACRO_FN_NAME`"); + return Err(e); + } + + let mut res = BTreeMap::new(); + + for arm in arms { + let Arm { attrs, pat, guard, fat_arrow_token: _, body, comma: _ } = arm; + + expect_empty_attrs(&attrs)?; + + let keys = match pat { + syn::Pat::Wild(w) => vec![Ident::new("_", w.span())], + _ => Parser::parse2(parse_ident_pat, pat.into_token_stream())?, + }; + + if let Some(guard) = guard { + let e = syn::Error::new(guard.0.span(), "no guards allowed in this position"); + return Err(e); + } + + for key in keys { + let inserted = res.insert(key.clone(), *body.clone()); + if inserted.is_some() { + let e = syn::Error::new(key.span(), format!("key `{key}` specified twice")); + return Err(e); + } + } + } + + Ok(res) +} + +fn expect_empty_attrs(attrs: &[Attribute]) -> syn::Result<()> { + if attrs.is_empty() { + return Ok(()); + } + + let e = + syn::Error::new(attrs.first().unwrap().span(), "no attributes allowed in this position"); + Err(e) +} + +/// Extract a named field from a map, raising an error if it doesn't exist. +fn expect_field(v: &mut Vec, name: &str) -> syn::Result { + let pos = v.iter().position(|v| v.name == name).ok_or_else(|| { + syn::Error::new(Span::call_site(), format!("missing expected field `{name}`")) + })?; + + Ok(v.remove(pos).expr) +} + +/// Coerce an expression into a simple identifier. +fn expect_ident(expr: Expr) -> syn::Result { + syn::parse2(expr.into_token_stream()) +} + +/// Parse either a single identifier (`foo`) or an array of identifiers (`[foo, bar, baz]`). +fn parse_ident_or_array(input: ParseStream) -> syn::Result> { + if !input.peek(token::Bracket) { + return Ok(vec![input.parse()?]); + } + + parse_ident_array(input) +} + +/// Parse an array of expressions. +fn parse_expr_array(input: ParseStream) -> syn::Result> { + let content; + let _ = bracketed!(content in input); + let fields = content.parse_terminated(Expr::parse, Token![,])?; + Ok(fields.into_iter().collect()) +} + +/// Parse an array of idents, e.g. `[foo, bar, baz]`. +fn parse_ident_array(input: ParseStream) -> syn::Result> { + let content; + let _ = bracketed!(content in input); + let fields = content.parse_terminated(Ident::parse, Token![,])?; + Ok(fields.into_iter().collect()) +} + +/// Parse an pattern of idents, specifically `(foo | bar | baz)`. +fn parse_ident_pat(input: ParseStream) -> syn::Result> { + if !input.peek2(Token![|]) { + return Ok(vec![input.parse()?]); + } + + let fields = Punctuated::::parse_separated_nonempty(input)?; + Ok(fields.into_iter().collect()) +} + +/// A mapping of attributes to identifiers (just a simplified `Expr`). +/// +/// Expressed as: +/// +/// ```ignore +/// #[meta1] +/// #[meta2] +/// [foo, bar, baz] +/// ``` +#[derive(Debug)] +pub struct AttributeMap { + pub meta: Vec, + pub names: Vec, +} + +impl Parse for AttributeMap { + fn parse(input: ParseStream) -> syn::Result { + let attrs = input.call(Attribute::parse_outer)?; + + Ok(Self { + meta: attrs.into_iter().map(|a| a.meta).collect(), + names: parse_ident_array(input)?, + }) + } +} diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs new file mode 100644 index 00000000000..5e58220eb39 --- /dev/null +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -0,0 +1,444 @@ +/* List of all functions that is shared between `libm-macros` and `libm-test`. */ + +use std::fmt; +use std::sync::LazyLock; + +const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] = &[ + ( + // `fn(f16) -> f16` + FloatTy::F16, + Signature { args: &[Ty::F16], returns: &[Ty::F16] }, + None, + &[ + "ceilf16", + "fabsf16", + "floorf16", + "rintf16", + "roundevenf16", + "roundf16", + "sqrtf16", + "truncf16", + ], + ), + ( + // `fn(f32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::F32] }, + None, + &[ + "acosf", + "acoshf", + "asinf", + "asinhf", + "atanf", + "atanhf", + "cbrtf", + "ceilf", + "cosf", + "coshf", + "erfcf", + "erff", + "exp10f", + "exp2f", + "expf", + "expm1f", + "fabsf", + "floorf", + "j0f", + "j1f", + "lgammaf", + "log10f", + "log1pf", + "log2f", + "logf", + "rintf", + "roundevenf", + "roundf", + "sinf", + "sinhf", + "sqrtf", + "tanf", + "tanhf", + "tgammaf", + "truncf", + "y0f", + "y1f", + ], + ), + ( + // `(f64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::F64] }, + None, + &[ + "acos", + "acosh", + "asin", + "asinh", + "atan", + "atanh", + "cbrt", + "ceil", + "cos", + "cosh", + "erf", + "erfc", + "exp", + "exp10", + "exp2", + "expm1", + "fabs", + "floor", + "j0", + "j1", + "lgamma", + "log", + "log10", + "log1p", + "log2", + "rint", + "round", + "roundeven", + "sin", + "sinh", + "sqrt", + "tan", + "tanh", + "tgamma", + "trunc", + "y0", + "y1", + ], + ), + ( + // `fn(f128) -> f128` + FloatTy::F128, + Signature { args: &[Ty::F128], returns: &[Ty::F128] }, + None, + &[ + "ceilf128", + "fabsf128", + "floorf128", + "rintf128", + "roundevenf128", + "roundf128", + "sqrtf128", + "truncf128", + ], + ), + ( + // `(f16, f16) -> f16` + FloatTy::F16, + Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, + None, + &[ + "copysignf16", + "fdimf16", + "fmaxf16", + "fmaximum_numf16", + "fmaximumf16", + "fminf16", + "fminimum_numf16", + "fminimumf16", + "fmodf16", + ], + ), + ( + // `(f32, f32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] }, + None, + &[ + "atan2f", + "copysignf", + "fdimf", + "fmaxf", + "fmaximum_numf", + "fmaximumf", + "fminf", + "fminimum_numf", + "fminimumf", + "fmodf", + "hypotf", + "nextafterf", + "powf", + "remainderf", + ], + ), + ( + // `(f64, f64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] }, + None, + &[ + "atan2", + "copysign", + "fdim", + "fmax", + "fmaximum", + "fmaximum_num", + "fmin", + "fminimum", + "fminimum_num", + "fmod", + "hypot", + "nextafter", + "pow", + "remainder", + ], + ), + ( + // `(f128, f128) -> f128` + FloatTy::F128, + Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, + None, + &[ + "copysignf128", + "fdimf128", + "fmaxf128", + "fmaximum_numf128", + "fmaximumf128", + "fminf128", + "fminimum_numf128", + "fminimumf128", + "fmodf128", + ], + ), + ( + // `(f32, f32, f32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] }, + None, + &["fmaf"], + ), + ( + // `(f64, f64, f64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] }, + None, + &["fma"], + ), + ( + // `(f128, f128, f128) -> f128` + FloatTy::F128, + Signature { args: &[Ty::F128, Ty::F128, Ty::F128], returns: &[Ty::F128] }, + None, + &["fmaf128"], + ), + ( + // `(f32) -> i32` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::I32] }, + None, + &["ilogbf"], + ), + ( + // `(f64) -> i32` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::I32] }, + None, + &["ilogb"], + ), + ( + // `(i32, f32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] }, + None, + &["jnf", "ynf"], + ), + ( + // `(i32, f64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] }, + None, + &["jn", "yn"], + ), + ( + // `(f16, i32) -> f16` + FloatTy::F16, + Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16] }, + None, + &["ldexpf16", "scalbnf16"], + ), + ( + // `(f32, i32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] }, + None, + &["ldexpf", "scalbnf"], + ), + ( + // `(f64, i64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] }, + None, + &["ldexp", "scalbn"], + ), + ( + // `(f128, i32) -> f128` + FloatTy::F128, + Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128] }, + None, + &["ldexpf128", "scalbnf128"], + ), + ( + // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, + Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }), + &["modff"], + ), + ( + // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, + Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }), + &["modf"], + ), + ( + // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] }, + Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), + &["frexpf", "lgammaf_r"], + ), + ( + // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] }, + Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), + &["frexp", "lgamma_r"], + ), + ( + // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` + FloatTy::F32, + Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] }, + Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), + &["remquof"], + ), + ( + // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` + FloatTy::F64, + Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] }, + Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), + &["remquo"], + ), + ( + // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, + Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }), + &["sincosf"], + ), + ( + // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, + Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }), + &["sincos"], + ), +]; + +/// A type used in a function signature. +#[allow(dead_code)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Ty { + F16, + F32, + F64, + F128, + I32, + CInt, + MutF16, + MutF32, + MutF64, + MutF128, + MutI32, + MutCInt, +} + +/// A subset of [`Ty`] representing only floats. +#[allow(dead_code)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum FloatTy { + F16, + F32, + F64, + F128, +} + +impl fmt::Display for Ty { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + Ty::F16 => "f16", + Ty::F32 => "f32", + Ty::F64 => "f64", + Ty::F128 => "f128", + Ty::I32 => "i32", + Ty::CInt => "::core::ffi::c_int", + Ty::MutF16 => "&mut f16", + Ty::MutF32 => "&mut f32", + Ty::MutF64 => "&mut f64", + Ty::MutF128 => "&mut f128", + Ty::MutI32 => "&mut i32", + Ty::MutCInt => "&mut ::core::ffi::c_int", + }; + f.write_str(s) + } +} + +impl fmt::Display for FloatTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + FloatTy::F16 => "f16", + FloatTy::F32 => "f32", + FloatTy::F64 => "f64", + FloatTy::F128 => "f128", + }; + f.write_str(s) + } +} + +/// Representation of e.g. `(f32, f32) -> f32` +#[derive(Debug, Clone)] +pub struct Signature { + pub args: &'static [Ty], + pub returns: &'static [Ty], +} + +/// Combined information about a function implementation. +#[derive(Debug, Clone)] +pub struct MathOpInfo { + pub name: &'static str, + pub float_ty: FloatTy, + /// Function signature for C implementations + pub c_sig: Signature, + /// Function signature for Rust implementations + pub rust_sig: Signature, +} + +/// A flat representation of `ALL_FUNCTIONS`. +pub static ALL_OPERATIONS: LazyLock> = LazyLock::new(|| { + let mut ret = Vec::new(); + + for (base_fty, rust_sig, c_sig, names) in ALL_OPERATIONS_NESTED { + for name in *names { + let api = MathOpInfo { + name, + float_ty: *base_fty, + rust_sig: rust_sig.clone(), + c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()), + }; + ret.push(api); + } + + if !names.is_sorted() { + let mut sorted = (*names).to_owned(); + sorted.sort_unstable(); + panic!("names list is not sorted: {names:?}\nExpected: {sorted:?}"); + } + } + + ret.sort_by_key(|item| item.name); + ret +}); diff --git a/library/compiler-builtins/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/crates/libm-macros/tests/basic.rs new file mode 100644 index 00000000000..5314e84bbb0 --- /dev/null +++ b/library/compiler-builtins/crates/libm-macros/tests/basic.rs @@ -0,0 +1,103 @@ +#![feature(f16)] +#![feature(f128)] +// `STATUS_DLL_NOT_FOUND` on i686 MinGW, not worth looking into. +#![cfg(not(all(target_arch = "x86", target_os = "windows", target_env = "gnu")))] + +macro_rules! basic { + ( + fn_name: $fn_name:ident, + FTy: $FTy:ty, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + attrs: [$($attr:meta),*], + extra: [$($extra_tt:tt)*], + fn_extra: $fn_extra:expr, + ) => { + $(#[$attr])* + #[allow(dead_code)] + pub mod $fn_name { + type FTy= $FTy; + type CFnTy<'a> = $CFn; + type RustFnTy = $RustFn; + type RustArgsTy = $RustArgs; + type RustRetTy = $RustRet; + const A: &[&str] = &[$($extra_tt)*]; + fn foo(a: f32) -> f32 { + $fn_extra(a) + } + } + }; +} + +mod test_basic { + libm_macros::for_each_function! { + callback: basic, + emit_types: all, + skip: [sin, cos], + attributes: [ + // just some random attributes + #[allow(clippy::pedantic)] + #[allow(dead_code)] + [sinf, cosf] + ], + extra: ["foo", "bar"], + fn_extra: match MACRO_FN_NAME { + sin => |x| x + 2.0, + cos | cosf => |x: f32| x.MACRO_FN_NAME_NORMALIZED(), + _ => |_x| 100.0 + } + } +} + +macro_rules! basic_no_extra { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + ) => { + $(#[$attr])* + mod $fn_name {} + }; +} + +mod test_basic_no_extra { + // Test with no extra, no skip, and no attributes + libm_macros::for_each_function! { + callback: basic_no_extra, + } +} + +mod test_only { + // Test that only works + libm_macros::for_each_function! { + callback: basic_no_extra, + only: [sin, sinf], + } +} + +macro_rules! specified_types { + ( + fn_name: $fn_name:ident, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + attrs: [$($attr:meta),*], + ) => { + $(#[$attr])* + #[allow(dead_code)] + mod $fn_name { + type RustFnTy = $RustFn; + type RustArgsTy = $RustArgs; + } + }; +} + +mod test_emit_types { + // Test that we can specify a couple types to emit + libm_macros::for_each_function! { + callback: specified_types, + emit_types: [RustFn, RustArgs], + } +} diff --git a/library/compiler-builtins/crates/libm-macros/tests/enum.rs b/library/compiler-builtins/crates/libm-macros/tests/enum.rs new file mode 100644 index 00000000000..93e209a0dcc --- /dev/null +++ b/library/compiler-builtins/crates/libm-macros/tests/enum.rs @@ -0,0 +1,38 @@ +#[libm_macros::function_enum(BaseName)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Identifier {} + +#[libm_macros::base_name_enum] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum BaseName {} + +#[test] +fn as_str() { + assert_eq!(Identifier::Sin.as_str(), "sin"); + assert_eq!(Identifier::Sinf.as_str(), "sinf"); +} + +#[test] +fn from_str() { + assert_eq!(Identifier::from_str("sin").unwrap(), Identifier::Sin); + assert_eq!(Identifier::from_str("sinf").unwrap(), Identifier::Sinf); +} + +#[test] +fn basename() { + assert_eq!(Identifier::Sin.base_name(), BaseName::Sin); + assert_eq!(Identifier::Sinf.base_name(), BaseName::Sin); +} + +#[test] +fn math_op() { + assert_eq!(Identifier::Sin.math_op().float_ty, FloatTy::F64); + assert_eq!(Identifier::Sinf.math_op().float_ty, FloatTy::F32); +} + +// Replicate the structure that we have in `libm-test` +mod op { + include!("../../libm-macros/src/shared.rs"); +} + +use op::FloatTy; diff --git a/library/compiler-builtins/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/crates/musl-math-sys/Cargo.toml new file mode 100644 index 00000000000..9e866a9704f --- /dev/null +++ b/library/compiler-builtins/crates/musl-math-sys/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "musl-math-sys" +version = "0.1.0" +edition = "2024" +publish = false + +[dependencies] + +[dev-dependencies] +libm = { path = "../../libm" } + +[build-dependencies] +cc = "1.2.16" diff --git a/library/compiler-builtins/crates/musl-math-sys/build.rs b/library/compiler-builtins/crates/musl-math-sys/build.rs new file mode 100644 index 00000000000..f06d84ee267 --- /dev/null +++ b/library/compiler-builtins/crates/musl-math-sys/build.rs @@ -0,0 +1,319 @@ +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; +use std::{env, fs, str}; + +/// Static library that will be built +const LIB_NAME: &str = "musl_math_prefixed"; + +/// Files that have more than one symbol. Map of file names to the symbols defined in that file. +const MULTIPLE_SYMBOLS: &[(&str, &[&str])] = &[ + ("__invtrigl", &["__invtrigl", "__invtrigl_R", "__pio2_hi", "__pio2_lo"]), + ("__polevll", &["__polevll", "__p1evll"]), + ("erf", &["erf", "erfc"]), + ("erff", &["erff", "erfcf"]), + ("erfl", &["erfl", "erfcl"]), + ("exp10", &["exp10", "pow10"]), + ("exp10f", &["exp10f", "pow10f"]), + ("exp10l", &["exp10l", "pow10l"]), + ("exp2f_data", &["exp2f_data", "__exp2f_data"]), + ("exp_data", &["exp_data", "__exp_data"]), + ("j0", &["j0", "y0"]), + ("j0f", &["j0f", "y0f"]), + ("j1", &["j1", "y1"]), + ("j1f", &["j1f", "y1f"]), + ("jn", &["jn", "yn"]), + ("jnf", &["jnf", "ynf"]), + ("lgamma", &["lgamma", "__lgamma_r"]), + ("remainder", &["remainder", "drem"]), + ("remainderf", &["remainderf", "dremf"]), + ("lgammaf", &["lgammaf", "lgammaf_r", "__lgammaf_r"]), + ("lgammal", &["lgammal", "lgammal_r", "__lgammal_r"]), + ("log2_data", &["log2_data", "__log2_data"]), + ("log2f_data", &["log2f_data", "__log2f_data"]), + ("log_data", &["log_data", "__log_data"]), + ("logf_data", &["logf_data", "__logf_data"]), + ("pow_data", &["pow_data", "__pow_log_data"]), + ("powf_data", &["powf_data", "__powf_log2_data"]), + ("signgam", &["signgam", "__signgam"]), + ("sqrt_data", &["sqrt_data", "__rsqrt_tab"]), +]; + +fn main() { + let cfg = Config::from_env(); + + if cfg.target_env == "msvc" + || cfg.target_family == "wasm" + || cfg.target_features.iter().any(|f| f == "thumb-mode") + { + println!( + "cargo::warning=Musl doesn't compile with the current \ + target {}; skipping build", + &cfg.target_string + ); + return; + } + + build_musl_math(&cfg); +} + +#[allow(dead_code)] +#[derive(Debug)] +struct Config { + manifest_dir: PathBuf, + out_dir: PathBuf, + musl_dir: PathBuf, + musl_arch: String, + target_arch: String, + target_env: String, + target_family: String, + target_os: String, + target_string: String, + target_vendor: String, + target_features: Vec, +} + +impl Config { + fn from_env() -> Self { + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let target_features = env::var("CARGO_CFG_TARGET_FEATURE") + .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) + .unwrap_or_default(); + let musl_dir = manifest_dir.join("musl"); + + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let musl_arch = if target_arch == "x86" { "i386".to_owned() } else { target_arch.clone() }; + + println!("cargo::rerun-if-changed={}/c_patches", manifest_dir.display()); + println!("cargo::rerun-if-changed={}", musl_dir.display()); + + Self { + manifest_dir, + out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), + musl_dir, + musl_arch, + target_arch, + target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), + target_family: env::var("CARGO_CFG_TARGET_FAMILY").unwrap(), + target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + target_string: env::var("TARGET").unwrap(), + target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), + target_features, + } + } +} + +/// Build musl math symbols to a static library +fn build_musl_math(cfg: &Config) { + let musl_dir = &cfg.musl_dir; + let math = musl_dir.join("src/math"); + let arch_dir = musl_dir.join("arch").join(&cfg.musl_arch); + assert!(math.exists(), "musl source not found. Is the submodule up to date?"); + + let source_map = find_math_source(&math, cfg); + let out_path = cfg.out_dir.join(format!("lib{LIB_NAME}.a")); + + // Run configuration steps. Usually done as part of the musl `Makefile`. + let obj_include = cfg.out_dir.join("musl_obj/include"); + fs::create_dir_all(&obj_include).unwrap(); + fs::create_dir_all(obj_include.join("bits")).unwrap(); + let sed_stat = Command::new("sed") + .arg("-f") + .arg(musl_dir.join("tools/mkalltypes.sed")) + .arg(arch_dir.join("bits/alltypes.h.in")) + .arg(musl_dir.join("include/alltypes.h.in")) + .stderr(Stdio::inherit()) + .output() + .unwrap(); + assert!(sed_stat.status.success(), "sed command failed: {:?}", sed_stat.status); + + fs::write(obj_include.join("bits/alltypes.h"), sed_stat.stdout).unwrap(); + + let mut cbuild = cc::Build::new(); + cbuild + .extra_warnings(false) + .warnings(false) + .flag_if_supported("-Wno-bitwise-op-parentheses") + .flag_if_supported("-Wno-literal-range") + .flag_if_supported("-Wno-parentheses") + .flag_if_supported("-Wno-shift-count-overflow") + .flag_if_supported("-Wno-shift-op-parentheses") + .flag_if_supported("-Wno-unused-but-set-variable") + .flag_if_supported("-std=c99") + .flag_if_supported("-ffreestanding") + .flag_if_supported("-nostdinc") + .define("_ALL_SOURCE", "1") + .define( + "ROOT_INCLUDE_FEATURES", + Some(musl_dir.join("include/features.h").to_str().unwrap()), + ) + // Our overrides are in this directory + .include(cfg.manifest_dir.join("c_patches")) + .include(musl_dir.join("arch").join(&cfg.musl_arch)) + .include(musl_dir.join("arch/generic")) + .include(musl_dir.join("src/include")) + .include(musl_dir.join("src/internal")) + .include(obj_include) + .include(musl_dir.join("include")) + .file(cfg.manifest_dir.join("c_patches/alias.c")); + + for (sym_name, src_file) in source_map { + // Build the source file + cbuild.file(src_file); + + // Trickery! Redefine the symbol names to have the prefix `musl_`, which allows us to + // differentiate these symbols from whatever we provide. + if let Some((_names, syms)) = + MULTIPLE_SYMBOLS.iter().find(|(name, _syms)| *name == sym_name) + { + // Handle the occasional file that defines multiple symbols + for sym in *syms { + cbuild.define(sym, Some(format!("musl_{sym}").as_str())); + } + } else { + // If the file doesn't define multiple symbols, the file name will be the symbol + cbuild.define(&sym_name, Some(format!("musl_{sym_name}").as_str())); + } + } + + if cfg!(windows) { + // On Windows we don't have a good way to check symbols, so skip that step. + cbuild.compile(LIB_NAME); + return; + } + + let objfiles = cbuild.compile_intermediates(); + + // We create the archive ourselves with relocations rather than letting `cc` do it so we can + // encourage it to resolve symbols now. This should help avoid accidentally linking the wrong + // thing. + let stat = cbuild + .get_compiler() + .to_command() + .arg("-r") + .arg("-o") + .arg(&out_path) + .args(objfiles) + .status() + .unwrap(); + assert!(stat.success()); + + println!("cargo::rustc-link-lib={LIB_NAME}"); + println!("cargo::rustc-link-search=native={}", cfg.out_dir.display()); + + validate_archive_symbols(&out_path); +} + +/// Build a map of `name -> path`. `name` is typically the symbol name, but this doesn't account +/// for files that provide multiple symbols. +fn find_math_source(math_root: &Path, cfg: &Config) -> BTreeMap { + let mut map = BTreeMap::new(); + let mut arch_dir = None; + + // Locate all files and directories + for item in fs::read_dir(math_root).unwrap() { + let path = item.unwrap().path(); + let meta = fs::metadata(&path).unwrap(); + + if meta.is_dir() { + // Make note of the arch-specific directory if it exists + if path.file_name().unwrap() == cfg.target_arch.as_str() { + arch_dir = Some(path); + } + continue; + } + + // Skip non-source files + if path.extension().is_some_and(|ext| ext == "h") { + continue; + } + + let sym_name = path.file_stem().unwrap(); + map.insert(sym_name.to_str().unwrap().to_owned(), path.to_owned()); + } + + // If arch-specific versions are available, build those instead. + if let Some(arch_dir) = arch_dir { + for item in fs::read_dir(arch_dir).unwrap() { + let path = item.unwrap().path(); + let sym_name = path.file_stem().unwrap(); + + if path.extension().unwrap() == "s" { + // FIXME: we never build assembly versions since we have no good way to + // rename the symbol (our options are probably preprocessor or objcopy). + continue; + } + map.insert(sym_name.to_str().unwrap().to_owned(), path); + } + } + + map +} + +/// Make sure we don't have something like a loose unprefixed `_cos` called somewhere, which could +/// wind up linking to system libraries rather than the built musl library. +fn validate_archive_symbols(out_path: &Path) { + const ALLOWED_UNDEF_PFX: &[&str] = &[ + // PIC and arch-specific + ".TOC", + "_GLOBAL_OFFSET_TABLE_", + "__x86.get_pc_thunk", + // gcc/compiler-rt/compiler-builtins symbols + "__add", + "__aeabi_", + "__div", + "__eq", + "__extend", + "__fix", + "__float", + "__gcc_", + "__ge", + "__gt", + "__le", + "__lshr", + "__lt", + "__mul", + "__ne", + "__stack_chk_fail", + "__stack_chk_guard", + "__sub", + "__trunc", + "__undef", + // string routines + "__bzero", + "bzero", + // FPENV interfaces + "feclearexcept", + "fegetround", + "feraiseexcept", + "fesetround", + "fetestexcept", + ]; + + // List global undefined symbols + let out = + Command::new("nm").arg("-guj").arg(out_path).stderr(Stdio::inherit()).output().unwrap(); + + let undef = str::from_utf8(&out.stdout).unwrap(); + let mut undef = undef.lines().collect::>(); + undef.retain(|sym| { + // Account for file formats that add a leading `_` + !ALLOWED_UNDEF_PFX.iter().any(|pfx| sym.starts_with(pfx) || sym[1..].starts_with(pfx)) + }); + + assert!(undef.is_empty(), "found disallowed undefined symbols: {undef:#?}"); + + // Find any symbols that are missing the `_musl_` prefix` + let out = + Command::new("nm").arg("-gUj").arg(out_path).stderr(Stdio::inherit()).output().unwrap(); + + let defined = str::from_utf8(&out.stdout).unwrap(); + let mut defined = defined.lines().collect::>(); + defined.retain(|sym| { + !(sym.starts_with("_musl_") + || sym.starts_with("musl_") + || sym.starts_with("__x86.get_pc_thunk")) + }); + + assert!(defined.is_empty(), "found unprefixed symbols: {defined:#?}"); +} diff --git a/library/compiler-builtins/crates/musl-math-sys/c_patches/alias.c b/library/compiler-builtins/crates/musl-math-sys/c_patches/alias.c new file mode 100644 index 00000000000..63e0f08d5eb --- /dev/null +++ b/library/compiler-builtins/crates/musl-math-sys/c_patches/alias.c @@ -0,0 +1,40 @@ +/* On platforms that don't support weak symbols, define required aliases + * as wrappers. See comments in `features.h` for more. + */ +#if defined(__APPLE__) || defined(__MINGW32__) + +double __lgamma_r(double a, int *b); +float __lgammaf_r(float a, int *b); +long __lgammal_r(long double a, int *b); +double exp10(double a); +float exp10f(float a); +long exp10l(long double a); +double remainder(double a, double b); +float remainderf(float a, float b); + +double lgamma_r(double a, int *b) { + return __lgamma_r(a, b); +} +float lgammaf_r(float a, int *b) { + return __lgammaf_r(a, b); +} +long double lgammal_r(long double a, int *b) { + return __lgammal_r(a, b); +} +double pow10(double a) { + return exp10(a); +} +float pow10f(float a) { + return exp10f(a); +} +long double pow10l(long double a) { + return exp10l(a); +} +double drem(double a, double b) { + return remainder(a, b); +} +float dremf(float a, float b) { + return remainderf(a, b); +} + +#endif diff --git a/library/compiler-builtins/crates/musl-math-sys/c_patches/features.h b/library/compiler-builtins/crates/musl-math-sys/c_patches/features.h new file mode 100644 index 00000000000..97af935979a --- /dev/null +++ b/library/compiler-builtins/crates/musl-math-sys/c_patches/features.h @@ -0,0 +1,39 @@ +/* This is meant to override Musl's src/include/features.h + * + * We use a separate file here to redefine some attributes that don't work on + * all platforms that we would like to build on. + */ + +#ifndef FEATURES_H +#define FEATURES_H + +/* Get the required `#include "../../include/features.h"` since we can't use + * the relative path. The C macros need double indirection to get a usable + * string. */ +#define _stringify_inner(s) #s +#define _stringify(s) _stringify_inner(s) +#include _stringify(ROOT_INCLUDE_FEATURES) + +#if defined(__APPLE__) +#define weak __attribute__((__weak__)) +#define hidden __attribute__((__visibility__("hidden"))) + +/* We _should_ be able to define this as: + * _Pragma(_stringify(weak musl_ ## new = musl_ ## old)) + * However, weak symbols aren't handled correctly [1]. So we manually write + * wrappers, which are in `alias.c`. + * + * [1]: https://github.com/llvm/llvm-project/issues/111321 + */ +#define weak_alias(old, new) /* nothing */ + +#else +#define weak __attribute__((__weak__)) +#define hidden __attribute__((__visibility__("hidden"))) +#define weak_alias(old, new) \ + extern __typeof(old) musl_ ## new \ + __attribute__((__weak__, __alias__(_stringify(musl_ ## old)))) + +#endif /* defined(__APPLE__) */ + +#endif diff --git a/library/compiler-builtins/crates/musl-math-sys/src/lib.rs b/library/compiler-builtins/crates/musl-math-sys/src/lib.rs new file mode 100644 index 00000000000..6a4bf4859d9 --- /dev/null +++ b/library/compiler-builtins/crates/musl-math-sys/src/lib.rs @@ -0,0 +1,287 @@ +//! Bindings to Musl math functions (these are built in `build.rs`). + +use std::ffi::{c_char, c_int, c_long}; + +/// Macro for creating bindings and exposing a safe function (since the implementations have no +/// preconditions). Included functions must have correct signatures, otherwise this will be +/// unsound. +macro_rules! functions { + ( $( + $( #[$meta:meta] )* + $pfx_name:ident: $name:ident( $($arg:ident: $aty:ty),+ ) -> $rty:ty; + )* ) => { + unsafe extern "C" { + $( fn $pfx_name( $($arg: $aty),+ ) -> $rty; )* + } + + $( + // Expose a safe version + $( #[$meta] )* + pub fn $name( $($arg: $aty),+ ) -> $rty { + // SAFETY: FFI calls with no preconditions + unsafe { $pfx_name( $($arg),+ ) } + } + )* + + #[cfg(test)] + mod tests { + use super::*; + use test_support::CallTest; + + $( functions!( + @single_test + $name($($arg: $aty),+) -> $rty + ); )* + } + }; + + (@single_test + $name:ident( $($arg:ident: $aty:ty),+ ) -> $rty:ty + ) => { + // Run a simple check to ensure we can link and call the function without crashing. + #[test] + // FIXME(#309): LE PPC crashes calling some musl functions + #[cfg_attr(all(target_arch = "powerpc64", target_endian = "little"), ignore)] + fn $name() { + $rty>::check(super::$name); + } + }; +} + +#[cfg(test)] +mod test_support { + use core::ffi::c_char; + + /// Just verify that we are able to call the function. + pub trait CallTest { + fn check(f: Self); + } + + macro_rules! impl_calltest { + ($( ($($arg:ty),*) -> $ret:ty; )*) => { + $( + impl CallTest for fn($($arg),*) -> $ret { + fn check(f: Self) { + f($(1 as $arg),*); + } + } + )* + }; + } + + impl_calltest! { + (f32) -> f32; + (f64) -> f64; + (f32, f32) -> f32; + (f64, f64) -> f64; + (i32, f32) -> f32; + (i32, f64) -> f64; + (f32, f32, f32) -> f32; + (f64, f64, f64) -> f64; + (f32, i32) -> f32; + (f32, i64) -> f32; + (f32) -> i32; + (f64) -> i32; + (f64, i32) -> f64; + (f64, i64) -> f64; + } + + impl CallTest for fn(f32, &mut f32) -> f32 { + fn check(f: Self) { + let mut tmp = 0.0; + f(0.0, &mut tmp); + } + } + impl CallTest for fn(f64, &mut f64) -> f64 { + fn check(f: Self) { + let mut tmp = 0.0; + f(0.0, &mut tmp); + } + } + impl CallTest for fn(f32, &mut i32) -> f32 { + fn check(f: Self) { + let mut tmp = 1; + f(0.0, &mut tmp); + } + } + impl CallTest for fn(f64, &mut i32) -> f64 { + fn check(f: Self) { + let mut tmp = 1; + f(0.0, &mut tmp); + } + } + impl CallTest for fn(f32, f32, &mut i32) -> f32 { + fn check(f: Self) { + let mut tmp = 1; + f(0.0, 0.0, &mut tmp); + } + } + impl CallTest for fn(f64, f64, &mut i32) -> f64 { + fn check(f: Self) { + let mut tmp = 1; + f(0.0, 0.0, &mut tmp); + } + } + impl CallTest for fn(f32, &mut f32, &mut f32) { + fn check(f: Self) { + let mut tmp1 = 1.0; + let mut tmp2 = 1.0; + f(0.0, &mut tmp1, &mut tmp2); + } + } + impl CallTest for fn(f64, &mut f64, &mut f64) { + fn check(f: Self) { + let mut tmp1 = 1.0; + let mut tmp2 = 1.0; + f(0.0, &mut tmp1, &mut tmp2); + } + } + impl CallTest for fn(*const c_char) -> f32 { + fn check(f: Self) { + f(c"1".as_ptr()); + } + } + impl CallTest for fn(*const c_char) -> f64 { + fn check(f: Self) { + f(c"1".as_ptr()); + } + } +} + +functions! { + musl_acos: acos(a: f64) -> f64; + musl_acosf: acosf(a: f32) -> f32; + musl_acosh: acosh(a: f64) -> f64; + musl_acoshf: acoshf(a: f32) -> f32; + musl_asin: asin(a: f64) -> f64; + musl_asinf: asinf(a: f32) -> f32; + musl_asinh: asinh(a: f64) -> f64; + musl_asinhf: asinhf(a: f32) -> f32; + musl_atan2: atan2(a: f64, b: f64) -> f64; + musl_atan2f: atan2f(a: f32, b: f32) -> f32; + musl_atan: atan(a: f64) -> f64; + musl_atanf: atanf(a: f32) -> f32; + musl_atanh: atanh(a: f64) -> f64; + musl_atanhf: atanhf(a: f32) -> f32; + musl_cbrt: cbrt(a: f64) -> f64; + musl_cbrtf: cbrtf(a: f32) -> f32; + musl_ceil: ceil(a: f64) -> f64; + musl_ceilf: ceilf(a: f32) -> f32; + musl_copysign: copysign(a: f64, b: f64) -> f64; + musl_copysignf: copysignf(a: f32, b: f32) -> f32; + musl_cos: cos(a: f64) -> f64; + musl_cosf: cosf(a: f32) -> f32; + musl_cosh: cosh(a: f64) -> f64; + musl_coshf: coshf(a: f32) -> f32; + musl_drem: drem(a: f64, b: f64) -> f64; + musl_dremf: dremf(a: f32, b: f32) -> f32; + musl_erf: erf(a: f64) -> f64; + musl_erfc: erfc(a: f64) -> f64; + musl_erfcf: erfcf(a: f32) -> f32; + musl_erff: erff(a: f32) -> f32; + musl_exp10: exp10(a: f64) -> f64; + musl_exp10f: exp10f(a: f32) -> f32; + musl_exp2: exp2(a: f64) -> f64; + musl_exp2f: exp2f(a: f32) -> f32; + musl_exp: exp(a: f64) -> f64; + musl_expf: expf(a: f32) -> f32; + musl_expm1: expm1(a: f64) -> f64; + musl_expm1f: expm1f(a: f32) -> f32; + musl_fabs: fabs(a: f64) -> f64; + musl_fabsf: fabsf(a: f32) -> f32; + musl_fdim: fdim(a: f64, b: f64) -> f64; + musl_fdimf: fdimf(a: f32, b: f32) -> f32; + musl_finite: finite(a: f64) -> c_int; + musl_finitef: finitef(a: f32) -> c_int; + musl_floor: floor(a: f64) -> f64; + musl_floorf: floorf(a: f32) -> f32; + musl_fma: fma(a: f64, b: f64, c: f64) -> f64; + musl_fmaf: fmaf(a: f32, b: f32, c: f32) -> f32; + musl_fmax: fmax(a: f64, b: f64) -> f64; + musl_fmaxf: fmaxf(a: f32, b: f32) -> f32; + musl_fmin: fmin(a: f64, b: f64) -> f64; + musl_fminf: fminf(a: f32, b: f32) -> f32; + musl_fmod: fmod(a: f64, b: f64) -> f64; + musl_fmodf: fmodf(a: f32, b: f32) -> f32; + musl_frexp: frexp(a: f64, b: &mut c_int) -> f64; + musl_frexpf: frexpf(a: f32, b: &mut c_int) -> f32; + musl_hypot: hypot(a: f64, b: f64) -> f64; + musl_hypotf: hypotf(a: f32, b: f32) -> f32; + musl_ilogb: ilogb(a: f64) -> c_int; + musl_ilogbf: ilogbf(a: f32) -> c_int; + musl_j0: j0(a: f64) -> f64; + musl_j0f: j0f(a: f32) -> f32; + musl_j1: j1(a: f64) -> f64; + musl_j1f: j1f(a: f32) -> f32; + musl_jn: jn(a: c_int, b: f64) -> f64; + musl_jnf: jnf(a: c_int, b: f32) -> f32; + musl_ldexp: ldexp(a: f64, b: c_int) -> f64; + musl_ldexpf: ldexpf(a: f32, b: c_int) -> f32; + musl_lgamma: lgamma(a: f64) -> f64; + musl_lgamma_r: lgamma_r(a: f64, b: &mut c_int) -> f64; + musl_lgammaf: lgammaf(a: f32) -> f32; + musl_lgammaf_r: lgammaf_r(a: f32, b: &mut c_int) -> f32; + musl_log10: log10(a: f64) -> f64; + musl_log10f: log10f(a: f32) -> f32; + musl_log1p: log1p(a: f64) -> f64; + musl_log1pf: log1pf(a: f32) -> f32; + musl_log2: log2(a: f64) -> f64; + musl_log2f: log2f(a: f32) -> f32; + musl_log: log(a: f64) -> f64; + musl_logb: logb(a: f64) -> f64; + musl_logbf: logbf(a: f32) -> f32; + musl_logf: logf(a: f32) -> f32; + musl_modf: modf(a: f64, b: &mut f64) -> f64; + musl_modff: modff(a: f32, b: &mut f32) -> f32; + + // FIXME: these need to be unsafe + #[allow(clippy::not_unsafe_ptr_arg_deref)] + musl_nan: nan(a: *const c_char) -> f64; + #[allow(clippy::not_unsafe_ptr_arg_deref)] + musl_nanf: nanf(a: *const c_char) -> f32; + + musl_nearbyint: nearbyint(a: f64) -> f64; + musl_nearbyintf: nearbyintf(a: f32) -> f32; + musl_nextafter: nextafter(a: f64, b: f64) -> f64; + musl_nextafterf: nextafterf(a: f32, b: f32) -> f32; + musl_pow10: pow10(a: f64) -> f64; + musl_pow10f: pow10f(a: f32) -> f32; + musl_pow: pow(a: f64, b: f64) -> f64; + musl_powf: powf(a: f32, b: f32) -> f32; + musl_remainder: remainder(a: f64, b: f64) -> f64; + musl_remainderf: remainderf(a: f32, b: f32) -> f32; + musl_remquo: remquo(a: f64, b: f64, c: &mut c_int) -> f64; + musl_remquof: remquof(a: f32, b: f32, c: &mut c_int) -> f32; + musl_rint: rint(a: f64) -> f64; + musl_rintf: rintf(a: f32) -> f32; + musl_round: round(a: f64) -> f64; + musl_roundf: roundf(a: f32) -> f32; + musl_scalbln: scalbln(a: f64, b: c_long) -> f64; + musl_scalblnf: scalblnf(a: f32, b: c_long) -> f32; + musl_scalbn: scalbn(a: f64, b: c_int) -> f64; + musl_scalbnf: scalbnf(a: f32, b: c_int) -> f32; + musl_significand: significand(a: f64) -> f64; + musl_significandf: significandf(a: f32) -> f32; + musl_sin: sin(a: f64) -> f64; + musl_sincos: sincos(a: f64, b: &mut f64, c: &mut f64) -> (); + musl_sincosf: sincosf(a: f32, b: &mut f32, c: &mut f32) -> (); + musl_sinf: sinf(a: f32) -> f32; + musl_sinh: sinh(a: f64) -> f64; + musl_sinhf: sinhf(a: f32) -> f32; + musl_sqrt: sqrt(a: f64) -> f64; + musl_sqrtf: sqrtf(a: f32) -> f32; + musl_tan: tan(a: f64) -> f64; + musl_tanf: tanf(a: f32) -> f32; + musl_tanh: tanh(a: f64) -> f64; + musl_tanhf: tanhf(a: f32) -> f32; + musl_tgamma: tgamma(a: f64) -> f64; + musl_tgammaf: tgammaf(a: f32) -> f32; + musl_trunc: trunc(a: f64) -> f64; + musl_truncf: truncf(a: f32) -> f32; + musl_y0: y0(a: f64) -> f64; + musl_y0f: y0f(a: f32) -> f32; + musl_y1: y1(a: f64) -> f64; + musl_y1f: y1f(a: f32) -> f32; + musl_yn: yn(a: c_int, b: f64) -> f64; + musl_ynf: ynf(a: c_int, b: f32) -> f32; +} diff --git a/library/compiler-builtins/crates/util/Cargo.toml b/library/compiler-builtins/crates/util/Cargo.toml new file mode 100644 index 00000000000..4bcb9747297 --- /dev/null +++ b/library/compiler-builtins/crates/util/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "util" +version = "0.1.0" +edition = "2024" +publish = false + +[features] +default = ["build-musl", "build-mpfr", "unstable-float"] +build-musl = ["libm-test/build-musl", "dep:musl-math-sys"] +build-mpfr = ["libm-test/build-mpfr", "dep:rug"] +unstable-float = ["libm/unstable-float", "libm-test/unstable-float", "rug?/nightly-float"] + +[dependencies] +libm = { path = "../../libm", default-features = false } +libm-macros = { path = "../libm-macros" } +libm-test = { path = "../libm-test", default-features = false } +musl-math-sys = { path = "../musl-math-sys", optional = true } +rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "std"] } diff --git a/library/compiler-builtins/crates/util/build.rs b/library/compiler-builtins/crates/util/build.rs new file mode 100644 index 00000000000..a1be4127527 --- /dev/null +++ b/library/compiler-builtins/crates/util/build.rs @@ -0,0 +1,10 @@ +#![allow(unexpected_cfgs)] + +#[path = "../../libm/configure.rs"] +mod configure; + +fn main() { + println!("cargo:rerun-if-changed=../../libm/configure.rs"); + let cfg = configure::Config::from_env(); + configure::emit_libm_config(&cfg); +} diff --git a/library/compiler-builtins/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs new file mode 100644 index 00000000000..ef70ec9035b --- /dev/null +++ b/library/compiler-builtins/crates/util/src/main.rs @@ -0,0 +1,382 @@ +//! Helper CLI utility for common tasks. + +#![cfg_attr(f16_enabled, feature(f16))] +#![cfg_attr(f128_enabled, feature(f128))] + +use std::any::type_name; +use std::env; +use std::num::ParseIntError; +use std::str::FromStr; + +use libm::support::{Hexf, hf32, hf64}; +#[cfg(feature = "build-mpfr")] +use libm_test::mpfloat::MpOp; +use libm_test::{MathOp, TupleCall}; +#[cfg(feature = "build-mpfr")] +use rug::az::{self, Az}; + +const USAGE: &str = "\ +usage: + +cargo run -p util -- + +SUBCOMMAND: + eval inputs... + Evaulate the expression with a given basis. This can be useful for + running routines with a debugger, or quickly checking input. Examples: + * eval musl sinf 1.234 # print the results of musl sinf(1.234f32) + * eval mpfr pow 1.234 2.432 # print the results of mpfr pow(1.234, 2.432) +"; + +fn main() { + let args = env::args().collect::>(); + let str_args = args.iter().map(|s| s.as_str()).collect::>(); + + match &str_args.as_slice()[1..] { + ["eval", basis, op, inputs @ ..] => do_eval(basis, op, inputs), + _ => { + println!("{USAGE}\nunrecognized input `{str_args:?}`"); + std::process::exit(1); + } + } +} + +macro_rules! handle_call { + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + attrs: [$($attr:meta),*], + extra: ($basis:ident, $op:ident, $inputs:ident), + fn_extra: $musl_fn:expr, + ) => { + $(#[$attr])* + if $op == stringify!($fn_name) { + type Op = libm_test::op::$fn_name::Routine; + + let input = <$RustArgs>::parse($inputs); + let libm_fn: ::RustFn = libm::$fn_name; + + let output = match $basis { + "libm" => input.call_intercept_panics(libm_fn), + #[cfg(feature = "build-musl")] + "musl" => { + let musl_fn: ::CFn = + $musl_fn.unwrap_or_else(|| panic!("no musl function for {}", $op)); + input.call(musl_fn) + } + #[cfg(feature = "build-mpfr")] + "mpfr" => { + let mut mp = ::new_mp(); + Op::run(&mut mp, input) + } + _ => panic!("unrecognized or disabled basis '{}'", $basis), + }; + println!("{output:?} {:x}", Hexf(output)); + return; + } + }; +} + +/// Evaluate the specified operation with a given basis. +fn do_eval(basis: &str, op: &str, inputs: &[&str]) { + libm_macros::for_each_function! { + callback: handle_call, + emit_types: [CFn, RustFn, RustArgs], + extra: (basis, op, inputs), + fn_extra: match MACRO_FN_NAME { + ceilf128 + | ceilf16 + | copysignf128 + | copysignf16 + | fabsf128 + | fabsf16 + | fdimf128 + | fdimf16 + | floorf128 + | floorf16 + | fmaf128 + | fmaxf128 + | fmaxf16 + | fmaximum + | fmaximum_num + | fmaximum_numf + | fmaximum_numf128 + | fmaximum_numf16 + | fmaximumf + | fmaximumf128 + | fmaximumf16 + | fminf128 + | fminf16 + | fminimum + | fminimum_num + | fminimum_numf + | fminimum_numf128 + | fminimum_numf16 + | fminimumf + | fminimumf128 + | fminimumf16 + | fmodf128 + | fmodf16 + | ldexpf128 + | ldexpf16 + | rintf128 + | rintf16 + | roundeven + | roundevenf + | roundevenf128 + | roundevenf16 + | roundf128 + | roundf16 + | scalbnf128 + | scalbnf16 + | sqrtf128 + | sqrtf16 + | truncf128 + | truncf16 => None, + _ => Some(musl_math_sys::MACRO_FN_NAME) + } + } + + panic!("no operation matching {op}"); +} + +/// Parse a tuple from a space-delimited string. +trait ParseTuple { + fn parse(input: &[&str]) -> Self; +} + +macro_rules! impl_parse_tuple { + ($ty:ty) => { + impl ParseTuple for ($ty,) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 1, "expected a single argument, got {input:?}"); + (parse(input, 0),) + } + } + + impl ParseTuple for ($ty, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse(input, 0), parse(input, 1)) + } + } + + impl ParseTuple for ($ty, i32) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse(input, 0), parse(input, 1)) + } + } + + impl ParseTuple for (i32, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse(input, 0), parse(input, 1)) + } + } + + impl ParseTuple for ($ty, $ty, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 3, "expected three arguments, got {input:?}"); + (parse(input, 0), parse(input, 1), parse(input, 2)) + } + } + }; +} + +#[allow(unused_macros)] +#[cfg(feature = "build-mpfr")] +macro_rules! impl_parse_tuple_via_rug { + ($ty:ty) => { + impl ParseTuple for ($ty,) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 1, "expected a single argument, got {input:?}"); + (parse_rug(input, 0),) + } + } + + impl ParseTuple for ($ty, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse_rug(input, 0), parse_rug(input, 1)) + } + } + + impl ParseTuple for ($ty, i32) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse_rug(input, 0), parse(input, 1)) + } + } + + impl ParseTuple for (i32, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse(input, 0), parse_rug(input, 1)) + } + } + + impl ParseTuple for ($ty, $ty, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 3, "expected three arguments, got {input:?}"); + (parse_rug(input, 0), parse_rug(input, 1), parse_rug(input, 2)) + } + } + }; +} + +// Fallback for when Rug is not built. +#[allow(unused_macros)] +#[cfg(not(feature = "build-mpfr"))] +macro_rules! impl_parse_tuple_via_rug { + ($ty:ty) => { + impl ParseTuple for ($ty,) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + + impl ParseTuple for ($ty, $ty) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + + impl ParseTuple for ($ty, i32) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + + impl ParseTuple for (i32, $ty) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + + impl ParseTuple for ($ty, $ty, $ty) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + }; +} + +impl_parse_tuple!(f32); +impl_parse_tuple!(f64); + +#[cfg(f16_enabled)] +impl_parse_tuple_via_rug!(f16); +#[cfg(f128_enabled)] +impl_parse_tuple_via_rug!(f128); + +/// Try to parse the number, printing a nice message on failure. +fn parse(input: &[&str], idx: usize) -> T { + let s = input[idx]; + + let msg = || format!("invalid {} input '{s}'", type_name::()); + + if s.starts_with("0x") || s.starts_with("-0x") { + return T::from_str_radix(s, 16).unwrap_or_else(|_| panic!("{}", msg())); + } + + if s.starts_with("0b") { + return T::from_str_radix(s, 2).unwrap_or_else(|_| panic!("{}", msg())); + } + + s.parse().unwrap_or_else(|_| panic!("{}", msg())) +} + +/// Try to parse the float type going via `rug`, for `f16` and `f128` which don't yet implement +/// `FromStr`. +#[cfg(feature = "build-mpfr")] +fn parse_rug(input: &[&str], idx: usize) -> F +where + F: libm_test::Float + FromStrRadix, + rug::Float: az::Cast, +{ + let s = input[idx]; + + let msg = || format!("invalid {} input '{s}'", type_name::()); + + if s.starts_with("0x") { + return F::from_str_radix(s, 16).unwrap_or_else(|_| panic!("{}", msg())); + } + + if s.starts_with("0b") { + return F::from_str_radix(s, 2).unwrap_or_else(|_| panic!("{}", msg())); + } + + let x = rug::Float::parse(s).unwrap_or_else(|_| panic!("{}", msg())); + let x = rug::Float::with_val(F::BITS, x); + x.az() +} + +trait FromStrRadix: Sized { + fn from_str_radix(s: &str, radix: u32) -> Result; +} + +impl FromStrRadix for i32 { + fn from_str_radix(s: &str, radix: u32) -> Result { + let s = strip_radix_prefix(s, radix); + i32::from_str_radix(s, radix) + } +} + +#[cfg(f16_enabled)] +impl FromStrRadix for f16 { + fn from_str_radix(s: &str, radix: u32) -> Result { + if radix == 16 && s.contains("p") { + return Ok(libm::support::hf16(s)); + } + + let s = strip_radix_prefix(s, radix); + u16::from_str_radix(s, radix).map(Self::from_bits) + } +} + +impl FromStrRadix for f32 { + fn from_str_radix(s: &str, radix: u32) -> Result { + if radix == 16 && s.contains("p") { + // Parse as hex float + return Ok(hf32(s)); + } + + let s = strip_radix_prefix(s, radix); + u32::from_str_radix(s, radix).map(Self::from_bits) + } +} + +impl FromStrRadix for f64 { + fn from_str_radix(s: &str, radix: u32) -> Result { + if s.contains("p") { + return Ok(hf64(s)); + } + + let s = strip_radix_prefix(s, radix); + u64::from_str_radix(s, radix).map(Self::from_bits) + } +} + +#[cfg(f128_enabled)] +impl FromStrRadix for f128 { + fn from_str_radix(s: &str, radix: u32) -> Result { + if radix == 16 && s.contains("p") { + return Ok(libm::support::hf128(s)); + } + let s = strip_radix_prefix(s, radix); + u128::from_str_radix(s, radix).map(Self::from_bits) + } +} + +fn strip_radix_prefix(s: &str, radix: u32) -> &str { + if radix == 16 { + s.strip_prefix("0x").unwrap() + } else if radix == 2 { + s.strip_prefix("0b").unwrap() + } else { + s + } +} diff --git a/library/compiler-builtins/etc/function-definitions.json b/library/compiler-builtins/etc/function-definitions.json new file mode 100644 index 00000000000..3e33343c464 --- /dev/null +++ b/library/compiler-builtins/etc/function-definitions.json @@ -0,0 +1,1069 @@ +{ + "__comment": "Autogenerated by update-api-list.py. List of files that define a function with a given name. This file is checked in to make it obvious if refactoring breaks things", + "acos": { + "sources": [ + "libm/src/math/acos.rs" + ], + "type": "f64" + }, + "acosf": { + "sources": [ + "libm/src/math/acosf.rs" + ], + "type": "f32" + }, + "acosh": { + "sources": [ + "libm/src/math/acosh.rs" + ], + "type": "f64" + }, + "acoshf": { + "sources": [ + "libm/src/math/acoshf.rs" + ], + "type": "f32" + }, + "asin": { + "sources": [ + "libm/src/math/asin.rs" + ], + "type": "f64" + }, + "asinf": { + "sources": [ + "libm/src/math/asinf.rs" + ], + "type": "f32" + }, + "asinh": { + "sources": [ + "libm/src/math/asinh.rs" + ], + "type": "f64" + }, + "asinhf": { + "sources": [ + "libm/src/math/asinhf.rs" + ], + "type": "f32" + }, + "atan": { + "sources": [ + "libm/src/math/atan.rs" + ], + "type": "f64" + }, + "atan2": { + "sources": [ + "libm/src/math/atan2.rs" + ], + "type": "f64" + }, + "atan2f": { + "sources": [ + "libm/src/math/atan2f.rs" + ], + "type": "f32" + }, + "atanf": { + "sources": [ + "libm/src/math/atanf.rs" + ], + "type": "f32" + }, + "atanh": { + "sources": [ + "libm/src/math/atanh.rs" + ], + "type": "f64" + }, + "atanhf": { + "sources": [ + "libm/src/math/atanhf.rs" + ], + "type": "f32" + }, + "cbrt": { + "sources": [ + "libm/src/math/cbrt.rs" + ], + "type": "f64" + }, + "cbrtf": { + "sources": [ + "libm/src/math/cbrtf.rs" + ], + "type": "f32" + }, + "ceil": { + "sources": [ + "libm/src/math/arch/i586.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/ceil.rs", + "libm/src/math/generic/ceil.rs" + ], + "type": "f64" + }, + "ceilf": { + "sources": [ + "libm/src/math/arch/wasm32.rs", + "libm/src/math/ceil.rs", + "libm/src/math/generic/ceil.rs" + ], + "type": "f32" + }, + "ceilf128": { + "sources": [ + "libm/src/math/ceil.rs", + "libm/src/math/generic/ceil.rs" + ], + "type": "f128" + }, + "ceilf16": { + "sources": [ + "libm/src/math/ceil.rs", + "libm/src/math/generic/ceil.rs" + ], + "type": "f16" + }, + "copysign": { + "sources": [ + "libm/src/math/copysign.rs", + "libm/src/math/generic/copysign.rs" + ], + "type": "f64" + }, + "copysignf": { + "sources": [ + "libm/src/math/copysign.rs", + "libm/src/math/generic/copysign.rs" + ], + "type": "f32" + }, + "copysignf128": { + "sources": [ + "libm/src/math/copysign.rs", + "libm/src/math/generic/copysign.rs" + ], + "type": "f128" + }, + "copysignf16": { + "sources": [ + "libm/src/math/copysign.rs", + "libm/src/math/generic/copysign.rs" + ], + "type": "f16" + }, + "cos": { + "sources": [ + "libm/src/math/cos.rs" + ], + "type": "f64" + }, + "cosf": { + "sources": [ + "libm/src/math/cosf.rs" + ], + "type": "f32" + }, + "cosh": { + "sources": [ + "libm/src/math/cosh.rs" + ], + "type": "f64" + }, + "coshf": { + "sources": [ + "libm/src/math/coshf.rs" + ], + "type": "f32" + }, + "erf": { + "sources": [ + "libm/src/math/erf.rs" + ], + "type": "f64" + }, + "erfc": { + "sources": [ + "libm/src/math/erf.rs" + ], + "type": "f64" + }, + "erfcf": { + "sources": [ + "libm/src/math/erff.rs" + ], + "type": "f32" + }, + "erff": { + "sources": [ + "libm/src/math/erff.rs" + ], + "type": "f32" + }, + "exp": { + "sources": [ + "libm/src/math/exp.rs" + ], + "type": "f64" + }, + "exp10": { + "sources": [ + "libm/src/math/exp10.rs" + ], + "type": "f64" + }, + "exp10f": { + "sources": [ + "libm/src/math/exp10f.rs" + ], + "type": "f32" + }, + "exp2": { + "sources": [ + "libm/src/math/exp2.rs" + ], + "type": "f64" + }, + "exp2f": { + "sources": [ + "libm/src/math/exp2f.rs" + ], + "type": "f32" + }, + "expf": { + "sources": [ + "libm/src/math/expf.rs" + ], + "type": "f32" + }, + "expm1": { + "sources": [ + "libm/src/math/expm1.rs" + ], + "type": "f64" + }, + "expm1f": { + "sources": [ + "libm/src/math/expm1f.rs" + ], + "type": "f32" + }, + "fabs": { + "sources": [ + "libm/src/math/arch/wasm32.rs", + "libm/src/math/fabs.rs", + "libm/src/math/generic/fabs.rs" + ], + "type": "f64" + }, + "fabsf": { + "sources": [ + "libm/src/math/arch/wasm32.rs", + "libm/src/math/fabs.rs", + "libm/src/math/generic/fabs.rs" + ], + "type": "f32" + }, + "fabsf128": { + "sources": [ + "libm/src/math/fabs.rs", + "libm/src/math/generic/fabs.rs" + ], + "type": "f128" + }, + "fabsf16": { + "sources": [ + "libm/src/math/fabs.rs", + "libm/src/math/generic/fabs.rs" + ], + "type": "f16" + }, + "fdim": { + "sources": [ + "libm/src/math/fdim.rs", + "libm/src/math/generic/fdim.rs" + ], + "type": "f64" + }, + "fdimf": { + "sources": [ + "libm/src/math/fdim.rs", + "libm/src/math/generic/fdim.rs" + ], + "type": "f32" + }, + "fdimf128": { + "sources": [ + "libm/src/math/fdim.rs", + "libm/src/math/generic/fdim.rs" + ], + "type": "f128" + }, + "fdimf16": { + "sources": [ + "libm/src/math/fdim.rs", + "libm/src/math/generic/fdim.rs" + ], + "type": "f16" + }, + "floor": { + "sources": [ + "libm/src/math/arch/i586.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/floor.rs", + "libm/src/math/generic/floor.rs" + ], + "type": "f64" + }, + "floorf": { + "sources": [ + "libm/src/math/arch/wasm32.rs", + "libm/src/math/floor.rs", + "libm/src/math/generic/floor.rs" + ], + "type": "f32" + }, + "floorf128": { + "sources": [ + "libm/src/math/floor.rs", + "libm/src/math/generic/floor.rs" + ], + "type": "f128" + }, + "floorf16": { + "sources": [ + "libm/src/math/floor.rs", + "libm/src/math/generic/floor.rs" + ], + "type": "f16" + }, + "fma": { + "sources": [ + "libm/src/math/arch/aarch64.rs", + "libm/src/math/fma.rs" + ], + "type": "f64" + }, + "fmaf": { + "sources": [ + "libm/src/math/arch/aarch64.rs", + "libm/src/math/fma_wide.rs" + ], + "type": "f32" + }, + "fmaf128": { + "sources": [ + "libm/src/math/fma.rs" + ], + "type": "f128" + }, + "fmax": { + "sources": [ + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmax.rs" + ], + "type": "f64" + }, + "fmaxf": { + "sources": [ + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmax.rs" + ], + "type": "f32" + }, + "fmaxf128": { + "sources": [ + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmax.rs" + ], + "type": "f128" + }, + "fmaxf16": { + "sources": [ + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmax.rs" + ], + "type": "f16" + }, + "fmaximum": { + "sources": [ + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fmaximum.rs" + ], + "type": "f64" + }, + "fmaximum_num": { + "sources": [ + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fmaximum_num.rs" + ], + "type": "f64" + }, + "fmaximum_numf": { + "sources": [ + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fmaximum_num.rs" + ], + "type": "f32" + }, + "fmaximum_numf128": { + "sources": [ + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fmaximum_num.rs" + ], + "type": "f128" + }, + "fmaximum_numf16": { + "sources": [ + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fmaximum_num.rs" + ], + "type": "f16" + }, + "fmaximumf": { + "sources": [ + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fmaximum.rs" + ], + "type": "f32" + }, + "fmaximumf128": { + "sources": [ + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fmaximum.rs" + ], + "type": "f128" + }, + "fmaximumf16": { + "sources": [ + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fmaximum.rs" + ], + "type": "f16" + }, + "fmin": { + "sources": [ + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmin.rs" + ], + "type": "f64" + }, + "fminf": { + "sources": [ + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmin.rs" + ], + "type": "f32" + }, + "fminf128": { + "sources": [ + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmin.rs" + ], + "type": "f128" + }, + "fminf16": { + "sources": [ + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmin.rs" + ], + "type": "f16" + }, + "fminimum": { + "sources": [ + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fminimum.rs" + ], + "type": "f64" + }, + "fminimum_num": { + "sources": [ + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fminimum_num.rs" + ], + "type": "f64" + }, + "fminimum_numf": { + "sources": [ + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fminimum_num.rs" + ], + "type": "f32" + }, + "fminimum_numf128": { + "sources": [ + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fminimum_num.rs" + ], + "type": "f128" + }, + "fminimum_numf16": { + "sources": [ + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fminimum_num.rs" + ], + "type": "f16" + }, + "fminimumf": { + "sources": [ + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fminimum.rs" + ], + "type": "f32" + }, + "fminimumf128": { + "sources": [ + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fminimum.rs" + ], + "type": "f128" + }, + "fminimumf16": { + "sources": [ + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fminimum.rs" + ], + "type": "f16" + }, + "fmod": { + "sources": [ + "libm/src/math/fmod.rs", + "libm/src/math/generic/fmod.rs" + ], + "type": "f64" + }, + "fmodf": { + "sources": [ + "libm/src/math/fmod.rs", + "libm/src/math/generic/fmod.rs" + ], + "type": "f32" + }, + "fmodf128": { + "sources": [ + "libm/src/math/fmod.rs", + "libm/src/math/generic/fmod.rs" + ], + "type": "f128" + }, + "fmodf16": { + "sources": [ + "libm/src/math/fmod.rs", + "libm/src/math/generic/fmod.rs" + ], + "type": "f16" + }, + "frexp": { + "sources": [ + "libm/src/math/frexp.rs" + ], + "type": "f64" + }, + "frexpf": { + "sources": [ + "libm/src/math/frexpf.rs" + ], + "type": "f32" + }, + "hypot": { + "sources": [ + "libm/src/math/hypot.rs" + ], + "type": "f64" + }, + "hypotf": { + "sources": [ + "libm/src/math/hypotf.rs" + ], + "type": "f32" + }, + "ilogb": { + "sources": [ + "libm/src/math/ilogb.rs" + ], + "type": "f64" + }, + "ilogbf": { + "sources": [ + "libm/src/math/ilogbf.rs" + ], + "type": "f32" + }, + "j0": { + "sources": [ + "libm/src/math/j0.rs" + ], + "type": "f64" + }, + "j0f": { + "sources": [ + "libm/src/math/j0f.rs" + ], + "type": "f32" + }, + "j1": { + "sources": [ + "libm/src/math/j1.rs" + ], + "type": "f64" + }, + "j1f": { + "sources": [ + "libm/src/math/j1f.rs" + ], + "type": "f32" + }, + "jn": { + "sources": [ + "libm/src/math/jn.rs" + ], + "type": "f64" + }, + "jnf": { + "sources": [ + "libm/src/math/jnf.rs" + ], + "type": "f32" + }, + "ldexp": { + "sources": [ + "libm/src/math/ldexp.rs" + ], + "type": "f64" + }, + "ldexpf": { + "sources": [ + "libm/src/math/ldexp.rs" + ], + "type": "f32" + }, + "ldexpf128": { + "sources": [ + "libm/src/math/ldexp.rs" + ], + "type": "f128" + }, + "ldexpf16": { + "sources": [ + "libm/src/math/ldexp.rs" + ], + "type": "f16" + }, + "lgamma": { + "sources": [ + "libm/src/math/lgamma.rs" + ], + "type": "f64" + }, + "lgamma_r": { + "sources": [ + "libm/src/math/lgamma_r.rs" + ], + "type": "f64" + }, + "lgammaf": { + "sources": [ + "libm/src/math/lgammaf.rs" + ], + "type": "f32" + }, + "lgammaf_r": { + "sources": [ + "libm/src/math/lgammaf_r.rs" + ], + "type": "f32" + }, + "log": { + "sources": [ + "libm/src/math/log.rs" + ], + "type": "f64" + }, + "log10": { + "sources": [ + "libm/src/math/log10.rs" + ], + "type": "f64" + }, + "log10f": { + "sources": [ + "libm/src/math/log10f.rs" + ], + "type": "f32" + }, + "log1p": { + "sources": [ + "libm/src/math/log1p.rs" + ], + "type": "f64" + }, + "log1pf": { + "sources": [ + "libm/src/math/log1pf.rs" + ], + "type": "f32" + }, + "log2": { + "sources": [ + "libm/src/math/log2.rs" + ], + "type": "f64" + }, + "log2f": { + "sources": [ + "libm/src/math/log2f.rs" + ], + "type": "f32" + }, + "logf": { + "sources": [ + "libm/src/math/logf.rs" + ], + "type": "f32" + }, + "modf": { + "sources": [ + "libm/src/math/modf.rs" + ], + "type": "f64" + }, + "modff": { + "sources": [ + "libm/src/math/modff.rs" + ], + "type": "f32" + }, + "nextafter": { + "sources": [ + "libm/src/math/nextafter.rs" + ], + "type": "f64" + }, + "nextafterf": { + "sources": [ + "libm/src/math/nextafterf.rs" + ], + "type": "f32" + }, + "pow": { + "sources": [ + "libm/src/math/pow.rs" + ], + "type": "f64" + }, + "powf": { + "sources": [ + "libm/src/math/powf.rs" + ], + "type": "f32" + }, + "remainder": { + "sources": [ + "libm/src/math/remainder.rs" + ], + "type": "f64" + }, + "remainderf": { + "sources": [ + "libm/src/math/remainderf.rs" + ], + "type": "f32" + }, + "remquo": { + "sources": [ + "libm/src/math/remquo.rs" + ], + "type": "f64" + }, + "remquof": { + "sources": [ + "libm/src/math/remquof.rs" + ], + "type": "f32" + }, + "rint": { + "sources": [ + "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/rint.rs" + ], + "type": "f64" + }, + "rintf": { + "sources": [ + "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/rint.rs" + ], + "type": "f32" + }, + "rintf128": { + "sources": [ + "libm/src/math/rint.rs" + ], + "type": "f128" + }, + "rintf16": { + "sources": [ + "libm/src/math/arch/aarch64.rs", + "libm/src/math/rint.rs" + ], + "type": "f16" + }, + "round": { + "sources": [ + "libm/src/math/generic/round.rs", + "libm/src/math/round.rs" + ], + "type": "f64" + }, + "roundeven": { + "sources": [ + "libm/src/math/roundeven.rs" + ], + "type": "f64" + }, + "roundevenf": { + "sources": [ + "libm/src/math/roundeven.rs" + ], + "type": "f32" + }, + "roundevenf128": { + "sources": [ + "libm/src/math/roundeven.rs" + ], + "type": "f128" + }, + "roundevenf16": { + "sources": [ + "libm/src/math/roundeven.rs" + ], + "type": "f16" + }, + "roundf": { + "sources": [ + "libm/src/math/generic/round.rs", + "libm/src/math/round.rs" + ], + "type": "f32" + }, + "roundf128": { + "sources": [ + "libm/src/math/generic/round.rs", + "libm/src/math/round.rs" + ], + "type": "f128" + }, + "roundf16": { + "sources": [ + "libm/src/math/generic/round.rs", + "libm/src/math/round.rs" + ], + "type": "f16" + }, + "scalbn": { + "sources": [ + "libm/src/math/generic/scalbn.rs", + "libm/src/math/scalbn.rs" + ], + "type": "f64" + }, + "scalbnf": { + "sources": [ + "libm/src/math/generic/scalbn.rs", + "libm/src/math/scalbn.rs" + ], + "type": "f32" + }, + "scalbnf128": { + "sources": [ + "libm/src/math/generic/scalbn.rs", + "libm/src/math/scalbn.rs" + ], + "type": "f128" + }, + "scalbnf16": { + "sources": [ + "libm/src/math/generic/scalbn.rs", + "libm/src/math/scalbn.rs" + ], + "type": "f16" + }, + "sin": { + "sources": [ + "libm/src/math/sin.rs" + ], + "type": "f64" + }, + "sincos": { + "sources": [ + "libm/src/math/sincos.rs" + ], + "type": "f64" + }, + "sincosf": { + "sources": [ + "libm/src/math/sincosf.rs" + ], + "type": "f32" + }, + "sinf": { + "sources": [ + "libm/src/math/sinf.rs" + ], + "type": "f32" + }, + "sinh": { + "sources": [ + "libm/src/math/sinh.rs" + ], + "type": "f64" + }, + "sinhf": { + "sources": [ + "libm/src/math/sinhf.rs" + ], + "type": "f32" + }, + "sqrt": { + "sources": [ + "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/i686.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/generic/sqrt.rs", + "libm/src/math/sqrt.rs" + ], + "type": "f64" + }, + "sqrtf": { + "sources": [ + "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/i686.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/generic/sqrt.rs", + "libm/src/math/sqrt.rs" + ], + "type": "f32" + }, + "sqrtf128": { + "sources": [ + "libm/src/math/generic/sqrt.rs", + "libm/src/math/sqrt.rs" + ], + "type": "f128" + }, + "sqrtf16": { + "sources": [ + "libm/src/math/arch/aarch64.rs", + "libm/src/math/generic/sqrt.rs", + "libm/src/math/sqrt.rs" + ], + "type": "f16" + }, + "tan": { + "sources": [ + "libm/src/math/tan.rs" + ], + "type": "f64" + }, + "tanf": { + "sources": [ + "libm/src/math/tanf.rs" + ], + "type": "f32" + }, + "tanh": { + "sources": [ + "libm/src/math/tanh.rs" + ], + "type": "f64" + }, + "tanhf": { + "sources": [ + "libm/src/math/tanhf.rs" + ], + "type": "f32" + }, + "tgamma": { + "sources": [ + "libm/src/math/tgamma.rs" + ], + "type": "f64" + }, + "tgammaf": { + "sources": [ + "libm/src/math/tgammaf.rs" + ], + "type": "f32" + }, + "trunc": { + "sources": [ + "libm/src/math/arch/wasm32.rs", + "libm/src/math/generic/trunc.rs", + "libm/src/math/trunc.rs" + ], + "type": "f64" + }, + "truncf": { + "sources": [ + "libm/src/math/arch/wasm32.rs", + "libm/src/math/generic/trunc.rs", + "libm/src/math/trunc.rs" + ], + "type": "f32" + }, + "truncf128": { + "sources": [ + "libm/src/math/generic/trunc.rs", + "libm/src/math/trunc.rs" + ], + "type": "f128" + }, + "truncf16": { + "sources": [ + "libm/src/math/generic/trunc.rs", + "libm/src/math/trunc.rs" + ], + "type": "f16" + }, + "y0": { + "sources": [ + "libm/src/math/j0.rs" + ], + "type": "f64" + }, + "y0f": { + "sources": [ + "libm/src/math/j0f.rs" + ], + "type": "f32" + }, + "y1": { + "sources": [ + "libm/src/math/j1.rs" + ], + "type": "f64" + }, + "y1f": { + "sources": [ + "libm/src/math/j1f.rs" + ], + "type": "f32" + }, + "yn": { + "sources": [ + "libm/src/math/jn.rs" + ], + "type": "f64" + }, + "ynf": { + "sources": [ + "libm/src/math/jnf.rs" + ], + "type": "f32" + } +} diff --git a/library/compiler-builtins/etc/function-list.txt b/library/compiler-builtins/etc/function-list.txt new file mode 100644 index 00000000000..1f226c8c0ff --- /dev/null +++ b/library/compiler-builtins/etc/function-list.txt @@ -0,0 +1,164 @@ +# autogenerated by update-api-list.py +acos +acosf +acosh +acoshf +asin +asinf +asinh +asinhf +atan +atan2 +atan2f +atanf +atanh +atanhf +cbrt +cbrtf +ceil +ceilf +ceilf128 +ceilf16 +copysign +copysignf +copysignf128 +copysignf16 +cos +cosf +cosh +coshf +erf +erfc +erfcf +erff +exp +exp10 +exp10f +exp2 +exp2f +expf +expm1 +expm1f +fabs +fabsf +fabsf128 +fabsf16 +fdim +fdimf +fdimf128 +fdimf16 +floor +floorf +floorf128 +floorf16 +fma +fmaf +fmaf128 +fmax +fmaxf +fmaxf128 +fmaxf16 +fmaximum +fmaximum_num +fmaximum_numf +fmaximum_numf128 +fmaximum_numf16 +fmaximumf +fmaximumf128 +fmaximumf16 +fmin +fminf +fminf128 +fminf16 +fminimum +fminimum_num +fminimum_numf +fminimum_numf128 +fminimum_numf16 +fminimumf +fminimumf128 +fminimumf16 +fmod +fmodf +fmodf128 +fmodf16 +frexp +frexpf +hypot +hypotf +ilogb +ilogbf +j0 +j0f +j1 +j1f +jn +jnf +ldexp +ldexpf +ldexpf128 +ldexpf16 +lgamma +lgamma_r +lgammaf +lgammaf_r +log +log10 +log10f +log1p +log1pf +log2 +log2f +logf +modf +modff +nextafter +nextafterf +pow +powf +remainder +remainderf +remquo +remquof +rint +rintf +rintf128 +rintf16 +round +roundeven +roundevenf +roundevenf128 +roundevenf16 +roundf +roundf128 +roundf16 +scalbn +scalbnf +scalbnf128 +scalbnf16 +sin +sincos +sincosf +sinf +sinh +sinhf +sqrt +sqrtf +sqrtf128 +sqrtf16 +tan +tanf +tanh +tanhf +tgamma +tgammaf +trunc +truncf +truncf128 +truncf16 +y0 +y0f +y1 +y1f +yn +ynf diff --git a/library/compiler-builtins/etc/libm/.editorconfig b/library/compiler-builtins/etc/libm/.editorconfig new file mode 100644 index 00000000000..ec6e107d547 --- /dev/null +++ b/library/compiler-builtins/etc/libm/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 4 + +[*.md] +# double whitespace at end of line +# denotes a line break in Markdown +trim_trailing_whitespace = false + +[*.yml] +indent_size = 2 diff --git a/library/compiler-builtins/etc/libm/.github/workflows/main.yaml b/library/compiler-builtins/etc/libm/.github/workflows/main.yaml new file mode 100644 index 00000000000..5ce0dbc26c8 --- /dev/null +++ b/library/compiler-builtins/etc/libm/.github/workflows/main.yaml @@ -0,0 +1,324 @@ +name: CI +on: + push: + branches: + - master + pull_request: + +concurrency: + # Make sure that new pushes cancel running jobs + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + RUSTDOCFLAGS: -Dwarnings + RUSTFLAGS: -Dwarnings + RUST_BACKTRACE: full + BENCHMARK_RUSTC: nightly-2025-01-16 # Pin the toolchain for reproducable results + +jobs: + test: + name: Build and test + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - target: aarch64-apple-darwin + os: macos-15 + # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 + channel: nightly-2025-02-07 + - target: aarch64-unknown-linux-gnu + os: ubuntu-24.04-arm + # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 + channel: nightly-2025-02-07 + - target: aarch64-pc-windows-msvc + os: windows-2025 + build_only: 1 # Can't run on x86 hosts + - target: arm-unknown-linux-gnueabi + os: ubuntu-24.04 + - target: arm-unknown-linux-gnueabihf + os: ubuntu-24.04 + - target: armv7-unknown-linux-gnueabihf + os: ubuntu-24.04 + - target: i586-unknown-linux-gnu + os: ubuntu-24.04 + - target: i686-unknown-linux-gnu + os: ubuntu-24.04 + - target: loongarch64-unknown-linux-gnu + os: ubuntu-24.04 + - target: powerpc-unknown-linux-gnu + os: ubuntu-24.04 + - target: powerpc64-unknown-linux-gnu + os: ubuntu-24.04 + - target: powerpc64le-unknown-linux-gnu + os: ubuntu-24.04 + - target: riscv64gc-unknown-linux-gnu + os: ubuntu-24.04 + - target: thumbv6m-none-eabi + os: ubuntu-24.04 + - target: thumbv7em-none-eabi + os: ubuntu-24.04 + - target: thumbv7em-none-eabihf + os: ubuntu-24.04 + - target: thumbv7m-none-eabi + os: ubuntu-24.04 + - target: x86_64-unknown-linux-gnu + os: ubuntu-24.04 + - target: x86_64-apple-darwin + os: macos-13 + - target: wasm32-unknown-unknown + os: ubuntu-24.04 + build_only: 1 + - target: i686-pc-windows-msvc + os: windows-2025 + - target: x86_64-pc-windows-msvc + os: windows-2025 + - target: i686-pc-windows-gnu + os: windows-2025 + # FIXME: pinned due to https://github.com/rust-lang/rust/issues/136795 + channel: nightly-2025-02-07-i686-gnu + - target: x86_64-pc-windows-gnu + os: windows-2025 + channel: nightly-x86_64-gnu + runs-on: ${{ matrix.os }} + env: + BUILD_ONLY: ${{ matrix.build_only }} + steps: + - name: Print runner information + run: uname -a + - uses: actions/checkout@v4 + with: + submodules: true + - name: Install Rust (rustup) + shell: bash + run: | + channel="nightly" + # Account for channels that have required components (MinGW) + [ -n "${{ matrix.channel }}" ] && channel="${{ matrix.channel }}" + rustup update "$channel" --no-self-update + rustup default "$channel" + rustup target add "${{ matrix.target }}" + rustup component add clippy llvm-tools-preview + - uses: taiki-e/install-action@nextest + - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} + + - name: Verify API list + if: matrix.os == 'ubuntu-24.04' + run: python3 etc/update-api-list.py --check + + # Non-linux tests just use our raw script + - name: Run locally + if: matrix.os != 'ubuntu-24.04' || contains(matrix.target, 'wasm') + shell: bash + run: ./ci/run.sh ${{ matrix.target }} + + # Otherwise we use our docker containers to run builds + - name: Run in Docker + if: matrix.os == 'ubuntu-24.04' && !contains(matrix.target, 'wasm') + run: | + rustup target add x86_64-unknown-linux-musl + cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} + + - name: Print test logs if available + if: always() + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + + clippy: + name: Clippy + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@master + with: + submodules: true + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + rustup component add clippy + - uses: Swatinem/rust-cache@v2 + - run: cargo clippy --all --all-features --all-targets + + builtins: + name: Check use with compiler-builtins + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update nightly --no-self-update && rustup default nightly + - uses: Swatinem/rust-cache@v2 + - run: cargo check --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml + - run: cargo test --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml + + benchmarks: + name: Benchmarks + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - uses: actions/checkout@master + with: + submodules: true + - uses: taiki-e/install-action@cargo-binstall + + - name: Set up dependencies + run: | + sudo apt update + sudo apt install -y valgrind gdb libc6-dbg # Needed for iai-callgrind + rustup update "$BENCHMARK_RUSTC" --no-self-update + rustup default "$BENCHMARK_RUSTC" + # Install the version of iai-callgrind-runner that is specified in Cargo.toml + iai_version="$(cargo metadata --format-version=1 --features icount | + jq -r '.packages[] | select(.name == "iai-callgrind").version')" + cargo binstall -y iai-callgrind-runner --version "$iai_version" + sudo apt-get install valgrind + + - uses: Swatinem/rust-cache@v2 + + - name: Run icount benchmarks + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: ./ci/bench-icount.sh + + - name: Upload the benchmark baseline + uses: actions/upload-artifact@v4 + with: + name: ${{ env.BASELINE_NAME }} + path: ${{ env.BASELINE_NAME }}.tar.xz + + - name: Run wall time benchmarks + run: | + # Always use the same seed for benchmarks. Ideally we should switch to a + # non-random generator. + export LIBM_SEED=benchesbenchesbenchesbencheswoo! + cargo bench --all --features short-benchmarks,build-musl,force-soft-floats + + - name: Print test logs if available + if: always() + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + + msrv: + name: Check MSRV + runs-on: ubuntu-24.04 + timeout-minutes: 10 + env: + RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` + steps: + - uses: actions/checkout@master + - name: Install Rust + run: | + msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' libm/Cargo.toml)" + echo "MSRV: $msrv" + rustup update "$msrv" --no-self-update && rustup default "$msrv" + - uses: Swatinem/rust-cache@v2 + - run: | + # FIXME(msrv): Remove the workspace Cargo.toml so 1.63 cargo doesn't see + # `edition = "2024"` and get spooked. + rm Cargo.toml + cargo build --manifest-path libm/Cargo.toml + + rustfmt: + name: Rustfmt + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@master + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + rustup component add rustfmt + - run: cargo fmt -- --check + + # Determine which extensive tests should be run based on changed files. + calculate_extensive_matrix: + name: Calculate job matrix + runs-on: ubuntu-24.04 + timeout-minutes: 10 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + outputs: + matrix: ${{ steps.script.outputs.matrix }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 100 + - name: Fetch pull request ref + run: git fetch origin "$GITHUB_REF:$GITHUB_REF" + if: github.event_name == 'pull_request' + - run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT" + id: script + + extensive: + name: Extensive tests for ${{ matrix.ty }} + needs: + # Wait on `clippy` so we have some confidence that the crate will build + - clippy + - calculate_extensive_matrix + runs-on: ubuntu-24.04 + timeout-minutes: 240 # 4 hours + strategy: + matrix: + # Use the output from `calculate_extensive_matrix` to calculate the matrix + # FIXME: it would be better to run all jobs (i.e. all types) but mark those that + # didn't change as skipped, rather than completely excluding the job. However, + # this is not currently possible https://github.com/actions/runner/issues/1985. + include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }} + env: + TO_TEST: ${{ matrix.to_test }} + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + - uses: Swatinem/rust-cache@v2 + - name: Run extensive tests + run: | + echo "Tests to run: '$TO_TEST'" + if [ -z "$TO_TEST" ]; then + echo "No tests to run, exiting." + exit + fi + + set -x + + # Run the non-extensive tests first to catch any easy failures + cargo t --profile release-checked -- "$TO_TEST" + + LIBM_EXTENSIVE_TESTS="$TO_TEST" cargo t \ + --features build-mpfr,unstable,force-soft-floats \ + --profile release-checked \ + -- extensive + - name: Print test logs if available + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + + success: + needs: + - test + - builtins + - benchmarks + - msrv + - rustfmt + - extensive + runs-on: ubuntu-24.04 + timeout-minutes: 10 + # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency + # failed" as success. So we have to do some contortions to ensure the job fails if any of its + # dependencies fails. + if: always() # make sure this is never "skipped" + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: check if any dependency failed + run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/library/compiler-builtins/etc/libm/.github/workflows/publish.yaml b/library/compiler-builtins/etc/libm/.github/workflows/publish.yaml new file mode 100644 index 00000000000..15904079d27 --- /dev/null +++ b/library/compiler-builtins/etc/libm/.github/workflows/publish.yaml @@ -0,0 +1,27 @@ +name: Release-plz + +permissions: + pull-requests: write + contents: write + +on: + push: + branches: + - master + +jobs: + release-plz: + name: Release-plz + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install Rust (rustup) + run: rustup update nightly --no-self-update && rustup default nightly + - name: Run release-plz + uses: MarcoIeni/release-plz-action@v0.5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/library/compiler-builtins/etc/libm/.gitignore b/library/compiler-builtins/etc/libm/.gitignore new file mode 100644 index 00000000000..d5caba1a0f3 --- /dev/null +++ b/library/compiler-builtins/etc/libm/.gitignore @@ -0,0 +1,11 @@ +**.bk +.#* +/bin +/math/src +target +Cargo.lock +**.tar.gz + +# Benchmark cache +iai-home +baseline-* diff --git a/library/compiler-builtins/etc/libm/Cargo.toml b/library/compiler-builtins/etc/libm/Cargo.toml new file mode 100644 index 00000000000..268b6fb0e6d --- /dev/null +++ b/library/compiler-builtins/etc/libm/Cargo.toml @@ -0,0 +1,37 @@ +[workspace] +resolver = "2" +members = [ + "libm", + "crates/libm-macros", + "crates/libm-test", + "crates/musl-math-sys", + "crates/util", +] +default-members = [ + "libm", + "crates/libm-macros", + "crates/libm-test" +] +exclude = [ + # Requires `panic = abort` so can't be a member of the workspace + "crates/compiler-builtins-smoke-test", +] + +# The default release profile is unchanged. + +# Release mode with debug assertions +[profile.release-checked] +inherits = "release" +debug-assertions = true +overflow-checks = true + +# Release with maximum optimizations, which is very slow to build. This is also +# what is needed to check `no-panic`. +[profile.release-opt] +inherits = "release" +codegen-units = 1 +lto = "fat" + +[profile.bench] +# Required for iai-callgrind +debug = true diff --git a/library/compiler-builtins/etc/libm/ci/bench-icount.sh b/library/compiler-builtins/etc/libm/ci/bench-icount.sh new file mode 100755 index 00000000000..4d93e257a6c --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/bench-icount.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +set -eux + +iai_home="iai-home" + +# Download the baseline from master +./ci/ci-util.py locate-baseline --download --extract + +# Run benchmarks once +function run_icount_benchmarks() { + cargo_args=( + "--bench" "icount" + "--no-default-features" + "--features" "unstable,unstable-float,icount" + ) + + iai_args=( + "--home" "$(pwd)/$iai_home" + "--regression=ir=5.0" + "--save-summary" + ) + + # Parse `cargo_arg0 cargo_arg1 -- iai_arg0 iai_arg1` syntax + parsing_iai_args=0 + while [ "$#" -gt 0 ]; do + if [ "$parsing_iai_args" == "1" ]; then + iai_args+=("$1") + elif [ "$1" == "--" ]; then + parsing_iai_args=1 + else + cargo_args+=("$1") + fi + + shift + done + + # Run iai-callgrind benchmarks + cargo bench "${cargo_args[@]}" -- "${iai_args[@]}" + + # NB: iai-callgrind should exit on error but does not, so we inspect the sumary + # for errors. See https://github.com/iai-callgrind/iai-callgrind/issues/337 + if [ -n "${PR_NUMBER:-}" ]; then + # If this is for a pull request, ignore regressions if specified. + ./ci/ci-util.py check-regressions --home "$iai_home" --allow-pr-override "$PR_NUMBER" + else + ./ci/ci-util.py check-regressions --home "$iai_home" || true + fi +} + +# Run once with softfloats, once with arch instructions enabled +run_icount_benchmarks --features force-soft-floats -- --save-baseline=softfloat +run_icount_benchmarks -- --save-baseline=hardfloat + +# Name and tar the new baseline +name="baseline-icount-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}" +echo "BASELINE_NAME=$name" >>"$GITHUB_ENV" +tar cJf "$name.tar.xz" "$iai_home" diff --git a/library/compiler-builtins/etc/libm/ci/ci-util.py b/library/compiler-builtins/etc/libm/ci/ci-util.py new file mode 100755 index 00000000000..d9e402d6bd7 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/ci-util.py @@ -0,0 +1,416 @@ +#!/usr/bin/env python3 +"""Utilities for CI. + +This dynamically prepares a list of routines that had a source file change based on +git history. +""" + +import json +import os +import subprocess as sp +import sys +from dataclasses import dataclass +from glob import glob, iglob +from inspect import cleandoc +from os import getenv +from pathlib import Path +from typing import TypedDict, Self + +USAGE = cleandoc( + """ + usage: + + ./ci/ci-util.py [flags] + + COMMAND: + generate-matrix + Calculate a matrix of which functions had source change, print that as + a JSON object. + + locate-baseline [--download] [--extract] + Locate the most recent benchmark baseline available in CI and, if flags + specify, download and extract it. Never exits with nonzero status if + downloading fails. + + Note that `--extract` will overwrite files in `iai-home`. + + check-regressions [--home iai-home] [--allow-pr-override pr_number] + Check `iai-home` (or `iai-home` if unspecified) for `summary.json` + files and see if there are any regressions. This is used as a workaround + for `iai-callgrind` not exiting with error status; see + . + + If `--allow-pr-override` is specified, the regression check will not exit + with failure if any line in the PR starts with `allow-regressions`. + """ +) + +REPO_ROOT = Path(__file__).parent.parent +GIT = ["git", "-C", REPO_ROOT] +DEFAULT_BRANCH = "master" +WORKFLOW_NAME = "CI" # Workflow that generates the benchmark artifacts +ARTIFACT_GLOB = "baseline-icount*" +# Place this in a PR body to skip regression checks (must be at the start of a line). +REGRESSION_DIRECTIVE = "ci: allow-regressions" +# Place this in a PR body to skip extensive tests +SKIP_EXTENSIVE_DIRECTIVE = "ci: skip-extensive" +# Place this in a PR body to allow running a large number of extensive tests. If not +# set, this script will error out if a threshold is exceeded in order to avoid +# accidentally spending huge amounts of CI time. +ALLOW_MANY_EXTENSIVE_DIRECTIVE = "ci: allow-many-extensive" +MANY_EXTENSIVE_THRESHOLD = 20 + +# Don't run exhaustive tests if these files change, even if they contaiin a function +# definition. +IGNORE_FILES = [ + "libm/src/math/support/", + "libm/src/libm_helper.rs", + "libm/src/math/arch/intrinsics.rs", +] + +TYPES = ["f16", "f32", "f64", "f128"] + + +def eprint(*args, **kwargs): + """Print to stderr.""" + print(*args, file=sys.stderr, **kwargs) + + +@dataclass +class PrInfo: + """GitHub response for PR query""" + + body: str + commits: list[str] + created_at: str + number: int + + @classmethod + def load(cls, pr_number: int | str) -> Self: + """For a given PR number, query the body and commit list""" + pr_info = sp.check_output( + [ + "gh", + "pr", + "view", + str(pr_number), + "--json=number,commits,body,createdAt", + # Flatten the commit list to only hashes, change a key to snake naming + "--jq=.commits |= map(.oid) | .created_at = .createdAt | del(.createdAt)", + ], + text=True, + ) + eprint("PR info:", json.dumps(pr_info, indent=4)) + return cls(**json.loads(pr_info)) + + def contains_directive(self, directive: str) -> bool: + """Return true if the provided directive is on a line in the PR body""" + lines = self.body.splitlines() + return any(line.startswith(directive) for line in lines) + + +class FunctionDef(TypedDict): + """Type for an entry in `function-definitions.json`""" + + sources: list[str] + type: str + + +@dataclass +class Context: + gh_ref: str | None + changed: list[Path] + defs: dict[str, FunctionDef] + + def __init__(self) -> None: + self.gh_ref = getenv("GITHUB_REF") + self.changed = [] + self._init_change_list() + + with open(REPO_ROOT.joinpath("etc/function-definitions.json")) as f: + defs = json.load(f) + + defs.pop("__comment", None) + self.defs = defs + + def _init_change_list(self): + """Create a list of files that have been changed. This uses GITHUB_REF if + available, otherwise a diff between `HEAD` and `master`. + """ + + # For pull requests, GitHub creates a ref `refs/pull/1234/merge` (1234 being + # the PR number), and sets this as `GITHUB_REF`. + ref = self.gh_ref + eprint(f"using ref `{ref}`") + if ref is None or "merge" not in ref: + # If the ref is not for `merge` then we are not in PR CI + eprint("No diff available for ref") + return + + # The ref is for a dummy merge commit. We can extract the merge base by + # inspecting all parents (`^@`). + merge_sha = sp.check_output( + GIT + ["show-ref", "--hash", ref], text=True + ).strip() + merge_log = sp.check_output(GIT + ["log", "-1", merge_sha], text=True) + eprint(f"Merge:\n{merge_log}\n") + + parents = ( + sp.check_output(GIT + ["rev-parse", f"{merge_sha}^@"], text=True) + .strip() + .splitlines() + ) + assert len(parents) == 2, f"expected two-parent merge but got:\n{parents}" + base = parents[0].strip() + incoming = parents[1].strip() + + eprint(f"base: {base}, incoming: {incoming}") + textlist = sp.check_output( + GIT + ["diff", base, incoming, "--name-only"], text=True + ) + self.changed = [Path(p) for p in textlist.splitlines()] + + @staticmethod + def _ignore_file(fname: str) -> bool: + return any(fname.startswith(pfx) for pfx in IGNORE_FILES) + + def changed_routines(self) -> dict[str, list[str]]: + """Create a list of routines for which one or more files have been updated, + separated by type. + """ + routines = set() + for name, meta in self.defs.items(): + # Don't update if changes to the file should be ignored + sources = (f for f in meta["sources"] if not self._ignore_file(f)) + + # Select changed files + changed = [f for f in sources if Path(f) in self.changed] + + if len(changed) > 0: + eprint(f"changed files for {name}: {changed}") + routines.add(name) + + ret: dict[str, list[str]] = {} + for r in sorted(routines): + ret.setdefault(self.defs[r]["type"], []).append(r) + + return ret + + def make_workflow_output(self) -> str: + """Create a JSON object a list items for each type's changed files, if any + did change, and the routines that were affected by the change. + """ + + pr_number = os.environ.get("PR_NUMBER") + skip_tests = False + error_on_many_tests = False + + if pr_number is not None and len(pr_number) > 0: + pr = PrInfo.load(pr_number) + skip_tests = pr.contains_directive(SKIP_EXTENSIVE_DIRECTIVE) + error_on_many_tests = not pr.contains_directive( + ALLOW_MANY_EXTENSIVE_DIRECTIVE + ) + + if skip_tests: + eprint("Skipping all extensive tests") + + changed = self.changed_routines() + ret = [] + total_to_test = 0 + + for ty in TYPES: + ty_changed = changed.get(ty, []) + ty_to_test = [] if skip_tests else ty_changed + total_to_test += len(ty_to_test) + + item = { + "ty": ty, + "changed": ",".join(ty_changed), + "to_test": ",".join(ty_to_test), + } + + ret.append(item) + output = json.dumps({"matrix": ret}, separators=(",", ":")) + eprint(f"output: {output}") + eprint(f"total extensive tests: {total_to_test}") + + if error_on_many_tests and total_to_test > MANY_EXTENSIVE_THRESHOLD: + eprint( + f"More than {MANY_EXTENSIVE_THRESHOLD} tests would be run; add" + f" `{ALLOW_MANY_EXTENSIVE_DIRECTIVE}` to the PR body if this is intentional" + ) + exit(1) + + return output + + +def locate_baseline(flags: list[str]) -> None: + """Find the most recent baseline from CI, download it if specified. + + This returns rather than erroring, even if the `gh` commands fail. This is to avoid + erroring in CI if the baseline is unavailable (artifact time limit exceeded, first + run on the branch, etc). + """ + + download = False + extract = False + + while len(flags) > 0: + match flags[0]: + case "--download": + download = True + case "--extract": + extract = True + case _: + eprint(USAGE) + exit(1) + flags = flags[1:] + + if extract and not download: + eprint("cannot extract without downloading") + exit(1) + + try: + # Locate the most recent job to complete with success on our branch + latest_job = sp.check_output( + [ + "gh", + "run", + "list", + "--status=success", + f"--branch={DEFAULT_BRANCH}", + "--json=databaseId,url,headSha,conclusion,createdAt," + "status,workflowDatabaseId,workflowName", + # Return the first array element matching our workflow name. NB: cannot + # just use `--limit=1`, jq filtering happens after limiting. We also + # cannot just use `--workflow` because GH gets confused from + # different file names in history. + f'--jq=[.[] | select(.workflowName == "{WORKFLOW_NAME}")][0]', + ], + text=True, + ) + except sp.CalledProcessError as e: + eprint(f"failed to run github command: {e}") + return + + try: + latest = json.loads(latest_job) + eprint("latest job: ", json.dumps(latest, indent=4)) + except json.JSONDecodeError as e: + eprint(f"failed to decode json '{latest_job}', {e}") + return + + if not download: + eprint("--download not specified, returning") + return + + job_id = latest.get("databaseId") + if job_id is None: + eprint("skipping download step") + return + + sp.run( + ["gh", "run", "download", str(job_id), f"--pattern={ARTIFACT_GLOB}"], + check=False, + ) + + if not extract: + eprint("skipping extraction step") + return + + # Find the baseline with the most recent timestamp. GH downloads the files to e.g. + # `some-dirname/some-dirname.tar.xz`, so just glob the whole thing together. + candidate_baselines = glob(f"{ARTIFACT_GLOB}/{ARTIFACT_GLOB}") + if len(candidate_baselines) == 0: + eprint("no possible baseline directories found") + return + + candidate_baselines.sort(reverse=True) + baseline_archive = candidate_baselines[0] + eprint(f"extracting {baseline_archive}") + sp.run(["tar", "xJvf", baseline_archive], check=True) + eprint("baseline extracted successfully") + + +def check_iai_regressions(args: list[str]): + """Find regressions in iai summary.json files, exit with failure if any are + found. + """ + + iai_home_str = "iai-home" + pr_number = None + + while len(args) > 0: + match args: + case ["--home", home, *rest]: + iai_home_str = home + args = rest + case ["--allow-pr-override", pr_num, *rest]: + pr_number = pr_num + args = rest + case _: + eprint(USAGE) + exit(1) + + iai_home = Path(iai_home_str) + + found_summaries = False + regressions: list[dict] = [] + for summary_path in iglob("**/summary.json", root_dir=iai_home, recursive=True): + found_summaries = True + with open(iai_home / summary_path, "r") as f: + summary = json.load(f) + + summary_regs = [] + run = summary["callgrind_summary"]["callgrind_run"] + fname = summary["function_name"] + id = summary["id"] + name_entry = {"name": f"{fname}.{id}"} + + for segment in run["segments"]: + summary_regs.extend(segment["regressions"]) + + summary_regs.extend(run["total"]["regressions"]) + + regressions.extend(name_entry | reg for reg in summary_regs) + + if not found_summaries: + eprint(f"did not find any summary.json files within {iai_home}") + exit(1) + + if len(regressions) == 0: + eprint("No regressions found") + return + + eprint("Found regressions:", json.dumps(regressions, indent=4)) + + if pr_number is not None: + pr = PrInfo.load(pr_number) + if pr.contains_directive(REGRESSION_DIRECTIVE): + eprint("PR allows regressions, returning") + return + + exit(1) + + +def main(): + match sys.argv[1:]: + case ["generate-matrix"]: + ctx = Context() + output = ctx.make_workflow_output() + print(f"matrix={output}") + case ["locate-baseline", *flags]: + locate_baseline(flags) + case ["check-regressions", *args]: + check_iai_regressions(args) + case ["--help" | "-h"]: + print(USAGE) + exit() + case _: + eprint(USAGE) + exit(1) + + +if __name__ == "__main__": + main() diff --git a/library/compiler-builtins/etc/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..7fa06b28601 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-aarch64-linux-gnu m4 make libc6-dev-arm64-cross \ + qemu-user-static + +ENV TOOLCHAIN_PREFIX=aarch64-linux-gnu- +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-aarch64-static \ + AR_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ + QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile new file mode 100644 index 00000000000..e070a7d936e --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -0,0 +1,14 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabi- +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER="$TOOLCHAIN_PREFIX"gcc \ + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER=qemu-arm-static \ + AR_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"ar \ + CC_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"gcc \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile new file mode 100644 index 00000000000..29f1e04a9b5 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -0,0 +1,14 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ + AR_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ + CC_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile new file mode 100644 index 00000000000..0a30801b44d --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -0,0 +1,14 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- +ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ + CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ + AR_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ + CC_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..37e206a84fc --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc-multilib m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/etc/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..37e206a84fc --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc-multilib m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/etc/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..a9ce320e8b4 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-14-loongarch64-linux-gnu libc6-dev-loong64-cross + +ENV CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER=loongarch64-linux-gnu-gcc-14 \ + CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-loongarch64-static \ + AR_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-ar \ + CC_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-gcc-14 \ + QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..298208c925a --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-mips-linux-gnu libc6-dev-mips-cross \ + binfmt-support qemu-user-static qemu-system-mips + +ENV TOOLCHAIN_PREFIX=mips-linux-gnu- +ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ + CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER=qemu-mips-static \ + AR_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ + QEMU_LD_PREFIX=/usr/mips-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile new file mode 100644 index 00000000000..101b3853efe --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + gcc \ + gcc-mips64-linux-gnuabi64 \ + libc6-dev \ + libc6-dev-mips64-cross \ + qemu-user-static \ + qemu-system-mips + +ENV TOOLCHAIN_PREFIX=mips64-linux-gnuabi64- +ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ + CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64-static \ + AR_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ + CC_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ + QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile new file mode 100644 index 00000000000..0eb14f9acf5 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -0,0 +1,18 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + gcc \ + gcc-mips64el-linux-gnuabi64 \ + libc6-dev \ + libc6-dev-mips64el-cross \ + qemu-user-static + +ENV TOOLCHAIN_PREFIX=mips64el-linux-gnuabi64- +ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ + CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64el-static \ + AR_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ + CC_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ + QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..1b9817cfef8 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ + binfmt-support qemu-user-static + +ENV TOOLCHAIN_PREFIX=mipsel-linux-gnu- +ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ + CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER=qemu-mipsel-static \ + AR_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ + QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..1ea2e30a242 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ + qemu-system-ppc + +ENV TOOLCHAIN_PREFIX=powerpc-linux-gnu- +ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ + CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc-static \ + AR_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ + QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..373814bcafd --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ + binfmt-support qemu-user-static qemu-system-ppc + +ENV TOOLCHAIN_PREFIX=powerpc64-linux-gnu- +ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ + CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64-static \ + AR_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ + QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..403bb1d95b2 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -0,0 +1,16 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ + qemu-system-ppc + +ENV TOOLCHAIN_PREFIX=powerpc64le-linux-gnu- +ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ + CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64le-static \ + AR_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ + QEMU_CPU=POWER8 \ + QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..5f8a2892411 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-riscv64-linux-gnu libc6-dev-riscv64-cross \ + qemu-system-riscv64 + +ENV TOOLCHAIN_PREFIX=riscv64-linux-gnu- +ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ + CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER=qemu-riscv64-static \ + AR_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ + QEMU_LD_PREFIX=/usr/riscv64-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile new file mode 100644 index 00000000000..ad0d4351ea6 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -0,0 +1,9 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile new file mode 100644 index 00000000000..ad0d4351ea6 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -0,0 +1,9 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile new file mode 100644 index 00000000000..ad0d4351ea6 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -0,0 +1,9 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile new file mode 100644 index 00000000000..ad0d4351ea6 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -0,0 +1,9 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile new file mode 100644 index 00000000000..c84a31c57a9 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/etc/libm/ci/run-docker.sh b/library/compiler-builtins/etc/libm/ci/run-docker.sh new file mode 100755 index 00000000000..6626e722685 --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/run-docker.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# Small script to run tests for a target (or all targets) inside all the +# respective docker images. + +set -euxo pipefail + +host_arch="$(uname -m | sed 's/arm64/aarch64/')" + +run() { + local target=$1 + + echo "testing target: $target" + + target_arch="$(echo "$target" | cut -d'-' -f1)" + + emulated="" + if [ "$target_arch" != "$host_arch" ]; then + emulated=1 + echo "target is emulated" + fi + + # This directory needs to exist before calling docker, otherwise docker will create it but it + # will be owned by root + mkdir -p target + + set_env="HOME=/tmp PATH=\$PATH:/rust/bin:/cargo/bin" + docker build -t "libm-$target" "ci/docker/$target" + docker run \ + --rm \ + --user "$(id -u):$(id -g)" \ + -e CI \ + -e RUSTFLAGS \ + -e CARGO_TERM_COLOR \ + -e CARGO_HOME=/cargo \ + -e CARGO_TARGET_DIR=/target \ + -e "EMULATED=$emulated" \ + -v "${HOME}/.cargo:/cargo" \ + -v "$(pwd)/target:/target" \ + -v "$(pwd):/checkout:ro" \ + -v "$(rustc --print sysroot):/rust:ro" \ + --init \ + -w /checkout \ + "libm-$target" \ + sh -c "$set_env exec ci/run.sh $target" +} + +if [ -z "$1" ]; then + echo "running tests for all targets" + + for d in ci/docker/*; do + run $d + done +else + run $1 +fi diff --git a/library/compiler-builtins/etc/libm/ci/run.sh b/library/compiler-builtins/etc/libm/ci/run.sh new file mode 100755 index 00000000000..a946d325ebd --- /dev/null +++ b/library/compiler-builtins/etc/libm/ci/run.sh @@ -0,0 +1,130 @@ +#!/bin/sh + +set -eux + +export RUST_BACKTRACE="${RUST_BACKTRACE:-full}" +export NEXTEST_STATUS_LEVEL=all + +target="${1:-}" +flags="" + +if [ -z "$target" ]; then + host_target=$(rustc -vV | awk '/^host/ { print $2 }') + echo "Defaulted to host target $host_target" + target="$host_target" +fi + +# We enumerate features manually. +flags="$flags --no-default-features" + +# Enable arch-specific routines when available. +flags="$flags --features arch" + +# Always enable `unstable-float` since it expands available API but does not +# change any implementations. +flags="$flags --features unstable-float" + +# We need to specifically skip tests for musl-math-sys on systems that can't +# build musl since otherwise `--all` will activate it. +case "$target" in + # Can't build at all on MSVC, WASM, or thumb + *windows-msvc*) flags="$flags --exclude musl-math-sys" ;; + *wasm*) flags="$flags --exclude musl-math-sys" ;; + *thumb*) flags="$flags --exclude musl-math-sys" ;; + + # We can build musl on MinGW but running tests gets a stack overflow + *windows-gnu*) ;; + # FIXME(#309): LE PPC crashes calling the musl version of some functions. It + # seems like a qemu bug but should be investigated further at some point. + # See . + *powerpc64le*) ;; + + # Everything else gets musl enabled + *) flags="$flags --features libm-test/build-musl" ;; +esac + +# Configure which targets test against MPFR +case "$target" in + # MSVC cannot link MPFR + *windows-msvc*) ;; + # FIXME: MinGW should be able to build MPFR, but setup in CI is nontrivial. + *windows-gnu*) ;; + # Targets that aren't cross compiled in CI work fine + aarch64*apple*) flags="$flags --features libm-test/build-mpfr" ;; + aarch64*linux*) flags="$flags --features libm-test/build-mpfr" ;; + i586*) flags="$flags --features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross" ;; + i686*) flags="$flags --features libm-test/build-mpfr" ;; + x86_64*) flags="$flags --features libm-test/build-mpfr" ;; +esac + +# FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. +# +case "$target" in + *windows-gnu) flags="$flags --exclude libm-macros" ;; +esac + +# Make sure we can build with overriding features. +cargo check -p libm --no-default-features + +if [ "${BUILD_ONLY:-}" = "1" ]; then + # If we are on targets that can't run tests, verify that we can build. + cmd="cargo build --target $target --package libm" + $cmd + $cmd --features unstable-intrinsics + + echo "can't run tests on $target; skipping" + exit +fi + +flags="$flags --all --target $target" +cmd="cargo test $flags" +profile="--profile" + +# If nextest is available, use that +command -v cargo-nextest && nextest=1 || nextest=0 +if [ "$nextest" = "1" ]; then + # Workaround for https://github.com/nextest-rs/nextest/issues/2066 + if [ -f /.dockerenv ]; then + cfg_file="/tmp/nextest-config.toml" + echo "[store]" >> "$cfg_file" + echo "dir = \"$CARGO_TARGET_DIR/nextest\"" >> "$cfg_file" + cfg_flag="--config-file $cfg_file" + fi + + cmd="cargo nextest run ${cfg_flag:-} --max-fail=10 $flags" + profile="--cargo-profile" +fi + +# Test once without intrinsics +$cmd + +# Run doctests if they were excluded by nextest +[ "$nextest" = "1" ] && cargo test --doc $flags + +# Exclude the macros and utile crates from the rest of the tests to save CI +# runtime, they shouldn't have anything feature- or opt-level-dependent. +cmd="$cmd --exclude util --exclude libm-macros" + +# Test once with intrinsics enabled +$cmd --features unstable-intrinsics +$cmd --features unstable-intrinsics --benches + +# Test the same in release mode, which also increases coverage. Also ensure +# the soft float routines are checked. +$cmd "$profile" release-checked +$cmd "$profile" release-checked --features force-soft-floats +$cmd "$profile" release-checked --features unstable-intrinsics +$cmd "$profile" release-checked --features unstable-intrinsics --benches + +# Ensure that the routines do not panic. +# +# `--tests` must be passed because no-panic is only enabled as a dev +# dependency. The `release-opt` profile must be used to enable LTO and a +# single CGU. +ENSURE_NO_PANIC=1 cargo build \ + -p libm \ + --target "$target" \ + --no-default-features \ + --features unstable-float \ + --tests \ + --profile release-opt diff --git a/library/compiler-builtins/etc/update-api-list.py b/library/compiler-builtins/etc/update-api-list.py new file mode 100755 index 00000000000..0770a8b20fb --- /dev/null +++ b/library/compiler-builtins/etc/update-api-list.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python3 +"""Create a text file listing all public API. This can be used to ensure that all +functions are covered by our macros. + +This file additionally does tidy-esque checks that all functions are listed where +needed, or that lists are sorted. +""" + +import difflib +import json +import re +import subprocess as sp +import sys +from dataclasses import dataclass +from glob import glob +from pathlib import Path +from typing import Any, Callable, TypeAlias + +SELF_PATH = Path(__file__) +ETC_DIR = SELF_PATH.parent +ROOT_DIR = ETC_DIR.parent + +# These files do not trigger a retest. +IGNORED_SOURCES = ["libm/src/libm_helper.rs", "libm/src/math/support/float_traits.rs"] + +IndexTy: TypeAlias = dict[str, dict[str, Any]] +"""Type of the `index` item in rustdoc's JSON output""" + + +def eprint(*args, **kwargs): + """Print to stderr.""" + print(*args, file=sys.stderr, **kwargs) + + +@dataclass +class Crate: + """Representation of public interfaces and function defintion locations in + `libm`. + """ + + public_functions: list[str] + """List of all public functions.""" + defs: dict[str, list[str]] + """Map from `name->[source files]` to find all places that define a public + function. We track this to know which tests need to be rerun when specific files + get updated. + """ + types: dict[str, str] + """Map from `name->type`.""" + + def __init__(self) -> None: + self.public_functions = [] + self.defs = {} + self.types = {} + + j = self.get_rustdoc_json() + index: IndexTy = j["index"] + self._init_function_list(index) + self._init_defs(index) + self._init_types() + + @staticmethod + def get_rustdoc_json() -> dict[Any, Any]: + """Get rustdoc's JSON output for the `libm` crate.""" + + j = sp.check_output( + [ + "rustdoc", + "libm/src/lib.rs", + "--edition=2021", + "--document-private-items", + "--output-format=json", + "--cfg=f16_enabled", + "--cfg=f128_enabled", + "-Zunstable-options", + "-o-", + ], + cwd=ROOT_DIR, + text=True, + ) + j = json.loads(j) + return j + + def _init_function_list(self, index: IndexTy) -> None: + """Get a list of public functions from rustdoc JSON output. + + Note that this only finds functions that are reexported in `lib.rs`, this will + need to be adjusted if we need to account for functions that are defined there, or + glob reexports in other locations. + """ + # Filter out items that are not public + public = [i for i in index.values() if i["visibility"] == "public"] + + # Collect a list of source IDs for reexported items in `lib.rs` or `mod math`. + use = (i for i in public if "use" in i["inner"]) + use = ( + i + for i in use + if i["span"]["filename"] in ["libm/src/math/mod.rs", "libm/src/lib.rs"] + ) + reexported_ids = [item["inner"]["use"]["id"] for item in use] + + # Collect a list of reexported items that are functions + for id in reexported_ids: + srcitem = index.get(str(id)) + # External crate + if srcitem is None: + continue + + # Skip if not a function + if "function" not in srcitem["inner"]: + continue + + self.public_functions.append(srcitem["name"]) + self.public_functions.sort() + + def _init_defs(self, index: IndexTy) -> None: + defs = {name: set() for name in self.public_functions} + funcs = (i for i in index.values() if "function" in i["inner"]) + funcs = (f for f in funcs if f["name"] in self.public_functions) + for func in funcs: + defs[func["name"]].add(func["span"]["filename"]) + + # A lot of the `arch` module is often configured out so doesn't show up in docs. Use + # string matching as a fallback. + for fname in glob("libm/src/math/arch/**.rs", root_dir=ROOT_DIR): + contents = (ROOT_DIR.joinpath(fname)).read_text() + + for name in self.public_functions: + if f"fn {name}" in contents: + defs[name].add(fname) + + for name, sources in defs.items(): + base_sources = defs[base_name(name)[0]] + for src in (s for s in base_sources if "generic" in s): + sources.add(src) + + for src in IGNORED_SOURCES: + sources.discard(src) + + # Sort the set + self.defs = {k: sorted(v) for (k, v) in defs.items()} + + def _init_types(self) -> None: + self.types = {name: base_name(name)[1] for name in self.public_functions} + + def write_function_list(self, check: bool) -> None: + """Collect the list of public functions to a simple text file.""" + output = "# autogenerated by update-api-list.py\n" + for name in self.public_functions: + output += f"{name}\n" + + out_file = ETC_DIR.joinpath("function-list.txt") + + if check: + with open(out_file, "r") as f: + current = f.read() + diff_and_exit(current, output, "function list") + else: + with open(out_file, "w") as f: + f.write(output) + + def write_function_defs(self, check: bool) -> None: + """Collect the list of information about public functions to a JSON file .""" + comment = ( + "Autogenerated by update-api-list.py. " + "List of files that define a function with a given name. " + "This file is checked in to make it obvious if refactoring breaks things" + ) + + d = {"__comment": comment} + d |= { + name: {"sources": self.defs[name], "type": self.types[name]} + for name in self.public_functions + } + + out_file = ETC_DIR.joinpath("function-definitions.json") + output = json.dumps(d, indent=4) + "\n" + + if check: + with open(out_file, "r") as f: + current = f.read() + diff_and_exit(current, output, "source list") + else: + with open(out_file, "w") as f: + f.write(output) + + def tidy_lists(self) -> None: + """In each file, check annotations indicating blocks of code should be sorted or should + include all public API. + """ + + flist = sp.check_output(["git", "ls-files"], cwd=ROOT_DIR, text=True) + + for path in flist.splitlines(): + fpath = ROOT_DIR.joinpath(path) + if fpath.is_dir() or fpath == SELF_PATH: + continue + + lines = fpath.read_text().splitlines() + + validate_delimited_block( + fpath, + lines, + "verify-sorted-start", + "verify-sorted-end", + ensure_sorted, + ) + + validate_delimited_block( + fpath, + lines, + "verify-apilist-start", + "verify-apilist-end", + lambda p, n, lines: self.ensure_contains_api(p, n, lines), + ) + + def ensure_contains_api(self, fpath: Path, line_num: int, lines: list[str]): + """Given a list of strings, ensure that each public function we have is named + somewhere. + """ + not_found = [] + for func in self.public_functions: + # The function name may be on its own or somewhere in a snake case string. + pat = re.compile(rf"(\b|_){func}(\b|_)") + found = next((line for line in lines if pat.search(line)), None) + + if found is None: + not_found.append(func) + + if len(not_found) == 0: + return + + relpath = fpath.relative_to(ROOT_DIR) + eprint(f"functions not found at {relpath}:{line_num}: {not_found}") + exit(1) + + +def validate_delimited_block( + fpath: Path, + lines: list[str], + start: str, + end: str, + validate: Callable[[Path, int, list[str]], None], +) -> None: + """Identify blocks of code wrapped within `start` and `end`, collect their contents + to a list of strings, and call `validate` for each of those lists. + """ + relpath = fpath.relative_to(ROOT_DIR) + block_lines = [] + block_start_line: None | int = None + for line_num, line in enumerate(lines): + line_num += 1 + + if start in line: + block_start_line = line_num + continue + + if end in line: + if block_start_line is None: + eprint(f"`{end}` without `{start}` at {relpath}:{line_num}") + exit(1) + + validate(fpath, block_start_line, block_lines) + block_lines = [] + block_start_line = None + continue + + if block_start_line is not None: + block_lines.append(line) + + if block_start_line is not None: + eprint(f"`{start}` without `{end}` at {relpath}:{block_start_line}") + exit(1) + + +def ensure_sorted(fpath: Path, block_start_line: int, lines: list[str]) -> None: + """Ensure that a list of lines is sorted, otherwise print a diff and exit.""" + relpath = fpath.relative_to(ROOT_DIR) + diff_and_exit( + "\n".join(lines), + "\n".join(sorted(lines)), + f"sorted block at {relpath}:{block_start_line}", + ) + + +def diff_and_exit(actual: str, expected: str, name: str): + """If the two strings are different, print a diff between them and then exit + with an error. + """ + if actual == expected: + print(f"{name} output matches expected; success") + return + + a = [f"{line}\n" for line in actual.splitlines()] + b = [f"{line}\n" for line in expected.splitlines()] + + diff = difflib.unified_diff(a, b, "actual", "expected") + sys.stdout.writelines(diff) + print(f"mismatched {name}") + exit(1) + + +def base_name(name: str) -> tuple[str, str]: + """Return the basename and type from a full function name. Keep in sync with Rust's + `fn base_name`. + """ + known_mappings = [ + ("erff", ("erf", "f32")), + ("erf", ("erf", "f64")), + ("modff", ("modf", "f32")), + ("modf", ("modf", "f64")), + ("lgammaf_r", ("lgamma_r", "f32")), + ("lgamma_r", ("lgamma_r", "f64")), + ] + + found = next((base for (full, base) in known_mappings if full == name), None) + if found is not None: + return found + + if name.endswith("f"): + return (name.rstrip("f"), "f32") + + if name.endswith("f16"): + return (name.rstrip("f16"), "f16") + + if name.endswith("f128"): + return (name.rstrip("f128"), "f128") + + return (name, "f64") + + +def ensure_updated_list(check: bool) -> None: + """Runner to update the function list and JSON, or check that it is already up + to date. + """ + crate = Crate() + crate.write_function_list(check) + crate.write_function_defs(check) + + crate.tidy_lists() + + +def main(): + """By default overwrite the file. If `--check` is passed, print a diff instead and + error if the files are different. + """ + match sys.argv: + case [_]: + ensure_updated_list(False) + case [_, "--check"]: + ensure_updated_list(True) + case _: + print("unrecognized arguments") + exit(1) + + +if __name__ == "__main__": + main() diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml new file mode 100644 index 00000000000..5d150b4aeaa --- /dev/null +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -0,0 +1,70 @@ +[package] +name = "libm-test" +version = "0.1.0" +edition = "2024" +publish = false + +[features] +default = ["build-mpfr", "build-musl", "unstable-float"] + +# Propagated from libm because this affects which functions we test. +unstable-float = ["libm/unstable-float", "rug?/nightly-float"] + +# Generate tests which are random inputs and the outputs are calculated with +# musl libc. +build-mpfr = ["dep:rug", "dep:gmp-mpfr-sys"] + +# Build our own musl for testing and benchmarks +build-musl = ["dep:musl-math-sys"] + +# Enable report generation without bringing in more dependencies by default +benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] + +# Enable icount benchmarks (requires iai-callgrind and valgrind) +icount = ["dep:iai-callgrind"] + +# Run with a reduced set of benchmarks, such as for CI +short-benchmarks = [] + +[dependencies] +anyhow = "1.0.97" +# This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. +gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } +iai-callgrind = { version = "0.14.0", optional = true } +indicatif = { version = "0.17.11", default-features = false } +libm = { path = "../../libm", features = ["unstable-public-internals"] } +libm-macros = { path = "../libm-macros" } +musl-math-sys = { path = "../musl-math-sys", optional = true } +paste = "1.0.15" +rand = "0.9.0" +rand_chacha = "0.9.0" +rayon = "1.10.0" +rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "integer", "std"] } + +[build-dependencies] +rand = { version = "0.9.0", optional = true } + +[dev-dependencies] +criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } +libtest-mimic = "0.8.1" + +[[bench]] +name = "icount" +harness = false +required-features = ["icount"] + +[[bench]] +name = "random" +harness = false + +[[test]] +# No harness so that we can skip tests at runtime based on env. Prefixed with +# `z` so these tests get run last. +name = "z_extensive" +harness = false + +[lints.rust] +# Values from the chared config.rs used by `libm` but not the test crate +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(feature, values("arch", "force-soft-floats", "unstable-intrinsics"))', +] } diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs new file mode 100644 index 00000000000..da8c6bfd15a --- /dev/null +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -0,0 +1,316 @@ +//! Benchmarks that use `iai-cachegrind` to be reasonably CI-stable. + +use std::hint::black_box; + +use iai_callgrind::{library_benchmark, library_benchmark_group, main}; +use libm::support::{HInt, u256}; +use libm_test::generate::spaced; +use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, OpRustArgs, TupleCall, op}; + +const BENCH_ITER_ITEMS: u64 = 500; + +macro_rules! icount_benches { + ( + fn_name: $fn_name:ident, + attrs: [$($_attr:meta),*], + ) => { + paste::paste! { + // Construct benchmark inputs from the logspace generator. + fn [< setup_ $fn_name >]() -> Vec> { + type Op = op::$fn_name::Routine; + let mut ctx = CheckCtx::new( + Op::IDENTIFIER, + CheckBasis::None, + GeneratorKind::QuickSpaced + ); + ctx.override_iterations(BENCH_ITER_ITEMS); + let ret = spaced::get_test_cases::(&ctx).0.collect::>(); + println!("operation {}, {} steps", Op::NAME, ret.len()); + ret + } + + // Run benchmarks with the above inputs. + #[library_benchmark] + #[bench::logspace([< setup_ $fn_name >]())] + fn [< icount_bench_ $fn_name >](cases: Vec>) { + type Op = op::$fn_name::Routine; + let f = black_box(Op::ROUTINE); + for input in cases.iter().copied() { + input.call(f); + } + } + + library_benchmark_group!( + name = [< icount_bench_ $fn_name _group >]; + benchmarks = [< icount_bench_ $fn_name >] + ); + } + }; +} + +libm_macros::for_each_function! { + callback: icount_benches, +} + +fn setup_u128_mul() -> Vec<(u128, u128)> { + let step = u128::MAX / 300; + let mut x = 0u128; + let mut y = 0u128; + let mut v = Vec::new(); + + loop { + 'inner: loop { + match y.checked_add(step) { + Some(new) => y = new, + None => break 'inner, + } + + v.push((x, y)) + } + + match x.checked_add(step) { + Some(new) => x = new, + None => break, + } + } + + v +} + +fn setup_u256_add() -> Vec<(u256, u256)> { + let mut v = Vec::new(); + for (x, y) in setup_u128_mul() { + // square the u128 inputs to cover most of the u256 range + v.push((x.widen_mul(x), y.widen_mul(y))); + } + // Doesn't get covered by `u128:MAX^2` + v.push((u256::MAX, u256::MAX)); + v +} + +fn setup_u256_shift() -> Vec<(u256, u32)> { + let mut v = Vec::new(); + + for (x, _) in setup_u128_mul() { + let x2 = x.widen_mul(x); + for y in 0u32..256 { + v.push((x2, y)); + } + } + + v +} + +#[library_benchmark] +#[bench::linspace(setup_u128_mul())] +fn icount_bench_u128_widen_mul(cases: Vec<(u128, u128)>) { + for (x, y) in cases.iter().copied() { + black_box(black_box(x).zero_widen_mul(black_box(y))); + } +} + +library_benchmark_group!( + name = icount_bench_u128_widen_mul_group; + benchmarks = icount_bench_u128_widen_mul +); + +#[library_benchmark] +#[bench::linspace(setup_u256_add())] +fn icount_bench_u256_add(cases: Vec<(u256, u256)>) { + for (x, y) in cases.iter().copied() { + black_box(black_box(x) + black_box(y)); + } +} + +library_benchmark_group!( + name = icount_bench_u256_add_group; + benchmarks = icount_bench_u256_add +); + +#[library_benchmark] +#[bench::linspace(setup_u256_shift())] +fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) { + for (x, y) in cases.iter().copied() { + black_box(black_box(x) >> black_box(y)); + } +} + +library_benchmark_group!( + name = icount_bench_u256_shr_group; + benchmarks = icount_bench_u256_shr +); + +main!( + library_benchmark_groups = + // u256-related benchmarks + icount_bench_u128_widen_mul_group, + icount_bench_u256_add_group, + icount_bench_u256_shr_group, + // verify-apilist-start + // verify-sorted-start + icount_bench_acos_group, + icount_bench_acosf_group, + icount_bench_acosh_group, + icount_bench_acoshf_group, + icount_bench_asin_group, + icount_bench_asinf_group, + icount_bench_asinh_group, + icount_bench_asinhf_group, + icount_bench_atan2_group, + icount_bench_atan2f_group, + icount_bench_atan_group, + icount_bench_atanf_group, + icount_bench_atanh_group, + icount_bench_atanhf_group, + icount_bench_cbrt_group, + icount_bench_cbrtf_group, + icount_bench_ceil_group, + icount_bench_ceilf128_group, + icount_bench_ceilf16_group, + icount_bench_ceilf_group, + icount_bench_copysign_group, + icount_bench_copysignf128_group, + icount_bench_copysignf16_group, + icount_bench_copysignf_group, + icount_bench_cos_group, + icount_bench_cosf_group, + icount_bench_cosh_group, + icount_bench_coshf_group, + icount_bench_erf_group, + icount_bench_erfc_group, + icount_bench_erfcf_group, + icount_bench_erff_group, + icount_bench_exp10_group, + icount_bench_exp10f_group, + icount_bench_exp2_group, + icount_bench_exp2f_group, + icount_bench_exp_group, + icount_bench_expf_group, + icount_bench_expm1_group, + icount_bench_expm1f_group, + icount_bench_fabs_group, + icount_bench_fabsf128_group, + icount_bench_fabsf16_group, + icount_bench_fabsf_group, + icount_bench_fdim_group, + icount_bench_fdimf128_group, + icount_bench_fdimf16_group, + icount_bench_fdimf_group, + icount_bench_floor_group, + icount_bench_floorf128_group, + icount_bench_floorf16_group, + icount_bench_floorf_group, + icount_bench_fma_group, + icount_bench_fmaf128_group, + icount_bench_fmaf_group, + icount_bench_fmax_group, + icount_bench_fmaxf128_group, + icount_bench_fmaxf16_group, + icount_bench_fmaxf_group, + icount_bench_fmaximum_group, + icount_bench_fmaximum_num_group, + icount_bench_fmaximum_numf128_group, + icount_bench_fmaximum_numf16_group, + icount_bench_fmaximum_numf_group, + icount_bench_fmaximumf128_group, + icount_bench_fmaximumf16_group, + icount_bench_fmaximumf_group, + icount_bench_fmin_group, + icount_bench_fminf128_group, + icount_bench_fminf16_group, + icount_bench_fminf_group, + icount_bench_fminimum_group, + icount_bench_fminimum_num_group, + icount_bench_fminimum_numf128_group, + icount_bench_fminimum_numf16_group, + icount_bench_fminimum_numf_group, + icount_bench_fminimumf128_group, + icount_bench_fminimumf16_group, + icount_bench_fminimumf_group, + icount_bench_fmod_group, + icount_bench_fmodf128_group, + icount_bench_fmodf16_group, + icount_bench_fmodf_group, + icount_bench_frexp_group, + icount_bench_frexpf_group, + icount_bench_hypot_group, + icount_bench_hypotf_group, + icount_bench_ilogb_group, + icount_bench_ilogbf_group, + icount_bench_j0_group, + icount_bench_j0f_group, + icount_bench_j1_group, + icount_bench_j1f_group, + icount_bench_jn_group, + icount_bench_jnf_group, + icount_bench_ldexp_group, + icount_bench_ldexpf128_group, + icount_bench_ldexpf16_group, + icount_bench_ldexpf_group, + icount_bench_lgamma_group, + icount_bench_lgamma_r_group, + icount_bench_lgammaf_group, + icount_bench_lgammaf_r_group, + icount_bench_log10_group, + icount_bench_log10f_group, + icount_bench_log1p_group, + icount_bench_log1pf_group, + icount_bench_log2_group, + icount_bench_log2f_group, + icount_bench_log_group, + icount_bench_logf_group, + icount_bench_modf_group, + icount_bench_modff_group, + icount_bench_nextafter_group, + icount_bench_nextafterf_group, + icount_bench_pow_group, + icount_bench_powf_group, + icount_bench_remainder_group, + icount_bench_remainderf_group, + icount_bench_remquo_group, + icount_bench_remquof_group, + icount_bench_rint_group, + icount_bench_rintf128_group, + icount_bench_rintf16_group, + icount_bench_rintf_group, + icount_bench_round_group, + icount_bench_roundeven_group, + icount_bench_roundevenf128_group, + icount_bench_roundevenf16_group, + icount_bench_roundevenf_group, + icount_bench_roundf128_group, + icount_bench_roundf16_group, + icount_bench_roundf_group, + icount_bench_scalbn_group, + icount_bench_scalbnf128_group, + icount_bench_scalbnf16_group, + icount_bench_scalbnf_group, + icount_bench_sin_group, + icount_bench_sincos_group, + icount_bench_sincosf_group, + icount_bench_sinf_group, + icount_bench_sinh_group, + icount_bench_sinhf_group, + icount_bench_sqrt_group, + icount_bench_sqrtf128_group, + icount_bench_sqrtf16_group, + icount_bench_sqrtf_group, + icount_bench_tan_group, + icount_bench_tanf_group, + icount_bench_tanh_group, + icount_bench_tanhf_group, + icount_bench_tgamma_group, + icount_bench_tgammaf_group, + icount_bench_trunc_group, + icount_bench_truncf128_group, + icount_bench_truncf16_group, + icount_bench_truncf_group, + icount_bench_y0_group, + icount_bench_y0f_group, + icount_bench_y1_group, + icount_bench_y1f_group, + icount_bench_yn_group, + icount_bench_ynf_group, + // verify-sorted-end + // verify-apilist-end +); diff --git a/library/compiler-builtins/libm-test/benches/random.rs b/library/compiler-builtins/libm-test/benches/random.rs new file mode 100644 index 00000000000..63d7e5c6d20 --- /dev/null +++ b/library/compiler-builtins/libm-test/benches/random.rs @@ -0,0 +1,207 @@ +use std::hint::black_box; +use std::time::Duration; + +use criterion::{Criterion, criterion_main}; +use libm_test::generate::random; +use libm_test::generate::random::RandomInput; +use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, TupleCall}; + +/// Benchmark with this many items to get a variety +const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { 50 } else { 500 }; + +/// Extra parameters we only care about if we are benchmarking against musl. +#[allow(dead_code)] +struct MuslExtra { + musl_fn: Option, + skip_on_i586: bool, +} + +macro_rules! musl_rand_benches { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + fn_extra: ($skip_on_i586:expr, $musl_fn:expr), + ) => { + paste::paste! { + $(#[$attr])* + fn [< musl_bench_ $fn_name >](c: &mut Criterion) { + type Op = libm_test::op::$fn_name::Routine; + + #[cfg(feature = "build-musl")] + let musl_extra = MuslExtra::> { + musl_fn: $musl_fn, + skip_on_i586: $skip_on_i586, + }; + + #[cfg(not(feature = "build-musl"))] + let musl_extra = MuslExtra { + musl_fn: None, + skip_on_i586: $skip_on_i586, + }; + + bench_one::(c, musl_extra); + } + } + }; +} + +fn bench_one(c: &mut Criterion, musl_extra: MuslExtra) +where + Op: MathOp, + Op::RustArgs: RandomInput, +{ + let name = Op::NAME; + + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl, GeneratorKind::Random); + let benchvec: Vec<_> = + random::get_test_cases::(&ctx).0.take(BENCH_ITER_ITEMS).collect(); + + // Perform a sanity check that we are benchmarking the same thing + // Don't test against musl if it is not available + #[cfg(feature = "build-musl")] + for input in benchvec.iter().copied() { + use anyhow::Context; + use libm_test::CheckOutput; + + if cfg!(x86_no_sse) && musl_extra.skip_on_i586 { + break; + } + + let Some(musl_fn) = musl_extra.musl_fn else { + continue; + }; + let musl_res = input.call(musl_fn); + let crate_res = input.call(Op::ROUTINE); + + crate_res.validate(musl_res, input, &ctx).context(name).unwrap(); + } + + #[cfg(not(feature = "build-musl"))] + let _ = musl_extra; // silence unused warnings + + /* Option pointers are black boxed to avoid inlining in the benchmark loop */ + + let mut group = c.benchmark_group(name); + group.bench_function("crate", |b| { + b.iter(|| { + let f = black_box(Op::ROUTINE); + for input in benchvec.iter().copied() { + input.call(f); + } + }) + }); + + // Don't test against musl if it is not available + #[cfg(feature = "build-musl")] + { + if let Some(musl_fn) = musl_extra.musl_fn { + group.bench_function("musl", |b| { + b.iter(|| { + let f = black_box(musl_fn); + for input in benchvec.iter().copied() { + input.call(f); + } + }) + }); + } + } +} + +libm_macros::for_each_function! { + callback: musl_rand_benches, + skip: [], + fn_extra: match MACRO_FN_NAME { + // We pass a tuple of `(skip_on_i586, musl_fn)` + + // FIXME(correctness): exp functions have the wrong result on i586 + exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)), + + // Musl does not provide `f16` and `f128` functions + ceilf128 + | ceilf16 + | copysignf128 + | copysignf16 + | fabsf128 + | fabsf16 + | fdimf128 + | fdimf16 + | floorf128 + | floorf16 + | fmaf128 + | fmaxf128 + | fmaxf16 + | fmaximum + | fmaximum_num + | fmaximum_numf + | fmaximum_numf128 + | fmaximum_numf16 + | fmaximumf + | fmaximumf128 + | fmaximumf16 + | fminf128 + | fminf16 + | fminimum + | fminimum_num + | fminimum_numf + | fminimum_numf128 + | fminimum_numf16 + | fminimumf + | fminimumf128 + | fminimumf16 + | fmodf128 + | fmodf16 + | ldexpf128 + | ldexpf16 + | rintf128 + | rintf16 + | roundeven + | roundevenf + | roundevenf128 + | roundevenf16 + | roundf128 + | roundf16 + | scalbnf128 + | scalbnf16 + | sqrtf128 + | sqrtf16 + | truncf128 + | truncf16 => (false, None), + + // By default we never skip (false) and always have a musl function available + _ => (false, Some(musl_math_sys::MACRO_FN_NAME)) + } +} + +macro_rules! run_callback { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + extra: [$criterion:ident], + ) => { + paste::paste! { + $(#[$attr])* + [< musl_bench_ $fn_name >](&mut $criterion) + } + }; +} + +pub fn musl_random() { + let mut criterion = Criterion::default(); + + // For CI, run a short 0.5s warmup and 1.0s tests. This makes benchmarks complete in + // about the same time as other tests. + if cfg!(feature = "short-benchmarks") { + criterion = criterion + .warm_up_time(Duration::from_millis(200)) + .measurement_time(Duration::from_millis(600)); + } + + criterion = criterion.configure_from_args(); + + libm_macros::for_each_function! { + callback: run_callback, + extra: [criterion], + }; +} + +criterion_main!(musl_random); diff --git a/library/compiler-builtins/libm-test/build.rs b/library/compiler-builtins/libm-test/build.rs new file mode 100644 index 00000000000..f75e3dda5ff --- /dev/null +++ b/library/compiler-builtins/libm-test/build.rs @@ -0,0 +1,9 @@ +#[path = "../../libm/configure.rs"] +mod configure; +use configure::Config; + +fn main() { + println!("cargo:rerun-if-changed=../../libm/configure.rs"); + let cfg = Config::from_env(); + configure::emit_test_config(&cfg); +} diff --git a/library/compiler-builtins/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm-test/examples/plot_domains.rs new file mode 100644 index 00000000000..78524761e2c --- /dev/null +++ b/library/compiler-builtins/libm-test/examples/plot_domains.rs @@ -0,0 +1,103 @@ +//! Program to write all inputs from a generator to a file, then invoke a Julia script to plot +//! them. Output is in `target/plots`. +//! +//! Requires Julia with the `CairoMakie` dependency. +//! +//! Note that running in release mode by default generates a _lot_ more datapoints, which +//! causes plotting to be extremely slow (some simplification to be done in the script). + +use std::fmt::Write as _; +use std::io::{BufWriter, Write}; +use std::path::Path; +use std::process::Command; +use std::{env, fs}; + +use libm_test::generate::spaced::SpacedInput; +use libm_test::generate::{edge_cases, spaced}; +use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; + +const JL_PLOT: &str = "examples/plot_file.jl"; + +fn main() { + let manifest_env = env::var("CARGO_MANIFEST_DIR").unwrap(); + let manifest_dir = Path::new(&manifest_env); + let out_dir = manifest_dir.join("../../target/plots"); + if !out_dir.exists() { + fs::create_dir(&out_dir).unwrap(); + } + + let jl_script = manifest_dir.join(JL_PLOT); + let mut config = format!(r#"out_dir = "{}""#, out_dir.display()); + config.write_str("\n\n").unwrap(); + + // Plot a few domains with some functions that use them. + plot_one_operator::(&out_dir, &mut config); + plot_one_operator::(&out_dir, &mut config); + plot_one_operator::(&out_dir, &mut config); + + let config_path = out_dir.join("config.toml"); + fs::write(&config_path, config).unwrap(); + + // The script expects a path to `config.toml` to be passed as its only argument + let mut cmd = Command::new("julia"); + if cfg!(optimizations_enabled) { + cmd.arg("-O3"); + } + cmd.arg(jl_script).arg(config_path); + + println!("launching script... {cmd:?}"); + cmd.status().unwrap(); +} + +/// Run multiple generators for a single operator. +fn plot_one_operator(out_dir: &Path, config: &mut String) +where + Op: MathOp, + Op::RustArgs: SpacedInput, +{ + let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::QuickSpaced); + plot_one_generator(out_dir, &ctx, "logspace", config, spaced::get_test_cases::(&ctx).0); + ctx.gen_kind = GeneratorKind::EdgeCases; + plot_one_generator( + out_dir, + &ctx, + "edge_cases", + config, + edge_cases::get_test_cases::(&ctx).0, + ); +} + +/// Plot the output of a single generator. +fn plot_one_generator( + out_dir: &Path, + ctx: &CheckCtx, + gen_name: &str, + config: &mut String, + generator: impl Iterator, +) { + let fn_name = ctx.base_name_str; + let text_file = out_dir.join(format!("input-{fn_name}-{gen_name}.txt")); + + let f = fs::File::create(&text_file).unwrap(); + let mut w = BufWriter::new(f); + let mut count = 0u64; + + for input in generator { + writeln!(w, "{:e}", input.0).unwrap(); + count += 1; + } + + w.flush().unwrap(); + println!("generated {count} inputs for {fn_name}-{gen_name}"); + + writeln!( + config, + r#"[[input]] +function = "{fn_name}" +generator = "{gen_name}" +input_file = "{}" +"#, + text_file.to_str().unwrap() + ) + .unwrap() +} diff --git a/library/compiler-builtins/libm-test/examples/plot_file.jl b/library/compiler-builtins/libm-test/examples/plot_file.jl new file mode 100644 index 00000000000..acffd97569f --- /dev/null +++ b/library/compiler-builtins/libm-test/examples/plot_file.jl @@ -0,0 +1,171 @@ +"A quick script for plotting a list of floats. + +Takes a path to a TOML file (Julia has builtin TOML support but not JSON) which +specifies a list of source files to plot. Plots are done with both a linear and +a log scale. + +Requires [Makie] (specifically CairoMakie) for plotting. + +[Makie]: https://docs.makie.org/stable/ +" + +using CairoMakie +using TOML + +function main()::Nothing + CairoMakie.activate!(px_per_unit = 10) + config_path = ARGS[1] + + cfg = Dict() + open(config_path, "r") do f + cfg = TOML.parse(f) + end + + out_dir = cfg["out_dir"] + for input in cfg["input"] + fn_name = input["function"] + gen_name = input["generator"] + input_file = input["input_file"] + + plot_one(input_file, out_dir, fn_name, gen_name) + end +end + +"Read inputs from a file, create both linear and log plots for one function" +function plot_one( + input_file::String, + out_dir::String, + fn_name::String, + gen_name::String, +)::Nothing + fig = Figure() + + lin_out_file = joinpath(out_dir, "plot-$fn_name-$gen_name.png") + log_out_file = joinpath(out_dir, "plot-$fn_name-$gen_name-log.png") + + # Map string function names to callable functions + if fn_name == "cos" + orig_func = cos + xlims = (-6.0, 6.0) + xlims_log = (-pi * 10, pi * 10) + elseif fn_name == "cbrt" + orig_func = cbrt + xlims = (-2.0, 2.0) + xlims_log = (-1000.0, 1000.0) + elseif fn_name == "sqrt" + orig_func = sqrt + xlims = (-1.1, 6.0) + xlims_log = (-1.1, 5000.0) + else + println("unrecognized function name `$fn_name`; update plot_file.jl") + exit(1) + end + + # Edge cases don't do much beyond +/-1, except for infinity. + if gen_name == "edge_cases" + xlims = (-1.1, 1.1) + xlims_log = (-1.1, 1.1) + end + + # Turn domain errors into NaN + func(x) = map_or(x, orig_func, NaN) + + # Parse a series of X values produced by the generator + inputs = readlines(input_file) + gen_x = map((v) -> parse(Float32, v), inputs) + + do_plot( + fig, + gen_x, + func, + xlims[1], + xlims[2], + "$fn_name $gen_name (linear scale)", + lin_out_file, + false, + ) + + do_plot( + fig, + gen_x, + func, + xlims_log[1], + xlims_log[2], + "$fn_name $gen_name (log scale)", + log_out_file, + true, + ) +end + +"Create a single plot" +function do_plot( + fig::Figure, + gen_x::Vector{F}, + func::Function, + xmin::AbstractFloat, + xmax::AbstractFloat, + title::String, + out_file::String, + logscale::Bool, +)::Nothing where {F<:AbstractFloat} + println("plotting $title") + + # `gen_x` is the values the generator produces. `actual_x` is for plotting a + # continuous function. + input_min = xmin - 1.0 + input_max = xmax + 1.0 + gen_x = filter((v) -> v >= input_min && v <= input_max, gen_x) + markersize = length(gen_x) < 10_000 ? 6.0 : 4.0 + + steps = 10_000 + if logscale + r = LinRange(symlog10(input_min), symlog10(input_max), steps) + actual_x = sympow10.(r) + xscale = Makie.pseudolog10 + else + actual_x = LinRange(input_min, input_max, steps) + xscale = identity + end + + gen_y = @. func(gen_x) + actual_y = @. func(actual_x) + + ax = Axis(fig[1, 1], xscale = xscale, title = title) + + lines!( + ax, + actual_x, + actual_y, + color = (:lightblue, 0.6), + linewidth = 6.0, + label = "true function", + ) + scatter!( + ax, + gen_x, + gen_y, + color = (:darkblue, 0.9), + markersize = markersize, + label = "checked inputs", + ) + axislegend(ax, position = :rb, framevisible = false) + + save(out_file, fig) + delete!(ax) +end + +"Apply a function, returning the default if there is a domain error" +function map_or(input::AbstractFloat, f::Function, default::Any)::Union{AbstractFloat,Any} + try + return f(input) + catch + return default + end +end + +# Operations for logarithms that are symmetric about 0 +C = 10 +symlog10(x::Number) = sign(x) * (log10(1 + abs(x) / (10^C))) +sympow10(x::Number) = (10^C) * (10^x - 1) + +main() diff --git a/library/compiler-builtins/libm-test/src/domain.rs b/library/compiler-builtins/libm-test/src/domain.rs new file mode 100644 index 00000000000..41e94846163 --- /dev/null +++ b/library/compiler-builtins/libm-test/src/domain.rs @@ -0,0 +1,265 @@ +//! Traits and operations related to bounds of a function. + +use std::fmt; +use std::ops::Bound; + +use libm::support::Int; + +use crate::{BaseName, Float, FloatExt, Identifier}; + +/// Representation of a single dimension of a function's domain. +#[derive(Clone, Debug)] +pub struct Domain { + /// Start of the region for which a function is defined (ignoring poles). + pub start: Bound, + /// Endof the region for which a function is defined (ignoring poles). + pub end: Bound, + /// Additional points to check closer around. These can be e.g. undefined asymptotes or + /// inflection points. + pub check_points: Option BoxIter>, +} + +type BoxIter = Box>; + +impl Domain { + /// The start of this domain, saturating at negative infinity. + pub fn range_start(&self) -> F { + match self.start { + Bound::Included(v) => v, + Bound::Excluded(v) => v.next_up(), + Bound::Unbounded => F::NEG_INFINITY, + } + } + + /// The end of this domain, saturating at infinity. + pub fn range_end(&self) -> F { + match self.end { + Bound::Included(v) => v, + Bound::Excluded(v) => v.next_down(), + Bound::Unbounded => F::INFINITY, + } + } +} + +/// A value that may be any float type or any integer type. +#[derive(Clone, Debug)] +pub enum EitherPrim { + Float(F), + Int(I), +} + +impl EitherPrim { + pub fn unwrap_float(self) -> F { + match self { + EitherPrim::Float(f) => f, + EitherPrim::Int(_) => panic!("expected float; got {self:?}"), + } + } + + pub fn unwrap_int(self) -> I { + match self { + EitherPrim::Float(_) => panic!("expected int; got {self:?}"), + EitherPrim::Int(i) => i, + } + } +} + +/// Convenience 1-dimensional float domains. +impl Domain { + /// x ∈ ℝ + const UNBOUNDED: Self = + Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }; + + /// x ∈ ℝ >= 0 + const POSITIVE: Self = + Self { start: Bound::Included(F::ZERO), end: Bound::Unbounded, check_points: None }; + + /// x ∈ ℝ > 0 + const STRICTLY_POSITIVE: Self = + Self { start: Bound::Excluded(F::ZERO), end: Bound::Unbounded, check_points: None }; + + /// Wrap in the float variant of [`EitherPrim`]. + const fn into_prim_float(self) -> EitherPrim> { + EitherPrim::Float(self) + } +} + +/// Convenience 1-dimensional integer domains. +impl Domain { + /// x ∈ ℝ + const UNBOUNDED_INT: Self = + Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }; + + /// Wrap in the int variant of [`EitherPrim`]. + const fn into_prim_int(self) -> EitherPrim, Self> { + EitherPrim::Int(self) + } +} + +/// Multidimensional domains, represented as an array of 1-D domains. +impl EitherPrim, Domain> { + /// x ∈ ℝ + const UNBOUNDED1: [Self; 1] = + [Domain { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None } + .into_prim_float()]; + + /// {x1, x2} ∈ ℝ + const UNBOUNDED2: [Self; 2] = + [Domain::UNBOUNDED.into_prim_float(), Domain::UNBOUNDED.into_prim_float()]; + + /// {x1, x2, x3} ∈ ℝ + const UNBOUNDED3: [Self; 3] = [ + Domain::UNBOUNDED.into_prim_float(), + Domain::UNBOUNDED.into_prim_float(), + Domain::UNBOUNDED.into_prim_float(), + ]; + + /// {x1, x2} ∈ ℝ, one float and one int + const UNBOUNDED_F_I: [Self; 2] = + [Domain::UNBOUNDED.into_prim_float(), Domain::UNBOUNDED_INT.into_prim_int()]; + + /// x ∈ ℝ >= 0 + const POSITIVE: [Self; 1] = [Domain::POSITIVE.into_prim_float()]; + + /// x ∈ ℝ > 0 + const STRICTLY_POSITIVE: [Self; 1] = [Domain::STRICTLY_POSITIVE.into_prim_float()]; + + /// Used for versions of `asin` and `acos`. + const INVERSE_TRIG_PERIODIC: [Self; 1] = [Domain { + start: Bound::Included(F::NEG_ONE), + end: Bound::Included(F::ONE), + check_points: None, + } + .into_prim_float()]; + + /// Domain for `acosh` + const ACOSH: [Self; 1] = + [Domain { start: Bound::Included(F::ONE), end: Bound::Unbounded, check_points: None } + .into_prim_float()]; + + /// Domain for `atanh` + const ATANH: [Self; 1] = [Domain { + start: Bound::Excluded(F::NEG_ONE), + end: Bound::Excluded(F::ONE), + check_points: None, + } + .into_prim_float()]; + + /// Domain for `sin`, `cos`, and `tan` + const TRIG: [Self; 1] = [Domain { + // Trig functions have special behavior at fractions of π. + check_points: Some(|| Box::new([-F::PI, -F::FRAC_PI_2, F::FRAC_PI_2, F::PI].into_iter())), + ..Domain::UNBOUNDED + } + .into_prim_float()]; + + /// Domain for `log` in various bases + const LOG: [Self; 1] = Self::STRICTLY_POSITIVE; + + /// Domain for `log1p` i.e. `log(1 + x)` + const LOG1P: [Self; 1] = + [Domain { start: Bound::Excluded(F::NEG_ONE), end: Bound::Unbounded, check_points: None } + .into_prim_float()]; + + /// Domain for `sqrt` + const SQRT: [Self; 1] = Self::POSITIVE; + + /// Domain for `gamma` + const GAMMA: [Self; 1] = [Domain { + check_points: Some(|| { + // Negative integers are asymptotes + Box::new((0..u8::MAX).map(|scale| { + let mut base = F::ZERO; + for _ in 0..scale { + base = base - F::ONE; + } + base + })) + }), + // Whether or not gamma is defined for negative numbers is implementation dependent + ..Domain::UNBOUNDED + } + .into_prim_float()]; + + /// Domain for `loggamma` + const LGAMMA: [Self; 1] = Self::STRICTLY_POSITIVE; + + /// Domain for `jn` and `yn`. + // FIXME: the domain should provide some sort of "reasonable range" so we don't actually test + // the entire system unbounded. + const BESSEL_N: [Self; 2] = + [Domain::UNBOUNDED_INT.into_prim_int(), Domain::UNBOUNDED.into_prim_float()]; +} + +/// Get the domain for a given function. +pub fn get_domain( + id: Identifier, + argnum: usize, +) -> EitherPrim, Domain> { + let x = match id.base_name() { + BaseName::Acos => &EitherPrim::INVERSE_TRIG_PERIODIC[..], + BaseName::Acosh => &EitherPrim::ACOSH[..], + BaseName::Asin => &EitherPrim::INVERSE_TRIG_PERIODIC[..], + BaseName::Asinh => &EitherPrim::UNBOUNDED1[..], + BaseName::Atan => &EitherPrim::UNBOUNDED1[..], + BaseName::Atan2 => &EitherPrim::UNBOUNDED2[..], + BaseName::Cbrt => &EitherPrim::UNBOUNDED1[..], + BaseName::Atanh => &EitherPrim::ATANH[..], + BaseName::Ceil => &EitherPrim::UNBOUNDED1[..], + BaseName::Cosh => &EitherPrim::UNBOUNDED1[..], + BaseName::Copysign => &EitherPrim::UNBOUNDED2[..], + BaseName::Cos => &EitherPrim::TRIG[..], + BaseName::Exp => &EitherPrim::UNBOUNDED1[..], + BaseName::Erf => &EitherPrim::UNBOUNDED1[..], + BaseName::Erfc => &EitherPrim::UNBOUNDED1[..], + BaseName::Expm1 => &EitherPrim::UNBOUNDED1[..], + BaseName::Exp10 => &EitherPrim::UNBOUNDED1[..], + BaseName::Exp2 => &EitherPrim::UNBOUNDED1[..], + BaseName::Frexp => &EitherPrim::UNBOUNDED1[..], + BaseName::Fabs => &EitherPrim::UNBOUNDED1[..], + BaseName::Fdim => &EitherPrim::UNBOUNDED2[..], + BaseName::Floor => &EitherPrim::UNBOUNDED1[..], + BaseName::Fma => &EitherPrim::UNBOUNDED3[..], + BaseName::Fmax => &EitherPrim::UNBOUNDED2[..], + BaseName::Fmaximum => &EitherPrim::UNBOUNDED2[..], + BaseName::FmaximumNum => &EitherPrim::UNBOUNDED2[..], + BaseName::Fmin => &EitherPrim::UNBOUNDED2[..], + BaseName::Fminimum => &EitherPrim::UNBOUNDED2[..], + BaseName::FminimumNum => &EitherPrim::UNBOUNDED2[..], + BaseName::Fmod => &EitherPrim::UNBOUNDED2[..], + BaseName::Hypot => &EitherPrim::UNBOUNDED2[..], + BaseName::Ilogb => &EitherPrim::UNBOUNDED1[..], + BaseName::J0 => &EitherPrim::UNBOUNDED1[..], + BaseName::J1 => &EitherPrim::UNBOUNDED1[..], + BaseName::Jn => &EitherPrim::BESSEL_N[..], + BaseName::Ldexp => &EitherPrim::UNBOUNDED_F_I[..], + BaseName::Lgamma => &EitherPrim::LGAMMA[..], + BaseName::LgammaR => &EitherPrim::LGAMMA[..], + BaseName::Log => &EitherPrim::LOG[..], + BaseName::Log10 => &EitherPrim::LOG[..], + BaseName::Log1p => &EitherPrim::LOG1P[..], + BaseName::Log2 => &EitherPrim::LOG[..], + BaseName::Modf => &EitherPrim::UNBOUNDED1[..], + BaseName::Nextafter => &EitherPrim::UNBOUNDED2[..], + BaseName::Pow => &EitherPrim::UNBOUNDED2[..], + BaseName::Remainder => &EitherPrim::UNBOUNDED2[..], + BaseName::Remquo => &EitherPrim::UNBOUNDED2[..], + BaseName::Rint => &EitherPrim::UNBOUNDED1[..], + BaseName::Round => &EitherPrim::UNBOUNDED1[..], + BaseName::Roundeven => &EitherPrim::UNBOUNDED1[..], + BaseName::Scalbn => &EitherPrim::UNBOUNDED_F_I[..], + BaseName::Sin => &EitherPrim::TRIG[..], + BaseName::Sincos => &EitherPrim::TRIG[..], + BaseName::Sinh => &EitherPrim::UNBOUNDED1[..], + BaseName::Sqrt => &EitherPrim::SQRT[..], + BaseName::Tan => &EitherPrim::TRIG[..], + BaseName::Tanh => &EitherPrim::UNBOUNDED1[..], + BaseName::Tgamma => &EitherPrim::GAMMA[..], + BaseName::Trunc => &EitherPrim::UNBOUNDED1[..], + BaseName::Y0 => &EitherPrim::UNBOUNDED1[..], + BaseName::Y1 => &EitherPrim::UNBOUNDED1[..], + BaseName::Yn => &EitherPrim::BESSEL_N[..], + }; + + x[argnum].clone() +} diff --git a/library/compiler-builtins/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm-test/src/f8_impl.rs new file mode 100644 index 00000000000..ddb7bf90e7f --- /dev/null +++ b/library/compiler-builtins/libm-test/src/f8_impl.rs @@ -0,0 +1,503 @@ +//! An IEEE-compliant 8-bit float type for testing purposes. + +use std::cmp::{self, Ordering}; +use std::{fmt, ops}; + +use crate::Float; + +/// Sometimes verifying float logic is easiest when all values can quickly be checked exhaustively +/// or by hand. +/// +/// IEEE-754 compliant type that includes a 1 bit sign, 4 bit exponent, and 3 bit significand. +/// Bias is -7. +/// +/// Based on . +#[derive(Clone, Copy)] +#[repr(transparent)] +#[allow(non_camel_case_types)] +pub struct f8(u8); + +impl Float for f8 { + type Int = u8; + type SignedInt = i8; + + const ZERO: Self = Self(0b0_0000_000); + const NEG_ZERO: Self = Self(0b1_0000_000); + const ONE: Self = Self(0b0_0111_000); + const NEG_ONE: Self = Self(0b1_0111_000); + const MAX: Self = Self(0b0_1110_111); + const MIN: Self = Self(0b1_1110_111); + const INFINITY: Self = Self(0b0_1111_000); + const NEG_INFINITY: Self = Self(0b1_1111_000); + const NAN: Self = Self(0b0_1111_100); + const NEG_NAN: Self = Self(0b1_1111_100); + const MIN_POSITIVE_NORMAL: Self = Self(1 << Self::SIG_BITS); + // FIXME: incorrect values + const EPSILON: Self = Self::ZERO; + const PI: Self = Self::ZERO; + const NEG_PI: Self = Self::ZERO; + const FRAC_PI_2: Self = Self::ZERO; + + const BITS: u32 = 8; + const SIG_BITS: u32 = 3; + const SIGN_MASK: Self::Int = 0b1_0000_000; + const SIG_MASK: Self::Int = 0b0_0000_111; + const EXP_MASK: Self::Int = 0b0_1111_000; + const IMPLICIT_BIT: Self::Int = 0b0_0001_000; + + fn to_bits(self) -> Self::Int { + self.0 + } + + fn to_bits_signed(self) -> Self::SignedInt { + self.0 as i8 + } + + fn is_nan(self) -> bool { + self.0 & Self::EXP_MASK == Self::EXP_MASK && self.0 & Self::SIG_MASK != 0 + } + + fn is_infinite(self) -> bool { + self.0 & Self::EXP_MASK == Self::EXP_MASK && self.0 & Self::SIG_MASK == 0 + } + + fn is_sign_negative(self) -> bool { + self.0 & Self::SIGN_MASK != 0 + } + + fn from_bits(a: Self::Int) -> Self { + Self(a) + } + + fn abs(self) -> Self { + libm::generic::fabs(self) + } + + fn copysign(self, other: Self) -> Self { + libm::generic::copysign(self, other) + } + + fn fma(self, _y: Self, _z: Self) -> Self { + unimplemented!() + } + + fn normalize(_significand: Self::Int) -> (i32, Self::Int) { + unimplemented!() + } +} + +impl f8 { + pub const ALL_LEN: usize = 240; + + /// All non-infinite non-NaN values of `f8` + pub const ALL: [Self; Self::ALL_LEN] = [ + // -m*2^7 + Self(0b1_1110_111), // -240 + Self(0b1_1110_110), + Self(0b1_1110_101), + Self(0b1_1110_100), + Self(0b1_1110_011), + Self(0b1_1110_010), + Self(0b1_1110_001), + Self(0b1_1110_000), // -128 + // -m*2^6 + Self(0b1_1101_111), // -120 + Self(0b1_1101_110), + Self(0b1_1101_101), + Self(0b1_1101_100), + Self(0b1_1101_011), + Self(0b1_1101_010), + Self(0b1_1101_001), + Self(0b1_1101_000), // -64 + // -m*2^5 + Self(0b1_1100_111), // -60 + Self(0b1_1100_110), + Self(0b1_1100_101), + Self(0b1_1100_100), + Self(0b1_1100_011), + Self(0b1_1100_010), + Self(0b1_1100_001), + Self(0b1_1100_000), // -32 + // -m*2^4 + Self(0b1_1011_111), // -30 + Self(0b1_1011_110), + Self(0b1_1011_101), + Self(0b1_1011_100), + Self(0b1_1011_011), + Self(0b1_1011_010), + Self(0b1_1011_001), + Self(0b1_1011_000), // -16 + // -m*2^3 + Self(0b1_1010_111), // -15 + Self(0b1_1010_110), + Self(0b1_1010_101), + Self(0b1_1010_100), + Self(0b1_1010_011), + Self(0b1_1010_010), + Self(0b1_1010_001), + Self(0b1_1010_000), // -8 + // -m*2^2 + Self(0b1_1001_111), // -7.5 + Self(0b1_1001_110), + Self(0b1_1001_101), + Self(0b1_1001_100), + Self(0b1_1001_011), + Self(0b1_1001_010), + Self(0b1_1001_001), + Self(0b1_1001_000), // -4 + // -m*2^1 + Self(0b1_1000_111), // -3.75 + Self(0b1_1000_110), + Self(0b1_1000_101), + Self(0b1_1000_100), + Self(0b1_1000_011), + Self(0b1_1000_010), + Self(0b1_1000_001), + Self(0b1_1000_000), // -2 + // -m*2^0 + Self(0b1_0111_111), // -1.875 + Self(0b1_0111_110), + Self(0b1_0111_101), + Self(0b1_0111_100), + Self(0b1_0111_011), + Self(0b1_0111_010), + Self(0b1_0111_001), + Self(0b1_0111_000), // -1 + // -m*2^-1 + Self(0b1_0110_111), // −0.9375 + Self(0b1_0110_110), + Self(0b1_0110_101), + Self(0b1_0110_100), + Self(0b1_0110_011), + Self(0b1_0110_010), + Self(0b1_0110_001), + Self(0b1_0110_000), // -0.5 + // -m*2^-2 + Self(0b1_0101_111), // −0.46875 + Self(0b1_0101_110), + Self(0b1_0101_101), + Self(0b1_0101_100), + Self(0b1_0101_011), + Self(0b1_0101_010), + Self(0b1_0101_001), + Self(0b1_0101_000), // -0.25 + // -m*2^-3 + Self(0b1_0100_111), // −0.234375 + Self(0b1_0100_110), + Self(0b1_0100_101), + Self(0b1_0100_100), + Self(0b1_0100_011), + Self(0b1_0100_010), + Self(0b1_0100_001), + Self(0b1_0100_000), // -0.125 + // -m*2^-4 + Self(0b1_0011_111), // −0.1171875 + Self(0b1_0011_110), + Self(0b1_0011_101), + Self(0b1_0011_100), + Self(0b1_0011_011), + Self(0b1_0011_010), + Self(0b1_0011_001), + Self(0b1_0011_000), // −0.0625 + // -m*2^-5 + Self(0b1_0010_111), // −0.05859375 + Self(0b1_0010_110), + Self(0b1_0010_101), + Self(0b1_0010_100), + Self(0b1_0010_011), + Self(0b1_0010_010), + Self(0b1_0010_001), + Self(0b1_0010_000), // −0.03125 + // -m*2^-6 + Self(0b1_0001_111), // −0.029296875 + Self(0b1_0001_110), + Self(0b1_0001_101), + Self(0b1_0001_100), + Self(0b1_0001_011), + Self(0b1_0001_010), + Self(0b1_0001_001), + Self(0b1_0001_000), // −0.015625 + // -m*2^-7 subnormal numbers + Self(0b1_0000_111), // −0.013671875 + Self(0b1_0000_110), + Self(0b1_0000_101), + Self(0b1_0000_100), + Self(0b1_0000_011), + Self(0b1_0000_010), + Self(0b1_0000_001), // −0.001953125 + // Zeroes + Self(0b1_0000_000), // -0.0 + Self(0b0_0000_000), // 0.0 + // m*2^-7 // subnormal numbers + Self(0b0_0000_001), + Self(0b0_0000_010), + Self(0b0_0000_011), + Self(0b0_0000_100), + Self(0b0_0000_101), + Self(0b0_0000_110), + Self(0b0_0000_111), // 0.013671875 + // m*2^-6 + Self(0b0_0001_000), // 0.015625 + Self(0b0_0001_001), + Self(0b0_0001_010), + Self(0b0_0001_011), + Self(0b0_0001_100), + Self(0b0_0001_101), + Self(0b0_0001_110), + Self(0b0_0001_111), // 0.029296875 + // m*2^-5 + Self(0b0_0010_000), // 0.03125 + Self(0b0_0010_001), + Self(0b0_0010_010), + Self(0b0_0010_011), + Self(0b0_0010_100), + Self(0b0_0010_101), + Self(0b0_0010_110), + Self(0b0_0010_111), // 0.05859375 + // m*2^-4 + Self(0b0_0011_000), // 0.0625 + Self(0b0_0011_001), + Self(0b0_0011_010), + Self(0b0_0011_011), + Self(0b0_0011_100), + Self(0b0_0011_101), + Self(0b0_0011_110), + Self(0b0_0011_111), // 0.1171875 + // m*2^-3 + Self(0b0_0100_000), // 0.125 + Self(0b0_0100_001), + Self(0b0_0100_010), + Self(0b0_0100_011), + Self(0b0_0100_100), + Self(0b0_0100_101), + Self(0b0_0100_110), + Self(0b0_0100_111), // 0.234375 + // m*2^-2 + Self(0b0_0101_000), // 0.25 + Self(0b0_0101_001), + Self(0b0_0101_010), + Self(0b0_0101_011), + Self(0b0_0101_100), + Self(0b0_0101_101), + Self(0b0_0101_110), + Self(0b0_0101_111), // 0.46875 + // m*2^-1 + Self(0b0_0110_000), // 0.5 + Self(0b0_0110_001), + Self(0b0_0110_010), + Self(0b0_0110_011), + Self(0b0_0110_100), + Self(0b0_0110_101), + Self(0b0_0110_110), + Self(0b0_0110_111), // 0.9375 + // m*2^0 + Self(0b0_0111_000), // 1 + Self(0b0_0111_001), + Self(0b0_0111_010), + Self(0b0_0111_011), + Self(0b0_0111_100), + Self(0b0_0111_101), + Self(0b0_0111_110), + Self(0b0_0111_111), // 1.875 + // m*2^1 + Self(0b0_1000_000), // 2 + Self(0b0_1000_001), + Self(0b0_1000_010), + Self(0b0_1000_011), + Self(0b0_1000_100), + Self(0b0_1000_101), + Self(0b0_1000_110), + Self(0b0_1000_111), // 3.75 + // m*2^2 + Self(0b0_1001_000), // 4 + Self(0b0_1001_001), + Self(0b0_1001_010), + Self(0b0_1001_011), + Self(0b0_1001_100), + Self(0b0_1001_101), + Self(0b0_1001_110), + Self(0b0_1001_111), // 7.5 + // m*2^3 + Self(0b0_1010_000), // 8 + Self(0b0_1010_001), + Self(0b0_1010_010), + Self(0b0_1010_011), + Self(0b0_1010_100), + Self(0b0_1010_101), + Self(0b0_1010_110), + Self(0b0_1010_111), // 15 + // m*2^4 + Self(0b0_1011_000), // 16 + Self(0b0_1011_001), + Self(0b0_1011_010), + Self(0b0_1011_011), + Self(0b0_1011_100), + Self(0b0_1011_101), + Self(0b0_1011_110), + Self(0b0_1011_111), // 30 + // m*2^5 + Self(0b0_1100_000), // 32 + Self(0b0_1100_001), + Self(0b0_1100_010), + Self(0b0_1100_011), + Self(0b0_1100_100), + Self(0b0_1100_101), + Self(0b0_1100_110), + Self(0b0_1100_111), // 60 + // m*2^6 + Self(0b0_1101_000), // 64 + Self(0b0_1101_001), + Self(0b0_1101_010), + Self(0b0_1101_011), + Self(0b0_1101_100), + Self(0b0_1101_101), + Self(0b0_1101_110), + Self(0b0_1101_111), // 120 + // m*2^7 + Self(0b0_1110_000), // 128 + Self(0b0_1110_001), + Self(0b0_1110_010), + Self(0b0_1110_011), + Self(0b0_1110_100), + Self(0b0_1110_101), + Self(0b0_1110_110), + Self(0b0_1110_111), // 240 + ]; +} + +impl ops::Add for f8 { + type Output = Self; + fn add(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} + +impl ops::Sub for f8 { + type Output = Self; + fn sub(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} +impl ops::Mul for f8 { + type Output = Self; + fn mul(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} +impl ops::Div for f8 { + type Output = Self; + fn div(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} + +impl ops::Neg for f8 { + type Output = Self; + fn neg(self) -> Self::Output { + Self(self.0 ^ Self::SIGN_MASK) + } +} + +impl ops::Rem for f8 { + type Output = Self; + fn rem(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} + +impl ops::AddAssign for f8 { + fn add_assign(&mut self, _rhs: Self) { + unimplemented!() + } +} + +impl ops::SubAssign for f8 { + fn sub_assign(&mut self, _rhs: Self) { + unimplemented!() + } +} + +impl ops::MulAssign for f8 { + fn mul_assign(&mut self, _rhs: Self) { + unimplemented!() + } +} + +impl cmp::PartialEq for f8 { + fn eq(&self, other: &Self) -> bool { + if self.is_nan() || other.is_nan() { + false + } else if self.abs().to_bits() | other.abs().to_bits() == 0 { + true + } else { + self.0 == other.0 + } + } +} +impl cmp::PartialOrd for f8 { + fn partial_cmp(&self, other: &Self) -> Option { + let inf_rep = f8::EXP_MASK; + + let a_abs = self.abs().to_bits(); + let b_abs = other.abs().to_bits(); + + // If either a or b is NaN, they are unordered. + if a_abs > inf_rep || b_abs > inf_rep { + return None; + } + + // If a and b are both zeros, they are equal. + if a_abs | b_abs == 0 { + return Some(Ordering::Equal); + } + + let a_srep = self.to_bits_signed(); + let b_srep = other.to_bits_signed(); + let res = a_srep.cmp(&b_srep); + + if a_srep & b_srep >= 0 { + // If at least one of a and b is positive, we get the same result comparing + // a and b as signed integers as we would with a fp_ting-point compare. + Some(res) + } else { + // Otherwise, both are negative, so we need to flip the sense of the + // comparison to get the correct result. + Some(res.reverse()) + } + } +} +impl fmt::Display for f8 { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() + } +} + +impl fmt::Debug for f8 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Binary::fmt(self, f) + } +} + +impl fmt::Binary for f8 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let v = self.0; + write!( + f, + "0b{:b}_{:04b}_{:03b}", + v >> 7, + (v & Self::EXP_MASK) >> Self::SIG_BITS, + v & Self::SIG_MASK + ) + } +} + +impl fmt::LowerHex for f8 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +pub const fn hf8(s: &str) -> f8 { + let Ok(bits) = libm::support::hex_float::parse_hex_exact(s, 8, 3) else { panic!() }; + f8(bits as u8) +} diff --git a/library/compiler-builtins/libm-test/src/generate.rs b/library/compiler-builtins/libm-test/src/generate.rs new file mode 100644 index 00000000000..89ca09a7a0b --- /dev/null +++ b/library/compiler-builtins/libm-test/src/generate.rs @@ -0,0 +1,43 @@ +//! Different generators that can create random or systematic bit patterns. + +pub mod case_list; +pub mod edge_cases; +pub mod random; +pub mod spaced; + +/// A wrapper to turn any iterator into an `ExactSizeIterator`. Asserts the final result to ensure +/// the provided size was correct. +#[derive(Debug)] +pub struct KnownSize { + total: u64, + current: u64, + iter: I, +} + +impl KnownSize { + pub fn new(iter: I, total: u64) -> Self { + Self { total, current: 0, iter } + } +} + +impl Iterator for KnownSize { + type Item = I::Item; + + fn next(&mut self) -> Option { + let next = self.iter.next(); + if next.is_some() { + self.current += 1; + return next; + } + + assert_eq!(self.current, self.total, "total items did not match expected"); + None + } + + fn size_hint(&self) -> (usize, Option) { + let remaining = usize::try_from(self.total - self.current).unwrap(); + (remaining, Some(remaining)) + } +} + +impl ExactSizeIterator for KnownSize {} diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs new file mode 100644 index 00000000000..e3628d51c9a --- /dev/null +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -0,0 +1,853 @@ +//! Test cases to verify specific values. +//! +//! Each routine can have a set of inputs and, optinoally, outputs. If an output is provided, it +//! will be used to check against. If only inputs are provided, the case will be checked against +//! a basis. +//! +//! This is useful for adding regression tests or expected failures. + +use libm::hf64; +#[cfg(f128_enabled)] +use libm::hf128; + +use crate::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; + +pub struct TestCase { + pub input: Op::RustArgs, + pub output: Option, +} + +impl TestCase { + #[expect(dead_code)] + fn append_inputs(v: &mut Vec, l: &[Op::RustArgs]) { + v.extend(l.iter().copied().map(|input| Self { input, output: None })); + } + + fn append_pairs(v: &mut Vec, l: &[(Op::RustArgs, Option)]) + where + Op::RustRet: Copy, + { + v.extend(l.iter().copied().map(|(input, output)| Self { input, output })); + } +} + +fn acos_cases() -> Vec> { + vec![] +} + +fn acosf_cases() -> Vec> { + vec![] +} + +fn acosh_cases() -> Vec> { + vec![] +} + +fn acoshf_cases() -> Vec> { + vec![] +} + +fn asin_cases() -> Vec> { + vec![] +} + +fn asinf_cases() -> Vec> { + vec![] +} + +fn asinh_cases() -> Vec> { + vec![] +} + +fn asinhf_cases() -> Vec> { + vec![] +} + +fn atan_cases() -> Vec> { + vec![] +} + +fn atan2_cases() -> Vec> { + vec![] +} + +fn atan2f_cases() -> Vec> { + vec![] +} + +fn atanf_cases() -> Vec> { + vec![] +} + +fn atanh_cases() -> Vec> { + vec![] +} + +fn atanhf_cases() -> Vec> { + vec![] +} + +fn cbrt_cases() -> Vec> { + vec![] +} + +fn cbrtf_cases() -> Vec> { + vec![] +} + +fn ceil_cases() -> Vec> { + vec![] +} + +fn ceilf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ceilf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn ceilf16_cases() -> Vec> { + vec![] +} + +fn copysign_cases() -> Vec> { + vec![] +} + +fn copysignf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn copysignf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn copysignf16_cases() -> Vec> { + vec![] +} + +fn cos_cases() -> Vec> { + vec![] +} + +fn cosf_cases() -> Vec> { + vec![] +} + +fn cosh_cases() -> Vec> { + vec![] +} + +fn coshf_cases() -> Vec> { + vec![] +} + +fn erf_cases() -> Vec> { + vec![] +} + +fn erfc_cases() -> Vec> { + vec![] +} + +fn erfcf_cases() -> Vec> { + vec![] +} + +fn erff_cases() -> Vec> { + vec![] +} + +fn exp_cases() -> Vec> { + vec![] +} + +fn exp10_cases() -> Vec> { + vec![] +} + +fn exp10f_cases() -> Vec> { + vec![] +} + +fn exp2_cases() -> Vec> { + vec![] +} + +fn exp2f_cases() -> Vec> { + vec![] +} + +fn expf_cases() -> Vec> { + vec![] +} + +fn expm1_cases() -> Vec> { + vec![] +} + +fn expm1f_cases() -> Vec> { + vec![] +} + +fn fabs_cases() -> Vec> { + vec![] +} + +fn fabsf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fabsf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fabsf16_cases() -> Vec> { + vec![] +} + +fn fdim_cases() -> Vec> { + vec![] +} + +fn fdimf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fdimf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fdimf16_cases() -> Vec> { + vec![] +} + +fn floor_cases() -> Vec> { + vec![] +} + +fn floorf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn floorf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn floorf16_cases() -> Vec> { + vec![] +} + +fn fma_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Previous failure with incorrect sign + ((5e-324, -5e-324, 0.0), Some(-0.0)), + ], + ); + v +} + +fn fmaf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmaf128_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + ( + // Tricky rounding case that previously failed in extensive tests + ( + hf128!("-0x1.1966cc01966cc01966cc01966f06p-25"), + hf128!("-0x1.669933fe69933fe69933fe6997c9p-16358"), + hf128!("-0x0.000000000000000000000000048ap-16382"), + ), + Some(hf128!("0x0.c5171470a3ff5e0f68d751491b18p-16382")), + ), + ( + // Subnormal edge case that caused a failure + ( + hf128!("0x0.7ffffffffffffffffffffffffff7p-16382"), + hf128!("0x1.ffffffffffffffffffffffffffffp-1"), + hf128!("0x0.8000000000000000000000000009p-16382"), + ), + Some(hf128!("0x1.0000000000000000000000000000p-16382")), + ), + ], + ); + v +} + +#[cfg(f16_enabled)] +fn fmaxf16_cases() -> Vec> { + vec![] +} + +fn fmaxf_cases() -> Vec> { + vec![] +} + +fn fmax_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmaxf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fmaximumf16_cases() -> Vec> { + vec![] +} + +fn fmaximumf_cases() -> Vec> { + vec![] +} + +fn fmaximum_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmaximumf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fmaximum_numf16_cases() -> Vec> { + vec![] +} + +fn fmaximum_numf_cases() -> Vec> { + vec![] +} + +fn fmaximum_num_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmaximum_numf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fminf16_cases() -> Vec> { + vec![] +} + +fn fminf_cases() -> Vec> { + vec![] +} + +fn fmin_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fminf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fminimumf16_cases() -> Vec> { + vec![] +} + +fn fminimumf_cases() -> Vec> { + vec![] +} + +fn fminimum_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fminimumf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fminimum_numf16_cases() -> Vec> { + vec![] +} + +fn fminimum_numf_cases() -> Vec> { + vec![] +} + +fn fminimum_num_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fminimum_numf128_cases() -> Vec> { + vec![] +} + +fn fmod_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Previous failure with incorrect loop iteration + // + ((2.1, 3.123e-320), Some(2.0696e-320)), + ((2.1, 2.253547e-318), Some(1.772535e-318)), + ], + ); + v +} + +fn fmodf_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Previous failure with incorrect loop iteration + // + ((2.1, 8.858e-42), Some(8.085e-42)), + ((2.1, 6.39164e-40), Some(6.1636e-40)), + ((5.5, 6.39164e-40), Some(4.77036e-40)), + ((-151.189, 6.39164e-40), Some(-5.64734e-40)), + ], + ); + v +} + +#[cfg(f128_enabled)] +fn fmodf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fmodf16_cases() -> Vec> { + vec![] +} + +fn frexp_cases() -> Vec> { + vec![] +} + +fn frexpf_cases() -> Vec> { + vec![] +} + +fn hypot_cases() -> Vec> { + vec![] +} + +fn hypotf_cases() -> Vec> { + vec![] +} + +fn ilogb_cases() -> Vec> { + vec![] +} + +fn ilogbf_cases() -> Vec> { + vec![] +} + +fn j0_cases() -> Vec> { + vec![] +} + +fn j0f_cases() -> Vec> { + vec![] +} + +fn j1_cases() -> Vec> { + vec![] +} + +fn j1f_cases() -> Vec> { + vec![] +} + +fn jn_cases() -> Vec> { + vec![] +} + +fn jnf_cases() -> Vec> { + vec![] +} + +fn ldexp_cases() -> Vec> { + vec![] +} + +fn ldexpf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ldexpf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn ldexpf16_cases() -> Vec> { + vec![] +} + +fn lgamma_cases() -> Vec> { + vec![] +} + +fn lgamma_r_cases() -> Vec> { + vec![] +} + +fn lgammaf_cases() -> Vec> { + vec![] +} + +fn lgammaf_r_cases() -> Vec> { + vec![] +} + +fn log_cases() -> Vec> { + vec![] +} + +fn log10_cases() -> Vec> { + vec![] +} + +fn log10f_cases() -> Vec> { + vec![] +} + +fn log1p_cases() -> Vec> { + vec![] +} + +fn log1pf_cases() -> Vec> { + vec![] +} + +fn log2_cases() -> Vec> { + vec![] +} + +fn log2f_cases() -> Vec> { + vec![] +} + +fn logf_cases() -> Vec> { + vec![] +} + +fn modf_cases() -> Vec> { + vec![] +} + +fn modff_cases() -> Vec> { + vec![] +} + +fn nextafter_cases() -> Vec> { + vec![] +} + +fn nextafterf_cases() -> Vec> { + vec![] +} + +fn pow_cases() -> Vec> { + vec![] +} + +fn powf_cases() -> Vec> { + vec![] +} + +fn remainder_cases() -> Vec> { + vec![] +} + +fn remainderf_cases() -> Vec> { + vec![] +} + +fn remquo_cases() -> Vec> { + vec![] +} + +fn remquof_cases() -> Vec> { + vec![] +} + +fn rint_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Known failure on i586 + #[cfg(not(x86_no_sse))] + ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), + #[cfg(x86_no_sse)] + ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))), + ], + ); + v +} + +fn rintf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn rintf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn rintf16_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn roundf16_cases() -> Vec> { + vec![] +} + +fn round_cases() -> Vec> { + vec![] +} + +fn roundf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn roundf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn roundevenf16_cases() -> Vec> { + vec![] +} + +fn roundeven_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Known failure on i586 + #[cfg(not(x86_no_sse))] + ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), + #[cfg(x86_no_sse)] + ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))), + ], + ); + v +} + +fn roundevenf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn roundevenf128_cases() -> Vec> { + vec![] +} + +fn scalbn_cases() -> Vec> { + vec![] +} + +fn scalbnf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn scalbnf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn scalbnf16_cases() -> Vec> { + vec![] +} + +fn sin_cases() -> Vec> { + vec![] +} + +fn sincos_cases() -> Vec> { + vec![] +} + +fn sincosf_cases() -> Vec> { + vec![] +} + +fn sinf_cases() -> Vec> { + vec![] +} + +fn sinh_cases() -> Vec> { + vec![] +} + +fn sinhf_cases() -> Vec> { + vec![] +} + +fn sqrt_cases() -> Vec> { + vec![] +} + +fn sqrtf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn sqrtf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn sqrtf16_cases() -> Vec> { + vec![] +} + +fn tan_cases() -> Vec> { + vec![] +} + +fn tanf_cases() -> Vec> { + vec![] +} + +fn tanh_cases() -> Vec> { + vec![] +} + +fn tanhf_cases() -> Vec> { + vec![] +} + +fn tgamma_cases() -> Vec> { + vec![] +} + +fn tgammaf_cases() -> Vec> { + vec![] +} + +fn trunc_cases() -> Vec> { + vec![] +} + +fn truncf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn truncf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn truncf16_cases() -> Vec> { + vec![] +} + +fn y0_cases() -> Vec> { + vec![] +} + +fn y0f_cases() -> Vec> { + vec![] +} + +fn y1_cases() -> Vec> { + vec![] +} + +fn y1f_cases() -> Vec> { + vec![] +} + +fn yn_cases() -> Vec> { + vec![] +} + +fn ynf_cases() -> Vec> { + vec![] +} + +pub trait CaseListInput: MathOp + Sized { + fn get_cases() -> Vec>; +} + +macro_rules! impl_case_list { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + ) => { + paste::paste! { + $(#[$attr])* + impl CaseListInput for crate::op::$fn_name::Routine { + fn get_cases() -> Vec> { + [< $fn_name _cases >]() + } + } + } + }; +} + +libm_macros::for_each_function! { + callback: impl_case_list, +} + +/// This is the test generator for standalone tests, i.e. those with no basis. For this, it +/// only extracts tests with a known output. +pub fn get_test_cases_standalone( + ctx: &CheckCtx, +) -> impl Iterator + use<'_, Op> +where + Op: MathOp + CaseListInput, +{ + assert_eq!(ctx.basis, CheckBasis::None); + assert_eq!(ctx.gen_kind, GeneratorKind::List); + Op::get_cases().into_iter().filter_map(|x| x.output.map(|o| (x.input, o))) +} + +/// Opposite of the above; extract only test cases that don't have a known output, to be run +/// against a basis. +pub fn get_test_cases_basis( + ctx: &CheckCtx, +) -> (impl Iterator + use<'_, Op>, u64) +where + Op: MathOp + CaseListInput, +{ + assert_ne!(ctx.basis, CheckBasis::None); + assert_eq!(ctx.gen_kind, GeneratorKind::List); + + let cases = Op::get_cases(); + let count: u64 = cases.iter().filter(|case| case.output.is_none()).count().try_into().unwrap(); + + (cases.into_iter().filter(|x| x.output.is_none()).map(|x| x.input), count) +} diff --git a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs new file mode 100644 index 00000000000..56cc9fa9a70 --- /dev/null +++ b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs @@ -0,0 +1,310 @@ +//! A generator that checks a handful of cases near infinities, zeros, asymptotes, and NaNs. + +use libm::support::{CastInto, Float, Int, MinInt}; + +use crate::domain::get_domain; +use crate::generate::KnownSize; +use crate::op::OpITy; +use crate::run_cfg::{check_near_count, check_point_count}; +use crate::{BaseName, CheckCtx, FloatExt, FloatTy, MathOp, test_log}; + +/// Generate a sequence of edge cases, e.g. numbers near zeroes and infiniteis. +pub trait EdgeCaseInput { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); +} + +/// Create a list of values around interesting points (infinities, zeroes, NaNs). +fn float_edge_cases( + ctx: &CheckCtx, + argnum: usize, +) -> (impl Iterator + Clone, u64) +where + Op: MathOp, +{ + let mut ret = Vec::new(); + let one = OpITy::::ONE; + let values = &mut ret; + let domain = get_domain::<_, i8>(ctx.fn_ident, argnum).unwrap_float(); + let domain_start = domain.range_start(); + let domain_end = domain.range_end(); + + let check_points = check_point_count(ctx); + let near_points = check_near_count(ctx); + + // Check near some notable constants + count_up(Op::FTy::ONE, near_points, values); + count_up(Op::FTy::ZERO, near_points, values); + count_up(Op::FTy::NEG_ONE, near_points, values); + count_down(Op::FTy::ONE, near_points, values); + count_down(Op::FTy::ZERO, near_points, values); + count_down(Op::FTy::NEG_ONE, near_points, values); + values.push(Op::FTy::NEG_ZERO); + + // Check values near the extremes + count_up(Op::FTy::NEG_INFINITY, near_points, values); + count_down(Op::FTy::INFINITY, near_points, values); + count_down(domain_end, near_points, values); + count_up(domain_start, near_points, values); + count_down(domain_start, near_points, values); + count_up(domain_end, near_points, values); + count_down(domain_end, near_points, values); + + // Check some special values that aren't included in the above ranges + values.push(Op::FTy::NAN); + values.extend(Op::FTy::consts().iter()); + + // Check around the maximum subnormal value + let sub_max = Op::FTy::from_bits(Op::FTy::SIG_MASK); + count_up(sub_max, near_points, values); + count_down(sub_max, near_points, values); + count_up(-sub_max, near_points, values); + count_down(-sub_max, near_points, values); + + // Check a few values around the subnormal range + for shift in (0..Op::FTy::SIG_BITS).step_by(Op::FTy::SIG_BITS as usize / 5) { + let v = Op::FTy::from_bits(one << shift); + count_up(v, 2, values); + count_down(v, 2, values); + count_up(-v, 2, values); + count_down(-v, 2, values); + } + + // Check around asymptotes + if let Some(f) = domain.check_points { + let iter = f(); + for x in iter.take(check_points) { + count_up(x, near_points, values); + count_down(x, near_points, values); + } + } + + // Some results may overlap so deduplicate the vector to save test cycles. + values.sort_by_key(|x| x.to_bits()); + values.dedup_by_key(|x| x.to_bits()); + + let count = ret.len().try_into().unwrap(); + + test_log(&format!( + "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {count} edge cases", + gen_kind = ctx.gen_kind, + basis = ctx.basis, + fn_ident = ctx.fn_ident, + arg = argnum + 1, + args = ctx.input_count(), + )); + + (ret.into_iter(), count) +} + +/// Add `points` values starting at and including `x` and counting up. Uses the smallest possible +/// increments (1 ULP). +fn count_up(mut x: F, points: u64, values: &mut Vec) { + assert!(!x.is_nan()); + + let mut count = 0; + while x < F::INFINITY && count < points { + values.push(x); + x = x.next_up(); + count += 1; + } +} + +/// Add `points` values starting at and including `x` and counting down. Uses the smallest possible +/// increments (1 ULP). +fn count_down(mut x: F, points: u64, values: &mut Vec) { + assert!(!x.is_nan()); + + let mut count = 0; + while x > F::NEG_INFINITY && count < points { + values.push(x); + x = x.next_down(); + count += 1; + } +} + +/// Create a list of values around interesting integer points (min, zero, max). +pub fn int_edge_cases( + ctx: &CheckCtx, + argnum: usize, +) -> (impl Iterator + Clone, u64) +where + i32: CastInto, +{ + let mut values = Vec::new(); + let near_points = check_near_count(ctx); + + // Check around max/min and zero + int_count_around(I::MIN, near_points, &mut values); + int_count_around(I::MAX, near_points, &mut values); + int_count_around(I::ZERO, near_points, &mut values); + int_count_around(I::ZERO, near_points, &mut values); + + if matches!(ctx.base_name, BaseName::Scalbn | BaseName::Ldexp) { + assert_eq!(argnum, 1, "scalbn integer argument should be arg1"); + let (emax, emin, emin_sn) = match ctx.fn_ident.math_op().float_ty { + FloatTy::F16 => { + #[cfg(not(f16_enabled))] + unreachable!(); + #[cfg(f16_enabled)] + (f16::EXP_MAX, f16::EXP_MIN, f16::EXP_MIN_SUBNORM) + } + FloatTy::F32 => (f32::EXP_MAX, f32::EXP_MIN, f32::EXP_MIN_SUBNORM), + FloatTy::F64 => (f64::EXP_MAX, f64::EXP_MIN, f64::EXP_MIN_SUBNORM), + FloatTy::F128 => { + #[cfg(not(f128_enabled))] + unreachable!(); + #[cfg(f128_enabled)] + (f128::EXP_MAX, f128::EXP_MIN, f128::EXP_MIN_SUBNORM) + } + }; + + // `scalbn`/`ldexp` have their trickiest behavior around exponent limits + int_count_around(emax.cast(), near_points, &mut values); + int_count_around(emin.cast(), near_points, &mut values); + int_count_around(emin_sn.cast(), near_points, &mut values); + int_count_around((-emin_sn).cast(), near_points, &mut values); + + // Also check values that cause the maximum possible difference in exponents + int_count_around((emax - emin).cast(), near_points, &mut values); + int_count_around((emin - emax).cast(), near_points, &mut values); + int_count_around((emax - emin_sn).cast(), near_points, &mut values); + int_count_around((emin_sn - emax).cast(), near_points, &mut values); + } + + values.sort(); + values.dedup(); + let count = values.len().try_into().unwrap(); + + test_log(&format!( + "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {count} edge cases", + gen_kind = ctx.gen_kind, + basis = ctx.basis, + fn_ident = ctx.fn_ident, + arg = argnum + 1, + args = ctx.input_count(), + )); + + (values.into_iter(), count) +} + +/// Add `points` values both up and down, starting at and including `x`. +fn int_count_around(x: I, points: u64, values: &mut Vec) { + let mut current = x; + for _ in 0..points { + values.push(current); + current = match current.checked_add(I::ONE) { + Some(v) => v, + None => break, + }; + } + + current = x; + for _ in 0..points { + values.push(current); + current = match current.checked_sub(I::ONE) { + Some(v) => v, + None => break, + }; + } +} + +macro_rules! impl_edge_case_input { + ($fty:ty) => { + impl EdgeCaseInput for ($fty,) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let (iter0, steps0) = float_edge_cases::(ctx, 0); + let iter0 = iter0.map(|v| (v,)); + (iter0, steps0) + } + } + + impl EdgeCaseInput for ($fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let (iter0, steps0) = float_edge_cases::(ctx, 0); + let (iter1, steps1) = float_edge_cases::(ctx, 1); + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + (iter, count) + } + } + + impl EdgeCaseInput for ($fty, $fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let (iter0, steps0) = float_edge_cases::(ctx, 0); + let (iter1, steps1) = float_edge_cases::(ctx, 1); + let (iter2, steps2) = float_edge_cases::(ctx, 2); + + let iter = iter0 + .flat_map(move |first| iter1.clone().map(move |second| (first, second))) + .flat_map(move |(first, second)| { + iter2.clone().map(move |third| (first, second, third)) + }); + let count = steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); + + (iter, count) + } + } + + impl EdgeCaseInput for (i32, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let (iter0, steps0) = int_edge_cases(ctx, 0); + let (iter1, steps1) = float_edge_cases::(ctx, 1); + + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + + (iter, count) + } + } + + impl EdgeCaseInput for ($fty, i32) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let (iter0, steps0) = float_edge_cases::(ctx, 0); + let (iter1, steps1) = int_edge_cases(ctx, 1); + + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + + (iter, count) + } + } + }; +} + +#[cfg(f16_enabled)] +impl_edge_case_input!(f16); +impl_edge_case_input!(f32); +impl_edge_case_input!(f64); +#[cfg(f128_enabled)] +impl_edge_case_input!(f128); + +pub fn get_test_cases( + ctx: &CheckCtx, +) -> (impl Iterator + Send + use<'_, Op>, u64) +where + Op: MathOp, + Op::RustArgs: EdgeCaseInput, +{ + let (iter, count) = Op::RustArgs::get_cases(ctx); + + // Wrap in `KnownSize` so we get an assertion if the cuunt is wrong. + (KnownSize::new(iter, count), count) +} diff --git a/library/compiler-builtins/libm-test/src/generate/random.rs b/library/compiler-builtins/libm-test/src/generate/random.rs new file mode 100644 index 00000000000..e8a7ee9057e --- /dev/null +++ b/library/compiler-builtins/libm-test/src/generate/random.rs @@ -0,0 +1,125 @@ +use std::env; +use std::ops::RangeInclusive; +use std::sync::LazyLock; + +use libm::support::Float; +use rand::distr::{Alphanumeric, StandardUniform}; +use rand::prelude::Distribution; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; + +use super::KnownSize; +use crate::CheckCtx; +use crate::run_cfg::{int_range, iteration_count}; + +pub(crate) const SEED_ENV: &str = "LIBM_SEED"; + +pub static SEED: LazyLock<[u8; 32]> = LazyLock::new(|| { + let s = env::var(SEED_ENV).unwrap_or_else(|_| { + let mut rng = rand::rng(); + (0..32).map(|_| rng.sample(Alphanumeric) as char).collect() + }); + + s.as_bytes().try_into().unwrap_or_else(|_| { + panic!("Seed must be 32 characters, got `{s}`"); + }) +}); + +/// Generate a sequence of random values of this type. +pub trait RandomInput: Sized { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); +} + +/// Generate a sequence of deterministically random floats. +fn random_floats(count: u64) -> impl Iterator +where + StandardUniform: Distribution, +{ + let mut rng = ChaCha8Rng::from_seed(*SEED); + + // Generate integers to get a full range of bitpatterns (including NaNs), then convert back + // to the float type. + (0..count).map(move |_| F::from_bits(rng.random::())) +} + +/// Generate a sequence of deterministically random `i32`s within a specified range. +fn random_ints(count: u64, range: RangeInclusive) -> impl Iterator { + let mut rng = ChaCha8Rng::from_seed(*SEED); + (0..count).map(move |_| rng.random_range::(range.clone())) +} + +macro_rules! impl_random_input { + ($fty:ty) => { + impl RandomInput for ($fty,) { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let count = iteration_count(ctx, 0); + let iter = random_floats(count).map(|f: $fty| (f,)); + (iter, count) + } + } + + impl RandomInput for ($fty, $fty) { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let iter = random_floats(count0) + .flat_map(move |f1: $fty| random_floats(count1).map(move |f2: $fty| (f1, f2))); + (iter, count0 * count1) + } + } + + impl RandomInput for ($fty, $fty, $fty) { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let count2 = iteration_count(ctx, 2); + let iter = random_floats(count0).flat_map(move |f1: $fty| { + random_floats(count1).flat_map(move |f2: $fty| { + random_floats(count2).map(move |f3: $fty| (f1, f2, f3)) + }) + }); + (iter, count0 * count1 * count2) + } + } + + impl RandomInput for (i32, $fty) { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let range0 = int_range(ctx, 0); + let iter = random_ints(count0, range0) + .flat_map(move |f1: i32| random_floats(count1).map(move |f2: $fty| (f1, f2))); + (iter, count0 * count1) + } + } + + impl RandomInput for ($fty, i32) { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let range1 = int_range(ctx, 1); + let iter = random_floats(count0).flat_map(move |f1: $fty| { + random_ints(count1, range1.clone()).map(move |f2: i32| (f1, f2)) + }); + (iter, count0 * count1) + } + } + }; +} + +#[cfg(f16_enabled)] +impl_random_input!(f16); +impl_random_input!(f32); +impl_random_input!(f64); +#[cfg(f128_enabled)] +impl_random_input!(f128); + +/// Create a test case iterator. +pub fn get_test_cases( + ctx: &CheckCtx, +) -> (impl Iterator + Send + use<'_, RustArgs>, u64) { + let (iter, count) = RustArgs::get_cases(ctx); + + // Wrap in `KnownSize` so we get an assertion if the cuunt is wrong. + (KnownSize::new(iter, count), count) +} diff --git a/library/compiler-builtins/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm-test/src/generate/spaced.rs new file mode 100644 index 00000000000..bea3f4c7e1b --- /dev/null +++ b/library/compiler-builtins/libm-test/src/generate/spaced.rs @@ -0,0 +1,253 @@ +use std::fmt; +use std::ops::RangeInclusive; + +use libm::support::{Float, MinInt}; + +use crate::domain::get_domain; +use crate::op::OpITy; +use crate::run_cfg::{int_range, iteration_count}; +use crate::{CheckCtx, MathOp, linear_ints, logspace}; + +/// Generate a sequence of inputs that eiher cover the domain in completeness (for smaller float +/// types and single argument functions) or provide evenly spaced inputs across the domain with +/// approximately `u32::MAX` total iterations. +pub trait SpacedInput { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); +} + +/// Construct an iterator from `logspace` and also calculate the total number of steps expected +/// for that iterator. +fn logspace_steps( + ctx: &CheckCtx, + argnum: usize, + max_steps: u64, +) -> (impl Iterator + Clone, u64) +where + Op: MathOp, + OpITy: TryFrom, + u64: TryFrom, Error: fmt::Debug>, + RangeInclusive>: Iterator, +{ + // i8 is a dummy type here, it can be any integer. + let domain = get_domain::(ctx.fn_ident, argnum).unwrap_float(); + let start = domain.range_start(); + let end = domain.range_end(); + + let max_steps = OpITy::::try_from(max_steps).unwrap_or(OpITy::::MAX); + let (iter, steps) = logspace(start, end, max_steps); + + // `steps` will be <= the original `max_steps`, which is a `u64`. + (iter, steps.try_into().unwrap()) +} + +/// Represents the iterator in either `Left` or `Right`. +enum EitherIter { + A(A), + B(B), +} + +impl, B: Iterator> Iterator for EitherIter { + type Item = T; + + fn next(&mut self) -> Option { + match self { + Self::A(iter) => iter.next(), + Self::B(iter) => iter.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self { + Self::A(iter) => iter.size_hint(), + Self::B(iter) => iter.size_hint(), + } + } +} + +/// Gets the total number of possible values, returning `None` if that number doesn't fit in a +/// `u64`. +fn value_count() -> Option +where + u64: TryFrom, +{ + u64::try_from(F::Int::MAX).ok().and_then(|max| max.checked_add(1)) +} + +/// Returns an iterator of every possible value of type `F`. +fn all_values() -> impl Iterator +where + RangeInclusive: Iterator, +{ + (F::Int::MIN..=F::Int::MAX).map(|bits| F::from_bits(bits)) +} + +macro_rules! impl_spaced_input { + ($fty:ty) => { + impl SpacedInput for ($fty,) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, 0); + // `f16` and `f32` can have exhaustive tests. + match value_count::() { + Some(steps0) if steps0 <= max_steps0 => { + let iter0 = all_values(); + let iter0 = iter0.map(|v| (v,)); + (EitherIter::A(iter0), steps0) + } + _ => { + let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); + let iter0 = iter0.map(|v| (v,)); + (EitherIter::B(iter0), steps0) + } + } + } + } + + impl SpacedInput for ($fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, 0); + let max_steps1 = iteration_count(ctx, 1); + // `f16` can have exhaustive tests. + match value_count::() { + Some(count) if count <= max_steps0 && count <= max_steps1 => { + let iter = all_values() + .flat_map(|first| all_values().map(move |second| (first, second))); + (EitherIter::A(iter), count.checked_mul(count).unwrap()) + } + _ => { + let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); + let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); + (EitherIter::B(iter), count) + } + } + } + } + + impl SpacedInput for ($fty, $fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, 0); + let max_steps1 = iteration_count(ctx, 1); + let max_steps2 = iteration_count(ctx, 2); + // `f16` can be exhaustive tested if `LIBM_EXTENSIVE_TESTS` is incresed. + match value_count::() { + Some(count) + if count <= max_steps0 && count <= max_steps1 && count <= max_steps2 => + { + let iter = all_values().flat_map(|first| { + all_values().flat_map(move |second| { + all_values().map(move |third| (first, second, third)) + }) + }); + (EitherIter::A(iter), count.checked_pow(3).unwrap()) + } + _ => { + let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); + let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); + let (iter2, steps2) = logspace_steps::(ctx, 2, max_steps2); + + let iter = iter0 + .flat_map(move |first| iter1.clone().map(move |second| (first, second))) + .flat_map(move |(first, second)| { + iter2.clone().map(move |third| (first, second, third)) + }); + let count = + steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); + + (EitherIter::B(iter), count) + } + } + } + } + + impl SpacedInput for (i32, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let range0 = int_range(ctx, 0); + let max_steps0 = iteration_count(ctx, 0); + let max_steps1 = iteration_count(ctx, 1); + match value_count::() { + Some(count1) if count1 <= max_steps1 => { + let (iter0, steps0) = linear_ints(range0, max_steps0); + let iter = iter0 + .flat_map(move |first| all_values().map(move |second| (first, second))); + (EitherIter::A(iter), steps0.checked_mul(count1).unwrap()) + } + _ => { + let (iter0, steps0) = linear_ints(range0, max_steps0); + let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); + + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); + + (EitherIter::B(iter), count) + } + } + } + } + + impl SpacedInput for ($fty, i32) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, 0); + let range1 = int_range(ctx, 1); + let max_steps1 = iteration_count(ctx, 1); + match value_count::() { + Some(count0) if count0 <= max_steps0 => { + let (iter1, steps1) = linear_ints(range1, max_steps1); + let iter = all_values().flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + (EitherIter::A(iter), count0.checked_mul(steps1).unwrap()) + } + _ => { + let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); + let (iter1, steps1) = linear_ints(range1, max_steps1); + + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); + + (EitherIter::B(iter), count) + } + } + } + } + }; +} + +#[cfg(f16_enabled)] +impl_spaced_input!(f16); +impl_spaced_input!(f32); +impl_spaced_input!(f64); +#[cfg(f128_enabled)] +impl_spaced_input!(f128); + +/// Create a test case iterator for extensive inputs. Also returns the total test case count. +pub fn get_test_cases( + ctx: &CheckCtx, +) -> (impl Iterator + Send + use<'_, Op>, u64) +where + Op: MathOp, + Op::RustArgs: SpacedInput, +{ + Op::RustArgs::get_cases(ctx) +} diff --git a/library/compiler-builtins/libm-test/src/lib.rs b/library/compiler-builtins/libm-test/src/lib.rs new file mode 100644 index 00000000000..485c01a4782 --- /dev/null +++ b/library/compiler-builtins/libm-test/src/lib.rs @@ -0,0 +1,105 @@ +#![cfg_attr(f16_enabled, feature(f16))] +#![cfg_attr(f128_enabled, feature(f128))] +#![allow(clippy::unusual_byte_groupings)] // sometimes we group by sign_exp_sig + +pub mod domain; +mod f8_impl; +pub mod generate; +#[cfg(feature = "build-mpfr")] +pub mod mpfloat; +mod num; +pub mod op; +mod precision; +mod run_cfg; +mod test_traits; + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; +use std::sync::LazyLock; +use std::time::SystemTime; + +pub use f8_impl::{f8, hf8}; +pub use libm::support::{Float, Int, IntTy, MinInt}; +pub use num::{FloatExt, linear_ints, logspace}; +pub use op::{ + BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustArgs, OpRustFn, OpRustRet, + Ty, +}; +pub use precision::{MaybeOverride, SpecialCase, default_ulp}; +use run_cfg::extensive_max_iterations; +pub use run_cfg::{ + CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, bigint_fuzz_iteration_count, + skip_extensive_test, +}; +pub use test_traits::{CheckOutput, Hex, TupleCall}; + +/// Result type for tests is usually from `anyhow`. Most times there is no success value to +/// propagate. +pub type TestResult = Result; + +/// True if `EMULATED` is set and nonempty. Used to determine how many iterations to run. +pub const fn emulated() -> bool { + match option_env!("EMULATED") { + Some(s) if s.is_empty() => false, + None => false, + Some(_) => true, + } +} + +/// True if `CI` is set and nonempty. +pub const fn ci() -> bool { + match option_env!("CI") { + Some(s) if s.is_empty() => false, + None => false, + Some(_) => true, + } +} + +/// Print to stderr and additionally log it to `target/test-log.txt`. This is useful for saving +/// output that would otherwise be consumed by the test harness. +pub fn test_log(s: &str) { + // Handle to a file opened in append mode, unless a suitable path can't be determined. + static OUTFILE: LazyLock> = LazyLock::new(|| { + // If the target directory is overridden, use that environment variable. Otherwise, save + // at the default path `{workspace_root}/target`. + let target_dir = match env::var("CARGO_TARGET_DIR") { + Ok(s) => PathBuf::from(s), + Err(_) => { + let Ok(x) = env::var("CARGO_MANIFEST_DIR") else { + return None; + }; + + PathBuf::from(x).parent().unwrap().parent().unwrap().join("target") + } + }; + let outfile = target_dir.join("test-log.txt"); + + let mut f = File::options() + .create(true) + .append(true) + .open(outfile) + .expect("failed to open logfile"); + let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); + + writeln!(f, "\n\nTest run at {}", now.as_secs()).unwrap(); + writeln!(f, "arch: {}", env::consts::ARCH).unwrap(); + writeln!(f, "os: {}", env::consts::OS).unwrap(); + writeln!(f, "bits: {}", usize::BITS).unwrap(); + writeln!(f, "emulated: {}", emulated()).unwrap(); + writeln!(f, "ci: {}", ci()).unwrap(); + writeln!(f, "cargo features: {}", env!("CFG_CARGO_FEATURES")).unwrap(); + writeln!(f, "opt level: {}", env!("CFG_OPT_LEVEL")).unwrap(); + writeln!(f, "target features: {}", env!("CFG_TARGET_FEATURES")).unwrap(); + writeln!(f, "extensive iterations {}", extensive_max_iterations()).unwrap(); + + Some(f) + }); + + eprintln!("{s}"); + + if let Some(mut f) = OUTFILE.as_ref() { + writeln!(f, "{s}").unwrap(); + } +} diff --git a/library/compiler-builtins/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm-test/src/mpfloat.rs new file mode 100644 index 00000000000..9b51dc6051d --- /dev/null +++ b/library/compiler-builtins/libm-test/src/mpfloat.rs @@ -0,0 +1,603 @@ +//! Interfaces needed to support testing with multi-precision floating point numbers. +//! +//! Within this module, the macros create a submodule for each `libm` function. These contain +//! a struct named `Operation` that implements [`MpOp`]. + +use std::cmp::Ordering; + +use rug::Assign; +pub use rug::Float as MpFloat; +use rug::az::{self, Az}; +use rug::float::Round::Nearest; +use rug::ops::{PowAssignRound, RemAssignRound}; + +use crate::{Float, MathOp}; + +/// Create a multiple-precision float with the correct number of bits for a concrete float type. +fn new_mpfloat() -> MpFloat { + MpFloat::new(F::SIG_BITS + 1) +} + +/// Set subnormal emulation and convert to a concrete float type. +fn prep_retval(mp: &mut MpFloat, ord: Ordering) -> F +where + for<'a> &'a MpFloat: az::Cast, +{ + mp.subnormalize_ieee_round(ord, Nearest); + (&*mp).az::() +} + +/// Structures that represent a float operation. +/// +pub trait MpOp: MathOp { + /// The struct itself should hold any context that can be reused among calls to `run` (allocated + /// `MpFloat`s). + type MpTy; + + /// Create a new instance. + fn new_mp() -> Self::MpTy; + + /// Perform the operation. + /// + /// Usually this means assigning inputs to cached floats, performing the operation, applying + /// subnormal approximation, and converting the result back to concrete values. + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet; +} + +/// Implement `MpOp` for functions with a single return value. +macro_rules! impl_mp_op { + // Matcher for unary functions + ( + fn_name: $fn_name:ident, + RustFn: fn($_fty:ty,) -> $_ret:ty, + attrs: [$($attr:meta),*], + fn_extra: $fn_name_normalized:expr, + ) => { + paste::paste! { + $(#[$attr])* + impl MpOp for crate::op::$fn_name::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + let ord = this.[< $fn_name_normalized _round >](Nearest); + prep_retval::(this, ord) + } + } + } + }; + // Matcher for binary functions + ( + fn_name: $fn_name:ident, + RustFn: fn($_fty:ty, $_fty2:ty,) -> $_ret:ty, + attrs: [$($attr:meta),*], + fn_extra: $fn_name_normalized:expr, + ) => { + paste::paste! { + $(#[$attr])* + impl MpOp for crate::op::$fn_name::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = this.0.[< $fn_name_normalized _round >](&this.1, Nearest); + prep_retval::(&mut this.0, ord) + } + } + } + }; + // Matcher for ternary functions + ( + fn_name: $fn_name:ident, + RustFn: fn($_fty:ty, $_fty2:ty, $_fty3:ty,) -> $_ret:ty, + attrs: [$($attr:meta),*], + fn_extra: $fn_name_normalized:expr, + ) => { + paste::paste! { + $(#[$attr])* + impl MpOp for crate::op::$fn_name::Routine { + type MpTy = (MpFloat, MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + ( + new_mpfloat::(), + new_mpfloat::(), + new_mpfloat::(), + ) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + this.2.assign(input.2); + let ord = this.0.[< $fn_name_normalized _round >](&this.1, &this.2, Nearest); + prep_retval::(&mut this.0, ord) + } + } + } + }; +} + +libm_macros::for_each_function! { + callback: impl_mp_op, + emit_types: [RustFn], + skip: [ + // Most of these need a manual implementation + // verify-sorted-start + ceil, + ceilf, + ceilf128, + ceilf16, + copysign, + copysignf, + copysignf128, + copysignf16, + fabs, + fabsf, + fabsf128, + fabsf16,floor, + floorf, + floorf128, + floorf16, + fmaximum, + fmaximumf, + fmaximumf128, + fmaximumf16, + fminimum, + fminimumf, + fminimumf128, + fminimumf16, + fmod, + fmodf, + fmodf128, + fmodf16, + frexp, + frexpf, + ilogb, + ilogbf, + jn, + jnf, + ldexp, + ldexpf, + ldexpf128, + ldexpf16, + lgamma_r, + lgammaf_r, + modf, + modff, + nextafter, + nextafterf, + pow, + powf,remquo, + remquof, + rint, + rintf, + rintf128, + rintf16, + round, + roundeven, + roundevenf, + roundevenf128, + roundevenf16, + roundf, + roundf128, + roundf16, + scalbn, + scalbnf, + scalbnf128, + scalbnf16, + sincos,sincosf, + trunc, + truncf, + truncf128, + truncf16,yn, + ynf, + // verify-sorted-end + ], + fn_extra: match MACRO_FN_NAME { + // Remap function names that are different between mpfr and libm + expm1 | expm1f => exp_m1, + fabs | fabsf => abs, + fdim | fdimf | fdimf16 | fdimf128 => positive_diff, + fma | fmaf | fmaf128 => mul_add, + fmax | fmaxf | fmaxf16 | fmaxf128 | + fmaximum_num | fmaximum_numf | fmaximum_numf16 | fmaximum_numf128 => max, + fmin | fminf | fminf16 | fminf128 | + fminimum_num | fminimum_numf | fminimum_numf16 | fminimum_numf128 => min, + lgamma | lgammaf => ln_gamma, + log | logf => ln, + log1p | log1pf => ln_1p, + tgamma | tgammaf => gamma, + _ => MACRO_FN_NAME_NORMALIZED + } +} + +/// Implement unary functions that don't have a `_round` version +macro_rules! impl_no_round { + // Unary matcher + ($($fn_name:ident => $rug_name:ident;)*) => { + paste::paste! { + $( impl_no_round!{ @inner_unary $fn_name, $rug_name } )* + } + }; + + (@inner_unary $fn_name:ident, $rug_name:ident) => { + impl MpOp for crate::op::$fn_name::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + this.$rug_name(); + prep_retval::(this, Ordering::Equal) + } + } + }; +} + +impl_no_round! { + ceil => ceil_mut; + ceilf => ceil_mut; + fabs => abs_mut; + fabsf => abs_mut; + floor => floor_mut; + floorf => floor_mut; + rint => round_even_mut; // FIXME: respect rounding mode + rintf => round_even_mut; // FIXME: respect rounding mode + round => round_mut; + roundeven => round_even_mut; + roundevenf => round_even_mut; + roundf => round_mut; + trunc => trunc_mut; + truncf => trunc_mut; +} + +#[cfg(f16_enabled)] +impl_no_round! { + ceilf16 => ceil_mut; + fabsf16 => abs_mut; + floorf16 => floor_mut; + rintf16 => round_even_mut; // FIXME: respect rounding mode + roundf16 => round_mut; + roundevenf16 => round_even_mut; + truncf16 => trunc_mut; +} + +#[cfg(f128_enabled)] +impl_no_round! { + ceilf128 => ceil_mut; + fabsf128 => abs_mut; + floorf128 => floor_mut; + rintf128 => round_even_mut; // FIXME: respect rounding mode + roundf128 => round_mut; + roundevenf128 => round_even_mut; + truncf128 => trunc_mut; +} + +/// Some functions are difficult to do in a generic way. Implement them here. +macro_rules! impl_op_for_ty { + ($fty:ty, $suffix:literal) => { + paste::paste! { + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(&this.0); + let (ord0, ord1) = this.0.trunc_fract_round(&mut this.1, Nearest); + ( + prep_retval::(&mut this.1, ord0), + prep_retval::(&mut this.0, ord1), + ) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = this.0.pow_assign_round(&this.1, Nearest); + prep_retval::(&mut this.0, ord) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + let exp = this.frexp_mut(); + (prep_retval::(this, Ordering::Equal), exp) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + + // `get_exp` follows `frexp` for `0.5 <= |m| < 1.0`. Adjust the exponent by + // one to scale the significand to `1.0 <= |m| < 2.0`. + this.get_exp().map(|v| v - 1).unwrap_or_else(|| { + if this.is_infinite() { + i32::MAX + } else { + // Zero or NaN + i32::MIN + } + }) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + let (n, x) = input; + this.assign(x); + let ord = this.jn_round(n, Nearest); + prep_retval::(this, ord) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(0.0); + let (sord, cord) = this.0.sin_cos_round(&mut this.1, Nearest); + ( + prep_retval::(&mut this.0, sord), + prep_retval::(&mut this.1, cord) + ) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + ( + new_mpfloat::(), + new_mpfloat::(), + ) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let (ord, q) = this.0.remainder_quo31_round(&this.1, Nearest); + (prep_retval::(&mut this.0, ord), q) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + let (n, x) = input; + this.assign(x); + let ord = this.yn_round(n, Nearest); + prep_retval::(this, ord) + } + } + } + }; +} + +/// Version of `impl_op_for_ty` with only functions that have `f16` and `f128` implementations. +macro_rules! impl_op_for_ty_all { + ($fty:ty, $suffix:literal) => { + paste::paste! { + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + this.0.copysign_mut(&this.1); + prep_retval::(&mut this.0, Ordering::Equal) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = this.0.rem_assign_round(&this.1, Nearest); + prep_retval::(&mut this.0, ord) + + } + } + + impl MpOp for crate::op::[< fmaximum $suffix >]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = if this.0.is_nan() || this.1.is_nan() { + this.0.assign($fty::NAN); + Ordering::Equal + } else { + this.0.max_round(&this.1, Nearest) + }; + prep_retval::(&mut this.0, ord) + } + } + + impl MpOp for crate::op::[< fminimum $suffix >]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = if this.0.is_nan() || this.1.is_nan() { + this.0.assign($fty::NAN); + Ordering::Equal + } else { + this.0.min_round(&this.1, Nearest) + }; + prep_retval::(&mut this.0, ord) + } + } + + // `ldexp` and `scalbn` are the same for binary floating point, so just forward all + // methods. + impl MpOp for crate::op::[]::Routine { + type MpTy = ]::Routine as MpOp>::MpTy; + + fn new_mp() -> Self::MpTy { + ]::Routine as MpOp>::new_mp() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + ]::Routine as MpOp>::run(this, input) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + *this <<= input.1; + prep_retval::(this, Ordering::Equal) + } + } + } + }; +} + +impl_op_for_ty!(f32, "f"); +impl_op_for_ty!(f64, ""); + +#[cfg(f16_enabled)] +impl_op_for_ty_all!(f16, "f16"); +impl_op_for_ty_all!(f32, "f"); +impl_op_for_ty_all!(f64, ""); +#[cfg(f128_enabled)] +impl_op_for_ty_all!(f128, "f128"); + +// `lgamma_r` is not a simple suffix so we can't use the above macro. +impl MpOp for crate::op::lgamma_r::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + let (sign, ord) = this.ln_abs_gamma_round(Nearest); + let ret = prep_retval::(this, ord); + (ret, sign as i32) + } +} + +impl MpOp for crate::op::lgammaf_r::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + let (sign, ord) = this.ln_abs_gamma_round(Nearest); + let ret = prep_retval::(this, ord); + (ret, sign as i32) + } +} + +/* stub implementations so we don't need to special case them */ + +impl MpOp for crate::op::nextafter::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + unimplemented!("nextafter does not yet have a MPFR operation"); + } + + fn run(_this: &mut Self::MpTy, _input: Self::RustArgs) -> Self::RustRet { + unimplemented!("nextafter does not yet have a MPFR operation"); + } +} + +impl MpOp for crate::op::nextafterf::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + unimplemented!("nextafter does not yet have a MPFR operation"); + } + + fn run(_this: &mut Self::MpTy, _input: Self::RustArgs) -> Self::RustRet { + unimplemented!("nextafter does not yet have a MPFR operation"); + } +} diff --git a/library/compiler-builtins/libm-test/src/num.rs b/library/compiler-builtins/libm-test/src/num.rs new file mode 100644 index 00000000000..eed941423d3 --- /dev/null +++ b/library/compiler-builtins/libm-test/src/num.rs @@ -0,0 +1,529 @@ +//! Helpful numeric operations. + +use std::cmp::min; +use std::ops::RangeInclusive; + +use libm::support::Float; + +use crate::{Int, MinInt}; + +/// Extension to `libm`'s `Float` trait with methods that are useful for tests but not +/// needed in `libm` itself. +pub trait FloatExt: Float { + /// The minimum subnormal number. + const TINY_BITS: Self::Int = Self::Int::ONE; + + /// Retrieve additional constants for this float type. + fn consts() -> Consts { + Consts::new() + } + + /// Increment by one ULP, saturating at infinity. + fn next_up(self) -> Self { + let bits = self.to_bits(); + if self.is_nan() || bits == Self::INFINITY.to_bits() { + return self; + } + + let abs = self.abs().to_bits(); + let next_bits = if abs == Self::Int::ZERO { + // Next up from 0 is the smallest subnormal + Self::TINY_BITS + } else if bits == abs { + // Positive: counting up is more positive + bits + Self::Int::ONE + } else { + // Negative: counting down is more positive + bits - Self::Int::ONE + }; + Self::from_bits(next_bits) + } + + /// A faster way to effectively call `next_up` `n` times. + fn n_up(self, n: Self::Int) -> Self { + let bits = self.to_bits(); + if self.is_nan() || bits == Self::INFINITY.to_bits() || n == Self::Int::ZERO { + return self; + } + + let abs = self.abs().to_bits(); + let is_positive = bits == abs; + let crosses_zero = !is_positive && n > abs; + let inf_bits = Self::INFINITY.to_bits(); + + let next_bits = if abs == Self::Int::ZERO { + min(n, inf_bits) + } else if crosses_zero { + min(n - abs, inf_bits) + } else if is_positive { + // Positive, counting up is more positive but this may overflow + match bits.checked_add(n) { + Some(v) if v >= inf_bits => inf_bits, + Some(v) => v, + None => inf_bits, + } + } else { + // Negative, counting down is more positive + bits - n + }; + Self::from_bits(next_bits) + } + + /// Decrement by one ULP, saturating at negative infinity. + fn next_down(self) -> Self { + let bits = self.to_bits(); + if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() { + return self; + } + + let abs = self.abs().to_bits(); + let next_bits = if abs == Self::Int::ZERO { + // Next up from 0 is the smallest negative subnormal + Self::TINY_BITS | Self::SIGN_MASK + } else if bits == abs { + // Positive: counting down is more negative + bits - Self::Int::ONE + } else { + // Negative: counting up is more negative + bits + Self::Int::ONE + }; + Self::from_bits(next_bits) + } + + /// A faster way to effectively call `next_down` `n` times. + fn n_down(self, n: Self::Int) -> Self { + let bits = self.to_bits(); + if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() || n == Self::Int::ZERO { + return self; + } + + let abs = self.abs().to_bits(); + let is_positive = bits == abs; + let crosses_zero = is_positive && n > abs; + let inf_bits = Self::INFINITY.to_bits(); + let ninf_bits = Self::NEG_INFINITY.to_bits(); + + let next_bits = if abs == Self::Int::ZERO { + min(n, inf_bits) | Self::SIGN_MASK + } else if crosses_zero { + min(n - abs, inf_bits) | Self::SIGN_MASK + } else if is_positive { + // Positive, counting down is more negative + bits - n + } else { + // Negative, counting up is more negative but this may overflow + match bits.checked_add(n) { + Some(v) if v > ninf_bits => ninf_bits, + Some(v) => v, + None => ninf_bits, + } + }; + Self::from_bits(next_bits) + } +} + +impl FloatExt for F where F: Float {} + +/// Extra constants that are useful for tests. +#[derive(Debug, Clone, Copy)] +pub struct Consts { + /// The default quiet NaN, which is also the minimum quiet NaN. + pub pos_nan: F, + /// The default quiet NaN with negative sign. + pub neg_nan: F, + /// NaN with maximum (unsigned) significand to be a quiet NaN. The significand is saturated. + pub max_qnan: F, + /// NaN with minimum (unsigned) significand to be a signaling NaN. + pub min_snan: F, + /// NaN with maximum (unsigned) significand to be a signaling NaN. + pub max_snan: F, + pub neg_max_qnan: F, + pub neg_min_snan: F, + pub neg_max_snan: F, +} + +impl Consts { + fn new() -> Self { + let top_sigbit_mask = F::Int::ONE << (F::SIG_BITS - 1); + let pos_nan = F::EXP_MASK | top_sigbit_mask; + let max_qnan = F::EXP_MASK | F::SIG_MASK; + let min_snan = F::EXP_MASK | F::Int::ONE; + let max_snan = (F::EXP_MASK | F::SIG_MASK) ^ top_sigbit_mask; + + let neg_nan = pos_nan | F::SIGN_MASK; + let neg_max_qnan = max_qnan | F::SIGN_MASK; + let neg_min_snan = min_snan | F::SIGN_MASK; + let neg_max_snan = max_snan | F::SIGN_MASK; + + Self { + pos_nan: F::from_bits(pos_nan), + neg_nan: F::from_bits(neg_nan), + max_qnan: F::from_bits(max_qnan), + min_snan: F::from_bits(min_snan), + max_snan: F::from_bits(max_snan), + neg_max_qnan: F::from_bits(neg_max_qnan), + neg_min_snan: F::from_bits(neg_min_snan), + neg_max_snan: F::from_bits(neg_max_snan), + } + } + + pub fn iter(self) -> impl Iterator { + // Destructure so we get unused warnings if we forget a list entry. + let Self { + pos_nan, + neg_nan, + max_qnan, + min_snan, + max_snan, + neg_max_qnan, + neg_min_snan, + neg_max_snan, + } = self; + + [pos_nan, neg_nan, max_qnan, min_snan, max_snan, neg_max_qnan, neg_min_snan, neg_max_snan] + .into_iter() + } +} + +/// Return the number of steps between two floats, returning `None` if either input is NaN. +/// +/// This is the number of steps needed for `n_up` or `n_down` to go between values. Infinities +/// are treated the same as those functions (will return the nearest finite value), and only one +/// of `-0` or `+0` is counted. It does not matter which value is greater. +pub fn ulp_between(x: F, y: F) -> Option { + let a = as_ulp_steps(x)?; + let b = as_ulp_steps(y)?; + Some(a.abs_diff(b)) +} + +/// Return the (signed) number of steps from zero to `x`. +fn as_ulp_steps(x: F) -> Option { + let s = x.to_bits_signed(); + let val = if s >= F::SignedInt::ZERO { + // each increment from `s = 0` is one step up from `x = 0.0` + s + } else { + // each increment from `s = F::SignedInt::MIN` is one step down from `x = -0.0` + F::SignedInt::MIN - s + }; + + // If `x` is NaN, return `None` + (!x.is_nan()).then_some(val) +} + +/// An iterator that returns floats with linearly spaced integer representations, which translates +/// to logarithmic spacing of their values. +/// +/// Note that this tends to skip negative zero, so that needs to be checked explicitly. +/// +/// Returns `(iterator, iterator_length)`. +pub fn logspace( + start: F, + end: F, + steps: F::Int, +) -> (impl Iterator + Clone, F::Int) +where + RangeInclusive: Iterator, +{ + assert!(!start.is_nan()); + assert!(!end.is_nan()); + assert!(end >= start); + + let steps = steps.checked_sub(F::Int::ONE).expect("`steps` must be at least 2"); + let between = ulp_between(start, end).expect("`start` or `end` is NaN"); + let spacing = (between / steps).max(F::Int::ONE); + let steps = steps.min(between); // At maximum, one step per ULP + + let mut x = start; + ( + (F::Int::ZERO..=steps).map(move |_| { + let ret = x; + x = x.n_up(spacing); + ret + }), + steps + F::Int::ONE, + ) +} + +/// Returns an iterator of up to `steps` integers evenly distributed. +pub fn linear_ints( + range: RangeInclusive, + steps: u64, +) -> (impl Iterator + Clone, u64) { + let steps = steps.checked_sub(1).unwrap(); + let between = u64::from(range.start().abs_diff(*range.end())); + let spacing = i32::try_from((between / steps).max(1)).unwrap(); + let steps = steps.min(between); + let mut x: i32 = *range.start(); + ( + (0..=steps).map(move |_| { + let res = x; + // Wrapping add to avoid panic on last item (where `x` could overflow past i32::MAX as + // there is no next item). + x = x.wrapping_add(spacing); + res + }), + steps + 1, + ) +} + +#[cfg(test)] +mod tests { + use std::cmp::max; + + use super::*; + use crate::f8; + + #[test] + fn test_next_up_down() { + for (i, v) in f8::ALL.into_iter().enumerate() { + let down = v.next_down().to_bits(); + let up = v.next_up().to_bits(); + + if i == 0 { + assert_eq!(down, f8::NEG_INFINITY.to_bits(), "{i} next_down({v:#010b})"); + } else { + let expected = + if v == f8::ZERO { 1 | f8::SIGN_MASK } else { f8::ALL[i - 1].to_bits() }; + assert_eq!(down, expected, "{i} next_down({v:#010b})"); + } + + if i == f8::ALL_LEN - 1 { + assert_eq!(up, f8::INFINITY.to_bits(), "{i} next_up({v:#010b})"); + } else { + let expected = if v == f8::NEG_ZERO { 1 } else { f8::ALL[i + 1].to_bits() }; + assert_eq!(up, expected, "{i} next_up({v:#010b})"); + } + } + } + + #[test] + fn test_next_up_down_inf_nan() { + assert_eq!(f8::NEG_INFINITY.next_up().to_bits(), f8::ALL[0].to_bits(),); + assert_eq!(f8::NEG_INFINITY.next_down().to_bits(), f8::NEG_INFINITY.to_bits(),); + assert_eq!(f8::INFINITY.next_down().to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits(),); + assert_eq!(f8::INFINITY.next_up().to_bits(), f8::INFINITY.to_bits(),); + assert_eq!(f8::NAN.next_up().to_bits(), f8::NAN.to_bits(),); + assert_eq!(f8::NAN.next_down().to_bits(), f8::NAN.to_bits(),); + } + + #[test] + fn test_n_up_down_quick() { + assert_eq!(f8::ALL[0].n_up(4).to_bits(), f8::ALL[4].to_bits(),); + assert_eq!( + f8::ALL[f8::ALL_LEN - 1].n_down(4).to_bits(), + f8::ALL[f8::ALL_LEN - 5].to_bits(), + ); + + // Check around zero + assert_eq!(f8::from_bits(0b0).n_up(7).to_bits(), 0b0_0000_111); + assert_eq!(f8::from_bits(0b0).n_down(7).to_bits(), 0b1_0000_111); + + // Check across zero + assert_eq!(f8::from_bits(0b1_0000_111).n_up(8).to_bits(), 0b0_0000_001); + assert_eq!(f8::from_bits(0b0_0000_111).n_down(8).to_bits(), 0b1_0000_001); + } + + #[test] + fn test_n_up_down_one() { + // Verify that `n_up(1)` and `n_down(1)` are the same as `next_up()` and next_down()`.` + for i in 0..u8::MAX { + let v = f8::from_bits(i); + assert_eq!(v.next_up().to_bits(), v.n_up(1).to_bits()); + assert_eq!(v.next_down().to_bits(), v.n_down(1).to_bits()); + } + } + + #[test] + fn test_n_up_down_inf_nan_zero() { + assert_eq!(f8::NEG_INFINITY.n_up(1).to_bits(), f8::ALL[0].to_bits()); + assert_eq!(f8::NEG_INFINITY.n_up(239).to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits()); + assert_eq!(f8::NEG_INFINITY.n_up(240).to_bits(), f8::INFINITY.to_bits()); + assert_eq!(f8::NEG_INFINITY.n_down(u8::MAX).to_bits(), f8::NEG_INFINITY.to_bits()); + + assert_eq!(f8::INFINITY.n_down(1).to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits()); + assert_eq!(f8::INFINITY.n_down(239).to_bits(), f8::ALL[0].to_bits()); + assert_eq!(f8::INFINITY.n_down(240).to_bits(), f8::NEG_INFINITY.to_bits()); + assert_eq!(f8::INFINITY.n_up(u8::MAX).to_bits(), f8::INFINITY.to_bits()); + + assert_eq!(f8::NAN.n_up(u8::MAX).to_bits(), f8::NAN.to_bits()); + assert_eq!(f8::NAN.n_down(u8::MAX).to_bits(), f8::NAN.to_bits()); + + assert_eq!(f8::ZERO.n_down(1).to_bits(), f8::TINY_BITS | f8::SIGN_MASK); + assert_eq!(f8::NEG_ZERO.n_up(1).to_bits(), f8::TINY_BITS); + } + + /// True if the specified range of `f8::ALL` includes both +0 and -0 + fn crossed_zero(start: usize, end: usize) -> bool { + let crossed = &f8::ALL[start..=end]; + crossed.iter().any(|f| f8::eq_repr(*f, f8::ZERO)) + && crossed.iter().any(|f| f8::eq_repr(*f, f8::NEG_ZERO)) + } + + #[test] + fn test_n_up_down() { + for (i, v) in f8::ALL.into_iter().enumerate() { + for n in 0..f8::ALL_LEN { + let down = v.n_down(n as u8).to_bits(); + let up = v.n_up(n as u8).to_bits(); + + if let Some(down_exp_idx) = i.checked_sub(n) { + // No overflow + let mut expected = f8::ALL[down_exp_idx].to_bits(); + if n >= 1 && crossed_zero(down_exp_idx, i) { + // If both -0 and +0 are included, we need to adjust our expected value + match down_exp_idx.checked_sub(1) { + Some(v) => expected = f8::ALL[v].to_bits(), + // Saturate to -inf if we are out of values + None => expected = f8::NEG_INFINITY.to_bits(), + } + } + assert_eq!(down, expected, "{i} {n} n_down({v:#010b})"); + } else { + // Overflow to -inf + assert_eq!(down, f8::NEG_INFINITY.to_bits(), "{i} {n} n_down({v:#010b})"); + } + + let mut up_exp_idx = i + n; + if up_exp_idx < f8::ALL_LEN { + // No overflow + if n >= 1 && up_exp_idx < f8::ALL_LEN && crossed_zero(i, up_exp_idx) { + // If both -0 and +0 are included, we need to adjust our expected value + up_exp_idx += 1; + } + + let expected = if up_exp_idx >= f8::ALL_LEN { + f8::INFINITY.to_bits() + } else { + f8::ALL[up_exp_idx].to_bits() + }; + + assert_eq!(up, expected, "{i} {n} n_up({v:#010b})"); + } else { + // Overflow to +inf + assert_eq!(up, f8::INFINITY.to_bits(), "{i} {n} n_up({v:#010b})"); + } + } + } + } + + #[test] + fn test_ulp_between() { + for (i, x) in f8::ALL.into_iter().enumerate() { + for (j, y) in f8::ALL.into_iter().enumerate() { + let ulp = ulp_between(x, y).unwrap(); + let make_msg = || format!("i: {i} j: {j} x: {x:b} y: {y:b} ulp {ulp}"); + + let i_low = min(i, j); + let i_hi = max(i, j); + let mut expected = u8::try_from(i_hi - i_low).unwrap(); + if crossed_zero(i_low, i_hi) { + expected -= 1; + } + + assert_eq!(ulp, expected, "{}", make_msg()); + + // Skip if either are zero since `next_{up,down}` will count over it + let either_zero = x == f8::ZERO || y == f8::ZERO; + if x < y && !either_zero { + assert_eq!(x.n_up(ulp).to_bits(), y.to_bits(), "{}", make_msg()); + assert_eq!(y.n_down(ulp).to_bits(), x.to_bits(), "{}", make_msg()); + } else if !either_zero { + assert_eq!(y.n_up(ulp).to_bits(), x.to_bits(), "{}", make_msg()); + assert_eq!(x.n_down(ulp).to_bits(), y.to_bits(), "{}", make_msg()); + } + } + } + } + + #[test] + fn test_ulp_between_inf_nan_zero() { + assert_eq!(ulp_between(f8::NEG_INFINITY, f8::INFINITY).unwrap(), f8::ALL_LEN as u8); + assert_eq!(ulp_between(f8::INFINITY, f8::NEG_INFINITY).unwrap(), f8::ALL_LEN as u8); + assert_eq!( + ulp_between(f8::NEG_INFINITY, f8::ALL[f8::ALL_LEN - 1]).unwrap(), + f8::ALL_LEN as u8 - 1 + ); + assert_eq!(ulp_between(f8::INFINITY, f8::ALL[0]).unwrap(), f8::ALL_LEN as u8 - 1); + + assert_eq!(ulp_between(f8::ZERO, f8::NEG_ZERO).unwrap(), 0); + assert_eq!(ulp_between(f8::NAN, f8::ZERO), None); + assert_eq!(ulp_between(f8::ZERO, f8::NAN), None); + } + + #[test] + fn test_logspace() { + let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 2); + let ls: Vec<_> = ls.collect(); + let exp = [f8::from_bits(0x0), f8::from_bits(0x4)]; + assert_eq!(ls, exp); + assert_eq!(ls.len(), usize::from(count)); + + let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 3); + let ls: Vec<_> = ls.collect(); + let exp = [f8::from_bits(0x0), f8::from_bits(0x2), f8::from_bits(0x4)]; + assert_eq!(ls, exp); + assert_eq!(ls.len(), usize::from(count)); + + // Check that we include all values with no repeats if `steps` exceeds the maximum number + // of steps. + let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x3), 10); + let ls: Vec<_> = ls.collect(); + let exp = [f8::from_bits(0x0), f8::from_bits(0x1), f8::from_bits(0x2), f8::from_bits(0x3)]; + assert_eq!(ls, exp); + assert_eq!(ls.len(), usize::from(count)); + } + + #[test] + fn test_linear_ints() { + let (ints, count) = linear_ints(0..=4, 2); + let ints: Vec<_> = ints.collect(); + let exp = [0, 4]; + assert_eq!(ints, exp); + assert_eq!(ints.len(), usize::try_from(count).unwrap()); + + let (ints, count) = linear_ints(0..=4, 3); + let ints: Vec<_> = ints.collect(); + let exp = [0, 2, 4]; + assert_eq!(ints, exp); + assert_eq!(ints.len(), usize::try_from(count).unwrap()); + + // Check that we include all values with no repeats if `steps` exceeds the maximum number + // of steps. + let (ints, count) = linear_ints(0x0..=0x3, 10); + let ints: Vec<_> = ints.collect(); + let exp = [0, 1, 2, 3]; + assert_eq!(ints, exp); + assert_eq!(ints.len(), usize::try_from(count).unwrap()); + + // Check that there are no panics around `i32::MAX`. + let (ints, count) = linear_ints(i32::MAX - 1..=i32::MAX, 5); + let ints: Vec<_> = ints.collect(); + let exp = [i32::MAX - 1, i32::MAX]; + assert_eq!(ints, exp); + assert_eq!(ints.len(), usize::try_from(count).unwrap()); + } + + #[test] + fn test_consts() { + let Consts { + pos_nan, + neg_nan, + max_qnan, + min_snan, + max_snan, + neg_max_qnan, + neg_min_snan, + neg_max_snan, + } = f8::consts(); + + assert_eq!(pos_nan.to_bits(), 0b0_1111_100); + assert_eq!(neg_nan.to_bits(), 0b1_1111_100); + assert_eq!(max_qnan.to_bits(), 0b0_1111_111); + assert_eq!(min_snan.to_bits(), 0b0_1111_001); + assert_eq!(max_snan.to_bits(), 0b0_1111_011); + assert_eq!(neg_max_qnan.to_bits(), 0b1_1111_111); + assert_eq!(neg_min_snan.to_bits(), 0b1_1111_001); + assert_eq!(neg_max_snan.to_bits(), 0b1_1111_011); + } +} diff --git a/library/compiler-builtins/libm-test/src/op.rs b/library/compiler-builtins/libm-test/src/op.rs new file mode 100644 index 00000000000..47d72ae58b3 --- /dev/null +++ b/library/compiler-builtins/libm-test/src/op.rs @@ -0,0 +1,151 @@ +//! Types representing individual functions. +//! +//! Each routine gets a module with its name, e.g. `mod sinf { /* ... */ }`. The module +//! contains a unit struct `Routine` which implements `MathOp`. +//! +//! Basically everything could be called a "function" here, so we loosely use the following +//! terminology: +//! +//! - "Function": the math operation that does not have an associated precision. E.g. `f(x) = e^x`, +//! `f(x) = log(x)`. +//! - "Routine": A code implementation of a math operation with a specific precision. E.g. `exp`, +//! `expf`, `expl`, `log`, `logf`. +//! - "Operation" / "Op": Something that relates a routine to a function or is otherwise higher +//! level. `Op` is also used as the name for generic parameters since it is terse. + +use std::fmt; +use std::panic::{RefUnwindSafe, UnwindSafe}; + +pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; + +use crate::{CheckOutput, Float, TupleCall}; + +mod shared { + include!("../../libm-macros/src/shared.rs"); +} + +/// An enum representing each possible symbol name (`sin`, `sinf`, `sinl`, etc). +#[libm_macros::function_enum(BaseName)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Identifier {} + +impl fmt::Display for Identifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +/// The name without any type specifier, e.g. `sin` and `sinf` both become `sin`. +#[libm_macros::base_name_enum] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum BaseName {} + +impl fmt::Display for BaseName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +/// Attributes ascribed to a `libm` routine including signature, type information, +/// and naming. +pub trait MathOp { + /// The float type used for this operation. + type FTy: Float; + + /// The function type representing the signature in a C library. + type CFn: Copy; + + /// Arguments passed to the C library function as a tuple. These may include `&mut` return + /// values. + type CArgs<'a> + where + Self: 'a; + + /// The type returned by C implementations. + type CRet; + + /// The signature of the Rust function as a `fn(...) -> ...` type. + type RustFn: Copy + UnwindSafe; + + /// Arguments passed to the Rust library function as a tuple. + /// + /// The required `TupleCall` bounds ensure this type can be passed either to the C function or + /// to the Rust function. + type RustArgs: Copy + + TupleCall + + TupleCall + + RefUnwindSafe; + + /// Type returned from the Rust function. + type RustRet: CheckOutput; + + /// The name of this function, including suffix (e.g. `sin`, `sinf`). + const IDENTIFIER: Identifier; + + /// The name as a string. + const NAME: &'static str = Self::IDENTIFIER.as_str(); + + /// The name of the function excluding the type suffix, e.g. `sin` and `sinf` are both `sin`. + const BASE_NAME: BaseName = Self::IDENTIFIER.base_name(); + + /// The function in `libm` which can be called. + const ROUTINE: Self::RustFn; +} + +/// Access the associated `FTy` type from an op (helper to avoid ambiguous associated types). +pub type OpFTy = ::FTy; +/// Access the associated `FTy::Int` type from an op (helper to avoid ambiguous associated types). +pub type OpITy = <::FTy as Float>::Int; +/// Access the associated `CFn` type from an op (helper to avoid ambiguous associated types). +pub type OpCFn = ::CFn; +/// Access the associated `CRet` type from an op (helper to avoid ambiguous associated types). +pub type OpCRet = ::CRet; +/// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types). +pub type OpRustFn = ::RustFn; +/// Access the associated `RustArgs` type from an op (helper to avoid ambiguous associated types). +pub type OpRustArgs = ::RustArgs; +/// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). +pub type OpRustRet = ::RustRet; + +macro_rules! do_thing { + // Matcher for unary functions + ( + fn_name: $fn_name:ident, + FTy: $FTy:ty, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + attrs: [$($attr:meta),*], + + ) => { + paste::paste! { + $(#[$attr])* + pub mod $fn_name { + use super::*; + pub struct Routine; + + impl MathOp for Routine { + type FTy = $FTy; + type CFn = for<'a> $CFn; + type CArgs<'a> = $CArgs where Self: 'a; + type CRet = $CRet; + type RustFn = $RustFn; + type RustArgs = $RustArgs; + type RustRet = $RustRet; + + const IDENTIFIER: Identifier = Identifier::[< $fn_name:camel >]; + const ROUTINE: Self::RustFn = libm::$fn_name; + } + } + + } + }; +} + +libm_macros::for_each_function! { + callback: do_thing, + emit_types: all, +} diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs new file mode 100644 index 00000000000..f5fb5f6707b --- /dev/null +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -0,0 +1,573 @@ +//! Configuration for skipping or changing the result for individual test cases (inputs) rather +//! than ignoring entire tests. + +use core::f32; + +use CheckBasis::{Mpfr, Musl}; +use libm::support::CastFrom; +use {BaseName as Bn, Identifier as Id}; + +use crate::{BaseName, CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; + +/// Type implementing [`IgnoreCase`]. +pub struct SpecialCase; + +/// ULP allowed to differ from the results returned by a test basis. +#[allow(clippy::single_match)] +pub fn default_ulp(ctx: &CheckCtx) -> u32 { + // ULP compared to the infinite (MPFR) result. + let mut ulp = match ctx.base_name { + // Operations that require exact results. This list should correlate with what we + // have documented at . + Bn::Ceil + | Bn::Copysign + | Bn::Fabs + | Bn::Fdim + | Bn::Floor + | Bn::Fma + | Bn::Fmax + | Bn::Fmaximum + | Bn::FmaximumNum + | Bn::Fmin + | Bn::Fminimum + | Bn::FminimumNum + | Bn::Fmod + | Bn::Frexp + | Bn::Ilogb + | Bn::Ldexp + | Bn::Modf + | Bn::Nextafter + | Bn::Remainder + | Bn::Remquo + | Bn::Rint + | Bn::Round + | Bn::Roundeven + | Bn::Scalbn + | Bn::Sqrt + | Bn::Trunc => 0, + + // Operations that aren't required to be exact, but our implementations are. + Bn::Cbrt => 0, + + // Bessel functions have large inaccuracies. + Bn::J0 | Bn::J1 | Bn::Y0 | Bn::Y1 | Bn::Jn | Bn::Yn => 8_000_000, + + // For all other operations, specify our implementation's worst case precision. + Bn::Acos => 1, + Bn::Acosh => 4, + Bn::Asin => 1, + Bn::Asinh => 2, + Bn::Atan => 1, + Bn::Atan2 => 2, + Bn::Atanh => 2, + Bn::Cos => 1, + Bn::Cosh => 1, + Bn::Erf => 1, + Bn::Erfc => 4, + Bn::Exp => 1, + Bn::Exp10 => 6, + Bn::Exp2 => 1, + Bn::Expm1 => 1, + Bn::Hypot => 1, + Bn::Lgamma | Bn::LgammaR => 16, + Bn::Log => 1, + Bn::Log10 => 1, + Bn::Log1p => 1, + Bn::Log2 => 1, + Bn::Pow => 1, + Bn::Sin => 1, + Bn::Sincos => 1, + Bn::Sinh => 2, + Bn::Tan => 1, + Bn::Tanh => 2, + // tgammaf has higher accuracy than tgamma. + Bn::Tgamma if ctx.fn_ident != Id::Tgamma => 1, + Bn::Tgamma => 20, + }; + + // There are some cases where musl's approximation is less accurate than ours. For these + // cases, increase the ULP. + if ctx.basis == Musl { + match ctx.base_name { + Bn::Cosh => ulp = 2, + Bn::Exp10 if usize::BITS < 64 => ulp = 4, + Bn::Lgamma | Bn::LgammaR => ulp = 400, + Bn::Tanh => ulp = 4, + _ => (), + } + + match ctx.fn_ident { + Id::Cbrt => ulp = 2, + // FIXME(#401): musl has an incorrect result here. + Id::Fdim => ulp = 2, + Id::Sincosf => ulp = 500, + Id::Tgamma => ulp = 20, + _ => (), + } + } + + if cfg!(target_arch = "x86") { + match ctx.fn_ident { + // Input `fma(0.999999999999999, 1.0000000000000013, 0.0) = 1.0000000000000002` is + // incorrect on i586 and i686. + Id::Fma => ulp = 1, + _ => (), + } + } + + // In some cases, our implementation is less accurate than musl on i586. + if cfg!(x86_no_sse) { + match ctx.fn_ident { + // FIXME(#401): these need to be correctly rounded but are not. + Id::Fmaf => ulp = 1, + Id::Fdim => ulp = 1, + Id::Round => ulp = 1, + + Id::Asinh => ulp = 3, + Id::Asinhf => ulp = 3, + Id::Cbrt => ulp = 1, + Id::Exp10 | Id::Exp10f => ulp = 1_000_000, + Id::Exp2 | Id::Exp2f => ulp = 10_000_000, + Id::Log1p | Id::Log1pf => ulp = 2, + Id::Tan => ulp = 2, + _ => (), + } + } + + ulp +} + +/// Result of checking for possible overrides. +#[derive(Debug, Default)] +pub enum CheckAction { + /// The check should pass. Default case. + #[default] + AssertSuccess, + + /// Override the ULP for this check. + AssertWithUlp(u32), + + /// Failure is expected, ensure this is the case (xfail). Takes a contxt string to help trace + /// back exactly why we expect this to fail. + AssertFailure(&'static str), + + /// The override somehow validated the result, here it is. + Custom(TestResult), + + /// Disregard the output. + Skip, +} + +/// Don't run further validation on this test case. +const SKIP: CheckAction = CheckAction::Skip; + +/// Return this to skip checks on a test that currently fails but shouldn't. Takes a description +/// of context. +const XFAIL: fn(&'static str) -> CheckAction = CheckAction::AssertFailure; + +/// Indicates that we expect a test to fail but we aren't asserting that it does (e.g. some results +/// within a range do actually pass). +/// +/// Same as `SKIP`, just indicates we have something to eventually fix. +const XFAIL_NOCHECK: CheckAction = CheckAction::Skip; + +/// By default, all tests should pass. +const DEFAULT: CheckAction = CheckAction::AssertSuccess; + +/// Allow overriding the outputs of specific test cases. +/// +/// There are some cases where we want to xfail specific cases or handle certain inputs +/// differently than the rest of calls to `validate`. This provides a hook to do that. +/// +/// If `None` is returned, checks will proceed as usual. If `Some(result)` is returned, checks +/// are skipped and the provided result is returned instead. +/// +/// This gets implemented once per input type, then the functions provide further filtering +/// based on function name and values. +/// +/// `ulp` can also be set to adjust the ULP for that specific test, even if `None` is still +/// returned. +pub trait MaybeOverride { + fn check_float( + _input: Input, + _actual: F, + _expected: F, + _ctx: &CheckCtx, + ) -> CheckAction { + DEFAULT + } + + fn check_int(_input: Input, _actual: I, _expected: I, _ctx: &CheckCtx) -> CheckAction { + DEFAULT + } +} + +#[cfg(f16_enabled)] +impl MaybeOverride<(f16,)> for SpecialCase {} + +impl MaybeOverride<(f32,)> for SpecialCase { + fn check_float(input: (f32,), actual: F, expected: F, ctx: &CheckCtx) -> CheckAction { + if ctx.base_name == BaseName::Expm1 + && !input.0.is_infinite() + && input.0 > 80.0 + && actual.is_infinite() + && !expected.is_infinite() + { + // we return infinity but the number is representable + if ctx.basis == CheckBasis::Musl { + return XFAIL_NOCHECK; + } + return XFAIL("expm1 representable numbers"); + } + + if cfg!(x86_no_sse) + && ctx.base_name == BaseName::Exp2 + && !expected.is_infinite() + && actual.is_infinite() + { + // We return infinity when there is a representable value. Test input: 127.97238 + return XFAIL("586 exp2 representable numbers"); + } + + if ctx.base_name == BaseName::Sinh && input.0.abs() > 80.0 && actual.is_nan() { + // we return some NaN that should be real values or infinite + if ctx.basis == CheckBasis::Musl { + return XFAIL_NOCHECK; + } + return XFAIL("sinh unexpected NaN"); + } + + if (ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR) + && input.0 > 4e36 + && expected.is_infinite() + && !actual.is_infinite() + { + // This result should saturate but we return a finite value. + return XFAIL_NOCHECK; + } + + if ctx.base_name == BaseName::J0 && input.0 < -1e34 { + // Errors get huge close to -inf + return XFAIL_NOCHECK; + } + + unop_common(input, actual, expected, ctx) + } + + fn check_int(input: (f32,), actual: I, expected: I, ctx: &CheckCtx) -> CheckAction { + // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR + // sets +1 + if ctx.basis == CheckBasis::Mpfr + && ctx.base_name == BaseName::LgammaR + && input.0 == f32::NEG_INFINITY + && actual.abs() == expected.abs() + { + return XFAIL("lgammar integer result"); + } + + DEFAULT + } +} + +impl MaybeOverride<(f64,)> for SpecialCase { + fn check_float(input: (f64,), actual: F, expected: F, ctx: &CheckCtx) -> CheckAction { + if cfg!(x86_no_sse) + && ctx.base_name == BaseName::Ceil + && ctx.basis == CheckBasis::Musl + && input.0 < 0.0 + && input.0 > -1.0 + && expected == F::ZERO + && actual == F::ZERO + { + // musl returns -0.0, we return +0.0 + return XFAIL("i586 ceil signed zero"); + } + + if cfg!(x86_no_sse) + && (ctx.base_name == BaseName::Rint || ctx.base_name == BaseName::Roundeven) + && (expected - actual).abs() <= F::ONE + && (expected - actual).abs() > F::ZERO + { + // Our rounding mode is incorrect. + return XFAIL("i586 rint rounding mode"); + } + + if cfg!(x86_no_sse) + && (ctx.fn_ident == Identifier::Ceil || ctx.fn_ident == Identifier::Floor) + && expected.eq_repr(F::NEG_ZERO) + && actual.eq_repr(F::ZERO) + { + // FIXME: the x87 implementations do not keep the distinction between -0.0 and 0.0. + // See https://github.com/rust-lang/libm/pull/404#issuecomment-2572399955 + return XFAIL("i586 ceil/floor signed zero"); + } + + if cfg!(x86_no_sse) + && (ctx.fn_ident == Identifier::Exp10 || ctx.fn_ident == Identifier::Exp2) + { + // FIXME: i586 has very imprecise results with ULP > u32::MAX for these + // operations so we can't reasonably provide a limit. + return XFAIL_NOCHECK; + } + + if ctx.base_name == BaseName::J0 && input.0 < -1e300 { + // Errors get huge close to -inf + return XFAIL_NOCHECK; + } + + // maybe_check_nan_bits(actual, expected, ctx) + unop_common(input, actual, expected, ctx) + } + + fn check_int(input: (f64,), actual: I, expected: I, ctx: &CheckCtx) -> CheckAction { + // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR + // sets +1 + if ctx.basis == CheckBasis::Mpfr + && ctx.base_name == BaseName::LgammaR + && input.0 == f64::NEG_INFINITY + && actual.abs() == expected.abs() + { + return XFAIL("lgammar integer result"); + } + + DEFAULT + } +} + +#[cfg(f128_enabled)] +impl MaybeOverride<(f128,)> for SpecialCase {} + +// F1 and F2 are always the same type, this is just to please generics +fn unop_common( + input: (F1,), + actual: F2, + expected: F2, + ctx: &CheckCtx, +) -> CheckAction { + if ctx.base_name == BaseName::Acosh + && input.0 < F1::NEG_ONE + && !(expected.is_nan() && actual.is_nan()) + { + // acoshf is undefined for x <= 1.0, but we return a random result at lower values. + + if ctx.basis == CheckBasis::Musl { + return XFAIL_NOCHECK; + } + + return XFAIL("acoshf undefined"); + } + + if (ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR) + && input.0 < F1::ZERO + && !input.0.is_infinite() + { + // loggamma should not be defined for x < 0, yet we both return results + return XFAIL_NOCHECK; + } + + // fabs and copysign must leave NaNs untouched. + if ctx.base_name == BaseName::Fabs && input.0.is_nan() { + // LLVM currently uses x87 instructions which quieten signalling NaNs to handle the i686 + // `extern "C"` `f32`/`f64` return ABI. + // LLVM issue + // Rust issue + if cfg!(target_arch = "x86") && ctx.basis == CheckBasis::Musl && actual.is_nan() { + return XFAIL_NOCHECK; + } + + // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. + if ctx.basis == CheckBasis::Mpfr { + return DEFAULT; + } + + // abs and copysign require signaling NaNs to be propagated, so verify bit equality. + if actual.to_bits() == expected.to_bits() { + return CheckAction::Custom(Ok(())); + } else { + return CheckAction::Custom(Err(anyhow::anyhow!("NaNs have different bitpatterns"))); + } + } + + DEFAULT +} + +#[cfg(f16_enabled)] +impl MaybeOverride<(f16, f16)> for SpecialCase { + fn check_float( + input: (f16, f16), + actual: F, + expected: F, + ctx: &CheckCtx, + ) -> CheckAction { + binop_common(input, actual, expected, ctx) + } +} + +impl MaybeOverride<(f32, f32)> for SpecialCase { + fn check_float( + input: (f32, f32), + actual: F, + expected: F, + ctx: &CheckCtx, + ) -> CheckAction { + binop_common(input, actual, expected, ctx) + } +} + +impl MaybeOverride<(f64, f64)> for SpecialCase { + fn check_float( + input: (f64, f64), + actual: F, + expected: F, + ctx: &CheckCtx, + ) -> CheckAction { + binop_common(input, actual, expected, ctx) + } +} + +#[cfg(f128_enabled)] +impl MaybeOverride<(f128, f128)> for SpecialCase { + fn check_float( + input: (f128, f128), + actual: F, + expected: F, + ctx: &CheckCtx, + ) -> CheckAction { + binop_common(input, actual, expected, ctx) + } +} + +// F1 and F2 are always the same type, this is just to please generics +fn binop_common( + input: (F1, F1), + actual: F2, + expected: F2, + ctx: &CheckCtx, +) -> CheckAction { + // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. Skip if + // the first input (magnitude source) is NaN and the output is also a NaN, or if the second + // input (sign source) is NaN. + if ctx.basis == CheckBasis::Mpfr + && ((input.0.is_nan() && actual.is_nan() && expected.is_nan()) || input.1.is_nan()) + { + return SKIP; + } + + /* FIXME(#439): our fmin and fmax do not compare signed zeros */ + + if ctx.base_name == BaseName::Fmin + && input.0.biteq(F1::NEG_ZERO) + && input.1.biteq(F1::ZERO) + && expected.biteq(F2::NEG_ZERO) + && actual.biteq(F2::ZERO) + { + return XFAIL("fmin signed zeroes"); + } + + if ctx.base_name == BaseName::Fmax + && input.0.biteq(F1::NEG_ZERO) + && input.1.biteq(F1::ZERO) + && expected.biteq(F2::ZERO) + && actual.biteq(F2::NEG_ZERO) + { + return XFAIL("fmax signed zeroes"); + } + + // Musl propagates NaNs if one is provided as the input, but we return the other input. + if (ctx.base_name == BaseName::Fmax || ctx.base_name == BaseName::Fmin) + && ctx.basis == Musl + && (input.0.is_nan() ^ input.1.is_nan()) + && expected.is_nan() + { + return XFAIL("fmax/fmin musl NaN"); + } + + DEFAULT +} + +impl MaybeOverride<(i32, f32)> for SpecialCase { + fn check_float( + input: (i32, f32), + actual: F, + expected: F, + ctx: &CheckCtx, + ) -> CheckAction { + // `ynf(213, 109.15641) = -inf` with our library, should be finite. + if ctx.basis == Mpfr + && ctx.base_name == BaseName::Yn + && input.0 > 200 + && !expected.is_infinite() + && actual.is_infinite() + { + return XFAIL("ynf infinity mismatch"); + } + + int_float_common(input, actual, expected, ctx) + } +} + +impl MaybeOverride<(i32, f64)> for SpecialCase { + fn check_float( + input: (i32, f64), + actual: F, + expected: F, + ctx: &CheckCtx, + ) -> CheckAction { + int_float_common(input, actual, expected, ctx) + } +} + +fn int_float_common( + input: (i32, F1), + actual: F2, + expected: F2, + ctx: &CheckCtx, +) -> CheckAction { + if ctx.basis == Mpfr + && (ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn) + && input.1 == F1::NEG_INFINITY + && actual == F2::ZERO + && expected == F2::ZERO + { + return XFAIL("we disagree with MPFR on the sign of zero"); + } + + // Values near infinity sometimes get cut off for us. `ynf(681, 509.90924) = -inf` but should + // be -3.2161271e38. + if ctx.basis == Musl + && ctx.fn_ident == Identifier::Ynf + && !expected.is_infinite() + && actual.is_infinite() + && (expected.abs().to_bits().abs_diff(actual.abs().to_bits()) + < F2::Int::cast_from(10_000_000u32)) + { + return XFAIL_NOCHECK; + } + + // Our bessel functions blow up with large N values + if ctx.basis == Musl && (ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn) { + if cfg!(x86_no_sse) { + // Precision is especially bad on i586, not worth checking. + return XFAIL_NOCHECK; + } + + if input.0 > 4000 { + return XFAIL_NOCHECK; + } else if input.0 > 100 { + return CheckAction::AssertWithUlp(1_000_000); + } + } + DEFAULT +} + +#[cfg(f16_enabled)] +impl MaybeOverride<(f16, i32)> for SpecialCase {} +impl MaybeOverride<(f32, i32)> for SpecialCase {} +impl MaybeOverride<(f64, i32)> for SpecialCase {} +#[cfg(f128_enabled)] +impl MaybeOverride<(f128, i32)> for SpecialCase {} + +impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} +impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} +#[cfg(f128_enabled)] +impl MaybeOverride<(f128, f128, f128)> for SpecialCase {} diff --git a/library/compiler-builtins/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm-test/src/run_cfg.rs new file mode 100644 index 00000000000..b36164b005f --- /dev/null +++ b/library/compiler-builtins/libm-test/src/run_cfg.rs @@ -0,0 +1,370 @@ +//! Configuration for how tests get run. + +use std::ops::RangeInclusive; +use std::sync::LazyLock; +use std::{env, str}; + +use crate::generate::random::{SEED, SEED_ENV}; +use crate::{BaseName, FloatTy, Identifier, test_log}; + +/// The environment variable indicating which extensive tests should be run. +pub const EXTENSIVE_ENV: &str = "LIBM_EXTENSIVE_TESTS"; + +/// Specify the number of iterations via this environment variable, rather than using the default. +pub const EXTENSIVE_ITER_ENV: &str = "LIBM_EXTENSIVE_ITERATIONS"; + +/// The override value, if set by the above environment. +static EXTENSIVE_ITER_OVERRIDE: LazyLock> = LazyLock::new(|| { + env::var(EXTENSIVE_ITER_ENV).map(|v| v.parse().expect("failed to parse iteration count")).ok() +}); + +/// Specific tests that need to have a reduced amount of iterations to complete in a reasonable +/// amount of time. +/// +/// Contains the itentifier+generator combo to match on, plus the factor to reduce by. +const EXTEMELY_SLOW_TESTS: &[(Identifier, GeneratorKind, u64)] = &[ + (Identifier::Fmodf128, GeneratorKind::QuickSpaced, 50), + (Identifier::Fmodf128, GeneratorKind::Extensive, 50), +]; + +/// Maximum number of iterations to run for a single routine. +/// +/// The default value of one greater than `u32::MAX` allows testing single-argument `f32` routines +/// and single- or double-argument `f16` routines exhaustively. `f64` and `f128` can't feasibly +/// be tested exhaustively; however, [`EXTENSIVE_ITER_ENV`] can be set to run tests for multiple +/// hours. +pub fn extensive_max_iterations() -> u64 { + let default = 1 << 32; // default value + EXTENSIVE_ITER_OVERRIDE.unwrap_or(default) +} + +/// Context passed to [`CheckOutput`]. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CheckCtx { + /// Allowed ULP deviation + pub ulp: u32, + pub fn_ident: Identifier, + pub base_name: BaseName, + /// Function name. + pub fn_name: &'static str, + /// Return the unsuffixed version of the function name. + pub base_name_str: &'static str, + /// Source of truth for tests. + pub basis: CheckBasis, + pub gen_kind: GeneratorKind, + /// If specified, this value will override the value returned by [`iteration_count`]. + pub override_iterations: Option, +} + +impl CheckCtx { + /// Create a new check context, using the default ULP for the function. + pub fn new(fn_ident: Identifier, basis: CheckBasis, gen_kind: GeneratorKind) -> Self { + let mut ret = Self { + ulp: 0, + fn_ident, + fn_name: fn_ident.as_str(), + base_name: fn_ident.base_name(), + base_name_str: fn_ident.base_name().as_str(), + basis, + gen_kind, + override_iterations: None, + }; + ret.ulp = crate::default_ulp(&ret); + ret + } + + /// The number of input arguments for this function. + pub fn input_count(&self) -> usize { + self.fn_ident.math_op().rust_sig.args.len() + } + + pub fn override_iterations(&mut self, count: u64) { + self.override_iterations = Some(count) + } +} + +/// Possible items to test against +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum CheckBasis { + /// Check against Musl's math sources. + Musl, + /// Check against infinite precision (MPFR). + Mpfr, + /// Benchmarks or other times when this is not relevant. + None, +} + +/// The different kinds of generators that provide test input, which account for input pattern +/// and quantity. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum GeneratorKind { + EdgeCases, + Extensive, + QuickSpaced, + Random, + List, +} + +/// A list of all functions that should get extensive tests. +/// +/// This also supports the special test name `all` to run all tests, as well as `all_f16`, +/// `all_f32`, `all_f64`, and `all_f128` to run all tests for a specific float type. +static EXTENSIVE: LazyLock> = LazyLock::new(|| { + let var = env::var(EXTENSIVE_ENV).unwrap_or_default(); + let list = var.split(",").filter(|s| !s.is_empty()).collect::>(); + let mut ret = Vec::new(); + + let append_ty_ops = |ret: &mut Vec<_>, fty: FloatTy| { + let iter = Identifier::ALL.iter().filter(move |id| id.math_op().float_ty == fty).copied(); + ret.extend(iter); + }; + + for item in list { + match item { + "all" => ret = Identifier::ALL.to_owned(), + "all_f16" => append_ty_ops(&mut ret, FloatTy::F16), + "all_f32" => append_ty_ops(&mut ret, FloatTy::F32), + "all_f64" => append_ty_ops(&mut ret, FloatTy::F64), + "all_f128" => append_ty_ops(&mut ret, FloatTy::F128), + s => { + let id = Identifier::from_str(s) + .unwrap_or_else(|| panic!("unrecognized test name `{s}`")); + ret.push(id); + } + } + } + + ret +}); + +/// Information about the function to be tested. +#[derive(Debug)] +struct TestEnv { + /// Tests should be reduced because the platform is slow. E.g. 32-bit or emulated. + slow_platform: bool, + /// The float cannot be tested exhaustively, `f64` or `f128`. + large_float_ty: bool, + /// Env indicates that an extensive test should be run. + should_run_extensive: bool, + /// Multiprecision tests will be run. + mp_tests_enabled: bool, + /// The number of inputs to the function. + input_count: usize, +} + +impl TestEnv { + fn from_env(ctx: &CheckCtx) -> Self { + let id = ctx.fn_ident; + let op = id.math_op(); + + let will_run_mp = cfg!(feature = "build-mpfr"); + let large_float_ty = match op.float_ty { + FloatTy::F16 | FloatTy::F32 => false, + FloatTy::F64 | FloatTy::F128 => true, + }; + + let will_run_extensive = EXTENSIVE.contains(&id); + + let input_count = op.rust_sig.args.len(); + + Self { + slow_platform: slow_platform(), + large_float_ty, + should_run_extensive: will_run_extensive, + mp_tests_enabled: will_run_mp, + input_count, + } + } +} + +/// Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run in QEMU. Start +/// with a reduced number on these platforms. +fn slow_platform() -> bool { + let slow_on_ci = crate::emulated() + || usize::BITS < 64 + || cfg!(all(target_arch = "x86_64", target_vendor = "apple")); + + // If not running in CI, there is no need to reduce iteration count. + slow_on_ci && crate::ci() +} + +/// The number of iterations to run for a given test. +pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { + let t_env = TestEnv::from_env(ctx); + + // Ideally run 5M tests + let mut domain_iter_count: u64 = 4_000_000; + + // Start with a reduced number of tests on slow platforms. + if t_env.slow_platform { + domain_iter_count = 100_000; + } + + // If we will be running tests against MPFR, we don't need to test as much against musl. + // However, there are some platforms where we have to test against musl since MPFR can't be + // built. + if t_env.mp_tests_enabled && ctx.basis == CheckBasis::Musl { + domain_iter_count /= 100; + } + + // Run fewer random tests than domain tests. + let random_iter_count = domain_iter_count / 100; + + let mut total_iterations = match ctx.gen_kind { + GeneratorKind::QuickSpaced => domain_iter_count, + GeneratorKind::Random => random_iter_count, + GeneratorKind::Extensive => extensive_max_iterations(), + GeneratorKind::EdgeCases | GeneratorKind::List => { + unimplemented!("shoudn't need `iteration_count` for {:?}", ctx.gen_kind) + } + }; + + // Larger float types get more iterations. + if t_env.large_float_ty && ctx.gen_kind != GeneratorKind::Extensive { + if ctx.gen_kind == GeneratorKind::Extensive { + // Extensive already has a pretty high test count. + total_iterations *= 2; + } else { + total_iterations *= 4; + } + } + + // Functions with more arguments get more iterations. + let arg_multiplier = 1 << (t_env.input_count - 1); + total_iterations *= arg_multiplier; + + // FMA has a huge domain but is reasonably fast to run, so increase another 1.5x. + if ctx.base_name == BaseName::Fma { + total_iterations = 3 * total_iterations / 2; + } + + // Some tests are significantly slower than others and need to be further reduced. + if let Some((_id, _gen, scale)) = EXTEMELY_SLOW_TESTS + .iter() + .find(|(id, generator, _scale)| *id == ctx.fn_ident && *generator == ctx.gen_kind) + { + // However, do not override if the extensive iteration count has been manually set. + if !(ctx.gen_kind == GeneratorKind::Extensive && EXTENSIVE_ITER_OVERRIDE.is_some()) { + total_iterations /= scale; + } + } + + if cfg!(optimizations_enabled) { + // Always run at least 10,000 tests. + total_iterations = total_iterations.max(10_000); + } else { + // Without optimizations, just run a quick check regardless of other parameters. + total_iterations = 800; + } + + let mut overridden = false; + if let Some(count) = ctx.override_iterations { + total_iterations = count; + overridden = true; + } + + // Adjust for the number of inputs + let ntests = match t_env.input_count { + 1 => total_iterations, + 2 => (total_iterations as f64).sqrt().ceil() as u64, + 3 => (total_iterations as f64).cbrt().ceil() as u64, + _ => panic!("test has more than three arguments"), + }; + + let total = ntests.pow(t_env.input_count.try_into().unwrap()); + + let seed_msg = match ctx.gen_kind { + GeneratorKind::QuickSpaced | GeneratorKind::Extensive => String::new(), + GeneratorKind::Random => { + format!(" using `{SEED_ENV}={}`", str::from_utf8(SEED.as_slice()).unwrap()) + } + GeneratorKind::EdgeCases | GeneratorKind::List => unimplemented!(), + }; + + test_log(&format!( + "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {ntests} iterations \ + ({total} total){seed_msg}{omsg}", + gen_kind = ctx.gen_kind, + basis = ctx.basis, + fn_ident = ctx.fn_ident, + arg = argnum + 1, + args = t_env.input_count, + omsg = if overridden { " (overridden)" } else { "" } + )); + + ntests +} + +/// Some tests require that an integer be kept within reasonable limits; generate that here. +pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { + let t_env = TestEnv::from_env(ctx); + + if !matches!(ctx.base_name, BaseName::Jn | BaseName::Yn) { + return i32::MIN..=i32::MAX; + } + + assert_eq!(argnum, 0, "For `jn`/`yn`, only the first argument takes an integer"); + + // The integer argument to `jn` is an iteration count. Limit this to ensure tests can be + // completed in a reasonable amount of time. + let non_extensive_range = if t_env.slow_platform || !cfg!(optimizations_enabled) { + (-0xf)..=0xff + } else { + (-0xff)..=0xffff + }; + + let extensive_range = (-0xfff)..=0xfffff; + + match ctx.gen_kind { + GeneratorKind::Extensive => extensive_range, + GeneratorKind::QuickSpaced | GeneratorKind::Random => non_extensive_range, + GeneratorKind::EdgeCases => extensive_range, + GeneratorKind::List => unimplemented!("shoudn't need range for {:?}", ctx.gen_kind), + } +} + +/// For domain tests, limit how many asymptotes or specified check points we test. +pub fn check_point_count(ctx: &CheckCtx) -> usize { + assert_eq!( + ctx.gen_kind, + GeneratorKind::EdgeCases, + "check_point_count is intended for edge case tests" + ); + let t_env = TestEnv::from_env(ctx); + if t_env.slow_platform || !cfg!(optimizations_enabled) { 4 } else { 10 } +} + +/// When validating points of interest (e.g. asymptotes, inflection points, extremes), also check +/// this many surrounding values. +pub fn check_near_count(ctx: &CheckCtx) -> u64 { + assert_eq!( + ctx.gen_kind, + GeneratorKind::EdgeCases, + "check_near_count is intended for edge case tests" + ); + if cfg!(optimizations_enabled) { + // Taper based on the number of inputs. + match ctx.input_count() { + 1 | 2 => 100, + 3 => 50, + x => panic!("unexpected argument count {x}"), + } + } else { + 8 + } +} + +/// Check whether extensive actions should be run or skipped. +pub fn skip_extensive_test(ctx: &CheckCtx) -> bool { + let t_env = TestEnv::from_env(ctx); + !t_env.should_run_extensive +} + +/// The number of iterations to run for `u256` fuzz tests. +pub fn bigint_fuzz_iteration_count() -> u64 { + if !cfg!(optimizations_enabled) { + return 1000; + } + + if slow_platform() { 100_000 } else { 5_000_000 } +} diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs new file mode 100644 index 00000000000..c560dade884 --- /dev/null +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -0,0 +1,447 @@ +//! Traits related to testing. +//! +//! There are two main traits in this module: +//! +//! - `TupleCall`: implemented on tuples to allow calling them as function arguments. +//! - `CheckOutput`: implemented on anything that is an output type for validation against an +//! expected value. + +use std::panic::{RefUnwindSafe, UnwindSafe}; +use std::{fmt, panic}; + +use anyhow::{Context, anyhow, bail, ensure}; +use libm::support::Hexf; + +use crate::precision::CheckAction; +use crate::{ + CheckBasis, CheckCtx, Float, GeneratorKind, Int, MaybeOverride, SpecialCase, TestResult, +}; + +/// Trait for calling a function with a tuple as arguments. +/// +/// Implemented on the tuple with the function signature as the generic (so we can use the same +/// tuple for multiple signatures). +pub trait TupleCall: fmt::Debug { + type Output; + fn call(self, f: Func) -> Self::Output; + + /// Intercept panics and print the input to stderr before continuing. + fn call_intercept_panics(self, f: Func) -> Self::Output + where + Self: RefUnwindSafe + Copy, + Func: UnwindSafe, + { + let res = panic::catch_unwind(|| self.call(f)); + match res { + Ok(v) => v, + Err(e) => { + eprintln!("panic with the following input: {self:?}"); + panic::resume_unwind(e) + } + } + } +} + +/// A trait to implement on any output type so we can verify it in a generic way. +pub trait CheckOutput: Sized { + /// Validate `self` (actual) and `expected` are the same. + /// + /// `input` is only used here for error messages. + fn validate(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult; +} + +/// A helper trait to print something as hex with the correct number of nibbles, e.g. a `u32` +/// will always print with `0x` followed by 8 digits. +/// +/// This is only used for printing errors so allocating is okay. +pub trait Hex: Copy { + /// Hex integer syntax. + fn hex(self) -> String; + /// Hex float syntax. + fn hexf(self) -> String; +} + +/* implement `TupleCall` */ + +impl TupleCall R> for (T1,) +where + T1: fmt::Debug, +{ + type Output = R; + + fn call(self, f: fn(T1) -> R) -> Self::Output { + f(self.0) + } +} + +impl TupleCall R> for (T1, T2) +where + T1: fmt::Debug, + T2: fmt::Debug, +{ + type Output = R; + + fn call(self, f: fn(T1, T2) -> R) -> Self::Output { + f(self.0, self.1) + } +} + +impl TupleCall R> for (T1,) +where + T1: fmt::Debug, + T2: fmt::Debug + Default, +{ + type Output = (R, T2); + + fn call(self, f: fn(T1, &mut T2) -> R) -> Self::Output { + let mut t2 = T2::default(); + (f(self.0, &mut t2), t2) + } +} + +impl TupleCall R> for (T1, T2, T3) +where + T1: fmt::Debug, + T2: fmt::Debug, + T3: fmt::Debug, +{ + type Output = R; + + fn call(self, f: fn(T1, T2, T3) -> R) -> Self::Output { + f(self.0, self.1, self.2) + } +} + +impl TupleCall R> for (T1, T2) +where + T1: fmt::Debug, + T2: fmt::Debug, + T3: fmt::Debug + Default, +{ + type Output = (R, T3); + + fn call(self, f: fn(T1, T2, &mut T3) -> R) -> Self::Output { + let mut t3 = T3::default(); + (f(self.0, self.1, &mut t3), t3) + } +} + +impl TupleCall fn(T1, &'a mut T2, &'a mut T3)> for (T1,) +where + T1: fmt::Debug, + T2: fmt::Debug + Default, + T3: fmt::Debug + Default, +{ + type Output = (T2, T3); + + fn call(self, f: for<'a> fn(T1, &'a mut T2, &'a mut T3)) -> Self::Output { + let mut t2 = T2::default(); + let mut t3 = T3::default(); + f(self.0, &mut t2, &mut t3); + (t2, t3) + } +} + +/* implement `Hex` */ + +impl Hex for (T1,) +where + T1: Hex, +{ + fn hex(self) -> String { + format!("({},)", self.0.hex()) + } + + fn hexf(self) -> String { + format!("({},)", self.0.hexf()) + } +} + +impl Hex for (T1, T2) +where + T1: Hex, + T2: Hex, +{ + fn hex(self) -> String { + format!("({}, {})", self.0.hex(), self.1.hex()) + } + + fn hexf(self) -> String { + format!("({}, {})", self.0.hexf(), self.1.hexf()) + } +} + +impl Hex for (T1, T2, T3) +where + T1: Hex, + T2: Hex, + T3: Hex, +{ + fn hex(self) -> String { + format!("({}, {}, {})", self.0.hex(), self.1.hex(), self.2.hex()) + } + + fn hexf(self) -> String { + format!("({}, {}, {})", self.0.hexf(), self.1.hexf(), self.2.hexf()) + } +} + +/* trait implementations for ints */ + +macro_rules! impl_int { + ($($ty:ty),*) => { + $( + impl Hex for $ty { + fn hex(self) -> String { + format!("{self:#0width$x}", width = ((Self::BITS / 4) + 2) as usize) + } + + fn hexf(self) -> String { + String::new() + } + } + + impl $crate::CheckOutput for $ty + where + Input: Hex + fmt::Debug, + SpecialCase: MaybeOverride, + { + fn validate<'a>( + self, + expected: Self, + input: Input, + ctx: &$crate::CheckCtx, + ) -> TestResult { + validate_int(self, expected, input, ctx) + } + } + )* + }; +} + +fn validate_int(actual: I, expected: I, input: Input, ctx: &CheckCtx) -> TestResult +where + I: Int + Hex, + Input: Hex + fmt::Debug, + SpecialCase: MaybeOverride, +{ + let (result, xfail_msg) = match SpecialCase::check_int(input, actual, expected, ctx) { + // `require_biteq` forbids overrides. + _ if ctx.gen_kind == GeneratorKind::List => (actual == expected, None), + CheckAction::AssertSuccess => (actual == expected, None), + CheckAction::AssertFailure(msg) => (actual != expected, Some(msg)), + CheckAction::Custom(res) => return res, + CheckAction::Skip => return Ok(()), + CheckAction::AssertWithUlp(_) => panic!("ulp has no meaning for integer checks"), + }; + + let make_xfail_msg = || match xfail_msg { + Some(m) => format!( + "expected failure but test passed. Does an XFAIL need to be updated?\n\ + failed at: {m}", + ), + None => String::new(), + }; + + anyhow::ensure!( + result, + "\ + \n input: {input:?} {ibits}\ + \n expected: {expected:<22?} {expbits}\ + \n actual: {actual:<22?} {actbits}\ + \n {msg}\ + ", + actbits = actual.hex(), + expbits = expected.hex(), + ibits = input.hex(), + msg = make_xfail_msg() + ); + + Ok(()) +} + +impl_int!(u32, i32, u64, i64); + +/* trait implementations for floats */ + +macro_rules! impl_float { + ($($ty:ty),*) => { + $( + impl Hex for $ty { + fn hex(self) -> String { + format!( + "{:#0width$x}", + self.to_bits(), + width = ((Self::BITS / 4) + 2) as usize + ) + } + + fn hexf(self) -> String { + format!("{}", Hexf(self)) + } + } + + impl $crate::CheckOutput for $ty + where + Input: Hex + fmt::Debug, + SpecialCase: MaybeOverride, + { + fn validate<'a>( + self, + expected: Self, + input: Input, + ctx: &$crate::CheckCtx, + ) -> TestResult { + validate_float(self, expected, input, ctx) + } + } + )* + }; +} + +fn validate_float(actual: F, expected: F, input: Input, ctx: &CheckCtx) -> TestResult +where + F: Float + Hex, + Input: Hex + fmt::Debug, + u32: TryFrom, + SpecialCase: MaybeOverride, +{ + let mut assert_failure_msg = None; + + // Create a wrapper function so we only need to `.with_context` once. + let mut inner = || -> TestResult { + let mut allowed_ulp = ctx.ulp; + + // Forbid overrides if the items came from an explicit list, as long as we are checking + // against either MPFR or the result itself. + let require_biteq = ctx.gen_kind == GeneratorKind::List && ctx.basis != CheckBasis::Musl; + + match SpecialCase::check_float(input, actual, expected, ctx) { + _ if require_biteq => (), + CheckAction::AssertSuccess => (), + CheckAction::AssertFailure(msg) => assert_failure_msg = Some(msg), + CheckAction::Custom(res) => return res, + CheckAction::Skip => return Ok(()), + CheckAction::AssertWithUlp(ulp_override) => allowed_ulp = ulp_override, + }; + + // Check when both are NaNs + if actual.is_nan() && expected.is_nan() { + if require_biteq && ctx.basis == CheckBasis::None { + ensure!(actual.to_bits() == expected.to_bits(), "mismatched NaN bitpatterns"); + } + // By default, NaNs have nothing special to check. + return Ok(()); + } else if actual.is_nan() || expected.is_nan() { + // Check when only one is a NaN + bail!("real value != NaN") + } + + // Make sure that the signs are the same before checing ULP to avoid wraparound + let act_sig = actual.signum(); + let exp_sig = expected.signum(); + ensure!(act_sig == exp_sig, "mismatched signs {act_sig:?} {exp_sig:?}"); + + if actual.is_infinite() ^ expected.is_infinite() { + bail!("mismatched infinities"); + } + + let act_bits = actual.to_bits().signed(); + let exp_bits = expected.to_bits().signed(); + + let ulp_diff = act_bits.checked_sub(exp_bits).unwrap().abs(); + + let ulp_u32 = u32::try_from(ulp_diff) + .map_err(|e| anyhow!("{e:?}: ulp of {ulp_diff} exceeds u32::MAX"))?; + + ensure!(ulp_u32 <= allowed_ulp, "ulp {ulp_diff} > {allowed_ulp}",); + + Ok(()) + }; + + let mut res = inner(); + + if let Some(msg) = assert_failure_msg { + // Invert `Ok` and `Err` if the test is an xfail. + if res.is_ok() { + let e = anyhow!( + "expected failure but test passed. Does an XFAIL need to be updated?\n\ + failed at: {msg}", + ); + res = Err(e) + } else { + res = Ok(()) + } + } + + res.with_context(|| { + format!( + "\ + \n input: {input:?}\ + \n as hex: {ihex}\ + \n as bits: {ibits}\ + \n expected: {expected:<22?} {exphex} {expbits}\ + \n actual: {actual:<22?} {acthex} {actbits}\ + ", + ihex = input.hexf(), + ibits = input.hex(), + exphex = expected.hexf(), + expbits = expected.hex(), + actbits = actual.hex(), + acthex = actual.hexf(), + ) + }) +} + +impl_float!(f32, f64); + +#[cfg(f16_enabled)] +impl_float!(f16); + +#[cfg(f128_enabled)] +impl_float!(f128); + +/* trait implementations for compound types */ + +/// Implement `CheckOutput` for combinations of types. +macro_rules! impl_tuples { + ($(($a:ty, $b:ty);)*) => { + $( + impl CheckOutput for ($a, $b) + where + Input: Hex + fmt::Debug, + SpecialCase: MaybeOverride, + { + fn validate<'a>( + self, + expected: Self, + input: Input, + ctx: &CheckCtx, + ) -> TestResult { + self.0.validate(expected.0, input, ctx) + .and_then(|()| self.1.validate(expected.1, input, ctx)) + .with_context(|| format!( + "full context:\ + \n input: {input:?} {ibits}\ + \n as hex: {ihex}\ + \n as bits: {ibits}\ + \n expected: {expected:?} {expbits}\ + \n actual: {self:?} {actbits}\ + ", + ihex = input.hexf(), + ibits = input.hex(), + expbits = expected.hex(), + actbits = self.hex(), + )) + } + } + )* + }; +} + +impl_tuples!( + (f32, i32); + (f64, i32); + (f32, f32); + (f64, f64); +); diff --git a/library/compiler-builtins/libm-test/tests/check_coverage.rs b/library/compiler-builtins/libm-test/tests/check_coverage.rs new file mode 100644 index 00000000000..c23298686fa --- /dev/null +++ b/library/compiler-builtins/libm-test/tests/check_coverage.rs @@ -0,0 +1,61 @@ +//! Ensure that `for_each_function!` isn't missing any symbols. + +use std::collections::HashSet; +use std::env; +use std::path::Path; +use std::process::Command; + +macro_rules! callback { + ( + fn_name: $name:ident, + attrs: [$($attr:meta),*], + extra: [$set:ident], + ) => { + let name = stringify!($name); + let new = $set.insert(name); + assert!(new, "duplicate function `{name}` in `ALL_OPERATIONS`"); + }; +} + +#[test] +fn test_for_each_function_all_included() { + let all_functions: HashSet<_> = include_str!("../../../etc/function-list.txt") + .lines() + .filter(|line| !line.starts_with("#")) + .collect(); + + let mut tested = HashSet::new(); + + libm_macros::for_each_function! { + callback: callback, + extra: [tested], + }; + + let untested = all_functions.difference(&tested); + if untested.clone().next().is_some() { + panic!( + "missing tests for the following: {untested:#?} \ + \nmake sure any new functions are entered in \ + `ALL_OPERATIONS` (in `libm-macros`)." + ); + } + assert_eq!(all_functions, tested); +} + +#[test] +fn ensure_list_updated() { + if libm_test::ci() { + // Most CI tests run in Docker where we don't have Python or Rustdoc, so it's easiest + // to just run the python file directly when it is available. + eprintln!("skipping test; CI runs the python file directly"); + return; + } + + let res = Command::new("python3") + .arg(Path::new(env!("CARGO_MANIFEST_DIR")).join("../../etc/update-api-list.py")) + .arg("--check") + .status() + .unwrap(); + + assert!(res.success(), "May need to run `./etc/update-api-list.py`"); +} diff --git a/library/compiler-builtins/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm-test/tests/compare_built_musl.rs new file mode 100644 index 00000000000..cbb4bd49b9c --- /dev/null +++ b/library/compiler-builtins/libm-test/tests/compare_built_musl.rs @@ -0,0 +1,143 @@ +//! Compare our implementations with the result of musl functions, as provided by `musl-math-sys`. +//! +//! Currently this only tests randomized inputs. In the future this may be improved to test edge +//! cases or run exhaustive tests. +//! +//! Note that musl functions do not always provide 0.5ULP rounding, so our functions can do better +//! than these results. + +// There are some targets we can't build musl for +#![cfg(feature = "build-musl")] + +use libm_test::generate::{case_list, edge_cases, random, spaced}; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; + +const BASIS: CheckBasis = CheckBasis::Musl; + +fn musl_runner( + ctx: &CheckCtx, + cases: impl Iterator, + musl_fn: Op::CFn, +) { + for input in cases { + let musl_res = input.call(musl_fn); + let crate_res = input.call_intercept_panics(Op::ROUTINE); + + crate_res.validate(musl_res, input, ctx).unwrap(); + } +} + +/// Test against musl with generators from a domain. +macro_rules! musl_tests { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + ) => { + paste::paste! { + #[test] + $(#[$attr])* + fn [< musl_case_list_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::List); + let cases = case_list::get_test_cases_basis::(&ctx).0; + musl_runner::(&ctx, cases, musl_math_sys::$fn_name); + } + + #[test] + $(#[$attr])* + fn [< musl_random_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Random); + let cases = random::get_test_cases::<::RustArgs>(&ctx).0; + musl_runner::(&ctx, cases, musl_math_sys::$fn_name); + } + + #[test] + $(#[$attr])* + fn [< musl_edge_case_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::EdgeCases); + let cases = edge_cases::get_test_cases::(&ctx).0; + musl_runner::(&ctx, cases, musl_math_sys::$fn_name); + } + + #[test] + $(#[$attr])* + fn [< musl_quickspace_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::QuickSpaced); + let cases = spaced::get_test_cases::(&ctx).0; + musl_runner::(&ctx, cases, musl_math_sys::$fn_name); + } + } + }; +} + +libm_macros::for_each_function! { + callback: musl_tests, + attributes: [], + skip: [ + // TODO integer inputs + jn, + jnf, + ldexp, + ldexpf, + scalbn, + scalbnf, + yn, + ynf, + + // Not provided by musl + // verify-sorted-start + ceilf128, + ceilf16, + copysignf128, + copysignf16, + fabsf128, + fabsf16, + fdimf128, + fdimf16, + floorf128, + floorf16, + fmaf128, + fmaxf128, + fmaxf16, + fmaximum, + fmaximum_num, + fmaximum_numf, + fmaximum_numf128, + fmaximum_numf16, + fmaximumf, + fmaximumf128, + fmaximumf16, + fminf128, + fminf16, + fminimum, + fminimum_num, + fminimum_numf, + fminimum_numf128, + fminimum_numf16, + fminimumf, + fminimumf128, + fminimumf16, + fmodf128, + fmodf16, + ldexpf128, + ldexpf16, + rintf128, + rintf16, + roundeven, + roundevenf, + roundevenf128, + roundevenf16, + roundf128, + roundf16, + scalbnf128, + scalbnf16, + sqrtf128, + sqrtf16, + truncf128, + truncf16, + // verify-sorted-end + ], +} diff --git a/library/compiler-builtins/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm-test/tests/multiprecision.rs new file mode 100644 index 00000000000..80b2c78688e --- /dev/null +++ b/library/compiler-builtins/libm-test/tests/multiprecision.rs @@ -0,0 +1,79 @@ +//! Test with "infinite precision" + +#![cfg(feature = "build-mpfr")] + +use libm_test::generate::{case_list, edge_cases, random, spaced}; +use libm_test::mpfloat::MpOp; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; + +const BASIS: CheckBasis = CheckBasis::Mpfr; + +fn mp_runner(ctx: &CheckCtx, cases: impl Iterator) { + let mut mp_vals = Op::new_mp(); + for input in cases { + let mp_res = Op::run(&mut mp_vals, input); + let crate_res = input.call_intercept_panics(Op::ROUTINE); + + crate_res.validate(mp_res, input, ctx).unwrap(); + } +} + +macro_rules! mp_tests { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + ) => { + paste::paste! { + #[test] + $(#[$attr])* + fn [< mp_case_list_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::List); + let cases = case_list::get_test_cases_basis::(&ctx).0; + mp_runner::(&ctx, cases); + } + + #[test] + $(#[$attr])* + fn [< mp_random_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Random); + let cases = random::get_test_cases::<::RustArgs>(&ctx).0; + mp_runner::(&ctx, cases); + } + + #[test] + $(#[$attr])* + fn [< mp_edge_case_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::EdgeCases); + let cases = edge_cases::get_test_cases::(&ctx).0; + mp_runner::(&ctx, cases); + } + + #[test] + $(#[$attr])* + fn [< mp_quickspace_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::QuickSpaced); + let cases = spaced::get_test_cases::(&ctx).0; + mp_runner::(&ctx, cases); + } + } + }; +} + +libm_macros::for_each_function! { + callback: mp_tests, + attributes: [ + // Also an assertion failure on i686: at `MPFR_ASSERTN (! mpfr_erangeflag_p ())` + #[ignore = "large values are infeasible in MPFR"] + [jn, jnf, yn, ynf], + ], + skip: [ + // FIXME: test needed, see + // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 + nextafter, + nextafterf, + ], +} diff --git a/library/compiler-builtins/libm-test/tests/standalone.rs b/library/compiler-builtins/libm-test/tests/standalone.rs new file mode 100644 index 00000000000..7b30a3b48d7 --- /dev/null +++ b/library/compiler-builtins/libm-test/tests/standalone.rs @@ -0,0 +1,38 @@ +//! Test cases that have both an input and an output, so do not require a basis. + +use libm_test::generate::case_list; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; + +const BASIS: CheckBasis = CheckBasis::None; + +fn standalone_runner( + ctx: &CheckCtx, + cases: impl Iterator, +) { + for (input, expected) in cases { + let crate_res = input.call_intercept_panics(Op::ROUTINE); + crate_res.validate(expected, input, ctx).unwrap(); + } +} + +macro_rules! mp_tests { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + ) => { + paste::paste! { + #[test] + $(#[$attr])* + fn [< standalone_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::List); + let cases = case_list::get_test_cases_standalone::(&ctx); + standalone_runner::(&ctx, cases); + } + } + }; +} + +libm_macros::for_each_function! { + callback: mp_tests, +} diff --git a/library/compiler-builtins/libm-test/tests/u256.rs b/library/compiler-builtins/libm-test/tests/u256.rs new file mode 100644 index 00000000000..4444036d0a4 --- /dev/null +++ b/library/compiler-builtins/libm-test/tests/u256.rs @@ -0,0 +1,147 @@ +//! Test the u256 implementation. the ops already get exercised reasonably well through the `f128` +//! routines, so this only does a few million fuzz iterations against GMP. + +#![cfg(feature = "build-mpfr")] + +use std::sync::LazyLock; + +use libm::support::{HInt, u256}; +type BigInt = rug::Integer; + +use libm_test::bigint_fuzz_iteration_count; +use libm_test::generate::random::SEED; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; +use rug::Assign; +use rug::integer::Order; +use rug::ops::NotAssign; + +static BIGINT_U256_MAX: LazyLock = + LazyLock::new(|| BigInt::from_digits(&[u128::MAX, u128::MAX], Order::Lsf)); + +/// Copied from the test module. +fn hexu(v: u256) -> String { + format!("0x{:032x}{:032x}", v.hi, v.lo) +} + +fn random_u256(rng: &mut ChaCha8Rng) -> u256 { + let lo: u128 = rng.random(); + let hi: u128 = rng.random(); + u256 { lo, hi } +} + +fn assign_bigint(bx: &mut BigInt, x: u256) { + bx.assign_digits(&[x.lo, x.hi], Order::Lsf); +} + +fn from_bigint(bx: &mut BigInt) -> u256 { + // Truncate so the result fits into `[u128; 2]`. This makes all ops overflowing. + *bx &= &*BIGINT_U256_MAX; + let mut bres = [0u128, 0]; + bx.write_digits(&mut bres, Order::Lsf); + bx.assign(0); + u256 { lo: bres[0], hi: bres[1] } +} + +fn check_one( + x: impl FnOnce() -> String, + y: impl FnOnce() -> Option, + actual: u256, + expected: &mut BigInt, +) { + let expected = from_bigint(expected); + if actual != expected { + let xmsg = x(); + let ymsg = y().map(|y| format!("y: {y}\n")).unwrap_or_default(); + panic!( + "Results do not match\n\ + input: {xmsg}\n\ + {ymsg}\ + actual: {}\n\ + expected: {}\ + ", + hexu(actual), + hexu(expected), + ) + } +} + +#[test] +fn mp_u256_bitor() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + let mut by = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_u256(&mut rng); + let y = random_u256(&mut rng); + assign_bigint(&mut bx, x); + assign_bigint(&mut by, y); + let actual = x | y; + bx |= &by; + check_one(|| hexu(x), || Some(hexu(y)), actual, &mut bx); + } +} + +#[test] +fn mp_u256_not() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_u256(&mut rng); + assign_bigint(&mut bx, x); + let actual = !x; + bx.not_assign(); + check_one(|| hexu(x), || None, actual, &mut bx); + } +} + +#[test] +fn mp_u256_add() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + let mut by = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_u256(&mut rng); + let y = random_u256(&mut rng); + assign_bigint(&mut bx, x); + assign_bigint(&mut by, y); + let actual = x + y; + bx += &by; + check_one(|| hexu(x), || Some(hexu(y)), actual, &mut bx); + } +} + +#[test] +fn mp_u256_shr() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_u256(&mut rng); + let shift: u32 = rng.random_range(0..255); + assign_bigint(&mut bx, x); + let actual = x >> shift; + bx >>= shift; + check_one(|| hexu(x), || Some(shift.to_string()), actual, &mut bx); + } +} + +#[test] +fn mp_u256_widen_mul() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + let mut by = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x: u128 = rng.random(); + let y: u128 = rng.random(); + bx.assign(x); + by.assign(y); + let actual = x.widen_mul(y); + bx *= &by; + check_one(|| format!("{x:#034x}"), || Some(format!("{y:#034x}")), actual, &mut bx); + } +} diff --git a/library/compiler-builtins/libm-test/tests/z_extensive/main.rs b/library/compiler-builtins/libm-test/tests/z_extensive/main.rs new file mode 100644 index 00000000000..5448cb6eaa5 --- /dev/null +++ b/library/compiler-builtins/libm-test/tests/z_extensive/main.rs @@ -0,0 +1,14 @@ +//! `main` is just a wrapper to handle configuration. + +#[cfg(not(feature = "build-mpfr"))] +fn main() { + eprintln!("multiprecision not enabled; skipping extensive tests"); +} + +#[cfg(feature = "build-mpfr")] +mod run; + +#[cfg(feature = "build-mpfr")] +fn main() { + run::run(); +} diff --git a/library/compiler-builtins/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm-test/tests/z_extensive/run.rs new file mode 100644 index 00000000000..b10c231d183 --- /dev/null +++ b/library/compiler-builtins/libm-test/tests/z_extensive/run.rs @@ -0,0 +1,233 @@ +//! Exhaustive tests for `f16` and `f32`, high-iteration for `f64` and `f128`. + +use std::fmt; +use std::io::{self, IsTerminal}; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::time::Duration; + +use indicatif::{ProgressBar, ProgressStyle}; +use libm_test::generate::spaced; +use libm_test::mpfloat::MpOp; +use libm_test::{ + CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TestResult, TupleCall, + skip_extensive_test, +}; +use libtest_mimic::{Arguments, Trial}; +use rayon::prelude::*; +use spaced::SpacedInput; + +const BASIS: CheckBasis = CheckBasis::Mpfr; +const GEN_KIND: GeneratorKind = GeneratorKind::Extensive; + +/// Run the extensive test suite. +pub fn run() { + let mut args = Arguments::from_args(); + // Prevent multiple tests from running in parallel, each test gets parallized internally. + args.test_threads = Some(1); + let tests = register_all_tests(); + + // With default parallelism, the CPU doesn't saturate. We don't need to be nice to + // other processes, so do 1.5x to make sure we use all available resources. + let threads = std::thread::available_parallelism().map(Into::into).unwrap_or(0) * 3 / 2; + rayon::ThreadPoolBuilder::new().num_threads(threads).build_global().unwrap(); + + libtest_mimic::run(&args, tests).exit(); +} + +macro_rules! mp_extensive_tests { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + extra: [$push_to:ident], + ) => { + $(#[$attr])* + register_single_test::(&mut $push_to); + }; +} + +/// Create a list of tests for consumption by `libtest_mimic`. +fn register_all_tests() -> Vec { + let mut all_tests = Vec::new(); + + libm_macros::for_each_function! { + callback: mp_extensive_tests, + extra: [all_tests], + skip: [ + // FIXME: test needed, see + // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 + nextafter, + nextafterf, + ], + } + + all_tests +} + +/// Add a single test to the list. +fn register_single_test(all: &mut Vec) +where + Op: MathOp + MpOp, + Op::RustArgs: SpacedInput + Send, +{ + let test_name = format!("mp_extensive_{}", Op::NAME); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GEN_KIND); + let skip = skip_extensive_test(&ctx); + + let runner = move || { + if !cfg!(optimizations_enabled) { + panic!("extensive tests should be run with --release"); + } + + let res = run_single_test::(&ctx); + let e = match res { + Ok(()) => return Ok(()), + Err(e) => e, + }; + + // Format with the `Debug` implementation so we get the error cause chain, and print it + // here so we see the result immediately (rather than waiting for all tests to conclude). + let e = format!("{e:?}"); + eprintln!("failure testing {}:{e}\n", Op::IDENTIFIER); + + Err(e.into()) + }; + + all.push(Trial::test(test_name, runner).with_ignored_flag(skip)); +} + +/// Test runner for a signle routine. +fn run_single_test(ctx: &CheckCtx) -> TestResult +where + Op: MathOp + MpOp, + Op::RustArgs: SpacedInput + Send, +{ + // Small delay before printing anything so other output from the runner has a chance to flush. + std::thread::sleep(Duration::from_millis(500)); + eprintln!(); + + let completed = AtomicU64::new(0); + let (ref mut cases, total) = spaced::get_test_cases::(ctx); + let pb = Progress::new(Op::NAME, total); + + let test_single_chunk = |mp_vals: &mut Op::MpTy, input_vec: Vec| -> TestResult { + for input in input_vec { + // Test the input. + let mp_res = Op::run(mp_vals, input); + let crate_res = input.call_intercept_panics(Op::ROUTINE); + crate_res.validate(mp_res, input, ctx)?; + + let completed = completed.fetch_add(1, Ordering::Relaxed) + 1; + pb.update(completed, input); + } + + Ok(()) + }; + + // Chunk the cases so Rayon doesn't switch threads between each iterator item. 50k seems near + // a performance sweet spot. Ideally we would reuse these allocations rather than discarding, + // but that is difficult with Rayon's API. + let chunk_size = 50_000; + let chunks = std::iter::from_fn(move || { + let mut v = Vec::with_capacity(chunk_size); + v.extend(cases.take(chunk_size)); + (!v.is_empty()).then_some(v) + }); + + // Run the actual tests + let res = chunks.par_bridge().try_for_each_init(Op::new_mp, test_single_chunk); + + let real_total = completed.load(Ordering::Relaxed); + pb.complete(real_total); + + if res.is_ok() && real_total != total { + // Provide a warning if our estimate needs to be updated. + panic!("total run {real_total} does not match expected {total}"); + } + + res +} + +/// Wrapper around a `ProgressBar` that handles styles and non-TTY messages. +struct Progress { + pb: ProgressBar, + name_padded: String, + final_style: ProgressStyle, + is_tty: bool, +} + +impl Progress { + const PB_TEMPLATE: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \ + {human_pos:>13}/{human_len:13} {per_sec:18} eta {eta:8} {msg}"; + const PB_TEMPLATE_FINAL: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \ + {human_pos:>13}/{human_len:13} {per_sec:18} done in {elapsed_precise}"; + + fn new(name: &str, total: u64) -> Self { + eprintln!("starting extensive tests for `{name}`"); + let name_padded = format!("{name:9}"); + let is_tty = io::stderr().is_terminal(); + + let initial_style = + ProgressStyle::with_template(&Self::PB_TEMPLATE.replace("NAME", &name_padded)) + .unwrap() + .progress_chars("##-"); + + let final_style = + ProgressStyle::with_template(&Self::PB_TEMPLATE_FINAL.replace("NAME", &name_padded)) + .unwrap() + .progress_chars("##-"); + + let pb = ProgressBar::new(total); + pb.set_style(initial_style); + + Self { pb, final_style, name_padded, is_tty } + } + + fn update(&self, completed: u64, input: impl fmt::Debug) { + // Infrequently update the progress bar. + if completed % 20_000 == 0 { + self.pb.set_position(completed); + } + + if completed % 500_000 == 0 { + self.pb.set_message(format!("input: {input:<24?}")); + } + + if !self.is_tty && completed % 5_000_000 == 0 { + let len = self.pb.length().unwrap_or_default(); + eprintln!( + "[{elapsed:3?}s {percent:3.0}%] {name} \ + {human_pos:>10}/{human_len:<10} {per_sec:14.2}/s eta {eta:4}s {input:<24?}", + elapsed = self.pb.elapsed().as_secs(), + percent = completed as f32 * 100.0 / len as f32, + name = self.name_padded, + human_pos = completed, + human_len = len, + per_sec = self.pb.per_sec(), + eta = self.pb.eta().as_secs() + ); + } + } + + fn complete(self, real_total: u64) { + self.pb.set_style(self.final_style); + self.pb.set_position(real_total); + self.pb.abandon(); + + if !self.is_tty { + let len = self.pb.length().unwrap_or_default(); + eprintln!( + "[{elapsed:3}s {percent:3.0}%] {name} \ + {human_pos:>10}/{human_len:<10} {per_sec:14.2}/s done in {elapsed_precise}", + elapsed = self.pb.elapsed().as_secs(), + percent = real_total as f32 * 100.0 / len as f32, + name = self.name_padded, + human_pos = real_total, + human_len = len, + per_sec = self.pb.per_sec(), + elapsed_precise = self.pb.elapsed().as_secs(), + ); + } + + eprintln!(); + } +} diff --git a/library/compiler-builtins/libm/.editorconfig b/library/compiler-builtins/libm/.editorconfig deleted file mode 100644 index ec6e107d547..00000000000 --- a/library/compiler-builtins/libm/.editorconfig +++ /dev/null @@ -1,21 +0,0 @@ -# EditorConfig helps developers define and maintain consistent -# coding styles between different editors and IDEs -# editorconfig.org - -root = true - -[*] -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true -indent_style = space -indent_size = 4 - -[*.md] -# double whitespace at end of line -# denotes a line break in Markdown -trim_trailing_whitespace = false - -[*.yml] -indent_size = 2 diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml deleted file mode 100644 index 5ce0dbc26c8..00000000000 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ /dev/null @@ -1,324 +0,0 @@ -name: CI -on: - push: - branches: - - master - pull_request: - -concurrency: - # Make sure that new pushes cancel running jobs - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -env: - CARGO_TERM_COLOR: always - RUSTDOCFLAGS: -Dwarnings - RUSTFLAGS: -Dwarnings - RUST_BACKTRACE: full - BENCHMARK_RUSTC: nightly-2025-01-16 # Pin the toolchain for reproducable results - -jobs: - test: - name: Build and test - timeout-minutes: 60 - strategy: - fail-fast: false - matrix: - include: - - target: aarch64-apple-darwin - os: macos-15 - # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 - channel: nightly-2025-02-07 - - target: aarch64-unknown-linux-gnu - os: ubuntu-24.04-arm - # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 - channel: nightly-2025-02-07 - - target: aarch64-pc-windows-msvc - os: windows-2025 - build_only: 1 # Can't run on x86 hosts - - target: arm-unknown-linux-gnueabi - os: ubuntu-24.04 - - target: arm-unknown-linux-gnueabihf - os: ubuntu-24.04 - - target: armv7-unknown-linux-gnueabihf - os: ubuntu-24.04 - - target: i586-unknown-linux-gnu - os: ubuntu-24.04 - - target: i686-unknown-linux-gnu - os: ubuntu-24.04 - - target: loongarch64-unknown-linux-gnu - os: ubuntu-24.04 - - target: powerpc-unknown-linux-gnu - os: ubuntu-24.04 - - target: powerpc64-unknown-linux-gnu - os: ubuntu-24.04 - - target: powerpc64le-unknown-linux-gnu - os: ubuntu-24.04 - - target: riscv64gc-unknown-linux-gnu - os: ubuntu-24.04 - - target: thumbv6m-none-eabi - os: ubuntu-24.04 - - target: thumbv7em-none-eabi - os: ubuntu-24.04 - - target: thumbv7em-none-eabihf - os: ubuntu-24.04 - - target: thumbv7m-none-eabi - os: ubuntu-24.04 - - target: x86_64-unknown-linux-gnu - os: ubuntu-24.04 - - target: x86_64-apple-darwin - os: macos-13 - - target: wasm32-unknown-unknown - os: ubuntu-24.04 - build_only: 1 - - target: i686-pc-windows-msvc - os: windows-2025 - - target: x86_64-pc-windows-msvc - os: windows-2025 - - target: i686-pc-windows-gnu - os: windows-2025 - # FIXME: pinned due to https://github.com/rust-lang/rust/issues/136795 - channel: nightly-2025-02-07-i686-gnu - - target: x86_64-pc-windows-gnu - os: windows-2025 - channel: nightly-x86_64-gnu - runs-on: ${{ matrix.os }} - env: - BUILD_ONLY: ${{ matrix.build_only }} - steps: - - name: Print runner information - run: uname -a - - uses: actions/checkout@v4 - with: - submodules: true - - name: Install Rust (rustup) - shell: bash - run: | - channel="nightly" - # Account for channels that have required components (MinGW) - [ -n "${{ matrix.channel }}" ] && channel="${{ matrix.channel }}" - rustup update "$channel" --no-self-update - rustup default "$channel" - rustup target add "${{ matrix.target }}" - rustup component add clippy llvm-tools-preview - - uses: taiki-e/install-action@nextest - - uses: Swatinem/rust-cache@v2 - with: - key: ${{ matrix.target }} - - - name: Verify API list - if: matrix.os == 'ubuntu-24.04' - run: python3 etc/update-api-list.py --check - - # Non-linux tests just use our raw script - - name: Run locally - if: matrix.os != 'ubuntu-24.04' || contains(matrix.target, 'wasm') - shell: bash - run: ./ci/run.sh ${{ matrix.target }} - - # Otherwise we use our docker containers to run builds - - name: Run in Docker - if: matrix.os == 'ubuntu-24.04' && !contains(matrix.target, 'wasm') - run: | - rustup target add x86_64-unknown-linux-musl - cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} - - - name: Print test logs if available - if: always() - run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi - shell: bash - - clippy: - name: Clippy - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@master - with: - submodules: true - - name: Install Rust - run: | - rustup update nightly --no-self-update - rustup default nightly - rustup component add clippy - - uses: Swatinem/rust-cache@v2 - - run: cargo clippy --all --all-features --all-targets - - builtins: - name: Check use with compiler-builtins - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@master - - name: Install Rust - run: rustup update nightly --no-self-update && rustup default nightly - - uses: Swatinem/rust-cache@v2 - - run: cargo check --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml - - run: cargo test --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml - - benchmarks: - name: Benchmarks - runs-on: ubuntu-24.04 - timeout-minutes: 20 - steps: - - uses: actions/checkout@master - with: - submodules: true - - uses: taiki-e/install-action@cargo-binstall - - - name: Set up dependencies - run: | - sudo apt update - sudo apt install -y valgrind gdb libc6-dbg # Needed for iai-callgrind - rustup update "$BENCHMARK_RUSTC" --no-self-update - rustup default "$BENCHMARK_RUSTC" - # Install the version of iai-callgrind-runner that is specified in Cargo.toml - iai_version="$(cargo metadata --format-version=1 --features icount | - jq -r '.packages[] | select(.name == "iai-callgrind").version')" - cargo binstall -y iai-callgrind-runner --version "$iai_version" - sudo apt-get install valgrind - - - uses: Swatinem/rust-cache@v2 - - - name: Run icount benchmarks - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - run: ./ci/bench-icount.sh - - - name: Upload the benchmark baseline - uses: actions/upload-artifact@v4 - with: - name: ${{ env.BASELINE_NAME }} - path: ${{ env.BASELINE_NAME }}.tar.xz - - - name: Run wall time benchmarks - run: | - # Always use the same seed for benchmarks. Ideally we should switch to a - # non-random generator. - export LIBM_SEED=benchesbenchesbenchesbencheswoo! - cargo bench --all --features short-benchmarks,build-musl,force-soft-floats - - - name: Print test logs if available - if: always() - run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi - shell: bash - - msrv: - name: Check MSRV - runs-on: ubuntu-24.04 - timeout-minutes: 10 - env: - RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` - steps: - - uses: actions/checkout@master - - name: Install Rust - run: | - msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' libm/Cargo.toml)" - echo "MSRV: $msrv" - rustup update "$msrv" --no-self-update && rustup default "$msrv" - - uses: Swatinem/rust-cache@v2 - - run: | - # FIXME(msrv): Remove the workspace Cargo.toml so 1.63 cargo doesn't see - # `edition = "2024"` and get spooked. - rm Cargo.toml - cargo build --manifest-path libm/Cargo.toml - - rustfmt: - name: Rustfmt - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@master - - name: Install Rust - run: | - rustup update nightly --no-self-update - rustup default nightly - rustup component add rustfmt - - run: cargo fmt -- --check - - # Determine which extensive tests should be run based on changed files. - calculate_extensive_matrix: - name: Calculate job matrix - runs-on: ubuntu-24.04 - timeout-minutes: 10 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - outputs: - matrix: ${{ steps.script.outputs.matrix }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 100 - - name: Fetch pull request ref - run: git fetch origin "$GITHUB_REF:$GITHUB_REF" - if: github.event_name == 'pull_request' - - run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT" - id: script - - extensive: - name: Extensive tests for ${{ matrix.ty }} - needs: - # Wait on `clippy` so we have some confidence that the crate will build - - clippy - - calculate_extensive_matrix - runs-on: ubuntu-24.04 - timeout-minutes: 240 # 4 hours - strategy: - matrix: - # Use the output from `calculate_extensive_matrix` to calculate the matrix - # FIXME: it would be better to run all jobs (i.e. all types) but mark those that - # didn't change as skipped, rather than completely excluding the job. However, - # this is not currently possible https://github.com/actions/runner/issues/1985. - include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }} - env: - TO_TEST: ${{ matrix.to_test }} - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Install Rust - run: | - rustup update nightly --no-self-update - rustup default nightly - - uses: Swatinem/rust-cache@v2 - - name: Run extensive tests - run: | - echo "Tests to run: '$TO_TEST'" - if [ -z "$TO_TEST" ]; then - echo "No tests to run, exiting." - exit - fi - - set -x - - # Run the non-extensive tests first to catch any easy failures - cargo t --profile release-checked -- "$TO_TEST" - - LIBM_EXTENSIVE_TESTS="$TO_TEST" cargo t \ - --features build-mpfr,unstable,force-soft-floats \ - --profile release-checked \ - -- extensive - - name: Print test logs if available - run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi - shell: bash - - success: - needs: - - test - - builtins - - benchmarks - - msrv - - rustfmt - - extensive - runs-on: ubuntu-24.04 - timeout-minutes: 10 - # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency - # failed" as success. So we have to do some contortions to ensure the job fails if any of its - # dependencies fails. - if: always() # make sure this is never "skipped" - steps: - # Manually check the status of all dependencies. `if: failure()` does not work. - - name: check if any dependency failed - run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/library/compiler-builtins/libm/.github/workflows/publish.yaml b/library/compiler-builtins/libm/.github/workflows/publish.yaml deleted file mode 100644 index 15904079d27..00000000000 --- a/library/compiler-builtins/libm/.github/workflows/publish.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: Release-plz - -permissions: - pull-requests: write - contents: write - -on: - push: - branches: - - master - -jobs: - release-plz: - name: Release-plz - runs-on: ubuntu-24.04 - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Install Rust (rustup) - run: rustup update nightly --no-self-update && rustup default nightly - - name: Run release-plz - uses: MarcoIeni/release-plz-action@v0.5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/library/compiler-builtins/libm/.gitignore b/library/compiler-builtins/libm/.gitignore deleted file mode 100644 index d5caba1a0f3..00000000000 --- a/library/compiler-builtins/libm/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -**.bk -.#* -/bin -/math/src -target -Cargo.lock -**.tar.gz - -# Benchmark cache -iai-home -baseline-* diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml deleted file mode 100644 index 268b6fb0e6d..00000000000 --- a/library/compiler-builtins/libm/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[workspace] -resolver = "2" -members = [ - "libm", - "crates/libm-macros", - "crates/libm-test", - "crates/musl-math-sys", - "crates/util", -] -default-members = [ - "libm", - "crates/libm-macros", - "crates/libm-test" -] -exclude = [ - # Requires `panic = abort` so can't be a member of the workspace - "crates/compiler-builtins-smoke-test", -] - -# The default release profile is unchanged. - -# Release mode with debug assertions -[profile.release-checked] -inherits = "release" -debug-assertions = true -overflow-checks = true - -# Release with maximum optimizations, which is very slow to build. This is also -# what is needed to check `no-panic`. -[profile.release-opt] -inherits = "release" -codegen-units = 1 -lto = "fat" - -[profile.bench] -# Required for iai-callgrind -debug = true diff --git a/library/compiler-builtins/libm/LICENSE.txt b/library/compiler-builtins/libm/LICENSE.txt deleted file mode 100644 index 2f8e41f1474..00000000000 --- a/library/compiler-builtins/libm/LICENSE.txt +++ /dev/null @@ -1,258 +0,0 @@ -rust-lang/libm as a whole is available for use under the MIT license: - ------------------------------------------------------------------------------- -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. ------------------------------------------------------------------------------- - -As a contributor, you agree that your code can be used under either the MIT -license or the Apache-2.0 license: - ------------------------------------------------------------------------------- - 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. - - 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. ------------------------------------------------------------------------------- - -This Rust library contains the following copyrights: - - Copyright (c) 2018 Jorge Aparicio - -Portions of this software are derived from third-party works licensed under -terms compatible with the above MIT license: - -* musl libc https://www.musl-libc.org/. This library contains the following - copyright: - - Copyright © 2005-2020 Rich Felker, et al. - -* The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH - routines are available under the MIT license on a per-file basis. - -The musl libc COPYRIGHT file also includes the following notice relevant to -math portions of the library: - ------------------------------------------------------------------------------- -Much of the math library code (src/math/* and src/complex/*) is -Copyright © 1993,2004 Sun Microsystems or -Copyright © 2003-2011 David Schultz or -Copyright © 2003-2009 Steven G. Kargl or -Copyright © 2003-2009 Bruce D. Evans or -Copyright © 2008 Stephen L. Moshier or -Copyright © 2017-2018 Arm Limited -and labelled as such in comments in the individual source files. All -have been licensed under extremely permissive terms. ------------------------------------------------------------------------------- - -Copyright notices are retained in src/* files where relevant. diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md deleted file mode 100644 index 52d760a4f15..00000000000 --- a/library/compiler-builtins/libm/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# `libm` - -A port of [MUSL]'s libm to Rust. - -[MUSL]: https://musl.libc.org/ - -## Goals - -The short term goal of this library is to [enable math support (e.g. `sin`, `atan2`) for the -`wasm32-unknown-unknown` target][wasm] (cf. [rust-lang/compiler-builtins][pr]). The longer -term goal is to enable [math support in the `core` crate][core]. - -[wasm]: https://github.com/rust-lang/libm/milestone/1 -[pr]: https://github.com/rust-lang/compiler-builtins/pull/248 -[core]: https://github.com/rust-lang/libm/milestone/2 - -## Already usable - -This crate is [on crates.io] and can be used today in stable `#![no_std]` programs. - -The API documentation can be found [here](https://docs.rs/libm). - -[on crates.io]: https://crates.io/crates/libm - -## Benchmark -[benchmark]: #benchmark - -The benchmarks are located in `crates/libm-bench` and require a nightly Rust toolchain. -To run all benchmarks: - -> cargo +nightly bench --all - -## Contributing - -Please check [CONTRIBUTING.md](CONTRIBUTING.md) - -## Minimum Rust version policy - -This crate supports rustc 1.63 and newer. - -## License - -Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or -https://opensource.org/licenses/MIT). - - -### Contribution - -Contributions are licensed under both the MIT license and the Apache License, -Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or -https://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state -otherwise, any contribution intentionally submitted for inclusion in the work -by you, as defined in the Apache-2.0 license, shall be dual licensed as -mentioned, without any additional terms or conditions. - -See `LICENSE.txt` for full details. diff --git a/library/compiler-builtins/libm/ci/bench-icount.sh b/library/compiler-builtins/libm/ci/bench-icount.sh deleted file mode 100755 index 4d93e257a6c..00000000000 --- a/library/compiler-builtins/libm/ci/bench-icount.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash - -set -eux - -iai_home="iai-home" - -# Download the baseline from master -./ci/ci-util.py locate-baseline --download --extract - -# Run benchmarks once -function run_icount_benchmarks() { - cargo_args=( - "--bench" "icount" - "--no-default-features" - "--features" "unstable,unstable-float,icount" - ) - - iai_args=( - "--home" "$(pwd)/$iai_home" - "--regression=ir=5.0" - "--save-summary" - ) - - # Parse `cargo_arg0 cargo_arg1 -- iai_arg0 iai_arg1` syntax - parsing_iai_args=0 - while [ "$#" -gt 0 ]; do - if [ "$parsing_iai_args" == "1" ]; then - iai_args+=("$1") - elif [ "$1" == "--" ]; then - parsing_iai_args=1 - else - cargo_args+=("$1") - fi - - shift - done - - # Run iai-callgrind benchmarks - cargo bench "${cargo_args[@]}" -- "${iai_args[@]}" - - # NB: iai-callgrind should exit on error but does not, so we inspect the sumary - # for errors. See https://github.com/iai-callgrind/iai-callgrind/issues/337 - if [ -n "${PR_NUMBER:-}" ]; then - # If this is for a pull request, ignore regressions if specified. - ./ci/ci-util.py check-regressions --home "$iai_home" --allow-pr-override "$PR_NUMBER" - else - ./ci/ci-util.py check-regressions --home "$iai_home" || true - fi -} - -# Run once with softfloats, once with arch instructions enabled -run_icount_benchmarks --features force-soft-floats -- --save-baseline=softfloat -run_icount_benchmarks -- --save-baseline=hardfloat - -# Name and tar the new baseline -name="baseline-icount-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}" -echo "BASELINE_NAME=$name" >>"$GITHUB_ENV" -tar cJf "$name.tar.xz" "$iai_home" diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py deleted file mode 100755 index d9e402d6bd7..00000000000 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ /dev/null @@ -1,416 +0,0 @@ -#!/usr/bin/env python3 -"""Utilities for CI. - -This dynamically prepares a list of routines that had a source file change based on -git history. -""" - -import json -import os -import subprocess as sp -import sys -from dataclasses import dataclass -from glob import glob, iglob -from inspect import cleandoc -from os import getenv -from pathlib import Path -from typing import TypedDict, Self - -USAGE = cleandoc( - """ - usage: - - ./ci/ci-util.py [flags] - - COMMAND: - generate-matrix - Calculate a matrix of which functions had source change, print that as - a JSON object. - - locate-baseline [--download] [--extract] - Locate the most recent benchmark baseline available in CI and, if flags - specify, download and extract it. Never exits with nonzero status if - downloading fails. - - Note that `--extract` will overwrite files in `iai-home`. - - check-regressions [--home iai-home] [--allow-pr-override pr_number] - Check `iai-home` (or `iai-home` if unspecified) for `summary.json` - files and see if there are any regressions. This is used as a workaround - for `iai-callgrind` not exiting with error status; see - . - - If `--allow-pr-override` is specified, the regression check will not exit - with failure if any line in the PR starts with `allow-regressions`. - """ -) - -REPO_ROOT = Path(__file__).parent.parent -GIT = ["git", "-C", REPO_ROOT] -DEFAULT_BRANCH = "master" -WORKFLOW_NAME = "CI" # Workflow that generates the benchmark artifacts -ARTIFACT_GLOB = "baseline-icount*" -# Place this in a PR body to skip regression checks (must be at the start of a line). -REGRESSION_DIRECTIVE = "ci: allow-regressions" -# Place this in a PR body to skip extensive tests -SKIP_EXTENSIVE_DIRECTIVE = "ci: skip-extensive" -# Place this in a PR body to allow running a large number of extensive tests. If not -# set, this script will error out if a threshold is exceeded in order to avoid -# accidentally spending huge amounts of CI time. -ALLOW_MANY_EXTENSIVE_DIRECTIVE = "ci: allow-many-extensive" -MANY_EXTENSIVE_THRESHOLD = 20 - -# Don't run exhaustive tests if these files change, even if they contaiin a function -# definition. -IGNORE_FILES = [ - "libm/src/math/support/", - "libm/src/libm_helper.rs", - "libm/src/math/arch/intrinsics.rs", -] - -TYPES = ["f16", "f32", "f64", "f128"] - - -def eprint(*args, **kwargs): - """Print to stderr.""" - print(*args, file=sys.stderr, **kwargs) - - -@dataclass -class PrInfo: - """GitHub response for PR query""" - - body: str - commits: list[str] - created_at: str - number: int - - @classmethod - def load(cls, pr_number: int | str) -> Self: - """For a given PR number, query the body and commit list""" - pr_info = sp.check_output( - [ - "gh", - "pr", - "view", - str(pr_number), - "--json=number,commits,body,createdAt", - # Flatten the commit list to only hashes, change a key to snake naming - "--jq=.commits |= map(.oid) | .created_at = .createdAt | del(.createdAt)", - ], - text=True, - ) - eprint("PR info:", json.dumps(pr_info, indent=4)) - return cls(**json.loads(pr_info)) - - def contains_directive(self, directive: str) -> bool: - """Return true if the provided directive is on a line in the PR body""" - lines = self.body.splitlines() - return any(line.startswith(directive) for line in lines) - - -class FunctionDef(TypedDict): - """Type for an entry in `function-definitions.json`""" - - sources: list[str] - type: str - - -@dataclass -class Context: - gh_ref: str | None - changed: list[Path] - defs: dict[str, FunctionDef] - - def __init__(self) -> None: - self.gh_ref = getenv("GITHUB_REF") - self.changed = [] - self._init_change_list() - - with open(REPO_ROOT.joinpath("etc/function-definitions.json")) as f: - defs = json.load(f) - - defs.pop("__comment", None) - self.defs = defs - - def _init_change_list(self): - """Create a list of files that have been changed. This uses GITHUB_REF if - available, otherwise a diff between `HEAD` and `master`. - """ - - # For pull requests, GitHub creates a ref `refs/pull/1234/merge` (1234 being - # the PR number), and sets this as `GITHUB_REF`. - ref = self.gh_ref - eprint(f"using ref `{ref}`") - if ref is None or "merge" not in ref: - # If the ref is not for `merge` then we are not in PR CI - eprint("No diff available for ref") - return - - # The ref is for a dummy merge commit. We can extract the merge base by - # inspecting all parents (`^@`). - merge_sha = sp.check_output( - GIT + ["show-ref", "--hash", ref], text=True - ).strip() - merge_log = sp.check_output(GIT + ["log", "-1", merge_sha], text=True) - eprint(f"Merge:\n{merge_log}\n") - - parents = ( - sp.check_output(GIT + ["rev-parse", f"{merge_sha}^@"], text=True) - .strip() - .splitlines() - ) - assert len(parents) == 2, f"expected two-parent merge but got:\n{parents}" - base = parents[0].strip() - incoming = parents[1].strip() - - eprint(f"base: {base}, incoming: {incoming}") - textlist = sp.check_output( - GIT + ["diff", base, incoming, "--name-only"], text=True - ) - self.changed = [Path(p) for p in textlist.splitlines()] - - @staticmethod - def _ignore_file(fname: str) -> bool: - return any(fname.startswith(pfx) for pfx in IGNORE_FILES) - - def changed_routines(self) -> dict[str, list[str]]: - """Create a list of routines for which one or more files have been updated, - separated by type. - """ - routines = set() - for name, meta in self.defs.items(): - # Don't update if changes to the file should be ignored - sources = (f for f in meta["sources"] if not self._ignore_file(f)) - - # Select changed files - changed = [f for f in sources if Path(f) in self.changed] - - if len(changed) > 0: - eprint(f"changed files for {name}: {changed}") - routines.add(name) - - ret: dict[str, list[str]] = {} - for r in sorted(routines): - ret.setdefault(self.defs[r]["type"], []).append(r) - - return ret - - def make_workflow_output(self) -> str: - """Create a JSON object a list items for each type's changed files, if any - did change, and the routines that were affected by the change. - """ - - pr_number = os.environ.get("PR_NUMBER") - skip_tests = False - error_on_many_tests = False - - if pr_number is not None and len(pr_number) > 0: - pr = PrInfo.load(pr_number) - skip_tests = pr.contains_directive(SKIP_EXTENSIVE_DIRECTIVE) - error_on_many_tests = not pr.contains_directive( - ALLOW_MANY_EXTENSIVE_DIRECTIVE - ) - - if skip_tests: - eprint("Skipping all extensive tests") - - changed = self.changed_routines() - ret = [] - total_to_test = 0 - - for ty in TYPES: - ty_changed = changed.get(ty, []) - ty_to_test = [] if skip_tests else ty_changed - total_to_test += len(ty_to_test) - - item = { - "ty": ty, - "changed": ",".join(ty_changed), - "to_test": ",".join(ty_to_test), - } - - ret.append(item) - output = json.dumps({"matrix": ret}, separators=(",", ":")) - eprint(f"output: {output}") - eprint(f"total extensive tests: {total_to_test}") - - if error_on_many_tests and total_to_test > MANY_EXTENSIVE_THRESHOLD: - eprint( - f"More than {MANY_EXTENSIVE_THRESHOLD} tests would be run; add" - f" `{ALLOW_MANY_EXTENSIVE_DIRECTIVE}` to the PR body if this is intentional" - ) - exit(1) - - return output - - -def locate_baseline(flags: list[str]) -> None: - """Find the most recent baseline from CI, download it if specified. - - This returns rather than erroring, even if the `gh` commands fail. This is to avoid - erroring in CI if the baseline is unavailable (artifact time limit exceeded, first - run on the branch, etc). - """ - - download = False - extract = False - - while len(flags) > 0: - match flags[0]: - case "--download": - download = True - case "--extract": - extract = True - case _: - eprint(USAGE) - exit(1) - flags = flags[1:] - - if extract and not download: - eprint("cannot extract without downloading") - exit(1) - - try: - # Locate the most recent job to complete with success on our branch - latest_job = sp.check_output( - [ - "gh", - "run", - "list", - "--status=success", - f"--branch={DEFAULT_BRANCH}", - "--json=databaseId,url,headSha,conclusion,createdAt," - "status,workflowDatabaseId,workflowName", - # Return the first array element matching our workflow name. NB: cannot - # just use `--limit=1`, jq filtering happens after limiting. We also - # cannot just use `--workflow` because GH gets confused from - # different file names in history. - f'--jq=[.[] | select(.workflowName == "{WORKFLOW_NAME}")][0]', - ], - text=True, - ) - except sp.CalledProcessError as e: - eprint(f"failed to run github command: {e}") - return - - try: - latest = json.loads(latest_job) - eprint("latest job: ", json.dumps(latest, indent=4)) - except json.JSONDecodeError as e: - eprint(f"failed to decode json '{latest_job}', {e}") - return - - if not download: - eprint("--download not specified, returning") - return - - job_id = latest.get("databaseId") - if job_id is None: - eprint("skipping download step") - return - - sp.run( - ["gh", "run", "download", str(job_id), f"--pattern={ARTIFACT_GLOB}"], - check=False, - ) - - if not extract: - eprint("skipping extraction step") - return - - # Find the baseline with the most recent timestamp. GH downloads the files to e.g. - # `some-dirname/some-dirname.tar.xz`, so just glob the whole thing together. - candidate_baselines = glob(f"{ARTIFACT_GLOB}/{ARTIFACT_GLOB}") - if len(candidate_baselines) == 0: - eprint("no possible baseline directories found") - return - - candidate_baselines.sort(reverse=True) - baseline_archive = candidate_baselines[0] - eprint(f"extracting {baseline_archive}") - sp.run(["tar", "xJvf", baseline_archive], check=True) - eprint("baseline extracted successfully") - - -def check_iai_regressions(args: list[str]): - """Find regressions in iai summary.json files, exit with failure if any are - found. - """ - - iai_home_str = "iai-home" - pr_number = None - - while len(args) > 0: - match args: - case ["--home", home, *rest]: - iai_home_str = home - args = rest - case ["--allow-pr-override", pr_num, *rest]: - pr_number = pr_num - args = rest - case _: - eprint(USAGE) - exit(1) - - iai_home = Path(iai_home_str) - - found_summaries = False - regressions: list[dict] = [] - for summary_path in iglob("**/summary.json", root_dir=iai_home, recursive=True): - found_summaries = True - with open(iai_home / summary_path, "r") as f: - summary = json.load(f) - - summary_regs = [] - run = summary["callgrind_summary"]["callgrind_run"] - fname = summary["function_name"] - id = summary["id"] - name_entry = {"name": f"{fname}.{id}"} - - for segment in run["segments"]: - summary_regs.extend(segment["regressions"]) - - summary_regs.extend(run["total"]["regressions"]) - - regressions.extend(name_entry | reg for reg in summary_regs) - - if not found_summaries: - eprint(f"did not find any summary.json files within {iai_home}") - exit(1) - - if len(regressions) == 0: - eprint("No regressions found") - return - - eprint("Found regressions:", json.dumps(regressions, indent=4)) - - if pr_number is not None: - pr = PrInfo.load(pr_number) - if pr.contains_directive(REGRESSION_DIRECTIVE): - eprint("PR allows regressions, returning") - return - - exit(1) - - -def main(): - match sys.argv[1:]: - case ["generate-matrix"]: - ctx = Context() - output = ctx.make_workflow_output() - print(f"matrix={output}") - case ["locate-baseline", *flags]: - locate_baseline(flags) - case ["check-regressions", *args]: - check_iai_regressions(args) - case ["--help" | "-h"]: - print(USAGE) - exit() - case _: - eprint(USAGE) - exit(1) - - -if __name__ == "__main__": - main() diff --git a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 7fa06b28601..00000000000 --- a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-aarch64-linux-gnu m4 make libc6-dev-arm64-cross \ - qemu-user-static - -ENV TOOLCHAIN_PREFIX=aarch64-linux-gnu- -ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-aarch64-static \ - AR_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile deleted file mode 100644 index e070a7d936e..00000000000 --- a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static - -ENV TOOLCHAIN_PREFIX=arm-linux-gnueabi- -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER=qemu-arm-static \ - AR_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"ar \ - CC_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile deleted file mode 100644 index 29f1e04a9b5..00000000000 --- a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static - -ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ - AR_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ - CC_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile deleted file mode 100644 index 0a30801b44d..00000000000 --- a/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static - -ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- -ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ - AR_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ - CC_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 37e206a84fc..00000000000 --- a/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc-multilib m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 37e206a84fc..00000000000 --- a/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc-multilib m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index a9ce320e8b4..00000000000 --- a/library/compiler-builtins/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-14-loongarch64-linux-gnu libc6-dev-loong64-cross - -ENV CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER=loongarch64-linux-gnu-gcc-14 \ - CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-loongarch64-static \ - AR_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-ar \ - CC_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-gcc-14 \ - QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 298208c925a..00000000000 --- a/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-mips-linux-gnu libc6-dev-mips-cross \ - binfmt-support qemu-user-static qemu-system-mips - -ENV TOOLCHAIN_PREFIX=mips-linux-gnu- -ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER=qemu-mips-static \ - AR_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/mips-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile deleted file mode 100644 index 101b3853efe..00000000000 --- a/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates \ - gcc \ - gcc-mips64-linux-gnuabi64 \ - libc6-dev \ - libc6-dev-mips64-cross \ - qemu-user-static \ - qemu-system-mips - -ENV TOOLCHAIN_PREFIX=mips64-linux-gnuabi64- -ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64-static \ - AR_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ - CC_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile deleted file mode 100644 index 0eb14f9acf5..00000000000 --- a/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates \ - gcc \ - gcc-mips64el-linux-gnuabi64 \ - libc6-dev \ - libc6-dev-mips64el-cross \ - qemu-user-static - -ENV TOOLCHAIN_PREFIX=mips64el-linux-gnuabi64- -ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64el-static \ - AR_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ - CC_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 1b9817cfef8..00000000000 --- a/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ - binfmt-support qemu-user-static - -ENV TOOLCHAIN_PREFIX=mipsel-linux-gnu- -ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER=qemu-mipsel-static \ - AR_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 1ea2e30a242..00000000000 --- a/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ - qemu-system-ppc - -ENV TOOLCHAIN_PREFIX=powerpc-linux-gnu- -ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc-static \ - AR_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 373814bcafd..00000000000 --- a/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ - binfmt-support qemu-user-static qemu-system-ppc - -ENV TOOLCHAIN_PREFIX=powerpc64-linux-gnu- -ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64-static \ - AR_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 403bb1d95b2..00000000000 --- a/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ - qemu-system-ppc - -ENV TOOLCHAIN_PREFIX=powerpc64le-linux-gnu- -ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64le-static \ - AR_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_CPU=POWER8 \ - QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 5f8a2892411..00000000000 --- a/library/compiler-builtins/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-riscv64-linux-gnu libc6-dev-riscv64-cross \ - qemu-system-riscv64 - -ENV TOOLCHAIN_PREFIX=riscv64-linux-gnu- -ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER=qemu-riscv64-static \ - AR_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/riscv64-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/thumbv6m-none-eabi/Dockerfile deleted file mode 100644 index ad0d4351ea6..00000000000 --- a/library/compiler-builtins/libm/ci/docker/thumbv6m-none-eabi/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -ARG IMAGE=ubuntu:24.04 -FROM $IMAGE - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-none-eabi \ - libnewlib-arm-none-eabi -ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabi/Dockerfile deleted file mode 100644 index ad0d4351ea6..00000000000 --- a/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabi/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -ARG IMAGE=ubuntu:24.04 -FROM $IMAGE - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-none-eabi \ - libnewlib-arm-none-eabi -ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile deleted file mode 100644 index ad0d4351ea6..00000000000 --- a/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -ARG IMAGE=ubuntu:24.04 -FROM $IMAGE - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-none-eabi \ - libnewlib-arm-none-eabi -ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/libm/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/thumbv7m-none-eabi/Dockerfile deleted file mode 100644 index ad0d4351ea6..00000000000 --- a/library/compiler-builtins/libm/ci/docker/thumbv7m-none-eabi/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -ARG IMAGE=ubuntu:24.04 -FROM $IMAGE - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-none-eabi \ - libnewlib-arm-none-eabi -ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index c84a31c57a9..00000000000 --- a/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh deleted file mode 100755 index 6626e722685..00000000000 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -# Small script to run tests for a target (or all targets) inside all the -# respective docker images. - -set -euxo pipefail - -host_arch="$(uname -m | sed 's/arm64/aarch64/')" - -run() { - local target=$1 - - echo "testing target: $target" - - target_arch="$(echo "$target" | cut -d'-' -f1)" - - emulated="" - if [ "$target_arch" != "$host_arch" ]; then - emulated=1 - echo "target is emulated" - fi - - # This directory needs to exist before calling docker, otherwise docker will create it but it - # will be owned by root - mkdir -p target - - set_env="HOME=/tmp PATH=\$PATH:/rust/bin:/cargo/bin" - docker build -t "libm-$target" "ci/docker/$target" - docker run \ - --rm \ - --user "$(id -u):$(id -g)" \ - -e CI \ - -e RUSTFLAGS \ - -e CARGO_TERM_COLOR \ - -e CARGO_HOME=/cargo \ - -e CARGO_TARGET_DIR=/target \ - -e "EMULATED=$emulated" \ - -v "${HOME}/.cargo:/cargo" \ - -v "$(pwd)/target:/target" \ - -v "$(pwd):/checkout:ro" \ - -v "$(rustc --print sysroot):/rust:ro" \ - --init \ - -w /checkout \ - "libm-$target" \ - sh -c "$set_env exec ci/run.sh $target" -} - -if [ -z "$1" ]; then - echo "running tests for all targets" - - for d in ci/docker/*; do - run $d - done -else - run $1 -fi diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh deleted file mode 100755 index a946d325ebd..00000000000 --- a/library/compiler-builtins/libm/ci/run.sh +++ /dev/null @@ -1,130 +0,0 @@ -#!/bin/sh - -set -eux - -export RUST_BACKTRACE="${RUST_BACKTRACE:-full}" -export NEXTEST_STATUS_LEVEL=all - -target="${1:-}" -flags="" - -if [ -z "$target" ]; then - host_target=$(rustc -vV | awk '/^host/ { print $2 }') - echo "Defaulted to host target $host_target" - target="$host_target" -fi - -# We enumerate features manually. -flags="$flags --no-default-features" - -# Enable arch-specific routines when available. -flags="$flags --features arch" - -# Always enable `unstable-float` since it expands available API but does not -# change any implementations. -flags="$flags --features unstable-float" - -# We need to specifically skip tests for musl-math-sys on systems that can't -# build musl since otherwise `--all` will activate it. -case "$target" in - # Can't build at all on MSVC, WASM, or thumb - *windows-msvc*) flags="$flags --exclude musl-math-sys" ;; - *wasm*) flags="$flags --exclude musl-math-sys" ;; - *thumb*) flags="$flags --exclude musl-math-sys" ;; - - # We can build musl on MinGW but running tests gets a stack overflow - *windows-gnu*) ;; - # FIXME(#309): LE PPC crashes calling the musl version of some functions. It - # seems like a qemu bug but should be investigated further at some point. - # See . - *powerpc64le*) ;; - - # Everything else gets musl enabled - *) flags="$flags --features libm-test/build-musl" ;; -esac - -# Configure which targets test against MPFR -case "$target" in - # MSVC cannot link MPFR - *windows-msvc*) ;; - # FIXME: MinGW should be able to build MPFR, but setup in CI is nontrivial. - *windows-gnu*) ;; - # Targets that aren't cross compiled in CI work fine - aarch64*apple*) flags="$flags --features libm-test/build-mpfr" ;; - aarch64*linux*) flags="$flags --features libm-test/build-mpfr" ;; - i586*) flags="$flags --features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross" ;; - i686*) flags="$flags --features libm-test/build-mpfr" ;; - x86_64*) flags="$flags --features libm-test/build-mpfr" ;; -esac - -# FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. -# -case "$target" in - *windows-gnu) flags="$flags --exclude libm-macros" ;; -esac - -# Make sure we can build with overriding features. -cargo check -p libm --no-default-features - -if [ "${BUILD_ONLY:-}" = "1" ]; then - # If we are on targets that can't run tests, verify that we can build. - cmd="cargo build --target $target --package libm" - $cmd - $cmd --features unstable-intrinsics - - echo "can't run tests on $target; skipping" - exit -fi - -flags="$flags --all --target $target" -cmd="cargo test $flags" -profile="--profile" - -# If nextest is available, use that -command -v cargo-nextest && nextest=1 || nextest=0 -if [ "$nextest" = "1" ]; then - # Workaround for https://github.com/nextest-rs/nextest/issues/2066 - if [ -f /.dockerenv ]; then - cfg_file="/tmp/nextest-config.toml" - echo "[store]" >> "$cfg_file" - echo "dir = \"$CARGO_TARGET_DIR/nextest\"" >> "$cfg_file" - cfg_flag="--config-file $cfg_file" - fi - - cmd="cargo nextest run ${cfg_flag:-} --max-fail=10 $flags" - profile="--cargo-profile" -fi - -# Test once without intrinsics -$cmd - -# Run doctests if they were excluded by nextest -[ "$nextest" = "1" ] && cargo test --doc $flags - -# Exclude the macros and utile crates from the rest of the tests to save CI -# runtime, they shouldn't have anything feature- or opt-level-dependent. -cmd="$cmd --exclude util --exclude libm-macros" - -# Test once with intrinsics enabled -$cmd --features unstable-intrinsics -$cmd --features unstable-intrinsics --benches - -# Test the same in release mode, which also increases coverage. Also ensure -# the soft float routines are checked. -$cmd "$profile" release-checked -$cmd "$profile" release-checked --features force-soft-floats -$cmd "$profile" release-checked --features unstable-intrinsics -$cmd "$profile" release-checked --features unstable-intrinsics --benches - -# Ensure that the routines do not panic. -# -# `--tests` must be passed because no-panic is only enabled as a dev -# dependency. The `release-opt` profile must be used to enable LTO and a -# single CGU. -ENSURE_NO_PANIC=1 cargo build \ - -p libm \ - --target "$target" \ - --no-default-features \ - --features unstable-float \ - --tests \ - --profile release-opt diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml deleted file mode 100644 index 50c869db7ff..00000000000 --- a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "libm-macros" -version = "0.1.0" -edition = "2024" -publish = false - -[lib] -proc-macro = true - -[dependencies] -heck = "0.5.0" -proc-macro2 = "1.0.94" -quote = "1.0.40" -syn = { version = "2.0.100", features = ["full", "extra-traits", "visit-mut"] } - -[lints.rust] -# Values used during testing -unexpected_cfgs = { level = "warn", check-cfg = [ - 'cfg(f16_enabled)', - 'cfg(f128_enabled)', -] } diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs deleted file mode 100644 index 864b625eab3..00000000000 --- a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs +++ /dev/null @@ -1,154 +0,0 @@ -use heck::ToUpperCamelCase; -use proc_macro2 as pm2; -use proc_macro2::{Ident, Span}; -use quote::quote; -use syn::spanned::Spanned; -use syn::{Fields, ItemEnum, Variant}; - -use crate::{ALL_OPERATIONS, base_name}; - -/// Implement `#[function_enum]`, see documentation in `lib.rs`. -pub fn function_enum( - mut item: ItemEnum, - attributes: pm2::TokenStream, -) -> syn::Result { - expect_empty_enum(&item)?; - let attr_span = attributes.span(); - let mut attr = attributes.into_iter(); - - // Attribute should be the identifier of the `BaseName` enum. - let Some(tt) = attr.next() else { - return Err(syn::Error::new(attr_span, "expected one attribute")); - }; - - let pm2::TokenTree::Ident(base_enum) = tt else { - return Err(syn::Error::new(tt.span(), "expected an identifier")); - }; - - if let Some(tt) = attr.next() { - return Err(syn::Error::new(tt.span(), "unexpected token after identifier")); - } - - let enum_name = &item.ident; - let mut as_str_arms = Vec::new(); - let mut from_str_arms = Vec::new(); - let mut base_arms = Vec::new(); - - for func in ALL_OPERATIONS.iter() { - let fn_name = func.name; - let ident = Ident::new(&fn_name.to_upper_camel_case(), Span::call_site()); - let bname_ident = Ident::new(&base_name(fn_name).to_upper_camel_case(), Span::call_site()); - - // Match arm for `fn as_str(self)` matcher - as_str_arms.push(quote! { Self::#ident => #fn_name }); - from_str_arms.push(quote! { #fn_name => Self::#ident }); - - // Match arm for `fn base_name(self)` matcher - base_arms.push(quote! { Self::#ident => #base_enum::#bname_ident }); - - let variant = - Variant { attrs: Vec::new(), ident, fields: Fields::Unit, discriminant: None }; - - item.variants.push(variant); - } - - let variants = item.variants.iter(); - - let res = quote! { - // Instantiate the enum - #item - - impl #enum_name { - /// All variants of this enum. - pub const ALL: &[Self] = &[ - #( Self::#variants, )* - ]; - - /// The stringified version of this function name. - pub const fn as_str(self) -> &'static str { - match self { - #( #as_str_arms , )* - } - } - - /// If `s` is the name of a function, return it. - pub fn from_str(s: &str) -> Option { - let ret = match s { - #( #from_str_arms , )* - _ => return None, - }; - Some(ret) - } - - /// The base name enum for this function. - pub const fn base_name(self) -> #base_enum { - match self { - #( #base_arms, )* - } - } - - /// Return information about this operation. - pub fn math_op(self) -> &'static crate::op::MathOpInfo { - crate::op::ALL_OPERATIONS.iter().find(|op| op.name == self.as_str()).unwrap() - } - } - }; - - Ok(res) -} - -/// Implement `#[base_name_enum]`, see documentation in `lib.rs`. -pub fn base_name_enum( - mut item: ItemEnum, - attributes: pm2::TokenStream, -) -> syn::Result { - expect_empty_enum(&item)?; - if !attributes.is_empty() { - let sp = attributes.span(); - return Err(syn::Error::new(sp.span(), "no attributes expected")); - } - - let mut base_names: Vec<_> = ALL_OPERATIONS.iter().map(|func| base_name(func.name)).collect(); - base_names.sort_unstable(); - base_names.dedup(); - - let item_name = &item.ident; - let mut as_str_arms = Vec::new(); - - for base_name in base_names { - let ident = Ident::new(&base_name.to_upper_camel_case(), Span::call_site()); - - // Match arm for `fn as_str(self)` matcher - as_str_arms.push(quote! { Self::#ident => #base_name }); - - let variant = - Variant { attrs: Vec::new(), ident, fields: Fields::Unit, discriminant: None }; - - item.variants.push(variant); - } - - let res = quote! { - // Instantiate the enum - #item - - impl #item_name { - /// The stringified version of this base name. - pub const fn as_str(self) -> &'static str { - match self { - #( #as_str_arms ),* - } - } - } - }; - - Ok(res) -} - -/// Verify that an enum is empty, otherwise return an error -fn expect_empty_enum(item: &ItemEnum) -> syn::Result<()> { - if !item.variants.is_empty() { - Err(syn::Error::new(item.variants.span(), "expected an empty enum")) - } else { - Ok(()) - } -} diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs deleted file mode 100644 index 3cee5385b62..00000000000 --- a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs +++ /dev/null @@ -1,446 +0,0 @@ -mod enums; -mod parse; -mod shared; - -use parse::{Invocation, StructuredInput}; -use proc_macro as pm; -use proc_macro2::{self as pm2, Span}; -use quote::{ToTokens, quote}; -pub(crate) use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; -use syn::spanned::Spanned; -use syn::visit_mut::VisitMut; -use syn::{Ident, ItemEnum}; - -const KNOWN_TYPES: &[&str] = &["FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet"]; - -/// Populate an enum with a variant representing function. Names are in upper camel case. -/// -/// Applied to an empty enum. Expects one attribute `#[function_enum(BaseName)]` that provides -/// the name of the `BaseName` enum. -#[proc_macro_attribute] -pub fn function_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> pm::TokenStream { - let item = syn::parse_macro_input!(tokens as ItemEnum); - let res = enums::function_enum(item, attributes.into()); - - match res { - Ok(ts) => ts, - Err(e) => e.into_compile_error(), - } - .into() -} - -/// Create an enum representing all possible base names, with names in upper camel case. -/// -/// Applied to an empty enum. -#[proc_macro_attribute] -pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> pm::TokenStream { - let item = syn::parse_macro_input!(tokens as ItemEnum); - let res = enums::base_name_enum(item, attributes.into()); - - match res { - Ok(ts) => ts, - Err(e) => e.into_compile_error(), - } - .into() -} - -/// Do something for each function present in this crate. -/// -/// Takes a callback macro and invokes it multiple times, once for each function that -/// this crate exports. This makes it easy to create generic tests, benchmarks, or other checks -/// and apply it to each symbol. -/// -/// Additionally, the `extra` and `fn_extra` patterns can make use of magic identifiers: -/// -/// - `MACRO_FN_NAME`: gets replaced with the name of the function on that invocation. -/// - `MACRO_FN_NAME_NORMALIZED`: similar to the above, but removes sufixes so e.g. `sinf` becomes -/// `sin`, `cosf128` becomes `cos`, etc. -/// -/// Invoke as: -/// -/// ``` -/// // Macro that is invoked once per function -/// macro_rules! callback_macro { -/// ( -/// // Name of that function -/// fn_name: $fn_name:ident, -/// // The basic float type for this function (e.g. `f32`, `f64`) -/// FTy: $FTy:ty, -/// // Function signature of the C version (e.g. `fn(f32, &mut f32) -> f32`) -/// CFn: $CFn:ty, -/// // A tuple representing the C version's arguments (e.g. `(f32, &mut f32)`) -/// CArgs: $CArgs:ty, -/// // The C version's return type (e.g. `f32`) -/// CRet: $CRet:ty, -/// // Function signature of the Rust version (e.g. `fn(f32) -> (f32, f32)`) -/// RustFn: $RustFn:ty, -/// // A tuple representing the Rust version's arguments (e.g. `(f32,)`) -/// RustArgs: $RustArgs:ty, -/// // The Rust version's return type (e.g. `(f32, f32)`) -/// RustRet: $RustRet:ty, -/// // Attributes for the current function, if any -/// attrs: [$($attr:meta),*], -/// // Extra tokens passed directly (if any) -/// extra: [$extra:ident], -/// // Extra function-tokens passed directly (if any) -/// fn_extra: $fn_extra:expr, -/// ) => { }; -/// } -/// -/// // All fields except for `callback` are optional. -/// libm_macros::for_each_function! { -/// // The macro to invoke as a callback -/// callback: callback_macro, -/// // Which types to include either as a list (`[CFn, RustFn, RustArgs]`) or "all" -/// emit_types: all, -/// // Functions to skip, i.e. `callback` shouldn't be called at all for these. -/// skip: [sin, cos], -/// // Attributes passed as `attrs` for specific functions. For example, here the invocation -/// // with `sinf` and that with `cosf` will both get `meta1` and `meta2`, but no others will. -/// // -/// // Note that `f16_enabled` and `f128_enabled` will always get emitted regardless of whether -/// // or not this is specified. -/// attributes: [ -/// #[meta1] -/// #[meta2] -/// [sinf, cosf], -/// ], -/// // Any tokens that should be passed directly to all invocations of the callback. This can -/// // be used to pass local variables or other things the macro needs access to. -/// extra: [foo], -/// // Similar to `extra`, but allow providing a pattern for only specific functions. Uses -/// // a simplified match-like syntax. -/// fn_extra: match MACRO_FN_NAME { -/// hypot | hypotf => |x| x.hypot(), -/// _ => |x| x, -/// }, -/// } -/// ``` -#[proc_macro] -pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream { - let input = syn::parse_macro_input!(tokens as Invocation); - - let res = StructuredInput::from_fields(input) - .and_then(|mut s_in| validate(&mut s_in).map(|fn_list| (s_in, fn_list))) - .and_then(|(s_in, fn_list)| expand(s_in, &fn_list)); - - match res { - Ok(ts) => ts.into(), - Err(e) => e.into_compile_error().into(), - } -} - -/// Check for any input that is structurally correct but has other problems. -/// -/// Returns the list of function names that we should expand for. -fn validate(input: &mut StructuredInput) -> syn::Result> { - // Collect lists of all functions that are provied as macro inputs in various fields (only, - // skip, attributes). - let attr_mentions = input - .attributes - .iter() - .flat_map(|map_list| map_list.iter()) - .flat_map(|attr_map| attr_map.names.iter()); - let only_mentions = input.only.iter().flat_map(|only_list| only_list.iter()); - let fn_extra_mentions = - input.fn_extra.iter().flat_map(|v| v.keys()).filter(|name| *name != "_"); - let all_mentioned_fns = - input.skip.iter().chain(only_mentions).chain(attr_mentions).chain(fn_extra_mentions); - - // Make sure that every function mentioned is a real function - for mentioned in all_mentioned_fns { - if !ALL_OPERATIONS.iter().any(|func| mentioned == func.name) { - let e = syn::Error::new( - mentioned.span(), - format!("unrecognized function name `{mentioned}`"), - ); - return Err(e); - } - } - - if !input.skip.is_empty() && input.only.is_some() { - let e = syn::Error::new( - input.only_span.unwrap(), - "only one of `skip` or `only` may be specified", - ); - return Err(e); - } - - // Construct a list of what we intend to expand - let mut fn_list = Vec::new(); - for func in ALL_OPERATIONS.iter() { - let fn_name = func.name; - // If we have an `only` list and it does _not_ contain this function name, skip it - if input.only.as_ref().is_some_and(|only| !only.iter().any(|o| o == fn_name)) { - continue; - } - - // If there is a `skip` list that contains this function name, skip it - if input.skip.iter().any(|s| s == fn_name) { - continue; - } - - // Run everything else - fn_list.push(func); - } - - // Types that the user would like us to provide in the macro - let mut add_all_types = false; - for ty in &input.emit_types { - let ty_name = ty.to_string(); - if ty_name == "all" { - add_all_types = true; - continue; - } - - // Check that all requested types are valid - if !KNOWN_TYPES.contains(&ty_name.as_str()) { - let e = syn::Error::new( - ty_name.span(), - format!("unrecognized type identifier `{ty_name}`"), - ); - return Err(e); - } - } - - if add_all_types { - // Ensure that if `all` was specified that nothing else was - if input.emit_types.len() > 1 { - let e = syn::Error::new( - input.emit_types_span.unwrap(), - "if `all` is specified, no other type identifiers may be given", - ); - return Err(e); - } - - // ...and then add all types - input.emit_types.clear(); - for ty in KNOWN_TYPES { - let ident = Ident::new(ty, Span::call_site()); - input.emit_types.push(ident); - } - } - - if let Some(map) = &input.fn_extra { - if !map.keys().any(|key| key == "_") { - // No default provided; make sure every expected function is covered - let mut fns_not_covered = Vec::new(); - for func in &fn_list { - if !map.keys().any(|key| key == func.name) { - // `name` was not mentioned in the `match` statement - fns_not_covered.push(func); - } - } - - if !fns_not_covered.is_empty() { - let e = syn::Error::new( - input.fn_extra_span.unwrap(), - format!( - "`fn_extra`: no default `_` pattern specified and the following \ - patterns are not covered: {fns_not_covered:#?}" - ), - ); - return Err(e); - } - } - }; - - Ok(fn_list) -} - -/// Expand our structured macro input into invocations of the callback macro. -fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result { - let mut out = pm2::TokenStream::new(); - let default_ident = Ident::new("_", Span::call_site()); - let callback = input.callback; - - for func in fn_list { - let fn_name = Ident::new(func.name, Span::call_site()); - - // Prepare attributes in an `attrs: ...` field - let mut meta_fields = Vec::new(); - if let Some(attrs) = &input.attributes { - let meta_iter = attrs - .iter() - .filter(|map| map.names.contains(&fn_name)) - .flat_map(|map| &map.meta) - .map(|v| v.into_token_stream()); - - meta_fields.extend(meta_iter); - } - - // Always emit f16 and f128 meta so this doesn't need to be repeated everywhere - if func.rust_sig.args.contains(&Ty::F16) || func.rust_sig.returns.contains(&Ty::F16) { - let ts = quote! { cfg(f16_enabled) }; - meta_fields.push(ts); - } - if func.rust_sig.args.contains(&Ty::F128) || func.rust_sig.returns.contains(&Ty::F128) { - let ts = quote! { cfg(f128_enabled) }; - meta_fields.push(ts); - } - - let meta_field = quote! { attrs: [ #( #meta_fields ),* ], }; - - // Prepare extra in an `extra: ...` field, running the replacer - let extra_field = match input.extra.clone() { - Some(mut extra) => { - let mut v = MacroReplace::new(func.name); - v.visit_expr_mut(&mut extra); - v.finish()?; - - quote! { extra: #extra, } - } - None => pm2::TokenStream::new(), - }; - - // Prepare function-specific extra in a `fn_extra: ...` field, running the replacer - let fn_extra_field = match input.fn_extra { - Some(ref map) => { - let mut fn_extra = - map.get(&fn_name).or_else(|| map.get(&default_ident)).unwrap().clone(); - - let mut v = MacroReplace::new(func.name); - v.visit_expr_mut(&mut fn_extra); - v.finish()?; - - quote! { fn_extra: #fn_extra, } - } - None => pm2::TokenStream::new(), - }; - - let base_fty = func.float_ty; - let c_args = &func.c_sig.args; - let c_ret = &func.c_sig.returns; - let rust_args = &func.rust_sig.args; - let rust_ret = &func.rust_sig.returns; - - let mut ty_fields = Vec::new(); - for ty in &input.emit_types { - let field = match ty.to_string().as_str() { - "FTy" => quote! { FTy: #base_fty, }, - "CFn" => quote! { CFn: fn( #(#c_args),* ,) -> ( #(#c_ret),* ), }, - "CArgs" => quote! { CArgs: ( #(#c_args),* ,), }, - "CRet" => quote! { CRet: ( #(#c_ret),* ), }, - "RustFn" => quote! { RustFn: fn( #(#rust_args),* ,) -> ( #(#rust_ret),* ), }, - "RustArgs" => quote! { RustArgs: ( #(#rust_args),* ,), }, - "RustRet" => quote! { RustRet: ( #(#rust_ret),* ), }, - _ => unreachable!("checked in validation"), - }; - ty_fields.push(field); - } - - let new = quote! { - #callback! { - fn_name: #fn_name, - #( #ty_fields )* - #meta_field - #extra_field - #fn_extra_field - } - }; - - out.extend(new); - } - - Ok(out) -} - -/// Visitor to replace "magic" identifiers that we allow: `MACRO_FN_NAME` and -/// `MACRO_FN_NAME_NORMALIZED`. -struct MacroReplace { - fn_name: &'static str, - /// Remove the trailing `f` or `f128` to make - norm_name: String, - error: Option, -} - -impl MacroReplace { - fn new(name: &'static str) -> Self { - let norm_name = base_name(name); - Self { fn_name: name, norm_name: norm_name.to_owned(), error: None } - } - - fn finish(self) -> syn::Result<()> { - match self.error { - Some(e) => Err(e), - None => Ok(()), - } - } - - fn visit_ident_inner(&mut self, i: &mut Ident) { - let s = i.to_string(); - if !s.starts_with("MACRO") || self.error.is_some() { - return; - } - - match s.as_str() { - "MACRO_FN_NAME" => *i = Ident::new(self.fn_name, i.span()), - "MACRO_FN_NAME_NORMALIZED" => *i = Ident::new(&self.norm_name, i.span()), - _ => { - self.error = - Some(syn::Error::new(i.span(), format!("unrecognized meta expression `{s}`"))); - } - } - } -} - -impl VisitMut for MacroReplace { - fn visit_ident_mut(&mut self, i: &mut Ident) { - self.visit_ident_inner(i); - syn::visit_mut::visit_ident_mut(self, i); - } -} - -/// Return the unsuffixed version of a function name; e.g. `abs` and `absf` both return `abs`, -/// `lgamma_r` and `lgammaf_r` both return `lgamma_r`. -fn base_name(name: &str) -> &str { - let known_mappings = &[ - ("erff", "erf"), - ("erf", "erf"), - ("lgammaf_r", "lgamma_r"), - ("modff", "modf"), - ("modf", "modf"), - ]; - - match known_mappings.iter().find(|known| known.0 == name) { - Some(found) => found.1, - None => name - .strip_suffix("f") - .or_else(|| name.strip_suffix("f16")) - .or_else(|| name.strip_suffix("f128")) - .unwrap_or(name), - } -} - -impl ToTokens for Ty { - fn to_tokens(&self, tokens: &mut pm2::TokenStream) { - let ts = match self { - Ty::F16 => quote! { f16 }, - Ty::F32 => quote! { f32 }, - Ty::F64 => quote! { f64 }, - Ty::F128 => quote! { f128 }, - Ty::I32 => quote! { i32 }, - Ty::CInt => quote! { ::core::ffi::c_int }, - Ty::MutF16 => quote! { &'a mut f16 }, - Ty::MutF32 => quote! { &'a mut f32 }, - Ty::MutF64 => quote! { &'a mut f64 }, - Ty::MutF128 => quote! { &'a mut f128 }, - Ty::MutI32 => quote! { &'a mut i32 }, - Ty::MutCInt => quote! { &'a mut core::ffi::c_int }, - }; - - tokens.extend(ts); - } -} -impl ToTokens for FloatTy { - fn to_tokens(&self, tokens: &mut pm2::TokenStream) { - let ts = match self { - FloatTy::F16 => quote! { f16 }, - FloatTy::F32 => quote! { f32 }, - FloatTy::F64 => quote! { f64 }, - FloatTy::F128 => quote! { f128 }, - }; - - tokens.extend(ts); - } -} diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs b/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs deleted file mode 100644 index 369bbae2f4f..00000000000 --- a/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs +++ /dev/null @@ -1,258 +0,0 @@ -use std::collections::BTreeMap; - -use proc_macro2::Span; -use quote::ToTokens; -use syn::parse::{Parse, ParseStream, Parser}; -use syn::punctuated::Punctuated; -use syn::spanned::Spanned; -use syn::token::{self, Comma}; -use syn::{Arm, Attribute, Expr, ExprMatch, Ident, Meta, Token, bracketed}; - -/// The input to our macro; just a list of `field: value` items. -#[derive(Debug)] -pub struct Invocation { - fields: Punctuated, -} - -impl Parse for Invocation { - fn parse(input: ParseStream) -> syn::Result { - Ok(Self { fields: input.parse_terminated(Mapping::parse, Token![,])? }) - } -} - -/// A `key: expression` mapping with nothing else. Basically a simplified `syn::Field`. -#[derive(Debug)] -struct Mapping { - name: Ident, - _sep: Token![:], - expr: Expr, -} - -impl Parse for Mapping { - fn parse(input: ParseStream) -> syn::Result { - Ok(Self { name: input.parse()?, _sep: input.parse()?, expr: input.parse()? }) - } -} - -/// The input provided to our proc macro, after parsing into the form we expect. -#[derive(Debug)] -pub struct StructuredInput { - /// Macro to invoke once per function - pub callback: Ident, - /// Whether or not to provide `CFn` `CArgs` `RustFn` etc. This is really only needed - /// once for crate to set up the main trait. - pub emit_types: Vec, - /// Skip these functions - pub skip: Vec, - /// Invoke only for these functions - pub only: Option>, - /// Attributes that get applied to specific functions - pub attributes: Option>, - /// Extra expressions to pass to all invocations of the macro - pub extra: Option, - /// Per-function extra expressions to pass to the macro - pub fn_extra: Option>, - // For diagnostics - pub emit_types_span: Option, - pub only_span: Option, - pub fn_extra_span: Option, -} - -impl StructuredInput { - pub fn from_fields(input: Invocation) -> syn::Result { - let mut map: Vec<_> = input.fields.into_iter().collect(); - let cb_expr = expect_field(&mut map, "callback")?; - let emit_types_expr = expect_field(&mut map, "emit_types").ok(); - let skip_expr = expect_field(&mut map, "skip").ok(); - let only_expr = expect_field(&mut map, "only").ok(); - let attr_expr = expect_field(&mut map, "attributes").ok(); - let extra = expect_field(&mut map, "extra").ok(); - let fn_extra = expect_field(&mut map, "fn_extra").ok(); - - if !map.is_empty() { - Err(syn::Error::new( - map.first().unwrap().name.span(), - format!("unexpected fields {map:?}"), - ))?; - } - - let emit_types_span = emit_types_expr.as_ref().map(|expr| expr.span()); - let emit_types = match emit_types_expr { - Some(expr) => Parser::parse2(parse_ident_or_array, expr.into_token_stream())?, - None => Vec::new(), - }; - - let skip = match skip_expr { - Some(expr) => Parser::parse2(parse_ident_array, expr.into_token_stream())?, - None => Vec::new(), - }; - - let only_span = only_expr.as_ref().map(|expr| expr.span()); - let only = match only_expr { - Some(expr) => Some(Parser::parse2(parse_ident_array, expr.into_token_stream())?), - None => None, - }; - - let attributes = match attr_expr { - Some(expr) => { - let mut attributes = Vec::new(); - let attr_exprs = Parser::parse2(parse_expr_array, expr.into_token_stream())?; - - for attr in attr_exprs { - attributes.push(syn::parse2(attr.into_token_stream())?); - } - Some(attributes) - } - None => None, - }; - - let fn_extra_span = fn_extra.as_ref().map(|expr| expr.span()); - let fn_extra = match fn_extra { - Some(expr) => Some(extract_fn_extra_field(expr)?), - None => None, - }; - - Ok(Self { - callback: expect_ident(cb_expr)?, - emit_types, - skip, - only, - only_span, - attributes, - extra, - fn_extra, - fn_extra_span, - emit_types_span, - }) - } -} - -fn extract_fn_extra_field(expr: Expr) -> syn::Result> { - let Expr::Match(mexpr) = expr else { - let e = syn::Error::new(expr.span(), "`fn_extra` expects a match expression"); - return Err(e); - }; - - let ExprMatch { attrs, match_token: _, expr, brace_token: _, arms } = mexpr; - - expect_empty_attrs(&attrs)?; - - let match_on = expect_ident(*expr)?; - if match_on != "MACRO_FN_NAME" { - let e = syn::Error::new(match_on.span(), "only allowed to match on `MACRO_FN_NAME`"); - return Err(e); - } - - let mut res = BTreeMap::new(); - - for arm in arms { - let Arm { attrs, pat, guard, fat_arrow_token: _, body, comma: _ } = arm; - - expect_empty_attrs(&attrs)?; - - let keys = match pat { - syn::Pat::Wild(w) => vec![Ident::new("_", w.span())], - _ => Parser::parse2(parse_ident_pat, pat.into_token_stream())?, - }; - - if let Some(guard) = guard { - let e = syn::Error::new(guard.0.span(), "no guards allowed in this position"); - return Err(e); - } - - for key in keys { - let inserted = res.insert(key.clone(), *body.clone()); - if inserted.is_some() { - let e = syn::Error::new(key.span(), format!("key `{key}` specified twice")); - return Err(e); - } - } - } - - Ok(res) -} - -fn expect_empty_attrs(attrs: &[Attribute]) -> syn::Result<()> { - if attrs.is_empty() { - return Ok(()); - } - - let e = - syn::Error::new(attrs.first().unwrap().span(), "no attributes allowed in this position"); - Err(e) -} - -/// Extract a named field from a map, raising an error if it doesn't exist. -fn expect_field(v: &mut Vec, name: &str) -> syn::Result { - let pos = v.iter().position(|v| v.name == name).ok_or_else(|| { - syn::Error::new(Span::call_site(), format!("missing expected field `{name}`")) - })?; - - Ok(v.remove(pos).expr) -} - -/// Coerce an expression into a simple identifier. -fn expect_ident(expr: Expr) -> syn::Result { - syn::parse2(expr.into_token_stream()) -} - -/// Parse either a single identifier (`foo`) or an array of identifiers (`[foo, bar, baz]`). -fn parse_ident_or_array(input: ParseStream) -> syn::Result> { - if !input.peek(token::Bracket) { - return Ok(vec![input.parse()?]); - } - - parse_ident_array(input) -} - -/// Parse an array of expressions. -fn parse_expr_array(input: ParseStream) -> syn::Result> { - let content; - let _ = bracketed!(content in input); - let fields = content.parse_terminated(Expr::parse, Token![,])?; - Ok(fields.into_iter().collect()) -} - -/// Parse an array of idents, e.g. `[foo, bar, baz]`. -fn parse_ident_array(input: ParseStream) -> syn::Result> { - let content; - let _ = bracketed!(content in input); - let fields = content.parse_terminated(Ident::parse, Token![,])?; - Ok(fields.into_iter().collect()) -} - -/// Parse an pattern of idents, specifically `(foo | bar | baz)`. -fn parse_ident_pat(input: ParseStream) -> syn::Result> { - if !input.peek2(Token![|]) { - return Ok(vec![input.parse()?]); - } - - let fields = Punctuated::::parse_separated_nonempty(input)?; - Ok(fields.into_iter().collect()) -} - -/// A mapping of attributes to identifiers (just a simplified `Expr`). -/// -/// Expressed as: -/// -/// ```ignore -/// #[meta1] -/// #[meta2] -/// [foo, bar, baz] -/// ``` -#[derive(Debug)] -pub struct AttributeMap { - pub meta: Vec, - pub names: Vec, -} - -impl Parse for AttributeMap { - fn parse(input: ParseStream) -> syn::Result { - let attrs = input.call(Attribute::parse_outer)?; - - Ok(Self { - meta: attrs.into_iter().map(|a| a.meta).collect(), - names: parse_ident_array(input)?, - }) - } -} diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs deleted file mode 100644 index 5e58220eb39..00000000000 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ /dev/null @@ -1,444 +0,0 @@ -/* List of all functions that is shared between `libm-macros` and `libm-test`. */ - -use std::fmt; -use std::sync::LazyLock; - -const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] = &[ - ( - // `fn(f16) -> f16` - FloatTy::F16, - Signature { args: &[Ty::F16], returns: &[Ty::F16] }, - None, - &[ - "ceilf16", - "fabsf16", - "floorf16", - "rintf16", - "roundevenf16", - "roundf16", - "sqrtf16", - "truncf16", - ], - ), - ( - // `fn(f32) -> f32` - FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32] }, - None, - &[ - "acosf", - "acoshf", - "asinf", - "asinhf", - "atanf", - "atanhf", - "cbrtf", - "ceilf", - "cosf", - "coshf", - "erfcf", - "erff", - "exp10f", - "exp2f", - "expf", - "expm1f", - "fabsf", - "floorf", - "j0f", - "j1f", - "lgammaf", - "log10f", - "log1pf", - "log2f", - "logf", - "rintf", - "roundevenf", - "roundf", - "sinf", - "sinhf", - "sqrtf", - "tanf", - "tanhf", - "tgammaf", - "truncf", - "y0f", - "y1f", - ], - ), - ( - // `(f64) -> f64` - FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64] }, - None, - &[ - "acos", - "acosh", - "asin", - "asinh", - "atan", - "atanh", - "cbrt", - "ceil", - "cos", - "cosh", - "erf", - "erfc", - "exp", - "exp10", - "exp2", - "expm1", - "fabs", - "floor", - "j0", - "j1", - "lgamma", - "log", - "log10", - "log1p", - "log2", - "rint", - "round", - "roundeven", - "sin", - "sinh", - "sqrt", - "tan", - "tanh", - "tgamma", - "trunc", - "y0", - "y1", - ], - ), - ( - // `fn(f128) -> f128` - FloatTy::F128, - Signature { args: &[Ty::F128], returns: &[Ty::F128] }, - None, - &[ - "ceilf128", - "fabsf128", - "floorf128", - "rintf128", - "roundevenf128", - "roundf128", - "sqrtf128", - "truncf128", - ], - ), - ( - // `(f16, f16) -> f16` - FloatTy::F16, - Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, - None, - &[ - "copysignf16", - "fdimf16", - "fmaxf16", - "fmaximum_numf16", - "fmaximumf16", - "fminf16", - "fminimum_numf16", - "fminimumf16", - "fmodf16", - ], - ), - ( - // `(f32, f32) -> f32` - FloatTy::F32, - Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] }, - None, - &[ - "atan2f", - "copysignf", - "fdimf", - "fmaxf", - "fmaximum_numf", - "fmaximumf", - "fminf", - "fminimum_numf", - "fminimumf", - "fmodf", - "hypotf", - "nextafterf", - "powf", - "remainderf", - ], - ), - ( - // `(f64, f64) -> f64` - FloatTy::F64, - Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] }, - None, - &[ - "atan2", - "copysign", - "fdim", - "fmax", - "fmaximum", - "fmaximum_num", - "fmin", - "fminimum", - "fminimum_num", - "fmod", - "hypot", - "nextafter", - "pow", - "remainder", - ], - ), - ( - // `(f128, f128) -> f128` - FloatTy::F128, - Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, - None, - &[ - "copysignf128", - "fdimf128", - "fmaxf128", - "fmaximum_numf128", - "fmaximumf128", - "fminf128", - "fminimum_numf128", - "fminimumf128", - "fmodf128", - ], - ), - ( - // `(f32, f32, f32) -> f32` - FloatTy::F32, - Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] }, - None, - &["fmaf"], - ), - ( - // `(f64, f64, f64) -> f64` - FloatTy::F64, - Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] }, - None, - &["fma"], - ), - ( - // `(f128, f128, f128) -> f128` - FloatTy::F128, - Signature { args: &[Ty::F128, Ty::F128, Ty::F128], returns: &[Ty::F128] }, - None, - &["fmaf128"], - ), - ( - // `(f32) -> i32` - FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::I32] }, - None, - &["ilogbf"], - ), - ( - // `(f64) -> i32` - FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::I32] }, - None, - &["ilogb"], - ), - ( - // `(i32, f32) -> f32` - FloatTy::F32, - Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] }, - None, - &["jnf", "ynf"], - ), - ( - // `(i32, f64) -> f64` - FloatTy::F64, - Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] }, - None, - &["jn", "yn"], - ), - ( - // `(f16, i32) -> f16` - FloatTy::F16, - Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16] }, - None, - &["ldexpf16", "scalbnf16"], - ), - ( - // `(f32, i32) -> f32` - FloatTy::F32, - Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] }, - None, - &["ldexpf", "scalbnf"], - ), - ( - // `(f64, i64) -> f64` - FloatTy::F64, - Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] }, - None, - &["ldexp", "scalbn"], - ), - ( - // `(f128, i32) -> f128` - FloatTy::F128, - Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128] }, - None, - &["ldexpf128", "scalbnf128"], - ), - ( - // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` - FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, - Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }), - &["modff"], - ), - ( - // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` - FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, - Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }), - &["modf"], - ), - ( - // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` - FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] }, - Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), - &["frexpf", "lgammaf_r"], - ), - ( - // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` - FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] }, - Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), - &["frexp", "lgamma_r"], - ), - ( - // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` - FloatTy::F32, - Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] }, - Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), - &["remquof"], - ), - ( - // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` - FloatTy::F64, - Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] }, - Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), - &["remquo"], - ), - ( - // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` - FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, - Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }), - &["sincosf"], - ), - ( - // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` - FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, - Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }), - &["sincos"], - ), -]; - -/// A type used in a function signature. -#[allow(dead_code)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum Ty { - F16, - F32, - F64, - F128, - I32, - CInt, - MutF16, - MutF32, - MutF64, - MutF128, - MutI32, - MutCInt, -} - -/// A subset of [`Ty`] representing only floats. -#[allow(dead_code)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum FloatTy { - F16, - F32, - F64, - F128, -} - -impl fmt::Display for Ty { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - Ty::F16 => "f16", - Ty::F32 => "f32", - Ty::F64 => "f64", - Ty::F128 => "f128", - Ty::I32 => "i32", - Ty::CInt => "::core::ffi::c_int", - Ty::MutF16 => "&mut f16", - Ty::MutF32 => "&mut f32", - Ty::MutF64 => "&mut f64", - Ty::MutF128 => "&mut f128", - Ty::MutI32 => "&mut i32", - Ty::MutCInt => "&mut ::core::ffi::c_int", - }; - f.write_str(s) - } -} - -impl fmt::Display for FloatTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - FloatTy::F16 => "f16", - FloatTy::F32 => "f32", - FloatTy::F64 => "f64", - FloatTy::F128 => "f128", - }; - f.write_str(s) - } -} - -/// Representation of e.g. `(f32, f32) -> f32` -#[derive(Debug, Clone)] -pub struct Signature { - pub args: &'static [Ty], - pub returns: &'static [Ty], -} - -/// Combined information about a function implementation. -#[derive(Debug, Clone)] -pub struct MathOpInfo { - pub name: &'static str, - pub float_ty: FloatTy, - /// Function signature for C implementations - pub c_sig: Signature, - /// Function signature for Rust implementations - pub rust_sig: Signature, -} - -/// A flat representation of `ALL_FUNCTIONS`. -pub static ALL_OPERATIONS: LazyLock> = LazyLock::new(|| { - let mut ret = Vec::new(); - - for (base_fty, rust_sig, c_sig, names) in ALL_OPERATIONS_NESTED { - for name in *names { - let api = MathOpInfo { - name, - float_ty: *base_fty, - rust_sig: rust_sig.clone(), - c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()), - }; - ret.push(api); - } - - if !names.is_sorted() { - let mut sorted = (*names).to_owned(); - sorted.sort_unstable(); - panic!("names list is not sorted: {names:?}\nExpected: {sorted:?}"); - } - } - - ret.sort_by_key(|item| item.name); - ret -}); diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs deleted file mode 100644 index 5314e84bbb0..00000000000 --- a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs +++ /dev/null @@ -1,103 +0,0 @@ -#![feature(f16)] -#![feature(f128)] -// `STATUS_DLL_NOT_FOUND` on i686 MinGW, not worth looking into. -#![cfg(not(all(target_arch = "x86", target_os = "windows", target_env = "gnu")))] - -macro_rules! basic { - ( - fn_name: $fn_name:ident, - FTy: $FTy:ty, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: $RustFn:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, - attrs: [$($attr:meta),*], - extra: [$($extra_tt:tt)*], - fn_extra: $fn_extra:expr, - ) => { - $(#[$attr])* - #[allow(dead_code)] - pub mod $fn_name { - type FTy= $FTy; - type CFnTy<'a> = $CFn; - type RustFnTy = $RustFn; - type RustArgsTy = $RustArgs; - type RustRetTy = $RustRet; - const A: &[&str] = &[$($extra_tt)*]; - fn foo(a: f32) -> f32 { - $fn_extra(a) - } - } - }; -} - -mod test_basic { - libm_macros::for_each_function! { - callback: basic, - emit_types: all, - skip: [sin, cos], - attributes: [ - // just some random attributes - #[allow(clippy::pedantic)] - #[allow(dead_code)] - [sinf, cosf] - ], - extra: ["foo", "bar"], - fn_extra: match MACRO_FN_NAME { - sin => |x| x + 2.0, - cos | cosf => |x: f32| x.MACRO_FN_NAME_NORMALIZED(), - _ => |_x| 100.0 - } - } -} - -macro_rules! basic_no_extra { - ( - fn_name: $fn_name:ident, - attrs: [$($attr:meta),*], - ) => { - $(#[$attr])* - mod $fn_name {} - }; -} - -mod test_basic_no_extra { - // Test with no extra, no skip, and no attributes - libm_macros::for_each_function! { - callback: basic_no_extra, - } -} - -mod test_only { - // Test that only works - libm_macros::for_each_function! { - callback: basic_no_extra, - only: [sin, sinf], - } -} - -macro_rules! specified_types { - ( - fn_name: $fn_name:ident, - RustFn: $RustFn:ty, - RustArgs: $RustArgs:ty, - attrs: [$($attr:meta),*], - ) => { - $(#[$attr])* - #[allow(dead_code)] - mod $fn_name { - type RustFnTy = $RustFn; - type RustArgsTy = $RustArgs; - } - }; -} - -mod test_emit_types { - // Test that we can specify a couple types to emit - libm_macros::for_each_function! { - callback: specified_types, - emit_types: [RustFn, RustArgs], - } -} diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs deleted file mode 100644 index 93e209a0dcc..00000000000 --- a/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs +++ /dev/null @@ -1,38 +0,0 @@ -#[libm_macros::function_enum(BaseName)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum Identifier {} - -#[libm_macros::base_name_enum] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum BaseName {} - -#[test] -fn as_str() { - assert_eq!(Identifier::Sin.as_str(), "sin"); - assert_eq!(Identifier::Sinf.as_str(), "sinf"); -} - -#[test] -fn from_str() { - assert_eq!(Identifier::from_str("sin").unwrap(), Identifier::Sin); - assert_eq!(Identifier::from_str("sinf").unwrap(), Identifier::Sinf); -} - -#[test] -fn basename() { - assert_eq!(Identifier::Sin.base_name(), BaseName::Sin); - assert_eq!(Identifier::Sinf.base_name(), BaseName::Sin); -} - -#[test] -fn math_op() { - assert_eq!(Identifier::Sin.math_op().float_ty, FloatTy::F64); - assert_eq!(Identifier::Sinf.math_op().float_ty, FloatTy::F32); -} - -// Replicate the structure that we have in `libm-test` -mod op { - include!("../../libm-macros/src/shared.rs"); -} - -use op::FloatTy; diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml deleted file mode 100644 index 5d150b4aeaa..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ /dev/null @@ -1,70 +0,0 @@ -[package] -name = "libm-test" -version = "0.1.0" -edition = "2024" -publish = false - -[features] -default = ["build-mpfr", "build-musl", "unstable-float"] - -# Propagated from libm because this affects which functions we test. -unstable-float = ["libm/unstable-float", "rug?/nightly-float"] - -# Generate tests which are random inputs and the outputs are calculated with -# musl libc. -build-mpfr = ["dep:rug", "dep:gmp-mpfr-sys"] - -# Build our own musl for testing and benchmarks -build-musl = ["dep:musl-math-sys"] - -# Enable report generation without bringing in more dependencies by default -benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] - -# Enable icount benchmarks (requires iai-callgrind and valgrind) -icount = ["dep:iai-callgrind"] - -# Run with a reduced set of benchmarks, such as for CI -short-benchmarks = [] - -[dependencies] -anyhow = "1.0.97" -# This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. -gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } -iai-callgrind = { version = "0.14.0", optional = true } -indicatif = { version = "0.17.11", default-features = false } -libm = { path = "../../libm", features = ["unstable-public-internals"] } -libm-macros = { path = "../libm-macros" } -musl-math-sys = { path = "../musl-math-sys", optional = true } -paste = "1.0.15" -rand = "0.9.0" -rand_chacha = "0.9.0" -rayon = "1.10.0" -rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "integer", "std"] } - -[build-dependencies] -rand = { version = "0.9.0", optional = true } - -[dev-dependencies] -criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } -libtest-mimic = "0.8.1" - -[[bench]] -name = "icount" -harness = false -required-features = ["icount"] - -[[bench]] -name = "random" -harness = false - -[[test]] -# No harness so that we can skip tests at runtime based on env. Prefixed with -# `z` so these tests get run last. -name = "z_extensive" -harness = false - -[lints.rust] -# Values from the chared config.rs used by `libm` but not the test crate -unexpected_cfgs = { level = "warn", check-cfg = [ - 'cfg(feature, values("arch", "force-soft-floats", "unstable-intrinsics"))', -] } diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs deleted file mode 100644 index da8c6bfd15a..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ /dev/null @@ -1,316 +0,0 @@ -//! Benchmarks that use `iai-cachegrind` to be reasonably CI-stable. - -use std::hint::black_box; - -use iai_callgrind::{library_benchmark, library_benchmark_group, main}; -use libm::support::{HInt, u256}; -use libm_test::generate::spaced; -use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, OpRustArgs, TupleCall, op}; - -const BENCH_ITER_ITEMS: u64 = 500; - -macro_rules! icount_benches { - ( - fn_name: $fn_name:ident, - attrs: [$($_attr:meta),*], - ) => { - paste::paste! { - // Construct benchmark inputs from the logspace generator. - fn [< setup_ $fn_name >]() -> Vec> { - type Op = op::$fn_name::Routine; - let mut ctx = CheckCtx::new( - Op::IDENTIFIER, - CheckBasis::None, - GeneratorKind::QuickSpaced - ); - ctx.override_iterations(BENCH_ITER_ITEMS); - let ret = spaced::get_test_cases::(&ctx).0.collect::>(); - println!("operation {}, {} steps", Op::NAME, ret.len()); - ret - } - - // Run benchmarks with the above inputs. - #[library_benchmark] - #[bench::logspace([< setup_ $fn_name >]())] - fn [< icount_bench_ $fn_name >](cases: Vec>) { - type Op = op::$fn_name::Routine; - let f = black_box(Op::ROUTINE); - for input in cases.iter().copied() { - input.call(f); - } - } - - library_benchmark_group!( - name = [< icount_bench_ $fn_name _group >]; - benchmarks = [< icount_bench_ $fn_name >] - ); - } - }; -} - -libm_macros::for_each_function! { - callback: icount_benches, -} - -fn setup_u128_mul() -> Vec<(u128, u128)> { - let step = u128::MAX / 300; - let mut x = 0u128; - let mut y = 0u128; - let mut v = Vec::new(); - - loop { - 'inner: loop { - match y.checked_add(step) { - Some(new) => y = new, - None => break 'inner, - } - - v.push((x, y)) - } - - match x.checked_add(step) { - Some(new) => x = new, - None => break, - } - } - - v -} - -fn setup_u256_add() -> Vec<(u256, u256)> { - let mut v = Vec::new(); - for (x, y) in setup_u128_mul() { - // square the u128 inputs to cover most of the u256 range - v.push((x.widen_mul(x), y.widen_mul(y))); - } - // Doesn't get covered by `u128:MAX^2` - v.push((u256::MAX, u256::MAX)); - v -} - -fn setup_u256_shift() -> Vec<(u256, u32)> { - let mut v = Vec::new(); - - for (x, _) in setup_u128_mul() { - let x2 = x.widen_mul(x); - for y in 0u32..256 { - v.push((x2, y)); - } - } - - v -} - -#[library_benchmark] -#[bench::linspace(setup_u128_mul())] -fn icount_bench_u128_widen_mul(cases: Vec<(u128, u128)>) { - for (x, y) in cases.iter().copied() { - black_box(black_box(x).zero_widen_mul(black_box(y))); - } -} - -library_benchmark_group!( - name = icount_bench_u128_widen_mul_group; - benchmarks = icount_bench_u128_widen_mul -); - -#[library_benchmark] -#[bench::linspace(setup_u256_add())] -fn icount_bench_u256_add(cases: Vec<(u256, u256)>) { - for (x, y) in cases.iter().copied() { - black_box(black_box(x) + black_box(y)); - } -} - -library_benchmark_group!( - name = icount_bench_u256_add_group; - benchmarks = icount_bench_u256_add -); - -#[library_benchmark] -#[bench::linspace(setup_u256_shift())] -fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) { - for (x, y) in cases.iter().copied() { - black_box(black_box(x) >> black_box(y)); - } -} - -library_benchmark_group!( - name = icount_bench_u256_shr_group; - benchmarks = icount_bench_u256_shr -); - -main!( - library_benchmark_groups = - // u256-related benchmarks - icount_bench_u128_widen_mul_group, - icount_bench_u256_add_group, - icount_bench_u256_shr_group, - // verify-apilist-start - // verify-sorted-start - icount_bench_acos_group, - icount_bench_acosf_group, - icount_bench_acosh_group, - icount_bench_acoshf_group, - icount_bench_asin_group, - icount_bench_asinf_group, - icount_bench_asinh_group, - icount_bench_asinhf_group, - icount_bench_atan2_group, - icount_bench_atan2f_group, - icount_bench_atan_group, - icount_bench_atanf_group, - icount_bench_atanh_group, - icount_bench_atanhf_group, - icount_bench_cbrt_group, - icount_bench_cbrtf_group, - icount_bench_ceil_group, - icount_bench_ceilf128_group, - icount_bench_ceilf16_group, - icount_bench_ceilf_group, - icount_bench_copysign_group, - icount_bench_copysignf128_group, - icount_bench_copysignf16_group, - icount_bench_copysignf_group, - icount_bench_cos_group, - icount_bench_cosf_group, - icount_bench_cosh_group, - icount_bench_coshf_group, - icount_bench_erf_group, - icount_bench_erfc_group, - icount_bench_erfcf_group, - icount_bench_erff_group, - icount_bench_exp10_group, - icount_bench_exp10f_group, - icount_bench_exp2_group, - icount_bench_exp2f_group, - icount_bench_exp_group, - icount_bench_expf_group, - icount_bench_expm1_group, - icount_bench_expm1f_group, - icount_bench_fabs_group, - icount_bench_fabsf128_group, - icount_bench_fabsf16_group, - icount_bench_fabsf_group, - icount_bench_fdim_group, - icount_bench_fdimf128_group, - icount_bench_fdimf16_group, - icount_bench_fdimf_group, - icount_bench_floor_group, - icount_bench_floorf128_group, - icount_bench_floorf16_group, - icount_bench_floorf_group, - icount_bench_fma_group, - icount_bench_fmaf128_group, - icount_bench_fmaf_group, - icount_bench_fmax_group, - icount_bench_fmaxf128_group, - icount_bench_fmaxf16_group, - icount_bench_fmaxf_group, - icount_bench_fmaximum_group, - icount_bench_fmaximum_num_group, - icount_bench_fmaximum_numf128_group, - icount_bench_fmaximum_numf16_group, - icount_bench_fmaximum_numf_group, - icount_bench_fmaximumf128_group, - icount_bench_fmaximumf16_group, - icount_bench_fmaximumf_group, - icount_bench_fmin_group, - icount_bench_fminf128_group, - icount_bench_fminf16_group, - icount_bench_fminf_group, - icount_bench_fminimum_group, - icount_bench_fminimum_num_group, - icount_bench_fminimum_numf128_group, - icount_bench_fminimum_numf16_group, - icount_bench_fminimum_numf_group, - icount_bench_fminimumf128_group, - icount_bench_fminimumf16_group, - icount_bench_fminimumf_group, - icount_bench_fmod_group, - icount_bench_fmodf128_group, - icount_bench_fmodf16_group, - icount_bench_fmodf_group, - icount_bench_frexp_group, - icount_bench_frexpf_group, - icount_bench_hypot_group, - icount_bench_hypotf_group, - icount_bench_ilogb_group, - icount_bench_ilogbf_group, - icount_bench_j0_group, - icount_bench_j0f_group, - icount_bench_j1_group, - icount_bench_j1f_group, - icount_bench_jn_group, - icount_bench_jnf_group, - icount_bench_ldexp_group, - icount_bench_ldexpf128_group, - icount_bench_ldexpf16_group, - icount_bench_ldexpf_group, - icount_bench_lgamma_group, - icount_bench_lgamma_r_group, - icount_bench_lgammaf_group, - icount_bench_lgammaf_r_group, - icount_bench_log10_group, - icount_bench_log10f_group, - icount_bench_log1p_group, - icount_bench_log1pf_group, - icount_bench_log2_group, - icount_bench_log2f_group, - icount_bench_log_group, - icount_bench_logf_group, - icount_bench_modf_group, - icount_bench_modff_group, - icount_bench_nextafter_group, - icount_bench_nextafterf_group, - icount_bench_pow_group, - icount_bench_powf_group, - icount_bench_remainder_group, - icount_bench_remainderf_group, - icount_bench_remquo_group, - icount_bench_remquof_group, - icount_bench_rint_group, - icount_bench_rintf128_group, - icount_bench_rintf16_group, - icount_bench_rintf_group, - icount_bench_round_group, - icount_bench_roundeven_group, - icount_bench_roundevenf128_group, - icount_bench_roundevenf16_group, - icount_bench_roundevenf_group, - icount_bench_roundf128_group, - icount_bench_roundf16_group, - icount_bench_roundf_group, - icount_bench_scalbn_group, - icount_bench_scalbnf128_group, - icount_bench_scalbnf16_group, - icount_bench_scalbnf_group, - icount_bench_sin_group, - icount_bench_sincos_group, - icount_bench_sincosf_group, - icount_bench_sinf_group, - icount_bench_sinh_group, - icount_bench_sinhf_group, - icount_bench_sqrt_group, - icount_bench_sqrtf128_group, - icount_bench_sqrtf16_group, - icount_bench_sqrtf_group, - icount_bench_tan_group, - icount_bench_tanf_group, - icount_bench_tanh_group, - icount_bench_tanhf_group, - icount_bench_tgamma_group, - icount_bench_tgammaf_group, - icount_bench_trunc_group, - icount_bench_truncf128_group, - icount_bench_truncf16_group, - icount_bench_truncf_group, - icount_bench_y0_group, - icount_bench_y0f_group, - icount_bench_y1_group, - icount_bench_y1f_group, - icount_bench_yn_group, - icount_bench_ynf_group, - // verify-sorted-end - // verify-apilist-end -); diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs deleted file mode 100644 index 63d7e5c6d20..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ /dev/null @@ -1,207 +0,0 @@ -use std::hint::black_box; -use std::time::Duration; - -use criterion::{Criterion, criterion_main}; -use libm_test::generate::random; -use libm_test::generate::random::RandomInput; -use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, TupleCall}; - -/// Benchmark with this many items to get a variety -const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { 50 } else { 500 }; - -/// Extra parameters we only care about if we are benchmarking against musl. -#[allow(dead_code)] -struct MuslExtra { - musl_fn: Option, - skip_on_i586: bool, -} - -macro_rules! musl_rand_benches { - ( - fn_name: $fn_name:ident, - attrs: [$($attr:meta),*], - fn_extra: ($skip_on_i586:expr, $musl_fn:expr), - ) => { - paste::paste! { - $(#[$attr])* - fn [< musl_bench_ $fn_name >](c: &mut Criterion) { - type Op = libm_test::op::$fn_name::Routine; - - #[cfg(feature = "build-musl")] - let musl_extra = MuslExtra::> { - musl_fn: $musl_fn, - skip_on_i586: $skip_on_i586, - }; - - #[cfg(not(feature = "build-musl"))] - let musl_extra = MuslExtra { - musl_fn: None, - skip_on_i586: $skip_on_i586, - }; - - bench_one::(c, musl_extra); - } - } - }; -} - -fn bench_one(c: &mut Criterion, musl_extra: MuslExtra) -where - Op: MathOp, - Op::RustArgs: RandomInput, -{ - let name = Op::NAME; - - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl, GeneratorKind::Random); - let benchvec: Vec<_> = - random::get_test_cases::(&ctx).0.take(BENCH_ITER_ITEMS).collect(); - - // Perform a sanity check that we are benchmarking the same thing - // Don't test against musl if it is not available - #[cfg(feature = "build-musl")] - for input in benchvec.iter().copied() { - use anyhow::Context; - use libm_test::CheckOutput; - - if cfg!(x86_no_sse) && musl_extra.skip_on_i586 { - break; - } - - let Some(musl_fn) = musl_extra.musl_fn else { - continue; - }; - let musl_res = input.call(musl_fn); - let crate_res = input.call(Op::ROUTINE); - - crate_res.validate(musl_res, input, &ctx).context(name).unwrap(); - } - - #[cfg(not(feature = "build-musl"))] - let _ = musl_extra; // silence unused warnings - - /* Option pointers are black boxed to avoid inlining in the benchmark loop */ - - let mut group = c.benchmark_group(name); - group.bench_function("crate", |b| { - b.iter(|| { - let f = black_box(Op::ROUTINE); - for input in benchvec.iter().copied() { - input.call(f); - } - }) - }); - - // Don't test against musl if it is not available - #[cfg(feature = "build-musl")] - { - if let Some(musl_fn) = musl_extra.musl_fn { - group.bench_function("musl", |b| { - b.iter(|| { - let f = black_box(musl_fn); - for input in benchvec.iter().copied() { - input.call(f); - } - }) - }); - } - } -} - -libm_macros::for_each_function! { - callback: musl_rand_benches, - skip: [], - fn_extra: match MACRO_FN_NAME { - // We pass a tuple of `(skip_on_i586, musl_fn)` - - // FIXME(correctness): exp functions have the wrong result on i586 - exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)), - - // Musl does not provide `f16` and `f128` functions - ceilf128 - | ceilf16 - | copysignf128 - | copysignf16 - | fabsf128 - | fabsf16 - | fdimf128 - | fdimf16 - | floorf128 - | floorf16 - | fmaf128 - | fmaxf128 - | fmaxf16 - | fmaximum - | fmaximum_num - | fmaximum_numf - | fmaximum_numf128 - | fmaximum_numf16 - | fmaximumf - | fmaximumf128 - | fmaximumf16 - | fminf128 - | fminf16 - | fminimum - | fminimum_num - | fminimum_numf - | fminimum_numf128 - | fminimum_numf16 - | fminimumf - | fminimumf128 - | fminimumf16 - | fmodf128 - | fmodf16 - | ldexpf128 - | ldexpf16 - | rintf128 - | rintf16 - | roundeven - | roundevenf - | roundevenf128 - | roundevenf16 - | roundf128 - | roundf16 - | scalbnf128 - | scalbnf16 - | sqrtf128 - | sqrtf16 - | truncf128 - | truncf16 => (false, None), - - // By default we never skip (false) and always have a musl function available - _ => (false, Some(musl_math_sys::MACRO_FN_NAME)) - } -} - -macro_rules! run_callback { - ( - fn_name: $fn_name:ident, - attrs: [$($attr:meta),*], - extra: [$criterion:ident], - ) => { - paste::paste! { - $(#[$attr])* - [< musl_bench_ $fn_name >](&mut $criterion) - } - }; -} - -pub fn musl_random() { - let mut criterion = Criterion::default(); - - // For CI, run a short 0.5s warmup and 1.0s tests. This makes benchmarks complete in - // about the same time as other tests. - if cfg!(feature = "short-benchmarks") { - criterion = criterion - .warm_up_time(Duration::from_millis(200)) - .measurement_time(Duration::from_millis(600)); - } - - criterion = criterion.configure_from_args(); - - libm_macros::for_each_function! { - callback: run_callback, - extra: [criterion], - }; -} - -criterion_main!(musl_random); diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs deleted file mode 100644 index f75e3dda5ff..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[path = "../../libm/configure.rs"] -mod configure; -use configure::Config; - -fn main() { - println!("cargo:rerun-if-changed=../../libm/configure.rs"); - let cfg = Config::from_env(); - configure::emit_test_config(&cfg); -} diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs deleted file mode 100644 index 78524761e2c..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! Program to write all inputs from a generator to a file, then invoke a Julia script to plot -//! them. Output is in `target/plots`. -//! -//! Requires Julia with the `CairoMakie` dependency. -//! -//! Note that running in release mode by default generates a _lot_ more datapoints, which -//! causes plotting to be extremely slow (some simplification to be done in the script). - -use std::fmt::Write as _; -use std::io::{BufWriter, Write}; -use std::path::Path; -use std::process::Command; -use std::{env, fs}; - -use libm_test::generate::spaced::SpacedInput; -use libm_test::generate::{edge_cases, spaced}; -use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; - -const JL_PLOT: &str = "examples/plot_file.jl"; - -fn main() { - let manifest_env = env::var("CARGO_MANIFEST_DIR").unwrap(); - let manifest_dir = Path::new(&manifest_env); - let out_dir = manifest_dir.join("../../target/plots"); - if !out_dir.exists() { - fs::create_dir(&out_dir).unwrap(); - } - - let jl_script = manifest_dir.join(JL_PLOT); - let mut config = format!(r#"out_dir = "{}""#, out_dir.display()); - config.write_str("\n\n").unwrap(); - - // Plot a few domains with some functions that use them. - plot_one_operator::(&out_dir, &mut config); - plot_one_operator::(&out_dir, &mut config); - plot_one_operator::(&out_dir, &mut config); - - let config_path = out_dir.join("config.toml"); - fs::write(&config_path, config).unwrap(); - - // The script expects a path to `config.toml` to be passed as its only argument - let mut cmd = Command::new("julia"); - if cfg!(optimizations_enabled) { - cmd.arg("-O3"); - } - cmd.arg(jl_script).arg(config_path); - - println!("launching script... {cmd:?}"); - cmd.status().unwrap(); -} - -/// Run multiple generators for a single operator. -fn plot_one_operator(out_dir: &Path, config: &mut String) -where - Op: MathOp, - Op::RustArgs: SpacedInput, -{ - let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::QuickSpaced); - plot_one_generator(out_dir, &ctx, "logspace", config, spaced::get_test_cases::(&ctx).0); - ctx.gen_kind = GeneratorKind::EdgeCases; - plot_one_generator( - out_dir, - &ctx, - "edge_cases", - config, - edge_cases::get_test_cases::(&ctx).0, - ); -} - -/// Plot the output of a single generator. -fn plot_one_generator( - out_dir: &Path, - ctx: &CheckCtx, - gen_name: &str, - config: &mut String, - generator: impl Iterator, -) { - let fn_name = ctx.base_name_str; - let text_file = out_dir.join(format!("input-{fn_name}-{gen_name}.txt")); - - let f = fs::File::create(&text_file).unwrap(); - let mut w = BufWriter::new(f); - let mut count = 0u64; - - for input in generator { - writeln!(w, "{:e}", input.0).unwrap(); - count += 1; - } - - w.flush().unwrap(); - println!("generated {count} inputs for {fn_name}-{gen_name}"); - - writeln!( - config, - r#"[[input]] -function = "{fn_name}" -generator = "{gen_name}" -input_file = "{}" -"#, - text_file.to_str().unwrap() - ) - .unwrap() -} diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl b/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl deleted file mode 100644 index acffd97569f..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl +++ /dev/null @@ -1,171 +0,0 @@ -"A quick script for plotting a list of floats. - -Takes a path to a TOML file (Julia has builtin TOML support but not JSON) which -specifies a list of source files to plot. Plots are done with both a linear and -a log scale. - -Requires [Makie] (specifically CairoMakie) for plotting. - -[Makie]: https://docs.makie.org/stable/ -" - -using CairoMakie -using TOML - -function main()::Nothing - CairoMakie.activate!(px_per_unit = 10) - config_path = ARGS[1] - - cfg = Dict() - open(config_path, "r") do f - cfg = TOML.parse(f) - end - - out_dir = cfg["out_dir"] - for input in cfg["input"] - fn_name = input["function"] - gen_name = input["generator"] - input_file = input["input_file"] - - plot_one(input_file, out_dir, fn_name, gen_name) - end -end - -"Read inputs from a file, create both linear and log plots for one function" -function plot_one( - input_file::String, - out_dir::String, - fn_name::String, - gen_name::String, -)::Nothing - fig = Figure() - - lin_out_file = joinpath(out_dir, "plot-$fn_name-$gen_name.png") - log_out_file = joinpath(out_dir, "plot-$fn_name-$gen_name-log.png") - - # Map string function names to callable functions - if fn_name == "cos" - orig_func = cos - xlims = (-6.0, 6.0) - xlims_log = (-pi * 10, pi * 10) - elseif fn_name == "cbrt" - orig_func = cbrt - xlims = (-2.0, 2.0) - xlims_log = (-1000.0, 1000.0) - elseif fn_name == "sqrt" - orig_func = sqrt - xlims = (-1.1, 6.0) - xlims_log = (-1.1, 5000.0) - else - println("unrecognized function name `$fn_name`; update plot_file.jl") - exit(1) - end - - # Edge cases don't do much beyond +/-1, except for infinity. - if gen_name == "edge_cases" - xlims = (-1.1, 1.1) - xlims_log = (-1.1, 1.1) - end - - # Turn domain errors into NaN - func(x) = map_or(x, orig_func, NaN) - - # Parse a series of X values produced by the generator - inputs = readlines(input_file) - gen_x = map((v) -> parse(Float32, v), inputs) - - do_plot( - fig, - gen_x, - func, - xlims[1], - xlims[2], - "$fn_name $gen_name (linear scale)", - lin_out_file, - false, - ) - - do_plot( - fig, - gen_x, - func, - xlims_log[1], - xlims_log[2], - "$fn_name $gen_name (log scale)", - log_out_file, - true, - ) -end - -"Create a single plot" -function do_plot( - fig::Figure, - gen_x::Vector{F}, - func::Function, - xmin::AbstractFloat, - xmax::AbstractFloat, - title::String, - out_file::String, - logscale::Bool, -)::Nothing where {F<:AbstractFloat} - println("plotting $title") - - # `gen_x` is the values the generator produces. `actual_x` is for plotting a - # continuous function. - input_min = xmin - 1.0 - input_max = xmax + 1.0 - gen_x = filter((v) -> v >= input_min && v <= input_max, gen_x) - markersize = length(gen_x) < 10_000 ? 6.0 : 4.0 - - steps = 10_000 - if logscale - r = LinRange(symlog10(input_min), symlog10(input_max), steps) - actual_x = sympow10.(r) - xscale = Makie.pseudolog10 - else - actual_x = LinRange(input_min, input_max, steps) - xscale = identity - end - - gen_y = @. func(gen_x) - actual_y = @. func(actual_x) - - ax = Axis(fig[1, 1], xscale = xscale, title = title) - - lines!( - ax, - actual_x, - actual_y, - color = (:lightblue, 0.6), - linewidth = 6.0, - label = "true function", - ) - scatter!( - ax, - gen_x, - gen_y, - color = (:darkblue, 0.9), - markersize = markersize, - label = "checked inputs", - ) - axislegend(ax, position = :rb, framevisible = false) - - save(out_file, fig) - delete!(ax) -end - -"Apply a function, returning the default if there is a domain error" -function map_or(input::AbstractFloat, f::Function, default::Any)::Union{AbstractFloat,Any} - try - return f(input) - catch - return default - end -end - -# Operations for logarithms that are symmetric about 0 -C = 10 -symlog10(x::Number) = sign(x) * (log10(1 + abs(x) / (10^C))) -sympow10(x::Number) = (10^C) * (10^x - 1) - -main() diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs deleted file mode 100644 index 41e94846163..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ /dev/null @@ -1,265 +0,0 @@ -//! Traits and operations related to bounds of a function. - -use std::fmt; -use std::ops::Bound; - -use libm::support::Int; - -use crate::{BaseName, Float, FloatExt, Identifier}; - -/// Representation of a single dimension of a function's domain. -#[derive(Clone, Debug)] -pub struct Domain { - /// Start of the region for which a function is defined (ignoring poles). - pub start: Bound, - /// Endof the region for which a function is defined (ignoring poles). - pub end: Bound, - /// Additional points to check closer around. These can be e.g. undefined asymptotes or - /// inflection points. - pub check_points: Option BoxIter>, -} - -type BoxIter = Box>; - -impl Domain { - /// The start of this domain, saturating at negative infinity. - pub fn range_start(&self) -> F { - match self.start { - Bound::Included(v) => v, - Bound::Excluded(v) => v.next_up(), - Bound::Unbounded => F::NEG_INFINITY, - } - } - - /// The end of this domain, saturating at infinity. - pub fn range_end(&self) -> F { - match self.end { - Bound::Included(v) => v, - Bound::Excluded(v) => v.next_down(), - Bound::Unbounded => F::INFINITY, - } - } -} - -/// A value that may be any float type or any integer type. -#[derive(Clone, Debug)] -pub enum EitherPrim { - Float(F), - Int(I), -} - -impl EitherPrim { - pub fn unwrap_float(self) -> F { - match self { - EitherPrim::Float(f) => f, - EitherPrim::Int(_) => panic!("expected float; got {self:?}"), - } - } - - pub fn unwrap_int(self) -> I { - match self { - EitherPrim::Float(_) => panic!("expected int; got {self:?}"), - EitherPrim::Int(i) => i, - } - } -} - -/// Convenience 1-dimensional float domains. -impl Domain { - /// x ∈ ℝ - const UNBOUNDED: Self = - Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }; - - /// x ∈ ℝ >= 0 - const POSITIVE: Self = - Self { start: Bound::Included(F::ZERO), end: Bound::Unbounded, check_points: None }; - - /// x ∈ ℝ > 0 - const STRICTLY_POSITIVE: Self = - Self { start: Bound::Excluded(F::ZERO), end: Bound::Unbounded, check_points: None }; - - /// Wrap in the float variant of [`EitherPrim`]. - const fn into_prim_float(self) -> EitherPrim> { - EitherPrim::Float(self) - } -} - -/// Convenience 1-dimensional integer domains. -impl Domain { - /// x ∈ ℝ - const UNBOUNDED_INT: Self = - Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }; - - /// Wrap in the int variant of [`EitherPrim`]. - const fn into_prim_int(self) -> EitherPrim, Self> { - EitherPrim::Int(self) - } -} - -/// Multidimensional domains, represented as an array of 1-D domains. -impl EitherPrim, Domain> { - /// x ∈ ℝ - const UNBOUNDED1: [Self; 1] = - [Domain { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None } - .into_prim_float()]; - - /// {x1, x2} ∈ ℝ - const UNBOUNDED2: [Self; 2] = - [Domain::UNBOUNDED.into_prim_float(), Domain::UNBOUNDED.into_prim_float()]; - - /// {x1, x2, x3} ∈ ℝ - const UNBOUNDED3: [Self; 3] = [ - Domain::UNBOUNDED.into_prim_float(), - Domain::UNBOUNDED.into_prim_float(), - Domain::UNBOUNDED.into_prim_float(), - ]; - - /// {x1, x2} ∈ ℝ, one float and one int - const UNBOUNDED_F_I: [Self; 2] = - [Domain::UNBOUNDED.into_prim_float(), Domain::UNBOUNDED_INT.into_prim_int()]; - - /// x ∈ ℝ >= 0 - const POSITIVE: [Self; 1] = [Domain::POSITIVE.into_prim_float()]; - - /// x ∈ ℝ > 0 - const STRICTLY_POSITIVE: [Self; 1] = [Domain::STRICTLY_POSITIVE.into_prim_float()]; - - /// Used for versions of `asin` and `acos`. - const INVERSE_TRIG_PERIODIC: [Self; 1] = [Domain { - start: Bound::Included(F::NEG_ONE), - end: Bound::Included(F::ONE), - check_points: None, - } - .into_prim_float()]; - - /// Domain for `acosh` - const ACOSH: [Self; 1] = - [Domain { start: Bound::Included(F::ONE), end: Bound::Unbounded, check_points: None } - .into_prim_float()]; - - /// Domain for `atanh` - const ATANH: [Self; 1] = [Domain { - start: Bound::Excluded(F::NEG_ONE), - end: Bound::Excluded(F::ONE), - check_points: None, - } - .into_prim_float()]; - - /// Domain for `sin`, `cos`, and `tan` - const TRIG: [Self; 1] = [Domain { - // Trig functions have special behavior at fractions of π. - check_points: Some(|| Box::new([-F::PI, -F::FRAC_PI_2, F::FRAC_PI_2, F::PI].into_iter())), - ..Domain::UNBOUNDED - } - .into_prim_float()]; - - /// Domain for `log` in various bases - const LOG: [Self; 1] = Self::STRICTLY_POSITIVE; - - /// Domain for `log1p` i.e. `log(1 + x)` - const LOG1P: [Self; 1] = - [Domain { start: Bound::Excluded(F::NEG_ONE), end: Bound::Unbounded, check_points: None } - .into_prim_float()]; - - /// Domain for `sqrt` - const SQRT: [Self; 1] = Self::POSITIVE; - - /// Domain for `gamma` - const GAMMA: [Self; 1] = [Domain { - check_points: Some(|| { - // Negative integers are asymptotes - Box::new((0..u8::MAX).map(|scale| { - let mut base = F::ZERO; - for _ in 0..scale { - base = base - F::ONE; - } - base - })) - }), - // Whether or not gamma is defined for negative numbers is implementation dependent - ..Domain::UNBOUNDED - } - .into_prim_float()]; - - /// Domain for `loggamma` - const LGAMMA: [Self; 1] = Self::STRICTLY_POSITIVE; - - /// Domain for `jn` and `yn`. - // FIXME: the domain should provide some sort of "reasonable range" so we don't actually test - // the entire system unbounded. - const BESSEL_N: [Self; 2] = - [Domain::UNBOUNDED_INT.into_prim_int(), Domain::UNBOUNDED.into_prim_float()]; -} - -/// Get the domain for a given function. -pub fn get_domain( - id: Identifier, - argnum: usize, -) -> EitherPrim, Domain> { - let x = match id.base_name() { - BaseName::Acos => &EitherPrim::INVERSE_TRIG_PERIODIC[..], - BaseName::Acosh => &EitherPrim::ACOSH[..], - BaseName::Asin => &EitherPrim::INVERSE_TRIG_PERIODIC[..], - BaseName::Asinh => &EitherPrim::UNBOUNDED1[..], - BaseName::Atan => &EitherPrim::UNBOUNDED1[..], - BaseName::Atan2 => &EitherPrim::UNBOUNDED2[..], - BaseName::Cbrt => &EitherPrim::UNBOUNDED1[..], - BaseName::Atanh => &EitherPrim::ATANH[..], - BaseName::Ceil => &EitherPrim::UNBOUNDED1[..], - BaseName::Cosh => &EitherPrim::UNBOUNDED1[..], - BaseName::Copysign => &EitherPrim::UNBOUNDED2[..], - BaseName::Cos => &EitherPrim::TRIG[..], - BaseName::Exp => &EitherPrim::UNBOUNDED1[..], - BaseName::Erf => &EitherPrim::UNBOUNDED1[..], - BaseName::Erfc => &EitherPrim::UNBOUNDED1[..], - BaseName::Expm1 => &EitherPrim::UNBOUNDED1[..], - BaseName::Exp10 => &EitherPrim::UNBOUNDED1[..], - BaseName::Exp2 => &EitherPrim::UNBOUNDED1[..], - BaseName::Frexp => &EitherPrim::UNBOUNDED1[..], - BaseName::Fabs => &EitherPrim::UNBOUNDED1[..], - BaseName::Fdim => &EitherPrim::UNBOUNDED2[..], - BaseName::Floor => &EitherPrim::UNBOUNDED1[..], - BaseName::Fma => &EitherPrim::UNBOUNDED3[..], - BaseName::Fmax => &EitherPrim::UNBOUNDED2[..], - BaseName::Fmaximum => &EitherPrim::UNBOUNDED2[..], - BaseName::FmaximumNum => &EitherPrim::UNBOUNDED2[..], - BaseName::Fmin => &EitherPrim::UNBOUNDED2[..], - BaseName::Fminimum => &EitherPrim::UNBOUNDED2[..], - BaseName::FminimumNum => &EitherPrim::UNBOUNDED2[..], - BaseName::Fmod => &EitherPrim::UNBOUNDED2[..], - BaseName::Hypot => &EitherPrim::UNBOUNDED2[..], - BaseName::Ilogb => &EitherPrim::UNBOUNDED1[..], - BaseName::J0 => &EitherPrim::UNBOUNDED1[..], - BaseName::J1 => &EitherPrim::UNBOUNDED1[..], - BaseName::Jn => &EitherPrim::BESSEL_N[..], - BaseName::Ldexp => &EitherPrim::UNBOUNDED_F_I[..], - BaseName::Lgamma => &EitherPrim::LGAMMA[..], - BaseName::LgammaR => &EitherPrim::LGAMMA[..], - BaseName::Log => &EitherPrim::LOG[..], - BaseName::Log10 => &EitherPrim::LOG[..], - BaseName::Log1p => &EitherPrim::LOG1P[..], - BaseName::Log2 => &EitherPrim::LOG[..], - BaseName::Modf => &EitherPrim::UNBOUNDED1[..], - BaseName::Nextafter => &EitherPrim::UNBOUNDED2[..], - BaseName::Pow => &EitherPrim::UNBOUNDED2[..], - BaseName::Remainder => &EitherPrim::UNBOUNDED2[..], - BaseName::Remquo => &EitherPrim::UNBOUNDED2[..], - BaseName::Rint => &EitherPrim::UNBOUNDED1[..], - BaseName::Round => &EitherPrim::UNBOUNDED1[..], - BaseName::Roundeven => &EitherPrim::UNBOUNDED1[..], - BaseName::Scalbn => &EitherPrim::UNBOUNDED_F_I[..], - BaseName::Sin => &EitherPrim::TRIG[..], - BaseName::Sincos => &EitherPrim::TRIG[..], - BaseName::Sinh => &EitherPrim::UNBOUNDED1[..], - BaseName::Sqrt => &EitherPrim::SQRT[..], - BaseName::Tan => &EitherPrim::TRIG[..], - BaseName::Tanh => &EitherPrim::UNBOUNDED1[..], - BaseName::Tgamma => &EitherPrim::GAMMA[..], - BaseName::Trunc => &EitherPrim::UNBOUNDED1[..], - BaseName::Y0 => &EitherPrim::UNBOUNDED1[..], - BaseName::Y1 => &EitherPrim::UNBOUNDED1[..], - BaseName::Yn => &EitherPrim::BESSEL_N[..], - }; - - x[argnum].clone() -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs deleted file mode 100644 index ddb7bf90e7f..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ /dev/null @@ -1,503 +0,0 @@ -//! An IEEE-compliant 8-bit float type for testing purposes. - -use std::cmp::{self, Ordering}; -use std::{fmt, ops}; - -use crate::Float; - -/// Sometimes verifying float logic is easiest when all values can quickly be checked exhaustively -/// or by hand. -/// -/// IEEE-754 compliant type that includes a 1 bit sign, 4 bit exponent, and 3 bit significand. -/// Bias is -7. -/// -/// Based on . -#[derive(Clone, Copy)] -#[repr(transparent)] -#[allow(non_camel_case_types)] -pub struct f8(u8); - -impl Float for f8 { - type Int = u8; - type SignedInt = i8; - - const ZERO: Self = Self(0b0_0000_000); - const NEG_ZERO: Self = Self(0b1_0000_000); - const ONE: Self = Self(0b0_0111_000); - const NEG_ONE: Self = Self(0b1_0111_000); - const MAX: Self = Self(0b0_1110_111); - const MIN: Self = Self(0b1_1110_111); - const INFINITY: Self = Self(0b0_1111_000); - const NEG_INFINITY: Self = Self(0b1_1111_000); - const NAN: Self = Self(0b0_1111_100); - const NEG_NAN: Self = Self(0b1_1111_100); - const MIN_POSITIVE_NORMAL: Self = Self(1 << Self::SIG_BITS); - // FIXME: incorrect values - const EPSILON: Self = Self::ZERO; - const PI: Self = Self::ZERO; - const NEG_PI: Self = Self::ZERO; - const FRAC_PI_2: Self = Self::ZERO; - - const BITS: u32 = 8; - const SIG_BITS: u32 = 3; - const SIGN_MASK: Self::Int = 0b1_0000_000; - const SIG_MASK: Self::Int = 0b0_0000_111; - const EXP_MASK: Self::Int = 0b0_1111_000; - const IMPLICIT_BIT: Self::Int = 0b0_0001_000; - - fn to_bits(self) -> Self::Int { - self.0 - } - - fn to_bits_signed(self) -> Self::SignedInt { - self.0 as i8 - } - - fn is_nan(self) -> bool { - self.0 & Self::EXP_MASK == Self::EXP_MASK && self.0 & Self::SIG_MASK != 0 - } - - fn is_infinite(self) -> bool { - self.0 & Self::EXP_MASK == Self::EXP_MASK && self.0 & Self::SIG_MASK == 0 - } - - fn is_sign_negative(self) -> bool { - self.0 & Self::SIGN_MASK != 0 - } - - fn from_bits(a: Self::Int) -> Self { - Self(a) - } - - fn abs(self) -> Self { - libm::generic::fabs(self) - } - - fn copysign(self, other: Self) -> Self { - libm::generic::copysign(self, other) - } - - fn fma(self, _y: Self, _z: Self) -> Self { - unimplemented!() - } - - fn normalize(_significand: Self::Int) -> (i32, Self::Int) { - unimplemented!() - } -} - -impl f8 { - pub const ALL_LEN: usize = 240; - - /// All non-infinite non-NaN values of `f8` - pub const ALL: [Self; Self::ALL_LEN] = [ - // -m*2^7 - Self(0b1_1110_111), // -240 - Self(0b1_1110_110), - Self(0b1_1110_101), - Self(0b1_1110_100), - Self(0b1_1110_011), - Self(0b1_1110_010), - Self(0b1_1110_001), - Self(0b1_1110_000), // -128 - // -m*2^6 - Self(0b1_1101_111), // -120 - Self(0b1_1101_110), - Self(0b1_1101_101), - Self(0b1_1101_100), - Self(0b1_1101_011), - Self(0b1_1101_010), - Self(0b1_1101_001), - Self(0b1_1101_000), // -64 - // -m*2^5 - Self(0b1_1100_111), // -60 - Self(0b1_1100_110), - Self(0b1_1100_101), - Self(0b1_1100_100), - Self(0b1_1100_011), - Self(0b1_1100_010), - Self(0b1_1100_001), - Self(0b1_1100_000), // -32 - // -m*2^4 - Self(0b1_1011_111), // -30 - Self(0b1_1011_110), - Self(0b1_1011_101), - Self(0b1_1011_100), - Self(0b1_1011_011), - Self(0b1_1011_010), - Self(0b1_1011_001), - Self(0b1_1011_000), // -16 - // -m*2^3 - Self(0b1_1010_111), // -15 - Self(0b1_1010_110), - Self(0b1_1010_101), - Self(0b1_1010_100), - Self(0b1_1010_011), - Self(0b1_1010_010), - Self(0b1_1010_001), - Self(0b1_1010_000), // -8 - // -m*2^2 - Self(0b1_1001_111), // -7.5 - Self(0b1_1001_110), - Self(0b1_1001_101), - Self(0b1_1001_100), - Self(0b1_1001_011), - Self(0b1_1001_010), - Self(0b1_1001_001), - Self(0b1_1001_000), // -4 - // -m*2^1 - Self(0b1_1000_111), // -3.75 - Self(0b1_1000_110), - Self(0b1_1000_101), - Self(0b1_1000_100), - Self(0b1_1000_011), - Self(0b1_1000_010), - Self(0b1_1000_001), - Self(0b1_1000_000), // -2 - // -m*2^0 - Self(0b1_0111_111), // -1.875 - Self(0b1_0111_110), - Self(0b1_0111_101), - Self(0b1_0111_100), - Self(0b1_0111_011), - Self(0b1_0111_010), - Self(0b1_0111_001), - Self(0b1_0111_000), // -1 - // -m*2^-1 - Self(0b1_0110_111), // −0.9375 - Self(0b1_0110_110), - Self(0b1_0110_101), - Self(0b1_0110_100), - Self(0b1_0110_011), - Self(0b1_0110_010), - Self(0b1_0110_001), - Self(0b1_0110_000), // -0.5 - // -m*2^-2 - Self(0b1_0101_111), // −0.46875 - Self(0b1_0101_110), - Self(0b1_0101_101), - Self(0b1_0101_100), - Self(0b1_0101_011), - Self(0b1_0101_010), - Self(0b1_0101_001), - Self(0b1_0101_000), // -0.25 - // -m*2^-3 - Self(0b1_0100_111), // −0.234375 - Self(0b1_0100_110), - Self(0b1_0100_101), - Self(0b1_0100_100), - Self(0b1_0100_011), - Self(0b1_0100_010), - Self(0b1_0100_001), - Self(0b1_0100_000), // -0.125 - // -m*2^-4 - Self(0b1_0011_111), // −0.1171875 - Self(0b1_0011_110), - Self(0b1_0011_101), - Self(0b1_0011_100), - Self(0b1_0011_011), - Self(0b1_0011_010), - Self(0b1_0011_001), - Self(0b1_0011_000), // −0.0625 - // -m*2^-5 - Self(0b1_0010_111), // −0.05859375 - Self(0b1_0010_110), - Self(0b1_0010_101), - Self(0b1_0010_100), - Self(0b1_0010_011), - Self(0b1_0010_010), - Self(0b1_0010_001), - Self(0b1_0010_000), // −0.03125 - // -m*2^-6 - Self(0b1_0001_111), // −0.029296875 - Self(0b1_0001_110), - Self(0b1_0001_101), - Self(0b1_0001_100), - Self(0b1_0001_011), - Self(0b1_0001_010), - Self(0b1_0001_001), - Self(0b1_0001_000), // −0.015625 - // -m*2^-7 subnormal numbers - Self(0b1_0000_111), // −0.013671875 - Self(0b1_0000_110), - Self(0b1_0000_101), - Self(0b1_0000_100), - Self(0b1_0000_011), - Self(0b1_0000_010), - Self(0b1_0000_001), // −0.001953125 - // Zeroes - Self(0b1_0000_000), // -0.0 - Self(0b0_0000_000), // 0.0 - // m*2^-7 // subnormal numbers - Self(0b0_0000_001), - Self(0b0_0000_010), - Self(0b0_0000_011), - Self(0b0_0000_100), - Self(0b0_0000_101), - Self(0b0_0000_110), - Self(0b0_0000_111), // 0.013671875 - // m*2^-6 - Self(0b0_0001_000), // 0.015625 - Self(0b0_0001_001), - Self(0b0_0001_010), - Self(0b0_0001_011), - Self(0b0_0001_100), - Self(0b0_0001_101), - Self(0b0_0001_110), - Self(0b0_0001_111), // 0.029296875 - // m*2^-5 - Self(0b0_0010_000), // 0.03125 - Self(0b0_0010_001), - Self(0b0_0010_010), - Self(0b0_0010_011), - Self(0b0_0010_100), - Self(0b0_0010_101), - Self(0b0_0010_110), - Self(0b0_0010_111), // 0.05859375 - // m*2^-4 - Self(0b0_0011_000), // 0.0625 - Self(0b0_0011_001), - Self(0b0_0011_010), - Self(0b0_0011_011), - Self(0b0_0011_100), - Self(0b0_0011_101), - Self(0b0_0011_110), - Self(0b0_0011_111), // 0.1171875 - // m*2^-3 - Self(0b0_0100_000), // 0.125 - Self(0b0_0100_001), - Self(0b0_0100_010), - Self(0b0_0100_011), - Self(0b0_0100_100), - Self(0b0_0100_101), - Self(0b0_0100_110), - Self(0b0_0100_111), // 0.234375 - // m*2^-2 - Self(0b0_0101_000), // 0.25 - Self(0b0_0101_001), - Self(0b0_0101_010), - Self(0b0_0101_011), - Self(0b0_0101_100), - Self(0b0_0101_101), - Self(0b0_0101_110), - Self(0b0_0101_111), // 0.46875 - // m*2^-1 - Self(0b0_0110_000), // 0.5 - Self(0b0_0110_001), - Self(0b0_0110_010), - Self(0b0_0110_011), - Self(0b0_0110_100), - Self(0b0_0110_101), - Self(0b0_0110_110), - Self(0b0_0110_111), // 0.9375 - // m*2^0 - Self(0b0_0111_000), // 1 - Self(0b0_0111_001), - Self(0b0_0111_010), - Self(0b0_0111_011), - Self(0b0_0111_100), - Self(0b0_0111_101), - Self(0b0_0111_110), - Self(0b0_0111_111), // 1.875 - // m*2^1 - Self(0b0_1000_000), // 2 - Self(0b0_1000_001), - Self(0b0_1000_010), - Self(0b0_1000_011), - Self(0b0_1000_100), - Self(0b0_1000_101), - Self(0b0_1000_110), - Self(0b0_1000_111), // 3.75 - // m*2^2 - Self(0b0_1001_000), // 4 - Self(0b0_1001_001), - Self(0b0_1001_010), - Self(0b0_1001_011), - Self(0b0_1001_100), - Self(0b0_1001_101), - Self(0b0_1001_110), - Self(0b0_1001_111), // 7.5 - // m*2^3 - Self(0b0_1010_000), // 8 - Self(0b0_1010_001), - Self(0b0_1010_010), - Self(0b0_1010_011), - Self(0b0_1010_100), - Self(0b0_1010_101), - Self(0b0_1010_110), - Self(0b0_1010_111), // 15 - // m*2^4 - Self(0b0_1011_000), // 16 - Self(0b0_1011_001), - Self(0b0_1011_010), - Self(0b0_1011_011), - Self(0b0_1011_100), - Self(0b0_1011_101), - Self(0b0_1011_110), - Self(0b0_1011_111), // 30 - // m*2^5 - Self(0b0_1100_000), // 32 - Self(0b0_1100_001), - Self(0b0_1100_010), - Self(0b0_1100_011), - Self(0b0_1100_100), - Self(0b0_1100_101), - Self(0b0_1100_110), - Self(0b0_1100_111), // 60 - // m*2^6 - Self(0b0_1101_000), // 64 - Self(0b0_1101_001), - Self(0b0_1101_010), - Self(0b0_1101_011), - Self(0b0_1101_100), - Self(0b0_1101_101), - Self(0b0_1101_110), - Self(0b0_1101_111), // 120 - // m*2^7 - Self(0b0_1110_000), // 128 - Self(0b0_1110_001), - Self(0b0_1110_010), - Self(0b0_1110_011), - Self(0b0_1110_100), - Self(0b0_1110_101), - Self(0b0_1110_110), - Self(0b0_1110_111), // 240 - ]; -} - -impl ops::Add for f8 { - type Output = Self; - fn add(self, _rhs: Self) -> Self::Output { - unimplemented!() - } -} - -impl ops::Sub for f8 { - type Output = Self; - fn sub(self, _rhs: Self) -> Self::Output { - unimplemented!() - } -} -impl ops::Mul for f8 { - type Output = Self; - fn mul(self, _rhs: Self) -> Self::Output { - unimplemented!() - } -} -impl ops::Div for f8 { - type Output = Self; - fn div(self, _rhs: Self) -> Self::Output { - unimplemented!() - } -} - -impl ops::Neg for f8 { - type Output = Self; - fn neg(self) -> Self::Output { - Self(self.0 ^ Self::SIGN_MASK) - } -} - -impl ops::Rem for f8 { - type Output = Self; - fn rem(self, _rhs: Self) -> Self::Output { - unimplemented!() - } -} - -impl ops::AddAssign for f8 { - fn add_assign(&mut self, _rhs: Self) { - unimplemented!() - } -} - -impl ops::SubAssign for f8 { - fn sub_assign(&mut self, _rhs: Self) { - unimplemented!() - } -} - -impl ops::MulAssign for f8 { - fn mul_assign(&mut self, _rhs: Self) { - unimplemented!() - } -} - -impl cmp::PartialEq for f8 { - fn eq(&self, other: &Self) -> bool { - if self.is_nan() || other.is_nan() { - false - } else if self.abs().to_bits() | other.abs().to_bits() == 0 { - true - } else { - self.0 == other.0 - } - } -} -impl cmp::PartialOrd for f8 { - fn partial_cmp(&self, other: &Self) -> Option { - let inf_rep = f8::EXP_MASK; - - let a_abs = self.abs().to_bits(); - let b_abs = other.abs().to_bits(); - - // If either a or b is NaN, they are unordered. - if a_abs > inf_rep || b_abs > inf_rep { - return None; - } - - // If a and b are both zeros, they are equal. - if a_abs | b_abs == 0 { - return Some(Ordering::Equal); - } - - let a_srep = self.to_bits_signed(); - let b_srep = other.to_bits_signed(); - let res = a_srep.cmp(&b_srep); - - if a_srep & b_srep >= 0 { - // If at least one of a and b is positive, we get the same result comparing - // a and b as signed integers as we would with a fp_ting-point compare. - Some(res) - } else { - // Otherwise, both are negative, so we need to flip the sense of the - // comparison to get the correct result. - Some(res.reverse()) - } - } -} -impl fmt::Display for f8 { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() - } -} - -impl fmt::Debug for f8 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Binary::fmt(self, f) - } -} - -impl fmt::Binary for f8 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let v = self.0; - write!( - f, - "0b{:b}_{:04b}_{:03b}", - v >> 7, - (v & Self::EXP_MASK) >> Self::SIG_BITS, - v & Self::SIG_MASK - ) - } -} - -impl fmt::LowerHex for f8 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -pub const fn hf8(s: &str) -> f8 { - let Ok(bits) = libm::support::hex_float::parse_hex_exact(s, 8, 3) else { panic!() }; - f8(bits as u8) -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate.rs deleted file mode 100644 index 89ca09a7a0b..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/generate.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Different generators that can create random or systematic bit patterns. - -pub mod case_list; -pub mod edge_cases; -pub mod random; -pub mod spaced; - -/// A wrapper to turn any iterator into an `ExactSizeIterator`. Asserts the final result to ensure -/// the provided size was correct. -#[derive(Debug)] -pub struct KnownSize { - total: u64, - current: u64, - iter: I, -} - -impl KnownSize { - pub fn new(iter: I, total: u64) -> Self { - Self { total, current: 0, iter } - } -} - -impl Iterator for KnownSize { - type Item = I::Item; - - fn next(&mut self) -> Option { - let next = self.iter.next(); - if next.is_some() { - self.current += 1; - return next; - } - - assert_eq!(self.current, self.total, "total items did not match expected"); - None - } - - fn size_hint(&self) -> (usize, Option) { - let remaining = usize::try_from(self.total - self.current).unwrap(); - (remaining, Some(remaining)) - } -} - -impl ExactSizeIterator for KnownSize {} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate/case_list.rs deleted file mode 100644 index e3628d51c9a..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/generate/case_list.rs +++ /dev/null @@ -1,853 +0,0 @@ -//! Test cases to verify specific values. -//! -//! Each routine can have a set of inputs and, optinoally, outputs. If an output is provided, it -//! will be used to check against. If only inputs are provided, the case will be checked against -//! a basis. -//! -//! This is useful for adding regression tests or expected failures. - -use libm::hf64; -#[cfg(f128_enabled)] -use libm::hf128; - -use crate::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; - -pub struct TestCase { - pub input: Op::RustArgs, - pub output: Option, -} - -impl TestCase { - #[expect(dead_code)] - fn append_inputs(v: &mut Vec, l: &[Op::RustArgs]) { - v.extend(l.iter().copied().map(|input| Self { input, output: None })); - } - - fn append_pairs(v: &mut Vec, l: &[(Op::RustArgs, Option)]) - where - Op::RustRet: Copy, - { - v.extend(l.iter().copied().map(|(input, output)| Self { input, output })); - } -} - -fn acos_cases() -> Vec> { - vec![] -} - -fn acosf_cases() -> Vec> { - vec![] -} - -fn acosh_cases() -> Vec> { - vec![] -} - -fn acoshf_cases() -> Vec> { - vec![] -} - -fn asin_cases() -> Vec> { - vec![] -} - -fn asinf_cases() -> Vec> { - vec![] -} - -fn asinh_cases() -> Vec> { - vec![] -} - -fn asinhf_cases() -> Vec> { - vec![] -} - -fn atan_cases() -> Vec> { - vec![] -} - -fn atan2_cases() -> Vec> { - vec![] -} - -fn atan2f_cases() -> Vec> { - vec![] -} - -fn atanf_cases() -> Vec> { - vec![] -} - -fn atanh_cases() -> Vec> { - vec![] -} - -fn atanhf_cases() -> Vec> { - vec![] -} - -fn cbrt_cases() -> Vec> { - vec![] -} - -fn cbrtf_cases() -> Vec> { - vec![] -} - -fn ceil_cases() -> Vec> { - vec![] -} - -fn ceilf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn ceilf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn ceilf16_cases() -> Vec> { - vec![] -} - -fn copysign_cases() -> Vec> { - vec![] -} - -fn copysignf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn copysignf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn copysignf16_cases() -> Vec> { - vec![] -} - -fn cos_cases() -> Vec> { - vec![] -} - -fn cosf_cases() -> Vec> { - vec![] -} - -fn cosh_cases() -> Vec> { - vec![] -} - -fn coshf_cases() -> Vec> { - vec![] -} - -fn erf_cases() -> Vec> { - vec![] -} - -fn erfc_cases() -> Vec> { - vec![] -} - -fn erfcf_cases() -> Vec> { - vec![] -} - -fn erff_cases() -> Vec> { - vec![] -} - -fn exp_cases() -> Vec> { - vec![] -} - -fn exp10_cases() -> Vec> { - vec![] -} - -fn exp10f_cases() -> Vec> { - vec![] -} - -fn exp2_cases() -> Vec> { - vec![] -} - -fn exp2f_cases() -> Vec> { - vec![] -} - -fn expf_cases() -> Vec> { - vec![] -} - -fn expm1_cases() -> Vec> { - vec![] -} - -fn expm1f_cases() -> Vec> { - vec![] -} - -fn fabs_cases() -> Vec> { - vec![] -} - -fn fabsf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fabsf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fabsf16_cases() -> Vec> { - vec![] -} - -fn fdim_cases() -> Vec> { - vec![] -} - -fn fdimf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fdimf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fdimf16_cases() -> Vec> { - vec![] -} - -fn floor_cases() -> Vec> { - vec![] -} - -fn floorf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn floorf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn floorf16_cases() -> Vec> { - vec![] -} - -fn fma_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Previous failure with incorrect sign - ((5e-324, -5e-324, 0.0), Some(-0.0)), - ], - ); - v -} - -fn fmaf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fmaf128_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - ( - // Tricky rounding case that previously failed in extensive tests - ( - hf128!("-0x1.1966cc01966cc01966cc01966f06p-25"), - hf128!("-0x1.669933fe69933fe69933fe6997c9p-16358"), - hf128!("-0x0.000000000000000000000000048ap-16382"), - ), - Some(hf128!("0x0.c5171470a3ff5e0f68d751491b18p-16382")), - ), - ( - // Subnormal edge case that caused a failure - ( - hf128!("0x0.7ffffffffffffffffffffffffff7p-16382"), - hf128!("0x1.ffffffffffffffffffffffffffffp-1"), - hf128!("0x0.8000000000000000000000000009p-16382"), - ), - Some(hf128!("0x1.0000000000000000000000000000p-16382")), - ), - ], - ); - v -} - -#[cfg(f16_enabled)] -fn fmaxf16_cases() -> Vec> { - vec![] -} - -fn fmaxf_cases() -> Vec> { - vec![] -} - -fn fmax_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fmaxf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fmaximumf16_cases() -> Vec> { - vec![] -} - -fn fmaximumf_cases() -> Vec> { - vec![] -} - -fn fmaximum_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fmaximumf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fmaximum_numf16_cases() -> Vec> { - vec![] -} - -fn fmaximum_numf_cases() -> Vec> { - vec![] -} - -fn fmaximum_num_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fmaximum_numf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fminf16_cases() -> Vec> { - vec![] -} - -fn fminf_cases() -> Vec> { - vec![] -} - -fn fmin_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fminf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fminimumf16_cases() -> Vec> { - vec![] -} - -fn fminimumf_cases() -> Vec> { - vec![] -} - -fn fminimum_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fminimumf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fminimum_numf16_cases() -> Vec> { - vec![] -} - -fn fminimum_numf_cases() -> Vec> { - vec![] -} - -fn fminimum_num_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn fminimum_numf128_cases() -> Vec> { - vec![] -} - -fn fmod_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Previous failure with incorrect loop iteration - // - ((2.1, 3.123e-320), Some(2.0696e-320)), - ((2.1, 2.253547e-318), Some(1.772535e-318)), - ], - ); - v -} - -fn fmodf_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Previous failure with incorrect loop iteration - // - ((2.1, 8.858e-42), Some(8.085e-42)), - ((2.1, 6.39164e-40), Some(6.1636e-40)), - ((5.5, 6.39164e-40), Some(4.77036e-40)), - ((-151.189, 6.39164e-40), Some(-5.64734e-40)), - ], - ); - v -} - -#[cfg(f128_enabled)] -fn fmodf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn fmodf16_cases() -> Vec> { - vec![] -} - -fn frexp_cases() -> Vec> { - vec![] -} - -fn frexpf_cases() -> Vec> { - vec![] -} - -fn hypot_cases() -> Vec> { - vec![] -} - -fn hypotf_cases() -> Vec> { - vec![] -} - -fn ilogb_cases() -> Vec> { - vec![] -} - -fn ilogbf_cases() -> Vec> { - vec![] -} - -fn j0_cases() -> Vec> { - vec![] -} - -fn j0f_cases() -> Vec> { - vec![] -} - -fn j1_cases() -> Vec> { - vec![] -} - -fn j1f_cases() -> Vec> { - vec![] -} - -fn jn_cases() -> Vec> { - vec![] -} - -fn jnf_cases() -> Vec> { - vec![] -} - -fn ldexp_cases() -> Vec> { - vec![] -} - -fn ldexpf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn ldexpf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn ldexpf16_cases() -> Vec> { - vec![] -} - -fn lgamma_cases() -> Vec> { - vec![] -} - -fn lgamma_r_cases() -> Vec> { - vec![] -} - -fn lgammaf_cases() -> Vec> { - vec![] -} - -fn lgammaf_r_cases() -> Vec> { - vec![] -} - -fn log_cases() -> Vec> { - vec![] -} - -fn log10_cases() -> Vec> { - vec![] -} - -fn log10f_cases() -> Vec> { - vec![] -} - -fn log1p_cases() -> Vec> { - vec![] -} - -fn log1pf_cases() -> Vec> { - vec![] -} - -fn log2_cases() -> Vec> { - vec![] -} - -fn log2f_cases() -> Vec> { - vec![] -} - -fn logf_cases() -> Vec> { - vec![] -} - -fn modf_cases() -> Vec> { - vec![] -} - -fn modff_cases() -> Vec> { - vec![] -} - -fn nextafter_cases() -> Vec> { - vec![] -} - -fn nextafterf_cases() -> Vec> { - vec![] -} - -fn pow_cases() -> Vec> { - vec![] -} - -fn powf_cases() -> Vec> { - vec![] -} - -fn remainder_cases() -> Vec> { - vec![] -} - -fn remainderf_cases() -> Vec> { - vec![] -} - -fn remquo_cases() -> Vec> { - vec![] -} - -fn remquof_cases() -> Vec> { - vec![] -} - -fn rint_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Known failure on i586 - #[cfg(not(x86_no_sse))] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), - #[cfg(x86_no_sse)] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))), - ], - ); - v -} - -fn rintf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn rintf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn rintf16_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn roundf16_cases() -> Vec> { - vec![] -} - -fn round_cases() -> Vec> { - vec![] -} - -fn roundf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn roundf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn roundevenf16_cases() -> Vec> { - vec![] -} - -fn roundeven_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Known failure on i586 - #[cfg(not(x86_no_sse))] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), - #[cfg(x86_no_sse)] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))), - ], - ); - v -} - -fn roundevenf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn roundevenf128_cases() -> Vec> { - vec![] -} - -fn scalbn_cases() -> Vec> { - vec![] -} - -fn scalbnf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn scalbnf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn scalbnf16_cases() -> Vec> { - vec![] -} - -fn sin_cases() -> Vec> { - vec![] -} - -fn sincos_cases() -> Vec> { - vec![] -} - -fn sincosf_cases() -> Vec> { - vec![] -} - -fn sinf_cases() -> Vec> { - vec![] -} - -fn sinh_cases() -> Vec> { - vec![] -} - -fn sinhf_cases() -> Vec> { - vec![] -} - -fn sqrt_cases() -> Vec> { - vec![] -} - -fn sqrtf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn sqrtf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn sqrtf16_cases() -> Vec> { - vec![] -} - -fn tan_cases() -> Vec> { - vec![] -} - -fn tanf_cases() -> Vec> { - vec![] -} - -fn tanh_cases() -> Vec> { - vec![] -} - -fn tanhf_cases() -> Vec> { - vec![] -} - -fn tgamma_cases() -> Vec> { - vec![] -} - -fn tgammaf_cases() -> Vec> { - vec![] -} - -fn trunc_cases() -> Vec> { - vec![] -} - -fn truncf_cases() -> Vec> { - vec![] -} - -#[cfg(f128_enabled)] -fn truncf128_cases() -> Vec> { - vec![] -} - -#[cfg(f16_enabled)] -fn truncf16_cases() -> Vec> { - vec![] -} - -fn y0_cases() -> Vec> { - vec![] -} - -fn y0f_cases() -> Vec> { - vec![] -} - -fn y1_cases() -> Vec> { - vec![] -} - -fn y1f_cases() -> Vec> { - vec![] -} - -fn yn_cases() -> Vec> { - vec![] -} - -fn ynf_cases() -> Vec> { - vec![] -} - -pub trait CaseListInput: MathOp + Sized { - fn get_cases() -> Vec>; -} - -macro_rules! impl_case_list { - ( - fn_name: $fn_name:ident, - attrs: [$($attr:meta),*], - ) => { - paste::paste! { - $(#[$attr])* - impl CaseListInput for crate::op::$fn_name::Routine { - fn get_cases() -> Vec> { - [< $fn_name _cases >]() - } - } - } - }; -} - -libm_macros::for_each_function! { - callback: impl_case_list, -} - -/// This is the test generator for standalone tests, i.e. those with no basis. For this, it -/// only extracts tests with a known output. -pub fn get_test_cases_standalone( - ctx: &CheckCtx, -) -> impl Iterator + use<'_, Op> -where - Op: MathOp + CaseListInput, -{ - assert_eq!(ctx.basis, CheckBasis::None); - assert_eq!(ctx.gen_kind, GeneratorKind::List); - Op::get_cases().into_iter().filter_map(|x| x.output.map(|o| (x.input, o))) -} - -/// Opposite of the above; extract only test cases that don't have a known output, to be run -/// against a basis. -pub fn get_test_cases_basis( - ctx: &CheckCtx, -) -> (impl Iterator + use<'_, Op>, u64) -where - Op: MathOp + CaseListInput, -{ - assert_ne!(ctx.basis, CheckBasis::None); - assert_eq!(ctx.gen_kind, GeneratorKind::List); - - let cases = Op::get_cases(); - let count: u64 = cases.iter().filter(|case| case.output.is_none()).count().try_into().unwrap(); - - (cases.into_iter().filter(|x| x.output.is_none()).map(|x| x.input), count) -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate/edge_cases.rs deleted file mode 100644 index 56cc9fa9a70..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/generate/edge_cases.rs +++ /dev/null @@ -1,310 +0,0 @@ -//! A generator that checks a handful of cases near infinities, zeros, asymptotes, and NaNs. - -use libm::support::{CastInto, Float, Int, MinInt}; - -use crate::domain::get_domain; -use crate::generate::KnownSize; -use crate::op::OpITy; -use crate::run_cfg::{check_near_count, check_point_count}; -use crate::{BaseName, CheckCtx, FloatExt, FloatTy, MathOp, test_log}; - -/// Generate a sequence of edge cases, e.g. numbers near zeroes and infiniteis. -pub trait EdgeCaseInput { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); -} - -/// Create a list of values around interesting points (infinities, zeroes, NaNs). -fn float_edge_cases( - ctx: &CheckCtx, - argnum: usize, -) -> (impl Iterator + Clone, u64) -where - Op: MathOp, -{ - let mut ret = Vec::new(); - let one = OpITy::::ONE; - let values = &mut ret; - let domain = get_domain::<_, i8>(ctx.fn_ident, argnum).unwrap_float(); - let domain_start = domain.range_start(); - let domain_end = domain.range_end(); - - let check_points = check_point_count(ctx); - let near_points = check_near_count(ctx); - - // Check near some notable constants - count_up(Op::FTy::ONE, near_points, values); - count_up(Op::FTy::ZERO, near_points, values); - count_up(Op::FTy::NEG_ONE, near_points, values); - count_down(Op::FTy::ONE, near_points, values); - count_down(Op::FTy::ZERO, near_points, values); - count_down(Op::FTy::NEG_ONE, near_points, values); - values.push(Op::FTy::NEG_ZERO); - - // Check values near the extremes - count_up(Op::FTy::NEG_INFINITY, near_points, values); - count_down(Op::FTy::INFINITY, near_points, values); - count_down(domain_end, near_points, values); - count_up(domain_start, near_points, values); - count_down(domain_start, near_points, values); - count_up(domain_end, near_points, values); - count_down(domain_end, near_points, values); - - // Check some special values that aren't included in the above ranges - values.push(Op::FTy::NAN); - values.extend(Op::FTy::consts().iter()); - - // Check around the maximum subnormal value - let sub_max = Op::FTy::from_bits(Op::FTy::SIG_MASK); - count_up(sub_max, near_points, values); - count_down(sub_max, near_points, values); - count_up(-sub_max, near_points, values); - count_down(-sub_max, near_points, values); - - // Check a few values around the subnormal range - for shift in (0..Op::FTy::SIG_BITS).step_by(Op::FTy::SIG_BITS as usize / 5) { - let v = Op::FTy::from_bits(one << shift); - count_up(v, 2, values); - count_down(v, 2, values); - count_up(-v, 2, values); - count_down(-v, 2, values); - } - - // Check around asymptotes - if let Some(f) = domain.check_points { - let iter = f(); - for x in iter.take(check_points) { - count_up(x, near_points, values); - count_down(x, near_points, values); - } - } - - // Some results may overlap so deduplicate the vector to save test cycles. - values.sort_by_key(|x| x.to_bits()); - values.dedup_by_key(|x| x.to_bits()); - - let count = ret.len().try_into().unwrap(); - - test_log(&format!( - "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {count} edge cases", - gen_kind = ctx.gen_kind, - basis = ctx.basis, - fn_ident = ctx.fn_ident, - arg = argnum + 1, - args = ctx.input_count(), - )); - - (ret.into_iter(), count) -} - -/// Add `points` values starting at and including `x` and counting up. Uses the smallest possible -/// increments (1 ULP). -fn count_up(mut x: F, points: u64, values: &mut Vec) { - assert!(!x.is_nan()); - - let mut count = 0; - while x < F::INFINITY && count < points { - values.push(x); - x = x.next_up(); - count += 1; - } -} - -/// Add `points` values starting at and including `x` and counting down. Uses the smallest possible -/// increments (1 ULP). -fn count_down(mut x: F, points: u64, values: &mut Vec) { - assert!(!x.is_nan()); - - let mut count = 0; - while x > F::NEG_INFINITY && count < points { - values.push(x); - x = x.next_down(); - count += 1; - } -} - -/// Create a list of values around interesting integer points (min, zero, max). -pub fn int_edge_cases( - ctx: &CheckCtx, - argnum: usize, -) -> (impl Iterator + Clone, u64) -where - i32: CastInto, -{ - let mut values = Vec::new(); - let near_points = check_near_count(ctx); - - // Check around max/min and zero - int_count_around(I::MIN, near_points, &mut values); - int_count_around(I::MAX, near_points, &mut values); - int_count_around(I::ZERO, near_points, &mut values); - int_count_around(I::ZERO, near_points, &mut values); - - if matches!(ctx.base_name, BaseName::Scalbn | BaseName::Ldexp) { - assert_eq!(argnum, 1, "scalbn integer argument should be arg1"); - let (emax, emin, emin_sn) = match ctx.fn_ident.math_op().float_ty { - FloatTy::F16 => { - #[cfg(not(f16_enabled))] - unreachable!(); - #[cfg(f16_enabled)] - (f16::EXP_MAX, f16::EXP_MIN, f16::EXP_MIN_SUBNORM) - } - FloatTy::F32 => (f32::EXP_MAX, f32::EXP_MIN, f32::EXP_MIN_SUBNORM), - FloatTy::F64 => (f64::EXP_MAX, f64::EXP_MIN, f64::EXP_MIN_SUBNORM), - FloatTy::F128 => { - #[cfg(not(f128_enabled))] - unreachable!(); - #[cfg(f128_enabled)] - (f128::EXP_MAX, f128::EXP_MIN, f128::EXP_MIN_SUBNORM) - } - }; - - // `scalbn`/`ldexp` have their trickiest behavior around exponent limits - int_count_around(emax.cast(), near_points, &mut values); - int_count_around(emin.cast(), near_points, &mut values); - int_count_around(emin_sn.cast(), near_points, &mut values); - int_count_around((-emin_sn).cast(), near_points, &mut values); - - // Also check values that cause the maximum possible difference in exponents - int_count_around((emax - emin).cast(), near_points, &mut values); - int_count_around((emin - emax).cast(), near_points, &mut values); - int_count_around((emax - emin_sn).cast(), near_points, &mut values); - int_count_around((emin_sn - emax).cast(), near_points, &mut values); - } - - values.sort(); - values.dedup(); - let count = values.len().try_into().unwrap(); - - test_log(&format!( - "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {count} edge cases", - gen_kind = ctx.gen_kind, - basis = ctx.basis, - fn_ident = ctx.fn_ident, - arg = argnum + 1, - args = ctx.input_count(), - )); - - (values.into_iter(), count) -} - -/// Add `points` values both up and down, starting at and including `x`. -fn int_count_around(x: I, points: u64, values: &mut Vec) { - let mut current = x; - for _ in 0..points { - values.push(current); - current = match current.checked_add(I::ONE) { - Some(v) => v, - None => break, - }; - } - - current = x; - for _ in 0..points { - values.push(current); - current = match current.checked_sub(I::ONE) { - Some(v) => v, - None => break, - }; - } -} - -macro_rules! impl_edge_case_input { - ($fty:ty) => { - impl EdgeCaseInput for ($fty,) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let (iter0, steps0) = float_edge_cases::(ctx, 0); - let iter0 = iter0.map(|v| (v,)); - (iter0, steps0) - } - } - - impl EdgeCaseInput for ($fty, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let (iter0, steps0) = float_edge_cases::(ctx, 0); - let (iter1, steps1) = float_edge_cases::(ctx, 1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); - (iter, count) - } - } - - impl EdgeCaseInput for ($fty, $fty, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let (iter0, steps0) = float_edge_cases::(ctx, 0); - let (iter1, steps1) = float_edge_cases::(ctx, 1); - let (iter2, steps2) = float_edge_cases::(ctx, 2); - - let iter = iter0 - .flat_map(move |first| iter1.clone().map(move |second| (first, second))) - .flat_map(move |(first, second)| { - iter2.clone().map(move |third| (first, second, third)) - }); - let count = steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); - - (iter, count) - } - } - - impl EdgeCaseInput for (i32, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let (iter0, steps0) = int_edge_cases(ctx, 0); - let (iter1, steps1) = float_edge_cases::(ctx, 1); - - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); - - (iter, count) - } - } - - impl EdgeCaseInput for ($fty, i32) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let (iter0, steps0) = float_edge_cases::(ctx, 0); - let (iter1, steps1) = int_edge_cases(ctx, 1); - - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); - - (iter, count) - } - } - }; -} - -#[cfg(f16_enabled)] -impl_edge_case_input!(f16); -impl_edge_case_input!(f32); -impl_edge_case_input!(f64); -#[cfg(f128_enabled)] -impl_edge_case_input!(f128); - -pub fn get_test_cases( - ctx: &CheckCtx, -) -> (impl Iterator + Send + use<'_, Op>, u64) -where - Op: MathOp, - Op::RustArgs: EdgeCaseInput, -{ - let (iter, count) = Op::RustArgs::get_cases(ctx); - - // Wrap in `KnownSize` so we get an assertion if the cuunt is wrong. - (KnownSize::new(iter, count), count) -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate/random.rs deleted file mode 100644 index e8a7ee9057e..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/generate/random.rs +++ /dev/null @@ -1,125 +0,0 @@ -use std::env; -use std::ops::RangeInclusive; -use std::sync::LazyLock; - -use libm::support::Float; -use rand::distr::{Alphanumeric, StandardUniform}; -use rand::prelude::Distribution; -use rand::{Rng, SeedableRng}; -use rand_chacha::ChaCha8Rng; - -use super::KnownSize; -use crate::CheckCtx; -use crate::run_cfg::{int_range, iteration_count}; - -pub(crate) const SEED_ENV: &str = "LIBM_SEED"; - -pub static SEED: LazyLock<[u8; 32]> = LazyLock::new(|| { - let s = env::var(SEED_ENV).unwrap_or_else(|_| { - let mut rng = rand::rng(); - (0..32).map(|_| rng.sample(Alphanumeric) as char).collect() - }); - - s.as_bytes().try_into().unwrap_or_else(|_| { - panic!("Seed must be 32 characters, got `{s}`"); - }) -}); - -/// Generate a sequence of random values of this type. -pub trait RandomInput: Sized { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); -} - -/// Generate a sequence of deterministically random floats. -fn random_floats(count: u64) -> impl Iterator -where - StandardUniform: Distribution, -{ - let mut rng = ChaCha8Rng::from_seed(*SEED); - - // Generate integers to get a full range of bitpatterns (including NaNs), then convert back - // to the float type. - (0..count).map(move |_| F::from_bits(rng.random::())) -} - -/// Generate a sequence of deterministically random `i32`s within a specified range. -fn random_ints(count: u64, range: RangeInclusive) -> impl Iterator { - let mut rng = ChaCha8Rng::from_seed(*SEED); - (0..count).map(move |_| rng.random_range::(range.clone())) -} - -macro_rules! impl_random_input { - ($fty:ty) => { - impl RandomInput for ($fty,) { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let count = iteration_count(ctx, 0); - let iter = random_floats(count).map(|f: $fty| (f,)); - (iter, count) - } - } - - impl RandomInput for ($fty, $fty) { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let count0 = iteration_count(ctx, 0); - let count1 = iteration_count(ctx, 1); - let iter = random_floats(count0) - .flat_map(move |f1: $fty| random_floats(count1).map(move |f2: $fty| (f1, f2))); - (iter, count0 * count1) - } - } - - impl RandomInput for ($fty, $fty, $fty) { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let count0 = iteration_count(ctx, 0); - let count1 = iteration_count(ctx, 1); - let count2 = iteration_count(ctx, 2); - let iter = random_floats(count0).flat_map(move |f1: $fty| { - random_floats(count1).flat_map(move |f2: $fty| { - random_floats(count2).map(move |f3: $fty| (f1, f2, f3)) - }) - }); - (iter, count0 * count1 * count2) - } - } - - impl RandomInput for (i32, $fty) { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let count0 = iteration_count(ctx, 0); - let count1 = iteration_count(ctx, 1); - let range0 = int_range(ctx, 0); - let iter = random_ints(count0, range0) - .flat_map(move |f1: i32| random_floats(count1).map(move |f2: $fty| (f1, f2))); - (iter, count0 * count1) - } - } - - impl RandomInput for ($fty, i32) { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let count0 = iteration_count(ctx, 0); - let count1 = iteration_count(ctx, 1); - let range1 = int_range(ctx, 1); - let iter = random_floats(count0).flat_map(move |f1: $fty| { - random_ints(count1, range1.clone()).map(move |f2: i32| (f1, f2)) - }); - (iter, count0 * count1) - } - } - }; -} - -#[cfg(f16_enabled)] -impl_random_input!(f16); -impl_random_input!(f32); -impl_random_input!(f64); -#[cfg(f128_enabled)] -impl_random_input!(f128); - -/// Create a test case iterator. -pub fn get_test_cases( - ctx: &CheckCtx, -) -> (impl Iterator + Send + use<'_, RustArgs>, u64) { - let (iter, count) = RustArgs::get_cases(ctx); - - // Wrap in `KnownSize` so we get an assertion if the cuunt is wrong. - (KnownSize::new(iter, count), count) -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate/spaced.rs deleted file mode 100644 index bea3f4c7e1b..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/generate/spaced.rs +++ /dev/null @@ -1,253 +0,0 @@ -use std::fmt; -use std::ops::RangeInclusive; - -use libm::support::{Float, MinInt}; - -use crate::domain::get_domain; -use crate::op::OpITy; -use crate::run_cfg::{int_range, iteration_count}; -use crate::{CheckCtx, MathOp, linear_ints, logspace}; - -/// Generate a sequence of inputs that eiher cover the domain in completeness (for smaller float -/// types and single argument functions) or provide evenly spaced inputs across the domain with -/// approximately `u32::MAX` total iterations. -pub trait SpacedInput { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); -} - -/// Construct an iterator from `logspace` and also calculate the total number of steps expected -/// for that iterator. -fn logspace_steps( - ctx: &CheckCtx, - argnum: usize, - max_steps: u64, -) -> (impl Iterator + Clone, u64) -where - Op: MathOp, - OpITy: TryFrom, - u64: TryFrom, Error: fmt::Debug>, - RangeInclusive>: Iterator, -{ - // i8 is a dummy type here, it can be any integer. - let domain = get_domain::(ctx.fn_ident, argnum).unwrap_float(); - let start = domain.range_start(); - let end = domain.range_end(); - - let max_steps = OpITy::::try_from(max_steps).unwrap_or(OpITy::::MAX); - let (iter, steps) = logspace(start, end, max_steps); - - // `steps` will be <= the original `max_steps`, which is a `u64`. - (iter, steps.try_into().unwrap()) -} - -/// Represents the iterator in either `Left` or `Right`. -enum EitherIter { - A(A), - B(B), -} - -impl, B: Iterator> Iterator for EitherIter { - type Item = T; - - fn next(&mut self) -> Option { - match self { - Self::A(iter) => iter.next(), - Self::B(iter) => iter.next(), - } - } - - fn size_hint(&self) -> (usize, Option) { - match self { - Self::A(iter) => iter.size_hint(), - Self::B(iter) => iter.size_hint(), - } - } -} - -/// Gets the total number of possible values, returning `None` if that number doesn't fit in a -/// `u64`. -fn value_count() -> Option -where - u64: TryFrom, -{ - u64::try_from(F::Int::MAX).ok().and_then(|max| max.checked_add(1)) -} - -/// Returns an iterator of every possible value of type `F`. -fn all_values() -> impl Iterator -where - RangeInclusive: Iterator, -{ - (F::Int::MIN..=F::Int::MAX).map(|bits| F::from_bits(bits)) -} - -macro_rules! impl_spaced_input { - ($fty:ty) => { - impl SpacedInput for ($fty,) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, 0); - // `f16` and `f32` can have exhaustive tests. - match value_count::() { - Some(steps0) if steps0 <= max_steps0 => { - let iter0 = all_values(); - let iter0 = iter0.map(|v| (v,)); - (EitherIter::A(iter0), steps0) - } - _ => { - let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); - let iter0 = iter0.map(|v| (v,)); - (EitherIter::B(iter0), steps0) - } - } - } - } - - impl SpacedInput for ($fty, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, 0); - let max_steps1 = iteration_count(ctx, 1); - // `f16` can have exhaustive tests. - match value_count::() { - Some(count) if count <= max_steps0 && count <= max_steps1 => { - let iter = all_values() - .flat_map(|first| all_values().map(move |second| (first, second))); - (EitherIter::A(iter), count.checked_mul(count).unwrap()) - } - _ => { - let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); - let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); - let iter = iter0.flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = steps0.checked_mul(steps1).unwrap(); - (EitherIter::B(iter), count) - } - } - } - } - - impl SpacedInput for ($fty, $fty, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, 0); - let max_steps1 = iteration_count(ctx, 1); - let max_steps2 = iteration_count(ctx, 2); - // `f16` can be exhaustive tested if `LIBM_EXTENSIVE_TESTS` is incresed. - match value_count::() { - Some(count) - if count <= max_steps0 && count <= max_steps1 && count <= max_steps2 => - { - let iter = all_values().flat_map(|first| { - all_values().flat_map(move |second| { - all_values().map(move |third| (first, second, third)) - }) - }); - (EitherIter::A(iter), count.checked_pow(3).unwrap()) - } - _ => { - let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); - let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); - let (iter2, steps2) = logspace_steps::(ctx, 2, max_steps2); - - let iter = iter0 - .flat_map(move |first| iter1.clone().map(move |second| (first, second))) - .flat_map(move |(first, second)| { - iter2.clone().map(move |third| (first, second, third)) - }); - let count = - steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); - - (EitherIter::B(iter), count) - } - } - } - } - - impl SpacedInput for (i32, $fty) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let range0 = int_range(ctx, 0); - let max_steps0 = iteration_count(ctx, 0); - let max_steps1 = iteration_count(ctx, 1); - match value_count::() { - Some(count1) if count1 <= max_steps1 => { - let (iter0, steps0) = linear_ints(range0, max_steps0); - let iter = iter0 - .flat_map(move |first| all_values().map(move |second| (first, second))); - (EitherIter::A(iter), steps0.checked_mul(count1).unwrap()) - } - _ => { - let (iter0, steps0) = linear_ints(range0, max_steps0); - let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); - - let iter = iter0.flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = steps0.checked_mul(steps1).unwrap(); - - (EitherIter::B(iter), count) - } - } - } - } - - impl SpacedInput for ($fty, i32) - where - Op: MathOp, - { - fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, 0); - let range1 = int_range(ctx, 1); - let max_steps1 = iteration_count(ctx, 1); - match value_count::() { - Some(count0) if count0 <= max_steps0 => { - let (iter1, steps1) = linear_ints(range1, max_steps1); - let iter = all_values().flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - (EitherIter::A(iter), count0.checked_mul(steps1).unwrap()) - } - _ => { - let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); - let (iter1, steps1) = linear_ints(range1, max_steps1); - - let iter = iter0.flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = steps0.checked_mul(steps1).unwrap(); - - (EitherIter::B(iter), count) - } - } - } - } - }; -} - -#[cfg(f16_enabled)] -impl_spaced_input!(f16); -impl_spaced_input!(f32); -impl_spaced_input!(f64); -#[cfg(f128_enabled)] -impl_spaced_input!(f128); - -/// Create a test case iterator for extensive inputs. Also returns the total test case count. -pub fn get_test_cases( - ctx: &CheckCtx, -) -> (impl Iterator + Send + use<'_, Op>, u64) -where - Op: MathOp, - Op::RustArgs: SpacedInput, -{ - Op::RustArgs::get_cases(ctx) -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs deleted file mode 100644 index 485c01a4782..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ /dev/null @@ -1,105 +0,0 @@ -#![cfg_attr(f16_enabled, feature(f16))] -#![cfg_attr(f128_enabled, feature(f128))] -#![allow(clippy::unusual_byte_groupings)] // sometimes we group by sign_exp_sig - -pub mod domain; -mod f8_impl; -pub mod generate; -#[cfg(feature = "build-mpfr")] -pub mod mpfloat; -mod num; -pub mod op; -mod precision; -mod run_cfg; -mod test_traits; - -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; -use std::sync::LazyLock; -use std::time::SystemTime; - -pub use f8_impl::{f8, hf8}; -pub use libm::support::{Float, Int, IntTy, MinInt}; -pub use num::{FloatExt, linear_ints, logspace}; -pub use op::{ - BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustArgs, OpRustFn, OpRustRet, - Ty, -}; -pub use precision::{MaybeOverride, SpecialCase, default_ulp}; -use run_cfg::extensive_max_iterations; -pub use run_cfg::{ - CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, bigint_fuzz_iteration_count, - skip_extensive_test, -}; -pub use test_traits::{CheckOutput, Hex, TupleCall}; - -/// Result type for tests is usually from `anyhow`. Most times there is no success value to -/// propagate. -pub type TestResult = Result; - -/// True if `EMULATED` is set and nonempty. Used to determine how many iterations to run. -pub const fn emulated() -> bool { - match option_env!("EMULATED") { - Some(s) if s.is_empty() => false, - None => false, - Some(_) => true, - } -} - -/// True if `CI` is set and nonempty. -pub const fn ci() -> bool { - match option_env!("CI") { - Some(s) if s.is_empty() => false, - None => false, - Some(_) => true, - } -} - -/// Print to stderr and additionally log it to `target/test-log.txt`. This is useful for saving -/// output that would otherwise be consumed by the test harness. -pub fn test_log(s: &str) { - // Handle to a file opened in append mode, unless a suitable path can't be determined. - static OUTFILE: LazyLock> = LazyLock::new(|| { - // If the target directory is overridden, use that environment variable. Otherwise, save - // at the default path `{workspace_root}/target`. - let target_dir = match env::var("CARGO_TARGET_DIR") { - Ok(s) => PathBuf::from(s), - Err(_) => { - let Ok(x) = env::var("CARGO_MANIFEST_DIR") else { - return None; - }; - - PathBuf::from(x).parent().unwrap().parent().unwrap().join("target") - } - }; - let outfile = target_dir.join("test-log.txt"); - - let mut f = File::options() - .create(true) - .append(true) - .open(outfile) - .expect("failed to open logfile"); - let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); - - writeln!(f, "\n\nTest run at {}", now.as_secs()).unwrap(); - writeln!(f, "arch: {}", env::consts::ARCH).unwrap(); - writeln!(f, "os: {}", env::consts::OS).unwrap(); - writeln!(f, "bits: {}", usize::BITS).unwrap(); - writeln!(f, "emulated: {}", emulated()).unwrap(); - writeln!(f, "ci: {}", ci()).unwrap(); - writeln!(f, "cargo features: {}", env!("CFG_CARGO_FEATURES")).unwrap(); - writeln!(f, "opt level: {}", env!("CFG_OPT_LEVEL")).unwrap(); - writeln!(f, "target features: {}", env!("CFG_TARGET_FEATURES")).unwrap(); - writeln!(f, "extensive iterations {}", extensive_max_iterations()).unwrap(); - - Some(f) - }); - - eprintln!("{s}"); - - if let Some(mut f) = OUTFILE.as_ref() { - writeln!(f, "{s}").unwrap(); - } -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs deleted file mode 100644 index 9b51dc6051d..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ /dev/null @@ -1,603 +0,0 @@ -//! Interfaces needed to support testing with multi-precision floating point numbers. -//! -//! Within this module, the macros create a submodule for each `libm` function. These contain -//! a struct named `Operation` that implements [`MpOp`]. - -use std::cmp::Ordering; - -use rug::Assign; -pub use rug::Float as MpFloat; -use rug::az::{self, Az}; -use rug::float::Round::Nearest; -use rug::ops::{PowAssignRound, RemAssignRound}; - -use crate::{Float, MathOp}; - -/// Create a multiple-precision float with the correct number of bits for a concrete float type. -fn new_mpfloat() -> MpFloat { - MpFloat::new(F::SIG_BITS + 1) -} - -/// Set subnormal emulation and convert to a concrete float type. -fn prep_retval(mp: &mut MpFloat, ord: Ordering) -> F -where - for<'a> &'a MpFloat: az::Cast, -{ - mp.subnormalize_ieee_round(ord, Nearest); - (&*mp).az::() -} - -/// Structures that represent a float operation. -/// -pub trait MpOp: MathOp { - /// The struct itself should hold any context that can be reused among calls to `run` (allocated - /// `MpFloat`s). - type MpTy; - - /// Create a new instance. - fn new_mp() -> Self::MpTy; - - /// Perform the operation. - /// - /// Usually this means assigning inputs to cached floats, performing the operation, applying - /// subnormal approximation, and converting the result back to concrete values. - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet; -} - -/// Implement `MpOp` for functions with a single return value. -macro_rules! impl_mp_op { - // Matcher for unary functions - ( - fn_name: $fn_name:ident, - RustFn: fn($_fty:ty,) -> $_ret:ty, - attrs: [$($attr:meta),*], - fn_extra: $fn_name_normalized:expr, - ) => { - paste::paste! { - $(#[$attr])* - impl MpOp for crate::op::$fn_name::Routine { - type MpTy = MpFloat; - - fn new_mp() -> Self::MpTy { - new_mpfloat::() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.assign(input.0); - let ord = this.[< $fn_name_normalized _round >](Nearest); - prep_retval::(this, ord) - } - } - } - }; - // Matcher for binary functions - ( - fn_name: $fn_name:ident, - RustFn: fn($_fty:ty, $_fty2:ty,) -> $_ret:ty, - attrs: [$($attr:meta),*], - fn_extra: $fn_name_normalized:expr, - ) => { - paste::paste! { - $(#[$attr])* - impl MpOp for crate::op::$fn_name::Routine { - type MpTy = (MpFloat, MpFloat); - - fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0.assign(input.0); - this.1.assign(input.1); - let ord = this.0.[< $fn_name_normalized _round >](&this.1, Nearest); - prep_retval::(&mut this.0, ord) - } - } - } - }; - // Matcher for ternary functions - ( - fn_name: $fn_name:ident, - RustFn: fn($_fty:ty, $_fty2:ty, $_fty3:ty,) -> $_ret:ty, - attrs: [$($attr:meta),*], - fn_extra: $fn_name_normalized:expr, - ) => { - paste::paste! { - $(#[$attr])* - impl MpOp for crate::op::$fn_name::Routine { - type MpTy = (MpFloat, MpFloat, MpFloat); - - fn new_mp() -> Self::MpTy { - ( - new_mpfloat::(), - new_mpfloat::(), - new_mpfloat::(), - ) - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0.assign(input.0); - this.1.assign(input.1); - this.2.assign(input.2); - let ord = this.0.[< $fn_name_normalized _round >](&this.1, &this.2, Nearest); - prep_retval::(&mut this.0, ord) - } - } - } - }; -} - -libm_macros::for_each_function! { - callback: impl_mp_op, - emit_types: [RustFn], - skip: [ - // Most of these need a manual implementation - // verify-sorted-start - ceil, - ceilf, - ceilf128, - ceilf16, - copysign, - copysignf, - copysignf128, - copysignf16, - fabs, - fabsf, - fabsf128, - fabsf16,floor, - floorf, - floorf128, - floorf16, - fmaximum, - fmaximumf, - fmaximumf128, - fmaximumf16, - fminimum, - fminimumf, - fminimumf128, - fminimumf16, - fmod, - fmodf, - fmodf128, - fmodf16, - frexp, - frexpf, - ilogb, - ilogbf, - jn, - jnf, - ldexp, - ldexpf, - ldexpf128, - ldexpf16, - lgamma_r, - lgammaf_r, - modf, - modff, - nextafter, - nextafterf, - pow, - powf,remquo, - remquof, - rint, - rintf, - rintf128, - rintf16, - round, - roundeven, - roundevenf, - roundevenf128, - roundevenf16, - roundf, - roundf128, - roundf16, - scalbn, - scalbnf, - scalbnf128, - scalbnf16, - sincos,sincosf, - trunc, - truncf, - truncf128, - truncf16,yn, - ynf, - // verify-sorted-end - ], - fn_extra: match MACRO_FN_NAME { - // Remap function names that are different between mpfr and libm - expm1 | expm1f => exp_m1, - fabs | fabsf => abs, - fdim | fdimf | fdimf16 | fdimf128 => positive_diff, - fma | fmaf | fmaf128 => mul_add, - fmax | fmaxf | fmaxf16 | fmaxf128 | - fmaximum_num | fmaximum_numf | fmaximum_numf16 | fmaximum_numf128 => max, - fmin | fminf | fminf16 | fminf128 | - fminimum_num | fminimum_numf | fminimum_numf16 | fminimum_numf128 => min, - lgamma | lgammaf => ln_gamma, - log | logf => ln, - log1p | log1pf => ln_1p, - tgamma | tgammaf => gamma, - _ => MACRO_FN_NAME_NORMALIZED - } -} - -/// Implement unary functions that don't have a `_round` version -macro_rules! impl_no_round { - // Unary matcher - ($($fn_name:ident => $rug_name:ident;)*) => { - paste::paste! { - $( impl_no_round!{ @inner_unary $fn_name, $rug_name } )* - } - }; - - (@inner_unary $fn_name:ident, $rug_name:ident) => { - impl MpOp for crate::op::$fn_name::Routine { - type MpTy = MpFloat; - - fn new_mp() -> Self::MpTy { - new_mpfloat::() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.assign(input.0); - this.$rug_name(); - prep_retval::(this, Ordering::Equal) - } - } - }; -} - -impl_no_round! { - ceil => ceil_mut; - ceilf => ceil_mut; - fabs => abs_mut; - fabsf => abs_mut; - floor => floor_mut; - floorf => floor_mut; - rint => round_even_mut; // FIXME: respect rounding mode - rintf => round_even_mut; // FIXME: respect rounding mode - round => round_mut; - roundeven => round_even_mut; - roundevenf => round_even_mut; - roundf => round_mut; - trunc => trunc_mut; - truncf => trunc_mut; -} - -#[cfg(f16_enabled)] -impl_no_round! { - ceilf16 => ceil_mut; - fabsf16 => abs_mut; - floorf16 => floor_mut; - rintf16 => round_even_mut; // FIXME: respect rounding mode - roundf16 => round_mut; - roundevenf16 => round_even_mut; - truncf16 => trunc_mut; -} - -#[cfg(f128_enabled)] -impl_no_round! { - ceilf128 => ceil_mut; - fabsf128 => abs_mut; - floorf128 => floor_mut; - rintf128 => round_even_mut; // FIXME: respect rounding mode - roundf128 => round_mut; - roundevenf128 => round_even_mut; - truncf128 => trunc_mut; -} - -/// Some functions are difficult to do in a generic way. Implement them here. -macro_rules! impl_op_for_ty { - ($fty:ty, $suffix:literal) => { - paste::paste! { - impl MpOp for crate::op::[]::Routine { - type MpTy = (MpFloat, MpFloat); - - fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0.assign(input.0); - this.1.assign(&this.0); - let (ord0, ord1) = this.0.trunc_fract_round(&mut this.1, Nearest); - ( - prep_retval::(&mut this.1, ord0), - prep_retval::(&mut this.0, ord1), - ) - } - } - - impl MpOp for crate::op::[]::Routine { - type MpTy = (MpFloat, MpFloat); - - fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0.assign(input.0); - this.1.assign(input.1); - let ord = this.0.pow_assign_round(&this.1, Nearest); - prep_retval::(&mut this.0, ord) - } - } - - impl MpOp for crate::op::[]::Routine { - type MpTy = MpFloat; - - fn new_mp() -> Self::MpTy { - new_mpfloat::() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.assign(input.0); - let exp = this.frexp_mut(); - (prep_retval::(this, Ordering::Equal), exp) - } - } - - impl MpOp for crate::op::[]::Routine { - type MpTy = MpFloat; - - fn new_mp() -> Self::MpTy { - new_mpfloat::() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.assign(input.0); - - // `get_exp` follows `frexp` for `0.5 <= |m| < 1.0`. Adjust the exponent by - // one to scale the significand to `1.0 <= |m| < 2.0`. - this.get_exp().map(|v| v - 1).unwrap_or_else(|| { - if this.is_infinite() { - i32::MAX - } else { - // Zero or NaN - i32::MIN - } - }) - } - } - - impl MpOp for crate::op::[]::Routine { - type MpTy = MpFloat; - - fn new_mp() -> Self::MpTy { - new_mpfloat::() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - let (n, x) = input; - this.assign(x); - let ord = this.jn_round(n, Nearest); - prep_retval::(this, ord) - } - } - - impl MpOp for crate::op::[]::Routine { - type MpTy = (MpFloat, MpFloat); - - fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0.assign(input.0); - this.1.assign(0.0); - let (sord, cord) = this.0.sin_cos_round(&mut this.1, Nearest); - ( - prep_retval::(&mut this.0, sord), - prep_retval::(&mut this.1, cord) - ) - } - } - - impl MpOp for crate::op::[]::Routine { - type MpTy = (MpFloat, MpFloat); - - fn new_mp() -> Self::MpTy { - ( - new_mpfloat::(), - new_mpfloat::(), - ) - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0.assign(input.0); - this.1.assign(input.1); - let (ord, q) = this.0.remainder_quo31_round(&this.1, Nearest); - (prep_retval::(&mut this.0, ord), q) - } - } - - impl MpOp for crate::op::[]::Routine { - type MpTy = MpFloat; - - fn new_mp() -> Self::MpTy { - new_mpfloat::() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - let (n, x) = input; - this.assign(x); - let ord = this.yn_round(n, Nearest); - prep_retval::(this, ord) - } - } - } - }; -} - -/// Version of `impl_op_for_ty` with only functions that have `f16` and `f128` implementations. -macro_rules! impl_op_for_ty_all { - ($fty:ty, $suffix:literal) => { - paste::paste! { - impl MpOp for crate::op::[]::Routine { - type MpTy = (MpFloat, MpFloat); - - fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0.assign(input.0); - this.1.assign(input.1); - this.0.copysign_mut(&this.1); - prep_retval::(&mut this.0, Ordering::Equal) - } - } - - impl MpOp for crate::op::[]::Routine { - type MpTy = (MpFloat, MpFloat); - - fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0.assign(input.0); - this.1.assign(input.1); - let ord = this.0.rem_assign_round(&this.1, Nearest); - prep_retval::(&mut this.0, ord) - - } - } - - impl MpOp for crate::op::[< fmaximum $suffix >]::Routine { - type MpTy = (MpFloat, MpFloat); - - fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0.assign(input.0); - this.1.assign(input.1); - let ord = if this.0.is_nan() || this.1.is_nan() { - this.0.assign($fty::NAN); - Ordering::Equal - } else { - this.0.max_round(&this.1, Nearest) - }; - prep_retval::(&mut this.0, ord) - } - } - - impl MpOp for crate::op::[< fminimum $suffix >]::Routine { - type MpTy = (MpFloat, MpFloat); - - fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0.assign(input.0); - this.1.assign(input.1); - let ord = if this.0.is_nan() || this.1.is_nan() { - this.0.assign($fty::NAN); - Ordering::Equal - } else { - this.0.min_round(&this.1, Nearest) - }; - prep_retval::(&mut this.0, ord) - } - } - - // `ldexp` and `scalbn` are the same for binary floating point, so just forward all - // methods. - impl MpOp for crate::op::[]::Routine { - type MpTy = ]::Routine as MpOp>::MpTy; - - fn new_mp() -> Self::MpTy { - ]::Routine as MpOp>::new_mp() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - ]::Routine as MpOp>::run(this, input) - } - } - - impl MpOp for crate::op::[]::Routine { - type MpTy = MpFloat; - - fn new_mp() -> Self::MpTy { - new_mpfloat::() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.assign(input.0); - *this <<= input.1; - prep_retval::(this, Ordering::Equal) - } - } - } - }; -} - -impl_op_for_ty!(f32, "f"); -impl_op_for_ty!(f64, ""); - -#[cfg(f16_enabled)] -impl_op_for_ty_all!(f16, "f16"); -impl_op_for_ty_all!(f32, "f"); -impl_op_for_ty_all!(f64, ""); -#[cfg(f128_enabled)] -impl_op_for_ty_all!(f128, "f128"); - -// `lgamma_r` is not a simple suffix so we can't use the above macro. -impl MpOp for crate::op::lgamma_r::Routine { - type MpTy = MpFloat; - - fn new_mp() -> Self::MpTy { - new_mpfloat::() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.assign(input.0); - let (sign, ord) = this.ln_abs_gamma_round(Nearest); - let ret = prep_retval::(this, ord); - (ret, sign as i32) - } -} - -impl MpOp for crate::op::lgammaf_r::Routine { - type MpTy = MpFloat; - - fn new_mp() -> Self::MpTy { - new_mpfloat::() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.assign(input.0); - let (sign, ord) = this.ln_abs_gamma_round(Nearest); - let ret = prep_retval::(this, ord); - (ret, sign as i32) - } -} - -/* stub implementations so we don't need to special case them */ - -impl MpOp for crate::op::nextafter::Routine { - type MpTy = MpFloat; - - fn new_mp() -> Self::MpTy { - unimplemented!("nextafter does not yet have a MPFR operation"); - } - - fn run(_this: &mut Self::MpTy, _input: Self::RustArgs) -> Self::RustRet { - unimplemented!("nextafter does not yet have a MPFR operation"); - } -} - -impl MpOp for crate::op::nextafterf::Routine { - type MpTy = MpFloat; - - fn new_mp() -> Self::MpTy { - unimplemented!("nextafter does not yet have a MPFR operation"); - } - - fn run(_this: &mut Self::MpTy, _input: Self::RustArgs) -> Self::RustRet { - unimplemented!("nextafter does not yet have a MPFR operation"); - } -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num.rs b/library/compiler-builtins/libm/crates/libm-test/src/num.rs deleted file mode 100644 index eed941423d3..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/num.rs +++ /dev/null @@ -1,529 +0,0 @@ -//! Helpful numeric operations. - -use std::cmp::min; -use std::ops::RangeInclusive; - -use libm::support::Float; - -use crate::{Int, MinInt}; - -/// Extension to `libm`'s `Float` trait with methods that are useful for tests but not -/// needed in `libm` itself. -pub trait FloatExt: Float { - /// The minimum subnormal number. - const TINY_BITS: Self::Int = Self::Int::ONE; - - /// Retrieve additional constants for this float type. - fn consts() -> Consts { - Consts::new() - } - - /// Increment by one ULP, saturating at infinity. - fn next_up(self) -> Self { - let bits = self.to_bits(); - if self.is_nan() || bits == Self::INFINITY.to_bits() { - return self; - } - - let abs = self.abs().to_bits(); - let next_bits = if abs == Self::Int::ZERO { - // Next up from 0 is the smallest subnormal - Self::TINY_BITS - } else if bits == abs { - // Positive: counting up is more positive - bits + Self::Int::ONE - } else { - // Negative: counting down is more positive - bits - Self::Int::ONE - }; - Self::from_bits(next_bits) - } - - /// A faster way to effectively call `next_up` `n` times. - fn n_up(self, n: Self::Int) -> Self { - let bits = self.to_bits(); - if self.is_nan() || bits == Self::INFINITY.to_bits() || n == Self::Int::ZERO { - return self; - } - - let abs = self.abs().to_bits(); - let is_positive = bits == abs; - let crosses_zero = !is_positive && n > abs; - let inf_bits = Self::INFINITY.to_bits(); - - let next_bits = if abs == Self::Int::ZERO { - min(n, inf_bits) - } else if crosses_zero { - min(n - abs, inf_bits) - } else if is_positive { - // Positive, counting up is more positive but this may overflow - match bits.checked_add(n) { - Some(v) if v >= inf_bits => inf_bits, - Some(v) => v, - None => inf_bits, - } - } else { - // Negative, counting down is more positive - bits - n - }; - Self::from_bits(next_bits) - } - - /// Decrement by one ULP, saturating at negative infinity. - fn next_down(self) -> Self { - let bits = self.to_bits(); - if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() { - return self; - } - - let abs = self.abs().to_bits(); - let next_bits = if abs == Self::Int::ZERO { - // Next up from 0 is the smallest negative subnormal - Self::TINY_BITS | Self::SIGN_MASK - } else if bits == abs { - // Positive: counting down is more negative - bits - Self::Int::ONE - } else { - // Negative: counting up is more negative - bits + Self::Int::ONE - }; - Self::from_bits(next_bits) - } - - /// A faster way to effectively call `next_down` `n` times. - fn n_down(self, n: Self::Int) -> Self { - let bits = self.to_bits(); - if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() || n == Self::Int::ZERO { - return self; - } - - let abs = self.abs().to_bits(); - let is_positive = bits == abs; - let crosses_zero = is_positive && n > abs; - let inf_bits = Self::INFINITY.to_bits(); - let ninf_bits = Self::NEG_INFINITY.to_bits(); - - let next_bits = if abs == Self::Int::ZERO { - min(n, inf_bits) | Self::SIGN_MASK - } else if crosses_zero { - min(n - abs, inf_bits) | Self::SIGN_MASK - } else if is_positive { - // Positive, counting down is more negative - bits - n - } else { - // Negative, counting up is more negative but this may overflow - match bits.checked_add(n) { - Some(v) if v > ninf_bits => ninf_bits, - Some(v) => v, - None => ninf_bits, - } - }; - Self::from_bits(next_bits) - } -} - -impl FloatExt for F where F: Float {} - -/// Extra constants that are useful for tests. -#[derive(Debug, Clone, Copy)] -pub struct Consts { - /// The default quiet NaN, which is also the minimum quiet NaN. - pub pos_nan: F, - /// The default quiet NaN with negative sign. - pub neg_nan: F, - /// NaN with maximum (unsigned) significand to be a quiet NaN. The significand is saturated. - pub max_qnan: F, - /// NaN with minimum (unsigned) significand to be a signaling NaN. - pub min_snan: F, - /// NaN with maximum (unsigned) significand to be a signaling NaN. - pub max_snan: F, - pub neg_max_qnan: F, - pub neg_min_snan: F, - pub neg_max_snan: F, -} - -impl Consts { - fn new() -> Self { - let top_sigbit_mask = F::Int::ONE << (F::SIG_BITS - 1); - let pos_nan = F::EXP_MASK | top_sigbit_mask; - let max_qnan = F::EXP_MASK | F::SIG_MASK; - let min_snan = F::EXP_MASK | F::Int::ONE; - let max_snan = (F::EXP_MASK | F::SIG_MASK) ^ top_sigbit_mask; - - let neg_nan = pos_nan | F::SIGN_MASK; - let neg_max_qnan = max_qnan | F::SIGN_MASK; - let neg_min_snan = min_snan | F::SIGN_MASK; - let neg_max_snan = max_snan | F::SIGN_MASK; - - Self { - pos_nan: F::from_bits(pos_nan), - neg_nan: F::from_bits(neg_nan), - max_qnan: F::from_bits(max_qnan), - min_snan: F::from_bits(min_snan), - max_snan: F::from_bits(max_snan), - neg_max_qnan: F::from_bits(neg_max_qnan), - neg_min_snan: F::from_bits(neg_min_snan), - neg_max_snan: F::from_bits(neg_max_snan), - } - } - - pub fn iter(self) -> impl Iterator { - // Destructure so we get unused warnings if we forget a list entry. - let Self { - pos_nan, - neg_nan, - max_qnan, - min_snan, - max_snan, - neg_max_qnan, - neg_min_snan, - neg_max_snan, - } = self; - - [pos_nan, neg_nan, max_qnan, min_snan, max_snan, neg_max_qnan, neg_min_snan, neg_max_snan] - .into_iter() - } -} - -/// Return the number of steps between two floats, returning `None` if either input is NaN. -/// -/// This is the number of steps needed for `n_up` or `n_down` to go between values. Infinities -/// are treated the same as those functions (will return the nearest finite value), and only one -/// of `-0` or `+0` is counted. It does not matter which value is greater. -pub fn ulp_between(x: F, y: F) -> Option { - let a = as_ulp_steps(x)?; - let b = as_ulp_steps(y)?; - Some(a.abs_diff(b)) -} - -/// Return the (signed) number of steps from zero to `x`. -fn as_ulp_steps(x: F) -> Option { - let s = x.to_bits_signed(); - let val = if s >= F::SignedInt::ZERO { - // each increment from `s = 0` is one step up from `x = 0.0` - s - } else { - // each increment from `s = F::SignedInt::MIN` is one step down from `x = -0.0` - F::SignedInt::MIN - s - }; - - // If `x` is NaN, return `None` - (!x.is_nan()).then_some(val) -} - -/// An iterator that returns floats with linearly spaced integer representations, which translates -/// to logarithmic spacing of their values. -/// -/// Note that this tends to skip negative zero, so that needs to be checked explicitly. -/// -/// Returns `(iterator, iterator_length)`. -pub fn logspace( - start: F, - end: F, - steps: F::Int, -) -> (impl Iterator + Clone, F::Int) -where - RangeInclusive: Iterator, -{ - assert!(!start.is_nan()); - assert!(!end.is_nan()); - assert!(end >= start); - - let steps = steps.checked_sub(F::Int::ONE).expect("`steps` must be at least 2"); - let between = ulp_between(start, end).expect("`start` or `end` is NaN"); - let spacing = (between / steps).max(F::Int::ONE); - let steps = steps.min(between); // At maximum, one step per ULP - - let mut x = start; - ( - (F::Int::ZERO..=steps).map(move |_| { - let ret = x; - x = x.n_up(spacing); - ret - }), - steps + F::Int::ONE, - ) -} - -/// Returns an iterator of up to `steps` integers evenly distributed. -pub fn linear_ints( - range: RangeInclusive, - steps: u64, -) -> (impl Iterator + Clone, u64) { - let steps = steps.checked_sub(1).unwrap(); - let between = u64::from(range.start().abs_diff(*range.end())); - let spacing = i32::try_from((between / steps).max(1)).unwrap(); - let steps = steps.min(between); - let mut x: i32 = *range.start(); - ( - (0..=steps).map(move |_| { - let res = x; - // Wrapping add to avoid panic on last item (where `x` could overflow past i32::MAX as - // there is no next item). - x = x.wrapping_add(spacing); - res - }), - steps + 1, - ) -} - -#[cfg(test)] -mod tests { - use std::cmp::max; - - use super::*; - use crate::f8; - - #[test] - fn test_next_up_down() { - for (i, v) in f8::ALL.into_iter().enumerate() { - let down = v.next_down().to_bits(); - let up = v.next_up().to_bits(); - - if i == 0 { - assert_eq!(down, f8::NEG_INFINITY.to_bits(), "{i} next_down({v:#010b})"); - } else { - let expected = - if v == f8::ZERO { 1 | f8::SIGN_MASK } else { f8::ALL[i - 1].to_bits() }; - assert_eq!(down, expected, "{i} next_down({v:#010b})"); - } - - if i == f8::ALL_LEN - 1 { - assert_eq!(up, f8::INFINITY.to_bits(), "{i} next_up({v:#010b})"); - } else { - let expected = if v == f8::NEG_ZERO { 1 } else { f8::ALL[i + 1].to_bits() }; - assert_eq!(up, expected, "{i} next_up({v:#010b})"); - } - } - } - - #[test] - fn test_next_up_down_inf_nan() { - assert_eq!(f8::NEG_INFINITY.next_up().to_bits(), f8::ALL[0].to_bits(),); - assert_eq!(f8::NEG_INFINITY.next_down().to_bits(), f8::NEG_INFINITY.to_bits(),); - assert_eq!(f8::INFINITY.next_down().to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits(),); - assert_eq!(f8::INFINITY.next_up().to_bits(), f8::INFINITY.to_bits(),); - assert_eq!(f8::NAN.next_up().to_bits(), f8::NAN.to_bits(),); - assert_eq!(f8::NAN.next_down().to_bits(), f8::NAN.to_bits(),); - } - - #[test] - fn test_n_up_down_quick() { - assert_eq!(f8::ALL[0].n_up(4).to_bits(), f8::ALL[4].to_bits(),); - assert_eq!( - f8::ALL[f8::ALL_LEN - 1].n_down(4).to_bits(), - f8::ALL[f8::ALL_LEN - 5].to_bits(), - ); - - // Check around zero - assert_eq!(f8::from_bits(0b0).n_up(7).to_bits(), 0b0_0000_111); - assert_eq!(f8::from_bits(0b0).n_down(7).to_bits(), 0b1_0000_111); - - // Check across zero - assert_eq!(f8::from_bits(0b1_0000_111).n_up(8).to_bits(), 0b0_0000_001); - assert_eq!(f8::from_bits(0b0_0000_111).n_down(8).to_bits(), 0b1_0000_001); - } - - #[test] - fn test_n_up_down_one() { - // Verify that `n_up(1)` and `n_down(1)` are the same as `next_up()` and next_down()`.` - for i in 0..u8::MAX { - let v = f8::from_bits(i); - assert_eq!(v.next_up().to_bits(), v.n_up(1).to_bits()); - assert_eq!(v.next_down().to_bits(), v.n_down(1).to_bits()); - } - } - - #[test] - fn test_n_up_down_inf_nan_zero() { - assert_eq!(f8::NEG_INFINITY.n_up(1).to_bits(), f8::ALL[0].to_bits()); - assert_eq!(f8::NEG_INFINITY.n_up(239).to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits()); - assert_eq!(f8::NEG_INFINITY.n_up(240).to_bits(), f8::INFINITY.to_bits()); - assert_eq!(f8::NEG_INFINITY.n_down(u8::MAX).to_bits(), f8::NEG_INFINITY.to_bits()); - - assert_eq!(f8::INFINITY.n_down(1).to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits()); - assert_eq!(f8::INFINITY.n_down(239).to_bits(), f8::ALL[0].to_bits()); - assert_eq!(f8::INFINITY.n_down(240).to_bits(), f8::NEG_INFINITY.to_bits()); - assert_eq!(f8::INFINITY.n_up(u8::MAX).to_bits(), f8::INFINITY.to_bits()); - - assert_eq!(f8::NAN.n_up(u8::MAX).to_bits(), f8::NAN.to_bits()); - assert_eq!(f8::NAN.n_down(u8::MAX).to_bits(), f8::NAN.to_bits()); - - assert_eq!(f8::ZERO.n_down(1).to_bits(), f8::TINY_BITS | f8::SIGN_MASK); - assert_eq!(f8::NEG_ZERO.n_up(1).to_bits(), f8::TINY_BITS); - } - - /// True if the specified range of `f8::ALL` includes both +0 and -0 - fn crossed_zero(start: usize, end: usize) -> bool { - let crossed = &f8::ALL[start..=end]; - crossed.iter().any(|f| f8::eq_repr(*f, f8::ZERO)) - && crossed.iter().any(|f| f8::eq_repr(*f, f8::NEG_ZERO)) - } - - #[test] - fn test_n_up_down() { - for (i, v) in f8::ALL.into_iter().enumerate() { - for n in 0..f8::ALL_LEN { - let down = v.n_down(n as u8).to_bits(); - let up = v.n_up(n as u8).to_bits(); - - if let Some(down_exp_idx) = i.checked_sub(n) { - // No overflow - let mut expected = f8::ALL[down_exp_idx].to_bits(); - if n >= 1 && crossed_zero(down_exp_idx, i) { - // If both -0 and +0 are included, we need to adjust our expected value - match down_exp_idx.checked_sub(1) { - Some(v) => expected = f8::ALL[v].to_bits(), - // Saturate to -inf if we are out of values - None => expected = f8::NEG_INFINITY.to_bits(), - } - } - assert_eq!(down, expected, "{i} {n} n_down({v:#010b})"); - } else { - // Overflow to -inf - assert_eq!(down, f8::NEG_INFINITY.to_bits(), "{i} {n} n_down({v:#010b})"); - } - - let mut up_exp_idx = i + n; - if up_exp_idx < f8::ALL_LEN { - // No overflow - if n >= 1 && up_exp_idx < f8::ALL_LEN && crossed_zero(i, up_exp_idx) { - // If both -0 and +0 are included, we need to adjust our expected value - up_exp_idx += 1; - } - - let expected = if up_exp_idx >= f8::ALL_LEN { - f8::INFINITY.to_bits() - } else { - f8::ALL[up_exp_idx].to_bits() - }; - - assert_eq!(up, expected, "{i} {n} n_up({v:#010b})"); - } else { - // Overflow to +inf - assert_eq!(up, f8::INFINITY.to_bits(), "{i} {n} n_up({v:#010b})"); - } - } - } - } - - #[test] - fn test_ulp_between() { - for (i, x) in f8::ALL.into_iter().enumerate() { - for (j, y) in f8::ALL.into_iter().enumerate() { - let ulp = ulp_between(x, y).unwrap(); - let make_msg = || format!("i: {i} j: {j} x: {x:b} y: {y:b} ulp {ulp}"); - - let i_low = min(i, j); - let i_hi = max(i, j); - let mut expected = u8::try_from(i_hi - i_low).unwrap(); - if crossed_zero(i_low, i_hi) { - expected -= 1; - } - - assert_eq!(ulp, expected, "{}", make_msg()); - - // Skip if either are zero since `next_{up,down}` will count over it - let either_zero = x == f8::ZERO || y == f8::ZERO; - if x < y && !either_zero { - assert_eq!(x.n_up(ulp).to_bits(), y.to_bits(), "{}", make_msg()); - assert_eq!(y.n_down(ulp).to_bits(), x.to_bits(), "{}", make_msg()); - } else if !either_zero { - assert_eq!(y.n_up(ulp).to_bits(), x.to_bits(), "{}", make_msg()); - assert_eq!(x.n_down(ulp).to_bits(), y.to_bits(), "{}", make_msg()); - } - } - } - } - - #[test] - fn test_ulp_between_inf_nan_zero() { - assert_eq!(ulp_between(f8::NEG_INFINITY, f8::INFINITY).unwrap(), f8::ALL_LEN as u8); - assert_eq!(ulp_between(f8::INFINITY, f8::NEG_INFINITY).unwrap(), f8::ALL_LEN as u8); - assert_eq!( - ulp_between(f8::NEG_INFINITY, f8::ALL[f8::ALL_LEN - 1]).unwrap(), - f8::ALL_LEN as u8 - 1 - ); - assert_eq!(ulp_between(f8::INFINITY, f8::ALL[0]).unwrap(), f8::ALL_LEN as u8 - 1); - - assert_eq!(ulp_between(f8::ZERO, f8::NEG_ZERO).unwrap(), 0); - assert_eq!(ulp_between(f8::NAN, f8::ZERO), None); - assert_eq!(ulp_between(f8::ZERO, f8::NAN), None); - } - - #[test] - fn test_logspace() { - let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 2); - let ls: Vec<_> = ls.collect(); - let exp = [f8::from_bits(0x0), f8::from_bits(0x4)]; - assert_eq!(ls, exp); - assert_eq!(ls.len(), usize::from(count)); - - let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 3); - let ls: Vec<_> = ls.collect(); - let exp = [f8::from_bits(0x0), f8::from_bits(0x2), f8::from_bits(0x4)]; - assert_eq!(ls, exp); - assert_eq!(ls.len(), usize::from(count)); - - // Check that we include all values with no repeats if `steps` exceeds the maximum number - // of steps. - let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x3), 10); - let ls: Vec<_> = ls.collect(); - let exp = [f8::from_bits(0x0), f8::from_bits(0x1), f8::from_bits(0x2), f8::from_bits(0x3)]; - assert_eq!(ls, exp); - assert_eq!(ls.len(), usize::from(count)); - } - - #[test] - fn test_linear_ints() { - let (ints, count) = linear_ints(0..=4, 2); - let ints: Vec<_> = ints.collect(); - let exp = [0, 4]; - assert_eq!(ints, exp); - assert_eq!(ints.len(), usize::try_from(count).unwrap()); - - let (ints, count) = linear_ints(0..=4, 3); - let ints: Vec<_> = ints.collect(); - let exp = [0, 2, 4]; - assert_eq!(ints, exp); - assert_eq!(ints.len(), usize::try_from(count).unwrap()); - - // Check that we include all values with no repeats if `steps` exceeds the maximum number - // of steps. - let (ints, count) = linear_ints(0x0..=0x3, 10); - let ints: Vec<_> = ints.collect(); - let exp = [0, 1, 2, 3]; - assert_eq!(ints, exp); - assert_eq!(ints.len(), usize::try_from(count).unwrap()); - - // Check that there are no panics around `i32::MAX`. - let (ints, count) = linear_ints(i32::MAX - 1..=i32::MAX, 5); - let ints: Vec<_> = ints.collect(); - let exp = [i32::MAX - 1, i32::MAX]; - assert_eq!(ints, exp); - assert_eq!(ints.len(), usize::try_from(count).unwrap()); - } - - #[test] - fn test_consts() { - let Consts { - pos_nan, - neg_nan, - max_qnan, - min_snan, - max_snan, - neg_max_qnan, - neg_min_snan, - neg_max_snan, - } = f8::consts(); - - assert_eq!(pos_nan.to_bits(), 0b0_1111_100); - assert_eq!(neg_nan.to_bits(), 0b1_1111_100); - assert_eq!(max_qnan.to_bits(), 0b0_1111_111); - assert_eq!(min_snan.to_bits(), 0b0_1111_001); - assert_eq!(max_snan.to_bits(), 0b0_1111_011); - assert_eq!(neg_max_qnan.to_bits(), 0b1_1111_111); - assert_eq!(neg_min_snan.to_bits(), 0b1_1111_001); - assert_eq!(neg_max_snan.to_bits(), 0b1_1111_011); - } -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs deleted file mode 100644 index 47d72ae58b3..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ /dev/null @@ -1,151 +0,0 @@ -//! Types representing individual functions. -//! -//! Each routine gets a module with its name, e.g. `mod sinf { /* ... */ }`. The module -//! contains a unit struct `Routine` which implements `MathOp`. -//! -//! Basically everything could be called a "function" here, so we loosely use the following -//! terminology: -//! -//! - "Function": the math operation that does not have an associated precision. E.g. `f(x) = e^x`, -//! `f(x) = log(x)`. -//! - "Routine": A code implementation of a math operation with a specific precision. E.g. `exp`, -//! `expf`, `expl`, `log`, `logf`. -//! - "Operation" / "Op": Something that relates a routine to a function or is otherwise higher -//! level. `Op` is also used as the name for generic parameters since it is terse. - -use std::fmt; -use std::panic::{RefUnwindSafe, UnwindSafe}; - -pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; - -use crate::{CheckOutput, Float, TupleCall}; - -mod shared { - include!("../../libm-macros/src/shared.rs"); -} - -/// An enum representing each possible symbol name (`sin`, `sinf`, `sinl`, etc). -#[libm_macros::function_enum(BaseName)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Identifier {} - -impl fmt::Display for Identifier { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - -/// The name without any type specifier, e.g. `sin` and `sinf` both become `sin`. -#[libm_macros::base_name_enum] -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum BaseName {} - -impl fmt::Display for BaseName { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - -/// Attributes ascribed to a `libm` routine including signature, type information, -/// and naming. -pub trait MathOp { - /// The float type used for this operation. - type FTy: Float; - - /// The function type representing the signature in a C library. - type CFn: Copy; - - /// Arguments passed to the C library function as a tuple. These may include `&mut` return - /// values. - type CArgs<'a> - where - Self: 'a; - - /// The type returned by C implementations. - type CRet; - - /// The signature of the Rust function as a `fn(...) -> ...` type. - type RustFn: Copy + UnwindSafe; - - /// Arguments passed to the Rust library function as a tuple. - /// - /// The required `TupleCall` bounds ensure this type can be passed either to the C function or - /// to the Rust function. - type RustArgs: Copy - + TupleCall - + TupleCall - + RefUnwindSafe; - - /// Type returned from the Rust function. - type RustRet: CheckOutput; - - /// The name of this function, including suffix (e.g. `sin`, `sinf`). - const IDENTIFIER: Identifier; - - /// The name as a string. - const NAME: &'static str = Self::IDENTIFIER.as_str(); - - /// The name of the function excluding the type suffix, e.g. `sin` and `sinf` are both `sin`. - const BASE_NAME: BaseName = Self::IDENTIFIER.base_name(); - - /// The function in `libm` which can be called. - const ROUTINE: Self::RustFn; -} - -/// Access the associated `FTy` type from an op (helper to avoid ambiguous associated types). -pub type OpFTy = ::FTy; -/// Access the associated `FTy::Int` type from an op (helper to avoid ambiguous associated types). -pub type OpITy = <::FTy as Float>::Int; -/// Access the associated `CFn` type from an op (helper to avoid ambiguous associated types). -pub type OpCFn = ::CFn; -/// Access the associated `CRet` type from an op (helper to avoid ambiguous associated types). -pub type OpCRet = ::CRet; -/// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types). -pub type OpRustFn = ::RustFn; -/// Access the associated `RustArgs` type from an op (helper to avoid ambiguous associated types). -pub type OpRustArgs = ::RustArgs; -/// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). -pub type OpRustRet = ::RustRet; - -macro_rules! do_thing { - // Matcher for unary functions - ( - fn_name: $fn_name:ident, - FTy: $FTy:ty, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: $RustFn:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, - attrs: [$($attr:meta),*], - - ) => { - paste::paste! { - $(#[$attr])* - pub mod $fn_name { - use super::*; - pub struct Routine; - - impl MathOp for Routine { - type FTy = $FTy; - type CFn = for<'a> $CFn; - type CArgs<'a> = $CArgs where Self: 'a; - type CRet = $CRet; - type RustFn = $RustFn; - type RustArgs = $RustArgs; - type RustRet = $RustRet; - - const IDENTIFIER: Identifier = Identifier::[< $fn_name:camel >]; - const ROUTINE: Self::RustFn = libm::$fn_name; - } - } - - } - }; -} - -libm_macros::for_each_function! { - callback: do_thing, - emit_types: all, -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs deleted file mode 100644 index f5fb5f6707b..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ /dev/null @@ -1,573 +0,0 @@ -//! Configuration for skipping or changing the result for individual test cases (inputs) rather -//! than ignoring entire tests. - -use core::f32; - -use CheckBasis::{Mpfr, Musl}; -use libm::support::CastFrom; -use {BaseName as Bn, Identifier as Id}; - -use crate::{BaseName, CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; - -/// Type implementing [`IgnoreCase`]. -pub struct SpecialCase; - -/// ULP allowed to differ from the results returned by a test basis. -#[allow(clippy::single_match)] -pub fn default_ulp(ctx: &CheckCtx) -> u32 { - // ULP compared to the infinite (MPFR) result. - let mut ulp = match ctx.base_name { - // Operations that require exact results. This list should correlate with what we - // have documented at . - Bn::Ceil - | Bn::Copysign - | Bn::Fabs - | Bn::Fdim - | Bn::Floor - | Bn::Fma - | Bn::Fmax - | Bn::Fmaximum - | Bn::FmaximumNum - | Bn::Fmin - | Bn::Fminimum - | Bn::FminimumNum - | Bn::Fmod - | Bn::Frexp - | Bn::Ilogb - | Bn::Ldexp - | Bn::Modf - | Bn::Nextafter - | Bn::Remainder - | Bn::Remquo - | Bn::Rint - | Bn::Round - | Bn::Roundeven - | Bn::Scalbn - | Bn::Sqrt - | Bn::Trunc => 0, - - // Operations that aren't required to be exact, but our implementations are. - Bn::Cbrt => 0, - - // Bessel functions have large inaccuracies. - Bn::J0 | Bn::J1 | Bn::Y0 | Bn::Y1 | Bn::Jn | Bn::Yn => 8_000_000, - - // For all other operations, specify our implementation's worst case precision. - Bn::Acos => 1, - Bn::Acosh => 4, - Bn::Asin => 1, - Bn::Asinh => 2, - Bn::Atan => 1, - Bn::Atan2 => 2, - Bn::Atanh => 2, - Bn::Cos => 1, - Bn::Cosh => 1, - Bn::Erf => 1, - Bn::Erfc => 4, - Bn::Exp => 1, - Bn::Exp10 => 6, - Bn::Exp2 => 1, - Bn::Expm1 => 1, - Bn::Hypot => 1, - Bn::Lgamma | Bn::LgammaR => 16, - Bn::Log => 1, - Bn::Log10 => 1, - Bn::Log1p => 1, - Bn::Log2 => 1, - Bn::Pow => 1, - Bn::Sin => 1, - Bn::Sincos => 1, - Bn::Sinh => 2, - Bn::Tan => 1, - Bn::Tanh => 2, - // tgammaf has higher accuracy than tgamma. - Bn::Tgamma if ctx.fn_ident != Id::Tgamma => 1, - Bn::Tgamma => 20, - }; - - // There are some cases where musl's approximation is less accurate than ours. For these - // cases, increase the ULP. - if ctx.basis == Musl { - match ctx.base_name { - Bn::Cosh => ulp = 2, - Bn::Exp10 if usize::BITS < 64 => ulp = 4, - Bn::Lgamma | Bn::LgammaR => ulp = 400, - Bn::Tanh => ulp = 4, - _ => (), - } - - match ctx.fn_ident { - Id::Cbrt => ulp = 2, - // FIXME(#401): musl has an incorrect result here. - Id::Fdim => ulp = 2, - Id::Sincosf => ulp = 500, - Id::Tgamma => ulp = 20, - _ => (), - } - } - - if cfg!(target_arch = "x86") { - match ctx.fn_ident { - // Input `fma(0.999999999999999, 1.0000000000000013, 0.0) = 1.0000000000000002` is - // incorrect on i586 and i686. - Id::Fma => ulp = 1, - _ => (), - } - } - - // In some cases, our implementation is less accurate than musl on i586. - if cfg!(x86_no_sse) { - match ctx.fn_ident { - // FIXME(#401): these need to be correctly rounded but are not. - Id::Fmaf => ulp = 1, - Id::Fdim => ulp = 1, - Id::Round => ulp = 1, - - Id::Asinh => ulp = 3, - Id::Asinhf => ulp = 3, - Id::Cbrt => ulp = 1, - Id::Exp10 | Id::Exp10f => ulp = 1_000_000, - Id::Exp2 | Id::Exp2f => ulp = 10_000_000, - Id::Log1p | Id::Log1pf => ulp = 2, - Id::Tan => ulp = 2, - _ => (), - } - } - - ulp -} - -/// Result of checking for possible overrides. -#[derive(Debug, Default)] -pub enum CheckAction { - /// The check should pass. Default case. - #[default] - AssertSuccess, - - /// Override the ULP for this check. - AssertWithUlp(u32), - - /// Failure is expected, ensure this is the case (xfail). Takes a contxt string to help trace - /// back exactly why we expect this to fail. - AssertFailure(&'static str), - - /// The override somehow validated the result, here it is. - Custom(TestResult), - - /// Disregard the output. - Skip, -} - -/// Don't run further validation on this test case. -const SKIP: CheckAction = CheckAction::Skip; - -/// Return this to skip checks on a test that currently fails but shouldn't. Takes a description -/// of context. -const XFAIL: fn(&'static str) -> CheckAction = CheckAction::AssertFailure; - -/// Indicates that we expect a test to fail but we aren't asserting that it does (e.g. some results -/// within a range do actually pass). -/// -/// Same as `SKIP`, just indicates we have something to eventually fix. -const XFAIL_NOCHECK: CheckAction = CheckAction::Skip; - -/// By default, all tests should pass. -const DEFAULT: CheckAction = CheckAction::AssertSuccess; - -/// Allow overriding the outputs of specific test cases. -/// -/// There are some cases where we want to xfail specific cases or handle certain inputs -/// differently than the rest of calls to `validate`. This provides a hook to do that. -/// -/// If `None` is returned, checks will proceed as usual. If `Some(result)` is returned, checks -/// are skipped and the provided result is returned instead. -/// -/// This gets implemented once per input type, then the functions provide further filtering -/// based on function name and values. -/// -/// `ulp` can also be set to adjust the ULP for that specific test, even if `None` is still -/// returned. -pub trait MaybeOverride { - fn check_float( - _input: Input, - _actual: F, - _expected: F, - _ctx: &CheckCtx, - ) -> CheckAction { - DEFAULT - } - - fn check_int(_input: Input, _actual: I, _expected: I, _ctx: &CheckCtx) -> CheckAction { - DEFAULT - } -} - -#[cfg(f16_enabled)] -impl MaybeOverride<(f16,)> for SpecialCase {} - -impl MaybeOverride<(f32,)> for SpecialCase { - fn check_float(input: (f32,), actual: F, expected: F, ctx: &CheckCtx) -> CheckAction { - if ctx.base_name == BaseName::Expm1 - && !input.0.is_infinite() - && input.0 > 80.0 - && actual.is_infinite() - && !expected.is_infinite() - { - // we return infinity but the number is representable - if ctx.basis == CheckBasis::Musl { - return XFAIL_NOCHECK; - } - return XFAIL("expm1 representable numbers"); - } - - if cfg!(x86_no_sse) - && ctx.base_name == BaseName::Exp2 - && !expected.is_infinite() - && actual.is_infinite() - { - // We return infinity when there is a representable value. Test input: 127.97238 - return XFAIL("586 exp2 representable numbers"); - } - - if ctx.base_name == BaseName::Sinh && input.0.abs() > 80.0 && actual.is_nan() { - // we return some NaN that should be real values or infinite - if ctx.basis == CheckBasis::Musl { - return XFAIL_NOCHECK; - } - return XFAIL("sinh unexpected NaN"); - } - - if (ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR) - && input.0 > 4e36 - && expected.is_infinite() - && !actual.is_infinite() - { - // This result should saturate but we return a finite value. - return XFAIL_NOCHECK; - } - - if ctx.base_name == BaseName::J0 && input.0 < -1e34 { - // Errors get huge close to -inf - return XFAIL_NOCHECK; - } - - unop_common(input, actual, expected, ctx) - } - - fn check_int(input: (f32,), actual: I, expected: I, ctx: &CheckCtx) -> CheckAction { - // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR - // sets +1 - if ctx.basis == CheckBasis::Mpfr - && ctx.base_name == BaseName::LgammaR - && input.0 == f32::NEG_INFINITY - && actual.abs() == expected.abs() - { - return XFAIL("lgammar integer result"); - } - - DEFAULT - } -} - -impl MaybeOverride<(f64,)> for SpecialCase { - fn check_float(input: (f64,), actual: F, expected: F, ctx: &CheckCtx) -> CheckAction { - if cfg!(x86_no_sse) - && ctx.base_name == BaseName::Ceil - && ctx.basis == CheckBasis::Musl - && input.0 < 0.0 - && input.0 > -1.0 - && expected == F::ZERO - && actual == F::ZERO - { - // musl returns -0.0, we return +0.0 - return XFAIL("i586 ceil signed zero"); - } - - if cfg!(x86_no_sse) - && (ctx.base_name == BaseName::Rint || ctx.base_name == BaseName::Roundeven) - && (expected - actual).abs() <= F::ONE - && (expected - actual).abs() > F::ZERO - { - // Our rounding mode is incorrect. - return XFAIL("i586 rint rounding mode"); - } - - if cfg!(x86_no_sse) - && (ctx.fn_ident == Identifier::Ceil || ctx.fn_ident == Identifier::Floor) - && expected.eq_repr(F::NEG_ZERO) - && actual.eq_repr(F::ZERO) - { - // FIXME: the x87 implementations do not keep the distinction between -0.0 and 0.0. - // See https://github.com/rust-lang/libm/pull/404#issuecomment-2572399955 - return XFAIL("i586 ceil/floor signed zero"); - } - - if cfg!(x86_no_sse) - && (ctx.fn_ident == Identifier::Exp10 || ctx.fn_ident == Identifier::Exp2) - { - // FIXME: i586 has very imprecise results with ULP > u32::MAX for these - // operations so we can't reasonably provide a limit. - return XFAIL_NOCHECK; - } - - if ctx.base_name == BaseName::J0 && input.0 < -1e300 { - // Errors get huge close to -inf - return XFAIL_NOCHECK; - } - - // maybe_check_nan_bits(actual, expected, ctx) - unop_common(input, actual, expected, ctx) - } - - fn check_int(input: (f64,), actual: I, expected: I, ctx: &CheckCtx) -> CheckAction { - // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR - // sets +1 - if ctx.basis == CheckBasis::Mpfr - && ctx.base_name == BaseName::LgammaR - && input.0 == f64::NEG_INFINITY - && actual.abs() == expected.abs() - { - return XFAIL("lgammar integer result"); - } - - DEFAULT - } -} - -#[cfg(f128_enabled)] -impl MaybeOverride<(f128,)> for SpecialCase {} - -// F1 and F2 are always the same type, this is just to please generics -fn unop_common( - input: (F1,), - actual: F2, - expected: F2, - ctx: &CheckCtx, -) -> CheckAction { - if ctx.base_name == BaseName::Acosh - && input.0 < F1::NEG_ONE - && !(expected.is_nan() && actual.is_nan()) - { - // acoshf is undefined for x <= 1.0, but we return a random result at lower values. - - if ctx.basis == CheckBasis::Musl { - return XFAIL_NOCHECK; - } - - return XFAIL("acoshf undefined"); - } - - if (ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR) - && input.0 < F1::ZERO - && !input.0.is_infinite() - { - // loggamma should not be defined for x < 0, yet we both return results - return XFAIL_NOCHECK; - } - - // fabs and copysign must leave NaNs untouched. - if ctx.base_name == BaseName::Fabs && input.0.is_nan() { - // LLVM currently uses x87 instructions which quieten signalling NaNs to handle the i686 - // `extern "C"` `f32`/`f64` return ABI. - // LLVM issue - // Rust issue - if cfg!(target_arch = "x86") && ctx.basis == CheckBasis::Musl && actual.is_nan() { - return XFAIL_NOCHECK; - } - - // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. - if ctx.basis == CheckBasis::Mpfr { - return DEFAULT; - } - - // abs and copysign require signaling NaNs to be propagated, so verify bit equality. - if actual.to_bits() == expected.to_bits() { - return CheckAction::Custom(Ok(())); - } else { - return CheckAction::Custom(Err(anyhow::anyhow!("NaNs have different bitpatterns"))); - } - } - - DEFAULT -} - -#[cfg(f16_enabled)] -impl MaybeOverride<(f16, f16)> for SpecialCase { - fn check_float( - input: (f16, f16), - actual: F, - expected: F, - ctx: &CheckCtx, - ) -> CheckAction { - binop_common(input, actual, expected, ctx) - } -} - -impl MaybeOverride<(f32, f32)> for SpecialCase { - fn check_float( - input: (f32, f32), - actual: F, - expected: F, - ctx: &CheckCtx, - ) -> CheckAction { - binop_common(input, actual, expected, ctx) - } -} - -impl MaybeOverride<(f64, f64)> for SpecialCase { - fn check_float( - input: (f64, f64), - actual: F, - expected: F, - ctx: &CheckCtx, - ) -> CheckAction { - binop_common(input, actual, expected, ctx) - } -} - -#[cfg(f128_enabled)] -impl MaybeOverride<(f128, f128)> for SpecialCase { - fn check_float( - input: (f128, f128), - actual: F, - expected: F, - ctx: &CheckCtx, - ) -> CheckAction { - binop_common(input, actual, expected, ctx) - } -} - -// F1 and F2 are always the same type, this is just to please generics -fn binop_common( - input: (F1, F1), - actual: F2, - expected: F2, - ctx: &CheckCtx, -) -> CheckAction { - // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. Skip if - // the first input (magnitude source) is NaN and the output is also a NaN, or if the second - // input (sign source) is NaN. - if ctx.basis == CheckBasis::Mpfr - && ((input.0.is_nan() && actual.is_nan() && expected.is_nan()) || input.1.is_nan()) - { - return SKIP; - } - - /* FIXME(#439): our fmin and fmax do not compare signed zeros */ - - if ctx.base_name == BaseName::Fmin - && input.0.biteq(F1::NEG_ZERO) - && input.1.biteq(F1::ZERO) - && expected.biteq(F2::NEG_ZERO) - && actual.biteq(F2::ZERO) - { - return XFAIL("fmin signed zeroes"); - } - - if ctx.base_name == BaseName::Fmax - && input.0.biteq(F1::NEG_ZERO) - && input.1.biteq(F1::ZERO) - && expected.biteq(F2::ZERO) - && actual.biteq(F2::NEG_ZERO) - { - return XFAIL("fmax signed zeroes"); - } - - // Musl propagates NaNs if one is provided as the input, but we return the other input. - if (ctx.base_name == BaseName::Fmax || ctx.base_name == BaseName::Fmin) - && ctx.basis == Musl - && (input.0.is_nan() ^ input.1.is_nan()) - && expected.is_nan() - { - return XFAIL("fmax/fmin musl NaN"); - } - - DEFAULT -} - -impl MaybeOverride<(i32, f32)> for SpecialCase { - fn check_float( - input: (i32, f32), - actual: F, - expected: F, - ctx: &CheckCtx, - ) -> CheckAction { - // `ynf(213, 109.15641) = -inf` with our library, should be finite. - if ctx.basis == Mpfr - && ctx.base_name == BaseName::Yn - && input.0 > 200 - && !expected.is_infinite() - && actual.is_infinite() - { - return XFAIL("ynf infinity mismatch"); - } - - int_float_common(input, actual, expected, ctx) - } -} - -impl MaybeOverride<(i32, f64)> for SpecialCase { - fn check_float( - input: (i32, f64), - actual: F, - expected: F, - ctx: &CheckCtx, - ) -> CheckAction { - int_float_common(input, actual, expected, ctx) - } -} - -fn int_float_common( - input: (i32, F1), - actual: F2, - expected: F2, - ctx: &CheckCtx, -) -> CheckAction { - if ctx.basis == Mpfr - && (ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn) - && input.1 == F1::NEG_INFINITY - && actual == F2::ZERO - && expected == F2::ZERO - { - return XFAIL("we disagree with MPFR on the sign of zero"); - } - - // Values near infinity sometimes get cut off for us. `ynf(681, 509.90924) = -inf` but should - // be -3.2161271e38. - if ctx.basis == Musl - && ctx.fn_ident == Identifier::Ynf - && !expected.is_infinite() - && actual.is_infinite() - && (expected.abs().to_bits().abs_diff(actual.abs().to_bits()) - < F2::Int::cast_from(10_000_000u32)) - { - return XFAIL_NOCHECK; - } - - // Our bessel functions blow up with large N values - if ctx.basis == Musl && (ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn) { - if cfg!(x86_no_sse) { - // Precision is especially bad on i586, not worth checking. - return XFAIL_NOCHECK; - } - - if input.0 > 4000 { - return XFAIL_NOCHECK; - } else if input.0 > 100 { - return CheckAction::AssertWithUlp(1_000_000); - } - } - DEFAULT -} - -#[cfg(f16_enabled)] -impl MaybeOverride<(f16, i32)> for SpecialCase {} -impl MaybeOverride<(f32, i32)> for SpecialCase {} -impl MaybeOverride<(f64, i32)> for SpecialCase {} -#[cfg(f128_enabled)] -impl MaybeOverride<(f128, i32)> for SpecialCase {} - -impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} -impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} -#[cfg(f128_enabled)] -impl MaybeOverride<(f128, f128, f128)> for SpecialCase {} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs deleted file mode 100644 index b36164b005f..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ /dev/null @@ -1,370 +0,0 @@ -//! Configuration for how tests get run. - -use std::ops::RangeInclusive; -use std::sync::LazyLock; -use std::{env, str}; - -use crate::generate::random::{SEED, SEED_ENV}; -use crate::{BaseName, FloatTy, Identifier, test_log}; - -/// The environment variable indicating which extensive tests should be run. -pub const EXTENSIVE_ENV: &str = "LIBM_EXTENSIVE_TESTS"; - -/// Specify the number of iterations via this environment variable, rather than using the default. -pub const EXTENSIVE_ITER_ENV: &str = "LIBM_EXTENSIVE_ITERATIONS"; - -/// The override value, if set by the above environment. -static EXTENSIVE_ITER_OVERRIDE: LazyLock> = LazyLock::new(|| { - env::var(EXTENSIVE_ITER_ENV).map(|v| v.parse().expect("failed to parse iteration count")).ok() -}); - -/// Specific tests that need to have a reduced amount of iterations to complete in a reasonable -/// amount of time. -/// -/// Contains the itentifier+generator combo to match on, plus the factor to reduce by. -const EXTEMELY_SLOW_TESTS: &[(Identifier, GeneratorKind, u64)] = &[ - (Identifier::Fmodf128, GeneratorKind::QuickSpaced, 50), - (Identifier::Fmodf128, GeneratorKind::Extensive, 50), -]; - -/// Maximum number of iterations to run for a single routine. -/// -/// The default value of one greater than `u32::MAX` allows testing single-argument `f32` routines -/// and single- or double-argument `f16` routines exhaustively. `f64` and `f128` can't feasibly -/// be tested exhaustively; however, [`EXTENSIVE_ITER_ENV`] can be set to run tests for multiple -/// hours. -pub fn extensive_max_iterations() -> u64 { - let default = 1 << 32; // default value - EXTENSIVE_ITER_OVERRIDE.unwrap_or(default) -} - -/// Context passed to [`CheckOutput`]. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CheckCtx { - /// Allowed ULP deviation - pub ulp: u32, - pub fn_ident: Identifier, - pub base_name: BaseName, - /// Function name. - pub fn_name: &'static str, - /// Return the unsuffixed version of the function name. - pub base_name_str: &'static str, - /// Source of truth for tests. - pub basis: CheckBasis, - pub gen_kind: GeneratorKind, - /// If specified, this value will override the value returned by [`iteration_count`]. - pub override_iterations: Option, -} - -impl CheckCtx { - /// Create a new check context, using the default ULP for the function. - pub fn new(fn_ident: Identifier, basis: CheckBasis, gen_kind: GeneratorKind) -> Self { - let mut ret = Self { - ulp: 0, - fn_ident, - fn_name: fn_ident.as_str(), - base_name: fn_ident.base_name(), - base_name_str: fn_ident.base_name().as_str(), - basis, - gen_kind, - override_iterations: None, - }; - ret.ulp = crate::default_ulp(&ret); - ret - } - - /// The number of input arguments for this function. - pub fn input_count(&self) -> usize { - self.fn_ident.math_op().rust_sig.args.len() - } - - pub fn override_iterations(&mut self, count: u64) { - self.override_iterations = Some(count) - } -} - -/// Possible items to test against -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum CheckBasis { - /// Check against Musl's math sources. - Musl, - /// Check against infinite precision (MPFR). - Mpfr, - /// Benchmarks or other times when this is not relevant. - None, -} - -/// The different kinds of generators that provide test input, which account for input pattern -/// and quantity. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum GeneratorKind { - EdgeCases, - Extensive, - QuickSpaced, - Random, - List, -} - -/// A list of all functions that should get extensive tests. -/// -/// This also supports the special test name `all` to run all tests, as well as `all_f16`, -/// `all_f32`, `all_f64`, and `all_f128` to run all tests for a specific float type. -static EXTENSIVE: LazyLock> = LazyLock::new(|| { - let var = env::var(EXTENSIVE_ENV).unwrap_or_default(); - let list = var.split(",").filter(|s| !s.is_empty()).collect::>(); - let mut ret = Vec::new(); - - let append_ty_ops = |ret: &mut Vec<_>, fty: FloatTy| { - let iter = Identifier::ALL.iter().filter(move |id| id.math_op().float_ty == fty).copied(); - ret.extend(iter); - }; - - for item in list { - match item { - "all" => ret = Identifier::ALL.to_owned(), - "all_f16" => append_ty_ops(&mut ret, FloatTy::F16), - "all_f32" => append_ty_ops(&mut ret, FloatTy::F32), - "all_f64" => append_ty_ops(&mut ret, FloatTy::F64), - "all_f128" => append_ty_ops(&mut ret, FloatTy::F128), - s => { - let id = Identifier::from_str(s) - .unwrap_or_else(|| panic!("unrecognized test name `{s}`")); - ret.push(id); - } - } - } - - ret -}); - -/// Information about the function to be tested. -#[derive(Debug)] -struct TestEnv { - /// Tests should be reduced because the platform is slow. E.g. 32-bit or emulated. - slow_platform: bool, - /// The float cannot be tested exhaustively, `f64` or `f128`. - large_float_ty: bool, - /// Env indicates that an extensive test should be run. - should_run_extensive: bool, - /// Multiprecision tests will be run. - mp_tests_enabled: bool, - /// The number of inputs to the function. - input_count: usize, -} - -impl TestEnv { - fn from_env(ctx: &CheckCtx) -> Self { - let id = ctx.fn_ident; - let op = id.math_op(); - - let will_run_mp = cfg!(feature = "build-mpfr"); - let large_float_ty = match op.float_ty { - FloatTy::F16 | FloatTy::F32 => false, - FloatTy::F64 | FloatTy::F128 => true, - }; - - let will_run_extensive = EXTENSIVE.contains(&id); - - let input_count = op.rust_sig.args.len(); - - Self { - slow_platform: slow_platform(), - large_float_ty, - should_run_extensive: will_run_extensive, - mp_tests_enabled: will_run_mp, - input_count, - } - } -} - -/// Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run in QEMU. Start -/// with a reduced number on these platforms. -fn slow_platform() -> bool { - let slow_on_ci = crate::emulated() - || usize::BITS < 64 - || cfg!(all(target_arch = "x86_64", target_vendor = "apple")); - - // If not running in CI, there is no need to reduce iteration count. - slow_on_ci && crate::ci() -} - -/// The number of iterations to run for a given test. -pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { - let t_env = TestEnv::from_env(ctx); - - // Ideally run 5M tests - let mut domain_iter_count: u64 = 4_000_000; - - // Start with a reduced number of tests on slow platforms. - if t_env.slow_platform { - domain_iter_count = 100_000; - } - - // If we will be running tests against MPFR, we don't need to test as much against musl. - // However, there are some platforms where we have to test against musl since MPFR can't be - // built. - if t_env.mp_tests_enabled && ctx.basis == CheckBasis::Musl { - domain_iter_count /= 100; - } - - // Run fewer random tests than domain tests. - let random_iter_count = domain_iter_count / 100; - - let mut total_iterations = match ctx.gen_kind { - GeneratorKind::QuickSpaced => domain_iter_count, - GeneratorKind::Random => random_iter_count, - GeneratorKind::Extensive => extensive_max_iterations(), - GeneratorKind::EdgeCases | GeneratorKind::List => { - unimplemented!("shoudn't need `iteration_count` for {:?}", ctx.gen_kind) - } - }; - - // Larger float types get more iterations. - if t_env.large_float_ty && ctx.gen_kind != GeneratorKind::Extensive { - if ctx.gen_kind == GeneratorKind::Extensive { - // Extensive already has a pretty high test count. - total_iterations *= 2; - } else { - total_iterations *= 4; - } - } - - // Functions with more arguments get more iterations. - let arg_multiplier = 1 << (t_env.input_count - 1); - total_iterations *= arg_multiplier; - - // FMA has a huge domain but is reasonably fast to run, so increase another 1.5x. - if ctx.base_name == BaseName::Fma { - total_iterations = 3 * total_iterations / 2; - } - - // Some tests are significantly slower than others and need to be further reduced. - if let Some((_id, _gen, scale)) = EXTEMELY_SLOW_TESTS - .iter() - .find(|(id, generator, _scale)| *id == ctx.fn_ident && *generator == ctx.gen_kind) - { - // However, do not override if the extensive iteration count has been manually set. - if !(ctx.gen_kind == GeneratorKind::Extensive && EXTENSIVE_ITER_OVERRIDE.is_some()) { - total_iterations /= scale; - } - } - - if cfg!(optimizations_enabled) { - // Always run at least 10,000 tests. - total_iterations = total_iterations.max(10_000); - } else { - // Without optimizations, just run a quick check regardless of other parameters. - total_iterations = 800; - } - - let mut overridden = false; - if let Some(count) = ctx.override_iterations { - total_iterations = count; - overridden = true; - } - - // Adjust for the number of inputs - let ntests = match t_env.input_count { - 1 => total_iterations, - 2 => (total_iterations as f64).sqrt().ceil() as u64, - 3 => (total_iterations as f64).cbrt().ceil() as u64, - _ => panic!("test has more than three arguments"), - }; - - let total = ntests.pow(t_env.input_count.try_into().unwrap()); - - let seed_msg = match ctx.gen_kind { - GeneratorKind::QuickSpaced | GeneratorKind::Extensive => String::new(), - GeneratorKind::Random => { - format!(" using `{SEED_ENV}={}`", str::from_utf8(SEED.as_slice()).unwrap()) - } - GeneratorKind::EdgeCases | GeneratorKind::List => unimplemented!(), - }; - - test_log(&format!( - "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {ntests} iterations \ - ({total} total){seed_msg}{omsg}", - gen_kind = ctx.gen_kind, - basis = ctx.basis, - fn_ident = ctx.fn_ident, - arg = argnum + 1, - args = t_env.input_count, - omsg = if overridden { " (overridden)" } else { "" } - )); - - ntests -} - -/// Some tests require that an integer be kept within reasonable limits; generate that here. -pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { - let t_env = TestEnv::from_env(ctx); - - if !matches!(ctx.base_name, BaseName::Jn | BaseName::Yn) { - return i32::MIN..=i32::MAX; - } - - assert_eq!(argnum, 0, "For `jn`/`yn`, only the first argument takes an integer"); - - // The integer argument to `jn` is an iteration count. Limit this to ensure tests can be - // completed in a reasonable amount of time. - let non_extensive_range = if t_env.slow_platform || !cfg!(optimizations_enabled) { - (-0xf)..=0xff - } else { - (-0xff)..=0xffff - }; - - let extensive_range = (-0xfff)..=0xfffff; - - match ctx.gen_kind { - GeneratorKind::Extensive => extensive_range, - GeneratorKind::QuickSpaced | GeneratorKind::Random => non_extensive_range, - GeneratorKind::EdgeCases => extensive_range, - GeneratorKind::List => unimplemented!("shoudn't need range for {:?}", ctx.gen_kind), - } -} - -/// For domain tests, limit how many asymptotes or specified check points we test. -pub fn check_point_count(ctx: &CheckCtx) -> usize { - assert_eq!( - ctx.gen_kind, - GeneratorKind::EdgeCases, - "check_point_count is intended for edge case tests" - ); - let t_env = TestEnv::from_env(ctx); - if t_env.slow_platform || !cfg!(optimizations_enabled) { 4 } else { 10 } -} - -/// When validating points of interest (e.g. asymptotes, inflection points, extremes), also check -/// this many surrounding values. -pub fn check_near_count(ctx: &CheckCtx) -> u64 { - assert_eq!( - ctx.gen_kind, - GeneratorKind::EdgeCases, - "check_near_count is intended for edge case tests" - ); - if cfg!(optimizations_enabled) { - // Taper based on the number of inputs. - match ctx.input_count() { - 1 | 2 => 100, - 3 => 50, - x => panic!("unexpected argument count {x}"), - } - } else { - 8 - } -} - -/// Check whether extensive actions should be run or skipped. -pub fn skip_extensive_test(ctx: &CheckCtx) -> bool { - let t_env = TestEnv::from_env(ctx); - !t_env.should_run_extensive -} - -/// The number of iterations to run for `u256` fuzz tests. -pub fn bigint_fuzz_iteration_count() -> u64 { - if !cfg!(optimizations_enabled) { - return 1000; - } - - if slow_platform() { 100_000 } else { 5_000_000 } -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs deleted file mode 100644 index c560dade884..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ /dev/null @@ -1,447 +0,0 @@ -//! Traits related to testing. -//! -//! There are two main traits in this module: -//! -//! - `TupleCall`: implemented on tuples to allow calling them as function arguments. -//! - `CheckOutput`: implemented on anything that is an output type for validation against an -//! expected value. - -use std::panic::{RefUnwindSafe, UnwindSafe}; -use std::{fmt, panic}; - -use anyhow::{Context, anyhow, bail, ensure}; -use libm::support::Hexf; - -use crate::precision::CheckAction; -use crate::{ - CheckBasis, CheckCtx, Float, GeneratorKind, Int, MaybeOverride, SpecialCase, TestResult, -}; - -/// Trait for calling a function with a tuple as arguments. -/// -/// Implemented on the tuple with the function signature as the generic (so we can use the same -/// tuple for multiple signatures). -pub trait TupleCall: fmt::Debug { - type Output; - fn call(self, f: Func) -> Self::Output; - - /// Intercept panics and print the input to stderr before continuing. - fn call_intercept_panics(self, f: Func) -> Self::Output - where - Self: RefUnwindSafe + Copy, - Func: UnwindSafe, - { - let res = panic::catch_unwind(|| self.call(f)); - match res { - Ok(v) => v, - Err(e) => { - eprintln!("panic with the following input: {self:?}"); - panic::resume_unwind(e) - } - } - } -} - -/// A trait to implement on any output type so we can verify it in a generic way. -pub trait CheckOutput: Sized { - /// Validate `self` (actual) and `expected` are the same. - /// - /// `input` is only used here for error messages. - fn validate(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult; -} - -/// A helper trait to print something as hex with the correct number of nibbles, e.g. a `u32` -/// will always print with `0x` followed by 8 digits. -/// -/// This is only used for printing errors so allocating is okay. -pub trait Hex: Copy { - /// Hex integer syntax. - fn hex(self) -> String; - /// Hex float syntax. - fn hexf(self) -> String; -} - -/* implement `TupleCall` */ - -impl TupleCall R> for (T1,) -where - T1: fmt::Debug, -{ - type Output = R; - - fn call(self, f: fn(T1) -> R) -> Self::Output { - f(self.0) - } -} - -impl TupleCall R> for (T1, T2) -where - T1: fmt::Debug, - T2: fmt::Debug, -{ - type Output = R; - - fn call(self, f: fn(T1, T2) -> R) -> Self::Output { - f(self.0, self.1) - } -} - -impl TupleCall R> for (T1,) -where - T1: fmt::Debug, - T2: fmt::Debug + Default, -{ - type Output = (R, T2); - - fn call(self, f: fn(T1, &mut T2) -> R) -> Self::Output { - let mut t2 = T2::default(); - (f(self.0, &mut t2), t2) - } -} - -impl TupleCall R> for (T1, T2, T3) -where - T1: fmt::Debug, - T2: fmt::Debug, - T3: fmt::Debug, -{ - type Output = R; - - fn call(self, f: fn(T1, T2, T3) -> R) -> Self::Output { - f(self.0, self.1, self.2) - } -} - -impl TupleCall R> for (T1, T2) -where - T1: fmt::Debug, - T2: fmt::Debug, - T3: fmt::Debug + Default, -{ - type Output = (R, T3); - - fn call(self, f: fn(T1, T2, &mut T3) -> R) -> Self::Output { - let mut t3 = T3::default(); - (f(self.0, self.1, &mut t3), t3) - } -} - -impl TupleCall fn(T1, &'a mut T2, &'a mut T3)> for (T1,) -where - T1: fmt::Debug, - T2: fmt::Debug + Default, - T3: fmt::Debug + Default, -{ - type Output = (T2, T3); - - fn call(self, f: for<'a> fn(T1, &'a mut T2, &'a mut T3)) -> Self::Output { - let mut t2 = T2::default(); - let mut t3 = T3::default(); - f(self.0, &mut t2, &mut t3); - (t2, t3) - } -} - -/* implement `Hex` */ - -impl Hex for (T1,) -where - T1: Hex, -{ - fn hex(self) -> String { - format!("({},)", self.0.hex()) - } - - fn hexf(self) -> String { - format!("({},)", self.0.hexf()) - } -} - -impl Hex for (T1, T2) -where - T1: Hex, - T2: Hex, -{ - fn hex(self) -> String { - format!("({}, {})", self.0.hex(), self.1.hex()) - } - - fn hexf(self) -> String { - format!("({}, {})", self.0.hexf(), self.1.hexf()) - } -} - -impl Hex for (T1, T2, T3) -where - T1: Hex, - T2: Hex, - T3: Hex, -{ - fn hex(self) -> String { - format!("({}, {}, {})", self.0.hex(), self.1.hex(), self.2.hex()) - } - - fn hexf(self) -> String { - format!("({}, {}, {})", self.0.hexf(), self.1.hexf(), self.2.hexf()) - } -} - -/* trait implementations for ints */ - -macro_rules! impl_int { - ($($ty:ty),*) => { - $( - impl Hex for $ty { - fn hex(self) -> String { - format!("{self:#0width$x}", width = ((Self::BITS / 4) + 2) as usize) - } - - fn hexf(self) -> String { - String::new() - } - } - - impl $crate::CheckOutput for $ty - where - Input: Hex + fmt::Debug, - SpecialCase: MaybeOverride, - { - fn validate<'a>( - self, - expected: Self, - input: Input, - ctx: &$crate::CheckCtx, - ) -> TestResult { - validate_int(self, expected, input, ctx) - } - } - )* - }; -} - -fn validate_int(actual: I, expected: I, input: Input, ctx: &CheckCtx) -> TestResult -where - I: Int + Hex, - Input: Hex + fmt::Debug, - SpecialCase: MaybeOverride, -{ - let (result, xfail_msg) = match SpecialCase::check_int(input, actual, expected, ctx) { - // `require_biteq` forbids overrides. - _ if ctx.gen_kind == GeneratorKind::List => (actual == expected, None), - CheckAction::AssertSuccess => (actual == expected, None), - CheckAction::AssertFailure(msg) => (actual != expected, Some(msg)), - CheckAction::Custom(res) => return res, - CheckAction::Skip => return Ok(()), - CheckAction::AssertWithUlp(_) => panic!("ulp has no meaning for integer checks"), - }; - - let make_xfail_msg = || match xfail_msg { - Some(m) => format!( - "expected failure but test passed. Does an XFAIL need to be updated?\n\ - failed at: {m}", - ), - None => String::new(), - }; - - anyhow::ensure!( - result, - "\ - \n input: {input:?} {ibits}\ - \n expected: {expected:<22?} {expbits}\ - \n actual: {actual:<22?} {actbits}\ - \n {msg}\ - ", - actbits = actual.hex(), - expbits = expected.hex(), - ibits = input.hex(), - msg = make_xfail_msg() - ); - - Ok(()) -} - -impl_int!(u32, i32, u64, i64); - -/* trait implementations for floats */ - -macro_rules! impl_float { - ($($ty:ty),*) => { - $( - impl Hex for $ty { - fn hex(self) -> String { - format!( - "{:#0width$x}", - self.to_bits(), - width = ((Self::BITS / 4) + 2) as usize - ) - } - - fn hexf(self) -> String { - format!("{}", Hexf(self)) - } - } - - impl $crate::CheckOutput for $ty - where - Input: Hex + fmt::Debug, - SpecialCase: MaybeOverride, - { - fn validate<'a>( - self, - expected: Self, - input: Input, - ctx: &$crate::CheckCtx, - ) -> TestResult { - validate_float(self, expected, input, ctx) - } - } - )* - }; -} - -fn validate_float(actual: F, expected: F, input: Input, ctx: &CheckCtx) -> TestResult -where - F: Float + Hex, - Input: Hex + fmt::Debug, - u32: TryFrom, - SpecialCase: MaybeOverride, -{ - let mut assert_failure_msg = None; - - // Create a wrapper function so we only need to `.with_context` once. - let mut inner = || -> TestResult { - let mut allowed_ulp = ctx.ulp; - - // Forbid overrides if the items came from an explicit list, as long as we are checking - // against either MPFR or the result itself. - let require_biteq = ctx.gen_kind == GeneratorKind::List && ctx.basis != CheckBasis::Musl; - - match SpecialCase::check_float(input, actual, expected, ctx) { - _ if require_biteq => (), - CheckAction::AssertSuccess => (), - CheckAction::AssertFailure(msg) => assert_failure_msg = Some(msg), - CheckAction::Custom(res) => return res, - CheckAction::Skip => return Ok(()), - CheckAction::AssertWithUlp(ulp_override) => allowed_ulp = ulp_override, - }; - - // Check when both are NaNs - if actual.is_nan() && expected.is_nan() { - if require_biteq && ctx.basis == CheckBasis::None { - ensure!(actual.to_bits() == expected.to_bits(), "mismatched NaN bitpatterns"); - } - // By default, NaNs have nothing special to check. - return Ok(()); - } else if actual.is_nan() || expected.is_nan() { - // Check when only one is a NaN - bail!("real value != NaN") - } - - // Make sure that the signs are the same before checing ULP to avoid wraparound - let act_sig = actual.signum(); - let exp_sig = expected.signum(); - ensure!(act_sig == exp_sig, "mismatched signs {act_sig:?} {exp_sig:?}"); - - if actual.is_infinite() ^ expected.is_infinite() { - bail!("mismatched infinities"); - } - - let act_bits = actual.to_bits().signed(); - let exp_bits = expected.to_bits().signed(); - - let ulp_diff = act_bits.checked_sub(exp_bits).unwrap().abs(); - - let ulp_u32 = u32::try_from(ulp_diff) - .map_err(|e| anyhow!("{e:?}: ulp of {ulp_diff} exceeds u32::MAX"))?; - - ensure!(ulp_u32 <= allowed_ulp, "ulp {ulp_diff} > {allowed_ulp}",); - - Ok(()) - }; - - let mut res = inner(); - - if let Some(msg) = assert_failure_msg { - // Invert `Ok` and `Err` if the test is an xfail. - if res.is_ok() { - let e = anyhow!( - "expected failure but test passed. Does an XFAIL need to be updated?\n\ - failed at: {msg}", - ); - res = Err(e) - } else { - res = Ok(()) - } - } - - res.with_context(|| { - format!( - "\ - \n input: {input:?}\ - \n as hex: {ihex}\ - \n as bits: {ibits}\ - \n expected: {expected:<22?} {exphex} {expbits}\ - \n actual: {actual:<22?} {acthex} {actbits}\ - ", - ihex = input.hexf(), - ibits = input.hex(), - exphex = expected.hexf(), - expbits = expected.hex(), - actbits = actual.hex(), - acthex = actual.hexf(), - ) - }) -} - -impl_float!(f32, f64); - -#[cfg(f16_enabled)] -impl_float!(f16); - -#[cfg(f128_enabled)] -impl_float!(f128); - -/* trait implementations for compound types */ - -/// Implement `CheckOutput` for combinations of types. -macro_rules! impl_tuples { - ($(($a:ty, $b:ty);)*) => { - $( - impl CheckOutput for ($a, $b) - where - Input: Hex + fmt::Debug, - SpecialCase: MaybeOverride, - { - fn validate<'a>( - self, - expected: Self, - input: Input, - ctx: &CheckCtx, - ) -> TestResult { - self.0.validate(expected.0, input, ctx) - .and_then(|()| self.1.validate(expected.1, input, ctx)) - .with_context(|| format!( - "full context:\ - \n input: {input:?} {ibits}\ - \n as hex: {ihex}\ - \n as bits: {ibits}\ - \n expected: {expected:?} {expbits}\ - \n actual: {self:?} {actbits}\ - ", - ihex = input.hexf(), - ibits = input.hex(), - expbits = expected.hex(), - actbits = self.hex(), - )) - } - } - )* - }; -} - -impl_tuples!( - (f32, i32); - (f64, i32); - (f32, f32); - (f64, f64); -); diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs deleted file mode 100644 index c23298686fa..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Ensure that `for_each_function!` isn't missing any symbols. - -use std::collections::HashSet; -use std::env; -use std::path::Path; -use std::process::Command; - -macro_rules! callback { - ( - fn_name: $name:ident, - attrs: [$($attr:meta),*], - extra: [$set:ident], - ) => { - let name = stringify!($name); - let new = $set.insert(name); - assert!(new, "duplicate function `{name}` in `ALL_OPERATIONS`"); - }; -} - -#[test] -fn test_for_each_function_all_included() { - let all_functions: HashSet<_> = include_str!("../../../etc/function-list.txt") - .lines() - .filter(|line| !line.starts_with("#")) - .collect(); - - let mut tested = HashSet::new(); - - libm_macros::for_each_function! { - callback: callback, - extra: [tested], - }; - - let untested = all_functions.difference(&tested); - if untested.clone().next().is_some() { - panic!( - "missing tests for the following: {untested:#?} \ - \nmake sure any new functions are entered in \ - `ALL_OPERATIONS` (in `libm-macros`)." - ); - } - assert_eq!(all_functions, tested); -} - -#[test] -fn ensure_list_updated() { - if libm_test::ci() { - // Most CI tests run in Docker where we don't have Python or Rustdoc, so it's easiest - // to just run the python file directly when it is available. - eprintln!("skipping test; CI runs the python file directly"); - return; - } - - let res = Command::new("python3") - .arg(Path::new(env!("CARGO_MANIFEST_DIR")).join("../../etc/update-api-list.py")) - .arg("--check") - .status() - .unwrap(); - - assert!(res.success(), "May need to run `./etc/update-api-list.py`"); -} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs deleted file mode 100644 index cbb4bd49b9c..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ /dev/null @@ -1,143 +0,0 @@ -//! Compare our implementations with the result of musl functions, as provided by `musl-math-sys`. -//! -//! Currently this only tests randomized inputs. In the future this may be improved to test edge -//! cases or run exhaustive tests. -//! -//! Note that musl functions do not always provide 0.5ULP rounding, so our functions can do better -//! than these results. - -// There are some targets we can't build musl for -#![cfg(feature = "build-musl")] - -use libm_test::generate::{case_list, edge_cases, random, spaced}; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; - -const BASIS: CheckBasis = CheckBasis::Musl; - -fn musl_runner( - ctx: &CheckCtx, - cases: impl Iterator, - musl_fn: Op::CFn, -) { - for input in cases { - let musl_res = input.call(musl_fn); - let crate_res = input.call_intercept_panics(Op::ROUTINE); - - crate_res.validate(musl_res, input, ctx).unwrap(); - } -} - -/// Test against musl with generators from a domain. -macro_rules! musl_tests { - ( - fn_name: $fn_name:ident, - attrs: [$($attr:meta),*], - ) => { - paste::paste! { - #[test] - $(#[$attr])* - fn [< musl_case_list_ $fn_name >]() { - type Op = libm_test::op::$fn_name::Routine; - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::List); - let cases = case_list::get_test_cases_basis::(&ctx).0; - musl_runner::(&ctx, cases, musl_math_sys::$fn_name); - } - - #[test] - $(#[$attr])* - fn [< musl_random_ $fn_name >]() { - type Op = libm_test::op::$fn_name::Routine; - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Random); - let cases = random::get_test_cases::<::RustArgs>(&ctx).0; - musl_runner::(&ctx, cases, musl_math_sys::$fn_name); - } - - #[test] - $(#[$attr])* - fn [< musl_edge_case_ $fn_name >]() { - type Op = libm_test::op::$fn_name::Routine; - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::EdgeCases); - let cases = edge_cases::get_test_cases::(&ctx).0; - musl_runner::(&ctx, cases, musl_math_sys::$fn_name); - } - - #[test] - $(#[$attr])* - fn [< musl_quickspace_ $fn_name >]() { - type Op = libm_test::op::$fn_name::Routine; - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::QuickSpaced); - let cases = spaced::get_test_cases::(&ctx).0; - musl_runner::(&ctx, cases, musl_math_sys::$fn_name); - } - } - }; -} - -libm_macros::for_each_function! { - callback: musl_tests, - attributes: [], - skip: [ - // TODO integer inputs - jn, - jnf, - ldexp, - ldexpf, - scalbn, - scalbnf, - yn, - ynf, - - // Not provided by musl - // verify-sorted-start - ceilf128, - ceilf16, - copysignf128, - copysignf16, - fabsf128, - fabsf16, - fdimf128, - fdimf16, - floorf128, - floorf16, - fmaf128, - fmaxf128, - fmaxf16, - fmaximum, - fmaximum_num, - fmaximum_numf, - fmaximum_numf128, - fmaximum_numf16, - fmaximumf, - fmaximumf128, - fmaximumf16, - fminf128, - fminf16, - fminimum, - fminimum_num, - fminimum_numf, - fminimum_numf128, - fminimum_numf16, - fminimumf, - fminimumf128, - fminimumf16, - fmodf128, - fmodf16, - ldexpf128, - ldexpf16, - rintf128, - rintf16, - roundeven, - roundevenf, - roundevenf128, - roundevenf16, - roundf128, - roundf16, - scalbnf128, - scalbnf16, - sqrtf128, - sqrtf16, - truncf128, - truncf16, - // verify-sorted-end - ], -} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs deleted file mode 100644 index 80b2c78688e..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! Test with "infinite precision" - -#![cfg(feature = "build-mpfr")] - -use libm_test::generate::{case_list, edge_cases, random, spaced}; -use libm_test::mpfloat::MpOp; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; - -const BASIS: CheckBasis = CheckBasis::Mpfr; - -fn mp_runner(ctx: &CheckCtx, cases: impl Iterator) { - let mut mp_vals = Op::new_mp(); - for input in cases { - let mp_res = Op::run(&mut mp_vals, input); - let crate_res = input.call_intercept_panics(Op::ROUTINE); - - crate_res.validate(mp_res, input, ctx).unwrap(); - } -} - -macro_rules! mp_tests { - ( - fn_name: $fn_name:ident, - attrs: [$($attr:meta),*], - ) => { - paste::paste! { - #[test] - $(#[$attr])* - fn [< mp_case_list_ $fn_name >]() { - type Op = libm_test::op::$fn_name::Routine; - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::List); - let cases = case_list::get_test_cases_basis::(&ctx).0; - mp_runner::(&ctx, cases); - } - - #[test] - $(#[$attr])* - fn [< mp_random_ $fn_name >]() { - type Op = libm_test::op::$fn_name::Routine; - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Random); - let cases = random::get_test_cases::<::RustArgs>(&ctx).0; - mp_runner::(&ctx, cases); - } - - #[test] - $(#[$attr])* - fn [< mp_edge_case_ $fn_name >]() { - type Op = libm_test::op::$fn_name::Routine; - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::EdgeCases); - let cases = edge_cases::get_test_cases::(&ctx).0; - mp_runner::(&ctx, cases); - } - - #[test] - $(#[$attr])* - fn [< mp_quickspace_ $fn_name >]() { - type Op = libm_test::op::$fn_name::Routine; - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::QuickSpaced); - let cases = spaced::get_test_cases::(&ctx).0; - mp_runner::(&ctx, cases); - } - } - }; -} - -libm_macros::for_each_function! { - callback: mp_tests, - attributes: [ - // Also an assertion failure on i686: at `MPFR_ASSERTN (! mpfr_erangeflag_p ())` - #[ignore = "large values are infeasible in MPFR"] - [jn, jnf, yn, ynf], - ], - skip: [ - // FIXME: test needed, see - // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 - nextafter, - nextafterf, - ], -} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs b/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs deleted file mode 100644 index 7b30a3b48d7..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! Test cases that have both an input and an output, so do not require a basis. - -use libm_test::generate::case_list; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; - -const BASIS: CheckBasis = CheckBasis::None; - -fn standalone_runner( - ctx: &CheckCtx, - cases: impl Iterator, -) { - for (input, expected) in cases { - let crate_res = input.call_intercept_panics(Op::ROUTINE); - crate_res.validate(expected, input, ctx).unwrap(); - } -} - -macro_rules! mp_tests { - ( - fn_name: $fn_name:ident, - attrs: [$($attr:meta),*], - ) => { - paste::paste! { - #[test] - $(#[$attr])* - fn [< standalone_ $fn_name >]() { - type Op = libm_test::op::$fn_name::Routine; - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::List); - let cases = case_list::get_test_cases_standalone::(&ctx); - standalone_runner::(&ctx, cases); - } - } - }; -} - -libm_macros::for_each_function! { - callback: mp_tests, -} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs b/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs deleted file mode 100644 index 4444036d0a4..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs +++ /dev/null @@ -1,147 +0,0 @@ -//! Test the u256 implementation. the ops already get exercised reasonably well through the `f128` -//! routines, so this only does a few million fuzz iterations against GMP. - -#![cfg(feature = "build-mpfr")] - -use std::sync::LazyLock; - -use libm::support::{HInt, u256}; -type BigInt = rug::Integer; - -use libm_test::bigint_fuzz_iteration_count; -use libm_test::generate::random::SEED; -use rand::{Rng, SeedableRng}; -use rand_chacha::ChaCha8Rng; -use rug::Assign; -use rug::integer::Order; -use rug::ops::NotAssign; - -static BIGINT_U256_MAX: LazyLock = - LazyLock::new(|| BigInt::from_digits(&[u128::MAX, u128::MAX], Order::Lsf)); - -/// Copied from the test module. -fn hexu(v: u256) -> String { - format!("0x{:032x}{:032x}", v.hi, v.lo) -} - -fn random_u256(rng: &mut ChaCha8Rng) -> u256 { - let lo: u128 = rng.random(); - let hi: u128 = rng.random(); - u256 { lo, hi } -} - -fn assign_bigint(bx: &mut BigInt, x: u256) { - bx.assign_digits(&[x.lo, x.hi], Order::Lsf); -} - -fn from_bigint(bx: &mut BigInt) -> u256 { - // Truncate so the result fits into `[u128; 2]`. This makes all ops overflowing. - *bx &= &*BIGINT_U256_MAX; - let mut bres = [0u128, 0]; - bx.write_digits(&mut bres, Order::Lsf); - bx.assign(0); - u256 { lo: bres[0], hi: bres[1] } -} - -fn check_one( - x: impl FnOnce() -> String, - y: impl FnOnce() -> Option, - actual: u256, - expected: &mut BigInt, -) { - let expected = from_bigint(expected); - if actual != expected { - let xmsg = x(); - let ymsg = y().map(|y| format!("y: {y}\n")).unwrap_or_default(); - panic!( - "Results do not match\n\ - input: {xmsg}\n\ - {ymsg}\ - actual: {}\n\ - expected: {}\ - ", - hexu(actual), - hexu(expected), - ) - } -} - -#[test] -fn mp_u256_bitor() { - let mut rng = ChaCha8Rng::from_seed(*SEED); - let mut bx = BigInt::new(); - let mut by = BigInt::new(); - - for _ in 0..bigint_fuzz_iteration_count() { - let x = random_u256(&mut rng); - let y = random_u256(&mut rng); - assign_bigint(&mut bx, x); - assign_bigint(&mut by, y); - let actual = x | y; - bx |= &by; - check_one(|| hexu(x), || Some(hexu(y)), actual, &mut bx); - } -} - -#[test] -fn mp_u256_not() { - let mut rng = ChaCha8Rng::from_seed(*SEED); - let mut bx = BigInt::new(); - - for _ in 0..bigint_fuzz_iteration_count() { - let x = random_u256(&mut rng); - assign_bigint(&mut bx, x); - let actual = !x; - bx.not_assign(); - check_one(|| hexu(x), || None, actual, &mut bx); - } -} - -#[test] -fn mp_u256_add() { - let mut rng = ChaCha8Rng::from_seed(*SEED); - let mut bx = BigInt::new(); - let mut by = BigInt::new(); - - for _ in 0..bigint_fuzz_iteration_count() { - let x = random_u256(&mut rng); - let y = random_u256(&mut rng); - assign_bigint(&mut bx, x); - assign_bigint(&mut by, y); - let actual = x + y; - bx += &by; - check_one(|| hexu(x), || Some(hexu(y)), actual, &mut bx); - } -} - -#[test] -fn mp_u256_shr() { - let mut rng = ChaCha8Rng::from_seed(*SEED); - let mut bx = BigInt::new(); - - for _ in 0..bigint_fuzz_iteration_count() { - let x = random_u256(&mut rng); - let shift: u32 = rng.random_range(0..255); - assign_bigint(&mut bx, x); - let actual = x >> shift; - bx >>= shift; - check_one(|| hexu(x), || Some(shift.to_string()), actual, &mut bx); - } -} - -#[test] -fn mp_u256_widen_mul() { - let mut rng = ChaCha8Rng::from_seed(*SEED); - let mut bx = BigInt::new(); - let mut by = BigInt::new(); - - for _ in 0..bigint_fuzz_iteration_count() { - let x: u128 = rng.random(); - let y: u128 = rng.random(); - bx.assign(x); - by.assign(y); - let actual = x.widen_mul(y); - bx *= &by; - check_one(|| format!("{x:#034x}"), || Some(format!("{y:#034x}")), actual, &mut bx); - } -} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs deleted file mode 100644 index 5448cb6eaa5..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! `main` is just a wrapper to handle configuration. - -#[cfg(not(feature = "build-mpfr"))] -fn main() { - eprintln!("multiprecision not enabled; skipping extensive tests"); -} - -#[cfg(feature = "build-mpfr")] -mod run; - -#[cfg(feature = "build-mpfr")] -fn main() { - run::run(); -} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs deleted file mode 100644 index b10c231d183..00000000000 --- a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs +++ /dev/null @@ -1,233 +0,0 @@ -//! Exhaustive tests for `f16` and `f32`, high-iteration for `f64` and `f128`. - -use std::fmt; -use std::io::{self, IsTerminal}; -use std::sync::atomic::{AtomicU64, Ordering}; -use std::time::Duration; - -use indicatif::{ProgressBar, ProgressStyle}; -use libm_test::generate::spaced; -use libm_test::mpfloat::MpOp; -use libm_test::{ - CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TestResult, TupleCall, - skip_extensive_test, -}; -use libtest_mimic::{Arguments, Trial}; -use rayon::prelude::*; -use spaced::SpacedInput; - -const BASIS: CheckBasis = CheckBasis::Mpfr; -const GEN_KIND: GeneratorKind = GeneratorKind::Extensive; - -/// Run the extensive test suite. -pub fn run() { - let mut args = Arguments::from_args(); - // Prevent multiple tests from running in parallel, each test gets parallized internally. - args.test_threads = Some(1); - let tests = register_all_tests(); - - // With default parallelism, the CPU doesn't saturate. We don't need to be nice to - // other processes, so do 1.5x to make sure we use all available resources. - let threads = std::thread::available_parallelism().map(Into::into).unwrap_or(0) * 3 / 2; - rayon::ThreadPoolBuilder::new().num_threads(threads).build_global().unwrap(); - - libtest_mimic::run(&args, tests).exit(); -} - -macro_rules! mp_extensive_tests { - ( - fn_name: $fn_name:ident, - attrs: [$($attr:meta),*], - extra: [$push_to:ident], - ) => { - $(#[$attr])* - register_single_test::(&mut $push_to); - }; -} - -/// Create a list of tests for consumption by `libtest_mimic`. -fn register_all_tests() -> Vec { - let mut all_tests = Vec::new(); - - libm_macros::for_each_function! { - callback: mp_extensive_tests, - extra: [all_tests], - skip: [ - // FIXME: test needed, see - // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 - nextafter, - nextafterf, - ], - } - - all_tests -} - -/// Add a single test to the list. -fn register_single_test(all: &mut Vec) -where - Op: MathOp + MpOp, - Op::RustArgs: SpacedInput + Send, -{ - let test_name = format!("mp_extensive_{}", Op::NAME); - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GEN_KIND); - let skip = skip_extensive_test(&ctx); - - let runner = move || { - if !cfg!(optimizations_enabled) { - panic!("extensive tests should be run with --release"); - } - - let res = run_single_test::(&ctx); - let e = match res { - Ok(()) => return Ok(()), - Err(e) => e, - }; - - // Format with the `Debug` implementation so we get the error cause chain, and print it - // here so we see the result immediately (rather than waiting for all tests to conclude). - let e = format!("{e:?}"); - eprintln!("failure testing {}:{e}\n", Op::IDENTIFIER); - - Err(e.into()) - }; - - all.push(Trial::test(test_name, runner).with_ignored_flag(skip)); -} - -/// Test runner for a signle routine. -fn run_single_test(ctx: &CheckCtx) -> TestResult -where - Op: MathOp + MpOp, - Op::RustArgs: SpacedInput + Send, -{ - // Small delay before printing anything so other output from the runner has a chance to flush. - std::thread::sleep(Duration::from_millis(500)); - eprintln!(); - - let completed = AtomicU64::new(0); - let (ref mut cases, total) = spaced::get_test_cases::(ctx); - let pb = Progress::new(Op::NAME, total); - - let test_single_chunk = |mp_vals: &mut Op::MpTy, input_vec: Vec| -> TestResult { - for input in input_vec { - // Test the input. - let mp_res = Op::run(mp_vals, input); - let crate_res = input.call_intercept_panics(Op::ROUTINE); - crate_res.validate(mp_res, input, ctx)?; - - let completed = completed.fetch_add(1, Ordering::Relaxed) + 1; - pb.update(completed, input); - } - - Ok(()) - }; - - // Chunk the cases so Rayon doesn't switch threads between each iterator item. 50k seems near - // a performance sweet spot. Ideally we would reuse these allocations rather than discarding, - // but that is difficult with Rayon's API. - let chunk_size = 50_000; - let chunks = std::iter::from_fn(move || { - let mut v = Vec::with_capacity(chunk_size); - v.extend(cases.take(chunk_size)); - (!v.is_empty()).then_some(v) - }); - - // Run the actual tests - let res = chunks.par_bridge().try_for_each_init(Op::new_mp, test_single_chunk); - - let real_total = completed.load(Ordering::Relaxed); - pb.complete(real_total); - - if res.is_ok() && real_total != total { - // Provide a warning if our estimate needs to be updated. - panic!("total run {real_total} does not match expected {total}"); - } - - res -} - -/// Wrapper around a `ProgressBar` that handles styles and non-TTY messages. -struct Progress { - pb: ProgressBar, - name_padded: String, - final_style: ProgressStyle, - is_tty: bool, -} - -impl Progress { - const PB_TEMPLATE: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \ - {human_pos:>13}/{human_len:13} {per_sec:18} eta {eta:8} {msg}"; - const PB_TEMPLATE_FINAL: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \ - {human_pos:>13}/{human_len:13} {per_sec:18} done in {elapsed_precise}"; - - fn new(name: &str, total: u64) -> Self { - eprintln!("starting extensive tests for `{name}`"); - let name_padded = format!("{name:9}"); - let is_tty = io::stderr().is_terminal(); - - let initial_style = - ProgressStyle::with_template(&Self::PB_TEMPLATE.replace("NAME", &name_padded)) - .unwrap() - .progress_chars("##-"); - - let final_style = - ProgressStyle::with_template(&Self::PB_TEMPLATE_FINAL.replace("NAME", &name_padded)) - .unwrap() - .progress_chars("##-"); - - let pb = ProgressBar::new(total); - pb.set_style(initial_style); - - Self { pb, final_style, name_padded, is_tty } - } - - fn update(&self, completed: u64, input: impl fmt::Debug) { - // Infrequently update the progress bar. - if completed % 20_000 == 0 { - self.pb.set_position(completed); - } - - if completed % 500_000 == 0 { - self.pb.set_message(format!("input: {input:<24?}")); - } - - if !self.is_tty && completed % 5_000_000 == 0 { - let len = self.pb.length().unwrap_or_default(); - eprintln!( - "[{elapsed:3?}s {percent:3.0}%] {name} \ - {human_pos:>10}/{human_len:<10} {per_sec:14.2}/s eta {eta:4}s {input:<24?}", - elapsed = self.pb.elapsed().as_secs(), - percent = completed as f32 * 100.0 / len as f32, - name = self.name_padded, - human_pos = completed, - human_len = len, - per_sec = self.pb.per_sec(), - eta = self.pb.eta().as_secs() - ); - } - } - - fn complete(self, real_total: u64) { - self.pb.set_style(self.final_style); - self.pb.set_position(real_total); - self.pb.abandon(); - - if !self.is_tty { - let len = self.pb.length().unwrap_or_default(); - eprintln!( - "[{elapsed:3}s {percent:3.0}%] {name} \ - {human_pos:>10}/{human_len:<10} {per_sec:14.2}/s done in {elapsed_precise}", - elapsed = self.pb.elapsed().as_secs(), - percent = real_total as f32 * 100.0 / len as f32, - name = self.name_padded, - human_pos = real_total, - human_len = len, - per_sec = self.pb.per_sec(), - elapsed_precise = self.pb.elapsed().as_secs(), - ); - } - - eprintln!(); - } -} diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml deleted file mode 100644 index 9e866a9704f..00000000000 --- a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "musl-math-sys" -version = "0.1.0" -edition = "2024" -publish = false - -[dependencies] - -[dev-dependencies] -libm = { path = "../../libm" } - -[build-dependencies] -cc = "1.2.16" diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs deleted file mode 100644 index f06d84ee267..00000000000 --- a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs +++ /dev/null @@ -1,319 +0,0 @@ -use std::collections::BTreeMap; -use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; -use std::{env, fs, str}; - -/// Static library that will be built -const LIB_NAME: &str = "musl_math_prefixed"; - -/// Files that have more than one symbol. Map of file names to the symbols defined in that file. -const MULTIPLE_SYMBOLS: &[(&str, &[&str])] = &[ - ("__invtrigl", &["__invtrigl", "__invtrigl_R", "__pio2_hi", "__pio2_lo"]), - ("__polevll", &["__polevll", "__p1evll"]), - ("erf", &["erf", "erfc"]), - ("erff", &["erff", "erfcf"]), - ("erfl", &["erfl", "erfcl"]), - ("exp10", &["exp10", "pow10"]), - ("exp10f", &["exp10f", "pow10f"]), - ("exp10l", &["exp10l", "pow10l"]), - ("exp2f_data", &["exp2f_data", "__exp2f_data"]), - ("exp_data", &["exp_data", "__exp_data"]), - ("j0", &["j0", "y0"]), - ("j0f", &["j0f", "y0f"]), - ("j1", &["j1", "y1"]), - ("j1f", &["j1f", "y1f"]), - ("jn", &["jn", "yn"]), - ("jnf", &["jnf", "ynf"]), - ("lgamma", &["lgamma", "__lgamma_r"]), - ("remainder", &["remainder", "drem"]), - ("remainderf", &["remainderf", "dremf"]), - ("lgammaf", &["lgammaf", "lgammaf_r", "__lgammaf_r"]), - ("lgammal", &["lgammal", "lgammal_r", "__lgammal_r"]), - ("log2_data", &["log2_data", "__log2_data"]), - ("log2f_data", &["log2f_data", "__log2f_data"]), - ("log_data", &["log_data", "__log_data"]), - ("logf_data", &["logf_data", "__logf_data"]), - ("pow_data", &["pow_data", "__pow_log_data"]), - ("powf_data", &["powf_data", "__powf_log2_data"]), - ("signgam", &["signgam", "__signgam"]), - ("sqrt_data", &["sqrt_data", "__rsqrt_tab"]), -]; - -fn main() { - let cfg = Config::from_env(); - - if cfg.target_env == "msvc" - || cfg.target_family == "wasm" - || cfg.target_features.iter().any(|f| f == "thumb-mode") - { - println!( - "cargo::warning=Musl doesn't compile with the current \ - target {}; skipping build", - &cfg.target_string - ); - return; - } - - build_musl_math(&cfg); -} - -#[allow(dead_code)] -#[derive(Debug)] -struct Config { - manifest_dir: PathBuf, - out_dir: PathBuf, - musl_dir: PathBuf, - musl_arch: String, - target_arch: String, - target_env: String, - target_family: String, - target_os: String, - target_string: String, - target_vendor: String, - target_features: Vec, -} - -impl Config { - fn from_env() -> Self { - let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - let target_features = env::var("CARGO_CFG_TARGET_FEATURE") - .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) - .unwrap_or_default(); - let musl_dir = manifest_dir.join("musl"); - - let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - let musl_arch = if target_arch == "x86" { "i386".to_owned() } else { target_arch.clone() }; - - println!("cargo::rerun-if-changed={}/c_patches", manifest_dir.display()); - println!("cargo::rerun-if-changed={}", musl_dir.display()); - - Self { - manifest_dir, - out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), - musl_dir, - musl_arch, - target_arch, - target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), - target_family: env::var("CARGO_CFG_TARGET_FAMILY").unwrap(), - target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), - target_string: env::var("TARGET").unwrap(), - target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), - target_features, - } - } -} - -/// Build musl math symbols to a static library -fn build_musl_math(cfg: &Config) { - let musl_dir = &cfg.musl_dir; - let math = musl_dir.join("src/math"); - let arch_dir = musl_dir.join("arch").join(&cfg.musl_arch); - assert!(math.exists(), "musl source not found. Is the submodule up to date?"); - - let source_map = find_math_source(&math, cfg); - let out_path = cfg.out_dir.join(format!("lib{LIB_NAME}.a")); - - // Run configuration steps. Usually done as part of the musl `Makefile`. - let obj_include = cfg.out_dir.join("musl_obj/include"); - fs::create_dir_all(&obj_include).unwrap(); - fs::create_dir_all(obj_include.join("bits")).unwrap(); - let sed_stat = Command::new("sed") - .arg("-f") - .arg(musl_dir.join("tools/mkalltypes.sed")) - .arg(arch_dir.join("bits/alltypes.h.in")) - .arg(musl_dir.join("include/alltypes.h.in")) - .stderr(Stdio::inherit()) - .output() - .unwrap(); - assert!(sed_stat.status.success(), "sed command failed: {:?}", sed_stat.status); - - fs::write(obj_include.join("bits/alltypes.h"), sed_stat.stdout).unwrap(); - - let mut cbuild = cc::Build::new(); - cbuild - .extra_warnings(false) - .warnings(false) - .flag_if_supported("-Wno-bitwise-op-parentheses") - .flag_if_supported("-Wno-literal-range") - .flag_if_supported("-Wno-parentheses") - .flag_if_supported("-Wno-shift-count-overflow") - .flag_if_supported("-Wno-shift-op-parentheses") - .flag_if_supported("-Wno-unused-but-set-variable") - .flag_if_supported("-std=c99") - .flag_if_supported("-ffreestanding") - .flag_if_supported("-nostdinc") - .define("_ALL_SOURCE", "1") - .define( - "ROOT_INCLUDE_FEATURES", - Some(musl_dir.join("include/features.h").to_str().unwrap()), - ) - // Our overrides are in this directory - .include(cfg.manifest_dir.join("c_patches")) - .include(musl_dir.join("arch").join(&cfg.musl_arch)) - .include(musl_dir.join("arch/generic")) - .include(musl_dir.join("src/include")) - .include(musl_dir.join("src/internal")) - .include(obj_include) - .include(musl_dir.join("include")) - .file(cfg.manifest_dir.join("c_patches/alias.c")); - - for (sym_name, src_file) in source_map { - // Build the source file - cbuild.file(src_file); - - // Trickery! Redefine the symbol names to have the prefix `musl_`, which allows us to - // differentiate these symbols from whatever we provide. - if let Some((_names, syms)) = - MULTIPLE_SYMBOLS.iter().find(|(name, _syms)| *name == sym_name) - { - // Handle the occasional file that defines multiple symbols - for sym in *syms { - cbuild.define(sym, Some(format!("musl_{sym}").as_str())); - } - } else { - // If the file doesn't define multiple symbols, the file name will be the symbol - cbuild.define(&sym_name, Some(format!("musl_{sym_name}").as_str())); - } - } - - if cfg!(windows) { - // On Windows we don't have a good way to check symbols, so skip that step. - cbuild.compile(LIB_NAME); - return; - } - - let objfiles = cbuild.compile_intermediates(); - - // We create the archive ourselves with relocations rather than letting `cc` do it so we can - // encourage it to resolve symbols now. This should help avoid accidentally linking the wrong - // thing. - let stat = cbuild - .get_compiler() - .to_command() - .arg("-r") - .arg("-o") - .arg(&out_path) - .args(objfiles) - .status() - .unwrap(); - assert!(stat.success()); - - println!("cargo::rustc-link-lib={LIB_NAME}"); - println!("cargo::rustc-link-search=native={}", cfg.out_dir.display()); - - validate_archive_symbols(&out_path); -} - -/// Build a map of `name -> path`. `name` is typically the symbol name, but this doesn't account -/// for files that provide multiple symbols. -fn find_math_source(math_root: &Path, cfg: &Config) -> BTreeMap { - let mut map = BTreeMap::new(); - let mut arch_dir = None; - - // Locate all files and directories - for item in fs::read_dir(math_root).unwrap() { - let path = item.unwrap().path(); - let meta = fs::metadata(&path).unwrap(); - - if meta.is_dir() { - // Make note of the arch-specific directory if it exists - if path.file_name().unwrap() == cfg.target_arch.as_str() { - arch_dir = Some(path); - } - continue; - } - - // Skip non-source files - if path.extension().is_some_and(|ext| ext == "h") { - continue; - } - - let sym_name = path.file_stem().unwrap(); - map.insert(sym_name.to_str().unwrap().to_owned(), path.to_owned()); - } - - // If arch-specific versions are available, build those instead. - if let Some(arch_dir) = arch_dir { - for item in fs::read_dir(arch_dir).unwrap() { - let path = item.unwrap().path(); - let sym_name = path.file_stem().unwrap(); - - if path.extension().unwrap() == "s" { - // FIXME: we never build assembly versions since we have no good way to - // rename the symbol (our options are probably preprocessor or objcopy). - continue; - } - map.insert(sym_name.to_str().unwrap().to_owned(), path); - } - } - - map -} - -/// Make sure we don't have something like a loose unprefixed `_cos` called somewhere, which could -/// wind up linking to system libraries rather than the built musl library. -fn validate_archive_symbols(out_path: &Path) { - const ALLOWED_UNDEF_PFX: &[&str] = &[ - // PIC and arch-specific - ".TOC", - "_GLOBAL_OFFSET_TABLE_", - "__x86.get_pc_thunk", - // gcc/compiler-rt/compiler-builtins symbols - "__add", - "__aeabi_", - "__div", - "__eq", - "__extend", - "__fix", - "__float", - "__gcc_", - "__ge", - "__gt", - "__le", - "__lshr", - "__lt", - "__mul", - "__ne", - "__stack_chk_fail", - "__stack_chk_guard", - "__sub", - "__trunc", - "__undef", - // string routines - "__bzero", - "bzero", - // FPENV interfaces - "feclearexcept", - "fegetround", - "feraiseexcept", - "fesetround", - "fetestexcept", - ]; - - // List global undefined symbols - let out = - Command::new("nm").arg("-guj").arg(out_path).stderr(Stdio::inherit()).output().unwrap(); - - let undef = str::from_utf8(&out.stdout).unwrap(); - let mut undef = undef.lines().collect::>(); - undef.retain(|sym| { - // Account for file formats that add a leading `_` - !ALLOWED_UNDEF_PFX.iter().any(|pfx| sym.starts_with(pfx) || sym[1..].starts_with(pfx)) - }); - - assert!(undef.is_empty(), "found disallowed undefined symbols: {undef:#?}"); - - // Find any symbols that are missing the `_musl_` prefix` - let out = - Command::new("nm").arg("-gUj").arg(out_path).stderr(Stdio::inherit()).output().unwrap(); - - let defined = str::from_utf8(&out.stdout).unwrap(); - let mut defined = defined.lines().collect::>(); - defined.retain(|sym| { - !(sym.starts_with("_musl_") - || sym.starts_with("musl_") - || sym.starts_with("__x86.get_pc_thunk")) - }); - - assert!(defined.is_empty(), "found unprefixed symbols: {defined:#?}"); -} diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/alias.c b/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/alias.c deleted file mode 100644 index 63e0f08d5eb..00000000000 --- a/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/alias.c +++ /dev/null @@ -1,40 +0,0 @@ -/* On platforms that don't support weak symbols, define required aliases - * as wrappers. See comments in `features.h` for more. - */ -#if defined(__APPLE__) || defined(__MINGW32__) - -double __lgamma_r(double a, int *b); -float __lgammaf_r(float a, int *b); -long __lgammal_r(long double a, int *b); -double exp10(double a); -float exp10f(float a); -long exp10l(long double a); -double remainder(double a, double b); -float remainderf(float a, float b); - -double lgamma_r(double a, int *b) { - return __lgamma_r(a, b); -} -float lgammaf_r(float a, int *b) { - return __lgammaf_r(a, b); -} -long double lgammal_r(long double a, int *b) { - return __lgammal_r(a, b); -} -double pow10(double a) { - return exp10(a); -} -float pow10f(float a) { - return exp10f(a); -} -long double pow10l(long double a) { - return exp10l(a); -} -double drem(double a, double b) { - return remainder(a, b); -} -float dremf(float a, float b) { - return remainderf(a, b); -} - -#endif diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/features.h b/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/features.h deleted file mode 100644 index 97af935979a..00000000000 --- a/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/features.h +++ /dev/null @@ -1,39 +0,0 @@ -/* This is meant to override Musl's src/include/features.h - * - * We use a separate file here to redefine some attributes that don't work on - * all platforms that we would like to build on. - */ - -#ifndef FEATURES_H -#define FEATURES_H - -/* Get the required `#include "../../include/features.h"` since we can't use - * the relative path. The C macros need double indirection to get a usable - * string. */ -#define _stringify_inner(s) #s -#define _stringify(s) _stringify_inner(s) -#include _stringify(ROOT_INCLUDE_FEATURES) - -#if defined(__APPLE__) -#define weak __attribute__((__weak__)) -#define hidden __attribute__((__visibility__("hidden"))) - -/* We _should_ be able to define this as: - * _Pragma(_stringify(weak musl_ ## new = musl_ ## old)) - * However, weak symbols aren't handled correctly [1]. So we manually write - * wrappers, which are in `alias.c`. - * - * [1]: https://github.com/llvm/llvm-project/issues/111321 - */ -#define weak_alias(old, new) /* nothing */ - -#else -#define weak __attribute__((__weak__)) -#define hidden __attribute__((__visibility__("hidden"))) -#define weak_alias(old, new) \ - extern __typeof(old) musl_ ## new \ - __attribute__((__weak__, __alias__(_stringify(musl_ ## old)))) - -#endif /* defined(__APPLE__) */ - -#endif diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/musl b/library/compiler-builtins/libm/crates/musl-math-sys/musl deleted file mode 160000 index 61399d4bd02..00000000000 --- a/library/compiler-builtins/libm/crates/musl-math-sys/musl +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 61399d4bd02ae1ec03068445aa7ffe9174466bfd diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs deleted file mode 100644 index 6a4bf4859d9..00000000000 --- a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs +++ /dev/null @@ -1,287 +0,0 @@ -//! Bindings to Musl math functions (these are built in `build.rs`). - -use std::ffi::{c_char, c_int, c_long}; - -/// Macro for creating bindings and exposing a safe function (since the implementations have no -/// preconditions). Included functions must have correct signatures, otherwise this will be -/// unsound. -macro_rules! functions { - ( $( - $( #[$meta:meta] )* - $pfx_name:ident: $name:ident( $($arg:ident: $aty:ty),+ ) -> $rty:ty; - )* ) => { - unsafe extern "C" { - $( fn $pfx_name( $($arg: $aty),+ ) -> $rty; )* - } - - $( - // Expose a safe version - $( #[$meta] )* - pub fn $name( $($arg: $aty),+ ) -> $rty { - // SAFETY: FFI calls with no preconditions - unsafe { $pfx_name( $($arg),+ ) } - } - )* - - #[cfg(test)] - mod tests { - use super::*; - use test_support::CallTest; - - $( functions!( - @single_test - $name($($arg: $aty),+) -> $rty - ); )* - } - }; - - (@single_test - $name:ident( $($arg:ident: $aty:ty),+ ) -> $rty:ty - ) => { - // Run a simple check to ensure we can link and call the function without crashing. - #[test] - // FIXME(#309): LE PPC crashes calling some musl functions - #[cfg_attr(all(target_arch = "powerpc64", target_endian = "little"), ignore)] - fn $name() { - $rty>::check(super::$name); - } - }; -} - -#[cfg(test)] -mod test_support { - use core::ffi::c_char; - - /// Just verify that we are able to call the function. - pub trait CallTest { - fn check(f: Self); - } - - macro_rules! impl_calltest { - ($( ($($arg:ty),*) -> $ret:ty; )*) => { - $( - impl CallTest for fn($($arg),*) -> $ret { - fn check(f: Self) { - f($(1 as $arg),*); - } - } - )* - }; - } - - impl_calltest! { - (f32) -> f32; - (f64) -> f64; - (f32, f32) -> f32; - (f64, f64) -> f64; - (i32, f32) -> f32; - (i32, f64) -> f64; - (f32, f32, f32) -> f32; - (f64, f64, f64) -> f64; - (f32, i32) -> f32; - (f32, i64) -> f32; - (f32) -> i32; - (f64) -> i32; - (f64, i32) -> f64; - (f64, i64) -> f64; - } - - impl CallTest for fn(f32, &mut f32) -> f32 { - fn check(f: Self) { - let mut tmp = 0.0; - f(0.0, &mut tmp); - } - } - impl CallTest for fn(f64, &mut f64) -> f64 { - fn check(f: Self) { - let mut tmp = 0.0; - f(0.0, &mut tmp); - } - } - impl CallTest for fn(f32, &mut i32) -> f32 { - fn check(f: Self) { - let mut tmp = 1; - f(0.0, &mut tmp); - } - } - impl CallTest for fn(f64, &mut i32) -> f64 { - fn check(f: Self) { - let mut tmp = 1; - f(0.0, &mut tmp); - } - } - impl CallTest for fn(f32, f32, &mut i32) -> f32 { - fn check(f: Self) { - let mut tmp = 1; - f(0.0, 0.0, &mut tmp); - } - } - impl CallTest for fn(f64, f64, &mut i32) -> f64 { - fn check(f: Self) { - let mut tmp = 1; - f(0.0, 0.0, &mut tmp); - } - } - impl CallTest for fn(f32, &mut f32, &mut f32) { - fn check(f: Self) { - let mut tmp1 = 1.0; - let mut tmp2 = 1.0; - f(0.0, &mut tmp1, &mut tmp2); - } - } - impl CallTest for fn(f64, &mut f64, &mut f64) { - fn check(f: Self) { - let mut tmp1 = 1.0; - let mut tmp2 = 1.0; - f(0.0, &mut tmp1, &mut tmp2); - } - } - impl CallTest for fn(*const c_char) -> f32 { - fn check(f: Self) { - f(c"1".as_ptr()); - } - } - impl CallTest for fn(*const c_char) -> f64 { - fn check(f: Self) { - f(c"1".as_ptr()); - } - } -} - -functions! { - musl_acos: acos(a: f64) -> f64; - musl_acosf: acosf(a: f32) -> f32; - musl_acosh: acosh(a: f64) -> f64; - musl_acoshf: acoshf(a: f32) -> f32; - musl_asin: asin(a: f64) -> f64; - musl_asinf: asinf(a: f32) -> f32; - musl_asinh: asinh(a: f64) -> f64; - musl_asinhf: asinhf(a: f32) -> f32; - musl_atan2: atan2(a: f64, b: f64) -> f64; - musl_atan2f: atan2f(a: f32, b: f32) -> f32; - musl_atan: atan(a: f64) -> f64; - musl_atanf: atanf(a: f32) -> f32; - musl_atanh: atanh(a: f64) -> f64; - musl_atanhf: atanhf(a: f32) -> f32; - musl_cbrt: cbrt(a: f64) -> f64; - musl_cbrtf: cbrtf(a: f32) -> f32; - musl_ceil: ceil(a: f64) -> f64; - musl_ceilf: ceilf(a: f32) -> f32; - musl_copysign: copysign(a: f64, b: f64) -> f64; - musl_copysignf: copysignf(a: f32, b: f32) -> f32; - musl_cos: cos(a: f64) -> f64; - musl_cosf: cosf(a: f32) -> f32; - musl_cosh: cosh(a: f64) -> f64; - musl_coshf: coshf(a: f32) -> f32; - musl_drem: drem(a: f64, b: f64) -> f64; - musl_dremf: dremf(a: f32, b: f32) -> f32; - musl_erf: erf(a: f64) -> f64; - musl_erfc: erfc(a: f64) -> f64; - musl_erfcf: erfcf(a: f32) -> f32; - musl_erff: erff(a: f32) -> f32; - musl_exp10: exp10(a: f64) -> f64; - musl_exp10f: exp10f(a: f32) -> f32; - musl_exp2: exp2(a: f64) -> f64; - musl_exp2f: exp2f(a: f32) -> f32; - musl_exp: exp(a: f64) -> f64; - musl_expf: expf(a: f32) -> f32; - musl_expm1: expm1(a: f64) -> f64; - musl_expm1f: expm1f(a: f32) -> f32; - musl_fabs: fabs(a: f64) -> f64; - musl_fabsf: fabsf(a: f32) -> f32; - musl_fdim: fdim(a: f64, b: f64) -> f64; - musl_fdimf: fdimf(a: f32, b: f32) -> f32; - musl_finite: finite(a: f64) -> c_int; - musl_finitef: finitef(a: f32) -> c_int; - musl_floor: floor(a: f64) -> f64; - musl_floorf: floorf(a: f32) -> f32; - musl_fma: fma(a: f64, b: f64, c: f64) -> f64; - musl_fmaf: fmaf(a: f32, b: f32, c: f32) -> f32; - musl_fmax: fmax(a: f64, b: f64) -> f64; - musl_fmaxf: fmaxf(a: f32, b: f32) -> f32; - musl_fmin: fmin(a: f64, b: f64) -> f64; - musl_fminf: fminf(a: f32, b: f32) -> f32; - musl_fmod: fmod(a: f64, b: f64) -> f64; - musl_fmodf: fmodf(a: f32, b: f32) -> f32; - musl_frexp: frexp(a: f64, b: &mut c_int) -> f64; - musl_frexpf: frexpf(a: f32, b: &mut c_int) -> f32; - musl_hypot: hypot(a: f64, b: f64) -> f64; - musl_hypotf: hypotf(a: f32, b: f32) -> f32; - musl_ilogb: ilogb(a: f64) -> c_int; - musl_ilogbf: ilogbf(a: f32) -> c_int; - musl_j0: j0(a: f64) -> f64; - musl_j0f: j0f(a: f32) -> f32; - musl_j1: j1(a: f64) -> f64; - musl_j1f: j1f(a: f32) -> f32; - musl_jn: jn(a: c_int, b: f64) -> f64; - musl_jnf: jnf(a: c_int, b: f32) -> f32; - musl_ldexp: ldexp(a: f64, b: c_int) -> f64; - musl_ldexpf: ldexpf(a: f32, b: c_int) -> f32; - musl_lgamma: lgamma(a: f64) -> f64; - musl_lgamma_r: lgamma_r(a: f64, b: &mut c_int) -> f64; - musl_lgammaf: lgammaf(a: f32) -> f32; - musl_lgammaf_r: lgammaf_r(a: f32, b: &mut c_int) -> f32; - musl_log10: log10(a: f64) -> f64; - musl_log10f: log10f(a: f32) -> f32; - musl_log1p: log1p(a: f64) -> f64; - musl_log1pf: log1pf(a: f32) -> f32; - musl_log2: log2(a: f64) -> f64; - musl_log2f: log2f(a: f32) -> f32; - musl_log: log(a: f64) -> f64; - musl_logb: logb(a: f64) -> f64; - musl_logbf: logbf(a: f32) -> f32; - musl_logf: logf(a: f32) -> f32; - musl_modf: modf(a: f64, b: &mut f64) -> f64; - musl_modff: modff(a: f32, b: &mut f32) -> f32; - - // FIXME: these need to be unsafe - #[allow(clippy::not_unsafe_ptr_arg_deref)] - musl_nan: nan(a: *const c_char) -> f64; - #[allow(clippy::not_unsafe_ptr_arg_deref)] - musl_nanf: nanf(a: *const c_char) -> f32; - - musl_nearbyint: nearbyint(a: f64) -> f64; - musl_nearbyintf: nearbyintf(a: f32) -> f32; - musl_nextafter: nextafter(a: f64, b: f64) -> f64; - musl_nextafterf: nextafterf(a: f32, b: f32) -> f32; - musl_pow10: pow10(a: f64) -> f64; - musl_pow10f: pow10f(a: f32) -> f32; - musl_pow: pow(a: f64, b: f64) -> f64; - musl_powf: powf(a: f32, b: f32) -> f32; - musl_remainder: remainder(a: f64, b: f64) -> f64; - musl_remainderf: remainderf(a: f32, b: f32) -> f32; - musl_remquo: remquo(a: f64, b: f64, c: &mut c_int) -> f64; - musl_remquof: remquof(a: f32, b: f32, c: &mut c_int) -> f32; - musl_rint: rint(a: f64) -> f64; - musl_rintf: rintf(a: f32) -> f32; - musl_round: round(a: f64) -> f64; - musl_roundf: roundf(a: f32) -> f32; - musl_scalbln: scalbln(a: f64, b: c_long) -> f64; - musl_scalblnf: scalblnf(a: f32, b: c_long) -> f32; - musl_scalbn: scalbn(a: f64, b: c_int) -> f64; - musl_scalbnf: scalbnf(a: f32, b: c_int) -> f32; - musl_significand: significand(a: f64) -> f64; - musl_significandf: significandf(a: f32) -> f32; - musl_sin: sin(a: f64) -> f64; - musl_sincos: sincos(a: f64, b: &mut f64, c: &mut f64) -> (); - musl_sincosf: sincosf(a: f32, b: &mut f32, c: &mut f32) -> (); - musl_sinf: sinf(a: f32) -> f32; - musl_sinh: sinh(a: f64) -> f64; - musl_sinhf: sinhf(a: f32) -> f32; - musl_sqrt: sqrt(a: f64) -> f64; - musl_sqrtf: sqrtf(a: f32) -> f32; - musl_tan: tan(a: f64) -> f64; - musl_tanf: tanf(a: f32) -> f32; - musl_tanh: tanh(a: f64) -> f64; - musl_tanhf: tanhf(a: f32) -> f32; - musl_tgamma: tgamma(a: f64) -> f64; - musl_tgammaf: tgammaf(a: f32) -> f32; - musl_trunc: trunc(a: f64) -> f64; - musl_truncf: truncf(a: f32) -> f32; - musl_y0: y0(a: f64) -> f64; - musl_y0f: y0f(a: f32) -> f32; - musl_y1: y1(a: f64) -> f64; - musl_y1f: y1f(a: f32) -> f32; - musl_yn: yn(a: c_int, b: f64) -> f64; - musl_ynf: ynf(a: c_int, b: f32) -> f32; -} diff --git a/library/compiler-builtins/libm/crates/util/Cargo.toml b/library/compiler-builtins/libm/crates/util/Cargo.toml deleted file mode 100644 index 4bcb9747297..00000000000 --- a/library/compiler-builtins/libm/crates/util/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "util" -version = "0.1.0" -edition = "2024" -publish = false - -[features] -default = ["build-musl", "build-mpfr", "unstable-float"] -build-musl = ["libm-test/build-musl", "dep:musl-math-sys"] -build-mpfr = ["libm-test/build-mpfr", "dep:rug"] -unstable-float = ["libm/unstable-float", "libm-test/unstable-float", "rug?/nightly-float"] - -[dependencies] -libm = { path = "../../libm", default-features = false } -libm-macros = { path = "../libm-macros" } -libm-test = { path = "../libm-test", default-features = false } -musl-math-sys = { path = "../musl-math-sys", optional = true } -rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "std"] } diff --git a/library/compiler-builtins/libm/crates/util/build.rs b/library/compiler-builtins/libm/crates/util/build.rs deleted file mode 100644 index a1be4127527..00000000000 --- a/library/compiler-builtins/libm/crates/util/build.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![allow(unexpected_cfgs)] - -#[path = "../../libm/configure.rs"] -mod configure; - -fn main() { - println!("cargo:rerun-if-changed=../../libm/configure.rs"); - let cfg = configure::Config::from_env(); - configure::emit_libm_config(&cfg); -} diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs deleted file mode 100644 index ef70ec9035b..00000000000 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ /dev/null @@ -1,382 +0,0 @@ -//! Helper CLI utility for common tasks. - -#![cfg_attr(f16_enabled, feature(f16))] -#![cfg_attr(f128_enabled, feature(f128))] - -use std::any::type_name; -use std::env; -use std::num::ParseIntError; -use std::str::FromStr; - -use libm::support::{Hexf, hf32, hf64}; -#[cfg(feature = "build-mpfr")] -use libm_test::mpfloat::MpOp; -use libm_test::{MathOp, TupleCall}; -#[cfg(feature = "build-mpfr")] -use rug::az::{self, Az}; - -const USAGE: &str = "\ -usage: - -cargo run -p util -- - -SUBCOMMAND: - eval inputs... - Evaulate the expression with a given basis. This can be useful for - running routines with a debugger, or quickly checking input. Examples: - * eval musl sinf 1.234 # print the results of musl sinf(1.234f32) - * eval mpfr pow 1.234 2.432 # print the results of mpfr pow(1.234, 2.432) -"; - -fn main() { - let args = env::args().collect::>(); - let str_args = args.iter().map(|s| s.as_str()).collect::>(); - - match &str_args.as_slice()[1..] { - ["eval", basis, op, inputs @ ..] => do_eval(basis, op, inputs), - _ => { - println!("{USAGE}\nunrecognized input `{str_args:?}`"); - std::process::exit(1); - } - } -} - -macro_rules! handle_call { - ( - fn_name: $fn_name:ident, - CFn: $CFn:ty, - RustFn: $RustFn:ty, - RustArgs: $RustArgs:ty, - attrs: [$($attr:meta),*], - extra: ($basis:ident, $op:ident, $inputs:ident), - fn_extra: $musl_fn:expr, - ) => { - $(#[$attr])* - if $op == stringify!($fn_name) { - type Op = libm_test::op::$fn_name::Routine; - - let input = <$RustArgs>::parse($inputs); - let libm_fn: ::RustFn = libm::$fn_name; - - let output = match $basis { - "libm" => input.call_intercept_panics(libm_fn), - #[cfg(feature = "build-musl")] - "musl" => { - let musl_fn: ::CFn = - $musl_fn.unwrap_or_else(|| panic!("no musl function for {}", $op)); - input.call(musl_fn) - } - #[cfg(feature = "build-mpfr")] - "mpfr" => { - let mut mp = ::new_mp(); - Op::run(&mut mp, input) - } - _ => panic!("unrecognized or disabled basis '{}'", $basis), - }; - println!("{output:?} {:x}", Hexf(output)); - return; - } - }; -} - -/// Evaluate the specified operation with a given basis. -fn do_eval(basis: &str, op: &str, inputs: &[&str]) { - libm_macros::for_each_function! { - callback: handle_call, - emit_types: [CFn, RustFn, RustArgs], - extra: (basis, op, inputs), - fn_extra: match MACRO_FN_NAME { - ceilf128 - | ceilf16 - | copysignf128 - | copysignf16 - | fabsf128 - | fabsf16 - | fdimf128 - | fdimf16 - | floorf128 - | floorf16 - | fmaf128 - | fmaxf128 - | fmaxf16 - | fmaximum - | fmaximum_num - | fmaximum_numf - | fmaximum_numf128 - | fmaximum_numf16 - | fmaximumf - | fmaximumf128 - | fmaximumf16 - | fminf128 - | fminf16 - | fminimum - | fminimum_num - | fminimum_numf - | fminimum_numf128 - | fminimum_numf16 - | fminimumf - | fminimumf128 - | fminimumf16 - | fmodf128 - | fmodf16 - | ldexpf128 - | ldexpf16 - | rintf128 - | rintf16 - | roundeven - | roundevenf - | roundevenf128 - | roundevenf16 - | roundf128 - | roundf16 - | scalbnf128 - | scalbnf16 - | sqrtf128 - | sqrtf16 - | truncf128 - | truncf16 => None, - _ => Some(musl_math_sys::MACRO_FN_NAME) - } - } - - panic!("no operation matching {op}"); -} - -/// Parse a tuple from a space-delimited string. -trait ParseTuple { - fn parse(input: &[&str]) -> Self; -} - -macro_rules! impl_parse_tuple { - ($ty:ty) => { - impl ParseTuple for ($ty,) { - fn parse(input: &[&str]) -> Self { - assert_eq!(input.len(), 1, "expected a single argument, got {input:?}"); - (parse(input, 0),) - } - } - - impl ParseTuple for ($ty, $ty) { - fn parse(input: &[&str]) -> Self { - assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); - (parse(input, 0), parse(input, 1)) - } - } - - impl ParseTuple for ($ty, i32) { - fn parse(input: &[&str]) -> Self { - assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); - (parse(input, 0), parse(input, 1)) - } - } - - impl ParseTuple for (i32, $ty) { - fn parse(input: &[&str]) -> Self { - assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); - (parse(input, 0), parse(input, 1)) - } - } - - impl ParseTuple for ($ty, $ty, $ty) { - fn parse(input: &[&str]) -> Self { - assert_eq!(input.len(), 3, "expected three arguments, got {input:?}"); - (parse(input, 0), parse(input, 1), parse(input, 2)) - } - } - }; -} - -#[allow(unused_macros)] -#[cfg(feature = "build-mpfr")] -macro_rules! impl_parse_tuple_via_rug { - ($ty:ty) => { - impl ParseTuple for ($ty,) { - fn parse(input: &[&str]) -> Self { - assert_eq!(input.len(), 1, "expected a single argument, got {input:?}"); - (parse_rug(input, 0),) - } - } - - impl ParseTuple for ($ty, $ty) { - fn parse(input: &[&str]) -> Self { - assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); - (parse_rug(input, 0), parse_rug(input, 1)) - } - } - - impl ParseTuple for ($ty, i32) { - fn parse(input: &[&str]) -> Self { - assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); - (parse_rug(input, 0), parse(input, 1)) - } - } - - impl ParseTuple for (i32, $ty) { - fn parse(input: &[&str]) -> Self { - assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); - (parse(input, 0), parse_rug(input, 1)) - } - } - - impl ParseTuple for ($ty, $ty, $ty) { - fn parse(input: &[&str]) -> Self { - assert_eq!(input.len(), 3, "expected three arguments, got {input:?}"); - (parse_rug(input, 0), parse_rug(input, 1), parse_rug(input, 2)) - } - } - }; -} - -// Fallback for when Rug is not built. -#[allow(unused_macros)] -#[cfg(not(feature = "build-mpfr"))] -macro_rules! impl_parse_tuple_via_rug { - ($ty:ty) => { - impl ParseTuple for ($ty,) { - fn parse(_input: &[&str]) -> Self { - panic!("parsing this type requires the `build-mpfr` feature") - } - } - - impl ParseTuple for ($ty, $ty) { - fn parse(_input: &[&str]) -> Self { - panic!("parsing this type requires the `build-mpfr` feature") - } - } - - impl ParseTuple for ($ty, i32) { - fn parse(_input: &[&str]) -> Self { - panic!("parsing this type requires the `build-mpfr` feature") - } - } - - impl ParseTuple for (i32, $ty) { - fn parse(_input: &[&str]) -> Self { - panic!("parsing this type requires the `build-mpfr` feature") - } - } - - impl ParseTuple for ($ty, $ty, $ty) { - fn parse(_input: &[&str]) -> Self { - panic!("parsing this type requires the `build-mpfr` feature") - } - } - }; -} - -impl_parse_tuple!(f32); -impl_parse_tuple!(f64); - -#[cfg(f16_enabled)] -impl_parse_tuple_via_rug!(f16); -#[cfg(f128_enabled)] -impl_parse_tuple_via_rug!(f128); - -/// Try to parse the number, printing a nice message on failure. -fn parse(input: &[&str], idx: usize) -> T { - let s = input[idx]; - - let msg = || format!("invalid {} input '{s}'", type_name::()); - - if s.starts_with("0x") || s.starts_with("-0x") { - return T::from_str_radix(s, 16).unwrap_or_else(|_| panic!("{}", msg())); - } - - if s.starts_with("0b") { - return T::from_str_radix(s, 2).unwrap_or_else(|_| panic!("{}", msg())); - } - - s.parse().unwrap_or_else(|_| panic!("{}", msg())) -} - -/// Try to parse the float type going via `rug`, for `f16` and `f128` which don't yet implement -/// `FromStr`. -#[cfg(feature = "build-mpfr")] -fn parse_rug(input: &[&str], idx: usize) -> F -where - F: libm_test::Float + FromStrRadix, - rug::Float: az::Cast, -{ - let s = input[idx]; - - let msg = || format!("invalid {} input '{s}'", type_name::()); - - if s.starts_with("0x") { - return F::from_str_radix(s, 16).unwrap_or_else(|_| panic!("{}", msg())); - } - - if s.starts_with("0b") { - return F::from_str_radix(s, 2).unwrap_or_else(|_| panic!("{}", msg())); - } - - let x = rug::Float::parse(s).unwrap_or_else(|_| panic!("{}", msg())); - let x = rug::Float::with_val(F::BITS, x); - x.az() -} - -trait FromStrRadix: Sized { - fn from_str_radix(s: &str, radix: u32) -> Result; -} - -impl FromStrRadix for i32 { - fn from_str_radix(s: &str, radix: u32) -> Result { - let s = strip_radix_prefix(s, radix); - i32::from_str_radix(s, radix) - } -} - -#[cfg(f16_enabled)] -impl FromStrRadix for f16 { - fn from_str_radix(s: &str, radix: u32) -> Result { - if radix == 16 && s.contains("p") { - return Ok(libm::support::hf16(s)); - } - - let s = strip_radix_prefix(s, radix); - u16::from_str_radix(s, radix).map(Self::from_bits) - } -} - -impl FromStrRadix for f32 { - fn from_str_radix(s: &str, radix: u32) -> Result { - if radix == 16 && s.contains("p") { - // Parse as hex float - return Ok(hf32(s)); - } - - let s = strip_radix_prefix(s, radix); - u32::from_str_radix(s, radix).map(Self::from_bits) - } -} - -impl FromStrRadix for f64 { - fn from_str_radix(s: &str, radix: u32) -> Result { - if s.contains("p") { - return Ok(hf64(s)); - } - - let s = strip_radix_prefix(s, radix); - u64::from_str_radix(s, radix).map(Self::from_bits) - } -} - -#[cfg(f128_enabled)] -impl FromStrRadix for f128 { - fn from_str_radix(s: &str, radix: u32) -> Result { - if radix == 16 && s.contains("p") { - return Ok(libm::support::hf128(s)); - } - let s = strip_radix_prefix(s, radix); - u128::from_str_radix(s, radix).map(Self::from_bits) - } -} - -fn strip_radix_prefix(s: &str, radix: u32) -> &str { - if radix == 16 { - s.strip_prefix("0x").unwrap() - } else if radix == 2 { - s.strip_prefix("0b").unwrap() - } else { - s - } -} diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json deleted file mode 100644 index 3e33343c464..00000000000 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ /dev/null @@ -1,1069 +0,0 @@ -{ - "__comment": "Autogenerated by update-api-list.py. List of files that define a function with a given name. This file is checked in to make it obvious if refactoring breaks things", - "acos": { - "sources": [ - "libm/src/math/acos.rs" - ], - "type": "f64" - }, - "acosf": { - "sources": [ - "libm/src/math/acosf.rs" - ], - "type": "f32" - }, - "acosh": { - "sources": [ - "libm/src/math/acosh.rs" - ], - "type": "f64" - }, - "acoshf": { - "sources": [ - "libm/src/math/acoshf.rs" - ], - "type": "f32" - }, - "asin": { - "sources": [ - "libm/src/math/asin.rs" - ], - "type": "f64" - }, - "asinf": { - "sources": [ - "libm/src/math/asinf.rs" - ], - "type": "f32" - }, - "asinh": { - "sources": [ - "libm/src/math/asinh.rs" - ], - "type": "f64" - }, - "asinhf": { - "sources": [ - "libm/src/math/asinhf.rs" - ], - "type": "f32" - }, - "atan": { - "sources": [ - "libm/src/math/atan.rs" - ], - "type": "f64" - }, - "atan2": { - "sources": [ - "libm/src/math/atan2.rs" - ], - "type": "f64" - }, - "atan2f": { - "sources": [ - "libm/src/math/atan2f.rs" - ], - "type": "f32" - }, - "atanf": { - "sources": [ - "libm/src/math/atanf.rs" - ], - "type": "f32" - }, - "atanh": { - "sources": [ - "libm/src/math/atanh.rs" - ], - "type": "f64" - }, - "atanhf": { - "sources": [ - "libm/src/math/atanhf.rs" - ], - "type": "f32" - }, - "cbrt": { - "sources": [ - "libm/src/math/cbrt.rs" - ], - "type": "f64" - }, - "cbrtf": { - "sources": [ - "libm/src/math/cbrtf.rs" - ], - "type": "f32" - }, - "ceil": { - "sources": [ - "libm/src/math/arch/i586.rs", - "libm/src/math/arch/wasm32.rs", - "libm/src/math/ceil.rs", - "libm/src/math/generic/ceil.rs" - ], - "type": "f64" - }, - "ceilf": { - "sources": [ - "libm/src/math/arch/wasm32.rs", - "libm/src/math/ceil.rs", - "libm/src/math/generic/ceil.rs" - ], - "type": "f32" - }, - "ceilf128": { - "sources": [ - "libm/src/math/ceil.rs", - "libm/src/math/generic/ceil.rs" - ], - "type": "f128" - }, - "ceilf16": { - "sources": [ - "libm/src/math/ceil.rs", - "libm/src/math/generic/ceil.rs" - ], - "type": "f16" - }, - "copysign": { - "sources": [ - "libm/src/math/copysign.rs", - "libm/src/math/generic/copysign.rs" - ], - "type": "f64" - }, - "copysignf": { - "sources": [ - "libm/src/math/copysign.rs", - "libm/src/math/generic/copysign.rs" - ], - "type": "f32" - }, - "copysignf128": { - "sources": [ - "libm/src/math/copysign.rs", - "libm/src/math/generic/copysign.rs" - ], - "type": "f128" - }, - "copysignf16": { - "sources": [ - "libm/src/math/copysign.rs", - "libm/src/math/generic/copysign.rs" - ], - "type": "f16" - }, - "cos": { - "sources": [ - "libm/src/math/cos.rs" - ], - "type": "f64" - }, - "cosf": { - "sources": [ - "libm/src/math/cosf.rs" - ], - "type": "f32" - }, - "cosh": { - "sources": [ - "libm/src/math/cosh.rs" - ], - "type": "f64" - }, - "coshf": { - "sources": [ - "libm/src/math/coshf.rs" - ], - "type": "f32" - }, - "erf": { - "sources": [ - "libm/src/math/erf.rs" - ], - "type": "f64" - }, - "erfc": { - "sources": [ - "libm/src/math/erf.rs" - ], - "type": "f64" - }, - "erfcf": { - "sources": [ - "libm/src/math/erff.rs" - ], - "type": "f32" - }, - "erff": { - "sources": [ - "libm/src/math/erff.rs" - ], - "type": "f32" - }, - "exp": { - "sources": [ - "libm/src/math/exp.rs" - ], - "type": "f64" - }, - "exp10": { - "sources": [ - "libm/src/math/exp10.rs" - ], - "type": "f64" - }, - "exp10f": { - "sources": [ - "libm/src/math/exp10f.rs" - ], - "type": "f32" - }, - "exp2": { - "sources": [ - "libm/src/math/exp2.rs" - ], - "type": "f64" - }, - "exp2f": { - "sources": [ - "libm/src/math/exp2f.rs" - ], - "type": "f32" - }, - "expf": { - "sources": [ - "libm/src/math/expf.rs" - ], - "type": "f32" - }, - "expm1": { - "sources": [ - "libm/src/math/expm1.rs" - ], - "type": "f64" - }, - "expm1f": { - "sources": [ - "libm/src/math/expm1f.rs" - ], - "type": "f32" - }, - "fabs": { - "sources": [ - "libm/src/math/arch/wasm32.rs", - "libm/src/math/fabs.rs", - "libm/src/math/generic/fabs.rs" - ], - "type": "f64" - }, - "fabsf": { - "sources": [ - "libm/src/math/arch/wasm32.rs", - "libm/src/math/fabs.rs", - "libm/src/math/generic/fabs.rs" - ], - "type": "f32" - }, - "fabsf128": { - "sources": [ - "libm/src/math/fabs.rs", - "libm/src/math/generic/fabs.rs" - ], - "type": "f128" - }, - "fabsf16": { - "sources": [ - "libm/src/math/fabs.rs", - "libm/src/math/generic/fabs.rs" - ], - "type": "f16" - }, - "fdim": { - "sources": [ - "libm/src/math/fdim.rs", - "libm/src/math/generic/fdim.rs" - ], - "type": "f64" - }, - "fdimf": { - "sources": [ - "libm/src/math/fdim.rs", - "libm/src/math/generic/fdim.rs" - ], - "type": "f32" - }, - "fdimf128": { - "sources": [ - "libm/src/math/fdim.rs", - "libm/src/math/generic/fdim.rs" - ], - "type": "f128" - }, - "fdimf16": { - "sources": [ - "libm/src/math/fdim.rs", - "libm/src/math/generic/fdim.rs" - ], - "type": "f16" - }, - "floor": { - "sources": [ - "libm/src/math/arch/i586.rs", - "libm/src/math/arch/wasm32.rs", - "libm/src/math/floor.rs", - "libm/src/math/generic/floor.rs" - ], - "type": "f64" - }, - "floorf": { - "sources": [ - "libm/src/math/arch/wasm32.rs", - "libm/src/math/floor.rs", - "libm/src/math/generic/floor.rs" - ], - "type": "f32" - }, - "floorf128": { - "sources": [ - "libm/src/math/floor.rs", - "libm/src/math/generic/floor.rs" - ], - "type": "f128" - }, - "floorf16": { - "sources": [ - "libm/src/math/floor.rs", - "libm/src/math/generic/floor.rs" - ], - "type": "f16" - }, - "fma": { - "sources": [ - "libm/src/math/arch/aarch64.rs", - "libm/src/math/fma.rs" - ], - "type": "f64" - }, - "fmaf": { - "sources": [ - "libm/src/math/arch/aarch64.rs", - "libm/src/math/fma_wide.rs" - ], - "type": "f32" - }, - "fmaf128": { - "sources": [ - "libm/src/math/fma.rs" - ], - "type": "f128" - }, - "fmax": { - "sources": [ - "libm/src/math/fmin_fmax.rs", - "libm/src/math/generic/fmax.rs" - ], - "type": "f64" - }, - "fmaxf": { - "sources": [ - "libm/src/math/fmin_fmax.rs", - "libm/src/math/generic/fmax.rs" - ], - "type": "f32" - }, - "fmaxf128": { - "sources": [ - "libm/src/math/fmin_fmax.rs", - "libm/src/math/generic/fmax.rs" - ], - "type": "f128" - }, - "fmaxf16": { - "sources": [ - "libm/src/math/fmin_fmax.rs", - "libm/src/math/generic/fmax.rs" - ], - "type": "f16" - }, - "fmaximum": { - "sources": [ - "libm/src/math/fminimum_fmaximum.rs", - "libm/src/math/generic/fmaximum.rs" - ], - "type": "f64" - }, - "fmaximum_num": { - "sources": [ - "libm/src/math/fminimum_fmaximum_num.rs", - "libm/src/math/generic/fmaximum_num.rs" - ], - "type": "f64" - }, - "fmaximum_numf": { - "sources": [ - "libm/src/math/fminimum_fmaximum_num.rs", - "libm/src/math/generic/fmaximum_num.rs" - ], - "type": "f32" - }, - "fmaximum_numf128": { - "sources": [ - "libm/src/math/fminimum_fmaximum_num.rs", - "libm/src/math/generic/fmaximum_num.rs" - ], - "type": "f128" - }, - "fmaximum_numf16": { - "sources": [ - "libm/src/math/fminimum_fmaximum_num.rs", - "libm/src/math/generic/fmaximum_num.rs" - ], - "type": "f16" - }, - "fmaximumf": { - "sources": [ - "libm/src/math/fminimum_fmaximum.rs", - "libm/src/math/generic/fmaximum.rs" - ], - "type": "f32" - }, - "fmaximumf128": { - "sources": [ - "libm/src/math/fminimum_fmaximum.rs", - "libm/src/math/generic/fmaximum.rs" - ], - "type": "f128" - }, - "fmaximumf16": { - "sources": [ - "libm/src/math/fminimum_fmaximum.rs", - "libm/src/math/generic/fmaximum.rs" - ], - "type": "f16" - }, - "fmin": { - "sources": [ - "libm/src/math/fmin_fmax.rs", - "libm/src/math/generic/fmin.rs" - ], - "type": "f64" - }, - "fminf": { - "sources": [ - "libm/src/math/fmin_fmax.rs", - "libm/src/math/generic/fmin.rs" - ], - "type": "f32" - }, - "fminf128": { - "sources": [ - "libm/src/math/fmin_fmax.rs", - "libm/src/math/generic/fmin.rs" - ], - "type": "f128" - }, - "fminf16": { - "sources": [ - "libm/src/math/fmin_fmax.rs", - "libm/src/math/generic/fmin.rs" - ], - "type": "f16" - }, - "fminimum": { - "sources": [ - "libm/src/math/fminimum_fmaximum.rs", - "libm/src/math/generic/fminimum.rs" - ], - "type": "f64" - }, - "fminimum_num": { - "sources": [ - "libm/src/math/fminimum_fmaximum_num.rs", - "libm/src/math/generic/fminimum_num.rs" - ], - "type": "f64" - }, - "fminimum_numf": { - "sources": [ - "libm/src/math/fminimum_fmaximum_num.rs", - "libm/src/math/generic/fminimum_num.rs" - ], - "type": "f32" - }, - "fminimum_numf128": { - "sources": [ - "libm/src/math/fminimum_fmaximum_num.rs", - "libm/src/math/generic/fminimum_num.rs" - ], - "type": "f128" - }, - "fminimum_numf16": { - "sources": [ - "libm/src/math/fminimum_fmaximum_num.rs", - "libm/src/math/generic/fminimum_num.rs" - ], - "type": "f16" - }, - "fminimumf": { - "sources": [ - "libm/src/math/fminimum_fmaximum.rs", - "libm/src/math/generic/fminimum.rs" - ], - "type": "f32" - }, - "fminimumf128": { - "sources": [ - "libm/src/math/fminimum_fmaximum.rs", - "libm/src/math/generic/fminimum.rs" - ], - "type": "f128" - }, - "fminimumf16": { - "sources": [ - "libm/src/math/fminimum_fmaximum.rs", - "libm/src/math/generic/fminimum.rs" - ], - "type": "f16" - }, - "fmod": { - "sources": [ - "libm/src/math/fmod.rs", - "libm/src/math/generic/fmod.rs" - ], - "type": "f64" - }, - "fmodf": { - "sources": [ - "libm/src/math/fmod.rs", - "libm/src/math/generic/fmod.rs" - ], - "type": "f32" - }, - "fmodf128": { - "sources": [ - "libm/src/math/fmod.rs", - "libm/src/math/generic/fmod.rs" - ], - "type": "f128" - }, - "fmodf16": { - "sources": [ - "libm/src/math/fmod.rs", - "libm/src/math/generic/fmod.rs" - ], - "type": "f16" - }, - "frexp": { - "sources": [ - "libm/src/math/frexp.rs" - ], - "type": "f64" - }, - "frexpf": { - "sources": [ - "libm/src/math/frexpf.rs" - ], - "type": "f32" - }, - "hypot": { - "sources": [ - "libm/src/math/hypot.rs" - ], - "type": "f64" - }, - "hypotf": { - "sources": [ - "libm/src/math/hypotf.rs" - ], - "type": "f32" - }, - "ilogb": { - "sources": [ - "libm/src/math/ilogb.rs" - ], - "type": "f64" - }, - "ilogbf": { - "sources": [ - "libm/src/math/ilogbf.rs" - ], - "type": "f32" - }, - "j0": { - "sources": [ - "libm/src/math/j0.rs" - ], - "type": "f64" - }, - "j0f": { - "sources": [ - "libm/src/math/j0f.rs" - ], - "type": "f32" - }, - "j1": { - "sources": [ - "libm/src/math/j1.rs" - ], - "type": "f64" - }, - "j1f": { - "sources": [ - "libm/src/math/j1f.rs" - ], - "type": "f32" - }, - "jn": { - "sources": [ - "libm/src/math/jn.rs" - ], - "type": "f64" - }, - "jnf": { - "sources": [ - "libm/src/math/jnf.rs" - ], - "type": "f32" - }, - "ldexp": { - "sources": [ - "libm/src/math/ldexp.rs" - ], - "type": "f64" - }, - "ldexpf": { - "sources": [ - "libm/src/math/ldexp.rs" - ], - "type": "f32" - }, - "ldexpf128": { - "sources": [ - "libm/src/math/ldexp.rs" - ], - "type": "f128" - }, - "ldexpf16": { - "sources": [ - "libm/src/math/ldexp.rs" - ], - "type": "f16" - }, - "lgamma": { - "sources": [ - "libm/src/math/lgamma.rs" - ], - "type": "f64" - }, - "lgamma_r": { - "sources": [ - "libm/src/math/lgamma_r.rs" - ], - "type": "f64" - }, - "lgammaf": { - "sources": [ - "libm/src/math/lgammaf.rs" - ], - "type": "f32" - }, - "lgammaf_r": { - "sources": [ - "libm/src/math/lgammaf_r.rs" - ], - "type": "f32" - }, - "log": { - "sources": [ - "libm/src/math/log.rs" - ], - "type": "f64" - }, - "log10": { - "sources": [ - "libm/src/math/log10.rs" - ], - "type": "f64" - }, - "log10f": { - "sources": [ - "libm/src/math/log10f.rs" - ], - "type": "f32" - }, - "log1p": { - "sources": [ - "libm/src/math/log1p.rs" - ], - "type": "f64" - }, - "log1pf": { - "sources": [ - "libm/src/math/log1pf.rs" - ], - "type": "f32" - }, - "log2": { - "sources": [ - "libm/src/math/log2.rs" - ], - "type": "f64" - }, - "log2f": { - "sources": [ - "libm/src/math/log2f.rs" - ], - "type": "f32" - }, - "logf": { - "sources": [ - "libm/src/math/logf.rs" - ], - "type": "f32" - }, - "modf": { - "sources": [ - "libm/src/math/modf.rs" - ], - "type": "f64" - }, - "modff": { - "sources": [ - "libm/src/math/modff.rs" - ], - "type": "f32" - }, - "nextafter": { - "sources": [ - "libm/src/math/nextafter.rs" - ], - "type": "f64" - }, - "nextafterf": { - "sources": [ - "libm/src/math/nextafterf.rs" - ], - "type": "f32" - }, - "pow": { - "sources": [ - "libm/src/math/pow.rs" - ], - "type": "f64" - }, - "powf": { - "sources": [ - "libm/src/math/powf.rs" - ], - "type": "f32" - }, - "remainder": { - "sources": [ - "libm/src/math/remainder.rs" - ], - "type": "f64" - }, - "remainderf": { - "sources": [ - "libm/src/math/remainderf.rs" - ], - "type": "f32" - }, - "remquo": { - "sources": [ - "libm/src/math/remquo.rs" - ], - "type": "f64" - }, - "remquof": { - "sources": [ - "libm/src/math/remquof.rs" - ], - "type": "f32" - }, - "rint": { - "sources": [ - "libm/src/math/arch/aarch64.rs", - "libm/src/math/arch/wasm32.rs", - "libm/src/math/rint.rs" - ], - "type": "f64" - }, - "rintf": { - "sources": [ - "libm/src/math/arch/aarch64.rs", - "libm/src/math/arch/wasm32.rs", - "libm/src/math/rint.rs" - ], - "type": "f32" - }, - "rintf128": { - "sources": [ - "libm/src/math/rint.rs" - ], - "type": "f128" - }, - "rintf16": { - "sources": [ - "libm/src/math/arch/aarch64.rs", - "libm/src/math/rint.rs" - ], - "type": "f16" - }, - "round": { - "sources": [ - "libm/src/math/generic/round.rs", - "libm/src/math/round.rs" - ], - "type": "f64" - }, - "roundeven": { - "sources": [ - "libm/src/math/roundeven.rs" - ], - "type": "f64" - }, - "roundevenf": { - "sources": [ - "libm/src/math/roundeven.rs" - ], - "type": "f32" - }, - "roundevenf128": { - "sources": [ - "libm/src/math/roundeven.rs" - ], - "type": "f128" - }, - "roundevenf16": { - "sources": [ - "libm/src/math/roundeven.rs" - ], - "type": "f16" - }, - "roundf": { - "sources": [ - "libm/src/math/generic/round.rs", - "libm/src/math/round.rs" - ], - "type": "f32" - }, - "roundf128": { - "sources": [ - "libm/src/math/generic/round.rs", - "libm/src/math/round.rs" - ], - "type": "f128" - }, - "roundf16": { - "sources": [ - "libm/src/math/generic/round.rs", - "libm/src/math/round.rs" - ], - "type": "f16" - }, - "scalbn": { - "sources": [ - "libm/src/math/generic/scalbn.rs", - "libm/src/math/scalbn.rs" - ], - "type": "f64" - }, - "scalbnf": { - "sources": [ - "libm/src/math/generic/scalbn.rs", - "libm/src/math/scalbn.rs" - ], - "type": "f32" - }, - "scalbnf128": { - "sources": [ - "libm/src/math/generic/scalbn.rs", - "libm/src/math/scalbn.rs" - ], - "type": "f128" - }, - "scalbnf16": { - "sources": [ - "libm/src/math/generic/scalbn.rs", - "libm/src/math/scalbn.rs" - ], - "type": "f16" - }, - "sin": { - "sources": [ - "libm/src/math/sin.rs" - ], - "type": "f64" - }, - "sincos": { - "sources": [ - "libm/src/math/sincos.rs" - ], - "type": "f64" - }, - "sincosf": { - "sources": [ - "libm/src/math/sincosf.rs" - ], - "type": "f32" - }, - "sinf": { - "sources": [ - "libm/src/math/sinf.rs" - ], - "type": "f32" - }, - "sinh": { - "sources": [ - "libm/src/math/sinh.rs" - ], - "type": "f64" - }, - "sinhf": { - "sources": [ - "libm/src/math/sinhf.rs" - ], - "type": "f32" - }, - "sqrt": { - "sources": [ - "libm/src/math/arch/aarch64.rs", - "libm/src/math/arch/i686.rs", - "libm/src/math/arch/wasm32.rs", - "libm/src/math/generic/sqrt.rs", - "libm/src/math/sqrt.rs" - ], - "type": "f64" - }, - "sqrtf": { - "sources": [ - "libm/src/math/arch/aarch64.rs", - "libm/src/math/arch/i686.rs", - "libm/src/math/arch/wasm32.rs", - "libm/src/math/generic/sqrt.rs", - "libm/src/math/sqrt.rs" - ], - "type": "f32" - }, - "sqrtf128": { - "sources": [ - "libm/src/math/generic/sqrt.rs", - "libm/src/math/sqrt.rs" - ], - "type": "f128" - }, - "sqrtf16": { - "sources": [ - "libm/src/math/arch/aarch64.rs", - "libm/src/math/generic/sqrt.rs", - "libm/src/math/sqrt.rs" - ], - "type": "f16" - }, - "tan": { - "sources": [ - "libm/src/math/tan.rs" - ], - "type": "f64" - }, - "tanf": { - "sources": [ - "libm/src/math/tanf.rs" - ], - "type": "f32" - }, - "tanh": { - "sources": [ - "libm/src/math/tanh.rs" - ], - "type": "f64" - }, - "tanhf": { - "sources": [ - "libm/src/math/tanhf.rs" - ], - "type": "f32" - }, - "tgamma": { - "sources": [ - "libm/src/math/tgamma.rs" - ], - "type": "f64" - }, - "tgammaf": { - "sources": [ - "libm/src/math/tgammaf.rs" - ], - "type": "f32" - }, - "trunc": { - "sources": [ - "libm/src/math/arch/wasm32.rs", - "libm/src/math/generic/trunc.rs", - "libm/src/math/trunc.rs" - ], - "type": "f64" - }, - "truncf": { - "sources": [ - "libm/src/math/arch/wasm32.rs", - "libm/src/math/generic/trunc.rs", - "libm/src/math/trunc.rs" - ], - "type": "f32" - }, - "truncf128": { - "sources": [ - "libm/src/math/generic/trunc.rs", - "libm/src/math/trunc.rs" - ], - "type": "f128" - }, - "truncf16": { - "sources": [ - "libm/src/math/generic/trunc.rs", - "libm/src/math/trunc.rs" - ], - "type": "f16" - }, - "y0": { - "sources": [ - "libm/src/math/j0.rs" - ], - "type": "f64" - }, - "y0f": { - "sources": [ - "libm/src/math/j0f.rs" - ], - "type": "f32" - }, - "y1": { - "sources": [ - "libm/src/math/j1.rs" - ], - "type": "f64" - }, - "y1f": { - "sources": [ - "libm/src/math/j1f.rs" - ], - "type": "f32" - }, - "yn": { - "sources": [ - "libm/src/math/jn.rs" - ], - "type": "f64" - }, - "ynf": { - "sources": [ - "libm/src/math/jnf.rs" - ], - "type": "f32" - } -} diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt deleted file mode 100644 index 1f226c8c0ff..00000000000 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ /dev/null @@ -1,164 +0,0 @@ -# autogenerated by update-api-list.py -acos -acosf -acosh -acoshf -asin -asinf -asinh -asinhf -atan -atan2 -atan2f -atanf -atanh -atanhf -cbrt -cbrtf -ceil -ceilf -ceilf128 -ceilf16 -copysign -copysignf -copysignf128 -copysignf16 -cos -cosf -cosh -coshf -erf -erfc -erfcf -erff -exp -exp10 -exp10f -exp2 -exp2f -expf -expm1 -expm1f -fabs -fabsf -fabsf128 -fabsf16 -fdim -fdimf -fdimf128 -fdimf16 -floor -floorf -floorf128 -floorf16 -fma -fmaf -fmaf128 -fmax -fmaxf -fmaxf128 -fmaxf16 -fmaximum -fmaximum_num -fmaximum_numf -fmaximum_numf128 -fmaximum_numf16 -fmaximumf -fmaximumf128 -fmaximumf16 -fmin -fminf -fminf128 -fminf16 -fminimum -fminimum_num -fminimum_numf -fminimum_numf128 -fminimum_numf16 -fminimumf -fminimumf128 -fminimumf16 -fmod -fmodf -fmodf128 -fmodf16 -frexp -frexpf -hypot -hypotf -ilogb -ilogbf -j0 -j0f -j1 -j1f -jn -jnf -ldexp -ldexpf -ldexpf128 -ldexpf16 -lgamma -lgamma_r -lgammaf -lgammaf_r -log -log10 -log10f -log1p -log1pf -log2 -log2f -logf -modf -modff -nextafter -nextafterf -pow -powf -remainder -remainderf -remquo -remquof -rint -rintf -rintf128 -rintf16 -round -roundeven -roundevenf -roundevenf128 -roundevenf16 -roundf -roundf128 -roundf16 -scalbn -scalbnf -scalbnf128 -scalbnf16 -sin -sincos -sincosf -sinf -sinh -sinhf -sqrt -sqrtf -sqrtf128 -sqrtf16 -tan -tanf -tanh -tanhf -tgamma -tgammaf -trunc -truncf -truncf128 -truncf16 -y0 -y0f -y1 -y1f -yn -ynf diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py deleted file mode 100755 index 0770a8b20fb..00000000000 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ /dev/null @@ -1,359 +0,0 @@ -#!/usr/bin/env python3 -"""Create a text file listing all public API. This can be used to ensure that all -functions are covered by our macros. - -This file additionally does tidy-esque checks that all functions are listed where -needed, or that lists are sorted. -""" - -import difflib -import json -import re -import subprocess as sp -import sys -from dataclasses import dataclass -from glob import glob -from pathlib import Path -from typing import Any, Callable, TypeAlias - -SELF_PATH = Path(__file__) -ETC_DIR = SELF_PATH.parent -ROOT_DIR = ETC_DIR.parent - -# These files do not trigger a retest. -IGNORED_SOURCES = ["libm/src/libm_helper.rs", "libm/src/math/support/float_traits.rs"] - -IndexTy: TypeAlias = dict[str, dict[str, Any]] -"""Type of the `index` item in rustdoc's JSON output""" - - -def eprint(*args, **kwargs): - """Print to stderr.""" - print(*args, file=sys.stderr, **kwargs) - - -@dataclass -class Crate: - """Representation of public interfaces and function defintion locations in - `libm`. - """ - - public_functions: list[str] - """List of all public functions.""" - defs: dict[str, list[str]] - """Map from `name->[source files]` to find all places that define a public - function. We track this to know which tests need to be rerun when specific files - get updated. - """ - types: dict[str, str] - """Map from `name->type`.""" - - def __init__(self) -> None: - self.public_functions = [] - self.defs = {} - self.types = {} - - j = self.get_rustdoc_json() - index: IndexTy = j["index"] - self._init_function_list(index) - self._init_defs(index) - self._init_types() - - @staticmethod - def get_rustdoc_json() -> dict[Any, Any]: - """Get rustdoc's JSON output for the `libm` crate.""" - - j = sp.check_output( - [ - "rustdoc", - "libm/src/lib.rs", - "--edition=2021", - "--document-private-items", - "--output-format=json", - "--cfg=f16_enabled", - "--cfg=f128_enabled", - "-Zunstable-options", - "-o-", - ], - cwd=ROOT_DIR, - text=True, - ) - j = json.loads(j) - return j - - def _init_function_list(self, index: IndexTy) -> None: - """Get a list of public functions from rustdoc JSON output. - - Note that this only finds functions that are reexported in `lib.rs`, this will - need to be adjusted if we need to account for functions that are defined there, or - glob reexports in other locations. - """ - # Filter out items that are not public - public = [i for i in index.values() if i["visibility"] == "public"] - - # Collect a list of source IDs for reexported items in `lib.rs` or `mod math`. - use = (i for i in public if "use" in i["inner"]) - use = ( - i - for i in use - if i["span"]["filename"] in ["libm/src/math/mod.rs", "libm/src/lib.rs"] - ) - reexported_ids = [item["inner"]["use"]["id"] for item in use] - - # Collect a list of reexported items that are functions - for id in reexported_ids: - srcitem = index.get(str(id)) - # External crate - if srcitem is None: - continue - - # Skip if not a function - if "function" not in srcitem["inner"]: - continue - - self.public_functions.append(srcitem["name"]) - self.public_functions.sort() - - def _init_defs(self, index: IndexTy) -> None: - defs = {name: set() for name in self.public_functions} - funcs = (i for i in index.values() if "function" in i["inner"]) - funcs = (f for f in funcs if f["name"] in self.public_functions) - for func in funcs: - defs[func["name"]].add(func["span"]["filename"]) - - # A lot of the `arch` module is often configured out so doesn't show up in docs. Use - # string matching as a fallback. - for fname in glob("libm/src/math/arch/**.rs", root_dir=ROOT_DIR): - contents = (ROOT_DIR.joinpath(fname)).read_text() - - for name in self.public_functions: - if f"fn {name}" in contents: - defs[name].add(fname) - - for name, sources in defs.items(): - base_sources = defs[base_name(name)[0]] - for src in (s for s in base_sources if "generic" in s): - sources.add(src) - - for src in IGNORED_SOURCES: - sources.discard(src) - - # Sort the set - self.defs = {k: sorted(v) for (k, v) in defs.items()} - - def _init_types(self) -> None: - self.types = {name: base_name(name)[1] for name in self.public_functions} - - def write_function_list(self, check: bool) -> None: - """Collect the list of public functions to a simple text file.""" - output = "# autogenerated by update-api-list.py\n" - for name in self.public_functions: - output += f"{name}\n" - - out_file = ETC_DIR.joinpath("function-list.txt") - - if check: - with open(out_file, "r") as f: - current = f.read() - diff_and_exit(current, output, "function list") - else: - with open(out_file, "w") as f: - f.write(output) - - def write_function_defs(self, check: bool) -> None: - """Collect the list of information about public functions to a JSON file .""" - comment = ( - "Autogenerated by update-api-list.py. " - "List of files that define a function with a given name. " - "This file is checked in to make it obvious if refactoring breaks things" - ) - - d = {"__comment": comment} - d |= { - name: {"sources": self.defs[name], "type": self.types[name]} - for name in self.public_functions - } - - out_file = ETC_DIR.joinpath("function-definitions.json") - output = json.dumps(d, indent=4) + "\n" - - if check: - with open(out_file, "r") as f: - current = f.read() - diff_and_exit(current, output, "source list") - else: - with open(out_file, "w") as f: - f.write(output) - - def tidy_lists(self) -> None: - """In each file, check annotations indicating blocks of code should be sorted or should - include all public API. - """ - - flist = sp.check_output(["git", "ls-files"], cwd=ROOT_DIR, text=True) - - for path in flist.splitlines(): - fpath = ROOT_DIR.joinpath(path) - if fpath.is_dir() or fpath == SELF_PATH: - continue - - lines = fpath.read_text().splitlines() - - validate_delimited_block( - fpath, - lines, - "verify-sorted-start", - "verify-sorted-end", - ensure_sorted, - ) - - validate_delimited_block( - fpath, - lines, - "verify-apilist-start", - "verify-apilist-end", - lambda p, n, lines: self.ensure_contains_api(p, n, lines), - ) - - def ensure_contains_api(self, fpath: Path, line_num: int, lines: list[str]): - """Given a list of strings, ensure that each public function we have is named - somewhere. - """ - not_found = [] - for func in self.public_functions: - # The function name may be on its own or somewhere in a snake case string. - pat = re.compile(rf"(\b|_){func}(\b|_)") - found = next((line for line in lines if pat.search(line)), None) - - if found is None: - not_found.append(func) - - if len(not_found) == 0: - return - - relpath = fpath.relative_to(ROOT_DIR) - eprint(f"functions not found at {relpath}:{line_num}: {not_found}") - exit(1) - - -def validate_delimited_block( - fpath: Path, - lines: list[str], - start: str, - end: str, - validate: Callable[[Path, int, list[str]], None], -) -> None: - """Identify blocks of code wrapped within `start` and `end`, collect their contents - to a list of strings, and call `validate` for each of those lists. - """ - relpath = fpath.relative_to(ROOT_DIR) - block_lines = [] - block_start_line: None | int = None - for line_num, line in enumerate(lines): - line_num += 1 - - if start in line: - block_start_line = line_num - continue - - if end in line: - if block_start_line is None: - eprint(f"`{end}` without `{start}` at {relpath}:{line_num}") - exit(1) - - validate(fpath, block_start_line, block_lines) - block_lines = [] - block_start_line = None - continue - - if block_start_line is not None: - block_lines.append(line) - - if block_start_line is not None: - eprint(f"`{start}` without `{end}` at {relpath}:{block_start_line}") - exit(1) - - -def ensure_sorted(fpath: Path, block_start_line: int, lines: list[str]) -> None: - """Ensure that a list of lines is sorted, otherwise print a diff and exit.""" - relpath = fpath.relative_to(ROOT_DIR) - diff_and_exit( - "\n".join(lines), - "\n".join(sorted(lines)), - f"sorted block at {relpath}:{block_start_line}", - ) - - -def diff_and_exit(actual: str, expected: str, name: str): - """If the two strings are different, print a diff between them and then exit - with an error. - """ - if actual == expected: - print(f"{name} output matches expected; success") - return - - a = [f"{line}\n" for line in actual.splitlines()] - b = [f"{line}\n" for line in expected.splitlines()] - - diff = difflib.unified_diff(a, b, "actual", "expected") - sys.stdout.writelines(diff) - print(f"mismatched {name}") - exit(1) - - -def base_name(name: str) -> tuple[str, str]: - """Return the basename and type from a full function name. Keep in sync with Rust's - `fn base_name`. - """ - known_mappings = [ - ("erff", ("erf", "f32")), - ("erf", ("erf", "f64")), - ("modff", ("modf", "f32")), - ("modf", ("modf", "f64")), - ("lgammaf_r", ("lgamma_r", "f32")), - ("lgamma_r", ("lgamma_r", "f64")), - ] - - found = next((base for (full, base) in known_mappings if full == name), None) - if found is not None: - return found - - if name.endswith("f"): - return (name.rstrip("f"), "f32") - - if name.endswith("f16"): - return (name.rstrip("f16"), "f16") - - if name.endswith("f128"): - return (name.rstrip("f128"), "f128") - - return (name, "f64") - - -def ensure_updated_list(check: bool) -> None: - """Runner to update the function list and JSON, or check that it is already up - to date. - """ - crate = Crate() - crate.write_function_list(check) - crate.write_function_defs(check) - - crate.tidy_lists() - - -def main(): - """By default overwrite the file. If `--check` is passed, print a diff instead and - error if the files are different. - """ - match sys.argv: - case [_]: - ensure_updated_list(False) - case [_, "--check"]: - ensure_updated_list(True) - case _: - print("unrecognized arguments") - exit(1) - - -if __name__ == "__main__": - main() diff --git a/library/compiler-builtins/libm/libm/LICENSE.txt b/library/compiler-builtins/libm/libm/LICENSE.txt deleted file mode 120000 index 4ab43736a83..00000000000 --- a/library/compiler-builtins/libm/libm/LICENSE.txt +++ /dev/null @@ -1 +0,0 @@ -../LICENSE.txt \ No newline at end of file diff --git a/library/compiler-builtins/libm/libm/LICENSE.txt b/library/compiler-builtins/libm/libm/LICENSE.txt new file mode 100644 index 00000000000..2f8e41f1474 --- /dev/null +++ b/library/compiler-builtins/libm/libm/LICENSE.txt @@ -0,0 +1,258 @@ +rust-lang/libm as a whole is available for use under the MIT license: + +------------------------------------------------------------------------------ +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. +------------------------------------------------------------------------------ + +As a contributor, you agree that your code can be used under either the MIT +license or the Apache-2.0 license: + +------------------------------------------------------------------------------ + 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. + + 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. +------------------------------------------------------------------------------ + +This Rust library contains the following copyrights: + + Copyright (c) 2018 Jorge Aparicio + +Portions of this software are derived from third-party works licensed under +terms compatible with the above MIT license: + +* musl libc https://www.musl-libc.org/. This library contains the following + copyright: + + Copyright © 2005-2020 Rich Felker, et al. + +* The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH + routines are available under the MIT license on a per-file basis. + +The musl libc COPYRIGHT file also includes the following notice relevant to +math portions of the library: + +------------------------------------------------------------------------------ +Much of the math library code (src/math/* and src/complex/*) is +Copyright © 1993,2004 Sun Microsystems or +Copyright © 2003-2011 David Schultz or +Copyright © 2003-2009 Steven G. Kargl or +Copyright © 2003-2009 Bruce D. Evans or +Copyright © 2008 Stephen L. Moshier or +Copyright © 2017-2018 Arm Limited +and labelled as such in comments in the individual source files. All +have been licensed under extremely permissive terms. +------------------------------------------------------------------------------ + +Copyright notices are retained in src/* files where relevant. diff --git a/library/compiler-builtins/libm/libm/README.md b/library/compiler-builtins/libm/libm/README.md deleted file mode 120000 index 32d46ee883b..00000000000 --- a/library/compiler-builtins/libm/libm/README.md +++ /dev/null @@ -1 +0,0 @@ -../README.md \ No newline at end of file diff --git a/library/compiler-builtins/libm/libm/README.md b/library/compiler-builtins/libm/libm/README.md new file mode 100644 index 00000000000..52d760a4f15 --- /dev/null +++ b/library/compiler-builtins/libm/libm/README.md @@ -0,0 +1,56 @@ +# `libm` + +A port of [MUSL]'s libm to Rust. + +[MUSL]: https://musl.libc.org/ + +## Goals + +The short term goal of this library is to [enable math support (e.g. `sin`, `atan2`) for the +`wasm32-unknown-unknown` target][wasm] (cf. [rust-lang/compiler-builtins][pr]). The longer +term goal is to enable [math support in the `core` crate][core]. + +[wasm]: https://github.com/rust-lang/libm/milestone/1 +[pr]: https://github.com/rust-lang/compiler-builtins/pull/248 +[core]: https://github.com/rust-lang/libm/milestone/2 + +## Already usable + +This crate is [on crates.io] and can be used today in stable `#![no_std]` programs. + +The API documentation can be found [here](https://docs.rs/libm). + +[on crates.io]: https://crates.io/crates/libm + +## Benchmark +[benchmark]: #benchmark + +The benchmarks are located in `crates/libm-bench` and require a nightly Rust toolchain. +To run all benchmarks: + +> cargo +nightly bench --all + +## Contributing + +Please check [CONTRIBUTING.md](CONTRIBUTING.md) + +## Minimum Rust version policy + +This crate supports rustc 1.63 and newer. + +## License + +Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or +https://opensource.org/licenses/MIT). + + +### Contribution + +Contributions are licensed under both the MIT license and the Apache License, +Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or +https://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state +otherwise, any contribution intentionally submitted for inclusion in the work +by you, as defined in the Apache-2.0 license, shall be dual licensed as +mentioned, without any additional terms or conditions. + +See `LICENSE.txt` for full details. -- cgit 1.4.1-3-g733a5 From 8b8bd8a0fd75e43a9b282284b849e651828ceec2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 21:09:49 +0000 Subject: libm: Flatten the `libm/libm` directory --- .../compiler-builtins/src/math.rs | 2 +- library/compiler-builtins/libm/Cargo.toml | 49 + library/compiler-builtins/libm/LICENSE.txt | 258 +++++ library/compiler-builtins/libm/README.md | 56 + library/compiler-builtins/libm/build.rs | 18 + library/compiler-builtins/libm/configure.rs | 183 ++++ library/compiler-builtins/libm/libm/Cargo.toml | 49 - library/compiler-builtins/libm/libm/LICENSE.txt | 258 ----- library/compiler-builtins/libm/libm/README.md | 56 - library/compiler-builtins/libm/libm/build.rs | 18 - library/compiler-builtins/libm/libm/configure.rs | 183 ---- library/compiler-builtins/libm/libm/src/lib.rs | 29 - .../compiler-builtins/libm/libm/src/libm_helper.rs | 244 ----- .../compiler-builtins/libm/libm/src/math/acos.rs | 112 -- .../compiler-builtins/libm/libm/src/math/acosf.rs | 79 -- .../compiler-builtins/libm/libm/src/math/acosh.rs | 27 - .../compiler-builtins/libm/libm/src/math/acoshf.rs | 26 - .../libm/libm/src/math/arch/aarch64.rs | 115 -- .../libm/libm/src/math/arch/i586.rs | 37 - .../libm/libm/src/math/arch/i686.rs | 27 - .../libm/libm/src/math/arch/mod.rs | 50 - .../libm/libm/src/math/arch/wasm32.rs | 50 - .../compiler-builtins/libm/libm/src/math/asin.rs | 115 -- .../compiler-builtins/libm/libm/src/math/asinf.rs | 68 -- .../compiler-builtins/libm/libm/src/math/asinh.rs | 36 - .../compiler-builtins/libm/libm/src/math/asinhf.rs | 35 - .../compiler-builtins/libm/libm/src/math/atan.rs | 182 --- .../compiler-builtins/libm/libm/src/math/atan2.rs | 131 --- .../compiler-builtins/libm/libm/src/math/atan2f.rs | 90 -- .../compiler-builtins/libm/libm/src/math/atanf.rs | 103 -- .../compiler-builtins/libm/libm/src/math/atanh.rs | 33 - .../compiler-builtins/libm/libm/src/math/atanhf.rs | 33 - .../compiler-builtins/libm/libm/src/math/cbrt.rs | 215 ---- .../compiler-builtins/libm/libm/src/math/cbrtf.rs | 75 -- .../compiler-builtins/libm/libm/src/math/ceil.rs | 46 - .../libm/libm/src/math/copysign.rs | 88 -- .../libm/libm/src/math/copysignf.rs | 8 - .../libm/libm/src/math/copysignf128.rs | 8 - .../libm/libm/src/math/copysignf16.rs | 8 - .../compiler-builtins/libm/libm/src/math/cos.rs | 77 -- .../compiler-builtins/libm/libm/src/math/cosf.rs | 86 -- .../compiler-builtins/libm/libm/src/math/cosh.rs | 36 - .../compiler-builtins/libm/libm/src/math/coshf.rs | 36 - .../compiler-builtins/libm/libm/src/math/erf.rs | 310 ------ .../compiler-builtins/libm/libm/src/math/erff.rs | 222 ---- .../compiler-builtins/libm/libm/src/math/exp.rs | 150 --- .../compiler-builtins/libm/libm/src/math/exp10.rs | 23 - .../compiler-builtins/libm/libm/src/math/exp10f.rs | 22 - .../compiler-builtins/libm/libm/src/math/exp2.rs | 394 ------- .../compiler-builtins/libm/libm/src/math/exp2f.rs | 135 --- .../compiler-builtins/libm/libm/src/math/expf.rs | 97 -- .../compiler-builtins/libm/libm/src/math/expm1.rs | 144 --- .../compiler-builtins/libm/libm/src/math/expm1f.rs | 130 --- .../compiler-builtins/libm/libm/src/math/expo2.rs | 14 - .../compiler-builtins/libm/libm/src/math/fabs.rs | 116 -- .../compiler-builtins/libm/libm/src/math/fabsf.rs | 39 - .../libm/libm/src/math/fabsf128.rs | 31 - .../libm/libm/src/math/fabsf16.rs | 31 - .../compiler-builtins/libm/libm/src/math/fdim.rs | 53 - .../compiler-builtins/libm/libm/src/math/fdimf.rs | 12 - .../libm/libm/src/math/fdimf128.rs | 12 - .../libm/libm/src/math/fdimf16.rs | 12 - .../compiler-builtins/libm/libm/src/math/floor.rs | 46 - .../compiler-builtins/libm/libm/src/math/floorf.rs | 13 - .../libm/libm/src/math/floorf128.rs | 7 - .../libm/libm/src/math/floorf16.rs | 7 - .../compiler-builtins/libm/libm/src/math/fma.rs | 397 ------- .../libm/libm/src/math/fma_wide.rs | 104 -- .../libm/libm/src/math/fmin_fmax.rs | 167 --- .../libm/libm/src/math/fminimum_fmaximum.rs | 163 --- .../libm/libm/src/math/fminimum_fmaximum_num.rs | 163 --- .../compiler-builtins/libm/libm/src/math/fmod.rs | 25 - .../compiler-builtins/libm/libm/src/math/fmodf.rs | 5 - .../libm/libm/src/math/fmodf128.rs | 5 - .../libm/libm/src/math/fmodf16.rs | 5 - .../compiler-builtins/libm/libm/src/math/frexp.rs | 21 - .../compiler-builtins/libm/libm/src/math/frexpf.rs | 22 - .../libm/libm/src/math/generic/ceil.rs | 168 --- .../libm/libm/src/math/generic/copysign.rs | 11 - .../libm/libm/src/math/generic/fabs.rs | 8 - .../libm/libm/src/math/generic/fdim.rs | 6 - .../libm/libm/src/math/generic/floor.rs | 151 --- .../libm/libm/src/math/generic/fmax.rs | 24 - .../libm/libm/src/math/generic/fmaximum.rs | 28 - .../libm/libm/src/math/generic/fmaximum_num.rs | 27 - .../libm/libm/src/math/generic/fmin.rs | 24 - .../libm/libm/src/math/generic/fminimum.rs | 28 - .../libm/libm/src/math/generic/fminimum_num.rs | 27 - .../libm/libm/src/math/generic/fmod.rs | 84 -- .../libm/libm/src/math/generic/mod.rs | 38 - .../libm/libm/src/math/generic/rint.rs | 120 -- .../libm/libm/src/math/generic/round.rs | 83 -- .../libm/libm/src/math/generic/scalbn.rs | 121 -- .../libm/libm/src/math/generic/sqrt.rs | 537 --------- .../libm/libm/src/math/generic/trunc.rs | 138 --- .../compiler-builtins/libm/libm/src/math/hypot.rs | 74 -- .../compiler-builtins/libm/libm/src/math/hypotf.rs | 43 - .../compiler-builtins/libm/libm/src/math/ilogb.rs | 28 - .../compiler-builtins/libm/libm/src/math/ilogbf.rs | 28 - library/compiler-builtins/libm/libm/src/math/j0.rs | 426 -------- .../compiler-builtins/libm/libm/src/math/j0f.rs | 363 ------ library/compiler-builtins/libm/libm/src/math/j1.rs | 418 ------- .../compiler-builtins/libm/libm/src/math/j1f.rs | 384 ------- library/compiler-builtins/libm/libm/src/math/jn.rs | 339 ------ .../compiler-builtins/libm/libm/src/math/jnf.rs | 253 ----- .../compiler-builtins/libm/libm/src/math/k_cos.rs | 62 -- .../compiler-builtins/libm/libm/src/math/k_cosf.rs | 29 - .../libm/libm/src/math/k_expo2.rs | 14 - .../libm/libm/src/math/k_expo2f.rs | 14 - .../compiler-builtins/libm/libm/src/math/k_sin.rs | 53 - .../compiler-builtins/libm/libm/src/math/k_sinf.rs | 30 - .../compiler-builtins/libm/libm/src/math/k_tan.rs | 105 -- .../compiler-builtins/libm/libm/src/math/k_tanf.rs | 46 - .../compiler-builtins/libm/libm/src/math/ldexp.rs | 21 - .../compiler-builtins/libm/libm/src/math/ldexpf.rs | 4 - .../libm/libm/src/math/ldexpf128.rs | 4 - .../libm/libm/src/math/ldexpf16.rs | 4 - .../compiler-builtins/libm/libm/src/math/lgamma.rs | 8 - .../libm/libm/src/math/lgamma_r.rs | 321 ------ .../libm/libm/src/math/lgammaf.rs | 8 - .../libm/libm/src/math/lgammaf_r.rs | 256 ----- .../compiler-builtins/libm/libm/src/math/log.rs | 118 -- .../compiler-builtins/libm/libm/src/math/log10.rs | 118 -- .../compiler-builtins/libm/libm/src/math/log10f.rs | 92 -- .../compiler-builtins/libm/libm/src/math/log1p.rs | 140 --- .../compiler-builtins/libm/libm/src/math/log1pf.rs | 95 -- .../compiler-builtins/libm/libm/src/math/log2.rs | 107 -- .../compiler-builtins/libm/libm/src/math/log2f.rs | 88 -- .../compiler-builtins/libm/libm/src/math/logf.rs | 66 -- .../compiler-builtins/libm/libm/src/math/mod.rs | 396 ------- .../compiler-builtins/libm/libm/src/math/modf.rs | 35 - .../compiler-builtins/libm/libm/src/math/modff.rs | 34 - .../libm/libm/src/math/nextafter.rs | 37 - .../libm/libm/src/math/nextafterf.rs | 37 - .../compiler-builtins/libm/libm/src/math/pow.rs | 607 ---------- .../compiler-builtins/libm/libm/src/math/powf.rs | 335 ------ .../libm/libm/src/math/rem_pio2.rs | 223 ---- .../libm/libm/src/math/rem_pio2_large.rs | 468 -------- .../libm/libm/src/math/rem_pio2f.rs | 67 -- .../libm/libm/src/math/remainder.rs | 5 - .../libm/libm/src/math/remainderf.rs | 5 - .../compiler-builtins/libm/libm/src/math/remquo.rs | 106 -- .../libm/libm/src/math/remquof.rs | 93 -- .../compiler-builtins/libm/libm/src/math/rint.rs | 51 - .../compiler-builtins/libm/libm/src/math/round.rs | 25 - .../libm/libm/src/math/roundeven.rs | 36 - .../compiler-builtins/libm/libm/src/math/roundf.rs | 5 - .../libm/libm/src/math/roundf128.rs | 5 - .../libm/libm/src/math/roundf16.rs | 5 - .../compiler-builtins/libm/libm/src/math/scalbn.rs | 87 -- .../libm/libm/src/math/scalbnf.rs | 4 - .../libm/libm/src/math/scalbnf128.rs | 4 - .../libm/libm/src/math/scalbnf16.rs | 4 - .../compiler-builtins/libm/libm/src/math/sin.rs | 95 -- .../compiler-builtins/libm/libm/src/math/sincos.rs | 137 --- .../libm/libm/src/math/sincosf.rs | 176 --- .../compiler-builtins/libm/libm/src/math/sinf.rs | 88 -- .../compiler-builtins/libm/libm/src/math/sinh.rs | 51 - .../compiler-builtins/libm/libm/src/math/sinhf.rs | 30 - .../compiler-builtins/libm/libm/src/math/sqrt.rs | 51 - .../compiler-builtins/libm/libm/src/math/sqrtf.rs | 15 - .../libm/libm/src/math/sqrtf128.rs | 5 - .../libm/libm/src/math/sqrtf16.rs | 11 - .../libm/libm/src/math/support/big.rs | 239 ---- .../libm/libm/src/math/support/big/tests.rs | 149 --- .../libm/libm/src/math/support/env.rs | 127 --- .../libm/libm/src/math/support/float_traits.rs | 484 -------- .../libm/libm/src/math/support/hex_float.rs | 1155 -------------------- .../libm/libm/src/math/support/int_traits.rs | 451 -------- .../libm/libm/src/math/support/macros.rs | 157 --- .../libm/libm/src/math/support/mod.rs | 29 - .../compiler-builtins/libm/libm/src/math/tan.rs | 70 -- .../compiler-builtins/libm/libm/src/math/tanf.rs | 77 -- .../compiler-builtins/libm/libm/src/math/tanh.rs | 53 - .../compiler-builtins/libm/libm/src/math/tanhf.rs | 38 - .../compiler-builtins/libm/libm/src/math/tgamma.rs | 209 ---- .../libm/libm/src/math/tgammaf.rs | 7 - .../compiler-builtins/libm/libm/src/math/trunc.rs | 53 - .../compiler-builtins/libm/libm/src/math/truncf.rs | 23 - .../libm/libm/src/math/truncf128.rs | 7 - .../libm/libm/src/math/truncf16.rs | 7 - library/compiler-builtins/libm/src/lib.rs | 29 + library/compiler-builtins/libm/src/libm_helper.rs | 244 +++++ library/compiler-builtins/libm/src/math/acos.rs | 112 ++ library/compiler-builtins/libm/src/math/acosf.rs | 79 ++ library/compiler-builtins/libm/src/math/acosh.rs | 27 + library/compiler-builtins/libm/src/math/acoshf.rs | 26 + .../libm/src/math/arch/aarch64.rs | 115 ++ .../compiler-builtins/libm/src/math/arch/i586.rs | 37 + .../compiler-builtins/libm/src/math/arch/i686.rs | 27 + .../compiler-builtins/libm/src/math/arch/mod.rs | 50 + .../compiler-builtins/libm/src/math/arch/wasm32.rs | 50 + library/compiler-builtins/libm/src/math/asin.rs | 115 ++ library/compiler-builtins/libm/src/math/asinf.rs | 68 ++ library/compiler-builtins/libm/src/math/asinh.rs | 36 + library/compiler-builtins/libm/src/math/asinhf.rs | 35 + library/compiler-builtins/libm/src/math/atan.rs | 182 +++ library/compiler-builtins/libm/src/math/atan2.rs | 131 +++ library/compiler-builtins/libm/src/math/atan2f.rs | 90 ++ library/compiler-builtins/libm/src/math/atanf.rs | 103 ++ library/compiler-builtins/libm/src/math/atanh.rs | 33 + library/compiler-builtins/libm/src/math/atanhf.rs | 33 + library/compiler-builtins/libm/src/math/cbrt.rs | 215 ++++ library/compiler-builtins/libm/src/math/cbrtf.rs | 75 ++ library/compiler-builtins/libm/src/math/ceil.rs | 46 + .../compiler-builtins/libm/src/math/copysign.rs | 88 ++ .../compiler-builtins/libm/src/math/copysignf.rs | 8 + .../libm/src/math/copysignf128.rs | 8 + .../compiler-builtins/libm/src/math/copysignf16.rs | 8 + library/compiler-builtins/libm/src/math/cos.rs | 77 ++ library/compiler-builtins/libm/src/math/cosf.rs | 86 ++ library/compiler-builtins/libm/src/math/cosh.rs | 36 + library/compiler-builtins/libm/src/math/coshf.rs | 36 + library/compiler-builtins/libm/src/math/erf.rs | 310 ++++++ library/compiler-builtins/libm/src/math/erff.rs | 222 ++++ library/compiler-builtins/libm/src/math/exp.rs | 150 +++ library/compiler-builtins/libm/src/math/exp10.rs | 23 + library/compiler-builtins/libm/src/math/exp10f.rs | 22 + library/compiler-builtins/libm/src/math/exp2.rs | 394 +++++++ library/compiler-builtins/libm/src/math/exp2f.rs | 135 +++ library/compiler-builtins/libm/src/math/expf.rs | 97 ++ library/compiler-builtins/libm/src/math/expm1.rs | 144 +++ library/compiler-builtins/libm/src/math/expm1f.rs | 130 +++ library/compiler-builtins/libm/src/math/expo2.rs | 14 + library/compiler-builtins/libm/src/math/fabs.rs | 116 ++ library/compiler-builtins/libm/src/math/fabsf.rs | 39 + .../compiler-builtins/libm/src/math/fabsf128.rs | 31 + library/compiler-builtins/libm/src/math/fabsf16.rs | 31 + library/compiler-builtins/libm/src/math/fdim.rs | 53 + library/compiler-builtins/libm/src/math/fdimf.rs | 12 + .../compiler-builtins/libm/src/math/fdimf128.rs | 12 + library/compiler-builtins/libm/src/math/fdimf16.rs | 12 + library/compiler-builtins/libm/src/math/floor.rs | 46 + library/compiler-builtins/libm/src/math/floorf.rs | 13 + .../compiler-builtins/libm/src/math/floorf128.rs | 7 + .../compiler-builtins/libm/src/math/floorf16.rs | 7 + library/compiler-builtins/libm/src/math/fma.rs | 397 +++++++ .../compiler-builtins/libm/src/math/fma_wide.rs | 104 ++ .../compiler-builtins/libm/src/math/fmin_fmax.rs | 167 +++ .../libm/src/math/fminimum_fmaximum.rs | 163 +++ .../libm/src/math/fminimum_fmaximum_num.rs | 163 +++ library/compiler-builtins/libm/src/math/fmod.rs | 25 + library/compiler-builtins/libm/src/math/fmodf.rs | 5 + .../compiler-builtins/libm/src/math/fmodf128.rs | 5 + library/compiler-builtins/libm/src/math/fmodf16.rs | 5 + library/compiler-builtins/libm/src/math/frexp.rs | 21 + library/compiler-builtins/libm/src/math/frexpf.rs | 22 + .../libm/src/math/generic/ceil.rs | 168 +++ .../libm/src/math/generic/copysign.rs | 11 + .../libm/src/math/generic/fabs.rs | 8 + .../libm/src/math/generic/fdim.rs | 6 + .../libm/src/math/generic/floor.rs | 151 +++ .../libm/src/math/generic/fmax.rs | 24 + .../libm/src/math/generic/fmaximum.rs | 28 + .../libm/src/math/generic/fmaximum_num.rs | 27 + .../libm/src/math/generic/fmin.rs | 24 + .../libm/src/math/generic/fminimum.rs | 28 + .../libm/src/math/generic/fminimum_num.rs | 27 + .../libm/src/math/generic/fmod.rs | 84 ++ .../compiler-builtins/libm/src/math/generic/mod.rs | 38 + .../libm/src/math/generic/rint.rs | 120 ++ .../libm/src/math/generic/round.rs | 83 ++ .../libm/src/math/generic/scalbn.rs | 121 ++ .../libm/src/math/generic/sqrt.rs | 537 +++++++++ .../libm/src/math/generic/trunc.rs | 138 +++ library/compiler-builtins/libm/src/math/hypot.rs | 74 ++ library/compiler-builtins/libm/src/math/hypotf.rs | 43 + library/compiler-builtins/libm/src/math/ilogb.rs | 28 + library/compiler-builtins/libm/src/math/ilogbf.rs | 28 + library/compiler-builtins/libm/src/math/j0.rs | 426 ++++++++ library/compiler-builtins/libm/src/math/j0f.rs | 363 ++++++ library/compiler-builtins/libm/src/math/j1.rs | 418 +++++++ library/compiler-builtins/libm/src/math/j1f.rs | 384 +++++++ library/compiler-builtins/libm/src/math/jn.rs | 339 ++++++ library/compiler-builtins/libm/src/math/jnf.rs | 253 +++++ library/compiler-builtins/libm/src/math/k_cos.rs | 62 ++ library/compiler-builtins/libm/src/math/k_cosf.rs | 29 + library/compiler-builtins/libm/src/math/k_expo2.rs | 14 + .../compiler-builtins/libm/src/math/k_expo2f.rs | 14 + library/compiler-builtins/libm/src/math/k_sin.rs | 53 + library/compiler-builtins/libm/src/math/k_sinf.rs | 30 + library/compiler-builtins/libm/src/math/k_tan.rs | 105 ++ library/compiler-builtins/libm/src/math/k_tanf.rs | 46 + library/compiler-builtins/libm/src/math/ldexp.rs | 21 + library/compiler-builtins/libm/src/math/ldexpf.rs | 4 + .../compiler-builtins/libm/src/math/ldexpf128.rs | 4 + .../compiler-builtins/libm/src/math/ldexpf16.rs | 4 + library/compiler-builtins/libm/src/math/lgamma.rs | 8 + .../compiler-builtins/libm/src/math/lgamma_r.rs | 321 ++++++ library/compiler-builtins/libm/src/math/lgammaf.rs | 8 + .../compiler-builtins/libm/src/math/lgammaf_r.rs | 256 +++++ library/compiler-builtins/libm/src/math/log.rs | 118 ++ library/compiler-builtins/libm/src/math/log10.rs | 118 ++ library/compiler-builtins/libm/src/math/log10f.rs | 92 ++ library/compiler-builtins/libm/src/math/log1p.rs | 140 +++ library/compiler-builtins/libm/src/math/log1pf.rs | 95 ++ library/compiler-builtins/libm/src/math/log2.rs | 107 ++ library/compiler-builtins/libm/src/math/log2f.rs | 88 ++ library/compiler-builtins/libm/src/math/logf.rs | 66 ++ library/compiler-builtins/libm/src/math/mod.rs | 396 +++++++ library/compiler-builtins/libm/src/math/modf.rs | 35 + library/compiler-builtins/libm/src/math/modff.rs | 34 + .../compiler-builtins/libm/src/math/nextafter.rs | 37 + .../compiler-builtins/libm/src/math/nextafterf.rs | 37 + library/compiler-builtins/libm/src/math/pow.rs | 607 ++++++++++ library/compiler-builtins/libm/src/math/powf.rs | 335 ++++++ .../compiler-builtins/libm/src/math/rem_pio2.rs | 223 ++++ .../libm/src/math/rem_pio2_large.rs | 468 ++++++++ .../compiler-builtins/libm/src/math/rem_pio2f.rs | 67 ++ .../compiler-builtins/libm/src/math/remainder.rs | 5 + .../compiler-builtins/libm/src/math/remainderf.rs | 5 + library/compiler-builtins/libm/src/math/remquo.rs | 106 ++ library/compiler-builtins/libm/src/math/remquof.rs | 93 ++ library/compiler-builtins/libm/src/math/rint.rs | 51 + library/compiler-builtins/libm/src/math/round.rs | 25 + .../compiler-builtins/libm/src/math/roundeven.rs | 36 + library/compiler-builtins/libm/src/math/roundf.rs | 5 + .../compiler-builtins/libm/src/math/roundf128.rs | 5 + .../compiler-builtins/libm/src/math/roundf16.rs | 5 + library/compiler-builtins/libm/src/math/scalbn.rs | 87 ++ library/compiler-builtins/libm/src/math/scalbnf.rs | 4 + .../compiler-builtins/libm/src/math/scalbnf128.rs | 4 + .../compiler-builtins/libm/src/math/scalbnf16.rs | 4 + library/compiler-builtins/libm/src/math/sin.rs | 95 ++ library/compiler-builtins/libm/src/math/sincos.rs | 137 +++ library/compiler-builtins/libm/src/math/sincosf.rs | 176 +++ library/compiler-builtins/libm/src/math/sinf.rs | 88 ++ library/compiler-builtins/libm/src/math/sinh.rs | 51 + library/compiler-builtins/libm/src/math/sinhf.rs | 30 + library/compiler-builtins/libm/src/math/sqrt.rs | 51 + library/compiler-builtins/libm/src/math/sqrtf.rs | 15 + .../compiler-builtins/libm/src/math/sqrtf128.rs | 5 + library/compiler-builtins/libm/src/math/sqrtf16.rs | 11 + .../compiler-builtins/libm/src/math/support/big.rs | 239 ++++ .../libm/src/math/support/big/tests.rs | 149 +++ .../compiler-builtins/libm/src/math/support/env.rs | 127 +++ .../libm/src/math/support/float_traits.rs | 484 ++++++++ .../libm/src/math/support/hex_float.rs | 1155 ++++++++++++++++++++ .../libm/src/math/support/int_traits.rs | 451 ++++++++ .../libm/src/math/support/macros.rs | 157 +++ .../compiler-builtins/libm/src/math/support/mod.rs | 29 + library/compiler-builtins/libm/src/math/tan.rs | 70 ++ library/compiler-builtins/libm/src/math/tanf.rs | 77 ++ library/compiler-builtins/libm/src/math/tanh.rs | 53 + library/compiler-builtins/libm/src/math/tanhf.rs | 38 + library/compiler-builtins/libm/src/math/tgamma.rs | 209 ++++ library/compiler-builtins/libm/src/math/tgammaf.rs | 7 + library/compiler-builtins/libm/src/math/trunc.rs | 53 + library/compiler-builtins/libm/src/math/truncf.rs | 23 + .../compiler-builtins/libm/src/math/truncf128.rs | 7 + .../compiler-builtins/libm/src/math/truncf16.rs | 7 + 351 files changed, 18417 insertions(+), 18417 deletions(-) create mode 100644 library/compiler-builtins/libm/Cargo.toml create mode 100644 library/compiler-builtins/libm/LICENSE.txt create mode 100644 library/compiler-builtins/libm/README.md create mode 100644 library/compiler-builtins/libm/build.rs create mode 100644 library/compiler-builtins/libm/configure.rs delete mode 100644 library/compiler-builtins/libm/libm/Cargo.toml delete mode 100644 library/compiler-builtins/libm/libm/LICENSE.txt delete mode 100644 library/compiler-builtins/libm/libm/README.md delete mode 100644 library/compiler-builtins/libm/libm/build.rs delete mode 100644 library/compiler-builtins/libm/libm/configure.rs delete mode 100644 library/compiler-builtins/libm/libm/src/lib.rs delete mode 100644 library/compiler-builtins/libm/libm/src/libm_helper.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/acos.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/acosf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/acosh.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/acoshf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/arch/aarch64.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/arch/i586.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/arch/i686.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/arch/mod.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/arch/wasm32.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/asin.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/asinf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/asinh.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/asinhf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/atan.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/atan2.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/atan2f.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/atanf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/atanh.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/atanhf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/cbrt.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/cbrtf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/ceil.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/copysign.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/copysignf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/copysignf128.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/copysignf16.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/cos.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/cosf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/cosh.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/coshf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/erf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/erff.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/exp.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/exp10.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/exp10f.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/exp2.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/exp2f.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/expf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/expm1.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/expm1f.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/expo2.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fabs.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fabsf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fabsf128.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fabsf16.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fdim.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fdimf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fdimf128.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fdimf16.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/floor.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/floorf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/floorf128.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/floorf16.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fma.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fma_wide.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fmin_fmax.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum_num.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fmod.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fmodf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fmodf128.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/fmodf16.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/frexp.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/frexpf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/ceil.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/copysign.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fabs.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fdim.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/floor.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fmax.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fmaximum.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fmaximum_num.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fmin.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fminimum.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fminimum_num.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/fmod.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/mod.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/rint.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/round.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/scalbn.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/sqrt.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/generic/trunc.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/hypot.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/hypotf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/ilogb.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/ilogbf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/j0.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/j0f.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/j1.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/j1f.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/jn.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/jnf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/k_cos.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/k_cosf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/k_expo2.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/k_expo2f.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/k_sin.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/k_sinf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/k_tan.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/k_tanf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/ldexp.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/ldexpf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/ldexpf128.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/ldexpf16.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/lgamma.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/lgamma_r.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/lgammaf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/lgammaf_r.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/log.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/log10.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/log10f.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/log1p.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/log1pf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/log2.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/log2f.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/logf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/mod.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/modf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/modff.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/nextafter.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/nextafterf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/pow.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/powf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/rem_pio2.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/rem_pio2_large.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/rem_pio2f.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/remainder.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/remainderf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/remquo.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/remquof.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/rint.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/round.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/roundeven.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/roundf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/roundf128.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/roundf16.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/scalbn.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/scalbnf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/scalbnf128.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/scalbnf16.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/sin.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/sincos.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/sincosf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/sinf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/sinh.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/sinhf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/sqrt.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/sqrtf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/sqrtf128.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/sqrtf16.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/support/big.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/support/big/tests.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/support/env.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/support/float_traits.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/support/hex_float.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/support/int_traits.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/support/macros.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/support/mod.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/tan.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/tanf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/tanh.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/tanhf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/tgamma.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/tgammaf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/trunc.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/truncf.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/truncf128.rs delete mode 100644 library/compiler-builtins/libm/libm/src/math/truncf16.rs create mode 100644 library/compiler-builtins/libm/src/lib.rs create mode 100644 library/compiler-builtins/libm/src/libm_helper.rs create mode 100644 library/compiler-builtins/libm/src/math/acos.rs create mode 100644 library/compiler-builtins/libm/src/math/acosf.rs create mode 100644 library/compiler-builtins/libm/src/math/acosh.rs create mode 100644 library/compiler-builtins/libm/src/math/acoshf.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/aarch64.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/i586.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/i686.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/mod.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/wasm32.rs create mode 100644 library/compiler-builtins/libm/src/math/asin.rs create mode 100644 library/compiler-builtins/libm/src/math/asinf.rs create mode 100644 library/compiler-builtins/libm/src/math/asinh.rs create mode 100644 library/compiler-builtins/libm/src/math/asinhf.rs create mode 100644 library/compiler-builtins/libm/src/math/atan.rs create mode 100644 library/compiler-builtins/libm/src/math/atan2.rs create mode 100644 library/compiler-builtins/libm/src/math/atan2f.rs create mode 100644 library/compiler-builtins/libm/src/math/atanf.rs create mode 100644 library/compiler-builtins/libm/src/math/atanh.rs create mode 100644 library/compiler-builtins/libm/src/math/atanhf.rs create mode 100644 library/compiler-builtins/libm/src/math/cbrt.rs create mode 100644 library/compiler-builtins/libm/src/math/cbrtf.rs create mode 100644 library/compiler-builtins/libm/src/math/ceil.rs create mode 100644 library/compiler-builtins/libm/src/math/copysign.rs create mode 100644 library/compiler-builtins/libm/src/math/copysignf.rs create mode 100644 library/compiler-builtins/libm/src/math/copysignf128.rs create mode 100644 library/compiler-builtins/libm/src/math/copysignf16.rs create mode 100644 library/compiler-builtins/libm/src/math/cos.rs create mode 100644 library/compiler-builtins/libm/src/math/cosf.rs create mode 100644 library/compiler-builtins/libm/src/math/cosh.rs create mode 100644 library/compiler-builtins/libm/src/math/coshf.rs create mode 100644 library/compiler-builtins/libm/src/math/erf.rs create mode 100644 library/compiler-builtins/libm/src/math/erff.rs create mode 100644 library/compiler-builtins/libm/src/math/exp.rs create mode 100644 library/compiler-builtins/libm/src/math/exp10.rs create mode 100644 library/compiler-builtins/libm/src/math/exp10f.rs create mode 100644 library/compiler-builtins/libm/src/math/exp2.rs create mode 100644 library/compiler-builtins/libm/src/math/exp2f.rs create mode 100644 library/compiler-builtins/libm/src/math/expf.rs create mode 100644 library/compiler-builtins/libm/src/math/expm1.rs create mode 100644 library/compiler-builtins/libm/src/math/expm1f.rs create mode 100644 library/compiler-builtins/libm/src/math/expo2.rs create mode 100644 library/compiler-builtins/libm/src/math/fabs.rs create mode 100644 library/compiler-builtins/libm/src/math/fabsf.rs create mode 100644 library/compiler-builtins/libm/src/math/fabsf128.rs create mode 100644 library/compiler-builtins/libm/src/math/fabsf16.rs create mode 100644 library/compiler-builtins/libm/src/math/fdim.rs create mode 100644 library/compiler-builtins/libm/src/math/fdimf.rs create mode 100644 library/compiler-builtins/libm/src/math/fdimf128.rs create mode 100644 library/compiler-builtins/libm/src/math/fdimf16.rs create mode 100644 library/compiler-builtins/libm/src/math/floor.rs create mode 100644 library/compiler-builtins/libm/src/math/floorf.rs create mode 100644 library/compiler-builtins/libm/src/math/floorf128.rs create mode 100644 library/compiler-builtins/libm/src/math/floorf16.rs create mode 100644 library/compiler-builtins/libm/src/math/fma.rs create mode 100644 library/compiler-builtins/libm/src/math/fma_wide.rs create mode 100644 library/compiler-builtins/libm/src/math/fmin_fmax.rs create mode 100644 library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs create mode 100644 library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs create mode 100644 library/compiler-builtins/libm/src/math/fmod.rs create mode 100644 library/compiler-builtins/libm/src/math/fmodf.rs create mode 100644 library/compiler-builtins/libm/src/math/fmodf128.rs create mode 100644 library/compiler-builtins/libm/src/math/fmodf16.rs create mode 100644 library/compiler-builtins/libm/src/math/frexp.rs create mode 100644 library/compiler-builtins/libm/src/math/frexpf.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/ceil.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/copysign.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fabs.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fdim.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/floor.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fmax.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fmaximum.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fmin.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fminimum.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fminimum_num.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fmod.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/mod.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/rint.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/round.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/scalbn.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/sqrt.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/trunc.rs create mode 100644 library/compiler-builtins/libm/src/math/hypot.rs create mode 100644 library/compiler-builtins/libm/src/math/hypotf.rs create mode 100644 library/compiler-builtins/libm/src/math/ilogb.rs create mode 100644 library/compiler-builtins/libm/src/math/ilogbf.rs create mode 100644 library/compiler-builtins/libm/src/math/j0.rs create mode 100644 library/compiler-builtins/libm/src/math/j0f.rs create mode 100644 library/compiler-builtins/libm/src/math/j1.rs create mode 100644 library/compiler-builtins/libm/src/math/j1f.rs create mode 100644 library/compiler-builtins/libm/src/math/jn.rs create mode 100644 library/compiler-builtins/libm/src/math/jnf.rs create mode 100644 library/compiler-builtins/libm/src/math/k_cos.rs create mode 100644 library/compiler-builtins/libm/src/math/k_cosf.rs create mode 100644 library/compiler-builtins/libm/src/math/k_expo2.rs create mode 100644 library/compiler-builtins/libm/src/math/k_expo2f.rs create mode 100644 library/compiler-builtins/libm/src/math/k_sin.rs create mode 100644 library/compiler-builtins/libm/src/math/k_sinf.rs create mode 100644 library/compiler-builtins/libm/src/math/k_tan.rs create mode 100644 library/compiler-builtins/libm/src/math/k_tanf.rs create mode 100644 library/compiler-builtins/libm/src/math/ldexp.rs create mode 100644 library/compiler-builtins/libm/src/math/ldexpf.rs create mode 100644 library/compiler-builtins/libm/src/math/ldexpf128.rs create mode 100644 library/compiler-builtins/libm/src/math/ldexpf16.rs create mode 100644 library/compiler-builtins/libm/src/math/lgamma.rs create mode 100644 library/compiler-builtins/libm/src/math/lgamma_r.rs create mode 100644 library/compiler-builtins/libm/src/math/lgammaf.rs create mode 100644 library/compiler-builtins/libm/src/math/lgammaf_r.rs create mode 100644 library/compiler-builtins/libm/src/math/log.rs create mode 100644 library/compiler-builtins/libm/src/math/log10.rs create mode 100644 library/compiler-builtins/libm/src/math/log10f.rs create mode 100644 library/compiler-builtins/libm/src/math/log1p.rs create mode 100644 library/compiler-builtins/libm/src/math/log1pf.rs create mode 100644 library/compiler-builtins/libm/src/math/log2.rs create mode 100644 library/compiler-builtins/libm/src/math/log2f.rs create mode 100644 library/compiler-builtins/libm/src/math/logf.rs create mode 100644 library/compiler-builtins/libm/src/math/mod.rs create mode 100644 library/compiler-builtins/libm/src/math/modf.rs create mode 100644 library/compiler-builtins/libm/src/math/modff.rs create mode 100644 library/compiler-builtins/libm/src/math/nextafter.rs create mode 100644 library/compiler-builtins/libm/src/math/nextafterf.rs create mode 100644 library/compiler-builtins/libm/src/math/pow.rs create mode 100644 library/compiler-builtins/libm/src/math/powf.rs create mode 100644 library/compiler-builtins/libm/src/math/rem_pio2.rs create mode 100644 library/compiler-builtins/libm/src/math/rem_pio2_large.rs create mode 100644 library/compiler-builtins/libm/src/math/rem_pio2f.rs create mode 100644 library/compiler-builtins/libm/src/math/remainder.rs create mode 100644 library/compiler-builtins/libm/src/math/remainderf.rs create mode 100644 library/compiler-builtins/libm/src/math/remquo.rs create mode 100644 library/compiler-builtins/libm/src/math/remquof.rs create mode 100644 library/compiler-builtins/libm/src/math/rint.rs create mode 100644 library/compiler-builtins/libm/src/math/round.rs create mode 100644 library/compiler-builtins/libm/src/math/roundeven.rs create mode 100644 library/compiler-builtins/libm/src/math/roundf.rs create mode 100644 library/compiler-builtins/libm/src/math/roundf128.rs create mode 100644 library/compiler-builtins/libm/src/math/roundf16.rs create mode 100644 library/compiler-builtins/libm/src/math/scalbn.rs create mode 100644 library/compiler-builtins/libm/src/math/scalbnf.rs create mode 100644 library/compiler-builtins/libm/src/math/scalbnf128.rs create mode 100644 library/compiler-builtins/libm/src/math/scalbnf16.rs create mode 100644 library/compiler-builtins/libm/src/math/sin.rs create mode 100644 library/compiler-builtins/libm/src/math/sincos.rs create mode 100644 library/compiler-builtins/libm/src/math/sincosf.rs create mode 100644 library/compiler-builtins/libm/src/math/sinf.rs create mode 100644 library/compiler-builtins/libm/src/math/sinh.rs create mode 100644 library/compiler-builtins/libm/src/math/sinhf.rs create mode 100644 library/compiler-builtins/libm/src/math/sqrt.rs create mode 100644 library/compiler-builtins/libm/src/math/sqrtf.rs create mode 100644 library/compiler-builtins/libm/src/math/sqrtf128.rs create mode 100644 library/compiler-builtins/libm/src/math/sqrtf16.rs create mode 100644 library/compiler-builtins/libm/src/math/support/big.rs create mode 100644 library/compiler-builtins/libm/src/math/support/big/tests.rs create mode 100644 library/compiler-builtins/libm/src/math/support/env.rs create mode 100644 library/compiler-builtins/libm/src/math/support/float_traits.rs create mode 100644 library/compiler-builtins/libm/src/math/support/hex_float.rs create mode 100644 library/compiler-builtins/libm/src/math/support/int_traits.rs create mode 100644 library/compiler-builtins/libm/src/math/support/macros.rs create mode 100644 library/compiler-builtins/libm/src/math/support/mod.rs create mode 100644 library/compiler-builtins/libm/src/math/tan.rs create mode 100644 library/compiler-builtins/libm/src/math/tanf.rs create mode 100644 library/compiler-builtins/libm/src/math/tanh.rs create mode 100644 library/compiler-builtins/libm/src/math/tanhf.rs create mode 100644 library/compiler-builtins/libm/src/math/tgamma.rs create mode 100644 library/compiler-builtins/libm/src/math/tgammaf.rs create mode 100644 library/compiler-builtins/libm/src/math/trunc.rs create mode 100644 library/compiler-builtins/libm/src/math/truncf.rs create mode 100644 library/compiler-builtins/libm/src/math/truncf128.rs create mode 100644 library/compiler-builtins/libm/src/math/truncf16.rs diff --git a/library/compiler-builtins/compiler-builtins/src/math.rs b/library/compiler-builtins/compiler-builtins/src/math.rs index bd52a749e39..722374f8e4f 100644 --- a/library/compiler-builtins/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/compiler-builtins/src/math.rs @@ -2,7 +2,7 @@ #[allow(dead_code)] #[allow(unused_imports)] #[allow(clippy::all)] -#[path = "../../libm/libm/src/math/mod.rs"] +#[path = "../../libm/src/math/mod.rs"] pub(crate) mod libm; macro_rules! libm_intrinsics { diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml new file mode 100644 index 00000000000..44154c1a8f5 --- /dev/null +++ b/library/compiler-builtins/libm/Cargo.toml @@ -0,0 +1,49 @@ +[package] +authors = ["Jorge Aparicio "] +categories = ["no-std"] +description = "libm in pure Rust" +documentation = "https://docs.rs/libm" +keywords = ["libm", "math"] +license = "MIT" +name = "libm" +readme = "README.md" +repository = "https://github.com/rust-lang/libm" +version = "0.2.11" +edition = "2021" +rust-version = "1.63" + +[features] +default = ["arch"] + +# Enable architecture-specific features such as SIMD or assembly routines. +arch = [] + +# This tells the compiler to assume that a Nightly toolchain is being used and +# that it should activate any useful Nightly things accordingly. +unstable = ["unstable-intrinsics", "unstable-float"] + +# Enable calls to functions in `core::intrinsics` +unstable-intrinsics = [] + +# Make some internal things public for testing. +unstable-public-internals = [] + +# Enable the nightly-only `f16` and `f128`. +unstable-float = [] + +# Used to prevent using any intrinsics or arch-specific code. +# +# HACK: this is a negative feature which is generally a bad idea in Cargo, but +# we need it to be able to forbid other features when this crate is used in +# Rust dependencies. Setting this overrides all features that may enable +# hard float operations. +force-soft-floats = [] + +[dev-dependencies] +no-panic = "0.1.35" + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = [ + # compiler-builtins sets this feature, but we use it in `libm` + 'cfg(feature, values("compiler-builtins"))', +] } diff --git a/library/compiler-builtins/libm/LICENSE.txt b/library/compiler-builtins/libm/LICENSE.txt new file mode 100644 index 00000000000..2f8e41f1474 --- /dev/null +++ b/library/compiler-builtins/libm/LICENSE.txt @@ -0,0 +1,258 @@ +rust-lang/libm as a whole is available for use under the MIT license: + +------------------------------------------------------------------------------ +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. +------------------------------------------------------------------------------ + +As a contributor, you agree that your code can be used under either the MIT +license or the Apache-2.0 license: + +------------------------------------------------------------------------------ + 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. + + 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. +------------------------------------------------------------------------------ + +This Rust library contains the following copyrights: + + Copyright (c) 2018 Jorge Aparicio + +Portions of this software are derived from third-party works licensed under +terms compatible with the above MIT license: + +* musl libc https://www.musl-libc.org/. This library contains the following + copyright: + + Copyright © 2005-2020 Rich Felker, et al. + +* The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH + routines are available under the MIT license on a per-file basis. + +The musl libc COPYRIGHT file also includes the following notice relevant to +math portions of the library: + +------------------------------------------------------------------------------ +Much of the math library code (src/math/* and src/complex/*) is +Copyright © 1993,2004 Sun Microsystems or +Copyright © 2003-2011 David Schultz or +Copyright © 2003-2009 Steven G. Kargl or +Copyright © 2003-2009 Bruce D. Evans or +Copyright © 2008 Stephen L. Moshier or +Copyright © 2017-2018 Arm Limited +and labelled as such in comments in the individual source files. All +have been licensed under extremely permissive terms. +------------------------------------------------------------------------------ + +Copyright notices are retained in src/* files where relevant. diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md new file mode 100644 index 00000000000..52d760a4f15 --- /dev/null +++ b/library/compiler-builtins/libm/README.md @@ -0,0 +1,56 @@ +# `libm` + +A port of [MUSL]'s libm to Rust. + +[MUSL]: https://musl.libc.org/ + +## Goals + +The short term goal of this library is to [enable math support (e.g. `sin`, `atan2`) for the +`wasm32-unknown-unknown` target][wasm] (cf. [rust-lang/compiler-builtins][pr]). The longer +term goal is to enable [math support in the `core` crate][core]. + +[wasm]: https://github.com/rust-lang/libm/milestone/1 +[pr]: https://github.com/rust-lang/compiler-builtins/pull/248 +[core]: https://github.com/rust-lang/libm/milestone/2 + +## Already usable + +This crate is [on crates.io] and can be used today in stable `#![no_std]` programs. + +The API documentation can be found [here](https://docs.rs/libm). + +[on crates.io]: https://crates.io/crates/libm + +## Benchmark +[benchmark]: #benchmark + +The benchmarks are located in `crates/libm-bench` and require a nightly Rust toolchain. +To run all benchmarks: + +> cargo +nightly bench --all + +## Contributing + +Please check [CONTRIBUTING.md](CONTRIBUTING.md) + +## Minimum Rust version policy + +This crate supports rustc 1.63 and newer. + +## License + +Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or +https://opensource.org/licenses/MIT). + + +### Contribution + +Contributions are licensed under both the MIT license and the Apache License, +Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or +https://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state +otherwise, any contribution intentionally submitted for inclusion in the work +by you, as defined in the Apache-2.0 license, shall be dual licensed as +mentioned, without any additional terms or conditions. + +See `LICENSE.txt` for full details. diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs new file mode 100644 index 00000000000..07d08ed4364 --- /dev/null +++ b/library/compiler-builtins/libm/build.rs @@ -0,0 +1,18 @@ +use std::env; + +mod configure; + +fn main() { + let cfg = configure::Config::from_env(); + + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=configure.rs"); + println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); + + // If set, enable `no-panic`. Requires LTO (`release-opt` profile). + if env::var("ENSURE_NO_PANIC").is_ok() { + println!("cargo:rustc-cfg=assert_no_panic"); + } + + configure::emit_libm_config(&cfg); +} diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs new file mode 100644 index 00000000000..8b8ba981565 --- /dev/null +++ b/library/compiler-builtins/libm/configure.rs @@ -0,0 +1,183 @@ +// Configuration shared with both libm and libm-test + +use std::env; +use std::path::PathBuf; + +#[allow(dead_code)] +pub struct Config { + pub manifest_dir: PathBuf, + pub out_dir: PathBuf, + pub opt_level: String, + pub cargo_features: Vec, + pub target_arch: String, + pub target_env: String, + pub target_family: Option, + pub target_os: String, + pub target_string: String, + pub target_vendor: String, + pub target_features: Vec, +} + +impl Config { + pub fn from_env() -> Self { + let target_features = env::var("CARGO_CFG_TARGET_FEATURE") + .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) + .unwrap_or_default(); + let cargo_features = env::vars() + .filter_map(|(name, _value)| name.strip_prefix("CARGO_FEATURE_").map(ToOwned::to_owned)) + .map(|s| s.to_lowercase().replace("_", "-")) + .collect(); + + Self { + manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()), + out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), + opt_level: env::var("OPT_LEVEL").unwrap(), + cargo_features, + target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), + target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), + target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(), + target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + target_string: env::var("TARGET").unwrap(), + target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), + target_features, + } + } +} + +/// Libm gets most config options made available. +#[allow(dead_code)] +pub fn emit_libm_config(cfg: &Config) { + emit_intrinsics_cfg(); + emit_arch_cfg(); + emit_optimization_cfg(cfg); + emit_cfg_shorthands(cfg); + emit_cfg_env(cfg); + emit_f16_f128_cfg(cfg); +} + +/// Tests don't need most feature-related config. +#[allow(dead_code)] +pub fn emit_test_config(cfg: &Config) { + emit_optimization_cfg(cfg); + emit_cfg_shorthands(cfg); + emit_cfg_env(cfg); + emit_f16_f128_cfg(cfg); +} + +/// Simplify the feature logic for enabling intrinsics so code only needs to use +/// `cfg(intrinsics_enabled)`. +fn emit_intrinsics_cfg() { + println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)"); + + // Disabled by default; `unstable-intrinsics` enables again; `force-soft-floats` overrides + // to disable. + if cfg!(feature = "unstable-intrinsics") && !cfg!(feature = "force-soft-floats") { + println!("cargo:rustc-cfg=intrinsics_enabled"); + } +} + +/// Simplify the feature logic for enabling arch-specific features so code only needs to use +/// `cfg(arch_enabled)`. +fn emit_arch_cfg() { + println!("cargo:rustc-check-cfg=cfg(arch_enabled)"); + + // Enabled by default via the "arch" feature, `force-soft-floats` overrides to disable. + if cfg!(feature = "arch") && !cfg!(feature = "force-soft-floats") { + println!("cargo:rustc-cfg=arch_enabled"); + } +} + +/// Some tests are extremely slow. Emit a config option based on optimization level. +fn emit_optimization_cfg(cfg: &Config) { + println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); + + if !matches!(cfg.opt_level.as_str(), "0" | "1") { + println!("cargo:rustc-cfg=optimizations_enabled"); + } +} + +/// Provide an alias for common longer config combinations. +fn emit_cfg_shorthands(cfg: &Config) { + println!("cargo:rustc-check-cfg=cfg(x86_no_sse)"); + if cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse") { + // Shorthand to detect i586 targets + println!("cargo:rustc-cfg=x86_no_sse"); + } +} + +/// Reemit config that we make use of for test logging. +fn emit_cfg_env(cfg: &Config) { + println!("cargo:rustc-env=CFG_CARGO_FEATURES={:?}", cfg.cargo_features); + println!("cargo:rustc-env=CFG_OPT_LEVEL={}", cfg.opt_level); + println!("cargo:rustc-env=CFG_TARGET_FEATURES={:?}", cfg.target_features); +} + +/// Configure whether or not `f16` and `f128` support should be enabled. +fn emit_f16_f128_cfg(cfg: &Config) { + println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); + println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); + + // `unstable-float` enables these features. + if !cfg!(feature = "unstable-float") { + return; + } + + // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means + // that the backend will not crash when using these types and generates code that can be called + // without crashing (no infinite recursion). This does not mean that the platform doesn't have + // ABI or other bugs. + // + // We do this here rather than in `rust-lang/rust` because configuring via cargo features is + // not straightforward. + // + // Original source of this list: + // + let f16_enabled = match cfg.target_arch.as_str() { + // Unsupported + "arm64ec" => false, + // Selection failure + "s390x" => false, + // Infinite recursion + // FIXME(llvm): loongarch fixed by + "csky" => false, + "hexagon" => false, + "loongarch64" => false, + "mips" | "mips64" | "mips32r6" | "mips64r6" => false, + "powerpc" | "powerpc64" => false, + "sparc" | "sparc64" => false, + "wasm32" | "wasm64" => false, + // Most everything else works as of LLVM 19 + _ => true, + }; + + let f128_enabled = match cfg.target_arch.as_str() { + // Unsupported (libcall is not supported) + "amdgpu" => false, + // Unsupported + "arm64ec" => false, + // Selection failure + "mips64" | "mips64r6" => false, + // Selection failure + "nvptx64" => false, + // Selection failure + "powerpc64" if &cfg.target_os == "aix" => false, + // Selection failure + "sparc" => false, + // Most everything else works as of LLVM 19 + _ => true, + }; + + // If the feature is set, disable these types. + let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); + + println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); + println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); + + if f16_enabled && !disable_both { + println!("cargo:rustc-cfg=f16_enabled"); + } + + if f128_enabled && !disable_both { + println!("cargo:rustc-cfg=f128_enabled"); + } +} diff --git a/library/compiler-builtins/libm/libm/Cargo.toml b/library/compiler-builtins/libm/libm/Cargo.toml deleted file mode 100644 index 44154c1a8f5..00000000000 --- a/library/compiler-builtins/libm/libm/Cargo.toml +++ /dev/null @@ -1,49 +0,0 @@ -[package] -authors = ["Jorge Aparicio "] -categories = ["no-std"] -description = "libm in pure Rust" -documentation = "https://docs.rs/libm" -keywords = ["libm", "math"] -license = "MIT" -name = "libm" -readme = "README.md" -repository = "https://github.com/rust-lang/libm" -version = "0.2.11" -edition = "2021" -rust-version = "1.63" - -[features] -default = ["arch"] - -# Enable architecture-specific features such as SIMD or assembly routines. -arch = [] - -# This tells the compiler to assume that a Nightly toolchain is being used and -# that it should activate any useful Nightly things accordingly. -unstable = ["unstable-intrinsics", "unstable-float"] - -# Enable calls to functions in `core::intrinsics` -unstable-intrinsics = [] - -# Make some internal things public for testing. -unstable-public-internals = [] - -# Enable the nightly-only `f16` and `f128`. -unstable-float = [] - -# Used to prevent using any intrinsics or arch-specific code. -# -# HACK: this is a negative feature which is generally a bad idea in Cargo, but -# we need it to be able to forbid other features when this crate is used in -# Rust dependencies. Setting this overrides all features that may enable -# hard float operations. -force-soft-floats = [] - -[dev-dependencies] -no-panic = "0.1.35" - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = [ - # compiler-builtins sets this feature, but we use it in `libm` - 'cfg(feature, values("compiler-builtins"))', -] } diff --git a/library/compiler-builtins/libm/libm/LICENSE.txt b/library/compiler-builtins/libm/libm/LICENSE.txt deleted file mode 100644 index 2f8e41f1474..00000000000 --- a/library/compiler-builtins/libm/libm/LICENSE.txt +++ /dev/null @@ -1,258 +0,0 @@ -rust-lang/libm as a whole is available for use under the MIT license: - ------------------------------------------------------------------------------- -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. ------------------------------------------------------------------------------- - -As a contributor, you agree that your code can be used under either the MIT -license or the Apache-2.0 license: - ------------------------------------------------------------------------------- - 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. - - 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. ------------------------------------------------------------------------------- - -This Rust library contains the following copyrights: - - Copyright (c) 2018 Jorge Aparicio - -Portions of this software are derived from third-party works licensed under -terms compatible with the above MIT license: - -* musl libc https://www.musl-libc.org/. This library contains the following - copyright: - - Copyright © 2005-2020 Rich Felker, et al. - -* The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH - routines are available under the MIT license on a per-file basis. - -The musl libc COPYRIGHT file also includes the following notice relevant to -math portions of the library: - ------------------------------------------------------------------------------- -Much of the math library code (src/math/* and src/complex/*) is -Copyright © 1993,2004 Sun Microsystems or -Copyright © 2003-2011 David Schultz or -Copyright © 2003-2009 Steven G. Kargl or -Copyright © 2003-2009 Bruce D. Evans or -Copyright © 2008 Stephen L. Moshier or -Copyright © 2017-2018 Arm Limited -and labelled as such in comments in the individual source files. All -have been licensed under extremely permissive terms. ------------------------------------------------------------------------------- - -Copyright notices are retained in src/* files where relevant. diff --git a/library/compiler-builtins/libm/libm/README.md b/library/compiler-builtins/libm/libm/README.md deleted file mode 100644 index 52d760a4f15..00000000000 --- a/library/compiler-builtins/libm/libm/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# `libm` - -A port of [MUSL]'s libm to Rust. - -[MUSL]: https://musl.libc.org/ - -## Goals - -The short term goal of this library is to [enable math support (e.g. `sin`, `atan2`) for the -`wasm32-unknown-unknown` target][wasm] (cf. [rust-lang/compiler-builtins][pr]). The longer -term goal is to enable [math support in the `core` crate][core]. - -[wasm]: https://github.com/rust-lang/libm/milestone/1 -[pr]: https://github.com/rust-lang/compiler-builtins/pull/248 -[core]: https://github.com/rust-lang/libm/milestone/2 - -## Already usable - -This crate is [on crates.io] and can be used today in stable `#![no_std]` programs. - -The API documentation can be found [here](https://docs.rs/libm). - -[on crates.io]: https://crates.io/crates/libm - -## Benchmark -[benchmark]: #benchmark - -The benchmarks are located in `crates/libm-bench` and require a nightly Rust toolchain. -To run all benchmarks: - -> cargo +nightly bench --all - -## Contributing - -Please check [CONTRIBUTING.md](CONTRIBUTING.md) - -## Minimum Rust version policy - -This crate supports rustc 1.63 and newer. - -## License - -Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or -https://opensource.org/licenses/MIT). - - -### Contribution - -Contributions are licensed under both the MIT license and the Apache License, -Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or -https://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state -otherwise, any contribution intentionally submitted for inclusion in the work -by you, as defined in the Apache-2.0 license, shall be dual licensed as -mentioned, without any additional terms or conditions. - -See `LICENSE.txt` for full details. diff --git a/library/compiler-builtins/libm/libm/build.rs b/library/compiler-builtins/libm/libm/build.rs deleted file mode 100644 index 07d08ed4364..00000000000 --- a/library/compiler-builtins/libm/libm/build.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::env; - -mod configure; - -fn main() { - let cfg = configure::Config::from_env(); - - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-changed=configure.rs"); - println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); - - // If set, enable `no-panic`. Requires LTO (`release-opt` profile). - if env::var("ENSURE_NO_PANIC").is_ok() { - println!("cargo:rustc-cfg=assert_no_panic"); - } - - configure::emit_libm_config(&cfg); -} diff --git a/library/compiler-builtins/libm/libm/configure.rs b/library/compiler-builtins/libm/libm/configure.rs deleted file mode 100644 index 8b8ba981565..00000000000 --- a/library/compiler-builtins/libm/libm/configure.rs +++ /dev/null @@ -1,183 +0,0 @@ -// Configuration shared with both libm and libm-test - -use std::env; -use std::path::PathBuf; - -#[allow(dead_code)] -pub struct Config { - pub manifest_dir: PathBuf, - pub out_dir: PathBuf, - pub opt_level: String, - pub cargo_features: Vec, - pub target_arch: String, - pub target_env: String, - pub target_family: Option, - pub target_os: String, - pub target_string: String, - pub target_vendor: String, - pub target_features: Vec, -} - -impl Config { - pub fn from_env() -> Self { - let target_features = env::var("CARGO_CFG_TARGET_FEATURE") - .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) - .unwrap_or_default(); - let cargo_features = env::vars() - .filter_map(|(name, _value)| name.strip_prefix("CARGO_FEATURE_").map(ToOwned::to_owned)) - .map(|s| s.to_lowercase().replace("_", "-")) - .collect(); - - Self { - manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()), - out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), - opt_level: env::var("OPT_LEVEL").unwrap(), - cargo_features, - target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), - target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), - target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(), - target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), - target_string: env::var("TARGET").unwrap(), - target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), - target_features, - } - } -} - -/// Libm gets most config options made available. -#[allow(dead_code)] -pub fn emit_libm_config(cfg: &Config) { - emit_intrinsics_cfg(); - emit_arch_cfg(); - emit_optimization_cfg(cfg); - emit_cfg_shorthands(cfg); - emit_cfg_env(cfg); - emit_f16_f128_cfg(cfg); -} - -/// Tests don't need most feature-related config. -#[allow(dead_code)] -pub fn emit_test_config(cfg: &Config) { - emit_optimization_cfg(cfg); - emit_cfg_shorthands(cfg); - emit_cfg_env(cfg); - emit_f16_f128_cfg(cfg); -} - -/// Simplify the feature logic for enabling intrinsics so code only needs to use -/// `cfg(intrinsics_enabled)`. -fn emit_intrinsics_cfg() { - println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)"); - - // Disabled by default; `unstable-intrinsics` enables again; `force-soft-floats` overrides - // to disable. - if cfg!(feature = "unstable-intrinsics") && !cfg!(feature = "force-soft-floats") { - println!("cargo:rustc-cfg=intrinsics_enabled"); - } -} - -/// Simplify the feature logic for enabling arch-specific features so code only needs to use -/// `cfg(arch_enabled)`. -fn emit_arch_cfg() { - println!("cargo:rustc-check-cfg=cfg(arch_enabled)"); - - // Enabled by default via the "arch" feature, `force-soft-floats` overrides to disable. - if cfg!(feature = "arch") && !cfg!(feature = "force-soft-floats") { - println!("cargo:rustc-cfg=arch_enabled"); - } -} - -/// Some tests are extremely slow. Emit a config option based on optimization level. -fn emit_optimization_cfg(cfg: &Config) { - println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); - - if !matches!(cfg.opt_level.as_str(), "0" | "1") { - println!("cargo:rustc-cfg=optimizations_enabled"); - } -} - -/// Provide an alias for common longer config combinations. -fn emit_cfg_shorthands(cfg: &Config) { - println!("cargo:rustc-check-cfg=cfg(x86_no_sse)"); - if cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse") { - // Shorthand to detect i586 targets - println!("cargo:rustc-cfg=x86_no_sse"); - } -} - -/// Reemit config that we make use of for test logging. -fn emit_cfg_env(cfg: &Config) { - println!("cargo:rustc-env=CFG_CARGO_FEATURES={:?}", cfg.cargo_features); - println!("cargo:rustc-env=CFG_OPT_LEVEL={}", cfg.opt_level); - println!("cargo:rustc-env=CFG_TARGET_FEATURES={:?}", cfg.target_features); -} - -/// Configure whether or not `f16` and `f128` support should be enabled. -fn emit_f16_f128_cfg(cfg: &Config) { - println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); - println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); - - // `unstable-float` enables these features. - if !cfg!(feature = "unstable-float") { - return; - } - - // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means - // that the backend will not crash when using these types and generates code that can be called - // without crashing (no infinite recursion). This does not mean that the platform doesn't have - // ABI or other bugs. - // - // We do this here rather than in `rust-lang/rust` because configuring via cargo features is - // not straightforward. - // - // Original source of this list: - // - let f16_enabled = match cfg.target_arch.as_str() { - // Unsupported - "arm64ec" => false, - // Selection failure - "s390x" => false, - // Infinite recursion - // FIXME(llvm): loongarch fixed by - "csky" => false, - "hexagon" => false, - "loongarch64" => false, - "mips" | "mips64" | "mips32r6" | "mips64r6" => false, - "powerpc" | "powerpc64" => false, - "sparc" | "sparc64" => false, - "wasm32" | "wasm64" => false, - // Most everything else works as of LLVM 19 - _ => true, - }; - - let f128_enabled = match cfg.target_arch.as_str() { - // Unsupported (libcall is not supported) - "amdgpu" => false, - // Unsupported - "arm64ec" => false, - // Selection failure - "mips64" | "mips64r6" => false, - // Selection failure - "nvptx64" => false, - // Selection failure - "powerpc64" if &cfg.target_os == "aix" => false, - // Selection failure - "sparc" => false, - // Most everything else works as of LLVM 19 - _ => true, - }; - - // If the feature is set, disable these types. - let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); - - println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); - println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); - - if f16_enabled && !disable_both { - println!("cargo:rustc-cfg=f16_enabled"); - } - - if f128_enabled && !disable_both { - println!("cargo:rustc-cfg=f128_enabled"); - } -} diff --git a/library/compiler-builtins/libm/libm/src/lib.rs b/library/compiler-builtins/libm/libm/src/lib.rs deleted file mode 100644 index 7e56bd0796c..00000000000 --- a/library/compiler-builtins/libm/libm/src/lib.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! libm in pure Rust -#![no_std] -#![cfg_attr(intrinsics_enabled, allow(internal_features))] -#![cfg_attr(intrinsics_enabled, feature(core_intrinsics))] -#![cfg_attr(all(intrinsics_enabled, target_family = "wasm"), feature(wasm_numeric_instr))] -#![cfg_attr(f128_enabled, feature(f128))] -#![cfg_attr(f16_enabled, feature(f16))] -#![allow(clippy::assign_op_pattern)] -#![allow(clippy::deprecated_cfg_attr)] -#![allow(clippy::eq_op)] -#![allow(clippy::excessive_precision)] -#![allow(clippy::float_cmp)] -#![allow(clippy::int_plus_one)] -#![allow(clippy::many_single_char_names)] -#![allow(clippy::mixed_case_hex_literals)] -#![allow(clippy::needless_late_init)] -#![allow(clippy::needless_return)] -#![allow(clippy::unreadable_literal)] -#![allow(clippy::zero_divided_by_zero)] -#![forbid(unsafe_op_in_unsafe_fn)] - -mod libm_helper; -mod math; - -use core::{f32, f64}; - -pub use libm_helper::*; - -pub use self::math::*; diff --git a/library/compiler-builtins/libm/libm/src/libm_helper.rs b/library/compiler-builtins/libm/libm/src/libm_helper.rs deleted file mode 100644 index dfa1ff77bf2..00000000000 --- a/library/compiler-builtins/libm/libm/src/libm_helper.rs +++ /dev/null @@ -1,244 +0,0 @@ -use core::marker::PhantomData; - -use crate::*; - -/// Generic helper for libm functions, abstracting over f32 and f64.
-/// # Type Parameter: -/// - `T`: Either `f32` or `f64` -/// -/// # Examples -/// ```rust -/// use libm::{self, Libm}; -/// -/// const PI_F32: f32 = 3.1415927410e+00; -/// const PI_F64: f64 = 3.1415926535897931160e+00; -/// -/// assert!(Libm::::cos(0.0f32) == libm::cosf(0.0)); -/// assert!(Libm::::sin(PI_F32) == libm::sinf(PI_F32)); -/// -/// assert!(Libm::::cos(0.0f64) == libm::cos(0.0)); -/// assert!(Libm::::sin(PI_F64) == libm::sin(PI_F64)); -/// ``` -pub struct Libm(PhantomData); - -macro_rules! libm_helper { - ($t:ident, funcs: $funcs:tt) => { - impl Libm<$t> { - #![allow(unused_parens)] - - libm_helper! { $funcs } - } - }; - - ({$($func:tt;)*}) => { - $( - libm_helper! { $func } - )* - }; - - ((fn $func:ident($($arg:ident: $arg_typ:ty),*) -> ($($ret_typ:ty),*); => $libm_fn:ident)) => { - #[inline(always)] - pub fn $func($($arg: $arg_typ),*) -> ($($ret_typ),*) { - $libm_fn($($arg),*) - } - }; -} - -// verify-apilist-start -libm_helper! { - f32, - funcs: { - // verify-sorted-start - (fn acos(x: f32) -> (f32); => acosf); - (fn acosh(x: f32) -> (f32); => acoshf); - (fn asin(x: f32) -> (f32); => asinf); - (fn asinh(x: f32) -> (f32); => asinhf); - (fn atan(x: f32) -> (f32); => atanf); - (fn atan2(y: f32, x: f32) -> (f32); => atan2f); - (fn atanh(x: f32) -> (f32); => atanhf); - (fn cbrt(x: f32) -> (f32); => cbrtf); - (fn ceil(x: f32) -> (f32); => ceilf); - (fn copysign(x: f32, y: f32) -> (f32); => copysignf); - (fn cos(x: f32) -> (f32); => cosf); - (fn cosh(x: f32) -> (f32); => coshf); - (fn erf(x: f32) -> (f32); => erff); - (fn erfc(x: f32) -> (f32); => erfcf); - (fn exp(x: f32) -> (f32); => expf); - (fn exp10(x: f32) -> (f32); => exp10f); - (fn exp2(x: f32) -> (f32); => exp2f); - (fn expm1(x: f32) -> (f32); => expm1f); - (fn fabs(x: f32) -> (f32); => fabsf); - (fn fdim(x: f32, y: f32) -> (f32); => fdimf); - (fn floor(x: f32) -> (f32); => floorf); - (fn fma(x: f32, y: f32, z: f32) -> (f32); => fmaf); - (fn fmax(x: f32, y: f32) -> (f32); => fmaxf); - (fn fmin(x: f32, y: f32) -> (f32); => fminf); - (fn fmod(x: f32, y: f32) -> (f32); => fmodf); - (fn frexp(x: f32) -> (f32, i32); => frexpf); - (fn hypot(x: f32, y: f32) -> (f32); => hypotf); - (fn ilogb(x: f32) -> (i32); => ilogbf); - (fn j0(x: f32) -> (f32); => j0f); - (fn j1(x: f32) -> (f32); => j1f); - (fn jn(n: i32, x: f32) -> (f32); => jnf); - (fn ldexp(x: f32, n: i32) -> (f32); => ldexpf); - (fn lgamma(x: f32) -> (f32); => lgammaf); - (fn lgamma_r(x: f32) -> (f32, i32); => lgammaf_r); - (fn log(x: f32) -> (f32); => logf); - (fn log10(x: f32) -> (f32); => log10f); - (fn log1p(x: f32) -> (f32); => log1pf); - (fn log2(x: f32) -> (f32); => log2f); - (fn modf(x: f32) -> (f32, f32); => modff); - (fn nextafter(x: f32, y: f32) -> (f32); => nextafterf); - (fn pow(x: f32, y: f32) -> (f32); => powf); - (fn remainder(x: f32, y: f32) -> (f32); => remainderf); - (fn remquo(x: f32, y: f32) -> (f32, i32); => remquof); - (fn rint(x: f32) -> (f32); => rintf); - (fn round(x: f32) -> (f32); => roundf); - (fn roundeven(x: f32) -> (f32); => roundevenf); - (fn scalbn(x: f32, n: i32) -> (f32); => scalbnf); - (fn sin(x: f32) -> (f32); => sinf); - (fn sincos(x: f32) -> (f32, f32); => sincosf); - (fn sinh(x: f32) -> (f32); => sinhf); - (fn sqrt(x: f32) -> (f32); => sqrtf); - (fn tan(x: f32) -> (f32); => tanf); - (fn tanh(x: f32) -> (f32); => tanhf); - (fn tgamma(x: f32) -> (f32); => tgammaf); - (fn trunc(x: f32) -> (f32); => truncf); - (fn y0(x: f32) -> (f32); => y0f); - (fn y1(x: f32) -> (f32); => y1f); - (fn yn(n: i32, x: f32) -> (f32); => ynf); - // verify-sorted-end - } -} - -libm_helper! { - f64, - funcs: { - // verify-sorted-start - (fn acos(x: f64) -> (f64); => acos); - (fn acosh(x: f64) -> (f64); => acosh); - (fn asin(x: f64) -> (f64); => asin); - (fn asinh(x: f64) -> (f64); => asinh); - (fn atan(x: f64) -> (f64); => atan); - (fn atan2(y: f64, x: f64) -> (f64); => atan2); - (fn atanh(x: f64) -> (f64); => atanh); - (fn cbrt(x: f64) -> (f64); => cbrt); - (fn ceil(x: f64) -> (f64); => ceil); - (fn copysign(x: f64, y: f64) -> (f64); => copysign); - (fn cos(x: f64) -> (f64); => cos); - (fn cosh(x: f64) -> (f64); => cosh); - (fn erf(x: f64) -> (f64); => erf); - (fn erfc(x: f64) -> (f64); => erfc); - (fn exp(x: f64) -> (f64); => exp); - (fn exp10(x: f64) -> (f64); => exp10); - (fn exp2(x: f64) -> (f64); => exp2); - (fn expm1(x: f64) -> (f64); => expm1); - (fn fabs(x: f64) -> (f64); => fabs); - (fn fdim(x: f64, y: f64) -> (f64); => fdim); - (fn floor(x: f64) -> (f64); => floor); - (fn fma(x: f64, y: f64, z: f64) -> (f64); => fma); - (fn fmax(x: f64, y: f64) -> (f64); => fmax); - (fn fmaximum(x: f64, y: f64) -> (f64); => fmaximum); - (fn fmaximum_num(x: f64, y: f64) -> (f64); => fmaximum_num); - (fn fmaximum_numf(x: f32, y: f32) -> (f32); => fmaximum_numf); - (fn fmaximumf(x: f32, y: f32) -> (f32); => fmaximumf); - (fn fmin(x: f64, y: f64) -> (f64); => fmin); - (fn fminimum(x: f64, y: f64) -> (f64); => fminimum); - (fn fminimum_num(x: f64, y: f64) -> (f64); => fminimum_num); - (fn fminimum_numf(x: f32, y: f32) -> (f32); => fminimum_numf); - (fn fminimumf(x: f32, y: f32) -> (f32); => fminimumf); - (fn fmod(x: f64, y: f64) -> (f64); => fmod); - (fn frexp(x: f64) -> (f64, i32); => frexp); - (fn hypot(x: f64, y: f64) -> (f64); => hypot); - (fn ilogb(x: f64) -> (i32); => ilogb); - (fn j0(x: f64) -> (f64); => j0); - (fn j1(x: f64) -> (f64); => j1); - (fn jn(n: i32, x: f64) -> (f64); => jn); - (fn ldexp(x: f64, n: i32) -> (f64); => ldexp); - (fn lgamma(x: f64) -> (f64); => lgamma); - (fn lgamma_r(x: f64) -> (f64, i32); => lgamma_r); - (fn log(x: f64) -> (f64); => log); - (fn log10(x: f64) -> (f64); => log10); - (fn log1p(x: f64) -> (f64); => log1p); - (fn log2(x: f64) -> (f64); => log2); - (fn modf(x: f64) -> (f64, f64); => modf); - (fn nextafter(x: f64, y: f64) -> (f64); => nextafter); - (fn pow(x: f64, y: f64) -> (f64); => pow); - (fn remainder(x: f64, y: f64) -> (f64); => remainder); - (fn remquo(x: f64, y: f64) -> (f64, i32); => remquo); - (fn rint(x: f64) -> (f64); => rint); - (fn round(x: f64) -> (f64); => round); - (fn roundevem(x: f64) -> (f64); => roundeven); - (fn scalbn(x: f64, n: i32) -> (f64); => scalbn); - (fn sin(x: f64) -> (f64); => sin); - (fn sincos(x: f64) -> (f64, f64); => sincos); - (fn sinh(x: f64) -> (f64); => sinh); - (fn sqrt(x: f64) -> (f64); => sqrt); - (fn tan(x: f64) -> (f64); => tan); - (fn tanh(x: f64) -> (f64); => tanh); - (fn tgamma(x: f64) -> (f64); => tgamma); - (fn trunc(x: f64) -> (f64); => trunc); - (fn y0(x: f64) -> (f64); => y0); - (fn y1(x: f64) -> (f64); => y1); - (fn yn(n: i32, x: f64) -> (f64); => yn); - // verify-sorted-end - } -} - -#[cfg(f16_enabled)] -libm_helper! { - f16, - funcs: { - // verify-sorted-start - (fn ceil(x: f16) -> (f16); => ceilf16); - (fn copysign(x: f16, y: f16) -> (f16); => copysignf16); - (fn fabs(x: f16) -> (f16); => fabsf16); - (fn fdim(x: f16, y: f16) -> (f16); => fdimf16); - (fn floor(x: f16) -> (f16); => floorf16); - (fn fmax(x: f16, y: f16) -> (f16); => fmaxf16); - (fn fmaximum_num(x: f16, y: f16) -> (f16); => fmaximum_numf16); - (fn fmaximumf16(x: f16, y: f16) -> (f16); => fmaximumf16); - (fn fmin(x: f16, y: f16) -> (f16); => fminf16); - (fn fminimum(x: f16, y: f16) -> (f16); => fminimumf16); - (fn fminimum_num(x: f16, y: f16) -> (f16); => fminimum_numf16); - (fn fmod(x: f16, y: f16) -> (f16); => fmodf16); - (fn ldexp(x: f16, n: i32) -> (f16); => ldexpf16); - (fn rint(x: f16) -> (f16); => rintf16); - (fn round(x: f16) -> (f16); => roundf16); - (fn roundeven(x: f16) -> (f16); => roundevenf16); - (fn scalbn(x: f16, n: i32) -> (f16); => scalbnf16); - (fn sqrtf(x: f16) -> (f16); => sqrtf16); - (fn truncf(x: f16) -> (f16); => truncf16); - // verify-sorted-end - } -} - -#[cfg(f128_enabled)] -libm_helper! { - f128, - funcs: { - // verify-sorted-start - (fn ceil(x: f128) -> (f128); => ceilf128); - (fn copysign(x: f128, y: f128) -> (f128); => copysignf128); - (fn fabs(x: f128) -> (f128); => fabsf128); - (fn fdim(x: f128, y: f128) -> (f128); => fdimf128); - (fn floor(x: f128) -> (f128); => floorf128); - (fn fma(x: f128, y: f128, z: f128) -> (f128); => fmaf128); - (fn fmax(x: f128, y: f128) -> (f128); => fmaxf128); - (fn fmaximum(x: f128, y: f128) -> (f128); => fmaximumf128); - (fn fmaximum_num(x: f128, y: f128) -> (f128); => fmaximum_numf128); - (fn fmin(x: f128, y: f128) -> (f128); => fminf128); - (fn fminimum(x: f128, y: f128) -> (f128); => fminimumf128); - (fn fminimum_num(x: f128, y: f128) -> (f128); => fminimum_numf128); - (fn fmod(x: f128, y: f128) -> (f128); => fmodf128); - (fn ldexp(x: f128, n: i32) -> (f128); => ldexpf128); - (fn rint(x: f128) -> (f128); => rintf128); - (fn round(x: f128) -> (f128); => roundf128); - (fn roundeven(x: f128) -> (f128); => roundevenf128); - (fn scalbn(x: f128, n: i32) -> (f128); => scalbnf128); - (fn sqrt(x: f128) -> (f128); => sqrtf128); - (fn trunc(x: f128) -> (f128); => truncf128); - // verify-sorted-end - } -} -// verify-apilist-end diff --git a/library/compiler-builtins/libm/libm/src/math/acos.rs b/library/compiler-builtins/libm/libm/src/math/acos.rs deleted file mode 100644 index 23b13251ee2..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/acos.rs +++ /dev/null @@ -1,112 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* acos(x) - * Method : - * acos(x) = pi/2 - asin(x) - * acos(-x) = pi/2 + asin(x) - * For |x|<=0.5 - * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) - * For x>0.5 - * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) - * = 2asin(sqrt((1-x)/2)) - * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) - * = 2f + (2c + 2s*z*R(z)) - * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term - * for f so that f+c ~ sqrt(z). - * For x<-0.5 - * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) - * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) - * - * Special cases: - * if x is NaN, return x itself; - * if |x|>1, return NaN with invalid signal. - * - * Function needed: sqrt - */ - -use super::sqrt; - -const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ -const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ -const PS0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ -const PS1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ -const PS2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ -const PS3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ -const PS4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ -const PS5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ -const QS1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ -const QS2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ -const QS3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ -const QS4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ - -fn r(z: f64) -> f64 { - let p: f64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); - let q: f64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); - p / q -} - -/// Arccosine (f64) -/// -/// Computes the inverse cosine (arc cosine) of the input value. -/// Arguments must be in the range -1 to 1. -/// Returns values in radians, in the range of 0 to pi. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn acos(x: f64) -> f64 { - let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120 - let z: f64; - let w: f64; - let s: f64; - let c: f64; - let df: f64; - let hx: u32; - let ix: u32; - - hx = (x.to_bits() >> 32) as u32; - ix = hx & 0x7fffffff; - /* |x| >= 1 or nan */ - if ix >= 0x3ff00000 { - let lx: u32 = x.to_bits() as u32; - - if ((ix - 0x3ff00000) | lx) == 0 { - /* acos(1)=0, acos(-1)=pi */ - if (hx >> 31) != 0 { - return 2. * PIO2_HI + x1p_120f; - } - return 0.; - } - return 0. / (x - x); - } - /* |x| < 0.5 */ - if ix < 0x3fe00000 { - if ix <= 0x3c600000 { - /* |x| < 2**-57 */ - return PIO2_HI + x1p_120f; - } - return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); - } - /* x < -0.5 */ - if (hx >> 31) != 0 { - z = (1.0 + x) * 0.5; - s = sqrt(z); - w = r(z) * s - PIO2_LO; - return 2. * (PIO2_HI - (s + w)); - } - /* x > 0.5 */ - z = (1.0 - x) * 0.5; - s = sqrt(z); - // Set the low 4 bytes to zero - df = f64::from_bits(s.to_bits() & 0xff_ff_ff_ff_00_00_00_00); - - c = (z - df * df) / (s + df); - w = r(z) * s + c; - 2. * (df + w) -} diff --git a/library/compiler-builtins/libm/libm/src/math/acosf.rs b/library/compiler-builtins/libm/libm/src/math/acosf.rs deleted file mode 100644 index dd88eea5b13..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/acosf.rs +++ /dev/null @@ -1,79 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::sqrt::sqrtf; - -const PIO2_HI: f32 = 1.5707962513e+00; /* 0x3fc90fda */ -const PIO2_LO: f32 = 7.5497894159e-08; /* 0x33a22168 */ -const P_S0: f32 = 1.6666586697e-01; -const P_S1: f32 = -4.2743422091e-02; -const P_S2: f32 = -8.6563630030e-03; -const Q_S1: f32 = -7.0662963390e-01; - -fn r(z: f32) -> f32 { - let p = z * (P_S0 + z * (P_S1 + z * P_S2)); - let q = 1. + z * Q_S1; - p / q -} - -/// Arccosine (f32) -/// -/// Computes the inverse cosine (arc cosine) of the input value. -/// Arguments must be in the range -1 to 1. -/// Returns values in radians, in the range of 0 to pi. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn acosf(x: f32) -> f32 { - let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) - - let z: f32; - let w: f32; - let s: f32; - - let mut hx = x.to_bits(); - let ix = hx & 0x7fffffff; - /* |x| >= 1 or nan */ - if ix >= 0x3f800000 { - if ix == 0x3f800000 { - if (hx >> 31) != 0 { - return 2. * PIO2_HI + x1p_120; - } - return 0.; - } - return 0. / (x - x); - } - /* |x| < 0.5 */ - if ix < 0x3f000000 { - if ix <= 0x32800000 { - /* |x| < 2**-26 */ - return PIO2_HI + x1p_120; - } - return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); - } - /* x < -0.5 */ - if (hx >> 31) != 0 { - z = (1. + x) * 0.5; - s = sqrtf(z); - w = r(z) * s - PIO2_LO; - return 2. * (PIO2_HI - (s + w)); - } - /* x > 0.5 */ - z = (1. - x) * 0.5; - s = sqrtf(z); - hx = s.to_bits(); - let df = f32::from_bits(hx & 0xfffff000); - let c = (z - df * df) / (s + df); - w = r(z) * s + c; - 2. * (df + w) -} diff --git a/library/compiler-builtins/libm/libm/src/math/acosh.rs b/library/compiler-builtins/libm/libm/src/math/acosh.rs deleted file mode 100644 index d1f5b9fa937..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/acosh.rs +++ /dev/null @@ -1,27 +0,0 @@ -use super::{log, log1p, sqrt}; - -const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ - -/// Inverse hyperbolic cosine (f64) -/// -/// Calculates the inverse hyperbolic cosine of `x`. -/// Is defined as `log(x + sqrt(x*x-1))`. -/// `x` must be a number greater than or equal to 1. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn acosh(x: f64) -> f64 { - let u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - - /* x < 1 domain error is handled in the called functions */ - - if e < 0x3ff + 1 { - /* |x| < 2, up to 2ulp error in [1,1.125] */ - return log1p(x - 1.0 + sqrt((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); - } - if e < 0x3ff + 26 { - /* |x| < 0x1p26 */ - return log(2.0 * x - 1.0 / (x + sqrt(x * x - 1.0))); - } - /* |x| >= 0x1p26 or nan */ - return log(x) + LN2; -} diff --git a/library/compiler-builtins/libm/libm/src/math/acoshf.rs b/library/compiler-builtins/libm/libm/src/math/acoshf.rs deleted file mode 100644 index ad3455fdd48..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/acoshf.rs +++ /dev/null @@ -1,26 +0,0 @@ -use super::{log1pf, logf, sqrtf}; - -const LN2: f32 = 0.693147180559945309417232121458176568; - -/// Inverse hyperbolic cosine (f32) -/// -/// Calculates the inverse hyperbolic cosine of `x`. -/// Is defined as `log(x + sqrt(x*x-1))`. -/// `x` must be a number greater than or equal to 1. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn acoshf(x: f32) -> f32 { - let u = x.to_bits(); - let a = u & 0x7fffffff; - - if a < 0x3f800000 + (1 << 23) { - /* |x| < 2, invalid if x < 1 or nan */ - /* up to 2ulp error in [1,1.125] */ - return log1pf(x - 1.0 + sqrtf((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); - } - if a < 0x3f800000 + (12 << 23) { - /* |x| < 0x1p12 */ - return logf(2.0 * x - 1.0 / (x + sqrtf(x * x - 1.0))); - } - /* x >= 0x1p12 */ - return logf(x) + LN2; -} diff --git a/library/compiler-builtins/libm/libm/src/math/arch/aarch64.rs b/library/compiler-builtins/libm/libm/src/math/arch/aarch64.rs deleted file mode 100644 index 020bb731cdc..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/arch/aarch64.rs +++ /dev/null @@ -1,115 +0,0 @@ -//! Architecture-specific support for aarch64 with neon. - -use core::arch::asm; - -pub fn fma(mut x: f64, y: f64, z: f64) -> f64 { - // SAFETY: `fmadd` is available with neon and has no side effects. - unsafe { - asm!( - "fmadd {x:d}, {x:d}, {y:d}, {z:d}", - x = inout(vreg) x, - y = in(vreg) y, - z = in(vreg) z, - options(nomem, nostack, pure) - ); - } - x -} - -pub fn fmaf(mut x: f32, y: f32, z: f32) -> f32 { - // SAFETY: `fmadd` is available with neon and has no side effects. - unsafe { - asm!( - "fmadd {x:s}, {x:s}, {y:s}, {z:s}", - x = inout(vreg) x, - y = in(vreg) y, - z = in(vreg) z, - options(nomem, nostack, pure) - ); - } - x -} - -pub fn rint(mut x: f64) -> f64 { - // SAFETY: `frintn` is available with neon and has no side effects. - // - // `frintn` is always round-to-nearest which does not match the C specification, but Rust does - // not support rounding modes. - unsafe { - asm!( - "frintn {x:d}, {x:d}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} - -pub fn rintf(mut x: f32) -> f32 { - // SAFETY: `frintn` is available with neon and has no side effects. - // - // `frintn` is always round-to-nearest which does not match the C specification, but Rust does - // not support rounding modes. - unsafe { - asm!( - "frintn {x:s}, {x:s}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} - -#[cfg(all(f16_enabled, target_feature = "fp16"))] -pub fn rintf16(mut x: f16) -> f16 { - // SAFETY: `frintn` is available for `f16` with `fp16` (implies `neon`) and has no side effects. - // - // `frintn` is always round-to-nearest which does not match the C specification, but Rust does - // not support rounding modes. - unsafe { - asm!( - "frintn {x:h}, {x:h}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} - -pub fn sqrt(mut x: f64) -> f64 { - // SAFETY: `fsqrt` is available with neon and has no side effects. - unsafe { - asm!( - "fsqrt {x:d}, {x:d}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} - -pub fn sqrtf(mut x: f32) -> f32 { - // SAFETY: `fsqrt` is available with neon and has no side effects. - unsafe { - asm!( - "fsqrt {x:s}, {x:s}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} - -#[cfg(all(f16_enabled, target_feature = "fp16"))] -pub fn sqrtf16(mut x: f16) -> f16 { - // SAFETY: `fsqrt` is available for `f16` with `fp16` (implies `neon`) and has no - // side effects. - unsafe { - asm!( - "fsqrt {x:h}, {x:h}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} diff --git a/library/compiler-builtins/libm/libm/src/math/arch/i586.rs b/library/compiler-builtins/libm/libm/src/math/arch/i586.rs deleted file mode 100644 index f92b9a2af71..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/arch/i586.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! Architecture-specific support for x86-32 without SSE2 - -use super::super::fabs; - -/// Use an alternative implementation on x86, because the -/// main implementation fails with the x87 FPU used by -/// debian i386, probably due to excess precision issues. -/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219. -pub fn ceil(x: f64) -> f64 { - if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { - let truncated = x as i64 as f64; - if truncated < x { - return truncated + 1.0; - } else { - return truncated; - } - } else { - return x; - } -} - -/// Use an alternative implementation on x86, because the -/// main implementation fails with the x87 FPU used by -/// debian i386, probably due to excess precision issues. -/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219. -pub fn floor(x: f64) -> f64 { - if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { - let truncated = x as i64 as f64; - if truncated > x { - return truncated - 1.0; - } else { - return truncated; - } - } else { - return x; - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/arch/i686.rs b/library/compiler-builtins/libm/libm/src/math/arch/i686.rs deleted file mode 100644 index 3e1d19bfab6..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/arch/i686.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Architecture-specific support for x86-32 and x86-64 with SSE2 - -pub fn sqrtf(mut x: f32) -> f32 { - // SAFETY: `sqrtss` is part of `sse2`, which this module is gated behind. It has no memory - // access or side effects. - unsafe { - core::arch::asm!( - "sqrtss {x}, {x}", - x = inout(xmm_reg) x, - options(nostack, nomem, pure), - ) - }; - x -} - -pub fn sqrt(mut x: f64) -> f64 { - // SAFETY: `sqrtsd` is part of `sse2`, which this module is gated behind. It has no memory - // access or side effects. - unsafe { - core::arch::asm!( - "sqrtsd {x}, {x}", - x = inout(xmm_reg) x, - options(nostack, nomem, pure), - ) - }; - x -} diff --git a/library/compiler-builtins/libm/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/libm/src/math/arch/mod.rs deleted file mode 100644 index d9f2aad66d4..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/arch/mod.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! Architecture-specific routines and operations. -//! -//! LLVM will already optimize calls to some of these in cases that there are hardware -//! instructions. Providing an implementation here just ensures that the faster implementation -//! is used when calling the function directly. This helps anyone who uses `libm` directly, as -//! well as improving things when these routines are called as part of other implementations. - -// Most implementations should be defined here, to ensure they are not made available when -// soft floats are required. -#[cfg(arch_enabled)] -cfg_if! { - if #[cfg(all(target_arch = "wasm32", intrinsics_enabled))] { - mod wasm32; - pub use wasm32::{ - ceil, ceilf, fabs, fabsf, floor, floorf, rint, rintf, sqrt, sqrtf, trunc, truncf, - }; - } else if #[cfg(target_feature = "sse2")] { - mod i686; - pub use i686::{sqrt, sqrtf}; - } else if #[cfg(all( - any(target_arch = "aarch64", target_arch = "arm64ec"), - target_feature = "neon" - ))] { - mod aarch64; - - pub use aarch64::{ - fma, - fmaf, - rint, - rintf, - sqrt, - sqrtf, - }; - - #[cfg(all(f16_enabled, target_feature = "fp16"))] - pub use aarch64::{ - rintf16, - sqrtf16, - }; - } -} - -// There are certain architecture-specific implementations that are needed for correctness -// even with `force-soft-float`. These are configured here. -cfg_if! { - if #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] { - mod i586; - pub use i586::{ceil, floor}; - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/arch/wasm32.rs b/library/compiler-builtins/libm/libm/src/math/arch/wasm32.rs deleted file mode 100644 index de80c8a5817..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/arch/wasm32.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! Wasm has builtins for simple float operations. Use the unstable `core::arch` intrinsics which -//! are significantly faster than soft float operations. - -pub fn ceil(x: f64) -> f64 { - core::arch::wasm32::f64_ceil(x) -} - -pub fn ceilf(x: f32) -> f32 { - core::arch::wasm32::f32_ceil(x) -} - -pub fn fabs(x: f64) -> f64 { - x.abs() -} - -pub fn fabsf(x: f32) -> f32 { - x.abs() -} - -pub fn floor(x: f64) -> f64 { - core::arch::wasm32::f64_floor(x) -} - -pub fn floorf(x: f32) -> f32 { - core::arch::wasm32::f32_floor(x) -} - -pub fn rint(x: f64) -> f64 { - core::arch::wasm32::f64_nearest(x) -} - -pub fn rintf(x: f32) -> f32 { - core::arch::wasm32::f32_nearest(x) -} - -pub fn sqrt(x: f64) -> f64 { - core::arch::wasm32::f64_sqrt(x) -} - -pub fn sqrtf(x: f32) -> f32 { - core::arch::wasm32::f32_sqrt(x) -} - -pub fn trunc(x: f64) -> f64 { - core::arch::wasm32::f64_trunc(x) -} - -pub fn truncf(x: f32) -> f32 { - core::arch::wasm32::f32_trunc(x) -} diff --git a/library/compiler-builtins/libm/libm/src/math/asin.rs b/library/compiler-builtins/libm/libm/src/math/asin.rs deleted file mode 100644 index 12d0cd35fa5..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/asin.rs +++ /dev/null @@ -1,115 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* asin(x) - * Method : - * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... - * we approximate asin(x) on [0,0.5] by - * asin(x) = x + x*x^2*R(x^2) - * where - * R(x^2) is a rational approximation of (asin(x)-x)/x^3 - * and its remez error is bounded by - * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) - * - * For x in [0.5,1] - * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) - * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; - * then for x>0.98 - * asin(x) = pi/2 - 2*(s+s*z*R(z)) - * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) - * For x<=0.98, let pio4_hi = pio2_hi/2, then - * f = hi part of s; - * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) - * and - * asin(x) = pi/2 - 2*(s+s*z*R(z)) - * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) - * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) - * - * Special cases: - * if x is NaN, return x itself; - * if |x|>1, return NaN with invalid signal. - * - */ - -use super::{fabs, get_high_word, get_low_word, sqrt, with_set_low_word}; - -const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ -const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ -/* coefficients for R(x^2) */ -const P_S0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ -const P_S1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ -const P_S2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ -const P_S3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ -const P_S4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ -const P_S5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ -const Q_S1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ -const Q_S2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ -const Q_S3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ -const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ - -fn comp_r(z: f64) -> f64 { - let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); - let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); - p / q -} - -/// Arcsine (f64) -/// -/// Computes the inverse sine (arc sine) of the argument `x`. -/// Arguments to asin must be in the range -1 to 1. -/// Returns values in radians, in the range of -pi/2 to pi/2. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn asin(mut x: f64) -> f64 { - let z: f64; - let r: f64; - let s: f64; - let hx: u32; - let ix: u32; - - hx = get_high_word(x); - ix = hx & 0x7fffffff; - /* |x| >= 1 or nan */ - if ix >= 0x3ff00000 { - let lx: u32; - lx = get_low_word(x); - if ((ix - 0x3ff00000) | lx) == 0 { - /* asin(1) = +-pi/2 with inexact */ - return x * PIO2_HI + f64::from_bits(0x3870000000000000); - } else { - return 0.0 / (x - x); - } - } - /* |x| < 0.5 */ - if ix < 0x3fe00000 { - /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ - if (0x00100000..0x3e500000).contains(&ix) { - return x; - } else { - return x + x * comp_r(x * x); - } - } - /* 1 > |x| >= 0.5 */ - z = (1.0 - fabs(x)) * 0.5; - s = sqrt(z); - r = comp_r(z); - if ix >= 0x3fef3333 { - /* if |x| > 0.975 */ - x = PIO2_HI - (2. * (s + s * r) - PIO2_LO); - } else { - let f: f64; - let c: f64; - /* f+c = sqrt(z) */ - f = with_set_low_word(s, 0); - c = (z - f * f) / (s + f); - x = 0.5 * PIO2_HI - (2.0 * s * r - (PIO2_LO - 2.0 * c) - (0.5 * PIO2_HI - 2.0 * f)); - } - if hx >> 31 != 0 { -x } else { x } -} diff --git a/library/compiler-builtins/libm/libm/src/math/asinf.rs b/library/compiler-builtins/libm/libm/src/math/asinf.rs deleted file mode 100644 index ed685556730..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/asinf.rs +++ /dev/null @@ -1,68 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::sqrt::sqrt; -use super::support::Float; - -const PIO2: f64 = 1.570796326794896558e+00; - -/* coefficients for R(x^2) */ -const P_S0: f32 = 1.6666586697e-01; -const P_S1: f32 = -4.2743422091e-02; -const P_S2: f32 = -8.6563630030e-03; -const Q_S1: f32 = -7.0662963390e-01; - -fn r(z: f32) -> f32 { - let p = z * (P_S0 + z * (P_S1 + z * P_S2)); - let q = 1. + z * Q_S1; - p / q -} - -/// Arcsine (f32) -/// -/// Computes the inverse sine (arc sine) of the argument `x`. -/// Arguments to asin must be in the range -1 to 1. -/// Returns values in radians, in the range of -pi/2 to pi/2. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn asinf(mut x: f32) -> f32 { - let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120) - - let hx = x.to_bits(); - let ix = hx & 0x7fffffff; - - if ix >= 0x3f800000 { - /* |x| >= 1 */ - if ix == 0x3f800000 { - /* |x| == 1 */ - return ((x as f64) * PIO2 + x1p_120) as f32; /* asin(+-1) = +-pi/2 with inexact */ - } - return 0. / (x - x); /* asin(|x|>1) is NaN */ - } - - if ix < 0x3f000000 { - /* |x| < 0.5 */ - /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ - if (0x00800000..0x39800000).contains(&ix) { - return x; - } - return x + x * r(x * x); - } - - /* 1 > |x| >= 0.5 */ - let z = (1. - Float::abs(x)) * 0.5; - let s = sqrt(z as f64); - x = (PIO2 - 2. * (s + s * (r(z) as f64))) as f32; - if (hx >> 31) != 0 { -x } else { x } -} diff --git a/library/compiler-builtins/libm/libm/src/math/asinh.rs b/library/compiler-builtins/libm/libm/src/math/asinh.rs deleted file mode 100644 index 75d3c3ad462..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/asinh.rs +++ /dev/null @@ -1,36 +0,0 @@ -use super::{log, log1p, sqrt}; - -const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ - -/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ -/// Inverse hyperbolic sine (f64) -/// -/// Calculates the inverse hyperbolic sine of `x`. -/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn asinh(mut x: f64) -> f64 { - let mut u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - let sign = (u >> 63) != 0; - - /* |x| */ - u &= (!0) >> 1; - x = f64::from_bits(u); - - if e >= 0x3ff + 26 { - /* |x| >= 0x1p26 or inf or nan */ - x = log(x) + LN2; - } else if e >= 0x3ff + 1 { - /* |x| >= 2 */ - x = log(2.0 * x + 1.0 / (sqrt(x * x + 1.0) + x)); - } else if e >= 0x3ff - 26 { - /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ - x = log1p(x + x * x / (sqrt(x * x + 1.0) + 1.0)); - } else { - /* |x| < 0x1p-26, raise inexact if x != 0 */ - let x1p120 = f64::from_bits(0x4770000000000000); - force_eval!(x + x1p120); - } - - if sign { -x } else { x } -} diff --git a/library/compiler-builtins/libm/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/libm/src/math/asinhf.rs deleted file mode 100644 index 27ed9dd372d..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/asinhf.rs +++ /dev/null @@ -1,35 +0,0 @@ -use super::{log1pf, logf, sqrtf}; - -const LN2: f32 = 0.693147180559945309417232121458176568; - -/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ -/// Inverse hyperbolic sine (f32) -/// -/// Calculates the inverse hyperbolic sine of `x`. -/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn asinhf(mut x: f32) -> f32 { - let u = x.to_bits(); - let i = u & 0x7fffffff; - let sign = (u >> 31) != 0; - - /* |x| */ - x = f32::from_bits(i); - - if i >= 0x3f800000 + (12 << 23) { - /* |x| >= 0x1p12 or inf or nan */ - x = logf(x) + LN2; - } else if i >= 0x3f800000 + (1 << 23) { - /* |x| >= 2 */ - x = logf(2.0 * x + 1.0 / (sqrtf(x * x + 1.0) + x)); - } else if i >= 0x3f800000 - (12 << 23) { - /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ - x = log1pf(x + x * x / (sqrtf(x * x + 1.0) + 1.0)); - } else { - /* |x| < 0x1p-12, raise inexact if x!=0 */ - let x1p120 = f32::from_bits(0x7b800000); - force_eval!(x + x1p120); - } - - if sign { -x } else { x } -} diff --git a/library/compiler-builtins/libm/libm/src/math/atan.rs b/library/compiler-builtins/libm/libm/src/math/atan.rs deleted file mode 100644 index 4ca5cc91a1e..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/atan.rs +++ /dev/null @@ -1,182 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* atan(x) - * Method - * 1. Reduce x to positive by atan(x) = -atan(-x). - * 2. According to the integer k=4t+0.25 chopped, t=x, the argument - * is further reduced to one of the following intervals and the - * arctangent of t is evaluated by the corresponding formula: - * - * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) - * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) - * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) - * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) - * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) - * - * Constants: - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. - */ - -use core::f64; - -use super::fabs; - -const ATANHI: [f64; 4] = [ - 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ - 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ - 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ - 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ -]; - -const ATANLO: [f64; 4] = [ - 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ - 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ - 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ - 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ -]; - -const AT: [f64; 11] = [ - 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ - -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ - 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ - -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ - 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ - -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ - 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ - -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ - 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ - -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ - 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ -]; - -/// Arctangent (f64) -/// -/// Computes the inverse tangent (arc tangent) of the input value. -/// Returns a value in radians, in the range of -pi/2 to pi/2. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atan(x: f64) -> f64 { - let mut x = x; - let mut ix = (x.to_bits() >> 32) as u32; - let sign = ix >> 31; - ix &= 0x7fff_ffff; - if ix >= 0x4410_0000 { - if x.is_nan() { - return x; - } - - let z = ATANHI[3] + f64::from_bits(0x0380_0000); // 0x1p-120f - return if sign != 0 { -z } else { z }; - } - - let id = if ix < 0x3fdc_0000 { - /* |x| < 0.4375 */ - if ix < 0x3e40_0000 { - /* |x| < 2^-27 */ - if ix < 0x0010_0000 { - /* raise underflow for subnormal x */ - force_eval!(x as f32); - } - - return x; - } - - -1 - } else { - x = fabs(x); - if ix < 0x3ff30000 { - /* |x| < 1.1875 */ - if ix < 0x3fe60000 { - /* 7/16 <= |x| < 11/16 */ - x = (2. * x - 1.) / (2. + x); - 0 - } else { - /* 11/16 <= |x| < 19/16 */ - x = (x - 1.) / (x + 1.); - 1 - } - } else if ix < 0x40038000 { - /* |x| < 2.4375 */ - x = (x - 1.5) / (1. + 1.5 * x); - 2 - } else { - /* 2.4375 <= |x| < 2^66 */ - x = -1. / x; - 3 - } - }; - - let z = x * x; - let w = z * z; - /* break sum from i=0 to 10 AT[i]z**(i+1) into odd and even poly */ - let s1 = z * (AT[0] + w * (AT[2] + w * (AT[4] + w * (AT[6] + w * (AT[8] + w * AT[10]))))); - let s2 = w * (AT[1] + w * (AT[3] + w * (AT[5] + w * (AT[7] + w * AT[9])))); - - if id < 0 { - return x - x * (s1 + s2); - } - - let z = i!(ATANHI, id as usize) - (x * (s1 + s2) - i!(ATANLO, id as usize) - x); - - if sign != 0 { -z } else { z } -} - -#[cfg(test)] -mod tests { - use core::f64; - - use super::atan; - - #[test] - fn sanity_check() { - for (input, answer) in [ - (3.0_f64.sqrt() / 3.0, f64::consts::FRAC_PI_6), - (1.0, f64::consts::FRAC_PI_4), - (3.0_f64.sqrt(), f64::consts::FRAC_PI_3), - (-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6), - (-1.0, -f64::consts::FRAC_PI_4), - (-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3), - ] - .iter() - { - assert!( - (atan(*input) - answer) / answer < 1e-5, - "\natan({:.4}/16) = {:.4}, actual: {}", - input * 16.0, - answer, - atan(*input) - ); - } - } - - #[test] - fn zero() { - assert_eq!(atan(0.0), 0.0); - } - - #[test] - fn infinity() { - assert_eq!(atan(f64::INFINITY), f64::consts::FRAC_PI_2); - } - - #[test] - fn minus_infinity() { - assert_eq!(atan(f64::NEG_INFINITY), -f64::consts::FRAC_PI_2); - } - - #[test] - fn nan() { - assert!(atan(f64::NAN).is_nan()); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/atan2.rs b/library/compiler-builtins/libm/libm/src/math/atan2.rs deleted file mode 100644 index c668731cf37..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/atan2.rs +++ /dev/null @@ -1,131 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - * - */ -/* atan2(y,x) - * Method : - * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). - * 2. Reduce x to positive by (if x and y are unexceptional): - * ARG (x+iy) = arctan(y/x) ... if x > 0, - * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, - * - * Special cases: - * - * ATAN2((anything), NaN ) is NaN; - * ATAN2(NAN , (anything) ) is NaN; - * ATAN2(+-0, +(anything but NaN)) is +-0 ; - * ATAN2(+-0, -(anything but NaN)) is +-pi ; - * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; - * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; - * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; - * ATAN2(+-INF,+INF ) is +-pi/4 ; - * ATAN2(+-INF,-INF ) is +-3pi/4; - * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; - * - * Constants: - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. - */ - -use super::{atan, fabs}; - -const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ -const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ - -/// Arctangent of y/x (f64) -/// -/// Computes the inverse tangent (arc tangent) of `y/x`. -/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). -/// Returns a value in radians, in the range of -pi to pi. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atan2(y: f64, x: f64) -> f64 { - if x.is_nan() || y.is_nan() { - return x + y; - } - let mut ix = (x.to_bits() >> 32) as u32; - let lx = x.to_bits() as u32; - let mut iy = (y.to_bits() >> 32) as u32; - let ly = y.to_bits() as u32; - if ((ix.wrapping_sub(0x3ff00000)) | lx) == 0 { - /* x = 1.0 */ - return atan(y); - } - let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ - ix &= 0x7fffffff; - iy &= 0x7fffffff; - - /* when y = 0 */ - if (iy | ly) == 0 { - return match m { - 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ - 2 => PI, /* atan(+0,-anything) = PI */ - _ => -PI, /* atan(-0,-anything) =-PI */ - }; - } - /* when x = 0 */ - if (ix | lx) == 0 { - return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; - } - /* when x is INF */ - if ix == 0x7ff00000 { - if iy == 0x7ff00000 { - return match m { - 0 => PI / 4.0, /* atan(+INF,+INF) */ - 1 => -PI / 4.0, /* atan(-INF,+INF) */ - 2 => 3.0 * PI / 4.0, /* atan(+INF,-INF) */ - _ => -3.0 * PI / 4.0, /* atan(-INF,-INF) */ - }; - } else { - return match m { - 0 => 0.0, /* atan(+...,+INF) */ - 1 => -0.0, /* atan(-...,+INF) */ - 2 => PI, /* atan(+...,-INF) */ - _ => -PI, /* atan(-...,-INF) */ - }; - } - } - /* |y/x| > 0x1p64 */ - if ix.wrapping_add(64 << 20) < iy || iy == 0x7ff00000 { - return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; - } - - /* z = atan(|y/x|) without spurious underflow */ - let z = if (m & 2 != 0) && iy.wrapping_add(64 << 20) < ix { - /* |y/x| < 0x1p-64, x<0 */ - 0.0 - } else { - atan(fabs(y / x)) - }; - match m { - 0 => z, /* atan(+,+) */ - 1 => -z, /* atan(-,+) */ - 2 => PI - (z - PI_LO), /* atan(+,-) */ - _ => (z - PI_LO) - PI, /* atan(-,-) */ - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[cfg_attr(x86_no_sse, ignore = "FIXME(i586): possible incorrect rounding")] - fn sanity_check() { - assert_eq!(atan2(0.0, 1.0), 0.0); - assert_eq!(atan2(0.0, -1.0), PI); - assert_eq!(atan2(-0.0, -1.0), -PI); - assert_eq!(atan2(3.0, 2.0), atan(3.0 / 2.0)); - assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI); - assert_eq!(atan2(-2.0, -1.0), atan(-2.0 / -1.0) - PI); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/libm/src/math/atan2f.rs deleted file mode 100644 index 95b466fff4e..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/atan2f.rs +++ /dev/null @@ -1,90 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{atanf, fabsf}; - -const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ -const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ - -/// Arctangent of y/x (f32) -/// -/// Computes the inverse tangent (arc tangent) of `y/x`. -/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). -/// Returns a value in radians, in the range of -pi to pi. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atan2f(y: f32, x: f32) -> f32 { - if x.is_nan() || y.is_nan() { - return x + y; - } - let mut ix = x.to_bits(); - let mut iy = y.to_bits(); - - if ix == 0x3f800000 { - /* x=1.0 */ - return atanf(y); - } - let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ - ix &= 0x7fffffff; - iy &= 0x7fffffff; - - /* when y = 0 */ - if iy == 0 { - return match m { - 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ - 2 => PI, /* atan(+0,-anything) = pi */ - _ => -PI, /* atan(-0,-anything) =-pi */ - }; - } - /* when x = 0 */ - if ix == 0 { - return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; - } - /* when x is INF */ - if ix == 0x7f800000 { - return if iy == 0x7f800000 { - match m { - 0 => PI / 4., /* atan(+INF,+INF) */ - 1 => -PI / 4., /* atan(-INF,+INF) */ - 2 => 3. * PI / 4., /* atan(+INF,-INF)*/ - _ => -3. * PI / 4., /* atan(-INF,-INF)*/ - } - } else { - match m { - 0 => 0., /* atan(+...,+INF) */ - 1 => -0., /* atan(-...,+INF) */ - 2 => PI, /* atan(+...,-INF) */ - _ => -PI, /* atan(-...,-INF) */ - } - }; - } - /* |y/x| > 0x1p26 */ - if (ix + (26 << 23) < iy) || (iy == 0x7f800000) { - return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; - } - - /* z = atan(|y/x|) with correct underflow */ - let z = if (m & 2 != 0) && (iy + (26 << 23) < ix) { - /*|y/x| < 0x1p-26, x < 0 */ - 0. - } else { - atanf(fabsf(y / x)) - }; - match m { - 0 => z, /* atan(+,+) */ - 1 => -z, /* atan(-,+) */ - 2 => PI - (z - PI_LO), /* atan(+,-) */ - _ => (z - PI_LO) - PI, /* case 3 */ /* atan(-,-) */ - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/atanf.rs b/library/compiler-builtins/libm/libm/src/math/atanf.rs deleted file mode 100644 index eb3d401cd96..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/atanf.rs +++ /dev/null @@ -1,103 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::fabsf; - -const ATAN_HI: [f32; 4] = [ - 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ - 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ - 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ - 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ -]; - -const ATAN_LO: [f32; 4] = [ - 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ - 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ - 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ - 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ -]; - -const A_T: [f32; 5] = - [3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, -1.0648017377e-01, 6.1687607318e-02]; - -/// Arctangent (f32) -/// -/// Computes the inverse tangent (arc tangent) of the input value. -/// Returns a value in radians, in the range of -pi/2 to pi/2. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atanf(mut x: f32) -> f32 { - let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) - - let z: f32; - - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - if ix >= 0x4c800000 { - /* if |x| >= 2**26 */ - if x.is_nan() { - return x; - } - z = i!(ATAN_HI, 3) + x1p_120; - return if sign { -z } else { z }; - } - let id = if ix < 0x3ee00000 { - /* |x| < 0.4375 */ - if ix < 0x39800000 { - /* |x| < 2**-12 */ - if ix < 0x00800000 { - /* raise underflow for subnormal x */ - force_eval!(x * x); - } - return x; - } - -1 - } else { - x = fabsf(x); - if ix < 0x3f980000 { - /* |x| < 1.1875 */ - if ix < 0x3f300000 { - /* 7/16 <= |x| < 11/16 */ - x = (2. * x - 1.) / (2. + x); - 0 - } else { - /* 11/16 <= |x| < 19/16 */ - x = (x - 1.) / (x + 1.); - 1 - } - } else if ix < 0x401c0000 { - /* |x| < 2.4375 */ - x = (x - 1.5) / (1. + 1.5 * x); - 2 - } else { - /* 2.4375 <= |x| < 2**26 */ - x = -1. / x; - 3 - } - }; - /* end of argument reduction */ - z = x * x; - let w = z * z; - /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ - let s1 = z * (i!(A_T, 0) + w * (i!(A_T, 2) + w * i!(A_T, 4))); - let s2 = w * (i!(A_T, 1) + w * i!(A_T, 3)); - if id < 0 { - return x - x * (s1 + s2); - } - let id = id as usize; - let z = i!(ATAN_HI, id) - ((x * (s1 + s2) - i!(ATAN_LO, id)) - x); - if sign { -z } else { z } -} diff --git a/library/compiler-builtins/libm/libm/src/math/atanh.rs b/library/compiler-builtins/libm/libm/src/math/atanh.rs deleted file mode 100644 index 9dc826f5605..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/atanh.rs +++ /dev/null @@ -1,33 +0,0 @@ -use super::log1p; - -/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ -/// Inverse hyperbolic tangent (f64) -/// -/// Calculates the inverse hyperbolic tangent of `x`. -/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atanh(x: f64) -> f64 { - let u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - let sign = (u >> 63) != 0; - - /* |x| */ - let mut y = f64::from_bits(u & 0x7fff_ffff_ffff_ffff); - - if e < 0x3ff - 1 { - if e < 0x3ff - 32 { - /* handle underflow */ - if e == 0 { - force_eval!(y as f32); - } - } else { - /* |x| < 0.5, up to 1.7ulp error */ - y = 0.5 * log1p(2.0 * y + 2.0 * y * y / (1.0 - y)); - } - } else { - /* avoid overflow */ - y = 0.5 * log1p(2.0 * (y / (1.0 - y))); - } - - if sign { -y } else { y } -} diff --git a/library/compiler-builtins/libm/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/libm/src/math/atanhf.rs deleted file mode 100644 index 80ccec1f67f..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/atanhf.rs +++ /dev/null @@ -1,33 +0,0 @@ -use super::log1pf; - -/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ -/// Inverse hyperbolic tangent (f32) -/// -/// Calculates the inverse hyperbolic tangent of `x`. -/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atanhf(mut x: f32) -> f32 { - let mut u = x.to_bits(); - let sign = (u >> 31) != 0; - - /* |x| */ - u &= 0x7fffffff; - x = f32::from_bits(u); - - if u < 0x3f800000 - (1 << 23) { - if u < 0x3f800000 - (32 << 23) { - /* handle underflow */ - if u < (1 << 23) { - force_eval!(x * x); - } - } else { - /* |x| < 0.5, up to 1.7ulp error */ - x = 0.5 * log1pf(2.0 * x + 2.0 * x * x / (1.0 - x)); - } - } else { - /* avoid overflow */ - x = 0.5 * log1pf(2.0 * (x / (1.0 - x))); - } - - if sign { -x } else { x } -} diff --git a/library/compiler-builtins/libm/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/libm/src/math/cbrt.rs deleted file mode 100644 index 9d3311cd6a8..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/cbrt.rs +++ /dev/null @@ -1,215 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: core-math/src/binary64/cbrt/cbrt.c - * Copyright (c) 2021-2022 Alexei Sibidanov. - * Ported to Rust in 2025 by Trevor Gross. - */ - -use super::Float; -use super::support::{FpResult, Round, cold_path}; - -/// Compute the cube root of the argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cbrt(x: f64) -> f64 { - cbrt_round(x, Round::Nearest).val -} - -pub fn cbrt_round(x: f64, round: Round) -> FpResult { - const ESCALE: [f64; 3] = [ - 1.0, - hf64!("0x1.428a2f98d728bp+0"), /* 2^(1/3) */ - hf64!("0x1.965fea53d6e3dp+0"), /* 2^(2/3) */ - ]; - - /* the polynomial c0+c1*x+c2*x^2+c3*x^3 approximates x^(1/3) on [1,2] - with maximal error < 9.2e-5 (attained at x=2) */ - const C: [f64; 4] = [ - hf64!("0x1.1b0babccfef9cp-1"), - hf64!("0x1.2c9a3e94d1da5p-1"), - hf64!("-0x1.4dc30b1a1ddbap-3"), - hf64!("0x1.7a8d3e4ec9b07p-6"), - ]; - - let u0: f64 = hf64!("0x1.5555555555555p-2"); - let u1: f64 = hf64!("0x1.c71c71c71c71cp-3"); - - let rsc = [1.0, -1.0, 0.5, -0.5, 0.25, -0.25]; - - let off = [hf64!("0x1p-53"), 0.0, 0.0, 0.0]; - - /* rm=0 for rounding to nearest, and other values for directed roundings */ - let hx: u64 = x.to_bits(); - let mut mant: u64 = hx & f64::SIG_MASK; - let sign: u64 = hx >> 63; - - let mut e: u32 = (hx >> f64::SIG_BITS) as u32 & f64::EXP_SAT; - - if ((e + 1) & f64::EXP_SAT) < 2 { - cold_path(); - - let ix: u64 = hx & !f64::SIGN_MASK; - - /* 0, inf, nan: we return x + x instead of simply x, - to that for x a signaling NaN, it correctly triggers - the invalid exception. */ - if e == f64::EXP_SAT || ix == 0 { - return FpResult::ok(x + x); - } - - let nz = ix.leading_zeros() - 11; /* subnormal */ - mant <<= nz; - mant &= f64::SIG_MASK; - e = e.wrapping_sub(nz - 1); - } - - e = e.wrapping_add(3072); - let cvt1: u64 = mant | (0x3ffu64 << 52); - let mut cvt5: u64 = cvt1; - - let et: u32 = e / 3; - let it: u32 = e % 3; - - /* 2^(3k+it) <= x < 2^(3k+it+1), with 0 <= it <= 3 */ - cvt5 += u64::from(it) << f64::SIG_BITS; - cvt5 |= sign << 63; - let zz: f64 = f64::from_bits(cvt5); - - /* cbrt(x) = cbrt(zz)*2^(et-1365) where 1 <= zz < 8 */ - let mut isc: u64 = ESCALE[it as usize].to_bits(); // todo: index - isc |= sign << 63; - let cvt2: u64 = isc; - let z: f64 = f64::from_bits(cvt1); - - /* cbrt(zz) = cbrt(z)*isc, where isc encodes 1, 2^(1/3) or 2^(2/3), - and 1 <= z < 2 */ - let r: f64 = 1.0 / z; - let rr: f64 = r * rsc[((it as usize) << 1) | sign as usize]; - let z2: f64 = z * z; - let c0: f64 = C[0] + z * C[1]; - let c2: f64 = C[2] + z * C[3]; - let mut y: f64 = c0 + z2 * c2; - let mut y2: f64 = y * y; - - /* y is an approximation of z^(1/3) */ - let mut h: f64 = y2 * (y * r) - 1.0; - - /* h determines the error between y and z^(1/3) */ - y -= (h * y) * (u0 - u1 * h); - - /* The correction y -= (h*y)*(u0 - u1*h) corresponds to a cubic variant - of Newton's method, with the function f(y) = 1-z/y^3. */ - y *= f64::from_bits(cvt2); - - /* Now y is an approximation of zz^(1/3), - * and rr an approximation of 1/zz. We now perform another iteration of - * Newton-Raphson, this time with a linear approximation only. */ - y2 = y * y; - let mut y2l: f64 = y.fma(y, -y2); - - /* y2 + y2l = y^2 exactly */ - let mut y3: f64 = y2 * y; - let mut y3l: f64 = y.fma(y2, -y3) + y * y2l; - - /* y3 + y3l approximates y^3 with about 106 bits of accuracy */ - h = ((y3 - zz) + y3l) * rr; - let mut dy: f64 = h * (y * u0); - - /* the approximation of zz^(1/3) is y - dy */ - let mut y1: f64 = y - dy; - dy = (y - y1) - dy; - - /* the approximation of zz^(1/3) is now y1 + dy, where |dy| < 1/2 ulp(y) - * (for rounding to nearest) */ - let mut ady: f64 = dy.abs(); - - /* For directed roundings, ady0 is tiny when dy is tiny, or ady0 is near - * from ulp(1); - * for rounding to nearest, ady0 is tiny when dy is near from 1/2 ulp(1), - * or from 3/2 ulp(1). */ - let mut ady0: f64 = (ady - off[round as usize]).abs(); - let mut ady1: f64 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs(); - - if ady0 < hf64!("0x1p-75") || ady1 < hf64!("0x1p-75") { - cold_path(); - - y2 = y1 * y1; - y2l = y1.fma(y1, -y2); - y3 = y2 * y1; - y3l = y1.fma(y2, -y3) + y1 * y2l; - h = ((y3 - zz) + y3l) * rr; - dy = h * (y1 * u0); - y = y1 - dy; - dy = (y1 - y) - dy; - y1 = y; - ady = dy.abs(); - ady0 = (ady - off[round as usize]).abs(); - ady1 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs(); - - if ady0 < hf64!("0x1p-98") || ady1 < hf64!("0x1p-98") { - cold_path(); - let azz: f64 = zz.abs(); - - // ~ 0x1.79d15d0e8d59b80000000000000ffc3dp+0 - if azz == hf64!("0x1.9b78223aa307cp+1") { - y1 = hf64!("0x1.79d15d0e8d59cp+0").copysign(zz); - } - - // ~ 0x1.de87aa837820e80000000000001c0f08p+0 - if azz == hf64!("0x1.a202bfc89ddffp+2") { - y1 = hf64!("0x1.de87aa837820fp+0").copysign(zz); - } - - if round != Round::Nearest { - let wlist = [ - (hf64!("0x1.3a9ccd7f022dbp+0"), hf64!("0x1.1236160ba9b93p+0")), // ~ 0x1.1236160ba9b930000000000001e7e8fap+0 - (hf64!("0x1.7845d2faac6fep+0"), hf64!("0x1.23115e657e49cp+0")), // ~ 0x1.23115e657e49c0000000000001d7a799p+0 - (hf64!("0x1.d1ef81cbbbe71p+0"), hf64!("0x1.388fb44cdcf5ap+0")), // ~ 0x1.388fb44cdcf5a0000000000002202c55p+0 - (hf64!("0x1.0a2014f62987cp+1"), hf64!("0x1.46bcbf47dc1e8p+0")), // ~ 0x1.46bcbf47dc1e8000000000000303aa2dp+0 - (hf64!("0x1.fe18a044a5501p+1"), hf64!("0x1.95decfec9c904p+0")), // ~ 0x1.95decfec9c9040000000000000159e8ep+0 - (hf64!("0x1.a6bb8c803147bp+2"), hf64!("0x1.e05335a6401dep+0")), // ~ 0x1.e05335a6401de00000000000027ca017p+0 - (hf64!("0x1.ac8538a031cbdp+2"), hf64!("0x1.e281d87098de8p+0")), // ~ 0x1.e281d87098de80000000000000ee9314p+0 - ]; - - for (a, b) in wlist { - if azz == a { - let tmp = if round as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 }; - y1 = (b + tmp).copysign(zz); - } - } - } - } - } - - let mut cvt3: u64 = y1.to_bits(); - cvt3 = cvt3.wrapping_add(((et.wrapping_sub(342).wrapping_sub(1023)) as u64) << 52); - let m0: u64 = cvt3 << 30; - let m1 = m0 >> 63; - - if (m0 ^ m1) <= (1u64 << 30) { - cold_path(); - - let mut cvt4: u64 = y1.to_bits(); - cvt4 = (cvt4 + (164 << 15)) & 0xffffffffffff0000u64; - - if ((f64::from_bits(cvt4) - y1) - dy).abs() < hf64!("0x1p-60") || (zz).abs() == 1.0 { - cvt3 = (cvt3 + (1u64 << 15)) & 0xffffffffffff0000u64; - } - } - - FpResult::ok(f64::from_bits(cvt3)) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn spot_checks() { - if !cfg!(x86_no_sse) { - // Exposes a rounding mode problem. Ignored on i586 because of inaccurate FMA. - assert_biteq!( - cbrt(f64::from_bits(0xf7f792b28f600000)), - f64::from_bits(0xd29ce68655d962f3) - ); - } - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/cbrtf.rs b/library/compiler-builtins/libm/libm/src/math/cbrtf.rs deleted file mode 100644 index 9d70305c647..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/cbrtf.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Debugged and optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* cbrtf(x) - * Return cube root of x - */ - -use core::f32; - -const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ -const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ - -/// Cube root (f32) -/// -/// Computes the cube root of the argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cbrtf(x: f32) -> f32 { - let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 - - let mut r: f64; - let mut t: f64; - let mut ui: u32 = x.to_bits(); - let mut hx: u32 = ui & 0x7fffffff; - - if hx >= 0x7f800000 { - /* cbrt(NaN,INF) is itself */ - return x + x; - } - - /* rough cbrt to 5 bits */ - if hx < 0x00800000 { - /* zero or subnormal? */ - if hx == 0 { - return x; /* cbrt(+-0) is itself */ - } - ui = (x * x1p24).to_bits(); - hx = ui & 0x7fffffff; - hx = hx / 3 + B2; - } else { - hx = hx / 3 + B1; - } - ui &= 0x80000000; - ui |= hx; - - /* - * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In - * double precision so that its terms can be arranged for efficiency - * without causing overflow or underflow. - */ - t = f32::from_bits(ui) as f64; - r = t * t * t; - t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); - - /* - * Second step Newton iteration to 47 bits. In double precision for - * efficiency and accuracy. - */ - r = t * t * t; - t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); - - /* rounding to 24 bits is perfect in round-to-nearest mode */ - t as f32 -} diff --git a/library/compiler-builtins/libm/libm/src/math/ceil.rs b/library/compiler-builtins/libm/libm/src/math/ceil.rs deleted file mode 100644 index 4e103545727..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/ceil.rs +++ /dev/null @@ -1,46 +0,0 @@ -/// Ceil (f16) -/// -/// Finds the nearest integer greater than or equal to `x`. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceilf16(x: f16) -> f16 { - super::generic::ceil(x) -} - -/// Ceil (f32) -/// -/// Finds the nearest integer greater than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceilf(x: f32) -> f32 { - select_implementation! { - name: ceilf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::ceil(x) -} - -/// Ceil (f64) -/// -/// Finds the nearest integer greater than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceil(x: f64) -> f64 { - select_implementation! { - name: ceil, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), - args: x, - } - - super::generic::ceil(x) -} - -/// Ceil (f128) -/// -/// Finds the nearest integer greater than or equal to `x`. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceilf128(x: f128) -> f128 { - super::generic::ceil(x) -} diff --git a/library/compiler-builtins/libm/libm/src/math/copysign.rs b/library/compiler-builtins/libm/libm/src/math/copysign.rs deleted file mode 100644 index d2a86e7fd54..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/copysign.rs +++ /dev/null @@ -1,88 +0,0 @@ -/// Sign of Y, magnitude of X (f16) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf16(x: f16, y: f16) -> f16 { - super::generic::copysign(x, y) -} - -/// Sign of Y, magnitude of X (f32) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf(x: f32, y: f32) -> f32 { - super::generic::copysign(x, y) -} - -/// Sign of Y, magnitude of X (f64) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysign(x: f64, y: f64) -> f64 { - super::generic::copysign(x, y) -} - -/// Sign of Y, magnitude of X (f128) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf128(x: f128, y: f128) -> f128 { - super::generic::copysign(x, y) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Float; - - fn spec_test(f: impl Fn(F, F) -> F) { - assert_biteq!(f(F::ZERO, F::ZERO), F::ZERO); - assert_biteq!(f(F::NEG_ZERO, F::ZERO), F::ZERO); - assert_biteq!(f(F::ZERO, F::NEG_ZERO), F::NEG_ZERO); - assert_biteq!(f(F::NEG_ZERO, F::NEG_ZERO), F::NEG_ZERO); - - assert_biteq!(f(F::ONE, F::ONE), F::ONE); - assert_biteq!(f(F::NEG_ONE, F::ONE), F::ONE); - assert_biteq!(f(F::ONE, F::NEG_ONE), F::NEG_ONE); - assert_biteq!(f(F::NEG_ONE, F::NEG_ONE), F::NEG_ONE); - - assert_biteq!(f(F::INFINITY, F::INFINITY), F::INFINITY); - assert_biteq!(f(F::NEG_INFINITY, F::INFINITY), F::INFINITY); - assert_biteq!(f(F::INFINITY, F::NEG_INFINITY), F::NEG_INFINITY); - assert_biteq!(f(F::NEG_INFINITY, F::NEG_INFINITY), F::NEG_INFINITY); - - // Not required but we expect it - assert_biteq!(f(F::NAN, F::NAN), F::NAN); - assert_biteq!(f(F::NEG_NAN, F::NAN), F::NAN); - assert_biteq!(f(F::NAN, F::NEG_NAN), F::NEG_NAN); - assert_biteq!(f(F::NEG_NAN, F::NEG_NAN), F::NEG_NAN); - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(copysignf16); - } - - #[test] - fn spec_tests_f32() { - spec_test::(copysignf); - } - - #[test] - fn spec_tests_f64() { - spec_test::(copysign); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(copysignf128); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/libm/src/math/copysignf.rs deleted file mode 100644 index 8b9bed4c0c4..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/copysignf.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f32) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf(x: f32, y: f32) -> f32 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/libm/src/math/copysignf128.rs b/library/compiler-builtins/libm/libm/src/math/copysignf128.rs deleted file mode 100644 index 7bd81d42b2e..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/copysignf128.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f128) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf128(x: f128, y: f128) -> f128 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/libm/src/math/copysignf16.rs b/library/compiler-builtins/libm/libm/src/math/copysignf16.rs deleted file mode 100644 index 82065868601..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/copysignf16.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f16) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf16(x: f16, y: f16) -> f16 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/libm/src/math/cos.rs b/library/compiler-builtins/libm/libm/src/math/cos.rs deleted file mode 100644 index de99cd4c5e4..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/cos.rs +++ /dev/null @@ -1,77 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */ -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunPro, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -use super::{k_cos, k_sin, rem_pio2}; - -// cos(x) -// Return cosine function of x. -// -// kernel function: -// k_sin ... sine function on [-pi/4,pi/4] -// k_cos ... cosine function on [-pi/4,pi/4] -// rem_pio2 ... argument reduction routine -// -// Method. -// Let S,C and T denote the sin, cos and tan respectively on -// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 -// in [-pi/4 , +pi/4], and let n = k mod 4. -// We have -// -// n sin(x) cos(x) tan(x) -// ---------------------------------------------------------- -// 0 S C T -// 1 C -S -1/T -// 2 -S -C T -// 3 -C S -1/T -// ---------------------------------------------------------- -// -// Special cases: -// Let trig be any of sin, cos, or tan. -// trig(+-INF) is NaN, with signals; -// trig(NaN) is that NaN; -// -// Accuracy: -// TRIG(x) returns trig(x) nearly rounded -// - -/// The cosine of `x` (f64). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cos(x: f64) -> f64 { - let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; - - /* |x| ~< pi/4 */ - if ix <= 0x3fe921fb { - if ix < 0x3e46a09e { - /* if x < 2**-27 * sqrt(2) */ - /* raise inexact if x != 0 */ - if x as i32 == 0 { - return 1.0; - } - } - return k_cos(x, 0.0); - } - - /* cos(Inf or NaN) is NaN */ - if ix >= 0x7ff00000 { - return x - x; - } - - /* argument reduction needed */ - let (n, y0, y1) = rem_pio2(x); - match n & 3 { - 0 => k_cos(y0, y1), - 1 => -k_sin(y0, y1, 1), - 2 => -k_cos(y0, y1), - _ => k_sin(y0, y1, 1), - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/cosf.rs b/library/compiler-builtins/libm/libm/src/math/cosf.rs deleted file mode 100644 index 27c2fc3b994..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/cosf.rs +++ /dev/null @@ -1,86 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::f64::consts::FRAC_PI_2; - -use super::{k_cosf, k_sinf, rem_pio2f}; - -/* Small multiples of pi/2 rounded to double precision. */ -const C1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ -const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ - -/// The cosine of `x` (f32). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cosf(x: f32) -> f32 { - let x64 = x as f64; - - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - if ix <= 0x3f490fda { - /* |x| ~<= pi/4 */ - if ix < 0x39800000 { - /* |x| < 2**-12 */ - /* raise inexact if x != 0 */ - force_eval!(x + x1p120); - return 1.; - } - return k_cosf(x64); - } - if ix <= 0x407b53d1 { - /* |x| ~<= 5*pi/4 */ - if ix > 0x4016cbe3 { - /* |x| ~> 3*pi/4 */ - return -k_cosf(if sign { x64 + C2_PIO2 } else { x64 - C2_PIO2 }); - } else if sign { - return k_sinf(x64 + C1_PIO2); - } else { - return k_sinf(C1_PIO2 - x64); - } - } - if ix <= 0x40e231d5 { - /* |x| ~<= 9*pi/4 */ - if ix > 0x40afeddf { - /* |x| ~> 7*pi/4 */ - return k_cosf(if sign { x64 + C4_PIO2 } else { x64 - C4_PIO2 }); - } else if sign { - return k_sinf(-x64 - C3_PIO2); - } else { - return k_sinf(x64 - C3_PIO2); - } - } - - /* cos(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - return x - x; - } - - /* general argument reduction needed */ - let (n, y) = rem_pio2f(x); - match n & 3 { - 0 => k_cosf(y), - 1 => k_sinf(-y), - 2 => -k_cosf(y), - _ => k_sinf(y), - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/cosh.rs b/library/compiler-builtins/libm/libm/src/math/cosh.rs deleted file mode 100644 index d2e43fd6cb6..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/cosh.rs +++ /dev/null @@ -1,36 +0,0 @@ -use super::{exp, expm1, k_expo2}; - -/// Hyperbolic cosine (f64) -/// -/// Computes the hyperbolic cosine of the argument x. -/// Is defined as `(exp(x) + exp(-x))/2` -/// Angles are specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cosh(mut x: f64) -> f64 { - /* |x| */ - let mut ix = x.to_bits(); - ix &= 0x7fffffffffffffff; - x = f64::from_bits(ix); - let w = ix >> 32; - - /* |x| < log(2) */ - if w < 0x3fe62e42 { - if w < 0x3ff00000 - (26 << 20) { - let x1p120 = f64::from_bits(0x4770000000000000); - force_eval!(x + x1p120); - return 1.; - } - let t = expm1(x); // exponential minus 1 - return 1. + t * t / (2. * (1. + t)); - } - - /* |x| < log(DBL_MAX) */ - if w < 0x40862e42 { - let t = exp(x); - /* note: if x>log(0x1p26) then the 1/t is not needed */ - return 0.5 * (t + 1. / t); - } - - /* |x| > log(DBL_MAX) or nan */ - k_expo2(x) -} diff --git a/library/compiler-builtins/libm/libm/src/math/coshf.rs b/library/compiler-builtins/libm/libm/src/math/coshf.rs deleted file mode 100644 index 567a24410e7..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/coshf.rs +++ /dev/null @@ -1,36 +0,0 @@ -use super::{expf, expm1f, k_expo2f}; - -/// Hyperbolic cosine (f64) -/// -/// Computes the hyperbolic cosine of the argument x. -/// Is defined as `(exp(x) + exp(-x))/2` -/// Angles are specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn coshf(mut x: f32) -> f32 { - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - /* |x| */ - let mut ix = x.to_bits(); - ix &= 0x7fffffff; - x = f32::from_bits(ix); - let w = ix; - - /* |x| < log(2) */ - if w < 0x3f317217 { - if w < (0x3f800000 - (12 << 23)) { - force_eval!(x + x1p120); - return 1.; - } - let t = expm1f(x); - return 1. + t * t / (2. * (1. + t)); - } - - /* |x| < log(FLT_MAX) */ - if w < 0x42b17217 { - let t = expf(x); - return 0.5 * (t + 1. / t); - } - - /* |x| > log(FLT_MAX) or nan */ - k_expo2f(x) -} diff --git a/library/compiler-builtins/libm/libm/src/math/erf.rs b/library/compiler-builtins/libm/libm/src/math/erf.rs deleted file mode 100644 index 1b634abec6b..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/erf.rs +++ /dev/null @@ -1,310 +0,0 @@ -use super::{exp, fabs, get_high_word, with_set_low_word}; -/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* double erf(double x) - * double erfc(double x) - * x - * 2 |\ - * erf(x) = --------- | exp(-t*t)dt - * sqrt(pi) \| - * 0 - * - * erfc(x) = 1-erf(x) - * Note that - * erf(-x) = -erf(x) - * erfc(-x) = 2 - erfc(x) - * - * Method: - * 1. For |x| in [0, 0.84375] - * erf(x) = x + x*R(x^2) - * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] - * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] - * where R = P/Q where P is an odd poly of degree 8 and - * Q is an odd poly of degree 10. - * -57.90 - * | R - (erf(x)-x)/x | <= 2 - * - * - * Remark. The formula is derived by noting - * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) - * and that - * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 - * is close to one. The interval is chosen because the fix - * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is - * near 0.6174), and by some experiment, 0.84375 is chosen to - * guarantee the error is less than one ulp for erf. - * - * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and - * c = 0.84506291151 rounded to single (24 bits) - * erf(x) = sign(x) * (c + P1(s)/Q1(s)) - * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 - * 1+(c+P1(s)/Q1(s)) if x < 0 - * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 - * Remark: here we use the taylor series expansion at x=1. - * erf(1+s) = erf(1) + s*Poly(s) - * = 0.845.. + P1(s)/Q1(s) - * That is, we use rational approximation to approximate - * erf(1+s) - (c = (single)0.84506291151) - * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] - * where - * P1(s) = degree 6 poly in s - * Q1(s) = degree 6 poly in s - * - * 3. For x in [1.25,1/0.35(~2.857143)], - * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) - * erf(x) = 1 - erfc(x) - * where - * R1(z) = degree 7 poly in z, (z=1/x^2) - * S1(z) = degree 8 poly in z - * - * 4. For x in [1/0.35,28] - * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 - * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 - * erf(x) = sign(x) *(1 - tiny) (raise inexact) - * erfc(x) = tiny*tiny (raise underflow) if x > 0 - * = 2 - tiny if x<0 - * - * 7. Special case: - * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, - * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, - * erfc/erf(NaN) is NaN - */ - -const ERX: f64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ -/* - * Coefficients for approximation to erf on [0,0.84375] - */ -const EFX8: f64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ -const PP0: f64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ -const PP1: f64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ -const PP2: f64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */ -const PP3: f64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */ -const PP4: f64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */ -const QQ1: f64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */ -const QQ2: f64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ -const QQ3: f64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ -const QQ4: f64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ -const QQ5: f64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ -/* - * Coefficients for approximation to erf in [0.84375,1.25] - */ -const PA0: f64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ -const PA1: f64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ -const PA2: f64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ -const PA3: f64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */ -const PA4: f64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */ -const PA5: f64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */ -const PA6: f64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */ -const QA1: f64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */ -const QA2: f64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */ -const QA3: f64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ -const QA4: f64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ -const QA5: f64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ -const QA6: f64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ -/* - * Coefficients for approximation to erfc in [1.25,1/0.35] - */ -const RA0: f64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ -const RA1: f64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ -const RA2: f64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ -const RA3: f64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */ -const RA4: f64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */ -const RA5: f64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */ -const RA6: f64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */ -const RA7: f64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */ -const SA1: f64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */ -const SA2: f64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */ -const SA3: f64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */ -const SA4: f64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */ -const SA5: f64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ -const SA6: f64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ -const SA7: f64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ -const SA8: f64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ -/* - * Coefficients for approximation to erfc in [1/.35,28] - */ -const RB0: f64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ -const RB1: f64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ -const RB2: f64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ -const RB3: f64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */ -const RB4: f64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */ -const RB5: f64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */ -const RB6: f64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */ -const SB1: f64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */ -const SB2: f64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */ -const SB3: f64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */ -const SB4: f64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ -const SB5: f64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ -const SB6: f64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ -const SB7: f64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ - -fn erfc1(x: f64) -> f64 { - let s: f64; - let p: f64; - let q: f64; - - s = fabs(x) - 1.0; - p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); - q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); - - 1.0 - ERX - p / q -} - -fn erfc2(ix: u32, mut x: f64) -> f64 { - let s: f64; - let r: f64; - let big_s: f64; - let z: f64; - - if ix < 0x3ff40000 { - /* |x| < 1.25 */ - return erfc1(x); - } - - x = fabs(x); - s = 1.0 / (x * x); - if ix < 0x4006db6d { - /* |x| < 1/.35 ~ 2.85714 */ - r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); - big_s = 1.0 - + s * (SA1 - + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); - } else { - /* |x| > 1/.35 */ - r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); - big_s = - 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); - } - z = with_set_low_word(x, 0); - - exp(-z * z - 0.5625) * exp((z - x) * (z + x) + r / big_s) / x -} - -/// Error function (f64) -/// -/// Calculates an approximation to the “error function”, which estimates -/// the probability that an observation will fall within x standard -/// deviations of the mean (assuming a normal distribution). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn erf(x: f64) -> f64 { - let r: f64; - let s: f64; - let z: f64; - let y: f64; - let mut ix: u32; - let sign: usize; - - ix = get_high_word(x); - sign = (ix >> 31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - /* erf(nan)=nan, erf(+-inf)=+-1 */ - return 1.0 - 2.0 * (sign as f64) + 1.0 / x; - } - if ix < 0x3feb0000 { - /* |x| < 0.84375 */ - if ix < 0x3e300000 { - /* |x| < 2**-28 */ - /* avoid underflow */ - return 0.125 * (8.0 * x + EFX8 * x); - } - z = x * x; - r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); - s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); - y = r / s; - return x + x * y; - } - if ix < 0x40180000 { - /* 0.84375 <= |x| < 6 */ - y = 1.0 - erfc2(ix, x); - } else { - let x1p_1022 = f64::from_bits(0x0010000000000000); - y = 1.0 - x1p_1022; - } - - if sign != 0 { -y } else { y } -} - -/// Complementary error function (f64) -/// -/// Calculates the complementary probability. -/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid -/// the loss of precision that would result from subtracting -/// large probabilities (on large `x`) from 1. -pub fn erfc(x: f64) -> f64 { - let r: f64; - let s: f64; - let z: f64; - let y: f64; - let mut ix: u32; - let sign: usize; - - ix = get_high_word(x); - sign = (ix >> 31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - /* erfc(nan)=nan, erfc(+-inf)=0,2 */ - return 2.0 * (sign as f64) + 1.0 / x; - } - if ix < 0x3feb0000 { - /* |x| < 0.84375 */ - if ix < 0x3c700000 { - /* |x| < 2**-56 */ - return 1.0 - x; - } - z = x * x; - r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); - s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); - y = r / s; - if sign != 0 || ix < 0x3fd00000 { - /* x < 1/4 */ - return 1.0 - (x + x * y); - } - return 0.5 - (x - 0.5 + x * y); - } - if ix < 0x403c0000 { - /* 0.84375 <= |x| < 28 */ - if sign != 0 { - return 2.0 - erfc2(ix, x); - } else { - return erfc2(ix, x); - } - } - - let x1p_1022 = f64::from_bits(0x0010000000000000); - if sign != 0 { 2.0 - x1p_1022 } else { x1p_1022 * x1p_1022 } -} diff --git a/library/compiler-builtins/libm/libm/src/math/erff.rs b/library/compiler-builtins/libm/libm/src/math/erff.rs deleted file mode 100644 index 2e41183bfc0..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/erff.rs +++ /dev/null @@ -1,222 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{expf, fabsf}; - -const ERX: f32 = 8.4506291151e-01; /* 0x3f58560b */ -/* - * Coefficients for approximation to erf on [0,0.84375] - */ -const EFX8: f32 = 1.0270333290e+00; /* 0x3f8375d4 */ -const PP0: f32 = 1.2837916613e-01; /* 0x3e0375d4 */ -const PP1: f32 = -3.2504209876e-01; /* 0xbea66beb */ -const PP2: f32 = -2.8481749818e-02; /* 0xbce9528f */ -const PP3: f32 = -5.7702702470e-03; /* 0xbbbd1489 */ -const PP4: f32 = -2.3763017452e-05; /* 0xb7c756b1 */ -const QQ1: f32 = 3.9791721106e-01; /* 0x3ecbbbce */ -const QQ2: f32 = 6.5022252500e-02; /* 0x3d852a63 */ -const QQ3: f32 = 5.0813062117e-03; /* 0x3ba68116 */ -const QQ4: f32 = 1.3249473704e-04; /* 0x390aee49 */ -const QQ5: f32 = -3.9602282413e-06; /* 0xb684e21a */ -/* - * Coefficients for approximation to erf in [0.84375,1.25] - */ -const PA0: f32 = -2.3621185683e-03; /* 0xbb1acdc6 */ -const PA1: f32 = 4.1485610604e-01; /* 0x3ed46805 */ -const PA2: f32 = -3.7220788002e-01; /* 0xbebe9208 */ -const PA3: f32 = 3.1834661961e-01; /* 0x3ea2fe54 */ -const PA4: f32 = -1.1089469492e-01; /* 0xbde31cc2 */ -const PA5: f32 = 3.5478305072e-02; /* 0x3d1151b3 */ -const PA6: f32 = -2.1663755178e-03; /* 0xbb0df9c0 */ -const QA1: f32 = 1.0642088205e-01; /* 0x3dd9f331 */ -const QA2: f32 = 5.4039794207e-01; /* 0x3f0a5785 */ -const QA3: f32 = 7.1828655899e-02; /* 0x3d931ae7 */ -const QA4: f32 = 1.2617121637e-01; /* 0x3e013307 */ -const QA5: f32 = 1.3637083583e-02; /* 0x3c5f6e13 */ -const QA6: f32 = 1.1984500103e-02; /* 0x3c445aa3 */ -/* - * Coefficients for approximation to erfc in [1.25,1/0.35] - */ -const RA0: f32 = -9.8649440333e-03; /* 0xbc21a093 */ -const RA1: f32 = -6.9385856390e-01; /* 0xbf31a0b7 */ -const RA2: f32 = -1.0558626175e+01; /* 0xc128f022 */ -const RA3: f32 = -6.2375331879e+01; /* 0xc2798057 */ -const RA4: f32 = -1.6239666748e+02; /* 0xc322658c */ -const RA5: f32 = -1.8460508728e+02; /* 0xc3389ae7 */ -const RA6: f32 = -8.1287437439e+01; /* 0xc2a2932b */ -const RA7: f32 = -9.8143291473e+00; /* 0xc11d077e */ -const SA1: f32 = 1.9651271820e+01; /* 0x419d35ce */ -const SA2: f32 = 1.3765776062e+02; /* 0x4309a863 */ -const SA3: f32 = 4.3456588745e+02; /* 0x43d9486f */ -const SA4: f32 = 6.4538726807e+02; /* 0x442158c9 */ -const SA5: f32 = 4.2900814819e+02; /* 0x43d6810b */ -const SA6: f32 = 1.0863500214e+02; /* 0x42d9451f */ -const SA7: f32 = 6.5702495575e+00; /* 0x40d23f7c */ -const SA8: f32 = -6.0424413532e-02; /* 0xbd777f97 */ -/* - * Coefficients for approximation to erfc in [1/.35,28] - */ -const RB0: f32 = -9.8649431020e-03; /* 0xbc21a092 */ -const RB1: f32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ -const RB2: f32 = -1.7757955551e+01; /* 0xc18e104b */ -const RB3: f32 = -1.6063638306e+02; /* 0xc320a2ea */ -const RB4: f32 = -6.3756646729e+02; /* 0xc41f6441 */ -const RB5: f32 = -1.0250950928e+03; /* 0xc480230b */ -const RB6: f32 = -4.8351919556e+02; /* 0xc3f1c275 */ -const SB1: f32 = 3.0338060379e+01; /* 0x41f2b459 */ -const SB2: f32 = 3.2579251099e+02; /* 0x43a2e571 */ -const SB3: f32 = 1.5367296143e+03; /* 0x44c01759 */ -const SB4: f32 = 3.1998581543e+03; /* 0x4547fdbb */ -const SB5: f32 = 2.5530502930e+03; /* 0x451f90ce */ -const SB6: f32 = 4.7452853394e+02; /* 0x43ed43a7 */ -const SB7: f32 = -2.2440952301e+01; /* 0xc1b38712 */ - -fn erfc1(x: f32) -> f32 { - let s: f32; - let p: f32; - let q: f32; - - s = fabsf(x) - 1.0; - p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); - q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); - return 1.0 - ERX - p / q; -} - -fn erfc2(mut ix: u32, mut x: f32) -> f32 { - let s: f32; - let r: f32; - let big_s: f32; - let z: f32; - - if ix < 0x3fa00000 { - /* |x| < 1.25 */ - return erfc1(x); - } - - x = fabsf(x); - s = 1.0 / (x * x); - if ix < 0x4036db6d { - /* |x| < 1/0.35 */ - r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); - big_s = 1.0 - + s * (SA1 - + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); - } else { - /* |x| >= 1/0.35 */ - r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); - big_s = - 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); - } - ix = x.to_bits(); - z = f32::from_bits(ix & 0xffffe000); - - expf(-z * z - 0.5625) * expf((z - x) * (z + x) + r / big_s) / x -} - -/// Error function (f32) -/// -/// Calculates an approximation to the “error function”, which estimates -/// the probability that an observation will fall within x standard -/// deviations of the mean (assuming a normal distribution). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn erff(x: f32) -> f32 { - let r: f32; - let s: f32; - let z: f32; - let y: f32; - let mut ix: u32; - let sign: usize; - - ix = x.to_bits(); - sign = (ix >> 31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - /* erf(nan)=nan, erf(+-inf)=+-1 */ - return 1.0 - 2.0 * (sign as f32) + 1.0 / x; - } - if ix < 0x3f580000 { - /* |x| < 0.84375 */ - if ix < 0x31800000 { - /* |x| < 2**-28 */ - /*avoid underflow */ - return 0.125 * (8.0 * x + EFX8 * x); - } - z = x * x; - r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); - s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); - y = r / s; - return x + x * y; - } - if ix < 0x40c00000 { - /* |x| < 6 */ - y = 1.0 - erfc2(ix, x); - } else { - let x1p_120 = f32::from_bits(0x03800000); - y = 1.0 - x1p_120; - } - - if sign != 0 { -y } else { y } -} - -/// Complementary error function (f32) -/// -/// Calculates the complementary probability. -/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid -/// the loss of precision that would result from subtracting -/// large probabilities (on large `x`) from 1. -pub fn erfcf(x: f32) -> f32 { - let r: f32; - let s: f32; - let z: f32; - let y: f32; - let mut ix: u32; - let sign: usize; - - ix = x.to_bits(); - sign = (ix >> 31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - /* erfc(nan)=nan, erfc(+-inf)=0,2 */ - return 2.0 * (sign as f32) + 1.0 / x; - } - - if ix < 0x3f580000 { - /* |x| < 0.84375 */ - if ix < 0x23800000 { - /* |x| < 2**-56 */ - return 1.0 - x; - } - z = x * x; - r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); - s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); - y = r / s; - if sign != 0 || ix < 0x3e800000 { - /* x < 1/4 */ - return 1.0 - (x + x * y); - } - return 0.5 - (x - 0.5 + x * y); - } - if ix < 0x41e00000 { - /* |x| < 28 */ - if sign != 0 { - return 2.0 - erfc2(ix, x); - } else { - return erfc2(ix, x); - } - } - - let x1p_120 = f32::from_bits(0x03800000); - if sign != 0 { 2.0 - x1p_120 } else { x1p_120 * x1p_120 } -} diff --git a/library/compiler-builtins/libm/libm/src/math/exp.rs b/library/compiler-builtins/libm/libm/src/math/exp.rs deleted file mode 100644 index 782042b62cd..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/exp.rs +++ /dev/null @@ -1,150 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */ -/* - * ==================================================== - * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. - * - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* exp(x) - * Returns the exponential of x. - * - * Method - * 1. Argument reduction: - * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. - * Given x, find r and integer k such that - * - * x = k*ln2 + r, |r| <= 0.5*ln2. - * - * Here r will be represented as r = hi-lo for better - * accuracy. - * - * 2. Approximation of exp(r) by a special rational function on - * the interval [0,0.34658]: - * Write - * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... - * We use a special Remez algorithm on [0,0.34658] to generate - * a polynomial of degree 5 to approximate R. The maximum error - * of this polynomial approximation is bounded by 2**-59. In - * other words, - * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 - * (where z=r*r, and the values of P1 to P5 are listed below) - * and - * | 5 | -59 - * | 2.0+P1*z+...+P5*z - R(z) | <= 2 - * | | - * The computation of exp(r) thus becomes - * 2*r - * exp(r) = 1 + ---------- - * R(r) - r - * r*c(r) - * = 1 + r + ----------- (for better accuracy) - * 2 - c(r) - * where - * 2 4 10 - * c(r) = r - (P1*r + P2*r + ... + P5*r ). - * - * 3. Scale back to obtain exp(x): - * From step 1, we have - * exp(x) = 2^k * exp(r) - * - * Special cases: - * exp(INF) is INF, exp(NaN) is NaN; - * exp(-INF) is 0, and - * for finite argument, only exp(0)=1 is exact. - * - * Accuracy: - * according to an error analysis, the error is always less than - * 1 ulp (unit in the last place). - * - * Misc. info. - * For IEEE double - * if x > 709.782712893383973096 then exp(x) overflows - * if x < -745.133219101941108420 then exp(x) underflows - */ - -use super::scalbn; - -const HALF: [f64; 2] = [0.5, -0.5]; -const LN2HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ -const LN2LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ -const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ -const P1: f64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */ -const P2: f64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ -const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ -const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ -const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ - -/// Exponential, base *e* (f64) -/// -/// Calculate the exponential of `x`, that is, *e* raised to the power `x` -/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp(mut x: f64) -> f64 { - let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 - let x1p_149 = f64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149 - - let hi: f64; - let lo: f64; - let c: f64; - let xx: f64; - let y: f64; - let k: i32; - let sign: i32; - let mut hx: u32; - - hx = (x.to_bits() >> 32) as u32; - sign = (hx >> 31) as i32; - hx &= 0x7fffffff; /* high word of |x| */ - - /* special cases */ - if hx >= 0x4086232b { - /* if |x| >= 708.39... */ - if x.is_nan() { - return x; - } - if x > 709.782712893383973096 { - /* overflow if x!=inf */ - x *= x1p1023; - return x; - } - if x < -708.39641853226410622 { - /* underflow if x!=-inf */ - force_eval!((-x1p_149 / x) as f32); - if x < -745.13321910194110842 { - return 0.; - } - } - } - - /* argument reduction */ - if hx > 0x3fd62e42 { - /* if |x| > 0.5 ln2 */ - if hx >= 0x3ff0a2b2 { - /* if |x| >= 1.5 ln2 */ - k = (INVLN2 * x + i!(HALF, sign as usize)) as i32; - } else { - k = 1 - sign - sign; - } - hi = x - k as f64 * LN2HI; /* k*ln2hi is exact here */ - lo = k as f64 * LN2LO; - x = hi - lo; - } else if hx > 0x3e300000 { - /* if |x| > 2**-28 */ - k = 0; - hi = x; - lo = 0.; - } else { - /* inexact if x!=0 */ - force_eval!(x1p1023 + x); - return 1. + x; - } - - /* x is now in primary range */ - xx = x * x; - c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); - y = 1. + (x * c / (2. - c) - lo + hi); - if k == 0 { y } else { scalbn(y, k) } -} diff --git a/library/compiler-builtins/libm/libm/src/math/exp10.rs b/library/compiler-builtins/libm/libm/src/math/exp10.rs deleted file mode 100644 index 7c33c92b603..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/exp10.rs +++ /dev/null @@ -1,23 +0,0 @@ -use super::{exp2, modf, pow}; - -const LN10: f64 = 3.32192809488736234787031942948939; -const P10: &[f64] = &[ - 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, -]; - -/// Calculates 10 raised to the power of `x` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp10(x: f64) -> f64 { - let (mut y, n) = modf(x); - let u: u64 = n.to_bits(); - /* fabs(n) < 16 without raising invalid on nan */ - if ((u >> 52) & 0x7ff) < 0x3ff + 4 { - if y == 0.0 { - return i!(P10, ((n as isize) + 15) as usize); - } - y = exp2(LN10 * y); - return y * i!(P10, ((n as isize) + 15) as usize); - } - return pow(10.0, x); -} diff --git a/library/compiler-builtins/libm/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/libm/src/math/exp10f.rs deleted file mode 100644 index 0520a41f2e9..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/exp10f.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{exp2, exp2f, modff}; - -const LN10_F32: f32 = 3.32192809488736234787031942948939; -const LN10_F64: f64 = 3.32192809488736234787031942948939; -const P10: &[f32] = - &[1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7]; - -/// Calculates 10 raised to the power of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp10f(x: f32) -> f32 { - let (mut y, n) = modff(x); - let u = n.to_bits(); - /* fabsf(n) < 8 without raising invalid on nan */ - if ((u >> 23) & 0xff) < 0x7f + 3 { - if y == 0.0 { - return i!(P10, ((n as isize) + 7) as usize); - } - y = exp2f(LN10_F32 * y); - return y * i!(P10, ((n as isize) + 7) as usize); - } - return exp2(LN10_F64 * (x as f64)) as f32; -} diff --git a/library/compiler-builtins/libm/libm/src/math/exp2.rs b/library/compiler-builtins/libm/libm/src/math/exp2.rs deleted file mode 100644 index 6e98d066cbf..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/exp2.rs +++ /dev/null @@ -1,394 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */ -//- -// Copyright (c) 2005 David Schultz -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. - -use super::scalbn; - -const TBLSIZE: usize = 256; - -#[rustfmt::skip] -static TBL: [u64; TBLSIZE * 2] = [ - // exp2(z + eps) eps - 0x3fe6a09e667f3d5d, 0x3d39880000000000, - 0x3fe6b052fa751744, 0x3cd8000000000000, - 0x3fe6c012750bd9fe, 0xbd28780000000000, - 0x3fe6cfdcddd476bf, 0x3d1ec00000000000, - 0x3fe6dfb23c651a29, 0xbcd8000000000000, - 0x3fe6ef9298593ae3, 0xbcbc000000000000, - 0x3fe6ff7df9519386, 0xbd2fd80000000000, - 0x3fe70f7466f42da3, 0xbd2c880000000000, - 0x3fe71f75e8ec5fc3, 0x3d13c00000000000, - 0x3fe72f8286eacf05, 0xbd38300000000000, - 0x3fe73f9a48a58152, 0xbd00c00000000000, - 0x3fe74fbd35d7ccfc, 0x3d2f880000000000, - 0x3fe75feb564267f1, 0x3d03e00000000000, - 0x3fe77024b1ab6d48, 0xbd27d00000000000, - 0x3fe780694fde5d38, 0xbcdd000000000000, - 0x3fe790b938ac1d00, 0x3ce3000000000000, - 0x3fe7a11473eb0178, 0xbced000000000000, - 0x3fe7b17b0976d060, 0x3d20400000000000, - 0x3fe7c1ed0130c133, 0x3ca0000000000000, - 0x3fe7d26a62ff8636, 0xbd26900000000000, - 0x3fe7e2f336cf4e3b, 0xbd02e00000000000, - 0x3fe7f3878491c3e8, 0xbd24580000000000, - 0x3fe80427543e1b4e, 0x3d33000000000000, - 0x3fe814d2add1071a, 0x3d0f000000000000, - 0x3fe82589994ccd7e, 0xbd21c00000000000, - 0x3fe8364c1eb942d0, 0x3d29d00000000000, - 0x3fe8471a4623cab5, 0x3d47100000000000, - 0x3fe857f4179f5bbc, 0x3d22600000000000, - 0x3fe868d99b4491af, 0xbd32c40000000000, - 0x3fe879cad931a395, 0xbd23000000000000, - 0x3fe88ac7d98a65b8, 0xbd2a800000000000, - 0x3fe89bd0a4785800, 0xbced000000000000, - 0x3fe8ace5422aa223, 0x3d33280000000000, - 0x3fe8be05bad619fa, 0x3d42b40000000000, - 0x3fe8cf3216b54383, 0xbd2ed00000000000, - 0x3fe8e06a5e08664c, 0xbd20500000000000, - 0x3fe8f1ae99157807, 0x3d28280000000000, - 0x3fe902fed0282c0e, 0xbd1cb00000000000, - 0x3fe9145b0b91ff96, 0xbd05e00000000000, - 0x3fe925c353aa2ff9, 0x3cf5400000000000, - 0x3fe93737b0cdc64a, 0x3d17200000000000, - 0x3fe948b82b5f98ae, 0xbd09000000000000, - 0x3fe95a44cbc852cb, 0x3d25680000000000, - 0x3fe96bdd9a766f21, 0xbd36d00000000000, - 0x3fe97d829fde4e2a, 0xbd01000000000000, - 0x3fe98f33e47a23a3, 0x3d2d000000000000, - 0x3fe9a0f170ca0604, 0xbd38a40000000000, - 0x3fe9b2bb4d53ff89, 0x3d355c0000000000, - 0x3fe9c49182a3f15b, 0x3d26b80000000000, - 0x3fe9d674194bb8c5, 0xbcec000000000000, - 0x3fe9e86319e3238e, 0x3d17d00000000000, - 0x3fe9fa5e8d07f302, 0x3d16400000000000, - 0x3fea0c667b5de54d, 0xbcf5000000000000, - 0x3fea1e7aed8eb8f6, 0x3d09e00000000000, - 0x3fea309bec4a2e27, 0x3d2ad80000000000, - 0x3fea42c980460a5d, 0xbd1af00000000000, - 0x3fea5503b23e259b, 0x3d0b600000000000, - 0x3fea674a8af46213, 0x3d38880000000000, - 0x3fea799e1330b3a7, 0x3d11200000000000, - 0x3fea8bfe53c12e8d, 0x3d06c00000000000, - 0x3fea9e6b5579fcd2, 0xbd29b80000000000, - 0x3feab0e521356fb8, 0x3d2b700000000000, - 0x3feac36bbfd3f381, 0x3cd9000000000000, - 0x3fead5ff3a3c2780, 0x3ce4000000000000, - 0x3feae89f995ad2a3, 0xbd2c900000000000, - 0x3feafb4ce622f367, 0x3d16500000000000, - 0x3feb0e07298db790, 0x3d2fd40000000000, - 0x3feb20ce6c9a89a9, 0x3d12700000000000, - 0x3feb33a2b84f1a4b, 0x3d4d470000000000, - 0x3feb468415b747e7, 0xbd38380000000000, - 0x3feb59728de5593a, 0x3c98000000000000, - 0x3feb6c6e29f1c56a, 0x3d0ad00000000000, - 0x3feb7f76f2fb5e50, 0x3cde800000000000, - 0x3feb928cf22749b2, 0xbd04c00000000000, - 0x3feba5b030a10603, 0xbd0d700000000000, - 0x3febb8e0b79a6f66, 0x3d0d900000000000, - 0x3febcc1e904bc1ff, 0x3d02a00000000000, - 0x3febdf69c3f3a16f, 0xbd1f780000000000, - 0x3febf2c25bd71db8, 0xbd10a00000000000, - 0x3fec06286141b2e9, 0xbd11400000000000, - 0x3fec199bdd8552e0, 0x3d0be00000000000, - 0x3fec2d1cd9fa64ee, 0xbd09400000000000, - 0x3fec40ab5fffd02f, 0xbd0ed00000000000, - 0x3fec544778fafd15, 0x3d39660000000000, - 0x3fec67f12e57d0cb, 0xbd1a100000000000, - 0x3fec7ba88988c1b6, 0xbd58458000000000, - 0x3fec8f6d9406e733, 0xbd1a480000000000, - 0x3feca3405751c4df, 0x3ccb000000000000, - 0x3fecb720dcef9094, 0x3d01400000000000, - 0x3feccb0f2e6d1689, 0x3cf0200000000000, - 0x3fecdf0b555dc412, 0x3cf3600000000000, - 0x3fecf3155b5bab3b, 0xbd06900000000000, - 0x3fed072d4a0789bc, 0x3d09a00000000000, - 0x3fed1b532b08c8fa, 0xbd15e00000000000, - 0x3fed2f87080d8a85, 0x3d1d280000000000, - 0x3fed43c8eacaa203, 0x3d01a00000000000, - 0x3fed5818dcfba491, 0x3cdf000000000000, - 0x3fed6c76e862e6a1, 0xbd03a00000000000, - 0x3fed80e316c9834e, 0xbd0cd80000000000, - 0x3fed955d71ff6090, 0x3cf4c00000000000, - 0x3feda9e603db32ae, 0x3cff900000000000, - 0x3fedbe7cd63a8325, 0x3ce9800000000000, - 0x3fedd321f301b445, 0xbcf5200000000000, - 0x3fede7d5641c05bf, 0xbd1d700000000000, - 0x3fedfc97337b9aec, 0xbd16140000000000, - 0x3fee11676b197d5e, 0x3d0b480000000000, - 0x3fee264614f5a3e7, 0x3d40ce0000000000, - 0x3fee3b333b16ee5c, 0x3d0c680000000000, - 0x3fee502ee78b3fb4, 0xbd09300000000000, - 0x3fee653924676d68, 0xbce5000000000000, - 0x3fee7a51fbc74c44, 0xbd07f80000000000, - 0x3fee8f7977cdb726, 0xbcf3700000000000, - 0x3feea4afa2a490e8, 0x3ce5d00000000000, - 0x3feeb9f4867ccae4, 0x3d161a0000000000, - 0x3feecf482d8e680d, 0x3cf5500000000000, - 0x3feee4aaa2188514, 0x3cc6400000000000, - 0x3feefa1bee615a13, 0xbcee800000000000, - 0x3fef0f9c1cb64106, 0xbcfa880000000000, - 0x3fef252b376bb963, 0xbd2c900000000000, - 0x3fef3ac948dd7275, 0x3caa000000000000, - 0x3fef50765b6e4524, 0xbcf4f00000000000, - 0x3fef6632798844fd, 0x3cca800000000000, - 0x3fef7bfdad9cbe38, 0x3cfabc0000000000, - 0x3fef91d802243c82, 0xbcd4600000000000, - 0x3fefa7c1819e908e, 0xbd0b0c0000000000, - 0x3fefbdba3692d511, 0xbcc0e00000000000, - 0x3fefd3c22b8f7194, 0xbd10de8000000000, - 0x3fefe9d96b2a23ee, 0x3cee430000000000, - 0x3ff0000000000000, 0x0, - 0x3ff00b1afa5abcbe, 0xbcb3400000000000, - 0x3ff0163da9fb3303, 0xbd12170000000000, - 0x3ff02168143b0282, 0x3cba400000000000, - 0x3ff02c9a3e77806c, 0x3cef980000000000, - 0x3ff037d42e11bbca, 0xbcc7400000000000, - 0x3ff04315e86e7f89, 0x3cd8300000000000, - 0x3ff04e5f72f65467, 0xbd1a3f0000000000, - 0x3ff059b0d315855a, 0xbd02840000000000, - 0x3ff0650a0e3c1f95, 0x3cf1600000000000, - 0x3ff0706b29ddf71a, 0x3d15240000000000, - 0x3ff07bd42b72a82d, 0xbce9a00000000000, - 0x3ff0874518759bd0, 0x3ce6400000000000, - 0x3ff092bdf66607c8, 0xbd00780000000000, - 0x3ff09e3ecac6f383, 0xbc98000000000000, - 0x3ff0a9c79b1f3930, 0x3cffa00000000000, - 0x3ff0b5586cf988fc, 0xbcfac80000000000, - 0x3ff0c0f145e46c8a, 0x3cd9c00000000000, - 0x3ff0cc922b724816, 0x3d05200000000000, - 0x3ff0d83b23395dd8, 0xbcfad00000000000, - 0x3ff0e3ec32d3d1f3, 0x3d1bac0000000000, - 0x3ff0efa55fdfa9a6, 0xbd04e80000000000, - 0x3ff0fb66affed2f0, 0xbd0d300000000000, - 0x3ff1073028d7234b, 0x3cf1500000000000, - 0x3ff11301d0125b5b, 0x3cec000000000000, - 0x3ff11edbab5e2af9, 0x3d16bc0000000000, - 0x3ff12abdc06c31d5, 0x3ce8400000000000, - 0x3ff136a814f2047d, 0xbd0ed00000000000, - 0x3ff1429aaea92de9, 0x3ce8e00000000000, - 0x3ff14e95934f3138, 0x3ceb400000000000, - 0x3ff15a98c8a58e71, 0x3d05300000000000, - 0x3ff166a45471c3df, 0x3d03380000000000, - 0x3ff172b83c7d5211, 0x3d28d40000000000, - 0x3ff17ed48695bb9f, 0xbd05d00000000000, - 0x3ff18af9388c8d93, 0xbd1c880000000000, - 0x3ff1972658375d66, 0x3d11f00000000000, - 0x3ff1a35beb6fcba7, 0x3d10480000000000, - 0x3ff1af99f81387e3, 0xbd47390000000000, - 0x3ff1bbe084045d54, 0x3d24e40000000000, - 0x3ff1c82f95281c43, 0xbd0a200000000000, - 0x3ff1d4873168b9b2, 0x3ce3800000000000, - 0x3ff1e0e75eb44031, 0x3ceac00000000000, - 0x3ff1ed5022fcd938, 0x3d01900000000000, - 0x3ff1f9c18438cdf7, 0xbd1b780000000000, - 0x3ff2063b88628d8f, 0x3d2d940000000000, - 0x3ff212be3578a81e, 0x3cd8000000000000, - 0x3ff21f49917ddd41, 0x3d2b340000000000, - 0x3ff22bdda2791323, 0x3d19f80000000000, - 0x3ff2387a6e7561e7, 0xbd19c80000000000, - 0x3ff2451ffb821427, 0x3d02300000000000, - 0x3ff251ce4fb2a602, 0xbd13480000000000, - 0x3ff25e85711eceb0, 0x3d12700000000000, - 0x3ff26b4565e27d16, 0x3d11d00000000000, - 0x3ff2780e341de00f, 0x3d31ee0000000000, - 0x3ff284dfe1f5633e, 0xbd14c00000000000, - 0x3ff291ba7591bb30, 0xbd13d80000000000, - 0x3ff29e9df51fdf09, 0x3d08b00000000000, - 0x3ff2ab8a66d10e9b, 0xbd227c0000000000, - 0x3ff2b87fd0dada3a, 0x3d2a340000000000, - 0x3ff2c57e39771af9, 0xbd10800000000000, - 0x3ff2d285a6e402d9, 0xbd0ed00000000000, - 0x3ff2df961f641579, 0xbcf4200000000000, - 0x3ff2ecafa93e2ecf, 0xbd24980000000000, - 0x3ff2f9d24abd8822, 0xbd16300000000000, - 0x3ff306fe0a31b625, 0xbd32360000000000, - 0x3ff31432edeea50b, 0xbd70df8000000000, - 0x3ff32170fc4cd7b8, 0xbd22480000000000, - 0x3ff32eb83ba8e9a2, 0xbd25980000000000, - 0x3ff33c08b2641766, 0x3d1ed00000000000, - 0x3ff3496266e3fa27, 0xbcdc000000000000, - 0x3ff356c55f929f0f, 0xbd30d80000000000, - 0x3ff36431a2de88b9, 0x3d22c80000000000, - 0x3ff371a7373aaa39, 0x3d20600000000000, - 0x3ff37f26231e74fe, 0xbd16600000000000, - 0x3ff38cae6d05d838, 0xbd0ae00000000000, - 0x3ff39a401b713ec3, 0xbd44720000000000, - 0x3ff3a7db34e5a020, 0x3d08200000000000, - 0x3ff3b57fbfec6e95, 0x3d3e800000000000, - 0x3ff3c32dc313a8f2, 0x3cef800000000000, - 0x3ff3d0e544ede122, 0xbd17a00000000000, - 0x3ff3dea64c1234bb, 0x3d26300000000000, - 0x3ff3ec70df1c4ecc, 0xbd48a60000000000, - 0x3ff3fa4504ac7e8c, 0xbd3cdc0000000000, - 0x3ff40822c367a0bb, 0x3d25b80000000000, - 0x3ff4160a21f72e95, 0x3d1ec00000000000, - 0x3ff423fb27094646, 0xbd13600000000000, - 0x3ff431f5d950a920, 0x3d23980000000000, - 0x3ff43ffa3f84b9eb, 0x3cfa000000000000, - 0x3ff44e0860618919, 0xbcf6c00000000000, - 0x3ff45c2042a7d201, 0xbd0bc00000000000, - 0x3ff46a41ed1d0016, 0xbd12800000000000, - 0x3ff4786d668b3326, 0x3d30e00000000000, - 0x3ff486a2b5c13c00, 0xbd2d400000000000, - 0x3ff494e1e192af04, 0x3d0c200000000000, - 0x3ff4a32af0d7d372, 0xbd1e500000000000, - 0x3ff4b17dea6db801, 0x3d07800000000000, - 0x3ff4bfdad53629e1, 0xbd13800000000000, - 0x3ff4ce41b817c132, 0x3d00800000000000, - 0x3ff4dcb299fddddb, 0x3d2c700000000000, - 0x3ff4eb2d81d8ab96, 0xbd1ce00000000000, - 0x3ff4f9b2769d2d02, 0x3d19200000000000, - 0x3ff508417f4531c1, 0xbd08c00000000000, - 0x3ff516daa2cf662a, 0xbcfa000000000000, - 0x3ff5257de83f51ea, 0x3d4a080000000000, - 0x3ff5342b569d4eda, 0xbd26d80000000000, - 0x3ff542e2f4f6ac1a, 0xbd32440000000000, - 0x3ff551a4ca5d94db, 0x3d483c0000000000, - 0x3ff56070dde9116b, 0x3d24b00000000000, - 0x3ff56f4736b529de, 0x3d415a0000000000, - 0x3ff57e27dbe2c40e, 0xbd29e00000000000, - 0x3ff58d12d497c76f, 0xbd23080000000000, - 0x3ff59c0827ff0b4c, 0x3d4dec0000000000, - 0x3ff5ab07dd485427, 0xbcc4000000000000, - 0x3ff5ba11fba87af4, 0x3d30080000000000, - 0x3ff5c9268a59460b, 0xbd26c80000000000, - 0x3ff5d84590998e3f, 0x3d469a0000000000, - 0x3ff5e76f15ad20e1, 0xbd1b400000000000, - 0x3ff5f6a320dcebca, 0x3d17700000000000, - 0x3ff605e1b976dcb8, 0x3d26f80000000000, - 0x3ff6152ae6cdf715, 0x3d01000000000000, - 0x3ff6247eb03a5531, 0xbd15d00000000000, - 0x3ff633dd1d1929b5, 0xbd12d00000000000, - 0x3ff6434634ccc313, 0xbcea800000000000, - 0x3ff652b9febc8efa, 0xbd28600000000000, - 0x3ff6623882553397, 0x3d71fe0000000000, - 0x3ff671c1c708328e, 0xbd37200000000000, - 0x3ff68155d44ca97e, 0x3ce6800000000000, - 0x3ff690f4b19e9471, 0xbd29780000000000, -]; - -// exp2(x): compute the base 2 exponential of x -// -// Accuracy: Peak error < 0.503 ulp for normalized results. -// -// Method: (accurate tables) -// -// Reduce x: -// x = k + y, for integer k and |y| <= 1/2. -// Thus we have exp2(x) = 2**k * exp2(y). -// -// Reduce y: -// y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. -// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), -// with |z - eps[i]| <= 2**-9 + 2**-39 for the table used. -// -// We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via -// a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61. -// The values in exp2t[] and eps[] are chosen such that -// exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such -// that exp2t[i] is accurate to 2**-64. -// -// Note that the range of i is +-TBLSIZE/2, so we actually index the tables -// by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are -// virtual tables, interleaved in the real table tbl[]. -// -// This method is due to Gal, with many details due to Gal and Bachelis: -// -// Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library -// for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). - -/// Exponential, base 2 (f64) -/// -/// Calculate `2^x`, that is, 2 raised to the power `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp2(mut x: f64) -> f64 { - let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64; - let p1 = f64::from_bits(0x3fe62e42fefa39ef); - let p2 = f64::from_bits(0x3fcebfbdff82c575); - let p3 = f64::from_bits(0x3fac6b08d704a0a6); - let p4 = f64::from_bits(0x3f83b2ab88f70400); - let p5 = f64::from_bits(0x3f55d88003875c74); - - // double_t r, t, z; - // uint32_t ix, i0; - // union {double f; uint64_t i;} u = {x}; - // union {uint32_t u; int32_t i;} k; - let x1p1023 = f64::from_bits(0x7fe0000000000000); - let x1p52 = f64::from_bits(0x4330000000000000); - let _0x1p_149 = f64::from_bits(0xb6a0000000000000); - - /* Filter out exceptional cases. */ - let ui = f64::to_bits(x); - let ix = (ui >> 32) & 0x7fffffff; - if ix >= 0x408ff000 { - /* |x| >= 1022 or nan */ - if ix >= 0x40900000 && ui >> 63 == 0 { - /* x >= 1024 or nan */ - /* overflow */ - x *= x1p1023; - return x; - } - if ix >= 0x7ff00000 { - /* -inf or -nan */ - return -1.0 / x; - } - if ui >> 63 != 0 { - /* x <= -1022 */ - /* underflow */ - if x <= -1075.0 || x - x1p52 + x1p52 != x { - force_eval!((_0x1p_149 / x) as f32); - } - if x <= -1075.0 { - return 0.0; - } - } - } else if ix < 0x3c900000 { - /* |x| < 0x1p-54 */ - return 1.0 + x; - } - - /* Reduce x, computing z, i0, and k. */ - let ui = f64::to_bits(x + redux); - let mut i0 = ui as u32; - i0 = i0.wrapping_add(TBLSIZE as u32 / 2); - let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32; - let ki = div!(ku as i32, TBLSIZE as i32); - i0 %= TBLSIZE as u32; - let uf = f64::from_bits(ui) - redux; - let mut z = x - uf; - - /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ - let t = f64::from_bits(i!(TBL, 2 * i0 as usize)); /* exp2t[i0] */ - z -= f64::from_bits(i!(TBL, 2 * i0 as usize + 1)); /* eps[i0] */ - let r = t + t * z * (p1 + z * (p2 + z * (p3 + z * (p4 + z * p5)))); - - scalbn(r, ki) -} - -#[test] -fn i0_wrap_test() { - let x = -3.0 / 256.0; - assert_eq!(exp2(x), f64::from_bits(0x3fefbdba3692d514)); -} diff --git a/library/compiler-builtins/libm/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/libm/src/math/exp2f.rs deleted file mode 100644 index f452b6a20f8..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/exp2f.rs +++ /dev/null @@ -1,135 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c -//- -// Copyright (c) 2005 David Schultz -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. - -const TBLSIZE: usize = 16; - -static EXP2FT: [u64; TBLSIZE] = [ - 0x3fe6a09e667f3bcd, - 0x3fe7a11473eb0187, - 0x3fe8ace5422aa0db, - 0x3fe9c49182a3f090, - 0x3feae89f995ad3ad, - 0x3fec199bdd85529c, - 0x3fed5818dcfba487, - 0x3feea4afa2a490da, - 0x3ff0000000000000, - 0x3ff0b5586cf9890f, - 0x3ff172b83c7d517b, - 0x3ff2387a6e756238, - 0x3ff306fe0a31b715, - 0x3ff3dea64c123422, - 0x3ff4bfdad5362a27, - 0x3ff5ab07dd485429, -]; - -// exp2f(x): compute the base 2 exponential of x -// -// Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. -// -// Method: (equally-spaced tables) -// -// Reduce x: -// x = k + y, for integer k and |y| <= 1/2. -// Thus we have exp2f(x) = 2**k * exp2(y). -// -// Reduce y: -// y = i/TBLSIZE + z for integer i near y * TBLSIZE. -// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), -// with |z| <= 2**-(TBLSIZE+1). -// -// We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a -// degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. -// Using double precision for everything except the reduction makes -// roundoff error insignificant and simplifies the scaling step. -// -// This method is due to Tang, but I do not use his suggested parameters: -// -// Tang, P. Table-driven Implementation of the Exponential Function -// in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). - -/// Exponential, base 2 (f32) -/// -/// Calculate `2^x`, that is, 2 raised to the power `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp2f(mut x: f32) -> f32 { - let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; - let p1 = f32::from_bits(0x3f317218); - let p2 = f32::from_bits(0x3e75fdf0); - let p3 = f32::from_bits(0x3d6359a4); - let p4 = f32::from_bits(0x3c1d964e); - - // double_t t, r, z; - // uint32_t ix, i0, k; - - let x1p127 = f32::from_bits(0x7f000000); - - /* Filter out exceptional cases. */ - let ui = f32::to_bits(x); - let ix = ui & 0x7fffffff; - if ix > 0x42fc0000 { - /* |x| > 126 */ - if ix > 0x7f800000 { - /* NaN */ - return x; - } - if (0x43000000..0x80000000).contains(&ui) { - /* x >= 128 */ - x *= x1p127; - return x; - } - if ui >= 0x80000000 { - /* x < -126 */ - if ui >= 0xc3160000 || (ui & 0x0000ffff != 0) { - force_eval!(f32::from_bits(0x80000001) / x); - } - if ui >= 0xc3160000 { - /* x <= -150 */ - return 0.0; - } - } - } else if ix <= 0x33000000 { - /* |x| <= 0x1p-25 */ - return 1.0 + x; - } - - /* Reduce x, computing z, i0, and k. */ - let ui = f32::to_bits(x + redux); - let mut i0 = ui; - i0 += TBLSIZE as u32 / 2; - let k = i0 / TBLSIZE as u32; - let ukf = f64::from_bits(((0x3ff + k) as u64) << 52); - i0 &= TBLSIZE as u32 - 1; - let mut uf = f32::from_bits(ui); - uf -= redux; - let z: f64 = (x - uf) as f64; - /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ - let r: f64 = f64::from_bits(i!(EXP2FT, i0 as usize)); - let t: f64 = r * z; - let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64); - - /* Scale by 2**k */ - (r * ukf) as f32 -} diff --git a/library/compiler-builtins/libm/libm/src/math/expf.rs b/library/compiler-builtins/libm/libm/src/math/expf.rs deleted file mode 100644 index 8dc067ab084..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/expf.rs +++ /dev/null @@ -1,97 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::scalbnf; - -const HALF: [f32; 2] = [0.5, -0.5]; -const LN2_HI: f32 = 6.9314575195e-01; /* 0x3f317200 */ -const LN2_LO: f32 = 1.4286067653e-06; /* 0x35bfbe8e */ -const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ -/* - * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: - * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 - */ -const P1: f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ -const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ - -/// Exponential, base *e* (f32) -/// -/// Calculate the exponential of `x`, that is, *e* raised to the power `x` -/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn expf(mut x: f32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ - let mut hx = x.to_bits(); - let sign = (hx >> 31) as i32; /* sign bit of x */ - let signb: bool = sign != 0; - hx &= 0x7fffffff; /* high word of |x| */ - - /* special cases */ - if hx >= 0x42aeac50 { - /* if |x| >= -87.33655f or NaN */ - if hx > 0x7f800000 { - /* NaN */ - return x; - } - if (hx >= 0x42b17218) && (!signb) { - /* x >= 88.722839f */ - /* overflow */ - x *= x1p127; - return x; - } - if signb { - /* underflow */ - force_eval!(-x1p_126 / x); - if hx >= 0x42cff1b5 { - /* x <= -103.972084f */ - return 0.; - } - } - } - - /* argument reduction */ - let k: i32; - let hi: f32; - let lo: f32; - if hx > 0x3eb17218 { - /* if |x| > 0.5 ln2 */ - if hx > 0x3f851592 { - /* if |x| > 1.5 ln2 */ - k = (INV_LN2 * x + i!(HALF, sign as usize)) as i32; - } else { - k = 1 - sign - sign; - } - let kf = k as f32; - hi = x - kf * LN2_HI; /* k*ln2hi is exact here */ - lo = kf * LN2_LO; - x = hi - lo; - } else if hx > 0x39000000 { - /* |x| > 2**-14 */ - k = 0; - hi = x; - lo = 0.; - } else { - /* raise inexact */ - force_eval!(x1p127 + x); - return 1. + x; - } - - /* x is now in primary range */ - let xx = x * x; - let c = x - xx * (P1 + xx * P2); - let y = 1. + (x * c / (2. - c) - lo + hi); - if k == 0 { y } else { scalbnf(y, k) } -} diff --git a/library/compiler-builtins/libm/libm/src/math/expm1.rs b/library/compiler-builtins/libm/libm/src/math/expm1.rs deleted file mode 100644 index f25153f32a3..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/expm1.rs +++ /dev/null @@ -1,144 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::f64; - -const O_THRESHOLD: f64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ -const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ -const LN2_LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ -const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ -/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ -const Q1: f64 = -3.33333333333331316428e-02; /* BFA11111 111110F4 */ -const Q2: f64 = 1.58730158725481460165e-03; /* 3F5A01A0 19FE5585 */ -const Q3: f64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ -const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ -const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ - -/// Exponential, base *e*, of x-1 (f64) -/// -/// Calculates the exponential of `x` and subtract 1, that is, *e* raised -/// to the power `x` minus 1 (where *e* is the base of the natural -/// system of logarithms, approximately 2.71828). -/// The result is accurate even for small values of `x`, -/// where using `exp(x)-1` would lose many significant digits. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn expm1(mut x: f64) -> f64 { - let hi: f64; - let lo: f64; - let k: i32; - let c: f64; - let mut t: f64; - let mut y: f64; - - let mut ui = x.to_bits(); - let hx = ((ui >> 32) & 0x7fffffff) as u32; - let sign = (ui >> 63) as i32; - - /* filter out huge and non-finite argument */ - if hx >= 0x4043687A { - /* if |x|>=56*ln2 */ - if x.is_nan() { - return x; - } - if sign != 0 { - return -1.0; - } - if x > O_THRESHOLD { - x *= f64::from_bits(0x7fe0000000000000); - return x; - } - } - - /* argument reduction */ - if hx > 0x3fd62e42 { - /* if |x| > 0.5 ln2 */ - if hx < 0x3FF0A2B2 { - /* and |x| < 1.5 ln2 */ - if sign == 0 { - hi = x - LN2_HI; - lo = LN2_LO; - k = 1; - } else { - hi = x + LN2_HI; - lo = -LN2_LO; - k = -1; - } - } else { - k = (INVLN2 * x + if sign != 0 { -0.5 } else { 0.5 }) as i32; - t = k as f64; - hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ - lo = t * LN2_LO; - } - x = hi - lo; - c = (hi - x) - lo; - } else if hx < 0x3c900000 { - /* |x| < 2**-54, return x */ - if hx < 0x00100000 { - force_eval!(x); - } - return x; - } else { - c = 0.0; - k = 0; - } - - /* x is now in primary range */ - let hfx = 0.5 * x; - let hxs = x * hfx; - let r1 = 1.0 + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5)))); - t = 3.0 - r1 * hfx; - let mut e = hxs * ((r1 - t) / (6.0 - x * t)); - if k == 0 { - /* c is 0 */ - return x - (x * e - hxs); - } - e = x * (e - c) - c; - e -= hxs; - /* exp(x) ~ 2^k (x_reduced - e + 1) */ - if k == -1 { - return 0.5 * (x - e) - 0.5; - } - if k == 1 { - if x < -0.25 { - return -2.0 * (e - (x + 0.5)); - } - return 1.0 + 2.0 * (x - e); - } - ui = ((0x3ff + k) as u64) << 52; /* 2^k */ - let twopk = f64::from_bits(ui); - if !(0..=56).contains(&k) { - /* suffice to return exp(x)-1 */ - y = x - e + 1.0; - if k == 1024 { - y = y * 2.0 * f64::from_bits(0x7fe0000000000000); - } else { - y = y * twopk; - } - return y - 1.0; - } - ui = ((0x3ff - k) as u64) << 52; /* 2^-k */ - let uf = f64::from_bits(ui); - if k < 20 { - y = (x - e + (1.0 - uf)) * twopk; - } else { - y = (x - (e + uf) + 1.0) * twopk; - } - y -} - -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::expm1(1.1), 2.0041660239464334); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/libm/src/math/expm1f.rs deleted file mode 100644 index 12c6f532b96..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/expm1f.rs +++ /dev/null @@ -1,130 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -const O_THRESHOLD: f32 = 8.8721679688e+01; /* 0x42b17180 */ -const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ -const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ -/* - * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: - * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 - * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): - */ -const Q1: f32 = -3.3333212137e-2; /* -0x888868.0p-28 */ -const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ - -/// Exponential, base *e*, of x-1 (f32) -/// -/// Calculates the exponential of `x` and subtract 1, that is, *e* raised -/// to the power `x` minus 1 (where *e* is the base of the natural -/// system of logarithms, approximately 2.71828). -/// The result is accurate even for small values of `x`, -/// where using `exp(x)-1` would lose many significant digits. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn expm1f(mut x: f32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - - let mut hx = x.to_bits(); - let sign = (hx >> 31) != 0; - hx &= 0x7fffffff; - - /* filter out huge and non-finite argument */ - if hx >= 0x4195b844 { - /* if |x|>=27*ln2 */ - if hx > 0x7f800000 { - /* NaN */ - return x; - } - if sign { - return -1.; - } - if x > O_THRESHOLD { - x *= x1p127; - return x; - } - } - - let k: i32; - let hi: f32; - let lo: f32; - let mut c = 0f32; - /* argument reduction */ - if hx > 0x3eb17218 { - /* if |x| > 0.5 ln2 */ - if hx < 0x3F851592 { - /* and |x| < 1.5 ln2 */ - if !sign { - hi = x - LN2_HI; - lo = LN2_LO; - k = 1; - } else { - hi = x + LN2_HI; - lo = -LN2_LO; - k = -1; - } - } else { - k = (INV_LN2 * x + (if sign { -0.5 } else { 0.5 })) as i32; - let t = k as f32; - hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ - lo = t * LN2_LO; - } - x = hi - lo; - c = (hi - x) - lo; - } else if hx < 0x33000000 { - /* when |x|<2**-25, return x */ - if hx < 0x00800000 { - force_eval!(x * x); - } - return x; - } else { - k = 0; - } - - /* x is now in primary range */ - let hfx = 0.5 * x; - let hxs = x * hfx; - let r1 = 1. + hxs * (Q1 + hxs * Q2); - let t = 3. - r1 * hfx; - let mut e = hxs * ((r1 - t) / (6. - x * t)); - if k == 0 { - /* c is 0 */ - return x - (x * e - hxs); - } - e = x * (e - c) - c; - e -= hxs; - /* exp(x) ~ 2^k (x_reduced - e + 1) */ - if k == -1 { - return 0.5 * (x - e) - 0.5; - } - if k == 1 { - if x < -0.25 { - return -2. * (e - (x + 0.5)); - } - return 1. + 2. * (x - e); - } - let twopk = f32::from_bits(((0x7f + k) << 23) as u32); /* 2^k */ - if !(0..=56).contains(&k) { - /* suffice to return exp(x)-1 */ - let mut y = x - e + 1.; - if k == 128 { - y = y * 2. * x1p127; - } else { - y = y * twopk; - } - return y - 1.; - } - let uf = f32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */ - if k < 23 { (x - e + (1. - uf)) * twopk } else { (x - (e + uf) + 1.) * twopk } -} diff --git a/library/compiler-builtins/libm/libm/src/math/expo2.rs b/library/compiler-builtins/libm/libm/src/math/expo2.rs deleted file mode 100644 index 82e9b360a76..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/expo2.rs +++ /dev/null @@ -1,14 +0,0 @@ -use super::{combine_words, exp}; - -/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn expo2(x: f64) -> f64 { - /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ - const K: i32 = 2043; - let kln2 = f64::from_bits(0x40962066151add8b); - - /* note that k is odd and scale*scale overflows */ - let scale = combine_words(((0x3ff + K / 2) as u32) << 20, 0); - /* exp(x - k ln2) * 2**(k-1) */ - exp(x - kln2) * scale * scale -} diff --git a/library/compiler-builtins/libm/libm/src/math/fabs.rs b/library/compiler-builtins/libm/libm/src/math/fabs.rs deleted file mode 100644 index 0050a309fee..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fabs.rs +++ /dev/null @@ -1,116 +0,0 @@ -/// Absolute value (magnitude) (f16) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf16(x: f16) -> f16 { - super::generic::fabs(x) -} - -/// Absolute value (magnitude) (f32) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf(x: f32) -> f32 { - select_implementation! { - name: fabsf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::fabs(x) -} - -/// Absolute value (magnitude) (f64) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabs(x: f64) -> f64 { - select_implementation! { - name: fabs, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::fabs(x) -} - -/// Absolute value (magnitude) (f128) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf128(x: f128) -> f128 { - super::generic::fabs(x) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Float; - - /// Based on https://en.cppreference.com/w/cpp/numeric/math/fabs - fn spec_test(f: impl Fn(F) -> F) { - assert_biteq!(f(F::ZERO), F::ZERO); - assert_biteq!(f(F::NEG_ZERO), F::ZERO); - assert_biteq!(f(F::INFINITY), F::INFINITY); - assert_biteq!(f(F::NEG_INFINITY), F::INFINITY); - assert!(f(F::NAN).is_nan()); - - // Not spec rewquired but we expect it - assert!(f(F::NAN).is_sign_positive()); - assert!(f(F::from_bits(F::NAN.to_bits() | F::SIGN_MASK)).is_sign_positive()); - } - - #[test] - #[cfg(f16_enabled)] - fn sanity_check_f16() { - assert_eq!(fabsf16(-1.0f16), 1.0); - assert_eq!(fabsf16(2.8f16), 2.8); - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(fabsf16); - } - - #[test] - fn sanity_check_f32() { - assert_eq!(fabsf(-1.0f32), 1.0); - assert_eq!(fabsf(2.8f32), 2.8); - } - - #[test] - fn spec_tests_f32() { - spec_test::(fabsf); - } - - #[test] - fn sanity_check_f64() { - assert_eq!(fabs(-1.0f64), 1.0); - assert_eq!(fabs(2.8f64), 2.8); - } - - #[test] - fn spec_tests_f64() { - spec_test::(fabs); - } - - #[test] - #[cfg(f128_enabled)] - fn sanity_check_f128() { - assert_eq!(fabsf128(-1.0f128), 1.0); - assert_eq!(fabsf128(2.8f128), 2.8); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(fabsf128); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/libm/src/math/fabsf.rs deleted file mode 100644 index e5820a26c52..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fabsf.rs +++ /dev/null @@ -1,39 +0,0 @@ -/// Absolute value (magnitude) (f32) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf(x: f32) -> f32 { - select_implementation! { - name: fabsf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::fabs(x) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf(-1.0), 1.0); - assert_eq!(fabsf(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf(f32::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf(f), 0.0); - } - for f in [f32::INFINITY, f32::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf(f), f32::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/fabsf128.rs b/library/compiler-builtins/libm/libm/src/math/fabsf128.rs deleted file mode 100644 index 46429ca4940..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fabsf128.rs +++ /dev/null @@ -1,31 +0,0 @@ -/// Absolute value (magnitude) (f128) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf128(x: f128) -> f128 { - super::generic::fabs(x) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf128(-1.0), 1.0); - assert_eq!(fabsf128(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf128(f128::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf128(f), 0.0); - } - for f in [f128::INFINITY, f128::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf128(f), f128::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/fabsf16.rs b/library/compiler-builtins/libm/libm/src/math/fabsf16.rs deleted file mode 100644 index eee42ac6a3c..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fabsf16.rs +++ /dev/null @@ -1,31 +0,0 @@ -/// Absolute value (magnitude) (f16) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf16(x: f16) -> f16 { - super::generic::fabs(x) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf16(-1.0), 1.0); - assert_eq!(fabsf16(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf16(f16::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf16(f), 0.0); - } - for f in [f16::INFINITY, f16::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf16(f), f16::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/fdim.rs b/library/compiler-builtins/libm/libm/src/math/fdim.rs deleted file mode 100644 index 082c5478b2a..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fdim.rs +++ /dev/null @@ -1,53 +0,0 @@ -/// Positive difference (f16) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf16(x: f16, y: f16) -> f16 { - super::generic::fdim(x, y) -} - -/// Positive difference (f32) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf(x: f32, y: f32) -> f32 { - super::generic::fdim(x, y) -} - -/// Positive difference (f64) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdim(x: f64, y: f64) -> f64 { - super::generic::fdim(x, y) -} - -/// Positive difference (f128) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf128(x: f128, y: f128) -> f128 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/libm/src/math/fdimf.rs deleted file mode 100644 index 367ef517c63..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fdimf.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f32) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf(x: f32, y: f32) -> f32 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/libm/src/math/fdimf128.rs b/library/compiler-builtins/libm/libm/src/math/fdimf128.rs deleted file mode 100644 index 6f3d1d0ff1d..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fdimf128.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f128) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf128(x: f128, y: f128) -> f128 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/libm/src/math/fdimf16.rs b/library/compiler-builtins/libm/libm/src/math/fdimf16.rs deleted file mode 100644 index 37bd6885817..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fdimf16.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f16) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf16(x: f16, y: f16) -> f16 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/libm/src/math/floor.rs b/library/compiler-builtins/libm/libm/src/math/floor.rs deleted file mode 100644 index 3c5eab101d1..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/floor.rs +++ /dev/null @@ -1,46 +0,0 @@ -/// Floor (f16) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf16(x: f16) -> f16 { - return super::generic::floor(x); -} - -/// Floor (f64) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floor(x: f64) -> f64 { - select_implementation! { - name: floor, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), - args: x, - } - - return super::generic::floor(x); -} - -/// Floor (f32) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf(x: f32) -> f32 { - select_implementation! { - name: floorf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - return super::generic::floor(x); -} - -/// Floor (f128) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf128(x: f128) -> f128 { - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/libm/src/math/floorf.rs b/library/compiler-builtins/libm/libm/src/math/floorf.rs deleted file mode 100644 index 16957b7f355..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/floorf.rs +++ /dev/null @@ -1,13 +0,0 @@ -/// Floor (f32) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf(x: f32) -> f32 { - select_implementation! { - name: floorf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/libm/src/math/floorf128.rs b/library/compiler-builtins/libm/libm/src/math/floorf128.rs deleted file mode 100644 index 9a9fe415115..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/floorf128.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Floor (f128) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf128(x: f128) -> f128 { - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/libm/src/math/floorf16.rs b/library/compiler-builtins/libm/libm/src/math/floorf16.rs deleted file mode 100644 index f9b868e0410..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/floorf16.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Floor (f16) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf16(x: f16) -> f16 { - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/libm/src/math/fma.rs b/library/compiler-builtins/libm/libm/src/math/fma.rs deleted file mode 100644 index e0b3347acf8..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fma.rs +++ /dev/null @@ -1,397 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ - -use super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; -use super::{CastFrom, CastInto, Float, Int, MinInt}; - -/// Fused multiply add (f64) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fma(x: f64, y: f64, z: f64) -> f64 { - select_implementation! { - name: fma, - use_arch: all(target_arch = "aarch64", target_feature = "neon"), - args: x, y, z, - } - - fma_round(x, y, z, Round::Nearest).val -} - -/// Fused multiply add (f128) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { - fma_round(x, y, z, Round::Nearest).val -} - -/// Fused multiply-add that works when there is not a larger float size available. Computes -/// `(x * y) + z`. -#[inline] -pub fn fma_round(x: F, y: F, z: F, _round: Round) -> FpResult -where - F: Float, - F: CastFrom, - F: CastFrom, - F::Int: HInt, - u32: CastInto, -{ - let one = IntTy::::ONE; - let zero = IntTy::::ZERO; - - // Normalize such that the top of the mantissa is zero and we have a guard bit. - let nx = Norm::from_float(x); - let ny = Norm::from_float(y); - let nz = Norm::from_float(z); - - if nx.is_zero_nan_inf() || ny.is_zero_nan_inf() { - // Value will overflow, defer to non-fused operations. - return FpResult::ok(x * y + z); - } - - if nz.is_zero_nan_inf() { - if nz.is_zero() { - // Empty add component means we only need to multiply. - return FpResult::ok(x * y); - } - // `z` is NaN or infinity, which sets the result. - return FpResult::ok(z); - } - - // multiply: r = x * y - let zhi: F::Int; - let zlo: F::Int; - let (mut rlo, mut rhi) = nx.m.widen_mul(ny.m).lo_hi(); - - // Exponent result of multiplication - let mut e: i32 = nx.e + ny.e; - // Needed shift to align `z` to the multiplication result - let mut d: i32 = nz.e - e; - let sbits = F::BITS as i32; - - // Scale `z`. Shift `z <<= kz`, `r >>= kr`, so `kz+kr == d`, set `e = e+kr` (== ez-kz) - if d > 0 { - // The magnitude of `z` is larger than `x * y` - if d < sbits { - // Maximum shift of one `F::BITS` means shifted `z` will fit into `2 * F::BITS`. Shift - // it into `(zhi, zlo)`. No exponent adjustment necessary. - zlo = nz.m << d; - zhi = nz.m >> (sbits - d); - } else { - // Shift larger than `sbits`, `z` only needs the top half `zhi`. Place it there (acts - // as a shift by `sbits`). - zlo = zero; - zhi = nz.m; - d -= sbits; - - // `z`'s exponent is large enough that it now needs to be taken into account. - e = nz.e - sbits; - - if d == 0 { - // Exactly `sbits`, nothing to do - } else if d < sbits { - // Remaining shift fits within `sbits`. Leave `z` in place, shift `x * y` - rlo = (rhi << (sbits - d)) | (rlo >> d); - // Set the sticky bit - rlo |= IntTy::::from((rlo << (sbits - d)) != zero); - rhi = rhi >> d; - } else { - // `z`'s magnitude is enough that `x * y` is irrelevant. It was nonzero, so set - // the sticky bit. - rlo = one; - rhi = zero; - } - } - } else { - // `z`'s magnitude once shifted fits entirely within `zlo` - zhi = zero; - d = -d; - if d == 0 { - // No shift needed - zlo = nz.m; - } else if d < sbits { - // Shift s.t. `nz.m` fits into `zlo` - let sticky = IntTy::::from((nz.m << (sbits - d)) != zero); - zlo = (nz.m >> d) | sticky; - } else { - // Would be entirely shifted out, only set the sticky bit - zlo = one; - } - } - - /* addition */ - - let mut neg = nx.neg ^ ny.neg; - let samesign: bool = !neg ^ nz.neg; - let mut rhi_nonzero = true; - - if samesign { - // r += z - rlo = rlo.wrapping_add(zlo); - rhi += zhi + IntTy::::from(rlo < zlo); - } else { - // r -= z - let (res, borrow) = rlo.overflowing_sub(zlo); - rlo = res; - rhi = rhi.wrapping_sub(zhi.wrapping_add(IntTy::::from(borrow))); - if (rhi >> (F::BITS - 1)) != zero { - rlo = rlo.signed().wrapping_neg().unsigned(); - rhi = rhi.signed().wrapping_neg().unsigned() - IntTy::::from(rlo != zero); - neg = !neg; - } - rhi_nonzero = rhi != zero; - } - - /* Construct result */ - - // Shift result into `rhi`, left-aligned. Last bit is sticky - if rhi_nonzero { - // `d` > 0, need to shift both `rhi` and `rlo` into result - e += sbits; - d = rhi.leading_zeros() as i32 - 1; - rhi = (rhi << d) | (rlo >> (sbits - d)); - // Update sticky - rhi |= IntTy::::from((rlo << d) != zero); - } else if rlo != zero { - // `rhi` is zero, `rlo` is the entire result and needs to be shifted - d = rlo.leading_zeros() as i32 - 1; - if d < 0 { - // Shift and set sticky - rhi = (rlo >> 1) | (rlo & one); - } else { - rhi = rlo << d; - } - } else { - // exact +/- 0.0 - return FpResult::ok(x * y + z); - } - - e -= d; - - // Use int->float conversion to populate the significand. - // i is in [1 << (BITS - 2), (1 << (BITS - 1)) - 1] - let mut i: F::SignedInt = rhi.signed(); - - if neg { - i = -i; - } - - // `|r|` is in `[0x1p62,0x1p63]` for `f64` - let mut r: F = F::cast_from_lossy(i); - - /* Account for subnormal and rounding */ - - // Unbiased exponent for the maximum value of `r` - let max_pow = F::BITS - 1 + F::EXP_BIAS; - - let mut status = Status::OK; - - if e < -(max_pow as i32 - 2) { - // Result is subnormal before rounding - if e == -(max_pow as i32 - 1) { - let mut c = F::from_parts(false, max_pow, zero); - if neg { - c = -c; - } - - if r == c { - // Min normal after rounding, - status.set_underflow(true); - r = F::MIN_POSITIVE_NORMAL.copysign(r); - return FpResult::new(r, status); - } - - if (rhi << (F::SIG_BITS + 1)) != zero { - // Account for truncated bits. One bit will be lost in the `scalbn` call, add - // another top bit to avoid double rounding if inexact. - let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << (F::BITS - 2)); - i = iu.signed(); - - if neg { - i = -i; - } - - r = F::cast_from_lossy(i); - - // Remove the top bit - r = F::cast_from(2i8) * r - c; - status.set_underflow(true); - } - } else { - // Only round once when scaled - d = F::EXP_BITS as i32 - 1; - let sticky = IntTy::::from(rhi << (F::BITS as i32 - d) != zero); - i = (((rhi >> d) | sticky) << d).signed(); - - if neg { - i = -i; - } - - r = F::cast_from_lossy(i); - } - } - - // Use our exponent to scale the final value. - FpResult::new(super::generic::scalbn(r, e), status) -} - -/// Representation of `F` that has handled subnormals. -#[derive(Clone, Copy, Debug)] -struct Norm { - /// Normalized significand with one guard bit, unsigned. - m: F::Int, - /// Exponent of the mantissa such that `m * 2^e = x`. Accounts for the shift in the mantissa - /// and the guard bit; that is, 1.0 will normalize as `m = 1 << 53` and `e = -53`. - e: i32, - neg: bool, -} - -impl Norm { - /// Unbias the exponent and account for the mantissa's precision, including the guard bit. - const EXP_UNBIAS: u32 = F::EXP_BIAS + F::SIG_BITS + 1; - - /// Values greater than this had a saturated exponent (infinity or NaN), OR were zero and we - /// adjusted the exponent such that it exceeds this threashold. - const ZERO_INF_NAN: u32 = F::EXP_SAT - Self::EXP_UNBIAS; - - fn from_float(x: F) -> Self { - let mut ix = x.to_bits(); - let mut e = x.ex() as i32; - let neg = x.is_sign_negative(); - if e == 0 { - // Normalize subnormals by multiplication - let scale_i = F::BITS - 1; - let scale_f = F::from_parts(false, scale_i + F::EXP_BIAS, F::Int::ZERO); - let scaled = x * scale_f; - ix = scaled.to_bits(); - e = scaled.ex() as i32; - e = if e == 0 { - // If the exponent is still zero, the input was zero. Artifically set this value - // such that the final `e` will exceed `ZERO_INF_NAN`. - 1 << F::EXP_BITS - } else { - // Otherwise, account for the scaling we just did. - e - scale_i as i32 - }; - } - - e -= Self::EXP_UNBIAS as i32; - - // Absolute value, set the implicit bit, and shift to create a guard bit - ix &= F::SIG_MASK; - ix |= F::IMPLICIT_BIT; - ix <<= 1; - - Self { m: ix, e, neg } - } - - /// True if the value was zero, infinity, or NaN. - fn is_zero_nan_inf(self) -> bool { - self.e >= Self::ZERO_INF_NAN as i32 - } - - /// The only value we have - fn is_zero(self) -> bool { - // The only exponent that strictly exceeds this value is our sentinel value for zero. - self.e > Self::ZERO_INF_NAN as i32 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - /// Test the generic `fma_round` algorithm for a given float. - fn spec_test() - where - F: Float, - F: CastFrom, - F: CastFrom, - F::Int: HInt, - u32: CastInto, - { - let x = F::from_bits(F::Int::ONE); - let y = F::from_bits(F::Int::ONE); - let z = F::ZERO; - - let fma = |x, y, z| fma_round(x, y, z, Round::Nearest).val; - - // 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of - // fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the - // exact result" - assert_biteq!(fma(x, y, z), F::ZERO); - assert_biteq!(fma(x, -y, z), F::NEG_ZERO); - assert_biteq!(fma(-x, y, z), F::NEG_ZERO); - assert_biteq!(fma(-x, -y, z), F::ZERO); - } - - #[test] - fn spec_test_f32() { - spec_test::(); - } - - #[test] - fn spec_test_f64() { - spec_test::(); - - let expect_underflow = [ - ( - hf64!("0x1.0p-1070"), - hf64!("0x1.0p-1070"), - hf64!("0x1.ffffffffffffp-1023"), - hf64!("0x0.ffffffffffff8p-1022"), - ), - ( - // FIXME: we raise underflow but this should only be inexact (based on C and - // `rustc_apfloat`). - hf64!("0x1.0p-1070"), - hf64!("0x1.0p-1070"), - hf64!("-0x1.0p-1022"), - hf64!("-0x1.0p-1022"), - ), - ]; - - for (x, y, z, res) in expect_underflow { - let FpResult { val, status } = fma_round(x, y, z, Round::Nearest); - assert_biteq!(val, res); - assert_eq!(status, Status::UNDERFLOW); - } - } - - #[test] - #[cfg(f128_enabled)] - fn spec_test_f128() { - spec_test::(); - } - - #[test] - fn fma_segfault() { - // These two inputs cause fma to segfault on release due to overflow: - assert_eq!( - fma( - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313 - ), - -0.00000000000000022204460492503126, - ); - - let result = fma(-0.992, -0.992, -0.992); - //force rounding to storage format on x87 to prevent superious errors. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let result = force_eval!(result); - assert_eq!(result, -0.007936000000000007,); - } - - #[test] - fn fma_sbb() { - assert_eq!(fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), -3991680619069439e277); - } - - #[test] - fn fma_underflow() { - assert_eq!(fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), 0.0,); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/libm/src/math/fma_wide.rs deleted file mode 100644 index 08b78b02264..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fma_wide.rs +++ /dev/null @@ -1,104 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/fmaf.c. Ported to generic Rust algorithm in 2025, TG. */ - -use super::support::{FpResult, IntTy, Round, Status}; -use super::{CastFrom, CastInto, DFloat, Float, HFloat, MinInt}; - -// Placeholder so we can have `fmaf16` in the `Float` trait. -#[allow(unused)] -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 { - unimplemented!() -} - -/// Floating multiply add (f32) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { - select_implementation! { - name: fmaf, - use_arch: all(target_arch = "aarch64", target_feature = "neon"), - args: x, y, z, - } - - fma_wide_round(x, y, z, Round::Nearest).val -} - -/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, -/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. -#[inline] -pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult -where - F: Float + HFloat, - B: Float + DFloat, - B::Int: CastInto, - i32: CastFrom, -{ - let one = IntTy::::ONE; - - let xy: B = x.widen() * y.widen(); - let mut result: B = xy + z.widen(); - let mut ui: B::Int = result.to_bits(); - let re = result.ex(); - let zb: B = z.widen(); - - let prec_diff = B::SIG_BITS - F::SIG_BITS; - let excess_prec = ui & ((one << prec_diff) - one); - let halfway = one << (prec_diff - 1); - - // Common case: the larger precision is fine if... - // This is not a halfway case - if excess_prec != halfway - // Or the result is NaN - || re == B::EXP_SAT - // Or the result is exact - || (result - xy == zb && result - zb == xy) - // Or the mode is something other than round to nearest - || round != Round::Nearest - { - let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; - let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; - - let mut status = Status::OK; - - if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() { - // This branch is never hit; requires previous operations to set a status - status.set_inexact(false); - - result = xy + z.widen(); - if status.inexact() { - status.set_underflow(true); - } else { - status.set_inexact(true); - } - } - - return FpResult { val: result.narrow(), status }; - } - - let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; - let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy }; - if neg == (err < B::ZERO) { - ui += one; - } else { - ui -= one; - } - - FpResult::ok(B::from_bits(ui).narrow()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn issue_263() { - let a = f32::from_bits(1266679807); - let b = f32::from_bits(1300234242); - let c = f32::from_bits(1115553792); - let expected = f32::from_bits(1501560833); - assert_eq!(fmaf(a, b, c), expected); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/libm/src/math/fmin_fmax.rs deleted file mode 100644 index 2947b783e2f..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fmin_fmax.rs +++ /dev/null @@ -1,167 +0,0 @@ -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminf16(x: f16, y: f16) -> f16 { - super::generic::fmin(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminf(x: f32, y: f32) -> f32 { - super::generic::fmin(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmin(x: f64, y: f64) -> f64 { - super::generic::fmin(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminf128(x: f128, y: f128) -> f128 { - super::generic::fmin(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaxf16(x: f16, y: f16) -> f16 { - super::generic::fmax(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaxf(x: f32, y: f32) -> f32 { - super::generic::fmax(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmax(x: f64, y: f64) -> f64 { - super::generic::fmax(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if -/// the inputs are -0.0 and +0.0, either may be returned). -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaxf128(x: f128, y: f128) -> f128 { - super::generic::fmax(x, y) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::{Float, Hexf}; - - fn fmin_spec_test(f: impl Fn(F, F) -> F) { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), - (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - ]; - - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn fmin_spec_tests_f16() { - fmin_spec_test::(fminf16); - } - - #[test] - fn fmin_spec_tests_f32() { - fmin_spec_test::(fminf); - } - - #[test] - fn fmin_spec_tests_f64() { - fmin_spec_test::(fmin); - } - - #[test] - #[cfg(f128_enabled)] - fn fmin_spec_tests_f128() { - fmin_spec_test::(fminf128); - } - - fn fmax_spec_test(f: impl Fn(F, F) -> F) { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), - (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - ]; - - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn fmax_spec_tests_f16() { - fmax_spec_test::(fmaxf16); - } - - #[test] - fn fmax_spec_tests_f32() { - fmax_spec_test::(fmaxf); - } - - #[test] - fn fmax_spec_tests_f64() { - fmax_spec_test::(fmax); - } - - #[test] - #[cfg(f128_enabled)] - fn fmax_spec_tests_f128() { - fmax_spec_test::(fmaxf128); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum.rs b/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum.rs deleted file mode 100644 index b7999e27392..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum.rs +++ /dev/null @@ -1,163 +0,0 @@ -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimumf16(x: f16, y: f16) -> f16 { - super::generic::fminimum(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimum(x: f64, y: f64) -> f64 { - super::generic::fminimum(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimumf(x: f32, y: f32) -> f32 { - super::generic::fminimum(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimumf128(x: f128, y: f128) -> f128 { - super::generic::fminimum(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximumf16(x: f16, y: f16) -> f16 { - super::generic::fmaximum(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximumf(x: f32, y: f32) -> f32 { - super::generic::fmaximum(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximum(x: f64, y: f64) -> f64 { - super::generic::fmaximum(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -/// -/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximumf128(x: f128, y: f128) -> f128 { - super::generic::fmaximum(x, y) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::{Float, Hexf}; - - fn fminimum_spec_test(f: impl Fn(F, F) -> F) { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), - (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::NAN), - (F::ZERO, F::NAN, F::NAN), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), - (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), - ]; - - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn fminimum_spec_tests_f16() { - fminimum_spec_test::(fminimumf16); - } - - #[test] - fn fminimum_spec_tests_f32() { - fminimum_spec_test::(fminimumf); - } - - #[test] - fn fminimum_spec_tests_f64() { - fminimum_spec_test::(fminimum); - } - - #[test] - #[cfg(f128_enabled)] - fn fminimum_spec_tests_f128() { - fminimum_spec_test::(fminimumf128); - } - - fn fmaximum_spec_test(f: impl Fn(F, F) -> F) { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), - (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::NAN), - (F::ZERO, F::NAN, F::NAN), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::ZERO), - (F::NEG_ZERO, F::ZERO, F::ZERO), - ]; - - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn fmaximum_spec_tests_f16() { - fmaximum_spec_test::(fmaximumf16); - } - - #[test] - fn fmaximum_spec_tests_f32() { - fmaximum_spec_test::(fmaximumf); - } - - #[test] - fn fmaximum_spec_tests_f64() { - fmaximum_spec_test::(fmaximum); - } - - #[test] - #[cfg(f128_enabled)] - fn fmaximum_spec_tests_f128() { - fmaximum_spec_test::(fmaximumf128); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum_num.rs b/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum_num.rs deleted file mode 100644 index 180d21f72b7..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum_num.rs +++ /dev/null @@ -1,163 +0,0 @@ -/// Return the lesser of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimum_numf16(x: f16, y: f16) -> f16 { - super::generic::fminimum_num(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimum_numf(x: f32, y: f32) -> f32 { - super::generic::fminimum_num(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimum_num(x: f64, y: f64) -> f64 { - super::generic::fminimum_num(x, y) -} - -/// Return the lesser of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminimum_numf128(x: f128, y: f128) -> f128 { - super::generic::fminimum_num(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximum_numf16(x: f16, y: f16) -> f16 { - super::generic::fmaximum_num(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximum_numf(x: f32, y: f32) -> f32 { - super::generic::fmaximum_num(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximum_num(x: f64, y: f64) -> f64 { - super::generic::fmaximum_num(x, y) -} - -/// Return the greater of two arguments or, if either argument is NaN, NaN. -/// -/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaximum_numf128(x: f128, y: f128) -> f128 { - super::generic::fmaximum_num(x, y) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::{Float, Hexf}; - - fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), - (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), - (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), - ]; - - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn fminimum_num_spec_tests_f16() { - fminimum_num_spec_test::(fminimum_numf16); - } - - #[test] - fn fminimum_num_spec_tests_f32() { - fminimum_num_spec_test::(fminimum_numf); - } - - #[test] - fn fminimum_num_spec_tests_f64() { - fminimum_num_spec_test::(fminimum_num); - } - - #[test] - #[cfg(f128_enabled)] - fn fminimum_num_spec_tests_f128() { - fminimum_num_spec_test::(fminimum_numf128); - } - - fn fmaximum_num_spec_test(f: impl Fn(F, F) -> F) { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), - (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::ZERO), - (F::NEG_ZERO, F::ZERO, F::ZERO), - ]; - - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn fmaximum_num_spec_tests_f16() { - fmaximum_num_spec_test::(fmaximum_numf16); - } - - #[test] - fn fmaximum_num_spec_tests_f32() { - fmaximum_num_spec_test::(fmaximum_numf); - } - - #[test] - fn fmaximum_num_spec_tests_f64() { - fmaximum_num_spec_test::(fmaximum_num); - } - - #[test] - #[cfg(f128_enabled)] - fn fmaximum_num_spec_tests_f128() { - fmaximum_num_spec_test::(fmaximum_numf128); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/fmod.rs b/library/compiler-builtins/libm/libm/src/math/fmod.rs deleted file mode 100644 index c4752b92578..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fmod.rs +++ /dev/null @@ -1,25 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf16(x: f16, y: f16) -> f16 { - super::generic::fmod(x, y) -} - -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf(x: f32, y: f32) -> f32 { - super::generic::fmod(x, y) -} - -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmod(x: f64, y: f64) -> f64 { - super::generic::fmod(x, y) -} - -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf128(x: f128, y: f128) -> f128 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/libm/src/math/fmodf.rs deleted file mode 100644 index 4e95696e20d..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fmodf.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf(x: f32, y: f32) -> f32 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/libm/src/math/fmodf128.rs b/library/compiler-builtins/libm/libm/src/math/fmodf128.rs deleted file mode 100644 index ff0e0493e26..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fmodf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf128(x: f128, y: f128) -> f128 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/libm/src/math/fmodf16.rs b/library/compiler-builtins/libm/libm/src/math/fmodf16.rs deleted file mode 100644 index 11972a7de4f..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/fmodf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf16(x: f16, y: f16) -> f16 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/libm/src/math/frexp.rs b/library/compiler-builtins/libm/libm/src/math/frexp.rs deleted file mode 100644 index de7a64fdae1..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/frexp.rs +++ /dev/null @@ -1,21 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn frexp(x: f64) -> (f64, i32) { - let mut y = x.to_bits(); - let ee = ((y >> 52) & 0x7ff) as i32; - - if ee == 0 { - if x != 0.0 { - let x1p64 = f64::from_bits(0x43f0000000000000); - let (x, e) = frexp(x * x1p64); - return (x, e - 64); - } - return (x, 0); - } else if ee == 0x7ff { - return (x, 0); - } - - let e = ee - 0x3fe; - y &= 0x800fffffffffffff; - y |= 0x3fe0000000000000; - return (f64::from_bits(y), e); -} diff --git a/library/compiler-builtins/libm/libm/src/math/frexpf.rs b/library/compiler-builtins/libm/libm/src/math/frexpf.rs deleted file mode 100644 index 0ec91c2d350..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/frexpf.rs +++ /dev/null @@ -1,22 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn frexpf(x: f32) -> (f32, i32) { - let mut y = x.to_bits(); - let ee: i32 = ((y >> 23) & 0xff) as i32; - - if ee == 0 { - if x != 0.0 { - let x1p64 = f32::from_bits(0x5f800000); - let (x, e) = frexpf(x * x1p64); - return (x, e - 64); - } else { - return (x, 0); - } - } else if ee == 0xff { - return (x, 0); - } - - let e = ee - 0x7e; - y &= 0x807fffff; - y |= 0x3f000000; - (f32::from_bits(y), e) -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/libm/src/math/generic/ceil.rs deleted file mode 100644 index 5c5bb47638f..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/ceil.rs +++ /dev/null @@ -1,168 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/ceilf.c */ - -//! Generic `ceil` algorithm. -//! -//! Note that this uses the algorithm from musl's `ceilf` rather than `ceil` or `ceill` because -//! performance seems to be better (based on icount) and it does not seem to experience rounding -//! errors on i386. - -use super::super::support::{FpResult, Status}; -use super::super::{Float, Int, IntTy, MinInt}; - -#[inline] -pub fn ceil(x: F) -> F { - ceil_status(x).val -} - -#[inline] -pub fn ceil_status(x: F) -> FpResult { - let zero = IntTy::::ZERO; - - let mut ix = x.to_bits(); - let e = x.exp_unbiased(); - - // If the represented value has no fractional part, no truncation is needed. - if e >= F::SIG_BITS as i32 { - return FpResult::ok(x); - } - - let status; - let res = if e >= 0 { - // |x| >= 1.0 - let m = F::SIG_MASK >> e.unsigned(); - if (ix & m) == zero { - // Portion to be masked is already zero; no adjustment needed. - return FpResult::ok(x); - } - - // Otherwise, raise an inexact exception. - status = Status::INEXACT; - - if x.is_sign_positive() { - ix += m; - } - - ix &= !m; - F::from_bits(ix) - } else { - // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). - if ix & F::SIG_MASK == F::Int::ZERO { - status = Status::OK; - } else { - status = Status::INEXACT; - } - - if x.is_sign_negative() { - // -1.0 < x <= -0.0; rounding up goes toward -0.0. - F::NEG_ZERO - } else if ix << 1 != zero { - // 0.0 < x < 1.0; rounding up goes toward +1.0. - F::ONE - } else { - // +0.0 remains unchanged - x - } - }; - - FpResult::new(res, status) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - /// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil - fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; - - for x in roundtrip { - let FpResult { val, status } = ceil_status(x); - assert_biteq!(val, x, "{}", Hexf(x)); - assert_eq!(status, Status::OK, "{}", Hexf(x)); - } - - for &(x, res, res_stat) in cases { - let FpResult { val, status } = ceil_status(x); - assert_biteq!(val, res, "{}", Hexf(x)); - assert_eq!(status, res_stat, "{}", Hexf(x)); - } - } - - /* Skipping f16 / f128 "sanity_check"s due to rejected literal lexing at MSRV */ - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - let cases = [ - (0.1, 1.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 2.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); - } - - #[test] - fn sanity_check_f32() { - assert_eq!(ceil(1.1f32), 2.0); - assert_eq!(ceil(2.9f32), 3.0); - } - - #[test] - fn spec_tests_f32() { - let cases = [ - (0.1, 1.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 2.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); - } - - #[test] - fn sanity_check_f64() { - assert_eq!(ceil(1.1f64), 2.0); - assert_eq!(ceil(2.9f64), 3.0); - } - - #[test] - fn spec_tests_f64() { - let cases = [ - (0.1, 1.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 2.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - let cases = [ - (0.1, 1.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 2.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/copysign.rs b/library/compiler-builtins/libm/libm/src/math/generic/copysign.rs deleted file mode 100644 index a61af22f04a..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/copysign.rs +++ /dev/null @@ -1,11 +0,0 @@ -use super::super::Float; - -/// Copy the sign of `y` to `x`. -#[inline] -pub fn copysign(x: F, y: F) -> F { - let mut ux = x.to_bits(); - let uy = y.to_bits(); - ux &= !F::SIGN_MASK; - ux |= uy & F::SIGN_MASK; - F::from_bits(ux) -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fabs.rs b/library/compiler-builtins/libm/libm/src/math/generic/fabs.rs deleted file mode 100644 index 0fa0edf9b87..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/fabs.rs +++ /dev/null @@ -1,8 +0,0 @@ -use super::super::Float; - -/// Absolute value. -#[inline] -pub fn fabs(x: F) -> F { - let abs_mask = !F::SIGN_MASK; - F::from_bits(x.to_bits() & abs_mask) -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fdim.rs b/library/compiler-builtins/libm/libm/src/math/generic/fdim.rs deleted file mode 100644 index a63007b191c..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/fdim.rs +++ /dev/null @@ -1,6 +0,0 @@ -use super::super::Float; - -#[inline] -pub fn fdim(x: F, y: F) -> F { - if x <= y { F::ZERO } else { x - y } -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/libm/src/math/generic/floor.rs deleted file mode 100644 index 2438046254f..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/floor.rs +++ /dev/null @@ -1,151 +0,0 @@ -/* SPDX-License-Identifier: MIT - * origin: musl src/math/floor.c */ - -//! Generic `floor` algorithm. -//! -//! Note that this uses the algorithm from musl's `floorf` rather than `floor` or `floorl` because -//! performance seems to be better (based on icount) and it does not seem to experience rounding -//! errors on i386. - -use super::super::support::{FpResult, Status}; -use super::super::{Float, Int, IntTy, MinInt}; - -#[inline] -pub fn floor(x: F) -> F { - floor_status(x).val -} - -#[inline] -pub fn floor_status(x: F) -> FpResult { - let zero = IntTy::::ZERO; - - let mut ix = x.to_bits(); - let e = x.exp_unbiased(); - - // If the represented value has no fractional part, no truncation is needed. - if e >= F::SIG_BITS as i32 { - return FpResult::ok(x); - } - - let status; - let res = if e >= 0 { - // |x| >= 1.0 - let m = F::SIG_MASK >> e.unsigned(); - if ix & m == zero { - // Portion to be masked is already zero; no adjustment needed. - return FpResult::ok(x); - } - - // Otherwise, raise an inexact exception. - status = Status::INEXACT; - - if x.is_sign_negative() { - ix += m; - } - - ix &= !m; - F::from_bits(ix) - } else { - // |x| < 1.0, raise an inexact exception since truncation will happen. - if ix & F::SIG_MASK == F::Int::ZERO { - status = Status::OK; - } else { - status = Status::INEXACT; - } - - if x.is_sign_positive() { - // 0.0 <= x < 1.0; rounding down goes toward +0.0. - F::ZERO - } else if ix << 1 != zero { - // -1.0 < x < 0.0; rounding down goes toward -1.0. - F::NEG_ONE - } else { - // -0.0 remains unchanged - x - } - }; - - FpResult::new(res, status) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - /// Test against https://en.cppreference.com/w/cpp/numeric/math/floor - fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; - - for x in roundtrip { - let FpResult { val, status } = floor_status(x); - assert_biteq!(val, x, "{}", Hexf(x)); - assert_eq!(status, Status::OK, "{}", Hexf(x)); - } - - for &(x, res, res_stat) in cases { - let FpResult { val, status } = floor_status(x); - assert_biteq!(val, res, "{}", Hexf(x)); - assert_eq!(status, res_stat, "{}", Hexf(x)); - } - } - - /* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */ - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - let cases = []; - spec_test::(&cases); - } - - #[test] - fn sanity_check_f32() { - assert_eq!(floor(0.5f32), 0.0); - assert_eq!(floor(1.1f32), 1.0); - assert_eq!(floor(2.9f32), 2.0); - } - - #[test] - fn spec_tests_f32() { - let cases = [ - (0.1, 0.0, Status::INEXACT), - (-0.1, -1.0, Status::INEXACT), - (0.9, 0.0, Status::INEXACT), - (-0.9, -1.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -2.0, Status::INEXACT), - (1.9, 1.0, Status::INEXACT), - (-1.9, -2.0, Status::INEXACT), - ]; - spec_test::(&cases); - } - - #[test] - fn sanity_check_f64() { - assert_eq!(floor(1.1f64), 1.0); - assert_eq!(floor(2.9f64), 2.0); - } - - #[test] - fn spec_tests_f64() { - let cases = [ - (0.1, 0.0, Status::INEXACT), - (-0.1, -1.0, Status::INEXACT), - (0.9, 0.0, Status::INEXACT), - (-0.9, -1.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -2.0, Status::INEXACT), - (1.9, 1.0, Status::INEXACT), - (-1.9, -2.0, Status::INEXACT), - ]; - spec_test::(&cases); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - let cases = []; - spec_test::(&cases); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmax.rs deleted file mode 100644 index bf3f847e89b..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/fmax.rs +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: MIT OR Apache-2.0 */ -//! IEEE 754-2011 `maxNum`. This has been superseded by IEEE 754-2019 `maximumNumber`. -//! -//! Per the spec, returns the canonicalized result of: -//! - `x` if `x > y` -//! - `y` if `y > x` -//! - The other number if one is NaN -//! - Otherwise, either `x` or `y`, canonicalized -//! - -0.0 and +0.0 may be disregarded (unlike newer operations) -//! -//! Excluded from our implementation is sNaN handling. -//! -//! More on the differences: [link]. -//! -//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf - -use super::super::Float; - -#[inline] -pub fn fmax(x: F, y: F) -> F { - let res = if x.is_nan() || x < y { y } else { x }; - // Canonicalize - res * F::ONE -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmaximum.rs deleted file mode 100644 index 387055af29c..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/fmaximum.rs +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: MIT OR Apache-2.0 */ -//! IEEE 754-2019 `maximum`. -//! -//! Per the spec, returns the canonicalized result of: -//! - `x` if `x > y` -//! - `y` if `y > x` -//! - qNaN if either operation is NaN -//! - Logic following +0.0 > -0.0 -//! -//! Excluded from our implementation is sNaN handling. - -use super::super::Float; - -#[inline] -pub fn fmaximum(x: F, y: F) -> F { - let res = if x.is_nan() { - x - } else if y.is_nan() { - y - } else if x > y || (y.to_bits() == F::NEG_ZERO.to_bits() && x.is_sign_positive()) { - x - } else { - y - }; - - // Canonicalize - res * F::ONE -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmaximum_num.rs deleted file mode 100644 index f7efdde80ea..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/fmaximum_num.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: MIT OR Apache-2.0 */ -//! IEEE 754-2019 `maximumNumber`. -//! -//! Per the spec, returns: -//! - `x` if `x > y` -//! - `y` if `y > x` -//! - Non-NaN if one operand is NaN -//! - Logic following +0.0 > -0.0 -//! - Either `x` or `y` if `x == y` and the signs are the same -//! - qNaN if either operand is a NaN -//! -//! Excluded from our implementation is sNaN handling. - -use super::super::Float; - -#[inline] -pub fn fmaximum_num(x: F, y: F) -> F { - let res = - if x.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { - y - } else { - x - }; - - // Canonicalize - res * F::ONE -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmin.rs deleted file mode 100644 index cd3caeee4f2..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/fmin.rs +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: MIT OR Apache-2.0 */ -//! IEEE 754-2008 `minNum`. This has been superseded by IEEE 754-2019 `minimumNumber`. -//! -//! Per the spec, returns the canonicalized result of: -//! - `x` if `x < y` -//! - `y` if `y < x` -//! - The other number if one is NaN -//! - Otherwise, either `x` or `y`, canonicalized -//! - -0.0 and +0.0 may be disregarded (unlike newer operations) -//! -//! Excluded from our implementation is sNaN handling. -//! -//! More on the differences: [link]. -//! -//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf - -use super::super::Float; - -#[inline] -pub fn fmin(x: F, y: F) -> F { - let res = if y.is_nan() || x < y { x } else { y }; - // Canonicalize - res * F::ONE -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/libm/src/math/generic/fminimum.rs deleted file mode 100644 index 4ddb3645506..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/fminimum.rs +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: MIT OR Apache-2.0 */ -//! IEEE 754-2019 `minimum`. -//! -//! Per the spec, returns the canonicalized result of: -//! - `x` if `x < y` -//! - `y` if `y < x` -//! - qNaN if either operation is NaN -//! - Logic following +0.0 > -0.0 -//! -//! Excluded from our implementation is sNaN handling. - -use super::super::Float; - -#[inline] -pub fn fminimum(x: F, y: F) -> F { - let res = if x.is_nan() { - x - } else if y.is_nan() { - y - } else if x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { - x - } else { - y - }; - - // Canonicalize - res * F::ONE -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/libm/src/math/generic/fminimum_num.rs deleted file mode 100644 index 441c204a921..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/fminimum_num.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: MIT OR Apache-2.0 */ -//! IEEE 754-2019 `minimum`. -//! -//! Per the spec, returns: -//! - `x` if `x < y` -//! - `y` if `y < x` -//! - Non-NaN if one operand is NaN -//! - Logic following +0.0 > -0.0 -//! - Either `x` or `y` if `x == y` and the signs are the same -//! - qNaN if either operand is a NaN -//! -//! Excluded from our implementation is sNaN handling. - -use super::super::Float; - -#[inline] -pub fn fminimum_num(x: F, y: F) -> F { - let res = - if y.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { - x - } else { - y - }; - - // Canonicalize - res * F::ONE -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmod.rs deleted file mode 100644 index 6414bbd2508..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/fmod.rs +++ /dev/null @@ -1,84 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/fmod.c. Ported to generic Rust algorithm in 2025, TG. */ - -use super::super::{CastFrom, Float, Int, MinInt}; - -#[inline] -pub fn fmod(x: F, y: F) -> F { - let zero = F::Int::ZERO; - let one = F::Int::ONE; - let mut ix = x.to_bits(); - let mut iy = y.to_bits(); - let mut ex = x.ex().signed(); - let mut ey = y.ex().signed(); - let sx = ix & F::SIGN_MASK; - - if iy << 1 == zero || y.is_nan() || ex == F::EXP_SAT as i32 { - return (x * y) / (x * y); - } - - if ix << 1 <= iy << 1 { - if ix << 1 == iy << 1 { - return F::ZERO * x; - } - return x; - } - - /* normalize x and y */ - if ex == 0 { - let i = ix << (F::EXP_BITS + 1); - ex -= i.leading_zeros() as i32; - ix <<= -ex + 1; - } else { - ix &= F::Int::MAX >> F::EXP_BITS; - ix |= one << F::SIG_BITS; - } - - if ey == 0 { - let i = iy << (F::EXP_BITS + 1); - ey -= i.leading_zeros() as i32; - iy <<= -ey + 1; - } else { - iy &= F::Int::MAX >> F::EXP_BITS; - iy |= one << F::SIG_BITS; - } - - /* x mod y */ - while ex > ey { - let i = ix.wrapping_sub(iy); - if i >> (F::BITS - 1) == zero { - if i == zero { - return F::ZERO * x; - } - ix = i; - } - - ix <<= 1; - ex -= 1; - } - - let i = ix.wrapping_sub(iy); - if i >> (F::BITS - 1) == zero { - if i == zero { - return F::ZERO * x; - } - - ix = i; - } - - let shift = ix.leading_zeros().saturating_sub(F::EXP_BITS); - ix <<= shift; - ex -= shift as i32; - - /* scale result */ - if ex > 0 { - ix -= one << F::SIG_BITS; - ix |= F::Int::cast_from(ex) << F::SIG_BITS; - } else { - ix >>= -ex + 1; - } - - ix |= sx; - - F::from_bits(ix) -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/libm/src/math/generic/mod.rs deleted file mode 100644 index 35846351a6e..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/mod.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Note: generic functions are marked `#[inline]` because, even though generic functions are -// typically inlined, this does not seem to always be the case. - -mod ceil; -mod copysign; -mod fabs; -mod fdim; -mod floor; -mod fmax; -mod fmaximum; -mod fmaximum_num; -mod fmin; -mod fminimum; -mod fminimum_num; -mod fmod; -mod rint; -mod round; -mod scalbn; -mod sqrt; -mod trunc; - -pub use ceil::ceil; -pub use copysign::copysign; -pub use fabs::fabs; -pub use fdim::fdim; -pub use floor::floor; -pub use fmax::fmax; -pub use fmaximum::fmaximum; -pub use fmaximum_num::fmaximum_num; -pub use fmin::fmin; -pub use fminimum::fminimum; -pub use fminimum_num::fminimum_num; -pub use fmod::fmod; -pub use rint::rint_round; -pub use round::round; -pub use scalbn::scalbn; -pub use sqrt::sqrt; -pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/libm/src/math/generic/rint.rs deleted file mode 100644 index 9cdeb1185a8..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/rint.rs +++ /dev/null @@ -1,120 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/rint.c */ - -use super::super::Float; -use super::super::support::{FpResult, Round}; - -/// IEEE 754-2019 `roundToIntegralExact`, which respects rounding mode and raises inexact if -/// applicable. -#[inline] -pub fn rint_round(x: F, _round: Round) -> FpResult { - let toint = F::ONE / F::EPSILON; - let e = x.ex(); - let positive = x.is_sign_positive(); - - // On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise, - // the excess precission from x87 would cause an incorrect final result. - let force = |x| { - if cfg!(x86_no_sse) && (F::BITS == 32 || F::BITS == 64) { force_eval!(x) } else { x } - }; - - let res = if e >= F::EXP_BIAS + F::SIG_BITS { - // No fractional part; exact result can be returned. - x - } else { - // Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode. For - // Rust this is always nearest, but ideally it would take `round` into account. - let y = if positive { - force(force(x) + toint) - toint - } else { - force(force(x) - toint) + toint - }; - - if y == F::ZERO { - // A zero result takes the sign of the input. - if positive { F::ZERO } else { F::NEG_ZERO } - } else { - y - } - }; - - FpResult::ok(res) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::{Hexf, Status}; - - fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; - - for x in roundtrip { - let FpResult { val, status } = rint_round(x, Round::Nearest); - assert_biteq!(val, x, "rint_round({})", Hexf(x)); - assert_eq!(status, Status::OK, "{}", Hexf(x)); - } - - for &(x, res, res_stat) in cases { - let FpResult { val, status } = rint_round(x, Round::Nearest); - assert_biteq!(val, res, "rint_round({})", Hexf(x)); - assert_eq!(status, res_stat, "{}", Hexf(x)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - let cases = []; - spec_test::(&cases); - } - - #[test] - fn spec_tests_f32() { - let cases = [ - (0.1, 0.0, Status::OK), - (-0.1, -0.0, Status::OK), - (0.5, 0.0, Status::OK), - (-0.5, -0.0, Status::OK), - (0.9, 1.0, Status::OK), - (-0.9, -1.0, Status::OK), - (1.1, 1.0, Status::OK), - (-1.1, -1.0, Status::OK), - (1.5, 2.0, Status::OK), - (-1.5, -2.0, Status::OK), - (1.9, 2.0, Status::OK), - (-1.9, -2.0, Status::OK), - (2.8, 3.0, Status::OK), - (-2.8, -3.0, Status::OK), - ]; - spec_test::(&cases); - } - - #[test] - fn spec_tests_f64() { - let cases = [ - (0.1, 0.0, Status::OK), - (-0.1, -0.0, Status::OK), - (0.5, 0.0, Status::OK), - (-0.5, -0.0, Status::OK), - (0.9, 1.0, Status::OK), - (-0.9, -1.0, Status::OK), - (1.1, 1.0, Status::OK), - (-1.1, -1.0, Status::OK), - (1.5, 2.0, Status::OK), - (-1.5, -2.0, Status::OK), - (1.9, 2.0, Status::OK), - (-1.9, -2.0, Status::OK), - (2.8, 3.0, Status::OK), - (-2.8, -3.0, Status::OK), - ]; - spec_test::(&cases); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - let cases = []; - spec_test::(&cases); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/round.rs b/library/compiler-builtins/libm/libm/src/math/generic/round.rs deleted file mode 100644 index 01314ac70c2..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/round.rs +++ /dev/null @@ -1,83 +0,0 @@ -use super::super::{Float, MinInt}; -use super::{copysign, trunc}; - -#[inline] -pub fn round(x: F) -> F { - let f0p5 = F::from_parts(false, F::EXP_BIAS - 1, F::Int::ZERO); // 0.5 - let f0p25 = F::from_parts(false, F::EXP_BIAS - 2, F::Int::ZERO); // 0.25 - - trunc(x + copysign(f0p5 - f0p25 * F::EPSILON, x)) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[cfg(f16_enabled)] - fn zeroes_f16() { - assert_biteq!(round(0.0_f16), 0.0_f16); - assert_biteq!(round(-0.0_f16), -0.0_f16); - } - - #[test] - #[cfg(f16_enabled)] - fn sanity_check_f16() { - assert_eq!(round(-1.0_f16), -1.0); - assert_eq!(round(2.8_f16), 3.0); - assert_eq!(round(-0.5_f16), -1.0); - assert_eq!(round(0.5_f16), 1.0); - assert_eq!(round(-1.5_f16), -2.0); - assert_eq!(round(1.5_f16), 2.0); - } - - #[test] - fn zeroes_f32() { - assert_biteq!(round(0.0_f32), 0.0_f32); - assert_biteq!(round(-0.0_f32), -0.0_f32); - } - - #[test] - fn sanity_check_f32() { - assert_eq!(round(-1.0_f32), -1.0); - assert_eq!(round(2.8_f32), 3.0); - assert_eq!(round(-0.5_f32), -1.0); - assert_eq!(round(0.5_f32), 1.0); - assert_eq!(round(-1.5_f32), -2.0); - assert_eq!(round(1.5_f32), 2.0); - } - - #[test] - fn zeroes_f64() { - assert_biteq!(round(0.0_f64), 0.0_f64); - assert_biteq!(round(-0.0_f64), -0.0_f64); - } - - #[test] - fn sanity_check_f64() { - assert_eq!(round(-1.0_f64), -1.0); - assert_eq!(round(2.8_f64), 3.0); - assert_eq!(round(-0.5_f64), -1.0); - assert_eq!(round(0.5_f64), 1.0); - assert_eq!(round(-1.5_f64), -2.0); - assert_eq!(round(1.5_f64), 2.0); - } - - #[test] - #[cfg(f128_enabled)] - fn zeroes_f128() { - assert_biteq!(round(0.0_f128), 0.0_f128); - assert_biteq!(round(-0.0_f128), -0.0_f128); - } - - #[test] - #[cfg(f128_enabled)] - fn sanity_check_f128() { - assert_eq!(round(-1.0_f128), -1.0); - assert_eq!(round(2.8_f128), 3.0); - assert_eq!(round(-0.5_f128), -1.0); - assert_eq!(round(0.5_f128), 1.0); - assert_eq!(round(-1.5_f128), -2.0); - assert_eq!(round(1.5_f128), 2.0); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/libm/src/math/generic/scalbn.rs deleted file mode 100644 index a45db1b4a02..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/scalbn.rs +++ /dev/null @@ -1,121 +0,0 @@ -use super::super::{CastFrom, CastInto, Float, IntTy, MinInt}; - -/// Scale the exponent. -/// -/// From N3220: -/// -/// > The scalbn and scalbln functions compute `x * b^n`, where `b = FLT_RADIX` if the return type -/// > of the function is a standard floating type, or `b = 10` if the return type of the function -/// > is a decimal floating type. A range error occurs for some finite x, depending on n. -/// > -/// > [...] -/// > -/// > * `scalbn(±0, n)` returns `±0`. -/// > * `scalbn(x, 0)` returns `x`. -/// > * `scalbn(±∞, n)` returns `±∞`. -/// > -/// > If the calculation does not overflow or underflow, the returned value is exact and -/// > independent of the current rounding direction mode. -#[inline] -pub fn scalbn(mut x: F, mut n: i32) -> F -where - u32: CastInto, - F::Int: CastFrom, - F::Int: CastFrom, -{ - let zero = IntTy::::ZERO; - - // Bits including the implicit bit - let sig_total_bits = F::SIG_BITS + 1; - - // Maximum and minimum values when biased - let exp_max = F::EXP_MAX; - let exp_min = F::EXP_MIN; - - // 2 ^ Emax, maximum positive with null significand (0x1p1023 for f64) - let f_exp_max = F::from_parts(false, F::EXP_BIAS << 1, zero); - - // 2 ^ Emin, minimum positive normal with null significand (0x1p-1022 for f64) - let f_exp_min = F::from_parts(false, 1, zero); - - // 2 ^ sig_total_bits, moltiplier to normalize subnormals (0x1p53 for f64) - let f_pow_subnorm = F::from_parts(false, sig_total_bits + F::EXP_BIAS, zero); - - /* - * The goal is to multiply `x` by a scale factor that applies `n`. However, there are cases - * where `2^n` is not representable by `F` but the result should be, e.g. `x = 2^Emin` with - * `n = -EMin + 2` (one out of range of 2^Emax). To get around this, reduce the magnitude of - * the final scale operation by prescaling by the max/min power representable by `F`. - */ - - if n > exp_max { - // Worse case positive `n`: `x` is the minimum subnormal value, the result is `F::MAX`. - // This can be reached by three scaling multiplications (two here and one final). - debug_assert!(-exp_min + F::SIG_BITS as i32 + exp_max <= exp_max * 3); - - x *= f_exp_max; - n -= exp_max; - if n > exp_max { - x *= f_exp_max; - n -= exp_max; - if n > exp_max { - n = exp_max; - } - } - } else if n < exp_min { - // When scaling toward 0, the prescaling is limited to a value that does not allow `x` to - // go subnormal. This avoids double rounding. - if F::BITS > 16 { - // `mul` s.t. `!(x * mul).is_subnormal() ∀ x` - let mul = f_exp_min * f_pow_subnorm; - let add = -exp_min - sig_total_bits as i32; - - // Worse case negative `n`: `x` is the maximum positive value, the result is `F::MIN`. - // This must be reachable by three scaling multiplications (two here and one final). - debug_assert!(-exp_min + F::SIG_BITS as i32 + exp_max <= add * 2 + -exp_min); - - x *= mul; - n += add; - - if n < exp_min { - x *= mul; - n += add; - - if n < exp_min { - n = exp_min; - } - } - } else { - // `f16` is unique compared to other float types in that the difference between the - // minimum exponent and the significand bits (`add = -exp_min - sig_total_bits`) is - // small, only three. The above method depend on decrementing `n` by `add` two times; - // for other float types this works out because `add` is a substantial fraction of - // the exponent range. For `f16`, however, 3 is relatively small compared to the - // exponent range (which is 39), so that requires ~10 prescale rounds rather than two. - // - // Work aroudn this by using a different algorithm that calculates the prescale - // dynamically based on the maximum possible value. This adds more operations per round - // since it needs to construct the scale, but works better in the general case. - let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32); - let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero); - - x *= mul; - n += add; - - if n < exp_min { - let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32); - let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero); - - x *= mul; - n += add; - - if n < exp_min { - n = exp_min; - } - } - } - } - - let scale = F::from_parts(false, (F::EXP_BIAS as i32 + n) as u32, zero); - x * scale -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/libm/src/math/generic/sqrt.rs deleted file mode 100644 index ec9ff22df20..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/sqrt.rs +++ /dev/null @@ -1,537 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/sqrt.c. Ported to generic Rust algorithm in 2025, TG. */ - -//! Generic square root algorithm. -//! -//! This routine operates around `m_u2`, a U.2 (fixed point with two integral bits) mantissa -//! within the range [1, 4). A table lookup provides an initial estimate, then goldschmidt -//! iterations at various widths are used to approach the real values. -//! -//! For the iterations, `r` is a U0 number that approaches `1/sqrt(m_u2)`, and `s` is a U2 number -//! that approaches `sqrt(m_u2)`. Recall that m_u2 ∈ [1, 4). -//! -//! With Newton-Raphson iterations, this would be: -//! -//! - `w = r * r w ~ 1 / m` -//! - `u = 3 - m * w u ~ 3 - m * w = 3 - m / m = 2` -//! - `r = r * u / 2 r ~ r` -//! -//! (Note that the righthand column does not show anything analytically meaningful (i.e. r ~ r), -//! since the value of performing one iteration is in reducing the error representable by `~`). -//! -//! Instead of Newton-Raphson iterations, Goldschmidt iterations are used to calculate -//! `s = m * r`: -//! -//! - `s = m * r s ~ m / sqrt(m)` -//! - `u = 3 - s * r u ~ 3 - (m / sqrt(m)) * (1 / sqrt(m)) = 3 - m / m = 2` -//! - `r = r * u / 2 r ~ r` -//! - `s = s * u / 2 s ~ s` -//! -//! The above is precise because it uses the original value `m`. There is also a faster version -//! that performs fewer steps but does not use `m`: -//! -//! - `u = 3 - s * r u ~ 3 - 1` -//! - `r = r * u / 2 r ~ r` -//! - `s = s * u / 2 s ~ s` -//! -//! Rounding errors accumulate faster with the second version, so it is only used for subsequent -//! iterations within the same width integer. The first version is always used for the first -//! iteration at a new width in order to avoid this accumulation. -//! -//! Goldschmidt has the advantage over Newton-Raphson that `sqrt(x)` and `1/sqrt(x)` are -//! computed at the same time, i.e. there is no need to calculate `1/sqrt(x)` and invert it. - -use super::super::support::{FpResult, IntTy, Round, Status, cold_path}; -use super::super::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; - -#[inline] -pub fn sqrt(x: F) -> F -where - F: Float + SqrtHelper, - F::Int: HInt, - F::Int: From, - F::Int: From, - F::Int: CastInto, - F::Int: CastInto, - u32: CastInto, -{ - sqrt_round(x, Round::Nearest).val -} - -#[inline] -pub fn sqrt_round(x: F, _round: Round) -> FpResult -where - F: Float + SqrtHelper, - F::Int: HInt, - F::Int: From, - F::Int: From, - F::Int: CastInto, - F::Int: CastInto, - u32: CastInto, -{ - let zero = IntTy::::ZERO; - let one = IntTy::::ONE; - - let mut ix = x.to_bits(); - - // Top is the exponent and sign, which may or may not be shifted. If the float fits into a - // `u32`, we can get by without paying shifting costs. - let noshift = F::BITS <= u32::BITS; - let (mut top, special_case) = if noshift { - let exp_lsb = one << F::SIG_BITS; - let special_case = ix.wrapping_sub(exp_lsb) >= F::EXP_MASK - exp_lsb; - (Exp::NoShift(()), special_case) - } else { - let top = u32::cast_from(ix >> F::SIG_BITS); - let special_case = top.wrapping_sub(1) >= F::EXP_SAT - 1; - (Exp::Shifted(top), special_case) - }; - - // Handle NaN, zero, and out of domain (<= 0) - if special_case { - cold_path(); - - // +/-0 - if ix << 1 == zero { - return FpResult::ok(x); - } - - // Positive infinity - if ix == F::EXP_MASK { - return FpResult::ok(x); - } - - // NaN or negative - if ix > F::EXP_MASK { - return FpResult::new(F::NAN, Status::INVALID); - } - - // Normalize subnormals by multiplying by 1.0 << SIG_BITS (e.g. 0x1p52 for doubles). - let scaled = x * F::from_parts(false, F::SIG_BITS + F::EXP_BIAS, zero); - ix = scaled.to_bits(); - match top { - Exp::Shifted(ref mut v) => { - *v = scaled.ex(); - *v = (*v).wrapping_sub(F::SIG_BITS); - } - Exp::NoShift(()) => { - ix = ix.wrapping_sub((F::SIG_BITS << F::SIG_BITS).cast()); - } - } - } - - // Reduce arguments such that `x = 4^e * m`: - // - // - m_u2 ∈ [1, 4), a fixed point U2.BITS number - // - 2^e is the exponent part of the result - let (m_u2, exp) = match top { - Exp::Shifted(top) => { - // We now know `x` is positive, so `top` is just its (biased) exponent - let mut e = top; - // Construct a fixed point representation of the mantissa. - let mut m_u2 = (ix | F::IMPLICIT_BIT) << F::EXP_BITS; - let even = (e & 1) != 0; - if even { - m_u2 >>= 1; - } - e = (e.wrapping_add(F::EXP_SAT >> 1)) >> 1; - (m_u2, Exp::Shifted(e)) - } - Exp::NoShift(()) => { - let even = ix & (one << F::SIG_BITS) != zero; - - // Exponent part of the return value - let mut e_noshift = ix >> 1; - // ey &= (F::EXP_MASK << 2) >> 2; // clear the top exponent bit (result = 1.0) - e_noshift += (F::EXP_MASK ^ (F::SIGN_MASK >> 1)) >> 1; - e_noshift &= F::EXP_MASK; - - let m1 = (ix << F::EXP_BITS) | F::SIGN_MASK; - let m0 = (ix << (F::EXP_BITS - 1)) & !F::SIGN_MASK; - let m_u2 = if even { m0 } else { m1 }; - - (m_u2, Exp::NoShift(e_noshift)) - } - }; - - // Extract the top 6 bits of the significand with the lowest bit of the exponent. - let i = usize::cast_from(ix >> (F::SIG_BITS - 6)) & 0b1111111; - - // Start with an initial guess for `r = 1 / sqrt(m)` from the table, and shift `m` as an - // initial value for `s = sqrt(m)`. See the module documentation for details. - let r1_u0: F::ISet1 = F::ISet1::cast_from(RSQRT_TAB[i]) << (F::ISet1::BITS - 16); - let s1_u2: F::ISet1 = ((m_u2) >> (F::BITS - F::ISet1::BITS)).cast(); - - // Perform iterations, if any, at quarter width (used for `f128`). - let (r1_u0, _s1_u2) = goldschmidt::(r1_u0, s1_u2, F::SET1_ROUNDS, false); - - // Widen values and perform iterations at half width (used for `f64` and `f128`). - let r2_u0: F::ISet2 = F::ISet2::from(r1_u0) << (F::ISet2::BITS - F::ISet1::BITS); - let s2_u2: F::ISet2 = ((m_u2) >> (F::BITS - F::ISet2::BITS)).cast(); - let (r2_u0, _s2_u2) = goldschmidt::(r2_u0, s2_u2, F::SET2_ROUNDS, false); - - // Perform final iterations at full width (used for all float types). - let r_u0: F::Int = F::Int::from(r2_u0) << (F::BITS - F::ISet2::BITS); - let s_u2: F::Int = m_u2; - let (_r_u0, s_u2) = goldschmidt::(r_u0, s_u2, F::FINAL_ROUNDS, true); - - // Shift back to mantissa position. - let mut m = s_u2 >> (F::EXP_BITS - 2); - - // The musl source includes the following comment (with literals replaced): - // - // > s < sqrt(m) < s + 0x1.09p-SIG_BITS - // > compute nearest rounded result: the nearest result to SIG_BITS bits is either s or - // > s+0x1p-SIG_BITS, we can decide by comparing (2^SIG_BITS s + 0.5)^2 to 2^(2*SIG_BITS) m. - // - // Expanding this with , with `SIG_BITS = p` and adjusting based on the operations done to - // `d0` and `d1`: - // - // - `2^(2p)m ≟ ((2^p)m + 0.5)^2` - // - `2^(2p)m ≟ 2^(2p)m^2 + (2^p)m + 0.25` - // - `2^(2p)m - m^2 ≟ (2^(2p) - 1)m^2 + (2^p)m + 0.25` - // - `(1 - 2^(2p))m + m^2 ≟ (1 - 2^(2p))m^2 + (1 - 2^p)m + 0.25` (?) - // - // I do not follow how the rounding bit is extracted from this comparison with the below - // operations. In any case, the algorithm is well tested. - - // The value needed to shift `m_u2` by to create `m*2^(2p)`. `2p = 2 * F::SIG_BITS`, - // `F::BITS - 2` accounts for the offset that `m_u2` already has. - let shift = 2 * F::SIG_BITS - (F::BITS - 2); - - // `2^(2p)m - m^2` - let d0 = (m_u2 << shift).wrapping_sub(m.wrapping_mul(m)); - // `m - 2^(2p)m + m^2` - let d1 = m.wrapping_sub(d0); - m += d1 >> (F::BITS - 1); - m &= F::SIG_MASK; - - match exp { - Exp::Shifted(e) => m |= IntTy::::cast_from(e) << F::SIG_BITS, - Exp::NoShift(e) => m |= e, - }; - - let mut y = F::from_bits(m); - - // FIXME(f16): the fenv math does not work for `f16` - if F::BITS > 16 { - // Handle rounding and inexact. `(m + 1)^2 == 2^shift m` is exact; for all other cases, add - // a tiny value to cause fenv effects. - let d2 = d1.wrapping_add(m).wrapping_add(one); - let mut tiny = if d2 == zero { - cold_path(); - zero - } else { - F::IMPLICIT_BIT - }; - - tiny |= (d1 ^ d2) & F::SIGN_MASK; - let t = F::from_bits(tiny); - y = y + t; - } - - FpResult::ok(y) -} - -/// Multiply at the wider integer size, returning the high half. -fn wmulh(a: I, b: I) -> I { - a.widen_mul(b).hi() -} - -/// Perform `count` goldschmidt iterations, returning `(r_u0, s_u?)`. -/// -/// - `r_u0` is the reciprocal `r ~ 1 / sqrt(m)`, as U0. -/// - `s_u2` is the square root, `s ~ sqrt(m)`, as U2. -/// - `count` is the number of iterations to perform. -/// - `final_set` should be true if this is the last round (same-sized integer). If so, the -/// returned `s` will be U3, for later shifting. Otherwise, the returned `s` is U2. -/// -/// Note that performance relies on the optimizer being able to unroll these loops (reasonably -/// trivial, `count` is a constant when called). -#[inline] -fn goldschmidt(mut r_u0: I, mut s_u2: I, count: u32, final_set: bool) -> (I, I) -where - F: SqrtHelper, - I: HInt + From, -{ - let three_u2 = I::from(0b11u8) << (I::BITS - 2); - let mut u_u0 = r_u0; - - for i in 0..count { - // First iteration: `s = m*r` (`u_u0 = r_u0` set above) - // Subsequent iterations: `s=s*u/2` - s_u2 = wmulh(s_u2, u_u0); - - // Perform `s /= 2` if: - // - // 1. This is not the first iteration (the first iteration is `s = m*r`)... - // 2. ... and this is not the last set of iterations - // 3. ... or, if this is the last set, it is not the last iteration - // - // This step is not performed for the final iteration because the shift is combined with - // a later shift (moving `s` into the mantissa). - if i > 0 && (!final_set || i + 1 < count) { - s_u2 <<= 1; - } - - // u = 3 - s*r - let d_u2 = wmulh(s_u2, r_u0); - u_u0 = three_u2.wrapping_sub(d_u2); - - // r = r*u/2 - r_u0 = wmulh(r_u0, u_u0) << 1; - } - - (r_u0, s_u2) -} - -/// Representation of whether we shift the exponent into a `u32`, or modify it in place to save -/// the shift operations. -enum Exp { - /// The exponent has been shifted to a `u32` and is LSB-aligned. - Shifted(u32), - /// The exponent is in its natural position in integer repr. - NoShift(T), -} - -/// Size-specific constants related to the square root routine. -pub trait SqrtHelper: Float { - /// Integer for the first set of rounds. If unused, set to the same type as the next set. - type ISet1: HInt + Into + CastFrom + From; - /// Integer for the second set of rounds. If unused, set to the same type as the next set. - type ISet2: HInt + From + From; - - /// Number of rounds at `ISet1`. - const SET1_ROUNDS: u32 = 0; - /// Number of rounds at `ISet2`. - const SET2_ROUNDS: u32 = 0; - /// Number of rounds at `Self::Int`. - const FINAL_ROUNDS: u32; -} - -#[cfg(f16_enabled)] -impl SqrtHelper for f16 { - type ISet1 = u16; // unused - type ISet2 = u16; // unused - - const FINAL_ROUNDS: u32 = 2; -} - -impl SqrtHelper for f32 { - type ISet1 = u32; // unused - type ISet2 = u32; // unused - - const FINAL_ROUNDS: u32 = 3; -} - -impl SqrtHelper for f64 { - type ISet1 = u32; // unused - type ISet2 = u32; - - const SET2_ROUNDS: u32 = 2; - const FINAL_ROUNDS: u32 = 2; -} - -#[cfg(f128_enabled)] -impl SqrtHelper for f128 { - type ISet1 = u32; - type ISet2 = u64; - - const SET1_ROUNDS: u32 = 1; - const SET2_ROUNDS: u32 = 2; - const FINAL_ROUNDS: u32 = 2; -} - -/// A U0.16 representation of `1/sqrt(x)`. -/// -/// The index is a 7-bit number consisting of a single exponent bit and 6 bits of significand. -#[rustfmt::skip] -static RSQRT_TAB: [u16; 128] = [ - 0xb451, 0xb2f0, 0xb196, 0xb044, 0xaef9, 0xadb6, 0xac79, 0xab43, - 0xaa14, 0xa8eb, 0xa7c8, 0xa6aa, 0xa592, 0xa480, 0xa373, 0xa26b, - 0xa168, 0xa06a, 0x9f70, 0x9e7b, 0x9d8a, 0x9c9d, 0x9bb5, 0x9ad1, - 0x99f0, 0x9913, 0x983a, 0x9765, 0x9693, 0x95c4, 0x94f8, 0x9430, - 0x936b, 0x92a9, 0x91ea, 0x912e, 0x9075, 0x8fbe, 0x8f0a, 0x8e59, - 0x8daa, 0x8cfe, 0x8c54, 0x8bac, 0x8b07, 0x8a64, 0x89c4, 0x8925, - 0x8889, 0x87ee, 0x8756, 0x86c0, 0x862b, 0x8599, 0x8508, 0x8479, - 0x83ec, 0x8361, 0x82d8, 0x8250, 0x81c9, 0x8145, 0x80c2, 0x8040, - 0xff02, 0xfd0e, 0xfb25, 0xf947, 0xf773, 0xf5aa, 0xf3ea, 0xf234, - 0xf087, 0xeee3, 0xed47, 0xebb3, 0xea27, 0xe8a3, 0xe727, 0xe5b2, - 0xe443, 0xe2dc, 0xe17a, 0xe020, 0xdecb, 0xdd7d, 0xdc34, 0xdaf1, - 0xd9b3, 0xd87b, 0xd748, 0xd61a, 0xd4f1, 0xd3cd, 0xd2ad, 0xd192, - 0xd07b, 0xcf69, 0xce5b, 0xcd51, 0xcc4a, 0xcb48, 0xca4a, 0xc94f, - 0xc858, 0xc764, 0xc674, 0xc587, 0xc49d, 0xc3b7, 0xc2d4, 0xc1f4, - 0xc116, 0xc03c, 0xbf65, 0xbe90, 0xbdbe, 0xbcef, 0xbc23, 0xbb59, - 0xba91, 0xb9cc, 0xb90a, 0xb84a, 0xb78c, 0xb6d0, 0xb617, 0xb560, -]; - -#[cfg(test)] -mod tests { - use super::*; - - /// Test behavior specified in IEEE 754 `squareRoot`. - fn spec_test() - where - F: Float + SqrtHelper, - F::Int: HInt, - F::Int: From, - F::Int: From, - F::Int: CastInto, - F::Int: CastInto, - u32: CastInto, - { - // Values that should return a NaN and raise invalid - let nan = [F::NEG_INFINITY, F::NEG_ONE, F::NAN, F::MIN]; - - // Values that return unaltered - let roundtrip = [F::ZERO, F::NEG_ZERO, F::INFINITY]; - - for x in nan { - let FpResult { val, status } = sqrt_round(x, Round::Nearest); - assert!(val.is_nan()); - assert!(status == Status::INVALID); - } - - for x in roundtrip { - let FpResult { val, status } = sqrt_round(x, Round::Nearest); - assert_biteq!(val, x); - assert!(status == Status::OK); - } - } - - #[test] - #[cfg(f16_enabled)] - fn sanity_check_f16() { - assert_biteq!(sqrt(100.0f16), 10.0); - assert_biteq!(sqrt(4.0f16), 2.0); - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - #[cfg(f16_enabled)] - #[allow(clippy::approx_constant)] - fn conformance_tests_f16() { - let cases = [ - (f16::PI, 0x3f17_u16), - // 10_000.0, using a hex literal for MSRV hack (Rust < 1.67 checks literal widths as - // part of the AST, so the `cfg` is irrelevant here). - (f16::from_bits(0x70e2), 0x5640_u16), - (f16::from_bits(0x0000000f), 0x13bf_u16), - (f16::INFINITY, f16::INFINITY.to_bits()), - ]; - - for (input, output) in cases { - assert_biteq!( - sqrt(input), - f16::from_bits(output), - "input: {input:?} ({:#018x})", - input.to_bits() - ); - } - } - - #[test] - fn sanity_check_f32() { - assert_biteq!(sqrt(100.0f32), 10.0); - assert_biteq!(sqrt(4.0f32), 2.0); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - #[allow(clippy::approx_constant)] - fn conformance_tests_f32() { - let cases = [ - (f32::PI, 0x3fe2dfc5_u32), - (10000.0f32, 0x42c80000_u32), - (f32::from_bits(0x0000000f), 0x1b2f456f_u32), - (f32::INFINITY, f32::INFINITY.to_bits()), - ]; - - for (input, output) in cases { - assert_biteq!( - sqrt(input), - f32::from_bits(output), - "input: {input:?} ({:#018x})", - input.to_bits() - ); - } - } - - #[test] - fn sanity_check_f64() { - assert_biteq!(sqrt(100.0f64), 10.0); - assert_biteq!(sqrt(4.0f64), 2.0); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[allow(clippy::approx_constant)] - fn conformance_tests_f64() { - let cases = [ - (f64::PI, 0x3ffc5bf891b4ef6a_u64), - (10000.0, 0x4059000000000000_u64), - (f64::from_bits(0x0000000f), 0x1e7efbdeb14f4eda_u64), - (f64::INFINITY, f64::INFINITY.to_bits()), - ]; - - for (input, output) in cases { - assert_biteq!( - sqrt(input), - f64::from_bits(output), - "input: {input:?} ({:#018x})", - input.to_bits() - ); - } - } - - #[test] - #[cfg(f128_enabled)] - fn sanity_check_f128() { - assert_biteq!(sqrt(100.0f128), 10.0); - assert_biteq!(sqrt(4.0f128), 2.0); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - #[allow(clippy::approx_constant)] - fn conformance_tests_f128() { - let cases = [ - (f128::PI, 0x3fffc5bf891b4ef6aa79c3b0520d5db9_u128), - // 10_000.0, see `f16` for reasoning. - ( - f128::from_bits(0x400c3880000000000000000000000000), - 0x40059000000000000000000000000000_u128, - ), - (f128::from_bits(0x0000000f), 0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128), - (f128::INFINITY, f128::INFINITY.to_bits()), - ]; - - for (input, output) in cases { - assert_biteq!( - sqrt(input), - f128::from_bits(output), - "input: {input:?} ({:#018x})", - input.to_bits() - ); - } - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/libm/src/math/generic/trunc.rs deleted file mode 100644 index 25414ecf426..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/generic/trunc.rs +++ /dev/null @@ -1,138 +0,0 @@ -/* SPDX-License-Identifier: MIT - * origin: musl src/math/trunc.c */ - -use super::super::support::{FpResult, Status}; -use super::super::{Float, Int, IntTy, MinInt}; - -#[inline] -pub fn trunc(x: F) -> F { - trunc_status(x).val -} - -#[inline] -pub fn trunc_status(x: F) -> FpResult { - let mut xi: F::Int = x.to_bits(); - let e: i32 = x.exp_unbiased(); - - // C1: The represented value has no fractional part, so no truncation is needed - if e >= F::SIG_BITS as i32 { - return FpResult::ok(x); - } - - let mask = if e < 0 { - // C2: If the exponent is negative, the result will be zero so we mask out everything - // except the sign. - F::SIGN_MASK - } else { - // C3: Otherwise, we mask out the last `e` bits of the significand. - !(F::SIG_MASK >> e.unsigned()) - }; - - // C4: If the to-be-masked-out portion is already zero, we have an exact result - if (xi & !mask) == IntTy::::ZERO { - return FpResult::ok(x); - } - - // C5: Otherwise the result is inexact and we will truncate. Raise `FE_INEXACT`, mask the - // result, and return. - - let status = if xi & F::SIG_MASK == F::Int::ZERO { Status::OK } else { Status::INEXACT }; - xi &= mask; - FpResult::new(F::from_bits(xi), status) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; - - for x in roundtrip { - let FpResult { val, status } = trunc_status(x); - assert_biteq!(val, x, "{}", Hexf(x)); - assert_eq!(status, Status::OK, "{}", Hexf(x)); - } - - for &(x, res, res_stat) in cases { - let FpResult { val, status } = trunc_status(x); - assert_biteq!(val, res, "{}", Hexf(x)); - assert_eq!(status, res_stat, "{}", Hexf(x)); - } - } - - /* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */ - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - let cases = []; - spec_test::(&cases); - } - - #[test] - fn sanity_check_f32() { - assert_eq!(trunc(0.5f32), 0.0); - assert_eq!(trunc(1.1f32), 1.0); - assert_eq!(trunc(2.9f32), 2.0); - } - - #[test] - fn spec_tests_f32() { - let cases = [ - (0.1, 0.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 0.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 1.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); - - assert_biteq!(trunc(1.1f32), 1.0); - assert_biteq!(trunc(1.1f64), 1.0); - - // C1 - assert_biteq!(trunc(hf32!("0x1p23")), hf32!("0x1p23")); - assert_biteq!(trunc(hf64!("0x1p52")), hf64!("0x1p52")); - assert_biteq!(trunc(hf32!("-0x1p23")), hf32!("-0x1p23")); - assert_biteq!(trunc(hf64!("-0x1p52")), hf64!("-0x1p52")); - - // C2 - assert_biteq!(trunc(hf32!("0x1p-1")), 0.0); - assert_biteq!(trunc(hf64!("0x1p-1")), 0.0); - assert_biteq!(trunc(hf32!("-0x1p-1")), -0.0); - assert_biteq!(trunc(hf64!("-0x1p-1")), -0.0); - } - - #[test] - fn sanity_check_f64() { - assert_eq!(trunc(1.1f64), 1.0); - assert_eq!(trunc(2.9f64), 2.0); - } - - #[test] - fn spec_tests_f64() { - let cases = [ - (0.1, 0.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.9, 0.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.9, 1.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ]; - spec_test::(&cases); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - let cases = []; - spec_test::(&cases); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/hypot.rs b/library/compiler-builtins/libm/libm/src/math/hypot.rs deleted file mode 100644 index da458ea1d05..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/hypot.rs +++ /dev/null @@ -1,74 +0,0 @@ -use core::f64; - -use super::sqrt; - -const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 - -fn sq(x: f64) -> (f64, f64) { - let xh: f64; - let xl: f64; - let xc: f64; - - xc = x * SPLIT; - xh = x - xc + xc; - xl = x - xh; - let hi = x * x; - let lo = xh * xh - hi + 2. * xh * xl + xl * xl; - (hi, lo) -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn hypot(mut x: f64, mut y: f64) -> f64 { - let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700 - let x1p_700 = f64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700 - - let mut uxi = x.to_bits(); - let mut uyi = y.to_bits(); - let uti; - let ex: i64; - let ey: i64; - let mut z: f64; - - /* arrange |x| >= |y| */ - uxi &= -1i64 as u64 >> 1; - uyi &= -1i64 as u64 >> 1; - if uxi < uyi { - uti = uxi; - uxi = uyi; - uyi = uti; - } - - /* special cases */ - ex = (uxi >> 52) as i64; - ey = (uyi >> 52) as i64; - x = f64::from_bits(uxi); - y = f64::from_bits(uyi); - /* note: hypot(inf,nan) == inf */ - if ey == 0x7ff { - return y; - } - if ex == 0x7ff || uyi == 0 { - return x; - } - /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ - /* 64 difference is enough for ld80 double_t */ - if ex - ey > 64 { - return x + y; - } - - /* precise sqrt argument in nearest rounding mode without overflow */ - /* xh*xh must not overflow and xl*xl must not underflow in sq */ - z = 1.; - if ex > 0x3ff + 510 { - z = x1p700; - x *= x1p_700; - y *= x1p_700; - } else if ey < 0x3ff - 450 { - z = x1p_700; - x *= x1p700; - y *= x1p700; - } - let (hx, lx) = sq(x); - let (hy, ly) = sq(y); - z * sqrt(ly + lx + hy + hx) -} diff --git a/library/compiler-builtins/libm/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/libm/src/math/hypotf.rs deleted file mode 100644 index 576eebb3343..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/hypotf.rs +++ /dev/null @@ -1,43 +0,0 @@ -use core::f32; - -use super::sqrtf; - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn hypotf(mut x: f32, mut y: f32) -> f32 { - let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90 - let x1p_90 = f32::from_bits(0x12800000); // 0x1p-90f === 2 ^ -90 - - let mut uxi = x.to_bits(); - let mut uyi = y.to_bits(); - let uti; - let mut z: f32; - - uxi &= -1i32 as u32 >> 1; - uyi &= -1i32 as u32 >> 1; - if uxi < uyi { - uti = uxi; - uxi = uyi; - uyi = uti; - } - - x = f32::from_bits(uxi); - y = f32::from_bits(uyi); - if uyi == 0xff << 23 { - return y; - } - if uxi >= 0xff << 23 || uyi == 0 || uxi - uyi >= 25 << 23 { - return x + y; - } - - z = 1.; - if uxi >= (0x7f + 60) << 23 { - z = x1p90; - x *= x1p_90; - y *= x1p_90; - } else if uyi < (0x7f - 60) << 23 { - z = x1p_90; - x *= x1p90; - y *= x1p90; - } - z * sqrtf((x as f64 * x as f64 + y as f64 * y as f64) as f32) -} diff --git a/library/compiler-builtins/libm/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/libm/src/math/ilogb.rs deleted file mode 100644 index ccc4914be2b..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/ilogb.rs +++ /dev/null @@ -1,28 +0,0 @@ -const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; -const FP_ILOGB0: i32 = FP_ILOGBNAN; - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ilogb(x: f64) -> i32 { - let mut i: u64 = x.to_bits(); - let e = ((i >> 52) & 0x7ff) as i32; - - if e == 0 { - i <<= 12; - if i == 0 { - force_eval!(0.0 / 0.0); - return FP_ILOGB0; - } - /* subnormal x */ - let mut e = -0x3ff; - while (i >> 63) == 0 { - e -= 1; - i <<= 1; - } - e - } else if e == 0x7ff { - force_eval!(0.0 / 0.0); - if (i << 12) != 0 { FP_ILOGBNAN } else { i32::MAX } - } else { - e - 0x3ff - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/libm/src/math/ilogbf.rs deleted file mode 100644 index 3585d6d36f1..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/ilogbf.rs +++ /dev/null @@ -1,28 +0,0 @@ -const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; -const FP_ILOGB0: i32 = FP_ILOGBNAN; - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ilogbf(x: f32) -> i32 { - let mut i = x.to_bits(); - let e = ((i >> 23) & 0xff) as i32; - - if e == 0 { - i <<= 9; - if i == 0 { - force_eval!(0.0 / 0.0); - return FP_ILOGB0; - } - /* subnormal x */ - let mut e = -0x7f; - while (i >> 31) == 0 { - e -= 1; - i <<= 1; - } - e - } else if e == 0xff { - force_eval!(0.0 / 0.0); - if (i << 9) != 0 { FP_ILOGBNAN } else { i32::MAX } - } else { - e - 0x7f - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/j0.rs b/library/compiler-builtins/libm/libm/src/math/j0.rs deleted file mode 100644 index 99d656f0d08..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/j0.rs +++ /dev/null @@ -1,426 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* j0(x), y0(x) - * Bessel function of the first and second kinds of order zero. - * Method -- j0(x): - * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... - * 2. Reduce x to |x| since j0(x)=j0(-x), and - * for x in (0,2) - * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; - * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) - * for x in (2,inf) - * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) - * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) - * as follow: - * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) - * = 1/sqrt(2) * (cos(x) + sin(x)) - * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) - * = 1/sqrt(2) * (sin(x) - cos(x)) - * (To avoid cancellation, use - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - * to compute the worse one.) - * - * 3 Special cases - * j0(nan)= nan - * j0(0) = 1 - * j0(inf) = 0 - * - * Method -- y0(x): - * 1. For x<2. - * Since - * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) - * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. - * We use the following function to approximate y0, - * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 - * where - * U(z) = u00 + u01*z + ... + u06*z^6 - * V(z) = 1 + v01*z + ... + v04*z^4 - * with absolute approximation error bounded by 2**-72. - * Note: For tiny x, U/V = u0 and j0(x)~1, hence - * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) - * 2. For x>=2. - * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) - * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) - * by the method mentioned above. - * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. - */ - -use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ -const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ - -/* common method when |x|>=2 */ -fn common(ix: u32, x: f64, y0: bool) -> f64 { - let s: f64; - let mut c: f64; - let mut ss: f64; - let mut cc: f64; - let z: f64; - - /* - * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) - * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) - * - * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) - * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - */ - s = sin(x); - c = cos(x); - if y0 { - c = -c; - } - cc = s + c; - /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ - if ix < 0x7fe00000 { - ss = s - c; - z = -cos(2.0 * x); - if s * c < 0.0 { - cc = z / ss; - } else { - ss = z / cc; - } - if ix < 0x48000000 { - if y0 { - ss = -ss; - } - cc = pzero(x) * cc - qzero(x) * ss; - } - } - return INVSQRTPI * cc / sqrt(x); -} - -/* R0/S0 on [0, 2.00] */ -const R02: f64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ -const R03: f64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ -const R04: f64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ -const R05: f64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */ -const S01: f64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ -const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ -const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ -const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ - -/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn j0(mut x: f64) -> f64 { - let z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - - /* j0(+-inf)=0, j0(nan)=nan */ - if ix >= 0x7ff00000 { - return 1.0 / (x * x); - } - x = fabs(x); - - if ix >= 0x40000000 { - /* |x| >= 2 */ - /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ - return common(ix, x, false); - } - - /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ - if ix >= 0x3f200000 { - /* |x| >= 2**-13 */ - /* up to 4ulp error close to 2 */ - z = x * x; - r = z * (R02 + z * (R03 + z * (R04 + z * R05))); - s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); - return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); - } - - /* 1 - x*x/4 */ - /* prevent underflow */ - /* inexact should be raised when x!=0, this is not done correctly */ - if ix >= 0x38000000 { - /* |x| >= 2**-127 */ - x = 0.25 * x * x; - } - return 1.0 - x; -} - -const U00: f64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ -const U01: f64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ -const U02: f64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ -const U03: f64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */ -const U04: f64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */ -const U05: f64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */ -const U06: f64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */ -const V01: f64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ -const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ -const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ -const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ - -/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn y0(x: f64) -> f64 { - let z: f64; - let u: f64; - let v: f64; - let ix: u32; - let lx: u32; - - ix = get_high_word(x); - lx = get_low_word(x); - - /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ - if ((ix << 1) | lx) == 0 { - return -1.0 / 0.0; - } - if (ix >> 31) != 0 { - return 0.0 / 0.0; - } - if ix >= 0x7ff00000 { - return 1.0 / x; - } - - if ix >= 0x40000000 { - /* x >= 2 */ - /* large ulp errors near zeros: 3.958, 7.086,.. */ - return common(ix, x, true); - } - - /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ - if ix >= 0x3e400000 { - /* x >= 2**-27 */ - /* large ulp error near the first zero, x ~= 0.89 */ - z = x * x; - u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); - v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); - return u / v + TPI * (j0(x) * log(x)); - } - return U00 + TPI * log(x); -} - -/* The asymptotic expansions of pzero is - * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. - * For x >= 2, We approximate pzero by - * pzero(x) = 1 + (R/S) - * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 - * S = 1 + pS0*s^2 + ... + pS4*s^10 - * and - * | pzero(x)-1-R/S | <= 2 ** ( -60.26) - */ -const PR8: [f64; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ - -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ - -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ - -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ - -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ -]; -const PS8: [f64; 5] = [ - 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ - 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ - 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ - 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ - 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ -]; - -const PR5: [f64; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ - -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ - -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ - -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ - -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ - -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ -]; -const PS5: [f64; 5] = [ - 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ - 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ - 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ - 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ - 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ -]; - -const PR3: [f64; 6] = [ - /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ - -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ - -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ - -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ - -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ - -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ -]; -const PS3: [f64; 5] = [ - 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ - 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ - 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ - 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ - 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ -]; - -const PR2: [f64; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ - -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ - -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ - -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ - -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ - -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ -]; -const PS2: [f64; 5] = [ - 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ - 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ - 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ - 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ - 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ -]; - -fn pzero(x: f64) -> f64 { - let p: &[f64; 6]; - let q: &[f64; 5]; - let z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 { - p = &PR8; - q = &PS8; - } else if ix >= 0x40122E8B { - p = &PR5; - q = &PS5; - } else if ix >= 0x4006DB6D { - p = &PR3; - q = &PS3; - } else - /*ix >= 0x40000000*/ - { - p = &PR2; - q = &PS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); - return 1.0 + r / s; -} - -/* For x >= 8, the asymptotic expansions of qzero is - * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. - * We approximate pzero by - * qzero(x) = s*(-1.25 + (R/S)) - * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 - * S = 1 + qS0*s^2 + ... + qS5*s^12 - * and - * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) - */ -const QR8: [f64; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ - 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ - 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ - 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ - 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ -]; -const QS8: [f64; 6] = [ - 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ - 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ - 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ - 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ - 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ - -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ -]; - -const QR5: [f64; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ - 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ - 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ - 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ - 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ - 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ -]; -const QS5: [f64; 6] = [ - 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ - 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ - 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ - 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ - 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ - -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ -]; - -const QR3: [f64; 6] = [ - /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ - 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ - 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ - 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ - 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ - 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ -]; -const QS3: [f64; 6] = [ - 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ - 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ - 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ - 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ - 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ - -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ -]; - -const QR2: [f64; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ - 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ - 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ - 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ - 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ - 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ -]; -const QS2: [f64; 6] = [ - 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ - 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ - 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ - 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ - 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ - -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ -]; - -fn qzero(x: f64) -> f64 { - let p: &[f64; 6]; - let q: &[f64; 6]; - let s: f64; - let r: f64; - let z: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 { - p = &QR8; - q = &QS8; - } else if ix >= 0x40122E8B { - p = &QR5; - q = &QS5; - } else if ix >= 0x4006DB6D { - p = &QR3; - q = &QS3; - } else - /*ix >= 0x40000000*/ - { - p = &QR2; - q = &QS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); - return (-0.125 + r / s) / x; -} diff --git a/library/compiler-builtins/libm/libm/src/math/j0f.rs b/library/compiler-builtins/libm/libm/src/math/j0f.rs deleted file mode 100644 index 25e5b325c8c..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/j0f.rs +++ /dev/null @@ -1,363 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{cosf, fabsf, logf, sinf, sqrtf}; - -const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ -const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ - -fn common(ix: u32, x: f32, y0: bool) -> f32 { - let z: f32; - let s: f32; - let mut c: f32; - let mut ss: f32; - let mut cc: f32; - /* - * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) - * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) - */ - s = sinf(x); - c = cosf(x); - if y0 { - c = -c; - } - cc = s + c; - if ix < 0x7f000000 { - ss = s - c; - z = -cosf(2.0 * x); - if s * c < 0.0 { - cc = z / ss; - } else { - ss = z / cc; - } - if ix < 0x58800000 { - if y0 { - ss = -ss; - } - cc = pzerof(x) * cc - qzerof(x) * ss; - } - } - return INVSQRTPI * cc / sqrtf(x); -} - -/* R0/S0 on [0, 2.00] */ -const R02: f32 = 1.5625000000e-02; /* 0x3c800000 */ -const R03: f32 = -1.8997929874e-04; /* 0xb947352e */ -const R04: f32 = 1.8295404516e-06; /* 0x35f58e88 */ -const R05: f32 = -4.6183270541e-09; /* 0xb19eaf3c */ -const S01: f32 = 1.5619102865e-02; /* 0x3c7fe744 */ -const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ -const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ -const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ - -/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn j0f(mut x: f32) -> f32 { - let z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - return 1.0 / (x * x); - } - x = fabsf(x); - - if ix >= 0x40000000 { - /* |x| >= 2 */ - /* large ulp error near zeros */ - return common(ix, x, false); - } - if ix >= 0x3a000000 { - /* |x| >= 2**-11 */ - /* up to 4ulp error near 2 */ - z = x * x; - r = z * (R02 + z * (R03 + z * (R04 + z * R05))); - s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); - return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); - } - if ix >= 0x21800000 { - /* |x| >= 2**-60 */ - x = 0.25 * x * x; - } - return 1.0 - x; -} - -const U00: f32 = -7.3804296553e-02; /* 0xbd9726b5 */ -const U01: f32 = 1.7666645348e-01; /* 0x3e34e80d */ -const U02: f32 = -1.3818567619e-02; /* 0xbc626746 */ -const U03: f32 = 3.4745343146e-04; /* 0x39b62a69 */ -const U04: f32 = -3.8140706238e-06; /* 0xb67ff53c */ -const U05: f32 = 1.9559013964e-08; /* 0x32a802ba */ -const U06: f32 = -3.9820518410e-11; /* 0xae2f21eb */ -const V01: f32 = 1.2730483897e-02; /* 0x3c509385 */ -const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ -const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ -const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ - -/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn y0f(x: f32) -> f32 { - let z: f32; - let u: f32; - let v: f32; - let ix: u32; - - ix = x.to_bits(); - if (ix & 0x7fffffff) == 0 { - return -1.0 / 0.0; - } - if (ix >> 31) != 0 { - return 0.0 / 0.0; - } - if ix >= 0x7f800000 { - return 1.0 / x; - } - if ix >= 0x40000000 { - /* |x| >= 2.0 */ - /* large ulp error near zeros */ - return common(ix, x, true); - } - if ix >= 0x39000000 { - /* x >= 2**-13 */ - /* large ulp error at x ~= 0.89 */ - z = x * x; - u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); - v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); - return u / v + TPI * (j0f(x) * logf(x)); - } - return U00 + TPI * logf(x); -} - -/* The asymptotic expansions of pzero is - * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. - * For x >= 2, We approximate pzero by - * pzero(x) = 1 + (R/S) - * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 - * S = 1 + pS0*s^2 + ... + pS4*s^10 - * and - * | pzero(x)-1-R/S | <= 2 ** ( -60.26) - */ -const PR8: [f32; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - -7.0312500000e-02, /* 0xbd900000 */ - -8.0816707611e+00, /* 0xc1014e86 */ - -2.5706311035e+02, /* 0xc3808814 */ - -2.4852163086e+03, /* 0xc51b5376 */ - -5.2530439453e+03, /* 0xc5a4285a */ -]; -const PS8: [f32; 5] = [ - 1.1653436279e+02, /* 0x42e91198 */ - 3.8337448730e+03, /* 0x456f9beb */ - 4.0597855469e+04, /* 0x471e95db */ - 1.1675296875e+05, /* 0x47e4087c */ - 4.7627726562e+04, /* 0x473a0bba */ -]; -const PR5: [f32; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -1.1412546255e-11, /* 0xad48c58a */ - -7.0312492549e-02, /* 0xbd8fffff */ - -4.1596107483e+00, /* 0xc0851b88 */ - -6.7674766541e+01, /* 0xc287597b */ - -3.3123129272e+02, /* 0xc3a59d9b */ - -3.4643338013e+02, /* 0xc3ad3779 */ -]; -const PS5: [f32; 5] = [ - 6.0753936768e+01, /* 0x42730408 */ - 1.0512523193e+03, /* 0x44836813 */ - 5.9789707031e+03, /* 0x45bad7c4 */ - 9.6254453125e+03, /* 0x461665c8 */ - 2.4060581055e+03, /* 0x451660ee */ -]; - -const PR3: [f32; 6] = [ - /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - -2.5470459075e-09, /* 0xb12f081b */ - -7.0311963558e-02, /* 0xbd8fffb8 */ - -2.4090321064e+00, /* 0xc01a2d95 */ - -2.1965976715e+01, /* 0xc1afba52 */ - -5.8079170227e+01, /* 0xc2685112 */ - -3.1447946548e+01, /* 0xc1fb9565 */ -]; -const PS3: [f32; 5] = [ - 3.5856033325e+01, /* 0x420f6c94 */ - 3.6151397705e+02, /* 0x43b4c1ca */ - 1.1936077881e+03, /* 0x44953373 */ - 1.1279968262e+03, /* 0x448cffe6 */ - 1.7358093262e+02, /* 0x432d94b8 */ -]; - -const PR2: [f32; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -8.8753431271e-08, /* 0xb3be98b7 */ - -7.0303097367e-02, /* 0xbd8ffb12 */ - -1.4507384300e+00, /* 0xbfb9b1cc */ - -7.6356959343e+00, /* 0xc0f4579f */ - -1.1193166733e+01, /* 0xc1331736 */ - -3.2336456776e+00, /* 0xc04ef40d */ -]; -const PS2: [f32; 5] = [ - 2.2220300674e+01, /* 0x41b1c32d */ - 1.3620678711e+02, /* 0x430834f0 */ - 2.7047027588e+02, /* 0x43873c32 */ - 1.5387539673e+02, /* 0x4319e01a */ - 1.4657617569e+01, /* 0x416a859a */ -]; - -fn pzerof(x: f32) -> f32 { - let p: &[f32; 6]; - let q: &[f32; 5]; - let z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 { - p = &PR8; - q = &PS8; - } else if ix >= 0x409173eb { - p = &PR5; - q = &PS5; - } else if ix >= 0x4036d917 { - p = &PR3; - q = &PS3; - } else - /*ix >= 0x40000000*/ - { - p = &PR2; - q = &PS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); - return 1.0 + r / s; -} - -/* For x >= 8, the asymptotic expansions of qzero is - * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. - * We approximate pzero by - * qzero(x) = s*(-1.25 + (R/S)) - * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 - * S = 1 + qS0*s^2 + ... + qS5*s^12 - * and - * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) - */ -const QR8: [f32; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - 7.3242187500e-02, /* 0x3d960000 */ - 1.1768206596e+01, /* 0x413c4a93 */ - 5.5767340088e+02, /* 0x440b6b19 */ - 8.8591972656e+03, /* 0x460a6cca */ - 3.7014625000e+04, /* 0x471096a0 */ -]; -const QS8: [f32; 6] = [ - 1.6377603149e+02, /* 0x4323c6aa */ - 8.0983447266e+03, /* 0x45fd12c2 */ - 1.4253829688e+05, /* 0x480b3293 */ - 8.0330925000e+05, /* 0x49441ed4 */ - 8.4050156250e+05, /* 0x494d3359 */ - -3.4389928125e+05, /* 0xc8a7eb69 */ -]; - -const QR5: [f32; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.8408595828e-11, /* 0x2da1ec79 */ - 7.3242180049e-02, /* 0x3d95ffff */ - 5.8356351852e+00, /* 0x40babd86 */ - 1.3511157227e+02, /* 0x43071c90 */ - 1.0272437744e+03, /* 0x448067cd */ - 1.9899779053e+03, /* 0x44f8bf4b */ -]; -const QS5: [f32; 6] = [ - 8.2776611328e+01, /* 0x42a58da0 */ - 2.0778142090e+03, /* 0x4501dd07 */ - 1.8847289062e+04, /* 0x46933e94 */ - 5.6751113281e+04, /* 0x475daf1d */ - 3.5976753906e+04, /* 0x470c88c1 */ - -5.3543427734e+03, /* 0xc5a752be */ -]; - -const QR3: [f32; 6] = [ - /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - 4.3774099900e-09, /* 0x3196681b */ - 7.3241114616e-02, /* 0x3d95ff70 */ - 3.3442313671e+00, /* 0x405607e3 */ - 4.2621845245e+01, /* 0x422a7cc5 */ - 1.7080809021e+02, /* 0x432acedf */ - 1.6673394775e+02, /* 0x4326bbe4 */ -]; -const QS3: [f32; 6] = [ - 4.8758872986e+01, /* 0x42430916 */ - 7.0968920898e+02, /* 0x44316c1c */ - 3.7041481934e+03, /* 0x4567825f */ - 6.4604252930e+03, /* 0x45c9e367 */ - 2.5163337402e+03, /* 0x451d4557 */ - -1.4924745178e+02, /* 0xc3153f59 */ -]; - -const QR2: [f32; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.5044444979e-07, /* 0x342189db */ - 7.3223426938e-02, /* 0x3d95f62a */ - 1.9981917143e+00, /* 0x3fffc4bf */ - 1.4495602608e+01, /* 0x4167edfd */ - 3.1666231155e+01, /* 0x41fd5471 */ - 1.6252708435e+01, /* 0x4182058c */ -]; -const QS2: [f32; 6] = [ - 3.0365585327e+01, /* 0x41f2ecb8 */ - 2.6934811401e+02, /* 0x4386ac8f */ - 8.4478375244e+02, /* 0x44533229 */ - 8.8293585205e+02, /* 0x445cbbe5 */ - 2.1266638184e+02, /* 0x4354aa98 */ - -5.3109550476e+00, /* 0xc0a9f358 */ -]; - -fn qzerof(x: f32) -> f32 { - let p: &[f32; 6]; - let q: &[f32; 6]; - let s: f32; - let r: f32; - let z: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 { - p = &QR8; - q = &QS8; - } else if ix >= 0x409173eb { - p = &QR5; - q = &QS5; - } else if ix >= 0x4036d917 { - p = &QR3; - q = &QS3; - } else - /*ix >= 0x40000000*/ - { - p = &QR2; - q = &QS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); - return (-0.125 + r / s) / x; -} diff --git a/library/compiler-builtins/libm/libm/src/math/j1.rs b/library/compiler-builtins/libm/libm/src/math/j1.rs deleted file mode 100644 index 9b604d9e46e..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/j1.rs +++ /dev/null @@ -1,418 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* j1(x), y1(x) - * Bessel function of the first and second kinds of order zero. - * Method -- j1(x): - * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... - * 2. Reduce x to |x| since j1(x)=-j1(-x), and - * for x in (0,2) - * j1(x) = x/2 + x*z*R0/S0, where z = x*x; - * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) - * for x in (2,inf) - * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) - * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) - * as follow: - * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) - * = 1/sqrt(2) * (sin(x) - cos(x)) - * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) - * = -1/sqrt(2) * (sin(x) + cos(x)) - * (To avoid cancellation, use - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - * to compute the worse one.) - * - * 3 Special cases - * j1(nan)= nan - * j1(0) = 0 - * j1(inf) = 0 - * - * Method -- y1(x): - * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN - * 2. For x<2. - * Since - * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) - * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. - * We use the following function to approximate y1, - * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 - * where for x in [0,2] (abs err less than 2**-65.89) - * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 - * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 - * Note: For tiny x, 1/x dominate y1 and hence - * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) - * 3. For x>=2. - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) - * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) - * by method mentioned above. - */ - -use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; - -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ -const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ - -fn common(ix: u32, x: f64, y1: bool, sign: bool) -> f64 { - let z: f64; - let mut s: f64; - let c: f64; - let mut ss: f64; - let mut cc: f64; - - /* - * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) - * - * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) - * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - */ - s = sin(x); - if y1 { - s = -s; - } - c = cos(x); - cc = s - c; - if ix < 0x7fe00000 { - /* avoid overflow in 2*x */ - ss = -s - c; - z = cos(2.0 * x); - if s * c > 0.0 { - cc = z / ss; - } else { - ss = z / cc; - } - if ix < 0x48000000 { - if y1 { - ss = -ss; - } - cc = pone(x) * cc - qone(x) * ss; - } - } - if sign { - cc = -cc; - } - return INVSQRTPI * cc / sqrt(x); -} - -/* R0/S0 on [0,2] */ -const R00: f64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ -const R01: f64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ -const R02: f64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ -const R03: f64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ -const S01: f64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ -const S02: f64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ -const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ -const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ -const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ - -/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn j1(x: f64) -> f64 { - let mut z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - let sign: bool; - - ix = get_high_word(x); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - return 1.0 / (x * x); - } - if ix >= 0x40000000 { - /* |x| >= 2 */ - return common(ix, fabs(x), false, sign); - } - if ix >= 0x38000000 { - /* |x| >= 2**-127 */ - z = x * x; - r = z * (R00 + z * (R01 + z * (R02 + z * R03))); - s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); - z = r / s; - } else { - /* avoid underflow, raise inexact if x!=0 */ - z = x; - } - return (0.5 + z) * x; -} - -const U0: [f64; 5] = [ - -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ - 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ - -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ - 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ - -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ -]; -const V0: [f64; 5] = [ - 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ - 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ - 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ - 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ - 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ -]; - -/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn y1(x: f64) -> f64 { - let z: f64; - let u: f64; - let v: f64; - let ix: u32; - let lx: u32; - - ix = get_high_word(x); - lx = get_low_word(x); - - /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ - if (ix << 1) | lx == 0 { - return -1.0 / 0.0; - } - if ix >> 31 != 0 { - return 0.0 / 0.0; - } - if ix >= 0x7ff00000 { - return 1.0 / x; - } - - if ix >= 0x40000000 { - /* x >= 2 */ - return common(ix, x, true, false); - } - if ix < 0x3c900000 { - /* x < 2**-54 */ - return -TPI / x; - } - z = x * x; - u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); - v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); - return x * (u / v) + TPI * (j1(x) * log(x) - 1.0 / x); -} - -/* For x >= 8, the asymptotic expansions of pone is - * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. - * We approximate pone by - * pone(x) = 1 + (R/S) - * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 - * S = 1 + ps0*s^2 + ... + ps4*s^10 - * and - * | pone(x)-1-R/S | <= 2 ** ( -60.06) - */ - -const PR8: [f64; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ - 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ - 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ - 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ - 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ -]; -const PS8: [f64; 5] = [ - 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ - 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ - 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ - 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ - 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ -]; - -const PR5: [f64; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ - 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ - 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ - 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ - 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ - 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ -]; -const PS5: [f64; 5] = [ - 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ - 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ - 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ - 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ - 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ -]; - -const PR3: [f64; 6] = [ - 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ - 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ - 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ - 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ - 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ - 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ -]; -const PS3: [f64; 5] = [ - 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ - 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ - 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ - 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ - 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ -]; - -const PR2: [f64; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ - 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ - 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ - 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ - 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ - 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ -]; -const PS2: [f64; 5] = [ - 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ - 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ - 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ - 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ - 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ -]; - -fn pone(x: f64) -> f64 { - let p: &[f64; 6]; - let q: &[f64; 5]; - let z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 { - p = &PR8; - q = &PS8; - } else if ix >= 0x40122E8B { - p = &PR5; - q = &PS5; - } else if ix >= 0x4006DB6D { - p = &PR3; - q = &PS3; - } else - /*ix >= 0x40000000*/ - { - p = &PR2; - q = &PS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); - return 1.0 + r / s; -} - -/* For x >= 8, the asymptotic expansions of qone is - * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. - * We approximate pone by - * qone(x) = s*(0.375 + (R/S)) - * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 - * S = 1 + qs1*s^2 + ... + qs6*s^12 - * and - * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) - */ - -const QR8: [f64; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ - -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ - -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ - -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ - -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ -]; -const QS8: [f64; 6] = [ - 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ - 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ - 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ - 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ - 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ - -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ -]; - -const QR5: [f64; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ - -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ - -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ - -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ - -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ - -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ -]; -const QS5: [f64; 6] = [ - 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ - 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ - 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ - 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ - 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ - -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ -]; - -const QR3: [f64; 6] = [ - -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ - -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ - -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ - -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ - -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ - -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ -]; -const QS3: [f64; 6] = [ - 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ - 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ - 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ - 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ - 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ - -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ -]; - -const QR2: [f64; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ - -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ - -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ - -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ - -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ - -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ -]; -const QS2: [f64; 6] = [ - 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ - 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ - 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ - 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ - 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ - -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ -]; - -fn qone(x: f64) -> f64 { - let p: &[f64; 6]; - let q: &[f64; 6]; - let s: f64; - let r: f64; - let z: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 { - p = &QR8; - q = &QS8; - } else if ix >= 0x40122E8B { - p = &QR5; - q = &QS5; - } else if ix >= 0x4006DB6D { - p = &QR3; - q = &QS3; - } else - /*ix >= 0x40000000*/ - { - p = &QR2; - q = &QS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); - return (0.375 + r / s) / x; -} diff --git a/library/compiler-builtins/libm/libm/src/math/j1f.rs b/library/compiler-builtins/libm/libm/src/math/j1f.rs deleted file mode 100644 index a47472401ee..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/j1f.rs +++ /dev/null @@ -1,384 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{cosf, fabsf, logf, sinf, sqrtf}; - -const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ -const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ - -fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 { - let z: f64; - let mut s: f64; - let c: f64; - let mut ss: f64; - let mut cc: f64; - - s = sinf(x) as f64; - if y1 { - s = -s; - } - c = cosf(x) as f64; - cc = s - c; - if ix < 0x7f000000 { - ss = -s - c; - z = cosf(2.0 * x) as f64; - if s * c > 0.0 { - cc = z / ss; - } else { - ss = z / cc; - } - if ix < 0x58800000 { - if y1 { - ss = -ss; - } - cc = (ponef(x) as f64) * cc - (qonef(x) as f64) * ss; - } - } - if sign { - cc = -cc; - } - return (((INVSQRTPI as f64) * cc) / (sqrtf(x) as f64)) as f32; -} - -/* R0/S0 on [0,2] */ -const R00: f32 = -6.2500000000e-02; /* 0xbd800000 */ -const R01: f32 = 1.4070566976e-03; /* 0x3ab86cfd */ -const R02: f32 = -1.5995563444e-05; /* 0xb7862e36 */ -const R03: f32 = 4.9672799207e-08; /* 0x335557d2 */ -const S01: f32 = 1.9153760746e-02; /* 0x3c9ce859 */ -const S02: f32 = 1.8594678841e-04; /* 0x3942fab6 */ -const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ -const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ -const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ - -/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn j1f(x: f32) -> f32 { - let mut z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - let sign: bool; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - return 1.0 / (x * x); - } - if ix >= 0x40000000 { - /* |x| >= 2 */ - return common(ix, fabsf(x), false, sign); - } - if ix >= 0x39000000 { - /* |x| >= 2**-13 */ - z = x * x; - r = z * (R00 + z * (R01 + z * (R02 + z * R03))); - s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); - z = 0.5 + r / s; - } else { - z = 0.5; - } - return z * x; -} - -const U0: [f32; 5] = [ - -1.9605709612e-01, /* 0xbe48c331 */ - 5.0443872809e-02, /* 0x3d4e9e3c */ - -1.9125689287e-03, /* 0xbafaaf2a */ - 2.3525259166e-05, /* 0x37c5581c */ - -9.1909917899e-08, /* 0xb3c56003 */ -]; -const V0: [f32; 5] = [ - 1.9916731864e-02, /* 0x3ca3286a */ - 2.0255257550e-04, /* 0x3954644b */ - 1.3560879779e-06, /* 0x35b602d4 */ - 6.2274145840e-09, /* 0x31d5f8eb */ - 1.6655924903e-11, /* 0x2d9281cf */ -]; - -/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn y1f(x: f32) -> f32 { - let z: f32; - let u: f32; - let v: f32; - let ix: u32; - - ix = x.to_bits(); - if (ix & 0x7fffffff) == 0 { - return -1.0 / 0.0; - } - if (ix >> 31) != 0 { - return 0.0 / 0.0; - } - if ix >= 0x7f800000 { - return 1.0 / x; - } - if ix >= 0x40000000 { - /* |x| >= 2.0 */ - return common(ix, x, true, false); - } - if ix < 0x33000000 { - /* x < 2**-25 */ - return -TPI / x; - } - z = x * x; - u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); - v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); - return x * (u / v) + TPI * (j1f(x) * logf(x) - 1.0 / x); -} - -/* For x >= 8, the asymptotic expansions of pone is - * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. - * We approximate pone by - * pone(x) = 1 + (R/S) - * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 - * S = 1 + ps0*s^2 + ... + ps4*s^10 - * and - * | pone(x)-1-R/S | <= 2 ** ( -60.06) - */ - -const PR8: [f32; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - 1.1718750000e-01, /* 0x3df00000 */ - 1.3239480972e+01, /* 0x4153d4ea */ - 4.1205184937e+02, /* 0x43ce06a3 */ - 3.8747453613e+03, /* 0x45722bed */ - 7.9144794922e+03, /* 0x45f753d6 */ -]; -const PS8: [f32; 5] = [ - 1.1420736694e+02, /* 0x42e46a2c */ - 3.6509309082e+03, /* 0x45642ee5 */ - 3.6956207031e+04, /* 0x47105c35 */ - 9.7602796875e+04, /* 0x47bea166 */ - 3.0804271484e+04, /* 0x46f0a88b */ -]; - -const PR5: [f32; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.3199052094e-11, /* 0x2d68333f */ - 1.1718749255e-01, /* 0x3defffff */ - 6.8027510643e+00, /* 0x40d9b023 */ - 1.0830818176e+02, /* 0x42d89dca */ - 5.1763616943e+02, /* 0x440168b7 */ - 5.2871520996e+02, /* 0x44042dc6 */ -]; -const PS5: [f32; 5] = [ - 5.9280597687e+01, /* 0x426d1f55 */ - 9.9140142822e+02, /* 0x4477d9b1 */ - 5.3532670898e+03, /* 0x45a74a23 */ - 7.8446904297e+03, /* 0x45f52586 */ - 1.5040468750e+03, /* 0x44bc0180 */ -]; - -const PR3: [f32; 6] = [ - 3.0250391081e-09, /* 0x314fe10d */ - 1.1718686670e-01, /* 0x3defffab */ - 3.9329774380e+00, /* 0x407bb5e7 */ - 3.5119403839e+01, /* 0x420c7a45 */ - 9.1055007935e+01, /* 0x42b61c2a */ - 4.8559066772e+01, /* 0x42423c7c */ -]; -const PS3: [f32; 5] = [ - 3.4791309357e+01, /* 0x420b2a4d */ - 3.3676245117e+02, /* 0x43a86198 */ - 1.0468714600e+03, /* 0x4482dbe3 */ - 8.9081134033e+02, /* 0x445eb3ed */ - 1.0378793335e+02, /* 0x42cf936c */ -]; - -const PR2: [f32; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.0771083225e-07, /* 0x33e74ea8 */ - 1.1717621982e-01, /* 0x3deffa16 */ - 2.3685150146e+00, /* 0x401795c0 */ - 1.2242610931e+01, /* 0x4143e1bc */ - 1.7693971634e+01, /* 0x418d8d41 */ - 5.0735230446e+00, /* 0x40a25a4d */ -]; -const PS2: [f32; 5] = [ - 2.1436485291e+01, /* 0x41ab7dec */ - 1.2529022980e+02, /* 0x42fa9499 */ - 2.3227647400e+02, /* 0x436846c7 */ - 1.1767937469e+02, /* 0x42eb5bd7 */ - 8.3646392822e+00, /* 0x4105d590 */ -]; - -fn ponef(x: f32) -> f32 { - let p: &[f32; 6]; - let q: &[f32; 5]; - let z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 { - p = &PR8; - q = &PS8; - } else if ix >= 0x409173eb { - p = &PR5; - q = &PS5; - } else if ix >= 0x4036d917 { - p = &PR3; - q = &PS3; - } else - /*ix >= 0x40000000*/ - { - p = &PR2; - q = &PS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); - return 1.0 + r / s; -} - -/* For x >= 8, the asymptotic expansions of qone is - * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. - * We approximate pone by - * qone(x) = s*(0.375 + (R/S)) - * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 - * S = 1 + qs1*s^2 + ... + qs6*s^12 - * and - * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) - */ - -const QR8: [f32; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - -1.0253906250e-01, /* 0xbdd20000 */ - -1.6271753311e+01, /* 0xc1822c8d */ - -7.5960174561e+02, /* 0xc43de683 */ - -1.1849806641e+04, /* 0xc639273a */ - -4.8438511719e+04, /* 0xc73d3683 */ -]; -const QS8: [f32; 6] = [ - 1.6139537048e+02, /* 0x43216537 */ - 7.8253862305e+03, /* 0x45f48b17 */ - 1.3387534375e+05, /* 0x4802bcd6 */ - 7.1965775000e+05, /* 0x492fb29c */ - 6.6660125000e+05, /* 0x4922be94 */ - -2.9449025000e+05, /* 0xc88fcb48 */ -]; - -const QR5: [f32; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -2.0897993405e-11, /* 0xadb7d219 */ - -1.0253904760e-01, /* 0xbdd1fffe */ - -8.0564479828e+00, /* 0xc100e736 */ - -1.8366960144e+02, /* 0xc337ab6b */ - -1.3731937256e+03, /* 0xc4aba633 */ - -2.6124443359e+03, /* 0xc523471c */ -]; -const QS5: [f32; 6] = [ - 8.1276550293e+01, /* 0x42a28d98 */ - 1.9917987061e+03, /* 0x44f8f98f */ - 1.7468484375e+04, /* 0x468878f8 */ - 4.9851425781e+04, /* 0x4742bb6d */ - 2.7948074219e+04, /* 0x46da5826 */ - -4.7191835938e+03, /* 0xc5937978 */ -]; - -const QR3: [f32; 6] = [ - -5.0783124372e-09, /* 0xb1ae7d4f */ - -1.0253783315e-01, /* 0xbdd1ff5b */ - -4.6101160049e+00, /* 0xc0938612 */ - -5.7847221375e+01, /* 0xc267638e */ - -2.2824453735e+02, /* 0xc3643e9a */ - -2.1921012878e+02, /* 0xc35b35cb */ -]; -const QS3: [f32; 6] = [ - 4.7665153503e+01, /* 0x423ea91e */ - 6.7386511230e+02, /* 0x4428775e */ - 3.3801528320e+03, /* 0x45534272 */ - 5.5477290039e+03, /* 0x45ad5dd5 */ - 1.9031191406e+03, /* 0x44ede3d0 */ - -1.3520118713e+02, /* 0xc3073381 */ -]; - -const QR2: [f32; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -1.7838172539e-07, /* 0xb43f8932 */ - -1.0251704603e-01, /* 0xbdd1f475 */ - -2.7522056103e+00, /* 0xc0302423 */ - -1.9663616180e+01, /* 0xc19d4f16 */ - -4.2325313568e+01, /* 0xc2294d1f */ - -2.1371921539e+01, /* 0xc1aaf9b2 */ -]; -const QS2: [f32; 6] = [ - 2.9533363342e+01, /* 0x41ec4454 */ - 2.5298155212e+02, /* 0x437cfb47 */ - 7.5750280762e+02, /* 0x443d602e */ - 7.3939318848e+02, /* 0x4438d92a */ - 1.5594900513e+02, /* 0x431bf2f2 */ - -4.9594988823e+00, /* 0xc09eb437 */ -]; - -fn qonef(x: f32) -> f32 { - let p: &[f32; 6]; - let q: &[f32; 6]; - let s: f32; - let r: f32; - let z: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 { - p = &QR8; - q = &QS8; - } else if ix >= 0x409173eb { - p = &QR5; - q = &QS5; - } else if ix >= 0x4036d917 { - p = &QR3; - q = &QS3; - } else - /*ix >= 0x40000000*/ - { - p = &QR2; - q = &QS2; - } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); - return (0.375 + r / s) / x; -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::{j1f, y1f}; - #[test] - fn test_j1f_2488() { - // 0x401F3E49 - assert_eq!(j1f(2.4881766_f32), 0.49999475_f32); - } - #[test] - fn test_y1f_2002() { - //allow slightly different result on x87 - let res = y1f(2.0000002_f32); - if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && (res == -0.10703231_f32) - { - return; - } - assert_eq!(res, -0.10703229_f32); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/jn.rs b/library/compiler-builtins/libm/libm/src/math/jn.rs deleted file mode 100644 index 31f8d9c5382..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/jn.rs +++ /dev/null @@ -1,339 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* - * jn(n, x), yn(n, x) - * floating point Bessel's function of the 1st and 2nd kind - * of order n - * - * Special cases: - * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; - * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. - * Note 2. About jn(n,x), yn(n,x) - * For n=0, j0(x) is called, - * for n=1, j1(x) is called, - * for n<=x, forward recursion is used starting - * from values of j0(x) and j1(x). - * for n>x, a continued fraction approximation to - * j(n,x)/j(n-1,x) is evaluated and then backward - * recursion is used starting from a supposed value - * for j(n,x). The resulting value of j(0,x) is - * compared with the actual value to correct the - * supposed value of j(n,x). - * - * yn(n,x) is similar in all respects, except - * that forward recursion is used for all - * values of n>1. - */ - -use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, y1}; - -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ - -/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn jn(n: i32, mut x: f64) -> f64 { - let mut ix: u32; - let lx: u32; - let nm1: i32; - let mut i: i32; - let mut sign: bool; - let mut a: f64; - let mut b: f64; - let mut temp: f64; - - ix = get_high_word(x); - lx = get_low_word(x); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - // -lx == !lx + 1 - if ix | ((lx | (!lx).wrapping_add(1)) >> 31) > 0x7ff00000 { - /* nan */ - return x; - } - - /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) - * Thus, J(-n,x) = J(n,-x) - */ - /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ - if n == 0 { - return j0(x); - } - if n < 0 { - nm1 = -(n + 1); - x = -x; - sign = !sign; - } else { - nm1 = n - 1; - } - if nm1 == 0 { - return j1(x); - } - - sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ - x = fabs(x); - if (ix | lx) == 0 || ix == 0x7ff00000 { - /* if x is 0 or inf */ - b = 0.0; - } else if (nm1 as f64) < x { - /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ - if ix >= 0x52d00000 { - /* x > 2**302 */ - /* (x >> n**2) - * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Let s=sin(x), c=cos(x), - * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then - * - * n sin(xn)*sqt2 cos(xn)*sqt2 - * ---------------------------------- - * 0 s-c c+s - * 1 -s-c -c+s - * 2 -s+c -c-s - * 3 s+c c-s - */ - temp = match nm1 & 3 { - 0 => -cos(x) + sin(x), - 1 => -cos(x) - sin(x), - 2 => cos(x) - sin(x), - // 3 - _ => cos(x) + sin(x), - }; - b = INVSQRTPI * temp / sqrt(x); - } else { - a = j0(x); - b = j1(x); - i = 0; - while i < nm1 { - i += 1; - temp = b; - b = b * (2.0 * (i as f64) / x) - a; /* avoid underflow */ - a = temp; - } - } - } else if ix < 0x3e100000 { - /* x < 2**-29 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 32 { - /* underflow */ - b = 0.0; - } else { - temp = x * 0.5; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as f64; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } - } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: f64; - let mut q0: f64; - let mut q1: f64; - let mut w: f64; - let h: f64; - let mut z: f64; - let mut tmp: f64; - let nf: f64; - - let mut k: i32; - - nf = (nm1 as f64) + 1.0; - w = 2.0 * nf / x; - h = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e9 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as f64) + nf) / x - t); - i -= 1; - } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf * log(fabs(w)); - if tmp < 7.09782712893383973096e+02 { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as f64)) / x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as f64)) / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 - if b > x1p500 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; - } - } - z = j0(x); - w = j1(x); - if fabs(z) >= fabs(w) { - b = t * z / b; - } else { - b = t * w / a; - } - } - - if sign { -b } else { b } -} - -/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn yn(n: i32, x: f64) -> f64 { - let mut ix: u32; - let lx: u32; - let mut ib: u32; - let nm1: i32; - let mut sign: bool; - let mut i: i32; - let mut a: f64; - let mut b: f64; - let mut temp: f64; - - ix = get_high_word(x); - lx = get_low_word(x); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - // -lx == !lx + 1 - if ix | ((lx | (!lx).wrapping_add(1)) >> 31) > 0x7ff00000 { - /* nan */ - return x; - } - if sign && (ix | lx) != 0 { - /* x < 0 */ - return 0.0 / 0.0; - } - if ix == 0x7ff00000 { - return 0.0; - } - - if n == 0 { - return y0(x); - } - if n < 0 { - nm1 = -(n + 1); - sign = (n & 1) != 0; - } else { - nm1 = n - 1; - sign = false; - } - if nm1 == 0 { - if sign { - return -y1(x); - } else { - return y1(x); - } - } - - if ix >= 0x52d00000 { - /* x > 2**302 */ - /* (x >> n**2) - * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Let s=sin(x), c=cos(x), - * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then - * - * n sin(xn)*sqt2 cos(xn)*sqt2 - * ---------------------------------- - * 0 s-c c+s - * 1 -s-c -c+s - * 2 -s+c -c-s - * 3 s+c c-s - */ - temp = match nm1 & 3 { - 0 => -sin(x) - cos(x), - 1 => -sin(x) + cos(x), - 2 => sin(x) + cos(x), - // 3 - _ => sin(x) - cos(x), - }; - b = INVSQRTPI * temp / sqrt(x); - } else { - a = y0(x); - b = y1(x); - /* quit if b is -inf */ - ib = get_high_word(b); - i = 0; - while i < nm1 && ib != 0xfff00000 { - i += 1; - temp = b; - b = (2.0 * (i as f64) / x) * b - a; - ib = get_high_word(b); - a = temp; - } - } - - if sign { -b } else { b } -} diff --git a/library/compiler-builtins/libm/libm/src/math/jnf.rs b/library/compiler-builtins/libm/libm/src/math/jnf.rs deleted file mode 100644 index 52cf7d8a8bd..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/jnf.rs +++ /dev/null @@ -1,253 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{fabsf, j0f, j1f, logf, y0f, y1f}; - -/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn jnf(n: i32, mut x: f32) -> f32 { - let mut ix: u32; - let mut nm1: i32; - let mut sign: bool; - let mut i: i32; - let mut a: f32; - let mut b: f32; - let mut temp: f32; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - if ix > 0x7f800000 { - /* nan */ - return x; - } - - /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ - if n == 0 { - return j0f(x); - } - if n < 0 { - nm1 = -(n + 1); - x = -x; - sign = !sign; - } else { - nm1 = n - 1; - } - if nm1 == 0 { - return j1f(x); - } - - sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ - x = fabsf(x); - if ix == 0 || ix == 0x7f800000 { - /* if x is 0 or inf */ - b = 0.0; - } else if (nm1 as f32) < x { - /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ - a = j0f(x); - b = j1f(x); - i = 0; - while i < nm1 { - i += 1; - temp = b; - b = b * (2.0 * (i as f32) / x) - a; - a = temp; - } - } else if ix < 0x35800000 { - /* x < 2**-20 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 8 { - /* underflow */ - nm1 = 8; - } - temp = 0.5 * x; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as f32; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: f32; - let mut q0: f32; - let mut q1: f32; - let mut w: f32; - let h: f32; - let mut z: f32; - let mut tmp: f32; - let nf: f32; - let mut k: i32; - - nf = (nm1 as f32) + 1.0; - w = 2.0 * nf / x; - h = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e4 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as f32) + nf) / x - t); - i -= 1; - } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf * logf(fabsf(w)); - if tmp < 88.721679688 { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as f32) * b / x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as f32) * b / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 - if b > x1p60 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; - } - } - z = j0f(x); - w = j1f(x); - if fabsf(z) >= fabsf(w) { - b = t * z / b; - } else { - b = t * w / a; - } - } - - if sign { -b } else { b } -} - -/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ynf(n: i32, x: f32) -> f32 { - let mut ix: u32; - let mut ib: u32; - let nm1: i32; - let mut sign: bool; - let mut i: i32; - let mut a: f32; - let mut b: f32; - let mut temp: f32; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - if ix > 0x7f800000 { - /* nan */ - return x; - } - if sign && ix != 0 { - /* x < 0 */ - return 0.0 / 0.0; - } - if ix == 0x7f800000 { - return 0.0; - } - - if n == 0 { - return y0f(x); - } - if n < 0 { - nm1 = -(n + 1); - sign = (n & 1) != 0; - } else { - nm1 = n - 1; - sign = false; - } - if nm1 == 0 { - if sign { - return -y1f(x); - } else { - return y1f(x); - } - } - - a = y0f(x); - b = y1f(x); - /* quit if b is -inf */ - ib = b.to_bits(); - i = 0; - while i < nm1 && ib != 0xff800000 { - i += 1; - temp = b; - b = (2.0 * (i as f32) / x) * b - a; - ib = b.to_bits(); - a = temp; - } - - if sign { -b } else { b } -} diff --git a/library/compiler-builtins/libm/libm/src/math/k_cos.rs b/library/compiler-builtins/libm/libm/src/math/k_cos.rs deleted file mode 100644 index 49b2fc64d86..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/k_cos.rs +++ /dev/null @@ -1,62 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/k_cos.c -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunSoft, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -const C1: f64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ -const C2: f64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ -const C3: f64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ -const C4: f64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ -const C5: f64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ -const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ - -// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 -// Input x is assumed to be bounded by ~pi/4 in magnitude. -// Input y is the tail of x. -// -// Algorithm -// 1. Since cos(-x) = cos(x), we need only to consider positive x. -// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. -// 3. cos(x) is approximated by a polynomial of degree 14 on -// [0,pi/4] -// 4 14 -// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x -// where the remez error is -// -// | 2 4 6 8 10 12 14 | -58 -// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 -// | | -// -// 4 6 8 10 12 14 -// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then -// cos(x) ~ 1 - x*x/2 + r -// since cos(x+y) ~ cos(x) - sin(x)*y -// ~ cos(x) - x*y, -// a correction term is necessary in cos(x) and hence -// cos(x+y) = 1 - (x*x/2 - (r - x*y)) -// For better accuracy, rearrange to -// cos(x+y) ~ w + (tmp + (r-x*y)) -// where w = 1 - x*x/2 and tmp is a tiny correction term -// (1 - x*x/2 == w + tmp exactly in infinite precision). -// The exactness of w + tmp in infinite precision depends on w -// and tmp having the same precision as x. If they have extra -// precision due to compiler bugs, then the extra precision is -// only good provided it is retained in all terms of the final -// expression for cos(). Retention happens in all cases tested -// under FreeBSD, so don't pessimize things by forcibly clipping -// any extra precision in w. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_cos(x: f64, y: f64) -> f64 { - let z = x * x; - let w = z * z; - let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); - let hz = 0.5 * z; - let w = 1.0 - hz; - w + (((1.0 - w) - hz) + (z * r - x * y)) -} diff --git a/library/compiler-builtins/libm/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/libm/src/math/k_cosf.rs deleted file mode 100644 index e99f2348c00..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/k_cosf.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Debugged and optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ -const C0: f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ -const C1: f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ -const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ -const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_cosf(x: f64) -> f32 { - let z = x * x; - let w = z * z; - let r = C2 + z * C3; - (((1.0 + z * C0) + w * C1) + (w * z) * r) as f32 -} diff --git a/library/compiler-builtins/libm/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/libm/src/math/k_expo2.rs deleted file mode 100644 index 7345075f376..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/k_expo2.rs +++ /dev/null @@ -1,14 +0,0 @@ -use super::exp; - -/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ -const K: i32 = 2043; - -/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_expo2(x: f64) -> f64 { - let k_ln2 = f64::from_bits(0x40962066151add8b); - /* note that k is odd and scale*scale overflows */ - let scale = f64::from_bits(((((0x3ff + K / 2) as u32) << 20) as u64) << 32); - /* exp(x - k ln2) * 2**(k-1) */ - exp(x - k_ln2) * scale * scale -} diff --git a/library/compiler-builtins/libm/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/libm/src/math/k_expo2f.rs deleted file mode 100644 index fbd7b27d583..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/k_expo2f.rs +++ /dev/null @@ -1,14 +0,0 @@ -use super::expf; - -/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ -const K: i32 = 235; - -/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_expo2f(x: f32) -> f32 { - let k_ln2 = f32::from_bits(0x4322e3bc); - /* note that k is odd and scale*scale overflows */ - let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); - /* exp(x - k ln2) * 2**(k-1) */ - expf(x - k_ln2) * scale * scale -} diff --git a/library/compiler-builtins/libm/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/libm/src/math/k_sin.rs deleted file mode 100644 index 42441455ff3..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/k_sin.rs +++ /dev/null @@ -1,53 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/k_sin.c -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunSoft, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -const S1: f64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ -const S2: f64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ -const S3: f64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ -const S4: f64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ -const S5: f64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ -const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ - -// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 -// Input x is assumed to be bounded by ~pi/4 in magnitude. -// Input y is the tail of x. -// Input iy indicates whether y is 0. (if iy=0, y assume to be 0). -// -// Algorithm -// 1. Since sin(-x) = -sin(x), we need only to consider positive x. -// 2. Callers must return sin(-0) = -0 without calling here since our -// odd polynomial is not evaluated in a way that preserves -0. -// Callers may do the optimization sin(x) ~ x for tiny x. -// 3. sin(x) is approximated by a polynomial of degree 13 on -// [0,pi/4] -// 3 13 -// sin(x) ~ x + S1*x + ... + S6*x -// where -// -// |sin(x) 2 4 6 8 10 12 | -58 -// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 -// | x | -// -// 4. sin(x+y) = sin(x) + sin'(x')*y -// ~ sin(x) + (1-x*x/2)*y -// For better accuracy, let -// 3 2 2 2 2 -// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) -// then 3 2 -// sin(x) = x + (S1*x + (x *(r-y/2)+y)) -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { - let z = x * x; - let w = z * z; - let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); - let v = z * x; - if iy == 0 { x + v * (S1 + z * r) } else { x - ((z * (0.5 * y - v * r) - y) - v * S1) } -} diff --git a/library/compiler-builtins/libm/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/libm/src/math/k_sinf.rs deleted file mode 100644 index 88d10cababc..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/k_sinf.rs +++ /dev/null @@ -1,30 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ -const S1: f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ -const S2: f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ -const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ -const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_sinf(x: f64) -> f32 { - let z = x * x; - let w = z * z; - let r = S3 + z * S4; - let s = z * x; - ((x + s * (S1 + z * S2)) + s * w * r) as f32 -} diff --git a/library/compiler-builtins/libm/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/libm/src/math/k_tan.rs deleted file mode 100644 index d177010bb0a..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/k_tan.rs +++ /dev/null @@ -1,105 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ -// -// ==================================================== -// Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. -// -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -// kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 -// Input x is assumed to be bounded by ~pi/4 in magnitude. -// Input y is the tail of x. -// Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. -// -// Algorithm -// 1. Since tan(-x) = -tan(x), we need only to consider positive x. -// 2. Callers must return tan(-0) = -0 without calling here since our -// odd polynomial is not evaluated in a way that preserves -0. -// Callers may do the optimization tan(x) ~ x for tiny x. -// 3. tan(x) is approximated by a odd polynomial of degree 27 on -// [0,0.67434] -// 3 27 -// tan(x) ~ x + T1*x + ... + T13*x -// where -// -// |tan(x) 2 4 26 | -59.2 -// |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 -// | x | -// -// Note: tan(x+y) = tan(x) + tan'(x)*y -// ~ tan(x) + (1+x*x)*y -// Therefore, for better accuracy in computing tan(x+y), let -// 3 2 2 2 2 -// r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) -// then -// 3 2 -// tan(x+y) = x + (T1*x + (x *(r+y)+y)) -// -// 4. For x in [0.67434,pi/4], let y = pi/4 - x, then -// tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) -// = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) -static T: [f64; 13] = [ - 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ - 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ - 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ - 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ - 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ - 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ - 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ - 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ - 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ - 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ - 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ - -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ - 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ -]; -const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ -const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { - let hx = (f64::to_bits(x) >> 32) as u32; - let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ - if big { - let sign = hx >> 31; - if sign != 0 { - x = -x; - y = -y; - } - x = (PIO4 - x) + (PIO4_LO - y); - y = 0.0; - } - let z = x * x; - let w = z * z; - /* - * Break x^5*(T[1]+x^2*T[2]+...) into - * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + - * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) - */ - let r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11])))); - let v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12]))))); - let s = z * x; - let r = y + z * (s * (r + v) + y) + s * T[0]; - let w = x + r; - if big { - let sign = hx >> 31; - let s = 1.0 - 2.0 * odd as f64; - let v = s - 2.0 * (x + (r - w * w / (w + s))); - return if sign != 0 { -v } else { v }; - } - if odd == 0 { - return w; - } - /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */ - let w0 = zero_low_word(w); - let v = r - (w0 - x); /* w0+v = r+x */ - let a = -1.0 / w; - let a0 = zero_low_word(a); - a0 + a * (1.0 + a0 * w0 + a0 * v) -} - -fn zero_low_word(x: f64) -> f64 { - f64::from_bits(f64::to_bits(x) & 0xFFFF_FFFF_0000_0000) -} diff --git a/library/compiler-builtins/libm/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/libm/src/math/k_tanf.rs deleted file mode 100644 index af8db539dad..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/k_tanf.rs +++ /dev/null @@ -1,46 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ -/* - * ==================================================== - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. - * - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ -const T: [f64; 6] = [ - 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ - 0.133392002712976742718, /* 0x1112fd38999f72.0p-55 */ - 0.0533812378445670393523, /* 0x1b54c91d865afe.0p-57 */ - 0.0245283181166547278873, /* 0x191df3908c33ce.0p-58 */ - 0.00297435743359967304927, /* 0x185dadfcecf44e.0p-61 */ - 0.00946564784943673166728, /* 0x1362b9bf971bcd.0p-59 */ -]; - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { - let z = x * x; - /* - * Split up the polynomial into small independent terms to give - * opportunities for parallel evaluation. The chosen splitting is - * micro-optimized for Athlons (XP, X64). It costs 2 multiplications - * relative to Horner's method on sequential machines. - * - * We add the small terms from lowest degree up for efficiency on - * non-sequential machines (the lowest degree terms tend to be ready - * earlier). Apart from this, we don't care about order of - * operations, and don't need to to care since we have precision to - * spare. However, the chosen splitting is good for accuracy too, - * and would give results as accurate as Horner's method if the - * small terms were added from highest degree down. - */ - let mut r = T[4] + z * T[5]; - let t = T[2] + z * T[3]; - let w = z * z; - let s = z * x; - let u = T[0] + z * T[1]; - r = (x + s * u) + (s * w) * (t + w * r); - (if odd { -1. / r } else { r }) as f32 -} diff --git a/library/compiler-builtins/libm/libm/src/math/ldexp.rs b/library/compiler-builtins/libm/libm/src/math/ldexp.rs deleted file mode 100644 index 24899ba306a..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/ldexp.rs +++ /dev/null @@ -1,21 +0,0 @@ -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf16(x: f16, n: i32) -> f16 { - super::scalbnf16(x, n) -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf(x: f32, n: i32) -> f32 { - super::scalbnf(x, n) -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexp(x: f64, n: i32) -> f64 { - super::scalbn(x, n) -} - -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf128(x: f128, n: i32) -> f128 { - super::scalbnf128(x, n) -} diff --git a/library/compiler-builtins/libm/libm/src/math/ldexpf.rs b/library/compiler-builtins/libm/libm/src/math/ldexpf.rs deleted file mode 100644 index 95b27fc49d2..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/ldexpf.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf(x: f32, n: i32) -> f32 { - super::scalbnf(x, n) -} diff --git a/library/compiler-builtins/libm/libm/src/math/ldexpf128.rs b/library/compiler-builtins/libm/libm/src/math/ldexpf128.rs deleted file mode 100644 index b35277d15fb..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/ldexpf128.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf128(x: f128, n: i32) -> f128 { - super::scalbnf128(x, n) -} diff --git a/library/compiler-builtins/libm/libm/src/math/ldexpf16.rs b/library/compiler-builtins/libm/libm/src/math/ldexpf16.rs deleted file mode 100644 index 8de6cffd699..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/ldexpf16.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf16(x: f16, n: i32) -> f16 { - super::scalbnf16(x, n) -} diff --git a/library/compiler-builtins/libm/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/libm/src/math/lgamma.rs deleted file mode 100644 index 8312dc18648..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/lgamma.rs +++ /dev/null @@ -1,8 +0,0 @@ -use super::lgamma_r; - -/// The natural logarithm of the -/// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgamma(x: f64) -> f64 { - lgamma_r(x).0 -} diff --git a/library/compiler-builtins/libm/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/libm/src/math/lgamma_r.rs deleted file mode 100644 index 6becaad2ce9..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/lgamma_r.rs +++ /dev/null @@ -1,321 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - * - */ -/* lgamma_r(x, signgamp) - * Reentrant version of the logarithm of the Gamma function - * with user provide pointer for the sign of Gamma(x). - * - * Method: - * 1. Argument Reduction for 0 < x <= 8 - * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may - * reduce x to a number in [1.5,2.5] by - * lgamma(1+s) = log(s) + lgamma(s) - * for example, - * lgamma(7.3) = log(6.3) + lgamma(6.3) - * = log(6.3*5.3) + lgamma(5.3) - * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) - * 2. Polynomial approximation of lgamma around its - * minimun ymin=1.461632144968362245 to maintain monotonicity. - * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use - * Let z = x-ymin; - * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) - * where - * poly(z) is a 14 degree polynomial. - * 2. Rational approximation in the primary interval [2,3] - * We use the following approximation: - * s = x-2.0; - * lgamma(x) = 0.5*s + s*P(s)/Q(s) - * with accuracy - * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 - * Our algorithms are based on the following observation - * - * zeta(2)-1 2 zeta(3)-1 3 - * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... - * 2 3 - * - * where Euler = 0.5771... is the Euler constant, which is very - * close to 0.5. - * - * 3. For x>=8, we have - * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... - * (better formula: - * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) - * Let z = 1/x, then we approximation - * f(z) = lgamma(x) - (x-0.5)(log(x)-1) - * by - * 3 5 11 - * w = w0 + w1*z + w2*z + w3*z + ... + w6*z - * where - * |w - f(z)| < 2**-58.74 - * - * 4. For negative x, since (G is gamma function) - * -x*G(-x)*G(x) = PI/sin(PI*x), - * we have - * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) - * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 - * Hence, for x<0, signgam = sign(sin(PI*x)) and - * lgamma(x) = log(|Gamma(x)|) - * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); - * Note: one should avoid compute PI*(-x) directly in the - * computation of sin(PI*(-x)). - * - * 5. Special Cases - * lgamma(2+s) ~ s*(1-Euler) for tiny s - * lgamma(1) = lgamma(2) = 0 - * lgamma(x) ~ -log(|x|) for tiny x - * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero - * lgamma(inf) = inf - * lgamma(-inf) = inf (bug for bug compatible with C99!?) - * - */ - -use super::{floor, k_cos, k_sin, log}; - -const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ -const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ -const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ -const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ -const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ -const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ -const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ -const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ -const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ -const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ -const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ -const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ -const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ -const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ -const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ -/* tt = -(tail of TF) */ -const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ -const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ -const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ -const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ -const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ -const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ -const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ -const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ -const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ -const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ -const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ -const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ -const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ -const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ -const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ -const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ -const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ -const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ -const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ -const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ -const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ -const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ -const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ -const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ -const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ -const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ -const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ -const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ -const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ -const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ -const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ -const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ -const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ -const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ -const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ -const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ -const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ -const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ -const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ -const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ -const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ -const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ -const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ -const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ -const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ - -/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: f64) -> f64 { - let mut n: i32; - - /* spurious inexact if odd int */ - x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ - - n = (x * 4.0) as i32; - n = div!(n + 1, 2); - x -= (n as f64) * 0.5; - x *= PI; - - match n { - 1 => k_cos(x, 0.0), - 2 => k_sin(-x, 0.0, 0), - 3 => -k_cos(x, 0.0), - // 0 - _ => k_sin(x, 0.0, 0), - } -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgamma_r(mut x: f64) -> (f64, i32) { - let u: u64 = x.to_bits(); - let mut t: f64; - let y: f64; - let mut z: f64; - let nadj: f64; - let p: f64; - let p1: f64; - let p2: f64; - let p3: f64; - let q: f64; - let mut r: f64; - let w: f64; - let ix: u32; - let sign: bool; - let i: i32; - let mut signgam: i32; - - /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - signgam = 1; - sign = (u >> 63) != 0; - ix = ((u >> 32) as u32) & 0x7fffffff; - if ix >= 0x7ff00000 { - return (x * x, signgam); - } - if ix < (0x3ff - 70) << 20 { - /* |x|<2**-70, return -log(|x|) */ - if sign { - x = -x; - signgam = -1; - } - return (-log(x), signgam); - } - if sign { - x = -x; - t = sin_pi(x); - if t == 0.0 { - /* -integer */ - return (1.0 / (x - x), signgam); - } - if t > 0.0 { - signgam = -1; - } else { - t = -t; - } - nadj = log(PI / (t * x)); - } else { - nadj = 0.0; - } - - /* purge off 1 and 2 */ - if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { - r = 0.0; - } - /* for x < 2.0 */ - else if ix < 0x40000000 { - if ix <= 0x3feccccc { - /* lgamma(x) = lgamma(x+1)-log(x) */ - r = -log(x); - if ix >= 0x3FE76944 { - y = 1.0 - x; - i = 0; - } else if ix >= 0x3FCDA661 { - y = x - (TC - 1.0); - i = 1; - } else { - y = x; - i = 2; - } - } else { - r = 0.0; - if ix >= 0x3FFBB4C3 { - /* [1.7316,2] */ - y = 2.0 - x; - i = 0; - } else if ix >= 0x3FF3B4C4 { - /* [1.23,1.73] */ - y = x - TC; - i = 1; - } else { - y = x - 1.0; - i = 2; - } - } - match i { - 0 => { - z = y * y; - p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); - p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); - p = y * p1 + p2; - r += p - 0.5 * y; - } - 1 => { - z = y * y; - w = z * y; - p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ - p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); - p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); - p = z * p1 - (TT - w * (p2 + y * p3)); - r += TF + p; - } - 2 => { - p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); - p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); - r += -0.5 * y + p1 / p2; - } - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => {} - } - } else if ix < 0x40200000 { - /* x < 8.0 */ - i = x as i32; - y = x - (i as f64); - p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); - q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); - r = 0.5 * y + p / q; - z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ - // TODO: In C, this was implemented using switch jumps with fallthrough. - // Does this implementation have performance problems? - if i >= 7 { - z *= y + 6.0; - } - if i >= 6 { - z *= y + 5.0; - } - if i >= 5 { - z *= y + 4.0; - } - if i >= 4 { - z *= y + 3.0; - } - if i >= 3 { - z *= y + 2.0; - r += log(z); - } - } else if ix < 0x43900000 { - /* 8.0 <= x < 2**58 */ - t = log(x); - z = 1.0 / x; - y = z * z; - w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); - r = (x - 0.5) * (t - 1.0) + w; - } else { - /* 2**58 <= x <= inf */ - r = x * (log(x) - 1.0); - } - if sign { - r = nadj - r; - } - return (r, signgam); -} diff --git a/library/compiler-builtins/libm/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/libm/src/math/lgammaf.rs deleted file mode 100644 index d37512397cb..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/lgammaf.rs +++ /dev/null @@ -1,8 +0,0 @@ -use super::lgammaf_r; - -/// The natural logarithm of the -/// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgammaf(x: f32) -> f32 { - lgammaf_r(x).0 -} diff --git a/library/compiler-builtins/libm/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/libm/src/math/lgammaf_r.rs deleted file mode 100644 index 10cecee541c..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/lgammaf_r.rs +++ /dev/null @@ -1,256 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{floorf, k_cosf, k_sinf, logf}; - -const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ -const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ -const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ -const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ -const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ -const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ -const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ -const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ -const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ -const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ -const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ -const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ -const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ -const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ -const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ -/* TT = -(tail of TF) */ -const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ -const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ -const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ -const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ -const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ -const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ -const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ -const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ -const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ -const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ -const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ -const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ -const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ -const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ -const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ -const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ -const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ -const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ -const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ -const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ -const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ -const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ -const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ -const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ -const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ -const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ -const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ -const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ -const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ -const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ -const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ -const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ -const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ -const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ -const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ -const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ -const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ -const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ -const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ -const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ -const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ -const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ -const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ -const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ -const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ -const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ -const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ - -/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: f32) -> f32 { - let mut y: f64; - let mut n: isize; - - /* spurious inexact if odd int */ - x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ - - n = (x * 4.0) as isize; - n = div!(n + 1, 2); - y = (x as f64) - (n as f64) * 0.5; - y *= 3.14159265358979323846; - match n { - 1 => k_cosf(y), - 2 => k_sinf(-y), - 3 => -k_cosf(y), - // 0 - _ => k_sinf(y), - } -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgammaf_r(mut x: f32) -> (f32, i32) { - let u = x.to_bits(); - let mut t: f32; - let y: f32; - let mut z: f32; - let nadj: f32; - let p: f32; - let p1: f32; - let p2: f32; - let p3: f32; - let q: f32; - let mut r: f32; - let w: f32; - let ix: u32; - let i: i32; - let sign: bool; - let mut signgam: i32; - - /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - signgam = 1; - sign = (u >> 31) != 0; - ix = u & 0x7fffffff; - if ix >= 0x7f800000 { - return (x * x, signgam); - } - if ix < 0x35000000 { - /* |x| < 2**-21, return -log(|x|) */ - if sign { - signgam = -1; - x = -x; - } - return (-logf(x), signgam); - } - if sign { - x = -x; - t = sin_pi(x); - if t == 0.0 { - /* -integer */ - return (1.0 / (x - x), signgam); - } - if t > 0.0 { - signgam = -1; - } else { - t = -t; - } - nadj = logf(PI / (t * x)); - } else { - nadj = 0.0; - } - - /* purge off 1 and 2 */ - if ix == 0x3f800000 || ix == 0x40000000 { - r = 0.0; - } - /* for x < 2.0 */ - else if ix < 0x40000000 { - if ix <= 0x3f666666 { - /* lgamma(x) = lgamma(x+1)-log(x) */ - r = -logf(x); - if ix >= 0x3f3b4a20 { - y = 1.0 - x; - i = 0; - } else if ix >= 0x3e6d3308 { - y = x - (TC - 1.0); - i = 1; - } else { - y = x; - i = 2; - } - } else { - r = 0.0; - if ix >= 0x3fdda618 { - /* [1.7316,2] */ - y = 2.0 - x; - i = 0; - } else if ix >= 0x3F9da620 { - /* [1.23,1.73] */ - y = x - TC; - i = 1; - } else { - y = x - 1.0; - i = 2; - } - } - match i { - 0 => { - z = y * y; - p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); - p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); - p = y * p1 + p2; - r += p - 0.5 * y; - } - 1 => { - z = y * y; - w = z * y; - p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ - p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); - p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); - p = z * p1 - (TT - w * (p2 + y * p3)); - r += TF + p; - } - 2 => { - p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); - p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); - r += -0.5 * y + p1 / p2; - } - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => {} - } - } else if ix < 0x41000000 { - /* x < 8.0 */ - i = x as i32; - y = x - (i as f32); - p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); - q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); - r = 0.5 * y + p / q; - z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ - // TODO: In C, this was implemented using switch jumps with fallthrough. - // Does this implementation have performance problems? - if i >= 7 { - z *= y + 6.0; - } - if i >= 6 { - z *= y + 5.0; - } - if i >= 5 { - z *= y + 4.0; - } - if i >= 4 { - z *= y + 3.0; - } - if i >= 3 { - z *= y + 2.0; - r += logf(z); - } - } else if ix < 0x5c800000 { - /* 8.0 <= x < 2**58 */ - t = logf(x); - z = 1.0 / x; - y = z * z; - w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); - r = (x - 0.5) * (t - 1.0) + w; - } else { - /* 2**58 <= x <= inf */ - r = x * (logf(x) - 1.0); - } - if sign { - r = nadj - r; - } - return (r, signgam); -} diff --git a/library/compiler-builtins/libm/libm/src/math/log.rs b/library/compiler-builtins/libm/libm/src/math/log.rs deleted file mode 100644 index f2dc47ec5cc..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/log.rs +++ /dev/null @@ -1,118 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* log(x) - * Return the logarithm of x - * - * Method : - * 1. Argument Reduction: find k and f such that - * x = 2^k * (1+f), - * where sqrt(2)/2 < 1+f < sqrt(2) . - * - * 2. Approximation of log(1+f). - * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) - * = 2s + 2/3 s**3 + 2/5 s**5 + ....., - * = 2s + s*R - * We use a special Remez algorithm on [0,0.1716] to generate - * a polynomial of degree 14 to approximate R The maximum error - * of this polynomial approximation is bounded by 2**-58.45. In - * other words, - * 2 4 6 8 10 12 14 - * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s - * (the values of Lg1 to Lg7 are listed in the program) - * and - * | 2 14 | -58.45 - * | Lg1*s +...+Lg7*s - R(z) | <= 2 - * | | - * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. - * In order to guarantee error in log below 1ulp, we compute log - * by - * log(1+f) = f - s*(f - R) (if f is not too large) - * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) - * - * 3. Finally, log(x) = k*ln2 + log(1+f). - * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) - * Here ln2 is split into two floating point number: - * ln2_hi + ln2_lo, - * where n*ln2_hi is always exact for |n| < 2000. - * - * Special cases: - * log(x) is NaN with signal if x < 0 (including -INF) ; - * log(+INF) is +INF; log(0) is -INF with signal; - * log(NaN) is that NaN with no signal. - * - * Accuracy: - * according to an error analysis, the error is always less than - * 1 ulp (unit in the last place). - * - * Constants: - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. - */ - -const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ -const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ -const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ - -/// The natural logarithm of `x` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log(mut x: f64) -> f64 { - let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 - - let mut ui = x.to_bits(); - let mut hx: u32 = (ui >> 32) as u32; - let mut k: i32 = 0; - - if (hx < 0x00100000) || ((hx >> 31) != 0) { - /* x < 2**-126 */ - if ui << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if hx >> 31 != 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale x up */ - k -= 54; - x *= x1p54; - ui = x.to_bits(); - hx = (ui >> 32) as u32; - } else if hx >= 0x7ff00000 { - return x; - } else if hx == 0x3ff00000 && ui << 32 == 0 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - hx += 0x3ff00000 - 0x3fe6a09e; - k += ((hx >> 20) as i32) - 0x3ff; - hx = (hx & 0x000fffff) + 0x3fe6a09e; - ui = ((hx as u64) << 32) | (ui & 0xffffffff); - x = f64::from_bits(ui); - - let f: f64 = x - 1.0; - let hfsq: f64 = 0.5 * f * f; - let s: f64 = f / (2.0 + f); - let z: f64 = s * s; - let w: f64 = z * z; - let t1: f64 = w * (LG2 + w * (LG4 + w * LG6)); - let t2: f64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - let r: f64 = t2 + t1; - let dk: f64 = k as f64; - s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI -} diff --git a/library/compiler-builtins/libm/libm/src/math/log10.rs b/library/compiler-builtins/libm/libm/src/math/log10.rs deleted file mode 100644 index 8c9d68c492d..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/log10.rs +++ /dev/null @@ -1,118 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* - * Return the base 10 logarithm of x. See log.c for most comments. - * - * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 - * as in log.c, then combine and scale in extra precision: - * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) - */ - -use core::f64; - -const IVLN10HI: f64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ -const IVLN10LO: f64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ -const LOG10_2HI: f64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ -const LOG10_2LO: f64 = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ -const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ - -/// The base 10 logarithm of `x` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log10(mut x: f64) -> f64 { - let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 - - let mut ui: u64 = x.to_bits(); - let hfsq: f64; - let f: f64; - let s: f64; - let z: f64; - let r: f64; - let mut w: f64; - let t1: f64; - let t2: f64; - let dk: f64; - let y: f64; - let mut hi: f64; - let lo: f64; - let mut val_hi: f64; - let mut val_lo: f64; - let mut hx: u32; - let mut k: i32; - - hx = (ui >> 32) as u32; - k = 0; - if hx < 0x00100000 || (hx >> 31) > 0 { - if ui << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (hx >> 31) > 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale x up */ - k -= 54; - x *= x1p54; - ui = x.to_bits(); - hx = (ui >> 32) as u32; - } else if hx >= 0x7ff00000 { - return x; - } else if hx == 0x3ff00000 && ui << 32 == 0 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - hx += 0x3ff00000 - 0x3fe6a09e; - k += (hx >> 20) as i32 - 0x3ff; - hx = (hx & 0x000fffff) + 0x3fe6a09e; - ui = ((hx as u64) << 32) | (ui & 0xffffffff); - x = f64::from_bits(ui); - - f = x - 1.0; - hfsq = 0.5 * f * f; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * (LG4 + w * LG6)); - t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - r = t2 + t1; - - /* See log2.c for details. */ - /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ - hi = f - hfsq; - ui = hi.to_bits(); - ui &= (-1i64 as u64) << 32; - hi = f64::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); - - /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ - val_hi = hi * IVLN10HI; - dk = k as f64; - y = dk * LOG10_2HI; - val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI; - - /* - * Extra precision in for adding y is not strictly needed - * since there is no very large cancellation near x = sqrt(2) or - * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs - * with some parallelism and it reduces the error for many args. - */ - w = y + val_hi; - val_lo += (y - w) + val_hi; - val_hi = w; - - val_lo + val_hi -} diff --git a/library/compiler-builtins/libm/libm/src/math/log10f.rs b/library/compiler-builtins/libm/libm/src/math/log10f.rs deleted file mode 100644 index 18bf8fcc832..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/log10f.rs +++ /dev/null @@ -1,92 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* - * See comments in log10.c. - */ - -use core::f32; - -const IVLN10HI: f32 = 4.3432617188e-01; /* 0x3ede6000 */ -const IVLN10LO: f32 = -3.1689971365e-05; /* 0xb804ead9 */ -const LOG10_2HI: f32 = 3.0102920532e-01; /* 0x3e9a2080 */ -const LOG10_2LO: f32 = 7.9034151668e-07; /* 0x355427db */ -/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ - -/// The base 10 logarithm of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log10f(mut x: f32) -> f32 { - let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 - - let mut ui: u32 = x.to_bits(); - let hfsq: f32; - let f: f32; - let s: f32; - let z: f32; - let r: f32; - let w: f32; - let t1: f32; - let t2: f32; - let dk: f32; - let mut hi: f32; - let lo: f32; - let mut ix: u32; - let mut k: i32; - - ix = ui; - k = 0; - if ix < 0x00800000 || (ix >> 31) > 0 { - /* x < 2**-126 */ - if ix << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (ix >> 31) > 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale up x */ - k -= 25; - x *= x1p25f; - ui = x.to_bits(); - ix = ui; - } else if ix >= 0x7f800000 { - return x; - } else if ix == 0x3f800000 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - ix += 0x3f800000 - 0x3f3504f3; - k += (ix >> 23) as i32 - 0x7f; - ix = (ix & 0x007fffff) + 0x3f3504f3; - ui = ix; - x = f32::from_bits(ui); - - f = x - 1.0; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * LG4); - t2 = z * (LG1 + w * LG3); - r = t2 + t1; - hfsq = 0.5 * f * f; - - hi = f - hfsq; - ui = hi.to_bits(); - ui &= 0xfffff000; - hi = f32::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); - dk = k as f32; - dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI -} diff --git a/library/compiler-builtins/libm/libm/src/math/log1p.rs b/library/compiler-builtins/libm/libm/src/math/log1p.rs deleted file mode 100644 index b7f3fb09e15..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/log1p.rs +++ /dev/null @@ -1,140 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* double log1p(double x) - * Return the natural logarithm of 1+x. - * - * Method : - * 1. Argument Reduction: find k and f such that - * 1+x = 2^k * (1+f), - * where sqrt(2)/2 < 1+f < sqrt(2) . - * - * Note. If k=0, then f=x is exact. However, if k!=0, then f - * may not be representable exactly. In that case, a correction - * term is need. Let u=1+x rounded. Let c = (1+x)-u, then - * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), - * and add back the correction term c/u. - * (Note: when x > 2**53, one can simply return log(x)) - * - * 2. Approximation of log(1+f): See log.c - * - * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c - * - * Special cases: - * log1p(x) is NaN with signal if x < -1 (including -INF) ; - * log1p(+INF) is +INF; log1p(-1) is -INF with signal; - * log1p(NaN) is that NaN with no signal. - * - * Accuracy: - * according to an error analysis, the error is always less than - * 1 ulp (unit in the last place). - * - * Constants: - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. - * - * Note: Assuming log() return accurate answer, the following - * algorithm can be used to compute log1p(x) to within a few ULP: - * - * u = 1+x; - * if(u==1.0) return x ; else - * return log(u)*(x/(u-1.0)); - * - * See HP-15C Advanced Functions Handbook, p.193. - */ - -use core::f64; - -const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ -const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ -const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ - -/// The natural logarithm of 1+`x` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log1p(x: f64) -> f64 { - let mut ui: u64 = x.to_bits(); - let hfsq: f64; - let mut f: f64 = 0.; - let mut c: f64 = 0.; - let s: f64; - let z: f64; - let r: f64; - let w: f64; - let t1: f64; - let t2: f64; - let dk: f64; - let hx: u32; - let mut hu: u32; - let mut k: i32; - - hx = (ui >> 32) as u32; - k = 1; - if hx < 0x3fda827a || (hx >> 31) > 0 { - /* 1+x < sqrt(2)+ */ - if hx >= 0xbff00000 { - /* x <= -1.0 */ - if x == -1. { - return x / 0.0; /* log1p(-1) = -inf */ - } - return (x - x) / 0.0; /* log1p(x<-1) = NaN */ - } - if hx << 1 < 0x3ca00000 << 1 { - /* |x| < 2**-53 */ - /* underflow if subnormal */ - if (hx & 0x7ff00000) == 0 { - force_eval!(x as f32); - } - return x; - } - if hx <= 0xbfd2bec4 { - /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ - k = 0; - c = 0.; - f = x; - } - } else if hx >= 0x7ff00000 { - return x; - } - if k > 0 { - ui = (1. + x).to_bits(); - hu = (ui >> 32) as u32; - hu += 0x3ff00000 - 0x3fe6a09e; - k = (hu >> 20) as i32 - 0x3ff; - /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ - if k < 54 { - c = if k >= 2 { 1. - (f64::from_bits(ui) - x) } else { x - (f64::from_bits(ui) - 1.) }; - c /= f64::from_bits(ui); - } else { - c = 0.; - } - /* reduce u into [sqrt(2)/2, sqrt(2)] */ - hu = (hu & 0x000fffff) + 0x3fe6a09e; - ui = ((hu as u64) << 32) | (ui & 0xffffffff); - f = f64::from_bits(ui) - 1.; - } - hfsq = 0.5 * f * f; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * (LG4 + w * LG6)); - t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - r = t2 + t1; - dk = k as f64; - s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI -} diff --git a/library/compiler-builtins/libm/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/libm/src/math/log1pf.rs deleted file mode 100644 index bba5b8a2f21..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/log1pf.rs +++ /dev/null @@ -1,95 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::f32; - -const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ -/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ - -/// The natural logarithm of 1+`x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log1pf(x: f32) -> f32 { - let mut ui: u32 = x.to_bits(); - let hfsq: f32; - let mut f: f32 = 0.; - let mut c: f32 = 0.; - let s: f32; - let z: f32; - let r: f32; - let w: f32; - let t1: f32; - let t2: f32; - let dk: f32; - let ix: u32; - let mut iu: u32; - let mut k: i32; - - ix = ui; - k = 1; - if ix < 0x3ed413d0 || (ix >> 31) > 0 { - /* 1+x < sqrt(2)+ */ - if ix >= 0xbf800000 { - /* x <= -1.0 */ - if x == -1. { - return x / 0.0; /* log1p(-1)=+inf */ - } - return (x - x) / 0.0; /* log1p(x<-1)=NaN */ - } - if ix << 1 < 0x33800000 << 1 { - /* |x| < 2**-24 */ - /* underflow if subnormal */ - if (ix & 0x7f800000) == 0 { - force_eval!(x * x); - } - return x; - } - if ix <= 0xbe95f619 { - /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ - k = 0; - c = 0.; - f = x; - } - } else if ix >= 0x7f800000 { - return x; - } - if k > 0 { - ui = (1. + x).to_bits(); - iu = ui; - iu += 0x3f800000 - 0x3f3504f3; - k = (iu >> 23) as i32 - 0x7f; - /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ - if k < 25 { - c = if k >= 2 { 1. - (f32::from_bits(ui) - x) } else { x - (f32::from_bits(ui) - 1.) }; - c /= f32::from_bits(ui); - } else { - c = 0.; - } - /* reduce u into [sqrt(2)/2, sqrt(2)] */ - iu = (iu & 0x007fffff) + 0x3f3504f3; - ui = iu; - f = f32::from_bits(ui) - 1.; - } - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * LG4); - t2 = z * (LG1 + w * LG3); - r = t2 + t1; - hfsq = 0.5 * f * f; - dk = k as f32; - s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI -} diff --git a/library/compiler-builtins/libm/libm/src/math/log2.rs b/library/compiler-builtins/libm/libm/src/math/log2.rs deleted file mode 100644 index 701f63c25e7..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/log2.rs +++ /dev/null @@ -1,107 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* - * Return the base 2 logarithm of x. See log.c for most comments. - * - * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 - * as in log.c, then combine and scale in extra precision: - * log2(x) = (f - f*f/2 + r)/log(2) + k - */ - -use core::f64; - -const IVLN2HI: f64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ -const IVLN2LO: f64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ -const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ - -/// The base 2 logarithm of `x` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log2(mut x: f64) -> f64 { - let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 - - let mut ui: u64 = x.to_bits(); - let hfsq: f64; - let f: f64; - let s: f64; - let z: f64; - let r: f64; - let mut w: f64; - let t1: f64; - let t2: f64; - let y: f64; - let mut hi: f64; - let lo: f64; - let mut val_hi: f64; - let mut val_lo: f64; - let mut hx: u32; - let mut k: i32; - - hx = (ui >> 32) as u32; - k = 0; - if hx < 0x00100000 || (hx >> 31) > 0 { - if ui << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (hx >> 31) > 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale x up */ - k -= 54; - x *= x1p54; - ui = x.to_bits(); - hx = (ui >> 32) as u32; - } else if hx >= 0x7ff00000 { - return x; - } else if hx == 0x3ff00000 && ui << 32 == 0 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - hx += 0x3ff00000 - 0x3fe6a09e; - k += (hx >> 20) as i32 - 0x3ff; - hx = (hx & 0x000fffff) + 0x3fe6a09e; - ui = ((hx as u64) << 32) | (ui & 0xffffffff); - x = f64::from_bits(ui); - - f = x - 1.0; - hfsq = 0.5 * f * f; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * (LG4 + w * LG6)); - t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - r = t2 + t1; - - /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ - hi = f - hfsq; - ui = hi.to_bits(); - ui &= (-1i64 as u64) << 32; - hi = f64::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); - - val_hi = hi * IVLN2HI; - val_lo = (lo + hi) * IVLN2LO + lo * IVLN2HI; - - /* spadd(val_hi, val_lo, y), except for not using double_t: */ - y = k.into(); - w = y + val_hi; - val_lo += (y - w) + val_hi; - val_hi = w; - - val_lo + val_hi -} diff --git a/library/compiler-builtins/libm/libm/src/math/log2f.rs b/library/compiler-builtins/libm/libm/src/math/log2f.rs deleted file mode 100644 index 5ba2427d1d4..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/log2f.rs +++ /dev/null @@ -1,88 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* - * See comments in log2.c. - */ - -use core::f32; - -const IVLN2HI: f32 = 1.4428710938e+00; /* 0x3fb8b000 */ -const IVLN2LO: f32 = -1.7605285393e-04; /* 0xb9389ad4 */ -/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ - -/// The base 2 logarithm of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log2f(mut x: f32) -> f32 { - let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 - - let mut ui: u32 = x.to_bits(); - let hfsq: f32; - let f: f32; - let s: f32; - let z: f32; - let r: f32; - let w: f32; - let t1: f32; - let t2: f32; - let mut hi: f32; - let lo: f32; - let mut ix: u32; - let mut k: i32; - - ix = ui; - k = 0; - if ix < 0x00800000 || (ix >> 31) > 0 { - /* x < 2**-126 */ - if ix << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (ix >> 31) > 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale up x */ - k -= 25; - x *= x1p25f; - ui = x.to_bits(); - ix = ui; - } else if ix >= 0x7f800000 { - return x; - } else if ix == 0x3f800000 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - ix += 0x3f800000 - 0x3f3504f3; - k += (ix >> 23) as i32 - 0x7f; - ix = (ix & 0x007fffff) + 0x3f3504f3; - ui = ix; - x = f32::from_bits(ui); - - f = x - 1.0; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * LG4); - t2 = z * (LG1 + w * LG3); - r = t2 + t1; - hfsq = 0.5 * f * f; - - hi = f - hfsq; - ui = hi.to_bits(); - ui &= 0xfffff000; - hi = f32::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); - (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as f32 -} diff --git a/library/compiler-builtins/libm/libm/src/math/logf.rs b/library/compiler-builtins/libm/libm/src/math/logf.rs deleted file mode 100644 index 68d1943025e..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/logf.rs +++ /dev/null @@ -1,66 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ -/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ -const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ - -/// The natural logarithm of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn logf(mut x: f32) -> f32 { - let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 - - let mut ix = x.to_bits(); - let mut k = 0i32; - - if (ix < 0x00800000) || ((ix >> 31) != 0) { - /* x < 2**-126 */ - if ix << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (ix >> 31) != 0 { - return (x - x) / 0.; /* log(-#) = NaN */ - } - /* subnormal number, scale up x */ - k -= 25; - x *= x1p25; - ix = x.to_bits(); - } else if ix >= 0x7f800000 { - return x; - } else if ix == 0x3f800000 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - ix += 0x3f800000 - 0x3f3504f3; - k += ((ix >> 23) as i32) - 0x7f; - ix = (ix & 0x007fffff) + 0x3f3504f3; - x = f32::from_bits(ix); - - let f = x - 1.; - let s = f / (2. + f); - let z = s * s; - let w = z * z; - let t1 = w * (LG2 + w * LG4); - let t2 = z * (LG1 + w * LG3); - let r = t2 + t1; - let hfsq = 0.5 * f * f; - let dk = k as f32; - s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI -} diff --git a/library/compiler-builtins/libm/libm/src/math/mod.rs b/library/compiler-builtins/libm/libm/src/math/mod.rs deleted file mode 100644 index 949c18b4000..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/mod.rs +++ /dev/null @@ -1,396 +0,0 @@ -macro_rules! force_eval { - ($e:expr) => { - unsafe { ::core::ptr::read_volatile(&$e) } - }; -} - -#[cfg(not(debug_assertions))] -macro_rules! i { - ($array:expr, $index:expr) => { - unsafe { *$array.get_unchecked($index) } - }; - ($array:expr, $index:expr, = , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) = $rhs; - } - }; - ($array:expr, $index:expr, += , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) += $rhs; - } - }; - ($array:expr, $index:expr, -= , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) -= $rhs; - } - }; - ($array:expr, $index:expr, &= , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) &= $rhs; - } - }; - ($array:expr, $index:expr, == , $rhs:expr) => { - unsafe { *$array.get_unchecked_mut($index) == $rhs } - }; -} - -#[cfg(debug_assertions)] -macro_rules! i { - ($array:expr, $index:expr) => { - *$array.get($index).unwrap() - }; - ($array:expr, $index:expr, = , $rhs:expr) => { - *$array.get_mut($index).unwrap() = $rhs; - }; - ($array:expr, $index:expr, -= , $rhs:expr) => { - *$array.get_mut($index).unwrap() -= $rhs; - }; - ($array:expr, $index:expr, += , $rhs:expr) => { - *$array.get_mut($index).unwrap() += $rhs; - }; - ($array:expr, $index:expr, &= , $rhs:expr) => { - *$array.get_mut($index).unwrap() &= $rhs; - }; - ($array:expr, $index:expr, == , $rhs:expr) => { - *$array.get_mut($index).unwrap() == $rhs - }; -} - -// Temporary macro to avoid panic codegen for division (in debug mode too). At -// the time of this writing this is only used in a few places, and once -// rust-lang/rust#72751 is fixed then this macro will no longer be necessary and -// the native `/` operator can be used and panics won't be codegen'd. -#[cfg(any(debug_assertions, not(intrinsics_enabled)))] -macro_rules! div { - ($a:expr, $b:expr) => { - $a / $b - }; -} - -#[cfg(all(not(debug_assertions), intrinsics_enabled))] -macro_rules! div { - ($a:expr, $b:expr) => { - unsafe { core::intrinsics::unchecked_div($a, $b) } - }; -} - -// `support` may be public for testing -#[macro_use] -#[cfg(feature = "unstable-public-internals")] -pub mod support; - -#[macro_use] -#[cfg(not(feature = "unstable-public-internals"))] -pub(crate) mod support; - -cfg_if! { - if #[cfg(feature = "unstable-public-internals")] { - pub mod generic; - } else { - mod generic; - } -} - -// Private modules -mod arch; -mod expo2; -mod k_cos; -mod k_cosf; -mod k_expo2; -mod k_expo2f; -mod k_sin; -mod k_sinf; -mod k_tan; -mod k_tanf; -mod rem_pio2; -mod rem_pio2_large; -mod rem_pio2f; - -// Private re-imports -use self::expo2::expo2; -use self::k_cos::k_cos; -use self::k_cosf::k_cosf; -use self::k_expo2::k_expo2; -use self::k_expo2f::k_expo2f; -use self::k_sin::k_sin; -use self::k_sinf::k_sinf; -use self::k_tan::k_tan; -use self::k_tanf::k_tanf; -use self::rem_pio2::rem_pio2; -use self::rem_pio2_large::rem_pio2_large; -use self::rem_pio2f::rem_pio2f; -#[allow(unused_imports)] -use self::support::{CastFrom, CastInto, DFloat, DInt, Float, HFloat, HInt, Int, IntTy, MinInt}; - -// Public modules -mod acos; -mod acosf; -mod acosh; -mod acoshf; -mod asin; -mod asinf; -mod asinh; -mod asinhf; -mod atan; -mod atan2; -mod atan2f; -mod atanf; -mod atanh; -mod atanhf; -mod cbrt; -mod cbrtf; -mod ceil; -mod copysign; -mod cos; -mod cosf; -mod cosh; -mod coshf; -mod erf; -mod erff; -mod exp; -mod exp10; -mod exp10f; -mod exp2; -mod exp2f; -mod expf; -mod expm1; -mod expm1f; -mod fabs; -mod fdim; -mod floor; -mod fma; -mod fma_wide; -mod fmin_fmax; -mod fminimum_fmaximum; -mod fminimum_fmaximum_num; -mod fmod; -mod frexp; -mod frexpf; -mod hypot; -mod hypotf; -mod ilogb; -mod ilogbf; -mod j0; -mod j0f; -mod j1; -mod j1f; -mod jn; -mod jnf; -mod ldexp; -mod lgamma; -mod lgamma_r; -mod lgammaf; -mod lgammaf_r; -mod log; -mod log10; -mod log10f; -mod log1p; -mod log1pf; -mod log2; -mod log2f; -mod logf; -mod modf; -mod modff; -mod nextafter; -mod nextafterf; -mod pow; -mod powf; -mod remainder; -mod remainderf; -mod remquo; -mod remquof; -mod rint; -mod round; -mod roundeven; -mod scalbn; -mod sin; -mod sincos; -mod sincosf; -mod sinf; -mod sinh; -mod sinhf; -mod sqrt; -mod tan; -mod tanf; -mod tanh; -mod tanhf; -mod tgamma; -mod tgammaf; -mod trunc; - -// Use separated imports instead of {}-grouped imports for easier merging. -pub use self::acos::acos; -pub use self::acosf::acosf; -pub use self::acosh::acosh; -pub use self::acoshf::acoshf; -pub use self::asin::asin; -pub use self::asinf::asinf; -pub use self::asinh::asinh; -pub use self::asinhf::asinhf; -pub use self::atan::atan; -pub use self::atan2::atan2; -pub use self::atan2f::atan2f; -pub use self::atanf::atanf; -pub use self::atanh::atanh; -pub use self::atanhf::atanhf; -pub use self::cbrt::cbrt; -pub use self::cbrtf::cbrtf; -pub use self::ceil::{ceil, ceilf}; -pub use self::copysign::{copysign, copysignf}; -pub use self::cos::cos; -pub use self::cosf::cosf; -pub use self::cosh::cosh; -pub use self::coshf::coshf; -pub use self::erf::{erf, erfc}; -pub use self::erff::{erfcf, erff}; -pub use self::exp::exp; -pub use self::exp2::exp2; -pub use self::exp2f::exp2f; -pub use self::exp10::exp10; -pub use self::exp10f::exp10f; -pub use self::expf::expf; -pub use self::expm1::expm1; -pub use self::expm1f::expm1f; -pub use self::fabs::{fabs, fabsf}; -pub use self::fdim::{fdim, fdimf}; -pub use self::floor::{floor, floorf}; -pub use self::fma::fma; -pub use self::fma_wide::fmaf; -pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; -pub use self::fminimum_fmaximum::{fmaximum, fmaximumf, fminimum, fminimumf}; -pub use self::fminimum_fmaximum_num::{fmaximum_num, fmaximum_numf, fminimum_num, fminimum_numf}; -pub use self::fmod::{fmod, fmodf}; -pub use self::frexp::frexp; -pub use self::frexpf::frexpf; -pub use self::hypot::hypot; -pub use self::hypotf::hypotf; -pub use self::ilogb::ilogb; -pub use self::ilogbf::ilogbf; -pub use self::j0::{j0, y0}; -pub use self::j0f::{j0f, y0f}; -pub use self::j1::{j1, y1}; -pub use self::j1f::{j1f, y1f}; -pub use self::jn::{jn, yn}; -pub use self::jnf::{jnf, ynf}; -pub use self::ldexp::{ldexp, ldexpf}; -pub use self::lgamma::lgamma; -pub use self::lgamma_r::lgamma_r; -pub use self::lgammaf::lgammaf; -pub use self::lgammaf_r::lgammaf_r; -pub use self::log::log; -pub use self::log1p::log1p; -pub use self::log1pf::log1pf; -pub use self::log2::log2; -pub use self::log2f::log2f; -pub use self::log10::log10; -pub use self::log10f::log10f; -pub use self::logf::logf; -pub use self::modf::modf; -pub use self::modff::modff; -pub use self::nextafter::nextafter; -pub use self::nextafterf::nextafterf; -pub use self::pow::pow; -pub use self::powf::powf; -pub use self::remainder::remainder; -pub use self::remainderf::remainderf; -pub use self::remquo::remquo; -pub use self::remquof::remquof; -pub use self::rint::{rint, rintf}; -pub use self::round::{round, roundf}; -pub use self::roundeven::{roundeven, roundevenf}; -pub use self::scalbn::{scalbn, scalbnf}; -pub use self::sin::sin; -pub use self::sincos::sincos; -pub use self::sincosf::sincosf; -pub use self::sinf::sinf; -pub use self::sinh::sinh; -pub use self::sinhf::sinhf; -pub use self::sqrt::{sqrt, sqrtf}; -pub use self::tan::tan; -pub use self::tanf::tanf; -pub use self::tanh::tanh; -pub use self::tanhf::tanhf; -pub use self::tgamma::tgamma; -pub use self::tgammaf::tgammaf; -pub use self::trunc::{trunc, truncf}; - -cfg_if! { - if #[cfg(f16_enabled)] { - // verify-sorted-start - pub use self::ceil::ceilf16; - pub use self::copysign::copysignf16; - pub use self::fabs::fabsf16; - pub use self::fdim::fdimf16; - pub use self::floor::floorf16; - pub use self::fmin_fmax::{fmaxf16, fminf16}; - pub use self::fminimum_fmaximum::{fmaximumf16, fminimumf16}; - pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16}; - pub use self::fmod::fmodf16; - pub use self::ldexp::ldexpf16; - pub use self::rint::rintf16; - pub use self::round::roundf16; - pub use self::roundeven::roundevenf16; - pub use self::scalbn::scalbnf16; - pub use self::sqrt::sqrtf16; - pub use self::trunc::truncf16; - // verify-sorted-end - - #[allow(unused_imports)] - pub(crate) use self::fma_wide::fmaf16; - } -} - -cfg_if! { - if #[cfg(f128_enabled)] { - // verify-sorted-start - pub use self::ceil::ceilf128; - pub use self::copysign::copysignf128; - pub use self::fabs::fabsf128; - pub use self::fdim::fdimf128; - pub use self::floor::floorf128; - pub use self::fma::fmaf128; - pub use self::fmin_fmax::{fmaxf128, fminf128}; - pub use self::fminimum_fmaximum::{fmaximumf128, fminimumf128}; - pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; - pub use self::fmod::fmodf128; - pub use self::ldexp::ldexpf128; - pub use self::rint::rintf128; - pub use self::round::roundf128; - pub use self::roundeven::roundevenf128; - pub use self::scalbn::scalbnf128; - pub use self::sqrt::sqrtf128; - pub use self::trunc::truncf128; - // verify-sorted-end - } -} - -#[inline] -fn get_high_word(x: f64) -> u32 { - (x.to_bits() >> 32) as u32 -} - -#[inline] -fn get_low_word(x: f64) -> u32 { - x.to_bits() as u32 -} - -#[inline] -fn with_set_high_word(f: f64, hi: u32) -> f64 { - let mut tmp = f.to_bits(); - tmp &= 0x00000000_ffffffff; - tmp |= (hi as u64) << 32; - f64::from_bits(tmp) -} - -#[inline] -fn with_set_low_word(f: f64, lo: u32) -> f64 { - let mut tmp = f.to_bits(); - tmp &= 0xffffffff_00000000; - tmp |= lo as u64; - f64::from_bits(tmp) -} - -#[inline] -fn combine_words(hi: u32, lo: u32) -> f64 { - f64::from_bits(((hi as u64) << 32) | lo as u64) -} diff --git a/library/compiler-builtins/libm/libm/src/math/modf.rs b/library/compiler-builtins/libm/libm/src/math/modf.rs deleted file mode 100644 index 6541862cdd9..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/modf.rs +++ /dev/null @@ -1,35 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn modf(x: f64) -> (f64, f64) { - let rv2: f64; - let mut u = x.to_bits(); - let mask: u64; - let e = (((u >> 52) & 0x7ff) as i32) - 0x3ff; - - /* no fractional part */ - if e >= 52 { - rv2 = x; - if e == 0x400 && (u << 12) != 0 { - /* nan */ - return (x, rv2); - } - u &= 1 << 63; - return (f64::from_bits(u), rv2); - } - - /* no integral part*/ - if e < 0 { - u &= 1 << 63; - rv2 = f64::from_bits(u); - return (x, rv2); - } - - mask = ((!0) >> 12) >> e; - if (u & mask) == 0 { - rv2 = x; - u &= 1 << 63; - return (f64::from_bits(u), rv2); - } - u &= !mask; - rv2 = f64::from_bits(u); - return (x - rv2, rv2); -} diff --git a/library/compiler-builtins/libm/libm/src/math/modff.rs b/library/compiler-builtins/libm/libm/src/math/modff.rs deleted file mode 100644 index 90c6bca7d8d..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/modff.rs +++ /dev/null @@ -1,34 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn modff(x: f32) -> (f32, f32) { - let rv2: f32; - let mut u: u32 = x.to_bits(); - let mask: u32; - let e = (((u >> 23) & 0xff) as i32) - 0x7f; - - /* no fractional part */ - if e >= 23 { - rv2 = x; - if e == 0x80 && (u << 9) != 0 { - /* nan */ - return (x, rv2); - } - u &= 0x80000000; - return (f32::from_bits(u), rv2); - } - /* no integral part */ - if e < 0 { - u &= 0x80000000; - rv2 = f32::from_bits(u); - return (x, rv2); - } - - mask = 0x007fffff >> e; - if (u & mask) == 0 { - rv2 = x; - u &= 0x80000000; - return (f32::from_bits(u), rv2); - } - u &= !mask; - rv2 = f32::from_bits(u); - return (x - rv2, rv2); -} diff --git a/library/compiler-builtins/libm/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/libm/src/math/nextafter.rs deleted file mode 100644 index c991ff6f233..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/nextafter.rs +++ /dev/null @@ -1,37 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn nextafter(x: f64, y: f64) -> f64 { - if x.is_nan() || y.is_nan() { - return x + y; - } - - let mut ux_i = x.to_bits(); - let uy_i = y.to_bits(); - if ux_i == uy_i { - return y; - } - - let ax = ux_i & (!1_u64 / 2); - let ay = uy_i & (!1_u64 / 2); - if ax == 0 { - if ay == 0 { - return y; - } - ux_i = (uy_i & (1_u64 << 63)) | 1; - } else if ax > ay || ((ux_i ^ uy_i) & (1_u64 << 63)) != 0 { - ux_i -= 1; - } else { - ux_i += 1; - } - - let e = (ux_i >> 52) & 0x7ff; - // raise overflow if ux.f is infinite and x is finite - if e == 0x7ff { - force_eval!(x + x); - } - let ux_f = f64::from_bits(ux_i); - // raise underflow if ux.f is subnormal or zero - if e == 0 { - force_eval!(x * x + ux_f * ux_f); - } - ux_f -} diff --git a/library/compiler-builtins/libm/libm/src/math/nextafterf.rs b/library/compiler-builtins/libm/libm/src/math/nextafterf.rs deleted file mode 100644 index 8ba3833562f..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/nextafterf.rs +++ /dev/null @@ -1,37 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn nextafterf(x: f32, y: f32) -> f32 { - if x.is_nan() || y.is_nan() { - return x + y; - } - - let mut ux_i = x.to_bits(); - let uy_i = y.to_bits(); - if ux_i == uy_i { - return y; - } - - let ax = ux_i & 0x7fff_ffff_u32; - let ay = uy_i & 0x7fff_ffff_u32; - if ax == 0 { - if ay == 0 { - return y; - } - ux_i = (uy_i & 0x8000_0000_u32) | 1; - } else if ax > ay || ((ux_i ^ uy_i) & 0x8000_0000_u32) != 0 { - ux_i -= 1; - } else { - ux_i += 1; - } - - let e = ux_i & 0x7f80_0000_u32; - // raise overflow if ux_f is infinite and x is finite - if e == 0x7f80_0000_u32 { - force_eval!(x + x); - } - let ux_f = f32::from_bits(ux_i); - // raise underflow if ux_f is subnormal or zero - if e == 0 { - force_eval!(x * x + ux_f * ux_f); - } - ux_f -} diff --git a/library/compiler-builtins/libm/libm/src/math/pow.rs b/library/compiler-builtins/libm/libm/src/math/pow.rs deleted file mode 100644 index 80b2a24999c..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/pow.rs +++ /dev/null @@ -1,607 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ -/* - * ==================================================== - * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. - * - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -// pow(x,y) return x**y -// -// n -// Method: Let x = 2 * (1+f) -// 1. Compute and return log2(x) in two pieces: -// log2(x) = w1 + w2, -// where w1 has 53-24 = 29 bit trailing zeros. -// 2. Perform y*log2(x) = n+y' by simulating multi-precision -// arithmetic, where |y'|<=0.5. -// 3. Return x**y = 2**n*exp(y'*log2) -// -// Special cases: -// 1. (anything) ** 0 is 1 -// 2. 1 ** (anything) is 1 -// 3. (anything except 1) ** NAN is NAN -// 4. NAN ** (anything except 0) is NAN -// 5. +-(|x| > 1) ** +INF is +INF -// 6. +-(|x| > 1) ** -INF is +0 -// 7. +-(|x| < 1) ** +INF is +0 -// 8. +-(|x| < 1) ** -INF is +INF -// 9. -1 ** +-INF is 1 -// 10. +0 ** (+anything except 0, NAN) is +0 -// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 -// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero -// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero -// 14. -0 ** (+odd integer) is -0 -// 15. -0 ** (-odd integer) is -INF, raise divbyzero -// 16. +INF ** (+anything except 0,NAN) is +INF -// 17. +INF ** (-anything except 0,NAN) is +0 -// 18. -INF ** (+odd integer) is -INF -// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) -// 20. (anything) ** 1 is (anything) -// 21. (anything) ** -1 is 1/(anything) -// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) -// 23. (-anything except 0 and inf) ** (non-integer) is NAN -// -// Accuracy: -// pow(x,y) returns x**y nearly rounded. In particular -// pow(integer,integer) -// always returns the correct integer provided it is -// representable. -// -// Constants : -// The hexadecimal values are the intended ones for the following -// constants. The decimal values may be used, provided that the -// compiler will convert from decimal to binary accurately enough -// to produce the hexadecimal values shown. -// -use super::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; - -const BP: [f64; 2] = [1.0, 1.5]; -const DP_H: [f64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ -const DP_L: [f64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ -const TWO53: f64 = 9007199254740992.0; /* 0x43400000_00000000 */ -const HUGE: f64 = 1.0e300; -const TINY: f64 = 1.0e-300; - -// poly coefs for (3/2)*(log(x)-2s-2/3*s**3: -const L1: f64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ -const L2: f64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ -const L3: f64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ -const L4: f64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ -const L5: f64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ -const L6: f64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ -const P1: f64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ -const P2: f64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ -const P3: f64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ -const P4: f64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ -const P5: f64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ -const LG2: f64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ -const LG2_H: f64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ -const LG2_L: f64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ -const OVT: f64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ -const CP: f64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ -const CP_H: f64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ -const CP_L: f64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ -const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ -const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ -const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ - -/// Returns `x` to the power of `y` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn pow(x: f64, y: f64) -> f64 { - let t1: f64; - let t2: f64; - - let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); - let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); - - let mut ix: i32 = hx & 0x7fffffff_i32; - let iy: i32 = hy & 0x7fffffff_i32; - - /* x**0 = 1, even if x is NaN */ - if ((iy as u32) | ly) == 0 { - return 1.0; - } - - /* 1**y = 1, even if y is NaN */ - if hx == 0x3ff00000 && lx == 0 { - return 1.0; - } - - /* NaN if either arg is NaN */ - if ix > 0x7ff00000 - || (ix == 0x7ff00000 && lx != 0) - || iy > 0x7ff00000 - || (iy == 0x7ff00000 && ly != 0) - { - return x + y; - } - - /* determine if y is an odd int when x < 0 - * yisint = 0 ... y is not an integer - * yisint = 1 ... y is an odd int - * yisint = 2 ... y is an even int - */ - let mut yisint: i32 = 0; - let mut k: i32; - let mut j: i32; - if hx < 0 { - if iy >= 0x43400000 { - yisint = 2; /* even integer y */ - } else if iy >= 0x3ff00000 { - k = (iy >> 20) - 0x3ff; /* exponent */ - - if k > 20 { - j = (ly >> (52 - k)) as i32; - - if (j << (52 - k)) == (ly as i32) { - yisint = 2 - (j & 1); - } - } else if ly == 0 { - j = iy >> (20 - k); - - if (j << (20 - k)) == iy { - yisint = 2 - (j & 1); - } - } - } - } - - if ly == 0 { - /* special value of y */ - if iy == 0x7ff00000 { - /* y is +-inf */ - - return if ((ix - 0x3ff00000) | (lx as i32)) == 0 { - /* (-1)**+-inf is 1 */ - 1.0 - } else if ix >= 0x3ff00000 { - /* (|x|>1)**+-inf = inf,0 */ - if hy >= 0 { y } else { 0.0 } - } else { - /* (|x|<1)**+-inf = 0,inf */ - if hy >= 0 { 0.0 } else { -y } - }; - } - - if iy == 0x3ff00000 { - /* y is +-1 */ - return if hy >= 0 { x } else { 1.0 / x }; - } - - if hy == 0x40000000 { - /* y is 2 */ - return x * x; - } - - if hy == 0x3fe00000 { - /* y is 0.5 */ - if hx >= 0 { - /* x >= +0 */ - return sqrt(x); - } - } - } - - let mut ax: f64 = fabs(x); - if lx == 0 { - /* special value of x */ - if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { - /* x is +-0,+-inf,+-1 */ - let mut z: f64 = ax; - - if hy < 0 { - /* z = (1/|x|) */ - z = 1.0 / z; - } - - if hx < 0 { - if ((ix - 0x3ff00000) | yisint) == 0 { - z = (z - z) / (z - z); /* (-1)**non-int is NaN */ - } else if yisint == 1 { - z = -z; /* (x<0)**odd = -(|x|**odd) */ - } - } - - return z; - } - } - - let mut s: f64 = 1.0; /* sign of result */ - if hx < 0 { - if yisint == 0 { - /* (x<0)**(non-int) is NaN */ - return (x - x) / (x - x); - } - - if yisint == 1 { - /* (x<0)**(odd int) */ - s = -1.0; - } - } - - /* |y| is HUGE */ - if iy > 0x41e00000 { - /* if |y| > 2**31 */ - if iy > 0x43f00000 { - /* if |y| > 2**64, must o/uflow */ - if ix <= 0x3fefffff { - return if hy < 0 { HUGE * HUGE } else { TINY * TINY }; - } - - if ix >= 0x3ff00000 { - return if hy > 0 { HUGE * HUGE } else { TINY * TINY }; - } - } - - /* over/underflow if x is not close to one */ - if ix < 0x3fefffff { - return if hy < 0 { s * HUGE * HUGE } else { s * TINY * TINY }; - } - if ix > 0x3ff00000 { - return if hy > 0 { s * HUGE * HUGE } else { s * TINY * TINY }; - } - - /* now |1-x| is TINY <= 2**-20, suffice to compute - log(x) by x-x^2/2+x^3/3-x^4/4 */ - let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ - let w: f64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); - let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ - let v: f64 = t * IVLN2_L - w * IVLN2; - t1 = with_set_low_word(u + v, 0); - t2 = v - (t1 - u); - } else { - // double ss,s2,s_h,s_l,t_h,t_l; - let mut n: i32 = 0; - - if ix < 0x00100000 { - /* take care subnormal number */ - ax *= TWO53; - n -= 53; - ix = get_high_word(ax) as i32; - } - - n += (ix >> 20) - 0x3ff; - j = ix & 0x000fffff; - - /* determine interval */ - let k: i32; - ix = j | 0x3ff00000; /* normalize ix */ - if j <= 0x3988E { - /* |x|> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18), - ); - let t_l: f64 = ax - (t_h - i!(BP, k as usize)); - let s_l: f64 = v * ((u - s_h * t_h) - s_h * t_l); - - /* compute log(ax) */ - let s2: f64 = ss * ss; - let mut r: f64 = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); - r += s_l * (s_h + ss); - let s2: f64 = s_h * s_h; - let t_h: f64 = with_set_low_word(3.0 + s2 + r, 0); - let t_l: f64 = r - ((t_h - 3.0) - s2); - - /* u+v = ss*(1+...) */ - let u: f64 = s_h * t_h; - let v: f64 = s_l * t_h + t_l * ss; - - /* 2/(3log2)*(ss+...) */ - let p_h: f64 = with_set_low_word(u + v, 0); - let p_l = v - (p_h - u); - let z_h: f64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ - let z_l: f64 = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); - - /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ - let t: f64 = n as f64; - t1 = with_set_low_word(((z_h + z_l) + i!(DP_H, k as usize)) + t, 0); - t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); - } - - /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ - let y1: f64 = with_set_low_word(y, 0); - let p_l: f64 = (y - y1) * t1 + y * t2; - let mut p_h: f64 = y1 * t1; - let z: f64 = p_l + p_h; - let mut j: i32 = (z.to_bits() >> 32) as i32; - let i: i32 = z.to_bits() as i32; - // let (j, i): (i32, i32) = ((z.to_bits() >> 32) as i32, z.to_bits() as i32); - - if j >= 0x40900000 { - /* z >= 1024 */ - if (j - 0x40900000) | i != 0 { - /* if z > 1024 */ - return s * HUGE * HUGE; /* overflow */ - } - - if p_l + OVT > z - p_h { - return s * HUGE * HUGE; /* overflow */ - } - } else if (j & 0x7fffffff) >= 0x4090cc00 { - /* z <= -1075 */ - // FIXME: instead of abs(j) use unsigned j - - if (((j as u32) - 0xc090cc00) | (i as u32)) != 0 { - /* z < -1075 */ - return s * TINY * TINY; /* underflow */ - } - - if p_l <= z - p_h { - return s * TINY * TINY; /* underflow */ - } - } - - /* compute 2**(p_h+p_l) */ - let i: i32 = j & 0x7fffffff_i32; - k = (i >> 20) - 0x3ff; - let mut n: i32 = 0; - - if i > 0x3fe00000 { - /* if |z| > 0.5, set n = [z+0.5] */ - n = j + (0x00100000 >> (k + 1)); - k = ((n & 0x7fffffff) >> 20) - 0x3ff; /* new k for n */ - let t: f64 = with_set_high_word(0.0, (n & !(0x000fffff >> k)) as u32); - n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); - if j < 0 { - n = -n; - } - p_h -= t; - } - - let t: f64 = with_set_low_word(p_l + p_h, 0); - let u: f64 = t * LG2_H; - let v: f64 = (p_l - (t - p_h)) * LG2 + t * LG2_L; - let mut z: f64 = u + v; - let w: f64 = v - (z - u); - let t: f64 = z * z; - let t1: f64 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); - let r: f64 = (z * t1) / (t1 - 2.0) - (w + z * w); - z = 1.0 - (r - z); - j = get_high_word(z) as i32; - j += n << 20; - - if (j >> 20) <= 0 { - /* subnormal output */ - z = scalbn(z, n); - } else { - z = with_set_high_word(z, j as u32); - } - - s * z -} - -#[cfg(test)] -mod tests { - extern crate core; - - use self::core::f64::consts::{E, PI}; - use super::pow; - - const POS_ZERO: &[f64] = &[0.0]; - const NEG_ZERO: &[f64] = &[-0.0]; - const POS_ONE: &[f64] = &[1.0]; - const NEG_ONE: &[f64] = &[-1.0]; - const POS_FLOATS: &[f64] = &[99.0 / 70.0, E, PI]; - const NEG_FLOATS: &[f64] = &[-99.0 / 70.0, -E, -PI]; - const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), f64::MIN_POSITIVE, f64::EPSILON]; - const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -f64::MIN_POSITIVE, -f64::EPSILON]; - const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, f64::MAX]; - const NEG_EVENS: &[f64] = &[f64::MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; - const POS_ODDS: &[f64] = &[3.0, 7.0]; - const NEG_ODDS: &[f64] = &[-7.0, -3.0]; - const NANS: &[f64] = &[f64::NAN]; - const POS_INF: &[f64] = &[f64::INFINITY]; - const NEG_INF: &[f64] = &[f64::NEG_INFINITY]; - - const ALL: &[&[f64]] = &[ - POS_ZERO, - NEG_ZERO, - NANS, - NEG_SMALL_FLOATS, - POS_SMALL_FLOATS, - NEG_FLOATS, - POS_FLOATS, - NEG_EVENS, - POS_EVENS, - NEG_ODDS, - POS_ODDS, - NEG_INF, - POS_INF, - NEG_ONE, - POS_ONE, - ]; - const POS: &[&[f64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF]; - const NEG: &[&[f64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF]; - - fn pow_test(base: f64, exponent: f64, expected: f64) { - let res = pow(base, exponent); - assert!( - if expected.is_nan() { res.is_nan() } else { pow(base, exponent) == expected }, - "{} ** {} was {} instead of {}", - base, - exponent, - res, - expected - ); - } - - fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { - sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); - } - - fn test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) { - sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); - } - - fn test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) { - sets.iter().for_each(|s| { - s.iter().for_each(|val| { - let exp = expected(*val); - let res = computed(*val); - - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let exp = force_eval!(exp); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let res = force_eval!(res); - assert!( - if exp.is_nan() { res.is_nan() } else { exp == res }, - "test for {} was {} instead of {}", - val, - res, - exp - ); - }) - }); - } - - #[test] - fn zero_as_exponent() { - test_sets_as_base(ALL, 0.0, 1.0); - test_sets_as_base(ALL, -0.0, 1.0); - } - - #[test] - fn one_as_base() { - test_sets_as_exponent(1.0, ALL, 1.0); - } - - #[test] - fn nan_inputs() { - // NAN as the base: - // (f64::NAN ^ anything *but 0* should be f64::NAN) - test_sets_as_exponent(f64::NAN, &ALL[2..], f64::NAN); - - // f64::NAN as the exponent: - // (anything *but 1* ^ f64::NAN should be f64::NAN) - test_sets_as_base(&ALL[..(ALL.len() - 2)], f64::NAN, f64::NAN); - } - - #[test] - fn infinity_as_base() { - // Positive Infinity as the base: - // (+Infinity ^ positive anything but 0 and f64::NAN should be +Infinity) - test_sets_as_exponent(f64::INFINITY, &POS[1..], f64::INFINITY); - - // (+Infinity ^ negative anything except 0 and f64::NAN should be 0.0) - test_sets_as_exponent(f64::INFINITY, &NEG[1..], 0.0); - - // Negative Infinity as the base: - // (-Infinity ^ positive odd ints should be -Infinity) - test_sets_as_exponent(f64::NEG_INFINITY, &[POS_ODDS], f64::NEG_INFINITY); - - // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) - // We can lump in pos/neg odd ints here because they don't seem to - // cause panics (div by zero) in release mode (I think). - test_sets(ALL, &|v: f64| pow(f64::NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); - } - - #[test] - fn infinity_as_exponent() { - // Positive/Negative base greater than 1: - // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes f64::NAN as the base) - test_sets_as_base(&ALL[5..(ALL.len() - 2)], f64::INFINITY, f64::INFINITY); - - // (pos/neg > 1 ^ -Infinity should be 0.0) - test_sets_as_base(&ALL[5..ALL.len() - 2], f64::NEG_INFINITY, 0.0); - - // Positive/Negative base less than 1: - let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS]; - - // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes f64::NAN as the base) - test_sets_as_base(base_below_one, f64::INFINITY, 0.0); - - // (pos/neg < 1 ^ -Infinity should be Infinity) - test_sets_as_base(base_below_one, f64::NEG_INFINITY, f64::INFINITY); - - // Positive/Negative 1 as the base: - // (pos/neg 1 ^ Infinity should be 1) - test_sets_as_base(&[NEG_ONE, POS_ONE], f64::INFINITY, 1.0); - - // (pos/neg 1 ^ -Infinity should be 1) - test_sets_as_base(&[NEG_ONE, POS_ONE], f64::NEG_INFINITY, 1.0); - } - - #[test] - fn zero_as_base() { - // Positive Zero as the base: - // (+0 ^ anything positive but 0 and f64::NAN should be +0) - test_sets_as_exponent(0.0, &POS[1..], 0.0); - - // (+0 ^ anything negative but 0 and f64::NAN should be Infinity) - // (this should panic because we're dividing by zero) - test_sets_as_exponent(0.0, &NEG[1..], f64::INFINITY); - - // Negative Zero as the base: - // (-0 ^ anything positive but 0, f64::NAN, and odd ints should be +0) - test_sets_as_exponent(-0.0, &POS[3..], 0.0); - - // (-0 ^ anything negative but 0, f64::NAN, and odd ints should be Infinity) - // (should panic because of divide by zero) - test_sets_as_exponent(-0.0, &NEG[3..], f64::INFINITY); - - // (-0 ^ positive odd ints should be -0) - test_sets_as_exponent(-0.0, &[POS_ODDS], -0.0); - - // (-0 ^ negative odd ints should be -Infinity) - // (should panic because of divide by zero) - test_sets_as_exponent(-0.0, &[NEG_ODDS], f64::NEG_INFINITY); - } - - #[test] - fn special_cases() { - // One as the exponent: - // (anything ^ 1 should be anything - i.e. the base) - test_sets(ALL, &|v: f64| pow(v, 1.0), &|v: f64| v); - - // Negative One as the exponent: - // (anything ^ -1 should be 1/anything) - test_sets(ALL, &|v: f64| pow(v, -1.0), &|v: f64| 1.0 / v); - - // Factoring -1 out: - // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| { - int_set.iter().for_each(|int| { - test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| pow(-1.0, *int) * pow(v, *int)); - }) - }); - - // Negative base (imaginary results): - // (-anything except 0 and Infinity ^ non-integer should be NAN) - NEG[1..(NEG.len() - 1)].iter().for_each(|set| { - set.iter().for_each(|val| { - test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| f64::NAN); - }) - }); - } - - #[test] - fn normal_cases() { - assert_eq!(pow(2.0, 20.0), (1 << 20) as f64); - assert_eq!(pow(-1.0, 9.0), -1.0); - assert!(pow(-1.0, 2.2).is_nan()); - assert!(pow(-1.0, -1.14).is_nan()); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/powf.rs b/library/compiler-builtins/libm/libm/src/math/powf.rs deleted file mode 100644 index 839c6c23d43..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/powf.rs +++ /dev/null @@ -1,335 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::cmp::Ordering; - -use super::{fabsf, scalbnf, sqrtf}; - -const BP: [f32; 2] = [1.0, 1.5]; -const DP_H: [f32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ -const DP_L: [f32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ -const TWO24: f32 = 16777216.0; /* 0x4b800000 */ -const HUGE: f32 = 1.0e30; -const TINY: f32 = 1.0e-30; -const L1: f32 = 6.0000002384e-01; /* 0x3f19999a */ -const L2: f32 = 4.2857143283e-01; /* 0x3edb6db7 */ -const L3: f32 = 3.3333334327e-01; /* 0x3eaaaaab */ -const L4: f32 = 2.7272811532e-01; /* 0x3e8ba305 */ -const L5: f32 = 2.3066075146e-01; /* 0x3e6c3255 */ -const L6: f32 = 2.0697501302e-01; /* 0x3e53f142 */ -const P1: f32 = 1.6666667163e-01; /* 0x3e2aaaab */ -const P2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ -const P3: f32 = 6.6137559770e-05; /* 0x388ab355 */ -const P4: f32 = -1.6533901999e-06; /* 0xb5ddea0e */ -const P5: f32 = 4.1381369442e-08; /* 0x3331bb4c */ -const LG2: f32 = 6.9314718246e-01; /* 0x3f317218 */ -const LG2_H: f32 = 6.93145752e-01; /* 0x3f317200 */ -const LG2_L: f32 = 1.42860654e-06; /* 0x35bfbe8c */ -const OVT: f32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ -const CP: f32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ -const CP_H: f32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ -const CP_L: f32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ -const IVLN2: f32 = 1.4426950216e+00; -const IVLN2_H: f32 = 1.4426879883e+00; -const IVLN2_L: f32 = 7.0526075433e-06; - -/// Returns `x` to the power of `y` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn powf(x: f32, y: f32) -> f32 { - let mut z: f32; - let mut ax: f32; - let z_h: f32; - let z_l: f32; - let mut p_h: f32; - let mut p_l: f32; - let y1: f32; - let mut t1: f32; - let t2: f32; - let mut r: f32; - let s: f32; - let mut sn: f32; - let mut t: f32; - let mut u: f32; - let mut v: f32; - let mut w: f32; - let i: i32; - let mut j: i32; - let mut k: i32; - let mut yisint: i32; - let mut n: i32; - let hx: i32; - let hy: i32; - let mut ix: i32; - let iy: i32; - let mut is: i32; - - hx = x.to_bits() as i32; - hy = y.to_bits() as i32; - - ix = hx & 0x7fffffff; - iy = hy & 0x7fffffff; - - /* x**0 = 1, even if x is NaN */ - if iy == 0 { - return 1.0; - } - - /* 1**y = 1, even if y is NaN */ - if hx == 0x3f800000 { - return 1.0; - } - - /* NaN if either arg is NaN */ - if ix > 0x7f800000 || iy > 0x7f800000 { - return x + y; - } - - /* determine if y is an odd int when x < 0 - * yisint = 0 ... y is not an integer - * yisint = 1 ... y is an odd int - * yisint = 2 ... y is an even int - */ - yisint = 0; - if hx < 0 { - if iy >= 0x4b800000 { - yisint = 2; /* even integer y */ - } else if iy >= 0x3f800000 { - k = (iy >> 23) - 0x7f; /* exponent */ - j = iy >> (23 - k); - if (j << (23 - k)) == iy { - yisint = 2 - (j & 1); - } - } - } - - /* special value of y */ - if iy == 0x7f800000 { - /* y is +-inf */ - match ix.cmp(&0x3f800000) { - /* (-1)**+-inf is 1 */ - Ordering::Equal => return 1.0, - /* (|x|>1)**+-inf = inf,0 */ - Ordering::Greater => return if hy >= 0 { y } else { 0.0 }, - /* (|x|<1)**+-inf = 0,inf */ - Ordering::Less => return if hy >= 0 { 0.0 } else { -y }, - } - } - if iy == 0x3f800000 { - /* y is +-1 */ - return if hy >= 0 { x } else { 1.0 / x }; - } - - if hy == 0x40000000 { - /* y is 2 */ - return x * x; - } - - if hy == 0x3f000000 - /* y is 0.5 */ - && hx >= 0 - { - /* x >= +0 */ - return sqrtf(x); - } - - ax = fabsf(x); - /* special value of x */ - if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 { - /* x is +-0,+-inf,+-1 */ - z = ax; - if hy < 0 { - /* z = (1/|x|) */ - z = 1.0 / z; - } - - if hx < 0 { - if ((ix - 0x3f800000) | yisint) == 0 { - z = (z - z) / (z - z); /* (-1)**non-int is NaN */ - } else if yisint == 1 { - z = -z; /* (x<0)**odd = -(|x|**odd) */ - } - } - return z; - } - - sn = 1.0; /* sign of result */ - if hx < 0 { - if yisint == 0 { - /* (x<0)**(non-int) is NaN */ - return (x - x) / (x - x); - } - - if yisint == 1 { - /* (x<0)**(odd int) */ - sn = -1.0; - } - } - - /* |y| is HUGE */ - if iy > 0x4d000000 { - /* if |y| > 2**27 */ - /* over/underflow if x is not close to one */ - if ix < 0x3f7ffff8 { - return if hy < 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; - } - - if ix > 0x3f800007 { - return if hy > 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; - } - - /* now |1-x| is TINY <= 2**-20, suffice to compute - log(x) by x-x^2/2+x^3/3-x^4/4 */ - t = ax - 1.; /* t has 20 trailing zeros */ - w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); - u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ - v = t * IVLN2_L - w * IVLN2; - t1 = u + v; - is = t1.to_bits() as i32; - t1 = f32::from_bits(is as u32 & 0xfffff000); - t2 = v - (t1 - u); - } else { - let mut s2: f32; - let mut s_h: f32; - let s_l: f32; - let mut t_h: f32; - let mut t_l: f32; - - n = 0; - /* take care subnormal number */ - if ix < 0x00800000 { - ax *= TWO24; - n -= 24; - ix = ax.to_bits() as i32; - } - n += ((ix) >> 23) - 0x7f; - j = ix & 0x007fffff; - /* determine interval */ - ix = j | 0x3f800000; /* normalize ix */ - if j <= 0x1cc471 { - /* |x|> 1) & 0xfffff000) | 0x20000000) as i32; - t_h = f32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); - t_l = ax - (t_h - i!(BP, k as usize)); - s_l = v * ((u - s_h * t_h) - s_h * t_l); - /* compute log(ax) */ - s2 = s * s; - r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); - r += s_l * (s_h + s); - s2 = s_h * s_h; - t_h = 3.0 + s2 + r; - is = t_h.to_bits() as i32; - t_h = f32::from_bits(is as u32 & 0xfffff000); - t_l = r - ((t_h - 3.0) - s2); - /* u+v = s*(1+...) */ - u = s_h * t_h; - v = s_l * t_h + t_l * s; - /* 2/(3log2)*(s+...) */ - p_h = u + v; - is = p_h.to_bits() as i32; - p_h = f32::from_bits(is as u32 & 0xfffff000); - p_l = v - (p_h - u); - z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ - z_l = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); - /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ - t = n as f32; - t1 = ((z_h + z_l) + i!(DP_H, k as usize)) + t; - is = t1.to_bits() as i32; - t1 = f32::from_bits(is as u32 & 0xfffff000); - t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); - }; - - /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ - is = y.to_bits() as i32; - y1 = f32::from_bits(is as u32 & 0xfffff000); - p_l = (y - y1) * t1 + y * t2; - p_h = y1 * t1; - z = p_l + p_h; - j = z.to_bits() as i32; - if j > 0x43000000 { - /* if z > 128 */ - return sn * HUGE * HUGE; /* overflow */ - } else if j == 0x43000000 { - /* if z == 128 */ - if p_l + OVT > z - p_h { - return sn * HUGE * HUGE; /* overflow */ - } - } else if (j & 0x7fffffff) > 0x43160000 { - /* z < -150 */ - // FIXME: check should be (uint32_t)j > 0xc3160000 - return sn * TINY * TINY; /* underflow */ - } else if j as u32 == 0xc3160000 - /* z == -150 */ - && p_l <= z - p_h - { - return sn * TINY * TINY; /* underflow */ - } - - /* - * compute 2**(p_h+p_l) - */ - i = j & 0x7fffffff; - k = (i >> 23) - 0x7f; - n = 0; - if i > 0x3f000000 { - /* if |z| > 0.5, set n = [z+0.5] */ - n = j + (0x00800000 >> (k + 1)); - k = ((n & 0x7fffffff) >> 23) - 0x7f; /* new k for n */ - t = f32::from_bits(n as u32 & !(0x007fffff >> k)); - n = ((n & 0x007fffff) | 0x00800000) >> (23 - k); - if j < 0 { - n = -n; - } - p_h -= t; - } - t = p_l + p_h; - is = t.to_bits() as i32; - t = f32::from_bits(is as u32 & 0xffff8000); - u = t * LG2_H; - v = (p_l - (t - p_h)) * LG2 + t * LG2_L; - z = u + v; - w = v - (z - u); - t = z * z; - t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); - r = (z * t1) / (t1 - 2.0) - (w + z * w); - z = 1.0 - (r - z); - j = z.to_bits() as i32; - j += n << 23; - if (j >> 23) <= 0 { - /* subnormal output */ - z = scalbnf(z, n); - } else { - z = f32::from_bits(j as u32); - } - sn * z -} diff --git a/library/compiler-builtins/libm/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/libm/src/math/rem_pio2.rs deleted file mode 100644 index 917e90819a5..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/rem_pio2.rs +++ /dev/null @@ -1,223 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunPro, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== -// -// Optimized by Bruce D. Evans. */ -use super::rem_pio2_large; - -// #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 -// #define EPS DBL_EPSILON -const EPS: f64 = 2.2204460492503131e-16; -// #elif FLT_EVAL_METHOD==2 -// #define EPS LDBL_EPSILON -// #endif - -// TODO: Support FLT_EVAL_METHOD? - -const TO_INT: f64 = 1.5 / EPS; -/// 53 bits of 2/pi -const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ -/// first 33 bits of pi/2 -const PIO2_1: f64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ -/// pi/2 - PIO2_1 -const PIO2_1T: f64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ -/// second 33 bits of pi/2 -const PIO2_2: f64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ -/// pi/2 - (PIO2_1+PIO2_2) -const PIO2_2T: f64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ -/// third 33 bits of pi/2 -const PIO2_3: f64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ -/// pi/2 - (PIO2_1+PIO2_2+PIO2_3) -const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ - -// return the remainder of x rem pi/2 in y[0]+y[1] -// use rem_pio2_large() for large x -// -// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { - let x1p24 = f64::from_bits(0x4170000000000000); - - let sign = (f64::to_bits(x) >> 63) as i32; - let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; - - fn medium(x: f64, ix: u32) -> (i32, f64, f64) { - /* rint(x/(pi/2)), Assume round-to-nearest. */ - let tmp = x * INV_PIO2 + TO_INT; - // force rounding of tmp to it's storage format on x87 to avoid - // excess precision issues. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let tmp = force_eval!(tmp); - let f_n = tmp - TO_INT; - let n = f_n as i32; - let mut r = x - f_n * PIO2_1; - let mut w = f_n * PIO2_1T; /* 1st round, good to 85 bits */ - let mut y0 = r - w; - let ui = f64::to_bits(y0); - let ey = (ui >> 52) as i32 & 0x7ff; - let ex = (ix >> 20) as i32; - if ex - ey > 16 { - /* 2nd round, good to 118 bits */ - let t = r; - w = f_n * PIO2_2; - r = t - w; - w = f_n * PIO2_2T - ((t - r) - w); - y0 = r - w; - let ey = (f64::to_bits(y0) >> 52) as i32 & 0x7ff; - if ex - ey > 49 { - /* 3rd round, good to 151 bits, covers all cases */ - let t = r; - w = f_n * PIO2_3; - r = t - w; - w = f_n * PIO2_3T - ((t - r) - w); - y0 = r - w; - } - } - let y1 = (r - y0) - w; - (n, y0, y1) - } - - if ix <= 0x400f6a7a { - /* |x| ~<= 5pi/4 */ - if (ix & 0xfffff) == 0x921fb { - /* |x| ~= pi/2 or 2pi/2 */ - return medium(x, ix); /* cancellation -- use medium case */ - } - if ix <= 0x4002d97c { - /* |x| ~<= 3pi/4 */ - if sign == 0 { - let z = x - PIO2_1; /* one round good to 85 bits */ - let y0 = z - PIO2_1T; - let y1 = (z - y0) - PIO2_1T; - return (1, y0, y1); - } else { - let z = x + PIO2_1; - let y0 = z + PIO2_1T; - let y1 = (z - y0) + PIO2_1T; - return (-1, y0, y1); - } - } else if sign == 0 { - let z = x - 2.0 * PIO2_1; - let y0 = z - 2.0 * PIO2_1T; - let y1 = (z - y0) - 2.0 * PIO2_1T; - return (2, y0, y1); - } else { - let z = x + 2.0 * PIO2_1; - let y0 = z + 2.0 * PIO2_1T; - let y1 = (z - y0) + 2.0 * PIO2_1T; - return (-2, y0, y1); - } - } - if ix <= 0x401c463b { - /* |x| ~<= 9pi/4 */ - if ix <= 0x4015fdbc { - /* |x| ~<= 7pi/4 */ - if ix == 0x4012d97c { - /* |x| ~= 3pi/2 */ - return medium(x, ix); - } - if sign == 0 { - let z = x - 3.0 * PIO2_1; - let y0 = z - 3.0 * PIO2_1T; - let y1 = (z - y0) - 3.0 * PIO2_1T; - return (3, y0, y1); - } else { - let z = x + 3.0 * PIO2_1; - let y0 = z + 3.0 * PIO2_1T; - let y1 = (z - y0) + 3.0 * PIO2_1T; - return (-3, y0, y1); - } - } else { - if ix == 0x401921fb { - /* |x| ~= 4pi/2 */ - return medium(x, ix); - } - if sign == 0 { - let z = x - 4.0 * PIO2_1; - let y0 = z - 4.0 * PIO2_1T; - let y1 = (z - y0) - 4.0 * PIO2_1T; - return (4, y0, y1); - } else { - let z = x + 4.0 * PIO2_1; - let y0 = z + 4.0 * PIO2_1T; - let y1 = (z - y0) + 4.0 * PIO2_1T; - return (-4, y0, y1); - } - } - } - if ix < 0x413921fb { - /* |x| ~< 2^20*(pi/2), medium size */ - return medium(x, ix); - } - /* - * all other (large) arguments - */ - if ix >= 0x7ff00000 { - /* x is inf or NaN */ - let y0 = x - x; - let y1 = y0; - return (0, y0, y1); - } - /* set z = scalbn(|x|,-ilogb(x)+23) */ - let mut ui = f64::to_bits(x); - ui &= (!1) >> 12; - ui |= (0x3ff + 23) << 52; - let mut z = f64::from_bits(ui); - let mut tx = [0.0; 3]; - for i in 0..2 { - i!(tx,i, =, z as i32 as f64); - z = (z - i!(tx, i)) * x1p24; - } - i!(tx,2, =, z); - /* skip zero terms, first term is non-zero */ - let mut i = 2; - while i != 0 && i!(tx, i) == 0.0 { - i -= 1; - } - let mut ty = [0.0; 3]; - let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix as i32) >> 20) - (0x3ff + 23), 1); - if sign != 0 { - return (-n, -i!(ty, 0), -i!(ty, 1)); - } - (n, i!(ty, 0), i!(ty, 1)) -} - -#[cfg(test)] -mod tests { - use super::rem_pio2; - - #[test] - // FIXME(correctness): inaccurate results on i586 - #[cfg_attr(all(target_arch = "x86", not(target_feature = "sse")), ignore)] - fn test_near_pi() { - let arg = 3.141592025756836; - let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, -6.278329573009626e-7, -2.1125998133974653e-23)); - let arg = 3.141592033207416; - let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, -6.20382377148128e-7, -2.1125998133974653e-23)); - let arg = 3.141592144966125; - let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, -5.086236681942706e-7, -2.1125998133974653e-23)); - let arg = 3.141592979431152; - let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, 3.2584135866119817e-7, -2.1125998133974653e-23)); - } - - #[test] - fn test_overflow_b9b847() { - let _ = rem_pio2(-3054214.5490637687); - } - - #[test] - fn test_overflow_4747b9() { - let _ = rem_pio2(917340800458.2274); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/libm/src/math/rem_pio2_large.rs deleted file mode 100644 index 6d679bbe98c..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/rem_pio2_large.rs +++ /dev/null @@ -1,468 +0,0 @@ -#![allow(unused_unsafe)] -/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{floor, scalbn}; - -// initial value for jk -const INIT_JK: [usize; 4] = [3, 4, 4, 6]; - -// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi -// -// integer array, contains the (24*i)-th to (24*i+23)-th -// bit of 2/pi after binary point. The corresponding -// floating value is -// -// ipio2[i] * 2^(-24(i+1)). -// -// NB: This table must have at least (e0-3)/24 + jk terms. -// For quad precision (e0 <= 16360, jk = 6), this is 686. -#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] -const IPIO2: [i32; 66] = [ - 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, - 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, - 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, - 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, - 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, - 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, - 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, - 0x73A8C9, 0x60E27B, 0xC08C6B, -]; - -#[cfg(target_pointer_width = "64")] -const IPIO2: [i32; 690] = [ - 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, - 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, - 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, - 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, - 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, - 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, - 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, - 0x73A8C9, 0x60E27B, 0xC08C6B, 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, - 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, 0xDE4F98, 0x327DBB, 0xC33D26, - 0xEF6B1E, 0x5EF89F, 0x3A1F35, 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, - 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, 0x467D86, 0x2D71E3, 0x9AC69B, - 0x006233, 0x7CD2B4, 0x97A7B4, 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, - 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, 0xCB2324, 0x778AD6, 0x23545A, - 0xB91F00, 0x1B0AF1, 0xDFCE19, 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, - 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, 0xDE3B58, 0x929BDE, 0x2822D2, - 0xE88628, 0x4D58E2, 0x32CAC6, 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, - 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, 0xD36710, 0xD8DDAA, 0x425FAE, - 0xCE616A, 0xA4280A, 0xB499D3, 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, - 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, 0x36D9CA, 0xD2A828, 0x8D61C2, - 0x77C912, 0x142604, 0x9B4612, 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, - 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, 0xC3E7B3, 0x28F8C7, 0x940593, - 0x3E71C1, 0xB3092E, 0xF3450B, 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, - 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, 0x9794E8, 0x84E6E2, 0x973199, - 0x6BED88, 0x365F5F, 0x0EFDBB, 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, - 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, 0x90AA47, 0x02E774, 0x24D6BD, - 0xA67DF7, 0x72486E, 0xEF169F, 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, - 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, 0x10D86D, 0x324832, 0x754C5B, - 0xD4714E, 0x6E5445, 0xC1090B, 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, - 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, 0x6AE290, 0x89D988, 0x50722C, - 0xBEA404, 0x940777, 0x7030F3, 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, - 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, 0x3BDF08, 0x2B3715, 0xA0805C, - 0x93805A, 0x921110, 0xD8E80F, 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, - 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, 0xAA140A, 0x2F2689, 0x768364, - 0x333B09, 0x1A940E, 0xAA3A51, 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, - 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, 0x5BC3D8, 0xC492F5, 0x4BADC6, - 0xA5CA4E, 0xCD37A7, 0x36A9E6, 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, - 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, 0x306529, 0xBF5657, 0x3AFF47, - 0xB9F96A, 0xF3BE75, 0xDF9328, 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, - 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, 0xA8654F, 0xA5C1D2, 0x0F3F0B, - 0xCD785B, 0x76F923, 0x048B7B, 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, - 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, 0xDA4886, 0xA05DF7, 0xF480C6, - 0x2FF0AC, 0x9AECDD, 0xBC5C3F, 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, - 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, 0x2A1216, 0x2DB7DC, 0xFDE5FA, - 0xFEDB89, 0xFDBE89, 0x6C76E4, 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, - 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, 0x48D784, 0x16DF30, 0x432DC7, - 0x356125, 0xCE70C9, 0xB8CB30, 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, - 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, 0xC4F133, 0x5F6E13, 0xE4305D, - 0xA92E85, 0xC3B21D, 0x3632A1, 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, - 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, 0xCBDA11, 0xD0BE7D, 0xC1DB9B, - 0xBD17AB, 0x81A2CA, 0x5C6A08, 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, - 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, 0x4F6A68, 0xA82A4A, 0x5AC44F, - 0xBCF82D, 0x985AD7, 0x95C7F4, 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, - 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, 0xD0C0B2, 0x485551, 0x0EFB1E, - 0xC37295, 0x3B06A3, 0x3540C0, 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, - 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, 0x3C3ABA, 0x461846, 0x5F7555, - 0xF5BDD2, 0xC6926E, 0x5D2EAC, 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, - 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, 0x745D7C, 0xB2AD6B, 0x9D6ECD, - 0x7B723E, 0x6A11C6, 0xA9CFF7, 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, - 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, 0xBEFDFD, 0xEF4556, 0x367ED9, - 0x13D9EC, 0xB9BA8B, 0xFC97C4, 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, - 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, 0x9C2A3E, 0xCC5F11, 0x4A0BFD, - 0xFBF4E1, 0x6D3B8E, 0x2C86E2, 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, - 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, 0xCC2254, 0xDC552A, 0xD6C6C0, - 0x96190B, 0xB8701A, 0x649569, 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, - 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, 0x9B5861, 0xBC57E1, 0xC68351, - 0x103ED8, 0x4871DD, 0xDD1C2D, 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, - 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, 0x382682, 0x9BE7CA, 0xA40D51, - 0xB13399, 0x0ED7A9, 0x480569, 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, - 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, 0x5FD45E, 0xA4677B, 0x7AACBA, - 0xA2F655, 0x23882B, 0x55BA41, 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, - 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, 0xAE5ADB, 0x86C547, 0x624385, - 0x3B8621, 0x94792C, 0x876110, 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, - 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, 0xB1933D, 0x0B7CBD, 0xDC51A4, - 0x63DD27, 0xDDE169, 0x19949A, 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, - 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, 0x4D7E6F, 0x5119A5, 0xABF9B5, - 0xD6DF82, 0x61DD96, 0x023616, 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, - 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, -]; - -const PIO2: [f64; 8] = [ - 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ - 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ - 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ - 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ - 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ - 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ - 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ - 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ -]; - -// fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 -// -// Input parameters: -// x[] The input value (must be positive) is broken into nx -// pieces of 24-bit integers in double precision format. -// x[i] will be the i-th 24 bit of x. The scaled exponent -// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 -// match x's up to 24 bits. -// -// Example of breaking a double positive z into x[0]+x[1]+x[2]: -// e0 = ilogb(z)-23 -// z = scalbn(z,-e0) -// for i = 0,1,2 -// x[i] = floor(z) -// z = (z-x[i])*2**24 -// -// y[] ouput result in an array of double precision numbers. -// The dimension of y[] is: -// 24-bit precision 1 -// 53-bit precision 2 -// 64-bit precision 2 -// 113-bit precision 3 -// The actual value is the sum of them. Thus for 113-bit -// precison, one may have to do something like: -// -// long double t,w,r_head, r_tail; -// t = (long double)y[2] + (long double)y[1]; -// w = (long double)y[0]; -// r_head = t+w; -// r_tail = w - (r_head - t); -// -// e0 The exponent of x[0]. Must be <= 16360 or you need to -// expand the ipio2 table. -// -// prec an integer indicating the precision: -// 0 24 bits (single) -// 1 53 bits (double) -// 2 64 bits (extended) -// 3 113 bits (quad) -// -// Here is the description of some local variables: -// -// jk jk+1 is the initial number of terms of ipio2[] needed -// in the computation. The minimum and recommended value -// for jk is 3,4,4,6 for single, double, extended, and quad. -// jk+1 must be 2 larger than you might expect so that our -// recomputation test works. (Up to 24 bits in the integer -// part (the 24 bits of it that we compute) and 23 bits in -// the fraction part may be lost to cancelation before we -// recompute.) -// -// jz local integer variable indicating the number of -// terms of ipio2[] used. -// -// jx nx - 1 -// -// jv index for pointing to the suitable ipio2[] for the -// computation. In general, we want -// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 -// is an integer. Thus -// e0-3-24*jv >= 0 or (e0-3)/24 >= jv -// Hence jv = max(0,(e0-3)/24). -// -// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. -// -// q[] double array with integral value, representing the -// 24-bits chunk of the product of x and 2/pi. -// -// q0 the corresponding exponent of q[0]. Note that the -// exponent for q[i] would be q0-24*i. -// -// PIo2[] double precision array, obtained by cutting pi/2 -// into 24 bits chunks. -// -// f[] ipio2[] in floating point -// -// iq[] integer array by breaking up q[] in 24-bits chunk. -// -// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] -// -// ih integer. If >0 it indicates q[] is >= 0.5, hence -// it also indicates the *sign* of the result. - -/// Return the last three digits of N with y = x - N*pi/2 -/// so that |y| < pi/2. -/// -/// The method is to compute the integer (mod 8) and fraction parts of -/// (2/pi)*x without doing the full multiplication. In general we -/// skip the part of the product that are known to be a huge integer ( -/// more accurately, = 0 mod 8 ). Thus the number of operations are -/// independent of the exponent of the input. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { - let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 - let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) - - if cfg!(target_pointer_width = "64") { - debug_assert!(e0 <= 16360); - } - - let nx = x.len(); - - let mut fw: f64; - let mut n: i32; - let mut ih: i32; - let mut z: f64; - let mut f: [f64; 20] = [0.; 20]; - let mut fq: [f64; 20] = [0.; 20]; - let mut q: [f64; 20] = [0.; 20]; - let mut iq: [i32; 20] = [0; 20]; - - /* initialize jk*/ - let jk = i!(INIT_JK, prec); - let jp = jk; - - /* determine jx,jv,q0, note that 3>q0 */ - let jx = nx - 1; - let mut jv = div!(e0 - 3, 24); - if jv < 0 { - jv = 0; - } - let mut q0 = e0 - 24 * (jv + 1); - let jv = jv as usize; - - /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ - let mut j = (jv as i32) - (jx as i32); - let m = jx + jk; - for i in 0..=m { - i!(f, i, =, if j < 0 { - 0. - } else { - i!(IPIO2, j as usize) as f64 - }); - j += 1; - } - - /* compute q[0],q[1],...q[jk] */ - for i in 0..=jk { - fw = 0f64; - for j in 0..=jx { - fw += i!(x, j) * i!(f, jx + i - j); - } - i!(q, i, =, fw); - } - - let mut jz = jk; - - 'recompute: loop { - /* distill q[] into iq[] reversingly */ - let mut i = 0i32; - z = i!(q, jz); - for j in (1..=jz).rev() { - fw = (x1p_24 * z) as i32 as f64; - i!(iq, i as usize, =, (z - x1p24 * fw) as i32); - z = i!(q, j - 1) + fw; - i += 1; - } - - /* compute n */ - z = scalbn(z, q0); /* actual value of z */ - z -= 8.0 * floor(z * 0.125); /* trim off integer >= 8 */ - n = z as i32; - z -= n as f64; - ih = 0; - if q0 > 0 { - /* need iq[jz-1] to determine n */ - i = i!(iq, jz - 1) >> (24 - q0); - n += i; - i!(iq, jz - 1, -=, i << (24 - q0)); - ih = i!(iq, jz - 1) >> (23 - q0); - } else if q0 == 0 { - ih = i!(iq, jz - 1) >> 23; - } else if z >= 0.5 { - ih = 2; - } - - if ih > 0 { - /* q > 0.5 */ - n += 1; - let mut carry = 0i32; - for i in 0..jz { - /* compute 1-q */ - let j = i!(iq, i); - if carry == 0 { - if j != 0 { - carry = 1; - i!(iq, i, =, 0x1000000 - j); - } - } else { - i!(iq, i, =, 0xffffff - j); - } - } - if q0 > 0 { - /* rare case: chance is 1 in 12 */ - match q0 { - 1 => { - i!(iq, jz - 1, &=, 0x7fffff); - } - 2 => { - i!(iq, jz - 1, &=, 0x3fffff); - } - _ => {} - } - } - if ih == 2 { - z = 1. - z; - if carry != 0 { - z -= scalbn(1., q0); - } - } - } - - /* check if recomputation is needed */ - if z == 0. { - let mut j = 0; - for i in (jk..=jz - 1).rev() { - j |= i!(iq, i); - } - if j == 0 { - /* need recomputation */ - let mut k = 1; - while i!(iq, jk - k, ==, 0) { - k += 1; /* k = no. of terms needed */ - } - - for i in (jz + 1)..=(jz + k) { - /* add q[jz+1] to q[jz+k] */ - i!(f, jx + i, =, i!(IPIO2, jv + i) as f64); - fw = 0f64; - for j in 0..=jx { - fw += i!(x, j) * i!(f, jx + i - j); - } - i!(q, i, =, fw); - } - jz += k; - continue 'recompute; - } - } - - break; - } - - /* chop off zero terms */ - if z == 0. { - jz -= 1; - q0 -= 24; - while i!(iq, jz) == 0 { - jz -= 1; - q0 -= 24; - } - } else { - /* break z into 24-bit if necessary */ - z = scalbn(z, -q0); - if z >= x1p24 { - fw = (x1p_24 * z) as i32 as f64; - i!(iq, jz, =, (z - x1p24 * fw) as i32); - jz += 1; - q0 += 24; - i!(iq, jz, =, fw as i32); - } else { - i!(iq, jz, =, z as i32); - } - } - - /* convert integer "bit" chunk to floating-point value */ - fw = scalbn(1., q0); - for i in (0..=jz).rev() { - i!(q, i, =, fw * (i!(iq, i) as f64)); - fw *= x1p_24; - } - - /* compute PIo2[0,...,jp]*q[jz,...,0] */ - for i in (0..=jz).rev() { - fw = 0f64; - let mut k = 0; - while (k <= jp) && (k <= jz - i) { - fw += i!(PIO2, k) * i!(q, i + k); - k += 1; - } - i!(fq, jz - i, =, fw); - } - - /* compress fq[] into y[] */ - match prec { - 0 => { - fw = 0f64; - for i in (0..=jz).rev() { - fw += i!(fq, i); - } - i!(y, 0, =, if ih == 0 { fw } else { -fw }); - } - 1 | 2 => { - fw = 0f64; - for i in (0..=jz).rev() { - fw += i!(fq, i); - } - i!(y, 0, =, if ih == 0 { fw } else { -fw }); - fw = i!(fq, 0) - fw; - for i in 1..=jz { - fw += i!(fq, i); - } - i!(y, 1, =, if ih == 0 { fw } else { -fw }); - } - 3 => { - /* painful */ - for i in (1..=jz).rev() { - fw = i!(fq, i - 1) + i!(fq, i); - i!(fq, i, +=, i!(fq, i - 1) - fw); - i!(fq, i - 1, =, fw); - } - for i in (2..=jz).rev() { - fw = i!(fq, i - 1) + i!(fq, i); - i!(fq, i, +=, i!(fq, i - 1) - fw); - i!(fq, i - 1, =, fw); - } - fw = 0f64; - for i in (2..=jz).rev() { - fw += i!(fq, i); - } - if ih == 0 { - i!(y, 0, =, i!(fq, 0)); - i!(y, 1, =, i!(fq, 1)); - i!(y, 2, =, fw); - } else { - i!(y, 0, =, -i!(fq, 0)); - i!(y, 1, =, -i!(fq, 1)); - i!(y, 2, =, -fw); - } - } - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => {} - } - n & 7 -} diff --git a/library/compiler-builtins/libm/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/libm/src/math/rem_pio2f.rs deleted file mode 100644 index 3c658fe3dbc..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/rem_pio2f.rs +++ /dev/null @@ -1,67 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Debugged and optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::f64; - -use super::rem_pio2_large; - -const TOINT: f64 = 1.5 / f64::EPSILON; - -/// 53 bits of 2/pi -const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ -/// first 25 bits of pi/2 -const PIO2_1: f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ -/// pi/2 - pio2_1 -const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ - -/// Return the remainder of x rem pi/2 in *y -/// -/// use double precision for everything except passing x -/// use __rem_pio2_large() for large x -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { - let x64 = x as f64; - - let mut tx: [f64; 1] = [0.]; - let mut ty: [f64; 1] = [0.]; - - let ix = x.to_bits() & 0x7fffffff; - /* 25+53 bit pi is good enough for medium size */ - if ix < 0x4dc90fdb { - /* |x| ~< 2^28*(pi/2), medium size */ - /* Use a specialized rint() to get fn. Assume round-to-nearest. */ - let tmp = x64 * INV_PIO2 + TOINT; - // force rounding of tmp to it's storage format on x87 to avoid - // excess precision issues. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let tmp = force_eval!(tmp); - let f_n = tmp - TOINT; - return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); - } - if ix >= 0x7f800000 { - /* x is inf or NaN */ - return (0, x64 - x64); - } - /* scale x into [2^23, 2^24-1] */ - let sign = (x.to_bits() >> 31) != 0; - let e0 = ((ix >> 23) - (0x7f + 23)) as i32; /* e0 = ilogb(|x|)-23, positive */ - tx[0] = f32::from_bits(ix - (e0 << 23) as u32) as f64; - let n = rem_pio2_large(&tx, &mut ty, e0, 0); - if sign { - return (-n, -ty[0]); - } - (n, ty[0]) -} diff --git a/library/compiler-builtins/libm/libm/src/math/remainder.rs b/library/compiler-builtins/libm/libm/src/math/remainder.rs deleted file mode 100644 index 9e966c9ed7f..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/remainder.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remainder(x: f64, y: f64) -> f64 { - let (result, _) = super::remquo(x, y); - result -} diff --git a/library/compiler-builtins/libm/libm/src/math/remainderf.rs b/library/compiler-builtins/libm/libm/src/math/remainderf.rs deleted file mode 100644 index b1407cf2ace..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/remainderf.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remainderf(x: f32, y: f32) -> f32 { - let (result, _) = super::remquof(x, y); - result -} diff --git a/library/compiler-builtins/libm/libm/src/math/remquo.rs b/library/compiler-builtins/libm/libm/src/math/remquo.rs deleted file mode 100644 index 4c11e848746..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/remquo.rs +++ /dev/null @@ -1,106 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { - let ux: u64 = x.to_bits(); - let mut uy: u64 = y.to_bits(); - let mut ex = ((ux >> 52) & 0x7ff) as i32; - let mut ey = ((uy >> 52) & 0x7ff) as i32; - let sx = (ux >> 63) != 0; - let sy = (uy >> 63) != 0; - let mut q: u32; - let mut i: u64; - let mut uxi: u64 = ux; - - if (uy << 1) == 0 || y.is_nan() || ex == 0x7ff { - return ((x * y) / (x * y), 0); - } - if (ux << 1) == 0 { - return (x, 0); - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 12; - while (i >> 63) == 0 { - ex -= 1; - i <<= 1; - } - uxi <<= -ex + 1; - } else { - uxi &= (!0) >> 12; - uxi |= 1 << 52; - } - if ey == 0 { - i = uy << 12; - while (i >> 63) == 0 { - ey -= 1; - i <<= 1; - } - uy <<= -ey + 1; - } else { - uy &= (!0) >> 12; - uy |= 1 << 52; - } - - q = 0; - - if ex + 1 != ey { - if ex < ey { - return (x, 0); - } - /* x mod y */ - while ex > ey { - i = uxi.wrapping_sub(uy); - if (i >> 63) == 0 { - uxi = i; - q += 1; - } - uxi <<= 1; - q <<= 1; - ex -= 1; - } - i = uxi.wrapping_sub(uy); - if (i >> 63) == 0 { - uxi = i; - q += 1; - } - if uxi == 0 { - ex = -60; - } else { - while (uxi >> 52) == 0 { - uxi <<= 1; - ex -= 1; - } - } - } - - /* scale result and decide between |x| and |x|-|y| */ - if ex > 0 { - uxi -= 1 << 52; - uxi |= (ex as u64) << 52; - } else { - uxi >>= -ex + 1; - } - x = f64::from_bits(uxi); - if sy { - y = -y; - } - if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { - x -= y; - // TODO: this matches musl behavior, but it is incorrect - q = q.wrapping_add(1); - } - q &= 0x7fffffff; - let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; - if sx { (-x, quo) } else { (x, quo) } -} - -#[cfg(test)] -mod tests { - use super::remquo; - - #[test] - fn test_q_overflow() { - // 0xc000000000000001, 0x04c0000000000004 - let _ = remquo(-2.0000000000000004, 8.406091369059082e-286); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/remquof.rs b/library/compiler-builtins/libm/libm/src/math/remquof.rs deleted file mode 100644 index b0e85ca6611..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/remquof.rs +++ /dev/null @@ -1,93 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { - let ux: u32 = x.to_bits(); - let mut uy: u32 = y.to_bits(); - let mut ex = ((ux >> 23) & 0xff) as i32; - let mut ey = ((uy >> 23) & 0xff) as i32; - let sx = (ux >> 31) != 0; - let sy = (uy >> 31) != 0; - let mut q: u32; - let mut i: u32; - let mut uxi: u32 = ux; - - if (uy << 1) == 0 || y.is_nan() || ex == 0xff { - return ((x * y) / (x * y), 0); - } - if (ux << 1) == 0 { - return (x, 0); - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 9; - while (i >> 31) == 0 { - ex -= 1; - i <<= 1; - } - uxi <<= -ex + 1; - } else { - uxi &= (!0) >> 9; - uxi |= 1 << 23; - } - if ey == 0 { - i = uy << 9; - while (i >> 31) == 0 { - ey -= 1; - i <<= 1; - } - uy <<= -ey + 1; - } else { - uy &= (!0) >> 9; - uy |= 1 << 23; - } - - q = 0; - if ex + 1 != ey { - if ex < ey { - return (x, 0); - } - /* x mod y */ - while ex > ey { - i = uxi.wrapping_sub(uy); - if (i >> 31) == 0 { - uxi = i; - q += 1; - } - uxi <<= 1; - q <<= 1; - ex -= 1; - } - i = uxi.wrapping_sub(uy); - if (i >> 31) == 0 { - uxi = i; - q += 1; - } - if uxi == 0 { - ex = -30; - } else { - while (uxi >> 23) == 0 { - uxi <<= 1; - ex -= 1; - } - } - } - - /* scale result and decide between |x| and |x|-|y| */ - if ex > 0 { - uxi -= 1 << 23; - uxi |= (ex as u32) << 23; - } else { - uxi >>= -ex + 1; - } - x = f32::from_bits(uxi); - if sy { - y = -y; - } - if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { - x -= y; - q += 1; - } - q &= 0x7fffffff; - let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; - if sx { (-x, quo) } else { (x, quo) } -} diff --git a/library/compiler-builtins/libm/libm/src/math/rint.rs b/library/compiler-builtins/libm/libm/src/math/rint.rs deleted file mode 100644 index e1c32c94355..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/rint.rs +++ /dev/null @@ -1,51 +0,0 @@ -use super::support::Round; - -/// Round `x` to the nearest integer, breaking ties toward even. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rintf16(x: f16) -> f16 { - select_implementation! { - name: rintf16, - use_arch: all(target_arch = "aarch64", target_feature = "fp16"), - args: x, - } - - super::generic::rint_round(x, Round::Nearest).val -} - -/// Round `x` to the nearest integer, breaking ties toward even. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rintf(x: f32) -> f32 { - select_implementation! { - name: rintf, - use_arch: any( - all(target_arch = "aarch64", target_feature = "neon"), - all(target_arch = "wasm32", intrinsics_enabled), - ), - args: x, - } - - super::generic::rint_round(x, Round::Nearest).val -} - -/// Round `x` to the nearest integer, breaking ties toward even. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rint(x: f64) -> f64 { - select_implementation! { - name: rint, - use_arch: any( - all(target_arch = "aarch64", target_feature = "neon"), - all(target_arch = "wasm32", intrinsics_enabled), - ), - args: x, - } - - super::generic::rint_round(x, Round::Nearest).val -} - -/// Round `x` to the nearest integer, breaking ties toward even. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rintf128(x: f128) -> f128 { - super::generic::rint_round(x, Round::Nearest).val -} diff --git a/library/compiler-builtins/libm/libm/src/math/round.rs b/library/compiler-builtins/libm/libm/src/math/round.rs deleted file mode 100644 index 6cd091cd73c..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/round.rs +++ /dev/null @@ -1,25 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf16(x: f16) -> f16 { - super::generic::round(x) -} - -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf(x: f32) -> f32 { - super::generic::round(x) -} - -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn round(x: f64) -> f64 { - super::generic::round(x) -} - -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf128(x: f128) -> f128 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/libm/src/math/roundeven.rs deleted file mode 100644 index 6e621d7628f..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/roundeven.rs +++ /dev/null @@ -1,36 +0,0 @@ -use super::support::{Float, Round}; - -/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 -/// `roundToIntegralTiesToEven`. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundevenf16(x: f16) -> f16 { - roundeven_impl(x) -} - -/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 -/// `roundToIntegralTiesToEven`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundevenf(x: f32) -> f32 { - roundeven_impl(x) -} - -/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 -/// `roundToIntegralTiesToEven`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundeven(x: f64) -> f64 { - roundeven_impl(x) -} - -/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 -/// `roundToIntegralTiesToEven`. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundevenf128(x: f128) -> f128 { - roundeven_impl(x) -} - -#[inline] -pub fn roundeven_impl(x: F) -> F { - super::generic::rint_round(x, Round::Nearest).val -} diff --git a/library/compiler-builtins/libm/libm/src/math/roundf.rs b/library/compiler-builtins/libm/libm/src/math/roundf.rs deleted file mode 100644 index b5d7c9d693e..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/roundf.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf(x: f32) -> f32 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/libm/src/math/roundf128.rs b/library/compiler-builtins/libm/libm/src/math/roundf128.rs deleted file mode 100644 index fc3164929fe..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/roundf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf128(x: f128) -> f128 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/libm/src/math/roundf16.rs b/library/compiler-builtins/libm/libm/src/math/roundf16.rs deleted file mode 100644 index 8b356eaabee..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/roundf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf16(x: f16) -> f16 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/libm/src/math/scalbn.rs deleted file mode 100644 index ed73c3f94f0..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/scalbn.rs +++ /dev/null @@ -1,87 +0,0 @@ -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf16(x: f16, n: i32) -> f16 { - super::generic::scalbn(x, n) -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf(x: f32, n: i32) -> f32 { - super::generic::scalbn(x, n) -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbn(x: f64, n: i32) -> f64 { - super::generic::scalbn(x, n) -} - -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf128(x: f128, n: i32) -> f128 { - super::generic::scalbn(x, n) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::{CastFrom, CastInto, Float}; - - // Tests against N3220 - fn spec_test(f: impl Fn(F, i32) -> F) - where - u32: CastInto, - F::Int: CastFrom, - F::Int: CastFrom, - { - // `scalbn(±0, n)` returns `±0`. - assert_biteq!(f(F::NEG_ZERO, 10), F::NEG_ZERO); - assert_biteq!(f(F::NEG_ZERO, 0), F::NEG_ZERO); - assert_biteq!(f(F::NEG_ZERO, -10), F::NEG_ZERO); - assert_biteq!(f(F::ZERO, 10), F::ZERO); - assert_biteq!(f(F::ZERO, 0), F::ZERO); - assert_biteq!(f(F::ZERO, -10), F::ZERO); - - // `scalbn(x, 0)` returns `x`. - assert_biteq!(f(F::MIN, 0), F::MIN); - assert_biteq!(f(F::MAX, 0), F::MAX); - assert_biteq!(f(F::INFINITY, 0), F::INFINITY); - assert_biteq!(f(F::NEG_INFINITY, 0), F::NEG_INFINITY); - assert_biteq!(f(F::ZERO, 0), F::ZERO); - assert_biteq!(f(F::NEG_ZERO, 0), F::NEG_ZERO); - - // `scalbn(±∞, n)` returns `±∞`. - assert_biteq!(f(F::INFINITY, 10), F::INFINITY); - assert_biteq!(f(F::INFINITY, -10), F::INFINITY); - assert_biteq!(f(F::NEG_INFINITY, 10), F::NEG_INFINITY); - assert_biteq!(f(F::NEG_INFINITY, -10), F::NEG_INFINITY); - - // NaN should remain NaNs. - assert!(f(F::NAN, 10).is_nan()); - assert!(f(F::NAN, 0).is_nan()); - assert!(f(F::NAN, -10).is_nan()); - assert!(f(-F::NAN, 10).is_nan()); - assert!(f(-F::NAN, 0).is_nan()); - assert!(f(-F::NAN, -10).is_nan()); - } - - #[test] - #[cfg(f16_enabled)] - fn spec_test_f16() { - spec_test::(scalbnf16); - } - - #[test] - fn spec_test_f32() { - spec_test::(scalbnf); - } - - #[test] - fn spec_test_f64() { - spec_test::(scalbn); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_test_f128() { - spec_test::(scalbnf128); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/libm/src/math/scalbnf.rs deleted file mode 100644 index 57e7ba76f60..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/scalbnf.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf(x: f32, n: i32) -> f32 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/libm/src/math/scalbnf128.rs b/library/compiler-builtins/libm/libm/src/math/scalbnf128.rs deleted file mode 100644 index c1d2b485585..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/scalbnf128.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf128(x: f128, n: i32) -> f128 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/libm/src/math/scalbnf16.rs b/library/compiler-builtins/libm/libm/src/math/scalbnf16.rs deleted file mode 100644 index 2209e1a1795..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/scalbnf16.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf16(x: f16, n: i32) -> f16 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/libm/src/math/sin.rs b/library/compiler-builtins/libm/libm/src/math/sin.rs deleted file mode 100644 index 229fa4bef08..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/sin.rs +++ /dev/null @@ -1,95 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunPro, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -use super::{k_cos, k_sin, rem_pio2}; - -// sin(x) -// Return sine function of x. -// -// kernel function: -// k_sin ... sine function on [-pi/4,pi/4] -// k_cos ... cose function on [-pi/4,pi/4] -// rem_pio2 ... argument reduction routine -// -// Method. -// Let S,C and T denote the sin, cos and tan respectively on -// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 -// in [-pi/4 , +pi/4], and let n = k mod 4. -// We have -// -// n sin(x) cos(x) tan(x) -// ---------------------------------------------------------- -// 0 S C T -// 1 C -S -1/T -// 2 -S -C T -// 3 -C S -1/T -// ---------------------------------------------------------- -// -// Special cases: -// Let trig be any of sin, cos, or tan. -// trig(+-INF) is NaN, with signals; -// trig(NaN) is that NaN; -// -// Accuracy: -// TRIG(x) returns trig(x) nearly rounded - -/// The sine of `x` (f64). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sin(x: f64) -> f64 { - let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 - - /* High word of x. */ - let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; - - /* |x| ~< pi/4 */ - if ix <= 0x3fe921fb { - if ix < 0x3e500000 { - /* |x| < 2**-26 */ - /* raise inexact if x != 0 and underflow if subnormal*/ - if ix < 0x00100000 { - force_eval!(x / x1p120); - } else { - force_eval!(x + x1p120); - } - return x; - } - return k_sin(x, 0.0, 0); - } - - /* sin(Inf or NaN) is NaN */ - if ix >= 0x7ff00000 { - return x - x; - } - - /* argument reduction needed */ - let (n, y0, y1) = rem_pio2(x); - match n & 3 { - 0 => k_sin(y0, y1, 1), - 1 => k_cos(y0, y1), - 2 => -k_sin(y0, y1, 1), - _ => -k_cos(y0, y1), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[cfg_attr(x86_no_sse, ignore = "FIXME(i586): possible incorrect rounding")] - fn test_near_pi() { - let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 - let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 - assert_eq!(sin(x), sx); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/sincos.rs b/library/compiler-builtins/libm/libm/src/math/sincos.rs deleted file mode 100644 index ebf482f2df3..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/sincos.rs +++ /dev/null @@ -1,137 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{get_high_word, k_cos, k_sin, rem_pio2}; - -/// Both the sine and cosine of `x` (f64). -/// -/// `x` is specified in radians and the return value is (sin(x), cos(x)). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sincos(x: f64) -> (f64, f64) { - let s: f64; - let c: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - - /* |x| ~< pi/4 */ - if ix <= 0x3fe921fb { - /* if |x| < 2**-27 * sqrt(2) */ - if ix < 0x3e46a09e { - /* raise inexact if x!=0 and underflow if subnormal */ - let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 - if ix < 0x00100000 { - force_eval!(x / x1p120); - } else { - force_eval!(x + x1p120); - } - return (x, 1.0); - } - return (k_sin(x, 0.0, 0), k_cos(x, 0.0)); - } - - /* sincos(Inf or NaN) is NaN */ - if ix >= 0x7ff00000 { - let rv = x - x; - return (rv, rv); - } - - /* argument reduction needed */ - let (n, y0, y1) = rem_pio2(x); - s = k_sin(y0, y1, 1); - c = k_cos(y0, y1); - match n & 3 { - 0 => (s, c), - 1 => (c, -s), - 2 => (-s, -c), - 3 => (-c, s), - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => (0.0, 1.0), - } -} - -// These tests are based on those from sincosf.rs -#[cfg(test)] -mod tests { - use super::sincos; - - const TOLERANCE: f64 = 1e-6; - - #[test] - fn with_pi() { - let (s, c) = sincos(core::f64::consts::PI); - assert!( - (s - 0.0).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - 0.0, - (s - 0.0).abs(), - TOLERANCE - ); - assert!( - (c + 1.0).abs() < TOLERANCE, - "|{} + {}| = {} >= {}", - c, - 1.0, - (s + 1.0).abs(), - TOLERANCE - ); - } - - #[test] - fn rotational_symmetry() { - use core::f64::consts::PI; - const N: usize = 24; - for n in 0..N { - let theta = 2. * PI * (n as f64) / (N as f64); - let (s, c) = sincos(theta); - let (s_plus, c_plus) = sincos(theta + 2. * PI); - let (s_minus, c_minus) = sincos(theta - 2. * PI); - - assert!( - (s - s_plus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - s_plus, - (s - s_plus).abs(), - TOLERANCE - ); - assert!( - (s - s_minus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - s_minus, - (s - s_minus).abs(), - TOLERANCE - ); - assert!( - (c - c_plus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - c, - c_plus, - (c - c_plus).abs(), - TOLERANCE - ); - assert!( - (c - c_minus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - c, - c_minus, - (c - c_minus).abs(), - TOLERANCE - ); - } - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/libm/src/math/sincosf.rs deleted file mode 100644 index f3360767683..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/sincosf.rs +++ /dev/null @@ -1,176 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use super::{k_cosf, k_sinf, rem_pio2f}; - -/* Small multiples of pi/2 rounded to double precision. */ -const PI_2: f64 = 0.5 * 3.1415926535897931160E+00; -const S1PIO2: f64 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ -const S2PIO2: f64 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ -const S3PIO2: f64 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const S4PIO2: f64 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ - -/// Both the sine and cosine of `x` (f32). -/// -/// `x` is specified in radians and the return value is (sin(x), cos(x)). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sincosf(x: f32) -> (f32, f32) { - let s: f32; - let c: f32; - let mut ix: u32; - let sign: bool; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - /* |x| ~<= pi/4 */ - if ix <= 0x3f490fda { - /* |x| < 2**-12 */ - if ix < 0x39800000 { - /* raise inexact if x!=0 and underflow if subnormal */ - - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120 == 2^120 - if ix < 0x00100000 { - force_eval!(x / x1p120); - } else { - force_eval!(x + x1p120); - } - return (x, 1.0); - } - return (k_sinf(x as f64), k_cosf(x as f64)); - } - - /* |x| ~<= 5*pi/4 */ - if ix <= 0x407b53d1 { - if ix <= 0x4016cbe3 { - /* |x| ~<= 3pi/4 */ - if sign { - s = -k_cosf(x as f64 + S1PIO2); - c = k_sinf(x as f64 + S1PIO2); - } else { - s = k_cosf(S1PIO2 - x as f64); - c = k_sinf(S1PIO2 - x as f64); - } - } - /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ - else if sign { - s = -k_sinf(x as f64 + S2PIO2); - c = -k_cosf(x as f64 + S2PIO2); - } else { - s = -k_sinf(x as f64 - S2PIO2); - c = -k_cosf(x as f64 - S2PIO2); - } - - return (s, c); - } - - /* |x| ~<= 9*pi/4 */ - if ix <= 0x40e231d5 { - if ix <= 0x40afeddf { - /* |x| ~<= 7*pi/4 */ - if sign { - s = k_cosf(x as f64 + S3PIO2); - c = -k_sinf(x as f64 + S3PIO2); - } else { - s = -k_cosf(x as f64 - S3PIO2); - c = k_sinf(x as f64 - S3PIO2); - } - } else if sign { - s = k_sinf(x as f64 + S4PIO2); - c = k_cosf(x as f64 + S4PIO2); - } else { - s = k_sinf(x as f64 - S4PIO2); - c = k_cosf(x as f64 - S4PIO2); - } - - return (s, c); - } - - /* sin(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - let rv = x - x; - return (rv, rv); - } - - /* general argument reduction needed */ - let (n, y) = rem_pio2f(x); - s = k_sinf(y); - c = k_cosf(y); - match n & 3 { - 0 => (s, c), - 1 => (c, -s), - 2 => (-s, -c), - 3 => (-c, s), - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => (0.0, 1.0), - } -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::sincosf; - - #[test] - fn rotational_symmetry() { - use core::f32::consts::PI; - const N: usize = 24; - for n in 0..N { - let theta = 2. * PI * (n as f32) / (N as f32); - let (s, c) = sincosf(theta); - let (s_plus, c_plus) = sincosf(theta + 2. * PI); - let (s_minus, c_minus) = sincosf(theta - 2. * PI); - - const TOLERANCE: f32 = 1e-6; - assert!( - (s - s_plus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - s_plus, - (s - s_plus).abs(), - TOLERANCE - ); - assert!( - (s - s_minus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - s_minus, - (s - s_minus).abs(), - TOLERANCE - ); - assert!( - (c - c_plus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - c, - c_plus, - (c - c_plus).abs(), - TOLERANCE - ); - assert!( - (c - c_minus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - c, - c_minus, - (c - c_minus).abs(), - TOLERANCE - ); - } - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/sinf.rs b/library/compiler-builtins/libm/libm/src/math/sinf.rs deleted file mode 100644 index b8fae2c9801..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/sinf.rs +++ /dev/null @@ -1,88 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::f64::consts::FRAC_PI_2; - -use super::{k_cosf, k_sinf, rem_pio2f}; - -/* Small multiples of pi/2 rounded to double precision. */ -const S1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ -const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ - -/// The sine of `x` (f32). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sinf(x: f32) -> f32 { - let x64 = x as f64; - - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - if ix <= 0x3f490fda { - /* |x| ~<= pi/4 */ - if ix < 0x39800000 { - /* |x| < 2**-12 */ - /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); - return x; - } - return k_sinf(x64); - } - if ix <= 0x407b53d1 { - /* |x| ~<= 5*pi/4 */ - if ix <= 0x4016cbe3 { - /* |x| ~<= 3pi/4 */ - if sign { - return -k_cosf(x64 + S1_PIO2); - } else { - return k_cosf(x64 - S1_PIO2); - } - } - return k_sinf(if sign { -(x64 + S2_PIO2) } else { -(x64 - S2_PIO2) }); - } - if ix <= 0x40e231d5 { - /* |x| ~<= 9*pi/4 */ - if ix <= 0x40afeddf { - /* |x| ~<= 7*pi/4 */ - if sign { - return k_cosf(x64 + S3_PIO2); - } else { - return -k_cosf(x64 - S3_PIO2); - } - } - return k_sinf(if sign { x64 + S4_PIO2 } else { x64 - S4_PIO2 }); - } - - /* sin(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - return x - x; - } - - /* general argument reduction needed */ - let (n, y) = rem_pio2f(x); - match n & 3 { - 0 => k_sinf(y), - 1 => k_cosf(y), - 2 => k_sinf(-y), - _ => -k_cosf(y), - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/sinh.rs b/library/compiler-builtins/libm/libm/src/math/sinh.rs deleted file mode 100644 index 79184198263..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/sinh.rs +++ /dev/null @@ -1,51 +0,0 @@ -use super::{expm1, expo2}; - -// sinh(x) = (exp(x) - 1/exp(x))/2 -// = (exp(x)-1 + (exp(x)-1)/exp(x))/2 -// = x + x^3/6 + o(x^5) -// - -/// The hyperbolic sine of `x` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sinh(x: f64) -> f64 { - // union {double f; uint64_t i;} u = {.f = x}; - // uint32_t w; - // double t, h, absx; - - let mut uf: f64 = x; - let mut ui: u64 = f64::to_bits(uf); - let w: u32; - let t: f64; - let mut h: f64; - let absx: f64; - - h = 0.5; - if ui >> 63 != 0 { - h = -h; - } - /* |x| */ - ui &= !1 / 2; - uf = f64::from_bits(ui); - absx = uf; - w = (ui >> 32) as u32; - - /* |x| < log(DBL_MAX) */ - if w < 0x40862e42 { - t = expm1(absx); - if w < 0x3ff00000 { - if w < 0x3ff00000 - (26 << 20) { - /* note: inexact and underflow are raised by expm1 */ - /* note: this branch avoids spurious underflow */ - return x; - } - return h * (2.0 * t - t * t / (t + 1.0)); - } - /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ - return h * (t + t / (t + 1.0)); - } - - /* |x| > log(DBL_MAX) or nan */ - /* note: the result is stored to handle overflow */ - t = 2.0 * h * expo2(absx); - t -} diff --git a/library/compiler-builtins/libm/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/libm/src/math/sinhf.rs deleted file mode 100644 index 44d2e3560d5..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/sinhf.rs +++ /dev/null @@ -1,30 +0,0 @@ -use super::{expm1f, k_expo2f}; - -/// The hyperbolic sine of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sinhf(x: f32) -> f32 { - let mut h = 0.5f32; - let mut ix = x.to_bits(); - if (ix >> 31) != 0 { - h = -h; - } - /* |x| */ - ix &= 0x7fffffff; - let absx = f32::from_bits(ix); - let w = ix; - - /* |x| < log(FLT_MAX) */ - if w < 0x42b17217 { - let t = expm1f(absx); - if w < 0x3f800000 { - if w < (0x3f800000 - (12 << 23)) { - return x; - } - return h * (2. * t - t * t / (t + 1.)); - } - return h * (t + t / (t + 1.)); - } - - /* |x| > logf(FLT_MAX) or nan */ - 2. * h * k_expo2f(absx) -} diff --git a/library/compiler-builtins/libm/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/libm/src/math/sqrt.rs deleted file mode 100644 index 76bc240cf01..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/sqrt.rs +++ /dev/null @@ -1,51 +0,0 @@ -/// The square root of `x` (f16). -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf16(x: f16) -> f16 { - select_implementation! { - name: sqrtf16, - use_arch: all(target_arch = "aarch64", target_feature = "fp16"), - args: x, - } - - return super::generic::sqrt(x); -} - -/// The square root of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf(x: f32) -> f32 { - select_implementation! { - name: sqrtf, - use_arch: any( - all(target_arch = "aarch64", target_feature = "neon"), - all(target_arch = "wasm32", intrinsics_enabled), - target_feature = "sse2" - ), - args: x, - } - - super::generic::sqrt(x) -} - -/// The square root of `x` (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrt(x: f64) -> f64 { - select_implementation! { - name: sqrt, - use_arch: any( - all(target_arch = "aarch64", target_feature = "neon"), - all(target_arch = "wasm32", intrinsics_enabled), - target_feature = "sse2" - ), - args: x, - } - - super::generic::sqrt(x) -} - -/// The square root of `x` (f128). -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf128(x: f128) -> f128 { - return super::generic::sqrt(x); -} diff --git a/library/compiler-builtins/libm/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/libm/src/math/sqrtf.rs deleted file mode 100644 index c28a705e378..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/sqrtf.rs +++ /dev/null @@ -1,15 +0,0 @@ -/// The square root of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf(x: f32) -> f32 { - select_implementation! { - name: sqrtf, - use_arch: any( - all(target_arch = "aarch64", target_feature = "neon"), - all(target_arch = "wasm32", intrinsics_enabled), - target_feature = "sse2" - ), - args: x, - } - - super::generic::sqrt(x) -} diff --git a/library/compiler-builtins/libm/libm/src/math/sqrtf128.rs b/library/compiler-builtins/libm/libm/src/math/sqrtf128.rs deleted file mode 100644 index eaef6ae0c1c..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/sqrtf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// The square root of `x` (f128). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf128(x: f128) -> f128 { - return super::generic::sqrt(x); -} diff --git a/library/compiler-builtins/libm/libm/src/math/sqrtf16.rs b/library/compiler-builtins/libm/libm/src/math/sqrtf16.rs deleted file mode 100644 index 7bedb7f8bbb..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/sqrtf16.rs +++ /dev/null @@ -1,11 +0,0 @@ -/// The square root of `x` (f16). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf16(x: f16) -> f16 { - select_implementation! { - name: sqrtf16, - use_arch: all(target_arch = "aarch64", target_feature = "fp16"), - args: x, - } - - return super::generic::sqrt(x); -} diff --git a/library/compiler-builtins/libm/libm/src/math/support/big.rs b/library/compiler-builtins/libm/libm/src/math/support/big.rs deleted file mode 100644 index eae08238e09..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/support/big.rs +++ /dev/null @@ -1,239 +0,0 @@ -//! Integers used for wide operations, larger than `u128`. - -#[cfg(test)] -mod tests; - -use core::ops; - -use super::{DInt, HInt, Int, MinInt}; - -const U128_LO_MASK: u128 = u64::MAX as u128; - -/// A 256-bit unsigned integer represented as two 128-bit native-endian limbs. -#[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] -pub struct u256 { - pub lo: u128, - pub hi: u128, -} - -impl u256 { - #[cfg(any(test, feature = "unstable-public-internals"))] - pub const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX }; - - /// Reinterpret as a signed integer - pub fn signed(self) -> i256 { - i256 { lo: self.lo, hi: self.hi } - } -} - -/// A 256-bit signed integer represented as two 128-bit native-endian limbs. -#[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] -pub struct i256 { - pub lo: u128, - pub hi: u128, -} - -impl i256 { - /// Reinterpret as an unsigned integer - #[cfg(any(test, feature = "unstable-public-internals"))] - pub fn unsigned(self) -> u256 { - u256 { lo: self.lo, hi: self.hi } - } -} - -impl MinInt for u256 { - type OtherSign = i256; - - type Unsigned = u256; - - const SIGNED: bool = false; - const BITS: u32 = 256; - const ZERO: Self = Self { lo: 0, hi: 0 }; - const ONE: Self = Self { lo: 1, hi: 0 }; - const MIN: Self = Self { lo: 0, hi: 0 }; - const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX }; -} - -impl MinInt for i256 { - type OtherSign = u256; - - type Unsigned = u256; - - const SIGNED: bool = false; - const BITS: u32 = 256; - const ZERO: Self = Self { lo: 0, hi: 0 }; - const ONE: Self = Self { lo: 1, hi: 0 }; - const MIN: Self = Self { lo: 0, hi: 1 << 127 }; - const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX << 1 }; -} - -macro_rules! impl_common { - ($ty:ty) => { - impl ops::BitOr for $ty { - type Output = Self; - - fn bitor(mut self, rhs: Self) -> Self::Output { - self.lo |= rhs.lo; - self.hi |= rhs.hi; - self - } - } - - impl ops::Not for $ty { - type Output = Self; - - fn not(mut self) -> Self::Output { - self.lo = !self.lo; - self.hi = !self.hi; - self - } - } - - impl ops::Shl for $ty { - type Output = Self; - - fn shl(self, _rhs: u32) -> Self::Output { - unimplemented!("only used to meet trait bounds") - } - } - }; -} - -impl_common!(i256); -impl_common!(u256); - -impl ops::Add for u256 { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - let (lo, carry) = self.lo.overflowing_add(rhs.lo); - let hi = self.hi.wrapping_add(carry as u128).wrapping_add(rhs.hi); - - Self { lo, hi } - } -} - -impl ops::Shr for u256 { - type Output = Self; - - fn shr(mut self, rhs: u32) -> Self::Output { - debug_assert!(rhs < Self::BITS, "attempted to shift right with overflow"); - if rhs >= Self::BITS { - return Self::ZERO; - } - - if rhs == 0 { - return self; - } - - if rhs < 128 { - self.lo >>= rhs; - self.lo |= self.hi << (128 - rhs); - } else { - self.lo = self.hi >> (rhs - 128); - } - - if rhs < 128 { - self.hi >>= rhs; - } else { - self.hi = 0; - } - - self - } -} - -impl HInt for u128 { - type D = u256; - - fn widen(self) -> Self::D { - u256 { lo: self, hi: 0 } - } - - fn zero_widen(self) -> Self::D { - self.widen() - } - - fn zero_widen_mul(self, rhs: Self) -> Self::D { - let l0 = self & U128_LO_MASK; - let l1 = rhs & U128_LO_MASK; - let h0 = self >> 64; - let h1 = rhs >> 64; - - let p_ll: u128 = l0.overflowing_mul(l1).0; - let p_lh: u128 = l0.overflowing_mul(h1).0; - let p_hl: u128 = h0.overflowing_mul(l1).0; - let p_hh: u128 = h0.overflowing_mul(h1).0; - - let s0 = p_hl + (p_ll >> 64); - let s1 = (p_ll & U128_LO_MASK) + (s0 << 64); - let s2 = p_lh + (s1 >> 64); - - let lo = (p_ll & U128_LO_MASK) + (s2 << 64); - let hi = p_hh + (s0 >> 64) + (s2 >> 64); - - u256 { lo, hi } - } - - fn widen_mul(self, rhs: Self) -> Self::D { - self.zero_widen_mul(rhs) - } - - fn widen_hi(self) -> Self::D { - self.widen() << ::BITS - } -} - -impl HInt for i128 { - type D = i256; - - fn widen(self) -> Self::D { - let mut ret = self.unsigned().zero_widen().signed(); - if self.is_negative() { - ret.hi = u128::MAX; - } - ret - } - - fn zero_widen(self) -> Self::D { - self.unsigned().zero_widen().signed() - } - - fn zero_widen_mul(self, rhs: Self) -> Self::D { - self.unsigned().zero_widen_mul(rhs.unsigned()).signed() - } - - fn widen_mul(self, _rhs: Self) -> Self::D { - unimplemented!("signed i128 widening multiply is not used") - } - - fn widen_hi(self) -> Self::D { - self.widen() << ::BITS - } -} - -impl DInt for u256 { - type H = u128; - - fn lo(self) -> Self::H { - self.lo - } - - fn hi(self) -> Self::H { - self.hi - } -} - -impl DInt for i256 { - type H = i128; - - fn lo(self) -> Self::H { - self.lo as i128 - } - - fn hi(self) -> Self::H { - self.hi as i128 - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/libm/src/math/support/big/tests.rs deleted file mode 100644 index 2c71191ba53..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/support/big/tests.rs +++ /dev/null @@ -1,149 +0,0 @@ -extern crate std; -use std::string::String; -use std::{eprintln, format}; - -use super::{HInt, MinInt, i256, u256}; - -const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; - -/// Print a `u256` as hex since we can't add format implementations -fn hexu(v: u256) -> String { - format!("0x{:032x}{:032x}", v.hi, v.lo) -} - -#[test] -fn widen_u128() { - assert_eq!(u128::MAX.widen(), u256 { lo: u128::MAX, hi: 0 }); - assert_eq!(LOHI_SPLIT.widen(), u256 { lo: LOHI_SPLIT, hi: 0 }); -} - -#[test] -fn widen_i128() { - assert_eq!((-1i128).widen(), u256::MAX.signed()); - assert_eq!((LOHI_SPLIT as i128).widen(), i256 { lo: LOHI_SPLIT, hi: u128::MAX }); - assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); -} - -#[test] -fn widen_mul_u128() { - let tests = [ - (u128::MAX / 2, 2_u128, u256 { lo: u128::MAX - 1, hi: 0 }), - (u128::MAX, 2_u128, u256 { lo: u128::MAX - 1, hi: 1 }), - (u128::MAX, u128::MAX, u256 { lo: 1, hi: u128::MAX - 1 }), - (0, 0, u256::ZERO), - (1234u128, 0, u256::ZERO), - (0, 1234, u256::ZERO), - ]; - - let mut has_errors = false; - let mut add_error = |i, a, b, expected, actual| { - has_errors = true; - eprintln!( - "\ - FAILURE ({i}): {a:#034x} * {b:#034x}\n\ - expected: {}\n\ - got: {}\ - ", - hexu(expected), - hexu(actual) - ); - }; - - for (i, (a, b, exp)) in tests.iter().copied().enumerate() { - let res = a.widen_mul(b); - let res_z = a.zero_widen_mul(b); - assert_eq!(res, res_z); - if res != exp { - add_error(i, a, b, exp, res); - } - } - - assert!(!has_errors); -} - -#[test] -fn not_u256() { - assert_eq!(!u256::ZERO, u256::MAX); -} - -#[test] -fn shr_u256() { - let only_low = [1, u16::MAX.into(), u32::MAX.into(), u64::MAX.into(), u128::MAX]; - let mut has_errors = false; - - let mut add_error = |a, b, expected, actual| { - has_errors = true; - eprintln!( - "\ - FAILURE: {} >> {b}\n\ - expected: {}\n\ - actual: {}\ - ", - hexu(a), - hexu(expected), - hexu(actual), - ); - }; - - for a in only_low { - for perturb in 0..10 { - let a = a.saturating_add(perturb); - for shift in 0..128 { - let res = a.widen() >> shift; - let expected = (a >> shift).widen(); - if res != expected { - add_error(a.widen(), shift, expected, res); - } - } - } - } - - let check = [ - (u256::MAX, 1, u256 { lo: u128::MAX, hi: u128::MAX >> 1 }), - (u256::MAX, 5, u256 { lo: u128::MAX, hi: u128::MAX >> 5 }), - (u256::MAX, 63, u256 { lo: u128::MAX, hi: u64::MAX as u128 | (1 << 64) }), - (u256::MAX, 64, u256 { lo: u128::MAX, hi: u64::MAX as u128 }), - (u256::MAX, 65, u256 { lo: u128::MAX, hi: (u64::MAX >> 1) as u128 }), - (u256::MAX, 127, u256 { lo: u128::MAX, hi: 1 }), - (u256::MAX, 128, u256 { lo: u128::MAX, hi: 0 }), - (u256::MAX, 129, u256 { lo: u128::MAX >> 1, hi: 0 }), - (u256::MAX, 191, u256 { lo: u64::MAX as u128 | 1 << 64, hi: 0 }), - (u256::MAX, 192, u256 { lo: u64::MAX as u128, hi: 0 }), - (u256::MAX, 193, u256 { lo: u64::MAX as u128 >> 1, hi: 0 }), - (u256::MAX, 254, u256 { lo: 0b11, hi: 0 }), - (u256::MAX, 255, u256 { lo: 1, hi: 0 }), - ( - u256 { hi: LOHI_SPLIT, lo: 0 }, - 64, - u256 { lo: 0xffffffffffffffff0000000000000000, hi: 0xaaaaaaaaaaaaaaaa }, - ), - ]; - - for (input, shift, expected) in check { - let res = input >> shift; - if res != expected { - add_error(input, shift, expected, res); - } - } - - assert!(!has_errors); -} - -#[test] -#[should_panic] -#[cfg(debug_assertions)] -// FIXME(ppc): ppc64le seems to have issues with `should_panic` tests. -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] -fn shr_u256_overflow() { - // Like regular shr, panic on overflow with debug assertions - let _ = u256::MAX >> 256; -} - -#[test] -#[cfg(not(debug_assertions))] -fn shr_u256_overflow() { - // No panic without debug assertions - assert_eq!(u256::MAX >> 256, u256::ZERO); - assert_eq!(u256::MAX >> 257, u256::ZERO); - assert_eq!(u256::MAX >> u32::MAX, u256::ZERO); -} diff --git a/library/compiler-builtins/libm/libm/src/math/support/env.rs b/library/compiler-builtins/libm/libm/src/math/support/env.rs deleted file mode 100644 index 796309372a5..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/support/env.rs +++ /dev/null @@ -1,127 +0,0 @@ -//! Support for rounding directions and status flags as specified by IEEE 754. -//! -//! Rust does not support the floating point environment so rounding mode is passed as an argument -//! and status flags are returned as part of the result. There is currently not much support for -//! this; most existing ports from musl use a form of `force_eval!` to raise exceptions, but this -//! has no side effects in Rust. Further, correct behavior relies on elementary operations making -//! use of the correct rounding and raising relevant exceptions, which is not the case for Rust. -//! -//! This module exists so no functionality is lost when porting algorithms that respect floating -//! point environment, and so that some functionality may be tested (that which does not rely on -//! side effects from elementary operations). Full support would require wrappers around basic -//! operations, but there is no plan to add this at the current time. - -/// A value combined with a floating point status. -pub struct FpResult { - pub val: T, - #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] - pub status: Status, -} - -impl FpResult { - pub fn new(val: T, status: Status) -> Self { - Self { val, status } - } - - /// Return `val` with `Status::OK`. - pub fn ok(val: T) -> Self { - Self { val, status: Status::OK } - } -} - -/// IEEE 754 rounding mode, excluding the optional `roundTiesToAway` version of nearest. -/// -/// Integer representation comes from what CORE-MATH uses for indexing. -#[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum Round { - /// IEEE 754 nearest, `roundTiesToEven`. - Nearest = 0, - /// IEEE 754 `roundTowardNegative`. - Negative = 1, - /// IEEE 754 `roundTowardPositive`. - Positive = 2, - /// IEEE 754 `roundTowardZero`. - Zero = 3, -} - -/// IEEE 754 exception status flags. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Status(u8); - -impl Status { - /// Default status indicating no errors. - pub const OK: Self = Self(0); - - /// No definable result. - /// - /// Includes: - /// - Any ops on sNaN, with a few exceptions. - /// - `0 * inf`, `inf * 0`. - /// - `fma(0, inf, c)` or `fma(inf, 0, c)`, possibly excluding `c = qNaN`. - /// - `+inf + -inf` and similar (includes subtraction and fma). - /// - `0.0 / 0.0`, `inf / inf` - /// - `remainder(x, y)` if `y == 0.0` or `x == inf`, and neither is NaN. - /// - `sqrt(x)` with `x < 0.0`. - pub const INVALID: Self = Self(1); - - /// Division by zero. - /// - /// The default result for division is +/-inf based on operand sign. For `logB`, the default - /// result is -inf. - /// `x / y` when `x != 0.0` and `y == 0.0`, - #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] - pub const DIVIDE_BY_ZERO: Self = Self(1 << 2); - - /// The result exceeds the maximum finite value. - /// - /// The default result depends on rounding mode. `Nearest*` rounds to +/- infinity, sign based - /// on the intermediate result. `Zero` rounds to the signed maximum finite. `Positive` and - /// `Negative` round to signed maximum finite in one direction, signed infinity in the other. - #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] - pub const OVERFLOW: Self = Self(1 << 3); - - /// The result is subnormal and lost precision. - pub const UNDERFLOW: Self = Self(1 << 4); - - /// The finite-precision result does not match that of infinite precision, and the reason - /// is not represented by one of the other flags. - pub const INEXACT: Self = Self(1 << 5); - - /// True if `UNDERFLOW` is set. - #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] - pub const fn underflow(self) -> bool { - self.0 & Self::UNDERFLOW.0 != 0 - } - - /// True if `OVERFLOW` is set. - #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] - pub const fn overflow(self) -> bool { - self.0 & Self::OVERFLOW.0 != 0 - } - - pub fn set_underflow(&mut self, val: bool) { - self.set_flag(val, Self::UNDERFLOW); - } - - /// True if `INEXACT` is set. - pub const fn inexact(self) -> bool { - self.0 & Self::INEXACT.0 != 0 - } - - pub fn set_inexact(&mut self, val: bool) { - self.set_flag(val, Self::INEXACT); - } - - fn set_flag(&mut self, val: bool, mask: Self) { - if val { - self.0 |= mask.0; - } else { - self.0 &= !mask.0; - } - } - - pub(crate) const fn with(self, rhs: Self) -> Self { - Self(self.0 | rhs.0) - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/libm/src/math/support/float_traits.rs deleted file mode 100644 index fac10483237..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/support/float_traits.rs +++ /dev/null @@ -1,484 +0,0 @@ -use core::{fmt, mem, ops}; - -use super::int_traits::{CastFrom, Int, MinInt}; - -/// Trait for some basic operations on floats -// #[allow(dead_code)] -pub trait Float: - Copy - + fmt::Debug - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::MulAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Rem - + ops::Neg - + 'static -{ - /// A uint of the same width as the float - type Int: Int; - - /// A int of the same width as the float - type SignedInt: Int - + MinInt - + ops::Neg; - - const ZERO: Self; - const NEG_ZERO: Self; - const ONE: Self; - const NEG_ONE: Self; - const INFINITY: Self; - const NEG_INFINITY: Self; - const NAN: Self; - const NEG_NAN: Self; - const MAX: Self; - const MIN: Self; - const EPSILON: Self; - const PI: Self; - const NEG_PI: Self; - const FRAC_PI_2: Self; - - const MIN_POSITIVE_NORMAL: Self; - - /// The bitwidth of the float type - const BITS: u32; - - /// The bitwidth of the significand - const SIG_BITS: u32; - - /// The bitwidth of the exponent - const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; - - /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite - /// representation. - /// - /// This shifted fully right, use `EXP_MASK` for the shifted value. - const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; - - /// The exponent bias value - const EXP_BIAS: u32 = Self::EXP_SAT >> 1; - - /// Maximum unbiased exponent value. - const EXP_MAX: i32 = Self::EXP_BIAS as i32; - - /// Minimum *NORMAL* unbiased exponent value. - const EXP_MIN: i32 = -(Self::EXP_MAX - 1); - - /// Minimum subnormal exponent value. - const EXP_MIN_SUBNORM: i32 = Self::EXP_MIN - Self::SIG_BITS as i32; - - /// A mask for the sign bit - const SIGN_MASK: Self::Int; - - /// A mask for the significand - const SIG_MASK: Self::Int; - - /// A mask for the exponent - const EXP_MASK: Self::Int; - - /// The implicit bit of the float format - const IMPLICIT_BIT: Self::Int; - - /// Returns `self` transmuted to `Self::Int` - fn to_bits(self) -> Self::Int; - - /// Returns `self` transmuted to `Self::SignedInt` - #[allow(dead_code)] - fn to_bits_signed(self) -> Self::SignedInt { - self.to_bits().signed() - } - - /// Check bitwise equality. - #[allow(dead_code)] - fn biteq(self, rhs: Self) -> bool { - self.to_bits() == rhs.to_bits() - } - - /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. - /// - /// This method returns `true` if two NaNs are compared. Use [`biteq`](Self::biteq) instead - /// if `NaN` should not be treated separately. - #[allow(dead_code)] - fn eq_repr(self, rhs: Self) -> bool { - if self.is_nan() && rhs.is_nan() { true } else { self.biteq(rhs) } - } - - /// Returns true if the value is NaN. - fn is_nan(self) -> bool; - - /// Returns true if the value is +inf or -inf. - fn is_infinite(self) -> bool; - - /// Returns true if the sign is negative. Extracts the sign bit regardless of zero or NaN. - fn is_sign_negative(self) -> bool; - - /// Returns true if the sign is positive. Extracts the sign bit regardless of zero or NaN. - fn is_sign_positive(self) -> bool { - !self.is_sign_negative() - } - - /// Returns if `self` is subnormal. - #[allow(dead_code)] - fn is_subnormal(self) -> bool { - (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO - } - - /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. - fn ex(self) -> u32 { - u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_SAT - } - - /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. - fn exp_unbiased(self) -> i32 { - self.ex().signed() - (Self::EXP_BIAS as i32) - } - - /// Returns the significand with no implicit bit (or the "fractional" part) - #[allow(dead_code)] - fn frac(self) -> Self::Int { - self.to_bits() & Self::SIG_MASK - } - - /// Returns a `Self::Int` transmuted back to `Self` - fn from_bits(a: Self::Int) -> Self; - - /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(negative: bool, exponent: u32, significand: Self::Int) -> Self { - let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; - Self::from_bits( - (sign << (Self::BITS - 1)) - | (Self::Int::cast_from(exponent & Self::EXP_SAT) << Self::SIG_BITS) - | (significand & Self::SIG_MASK), - ) - } - - #[allow(dead_code)] - fn abs(self) -> Self; - - /// Returns a number composed of the magnitude of self and the sign of sign. - fn copysign(self, other: Self) -> Self; - - /// Fused multiply add, rounding once. - fn fma(self, y: Self, z: Self) -> Self; - - /// Returns (normalized exponent, normalized significand) - #[allow(dead_code)] - fn normalize(significand: Self::Int) -> (i32, Self::Int); - - /// Returns a number that represents the sign of self. - #[allow(dead_code)] - fn signum(self) -> Self { - if self.is_nan() { self } else { Self::ONE.copysign(self) } - } -} - -/// Access the associated `Int` type from a float (helper to avoid ambiguous associated types). -pub type IntTy = ::Int; - -macro_rules! float_impl { - ( - $ty:ident, - $ity:ident, - $sity:ident, - $bits:expr, - $significand_bits:expr, - $from_bits:path, - $to_bits:path, - $fma_fn:ident, - $fma_intrinsic:ident - ) => { - impl Float for $ty { - type Int = $ity; - type SignedInt = $sity; - - const ZERO: Self = 0.0; - const NEG_ZERO: Self = -0.0; - const ONE: Self = 1.0; - const NEG_ONE: Self = -1.0; - const INFINITY: Self = Self::INFINITY; - const NEG_INFINITY: Self = Self::NEG_INFINITY; - const NAN: Self = Self::NAN; - // NAN isn't guaranteed to be positive but it usually is. We only use this for - // tests. - const NEG_NAN: Self = $from_bits($to_bits(Self::NAN) | Self::SIGN_MASK); - const MAX: Self = -Self::MIN; - // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed - const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS)); - const EPSILON: Self = <$ty>::EPSILON; - - // Exponent is a 1 in the LSB - const MIN_POSITIVE_NORMAL: Self = $from_bits(1 << Self::SIG_BITS); - - const PI: Self = core::$ty::consts::PI; - const NEG_PI: Self = -Self::PI; - const FRAC_PI_2: Self = core::$ty::consts::FRAC_PI_2; - - const BITS: u32 = $bits; - const SIG_BITS: u32 = $significand_bits; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; - const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); - const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; - - fn to_bits(self) -> Self::Int { - self.to_bits() - } - fn is_nan(self) -> bool { - self.is_nan() - } - fn is_infinite(self) -> bool { - self.is_infinite() - } - fn is_sign_negative(self) -> bool { - self.is_sign_negative() - } - fn from_bits(a: Self::Int) -> Self { - Self::from_bits(a) - } - fn abs(self) -> Self { - cfg_if! { - // FIXME(msrv): `abs` is available in `core` starting with 1.85. - if #[cfg(intrinsics_enabled)] { - self.abs() - } else { - super::super::generic::fabs(self) - } - } - } - fn copysign(self, other: Self) -> Self { - cfg_if! { - // FIXME(msrv): `copysign` is available in `core` starting with 1.85. - if #[cfg(intrinsics_enabled)] { - self.copysign(other) - } else { - super::super::generic::copysign(self, other) - } - } - } - fn fma(self, y: Self, z: Self) -> Self { - cfg_if! { - // fma is not yet available in `core` - if #[cfg(intrinsics_enabled)] { - unsafe{ core::intrinsics::$fma_intrinsic(self, y, z) } - } else { - super::super::$fma_fn(self, y, z) - } - } - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); - (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) - } - } - }; -} - -#[cfg(f16_enabled)] -float_impl!(f16, u16, i16, 16, 10, f16::from_bits, f16::to_bits, fmaf16, fmaf16); -float_impl!(f32, u32, i32, 32, 23, f32_from_bits, f32_to_bits, fmaf, fmaf32); -float_impl!(f64, u64, i64, 64, 52, f64_from_bits, f64_to_bits, fma, fmaf64); -#[cfg(f128_enabled)] -float_impl!(f128, u128, i128, 128, 112, f128::from_bits, f128::to_bits, fmaf128, fmaf128); - -/* FIXME(msrv): vendor some things that are not const stable at our MSRV */ - -/// `f32::from_bits` -pub const fn f32_from_bits(bits: u32) -> f32 { - // SAFETY: POD cast with no preconditions - unsafe { mem::transmute::(bits) } -} - -/// `f32::to_bits` -pub const fn f32_to_bits(x: f32) -> u32 { - // SAFETY: POD cast with no preconditions - unsafe { mem::transmute::(x) } -} - -/// `f64::from_bits` -pub const fn f64_from_bits(bits: u64) -> f64 { - // SAFETY: POD cast with no preconditions - unsafe { mem::transmute::(bits) } -} - -/// `f64::to_bits` -pub const fn f64_to_bits(x: f64) -> u64 { - // SAFETY: POD cast with no preconditions - unsafe { mem::transmute::(x) } -} - -/// Trait for floats twice the bit width of another integer. -pub trait DFloat: Float { - /// Float that is half the bit width of the floatthis trait is implemented for. - type H: HFloat; - - /// Narrow the float type. - fn narrow(self) -> Self::H; -} - -/// Trait for floats half the bit width of another float. -pub trait HFloat: Float { - /// Float that is double the bit width of the float this trait is implemented for. - type D: DFloat; - - /// Widen the float type. - fn widen(self) -> Self::D; -} - -macro_rules! impl_d_float { - ($($X:ident $D:ident),*) => { - $( - impl DFloat for $D { - type H = $X; - - fn narrow(self) -> Self::H { - self as $X - } - } - )* - }; -} - -macro_rules! impl_h_float { - ($($H:ident $X:ident),*) => { - $( - impl HFloat for $H { - type D = $X; - - fn widen(self) -> Self::D { - self as $X - } - } - )* - }; -} - -impl_d_float!(f32 f64); -#[cfg(f16_enabled)] -impl_d_float!(f16 f32); -#[cfg(f128_enabled)] -impl_d_float!(f64 f128); - -impl_h_float!(f32 f64); -#[cfg(f16_enabled)] -impl_h_float!(f16 f32); -#[cfg(f128_enabled)] -impl_h_float!(f64 f128); - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[cfg(f16_enabled)] - fn check_f16() { - // Constants - assert_eq!(f16::EXP_SAT, 0b11111); - assert_eq!(f16::EXP_BIAS, 15); - assert_eq!(f16::EXP_MAX, 15); - assert_eq!(f16::EXP_MIN, -14); - assert_eq!(f16::EXP_MIN_SUBNORM, -24); - - // `exp_unbiased` - assert_eq!(f16::FRAC_PI_2.exp_unbiased(), 0); - assert_eq!((1.0f16 / 2.0).exp_unbiased(), -1); - assert_eq!(f16::MAX.exp_unbiased(), 15); - assert_eq!(f16::MIN.exp_unbiased(), 15); - assert_eq!(f16::MIN_POSITIVE.exp_unbiased(), -14); - // This is a convenience method and not ldexp, `exp_unbiased` does not return correct - // results for zero and subnormals. - assert_eq!(f16::ZERO.exp_unbiased(), -15); - assert_eq!(f16::from_bits(0x1).exp_unbiased(), -15); - assert_eq!(f16::MIN_POSITIVE, f16::MIN_POSITIVE_NORMAL); - - // `from_parts` - assert_biteq!(f16::from_parts(true, f16::EXP_BIAS, 0), -1.0f16); - assert_biteq!(f16::from_parts(false, 0, 1), f16::from_bits(0x1)); - } - - #[test] - fn check_f32() { - // Constants - assert_eq!(f32::EXP_SAT, 0b11111111); - assert_eq!(f32::EXP_BIAS, 127); - assert_eq!(f32::EXP_MAX, 127); - assert_eq!(f32::EXP_MIN, -126); - assert_eq!(f32::EXP_MIN_SUBNORM, -149); - - // `exp_unbiased` - assert_eq!(f32::FRAC_PI_2.exp_unbiased(), 0); - assert_eq!((1.0f32 / 2.0).exp_unbiased(), -1); - assert_eq!(f32::MAX.exp_unbiased(), 127); - assert_eq!(f32::MIN.exp_unbiased(), 127); - assert_eq!(f32::MIN_POSITIVE.exp_unbiased(), -126); - // This is a convenience method and not ldexp, `exp_unbiased` does not return correct - // results for zero and subnormals. - assert_eq!(f32::ZERO.exp_unbiased(), -127); - assert_eq!(f32::from_bits(0x1).exp_unbiased(), -127); - assert_eq!(f32::MIN_POSITIVE, f32::MIN_POSITIVE_NORMAL); - - // `from_parts` - assert_biteq!(f32::from_parts(true, f32::EXP_BIAS, 0), -1.0f32); - assert_biteq!(f32::from_parts(false, 10 + f32::EXP_BIAS, 0), hf32!("0x1p10")); - assert_biteq!(f32::from_parts(false, 0, 1), f32::from_bits(0x1)); - } - - #[test] - fn check_f64() { - // Constants - assert_eq!(f64::EXP_SAT, 0b11111111111); - assert_eq!(f64::EXP_BIAS, 1023); - assert_eq!(f64::EXP_MAX, 1023); - assert_eq!(f64::EXP_MIN, -1022); - assert_eq!(f64::EXP_MIN_SUBNORM, -1074); - - // `exp_unbiased` - assert_eq!(f64::FRAC_PI_2.exp_unbiased(), 0); - assert_eq!((1.0f64 / 2.0).exp_unbiased(), -1); - assert_eq!(f64::MAX.exp_unbiased(), 1023); - assert_eq!(f64::MIN.exp_unbiased(), 1023); - assert_eq!(f64::MIN_POSITIVE.exp_unbiased(), -1022); - // This is a convenience method and not ldexp, `exp_unbiased` does not return correct - // results for zero and subnormals. - assert_eq!(f64::ZERO.exp_unbiased(), -1023); - assert_eq!(f64::from_bits(0x1).exp_unbiased(), -1023); - assert_eq!(f64::MIN_POSITIVE, f64::MIN_POSITIVE_NORMAL); - - // `from_parts` - assert_biteq!(f64::from_parts(true, f64::EXP_BIAS, 0), -1.0f64); - assert_biteq!(f64::from_parts(false, 10 + f64::EXP_BIAS, 0), hf64!("0x1p10")); - assert_biteq!(f64::from_parts(false, 0, 1), f64::from_bits(0x1)); - } - - #[test] - #[cfg(f128_enabled)] - fn check_f128() { - // Constants - assert_eq!(f128::EXP_SAT, 0b111111111111111); - assert_eq!(f128::EXP_BIAS, 16383); - assert_eq!(f128::EXP_MAX, 16383); - assert_eq!(f128::EXP_MIN, -16382); - assert_eq!(f128::EXP_MIN_SUBNORM, -16494); - - // `exp_unbiased` - assert_eq!(f128::FRAC_PI_2.exp_unbiased(), 0); - assert_eq!((1.0f128 / 2.0).exp_unbiased(), -1); - assert_eq!(f128::MAX.exp_unbiased(), 16383); - assert_eq!(f128::MIN.exp_unbiased(), 16383); - assert_eq!(f128::MIN_POSITIVE.exp_unbiased(), -16382); - // This is a convenience method and not ldexp, `exp_unbiased` does not return correct - // results for zero and subnormals. - assert_eq!(f128::ZERO.exp_unbiased(), -16383); - assert_eq!(f128::from_bits(0x1).exp_unbiased(), -16383); - assert_eq!(f128::MIN_POSITIVE, f128::MIN_POSITIVE_NORMAL); - - // `from_parts` - assert_biteq!(f128::from_parts(true, f128::EXP_BIAS, 0), -1.0f128); - assert_biteq!(f128::from_parts(false, 0, 1), f128::from_bits(0x1)); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/libm/src/math/support/hex_float.rs deleted file mode 100644 index 819e2f56e36..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/support/hex_float.rs +++ /dev/null @@ -1,1155 +0,0 @@ -//! Utilities for working with hex float formats. - -use core::fmt; - -use super::{Float, Round, Status, f32_from_bits, f64_from_bits}; - -/// Construct a 16-bit float from hex float representation (C-style) -#[cfg(f16_enabled)] -pub const fn hf16(s: &str) -> f16 { - match parse_hex_exact(s, 16, 10) { - Ok(bits) => f16::from_bits(bits as u16), - Err(HexFloatParseError(s)) => panic!("{}", s), - } -} - -/// Construct a 32-bit float from hex float representation (C-style) -#[allow(unused)] -pub const fn hf32(s: &str) -> f32 { - match parse_hex_exact(s, 32, 23) { - Ok(bits) => f32_from_bits(bits as u32), - Err(HexFloatParseError(s)) => panic!("{}", s), - } -} - -/// Construct a 64-bit float from hex float representation (C-style) -pub const fn hf64(s: &str) -> f64 { - match parse_hex_exact(s, 64, 52) { - Ok(bits) => f64_from_bits(bits as u64), - Err(HexFloatParseError(s)) => panic!("{}", s), - } -} - -/// Construct a 128-bit float from hex float representation (C-style) -#[cfg(f128_enabled)] -pub const fn hf128(s: &str) -> f128 { - match parse_hex_exact(s, 128, 112) { - Ok(bits) => f128::from_bits(bits), - Err(HexFloatParseError(s)) => panic!("{}", s), - } -} -#[derive(Copy, Clone, Debug)] -pub struct HexFloatParseError(&'static str); - -/// Parses any float to its bitwise representation, returning an error if it cannot be represented exactly -pub const fn parse_hex_exact( - s: &str, - bits: u32, - sig_bits: u32, -) -> Result { - match parse_any(s, bits, sig_bits, Round::Nearest) { - Err(e) => Err(e), - Ok((bits, Status::OK)) => Ok(bits), - Ok((_, status)) if status.overflow() => Err(HexFloatParseError("the value is too huge")), - Ok((_, status)) if status.underflow() => Err(HexFloatParseError("the value is too tiny")), - Ok((_, status)) if status.inexact() => Err(HexFloatParseError("the value is too precise")), - Ok(_) => unreachable!(), - } -} - -/// Parse any float from hex to its bitwise representation. -pub const fn parse_any( - s: &str, - bits: u32, - sig_bits: u32, - round: Round, -) -> Result<(u128, Status), HexFloatParseError> { - let mut b = s.as_bytes(); - - if sig_bits > 119 || bits > 128 || bits < sig_bits + 3 || bits > sig_bits + 30 { - return Err(HexFloatParseError("unsupported target float configuration")); - } - - let neg = matches!(b, [b'-', ..]); - if let &[b'-' | b'+', ref rest @ ..] = b { - b = rest; - } - - let sign_bit = 1 << (bits - 1); - let quiet_bit = 1 << (sig_bits - 1); - let nan = sign_bit - quiet_bit; - let inf = nan - quiet_bit; - - let (mut x, status) = match *b { - [b'i' | b'I', b'n' | b'N', b'f' | b'F'] => (inf, Status::OK), - [b'n' | b'N', b'a' | b'A', b'n' | b'N'] => (nan, Status::OK), - [b'0', b'x' | b'X', ref rest @ ..] => { - let round = match (neg, round) { - // parse("-x", Round::Positive) == -parse("x", Round::Negative) - (true, Round::Positive) => Round::Negative, - (true, Round::Negative) => Round::Positive, - // rounding toward nearest or zero are symmetric - (true, Round::Nearest | Round::Zero) | (false, _) => round, - }; - match parse_finite(rest, bits, sig_bits, round) { - Err(e) => return Err(e), - Ok(res) => res, - } - } - _ => return Err(HexFloatParseError("no hex indicator")), - }; - - if neg { - x ^= sign_bit; - } - - Ok((x, status)) -} - -const fn parse_finite( - b: &[u8], - bits: u32, - sig_bits: u32, - rounding_mode: Round, -) -> Result<(u128, Status), HexFloatParseError> { - let exp_bits: u32 = bits - sig_bits - 1; - let max_msb: i32 = (1 << (exp_bits - 1)) - 1; - // The exponent of one ULP in the subnormals - let min_lsb: i32 = 1 - max_msb - sig_bits as i32; - - let (mut sig, mut exp) = match parse_hex(b) { - Err(e) => return Err(e), - Ok(Parsed { sig: 0, .. }) => return Ok((0, Status::OK)), - Ok(Parsed { sig, exp }) => (sig, exp), - }; - - let mut round_bits = u128_ilog2(sig) as i32 - sig_bits as i32; - - // Round at least up to min_lsb - if exp < min_lsb - round_bits { - round_bits = min_lsb - exp; - } - - let mut status = Status::OK; - - exp += round_bits; - - if round_bits > 0 { - // first, prepare for rounding exactly two bits - if round_bits == 1 { - sig <<= 1; - } else if round_bits > 2 { - sig = shr_odd_rounding(sig, (round_bits - 2) as u32); - } - - if sig & 0b11 != 0 { - status = Status::INEXACT; - } - - sig = shr2_round(sig, rounding_mode); - } else if round_bits < 0 { - sig <<= -round_bits; - } - - // The parsed value is X = sig * 2^exp - // Expressed as a multiple U of the smallest subnormal value: - // X = U * 2^min_lsb, so U = sig * 2^(exp-min_lsb) - let uexp = (exp - min_lsb) as u128; - let uexp = uexp << sig_bits; - - // Note that it is possible for the exponent bits to equal 2 here - // if the value rounded up, but that means the mantissa is all zeroes - // so the value is still correct - debug_assert!(sig <= 2 << sig_bits); - - let inf = ((1 << exp_bits) - 1) << sig_bits; - - let bits = match sig.checked_add(uexp) { - Some(bits) if bits < inf => { - // inexact subnormal or zero? - if status.inexact() && bits < (1 << sig_bits) { - status = status.with(Status::UNDERFLOW); - } - bits - } - _ => { - // overflow to infinity - status = status.with(Status::OVERFLOW).with(Status::INEXACT); - match rounding_mode { - Round::Positive | Round::Nearest => inf, - Round::Negative | Round::Zero => inf - 1, - } - } - }; - Ok((bits, status)) -} - -/// Shift right, rounding all inexact divisions to the nearest odd number -/// E.g. (0 >> 4) -> 0, (1..=31 >> 4) -> 1, (32 >> 4) -> 2, ... -/// -/// Useful for reducing a number before rounding the last two bits, since -/// the result of the final rounding is preserved for all rounding modes. -const fn shr_odd_rounding(x: u128, k: u32) -> u128 { - if k < 128 { - let inexact = x.trailing_zeros() < k; - (x >> k) | (inexact as u128) - } else { - (x != 0) as u128 - } -} - -/// Divide by 4, rounding with the given mode -const fn shr2_round(mut x: u128, round: Round) -> u128 { - let t = (x as u32) & 0b111; - x >>= 2; - match round { - // Look-up-table on the last three bits for when to round up - Round::Nearest => x + ((0b11001000_u8 >> t) & 1) as u128, - - Round::Negative => x, - Round::Zero => x, - Round::Positive => x + (t & 0b11 != 0) as u128, - } -} - -/// A parsed finite and unsigned floating point number. -struct Parsed { - /// Absolute value sig * 2^exp - sig: u128, - exp: i32, -} - -/// Parse a hexadecimal float x -const fn parse_hex(mut b: &[u8]) -> Result { - let mut sig: u128 = 0; - let mut exp: i32 = 0; - - let mut seen_point = false; - let mut some_digits = false; - let mut inexact = false; - - while let &[c, ref rest @ ..] = b { - b = rest; - - match c { - b'.' => { - if seen_point { - return Err(HexFloatParseError("unexpected '.' parsing fractional digits")); - } - seen_point = true; - continue; - } - b'p' | b'P' => break, - c => { - let digit = match hex_digit(c) { - Some(d) => d, - None => return Err(HexFloatParseError("expected hexadecimal digit")), - }; - some_digits = true; - - if (sig >> 124) == 0 { - sig <<= 4; - sig |= digit as u128; - } else { - // FIXME: it is technically possible for exp to overflow if parsing a string with >500M digits - exp += 4; - inexact |= digit != 0; - } - // Up until the fractional point, the value grows - // with more digits, but after it the exponent is - // compensated to match. - if seen_point { - exp -= 4; - } - } - } - } - // If we've set inexact, the exact value has more than 125 - // significant bits, and lies somewhere between sig and sig + 1. - // Because we'll round off at least two of the trailing bits, - // setting the last bit gives correct rounding for inexact values. - sig |= inexact as u128; - - if !some_digits { - return Err(HexFloatParseError("at least one digit is required")); - }; - - some_digits = false; - - let negate_exp = matches!(b, [b'-', ..]); - if let &[b'-' | b'+', ref rest @ ..] = b { - b = rest; - } - - let mut pexp: u32 = 0; - while let &[c, ref rest @ ..] = b { - b = rest; - let digit = match dec_digit(c) { - Some(d) => d, - None => return Err(HexFloatParseError("expected decimal digit")), - }; - some_digits = true; - pexp = pexp.saturating_mul(10); - pexp += digit as u32; - } - - if !some_digits { - return Err(HexFloatParseError("at least one exponent digit is required")); - }; - - { - let e; - if negate_exp { - e = (exp as i64) - (pexp as i64); - } else { - e = (exp as i64) + (pexp as i64); - }; - - exp = if e < i32::MIN as i64 { - i32::MIN - } else if e > i32::MAX as i64 { - i32::MAX - } else { - e as i32 - }; - } - /* FIXME(msrv): once MSRV >= 1.66, replace the above workaround block with: - if negate_exp { - exp = exp.saturating_sub_unsigned(pexp); - } else { - exp = exp.saturating_add_unsigned(pexp); - }; - */ - - Ok(Parsed { sig, exp }) -} - -const fn dec_digit(c: u8) -> Option { - match c { - b'0'..=b'9' => Some(c - b'0'), - _ => None, - } -} - -const fn hex_digit(c: u8) -> Option { - match c { - b'0'..=b'9' => Some(c - b'0'), - b'a'..=b'f' => Some(c - b'a' + 10), - b'A'..=b'F' => Some(c - b'A' + 10), - _ => None, - } -} - -/* FIXME(msrv): vendor some things that are not const stable at our MSRV */ - -/// `u128::ilog2` -const fn u128_ilog2(v: u128) -> u32 { - assert!(v != 0); - u128::BITS - 1 - v.leading_zeros() -} - -/// Format a floating point number as its IEEE hex (`%a`) representation. -pub struct Hexf(pub F); - -// Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs -#[cfg(not(feature = "compiler-builtins"))] -fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if x.is_sign_negative() { - write!(f, "-")?; - } - - if x.is_nan() { - return write!(f, "NaN"); - } else if x.is_infinite() { - return write!(f, "inf"); - } else if *x == F::ZERO { - return write!(f, "0x0p+0"); - } - - let mut exponent = x.exp_unbiased(); - let sig = x.to_bits() & F::SIG_MASK; - - let bias = F::EXP_BIAS as i32; - // The mantissa MSB needs to be shifted up to the nearest nibble. - let mshift = (4 - (F::SIG_BITS % 4)) % 4; - let sig = sig << mshift; - // The width is rounded up to the nearest char (4 bits) - let mwidth = (F::SIG_BITS as usize + 3) / 4; - let leading = if exponent == -bias { - // subnormal number means we shift our output by 1 bit. - exponent += 1; - "0." - } else { - "1." - }; - - write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") -} - -#[cfg(feature = "compiler-builtins")] -fn fmt_any_hex(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() -} - -impl fmt::LowerHex for Hexf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt_any_hex(&self.0, f) - } - } - } -} - -impl fmt::LowerHex for Hexf<(F, F)> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) - } - } - } -} - -impl fmt::LowerHex for Hexf<(F, i32)> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) - } - } - } -} - -impl fmt::LowerHex for Hexf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(&self.0, f) - } - } - } -} - -impl fmt::Debug for Hexf -where - Hexf: fmt::LowerHex, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(self, f) - } - } - } -} - -impl fmt::Display for Hexf -where - Hexf: fmt::LowerHex, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(self, f) - } - } - } -} - -#[cfg(test)] -mod parse_tests { - extern crate std; - use std::{format, println}; - - use super::*; - - #[cfg(f16_enabled)] - fn rounding_properties(s: &str) -> Result<(), HexFloatParseError> { - let (xd, s0) = parse_any(s, 16, 10, Round::Negative)?; - let (xu, s1) = parse_any(s, 16, 10, Round::Positive)?; - let (xz, s2) = parse_any(s, 16, 10, Round::Zero)?; - let (xn, s3) = parse_any(s, 16, 10, Round::Nearest)?; - - // FIXME: A value between the least normal and largest subnormal - // could have underflow status depend on rounding mode. - - if let Status::OK = s0 { - // an exact result is the same for all rounding modes - assert_eq!(s0, s1); - assert_eq!(s0, s2); - assert_eq!(s0, s3); - - assert_eq!(xd, xu); - assert_eq!(xd, xz); - assert_eq!(xd, xn); - } else { - assert!([s0, s1, s2, s3].into_iter().all(Status::inexact)); - - let xd = f16::from_bits(xd as u16); - let xu = f16::from_bits(xu as u16); - let xz = f16::from_bits(xz as u16); - let xn = f16::from_bits(xn as u16); - - assert_biteq!(xd.next_up(), xu, "s={s}, xd={xd:?}, xu={xu:?}"); - - let signs = [xd, xu, xz, xn].map(f16::is_sign_negative); - - if signs == [true; 4] { - assert_biteq!(xz, xu); - } else { - assert_eq!(signs, [false; 4]); - assert_biteq!(xz, xd); - } - - if xn.to_bits() != xd.to_bits() { - assert_biteq!(xn, xu); - } - } - Ok(()) - } - #[test] - #[cfg(f16_enabled)] - fn test_rounding() { - let n = 1_i32 << 14; - for i in -n..n { - let u = i.rotate_right(11) as u32; - let s = format!("{}", Hexf(f32::from_bits(u))); - assert!(rounding_properties(&s).is_ok()); - } - } - - #[test] - fn test_parse_any() { - for k in -149..=127 { - let s = format!("0x1p{k}"); - let x = hf32(&s); - let y = if k < 0 { 0.5f32.powi(-k) } else { 2.0f32.powi(k) }; - assert_eq!(x, y); - } - - let mut s = *b"0x.0000000p-121"; - for e in 0..40 { - for k in 0..(1 << 15) { - let expected = f32::from_bits(k) * 2.0f32.powi(e); - let x = hf32(std::str::from_utf8(&s).unwrap()); - assert_eq!( - x.to_bits(), - expected.to_bits(), - "\ - e={e}\n\ - k={k}\n\ - x={x}\n\ - expected={expected}\n\ - s={}\n\ - f32::from_bits(k)={}\n\ - 2.0f32.powi(e)={}\ - ", - std::str::from_utf8(&s).unwrap(), - f32::from_bits(k), - 2.0f32.powi(e), - ); - for i in (3..10).rev() { - if s[i] == b'f' { - s[i] = b'0'; - } else if s[i] == b'9' { - s[i] = b'a'; - break; - } else { - s[i] += 1; - break; - } - } - } - for i in (12..15).rev() { - if s[i] == b'0' { - s[i] = b'9'; - } else { - s[i] -= 1; - break; - } - } - for i in (3..10).rev() { - s[i] = b'0'; - } - } - } - - // FIXME: this test is causing failures that are likely UB on various platforms - #[cfg(all(target_arch = "x86_64", target_os = "linux"))] - #[test] - #[cfg(f128_enabled)] - fn rounding() { - let pi = std::f128::consts::PI; - let s = format!("{}", Hexf(pi)); - - for k in 0..=111 { - let (bits, status) = parse_any(&s, 128 - k, 112 - k, Round::Nearest).unwrap(); - let scale = (1u128 << (112 - k - 1)) as f128; - let expected = (pi * scale).round_ties_even() / scale; - assert_eq!(bits << k, expected.to_bits(), "k = {k}, s = {s}"); - assert_eq!(expected != pi, status.inexact()); - } - } - #[test] - fn rounding_extreme_underflow() { - for k in 1..1000 { - let s = format!("0x1p{}", -149 - k); - let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; - assert_eq!(bits, 0, "{s} should round to zero, got bits={bits}"); - assert!(status.underflow(), "should indicate underflow when parsing {s}"); - assert!(status.inexact(), "should indicate inexact when parsing {s}"); - } - } - #[test] - fn long_tail() { - for k in 1..1000 { - let s = format!("0x1.{}p0", "0".repeat(k)); - let Ok(bits) = parse_hex_exact(&s, 32, 23) else { panic!("parsing {s} failed") }; - assert_eq!(f32::from_bits(bits as u32), 1.0); - - let s = format!("0x1.{}1p0", "0".repeat(k)); - let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; - if status.inexact() { - assert!(1.0 == f32::from_bits(bits as u32)); - } else { - assert!(1.0 < f32::from_bits(bits as u32)); - } - } - } - // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to - // hide them from the AST. - #[cfg(f16_enabled)] - macro_rules! f16_tests { - () => { - #[test] - fn test_f16() { - let checks = [ - ("0x.1234p+16", (0x1234 as f16).to_bits()), - ("0x1.234p+12", (0x1234 as f16).to_bits()), - ("0x12.34p+8", (0x1234 as f16).to_bits()), - ("0x123.4p+4", (0x1234 as f16).to_bits()), - ("0x1234p+0", (0x1234 as f16).to_bits()), - ("0x1234.p+0", (0x1234 as f16).to_bits()), - ("0x1234.0p+0", (0x1234 as f16).to_bits()), - ("0x1.ffcp+15", f16::MAX.to_bits()), - ("0x1.0p+1", 2.0f16.to_bits()), - ("0x1.0p+0", 1.0f16.to_bits()), - ("0x1.ffp+8", 0x5ffc), - ("+0x1.ffp+8", 0x5ffc), - ("0x1p+0", 0x3c00), - ("0x1.998p-4", 0x2e66), - ("0x1.9p+6", 0x5640), - ("0x0.0p0", 0.0f16.to_bits()), - ("-0x0.0p0", (-0.0f16).to_bits()), - ("0x1.0p0", 1.0f16.to_bits()), - ("0x1.998p-4", (0.1f16).to_bits()), - ("-0x1.998p-4", (-0.1f16).to_bits()), - ("0x0.123p-12", 0x0123), - ("0x1p-24", 0x0001), - ("nan", f16::NAN.to_bits()), - ("-nan", (-f16::NAN).to_bits()), - ("inf", f16::INFINITY.to_bits()), - ("-inf", f16::NEG_INFINITY.to_bits()), - ]; - for (s, exp) in checks { - println!("parsing {s}"); - assert!(rounding_properties(s).is_ok()); - let act = hf16(s).to_bits(); - assert_eq!( - act, exp, - "parsing {s}: {act:#06x} != {exp:#06x}\nact: {act:#018b}\nexp: {exp:#018b}" - ); - } - } - - #[test] - fn test_macros_f16() { - assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); - } - }; - } - - #[cfg(f16_enabled)] - f16_tests!(); - - #[test] - fn test_f32() { - let checks = [ - ("0x.1234p+16", (0x1234 as f32).to_bits()), - ("0x1.234p+12", (0x1234 as f32).to_bits()), - ("0x12.34p+8", (0x1234 as f32).to_bits()), - ("0x123.4p+4", (0x1234 as f32).to_bits()), - ("0x1234p+0", (0x1234 as f32).to_bits()), - ("0x1234.p+0", (0x1234 as f32).to_bits()), - ("0x1234.0p+0", (0x1234 as f32).to_bits()), - ("0x1.fffffep+127", f32::MAX.to_bits()), - ("0x1.0p+1", 2.0f32.to_bits()), - ("0x1.0p+0", 1.0f32.to_bits()), - ("0x1.ffep+8", 0x43fff000), - ("+0x1.ffep+8", 0x43fff000), - ("0x1p+0", 0x3f800000), - ("0x1.99999ap-4", 0x3dcccccd), - ("0x1.9p+6", 0x42c80000), - ("0x1.2d5ed2p+20", 0x4996af69), - ("-0x1.348eb8p+10", 0xc49a475c), - ("-0x1.33dcfep-33", 0xaf19ee7f), - ("0x0.0p0", 0.0f32.to_bits()), - ("-0x0.0p0", (-0.0f32).to_bits()), - ("0x1.0p0", 1.0f32.to_bits()), - ("0x1.99999ap-4", (0.1f32).to_bits()), - ("-0x1.99999ap-4", (-0.1f32).to_bits()), - ("0x1.111114p-127", 0x00444445), - ("0x1.23456p-130", 0x00091a2b), - ("0x1p-149", 0x00000001), - ("nan", f32::NAN.to_bits()), - ("-nan", (-f32::NAN).to_bits()), - ("inf", f32::INFINITY.to_bits()), - ("-inf", f32::NEG_INFINITY.to_bits()), - ]; - for (s, exp) in checks { - println!("parsing {s}"); - let act = hf32(s).to_bits(); - assert_eq!( - act, exp, - "parsing {s}: {act:#010x} != {exp:#010x}\nact: {act:#034b}\nexp: {exp:#034b}" - ); - } - } - - #[test] - fn test_f64() { - let checks = [ - ("0x.1234p+16", (0x1234 as f64).to_bits()), - ("0x1.234p+12", (0x1234 as f64).to_bits()), - ("0x12.34p+8", (0x1234 as f64).to_bits()), - ("0x123.4p+4", (0x1234 as f64).to_bits()), - ("0x1234p+0", (0x1234 as f64).to_bits()), - ("0x1234.p+0", (0x1234 as f64).to_bits()), - ("0x1234.0p+0", (0x1234 as f64).to_bits()), - ("0x1.ffep+8", 0x407ffe0000000000), - ("0x1p+0", 0x3ff0000000000000), - ("0x1.999999999999ap-4", 0x3fb999999999999a), - ("0x1.9p+6", 0x4059000000000000), - ("0x1.2d5ed1fe1da7bp+20", 0x4132d5ed1fe1da7b), - ("-0x1.348eb851eb852p+10", 0xc09348eb851eb852), - ("-0x1.33dcfe54a3803p-33", 0xbde33dcfe54a3803), - ("0x1.0p0", 1.0f64.to_bits()), - ("0x0.0p0", 0.0f64.to_bits()), - ("-0x0.0p0", (-0.0f64).to_bits()), - ("0x1.999999999999ap-4", 0.1f64.to_bits()), - ("0x1.999999999998ap-4", (0.1f64 - f64::EPSILON).to_bits()), - ("-0x1.999999999999ap-4", (-0.1f64).to_bits()), - ("-0x1.999999999998ap-4", (-0.1f64 + f64::EPSILON).to_bits()), - ("0x0.8000000000001p-1022", 0x0008000000000001), - ("0x0.123456789abcdp-1022", 0x000123456789abcd), - ("0x0.0000000000002p-1022", 0x0000000000000002), - ("nan", f64::NAN.to_bits()), - ("-nan", (-f64::NAN).to_bits()), - ("inf", f64::INFINITY.to_bits()), - ("-inf", f64::NEG_INFINITY.to_bits()), - ]; - for (s, exp) in checks { - println!("parsing {s}"); - let act = hf64(s).to_bits(); - assert_eq!( - act, exp, - "parsing {s}: {act:#018x} != {exp:#018x}\nact: {act:#066b}\nexp: {exp:#066b}" - ); - } - } - - // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to - // hide them from the AST. - #[cfg(f128_enabled)] - macro_rules! f128_tests { - () => { - #[test] - fn test_f128() { - let checks = [ - ("0x.1234p+16", (0x1234 as f128).to_bits()), - ("0x1.234p+12", (0x1234 as f128).to_bits()), - ("0x12.34p+8", (0x1234 as f128).to_bits()), - ("0x123.4p+4", (0x1234 as f128).to_bits()), - ("0x1234p+0", (0x1234 as f128).to_bits()), - ("0x1234.p+0", (0x1234 as f128).to_bits()), - ("0x1234.0p+0", (0x1234 as f128).to_bits()), - ("0x1.ffffffffffffffffffffffffffffp+16383", f128::MAX.to_bits()), - ("0x1.0p+1", 2.0f128.to_bits()), - ("0x1.0p+0", 1.0f128.to_bits()), - ("0x1.ffep+8", 0x4007ffe0000000000000000000000000), - ("+0x1.ffep+8", 0x4007ffe0000000000000000000000000), - ("0x1p+0", 0x3fff0000000000000000000000000000), - ("0x1.999999999999999999999999999ap-4", 0x3ffb999999999999999999999999999a), - ("0x1.9p+6", 0x40059000000000000000000000000000), - ("0x0.0p0", 0.0f128.to_bits()), - ("-0x0.0p0", (-0.0f128).to_bits()), - ("0x1.0p0", 1.0f128.to_bits()), - ("0x1.999999999999999999999999999ap-4", (0.1f128).to_bits()), - ("-0x1.999999999999999999999999999ap-4", (-0.1f128).to_bits()), - ("0x0.abcdef0123456789abcdef012345p-16382", 0x0000abcdef0123456789abcdef012345), - ("0x1p-16494", 0x00000000000000000000000000000001), - ("nan", f128::NAN.to_bits()), - ("-nan", (-f128::NAN).to_bits()), - ("inf", f128::INFINITY.to_bits()), - ("-inf", f128::NEG_INFINITY.to_bits()), - ]; - for (s, exp) in checks { - println!("parsing {s}"); - let act = hf128(s).to_bits(); - assert_eq!( - act, exp, - "parsing {s}: {act:#034x} != {exp:#034x}\nact: {act:#0130b}\nexp: {exp:#0130b}" - ); - } - } - - #[test] - fn test_macros_f128() { - assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); - } - } - } - - #[cfg(f128_enabled)] - f128_tests!(); - - #[test] - fn test_macros() { - #[cfg(f16_enabled)] - assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); - assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000_u32); - assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000_u64); - #[cfg(f128_enabled)] - assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); - } -} - -#[cfg(test)] -// FIXME(ppc): something with `should_panic` tests cause a SIGILL with ppc64le -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] -mod tests_panicking { - extern crate std; - use super::*; - - // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to - // hide them from the AST. - #[cfg(f16_enabled)] - macro_rules! f16_tests { - () => { - #[test] - fn test_f16_almost_extra_precision() { - // Exact maximum precision allowed - hf16("0x1.ffcp+0"); - } - - #[test] - #[should_panic(expected = "the value is too precise")] - fn test_f16_extra_precision() { - // One bit more than the above. - hf16("0x1.ffdp+0"); - } - - #[test] - #[should_panic(expected = "the value is too huge")] - fn test_f16_overflow() { - // One bit more than the above. - hf16("0x1p+16"); - } - - #[test] - fn test_f16_tiniest() { - let x = hf16("0x1.p-24"); - let y = hf16("0x0.001p-12"); - let z = hf16("0x0.8p-23"); - assert_eq!(x, y); - assert_eq!(x, z); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f16_too_tiny() { - hf16("0x1.p-25"); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f16_also_too_tiny() { - hf16("0x0.8p-24"); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f16_again_too_tiny() { - hf16("0x0.001p-13"); - } - }; - } - - #[cfg(f16_enabled)] - f16_tests!(); - - #[test] - fn test_f32_almost_extra_precision() { - // Exact maximum precision allowed - hf32("0x1.abcdeep+0"); - } - - #[test] - #[should_panic] - fn test_f32_extra_precision2() { - // One bit more than the above. - hf32("0x1.ffffffp+127"); - } - - #[test] - #[should_panic(expected = "the value is too huge")] - fn test_f32_overflow() { - // One bit more than the above. - hf32("0x1p+128"); - } - - #[test] - #[should_panic(expected = "the value is too precise")] - fn test_f32_extra_precision() { - // One bit more than the above. - hf32("0x1.abcdefp+0"); - } - - #[test] - fn test_f32_tiniest() { - let x = hf32("0x1.p-149"); - let y = hf32("0x0.0000000000000001p-85"); - let z = hf32("0x0.8p-148"); - assert_eq!(x, y); - assert_eq!(x, z); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f32_too_tiny() { - hf32("0x1.p-150"); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f32_also_too_tiny() { - hf32("0x0.8p-149"); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f32_again_too_tiny() { - hf32("0x0.0000000000000001p-86"); - } - - #[test] - fn test_f64_almost_extra_precision() { - // Exact maximum precision allowed - hf64("0x1.abcdabcdabcdfp+0"); - } - - #[test] - #[should_panic(expected = "the value is too precise")] - fn test_f64_extra_precision() { - // One bit more than the above. - hf64("0x1.abcdabcdabcdf8p+0"); - } - - // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to - // hide them from the AST. - #[cfg(f128_enabled)] - macro_rules! f128_tests { - () => { - #[test] - fn test_f128_almost_extra_precision() { - // Exact maximum precision allowed - hf128("0x1.ffffffffffffffffffffffffffffp+16383"); - } - - #[test] - #[should_panic(expected = "the value is too precise")] - fn test_f128_extra_precision() { - // Just below the maximum finite. - hf128("0x1.fffffffffffffffffffffffffffe8p+16383"); - } - #[test] - #[should_panic(expected = "the value is too huge")] - fn test_f128_extra_precision_overflow() { - // One bit more than the above. Should overflow. - hf128("0x1.ffffffffffffffffffffffffffff8p+16383"); - } - - #[test] - #[should_panic(expected = "the value is too huge")] - fn test_f128_overflow() { - // One bit more than the above. - hf128("0x1p+16384"); - } - - #[test] - fn test_f128_tiniest() { - let x = hf128("0x1.p-16494"); - let y = hf128("0x0.0000000000000001p-16430"); - let z = hf128("0x0.8p-16493"); - assert_eq!(x, y); - assert_eq!(x, z); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f128_too_tiny() { - hf128("0x1.p-16495"); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f128_again_too_tiny() { - hf128("0x0.0000000000000001p-16431"); - } - - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f128_also_too_tiny() { - hf128("0x0.8p-16494"); - } - }; - } - - #[cfg(f128_enabled)] - f128_tests!(); -} - -#[cfg(test)] -mod print_tests { - extern crate std; - use std::string::ToString; - - use super::*; - - #[test] - #[cfg(f16_enabled)] - fn test_f16() { - use std::format; - // Exhaustively check that `f16` roundtrips. - for x in 0..=u16::MAX { - let f = f16::from_bits(x); - let s = format!("{}", Hexf(f)); - let from_s = hf16(&s); - - if f.is_nan() && from_s.is_nan() { - continue; - } - - assert_eq!( - f.to_bits(), - from_s.to_bits(), - "{f:?} formatted as {s} but parsed as {from_s:?}" - ); - } - } - - #[test] - #[cfg(f16_enabled)] - fn test_f16_to_f32() { - use std::format; - // Exhaustively check that these are equivalent for all `f16`: - // - `f16 -> f32` - // - `f16 -> str -> f32` - // - `f16 -> f32 -> str -> f32` - // - `f16 -> f32 -> str -> f16 -> f32` - for x in 0..=u16::MAX { - let f16 = f16::from_bits(x); - let s16 = format!("{}", Hexf(f16)); - let f32 = f16 as f32; - let s32 = format!("{}", Hexf(f32)); - - let a = hf32(&s16); - let b = hf32(&s32); - let c = hf16(&s32); - - if f32.is_nan() && a.is_nan() && b.is_nan() && c.is_nan() { - continue; - } - - assert_eq!( - f32.to_bits(), - a.to_bits(), - "{f16:?} : f16 formatted as {s16} which parsed as {a:?} : f16" - ); - assert_eq!( - f32.to_bits(), - b.to_bits(), - "{f32:?} : f32 formatted as {s32} which parsed as {b:?} : f32" - ); - assert_eq!( - f32.to_bits(), - (c as f32).to_bits(), - "{f32:?} : f32 formatted as {s32} which parsed as {c:?} : f16" - ); - } - } - #[test] - fn spot_checks() { - assert_eq!(Hexf(f32::MAX).to_string(), "0x1.fffffep+127"); - assert_eq!(Hexf(f64::MAX).to_string(), "0x1.fffffffffffffp+1023"); - - assert_eq!(Hexf(f32::MIN).to_string(), "-0x1.fffffep+127"); - assert_eq!(Hexf(f64::MIN).to_string(), "-0x1.fffffffffffffp+1023"); - - assert_eq!(Hexf(f32::ZERO).to_string(), "0x0p+0"); - assert_eq!(Hexf(f64::ZERO).to_string(), "0x0p+0"); - - assert_eq!(Hexf(f32::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hexf(f64::NEG_ZERO).to_string(), "-0x0p+0"); - - assert_eq!(Hexf(f32::NAN).to_string(), "NaN"); - assert_eq!(Hexf(f64::NAN).to_string(), "NaN"); - - assert_eq!(Hexf(f32::INFINITY).to_string(), "inf"); - assert_eq!(Hexf(f64::INFINITY).to_string(), "inf"); - - assert_eq!(Hexf(f32::NEG_INFINITY).to_string(), "-inf"); - assert_eq!(Hexf(f64::NEG_INFINITY).to_string(), "-inf"); - - #[cfg(f16_enabled)] - { - assert_eq!(Hexf(f16::MAX).to_string(), "0x1.ffcp+15"); - assert_eq!(Hexf(f16::MIN).to_string(), "-0x1.ffcp+15"); - assert_eq!(Hexf(f16::ZERO).to_string(), "0x0p+0"); - assert_eq!(Hexf(f16::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hexf(f16::NAN).to_string(), "NaN"); - assert_eq!(Hexf(f16::INFINITY).to_string(), "inf"); - assert_eq!(Hexf(f16::NEG_INFINITY).to_string(), "-inf"); - } - - #[cfg(f128_enabled)] - { - assert_eq!(Hexf(f128::MAX).to_string(), "0x1.ffffffffffffffffffffffffffffp+16383"); - assert_eq!(Hexf(f128::MIN).to_string(), "-0x1.ffffffffffffffffffffffffffffp+16383"); - assert_eq!(Hexf(f128::ZERO).to_string(), "0x0p+0"); - assert_eq!(Hexf(f128::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hexf(f128::NAN).to_string(), "NaN"); - assert_eq!(Hexf(f128::INFINITY).to_string(), "inf"); - assert_eq!(Hexf(f128::NEG_INFINITY).to_string(), "-inf"); - } - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/libm/src/math/support/int_traits.rs deleted file mode 100644 index 491adb1f22c..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/support/int_traits.rs +++ /dev/null @@ -1,451 +0,0 @@ -use core::{cmp, fmt, ops}; - -/// Minimal integer implementations needed on all integer types, including wide integers. -pub trait MinInt: - Copy - + fmt::Debug - + ops::BitOr - + ops::Not - + ops::Shl -{ - /// Type with the same width but other signedness - type OtherSign: MinInt; - /// Unsigned version of Self - type Unsigned: MinInt; - - /// If `Self` is a signed integer - const SIGNED: bool; - - /// The bitwidth of the int type - const BITS: u32; - - const ZERO: Self; - const ONE: Self; - const MIN: Self; - const MAX: Self; -} - -/// Access the associated `OtherSign` type from an int (helper to avoid ambiguous associated -/// types). -pub type OtherSign = ::OtherSign; - -/// Trait for some basic operations on integers -#[allow(dead_code)] -pub trait Int: - MinInt - + fmt::Display - + fmt::Binary - + fmt::LowerHex - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Shl - + ops::Shl - + ops::Shr - + ops::Shr - + ops::BitXor - + ops::BitAnd - + cmp::Ord - + From - + CastFrom - + CastFrom - + CastFrom - + CastFrom - + CastFrom - + CastInto - + CastInto - + CastInto - + CastInto - + CastInto -{ - fn signed(self) -> OtherSign; - fn unsigned(self) -> Self::Unsigned; - fn from_unsigned(unsigned: Self::Unsigned) -> Self; - fn abs(self) -> Self; - - fn from_bool(b: bool) -> Self; - - /// Prevents the need for excessive conversions between signed and unsigned - fn logical_shr(self, other: u32) -> Self; - - /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::Unsigned; - - // copied from primitive integers, but put in a trait - fn is_zero(self) -> bool; - fn checked_add(self, other: Self) -> Option; - fn checked_sub(self, other: Self) -> Option; - fn wrapping_neg(self) -> Self; - fn wrapping_add(self, other: Self) -> Self; - fn wrapping_mul(self, other: Self) -> Self; - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn overflowing_sub(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - fn ilog2(self) -> u32; -} - -macro_rules! int_impl_common { - ($ty:ty) => { - fn from_bool(b: bool) -> Self { - b as $ty - } - - fn logical_shr(self, other: u32) -> Self { - Self::from_unsigned(self.unsigned().wrapping_shr(other)) - } - - fn is_zero(self) -> bool { - self == Self::ZERO - } - - fn checked_add(self, other: Self) -> Option { - self.checked_add(other) - } - - fn checked_sub(self, other: Self) -> Option { - self.checked_sub(other) - } - - fn wrapping_neg(self) -> Self { - ::wrapping_neg(self) - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn wrapping_shr(self, other: u32) -> Self { - ::wrapping_shr(self, other) - } - - fn rotate_left(self, other: u32) -> Self { - ::rotate_left(self, other) - } - - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } - - fn overflowing_sub(self, other: Self) -> (Self, bool) { - ::overflowing_sub(self, other) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - - fn ilog2(self) -> u32 { - // On our older MSRV, this resolves to the trait method. Which won't actually work, - // but this is only called behind other gates. - #[allow(clippy::incompatible_msrv)] - ::ilog2(self) - } - }; -} - -macro_rules! int_impl { - ($ity:ty, $uty:ty) => { - impl MinInt for $uty { - type OtherSign = $ity; - type Unsigned = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $uty { - fn signed(self) -> $ity { - self as $ity - } - - fn unsigned(self) -> Self { - self - } - - fn abs(self) -> Self { - unimplemented!() - } - - // It makes writing macros easier if this is implemented for both signed and unsigned - #[allow(clippy::wrong_self_convention)] - fn from_unsigned(me: $uty) -> Self { - me - } - - fn abs_diff(self, other: Self) -> Self { - self.abs_diff(other) - } - - int_impl_common!($uty); - } - - impl MinInt for $ity { - type OtherSign = $uty; - type Unsigned = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $ity { - fn signed(self) -> Self { - self - } - - fn unsigned(self) -> $uty { - self as $uty - } - - fn abs(self) -> Self { - self.abs() - } - - fn from_unsigned(me: $uty) -> Self { - me as $ity - } - - fn abs_diff(self, other: Self) -> $uty { - self.abs_diff(other) - } - - int_impl_common!($ity); - } - }; -} - -int_impl!(isize, usize); -int_impl!(i8, u8); -int_impl!(i16, u16); -int_impl!(i32, u32); -int_impl!(i64, u64); -int_impl!(i128, u128); - -/// Trait for integers twice the bit width of another integer. This is implemented for all -/// primitives except for `u8`, because there is not a smaller primitive. -pub trait DInt: MinInt { - /// Integer that is half the bit width of the integer this trait is implemented for - type H: HInt; - - /// Returns the low half of `self` - fn lo(self) -> Self::H; - /// Returns the high half of `self` - fn hi(self) -> Self::H; - /// Returns the low and high halves of `self` as a tuple - fn lo_hi(self) -> (Self::H, Self::H) { - (self.lo(), self.hi()) - } - /// Constructs an integer using lower and higher half parts - #[allow(unused)] - fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { - lo.zero_widen() | hi.widen_hi() - } -} - -/// Trait for integers half the bit width of another integer. This is implemented for all -/// primitives except for `u128`, because it there is not a larger primitive. -pub trait HInt: Int { - /// Integer that is double the bit width of the integer this trait is implemented for - type D: DInt + MinInt; - - // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for - // unknown reasons this can cause infinite recursion when optimizations are disabled. See - // for context. - - /// Widens (using default extension) the integer to have double bit width - fn widen(self) -> Self::D; - /// Widens (zero extension only) the integer to have double bit width. This is needed to get - /// around problems with associated type bounds (such as `Int`) being unstable - fn zero_widen(self) -> Self::D; - /// Widens the integer to have double bit width and shifts the integer into the higher bits - #[allow(unused)] - fn widen_hi(self) -> Self::D; - /// Widening multiplication with zero widening. This cannot overflow. - fn zero_widen_mul(self, rhs: Self) -> Self::D; - /// Widening multiplication. This cannot overflow. - fn widen_mul(self, rhs: Self) -> Self::D; -} - -macro_rules! impl_d_int { - ($($X:ident $D:ident),*) => { - $( - impl DInt for $D { - type H = $X; - - fn lo(self) -> Self::H { - self as $X - } - fn hi(self) -> Self::H { - (self >> <$X as MinInt>::BITS) as $X - } - } - )* - }; -} - -macro_rules! impl_h_int { - ($($H:ident $uH:ident $X:ident),*) => { - $( - impl HInt for $H { - type D = $X; - - fn widen(self) -> Self::D { - self as $X - } - fn zero_widen(self) -> Self::D { - (self as $uH) as $X - } - fn zero_widen_mul(self, rhs: Self) -> Self::D { - self.zero_widen().wrapping_mul(rhs.zero_widen()) - } - fn widen_mul(self, rhs: Self) -> Self::D { - self.widen().wrapping_mul(rhs.widen()) - } - fn widen_hi(self) -> Self::D { - (self as $X) << ::BITS - } - } - )* - }; -} - -impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); -impl_h_int!( - u8 u8 u16, - u16 u16 u32, - u32 u32 u64, - u64 u64 u128, - i8 u8 i16, - i16 u16 i32, - i32 u32 i64, - i64 u64 i128 -); - -/// Trait to express (possibly lossy) casting of integers -pub trait CastInto: Copy { - /// By default, casts should be exact. - fn cast(self) -> T; - - /// Call for casts that are expected to truncate. - fn cast_lossy(self) -> T; -} - -pub trait CastFrom: Copy { - /// By default, casts should be exact. - fn cast_from(value: T) -> Self; - - /// Call for casts that are expected to truncate. - fn cast_from_lossy(value: T) -> Self; -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } - - fn cast_from_lossy(value: U) -> Self { - value.cast_lossy() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - // All we can really do to enforce casting rules is check the rules when in - // debug mode. - #[cfg(not(feature = "compiler-builtins"))] - debug_assert!(<$into>::try_from(self).is_ok(), "failed cast from {self}"); - self as $into - } - - fn cast_lossy(self) -> $into { - self as $into - } - } - )*}; -} - -macro_rules! cast_into_float { - ($ty:ty) => { - #[cfg(f16_enabled)] - cast_into_float!($ty; f16); - - cast_into_float!($ty; f32, f64); - - #[cfg(f128_enabled)] - cast_into_float!($ty; f128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - #[cfg(not(feature = "compiler-builtins"))] - debug_assert_eq!(self as $into as $ty, self, "inexact float cast"); - self as $into - } - - fn cast_lossy(self) -> $into { - self as $into - } - } - )*}; -} - -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); - -cast_into_float!(i8); -cast_into_float!(i16); -cast_into_float!(i32); -cast_into_float!(i64); -cast_into_float!(i128); diff --git a/library/compiler-builtins/libm/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/libm/src/math/support/macros.rs deleted file mode 100644 index 0b72db0e46e..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/support/macros.rs +++ /dev/null @@ -1,157 +0,0 @@ -/// `libm` cannot have dependencies, so this is vendored directly from the `cfg-if` crate -/// (with some comments stripped for compactness). -macro_rules! cfg_if { - // match if/else chains with a final `else` - ($( - if #[cfg($meta:meta)] { $($tokens:tt)* } - ) else * else { - $($tokens2:tt)* - }) => { - cfg_if! { @__items () ; $( ( ($meta) ($($tokens)*) ), )* ( () ($($tokens2)*) ), } - }; - - // match if/else chains lacking a final `else` - ( - if #[cfg($i_met:meta)] { $($i_tokens:tt)* } - $( else if #[cfg($e_met:meta)] { $($e_tokens:tt)* } )* - ) => { - cfg_if! { - @__items - () ; - ( ($i_met) ($($i_tokens)*) ), - $( ( ($e_met) ($($e_tokens)*) ), )* - ( () () ), - } - }; - - // Internal and recursive macro to emit all the items - // - // Collects all the negated cfgs in a list at the beginning and after the - // semicolon is all the remaining items - (@__items ($($not:meta,)*) ; ) => {}; - (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($tokens:tt)*) ), $($rest:tt)*) => { - #[cfg(all($($m,)* not(any($($not),*))))] cfg_if! { @__identity $($tokens)* } - cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } - }; - - // Internal macro to make __apply work out right for different match types, - // because of how macros matching/expand stuff. - (@__identity $($tokens:tt)*) => { $($tokens)* }; -} - -/// Choose between using an arch-specific implementation and the function body. Returns directly -/// if the arch implementation is used, otherwise continue with the rest of the function. -/// -/// Specify a `use_arch` meta field if an architecture-specific implementation is provided. -/// These live in the `math::arch::some_target_arch` module. -/// -/// Specify a `use_arch_required` meta field if something architecture-specific must be used -/// regardless of feature configuration (`force-soft-floats`). -/// -/// The passed meta options do not need to account for the `arch` target feature. -macro_rules! select_implementation { - ( - name: $fn_name:ident, - // Configuration meta for when to use arch-specific implementation that requires hard - // float ops - $( use_arch: $use_arch:meta, )? - // Configuration meta for when to use the arch module regardless of whether softfloats - // have been requested. - $( use_arch_required: $use_arch_required:meta, )? - args: $($arg:ident),+ , - ) => { - // FIXME: these use paths that are a pretty fragile (`super`). We should figure out - // something better w.r.t. how this is vendored into compiler-builtins. - - // However, we do need a few things from `arch` that are used even with soft floats. - select_implementation! { - @cfg $($use_arch_required)?; - if true { - return super::arch::$fn_name( $($arg),+ ); - } - } - - // By default, never use arch-specific implementations if we have force-soft-floats - #[cfg(arch_enabled)] - select_implementation! { - @cfg $($use_arch)?; - // Wrap in `if true` to avoid unused warnings - if true { - return super::arch::$fn_name( $($arg),+ ); - } - } - }; - - // Coalesce helper to construct an expression only if a config is provided - (@cfg ; $ex:expr) => { }; - (@cfg $provided:meta; $ex:expr) => { #[cfg($provided)] $ex }; -} - -/// Construct a 16-bit float from hex float representation (C-style), guaranteed to -/// evaluate at compile time. -#[cfg(f16_enabled)] -#[cfg_attr(feature = "unstable-public-internals", macro_export)] -#[allow(unused_macros)] -macro_rules! hf16 { - ($s:literal) => {{ - const X: f16 = $crate::support::hf16($s); - X - }}; -} - -/// Construct a 32-bit float from hex float representation (C-style), guaranteed to -/// evaluate at compile time. -#[allow(unused_macros)] -#[cfg_attr(feature = "unstable-public-internals", macro_export)] -macro_rules! hf32 { - ($s:literal) => {{ - const X: f32 = $crate::support::hf32($s); - X - }}; -} - -/// Construct a 64-bit float from hex float representation (C-style), guaranteed to -/// evaluate at compile time. -#[allow(unused_macros)] -#[cfg_attr(feature = "unstable-public-internals", macro_export)] -macro_rules! hf64 { - ($s:literal) => {{ - const X: f64 = $crate::support::hf64($s); - X - }}; -} - -/// Construct a 128-bit float from hex float representation (C-style), guaranteed to -/// evaluate at compile time. -#[cfg(f128_enabled)] -#[allow(unused_macros)] -#[cfg_attr(feature = "unstable-public-internals", macro_export)] -macro_rules! hf128 { - ($s:literal) => {{ - const X: f128 = $crate::support::hf128($s); - X - }}; -} - -/// Assert `F::biteq` with better messages. -#[cfg(test)] -macro_rules! assert_biteq { - ($left:expr, $right:expr, $($tt:tt)*) => {{ - use $crate::support::Int; - let l = $left; - let r = $right; - let bits = Int::leading_zeros(l.to_bits() - l.to_bits()); // hack to get the width from the value - assert!( - l.biteq(r), - "{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", - format_args!($($tt)*), - lb = l.to_bits(), - rb = r.to_bits(), - width = ((bits / 4) + 2) as usize, - - ); - }}; - ($left:expr, $right:expr $(,)?) => { - assert_biteq!($left, $right, "") - }; -} diff --git a/library/compiler-builtins/libm/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/libm/src/math/support/mod.rs deleted file mode 100644 index ee3f2bbdf02..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/support/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -#[macro_use] -pub mod macros; -mod big; -mod env; -mod float_traits; -pub mod hex_float; -mod int_traits; - -#[allow(unused_imports)] -pub use big::{i256, u256}; -pub use env::{FpResult, Round, Status}; -#[allow(unused_imports)] -pub use float_traits::{DFloat, Float, HFloat, IntTy}; -pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; -#[cfg(f16_enabled)] -#[allow(unused_imports)] -pub use hex_float::hf16; -#[cfg(f128_enabled)] -#[allow(unused_imports)] -pub use hex_float::hf128; -#[allow(unused_imports)] -pub use hex_float::{Hexf, hf32, hf64}; -pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; - -/// Hint to the compiler that the current path is cold. -pub fn cold_path() { - #[cfg(intrinsics_enabled)] - core::intrinsics::cold_path(); -} diff --git a/library/compiler-builtins/libm/libm/src/math/tan.rs b/library/compiler-builtins/libm/libm/src/math/tan.rs deleted file mode 100644 index a074ca5540a..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/tan.rs +++ /dev/null @@ -1,70 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */ -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunPro, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -use super::{k_tan, rem_pio2}; - -// tan(x) -// Return tangent function of x. -// -// kernel function: -// k_tan ... tangent function on [-pi/4,pi/4] -// rem_pio2 ... argument reduction routine -// -// Method. -// Let S,C and T denote the sin, cos and tan respectively on -// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 -// in [-pi/4 , +pi/4], and let n = k mod 4. -// We have -// -// n sin(x) cos(x) tan(x) -// ---------------------------------------------------------- -// 0 S C T -// 1 C -S -1/T -// 2 -S -C T -// 3 -C S -1/T -// ---------------------------------------------------------- -// -// Special cases: -// Let trig be any of sin, cos, or tan. -// trig(+-INF) is NaN, with signals; -// trig(NaN) is that NaN; -// -// Accuracy: -// TRIG(x) returns trig(x) nearly rounded - -/// The tangent of `x` (f64). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tan(x: f64) -> f64 { - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; - /* |x| ~< pi/4 */ - if ix <= 0x3fe921fb { - if ix < 0x3e400000 { - /* |x| < 2**-27 */ - /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00100000 { x / x1p120 as f64 } else { x + x1p120 as f64 }); - return x; - } - return k_tan(x, 0.0, 0); - } - - /* tan(Inf or NaN) is NaN */ - if ix >= 0x7ff00000 { - return x - x; - } - - /* argument reduction */ - let (n, y0, y1) = rem_pio2(x); - k_tan(y0, y1, n & 1) -} diff --git a/library/compiler-builtins/libm/libm/src/math/tanf.rs b/library/compiler-builtins/libm/libm/src/math/tanf.rs deleted file mode 100644 index 7586aae4c7e..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/tanf.rs +++ /dev/null @@ -1,77 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_tanf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -use core::f64::consts::FRAC_PI_2; - -use super::{k_tanf, rem_pio2f}; - -/* Small multiples of pi/2 rounded to double precision. */ -const T1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ -const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ - -/// The tangent of `x` (f32). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tanf(x: f32) -> f32 { - let x64 = x as f64; - - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - if ix <= 0x3f490fda { - /* |x| ~<= pi/4 */ - if ix < 0x39800000 { - /* |x| < 2**-12 */ - /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); - return x; - } - return k_tanf(x64, false); - } - if ix <= 0x407b53d1 { - /* |x| ~<= 5*pi/4 */ - if ix <= 0x4016cbe3 { - /* |x| ~<= 3pi/4 */ - return k_tanf(if sign { x64 + T1_PIO2 } else { x64 - T1_PIO2 }, true); - } else { - return k_tanf(if sign { x64 + T2_PIO2 } else { x64 - T2_PIO2 }, false); - } - } - if ix <= 0x40e231d5 { - /* |x| ~<= 9*pi/4 */ - if ix <= 0x40afeddf { - /* |x| ~<= 7*pi/4 */ - return k_tanf(if sign { x64 + T3_PIO2 } else { x64 - T3_PIO2 }, true); - } else { - return k_tanf(if sign { x64 + T4_PIO2 } else { x64 - T4_PIO2 }, false); - } - } - - /* tan(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - return x - x; - } - - /* argument reduction */ - let (n, y) = rem_pio2f(x); - k_tanf(y, n & 1 != 0) -} diff --git a/library/compiler-builtins/libm/libm/src/math/tanh.rs b/library/compiler-builtins/libm/libm/src/math/tanh.rs deleted file mode 100644 index cc0abe4fcb2..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/tanh.rs +++ /dev/null @@ -1,53 +0,0 @@ -use super::expm1; - -/* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) - * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) - * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) - */ - -/// The hyperbolic tangent of `x` (f64). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tanh(mut x: f64) -> f64 { - let mut uf: f64 = x; - let mut ui: u64 = f64::to_bits(uf); - - let w: u32; - let sign: bool; - let mut t: f64; - - /* x = |x| */ - sign = ui >> 63 != 0; - ui &= !1 / 2; - uf = f64::from_bits(ui); - x = uf; - w = (ui >> 32) as u32; - - if w > 0x3fe193ea { - /* |x| > log(3)/2 ~= 0.5493 or nan */ - if w > 0x40340000 { - /* |x| > 20 or nan */ - /* note: this branch avoids raising overflow */ - t = 1.0 - 0.0 / x; - } else { - t = expm1(2.0 * x); - t = 1.0 - 2.0 / (t + 2.0); - } - } else if w > 0x3fd058ae { - /* |x| > log(5/3)/2 ~= 0.2554 */ - t = expm1(2.0 * x); - t = t / (t + 2.0); - } else if w >= 0x00100000 { - /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ - t = expm1(-2.0 * x); - t = -t / (t + 2.0); - } else { - /* |x| is subnormal */ - /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ - force_eval!(x as f32); - t = x; - } - - if sign { -t } else { t } -} diff --git a/library/compiler-builtins/libm/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/libm/src/math/tanhf.rs deleted file mode 100644 index fffbba6c6ec..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/tanhf.rs +++ /dev/null @@ -1,38 +0,0 @@ -use super::expm1f; - -/// The hyperbolic tangent of `x` (f32). -/// -/// `x` is specified in radians. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tanhf(mut x: f32) -> f32 { - /* x = |x| */ - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - x = f32::from_bits(ix); - let w = ix; - - let tt = if w > 0x3f0c9f54 { - /* |x| > log(3)/2 ~= 0.5493 or nan */ - if w > 0x41200000 { - /* |x| > 10 */ - 1. + 0. / x - } else { - let t = expm1f(2. * x); - 1. - 2. / (t + 2.) - } - } else if w > 0x3e82c578 { - /* |x| > log(5/3)/2 ~= 0.2554 */ - let t = expm1f(2. * x); - t / (t + 2.) - } else if w >= 0x00800000 { - /* |x| >= 0x1p-126 */ - let t = expm1f(-2. * x); - -t / (t + 2.) - } else { - /* |x| is subnormal */ - force_eval!(x * x); - x - }; - if sign { -tt } else { tt } -} diff --git a/library/compiler-builtins/libm/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/libm/src/math/tgamma.rs deleted file mode 100644 index 3059860646a..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/tgamma.rs +++ /dev/null @@ -1,209 +0,0 @@ -/* -"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) -"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) -"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) - -approximation method: - - (x - 0.5) S(x) -Gamma(x) = (x + g - 0.5) * ---------------- - exp(x + g - 0.5) - -with - a1 a2 a3 aN -S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] - x + 1 x + 2 x + 3 x + N - -with a0, a1, a2, a3,.. aN constants which depend on g. - -for x < 0 the following reflection formula is used: - -Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) - -most ideas and constants are from boost and python -*/ -use super::{exp, floor, k_cos, k_sin, pow}; - -const PI: f64 = 3.141592653589793238462643383279502884; - -/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ -fn sinpi(mut x: f64) -> f64 { - let mut n: isize; - - /* argument reduction: x = |x| mod 2 */ - /* spurious inexact when x is odd int */ - x = x * 0.5; - x = 2.0 * (x - floor(x)); - - /* reduce x into [-.25,.25] */ - n = (4.0 * x) as isize; - n = div!(n + 1, 2); - x -= (n as f64) * 0.5; - - x *= PI; - match n { - 1 => k_cos(x, 0.0), - 2 => k_sin(-x, 0.0, 0), - 3 => -k_cos(x, 0.0), - // 0 - _ => k_sin(x, 0.0, 0), - } -} - -const N: usize = 12; -//static const double g = 6.024680040776729583740234375; -const GMHALF: f64 = 5.524680040776729583740234375; -const SNUM: [f64; N + 1] = [ - 23531376880.410759688572007674451636754734846804940, - 42919803642.649098768957899047001988850926355848959, - 35711959237.355668049440185451547166705960488635843, - 17921034426.037209699919755754458931112671403265390, - 6039542586.3520280050642916443072979210699388420708, - 1439720407.3117216736632230727949123939715485786772, - 248874557.86205415651146038641322942321632125127801, - 31426415.585400194380614231628318205362874684987640, - 2876370.6289353724412254090516208496135991145378768, - 186056.26539522349504029498971604569928220784236328, - 8071.6720023658162106380029022722506138218516325024, - 210.82427775157934587250973392071336271166969580291, - 2.5066282746310002701649081771338373386264310793408, -]; -const SDEN: [f64; N + 1] = [ - 0.0, - 39916800.0, - 120543840.0, - 150917976.0, - 105258076.0, - 45995730.0, - 13339535.0, - 2637558.0, - 357423.0, - 32670.0, - 1925.0, - 66.0, - 1.0, -]; -/* n! for small integer n */ -const FACT: [f64; 23] = [ - 1.0, - 1.0, - 2.0, - 6.0, - 24.0, - 120.0, - 720.0, - 5040.0, - 40320.0, - 362880.0, - 3628800.0, - 39916800.0, - 479001600.0, - 6227020800.0, - 87178291200.0, - 1307674368000.0, - 20922789888000.0, - 355687428096000.0, - 6402373705728000.0, - 121645100408832000.0, - 2432902008176640000.0, - 51090942171709440000.0, - 1124000727777607680000.0, -]; - -/* S(x) rational function for positive x */ -fn s(x: f64) -> f64 { - let mut num: f64 = 0.0; - let mut den: f64 = 0.0; - - /* to avoid overflow handle large x differently */ - if x < 8.0 { - for i in (0..=N).rev() { - num = num * x + i!(SNUM, i); - den = den * x + i!(SDEN, i); - } - } else { - for i in 0..=N { - num = num / x + i!(SNUM, i); - den = den / x + i!(SDEN, i); - } - } - return num / den; -} - -/// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tgamma(mut x: f64) -> f64 { - let u: u64 = x.to_bits(); - let absx: f64; - let mut y: f64; - let mut dy: f64; - let mut z: f64; - let mut r: f64; - let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; - let sign: bool = (u >> 63) != 0; - - /* special cases */ - if ix >= 0x7ff00000 { - /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ - return x + f64::INFINITY; - } - if ix < ((0x3ff - 54) << 20) { - /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ - return 1.0 / x; - } - - /* integer arguments */ - /* raise inexact when non-integer */ - if x == floor(x) { - if sign { - return 0.0 / 0.0; - } - if x <= FACT.len() as f64 { - return i!(FACT, (x as usize) - 1); - } - } - - /* x >= 172: tgamma(x)=inf with overflow */ - /* x =< -184: tgamma(x)=+-0 with underflow */ - if ix >= 0x40670000 { - /* |x| >= 184 */ - if sign { - let x1p_126 = f64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 - force_eval!((x1p_126 / x) as f32); - if floor(x) * 0.5 == floor(x * 0.5) { - return 0.0; - } else { - return -0.0; - } - } - let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 - x *= x1p1023; - return x; - } - - absx = if sign { -x } else { x }; - - /* handle the error of x + g - 0.5 */ - y = absx + GMHALF; - if absx > GMHALF { - dy = y - absx; - dy -= GMHALF; - } else { - dy = y - GMHALF; - dy -= absx; - } - - z = absx - 0.5; - r = s(absx) * exp(-y); - if x < 0.0 { - /* reflection formula for negative x */ - /* sinpi(absx) is not 0, integers are already handled */ - r = -PI / (sinpi(absx) * absx * r); - dy = -dy; - z = -z; - } - r += dy * (GMHALF + 0.5) * r / y; - z = pow(y, 0.5 * z); - y = r * z * z; - return y; -} diff --git a/library/compiler-builtins/libm/libm/src/math/tgammaf.rs b/library/compiler-builtins/libm/libm/src/math/tgammaf.rs deleted file mode 100644 index fe178f7a3c0..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/tgammaf.rs +++ /dev/null @@ -1,7 +0,0 @@ -use super::tgamma; - -/// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tgammaf(x: f32) -> f32 { - tgamma(x as f64) as f32 -} diff --git a/library/compiler-builtins/libm/libm/src/math/trunc.rs b/library/compiler-builtins/libm/libm/src/math/trunc.rs deleted file mode 100644 index fa50d55e136..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/trunc.rs +++ /dev/null @@ -1,53 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f16). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf16(x: f16) -> f16 { - super::generic::trunc(x) -} - -/// Rounds the number toward 0 to the closest integral value (f32). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf(x: f32) -> f32 { - select_implementation! { - name: truncf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::trunc(x) -} - -/// Rounds the number toward 0 to the closest integral value (f64). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn trunc(x: f64) -> f64 { - select_implementation! { - name: trunc, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::trunc(x) -} - -/// Rounds the number toward 0 to the closest integral value (f128). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf128(x: f128) -> f128 { - super::generic::trunc(x) -} - -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::truncf(1.1), 1.0); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/truncf.rs b/library/compiler-builtins/libm/libm/src/math/truncf.rs deleted file mode 100644 index 14533a26706..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/truncf.rs +++ /dev/null @@ -1,23 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f32). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf(x: f32) -> f32 { - select_implementation! { - name: truncf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::trunc(x) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::truncf(1.1), 1.0); - } -} diff --git a/library/compiler-builtins/libm/libm/src/math/truncf128.rs b/library/compiler-builtins/libm/libm/src/math/truncf128.rs deleted file mode 100644 index 9dccc0d0e9d..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/truncf128.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f128). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf128(x: f128) -> f128 { - super::generic::trunc(x) -} diff --git a/library/compiler-builtins/libm/libm/src/math/truncf16.rs b/library/compiler-builtins/libm/libm/src/math/truncf16.rs deleted file mode 100644 index d7c3d225cf9..00000000000 --- a/library/compiler-builtins/libm/libm/src/math/truncf16.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f16). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf16(x: f16) -> f16 { - super::generic::trunc(x) -} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs new file mode 100644 index 00000000000..7e56bd0796c --- /dev/null +++ b/library/compiler-builtins/libm/src/lib.rs @@ -0,0 +1,29 @@ +//! libm in pure Rust +#![no_std] +#![cfg_attr(intrinsics_enabled, allow(internal_features))] +#![cfg_attr(intrinsics_enabled, feature(core_intrinsics))] +#![cfg_attr(all(intrinsics_enabled, target_family = "wasm"), feature(wasm_numeric_instr))] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] +#![allow(clippy::assign_op_pattern)] +#![allow(clippy::deprecated_cfg_attr)] +#![allow(clippy::eq_op)] +#![allow(clippy::excessive_precision)] +#![allow(clippy::float_cmp)] +#![allow(clippy::int_plus_one)] +#![allow(clippy::many_single_char_names)] +#![allow(clippy::mixed_case_hex_literals)] +#![allow(clippy::needless_late_init)] +#![allow(clippy::needless_return)] +#![allow(clippy::unreadable_literal)] +#![allow(clippy::zero_divided_by_zero)] +#![forbid(unsafe_op_in_unsafe_fn)] + +mod libm_helper; +mod math; + +use core::{f32, f64}; + +pub use libm_helper::*; + +pub use self::math::*; diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs new file mode 100644 index 00000000000..dfa1ff77bf2 --- /dev/null +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -0,0 +1,244 @@ +use core::marker::PhantomData; + +use crate::*; + +/// Generic helper for libm functions, abstracting over f32 and f64.
+/// # Type Parameter: +/// - `T`: Either `f32` or `f64` +/// +/// # Examples +/// ```rust +/// use libm::{self, Libm}; +/// +/// const PI_F32: f32 = 3.1415927410e+00; +/// const PI_F64: f64 = 3.1415926535897931160e+00; +/// +/// assert!(Libm::::cos(0.0f32) == libm::cosf(0.0)); +/// assert!(Libm::::sin(PI_F32) == libm::sinf(PI_F32)); +/// +/// assert!(Libm::::cos(0.0f64) == libm::cos(0.0)); +/// assert!(Libm::::sin(PI_F64) == libm::sin(PI_F64)); +/// ``` +pub struct Libm(PhantomData); + +macro_rules! libm_helper { + ($t:ident, funcs: $funcs:tt) => { + impl Libm<$t> { + #![allow(unused_parens)] + + libm_helper! { $funcs } + } + }; + + ({$($func:tt;)*}) => { + $( + libm_helper! { $func } + )* + }; + + ((fn $func:ident($($arg:ident: $arg_typ:ty),*) -> ($($ret_typ:ty),*); => $libm_fn:ident)) => { + #[inline(always)] + pub fn $func($($arg: $arg_typ),*) -> ($($ret_typ),*) { + $libm_fn($($arg),*) + } + }; +} + +// verify-apilist-start +libm_helper! { + f32, + funcs: { + // verify-sorted-start + (fn acos(x: f32) -> (f32); => acosf); + (fn acosh(x: f32) -> (f32); => acoshf); + (fn asin(x: f32) -> (f32); => asinf); + (fn asinh(x: f32) -> (f32); => asinhf); + (fn atan(x: f32) -> (f32); => atanf); + (fn atan2(y: f32, x: f32) -> (f32); => atan2f); + (fn atanh(x: f32) -> (f32); => atanhf); + (fn cbrt(x: f32) -> (f32); => cbrtf); + (fn ceil(x: f32) -> (f32); => ceilf); + (fn copysign(x: f32, y: f32) -> (f32); => copysignf); + (fn cos(x: f32) -> (f32); => cosf); + (fn cosh(x: f32) -> (f32); => coshf); + (fn erf(x: f32) -> (f32); => erff); + (fn erfc(x: f32) -> (f32); => erfcf); + (fn exp(x: f32) -> (f32); => expf); + (fn exp10(x: f32) -> (f32); => exp10f); + (fn exp2(x: f32) -> (f32); => exp2f); + (fn expm1(x: f32) -> (f32); => expm1f); + (fn fabs(x: f32) -> (f32); => fabsf); + (fn fdim(x: f32, y: f32) -> (f32); => fdimf); + (fn floor(x: f32) -> (f32); => floorf); + (fn fma(x: f32, y: f32, z: f32) -> (f32); => fmaf); + (fn fmax(x: f32, y: f32) -> (f32); => fmaxf); + (fn fmin(x: f32, y: f32) -> (f32); => fminf); + (fn fmod(x: f32, y: f32) -> (f32); => fmodf); + (fn frexp(x: f32) -> (f32, i32); => frexpf); + (fn hypot(x: f32, y: f32) -> (f32); => hypotf); + (fn ilogb(x: f32) -> (i32); => ilogbf); + (fn j0(x: f32) -> (f32); => j0f); + (fn j1(x: f32) -> (f32); => j1f); + (fn jn(n: i32, x: f32) -> (f32); => jnf); + (fn ldexp(x: f32, n: i32) -> (f32); => ldexpf); + (fn lgamma(x: f32) -> (f32); => lgammaf); + (fn lgamma_r(x: f32) -> (f32, i32); => lgammaf_r); + (fn log(x: f32) -> (f32); => logf); + (fn log10(x: f32) -> (f32); => log10f); + (fn log1p(x: f32) -> (f32); => log1pf); + (fn log2(x: f32) -> (f32); => log2f); + (fn modf(x: f32) -> (f32, f32); => modff); + (fn nextafter(x: f32, y: f32) -> (f32); => nextafterf); + (fn pow(x: f32, y: f32) -> (f32); => powf); + (fn remainder(x: f32, y: f32) -> (f32); => remainderf); + (fn remquo(x: f32, y: f32) -> (f32, i32); => remquof); + (fn rint(x: f32) -> (f32); => rintf); + (fn round(x: f32) -> (f32); => roundf); + (fn roundeven(x: f32) -> (f32); => roundevenf); + (fn scalbn(x: f32, n: i32) -> (f32); => scalbnf); + (fn sin(x: f32) -> (f32); => sinf); + (fn sincos(x: f32) -> (f32, f32); => sincosf); + (fn sinh(x: f32) -> (f32); => sinhf); + (fn sqrt(x: f32) -> (f32); => sqrtf); + (fn tan(x: f32) -> (f32); => tanf); + (fn tanh(x: f32) -> (f32); => tanhf); + (fn tgamma(x: f32) -> (f32); => tgammaf); + (fn trunc(x: f32) -> (f32); => truncf); + (fn y0(x: f32) -> (f32); => y0f); + (fn y1(x: f32) -> (f32); => y1f); + (fn yn(n: i32, x: f32) -> (f32); => ynf); + // verify-sorted-end + } +} + +libm_helper! { + f64, + funcs: { + // verify-sorted-start + (fn acos(x: f64) -> (f64); => acos); + (fn acosh(x: f64) -> (f64); => acosh); + (fn asin(x: f64) -> (f64); => asin); + (fn asinh(x: f64) -> (f64); => asinh); + (fn atan(x: f64) -> (f64); => atan); + (fn atan2(y: f64, x: f64) -> (f64); => atan2); + (fn atanh(x: f64) -> (f64); => atanh); + (fn cbrt(x: f64) -> (f64); => cbrt); + (fn ceil(x: f64) -> (f64); => ceil); + (fn copysign(x: f64, y: f64) -> (f64); => copysign); + (fn cos(x: f64) -> (f64); => cos); + (fn cosh(x: f64) -> (f64); => cosh); + (fn erf(x: f64) -> (f64); => erf); + (fn erfc(x: f64) -> (f64); => erfc); + (fn exp(x: f64) -> (f64); => exp); + (fn exp10(x: f64) -> (f64); => exp10); + (fn exp2(x: f64) -> (f64); => exp2); + (fn expm1(x: f64) -> (f64); => expm1); + (fn fabs(x: f64) -> (f64); => fabs); + (fn fdim(x: f64, y: f64) -> (f64); => fdim); + (fn floor(x: f64) -> (f64); => floor); + (fn fma(x: f64, y: f64, z: f64) -> (f64); => fma); + (fn fmax(x: f64, y: f64) -> (f64); => fmax); + (fn fmaximum(x: f64, y: f64) -> (f64); => fmaximum); + (fn fmaximum_num(x: f64, y: f64) -> (f64); => fmaximum_num); + (fn fmaximum_numf(x: f32, y: f32) -> (f32); => fmaximum_numf); + (fn fmaximumf(x: f32, y: f32) -> (f32); => fmaximumf); + (fn fmin(x: f64, y: f64) -> (f64); => fmin); + (fn fminimum(x: f64, y: f64) -> (f64); => fminimum); + (fn fminimum_num(x: f64, y: f64) -> (f64); => fminimum_num); + (fn fminimum_numf(x: f32, y: f32) -> (f32); => fminimum_numf); + (fn fminimumf(x: f32, y: f32) -> (f32); => fminimumf); + (fn fmod(x: f64, y: f64) -> (f64); => fmod); + (fn frexp(x: f64) -> (f64, i32); => frexp); + (fn hypot(x: f64, y: f64) -> (f64); => hypot); + (fn ilogb(x: f64) -> (i32); => ilogb); + (fn j0(x: f64) -> (f64); => j0); + (fn j1(x: f64) -> (f64); => j1); + (fn jn(n: i32, x: f64) -> (f64); => jn); + (fn ldexp(x: f64, n: i32) -> (f64); => ldexp); + (fn lgamma(x: f64) -> (f64); => lgamma); + (fn lgamma_r(x: f64) -> (f64, i32); => lgamma_r); + (fn log(x: f64) -> (f64); => log); + (fn log10(x: f64) -> (f64); => log10); + (fn log1p(x: f64) -> (f64); => log1p); + (fn log2(x: f64) -> (f64); => log2); + (fn modf(x: f64) -> (f64, f64); => modf); + (fn nextafter(x: f64, y: f64) -> (f64); => nextafter); + (fn pow(x: f64, y: f64) -> (f64); => pow); + (fn remainder(x: f64, y: f64) -> (f64); => remainder); + (fn remquo(x: f64, y: f64) -> (f64, i32); => remquo); + (fn rint(x: f64) -> (f64); => rint); + (fn round(x: f64) -> (f64); => round); + (fn roundevem(x: f64) -> (f64); => roundeven); + (fn scalbn(x: f64, n: i32) -> (f64); => scalbn); + (fn sin(x: f64) -> (f64); => sin); + (fn sincos(x: f64) -> (f64, f64); => sincos); + (fn sinh(x: f64) -> (f64); => sinh); + (fn sqrt(x: f64) -> (f64); => sqrt); + (fn tan(x: f64) -> (f64); => tan); + (fn tanh(x: f64) -> (f64); => tanh); + (fn tgamma(x: f64) -> (f64); => tgamma); + (fn trunc(x: f64) -> (f64); => trunc); + (fn y0(x: f64) -> (f64); => y0); + (fn y1(x: f64) -> (f64); => y1); + (fn yn(n: i32, x: f64) -> (f64); => yn); + // verify-sorted-end + } +} + +#[cfg(f16_enabled)] +libm_helper! { + f16, + funcs: { + // verify-sorted-start + (fn ceil(x: f16) -> (f16); => ceilf16); + (fn copysign(x: f16, y: f16) -> (f16); => copysignf16); + (fn fabs(x: f16) -> (f16); => fabsf16); + (fn fdim(x: f16, y: f16) -> (f16); => fdimf16); + (fn floor(x: f16) -> (f16); => floorf16); + (fn fmax(x: f16, y: f16) -> (f16); => fmaxf16); + (fn fmaximum_num(x: f16, y: f16) -> (f16); => fmaximum_numf16); + (fn fmaximumf16(x: f16, y: f16) -> (f16); => fmaximumf16); + (fn fmin(x: f16, y: f16) -> (f16); => fminf16); + (fn fminimum(x: f16, y: f16) -> (f16); => fminimumf16); + (fn fminimum_num(x: f16, y: f16) -> (f16); => fminimum_numf16); + (fn fmod(x: f16, y: f16) -> (f16); => fmodf16); + (fn ldexp(x: f16, n: i32) -> (f16); => ldexpf16); + (fn rint(x: f16) -> (f16); => rintf16); + (fn round(x: f16) -> (f16); => roundf16); + (fn roundeven(x: f16) -> (f16); => roundevenf16); + (fn scalbn(x: f16, n: i32) -> (f16); => scalbnf16); + (fn sqrtf(x: f16) -> (f16); => sqrtf16); + (fn truncf(x: f16) -> (f16); => truncf16); + // verify-sorted-end + } +} + +#[cfg(f128_enabled)] +libm_helper! { + f128, + funcs: { + // verify-sorted-start + (fn ceil(x: f128) -> (f128); => ceilf128); + (fn copysign(x: f128, y: f128) -> (f128); => copysignf128); + (fn fabs(x: f128) -> (f128); => fabsf128); + (fn fdim(x: f128, y: f128) -> (f128); => fdimf128); + (fn floor(x: f128) -> (f128); => floorf128); + (fn fma(x: f128, y: f128, z: f128) -> (f128); => fmaf128); + (fn fmax(x: f128, y: f128) -> (f128); => fmaxf128); + (fn fmaximum(x: f128, y: f128) -> (f128); => fmaximumf128); + (fn fmaximum_num(x: f128, y: f128) -> (f128); => fmaximum_numf128); + (fn fmin(x: f128, y: f128) -> (f128); => fminf128); + (fn fminimum(x: f128, y: f128) -> (f128); => fminimumf128); + (fn fminimum_num(x: f128, y: f128) -> (f128); => fminimum_numf128); + (fn fmod(x: f128, y: f128) -> (f128); => fmodf128); + (fn ldexp(x: f128, n: i32) -> (f128); => ldexpf128); + (fn rint(x: f128) -> (f128); => rintf128); + (fn round(x: f128) -> (f128); => roundf128); + (fn roundeven(x: f128) -> (f128); => roundevenf128); + (fn scalbn(x: f128, n: i32) -> (f128); => scalbnf128); + (fn sqrt(x: f128) -> (f128); => sqrtf128); + (fn trunc(x: f128) -> (f128); => truncf128); + // verify-sorted-end + } +} +// verify-apilist-end diff --git a/library/compiler-builtins/libm/src/math/acos.rs b/library/compiler-builtins/libm/src/math/acos.rs new file mode 100644 index 00000000000..23b13251ee2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/acos.rs @@ -0,0 +1,112 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* acos(x) + * Method : + * acos(x) = pi/2 - asin(x) + * acos(-x) = pi/2 + asin(x) + * For |x|<=0.5 + * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) + * For x>0.5 + * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) + * = 2asin(sqrt((1-x)/2)) + * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) + * = 2f + (2c + 2s*z*R(z)) + * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term + * for f so that f+c ~ sqrt(z). + * For x<-0.5 + * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) + * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + * Function needed: sqrt + */ + +use super::sqrt; + +const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ +const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ +const PS0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ +const PS1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ +const PS2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ +const PS3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ +const PS4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ +const PS5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ +const QS1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ +const QS2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ +const QS3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ +const QS4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +fn r(z: f64) -> f64 { + let p: f64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); + let q: f64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); + p / q +} + +/// Arccosine (f64) +/// +/// Computes the inverse cosine (arc cosine) of the input value. +/// Arguments must be in the range -1 to 1. +/// Returns values in radians, in the range of 0 to pi. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn acos(x: f64) -> f64 { + let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120 + let z: f64; + let w: f64; + let s: f64; + let c: f64; + let df: f64; + let hx: u32; + let ix: u32; + + hx = (x.to_bits() >> 32) as u32; + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3ff00000 { + let lx: u32 = x.to_bits() as u32; + + if ((ix - 0x3ff00000) | lx) == 0 { + /* acos(1)=0, acos(-1)=pi */ + if (hx >> 31) != 0 { + return 2. * PIO2_HI + x1p_120f; + } + return 0.; + } + return 0. / (x - x); + } + /* |x| < 0.5 */ + if ix < 0x3fe00000 { + if ix <= 0x3c600000 { + /* |x| < 2**-57 */ + return PIO2_HI + x1p_120f; + } + return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); + } + /* x < -0.5 */ + if (hx >> 31) != 0 { + z = (1.0 + x) * 0.5; + s = sqrt(z); + w = r(z) * s - PIO2_LO; + return 2. * (PIO2_HI - (s + w)); + } + /* x > 0.5 */ + z = (1.0 - x) * 0.5; + s = sqrt(z); + // Set the low 4 bytes to zero + df = f64::from_bits(s.to_bits() & 0xff_ff_ff_ff_00_00_00_00); + + c = (z - df * df) / (s + df); + w = r(z) * s + c; + 2. * (df + w) +} diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs new file mode 100644 index 00000000000..dd88eea5b13 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -0,0 +1,79 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::sqrt::sqrtf; + +const PIO2_HI: f32 = 1.5707962513e+00; /* 0x3fc90fda */ +const PIO2_LO: f32 = 7.5497894159e-08; /* 0x33a22168 */ +const P_S0: f32 = 1.6666586697e-01; +const P_S1: f32 = -4.2743422091e-02; +const P_S2: f32 = -8.6563630030e-03; +const Q_S1: f32 = -7.0662963390e-01; + +fn r(z: f32) -> f32 { + let p = z * (P_S0 + z * (P_S1 + z * P_S2)); + let q = 1. + z * Q_S1; + p / q +} + +/// Arccosine (f32) +/// +/// Computes the inverse cosine (arc cosine) of the input value. +/// Arguments must be in the range -1 to 1. +/// Returns values in radians, in the range of 0 to pi. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn acosf(x: f32) -> f32 { + let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) + + let z: f32; + let w: f32; + let s: f32; + + let mut hx = x.to_bits(); + let ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3f800000 { + if ix == 0x3f800000 { + if (hx >> 31) != 0 { + return 2. * PIO2_HI + x1p_120; + } + return 0.; + } + return 0. / (x - x); + } + /* |x| < 0.5 */ + if ix < 0x3f000000 { + if ix <= 0x32800000 { + /* |x| < 2**-26 */ + return PIO2_HI + x1p_120; + } + return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); + } + /* x < -0.5 */ + if (hx >> 31) != 0 { + z = (1. + x) * 0.5; + s = sqrtf(z); + w = r(z) * s - PIO2_LO; + return 2. * (PIO2_HI - (s + w)); + } + /* x > 0.5 */ + z = (1. - x) * 0.5; + s = sqrtf(z); + hx = s.to_bits(); + let df = f32::from_bits(hx & 0xfffff000); + let c = (z - df * df) / (s + df); + w = r(z) * s + c; + 2. * (df + w) +} diff --git a/library/compiler-builtins/libm/src/math/acosh.rs b/library/compiler-builtins/libm/src/math/acosh.rs new file mode 100644 index 00000000000..d1f5b9fa937 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/acosh.rs @@ -0,0 +1,27 @@ +use super::{log, log1p, sqrt}; + +const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ + +/// Inverse hyperbolic cosine (f64) +/// +/// Calculates the inverse hyperbolic cosine of `x`. +/// Is defined as `log(x + sqrt(x*x-1))`. +/// `x` must be a number greater than or equal to 1. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn acosh(x: f64) -> f64 { + let u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + + /* x < 1 domain error is handled in the called functions */ + + if e < 0x3ff + 1 { + /* |x| < 2, up to 2ulp error in [1,1.125] */ + return log1p(x - 1.0 + sqrt((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); + } + if e < 0x3ff + 26 { + /* |x| < 0x1p26 */ + return log(2.0 * x - 1.0 / (x + sqrt(x * x - 1.0))); + } + /* |x| >= 0x1p26 or nan */ + return log(x) + LN2; +} diff --git a/library/compiler-builtins/libm/src/math/acoshf.rs b/library/compiler-builtins/libm/src/math/acoshf.rs new file mode 100644 index 00000000000..ad3455fdd48 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/acoshf.rs @@ -0,0 +1,26 @@ +use super::{log1pf, logf, sqrtf}; + +const LN2: f32 = 0.693147180559945309417232121458176568; + +/// Inverse hyperbolic cosine (f32) +/// +/// Calculates the inverse hyperbolic cosine of `x`. +/// Is defined as `log(x + sqrt(x*x-1))`. +/// `x` must be a number greater than or equal to 1. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn acoshf(x: f32) -> f32 { + let u = x.to_bits(); + let a = u & 0x7fffffff; + + if a < 0x3f800000 + (1 << 23) { + /* |x| < 2, invalid if x < 1 or nan */ + /* up to 2ulp error in [1,1.125] */ + return log1pf(x - 1.0 + sqrtf((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); + } + if a < 0x3f800000 + (12 << 23) { + /* |x| < 0x1p12 */ + return logf(2.0 * x - 1.0 / (x + sqrtf(x * x - 1.0))); + } + /* x >= 0x1p12 */ + return logf(x) + LN2; +} diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64.rs b/library/compiler-builtins/libm/src/math/arch/aarch64.rs new file mode 100644 index 00000000000..020bb731cdc --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/aarch64.rs @@ -0,0 +1,115 @@ +//! Architecture-specific support for aarch64 with neon. + +use core::arch::asm; + +pub fn fma(mut x: f64, y: f64, z: f64) -> f64 { + // SAFETY: `fmadd` is available with neon and has no side effects. + unsafe { + asm!( + "fmadd {x:d}, {x:d}, {y:d}, {z:d}", + x = inout(vreg) x, + y = in(vreg) y, + z = in(vreg) z, + options(nomem, nostack, pure) + ); + } + x +} + +pub fn fmaf(mut x: f32, y: f32, z: f32) -> f32 { + // SAFETY: `fmadd` is available with neon and has no side effects. + unsafe { + asm!( + "fmadd {x:s}, {x:s}, {y:s}, {z:s}", + x = inout(vreg) x, + y = in(vreg) y, + z = in(vreg) z, + options(nomem, nostack, pure) + ); + } + x +} + +pub fn rint(mut x: f64) -> f64 { + // SAFETY: `frintn` is available with neon and has no side effects. + // + // `frintn` is always round-to-nearest which does not match the C specification, but Rust does + // not support rounding modes. + unsafe { + asm!( + "frintn {x:d}, {x:d}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} + +pub fn rintf(mut x: f32) -> f32 { + // SAFETY: `frintn` is available with neon and has no side effects. + // + // `frintn` is always round-to-nearest which does not match the C specification, but Rust does + // not support rounding modes. + unsafe { + asm!( + "frintn {x:s}, {x:s}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} + +#[cfg(all(f16_enabled, target_feature = "fp16"))] +pub fn rintf16(mut x: f16) -> f16 { + // SAFETY: `frintn` is available for `f16` with `fp16` (implies `neon`) and has no side effects. + // + // `frintn` is always round-to-nearest which does not match the C specification, but Rust does + // not support rounding modes. + unsafe { + asm!( + "frintn {x:h}, {x:h}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} + +pub fn sqrt(mut x: f64) -> f64 { + // SAFETY: `fsqrt` is available with neon and has no side effects. + unsafe { + asm!( + "fsqrt {x:d}, {x:d}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} + +pub fn sqrtf(mut x: f32) -> f32 { + // SAFETY: `fsqrt` is available with neon and has no side effects. + unsafe { + asm!( + "fsqrt {x:s}, {x:s}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} + +#[cfg(all(f16_enabled, target_feature = "fp16"))] +pub fn sqrtf16(mut x: f16) -> f16 { + // SAFETY: `fsqrt` is available for `f16` with `fp16` (implies `neon`) and has no + // side effects. + unsafe { + asm!( + "fsqrt {x:h}, {x:h}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} diff --git a/library/compiler-builtins/libm/src/math/arch/i586.rs b/library/compiler-builtins/libm/src/math/arch/i586.rs new file mode 100644 index 00000000000..f92b9a2af71 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/i586.rs @@ -0,0 +1,37 @@ +//! Architecture-specific support for x86-32 without SSE2 + +use super::super::fabs; + +/// Use an alternative implementation on x86, because the +/// main implementation fails with the x87 FPU used by +/// debian i386, probably due to excess precision issues. +/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219. +pub fn ceil(x: f64) -> f64 { + if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated < x { + return truncated + 1.0; + } else { + return truncated; + } + } else { + return x; + } +} + +/// Use an alternative implementation on x86, because the +/// main implementation fails with the x87 FPU used by +/// debian i386, probably due to excess precision issues. +/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219. +pub fn floor(x: f64) -> f64 { + if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated > x { + return truncated - 1.0; + } else { + return truncated; + } + } else { + return x; + } +} diff --git a/library/compiler-builtins/libm/src/math/arch/i686.rs b/library/compiler-builtins/libm/src/math/arch/i686.rs new file mode 100644 index 00000000000..3e1d19bfab6 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/i686.rs @@ -0,0 +1,27 @@ +//! Architecture-specific support for x86-32 and x86-64 with SSE2 + +pub fn sqrtf(mut x: f32) -> f32 { + // SAFETY: `sqrtss` is part of `sse2`, which this module is gated behind. It has no memory + // access or side effects. + unsafe { + core::arch::asm!( + "sqrtss {x}, {x}", + x = inout(xmm_reg) x, + options(nostack, nomem, pure), + ) + }; + x +} + +pub fn sqrt(mut x: f64) -> f64 { + // SAFETY: `sqrtsd` is part of `sse2`, which this module is gated behind. It has no memory + // access or side effects. + unsafe { + core::arch::asm!( + "sqrtsd {x}, {x}", + x = inout(xmm_reg) x, + options(nostack, nomem, pure), + ) + }; + x +} diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs new file mode 100644 index 00000000000..d9f2aad66d4 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -0,0 +1,50 @@ +//! Architecture-specific routines and operations. +//! +//! LLVM will already optimize calls to some of these in cases that there are hardware +//! instructions. Providing an implementation here just ensures that the faster implementation +//! is used when calling the function directly. This helps anyone who uses `libm` directly, as +//! well as improving things when these routines are called as part of other implementations. + +// Most implementations should be defined here, to ensure they are not made available when +// soft floats are required. +#[cfg(arch_enabled)] +cfg_if! { + if #[cfg(all(target_arch = "wasm32", intrinsics_enabled))] { + mod wasm32; + pub use wasm32::{ + ceil, ceilf, fabs, fabsf, floor, floorf, rint, rintf, sqrt, sqrtf, trunc, truncf, + }; + } else if #[cfg(target_feature = "sse2")] { + mod i686; + pub use i686::{sqrt, sqrtf}; + } else if #[cfg(all( + any(target_arch = "aarch64", target_arch = "arm64ec"), + target_feature = "neon" + ))] { + mod aarch64; + + pub use aarch64::{ + fma, + fmaf, + rint, + rintf, + sqrt, + sqrtf, + }; + + #[cfg(all(f16_enabled, target_feature = "fp16"))] + pub use aarch64::{ + rintf16, + sqrtf16, + }; + } +} + +// There are certain architecture-specific implementations that are needed for correctness +// even with `force-soft-float`. These are configured here. +cfg_if! { + if #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] { + mod i586; + pub use i586::{ceil, floor}; + } +} diff --git a/library/compiler-builtins/libm/src/math/arch/wasm32.rs b/library/compiler-builtins/libm/src/math/arch/wasm32.rs new file mode 100644 index 00000000000..de80c8a5817 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/wasm32.rs @@ -0,0 +1,50 @@ +//! Wasm has builtins for simple float operations. Use the unstable `core::arch` intrinsics which +//! are significantly faster than soft float operations. + +pub fn ceil(x: f64) -> f64 { + core::arch::wasm32::f64_ceil(x) +} + +pub fn ceilf(x: f32) -> f32 { + core::arch::wasm32::f32_ceil(x) +} + +pub fn fabs(x: f64) -> f64 { + x.abs() +} + +pub fn fabsf(x: f32) -> f32 { + x.abs() +} + +pub fn floor(x: f64) -> f64 { + core::arch::wasm32::f64_floor(x) +} + +pub fn floorf(x: f32) -> f32 { + core::arch::wasm32::f32_floor(x) +} + +pub fn rint(x: f64) -> f64 { + core::arch::wasm32::f64_nearest(x) +} + +pub fn rintf(x: f32) -> f32 { + core::arch::wasm32::f32_nearest(x) +} + +pub fn sqrt(x: f64) -> f64 { + core::arch::wasm32::f64_sqrt(x) +} + +pub fn sqrtf(x: f32) -> f32 { + core::arch::wasm32::f32_sqrt(x) +} + +pub fn trunc(x: f64) -> f64 { + core::arch::wasm32::f64_trunc(x) +} + +pub fn truncf(x: f32) -> f32 { + core::arch::wasm32::f32_trunc(x) +} diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs new file mode 100644 index 00000000000..12d0cd35fa5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -0,0 +1,115 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* asin(x) + * Method : + * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... + * we approximate asin(x) on [0,0.5] by + * asin(x) = x + x*x^2*R(x^2) + * where + * R(x^2) is a rational approximation of (asin(x)-x)/x^3 + * and its remez error is bounded by + * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) + * + * For x in [0.5,1] + * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) + * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; + * then for x>0.98 + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) + * For x<=0.98, let pio4_hi = pio2_hi/2, then + * f = hi part of s; + * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) + * and + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) + * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + */ + +use super::{fabs, get_high_word, get_low_word, sqrt, with_set_low_word}; + +const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ +const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ +/* coefficients for R(x^2) */ +const P_S0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ +const P_S1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ +const P_S2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ +const P_S3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ +const P_S4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ +const P_S5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ +const Q_S1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ +const Q_S2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ +const Q_S3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ +const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +fn comp_r(z: f64) -> f64 { + let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); + let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); + p / q +} + +/// Arcsine (f64) +/// +/// Computes the inverse sine (arc sine) of the argument `x`. +/// Arguments to asin must be in the range -1 to 1. +/// Returns values in radians, in the range of -pi/2 to pi/2. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn asin(mut x: f64) -> f64 { + let z: f64; + let r: f64; + let s: f64; + let hx: u32; + let ix: u32; + + hx = get_high_word(x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3ff00000 { + let lx: u32; + lx = get_low_word(x); + if ((ix - 0x3ff00000) | lx) == 0 { + /* asin(1) = +-pi/2 with inexact */ + return x * PIO2_HI + f64::from_bits(0x3870000000000000); + } else { + return 0.0 / (x - x); + } + } + /* |x| < 0.5 */ + if ix < 0x3fe00000 { + /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ + if (0x00100000..0x3e500000).contains(&ix) { + return x; + } else { + return x + x * comp_r(x * x); + } + } + /* 1 > |x| >= 0.5 */ + z = (1.0 - fabs(x)) * 0.5; + s = sqrt(z); + r = comp_r(z); + if ix >= 0x3fef3333 { + /* if |x| > 0.975 */ + x = PIO2_HI - (2. * (s + s * r) - PIO2_LO); + } else { + let f: f64; + let c: f64; + /* f+c = sqrt(z) */ + f = with_set_low_word(s, 0); + c = (z - f * f) / (s + f); + x = 0.5 * PIO2_HI - (2.0 * s * r - (PIO2_LO - 2.0 * c) - (0.5 * PIO2_HI - 2.0 * f)); + } + if hx >> 31 != 0 { -x } else { x } +} diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs new file mode 100644 index 00000000000..ed685556730 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -0,0 +1,68 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::sqrt::sqrt; +use super::support::Float; + +const PIO2: f64 = 1.570796326794896558e+00; + +/* coefficients for R(x^2) */ +const P_S0: f32 = 1.6666586697e-01; +const P_S1: f32 = -4.2743422091e-02; +const P_S2: f32 = -8.6563630030e-03; +const Q_S1: f32 = -7.0662963390e-01; + +fn r(z: f32) -> f32 { + let p = z * (P_S0 + z * (P_S1 + z * P_S2)); + let q = 1. + z * Q_S1; + p / q +} + +/// Arcsine (f32) +/// +/// Computes the inverse sine (arc sine) of the argument `x`. +/// Arguments to asin must be in the range -1 to 1. +/// Returns values in radians, in the range of -pi/2 to pi/2. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn asinf(mut x: f32) -> f32 { + let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120) + + let hx = x.to_bits(); + let ix = hx & 0x7fffffff; + + if ix >= 0x3f800000 { + /* |x| >= 1 */ + if ix == 0x3f800000 { + /* |x| == 1 */ + return ((x as f64) * PIO2 + x1p_120) as f32; /* asin(+-1) = +-pi/2 with inexact */ + } + return 0. / (x - x); /* asin(|x|>1) is NaN */ + } + + if ix < 0x3f000000 { + /* |x| < 0.5 */ + /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ + if (0x00800000..0x39800000).contains(&ix) { + return x; + } + return x + x * r(x * x); + } + + /* 1 > |x| >= 0.5 */ + let z = (1. - Float::abs(x)) * 0.5; + let s = sqrt(z as f64); + x = (PIO2 - 2. * (s + s * (r(z) as f64))) as f32; + if (hx >> 31) != 0 { -x } else { x } +} diff --git a/library/compiler-builtins/libm/src/math/asinh.rs b/library/compiler-builtins/libm/src/math/asinh.rs new file mode 100644 index 00000000000..75d3c3ad462 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/asinh.rs @@ -0,0 +1,36 @@ +use super::{log, log1p, sqrt}; + +const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +/// Inverse hyperbolic sine (f64) +/// +/// Calculates the inverse hyperbolic sine of `x`. +/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn asinh(mut x: f64) -> f64 { + let mut u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + let sign = (u >> 63) != 0; + + /* |x| */ + u &= (!0) >> 1; + x = f64::from_bits(u); + + if e >= 0x3ff + 26 { + /* |x| >= 0x1p26 or inf or nan */ + x = log(x) + LN2; + } else if e >= 0x3ff + 1 { + /* |x| >= 2 */ + x = log(2.0 * x + 1.0 / (sqrt(x * x + 1.0) + x)); + } else if e >= 0x3ff - 26 { + /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ + x = log1p(x + x * x / (sqrt(x * x + 1.0) + 1.0)); + } else { + /* |x| < 0x1p-26, raise inexact if x != 0 */ + let x1p120 = f64::from_bits(0x4770000000000000); + force_eval!(x + x1p120); + } + + if sign { -x } else { x } +} diff --git a/library/compiler-builtins/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/src/math/asinhf.rs new file mode 100644 index 00000000000..27ed9dd372d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/asinhf.rs @@ -0,0 +1,35 @@ +use super::{log1pf, logf, sqrtf}; + +const LN2: f32 = 0.693147180559945309417232121458176568; + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +/// Inverse hyperbolic sine (f32) +/// +/// Calculates the inverse hyperbolic sine of `x`. +/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn asinhf(mut x: f32) -> f32 { + let u = x.to_bits(); + let i = u & 0x7fffffff; + let sign = (u >> 31) != 0; + + /* |x| */ + x = f32::from_bits(i); + + if i >= 0x3f800000 + (12 << 23) { + /* |x| >= 0x1p12 or inf or nan */ + x = logf(x) + LN2; + } else if i >= 0x3f800000 + (1 << 23) { + /* |x| >= 2 */ + x = logf(2.0 * x + 1.0 / (sqrtf(x * x + 1.0) + x)); + } else if i >= 0x3f800000 - (12 << 23) { + /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ + x = log1pf(x + x * x / (sqrtf(x * x + 1.0) + 1.0)); + } else { + /* |x| < 0x1p-12, raise inexact if x!=0 */ + let x1p120 = f32::from_bits(0x7b800000); + force_eval!(x + x1p120); + } + + if sign { -x } else { x } +} diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs new file mode 100644 index 00000000000..4ca5cc91a1e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -0,0 +1,182 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* atan(x) + * Method + * 1. Reduce x to positive by atan(x) = -atan(-x). + * 2. According to the integer k=4t+0.25 chopped, t=x, the argument + * is further reduced to one of the following intervals and the + * arctangent of t is evaluated by the corresponding formula: + * + * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) + * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) + * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) + * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) + * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +use core::f64; + +use super::fabs; + +const ATANHI: [f64; 4] = [ + 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ + 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ + 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ + 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ +]; + +const ATANLO: [f64; 4] = [ + 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ + 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ + 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ + 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ +]; + +const AT: [f64; 11] = [ + 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ + -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ + 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ + -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ + 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ + -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ + 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ + -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ + 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ + -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ + 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ +]; + +/// Arctangent (f64) +/// +/// Computes the inverse tangent (arc tangent) of the input value. +/// Returns a value in radians, in the range of -pi/2 to pi/2. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atan(x: f64) -> f64 { + let mut x = x; + let mut ix = (x.to_bits() >> 32) as u32; + let sign = ix >> 31; + ix &= 0x7fff_ffff; + if ix >= 0x4410_0000 { + if x.is_nan() { + return x; + } + + let z = ATANHI[3] + f64::from_bits(0x0380_0000); // 0x1p-120f + return if sign != 0 { -z } else { z }; + } + + let id = if ix < 0x3fdc_0000 { + /* |x| < 0.4375 */ + if ix < 0x3e40_0000 { + /* |x| < 2^-27 */ + if ix < 0x0010_0000 { + /* raise underflow for subnormal x */ + force_eval!(x as f32); + } + + return x; + } + + -1 + } else { + x = fabs(x); + if ix < 0x3ff30000 { + /* |x| < 1.1875 */ + if ix < 0x3fe60000 { + /* 7/16 <= |x| < 11/16 */ + x = (2. * x - 1.) / (2. + x); + 0 + } else { + /* 11/16 <= |x| < 19/16 */ + x = (x - 1.) / (x + 1.); + 1 + } + } else if ix < 0x40038000 { + /* |x| < 2.4375 */ + x = (x - 1.5) / (1. + 1.5 * x); + 2 + } else { + /* 2.4375 <= |x| < 2^66 */ + x = -1. / x; + 3 + } + }; + + let z = x * x; + let w = z * z; + /* break sum from i=0 to 10 AT[i]z**(i+1) into odd and even poly */ + let s1 = z * (AT[0] + w * (AT[2] + w * (AT[4] + w * (AT[6] + w * (AT[8] + w * AT[10]))))); + let s2 = w * (AT[1] + w * (AT[3] + w * (AT[5] + w * (AT[7] + w * AT[9])))); + + if id < 0 { + return x - x * (s1 + s2); + } + + let z = i!(ATANHI, id as usize) - (x * (s1 + s2) - i!(ATANLO, id as usize) - x); + + if sign != 0 { -z } else { z } +} + +#[cfg(test)] +mod tests { + use core::f64; + + use super::atan; + + #[test] + fn sanity_check() { + for (input, answer) in [ + (3.0_f64.sqrt() / 3.0, f64::consts::FRAC_PI_6), + (1.0, f64::consts::FRAC_PI_4), + (3.0_f64.sqrt(), f64::consts::FRAC_PI_3), + (-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6), + (-1.0, -f64::consts::FRAC_PI_4), + (-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3), + ] + .iter() + { + assert!( + (atan(*input) - answer) / answer < 1e-5, + "\natan({:.4}/16) = {:.4}, actual: {}", + input * 16.0, + answer, + atan(*input) + ); + } + } + + #[test] + fn zero() { + assert_eq!(atan(0.0), 0.0); + } + + #[test] + fn infinity() { + assert_eq!(atan(f64::INFINITY), f64::consts::FRAC_PI_2); + } + + #[test] + fn minus_infinity() { + assert_eq!(atan(f64::NEG_INFINITY), -f64::consts::FRAC_PI_2); + } + + #[test] + fn nan() { + assert!(atan(f64::NAN).is_nan()); + } +} diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs new file mode 100644 index 00000000000..c668731cf37 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -0,0 +1,131 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* atan2(y,x) + * Method : + * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). + * 2. Reduce x to positive by (if x and y are unexceptional): + * ARG (x+iy) = arctan(y/x) ... if x > 0, + * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, + * + * Special cases: + * + * ATAN2((anything), NaN ) is NaN; + * ATAN2(NAN , (anything) ) is NaN; + * ATAN2(+-0, +(anything but NaN)) is +-0 ; + * ATAN2(+-0, -(anything but NaN)) is +-pi ; + * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; + * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; + * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; + * ATAN2(+-INF,+INF ) is +-pi/4 ; + * ATAN2(+-INF,-INF ) is +-3pi/4; + * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +use super::{atan, fabs}; + +const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ +const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +/// Arctangent of y/x (f64) +/// +/// Computes the inverse tangent (arc tangent) of `y/x`. +/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). +/// Returns a value in radians, in the range of -pi to pi. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atan2(y: f64, x: f64) -> f64 { + if x.is_nan() || y.is_nan() { + return x + y; + } + let mut ix = (x.to_bits() >> 32) as u32; + let lx = x.to_bits() as u32; + let mut iy = (y.to_bits() >> 32) as u32; + let ly = y.to_bits() as u32; + if ((ix.wrapping_sub(0x3ff00000)) | lx) == 0 { + /* x = 1.0 */ + return atan(y); + } + let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if (iy | ly) == 0 { + return match m { + 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ + 2 => PI, /* atan(+0,-anything) = PI */ + _ => -PI, /* atan(-0,-anything) =-PI */ + }; + } + /* when x = 0 */ + if (ix | lx) == 0 { + return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; + } + /* when x is INF */ + if ix == 0x7ff00000 { + if iy == 0x7ff00000 { + return match m { + 0 => PI / 4.0, /* atan(+INF,+INF) */ + 1 => -PI / 4.0, /* atan(-INF,+INF) */ + 2 => 3.0 * PI / 4.0, /* atan(+INF,-INF) */ + _ => -3.0 * PI / 4.0, /* atan(-INF,-INF) */ + }; + } else { + return match m { + 0 => 0.0, /* atan(+...,+INF) */ + 1 => -0.0, /* atan(-...,+INF) */ + 2 => PI, /* atan(+...,-INF) */ + _ => -PI, /* atan(-...,-INF) */ + }; + } + } + /* |y/x| > 0x1p64 */ + if ix.wrapping_add(64 << 20) < iy || iy == 0x7ff00000 { + return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; + } + + /* z = atan(|y/x|) without spurious underflow */ + let z = if (m & 2 != 0) && iy.wrapping_add(64 << 20) < ix { + /* |y/x| < 0x1p-64, x<0 */ + 0.0 + } else { + atan(fabs(y / x)) + }; + match m { + 0 => z, /* atan(+,+) */ + 1 => -z, /* atan(-,+) */ + 2 => PI - (z - PI_LO), /* atan(+,-) */ + _ => (z - PI_LO) - PI, /* atan(-,-) */ + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg_attr(x86_no_sse, ignore = "FIXME(i586): possible incorrect rounding")] + fn sanity_check() { + assert_eq!(atan2(0.0, 1.0), 0.0); + assert_eq!(atan2(0.0, -1.0), PI); + assert_eq!(atan2(-0.0, -1.0), -PI); + assert_eq!(atan2(3.0, 2.0), atan(3.0 / 2.0)); + assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI); + assert_eq!(atan2(-2.0, -1.0), atan(-2.0 / -1.0) - PI); + } +} diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs new file mode 100644 index 00000000000..95b466fff4e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -0,0 +1,90 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{atanf, fabsf}; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ + +/// Arctangent of y/x (f32) +/// +/// Computes the inverse tangent (arc tangent) of `y/x`. +/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). +/// Returns a value in radians, in the range of -pi to pi. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atan2f(y: f32, x: f32) -> f32 { + if x.is_nan() || y.is_nan() { + return x + y; + } + let mut ix = x.to_bits(); + let mut iy = y.to_bits(); + + if ix == 0x3f800000 { + /* x=1.0 */ + return atanf(y); + } + let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if iy == 0 { + return match m { + 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ + 2 => PI, /* atan(+0,-anything) = pi */ + _ => -PI, /* atan(-0,-anything) =-pi */ + }; + } + /* when x = 0 */ + if ix == 0 { + return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; + } + /* when x is INF */ + if ix == 0x7f800000 { + return if iy == 0x7f800000 { + match m { + 0 => PI / 4., /* atan(+INF,+INF) */ + 1 => -PI / 4., /* atan(-INF,+INF) */ + 2 => 3. * PI / 4., /* atan(+INF,-INF)*/ + _ => -3. * PI / 4., /* atan(-INF,-INF)*/ + } + } else { + match m { + 0 => 0., /* atan(+...,+INF) */ + 1 => -0., /* atan(-...,+INF) */ + 2 => PI, /* atan(+...,-INF) */ + _ => -PI, /* atan(-...,-INF) */ + } + }; + } + /* |y/x| > 0x1p26 */ + if (ix + (26 << 23) < iy) || (iy == 0x7f800000) { + return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; + } + + /* z = atan(|y/x|) with correct underflow */ + let z = if (m & 2 != 0) && (iy + (26 << 23) < ix) { + /*|y/x| < 0x1p-26, x < 0 */ + 0. + } else { + atanf(fabsf(y / x)) + }; + match m { + 0 => z, /* atan(+,+) */ + 1 => -z, /* atan(-,+) */ + 2 => PI - (z - PI_LO), /* atan(+,-) */ + _ => (z - PI_LO) - PI, /* case 3 */ /* atan(-,-) */ + } +} diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs new file mode 100644 index 00000000000..eb3d401cd96 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -0,0 +1,103 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::fabsf; + +const ATAN_HI: [f32; 4] = [ + 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ + 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ + 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ + 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ +]; + +const ATAN_LO: [f32; 4] = [ + 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ + 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ + 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ + 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ +]; + +const A_T: [f32; 5] = + [3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, -1.0648017377e-01, 6.1687607318e-02]; + +/// Arctangent (f32) +/// +/// Computes the inverse tangent (arc tangent) of the input value. +/// Returns a value in radians, in the range of -pi/2 to pi/2. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atanf(mut x: f32) -> f32 { + let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) + + let z: f32; + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix >= 0x4c800000 { + /* if |x| >= 2**26 */ + if x.is_nan() { + return x; + } + z = i!(ATAN_HI, 3) + x1p_120; + return if sign { -z } else { z }; + } + let id = if ix < 0x3ee00000 { + /* |x| < 0.4375 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + if ix < 0x00800000 { + /* raise underflow for subnormal x */ + force_eval!(x * x); + } + return x; + } + -1 + } else { + x = fabsf(x); + if ix < 0x3f980000 { + /* |x| < 1.1875 */ + if ix < 0x3f300000 { + /* 7/16 <= |x| < 11/16 */ + x = (2. * x - 1.) / (2. + x); + 0 + } else { + /* 11/16 <= |x| < 19/16 */ + x = (x - 1.) / (x + 1.); + 1 + } + } else if ix < 0x401c0000 { + /* |x| < 2.4375 */ + x = (x - 1.5) / (1. + 1.5 * x); + 2 + } else { + /* 2.4375 <= |x| < 2**26 */ + x = -1. / x; + 3 + } + }; + /* end of argument reduction */ + z = x * x; + let w = z * z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + let s1 = z * (i!(A_T, 0) + w * (i!(A_T, 2) + w * i!(A_T, 4))); + let s2 = w * (i!(A_T, 1) + w * i!(A_T, 3)); + if id < 0 { + return x - x * (s1 + s2); + } + let id = id as usize; + let z = i!(ATAN_HI, id) - ((x * (s1 + s2) - i!(ATAN_LO, id)) - x); + if sign { -z } else { z } +} diff --git a/library/compiler-builtins/libm/src/math/atanh.rs b/library/compiler-builtins/libm/src/math/atanh.rs new file mode 100644 index 00000000000..9dc826f5605 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atanh.rs @@ -0,0 +1,33 @@ +use super::log1p; + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +/// Inverse hyperbolic tangent (f64) +/// +/// Calculates the inverse hyperbolic tangent of `x`. +/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atanh(x: f64) -> f64 { + let u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + let sign = (u >> 63) != 0; + + /* |x| */ + let mut y = f64::from_bits(u & 0x7fff_ffff_ffff_ffff); + + if e < 0x3ff - 1 { + if e < 0x3ff - 32 { + /* handle underflow */ + if e == 0 { + force_eval!(y as f32); + } + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5 * log1p(2.0 * y + 2.0 * y * y / (1.0 - y)); + } + } else { + /* avoid overflow */ + y = 0.5 * log1p(2.0 * (y / (1.0 - y))); + } + + if sign { -y } else { y } +} diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs new file mode 100644 index 00000000000..80ccec1f67f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atanhf.rs @@ -0,0 +1,33 @@ +use super::log1pf; + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +/// Inverse hyperbolic tangent (f32) +/// +/// Calculates the inverse hyperbolic tangent of `x`. +/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atanhf(mut x: f32) -> f32 { + let mut u = x.to_bits(); + let sign = (u >> 31) != 0; + + /* |x| */ + u &= 0x7fffffff; + x = f32::from_bits(u); + + if u < 0x3f800000 - (1 << 23) { + if u < 0x3f800000 - (32 << 23) { + /* handle underflow */ + if u < (1 << 23) { + force_eval!(x * x); + } + } else { + /* |x| < 0.5, up to 1.7ulp error */ + x = 0.5 * log1pf(2.0 * x + 2.0 * x * x / (1.0 - x)); + } + } else { + /* avoid overflow */ + x = 0.5 * log1pf(2.0 * (x / (1.0 - x))); + } + + if sign { -x } else { x } +} diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs new file mode 100644 index 00000000000..9d3311cd6a8 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -0,0 +1,215 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: core-math/src/binary64/cbrt/cbrt.c + * Copyright (c) 2021-2022 Alexei Sibidanov. + * Ported to Rust in 2025 by Trevor Gross. + */ + +use super::Float; +use super::support::{FpResult, Round, cold_path}; + +/// Compute the cube root of the argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cbrt(x: f64) -> f64 { + cbrt_round(x, Round::Nearest).val +} + +pub fn cbrt_round(x: f64, round: Round) -> FpResult { + const ESCALE: [f64; 3] = [ + 1.0, + hf64!("0x1.428a2f98d728bp+0"), /* 2^(1/3) */ + hf64!("0x1.965fea53d6e3dp+0"), /* 2^(2/3) */ + ]; + + /* the polynomial c0+c1*x+c2*x^2+c3*x^3 approximates x^(1/3) on [1,2] + with maximal error < 9.2e-5 (attained at x=2) */ + const C: [f64; 4] = [ + hf64!("0x1.1b0babccfef9cp-1"), + hf64!("0x1.2c9a3e94d1da5p-1"), + hf64!("-0x1.4dc30b1a1ddbap-3"), + hf64!("0x1.7a8d3e4ec9b07p-6"), + ]; + + let u0: f64 = hf64!("0x1.5555555555555p-2"); + let u1: f64 = hf64!("0x1.c71c71c71c71cp-3"); + + let rsc = [1.0, -1.0, 0.5, -0.5, 0.25, -0.25]; + + let off = [hf64!("0x1p-53"), 0.0, 0.0, 0.0]; + + /* rm=0 for rounding to nearest, and other values for directed roundings */ + let hx: u64 = x.to_bits(); + let mut mant: u64 = hx & f64::SIG_MASK; + let sign: u64 = hx >> 63; + + let mut e: u32 = (hx >> f64::SIG_BITS) as u32 & f64::EXP_SAT; + + if ((e + 1) & f64::EXP_SAT) < 2 { + cold_path(); + + let ix: u64 = hx & !f64::SIGN_MASK; + + /* 0, inf, nan: we return x + x instead of simply x, + to that for x a signaling NaN, it correctly triggers + the invalid exception. */ + if e == f64::EXP_SAT || ix == 0 { + return FpResult::ok(x + x); + } + + let nz = ix.leading_zeros() - 11; /* subnormal */ + mant <<= nz; + mant &= f64::SIG_MASK; + e = e.wrapping_sub(nz - 1); + } + + e = e.wrapping_add(3072); + let cvt1: u64 = mant | (0x3ffu64 << 52); + let mut cvt5: u64 = cvt1; + + let et: u32 = e / 3; + let it: u32 = e % 3; + + /* 2^(3k+it) <= x < 2^(3k+it+1), with 0 <= it <= 3 */ + cvt5 += u64::from(it) << f64::SIG_BITS; + cvt5 |= sign << 63; + let zz: f64 = f64::from_bits(cvt5); + + /* cbrt(x) = cbrt(zz)*2^(et-1365) where 1 <= zz < 8 */ + let mut isc: u64 = ESCALE[it as usize].to_bits(); // todo: index + isc |= sign << 63; + let cvt2: u64 = isc; + let z: f64 = f64::from_bits(cvt1); + + /* cbrt(zz) = cbrt(z)*isc, where isc encodes 1, 2^(1/3) or 2^(2/3), + and 1 <= z < 2 */ + let r: f64 = 1.0 / z; + let rr: f64 = r * rsc[((it as usize) << 1) | sign as usize]; + let z2: f64 = z * z; + let c0: f64 = C[0] + z * C[1]; + let c2: f64 = C[2] + z * C[3]; + let mut y: f64 = c0 + z2 * c2; + let mut y2: f64 = y * y; + + /* y is an approximation of z^(1/3) */ + let mut h: f64 = y2 * (y * r) - 1.0; + + /* h determines the error between y and z^(1/3) */ + y -= (h * y) * (u0 - u1 * h); + + /* The correction y -= (h*y)*(u0 - u1*h) corresponds to a cubic variant + of Newton's method, with the function f(y) = 1-z/y^3. */ + y *= f64::from_bits(cvt2); + + /* Now y is an approximation of zz^(1/3), + * and rr an approximation of 1/zz. We now perform another iteration of + * Newton-Raphson, this time with a linear approximation only. */ + y2 = y * y; + let mut y2l: f64 = y.fma(y, -y2); + + /* y2 + y2l = y^2 exactly */ + let mut y3: f64 = y2 * y; + let mut y3l: f64 = y.fma(y2, -y3) + y * y2l; + + /* y3 + y3l approximates y^3 with about 106 bits of accuracy */ + h = ((y3 - zz) + y3l) * rr; + let mut dy: f64 = h * (y * u0); + + /* the approximation of zz^(1/3) is y - dy */ + let mut y1: f64 = y - dy; + dy = (y - y1) - dy; + + /* the approximation of zz^(1/3) is now y1 + dy, where |dy| < 1/2 ulp(y) + * (for rounding to nearest) */ + let mut ady: f64 = dy.abs(); + + /* For directed roundings, ady0 is tiny when dy is tiny, or ady0 is near + * from ulp(1); + * for rounding to nearest, ady0 is tiny when dy is near from 1/2 ulp(1), + * or from 3/2 ulp(1). */ + let mut ady0: f64 = (ady - off[round as usize]).abs(); + let mut ady1: f64 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs(); + + if ady0 < hf64!("0x1p-75") || ady1 < hf64!("0x1p-75") { + cold_path(); + + y2 = y1 * y1; + y2l = y1.fma(y1, -y2); + y3 = y2 * y1; + y3l = y1.fma(y2, -y3) + y1 * y2l; + h = ((y3 - zz) + y3l) * rr; + dy = h * (y1 * u0); + y = y1 - dy; + dy = (y1 - y) - dy; + y1 = y; + ady = dy.abs(); + ady0 = (ady - off[round as usize]).abs(); + ady1 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs(); + + if ady0 < hf64!("0x1p-98") || ady1 < hf64!("0x1p-98") { + cold_path(); + let azz: f64 = zz.abs(); + + // ~ 0x1.79d15d0e8d59b80000000000000ffc3dp+0 + if azz == hf64!("0x1.9b78223aa307cp+1") { + y1 = hf64!("0x1.79d15d0e8d59cp+0").copysign(zz); + } + + // ~ 0x1.de87aa837820e80000000000001c0f08p+0 + if azz == hf64!("0x1.a202bfc89ddffp+2") { + y1 = hf64!("0x1.de87aa837820fp+0").copysign(zz); + } + + if round != Round::Nearest { + let wlist = [ + (hf64!("0x1.3a9ccd7f022dbp+0"), hf64!("0x1.1236160ba9b93p+0")), // ~ 0x1.1236160ba9b930000000000001e7e8fap+0 + (hf64!("0x1.7845d2faac6fep+0"), hf64!("0x1.23115e657e49cp+0")), // ~ 0x1.23115e657e49c0000000000001d7a799p+0 + (hf64!("0x1.d1ef81cbbbe71p+0"), hf64!("0x1.388fb44cdcf5ap+0")), // ~ 0x1.388fb44cdcf5a0000000000002202c55p+0 + (hf64!("0x1.0a2014f62987cp+1"), hf64!("0x1.46bcbf47dc1e8p+0")), // ~ 0x1.46bcbf47dc1e8000000000000303aa2dp+0 + (hf64!("0x1.fe18a044a5501p+1"), hf64!("0x1.95decfec9c904p+0")), // ~ 0x1.95decfec9c9040000000000000159e8ep+0 + (hf64!("0x1.a6bb8c803147bp+2"), hf64!("0x1.e05335a6401dep+0")), // ~ 0x1.e05335a6401de00000000000027ca017p+0 + (hf64!("0x1.ac8538a031cbdp+2"), hf64!("0x1.e281d87098de8p+0")), // ~ 0x1.e281d87098de80000000000000ee9314p+0 + ]; + + for (a, b) in wlist { + if azz == a { + let tmp = if round as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 }; + y1 = (b + tmp).copysign(zz); + } + } + } + } + } + + let mut cvt3: u64 = y1.to_bits(); + cvt3 = cvt3.wrapping_add(((et.wrapping_sub(342).wrapping_sub(1023)) as u64) << 52); + let m0: u64 = cvt3 << 30; + let m1 = m0 >> 63; + + if (m0 ^ m1) <= (1u64 << 30) { + cold_path(); + + let mut cvt4: u64 = y1.to_bits(); + cvt4 = (cvt4 + (164 << 15)) & 0xffffffffffff0000u64; + + if ((f64::from_bits(cvt4) - y1) - dy).abs() < hf64!("0x1p-60") || (zz).abs() == 1.0 { + cvt3 = (cvt3 + (1u64 << 15)) & 0xffffffffffff0000u64; + } + } + + FpResult::ok(f64::from_bits(cvt3)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn spot_checks() { + if !cfg!(x86_no_sse) { + // Exposes a rounding mode problem. Ignored on i586 because of inaccurate FMA. + assert_biteq!( + cbrt(f64::from_bits(0xf7f792b28f600000)), + f64::from_bits(0xd29ce68655d962f3) + ); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/cbrtf.rs b/library/compiler-builtins/libm/src/math/cbrtf.rs new file mode 100644 index 00000000000..9d70305c647 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cbrtf.rs @@ -0,0 +1,75 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* cbrtf(x) + * Return cube root of x + */ + +use core::f32; + +const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ +const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ + +/// Cube root (f32) +/// +/// Computes the cube root of the argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cbrtf(x: f32) -> f32 { + let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 + + let mut r: f64; + let mut t: f64; + let mut ui: u32 = x.to_bits(); + let mut hx: u32 = ui & 0x7fffffff; + + if hx >= 0x7f800000 { + /* cbrt(NaN,INF) is itself */ + return x + x; + } + + /* rough cbrt to 5 bits */ + if hx < 0x00800000 { + /* zero or subnormal? */ + if hx == 0 { + return x; /* cbrt(+-0) is itself */ + } + ui = (x * x1p24).to_bits(); + hx = ui & 0x7fffffff; + hx = hx / 3 + B2; + } else { + hx = hx / 3 + B1; + } + ui &= 0x80000000; + ui |= hx; + + /* + * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In + * double precision so that its terms can be arranged for efficiency + * without causing overflow or underflow. + */ + t = f32::from_bits(ui) as f64; + r = t * t * t; + t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); + + /* + * Second step Newton iteration to 47 bits. In double precision for + * efficiency and accuracy. + */ + r = t * t * t; + t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); + + /* rounding to 24 bits is perfect in round-to-nearest mode */ + t as f32 +} diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs new file mode 100644 index 00000000000..4e103545727 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -0,0 +1,46 @@ +/// Ceil (f16) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf16(x: f16) -> f16 { + super::generic::ceil(x) +} + +/// Ceil (f32) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf(x: f32) -> f32 { + select_implementation! { + name: ceilf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::ceil(x) +} + +/// Ceil (f64) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceil(x: f64) -> f64 { + select_implementation! { + name: ceil, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), + args: x, + } + + super::generic::ceil(x) +} + +/// Ceil (f128) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf128(x: f128) -> f128 { + super::generic::ceil(x) +} diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs new file mode 100644 index 00000000000..d2a86e7fd54 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -0,0 +1,88 @@ +/// Sign of Y, magnitude of X (f16) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf16(x: f16, y: f16) -> f16 { + super::generic::copysign(x, y) +} + +/// Sign of Y, magnitude of X (f32) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf(x: f32, y: f32) -> f32 { + super::generic::copysign(x, y) +} + +/// Sign of Y, magnitude of X (f64) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysign(x: f64, y: f64) -> f64 { + super::generic::copysign(x, y) +} + +/// Sign of Y, magnitude of X (f128) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf128(x: f128, y: f128) -> f128 { + super::generic::copysign(x, y) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::Float; + + fn spec_test(f: impl Fn(F, F) -> F) { + assert_biteq!(f(F::ZERO, F::ZERO), F::ZERO); + assert_biteq!(f(F::NEG_ZERO, F::ZERO), F::ZERO); + assert_biteq!(f(F::ZERO, F::NEG_ZERO), F::NEG_ZERO); + assert_biteq!(f(F::NEG_ZERO, F::NEG_ZERO), F::NEG_ZERO); + + assert_biteq!(f(F::ONE, F::ONE), F::ONE); + assert_biteq!(f(F::NEG_ONE, F::ONE), F::ONE); + assert_biteq!(f(F::ONE, F::NEG_ONE), F::NEG_ONE); + assert_biteq!(f(F::NEG_ONE, F::NEG_ONE), F::NEG_ONE); + + assert_biteq!(f(F::INFINITY, F::INFINITY), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY, F::INFINITY), F::INFINITY); + assert_biteq!(f(F::INFINITY, F::NEG_INFINITY), F::NEG_INFINITY); + assert_biteq!(f(F::NEG_INFINITY, F::NEG_INFINITY), F::NEG_INFINITY); + + // Not required but we expect it + assert_biteq!(f(F::NAN, F::NAN), F::NAN); + assert_biteq!(f(F::NEG_NAN, F::NAN), F::NAN); + assert_biteq!(f(F::NAN, F::NEG_NAN), F::NEG_NAN); + assert_biteq!(f(F::NEG_NAN, F::NEG_NAN), F::NEG_NAN); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(copysignf16); + } + + #[test] + fn spec_tests_f32() { + spec_test::(copysignf); + } + + #[test] + fn spec_tests_f64() { + spec_test::(copysign); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(copysignf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs new file mode 100644 index 00000000000..8b9bed4c0c4 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/copysignf.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f32) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf(x: f32, y: f32) -> f32 { + super::generic::copysign(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/copysignf128.rs b/library/compiler-builtins/libm/src/math/copysignf128.rs new file mode 100644 index 00000000000..7bd81d42b2e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/copysignf128.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f128) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf128(x: f128, y: f128) -> f128 { + super::generic::copysign(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/copysignf16.rs b/library/compiler-builtins/libm/src/math/copysignf16.rs new file mode 100644 index 00000000000..82065868601 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/copysignf16.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f16) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf16(x: f16, y: f16) -> f16 { + super::generic::copysign(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs new file mode 100644 index 00000000000..de99cd4c5e4 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cos.rs @@ -0,0 +1,77 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */ +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +use super::{k_cos, k_sin, rem_pio2}; + +// cos(x) +// Return cosine function of x. +// +// kernel function: +// k_sin ... sine function on [-pi/4,pi/4] +// k_cos ... cosine function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded +// + +/// The cosine of `x` (f64). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cos(x: f64) -> f64 { + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e46a09e { + /* if x < 2**-27 * sqrt(2) */ + /* raise inexact if x != 0 */ + if x as i32 == 0 { + return 1.0; + } + } + return k_cos(x, 0.0); + } + + /* cos(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + match n & 3 { + 0 => k_cos(y0, y1), + 1 => -k_sin(y0, y1, 1), + 2 => -k_cos(y0, y1), + _ => k_sin(y0, y1, 1), + } +} diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs new file mode 100644 index 00000000000..27c2fc3b994 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -0,0 +1,86 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f64::consts::FRAC_PI_2; + +use super::{k_cosf, k_sinf, rem_pio2f}; + +/* Small multiples of pi/2 rounded to double precision. */ +const C1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +/// The cosine of `x` (f32). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cosf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + /* raise inexact if x != 0 */ + force_eval!(x + x1p120); + return 1.; + } + return k_cosf(x64); + } + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix > 0x4016cbe3 { + /* |x| ~> 3*pi/4 */ + return -k_cosf(if sign { x64 + C2_PIO2 } else { x64 - C2_PIO2 }); + } else if sign { + return k_sinf(x64 + C1_PIO2); + } else { + return k_sinf(C1_PIO2 - x64); + } + } + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix > 0x40afeddf { + /* |x| ~> 7*pi/4 */ + return k_cosf(if sign { x64 + C4_PIO2 } else { x64 - C4_PIO2 }); + } else if sign { + return k_sinf(-x64 - C3_PIO2); + } else { + return k_sinf(x64 - C3_PIO2); + } + } + + /* cos(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x - x; + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + match n & 3 { + 0 => k_cosf(y), + 1 => k_sinf(-y), + 2 => -k_cosf(y), + _ => k_sinf(y), + } +} diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs new file mode 100644 index 00000000000..d2e43fd6cb6 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -0,0 +1,36 @@ +use super::{exp, expm1, k_expo2}; + +/// Hyperbolic cosine (f64) +/// +/// Computes the hyperbolic cosine of the argument x. +/// Is defined as `(exp(x) + exp(-x))/2` +/// Angles are specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cosh(mut x: f64) -> f64 { + /* |x| */ + let mut ix = x.to_bits(); + ix &= 0x7fffffffffffffff; + x = f64::from_bits(ix); + let w = ix >> 32; + + /* |x| < log(2) */ + if w < 0x3fe62e42 { + if w < 0x3ff00000 - (26 << 20) { + let x1p120 = f64::from_bits(0x4770000000000000); + force_eval!(x + x1p120); + return 1.; + } + let t = expm1(x); // exponential minus 1 + return 1. + t * t / (2. * (1. + t)); + } + + /* |x| < log(DBL_MAX) */ + if w < 0x40862e42 { + let t = exp(x); + /* note: if x>log(0x1p26) then the 1/t is not needed */ + return 0.5 * (t + 1. / t); + } + + /* |x| > log(DBL_MAX) or nan */ + k_expo2(x) +} diff --git a/library/compiler-builtins/libm/src/math/coshf.rs b/library/compiler-builtins/libm/src/math/coshf.rs new file mode 100644 index 00000000000..567a24410e7 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/coshf.rs @@ -0,0 +1,36 @@ +use super::{expf, expm1f, k_expo2f}; + +/// Hyperbolic cosine (f64) +/// +/// Computes the hyperbolic cosine of the argument x. +/// Is defined as `(exp(x) + exp(-x))/2` +/// Angles are specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn coshf(mut x: f32) -> f32 { + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + /* |x| */ + let mut ix = x.to_bits(); + ix &= 0x7fffffff; + x = f32::from_bits(ix); + let w = ix; + + /* |x| < log(2) */ + if w < 0x3f317217 { + if w < (0x3f800000 - (12 << 23)) { + force_eval!(x + x1p120); + return 1.; + } + let t = expm1f(x); + return 1. + t * t / (2. * (1. + t)); + } + + /* |x| < log(FLT_MAX) */ + if w < 0x42b17217 { + let t = expf(x); + return 0.5 * (t + 1. / t); + } + + /* |x| > log(FLT_MAX) or nan */ + k_expo2f(x) +} diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs new file mode 100644 index 00000000000..1b634abec6b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -0,0 +1,310 @@ +use super::{exp, fabs, get_high_word, with_set_low_word}; +/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * where R = P/Q where P is an odd poly of degree 8 and + * Q is an odd poly of degree 10. + * -57.90 + * | R - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + * erf(x) = 1 - erfc(x) + * where + * R1(z) = degree 7 poly in z, (z=1/x^2) + * S1(z) = degree 8 poly in z + * + * 4. For x in [1/0.35,28] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +const ERX: f64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +const EFX8: f64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ +const PP0: f64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ +const PP1: f64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ +const PP2: f64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */ +const PP3: f64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */ +const PP4: f64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */ +const QQ1: f64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */ +const QQ2: f64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ +const QQ3: f64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ +const QQ4: f64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ +const QQ5: f64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +const PA0: f64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ +const PA1: f64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ +const PA2: f64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ +const PA3: f64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */ +const PA4: f64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */ +const PA5: f64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */ +const PA6: f64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */ +const QA1: f64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */ +const QA2: f64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */ +const QA3: f64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ +const QA4: f64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ +const QA5: f64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ +const QA6: f64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +const RA0: f64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ +const RA1: f64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ +const RA2: f64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ +const RA3: f64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */ +const RA4: f64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */ +const RA5: f64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */ +const RA6: f64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */ +const RA7: f64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */ +const SA1: f64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */ +const SA2: f64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */ +const SA3: f64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */ +const SA4: f64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */ +const SA5: f64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ +const SA6: f64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ +const SA7: f64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ +const SA8: f64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +const RB0: f64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ +const RB1: f64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ +const RB2: f64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ +const RB3: f64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */ +const RB4: f64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */ +const RB5: f64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */ +const RB6: f64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */ +const SB1: f64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */ +const SB2: f64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */ +const SB3: f64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */ +const SB4: f64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ +const SB5: f64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ +const SB6: f64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ +const SB7: f64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +fn erfc1(x: f64) -> f64 { + let s: f64; + let p: f64; + let q: f64; + + s = fabs(x) - 1.0; + p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); + q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); + + 1.0 - ERX - p / q +} + +fn erfc2(ix: u32, mut x: f64) -> f64 { + let s: f64; + let r: f64; + let big_s: f64; + let z: f64; + + if ix < 0x3ff40000 { + /* |x| < 1.25 */ + return erfc1(x); + } + + x = fabs(x); + s = 1.0 / (x * x); + if ix < 0x4006db6d { + /* |x| < 1/.35 ~ 2.85714 */ + r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); + big_s = 1.0 + + s * (SA1 + + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); + } else { + /* |x| > 1/.35 */ + r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); + big_s = + 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); + } + z = with_set_low_word(x, 0); + + exp(-z * z - 0.5625) * exp((z - x) * (z + x) + r / big_s) / x +} + +/// Error function (f64) +/// +/// Calculates an approximation to the “error function”, which estimates +/// the probability that an observation will fall within x standard +/// deviations of the mean (assuming a normal distribution). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn erf(x: f64) -> f64 { + let r: f64; + let s: f64; + let z: f64; + let y: f64; + let mut ix: u32; + let sign: usize; + + ix = get_high_word(x); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1.0 - 2.0 * (sign as f64) + 1.0 / x; + } + if ix < 0x3feb0000 { + /* |x| < 0.84375 */ + if ix < 0x3e300000 { + /* |x| < 2**-28 */ + /* avoid underflow */ + return 0.125 * (8.0 * x + EFX8 * x); + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + return x + x * y; + } + if ix < 0x40180000 { + /* 0.84375 <= |x| < 6 */ + y = 1.0 - erfc2(ix, x); + } else { + let x1p_1022 = f64::from_bits(0x0010000000000000); + y = 1.0 - x1p_1022; + } + + if sign != 0 { -y } else { y } +} + +/// Complementary error function (f64) +/// +/// Calculates the complementary probability. +/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid +/// the loss of precision that would result from subtracting +/// large probabilities (on large `x`) from 1. +pub fn erfc(x: f64) -> f64 { + let r: f64; + let s: f64; + let z: f64; + let y: f64; + let mut ix: u32; + let sign: usize; + + ix = get_high_word(x); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2.0 * (sign as f64) + 1.0 / x; + } + if ix < 0x3feb0000 { + /* |x| < 0.84375 */ + if ix < 0x3c700000 { + /* |x| < 2**-56 */ + return 1.0 - x; + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + if sign != 0 || ix < 0x3fd00000 { + /* x < 1/4 */ + return 1.0 - (x + x * y); + } + return 0.5 - (x - 0.5 + x * y); + } + if ix < 0x403c0000 { + /* 0.84375 <= |x| < 28 */ + if sign != 0 { + return 2.0 - erfc2(ix, x); + } else { + return erfc2(ix, x); + } + } + + let x1p_1022 = f64::from_bits(0x0010000000000000); + if sign != 0 { 2.0 - x1p_1022 } else { x1p_1022 * x1p_1022 } +} diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs new file mode 100644 index 00000000000..2e41183bfc0 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -0,0 +1,222 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{expf, fabsf}; + +const ERX: f32 = 8.4506291151e-01; /* 0x3f58560b */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +const EFX8: f32 = 1.0270333290e+00; /* 0x3f8375d4 */ +const PP0: f32 = 1.2837916613e-01; /* 0x3e0375d4 */ +const PP1: f32 = -3.2504209876e-01; /* 0xbea66beb */ +const PP2: f32 = -2.8481749818e-02; /* 0xbce9528f */ +const PP3: f32 = -5.7702702470e-03; /* 0xbbbd1489 */ +const PP4: f32 = -2.3763017452e-05; /* 0xb7c756b1 */ +const QQ1: f32 = 3.9791721106e-01; /* 0x3ecbbbce */ +const QQ2: f32 = 6.5022252500e-02; /* 0x3d852a63 */ +const QQ3: f32 = 5.0813062117e-03; /* 0x3ba68116 */ +const QQ4: f32 = 1.3249473704e-04; /* 0x390aee49 */ +const QQ5: f32 = -3.9602282413e-06; /* 0xb684e21a */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +const PA0: f32 = -2.3621185683e-03; /* 0xbb1acdc6 */ +const PA1: f32 = 4.1485610604e-01; /* 0x3ed46805 */ +const PA2: f32 = -3.7220788002e-01; /* 0xbebe9208 */ +const PA3: f32 = 3.1834661961e-01; /* 0x3ea2fe54 */ +const PA4: f32 = -1.1089469492e-01; /* 0xbde31cc2 */ +const PA5: f32 = 3.5478305072e-02; /* 0x3d1151b3 */ +const PA6: f32 = -2.1663755178e-03; /* 0xbb0df9c0 */ +const QA1: f32 = 1.0642088205e-01; /* 0x3dd9f331 */ +const QA2: f32 = 5.4039794207e-01; /* 0x3f0a5785 */ +const QA3: f32 = 7.1828655899e-02; /* 0x3d931ae7 */ +const QA4: f32 = 1.2617121637e-01; /* 0x3e013307 */ +const QA5: f32 = 1.3637083583e-02; /* 0x3c5f6e13 */ +const QA6: f32 = 1.1984500103e-02; /* 0x3c445aa3 */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +const RA0: f32 = -9.8649440333e-03; /* 0xbc21a093 */ +const RA1: f32 = -6.9385856390e-01; /* 0xbf31a0b7 */ +const RA2: f32 = -1.0558626175e+01; /* 0xc128f022 */ +const RA3: f32 = -6.2375331879e+01; /* 0xc2798057 */ +const RA4: f32 = -1.6239666748e+02; /* 0xc322658c */ +const RA5: f32 = -1.8460508728e+02; /* 0xc3389ae7 */ +const RA6: f32 = -8.1287437439e+01; /* 0xc2a2932b */ +const RA7: f32 = -9.8143291473e+00; /* 0xc11d077e */ +const SA1: f32 = 1.9651271820e+01; /* 0x419d35ce */ +const SA2: f32 = 1.3765776062e+02; /* 0x4309a863 */ +const SA3: f32 = 4.3456588745e+02; /* 0x43d9486f */ +const SA4: f32 = 6.4538726807e+02; /* 0x442158c9 */ +const SA5: f32 = 4.2900814819e+02; /* 0x43d6810b */ +const SA6: f32 = 1.0863500214e+02; /* 0x42d9451f */ +const SA7: f32 = 6.5702495575e+00; /* 0x40d23f7c */ +const SA8: f32 = -6.0424413532e-02; /* 0xbd777f97 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +const RB0: f32 = -9.8649431020e-03; /* 0xbc21a092 */ +const RB1: f32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ +const RB2: f32 = -1.7757955551e+01; /* 0xc18e104b */ +const RB3: f32 = -1.6063638306e+02; /* 0xc320a2ea */ +const RB4: f32 = -6.3756646729e+02; /* 0xc41f6441 */ +const RB5: f32 = -1.0250950928e+03; /* 0xc480230b */ +const RB6: f32 = -4.8351919556e+02; /* 0xc3f1c275 */ +const SB1: f32 = 3.0338060379e+01; /* 0x41f2b459 */ +const SB2: f32 = 3.2579251099e+02; /* 0x43a2e571 */ +const SB3: f32 = 1.5367296143e+03; /* 0x44c01759 */ +const SB4: f32 = 3.1998581543e+03; /* 0x4547fdbb */ +const SB5: f32 = 2.5530502930e+03; /* 0x451f90ce */ +const SB6: f32 = 4.7452853394e+02; /* 0x43ed43a7 */ +const SB7: f32 = -2.2440952301e+01; /* 0xc1b38712 */ + +fn erfc1(x: f32) -> f32 { + let s: f32; + let p: f32; + let q: f32; + + s = fabsf(x) - 1.0; + p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); + q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); + return 1.0 - ERX - p / q; +} + +fn erfc2(mut ix: u32, mut x: f32) -> f32 { + let s: f32; + let r: f32; + let big_s: f32; + let z: f32; + + if ix < 0x3fa00000 { + /* |x| < 1.25 */ + return erfc1(x); + } + + x = fabsf(x); + s = 1.0 / (x * x); + if ix < 0x4036db6d { + /* |x| < 1/0.35 */ + r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); + big_s = 1.0 + + s * (SA1 + + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); + } else { + /* |x| >= 1/0.35 */ + r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); + big_s = + 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); + } + ix = x.to_bits(); + z = f32::from_bits(ix & 0xffffe000); + + expf(-z * z - 0.5625) * expf((z - x) * (z + x) + r / big_s) / x +} + +/// Error function (f32) +/// +/// Calculates an approximation to the “error function”, which estimates +/// the probability that an observation will fall within x standard +/// deviations of the mean (assuming a normal distribution). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn erff(x: f32) -> f32 { + let r: f32; + let s: f32; + let z: f32; + let y: f32; + let mut ix: u32; + let sign: usize; + + ix = x.to_bits(); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1.0 - 2.0 * (sign as f32) + 1.0 / x; + } + if ix < 0x3f580000 { + /* |x| < 0.84375 */ + if ix < 0x31800000 { + /* |x| < 2**-28 */ + /*avoid underflow */ + return 0.125 * (8.0 * x + EFX8 * x); + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + return x + x * y; + } + if ix < 0x40c00000 { + /* |x| < 6 */ + y = 1.0 - erfc2(ix, x); + } else { + let x1p_120 = f32::from_bits(0x03800000); + y = 1.0 - x1p_120; + } + + if sign != 0 { -y } else { y } +} + +/// Complementary error function (f32) +/// +/// Calculates the complementary probability. +/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid +/// the loss of precision that would result from subtracting +/// large probabilities (on large `x`) from 1. +pub fn erfcf(x: f32) -> f32 { + let r: f32; + let s: f32; + let z: f32; + let y: f32; + let mut ix: u32; + let sign: usize; + + ix = x.to_bits(); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2.0 * (sign as f32) + 1.0 / x; + } + + if ix < 0x3f580000 { + /* |x| < 0.84375 */ + if ix < 0x23800000 { + /* |x| < 2**-56 */ + return 1.0 - x; + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + if sign != 0 || ix < 0x3e800000 { + /* x < 1/4 */ + return 1.0 - (x + x * y); + } + return 0.5 - (x - 0.5 + x * y); + } + if ix < 0x41e00000 { + /* |x| < 28 */ + if sign != 0 { + return 2.0 - erfc2(ix, x); + } else { + return erfc2(ix, x); + } + } + + let x1p_120 = f32::from_bits(0x03800000); + if sign != 0 { 2.0 - x1p_120 } else { x1p_120 * x1p_120 } +} diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs new file mode 100644 index 00000000000..782042b62cd --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -0,0 +1,150 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* exp(x) + * Returns the exponential of x. + * + * Method + * 1. Argument reduction: + * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2. + * + * Here r will be represented as r = hi-lo for better + * accuracy. + * + * 2. Approximation of exp(r) by a special rational function on + * the interval [0,0.34658]: + * Write + * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... + * We use a special Remez algorithm on [0,0.34658] to generate + * a polynomial of degree 5 to approximate R. The maximum error + * of this polynomial approximation is bounded by 2**-59. In + * other words, + * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 + * (where z=r*r, and the values of P1 to P5 are listed below) + * and + * | 5 | -59 + * | 2.0+P1*z+...+P5*z - R(z) | <= 2 + * | | + * The computation of exp(r) thus becomes + * 2*r + * exp(r) = 1 + ---------- + * R(r) - r + * r*c(r) + * = 1 + r + ----------- (for better accuracy) + * 2 - c(r) + * where + * 2 4 10 + * c(r) = r - (P1*r + P2*r + ... + P5*r ). + * + * 3. Scale back to obtain exp(x): + * From step 1, we have + * exp(x) = 2^k * exp(r) + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF) is 0, and + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 709.782712893383973096 then exp(x) overflows + * if x < -745.133219101941108420 then exp(x) underflows + */ + +use super::scalbn; + +const HALF: [f64; 2] = [0.5, -0.5]; +const LN2HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ +const LN2LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ +const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ +const P1: f64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */ +const P2: f64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ +const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ +const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ +const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +/// Exponential, base *e* (f64) +/// +/// Calculate the exponential of `x`, that is, *e* raised to the power `x` +/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp(mut x: f64) -> f64 { + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 + let x1p_149 = f64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149 + + let hi: f64; + let lo: f64; + let c: f64; + let xx: f64; + let y: f64; + let k: i32; + let sign: i32; + let mut hx: u32; + + hx = (x.to_bits() >> 32) as u32; + sign = (hx >> 31) as i32; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if hx >= 0x4086232b { + /* if |x| >= 708.39... */ + if x.is_nan() { + return x; + } + if x > 709.782712893383973096 { + /* overflow if x!=inf */ + x *= x1p1023; + return x; + } + if x < -708.39641853226410622 { + /* underflow if x!=-inf */ + force_eval!((-x1p_149 / x) as f32); + if x < -745.13321910194110842 { + return 0.; + } + } + } + + /* argument reduction */ + if hx > 0x3fd62e42 { + /* if |x| > 0.5 ln2 */ + if hx >= 0x3ff0a2b2 { + /* if |x| >= 1.5 ln2 */ + k = (INVLN2 * x + i!(HALF, sign as usize)) as i32; + } else { + k = 1 - sign - sign; + } + hi = x - k as f64 * LN2HI; /* k*ln2hi is exact here */ + lo = k as f64 * LN2LO; + x = hi - lo; + } else if hx > 0x3e300000 { + /* if |x| > 2**-28 */ + k = 0; + hi = x; + lo = 0.; + } else { + /* inexact if x!=0 */ + force_eval!(x1p1023 + x); + return 1. + x; + } + + /* x is now in primary range */ + xx = x * x; + c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); + y = 1. + (x * c / (2. - c) - lo + hi); + if k == 0 { y } else { scalbn(y, k) } +} diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs new file mode 100644 index 00000000000..7c33c92b603 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp10.rs @@ -0,0 +1,23 @@ +use super::{exp2, modf, pow}; + +const LN10: f64 = 3.32192809488736234787031942948939; +const P10: &[f64] = &[ + 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, +]; + +/// Calculates 10 raised to the power of `x` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp10(x: f64) -> f64 { + let (mut y, n) = modf(x); + let u: u64 = n.to_bits(); + /* fabs(n) < 16 without raising invalid on nan */ + if ((u >> 52) & 0x7ff) < 0x3ff + 4 { + if y == 0.0 { + return i!(P10, ((n as isize) + 15) as usize); + } + y = exp2(LN10 * y); + return y * i!(P10, ((n as isize) + 15) as usize); + } + return pow(10.0, x); +} diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs new file mode 100644 index 00000000000..0520a41f2e9 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -0,0 +1,22 @@ +use super::{exp2, exp2f, modff}; + +const LN10_F32: f32 = 3.32192809488736234787031942948939; +const LN10_F64: f64 = 3.32192809488736234787031942948939; +const P10: &[f32] = + &[1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7]; + +/// Calculates 10 raised to the power of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp10f(x: f32) -> f32 { + let (mut y, n) = modff(x); + let u = n.to_bits(); + /* fabsf(n) < 8 without raising invalid on nan */ + if ((u >> 23) & 0xff) < 0x7f + 3 { + if y == 0.0 { + return i!(P10, ((n as isize) + 7) as usize); + } + y = exp2f(LN10_F32 * y); + return y * i!(P10, ((n as isize) + 7) as usize); + } + return exp2(LN10_F64 * (x as f64)) as f32; +} diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs new file mode 100644 index 00000000000..6e98d066cbf --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -0,0 +1,394 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */ +//- +// Copyright (c) 2005 David Schultz +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +use super::scalbn; + +const TBLSIZE: usize = 256; + +#[rustfmt::skip] +static TBL: [u64; TBLSIZE * 2] = [ + // exp2(z + eps) eps + 0x3fe6a09e667f3d5d, 0x3d39880000000000, + 0x3fe6b052fa751744, 0x3cd8000000000000, + 0x3fe6c012750bd9fe, 0xbd28780000000000, + 0x3fe6cfdcddd476bf, 0x3d1ec00000000000, + 0x3fe6dfb23c651a29, 0xbcd8000000000000, + 0x3fe6ef9298593ae3, 0xbcbc000000000000, + 0x3fe6ff7df9519386, 0xbd2fd80000000000, + 0x3fe70f7466f42da3, 0xbd2c880000000000, + 0x3fe71f75e8ec5fc3, 0x3d13c00000000000, + 0x3fe72f8286eacf05, 0xbd38300000000000, + 0x3fe73f9a48a58152, 0xbd00c00000000000, + 0x3fe74fbd35d7ccfc, 0x3d2f880000000000, + 0x3fe75feb564267f1, 0x3d03e00000000000, + 0x3fe77024b1ab6d48, 0xbd27d00000000000, + 0x3fe780694fde5d38, 0xbcdd000000000000, + 0x3fe790b938ac1d00, 0x3ce3000000000000, + 0x3fe7a11473eb0178, 0xbced000000000000, + 0x3fe7b17b0976d060, 0x3d20400000000000, + 0x3fe7c1ed0130c133, 0x3ca0000000000000, + 0x3fe7d26a62ff8636, 0xbd26900000000000, + 0x3fe7e2f336cf4e3b, 0xbd02e00000000000, + 0x3fe7f3878491c3e8, 0xbd24580000000000, + 0x3fe80427543e1b4e, 0x3d33000000000000, + 0x3fe814d2add1071a, 0x3d0f000000000000, + 0x3fe82589994ccd7e, 0xbd21c00000000000, + 0x3fe8364c1eb942d0, 0x3d29d00000000000, + 0x3fe8471a4623cab5, 0x3d47100000000000, + 0x3fe857f4179f5bbc, 0x3d22600000000000, + 0x3fe868d99b4491af, 0xbd32c40000000000, + 0x3fe879cad931a395, 0xbd23000000000000, + 0x3fe88ac7d98a65b8, 0xbd2a800000000000, + 0x3fe89bd0a4785800, 0xbced000000000000, + 0x3fe8ace5422aa223, 0x3d33280000000000, + 0x3fe8be05bad619fa, 0x3d42b40000000000, + 0x3fe8cf3216b54383, 0xbd2ed00000000000, + 0x3fe8e06a5e08664c, 0xbd20500000000000, + 0x3fe8f1ae99157807, 0x3d28280000000000, + 0x3fe902fed0282c0e, 0xbd1cb00000000000, + 0x3fe9145b0b91ff96, 0xbd05e00000000000, + 0x3fe925c353aa2ff9, 0x3cf5400000000000, + 0x3fe93737b0cdc64a, 0x3d17200000000000, + 0x3fe948b82b5f98ae, 0xbd09000000000000, + 0x3fe95a44cbc852cb, 0x3d25680000000000, + 0x3fe96bdd9a766f21, 0xbd36d00000000000, + 0x3fe97d829fde4e2a, 0xbd01000000000000, + 0x3fe98f33e47a23a3, 0x3d2d000000000000, + 0x3fe9a0f170ca0604, 0xbd38a40000000000, + 0x3fe9b2bb4d53ff89, 0x3d355c0000000000, + 0x3fe9c49182a3f15b, 0x3d26b80000000000, + 0x3fe9d674194bb8c5, 0xbcec000000000000, + 0x3fe9e86319e3238e, 0x3d17d00000000000, + 0x3fe9fa5e8d07f302, 0x3d16400000000000, + 0x3fea0c667b5de54d, 0xbcf5000000000000, + 0x3fea1e7aed8eb8f6, 0x3d09e00000000000, + 0x3fea309bec4a2e27, 0x3d2ad80000000000, + 0x3fea42c980460a5d, 0xbd1af00000000000, + 0x3fea5503b23e259b, 0x3d0b600000000000, + 0x3fea674a8af46213, 0x3d38880000000000, + 0x3fea799e1330b3a7, 0x3d11200000000000, + 0x3fea8bfe53c12e8d, 0x3d06c00000000000, + 0x3fea9e6b5579fcd2, 0xbd29b80000000000, + 0x3feab0e521356fb8, 0x3d2b700000000000, + 0x3feac36bbfd3f381, 0x3cd9000000000000, + 0x3fead5ff3a3c2780, 0x3ce4000000000000, + 0x3feae89f995ad2a3, 0xbd2c900000000000, + 0x3feafb4ce622f367, 0x3d16500000000000, + 0x3feb0e07298db790, 0x3d2fd40000000000, + 0x3feb20ce6c9a89a9, 0x3d12700000000000, + 0x3feb33a2b84f1a4b, 0x3d4d470000000000, + 0x3feb468415b747e7, 0xbd38380000000000, + 0x3feb59728de5593a, 0x3c98000000000000, + 0x3feb6c6e29f1c56a, 0x3d0ad00000000000, + 0x3feb7f76f2fb5e50, 0x3cde800000000000, + 0x3feb928cf22749b2, 0xbd04c00000000000, + 0x3feba5b030a10603, 0xbd0d700000000000, + 0x3febb8e0b79a6f66, 0x3d0d900000000000, + 0x3febcc1e904bc1ff, 0x3d02a00000000000, + 0x3febdf69c3f3a16f, 0xbd1f780000000000, + 0x3febf2c25bd71db8, 0xbd10a00000000000, + 0x3fec06286141b2e9, 0xbd11400000000000, + 0x3fec199bdd8552e0, 0x3d0be00000000000, + 0x3fec2d1cd9fa64ee, 0xbd09400000000000, + 0x3fec40ab5fffd02f, 0xbd0ed00000000000, + 0x3fec544778fafd15, 0x3d39660000000000, + 0x3fec67f12e57d0cb, 0xbd1a100000000000, + 0x3fec7ba88988c1b6, 0xbd58458000000000, + 0x3fec8f6d9406e733, 0xbd1a480000000000, + 0x3feca3405751c4df, 0x3ccb000000000000, + 0x3fecb720dcef9094, 0x3d01400000000000, + 0x3feccb0f2e6d1689, 0x3cf0200000000000, + 0x3fecdf0b555dc412, 0x3cf3600000000000, + 0x3fecf3155b5bab3b, 0xbd06900000000000, + 0x3fed072d4a0789bc, 0x3d09a00000000000, + 0x3fed1b532b08c8fa, 0xbd15e00000000000, + 0x3fed2f87080d8a85, 0x3d1d280000000000, + 0x3fed43c8eacaa203, 0x3d01a00000000000, + 0x3fed5818dcfba491, 0x3cdf000000000000, + 0x3fed6c76e862e6a1, 0xbd03a00000000000, + 0x3fed80e316c9834e, 0xbd0cd80000000000, + 0x3fed955d71ff6090, 0x3cf4c00000000000, + 0x3feda9e603db32ae, 0x3cff900000000000, + 0x3fedbe7cd63a8325, 0x3ce9800000000000, + 0x3fedd321f301b445, 0xbcf5200000000000, + 0x3fede7d5641c05bf, 0xbd1d700000000000, + 0x3fedfc97337b9aec, 0xbd16140000000000, + 0x3fee11676b197d5e, 0x3d0b480000000000, + 0x3fee264614f5a3e7, 0x3d40ce0000000000, + 0x3fee3b333b16ee5c, 0x3d0c680000000000, + 0x3fee502ee78b3fb4, 0xbd09300000000000, + 0x3fee653924676d68, 0xbce5000000000000, + 0x3fee7a51fbc74c44, 0xbd07f80000000000, + 0x3fee8f7977cdb726, 0xbcf3700000000000, + 0x3feea4afa2a490e8, 0x3ce5d00000000000, + 0x3feeb9f4867ccae4, 0x3d161a0000000000, + 0x3feecf482d8e680d, 0x3cf5500000000000, + 0x3feee4aaa2188514, 0x3cc6400000000000, + 0x3feefa1bee615a13, 0xbcee800000000000, + 0x3fef0f9c1cb64106, 0xbcfa880000000000, + 0x3fef252b376bb963, 0xbd2c900000000000, + 0x3fef3ac948dd7275, 0x3caa000000000000, + 0x3fef50765b6e4524, 0xbcf4f00000000000, + 0x3fef6632798844fd, 0x3cca800000000000, + 0x3fef7bfdad9cbe38, 0x3cfabc0000000000, + 0x3fef91d802243c82, 0xbcd4600000000000, + 0x3fefa7c1819e908e, 0xbd0b0c0000000000, + 0x3fefbdba3692d511, 0xbcc0e00000000000, + 0x3fefd3c22b8f7194, 0xbd10de8000000000, + 0x3fefe9d96b2a23ee, 0x3cee430000000000, + 0x3ff0000000000000, 0x0, + 0x3ff00b1afa5abcbe, 0xbcb3400000000000, + 0x3ff0163da9fb3303, 0xbd12170000000000, + 0x3ff02168143b0282, 0x3cba400000000000, + 0x3ff02c9a3e77806c, 0x3cef980000000000, + 0x3ff037d42e11bbca, 0xbcc7400000000000, + 0x3ff04315e86e7f89, 0x3cd8300000000000, + 0x3ff04e5f72f65467, 0xbd1a3f0000000000, + 0x3ff059b0d315855a, 0xbd02840000000000, + 0x3ff0650a0e3c1f95, 0x3cf1600000000000, + 0x3ff0706b29ddf71a, 0x3d15240000000000, + 0x3ff07bd42b72a82d, 0xbce9a00000000000, + 0x3ff0874518759bd0, 0x3ce6400000000000, + 0x3ff092bdf66607c8, 0xbd00780000000000, + 0x3ff09e3ecac6f383, 0xbc98000000000000, + 0x3ff0a9c79b1f3930, 0x3cffa00000000000, + 0x3ff0b5586cf988fc, 0xbcfac80000000000, + 0x3ff0c0f145e46c8a, 0x3cd9c00000000000, + 0x3ff0cc922b724816, 0x3d05200000000000, + 0x3ff0d83b23395dd8, 0xbcfad00000000000, + 0x3ff0e3ec32d3d1f3, 0x3d1bac0000000000, + 0x3ff0efa55fdfa9a6, 0xbd04e80000000000, + 0x3ff0fb66affed2f0, 0xbd0d300000000000, + 0x3ff1073028d7234b, 0x3cf1500000000000, + 0x3ff11301d0125b5b, 0x3cec000000000000, + 0x3ff11edbab5e2af9, 0x3d16bc0000000000, + 0x3ff12abdc06c31d5, 0x3ce8400000000000, + 0x3ff136a814f2047d, 0xbd0ed00000000000, + 0x3ff1429aaea92de9, 0x3ce8e00000000000, + 0x3ff14e95934f3138, 0x3ceb400000000000, + 0x3ff15a98c8a58e71, 0x3d05300000000000, + 0x3ff166a45471c3df, 0x3d03380000000000, + 0x3ff172b83c7d5211, 0x3d28d40000000000, + 0x3ff17ed48695bb9f, 0xbd05d00000000000, + 0x3ff18af9388c8d93, 0xbd1c880000000000, + 0x3ff1972658375d66, 0x3d11f00000000000, + 0x3ff1a35beb6fcba7, 0x3d10480000000000, + 0x3ff1af99f81387e3, 0xbd47390000000000, + 0x3ff1bbe084045d54, 0x3d24e40000000000, + 0x3ff1c82f95281c43, 0xbd0a200000000000, + 0x3ff1d4873168b9b2, 0x3ce3800000000000, + 0x3ff1e0e75eb44031, 0x3ceac00000000000, + 0x3ff1ed5022fcd938, 0x3d01900000000000, + 0x3ff1f9c18438cdf7, 0xbd1b780000000000, + 0x3ff2063b88628d8f, 0x3d2d940000000000, + 0x3ff212be3578a81e, 0x3cd8000000000000, + 0x3ff21f49917ddd41, 0x3d2b340000000000, + 0x3ff22bdda2791323, 0x3d19f80000000000, + 0x3ff2387a6e7561e7, 0xbd19c80000000000, + 0x3ff2451ffb821427, 0x3d02300000000000, + 0x3ff251ce4fb2a602, 0xbd13480000000000, + 0x3ff25e85711eceb0, 0x3d12700000000000, + 0x3ff26b4565e27d16, 0x3d11d00000000000, + 0x3ff2780e341de00f, 0x3d31ee0000000000, + 0x3ff284dfe1f5633e, 0xbd14c00000000000, + 0x3ff291ba7591bb30, 0xbd13d80000000000, + 0x3ff29e9df51fdf09, 0x3d08b00000000000, + 0x3ff2ab8a66d10e9b, 0xbd227c0000000000, + 0x3ff2b87fd0dada3a, 0x3d2a340000000000, + 0x3ff2c57e39771af9, 0xbd10800000000000, + 0x3ff2d285a6e402d9, 0xbd0ed00000000000, + 0x3ff2df961f641579, 0xbcf4200000000000, + 0x3ff2ecafa93e2ecf, 0xbd24980000000000, + 0x3ff2f9d24abd8822, 0xbd16300000000000, + 0x3ff306fe0a31b625, 0xbd32360000000000, + 0x3ff31432edeea50b, 0xbd70df8000000000, + 0x3ff32170fc4cd7b8, 0xbd22480000000000, + 0x3ff32eb83ba8e9a2, 0xbd25980000000000, + 0x3ff33c08b2641766, 0x3d1ed00000000000, + 0x3ff3496266e3fa27, 0xbcdc000000000000, + 0x3ff356c55f929f0f, 0xbd30d80000000000, + 0x3ff36431a2de88b9, 0x3d22c80000000000, + 0x3ff371a7373aaa39, 0x3d20600000000000, + 0x3ff37f26231e74fe, 0xbd16600000000000, + 0x3ff38cae6d05d838, 0xbd0ae00000000000, + 0x3ff39a401b713ec3, 0xbd44720000000000, + 0x3ff3a7db34e5a020, 0x3d08200000000000, + 0x3ff3b57fbfec6e95, 0x3d3e800000000000, + 0x3ff3c32dc313a8f2, 0x3cef800000000000, + 0x3ff3d0e544ede122, 0xbd17a00000000000, + 0x3ff3dea64c1234bb, 0x3d26300000000000, + 0x3ff3ec70df1c4ecc, 0xbd48a60000000000, + 0x3ff3fa4504ac7e8c, 0xbd3cdc0000000000, + 0x3ff40822c367a0bb, 0x3d25b80000000000, + 0x3ff4160a21f72e95, 0x3d1ec00000000000, + 0x3ff423fb27094646, 0xbd13600000000000, + 0x3ff431f5d950a920, 0x3d23980000000000, + 0x3ff43ffa3f84b9eb, 0x3cfa000000000000, + 0x3ff44e0860618919, 0xbcf6c00000000000, + 0x3ff45c2042a7d201, 0xbd0bc00000000000, + 0x3ff46a41ed1d0016, 0xbd12800000000000, + 0x3ff4786d668b3326, 0x3d30e00000000000, + 0x3ff486a2b5c13c00, 0xbd2d400000000000, + 0x3ff494e1e192af04, 0x3d0c200000000000, + 0x3ff4a32af0d7d372, 0xbd1e500000000000, + 0x3ff4b17dea6db801, 0x3d07800000000000, + 0x3ff4bfdad53629e1, 0xbd13800000000000, + 0x3ff4ce41b817c132, 0x3d00800000000000, + 0x3ff4dcb299fddddb, 0x3d2c700000000000, + 0x3ff4eb2d81d8ab96, 0xbd1ce00000000000, + 0x3ff4f9b2769d2d02, 0x3d19200000000000, + 0x3ff508417f4531c1, 0xbd08c00000000000, + 0x3ff516daa2cf662a, 0xbcfa000000000000, + 0x3ff5257de83f51ea, 0x3d4a080000000000, + 0x3ff5342b569d4eda, 0xbd26d80000000000, + 0x3ff542e2f4f6ac1a, 0xbd32440000000000, + 0x3ff551a4ca5d94db, 0x3d483c0000000000, + 0x3ff56070dde9116b, 0x3d24b00000000000, + 0x3ff56f4736b529de, 0x3d415a0000000000, + 0x3ff57e27dbe2c40e, 0xbd29e00000000000, + 0x3ff58d12d497c76f, 0xbd23080000000000, + 0x3ff59c0827ff0b4c, 0x3d4dec0000000000, + 0x3ff5ab07dd485427, 0xbcc4000000000000, + 0x3ff5ba11fba87af4, 0x3d30080000000000, + 0x3ff5c9268a59460b, 0xbd26c80000000000, + 0x3ff5d84590998e3f, 0x3d469a0000000000, + 0x3ff5e76f15ad20e1, 0xbd1b400000000000, + 0x3ff5f6a320dcebca, 0x3d17700000000000, + 0x3ff605e1b976dcb8, 0x3d26f80000000000, + 0x3ff6152ae6cdf715, 0x3d01000000000000, + 0x3ff6247eb03a5531, 0xbd15d00000000000, + 0x3ff633dd1d1929b5, 0xbd12d00000000000, + 0x3ff6434634ccc313, 0xbcea800000000000, + 0x3ff652b9febc8efa, 0xbd28600000000000, + 0x3ff6623882553397, 0x3d71fe0000000000, + 0x3ff671c1c708328e, 0xbd37200000000000, + 0x3ff68155d44ca97e, 0x3ce6800000000000, + 0x3ff690f4b19e9471, 0xbd29780000000000, +]; + +// exp2(x): compute the base 2 exponential of x +// +// Accuracy: Peak error < 0.503 ulp for normalized results. +// +// Method: (accurate tables) +// +// Reduce x: +// x = k + y, for integer k and |y| <= 1/2. +// Thus we have exp2(x) = 2**k * exp2(y). +// +// Reduce y: +// y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. +// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), +// with |z - eps[i]| <= 2**-9 + 2**-39 for the table used. +// +// We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via +// a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61. +// The values in exp2t[] and eps[] are chosen such that +// exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such +// that exp2t[i] is accurate to 2**-64. +// +// Note that the range of i is +-TBLSIZE/2, so we actually index the tables +// by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are +// virtual tables, interleaved in the real table tbl[]. +// +// This method is due to Gal, with many details due to Gal and Bachelis: +// +// Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library +// for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + +/// Exponential, base 2 (f64) +/// +/// Calculate `2^x`, that is, 2 raised to the power `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp2(mut x: f64) -> f64 { + let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64; + let p1 = f64::from_bits(0x3fe62e42fefa39ef); + let p2 = f64::from_bits(0x3fcebfbdff82c575); + let p3 = f64::from_bits(0x3fac6b08d704a0a6); + let p4 = f64::from_bits(0x3f83b2ab88f70400); + let p5 = f64::from_bits(0x3f55d88003875c74); + + // double_t r, t, z; + // uint32_t ix, i0; + // union {double f; uint64_t i;} u = {x}; + // union {uint32_t u; int32_t i;} k; + let x1p1023 = f64::from_bits(0x7fe0000000000000); + let x1p52 = f64::from_bits(0x4330000000000000); + let _0x1p_149 = f64::from_bits(0xb6a0000000000000); + + /* Filter out exceptional cases. */ + let ui = f64::to_bits(x); + let ix = (ui >> 32) & 0x7fffffff; + if ix >= 0x408ff000 { + /* |x| >= 1022 or nan */ + if ix >= 0x40900000 && ui >> 63 == 0 { + /* x >= 1024 or nan */ + /* overflow */ + x *= x1p1023; + return x; + } + if ix >= 0x7ff00000 { + /* -inf or -nan */ + return -1.0 / x; + } + if ui >> 63 != 0 { + /* x <= -1022 */ + /* underflow */ + if x <= -1075.0 || x - x1p52 + x1p52 != x { + force_eval!((_0x1p_149 / x) as f32); + } + if x <= -1075.0 { + return 0.0; + } + } + } else if ix < 0x3c900000 { + /* |x| < 0x1p-54 */ + return 1.0 + x; + } + + /* Reduce x, computing z, i0, and k. */ + let ui = f64::to_bits(x + redux); + let mut i0 = ui as u32; + i0 = i0.wrapping_add(TBLSIZE as u32 / 2); + let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32; + let ki = div!(ku as i32, TBLSIZE as i32); + i0 %= TBLSIZE as u32; + let uf = f64::from_bits(ui) - redux; + let mut z = x - uf; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + let t = f64::from_bits(i!(TBL, 2 * i0 as usize)); /* exp2t[i0] */ + z -= f64::from_bits(i!(TBL, 2 * i0 as usize + 1)); /* eps[i0] */ + let r = t + t * z * (p1 + z * (p2 + z * (p3 + z * (p4 + z * p5)))); + + scalbn(r, ki) +} + +#[test] +fn i0_wrap_test() { + let x = -3.0 / 256.0; + assert_eq!(exp2(x), f64::from_bits(0x3fefbdba3692d514)); +} diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs new file mode 100644 index 00000000000..f452b6a20f8 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -0,0 +1,135 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c +//- +// Copyright (c) 2005 David Schultz +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +const TBLSIZE: usize = 16; + +static EXP2FT: [u64; TBLSIZE] = [ + 0x3fe6a09e667f3bcd, + 0x3fe7a11473eb0187, + 0x3fe8ace5422aa0db, + 0x3fe9c49182a3f090, + 0x3feae89f995ad3ad, + 0x3fec199bdd85529c, + 0x3fed5818dcfba487, + 0x3feea4afa2a490da, + 0x3ff0000000000000, + 0x3ff0b5586cf9890f, + 0x3ff172b83c7d517b, + 0x3ff2387a6e756238, + 0x3ff306fe0a31b715, + 0x3ff3dea64c123422, + 0x3ff4bfdad5362a27, + 0x3ff5ab07dd485429, +]; + +// exp2f(x): compute the base 2 exponential of x +// +// Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. +// +// Method: (equally-spaced tables) +// +// Reduce x: +// x = k + y, for integer k and |y| <= 1/2. +// Thus we have exp2f(x) = 2**k * exp2(y). +// +// Reduce y: +// y = i/TBLSIZE + z for integer i near y * TBLSIZE. +// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), +// with |z| <= 2**-(TBLSIZE+1). +// +// We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a +// degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. +// Using double precision for everything except the reduction makes +// roundoff error insignificant and simplifies the scaling step. +// +// This method is due to Tang, but I do not use his suggested parameters: +// +// Tang, P. Table-driven Implementation of the Exponential Function +// in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). + +/// Exponential, base 2 (f32) +/// +/// Calculate `2^x`, that is, 2 raised to the power `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp2f(mut x: f32) -> f32 { + let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; + let p1 = f32::from_bits(0x3f317218); + let p2 = f32::from_bits(0x3e75fdf0); + let p3 = f32::from_bits(0x3d6359a4); + let p4 = f32::from_bits(0x3c1d964e); + + // double_t t, r, z; + // uint32_t ix, i0, k; + + let x1p127 = f32::from_bits(0x7f000000); + + /* Filter out exceptional cases. */ + let ui = f32::to_bits(x); + let ix = ui & 0x7fffffff; + if ix > 0x42fc0000 { + /* |x| > 126 */ + if ix > 0x7f800000 { + /* NaN */ + return x; + } + if (0x43000000..0x80000000).contains(&ui) { + /* x >= 128 */ + x *= x1p127; + return x; + } + if ui >= 0x80000000 { + /* x < -126 */ + if ui >= 0xc3160000 || (ui & 0x0000ffff != 0) { + force_eval!(f32::from_bits(0x80000001) / x); + } + if ui >= 0xc3160000 { + /* x <= -150 */ + return 0.0; + } + } + } else if ix <= 0x33000000 { + /* |x| <= 0x1p-25 */ + return 1.0 + x; + } + + /* Reduce x, computing z, i0, and k. */ + let ui = f32::to_bits(x + redux); + let mut i0 = ui; + i0 += TBLSIZE as u32 / 2; + let k = i0 / TBLSIZE as u32; + let ukf = f64::from_bits(((0x3ff + k) as u64) << 52); + i0 &= TBLSIZE as u32 - 1; + let mut uf = f32::from_bits(ui); + uf -= redux; + let z: f64 = (x - uf) as f64; + /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ + let r: f64 = f64::from_bits(i!(EXP2FT, i0 as usize)); + let t: f64 = r * z; + let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64); + + /* Scale by 2**k */ + (r * ukf) as f32 +} diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs new file mode 100644 index 00000000000..8dc067ab084 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -0,0 +1,97 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::scalbnf; + +const HALF: [f32; 2] = [0.5, -0.5]; +const LN2_HI: f32 = 6.9314575195e-01; /* 0x3f317200 */ +const LN2_LO: f32 = 1.4286067653e-06; /* 0x35bfbe8e */ +const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: + * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 + */ +const P1: f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ +const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ + +/// Exponential, base *e* (f32) +/// +/// Calculate the exponential of `x`, that is, *e* raised to the power `x` +/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn expf(mut x: f32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ + let mut hx = x.to_bits(); + let sign = (hx >> 31) as i32; /* sign bit of x */ + let signb: bool = sign != 0; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if hx >= 0x42aeac50 { + /* if |x| >= -87.33655f or NaN */ + if hx > 0x7f800000 { + /* NaN */ + return x; + } + if (hx >= 0x42b17218) && (!signb) { + /* x >= 88.722839f */ + /* overflow */ + x *= x1p127; + return x; + } + if signb { + /* underflow */ + force_eval!(-x1p_126 / x); + if hx >= 0x42cff1b5 { + /* x <= -103.972084f */ + return 0.; + } + } + } + + /* argument reduction */ + let k: i32; + let hi: f32; + let lo: f32; + if hx > 0x3eb17218 { + /* if |x| > 0.5 ln2 */ + if hx > 0x3f851592 { + /* if |x| > 1.5 ln2 */ + k = (INV_LN2 * x + i!(HALF, sign as usize)) as i32; + } else { + k = 1 - sign - sign; + } + let kf = k as f32; + hi = x - kf * LN2_HI; /* k*ln2hi is exact here */ + lo = kf * LN2_LO; + x = hi - lo; + } else if hx > 0x39000000 { + /* |x| > 2**-14 */ + k = 0; + hi = x; + lo = 0.; + } else { + /* raise inexact */ + force_eval!(x1p127 + x); + return 1. + x; + } + + /* x is now in primary range */ + let xx = x * x; + let c = x - xx * (P1 + xx * P2); + let y = 1. + (x * c / (2. - c) - lo + hi); + if k == 0 { y } else { scalbnf(y, k) } +} diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs new file mode 100644 index 00000000000..f25153f32a3 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -0,0 +1,144 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f64; + +const O_THRESHOLD: f64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ +const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ +/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ +const Q1: f64 = -3.33333333333331316428e-02; /* BFA11111 111110F4 */ +const Q2: f64 = 1.58730158725481460165e-03; /* 3F5A01A0 19FE5585 */ +const Q3: f64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ +const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ +const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ + +/// Exponential, base *e*, of x-1 (f64) +/// +/// Calculates the exponential of `x` and subtract 1, that is, *e* raised +/// to the power `x` minus 1 (where *e* is the base of the natural +/// system of logarithms, approximately 2.71828). +/// The result is accurate even for small values of `x`, +/// where using `exp(x)-1` would lose many significant digits. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn expm1(mut x: f64) -> f64 { + let hi: f64; + let lo: f64; + let k: i32; + let c: f64; + let mut t: f64; + let mut y: f64; + + let mut ui = x.to_bits(); + let hx = ((ui >> 32) & 0x7fffffff) as u32; + let sign = (ui >> 63) as i32; + + /* filter out huge and non-finite argument */ + if hx >= 0x4043687A { + /* if |x|>=56*ln2 */ + if x.is_nan() { + return x; + } + if sign != 0 { + return -1.0; + } + if x > O_THRESHOLD { + x *= f64::from_bits(0x7fe0000000000000); + return x; + } + } + + /* argument reduction */ + if hx > 0x3fd62e42 { + /* if |x| > 0.5 ln2 */ + if hx < 0x3FF0A2B2 { + /* and |x| < 1.5 ln2 */ + if sign == 0 { + hi = x - LN2_HI; + lo = LN2_LO; + k = 1; + } else { + hi = x + LN2_HI; + lo = -LN2_LO; + k = -1; + } + } else { + k = (INVLN2 * x + if sign != 0 { -0.5 } else { 0.5 }) as i32; + t = k as f64; + hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ + lo = t * LN2_LO; + } + x = hi - lo; + c = (hi - x) - lo; + } else if hx < 0x3c900000 { + /* |x| < 2**-54, return x */ + if hx < 0x00100000 { + force_eval!(x); + } + return x; + } else { + c = 0.0; + k = 0; + } + + /* x is now in primary range */ + let hfx = 0.5 * x; + let hxs = x * hfx; + let r1 = 1.0 + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5)))); + t = 3.0 - r1 * hfx; + let mut e = hxs * ((r1 - t) / (6.0 - x * t)); + if k == 0 { + /* c is 0 */ + return x - (x * e - hxs); + } + e = x * (e - c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if k == -1 { + return 0.5 * (x - e) - 0.5; + } + if k == 1 { + if x < -0.25 { + return -2.0 * (e - (x + 0.5)); + } + return 1.0 + 2.0 * (x - e); + } + ui = ((0x3ff + k) as u64) << 52; /* 2^k */ + let twopk = f64::from_bits(ui); + if !(0..=56).contains(&k) { + /* suffice to return exp(x)-1 */ + y = x - e + 1.0; + if k == 1024 { + y = y * 2.0 * f64::from_bits(0x7fe0000000000000); + } else { + y = y * twopk; + } + return y - 1.0; + } + ui = ((0x3ff - k) as u64) << 52; /* 2^-k */ + let uf = f64::from_bits(ui); + if k < 20 { + y = (x - e + (1.0 - uf)) * twopk; + } else { + y = (x - (e + uf) + 1.0) * twopk; + } + y +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::expm1(1.1), 2.0041660239464334); + } +} diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs new file mode 100644 index 00000000000..12c6f532b96 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -0,0 +1,130 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +const O_THRESHOLD: f32 = 8.8721679688e+01; /* 0x42b17180 */ +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: + * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 + * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): + */ +const Q1: f32 = -3.3333212137e-2; /* -0x888868.0p-28 */ +const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ + +/// Exponential, base *e*, of x-1 (f32) +/// +/// Calculates the exponential of `x` and subtract 1, that is, *e* raised +/// to the power `x` minus 1 (where *e* is the base of the natural +/// system of logarithms, approximately 2.71828). +/// The result is accurate even for small values of `x`, +/// where using `exp(x)-1` would lose many significant digits. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn expm1f(mut x: f32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + + let mut hx = x.to_bits(); + let sign = (hx >> 31) != 0; + hx &= 0x7fffffff; + + /* filter out huge and non-finite argument */ + if hx >= 0x4195b844 { + /* if |x|>=27*ln2 */ + if hx > 0x7f800000 { + /* NaN */ + return x; + } + if sign { + return -1.; + } + if x > O_THRESHOLD { + x *= x1p127; + return x; + } + } + + let k: i32; + let hi: f32; + let lo: f32; + let mut c = 0f32; + /* argument reduction */ + if hx > 0x3eb17218 { + /* if |x| > 0.5 ln2 */ + if hx < 0x3F851592 { + /* and |x| < 1.5 ln2 */ + if !sign { + hi = x - LN2_HI; + lo = LN2_LO; + k = 1; + } else { + hi = x + LN2_HI; + lo = -LN2_LO; + k = -1; + } + } else { + k = (INV_LN2 * x + (if sign { -0.5 } else { 0.5 })) as i32; + let t = k as f32; + hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ + lo = t * LN2_LO; + } + x = hi - lo; + c = (hi - x) - lo; + } else if hx < 0x33000000 { + /* when |x|<2**-25, return x */ + if hx < 0x00800000 { + force_eval!(x * x); + } + return x; + } else { + k = 0; + } + + /* x is now in primary range */ + let hfx = 0.5 * x; + let hxs = x * hfx; + let r1 = 1. + hxs * (Q1 + hxs * Q2); + let t = 3. - r1 * hfx; + let mut e = hxs * ((r1 - t) / (6. - x * t)); + if k == 0 { + /* c is 0 */ + return x - (x * e - hxs); + } + e = x * (e - c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if k == -1 { + return 0.5 * (x - e) - 0.5; + } + if k == 1 { + if x < -0.25 { + return -2. * (e - (x + 0.5)); + } + return 1. + 2. * (x - e); + } + let twopk = f32::from_bits(((0x7f + k) << 23) as u32); /* 2^k */ + if !(0..=56).contains(&k) { + /* suffice to return exp(x)-1 */ + let mut y = x - e + 1.; + if k == 128 { + y = y * 2. * x1p127; + } else { + y = y * twopk; + } + return y - 1.; + } + let uf = f32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */ + if k < 23 { (x - e + (1. - uf)) * twopk } else { (x - (e + uf) + 1.) * twopk } +} diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs new file mode 100644 index 00000000000..82e9b360a76 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/expo2.rs @@ -0,0 +1,14 @@ +use super::{combine_words, exp}; + +/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn expo2(x: f64) -> f64 { + /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ + const K: i32 = 2043; + let kln2 = f64::from_bits(0x40962066151add8b); + + /* note that k is odd and scale*scale overflows */ + let scale = combine_words(((0x3ff + K / 2) as u32) << 20, 0); + /* exp(x - k ln2) * 2**(k-1) */ + exp(x - kln2) * scale * scale +} diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs new file mode 100644 index 00000000000..0050a309fee --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -0,0 +1,116 @@ +/// Absolute value (magnitude) (f16) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf16(x: f16) -> f16 { + super::generic::fabs(x) +} + +/// Absolute value (magnitude) (f32) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf(x: f32) -> f32 { + select_implementation! { + name: fabsf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::fabs(x) +} + +/// Absolute value (magnitude) (f64) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabs(x: f64) -> f64 { + select_implementation! { + name: fabs, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::fabs(x) +} + +/// Absolute value (magnitude) (f128) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf128(x: f128) -> f128 { + super::generic::fabs(x) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::Float; + + /// Based on https://en.cppreference.com/w/cpp/numeric/math/fabs + fn spec_test(f: impl Fn(F) -> F) { + assert_biteq!(f(F::ZERO), F::ZERO); + assert_biteq!(f(F::NEG_ZERO), F::ZERO); + assert_biteq!(f(F::INFINITY), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY), F::INFINITY); + assert!(f(F::NAN).is_nan()); + + // Not spec rewquired but we expect it + assert!(f(F::NAN).is_sign_positive()); + assert!(f(F::from_bits(F::NAN.to_bits() | F::SIGN_MASK)).is_sign_positive()); + } + + #[test] + #[cfg(f16_enabled)] + fn sanity_check_f16() { + assert_eq!(fabsf16(-1.0f16), 1.0); + assert_eq!(fabsf16(2.8f16), 2.8); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(fabsf16); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(fabsf(-1.0f32), 1.0); + assert_eq!(fabsf(2.8f32), 2.8); + } + + #[test] + fn spec_tests_f32() { + spec_test::(fabsf); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(fabs(-1.0f64), 1.0); + assert_eq!(fabs(2.8f64), 2.8); + } + + #[test] + fn spec_tests_f64() { + spec_test::(fabs); + } + + #[test] + #[cfg(f128_enabled)] + fn sanity_check_f128() { + assert_eq!(fabsf128(-1.0f128), 1.0); + assert_eq!(fabsf128(2.8f128), 2.8); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(fabsf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs new file mode 100644 index 00000000000..e5820a26c52 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -0,0 +1,39 @@ +/// Absolute value (magnitude) (f32) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf(x: f32) -> f32 { + select_implementation! { + name: fabsf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::fabs(x) +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf(-1.0), 1.0); + assert_eq!(fabsf(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf(f32::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf(f), 0.0); + } + for f in [f32::INFINITY, f32::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf(f), f32::INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/fabsf128.rs b/library/compiler-builtins/libm/src/math/fabsf128.rs new file mode 100644 index 00000000000..46429ca4940 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fabsf128.rs @@ -0,0 +1,31 @@ +/// Absolute value (magnitude) (f128) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf128(x: f128) -> f128 { + super::generic::fabs(x) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf128(-1.0), 1.0); + assert_eq!(fabsf128(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf128(f128::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf128(f), 0.0); + } + for f in [f128::INFINITY, f128::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf128(f), f128::INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/fabsf16.rs b/library/compiler-builtins/libm/src/math/fabsf16.rs new file mode 100644 index 00000000000..eee42ac6a3c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fabsf16.rs @@ -0,0 +1,31 @@ +/// Absolute value (magnitude) (f16) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf16(x: f16) -> f16 { + super::generic::fabs(x) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf16(-1.0), 1.0); + assert_eq!(fabsf16(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf16(f16::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf16(f), 0.0); + } + for f in [f16::INFINITY, f16::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf16(f), f16::INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs new file mode 100644 index 00000000000..082c5478b2a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -0,0 +1,53 @@ +/// Positive difference (f16) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf16(x: f16, y: f16) -> f16 { + super::generic::fdim(x, y) +} + +/// Positive difference (f32) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf(x: f32, y: f32) -> f32 { + super::generic::fdim(x, y) +} + +/// Positive difference (f64) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdim(x: f64, y: f64) -> f64 { + super::generic::fdim(x, y) +} + +/// Positive difference (f128) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf128(x: f128, y: f128) -> f128 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs new file mode 100644 index 00000000000..367ef517c63 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -0,0 +1,12 @@ +/// Positive difference (f32) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf(x: f32, y: f32) -> f32 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fdimf128.rs b/library/compiler-builtins/libm/src/math/fdimf128.rs new file mode 100644 index 00000000000..6f3d1d0ff1d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fdimf128.rs @@ -0,0 +1,12 @@ +/// Positive difference (f128) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf128(x: f128, y: f128) -> f128 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fdimf16.rs b/library/compiler-builtins/libm/src/math/fdimf16.rs new file mode 100644 index 00000000000..37bd6885817 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fdimf16.rs @@ -0,0 +1,12 @@ +/// Positive difference (f16) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf16(x: f16, y: f16) -> f16 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs new file mode 100644 index 00000000000..3c5eab101d1 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -0,0 +1,46 @@ +/// Floor (f16) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf16(x: f16) -> f16 { + return super::generic::floor(x); +} + +/// Floor (f64) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floor(x: f64) -> f64 { + select_implementation! { + name: floor, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), + args: x, + } + + return super::generic::floor(x); +} + +/// Floor (f32) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf(x: f32) -> f32 { + select_implementation! { + name: floorf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + return super::generic::floor(x); +} + +/// Floor (f128) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf128(x: f128) -> f128 { + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs new file mode 100644 index 00000000000..16957b7f355 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -0,0 +1,13 @@ +/// Floor (f32) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf(x: f32) -> f32 { + select_implementation! { + name: floorf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/src/math/floorf128.rs b/library/compiler-builtins/libm/src/math/floorf128.rs new file mode 100644 index 00000000000..9a9fe415115 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/floorf128.rs @@ -0,0 +1,7 @@ +/// Floor (f128) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf128(x: f128) -> f128 { + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/src/math/floorf16.rs b/library/compiler-builtins/libm/src/math/floorf16.rs new file mode 100644 index 00000000000..f9b868e0410 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/floorf16.rs @@ -0,0 +1,7 @@ +/// Floor (f16) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf16(x: f16) -> f16 { + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs new file mode 100644 index 00000000000..e0b3347acf8 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -0,0 +1,397 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ + +use super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; +use super::{CastFrom, CastInto, Float, Int, MinInt}; + +/// Fused multiply add (f64) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fma(x: f64, y: f64, z: f64) -> f64 { + select_implementation! { + name: fma, + use_arch: all(target_arch = "aarch64", target_feature = "neon"), + args: x, y, z, + } + + fma_round(x, y, z, Round::Nearest).val +} + +/// Fused multiply add (f128) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { + fma_round(x, y, z, Round::Nearest).val +} + +/// Fused multiply-add that works when there is not a larger float size available. Computes +/// `(x * y) + z`. +#[inline] +pub fn fma_round(x: F, y: F, z: F, _round: Round) -> FpResult +where + F: Float, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, +{ + let one = IntTy::::ONE; + let zero = IntTy::::ZERO; + + // Normalize such that the top of the mantissa is zero and we have a guard bit. + let nx = Norm::from_float(x); + let ny = Norm::from_float(y); + let nz = Norm::from_float(z); + + if nx.is_zero_nan_inf() || ny.is_zero_nan_inf() { + // Value will overflow, defer to non-fused operations. + return FpResult::ok(x * y + z); + } + + if nz.is_zero_nan_inf() { + if nz.is_zero() { + // Empty add component means we only need to multiply. + return FpResult::ok(x * y); + } + // `z` is NaN or infinity, which sets the result. + return FpResult::ok(z); + } + + // multiply: r = x * y + let zhi: F::Int; + let zlo: F::Int; + let (mut rlo, mut rhi) = nx.m.widen_mul(ny.m).lo_hi(); + + // Exponent result of multiplication + let mut e: i32 = nx.e + ny.e; + // Needed shift to align `z` to the multiplication result + let mut d: i32 = nz.e - e; + let sbits = F::BITS as i32; + + // Scale `z`. Shift `z <<= kz`, `r >>= kr`, so `kz+kr == d`, set `e = e+kr` (== ez-kz) + if d > 0 { + // The magnitude of `z` is larger than `x * y` + if d < sbits { + // Maximum shift of one `F::BITS` means shifted `z` will fit into `2 * F::BITS`. Shift + // it into `(zhi, zlo)`. No exponent adjustment necessary. + zlo = nz.m << d; + zhi = nz.m >> (sbits - d); + } else { + // Shift larger than `sbits`, `z` only needs the top half `zhi`. Place it there (acts + // as a shift by `sbits`). + zlo = zero; + zhi = nz.m; + d -= sbits; + + // `z`'s exponent is large enough that it now needs to be taken into account. + e = nz.e - sbits; + + if d == 0 { + // Exactly `sbits`, nothing to do + } else if d < sbits { + // Remaining shift fits within `sbits`. Leave `z` in place, shift `x * y` + rlo = (rhi << (sbits - d)) | (rlo >> d); + // Set the sticky bit + rlo |= IntTy::::from((rlo << (sbits - d)) != zero); + rhi = rhi >> d; + } else { + // `z`'s magnitude is enough that `x * y` is irrelevant. It was nonzero, so set + // the sticky bit. + rlo = one; + rhi = zero; + } + } + } else { + // `z`'s magnitude once shifted fits entirely within `zlo` + zhi = zero; + d = -d; + if d == 0 { + // No shift needed + zlo = nz.m; + } else if d < sbits { + // Shift s.t. `nz.m` fits into `zlo` + let sticky = IntTy::::from((nz.m << (sbits - d)) != zero); + zlo = (nz.m >> d) | sticky; + } else { + // Would be entirely shifted out, only set the sticky bit + zlo = one; + } + } + + /* addition */ + + let mut neg = nx.neg ^ ny.neg; + let samesign: bool = !neg ^ nz.neg; + let mut rhi_nonzero = true; + + if samesign { + // r += z + rlo = rlo.wrapping_add(zlo); + rhi += zhi + IntTy::::from(rlo < zlo); + } else { + // r -= z + let (res, borrow) = rlo.overflowing_sub(zlo); + rlo = res; + rhi = rhi.wrapping_sub(zhi.wrapping_add(IntTy::::from(borrow))); + if (rhi >> (F::BITS - 1)) != zero { + rlo = rlo.signed().wrapping_neg().unsigned(); + rhi = rhi.signed().wrapping_neg().unsigned() - IntTy::::from(rlo != zero); + neg = !neg; + } + rhi_nonzero = rhi != zero; + } + + /* Construct result */ + + // Shift result into `rhi`, left-aligned. Last bit is sticky + if rhi_nonzero { + // `d` > 0, need to shift both `rhi` and `rlo` into result + e += sbits; + d = rhi.leading_zeros() as i32 - 1; + rhi = (rhi << d) | (rlo >> (sbits - d)); + // Update sticky + rhi |= IntTy::::from((rlo << d) != zero); + } else if rlo != zero { + // `rhi` is zero, `rlo` is the entire result and needs to be shifted + d = rlo.leading_zeros() as i32 - 1; + if d < 0 { + // Shift and set sticky + rhi = (rlo >> 1) | (rlo & one); + } else { + rhi = rlo << d; + } + } else { + // exact +/- 0.0 + return FpResult::ok(x * y + z); + } + + e -= d; + + // Use int->float conversion to populate the significand. + // i is in [1 << (BITS - 2), (1 << (BITS - 1)) - 1] + let mut i: F::SignedInt = rhi.signed(); + + if neg { + i = -i; + } + + // `|r|` is in `[0x1p62,0x1p63]` for `f64` + let mut r: F = F::cast_from_lossy(i); + + /* Account for subnormal and rounding */ + + // Unbiased exponent for the maximum value of `r` + let max_pow = F::BITS - 1 + F::EXP_BIAS; + + let mut status = Status::OK; + + if e < -(max_pow as i32 - 2) { + // Result is subnormal before rounding + if e == -(max_pow as i32 - 1) { + let mut c = F::from_parts(false, max_pow, zero); + if neg { + c = -c; + } + + if r == c { + // Min normal after rounding, + status.set_underflow(true); + r = F::MIN_POSITIVE_NORMAL.copysign(r); + return FpResult::new(r, status); + } + + if (rhi << (F::SIG_BITS + 1)) != zero { + // Account for truncated bits. One bit will be lost in the `scalbn` call, add + // another top bit to avoid double rounding if inexact. + let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << (F::BITS - 2)); + i = iu.signed(); + + if neg { + i = -i; + } + + r = F::cast_from_lossy(i); + + // Remove the top bit + r = F::cast_from(2i8) * r - c; + status.set_underflow(true); + } + } else { + // Only round once when scaled + d = F::EXP_BITS as i32 - 1; + let sticky = IntTy::::from(rhi << (F::BITS as i32 - d) != zero); + i = (((rhi >> d) | sticky) << d).signed(); + + if neg { + i = -i; + } + + r = F::cast_from_lossy(i); + } + } + + // Use our exponent to scale the final value. + FpResult::new(super::generic::scalbn(r, e), status) +} + +/// Representation of `F` that has handled subnormals. +#[derive(Clone, Copy, Debug)] +struct Norm { + /// Normalized significand with one guard bit, unsigned. + m: F::Int, + /// Exponent of the mantissa such that `m * 2^e = x`. Accounts for the shift in the mantissa + /// and the guard bit; that is, 1.0 will normalize as `m = 1 << 53` and `e = -53`. + e: i32, + neg: bool, +} + +impl Norm { + /// Unbias the exponent and account for the mantissa's precision, including the guard bit. + const EXP_UNBIAS: u32 = F::EXP_BIAS + F::SIG_BITS + 1; + + /// Values greater than this had a saturated exponent (infinity or NaN), OR were zero and we + /// adjusted the exponent such that it exceeds this threashold. + const ZERO_INF_NAN: u32 = F::EXP_SAT - Self::EXP_UNBIAS; + + fn from_float(x: F) -> Self { + let mut ix = x.to_bits(); + let mut e = x.ex() as i32; + let neg = x.is_sign_negative(); + if e == 0 { + // Normalize subnormals by multiplication + let scale_i = F::BITS - 1; + let scale_f = F::from_parts(false, scale_i + F::EXP_BIAS, F::Int::ZERO); + let scaled = x * scale_f; + ix = scaled.to_bits(); + e = scaled.ex() as i32; + e = if e == 0 { + // If the exponent is still zero, the input was zero. Artifically set this value + // such that the final `e` will exceed `ZERO_INF_NAN`. + 1 << F::EXP_BITS + } else { + // Otherwise, account for the scaling we just did. + e - scale_i as i32 + }; + } + + e -= Self::EXP_UNBIAS as i32; + + // Absolute value, set the implicit bit, and shift to create a guard bit + ix &= F::SIG_MASK; + ix |= F::IMPLICIT_BIT; + ix <<= 1; + + Self { m: ix, e, neg } + } + + /// True if the value was zero, infinity, or NaN. + fn is_zero_nan_inf(self) -> bool { + self.e >= Self::ZERO_INF_NAN as i32 + } + + /// The only value we have + fn is_zero(self) -> bool { + // The only exponent that strictly exceeds this value is our sentinel value for zero. + self.e > Self::ZERO_INF_NAN as i32 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Test the generic `fma_round` algorithm for a given float. + fn spec_test() + where + F: Float, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, + { + let x = F::from_bits(F::Int::ONE); + let y = F::from_bits(F::Int::ONE); + let z = F::ZERO; + + let fma = |x, y, z| fma_round(x, y, z, Round::Nearest).val; + + // 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of + // fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the + // exact result" + assert_biteq!(fma(x, y, z), F::ZERO); + assert_biteq!(fma(x, -y, z), F::NEG_ZERO); + assert_biteq!(fma(-x, y, z), F::NEG_ZERO); + assert_biteq!(fma(-x, -y, z), F::ZERO); + } + + #[test] + fn spec_test_f32() { + spec_test::(); + } + + #[test] + fn spec_test_f64() { + spec_test::(); + + let expect_underflow = [ + ( + hf64!("0x1.0p-1070"), + hf64!("0x1.0p-1070"), + hf64!("0x1.ffffffffffffp-1023"), + hf64!("0x0.ffffffffffff8p-1022"), + ), + ( + // FIXME: we raise underflow but this should only be inexact (based on C and + // `rustc_apfloat`). + hf64!("0x1.0p-1070"), + hf64!("0x1.0p-1070"), + hf64!("-0x1.0p-1022"), + hf64!("-0x1.0p-1022"), + ), + ]; + + for (x, y, z, res) in expect_underflow { + let FpResult { val, status } = fma_round(x, y, z, Round::Nearest); + assert_biteq!(val, res); + assert_eq!(status, Status::UNDERFLOW); + } + } + + #[test] + #[cfg(f128_enabled)] + fn spec_test_f128() { + spec_test::(); + } + + #[test] + fn fma_segfault() { + // These two inputs cause fma to segfault on release due to overflow: + assert_eq!( + fma( + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313 + ), + -0.00000000000000022204460492503126, + ); + + let result = fma(-0.992, -0.992, -0.992); + //force rounding to storage format on x87 to prevent superious errors. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let result = force_eval!(result); + assert_eq!(result, -0.007936000000000007,); + } + + #[test] + fn fma_sbb() { + assert_eq!(fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), -3991680619069439e277); + } + + #[test] + fn fma_underflow() { + assert_eq!(fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), 0.0,); + } +} diff --git a/library/compiler-builtins/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/src/math/fma_wide.rs new file mode 100644 index 00000000000..08b78b02264 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fma_wide.rs @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fmaf.c. Ported to generic Rust algorithm in 2025, TG. */ + +use super::support::{FpResult, IntTy, Round, Status}; +use super::{CastFrom, CastInto, DFloat, Float, HFloat, MinInt}; + +// Placeholder so we can have `fmaf16` in the `Float` trait. +#[allow(unused)] +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 { + unimplemented!() +} + +/// Floating multiply add (f32) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { + select_implementation! { + name: fmaf, + use_arch: all(target_arch = "aarch64", target_feature = "neon"), + args: x, y, z, + } + + fma_wide_round(x, y, z, Round::Nearest).val +} + +/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, +/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. +#[inline] +pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult +where + F: Float + HFloat, + B: Float + DFloat, + B::Int: CastInto, + i32: CastFrom, +{ + let one = IntTy::::ONE; + + let xy: B = x.widen() * y.widen(); + let mut result: B = xy + z.widen(); + let mut ui: B::Int = result.to_bits(); + let re = result.ex(); + let zb: B = z.widen(); + + let prec_diff = B::SIG_BITS - F::SIG_BITS; + let excess_prec = ui & ((one << prec_diff) - one); + let halfway = one << (prec_diff - 1); + + // Common case: the larger precision is fine if... + // This is not a halfway case + if excess_prec != halfway + // Or the result is NaN + || re == B::EXP_SAT + // Or the result is exact + || (result - xy == zb && result - zb == xy) + // Or the mode is something other than round to nearest + || round != Round::Nearest + { + let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; + let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; + + let mut status = Status::OK; + + if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() { + // This branch is never hit; requires previous operations to set a status + status.set_inexact(false); + + result = xy + z.widen(); + if status.inexact() { + status.set_underflow(true); + } else { + status.set_inexact(true); + } + } + + return FpResult { val: result.narrow(), status }; + } + + let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; + let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy }; + if neg == (err < B::ZERO) { + ui += one; + } else { + ui -= one; + } + + FpResult::ok(B::from_bits(ui).narrow()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn issue_263() { + let a = f32::from_bits(1266679807); + let b = f32::from_bits(1300234242); + let c = f32::from_bits(1115553792); + let expected = f32::from_bits(1501560833); + assert_eq!(fmaf(a, b, c), expected); + } +} diff --git a/library/compiler-builtins/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/src/math/fmin_fmax.rs new file mode 100644 index 00000000000..2947b783e2f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmin_fmax.rs @@ -0,0 +1,167 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf16(x: f16, y: f16) -> f16 { + super::generic::fmin(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf(x: f32, y: f32) -> f32 { + super::generic::fmin(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmin(x: f64, y: f64) -> f64 { + super::generic::fmin(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf128(x: f128, y: f128) -> f128 { + super::generic::fmin(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf16(x: f16, y: f16) -> f16 { + super::generic::fmax(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf(x: f32, y: f32) -> f32 { + super::generic::fmax(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmax(x: f64, y: f64) -> f64 { + super::generic::fmax(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf128(x: f128, y: f128) -> f128 { + super::generic::fmax(x, y) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, Hexf}; + + fn fmin_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmin_spec_tests_f16() { + fmin_spec_test::(fminf16); + } + + #[test] + fn fmin_spec_tests_f32() { + fmin_spec_test::(fminf); + } + + #[test] + fn fmin_spec_tests_f64() { + fmin_spec_test::(fmin); + } + + #[test] + #[cfg(f128_enabled)] + fn fmin_spec_tests_f128() { + fmin_spec_test::(fminf128); + } + + fn fmax_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmax_spec_tests_f16() { + fmax_spec_test::(fmaxf16); + } + + #[test] + fn fmax_spec_tests_f32() { + fmax_spec_test::(fmaxf); + } + + #[test] + fn fmax_spec_tests_f64() { + fmax_spec_test::(fmax); + } + + #[test] + #[cfg(f128_enabled)] + fn fmax_spec_tests_f128() { + fmax_spec_test::(fmaxf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs new file mode 100644 index 00000000000..b7999e27392 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs @@ -0,0 +1,163 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimumf16(x: f16, y: f16) -> f16 { + super::generic::fminimum(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum(x: f64, y: f64) -> f64 { + super::generic::fminimum(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimumf(x: f32, y: f32) -> f32 { + super::generic::fminimum(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimumf128(x: f128, y: f128) -> f128 { + super::generic::fminimum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximumf16(x: f16, y: f16) -> f16 { + super::generic::fmaximum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximumf(x: f32, y: f32) -> f32 { + super::generic::fmaximum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum(x: f64, y: f64) -> f64 { + super::generic::fmaximum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximumf128(x: f128, y: f128) -> f128 { + super::generic::fmaximum(x, y) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, Hexf}; + + fn fminimum_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::NAN), + (F::ZERO, F::NAN, F::NAN), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fminimum_spec_tests_f16() { + fminimum_spec_test::(fminimumf16); + } + + #[test] + fn fminimum_spec_tests_f32() { + fminimum_spec_test::(fminimumf); + } + + #[test] + fn fminimum_spec_tests_f64() { + fminimum_spec_test::(fminimum); + } + + #[test] + #[cfg(f128_enabled)] + fn fminimum_spec_tests_f128() { + fminimum_spec_test::(fminimumf128); + } + + fn fmaximum_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::NAN), + (F::ZERO, F::NAN, F::NAN), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::ZERO), + (F::NEG_ZERO, F::ZERO, F::ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmaximum_spec_tests_f16() { + fmaximum_spec_test::(fmaximumf16); + } + + #[test] + fn fmaximum_spec_tests_f32() { + fmaximum_spec_test::(fmaximumf); + } + + #[test] + fn fmaximum_spec_tests_f64() { + fmaximum_spec_test::(fmaximum); + } + + #[test] + #[cfg(f128_enabled)] + fn fmaximum_spec_tests_f128() { + fmaximum_spec_test::(fmaximumf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs new file mode 100644 index 00000000000..180d21f72b7 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs @@ -0,0 +1,163 @@ +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_numf16(x: f16, y: f16) -> f16 { + super::generic::fminimum_num(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_numf(x: f32, y: f32) -> f32 { + super::generic::fminimum_num(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_num(x: f64, y: f64) -> f64 { + super::generic::fminimum_num(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_numf128(x: f128, y: f128) -> f128 { + super::generic::fminimum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_numf16(x: f16, y: f16) -> f16 { + super::generic::fmaximum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_numf(x: f32, y: f32) -> f32 { + super::generic::fmaximum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_num(x: f64, y: f64) -> f64 { + super::generic::fmaximum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_numf128(x: f128, y: f128) -> f128 { + super::generic::fmaximum_num(x, y) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, Hexf}; + + fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fminimum_num_spec_tests_f16() { + fminimum_num_spec_test::(fminimum_numf16); + } + + #[test] + fn fminimum_num_spec_tests_f32() { + fminimum_num_spec_test::(fminimum_numf); + } + + #[test] + fn fminimum_num_spec_tests_f64() { + fminimum_num_spec_test::(fminimum_num); + } + + #[test] + #[cfg(f128_enabled)] + fn fminimum_num_spec_tests_f128() { + fminimum_num_spec_test::(fminimum_numf128); + } + + fn fmaximum_num_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::ZERO), + (F::NEG_ZERO, F::ZERO, F::ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmaximum_num_spec_tests_f16() { + fmaximum_num_spec_test::(fmaximum_numf16); + } + + #[test] + fn fmaximum_num_spec_tests_f32() { + fmaximum_num_spec_test::(fmaximum_numf); + } + + #[test] + fn fmaximum_num_spec_tests_f64() { + fmaximum_num_spec_test::(fmaximum_num); + } + + #[test] + #[cfg(f128_enabled)] + fn fmaximum_num_spec_tests_f128() { + fmaximum_num_spec_test::(fmaximum_numf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs new file mode 100644 index 00000000000..c4752b92578 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -0,0 +1,25 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf16(x: f16, y: f16) -> f16 { + super::generic::fmod(x, y) +} + +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf(x: f32, y: f32) -> f32 { + super::generic::fmod(x, y) +} + +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmod(x: f64, y: f64) -> f64 { + super::generic::fmod(x, y) +} + +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf128(x: f128, y: f128) -> f128 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs new file mode 100644 index 00000000000..4e95696e20d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -0,0 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf(x: f32, y: f32) -> f32 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fmodf128.rs b/library/compiler-builtins/libm/src/math/fmodf128.rs new file mode 100644 index 00000000000..ff0e0493e26 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmodf128.rs @@ -0,0 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf128(x: f128, y: f128) -> f128 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fmodf16.rs b/library/compiler-builtins/libm/src/math/fmodf16.rs new file mode 100644 index 00000000000..11972a7de4f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmodf16.rs @@ -0,0 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf16(x: f16, y: f16) -> f16 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/frexp.rs b/library/compiler-builtins/libm/src/math/frexp.rs new file mode 100644 index 00000000000..de7a64fdae1 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/frexp.rs @@ -0,0 +1,21 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn frexp(x: f64) -> (f64, i32) { + let mut y = x.to_bits(); + let ee = ((y >> 52) & 0x7ff) as i32; + + if ee == 0 { + if x != 0.0 { + let x1p64 = f64::from_bits(0x43f0000000000000); + let (x, e) = frexp(x * x1p64); + return (x, e - 64); + } + return (x, 0); + } else if ee == 0x7ff { + return (x, 0); + } + + let e = ee - 0x3fe; + y &= 0x800fffffffffffff; + y |= 0x3fe0000000000000; + return (f64::from_bits(y), e); +} diff --git a/library/compiler-builtins/libm/src/math/frexpf.rs b/library/compiler-builtins/libm/src/math/frexpf.rs new file mode 100644 index 00000000000..0ec91c2d350 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/frexpf.rs @@ -0,0 +1,22 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn frexpf(x: f32) -> (f32, i32) { + let mut y = x.to_bits(); + let ee: i32 = ((y >> 23) & 0xff) as i32; + + if ee == 0 { + if x != 0.0 { + let x1p64 = f32::from_bits(0x5f800000); + let (x, e) = frexpf(x * x1p64); + return (x, e - 64); + } else { + return (x, 0); + } + } else if ee == 0xff { + return (x, 0); + } + + let e = ee - 0x7e; + y &= 0x807fffff; + y |= 0x3f000000; + (f32::from_bits(y), e) +} diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs new file mode 100644 index 00000000000..5c5bb47638f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/ceilf.c */ + +//! Generic `ceil` algorithm. +//! +//! Note that this uses the algorithm from musl's `ceilf` rather than `ceil` or `ceill` because +//! performance seems to be better (based on icount) and it does not seem to experience rounding +//! errors on i386. + +use super::super::support::{FpResult, Status}; +use super::super::{Float, Int, IntTy, MinInt}; + +#[inline] +pub fn ceil(x: F) -> F { + ceil_status(x).val +} + +#[inline] +pub fn ceil_status(x: F) -> FpResult { + let zero = IntTy::::ZERO; + + let mut ix = x.to_bits(); + let e = x.exp_unbiased(); + + // If the represented value has no fractional part, no truncation is needed. + if e >= F::SIG_BITS as i32 { + return FpResult::ok(x); + } + + let status; + let res = if e >= 0 { + // |x| >= 1.0 + let m = F::SIG_MASK >> e.unsigned(); + if (ix & m) == zero { + // Portion to be masked is already zero; no adjustment needed. + return FpResult::ok(x); + } + + // Otherwise, raise an inexact exception. + status = Status::INEXACT; + + if x.is_sign_positive() { + ix += m; + } + + ix &= !m; + F::from_bits(ix) + } else { + // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). + if ix & F::SIG_MASK == F::Int::ZERO { + status = Status::OK; + } else { + status = Status::INEXACT; + } + + if x.is_sign_negative() { + // -1.0 < x <= -0.0; rounding up goes toward -0.0. + F::NEG_ZERO + } else if ix << 1 != zero { + // 0.0 < x < 1.0; rounding up goes toward +1.0. + F::ONE + } else { + // +0.0 remains unchanged + x + } + }; + + FpResult::new(res, status) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::Hexf; + + /// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil + fn spec_test(cases: &[(F, F, Status)]) { + let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + + for x in roundtrip { + let FpResult { val, status } = ceil_status(x); + assert_biteq!(val, x, "{}", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = ceil_status(x); + assert_biteq!(val, res, "{}", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); + } + } + + /* Skipping f16 / f128 "sanity_check"s due to rejected literal lexing at MSRV */ + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 2.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(ceil(1.1f32), 2.0); + assert_eq!(ceil(2.9f32), 3.0); + } + + #[test] + fn spec_tests_f32() { + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 2.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(ceil(1.1f64), 2.0); + assert_eq!(ceil(2.9f64), 3.0); + } + + #[test] + fn spec_tests_f64() { + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 2.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 2.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/copysign.rs b/library/compiler-builtins/libm/src/math/generic/copysign.rs new file mode 100644 index 00000000000..a61af22f04a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/copysign.rs @@ -0,0 +1,11 @@ +use super::super::Float; + +/// Copy the sign of `y` to `x`. +#[inline] +pub fn copysign(x: F, y: F) -> F { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= !F::SIGN_MASK; + ux |= uy & F::SIGN_MASK; + F::from_bits(ux) +} diff --git a/library/compiler-builtins/libm/src/math/generic/fabs.rs b/library/compiler-builtins/libm/src/math/generic/fabs.rs new file mode 100644 index 00000000000..0fa0edf9b87 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fabs.rs @@ -0,0 +1,8 @@ +use super::super::Float; + +/// Absolute value. +#[inline] +pub fn fabs(x: F) -> F { + let abs_mask = !F::SIGN_MASK; + F::from_bits(x.to_bits() & abs_mask) +} diff --git a/library/compiler-builtins/libm/src/math/generic/fdim.rs b/library/compiler-builtins/libm/src/math/generic/fdim.rs new file mode 100644 index 00000000000..a63007b191c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fdim.rs @@ -0,0 +1,6 @@ +use super::super::Float; + +#[inline] +pub fn fdim(x: F, y: F) -> F { + if x <= y { F::ZERO } else { x - y } +} diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs new file mode 100644 index 00000000000..2438046254f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/floor.rs @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: MIT + * origin: musl src/math/floor.c */ + +//! Generic `floor` algorithm. +//! +//! Note that this uses the algorithm from musl's `floorf` rather than `floor` or `floorl` because +//! performance seems to be better (based on icount) and it does not seem to experience rounding +//! errors on i386. + +use super::super::support::{FpResult, Status}; +use super::super::{Float, Int, IntTy, MinInt}; + +#[inline] +pub fn floor(x: F) -> F { + floor_status(x).val +} + +#[inline] +pub fn floor_status(x: F) -> FpResult { + let zero = IntTy::::ZERO; + + let mut ix = x.to_bits(); + let e = x.exp_unbiased(); + + // If the represented value has no fractional part, no truncation is needed. + if e >= F::SIG_BITS as i32 { + return FpResult::ok(x); + } + + let status; + let res = if e >= 0 { + // |x| >= 1.0 + let m = F::SIG_MASK >> e.unsigned(); + if ix & m == zero { + // Portion to be masked is already zero; no adjustment needed. + return FpResult::ok(x); + } + + // Otherwise, raise an inexact exception. + status = Status::INEXACT; + + if x.is_sign_negative() { + ix += m; + } + + ix &= !m; + F::from_bits(ix) + } else { + // |x| < 1.0, raise an inexact exception since truncation will happen. + if ix & F::SIG_MASK == F::Int::ZERO { + status = Status::OK; + } else { + status = Status::INEXACT; + } + + if x.is_sign_positive() { + // 0.0 <= x < 1.0; rounding down goes toward +0.0. + F::ZERO + } else if ix << 1 != zero { + // -1.0 < x < 0.0; rounding down goes toward -1.0. + F::NEG_ONE + } else { + // -0.0 remains unchanged + x + } + }; + + FpResult::new(res, status) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::Hexf; + + /// Test against https://en.cppreference.com/w/cpp/numeric/math/floor + fn spec_test(cases: &[(F, F, Status)]) { + let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + + for x in roundtrip { + let FpResult { val, status } = floor_status(x); + assert_biteq!(val, x, "{}", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = floor_status(x); + assert_biteq!(val, res, "{}", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); + } + } + + /* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */ + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + let cases = []; + spec_test::(&cases); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(floor(0.5f32), 0.0); + assert_eq!(floor(1.1f32), 1.0); + assert_eq!(floor(2.9f32), 2.0); + } + + #[test] + fn spec_tests_f32() { + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -1.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -1.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -2.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -2.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(floor(1.1f64), 1.0); + assert_eq!(floor(2.9f64), 2.0); + } + + #[test] + fn spec_tests_f64() { + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -1.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -1.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -2.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -2.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + let cases = []; + spec_test::(&cases); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs new file mode 100644 index 00000000000..bf3f847e89b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmax.rs @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2011 `maxNum`. This has been superseded by IEEE 754-2019 `maximumNumber`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x > y` +//! - `y` if `y > x` +//! - The other number if one is NaN +//! - Otherwise, either `x` or `y`, canonicalized +//! - -0.0 and +0.0 may be disregarded (unlike newer operations) +//! +//! Excluded from our implementation is sNaN handling. +//! +//! More on the differences: [link]. +//! +//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf + +use super::super::Float; + +#[inline] +pub fn fmax(x: F, y: F) -> F { + let res = if x.is_nan() || x < y { y } else { x }; + // Canonicalize + res * F::ONE +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs new file mode 100644 index 00000000000..387055af29c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `maximum`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x > y` +//! - `y` if `y > x` +//! - qNaN if either operation is NaN +//! - Logic following +0.0 > -0.0 +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +#[inline] +pub fn fmaximum(x: F, y: F) -> F { + let res = if x.is_nan() { + x + } else if y.is_nan() { + y + } else if x > y || (y.to_bits() == F::NEG_ZERO.to_bits() && x.is_sign_positive()) { + x + } else { + y + }; + + // Canonicalize + res * F::ONE +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs new file mode 100644 index 00000000000..f7efdde80ea --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `maximumNumber`. +//! +//! Per the spec, returns: +//! - `x` if `x > y` +//! - `y` if `y > x` +//! - Non-NaN if one operand is NaN +//! - Logic following +0.0 > -0.0 +//! - Either `x` or `y` if `x == y` and the signs are the same +//! - qNaN if either operand is a NaN +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +#[inline] +pub fn fmaximum_num(x: F, y: F) -> F { + let res = + if x.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { + y + } else { + x + }; + + // Canonicalize + res * F::ONE +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs new file mode 100644 index 00000000000..cd3caeee4f2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmin.rs @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2008 `minNum`. This has been superseded by IEEE 754-2019 `minimumNumber`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x < y` +//! - `y` if `y < x` +//! - The other number if one is NaN +//! - Otherwise, either `x` or `y`, canonicalized +//! - -0.0 and +0.0 may be disregarded (unlike newer operations) +//! +//! Excluded from our implementation is sNaN handling. +//! +//! More on the differences: [link]. +//! +//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf + +use super::super::Float; + +#[inline] +pub fn fmin(x: F, y: F) -> F { + let res = if y.is_nan() || x < y { x } else { y }; + // Canonicalize + res * F::ONE +} diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs new file mode 100644 index 00000000000..4ddb3645506 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fminimum.rs @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `minimum`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x < y` +//! - `y` if `y < x` +//! - qNaN if either operation is NaN +//! - Logic following +0.0 > -0.0 +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +#[inline] +pub fn fminimum(x: F, y: F) -> F { + let res = if x.is_nan() { + x + } else if y.is_nan() { + y + } else if x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { + x + } else { + y + }; + + // Canonicalize + res * F::ONE +} diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs new file mode 100644 index 00000000000..441c204a921 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `minimum`. +//! +//! Per the spec, returns: +//! - `x` if `x < y` +//! - `y` if `y < x` +//! - Non-NaN if one operand is NaN +//! - Logic following +0.0 > -0.0 +//! - Either `x` or `y` if `x == y` and the signs are the same +//! - qNaN if either operand is a NaN +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +#[inline] +pub fn fminimum_num(x: F, y: F) -> F { + let res = + if y.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { + x + } else { + y + }; + + // Canonicalize + res * F::ONE +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs new file mode 100644 index 00000000000..6414bbd2508 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fmod.c. Ported to generic Rust algorithm in 2025, TG. */ + +use super::super::{CastFrom, Float, Int, MinInt}; + +#[inline] +pub fn fmod(x: F, y: F) -> F { + let zero = F::Int::ZERO; + let one = F::Int::ONE; + let mut ix = x.to_bits(); + let mut iy = y.to_bits(); + let mut ex = x.ex().signed(); + let mut ey = y.ex().signed(); + let sx = ix & F::SIGN_MASK; + + if iy << 1 == zero || y.is_nan() || ex == F::EXP_SAT as i32 { + return (x * y) / (x * y); + } + + if ix << 1 <= iy << 1 { + if ix << 1 == iy << 1 { + return F::ZERO * x; + } + return x; + } + + /* normalize x and y */ + if ex == 0 { + let i = ix << (F::EXP_BITS + 1); + ex -= i.leading_zeros() as i32; + ix <<= -ex + 1; + } else { + ix &= F::Int::MAX >> F::EXP_BITS; + ix |= one << F::SIG_BITS; + } + + if ey == 0 { + let i = iy << (F::EXP_BITS + 1); + ey -= i.leading_zeros() as i32; + iy <<= -ey + 1; + } else { + iy &= F::Int::MAX >> F::EXP_BITS; + iy |= one << F::SIG_BITS; + } + + /* x mod y */ + while ex > ey { + let i = ix.wrapping_sub(iy); + if i >> (F::BITS - 1) == zero { + if i == zero { + return F::ZERO * x; + } + ix = i; + } + + ix <<= 1; + ex -= 1; + } + + let i = ix.wrapping_sub(iy); + if i >> (F::BITS - 1) == zero { + if i == zero { + return F::ZERO * x; + } + + ix = i; + } + + let shift = ix.leading_zeros().saturating_sub(F::EXP_BITS); + ix <<= shift; + ex -= shift as i32; + + /* scale result */ + if ex > 0 { + ix -= one << F::SIG_BITS; + ix |= F::Int::cast_from(ex) << F::SIG_BITS; + } else { + ix >>= -ex + 1; + } + + ix |= sx; + + F::from_bits(ix) +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs new file mode 100644 index 00000000000..35846351a6e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -0,0 +1,38 @@ +// Note: generic functions are marked `#[inline]` because, even though generic functions are +// typically inlined, this does not seem to always be the case. + +mod ceil; +mod copysign; +mod fabs; +mod fdim; +mod floor; +mod fmax; +mod fmaximum; +mod fmaximum_num; +mod fmin; +mod fminimum; +mod fminimum_num; +mod fmod; +mod rint; +mod round; +mod scalbn; +mod sqrt; +mod trunc; + +pub use ceil::ceil; +pub use copysign::copysign; +pub use fabs::fabs; +pub use fdim::fdim; +pub use floor::floor; +pub use fmax::fmax; +pub use fmaximum::fmaximum; +pub use fmaximum_num::fmaximum_num; +pub use fmin::fmin; +pub use fminimum::fminimum; +pub use fminimum_num::fminimum_num; +pub use fmod::fmod; +pub use rint::rint_round; +pub use round::round; +pub use scalbn::scalbn; +pub use sqrt::sqrt; +pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs new file mode 100644 index 00000000000..9cdeb1185a8 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/rint.c */ + +use super::super::Float; +use super::super::support::{FpResult, Round}; + +/// IEEE 754-2019 `roundToIntegralExact`, which respects rounding mode and raises inexact if +/// applicable. +#[inline] +pub fn rint_round(x: F, _round: Round) -> FpResult { + let toint = F::ONE / F::EPSILON; + let e = x.ex(); + let positive = x.is_sign_positive(); + + // On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise, + // the excess precission from x87 would cause an incorrect final result. + let force = |x| { + if cfg!(x86_no_sse) && (F::BITS == 32 || F::BITS == 64) { force_eval!(x) } else { x } + }; + + let res = if e >= F::EXP_BIAS + F::SIG_BITS { + // No fractional part; exact result can be returned. + x + } else { + // Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode. For + // Rust this is always nearest, but ideally it would take `round` into account. + let y = if positive { + force(force(x) + toint) - toint + } else { + force(force(x) - toint) + toint + }; + + if y == F::ZERO { + // A zero result takes the sign of the input. + if positive { F::ZERO } else { F::NEG_ZERO } + } else { + y + } + }; + + FpResult::ok(res) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Hexf, Status}; + + fn spec_test(cases: &[(F, F, Status)]) { + let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + + for x in roundtrip { + let FpResult { val, status } = rint_round(x, Round::Nearest); + assert_biteq!(val, x, "rint_round({})", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = rint_round(x, Round::Nearest); + assert_biteq!(val, res, "rint_round({})", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + let cases = []; + spec_test::(&cases); + } + + #[test] + fn spec_tests_f32() { + let cases = [ + (0.1, 0.0, Status::OK), + (-0.1, -0.0, Status::OK), + (0.5, 0.0, Status::OK), + (-0.5, -0.0, Status::OK), + (0.9, 1.0, Status::OK), + (-0.9, -1.0, Status::OK), + (1.1, 1.0, Status::OK), + (-1.1, -1.0, Status::OK), + (1.5, 2.0, Status::OK), + (-1.5, -2.0, Status::OK), + (1.9, 2.0, Status::OK), + (-1.9, -2.0, Status::OK), + (2.8, 3.0, Status::OK), + (-2.8, -3.0, Status::OK), + ]; + spec_test::(&cases); + } + + #[test] + fn spec_tests_f64() { + let cases = [ + (0.1, 0.0, Status::OK), + (-0.1, -0.0, Status::OK), + (0.5, 0.0, Status::OK), + (-0.5, -0.0, Status::OK), + (0.9, 1.0, Status::OK), + (-0.9, -1.0, Status::OK), + (1.1, 1.0, Status::OK), + (-1.1, -1.0, Status::OK), + (1.5, 2.0, Status::OK), + (-1.5, -2.0, Status::OK), + (1.9, 2.0, Status::OK), + (-1.9, -2.0, Status::OK), + (2.8, 3.0, Status::OK), + (-2.8, -3.0, Status::OK), + ]; + spec_test::(&cases); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + let cases = []; + spec_test::(&cases); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/round.rs b/library/compiler-builtins/libm/src/math/generic/round.rs new file mode 100644 index 00000000000..01314ac70c2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/round.rs @@ -0,0 +1,83 @@ +use super::super::{Float, MinInt}; +use super::{copysign, trunc}; + +#[inline] +pub fn round(x: F) -> F { + let f0p5 = F::from_parts(false, F::EXP_BIAS - 1, F::Int::ZERO); // 0.5 + let f0p25 = F::from_parts(false, F::EXP_BIAS - 2, F::Int::ZERO); // 0.25 + + trunc(x + copysign(f0p5 - f0p25 * F::EPSILON, x)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(f16_enabled)] + fn zeroes_f16() { + assert_biteq!(round(0.0_f16), 0.0_f16); + assert_biteq!(round(-0.0_f16), -0.0_f16); + } + + #[test] + #[cfg(f16_enabled)] + fn sanity_check_f16() { + assert_eq!(round(-1.0_f16), -1.0); + assert_eq!(round(2.8_f16), 3.0); + assert_eq!(round(-0.5_f16), -1.0); + assert_eq!(round(0.5_f16), 1.0); + assert_eq!(round(-1.5_f16), -2.0); + assert_eq!(round(1.5_f16), 2.0); + } + + #[test] + fn zeroes_f32() { + assert_biteq!(round(0.0_f32), 0.0_f32); + assert_biteq!(round(-0.0_f32), -0.0_f32); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(round(-1.0_f32), -1.0); + assert_eq!(round(2.8_f32), 3.0); + assert_eq!(round(-0.5_f32), -1.0); + assert_eq!(round(0.5_f32), 1.0); + assert_eq!(round(-1.5_f32), -2.0); + assert_eq!(round(1.5_f32), 2.0); + } + + #[test] + fn zeroes_f64() { + assert_biteq!(round(0.0_f64), 0.0_f64); + assert_biteq!(round(-0.0_f64), -0.0_f64); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(round(-1.0_f64), -1.0); + assert_eq!(round(2.8_f64), 3.0); + assert_eq!(round(-0.5_f64), -1.0); + assert_eq!(round(0.5_f64), 1.0); + assert_eq!(round(-1.5_f64), -2.0); + assert_eq!(round(1.5_f64), 2.0); + } + + #[test] + #[cfg(f128_enabled)] + fn zeroes_f128() { + assert_biteq!(round(0.0_f128), 0.0_f128); + assert_biteq!(round(-0.0_f128), -0.0_f128); + } + + #[test] + #[cfg(f128_enabled)] + fn sanity_check_f128() { + assert_eq!(round(-1.0_f128), -1.0); + assert_eq!(round(2.8_f128), 3.0); + assert_eq!(round(-0.5_f128), -1.0); + assert_eq!(round(0.5_f128), 1.0); + assert_eq!(round(-1.5_f128), -2.0); + assert_eq!(round(1.5_f128), 2.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs new file mode 100644 index 00000000000..a45db1b4a02 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs @@ -0,0 +1,121 @@ +use super::super::{CastFrom, CastInto, Float, IntTy, MinInt}; + +/// Scale the exponent. +/// +/// From N3220: +/// +/// > The scalbn and scalbln functions compute `x * b^n`, where `b = FLT_RADIX` if the return type +/// > of the function is a standard floating type, or `b = 10` if the return type of the function +/// > is a decimal floating type. A range error occurs for some finite x, depending on n. +/// > +/// > [...] +/// > +/// > * `scalbn(±0, n)` returns `±0`. +/// > * `scalbn(x, 0)` returns `x`. +/// > * `scalbn(±∞, n)` returns `±∞`. +/// > +/// > If the calculation does not overflow or underflow, the returned value is exact and +/// > independent of the current rounding direction mode. +#[inline] +pub fn scalbn(mut x: F, mut n: i32) -> F +where + u32: CastInto, + F::Int: CastFrom, + F::Int: CastFrom, +{ + let zero = IntTy::::ZERO; + + // Bits including the implicit bit + let sig_total_bits = F::SIG_BITS + 1; + + // Maximum and minimum values when biased + let exp_max = F::EXP_MAX; + let exp_min = F::EXP_MIN; + + // 2 ^ Emax, maximum positive with null significand (0x1p1023 for f64) + let f_exp_max = F::from_parts(false, F::EXP_BIAS << 1, zero); + + // 2 ^ Emin, minimum positive normal with null significand (0x1p-1022 for f64) + let f_exp_min = F::from_parts(false, 1, zero); + + // 2 ^ sig_total_bits, moltiplier to normalize subnormals (0x1p53 for f64) + let f_pow_subnorm = F::from_parts(false, sig_total_bits + F::EXP_BIAS, zero); + + /* + * The goal is to multiply `x` by a scale factor that applies `n`. However, there are cases + * where `2^n` is not representable by `F` but the result should be, e.g. `x = 2^Emin` with + * `n = -EMin + 2` (one out of range of 2^Emax). To get around this, reduce the magnitude of + * the final scale operation by prescaling by the max/min power representable by `F`. + */ + + if n > exp_max { + // Worse case positive `n`: `x` is the minimum subnormal value, the result is `F::MAX`. + // This can be reached by three scaling multiplications (two here and one final). + debug_assert!(-exp_min + F::SIG_BITS as i32 + exp_max <= exp_max * 3); + + x *= f_exp_max; + n -= exp_max; + if n > exp_max { + x *= f_exp_max; + n -= exp_max; + if n > exp_max { + n = exp_max; + } + } + } else if n < exp_min { + // When scaling toward 0, the prescaling is limited to a value that does not allow `x` to + // go subnormal. This avoids double rounding. + if F::BITS > 16 { + // `mul` s.t. `!(x * mul).is_subnormal() ∀ x` + let mul = f_exp_min * f_pow_subnorm; + let add = -exp_min - sig_total_bits as i32; + + // Worse case negative `n`: `x` is the maximum positive value, the result is `F::MIN`. + // This must be reachable by three scaling multiplications (two here and one final). + debug_assert!(-exp_min + F::SIG_BITS as i32 + exp_max <= add * 2 + -exp_min); + + x *= mul; + n += add; + + if n < exp_min { + x *= mul; + n += add; + + if n < exp_min { + n = exp_min; + } + } + } else { + // `f16` is unique compared to other float types in that the difference between the + // minimum exponent and the significand bits (`add = -exp_min - sig_total_bits`) is + // small, only three. The above method depend on decrementing `n` by `add` two times; + // for other float types this works out because `add` is a substantial fraction of + // the exponent range. For `f16`, however, 3 is relatively small compared to the + // exponent range (which is 39), so that requires ~10 prescale rounds rather than two. + // + // Work aroudn this by using a different algorithm that calculates the prescale + // dynamically based on the maximum possible value. This adds more operations per round + // since it needs to construct the scale, but works better in the general case. + let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32); + let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero); + + x *= mul; + n += add; + + if n < exp_min { + let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32); + let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero); + + x *= mul; + n += add; + + if n < exp_min { + n = exp_min; + } + } + } + } + + let scale = F::from_parts(false, (F::EXP_BIAS as i32 + n) as u32, zero); + x * scale +} diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs new file mode 100644 index 00000000000..ec9ff22df20 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -0,0 +1,537 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/sqrt.c. Ported to generic Rust algorithm in 2025, TG. */ + +//! Generic square root algorithm. +//! +//! This routine operates around `m_u2`, a U.2 (fixed point with two integral bits) mantissa +//! within the range [1, 4). A table lookup provides an initial estimate, then goldschmidt +//! iterations at various widths are used to approach the real values. +//! +//! For the iterations, `r` is a U0 number that approaches `1/sqrt(m_u2)`, and `s` is a U2 number +//! that approaches `sqrt(m_u2)`. Recall that m_u2 ∈ [1, 4). +//! +//! With Newton-Raphson iterations, this would be: +//! +//! - `w = r * r w ~ 1 / m` +//! - `u = 3 - m * w u ~ 3 - m * w = 3 - m / m = 2` +//! - `r = r * u / 2 r ~ r` +//! +//! (Note that the righthand column does not show anything analytically meaningful (i.e. r ~ r), +//! since the value of performing one iteration is in reducing the error representable by `~`). +//! +//! Instead of Newton-Raphson iterations, Goldschmidt iterations are used to calculate +//! `s = m * r`: +//! +//! - `s = m * r s ~ m / sqrt(m)` +//! - `u = 3 - s * r u ~ 3 - (m / sqrt(m)) * (1 / sqrt(m)) = 3 - m / m = 2` +//! - `r = r * u / 2 r ~ r` +//! - `s = s * u / 2 s ~ s` +//! +//! The above is precise because it uses the original value `m`. There is also a faster version +//! that performs fewer steps but does not use `m`: +//! +//! - `u = 3 - s * r u ~ 3 - 1` +//! - `r = r * u / 2 r ~ r` +//! - `s = s * u / 2 s ~ s` +//! +//! Rounding errors accumulate faster with the second version, so it is only used for subsequent +//! iterations within the same width integer. The first version is always used for the first +//! iteration at a new width in order to avoid this accumulation. +//! +//! Goldschmidt has the advantage over Newton-Raphson that `sqrt(x)` and `1/sqrt(x)` are +//! computed at the same time, i.e. there is no need to calculate `1/sqrt(x)` and invert it. + +use super::super::support::{FpResult, IntTy, Round, Status, cold_path}; +use super::super::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; + +#[inline] +pub fn sqrt(x: F) -> F +where + F: Float + SqrtHelper, + F::Int: HInt, + F::Int: From, + F::Int: From, + F::Int: CastInto, + F::Int: CastInto, + u32: CastInto, +{ + sqrt_round(x, Round::Nearest).val +} + +#[inline] +pub fn sqrt_round(x: F, _round: Round) -> FpResult +where + F: Float + SqrtHelper, + F::Int: HInt, + F::Int: From, + F::Int: From, + F::Int: CastInto, + F::Int: CastInto, + u32: CastInto, +{ + let zero = IntTy::::ZERO; + let one = IntTy::::ONE; + + let mut ix = x.to_bits(); + + // Top is the exponent and sign, which may or may not be shifted. If the float fits into a + // `u32`, we can get by without paying shifting costs. + let noshift = F::BITS <= u32::BITS; + let (mut top, special_case) = if noshift { + let exp_lsb = one << F::SIG_BITS; + let special_case = ix.wrapping_sub(exp_lsb) >= F::EXP_MASK - exp_lsb; + (Exp::NoShift(()), special_case) + } else { + let top = u32::cast_from(ix >> F::SIG_BITS); + let special_case = top.wrapping_sub(1) >= F::EXP_SAT - 1; + (Exp::Shifted(top), special_case) + }; + + // Handle NaN, zero, and out of domain (<= 0) + if special_case { + cold_path(); + + // +/-0 + if ix << 1 == zero { + return FpResult::ok(x); + } + + // Positive infinity + if ix == F::EXP_MASK { + return FpResult::ok(x); + } + + // NaN or negative + if ix > F::EXP_MASK { + return FpResult::new(F::NAN, Status::INVALID); + } + + // Normalize subnormals by multiplying by 1.0 << SIG_BITS (e.g. 0x1p52 for doubles). + let scaled = x * F::from_parts(false, F::SIG_BITS + F::EXP_BIAS, zero); + ix = scaled.to_bits(); + match top { + Exp::Shifted(ref mut v) => { + *v = scaled.ex(); + *v = (*v).wrapping_sub(F::SIG_BITS); + } + Exp::NoShift(()) => { + ix = ix.wrapping_sub((F::SIG_BITS << F::SIG_BITS).cast()); + } + } + } + + // Reduce arguments such that `x = 4^e * m`: + // + // - m_u2 ∈ [1, 4), a fixed point U2.BITS number + // - 2^e is the exponent part of the result + let (m_u2, exp) = match top { + Exp::Shifted(top) => { + // We now know `x` is positive, so `top` is just its (biased) exponent + let mut e = top; + // Construct a fixed point representation of the mantissa. + let mut m_u2 = (ix | F::IMPLICIT_BIT) << F::EXP_BITS; + let even = (e & 1) != 0; + if even { + m_u2 >>= 1; + } + e = (e.wrapping_add(F::EXP_SAT >> 1)) >> 1; + (m_u2, Exp::Shifted(e)) + } + Exp::NoShift(()) => { + let even = ix & (one << F::SIG_BITS) != zero; + + // Exponent part of the return value + let mut e_noshift = ix >> 1; + // ey &= (F::EXP_MASK << 2) >> 2; // clear the top exponent bit (result = 1.0) + e_noshift += (F::EXP_MASK ^ (F::SIGN_MASK >> 1)) >> 1; + e_noshift &= F::EXP_MASK; + + let m1 = (ix << F::EXP_BITS) | F::SIGN_MASK; + let m0 = (ix << (F::EXP_BITS - 1)) & !F::SIGN_MASK; + let m_u2 = if even { m0 } else { m1 }; + + (m_u2, Exp::NoShift(e_noshift)) + } + }; + + // Extract the top 6 bits of the significand with the lowest bit of the exponent. + let i = usize::cast_from(ix >> (F::SIG_BITS - 6)) & 0b1111111; + + // Start with an initial guess for `r = 1 / sqrt(m)` from the table, and shift `m` as an + // initial value for `s = sqrt(m)`. See the module documentation for details. + let r1_u0: F::ISet1 = F::ISet1::cast_from(RSQRT_TAB[i]) << (F::ISet1::BITS - 16); + let s1_u2: F::ISet1 = ((m_u2) >> (F::BITS - F::ISet1::BITS)).cast(); + + // Perform iterations, if any, at quarter width (used for `f128`). + let (r1_u0, _s1_u2) = goldschmidt::(r1_u0, s1_u2, F::SET1_ROUNDS, false); + + // Widen values and perform iterations at half width (used for `f64` and `f128`). + let r2_u0: F::ISet2 = F::ISet2::from(r1_u0) << (F::ISet2::BITS - F::ISet1::BITS); + let s2_u2: F::ISet2 = ((m_u2) >> (F::BITS - F::ISet2::BITS)).cast(); + let (r2_u0, _s2_u2) = goldschmidt::(r2_u0, s2_u2, F::SET2_ROUNDS, false); + + // Perform final iterations at full width (used for all float types). + let r_u0: F::Int = F::Int::from(r2_u0) << (F::BITS - F::ISet2::BITS); + let s_u2: F::Int = m_u2; + let (_r_u0, s_u2) = goldschmidt::(r_u0, s_u2, F::FINAL_ROUNDS, true); + + // Shift back to mantissa position. + let mut m = s_u2 >> (F::EXP_BITS - 2); + + // The musl source includes the following comment (with literals replaced): + // + // > s < sqrt(m) < s + 0x1.09p-SIG_BITS + // > compute nearest rounded result: the nearest result to SIG_BITS bits is either s or + // > s+0x1p-SIG_BITS, we can decide by comparing (2^SIG_BITS s + 0.5)^2 to 2^(2*SIG_BITS) m. + // + // Expanding this with , with `SIG_BITS = p` and adjusting based on the operations done to + // `d0` and `d1`: + // + // - `2^(2p)m ≟ ((2^p)m + 0.5)^2` + // - `2^(2p)m ≟ 2^(2p)m^2 + (2^p)m + 0.25` + // - `2^(2p)m - m^2 ≟ (2^(2p) - 1)m^2 + (2^p)m + 0.25` + // - `(1 - 2^(2p))m + m^2 ≟ (1 - 2^(2p))m^2 + (1 - 2^p)m + 0.25` (?) + // + // I do not follow how the rounding bit is extracted from this comparison with the below + // operations. In any case, the algorithm is well tested. + + // The value needed to shift `m_u2` by to create `m*2^(2p)`. `2p = 2 * F::SIG_BITS`, + // `F::BITS - 2` accounts for the offset that `m_u2` already has. + let shift = 2 * F::SIG_BITS - (F::BITS - 2); + + // `2^(2p)m - m^2` + let d0 = (m_u2 << shift).wrapping_sub(m.wrapping_mul(m)); + // `m - 2^(2p)m + m^2` + let d1 = m.wrapping_sub(d0); + m += d1 >> (F::BITS - 1); + m &= F::SIG_MASK; + + match exp { + Exp::Shifted(e) => m |= IntTy::::cast_from(e) << F::SIG_BITS, + Exp::NoShift(e) => m |= e, + }; + + let mut y = F::from_bits(m); + + // FIXME(f16): the fenv math does not work for `f16` + if F::BITS > 16 { + // Handle rounding and inexact. `(m + 1)^2 == 2^shift m` is exact; for all other cases, add + // a tiny value to cause fenv effects. + let d2 = d1.wrapping_add(m).wrapping_add(one); + let mut tiny = if d2 == zero { + cold_path(); + zero + } else { + F::IMPLICIT_BIT + }; + + tiny |= (d1 ^ d2) & F::SIGN_MASK; + let t = F::from_bits(tiny); + y = y + t; + } + + FpResult::ok(y) +} + +/// Multiply at the wider integer size, returning the high half. +fn wmulh(a: I, b: I) -> I { + a.widen_mul(b).hi() +} + +/// Perform `count` goldschmidt iterations, returning `(r_u0, s_u?)`. +/// +/// - `r_u0` is the reciprocal `r ~ 1 / sqrt(m)`, as U0. +/// - `s_u2` is the square root, `s ~ sqrt(m)`, as U2. +/// - `count` is the number of iterations to perform. +/// - `final_set` should be true if this is the last round (same-sized integer). If so, the +/// returned `s` will be U3, for later shifting. Otherwise, the returned `s` is U2. +/// +/// Note that performance relies on the optimizer being able to unroll these loops (reasonably +/// trivial, `count` is a constant when called). +#[inline] +fn goldschmidt(mut r_u0: I, mut s_u2: I, count: u32, final_set: bool) -> (I, I) +where + F: SqrtHelper, + I: HInt + From, +{ + let three_u2 = I::from(0b11u8) << (I::BITS - 2); + let mut u_u0 = r_u0; + + for i in 0..count { + // First iteration: `s = m*r` (`u_u0 = r_u0` set above) + // Subsequent iterations: `s=s*u/2` + s_u2 = wmulh(s_u2, u_u0); + + // Perform `s /= 2` if: + // + // 1. This is not the first iteration (the first iteration is `s = m*r`)... + // 2. ... and this is not the last set of iterations + // 3. ... or, if this is the last set, it is not the last iteration + // + // This step is not performed for the final iteration because the shift is combined with + // a later shift (moving `s` into the mantissa). + if i > 0 && (!final_set || i + 1 < count) { + s_u2 <<= 1; + } + + // u = 3 - s*r + let d_u2 = wmulh(s_u2, r_u0); + u_u0 = three_u2.wrapping_sub(d_u2); + + // r = r*u/2 + r_u0 = wmulh(r_u0, u_u0) << 1; + } + + (r_u0, s_u2) +} + +/// Representation of whether we shift the exponent into a `u32`, or modify it in place to save +/// the shift operations. +enum Exp { + /// The exponent has been shifted to a `u32` and is LSB-aligned. + Shifted(u32), + /// The exponent is in its natural position in integer repr. + NoShift(T), +} + +/// Size-specific constants related to the square root routine. +pub trait SqrtHelper: Float { + /// Integer for the first set of rounds. If unused, set to the same type as the next set. + type ISet1: HInt + Into + CastFrom + From; + /// Integer for the second set of rounds. If unused, set to the same type as the next set. + type ISet2: HInt + From + From; + + /// Number of rounds at `ISet1`. + const SET1_ROUNDS: u32 = 0; + /// Number of rounds at `ISet2`. + const SET2_ROUNDS: u32 = 0; + /// Number of rounds at `Self::Int`. + const FINAL_ROUNDS: u32; +} + +#[cfg(f16_enabled)] +impl SqrtHelper for f16 { + type ISet1 = u16; // unused + type ISet2 = u16; // unused + + const FINAL_ROUNDS: u32 = 2; +} + +impl SqrtHelper for f32 { + type ISet1 = u32; // unused + type ISet2 = u32; // unused + + const FINAL_ROUNDS: u32 = 3; +} + +impl SqrtHelper for f64 { + type ISet1 = u32; // unused + type ISet2 = u32; + + const SET2_ROUNDS: u32 = 2; + const FINAL_ROUNDS: u32 = 2; +} + +#[cfg(f128_enabled)] +impl SqrtHelper for f128 { + type ISet1 = u32; + type ISet2 = u64; + + const SET1_ROUNDS: u32 = 1; + const SET2_ROUNDS: u32 = 2; + const FINAL_ROUNDS: u32 = 2; +} + +/// A U0.16 representation of `1/sqrt(x)`. +/// +/// The index is a 7-bit number consisting of a single exponent bit and 6 bits of significand. +#[rustfmt::skip] +static RSQRT_TAB: [u16; 128] = [ + 0xb451, 0xb2f0, 0xb196, 0xb044, 0xaef9, 0xadb6, 0xac79, 0xab43, + 0xaa14, 0xa8eb, 0xa7c8, 0xa6aa, 0xa592, 0xa480, 0xa373, 0xa26b, + 0xa168, 0xa06a, 0x9f70, 0x9e7b, 0x9d8a, 0x9c9d, 0x9bb5, 0x9ad1, + 0x99f0, 0x9913, 0x983a, 0x9765, 0x9693, 0x95c4, 0x94f8, 0x9430, + 0x936b, 0x92a9, 0x91ea, 0x912e, 0x9075, 0x8fbe, 0x8f0a, 0x8e59, + 0x8daa, 0x8cfe, 0x8c54, 0x8bac, 0x8b07, 0x8a64, 0x89c4, 0x8925, + 0x8889, 0x87ee, 0x8756, 0x86c0, 0x862b, 0x8599, 0x8508, 0x8479, + 0x83ec, 0x8361, 0x82d8, 0x8250, 0x81c9, 0x8145, 0x80c2, 0x8040, + 0xff02, 0xfd0e, 0xfb25, 0xf947, 0xf773, 0xf5aa, 0xf3ea, 0xf234, + 0xf087, 0xeee3, 0xed47, 0xebb3, 0xea27, 0xe8a3, 0xe727, 0xe5b2, + 0xe443, 0xe2dc, 0xe17a, 0xe020, 0xdecb, 0xdd7d, 0xdc34, 0xdaf1, + 0xd9b3, 0xd87b, 0xd748, 0xd61a, 0xd4f1, 0xd3cd, 0xd2ad, 0xd192, + 0xd07b, 0xcf69, 0xce5b, 0xcd51, 0xcc4a, 0xcb48, 0xca4a, 0xc94f, + 0xc858, 0xc764, 0xc674, 0xc587, 0xc49d, 0xc3b7, 0xc2d4, 0xc1f4, + 0xc116, 0xc03c, 0xbf65, 0xbe90, 0xbdbe, 0xbcef, 0xbc23, 0xbb59, + 0xba91, 0xb9cc, 0xb90a, 0xb84a, 0xb78c, 0xb6d0, 0xb617, 0xb560, +]; + +#[cfg(test)] +mod tests { + use super::*; + + /// Test behavior specified in IEEE 754 `squareRoot`. + fn spec_test() + where + F: Float + SqrtHelper, + F::Int: HInt, + F::Int: From, + F::Int: From, + F::Int: CastInto, + F::Int: CastInto, + u32: CastInto, + { + // Values that should return a NaN and raise invalid + let nan = [F::NEG_INFINITY, F::NEG_ONE, F::NAN, F::MIN]; + + // Values that return unaltered + let roundtrip = [F::ZERO, F::NEG_ZERO, F::INFINITY]; + + for x in nan { + let FpResult { val, status } = sqrt_round(x, Round::Nearest); + assert!(val.is_nan()); + assert!(status == Status::INVALID); + } + + for x in roundtrip { + let FpResult { val, status } = sqrt_round(x, Round::Nearest); + assert_biteq!(val, x); + assert!(status == Status::OK); + } + } + + #[test] + #[cfg(f16_enabled)] + fn sanity_check_f16() { + assert_biteq!(sqrt(100.0f16), 10.0); + assert_biteq!(sqrt(4.0f16), 2.0); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + #[cfg(f16_enabled)] + #[allow(clippy::approx_constant)] + fn conformance_tests_f16() { + let cases = [ + (f16::PI, 0x3f17_u16), + // 10_000.0, using a hex literal for MSRV hack (Rust < 1.67 checks literal widths as + // part of the AST, so the `cfg` is irrelevant here). + (f16::from_bits(0x70e2), 0x5640_u16), + (f16::from_bits(0x0000000f), 0x13bf_u16), + (f16::INFINITY, f16::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrt(input), + f16::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } + + #[test] + fn sanity_check_f32() { + assert_biteq!(sqrt(100.0f32), 10.0); + assert_biteq!(sqrt(4.0f32), 2.0); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + #[allow(clippy::approx_constant)] + fn conformance_tests_f32() { + let cases = [ + (f32::PI, 0x3fe2dfc5_u32), + (10000.0f32, 0x42c80000_u32), + (f32::from_bits(0x0000000f), 0x1b2f456f_u32), + (f32::INFINITY, f32::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrt(input), + f32::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } + + #[test] + fn sanity_check_f64() { + assert_biteq!(sqrt(100.0f64), 10.0); + assert_biteq!(sqrt(4.0f64), 2.0); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[allow(clippy::approx_constant)] + fn conformance_tests_f64() { + let cases = [ + (f64::PI, 0x3ffc5bf891b4ef6a_u64), + (10000.0, 0x4059000000000000_u64), + (f64::from_bits(0x0000000f), 0x1e7efbdeb14f4eda_u64), + (f64::INFINITY, f64::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrt(input), + f64::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } + + #[test] + #[cfg(f128_enabled)] + fn sanity_check_f128() { + assert_biteq!(sqrt(100.0f128), 10.0); + assert_biteq!(sqrt(4.0f128), 2.0); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + #[allow(clippy::approx_constant)] + fn conformance_tests_f128() { + let cases = [ + (f128::PI, 0x3fffc5bf891b4ef6aa79c3b0520d5db9_u128), + // 10_000.0, see `f16` for reasoning. + ( + f128::from_bits(0x400c3880000000000000000000000000), + 0x40059000000000000000000000000000_u128, + ), + (f128::from_bits(0x0000000f), 0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128), + (f128::INFINITY, f128::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrt(input), + f128::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs new file mode 100644 index 00000000000..25414ecf426 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: MIT + * origin: musl src/math/trunc.c */ + +use super::super::support::{FpResult, Status}; +use super::super::{Float, Int, IntTy, MinInt}; + +#[inline] +pub fn trunc(x: F) -> F { + trunc_status(x).val +} + +#[inline] +pub fn trunc_status(x: F) -> FpResult { + let mut xi: F::Int = x.to_bits(); + let e: i32 = x.exp_unbiased(); + + // C1: The represented value has no fractional part, so no truncation is needed + if e >= F::SIG_BITS as i32 { + return FpResult::ok(x); + } + + let mask = if e < 0 { + // C2: If the exponent is negative, the result will be zero so we mask out everything + // except the sign. + F::SIGN_MASK + } else { + // C3: Otherwise, we mask out the last `e` bits of the significand. + !(F::SIG_MASK >> e.unsigned()) + }; + + // C4: If the to-be-masked-out portion is already zero, we have an exact result + if (xi & !mask) == IntTy::::ZERO { + return FpResult::ok(x); + } + + // C5: Otherwise the result is inexact and we will truncate. Raise `FE_INEXACT`, mask the + // result, and return. + + let status = if xi & F::SIG_MASK == F::Int::ZERO { Status::OK } else { Status::INEXACT }; + xi &= mask; + FpResult::new(F::from_bits(xi), status) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::Hexf; + + fn spec_test(cases: &[(F, F, Status)]) { + let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + + for x in roundtrip { + let FpResult { val, status } = trunc_status(x); + assert_biteq!(val, x, "{}", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = trunc_status(x); + assert_biteq!(val, res, "{}", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); + } + } + + /* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */ + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + let cases = []; + spec_test::(&cases); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(trunc(0.5f32), 0.0); + assert_eq!(trunc(1.1f32), 1.0); + assert_eq!(trunc(2.9f32), 2.0); + } + + #[test] + fn spec_tests_f32() { + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + + assert_biteq!(trunc(1.1f32), 1.0); + assert_biteq!(trunc(1.1f64), 1.0); + + // C1 + assert_biteq!(trunc(hf32!("0x1p23")), hf32!("0x1p23")); + assert_biteq!(trunc(hf64!("0x1p52")), hf64!("0x1p52")); + assert_biteq!(trunc(hf32!("-0x1p23")), hf32!("-0x1p23")); + assert_biteq!(trunc(hf64!("-0x1p52")), hf64!("-0x1p52")); + + // C2 + assert_biteq!(trunc(hf32!("0x1p-1")), 0.0); + assert_biteq!(trunc(hf64!("0x1p-1")), 0.0); + assert_biteq!(trunc(hf32!("-0x1p-1")), -0.0); + assert_biteq!(trunc(hf64!("-0x1p-1")), -0.0); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(trunc(1.1f64), 1.0); + assert_eq!(trunc(2.9f64), 2.0); + } + + #[test] + fn spec_tests_f64() { + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + let cases = []; + spec_test::(&cases); + } +} diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs new file mode 100644 index 00000000000..da458ea1d05 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -0,0 +1,74 @@ +use core::f64; + +use super::sqrt; + +const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 + +fn sq(x: f64) -> (f64, f64) { + let xh: f64; + let xl: f64; + let xc: f64; + + xc = x * SPLIT; + xh = x - xc + xc; + xl = x - xh; + let hi = x * x; + let lo = xh * xh - hi + 2. * xh * xl + xl * xl; + (hi, lo) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn hypot(mut x: f64, mut y: f64) -> f64 { + let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700 + let x1p_700 = f64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700 + + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let uti; + let ex: i64; + let ey: i64; + let mut z: f64; + + /* arrange |x| >= |y| */ + uxi &= -1i64 as u64 >> 1; + uyi &= -1i64 as u64 >> 1; + if uxi < uyi { + uti = uxi; + uxi = uyi; + uyi = uti; + } + + /* special cases */ + ex = (uxi >> 52) as i64; + ey = (uyi >> 52) as i64; + x = f64::from_bits(uxi); + y = f64::from_bits(uyi); + /* note: hypot(inf,nan) == inf */ + if ey == 0x7ff { + return y; + } + if ex == 0x7ff || uyi == 0 { + return x; + } + /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ + /* 64 difference is enough for ld80 double_t */ + if ex - ey > 64 { + return x + y; + } + + /* precise sqrt argument in nearest rounding mode without overflow */ + /* xh*xh must not overflow and xl*xl must not underflow in sq */ + z = 1.; + if ex > 0x3ff + 510 { + z = x1p700; + x *= x1p_700; + y *= x1p_700; + } else if ey < 0x3ff - 450 { + z = x1p_700; + x *= x1p700; + y *= x1p700; + } + let (hx, lx) = sq(x); + let (hy, ly) = sq(y); + z * sqrt(ly + lx + hy + hx) +} diff --git a/library/compiler-builtins/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/src/math/hypotf.rs new file mode 100644 index 00000000000..576eebb3343 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/hypotf.rs @@ -0,0 +1,43 @@ +use core::f32; + +use super::sqrtf; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn hypotf(mut x: f32, mut y: f32) -> f32 { + let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90 + let x1p_90 = f32::from_bits(0x12800000); // 0x1p-90f === 2 ^ -90 + + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let uti; + let mut z: f32; + + uxi &= -1i32 as u32 >> 1; + uyi &= -1i32 as u32 >> 1; + if uxi < uyi { + uti = uxi; + uxi = uyi; + uyi = uti; + } + + x = f32::from_bits(uxi); + y = f32::from_bits(uyi); + if uyi == 0xff << 23 { + return y; + } + if uxi >= 0xff << 23 || uyi == 0 || uxi - uyi >= 25 << 23 { + return x + y; + } + + z = 1.; + if uxi >= (0x7f + 60) << 23 { + z = x1p90; + x *= x1p_90; + y *= x1p_90; + } else if uyi < (0x7f - 60) << 23 { + z = x1p_90; + x *= x1p90; + y *= x1p90; + } + z * sqrtf((x as f64 * x as f64 + y as f64 * y as f64) as f32) +} diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs new file mode 100644 index 00000000000..ccc4914be2b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -0,0 +1,28 @@ +const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; +const FP_ILOGB0: i32 = FP_ILOGBNAN; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ilogb(x: f64) -> i32 { + let mut i: u64 = x.to_bits(); + let e = ((i >> 52) & 0x7ff) as i32; + + if e == 0 { + i <<= 12; + if i == 0 { + force_eval!(0.0 / 0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -0x3ff; + while (i >> 63) == 0 { + e -= 1; + i <<= 1; + } + e + } else if e == 0x7ff { + force_eval!(0.0 / 0.0); + if (i << 12) != 0 { FP_ILOGBNAN } else { i32::MAX } + } else { + e - 0x3ff + } +} diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs new file mode 100644 index 00000000000..3585d6d36f1 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ilogbf.rs @@ -0,0 +1,28 @@ +const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; +const FP_ILOGB0: i32 = FP_ILOGBNAN; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ilogbf(x: f32) -> i32 { + let mut i = x.to_bits(); + let e = ((i >> 23) & 0xff) as i32; + + if e == 0 { + i <<= 9; + if i == 0 { + force_eval!(0.0 / 0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -0x7f; + while (i >> 31) == 0 { + e -= 1; + i <<= 1; + } + e + } else if e == 0xff { + force_eval!(0.0 / 0.0); + if (i << 9) != 0 { FP_ILOGBNAN } else { i32::MAX } + } else { + e - 0x7f + } +} diff --git a/library/compiler-builtins/libm/src/math/j0.rs b/library/compiler-builtins/libm/src/math/j0.rs new file mode 100644 index 00000000000..99d656f0d08 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/j0.rs @@ -0,0 +1,426 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j0(x), y0(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j0(x): + * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... + * 2. Reduce x to |x| since j0(x)=j0(-x), and + * for x in (0,2) + * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; + * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) + * for x in (2,inf) + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * as follow: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (cos(x) + sin(x)) + * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j0(nan)= nan + * j0(0) = 1 + * j0(inf) = 0 + * + * Method -- y0(x): + * 1. For x<2. + * Since + * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) + * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. + * We use the following function to approximate y0, + * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 + * where + * U(z) = u00 + u01*z + ... + u06*z^6 + * V(z) = 1 + v01*z + ... + v04*z^4 + * with absolute approximation error bounded by 2**-72. + * Note: For tiny x, U/V = u0 and j0(x)~1, hence + * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) + * 2. For x>=2. + * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * by the method mentioned above. + * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. + */ + +use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +/* common method when |x|>=2 */ +fn common(ix: u32, x: f64, y0: bool) -> f64 { + let s: f64; + let mut c: f64; + let mut ss: f64; + let mut cc: f64; + let z: f64; + + /* + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) + * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) + * + * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) + * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + c = cos(x); + if y0 { + c = -c; + } + cc = s + c; + /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ + if ix < 0x7fe00000 { + ss = s - c; + z = -cos(2.0 * x); + if s * c < 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x48000000 { + if y0 { + ss = -ss; + } + cc = pzero(x) * cc - qzero(x) * ss; + } + } + return INVSQRTPI * cc / sqrt(x); +} + +/* R0/S0 on [0, 2.00] */ +const R02: f64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ +const R03: f64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ +const R04: f64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ +const R05: f64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */ +const S01: f64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ +const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ +const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ +const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ + +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn j0(mut x: f64) -> f64 { + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + + /* j0(+-inf)=0, j0(nan)=nan */ + if ix >= 0x7ff00000 { + return 1.0 / (x * x); + } + x = fabs(x); + + if ix >= 0x40000000 { + /* |x| >= 2 */ + /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ + return common(ix, x, false); + } + + /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ + if ix >= 0x3f200000 { + /* |x| >= 2**-13 */ + /* up to 4ulp error close to 2 */ + z = x * x; + r = z * (R02 + z * (R03 + z * (R04 + z * R05))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); + return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); + } + + /* 1 - x*x/4 */ + /* prevent underflow */ + /* inexact should be raised when x!=0, this is not done correctly */ + if ix >= 0x38000000 { + /* |x| >= 2**-127 */ + x = 0.25 * x * x; + } + return 1.0 - x; +} + +const U00: f64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ +const U01: f64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ +const U02: f64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ +const U03: f64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */ +const U04: f64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */ +const U05: f64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */ +const U06: f64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */ +const V01: f64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ +const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ +const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ +const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ + +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn y0(x: f64) -> f64 { + let z: f64; + let u: f64; + let v: f64; + let ix: u32; + let lx: u32; + + ix = get_high_word(x); + lx = get_low_word(x); + + /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ + if ((ix << 1) | lx) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7ff00000 { + return 1.0 / x; + } + + if ix >= 0x40000000 { + /* x >= 2 */ + /* large ulp errors near zeros: 3.958, 7.086,.. */ + return common(ix, x, true); + } + + /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ + if ix >= 0x3e400000 { + /* x >= 2**-27 */ + /* large ulp error near the first zero, x ~= 0.89 */ + z = x * x; + u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); + v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); + return u / v + TPI * (j0(x) * log(x)); + } + return U00 + TPI * log(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +const PR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ + -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ + -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ + -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ + -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ +]; +const PS8: [f64; 5] = [ + 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ + 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ + 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ + 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ + 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ +]; + +const PR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ + -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ + -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ + -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ + -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ + -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ +]; +const PS5: [f64; 5] = [ + 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ + 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ + 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ + 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ + 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ +]; + +const PR3: [f64; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ + -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ + -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ + -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ + -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ + -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ +]; +const PS3: [f64; 5] = [ + 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ + 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ + 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ + 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ + 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ +]; + +const PR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ + -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ + -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ + -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ + -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ + -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ +]; +const PS2: [f64; 5] = [ + 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ + 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ + 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ + 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ + 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ +]; + +fn pzero(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 5]; + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x40122E8B { + p = &PR5; + q = &PS5; + } else if ix >= 0x4006DB6D { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +const QR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ + 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ + 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ + 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ + 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ +]; +const QS8: [f64; 6] = [ + 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ + 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ + 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ + 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ + 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ + -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ +]; + +const QR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ + 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ + 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ + 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ + 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ + 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ +]; +const QS5: [f64; 6] = [ + 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ + 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ + 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ + 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ + 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ + -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ +]; + +const QR3: [f64; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ + 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ + 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ + 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ + 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ + 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ +]; +const QS3: [f64; 6] = [ + 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ + 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ + 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ + 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ + 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ + -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ +]; + +const QR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ + 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ + 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ + 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ + 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ + 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ +]; +const QS2: [f64; 6] = [ + 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ + 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ + 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ + 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ + 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ + -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ +]; + +fn qzero(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 6]; + let s: f64; + let r: f64; + let z: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x40122E8B { + p = &QR5; + q = &QS5; + } else if ix >= 0x4006DB6D { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (-0.125 + r / s) / x; +} diff --git a/library/compiler-builtins/libm/src/math/j0f.rs b/library/compiler-builtins/libm/src/math/j0f.rs new file mode 100644 index 00000000000..25e5b325c8c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/j0f.rs @@ -0,0 +1,363 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{cosf, fabsf, logf, sinf, sqrtf}; + +const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ + +fn common(ix: u32, x: f32, y0: bool) -> f32 { + let z: f32; + let s: f32; + let mut c: f32; + let mut ss: f32; + let mut cc: f32; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + s = sinf(x); + c = cosf(x); + if y0 { + c = -c; + } + cc = s + c; + if ix < 0x7f000000 { + ss = s - c; + z = -cosf(2.0 * x); + if s * c < 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x58800000 { + if y0 { + ss = -ss; + } + cc = pzerof(x) * cc - qzerof(x) * ss; + } + } + return INVSQRTPI * cc / sqrtf(x); +} + +/* R0/S0 on [0, 2.00] */ +const R02: f32 = 1.5625000000e-02; /* 0x3c800000 */ +const R03: f32 = -1.8997929874e-04; /* 0xb947352e */ +const R04: f32 = 1.8295404516e-06; /* 0x35f58e88 */ +const R05: f32 = -4.6183270541e-09; /* 0xb19eaf3c */ +const S01: f32 = 1.5619102865e-02; /* 0x3c7fe744 */ +const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ +const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ +const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ + +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn j0f(mut x: f32) -> f32 { + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + return 1.0 / (x * x); + } + x = fabsf(x); + + if ix >= 0x40000000 { + /* |x| >= 2 */ + /* large ulp error near zeros */ + return common(ix, x, false); + } + if ix >= 0x3a000000 { + /* |x| >= 2**-11 */ + /* up to 4ulp error near 2 */ + z = x * x; + r = z * (R02 + z * (R03 + z * (R04 + z * R05))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); + return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); + } + if ix >= 0x21800000 { + /* |x| >= 2**-60 */ + x = 0.25 * x * x; + } + return 1.0 - x; +} + +const U00: f32 = -7.3804296553e-02; /* 0xbd9726b5 */ +const U01: f32 = 1.7666645348e-01; /* 0x3e34e80d */ +const U02: f32 = -1.3818567619e-02; /* 0xbc626746 */ +const U03: f32 = 3.4745343146e-04; /* 0x39b62a69 */ +const U04: f32 = -3.8140706238e-06; /* 0xb67ff53c */ +const U05: f32 = 1.9559013964e-08; /* 0x32a802ba */ +const U06: f32 = -3.9820518410e-11; /* 0xae2f21eb */ +const V01: f32 = 1.2730483897e-02; /* 0x3c509385 */ +const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ +const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ +const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ + +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn y0f(x: f32) -> f32 { + let z: f32; + let u: f32; + let v: f32; + let ix: u32; + + ix = x.to_bits(); + if (ix & 0x7fffffff) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7f800000 { + return 1.0 / x; + } + if ix >= 0x40000000 { + /* |x| >= 2.0 */ + /* large ulp error near zeros */ + return common(ix, x, true); + } + if ix >= 0x39000000 { + /* x >= 2**-13 */ + /* large ulp error at x ~= 0.89 */ + z = x * x; + u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); + v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); + return u / v + TPI * (j0f(x) * logf(x)); + } + return U00 + TPI * logf(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +const PR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -7.0312500000e-02, /* 0xbd900000 */ + -8.0816707611e+00, /* 0xc1014e86 */ + -2.5706311035e+02, /* 0xc3808814 */ + -2.4852163086e+03, /* 0xc51b5376 */ + -5.2530439453e+03, /* 0xc5a4285a */ +]; +const PS8: [f32; 5] = [ + 1.1653436279e+02, /* 0x42e91198 */ + 3.8337448730e+03, /* 0x456f9beb */ + 4.0597855469e+04, /* 0x471e95db */ + 1.1675296875e+05, /* 0x47e4087c */ + 4.7627726562e+04, /* 0x473a0bba */ +]; +const PR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.1412546255e-11, /* 0xad48c58a */ + -7.0312492549e-02, /* 0xbd8fffff */ + -4.1596107483e+00, /* 0xc0851b88 */ + -6.7674766541e+01, /* 0xc287597b */ + -3.3123129272e+02, /* 0xc3a59d9b */ + -3.4643338013e+02, /* 0xc3ad3779 */ +]; +const PS5: [f32; 5] = [ + 6.0753936768e+01, /* 0x42730408 */ + 1.0512523193e+03, /* 0x44836813 */ + 5.9789707031e+03, /* 0x45bad7c4 */ + 9.6254453125e+03, /* 0x461665c8 */ + 2.4060581055e+03, /* 0x451660ee */ +]; + +const PR3: [f32; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.5470459075e-09, /* 0xb12f081b */ + -7.0311963558e-02, /* 0xbd8fffb8 */ + -2.4090321064e+00, /* 0xc01a2d95 */ + -2.1965976715e+01, /* 0xc1afba52 */ + -5.8079170227e+01, /* 0xc2685112 */ + -3.1447946548e+01, /* 0xc1fb9565 */ +]; +const PS3: [f32; 5] = [ + 3.5856033325e+01, /* 0x420f6c94 */ + 3.6151397705e+02, /* 0x43b4c1ca */ + 1.1936077881e+03, /* 0x44953373 */ + 1.1279968262e+03, /* 0x448cffe6 */ + 1.7358093262e+02, /* 0x432d94b8 */ +]; + +const PR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.8753431271e-08, /* 0xb3be98b7 */ + -7.0303097367e-02, /* 0xbd8ffb12 */ + -1.4507384300e+00, /* 0xbfb9b1cc */ + -7.6356959343e+00, /* 0xc0f4579f */ + -1.1193166733e+01, /* 0xc1331736 */ + -3.2336456776e+00, /* 0xc04ef40d */ +]; +const PS2: [f32; 5] = [ + 2.2220300674e+01, /* 0x41b1c32d */ + 1.3620678711e+02, /* 0x430834f0 */ + 2.7047027588e+02, /* 0x43873c32 */ + 1.5387539673e+02, /* 0x4319e01a */ + 1.4657617569e+01, /* 0x416a859a */ +]; + +fn pzerof(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 5]; + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x409173eb { + p = &PR5; + q = &PS5; + } else if ix >= 0x4036d917 { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +const QR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 7.3242187500e-02, /* 0x3d960000 */ + 1.1768206596e+01, /* 0x413c4a93 */ + 5.5767340088e+02, /* 0x440b6b19 */ + 8.8591972656e+03, /* 0x460a6cca */ + 3.7014625000e+04, /* 0x471096a0 */ +]; +const QS8: [f32; 6] = [ + 1.6377603149e+02, /* 0x4323c6aa */ + 8.0983447266e+03, /* 0x45fd12c2 */ + 1.4253829688e+05, /* 0x480b3293 */ + 8.0330925000e+05, /* 0x49441ed4 */ + 8.4050156250e+05, /* 0x494d3359 */ + -3.4389928125e+05, /* 0xc8a7eb69 */ +]; + +const QR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.8408595828e-11, /* 0x2da1ec79 */ + 7.3242180049e-02, /* 0x3d95ffff */ + 5.8356351852e+00, /* 0x40babd86 */ + 1.3511157227e+02, /* 0x43071c90 */ + 1.0272437744e+03, /* 0x448067cd */ + 1.9899779053e+03, /* 0x44f8bf4b */ +]; +const QS5: [f32; 6] = [ + 8.2776611328e+01, /* 0x42a58da0 */ + 2.0778142090e+03, /* 0x4501dd07 */ + 1.8847289062e+04, /* 0x46933e94 */ + 5.6751113281e+04, /* 0x475daf1d */ + 3.5976753906e+04, /* 0x470c88c1 */ + -5.3543427734e+03, /* 0xc5a752be */ +]; + +const QR3: [f32; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.3774099900e-09, /* 0x3196681b */ + 7.3241114616e-02, /* 0x3d95ff70 */ + 3.3442313671e+00, /* 0x405607e3 */ + 4.2621845245e+01, /* 0x422a7cc5 */ + 1.7080809021e+02, /* 0x432acedf */ + 1.6673394775e+02, /* 0x4326bbe4 */ +]; +const QS3: [f32; 6] = [ + 4.8758872986e+01, /* 0x42430916 */ + 7.0968920898e+02, /* 0x44316c1c */ + 3.7041481934e+03, /* 0x4567825f */ + 6.4604252930e+03, /* 0x45c9e367 */ + 2.5163337402e+03, /* 0x451d4557 */ + -1.4924745178e+02, /* 0xc3153f59 */ +]; + +const QR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.5044444979e-07, /* 0x342189db */ + 7.3223426938e-02, /* 0x3d95f62a */ + 1.9981917143e+00, /* 0x3fffc4bf */ + 1.4495602608e+01, /* 0x4167edfd */ + 3.1666231155e+01, /* 0x41fd5471 */ + 1.6252708435e+01, /* 0x4182058c */ +]; +const QS2: [f32; 6] = [ + 3.0365585327e+01, /* 0x41f2ecb8 */ + 2.6934811401e+02, /* 0x4386ac8f */ + 8.4478375244e+02, /* 0x44533229 */ + 8.8293585205e+02, /* 0x445cbbe5 */ + 2.1266638184e+02, /* 0x4354aa98 */ + -5.3109550476e+00, /* 0xc0a9f358 */ +]; + +fn qzerof(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 6]; + let s: f32; + let r: f32; + let z: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x409173eb { + p = &QR5; + q = &QS5; + } else if ix >= 0x4036d917 { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (-0.125 + r / s) / x; +} diff --git a/library/compiler-builtins/libm/src/math/j1.rs b/library/compiler-builtins/libm/src/math/j1.rs new file mode 100644 index 00000000000..9b604d9e46e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/j1.rs @@ -0,0 +1,418 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j1(x), y1(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j1(x): + * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... + * 2. Reduce x to |x| since j1(x)=-j1(-x), and + * for x in (0,2) + * j1(x) = x/2 + x*z*R0/S0, where z = x*x; + * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) + * for x in (2,inf) + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * as follow: + * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (sin(x) + cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j1(nan)= nan + * j1(0) = 0 + * j1(inf) = 0 + * + * Method -- y1(x): + * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN + * 2. For x<2. + * Since + * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) + * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. + * We use the following function to approximate y1, + * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 + * where for x in [0,2] (abs err less than 2**-65.89) + * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 + * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 + * Note: For tiny x, 1/x dominate y1 and hence + * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) + * 3. For x>=2. + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * by method mentioned above. + */ + +use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; + +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +fn common(ix: u32, x: f64, y1: bool, sign: bool) -> f64 { + let z: f64; + let mut s: f64; + let c: f64; + let mut ss: f64; + let mut cc: f64; + + /* + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) + * + * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) + * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + if y1 { + s = -s; + } + c = cos(x); + cc = s - c; + if ix < 0x7fe00000 { + /* avoid overflow in 2*x */ + ss = -s - c; + z = cos(2.0 * x); + if s * c > 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x48000000 { + if y1 { + ss = -ss; + } + cc = pone(x) * cc - qone(x) * ss; + } + } + if sign { + cc = -cc; + } + return INVSQRTPI * cc / sqrt(x); +} + +/* R0/S0 on [0,2] */ +const R00: f64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ +const R01: f64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ +const R02: f64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ +const R03: f64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ +const S01: f64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ +const S02: f64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ +const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ +const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ +const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ + +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn j1(x: f64) -> f64 { + let mut z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + let sign: bool; + + ix = get_high_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + return 1.0 / (x * x); + } + if ix >= 0x40000000 { + /* |x| >= 2 */ + return common(ix, fabs(x), false, sign); + } + if ix >= 0x38000000 { + /* |x| >= 2**-127 */ + z = x * x; + r = z * (R00 + z * (R01 + z * (R02 + z * R03))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); + z = r / s; + } else { + /* avoid underflow, raise inexact if x!=0 */ + z = x; + } + return (0.5 + z) * x; +} + +const U0: [f64; 5] = [ + -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ + 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ + 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ +]; +const V0: [f64; 5] = [ + 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ + 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ +]; + +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn y1(x: f64) -> f64 { + let z: f64; + let u: f64; + let v: f64; + let ix: u32; + let lx: u32; + + ix = get_high_word(x); + lx = get_low_word(x); + + /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ + if (ix << 1) | lx == 0 { + return -1.0 / 0.0; + } + if ix >> 31 != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7ff00000 { + return 1.0 / x; + } + + if ix >= 0x40000000 { + /* x >= 2 */ + return common(ix, x, true, false); + } + if ix < 0x3c900000 { + /* x < 2**-54 */ + return -TPI / x; + } + z = x * x; + u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + return x * (u / v) + TPI * (j1(x) * log(x) - 1.0 / x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +const PR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ + 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ + 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ + 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ +]; +const PS8: [f64; 5] = [ + 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ + 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ + 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ + 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ + 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ +]; + +const PR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ + 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ + 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ + 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ +]; +const PS5: [f64; 5] = [ + 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ + 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ + 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ + 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ +]; + +const PR3: [f64; 6] = [ + 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ + 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ + 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ + 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ +]; +const PS3: [f64; 5] = [ + 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ + 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ + 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ + 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ + 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ +]; + +const PR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ + 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ + 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ + 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ +]; +const PS2: [f64; 5] = [ + 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ + 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ + 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ + 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ +]; + +fn pone(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 5]; + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x40122E8B { + p = &PR5; + q = &PS5; + } else if ix >= 0x4006DB6D { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +const QR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ + -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ + -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ + -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ + -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ +]; +const QS8: [f64; 6] = [ + 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ + 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ + 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ + 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ + 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ + -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ +]; + +const QR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ + -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ + -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ + -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ + -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ + -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ +]; +const QS5: [f64; 6] = [ + 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ + 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ + 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ + 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ + 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ + -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ +]; + +const QR3: [f64; 6] = [ + -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ + -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ + -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ + -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ + -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ + -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ +]; +const QS3: [f64; 6] = [ + 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ + 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ + 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ + 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ + 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ + -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ +]; + +const QR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ + -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ + -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ + -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ + -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ + -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ +]; +const QS2: [f64; 6] = [ + 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ + 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ + 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ + 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ + 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ + -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ +]; + +fn qone(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 6]; + let s: f64; + let r: f64; + let z: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x40122E8B { + p = &QR5; + q = &QS5; + } else if ix >= 0x4006DB6D { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (0.375 + r / s) / x; +} diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs new file mode 100644 index 00000000000..a47472401ee --- /dev/null +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -0,0 +1,384 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{cosf, fabsf, logf, sinf, sqrtf}; + +const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ + +fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 { + let z: f64; + let mut s: f64; + let c: f64; + let mut ss: f64; + let mut cc: f64; + + s = sinf(x) as f64; + if y1 { + s = -s; + } + c = cosf(x) as f64; + cc = s - c; + if ix < 0x7f000000 { + ss = -s - c; + z = cosf(2.0 * x) as f64; + if s * c > 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x58800000 { + if y1 { + ss = -ss; + } + cc = (ponef(x) as f64) * cc - (qonef(x) as f64) * ss; + } + } + if sign { + cc = -cc; + } + return (((INVSQRTPI as f64) * cc) / (sqrtf(x) as f64)) as f32; +} + +/* R0/S0 on [0,2] */ +const R00: f32 = -6.2500000000e-02; /* 0xbd800000 */ +const R01: f32 = 1.4070566976e-03; /* 0x3ab86cfd */ +const R02: f32 = -1.5995563444e-05; /* 0xb7862e36 */ +const R03: f32 = 4.9672799207e-08; /* 0x335557d2 */ +const S01: f32 = 1.9153760746e-02; /* 0x3c9ce859 */ +const S02: f32 = 1.8594678841e-04; /* 0x3942fab6 */ +const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ +const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ +const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ + +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn j1f(x: f32) -> f32 { + let mut z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + let sign: bool; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + return 1.0 / (x * x); + } + if ix >= 0x40000000 { + /* |x| >= 2 */ + return common(ix, fabsf(x), false, sign); + } + if ix >= 0x39000000 { + /* |x| >= 2**-13 */ + z = x * x; + r = z * (R00 + z * (R01 + z * (R02 + z * R03))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); + z = 0.5 + r / s; + } else { + z = 0.5; + } + return z * x; +} + +const U0: [f32; 5] = [ + -1.9605709612e-01, /* 0xbe48c331 */ + 5.0443872809e-02, /* 0x3d4e9e3c */ + -1.9125689287e-03, /* 0xbafaaf2a */ + 2.3525259166e-05, /* 0x37c5581c */ + -9.1909917899e-08, /* 0xb3c56003 */ +]; +const V0: [f32; 5] = [ + 1.9916731864e-02, /* 0x3ca3286a */ + 2.0255257550e-04, /* 0x3954644b */ + 1.3560879779e-06, /* 0x35b602d4 */ + 6.2274145840e-09, /* 0x31d5f8eb */ + 1.6655924903e-11, /* 0x2d9281cf */ +]; + +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn y1f(x: f32) -> f32 { + let z: f32; + let u: f32; + let v: f32; + let ix: u32; + + ix = x.to_bits(); + if (ix & 0x7fffffff) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7f800000 { + return 1.0 / x; + } + if ix >= 0x40000000 { + /* |x| >= 2.0 */ + return common(ix, x, true, false); + } + if ix < 0x33000000 { + /* x < 2**-25 */ + return -TPI / x; + } + z = x * x; + u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + return x * (u / v) + TPI * (j1f(x) * logf(x) - 1.0 / x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +const PR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 1.1718750000e-01, /* 0x3df00000 */ + 1.3239480972e+01, /* 0x4153d4ea */ + 4.1205184937e+02, /* 0x43ce06a3 */ + 3.8747453613e+03, /* 0x45722bed */ + 7.9144794922e+03, /* 0x45f753d6 */ +]; +const PS8: [f32; 5] = [ + 1.1420736694e+02, /* 0x42e46a2c */ + 3.6509309082e+03, /* 0x45642ee5 */ + 3.6956207031e+04, /* 0x47105c35 */ + 9.7602796875e+04, /* 0x47bea166 */ + 3.0804271484e+04, /* 0x46f0a88b */ +]; + +const PR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.3199052094e-11, /* 0x2d68333f */ + 1.1718749255e-01, /* 0x3defffff */ + 6.8027510643e+00, /* 0x40d9b023 */ + 1.0830818176e+02, /* 0x42d89dca */ + 5.1763616943e+02, /* 0x440168b7 */ + 5.2871520996e+02, /* 0x44042dc6 */ +]; +const PS5: [f32; 5] = [ + 5.9280597687e+01, /* 0x426d1f55 */ + 9.9140142822e+02, /* 0x4477d9b1 */ + 5.3532670898e+03, /* 0x45a74a23 */ + 7.8446904297e+03, /* 0x45f52586 */ + 1.5040468750e+03, /* 0x44bc0180 */ +]; + +const PR3: [f32; 6] = [ + 3.0250391081e-09, /* 0x314fe10d */ + 1.1718686670e-01, /* 0x3defffab */ + 3.9329774380e+00, /* 0x407bb5e7 */ + 3.5119403839e+01, /* 0x420c7a45 */ + 9.1055007935e+01, /* 0x42b61c2a */ + 4.8559066772e+01, /* 0x42423c7c */ +]; +const PS3: [f32; 5] = [ + 3.4791309357e+01, /* 0x420b2a4d */ + 3.3676245117e+02, /* 0x43a86198 */ + 1.0468714600e+03, /* 0x4482dbe3 */ + 8.9081134033e+02, /* 0x445eb3ed */ + 1.0378793335e+02, /* 0x42cf936c */ +]; + +const PR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.0771083225e-07, /* 0x33e74ea8 */ + 1.1717621982e-01, /* 0x3deffa16 */ + 2.3685150146e+00, /* 0x401795c0 */ + 1.2242610931e+01, /* 0x4143e1bc */ + 1.7693971634e+01, /* 0x418d8d41 */ + 5.0735230446e+00, /* 0x40a25a4d */ +]; +const PS2: [f32; 5] = [ + 2.1436485291e+01, /* 0x41ab7dec */ + 1.2529022980e+02, /* 0x42fa9499 */ + 2.3227647400e+02, /* 0x436846c7 */ + 1.1767937469e+02, /* 0x42eb5bd7 */ + 8.3646392822e+00, /* 0x4105d590 */ +]; + +fn ponef(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 5]; + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x409173eb { + p = &PR5; + q = &PS5; + } else if ix >= 0x4036d917 { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +const QR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -1.0253906250e-01, /* 0xbdd20000 */ + -1.6271753311e+01, /* 0xc1822c8d */ + -7.5960174561e+02, /* 0xc43de683 */ + -1.1849806641e+04, /* 0xc639273a */ + -4.8438511719e+04, /* 0xc73d3683 */ +]; +const QS8: [f32; 6] = [ + 1.6139537048e+02, /* 0x43216537 */ + 7.8253862305e+03, /* 0x45f48b17 */ + 1.3387534375e+05, /* 0x4802bcd6 */ + 7.1965775000e+05, /* 0x492fb29c */ + 6.6660125000e+05, /* 0x4922be94 */ + -2.9449025000e+05, /* 0xc88fcb48 */ +]; + +const QR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.0897993405e-11, /* 0xadb7d219 */ + -1.0253904760e-01, /* 0xbdd1fffe */ + -8.0564479828e+00, /* 0xc100e736 */ + -1.8366960144e+02, /* 0xc337ab6b */ + -1.3731937256e+03, /* 0xc4aba633 */ + -2.6124443359e+03, /* 0xc523471c */ +]; +const QS5: [f32; 6] = [ + 8.1276550293e+01, /* 0x42a28d98 */ + 1.9917987061e+03, /* 0x44f8f98f */ + 1.7468484375e+04, /* 0x468878f8 */ + 4.9851425781e+04, /* 0x4742bb6d */ + 2.7948074219e+04, /* 0x46da5826 */ + -4.7191835938e+03, /* 0xc5937978 */ +]; + +const QR3: [f32; 6] = [ + -5.0783124372e-09, /* 0xb1ae7d4f */ + -1.0253783315e-01, /* 0xbdd1ff5b */ + -4.6101160049e+00, /* 0xc0938612 */ + -5.7847221375e+01, /* 0xc267638e */ + -2.2824453735e+02, /* 0xc3643e9a */ + -2.1921012878e+02, /* 0xc35b35cb */ +]; +const QS3: [f32; 6] = [ + 4.7665153503e+01, /* 0x423ea91e */ + 6.7386511230e+02, /* 0x4428775e */ + 3.3801528320e+03, /* 0x45534272 */ + 5.5477290039e+03, /* 0x45ad5dd5 */ + 1.9031191406e+03, /* 0x44ede3d0 */ + -1.3520118713e+02, /* 0xc3073381 */ +]; + +const QR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.7838172539e-07, /* 0xb43f8932 */ + -1.0251704603e-01, /* 0xbdd1f475 */ + -2.7522056103e+00, /* 0xc0302423 */ + -1.9663616180e+01, /* 0xc19d4f16 */ + -4.2325313568e+01, /* 0xc2294d1f */ + -2.1371921539e+01, /* 0xc1aaf9b2 */ +]; +const QS2: [f32; 6] = [ + 2.9533363342e+01, /* 0x41ec4454 */ + 2.5298155212e+02, /* 0x437cfb47 */ + 7.5750280762e+02, /* 0x443d602e */ + 7.3939318848e+02, /* 0x4438d92a */ + 1.5594900513e+02, /* 0x431bf2f2 */ + -4.9594988823e+00, /* 0xc09eb437 */ +]; + +fn qonef(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 6]; + let s: f32; + let r: f32; + let z: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x409173eb { + p = &QR5; + q = &QS5; + } else if ix >= 0x4036d917 { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (0.375 + r / s) / x; +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::{j1f, y1f}; + #[test] + fn test_j1f_2488() { + // 0x401F3E49 + assert_eq!(j1f(2.4881766_f32), 0.49999475_f32); + } + #[test] + fn test_y1f_2002() { + //allow slightly different result on x87 + let res = y1f(2.0000002_f32); + if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && (res == -0.10703231_f32) + { + return; + } + assert_eq!(res, -0.10703229_f32); + } +} diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs new file mode 100644 index 00000000000..31f8d9c5382 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -0,0 +1,339 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * jn(n, x), yn(n, x) + * floating point Bessel's function of the 1st and 2nd kind + * of order n + * + * Special cases: + * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; + * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. + * Note 2. About jn(n,x), yn(n,x) + * For n=0, j0(x) is called, + * for n=1, j1(x) is called, + * for n<=x, forward recursion is used starting + * from values of j0(x) and j1(x). + * for n>x, a continued fraction approximation to + * j(n,x)/j(n-1,x) is evaluated and then backward + * recursion is used starting from a supposed value + * for j(n,x). The resulting value of j(0,x) is + * compared with the actual value to correct the + * supposed value of j(n,x). + * + * yn(n,x) is similar in all respects, except + * that forward recursion is used for all + * values of n>1. + */ + +use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, y1}; + +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ + +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn jn(n: i32, mut x: f64) -> f64 { + let mut ix: u32; + let lx: u32; + let nm1: i32; + let mut i: i32; + let mut sign: bool; + let mut a: f64; + let mut b: f64; + let mut temp: f64; + + ix = get_high_word(x); + lx = get_low_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + // -lx == !lx + 1 + if ix | ((lx | (!lx).wrapping_add(1)) >> 31) > 0x7ff00000 { + /* nan */ + return x; + } + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ + if n == 0 { + return j0(x); + } + if n < 0 { + nm1 = -(n + 1); + x = -x; + sign = !sign; + } else { + nm1 = n - 1; + } + if nm1 == 0 { + return j1(x); + } + + sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabs(x); + if (ix | lx) == 0 || ix == 0x7ff00000 { + /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as f64) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + if ix >= 0x52d00000 { + /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + temp = match nm1 & 3 { + 0 => -cos(x) + sin(x), + 1 => -cos(x) - sin(x), + 2 => cos(x) - sin(x), + // 3 + _ => cos(x) + sin(x), + }; + b = INVSQRTPI * temp / sqrt(x); + } else { + a = j0(x); + b = j1(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b * (2.0 * (i as f64) / x) - a; /* avoid underflow */ + a = temp; + } + } + } else if ix < 0x3e100000 { + /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 32 { + /* underflow */ + b = 0.0; + } else { + temp = x * 0.5; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f64; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f64; + let mut q0: f64; + let mut q1: f64; + let mut w: f64; + let h: f64; + let mut z: f64; + let mut tmp: f64; + let nf: f64; + + let mut k: i32; + + nf = (nm1 as f64) + 1.0; + w = 2.0 * nf / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e9 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as f64) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * log(fabs(w)); + if tmp < 7.09782712893383973096e+02 { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as f64)) / x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as f64)) / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 + if b > x1p500 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0(x); + w = j1(x); + if fabs(z) >= fabs(w) { + b = t * z / b; + } else { + b = t * w / a; + } + } + + if sign { -b } else { b } +} + +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn yn(n: i32, x: f64) -> f64 { + let mut ix: u32; + let lx: u32; + let mut ib: u32; + let nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f64; + let mut b: f64; + let mut temp: f64; + + ix = get_high_word(x); + lx = get_low_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + // -lx == !lx + 1 + if ix | ((lx | (!lx).wrapping_add(1)) >> 31) > 0x7ff00000 { + /* nan */ + return x; + } + if sign && (ix | lx) != 0 { + /* x < 0 */ + return 0.0 / 0.0; + } + if ix == 0x7ff00000 { + return 0.0; + } + + if n == 0 { + return y0(x); + } + if n < 0 { + nm1 = -(n + 1); + sign = (n & 1) != 0; + } else { + nm1 = n - 1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1(x); + } else { + return y1(x); + } + } + + if ix >= 0x52d00000 { + /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + temp = match nm1 & 3 { + 0 => -sin(x) - cos(x), + 1 => -sin(x) + cos(x), + 2 => sin(x) + cos(x), + // 3 + _ => sin(x) - cos(x), + }; + b = INVSQRTPI * temp / sqrt(x); + } else { + a = y0(x); + b = y1(x); + /* quit if b is -inf */ + ib = get_high_word(b); + i = 0; + while i < nm1 && ib != 0xfff00000 { + i += 1; + temp = b; + b = (2.0 * (i as f64) / x) * b - a; + ib = get_high_word(b); + a = temp; + } + } + + if sign { -b } else { b } +} diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs new file mode 100644 index 00000000000..52cf7d8a8bd --- /dev/null +++ b/library/compiler-builtins/libm/src/math/jnf.rs @@ -0,0 +1,253 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{fabsf, j0f, j1f, logf, y0f, y1f}; + +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn jnf(n: i32, mut x: f32) -> f32 { + let mut ix: u32; + let mut nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f32; + let mut b: f32; + let mut temp: f32; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { + /* nan */ + return x; + } + + /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ + if n == 0 { + return j0f(x); + } + if n < 0 { + nm1 = -(n + 1); + x = -x; + sign = !sign; + } else { + nm1 = n - 1; + } + if nm1 == 0 { + return j1f(x); + } + + sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabsf(x); + if ix == 0 || ix == 0x7f800000 { + /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as f32) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + a = j0f(x); + b = j1f(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b * (2.0 * (i as f32) / x) - a; + a = temp; + } + } else if ix < 0x35800000 { + /* x < 2**-20 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 8 { + /* underflow */ + nm1 = 8; + } + temp = 0.5 * x; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f32; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f32; + let mut q0: f32; + let mut q1: f32; + let mut w: f32; + let h: f32; + let mut z: f32; + let mut tmp: f32; + let nf: f32; + let mut k: i32; + + nf = (nm1 as f32) + 1.0; + w = 2.0 * nf / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e4 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as f32) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * logf(fabsf(w)); + if tmp < 88.721679688 { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as f32) * b / x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as f32) * b / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 + if b > x1p60 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0f(x); + w = j1f(x); + if fabsf(z) >= fabsf(w) { + b = t * z / b; + } else { + b = t * w / a; + } + } + + if sign { -b } else { b } +} + +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ynf(n: i32, x: f32) -> f32 { + let mut ix: u32; + let mut ib: u32; + let nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f32; + let mut b: f32; + let mut temp: f32; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { + /* nan */ + return x; + } + if sign && ix != 0 { + /* x < 0 */ + return 0.0 / 0.0; + } + if ix == 0x7f800000 { + return 0.0; + } + + if n == 0 { + return y0f(x); + } + if n < 0 { + nm1 = -(n + 1); + sign = (n & 1) != 0; + } else { + nm1 = n - 1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1f(x); + } else { + return y1f(x); + } + } + + a = y0f(x); + b = y1f(x); + /* quit if b is -inf */ + ib = b.to_bits(); + i = 0; + while i < nm1 && ib != 0xff800000 { + i += 1; + temp = b; + b = (2.0 * (i as f32) / x) * b - a; + ib = b.to_bits(); + a = temp; + } + + if sign { -b } else { b } +} diff --git a/library/compiler-builtins/libm/src/math/k_cos.rs b/library/compiler-builtins/libm/src/math/k_cos.rs new file mode 100644 index 00000000000..49b2fc64d86 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_cos.rs @@ -0,0 +1,62 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_cos.c +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunSoft, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +const C1: f64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ +const C2: f64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ +const C3: f64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ +const C4: f64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ +const C5: f64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ +const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// +// Algorithm +// 1. Since cos(-x) = cos(x), we need only to consider positive x. +// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. +// 3. cos(x) is approximated by a polynomial of degree 14 on +// [0,pi/4] +// 4 14 +// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x +// where the remez error is +// +// | 2 4 6 8 10 12 14 | -58 +// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 +// | | +// +// 4 6 8 10 12 14 +// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then +// cos(x) ~ 1 - x*x/2 + r +// since cos(x+y) ~ cos(x) - sin(x)*y +// ~ cos(x) - x*y, +// a correction term is necessary in cos(x) and hence +// cos(x+y) = 1 - (x*x/2 - (r - x*y)) +// For better accuracy, rearrange to +// cos(x+y) ~ w + (tmp + (r-x*y)) +// where w = 1 - x*x/2 and tmp is a tiny correction term +// (1 - x*x/2 == w + tmp exactly in infinite precision). +// The exactness of w + tmp in infinite precision depends on w +// and tmp having the same precision as x. If they have extra +// precision due to compiler bugs, then the extra precision is +// only good provided it is retained in all terms of the final +// expression for cos(). Retention happens in all cases tested +// under FreeBSD, so don't pessimize things by forcibly clipping +// any extra precision in w. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_cos(x: f64, y: f64) -> f64 { + let z = x * x; + let w = z * z; + let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); + let hz = 0.5 * z; + let w = 1.0 - hz; + w + (((1.0 - w) - hz) + (z * r - x * y)) +} diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs new file mode 100644 index 00000000000..e99f2348c00 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -0,0 +1,29 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +const C0: f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ +const C1: f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ +const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ +const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_cosf(x: f64) -> f32 { + let z = x * x; + let w = z * z; + let r = C2 + z * C3; + (((1.0 + z * C0) + w * C1) + (w * z) * r) as f32 +} diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs new file mode 100644 index 00000000000..7345075f376 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_expo2.rs @@ -0,0 +1,14 @@ +use super::exp; + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +const K: i32 = 2043; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_expo2(x: f64) -> f64 { + let k_ln2 = f64::from_bits(0x40962066151add8b); + /* note that k is odd and scale*scale overflows */ + let scale = f64::from_bits(((((0x3ff + K / 2) as u32) << 20) as u64) << 32); + /* exp(x - k ln2) * 2**(k-1) */ + exp(x - k_ln2) * scale * scale +} diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs new file mode 100644 index 00000000000..fbd7b27d583 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -0,0 +1,14 @@ +use super::expf; + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +const K: i32 = 235; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_expo2f(x: f32) -> f32 { + let k_ln2 = f32::from_bits(0x4322e3bc); + /* note that k is odd and scale*scale overflows */ + let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); + /* exp(x - k ln2) * 2**(k-1) */ + expf(x - k_ln2) * scale * scale +} diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs new file mode 100644 index 00000000000..42441455ff3 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_sin.rs @@ -0,0 +1,53 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_sin.c +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunSoft, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +const S1: f64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ +const S2: f64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ +const S3: f64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ +const S4: f64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ +const S5: f64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ +const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// Input iy indicates whether y is 0. (if iy=0, y assume to be 0). +// +// Algorithm +// 1. Since sin(-x) = -sin(x), we need only to consider positive x. +// 2. Callers must return sin(-0) = -0 without calling here since our +// odd polynomial is not evaluated in a way that preserves -0. +// Callers may do the optimization sin(x) ~ x for tiny x. +// 3. sin(x) is approximated by a polynomial of degree 13 on +// [0,pi/4] +// 3 13 +// sin(x) ~ x + S1*x + ... + S6*x +// where +// +// |sin(x) 2 4 6 8 10 12 | -58 +// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 +// | x | +// +// 4. sin(x+y) = sin(x) + sin'(x')*y +// ~ sin(x) + (1-x*x/2)*y +// For better accuracy, let +// 3 2 2 2 2 +// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) +// then 3 2 +// sin(x) = x + (S1*x + (x *(r-y/2)+y)) +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { + let z = x * x; + let w = z * z; + let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); + let v = z * x; + if iy == 0 { x + v * (S1 + z * r) } else { x - ((z * (0.5 * y - v * r) - y) - v * S1) } +} diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs new file mode 100644 index 00000000000..88d10cababc --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -0,0 +1,30 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +const S1: f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ +const S2: f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ +const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ +const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_sinf(x: f64) -> f32 { + let z = x * x; + let w = z * z; + let r = S3 + z * S4; + let s = z * x; + ((x + s * (S1 + z * S2)) + s * w * r) as f32 +} diff --git a/library/compiler-builtins/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/src/math/k_tan.rs new file mode 100644 index 00000000000..d177010bb0a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_tan.rs @@ -0,0 +1,105 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ +// +// ==================================================== +// Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. +// +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +// kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. +// +// Algorithm +// 1. Since tan(-x) = -tan(x), we need only to consider positive x. +// 2. Callers must return tan(-0) = -0 without calling here since our +// odd polynomial is not evaluated in a way that preserves -0. +// Callers may do the optimization tan(x) ~ x for tiny x. +// 3. tan(x) is approximated by a odd polynomial of degree 27 on +// [0,0.67434] +// 3 27 +// tan(x) ~ x + T1*x + ... + T13*x +// where +// +// |tan(x) 2 4 26 | -59.2 +// |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 +// | x | +// +// Note: tan(x+y) = tan(x) + tan'(x)*y +// ~ tan(x) + (1+x*x)*y +// Therefore, for better accuracy in computing tan(x+y), let +// 3 2 2 2 2 +// r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) +// then +// 3 2 +// tan(x+y) = x + (T1*x + (x *(r+y)+y)) +// +// 4. For x in [0.67434,pi/4], let y = pi/4 - x, then +// tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) +// = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) +static T: [f64; 13] = [ + 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ + 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ + 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ + 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ + 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ + 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ + 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ + 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ + 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ + 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ + 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ + -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ + 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ +]; +const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ +const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { + let hx = (f64::to_bits(x) >> 32) as u32; + let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ + if big { + let sign = hx >> 31; + if sign != 0 { + x = -x; + y = -y; + } + x = (PIO4 - x) + (PIO4_LO - y); + y = 0.0; + } + let z = x * x; + let w = z * z; + /* + * Break x^5*(T[1]+x^2*T[2]+...) into + * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + + * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) + */ + let r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11])))); + let v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12]))))); + let s = z * x; + let r = y + z * (s * (r + v) + y) + s * T[0]; + let w = x + r; + if big { + let sign = hx >> 31; + let s = 1.0 - 2.0 * odd as f64; + let v = s - 2.0 * (x + (r - w * w / (w + s))); + return if sign != 0 { -v } else { v }; + } + if odd == 0 { + return w; + } + /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */ + let w0 = zero_low_word(w); + let v = r - (w0 - x); /* w0+v = r+x */ + let a = -1.0 / w; + let a0 = zero_low_word(a); + a0 + a * (1.0 + a0 * w0 + a0 * v) +} + +fn zero_low_word(x: f64) -> f64 { + f64::from_bits(f64::to_bits(x) & 0xFFFF_FFFF_0000_0000) +} diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs new file mode 100644 index 00000000000..af8db539dad --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_tanf.rs @@ -0,0 +1,46 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ +const T: [f64; 6] = [ + 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ + 0.133392002712976742718, /* 0x1112fd38999f72.0p-55 */ + 0.0533812378445670393523, /* 0x1b54c91d865afe.0p-57 */ + 0.0245283181166547278873, /* 0x191df3908c33ce.0p-58 */ + 0.00297435743359967304927, /* 0x185dadfcecf44e.0p-61 */ + 0.00946564784943673166728, /* 0x1362b9bf971bcd.0p-59 */ +]; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { + let z = x * x; + /* + * Split up the polynomial into small independent terms to give + * opportunities for parallel evaluation. The chosen splitting is + * micro-optimized for Athlons (XP, X64). It costs 2 multiplications + * relative to Horner's method on sequential machines. + * + * We add the small terms from lowest degree up for efficiency on + * non-sequential machines (the lowest degree terms tend to be ready + * earlier). Apart from this, we don't care about order of + * operations, and don't need to to care since we have precision to + * spare. However, the chosen splitting is good for accuracy too, + * and would give results as accurate as Horner's method if the + * small terms were added from highest degree down. + */ + let mut r = T[4] + z * T[5]; + let t = T[2] + z * T[3]; + let w = z * z; + let s = z * x; + let u = T[0] + z * T[1]; + r = (x + s * u) + (s * w) * (t + w * r); + (if odd { -1. / r } else { r }) as f32 +} diff --git a/library/compiler-builtins/libm/src/math/ldexp.rs b/library/compiler-builtins/libm/src/math/ldexp.rs new file mode 100644 index 00000000000..24899ba306a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ldexp.rs @@ -0,0 +1,21 @@ +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf16(x: f16, n: i32) -> f16 { + super::scalbnf16(x, n) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf(x: f32, n: i32) -> f32 { + super::scalbnf(x, n) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexp(x: f64, n: i32) -> f64 { + super::scalbn(x, n) +} + +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf128(x: f128, n: i32) -> f128 { + super::scalbnf128(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/ldexpf.rs b/library/compiler-builtins/libm/src/math/ldexpf.rs new file mode 100644 index 00000000000..95b27fc49d2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ldexpf.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf(x: f32, n: i32) -> f32 { + super::scalbnf(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/ldexpf128.rs b/library/compiler-builtins/libm/src/math/ldexpf128.rs new file mode 100644 index 00000000000..b35277d15fb --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ldexpf128.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf128(x: f128, n: i32) -> f128 { + super::scalbnf128(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/ldexpf16.rs b/library/compiler-builtins/libm/src/math/ldexpf16.rs new file mode 100644 index 00000000000..8de6cffd699 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ldexpf16.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf16(x: f16, n: i32) -> f16 { + super::scalbnf16(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/src/math/lgamma.rs new file mode 100644 index 00000000000..8312dc18648 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/lgamma.rs @@ -0,0 +1,8 @@ +use super::lgamma_r; + +/// The natural logarithm of the +/// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn lgamma(x: f64) -> f64 { + lgamma_r(x).0 +} diff --git a/library/compiler-builtins/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/src/math/lgamma_r.rs new file mode 100644 index 00000000000..6becaad2ce9 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/lgamma_r.rs @@ -0,0 +1,321 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = PI/sin(PI*x), + * we have + * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(PI*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); + * Note: one should avoid compute PI*(-x) directly in the + * computation of sin(PI*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +use super::{floor, k_cos, k_sin, log}; + +const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ +const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ +const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ +const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ +const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ +const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ +const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ +const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ +const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ +const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ +const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ +const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ +const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ +const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ +const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of TF) */ +const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ +const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ +const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ +const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ +const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ +const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ +const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ +const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ +const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ +const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ +const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ +const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ +const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ +const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ +const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ +const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ +const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ +const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ +const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ +const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ +const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ +const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ +const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ +const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ +const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ +const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ +const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ +const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ +const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ +const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ +const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ +const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ +const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ +const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ +const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ +const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ +const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ +const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ +const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ +const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ +const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ +const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ +const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ +const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ +const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f64) -> f64 { + let mut n: i32; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ + + n = (x * 4.0) as i32; + n = div!(n + 1, 2); + x -= (n as f64) * 0.5; + x *= PI; + + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + // 0 + _ => k_sin(x, 0.0, 0), + } +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn lgamma_r(mut x: f64) -> (f64, i32) { + let u: u64 = x.to_bits(); + let mut t: f64; + let y: f64; + let mut z: f64; + let nadj: f64; + let p: f64; + let p1: f64; + let p2: f64; + let p3: f64; + let q: f64; + let mut r: f64; + let w: f64; + let ix: u32; + let sign: bool; + let i: i32; + let mut signgam: i32; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u >> 63) != 0; + ix = ((u >> 32) as u32) & 0x7fffffff; + if ix >= 0x7ff00000 { + return (x * x, signgam); + } + if ix < (0x3ff - 70) << 20 { + /* |x|<2**-70, return -log(|x|) */ + if sign { + x = -x; + signgam = -1; + } + return (-log(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { + /* -integer */ + return (1.0 / (x - x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = log(PI / (t * x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3feccccc { + /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -log(x); + if ix >= 0x3FE76944 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3FCDA661 { + y = x - (TC - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3FFBB4C3 { + /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3FF3B4C4 { + /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y * y; + p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); + p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); + p = y * p1 + p2; + r += p - 0.5 * y; + } + 1 => { + z = y * y; + w = z * y; + p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ + p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); + p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); + p = z * p1 - (TT - w * (p2 + y * p3)); + r += TF + p; + } + 2 => { + p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); + p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); + r += -0.5 * y + p1 / p2; + } + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => {} + } + } else if ix < 0x40200000 { + /* x < 8.0 */ + i = x as i32; + y = x - (i as f64); + p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); + q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { + z *= y + 6.0; + } + if i >= 6 { + z *= y + 5.0; + } + if i >= 5 { + z *= y + 4.0; + } + if i >= 4 { + z *= y + 3.0; + } + if i >= 3 { + z *= y + 2.0; + r += log(z); + } + } else if ix < 0x43900000 { + /* 8.0 <= x < 2**58 */ + t = log(x); + z = 1.0 / x; + y = z * z; + w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else { + /* 2**58 <= x <= inf */ + r = x * (log(x) - 1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/src/math/lgammaf.rs new file mode 100644 index 00000000000..d37512397cb --- /dev/null +++ b/library/compiler-builtins/libm/src/math/lgammaf.rs @@ -0,0 +1,8 @@ +use super::lgammaf_r; + +/// The natural logarithm of the +/// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn lgammaf(x: f32) -> f32 { + lgammaf_r(x).0 +} diff --git a/library/compiler-builtins/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/src/math/lgammaf_r.rs new file mode 100644 index 00000000000..10cecee541c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/lgammaf_r.rs @@ -0,0 +1,256 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{floorf, k_cosf, k_sinf, logf}; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ +const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ +const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ +const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ +const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ +const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ +const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ +const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ +const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ +const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ +const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ +const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ +const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ +const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ +/* TT = -(tail of TF) */ +const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ +const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ +const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ +const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ +const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ +const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ +const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ +const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ +const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ +const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ +const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ +const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ +const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ +const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ +const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ +const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ +const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ +const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ +const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ +const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ +const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ +const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ +const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ +const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ +const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ +const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ +const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ +const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ +const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ +const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ +const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ +const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ +const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ +const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ +const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ +const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ +const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ +const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ +const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ +const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ +const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ +const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ +const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ +const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f32) -> f32 { + let mut y: f64; + let mut n: isize; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ + + n = (x * 4.0) as isize; + n = div!(n + 1, 2); + y = (x as f64) - (n as f64) * 0.5; + y *= 3.14159265358979323846; + match n { + 1 => k_cosf(y), + 2 => k_sinf(-y), + 3 => -k_cosf(y), + // 0 + _ => k_sinf(y), + } +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn lgammaf_r(mut x: f32) -> (f32, i32) { + let u = x.to_bits(); + let mut t: f32; + let y: f32; + let mut z: f32; + let nadj: f32; + let p: f32; + let p1: f32; + let p2: f32; + let p3: f32; + let q: f32; + let mut r: f32; + let w: f32; + let ix: u32; + let i: i32; + let sign: bool; + let mut signgam: i32; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u >> 31) != 0; + ix = u & 0x7fffffff; + if ix >= 0x7f800000 { + return (x * x, signgam); + } + if ix < 0x35000000 { + /* |x| < 2**-21, return -log(|x|) */ + if sign { + signgam = -1; + x = -x; + } + return (-logf(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { + /* -integer */ + return (1.0 / (x - x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = logf(PI / (t * x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if ix == 0x3f800000 || ix == 0x40000000 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3f666666 { + /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -logf(x); + if ix >= 0x3f3b4a20 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3e6d3308 { + y = x - (TC - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3fdda618 { + /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3F9da620 { + /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y * y; + p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); + p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); + p = y * p1 + p2; + r += p - 0.5 * y; + } + 1 => { + z = y * y; + w = z * y; + p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ + p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); + p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); + p = z * p1 - (TT - w * (p2 + y * p3)); + r += TF + p; + } + 2 => { + p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); + p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); + r += -0.5 * y + p1 / p2; + } + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => {} + } + } else if ix < 0x41000000 { + /* x < 8.0 */ + i = x as i32; + y = x - (i as f32); + p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); + q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { + z *= y + 6.0; + } + if i >= 6 { + z *= y + 5.0; + } + if i >= 5 { + z *= y + 4.0; + } + if i >= 4 { + z *= y + 3.0; + } + if i >= 3 { + z *= y + 2.0; + r += logf(z); + } + } else if ix < 0x5c800000 { + /* 8.0 <= x < 2**58 */ + t = logf(x); + z = 1.0 / x; + y = z * z; + w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else { + /* 2**58 <= x <= inf */ + r = x * (logf(x) - 1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/src/math/log.rs b/library/compiler-builtins/libm/src/math/log.rs new file mode 100644 index 00000000000..f2dc47ec5cc --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log.rs @@ -0,0 +1,118 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* log(x) + * Return the logarithm of x + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Remez algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +/// The natural logarithm of `x` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui = x.to_bits(); + let mut hx: u32 = (ui >> 32) as u32; + let mut k: i32 = 0; + + if (hx < 0x00100000) || ((hx >> 31) != 0) { + /* x < 2**-126 */ + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if hx >> 31 != 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += ((hx >> 20) as i32) - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = ((hx as u64) << 32) | (ui & 0xffffffff); + x = f64::from_bits(ui); + + let f: f64 = x - 1.0; + let hfsq: f64 = 0.5 * f * f; + let s: f64 = f / (2.0 + f); + let z: f64 = s * s; + let w: f64 = z * z; + let t1: f64 = w * (LG2 + w * (LG4 + w * LG6)); + let t2: f64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + let r: f64 = t2 + t1; + let dk: f64 = k as f64; + s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI +} diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs new file mode 100644 index 00000000000..8c9d68c492d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -0,0 +1,118 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 10 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) + */ + +use core::f64; + +const IVLN10HI: f64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ +const IVLN10LO: f64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ +const LOG10_2HI: f64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ +const LOG10_2LO: f64 = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +/// The base 10 logarithm of `x` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log10(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let f: f64; + let s: f64; + let z: f64; + let r: f64; + let mut w: f64; + let t1: f64; + let t2: f64; + let dk: f64; + let y: f64; + let mut hi: f64; + let lo: f64; + let mut val_hi: f64; + let mut val_lo: f64; + let mut hx: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 0; + if hx < 0x00100000 || (hx >> 31) > 0 { + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (hx >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (hx >> 20) as i32 - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = ((hx as u64) << 32) | (ui & 0xffffffff); + x = f64::from_bits(ui); + + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + + /* See log2.c for details. */ + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + ui = hi.to_bits(); + ui &= (-1i64 as u64) << 32; + hi = f64::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + + /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ + val_hi = hi * IVLN10HI; + dk = k as f64; + y = dk * LOG10_2HI; + val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI; + + /* + * Extra precision in for adding y is not strictly needed + * since there is no very large cancellation near x = sqrt(2) or + * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs + * with some parallelism and it reduces the error for many args. + */ + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + val_lo + val_hi +} diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs new file mode 100644 index 00000000000..18bf8fcc832 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log10f.rs @@ -0,0 +1,92 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log10.c. + */ + +use core::f32; + +const IVLN10HI: f32 = 4.3432617188e-01; /* 0x3ede6000 */ +const IVLN10LO: f32 = -3.1689971365e-05; /* 0xb804ead9 */ +const LOG10_2HI: f32 = 3.0102920532e-01; /* 0x3e9a2080 */ +const LOG10_2LO: f32 = 7.9034151668e-07; /* 0x355427db */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +/// The base 10 logarithm of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log10f(mut x: f32) -> f32 { + let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 + + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let f: f32; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let dk: f32; + let mut hi: f32; + let lo: f32; + let mut ix: u32; + let mut k: i32; + + ix = ui; + k = 0; + if ix < 0x00800000 || (ix >> 31) > 0 { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (ix >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25f; + ui = x.to_bits(); + ix = ui; + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (ix >> 23) as i32 - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + ui = ix; + x = f32::from_bits(ui); + + f = x - 1.0; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + + hi = f - hfsq; + ui = hi.to_bits(); + ui &= 0xfffff000; + hi = f32::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + dk = k as f32; + dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI +} diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs new file mode 100644 index 00000000000..b7f3fb09e15 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -0,0 +1,140 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double log1p(double x) + * Return the natural logarithm of 1+x. + * + * Method : + * 1. Argument Reduction: find k and f such that + * 1+x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * Note. If k=0, then f=x is exact. However, if k!=0, then f + * may not be representable exactly. In that case, a correction + * term is need. Let u=1+x rounded. Let c = (1+x)-u, then + * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), + * and add back the correction term c/u. + * (Note: when x > 2**53, one can simply return log(x)) + * + * 2. Approximation of log(1+f): See log.c + * + * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c + * + * Special cases: + * log1p(x) is NaN with signal if x < -1 (including -INF) ; + * log1p(+INF) is +INF; log1p(-1) is -INF with signal; + * log1p(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + * + * Note: Assuming log() return accurate answer, the following + * algorithm can be used to compute log1p(x) to within a few ULP: + * + * u = 1+x; + * if(u==1.0) return x ; else + * return log(u)*(x/(u-1.0)); + * + * See HP-15C Advanced Functions Handbook, p.193. + */ + +use core::f64; + +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +/// The natural logarithm of 1+`x` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log1p(x: f64) -> f64 { + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let mut f: f64 = 0.; + let mut c: f64 = 0.; + let s: f64; + let z: f64; + let r: f64; + let w: f64; + let t1: f64; + let t2: f64; + let dk: f64; + let hx: u32; + let mut hu: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 1; + if hx < 0x3fda827a || (hx >> 31) > 0 { + /* 1+x < sqrt(2)+ */ + if hx >= 0xbff00000 { + /* x <= -1.0 */ + if x == -1. { + return x / 0.0; /* log1p(-1) = -inf */ + } + return (x - x) / 0.0; /* log1p(x<-1) = NaN */ + } + if hx << 1 < 0x3ca00000 << 1 { + /* |x| < 2**-53 */ + /* underflow if subnormal */ + if (hx & 0x7ff00000) == 0 { + force_eval!(x as f32); + } + return x; + } + if hx <= 0xbfd2bec4 { + /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0.; + f = x; + } + } else if hx >= 0x7ff00000 { + return x; + } + if k > 0 { + ui = (1. + x).to_bits(); + hu = (ui >> 32) as u32; + hu += 0x3ff00000 - 0x3fe6a09e; + k = (hu >> 20) as i32 - 0x3ff; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if k < 54 { + c = if k >= 2 { 1. - (f64::from_bits(ui) - x) } else { x - (f64::from_bits(ui) - 1.) }; + c /= f64::from_bits(ui); + } else { + c = 0.; + } + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + hu = (hu & 0x000fffff) + 0x3fe6a09e; + ui = ((hu as u64) << 32) | (ui & 0xffffffff); + f = f64::from_bits(ui) - 1.; + } + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + dk = k as f64; + s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI +} diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs new file mode 100644 index 00000000000..bba5b8a2f21 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -0,0 +1,95 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f32; + +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +/// The natural logarithm of 1+`x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log1pf(x: f32) -> f32 { + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let mut f: f32 = 0.; + let mut c: f32 = 0.; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let dk: f32; + let ix: u32; + let mut iu: u32; + let mut k: i32; + + ix = ui; + k = 1; + if ix < 0x3ed413d0 || (ix >> 31) > 0 { + /* 1+x < sqrt(2)+ */ + if ix >= 0xbf800000 { + /* x <= -1.0 */ + if x == -1. { + return x / 0.0; /* log1p(-1)=+inf */ + } + return (x - x) / 0.0; /* log1p(x<-1)=NaN */ + } + if ix << 1 < 0x33800000 << 1 { + /* |x| < 2**-24 */ + /* underflow if subnormal */ + if (ix & 0x7f800000) == 0 { + force_eval!(x * x); + } + return x; + } + if ix <= 0xbe95f619 { + /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0.; + f = x; + } + } else if ix >= 0x7f800000 { + return x; + } + if k > 0 { + ui = (1. + x).to_bits(); + iu = ui; + iu += 0x3f800000 - 0x3f3504f3; + k = (iu >> 23) as i32 - 0x7f; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if k < 25 { + c = if k >= 2 { 1. - (f32::from_bits(ui) - x) } else { x - (f32::from_bits(ui) - 1.) }; + c /= f32::from_bits(ui); + } else { + c = 0.; + } + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + iu = (iu & 0x007fffff) + 0x3f3504f3; + ui = iu; + f = f32::from_bits(ui) - 1.; + } + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + dk = k as f32; + s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI +} diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs new file mode 100644 index 00000000000..701f63c25e7 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -0,0 +1,107 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 2 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log2(x) = (f - f*f/2 + r)/log(2) + k + */ + +use core::f64; + +const IVLN2HI: f64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ +const IVLN2LO: f64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +/// The base 2 logarithm of `x` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log2(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let f: f64; + let s: f64; + let z: f64; + let r: f64; + let mut w: f64; + let t1: f64; + let t2: f64; + let y: f64; + let mut hi: f64; + let lo: f64; + let mut val_hi: f64; + let mut val_lo: f64; + let mut hx: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 0; + if hx < 0x00100000 || (hx >> 31) > 0 { + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (hx >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (hx >> 20) as i32 - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = ((hx as u64) << 32) | (ui & 0xffffffff); + x = f64::from_bits(ui); + + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + ui = hi.to_bits(); + ui &= (-1i64 as u64) << 32; + hi = f64::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + + val_hi = hi * IVLN2HI; + val_lo = (lo + hi) * IVLN2LO + lo * IVLN2HI; + + /* spadd(val_hi, val_lo, y), except for not using double_t: */ + y = k.into(); + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + val_lo + val_hi +} diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs new file mode 100644 index 00000000000..5ba2427d1d4 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -0,0 +1,88 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log2.c. + */ + +use core::f32; + +const IVLN2HI: f32 = 1.4428710938e+00; /* 0x3fb8b000 */ +const IVLN2LO: f32 = -1.7605285393e-04; /* 0xb9389ad4 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +/// The base 2 logarithm of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log2f(mut x: f32) -> f32 { + let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 + + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let f: f32; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let mut hi: f32; + let lo: f32; + let mut ix: u32; + let mut k: i32; + + ix = ui; + k = 0; + if ix < 0x00800000 || (ix >> 31) > 0 { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (ix >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25f; + ui = x.to_bits(); + ix = ui; + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (ix >> 23) as i32 - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + ui = ix; + x = f32::from_bits(ui); + + f = x - 1.0; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + + hi = f - hfsq; + ui = hi.to_bits(); + ui &= 0xfffff000; + hi = f32::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as f32 +} diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs new file mode 100644 index 00000000000..68d1943025e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -0,0 +1,66 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +/// The natural logarithm of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn logf(mut x: f32) -> f32 { + let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 + + let mut ix = x.to_bits(); + let mut k = 0i32; + + if (ix < 0x00800000) || ((ix >> 31) != 0) { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (ix >> 31) != 0 { + return (x - x) / 0.; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25; + ix = x.to_bits(); + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += ((ix >> 23) as i32) - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + x = f32::from_bits(ix); + + let f = x - 1.; + let s = f / (2. + f); + let z = s * s; + let w = z * z; + let t1 = w * (LG2 + w * LG4); + let t2 = z * (LG1 + w * LG3); + let r = t2 + t1; + let hfsq = 0.5 * f * f; + let dk = k as f32; + s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs new file mode 100644 index 00000000000..949c18b4000 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -0,0 +1,396 @@ +macro_rules! force_eval { + ($e:expr) => { + unsafe { ::core::ptr::read_volatile(&$e) } + }; +} + +#[cfg(not(debug_assertions))] +macro_rules! i { + ($array:expr, $index:expr) => { + unsafe { *$array.get_unchecked($index) } + }; + ($array:expr, $index:expr, = , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) = $rhs; + } + }; + ($array:expr, $index:expr, += , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) += $rhs; + } + }; + ($array:expr, $index:expr, -= , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) -= $rhs; + } + }; + ($array:expr, $index:expr, &= , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) &= $rhs; + } + }; + ($array:expr, $index:expr, == , $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) == $rhs } + }; +} + +#[cfg(debug_assertions)] +macro_rules! i { + ($array:expr, $index:expr) => { + *$array.get($index).unwrap() + }; + ($array:expr, $index:expr, = , $rhs:expr) => { + *$array.get_mut($index).unwrap() = $rhs; + }; + ($array:expr, $index:expr, -= , $rhs:expr) => { + *$array.get_mut($index).unwrap() -= $rhs; + }; + ($array:expr, $index:expr, += , $rhs:expr) => { + *$array.get_mut($index).unwrap() += $rhs; + }; + ($array:expr, $index:expr, &= , $rhs:expr) => { + *$array.get_mut($index).unwrap() &= $rhs; + }; + ($array:expr, $index:expr, == , $rhs:expr) => { + *$array.get_mut($index).unwrap() == $rhs + }; +} + +// Temporary macro to avoid panic codegen for division (in debug mode too). At +// the time of this writing this is only used in a few places, and once +// rust-lang/rust#72751 is fixed then this macro will no longer be necessary and +// the native `/` operator can be used and panics won't be codegen'd. +#[cfg(any(debug_assertions, not(intrinsics_enabled)))] +macro_rules! div { + ($a:expr, $b:expr) => { + $a / $b + }; +} + +#[cfg(all(not(debug_assertions), intrinsics_enabled))] +macro_rules! div { + ($a:expr, $b:expr) => { + unsafe { core::intrinsics::unchecked_div($a, $b) } + }; +} + +// `support` may be public for testing +#[macro_use] +#[cfg(feature = "unstable-public-internals")] +pub mod support; + +#[macro_use] +#[cfg(not(feature = "unstable-public-internals"))] +pub(crate) mod support; + +cfg_if! { + if #[cfg(feature = "unstable-public-internals")] { + pub mod generic; + } else { + mod generic; + } +} + +// Private modules +mod arch; +mod expo2; +mod k_cos; +mod k_cosf; +mod k_expo2; +mod k_expo2f; +mod k_sin; +mod k_sinf; +mod k_tan; +mod k_tanf; +mod rem_pio2; +mod rem_pio2_large; +mod rem_pio2f; + +// Private re-imports +use self::expo2::expo2; +use self::k_cos::k_cos; +use self::k_cosf::k_cosf; +use self::k_expo2::k_expo2; +use self::k_expo2f::k_expo2f; +use self::k_sin::k_sin; +use self::k_sinf::k_sinf; +use self::k_tan::k_tan; +use self::k_tanf::k_tanf; +use self::rem_pio2::rem_pio2; +use self::rem_pio2_large::rem_pio2_large; +use self::rem_pio2f::rem_pio2f; +#[allow(unused_imports)] +use self::support::{CastFrom, CastInto, DFloat, DInt, Float, HFloat, HInt, Int, IntTy, MinInt}; + +// Public modules +mod acos; +mod acosf; +mod acosh; +mod acoshf; +mod asin; +mod asinf; +mod asinh; +mod asinhf; +mod atan; +mod atan2; +mod atan2f; +mod atanf; +mod atanh; +mod atanhf; +mod cbrt; +mod cbrtf; +mod ceil; +mod copysign; +mod cos; +mod cosf; +mod cosh; +mod coshf; +mod erf; +mod erff; +mod exp; +mod exp10; +mod exp10f; +mod exp2; +mod exp2f; +mod expf; +mod expm1; +mod expm1f; +mod fabs; +mod fdim; +mod floor; +mod fma; +mod fma_wide; +mod fmin_fmax; +mod fminimum_fmaximum; +mod fminimum_fmaximum_num; +mod fmod; +mod frexp; +mod frexpf; +mod hypot; +mod hypotf; +mod ilogb; +mod ilogbf; +mod j0; +mod j0f; +mod j1; +mod j1f; +mod jn; +mod jnf; +mod ldexp; +mod lgamma; +mod lgamma_r; +mod lgammaf; +mod lgammaf_r; +mod log; +mod log10; +mod log10f; +mod log1p; +mod log1pf; +mod log2; +mod log2f; +mod logf; +mod modf; +mod modff; +mod nextafter; +mod nextafterf; +mod pow; +mod powf; +mod remainder; +mod remainderf; +mod remquo; +mod remquof; +mod rint; +mod round; +mod roundeven; +mod scalbn; +mod sin; +mod sincos; +mod sincosf; +mod sinf; +mod sinh; +mod sinhf; +mod sqrt; +mod tan; +mod tanf; +mod tanh; +mod tanhf; +mod tgamma; +mod tgammaf; +mod trunc; + +// Use separated imports instead of {}-grouped imports for easier merging. +pub use self::acos::acos; +pub use self::acosf::acosf; +pub use self::acosh::acosh; +pub use self::acoshf::acoshf; +pub use self::asin::asin; +pub use self::asinf::asinf; +pub use self::asinh::asinh; +pub use self::asinhf::asinhf; +pub use self::atan::atan; +pub use self::atan2::atan2; +pub use self::atan2f::atan2f; +pub use self::atanf::atanf; +pub use self::atanh::atanh; +pub use self::atanhf::atanhf; +pub use self::cbrt::cbrt; +pub use self::cbrtf::cbrtf; +pub use self::ceil::{ceil, ceilf}; +pub use self::copysign::{copysign, copysignf}; +pub use self::cos::cos; +pub use self::cosf::cosf; +pub use self::cosh::cosh; +pub use self::coshf::coshf; +pub use self::erf::{erf, erfc}; +pub use self::erff::{erfcf, erff}; +pub use self::exp::exp; +pub use self::exp2::exp2; +pub use self::exp2f::exp2f; +pub use self::exp10::exp10; +pub use self::exp10f::exp10f; +pub use self::expf::expf; +pub use self::expm1::expm1; +pub use self::expm1f::expm1f; +pub use self::fabs::{fabs, fabsf}; +pub use self::fdim::{fdim, fdimf}; +pub use self::floor::{floor, floorf}; +pub use self::fma::fma; +pub use self::fma_wide::fmaf; +pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; +pub use self::fminimum_fmaximum::{fmaximum, fmaximumf, fminimum, fminimumf}; +pub use self::fminimum_fmaximum_num::{fmaximum_num, fmaximum_numf, fminimum_num, fminimum_numf}; +pub use self::fmod::{fmod, fmodf}; +pub use self::frexp::frexp; +pub use self::frexpf::frexpf; +pub use self::hypot::hypot; +pub use self::hypotf::hypotf; +pub use self::ilogb::ilogb; +pub use self::ilogbf::ilogbf; +pub use self::j0::{j0, y0}; +pub use self::j0f::{j0f, y0f}; +pub use self::j1::{j1, y1}; +pub use self::j1f::{j1f, y1f}; +pub use self::jn::{jn, yn}; +pub use self::jnf::{jnf, ynf}; +pub use self::ldexp::{ldexp, ldexpf}; +pub use self::lgamma::lgamma; +pub use self::lgamma_r::lgamma_r; +pub use self::lgammaf::lgammaf; +pub use self::lgammaf_r::lgammaf_r; +pub use self::log::log; +pub use self::log1p::log1p; +pub use self::log1pf::log1pf; +pub use self::log2::log2; +pub use self::log2f::log2f; +pub use self::log10::log10; +pub use self::log10f::log10f; +pub use self::logf::logf; +pub use self::modf::modf; +pub use self::modff::modff; +pub use self::nextafter::nextafter; +pub use self::nextafterf::nextafterf; +pub use self::pow::pow; +pub use self::powf::powf; +pub use self::remainder::remainder; +pub use self::remainderf::remainderf; +pub use self::remquo::remquo; +pub use self::remquof::remquof; +pub use self::rint::{rint, rintf}; +pub use self::round::{round, roundf}; +pub use self::roundeven::{roundeven, roundevenf}; +pub use self::scalbn::{scalbn, scalbnf}; +pub use self::sin::sin; +pub use self::sincos::sincos; +pub use self::sincosf::sincosf; +pub use self::sinf::sinf; +pub use self::sinh::sinh; +pub use self::sinhf::sinhf; +pub use self::sqrt::{sqrt, sqrtf}; +pub use self::tan::tan; +pub use self::tanf::tanf; +pub use self::tanh::tanh; +pub use self::tanhf::tanhf; +pub use self::tgamma::tgamma; +pub use self::tgammaf::tgammaf; +pub use self::trunc::{trunc, truncf}; + +cfg_if! { + if #[cfg(f16_enabled)] { + // verify-sorted-start + pub use self::ceil::ceilf16; + pub use self::copysign::copysignf16; + pub use self::fabs::fabsf16; + pub use self::fdim::fdimf16; + pub use self::floor::floorf16; + pub use self::fmin_fmax::{fmaxf16, fminf16}; + pub use self::fminimum_fmaximum::{fmaximumf16, fminimumf16}; + pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16}; + pub use self::fmod::fmodf16; + pub use self::ldexp::ldexpf16; + pub use self::rint::rintf16; + pub use self::round::roundf16; + pub use self::roundeven::roundevenf16; + pub use self::scalbn::scalbnf16; + pub use self::sqrt::sqrtf16; + pub use self::trunc::truncf16; + // verify-sorted-end + + #[allow(unused_imports)] + pub(crate) use self::fma_wide::fmaf16; + } +} + +cfg_if! { + if #[cfg(f128_enabled)] { + // verify-sorted-start + pub use self::ceil::ceilf128; + pub use self::copysign::copysignf128; + pub use self::fabs::fabsf128; + pub use self::fdim::fdimf128; + pub use self::floor::floorf128; + pub use self::fma::fmaf128; + pub use self::fmin_fmax::{fmaxf128, fminf128}; + pub use self::fminimum_fmaximum::{fmaximumf128, fminimumf128}; + pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; + pub use self::fmod::fmodf128; + pub use self::ldexp::ldexpf128; + pub use self::rint::rintf128; + pub use self::round::roundf128; + pub use self::roundeven::roundevenf128; + pub use self::scalbn::scalbnf128; + pub use self::sqrt::sqrtf128; + pub use self::trunc::truncf128; + // verify-sorted-end + } +} + +#[inline] +fn get_high_word(x: f64) -> u32 { + (x.to_bits() >> 32) as u32 +} + +#[inline] +fn get_low_word(x: f64) -> u32 { + x.to_bits() as u32 +} + +#[inline] +fn with_set_high_word(f: f64, hi: u32) -> f64 { + let mut tmp = f.to_bits(); + tmp &= 0x00000000_ffffffff; + tmp |= (hi as u64) << 32; + f64::from_bits(tmp) +} + +#[inline] +fn with_set_low_word(f: f64, lo: u32) -> f64 { + let mut tmp = f.to_bits(); + tmp &= 0xffffffff_00000000; + tmp |= lo as u64; + f64::from_bits(tmp) +} + +#[inline] +fn combine_words(hi: u32, lo: u32) -> f64 { + f64::from_bits(((hi as u64) << 32) | lo as u64) +} diff --git a/library/compiler-builtins/libm/src/math/modf.rs b/library/compiler-builtins/libm/src/math/modf.rs new file mode 100644 index 00000000000..6541862cdd9 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/modf.rs @@ -0,0 +1,35 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn modf(x: f64) -> (f64, f64) { + let rv2: f64; + let mut u = x.to_bits(); + let mask: u64; + let e = (((u >> 52) & 0x7ff) as i32) - 0x3ff; + + /* no fractional part */ + if e >= 52 { + rv2 = x; + if e == 0x400 && (u << 12) != 0 { + /* nan */ + return (x, rv2); + } + u &= 1 << 63; + return (f64::from_bits(u), rv2); + } + + /* no integral part*/ + if e < 0 { + u &= 1 << 63; + rv2 = f64::from_bits(u); + return (x, rv2); + } + + mask = ((!0) >> 12) >> e; + if (u & mask) == 0 { + rv2 = x; + u &= 1 << 63; + return (f64::from_bits(u), rv2); + } + u &= !mask; + rv2 = f64::from_bits(u); + return (x - rv2, rv2); +} diff --git a/library/compiler-builtins/libm/src/math/modff.rs b/library/compiler-builtins/libm/src/math/modff.rs new file mode 100644 index 00000000000..90c6bca7d8d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/modff.rs @@ -0,0 +1,34 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn modff(x: f32) -> (f32, f32) { + let rv2: f32; + let mut u: u32 = x.to_bits(); + let mask: u32; + let e = (((u >> 23) & 0xff) as i32) - 0x7f; + + /* no fractional part */ + if e >= 23 { + rv2 = x; + if e == 0x80 && (u << 9) != 0 { + /* nan */ + return (x, rv2); + } + u &= 0x80000000; + return (f32::from_bits(u), rv2); + } + /* no integral part */ + if e < 0 { + u &= 0x80000000; + rv2 = f32::from_bits(u); + return (x, rv2); + } + + mask = 0x007fffff >> e; + if (u & mask) == 0 { + rv2 = x; + u &= 0x80000000; + return (f32::from_bits(u), rv2); + } + u &= !mask; + rv2 = f32::from_bits(u); + return (x - rv2, rv2); +} diff --git a/library/compiler-builtins/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/src/math/nextafter.rs new file mode 100644 index 00000000000..c991ff6f233 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/nextafter.rs @@ -0,0 +1,37 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn nextafter(x: f64, y: f64) -> f64 { + if x.is_nan() || y.is_nan() { + return x + y; + } + + let mut ux_i = x.to_bits(); + let uy_i = y.to_bits(); + if ux_i == uy_i { + return y; + } + + let ax = ux_i & (!1_u64 / 2); + let ay = uy_i & (!1_u64 / 2); + if ax == 0 { + if ay == 0 { + return y; + } + ux_i = (uy_i & (1_u64 << 63)) | 1; + } else if ax > ay || ((ux_i ^ uy_i) & (1_u64 << 63)) != 0 { + ux_i -= 1; + } else { + ux_i += 1; + } + + let e = (ux_i >> 52) & 0x7ff; + // raise overflow if ux.f is infinite and x is finite + if e == 0x7ff { + force_eval!(x + x); + } + let ux_f = f64::from_bits(ux_i); + // raise underflow if ux.f is subnormal or zero + if e == 0 { + force_eval!(x * x + ux_f * ux_f); + } + ux_f +} diff --git a/library/compiler-builtins/libm/src/math/nextafterf.rs b/library/compiler-builtins/libm/src/math/nextafterf.rs new file mode 100644 index 00000000000..8ba3833562f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/nextafterf.rs @@ -0,0 +1,37 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn nextafterf(x: f32, y: f32) -> f32 { + if x.is_nan() || y.is_nan() { + return x + y; + } + + let mut ux_i = x.to_bits(); + let uy_i = y.to_bits(); + if ux_i == uy_i { + return y; + } + + let ax = ux_i & 0x7fff_ffff_u32; + let ay = uy_i & 0x7fff_ffff_u32; + if ax == 0 { + if ay == 0 { + return y; + } + ux_i = (uy_i & 0x8000_0000_u32) | 1; + } else if ax > ay || ((ux_i ^ uy_i) & 0x8000_0000_u32) != 0 { + ux_i -= 1; + } else { + ux_i += 1; + } + + let e = ux_i & 0x7f80_0000_u32; + // raise overflow if ux_f is infinite and x is finite + if e == 0x7f80_0000_u32 { + force_eval!(x + x); + } + let ux_f = f32::from_bits(ux_i); + // raise underflow if ux_f is subnormal or zero + if e == 0 { + force_eval!(x * x + ux_f * ux_f); + } + ux_f +} diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs new file mode 100644 index 00000000000..80b2a24999c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -0,0 +1,607 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +// pow(x,y) return x**y +// +// n +// Method: Let x = 2 * (1+f) +// 1. Compute and return log2(x) in two pieces: +// log2(x) = w1 + w2, +// where w1 has 53-24 = 29 bit trailing zeros. +// 2. Perform y*log2(x) = n+y' by simulating multi-precision +// arithmetic, where |y'|<=0.5. +// 3. Return x**y = 2**n*exp(y'*log2) +// +// Special cases: +// 1. (anything) ** 0 is 1 +// 2. 1 ** (anything) is 1 +// 3. (anything except 1) ** NAN is NAN +// 4. NAN ** (anything except 0) is NAN +// 5. +-(|x| > 1) ** +INF is +INF +// 6. +-(|x| > 1) ** -INF is +0 +// 7. +-(|x| < 1) ** +INF is +0 +// 8. +-(|x| < 1) ** -INF is +INF +// 9. -1 ** +-INF is 1 +// 10. +0 ** (+anything except 0, NAN) is +0 +// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 +// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero +// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero +// 14. -0 ** (+odd integer) is -0 +// 15. -0 ** (-odd integer) is -INF, raise divbyzero +// 16. +INF ** (+anything except 0,NAN) is +INF +// 17. +INF ** (-anything except 0,NAN) is +0 +// 18. -INF ** (+odd integer) is -INF +// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) +// 20. (anything) ** 1 is (anything) +// 21. (anything) ** -1 is 1/(anything) +// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) +// 23. (-anything except 0 and inf) ** (non-integer) is NAN +// +// Accuracy: +// pow(x,y) returns x**y nearly rounded. In particular +// pow(integer,integer) +// always returns the correct integer provided it is +// representable. +// +// Constants : +// The hexadecimal values are the intended ones for the following +// constants. The decimal values may be used, provided that the +// compiler will convert from decimal to binary accurately enough +// to produce the hexadecimal values shown. +// +use super::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; + +const BP: [f64; 2] = [1.0, 1.5]; +const DP_H: [f64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ +const DP_L: [f64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ +const TWO53: f64 = 9007199254740992.0; /* 0x43400000_00000000 */ +const HUGE: f64 = 1.0e300; +const TINY: f64 = 1.0e-300; + +// poly coefs for (3/2)*(log(x)-2s-2/3*s**3: +const L1: f64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ +const L2: f64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ +const L3: f64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ +const L4: f64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ +const L5: f64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ +const L6: f64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ +const P1: f64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ +const P2: f64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ +const P3: f64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ +const P4: f64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ +const P5: f64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ +const LG2: f64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ +const LG2_H: f64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ +const LG2_L: f64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ +const OVT: f64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ +const CP: f64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ +const CP_H: f64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ +const CP_L: f64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ +const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ +const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ +const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ + +/// Returns `x` to the power of `y` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn pow(x: f64, y: f64) -> f64 { + let t1: f64; + let t2: f64; + + let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); + let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); + + let mut ix: i32 = hx & 0x7fffffff_i32; + let iy: i32 = hy & 0x7fffffff_i32; + + /* x**0 = 1, even if x is NaN */ + if ((iy as u32) | ly) == 0 { + return 1.0; + } + + /* 1**y = 1, even if y is NaN */ + if hx == 0x3ff00000 && lx == 0 { + return 1.0; + } + + /* NaN if either arg is NaN */ + if ix > 0x7ff00000 + || (ix == 0x7ff00000 && lx != 0) + || iy > 0x7ff00000 + || (iy == 0x7ff00000 && ly != 0) + { + return x + y; + } + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + let mut yisint: i32 = 0; + let mut k: i32; + let mut j: i32; + if hx < 0 { + if iy >= 0x43400000 { + yisint = 2; /* even integer y */ + } else if iy >= 0x3ff00000 { + k = (iy >> 20) - 0x3ff; /* exponent */ + + if k > 20 { + j = (ly >> (52 - k)) as i32; + + if (j << (52 - k)) == (ly as i32) { + yisint = 2 - (j & 1); + } + } else if ly == 0 { + j = iy >> (20 - k); + + if (j << (20 - k)) == iy { + yisint = 2 - (j & 1); + } + } + } + } + + if ly == 0 { + /* special value of y */ + if iy == 0x7ff00000 { + /* y is +-inf */ + + return if ((ix - 0x3ff00000) | (lx as i32)) == 0 { + /* (-1)**+-inf is 1 */ + 1.0 + } else if ix >= 0x3ff00000 { + /* (|x|>1)**+-inf = inf,0 */ + if hy >= 0 { y } else { 0.0 } + } else { + /* (|x|<1)**+-inf = 0,inf */ + if hy >= 0 { 0.0 } else { -y } + }; + } + + if iy == 0x3ff00000 { + /* y is +-1 */ + return if hy >= 0 { x } else { 1.0 / x }; + } + + if hy == 0x40000000 { + /* y is 2 */ + return x * x; + } + + if hy == 0x3fe00000 { + /* y is 0.5 */ + if hx >= 0 { + /* x >= +0 */ + return sqrt(x); + } + } + } + + let mut ax: f64 = fabs(x); + if lx == 0 { + /* special value of x */ + if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { + /* x is +-0,+-inf,+-1 */ + let mut z: f64 = ax; + + if hy < 0 { + /* z = (1/|x|) */ + z = 1.0 / z; + } + + if hx < 0 { + if ((ix - 0x3ff00000) | yisint) == 0 { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } else if yisint == 1 { + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + } + + return z; + } + } + + let mut s: f64 = 1.0; /* sign of result */ + if hx < 0 { + if yisint == 0 { + /* (x<0)**(non-int) is NaN */ + return (x - x) / (x - x); + } + + if yisint == 1 { + /* (x<0)**(odd int) */ + s = -1.0; + } + } + + /* |y| is HUGE */ + if iy > 0x41e00000 { + /* if |y| > 2**31 */ + if iy > 0x43f00000 { + /* if |y| > 2**64, must o/uflow */ + if ix <= 0x3fefffff { + return if hy < 0 { HUGE * HUGE } else { TINY * TINY }; + } + + if ix >= 0x3ff00000 { + return if hy > 0 { HUGE * HUGE } else { TINY * TINY }; + } + } + + /* over/underflow if x is not close to one */ + if ix < 0x3fefffff { + return if hy < 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + } + if ix > 0x3ff00000 { + return if hy > 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + } + + /* now |1-x| is TINY <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ + let w: f64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); + let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ + let v: f64 = t * IVLN2_L - w * IVLN2; + t1 = with_set_low_word(u + v, 0); + t2 = v - (t1 - u); + } else { + // double ss,s2,s_h,s_l,t_h,t_l; + let mut n: i32 = 0; + + if ix < 0x00100000 { + /* take care subnormal number */ + ax *= TWO53; + n -= 53; + ix = get_high_word(ax) as i32; + } + + n += (ix >> 20) - 0x3ff; + j = ix & 0x000fffff; + + /* determine interval */ + let k: i32; + ix = j | 0x3ff00000; /* normalize ix */ + if j <= 0x3988E { + /* |x|> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18), + ); + let t_l: f64 = ax - (t_h - i!(BP, k as usize)); + let s_l: f64 = v * ((u - s_h * t_h) - s_h * t_l); + + /* compute log(ax) */ + let s2: f64 = ss * ss; + let mut r: f64 = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); + r += s_l * (s_h + ss); + let s2: f64 = s_h * s_h; + let t_h: f64 = with_set_low_word(3.0 + s2 + r, 0); + let t_l: f64 = r - ((t_h - 3.0) - s2); + + /* u+v = ss*(1+...) */ + let u: f64 = s_h * t_h; + let v: f64 = s_l * t_h + t_l * ss; + + /* 2/(3log2)*(ss+...) */ + let p_h: f64 = with_set_low_word(u + v, 0); + let p_l = v - (p_h - u); + let z_h: f64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ + let z_l: f64 = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); + + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + let t: f64 = n as f64; + t1 = with_set_low_word(((z_h + z_l) + i!(DP_H, k as usize)) + t, 0); + t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + let y1: f64 = with_set_low_word(y, 0); + let p_l: f64 = (y - y1) * t1 + y * t2; + let mut p_h: f64 = y1 * t1; + let z: f64 = p_l + p_h; + let mut j: i32 = (z.to_bits() >> 32) as i32; + let i: i32 = z.to_bits() as i32; + // let (j, i): (i32, i32) = ((z.to_bits() >> 32) as i32, z.to_bits() as i32); + + if j >= 0x40900000 { + /* z >= 1024 */ + if (j - 0x40900000) | i != 0 { + /* if z > 1024 */ + return s * HUGE * HUGE; /* overflow */ + } + + if p_l + OVT > z - p_h { + return s * HUGE * HUGE; /* overflow */ + } + } else if (j & 0x7fffffff) >= 0x4090cc00 { + /* z <= -1075 */ + // FIXME: instead of abs(j) use unsigned j + + if (((j as u32) - 0xc090cc00) | (i as u32)) != 0 { + /* z < -1075 */ + return s * TINY * TINY; /* underflow */ + } + + if p_l <= z - p_h { + return s * TINY * TINY; /* underflow */ + } + } + + /* compute 2**(p_h+p_l) */ + let i: i32 = j & 0x7fffffff_i32; + k = (i >> 20) - 0x3ff; + let mut n: i32 = 0; + + if i > 0x3fe00000 { + /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00100000 >> (k + 1)); + k = ((n & 0x7fffffff) >> 20) - 0x3ff; /* new k for n */ + let t: f64 = with_set_high_word(0.0, (n & !(0x000fffff >> k)) as u32); + n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); + if j < 0 { + n = -n; + } + p_h -= t; + } + + let t: f64 = with_set_low_word(p_l + p_h, 0); + let u: f64 = t * LG2_H; + let v: f64 = (p_l - (t - p_h)) * LG2 + t * LG2_L; + let mut z: f64 = u + v; + let w: f64 = v - (z - u); + let t: f64 = z * z; + let t1: f64 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + let r: f64 = (z * t1) / (t1 - 2.0) - (w + z * w); + z = 1.0 - (r - z); + j = get_high_word(z) as i32; + j += n << 20; + + if (j >> 20) <= 0 { + /* subnormal output */ + z = scalbn(z, n); + } else { + z = with_set_high_word(z, j as u32); + } + + s * z +} + +#[cfg(test)] +mod tests { + extern crate core; + + use self::core::f64::consts::{E, PI}; + use super::pow; + + const POS_ZERO: &[f64] = &[0.0]; + const NEG_ZERO: &[f64] = &[-0.0]; + const POS_ONE: &[f64] = &[1.0]; + const NEG_ONE: &[f64] = &[-1.0]; + const POS_FLOATS: &[f64] = &[99.0 / 70.0, E, PI]; + const NEG_FLOATS: &[f64] = &[-99.0 / 70.0, -E, -PI]; + const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), f64::MIN_POSITIVE, f64::EPSILON]; + const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -f64::MIN_POSITIVE, -f64::EPSILON]; + const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, f64::MAX]; + const NEG_EVENS: &[f64] = &[f64::MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; + const POS_ODDS: &[f64] = &[3.0, 7.0]; + const NEG_ODDS: &[f64] = &[-7.0, -3.0]; + const NANS: &[f64] = &[f64::NAN]; + const POS_INF: &[f64] = &[f64::INFINITY]; + const NEG_INF: &[f64] = &[f64::NEG_INFINITY]; + + const ALL: &[&[f64]] = &[ + POS_ZERO, + NEG_ZERO, + NANS, + NEG_SMALL_FLOATS, + POS_SMALL_FLOATS, + NEG_FLOATS, + POS_FLOATS, + NEG_EVENS, + POS_EVENS, + NEG_ODDS, + POS_ODDS, + NEG_INF, + POS_INF, + NEG_ONE, + POS_ONE, + ]; + const POS: &[&[f64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF]; + const NEG: &[&[f64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF]; + + fn pow_test(base: f64, exponent: f64, expected: f64) { + let res = pow(base, exponent); + assert!( + if expected.is_nan() { res.is_nan() } else { pow(base, exponent) == expected }, + "{} ** {} was {} instead of {}", + base, + exponent, + res, + expected + ); + } + + fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { + sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); + } + + fn test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) { + sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); + } + + fn test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) { + sets.iter().for_each(|s| { + s.iter().for_each(|val| { + let exp = expected(*val); + let res = computed(*val); + + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let exp = force_eval!(exp); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let res = force_eval!(res); + assert!( + if exp.is_nan() { res.is_nan() } else { exp == res }, + "test for {} was {} instead of {}", + val, + res, + exp + ); + }) + }); + } + + #[test] + fn zero_as_exponent() { + test_sets_as_base(ALL, 0.0, 1.0); + test_sets_as_base(ALL, -0.0, 1.0); + } + + #[test] + fn one_as_base() { + test_sets_as_exponent(1.0, ALL, 1.0); + } + + #[test] + fn nan_inputs() { + // NAN as the base: + // (f64::NAN ^ anything *but 0* should be f64::NAN) + test_sets_as_exponent(f64::NAN, &ALL[2..], f64::NAN); + + // f64::NAN as the exponent: + // (anything *but 1* ^ f64::NAN should be f64::NAN) + test_sets_as_base(&ALL[..(ALL.len() - 2)], f64::NAN, f64::NAN); + } + + #[test] + fn infinity_as_base() { + // Positive Infinity as the base: + // (+Infinity ^ positive anything but 0 and f64::NAN should be +Infinity) + test_sets_as_exponent(f64::INFINITY, &POS[1..], f64::INFINITY); + + // (+Infinity ^ negative anything except 0 and f64::NAN should be 0.0) + test_sets_as_exponent(f64::INFINITY, &NEG[1..], 0.0); + + // Negative Infinity as the base: + // (-Infinity ^ positive odd ints should be -Infinity) + test_sets_as_exponent(f64::NEG_INFINITY, &[POS_ODDS], f64::NEG_INFINITY); + + // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) + // We can lump in pos/neg odd ints here because they don't seem to + // cause panics (div by zero) in release mode (I think). + test_sets(ALL, &|v: f64| pow(f64::NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); + } + + #[test] + fn infinity_as_exponent() { + // Positive/Negative base greater than 1: + // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes f64::NAN as the base) + test_sets_as_base(&ALL[5..(ALL.len() - 2)], f64::INFINITY, f64::INFINITY); + + // (pos/neg > 1 ^ -Infinity should be 0.0) + test_sets_as_base(&ALL[5..ALL.len() - 2], f64::NEG_INFINITY, 0.0); + + // Positive/Negative base less than 1: + let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS]; + + // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes f64::NAN as the base) + test_sets_as_base(base_below_one, f64::INFINITY, 0.0); + + // (pos/neg < 1 ^ -Infinity should be Infinity) + test_sets_as_base(base_below_one, f64::NEG_INFINITY, f64::INFINITY); + + // Positive/Negative 1 as the base: + // (pos/neg 1 ^ Infinity should be 1) + test_sets_as_base(&[NEG_ONE, POS_ONE], f64::INFINITY, 1.0); + + // (pos/neg 1 ^ -Infinity should be 1) + test_sets_as_base(&[NEG_ONE, POS_ONE], f64::NEG_INFINITY, 1.0); + } + + #[test] + fn zero_as_base() { + // Positive Zero as the base: + // (+0 ^ anything positive but 0 and f64::NAN should be +0) + test_sets_as_exponent(0.0, &POS[1..], 0.0); + + // (+0 ^ anything negative but 0 and f64::NAN should be Infinity) + // (this should panic because we're dividing by zero) + test_sets_as_exponent(0.0, &NEG[1..], f64::INFINITY); + + // Negative Zero as the base: + // (-0 ^ anything positive but 0, f64::NAN, and odd ints should be +0) + test_sets_as_exponent(-0.0, &POS[3..], 0.0); + + // (-0 ^ anything negative but 0, f64::NAN, and odd ints should be Infinity) + // (should panic because of divide by zero) + test_sets_as_exponent(-0.0, &NEG[3..], f64::INFINITY); + + // (-0 ^ positive odd ints should be -0) + test_sets_as_exponent(-0.0, &[POS_ODDS], -0.0); + + // (-0 ^ negative odd ints should be -Infinity) + // (should panic because of divide by zero) + test_sets_as_exponent(-0.0, &[NEG_ODDS], f64::NEG_INFINITY); + } + + #[test] + fn special_cases() { + // One as the exponent: + // (anything ^ 1 should be anything - i.e. the base) + test_sets(ALL, &|v: f64| pow(v, 1.0), &|v: f64| v); + + // Negative One as the exponent: + // (anything ^ -1 should be 1/anything) + test_sets(ALL, &|v: f64| pow(v, -1.0), &|v: f64| 1.0 / v); + + // Factoring -1 out: + // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) + [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| { + int_set.iter().for_each(|int| { + test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| pow(-1.0, *int) * pow(v, *int)); + }) + }); + + // Negative base (imaginary results): + // (-anything except 0 and Infinity ^ non-integer should be NAN) + NEG[1..(NEG.len() - 1)].iter().for_each(|set| { + set.iter().for_each(|val| { + test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| f64::NAN); + }) + }); + } + + #[test] + fn normal_cases() { + assert_eq!(pow(2.0, 20.0), (1 << 20) as f64); + assert_eq!(pow(-1.0, 9.0), -1.0); + assert!(pow(-1.0, 2.2).is_nan()); + assert!(pow(-1.0, -1.14).is_nan()); + } +} diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs new file mode 100644 index 00000000000..839c6c23d43 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -0,0 +1,335 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::cmp::Ordering; + +use super::{fabsf, scalbnf, sqrtf}; + +const BP: [f32; 2] = [1.0, 1.5]; +const DP_H: [f32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ +const DP_L: [f32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ +const TWO24: f32 = 16777216.0; /* 0x4b800000 */ +const HUGE: f32 = 1.0e30; +const TINY: f32 = 1.0e-30; +const L1: f32 = 6.0000002384e-01; /* 0x3f19999a */ +const L2: f32 = 4.2857143283e-01; /* 0x3edb6db7 */ +const L3: f32 = 3.3333334327e-01; /* 0x3eaaaaab */ +const L4: f32 = 2.7272811532e-01; /* 0x3e8ba305 */ +const L5: f32 = 2.3066075146e-01; /* 0x3e6c3255 */ +const L6: f32 = 2.0697501302e-01; /* 0x3e53f142 */ +const P1: f32 = 1.6666667163e-01; /* 0x3e2aaaab */ +const P2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const P3: f32 = 6.6137559770e-05; /* 0x388ab355 */ +const P4: f32 = -1.6533901999e-06; /* 0xb5ddea0e */ +const P5: f32 = 4.1381369442e-08; /* 0x3331bb4c */ +const LG2: f32 = 6.9314718246e-01; /* 0x3f317218 */ +const LG2_H: f32 = 6.93145752e-01; /* 0x3f317200 */ +const LG2_L: f32 = 1.42860654e-06; /* 0x35bfbe8c */ +const OVT: f32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ +const CP: f32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ +const CP_H: f32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ +const CP_L: f32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ +const IVLN2: f32 = 1.4426950216e+00; +const IVLN2_H: f32 = 1.4426879883e+00; +const IVLN2_L: f32 = 7.0526075433e-06; + +/// Returns `x` to the power of `y` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn powf(x: f32, y: f32) -> f32 { + let mut z: f32; + let mut ax: f32; + let z_h: f32; + let z_l: f32; + let mut p_h: f32; + let mut p_l: f32; + let y1: f32; + let mut t1: f32; + let t2: f32; + let mut r: f32; + let s: f32; + let mut sn: f32; + let mut t: f32; + let mut u: f32; + let mut v: f32; + let mut w: f32; + let i: i32; + let mut j: i32; + let mut k: i32; + let mut yisint: i32; + let mut n: i32; + let hx: i32; + let hy: i32; + let mut ix: i32; + let iy: i32; + let mut is: i32; + + hx = x.to_bits() as i32; + hy = y.to_bits() as i32; + + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if iy == 0 { + return 1.0; + } + + /* 1**y = 1, even if y is NaN */ + if hx == 0x3f800000 { + return 1.0; + } + + /* NaN if either arg is NaN */ + if ix > 0x7f800000 || iy > 0x7f800000 { + return x + y; + } + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if hx < 0 { + if iy >= 0x4b800000 { + yisint = 2; /* even integer y */ + } else if iy >= 0x3f800000 { + k = (iy >> 23) - 0x7f; /* exponent */ + j = iy >> (23 - k); + if (j << (23 - k)) == iy { + yisint = 2 - (j & 1); + } + } + } + + /* special value of y */ + if iy == 0x7f800000 { + /* y is +-inf */ + match ix.cmp(&0x3f800000) { + /* (-1)**+-inf is 1 */ + Ordering::Equal => return 1.0, + /* (|x|>1)**+-inf = inf,0 */ + Ordering::Greater => return if hy >= 0 { y } else { 0.0 }, + /* (|x|<1)**+-inf = 0,inf */ + Ordering::Less => return if hy >= 0 { 0.0 } else { -y }, + } + } + if iy == 0x3f800000 { + /* y is +-1 */ + return if hy >= 0 { x } else { 1.0 / x }; + } + + if hy == 0x40000000 { + /* y is 2 */ + return x * x; + } + + if hy == 0x3f000000 + /* y is 0.5 */ + && hx >= 0 + { + /* x >= +0 */ + return sqrtf(x); + } + + ax = fabsf(x); + /* special value of x */ + if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 { + /* x is +-0,+-inf,+-1 */ + z = ax; + if hy < 0 { + /* z = (1/|x|) */ + z = 1.0 / z; + } + + if hx < 0 { + if ((ix - 0x3f800000) | yisint) == 0 { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } else if yisint == 1 { + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + } + return z; + } + + sn = 1.0; /* sign of result */ + if hx < 0 { + if yisint == 0 { + /* (x<0)**(non-int) is NaN */ + return (x - x) / (x - x); + } + + if yisint == 1 { + /* (x<0)**(odd int) */ + sn = -1.0; + } + } + + /* |y| is HUGE */ + if iy > 0x4d000000 { + /* if |y| > 2**27 */ + /* over/underflow if x is not close to one */ + if ix < 0x3f7ffff8 { + return if hy < 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; + } + + if ix > 0x3f800007 { + return if hy > 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; + } + + /* now |1-x| is TINY <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1.; /* t has 20 trailing zeros */ + w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); + u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ + v = t * IVLN2_L - w * IVLN2; + t1 = u + v; + is = t1.to_bits() as i32; + t1 = f32::from_bits(is as u32 & 0xfffff000); + t2 = v - (t1 - u); + } else { + let mut s2: f32; + let mut s_h: f32; + let s_l: f32; + let mut t_h: f32; + let mut t_l: f32; + + n = 0; + /* take care subnormal number */ + if ix < 0x00800000 { + ax *= TWO24; + n -= 24; + ix = ax.to_bits() as i32; + } + n += ((ix) >> 23) - 0x7f; + j = ix & 0x007fffff; + /* determine interval */ + ix = j | 0x3f800000; /* normalize ix */ + if j <= 0x1cc471 { + /* |x|> 1) & 0xfffff000) | 0x20000000) as i32; + t_h = f32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); + t_l = ax - (t_h - i!(BP, k as usize)); + s_l = v * ((u - s_h * t_h) - s_h * t_l); + /* compute log(ax) */ + s2 = s * s; + r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); + r += s_l * (s_h + s); + s2 = s_h * s_h; + t_h = 3.0 + s2 + r; + is = t_h.to_bits() as i32; + t_h = f32::from_bits(is as u32 & 0xfffff000); + t_l = r - ((t_h - 3.0) - s2); + /* u+v = s*(1+...) */ + u = s_h * t_h; + v = s_l * t_h + t_l * s; + /* 2/(3log2)*(s+...) */ + p_h = u + v; + is = p_h.to_bits() as i32; + p_h = f32::from_bits(is as u32 & 0xfffff000); + p_l = v - (p_h - u); + z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = n as f32; + t1 = ((z_h + z_l) + i!(DP_H, k as usize)) + t; + is = t1.to_bits() as i32; + t1 = f32::from_bits(is as u32 & 0xfffff000); + t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); + }; + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + is = y.to_bits() as i32; + y1 = f32::from_bits(is as u32 & 0xfffff000); + p_l = (y - y1) * t1 + y * t2; + p_h = y1 * t1; + z = p_l + p_h; + j = z.to_bits() as i32; + if j > 0x43000000 { + /* if z > 128 */ + return sn * HUGE * HUGE; /* overflow */ + } else if j == 0x43000000 { + /* if z == 128 */ + if p_l + OVT > z - p_h { + return sn * HUGE * HUGE; /* overflow */ + } + } else if (j & 0x7fffffff) > 0x43160000 { + /* z < -150 */ + // FIXME: check should be (uint32_t)j > 0xc3160000 + return sn * TINY * TINY; /* underflow */ + } else if j as u32 == 0xc3160000 + /* z == -150 */ + && p_l <= z - p_h + { + return sn * TINY * TINY; /* underflow */ + } + + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i >> 23) - 0x7f; + n = 0; + if i > 0x3f000000 { + /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00800000 >> (k + 1)); + k = ((n & 0x7fffffff) >> 23) - 0x7f; /* new k for n */ + t = f32::from_bits(n as u32 & !(0x007fffff >> k)); + n = ((n & 0x007fffff) | 0x00800000) >> (23 - k); + if j < 0 { + n = -n; + } + p_h -= t; + } + t = p_l + p_h; + is = t.to_bits() as i32; + t = f32::from_bits(is as u32 & 0xffff8000); + u = t * LG2_H; + v = (p_l - (t - p_h)) * LG2 + t * LG2_L; + z = u + v; + w = v - (z - u); + t = z * z; + t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + r = (z * t1) / (t1 - 2.0) - (w + z * w); + z = 1.0 - (r - z); + j = z.to_bits() as i32; + j += n << 23; + if (j >> 23) <= 0 { + /* subnormal output */ + z = scalbnf(z, n); + } else { + z = f32::from_bits(j as u32); + } + sn * z +} diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs new file mode 100644 index 00000000000..917e90819a5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -0,0 +1,223 @@ +// origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== +// +// Optimized by Bruce D. Evans. */ +use super::rem_pio2_large; + +// #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +// #define EPS DBL_EPSILON +const EPS: f64 = 2.2204460492503131e-16; +// #elif FLT_EVAL_METHOD==2 +// #define EPS LDBL_EPSILON +// #endif + +// TODO: Support FLT_EVAL_METHOD? + +const TO_INT: f64 = 1.5 / EPS; +/// 53 bits of 2/pi +const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +/// first 33 bits of pi/2 +const PIO2_1: f64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ +/// pi/2 - PIO2_1 +const PIO2_1T: f64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ +/// second 33 bits of pi/2 +const PIO2_2: f64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ +/// pi/2 - (PIO2_1+PIO2_2) +const PIO2_2T: f64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ +/// third 33 bits of pi/2 +const PIO2_3: f64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ +/// pi/2 - (PIO2_1+PIO2_2+PIO2_3) +const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +// return the remainder of x rem pi/2 in y[0]+y[1] +// use rem_pio2_large() for large x +// +// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { + let x1p24 = f64::from_bits(0x4170000000000000); + + let sign = (f64::to_bits(x) >> 63) as i32; + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + fn medium(x: f64, ix: u32) -> (i32, f64, f64) { + /* rint(x/(pi/2)), Assume round-to-nearest. */ + let tmp = x * INV_PIO2 + TO_INT; + // force rounding of tmp to it's storage format on x87 to avoid + // excess precision issues. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let tmp = force_eval!(tmp); + let f_n = tmp - TO_INT; + let n = f_n as i32; + let mut r = x - f_n * PIO2_1; + let mut w = f_n * PIO2_1T; /* 1st round, good to 85 bits */ + let mut y0 = r - w; + let ui = f64::to_bits(y0); + let ey = (ui >> 52) as i32 & 0x7ff; + let ex = (ix >> 20) as i32; + if ex - ey > 16 { + /* 2nd round, good to 118 bits */ + let t = r; + w = f_n * PIO2_2; + r = t - w; + w = f_n * PIO2_2T - ((t - r) - w); + y0 = r - w; + let ey = (f64::to_bits(y0) >> 52) as i32 & 0x7ff; + if ex - ey > 49 { + /* 3rd round, good to 151 bits, covers all cases */ + let t = r; + w = f_n * PIO2_3; + r = t - w; + w = f_n * PIO2_3T - ((t - r) - w); + y0 = r - w; + } + } + let y1 = (r - y0) - w; + (n, y0, y1) + } + + if ix <= 0x400f6a7a { + /* |x| ~<= 5pi/4 */ + if (ix & 0xfffff) == 0x921fb { + /* |x| ~= pi/2 or 2pi/2 */ + return medium(x, ix); /* cancellation -- use medium case */ + } + if ix <= 0x4002d97c { + /* |x| ~<= 3pi/4 */ + if sign == 0 { + let z = x - PIO2_1; /* one round good to 85 bits */ + let y0 = z - PIO2_1T; + let y1 = (z - y0) - PIO2_1T; + return (1, y0, y1); + } else { + let z = x + PIO2_1; + let y0 = z + PIO2_1T; + let y1 = (z - y0) + PIO2_1T; + return (-1, y0, y1); + } + } else if sign == 0 { + let z = x - 2.0 * PIO2_1; + let y0 = z - 2.0 * PIO2_1T; + let y1 = (z - y0) - 2.0 * PIO2_1T; + return (2, y0, y1); + } else { + let z = x + 2.0 * PIO2_1; + let y0 = z + 2.0 * PIO2_1T; + let y1 = (z - y0) + 2.0 * PIO2_1T; + return (-2, y0, y1); + } + } + if ix <= 0x401c463b { + /* |x| ~<= 9pi/4 */ + if ix <= 0x4015fdbc { + /* |x| ~<= 7pi/4 */ + if ix == 0x4012d97c { + /* |x| ~= 3pi/2 */ + return medium(x, ix); + } + if sign == 0 { + let z = x - 3.0 * PIO2_1; + let y0 = z - 3.0 * PIO2_1T; + let y1 = (z - y0) - 3.0 * PIO2_1T; + return (3, y0, y1); + } else { + let z = x + 3.0 * PIO2_1; + let y0 = z + 3.0 * PIO2_1T; + let y1 = (z - y0) + 3.0 * PIO2_1T; + return (-3, y0, y1); + } + } else { + if ix == 0x401921fb { + /* |x| ~= 4pi/2 */ + return medium(x, ix); + } + if sign == 0 { + let z = x - 4.0 * PIO2_1; + let y0 = z - 4.0 * PIO2_1T; + let y1 = (z - y0) - 4.0 * PIO2_1T; + return (4, y0, y1); + } else { + let z = x + 4.0 * PIO2_1; + let y0 = z + 4.0 * PIO2_1T; + let y1 = (z - y0) + 4.0 * PIO2_1T; + return (-4, y0, y1); + } + } + } + if ix < 0x413921fb { + /* |x| ~< 2^20*(pi/2), medium size */ + return medium(x, ix); + } + /* + * all other (large) arguments + */ + if ix >= 0x7ff00000 { + /* x is inf or NaN */ + let y0 = x - x; + let y1 = y0; + return (0, y0, y1); + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + let mut ui = f64::to_bits(x); + ui &= (!1) >> 12; + ui |= (0x3ff + 23) << 52; + let mut z = f64::from_bits(ui); + let mut tx = [0.0; 3]; + for i in 0..2 { + i!(tx,i, =, z as i32 as f64); + z = (z - i!(tx, i)) * x1p24; + } + i!(tx,2, =, z); + /* skip zero terms, first term is non-zero */ + let mut i = 2; + while i != 0 && i!(tx, i) == 0.0 { + i -= 1; + } + let mut ty = [0.0; 3]; + let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix as i32) >> 20) - (0x3ff + 23), 1); + if sign != 0 { + return (-n, -i!(ty, 0), -i!(ty, 1)); + } + (n, i!(ty, 0), i!(ty, 1)) +} + +#[cfg(test)] +mod tests { + use super::rem_pio2; + + #[test] + // FIXME(correctness): inaccurate results on i586 + #[cfg_attr(all(target_arch = "x86", not(target_feature = "sse")), ignore)] + fn test_near_pi() { + let arg = 3.141592025756836; + let arg = force_eval!(arg); + assert_eq!(rem_pio2(arg), (2, -6.278329573009626e-7, -2.1125998133974653e-23)); + let arg = 3.141592033207416; + let arg = force_eval!(arg); + assert_eq!(rem_pio2(arg), (2, -6.20382377148128e-7, -2.1125998133974653e-23)); + let arg = 3.141592144966125; + let arg = force_eval!(arg); + assert_eq!(rem_pio2(arg), (2, -5.086236681942706e-7, -2.1125998133974653e-23)); + let arg = 3.141592979431152; + let arg = force_eval!(arg); + assert_eq!(rem_pio2(arg), (2, 3.2584135866119817e-7, -2.1125998133974653e-23)); + } + + #[test] + fn test_overflow_b9b847() { + let _ = rem_pio2(-3054214.5490637687); + } + + #[test] + fn test_overflow_4747b9() { + let _ = rem_pio2(917340800458.2274); + } +} diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs new file mode 100644 index 00000000000..6d679bbe98c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -0,0 +1,468 @@ +#![allow(unused_unsafe)] +/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{floor, scalbn}; + +// initial value for jk +const INIT_JK: [usize; 4] = [3, 4, 4, 6]; + +// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi +// +// integer array, contains the (24*i)-th to (24*i+23)-th +// bit of 2/pi after binary point. The corresponding +// floating value is +// +// ipio2[i] * 2^(-24(i+1)). +// +// NB: This table must have at least (e0-3)/24 + jk terms. +// For quad precision (e0 <= 16360, jk = 6), this is 686. +#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] +const IPIO2: [i32; 66] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, + 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, + 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, + 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, + 0x73A8C9, 0x60E27B, 0xC08C6B, +]; + +#[cfg(target_pointer_width = "64")] +const IPIO2: [i32; 690] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, + 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, + 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, + 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, + 0x73A8C9, 0x60E27B, 0xC08C6B, 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, + 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, 0xDE4F98, 0x327DBB, 0xC33D26, + 0xEF6B1E, 0x5EF89F, 0x3A1F35, 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, + 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, 0x467D86, 0x2D71E3, 0x9AC69B, + 0x006233, 0x7CD2B4, 0x97A7B4, 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, + 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, 0xCB2324, 0x778AD6, 0x23545A, + 0xB91F00, 0x1B0AF1, 0xDFCE19, 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, + 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, 0xDE3B58, 0x929BDE, 0x2822D2, + 0xE88628, 0x4D58E2, 0x32CAC6, 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, + 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, 0xD36710, 0xD8DDAA, 0x425FAE, + 0xCE616A, 0xA4280A, 0xB499D3, 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, + 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, 0x36D9CA, 0xD2A828, 0x8D61C2, + 0x77C912, 0x142604, 0x9B4612, 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, + 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, 0xC3E7B3, 0x28F8C7, 0x940593, + 0x3E71C1, 0xB3092E, 0xF3450B, 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, + 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, 0x9794E8, 0x84E6E2, 0x973199, + 0x6BED88, 0x365F5F, 0x0EFDBB, 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, + 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, 0x90AA47, 0x02E774, 0x24D6BD, + 0xA67DF7, 0x72486E, 0xEF169F, 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, + 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, 0x10D86D, 0x324832, 0x754C5B, + 0xD4714E, 0x6E5445, 0xC1090B, 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, + 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, 0x6AE290, 0x89D988, 0x50722C, + 0xBEA404, 0x940777, 0x7030F3, 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, + 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, 0x3BDF08, 0x2B3715, 0xA0805C, + 0x93805A, 0x921110, 0xD8E80F, 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, + 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, 0xAA140A, 0x2F2689, 0x768364, + 0x333B09, 0x1A940E, 0xAA3A51, 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, + 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, 0x5BC3D8, 0xC492F5, 0x4BADC6, + 0xA5CA4E, 0xCD37A7, 0x36A9E6, 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, + 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, 0x306529, 0xBF5657, 0x3AFF47, + 0xB9F96A, 0xF3BE75, 0xDF9328, 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, + 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, 0xA8654F, 0xA5C1D2, 0x0F3F0B, + 0xCD785B, 0x76F923, 0x048B7B, 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, + 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, 0xDA4886, 0xA05DF7, 0xF480C6, + 0x2FF0AC, 0x9AECDD, 0xBC5C3F, 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, + 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, 0x2A1216, 0x2DB7DC, 0xFDE5FA, + 0xFEDB89, 0xFDBE89, 0x6C76E4, 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, + 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, 0x48D784, 0x16DF30, 0x432DC7, + 0x356125, 0xCE70C9, 0xB8CB30, 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, + 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, 0xC4F133, 0x5F6E13, 0xE4305D, + 0xA92E85, 0xC3B21D, 0x3632A1, 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, + 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, 0xCBDA11, 0xD0BE7D, 0xC1DB9B, + 0xBD17AB, 0x81A2CA, 0x5C6A08, 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, + 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, 0x4F6A68, 0xA82A4A, 0x5AC44F, + 0xBCF82D, 0x985AD7, 0x95C7F4, 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, + 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, 0xD0C0B2, 0x485551, 0x0EFB1E, + 0xC37295, 0x3B06A3, 0x3540C0, 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, + 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, 0x3C3ABA, 0x461846, 0x5F7555, + 0xF5BDD2, 0xC6926E, 0x5D2EAC, 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, + 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, 0x745D7C, 0xB2AD6B, 0x9D6ECD, + 0x7B723E, 0x6A11C6, 0xA9CFF7, 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, + 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, 0xBEFDFD, 0xEF4556, 0x367ED9, + 0x13D9EC, 0xB9BA8B, 0xFC97C4, 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, + 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, 0x9C2A3E, 0xCC5F11, 0x4A0BFD, + 0xFBF4E1, 0x6D3B8E, 0x2C86E2, 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, + 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, 0xCC2254, 0xDC552A, 0xD6C6C0, + 0x96190B, 0xB8701A, 0x649569, 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, + 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, 0x9B5861, 0xBC57E1, 0xC68351, + 0x103ED8, 0x4871DD, 0xDD1C2D, 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, + 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, 0x382682, 0x9BE7CA, 0xA40D51, + 0xB13399, 0x0ED7A9, 0x480569, 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, + 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, 0x5FD45E, 0xA4677B, 0x7AACBA, + 0xA2F655, 0x23882B, 0x55BA41, 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, + 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, 0xAE5ADB, 0x86C547, 0x624385, + 0x3B8621, 0x94792C, 0x876110, 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, + 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, 0xB1933D, 0x0B7CBD, 0xDC51A4, + 0x63DD27, 0xDDE169, 0x19949A, 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, + 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, 0x4D7E6F, 0x5119A5, 0xABF9B5, + 0xD6DF82, 0x61DD96, 0x023616, 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, + 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, +]; + +const PIO2: [f64; 8] = [ + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +]; + +// fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 +// +// Input parameters: +// x[] The input value (must be positive) is broken into nx +// pieces of 24-bit integers in double precision format. +// x[i] will be the i-th 24 bit of x. The scaled exponent +// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 +// match x's up to 24 bits. +// +// Example of breaking a double positive z into x[0]+x[1]+x[2]: +// e0 = ilogb(z)-23 +// z = scalbn(z,-e0) +// for i = 0,1,2 +// x[i] = floor(z) +// z = (z-x[i])*2**24 +// +// y[] ouput result in an array of double precision numbers. +// The dimension of y[] is: +// 24-bit precision 1 +// 53-bit precision 2 +// 64-bit precision 2 +// 113-bit precision 3 +// The actual value is the sum of them. Thus for 113-bit +// precison, one may have to do something like: +// +// long double t,w,r_head, r_tail; +// t = (long double)y[2] + (long double)y[1]; +// w = (long double)y[0]; +// r_head = t+w; +// r_tail = w - (r_head - t); +// +// e0 The exponent of x[0]. Must be <= 16360 or you need to +// expand the ipio2 table. +// +// prec an integer indicating the precision: +// 0 24 bits (single) +// 1 53 bits (double) +// 2 64 bits (extended) +// 3 113 bits (quad) +// +// Here is the description of some local variables: +// +// jk jk+1 is the initial number of terms of ipio2[] needed +// in the computation. The minimum and recommended value +// for jk is 3,4,4,6 for single, double, extended, and quad. +// jk+1 must be 2 larger than you might expect so that our +// recomputation test works. (Up to 24 bits in the integer +// part (the 24 bits of it that we compute) and 23 bits in +// the fraction part may be lost to cancelation before we +// recompute.) +// +// jz local integer variable indicating the number of +// terms of ipio2[] used. +// +// jx nx - 1 +// +// jv index for pointing to the suitable ipio2[] for the +// computation. In general, we want +// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 +// is an integer. Thus +// e0-3-24*jv >= 0 or (e0-3)/24 >= jv +// Hence jv = max(0,(e0-3)/24). +// +// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. +// +// q[] double array with integral value, representing the +// 24-bits chunk of the product of x and 2/pi. +// +// q0 the corresponding exponent of q[0]. Note that the +// exponent for q[i] would be q0-24*i. +// +// PIo2[] double precision array, obtained by cutting pi/2 +// into 24 bits chunks. +// +// f[] ipio2[] in floating point +// +// iq[] integer array by breaking up q[] in 24-bits chunk. +// +// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] +// +// ih integer. If >0 it indicates q[] is >= 0.5, hence +// it also indicates the *sign* of the result. + +/// Return the last three digits of N with y = x - N*pi/2 +/// so that |y| < pi/2. +/// +/// The method is to compute the integer (mod 8) and fraction parts of +/// (2/pi)*x without doing the full multiplication. In general we +/// skip the part of the product that are known to be a huge integer ( +/// more accurately, = 0 mod 8 ). Thus the number of operations are +/// independent of the exponent of the input. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { + let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 + let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) + + if cfg!(target_pointer_width = "64") { + debug_assert!(e0 <= 16360); + } + + let nx = x.len(); + + let mut fw: f64; + let mut n: i32; + let mut ih: i32; + let mut z: f64; + let mut f: [f64; 20] = [0.; 20]; + let mut fq: [f64; 20] = [0.; 20]; + let mut q: [f64; 20] = [0.; 20]; + let mut iq: [i32; 20] = [0; 20]; + + /* initialize jk*/ + let jk = i!(INIT_JK, prec); + let jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + let jx = nx - 1; + let mut jv = div!(e0 - 3, 24); + if jv < 0 { + jv = 0; + } + let mut q0 = e0 - 24 * (jv + 1); + let jv = jv as usize; + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + let mut j = (jv as i32) - (jx as i32); + let m = jx + jk; + for i in 0..=m { + i!(f, i, =, if j < 0 { + 0. + } else { + i!(IPIO2, j as usize) as f64 + }); + j += 1; + } + + /* compute q[0],q[1],...q[jk] */ + for i in 0..=jk { + fw = 0f64; + for j in 0..=jx { + fw += i!(x, j) * i!(f, jx + i - j); + } + i!(q, i, =, fw); + } + + let mut jz = jk; + + 'recompute: loop { + /* distill q[] into iq[] reversingly */ + let mut i = 0i32; + z = i!(q, jz); + for j in (1..=jz).rev() { + fw = (x1p_24 * z) as i32 as f64; + i!(iq, i as usize, =, (z - x1p24 * fw) as i32); + z = i!(q, j - 1) + fw; + i += 1; + } + + /* compute n */ + z = scalbn(z, q0); /* actual value of z */ + z -= 8.0 * floor(z * 0.125); /* trim off integer >= 8 */ + n = z as i32; + z -= n as f64; + ih = 0; + if q0 > 0 { + /* need iq[jz-1] to determine n */ + i = i!(iq, jz - 1) >> (24 - q0); + n += i; + i!(iq, jz - 1, -=, i << (24 - q0)); + ih = i!(iq, jz - 1) >> (23 - q0); + } else if q0 == 0 { + ih = i!(iq, jz - 1) >> 23; + } else if z >= 0.5 { + ih = 2; + } + + if ih > 0 { + /* q > 0.5 */ + n += 1; + let mut carry = 0i32; + for i in 0..jz { + /* compute 1-q */ + let j = i!(iq, i); + if carry == 0 { + if j != 0 { + carry = 1; + i!(iq, i, =, 0x1000000 - j); + } + } else { + i!(iq, i, =, 0xffffff - j); + } + } + if q0 > 0 { + /* rare case: chance is 1 in 12 */ + match q0 { + 1 => { + i!(iq, jz - 1, &=, 0x7fffff); + } + 2 => { + i!(iq, jz - 1, &=, 0x3fffff); + } + _ => {} + } + } + if ih == 2 { + z = 1. - z; + if carry != 0 { + z -= scalbn(1., q0); + } + } + } + + /* check if recomputation is needed */ + if z == 0. { + let mut j = 0; + for i in (jk..=jz - 1).rev() { + j |= i!(iq, i); + } + if j == 0 { + /* need recomputation */ + let mut k = 1; + while i!(iq, jk - k, ==, 0) { + k += 1; /* k = no. of terms needed */ + } + + for i in (jz + 1)..=(jz + k) { + /* add q[jz+1] to q[jz+k] */ + i!(f, jx + i, =, i!(IPIO2, jv + i) as f64); + fw = 0f64; + for j in 0..=jx { + fw += i!(x, j) * i!(f, jx + i - j); + } + i!(q, i, =, fw); + } + jz += k; + continue 'recompute; + } + } + + break; + } + + /* chop off zero terms */ + if z == 0. { + jz -= 1; + q0 -= 24; + while i!(iq, jz) == 0 { + jz -= 1; + q0 -= 24; + } + } else { + /* break z into 24-bit if necessary */ + z = scalbn(z, -q0); + if z >= x1p24 { + fw = (x1p_24 * z) as i32 as f64; + i!(iq, jz, =, (z - x1p24 * fw) as i32); + jz += 1; + q0 += 24; + i!(iq, jz, =, fw as i32); + } else { + i!(iq, jz, =, z as i32); + } + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(1., q0); + for i in (0..=jz).rev() { + i!(q, i, =, fw * (i!(iq, i) as f64)); + fw *= x1p_24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for i in (0..=jz).rev() { + fw = 0f64; + let mut k = 0; + while (k <= jp) && (k <= jz - i) { + fw += i!(PIO2, k) * i!(q, i + k); + k += 1; + } + i!(fq, jz - i, =, fw); + } + + /* compress fq[] into y[] */ + match prec { + 0 => { + fw = 0f64; + for i in (0..=jz).rev() { + fw += i!(fq, i); + } + i!(y, 0, =, if ih == 0 { fw } else { -fw }); + } + 1 | 2 => { + fw = 0f64; + for i in (0..=jz).rev() { + fw += i!(fq, i); + } + i!(y, 0, =, if ih == 0 { fw } else { -fw }); + fw = i!(fq, 0) - fw; + for i in 1..=jz { + fw += i!(fq, i); + } + i!(y, 1, =, if ih == 0 { fw } else { -fw }); + } + 3 => { + /* painful */ + for i in (1..=jz).rev() { + fw = i!(fq, i - 1) + i!(fq, i); + i!(fq, i, +=, i!(fq, i - 1) - fw); + i!(fq, i - 1, =, fw); + } + for i in (2..=jz).rev() { + fw = i!(fq, i - 1) + i!(fq, i); + i!(fq, i, +=, i!(fq, i - 1) - fw); + i!(fq, i - 1, =, fw); + } + fw = 0f64; + for i in (2..=jz).rev() { + fw += i!(fq, i); + } + if ih == 0 { + i!(y, 0, =, i!(fq, 0)); + i!(y, 1, =, i!(fq, 1)); + i!(y, 2, =, fw); + } else { + i!(y, 0, =, -i!(fq, 0)); + i!(y, 1, =, -i!(fq, 1)); + i!(y, 2, =, -fw); + } + } + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => {} + } + n & 7 +} diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs new file mode 100644 index 00000000000..3c658fe3dbc --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -0,0 +1,67 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f64; + +use super::rem_pio2_large; + +const TOINT: f64 = 1.5 / f64::EPSILON; + +/// 53 bits of 2/pi +const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +/// first 25 bits of pi/2 +const PIO2_1: f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ +/// pi/2 - pio2_1 +const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + +/// Return the remainder of x rem pi/2 in *y +/// +/// use double precision for everything except passing x +/// use __rem_pio2_large() for large x +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { + let x64 = x as f64; + + let mut tx: [f64; 1] = [0.]; + let mut ty: [f64; 1] = [0.]; + + let ix = x.to_bits() & 0x7fffffff; + /* 25+53 bit pi is good enough for medium size */ + if ix < 0x4dc90fdb { + /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + let tmp = x64 * INV_PIO2 + TOINT; + // force rounding of tmp to it's storage format on x87 to avoid + // excess precision issues. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let tmp = force_eval!(tmp); + let f_n = tmp - TOINT; + return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); + } + if ix >= 0x7f800000 { + /* x is inf or NaN */ + return (0, x64 - x64); + } + /* scale x into [2^23, 2^24-1] */ + let sign = (x.to_bits() >> 31) != 0; + let e0 = ((ix >> 23) - (0x7f + 23)) as i32; /* e0 = ilogb(|x|)-23, positive */ + tx[0] = f32::from_bits(ix - (e0 << 23) as u32) as f64; + let n = rem_pio2_large(&tx, &mut ty, e0, 0); + if sign { + return (-n, -ty[0]); + } + (n, ty[0]) +} diff --git a/library/compiler-builtins/libm/src/math/remainder.rs b/library/compiler-builtins/libm/src/math/remainder.rs new file mode 100644 index 00000000000..9e966c9ed7f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/remainder.rs @@ -0,0 +1,5 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remainder(x: f64, y: f64) -> f64 { + let (result, _) = super::remquo(x, y); + result +} diff --git a/library/compiler-builtins/libm/src/math/remainderf.rs b/library/compiler-builtins/libm/src/math/remainderf.rs new file mode 100644 index 00000000000..b1407cf2ace --- /dev/null +++ b/library/compiler-builtins/libm/src/math/remainderf.rs @@ -0,0 +1,5 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remainderf(x: f32, y: f32) -> f32 { + let (result, _) = super::remquof(x, y); + result +} diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs new file mode 100644 index 00000000000..4c11e848746 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -0,0 +1,106 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { + let ux: u64 = x.to_bits(); + let mut uy: u64 = y.to_bits(); + let mut ex = ((ux >> 52) & 0x7ff) as i32; + let mut ey = ((uy >> 52) & 0x7ff) as i32; + let sx = (ux >> 63) != 0; + let sy = (uy >> 63) != 0; + let mut q: u32; + let mut i: u64; + let mut uxi: u64 = ux; + + if (uy << 1) == 0 || y.is_nan() || ex == 0x7ff { + return ((x * y) / (x * y), 0); + } + if (ux << 1) == 0 { + return (x, 0); + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 12; + while (i >> 63) == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= (!0) >> 12; + uxi |= 1 << 52; + } + if ey == 0 { + i = uy << 12; + while (i >> 63) == 0 { + ey -= 1; + i <<= 1; + } + uy <<= -ey + 1; + } else { + uy &= (!0) >> 12; + uy |= 1 << 52; + } + + q = 0; + + if ex + 1 != ey { + if ex < ey { + return (x, 0); + } + /* x mod y */ + while ex > ey { + i = uxi.wrapping_sub(uy); + if (i >> 63) == 0 { + uxi = i; + q += 1; + } + uxi <<= 1; + q <<= 1; + ex -= 1; + } + i = uxi.wrapping_sub(uy); + if (i >> 63) == 0 { + uxi = i; + q += 1; + } + if uxi == 0 { + ex = -60; + } else { + while (uxi >> 52) == 0 { + uxi <<= 1; + ex -= 1; + } + } + } + + /* scale result and decide between |x| and |x|-|y| */ + if ex > 0 { + uxi -= 1 << 52; + uxi |= (ex as u64) << 52; + } else { + uxi >>= -ex + 1; + } + x = f64::from_bits(uxi); + if sy { + y = -y; + } + if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { + x -= y; + // TODO: this matches musl behavior, but it is incorrect + q = q.wrapping_add(1); + } + q &= 0x7fffffff; + let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; + if sx { (-x, quo) } else { (x, quo) } +} + +#[cfg(test)] +mod tests { + use super::remquo; + + #[test] + fn test_q_overflow() { + // 0xc000000000000001, 0x04c0000000000004 + let _ = remquo(-2.0000000000000004, 8.406091369059082e-286); + } +} diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs new file mode 100644 index 00000000000..b0e85ca6611 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/remquof.rs @@ -0,0 +1,93 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { + let ux: u32 = x.to_bits(); + let mut uy: u32 = y.to_bits(); + let mut ex = ((ux >> 23) & 0xff) as i32; + let mut ey = ((uy >> 23) & 0xff) as i32; + let sx = (ux >> 31) != 0; + let sy = (uy >> 31) != 0; + let mut q: u32; + let mut i: u32; + let mut uxi: u32 = ux; + + if (uy << 1) == 0 || y.is_nan() || ex == 0xff { + return ((x * y) / (x * y), 0); + } + if (ux << 1) == 0 { + return (x, 0); + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 9; + while (i >> 31) == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= (!0) >> 9; + uxi |= 1 << 23; + } + if ey == 0 { + i = uy << 9; + while (i >> 31) == 0 { + ey -= 1; + i <<= 1; + } + uy <<= -ey + 1; + } else { + uy &= (!0) >> 9; + uy |= 1 << 23; + } + + q = 0; + if ex + 1 != ey { + if ex < ey { + return (x, 0); + } + /* x mod y */ + while ex > ey { + i = uxi.wrapping_sub(uy); + if (i >> 31) == 0 { + uxi = i; + q += 1; + } + uxi <<= 1; + q <<= 1; + ex -= 1; + } + i = uxi.wrapping_sub(uy); + if (i >> 31) == 0 { + uxi = i; + q += 1; + } + if uxi == 0 { + ex = -30; + } else { + while (uxi >> 23) == 0 { + uxi <<= 1; + ex -= 1; + } + } + } + + /* scale result and decide between |x| and |x|-|y| */ + if ex > 0 { + uxi -= 1 << 23; + uxi |= (ex as u32) << 23; + } else { + uxi >>= -ex + 1; + } + x = f32::from_bits(uxi); + if sy { + y = -y; + } + if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { + x -= y; + q += 1; + } + q &= 0x7fffffff; + let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; + if sx { (-x, quo) } else { (x, quo) } +} diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs new file mode 100644 index 00000000000..e1c32c94355 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -0,0 +1,51 @@ +use super::support::Round; + +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf16(x: f16) -> f16 { + select_implementation! { + name: rintf16, + use_arch: all(target_arch = "aarch64", target_feature = "fp16"), + args: x, + } + + super::generic::rint_round(x, Round::Nearest).val +} + +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf(x: f32) -> f32 { + select_implementation! { + name: rintf, + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + all(target_arch = "wasm32", intrinsics_enabled), + ), + args: x, + } + + super::generic::rint_round(x, Round::Nearest).val +} + +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rint(x: f64) -> f64 { + select_implementation! { + name: rint, + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + all(target_arch = "wasm32", intrinsics_enabled), + ), + args: x, + } + + super::generic::rint_round(x, Round::Nearest).val +} + +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf128(x: f128) -> f128 { + super::generic::rint_round(x, Round::Nearest).val +} diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs new file mode 100644 index 00000000000..6cd091cd73c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -0,0 +1,25 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf16(x: f16) -> f16 { + super::generic::round(x) +} + +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf(x: f32) -> f32 { + super::generic::round(x) +} + +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn round(x: f64) -> f64 { + super::generic::round(x) +} + +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf128(x: f128) -> f128 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/src/math/roundeven.rs new file mode 100644 index 00000000000..6e621d7628f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundeven.rs @@ -0,0 +1,36 @@ +use super::support::{Float, Round}; + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf16(x: f16) -> f16 { + roundeven_impl(x) +} + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf(x: f32) -> f32 { + roundeven_impl(x) +} + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundeven(x: f64) -> f64 { + roundeven_impl(x) +} + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf128(x: f128) -> f128 { + roundeven_impl(x) +} + +#[inline] +pub fn roundeven_impl(x: F) -> F { + super::generic::rint_round(x, Round::Nearest).val +} diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs new file mode 100644 index 00000000000..b5d7c9d693e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf(x: f32) -> f32 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/src/math/roundf128.rs b/library/compiler-builtins/libm/src/math/roundf128.rs new file mode 100644 index 00000000000..fc3164929fe --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundf128.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf128(x: f128) -> f128 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/src/math/roundf16.rs b/library/compiler-builtins/libm/src/math/roundf16.rs new file mode 100644 index 00000000000..8b356eaabee --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundf16.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf16(x: f16) -> f16 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs new file mode 100644 index 00000000000..ed73c3f94f0 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -0,0 +1,87 @@ +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf16(x: f16, n: i32) -> f16 { + super::generic::scalbn(x, n) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf(x: f32, n: i32) -> f32 { + super::generic::scalbn(x, n) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbn(x: f64, n: i32) -> f64 { + super::generic::scalbn(x, n) +} + +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf128(x: f128, n: i32) -> f128 { + super::generic::scalbn(x, n) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{CastFrom, CastInto, Float}; + + // Tests against N3220 + fn spec_test(f: impl Fn(F, i32) -> F) + where + u32: CastInto, + F::Int: CastFrom, + F::Int: CastFrom, + { + // `scalbn(±0, n)` returns `±0`. + assert_biteq!(f(F::NEG_ZERO, 10), F::NEG_ZERO); + assert_biteq!(f(F::NEG_ZERO, 0), F::NEG_ZERO); + assert_biteq!(f(F::NEG_ZERO, -10), F::NEG_ZERO); + assert_biteq!(f(F::ZERO, 10), F::ZERO); + assert_biteq!(f(F::ZERO, 0), F::ZERO); + assert_biteq!(f(F::ZERO, -10), F::ZERO); + + // `scalbn(x, 0)` returns `x`. + assert_biteq!(f(F::MIN, 0), F::MIN); + assert_biteq!(f(F::MAX, 0), F::MAX); + assert_biteq!(f(F::INFINITY, 0), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY, 0), F::NEG_INFINITY); + assert_biteq!(f(F::ZERO, 0), F::ZERO); + assert_biteq!(f(F::NEG_ZERO, 0), F::NEG_ZERO); + + // `scalbn(±∞, n)` returns `±∞`. + assert_biteq!(f(F::INFINITY, 10), F::INFINITY); + assert_biteq!(f(F::INFINITY, -10), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY, 10), F::NEG_INFINITY); + assert_biteq!(f(F::NEG_INFINITY, -10), F::NEG_INFINITY); + + // NaN should remain NaNs. + assert!(f(F::NAN, 10).is_nan()); + assert!(f(F::NAN, 0).is_nan()); + assert!(f(F::NAN, -10).is_nan()); + assert!(f(-F::NAN, 10).is_nan()); + assert!(f(-F::NAN, 0).is_nan()); + assert!(f(-F::NAN, -10).is_nan()); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_test_f16() { + spec_test::(scalbnf16); + } + + #[test] + fn spec_test_f32() { + spec_test::(scalbnf); + } + + #[test] + fn spec_test_f64() { + spec_test::(scalbn); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_test_f128() { + spec_test::(scalbnf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs new file mode 100644 index 00000000000..57e7ba76f60 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/scalbnf.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf(x: f32, n: i32) -> f32 { + super::generic::scalbn(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/scalbnf128.rs b/library/compiler-builtins/libm/src/math/scalbnf128.rs new file mode 100644 index 00000000000..c1d2b485585 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/scalbnf128.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf128(x: f128, n: i32) -> f128 { + super::generic::scalbn(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/scalbnf16.rs b/library/compiler-builtins/libm/src/math/scalbnf16.rs new file mode 100644 index 00000000000..2209e1a1795 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/scalbnf16.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf16(x: f16, n: i32) -> f16 { + super::generic::scalbn(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs new file mode 100644 index 00000000000..229fa4bef08 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -0,0 +1,95 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +use super::{k_cos, k_sin, rem_pio2}; + +// sin(x) +// Return sine function of x. +// +// kernel function: +// k_sin ... sine function on [-pi/4,pi/4] +// k_cos ... cose function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded + +/// The sine of `x` (f64). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sin(x: f64) -> f64 { + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 + + /* High word of x. */ + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e500000 { + /* |x| < 2**-26 */ + /* raise inexact if x != 0 and underflow if subnormal*/ + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return x; + } + return k_sin(x, 0.0, 0); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + match n & 3 { + 0 => k_sin(y0, y1, 1), + 1 => k_cos(y0, y1), + 2 => -k_sin(y0, y1, 1), + _ => -k_cos(y0, y1), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg_attr(x86_no_sse, ignore = "FIXME(i586): possible incorrect rounding")] + fn test_near_pi() { + let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 + let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 + assert_eq!(sin(x), sx); + } +} diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs new file mode 100644 index 00000000000..ebf482f2df3 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -0,0 +1,137 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{get_high_word, k_cos, k_sin, rem_pio2}; + +/// Both the sine and cosine of `x` (f64). +/// +/// `x` is specified in radians and the return value is (sin(x), cos(x)). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sincos(x: f64) -> (f64, f64) { + let s: f64; + let c: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + /* if |x| < 2**-27 * sqrt(2) */ + if ix < 0x3e46a09e { + /* raise inexact if x!=0 and underflow if subnormal */ + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return (x, 1.0); + } + return (k_sin(x, 0.0, 0), k_cos(x, 0.0)); + } + + /* sincos(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + let rv = x - x; + return (rv, rv); + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + s = k_sin(y0, y1, 1); + c = k_cos(y0, y1); + match n & 3 { + 0 => (s, c), + 1 => (c, -s), + 2 => (-s, -c), + 3 => (-c, s), + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => (0.0, 1.0), + } +} + +// These tests are based on those from sincosf.rs +#[cfg(test)] +mod tests { + use super::sincos; + + const TOLERANCE: f64 = 1e-6; + + #[test] + fn with_pi() { + let (s, c) = sincos(core::f64::consts::PI); + assert!( + (s - 0.0).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + 0.0, + (s - 0.0).abs(), + TOLERANCE + ); + assert!( + (c + 1.0).abs() < TOLERANCE, + "|{} + {}| = {} >= {}", + c, + 1.0, + (s + 1.0).abs(), + TOLERANCE + ); + } + + #[test] + fn rotational_symmetry() { + use core::f64::consts::PI; + const N: usize = 24; + for n in 0..N { + let theta = 2. * PI * (n as f64) / (N as f64); + let (s, c) = sincos(theta); + let (s_plus, c_plus) = sincos(theta + 2. * PI); + let (s_minus, c_minus) = sincos(theta - 2. * PI); + + assert!( + (s - s_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_plus, + (s - s_plus).abs(), + TOLERANCE + ); + assert!( + (s - s_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_minus, + (s - s_minus).abs(), + TOLERANCE + ); + assert!( + (c - c_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_plus, + (c - c_plus).abs(), + TOLERANCE + ); + assert!( + (c - c_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_minus, + (c - c_minus).abs(), + TOLERANCE + ); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs new file mode 100644 index 00000000000..f3360767683 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -0,0 +1,176 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{k_cosf, k_sinf, rem_pio2f}; + +/* Small multiples of pi/2 rounded to double precision. */ +const PI_2: f64 = 0.5 * 3.1415926535897931160E+00; +const S1PIO2: f64 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2PIO2: f64 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ +const S3PIO2: f64 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4PIO2: f64 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ + +/// Both the sine and cosine of `x` (f32). +/// +/// `x` is specified in radians and the return value is (sin(x), cos(x)). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sincosf(x: f32) -> (f32, f32) { + let s: f32; + let c: f32; + let mut ix: u32; + let sign: bool; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + /* |x| ~<= pi/4 */ + if ix <= 0x3f490fda { + /* |x| < 2**-12 */ + if ix < 0x39800000 { + /* raise inexact if x!=0 and underflow if subnormal */ + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120 == 2^120 + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return (x, 1.0); + } + return (k_sinf(x as f64), k_cosf(x as f64)); + } + + /* |x| ~<= 5*pi/4 */ + if ix <= 0x407b53d1 { + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + if sign { + s = -k_cosf(x as f64 + S1PIO2); + c = k_sinf(x as f64 + S1PIO2); + } else { + s = k_cosf(S1PIO2 - x as f64); + c = k_sinf(S1PIO2 - x as f64); + } + } + /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ + else if sign { + s = -k_sinf(x as f64 + S2PIO2); + c = -k_cosf(x as f64 + S2PIO2); + } else { + s = -k_sinf(x as f64 - S2PIO2); + c = -k_cosf(x as f64 - S2PIO2); + } + + return (s, c); + } + + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40e231d5 { + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + if sign { + s = k_cosf(x as f64 + S3PIO2); + c = -k_sinf(x as f64 + S3PIO2); + } else { + s = -k_cosf(x as f64 - S3PIO2); + c = k_sinf(x as f64 - S3PIO2); + } + } else if sign { + s = k_sinf(x as f64 + S4PIO2); + c = k_cosf(x as f64 + S4PIO2); + } else { + s = k_sinf(x as f64 - S4PIO2); + c = k_cosf(x as f64 - S4PIO2); + } + + return (s, c); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + let rv = x - x; + return (rv, rv); + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + s = k_sinf(y); + c = k_cosf(y); + match n & 3 { + 0 => (s, c), + 1 => (c, -s), + 2 => (-s, -c), + 3 => (-c, s), + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => (0.0, 1.0), + } +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::sincosf; + + #[test] + fn rotational_symmetry() { + use core::f32::consts::PI; + const N: usize = 24; + for n in 0..N { + let theta = 2. * PI * (n as f32) / (N as f32); + let (s, c) = sincosf(theta); + let (s_plus, c_plus) = sincosf(theta + 2. * PI); + let (s_minus, c_minus) = sincosf(theta - 2. * PI); + + const TOLERANCE: f32 = 1e-6; + assert!( + (s - s_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_plus, + (s - s_plus).abs(), + TOLERANCE + ); + assert!( + (s - s_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_minus, + (s - s_minus).abs(), + TOLERANCE + ); + assert!( + (c - c_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_plus, + (c - c_plus).abs(), + TOLERANCE + ); + assert!( + (c - c_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_minus, + (c - c_minus).abs(), + TOLERANCE + ); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs new file mode 100644 index 00000000000..b8fae2c9801 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -0,0 +1,88 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f64::consts::FRAC_PI_2; + +use super::{k_cosf, k_sinf, rem_pio2f}; + +/* Small multiples of pi/2 rounded to double precision. */ +const S1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +/// The sine of `x` (f32). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sinf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); + return x; + } + return k_sinf(x64); + } + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + if sign { + return -k_cosf(x64 + S1_PIO2); + } else { + return k_cosf(x64 - S1_PIO2); + } + } + return k_sinf(if sign { -(x64 + S2_PIO2) } else { -(x64 - S2_PIO2) }); + } + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + if sign { + return k_cosf(x64 + S3_PIO2); + } else { + return -k_cosf(x64 - S3_PIO2); + } + } + return k_sinf(if sign { x64 + S4_PIO2 } else { x64 - S4_PIO2 }); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x - x; + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + match n & 3 { + 0 => k_sinf(y), + 1 => k_cosf(y), + 2 => k_sinf(-y), + _ => -k_cosf(y), + } +} diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs new file mode 100644 index 00000000000..79184198263 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sinh.rs @@ -0,0 +1,51 @@ +use super::{expm1, expo2}; + +// sinh(x) = (exp(x) - 1/exp(x))/2 +// = (exp(x)-1 + (exp(x)-1)/exp(x))/2 +// = x + x^3/6 + o(x^5) +// + +/// The hyperbolic sine of `x` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sinh(x: f64) -> f64 { + // union {double f; uint64_t i;} u = {.f = x}; + // uint32_t w; + // double t, h, absx; + + let mut uf: f64 = x; + let mut ui: u64 = f64::to_bits(uf); + let w: u32; + let t: f64; + let mut h: f64; + let absx: f64; + + h = 0.5; + if ui >> 63 != 0 { + h = -h; + } + /* |x| */ + ui &= !1 / 2; + uf = f64::from_bits(ui); + absx = uf; + w = (ui >> 32) as u32; + + /* |x| < log(DBL_MAX) */ + if w < 0x40862e42 { + t = expm1(absx); + if w < 0x3ff00000 { + if w < 0x3ff00000 - (26 << 20) { + /* note: inexact and underflow are raised by expm1 */ + /* note: this branch avoids spurious underflow */ + return x; + } + return h * (2.0 * t - t * t / (t + 1.0)); + } + /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ + return h * (t + t / (t + 1.0)); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = 2.0 * h * expo2(absx); + t +} diff --git a/library/compiler-builtins/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/src/math/sinhf.rs new file mode 100644 index 00000000000..44d2e3560d5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sinhf.rs @@ -0,0 +1,30 @@ +use super::{expm1f, k_expo2f}; + +/// The hyperbolic sine of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sinhf(x: f32) -> f32 { + let mut h = 0.5f32; + let mut ix = x.to_bits(); + if (ix >> 31) != 0 { + h = -h; + } + /* |x| */ + ix &= 0x7fffffff; + let absx = f32::from_bits(ix); + let w = ix; + + /* |x| < log(FLT_MAX) */ + if w < 0x42b17217 { + let t = expm1f(absx); + if w < 0x3f800000 { + if w < (0x3f800000 - (12 << 23)) { + return x; + } + return h * (2. * t - t * t / (t + 1.)); + } + return h * (t + t / (t + 1.)); + } + + /* |x| > logf(FLT_MAX) or nan */ + 2. * h * k_expo2f(absx) +} diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs new file mode 100644 index 00000000000..76bc240cf01 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -0,0 +1,51 @@ +/// The square root of `x` (f16). +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf16(x: f16) -> f16 { + select_implementation! { + name: sqrtf16, + use_arch: all(target_arch = "aarch64", target_feature = "fp16"), + args: x, + } + + return super::generic::sqrt(x); +} + +/// The square root of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf(x: f32) -> f32 { + select_implementation! { + name: sqrtf, + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + all(target_arch = "wasm32", intrinsics_enabled), + target_feature = "sse2" + ), + args: x, + } + + super::generic::sqrt(x) +} + +/// The square root of `x` (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrt(x: f64) -> f64 { + select_implementation! { + name: sqrt, + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + all(target_arch = "wasm32", intrinsics_enabled), + target_feature = "sse2" + ), + args: x, + } + + super::generic::sqrt(x) +} + +/// The square root of `x` (f128). +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf128(x: f128) -> f128 { + return super::generic::sqrt(x); +} diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs new file mode 100644 index 00000000000..c28a705e378 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -0,0 +1,15 @@ +/// The square root of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf(x: f32) -> f32 { + select_implementation! { + name: sqrtf, + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + all(target_arch = "wasm32", intrinsics_enabled), + target_feature = "sse2" + ), + args: x, + } + + super::generic::sqrt(x) +} diff --git a/library/compiler-builtins/libm/src/math/sqrtf128.rs b/library/compiler-builtins/libm/src/math/sqrtf128.rs new file mode 100644 index 00000000000..eaef6ae0c1c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sqrtf128.rs @@ -0,0 +1,5 @@ +/// The square root of `x` (f128). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf128(x: f128) -> f128 { + return super::generic::sqrt(x); +} diff --git a/library/compiler-builtins/libm/src/math/sqrtf16.rs b/library/compiler-builtins/libm/src/math/sqrtf16.rs new file mode 100644 index 00000000000..7bedb7f8bbb --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sqrtf16.rs @@ -0,0 +1,11 @@ +/// The square root of `x` (f16). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf16(x: f16) -> f16 { + select_implementation! { + name: sqrtf16, + use_arch: all(target_arch = "aarch64", target_feature = "fp16"), + args: x, + } + + return super::generic::sqrt(x); +} diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs new file mode 100644 index 00000000000..eae08238e09 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -0,0 +1,239 @@ +//! Integers used for wide operations, larger than `u128`. + +#[cfg(test)] +mod tests; + +use core::ops; + +use super::{DInt, HInt, Int, MinInt}; + +const U128_LO_MASK: u128 = u64::MAX as u128; + +/// A 256-bit unsigned integer represented as two 128-bit native-endian limbs. +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +pub struct u256 { + pub lo: u128, + pub hi: u128, +} + +impl u256 { + #[cfg(any(test, feature = "unstable-public-internals"))] + pub const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX }; + + /// Reinterpret as a signed integer + pub fn signed(self) -> i256 { + i256 { lo: self.lo, hi: self.hi } + } +} + +/// A 256-bit signed integer represented as two 128-bit native-endian limbs. +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +pub struct i256 { + pub lo: u128, + pub hi: u128, +} + +impl i256 { + /// Reinterpret as an unsigned integer + #[cfg(any(test, feature = "unstable-public-internals"))] + pub fn unsigned(self) -> u256 { + u256 { lo: self.lo, hi: self.hi } + } +} + +impl MinInt for u256 { + type OtherSign = i256; + + type Unsigned = u256; + + const SIGNED: bool = false; + const BITS: u32 = 256; + const ZERO: Self = Self { lo: 0, hi: 0 }; + const ONE: Self = Self { lo: 1, hi: 0 }; + const MIN: Self = Self { lo: 0, hi: 0 }; + const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX }; +} + +impl MinInt for i256 { + type OtherSign = u256; + + type Unsigned = u256; + + const SIGNED: bool = false; + const BITS: u32 = 256; + const ZERO: Self = Self { lo: 0, hi: 0 }; + const ONE: Self = Self { lo: 1, hi: 0 }; + const MIN: Self = Self { lo: 0, hi: 1 << 127 }; + const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX << 1 }; +} + +macro_rules! impl_common { + ($ty:ty) => { + impl ops::BitOr for $ty { + type Output = Self; + + fn bitor(mut self, rhs: Self) -> Self::Output { + self.lo |= rhs.lo; + self.hi |= rhs.hi; + self + } + } + + impl ops::Not for $ty { + type Output = Self; + + fn not(mut self) -> Self::Output { + self.lo = !self.lo; + self.hi = !self.hi; + self + } + } + + impl ops::Shl for $ty { + type Output = Self; + + fn shl(self, _rhs: u32) -> Self::Output { + unimplemented!("only used to meet trait bounds") + } + } + }; +} + +impl_common!(i256); +impl_common!(u256); + +impl ops::Add for u256 { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + let (lo, carry) = self.lo.overflowing_add(rhs.lo); + let hi = self.hi.wrapping_add(carry as u128).wrapping_add(rhs.hi); + + Self { lo, hi } + } +} + +impl ops::Shr for u256 { + type Output = Self; + + fn shr(mut self, rhs: u32) -> Self::Output { + debug_assert!(rhs < Self::BITS, "attempted to shift right with overflow"); + if rhs >= Self::BITS { + return Self::ZERO; + } + + if rhs == 0 { + return self; + } + + if rhs < 128 { + self.lo >>= rhs; + self.lo |= self.hi << (128 - rhs); + } else { + self.lo = self.hi >> (rhs - 128); + } + + if rhs < 128 { + self.hi >>= rhs; + } else { + self.hi = 0; + } + + self + } +} + +impl HInt for u128 { + type D = u256; + + fn widen(self) -> Self::D { + u256 { lo: self, hi: 0 } + } + + fn zero_widen(self) -> Self::D { + self.widen() + } + + fn zero_widen_mul(self, rhs: Self) -> Self::D { + let l0 = self & U128_LO_MASK; + let l1 = rhs & U128_LO_MASK; + let h0 = self >> 64; + let h1 = rhs >> 64; + + let p_ll: u128 = l0.overflowing_mul(l1).0; + let p_lh: u128 = l0.overflowing_mul(h1).0; + let p_hl: u128 = h0.overflowing_mul(l1).0; + let p_hh: u128 = h0.overflowing_mul(h1).0; + + let s0 = p_hl + (p_ll >> 64); + let s1 = (p_ll & U128_LO_MASK) + (s0 << 64); + let s2 = p_lh + (s1 >> 64); + + let lo = (p_ll & U128_LO_MASK) + (s2 << 64); + let hi = p_hh + (s0 >> 64) + (s2 >> 64); + + u256 { lo, hi } + } + + fn widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen_mul(rhs) + } + + fn widen_hi(self) -> Self::D { + self.widen() << ::BITS + } +} + +impl HInt for i128 { + type D = i256; + + fn widen(self) -> Self::D { + let mut ret = self.unsigned().zero_widen().signed(); + if self.is_negative() { + ret.hi = u128::MAX; + } + ret + } + + fn zero_widen(self) -> Self::D { + self.unsigned().zero_widen().signed() + } + + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.unsigned().zero_widen_mul(rhs.unsigned()).signed() + } + + fn widen_mul(self, _rhs: Self) -> Self::D { + unimplemented!("signed i128 widening multiply is not used") + } + + fn widen_hi(self) -> Self::D { + self.widen() << ::BITS + } +} + +impl DInt for u256 { + type H = u128; + + fn lo(self) -> Self::H { + self.lo + } + + fn hi(self) -> Self::H { + self.hi + } +} + +impl DInt for i256 { + type H = i128; + + fn lo(self) -> Self::H { + self.lo as i128 + } + + fn hi(self) -> Self::H { + self.hi as i128 + } +} diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs new file mode 100644 index 00000000000..2c71191ba53 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -0,0 +1,149 @@ +extern crate std; +use std::string::String; +use std::{eprintln, format}; + +use super::{HInt, MinInt, i256, u256}; + +const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; + +/// Print a `u256` as hex since we can't add format implementations +fn hexu(v: u256) -> String { + format!("0x{:032x}{:032x}", v.hi, v.lo) +} + +#[test] +fn widen_u128() { + assert_eq!(u128::MAX.widen(), u256 { lo: u128::MAX, hi: 0 }); + assert_eq!(LOHI_SPLIT.widen(), u256 { lo: LOHI_SPLIT, hi: 0 }); +} + +#[test] +fn widen_i128() { + assert_eq!((-1i128).widen(), u256::MAX.signed()); + assert_eq!((LOHI_SPLIT as i128).widen(), i256 { lo: LOHI_SPLIT, hi: u128::MAX }); + assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); +} + +#[test] +fn widen_mul_u128() { + let tests = [ + (u128::MAX / 2, 2_u128, u256 { lo: u128::MAX - 1, hi: 0 }), + (u128::MAX, 2_u128, u256 { lo: u128::MAX - 1, hi: 1 }), + (u128::MAX, u128::MAX, u256 { lo: 1, hi: u128::MAX - 1 }), + (0, 0, u256::ZERO), + (1234u128, 0, u256::ZERO), + (0, 1234, u256::ZERO), + ]; + + let mut has_errors = false; + let mut add_error = |i, a, b, expected, actual| { + has_errors = true; + eprintln!( + "\ + FAILURE ({i}): {a:#034x} * {b:#034x}\n\ + expected: {}\n\ + got: {}\ + ", + hexu(expected), + hexu(actual) + ); + }; + + for (i, (a, b, exp)) in tests.iter().copied().enumerate() { + let res = a.widen_mul(b); + let res_z = a.zero_widen_mul(b); + assert_eq!(res, res_z); + if res != exp { + add_error(i, a, b, exp, res); + } + } + + assert!(!has_errors); +} + +#[test] +fn not_u256() { + assert_eq!(!u256::ZERO, u256::MAX); +} + +#[test] +fn shr_u256() { + let only_low = [1, u16::MAX.into(), u32::MAX.into(), u64::MAX.into(), u128::MAX]; + let mut has_errors = false; + + let mut add_error = |a, b, expected, actual| { + has_errors = true; + eprintln!( + "\ + FAILURE: {} >> {b}\n\ + expected: {}\n\ + actual: {}\ + ", + hexu(a), + hexu(expected), + hexu(actual), + ); + }; + + for a in only_low { + for perturb in 0..10 { + let a = a.saturating_add(perturb); + for shift in 0..128 { + let res = a.widen() >> shift; + let expected = (a >> shift).widen(); + if res != expected { + add_error(a.widen(), shift, expected, res); + } + } + } + } + + let check = [ + (u256::MAX, 1, u256 { lo: u128::MAX, hi: u128::MAX >> 1 }), + (u256::MAX, 5, u256 { lo: u128::MAX, hi: u128::MAX >> 5 }), + (u256::MAX, 63, u256 { lo: u128::MAX, hi: u64::MAX as u128 | (1 << 64) }), + (u256::MAX, 64, u256 { lo: u128::MAX, hi: u64::MAX as u128 }), + (u256::MAX, 65, u256 { lo: u128::MAX, hi: (u64::MAX >> 1) as u128 }), + (u256::MAX, 127, u256 { lo: u128::MAX, hi: 1 }), + (u256::MAX, 128, u256 { lo: u128::MAX, hi: 0 }), + (u256::MAX, 129, u256 { lo: u128::MAX >> 1, hi: 0 }), + (u256::MAX, 191, u256 { lo: u64::MAX as u128 | 1 << 64, hi: 0 }), + (u256::MAX, 192, u256 { lo: u64::MAX as u128, hi: 0 }), + (u256::MAX, 193, u256 { lo: u64::MAX as u128 >> 1, hi: 0 }), + (u256::MAX, 254, u256 { lo: 0b11, hi: 0 }), + (u256::MAX, 255, u256 { lo: 1, hi: 0 }), + ( + u256 { hi: LOHI_SPLIT, lo: 0 }, + 64, + u256 { lo: 0xffffffffffffffff0000000000000000, hi: 0xaaaaaaaaaaaaaaaa }, + ), + ]; + + for (input, shift, expected) in check { + let res = input >> shift; + if res != expected { + add_error(input, shift, expected, res); + } + } + + assert!(!has_errors); +} + +#[test] +#[should_panic] +#[cfg(debug_assertions)] +// FIXME(ppc): ppc64le seems to have issues with `should_panic` tests. +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +fn shr_u256_overflow() { + // Like regular shr, panic on overflow with debug assertions + let _ = u256::MAX >> 256; +} + +#[test] +#[cfg(not(debug_assertions))] +fn shr_u256_overflow() { + // No panic without debug assertions + assert_eq!(u256::MAX >> 256, u256::ZERO); + assert_eq!(u256::MAX >> 257, u256::ZERO); + assert_eq!(u256::MAX >> u32::MAX, u256::ZERO); +} diff --git a/library/compiler-builtins/libm/src/math/support/env.rs b/library/compiler-builtins/libm/src/math/support/env.rs new file mode 100644 index 00000000000..796309372a5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/env.rs @@ -0,0 +1,127 @@ +//! Support for rounding directions and status flags as specified by IEEE 754. +//! +//! Rust does not support the floating point environment so rounding mode is passed as an argument +//! and status flags are returned as part of the result. There is currently not much support for +//! this; most existing ports from musl use a form of `force_eval!` to raise exceptions, but this +//! has no side effects in Rust. Further, correct behavior relies on elementary operations making +//! use of the correct rounding and raising relevant exceptions, which is not the case for Rust. +//! +//! This module exists so no functionality is lost when porting algorithms that respect floating +//! point environment, and so that some functionality may be tested (that which does not rely on +//! side effects from elementary operations). Full support would require wrappers around basic +//! operations, but there is no plan to add this at the current time. + +/// A value combined with a floating point status. +pub struct FpResult { + pub val: T, + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub status: Status, +} + +impl FpResult { + pub fn new(val: T, status: Status) -> Self { + Self { val, status } + } + + /// Return `val` with `Status::OK`. + pub fn ok(val: T) -> Self { + Self { val, status: Status::OK } + } +} + +/// IEEE 754 rounding mode, excluding the optional `roundTiesToAway` version of nearest. +/// +/// Integer representation comes from what CORE-MATH uses for indexing. +#[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Round { + /// IEEE 754 nearest, `roundTiesToEven`. + Nearest = 0, + /// IEEE 754 `roundTowardNegative`. + Negative = 1, + /// IEEE 754 `roundTowardPositive`. + Positive = 2, + /// IEEE 754 `roundTowardZero`. + Zero = 3, +} + +/// IEEE 754 exception status flags. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Status(u8); + +impl Status { + /// Default status indicating no errors. + pub const OK: Self = Self(0); + + /// No definable result. + /// + /// Includes: + /// - Any ops on sNaN, with a few exceptions. + /// - `0 * inf`, `inf * 0`. + /// - `fma(0, inf, c)` or `fma(inf, 0, c)`, possibly excluding `c = qNaN`. + /// - `+inf + -inf` and similar (includes subtraction and fma). + /// - `0.0 / 0.0`, `inf / inf` + /// - `remainder(x, y)` if `y == 0.0` or `x == inf`, and neither is NaN. + /// - `sqrt(x)` with `x < 0.0`. + pub const INVALID: Self = Self(1); + + /// Division by zero. + /// + /// The default result for division is +/-inf based on operand sign. For `logB`, the default + /// result is -inf. + /// `x / y` when `x != 0.0` and `y == 0.0`, + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub const DIVIDE_BY_ZERO: Self = Self(1 << 2); + + /// The result exceeds the maximum finite value. + /// + /// The default result depends on rounding mode. `Nearest*` rounds to +/- infinity, sign based + /// on the intermediate result. `Zero` rounds to the signed maximum finite. `Positive` and + /// `Negative` round to signed maximum finite in one direction, signed infinity in the other. + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub const OVERFLOW: Self = Self(1 << 3); + + /// The result is subnormal and lost precision. + pub const UNDERFLOW: Self = Self(1 << 4); + + /// The finite-precision result does not match that of infinite precision, and the reason + /// is not represented by one of the other flags. + pub const INEXACT: Self = Self(1 << 5); + + /// True if `UNDERFLOW` is set. + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub const fn underflow(self) -> bool { + self.0 & Self::UNDERFLOW.0 != 0 + } + + /// True if `OVERFLOW` is set. + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub const fn overflow(self) -> bool { + self.0 & Self::OVERFLOW.0 != 0 + } + + pub fn set_underflow(&mut self, val: bool) { + self.set_flag(val, Self::UNDERFLOW); + } + + /// True if `INEXACT` is set. + pub const fn inexact(self) -> bool { + self.0 & Self::INEXACT.0 != 0 + } + + pub fn set_inexact(&mut self, val: bool) { + self.set_flag(val, Self::INEXACT); + } + + fn set_flag(&mut self, val: bool, mask: Self) { + if val { + self.0 |= mask.0; + } else { + self.0 &= !mask.0; + } + } + + pub(crate) const fn with(self, rhs: Self) -> Self { + Self(self.0 | rhs.0) + } +} diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs new file mode 100644 index 00000000000..fac10483237 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -0,0 +1,484 @@ +use core::{fmt, mem, ops}; + +use super::int_traits::{CastFrom, Int, MinInt}; + +/// Trait for some basic operations on floats +// #[allow(dead_code)] +pub trait Float: + Copy + + fmt::Debug + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::MulAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Rem + + ops::Neg + + 'static +{ + /// A uint of the same width as the float + type Int: Int; + + /// A int of the same width as the float + type SignedInt: Int + + MinInt + + ops::Neg; + + const ZERO: Self; + const NEG_ZERO: Self; + const ONE: Self; + const NEG_ONE: Self; + const INFINITY: Self; + const NEG_INFINITY: Self; + const NAN: Self; + const NEG_NAN: Self; + const MAX: Self; + const MIN: Self; + const EPSILON: Self; + const PI: Self; + const NEG_PI: Self; + const FRAC_PI_2: Self; + + const MIN_POSITIVE_NORMAL: Self; + + /// The bitwidth of the float type + const BITS: u32; + + /// The bitwidth of the significand + const SIG_BITS: u32; + + /// The bitwidth of the exponent + const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; + + /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite + /// representation. + /// + /// This shifted fully right, use `EXP_MASK` for the shifted value. + const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; + + /// The exponent bias value + const EXP_BIAS: u32 = Self::EXP_SAT >> 1; + + /// Maximum unbiased exponent value. + const EXP_MAX: i32 = Self::EXP_BIAS as i32; + + /// Minimum *NORMAL* unbiased exponent value. + const EXP_MIN: i32 = -(Self::EXP_MAX - 1); + + /// Minimum subnormal exponent value. + const EXP_MIN_SUBNORM: i32 = Self::EXP_MIN - Self::SIG_BITS as i32; + + /// A mask for the sign bit + const SIGN_MASK: Self::Int; + + /// A mask for the significand + const SIG_MASK: Self::Int; + + /// A mask for the exponent + const EXP_MASK: Self::Int; + + /// The implicit bit of the float format + const IMPLICIT_BIT: Self::Int; + + /// Returns `self` transmuted to `Self::Int` + fn to_bits(self) -> Self::Int; + + /// Returns `self` transmuted to `Self::SignedInt` + #[allow(dead_code)] + fn to_bits_signed(self) -> Self::SignedInt { + self.to_bits().signed() + } + + /// Check bitwise equality. + #[allow(dead_code)] + fn biteq(self, rhs: Self) -> bool { + self.to_bits() == rhs.to_bits() + } + + /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be + /// represented in multiple different ways. + /// + /// This method returns `true` if two NaNs are compared. Use [`biteq`](Self::biteq) instead + /// if `NaN` should not be treated separately. + #[allow(dead_code)] + fn eq_repr(self, rhs: Self) -> bool { + if self.is_nan() && rhs.is_nan() { true } else { self.biteq(rhs) } + } + + /// Returns true if the value is NaN. + fn is_nan(self) -> bool; + + /// Returns true if the value is +inf or -inf. + fn is_infinite(self) -> bool; + + /// Returns true if the sign is negative. Extracts the sign bit regardless of zero or NaN. + fn is_sign_negative(self) -> bool; + + /// Returns true if the sign is positive. Extracts the sign bit regardless of zero or NaN. + fn is_sign_positive(self) -> bool { + !self.is_sign_negative() + } + + /// Returns if `self` is subnormal. + #[allow(dead_code)] + fn is_subnormal(self) -> bool { + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO + } + + /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. + fn ex(self) -> u32 { + u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_SAT + } + + /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. + fn exp_unbiased(self) -> i32 { + self.ex().signed() - (Self::EXP_BIAS as i32) + } + + /// Returns the significand with no implicit bit (or the "fractional" part) + #[allow(dead_code)] + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIG_MASK + } + + /// Returns a `Self::Int` transmuted back to `Self` + fn from_bits(a: Self::Int) -> Self; + + /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. + fn from_parts(negative: bool, exponent: u32, significand: Self::Int) -> Self { + let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; + Self::from_bits( + (sign << (Self::BITS - 1)) + | (Self::Int::cast_from(exponent & Self::EXP_SAT) << Self::SIG_BITS) + | (significand & Self::SIG_MASK), + ) + } + + #[allow(dead_code)] + fn abs(self) -> Self; + + /// Returns a number composed of the magnitude of self and the sign of sign. + fn copysign(self, other: Self) -> Self; + + /// Fused multiply add, rounding once. + fn fma(self, y: Self, z: Self) -> Self; + + /// Returns (normalized exponent, normalized significand) + #[allow(dead_code)] + fn normalize(significand: Self::Int) -> (i32, Self::Int); + + /// Returns a number that represents the sign of self. + #[allow(dead_code)] + fn signum(self) -> Self { + if self.is_nan() { self } else { Self::ONE.copysign(self) } + } +} + +/// Access the associated `Int` type from a float (helper to avoid ambiguous associated types). +pub type IntTy = ::Int; + +macro_rules! float_impl { + ( + $ty:ident, + $ity:ident, + $sity:ident, + $bits:expr, + $significand_bits:expr, + $from_bits:path, + $to_bits:path, + $fma_fn:ident, + $fma_intrinsic:ident + ) => { + impl Float for $ty { + type Int = $ity; + type SignedInt = $sity; + + const ZERO: Self = 0.0; + const NEG_ZERO: Self = -0.0; + const ONE: Self = 1.0; + const NEG_ONE: Self = -1.0; + const INFINITY: Self = Self::INFINITY; + const NEG_INFINITY: Self = Self::NEG_INFINITY; + const NAN: Self = Self::NAN; + // NAN isn't guaranteed to be positive but it usually is. We only use this for + // tests. + const NEG_NAN: Self = $from_bits($to_bits(Self::NAN) | Self::SIGN_MASK); + const MAX: Self = -Self::MIN; + // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed + const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS)); + const EPSILON: Self = <$ty>::EPSILON; + + // Exponent is a 1 in the LSB + const MIN_POSITIVE_NORMAL: Self = $from_bits(1 << Self::SIG_BITS); + + const PI: Self = core::$ty::consts::PI; + const NEG_PI: Self = -Self::PI; + const FRAC_PI_2: Self = core::$ty::consts::FRAC_PI_2; + + const BITS: u32 = $bits; + const SIG_BITS: u32 = $significand_bits; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; + const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); + const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; + + fn to_bits(self) -> Self::Int { + self.to_bits() + } + fn is_nan(self) -> bool { + self.is_nan() + } + fn is_infinite(self) -> bool { + self.is_infinite() + } + fn is_sign_negative(self) -> bool { + self.is_sign_negative() + } + fn from_bits(a: Self::Int) -> Self { + Self::from_bits(a) + } + fn abs(self) -> Self { + cfg_if! { + // FIXME(msrv): `abs` is available in `core` starting with 1.85. + if #[cfg(intrinsics_enabled)] { + self.abs() + } else { + super::super::generic::fabs(self) + } + } + } + fn copysign(self, other: Self) -> Self { + cfg_if! { + // FIXME(msrv): `copysign` is available in `core` starting with 1.85. + if #[cfg(intrinsics_enabled)] { + self.copysign(other) + } else { + super::super::generic::copysign(self, other) + } + } + } + fn fma(self, y: Self, z: Self) -> Self { + cfg_if! { + // fma is not yet available in `core` + if #[cfg(intrinsics_enabled)] { + unsafe{ core::intrinsics::$fma_intrinsic(self, y, z) } + } else { + super::super::$fma_fn(self, y, z) + } + } + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); + (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) + } + } + }; +} + +#[cfg(f16_enabled)] +float_impl!(f16, u16, i16, 16, 10, f16::from_bits, f16::to_bits, fmaf16, fmaf16); +float_impl!(f32, u32, i32, 32, 23, f32_from_bits, f32_to_bits, fmaf, fmaf32); +float_impl!(f64, u64, i64, 64, 52, f64_from_bits, f64_to_bits, fma, fmaf64); +#[cfg(f128_enabled)] +float_impl!(f128, u128, i128, 128, 112, f128::from_bits, f128::to_bits, fmaf128, fmaf128); + +/* FIXME(msrv): vendor some things that are not const stable at our MSRV */ + +/// `f32::from_bits` +pub const fn f32_from_bits(bits: u32) -> f32 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(bits) } +} + +/// `f32::to_bits` +pub const fn f32_to_bits(x: f32) -> u32 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(x) } +} + +/// `f64::from_bits` +pub const fn f64_from_bits(bits: u64) -> f64 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(bits) } +} + +/// `f64::to_bits` +pub const fn f64_to_bits(x: f64) -> u64 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(x) } +} + +/// Trait for floats twice the bit width of another integer. +pub trait DFloat: Float { + /// Float that is half the bit width of the floatthis trait is implemented for. + type H: HFloat; + + /// Narrow the float type. + fn narrow(self) -> Self::H; +} + +/// Trait for floats half the bit width of another float. +pub trait HFloat: Float { + /// Float that is double the bit width of the float this trait is implemented for. + type D: DFloat; + + /// Widen the float type. + fn widen(self) -> Self::D; +} + +macro_rules! impl_d_float { + ($($X:ident $D:ident),*) => { + $( + impl DFloat for $D { + type H = $X; + + fn narrow(self) -> Self::H { + self as $X + } + } + )* + }; +} + +macro_rules! impl_h_float { + ($($H:ident $X:ident),*) => { + $( + impl HFloat for $H { + type D = $X; + + fn widen(self) -> Self::D { + self as $X + } + } + )* + }; +} + +impl_d_float!(f32 f64); +#[cfg(f16_enabled)] +impl_d_float!(f16 f32); +#[cfg(f128_enabled)] +impl_d_float!(f64 f128); + +impl_h_float!(f32 f64); +#[cfg(f16_enabled)] +impl_h_float!(f16 f32); +#[cfg(f128_enabled)] +impl_h_float!(f64 f128); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(f16_enabled)] + fn check_f16() { + // Constants + assert_eq!(f16::EXP_SAT, 0b11111); + assert_eq!(f16::EXP_BIAS, 15); + assert_eq!(f16::EXP_MAX, 15); + assert_eq!(f16::EXP_MIN, -14); + assert_eq!(f16::EXP_MIN_SUBNORM, -24); + + // `exp_unbiased` + assert_eq!(f16::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f16 / 2.0).exp_unbiased(), -1); + assert_eq!(f16::MAX.exp_unbiased(), 15); + assert_eq!(f16::MIN.exp_unbiased(), 15); + assert_eq!(f16::MIN_POSITIVE.exp_unbiased(), -14); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f16::ZERO.exp_unbiased(), -15); + assert_eq!(f16::from_bits(0x1).exp_unbiased(), -15); + assert_eq!(f16::MIN_POSITIVE, f16::MIN_POSITIVE_NORMAL); + + // `from_parts` + assert_biteq!(f16::from_parts(true, f16::EXP_BIAS, 0), -1.0f16); + assert_biteq!(f16::from_parts(false, 0, 1), f16::from_bits(0x1)); + } + + #[test] + fn check_f32() { + // Constants + assert_eq!(f32::EXP_SAT, 0b11111111); + assert_eq!(f32::EXP_BIAS, 127); + assert_eq!(f32::EXP_MAX, 127); + assert_eq!(f32::EXP_MIN, -126); + assert_eq!(f32::EXP_MIN_SUBNORM, -149); + + // `exp_unbiased` + assert_eq!(f32::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f32 / 2.0).exp_unbiased(), -1); + assert_eq!(f32::MAX.exp_unbiased(), 127); + assert_eq!(f32::MIN.exp_unbiased(), 127); + assert_eq!(f32::MIN_POSITIVE.exp_unbiased(), -126); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f32::ZERO.exp_unbiased(), -127); + assert_eq!(f32::from_bits(0x1).exp_unbiased(), -127); + assert_eq!(f32::MIN_POSITIVE, f32::MIN_POSITIVE_NORMAL); + + // `from_parts` + assert_biteq!(f32::from_parts(true, f32::EXP_BIAS, 0), -1.0f32); + assert_biteq!(f32::from_parts(false, 10 + f32::EXP_BIAS, 0), hf32!("0x1p10")); + assert_biteq!(f32::from_parts(false, 0, 1), f32::from_bits(0x1)); + } + + #[test] + fn check_f64() { + // Constants + assert_eq!(f64::EXP_SAT, 0b11111111111); + assert_eq!(f64::EXP_BIAS, 1023); + assert_eq!(f64::EXP_MAX, 1023); + assert_eq!(f64::EXP_MIN, -1022); + assert_eq!(f64::EXP_MIN_SUBNORM, -1074); + + // `exp_unbiased` + assert_eq!(f64::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f64 / 2.0).exp_unbiased(), -1); + assert_eq!(f64::MAX.exp_unbiased(), 1023); + assert_eq!(f64::MIN.exp_unbiased(), 1023); + assert_eq!(f64::MIN_POSITIVE.exp_unbiased(), -1022); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f64::ZERO.exp_unbiased(), -1023); + assert_eq!(f64::from_bits(0x1).exp_unbiased(), -1023); + assert_eq!(f64::MIN_POSITIVE, f64::MIN_POSITIVE_NORMAL); + + // `from_parts` + assert_biteq!(f64::from_parts(true, f64::EXP_BIAS, 0), -1.0f64); + assert_biteq!(f64::from_parts(false, 10 + f64::EXP_BIAS, 0), hf64!("0x1p10")); + assert_biteq!(f64::from_parts(false, 0, 1), f64::from_bits(0x1)); + } + + #[test] + #[cfg(f128_enabled)] + fn check_f128() { + // Constants + assert_eq!(f128::EXP_SAT, 0b111111111111111); + assert_eq!(f128::EXP_BIAS, 16383); + assert_eq!(f128::EXP_MAX, 16383); + assert_eq!(f128::EXP_MIN, -16382); + assert_eq!(f128::EXP_MIN_SUBNORM, -16494); + + // `exp_unbiased` + assert_eq!(f128::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f128 / 2.0).exp_unbiased(), -1); + assert_eq!(f128::MAX.exp_unbiased(), 16383); + assert_eq!(f128::MIN.exp_unbiased(), 16383); + assert_eq!(f128::MIN_POSITIVE.exp_unbiased(), -16382); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f128::ZERO.exp_unbiased(), -16383); + assert_eq!(f128::from_bits(0x1).exp_unbiased(), -16383); + assert_eq!(f128::MIN_POSITIVE, f128::MIN_POSITIVE_NORMAL); + + // `from_parts` + assert_biteq!(f128::from_parts(true, f128::EXP_BIAS, 0), -1.0f128); + assert_biteq!(f128::from_parts(false, 0, 1), f128::from_bits(0x1)); + } +} diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs new file mode 100644 index 00000000000..819e2f56e36 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -0,0 +1,1155 @@ +//! Utilities for working with hex float formats. + +use core::fmt; + +use super::{Float, Round, Status, f32_from_bits, f64_from_bits}; + +/// Construct a 16-bit float from hex float representation (C-style) +#[cfg(f16_enabled)] +pub const fn hf16(s: &str) -> f16 { + match parse_hex_exact(s, 16, 10) { + Ok(bits) => f16::from_bits(bits as u16), + Err(HexFloatParseError(s)) => panic!("{}", s), + } +} + +/// Construct a 32-bit float from hex float representation (C-style) +#[allow(unused)] +pub const fn hf32(s: &str) -> f32 { + match parse_hex_exact(s, 32, 23) { + Ok(bits) => f32_from_bits(bits as u32), + Err(HexFloatParseError(s)) => panic!("{}", s), + } +} + +/// Construct a 64-bit float from hex float representation (C-style) +pub const fn hf64(s: &str) -> f64 { + match parse_hex_exact(s, 64, 52) { + Ok(bits) => f64_from_bits(bits as u64), + Err(HexFloatParseError(s)) => panic!("{}", s), + } +} + +/// Construct a 128-bit float from hex float representation (C-style) +#[cfg(f128_enabled)] +pub const fn hf128(s: &str) -> f128 { + match parse_hex_exact(s, 128, 112) { + Ok(bits) => f128::from_bits(bits), + Err(HexFloatParseError(s)) => panic!("{}", s), + } +} +#[derive(Copy, Clone, Debug)] +pub struct HexFloatParseError(&'static str); + +/// Parses any float to its bitwise representation, returning an error if it cannot be represented exactly +pub const fn parse_hex_exact( + s: &str, + bits: u32, + sig_bits: u32, +) -> Result { + match parse_any(s, bits, sig_bits, Round::Nearest) { + Err(e) => Err(e), + Ok((bits, Status::OK)) => Ok(bits), + Ok((_, status)) if status.overflow() => Err(HexFloatParseError("the value is too huge")), + Ok((_, status)) if status.underflow() => Err(HexFloatParseError("the value is too tiny")), + Ok((_, status)) if status.inexact() => Err(HexFloatParseError("the value is too precise")), + Ok(_) => unreachable!(), + } +} + +/// Parse any float from hex to its bitwise representation. +pub const fn parse_any( + s: &str, + bits: u32, + sig_bits: u32, + round: Round, +) -> Result<(u128, Status), HexFloatParseError> { + let mut b = s.as_bytes(); + + if sig_bits > 119 || bits > 128 || bits < sig_bits + 3 || bits > sig_bits + 30 { + return Err(HexFloatParseError("unsupported target float configuration")); + } + + let neg = matches!(b, [b'-', ..]); + if let &[b'-' | b'+', ref rest @ ..] = b { + b = rest; + } + + let sign_bit = 1 << (bits - 1); + let quiet_bit = 1 << (sig_bits - 1); + let nan = sign_bit - quiet_bit; + let inf = nan - quiet_bit; + + let (mut x, status) = match *b { + [b'i' | b'I', b'n' | b'N', b'f' | b'F'] => (inf, Status::OK), + [b'n' | b'N', b'a' | b'A', b'n' | b'N'] => (nan, Status::OK), + [b'0', b'x' | b'X', ref rest @ ..] => { + let round = match (neg, round) { + // parse("-x", Round::Positive) == -parse("x", Round::Negative) + (true, Round::Positive) => Round::Negative, + (true, Round::Negative) => Round::Positive, + // rounding toward nearest or zero are symmetric + (true, Round::Nearest | Round::Zero) | (false, _) => round, + }; + match parse_finite(rest, bits, sig_bits, round) { + Err(e) => return Err(e), + Ok(res) => res, + } + } + _ => return Err(HexFloatParseError("no hex indicator")), + }; + + if neg { + x ^= sign_bit; + } + + Ok((x, status)) +} + +const fn parse_finite( + b: &[u8], + bits: u32, + sig_bits: u32, + rounding_mode: Round, +) -> Result<(u128, Status), HexFloatParseError> { + let exp_bits: u32 = bits - sig_bits - 1; + let max_msb: i32 = (1 << (exp_bits - 1)) - 1; + // The exponent of one ULP in the subnormals + let min_lsb: i32 = 1 - max_msb - sig_bits as i32; + + let (mut sig, mut exp) = match parse_hex(b) { + Err(e) => return Err(e), + Ok(Parsed { sig: 0, .. }) => return Ok((0, Status::OK)), + Ok(Parsed { sig, exp }) => (sig, exp), + }; + + let mut round_bits = u128_ilog2(sig) as i32 - sig_bits as i32; + + // Round at least up to min_lsb + if exp < min_lsb - round_bits { + round_bits = min_lsb - exp; + } + + let mut status = Status::OK; + + exp += round_bits; + + if round_bits > 0 { + // first, prepare for rounding exactly two bits + if round_bits == 1 { + sig <<= 1; + } else if round_bits > 2 { + sig = shr_odd_rounding(sig, (round_bits - 2) as u32); + } + + if sig & 0b11 != 0 { + status = Status::INEXACT; + } + + sig = shr2_round(sig, rounding_mode); + } else if round_bits < 0 { + sig <<= -round_bits; + } + + // The parsed value is X = sig * 2^exp + // Expressed as a multiple U of the smallest subnormal value: + // X = U * 2^min_lsb, so U = sig * 2^(exp-min_lsb) + let uexp = (exp - min_lsb) as u128; + let uexp = uexp << sig_bits; + + // Note that it is possible for the exponent bits to equal 2 here + // if the value rounded up, but that means the mantissa is all zeroes + // so the value is still correct + debug_assert!(sig <= 2 << sig_bits); + + let inf = ((1 << exp_bits) - 1) << sig_bits; + + let bits = match sig.checked_add(uexp) { + Some(bits) if bits < inf => { + // inexact subnormal or zero? + if status.inexact() && bits < (1 << sig_bits) { + status = status.with(Status::UNDERFLOW); + } + bits + } + _ => { + // overflow to infinity + status = status.with(Status::OVERFLOW).with(Status::INEXACT); + match rounding_mode { + Round::Positive | Round::Nearest => inf, + Round::Negative | Round::Zero => inf - 1, + } + } + }; + Ok((bits, status)) +} + +/// Shift right, rounding all inexact divisions to the nearest odd number +/// E.g. (0 >> 4) -> 0, (1..=31 >> 4) -> 1, (32 >> 4) -> 2, ... +/// +/// Useful for reducing a number before rounding the last two bits, since +/// the result of the final rounding is preserved for all rounding modes. +const fn shr_odd_rounding(x: u128, k: u32) -> u128 { + if k < 128 { + let inexact = x.trailing_zeros() < k; + (x >> k) | (inexact as u128) + } else { + (x != 0) as u128 + } +} + +/// Divide by 4, rounding with the given mode +const fn shr2_round(mut x: u128, round: Round) -> u128 { + let t = (x as u32) & 0b111; + x >>= 2; + match round { + // Look-up-table on the last three bits for when to round up + Round::Nearest => x + ((0b11001000_u8 >> t) & 1) as u128, + + Round::Negative => x, + Round::Zero => x, + Round::Positive => x + (t & 0b11 != 0) as u128, + } +} + +/// A parsed finite and unsigned floating point number. +struct Parsed { + /// Absolute value sig * 2^exp + sig: u128, + exp: i32, +} + +/// Parse a hexadecimal float x +const fn parse_hex(mut b: &[u8]) -> Result { + let mut sig: u128 = 0; + let mut exp: i32 = 0; + + let mut seen_point = false; + let mut some_digits = false; + let mut inexact = false; + + while let &[c, ref rest @ ..] = b { + b = rest; + + match c { + b'.' => { + if seen_point { + return Err(HexFloatParseError("unexpected '.' parsing fractional digits")); + } + seen_point = true; + continue; + } + b'p' | b'P' => break, + c => { + let digit = match hex_digit(c) { + Some(d) => d, + None => return Err(HexFloatParseError("expected hexadecimal digit")), + }; + some_digits = true; + + if (sig >> 124) == 0 { + sig <<= 4; + sig |= digit as u128; + } else { + // FIXME: it is technically possible for exp to overflow if parsing a string with >500M digits + exp += 4; + inexact |= digit != 0; + } + // Up until the fractional point, the value grows + // with more digits, but after it the exponent is + // compensated to match. + if seen_point { + exp -= 4; + } + } + } + } + // If we've set inexact, the exact value has more than 125 + // significant bits, and lies somewhere between sig and sig + 1. + // Because we'll round off at least two of the trailing bits, + // setting the last bit gives correct rounding for inexact values. + sig |= inexact as u128; + + if !some_digits { + return Err(HexFloatParseError("at least one digit is required")); + }; + + some_digits = false; + + let negate_exp = matches!(b, [b'-', ..]); + if let &[b'-' | b'+', ref rest @ ..] = b { + b = rest; + } + + let mut pexp: u32 = 0; + while let &[c, ref rest @ ..] = b { + b = rest; + let digit = match dec_digit(c) { + Some(d) => d, + None => return Err(HexFloatParseError("expected decimal digit")), + }; + some_digits = true; + pexp = pexp.saturating_mul(10); + pexp += digit as u32; + } + + if !some_digits { + return Err(HexFloatParseError("at least one exponent digit is required")); + }; + + { + let e; + if negate_exp { + e = (exp as i64) - (pexp as i64); + } else { + e = (exp as i64) + (pexp as i64); + }; + + exp = if e < i32::MIN as i64 { + i32::MIN + } else if e > i32::MAX as i64 { + i32::MAX + } else { + e as i32 + }; + } + /* FIXME(msrv): once MSRV >= 1.66, replace the above workaround block with: + if negate_exp { + exp = exp.saturating_sub_unsigned(pexp); + } else { + exp = exp.saturating_add_unsigned(pexp); + }; + */ + + Ok(Parsed { sig, exp }) +} + +const fn dec_digit(c: u8) -> Option { + match c { + b'0'..=b'9' => Some(c - b'0'), + _ => None, + } +} + +const fn hex_digit(c: u8) -> Option { + match c { + b'0'..=b'9' => Some(c - b'0'), + b'a'..=b'f' => Some(c - b'a' + 10), + b'A'..=b'F' => Some(c - b'A' + 10), + _ => None, + } +} + +/* FIXME(msrv): vendor some things that are not const stable at our MSRV */ + +/// `u128::ilog2` +const fn u128_ilog2(v: u128) -> u32 { + assert!(v != 0); + u128::BITS - 1 - v.leading_zeros() +} + +/// Format a floating point number as its IEEE hex (`%a`) representation. +pub struct Hexf(pub F); + +// Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs +#[cfg(not(feature = "compiler-builtins"))] +fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if x.is_sign_negative() { + write!(f, "-")?; + } + + if x.is_nan() { + return write!(f, "NaN"); + } else if x.is_infinite() { + return write!(f, "inf"); + } else if *x == F::ZERO { + return write!(f, "0x0p+0"); + } + + let mut exponent = x.exp_unbiased(); + let sig = x.to_bits() & F::SIG_MASK; + + let bias = F::EXP_BIAS as i32; + // The mantissa MSB needs to be shifted up to the nearest nibble. + let mshift = (4 - (F::SIG_BITS % 4)) % 4; + let sig = sig << mshift; + // The width is rounded up to the nearest char (4 bits) + let mwidth = (F::SIG_BITS as usize + 3) / 4; + let leading = if exponent == -bias { + // subnormal number means we shift our output by 1 bit. + exponent += 1; + "0." + } else { + "1." + }; + + write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") +} + +#[cfg(feature = "compiler-builtins")] +fn fmt_any_hex(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() +} + +impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt_any_hex(&self.0, f) + } + } + } +} + +impl fmt::LowerHex for Hexf<(F, F)> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + } + } + } +} + +impl fmt::LowerHex for Hexf<(F, i32)> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + } + } + } +} + +impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(&self.0, f) + } + } + } +} + +impl fmt::Debug for Hexf +where + Hexf: fmt::LowerHex, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(self, f) + } + } + } +} + +impl fmt::Display for Hexf +where + Hexf: fmt::LowerHex, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(self, f) + } + } + } +} + +#[cfg(test)] +mod parse_tests { + extern crate std; + use std::{format, println}; + + use super::*; + + #[cfg(f16_enabled)] + fn rounding_properties(s: &str) -> Result<(), HexFloatParseError> { + let (xd, s0) = parse_any(s, 16, 10, Round::Negative)?; + let (xu, s1) = parse_any(s, 16, 10, Round::Positive)?; + let (xz, s2) = parse_any(s, 16, 10, Round::Zero)?; + let (xn, s3) = parse_any(s, 16, 10, Round::Nearest)?; + + // FIXME: A value between the least normal and largest subnormal + // could have underflow status depend on rounding mode. + + if let Status::OK = s0 { + // an exact result is the same for all rounding modes + assert_eq!(s0, s1); + assert_eq!(s0, s2); + assert_eq!(s0, s3); + + assert_eq!(xd, xu); + assert_eq!(xd, xz); + assert_eq!(xd, xn); + } else { + assert!([s0, s1, s2, s3].into_iter().all(Status::inexact)); + + let xd = f16::from_bits(xd as u16); + let xu = f16::from_bits(xu as u16); + let xz = f16::from_bits(xz as u16); + let xn = f16::from_bits(xn as u16); + + assert_biteq!(xd.next_up(), xu, "s={s}, xd={xd:?}, xu={xu:?}"); + + let signs = [xd, xu, xz, xn].map(f16::is_sign_negative); + + if signs == [true; 4] { + assert_biteq!(xz, xu); + } else { + assert_eq!(signs, [false; 4]); + assert_biteq!(xz, xd); + } + + if xn.to_bits() != xd.to_bits() { + assert_biteq!(xn, xu); + } + } + Ok(()) + } + #[test] + #[cfg(f16_enabled)] + fn test_rounding() { + let n = 1_i32 << 14; + for i in -n..n { + let u = i.rotate_right(11) as u32; + let s = format!("{}", Hexf(f32::from_bits(u))); + assert!(rounding_properties(&s).is_ok()); + } + } + + #[test] + fn test_parse_any() { + for k in -149..=127 { + let s = format!("0x1p{k}"); + let x = hf32(&s); + let y = if k < 0 { 0.5f32.powi(-k) } else { 2.0f32.powi(k) }; + assert_eq!(x, y); + } + + let mut s = *b"0x.0000000p-121"; + for e in 0..40 { + for k in 0..(1 << 15) { + let expected = f32::from_bits(k) * 2.0f32.powi(e); + let x = hf32(std::str::from_utf8(&s).unwrap()); + assert_eq!( + x.to_bits(), + expected.to_bits(), + "\ + e={e}\n\ + k={k}\n\ + x={x}\n\ + expected={expected}\n\ + s={}\n\ + f32::from_bits(k)={}\n\ + 2.0f32.powi(e)={}\ + ", + std::str::from_utf8(&s).unwrap(), + f32::from_bits(k), + 2.0f32.powi(e), + ); + for i in (3..10).rev() { + if s[i] == b'f' { + s[i] = b'0'; + } else if s[i] == b'9' { + s[i] = b'a'; + break; + } else { + s[i] += 1; + break; + } + } + } + for i in (12..15).rev() { + if s[i] == b'0' { + s[i] = b'9'; + } else { + s[i] -= 1; + break; + } + } + for i in (3..10).rev() { + s[i] = b'0'; + } + } + } + + // FIXME: this test is causing failures that are likely UB on various platforms + #[cfg(all(target_arch = "x86_64", target_os = "linux"))] + #[test] + #[cfg(f128_enabled)] + fn rounding() { + let pi = std::f128::consts::PI; + let s = format!("{}", Hexf(pi)); + + for k in 0..=111 { + let (bits, status) = parse_any(&s, 128 - k, 112 - k, Round::Nearest).unwrap(); + let scale = (1u128 << (112 - k - 1)) as f128; + let expected = (pi * scale).round_ties_even() / scale; + assert_eq!(bits << k, expected.to_bits(), "k = {k}, s = {s}"); + assert_eq!(expected != pi, status.inexact()); + } + } + #[test] + fn rounding_extreme_underflow() { + for k in 1..1000 { + let s = format!("0x1p{}", -149 - k); + let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; + assert_eq!(bits, 0, "{s} should round to zero, got bits={bits}"); + assert!(status.underflow(), "should indicate underflow when parsing {s}"); + assert!(status.inexact(), "should indicate inexact when parsing {s}"); + } + } + #[test] + fn long_tail() { + for k in 1..1000 { + let s = format!("0x1.{}p0", "0".repeat(k)); + let Ok(bits) = parse_hex_exact(&s, 32, 23) else { panic!("parsing {s} failed") }; + assert_eq!(f32::from_bits(bits as u32), 1.0); + + let s = format!("0x1.{}1p0", "0".repeat(k)); + let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; + if status.inexact() { + assert!(1.0 == f32::from_bits(bits as u32)); + } else { + assert!(1.0 < f32::from_bits(bits as u32)); + } + } + } + // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to + // hide them from the AST. + #[cfg(f16_enabled)] + macro_rules! f16_tests { + () => { + #[test] + fn test_f16() { + let checks = [ + ("0x.1234p+16", (0x1234 as f16).to_bits()), + ("0x1.234p+12", (0x1234 as f16).to_bits()), + ("0x12.34p+8", (0x1234 as f16).to_bits()), + ("0x123.4p+4", (0x1234 as f16).to_bits()), + ("0x1234p+0", (0x1234 as f16).to_bits()), + ("0x1234.p+0", (0x1234 as f16).to_bits()), + ("0x1234.0p+0", (0x1234 as f16).to_bits()), + ("0x1.ffcp+15", f16::MAX.to_bits()), + ("0x1.0p+1", 2.0f16.to_bits()), + ("0x1.0p+0", 1.0f16.to_bits()), + ("0x1.ffp+8", 0x5ffc), + ("+0x1.ffp+8", 0x5ffc), + ("0x1p+0", 0x3c00), + ("0x1.998p-4", 0x2e66), + ("0x1.9p+6", 0x5640), + ("0x0.0p0", 0.0f16.to_bits()), + ("-0x0.0p0", (-0.0f16).to_bits()), + ("0x1.0p0", 1.0f16.to_bits()), + ("0x1.998p-4", (0.1f16).to_bits()), + ("-0x1.998p-4", (-0.1f16).to_bits()), + ("0x0.123p-12", 0x0123), + ("0x1p-24", 0x0001), + ("nan", f16::NAN.to_bits()), + ("-nan", (-f16::NAN).to_bits()), + ("inf", f16::INFINITY.to_bits()), + ("-inf", f16::NEG_INFINITY.to_bits()), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + assert!(rounding_properties(s).is_ok()); + let act = hf16(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#06x} != {exp:#06x}\nact: {act:#018b}\nexp: {exp:#018b}" + ); + } + } + + #[test] + fn test_macros_f16() { + assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); + } + }; + } + + #[cfg(f16_enabled)] + f16_tests!(); + + #[test] + fn test_f32() { + let checks = [ + ("0x.1234p+16", (0x1234 as f32).to_bits()), + ("0x1.234p+12", (0x1234 as f32).to_bits()), + ("0x12.34p+8", (0x1234 as f32).to_bits()), + ("0x123.4p+4", (0x1234 as f32).to_bits()), + ("0x1234p+0", (0x1234 as f32).to_bits()), + ("0x1234.p+0", (0x1234 as f32).to_bits()), + ("0x1234.0p+0", (0x1234 as f32).to_bits()), + ("0x1.fffffep+127", f32::MAX.to_bits()), + ("0x1.0p+1", 2.0f32.to_bits()), + ("0x1.0p+0", 1.0f32.to_bits()), + ("0x1.ffep+8", 0x43fff000), + ("+0x1.ffep+8", 0x43fff000), + ("0x1p+0", 0x3f800000), + ("0x1.99999ap-4", 0x3dcccccd), + ("0x1.9p+6", 0x42c80000), + ("0x1.2d5ed2p+20", 0x4996af69), + ("-0x1.348eb8p+10", 0xc49a475c), + ("-0x1.33dcfep-33", 0xaf19ee7f), + ("0x0.0p0", 0.0f32.to_bits()), + ("-0x0.0p0", (-0.0f32).to_bits()), + ("0x1.0p0", 1.0f32.to_bits()), + ("0x1.99999ap-4", (0.1f32).to_bits()), + ("-0x1.99999ap-4", (-0.1f32).to_bits()), + ("0x1.111114p-127", 0x00444445), + ("0x1.23456p-130", 0x00091a2b), + ("0x1p-149", 0x00000001), + ("nan", f32::NAN.to_bits()), + ("-nan", (-f32::NAN).to_bits()), + ("inf", f32::INFINITY.to_bits()), + ("-inf", f32::NEG_INFINITY.to_bits()), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + let act = hf32(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#010x} != {exp:#010x}\nact: {act:#034b}\nexp: {exp:#034b}" + ); + } + } + + #[test] + fn test_f64() { + let checks = [ + ("0x.1234p+16", (0x1234 as f64).to_bits()), + ("0x1.234p+12", (0x1234 as f64).to_bits()), + ("0x12.34p+8", (0x1234 as f64).to_bits()), + ("0x123.4p+4", (0x1234 as f64).to_bits()), + ("0x1234p+0", (0x1234 as f64).to_bits()), + ("0x1234.p+0", (0x1234 as f64).to_bits()), + ("0x1234.0p+0", (0x1234 as f64).to_bits()), + ("0x1.ffep+8", 0x407ffe0000000000), + ("0x1p+0", 0x3ff0000000000000), + ("0x1.999999999999ap-4", 0x3fb999999999999a), + ("0x1.9p+6", 0x4059000000000000), + ("0x1.2d5ed1fe1da7bp+20", 0x4132d5ed1fe1da7b), + ("-0x1.348eb851eb852p+10", 0xc09348eb851eb852), + ("-0x1.33dcfe54a3803p-33", 0xbde33dcfe54a3803), + ("0x1.0p0", 1.0f64.to_bits()), + ("0x0.0p0", 0.0f64.to_bits()), + ("-0x0.0p0", (-0.0f64).to_bits()), + ("0x1.999999999999ap-4", 0.1f64.to_bits()), + ("0x1.999999999998ap-4", (0.1f64 - f64::EPSILON).to_bits()), + ("-0x1.999999999999ap-4", (-0.1f64).to_bits()), + ("-0x1.999999999998ap-4", (-0.1f64 + f64::EPSILON).to_bits()), + ("0x0.8000000000001p-1022", 0x0008000000000001), + ("0x0.123456789abcdp-1022", 0x000123456789abcd), + ("0x0.0000000000002p-1022", 0x0000000000000002), + ("nan", f64::NAN.to_bits()), + ("-nan", (-f64::NAN).to_bits()), + ("inf", f64::INFINITY.to_bits()), + ("-inf", f64::NEG_INFINITY.to_bits()), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + let act = hf64(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#018x} != {exp:#018x}\nact: {act:#066b}\nexp: {exp:#066b}" + ); + } + } + + // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to + // hide them from the AST. + #[cfg(f128_enabled)] + macro_rules! f128_tests { + () => { + #[test] + fn test_f128() { + let checks = [ + ("0x.1234p+16", (0x1234 as f128).to_bits()), + ("0x1.234p+12", (0x1234 as f128).to_bits()), + ("0x12.34p+8", (0x1234 as f128).to_bits()), + ("0x123.4p+4", (0x1234 as f128).to_bits()), + ("0x1234p+0", (0x1234 as f128).to_bits()), + ("0x1234.p+0", (0x1234 as f128).to_bits()), + ("0x1234.0p+0", (0x1234 as f128).to_bits()), + ("0x1.ffffffffffffffffffffffffffffp+16383", f128::MAX.to_bits()), + ("0x1.0p+1", 2.0f128.to_bits()), + ("0x1.0p+0", 1.0f128.to_bits()), + ("0x1.ffep+8", 0x4007ffe0000000000000000000000000), + ("+0x1.ffep+8", 0x4007ffe0000000000000000000000000), + ("0x1p+0", 0x3fff0000000000000000000000000000), + ("0x1.999999999999999999999999999ap-4", 0x3ffb999999999999999999999999999a), + ("0x1.9p+6", 0x40059000000000000000000000000000), + ("0x0.0p0", 0.0f128.to_bits()), + ("-0x0.0p0", (-0.0f128).to_bits()), + ("0x1.0p0", 1.0f128.to_bits()), + ("0x1.999999999999999999999999999ap-4", (0.1f128).to_bits()), + ("-0x1.999999999999999999999999999ap-4", (-0.1f128).to_bits()), + ("0x0.abcdef0123456789abcdef012345p-16382", 0x0000abcdef0123456789abcdef012345), + ("0x1p-16494", 0x00000000000000000000000000000001), + ("nan", f128::NAN.to_bits()), + ("-nan", (-f128::NAN).to_bits()), + ("inf", f128::INFINITY.to_bits()), + ("-inf", f128::NEG_INFINITY.to_bits()), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + let act = hf128(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#034x} != {exp:#034x}\nact: {act:#0130b}\nexp: {exp:#0130b}" + ); + } + } + + #[test] + fn test_macros_f128() { + assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); + } + } + } + + #[cfg(f128_enabled)] + f128_tests!(); + + #[test] + fn test_macros() { + #[cfg(f16_enabled)] + assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); + assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000_u32); + assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000_u64); + #[cfg(f128_enabled)] + assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); + } +} + +#[cfg(test)] +// FIXME(ppc): something with `should_panic` tests cause a SIGILL with ppc64le +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +mod tests_panicking { + extern crate std; + use super::*; + + // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to + // hide them from the AST. + #[cfg(f16_enabled)] + macro_rules! f16_tests { + () => { + #[test] + fn test_f16_almost_extra_precision() { + // Exact maximum precision allowed + hf16("0x1.ffcp+0"); + } + + #[test] + #[should_panic(expected = "the value is too precise")] + fn test_f16_extra_precision() { + // One bit more than the above. + hf16("0x1.ffdp+0"); + } + + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f16_overflow() { + // One bit more than the above. + hf16("0x1p+16"); + } + + #[test] + fn test_f16_tiniest() { + let x = hf16("0x1.p-24"); + let y = hf16("0x0.001p-12"); + let z = hf16("0x0.8p-23"); + assert_eq!(x, y); + assert_eq!(x, z); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f16_too_tiny() { + hf16("0x1.p-25"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f16_also_too_tiny() { + hf16("0x0.8p-24"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f16_again_too_tiny() { + hf16("0x0.001p-13"); + } + }; + } + + #[cfg(f16_enabled)] + f16_tests!(); + + #[test] + fn test_f32_almost_extra_precision() { + // Exact maximum precision allowed + hf32("0x1.abcdeep+0"); + } + + #[test] + #[should_panic] + fn test_f32_extra_precision2() { + // One bit more than the above. + hf32("0x1.ffffffp+127"); + } + + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f32_overflow() { + // One bit more than the above. + hf32("0x1p+128"); + } + + #[test] + #[should_panic(expected = "the value is too precise")] + fn test_f32_extra_precision() { + // One bit more than the above. + hf32("0x1.abcdefp+0"); + } + + #[test] + fn test_f32_tiniest() { + let x = hf32("0x1.p-149"); + let y = hf32("0x0.0000000000000001p-85"); + let z = hf32("0x0.8p-148"); + assert_eq!(x, y); + assert_eq!(x, z); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f32_too_tiny() { + hf32("0x1.p-150"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f32_also_too_tiny() { + hf32("0x0.8p-149"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f32_again_too_tiny() { + hf32("0x0.0000000000000001p-86"); + } + + #[test] + fn test_f64_almost_extra_precision() { + // Exact maximum precision allowed + hf64("0x1.abcdabcdabcdfp+0"); + } + + #[test] + #[should_panic(expected = "the value is too precise")] + fn test_f64_extra_precision() { + // One bit more than the above. + hf64("0x1.abcdabcdabcdf8p+0"); + } + + // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to + // hide them from the AST. + #[cfg(f128_enabled)] + macro_rules! f128_tests { + () => { + #[test] + fn test_f128_almost_extra_precision() { + // Exact maximum precision allowed + hf128("0x1.ffffffffffffffffffffffffffffp+16383"); + } + + #[test] + #[should_panic(expected = "the value is too precise")] + fn test_f128_extra_precision() { + // Just below the maximum finite. + hf128("0x1.fffffffffffffffffffffffffffe8p+16383"); + } + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f128_extra_precision_overflow() { + // One bit more than the above. Should overflow. + hf128("0x1.ffffffffffffffffffffffffffff8p+16383"); + } + + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f128_overflow() { + // One bit more than the above. + hf128("0x1p+16384"); + } + + #[test] + fn test_f128_tiniest() { + let x = hf128("0x1.p-16494"); + let y = hf128("0x0.0000000000000001p-16430"); + let z = hf128("0x0.8p-16493"); + assert_eq!(x, y); + assert_eq!(x, z); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f128_too_tiny() { + hf128("0x1.p-16495"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f128_again_too_tiny() { + hf128("0x0.0000000000000001p-16431"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f128_also_too_tiny() { + hf128("0x0.8p-16494"); + } + }; + } + + #[cfg(f128_enabled)] + f128_tests!(); +} + +#[cfg(test)] +mod print_tests { + extern crate std; + use std::string::ToString; + + use super::*; + + #[test] + #[cfg(f16_enabled)] + fn test_f16() { + use std::format; + // Exhaustively check that `f16` roundtrips. + for x in 0..=u16::MAX { + let f = f16::from_bits(x); + let s = format!("{}", Hexf(f)); + let from_s = hf16(&s); + + if f.is_nan() && from_s.is_nan() { + continue; + } + + assert_eq!( + f.to_bits(), + from_s.to_bits(), + "{f:?} formatted as {s} but parsed as {from_s:?}" + ); + } + } + + #[test] + #[cfg(f16_enabled)] + fn test_f16_to_f32() { + use std::format; + // Exhaustively check that these are equivalent for all `f16`: + // - `f16 -> f32` + // - `f16 -> str -> f32` + // - `f16 -> f32 -> str -> f32` + // - `f16 -> f32 -> str -> f16 -> f32` + for x in 0..=u16::MAX { + let f16 = f16::from_bits(x); + let s16 = format!("{}", Hexf(f16)); + let f32 = f16 as f32; + let s32 = format!("{}", Hexf(f32)); + + let a = hf32(&s16); + let b = hf32(&s32); + let c = hf16(&s32); + + if f32.is_nan() && a.is_nan() && b.is_nan() && c.is_nan() { + continue; + } + + assert_eq!( + f32.to_bits(), + a.to_bits(), + "{f16:?} : f16 formatted as {s16} which parsed as {a:?} : f16" + ); + assert_eq!( + f32.to_bits(), + b.to_bits(), + "{f32:?} : f32 formatted as {s32} which parsed as {b:?} : f32" + ); + assert_eq!( + f32.to_bits(), + (c as f32).to_bits(), + "{f32:?} : f32 formatted as {s32} which parsed as {c:?} : f16" + ); + } + } + #[test] + fn spot_checks() { + assert_eq!(Hexf(f32::MAX).to_string(), "0x1.fffffep+127"); + assert_eq!(Hexf(f64::MAX).to_string(), "0x1.fffffffffffffp+1023"); + + assert_eq!(Hexf(f32::MIN).to_string(), "-0x1.fffffep+127"); + assert_eq!(Hexf(f64::MIN).to_string(), "-0x1.fffffffffffffp+1023"); + + assert_eq!(Hexf(f32::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hexf(f64::ZERO).to_string(), "0x0p+0"); + + assert_eq!(Hexf(f32::NEG_ZERO).to_string(), "-0x0p+0"); + assert_eq!(Hexf(f64::NEG_ZERO).to_string(), "-0x0p+0"); + + assert_eq!(Hexf(f32::NAN).to_string(), "NaN"); + assert_eq!(Hexf(f64::NAN).to_string(), "NaN"); + + assert_eq!(Hexf(f32::INFINITY).to_string(), "inf"); + assert_eq!(Hexf(f64::INFINITY).to_string(), "inf"); + + assert_eq!(Hexf(f32::NEG_INFINITY).to_string(), "-inf"); + assert_eq!(Hexf(f64::NEG_INFINITY).to_string(), "-inf"); + + #[cfg(f16_enabled)] + { + assert_eq!(Hexf(f16::MAX).to_string(), "0x1.ffcp+15"); + assert_eq!(Hexf(f16::MIN).to_string(), "-0x1.ffcp+15"); + assert_eq!(Hexf(f16::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hexf(f16::NEG_ZERO).to_string(), "-0x0p+0"); + assert_eq!(Hexf(f16::NAN).to_string(), "NaN"); + assert_eq!(Hexf(f16::INFINITY).to_string(), "inf"); + assert_eq!(Hexf(f16::NEG_INFINITY).to_string(), "-inf"); + } + + #[cfg(f128_enabled)] + { + assert_eq!(Hexf(f128::MAX).to_string(), "0x1.ffffffffffffffffffffffffffffp+16383"); + assert_eq!(Hexf(f128::MIN).to_string(), "-0x1.ffffffffffffffffffffffffffffp+16383"); + assert_eq!(Hexf(f128::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hexf(f128::NEG_ZERO).to_string(), "-0x0p+0"); + assert_eq!(Hexf(f128::NAN).to_string(), "NaN"); + assert_eq!(Hexf(f128::INFINITY).to_string(), "inf"); + assert_eq!(Hexf(f128::NEG_INFINITY).to_string(), "-inf"); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs new file mode 100644 index 00000000000..491adb1f22c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -0,0 +1,451 @@ +use core::{cmp, fmt, ops}; + +/// Minimal integer implementations needed on all integer types, including wide integers. +pub trait MinInt: + Copy + + fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type Unsigned: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} + +/// Access the associated `OtherSign` type from an int (helper to avoid ambiguous associated +/// types). +pub type OtherSign = ::OtherSign; + +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub trait Int: + MinInt + + fmt::Display + + fmt::Binary + + fmt::LowerHex + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shl + + ops::Shl + + ops::Shr + + ops::Shr + + ops::BitXor + + ops::BitAnd + + cmp::Ord + + From + + CastFrom + + CastFrom + + CastFrom + + CastFrom + + CastFrom + + CastInto + + CastInto + + CastInto + + CastInto + + CastInto +{ + fn signed(self) -> OtherSign; + fn unsigned(self) -> Self::Unsigned; + fn from_unsigned(unsigned: Self::Unsigned) -> Self; + fn abs(self) -> Self; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::Unsigned; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn checked_add(self, other: Self) -> Option; + fn checked_sub(self, other: Self) -> Option; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn overflowing_sub(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn checked_add(self, other: Self) -> Option { + self.checked_add(other) + } + + fn checked_sub(self, other: Self) -> Option { + self.checked_sub(other) + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn overflowing_sub(self, other: Self) -> (Self, bool) { + ::overflowing_sub(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + // On our older MSRV, this resolves to the trait method. Which won't actually work, + // but this is only called behind other gates. + #[allow(clippy::incompatible_msrv)] + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type Unsigned = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn signed(self) -> $ity { + self as $ity + } + + fn unsigned(self) -> Self { + self + } + + fn abs(self) -> Self { + unimplemented!() + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn abs_diff(self, other: Self) -> Self { + self.abs_diff(other) + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type Unsigned = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn signed(self) -> Self { + self + } + + fn unsigned(self) -> $uty { + self as $uty + } + + fn abs(self) -> Self { + self.abs() + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn abs_diff(self, other: Self) -> $uty { + self.abs_diff(other) + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +/// Trait for integers twice the bit width of another integer. This is implemented for all +/// primitives except for `u8`, because there is not a smaller primitive. +pub trait DInt: MinInt { + /// Integer that is half the bit width of the integer this trait is implemented for + type H: HInt; + + /// Returns the low half of `self` + fn lo(self) -> Self::H; + /// Returns the high half of `self` + fn hi(self) -> Self::H; + /// Returns the low and high halves of `self` as a tuple + fn lo_hi(self) -> (Self::H, Self::H) { + (self.lo(), self.hi()) + } + /// Constructs an integer using lower and higher half parts + #[allow(unused)] + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { + lo.zero_widen() | hi.widen_hi() + } +} + +/// Trait for integers half the bit width of another integer. This is implemented for all +/// primitives except for `u128`, because it there is not a larger primitive. +pub trait HInt: Int { + /// Integer that is double the bit width of the integer this trait is implemented for + type D: DInt + MinInt; + + // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for + // unknown reasons this can cause infinite recursion when optimizations are disabled. See + // for context. + + /// Widens (using default extension) the integer to have double bit width + fn widen(self) -> Self::D; + /// Widens (zero extension only) the integer to have double bit width. This is needed to get + /// around problems with associated type bounds (such as `Int`) being unstable + fn zero_widen(self) -> Self::D; + /// Widens the integer to have double bit width and shifts the integer into the higher bits + #[allow(unused)] + fn widen_hi(self) -> Self::D; + /// Widening multiplication with zero widening. This cannot overflow. + fn zero_widen_mul(self, rhs: Self) -> Self::D; + /// Widening multiplication. This cannot overflow. + fn widen_mul(self, rhs: Self) -> Self::D; +} + +macro_rules! impl_d_int { + ($($X:ident $D:ident),*) => { + $( + impl DInt for $D { + type H = $X; + + fn lo(self) -> Self::H { + self as $X + } + fn hi(self) -> Self::H { + (self >> <$X as MinInt>::BITS) as $X + } + } + )* + }; +} + +macro_rules! impl_h_int { + ($($H:ident $uH:ident $X:ident),*) => { + $( + impl HInt for $H { + type D = $X; + + fn widen(self) -> Self::D { + self as $X + } + fn zero_widen(self) -> Self::D { + (self as $uH) as $X + } + fn zero_widen_mul(self, rhs: Self) -> Self::D { + self.zero_widen().wrapping_mul(rhs.zero_widen()) + } + fn widen_mul(self, rhs: Self) -> Self::D { + self.widen().wrapping_mul(rhs.widen()) + } + fn widen_hi(self) -> Self::D { + (self as $X) << ::BITS + } + } + )* + }; +} + +impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); +impl_h_int!( + u8 u8 u16, + u16 u16 u32, + u32 u32 u64, + u64 u64 u128, + i8 u8 i16, + i16 u16 i32, + i32 u32 i64, + i64 u64 i128 +); + +/// Trait to express (possibly lossy) casting of integers +pub trait CastInto: Copy { + /// By default, casts should be exact. + fn cast(self) -> T; + + /// Call for casts that are expected to truncate. + fn cast_lossy(self) -> T; +} + +pub trait CastFrom: Copy { + /// By default, casts should be exact. + fn cast_from(value: T) -> Self; + + /// Call for casts that are expected to truncate. + fn cast_from_lossy(value: T) -> Self; +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } + + fn cast_from_lossy(value: U) -> Self { + value.cast_lossy() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + // All we can really do to enforce casting rules is check the rules when in + // debug mode. + #[cfg(not(feature = "compiler-builtins"))] + debug_assert!(<$into>::try_from(self).is_ok(), "failed cast from {self}"); + self as $into + } + + fn cast_lossy(self) -> $into { + self as $into + } + } + )*}; +} + +macro_rules! cast_into_float { + ($ty:ty) => { + #[cfg(f16_enabled)] + cast_into_float!($ty; f16); + + cast_into_float!($ty; f32, f64); + + #[cfg(f128_enabled)] + cast_into_float!($ty; f128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + #[cfg(not(feature = "compiler-builtins"))] + debug_assert_eq!(self as $into as $ty, self, "inexact float cast"); + self as $into + } + + fn cast_lossy(self) -> $into { + self as $into + } + } + )*}; +} + +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); + +cast_into_float!(i8); +cast_into_float!(i16); +cast_into_float!(i32); +cast_into_float!(i64); +cast_into_float!(i128); diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs new file mode 100644 index 00000000000..0b72db0e46e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -0,0 +1,157 @@ +/// `libm` cannot have dependencies, so this is vendored directly from the `cfg-if` crate +/// (with some comments stripped for compactness). +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($meta:meta)] { $($tokens:tt)* } + ) else * else { + $($tokens2:tt)* + }) => { + cfg_if! { @__items () ; $( ( ($meta) ($($tokens)*) ), )* ( () ($($tokens2)*) ), } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($i_met:meta)] { $($i_tokens:tt)* } + $( else if #[cfg($e_met:meta)] { $($e_tokens:tt)* } )* + ) => { + cfg_if! { + @__items + () ; + ( ($i_met) ($($i_tokens)*) ), + $( ( ($e_met) ($($e_tokens)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($tokens:tt)*) ), $($rest:tt)*) => { + #[cfg(all($($m,)* not(any($($not),*))))] cfg_if! { @__identity $($tokens)* } + cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to make __apply work out right for different match types, + // because of how macros matching/expand stuff. + (@__identity $($tokens:tt)*) => { $($tokens)* }; +} + +/// Choose between using an arch-specific implementation and the function body. Returns directly +/// if the arch implementation is used, otherwise continue with the rest of the function. +/// +/// Specify a `use_arch` meta field if an architecture-specific implementation is provided. +/// These live in the `math::arch::some_target_arch` module. +/// +/// Specify a `use_arch_required` meta field if something architecture-specific must be used +/// regardless of feature configuration (`force-soft-floats`). +/// +/// The passed meta options do not need to account for the `arch` target feature. +macro_rules! select_implementation { + ( + name: $fn_name:ident, + // Configuration meta for when to use arch-specific implementation that requires hard + // float ops + $( use_arch: $use_arch:meta, )? + // Configuration meta for when to use the arch module regardless of whether softfloats + // have been requested. + $( use_arch_required: $use_arch_required:meta, )? + args: $($arg:ident),+ , + ) => { + // FIXME: these use paths that are a pretty fragile (`super`). We should figure out + // something better w.r.t. how this is vendored into compiler-builtins. + + // However, we do need a few things from `arch` that are used even with soft floats. + select_implementation! { + @cfg $($use_arch_required)?; + if true { + return super::arch::$fn_name( $($arg),+ ); + } + } + + // By default, never use arch-specific implementations if we have force-soft-floats + #[cfg(arch_enabled)] + select_implementation! { + @cfg $($use_arch)?; + // Wrap in `if true` to avoid unused warnings + if true { + return super::arch::$fn_name( $($arg),+ ); + } + } + }; + + // Coalesce helper to construct an expression only if a config is provided + (@cfg ; $ex:expr) => { }; + (@cfg $provided:meta; $ex:expr) => { #[cfg($provided)] $ex }; +} + +/// Construct a 16-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[cfg(f16_enabled)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] +#[allow(unused_macros)] +macro_rules! hf16 { + ($s:literal) => {{ + const X: f16 = $crate::support::hf16($s); + X + }}; +} + +/// Construct a 32-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[allow(unused_macros)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] +macro_rules! hf32 { + ($s:literal) => {{ + const X: f32 = $crate::support::hf32($s); + X + }}; +} + +/// Construct a 64-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[allow(unused_macros)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] +macro_rules! hf64 { + ($s:literal) => {{ + const X: f64 = $crate::support::hf64($s); + X + }}; +} + +/// Construct a 128-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[cfg(f128_enabled)] +#[allow(unused_macros)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] +macro_rules! hf128 { + ($s:literal) => {{ + const X: f128 = $crate::support::hf128($s); + X + }}; +} + +/// Assert `F::biteq` with better messages. +#[cfg(test)] +macro_rules! assert_biteq { + ($left:expr, $right:expr, $($tt:tt)*) => {{ + use $crate::support::Int; + let l = $left; + let r = $right; + let bits = Int::leading_zeros(l.to_bits() - l.to_bits()); // hack to get the width from the value + assert!( + l.biteq(r), + "{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", + format_args!($($tt)*), + lb = l.to_bits(), + rb = r.to_bits(), + width = ((bits / 4) + 2) as usize, + + ); + }}; + ($left:expr, $right:expr $(,)?) => { + assert_biteq!($left, $right, "") + }; +} diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs new file mode 100644 index 00000000000..ee3f2bbdf02 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -0,0 +1,29 @@ +#[macro_use] +pub mod macros; +mod big; +mod env; +mod float_traits; +pub mod hex_float; +mod int_traits; + +#[allow(unused_imports)] +pub use big::{i256, u256}; +pub use env::{FpResult, Round, Status}; +#[allow(unused_imports)] +pub use float_traits::{DFloat, Float, HFloat, IntTy}; +pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; +#[cfg(f16_enabled)] +#[allow(unused_imports)] +pub use hex_float::hf16; +#[cfg(f128_enabled)] +#[allow(unused_imports)] +pub use hex_float::hf128; +#[allow(unused_imports)] +pub use hex_float::{Hexf, hf32, hf64}; +pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; + +/// Hint to the compiler that the current path is cold. +pub fn cold_path() { + #[cfg(intrinsics_enabled)] + core::intrinsics::cold_path(); +} diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs new file mode 100644 index 00000000000..a074ca5540a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -0,0 +1,70 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */ +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +use super::{k_tan, rem_pio2}; + +// tan(x) +// Return tangent function of x. +// +// kernel function: +// k_tan ... tangent function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded + +/// The tangent of `x` (f64). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tan(x: f64) -> f64 { + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e400000 { + /* |x| < 2**-27 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00100000 { x / x1p120 as f64 } else { x + x1p120 as f64 }); + return x; + } + return k_tan(x, 0.0, 0); + } + + /* tan(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction */ + let (n, y0, y1) = rem_pio2(x); + k_tan(y0, y1, n & 1) +} diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs new file mode 100644 index 00000000000..7586aae4c7e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -0,0 +1,77 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_tanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f64::consts::FRAC_PI_2; + +use super::{k_tanf, rem_pio2f}; + +/* Small multiples of pi/2 rounded to double precision. */ +const T1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +/// The tangent of `x` (f32). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tanf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); + return x; + } + return k_tanf(x64, false); + } + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + return k_tanf(if sign { x64 + T1_PIO2 } else { x64 - T1_PIO2 }, true); + } else { + return k_tanf(if sign { x64 + T2_PIO2 } else { x64 - T2_PIO2 }, false); + } + } + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + return k_tanf(if sign { x64 + T3_PIO2 } else { x64 - T3_PIO2 }, true); + } else { + return k_tanf(if sign { x64 + T4_PIO2 } else { x64 - T4_PIO2 }, false); + } + } + + /* tan(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x - x; + } + + /* argument reduction */ + let (n, y) = rem_pio2f(x); + k_tanf(y, n & 1 != 0) +} diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs new file mode 100644 index 00000000000..cc0abe4fcb2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tanh.rs @@ -0,0 +1,53 @@ +use super::expm1; + +/* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) + * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) + * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) + */ + +/// The hyperbolic tangent of `x` (f64). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tanh(mut x: f64) -> f64 { + let mut uf: f64 = x; + let mut ui: u64 = f64::to_bits(uf); + + let w: u32; + let sign: bool; + let mut t: f64; + + /* x = |x| */ + sign = ui >> 63 != 0; + ui &= !1 / 2; + uf = f64::from_bits(ui); + x = uf; + w = (ui >> 32) as u32; + + if w > 0x3fe193ea { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if w > 0x40340000 { + /* |x| > 20 or nan */ + /* note: this branch avoids raising overflow */ + t = 1.0 - 0.0 / x; + } else { + t = expm1(2.0 * x); + t = 1.0 - 2.0 / (t + 2.0); + } + } else if w > 0x3fd058ae { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1(2.0 * x); + t = t / (t + 2.0); + } else if w >= 0x00100000 { + /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ + t = expm1(-2.0 * x); + t = -t / (t + 2.0); + } else { + /* |x| is subnormal */ + /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ + force_eval!(x as f32); + t = x; + } + + if sign { -t } else { t } +} diff --git a/library/compiler-builtins/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/src/math/tanhf.rs new file mode 100644 index 00000000000..fffbba6c6ec --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tanhf.rs @@ -0,0 +1,38 @@ +use super::expm1f; + +/// The hyperbolic tangent of `x` (f32). +/// +/// `x` is specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tanhf(mut x: f32) -> f32 { + /* x = |x| */ + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + x = f32::from_bits(ix); + let w = ix; + + let tt = if w > 0x3f0c9f54 { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if w > 0x41200000 { + /* |x| > 10 */ + 1. + 0. / x + } else { + let t = expm1f(2. * x); + 1. - 2. / (t + 2.) + } + } else if w > 0x3e82c578 { + /* |x| > log(5/3)/2 ~= 0.2554 */ + let t = expm1f(2. * x); + t / (t + 2.) + } else if w >= 0x00800000 { + /* |x| >= 0x1p-126 */ + let t = expm1f(-2. * x); + -t / (t + 2.) + } else { + /* |x| is subnormal */ + force_eval!(x * x); + x + }; + if sign { -tt } else { tt } +} diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs new file mode 100644 index 00000000000..3059860646a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tgamma.rs @@ -0,0 +1,209 @@ +/* +"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) +"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) +"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) + +approximation method: + + (x - 0.5) S(x) +Gamma(x) = (x + g - 0.5) * ---------------- + exp(x + g - 0.5) + +with + a1 a2 a3 aN +S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] + x + 1 x + 2 x + 3 x + N + +with a0, a1, a2, a3,.. aN constants which depend on g. + +for x < 0 the following reflection formula is used: + +Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) + +most ideas and constants are from boost and python +*/ +use super::{exp, floor, k_cos, k_sin, pow}; + +const PI: f64 = 3.141592653589793238462643383279502884; + +/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ +fn sinpi(mut x: f64) -> f64 { + let mut n: isize; + + /* argument reduction: x = |x| mod 2 */ + /* spurious inexact when x is odd int */ + x = x * 0.5; + x = 2.0 * (x - floor(x)); + + /* reduce x into [-.25,.25] */ + n = (4.0 * x) as isize; + n = div!(n + 1, 2); + x -= (n as f64) * 0.5; + + x *= PI; + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + // 0 + _ => k_sin(x, 0.0, 0), + } +} + +const N: usize = 12; +//static const double g = 6.024680040776729583740234375; +const GMHALF: f64 = 5.524680040776729583740234375; +const SNUM: [f64; N + 1] = [ + 23531376880.410759688572007674451636754734846804940, + 42919803642.649098768957899047001988850926355848959, + 35711959237.355668049440185451547166705960488635843, + 17921034426.037209699919755754458931112671403265390, + 6039542586.3520280050642916443072979210699388420708, + 1439720407.3117216736632230727949123939715485786772, + 248874557.86205415651146038641322942321632125127801, + 31426415.585400194380614231628318205362874684987640, + 2876370.6289353724412254090516208496135991145378768, + 186056.26539522349504029498971604569928220784236328, + 8071.6720023658162106380029022722506138218516325024, + 210.82427775157934587250973392071336271166969580291, + 2.5066282746310002701649081771338373386264310793408, +]; +const SDEN: [f64; N + 1] = [ + 0.0, + 39916800.0, + 120543840.0, + 150917976.0, + 105258076.0, + 45995730.0, + 13339535.0, + 2637558.0, + 357423.0, + 32670.0, + 1925.0, + 66.0, + 1.0, +]; +/* n! for small integer n */ +const FACT: [f64; 23] = [ + 1.0, + 1.0, + 2.0, + 6.0, + 24.0, + 120.0, + 720.0, + 5040.0, + 40320.0, + 362880.0, + 3628800.0, + 39916800.0, + 479001600.0, + 6227020800.0, + 87178291200.0, + 1307674368000.0, + 20922789888000.0, + 355687428096000.0, + 6402373705728000.0, + 121645100408832000.0, + 2432902008176640000.0, + 51090942171709440000.0, + 1124000727777607680000.0, +]; + +/* S(x) rational function for positive x */ +fn s(x: f64) -> f64 { + let mut num: f64 = 0.0; + let mut den: f64 = 0.0; + + /* to avoid overflow handle large x differently */ + if x < 8.0 { + for i in (0..=N).rev() { + num = num * x + i!(SNUM, i); + den = den * x + i!(SDEN, i); + } + } else { + for i in 0..=N { + num = num / x + i!(SNUM, i); + den = den / x + i!(SDEN, i); + } + } + return num / den; +} + +/// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tgamma(mut x: f64) -> f64 { + let u: u64 = x.to_bits(); + let absx: f64; + let mut y: f64; + let mut dy: f64; + let mut z: f64; + let mut r: f64; + let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; + let sign: bool = (u >> 63) != 0; + + /* special cases */ + if ix >= 0x7ff00000 { + /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ + return x + f64::INFINITY; + } + if ix < ((0x3ff - 54) << 20) { + /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ + return 1.0 / x; + } + + /* integer arguments */ + /* raise inexact when non-integer */ + if x == floor(x) { + if sign { + return 0.0 / 0.0; + } + if x <= FACT.len() as f64 { + return i!(FACT, (x as usize) - 1); + } + } + + /* x >= 172: tgamma(x)=inf with overflow */ + /* x =< -184: tgamma(x)=+-0 with underflow */ + if ix >= 0x40670000 { + /* |x| >= 184 */ + if sign { + let x1p_126 = f64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 + force_eval!((x1p_126 / x) as f32); + if floor(x) * 0.5 == floor(x * 0.5) { + return 0.0; + } else { + return -0.0; + } + } + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 + x *= x1p1023; + return x; + } + + absx = if sign { -x } else { x }; + + /* handle the error of x + g - 0.5 */ + y = absx + GMHALF; + if absx > GMHALF { + dy = y - absx; + dy -= GMHALF; + } else { + dy = y - GMHALF; + dy -= absx; + } + + z = absx - 0.5; + r = s(absx) * exp(-y); + if x < 0.0 { + /* reflection formula for negative x */ + /* sinpi(absx) is not 0, integers are already handled */ + r = -PI / (sinpi(absx) * absx * r); + dy = -dy; + z = -z; + } + r += dy * (GMHALF + 0.5) * r / y; + z = pow(y, 0.5 * z); + y = r * z * z; + return y; +} diff --git a/library/compiler-builtins/libm/src/math/tgammaf.rs b/library/compiler-builtins/libm/src/math/tgammaf.rs new file mode 100644 index 00000000000..fe178f7a3c0 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tgammaf.rs @@ -0,0 +1,7 @@ +use super::tgamma; + +/// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tgammaf(x: f32) -> f32 { + tgamma(x as f64) as f32 +} diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs new file mode 100644 index 00000000000..fa50d55e136 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -0,0 +1,53 @@ +/// Rounds the number toward 0 to the closest integral value (f16). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf16(x: f16) -> f16 { + super::generic::trunc(x) +} + +/// Rounds the number toward 0 to the closest integral value (f32). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf(x: f32) -> f32 { + select_implementation! { + name: truncf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::trunc(x) +} + +/// Rounds the number toward 0 to the closest integral value (f64). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn trunc(x: f64) -> f64 { + select_implementation! { + name: trunc, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::trunc(x) +} + +/// Rounds the number toward 0 to the closest integral value (f128). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf128(x: f128) -> f128 { + super::generic::trunc(x) +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::truncf(1.1), 1.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs new file mode 100644 index 00000000000..14533a26706 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -0,0 +1,23 @@ +/// Rounds the number toward 0 to the closest integral value (f32). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf(x: f32) -> f32 { + select_implementation! { + name: truncf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::trunc(x) +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::truncf(1.1), 1.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/truncf128.rs b/library/compiler-builtins/libm/src/math/truncf128.rs new file mode 100644 index 00000000000..9dccc0d0e9d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/truncf128.rs @@ -0,0 +1,7 @@ +/// Rounds the number toward 0 to the closest integral value (f128). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf128(x: f128) -> f128 { + super::generic::trunc(x) +} diff --git a/library/compiler-builtins/libm/src/math/truncf16.rs b/library/compiler-builtins/libm/src/math/truncf16.rs new file mode 100644 index 00000000000..d7c3d225cf9 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/truncf16.rs @@ -0,0 +1,7 @@ +/// Rounds the number toward 0 to the closest integral value (f16). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf16(x: f16) -> f16 { + super::generic::trunc(x) +} -- cgit 1.4.1-3-g733a5 From ca5c4ed8d7db731470395055d8f438f0abe7a18a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 21:25:19 +0000 Subject: Fix the release-plz job --- .../.github/workflows/publish.yaml | 9 ++------ .../etc/libm/.github/workflows/publish.yaml | 27 ---------------------- 2 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 library/compiler-builtins/etc/libm/.github/workflows/publish.yaml diff --git a/library/compiler-builtins/.github/workflows/publish.yaml b/library/compiler-builtins/.github/workflows/publish.yaml index 7d6a8df0305..85a33c039d2 100644 --- a/library/compiler-builtins/.github/workflows/publish.yaml +++ b/library/compiler-builtins/.github/workflows/publish.yaml @@ -5,24 +5,19 @@ permissions: contents: write on: - push: - branches: - - master + push: { branches: [master] } jobs: release-plz: name: Release-plz - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: true - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly - - name: Publish `libm` as part of builtins, rather than its own crate - run: rm compiler-builtins/libm/Cargo.toml - name: Run release-plz uses: MarcoIeni/release-plz-action@v0.5 env: diff --git a/library/compiler-builtins/etc/libm/.github/workflows/publish.yaml b/library/compiler-builtins/etc/libm/.github/workflows/publish.yaml deleted file mode 100644 index 15904079d27..00000000000 --- a/library/compiler-builtins/etc/libm/.github/workflows/publish.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: Release-plz - -permissions: - pull-requests: write - contents: write - -on: - push: - branches: - - master - -jobs: - release-plz: - name: Release-plz - runs-on: ubuntu-24.04 - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Install Rust (rustup) - run: rustup update nightly --no-self-update && rustup default nightly - - name: Run release-plz - uses: MarcoIeni/release-plz-action@v0.5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} -- cgit 1.4.1-3-g733a5 From cab8700e84dd49d30cf7a4331a7269c36edf6ae9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 22:15:43 +0000 Subject: libm: Fix crate compilation Update paths and submodules to fix `libm-test` and `util` building so we will be able to add them to the workspace. --- library/compiler-builtins/.gitmodules | 4 ++-- library/compiler-builtins/crates/musl-math-sys/musl | 1 + library/compiler-builtins/crates/util/Cargo.toml | 2 +- library/compiler-builtins/libm-test/Cargo.toml | 6 +++--- library/compiler-builtins/libm-test/build.rs | 4 ++-- library/compiler-builtins/libm-test/src/op.rs | 4 ++-- 6 files changed, 11 insertions(+), 10 deletions(-) create mode 160000 library/compiler-builtins/crates/musl-math-sys/musl diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index ee941a47e77..792ed9ab21f 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,4 +1,4 @@ -[submodule "musl"] - path = libm/crates/musl-math-sys/musl +[submodule "crates/musl-math-sys/musl"] + path = crates/musl-math-sys/musl url = https://git.musl-libc.org/git/musl shallow = true diff --git a/library/compiler-builtins/crates/musl-math-sys/musl b/library/compiler-builtins/crates/musl-math-sys/musl new file mode 160000 index 00000000000..0784374d561 --- /dev/null +++ b/library/compiler-builtins/crates/musl-math-sys/musl @@ -0,0 +1 @@ +Subproject commit 0784374d561435f7c787a555aeab8ede699ed298 diff --git a/library/compiler-builtins/crates/util/Cargo.toml b/library/compiler-builtins/crates/util/Cargo.toml index 4bcb9747297..ae37a723816 100644 --- a/library/compiler-builtins/crates/util/Cargo.toml +++ b/library/compiler-builtins/crates/util/Cargo.toml @@ -13,6 +13,6 @@ unstable-float = ["libm/unstable-float", "libm-test/unstable-float", "rug?/night [dependencies] libm = { path = "../../libm", default-features = false } libm-macros = { path = "../libm-macros" } -libm-test = { path = "../libm-test", default-features = false } +libm-test = { path = "../../libm-test", default-features = false } musl-math-sys = { path = "../musl-math-sys", optional = true } rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "std"] } diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index 5d150b4aeaa..c9b3b795837 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -32,9 +32,9 @@ anyhow = "1.0.97" gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } iai-callgrind = { version = "0.14.0", optional = true } indicatif = { version = "0.17.11", default-features = false } -libm = { path = "../../libm", features = ["unstable-public-internals"] } -libm-macros = { path = "../libm-macros" } -musl-math-sys = { path = "../musl-math-sys", optional = true } +libm = { path = "../libm", features = ["unstable-public-internals"] } +libm-macros = { path = "../crates/libm-macros" } +musl-math-sys = { path = "../crates/musl-math-sys", optional = true } paste = "1.0.15" rand = "0.9.0" rand_chacha = "0.9.0" diff --git a/library/compiler-builtins/libm-test/build.rs b/library/compiler-builtins/libm-test/build.rs index f75e3dda5ff..510ba842f10 100644 --- a/library/compiler-builtins/libm-test/build.rs +++ b/library/compiler-builtins/libm-test/build.rs @@ -1,9 +1,9 @@ -#[path = "../../libm/configure.rs"] +#[path = "../libm/configure.rs"] mod configure; use configure::Config; fn main() { - println!("cargo:rerun-if-changed=../../libm/configure.rs"); + println!("cargo:rerun-if-changed=../libm/configure.rs"); let cfg = Config::from_env(); configure::emit_test_config(&cfg); } diff --git a/library/compiler-builtins/libm-test/src/op.rs b/library/compiler-builtins/libm-test/src/op.rs index 47d72ae58b3..4f251f80df6 100644 --- a/library/compiler-builtins/libm-test/src/op.rs +++ b/library/compiler-builtins/libm-test/src/op.rs @@ -16,12 +16,12 @@ use std::fmt; use std::panic::{RefUnwindSafe, UnwindSafe}; -pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; +pub use shared::{FloatTy, MathOpInfo, Ty, ALL_OPERATIONS}; use crate::{CheckOutput, Float, TupleCall}; mod shared { - include!("../../libm-macros/src/shared.rs"); + include!("../../crates/libm-macros/src/shared.rs"); } /// An enum representing each possible symbol name (`sin`, `sinf`, `sinl`, etc). -- cgit 1.4.1-3-g733a5 From 66fa4fd265d7896ef5262d8408006633ba1b8586 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 21:33:14 +0000 Subject: Add libm and libm-macros to the workspace These should build and test correctly. `libm-test` and others that depend on it are excluded since the necessary CI is not yet set up. --- library/compiler-builtins/Cargo.toml | 36 +++++++++++++++++++++++--- library/compiler-builtins/etc/libm/Cargo.toml | 37 --------------------------- 2 files changed, 33 insertions(+), 40 deletions(-) delete mode 100644 library/compiler-builtins/etc/libm/Cargo.toml diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 2e17c303a5f..155fb00b195 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -7,15 +7,45 @@ members = [ "builtins-test", "builtins-test-intrinsics", "compiler-builtins", + "crates/libm-macros", + "libm", + # FIXME(libm): disabled until tests work in CI + # "libm-test", + # "crates/musl-math-sys", + # "crates/util", ] default-members = [ - "compiler-builtins", "builtins-test", + "compiler-builtins", + "crates/libm-macros", + # FIXME(libm): disabled until tests work in CI + # "crates/libm-test" + "libm", ] [profile.release] -panic = 'abort' +panic = "abort" [profile.dev] -panic = 'abort' +panic = "abort" + +# FIXME(libm): these profiles are needed for testing +# # The default release profile is unchanged. + +# # Release mode with debug assertions +# [profile.release-checked] +# inherits = "release" +# debug-assertions = true +# overflow-checks = true + +# # Release with maximum optimizations, which is very slow to build. This is also +# # what is needed to check `no-panic`. +# [profile.release-opt] +# inherits = "release" +# codegen-units = 1 +# lto = "fat" + +# [profile.bench] +# # Required for iai-callgrind +# debug = true diff --git a/library/compiler-builtins/etc/libm/Cargo.toml b/library/compiler-builtins/etc/libm/Cargo.toml deleted file mode 100644 index 268b6fb0e6d..00000000000 --- a/library/compiler-builtins/etc/libm/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[workspace] -resolver = "2" -members = [ - "libm", - "crates/libm-macros", - "crates/libm-test", - "crates/musl-math-sys", - "crates/util", -] -default-members = [ - "libm", - "crates/libm-macros", - "crates/libm-test" -] -exclude = [ - # Requires `panic = abort` so can't be a member of the workspace - "crates/compiler-builtins-smoke-test", -] - -# The default release profile is unchanged. - -# Release mode with debug assertions -[profile.release-checked] -inherits = "release" -debug-assertions = true -overflow-checks = true - -# Release with maximum optimizations, which is very slow to build. This is also -# what is needed to check `no-panic`. -[profile.release-opt] -inherits = "release" -codegen-units = 1 -lto = "fat" - -[profile.bench] -# Required for iai-callgrind -debug = true -- cgit 1.4.1-3-g733a5 From 569b40209dd83af5decf494541cd96b749813973 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 22:54:23 +0000 Subject: Add a .rustfmt.toml with style edition 2024 Use the 2024 style edition for all crates and enable import sorting. 2024 already applies some smaller heuristics that look good in compiler-builtins, I have dropped `use_small_heuristics` that was set in `libm` because it seems to negatively affect the readibility of anything working with numbers (e.g. collapsing multiple small `if` expressions into a single line). --- library/compiler-builtins/.rustfmt.toml | 4 ++++ library/compiler-builtins/libm/.rustfmt.toml | 5 ----- 2 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/.rustfmt.toml delete mode 100644 library/compiler-builtins/libm/.rustfmt.toml diff --git a/library/compiler-builtins/.rustfmt.toml b/library/compiler-builtins/.rustfmt.toml new file mode 100644 index 00000000000..79ac399c1b6 --- /dev/null +++ b/library/compiler-builtins/.rustfmt.toml @@ -0,0 +1,4 @@ +# This matches rustc +style_edition = "2024" +group_imports = "StdExternalCrate" +imports_granularity = "Module" diff --git a/library/compiler-builtins/libm/.rustfmt.toml b/library/compiler-builtins/libm/.rustfmt.toml deleted file mode 100644 index c73bb9301e3..00000000000 --- a/library/compiler-builtins/libm/.rustfmt.toml +++ /dev/null @@ -1,5 +0,0 @@ -# This matches rustc -style_edition = "2024" -use_small_heuristics = "Max" -group_imports = "StdExternalCrate" -imports_granularity = "Module" -- cgit 1.4.1-3-g733a5 From 8d70be87e6e8f88fdad0f469b894a3ec9a87d3ce Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 22:39:00 +0000 Subject: Run `cargo fmt` on all projects Apply the same formatting rules to both `libm` and `compiler-builtins`. --- .../builtins-test-intrinsics/src/main.rs | 1 + .../builtins-test/benches/float_cmp.rs | 3 +- .../builtins-test/benches/mem_icount.rs | 3 +- .../compiler-builtins/builtins-test/src/bench.rs | 2 +- library/compiler-builtins/builtins-test/src/lib.rs | 1 - .../compiler-builtins/builtins-test/tests/cmp.rs | 1 - .../builtins-test/tests/div_rem.rs | 3 +- .../compiler-builtins/compiler-builtins/build.rs | 7 +- .../compiler-builtins/src/arm_linux.rs | 3 +- .../compiler-builtins/src/float/conv.rs | 3 +- .../compiler-builtins/src/float/div.rs | 7 +- .../compiler-builtins/src/float/mod.rs | 1 - .../compiler-builtins/src/float/pow.rs | 6 +- .../compiler-builtins/src/int/big.rs | 3 +- .../compiler-builtins/src/int/leading_zeros.rs | 6 +- .../compiler-builtins/src/int/mod.rs | 2 - .../src/int/specialized_div_rem/mod.rs | 1 - .../compiler-builtins/src/int/udiv.rs | 1 - .../compiler-builtins/src/mem/x86_64.rs | 3 +- .../crates/libm-macros/src/enums.rs | 31 +++- .../crates/libm-macros/src/lib.rs | 44 ++++-- .../crates/libm-macros/src/parse.rs | 38 ++++- .../crates/libm-macros/src/shared.rs | 175 ++++++++++++++++----- .../crates/musl-math-sys/build.rs | 57 +++++-- library/compiler-builtins/crates/util/src/main.rs | 6 +- .../compiler-builtins/libm-test/benches/random.rs | 17 +- .../libm-test/examples/plot_domains.rs | 8 +- library/compiler-builtins/libm-test/src/domain.rs | 73 ++++++--- library/compiler-builtins/libm-test/src/f8_impl.rs | 4 +- .../compiler-builtins/libm-test/src/generate.rs | 11 +- .../libm-test/src/generate/case_list.rs | 50 ++++-- .../libm-test/src/generate/edge_cases.rs | 6 +- .../libm-test/src/generate/random.rs | 5 +- .../libm-test/src/generate/spaced.rs | 11 +- library/compiler-builtins/libm-test/src/lib.rs | 11 +- library/compiler-builtins/libm-test/src/num.rs | 93 ++++++++--- library/compiler-builtins/libm-test/src/op.rs | 2 +- library/compiler-builtins/libm-test/src/run_cfg.rs | 25 ++- .../compiler-builtins/libm-test/src/test_traits.rs | 10 +- library/compiler-builtins/libm-test/tests/u256.rs | 12 +- .../libm-test/tests/z_extensive/run.rs | 22 ++- library/compiler-builtins/libm/configure.rs | 10 +- library/compiler-builtins/libm/src/lib.rs | 5 +- library/compiler-builtins/libm/src/math/atanf.rs | 9 +- library/compiler-builtins/libm/src/math/cbrt.rs | 6 +- library/compiler-builtins/libm/src/math/erf.rs | 6 +- library/compiler-builtins/libm/src/math/erff.rs | 6 +- library/compiler-builtins/libm/src/math/exp10f.rs | 5 +- library/compiler-builtins/libm/src/math/expm1f.rs | 6 +- library/compiler-builtins/libm/src/math/fma.rs | 10 +- .../compiler-builtins/libm/src/math/fma_wide.rs | 11 +- .../libm/src/math/generic/ceil.rs | 9 +- .../libm/src/math/generic/floor.rs | 9 +- .../libm/src/math/generic/rint.rs | 15 +- .../libm/src/math/generic/sqrt.rs | 5 +- .../libm/src/math/generic/trunc.rs | 15 +- library/compiler-builtins/libm/src/math/ilogb.rs | 6 +- library/compiler-builtins/libm/src/math/k_sin.rs | 6 +- library/compiler-builtins/libm/src/math/log1p.rs | 6 +- library/compiler-builtins/libm/src/math/log1pf.rs | 6 +- library/compiler-builtins/libm/src/math/pow.rs | 48 ++++-- library/compiler-builtins/libm/src/math/powf.rs | 12 +- .../compiler-builtins/libm/src/math/rem_pio2.rs | 20 ++- library/compiler-builtins/libm/src/math/sinf.rs | 12 +- .../compiler-builtins/libm/src/math/support/big.rs | 30 +++- .../libm/src/math/support/big/tests.rs | 168 +++++++++++++++++--- .../compiler-builtins/libm/src/math/support/env.rs | 5 +- .../libm/src/math/support/float_traits.rs | 81 ++++++++-- .../libm/src/math/support/hex_float.rs | 46 ++++-- library/compiler-builtins/libm/src/math/tan.rs | 6 +- library/compiler-builtins/libm/src/math/tanf.rs | 6 +- 71 files changed, 1070 insertions(+), 283 deletions(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs index 21d0a083c71..c4c026368e0 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -480,6 +480,7 @@ mod intrinsics { fn run() { use core::hint::black_box as bb; + use intrinsics::*; // FIXME(f16_f128): some PPC f128 <-> int conversion functions have the wrong names diff --git a/library/compiler-builtins/builtins-test/benches/float_cmp.rs b/library/compiler-builtins/builtins-test/benches/float_cmp.rs index 4493765ec1b..42d6652397d 100644 --- a/library/compiler-builtins/builtins-test/benches/float_cmp.rs +++ b/library/compiler-builtins/builtins-test/benches/float_cmp.rs @@ -1,9 +1,8 @@ #![cfg_attr(f128_enabled, feature(f128))] use builtins_test::float_bench; -use criterion::{Criterion, criterion_main}; - use compiler_builtins::float::cmp; +use criterion::{Criterion, criterion_main}; /// `gt` symbols are allowed to return differing results, they just get compared /// to 0. diff --git a/library/compiler-builtins/builtins-test/benches/mem_icount.rs b/library/compiler-builtins/builtins-test/benches/mem_icount.rs index 63045f6e1ec..bd88cf80c7d 100644 --- a/library/compiler-builtins/builtins-test/benches/mem_icount.rs +++ b/library/compiler-builtins/builtins-test/benches/mem_icount.rs @@ -239,9 +239,10 @@ mod mcmp { } mod mmove { - use super::*; use Spread::{Aligned, Large, Medium, Small}; + use super::*; + struct Cfg { len: usize, spread: Spread, diff --git a/library/compiler-builtins/builtins-test/src/bench.rs b/library/compiler-builtins/builtins-test/src/bench.rs index 45a3a1ad467..2348f6bc973 100644 --- a/library/compiler-builtins/builtins-test/src/bench.rs +++ b/library/compiler-builtins/builtins-test/src/bench.rs @@ -1,6 +1,6 @@ +use alloc::vec::Vec; use core::cell::RefCell; -use alloc::vec::Vec; use compiler_builtins::float::Float; /// Fuzz with these many items to ensure equal functions diff --git a/library/compiler-builtins/builtins-test/src/lib.rs b/library/compiler-builtins/builtins-test/src/lib.rs index a83aea56206..c596ac21380 100644 --- a/library/compiler-builtins/builtins-test/src/lib.rs +++ b/library/compiler-builtins/builtins-test/src/lib.rs @@ -21,7 +21,6 @@ extern crate alloc; use compiler_builtins::float::Float; use compiler_builtins::int::{Int, MinInt}; - use rand_xoshiro::Xoshiro128StarStar; use rand_xoshiro::rand_core::{RngCore, SeedableRng}; diff --git a/library/compiler-builtins/builtins-test/tests/cmp.rs b/library/compiler-builtins/builtins-test/tests/cmp.rs index dbedd213e90..a904dc5f7de 100644 --- a/library/compiler-builtins/builtins-test/tests/cmp.rs +++ b/library/compiler-builtins/builtins-test/tests/cmp.rs @@ -97,7 +97,6 @@ mod float_comparisons { __eqkf2 as __eqtf2, __gekf2 as __getf2, __gtkf2 as __gttf2, __lekf2 as __letf2, __ltkf2 as __lttf2, __nekf2 as __netf2, __unordkf2 as __unordtf2, }; - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] use compiler_builtins::float::cmp::{ __eqtf2, __getf2, __gttf2, __letf2, __lttf2, __netf2, __unordtf2, diff --git a/library/compiler-builtins/builtins-test/tests/div_rem.rs b/library/compiler-builtins/builtins-test/tests/div_rem.rs index 6c0280a3286..5ae653cc90c 100644 --- a/library/compiler-builtins/builtins-test/tests/div_rem.rs +++ b/library/compiler-builtins/builtins-test/tests/div_rem.rs @@ -1,11 +1,10 @@ #![feature(f128)] #![allow(unused_macros)] +use builtins_test::*; use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc}; -use builtins_test::*; - // Division algorithms have by far the nastiest and largest number of edge cases, and experience shows // that sometimes 100_000 iterations of the random fuzzer is needed. diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index d627121f348..04369a4aa4e 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -1,8 +1,11 @@ mod configure; -use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering}; +use std::collections::BTreeMap; +use std::env; +use std::path::PathBuf; +use std::sync::atomic::Ordering; -use configure::{configure_aliases, configure_f16_f128, Target}; +use configure::{Target, configure_aliases, configure_f16_f128}; fn main() { println!("cargo::rerun-if-changed=build.rs"); diff --git a/library/compiler-builtins/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/compiler-builtins/src/arm_linux.rs index aeb3ff3e506..6ce67ba719c 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm_linux.rs @@ -1,6 +1,5 @@ -use core::arch; -use core::mem; use core::sync::atomic::{AtomicU32, Ordering}; +use core::{arch, mem}; // Kernel-provided user-mode helper functions: // https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt diff --git a/library/compiler-builtins/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/compiler-builtins/src/float/conv.rs index 42a526bd524..f5427a11390 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/conv.rs @@ -1,8 +1,7 @@ use core::ops::Neg; -use crate::int::{CastFrom, CastInto, Int, MinInt}; - use super::Float; +use crate::int::{CastFrom, CastInto, Int, MinInt}; /// Conversions from integers to floats. /// diff --git a/library/compiler-builtins/compiler-builtins/src/float/div.rs b/library/compiler-builtins/compiler-builtins/src/float/div.rs index 929f2919787..5df637c7e0f 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/div.rs @@ -79,11 +79,12 @@ //! //! [Newton-Raphson method]: https://en.wikipedia.org/wiki/Newton%27s_method +use core::mem::size_of; +use core::ops; + use super::HalfRep; use crate::float::Float; use crate::int::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -use core::mem::size_of; -use core::ops; fn div(a: F, b: F) -> F where @@ -487,7 +488,7 @@ where }; residual_lo += abs_result & one; // tie to even - // conditionally turns the below LT comparison into LTE + // conditionally turns the below LT comparison into LTE abs_result += u8::from(residual_lo > b_significand).into(); if F::BITS == 128 || (F::BITS == 32 && half_iterations > 0) { diff --git a/library/compiler-builtins/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/compiler-builtins/src/float/mod.rs index 41b308626b3..f2c543bd2b7 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/mod.rs @@ -11,6 +11,5 @@ pub mod trunc; #[cfg(not(feature = "public-test-deps"))] pub(crate) use traits::{Float, HalfRep}; - #[cfg(feature = "public-test-deps")] pub use traits::{Float, HalfRep}; diff --git a/library/compiler-builtins/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/compiler-builtins/src/float/pow.rs index fe76060e0fa..45a4ad9049d 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/pow.rs @@ -18,11 +18,7 @@ fn pow(a: F, b: i32) -> F { a *= a; } - if recip { - F::ONE / mul - } else { - mul - } + if recip { F::ONE / mul } else { mul } } intrinsics! { diff --git a/library/compiler-builtins/compiler-builtins/src/int/big.rs b/library/compiler-builtins/compiler-builtins/src/int/big.rs index 0ef3caaedff..61f1349d9a4 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/big.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/big.rs @@ -2,9 +2,10 @@ #![allow(unused)] -use crate::int::{DInt, HInt, Int, MinInt}; use core::{fmt, ops}; +use crate::int::{DInt, HInt, Int, MinInt}; + const WORD_LO_MASK: u64 = 0x00000000ffffffff; const WORD_HI_MASK: u64 = 0xffffffff00000000; const WORD_FULL_MASK: u64 = 0xffffffffffffffff; diff --git a/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs index ba735aa7462..a57f881848d 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs @@ -60,11 +60,7 @@ mod implementation { } // the last two bisections are combined into one conditional t = x >> 1; - if t != T::ZERO { - z - 2 - } else { - z - x.cast() - } + if t != T::ZERO { z - 2 } else { z - x.cast() } // We could potentially save a few cycles by using the LUT trick from // "https://embeddedgurus.com/state-space/2014/09/ diff --git a/library/compiler-builtins/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/compiler-builtins/src/int/mod.rs index 1f1be711bbd..5633510d3c7 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/mod.rs @@ -12,9 +12,7 @@ mod traits; pub mod udiv; pub use big::{i256, u256}; - #[cfg(not(feature = "public-test-deps"))] pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; - #[cfg(feature = "public-test-deps")] pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; diff --git a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs index a91fe6632ee..b81f0469813 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -58,7 +58,6 @@ mod delegate; #[allow(unused_imports)] #[cfg(not(feature = "public-test-deps"))] pub(crate) use self::delegate::u128_divide_sparc; - #[cfg(feature = "public-test-deps")] pub use self::delegate::u128_divide_sparc; diff --git a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs index f18537b006b..4e985ba4739 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs @@ -1,6 +1,5 @@ #[cfg(not(feature = "public-test-deps"))] pub(crate) use crate::int::specialized_div_rem::*; - #[cfg(feature = "public-test-deps")] pub use crate::int::specialized_div_rem::*; diff --git a/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs index 40b67093f51..5cbe83ab1e2 100644 --- a/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs @@ -17,8 +17,7 @@ // Note that ERMSB does not enhance the backwards (DF=1) "rep movsb". use core::arch::asm; -use core::intrinsics; -use core::mem; +use core::{intrinsics, mem}; #[inline(always)] #[cfg(target_feature = "ermsb")] diff --git a/library/compiler-builtins/crates/libm-macros/src/enums.rs b/library/compiler-builtins/crates/libm-macros/src/enums.rs index 864b625eab3..b4646f984d4 100644 --- a/library/compiler-builtins/crates/libm-macros/src/enums.rs +++ b/library/compiler-builtins/crates/libm-macros/src/enums.rs @@ -26,7 +26,10 @@ pub fn function_enum( }; if let Some(tt) = attr.next() { - return Err(syn::Error::new(tt.span(), "unexpected token after identifier")); + return Err(syn::Error::new( + tt.span(), + "unexpected token after identifier", + )); } let enum_name = &item.ident; @@ -46,8 +49,12 @@ pub fn function_enum( // Match arm for `fn base_name(self)` matcher base_arms.push(quote! { Self::#ident => #base_enum::#bname_ident }); - let variant = - Variant { attrs: Vec::new(), ident, fields: Fields::Unit, discriminant: None }; + let variant = Variant { + attrs: Vec::new(), + ident, + fields: Fields::Unit, + discriminant: None, + }; item.variants.push(variant); } @@ -108,7 +115,10 @@ pub fn base_name_enum( return Err(syn::Error::new(sp.span(), "no attributes expected")); } - let mut base_names: Vec<_> = ALL_OPERATIONS.iter().map(|func| base_name(func.name)).collect(); + let mut base_names: Vec<_> = ALL_OPERATIONS + .iter() + .map(|func| base_name(func.name)) + .collect(); base_names.sort_unstable(); base_names.dedup(); @@ -121,8 +131,12 @@ pub fn base_name_enum( // Match arm for `fn as_str(self)` matcher as_str_arms.push(quote! { Self::#ident => #base_name }); - let variant = - Variant { attrs: Vec::new(), ident, fields: Fields::Unit, discriminant: None }; + let variant = Variant { + attrs: Vec::new(), + ident, + fields: Fields::Unit, + discriminant: None, + }; item.variants.push(variant); } @@ -147,7 +161,10 @@ pub fn base_name_enum( /// Verify that an enum is empty, otherwise return an error fn expect_empty_enum(item: &ItemEnum) -> syn::Result<()> { if !item.variants.is_empty() { - Err(syn::Error::new(item.variants.span(), "expected an empty enum")) + Err(syn::Error::new( + item.variants.span(), + "expected an empty enum", + )) } else { Ok(()) } diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index 3cee5385b62..3cdd364e830 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -11,7 +11,9 @@ use syn::spanned::Spanned; use syn::visit_mut::VisitMut; use syn::{Ident, ItemEnum}; -const KNOWN_TYPES: &[&str] = &["FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet"]; +const KNOWN_TYPES: &[&str] = &[ + "FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet", +]; /// Populate an enum with a variant representing function. Names are in upper camel case. /// @@ -142,10 +144,17 @@ fn validate(input: &mut StructuredInput) -> syn::Result .flat_map(|map_list| map_list.iter()) .flat_map(|attr_map| attr_map.names.iter()); let only_mentions = input.only.iter().flat_map(|only_list| only_list.iter()); - let fn_extra_mentions = - input.fn_extra.iter().flat_map(|v| v.keys()).filter(|name| *name != "_"); - let all_mentioned_fns = - input.skip.iter().chain(only_mentions).chain(attr_mentions).chain(fn_extra_mentions); + let fn_extra_mentions = input + .fn_extra + .iter() + .flat_map(|v| v.keys()) + .filter(|name| *name != "_"); + let all_mentioned_fns = input + .skip + .iter() + .chain(only_mentions) + .chain(attr_mentions) + .chain(fn_extra_mentions); // Make sure that every function mentioned is a real function for mentioned in all_mentioned_fns { @@ -171,7 +180,11 @@ fn validate(input: &mut StructuredInput) -> syn::Result for func in ALL_OPERATIONS.iter() { let fn_name = func.name; // If we have an `only` list and it does _not_ contain this function name, skip it - if input.only.as_ref().is_some_and(|only| !only.iter().any(|o| o == fn_name)) { + if input + .only + .as_ref() + .is_some_and(|only| !only.iter().any(|o| o == fn_name)) + { continue; } @@ -296,8 +309,11 @@ fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result { - let mut fn_extra = - map.get(&fn_name).or_else(|| map.get(&default_ident)).unwrap().clone(); + let mut fn_extra = map + .get(&fn_name) + .or_else(|| map.get(&default_ident)) + .unwrap() + .clone(); let mut v = MacroReplace::new(func.name); v.visit_expr_mut(&mut fn_extra); @@ -357,7 +373,11 @@ struct MacroReplace { impl MacroReplace { fn new(name: &'static str) -> Self { let norm_name = base_name(name); - Self { fn_name: name, norm_name: norm_name.to_owned(), error: None } + Self { + fn_name: name, + norm_name: norm_name.to_owned(), + error: None, + } } fn finish(self) -> syn::Result<()> { @@ -377,8 +397,10 @@ impl MacroReplace { "MACRO_FN_NAME" => *i = Ident::new(self.fn_name, i.span()), "MACRO_FN_NAME_NORMALIZED" => *i = Ident::new(&self.norm_name, i.span()), _ => { - self.error = - Some(syn::Error::new(i.span(), format!("unrecognized meta expression `{s}`"))); + self.error = Some(syn::Error::new( + i.span(), + format!("unrecognized meta expression `{s}`"), + )); } } } diff --git a/library/compiler-builtins/crates/libm-macros/src/parse.rs b/library/compiler-builtins/crates/libm-macros/src/parse.rs index 369bbae2f4f..d60d1247a9e 100644 --- a/library/compiler-builtins/crates/libm-macros/src/parse.rs +++ b/library/compiler-builtins/crates/libm-macros/src/parse.rs @@ -16,7 +16,9 @@ pub struct Invocation { impl Parse for Invocation { fn parse(input: ParseStream) -> syn::Result { - Ok(Self { fields: input.parse_terminated(Mapping::parse, Token![,])? }) + Ok(Self { + fields: input.parse_terminated(Mapping::parse, Token![,])?, + }) } } @@ -30,7 +32,11 @@ struct Mapping { impl Parse for Mapping { fn parse(input: ParseStream) -> syn::Result { - Ok(Self { name: input.parse()?, _sep: input.parse()?, expr: input.parse()? }) + Ok(Self { + name: input.parse()?, + _sep: input.parse()?, + expr: input.parse()?, + }) } } @@ -133,7 +139,13 @@ fn extract_fn_extra_field(expr: Expr) -> syn::Result> { return Err(e); }; - let ExprMatch { attrs, match_token: _, expr, brace_token: _, arms } = mexpr; + let ExprMatch { + attrs, + match_token: _, + expr, + brace_token: _, + arms, + } = mexpr; expect_empty_attrs(&attrs)?; @@ -146,7 +158,14 @@ fn extract_fn_extra_field(expr: Expr) -> syn::Result> { let mut res = BTreeMap::new(); for arm in arms { - let Arm { attrs, pat, guard, fat_arrow_token: _, body, comma: _ } = arm; + let Arm { + attrs, + pat, + guard, + fat_arrow_token: _, + body, + comma: _, + } = arm; expect_empty_attrs(&attrs)?; @@ -177,15 +196,20 @@ fn expect_empty_attrs(attrs: &[Attribute]) -> syn::Result<()> { return Ok(()); } - let e = - syn::Error::new(attrs.first().unwrap().span(), "no attributes allowed in this position"); + let e = syn::Error::new( + attrs.first().unwrap().span(), + "no attributes allowed in this position", + ); Err(e) } /// Extract a named field from a map, raising an error if it doesn't exist. fn expect_field(v: &mut Vec, name: &str) -> syn::Result { let pos = v.iter().position(|v| v.name == name).ok_or_else(|| { - syn::Error::new(Span::call_site(), format!("missing expected field `{name}`")) + syn::Error::new( + Span::call_site(), + format!("missing expected field `{name}`"), + ) })?; Ok(v.remove(pos).expr) diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index 5e58220eb39..750ed1afb05 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -7,7 +7,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `fn(f16) -> f16` FloatTy::F16, - Signature { args: &[Ty::F16], returns: &[Ty::F16] }, + Signature { + args: &[Ty::F16], + returns: &[Ty::F16], + }, None, &[ "ceilf16", @@ -23,7 +26,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `fn(f32) -> f32` FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32] }, + Signature { + args: &[Ty::F32], + returns: &[Ty::F32], + }, None, &[ "acosf", @@ -68,7 +74,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `(f64) -> f64` FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64] }, + Signature { + args: &[Ty::F64], + returns: &[Ty::F64], + }, None, &[ "acos", @@ -113,7 +122,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `fn(f128) -> f128` FloatTy::F128, - Signature { args: &[Ty::F128], returns: &[Ty::F128] }, + Signature { + args: &[Ty::F128], + returns: &[Ty::F128], + }, None, &[ "ceilf128", @@ -129,7 +141,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `(f16, f16) -> f16` FloatTy::F16, - Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, + Signature { + args: &[Ty::F16, Ty::F16], + returns: &[Ty::F16], + }, None, &[ "copysignf16", @@ -146,7 +161,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `(f32, f32) -> f32` FloatTy::F32, - Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] }, + Signature { + args: &[Ty::F32, Ty::F32], + returns: &[Ty::F32], + }, None, &[ "atan2f", @@ -168,7 +186,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `(f64, f64) -> f64` FloatTy::F64, - Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] }, + Signature { + args: &[Ty::F64, Ty::F64], + returns: &[Ty::F64], + }, None, &[ "atan2", @@ -190,7 +211,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `(f128, f128) -> f128` FloatTy::F128, - Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, + Signature { + args: &[Ty::F128, Ty::F128], + returns: &[Ty::F128], + }, None, &[ "copysignf128", @@ -207,134 +231,215 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `(f32, f32, f32) -> f32` FloatTy::F32, - Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] }, + Signature { + args: &[Ty::F32, Ty::F32, Ty::F32], + returns: &[Ty::F32], + }, None, &["fmaf"], ), ( // `(f64, f64, f64) -> f64` FloatTy::F64, - Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] }, + Signature { + args: &[Ty::F64, Ty::F64, Ty::F64], + returns: &[Ty::F64], + }, None, &["fma"], ), ( // `(f128, f128, f128) -> f128` FloatTy::F128, - Signature { args: &[Ty::F128, Ty::F128, Ty::F128], returns: &[Ty::F128] }, + Signature { + args: &[Ty::F128, Ty::F128, Ty::F128], + returns: &[Ty::F128], + }, None, &["fmaf128"], ), ( // `(f32) -> i32` FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::I32] }, + Signature { + args: &[Ty::F32], + returns: &[Ty::I32], + }, None, &["ilogbf"], ), ( // `(f64) -> i32` FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::I32] }, + Signature { + args: &[Ty::F64], + returns: &[Ty::I32], + }, None, &["ilogb"], ), ( // `(i32, f32) -> f32` FloatTy::F32, - Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] }, + Signature { + args: &[Ty::I32, Ty::F32], + returns: &[Ty::F32], + }, None, &["jnf", "ynf"], ), ( // `(i32, f64) -> f64` FloatTy::F64, - Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] }, + Signature { + args: &[Ty::I32, Ty::F64], + returns: &[Ty::F64], + }, None, &["jn", "yn"], ), ( // `(f16, i32) -> f16` FloatTy::F16, - Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16] }, + Signature { + args: &[Ty::F16, Ty::I32], + returns: &[Ty::F16], + }, None, &["ldexpf16", "scalbnf16"], ), ( // `(f32, i32) -> f32` FloatTy::F32, - Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] }, + Signature { + args: &[Ty::F32, Ty::I32], + returns: &[Ty::F32], + }, None, &["ldexpf", "scalbnf"], ), ( // `(f64, i64) -> f64` FloatTy::F64, - Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] }, + Signature { + args: &[Ty::F64, Ty::I32], + returns: &[Ty::F64], + }, None, &["ldexp", "scalbn"], ), ( // `(f128, i32) -> f128` FloatTy::F128, - Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128] }, + Signature { + args: &[Ty::F128, Ty::I32], + returns: &[Ty::F128], + }, None, &["ldexpf128", "scalbnf128"], ), ( // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, - Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }), + Signature { + args: &[Ty::F32], + returns: &[Ty::F32, Ty::F32], + }, + Some(Signature { + args: &[Ty::F32, Ty::MutF32], + returns: &[Ty::F32], + }), &["modff"], ), ( // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, - Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }), + Signature { + args: &[Ty::F64], + returns: &[Ty::F64, Ty::F64], + }, + Some(Signature { + args: &[Ty::F64, Ty::MutF64], + returns: &[Ty::F64], + }), &["modf"], ), ( // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] }, - Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), + Signature { + args: &[Ty::F32], + returns: &[Ty::F32, Ty::I32], + }, + Some(Signature { + args: &[Ty::F32, Ty::MutCInt], + returns: &[Ty::F32], + }), &["frexpf", "lgammaf_r"], ), ( // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] }, - Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), + Signature { + args: &[Ty::F64], + returns: &[Ty::F64, Ty::I32], + }, + Some(Signature { + args: &[Ty::F64, Ty::MutCInt], + returns: &[Ty::F64], + }), &["frexp", "lgamma_r"], ), ( // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` FloatTy::F32, - Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] }, - Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), + Signature { + args: &[Ty::F32, Ty::F32], + returns: &[Ty::F32, Ty::I32], + }, + Some(Signature { + args: &[Ty::F32, Ty::F32, Ty::MutCInt], + returns: &[Ty::F32], + }), &["remquof"], ), ( // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` FloatTy::F64, - Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] }, - Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), + Signature { + args: &[Ty::F64, Ty::F64], + returns: &[Ty::F64, Ty::I32], + }, + Some(Signature { + args: &[Ty::F64, Ty::F64, Ty::MutCInt], + returns: &[Ty::F64], + }), &["remquo"], ), ( // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, - Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }), + Signature { + args: &[Ty::F32], + returns: &[Ty::F32, Ty::F32], + }, + Some(Signature { + args: &[Ty::F32, Ty::MutF32, Ty::MutF32], + returns: &[], + }), &["sincosf"], ), ( // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, - Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }), + Signature { + args: &[Ty::F64], + returns: &[Ty::F64, Ty::F64], + }, + Some(Signature { + args: &[Ty::F64, Ty::MutF64, Ty::MutF64], + returns: &[], + }), &["sincos"], ), ]; diff --git a/library/compiler-builtins/crates/musl-math-sys/build.rs b/library/compiler-builtins/crates/musl-math-sys/build.rs index f06d84ee267..b00dbc73e28 100644 --- a/library/compiler-builtins/crates/musl-math-sys/build.rs +++ b/library/compiler-builtins/crates/musl-math-sys/build.rs @@ -8,7 +8,10 @@ const LIB_NAME: &str = "musl_math_prefixed"; /// Files that have more than one symbol. Map of file names to the symbols defined in that file. const MULTIPLE_SYMBOLS: &[(&str, &[&str])] = &[ - ("__invtrigl", &["__invtrigl", "__invtrigl_R", "__pio2_hi", "__pio2_lo"]), + ( + "__invtrigl", + &["__invtrigl", "__invtrigl_R", "__pio2_hi", "__pio2_lo"], + ), ("__polevll", &["__polevll", "__p1evll"]), ("erf", &["erf", "erfc"]), ("erff", &["erff", "erfcf"]), @@ -82,9 +85,16 @@ impl Config { let musl_dir = manifest_dir.join("musl"); let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - let musl_arch = if target_arch == "x86" { "i386".to_owned() } else { target_arch.clone() }; + let musl_arch = if target_arch == "x86" { + "i386".to_owned() + } else { + target_arch.clone() + }; - println!("cargo::rerun-if-changed={}/c_patches", manifest_dir.display()); + println!( + "cargo::rerun-if-changed={}/c_patches", + manifest_dir.display() + ); println!("cargo::rerun-if-changed={}", musl_dir.display()); Self { @@ -108,7 +118,10 @@ fn build_musl_math(cfg: &Config) { let musl_dir = &cfg.musl_dir; let math = musl_dir.join("src/math"); let arch_dir = musl_dir.join("arch").join(&cfg.musl_arch); - assert!(math.exists(), "musl source not found. Is the submodule up to date?"); + assert!( + math.exists(), + "musl source not found. Is the submodule up to date?" + ); let source_map = find_math_source(&math, cfg); let out_path = cfg.out_dir.join(format!("lib{LIB_NAME}.a")); @@ -125,7 +138,11 @@ fn build_musl_math(cfg: &Config) { .stderr(Stdio::inherit()) .output() .unwrap(); - assert!(sed_stat.status.success(), "sed command failed: {:?}", sed_stat.status); + assert!( + sed_stat.status.success(), + "sed command failed: {:?}", + sed_stat.status + ); fs::write(obj_include.join("bits/alltypes.h"), sed_stat.stdout).unwrap(); @@ -163,8 +180,9 @@ fn build_musl_math(cfg: &Config) { // Trickery! Redefine the symbol names to have the prefix `musl_`, which allows us to // differentiate these symbols from whatever we provide. - if let Some((_names, syms)) = - MULTIPLE_SYMBOLS.iter().find(|(name, _syms)| *name == sym_name) + if let Some((_names, syms)) = MULTIPLE_SYMBOLS + .iter() + .find(|(name, _syms)| *name == sym_name) { // Handle the occasional file that defines multiple symbols for sym in *syms { @@ -291,21 +309,34 @@ fn validate_archive_symbols(out_path: &Path) { ]; // List global undefined symbols - let out = - Command::new("nm").arg("-guj").arg(out_path).stderr(Stdio::inherit()).output().unwrap(); + let out = Command::new("nm") + .arg("-guj") + .arg(out_path) + .stderr(Stdio::inherit()) + .output() + .unwrap(); let undef = str::from_utf8(&out.stdout).unwrap(); let mut undef = undef.lines().collect::>(); undef.retain(|sym| { // Account for file formats that add a leading `_` - !ALLOWED_UNDEF_PFX.iter().any(|pfx| sym.starts_with(pfx) || sym[1..].starts_with(pfx)) + !ALLOWED_UNDEF_PFX + .iter() + .any(|pfx| sym.starts_with(pfx) || sym[1..].starts_with(pfx)) }); - assert!(undef.is_empty(), "found disallowed undefined symbols: {undef:#?}"); + assert!( + undef.is_empty(), + "found disallowed undefined symbols: {undef:#?}" + ); // Find any symbols that are missing the `_musl_` prefix` - let out = - Command::new("nm").arg("-gUj").arg(out_path).stderr(Stdio::inherit()).output().unwrap(); + let out = Command::new("nm") + .arg("-gUj") + .arg(out_path) + .stderr(Stdio::inherit()) + .output() + .unwrap(); let defined = str::from_utf8(&out.stdout).unwrap(); let mut defined = defined.lines().collect::>(); diff --git a/library/compiler-builtins/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs index ef70ec9035b..e7057869996 100644 --- a/library/compiler-builtins/crates/util/src/main.rs +++ b/library/compiler-builtins/crates/util/src/main.rs @@ -221,7 +221,11 @@ macro_rules! impl_parse_tuple_via_rug { impl ParseTuple for ($ty, $ty, $ty) { fn parse(input: &[&str]) -> Self { assert_eq!(input.len(), 3, "expected three arguments, got {input:?}"); - (parse_rug(input, 0), parse_rug(input, 1), parse_rug(input, 2)) + ( + parse_rug(input, 0), + parse_rug(input, 1), + parse_rug(input, 2), + ) } } }; diff --git a/library/compiler-builtins/libm-test/benches/random.rs b/library/compiler-builtins/libm-test/benches/random.rs index 63d7e5c6d20..81f58e3a658 100644 --- a/library/compiler-builtins/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm-test/benches/random.rs @@ -7,7 +7,11 @@ use libm_test::generate::random::RandomInput; use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, TupleCall}; /// Benchmark with this many items to get a variety -const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { 50 } else { 500 }; +const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { + 50 +} else { + 500 +}; /// Extra parameters we only care about if we are benchmarking against musl. #[allow(dead_code)] @@ -53,8 +57,10 @@ where let name = Op::NAME; let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl, GeneratorKind::Random); - let benchvec: Vec<_> = - random::get_test_cases::(&ctx).0.take(BENCH_ITER_ITEMS).collect(); + let benchvec: Vec<_> = random::get_test_cases::(&ctx) + .0 + .take(BENCH_ITER_ITEMS) + .collect(); // Perform a sanity check that we are benchmarking the same thing // Don't test against musl if it is not available @@ -73,7 +79,10 @@ where let musl_res = input.call(musl_fn); let crate_res = input.call(Op::ROUTINE); - crate_res.validate(musl_res, input, &ctx).context(name).unwrap(); + crate_res + .validate(musl_res, input, &ctx) + .context(name) + .unwrap(); } #[cfg(not(feature = "build-musl"))] diff --git a/library/compiler-builtins/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm-test/examples/plot_domains.rs index 78524761e2c..3563103b8cd 100644 --- a/library/compiler-builtins/libm-test/examples/plot_domains.rs +++ b/library/compiler-builtins/libm-test/examples/plot_domains.rs @@ -56,7 +56,13 @@ where Op::RustArgs: SpacedInput, { let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::QuickSpaced); - plot_one_generator(out_dir, &ctx, "logspace", config, spaced::get_test_cases::(&ctx).0); + plot_one_generator( + out_dir, + &ctx, + "logspace", + config, + spaced::get_test_cases::(&ctx).0, + ); ctx.gen_kind = GeneratorKind::EdgeCases; plot_one_generator( out_dir, diff --git a/library/compiler-builtins/libm-test/src/domain.rs b/library/compiler-builtins/libm-test/src/domain.rs index 41e94846163..94641be9b54 100644 --- a/library/compiler-builtins/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm-test/src/domain.rs @@ -67,16 +67,25 @@ impl EitherPrim { /// Convenience 1-dimensional float domains. impl Domain { /// x ∈ ℝ - const UNBOUNDED: Self = - Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }; + const UNBOUNDED: Self = Self { + start: Bound::Unbounded, + end: Bound::Unbounded, + check_points: None, + }; /// x ∈ ℝ >= 0 - const POSITIVE: Self = - Self { start: Bound::Included(F::ZERO), end: Bound::Unbounded, check_points: None }; + const POSITIVE: Self = Self { + start: Bound::Included(F::ZERO), + end: Bound::Unbounded, + check_points: None, + }; /// x ∈ ℝ > 0 - const STRICTLY_POSITIVE: Self = - Self { start: Bound::Excluded(F::ZERO), end: Bound::Unbounded, check_points: None }; + const STRICTLY_POSITIVE: Self = Self { + start: Bound::Excluded(F::ZERO), + end: Bound::Unbounded, + check_points: None, + }; /// Wrap in the float variant of [`EitherPrim`]. const fn into_prim_float(self) -> EitherPrim> { @@ -87,8 +96,11 @@ impl Domain { /// Convenience 1-dimensional integer domains. impl Domain { /// x ∈ ℝ - const UNBOUNDED_INT: Self = - Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }; + const UNBOUNDED_INT: Self = Self { + start: Bound::Unbounded, + end: Bound::Unbounded, + check_points: None, + }; /// Wrap in the int variant of [`EitherPrim`]. const fn into_prim_int(self) -> EitherPrim, Self> { @@ -99,13 +111,18 @@ impl Domain { /// Multidimensional domains, represented as an array of 1-D domains. impl EitherPrim, Domain> { /// x ∈ ℝ - const UNBOUNDED1: [Self; 1] = - [Domain { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None } - .into_prim_float()]; + const UNBOUNDED1: [Self; 1] = [Domain { + start: Bound::Unbounded, + end: Bound::Unbounded, + check_points: None, + } + .into_prim_float()]; /// {x1, x2} ∈ ℝ - const UNBOUNDED2: [Self; 2] = - [Domain::UNBOUNDED.into_prim_float(), Domain::UNBOUNDED.into_prim_float()]; + const UNBOUNDED2: [Self; 2] = [ + Domain::UNBOUNDED.into_prim_float(), + Domain::UNBOUNDED.into_prim_float(), + ]; /// {x1, x2, x3} ∈ ℝ const UNBOUNDED3: [Self; 3] = [ @@ -115,8 +132,10 @@ impl EitherPrim, Domain> { ]; /// {x1, x2} ∈ ℝ, one float and one int - const UNBOUNDED_F_I: [Self; 2] = - [Domain::UNBOUNDED.into_prim_float(), Domain::UNBOUNDED_INT.into_prim_int()]; + const UNBOUNDED_F_I: [Self; 2] = [ + Domain::UNBOUNDED.into_prim_float(), + Domain::UNBOUNDED_INT.into_prim_int(), + ]; /// x ∈ ℝ >= 0 const POSITIVE: [Self; 1] = [Domain::POSITIVE.into_prim_float()]; @@ -133,9 +152,12 @@ impl EitherPrim, Domain> { .into_prim_float()]; /// Domain for `acosh` - const ACOSH: [Self; 1] = - [Domain { start: Bound::Included(F::ONE), end: Bound::Unbounded, check_points: None } - .into_prim_float()]; + const ACOSH: [Self; 1] = [Domain { + start: Bound::Included(F::ONE), + end: Bound::Unbounded, + check_points: None, + } + .into_prim_float()]; /// Domain for `atanh` const ATANH: [Self; 1] = [Domain { @@ -157,9 +179,12 @@ impl EitherPrim, Domain> { const LOG: [Self; 1] = Self::STRICTLY_POSITIVE; /// Domain for `log1p` i.e. `log(1 + x)` - const LOG1P: [Self; 1] = - [Domain { start: Bound::Excluded(F::NEG_ONE), end: Bound::Unbounded, check_points: None } - .into_prim_float()]; + const LOG1P: [Self; 1] = [Domain { + start: Bound::Excluded(F::NEG_ONE), + end: Bound::Unbounded, + check_points: None, + } + .into_prim_float()]; /// Domain for `sqrt` const SQRT: [Self; 1] = Self::POSITIVE; @@ -187,8 +212,10 @@ impl EitherPrim, Domain> { /// Domain for `jn` and `yn`. // FIXME: the domain should provide some sort of "reasonable range" so we don't actually test // the entire system unbounded. - const BESSEL_N: [Self; 2] = - [Domain::UNBOUNDED_INT.into_prim_int(), Domain::UNBOUNDED.into_prim_float()]; + const BESSEL_N: [Self; 2] = [ + Domain::UNBOUNDED_INT.into_prim_int(), + Domain::UNBOUNDED.into_prim_float(), + ]; } /// Get the domain for a given function. diff --git a/library/compiler-builtins/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm-test/src/f8_impl.rs index ddb7bf90e7f..905c7d7fde9 100644 --- a/library/compiler-builtins/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm-test/src/f8_impl.rs @@ -498,6 +498,8 @@ impl fmt::LowerHex for f8 { } pub const fn hf8(s: &str) -> f8 { - let Ok(bits) = libm::support::hex_float::parse_hex_exact(s, 8, 3) else { panic!() }; + let Ok(bits) = libm::support::hex_float::parse_hex_exact(s, 8, 3) else { + panic!() + }; f8(bits as u8) } diff --git a/library/compiler-builtins/libm-test/src/generate.rs b/library/compiler-builtins/libm-test/src/generate.rs index 89ca09a7a0b..da080d23fa7 100644 --- a/library/compiler-builtins/libm-test/src/generate.rs +++ b/library/compiler-builtins/libm-test/src/generate.rs @@ -16,7 +16,11 @@ pub struct KnownSize { impl KnownSize { pub fn new(iter: I, total: u64) -> Self { - Self { total, current: 0, iter } + Self { + total, + current: 0, + iter, + } } } @@ -30,7 +34,10 @@ impl Iterator for KnownSize { return next; } - assert_eq!(self.current, self.total, "total items did not match expected"); + assert_eq!( + self.current, self.total, + "total items did not match expected" + ); None } diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index e3628d51c9a..f1e6fcec397 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -20,14 +20,21 @@ pub struct TestCase { impl TestCase { #[expect(dead_code)] fn append_inputs(v: &mut Vec, l: &[Op::RustArgs]) { - v.extend(l.iter().copied().map(|input| Self { input, output: None })); + v.extend(l.iter().copied().map(|input| Self { + input, + output: None, + })); } fn append_pairs(v: &mut Vec, l: &[(Op::RustArgs, Option)]) where Op::RustRet: Copy, { - v.extend(l.iter().copied().map(|(input, output)| Self { input, output })); + v.extend( + l.iter() + .copied() + .map(|(input, output)| Self { input, output }), + ); } } @@ -603,9 +610,15 @@ fn rint_cases() -> Vec> { &[ // Known failure on i586 #[cfg(not(x86_no_sse))] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), + ( + (hf64!("-0x1.e3f13ff995ffcp+38"),), + Some(hf64!("-0x1.e3f13ff994000p+38")), + ), #[cfg(x86_no_sse)] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))), + ( + (hf64!("-0x1.e3f13ff995ffcp+38"),), + Some(hf64!("-0x1.e3f13ff998000p+38")), + ), ], ); v @@ -655,9 +668,15 @@ fn roundeven_cases() -> Vec> { &[ // Known failure on i586 #[cfg(not(x86_no_sse))] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), + ( + (hf64!("-0x1.e3f13ff995ffcp+38"),), + Some(hf64!("-0x1.e3f13ff994000p+38")), + ), #[cfg(x86_no_sse)] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))), + ( + (hf64!("-0x1.e3f13ff995ffcp+38"),), + Some(hf64!("-0x1.e3f13ff998000p+38")), + ), ], ); v @@ -832,7 +851,9 @@ where { assert_eq!(ctx.basis, CheckBasis::None); assert_eq!(ctx.gen_kind, GeneratorKind::List); - Op::get_cases().into_iter().filter_map(|x| x.output.map(|o| (x.input, o))) + Op::get_cases() + .into_iter() + .filter_map(|x| x.output.map(|o| (x.input, o))) } /// Opposite of the above; extract only test cases that don't have a known output, to be run @@ -847,7 +868,18 @@ where assert_eq!(ctx.gen_kind, GeneratorKind::List); let cases = Op::get_cases(); - let count: u64 = cases.iter().filter(|case| case.output.is_none()).count().try_into().unwrap(); + let count: u64 = cases + .iter() + .filter(|case| case.output.is_none()) + .count() + .try_into() + .unwrap(); - (cases.into_iter().filter(|x| x.output.is_none()).map(|x| x.input), count) + ( + cases + .into_iter() + .filter(|x| x.output.is_none()) + .map(|x| x.input), + count, + ) } diff --git a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs index 56cc9fa9a70..2fb0746388c 100644 --- a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs +++ b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs @@ -249,7 +249,11 @@ macro_rules! impl_edge_case_input { .flat_map(move |(first, second)| { iter2.clone().map(move |third| (first, second, third)) }); - let count = steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); + let count = steps0 + .checked_mul(steps1) + .unwrap() + .checked_mul(steps2) + .unwrap(); (iter, count) } diff --git a/library/compiler-builtins/libm-test/src/generate/random.rs b/library/compiler-builtins/libm-test/src/generate/random.rs index e8a7ee9057e..4ee88946d8e 100644 --- a/library/compiler-builtins/libm-test/src/generate/random.rs +++ b/library/compiler-builtins/libm-test/src/generate/random.rs @@ -117,7 +117,10 @@ impl_random_input!(f128); /// Create a test case iterator. pub fn get_test_cases( ctx: &CheckCtx, -) -> (impl Iterator + Send + use<'_, RustArgs>, u64) { +) -> ( + impl Iterator + Send + use<'_, RustArgs>, + u64, +) { let (iter, count) = RustArgs::get_cases(ctx); // Wrap in `KnownSize` so we get an assertion if the cuunt is wrong. diff --git a/library/compiler-builtins/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm-test/src/generate/spaced.rs index bea3f4c7e1b..8e6b376ebd1 100644 --- a/library/compiler-builtins/libm-test/src/generate/spaced.rs +++ b/library/compiler-builtins/libm-test/src/generate/spaced.rs @@ -70,7 +70,9 @@ fn value_count() -> Option where u64: TryFrom, { - u64::try_from(F::Int::MAX).ok().and_then(|max| max.checked_add(1)) + u64::try_from(F::Int::MAX) + .ok() + .and_then(|max| max.checked_add(1)) } /// Returns an iterator of every possible value of type `F`. @@ -162,8 +164,11 @@ macro_rules! impl_spaced_input { .flat_map(move |(first, second)| { iter2.clone().map(move |third| (first, second, third)) }); - let count = - steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); + let count = steps0 + .checked_mul(steps1) + .unwrap() + .checked_mul(steps2) + .unwrap(); (EitherIter::B(iter), count) } diff --git a/library/compiler-builtins/libm-test/src/lib.rs b/library/compiler-builtins/libm-test/src/lib.rs index 485c01a4782..730318abcba 100644 --- a/library/compiler-builtins/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm-test/src/lib.rs @@ -71,7 +71,12 @@ pub fn test_log(s: &str) { return None; }; - PathBuf::from(x).parent().unwrap().parent().unwrap().join("target") + PathBuf::from(x) + .parent() + .unwrap() + .parent() + .unwrap() + .join("target") } }; let outfile = target_dir.join("test-log.txt"); @@ -81,7 +86,9 @@ pub fn test_log(s: &str) { .append(true) .open(outfile) .expect("failed to open logfile"); - let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); + let now = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap(); writeln!(f, "\n\nTest run at {}", now.as_secs()).unwrap(); writeln!(f, "arch: {}", env::consts::ARCH).unwrap(); diff --git a/library/compiler-builtins/libm-test/src/num.rs b/library/compiler-builtins/libm-test/src/num.rs index eed941423d3..3237c85039d 100644 --- a/library/compiler-builtins/libm-test/src/num.rs +++ b/library/compiler-builtins/libm-test/src/num.rs @@ -180,8 +180,17 @@ impl Consts { neg_max_snan, } = self; - [pos_nan, neg_nan, max_qnan, min_snan, max_snan, neg_max_qnan, neg_min_snan, neg_max_snan] - .into_iter() + [ + pos_nan, + neg_nan, + max_qnan, + min_snan, + max_snan, + neg_max_qnan, + neg_min_snan, + neg_max_snan, + ] + .into_iter() } } @@ -229,7 +238,9 @@ where assert!(!end.is_nan()); assert!(end >= start); - let steps = steps.checked_sub(F::Int::ONE).expect("`steps` must be at least 2"); + let steps = steps + .checked_sub(F::Int::ONE) + .expect("`steps` must be at least 2"); let between = ulp_between(start, end).expect("`start` or `end` is NaN"); let spacing = (between / steps).max(F::Int::ONE); let steps = steps.min(between); // At maximum, one step per ULP @@ -283,15 +294,22 @@ mod tests { if i == 0 { assert_eq!(down, f8::NEG_INFINITY.to_bits(), "{i} next_down({v:#010b})"); } else { - let expected = - if v == f8::ZERO { 1 | f8::SIGN_MASK } else { f8::ALL[i - 1].to_bits() }; + let expected = if v == f8::ZERO { + 1 | f8::SIGN_MASK + } else { + f8::ALL[i - 1].to_bits() + }; assert_eq!(down, expected, "{i} next_down({v:#010b})"); } if i == f8::ALL_LEN - 1 { assert_eq!(up, f8::INFINITY.to_bits(), "{i} next_up({v:#010b})"); } else { - let expected = if v == f8::NEG_ZERO { 1 } else { f8::ALL[i + 1].to_bits() }; + let expected = if v == f8::NEG_ZERO { + 1 + } else { + f8::ALL[i + 1].to_bits() + }; assert_eq!(up, expected, "{i} next_up({v:#010b})"); } } @@ -300,8 +318,14 @@ mod tests { #[test] fn test_next_up_down_inf_nan() { assert_eq!(f8::NEG_INFINITY.next_up().to_bits(), f8::ALL[0].to_bits(),); - assert_eq!(f8::NEG_INFINITY.next_down().to_bits(), f8::NEG_INFINITY.to_bits(),); - assert_eq!(f8::INFINITY.next_down().to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits(),); + assert_eq!( + f8::NEG_INFINITY.next_down().to_bits(), + f8::NEG_INFINITY.to_bits(), + ); + assert_eq!( + f8::INFINITY.next_down().to_bits(), + f8::ALL[f8::ALL_LEN - 1].to_bits(), + ); assert_eq!(f8::INFINITY.next_up().to_bits(), f8::INFINITY.to_bits(),); assert_eq!(f8::NAN.next_up().to_bits(), f8::NAN.to_bits(),); assert_eq!(f8::NAN.next_down().to_bits(), f8::NAN.to_bits(),); @@ -321,7 +345,10 @@ mod tests { // Check across zero assert_eq!(f8::from_bits(0b1_0000_111).n_up(8).to_bits(), 0b0_0000_001); - assert_eq!(f8::from_bits(0b0_0000_111).n_down(8).to_bits(), 0b1_0000_001); + assert_eq!( + f8::from_bits(0b0_0000_111).n_down(8).to_bits(), + 0b1_0000_001 + ); } #[test] @@ -337,13 +364,25 @@ mod tests { #[test] fn test_n_up_down_inf_nan_zero() { assert_eq!(f8::NEG_INFINITY.n_up(1).to_bits(), f8::ALL[0].to_bits()); - assert_eq!(f8::NEG_INFINITY.n_up(239).to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits()); + assert_eq!( + f8::NEG_INFINITY.n_up(239).to_bits(), + f8::ALL[f8::ALL_LEN - 1].to_bits() + ); assert_eq!(f8::NEG_INFINITY.n_up(240).to_bits(), f8::INFINITY.to_bits()); - assert_eq!(f8::NEG_INFINITY.n_down(u8::MAX).to_bits(), f8::NEG_INFINITY.to_bits()); + assert_eq!( + f8::NEG_INFINITY.n_down(u8::MAX).to_bits(), + f8::NEG_INFINITY.to_bits() + ); - assert_eq!(f8::INFINITY.n_down(1).to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits()); + assert_eq!( + f8::INFINITY.n_down(1).to_bits(), + f8::ALL[f8::ALL_LEN - 1].to_bits() + ); assert_eq!(f8::INFINITY.n_down(239).to_bits(), f8::ALL[0].to_bits()); - assert_eq!(f8::INFINITY.n_down(240).to_bits(), f8::NEG_INFINITY.to_bits()); + assert_eq!( + f8::INFINITY.n_down(240).to_bits(), + f8::NEG_INFINITY.to_bits() + ); assert_eq!(f8::INFINITY.n_up(u8::MAX).to_bits(), f8::INFINITY.to_bits()); assert_eq!(f8::NAN.n_up(u8::MAX).to_bits(), f8::NAN.to_bits()); @@ -381,7 +420,11 @@ mod tests { assert_eq!(down, expected, "{i} {n} n_down({v:#010b})"); } else { // Overflow to -inf - assert_eq!(down, f8::NEG_INFINITY.to_bits(), "{i} {n} n_down({v:#010b})"); + assert_eq!( + down, + f8::NEG_INFINITY.to_bits(), + "{i} {n} n_down({v:#010b})" + ); } let mut up_exp_idx = i + n; @@ -438,13 +481,22 @@ mod tests { #[test] fn test_ulp_between_inf_nan_zero() { - assert_eq!(ulp_between(f8::NEG_INFINITY, f8::INFINITY).unwrap(), f8::ALL_LEN as u8); - assert_eq!(ulp_between(f8::INFINITY, f8::NEG_INFINITY).unwrap(), f8::ALL_LEN as u8); + assert_eq!( + ulp_between(f8::NEG_INFINITY, f8::INFINITY).unwrap(), + f8::ALL_LEN as u8 + ); + assert_eq!( + ulp_between(f8::INFINITY, f8::NEG_INFINITY).unwrap(), + f8::ALL_LEN as u8 + ); assert_eq!( ulp_between(f8::NEG_INFINITY, f8::ALL[f8::ALL_LEN - 1]).unwrap(), f8::ALL_LEN as u8 - 1 ); - assert_eq!(ulp_between(f8::INFINITY, f8::ALL[0]).unwrap(), f8::ALL_LEN as u8 - 1); + assert_eq!( + ulp_between(f8::INFINITY, f8::ALL[0]).unwrap(), + f8::ALL_LEN as u8 - 1 + ); assert_eq!(ulp_between(f8::ZERO, f8::NEG_ZERO).unwrap(), 0); assert_eq!(ulp_between(f8::NAN, f8::ZERO), None); @@ -469,7 +521,12 @@ mod tests { // of steps. let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x3), 10); let ls: Vec<_> = ls.collect(); - let exp = [f8::from_bits(0x0), f8::from_bits(0x1), f8::from_bits(0x2), f8::from_bits(0x3)]; + let exp = [ + f8::from_bits(0x0), + f8::from_bits(0x1), + f8::from_bits(0x2), + f8::from_bits(0x3), + ]; assert_eq!(ls, exp); assert_eq!(ls.len(), usize::from(count)); } diff --git a/library/compiler-builtins/libm-test/src/op.rs b/library/compiler-builtins/libm-test/src/op.rs index 4f251f80df6..bd17aad7d03 100644 --- a/library/compiler-builtins/libm-test/src/op.rs +++ b/library/compiler-builtins/libm-test/src/op.rs @@ -16,7 +16,7 @@ use std::fmt; use std::panic::{RefUnwindSafe, UnwindSafe}; -pub use shared::{FloatTy, MathOpInfo, Ty, ALL_OPERATIONS}; +pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; use crate::{CheckOutput, Float, TupleCall}; diff --git a/library/compiler-builtins/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm-test/src/run_cfg.rs index b36164b005f..3345a01d2de 100644 --- a/library/compiler-builtins/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm-test/src/run_cfg.rs @@ -15,7 +15,9 @@ pub const EXTENSIVE_ITER_ENV: &str = "LIBM_EXTENSIVE_ITERATIONS"; /// The override value, if set by the above environment. static EXTENSIVE_ITER_OVERRIDE: LazyLock> = LazyLock::new(|| { - env::var(EXTENSIVE_ITER_ENV).map(|v| v.parse().expect("failed to parse iteration count")).ok() + env::var(EXTENSIVE_ITER_ENV) + .map(|v| v.parse().expect("failed to parse iteration count")) + .ok() }); /// Specific tests that need to have a reduced amount of iterations to complete in a reasonable @@ -115,7 +117,10 @@ static EXTENSIVE: LazyLock> = LazyLock::new(|| { let mut ret = Vec::new(); let append_ty_ops = |ret: &mut Vec<_>, fty: FloatTy| { - let iter = Identifier::ALL.iter().filter(move |id| id.math_op().float_ty == fty).copied(); + let iter = Identifier::ALL + .iter() + .filter(move |id| id.math_op().float_ty == fty) + .copied(); ret.extend(iter); }; @@ -276,7 +281,10 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { let seed_msg = match ctx.gen_kind { GeneratorKind::QuickSpaced | GeneratorKind::Extensive => String::new(), GeneratorKind::Random => { - format!(" using `{SEED_ENV}={}`", str::from_utf8(SEED.as_slice()).unwrap()) + format!( + " using `{SEED_ENV}={}`", + str::from_utf8(SEED.as_slice()).unwrap() + ) } GeneratorKind::EdgeCases | GeneratorKind::List => unimplemented!(), }; @@ -303,7 +311,10 @@ pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { return i32::MIN..=i32::MAX; } - assert_eq!(argnum, 0, "For `jn`/`yn`, only the first argument takes an integer"); + assert_eq!( + argnum, 0, + "For `jn`/`yn`, only the first argument takes an integer" + ); // The integer argument to `jn` is an iteration count. Limit this to ensure tests can be // completed in a reasonable amount of time. @@ -331,7 +342,11 @@ pub fn check_point_count(ctx: &CheckCtx) -> usize { "check_point_count is intended for edge case tests" ); let t_env = TestEnv::from_env(ctx); - if t_env.slow_platform || !cfg!(optimizations_enabled) { 4 } else { 10 } + if t_env.slow_platform || !cfg!(optimizations_enabled) { + 4 + } else { + 10 + } } /// When validating points of interest (e.g. asymptotes, inflection points, extremes), also check diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index c560dade884..dbb97016153 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -328,7 +328,10 @@ where // Check when both are NaNs if actual.is_nan() && expected.is_nan() { if require_biteq && ctx.basis == CheckBasis::None { - ensure!(actual.to_bits() == expected.to_bits(), "mismatched NaN bitpatterns"); + ensure!( + actual.to_bits() == expected.to_bits(), + "mismatched NaN bitpatterns" + ); } // By default, NaNs have nothing special to check. return Ok(()); @@ -340,7 +343,10 @@ where // Make sure that the signs are the same before checing ULP to avoid wraparound let act_sig = actual.signum(); let exp_sig = expected.signum(); - ensure!(act_sig == exp_sig, "mismatched signs {act_sig:?} {exp_sig:?}"); + ensure!( + act_sig == exp_sig, + "mismatched signs {act_sig:?} {exp_sig:?}" + ); if actual.is_infinite() ^ expected.is_infinite() { bail!("mismatched infinities"); diff --git a/library/compiler-builtins/libm-test/tests/u256.rs b/library/compiler-builtins/libm-test/tests/u256.rs index 4444036d0a4..8cbb3ad226f 100644 --- a/library/compiler-builtins/libm-test/tests/u256.rs +++ b/library/compiler-builtins/libm-test/tests/u256.rs @@ -40,7 +40,10 @@ fn from_bigint(bx: &mut BigInt) -> u256 { let mut bres = [0u128, 0]; bx.write_digits(&mut bres, Order::Lsf); bx.assign(0); - u256 { lo: bres[0], hi: bres[1] } + u256 { + lo: bres[0], + hi: bres[1], + } } fn check_one( @@ -142,6 +145,11 @@ fn mp_u256_widen_mul() { by.assign(y); let actual = x.widen_mul(y); bx *= &by; - check_one(|| format!("{x:#034x}"), || Some(format!("{y:#034x}")), actual, &mut bx); + check_one( + || format!("{x:#034x}"), + || Some(format!("{y:#034x}")), + actual, + &mut bx, + ); } } diff --git a/library/compiler-builtins/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm-test/tests/z_extensive/run.rs index b10c231d183..59c806ce73e 100644 --- a/library/compiler-builtins/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm-test/tests/z_extensive/run.rs @@ -28,8 +28,15 @@ pub fn run() { // With default parallelism, the CPU doesn't saturate. We don't need to be nice to // other processes, so do 1.5x to make sure we use all available resources. - let threads = std::thread::available_parallelism().map(Into::into).unwrap_or(0) * 3 / 2; - rayon::ThreadPoolBuilder::new().num_threads(threads).build_global().unwrap(); + let threads = std::thread::available_parallelism() + .map(Into::into) + .unwrap_or(0) + * 3 + / 2; + rayon::ThreadPoolBuilder::new() + .num_threads(threads) + .build_global() + .unwrap(); libtest_mimic::run(&args, tests).exit(); } @@ -134,7 +141,9 @@ where }); // Run the actual tests - let res = chunks.par_bridge().try_for_each_init(Op::new_mp, test_single_chunk); + let res = chunks + .par_bridge() + .try_for_each_init(Op::new_mp, test_single_chunk); let real_total = completed.load(Ordering::Relaxed); pb.complete(real_total); @@ -179,7 +188,12 @@ impl Progress { let pb = ProgressBar::new(total); pb.set_style(initial_style); - Self { pb, final_style, name_padded, is_tty } + Self { + pb, + final_style, + name_padded, + is_tty, + } } fn update(&self, completed: u64, input: impl fmt::Debug) { diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index 8b8ba981565..2a497c7b117 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -107,9 +107,15 @@ fn emit_cfg_shorthands(cfg: &Config) { /// Reemit config that we make use of for test logging. fn emit_cfg_env(cfg: &Config) { - println!("cargo:rustc-env=CFG_CARGO_FEATURES={:?}", cfg.cargo_features); + println!( + "cargo:rustc-env=CFG_CARGO_FEATURES={:?}", + cfg.cargo_features + ); println!("cargo:rustc-env=CFG_OPT_LEVEL={}", cfg.opt_level); - println!("cargo:rustc-env=CFG_TARGET_FEATURES={:?}", cfg.target_features); + println!( + "cargo:rustc-env=CFG_TARGET_FEATURES={:?}", + cfg.target_features + ); } /// Configure whether or not `f16` and `f128` support should be enabled. diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 7e56bd0796c..7df84fe1879 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -2,7 +2,10 @@ #![no_std] #![cfg_attr(intrinsics_enabled, allow(internal_features))] #![cfg_attr(intrinsics_enabled, feature(core_intrinsics))] -#![cfg_attr(all(intrinsics_enabled, target_family = "wasm"), feature(wasm_numeric_instr))] +#![cfg_attr( + all(intrinsics_enabled, target_family = "wasm"), + feature(wasm_numeric_instr) +)] #![cfg_attr(f128_enabled, feature(f128))] #![cfg_attr(f16_enabled, feature(f16))] #![allow(clippy::assign_op_pattern)] diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index eb3d401cd96..da8daa41a01 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -29,8 +29,13 @@ const ATAN_LO: [f32; 4] = [ 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ ]; -const A_T: [f32; 5] = - [3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, -1.0648017377e-01, 6.1687607318e-02]; +const A_T: [f32; 5] = [ + 3.3333328366e-01, + -1.9999158382e-01, + 1.4253635705e-01, + -1.0648017377e-01, + 6.1687607318e-02, +]; /// Arctangent (f32) /// diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index 9d3311cd6a8..cf56f7a9792 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -171,7 +171,11 @@ pub fn cbrt_round(x: f64, round: Round) -> FpResult { for (a, b) in wlist { if azz == a { - let tmp = if round as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 }; + let tmp = if round as u64 + sign == 2 { + hf64!("0x1p-52") + } else { + 0.0 + }; y1 = (b + tmp).copysign(zz); } } diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs index 1b634abec6b..5d82228a05f 100644 --- a/library/compiler-builtins/libm/src/math/erf.rs +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -306,5 +306,9 @@ pub fn erfc(x: f64) -> f64 { } let x1p_1022 = f64::from_bits(0x0010000000000000); - if sign != 0 { 2.0 - x1p_1022 } else { x1p_1022 * x1p_1022 } + if sign != 0 { + 2.0 - x1p_1022 + } else { + x1p_1022 * x1p_1022 + } } diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs index 2e41183bfc0..fe15f01082e 100644 --- a/library/compiler-builtins/libm/src/math/erff.rs +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -218,5 +218,9 @@ pub fn erfcf(x: f32) -> f32 { } let x1p_120 = f32::from_bits(0x03800000); - if sign != 0 { 2.0 - x1p_120 } else { x1p_120 * x1p_120 } + if sign != 0 { + 2.0 - x1p_120 + } else { + x1p_120 * x1p_120 + } } diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs index 0520a41f2e9..303045b3313 100644 --- a/library/compiler-builtins/libm/src/math/exp10f.rs +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -2,8 +2,9 @@ use super::{exp2, exp2f, modff}; const LN10_F32: f32 = 3.32192809488736234787031942948939; const LN10_F64: f64 = 3.32192809488736234787031942948939; -const P10: &[f32] = - &[1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7]; +const P10: &[f32] = &[ + 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, +]; /// Calculates 10 raised to the power of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs index 12c6f532b96..63dc86e37c8 100644 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -126,5 +126,9 @@ pub fn expm1f(mut x: f32) -> f32 { return y - 1.; } let uf = f32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */ - if k < 23 { (x - e + (1. - uf)) * twopk } else { (x - (e + uf) + 1.) * twopk } + if k < 23 { + (x - e + (1. - uf)) * twopk + } else { + (x - (e + uf) + 1.) * twopk + } } diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index e0b3347acf8..8856e63f596 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -387,11 +387,17 @@ mod tests { #[test] fn fma_sbb() { - assert_eq!(fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), -3991680619069439e277); + assert_eq!( + fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), + -3991680619069439e277 + ); } #[test] fn fma_underflow() { - assert_eq!(fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), 0.0,); + assert_eq!( + fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), + 0.0, + ); } } diff --git a/library/compiler-builtins/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/src/math/fma_wide.rs index 08b78b02264..f268c2f144c 100644 --- a/library/compiler-builtins/libm/src/math/fma_wide.rs +++ b/library/compiler-builtins/libm/src/math/fma_wide.rs @@ -75,11 +75,18 @@ where } } - return FpResult { val: result.narrow(), status }; + return FpResult { + val: result.narrow(), + status, + }; } let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; - let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy }; + let err = if neg == (zb > xy) { + xy - result + zb + } else { + zb - result + xy + }; if neg == (err < B::ZERO) { ui += one; } else { diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs index 5c5bb47638f..499770c0d6d 100644 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -75,7 +75,14 @@ mod tests { /// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + let roundtrip = [ + F::ZERO, + F::ONE, + F::NEG_ONE, + F::NEG_ZERO, + F::INFINITY, + F::NEG_INFINITY, + ]; for x in roundtrip { let FpResult { val, status } = ceil_status(x); diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs index 2438046254f..58d1ee4c247 100644 --- a/library/compiler-builtins/libm/src/math/generic/floor.rs +++ b/library/compiler-builtins/libm/src/math/generic/floor.rs @@ -75,7 +75,14 @@ mod tests { /// Test against https://en.cppreference.com/w/cpp/numeric/math/floor fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + let roundtrip = [ + F::ZERO, + F::ONE, + F::NEG_ONE, + F::NEG_ZERO, + F::INFINITY, + F::NEG_INFINITY, + ]; for x in roundtrip { let FpResult { val, status } = floor_status(x); diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index 9cdeb1185a8..7bf38e3235c 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -15,7 +15,11 @@ pub fn rint_round(x: F, _round: Round) -> FpResult { // On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise, // the excess precission from x87 would cause an incorrect final result. let force = |x| { - if cfg!(x86_no_sse) && (F::BITS == 32 || F::BITS == 64) { force_eval!(x) } else { x } + if cfg!(x86_no_sse) && (F::BITS == 32 || F::BITS == 64) { + force_eval!(x) + } else { + x + } }; let res = if e >= F::EXP_BIAS + F::SIG_BITS { @@ -47,7 +51,14 @@ mod tests { use crate::support::{Hexf, Status}; fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + let roundtrip = [ + F::ZERO, + F::ONE, + F::NEG_ONE, + F::NEG_ZERO, + F::INFINITY, + F::NEG_INFINITY, + ]; for x in roundtrip { let FpResult { val, status } = rint_round(x, Round::Nearest); diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index ec9ff22df20..c52560bdb2c 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -521,7 +521,10 @@ mod tests { f128::from_bits(0x400c3880000000000000000000000000), 0x40059000000000000000000000000000_u128, ), - (f128::from_bits(0x0000000f), 0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128), + ( + f128::from_bits(0x0000000f), + 0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128, + ), (f128::INFINITY, f128::INFINITY.to_bits()), ]; diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs index 25414ecf426..29a28f47b63 100644 --- a/library/compiler-builtins/libm/src/math/generic/trunc.rs +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -36,7 +36,11 @@ pub fn trunc_status(x: F) -> FpResult { // C5: Otherwise the result is inexact and we will truncate. Raise `FE_INEXACT`, mask the // result, and return. - let status = if xi & F::SIG_MASK == F::Int::ZERO { Status::OK } else { Status::INEXACT }; + let status = if xi & F::SIG_MASK == F::Int::ZERO { + Status::OK + } else { + Status::INEXACT + }; xi &= mask; FpResult::new(F::from_bits(xi), status) } @@ -47,7 +51,14 @@ mod tests { use crate::support::Hexf; fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + let roundtrip = [ + F::ZERO, + F::ONE, + F::NEG_ONE, + F::NEG_ZERO, + F::INFINITY, + F::NEG_INFINITY, + ]; for x in roundtrip { let FpResult { val, status } = trunc_status(x); diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs index ccc4914be2b..5b41f7b1dc0 100644 --- a/library/compiler-builtins/libm/src/math/ilogb.rs +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -21,7 +21,11 @@ pub fn ilogb(x: f64) -> i32 { e } else if e == 0x7ff { force_eval!(0.0 / 0.0); - if (i << 12) != 0 { FP_ILOGBNAN } else { i32::MAX } + if (i << 12) != 0 { + FP_ILOGBNAN + } else { + i32::MAX + } } else { e - 0x3ff } diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs index 42441455ff3..9dd96c94474 100644 --- a/library/compiler-builtins/libm/src/math/k_sin.rs +++ b/library/compiler-builtins/libm/src/math/k_sin.rs @@ -49,5 +49,9 @@ pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { let w = z * z; let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); let v = z * x; - if iy == 0 { x + v * (S1 + z * r) } else { x - ((z * (0.5 * y - v * r) - y) - v * S1) } + if iy == 0 { + x + v * (S1 + z * r) + } else { + x - ((z * (0.5 * y - v * r) - y) - v * S1) + } } diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index b7f3fb09e15..65142c0d622 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -118,7 +118,11 @@ pub fn log1p(x: f64) -> f64 { k = (hu >> 20) as i32 - 0x3ff; /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ if k < 54 { - c = if k >= 2 { 1. - (f64::from_bits(ui) - x) } else { x - (f64::from_bits(ui) - 1.) }; + c = if k >= 2 { + 1. - (f64::from_bits(ui) - x) + } else { + x - (f64::from_bits(ui) - 1.) + }; c /= f64::from_bits(ui); } else { c = 0.; diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index bba5b8a2f21..23978e61c3c 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -73,7 +73,11 @@ pub fn log1pf(x: f32) -> f32 { k = (iu >> 23) as i32 - 0x7f; /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ if k < 25 { - c = if k >= 2 { 1. - (f32::from_bits(ui) - x) } else { x - (f32::from_bits(ui) - 1.) }; + c = if k >= 2 { + 1. - (f32::from_bits(ui) - x) + } else { + x - (f32::from_bits(ui) - 1.) + }; c /= f32::from_bits(ui); } else { c = 0.; diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 80b2a24999c..7e7d049b930 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -239,10 +239,18 @@ pub fn pow(x: f64, y: f64) -> f64 { /* over/underflow if x is not close to one */ if ix < 0x3fefffff { - return if hy < 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + return if hy < 0 { + s * HUGE * HUGE + } else { + s * TINY * TINY + }; } if ix > 0x3ff00000 { - return if hy > 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + return if hy > 0 { + s * HUGE * HUGE + } else { + s * TINY * TINY + }; } /* now |1-x| is TINY <= 2**-20, suffice to compute @@ -439,7 +447,11 @@ mod tests { fn pow_test(base: f64, exponent: f64, expected: f64) { let res = pow(base, exponent); assert!( - if expected.is_nan() { res.is_nan() } else { pow(base, exponent) == expected }, + if expected.is_nan() { + res.is_nan() + } else { + pow(base, exponent) == expected + }, "{} ** {} was {} instead of {}", base, exponent, @@ -449,11 +461,13 @@ mod tests { } fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { - sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); + sets.iter() + .for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); } fn test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) { - sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); + sets.iter() + .for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); } fn test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) { @@ -467,7 +481,11 @@ mod tests { #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] let res = force_eval!(res); assert!( - if exp.is_nan() { res.is_nan() } else { exp == res }, + if exp.is_nan() { + res.is_nan() + } else { + exp == res + }, "test for {} was {} instead of {}", val, res, @@ -515,7 +533,9 @@ mod tests { // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) // We can lump in pos/neg odd ints here because they don't seem to // cause panics (div by zero) in release mode (I think). - test_sets(ALL, &|v: f64| pow(f64::NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); + test_sets(ALL, &|v: f64| pow(f64::NEG_INFINITY, v), &|v: f64| { + pow(-0.0, -v) + }); } #[test] @@ -582,11 +602,15 @@ mod tests { // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| { - int_set.iter().for_each(|int| { - test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| pow(-1.0, *int) * pow(v, *int)); - }) - }); + [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS] + .iter() + .for_each(|int_set| { + int_set.iter().for_each(|int| { + test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| { + pow(-1.0, *int) * pow(v, *int) + }); + }) + }); // Negative base (imaginary results): // (-anything except 0 and Infinity ^ non-integer should be NAN) diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index 839c6c23d43..11c7a7cbd94 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -182,11 +182,19 @@ pub fn powf(x: f32, y: f32) -> f32 { /* if |y| > 2**27 */ /* over/underflow if x is not close to one */ if ix < 0x3f7ffff8 { - return if hy < 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; + return if hy < 0 { + sn * HUGE * HUGE + } else { + sn * TINY * TINY + }; } if ix > 0x3f800007 { - return if hy > 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; + return if hy > 0 { + sn * HUGE * HUGE + } else { + sn * TINY * TINY + }; } /* now |1-x| is TINY <= 2**-20, suffice to compute diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 917e90819a5..d677fd9dcb3 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -199,16 +199,28 @@ mod tests { fn test_near_pi() { let arg = 3.141592025756836; let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, -6.278329573009626e-7, -2.1125998133974653e-23)); + assert_eq!( + rem_pio2(arg), + (2, -6.278329573009626e-7, -2.1125998133974653e-23) + ); let arg = 3.141592033207416; let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, -6.20382377148128e-7, -2.1125998133974653e-23)); + assert_eq!( + rem_pio2(arg), + (2, -6.20382377148128e-7, -2.1125998133974653e-23) + ); let arg = 3.141592144966125; let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, -5.086236681942706e-7, -2.1125998133974653e-23)); + assert_eq!( + rem_pio2(arg), + (2, -5.086236681942706e-7, -2.1125998133974653e-23) + ); let arg = 3.141592979431152; let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, 3.2584135866119817e-7, -2.1125998133974653e-23)); + assert_eq!( + rem_pio2(arg), + (2, 3.2584135866119817e-7, -2.1125998133974653e-23) + ); } #[test] diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs index b8fae2c9801..709b63fcf29 100644 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -42,7 +42,11 @@ pub fn sinf(x: f32) -> f32 { if ix < 0x39800000 { /* |x| < 2**-12 */ /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); + force_eval!(if ix < 0x00800000 { + x / x1p120 + } else { + x + x1p120 + }); return x; } return k_sinf(x64); @@ -57,7 +61,11 @@ pub fn sinf(x: f32) -> f32 { return k_cosf(x64 - S1_PIO2); } } - return k_sinf(if sign { -(x64 + S2_PIO2) } else { -(x64 - S2_PIO2) }); + return k_sinf(if sign { + -(x64 + S2_PIO2) + } else { + -(x64 - S2_PIO2) + }); } if ix <= 0x40e231d5 { /* |x| ~<= 9*pi/4 */ diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs index eae08238e09..f24c063cd34 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -19,11 +19,17 @@ pub struct u256 { impl u256 { #[cfg(any(test, feature = "unstable-public-internals"))] - pub const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX }; + pub const MAX: Self = Self { + lo: u128::MAX, + hi: u128::MAX, + }; /// Reinterpret as a signed integer pub fn signed(self) -> i256 { - i256 { lo: self.lo, hi: self.hi } + i256 { + lo: self.lo, + hi: self.hi, + } } } @@ -39,7 +45,10 @@ impl i256 { /// Reinterpret as an unsigned integer #[cfg(any(test, feature = "unstable-public-internals"))] pub fn unsigned(self) -> u256 { - u256 { lo: self.lo, hi: self.hi } + u256 { + lo: self.lo, + hi: self.hi, + } } } @@ -53,7 +62,10 @@ impl MinInt for u256 { const ZERO: Self = Self { lo: 0, hi: 0 }; const ONE: Self = Self { lo: 1, hi: 0 }; const MIN: Self = Self { lo: 0, hi: 0 }; - const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX }; + const MAX: Self = Self { + lo: u128::MAX, + hi: u128::MAX, + }; } impl MinInt for i256 { @@ -65,8 +77,14 @@ impl MinInt for i256 { const BITS: u32 = 256; const ZERO: Self = Self { lo: 0, hi: 0 }; const ONE: Self = Self { lo: 1, hi: 0 }; - const MIN: Self = Self { lo: 0, hi: 1 << 127 }; - const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX << 1 }; + const MIN: Self = Self { + lo: 0, + hi: 1 << 127, + }; + const MAX: Self = Self { + lo: u128::MAX, + hi: u128::MAX << 1, + }; } macro_rules! impl_common { diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs index 2c71191ba53..d2010f0216e 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -13,23 +13,62 @@ fn hexu(v: u256) -> String { #[test] fn widen_u128() { - assert_eq!(u128::MAX.widen(), u256 { lo: u128::MAX, hi: 0 }); - assert_eq!(LOHI_SPLIT.widen(), u256 { lo: LOHI_SPLIT, hi: 0 }); + assert_eq!( + u128::MAX.widen(), + u256 { + lo: u128::MAX, + hi: 0 + } + ); + assert_eq!( + LOHI_SPLIT.widen(), + u256 { + lo: LOHI_SPLIT, + hi: 0 + } + ); } #[test] fn widen_i128() { assert_eq!((-1i128).widen(), u256::MAX.signed()); - assert_eq!((LOHI_SPLIT as i128).widen(), i256 { lo: LOHI_SPLIT, hi: u128::MAX }); + assert_eq!( + (LOHI_SPLIT as i128).widen(), + i256 { + lo: LOHI_SPLIT, + hi: u128::MAX + } + ); assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); } #[test] fn widen_mul_u128() { let tests = [ - (u128::MAX / 2, 2_u128, u256 { lo: u128::MAX - 1, hi: 0 }), - (u128::MAX, 2_u128, u256 { lo: u128::MAX - 1, hi: 1 }), - (u128::MAX, u128::MAX, u256 { lo: 1, hi: u128::MAX - 1 }), + ( + u128::MAX / 2, + 2_u128, + u256 { + lo: u128::MAX - 1, + hi: 0, + }, + ), + ( + u128::MAX, + 2_u128, + u256 { + lo: u128::MAX - 1, + hi: 1, + }, + ), + ( + u128::MAX, + u128::MAX, + u256 { + lo: 1, + hi: u128::MAX - 1, + }, + ), (0, 0, u256::ZERO), (1234u128, 0, u256::ZERO), (0, 1234, u256::ZERO), @@ -68,7 +107,13 @@ fn not_u256() { #[test] fn shr_u256() { - let only_low = [1, u16::MAX.into(), u32::MAX.into(), u64::MAX.into(), u128::MAX]; + let only_low = [ + 1, + u16::MAX.into(), + u32::MAX.into(), + u64::MAX.into(), + u128::MAX, + ]; let mut has_errors = false; let mut add_error = |a, b, expected, actual| { @@ -99,23 +144,106 @@ fn shr_u256() { } let check = [ - (u256::MAX, 1, u256 { lo: u128::MAX, hi: u128::MAX >> 1 }), - (u256::MAX, 5, u256 { lo: u128::MAX, hi: u128::MAX >> 5 }), - (u256::MAX, 63, u256 { lo: u128::MAX, hi: u64::MAX as u128 | (1 << 64) }), - (u256::MAX, 64, u256 { lo: u128::MAX, hi: u64::MAX as u128 }), - (u256::MAX, 65, u256 { lo: u128::MAX, hi: (u64::MAX >> 1) as u128 }), - (u256::MAX, 127, u256 { lo: u128::MAX, hi: 1 }), - (u256::MAX, 128, u256 { lo: u128::MAX, hi: 0 }), - (u256::MAX, 129, u256 { lo: u128::MAX >> 1, hi: 0 }), - (u256::MAX, 191, u256 { lo: u64::MAX as u128 | 1 << 64, hi: 0 }), - (u256::MAX, 192, u256 { lo: u64::MAX as u128, hi: 0 }), - (u256::MAX, 193, u256 { lo: u64::MAX as u128 >> 1, hi: 0 }), + ( + u256::MAX, + 1, + u256 { + lo: u128::MAX, + hi: u128::MAX >> 1, + }, + ), + ( + u256::MAX, + 5, + u256 { + lo: u128::MAX, + hi: u128::MAX >> 5, + }, + ), + ( + u256::MAX, + 63, + u256 { + lo: u128::MAX, + hi: u64::MAX as u128 | (1 << 64), + }, + ), + ( + u256::MAX, + 64, + u256 { + lo: u128::MAX, + hi: u64::MAX as u128, + }, + ), + ( + u256::MAX, + 65, + u256 { + lo: u128::MAX, + hi: (u64::MAX >> 1) as u128, + }, + ), + ( + u256::MAX, + 127, + u256 { + lo: u128::MAX, + hi: 1, + }, + ), + ( + u256::MAX, + 128, + u256 { + lo: u128::MAX, + hi: 0, + }, + ), + ( + u256::MAX, + 129, + u256 { + lo: u128::MAX >> 1, + hi: 0, + }, + ), + ( + u256::MAX, + 191, + u256 { + lo: u64::MAX as u128 | 1 << 64, + hi: 0, + }, + ), + ( + u256::MAX, + 192, + u256 { + lo: u64::MAX as u128, + hi: 0, + }, + ), + ( + u256::MAX, + 193, + u256 { + lo: u64::MAX as u128 >> 1, + hi: 0, + }, + ), (u256::MAX, 254, u256 { lo: 0b11, hi: 0 }), (u256::MAX, 255, u256 { lo: 1, hi: 0 }), ( - u256 { hi: LOHI_SPLIT, lo: 0 }, + u256 { + hi: LOHI_SPLIT, + lo: 0, + }, 64, - u256 { lo: 0xffffffffffffffff0000000000000000, hi: 0xaaaaaaaaaaaaaaaa }, + u256 { + lo: 0xffffffffffffffff0000000000000000, + hi: 0xaaaaaaaaaaaaaaaa, + }, ), ]; diff --git a/library/compiler-builtins/libm/src/math/support/env.rs b/library/compiler-builtins/libm/src/math/support/env.rs index 796309372a5..53ae32f658d 100644 --- a/library/compiler-builtins/libm/src/math/support/env.rs +++ b/library/compiler-builtins/libm/src/math/support/env.rs @@ -25,7 +25,10 @@ impl FpResult { /// Return `val` with `Status::OK`. pub fn ok(val: T) -> Self { - Self { val, status: Status::OK } + Self { + val, + status: Status::OK, + } } } diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index fac10483237..8094a7b84d5 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -105,7 +105,11 @@ pub trait Float: /// if `NaN` should not be treated separately. #[allow(dead_code)] fn eq_repr(self, rhs: Self) -> bool { - if self.is_nan() && rhs.is_nan() { true } else { self.biteq(rhs) } + if self.is_nan() && rhs.is_nan() { + true + } else { + self.biteq(rhs) + } } /// Returns true if the value is NaN. @@ -149,7 +153,11 @@ pub trait Float: /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. fn from_parts(negative: bool, exponent: u32, significand: Self::Int) -> Self { - let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; + let sign = if negative { + Self::Int::ONE + } else { + Self::Int::ZERO + }; Self::from_bits( (sign << (Self::BITS - 1)) | (Self::Int::cast_from(exponent & Self::EXP_SAT) << Self::SIG_BITS) @@ -173,7 +181,11 @@ pub trait Float: /// Returns a number that represents the sign of self. #[allow(dead_code)] fn signum(self) -> Self { - if self.is_nan() { self } else { Self::ONE.copysign(self) } + if self.is_nan() { + self + } else { + Self::ONE.copysign(self) + } } } @@ -273,18 +285,61 @@ macro_rules! float_impl { } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); - (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) + ( + 1i32.wrapping_sub(shift as i32), + significand << shift as Self::Int, + ) } } }; } #[cfg(f16_enabled)] -float_impl!(f16, u16, i16, 16, 10, f16::from_bits, f16::to_bits, fmaf16, fmaf16); -float_impl!(f32, u32, i32, 32, 23, f32_from_bits, f32_to_bits, fmaf, fmaf32); -float_impl!(f64, u64, i64, 64, 52, f64_from_bits, f64_to_bits, fma, fmaf64); +float_impl!( + f16, + u16, + i16, + 16, + 10, + f16::from_bits, + f16::to_bits, + fmaf16, + fmaf16 +); +float_impl!( + f32, + u32, + i32, + 32, + 23, + f32_from_bits, + f32_to_bits, + fmaf, + fmaf32 +); +float_impl!( + f64, + u64, + i64, + 64, + 52, + f64_from_bits, + f64_to_bits, + fma, + fmaf64 +); #[cfg(f128_enabled)] -float_impl!(f128, u128, i128, 128, 112, f128::from_bits, f128::to_bits, fmaf128, fmaf128); +float_impl!( + f128, + u128, + i128, + 128, + 112, + f128::from_bits, + f128::to_bits, + fmaf128, + fmaf128 +); /* FIXME(msrv): vendor some things that are not const stable at our MSRV */ @@ -424,7 +479,10 @@ mod tests { // `from_parts` assert_biteq!(f32::from_parts(true, f32::EXP_BIAS, 0), -1.0f32); - assert_biteq!(f32::from_parts(false, 10 + f32::EXP_BIAS, 0), hf32!("0x1p10")); + assert_biteq!( + f32::from_parts(false, 10 + f32::EXP_BIAS, 0), + hf32!("0x1p10") + ); assert_biteq!(f32::from_parts(false, 0, 1), f32::from_bits(0x1)); } @@ -451,7 +509,10 @@ mod tests { // `from_parts` assert_biteq!(f64::from_parts(true, f64::EXP_BIAS, 0), -1.0f64); - assert_biteq!(f64::from_parts(false, 10 + f64::EXP_BIAS, 0), hf64!("0x1p10")); + assert_biteq!( + f64::from_parts(false, 10 + f64::EXP_BIAS, 0), + hf64!("0x1p10") + ); assert_biteq!(f64::from_parts(false, 0, 1), f64::from_bits(0x1)); } diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index 819e2f56e36..85569d98aef 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -234,7 +234,9 @@ const fn parse_hex(mut b: &[u8]) -> Result { match c { b'.' => { if seen_point { - return Err(HexFloatParseError("unexpected '.' parsing fractional digits")); + return Err(HexFloatParseError( + "unexpected '.' parsing fractional digits", + )); } seen_point = true; continue; @@ -294,7 +296,9 @@ const fn parse_hex(mut b: &[u8]) -> Result { } if !some_digits { - return Err(HexFloatParseError("at least one exponent digit is required")); + return Err(HexFloatParseError( + "at least one exponent digit is required", + )); }; { @@ -542,7 +546,11 @@ mod parse_tests { for k in -149..=127 { let s = format!("0x1p{k}"); let x = hf32(&s); - let y = if k < 0 { 0.5f32.powi(-k) } else { 2.0f32.powi(k) }; + let y = if k < 0 { + 0.5f32.powi(-k) + } else { + 2.0f32.powi(k) + }; assert_eq!(x, y); } @@ -613,9 +621,14 @@ mod parse_tests { fn rounding_extreme_underflow() { for k in 1..1000 { let s = format!("0x1p{}", -149 - k); - let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; + let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { + unreachable!() + }; assert_eq!(bits, 0, "{s} should round to zero, got bits={bits}"); - assert!(status.underflow(), "should indicate underflow when parsing {s}"); + assert!( + status.underflow(), + "should indicate underflow when parsing {s}" + ); assert!(status.inexact(), "should indicate inexact when parsing {s}"); } } @@ -623,11 +636,15 @@ mod parse_tests { fn long_tail() { for k in 1..1000 { let s = format!("0x1.{}p0", "0".repeat(k)); - let Ok(bits) = parse_hex_exact(&s, 32, 23) else { panic!("parsing {s} failed") }; + let Ok(bits) = parse_hex_exact(&s, 32, 23) else { + panic!("parsing {s} failed") + }; assert_eq!(f32::from_bits(bits as u32), 1.0); let s = format!("0x1.{}1p0", "0".repeat(k)); - let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; + let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { + unreachable!() + }; if status.inexact() { assert!(1.0 == f32::from_bits(bits as u32)); } else { @@ -839,7 +856,10 @@ mod parse_tests { assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000_u32); assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000_u64); #[cfg(f128_enabled)] - assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); + assert_eq!( + hf128!("0x1.ffep+8").to_bits(), + 0x4007ffe0000000000000000000000000_u128 + ); } } @@ -1143,8 +1163,14 @@ mod print_tests { #[cfg(f128_enabled)] { - assert_eq!(Hexf(f128::MAX).to_string(), "0x1.ffffffffffffffffffffffffffffp+16383"); - assert_eq!(Hexf(f128::MIN).to_string(), "-0x1.ffffffffffffffffffffffffffffp+16383"); + assert_eq!( + Hexf(f128::MAX).to_string(), + "0x1.ffffffffffffffffffffffffffffp+16383" + ); + assert_eq!( + Hexf(f128::MIN).to_string(), + "-0x1.ffffffffffffffffffffffffffffp+16383" + ); assert_eq!(Hexf(f128::ZERO).to_string(), "0x0p+0"); assert_eq!(Hexf(f128::NEG_ZERO).to_string(), "-0x0p+0"); assert_eq!(Hexf(f128::NAN).to_string(), "NaN"); diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs index a074ca5540a..a072bdec56e 100644 --- a/library/compiler-builtins/libm/src/math/tan.rs +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -53,7 +53,11 @@ pub fn tan(x: f64) -> f64 { if ix < 0x3e400000 { /* |x| < 2**-27 */ /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00100000 { x / x1p120 as f64 } else { x + x1p120 as f64 }); + force_eval!(if ix < 0x00100000 { + x / x1p120 as f64 + } else { + x + x1p120 as f64 + }); return x; } return k_tan(x, 0.0, 0); diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs index 7586aae4c7e..8bcf9581ff6 100644 --- a/library/compiler-builtins/libm/src/math/tanf.rs +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -42,7 +42,11 @@ pub fn tanf(x: f32) -> f32 { if ix < 0x39800000 { /* |x| < 2**-12 */ /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); + force_eval!(if ix < 0x00800000 { + x / x1p120 + } else { + x + x1p120 + }); return x; } return k_tanf(x64, false); -- cgit 1.4.1-3-g733a5 From 98acedc9144c3ea6dad685cb6b673631e430c66e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 23:30:12 +0000 Subject: Remove libm CI dockerfiles These are identical to what already exists in compiler-builtins except for some base image changes, so we can eliminate the duplicates. --- .../ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 15 --------------- .../ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 14 -------------- .../ci/docker/arm-unknown-linux-gnueabihf/Dockerfile | 14 -------------- .../docker/armv7-unknown-linux-gnueabihf/Dockerfile | 14 -------------- .../libm/ci/docker/i586-unknown-linux-gnu/Dockerfile | 5 ----- .../libm/ci/docker/i686-unknown-linux-gnu/Dockerfile | 5 ----- .../docker/loongarch64-unknown-linux-gnu/Dockerfile | 13 ------------- .../libm/ci/docker/mips-unknown-linux-gnu/Dockerfile | 15 --------------- .../docker/mips64-unknown-linux-gnuabi64/Dockerfile | 19 ------------------- .../docker/mips64el-unknown-linux-gnuabi64/Dockerfile | 18 ------------------ .../ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 15 --------------- .../ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 15 --------------- .../ci/docker/powerpc64-unknown-linux-gnu/Dockerfile | 15 --------------- .../docker/powerpc64le-unknown-linux-gnu/Dockerfile | 16 ---------------- .../ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile | 15 --------------- .../etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile | 9 --------- .../etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile | 9 --------- .../libm/ci/docker/thumbv7em-none-eabihf/Dockerfile | 9 --------- .../etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile | 9 --------- .../ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 5 ----- 20 files changed, 249 deletions(-) delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/etc/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 7fa06b28601..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-aarch64-linux-gnu m4 make libc6-dev-arm64-cross \ - qemu-user-static - -ENV TOOLCHAIN_PREFIX=aarch64-linux-gnu- -ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-aarch64-static \ - AR_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile deleted file mode 100644 index e070a7d936e..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static - -ENV TOOLCHAIN_PREFIX=arm-linux-gnueabi- -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER=qemu-arm-static \ - AR_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"ar \ - CC_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile deleted file mode 100644 index 29f1e04a9b5..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static - -ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ - AR_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ - CC_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile deleted file mode 100644 index 0a30801b44d..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static - -ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- -ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ - AR_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ - CC_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 37e206a84fc..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc-multilib m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/etc/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 37e206a84fc..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc-multilib m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/etc/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index a9ce320e8b4..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-14-loongarch64-linux-gnu libc6-dev-loong64-cross - -ENV CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER=loongarch64-linux-gnu-gcc-14 \ - CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-loongarch64-static \ - AR_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-ar \ - CC_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-gcc-14 \ - QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 298208c925a..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-mips-linux-gnu libc6-dev-mips-cross \ - binfmt-support qemu-user-static qemu-system-mips - -ENV TOOLCHAIN_PREFIX=mips-linux-gnu- -ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER=qemu-mips-static \ - AR_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/mips-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile deleted file mode 100644 index 101b3853efe..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates \ - gcc \ - gcc-mips64-linux-gnuabi64 \ - libc6-dev \ - libc6-dev-mips64-cross \ - qemu-user-static \ - qemu-system-mips - -ENV TOOLCHAIN_PREFIX=mips64-linux-gnuabi64- -ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64-static \ - AR_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ - CC_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile deleted file mode 100644 index 0eb14f9acf5..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates \ - gcc \ - gcc-mips64el-linux-gnuabi64 \ - libc6-dev \ - libc6-dev-mips64el-cross \ - qemu-user-static - -ENV TOOLCHAIN_PREFIX=mips64el-linux-gnuabi64- -ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64el-static \ - AR_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ - CC_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 1b9817cfef8..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ - binfmt-support qemu-user-static - -ENV TOOLCHAIN_PREFIX=mipsel-linux-gnu- -ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER=qemu-mipsel-static \ - AR_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 1ea2e30a242..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ - qemu-system-ppc - -ENV TOOLCHAIN_PREFIX=powerpc-linux-gnu- -ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc-static \ - AR_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 373814bcafd..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ - binfmt-support qemu-user-static qemu-system-ppc - -ENV TOOLCHAIN_PREFIX=powerpc64-linux-gnu- -ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64-static \ - AR_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 403bb1d95b2..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ - qemu-system-ppc - -ENV TOOLCHAIN_PREFIX=powerpc64le-linux-gnu- -ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64le-static \ - AR_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_CPU=POWER8 \ - QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 5f8a2892411..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-riscv64-linux-gnu libc6-dev-riscv64-cross \ - qemu-system-riscv64 - -ENV TOOLCHAIN_PREFIX=riscv64-linux-gnu- -ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER=qemu-riscv64-static \ - AR_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/riscv64-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile deleted file mode 100644 index ad0d4351ea6..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -ARG IMAGE=ubuntu:24.04 -FROM $IMAGE - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-none-eabi \ - libnewlib-arm-none-eabi -ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile deleted file mode 100644 index ad0d4351ea6..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -ARG IMAGE=ubuntu:24.04 -FROM $IMAGE - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-none-eabi \ - libnewlib-arm-none-eabi -ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile deleted file mode 100644 index ad0d4351ea6..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -ARG IMAGE=ubuntu:24.04 -FROM $IMAGE - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-none-eabi \ - libnewlib-arm-none-eabi -ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile deleted file mode 100644 index ad0d4351ea6..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -ARG IMAGE=ubuntu:24.04 -FROM $IMAGE - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-none-eabi \ - libnewlib-arm-none-eabi -ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index c84a31c57a9..00000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc m4 make libc6-dev ca-certificates -- cgit 1.4.1-3-g733a5 From 9b8065decbddabf399a7d9c73928967c044115f7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 23:34:41 +0000 Subject: Combine the libm .gitignore --- library/compiler-builtins/.gitignore | 13 ++++++++++++- library/compiler-builtins/etc/libm/.gitignore | 11 ----------- 2 files changed, 12 insertions(+), 12 deletions(-) delete mode 100644 library/compiler-builtins/etc/libm/.gitignore diff --git a/library/compiler-builtins/.gitignore b/library/compiler-builtins/.gitignore index 97df30ffaa8..5287a6c72be 100644 --- a/library/compiler-builtins/.gitignore +++ b/library/compiler-builtins/.gitignore @@ -1,5 +1,16 @@ -*.rs.bk +# Rust files Cargo.lock target + +# Sources for external files compiler-rt *.tar.gz + +# Benchmark cache +baseline-* +iai-home + +# Temporary files +*.bk +*.rs.bk +.#* diff --git a/library/compiler-builtins/etc/libm/.gitignore b/library/compiler-builtins/etc/libm/.gitignore deleted file mode 100644 index d5caba1a0f3..00000000000 --- a/library/compiler-builtins/etc/libm/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -**.bk -.#* -/bin -/math/src -target -Cargo.lock -**.tar.gz - -# Benchmark cache -iai-home -baseline-* -- cgit 1.4.1-3-g733a5 From c35cccd6764838330fb12320a33740e15ec8bb35 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 23:35:50 +0000 Subject: Move the libm .editorconfig to root --- library/compiler-builtins/.editorconfig | 16 ++++++++++++++++ library/compiler-builtins/etc/libm/.editorconfig | 21 --------------------- 2 files changed, 16 insertions(+), 21 deletions(-) create mode 100644 library/compiler-builtins/.editorconfig delete mode 100644 library/compiler-builtins/etc/libm/.editorconfig diff --git a/library/compiler-builtins/.editorconfig b/library/compiler-builtins/.editorconfig new file mode 100644 index 00000000000..f0735cedfbd --- /dev/null +++ b/library/compiler-builtins/.editorconfig @@ -0,0 +1,16 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 4 + +[*.yml] +indent_size = 2 diff --git a/library/compiler-builtins/etc/libm/.editorconfig b/library/compiler-builtins/etc/libm/.editorconfig deleted file mode 100644 index ec6e107d547..00000000000 --- a/library/compiler-builtins/etc/libm/.editorconfig +++ /dev/null @@ -1,21 +0,0 @@ -# EditorConfig helps developers define and maintain consistent -# coding styles between different editors and IDEs -# editorconfig.org - -root = true - -[*] -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true -indent_style = space -indent_size = 4 - -[*.md] -# double whitespace at end of line -# denotes a line break in Markdown -trim_trailing_whitespace = false - -[*.yml] -indent_size = 2 -- cgit 1.4.1-3-g733a5 From a48de6950ce784299dd06fc71c015ed48c09a95f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 01:18:08 +0000 Subject: Move builtins-test-intrinsics out of the workspace This crate doesn't need to be a default member since it requires the opposite settings from everything else. Exclude it from the workspace and run it only when explicitly requested. This also makes `cargo t --no-default-features` work without additional qualifiers. `--no-default-features` still needs to be passed to ensure `#![compiler_builtins]` does not get set. compiler-builtins needs doctests disabled in order for everything to work correctly, since this causes an error running rustdoc that is unrelated to features (our `compiler_builtins` is getting into the crate graph before that from the sysroot, but `#![compiler_builtins]` is not set). We can also remove `test = false` and `doctest = false` in `builtins-test` since these no longer cause issues. This is unlikely to be used but it is better to not quietly skip if anything ever gets added by accident. --- library/compiler-builtins/Cargo.toml | 11 +++++++---- library/compiler-builtins/builtins-test-intrinsics/Cargo.toml | 8 +++++++- library/compiler-builtins/builtins-test/Cargo.toml | 4 ---- library/compiler-builtins/ci/run-docker.sh | 9 ++++++--- library/compiler-builtins/ci/run.sh | 10 +++++----- library/compiler-builtins/compiler-builtins/Cargo.toml | 3 ++- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 155fb00b195..feaeb97915b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,11 +1,7 @@ [workspace] resolver = "3" members = [ - # Note that builtins-test-intrinsics cannot be a default member because it - # needs the `mangled-names` feature disabled, while `builtins-test` needs - # it enabled. "builtins-test", - "builtins-test-intrinsics", "compiler-builtins", "crates/libm-macros", "libm", @@ -24,6 +20,13 @@ default-members = [ "libm", ] +exclude = [ + # `builtins-test-intrinsics` needs the feature `compiler-builtins` enabled + # and `mangled-names` disabled, which is the opposite of what is needed for + # other tests, so it makes sense to keep it out of the workspace. + "builtins-test-intrinsics", +] + [profile.release] panic = "abort" diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 9dbd3c32f96..6d88cbec90d 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -6,7 +6,13 @@ publish = false [dependencies] compiler_builtins = { path = "../compiler-builtins", features = ["compiler-builtins"]} -panic-handler = { path = '../crates/panic-handler' } +panic-handler = { path = "../crates/panic-handler" } [features] c = ["compiler_builtins/c"] + +[profile.release] +panic = "abort" + +[profile.dev] +panic = "abort" diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index 526e9b18af0..18185d8fe40 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -5,10 +5,6 @@ authors = ["Alex Crichton "] edition = "2024" publish = false -[lib] -test = false -doctest = false - [dependencies] # For fuzzing tests we want a deterministic seedable RNG. We also eliminate potential # problems with system RNGs on the variety of platforms this crate is tested on. diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 2c27ab7955b..d07e7784c9a 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -19,9 +19,11 @@ run() { echo "target is emulated" fi - # This directory needs to exist before calling docker, otherwise docker will create it but it - # will be owned by root + # Directories and files that do not yet exist need to be created before + # calling docker, otherwise docker will create them but they will be owned + # by root. mkdir -p target + cargo generate-lockfile --manifest-path builtins-test-intrinsics/Cargo.toml run_cmd="HOME=/tmp" @@ -53,7 +55,8 @@ run() { # Use rustc provided by a docker image docker volume create compiler-builtins-cache build_args=( - "--build-arg" "IMAGE=${DOCKER_BASE_IMAGE:-rustlang/rust:nightly}" + "--build-arg" + "IMAGE=${DOCKER_BASE_IMAGE:-rustlang/rust:nightly}" ) run_args=(-v "compiler-builtins-cache:/builtins-target") run_cmd="$run_cmd HOME=/tmp" "USING_CONTAINER_RUSTC=1" diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 49cc1628652..96a6e92a9b9 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -122,7 +122,9 @@ done rm -f "${rlib_paths[@]}" build_intrinsics_test() { - cargo build --target "$target" -v --package builtins-test-intrinsics "$@" + cargo build \ + --target "$target" --verbose \ + --manifest-path builtins-test-intrinsics/Cargo.toml "$@" } # Verify that we haven't dropped any intrinsics/symbols @@ -133,10 +135,8 @@ build_intrinsics_test --features c --release # Verify that there are no undefined symbols to `panic` within our # implementations -CARGO_PROFILE_DEV_LTO=true \ - cargo build --target "$target" --package builtins-test-intrinsics -CARGO_PROFILE_RELEASE_LTO=true \ - cargo build --target "$target" --package builtins-test-intrinsics --release +CARGO_PROFILE_DEV_LTO=true build_intrinsics_test +CARGO_PROFILE_RELEASE_LTO=true build_intrinsics_test --release # Ensure no references to any symbols from core update_rlib_paths diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 3151546ab8d..c9503bbce8e 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -25,8 +25,9 @@ include = [ links = 'compiler-rt' [lib] -test = false bench = false +doctest = false +test = false [dependencies] # For more information on this dependency see -- cgit 1.4.1-3-g733a5 From 141c7b06c416e123ec4c6785c104785987cbe894 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 03:02:47 +0000 Subject: Add remaining `libm` crates to the workspace These are still not yet covered in CI since we always name explicit packages there, but all crates are now part of the workspace. --- library/compiler-builtins/Cargo.toml | 10 ++++------ library/compiler-builtins/ci/run.sh | 16 ++++++++-------- .../compiler-builtins/libm-test/tests/check_coverage.rs | 4 ++-- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index feaeb97915b..194a2cdc2f7 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -4,20 +4,18 @@ members = [ "builtins-test", "compiler-builtins", "crates/libm-macros", + "crates/musl-math-sys", + "crates/util", "libm", - # FIXME(libm): disabled until tests work in CI - # "libm-test", - # "crates/musl-math-sys", - # "crates/util", + "libm-test", ] default-members = [ "builtins-test", "compiler-builtins", "crates/libm-macros", - # FIXME(libm): disabled until tests work in CI - # "crates/libm-test" "libm", + "libm-test", ] exclude = [ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 96a6e92a9b9..bce90d48d50 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -58,14 +58,14 @@ update_rlib_paths() { update_rlib_paths rm -f "${rlib_paths[@]}" -cargo build --target "$target" -cargo build --target "$target" --release -cargo build --target "$target" --features c -cargo build --target "$target" --release --features c -cargo build --target "$target" --features no-asm -cargo build --target "$target" --release --features no-asm -cargo build --target "$target" --features no-f16-f128 -cargo build --target "$target" --release --features no-f16-f128 +cargo build -p compiler_builtins --target "$target" +cargo build -p compiler_builtins --target "$target" --release +cargo build -p compiler_builtins --target "$target" --features c +cargo build -p compiler_builtins --target "$target" --release --features c +cargo build -p compiler_builtins --target "$target" --features no-asm +cargo build -p compiler_builtins --target "$target" --release --features no-asm +cargo build -p compiler_builtins --target "$target" --features no-f16-f128 +cargo build -p compiler_builtins --target "$target" --release --features no-f16-f128 PREFIX=${target//unknown-/}- case "$target" in diff --git a/library/compiler-builtins/libm-test/tests/check_coverage.rs b/library/compiler-builtins/libm-test/tests/check_coverage.rs index c23298686fa..3b445a3de9d 100644 --- a/library/compiler-builtins/libm-test/tests/check_coverage.rs +++ b/library/compiler-builtins/libm-test/tests/check_coverage.rs @@ -19,7 +19,7 @@ macro_rules! callback { #[test] fn test_for_each_function_all_included() { - let all_functions: HashSet<_> = include_str!("../../../etc/function-list.txt") + let all_functions: HashSet<_> = include_str!("../../etc/function-list.txt") .lines() .filter(|line| !line.starts_with("#")) .collect(); @@ -52,7 +52,7 @@ fn ensure_list_updated() { } let res = Command::new("python3") - .arg(Path::new(env!("CARGO_MANIFEST_DIR")).join("../../etc/update-api-list.py")) + .arg(Path::new(env!("CARGO_MANIFEST_DIR")).join("../etc/update-api-list.py")) .arg("--check") .status() .unwrap(); -- cgit 1.4.1-3-g733a5 From 0d0d3172424cfc4386976d35fc1ce7710a07d1eb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 03:28:17 +0000 Subject: Enable icount benchmarks in CI --- .../compiler-builtins/.github/workflows/main.yaml | 55 ++- library/compiler-builtins/ci/bench-icount.sh | 58 +++ library/compiler-builtins/ci/ci-util.py | 416 +++++++++++++++++++++ .../compiler-builtins/compiler-builtins/Cargo.toml | 3 +- .../compiler-builtins/etc/libm/ci/bench-icount.sh | 58 --- library/compiler-builtins/etc/libm/ci/ci-util.py | 416 --------------------- 6 files changed, 529 insertions(+), 477 deletions(-) create mode 100755 library/compiler-builtins/ci/bench-icount.sh create mode 100755 library/compiler-builtins/ci/ci-util.py delete mode 100755 library/compiler-builtins/etc/libm/ci/bench-icount.sh delete mode 100755 library/compiler-builtins/etc/libm/ci/ci-util.py diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index eec747a2436..54cfd506e83 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -13,6 +13,7 @@ env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings RUST_BACKTRACE: full + BENCHMARK_RUSTC: nightly-2025-01-16 # Pin the toolchain for reproducable results jobs: test: @@ -161,6 +162,55 @@ jobs: - uses: Swatinem/rust-cache@v2 - run: cargo clippy -- -D clippy::all + benchmarks: + name: Benchmarks + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - uses: actions/checkout@master + with: + submodules: true + - uses: taiki-e/install-action@cargo-binstall + + - name: Set up dependencies + run: | + sudo apt-get update + sudo apt-get install -y valgrind gdb libc6-dbg # Needed for iai-callgrind + rustup update "$BENCHMARK_RUSTC" --no-self-update + rustup default "$BENCHMARK_RUSTC" + # Install the version of iai-callgrind-runner that is specified in Cargo.toml + iai_version="$(cargo metadata --format-version=1 --features icount | + jq -r '.packages[] | select(.name == "iai-callgrind").version')" + cargo binstall -y iai-callgrind-runner --version "$iai_version" + sudo apt-get install valgrind + - uses: Swatinem/rust-cache@v2 + + - name: Run icount benchmarks + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: ./ci/bench-icount.sh + + - name: Upload the benchmark baseline + uses: actions/upload-artifact@v4 + with: + name: ${{ env.BASELINE_NAME }} + path: ${{ env.BASELINE_NAME }}.tar.xz + + - name: Run wall time benchmarks + run: | + # Always use the same seed for benchmarks. Ideally we should switch to a + # non-random generator. + export LIBM_SEED=benchesbenchesbenchesbencheswoo! + cargo bench --package libm-test \ + --no-default-features \ + --features short-benchmarks,build-musl,libm/force-soft-floats + + - name: Print test logs if available + if: always() + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + miri: name: Miri runs-on: ubuntu-24.04 @@ -189,10 +239,11 @@ jobs: success: needs: - - test - - rustfmt + - benchmarks - clippy - miri + - rustfmt + - test runs-on: ubuntu-24.04 # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its diff --git a/library/compiler-builtins/ci/bench-icount.sh b/library/compiler-builtins/ci/bench-icount.sh new file mode 100755 index 00000000000..4d93e257a6c --- /dev/null +++ b/library/compiler-builtins/ci/bench-icount.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +set -eux + +iai_home="iai-home" + +# Download the baseline from master +./ci/ci-util.py locate-baseline --download --extract + +# Run benchmarks once +function run_icount_benchmarks() { + cargo_args=( + "--bench" "icount" + "--no-default-features" + "--features" "unstable,unstable-float,icount" + ) + + iai_args=( + "--home" "$(pwd)/$iai_home" + "--regression=ir=5.0" + "--save-summary" + ) + + # Parse `cargo_arg0 cargo_arg1 -- iai_arg0 iai_arg1` syntax + parsing_iai_args=0 + while [ "$#" -gt 0 ]; do + if [ "$parsing_iai_args" == "1" ]; then + iai_args+=("$1") + elif [ "$1" == "--" ]; then + parsing_iai_args=1 + else + cargo_args+=("$1") + fi + + shift + done + + # Run iai-callgrind benchmarks + cargo bench "${cargo_args[@]}" -- "${iai_args[@]}" + + # NB: iai-callgrind should exit on error but does not, so we inspect the sumary + # for errors. See https://github.com/iai-callgrind/iai-callgrind/issues/337 + if [ -n "${PR_NUMBER:-}" ]; then + # If this is for a pull request, ignore regressions if specified. + ./ci/ci-util.py check-regressions --home "$iai_home" --allow-pr-override "$PR_NUMBER" + else + ./ci/ci-util.py check-regressions --home "$iai_home" || true + fi +} + +# Run once with softfloats, once with arch instructions enabled +run_icount_benchmarks --features force-soft-floats -- --save-baseline=softfloat +run_icount_benchmarks -- --save-baseline=hardfloat + +# Name and tar the new baseline +name="baseline-icount-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}" +echo "BASELINE_NAME=$name" >>"$GITHUB_ENV" +tar cJf "$name.tar.xz" "$iai_home" diff --git a/library/compiler-builtins/ci/ci-util.py b/library/compiler-builtins/ci/ci-util.py new file mode 100755 index 00000000000..d9e402d6bd7 --- /dev/null +++ b/library/compiler-builtins/ci/ci-util.py @@ -0,0 +1,416 @@ +#!/usr/bin/env python3 +"""Utilities for CI. + +This dynamically prepares a list of routines that had a source file change based on +git history. +""" + +import json +import os +import subprocess as sp +import sys +from dataclasses import dataclass +from glob import glob, iglob +from inspect import cleandoc +from os import getenv +from pathlib import Path +from typing import TypedDict, Self + +USAGE = cleandoc( + """ + usage: + + ./ci/ci-util.py [flags] + + COMMAND: + generate-matrix + Calculate a matrix of which functions had source change, print that as + a JSON object. + + locate-baseline [--download] [--extract] + Locate the most recent benchmark baseline available in CI and, if flags + specify, download and extract it. Never exits with nonzero status if + downloading fails. + + Note that `--extract` will overwrite files in `iai-home`. + + check-regressions [--home iai-home] [--allow-pr-override pr_number] + Check `iai-home` (or `iai-home` if unspecified) for `summary.json` + files and see if there are any regressions. This is used as a workaround + for `iai-callgrind` not exiting with error status; see + . + + If `--allow-pr-override` is specified, the regression check will not exit + with failure if any line in the PR starts with `allow-regressions`. + """ +) + +REPO_ROOT = Path(__file__).parent.parent +GIT = ["git", "-C", REPO_ROOT] +DEFAULT_BRANCH = "master" +WORKFLOW_NAME = "CI" # Workflow that generates the benchmark artifacts +ARTIFACT_GLOB = "baseline-icount*" +# Place this in a PR body to skip regression checks (must be at the start of a line). +REGRESSION_DIRECTIVE = "ci: allow-regressions" +# Place this in a PR body to skip extensive tests +SKIP_EXTENSIVE_DIRECTIVE = "ci: skip-extensive" +# Place this in a PR body to allow running a large number of extensive tests. If not +# set, this script will error out if a threshold is exceeded in order to avoid +# accidentally spending huge amounts of CI time. +ALLOW_MANY_EXTENSIVE_DIRECTIVE = "ci: allow-many-extensive" +MANY_EXTENSIVE_THRESHOLD = 20 + +# Don't run exhaustive tests if these files change, even if they contaiin a function +# definition. +IGNORE_FILES = [ + "libm/src/math/support/", + "libm/src/libm_helper.rs", + "libm/src/math/arch/intrinsics.rs", +] + +TYPES = ["f16", "f32", "f64", "f128"] + + +def eprint(*args, **kwargs): + """Print to stderr.""" + print(*args, file=sys.stderr, **kwargs) + + +@dataclass +class PrInfo: + """GitHub response for PR query""" + + body: str + commits: list[str] + created_at: str + number: int + + @classmethod + def load(cls, pr_number: int | str) -> Self: + """For a given PR number, query the body and commit list""" + pr_info = sp.check_output( + [ + "gh", + "pr", + "view", + str(pr_number), + "--json=number,commits,body,createdAt", + # Flatten the commit list to only hashes, change a key to snake naming + "--jq=.commits |= map(.oid) | .created_at = .createdAt | del(.createdAt)", + ], + text=True, + ) + eprint("PR info:", json.dumps(pr_info, indent=4)) + return cls(**json.loads(pr_info)) + + def contains_directive(self, directive: str) -> bool: + """Return true if the provided directive is on a line in the PR body""" + lines = self.body.splitlines() + return any(line.startswith(directive) for line in lines) + + +class FunctionDef(TypedDict): + """Type for an entry in `function-definitions.json`""" + + sources: list[str] + type: str + + +@dataclass +class Context: + gh_ref: str | None + changed: list[Path] + defs: dict[str, FunctionDef] + + def __init__(self) -> None: + self.gh_ref = getenv("GITHUB_REF") + self.changed = [] + self._init_change_list() + + with open(REPO_ROOT.joinpath("etc/function-definitions.json")) as f: + defs = json.load(f) + + defs.pop("__comment", None) + self.defs = defs + + def _init_change_list(self): + """Create a list of files that have been changed. This uses GITHUB_REF if + available, otherwise a diff between `HEAD` and `master`. + """ + + # For pull requests, GitHub creates a ref `refs/pull/1234/merge` (1234 being + # the PR number), and sets this as `GITHUB_REF`. + ref = self.gh_ref + eprint(f"using ref `{ref}`") + if ref is None or "merge" not in ref: + # If the ref is not for `merge` then we are not in PR CI + eprint("No diff available for ref") + return + + # The ref is for a dummy merge commit. We can extract the merge base by + # inspecting all parents (`^@`). + merge_sha = sp.check_output( + GIT + ["show-ref", "--hash", ref], text=True + ).strip() + merge_log = sp.check_output(GIT + ["log", "-1", merge_sha], text=True) + eprint(f"Merge:\n{merge_log}\n") + + parents = ( + sp.check_output(GIT + ["rev-parse", f"{merge_sha}^@"], text=True) + .strip() + .splitlines() + ) + assert len(parents) == 2, f"expected two-parent merge but got:\n{parents}" + base = parents[0].strip() + incoming = parents[1].strip() + + eprint(f"base: {base}, incoming: {incoming}") + textlist = sp.check_output( + GIT + ["diff", base, incoming, "--name-only"], text=True + ) + self.changed = [Path(p) for p in textlist.splitlines()] + + @staticmethod + def _ignore_file(fname: str) -> bool: + return any(fname.startswith(pfx) for pfx in IGNORE_FILES) + + def changed_routines(self) -> dict[str, list[str]]: + """Create a list of routines for which one or more files have been updated, + separated by type. + """ + routines = set() + for name, meta in self.defs.items(): + # Don't update if changes to the file should be ignored + sources = (f for f in meta["sources"] if not self._ignore_file(f)) + + # Select changed files + changed = [f for f in sources if Path(f) in self.changed] + + if len(changed) > 0: + eprint(f"changed files for {name}: {changed}") + routines.add(name) + + ret: dict[str, list[str]] = {} + for r in sorted(routines): + ret.setdefault(self.defs[r]["type"], []).append(r) + + return ret + + def make_workflow_output(self) -> str: + """Create a JSON object a list items for each type's changed files, if any + did change, and the routines that were affected by the change. + """ + + pr_number = os.environ.get("PR_NUMBER") + skip_tests = False + error_on_many_tests = False + + if pr_number is not None and len(pr_number) > 0: + pr = PrInfo.load(pr_number) + skip_tests = pr.contains_directive(SKIP_EXTENSIVE_DIRECTIVE) + error_on_many_tests = not pr.contains_directive( + ALLOW_MANY_EXTENSIVE_DIRECTIVE + ) + + if skip_tests: + eprint("Skipping all extensive tests") + + changed = self.changed_routines() + ret = [] + total_to_test = 0 + + for ty in TYPES: + ty_changed = changed.get(ty, []) + ty_to_test = [] if skip_tests else ty_changed + total_to_test += len(ty_to_test) + + item = { + "ty": ty, + "changed": ",".join(ty_changed), + "to_test": ",".join(ty_to_test), + } + + ret.append(item) + output = json.dumps({"matrix": ret}, separators=(",", ":")) + eprint(f"output: {output}") + eprint(f"total extensive tests: {total_to_test}") + + if error_on_many_tests and total_to_test > MANY_EXTENSIVE_THRESHOLD: + eprint( + f"More than {MANY_EXTENSIVE_THRESHOLD} tests would be run; add" + f" `{ALLOW_MANY_EXTENSIVE_DIRECTIVE}` to the PR body if this is intentional" + ) + exit(1) + + return output + + +def locate_baseline(flags: list[str]) -> None: + """Find the most recent baseline from CI, download it if specified. + + This returns rather than erroring, even if the `gh` commands fail. This is to avoid + erroring in CI if the baseline is unavailable (artifact time limit exceeded, first + run on the branch, etc). + """ + + download = False + extract = False + + while len(flags) > 0: + match flags[0]: + case "--download": + download = True + case "--extract": + extract = True + case _: + eprint(USAGE) + exit(1) + flags = flags[1:] + + if extract and not download: + eprint("cannot extract without downloading") + exit(1) + + try: + # Locate the most recent job to complete with success on our branch + latest_job = sp.check_output( + [ + "gh", + "run", + "list", + "--status=success", + f"--branch={DEFAULT_BRANCH}", + "--json=databaseId,url,headSha,conclusion,createdAt," + "status,workflowDatabaseId,workflowName", + # Return the first array element matching our workflow name. NB: cannot + # just use `--limit=1`, jq filtering happens after limiting. We also + # cannot just use `--workflow` because GH gets confused from + # different file names in history. + f'--jq=[.[] | select(.workflowName == "{WORKFLOW_NAME}")][0]', + ], + text=True, + ) + except sp.CalledProcessError as e: + eprint(f"failed to run github command: {e}") + return + + try: + latest = json.loads(latest_job) + eprint("latest job: ", json.dumps(latest, indent=4)) + except json.JSONDecodeError as e: + eprint(f"failed to decode json '{latest_job}', {e}") + return + + if not download: + eprint("--download not specified, returning") + return + + job_id = latest.get("databaseId") + if job_id is None: + eprint("skipping download step") + return + + sp.run( + ["gh", "run", "download", str(job_id), f"--pattern={ARTIFACT_GLOB}"], + check=False, + ) + + if not extract: + eprint("skipping extraction step") + return + + # Find the baseline with the most recent timestamp. GH downloads the files to e.g. + # `some-dirname/some-dirname.tar.xz`, so just glob the whole thing together. + candidate_baselines = glob(f"{ARTIFACT_GLOB}/{ARTIFACT_GLOB}") + if len(candidate_baselines) == 0: + eprint("no possible baseline directories found") + return + + candidate_baselines.sort(reverse=True) + baseline_archive = candidate_baselines[0] + eprint(f"extracting {baseline_archive}") + sp.run(["tar", "xJvf", baseline_archive], check=True) + eprint("baseline extracted successfully") + + +def check_iai_regressions(args: list[str]): + """Find regressions in iai summary.json files, exit with failure if any are + found. + """ + + iai_home_str = "iai-home" + pr_number = None + + while len(args) > 0: + match args: + case ["--home", home, *rest]: + iai_home_str = home + args = rest + case ["--allow-pr-override", pr_num, *rest]: + pr_number = pr_num + args = rest + case _: + eprint(USAGE) + exit(1) + + iai_home = Path(iai_home_str) + + found_summaries = False + regressions: list[dict] = [] + for summary_path in iglob("**/summary.json", root_dir=iai_home, recursive=True): + found_summaries = True + with open(iai_home / summary_path, "r") as f: + summary = json.load(f) + + summary_regs = [] + run = summary["callgrind_summary"]["callgrind_run"] + fname = summary["function_name"] + id = summary["id"] + name_entry = {"name": f"{fname}.{id}"} + + for segment in run["segments"]: + summary_regs.extend(segment["regressions"]) + + summary_regs.extend(run["total"]["regressions"]) + + regressions.extend(name_entry | reg for reg in summary_regs) + + if not found_summaries: + eprint(f"did not find any summary.json files within {iai_home}") + exit(1) + + if len(regressions) == 0: + eprint("No regressions found") + return + + eprint("Found regressions:", json.dumps(regressions, indent=4)) + + if pr_number is not None: + pr = PrInfo.load(pr_number) + if pr.contains_directive(REGRESSION_DIRECTIVE): + eprint("PR allows regressions, returning") + return + + exit(1) + + +def main(): + match sys.argv[1:]: + case ["generate-matrix"]: + ctx = Context() + output = ctx.make_workflow_output() + print(f"matrix={output}") + case ["locate-baseline", *flags]: + locate_baseline(flags) + case ["check-regressions", *args]: + check_iai_regressions(args) + case ["--help" | "-h"]: + print(USAGE) + exit() + case _: + eprint(USAGE) + exit(1) + + +if __name__ == "__main__": + main() diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index c9503bbce8e..a014baf040a 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -73,4 +73,5 @@ rustc-dep-of-std = ['compiler-builtins', 'core'] public-test-deps = [] [lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)'] } +# The cygwin config can be dropped after our benchmark toolchain is bumped +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)', 'cfg(target_os, values("cygwin"))'] } diff --git a/library/compiler-builtins/etc/libm/ci/bench-icount.sh b/library/compiler-builtins/etc/libm/ci/bench-icount.sh deleted file mode 100755 index 4d93e257a6c..00000000000 --- a/library/compiler-builtins/etc/libm/ci/bench-icount.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash - -set -eux - -iai_home="iai-home" - -# Download the baseline from master -./ci/ci-util.py locate-baseline --download --extract - -# Run benchmarks once -function run_icount_benchmarks() { - cargo_args=( - "--bench" "icount" - "--no-default-features" - "--features" "unstable,unstable-float,icount" - ) - - iai_args=( - "--home" "$(pwd)/$iai_home" - "--regression=ir=5.0" - "--save-summary" - ) - - # Parse `cargo_arg0 cargo_arg1 -- iai_arg0 iai_arg1` syntax - parsing_iai_args=0 - while [ "$#" -gt 0 ]; do - if [ "$parsing_iai_args" == "1" ]; then - iai_args+=("$1") - elif [ "$1" == "--" ]; then - parsing_iai_args=1 - else - cargo_args+=("$1") - fi - - shift - done - - # Run iai-callgrind benchmarks - cargo bench "${cargo_args[@]}" -- "${iai_args[@]}" - - # NB: iai-callgrind should exit on error but does not, so we inspect the sumary - # for errors. See https://github.com/iai-callgrind/iai-callgrind/issues/337 - if [ -n "${PR_NUMBER:-}" ]; then - # If this is for a pull request, ignore regressions if specified. - ./ci/ci-util.py check-regressions --home "$iai_home" --allow-pr-override "$PR_NUMBER" - else - ./ci/ci-util.py check-regressions --home "$iai_home" || true - fi -} - -# Run once with softfloats, once with arch instructions enabled -run_icount_benchmarks --features force-soft-floats -- --save-baseline=softfloat -run_icount_benchmarks -- --save-baseline=hardfloat - -# Name and tar the new baseline -name="baseline-icount-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}" -echo "BASELINE_NAME=$name" >>"$GITHUB_ENV" -tar cJf "$name.tar.xz" "$iai_home" diff --git a/library/compiler-builtins/etc/libm/ci/ci-util.py b/library/compiler-builtins/etc/libm/ci/ci-util.py deleted file mode 100755 index d9e402d6bd7..00000000000 --- a/library/compiler-builtins/etc/libm/ci/ci-util.py +++ /dev/null @@ -1,416 +0,0 @@ -#!/usr/bin/env python3 -"""Utilities for CI. - -This dynamically prepares a list of routines that had a source file change based on -git history. -""" - -import json -import os -import subprocess as sp -import sys -from dataclasses import dataclass -from glob import glob, iglob -from inspect import cleandoc -from os import getenv -from pathlib import Path -from typing import TypedDict, Self - -USAGE = cleandoc( - """ - usage: - - ./ci/ci-util.py [flags] - - COMMAND: - generate-matrix - Calculate a matrix of which functions had source change, print that as - a JSON object. - - locate-baseline [--download] [--extract] - Locate the most recent benchmark baseline available in CI and, if flags - specify, download and extract it. Never exits with nonzero status if - downloading fails. - - Note that `--extract` will overwrite files in `iai-home`. - - check-regressions [--home iai-home] [--allow-pr-override pr_number] - Check `iai-home` (or `iai-home` if unspecified) for `summary.json` - files and see if there are any regressions. This is used as a workaround - for `iai-callgrind` not exiting with error status; see - . - - If `--allow-pr-override` is specified, the regression check will not exit - with failure if any line in the PR starts with `allow-regressions`. - """ -) - -REPO_ROOT = Path(__file__).parent.parent -GIT = ["git", "-C", REPO_ROOT] -DEFAULT_BRANCH = "master" -WORKFLOW_NAME = "CI" # Workflow that generates the benchmark artifacts -ARTIFACT_GLOB = "baseline-icount*" -# Place this in a PR body to skip regression checks (must be at the start of a line). -REGRESSION_DIRECTIVE = "ci: allow-regressions" -# Place this in a PR body to skip extensive tests -SKIP_EXTENSIVE_DIRECTIVE = "ci: skip-extensive" -# Place this in a PR body to allow running a large number of extensive tests. If not -# set, this script will error out if a threshold is exceeded in order to avoid -# accidentally spending huge amounts of CI time. -ALLOW_MANY_EXTENSIVE_DIRECTIVE = "ci: allow-many-extensive" -MANY_EXTENSIVE_THRESHOLD = 20 - -# Don't run exhaustive tests if these files change, even if they contaiin a function -# definition. -IGNORE_FILES = [ - "libm/src/math/support/", - "libm/src/libm_helper.rs", - "libm/src/math/arch/intrinsics.rs", -] - -TYPES = ["f16", "f32", "f64", "f128"] - - -def eprint(*args, **kwargs): - """Print to stderr.""" - print(*args, file=sys.stderr, **kwargs) - - -@dataclass -class PrInfo: - """GitHub response for PR query""" - - body: str - commits: list[str] - created_at: str - number: int - - @classmethod - def load(cls, pr_number: int | str) -> Self: - """For a given PR number, query the body and commit list""" - pr_info = sp.check_output( - [ - "gh", - "pr", - "view", - str(pr_number), - "--json=number,commits,body,createdAt", - # Flatten the commit list to only hashes, change a key to snake naming - "--jq=.commits |= map(.oid) | .created_at = .createdAt | del(.createdAt)", - ], - text=True, - ) - eprint("PR info:", json.dumps(pr_info, indent=4)) - return cls(**json.loads(pr_info)) - - def contains_directive(self, directive: str) -> bool: - """Return true if the provided directive is on a line in the PR body""" - lines = self.body.splitlines() - return any(line.startswith(directive) for line in lines) - - -class FunctionDef(TypedDict): - """Type for an entry in `function-definitions.json`""" - - sources: list[str] - type: str - - -@dataclass -class Context: - gh_ref: str | None - changed: list[Path] - defs: dict[str, FunctionDef] - - def __init__(self) -> None: - self.gh_ref = getenv("GITHUB_REF") - self.changed = [] - self._init_change_list() - - with open(REPO_ROOT.joinpath("etc/function-definitions.json")) as f: - defs = json.load(f) - - defs.pop("__comment", None) - self.defs = defs - - def _init_change_list(self): - """Create a list of files that have been changed. This uses GITHUB_REF if - available, otherwise a diff between `HEAD` and `master`. - """ - - # For pull requests, GitHub creates a ref `refs/pull/1234/merge` (1234 being - # the PR number), and sets this as `GITHUB_REF`. - ref = self.gh_ref - eprint(f"using ref `{ref}`") - if ref is None or "merge" not in ref: - # If the ref is not for `merge` then we are not in PR CI - eprint("No diff available for ref") - return - - # The ref is for a dummy merge commit. We can extract the merge base by - # inspecting all parents (`^@`). - merge_sha = sp.check_output( - GIT + ["show-ref", "--hash", ref], text=True - ).strip() - merge_log = sp.check_output(GIT + ["log", "-1", merge_sha], text=True) - eprint(f"Merge:\n{merge_log}\n") - - parents = ( - sp.check_output(GIT + ["rev-parse", f"{merge_sha}^@"], text=True) - .strip() - .splitlines() - ) - assert len(parents) == 2, f"expected two-parent merge but got:\n{parents}" - base = parents[0].strip() - incoming = parents[1].strip() - - eprint(f"base: {base}, incoming: {incoming}") - textlist = sp.check_output( - GIT + ["diff", base, incoming, "--name-only"], text=True - ) - self.changed = [Path(p) for p in textlist.splitlines()] - - @staticmethod - def _ignore_file(fname: str) -> bool: - return any(fname.startswith(pfx) for pfx in IGNORE_FILES) - - def changed_routines(self) -> dict[str, list[str]]: - """Create a list of routines for which one or more files have been updated, - separated by type. - """ - routines = set() - for name, meta in self.defs.items(): - # Don't update if changes to the file should be ignored - sources = (f for f in meta["sources"] if not self._ignore_file(f)) - - # Select changed files - changed = [f for f in sources if Path(f) in self.changed] - - if len(changed) > 0: - eprint(f"changed files for {name}: {changed}") - routines.add(name) - - ret: dict[str, list[str]] = {} - for r in sorted(routines): - ret.setdefault(self.defs[r]["type"], []).append(r) - - return ret - - def make_workflow_output(self) -> str: - """Create a JSON object a list items for each type's changed files, if any - did change, and the routines that were affected by the change. - """ - - pr_number = os.environ.get("PR_NUMBER") - skip_tests = False - error_on_many_tests = False - - if pr_number is not None and len(pr_number) > 0: - pr = PrInfo.load(pr_number) - skip_tests = pr.contains_directive(SKIP_EXTENSIVE_DIRECTIVE) - error_on_many_tests = not pr.contains_directive( - ALLOW_MANY_EXTENSIVE_DIRECTIVE - ) - - if skip_tests: - eprint("Skipping all extensive tests") - - changed = self.changed_routines() - ret = [] - total_to_test = 0 - - for ty in TYPES: - ty_changed = changed.get(ty, []) - ty_to_test = [] if skip_tests else ty_changed - total_to_test += len(ty_to_test) - - item = { - "ty": ty, - "changed": ",".join(ty_changed), - "to_test": ",".join(ty_to_test), - } - - ret.append(item) - output = json.dumps({"matrix": ret}, separators=(",", ":")) - eprint(f"output: {output}") - eprint(f"total extensive tests: {total_to_test}") - - if error_on_many_tests and total_to_test > MANY_EXTENSIVE_THRESHOLD: - eprint( - f"More than {MANY_EXTENSIVE_THRESHOLD} tests would be run; add" - f" `{ALLOW_MANY_EXTENSIVE_DIRECTIVE}` to the PR body if this is intentional" - ) - exit(1) - - return output - - -def locate_baseline(flags: list[str]) -> None: - """Find the most recent baseline from CI, download it if specified. - - This returns rather than erroring, even if the `gh` commands fail. This is to avoid - erroring in CI if the baseline is unavailable (artifact time limit exceeded, first - run on the branch, etc). - """ - - download = False - extract = False - - while len(flags) > 0: - match flags[0]: - case "--download": - download = True - case "--extract": - extract = True - case _: - eprint(USAGE) - exit(1) - flags = flags[1:] - - if extract and not download: - eprint("cannot extract without downloading") - exit(1) - - try: - # Locate the most recent job to complete with success on our branch - latest_job = sp.check_output( - [ - "gh", - "run", - "list", - "--status=success", - f"--branch={DEFAULT_BRANCH}", - "--json=databaseId,url,headSha,conclusion,createdAt," - "status,workflowDatabaseId,workflowName", - # Return the first array element matching our workflow name. NB: cannot - # just use `--limit=1`, jq filtering happens after limiting. We also - # cannot just use `--workflow` because GH gets confused from - # different file names in history. - f'--jq=[.[] | select(.workflowName == "{WORKFLOW_NAME}")][0]', - ], - text=True, - ) - except sp.CalledProcessError as e: - eprint(f"failed to run github command: {e}") - return - - try: - latest = json.loads(latest_job) - eprint("latest job: ", json.dumps(latest, indent=4)) - except json.JSONDecodeError as e: - eprint(f"failed to decode json '{latest_job}', {e}") - return - - if not download: - eprint("--download not specified, returning") - return - - job_id = latest.get("databaseId") - if job_id is None: - eprint("skipping download step") - return - - sp.run( - ["gh", "run", "download", str(job_id), f"--pattern={ARTIFACT_GLOB}"], - check=False, - ) - - if not extract: - eprint("skipping extraction step") - return - - # Find the baseline with the most recent timestamp. GH downloads the files to e.g. - # `some-dirname/some-dirname.tar.xz`, so just glob the whole thing together. - candidate_baselines = glob(f"{ARTIFACT_GLOB}/{ARTIFACT_GLOB}") - if len(candidate_baselines) == 0: - eprint("no possible baseline directories found") - return - - candidate_baselines.sort(reverse=True) - baseline_archive = candidate_baselines[0] - eprint(f"extracting {baseline_archive}") - sp.run(["tar", "xJvf", baseline_archive], check=True) - eprint("baseline extracted successfully") - - -def check_iai_regressions(args: list[str]): - """Find regressions in iai summary.json files, exit with failure if any are - found. - """ - - iai_home_str = "iai-home" - pr_number = None - - while len(args) > 0: - match args: - case ["--home", home, *rest]: - iai_home_str = home - args = rest - case ["--allow-pr-override", pr_num, *rest]: - pr_number = pr_num - args = rest - case _: - eprint(USAGE) - exit(1) - - iai_home = Path(iai_home_str) - - found_summaries = False - regressions: list[dict] = [] - for summary_path in iglob("**/summary.json", root_dir=iai_home, recursive=True): - found_summaries = True - with open(iai_home / summary_path, "r") as f: - summary = json.load(f) - - summary_regs = [] - run = summary["callgrind_summary"]["callgrind_run"] - fname = summary["function_name"] - id = summary["id"] - name_entry = {"name": f"{fname}.{id}"} - - for segment in run["segments"]: - summary_regs.extend(segment["regressions"]) - - summary_regs.extend(run["total"]["regressions"]) - - regressions.extend(name_entry | reg for reg in summary_regs) - - if not found_summaries: - eprint(f"did not find any summary.json files within {iai_home}") - exit(1) - - if len(regressions) == 0: - eprint("No regressions found") - return - - eprint("Found regressions:", json.dumps(regressions, indent=4)) - - if pr_number is not None: - pr = PrInfo.load(pr_number) - if pr.contains_directive(REGRESSION_DIRECTIVE): - eprint("PR allows regressions, returning") - return - - exit(1) - - -def main(): - match sys.argv[1:]: - case ["generate-matrix"]: - ctx = Context() - output = ctx.make_workflow_output() - print(f"matrix={output}") - case ["locate-baseline", *flags]: - locate_baseline(flags) - case ["check-regressions", *args]: - check_iai_regressions(args) - case ["--help" | "-h"]: - print(USAGE) - exit() - case _: - eprint(USAGE) - exit(1) - - -if __name__ == "__main__": - main() -- cgit 1.4.1-3-g733a5 From d02b25fd6e6c8da41f0248333df93a03dc53fec1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 04:48:51 +0000 Subject: Fix the libm-test logfile path This was broken since the crate's location relative to the target directory had changed. --- library/compiler-builtins/libm-test/src/lib.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/lib.rs b/library/compiler-builtins/libm-test/src/lib.rs index 730318abcba..accb39654d1 100644 --- a/library/compiler-builtins/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm-test/src/lib.rs @@ -71,12 +71,7 @@ pub fn test_log(s: &str) { return None; }; - PathBuf::from(x) - .parent() - .unwrap() - .parent() - .unwrap() - .join("target") + PathBuf::from(x).join("../target") } }; let outfile = target_dir.join("test-log.txt"); -- cgit 1.4.1-3-g733a5 From 9919218493c37d3f7a987f7a6c6e3fceba63c40a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 06:10:45 +0000 Subject: ci: Add a libm MSRV check Add the job from rust-lang/libm --- .../compiler-builtins/.github/workflows/main.yaml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 54cfd506e83..7ef0074deb2 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -226,6 +226,26 @@ jobs: - uses: Swatinem/rust-cache@v2 - run: ./ci/miri.sh + msrv: + name: Check libm MSRV + runs-on: ubuntu-24.04 + timeout-minutes: 10 + env: + RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` + steps: + - uses: actions/checkout@master + - name: Install Rust + run: | + msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' libm/Cargo.toml)" + echo "MSRV: $msrv" + rustup update "$msrv" --no-self-update && rustup default "$msrv" + - uses: Swatinem/rust-cache@v2 + - run: | + # FIXME(msrv): Remove the workspace Cargo.toml so 1.63 cargo doesn't see + # `edition = "2024"` and get spooked. + rm Cargo.toml + cargo build --manifest-path libm/Cargo.toml + rustfmt: name: Rustfmt runs-on: ubuntu-24.04 @@ -242,6 +262,7 @@ jobs: - benchmarks - clippy - miri + - msrv - rustfmt - test runs-on: ubuntu-24.04 -- cgit 1.4.1-3-g733a5 From d0e0134dc56b764a4f8f0a4971f737e2fbbbef21 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 06:21:44 +0000 Subject: ci: Add extensive tests from rust-lang/libm --- .../compiler-builtins/.github/workflows/main.yaml | 68 ++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 7ef0074deb2..8f8ac033a13 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -257,10 +257,78 @@ jobs: run: rustup set profile minimal && rustup default stable && rustup component add rustfmt - run: cargo fmt -- --check + # Determine which extensive tests should be run based on changed files. + calculate_extensive_matrix: + name: Calculate job matrix + runs-on: ubuntu-24.04 + timeout-minutes: 10 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + outputs: + matrix: ${{ steps.script.outputs.matrix }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 100 + - name: Fetch pull request ref + run: git fetch origin "$GITHUB_REF:$GITHUB_REF" + if: github.event_name == 'pull_request' + - run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT" + id: script + + extensive: + name: Extensive tests for ${{ matrix.ty }} + needs: + # Wait on `clippy` so we have some confidence that the crate will build + - clippy + - calculate_extensive_matrix + runs-on: ubuntu-24.04 + timeout-minutes: 240 # 4 hours + strategy: + matrix: + # Use the output from `calculate_extensive_matrix` to calculate the matrix + # FIXME: it would be better to run all jobs (i.e. all types) but mark those that + # didn't change as skipped, rather than completely excluding the job. However, + # this is not currently possible https://github.com/actions/runner/issues/1985. + include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }} + env: + TO_TEST: ${{ matrix.to_test }} + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + - uses: Swatinem/rust-cache@v2 + - name: Run extensive tests + run: | + echo "Tests to run: '$TO_TEST'" + if [ -z "$TO_TEST" ]; then + echo "No tests to run, exiting." + exit + fi + + set -x + + # Run the non-extensive tests first to catch any easy failures + cargo t --profile release-checked -- "$TO_TEST" + + LIBM_EXTENSIVE_TESTS="$TO_TEST" cargo test \ + --features build-mpfr,unstable,force-soft-floats \ + --profile release-checked \ + -- extensive + - name: Print test logs if available + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + success: needs: - benchmarks - clippy + - extensive - miri - msrv - rustfmt -- cgit 1.4.1-3-g733a5 From 9c96f245b8e7b40d46653dcc77970a8308c3b012 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 04:40:12 +0000 Subject: ci: Enable testing of `libm` crates Update `run.sh` to start testing `libm`. Currently this is somewhat inefficient because `builtins-test` gets run more than once on some targets; this can be cleaned up later. --- .../compiler-builtins/.github/workflows/main.yaml | 12 +- library/compiler-builtins/Cargo.toml | 35 ++--- library/compiler-builtins/ci/run.sh | 167 ++++++++++++++++++--- .../compiler-builtins/etc/libm/ci/run-docker.sh | 56 ------- library/compiler-builtins/etc/libm/ci/run.sh | 130 ---------------- library/compiler-builtins/libm-test/Cargo.toml | 3 + 6 files changed, 176 insertions(+), 227 deletions(-) delete mode 100755 library/compiler-builtins/etc/libm/ci/run-docker.sh delete mode 100755 library/compiler-builtins/etc/libm/ci/run.sh diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 8f8ac033a13..95ed6a855f3 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -97,6 +97,7 @@ jobs: rustup default "$channel" rustup target add "${{ matrix.target }}" rustup component add llvm-tools-preview + - uses: taiki-e/install-action@nextest - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} @@ -107,7 +108,7 @@ jobs: path: /tmp/.buildx-cache key: ${{ matrix.target }}-buildx-${{ github.sha }} restore-keys: ${{ matrix.target }}-buildx- - + - name: Cache compiler-rt id: cache-compiler-rt uses: actions/cache@v4 @@ -121,6 +122,10 @@ jobs: - run: echo "RUST_COMPILER_RT_ROOT=$(realpath ./compiler-rt)" >> "$GITHUB_ENV" shell: bash + - name: Verify API list + if: matrix.os == 'ubuntu-24.04' + run: python3 etc/update-api-list.py --check + # Non-linux tests just use our raw script - name: Run locally if: matrix.os != 'ubuntu-24.04' @@ -136,6 +141,11 @@ jobs: if: matrix.os == 'ubuntu-24.04' run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} + - name: Print test logs if available + if: always() + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + # Workaround to keep Docker cache smaller # https://github.com/docker/build-push-action/issues/252 # https://github.com/moby/buildkit/issues/1896 diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 194a2cdc2f7..c3737a042f5 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -31,22 +31,19 @@ panic = "abort" [profile.dev] panic = "abort" -# FIXME(libm): these profiles are needed for testing -# # The default release profile is unchanged. - -# # Release mode with debug assertions -# [profile.release-checked] -# inherits = "release" -# debug-assertions = true -# overflow-checks = true - -# # Release with maximum optimizations, which is very slow to build. This is also -# # what is needed to check `no-panic`. -# [profile.release-opt] -# inherits = "release" -# codegen-units = 1 -# lto = "fat" - -# [profile.bench] -# # Required for iai-callgrind -# debug = true +# Release mode with debug assertions +[profile.release-checked] +inherits = "release" +debug-assertions = true +overflow-checks = true + +# Release with maximum optimizations, which is very slow to build. This is also +# what is needed to check `no-panic`. +[profile.release-opt] +inherits = "release" +codegen-units = 1 +lto = "fat" + +[profile.bench] +# Required for iai-callgrind +debug = true diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index bce90d48d50..730079be789 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -13,6 +13,11 @@ if [ -z "$target" ]; then target="$host_target" fi +if [[ "$target" = *"wasm"* ]]; then + # Enable the random backend + export RUSTFLAGS="${RUSTFLAGS:-} --cfg getrandom_backend=\"wasm_js\"" +fi + if [ "${USING_CONTAINER_RUSTC:-}" = 1 ]; then # Install nonstandard components if we have control of the environment rustup target list --installed | @@ -22,27 +27,27 @@ fi # Test our implementation if [ "${BUILD_ONLY:-}" = "1" ]; then - echo "nothing to do for no_std" + echo "no tests to run for build-only targets" else - run="cargo test --package builtins-test --no-fail-fast --target $target" - $run - $run --release - $run --features c - $run --features c --release - $run --features no-asm - $run --features no-asm --release - $run --features no-f16-f128 - $run --features no-f16-f128 --release - $run --benches - $run --benches --release -fi + test_builtins=(cargo test --package builtins-test --no-fail-fast --target "$target") + "${test_builtins[@]}" + "${test_builtins[@]}" --release + "${test_builtins[@]}" --features c + "${test_builtins[@]}" --features c --release + "${test_builtins[@]}" --features no-asm + "${test_builtins[@]}" --features no-asm --release + "${test_builtins[@]}" --features no-f16-f128 + "${test_builtins[@]}" --features no-f16-f128 --release + "${test_builtins[@]}" --benches + "${test_builtins[@]}" --benches --release -if [ "${TEST_VERBATIM:-}" = "1" ]; then - verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\builtins-test\\target2) - cargo build --package builtins-test \ - --target "$target" --target-dir "$verb_path" --features c + if [ "${TEST_VERBATIM:-}" = "1" ]; then + verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\builtins-test\\target2) + "${test_builtins[@]}" --target-dir "$verb_path" --features c + fi fi + declare -a rlib_paths # Set the `rlib_paths` global array to a list of all compiler-builtins rlibs @@ -61,11 +66,11 @@ rm -f "${rlib_paths[@]}" cargo build -p compiler_builtins --target "$target" cargo build -p compiler_builtins --target "$target" --release cargo build -p compiler_builtins --target "$target" --features c -cargo build -p compiler_builtins --target "$target" --release --features c +cargo build -p compiler_builtins --target "$target" --features c --release cargo build -p compiler_builtins --target "$target" --features no-asm -cargo build -p compiler_builtins --target "$target" --release --features no-asm +cargo build -p compiler_builtins --target "$target" --features no-asm --release cargo build -p compiler_builtins --target "$target" --features no-f16-f128 -cargo build -p compiler_builtins --target "$target" --release --features no-f16-f128 +cargo build -p compiler_builtins --target "$target" --features no-f16-f128 --release PREFIX=${target//unknown-/}- case "$target" in @@ -167,4 +172,124 @@ for rlib in "${rlib_paths[@]}"; do fi done -true +# Test libm + +mflags=() + +# We enumerate features manually. +mflags+=(--no-default-features) + +# Enable arch-specific routines when available. +mflags+=(--features arch) + +# Always enable `unstable-float` since it expands available API but does not +# change any implementations. +mflags+=(--features unstable-float) + +# We need to specifically skip tests for musl-math-sys on systems that can't +# build musl since otherwise `--all` will activate it. +case "$target" in + # Can't build at all on MSVC, WASM, or thumb + *windows-msvc*) mflags+=(--exclude musl-math-sys) ;; + *wasm*) mflags+=(--exclude musl-math-sys) ;; + *thumb*) mflags+=(--exclude musl-math-sys) ;; + + # We can build musl on MinGW but running tests gets a stack overflow + *windows-gnu*) ;; + # FIXME(#309): LE PPC crashes calling the musl version of some functions. It + # seems like a qemu bug but should be investigated further at some point. + # See . + *powerpc64le*) ;; + + # Everything else gets musl enabled + *) mflags+=(--features libm-test/build-musl) ;; +esac + + +# Configure which targets test against MPFR +case "$target" in + # MSVC cannot link MPFR + *windows-msvc*) ;; + # FIXME: MinGW should be able to build MPFR, but setup in CI is nontrivial. + *windows-gnu*) ;; + # Targets that aren't cross compiled in CI work fine + aarch64*apple*) mflags+=(--features libm-test/build-mpfr) ;; + aarch64*linux*) mflags+=(--features libm-test/build-mpfr) ;; + i586*) mflags+=(--features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross) ;; + i686*) mflags+=(--features libm-test/build-mpfr) ;; + x86_64*) mflags+=(--features libm-test/build-mpfr) ;; +esac + +# FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. +# +case "$target" in + *windows-gnu) mflags+=(--exclude libm-macros) ;; +esac + +# Make sure a simple build works +cargo check -p libm --no-default-features --target "$target" + + +if [ "${BUILD_ONLY:-}" = "1" ]; then + # If we are on targets that can't run tests, verify that we can build. + cmd=(cargo build --target "$target" --package libm) + "${cmd[@]}" + "${cmd[@]}" --features unstable-intrinsics + + echo "can't run tests on $target; skipping" +else + mflags+=(--workspace --target "$target") + cmd=(cargo test "${mflags[@]}") + profile_flag="--profile" + + # If nextest is available, use that + command -v cargo-nextest && nextest=1 || nextest=0 + if [ "$nextest" = "1" ]; then + cmd=(cargo nextest run --max-fail=10) + + # Workaround for https://github.com/nextest-rs/nextest/issues/2066 + if [ -f /.dockerenv ]; then + cfg_file="/tmp/nextest-config.toml" + echo "[store]" >> "$cfg_file" + echo "dir = \"$CARGO_TARGET_DIR/nextest\"" >> "$cfg_file" + cmd+=(--config-file "$cfg_file") + fi + + cmd+=("${mflags[@]}") + profile_flag="--cargo-profile" + fi + + # Test once without intrinsics + "${cmd[@]}" + + # Run doctests if they were excluded by nextest + [ "$nextest" = "1" ] && cargo test --doc --exclude compiler_builtins "${mflags[@]}" + + # Exclude the macros and utile crates from the rest of the tests to save CI + # runtime, they shouldn't have anything feature- or opt-level-dependent. + cmd+=(--exclude util --exclude libm-macros) + + # Test once with intrinsics enabled + "${cmd[@]}" --features unstable-intrinsics + "${cmd[@]}" --features unstable-intrinsics --benches + + # Test the same in release mode, which also increases coverage. Also ensure + # the soft float routines are checked. + "${cmd[@]}" "$profile_flag" release-checked + "${cmd[@]}" "$profile_flag" release-checked --features force-soft-floats + "${cmd[@]}" "$profile_flag" release-checked --features unstable-intrinsics + "${cmd[@]}" "$profile_flag" release-checked --features unstable-intrinsics --benches + + # Ensure that the routines do not panic. + # + # `--tests` must be passed because no-panic is only enabled as a dev + # dependency. The `release-opt` profile must be used to enable LTO and a + # single CGU. + ENSURE_NO_PANIC=1 cargo build \ + -p libm \ + --target "$target" \ + --no-default-features \ + --features unstable-float \ + --tests \ + --profile release-opt +fi diff --git a/library/compiler-builtins/etc/libm/ci/run-docker.sh b/library/compiler-builtins/etc/libm/ci/run-docker.sh deleted file mode 100755 index 6626e722685..00000000000 --- a/library/compiler-builtins/etc/libm/ci/run-docker.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -# Small script to run tests for a target (or all targets) inside all the -# respective docker images. - -set -euxo pipefail - -host_arch="$(uname -m | sed 's/arm64/aarch64/')" - -run() { - local target=$1 - - echo "testing target: $target" - - target_arch="$(echo "$target" | cut -d'-' -f1)" - - emulated="" - if [ "$target_arch" != "$host_arch" ]; then - emulated=1 - echo "target is emulated" - fi - - # This directory needs to exist before calling docker, otherwise docker will create it but it - # will be owned by root - mkdir -p target - - set_env="HOME=/tmp PATH=\$PATH:/rust/bin:/cargo/bin" - docker build -t "libm-$target" "ci/docker/$target" - docker run \ - --rm \ - --user "$(id -u):$(id -g)" \ - -e CI \ - -e RUSTFLAGS \ - -e CARGO_TERM_COLOR \ - -e CARGO_HOME=/cargo \ - -e CARGO_TARGET_DIR=/target \ - -e "EMULATED=$emulated" \ - -v "${HOME}/.cargo:/cargo" \ - -v "$(pwd)/target:/target" \ - -v "$(pwd):/checkout:ro" \ - -v "$(rustc --print sysroot):/rust:ro" \ - --init \ - -w /checkout \ - "libm-$target" \ - sh -c "$set_env exec ci/run.sh $target" -} - -if [ -z "$1" ]; then - echo "running tests for all targets" - - for d in ci/docker/*; do - run $d - done -else - run $1 -fi diff --git a/library/compiler-builtins/etc/libm/ci/run.sh b/library/compiler-builtins/etc/libm/ci/run.sh deleted file mode 100755 index a946d325ebd..00000000000 --- a/library/compiler-builtins/etc/libm/ci/run.sh +++ /dev/null @@ -1,130 +0,0 @@ -#!/bin/sh - -set -eux - -export RUST_BACKTRACE="${RUST_BACKTRACE:-full}" -export NEXTEST_STATUS_LEVEL=all - -target="${1:-}" -flags="" - -if [ -z "$target" ]; then - host_target=$(rustc -vV | awk '/^host/ { print $2 }') - echo "Defaulted to host target $host_target" - target="$host_target" -fi - -# We enumerate features manually. -flags="$flags --no-default-features" - -# Enable arch-specific routines when available. -flags="$flags --features arch" - -# Always enable `unstable-float` since it expands available API but does not -# change any implementations. -flags="$flags --features unstable-float" - -# We need to specifically skip tests for musl-math-sys on systems that can't -# build musl since otherwise `--all` will activate it. -case "$target" in - # Can't build at all on MSVC, WASM, or thumb - *windows-msvc*) flags="$flags --exclude musl-math-sys" ;; - *wasm*) flags="$flags --exclude musl-math-sys" ;; - *thumb*) flags="$flags --exclude musl-math-sys" ;; - - # We can build musl on MinGW but running tests gets a stack overflow - *windows-gnu*) ;; - # FIXME(#309): LE PPC crashes calling the musl version of some functions. It - # seems like a qemu bug but should be investigated further at some point. - # See . - *powerpc64le*) ;; - - # Everything else gets musl enabled - *) flags="$flags --features libm-test/build-musl" ;; -esac - -# Configure which targets test against MPFR -case "$target" in - # MSVC cannot link MPFR - *windows-msvc*) ;; - # FIXME: MinGW should be able to build MPFR, but setup in CI is nontrivial. - *windows-gnu*) ;; - # Targets that aren't cross compiled in CI work fine - aarch64*apple*) flags="$flags --features libm-test/build-mpfr" ;; - aarch64*linux*) flags="$flags --features libm-test/build-mpfr" ;; - i586*) flags="$flags --features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross" ;; - i686*) flags="$flags --features libm-test/build-mpfr" ;; - x86_64*) flags="$flags --features libm-test/build-mpfr" ;; -esac - -# FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. -# -case "$target" in - *windows-gnu) flags="$flags --exclude libm-macros" ;; -esac - -# Make sure we can build with overriding features. -cargo check -p libm --no-default-features - -if [ "${BUILD_ONLY:-}" = "1" ]; then - # If we are on targets that can't run tests, verify that we can build. - cmd="cargo build --target $target --package libm" - $cmd - $cmd --features unstable-intrinsics - - echo "can't run tests on $target; skipping" - exit -fi - -flags="$flags --all --target $target" -cmd="cargo test $flags" -profile="--profile" - -# If nextest is available, use that -command -v cargo-nextest && nextest=1 || nextest=0 -if [ "$nextest" = "1" ]; then - # Workaround for https://github.com/nextest-rs/nextest/issues/2066 - if [ -f /.dockerenv ]; then - cfg_file="/tmp/nextest-config.toml" - echo "[store]" >> "$cfg_file" - echo "dir = \"$CARGO_TARGET_DIR/nextest\"" >> "$cfg_file" - cfg_flag="--config-file $cfg_file" - fi - - cmd="cargo nextest run ${cfg_flag:-} --max-fail=10 $flags" - profile="--cargo-profile" -fi - -# Test once without intrinsics -$cmd - -# Run doctests if they were excluded by nextest -[ "$nextest" = "1" ] && cargo test --doc $flags - -# Exclude the macros and utile crates from the rest of the tests to save CI -# runtime, they shouldn't have anything feature- or opt-level-dependent. -cmd="$cmd --exclude util --exclude libm-macros" - -# Test once with intrinsics enabled -$cmd --features unstable-intrinsics -$cmd --features unstable-intrinsics --benches - -# Test the same in release mode, which also increases coverage. Also ensure -# the soft float routines are checked. -$cmd "$profile" release-checked -$cmd "$profile" release-checked --features force-soft-floats -$cmd "$profile" release-checked --features unstable-intrinsics -$cmd "$profile" release-checked --features unstable-intrinsics --benches - -# Ensure that the routines do not panic. -# -# `--tests` must be passed because no-panic is only enabled as a dev -# dependency. The `release-opt` profile must be used to enable LTO and a -# single CGU. -ENSURE_NO_PANIC=1 cargo build \ - -p libm \ - --target "$target" \ - --no-default-features \ - --features unstable-float \ - --tests \ - --profile release-opt diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index c9b3b795837..6fd49774e0c 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -41,6 +41,9 @@ rand_chacha = "0.9.0" rayon = "1.10.0" rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "integer", "std"] } +[target.'cfg(target_family = "wasm")'.dependencies] +getrandom = { version = "0.3.2", features = ["wasm_js"] } + [build-dependencies] rand = { version = "0.9.0", optional = true } -- cgit 1.4.1-3-g733a5 From 22f44df8bdf6588236ab7523bb3e35b08df5f750 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 05:37:08 +0000 Subject: Set the musl submodule to 61399d4b ("loongarch64: add TLSDESC support") Set the submodule to the same version we had been using in rust-lang/libm. This is a downgrade from the current version but it avoids some new deviations that show up, which can be corrected later. --- library/compiler-builtins/crates/musl-math-sys/musl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/crates/musl-math-sys/musl b/library/compiler-builtins/crates/musl-math-sys/musl index 0784374d561..61399d4bd02 160000 --- a/library/compiler-builtins/crates/musl-math-sys/musl +++ b/library/compiler-builtins/crates/musl-math-sys/musl @@ -1 +1 @@ -Subproject commit 0784374d561435f7c787a555aeab8ede699ed298 +Subproject commit 61399d4bd02ae1ec03068445aa7ffe9174466bfd -- cgit 1.4.1-3-g733a5 From a829d916b5555a5ef65d521e98488f32b5476d36 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 07:26:43 +0000 Subject: ci: Add `/cargo/bin` to the path in Docker This makes it possible to use nextest within the container. --- library/compiler-builtins/ci/run-docker.sh | 2 +- library/compiler-builtins/ci/run.sh | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index d07e7784c9a..c4d3af55ddc 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -50,7 +50,7 @@ run() { -v "$(pwd)/target:/builtins-target" -v "$(rustc --print sysroot):/rust:ro" ) - run_cmd="$run_cmd PATH=\$PATH:/rust/bin" + run_cmd="$run_cmd PATH=\$PATH:/rust/bin:/cargo/bin" else # Use rustc provided by a docker image docker volume create compiler-builtins-cache diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 730079be789..0ad99da19f0 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -229,7 +229,6 @@ esac # Make sure a simple build works cargo check -p libm --no-default-features --target "$target" - if [ "${BUILD_ONLY:-}" = "1" ]; then # If we are on targets that can't run tests, verify that we can build. cmd=(cargo build --target "$target" --package libm) @@ -255,6 +254,9 @@ else cmd+=(--config-file "$cfg_file") fi + # Not all configurations have tests to run on wasm + [[ "$target" = *"wasm"* ]] && cmd+=(--no-tests=warn) + cmd+=("${mflags[@]}") profile_flag="--cargo-profile" fi -- cgit 1.4.1-3-g733a5 From 8902f740da9566061c5b23000899e7908921370b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 07:05:32 +0000 Subject: ci: Skip testing libm in PRs if it did not change Many contributions to compiler-builtins don't have any need to touch libm, and could get by with the few minutes of CI for compiler-builtins rather than the ~30 minutes for libm. We already have some scripts that handle changed file detection, so expand its use to skip libm CI if it doesn't need to run. --- .../compiler-builtins/.github/workflows/main.yaml | 49 ++++++++++++---------- library/compiler-builtins/ci/ci-util.py | 42 ++++++++++++++----- library/compiler-builtins/ci/run-docker.sh | 1 + library/compiler-builtins/ci/run.sh | 11 +++-- 4 files changed, 66 insertions(+), 37 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 95ed6a855f3..690cdc89b1c 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -16,6 +16,27 @@ env: BENCHMARK_RUSTC: nightly-2025-01-16 # Pin the toolchain for reproducable results jobs: + # Determine which tests should be run based on changed files. + calculate_vars: + name: Calculate workflow variables + runs-on: ubuntu-24.04 + timeout-minutes: 10 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + outputs: + extensive_matrix: ${{ steps.script.outputs.extensive_matrix }} + may_skip_libm_ci: ${{ steps.script.outputs.may_skip_libm_ci }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 500 + - name: Fetch pull request ref + run: git fetch origin "$GITHUB_REF:$GITHUB_REF" + if: github.event_name == 'pull_request' + - run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT" + id: script + test: name: Build and test timeout-minutes: 60 @@ -78,9 +99,11 @@ jobs: os: windows-2025 channel: nightly-x86_64-gnu runs-on: ${{ matrix.os }} + needs: [calculate_vars] env: BUILD_ONLY: ${{ matrix.build_only }} TEST_VERBATIM: ${{ matrix.test_verbatim }} + MAY_SKIP_LIBM_CI: ${{ needs.calculate_vars.outputs.may_skip_libm_ci }} steps: - name: Print runner information run: uname -a @@ -267,41 +290,21 @@ jobs: run: rustup set profile minimal && rustup default stable && rustup component add rustfmt - run: cargo fmt -- --check - # Determine which extensive tests should be run based on changed files. - calculate_extensive_matrix: - name: Calculate job matrix - runs-on: ubuntu-24.04 - timeout-minutes: 10 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - outputs: - matrix: ${{ steps.script.outputs.matrix }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 100 - - name: Fetch pull request ref - run: git fetch origin "$GITHUB_REF:$GITHUB_REF" - if: github.event_name == 'pull_request' - - run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT" - id: script - extensive: name: Extensive tests for ${{ matrix.ty }} needs: # Wait on `clippy` so we have some confidence that the crate will build - clippy - - calculate_extensive_matrix + - calculate_vars runs-on: ubuntu-24.04 timeout-minutes: 240 # 4 hours strategy: matrix: - # Use the output from `calculate_extensive_matrix` to calculate the matrix + # Use the output from `calculate_vars` to create the matrix # FIXME: it would be better to run all jobs (i.e. all types) but mark those that # didn't change as skipped, rather than completely excluding the job. However, # this is not currently possible https://github.com/actions/runner/issues/1985. - include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }} + include: ${{ fromJSON(needs.calculate_vars.outputs.extensive_matrix).extensive_matrix }} env: TO_TEST: ${{ matrix.to_test }} steps: diff --git a/library/compiler-builtins/ci/ci-util.py b/library/compiler-builtins/ci/ci-util.py index d9e402d6bd7..7486d6b4186 100755 --- a/library/compiler-builtins/ci/ci-util.py +++ b/library/compiler-builtins/ci/ci-util.py @@ -7,6 +7,7 @@ git history. import json import os +import re import subprocess as sp import sys from dataclasses import dataclass @@ -68,6 +69,10 @@ IGNORE_FILES = [ "libm/src/math/arch/intrinsics.rs", ] +# libm PR CI takes a long time and doesn't need to run unless relevant files have been +# changed. Anything matching this regex pattern will trigger a run. +TRIGGER_LIBM_PR_CI = ".*(libm|musl).*" + TYPES = ["f16", "f32", "f64", "f128"] @@ -116,7 +121,6 @@ class FunctionDef(TypedDict): type: str -@dataclass class Context: gh_ref: str | None changed: list[Path] @@ -142,7 +146,7 @@ class Context: # the PR number), and sets this as `GITHUB_REF`. ref = self.gh_ref eprint(f"using ref `{ref}`") - if ref is None or "merge" not in ref: + if not self.is_pr(): # If the ref is not for `merge` then we are not in PR CI eprint("No diff available for ref") return @@ -170,6 +174,10 @@ class Context: ) self.changed = [Path(p) for p in textlist.splitlines()] + def is_pr(self) -> bool: + """Check if we are looking at a PR rather than a push.""" + return self.gh_ref is not None and "merge" in self.gh_ref + @staticmethod def _ignore_file(fname: str) -> bool: return any(fname.startswith(pfx) for pfx in IGNORE_FILES) @@ -196,7 +204,16 @@ class Context: return ret - def make_workflow_output(self) -> str: + def may_skip_libm_ci(self) -> bool: + """If this is a PR and no libm files were changed, allow skipping libm + jobs.""" + + if self.is_pr(): + return all(not re.match(TRIGGER_LIBM_PR_CI, str(f)) for f in self.changed) + + return False + + def emit_workflow_output(self): """Create a JSON object a list items for each type's changed files, if any did change, and the routines that were affected by the change. """ @@ -216,9 +233,10 @@ class Context: eprint("Skipping all extensive tests") changed = self.changed_routines() - ret = [] + matrix = [] total_to_test = 0 + # Figure out which extensive tests need to run for ty in TYPES: ty_changed = changed.get(ty, []) ty_to_test = [] if skip_tests else ty_changed @@ -230,9 +248,14 @@ class Context: "to_test": ",".join(ty_to_test), } - ret.append(item) - output = json.dumps({"matrix": ret}, separators=(",", ":")) - eprint(f"output: {output}") + matrix.append(item) + + ext_matrix = json.dumps({"extensive_matrix": matrix}, separators=(",", ":")) + may_skip = str(self.may_skip_libm_ci()).lower() + print(f"extensive_matrix={ext_matrix}") + print(f"may_skip_libm_ci={may_skip}") + eprint(f"extensive_matrix={ext_matrix}") + eprint(f"may_skip_libm_ci={may_skip}") eprint(f"total extensive tests: {total_to_test}") if error_on_many_tests and total_to_test > MANY_EXTENSIVE_THRESHOLD: @@ -242,8 +265,6 @@ class Context: ) exit(1) - return output - def locate_baseline(flags: list[str]) -> None: """Find the most recent baseline from CI, download it if specified. @@ -398,8 +419,7 @@ def main(): match sys.argv[1:]: case ["generate-matrix"]: ctx = Context() - output = ctx.make_workflow_output() - print(f"matrix={output}") + ctx.emit_workflow_output() case ["locate-baseline", *flags]: locate_baseline(flags) case ["check-regressions", *args]: diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index c4d3af55ddc..58838fadf3c 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -77,6 +77,7 @@ run() { -e CI \ -e CARGO_TARGET_DIR=/builtins-target \ -e CARGO_TERM_COLOR \ + -e MAY_SKIP_LIBM_CI \ -e RUSTFLAGS \ -e RUST_BACKTRACE \ -e RUST_COMPILER_RT_ROOT \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 0ad99da19f0..68d13c130bc 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -174,6 +174,14 @@ done # Test libm +# Make sure a simple build works +cargo check -p libm --no-default-features --target "$target" + +if [ "${MAY_SKIP_LIBM_CI:-}" = "true" ]; then + echo "skipping libm PR CI" + exit +fi + mflags=() # We enumerate features manually. @@ -226,9 +234,6 @@ case "$target" in *windows-gnu) mflags+=(--exclude libm-macros) ;; esac -# Make sure a simple build works -cargo check -p libm --no-default-features --target "$target" - if [ "${BUILD_ONLY:-}" = "1" ]; then # If we are on targets that can't run tests, verify that we can build. cmd=(cargo build --target "$target" --package libm) -- cgit 1.4.1-3-g733a5 From ee431374eb639598c93753f94125d87b47ed20ae Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 08:26:08 +0000 Subject: ci: Add a timeout for all jobs --- library/compiler-builtins/.github/workflows/main.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 690cdc89b1c..2b57d7eb3aa 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -247,6 +247,7 @@ jobs: miri: name: Miri runs-on: ubuntu-24.04 + timeout-minutes: 10 steps: - uses: actions/checkout@v4 with: @@ -282,6 +283,7 @@ jobs: rustfmt: name: Rustfmt runs-on: ubuntu-24.04 + timeout-minutes: 10 steps: - uses: actions/checkout@v4 with: @@ -347,6 +349,7 @@ jobs: - rustfmt - test runs-on: ubuntu-24.04 + timeout-minutes: 10 # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its # dependencies fails. -- cgit 1.4.1-3-g733a5 From 13bf5f5bb4115cebe30c8b18935ad017c7fa3de1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 08:34:47 +0000 Subject: ci: Use lowercase for bash locals, fix shellcheck --- library/compiler-builtins/ci/miri.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/ci/miri.sh b/library/compiler-builtins/ci/miri.sh index 79e660bab62..7b0ea44c690 100755 --- a/library/compiler-builtins/ci/miri.sh +++ b/library/compiler-builtins/ci/miri.sh @@ -1,5 +1,5 @@ #!/bin/bash -set -ex +set -eux # We need Tree Borrows as some of our raw pointer patterns are not # compatible with Stacked Borrows. @@ -7,10 +7,12 @@ export MIRIFLAGS="-Zmiri-tree-borrows" # One target that sets `mem-unaligned` and one that does not, # and a big-endian target. -TARGETS=(x86_64-unknown-linux-gnu +targets=( + x86_64-unknown-linux-gnu armv7-unknown-linux-gnueabihf - s390x-unknown-linux-gnu) -for TARGET in "${TARGETS[@]}"; do + s390x-unknown-linux-gnu +) +for target in "${targets[@]}"; do # Only run the `mem` tests to avoid this taking too long. - cargo miri test --manifest-path builtins-test/Cargo.toml --features no-asm --target $TARGET -- mem + cargo miri test --manifest-path builtins-test/Cargo.toml --features no-asm --target "$target" -- mem done -- cgit 1.4.1-3-g733a5 From 46bbc3dd88d998c910920c939a032d8f44cc16e9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 08:42:12 +0000 Subject: ci: Clean up workflow file and docker script --- library/compiler-builtins/.github/workflows/main.yaml | 11 +++++------ library/compiler-builtins/ci/run-docker.sh | 13 +++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 2b57d7eb3aa..f7522a53d9d 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -131,6 +131,9 @@ jobs: path: /tmp/.buildx-cache key: ${{ matrix.target }}-buildx-${{ github.sha }} restore-keys: ${{ matrix.target }}-buildx- + # Configure buildx to use Docker layer caching + - uses: docker/setup-buildx-action@v3 + if: matrix.os == 'ubuntu-24.04' - name: Cache compiler-rt id: cache-compiler-rt @@ -155,14 +158,10 @@ jobs: shell: bash run: ./ci/run.sh ${{ matrix.target }} - # Configure buildx to use Docker layer caching - - uses: docker/setup-buildx-action@v3 - if: matrix.os == 'ubuntu-24.04' - # Otherwise we use our docker containers to run builds - name: Run in Docker if: matrix.os == 'ubuntu-24.04' - run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} + run: ./ci/run-docker.sh ${{ matrix.target }} - name: Print test logs if available if: always() @@ -193,7 +192,7 @@ jobs: rustup default nightly rustup component add clippy - uses: Swatinem/rust-cache@v2 - - run: cargo clippy -- -D clippy::all + - run: cargo clippy --workspace --all-targets benchmarks: name: Benchmarks diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 58838fadf3c..d0122dee5c8 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -7,6 +7,13 @@ set -euxo pipefail host_arch="$(uname -m | sed 's/arm64/aarch64/')" +# Directories and files that do not yet exist need to be created before +# calling docker, otherwise docker will create them but they will be owned +# by root. +mkdir -p target +cargo generate-lockfile +cargo generate-lockfile --manifest-path builtins-test-intrinsics/Cargo.toml + run() { local target="$1" @@ -19,12 +26,6 @@ run() { echo "target is emulated" fi - # Directories and files that do not yet exist need to be created before - # calling docker, otherwise docker will create them but they will be owned - # by root. - mkdir -p target - cargo generate-lockfile --manifest-path builtins-test-intrinsics/Cargo.toml - run_cmd="HOME=/tmp" if [ "${GITHUB_ACTIONS:-}" = "true" ]; then -- cgit 1.4.1-3-g733a5 From 97e4729525b50533a49e49617ced23c8e692fd5b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 08:22:36 +0000 Subject: ci: Configure release-plz to run semver checks on `libm` --- library/compiler-builtins/.release-plz.toml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.release-plz.toml b/library/compiler-builtins/.release-plz.toml index e32f6761084..95d7517feea 100644 --- a/library/compiler-builtins/.release-plz.toml +++ b/library/compiler-builtins/.release-plz.toml @@ -1,7 +1,10 @@ -[workspace] +[[package]] +name = "compiler_builtins" semver_check = false - # As part of the release process, we delete `libm/Cargo.toml`. Since # this is only run in CI, we shouldn't need to worry about it. allow_dirty = true publish_allow_dirty = true + +[[package]] +name = "libm" -- cgit 1.4.1-3-g733a5 From 66be06a1a7968eaf7d201734eb5fc0e6a6a0d753 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 08:47:02 +0000 Subject: ci: Remove the old libm workflow file All jobs are now run as part of `compiler-builtins`. --- .../etc/libm/.github/workflows/main.yaml | 324 --------------------- 1 file changed, 324 deletions(-) delete mode 100644 library/compiler-builtins/etc/libm/.github/workflows/main.yaml diff --git a/library/compiler-builtins/etc/libm/.github/workflows/main.yaml b/library/compiler-builtins/etc/libm/.github/workflows/main.yaml deleted file mode 100644 index 5ce0dbc26c8..00000000000 --- a/library/compiler-builtins/etc/libm/.github/workflows/main.yaml +++ /dev/null @@ -1,324 +0,0 @@ -name: CI -on: - push: - branches: - - master - pull_request: - -concurrency: - # Make sure that new pushes cancel running jobs - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -env: - CARGO_TERM_COLOR: always - RUSTDOCFLAGS: -Dwarnings - RUSTFLAGS: -Dwarnings - RUST_BACKTRACE: full - BENCHMARK_RUSTC: nightly-2025-01-16 # Pin the toolchain for reproducable results - -jobs: - test: - name: Build and test - timeout-minutes: 60 - strategy: - fail-fast: false - matrix: - include: - - target: aarch64-apple-darwin - os: macos-15 - # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 - channel: nightly-2025-02-07 - - target: aarch64-unknown-linux-gnu - os: ubuntu-24.04-arm - # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 - channel: nightly-2025-02-07 - - target: aarch64-pc-windows-msvc - os: windows-2025 - build_only: 1 # Can't run on x86 hosts - - target: arm-unknown-linux-gnueabi - os: ubuntu-24.04 - - target: arm-unknown-linux-gnueabihf - os: ubuntu-24.04 - - target: armv7-unknown-linux-gnueabihf - os: ubuntu-24.04 - - target: i586-unknown-linux-gnu - os: ubuntu-24.04 - - target: i686-unknown-linux-gnu - os: ubuntu-24.04 - - target: loongarch64-unknown-linux-gnu - os: ubuntu-24.04 - - target: powerpc-unknown-linux-gnu - os: ubuntu-24.04 - - target: powerpc64-unknown-linux-gnu - os: ubuntu-24.04 - - target: powerpc64le-unknown-linux-gnu - os: ubuntu-24.04 - - target: riscv64gc-unknown-linux-gnu - os: ubuntu-24.04 - - target: thumbv6m-none-eabi - os: ubuntu-24.04 - - target: thumbv7em-none-eabi - os: ubuntu-24.04 - - target: thumbv7em-none-eabihf - os: ubuntu-24.04 - - target: thumbv7m-none-eabi - os: ubuntu-24.04 - - target: x86_64-unknown-linux-gnu - os: ubuntu-24.04 - - target: x86_64-apple-darwin - os: macos-13 - - target: wasm32-unknown-unknown - os: ubuntu-24.04 - build_only: 1 - - target: i686-pc-windows-msvc - os: windows-2025 - - target: x86_64-pc-windows-msvc - os: windows-2025 - - target: i686-pc-windows-gnu - os: windows-2025 - # FIXME: pinned due to https://github.com/rust-lang/rust/issues/136795 - channel: nightly-2025-02-07-i686-gnu - - target: x86_64-pc-windows-gnu - os: windows-2025 - channel: nightly-x86_64-gnu - runs-on: ${{ matrix.os }} - env: - BUILD_ONLY: ${{ matrix.build_only }} - steps: - - name: Print runner information - run: uname -a - - uses: actions/checkout@v4 - with: - submodules: true - - name: Install Rust (rustup) - shell: bash - run: | - channel="nightly" - # Account for channels that have required components (MinGW) - [ -n "${{ matrix.channel }}" ] && channel="${{ matrix.channel }}" - rustup update "$channel" --no-self-update - rustup default "$channel" - rustup target add "${{ matrix.target }}" - rustup component add clippy llvm-tools-preview - - uses: taiki-e/install-action@nextest - - uses: Swatinem/rust-cache@v2 - with: - key: ${{ matrix.target }} - - - name: Verify API list - if: matrix.os == 'ubuntu-24.04' - run: python3 etc/update-api-list.py --check - - # Non-linux tests just use our raw script - - name: Run locally - if: matrix.os != 'ubuntu-24.04' || contains(matrix.target, 'wasm') - shell: bash - run: ./ci/run.sh ${{ matrix.target }} - - # Otherwise we use our docker containers to run builds - - name: Run in Docker - if: matrix.os == 'ubuntu-24.04' && !contains(matrix.target, 'wasm') - run: | - rustup target add x86_64-unknown-linux-musl - cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} - - - name: Print test logs if available - if: always() - run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi - shell: bash - - clippy: - name: Clippy - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@master - with: - submodules: true - - name: Install Rust - run: | - rustup update nightly --no-self-update - rustup default nightly - rustup component add clippy - - uses: Swatinem/rust-cache@v2 - - run: cargo clippy --all --all-features --all-targets - - builtins: - name: Check use with compiler-builtins - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@master - - name: Install Rust - run: rustup update nightly --no-self-update && rustup default nightly - - uses: Swatinem/rust-cache@v2 - - run: cargo check --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml - - run: cargo test --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml - - benchmarks: - name: Benchmarks - runs-on: ubuntu-24.04 - timeout-minutes: 20 - steps: - - uses: actions/checkout@master - with: - submodules: true - - uses: taiki-e/install-action@cargo-binstall - - - name: Set up dependencies - run: | - sudo apt update - sudo apt install -y valgrind gdb libc6-dbg # Needed for iai-callgrind - rustup update "$BENCHMARK_RUSTC" --no-self-update - rustup default "$BENCHMARK_RUSTC" - # Install the version of iai-callgrind-runner that is specified in Cargo.toml - iai_version="$(cargo metadata --format-version=1 --features icount | - jq -r '.packages[] | select(.name == "iai-callgrind").version')" - cargo binstall -y iai-callgrind-runner --version "$iai_version" - sudo apt-get install valgrind - - - uses: Swatinem/rust-cache@v2 - - - name: Run icount benchmarks - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - run: ./ci/bench-icount.sh - - - name: Upload the benchmark baseline - uses: actions/upload-artifact@v4 - with: - name: ${{ env.BASELINE_NAME }} - path: ${{ env.BASELINE_NAME }}.tar.xz - - - name: Run wall time benchmarks - run: | - # Always use the same seed for benchmarks. Ideally we should switch to a - # non-random generator. - export LIBM_SEED=benchesbenchesbenchesbencheswoo! - cargo bench --all --features short-benchmarks,build-musl,force-soft-floats - - - name: Print test logs if available - if: always() - run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi - shell: bash - - msrv: - name: Check MSRV - runs-on: ubuntu-24.04 - timeout-minutes: 10 - env: - RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` - steps: - - uses: actions/checkout@master - - name: Install Rust - run: | - msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' libm/Cargo.toml)" - echo "MSRV: $msrv" - rustup update "$msrv" --no-self-update && rustup default "$msrv" - - uses: Swatinem/rust-cache@v2 - - run: | - # FIXME(msrv): Remove the workspace Cargo.toml so 1.63 cargo doesn't see - # `edition = "2024"` and get spooked. - rm Cargo.toml - cargo build --manifest-path libm/Cargo.toml - - rustfmt: - name: Rustfmt - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@master - - name: Install Rust - run: | - rustup update nightly --no-self-update - rustup default nightly - rustup component add rustfmt - - run: cargo fmt -- --check - - # Determine which extensive tests should be run based on changed files. - calculate_extensive_matrix: - name: Calculate job matrix - runs-on: ubuntu-24.04 - timeout-minutes: 10 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - outputs: - matrix: ${{ steps.script.outputs.matrix }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 100 - - name: Fetch pull request ref - run: git fetch origin "$GITHUB_REF:$GITHUB_REF" - if: github.event_name == 'pull_request' - - run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT" - id: script - - extensive: - name: Extensive tests for ${{ matrix.ty }} - needs: - # Wait on `clippy` so we have some confidence that the crate will build - - clippy - - calculate_extensive_matrix - runs-on: ubuntu-24.04 - timeout-minutes: 240 # 4 hours - strategy: - matrix: - # Use the output from `calculate_extensive_matrix` to calculate the matrix - # FIXME: it would be better to run all jobs (i.e. all types) but mark those that - # didn't change as skipped, rather than completely excluding the job. However, - # this is not currently possible https://github.com/actions/runner/issues/1985. - include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }} - env: - TO_TEST: ${{ matrix.to_test }} - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Install Rust - run: | - rustup update nightly --no-self-update - rustup default nightly - - uses: Swatinem/rust-cache@v2 - - name: Run extensive tests - run: | - echo "Tests to run: '$TO_TEST'" - if [ -z "$TO_TEST" ]; then - echo "No tests to run, exiting." - exit - fi - - set -x - - # Run the non-extensive tests first to catch any easy failures - cargo t --profile release-checked -- "$TO_TEST" - - LIBM_EXTENSIVE_TESTS="$TO_TEST" cargo t \ - --features build-mpfr,unstable,force-soft-floats \ - --profile release-checked \ - -- extensive - - name: Print test logs if available - run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi - shell: bash - - success: - needs: - - test - - builtins - - benchmarks - - msrv - - rustfmt - - extensive - runs-on: ubuntu-24.04 - timeout-minutes: 10 - # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency - # failed" as success. So we have to do some contortions to ensure the job fails if any of its - # dependencies fails. - if: always() # make sure this is never "skipped" - steps: - # Manually check the status of all dependencies. `if: failure()` does not work. - - name: check if any dependency failed - run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' -- cgit 1.4.1-3-g733a5 From 4e8eea696d8a1777b2f0eed7c58323c478b91b39 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 08:54:11 +0000 Subject: Add panic-handler to the workspace This crate does not interact with features so there isn't any reason it can't become part of the workspace. --- library/compiler-builtins/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c3737a042f5..75bb81ec187 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,6 +5,7 @@ members = [ "compiler-builtins", "crates/libm-macros", "crates/musl-math-sys", + "crates/panic-handler", "crates/util", "libm", "libm-test", -- cgit 1.4.1-3-g733a5 From cf13785636c924ba13ce3f2ae51f5ffe5057b007 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 18:39:53 +0000 Subject: ci: Fix release-plz configuration --- library/compiler-builtins/.release-plz.toml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.release-plz.toml b/library/compiler-builtins/.release-plz.toml index 95d7517feea..95e91a46c8d 100644 --- a/library/compiler-builtins/.release-plz.toml +++ b/library/compiler-builtins/.release-plz.toml @@ -1,10 +1,12 @@ -[[package]] -name = "compiler_builtins" -semver_check = false +[workspace] # As part of the release process, we delete `libm/Cargo.toml`. Since # this is only run in CI, we shouldn't need to worry about it. allow_dirty = true publish_allow_dirty = true +[[package]] +name = "compiler_builtins" +semver_check = false + [[package]] name = "libm" -- cgit 1.4.1-3-g733a5 From 97ddaca3565d2720c2ccfe78e02e841dc3872005 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Apr 2025 06:35:12 +0000 Subject: Remove `unsafe` from `naked_asm!` blocks This was changed in a recent nightly so the unsafety is only in the attribute, `#[unsafe(naked)]`. --- .../compiler-builtins/src/aarch64_linux.rs | 16 ++++++++-------- .../compiler-builtins/compiler-builtins/src/macros.rs | 3 ++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs b/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs index 5515dbfc43a..e238d0237eb 100644 --- a/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs +++ b/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs @@ -136,7 +136,7 @@ macro_rules! compare_and_swap { expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { // We can't use `AtomicI8::compare_and_swap`; we *are* compare_and_swap. - unsafe { core::arch::naked_asm! { + core::arch::naked_asm! { // UXT s(tmp0), s(0) concat!(uxt!($bytes), " ", reg!($bytes, 16), ", ", reg!($bytes, 0)), "0:", @@ -150,7 +150,7 @@ macro_rules! compare_and_swap { "cbnz w17, 0b", "1:", "ret", - } } + } } } }; @@ -165,7 +165,7 @@ macro_rules! compare_and_swap_i128 { pub unsafe extern "C" fn $name ( expected: i128, desired: i128, ptr: *mut i128 ) -> i128 { - unsafe { core::arch::naked_asm! { + core::arch::naked_asm! { "mov x16, x0", "mov x17, x1", "0:", @@ -179,7 +179,7 @@ macro_rules! compare_and_swap_i128 { "cbnz w15, 0b", "1:", "ret", - } } + } } } }; @@ -194,7 +194,7 @@ macro_rules! swap { pub unsafe extern "C" fn $name ( left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { - unsafe { core::arch::naked_asm! { + core::arch::naked_asm! { // mov s(tmp0), s(0) concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), "0:", @@ -204,7 +204,7 @@ macro_rules! swap { concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 16), ", [x1]"), "cbnz w17, 0b", "ret", - } } + } } } }; @@ -219,7 +219,7 @@ macro_rules! fetch_op { pub unsafe extern "C" fn $name ( val: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { - unsafe { core::arch::naked_asm! { + core::arch::naked_asm! { // mov s(tmp0), s(0) concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), "0:", @@ -231,7 +231,7 @@ macro_rules! fetch_op { concat!(stxr!($ordering, $bytes), " w15, ", reg!($bytes, 17), ", [x1]"), "cbnz w15, 0b", "ret", - } } + } } } } diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index b83414ce2b7..4fa53656e5c 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -436,11 +436,12 @@ macro_rules! intrinsics { // FIXME: when bootstrap supports `#[unsafe(naked)]` this duplication can be removed #[cfg(bootstrap)] #[naked] + #[allow(unused_unsafe)] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* + unsafe { $($body)* } } #[cfg(not(bootstrap))] -- cgit 1.4.1-3-g733a5 From e0d07241d06960b248d32fc2d33e5082c5ec8d53 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Sun, 20 Apr 2025 09:05:10 +0200 Subject: avr: Provide `abort()` --- .../compiler-builtins/compiler-builtins/src/avr.rs | 23 ++++++++++++++++++++++ .../compiler-builtins/compiler-builtins/src/lib.rs | 3 +++ 2 files changed, 26 insertions(+) create mode 100644 library/compiler-builtins/compiler-builtins/src/avr.rs diff --git a/library/compiler-builtins/compiler-builtins/src/avr.rs b/library/compiler-builtins/compiler-builtins/src/avr.rs new file mode 100644 index 00000000000..359a1d1acc1 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/avr.rs @@ -0,0 +1,23 @@ +intrinsics! { + pub unsafe extern "C" fn abort() -> ! { + // On AVRs, an architecture that doesn't support traps, unreachable code + // paths get lowered into calls to `abort`: + // + // https://github.com/llvm/llvm-project/blob/cbe8f3ad7621e402b050e768f400ff0d19c3aedd/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp#L4462 + // + // When control gets here, it means that either core::intrinsics::abort() + // was called or an undefined bebavior has occurred, so there's not that + // much we can do to recover - we can't `panic!()`, because for all we + // know the environment is gone now, so panicking might end up with us + // getting back to this very function. + // + // So let's do the next best thing, loop. + // + // Alternatively we could (try to) restart the program, but since + // undefined behavior is undefined, there's really no obligation for us + // to do anything here - for all we care, we could just set the chip on + // fire; but that'd be bad for the environment. + + loop {} + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index 16de96b4da0..0678556037f 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -63,6 +63,9 @@ pub mod aarch64_linux; ))] pub mod arm_linux; +#[cfg(target_arch = "avr")] +pub mod avr; + #[cfg(target_arch = "hexagon")] pub mod hexagon; -- cgit 1.4.1-3-g733a5 From 013a83acddaa5fba20c3b0a593ce0c81ef0689da Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Apr 2025 07:15:48 +0000 Subject: Update licensing information after repository refactoring In order to disambiguate things now that libm is part of the compiler-builtins repository, do the following: * Mention libm in LICENSE.txt * Clarify the default license for crates other than libm and compiler-builtins * Add an explicit license field to Cargo.toml for all other crates --- library/compiler-builtins/LICENSE.txt | 17 +++++++++++------ .../builtins-test-intrinsics/Cargo.toml | 1 + library/compiler-builtins/builtins-test/Cargo.toml | 1 + library/compiler-builtins/crates/libm-macros/Cargo.toml | 1 + .../compiler-builtins/crates/musl-math-sys/Cargo.toml | 1 + library/compiler-builtins/crates/util/Cargo.toml | 1 + library/compiler-builtins/libm-test/Cargo.toml | 1 + 7 files changed, 17 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/LICENSE.txt b/library/compiler-builtins/LICENSE.txt index 367e3538df0..00ae6140bd5 100644 --- a/library/compiler-builtins/LICENSE.txt +++ b/library/compiler-builtins/LICENSE.txt @@ -1,10 +1,14 @@ -compiler-builtins as a whole is available for use under both the MIT license +The compiler-builtins crate is available for use under both the MIT license and the Apache-2.0 license with the LLVM exception (MIT AND Apache-2.0 WITH LLVM-exception). -As a contributor, you agree that your code can be used under either the MIT -license, or the Apache-2.0 license, or the Apache-2.0 license with the LLVM -exception. +The libm crate is available for use under the MIT license. + +As a contributor, you agree that your code may be used under any of the +following: the MIT license, the Apache-2.0 license, or the Apache-2.0 license +with the LLVM exception. In other words, original (non-derivative) work is +licensed under MIT OR Apache-2.0 OR Apache-2.0 WITH LLVM-exception. This is +the default license for all other source in this repository. Text of the relevant licenses is provided below: @@ -263,8 +267,9 @@ license: * Work derived from compiler-rt after 2019-01-19 is usable under the Apache-2.0 license with the LLVM exception. -* The bundled `math` module is from rust-lang/libm, usable under the MIT - license. See https://github.com/rust-lang/libm for details. +* The bundled `math` module is from the libm crate, usable under the MIT + license. For further details and copyrights, see see libm/LICENSE.txt at + https://github.com/rust-lang/compiler-builtins. Additionally, some source files may contain comments with specific copyrights or licenses. diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 6d88cbec90d..6e10628a41b 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -3,6 +3,7 @@ name = "builtins-test-intrinsics" version = "0.1.0" edition = "2021" publish = false +license = "MIT OR Apache-2.0" [dependencies] compiler_builtins = { path = "../compiler-builtins", features = ["compiler-builtins"]} diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index 18185d8fe40..f7bcb52b40f 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Alex Crichton "] edition = "2024" publish = false +license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" [dependencies] # For fuzzing tests we want a deterministic seedable RNG. We also eliminate potential diff --git a/library/compiler-builtins/crates/libm-macros/Cargo.toml b/library/compiler-builtins/crates/libm-macros/Cargo.toml index 50c869db7ff..3929854f08e 100644 --- a/library/compiler-builtins/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/crates/libm-macros/Cargo.toml @@ -3,6 +3,7 @@ name = "libm-macros" version = "0.1.0" edition = "2024" publish = false +license = "MIT OR Apache-2.0" [lib] proc-macro = true diff --git a/library/compiler-builtins/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/crates/musl-math-sys/Cargo.toml index 9e866a9704f..d3fb147e526 100644 --- a/library/compiler-builtins/crates/musl-math-sys/Cargo.toml +++ b/library/compiler-builtins/crates/musl-math-sys/Cargo.toml @@ -3,6 +3,7 @@ name = "musl-math-sys" version = "0.1.0" edition = "2024" publish = false +license = "MIT OR Apache-2.0" [dependencies] diff --git a/library/compiler-builtins/crates/util/Cargo.toml b/library/compiler-builtins/crates/util/Cargo.toml index ae37a723816..614c54bd835 100644 --- a/library/compiler-builtins/crates/util/Cargo.toml +++ b/library/compiler-builtins/crates/util/Cargo.toml @@ -3,6 +3,7 @@ name = "util" version = "0.1.0" edition = "2024" publish = false +license = "MIT OR Apache-2.0" [features] default = ["build-musl", "build-mpfr", "unstable-float"] diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index 6fd49774e0c..7a306e73557 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -3,6 +3,7 @@ name = "libm-test" version = "0.1.0" edition = "2024" publish = false +license = "MIT OR Apache-2.0" [features] default = ["build-mpfr", "build-musl", "unstable-float"] -- cgit 1.4.1-3-g733a5 From 8ce02e8ef578880d56e89ff975475c190471db2a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Apr 2025 07:22:24 +0000 Subject: Move README.md to compiler-builtins, CONTRIBUTING.md to root Do this in a commit so git tracks the move; a new README will be introduced in the root, and CONTRIBUTING will be updated to apply to both crates. --- library/compiler-builtins/CONTRIBUTING.md | 82 ++++ library/compiler-builtins/README.md | 476 --------------------- .../compiler-builtins/compiler-builtins/Cargo.toml | 2 +- .../compiler-builtins/compiler-builtins/README.md | 476 +++++++++++++++++++++ library/compiler-builtins/libm/CONTRIBUTING.md | 82 ---- 5 files changed, 559 insertions(+), 559 deletions(-) create mode 100644 library/compiler-builtins/CONTRIBUTING.md delete mode 100644 library/compiler-builtins/README.md create mode 100644 library/compiler-builtins/compiler-builtins/README.md delete mode 100644 library/compiler-builtins/libm/CONTRIBUTING.md diff --git a/library/compiler-builtins/CONTRIBUTING.md b/library/compiler-builtins/CONTRIBUTING.md new file mode 100644 index 00000000000..dc40060357c --- /dev/null +++ b/library/compiler-builtins/CONTRIBUTING.md @@ -0,0 +1,82 @@ +# How to contribute + +- Pick your favorite math function from the [issue tracker]. +- Look for the C implementation of the function in the [MUSL source code][src]. +- Copy paste the C code into a Rust file in the `src/math` directory and adjust + `src/math/mod.rs` accordingly. Also, uncomment the corresponding trait method + in `src/lib.rs`. +- Write some simple tests in your module (using `#[test]`) +- Run `cargo test` to make sure it works. Full tests are only run when enabling + features, see [Testing](#testing) below. +- Send us a pull request! Make sure to run `cargo fmt` on your code before + sending the PR. Also include "closes #42" in the PR description to close the + corresponding issue. +- :tada: + +[issue tracker]: https://github.com/rust-lang/libm/issues +[src]: https://git.musl-libc.org/cgit/musl/tree/src/math +[`src/math/truncf.rs`]: https://github.com/rust-lang/libm/blob/master/src/math/truncf.rs + +Check [PR #65] for an example. + +[PR #65]: https://github.com/rust-lang/libm/pull/65 + +## Tips and tricks + +- *IMPORTANT* The code in this crate will end up being used in the `core` crate so it can **not** + have any external dependencies (other than `core` itself). + +- Only use relative imports within the `math` directory / module, e.g. `use self::fabs::fabs` or +`use super::k_cos`. Absolute imports from core are OK, e.g. `use core::u64`. + +- To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the + `GET_FLOAT_WORD` macro, or a union, to do this operation. + +- To reinterpret an integer as a float use the `f32::from_bits` constructor. The MUSL code uses the + `SET_FLOAT_WORD` macro, or a union, to do this operation. + +- You may use other methods from core like `f64::is_nan`, etc. as appropriate. + +- If you're implementing one of the private double-underscore functions, take a look at the + "source" name in the comment at the top for an idea for alternate naming. For example, `__sin` + was renamed to `k_sin` after the FreeBSD source code naming. Do `use` these private functions in + `mod.rs`. + +- You may encounter weird literals like `0x1p127f` in the MUSL code. These are hexadecimal floating + point literals. Rust (the language) doesn't support these kind of literals. This crate provides + two macros, `hf32!` and `hf64!`, which convert string literals to floats at compile time. + + ```rust + assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000); + assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000); + ``` + +- Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`] + newtype to avoid this problem, or individual methods like [`wrapping_add`]. + +[`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html +[`wrapping_add`]: https://doc.rust-lang.org/std/primitive.u32.html#method.wrapping_add + +## Testing + +Normal tests can be executed with: + +```sh +# Tests against musl require that the submodule is up to date. +git submodule init +git submodule update + +# `--release` ables more test cases +cargo test --release +``` + +If you are on a system that cannot build musl or MPFR, passing +`--no-default-features` will run some limited tests. + +The multiprecision tests use the [`rug`] crate for bindings to MPFR. MPFR can +be difficult to build on non-Unix systems, refer to [`gmp_mpfr_sys`] for help. + +`build-musl` does not build with MSVC, Wasm, or Thumb. + +[`rug`]: https://docs.rs/rug/latest/rug/ +[`gmp_mpfr_sys`]: https://docs.rs/gmp-mpfr-sys/1.6.4/gmp_mpfr_sys/ diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md deleted file mode 100644 index e5350d58c3e..00000000000 --- a/library/compiler-builtins/README.md +++ /dev/null @@ -1,476 +0,0 @@ -# `compiler-builtins` - -This crate provides external symbols that the compiler expects to be available when -building Rust projects, typically software routines for basic operations that do not -have hardware support. It is largely a port of LLVM's [`compiler-rt`]. - -It is distributed as part of Rust's sysroot. - -[`compiler-rt`]: https://github.com/llvm/llvm-project/tree/1b1dc505057322f4fa1110ef4f53c44347f52986/compiler-rt - -## Contributing - -1. Pick one or more intrinsics from the [pending list](#progress). -2. Fork this repository. -3. Port the intrinsic(s) and their corresponding [unit tests][1] from their - [C implementation][2] to Rust. -4. Add a test to compare the behavior of the ported intrinsic(s) with their - implementation on the testing host. -5. Add the intrinsic to `builtins-test-intrinsics/src/main.rs` to verify it - can be linked on all targets. -6. Send a Pull Request (PR). -7. Once the PR passes our extensive testing infrastructure, we'll merge it! -8. Celebrate :tada: - -[1]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/test/builtins/Unit -[2]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/lib/builtins -[3]: https://github.com/rust-lang/compiler-builtins/actions - -### Porting Reminders - -1. [Rust][5a] and [C][5b] have slightly different operator precedence. C evaluates comparisons (`== !=`) before bitwise operations (`& | ^`), while Rust evaluates the other way. -2. C assumes wrapping operations everywhere. Rust panics on overflow when in debug mode. Consider using the [Wrapping][6] type or the explicit [wrapping_*][7] functions where applicable. -3. Note [C implicit casts][8], especially integer promotion. Rust is much more explicit about casting, so be sure that any cast which affects the output is ported to the Rust implementation. -4. Rust has [many functions][9] for integer or floating point manipulation in the standard library. Consider using one of these functions rather than porting a new one. - -[5a]: https://doc.rust-lang.org/reference/expressions.html#expression-precedence -[5b]: http://en.cppreference.com/w/c/language/operator_precedence -[6]: https://doc.rust-lang.org/core/num/struct.Wrapping.html -[7]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_add -[8]: http://en.cppreference.com/w/cpp/language/implicit_conversion -[9]: https://doc.rust-lang.org/std/primitive.i32.html - -## Testing - -The easiest way to test locally is using Docker. This can be done by running -`./ci/run-docker.sh [target]`. If no target is specified, all targets will be -run. - -In order to run the full test suite, you will also need the C compiler runtime -to test against, located in a directory called `compiler-rt`. This can be -obtained with the following: - -```sh -curl -L -o rustc-llvm-20.1.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/20.1-2025-02-13.tar.gz -tar xzf rustc-llvm-20.1.tar.gz --strip-components 1 llvm-project-rustc-20.1-2025-02-13/compiler-rt -``` - -Local targets may also be tested with `./ci/run.sh [target]`. - -Note that testing may not work on all hosts, in which cases it is acceptable to -rely on CI. - -## Progress - -- [x] aarch64/chkstk.S -- [x] adddf3.c -- [x] addsf3.c -- [x] arm/addsf3.S -- [x] arm/aeabi_dcmp.S -- [x] arm/aeabi_fcmp.S -- [x] arm/aeabi_idivmod.S -- [x] arm/aeabi_ldivmod.S -- [x] arm/aeabi_memcpy.S -- [x] arm/aeabi_memmove.S -- [x] arm/aeabi_memset.S -- [x] arm/aeabi_uidivmod.S -- [x] arm/aeabi_uldivmod.S -- [ ] arm/chkstk.S -- [ ] arm/divmodsi4.S (generic version is done) -- [ ] arm/divsi3.S (generic version is done) -- [ ] arm/modsi3.S (generic version is done) -- [x] arm/softfloat-alias.list -- [ ] arm/udivmodsi4.S (generic version is done) -- [ ] arm/udivsi3.S (generic version is done) -- [ ] arm/umodsi3.S (generic version is done) -- [x] ashldi3.c -- [x] ashrdi3.c -- [ ] avr/divmodhi4.S -- [ ] avr/divmodqi4.S -- [ ] avr/mulhi3.S -- [ ] avr/mulqi3.S -- [ ] avr/udivmodhi4.S -- [ ] avr/udivmodqi4.S -- [x] bswapdi2.c -- [x] bswapsi2.c -- [x] bswapti2.c -- [x] clzdi2.c -- [x] clzsi2.c -- [x] clzti2.c -- [x] comparedf2.c -- [x] comparesf2.c -- [x] ctzdi2.c -- [x] ctzsi2.c -- [x] ctzti2.c -- [x] divdf3.c -- [x] divdi3.c -- [x] divmoddi4.c -- [x] divmodsi4.c -- [x] divmodti4.c -- [x] divsf3.c -- [x] divsi3.c -- [x] extendsfdf2.c -- [x] fixdfdi.c -- [x] fixdfsi.c -- [x] fixsfdi.c -- [x] fixsfsi.c -- [x] fixunsdfdi.c -- [x] fixunsdfsi.c -- [x] fixunssfdi.c -- [x] fixunssfsi.c -- [x] floatdidf.c -- [x] floatdisf.c -- [x] floatsidf.c -- [x] floatsisf.c -- [x] floatundidf.c -- [x] floatundisf.c -- [x] floatunsidf.c -- [x] floatunsisf.c -- [ ] i386/ashldi3.S -- [ ] i386/ashrdi3.S -- [x] i386/chkstk.S -- [ ] i386/divdi3.S -- [ ] i386/lshrdi3.S -- [ ] i386/moddi3.S -- [ ] i386/muldi3.S -- [ ] i386/udivdi3.S -- [ ] i386/umoddi3.S -- [x] lshrdi3.c -- [x] moddi3.c -- [x] modsi3.c -- [x] muldf3.c -- [x] muldi3.c -- [x] mulodi4.c -- [x] mulosi4.c -- [x] mulsf3.c -- [x] powidf2.c -- [x] powisf2.c -- [ ] riscv/muldi3.S -- [ ] riscv/mulsi3.S -- [x] subdf3.c -- [x] subsf3.c -- [x] truncdfsf2.c -- [x] udivdi3.c -- [x] udivmoddi4.c -- [x] udivmodsi4.c -- [x] udivsi3.c -- [x] umoddi3.c -- [x] umodsi3.c -- [x] x86_64/chkstk.S - -These builtins are needed to support 128-bit integers. - -- [x] ashlti3.c -- [x] ashrti3.c -- [x] divti3.c -- [x] fixdfti.c -- [x] fixsfti.c -- [x] fixunsdfti.c -- [x] fixunssfti.c -- [x] floattidf.c -- [x] floattisf.c -- [x] floatuntidf.c -- [x] floatuntisf.c -- [x] lshrti3.c -- [x] modti3.c -- [x] muloti4.c -- [x] multi3.c -- [x] udivmodti4.c -- [x] udivti3.c -- [x] umodti3.c - -These builtins are needed to support `f16` and `f128`, which are in the process -of being added to Rust. - -- [x] addtf3.c -- [x] comparetf2.c -- [x] divtf3.c -- [x] extenddftf2.c -- [x] extendhfsf2.c -- [x] extendhftf2.c -- [x] extendsftf2.c -- [x] fixtfdi.c -- [x] fixtfsi.c -- [x] fixtfti.c -- [x] fixunstfdi.c -- [x] fixunstfsi.c -- [x] fixunstfti.c -- [x] floatditf.c -- [x] floatsitf.c -- [x] floattitf.c -- [x] floatunditf.c -- [x] floatunsitf.c -- [x] floatuntitf.c -- [x] multf3.c -- [x] powitf2.c -- [x] subtf3.c -- [x] truncdfhf2.c -- [x] truncsfhf2.c -- [x] trunctfdf2.c -- [x] trunctfhf2.c -- [x] trunctfsf2.c - - -These builtins are used by the Hexagon DSP - -- [ ] hexagon/common_entry_exit_abi1.S -- [ ] hexagon/common_entry_exit_abi2.S -- [ ] hexagon/common_entry_exit_legacy.S -- [x] hexagon/dfaddsub.S~~ -- [x] hexagon/dfdiv.S~~ -- [x] hexagon/dffma.S~~ -- [x] hexagon/dfminmax.S~~ -- [x] hexagon/dfmul.S~~ -- [x] hexagon/dfsqrt.S~~ -- [x] hexagon/divdi3.S~~ -- [x] hexagon/divsi3.S~~ -- [x] hexagon/fastmath2_dlib_asm.S~~ -- [x] hexagon/fastmath2_ldlib_asm.S~~ -- [x] hexagon/fastmath_dlib_asm.S~~ -- [x] hexagon/memcpy_forward_vp4cp4n2.S~~ -- [x] hexagon/memcpy_likely_aligned.S~~ -- [x] hexagon/moddi3.S~~ -- [x] hexagon/modsi3.S~~ -- [x] hexagon/sfdiv_opt.S~~ -- [x] hexagon/sfsqrt_opt.S~~ -- [x] hexagon/udivdi3.S~~ -- [x] hexagon/udivmoddi4.S~~ -- [x] hexagon/udivmodsi4.S~~ -- [x] hexagon/udivsi3.S~~ -- [x] hexagon/umoddi3.S~~ -- [x] hexagon/umodsi3.S~~ - -## Unimplemented functions - -These builtins are for x87 `f80` floating-point numbers that are not supported -by Rust. - -- ~~extendxftf2.c~~ -- ~~fixunsxfdi.c~~ -- ~~fixunsxfsi.c~~ -- ~~fixunsxfti.c~~ -- ~~fixxfdi.c~~ -- ~~fixxfti.c~~ -- ~~floatdixf.c~~ -- ~~floattixf.c~~ -- ~~floatundixf.c~~ -- ~~floatuntixf.c~~ -- ~~i386/floatdixf.S~~ -- ~~i386/floatundixf.S~~ -- ~~x86_64/floatdixf.c~~ -- ~~x86_64/floatundixf.S~~ - -These builtins are for IBM "extended double" non-IEEE 128-bit floating-point -numbers. - -- ~~ppc/divtc3.c~~ -- ~~ppc/fixtfdi.c~~ -- ~~ppc/fixtfti.c~~ -- ~~ppc/fixunstfdi.c~~ -- ~~ppc/fixunstfti.c~~ -- ~~ppc/floatditf.c~~ -- ~~ppc/floattitf.c~~ -- ~~ppc/floatunditf.c~~ -- ~~ppc/gcc_qadd.c~~ -- ~~ppc/gcc_qdiv.c~~ -- ~~ppc/gcc_qmul.c~~ -- ~~ppc/gcc_qsub.c~~ -- ~~ppc/multc3.c~~ - -These builtins are for 16-bit brain floating-point numbers that are not -supported by Rust. - -- ~~truncdfbf2.c~~ -- ~~truncsfbf2.c~~ -- ~~trunctfxf2.c~~ - -These builtins involve complex floating-point types that are not supported by -Rust. - -- ~~divdc3.c~~ -- ~~divsc3.c~~ -- ~~divtc3.c~~ -- ~~divxc3.c~~ -- ~~muldc3.c~~ -- ~~mulsc3.c~~ -- ~~multc3.c~~ -- ~~mulxc3.c~~ -- ~~powixf2.c~~ - -These builtins are never called by LLVM. - -- ~~absvdi2.c~~ -- ~~absvsi2.c~~ -- ~~absvti2.c~~ -- ~~addvdi3.c~~ -- ~~addvsi3.c~~ -- ~~addvti3.c~~ -- ~~arm/aeabi_cdcmp.S~~ -- ~~arm/aeabi_cdcmpeq_check_nan.c~~ -- ~~arm/aeabi_cfcmp.S~~ -- ~~arm/aeabi_cfcmpeq_check_nan.c~~ -- ~~arm/aeabi_div0.c~~ -- ~~arm/aeabi_drsub.c~~ -- ~~arm/aeabi_frsub.c~~ -- ~~arm/aeabi_memcmp.S~~ -- ~~arm/bswapdi2.S~~ -- ~~arm/bswapsi2.S~~ -- ~~arm/clzdi2.S~~ -- ~~arm/clzsi2.S~~ -- ~~arm/comparesf2.S~~ -- ~~arm/restore_vfp_d8_d15_regs.S~~ -- ~~arm/save_vfp_d8_d15_regs.S~~ -- ~~arm/switch16.S~~ -- ~~arm/switch32.S~~ -- ~~arm/switch8.S~~ -- ~~arm/switchu8.S~~ -- ~~cmpdi2.c~~ -- ~~cmpti2.c~~ -- ~~ffssi2.c~~ -- ~~ffsdi2.c~~ - this is [called by gcc][jemalloc-fail] though! -- ~~ffsti2.c~~ -- ~~mulvdi3.c~~ -- ~~mulvsi3.c~~ -- ~~mulvti3.c~~ -- ~~negdf2.c~~ -- ~~negdi2.c~~ -- ~~negsf2.c~~ -- ~~negti2.c~~ -- ~~negvdi2.c~~ -- ~~negvsi2.c~~ -- ~~negvti2.c~~ -- ~~paritydi2.c~~ -- ~~paritysi2.c~~ -- ~~parityti2.c~~ -- ~~popcountdi2.c~~ -- ~~popcountsi2.c~~ -- ~~popcountti2.c~~ -- ~~ppc/restFP.S~~ -- ~~ppc/saveFP.S~~ -- ~~subvdi3.c~~ -- ~~subvsi3.c~~ -- ~~subvti3.c~~ -- ~~ucmpdi2.c~~ -- ~~ucmpti2.c~~ -- ~~udivmodti4.c~~ - -[jemalloc-fail]: https://travis-ci.org/rust-lang/rust/jobs/249772758 - -Rust only exposes atomic types on platforms that support them, and therefore does not need to fall back to software implementations. - -- ~~arm/sync_fetch_and_add_4.S~~ -- ~~arm/sync_fetch_and_add_8.S~~ -- ~~arm/sync_fetch_and_and_4.S~~ -- ~~arm/sync_fetch_and_and_8.S~~ -- ~~arm/sync_fetch_and_max_4.S~~ -- ~~arm/sync_fetch_and_max_8.S~~ -- ~~arm/sync_fetch_and_min_4.S~~ -- ~~arm/sync_fetch_and_min_8.S~~ -- ~~arm/sync_fetch_and_nand_4.S~~ -- ~~arm/sync_fetch_and_nand_8.S~~ -- ~~arm/sync_fetch_and_or_4.S~~ -- ~~arm/sync_fetch_and_or_8.S~~ -- ~~arm/sync_fetch_and_sub_4.S~~ -- ~~arm/sync_fetch_and_sub_8.S~~ -- ~~arm/sync_fetch_and_umax_4.S~~ -- ~~arm/sync_fetch_and_umax_8.S~~ -- ~~arm/sync_fetch_and_umin_4.S~~ -- ~~arm/sync_fetch_and_umin_8.S~~ -- ~~arm/sync_fetch_and_xor_4.S~~ -- ~~arm/sync_fetch_and_xor_8.S~~ -- ~~arm/sync_synchronize.S~~ -- ~~atomic.c~~ -- ~~atomic_flag_clear.c~~ -- ~~atomic_flag_clear_explicit.c~~ -- ~~atomic_flag_test_and_set.c~~ -- ~~atomic_flag_test_and_set_explicit.c~~ -- ~~atomic_signal_fence.c~~ -- ~~atomic_thread_fence.c~~ - -Miscellaneous functionality that is not used by Rust. - -- ~~aarch64/fp_mode.c~~ -- ~~aarch64/lse.S~~ (LSE atomics) -- ~~aarch64/sme-abi-init.c~~ (matrix extension) -- ~~aarch64/sme-abi.S~~ (matrix extension) -- ~~aarch64/sme-libc-routines.c~~ (matrix extension) -- ~~apple_versioning.c~~ -- ~~arm/fp_mode.c~~ -- ~~avr/exit.S~~ -- ~~clear_cache.c~~ -- ~~cpu_model/aarch64.c~~ -- ~~cpu_model/x86.c~~ -- ~~crtbegin.c~~ -- ~~crtend.c~~ -- ~~emutls.c~~ -- ~~enable_execute_stack.c~~ -- ~~eprintf.c~~ -- ~~fp_mode.c~~ (float exception handling) -- ~~gcc_personality_v0.c~~ -- ~~i386/fp_mode.c~~ -- ~~int_util.c~~ -- ~~loongarch/fp_mode.c~~ -- ~~os_version_check.c~~ -- ~~riscv/fp_mode.c~~ -- ~~riscv/restore.S~~ (callee-saved registers) -- ~~riscv/save.S~~ (callee-saved registers) -- ~~trampoline_setup.c~~ -- ~~ve/grow_stack.S~~ -- ~~ve/grow_stack_align.S~~ - -Floating-point implementations of builtins that are only called from soft-float code. It would be better to simply use the generic soft-float versions in this case. - -- ~~i386/floatdidf.S~~ -- ~~i386/floatdisf.S~~ -- ~~i386/floatundidf.S~~ -- ~~i386/floatundisf.S~~ -- ~~x86_64/floatundidf.S~~ -- ~~x86_64/floatundisf.S~~ -- ~~x86_64/floatdidf.c~~ -- ~~x86_64/floatdisf.c~~ - -Unsupported in any current target: used on old versions of 32-bit iOS with ARMv5. - -- ~~arm/adddf3vfp.S~~ -- ~~arm/addsf3vfp.S~~ -- ~~arm/divdf3vfp.S~~ -- ~~arm/divsf3vfp.S~~ -- ~~arm/eqdf2vfp.S~~ -- ~~arm/eqsf2vfp.S~~ -- ~~arm/extendsfdf2vfp.S~~ -- ~~arm/fixdfsivfp.S~~ -- ~~arm/fixsfsivfp.S~~ -- ~~arm/fixunsdfsivfp.S~~ -- ~~arm/fixunssfsivfp.S~~ -- ~~arm/floatsidfvfp.S~~ -- ~~arm/floatsisfvfp.S~~ -- ~~arm/floatunssidfvfp.S~~ -- ~~arm/floatunssisfvfp.S~~ -- ~~arm/gedf2vfp.S~~ -- ~~arm/gesf2vfp.S~~ -- ~~arm/gtdf2vfp.S~~ -- ~~arm/gtsf2vfp.S~~ -- ~~arm/ledf2vfp.S~~ -- ~~arm/lesf2vfp.S~~ -- ~~arm/ltdf2vfp.S~~ -- ~~arm/ltsf2vfp.S~~ -- ~~arm/muldf3vfp.S~~ -- ~~arm/mulsf3vfp.S~~ -- ~~arm/nedf2vfp.S~~ -- ~~arm/negdf2vfp.S~~ -- ~~arm/negsf2vfp.S~~ -- ~~arm/nesf2vfp.S~~ -- ~~arm/subdf3vfp.S~~ -- ~~arm/subsf3vfp.S~~ -- ~~arm/truncdfsf2vfp.S~~ -- ~~arm/unorddf2vfp.S~~ -- ~~arm/unordsf2vfp.S~~ - -## License - -The compiler-builtins crate is dual licensed under both the University of -Illinois "BSD-Like" license and the MIT license. As a user of this code you may -choose to use it under either license. As a contributor, you agree to allow -your code to be used under both. - -Full text of the relevant licenses is in LICENSE.TXT. diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index a014baf040a..e2a6c0a74bd 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -18,8 +18,8 @@ include = [ '/configure.rs', '/src/*', '../LICENSE.txt', - '../README.md', '../compiler-rt/*', + 'README.md', 'libm/src/math/*', ] links = 'compiler-rt' diff --git a/library/compiler-builtins/compiler-builtins/README.md b/library/compiler-builtins/compiler-builtins/README.md new file mode 100644 index 00000000000..e5350d58c3e --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/README.md @@ -0,0 +1,476 @@ +# `compiler-builtins` + +This crate provides external symbols that the compiler expects to be available when +building Rust projects, typically software routines for basic operations that do not +have hardware support. It is largely a port of LLVM's [`compiler-rt`]. + +It is distributed as part of Rust's sysroot. + +[`compiler-rt`]: https://github.com/llvm/llvm-project/tree/1b1dc505057322f4fa1110ef4f53c44347f52986/compiler-rt + +## Contributing + +1. Pick one or more intrinsics from the [pending list](#progress). +2. Fork this repository. +3. Port the intrinsic(s) and their corresponding [unit tests][1] from their + [C implementation][2] to Rust. +4. Add a test to compare the behavior of the ported intrinsic(s) with their + implementation on the testing host. +5. Add the intrinsic to `builtins-test-intrinsics/src/main.rs` to verify it + can be linked on all targets. +6. Send a Pull Request (PR). +7. Once the PR passes our extensive testing infrastructure, we'll merge it! +8. Celebrate :tada: + +[1]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/test/builtins/Unit +[2]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/lib/builtins +[3]: https://github.com/rust-lang/compiler-builtins/actions + +### Porting Reminders + +1. [Rust][5a] and [C][5b] have slightly different operator precedence. C evaluates comparisons (`== !=`) before bitwise operations (`& | ^`), while Rust evaluates the other way. +2. C assumes wrapping operations everywhere. Rust panics on overflow when in debug mode. Consider using the [Wrapping][6] type or the explicit [wrapping_*][7] functions where applicable. +3. Note [C implicit casts][8], especially integer promotion. Rust is much more explicit about casting, so be sure that any cast which affects the output is ported to the Rust implementation. +4. Rust has [many functions][9] for integer or floating point manipulation in the standard library. Consider using one of these functions rather than porting a new one. + +[5a]: https://doc.rust-lang.org/reference/expressions.html#expression-precedence +[5b]: http://en.cppreference.com/w/c/language/operator_precedence +[6]: https://doc.rust-lang.org/core/num/struct.Wrapping.html +[7]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_add +[8]: http://en.cppreference.com/w/cpp/language/implicit_conversion +[9]: https://doc.rust-lang.org/std/primitive.i32.html + +## Testing + +The easiest way to test locally is using Docker. This can be done by running +`./ci/run-docker.sh [target]`. If no target is specified, all targets will be +run. + +In order to run the full test suite, you will also need the C compiler runtime +to test against, located in a directory called `compiler-rt`. This can be +obtained with the following: + +```sh +curl -L -o rustc-llvm-20.1.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/20.1-2025-02-13.tar.gz +tar xzf rustc-llvm-20.1.tar.gz --strip-components 1 llvm-project-rustc-20.1-2025-02-13/compiler-rt +``` + +Local targets may also be tested with `./ci/run.sh [target]`. + +Note that testing may not work on all hosts, in which cases it is acceptable to +rely on CI. + +## Progress + +- [x] aarch64/chkstk.S +- [x] adddf3.c +- [x] addsf3.c +- [x] arm/addsf3.S +- [x] arm/aeabi_dcmp.S +- [x] arm/aeabi_fcmp.S +- [x] arm/aeabi_idivmod.S +- [x] arm/aeabi_ldivmod.S +- [x] arm/aeabi_memcpy.S +- [x] arm/aeabi_memmove.S +- [x] arm/aeabi_memset.S +- [x] arm/aeabi_uidivmod.S +- [x] arm/aeabi_uldivmod.S +- [ ] arm/chkstk.S +- [ ] arm/divmodsi4.S (generic version is done) +- [ ] arm/divsi3.S (generic version is done) +- [ ] arm/modsi3.S (generic version is done) +- [x] arm/softfloat-alias.list +- [ ] arm/udivmodsi4.S (generic version is done) +- [ ] arm/udivsi3.S (generic version is done) +- [ ] arm/umodsi3.S (generic version is done) +- [x] ashldi3.c +- [x] ashrdi3.c +- [ ] avr/divmodhi4.S +- [ ] avr/divmodqi4.S +- [ ] avr/mulhi3.S +- [ ] avr/mulqi3.S +- [ ] avr/udivmodhi4.S +- [ ] avr/udivmodqi4.S +- [x] bswapdi2.c +- [x] bswapsi2.c +- [x] bswapti2.c +- [x] clzdi2.c +- [x] clzsi2.c +- [x] clzti2.c +- [x] comparedf2.c +- [x] comparesf2.c +- [x] ctzdi2.c +- [x] ctzsi2.c +- [x] ctzti2.c +- [x] divdf3.c +- [x] divdi3.c +- [x] divmoddi4.c +- [x] divmodsi4.c +- [x] divmodti4.c +- [x] divsf3.c +- [x] divsi3.c +- [x] extendsfdf2.c +- [x] fixdfdi.c +- [x] fixdfsi.c +- [x] fixsfdi.c +- [x] fixsfsi.c +- [x] fixunsdfdi.c +- [x] fixunsdfsi.c +- [x] fixunssfdi.c +- [x] fixunssfsi.c +- [x] floatdidf.c +- [x] floatdisf.c +- [x] floatsidf.c +- [x] floatsisf.c +- [x] floatundidf.c +- [x] floatundisf.c +- [x] floatunsidf.c +- [x] floatunsisf.c +- [ ] i386/ashldi3.S +- [ ] i386/ashrdi3.S +- [x] i386/chkstk.S +- [ ] i386/divdi3.S +- [ ] i386/lshrdi3.S +- [ ] i386/moddi3.S +- [ ] i386/muldi3.S +- [ ] i386/udivdi3.S +- [ ] i386/umoddi3.S +- [x] lshrdi3.c +- [x] moddi3.c +- [x] modsi3.c +- [x] muldf3.c +- [x] muldi3.c +- [x] mulodi4.c +- [x] mulosi4.c +- [x] mulsf3.c +- [x] powidf2.c +- [x] powisf2.c +- [ ] riscv/muldi3.S +- [ ] riscv/mulsi3.S +- [x] subdf3.c +- [x] subsf3.c +- [x] truncdfsf2.c +- [x] udivdi3.c +- [x] udivmoddi4.c +- [x] udivmodsi4.c +- [x] udivsi3.c +- [x] umoddi3.c +- [x] umodsi3.c +- [x] x86_64/chkstk.S + +These builtins are needed to support 128-bit integers. + +- [x] ashlti3.c +- [x] ashrti3.c +- [x] divti3.c +- [x] fixdfti.c +- [x] fixsfti.c +- [x] fixunsdfti.c +- [x] fixunssfti.c +- [x] floattidf.c +- [x] floattisf.c +- [x] floatuntidf.c +- [x] floatuntisf.c +- [x] lshrti3.c +- [x] modti3.c +- [x] muloti4.c +- [x] multi3.c +- [x] udivmodti4.c +- [x] udivti3.c +- [x] umodti3.c + +These builtins are needed to support `f16` and `f128`, which are in the process +of being added to Rust. + +- [x] addtf3.c +- [x] comparetf2.c +- [x] divtf3.c +- [x] extenddftf2.c +- [x] extendhfsf2.c +- [x] extendhftf2.c +- [x] extendsftf2.c +- [x] fixtfdi.c +- [x] fixtfsi.c +- [x] fixtfti.c +- [x] fixunstfdi.c +- [x] fixunstfsi.c +- [x] fixunstfti.c +- [x] floatditf.c +- [x] floatsitf.c +- [x] floattitf.c +- [x] floatunditf.c +- [x] floatunsitf.c +- [x] floatuntitf.c +- [x] multf3.c +- [x] powitf2.c +- [x] subtf3.c +- [x] truncdfhf2.c +- [x] truncsfhf2.c +- [x] trunctfdf2.c +- [x] trunctfhf2.c +- [x] trunctfsf2.c + + +These builtins are used by the Hexagon DSP + +- [ ] hexagon/common_entry_exit_abi1.S +- [ ] hexagon/common_entry_exit_abi2.S +- [ ] hexagon/common_entry_exit_legacy.S +- [x] hexagon/dfaddsub.S~~ +- [x] hexagon/dfdiv.S~~ +- [x] hexagon/dffma.S~~ +- [x] hexagon/dfminmax.S~~ +- [x] hexagon/dfmul.S~~ +- [x] hexagon/dfsqrt.S~~ +- [x] hexagon/divdi3.S~~ +- [x] hexagon/divsi3.S~~ +- [x] hexagon/fastmath2_dlib_asm.S~~ +- [x] hexagon/fastmath2_ldlib_asm.S~~ +- [x] hexagon/fastmath_dlib_asm.S~~ +- [x] hexagon/memcpy_forward_vp4cp4n2.S~~ +- [x] hexagon/memcpy_likely_aligned.S~~ +- [x] hexagon/moddi3.S~~ +- [x] hexagon/modsi3.S~~ +- [x] hexagon/sfdiv_opt.S~~ +- [x] hexagon/sfsqrt_opt.S~~ +- [x] hexagon/udivdi3.S~~ +- [x] hexagon/udivmoddi4.S~~ +- [x] hexagon/udivmodsi4.S~~ +- [x] hexagon/udivsi3.S~~ +- [x] hexagon/umoddi3.S~~ +- [x] hexagon/umodsi3.S~~ + +## Unimplemented functions + +These builtins are for x87 `f80` floating-point numbers that are not supported +by Rust. + +- ~~extendxftf2.c~~ +- ~~fixunsxfdi.c~~ +- ~~fixunsxfsi.c~~ +- ~~fixunsxfti.c~~ +- ~~fixxfdi.c~~ +- ~~fixxfti.c~~ +- ~~floatdixf.c~~ +- ~~floattixf.c~~ +- ~~floatundixf.c~~ +- ~~floatuntixf.c~~ +- ~~i386/floatdixf.S~~ +- ~~i386/floatundixf.S~~ +- ~~x86_64/floatdixf.c~~ +- ~~x86_64/floatundixf.S~~ + +These builtins are for IBM "extended double" non-IEEE 128-bit floating-point +numbers. + +- ~~ppc/divtc3.c~~ +- ~~ppc/fixtfdi.c~~ +- ~~ppc/fixtfti.c~~ +- ~~ppc/fixunstfdi.c~~ +- ~~ppc/fixunstfti.c~~ +- ~~ppc/floatditf.c~~ +- ~~ppc/floattitf.c~~ +- ~~ppc/floatunditf.c~~ +- ~~ppc/gcc_qadd.c~~ +- ~~ppc/gcc_qdiv.c~~ +- ~~ppc/gcc_qmul.c~~ +- ~~ppc/gcc_qsub.c~~ +- ~~ppc/multc3.c~~ + +These builtins are for 16-bit brain floating-point numbers that are not +supported by Rust. + +- ~~truncdfbf2.c~~ +- ~~truncsfbf2.c~~ +- ~~trunctfxf2.c~~ + +These builtins involve complex floating-point types that are not supported by +Rust. + +- ~~divdc3.c~~ +- ~~divsc3.c~~ +- ~~divtc3.c~~ +- ~~divxc3.c~~ +- ~~muldc3.c~~ +- ~~mulsc3.c~~ +- ~~multc3.c~~ +- ~~mulxc3.c~~ +- ~~powixf2.c~~ + +These builtins are never called by LLVM. + +- ~~absvdi2.c~~ +- ~~absvsi2.c~~ +- ~~absvti2.c~~ +- ~~addvdi3.c~~ +- ~~addvsi3.c~~ +- ~~addvti3.c~~ +- ~~arm/aeabi_cdcmp.S~~ +- ~~arm/aeabi_cdcmpeq_check_nan.c~~ +- ~~arm/aeabi_cfcmp.S~~ +- ~~arm/aeabi_cfcmpeq_check_nan.c~~ +- ~~arm/aeabi_div0.c~~ +- ~~arm/aeabi_drsub.c~~ +- ~~arm/aeabi_frsub.c~~ +- ~~arm/aeabi_memcmp.S~~ +- ~~arm/bswapdi2.S~~ +- ~~arm/bswapsi2.S~~ +- ~~arm/clzdi2.S~~ +- ~~arm/clzsi2.S~~ +- ~~arm/comparesf2.S~~ +- ~~arm/restore_vfp_d8_d15_regs.S~~ +- ~~arm/save_vfp_d8_d15_regs.S~~ +- ~~arm/switch16.S~~ +- ~~arm/switch32.S~~ +- ~~arm/switch8.S~~ +- ~~arm/switchu8.S~~ +- ~~cmpdi2.c~~ +- ~~cmpti2.c~~ +- ~~ffssi2.c~~ +- ~~ffsdi2.c~~ - this is [called by gcc][jemalloc-fail] though! +- ~~ffsti2.c~~ +- ~~mulvdi3.c~~ +- ~~mulvsi3.c~~ +- ~~mulvti3.c~~ +- ~~negdf2.c~~ +- ~~negdi2.c~~ +- ~~negsf2.c~~ +- ~~negti2.c~~ +- ~~negvdi2.c~~ +- ~~negvsi2.c~~ +- ~~negvti2.c~~ +- ~~paritydi2.c~~ +- ~~paritysi2.c~~ +- ~~parityti2.c~~ +- ~~popcountdi2.c~~ +- ~~popcountsi2.c~~ +- ~~popcountti2.c~~ +- ~~ppc/restFP.S~~ +- ~~ppc/saveFP.S~~ +- ~~subvdi3.c~~ +- ~~subvsi3.c~~ +- ~~subvti3.c~~ +- ~~ucmpdi2.c~~ +- ~~ucmpti2.c~~ +- ~~udivmodti4.c~~ + +[jemalloc-fail]: https://travis-ci.org/rust-lang/rust/jobs/249772758 + +Rust only exposes atomic types on platforms that support them, and therefore does not need to fall back to software implementations. + +- ~~arm/sync_fetch_and_add_4.S~~ +- ~~arm/sync_fetch_and_add_8.S~~ +- ~~arm/sync_fetch_and_and_4.S~~ +- ~~arm/sync_fetch_and_and_8.S~~ +- ~~arm/sync_fetch_and_max_4.S~~ +- ~~arm/sync_fetch_and_max_8.S~~ +- ~~arm/sync_fetch_and_min_4.S~~ +- ~~arm/sync_fetch_and_min_8.S~~ +- ~~arm/sync_fetch_and_nand_4.S~~ +- ~~arm/sync_fetch_and_nand_8.S~~ +- ~~arm/sync_fetch_and_or_4.S~~ +- ~~arm/sync_fetch_and_or_8.S~~ +- ~~arm/sync_fetch_and_sub_4.S~~ +- ~~arm/sync_fetch_and_sub_8.S~~ +- ~~arm/sync_fetch_and_umax_4.S~~ +- ~~arm/sync_fetch_and_umax_8.S~~ +- ~~arm/sync_fetch_and_umin_4.S~~ +- ~~arm/sync_fetch_and_umin_8.S~~ +- ~~arm/sync_fetch_and_xor_4.S~~ +- ~~arm/sync_fetch_and_xor_8.S~~ +- ~~arm/sync_synchronize.S~~ +- ~~atomic.c~~ +- ~~atomic_flag_clear.c~~ +- ~~atomic_flag_clear_explicit.c~~ +- ~~atomic_flag_test_and_set.c~~ +- ~~atomic_flag_test_and_set_explicit.c~~ +- ~~atomic_signal_fence.c~~ +- ~~atomic_thread_fence.c~~ + +Miscellaneous functionality that is not used by Rust. + +- ~~aarch64/fp_mode.c~~ +- ~~aarch64/lse.S~~ (LSE atomics) +- ~~aarch64/sme-abi-init.c~~ (matrix extension) +- ~~aarch64/sme-abi.S~~ (matrix extension) +- ~~aarch64/sme-libc-routines.c~~ (matrix extension) +- ~~apple_versioning.c~~ +- ~~arm/fp_mode.c~~ +- ~~avr/exit.S~~ +- ~~clear_cache.c~~ +- ~~cpu_model/aarch64.c~~ +- ~~cpu_model/x86.c~~ +- ~~crtbegin.c~~ +- ~~crtend.c~~ +- ~~emutls.c~~ +- ~~enable_execute_stack.c~~ +- ~~eprintf.c~~ +- ~~fp_mode.c~~ (float exception handling) +- ~~gcc_personality_v0.c~~ +- ~~i386/fp_mode.c~~ +- ~~int_util.c~~ +- ~~loongarch/fp_mode.c~~ +- ~~os_version_check.c~~ +- ~~riscv/fp_mode.c~~ +- ~~riscv/restore.S~~ (callee-saved registers) +- ~~riscv/save.S~~ (callee-saved registers) +- ~~trampoline_setup.c~~ +- ~~ve/grow_stack.S~~ +- ~~ve/grow_stack_align.S~~ + +Floating-point implementations of builtins that are only called from soft-float code. It would be better to simply use the generic soft-float versions in this case. + +- ~~i386/floatdidf.S~~ +- ~~i386/floatdisf.S~~ +- ~~i386/floatundidf.S~~ +- ~~i386/floatundisf.S~~ +- ~~x86_64/floatundidf.S~~ +- ~~x86_64/floatundisf.S~~ +- ~~x86_64/floatdidf.c~~ +- ~~x86_64/floatdisf.c~~ + +Unsupported in any current target: used on old versions of 32-bit iOS with ARMv5. + +- ~~arm/adddf3vfp.S~~ +- ~~arm/addsf3vfp.S~~ +- ~~arm/divdf3vfp.S~~ +- ~~arm/divsf3vfp.S~~ +- ~~arm/eqdf2vfp.S~~ +- ~~arm/eqsf2vfp.S~~ +- ~~arm/extendsfdf2vfp.S~~ +- ~~arm/fixdfsivfp.S~~ +- ~~arm/fixsfsivfp.S~~ +- ~~arm/fixunsdfsivfp.S~~ +- ~~arm/fixunssfsivfp.S~~ +- ~~arm/floatsidfvfp.S~~ +- ~~arm/floatsisfvfp.S~~ +- ~~arm/floatunssidfvfp.S~~ +- ~~arm/floatunssisfvfp.S~~ +- ~~arm/gedf2vfp.S~~ +- ~~arm/gesf2vfp.S~~ +- ~~arm/gtdf2vfp.S~~ +- ~~arm/gtsf2vfp.S~~ +- ~~arm/ledf2vfp.S~~ +- ~~arm/lesf2vfp.S~~ +- ~~arm/ltdf2vfp.S~~ +- ~~arm/ltsf2vfp.S~~ +- ~~arm/muldf3vfp.S~~ +- ~~arm/mulsf3vfp.S~~ +- ~~arm/nedf2vfp.S~~ +- ~~arm/negdf2vfp.S~~ +- ~~arm/negsf2vfp.S~~ +- ~~arm/nesf2vfp.S~~ +- ~~arm/subdf3vfp.S~~ +- ~~arm/subsf3vfp.S~~ +- ~~arm/truncdfsf2vfp.S~~ +- ~~arm/unorddf2vfp.S~~ +- ~~arm/unordsf2vfp.S~~ + +## License + +The compiler-builtins crate is dual licensed under both the University of +Illinois "BSD-Like" license and the MIT license. As a user of this code you may +choose to use it under either license. As a contributor, you agree to allow +your code to be used under both. + +Full text of the relevant licenses is in LICENSE.TXT. diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md deleted file mode 100644 index dc40060357c..00000000000 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ /dev/null @@ -1,82 +0,0 @@ -# How to contribute - -- Pick your favorite math function from the [issue tracker]. -- Look for the C implementation of the function in the [MUSL source code][src]. -- Copy paste the C code into a Rust file in the `src/math` directory and adjust - `src/math/mod.rs` accordingly. Also, uncomment the corresponding trait method - in `src/lib.rs`. -- Write some simple tests in your module (using `#[test]`) -- Run `cargo test` to make sure it works. Full tests are only run when enabling - features, see [Testing](#testing) below. -- Send us a pull request! Make sure to run `cargo fmt` on your code before - sending the PR. Also include "closes #42" in the PR description to close the - corresponding issue. -- :tada: - -[issue tracker]: https://github.com/rust-lang/libm/issues -[src]: https://git.musl-libc.org/cgit/musl/tree/src/math -[`src/math/truncf.rs`]: https://github.com/rust-lang/libm/blob/master/src/math/truncf.rs - -Check [PR #65] for an example. - -[PR #65]: https://github.com/rust-lang/libm/pull/65 - -## Tips and tricks - -- *IMPORTANT* The code in this crate will end up being used in the `core` crate so it can **not** - have any external dependencies (other than `core` itself). - -- Only use relative imports within the `math` directory / module, e.g. `use self::fabs::fabs` or -`use super::k_cos`. Absolute imports from core are OK, e.g. `use core::u64`. - -- To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the - `GET_FLOAT_WORD` macro, or a union, to do this operation. - -- To reinterpret an integer as a float use the `f32::from_bits` constructor. The MUSL code uses the - `SET_FLOAT_WORD` macro, or a union, to do this operation. - -- You may use other methods from core like `f64::is_nan`, etc. as appropriate. - -- If you're implementing one of the private double-underscore functions, take a look at the - "source" name in the comment at the top for an idea for alternate naming. For example, `__sin` - was renamed to `k_sin` after the FreeBSD source code naming. Do `use` these private functions in - `mod.rs`. - -- You may encounter weird literals like `0x1p127f` in the MUSL code. These are hexadecimal floating - point literals. Rust (the language) doesn't support these kind of literals. This crate provides - two macros, `hf32!` and `hf64!`, which convert string literals to floats at compile time. - - ```rust - assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000); - assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000); - ``` - -- Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`] - newtype to avoid this problem, or individual methods like [`wrapping_add`]. - -[`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html -[`wrapping_add`]: https://doc.rust-lang.org/std/primitive.u32.html#method.wrapping_add - -## Testing - -Normal tests can be executed with: - -```sh -# Tests against musl require that the submodule is up to date. -git submodule init -git submodule update - -# `--release` ables more test cases -cargo test --release -``` - -If you are on a system that cannot build musl or MPFR, passing -`--no-default-features` will run some limited tests. - -The multiprecision tests use the [`rug`] crate for bindings to MPFR. MPFR can -be difficult to build on non-Unix systems, refer to [`gmp_mpfr_sys`] for help. - -`build-musl` does not build with MSVC, Wasm, or Thumb. - -[`rug`]: https://docs.rs/rug/latest/rug/ -[`gmp_mpfr_sys`]: https://docs.rs/gmp-mpfr-sys/1.6.4/gmp_mpfr_sys/ -- cgit 1.4.1-3-g733a5 From 94448a6ff6ac1d4af6892086ea1bc67518363e44 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Apr 2025 08:46:19 +0000 Subject: Update README and CONTRIBUTING for the new repository layout --- library/compiler-builtins/CONTRIBUTING.md | 189 +++++++++++++++------ library/compiler-builtins/README.md | 27 +++ .../compiler-builtins/compiler-builtins/Cargo.toml | 23 ++- .../compiler-builtins/compiler-builtins/README.md | 76 ++------- library/compiler-builtins/libm/Cargo.toml | 2 +- library/compiler-builtins/libm/README.md | 54 +++--- 6 files changed, 213 insertions(+), 158 deletions(-) create mode 100644 library/compiler-builtins/README.md diff --git a/library/compiler-builtins/CONTRIBUTING.md b/library/compiler-builtins/CONTRIBUTING.md index dc40060357c..9f67cfc3157 100644 --- a/library/compiler-builtins/CONTRIBUTING.md +++ b/library/compiler-builtins/CONTRIBUTING.md @@ -1,68 +1,115 @@ # How to contribute -- Pick your favorite math function from the [issue tracker]. -- Look for the C implementation of the function in the [MUSL source code][src]. -- Copy paste the C code into a Rust file in the `src/math` directory and adjust - `src/math/mod.rs` accordingly. Also, uncomment the corresponding trait method - in `src/lib.rs`. -- Write some simple tests in your module (using `#[test]`) -- Run `cargo test` to make sure it works. Full tests are only run when enabling - features, see [Testing](#testing) below. -- Send us a pull request! Make sure to run `cargo fmt` on your code before - sending the PR. Also include "closes #42" in the PR description to close the - corresponding issue. -- :tada: - -[issue tracker]: https://github.com/rust-lang/libm/issues -[src]: https://git.musl-libc.org/cgit/musl/tree/src/math -[`src/math/truncf.rs`]: https://github.com/rust-lang/libm/blob/master/src/math/truncf.rs - -Check [PR #65] for an example. - -[PR #65]: https://github.com/rust-lang/libm/pull/65 +## compiler-builtins + +1. From the [pending list](compiler-builtins/README.md#progress), pick one or + more intrinsics. +2. Port the version from [`compiler-rt`] and, if applicable, their + [tests][rt-tests]. Note that this crate has generic implementations for a lot + of routines, which may be usable without porting the entire implementation. +3. Add a test to `builtins-test`, comparing the behavior of the ported + intrinsic(s) with their implementation on the testing host. +4. Add the intrinsic to `builtins-test-intrinsics/src/main.rs` to verify it can + be linked on all targets. +5. Send a Pull Request (PR) :tada:. + +[`compiler-rt`]: https://github.com/llvm/llvm-project/tree/b6820c35c59a4da3e59c11f657093ffbd79ae1db/compiler-rt/lib/builtins +[rt-tests]: https://github.com/llvm/llvm-project/tree/b6820c35c59a4da3e59c11f657093ffbd79ae1db/compiler-rt/test/builtins + +## Porting Reminders + +1. [Rust][prec-rust] and [C][prec-c] have slightly different operator + precedence. C evaluates comparisons (`== !=`) before bitwise operations + (`& | ^`), while Rust evaluates the other way. +2. C assumes wrapping operations everywhere. Rust panics on overflow when in + debug mode. Consider using the [Wrapping][wrap-ty] type or the explicit + [wrapping_*][wrap-fn] functions where applicable. +3. Note [C implicit casts][casts], especially integer promotion. Rust is much + more explicit about casting, so be sure that any cast which affects the + output is ported to the Rust implementation. +4. Rust has [many functions][i32] for integer or floating point manipulation in + the standard library. Consider using one of these functions rather than + porting a new one. + +[prec-rust]: https://doc.rust-lang.org/reference/expressions.html#expression-precedence +[prec-c]: http://en.cppreference.com/w/c/language/operator_precedence +[wrap-ty]: https://doc.rust-lang.org/core/num/struct.Wrapping.html +[wrap-fn]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_add +[casts]: http://en.cppreference.com/w/cpp/language/implicit_conversion +[i32]: https://doc.rust-lang.org/std/primitive.i32.html ## Tips and tricks -- *IMPORTANT* The code in this crate will end up being used in the `core` crate so it can **not** - have any external dependencies (other than `core` itself). - -- Only use relative imports within the `math` directory / module, e.g. `use self::fabs::fabs` or -`use super::k_cos`. Absolute imports from core are OK, e.g. `use core::u64`. - -- To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the - `GET_FLOAT_WORD` macro, or a union, to do this operation. - -- To reinterpret an integer as a float use the `f32::from_bits` constructor. The MUSL code uses the - `SET_FLOAT_WORD` macro, or a union, to do this operation. - +- _IMPORTANT_ The code in this crate will end up being used in the `core` crate + so it can **not** have any external dependencies (other than a subset of + `core` itself). +- Only use relative imports within the `math` directory / module, e.g. + `use self::fabs::fabs` or `use super::k_cos`. Absolute imports from core are + OK, e.g. `use core::u64`. +- To reinterpret a float as an integer use the `to_bits` method. The MUSL code + uses the `GET_FLOAT_WORD` macro, or a union, to do this operation. +- To reinterpret an integer as a float use the `f32::from_bits` constructor. The + MUSL code uses the `SET_FLOAT_WORD` macro, or a union, to do this operation. - You may use other methods from core like `f64::is_nan`, etc. as appropriate. - -- If you're implementing one of the private double-underscore functions, take a look at the - "source" name in the comment at the top for an idea for alternate naming. For example, `__sin` - was renamed to `k_sin` after the FreeBSD source code naming. Do `use` these private functions in - `mod.rs`. - -- You may encounter weird literals like `0x1p127f` in the MUSL code. These are hexadecimal floating - point literals. Rust (the language) doesn't support these kind of literals. This crate provides - two macros, `hf32!` and `hf64!`, which convert string literals to floats at compile time. +- Rust does not have hex float literals. This crate provides two `hf16!`, + `hf32!`, `hf64!`, and `hf128!` which convert string literals to floats at + compile time. ```rust assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000); assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000); ``` -- Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`] - newtype to avoid this problem, or individual methods like [`wrapping_add`]. +- Rust code panics on arithmetic overflows when not optimized. You may need to + use the [`Wrapping`] newtype to avoid this problem, or individual methods like + [`wrapping_add`]. [`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html [`wrapping_add`]: https://doc.rust-lang.org/std/primitive.u32.html#method.wrapping_add ## Testing -Normal tests can be executed with: +Testing for these crates can be somewhat complex, so feel free to rely on CI. + +The easiest way replicate CI testing is using Docker. This can be done by +running `./ci/run-docker.sh [target]`. If no target is specified, all targets +will be run. + +Tests can also be run without Docker: ```sh -# Tests against musl require that the submodule is up to date. +# Run basic tests +# +# --no-default-features always needs to be passed, an unfortunate limitation +# since the `#![compiler_builtins]` feature is enabled by default. +cargo test --workspace --no-default-features + +# Test with all interesting features +cargo test --workspace --no-default-features \ + --features arch,unstable-float,unstable-intrinsics,mem + +# Run with more detailed tests for libm +cargo test --workspace --no-default-features \ + --features arch,unstable-float,unstable-intrinsics,mem \ + --features build-mpfr,build-musl \ + --profile release-checked +``` + +The multiprecision tests use the [`rug`] crate for bindings to MPFR. MPFR can be +difficult to build on non-Unix systems, refer to [`gmp_mpfr_sys`] for help. + +`build-musl` does not build with MSVC, Wasm, or Thumb. + +[`rug`]: https://docs.rs/rug/latest/rug/ +[`gmp_mpfr_sys`]: https://docs.rs/gmp-mpfr-sys/1.6.4/gmp_mpfr_sys/ + +In order to run all tests, some dependencies may be required: + +```sh +# Allow testing compiler-builtins +./ci/download-compiler-rt.sh + +# Optional, initialize musl for `--features build-musl` git submodule init git submodule update @@ -70,13 +117,51 @@ git submodule update cargo test --release ``` -If you are on a system that cannot build musl or MPFR, passing -`--no-default-features` will run some limited tests. +### Extensive tests -The multiprecision tests use the [`rug`] crate for bindings to MPFR. MPFR can -be difficult to build on non-Unix systems, refer to [`gmp_mpfr_sys`] for help. +Libm also has tests that are exhaustive (for single-argument `f32` and 1- or 2- +argument `f16`) or extensive (for all other float and argument combinations). +These take quite a long time to run, but are launched in CI when relevant files +are changed. -`build-musl` does not build with MSVC, Wasm, or Thumb. +Exhaustive tests can be selected by passing an environment variable: -[`rug`]: https://docs.rs/rug/latest/rug/ -[`gmp_mpfr_sys`]: https://docs.rs/gmp-mpfr-sys/1.6.4/gmp_mpfr_sys/ +```sh +LIBM_EXTENSIVE_TESTS=sqrt,sqrtf cargo test --features build-mpfr \ + --test z_extensive \ + --profile release-checked + +# Run all tests for one type +LIBM_EXTENSIVE_TESTS=all_f16 cargo test ... + +# Ensure `f64` tests can run exhaustively. Estimated completion test for a +# single test is 57306 years on my machine so this may be worth skipping. +LIBM_EXTENSIVE_TESTS=all LIBM_EXTENSIVE_ITERATIONS=18446744073709551615 cargo test ... +``` + +## Benchmarking + +Regular walltime benchmarks can be run with `cargo bench`: + +```sh +cargo bench --no-default-features \ + --features arch,unstable-float,unstable-intrinsics,mem \ + --features benchmarking-reports +``` + +There are also benchmarks that check instruction count behind the `icount` +feature. These require [`iai-callgrind-runner`] (via Cargo) and [Valgrind] +to be installed, which means these only run on limited platforms. + +Instruction count benchmarks are run as part of CI to flag performance +regresions. + +```sh +cargo bench --no-default-features \ + --features arch,unstable-float,unstable-intrinsics,mem \ + --features icount \ + --bench icount --bench mem_icount +``` + +[`iai-callgrind-runner`]: https://crates.io/crates/iai-callgrind-runner +[Valgrind]: https://valgrind.org/ diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md new file mode 100644 index 00000000000..3130ff7b77d --- /dev/null +++ b/library/compiler-builtins/README.md @@ -0,0 +1,27 @@ +# `compiler-builtins` and `libm` + +This repository contains two main crates: + +* `compiler-builtins`: symbols that the compiler expects to be available at + link time +* `libm`: a Rust implementation of C math libraries, used to provide + implementations in `ocre`. + +More details are at [compiler-builtins/README.md](compiler-builtins/README.md) +and [libm/README.md](libm/README.md). + +For instructions on contributing, see [CONTRIBUTING.md](CONTRIBUTING.md). + +## License + +* `libm` may be used under the [MIT License] +* `compiler-builtins` may be used under the [MIT License] and the + [Apache License, Version 2.0] with the LLVM exception. +* All original contributions must be under all of: the MIT license, the + Apache-2.0 license, and the Apache-2.0 license with the LLVM exception. + +More details are in [LICENSE.txt](LICENSE.txt) and +[libm/LICENSE.txt](libm/LICENSE.txt). + +[MIT License]: https://opensource.org/license/mit +[Apache License, Version 2.0]: htps://www.apache.org/licenses/LICENSE-2.0 diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index e2a6c0a74bd..9e23c75a826 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -3,24 +3,21 @@ authors = ["Jorge Aparicio "] name = "compiler_builtins" version = "0.1.155" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" -readme = "../README.md" +readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" homepage = "https://github.com/rust-lang/compiler-builtins" documentation = "https://docs.rs/compiler_builtins" edition = "2021" -description = """ -Compiler intrinsics used by the Rust compiler. Also available for other targets -if necessary! -""" +description = "Compiler intrinsics used by the Rust compiler." include = [ - '/Cargo.toml', - '/build.rs', - '/configure.rs', - '/src/*', - '../LICENSE.txt', - '../compiler-rt/*', - 'README.md', - 'libm/src/math/*', + "../LICENSE.txt", + "../compiler-rt/*", + "/Cargo.toml", + "/build.rs", + "/configure.rs", + "/src/*", + "README.md", + "libm/src/math/*", ] links = 'compiler-rt' diff --git a/library/compiler-builtins/compiler-builtins/README.md b/library/compiler-builtins/compiler-builtins/README.md index e5350d58c3e..387b70c0499 100644 --- a/library/compiler-builtins/compiler-builtins/README.md +++ b/library/compiler-builtins/compiler-builtins/README.md @@ -1,64 +1,18 @@ # `compiler-builtins` -This crate provides external symbols that the compiler expects to be available when -building Rust projects, typically software routines for basic operations that do not -have hardware support. It is largely a port of LLVM's [`compiler-rt`]. +This crate provides external symbols that the compiler expects to be available +when building Rust projects, typically software routines for basic operations +that do not have hardware support. It is largely a port of LLVM's +[`compiler-rt`]. -It is distributed as part of Rust's sysroot. +It is distributed as part of Rust's sysroot. `compiler-builtins` does not need +to be added as an explicit dependency in `Cargo.toml`. [`compiler-rt`]: https://github.com/llvm/llvm-project/tree/1b1dc505057322f4fa1110ef4f53c44347f52986/compiler-rt ## Contributing -1. Pick one or more intrinsics from the [pending list](#progress). -2. Fork this repository. -3. Port the intrinsic(s) and their corresponding [unit tests][1] from their - [C implementation][2] to Rust. -4. Add a test to compare the behavior of the ported intrinsic(s) with their - implementation on the testing host. -5. Add the intrinsic to `builtins-test-intrinsics/src/main.rs` to verify it - can be linked on all targets. -6. Send a Pull Request (PR). -7. Once the PR passes our extensive testing infrastructure, we'll merge it! -8. Celebrate :tada: - -[1]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/test/builtins/Unit -[2]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/lib/builtins -[3]: https://github.com/rust-lang/compiler-builtins/actions - -### Porting Reminders - -1. [Rust][5a] and [C][5b] have slightly different operator precedence. C evaluates comparisons (`== !=`) before bitwise operations (`& | ^`), while Rust evaluates the other way. -2. C assumes wrapping operations everywhere. Rust panics on overflow when in debug mode. Consider using the [Wrapping][6] type or the explicit [wrapping_*][7] functions where applicable. -3. Note [C implicit casts][8], especially integer promotion. Rust is much more explicit about casting, so be sure that any cast which affects the output is ported to the Rust implementation. -4. Rust has [many functions][9] for integer or floating point manipulation in the standard library. Consider using one of these functions rather than porting a new one. - -[5a]: https://doc.rust-lang.org/reference/expressions.html#expression-precedence -[5b]: http://en.cppreference.com/w/c/language/operator_precedence -[6]: https://doc.rust-lang.org/core/num/struct.Wrapping.html -[7]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_add -[8]: http://en.cppreference.com/w/cpp/language/implicit_conversion -[9]: https://doc.rust-lang.org/std/primitive.i32.html - -## Testing - -The easiest way to test locally is using Docker. This can be done by running -`./ci/run-docker.sh [target]`. If no target is specified, all targets will be -run. - -In order to run the full test suite, you will also need the C compiler runtime -to test against, located in a directory called `compiler-rt`. This can be -obtained with the following: - -```sh -curl -L -o rustc-llvm-20.1.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/20.1-2025-02-13.tar.gz -tar xzf rustc-llvm-20.1.tar.gz --strip-components 1 llvm-project-rustc-20.1-2025-02-13/compiler-rt -``` - -Local targets may also be tested with `./ci/run.sh [target]`. - -Note that testing may not work on all hosts, in which cases it is acceptable to -rely on CI. +See [CONTRIBUTING.md](CONTRIBUTING.md). ## Progress @@ -468,9 +422,15 @@ Unsupported in any current target: used on old versions of 32-bit iOS with ARMv5 ## License -The compiler-builtins crate is dual licensed under both the University of -Illinois "BSD-Like" license and the MIT license. As a user of this code you may -choose to use it under either license. As a contributor, you agree to allow -your code to be used under both. +Usage is allowed under the [MIT License] and the [Apache License, Version 2.0] +with the LLVM exception. + +[MIT License]: https://opensource.org/license/mit +[Apache License, Version 2.0]: htps://www.apache.org/licenses/LICENSE-2.0 + +### Contribution + +Contributions are licensed under the MIT License, the Apache License, +Version 2.0, and the Apache-2.0 license with the LLVM exception. -Full text of the relevant licenses is in LICENSE.TXT. +See [LICENSE.txt](../LICENSE.txt) for full details. diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 44154c1a8f5..4e3850bbff0 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["libm", "math"] license = "MIT" name = "libm" readme = "README.md" -repository = "https://github.com/rust-lang/libm" +repository = "https://github.com/rust-lang/compiler-builtins" version = "0.2.11" edition = "2021" rust-version = "1.63" diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 52d760a4f15..349e892dfcf 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -1,38 +1,26 @@ # `libm` -A port of [MUSL]'s libm to Rust. +A Rust implementations of the C math library. -[MUSL]: https://musl.libc.org/ +## Usage -## Goals +`libm` provides fallback implementations for Rust's [float math functions] in +`core`, and the [`core_float_math`] feature. If what is available suits your +needs, there is no need to add `libm` as a dependency. -The short term goal of this library is to [enable math support (e.g. `sin`, `atan2`) for the -`wasm32-unknown-unknown` target][wasm] (cf. [rust-lang/compiler-builtins][pr]). The longer -term goal is to enable [math support in the `core` crate][core]. +If more functionality is needed, this crate can also be used directly: -[wasm]: https://github.com/rust-lang/libm/milestone/1 -[pr]: https://github.com/rust-lang/compiler-builtins/pull/248 -[core]: https://github.com/rust-lang/libm/milestone/2 +```toml +[dependencies] +libm = "0.2.11" +``` -## Already usable - -This crate is [on crates.io] and can be used today in stable `#![no_std]` programs. - -The API documentation can be found [here](https://docs.rs/libm). - -[on crates.io]: https://crates.io/crates/libm - -## Benchmark -[benchmark]: #benchmark - -The benchmarks are located in `crates/libm-bench` and require a nightly Rust toolchain. -To run all benchmarks: - -> cargo +nightly bench --all +[float math functions]: https://doc.rust-lang.org/std/primitive.f32.html +[`core_float_math`]: https://github.com/rust-lang/rust/issues/137578 ## Contributing -Please check [CONTRIBUTING.md](CONTRIBUTING.md) +Please check [CONTRIBUTING.md](../CONTRIBUTING.md) ## Minimum Rust version policy @@ -40,17 +28,15 @@ This crate supports rustc 1.63 and newer. ## License -Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or -https://opensource.org/licenses/MIT). - +Usage is under the MIT license, available at +. ### Contribution Contributions are licensed under both the MIT license and the Apache License, -Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or -https://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state -otherwise, any contribution intentionally submitted for inclusion in the work -by you, as defined in the Apache-2.0 license, shall be dual licensed as -mentioned, without any additional terms or conditions. +Version 2.0, available at . Unless +you explicitly state otherwise, any contribution intentionally submitted for +inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as mentioned, without any additional terms or conditions. -See `LICENSE.txt` for full details. +See [LICENSE.txt](LICENSE.txt) for full details. -- cgit 1.4.1-3-g733a5 From 913796c1c5f7e0afa6c4323e8bd850efd7a646d9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Apr 2025 09:20:37 +0000 Subject: Fix compiler-builtins publish compiler-builtins currently wouldn't publish correctly because of a relative path to `libm` that doesn't get included in the package. Fix this by simlinking `libm` to within the `compiler-builtins` directory. Also symlink LICENSE.txt which lets us drop the `include` array in Cargo.toml. LICENSE.txt and compiler-rt were not being included anyway, since Cargo silently drops items that are not within the crate directory. --- .../compiler-builtins/compiler-builtins/Cargo.toml | 10 -- .../compiler-builtins/LICENSE.txt | 1 + .../compiler-builtins/compiler-builtins/src/lib.rs | 2 +- .../compiler-builtins/src/math.rs | 199 --------------------- .../compiler-builtins/src/math/libm_math | 1 + .../compiler-builtins/src/math/mod.rs | 198 ++++++++++++++++++++ 6 files changed, 201 insertions(+), 210 deletions(-) create mode 120000 library/compiler-builtins/compiler-builtins/LICENSE.txt delete mode 100644 library/compiler-builtins/compiler-builtins/src/math.rs create mode 120000 library/compiler-builtins/compiler-builtins/src/math/libm_math create mode 100644 library/compiler-builtins/compiler-builtins/src/math/mod.rs diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 9e23c75a826..1de37bd8683 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -9,16 +9,6 @@ homepage = "https://github.com/rust-lang/compiler-builtins" documentation = "https://docs.rs/compiler_builtins" edition = "2021" description = "Compiler intrinsics used by the Rust compiler." -include = [ - "../LICENSE.txt", - "../compiler-rt/*", - "/Cargo.toml", - "/build.rs", - "/configure.rs", - "/src/*", - "README.md", - "libm/src/math/*", -] links = 'compiler-rt' [lib] diff --git a/library/compiler-builtins/compiler-builtins/LICENSE.txt b/library/compiler-builtins/compiler-builtins/LICENSE.txt new file mode 120000 index 00000000000..4ab43736a83 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/LICENSE.txt @@ -0,0 +1 @@ +../LICENSE.txt \ No newline at end of file diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index 0678556037f..7523a00cf9b 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -45,7 +45,7 @@ pub mod math; pub mod mem; // `libm` expects its `support` module to be available in the crate root. -use math::libm::support; +use math::libm_math::support; #[cfg(target_arch = "arm")] pub mod arm; diff --git a/library/compiler-builtins/compiler-builtins/src/math.rs b/library/compiler-builtins/compiler-builtins/src/math.rs deleted file mode 100644 index 722374f8e4f..00000000000 --- a/library/compiler-builtins/compiler-builtins/src/math.rs +++ /dev/null @@ -1,199 +0,0 @@ -#[rustfmt::skip] -#[allow(dead_code)] -#[allow(unused_imports)] -#[allow(clippy::all)] -#[path = "../../libm/src/math/mod.rs"] -pub(crate) mod libm; - -macro_rules! libm_intrinsics { - ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { - intrinsics! { - $( - pub extern "C" fn $fun($($iid: $ity),+) -> $oty { - $crate::math::libm::$fun($($iid),+) - } - )+ - } - } -} - -/// This set of functions is well tested in `libm` and known to provide similar performance to -/// system `libm`, as well as the same or better accuracy. -pub mod full_availability { - #[cfg(f16_enabled)] - libm_intrinsics! { - fn ceilf16(x: f16) -> f16; - fn copysignf16(x: f16, y: f16) -> f16; - fn fabsf16(x: f16) -> f16; - fn fdimf16(x: f16, y: f16) -> f16; - fn floorf16(x: f16) -> f16; - fn fmaxf16(x: f16, y: f16) -> f16; - fn fmaximumf16(x: f16, y: f16) -> f16; - fn fminf16(x: f16, y: f16) -> f16; - fn fminimumf16(x: f16, y: f16) -> f16; - fn fmodf16(x: f16, y: f16) -> f16; - fn rintf16(x: f16) -> f16; - fn roundevenf16(x: f16) -> f16; - fn roundf16(x: f16) -> f16; - fn sqrtf16(x: f16) -> f16; - fn truncf16(x: f16) -> f16; - } - - /* Weak linkage is unreliable on Windows and Apple, so we don't expose symbols that we know - * the system libc provides in order to avoid conflicts. */ - - #[cfg(all(not(windows), not(target_vendor = "apple")))] - libm_intrinsics! { - /* f32 */ - fn cbrtf(n: f32) -> f32; - fn ceilf(x: f32) -> f32; - fn copysignf(x: f32, y: f32) -> f32; - fn fabsf(x: f32) -> f32; - fn fdimf(a: f32, b: f32) -> f32; - fn floorf(x: f32) -> f32; - fn fmaf(x: f32, y: f32, z: f32) -> f32; - fn fmaxf(x: f32, y: f32) -> f32; - fn fminf(x: f32, y: f32) -> f32; - fn fmodf(x: f32, y: f32) -> f32; - fn rintf(x: f32) -> f32; - fn roundf(x: f32) -> f32; - fn sqrtf(x: f32) -> f32; - fn truncf(x: f32) -> f32; - - /* f64 */ - fn cbrt(x: f64) -> f64; - fn ceil(x: f64) -> f64; - fn copysign(x: f64, y: f64) -> f64; - fn fabs(x: f64) -> f64; - fn fdim(a: f64, b: f64) -> f64; - fn floor(x: f64) -> f64; - fn fma(x: f64, y: f64, z: f64) -> f64; - fn fmax(x: f64, y: f64) -> f64; - fn fmin(x: f64, y: f64) -> f64; - fn fmod(x: f64, y: f64) -> f64; - fn rint(x: f64) -> f64; - fn round(x: f64) -> f64; - fn sqrt(x: f64) -> f64; - fn trunc(x: f64) -> f64; - } - - // Windows and MacOS do not yet expose roundeven and IEEE 754-2019 `maximum` / `minimum`, - // however, so we still provide a fallback. - libm_intrinsics! { - fn fmaximum(x: f64, y: f64) -> f64; - fn fmaximumf(x: f32, y: f32) -> f32; - fn fminimum(x: f64, y: f64) -> f64; - fn fminimumf(x: f32, y: f32) -> f32; - fn roundeven(x: f64) -> f64; - fn roundevenf(x: f32) -> f32; - } - - #[cfg(f128_enabled)] - libm_intrinsics! { - fn ceilf128(x: f128) -> f128; - fn copysignf128(x: f128, y: f128) -> f128; - fn fabsf128(x: f128) -> f128; - fn fdimf128(x: f128, y: f128) -> f128; - fn floorf128(x: f128) -> f128; - fn fmaf128(x: f128, y: f128, z: f128) -> f128; - fn fmaxf128(x: f128, y: f128) -> f128; - fn fmaximumf128(x: f128, y: f128) -> f128; - fn fminf128(x: f128, y: f128) -> f128; - fn fminimumf128(x: f128, y: f128) -> f128; - fn fmodf128(x: f128, y: f128) -> f128; - fn rintf128(x: f128) -> f128; - fn roundevenf128(x: f128) -> f128; - fn roundf128(x: f128) -> f128; - fn sqrtf128(x: f128) -> f128; - fn truncf128(x: f128) -> f128; - } -} - -/// This group of functions has more performance or precision issues than system versions, or -/// are otherwise less well tested. Provide them only on platforms that have problems with the -/// system `libm`. -/// -/// As `libm` improves, more functions will be moved from this group to the first group. -/// -/// Do not supply for any of the following: -/// - x86 without sse2 due to ABI issues -/// - -/// - but exclude UEFI since it is a soft-float target -/// - -/// - All unix targets (linux, macos, freebsd, android, etc) -/// - wasm with known target_os -#[cfg(not(any( - all( - target_arch = "x86", - not(target_feature = "sse2"), - not(target_os = "uefi"), - ), - unix, - all(target_family = "wasm", not(target_os = "unknown")) -)))] -pub mod partial_availability { - #[cfg(not(windows))] - libm_intrinsics! { - fn acos(x: f64) -> f64; - fn acosf(n: f32) -> f32; - fn asin(x: f64) -> f64; - fn asinf(n: f32) -> f32; - fn atan(x: f64) -> f64; - fn atan2(x: f64, y: f64) -> f64; - fn atan2f(a: f32, b: f32) -> f32; - fn atanf(n: f32) -> f32; - fn cos(x: f64) -> f64; - fn cosf(x: f32) -> f32; - fn cosh(x: f64) -> f64; - fn coshf(n: f32) -> f32; - fn erf(x: f64) -> f64; - fn erfc(x: f64) -> f64; - fn erfcf(x: f32) -> f32; - fn erff(x: f32) -> f32; - fn exp(x: f64) -> f64; - fn exp2(x: f64) -> f64; - fn exp2f(x: f32) -> f32; - fn expf(x: f32) -> f32; - fn expm1(x: f64) -> f64; - fn expm1f(n: f32) -> f32; - fn hypot(x: f64, y: f64) -> f64; - fn hypotf(x: f32, y: f32) -> f32; - fn ldexp(f: f64, n: i32) -> f64; - fn ldexpf(f: f32, n: i32) -> f32; - fn log(x: f64) -> f64; - fn log10(x: f64) -> f64; - fn log10f(x: f32) -> f32; - fn log1p(x: f64) -> f64; - fn log1pf(n: f32) -> f32; - fn log2(x: f64) -> f64; - fn log2f(x: f32) -> f32; - fn logf(x: f32) -> f32; - fn pow(x: f64, y: f64) -> f64; - fn powf(x: f32, y: f32) -> f32; - fn sin(x: f64) -> f64; - fn sinf(x: f32) -> f32; - fn sinh(x: f64) -> f64; - fn sinhf(n: f32) -> f32; - fn tan(x: f64) -> f64; - fn tanf(n: f32) -> f32; - fn tanh(x: f64) -> f64; - fn tanhf(n: f32) -> f32; - fn tgamma(x: f64) -> f64; - fn tgammaf(x: f32) -> f32; - } - - // allow for windows (and other targets) - intrinsics! { - pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { - let r = super::libm::lgamma_r(x); - *s = r.1; - r.0 - } - - pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { - let r = super::libm::lgammaf_r(x); - *s = r.1; - r.0 - } - } -} diff --git a/library/compiler-builtins/compiler-builtins/src/math/libm_math b/library/compiler-builtins/compiler-builtins/src/math/libm_math new file mode 120000 index 00000000000..4d65313c232 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/math/libm_math @@ -0,0 +1 @@ +../../../libm/src/math \ No newline at end of file diff --git a/library/compiler-builtins/compiler-builtins/src/math/mod.rs b/library/compiler-builtins/compiler-builtins/src/math/mod.rs new file mode 100644 index 00000000000..078feb9ff9e --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/math/mod.rs @@ -0,0 +1,198 @@ +#[rustfmt::skip] +#[allow(dead_code)] +#[allow(unused_imports)] +#[allow(clippy::all)] +pub(crate) mod libm_math; + +macro_rules! libm_intrinsics { + ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { + intrinsics! { + $( + pub extern "C" fn $fun($($iid: $ity),+) -> $oty { + $crate::math::libm_math::$fun($($iid),+) + } + )+ + } + } +} + +/// This set of functions is well tested in `libm` and known to provide similar performance to +/// system `libm`, as well as the same or better accuracy. +pub mod full_availability { + #[cfg(f16_enabled)] + libm_intrinsics! { + fn ceilf16(x: f16) -> f16; + fn copysignf16(x: f16, y: f16) -> f16; + fn fabsf16(x: f16) -> f16; + fn fdimf16(x: f16, y: f16) -> f16; + fn floorf16(x: f16) -> f16; + fn fmaxf16(x: f16, y: f16) -> f16; + fn fmaximumf16(x: f16, y: f16) -> f16; + fn fminf16(x: f16, y: f16) -> f16; + fn fminimumf16(x: f16, y: f16) -> f16; + fn fmodf16(x: f16, y: f16) -> f16; + fn rintf16(x: f16) -> f16; + fn roundevenf16(x: f16) -> f16; + fn roundf16(x: f16) -> f16; + fn sqrtf16(x: f16) -> f16; + fn truncf16(x: f16) -> f16; + } + + /* Weak linkage is unreliable on Windows and Apple, so we don't expose symbols that we know + * the system libc provides in order to avoid conflicts. */ + + #[cfg(all(not(windows), not(target_vendor = "apple")))] + libm_intrinsics! { + /* f32 */ + fn cbrtf(n: f32) -> f32; + fn ceilf(x: f32) -> f32; + fn copysignf(x: f32, y: f32) -> f32; + fn fabsf(x: f32) -> f32; + fn fdimf(a: f32, b: f32) -> f32; + fn floorf(x: f32) -> f32; + fn fmaf(x: f32, y: f32, z: f32) -> f32; + fn fmaxf(x: f32, y: f32) -> f32; + fn fminf(x: f32, y: f32) -> f32; + fn fmodf(x: f32, y: f32) -> f32; + fn rintf(x: f32) -> f32; + fn roundf(x: f32) -> f32; + fn sqrtf(x: f32) -> f32; + fn truncf(x: f32) -> f32; + + /* f64 */ + fn cbrt(x: f64) -> f64; + fn ceil(x: f64) -> f64; + fn copysign(x: f64, y: f64) -> f64; + fn fabs(x: f64) -> f64; + fn fdim(a: f64, b: f64) -> f64; + fn floor(x: f64) -> f64; + fn fma(x: f64, y: f64, z: f64) -> f64; + fn fmax(x: f64, y: f64) -> f64; + fn fmin(x: f64, y: f64) -> f64; + fn fmod(x: f64, y: f64) -> f64; + fn rint(x: f64) -> f64; + fn round(x: f64) -> f64; + fn sqrt(x: f64) -> f64; + fn trunc(x: f64) -> f64; + } + + // Windows and MacOS do not yet expose roundeven and IEEE 754-2019 `maximum` / `minimum`, + // however, so we still provide a fallback. + libm_intrinsics! { + fn fmaximum(x: f64, y: f64) -> f64; + fn fmaximumf(x: f32, y: f32) -> f32; + fn fminimum(x: f64, y: f64) -> f64; + fn fminimumf(x: f32, y: f32) -> f32; + fn roundeven(x: f64) -> f64; + fn roundevenf(x: f32) -> f32; + } + + #[cfg(f128_enabled)] + libm_intrinsics! { + fn ceilf128(x: f128) -> f128; + fn copysignf128(x: f128, y: f128) -> f128; + fn fabsf128(x: f128) -> f128; + fn fdimf128(x: f128, y: f128) -> f128; + fn floorf128(x: f128) -> f128; + fn fmaf128(x: f128, y: f128, z: f128) -> f128; + fn fmaxf128(x: f128, y: f128) -> f128; + fn fmaximumf128(x: f128, y: f128) -> f128; + fn fminf128(x: f128, y: f128) -> f128; + fn fminimumf128(x: f128, y: f128) -> f128; + fn fmodf128(x: f128, y: f128) -> f128; + fn rintf128(x: f128) -> f128; + fn roundevenf128(x: f128) -> f128; + fn roundf128(x: f128) -> f128; + fn sqrtf128(x: f128) -> f128; + fn truncf128(x: f128) -> f128; + } +} + +/// This group of functions has more performance or precision issues than system versions, or +/// are otherwise less well tested. Provide them only on platforms that have problems with the +/// system `libm`. +/// +/// As `libm` improves, more functions will be moved from this group to the first group. +/// +/// Do not supply for any of the following: +/// - x86 without sse2 due to ABI issues +/// - +/// - but exclude UEFI since it is a soft-float target +/// - +/// - All unix targets (linux, macos, freebsd, android, etc) +/// - wasm with known target_os +#[cfg(not(any( + all( + target_arch = "x86", + not(target_feature = "sse2"), + not(target_os = "uefi"), + ), + unix, + all(target_family = "wasm", not(target_os = "unknown")) +)))] +pub mod partial_availability { + #[cfg(not(windows))] + libm_intrinsics! { + fn acos(x: f64) -> f64; + fn acosf(n: f32) -> f32; + fn asin(x: f64) -> f64; + fn asinf(n: f32) -> f32; + fn atan(x: f64) -> f64; + fn atan2(x: f64, y: f64) -> f64; + fn atan2f(a: f32, b: f32) -> f32; + fn atanf(n: f32) -> f32; + fn cos(x: f64) -> f64; + fn cosf(x: f32) -> f32; + fn cosh(x: f64) -> f64; + fn coshf(n: f32) -> f32; + fn erf(x: f64) -> f64; + fn erfc(x: f64) -> f64; + fn erfcf(x: f32) -> f32; + fn erff(x: f32) -> f32; + fn exp(x: f64) -> f64; + fn exp2(x: f64) -> f64; + fn exp2f(x: f32) -> f32; + fn expf(x: f32) -> f32; + fn expm1(x: f64) -> f64; + fn expm1f(n: f32) -> f32; + fn hypot(x: f64, y: f64) -> f64; + fn hypotf(x: f32, y: f32) -> f32; + fn ldexp(f: f64, n: i32) -> f64; + fn ldexpf(f: f32, n: i32) -> f32; + fn log(x: f64) -> f64; + fn log10(x: f64) -> f64; + fn log10f(x: f32) -> f32; + fn log1p(x: f64) -> f64; + fn log1pf(n: f32) -> f32; + fn log2(x: f64) -> f64; + fn log2f(x: f32) -> f32; + fn logf(x: f32) -> f32; + fn pow(x: f64, y: f64) -> f64; + fn powf(x: f32, y: f32) -> f32; + fn sin(x: f64) -> f64; + fn sinf(x: f32) -> f32; + fn sinh(x: f64) -> f64; + fn sinhf(n: f32) -> f32; + fn tan(x: f64) -> f64; + fn tanf(n: f32) -> f32; + fn tanh(x: f64) -> f64; + fn tanhf(n: f32) -> f32; + fn tgamma(x: f64) -> f64; + fn tgammaf(x: f32) -> f32; + } + + // allow for windows (and other targets) + intrinsics! { + pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { + let r = super::libm_math::lgamma_r(x); + *s = r.1; + r.0 + } + + pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { + let r = super::libm_math::lgammaf_r(x); + *s = r.1; + r.0 + } + } +} -- cgit 1.4.1-3-g733a5 From 13b94cf89f3e974fe697f80a5f2742ee4bccc05a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 02:23:44 +0000 Subject: ci: Fix extensive tests Move this to a script and ensure only `libm-test` gets built to avoid default feature issues with `compiler-builtins`. --- .../compiler-builtins/.github/workflows/main.yaml | 17 +-------------- library/compiler-builtins/ci/run-extensive.sh | 24 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 16 deletions(-) create mode 100755 library/compiler-builtins/ci/run-extensive.sh diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index f7522a53d9d..d13dd6b0f64 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -318,22 +318,7 @@ jobs: rustup default nightly - uses: Swatinem/rust-cache@v2 - name: Run extensive tests - run: | - echo "Tests to run: '$TO_TEST'" - if [ -z "$TO_TEST" ]; then - echo "No tests to run, exiting." - exit - fi - - set -x - - # Run the non-extensive tests first to catch any easy failures - cargo t --profile release-checked -- "$TO_TEST" - - LIBM_EXTENSIVE_TESTS="$TO_TEST" cargo test \ - --features build-mpfr,unstable,force-soft-floats \ - --profile release-checked \ - -- extensive + run: ./ci/run-extensive.sh - name: Print test logs if available run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi shell: bash diff --git a/library/compiler-builtins/ci/run-extensive.sh b/library/compiler-builtins/ci/run-extensive.sh new file mode 100755 index 00000000000..4ba41a026fa --- /dev/null +++ b/library/compiler-builtins/ci/run-extensive.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +set -euo pipefail + +echo "Tests to run: '$TO_TEST'" + +if [ -z "$TO_TEST" ]; then + echo "No tests to run, exiting." + exit +fi + +set -x + +test_cmd=( + cargo test + --package libm-test + --features "build-mpfr,libm/unstable,libm/force-soft-floats" + --profile release-checked +) + +# Run the non-extensive tests first to catch any easy failures +"${test_cmd[@]}" -- "$TO_TEST" + +LIBM_EXTENSIVE_TESTS="$TO_TEST" "${test_cmd[@]}" -- extensive -- cgit 1.4.1-3-g733a5 From a8652953e4741992865b626cfb10d676bc65b1cb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 03:10:38 +0000 Subject: Rename the `public-test-deps` feature to `unstable-public-internals` `compiler-builtins` uses `public-test-deps`, `libm` uses `unstable-public-internals`. Consolidate these under the `libm` name. Once compiler-builtins is no longer published, this feature can probably be dropped. Also switch to `dep:` syntax for features that enable dependencies. --- library/compiler-builtins/builtins-test/Cargo.toml | 2 +- library/compiler-builtins/compiler-builtins/Cargo.toml | 12 ++++++------ library/compiler-builtins/compiler-builtins/src/float/mod.rs | 4 ++-- .../compiler-builtins/src/int/leading_zeros.rs | 4 ++-- library/compiler-builtins/compiler-builtins/src/int/mod.rs | 4 ++-- .../compiler-builtins/src/int/specialized_div_rem/mod.rs | 4 ++-- .../compiler-builtins/src/int/trailing_zeros.rs | 4 ++-- library/compiler-builtins/compiler-builtins/src/int/udiv.rs | 4 ++-- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index f7bcb52b40f..10978c0bb7e 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -19,7 +19,7 @@ iai-callgrind = { version = "0.14.0", optional = true } [dependencies.compiler_builtins] path = "../compiler-builtins" default-features = false -features = ["public-test-deps"] +features = ["unstable-public-internals"] [dev-dependencies] criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 1de37bd8683..1ea32c10ce4 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/rust-lang/compiler-builtins" documentation = "https://docs.rs/compiler_builtins" edition = "2021" description = "Compiler intrinsics used by the Rust compiler." -links = 'compiler-rt' +links = "compiler-rt" [lib] bench = false @@ -19,20 +19,20 @@ test = false [dependencies] # For more information on this dependency see # https://github.com/rust-lang/rust/tree/master/library/rustc-std-workspace-core -core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } +core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } [build-dependencies] cc = { optional = true, version = "1.0" } [dev-dependencies] -panic-handler = { path = '../crates/panic-handler' } +panic-handler = { path = "../crates/panic-handler" } [features] default = ["compiler-builtins"] # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics -c = ["cc"] +c = ["dep:cc"] # Workaround for the Cranelift codegen backend. Disables any implementations # which use inline assembly and fall back to pure Rust versions (if avalible). @@ -53,11 +53,11 @@ mem = [] mangled-names = [] # Only used in the compiler's build system -rustc-dep-of-std = ['compiler-builtins', 'core'] +rustc-dep-of-std = ["compiler-builtins", "dep:core"] # This makes certain traits and function specializations public that # are not normally public but are required by the `builtins-test` -public-test-deps = [] +unstable-public-internals = [] [lints.rust] # The cygwin config can be dropped after our benchmark toolchain is bumped diff --git a/library/compiler-builtins/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/compiler-builtins/src/float/mod.rs index f2c543bd2b7..4a379d0d357 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/mod.rs @@ -9,7 +9,7 @@ pub mod sub; pub(crate) mod traits; pub mod trunc; -#[cfg(not(feature = "public-test-deps"))] +#[cfg(not(feature = "unstable-public-internals"))] pub(crate) use traits::{Float, HalfRep}; -#[cfg(feature = "public-test-deps")] +#[cfg(feature = "unstable-public-internals")] pub use traits::{Float, HalfRep}; diff --git a/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs index a57f881848d..112f4d03613 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs @@ -3,9 +3,9 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. -#[cfg(feature = "public-test-deps")] +#[cfg(feature = "unstable-public-internals")] pub use implementation::{leading_zeros_default, leading_zeros_riscv}; -#[cfg(not(feature = "public-test-deps"))] +#[cfg(not(feature = "unstable-public-internals"))] pub(crate) use implementation::{leading_zeros_default, leading_zeros_riscv}; mod implementation { diff --git a/library/compiler-builtins/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/compiler-builtins/src/int/mod.rs index 5633510d3c7..518ccb23f80 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/mod.rs @@ -12,7 +12,7 @@ mod traits; pub mod udiv; pub use big::{i256, u256}; -#[cfg(not(feature = "public-test-deps"))] +#[cfg(not(feature = "unstable-public-internals"))] pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -#[cfg(feature = "public-test-deps")] +#[cfg(feature = "unstable-public-internals")] pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; diff --git a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs index b81f0469813..43f466e75ba 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -56,9 +56,9 @@ mod delegate; // used on SPARC #[allow(unused_imports)] -#[cfg(not(feature = "public-test-deps"))] +#[cfg(not(feature = "unstable-public-internals"))] pub(crate) use self::delegate::u128_divide_sparc; -#[cfg(feature = "public-test-deps")] +#[cfg(feature = "unstable-public-internals")] pub use self::delegate::u128_divide_sparc; #[macro_use] diff --git a/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs index dbc0cce9fac..c45d6b1cfe8 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs @@ -1,6 +1,6 @@ -#[cfg(feature = "public-test-deps")] +#[cfg(feature = "unstable-public-internals")] pub use implementation::trailing_zeros; -#[cfg(not(feature = "public-test-deps"))] +#[cfg(not(feature = "unstable-public-internals"))] pub(crate) use implementation::trailing_zeros; mod implementation { diff --git a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs index 4e985ba4739..b9dee63c4cc 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs @@ -1,6 +1,6 @@ -#[cfg(not(feature = "public-test-deps"))] +#[cfg(not(feature = "unstable-public-internals"))] pub(crate) use crate::int::specialized_div_rem::*; -#[cfg(feature = "public-test-deps")] +#[cfg(feature = "unstable-public-internals")] pub use crate::int::specialized_div_rem::*; intrinsics! { -- cgit 1.4.1-3-g733a5 From e075e9fbde213c5fb0232c7a477f4f6dc199fc3d Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Tue, 22 Apr 2025 03:56:51 +0300 Subject: Reimplement the generic fmod --- library/compiler-builtins/libm/src/lib.rs | 1 + .../libm/src/math/generic/fmod.rs | 116 +++++++++------------ .../libm/src/math/support/int_traits.rs | 4 + 3 files changed, 55 insertions(+), 66 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 7df84fe1879..31b12235314 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -14,6 +14,7 @@ #![allow(clippy::excessive_precision)] #![allow(clippy::float_cmp)] #![allow(clippy::int_plus_one)] +#![allow(clippy::just_underscores_and_digits)] #![allow(clippy::many_single_char_names)] #![allow(clippy::mixed_case_hex_literals)] #![allow(clippy::needless_late_init)] diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs index 6414bbd2508..e9898012fcc 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmod.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs @@ -1,84 +1,68 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/fmod.c. Ported to generic Rust algorithm in 2025, TG. */ - +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ use super::super::{CastFrom, Float, Int, MinInt}; #[inline] pub fn fmod(x: F, y: F) -> F { - let zero = F::Int::ZERO; - let one = F::Int::ONE; - let mut ix = x.to_bits(); - let mut iy = y.to_bits(); - let mut ex = x.ex().signed(); - let mut ey = y.ex().signed(); - let sx = ix & F::SIGN_MASK; + let _1 = F::Int::ONE; + let sx = x.to_bits() & F::SIGN_MASK; + let ux = x.to_bits() & !F::SIGN_MASK; + let uy = y.to_bits() & !F::SIGN_MASK; - if iy << 1 == zero || y.is_nan() || ex == F::EXP_SAT as i32 { + // Cases that return NaN: + // NaN % _ + // Inf % _ + // _ % NaN + // _ % 0 + let x_nan_or_inf = ux & F::EXP_MASK == F::EXP_MASK; + let y_nan_or_zero = uy.wrapping_sub(_1) & F::EXP_MASK == F::EXP_MASK; + if x_nan_or_inf | y_nan_or_zero { return (x * y) / (x * y); } - if ix << 1 <= iy << 1 { - if ix << 1 == iy << 1 { - return F::ZERO * x; - } + if ux < uy { + // |x| < |y| return x; } - /* normalize x and y */ - if ex == 0 { - let i = ix << (F::EXP_BITS + 1); - ex -= i.leading_zeros() as i32; - ix <<= -ex + 1; - } else { - ix &= F::Int::MAX >> F::EXP_BITS; - ix |= one << F::SIG_BITS; - } - - if ey == 0 { - let i = iy << (F::EXP_BITS + 1); - ey -= i.leading_zeros() as i32; - iy <<= -ey + 1; - } else { - iy &= F::Int::MAX >> F::EXP_BITS; - iy |= one << F::SIG_BITS; - } - - /* x mod y */ - while ex > ey { - let i = ix.wrapping_sub(iy); - if i >> (F::BITS - 1) == zero { - if i == zero { - return F::ZERO * x; - } - ix = i; - } + let (num, ex) = into_sig_exp::(ux); + let (div, ey) = into_sig_exp::(uy); - ix <<= 1; - ex -= 1; - } + // To compute `(num << ex) % (div << ey)`, first + // evaluate `rem = (num << (ex - ey)) % div` ... + let rem = reduction(num, ex - ey, div); + // ... so the result will be `rem << ey` - let i = ix.wrapping_sub(iy); - if i >> (F::BITS - 1) == zero { - if i == zero { - return F::ZERO * x; - } + if rem.is_zero() { + // Return zero with the sign of `x` + return F::from_bits(sx); + }; - ix = i; - } + // We would shift `rem` up by `ey`, but have to stop at `F::SIG_BITS` + let shift = ey.min(F::SIG_BITS - rem.ilog2()); + // Anything past that is added to the exponent field + let bits = (rem << shift) + (F::Int::cast_from(ey - shift) << F::SIG_BITS); + F::from_bits(sx + bits) +} - let shift = ix.leading_zeros().saturating_sub(F::EXP_BITS); - ix <<= shift; - ex -= shift as i32; +/// Given the bits of a finite float, return a tuple of +/// - the mantissa with the implicit bit (0 if subnormal, 1 otherwise) +/// - the additional exponent past 1, (0 for subnormal, 0 or more otherwise) +fn into_sig_exp(mut bits: F::Int) -> (F::Int, u32) { + bits &= !F::SIGN_MASK; + // Subtract 1 from the exponent, clamping at 0 + let sat = bits.checked_sub(F::IMPLICIT_BIT).unwrap_or(F::Int::ZERO); + ( + bits - (sat & F::EXP_MASK), + u32::cast_from(sat >> F::SIG_BITS), + ) +} - /* scale result */ - if ex > 0 { - ix -= one << F::SIG_BITS; - ix |= F::Int::cast_from(ex) << F::SIG_BITS; - } else { - ix >>= -ex + 1; +/// Compute the remainder `(x * 2.pow(e)) % y` without overflow. +fn reduction(mut x: I, e: u32, y: I) -> I { + x %= y; + for _ in 0..e { + x <<= 1; + x = x.checked_sub(y).unwrap_or(x); } - - ix |= sx; - - F::from_bits(ix) + x } diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index 491adb1f22c..3ec1faba170 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -40,6 +40,9 @@ pub trait Int: + PartialOrd + ops::AddAssign + ops::SubAssign + + ops::MulAssign + + ops::DivAssign + + ops::RemAssign + ops::BitAndAssign + ops::BitOrAssign + ops::BitXorAssign @@ -51,6 +54,7 @@ pub trait Int: + ops::Sub + ops::Mul + ops::Div + + ops::Rem + ops::Shl + ops::Shl + ops::Shr -- cgit 1.4.1-3-g733a5 From 1fa9d0fce37a0349bc6eaec7f037b4fc88abd7d5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 21 Apr 2025 07:03:13 +0000 Subject: chore: release builtins 0.1.156 and libm 0.2.12 --- .../compiler-builtins/CHANGELOG.md | 12 ++++++++ .../compiler-builtins/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm/CHANGELOG.md | 36 ++++++++++++++++++++++ library/compiler-builtins/libm/Cargo.toml | 2 +- 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index 9916f2986e9..3450da99202 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.156](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.155...compiler_builtins-v0.1.156) - 2025-04-21 + +### Other + +- avr: Provide `abort()` +- Remove `unsafe` from `naked_asm!` blocks +- Enable icount benchmarks in CI +- Move builtins-test-intrinsics out of the workspace +- Run `cargo fmt` on all projects +- Flatten the `libm/libm` directory +- Update path to libm after the merge + ## [0.1.155](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.154...compiler_builtins-v0.1.155) - 2025-04-17 ### Other diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 1ea32c10ce4..acbace68729 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.155" +version = "0.1.156" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 4e5acb899d2..c507608ddbc 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -8,6 +8,42 @@ and this project adheres to ## [Unreleased] +## [0.2.12](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.11...libm-v0.2.12) - 2025-04-21 + +- Mark generic functions `#[inline]` +- Combine the source files for `fmod` +- Ensure all public functions are marked `no_panic` +- Add assembly version of simple operations on aarch64 +- Add `roundeven{,f,f16,f128}` +- Add `fminimum`, `fmaximum`, `fminimum_num`, and `fmaximum_num` +- Eliminate the use of `force_eval!` in `ceil`, `floor`, and `trunc` +- Port the CORE-MATH version of `cbrt` +- Add `fmaf128` +- fma: Ensure zero has the correct sign +- Add `scalbnf16`, `scalbnf128`, `ldexpf16`, and `ldexpf128` +- Specify license as just MIT +- Add `fmodf128` +- Add `fmodf16` using the generic implementation +- Add `fminf16`, `fmaxf16`, `fminf128`, and `fmaxf128` +- Add `roundf16` and `roundf128` +- Add `rintf16` and `rintf128` +- Add `floorf16` and `floorf128` +- Add `ceilf16` and `ceilf128` +- Add `sqrtf16` and `sqrtf128` +- Simplify and optimize `fdim` ([#442](https://github.com/rust-lang/libm/pull/442)) +- Add `fdimf16` and `fdimf128` +- Add `truncf16` and `truncf128` +- Add `fabsf16`, `fabsf128`, `copysignf16`, and `copysignf128` +- Move some numeric trait logic to default implementations +- Add some more basic docstrings ([#352](https://github.com/rust-lang/libm/pull/352)) +- Add support for loongarch64-unknown-linux-gnu +- Add an "arch" Cargo feature that is on by default +- Rename the `special_case` module to `precision` and move default ULP +- Move the existing "unstable" feature to "unstable-intrinsics" + +There are a number of things that changed internally, see the git log for a full +list of changes. + ## [0.2.11](https://github.com/rust-lang/libm/compare/libm-v0.2.10...libm-v0.2.11) - 2024-10-28 ### Fixed diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 4e3850bbff0..dc553ca4aaf 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -version = "0.2.11" +version = "0.2.12" edition = "2021" rust-version = "1.63" -- cgit 1.4.1-3-g733a5 From aec649faae092a09b17991499f142b50f348c91b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 03:43:35 +0000 Subject: chore: Combine CHANGELOG files for compiler-builtins This unintentionally got split when compiler-builtins was moved to a subdirectory. --- library/compiler-builtins/CHANGELOG.md | 108 --------------------- .../compiler-builtins/CHANGELOG.md | 100 +++++++++++++++++++ 2 files changed, 100 insertions(+), 108 deletions(-) delete mode 100644 library/compiler-builtins/CHANGELOG.md diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md deleted file mode 100644 index 763b0e10ed0..00000000000 --- a/library/compiler-builtins/CHANGELOG.md +++ /dev/null @@ -1,108 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] - -## [0.1.151](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.150...compiler_builtins-v0.1.151) - 2025-03-05 - -### Other - -- Add cygwin support -- Enable `f16` for LoongArch ([#770](https://github.com/rust-lang/compiler-builtins/pull/770)) -- Add __extendhfdf2 and add __truncdfhf2 test -- Remove outdated information from the readme - -## [0.1.150](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.149...compiler_builtins-v0.1.150) - 2025-03-01 - -### Other - -- Disable `f16` on AArch64 without the `neon` feature -- Update LLVM downloads to 20.1-2025-02-13 - -## [0.1.149](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.148...compiler_builtins-v0.1.149) - 2025-02-25 - -### Other - -- Make a subset of `libm` symbols weakly available on all platforms - -## [0.1.148](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.147...compiler_builtins-v0.1.148) - 2025-02-24 - -### Other - -- Update the `libm` submodule -- Enable `f16` for MIPS -- Eliminate the use of `public_test_dep!` for a third time - -## [0.1.147](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.146...compiler_builtins-v0.1.147) - 2025-02-19 - -### Other - -- remove win64_128bit_abi_hack - -## [0.1.146](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.145...compiler_builtins-v0.1.146) - 2025-02-06 - -### Other - -- Expose erf{,c}{,f} from libm - -## [0.1.145](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.144...compiler_builtins-v0.1.145) - 2025-02-04 - -### Other - -- Revert "Eliminate the use of `public_test_dep!`" -- Indentation fix to please clippy -- Don't build out of line atomics support code for uefi -- Add a version to some FIXMEs that will be resolved in LLVM 20 -- Remove use of the `start` feature - -## [0.1.144](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.143...compiler_builtins-v0.1.144) - 2025-01-15 - -### Other - -- Eliminate the use of `public_test_dep!` - -## [0.1.143](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.142...compiler_builtins-v0.1.143) - 2025-01-15 - -### Other - -- Use a C-safe return type for `__rust_[ui]128_*` overflowing intrinsics - -## [0.1.142](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.141...compiler_builtins-v0.1.142) - 2025-01-07 - -### Other - -- Account for optimization levels other than numbers - -## [0.1.141](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.140...compiler_builtins-v0.1.141) - 2025-01-07 - -### Other - -- Update the `libm` submodule -- Fix new `clippy::precedence` errors -- Rename `EXP_MAX` to `EXP_SAT` -- Shorten prefixes for float constants - -## [0.1.140](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.139...compiler_builtins-v0.1.140) - 2024-12-26 - -### Other - -- Disable f128 for amdgpu ([#737](https://github.com/rust-lang/compiler-builtins/pull/737)) -- Fix a bug in `abs_diff` -- Disable `f16` on platforms that have recursion problems - -## [0.1.139](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.138...compiler_builtins-v0.1.139) - 2024-11-03 - -### Other - -- Remove incorrect `sparcv9` match pattern from `configure_f16_f128` - -## [0.1.138](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.137...compiler_builtins-v0.1.138) - 2024-11-01 - -### Other - -- Use `f16_enabled`/`f128_enabled` in `examples/intrinsics.rs` ([#724](https://github.com/rust-lang/compiler-builtins/pull/724)) -- Disable `f16` for LoongArch64 ([#722](https://github.com/rust-lang/compiler-builtins/pull/722)) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index 3450da99202..34b413a8683 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -48,3 +48,103 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Remove use of `atomic_load_unordered` and undefined behaviour from `arm_linux.rs` - Switch repository layout to use a virtual manifest + +## [0.1.151](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.150...compiler_builtins-v0.1.151) - 2025-03-05 + +### Other + +- Add cygwin support +- Enable `f16` for LoongArch ([#770](https://github.com/rust-lang/compiler-builtins/pull/770)) +- Add __extendhfdf2 and add __truncdfhf2 test +- Remove outdated information from the readme + +## [0.1.150](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.149...compiler_builtins-v0.1.150) - 2025-03-01 + +### Other + +- Disable `f16` on AArch64 without the `neon` feature +- Update LLVM downloads to 20.1-2025-02-13 + +## [0.1.149](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.148...compiler_builtins-v0.1.149) - 2025-02-25 + +### Other + +- Make a subset of `libm` symbols weakly available on all platforms + +## [0.1.148](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.147...compiler_builtins-v0.1.148) - 2025-02-24 + +### Other + +- Update the `libm` submodule +- Enable `f16` for MIPS +- Eliminate the use of `public_test_dep!` for a third time + +## [0.1.147](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.146...compiler_builtins-v0.1.147) - 2025-02-19 + +### Other + +- remove win64_128bit_abi_hack + +## [0.1.146](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.145...compiler_builtins-v0.1.146) - 2025-02-06 + +### Other + +- Expose erf{,c}{,f} from libm + +## [0.1.145](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.144...compiler_builtins-v0.1.145) - 2025-02-04 + +### Other + +- Revert "Eliminate the use of `public_test_dep!`" +- Indentation fix to please clippy +- Don't build out of line atomics support code for uefi +- Add a version to some FIXMEs that will be resolved in LLVM 20 +- Remove use of the `start` feature + +## [0.1.144](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.143...compiler_builtins-v0.1.144) - 2025-01-15 + +### Other + +- Eliminate the use of `public_test_dep!` + +## [0.1.143](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.142...compiler_builtins-v0.1.143) - 2025-01-15 + +### Other + +- Use a C-safe return type for `__rust_[ui]128_*` overflowing intrinsics + +## [0.1.142](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.141...compiler_builtins-v0.1.142) - 2025-01-07 + +### Other + +- Account for optimization levels other than numbers + +## [0.1.141](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.140...compiler_builtins-v0.1.141) - 2025-01-07 + +### Other + +- Update the `libm` submodule +- Fix new `clippy::precedence` errors +- Rename `EXP_MAX` to `EXP_SAT` +- Shorten prefixes for float constants + +## [0.1.140](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.139...compiler_builtins-v0.1.140) - 2024-12-26 + +### Other + +- Disable f128 for amdgpu ([#737](https://github.com/rust-lang/compiler-builtins/pull/737)) +- Fix a bug in `abs_diff` +- Disable `f16` on platforms that have recursion problems + +## [0.1.139](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.138...compiler_builtins-v0.1.139) - 2024-11-03 + +### Other + +- Remove incorrect `sparcv9` match pattern from `configure_f16_f128` + +## [0.1.138](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.137...compiler_builtins-v0.1.138) - 2024-11-01 + +### Other + +- Use `f16_enabled`/`f128_enabled` in `examples/intrinsics.rs` ([#724](https://github.com/rust-lang/compiler-builtins/pull/724)) +- Disable `f16` for LoongArch64 ([#722](https://github.com/rust-lang/compiler-builtins/pull/722)) -- cgit 1.4.1-3-g733a5 From d30dde73b35da060279ca40409975d50eba1139f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 07:46:09 +0000 Subject: fix: Switch to resolver v2 The published crates fail to build with an edition less than 2024 because they are packaged with `resolver = "3"`, which is a 2024-only option. Revert back to resolver v2 to drop this requirement. Fixes: https://github.com/rust-lang/compiler-builtins/issues/883 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 75bb81ec187..b39ec8a25da 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -resolver = "3" +resolver = "2" members = [ "builtins-test", "compiler-builtins", -- cgit 1.4.1-3-g733a5 From 5028ecd025fc051fc191d1fb569cd22932b98f60 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 08:05:23 +0000 Subject: chore: Release libm v0.2.13 --- library/compiler-builtins/libm/CHANGELOG.md | 6 ++++++ library/compiler-builtins/libm/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index c507608ddbc..292561f86ab 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -8,6 +8,12 @@ and this project adheres to ## [Unreleased] +## [0.2.13](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.12...libm-v0.2.13) - 2025-04-21 + +### Fixed + +- Switch back to workspace resolver v2 to unbreak builds without the 2024 edition + ## [0.2.12](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.11...libm-v0.2.12) - 2025-04-21 - Mark generic functions `#[inline]` diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index dc553ca4aaf..f80715ff6c5 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -version = "0.2.12" +version = "0.2.13" edition = "2021" rust-version = "1.63" -- cgit 1.4.1-3-g733a5 From b6db36061e83d5e0566331e78d8f80423cf3757e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 16:30:17 -0400 Subject: musl: Update submodule Update the musl submodule to c47ad25ea3 ("iconv: harden UTF-8 output code path against input decoder bugs"). --- library/compiler-builtins/crates/musl-math-sys/musl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/crates/musl-math-sys/musl b/library/compiler-builtins/crates/musl-math-sys/musl index 61399d4bd02..c47ad25ea3b 160000 --- a/library/compiler-builtins/crates/musl-math-sys/musl +++ b/library/compiler-builtins/crates/musl-math-sys/musl @@ -1 +1 @@ -Subproject commit 61399d4bd02ae1ec03068445aa7ffe9174466bfd +Subproject commit c47ad25ea3b484e10326f933e927c0bc8cded3da -- cgit 1.4.1-3-g733a5 From 1dd39e27f06d0028bc62452283cf00a2d932d981 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 23 Apr 2025 06:46:31 +0000 Subject: libm-macros: Start tracking which functions are public It would be nice to reuse some of the macro structure for internal functions, like `rem_pio2`. To facilitate this, add a `public` field and make it available in the macro's API. --- .../crates/libm-macros/src/lib.rs | 6 +- .../crates/libm-macros/src/shared.rs | 383 ++++++++++++--------- .../crates/libm-macros/tests/basic.rs | 2 + library/compiler-builtins/libm-test/src/op.rs | 10 +- 4 files changed, 226 insertions(+), 175 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index 3cdd364e830..144676c1253 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -12,7 +12,7 @@ use syn::visit_mut::VisitMut; use syn::{Ident, ItemEnum}; const KNOWN_TYPES: &[&str] = &[ - "FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet", + "FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet", "public", ]; /// Populate an enum with a variant representing function. Names are in upper camel case. @@ -80,6 +80,8 @@ pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> p /// RustArgs: $RustArgs:ty, /// // The Rust version's return type (e.g. `(f32, f32)`) /// RustRet: $RustRet:ty, +/// // True if this is part of `libm`'s public API +/// public: $public:expr, /// // Attributes for the current function, if any /// attrs: [$($attr:meta),*], /// // Extra tokens passed directly (if any) @@ -329,6 +331,7 @@ fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result syn::Result quote! { RustFn: fn( #(#rust_args),* ,) -> ( #(#rust_ret),* ), }, "RustArgs" => quote! { RustArgs: ( #(#rust_args),* ,), }, "RustRet" => quote! { RustRet: ( #(#rust_ret),* ), }, + "public" => quote! { public: #public, }, _ => unreachable!("checked in validation"), }; ty_fields.push(field); diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index 750ed1afb05..1cefe4e8c7e 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -3,16 +3,26 @@ use std::fmt; use std::sync::LazyLock; -const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] = &[ - ( +struct NestedOp { + float_ty: FloatTy, + rust_sig: Signature, + c_sig: Option, + fn_list: &'static [&'static str], + public: bool, +} + +/// We need a flat list to work with most of the time, but define things as a more convenient +/// nested list. +const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ + NestedOp { // `fn(f16) -> f16` - FloatTy::F16, - Signature { + float_ty: FloatTy::F16, + rust_sig: Signature { args: &[Ty::F16], returns: &[Ty::F16], }, - None, - &[ + c_sig: None, + fn_list: &[ "ceilf16", "fabsf16", "floorf16", @@ -22,16 +32,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "sqrtf16", "truncf16", ], - ), - ( + public: true, + }, + NestedOp { // `fn(f32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32], }, - None, - &[ + c_sig: None, + fn_list: &[ "acosf", "acoshf", "asinf", @@ -70,16 +81,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "y0f", "y1f", ], - ), - ( + public: true, + }, + NestedOp { // `(f64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64], }, - None, - &[ + c_sig: None, + fn_list: &[ "acos", "acosh", "asin", @@ -118,16 +130,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "y0", "y1", ], - ), - ( + public: true, + }, + NestedOp { // `fn(f128) -> f128` - FloatTy::F128, - Signature { + float_ty: FloatTy::F128, + rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::F128], }, - None, - &[ + c_sig: None, + fn_list: &[ "ceilf128", "fabsf128", "floorf128", @@ -137,16 +150,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "sqrtf128", "truncf128", ], - ), - ( + public: true, + }, + NestedOp { // `(f16, f16) -> f16` - FloatTy::F16, - Signature { + float_ty: FloatTy::F16, + rust_sig: Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16], }, - None, - &[ + c_sig: None, + fn_list: &[ "copysignf16", "fdimf16", "fmaxf16", @@ -157,16 +171,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "fminimumf16", "fmodf16", ], - ), - ( + public: true, + }, + NestedOp { // `(f32, f32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32], }, - None, - &[ + c_sig: None, + fn_list: &[ "atan2f", "copysignf", "fdimf", @@ -182,16 +197,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "powf", "remainderf", ], - ), - ( + public: true, + }, + NestedOp { // `(f64, f64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64], }, - None, - &[ + c_sig: None, + fn_list: &[ "atan2", "copysign", "fdim", @@ -207,16 +223,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "pow", "remainder", ], - ), - ( + public: true, + }, + NestedOp { // `(f128, f128) -> f128` - FloatTy::F128, - Signature { + float_ty: FloatTy::F128, + rust_sig: Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128], }, - None, - &[ + c_sig: None, + fn_list: &[ "copysignf128", "fdimf128", "fmaxf128", @@ -227,221 +244,241 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "fminimumf128", "fmodf128", ], - ), - ( + public: true, + }, + NestedOp { // `(f32, f32, f32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32], }, - None, - &["fmaf"], - ), - ( + c_sig: None, + fn_list: &["fmaf"], + public: true, + }, + NestedOp { // `(f64, f64, f64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64], }, - None, - &["fma"], - ), - ( + c_sig: None, + fn_list: &["fma"], + public: true, + }, + NestedOp { // `(f128, f128, f128) -> f128` - FloatTy::F128, - Signature { + float_ty: FloatTy::F128, + rust_sig: Signature { args: &[Ty::F128, Ty::F128, Ty::F128], returns: &[Ty::F128], }, - None, - &["fmaf128"], - ), - ( + c_sig: None, + fn_list: &["fmaf128"], + public: true, + }, + NestedOp { // `(f32) -> i32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::I32], }, - None, - &["ilogbf"], - ), - ( + c_sig: None, + fn_list: &["ilogbf"], + public: true, + }, + NestedOp { // `(f64) -> i32` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::I32], }, - None, - &["ilogb"], - ), - ( + c_sig: None, + fn_list: &["ilogb"], + public: true, + }, + NestedOp { // `(i32, f32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32], }, - None, - &["jnf", "ynf"], - ), - ( + c_sig: None, + fn_list: &["jnf", "ynf"], + public: true, + }, + NestedOp { // `(i32, f64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64], }, - None, - &["jn", "yn"], - ), - ( + c_sig: None, + fn_list: &["jn", "yn"], + public: true, + }, + NestedOp { // `(f16, i32) -> f16` - FloatTy::F16, - Signature { + float_ty: FloatTy::F16, + rust_sig: Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16], }, - None, - &["ldexpf16", "scalbnf16"], - ), - ( + c_sig: None, + fn_list: &["ldexpf16", "scalbnf16"], + public: true, + }, + NestedOp { // `(f32, i32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32], }, - None, - &["ldexpf", "scalbnf"], - ), - ( + c_sig: None, + fn_list: &["ldexpf", "scalbnf"], + public: true, + }, + NestedOp { // `(f64, i64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64], }, - None, - &["ldexp", "scalbn"], - ), - ( + c_sig: None, + fn_list: &["ldexp", "scalbn"], + public: true, + }, + NestedOp { // `(f128, i32) -> f128` - FloatTy::F128, - Signature { + float_ty: FloatTy::F128, + rust_sig: Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128], }, - None, - &["ldexpf128", "scalbnf128"], - ), - ( + c_sig: None, + fn_list: &["ldexpf128", "scalbnf128"], + public: true, + }, + NestedOp { // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32], }), - &["modff"], - ), - ( + fn_list: &["modff"], + public: true, + }, + NestedOp { // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64], }), - &["modf"], - ), - ( + fn_list: &["modf"], + public: true, + }, + NestedOp { // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32], }), - &["frexpf", "lgammaf_r"], - ), - ( + fn_list: &["frexpf", "lgammaf_r"], + public: true, + }, + NestedOp { // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64], }), - &["frexp", "lgamma_r"], - ), - ( + fn_list: &["frexp", "lgamma_r"], + public: true, + }, + NestedOp { // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32], }), - &["remquof"], - ), - ( + fn_list: &["remquof"], + public: true, + }, + NestedOp { // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64], }), - &["remquo"], - ), - ( + fn_list: &["remquo"], + public: true, + }, + NestedOp { // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[], }), - &["sincosf"], - ), - ( + fn_list: &["sincosf"], + public: true, + }, + NestedOp { // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[], }), - &["sincos"], - ), + fn_list: &["sincos"], + public: true, + }, ]; /// A type used in a function signature. @@ -520,27 +557,31 @@ pub struct MathOpInfo { pub c_sig: Signature, /// Function signature for Rust implementations pub rust_sig: Signature, + /// True if part of libm's public API + pub public: bool, } /// A flat representation of `ALL_FUNCTIONS`. pub static ALL_OPERATIONS: LazyLock> = LazyLock::new(|| { let mut ret = Vec::new(); - for (base_fty, rust_sig, c_sig, names) in ALL_OPERATIONS_NESTED { - for name in *names { + for op in ALL_OPERATIONS_NESTED { + let fn_names = op.fn_list; + for name in fn_names { let api = MathOpInfo { name, - float_ty: *base_fty, - rust_sig: rust_sig.clone(), - c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()), + float_ty: op.float_ty, + rust_sig: op.rust_sig.clone(), + c_sig: op.c_sig.clone().unwrap_or_else(|| op.rust_sig.clone()), + public: op.public, }; ret.push(api); } - if !names.is_sorted() { - let mut sorted = (*names).to_owned(); + if !fn_names.is_sorted() { + let mut sorted = (*fn_names).to_owned(); sorted.sort_unstable(); - panic!("names list is not sorted: {names:?}\nExpected: {sorted:?}"); + panic!("names list is not sorted: {fn_names:?}\nExpected: {sorted:?}"); } } diff --git a/library/compiler-builtins/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/crates/libm-macros/tests/basic.rs index 5314e84bbb0..260350ef254 100644 --- a/library/compiler-builtins/crates/libm-macros/tests/basic.rs +++ b/library/compiler-builtins/crates/libm-macros/tests/basic.rs @@ -13,6 +13,7 @@ macro_rules! basic { RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, RustRet: $RustRet:ty, + public: $public:expr, attrs: [$($attr:meta),*], extra: [$($extra_tt:tt)*], fn_extra: $fn_extra:expr, @@ -25,6 +26,7 @@ macro_rules! basic { type RustFnTy = $RustFn; type RustArgsTy = $RustArgs; type RustRetTy = $RustRet; + const PUBLIC: bool = $public; const A: &[&str] = &[$($extra_tt)*]; fn foo(a: f32) -> f32 { $fn_extra(a) diff --git a/library/compiler-builtins/libm-test/src/op.rs b/library/compiler-builtins/libm-test/src/op.rs index bd17aad7d03..afd445ff9c5 100644 --- a/library/compiler-builtins/libm-test/src/op.rs +++ b/library/compiler-builtins/libm-test/src/op.rs @@ -90,6 +90,9 @@ pub trait MathOp { /// The function in `libm` which can be called. const ROUTINE: Self::RustFn; + + /// Whether or not the function is part of libm public API. + const PUBLIC: bool; } /// Access the associated `FTy` type from an op (helper to avoid ambiguous associated types). @@ -107,7 +110,7 @@ pub type OpRustArgs = ::RustArgs; /// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). pub type OpRustRet = ::RustRet; -macro_rules! do_thing { +macro_rules! create_op_modules { // Matcher for unary functions ( fn_name: $fn_name:ident, @@ -118,8 +121,8 @@ macro_rules! do_thing { RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, RustRet: $RustRet:ty, + public: $public:expr, attrs: [$($attr:meta),*], - ) => { paste::paste! { $(#[$attr])* @@ -138,6 +141,7 @@ macro_rules! do_thing { const IDENTIFIER: Identifier = Identifier::[< $fn_name:camel >]; const ROUTINE: Self::RustFn = libm::$fn_name; + const PUBLIC: bool = $public; } } @@ -146,6 +150,6 @@ macro_rules! do_thing { } libm_macros::for_each_function! { - callback: do_thing, + callback: create_op_modules, emit_types: all, } -- cgit 1.4.1-3-g733a5 From 99202af0758bbeb9909acf848de3cd968a41148f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 23 Apr 2025 07:47:48 +0000 Subject: libm-macros: Allow a way to bulk match f16 and f128 functions These are never available in musl, so introduce easier ways to skip them rather than needing to exclude f16/f128 functions in three different places. --- .../crates/libm-macros/src/lib.rs | 30 +++++++++ .../crates/libm-macros/src/parse.rs | 16 ++++- .../crates/libm-macros/tests/basic.rs | 72 ++++++++++++++++++++++ library/compiler-builtins/crates/util/src/main.rs | 44 ++----------- .../compiler-builtins/libm-test/benches/random.rs | 45 ++------------ .../libm-test/tests/compare_built_musl.rs | 43 +------------ 6 files changed, 128 insertions(+), 122 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index 144676c1253..e8afe3aad55 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -116,6 +116,9 @@ pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> p /// // a simplified match-like syntax. /// fn_extra: match MACRO_FN_NAME { /// hypot | hypotf => |x| x.hypot(), +/// // `ALL_*` magic matchers also work to extract specific types +/// ALL_F64 => |x| x, +/// // The default pattern gets applied to everything that did not match /// _ => |x| x, /// }, /// } @@ -138,6 +141,27 @@ pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream { /// /// Returns the list of function names that we should expand for. fn validate(input: &mut StructuredInput) -> syn::Result> { + // Replace magic mappers with a list of relevant functions. + if let Some(map) = &mut input.fn_extra { + for (name, ty) in [ + ("ALL_F16", FloatTy::F16), + ("ALL_F32", FloatTy::F32), + ("ALL_F64", FloatTy::F64), + ("ALL_F128", FloatTy::F128), + ] { + let Some(k) = map.keys().find(|key| *key == name) else { + continue; + }; + + let key = k.clone(); + let val = map.remove(&key).unwrap(); + + for op in ALL_OPERATIONS.iter().filter(|op| op.float_ty == ty) { + map.insert(Ident::new(op.name, key.span()), val.clone()); + } + } + } + // Collect lists of all functions that are provied as macro inputs in various fields (only, // skip, attributes). let attr_mentions = input @@ -195,6 +219,12 @@ fn validate(input: &mut StructuredInput) -> syn::Result continue; } + // Omit f16 and f128 functions if requested + if input.skip_f16_f128 && (func.float_ty == FloatTy::F16 || func.float_ty == FloatTy::F128) + { + continue; + } + // Run everything else fn_list.push(func); } diff --git a/library/compiler-builtins/crates/libm-macros/src/parse.rs b/library/compiler-builtins/crates/libm-macros/src/parse.rs index d60d1247a9e..4876f3ef726 100644 --- a/library/compiler-builtins/crates/libm-macros/src/parse.rs +++ b/library/compiler-builtins/crates/libm-macros/src/parse.rs @@ -6,7 +6,7 @@ use syn::parse::{Parse, ParseStream, Parser}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::token::{self, Comma}; -use syn::{Arm, Attribute, Expr, ExprMatch, Ident, Meta, Token, bracketed}; +use syn::{Arm, Attribute, Expr, ExprMatch, Ident, LitBool, Meta, Token, bracketed}; /// The input to our macro; just a list of `field: value` items. #[derive(Debug)] @@ -50,6 +50,8 @@ pub struct StructuredInput { pub emit_types: Vec, /// Skip these functions pub skip: Vec, + /// If true, omit f16 and f128 functions that aren't present in other libraries. + pub skip_f16_f128: bool, /// Invoke only for these functions pub only: Option>, /// Attributes that get applied to specific functions @@ -70,6 +72,7 @@ impl StructuredInput { let cb_expr = expect_field(&mut map, "callback")?; let emit_types_expr = expect_field(&mut map, "emit_types").ok(); let skip_expr = expect_field(&mut map, "skip").ok(); + let skip_f16_f128 = expect_field(&mut map, "skip_f16_f128").ok(); let only_expr = expect_field(&mut map, "only").ok(); let attr_expr = expect_field(&mut map, "attributes").ok(); let extra = expect_field(&mut map, "extra").ok(); @@ -93,6 +96,11 @@ impl StructuredInput { None => Vec::new(), }; + let skip_f16_f128 = match skip_f16_f128 { + Some(expr) => expect_litbool(expr)?.value, + None => false, + }; + let only_span = only_expr.as_ref().map(|expr| expr.span()); let only = match only_expr { Some(expr) => Some(Parser::parse2(parse_ident_array, expr.into_token_stream())?), @@ -122,6 +130,7 @@ impl StructuredInput { callback: expect_ident(cb_expr)?, emit_types, skip, + skip_f16_f128, only, only_span, attributes, @@ -220,6 +229,11 @@ fn expect_ident(expr: Expr) -> syn::Result { syn::parse2(expr.into_token_stream()) } +/// Coerce an expression into a simple keyword. +fn expect_litbool(expr: Expr) -> syn::Result { + syn::parse2(expr.into_token_stream()) +} + /// Parse either a single identifier (`foo`) or an array of identifiers (`[foo, bar, baz]`). fn parse_ident_or_array(input: ParseStream) -> syn::Result> { if !input.peek(token::Bracket) { diff --git a/library/compiler-builtins/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/crates/libm-macros/tests/basic.rs index 260350ef254..b4276262229 100644 --- a/library/compiler-builtins/crates/libm-macros/tests/basic.rs +++ b/library/compiler-builtins/crates/libm-macros/tests/basic.rs @@ -103,3 +103,75 @@ mod test_emit_types { emit_types: [RustFn, RustArgs], } } + +#[test] +fn test_skip_f16_f128() { + macro_rules! skip_f16_f128 { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + extra: $vec:ident, + ) => { + $vec.push(stringify!($fn_name)); + }; + } + + let mut v = Vec::new(); + // Test with no extra, no skip, and no attributes + libm_macros::for_each_function! { + callback: skip_f16_f128, + skip_f16_f128: true, + extra: v, + } + + for name in v { + assert!(!name.contains("f16"), "{name}"); + assert!(!name.contains("f128"), "{name}"); + } +} + +#[test] +fn test_fn_extra_expansion() { + macro_rules! fn_extra_expansion { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + fn_extra: $vec:expr, + ) => { + $vec.push(stringify!($fn_name)); + }; + } + + let mut vf16 = Vec::new(); + let mut vf32 = Vec::new(); + let mut vf64 = Vec::new(); + let mut vf128 = Vec::new(); + + // Test with no extra, no skip, and no attributes + libm_macros::for_each_function! { + callback: fn_extra_expansion, + fn_extra: match MACRO_FN_NAME { + ALL_F16 => vf16, + ALL_F32 => vf32, + ALL_F64 => vf64, + ALL_F128 => vf128, + } + } + + // Skip functions with a suffix after the type spec + vf16.retain(|name| !name.ends_with("_r")); + vf32.retain(|name| !name.ends_with("_r")); + vf64.retain(|name| !name.ends_with("_r")); + vf128.retain(|name| !name.ends_with("_r")); + + for name in vf16 { + assert!(name.ends_with("f16"), "{name}"); + } + for name in vf32 { + assert!(name.ends_with("f"), "{name}"); + } + let _ = vf64; + for name in vf128 { + assert!(name.ends_with("f128"), "{name}"); + } +} diff --git a/library/compiler-builtins/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs index e7057869996..5972181531b 100644 --- a/library/compiler-builtins/crates/util/src/main.rs +++ b/library/compiler-builtins/crates/util/src/main.rs @@ -86,55 +86,19 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { emit_types: [CFn, RustFn, RustArgs], extra: (basis, op, inputs), fn_extra: match MACRO_FN_NAME { - ceilf128 - | ceilf16 - | copysignf128 - | copysignf16 - | fabsf128 - | fabsf16 - | fdimf128 - | fdimf16 - | floorf128 - | floorf16 - | fmaf128 - | fmaxf128 - | fmaxf16 - | fmaximum + // Not provided by musl + fmaximum | fmaximum_num | fmaximum_numf - | fmaximum_numf128 - | fmaximum_numf16 | fmaximumf - | fmaximumf128 - | fmaximumf16 - | fminf128 - | fminf16 | fminimum | fminimum_num | fminimum_numf - | fminimum_numf128 - | fminimum_numf16 | fminimumf - | fminimumf128 - | fminimumf16 - | fmodf128 - | fmodf16 - | ldexpf128 - | ldexpf16 - | rintf128 - | rintf16 | roundeven | roundevenf - | roundevenf128 - | roundevenf16 - | roundf128 - | roundf16 - | scalbnf128 - | scalbnf16 - | sqrtf128 - | sqrtf16 - | truncf128 - | truncf16 => None, + | ALL_F16 + | ALL_F128 => None, _ => Some(musl_math_sys::MACRO_FN_NAME) } } diff --git a/library/compiler-builtins/libm-test/benches/random.rs b/library/compiler-builtins/libm-test/benches/random.rs index 81f58e3a658..1b17f049eca 100644 --- a/library/compiler-builtins/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm-test/benches/random.rs @@ -125,56 +125,19 @@ libm_macros::for_each_function! { // FIXME(correctness): exp functions have the wrong result on i586 exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)), - // Musl does not provide `f16` and `f128` functions - ceilf128 - | ceilf16 - | copysignf128 - | copysignf16 - | fabsf128 - | fabsf16 - | fdimf128 - | fdimf16 - | floorf128 - | floorf16 - | fmaf128 - | fmaxf128 - | fmaxf16 - | fmaximum + // Musl does not provide `f16` and `f128` functions, as well as a handful of others + fmaximum | fmaximum_num | fmaximum_numf - | fmaximum_numf128 - | fmaximum_numf16 | fmaximumf - | fmaximumf128 - | fmaximumf16 - | fminf128 - | fminf16 | fminimum | fminimum_num | fminimum_numf - | fminimum_numf128 - | fminimum_numf16 | fminimumf - | fminimumf128 - | fminimumf16 - | fmodf128 - | fmodf16 - | ldexpf128 - | ldexpf16 - | rintf128 - | rintf16 | roundeven | roundevenf - | roundevenf128 - | roundevenf16 - | roundf128 - | roundf16 - | scalbnf128 - | scalbnf16 - | sqrtf128 - | sqrtf16 - | truncf128 - | truncf16 => (false, None), + | ALL_F16 + | ALL_F128 => (false, None), // By default we never skip (false) and always have a musl function available _ => (false, Some(musl_math_sys::MACRO_FN_NAME)) diff --git a/library/compiler-builtins/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm-test/tests/compare_built_musl.rs index cbb4bd49b9c..6ccbb6f4c51 100644 --- a/library/compiler-builtins/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm-test/tests/compare_built_musl.rs @@ -76,6 +76,8 @@ macro_rules! musl_tests { libm_macros::for_each_function! { callback: musl_tests, attributes: [], + // Not provided by musl + skip_f16_f128: true, skip: [ // TODO integer inputs jn, @@ -89,55 +91,16 @@ libm_macros::for_each_function! { // Not provided by musl // verify-sorted-start - ceilf128, - ceilf16, - copysignf128, - copysignf16, - fabsf128, - fabsf16, - fdimf128, - fdimf16, - floorf128, - floorf16, - fmaf128, - fmaxf128, - fmaxf16, fmaximum, fmaximum_num, fmaximum_numf, - fmaximum_numf128, - fmaximum_numf16, fmaximumf, - fmaximumf128, - fmaximumf16, - fminf128, - fminf16, fminimum, fminimum_num, fminimum_numf, - fminimum_numf128, - fminimum_numf16, fminimumf, - fminimumf128, - fminimumf16, - fmodf128, - fmodf16, - ldexpf128, - ldexpf16, - rintf128, - rintf16, roundeven, roundevenf, - roundevenf128, - roundevenf16, - roundf128, - roundf16, - scalbnf128, - scalbnf16, - sqrtf128, - sqrtf16, - truncf128, - truncf16, - // verify-sorted-end + // // verify-sorted-end ], } -- cgit 1.4.1-3-g733a5 From 975617e8d4105f30d741ac7a3f5478d3b7b7917c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Mar 2025 00:19:04 +0000 Subject: Warn on `unsafe_op_in_unsafe_fn` by default Edition 2024 requires that we avoid this. There is a lot of code that will need to be adjusted, so start the process here with a warning that will show up in CI. --- .../builtins-test-intrinsics/src/main.rs | 20 +-- .../compiler-builtins/compiler-builtins/src/arm.rs | 181 +++++++++++++++++---- .../compiler-builtins/compiler-builtins/src/lib.rs | 3 + .../compiler-builtins/src/macros.rs | 15 +- .../compiler-builtins/src/mem/mod.rs | 2 + .../compiler-builtins/src/x86_64.rs | 2 +- 6 files changed, 172 insertions(+), 51 deletions(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs index c4c026368e0..18f943eff35 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -649,14 +649,14 @@ fn something_with_a_dtor(f: &dyn Fn()) { f(); } -#[no_mangle] +#[unsafe(no_mangle)] #[cfg(not(thumb))] fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { run(); 0 } -#[no_mangle] +#[unsafe(no_mangle)] #[cfg(thumb)] pub fn _start() -> ! { run(); @@ -669,30 +669,30 @@ pub fn _start() -> ! { extern "C" {} // ARM targets need these symbols -#[no_mangle] +#[unsafe(no_mangle)] pub fn __aeabi_unwind_cpp_pr0() {} -#[no_mangle] +#[unsafe(no_mangle)] pub fn __aeabi_unwind_cpp_pr1() {} #[cfg(not(any(windows, target_os = "cygwin")))] #[allow(non_snake_case)] -#[no_mangle] +#[unsafe(no_mangle)] pub fn _Unwind_Resume() {} #[cfg(not(any(windows, target_os = "cygwin")))] #[lang = "eh_personality"] -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn eh_personality() {} #[cfg(any(all(windows, target_env = "gnu"), target_os = "cygwin"))] mod mingw_unwinding { - #[no_mangle] + #[unsafe(no_mangle)] pub fn rust_eh_personality() {} - #[no_mangle] + #[unsafe(no_mangle)] pub fn rust_eh_unwind_resume() {} - #[no_mangle] + #[unsafe(no_mangle)] pub fn rust_eh_register_frames() {} - #[no_mangle] + #[unsafe(no_mangle)] pub fn rust_eh_unregister_frames() {} } diff --git a/library/compiler-builtins/compiler-builtins/src/arm.rs b/library/compiler-builtins/compiler-builtins/src/arm.rs index 7859b51207c..a9107e3cdfd 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm.rs @@ -76,90 +76,205 @@ intrinsics! { ); } - // FIXME: The `*4` and `*8` variants should be defined as aliases. + // FIXME(arm): The `*4` and `*8` variants should be defined as aliases. + /// `memcpy` provided with the `aapcs` ABI. + /// + /// # Safety + /// + /// Usual `memcpy` requirements apply. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { - crate::mem::memcpy(dest, src, n); + pub unsafe extern "aapcs" fn __aeabi_memcpy(dst: *mut u8, src: *const u8, n: usize) { + // SAFETY: memcpy preconditions apply. + unsafe { crate::mem::memcpy(dst, src, n) }; } + /// `memcpy` for 4-byte alignment. + /// + /// # Safety + /// + /// Usual `memcpy` requirements apply. Additionally, `dest` and `src` must be aligned to + /// four bytes. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { + pub unsafe extern "aapcs" fn __aeabi_memcpy4(dst: *mut u8, src: *const u8, n: usize) { // We are guaranteed 4-alignment, so accessing at u32 is okay. - let mut dest = dest as *mut u32; - let mut src = src as *mut u32; + let mut dst = dst.cast::(); + let mut src = src.cast::(); + debug_assert!(dst.is_aligned()); + debug_assert!(src.is_aligned()); let mut n = n; while n >= 4 { - *dest = *src; - dest = dest.offset(1); - src = src.offset(1); + // SAFETY: `dst` and `src` are both valid for at least 4 bytes, from + // `memcpy` preconditions and the loop guard. + unsafe { *dst = *src }; + + // FIXME(addr): if we can make this end-of-address-space safe without losing + // performance, we may want to consider that. + // SAFETY: memcpy is not expected to work at the end of the address space + unsafe { + dst = dst.offset(1); + src = src.offset(1); + } + n -= 4; } - __aeabi_memcpy(dest as *mut u8, src as *const u8, n); + // SAFETY: `dst` and `src` will still be valid for `n` bytes + unsafe { __aeabi_memcpy(dst.cast::(), src.cast::(), n) }; } + /// `memcpy` for 8-byte alignment. + /// + /// # Safety + /// + /// Usual `memcpy` requirements apply. Additionally, `dest` and `src` must be aligned to + /// eight bytes. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memcpy4(dest, src, n); + pub unsafe extern "aapcs" fn __aeabi_memcpy8(dst: *mut u8, src: *const u8, n: usize) { + debug_assert!(dst.addr() & 7 == 0); + debug_assert!(src.addr() & 7 == 0); + + // SAFETY: memcpy preconditions apply, less strict alignment. + unsafe { __aeabi_memcpy4(dst, src, n) }; } + /// `memmove` provided with the `aapcs` ABI. + /// + /// # Safety + /// + /// Usual `memmove` requirements apply. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { - crate::mem::memmove(dest, src, n); + pub unsafe extern "aapcs" fn __aeabi_memmove(dst: *mut u8, src: *const u8, n: usize) { + // SAFETY: memmove preconditions apply. + unsafe { crate::mem::memmove(dst, src, n) }; } + /// `memmove` for 4-byte alignment. + /// + /// # Safety + /// + /// Usual `memmove` requirements apply. Additionally, `dest` and `src` must be aligned to + /// four bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memmove(dest, src, n); + pub unsafe extern "aapcs" fn __aeabi_memmove4(dst: *mut u8, src: *const u8, n: usize) { + debug_assert!(dst.addr() & 3 == 0); + debug_assert!(src.addr() & 3 == 0); + + // SAFETY: same preconditions, less strict aligment. + unsafe { __aeabi_memmove(dst, src, n) }; } + /// `memmove` for 8-byte alignment. + /// + /// # Safety + /// + /// Usual `memmove` requirements apply. Additionally, `dst` and `src` must be aligned to + /// eight bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memmove(dest, src, n); + pub unsafe extern "aapcs" fn __aeabi_memmove8(dst: *mut u8, src: *const u8, n: usize) { + debug_assert!(dst.addr() & 7 == 0); + debug_assert!(src.addr() & 7 == 0); + + // SAFETY: memmove preconditions apply, less strict alignment. + unsafe { __aeabi_memmove(dst, src, n) }; } + /// `memset` provided with the `aapcs` ABI. + /// + /// # Safety + /// + /// Usual `memset` requirements apply. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { + pub unsafe extern "aapcs" fn __aeabi_memset(dst: *mut u8, n: usize, c: i32) { // Note the different argument order - crate::mem::memset(dest, c, n); + // SAFETY: memset preconditions apply. + unsafe { crate::mem::memset(dst, c, n) }; } + /// `memset` for 4-byte alignment. + /// + /// # Safety + /// + /// Usual `memset` requirements apply. Additionally, `dest` and `src` must be aligned to + /// four bytes. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { - let mut dest = dest as *mut u32; + pub unsafe extern "aapcs" fn __aeabi_memset4(dst: *mut u8, n: usize, c: i32) { + let mut dst = dst.cast::(); + debug_assert!(dst.is_aligned()); let mut n = n; let byte = (c as u32) & 0xff; let c = (byte << 24) | (byte << 16) | (byte << 8) | byte; while n >= 4 { - *dest = c; - dest = dest.offset(1); + // SAFETY: `dst` is valid for at least 4 bytes, from `memset` preconditions and + // the loop guard. + unsafe { *dst = c }; + + // FIXME(addr): if we can make this end-of-address-space safe without losing + // performance, we may want to consider that. + // SAFETY: memcpy is not expected to work at the end of the address space + unsafe { + dst = dst.offset(1); + } n -= 4; } - __aeabi_memset(dest as *mut u8, n, byte as i32); + // SAFETY: `dst` will still be valid for `n` bytes + unsafe { __aeabi_memset(dst.cast::(), n, byte as i32) }; } + /// `memset` for 8-byte alignment. + /// + /// # Safety + /// + /// Usual `memset` requirements apply. Additionally, `dst` and `src` must be aligned to + /// eight bytes. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { - __aeabi_memset4(dest, n, c); + pub unsafe extern "aapcs" fn __aeabi_memset8(dst: *mut u8, n: usize, c: i32) { + debug_assert!(dst.addr() & 7 == 0); + + // SAFETY: memset preconditions apply, less strict alignment. + unsafe { __aeabi_memset4(dst, n, c) }; } + /// `memclr` provided with the `aapcs` ABI. + /// + /// # Safety + /// + /// Usual `memclr` requirements apply. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { - __aeabi_memset(dest, n, 0); + pub unsafe extern "aapcs" fn __aeabi_memclr(dst: *mut u8, n: usize) { + // SAFETY: memclr preconditions apply, less strict alignment. + unsafe { __aeabi_memset(dst, n, 0) }; } + /// `memclr` for 4-byte alignment. + /// + /// # Safety + /// + /// Usual `memclr` requirements apply. Additionally, `dest` and `src` must be aligned to + /// four bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { - __aeabi_memset4(dest, n, 0); + pub unsafe extern "aapcs" fn __aeabi_memclr4(dst: *mut u8, n: usize) { + debug_assert!(dst.addr() & 3 == 0); + + // SAFETY: memclr preconditions apply, less strict alignment. + unsafe { __aeabi_memset4(dst, n, 0) }; } + /// `memclr` for 8-byte alignment. + /// + /// # Safety + /// + /// Usual `memclr` requirements apply. Additionally, `dst` and `src` must be aligned to + /// eight bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { - __aeabi_memset4(dest, n, 0); + pub unsafe extern "aapcs" fn __aeabi_memclr8(dst: *mut u8, n: usize) { + debug_assert!(dst.addr() & 7 == 0); + + // SAFETY: memclr preconditions apply, less strict alignment. + unsafe { __aeabi_memset4(dst, n, 0) }; } } diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index 7523a00cf9b..6a6b28067e8 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -22,6 +22,9 @@ #![allow(clippy::manual_swap)] // Support compiling on both stage0 and stage1 which may differ in supported stable features. #![allow(stable_features)] +// By default, disallow this as it is forbidden in edition 2024. There is a lot of unsafe code to +// be migrated, however, so exceptions exist. +#![warn(unsafe_op_in_unsafe_fn)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index 4fa53656e5c..dbf71553440 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -256,7 +256,7 @@ macro_rules! intrinsics { #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] mod $name { - #[no_mangle] + #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern $abi fn $name( $($argname: u16),* ) $(-> $ret)? { @@ -292,7 +292,7 @@ macro_rules! intrinsics { #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] mod $name { - #[no_mangle] + #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern $abi fn $name( $($argname: $ty),* ) -> u16 { @@ -333,7 +333,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] mod $name { - #[no_mangle] + #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { @@ -343,7 +343,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] mod $alias { - #[no_mangle] + #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { @@ -410,7 +410,7 @@ macro_rules! intrinsics { #[cfg(all(feature = "mem", not(feature = "mangled-names")))] mod $name { $(#[$($attr)*])* - #[no_mangle] + #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) @@ -485,10 +485,11 @@ macro_rules! intrinsics { #[cfg(not(feature = "mangled-names"))] mod $name { $(#[$($attr)*])* - #[no_mangle] + #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - super::$name($($argname),*) + // SAFETY: same preconditions. + $(unsafe $($empty)?)? { super::$name($($argname),*) } } } diff --git a/library/compiler-builtins/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/compiler-builtins/src/mem/mod.rs index ec160039d0d..6828f3804e0 100644 --- a/library/compiler-builtins/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/mem/mod.rs @@ -1,5 +1,7 @@ // Trying to satisfy clippy here is hopeless #![allow(clippy::style)] +// FIXME(e2024): this eventually needs to be removed. +#![allow(unsafe_op_in_unsafe_fn)] #[allow(warnings)] #[cfg(target_pointer_width = "16")] diff --git a/library/compiler-builtins/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/x86_64.rs index af67e66e28d..fc1190f79b2 100644 --- a/library/compiler-builtins/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/compiler-builtins/src/x86_64.rs @@ -44,7 +44,7 @@ intrinsics! { // HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM // support unless we emit the _fltused mod _fltused { - #[no_mangle] + #[unsafe(no_mangle)] #[used] #[cfg(target_os = "uefi")] static _fltused: i32 = 0; -- cgit 1.4.1-3-g733a5 From 8db68dafc70cb51ddc6eabb6a6db754b95aa296c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Apr 2025 19:57:44 -0400 Subject: Reexport types from `c_size_t` in `std` These are unstably available in `core` and should be in `std` too, but are not currently reexported. Resolve this here. --- library/std/src/ffi/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index bd9446f5aba..f77bc1916e1 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -178,6 +178,8 @@ pub use core::ffi::{ c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong, c_ulonglong, c_ushort, }; +#[unstable(feature = "c_size_t", issue = "88345")] +pub use core::ffi::{c_ptrdiff_t, c_size_t, c_ssize_t}; #[doc(inline)] #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] -- cgit 1.4.1-3-g733a5 From 8d789ea8f1f41c73a0862015f1659cbbd0c523c1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 29 Apr 2025 21:04:30 +0000 Subject: Resolve `unnecessary_transmutes` lints These appeared in a later nightly. In compiler-builtins we can apply the suggestion, but in `libm` we need to ignore them since `fx::from_bits` is not `const` at the MSRV. `clippy::uninlined_format_args` also seems to have gotten stricter, so fix those here. --- .../compiler-builtins/builtins-test/tests/misc.rs | 30 +++++++++------------- .../compiler-builtins/builtins-test/tests/mul.rs | 22 ++++++---------- .../compiler-builtins/compiler-builtins/build.rs | 9 +++---- .../compiler-builtins/src/mem/impls.rs | 2 +- library/compiler-builtins/libm/src/math/pow.rs | 11 ++------ .../libm/src/math/support/float_traits.rs | 6 +++++ 6 files changed, 32 insertions(+), 48 deletions(-) diff --git a/library/compiler-builtins/builtins-test/tests/misc.rs b/library/compiler-builtins/builtins-test/tests/misc.rs index b8c75c02653..64a9d56f36b 100644 --- a/library/compiler-builtins/builtins-test/tests/misc.rs +++ b/library/compiler-builtins/builtins-test/tests/misc.rs @@ -77,16 +77,13 @@ fn leading_zeros() { let lz1 = leading_zeros_default(x); let lz2 = leading_zeros_riscv(x); if lz0 != lz { - panic!("__clzsi2({}): std: {}, builtins: {}", x, lz, lz0); + panic!("__clzsi2({x}): std: {lz}, builtins: {lz0}"); } if lz1 != lz { - panic!( - "leading_zeros_default({}): std: {}, builtins: {}", - x, lz, lz1 - ); + panic!("leading_zeros_default({x}): std: {lz}, builtins: {lz1}"); } if lz2 != lz { - panic!("leading_zeros_riscv({}): std: {}, builtins: {}", x, lz, lz2); + panic!("leading_zeros_riscv({x}): std: {lz}, builtins: {lz2}"); } }); } @@ -102,16 +99,13 @@ fn leading_zeros() { let lz1 = leading_zeros_default(x); let lz2 = leading_zeros_riscv(x); if lz0 != lz { - panic!("__clzdi2({}): std: {}, builtins: {}", x, lz, lz0); + panic!("__clzdi2({x}): std: {lz}, builtins: {lz0}"); } if lz1 != lz { - panic!( - "leading_zeros_default({}): std: {}, builtins: {}", - x, lz, lz1 - ); + panic!("leading_zeros_default({x}): std: {lz}, builtins: {lz1}"); } if lz2 != lz { - panic!("leading_zeros_riscv({}): std: {}, builtins: {}", x, lz, lz2); + panic!("leading_zeros_riscv({x}): std: {lz}, builtins: {lz2}"); } }); } @@ -125,7 +119,7 @@ fn leading_zeros() { let lz = x.leading_zeros() as usize; let lz0 = __clzti2(x); if lz0 != lz { - panic!("__clzti2({}): std: {}, builtins: {}", x, lz, lz0); + panic!("__clzti2({x}): std: {lz}, builtins: {lz0}"); } }); } @@ -142,10 +136,10 @@ fn trailing_zeros() { let tz0 = __ctzsi2(x); let tz1 = trailing_zeros(x); if tz0 != tz { - panic!("__ctzsi2({}): std: {}, builtins: {}", x, tz, tz0); + panic!("__ctzsi2({x}): std: {tz}, builtins: {tz0}"); } if tz1 != tz { - panic!("trailing_zeros({}): std: {}, builtins: {}", x, tz, tz1); + panic!("trailing_zeros({x}): std: {tz}, builtins: {tz1}"); } }); fuzz(N, |x: u64| { @@ -156,10 +150,10 @@ fn trailing_zeros() { let tz0 = __ctzdi2(x); let tz1 = trailing_zeros(x); if tz0 != tz { - panic!("__ctzdi2({}): std: {}, builtins: {}", x, tz, tz0); + panic!("__ctzdi2({x}): std: {tz}, builtins: {tz0}"); } if tz1 != tz { - panic!("trailing_zeros({}): std: {}, builtins: {}", x, tz, tz1); + panic!("trailing_zeros({x}): std: {tz}, builtins: {tz1}"); } }); fuzz(N, |x: u128| { @@ -169,7 +163,7 @@ fn trailing_zeros() { let tz = x.trailing_zeros() as usize; let tz0 = __ctzti2(x); if tz0 != tz { - panic!("__ctzti2({}): std: {}, builtins: {}", x, tz, tz0); + panic!("__ctzti2({x}): std: {tz}, builtins: {tz0}"); } }); } diff --git a/library/compiler-builtins/builtins-test/tests/mul.rs b/library/compiler-builtins/builtins-test/tests/mul.rs index 198cacb3489..58bc9ab4ac9 100644 --- a/library/compiler-builtins/builtins-test/tests/mul.rs +++ b/library/compiler-builtins/builtins-test/tests/mul.rs @@ -18,8 +18,8 @@ mod int_mul { let mul1: $i = $fn(x, y); if mul0 != mul1 { panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, y, mul0, mul1 + "{func}({x}, {y}): std: {mul0}, builtins: {mul1}", + func = stringify!($fn), ); } }); @@ -52,8 +52,8 @@ mod int_overflowing_mul { let o1 = o1 != 0; if mul0 != mul1 || o0 != o1 { panic!( - "{}({}, {}): std: ({}, {}), builtins: ({}, {})", - stringify!($fn), x, y, mul0, o0, mul1, o1 + "{func}({x}, {y}): std: ({mul0}, {o0}), builtins: ({mul1}, {o1})", + func = stringify!($fn), ); } }); @@ -77,20 +77,14 @@ mod int_overflowing_mul { let (mul0, o0) = x.overflowing_mul(y); let mul1 = __rust_u128_mulo(x, y, &mut o1); if mul0 != mul1 || i32::from(o0) != o1 { - panic!( - "__rust_u128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", - x, y, mul0, o0, mul1, o1 - ); + panic!("__rust_u128_mulo({x}, {y}): std: ({mul0}, {o0}), builtins: ({mul1}, {o1})",); } let x = x as i128; let y = y as i128; let (mul0, o0) = x.overflowing_mul(y); let mul1 = __rust_i128_mulo(x, y, &mut o1); if mul0 != mul1 || i32::from(o0) != o1 { - panic!( - "__rust_i128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", - x, y, mul0, o0, mul1, o1 - ); + panic!("__rust_i128_mulo({x}, {y}): std: ({mul0}, {o0}), builtins: ({mul1}, {o1})",); } }); } @@ -109,8 +103,8 @@ macro_rules! float_mul { let mul1: $f = $fn(x, y); if !Float::eq_repr(mul0, mul1) { panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), x, y, mul0, mul1 + "{func}({x:?}, {y:?}): std: {mul0:?}, builtins: {mul1:?}", + func = stringify!($fn), ); } }); diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index 04369a4aa4e..90d98ec7ce9 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -137,7 +137,7 @@ fn aarch64_symbol(ordering: Ordering) -> &'static str { Ordering::Acquire => "acq", Ordering::Release => "rel", Ordering::AcqRel => "acq_rel", - _ => panic!("unknown symbol for {:?}", ordering), + _ => panic!("unknown symbol for {ordering:?}"), } } @@ -229,7 +229,7 @@ fn configure_check_cfg() { for op_size in op_sizes { for ordering in ["relax", "acq", "rel", "acq_rel"] { - aarch_atomic.push(format!("__aarch64_{}{}_{}", aarch_op, op_size, ordering)); + aarch_atomic.push(format!("__aarch64_{aarch_op}{op_size}_{ordering}")); } } } @@ -239,10 +239,7 @@ fn configure_check_cfg() { .copied() .chain(aarch_atomic.iter().map(|s| s.as_str())) { - println!( - "cargo::rustc-check-cfg=cfg({}, values(\"optimized-c\"))", - fn_name - ); + println!("cargo::rustc-check-cfg=cfg({fn_name}, values(\"optimized-c\"))",); } // Rustc is unaware of sparc target features, but this does show up from diff --git a/library/compiler-builtins/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs index dc12d69969c..14a4787485d 100644 --- a/library/compiler-builtins/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs @@ -38,7 +38,7 @@ unsafe fn read_usize_unaligned(x: *const usize) -> usize { // Do not use `core::ptr::read_unaligned` here, since it calls `copy_nonoverlapping` which // is translated to memcpy in LLVM. let x_read = (x as *const [u8; core::mem::size_of::()]).read(); - core::mem::transmute(x_read) + usize::from_ne_bytes(x_read) } /// Loads a `T`-sized chunk from `src` into `dst` at offset `offset`, if that does not exceed diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 7e7d049b930..94ae31cf0da 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -452,11 +452,7 @@ mod tests { } else { pow(base, exponent) == expected }, - "{} ** {} was {} instead of {}", - base, - exponent, - res, - expected + "{base} ** {exponent} was {res} instead of {expected}", ); } @@ -486,10 +482,7 @@ mod tests { } else { exp == res }, - "test for {} was {} instead of {}", - val, - res, - exp + "test for {val} was {res} instead of {exp}", ); }) }); diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 8094a7b84d5..4c866ef10bd 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -1,3 +1,5 @@ +#![allow(unknown_lints)] // FIXME(msrv) we shouldn't need this + use core::{fmt, mem, ops}; use super::int_traits::{CastFrom, Int, MinInt}; @@ -344,24 +346,28 @@ float_impl!( /* FIXME(msrv): vendor some things that are not const stable at our MSRV */ /// `f32::from_bits` +#[allow(unnecessary_transmutes)] // lint appears in newer versions of Rust pub const fn f32_from_bits(bits: u32) -> f32 { // SAFETY: POD cast with no preconditions unsafe { mem::transmute::(bits) } } /// `f32::to_bits` +#[allow(unnecessary_transmutes)] // lint appears in newer versions of Rust pub const fn f32_to_bits(x: f32) -> u32 { // SAFETY: POD cast with no preconditions unsafe { mem::transmute::(x) } } /// `f64::from_bits` +#[allow(unnecessary_transmutes)] // lint appears in newer versions of Rust pub const fn f64_from_bits(bits: u64) -> f64 { // SAFETY: POD cast with no preconditions unsafe { mem::transmute::(bits) } } /// `f64::to_bits` +#[allow(unnecessary_transmutes)] // lint appears in newer versions of Rust pub const fn f64_to_bits(x: f64) -> u64 { // SAFETY: POD cast with no preconditions unsafe { mem::transmute::(x) } -- cgit 1.4.1-3-g733a5 From 6d83a3226f1401d777da0a91019caf2c3191b685 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 29 Apr 2025 20:50:58 +0000 Subject: Move `fma` implementations to `mod generic` This will not build correctly, the move is done as a separate step from the rest of refactoring so git's history is cleaner. --- library/compiler-builtins/libm/src/math/fma.rs | 403 --------------------- .../compiler-builtins/libm/src/math/fma_wide.rs | 111 ------ .../compiler-builtins/libm/src/math/generic/fma.rs | 403 +++++++++++++++++++++ .../libm/src/math/generic/fma_wide.rs | 111 ++++++ 4 files changed, 514 insertions(+), 514 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/fma.rs delete mode 100644 library/compiler-builtins/libm/src/math/fma_wide.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fma.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fma_wide.rs diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs deleted file mode 100644 index 8856e63f596..00000000000 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ /dev/null @@ -1,403 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ - -use super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; -use super::{CastFrom, CastInto, Float, Int, MinInt}; - -/// Fused multiply add (f64) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fma(x: f64, y: f64, z: f64) -> f64 { - select_implementation! { - name: fma, - use_arch: all(target_arch = "aarch64", target_feature = "neon"), - args: x, y, z, - } - - fma_round(x, y, z, Round::Nearest).val -} - -/// Fused multiply add (f128) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { - fma_round(x, y, z, Round::Nearest).val -} - -/// Fused multiply-add that works when there is not a larger float size available. Computes -/// `(x * y) + z`. -#[inline] -pub fn fma_round(x: F, y: F, z: F, _round: Round) -> FpResult -where - F: Float, - F: CastFrom, - F: CastFrom, - F::Int: HInt, - u32: CastInto, -{ - let one = IntTy::::ONE; - let zero = IntTy::::ZERO; - - // Normalize such that the top of the mantissa is zero and we have a guard bit. - let nx = Norm::from_float(x); - let ny = Norm::from_float(y); - let nz = Norm::from_float(z); - - if nx.is_zero_nan_inf() || ny.is_zero_nan_inf() { - // Value will overflow, defer to non-fused operations. - return FpResult::ok(x * y + z); - } - - if nz.is_zero_nan_inf() { - if nz.is_zero() { - // Empty add component means we only need to multiply. - return FpResult::ok(x * y); - } - // `z` is NaN or infinity, which sets the result. - return FpResult::ok(z); - } - - // multiply: r = x * y - let zhi: F::Int; - let zlo: F::Int; - let (mut rlo, mut rhi) = nx.m.widen_mul(ny.m).lo_hi(); - - // Exponent result of multiplication - let mut e: i32 = nx.e + ny.e; - // Needed shift to align `z` to the multiplication result - let mut d: i32 = nz.e - e; - let sbits = F::BITS as i32; - - // Scale `z`. Shift `z <<= kz`, `r >>= kr`, so `kz+kr == d`, set `e = e+kr` (== ez-kz) - if d > 0 { - // The magnitude of `z` is larger than `x * y` - if d < sbits { - // Maximum shift of one `F::BITS` means shifted `z` will fit into `2 * F::BITS`. Shift - // it into `(zhi, zlo)`. No exponent adjustment necessary. - zlo = nz.m << d; - zhi = nz.m >> (sbits - d); - } else { - // Shift larger than `sbits`, `z` only needs the top half `zhi`. Place it there (acts - // as a shift by `sbits`). - zlo = zero; - zhi = nz.m; - d -= sbits; - - // `z`'s exponent is large enough that it now needs to be taken into account. - e = nz.e - sbits; - - if d == 0 { - // Exactly `sbits`, nothing to do - } else if d < sbits { - // Remaining shift fits within `sbits`. Leave `z` in place, shift `x * y` - rlo = (rhi << (sbits - d)) | (rlo >> d); - // Set the sticky bit - rlo |= IntTy::::from((rlo << (sbits - d)) != zero); - rhi = rhi >> d; - } else { - // `z`'s magnitude is enough that `x * y` is irrelevant. It was nonzero, so set - // the sticky bit. - rlo = one; - rhi = zero; - } - } - } else { - // `z`'s magnitude once shifted fits entirely within `zlo` - zhi = zero; - d = -d; - if d == 0 { - // No shift needed - zlo = nz.m; - } else if d < sbits { - // Shift s.t. `nz.m` fits into `zlo` - let sticky = IntTy::::from((nz.m << (sbits - d)) != zero); - zlo = (nz.m >> d) | sticky; - } else { - // Would be entirely shifted out, only set the sticky bit - zlo = one; - } - } - - /* addition */ - - let mut neg = nx.neg ^ ny.neg; - let samesign: bool = !neg ^ nz.neg; - let mut rhi_nonzero = true; - - if samesign { - // r += z - rlo = rlo.wrapping_add(zlo); - rhi += zhi + IntTy::::from(rlo < zlo); - } else { - // r -= z - let (res, borrow) = rlo.overflowing_sub(zlo); - rlo = res; - rhi = rhi.wrapping_sub(zhi.wrapping_add(IntTy::::from(borrow))); - if (rhi >> (F::BITS - 1)) != zero { - rlo = rlo.signed().wrapping_neg().unsigned(); - rhi = rhi.signed().wrapping_neg().unsigned() - IntTy::::from(rlo != zero); - neg = !neg; - } - rhi_nonzero = rhi != zero; - } - - /* Construct result */ - - // Shift result into `rhi`, left-aligned. Last bit is sticky - if rhi_nonzero { - // `d` > 0, need to shift both `rhi` and `rlo` into result - e += sbits; - d = rhi.leading_zeros() as i32 - 1; - rhi = (rhi << d) | (rlo >> (sbits - d)); - // Update sticky - rhi |= IntTy::::from((rlo << d) != zero); - } else if rlo != zero { - // `rhi` is zero, `rlo` is the entire result and needs to be shifted - d = rlo.leading_zeros() as i32 - 1; - if d < 0 { - // Shift and set sticky - rhi = (rlo >> 1) | (rlo & one); - } else { - rhi = rlo << d; - } - } else { - // exact +/- 0.0 - return FpResult::ok(x * y + z); - } - - e -= d; - - // Use int->float conversion to populate the significand. - // i is in [1 << (BITS - 2), (1 << (BITS - 1)) - 1] - let mut i: F::SignedInt = rhi.signed(); - - if neg { - i = -i; - } - - // `|r|` is in `[0x1p62,0x1p63]` for `f64` - let mut r: F = F::cast_from_lossy(i); - - /* Account for subnormal and rounding */ - - // Unbiased exponent for the maximum value of `r` - let max_pow = F::BITS - 1 + F::EXP_BIAS; - - let mut status = Status::OK; - - if e < -(max_pow as i32 - 2) { - // Result is subnormal before rounding - if e == -(max_pow as i32 - 1) { - let mut c = F::from_parts(false, max_pow, zero); - if neg { - c = -c; - } - - if r == c { - // Min normal after rounding, - status.set_underflow(true); - r = F::MIN_POSITIVE_NORMAL.copysign(r); - return FpResult::new(r, status); - } - - if (rhi << (F::SIG_BITS + 1)) != zero { - // Account for truncated bits. One bit will be lost in the `scalbn` call, add - // another top bit to avoid double rounding if inexact. - let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << (F::BITS - 2)); - i = iu.signed(); - - if neg { - i = -i; - } - - r = F::cast_from_lossy(i); - - // Remove the top bit - r = F::cast_from(2i8) * r - c; - status.set_underflow(true); - } - } else { - // Only round once when scaled - d = F::EXP_BITS as i32 - 1; - let sticky = IntTy::::from(rhi << (F::BITS as i32 - d) != zero); - i = (((rhi >> d) | sticky) << d).signed(); - - if neg { - i = -i; - } - - r = F::cast_from_lossy(i); - } - } - - // Use our exponent to scale the final value. - FpResult::new(super::generic::scalbn(r, e), status) -} - -/// Representation of `F` that has handled subnormals. -#[derive(Clone, Copy, Debug)] -struct Norm { - /// Normalized significand with one guard bit, unsigned. - m: F::Int, - /// Exponent of the mantissa such that `m * 2^e = x`. Accounts for the shift in the mantissa - /// and the guard bit; that is, 1.0 will normalize as `m = 1 << 53` and `e = -53`. - e: i32, - neg: bool, -} - -impl Norm { - /// Unbias the exponent and account for the mantissa's precision, including the guard bit. - const EXP_UNBIAS: u32 = F::EXP_BIAS + F::SIG_BITS + 1; - - /// Values greater than this had a saturated exponent (infinity or NaN), OR were zero and we - /// adjusted the exponent such that it exceeds this threashold. - const ZERO_INF_NAN: u32 = F::EXP_SAT - Self::EXP_UNBIAS; - - fn from_float(x: F) -> Self { - let mut ix = x.to_bits(); - let mut e = x.ex() as i32; - let neg = x.is_sign_negative(); - if e == 0 { - // Normalize subnormals by multiplication - let scale_i = F::BITS - 1; - let scale_f = F::from_parts(false, scale_i + F::EXP_BIAS, F::Int::ZERO); - let scaled = x * scale_f; - ix = scaled.to_bits(); - e = scaled.ex() as i32; - e = if e == 0 { - // If the exponent is still zero, the input was zero. Artifically set this value - // such that the final `e` will exceed `ZERO_INF_NAN`. - 1 << F::EXP_BITS - } else { - // Otherwise, account for the scaling we just did. - e - scale_i as i32 - }; - } - - e -= Self::EXP_UNBIAS as i32; - - // Absolute value, set the implicit bit, and shift to create a guard bit - ix &= F::SIG_MASK; - ix |= F::IMPLICIT_BIT; - ix <<= 1; - - Self { m: ix, e, neg } - } - - /// True if the value was zero, infinity, or NaN. - fn is_zero_nan_inf(self) -> bool { - self.e >= Self::ZERO_INF_NAN as i32 - } - - /// The only value we have - fn is_zero(self) -> bool { - // The only exponent that strictly exceeds this value is our sentinel value for zero. - self.e > Self::ZERO_INF_NAN as i32 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - /// Test the generic `fma_round` algorithm for a given float. - fn spec_test() - where - F: Float, - F: CastFrom, - F: CastFrom, - F::Int: HInt, - u32: CastInto, - { - let x = F::from_bits(F::Int::ONE); - let y = F::from_bits(F::Int::ONE); - let z = F::ZERO; - - let fma = |x, y, z| fma_round(x, y, z, Round::Nearest).val; - - // 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of - // fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the - // exact result" - assert_biteq!(fma(x, y, z), F::ZERO); - assert_biteq!(fma(x, -y, z), F::NEG_ZERO); - assert_biteq!(fma(-x, y, z), F::NEG_ZERO); - assert_biteq!(fma(-x, -y, z), F::ZERO); - } - - #[test] - fn spec_test_f32() { - spec_test::(); - } - - #[test] - fn spec_test_f64() { - spec_test::(); - - let expect_underflow = [ - ( - hf64!("0x1.0p-1070"), - hf64!("0x1.0p-1070"), - hf64!("0x1.ffffffffffffp-1023"), - hf64!("0x0.ffffffffffff8p-1022"), - ), - ( - // FIXME: we raise underflow but this should only be inexact (based on C and - // `rustc_apfloat`). - hf64!("0x1.0p-1070"), - hf64!("0x1.0p-1070"), - hf64!("-0x1.0p-1022"), - hf64!("-0x1.0p-1022"), - ), - ]; - - for (x, y, z, res) in expect_underflow { - let FpResult { val, status } = fma_round(x, y, z, Round::Nearest); - assert_biteq!(val, res); - assert_eq!(status, Status::UNDERFLOW); - } - } - - #[test] - #[cfg(f128_enabled)] - fn spec_test_f128() { - spec_test::(); - } - - #[test] - fn fma_segfault() { - // These two inputs cause fma to segfault on release due to overflow: - assert_eq!( - fma( - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313 - ), - -0.00000000000000022204460492503126, - ); - - let result = fma(-0.992, -0.992, -0.992); - //force rounding to storage format on x87 to prevent superious errors. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let result = force_eval!(result); - assert_eq!(result, -0.007936000000000007,); - } - - #[test] - fn fma_sbb() { - assert_eq!( - fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), - -3991680619069439e277 - ); - } - - #[test] - fn fma_underflow() { - assert_eq!( - fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), - 0.0, - ); - } -} diff --git a/library/compiler-builtins/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/src/math/fma_wide.rs deleted file mode 100644 index f268c2f144c..00000000000 --- a/library/compiler-builtins/libm/src/math/fma_wide.rs +++ /dev/null @@ -1,111 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/fmaf.c. Ported to generic Rust algorithm in 2025, TG. */ - -use super::support::{FpResult, IntTy, Round, Status}; -use super::{CastFrom, CastInto, DFloat, Float, HFloat, MinInt}; - -// Placeholder so we can have `fmaf16` in the `Float` trait. -#[allow(unused)] -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 { - unimplemented!() -} - -/// Floating multiply add (f32) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { - select_implementation! { - name: fmaf, - use_arch: all(target_arch = "aarch64", target_feature = "neon"), - args: x, y, z, - } - - fma_wide_round(x, y, z, Round::Nearest).val -} - -/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, -/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. -#[inline] -pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult -where - F: Float + HFloat, - B: Float + DFloat, - B::Int: CastInto, - i32: CastFrom, -{ - let one = IntTy::::ONE; - - let xy: B = x.widen() * y.widen(); - let mut result: B = xy + z.widen(); - let mut ui: B::Int = result.to_bits(); - let re = result.ex(); - let zb: B = z.widen(); - - let prec_diff = B::SIG_BITS - F::SIG_BITS; - let excess_prec = ui & ((one << prec_diff) - one); - let halfway = one << (prec_diff - 1); - - // Common case: the larger precision is fine if... - // This is not a halfway case - if excess_prec != halfway - // Or the result is NaN - || re == B::EXP_SAT - // Or the result is exact - || (result - xy == zb && result - zb == xy) - // Or the mode is something other than round to nearest - || round != Round::Nearest - { - let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; - let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; - - let mut status = Status::OK; - - if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() { - // This branch is never hit; requires previous operations to set a status - status.set_inexact(false); - - result = xy + z.widen(); - if status.inexact() { - status.set_underflow(true); - } else { - status.set_inexact(true); - } - } - - return FpResult { - val: result.narrow(), - status, - }; - } - - let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; - let err = if neg == (zb > xy) { - xy - result + zb - } else { - zb - result + xy - }; - if neg == (err < B::ZERO) { - ui += one; - } else { - ui -= one; - } - - FpResult::ok(B::from_bits(ui).narrow()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn issue_263() { - let a = f32::from_bits(1266679807); - let b = f32::from_bits(1300234242); - let c = f32::from_bits(1115553792); - let expected = f32::from_bits(1501560833); - assert_eq!(fmaf(a, b, c), expected); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs new file mode 100644 index 00000000000..8856e63f596 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ + +use super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; +use super::{CastFrom, CastInto, Float, Int, MinInt}; + +/// Fused multiply add (f64) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fma(x: f64, y: f64, z: f64) -> f64 { + select_implementation! { + name: fma, + use_arch: all(target_arch = "aarch64", target_feature = "neon"), + args: x, y, z, + } + + fma_round(x, y, z, Round::Nearest).val +} + +/// Fused multiply add (f128) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { + fma_round(x, y, z, Round::Nearest).val +} + +/// Fused multiply-add that works when there is not a larger float size available. Computes +/// `(x * y) + z`. +#[inline] +pub fn fma_round(x: F, y: F, z: F, _round: Round) -> FpResult +where + F: Float, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, +{ + let one = IntTy::::ONE; + let zero = IntTy::::ZERO; + + // Normalize such that the top of the mantissa is zero and we have a guard bit. + let nx = Norm::from_float(x); + let ny = Norm::from_float(y); + let nz = Norm::from_float(z); + + if nx.is_zero_nan_inf() || ny.is_zero_nan_inf() { + // Value will overflow, defer to non-fused operations. + return FpResult::ok(x * y + z); + } + + if nz.is_zero_nan_inf() { + if nz.is_zero() { + // Empty add component means we only need to multiply. + return FpResult::ok(x * y); + } + // `z` is NaN or infinity, which sets the result. + return FpResult::ok(z); + } + + // multiply: r = x * y + let zhi: F::Int; + let zlo: F::Int; + let (mut rlo, mut rhi) = nx.m.widen_mul(ny.m).lo_hi(); + + // Exponent result of multiplication + let mut e: i32 = nx.e + ny.e; + // Needed shift to align `z` to the multiplication result + let mut d: i32 = nz.e - e; + let sbits = F::BITS as i32; + + // Scale `z`. Shift `z <<= kz`, `r >>= kr`, so `kz+kr == d`, set `e = e+kr` (== ez-kz) + if d > 0 { + // The magnitude of `z` is larger than `x * y` + if d < sbits { + // Maximum shift of one `F::BITS` means shifted `z` will fit into `2 * F::BITS`. Shift + // it into `(zhi, zlo)`. No exponent adjustment necessary. + zlo = nz.m << d; + zhi = nz.m >> (sbits - d); + } else { + // Shift larger than `sbits`, `z` only needs the top half `zhi`. Place it there (acts + // as a shift by `sbits`). + zlo = zero; + zhi = nz.m; + d -= sbits; + + // `z`'s exponent is large enough that it now needs to be taken into account. + e = nz.e - sbits; + + if d == 0 { + // Exactly `sbits`, nothing to do + } else if d < sbits { + // Remaining shift fits within `sbits`. Leave `z` in place, shift `x * y` + rlo = (rhi << (sbits - d)) | (rlo >> d); + // Set the sticky bit + rlo |= IntTy::::from((rlo << (sbits - d)) != zero); + rhi = rhi >> d; + } else { + // `z`'s magnitude is enough that `x * y` is irrelevant. It was nonzero, so set + // the sticky bit. + rlo = one; + rhi = zero; + } + } + } else { + // `z`'s magnitude once shifted fits entirely within `zlo` + zhi = zero; + d = -d; + if d == 0 { + // No shift needed + zlo = nz.m; + } else if d < sbits { + // Shift s.t. `nz.m` fits into `zlo` + let sticky = IntTy::::from((nz.m << (sbits - d)) != zero); + zlo = (nz.m >> d) | sticky; + } else { + // Would be entirely shifted out, only set the sticky bit + zlo = one; + } + } + + /* addition */ + + let mut neg = nx.neg ^ ny.neg; + let samesign: bool = !neg ^ nz.neg; + let mut rhi_nonzero = true; + + if samesign { + // r += z + rlo = rlo.wrapping_add(zlo); + rhi += zhi + IntTy::::from(rlo < zlo); + } else { + // r -= z + let (res, borrow) = rlo.overflowing_sub(zlo); + rlo = res; + rhi = rhi.wrapping_sub(zhi.wrapping_add(IntTy::::from(borrow))); + if (rhi >> (F::BITS - 1)) != zero { + rlo = rlo.signed().wrapping_neg().unsigned(); + rhi = rhi.signed().wrapping_neg().unsigned() - IntTy::::from(rlo != zero); + neg = !neg; + } + rhi_nonzero = rhi != zero; + } + + /* Construct result */ + + // Shift result into `rhi`, left-aligned. Last bit is sticky + if rhi_nonzero { + // `d` > 0, need to shift both `rhi` and `rlo` into result + e += sbits; + d = rhi.leading_zeros() as i32 - 1; + rhi = (rhi << d) | (rlo >> (sbits - d)); + // Update sticky + rhi |= IntTy::::from((rlo << d) != zero); + } else if rlo != zero { + // `rhi` is zero, `rlo` is the entire result and needs to be shifted + d = rlo.leading_zeros() as i32 - 1; + if d < 0 { + // Shift and set sticky + rhi = (rlo >> 1) | (rlo & one); + } else { + rhi = rlo << d; + } + } else { + // exact +/- 0.0 + return FpResult::ok(x * y + z); + } + + e -= d; + + // Use int->float conversion to populate the significand. + // i is in [1 << (BITS - 2), (1 << (BITS - 1)) - 1] + let mut i: F::SignedInt = rhi.signed(); + + if neg { + i = -i; + } + + // `|r|` is in `[0x1p62,0x1p63]` for `f64` + let mut r: F = F::cast_from_lossy(i); + + /* Account for subnormal and rounding */ + + // Unbiased exponent for the maximum value of `r` + let max_pow = F::BITS - 1 + F::EXP_BIAS; + + let mut status = Status::OK; + + if e < -(max_pow as i32 - 2) { + // Result is subnormal before rounding + if e == -(max_pow as i32 - 1) { + let mut c = F::from_parts(false, max_pow, zero); + if neg { + c = -c; + } + + if r == c { + // Min normal after rounding, + status.set_underflow(true); + r = F::MIN_POSITIVE_NORMAL.copysign(r); + return FpResult::new(r, status); + } + + if (rhi << (F::SIG_BITS + 1)) != zero { + // Account for truncated bits. One bit will be lost in the `scalbn` call, add + // another top bit to avoid double rounding if inexact. + let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << (F::BITS - 2)); + i = iu.signed(); + + if neg { + i = -i; + } + + r = F::cast_from_lossy(i); + + // Remove the top bit + r = F::cast_from(2i8) * r - c; + status.set_underflow(true); + } + } else { + // Only round once when scaled + d = F::EXP_BITS as i32 - 1; + let sticky = IntTy::::from(rhi << (F::BITS as i32 - d) != zero); + i = (((rhi >> d) | sticky) << d).signed(); + + if neg { + i = -i; + } + + r = F::cast_from_lossy(i); + } + } + + // Use our exponent to scale the final value. + FpResult::new(super::generic::scalbn(r, e), status) +} + +/// Representation of `F` that has handled subnormals. +#[derive(Clone, Copy, Debug)] +struct Norm { + /// Normalized significand with one guard bit, unsigned. + m: F::Int, + /// Exponent of the mantissa such that `m * 2^e = x`. Accounts for the shift in the mantissa + /// and the guard bit; that is, 1.0 will normalize as `m = 1 << 53` and `e = -53`. + e: i32, + neg: bool, +} + +impl Norm { + /// Unbias the exponent and account for the mantissa's precision, including the guard bit. + const EXP_UNBIAS: u32 = F::EXP_BIAS + F::SIG_BITS + 1; + + /// Values greater than this had a saturated exponent (infinity or NaN), OR were zero and we + /// adjusted the exponent such that it exceeds this threashold. + const ZERO_INF_NAN: u32 = F::EXP_SAT - Self::EXP_UNBIAS; + + fn from_float(x: F) -> Self { + let mut ix = x.to_bits(); + let mut e = x.ex() as i32; + let neg = x.is_sign_negative(); + if e == 0 { + // Normalize subnormals by multiplication + let scale_i = F::BITS - 1; + let scale_f = F::from_parts(false, scale_i + F::EXP_BIAS, F::Int::ZERO); + let scaled = x * scale_f; + ix = scaled.to_bits(); + e = scaled.ex() as i32; + e = if e == 0 { + // If the exponent is still zero, the input was zero. Artifically set this value + // such that the final `e` will exceed `ZERO_INF_NAN`. + 1 << F::EXP_BITS + } else { + // Otherwise, account for the scaling we just did. + e - scale_i as i32 + }; + } + + e -= Self::EXP_UNBIAS as i32; + + // Absolute value, set the implicit bit, and shift to create a guard bit + ix &= F::SIG_MASK; + ix |= F::IMPLICIT_BIT; + ix <<= 1; + + Self { m: ix, e, neg } + } + + /// True if the value was zero, infinity, or NaN. + fn is_zero_nan_inf(self) -> bool { + self.e >= Self::ZERO_INF_NAN as i32 + } + + /// The only value we have + fn is_zero(self) -> bool { + // The only exponent that strictly exceeds this value is our sentinel value for zero. + self.e > Self::ZERO_INF_NAN as i32 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Test the generic `fma_round` algorithm for a given float. + fn spec_test() + where + F: Float, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, + { + let x = F::from_bits(F::Int::ONE); + let y = F::from_bits(F::Int::ONE); + let z = F::ZERO; + + let fma = |x, y, z| fma_round(x, y, z, Round::Nearest).val; + + // 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of + // fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the + // exact result" + assert_biteq!(fma(x, y, z), F::ZERO); + assert_biteq!(fma(x, -y, z), F::NEG_ZERO); + assert_biteq!(fma(-x, y, z), F::NEG_ZERO); + assert_biteq!(fma(-x, -y, z), F::ZERO); + } + + #[test] + fn spec_test_f32() { + spec_test::(); + } + + #[test] + fn spec_test_f64() { + spec_test::(); + + let expect_underflow = [ + ( + hf64!("0x1.0p-1070"), + hf64!("0x1.0p-1070"), + hf64!("0x1.ffffffffffffp-1023"), + hf64!("0x0.ffffffffffff8p-1022"), + ), + ( + // FIXME: we raise underflow but this should only be inexact (based on C and + // `rustc_apfloat`). + hf64!("0x1.0p-1070"), + hf64!("0x1.0p-1070"), + hf64!("-0x1.0p-1022"), + hf64!("-0x1.0p-1022"), + ), + ]; + + for (x, y, z, res) in expect_underflow { + let FpResult { val, status } = fma_round(x, y, z, Round::Nearest); + assert_biteq!(val, res); + assert_eq!(status, Status::UNDERFLOW); + } + } + + #[test] + #[cfg(f128_enabled)] + fn spec_test_f128() { + spec_test::(); + } + + #[test] + fn fma_segfault() { + // These two inputs cause fma to segfault on release due to overflow: + assert_eq!( + fma( + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313 + ), + -0.00000000000000022204460492503126, + ); + + let result = fma(-0.992, -0.992, -0.992); + //force rounding to storage format on x87 to prevent superious errors. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let result = force_eval!(result); + assert_eq!(result, -0.007936000000000007,); + } + + #[test] + fn fma_sbb() { + assert_eq!( + fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), + -3991680619069439e277 + ); + } + + #[test] + fn fma_underflow() { + assert_eq!( + fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), + 0.0, + ); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/fma_wide.rs b/library/compiler-builtins/libm/src/math/generic/fma_wide.rs new file mode 100644 index 00000000000..f268c2f144c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fma_wide.rs @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fmaf.c. Ported to generic Rust algorithm in 2025, TG. */ + +use super::support::{FpResult, IntTy, Round, Status}; +use super::{CastFrom, CastInto, DFloat, Float, HFloat, MinInt}; + +// Placeholder so we can have `fmaf16` in the `Float` trait. +#[allow(unused)] +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 { + unimplemented!() +} + +/// Floating multiply add (f32) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { + select_implementation! { + name: fmaf, + use_arch: all(target_arch = "aarch64", target_feature = "neon"), + args: x, y, z, + } + + fma_wide_round(x, y, z, Round::Nearest).val +} + +/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, +/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. +#[inline] +pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult +where + F: Float + HFloat, + B: Float + DFloat, + B::Int: CastInto, + i32: CastFrom, +{ + let one = IntTy::::ONE; + + let xy: B = x.widen() * y.widen(); + let mut result: B = xy + z.widen(); + let mut ui: B::Int = result.to_bits(); + let re = result.ex(); + let zb: B = z.widen(); + + let prec_diff = B::SIG_BITS - F::SIG_BITS; + let excess_prec = ui & ((one << prec_diff) - one); + let halfway = one << (prec_diff - 1); + + // Common case: the larger precision is fine if... + // This is not a halfway case + if excess_prec != halfway + // Or the result is NaN + || re == B::EXP_SAT + // Or the result is exact + || (result - xy == zb && result - zb == xy) + // Or the mode is something other than round to nearest + || round != Round::Nearest + { + let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; + let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; + + let mut status = Status::OK; + + if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() { + // This branch is never hit; requires previous operations to set a status + status.set_inexact(false); + + result = xy + z.widen(); + if status.inexact() { + status.set_underflow(true); + } else { + status.set_inexact(true); + } + } + + return FpResult { + val: result.narrow(), + status, + }; + } + + let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; + let err = if neg == (zb > xy) { + xy - result + zb + } else { + zb - result + xy + }; + if neg == (err < B::ZERO) { + ui += one; + } else { + ui -= one; + } + + FpResult::ok(B::from_bits(ui).narrow()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn issue_263() { + let a = f32::from_bits(1266679807); + let b = f32::from_bits(1300234242); + let c = f32::from_bits(1115553792); + let expected = f32::from_bits(1501560833); + assert_eq!(fmaf(a, b, c), expected); + } +} -- cgit 1.4.1-3-g733a5 From caf337d46742aca1705c3254e8d45d7238a8435c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 29 Apr 2025 20:52:54 +0000 Subject: Refactor the fma modules Move implementations to `generic/` like the other functions. This also allows us to combine the `fma` and `fma_wide` modules. --- .../etc/function-definitions.json | 2 +- library/compiler-builtins/libm/src/math/fma.rs | 165 +++++++++++++++++++++ .../compiler-builtins/libm/src/math/generic/fma.rs | 133 +---------------- .../libm/src/math/generic/fma_wide.rs | 44 +----- .../compiler-builtins/libm/src/math/generic/mod.rs | 4 + library/compiler-builtins/libm/src/math/mod.rs | 6 +- 6 files changed, 179 insertions(+), 175 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fma.rs diff --git a/library/compiler-builtins/etc/function-definitions.json b/library/compiler-builtins/etc/function-definitions.json index 3e33343c464..9e5774eaf0a 100644 --- a/library/compiler-builtins/etc/function-definitions.json +++ b/library/compiler-builtins/etc/function-definitions.json @@ -350,7 +350,7 @@ "fmaf": { "sources": [ "libm/src/math/arch/aarch64.rs", - "libm/src/math/fma_wide.rs" + "libm/src/math/fma.rs" ], "type": "f32" }, diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs new file mode 100644 index 00000000000..78f0f8992ea --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fma.c, fmaf.c Ported to generic Rust algorithm in 2025, TG. */ + +use super::generic; +use crate::support::Round; + +// Placeholder so we can have `fmaf16` in the `Float` trait. +#[allow(unused)] +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 { + unimplemented!() +} + +/// Floating multiply add (f32) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { + select_implementation! { + name: fmaf, + use_arch: all(target_arch = "aarch64", target_feature = "neon"), + args: x, y, z, + } + + generic::fma_wide_round(x, y, z, Round::Nearest).val +} + +/// Fused multiply add (f64) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fma(x: f64, y: f64, z: f64) -> f64 { + select_implementation! { + name: fma, + use_arch: all(target_arch = "aarch64", target_feature = "neon"), + args: x, y, z, + } + + generic::fma_round(x, y, z, Round::Nearest).val +} + +/// Fused multiply add (f128) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { + generic::fma_round(x, y, z, Round::Nearest).val +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{CastFrom, CastInto, Float, FpResult, HInt, MinInt, Round, Status}; + + /// Test the generic `fma_round` algorithm for a given float. + fn spec_test(f: impl Fn(F, F, F) -> F) + where + F: Float, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, + { + let x = F::from_bits(F::Int::ONE); + let y = F::from_bits(F::Int::ONE); + let z = F::ZERO; + + // 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of + // fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the + // exact result" + assert_biteq!(f(x, y, z), F::ZERO); + assert_biteq!(f(x, -y, z), F::NEG_ZERO); + assert_biteq!(f(-x, y, z), F::NEG_ZERO); + assert_biteq!(f(-x, -y, z), F::ZERO); + } + + #[test] + fn spec_test_f32() { + spec_test::(fmaf); + + // Also do a small check that the non-widening version works for f32 (this should ideally + // get tested some more). + spec_test::(|x, y, z| generic::fma_round(x, y, z, Round::Nearest).val); + } + + #[test] + fn spec_test_f64() { + spec_test::(fma); + + let expect_underflow = [ + ( + hf64!("0x1.0p-1070"), + hf64!("0x1.0p-1070"), + hf64!("0x1.ffffffffffffp-1023"), + hf64!("0x0.ffffffffffff8p-1022"), + ), + ( + // FIXME: we raise underflow but this should only be inexact (based on C and + // `rustc_apfloat`). + hf64!("0x1.0p-1070"), + hf64!("0x1.0p-1070"), + hf64!("-0x1.0p-1022"), + hf64!("-0x1.0p-1022"), + ), + ]; + + for (x, y, z, res) in expect_underflow { + let FpResult { val, status } = generic::fma_round(x, y, z, Round::Nearest); + assert_biteq!(val, res); + assert_eq!(status, Status::UNDERFLOW); + } + } + + #[test] + #[cfg(f128_enabled)] + fn spec_test_f128() { + spec_test::(fmaf128); + } + + #[test] + fn issue_263() { + let a = f32::from_bits(1266679807); + let b = f32::from_bits(1300234242); + let c = f32::from_bits(1115553792); + let expected = f32::from_bits(1501560833); + assert_eq!(fmaf(a, b, c), expected); + } + + #[test] + fn fma_segfault() { + // These two inputs cause fma to segfault on release due to overflow: + assert_eq!( + fma( + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313 + ), + -0.00000000000000022204460492503126, + ); + + let result = fma(-0.992, -0.992, -0.992); + //force rounding to storage format on x87 to prevent superious errors. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let result = force_eval!(result); + assert_eq!(result, -0.007936000000000007,); + } + + #[test] + fn fma_sbb() { + assert_eq!( + fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), + -3991680619069439e277 + ); + } + + #[test] + fn fma_underflow() { + assert_eq!( + fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), + 0.0, + ); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs index 8856e63f596..aaf459d1b61 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -1,31 +1,9 @@ /* SPDX-License-Identifier: MIT */ /* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ -use super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; -use super::{CastFrom, CastInto, Float, Int, MinInt}; - -/// Fused multiply add (f64) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fma(x: f64, y: f64, z: f64) -> f64 { - select_implementation! { - name: fma, - use_arch: all(target_arch = "aarch64", target_feature = "neon"), - args: x, y, z, - } - - fma_round(x, y, z, Round::Nearest).val -} - -/// Fused multiply add (f128) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg(f128_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { - fma_round(x, y, z, Round::Nearest).val -} +use crate::support::{ + CastFrom, CastInto, DInt, Float, FpResult, HInt, Int, IntTy, MinInt, Round, Status, +}; /// Fused multiply-add that works when there is not a larger float size available. Computes /// `(x * y) + z`. @@ -234,7 +212,7 @@ where } // Use our exponent to scale the final value. - FpResult::new(super::generic::scalbn(r, e), status) + FpResult::new(super::scalbn(r, e), status) } /// Representation of `F` that has handled subnormals. @@ -298,106 +276,3 @@ impl Norm { self.e > Self::ZERO_INF_NAN as i32 } } - -#[cfg(test)] -mod tests { - use super::*; - - /// Test the generic `fma_round` algorithm for a given float. - fn spec_test() - where - F: Float, - F: CastFrom, - F: CastFrom, - F::Int: HInt, - u32: CastInto, - { - let x = F::from_bits(F::Int::ONE); - let y = F::from_bits(F::Int::ONE); - let z = F::ZERO; - - let fma = |x, y, z| fma_round(x, y, z, Round::Nearest).val; - - // 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of - // fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the - // exact result" - assert_biteq!(fma(x, y, z), F::ZERO); - assert_biteq!(fma(x, -y, z), F::NEG_ZERO); - assert_biteq!(fma(-x, y, z), F::NEG_ZERO); - assert_biteq!(fma(-x, -y, z), F::ZERO); - } - - #[test] - fn spec_test_f32() { - spec_test::(); - } - - #[test] - fn spec_test_f64() { - spec_test::(); - - let expect_underflow = [ - ( - hf64!("0x1.0p-1070"), - hf64!("0x1.0p-1070"), - hf64!("0x1.ffffffffffffp-1023"), - hf64!("0x0.ffffffffffff8p-1022"), - ), - ( - // FIXME: we raise underflow but this should only be inexact (based on C and - // `rustc_apfloat`). - hf64!("0x1.0p-1070"), - hf64!("0x1.0p-1070"), - hf64!("-0x1.0p-1022"), - hf64!("-0x1.0p-1022"), - ), - ]; - - for (x, y, z, res) in expect_underflow { - let FpResult { val, status } = fma_round(x, y, z, Round::Nearest); - assert_biteq!(val, res); - assert_eq!(status, Status::UNDERFLOW); - } - } - - #[test] - #[cfg(f128_enabled)] - fn spec_test_f128() { - spec_test::(); - } - - #[test] - fn fma_segfault() { - // These two inputs cause fma to segfault on release due to overflow: - assert_eq!( - fma( - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313 - ), - -0.00000000000000022204460492503126, - ); - - let result = fma(-0.992, -0.992, -0.992); - //force rounding to storage format on x87 to prevent superious errors. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let result = force_eval!(result); - assert_eq!(result, -0.007936000000000007,); - } - - #[test] - fn fma_sbb() { - assert_eq!( - fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), - -3991680619069439e277 - ); - } - - #[test] - fn fma_underflow() { - assert_eq!( - fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), - 0.0, - ); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fma_wide.rs b/library/compiler-builtins/libm/src/math/generic/fma_wide.rs index f268c2f144c..a2ef59d3e3d 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma_wide.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma_wide.rs @@ -1,30 +1,6 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/fmaf.c. Ported to generic Rust algorithm in 2025, TG. */ - -use super::support::{FpResult, IntTy, Round, Status}; -use super::{CastFrom, CastInto, DFloat, Float, HFloat, MinInt}; - -// Placeholder so we can have `fmaf16` in the `Float` trait. -#[allow(unused)] -#[cfg(f16_enabled)] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 { - unimplemented!() -} - -/// Floating multiply add (f32) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { - select_implementation! { - name: fmaf, - use_arch: all(target_arch = "aarch64", target_feature = "neon"), - args: x, y, z, - } - - fma_wide_round(x, y, z, Round::Nearest).val -} +use crate::support::{ + CastFrom, CastInto, DFloat, Float, FpResult, HFloat, IntTy, MinInt, Round, Status, +}; /// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, /// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. @@ -95,17 +71,3 @@ where FpResult::ok(B::from_bits(ui).narrow()) } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn issue_263() { - let a = f32::from_bits(1266679807); - let b = f32::from_bits(1300234242); - let c = f32::from_bits(1115553792); - let expected = f32::from_bits(1501560833); - assert_eq!(fmaf(a, b, c), expected); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 35846351a6e..9d497a03f54 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -6,6 +6,8 @@ mod copysign; mod fabs; mod fdim; mod floor; +mod fma; +mod fma_wide; mod fmax; mod fmaximum; mod fmaximum_num; @@ -24,6 +26,8 @@ pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; +pub use fma::fma_round; +pub use fma_wide::fma_wide_round; pub use fmax::fmax; pub use fmaximum::fmaximum; pub use fmaximum_num::fmaximum_num; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 949c18b4000..ce9b8fc58bb 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -159,7 +159,6 @@ mod fabs; mod fdim; mod floor; mod fma; -mod fma_wide; mod fmin_fmax; mod fminimum_fmaximum; mod fminimum_fmaximum_num; @@ -254,8 +253,7 @@ pub use self::expm1f::expm1f; pub use self::fabs::{fabs, fabsf}; pub use self::fdim::{fdim, fdimf}; pub use self::floor::{floor, floorf}; -pub use self::fma::fma; -pub use self::fma_wide::fmaf; +pub use self::fma::{fma, fmaf}; pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; pub use self::fminimum_fmaximum::{fmaximum, fmaximumf, fminimum, fminimumf}; pub use self::fminimum_fmaximum_num::{fmaximum_num, fmaximum_numf, fminimum_num, fminimum_numf}; @@ -336,7 +334,7 @@ cfg_if! { // verify-sorted-end #[allow(unused_imports)] - pub(crate) use self::fma_wide::fmaf16; + pub(crate) use self::fma::fmaf16; } } -- cgit 1.4.1-3-g733a5 From 4c2659f9cee7829bea317d5c6f575a7f4fb13628 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 1 May 2025 18:52:12 +0000 Subject: builtins-test: Remove `no_mangle` from `eh_personality` Rustc now mangles these symbols on its own, so `no_mangle` is rejected as an error. --- library/compiler-builtins/builtins-test-intrinsics/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs index 18f943eff35..1fa7b00916f 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -682,7 +682,6 @@ pub fn _Unwind_Resume() {} #[cfg(not(any(windows, target_os = "cygwin")))] #[lang = "eh_personality"] -#[unsafe(no_mangle)] pub extern "C" fn eh_personality() {} #[cfg(any(all(windows, target_env = "gnu"), target_os = "cygwin"))] -- cgit 1.4.1-3-g733a5 From 1c5f8cc72df4b82f2265737c9e86a4e4365cae8c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 May 2025 00:46:21 +0000 Subject: fmaf: Add a test case from a MinGW failure This is a known problem in the MinGW fmaf implementation, identified at [1]. Make sure our implementation passes this edge case. [1]: https://github.com/rust-lang/rust/issues/140515 --- .../compiler-builtins/libm-test/src/generate/case_list.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index f1e6fcec397..43b28722f2d 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -269,7 +269,18 @@ fn fma_cases() -> Vec> { } fn fmaf_cases() -> Vec> { - vec![] + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Known rounding error for some implementations (notably MinGW) + ( + (-1.9369631e13f32, 2.1513551e-7, -1.7354427e-24), + Some(-4167095.8), + ), + ], + ); + v } #[cfg(f128_enabled)] -- cgit 1.4.1-3-g733a5 From 2705f686b556c179fd56f2f496ed69eb7b06c97d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 1 May 2025 18:41:05 +0000 Subject: update-api-list: Match subdirectories within arch --- library/compiler-builtins/etc/update-api-list.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/etc/update-api-list.py b/library/compiler-builtins/etc/update-api-list.py index 0770a8b20fb..28ff22f4cbb 100755 --- a/library/compiler-builtins/etc/update-api-list.py +++ b/library/compiler-builtins/etc/update-api-list.py @@ -123,7 +123,9 @@ class Crate: # A lot of the `arch` module is often configured out so doesn't show up in docs. Use # string matching as a fallback. - for fname in glob("libm/src/math/arch/**.rs", root_dir=ROOT_DIR): + for fname in glob( + "libm/src/math/arch/**/*.rs", root_dir=ROOT_DIR, recursive=True + ): contents = (ROOT_DIR.joinpath(fname)).read_text() for name in self.public_functions: -- cgit 1.4.1-3-g733a5 From 4a1dc96652ea5cbd7e0273df19c828324699f4db Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 1 May 2025 17:49:56 +0000 Subject: Rename the i686 module to x86 This module is used for both i686 and x86-64. --- .../etc/function-definitions.json | 4 ++-- .../compiler-builtins/libm/src/math/arch/i686.rs | 27 ---------------------- .../compiler-builtins/libm/src/math/arch/mod.rs | 4 ++-- .../compiler-builtins/libm/src/math/arch/x86.rs | 27 ++++++++++++++++++++++ 4 files changed, 31 insertions(+), 31 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/arch/i686.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/x86.rs diff --git a/library/compiler-builtins/etc/function-definitions.json b/library/compiler-builtins/etc/function-definitions.json index 9e5774eaf0a..691205ddffe 100644 --- a/library/compiler-builtins/etc/function-definitions.json +++ b/library/compiler-builtins/etc/function-definitions.json @@ -932,8 +932,8 @@ "sqrt": { "sources": [ "libm/src/math/arch/aarch64.rs", - "libm/src/math/arch/i686.rs", "libm/src/math/arch/wasm32.rs", + "libm/src/math/arch/x86.rs", "libm/src/math/generic/sqrt.rs", "libm/src/math/sqrt.rs" ], @@ -942,8 +942,8 @@ "sqrtf": { "sources": [ "libm/src/math/arch/aarch64.rs", - "libm/src/math/arch/i686.rs", "libm/src/math/arch/wasm32.rs", + "libm/src/math/arch/x86.rs", "libm/src/math/generic/sqrt.rs", "libm/src/math/sqrt.rs" ], diff --git a/library/compiler-builtins/libm/src/math/arch/i686.rs b/library/compiler-builtins/libm/src/math/arch/i686.rs deleted file mode 100644 index 3e1d19bfab6..00000000000 --- a/library/compiler-builtins/libm/src/math/arch/i686.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Architecture-specific support for x86-32 and x86-64 with SSE2 - -pub fn sqrtf(mut x: f32) -> f32 { - // SAFETY: `sqrtss` is part of `sse2`, which this module is gated behind. It has no memory - // access or side effects. - unsafe { - core::arch::asm!( - "sqrtss {x}, {x}", - x = inout(xmm_reg) x, - options(nostack, nomem, pure), - ) - }; - x -} - -pub fn sqrt(mut x: f64) -> f64 { - // SAFETY: `sqrtsd` is part of `sse2`, which this module is gated behind. It has no memory - // access or side effects. - unsafe { - core::arch::asm!( - "sqrtsd {x}, {x}", - x = inout(xmm_reg) x, - options(nostack, nomem, pure), - ) - }; - x -} diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index d9f2aad66d4..67352f90cc2 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -15,8 +15,8 @@ cfg_if! { ceil, ceilf, fabs, fabsf, floor, floorf, rint, rintf, sqrt, sqrtf, trunc, truncf, }; } else if #[cfg(target_feature = "sse2")] { - mod i686; - pub use i686::{sqrt, sqrtf}; + mod x86; + pub use x86::{sqrt, sqrtf}; } else if #[cfg(all( any(target_arch = "aarch64", target_arch = "arm64ec"), target_feature = "neon" diff --git a/library/compiler-builtins/libm/src/math/arch/x86.rs b/library/compiler-builtins/libm/src/math/arch/x86.rs new file mode 100644 index 00000000000..3e1d19bfab6 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/x86.rs @@ -0,0 +1,27 @@ +//! Architecture-specific support for x86-32 and x86-64 with SSE2 + +pub fn sqrtf(mut x: f32) -> f32 { + // SAFETY: `sqrtss` is part of `sse2`, which this module is gated behind. It has no memory + // access or side effects. + unsafe { + core::arch::asm!( + "sqrtss {x}, {x}", + x = inout(xmm_reg) x, + options(nostack, nomem, pure), + ) + }; + x +} + +pub fn sqrt(mut x: f64) -> f64 { + // SAFETY: `sqrtsd` is part of `sse2`, which this module is gated behind. It has no memory + // access or side effects. + unsafe { + core::arch::asm!( + "sqrtsd {x}, {x}", + x = inout(xmm_reg) x, + options(nostack, nomem, pure), + ) + }; + x +} -- cgit 1.4.1-3-g733a5 From 8995ac0448312c94f85ffe3ec92e44b85834aead Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 29 Apr 2025 22:16:41 +0000 Subject: Use runtime feature detection for fma routines on x86 Get performance closer to the glibc implementations by adding assembly fma routines, with runtime feature detection so they are used even if not compiled with `+fma` (as the distributed standard library is often not). Glibc uses ifuncs, this implementation stores a function pointer in an atomic. Results of CPU flags are also cached in order to avoid repeating the startup time in calls to different functions. The feature detection code is a slightly simplified version of `std-detect`. Musl sources were used as a reference [1]. Fixes: https://github.com/rust-lang/rust/issues/140452 once synced [1]: https://github.com/bminor/musl/blob/c47ad25ea3b484e10326f933e927c0bc8cded3da/src/math/x32/fma.c --- .../etc/function-definitions.json | 2 + .../compiler-builtins/libm/src/math/arch/mod.rs | 2 +- .../compiler-builtins/libm/src/math/arch/x86.rs | 5 + .../libm/src/math/arch/x86/detect.rs | 229 +++++++++++++++++++++ .../libm/src/math/arch/x86/fma.rs | 134 ++++++++++++ library/compiler-builtins/libm/src/math/fma.rs | 10 +- .../libm/src/math/support/feature_detect.rs | 206 ++++++++++++++++++ .../compiler-builtins/libm/src/math/support/mod.rs | 3 + 8 files changed, 588 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/arch/x86/detect.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/x86/fma.rs create mode 100644 library/compiler-builtins/libm/src/math/support/feature_detect.rs diff --git a/library/compiler-builtins/etc/function-definitions.json b/library/compiler-builtins/etc/function-definitions.json index 691205ddffe..4f796905b75 100644 --- a/library/compiler-builtins/etc/function-definitions.json +++ b/library/compiler-builtins/etc/function-definitions.json @@ -343,6 +343,7 @@ "fma": { "sources": [ "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/x86/fma.rs", "libm/src/math/fma.rs" ], "type": "f64" @@ -350,6 +351,7 @@ "fmaf": { "sources": [ "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/x86/fma.rs", "libm/src/math/fma.rs" ], "type": "f32" diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index 67352f90cc2..984ae7f3129 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -16,7 +16,7 @@ cfg_if! { }; } else if #[cfg(target_feature = "sse2")] { mod x86; - pub use x86::{sqrt, sqrtf}; + pub use x86::{sqrt, sqrtf, fma, fmaf}; } else if #[cfg(all( any(target_arch = "aarch64", target_arch = "arm64ec"), target_feature = "neon" diff --git a/library/compiler-builtins/libm/src/math/arch/x86.rs b/library/compiler-builtins/libm/src/math/arch/x86.rs index 3e1d19bfab6..454aa285074 100644 --- a/library/compiler-builtins/libm/src/math/arch/x86.rs +++ b/library/compiler-builtins/libm/src/math/arch/x86.rs @@ -1,5 +1,10 @@ //! Architecture-specific support for x86-32 and x86-64 with SSE2 +mod detect; +mod fma; + +pub use fma::{fma, fmaf}; + pub fn sqrtf(mut x: f32) -> f32 { // SAFETY: `sqrtss` is part of `sse2`, which this module is gated behind. It has no memory // access or side effects. diff --git a/library/compiler-builtins/libm/src/math/arch/x86/detect.rs b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs new file mode 100644 index 00000000000..71c3281dc55 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs @@ -0,0 +1,229 @@ +#[cfg(target_arch = "x86")] +use core::arch::x86::{__cpuid, __cpuid_count, _xgetbv, CpuidResult}; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::{__cpuid, __cpuid_count, _xgetbv, CpuidResult}; + +use crate::support::{Flags, get_or_init_flags_cache}; + +/// CPU features that get cached (doesn't correlate to anything on the CPU). +pub mod cpu_flags { + use crate::support::unique_masks; + + unique_masks! { + u32, + SSE3, + F16C, + SSE, + SSE2, + ERMSB, + MOVRS, + FMA, + FMA4, + AVX512FP16, + AVX512BF16, + } +} + +/// Get CPU features, loading from a cache if available. +pub fn get_cpu_features() -> Flags { + use core::sync::atomic::AtomicU32; + static CACHE: AtomicU32 = AtomicU32::new(0); + get_or_init_flags_cache(&CACHE, load_x86_features) +} + +/// Read from cpuid and translate to a `Flags` instance, using `cpu_flags`. +/// +/// Implementation is taken from [std-detect][std-detect]. +/// +/// [std-detect]: https://github.com/rust-lang/stdarch/blob/690b3a6334d482874163bd6fcef408e0518febe9/crates/std_detect/src/detect/os/x86.rs#L142 +fn load_x86_features() -> Flags { + let mut value = Flags::empty(); + + if cfg!(target_env = "sgx") { + // doesn't support this because it is untrusted data + return Flags::empty(); + } + + // 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 mut vendor_id = [0u8; 12]; + let max_basic_leaf; + unsafe { + let CpuidResult { eax, ebx, ecx, edx } = __cpuid(0); + max_basic_leaf = eax; + vendor_id[0..4].copy_from_slice(&ebx.to_ne_bytes()); + vendor_id[4..8].copy_from_slice(&edx.to_ne_bytes()); + vendor_id[8..12].copy_from_slice(&ecx.to_ne_bytes()); + } + + 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, edx, .. } = unsafe { __cpuid(0x0000_0001_u32) }; + let proc_info_ecx = Flags::from_bits(ecx); + let proc_info_edx = Flags::from_bits(edx); + + // EAX = 7: Queries "Extended Features"; + // Contains information about bmi,bmi2, and avx2 support. + let mut extended_features_ebx = Flags::empty(); + let mut extended_features_edx = Flags::empty(); + let mut extended_features_eax_leaf_1 = Flags::empty(); + if max_basic_leaf >= 7 { + let CpuidResult { ebx, edx, .. } = unsafe { __cpuid(0x0000_0007_u32) }; + extended_features_ebx = Flags::from_bits(ebx); + extended_features_edx = Flags::from_bits(edx); + + let CpuidResult { eax, .. } = unsafe { __cpuid_count(0x0000_0007_u32, 0x0000_0001_u32) }; + extended_features_eax_leaf_1 = Flags::from_bits(eax) + } + + // 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 extended_max_basic_leaf = unsafe { __cpuid(0x8000_0000_u32) }.eax; + + // EAX = 0x8000_0001, ECX=0: Queries "Extended Processor Info and Feature Bits" + let mut extended_proc_info_ecx = Flags::empty(); + if extended_max_basic_leaf >= 1 { + let CpuidResult { ecx, .. } = unsafe { __cpuid(0x8000_0001_u32) }; + extended_proc_info_ecx = Flags::from_bits(ecx); + } + + let mut enable = |regflags: Flags, regbit, flag| { + if regflags.test_nth(regbit) { + value.insert(flag); + } + }; + + enable(proc_info_ecx, 0, cpu_flags::SSE3); + enable(proc_info_ecx, 29, cpu_flags::F16C); + enable(proc_info_edx, 25, cpu_flags::SSE); + enable(proc_info_edx, 26, cpu_flags::SSE2); + enable(extended_features_ebx, 9, cpu_flags::ERMSB); + enable(extended_features_eax_leaf_1, 31, cpu_flags::MOVRS); + + // `XSAVE` and `AVX` support: + let cpu_xsave = proc_info_ecx.test_nth(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 = proc_info_ecx.test_nth(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; + + // 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)" + + // FMA (uses 256-bit wide registers): + enable(proc_info_ecx, 12, cpu_flags::FMA); + + // For AVX-512 the OS also needs to support saving/restoring + // the extended state, only then we enable AVX-512 support: + if os_avx512_support { + enable(extended_features_edx, 23, cpu_flags::AVX512FP16); + enable(extended_features_eax_leaf_1, 5, cpu_flags::AVX512BF16); + } + } + } + } + + // 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 + // (AMD64 Architecture Programmer's Manual, Appendix E). + // 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, 16, cpu_flags::FMA4); + } + + value +} + +#[cfg(test)] +mod tests { + extern crate std; + use std::is_x86_feature_detected; + + use super::*; + + #[test] + fn check_matches_std() { + let features = get_cpu_features(); + for i in 0..cpu_flags::ALL.len() { + let flag = cpu_flags::ALL[i]; + let name = cpu_flags::NAMES[i]; + + let std_detected = match flag { + cpu_flags::SSE3 => is_x86_feature_detected!("sse3"), + cpu_flags::F16C => is_x86_feature_detected!("f16c"), + cpu_flags::SSE => is_x86_feature_detected!("sse"), + cpu_flags::SSE2 => is_x86_feature_detected!("sse2"), + cpu_flags::ERMSB => is_x86_feature_detected!("ermsb"), + cpu_flags::MOVRS => continue, // only very recent support in std + cpu_flags::FMA => is_x86_feature_detected!("fma"), + cpu_flags::FMA4 => continue, // not yet supported in std + cpu_flags::AVX512FP16 => is_x86_feature_detected!("avx512fp16"), + cpu_flags::AVX512BF16 => is_x86_feature_detected!("avx512bf16"), + _ => panic!("untested CPU flag {name}"), + }; + + assert_eq!( + std_detected, + features.contains(flag), + "different flag {name}. flags: {features:?}" + ); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/arch/x86/fma.rs b/library/compiler-builtins/libm/src/math/arch/x86/fma.rs new file mode 100644 index 00000000000..eb43f4696d7 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/x86/fma.rs @@ -0,0 +1,134 @@ +//! Use assembly fma if the `fma` or `fma4` feature is detected at runtime. + +use core::arch::asm; + +use super::super::super::generic; +use super::detect::{cpu_flags, get_cpu_features}; +use crate::support::{Round, select_once}; + +pub fn fma(x: f64, y: f64, z: f64) -> f64 { + select_once! { + sig: fn(x: f64, y: f64, z: f64) -> f64, + init: || { + let features = get_cpu_features(); + if features.contains(cpu_flags::FMA) { + fma_with_fma + } else if features.contains(cpu_flags::FMA4) { + fma_with_fma4 + } else { + fma_fallback as Func + } + }, + // SAFETY: `fn_ptr` is the result of `init`, preconditions have been checked. + call: |fn_ptr: Func| unsafe { fn_ptr(x, y, z) }, + } +} + +pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { + select_once! { + sig: fn(x: f32, y: f32, z: f32) -> f32, + init: || { + let features = get_cpu_features(); + if features.contains(cpu_flags::FMA) { + fmaf_with_fma + } else if features.contains(cpu_flags::FMA4) { + fmaf_with_fma4 + } else { + fmaf_fallback as Func + } + }, + // SAFETY: `fn_ptr` is the result of `init`, preconditions have been checked. + call: |fn_ptr: Func| unsafe { fn_ptr(x, y, z) }, + } +} + +/// # Safety +/// +/// Must have +fma available. +unsafe fn fma_with_fma(mut x: f64, y: f64, z: f64) -> f64 { + debug_assert!(get_cpu_features().contains(cpu_flags::FMA)); + + // SAFETY: fma is asserted available by precondition, which provides the instruction. No + // memory access or side effects. + unsafe { + asm!( + "vfmadd213sd {x}, {y}, {z}", + x = inout(xmm_reg) x, + y = in(xmm_reg) y, + z = in(xmm_reg) z, + options(nostack, nomem, pure), + ); + } + x +} + +/// # Safety +/// +/// Must have +fma available. +unsafe fn fmaf_with_fma(mut x: f32, y: f32, z: f32) -> f32 { + debug_assert!(get_cpu_features().contains(cpu_flags::FMA)); + + // SAFETY: fma is asserted available by precondition, which provides the instruction. No + // memory access or side effects. + unsafe { + asm!( + "vfmadd213ss {x}, {y}, {z}", + x = inout(xmm_reg) x, + y = in(xmm_reg) y, + z = in(xmm_reg) z, + options(nostack, nomem, pure), + ); + } + x +} + +/// # Safety +/// +/// Must have +fma4 available. +unsafe fn fma_with_fma4(mut x: f64, y: f64, z: f64) -> f64 { + debug_assert!(get_cpu_features().contains(cpu_flags::FMA4)); + + // SAFETY: fma4 is asserted available by precondition, which provides the instruction. No + // memory access or side effects. + unsafe { + asm!( + "vfmaddsd {x}, {x}, {y}, {z}", + x = inout(xmm_reg) x, + y = in(xmm_reg) y, + z = in(xmm_reg) z, + options(nostack, nomem, pure), + ); + } + x +} + +/// # Safety +/// +/// Must have +fma4 available. +unsafe fn fmaf_with_fma4(mut x: f32, y: f32, z: f32) -> f32 { + debug_assert!(get_cpu_features().contains(cpu_flags::FMA4)); + + // SAFETY: fma4 is asserted available by precondition, which provides the instruction. No + // memory access or side effects. + unsafe { + asm!( + "vfmaddss {x}, {x}, {y}, {z}", + x = inout(xmm_reg) x, + y = in(xmm_reg) y, + z = in(xmm_reg) z, + options(nostack, nomem, pure), + ); + } + x +} + +// FIXME: the `select_implementation` macro should handle arch implementations that want +// to use the fallback, so we don't need to recreate the body. + +fn fma_fallback(x: f64, y: f64, z: f64) -> f64 { + generic::fma_round(x, y, z, Round::Nearest).val +} + +fn fmaf_fallback(x: f32, y: f32, z: f32) -> f32 { + generic::fma_wide_round(x, y, z, Round::Nearest).val +} diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 78f0f8992ea..5bf473cfe06 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -19,7 +19,10 @@ pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 { pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { select_implementation! { name: fmaf, - use_arch: all(target_arch = "aarch64", target_feature = "neon"), + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + target_feature = "sse2", + ), args: x, y, z, } @@ -33,7 +36,10 @@ pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { pub fn fma(x: f64, y: f64, z: f64) -> f64 { select_implementation! { name: fma, - use_arch: all(target_arch = "aarch64", target_feature = "neon"), + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + target_feature = "sse2", + ), args: x, y, z, } diff --git a/library/compiler-builtins/libm/src/math/support/feature_detect.rs b/library/compiler-builtins/libm/src/math/support/feature_detect.rs new file mode 100644 index 00000000000..cb669b07332 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/feature_detect.rs @@ -0,0 +1,206 @@ +//! Helpers for runtime target feature detection that are shared across architectures. + +use core::sync::atomic::{AtomicU32, Ordering}; + +/// Given a list of identifiers, assign each one a unique sequential single-bit mask. +#[allow(unused_macros)] +macro_rules! unique_masks { + ($ty:ty, $($name:ident,)+) => { + #[cfg(test)] + pub const ALL: &[$ty] = &[$($name),+]; + #[cfg(test)] + pub const NAMES: &[&str] = &[$(stringify!($name)),+]; + + unique_masks!(@one; $ty; 0; $($name,)+); + }; + // Matcher for a single value + (@one; $_ty:ty; $_idx:expr;) => {}; + (@one; $ty:ty; $shift:expr; $name:ident, $($tail:tt)*) => { + pub const $name: $ty = 1 << $shift; + // Ensure the top bit is not used since it stores initialized state. + const _: () = assert!($name != (1 << (<$ty>::BITS - 1))); + // Increment the shift and invoke the next + unique_masks!(@one; $ty; $shift + 1; $($tail)*); + }; +} + +/// Call `init` once to choose an implementation, then use it for the rest of the program. +/// +/// - `sig` is the function type. +/// - `init` is an expression called at startup that chooses an implementation and returns a +/// function pointer. +/// - `call` is an expression to call a function returned by `init`, encapsulating any safety +/// preconditions. +/// +/// The type `Func` is available in `init` and `call`. +/// +/// This is effectively our version of an ifunc without linker support. Note that `init` may be +/// called more than once until one completes. +#[allow(unused_macros)] // only used on some architectures +macro_rules! select_once { + ( + sig: fn($($arg:ident: $ArgTy:ty),*) -> $RetTy:ty, + init: $init:expr, + call: $call:expr, + ) => {{ + use core::mem; + use core::sync::atomic::{AtomicPtr, Ordering}; + + type Func = unsafe fn($($arg: $ArgTy),*) -> $RetTy; + + /// Stores a pointer that is immediately jumped to. By default it is an init function + /// that sets FUNC to something else. + static FUNC: AtomicPtr<()> = AtomicPtr::new((initializer as Func) as *mut ()); + + /// Run once to set the function that will be used for all subsequent calls. + fn initializer($($arg: $ArgTy),*) -> $RetTy { + // Select an implementation, ensuring a 'static lifetime. + let fn_ptr: Func = $init(); + FUNC.store(fn_ptr as *mut (), Ordering::Relaxed); + + // Forward the call to the selected function. + $call(fn_ptr) + } + + let raw: *mut () = FUNC.load(Ordering::Relaxed); + + // SAFETY: will only ever be `initializer` or another function pointer that has the + // 'static lifetime. + let fn_ptr: Func = unsafe { mem::transmute::<*mut (), Func>(raw) }; + + $call(fn_ptr) + }} +} + +pub(crate) use {select_once, unique_masks}; + +use crate::support::cold_path; + +/// Helper for working with bit flags, based on `bitflags`. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Flags(u32); + +#[allow(dead_code)] // only used on some architectures +impl Flags { + /// No bits set. + pub const fn empty() -> Self { + Self(0) + } + + /// Create with bits already set. + pub const fn from_bits(val: u32) -> Self { + Self(val) + } + + /// Get the integer representation. + pub fn bits(&self) -> u32 { + self.0 + } + + /// Set any bits in `mask`. + pub fn insert(&mut self, mask: u32) { + self.0 |= mask; + } + + /// Check whether the mask is set. + pub fn contains(&self, mask: u32) -> bool { + self.0 & mask == mask + } + + /// Check whether the nth bit is set. + pub fn test_nth(&self, bit: u32) -> bool { + debug_assert!(bit < u32::BITS, "bit index out-of-bounds"); + self.0 & (1 << bit) != 0 + } +} + +/// Load flags from an atomic value. If the flags have not yet been initialized, call `init` +/// to do so. +/// +/// Note that `init` may run more than once. +#[allow(dead_code)] // only used on some architectures +pub fn get_or_init_flags_cache(cache: &AtomicU32, init: impl FnOnce() -> Flags) -> Flags { + // The top bit is used to indicate that the values have already been set once. + const INITIALIZED: u32 = 1 << 31; + + // Relaxed ops are sufficient since the result should always be the same. + let mut flags = Flags::from_bits(cache.load(Ordering::Relaxed)); + + if !flags.contains(INITIALIZED) { + // Without this, `init` is inlined and the bit check gets wrapped in `init`'s lengthy + // prologue/epilogue. Cold pathing gives a preferable load->test->?jmp->ret. + cold_path(); + + flags = init(); + debug_assert!( + !flags.contains(INITIALIZED), + "initialized bit shouldn't be set" + ); + flags.insert(INITIALIZED); + cache.store(flags.bits(), Ordering::Relaxed); + } + + flags +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn unique_masks() { + unique_masks! { + u32, + V0, + V1, + V2, + } + assert_eq!(V0, 1u32 << 0); + assert_eq!(V1, 1u32 << 1); + assert_eq!(V2, 1u32 << 2); + assert_eq!(ALL, [V0, V1, V2]); + assert_eq!(NAMES, ["V0", "V1", "V2"]); + } + + #[test] + fn flag_cache_is_used() { + // Sanity check that flags are only ever set once + static CACHE: AtomicU32 = AtomicU32::new(0); + + let mut f1 = Flags::from_bits(0x1); + let f2 = Flags::from_bits(0x2); + + let r1 = get_or_init_flags_cache(&CACHE, || f1); + let r2 = get_or_init_flags_cache(&CACHE, || f2); + + f1.insert(1 << 31); // init bit + + assert_eq!(r1, f1); + assert_eq!(r2, f1); + } + + #[test] + fn select_cache_is_used() { + // Sanity check that cache is used + static CALLED: AtomicU32 = AtomicU32::new(0); + + fn inner() { + fn nop() {} + + select_once! { + sig: fn() -> (), + init: || { + CALLED.fetch_add(1, Ordering::Relaxed); + nop + }, + call: |fn_ptr: Func| unsafe { fn_ptr() }, + } + } + + // `init` should only have been called once. + inner(); + assert_eq!(CALLED.load(Ordering::Relaxed), 1); + inner(); + assert_eq!(CALLED.load(Ordering::Relaxed), 1); + } +} diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index ee3f2bbdf02..727b9a360e2 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -2,6 +2,7 @@ pub mod macros; mod big; mod env; +mod feature_detect; mod float_traits; pub mod hex_float; mod int_traits; @@ -10,6 +11,8 @@ mod int_traits; pub use big::{i256, u256}; pub use env::{FpResult, Round, Status}; #[allow(unused_imports)] +pub(crate) use feature_detect::{Flags, get_or_init_flags_cache, select_once, unique_masks}; +#[allow(unused_imports)] pub use float_traits::{DFloat, Float, HFloat, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; #[cfg(f16_enabled)] -- cgit 1.4.1-3-g733a5 From 16150ebb314b3ff80bab2c6776641f43a583acd3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 3 May 2025 18:18:20 +0000 Subject: chore: release --- library/compiler-builtins/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm/CHANGELOG.md | 6 ++++++ library/compiler-builtins/libm/Cargo.toml | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index 34b413a8683..f152c2c2c8c 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.157](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.156...compiler_builtins-v0.1.157) - 2025-05-03 + +### Other + +- Use runtime feature detection for fma routines on x86 + ## [0.1.156](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.155...compiler_builtins-v0.1.156) - 2025-04-21 ### Other diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index acbace68729..78456377730 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.156" +version = "0.1.157" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 292561f86ab..a0217af09e2 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -8,6 +8,12 @@ and this project adheres to ## [Unreleased] +## [0.2.14](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.13...libm-v0.2.14) - 2025-05-03 + +### Other + +- Use runtime feature detection for fma routines on x86 + ## [0.2.13](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.12...libm-v0.2.13) - 2025-04-21 ### Fixed diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index f80715ff6c5..76c9a73bc6e 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -version = "0.2.13" +version = "0.2.14" edition = "2021" rust-version = "1.63" -- cgit 1.4.1-3-g733a5 From 5032002c2fc753b9f2734e7723254b57b860f22e Mon Sep 17 00:00:00 2001 From: ELginas Date: Mon, 28 Apr 2025 17:17:11 +0300 Subject: docs: fix typo in Cargo.toml Initially introduced in 63ccaf11f08fb5d0b39cc33884c5a1a63f547ace Signed-off-by: ELginas --- library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 78456377730..d9eebcfc8a1 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -35,7 +35,7 @@ default = ["compiler-builtins"] c = ["dep:cc"] # Workaround for the Cranelift codegen backend. Disables any implementations -# which use inline assembly and fall back to pure Rust versions (if avalible). +# which use inline assembly and fall back to pure Rust versions (if available). no-asm = [] # Workaround for codegen backends which haven't yet implemented `f16` and -- cgit 1.4.1-3-g733a5 From 687902c1af4651ca0db9614c0a1ba6431cff266a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 5 May 2025 05:40:54 +0000 Subject: Replace `super::super` with `crate::support` where possible Since `crate::support` now works in both `compiler-builtins` and `libm`, we can get rid of some of these unusual paths. --- library/compiler-builtins/libm/src/math/generic/ceil.rs | 3 +-- library/compiler-builtins/libm/src/math/generic/copysign.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fabs.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fdim.rs | 2 +- library/compiler-builtins/libm/src/math/generic/floor.rs | 3 +-- library/compiler-builtins/libm/src/math/generic/fmax.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fmaximum.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fmin.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fminimum.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fminimum_num.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fmod.rs | 2 +- library/compiler-builtins/libm/src/math/generic/rint.rs | 3 +-- library/compiler-builtins/libm/src/math/generic/round.rs | 2 +- library/compiler-builtins/libm/src/math/generic/scalbn.rs | 2 +- library/compiler-builtins/libm/src/math/generic/sqrt.rs | 5 +++-- library/compiler-builtins/libm/src/math/generic/trunc.rs | 3 +-- 17 files changed, 19 insertions(+), 22 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs index 499770c0d6d..1072ba7c29b 100644 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -7,8 +7,7 @@ //! performance seems to be better (based on icount) and it does not seem to experience rounding //! errors on i386. -use super::super::support::{FpResult, Status}; -use super::super::{Float, Int, IntTy, MinInt}; +use crate::support::{Float, FpResult, Int, IntTy, MinInt, Status}; #[inline] pub fn ceil(x: F) -> F { diff --git a/library/compiler-builtins/libm/src/math/generic/copysign.rs b/library/compiler-builtins/libm/src/math/generic/copysign.rs index a61af22f04a..da9ce387885 100644 --- a/library/compiler-builtins/libm/src/math/generic/copysign.rs +++ b/library/compiler-builtins/libm/src/math/generic/copysign.rs @@ -1,4 +1,4 @@ -use super::super::Float; +use crate::support::Float; /// Copy the sign of `y` to `x`. #[inline] diff --git a/library/compiler-builtins/libm/src/math/generic/fabs.rs b/library/compiler-builtins/libm/src/math/generic/fabs.rs index 0fa0edf9b87..0adfa57d91b 100644 --- a/library/compiler-builtins/libm/src/math/generic/fabs.rs +++ b/library/compiler-builtins/libm/src/math/generic/fabs.rs @@ -1,4 +1,4 @@ -use super::super::Float; +use crate::support::Float; /// Absolute value. #[inline] diff --git a/library/compiler-builtins/libm/src/math/generic/fdim.rs b/library/compiler-builtins/libm/src/math/generic/fdim.rs index a63007b191c..289e5fd96f8 100644 --- a/library/compiler-builtins/libm/src/math/generic/fdim.rs +++ b/library/compiler-builtins/libm/src/math/generic/fdim.rs @@ -1,4 +1,4 @@ -use super::super::Float; +use crate::support::Float; #[inline] pub fn fdim(x: F, y: F) -> F { diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs index 58d1ee4c247..e6dfd8866a4 100644 --- a/library/compiler-builtins/libm/src/math/generic/floor.rs +++ b/library/compiler-builtins/libm/src/math/generic/floor.rs @@ -7,8 +7,7 @@ //! performance seems to be better (based on icount) and it does not seem to experience rounding //! errors on i386. -use super::super::support::{FpResult, Status}; -use super::super::{Float, Int, IntTy, MinInt}; +use crate::support::{Float, FpResult, Int, IntTy, MinInt, Status}; #[inline] pub fn floor(x: F) -> F { diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs index bf3f847e89b..54207e4b328 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmax.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmax.rs @@ -14,7 +14,7 @@ //! //! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf -use super::super::Float; +use crate::support::Float; #[inline] pub fn fmax(x: F, y: F) -> F { diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs index 387055af29c..4b6295bc0c6 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs @@ -9,7 +9,7 @@ //! //! Excluded from our implementation is sNaN handling. -use super::super::Float; +use crate::support::Float; #[inline] pub fn fmaximum(x: F, y: F) -> F { diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs index f7efdde80ea..2e97ff6d369 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs @@ -11,7 +11,7 @@ //! //! Excluded from our implementation is sNaN handling. -use super::super::Float; +use crate::support::Float; #[inline] pub fn fmaximum_num(x: F, y: F) -> F { diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs index cd3caeee4f2..0f86364d230 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmin.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmin.rs @@ -14,7 +14,7 @@ //! //! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf -use super::super::Float; +use crate::support::Float; #[inline] pub fn fmin(x: F, y: F) -> F { diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs index 4ddb3645506..9dc0b64be3f 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum.rs @@ -9,7 +9,7 @@ //! //! Excluded from our implementation is sNaN handling. -use super::super::Float; +use crate::support::Float; #[inline] pub fn fminimum(x: F, y: F) -> F { diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs index 441c204a921..40db8b18957 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs @@ -11,7 +11,7 @@ //! //! Excluded from our implementation is sNaN handling. -use super::super::Float; +use crate::support::Float; #[inline] pub fn fminimum_num(x: F, y: F) -> F { diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs index e9898012fcc..29acc8a4d5d 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmod.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: MIT OR Apache-2.0 */ -use super::super::{CastFrom, Float, Int, MinInt}; +use crate::support::{CastFrom, Float, Int, MinInt}; #[inline] pub fn fmod(x: F, y: F) -> F { diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index 7bf38e3235c..c5bc27d3de6 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: MIT */ /* origin: musl src/math/rint.c */ -use super::super::Float; -use super::super::support::{FpResult, Round}; +use crate::support::{Float, FpResult, Round}; /// IEEE 754-2019 `roundToIntegralExact`, which respects rounding mode and raises inexact if /// applicable. diff --git a/library/compiler-builtins/libm/src/math/generic/round.rs b/library/compiler-builtins/libm/src/math/generic/round.rs index 01314ac70c2..16739f01d87 100644 --- a/library/compiler-builtins/libm/src/math/generic/round.rs +++ b/library/compiler-builtins/libm/src/math/generic/round.rs @@ -1,5 +1,5 @@ -use super::super::{Float, MinInt}; use super::{copysign, trunc}; +use crate::support::{Float, MinInt}; #[inline] pub fn round(x: F) -> F { diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs index a45db1b4a02..6dd9b1a9b84 100644 --- a/library/compiler-builtins/libm/src/math/generic/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs @@ -1,4 +1,4 @@ -use super::super::{CastFrom, CastInto, Float, IntTy, MinInt}; +use crate::support::{CastFrom, CastInto, Float, IntTy, MinInt}; /// Scale the exponent. /// diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index c52560bdb2c..9481c4cdb7b 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -41,8 +41,9 @@ //! Goldschmidt has the advantage over Newton-Raphson that `sqrt(x)` and `1/sqrt(x)` are //! computed at the same time, i.e. there is no need to calculate `1/sqrt(x)` and invert it. -use super::super::support::{FpResult, IntTy, Round, Status, cold_path}; -use super::super::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; +use crate::support::{ + CastFrom, CastInto, DInt, Float, FpResult, HInt, Int, IntTy, MinInt, Round, Status, cold_path, +}; #[inline] pub fn sqrt(x: F) -> F diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs index 29a28f47b63..d5b444d15df 100644 --- a/library/compiler-builtins/libm/src/math/generic/trunc.rs +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: MIT * origin: musl src/math/trunc.c */ -use super::super::support::{FpResult, Status}; -use super::super::{Float, Int, IntTy, MinInt}; +use crate::support::{Float, FpResult, Int, IntTy, MinInt, Status}; #[inline] pub fn trunc(x: F) -> F { -- cgit 1.4.1-3-g733a5 From 339793d62b4c455f2a8268e09f85ee471cd4847c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 5 May 2025 05:43:58 +0000 Subject: ci: Mention `ci: skip-extensive` in the error message --- library/compiler-builtins/ci/ci-util.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/ci-util.py b/library/compiler-builtins/ci/ci-util.py index 7486d6b4186..d785b2e9e1d 100755 --- a/library/compiler-builtins/ci/ci-util.py +++ b/library/compiler-builtins/ci/ci-util.py @@ -261,7 +261,9 @@ class Context: if error_on_many_tests and total_to_test > MANY_EXTENSIVE_THRESHOLD: eprint( f"More than {MANY_EXTENSIVE_THRESHOLD} tests would be run; add" - f" `{ALLOW_MANY_EXTENSIVE_DIRECTIVE}` to the PR body if this is intentional" + f" `{ALLOW_MANY_EXTENSIVE_DIRECTIVE}` to the PR body if this is" + " intentional. If this is refactoring that happens to touch a lot of" + f" files, `{SKIP_EXTENSIVE_DIRECTIVE}` can be used instead." ) exit(1) -- cgit 1.4.1-3-g733a5 From 61a14fcea05f8e9a544a5557b98633f7ace65109 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 6 May 2025 20:11:48 +0000 Subject: Require `target_has_atomic = "ptr"` for runtime feature detection The `feature_detect` module is currently being built on all targets, but the use of `AtomicU32` causes a problem if atomics are not available (such as with `bpfel-unknown-none`). Gate this module behind `target_has_atomic = "ptr"`. The below now completes successfully: cargo build -p compiler_builtins --target=bpfel-unknown-none -Z build-std=core Fixes: https://github.com/rust-lang/compiler-builtins/issues/908 --- library/compiler-builtins/libm/src/math/arch/x86/detect.rs | 7 +++++-- library/compiler-builtins/libm/src/math/arch/x86/fma.rs | 3 ++- library/compiler-builtins/libm/src/math/support/feature_detect.rs | 5 +++++ library/compiler-builtins/libm/src/math/support/mod.rs | 6 +++--- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/arch/x86/detect.rs b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs index 71c3281dc55..e6d9b040bfa 100644 --- a/library/compiler-builtins/libm/src/math/arch/x86/detect.rs +++ b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs @@ -1,13 +1,16 @@ +// Using runtime feature detection requires atomics. Currently there are no x86 targets +// that support sse but not `AtomicPtr`. + #[cfg(target_arch = "x86")] use core::arch::x86::{__cpuid, __cpuid_count, _xgetbv, CpuidResult}; #[cfg(target_arch = "x86_64")] use core::arch::x86_64::{__cpuid, __cpuid_count, _xgetbv, CpuidResult}; -use crate::support::{Flags, get_or_init_flags_cache}; +use crate::support::feature_detect::{Flags, get_or_init_flags_cache, unique_masks}; /// CPU features that get cached (doesn't correlate to anything on the CPU). pub mod cpu_flags { - use crate::support::unique_masks; + use super::unique_masks; unique_masks! { u32, diff --git a/library/compiler-builtins/libm/src/math/arch/x86/fma.rs b/library/compiler-builtins/libm/src/math/arch/x86/fma.rs index eb43f4696d7..43ac187792d 100644 --- a/library/compiler-builtins/libm/src/math/arch/x86/fma.rs +++ b/library/compiler-builtins/libm/src/math/arch/x86/fma.rs @@ -4,7 +4,8 @@ use core::arch::asm; use super::super::super::generic; use super::detect::{cpu_flags, get_cpu_features}; -use crate::support::{Round, select_once}; +use crate::support::Round; +use crate::support::feature_detect::select_once; pub fn fma(x: f64, y: f64, z: f64) -> f64 { select_once! { diff --git a/library/compiler-builtins/libm/src/math/support/feature_detect.rs b/library/compiler-builtins/libm/src/math/support/feature_detect.rs index cb669b07332..9ebd434a5f8 100644 --- a/library/compiler-builtins/libm/src/math/support/feature_detect.rs +++ b/library/compiler-builtins/libm/src/math/support/feature_detect.rs @@ -1,5 +1,9 @@ //! Helpers for runtime target feature detection that are shared across architectures. +// `AtomicU32` is preferred for a consistent size across targets. +#[cfg(all(target_has_atomic = "ptr", not(target_has_atomic = "32")))] +compile_error!("currently all targets that support `AtomicPtr` also support `AtomicU32`"); + use core::sync::atomic::{AtomicU32, Ordering}; /// Given a list of identifiers, assign each one a unique sequential single-bit mask. @@ -72,6 +76,7 @@ macro_rules! select_once { }} } +#[allow(unused_imports)] pub(crate) use {select_once, unique_masks}; use crate::support::cold_path; diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 727b9a360e2..a4f596ab844 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -2,7 +2,9 @@ pub mod macros; mod big; mod env; -mod feature_detect; +// Runtime feature detection requires atomics. +#[cfg(target_has_atomic = "ptr")] +pub(crate) mod feature_detect; mod float_traits; pub mod hex_float; mod int_traits; @@ -11,8 +13,6 @@ mod int_traits; pub use big::{i256, u256}; pub use env::{FpResult, Round, Status}; #[allow(unused_imports)] -pub(crate) use feature_detect::{Flags, get_or_init_flags_cache, select_once, unique_masks}; -#[allow(unused_imports)] pub use float_traits::{DFloat, Float, HFloat, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; #[cfg(f16_enabled)] -- cgit 1.4.1-3-g733a5 From 0d63b9979941305447f49bd1dcd2bd007e7e426e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 21:59:33 +0000 Subject: chore: release --- library/compiler-builtins/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm/CHANGELOG.md | 6 ++++++ library/compiler-builtins/libm/Cargo.toml | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index f152c2c2c8c..f0af37ba0b2 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.158](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.157...compiler_builtins-v0.1.158) - 2025-05-06 + +### Other + +- Require `target_has_atomic = "ptr"` for runtime feature detection + ## [0.1.157](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.156...compiler_builtins-v0.1.157) - 2025-05-03 ### Other diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index d9eebcfc8a1..81f708c48e6 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.157" +version = "0.1.158" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index a0217af09e2..33fec06aa23 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -8,6 +8,12 @@ and this project adheres to ## [Unreleased] +## [0.2.15](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.14...libm-v0.2.15) - 2025-05-06 + +### Other + +- Require `target_has_atomic = "ptr"` for runtime feature detection + ## [0.2.14](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.13...libm-v0.2.14) - 2025-05-03 ### Other diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 76c9a73bc6e..b6fb5efcf76 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -version = "0.2.14" +version = "0.2.15" edition = "2021" rust-version = "1.63" -- cgit 1.4.1-3-g733a5 From 1768cb17317a038f812d1159f2e002b92c3fbb2c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 6 May 2025 23:00:46 +0000 Subject: release-plz: Include the libm changelog in compiler-builtins --- library/compiler-builtins/.release-plz.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/.release-plz.toml b/library/compiler-builtins/.release-plz.toml index 95e91a46c8d..8023ade9bfd 100644 --- a/library/compiler-builtins/.release-plz.toml +++ b/library/compiler-builtins/.release-plz.toml @@ -7,6 +7,7 @@ publish_allow_dirty = true [[package]] name = "compiler_builtins" semver_check = false +changelog_include = ["libm"] # libm is included as part of builtins [[package]] name = "libm" -- cgit 1.4.1-3-g733a5 From c4c7f25c4cbf2615c59ee45343d05b0cf5046a6d Mon Sep 17 00:00:00 2001 From: nora <48135649+Noratrieb@users.noreply.github.com> Date: Mon, 12 May 2025 16:15:24 +0200 Subject: Remove cfg(bootstrap) Foe the bootstrap bump --- library/compiler-builtins/compiler-builtins/src/macros.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index dbf71553440..22e0dd27f2f 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -433,18 +433,6 @@ macro_rules! intrinsics { ) => ( // `#[naked]` definitions are referenced by other places, so we can't use `cfg` like the others pub mod $name { - // FIXME: when bootstrap supports `#[unsafe(naked)]` this duplication can be removed - #[cfg(bootstrap)] - #[naked] - #[allow(unused_unsafe)] - $(#[$($attr)*])* - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] - pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - unsafe { $($body)* } - } - - #[cfg(not(bootstrap))] #[unsafe(naked)] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -- cgit 1.4.1-3-g733a5 From 65663b538fd8c3a593b0470b1d966100ac968a77 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 May 2025 14:26:59 +0000 Subject: chore(compiler_builtins): release v0.1.159 --- library/compiler-builtins/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index f0af37ba0b2..a7c01c463ca 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.159](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.158...compiler_builtins-v0.1.159) - 2025-05-12 + +### Other + +- Remove cfg(bootstrap) + ## [0.1.158](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.157...compiler_builtins-v0.1.158) - 2025-05-06 ### Other diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 81f708c48e6..d65a22152ef 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.158" +version = "0.1.159" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From d16c82dba15f4aaf61874f6668417856002d32a6 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Thu, 8 May 2025 15:00:59 +0200 Subject: Fix `i256::MAX` --- library/compiler-builtins/compiler-builtins/src/int/big.rs | 2 +- library/compiler-builtins/libm/src/math/support/big.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/int/big.rs b/library/compiler-builtins/compiler-builtins/src/int/big.rs index 61f1349d9a4..1402efb8ed4 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/big.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/big.rs @@ -65,7 +65,7 @@ impl MinInt for i256 { const ZERO: Self = Self([0u64; 4]); const ONE: Self = Self([1, 0, 0, 0]); const MIN: Self = Self([0, 0, 0, 1 << 63]); - const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX << 1]); + const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 1]); } macro_rules! impl_common { diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs index f24c063cd34..8a52d86cc98 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -83,7 +83,7 @@ impl MinInt for i256 { }; const MAX: Self = Self { lo: u128::MAX, - hi: u128::MAX << 1, + hi: u128::MAX >> 1, }; } -- cgit 1.4.1-3-g733a5 From abbf8fe6e7abf6b6b612bcc65f87ded71a6ce562 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 18 May 2025 10:14:22 +0200 Subject: fix an if statement that can be collapsed --- .../crates/libm-macros/src/lib.rs | 40 ++++++++++++---------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index e8afe3aad55..482da974ca8 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(let_chains)] + mod enums; mod parse; mod shared; @@ -266,27 +268,27 @@ fn validate(input: &mut StructuredInput) -> syn::Result } } - if let Some(map) = &input.fn_extra { - if !map.keys().any(|key| key == "_") { - // No default provided; make sure every expected function is covered - let mut fns_not_covered = Vec::new(); - for func in &fn_list { - if !map.keys().any(|key| key == func.name) { - // `name` was not mentioned in the `match` statement - fns_not_covered.push(func); - } + if let Some(map) = &input.fn_extra + && !map.keys().any(|key| key == "_") + { + // No default provided; make sure every expected function is covered + let mut fns_not_covered = Vec::new(); + for func in &fn_list { + if !map.keys().any(|key| key == func.name) { + // `name` was not mentioned in the `match` statement + fns_not_covered.push(func); } + } - if !fns_not_covered.is_empty() { - let e = syn::Error::new( - input.fn_extra_span.unwrap(), - format!( - "`fn_extra`: no default `_` pattern specified and the following \ - patterns are not covered: {fns_not_covered:#?}" - ), - ); - return Err(e); - } + if !fns_not_covered.is_empty() { + let e = syn::Error::new( + input.fn_extra_span.unwrap(), + format!( + "`fn_extra`: no default `_` pattern specified and the following \ + patterns are not covered: {fns_not_covered:#?}" + ), + ); + return Err(e); } }; -- cgit 1.4.1-3-g733a5 From c801c569dc2b264ee4b6db024155093ea1d616d0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 18 May 2025 15:42:35 +0000 Subject: Do not run `rustfmt` on the `compiler-builtins` subtree This will get checked in the compiler-builtins repository. The rules are slightly different from rust-lang/rust since `use_small_heuristics = "Max"` tends to create difficult to read output with math-heavy code (e.g. multiple `if` statements with numbers are small enough that they sometimes get collapsed into a single line). --- rustfmt.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/rustfmt.toml b/rustfmt.toml index d9857a7e3e7..689e390b990 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -29,6 +29,7 @@ ignore = [ # Do not format submodules. "library/backtrace", + "library/compiler-builtins", "library/portable-simd", "library/stdarch", "src/doc/book", -- cgit 1.4.1-3-g733a5 From 8c150144fd6d2fd5944021c1fb566a2e7b0ee889 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 18 May 2025 15:53:02 +0000 Subject: triagebot: Add pings and autolabels for the compiler-builtins subtree. --- triagebot.toml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 9dcdbcecbec..5921c2056f5 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -254,6 +254,11 @@ trigger_files = [ "compiler/rustc_attr_data_structures", ] +[autolabel."A-compiler-builtins"] +trigger_files = [ + "library/compiler-builtins", +] + [autolabel."F-autodiff"] trigger_files = [ "src/tools/enzyme", @@ -851,6 +856,15 @@ cc = ["@Urgau"] message = "Some changes occurred in check-cfg diagnostics" cc = ["@Urgau"] +[mentions."library/compiler-builtins"] +message = """ +`compiler-builtins` is developed in its own repository. If possible, consider \ +making this change to \ +[rust-lang/compiler-builtins](https://github.com/rust-lang/compiler-builtins) \ +instead. +""" +cc = ["@tgross35"] + [mentions."library/core/src/intrinsics/simd.rs"] message = """ Some changes occurred to the platform-builtins intrinsics. Make sure the -- cgit 1.4.1-3-g733a5 From c24e1c378f93055a53503b02894ccbede02203db Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 19 May 2025 15:14:38 +0200 Subject: add s390x z17 target features --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 8 ++++++++ compiler/rustc_target/src/target_features.rs | 26 ++++++++++++++++---------- tests/ui/check-cfg/target_feature.stderr | 12 ++++++++++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 8f57f0983ab..9718c95f38a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -282,6 +282,14 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option None, + ( + "s390x", + "message-security-assist-extension12" + | "concurrent-functions" + | "miscellaneous-extensions-4" + | "vector-enhancements-3" + | "vector-packed-decimal-enhancement-3", + ) if get_version().0 < 20 => None, // Enable the evex512 target feature if an avx512 target feature is enabled. ("x86", s) if s.starts_with("avx512") => Some(LLVMFeature::with_dependencies( s, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 99b04ac2720..45c971cdfa6 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -710,29 +710,35 @@ static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-end ]; +#[rustfmt::skip] const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("backchain", Unstable(sym::s390x_target_feature), &[]), + ("concurrent-functions", Unstable(sym::s390x_target_feature), &[]), ("deflate-conversion", Unstable(sym::s390x_target_feature), &[]), ("enhanced-sort", Unstable(sym::s390x_target_feature), &[]), ("guarded-storage", Unstable(sym::s390x_target_feature), &[]), ("high-word", Unstable(sym::s390x_target_feature), &[]), + // LLVM does not define message-security-assist-extension versions 1, 2, 6, 10 and 11. + ("message-security-assist-extension12", Unstable(sym::s390x_target_feature), &[]), + ("message-security-assist-extension3", Unstable(sym::s390x_target_feature), &[]), + ("message-security-assist-extension4", Unstable(sym::s390x_target_feature), &[]), + ("message-security-assist-extension5", Unstable(sym::s390x_target_feature), &[]), + ("message-security-assist-extension8", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3"]), + ("message-security-assist-extension9", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3", "message-security-assist-extension4"]), + ("miscellaneous-extensions-2", Unstable(sym::s390x_target_feature), &[]), + ("miscellaneous-extensions-3", Unstable(sym::s390x_target_feature), &[]), + ("miscellaneous-extensions-4", Unstable(sym::s390x_target_feature), &[]), ("nnp-assist", Unstable(sym::s390x_target_feature), &["vector"]), ("transactional-execution", Unstable(sym::s390x_target_feature), &[]), ("vector", Unstable(sym::s390x_target_feature), &[]), ("vector-enhancements-1", Unstable(sym::s390x_target_feature), &["vector"]), ("vector-enhancements-2", Unstable(sym::s390x_target_feature), &["vector-enhancements-1"]), + ("vector-enhancements-3", Unstable(sym::s390x_target_feature), &["vector-enhancements-2"]), ("vector-packed-decimal", Unstable(sym::s390x_target_feature), &["vector"]), - ( - "vector-packed-decimal-enhancement", - Unstable(sym::s390x_target_feature), - &["vector-packed-decimal"], - ), - ( - "vector-packed-decimal-enhancement-2", - Unstable(sym::s390x_target_feature), - &["vector-packed-decimal-enhancement"], - ), + ("vector-packed-decimal-enhancement", Unstable(sym::s390x_target_feature), &["vector-packed-decimal"]), + ("vector-packed-decimal-enhancement-2", Unstable(sym::s390x_target_feature), &["vector-packed-decimal-enhancement"]), + ("vector-packed-decimal-enhancement-3", Unstable(sym::s390x_target_feature), &["vector-packed-decimal-enhancement-2"]), // tidy-alphabetical-end ]; diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index eb66633f9dd..ec81ba2e3d8 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -62,6 +62,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `c` `cache` `cmpxchg16b` +`concurrent-functions` `crc` `crt-static` `cssc` @@ -159,6 +160,15 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `lzcnt` `m` `mclass` +`message-security-assist-extension12` +`message-security-assist-extension3` +`message-security-assist-extension4` +`message-security-assist-extension5` +`message-security-assist-extension8` +`message-security-assist-extension9` +`miscellaneous-extensions-2` +`miscellaneous-extensions-3` +`miscellaneous-extensions-4` `mops` `movbe` `movrs` @@ -287,9 +297,11 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `vector` `vector-enhancements-1` `vector-enhancements-2` +`vector-enhancements-3` `vector-packed-decimal` `vector-packed-decimal-enhancement` `vector-packed-decimal-enhancement-2` +`vector-packed-decimal-enhancement-3` `vfp2` `vfp3` `vfp4` -- cgit 1.4.1-3-g733a5 From ee1c2d583a081e24684e09fbbcc78fe4d5220066 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 11:57:50 +1000 Subject: Remove `MetaItemListParser::all_{word,path}_list`, which are unused. --- compiler/rustc_attr_parsing/src/parser.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 077d953cfa3..a5c3cec3bdd 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -561,20 +561,6 @@ impl<'a> MetaItemListParser<'a> { self.len() == 0 } - /// Asserts that every item in the list is another list starting with a word. - /// - /// See [`MetaItemParser::word`] for examples of words. - pub fn all_word_list<'s>(&'s self) -> Option)>> { - self.mixed().map(|i| i.meta_item()?.word()).collect() - } - - /// Asserts that every item in the list is another list starting with a full path. - /// - /// See [`MetaItemParser::path`] for examples of paths. - pub fn all_path_list<'s>(&'s self) -> Option, &'s ArgParser<'a>)>> { - self.mixed().map(|i| Some(i.meta_item()?.path())).collect() - } - /// Returns Some if the list contains only a single element. /// /// Inside the Some is the parser to parse this single element. -- cgit 1.4.1-3-g733a5 From a822e557cd19efa0dcf62ae3e7af6b6310fa2f5c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 12:01:03 +1000 Subject: Remove an unnecessary lifetime. --- compiler/rustc_attr_parsing/src/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index a5c3cec3bdd..a9eb0a51888 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -549,7 +549,7 @@ impl<'a> MetaItemListParser<'a> { } /// Lets you pick and choose as what you want to parse each element in the list - pub fn mixed<'s>(&'s self) -> impl Iterator> + 's { + pub fn mixed(&self) -> impl Iterator> { self.sub_parsers.iter() } -- cgit 1.4.1-3-g733a5 From ea3b3fdcc155fb0cd758392b68b1859cf9a435b4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 12:08:00 +1000 Subject: Remove `MetaItemParser::{word,word_without_args,path_is}`. They are unused. --- compiler/rustc_attr_parsing/src/parser.rs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index a9eb0a51888..8366f163a68 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -276,38 +276,15 @@ impl<'a> MetaItemParser<'a> { self.deconstruct() } - /// Asserts that this MetaItem starts with a word, or single segment path. - /// Doesn't return the args parser. - /// - /// For examples. see [`Self::word`] - pub fn word_without_args(&self) -> Option { - Some(self.word()?.0) - } - /// Asserts that this MetaItem starts with a word, or single segment path. /// /// Some examples: /// - `#[inline]`: `inline` is a word /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path, /// and not a word and should instead be parsed using [`path`](Self::path) - pub fn word(&self) -> Option<(Ident, &ArgParser<'a>)> { - let (path, args) = self.deconstruct(); - Some((path.word()?, args)) - } - - /// Asserts that this MetaItem starts with some specific word. - /// - /// See [`word`](Self::word) for examples of what a word is. pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser<'a>> { self.path_without_args().word_is(sym).then(|| self.args()) } - - /// Asserts that this MetaItem starts with some specific path. - /// - /// See [`word`](Self::path) for examples of what a word is. - pub fn path_is(&self, segments: &[Symbol]) -> Option<&ArgParser<'a>> { - self.path_without_args().segments_is(segments).then(|| self.args()) - } } #[derive(Clone)] -- cgit 1.4.1-3-g733a5 From 2cd2d249673b316bb4a15c10c6a1113b2bee02db Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 11:57:21 +1000 Subject: Remove `MetaItemParser::{path,deconstruct}`. They're equivalent, and `path` is unused, and `deconstruct` has only one call site outside of `path`. --- compiler/rustc_attr_parsing/src/context.rs | 3 ++- compiler/rustc_attr_parsing/src/parser.rs | 19 +++++-------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 55c3df003fe..820c70edebf 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -260,7 +260,8 @@ impl<'sess> AttributeParser<'sess> { // } ast::AttrKind::Normal(n) => { let parser = MetaItemParser::from_attr(n, self.dcx()); - let (path, args) = parser.deconstruct(); + let path = parser.path_without_args(); + let args = parser.args(); let parts = path.segments().map(|i| i.name).collect::>(); if let Some(accepts) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) { diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 8366f163a68..30d8aa02720 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -253,7 +253,11 @@ impl<'a> MetaItemParser<'a> { } } - /// Gets just the path, without the args. + /// Gets just the path, without the args. Some examples: + /// + /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path + /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path + /// - `#[inline]`: `inline` is a single segment path pub fn path_without_args(&self) -> PathParser<'a> { self.path.clone() } @@ -263,19 +267,6 @@ impl<'a> MetaItemParser<'a> { &self.args } - pub fn deconstruct(&self) -> (PathParser<'a>, &ArgParser<'a>) { - (self.path_without_args(), self.args()) - } - - /// Asserts that this MetaItem starts with a path. Some examples: - /// - /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path - /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path - /// - `#[inline]`: `inline` is a single segment path - pub fn path(&self) -> (PathParser<'a>, &ArgParser<'a>) { - self.deconstruct() - } - /// Asserts that this MetaItem starts with a word, or single segment path. /// /// Some examples: -- cgit 1.4.1-3-g733a5 From e5c78de85c01e576671f9ba0c880520baf0d938d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 12:41:56 +1000 Subject: Rename `MetaItemParser::path_without_args` as `MetaItemParser::path`. And avoid the clone. --- compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs | 2 +- compiler/rustc_attr_parsing/src/attributes/deprecation.rs | 4 ++-- compiler/rustc_attr_parsing/src/attributes/repr.rs | 2 +- compiler/rustc_attr_parsing/src/attributes/stability.rs | 10 +++++----- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_attr_parsing/src/parser.rs | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index c1d95d07f4c..8460a4a4122 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -53,7 +53,7 @@ fn parse_unstable<'a>( for param in list.mixed() { let param_span = param.span(); - if let Some(ident) = param.meta_item().and_then(|i| i.path_without_args().word()) { + if let Some(ident) = param.meta_item().and_then(|i| i.path().word()) { res.push(ident.name); } else { cx.emit_err(session_diagnostics::ExpectsFeatures { diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index fb3d5f57d4f..5e94261f1c4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -79,7 +79,7 @@ impl SingleAttributeParser for DeprecationParser { return None; }; - let ident_name = param.path_without_args().word_sym(); + let ident_name = param.path().word_sym(); match ident_name { Some(name @ sym::since) => { @@ -102,7 +102,7 @@ impl SingleAttributeParser for DeprecationParser { _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param_span, - item: param.path_without_args().to_string(), + item: param.path().to_string(), expected: if features.deprecated_suggestion() { &["since", "note", "suggestion"] } else { diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 43dfb85a7c4..97c865230f2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -96,7 +96,7 @@ fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option insert_value_into_option_or_error(cx, ¶m, &mut feature)?, Some(sym::since) => insert_value_into_option_or_error(cx, ¶m, &mut since)?, _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param_span, - item: param.path_without_args().to_string(), + item: param.path().to_string(), expected: &["feature", "since"], }); return None; @@ -310,7 +310,7 @@ pub(crate) fn parse_unstability( return None; }; - match param.path_without_args().word_sym() { + match param.path().word_sym() { Some(sym::feature) => insert_value_into_option_or_error(cx, ¶m, &mut feature)?, Some(sym::reason) => insert_value_into_option_or_error(cx, ¶m, &mut reason)?, Some(sym::issue) => { @@ -349,7 +349,7 @@ pub(crate) fn parse_unstability( _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param.span(), - item: param.path_without_args().to_string(), + item: param.path().to_string(), expected: &["feature", "reason", "issue", "soft", "implied_by"], }); return None; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 820c70edebf..c1017854916 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -260,7 +260,7 @@ impl<'sess> AttributeParser<'sess> { // } ast::AttrKind::Normal(n) => { let parser = MetaItemParser::from_attr(n, self.dcx()); - let path = parser.path_without_args(); + let path = parser.path(); let args = parser.args(); let parts = path.segments().map(|i| i.name).collect::>(); diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 30d8aa02720..7e89f6c6a2e 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -258,8 +258,8 @@ impl<'a> MetaItemParser<'a> { /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path /// - `#[inline]`: `inline` is a single segment path - pub fn path_without_args(&self) -> PathParser<'a> { - self.path.clone() + pub fn path(&self) -> &PathParser<'a> { + &self.path } /// Gets just the args parser, without caring about the path. @@ -274,7 +274,7 @@ impl<'a> MetaItemParser<'a> { /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path, /// and not a word and should instead be parsed using [`path`](Self::path) pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser<'a>> { - self.path_without_args().word_is(sym).then(|| self.args()) + self.path().word_is(sym).then(|| self.args()) } } -- cgit 1.4.1-3-g733a5 From 11c15229557cb489a5604f13e26a51099cc05314 Mon Sep 17 00:00:00 2001 From: beetrees Date: Wed, 21 May 2025 18:11:11 +0100 Subject: Enable `__powitf2` on MSVC --- library/compiler-builtins/builtins-test/tests/float_pow.rs | 2 -- library/compiler-builtins/compiler-builtins/src/float/pow.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/library/compiler-builtins/builtins-test/tests/float_pow.rs b/library/compiler-builtins/builtins-test/tests/float_pow.rs index 8209543e666..0e8ae88e83e 100644 --- a/library/compiler-builtins/builtins-test/tests/float_pow.rs +++ b/library/compiler-builtins/builtins-test/tests/float_pow.rs @@ -58,8 +58,6 @@ pow! { } #[cfg(f128_enabled)] -// FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly. -#[cfg(not(target_env = "msvc"))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pow! { f128, 1e-36, __powitf2, not(feature = "no-sys-f128"); diff --git a/library/compiler-builtins/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/compiler-builtins/src/float/pow.rs index 45a4ad9049d..6997a9c213c 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/pow.rs @@ -32,8 +32,6 @@ intrinsics! { #[ppc_alias = __powikf2] #[cfg(f128_enabled)] - // FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly. - #[cfg(not(target_env = "msvc"))] pub extern "C" fn __powitf2(a: f128, b: i32) -> f128 { pow(a, b) } -- cgit 1.4.1-3-g733a5 From 7966f1b556f39882b3e451533a74a3b24a34cb05 Mon Sep 17 00:00:00 2001 From: Pályi Lőrinc Date: Sat, 10 May 2025 08:36:28 +0000 Subject: fixed typo in readme --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 3130ff7b77d..177bce624e0 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -5,7 +5,7 @@ This repository contains two main crates: * `compiler-builtins`: symbols that the compiler expects to be available at link time * `libm`: a Rust implementation of C math libraries, used to provide - implementations in `ocre`. + implementations in `core`. More details are at [compiler-builtins/README.md](compiler-builtins/README.md) and [libm/README.md](libm/README.md). -- cgit 1.4.1-3-g733a5 From db21837095f18a76d1fecb7d55547688a6b19647 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 19:35:21 -0400 Subject: libm: Clean up unused files These were deleted during refactoring in 0a2dc5d9 ("Combine the source files for more generic implementations") but got added back by accident in 54bac411 ("refactor: Move the libm crate to a subdirectory"). Remove them again here. --- .../compiler-builtins/libm/src/math/copysignf.rs | 8 ----- .../libm/src/math/copysignf128.rs | 8 ----- .../compiler-builtins/libm/src/math/copysignf16.rs | 8 ----- library/compiler-builtins/libm/src/math/fabsf.rs | 39 ---------------------- .../compiler-builtins/libm/src/math/fabsf128.rs | 31 ----------------- library/compiler-builtins/libm/src/math/fabsf16.rs | 31 ----------------- library/compiler-builtins/libm/src/math/fdimf.rs | 12 ------- .../compiler-builtins/libm/src/math/fdimf128.rs | 12 ------- library/compiler-builtins/libm/src/math/fdimf16.rs | 12 ------- library/compiler-builtins/libm/src/math/floorf.rs | 13 -------- .../compiler-builtins/libm/src/math/floorf128.rs | 7 ---- .../compiler-builtins/libm/src/math/floorf16.rs | 7 ---- library/compiler-builtins/libm/src/math/fmodf.rs | 5 --- .../compiler-builtins/libm/src/math/fmodf128.rs | 5 --- library/compiler-builtins/libm/src/math/fmodf16.rs | 5 --- library/compiler-builtins/libm/src/math/ldexpf.rs | 4 --- .../compiler-builtins/libm/src/math/ldexpf128.rs | 4 --- .../compiler-builtins/libm/src/math/ldexpf16.rs | 4 --- library/compiler-builtins/libm/src/math/roundf.rs | 5 --- .../compiler-builtins/libm/src/math/roundf128.rs | 5 --- .../compiler-builtins/libm/src/math/roundf16.rs | 5 --- library/compiler-builtins/libm/src/math/scalbnf.rs | 4 --- .../compiler-builtins/libm/src/math/scalbnf128.rs | 4 --- .../compiler-builtins/libm/src/math/scalbnf16.rs | 4 --- library/compiler-builtins/libm/src/math/sqrtf.rs | 15 --------- .../compiler-builtins/libm/src/math/sqrtf128.rs | 5 --- library/compiler-builtins/libm/src/math/sqrtf16.rs | 11 ------ library/compiler-builtins/libm/src/math/truncf.rs | 23 ------------- .../compiler-builtins/libm/src/math/truncf128.rs | 7 ---- .../compiler-builtins/libm/src/math/truncf16.rs | 7 ---- 30 files changed, 310 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/copysignf.rs delete mode 100644 library/compiler-builtins/libm/src/math/copysignf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/copysignf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/fabsf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fabsf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fabsf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/fdimf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fdimf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fdimf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/floorf.rs delete mode 100644 library/compiler-builtins/libm/src/math/floorf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/floorf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmodf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmodf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmodf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/ldexpf.rs delete mode 100644 library/compiler-builtins/libm/src/math/ldexpf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/ldexpf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundf.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/scalbnf.rs delete mode 100644 library/compiler-builtins/libm/src/math/scalbnf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/scalbnf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/sqrtf.rs delete mode 100644 library/compiler-builtins/libm/src/math/sqrtf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/sqrtf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/truncf.rs delete mode 100644 library/compiler-builtins/libm/src/math/truncf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/truncf16.rs diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs deleted file mode 100644 index 8b9bed4c0c4..00000000000 --- a/library/compiler-builtins/libm/src/math/copysignf.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f32) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf(x: f32, y: f32) -> f32 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/copysignf128.rs b/library/compiler-builtins/libm/src/math/copysignf128.rs deleted file mode 100644 index 7bd81d42b2e..00000000000 --- a/library/compiler-builtins/libm/src/math/copysignf128.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f128) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf128(x: f128, y: f128) -> f128 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/copysignf16.rs b/library/compiler-builtins/libm/src/math/copysignf16.rs deleted file mode 100644 index 82065868601..00000000000 --- a/library/compiler-builtins/libm/src/math/copysignf16.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f16) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf16(x: f16, y: f16) -> f16 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs deleted file mode 100644 index e5820a26c52..00000000000 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ /dev/null @@ -1,39 +0,0 @@ -/// Absolute value (magnitude) (f32) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf(x: f32) -> f32 { - select_implementation! { - name: fabsf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::fabs(x) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf(-1.0), 1.0); - assert_eq!(fabsf(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf(f32::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf(f), 0.0); - } - for f in [f32::INFINITY, f32::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf(f), f32::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/fabsf128.rs b/library/compiler-builtins/libm/src/math/fabsf128.rs deleted file mode 100644 index 46429ca4940..00000000000 --- a/library/compiler-builtins/libm/src/math/fabsf128.rs +++ /dev/null @@ -1,31 +0,0 @@ -/// Absolute value (magnitude) (f128) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf128(x: f128) -> f128 { - super::generic::fabs(x) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf128(-1.0), 1.0); - assert_eq!(fabsf128(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf128(f128::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf128(f), 0.0); - } - for f in [f128::INFINITY, f128::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf128(f), f128::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/fabsf16.rs b/library/compiler-builtins/libm/src/math/fabsf16.rs deleted file mode 100644 index eee42ac6a3c..00000000000 --- a/library/compiler-builtins/libm/src/math/fabsf16.rs +++ /dev/null @@ -1,31 +0,0 @@ -/// Absolute value (magnitude) (f16) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf16(x: f16) -> f16 { - super::generic::fabs(x) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf16(-1.0), 1.0); - assert_eq!(fabsf16(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf16(f16::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf16(f), 0.0); - } - for f in [f16::INFINITY, f16::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf16(f), f16::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs deleted file mode 100644 index 367ef517c63..00000000000 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f32) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf(x: f32, y: f32) -> f32 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fdimf128.rs b/library/compiler-builtins/libm/src/math/fdimf128.rs deleted file mode 100644 index 6f3d1d0ff1d..00000000000 --- a/library/compiler-builtins/libm/src/math/fdimf128.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f128) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf128(x: f128, y: f128) -> f128 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fdimf16.rs b/library/compiler-builtins/libm/src/math/fdimf16.rs deleted file mode 100644 index 37bd6885817..00000000000 --- a/library/compiler-builtins/libm/src/math/fdimf16.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f16) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf16(x: f16, y: f16) -> f16 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs deleted file mode 100644 index 16957b7f355..00000000000 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ /dev/null @@ -1,13 +0,0 @@ -/// Floor (f32) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf(x: f32) -> f32 { - select_implementation! { - name: floorf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/src/math/floorf128.rs b/library/compiler-builtins/libm/src/math/floorf128.rs deleted file mode 100644 index 9a9fe415115..00000000000 --- a/library/compiler-builtins/libm/src/math/floorf128.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Floor (f128) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf128(x: f128) -> f128 { - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/src/math/floorf16.rs b/library/compiler-builtins/libm/src/math/floorf16.rs deleted file mode 100644 index f9b868e0410..00000000000 --- a/library/compiler-builtins/libm/src/math/floorf16.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Floor (f16) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf16(x: f16) -> f16 { - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs deleted file mode 100644 index 4e95696e20d..00000000000 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf(x: f32, y: f32) -> f32 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmodf128.rs b/library/compiler-builtins/libm/src/math/fmodf128.rs deleted file mode 100644 index ff0e0493e26..00000000000 --- a/library/compiler-builtins/libm/src/math/fmodf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf128(x: f128, y: f128) -> f128 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmodf16.rs b/library/compiler-builtins/libm/src/math/fmodf16.rs deleted file mode 100644 index 11972a7de4f..00000000000 --- a/library/compiler-builtins/libm/src/math/fmodf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf16(x: f16, y: f16) -> f16 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/ldexpf.rs b/library/compiler-builtins/libm/src/math/ldexpf.rs deleted file mode 100644 index 95b27fc49d2..00000000000 --- a/library/compiler-builtins/libm/src/math/ldexpf.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf(x: f32, n: i32) -> f32 { - super::scalbnf(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/ldexpf128.rs b/library/compiler-builtins/libm/src/math/ldexpf128.rs deleted file mode 100644 index b35277d15fb..00000000000 --- a/library/compiler-builtins/libm/src/math/ldexpf128.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf128(x: f128, n: i32) -> f128 { - super::scalbnf128(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/ldexpf16.rs b/library/compiler-builtins/libm/src/math/ldexpf16.rs deleted file mode 100644 index 8de6cffd699..00000000000 --- a/library/compiler-builtins/libm/src/math/ldexpf16.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf16(x: f16, n: i32) -> f16 { - super::scalbnf16(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs deleted file mode 100644 index b5d7c9d693e..00000000000 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf(x: f32) -> f32 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/src/math/roundf128.rs b/library/compiler-builtins/libm/src/math/roundf128.rs deleted file mode 100644 index fc3164929fe..00000000000 --- a/library/compiler-builtins/libm/src/math/roundf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf128(x: f128) -> f128 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/src/math/roundf16.rs b/library/compiler-builtins/libm/src/math/roundf16.rs deleted file mode 100644 index 8b356eaabee..00000000000 --- a/library/compiler-builtins/libm/src/math/roundf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf16(x: f16) -> f16 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs deleted file mode 100644 index 57e7ba76f60..00000000000 --- a/library/compiler-builtins/libm/src/math/scalbnf.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf(x: f32, n: i32) -> f32 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/scalbnf128.rs b/library/compiler-builtins/libm/src/math/scalbnf128.rs deleted file mode 100644 index c1d2b485585..00000000000 --- a/library/compiler-builtins/libm/src/math/scalbnf128.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf128(x: f128, n: i32) -> f128 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/scalbnf16.rs b/library/compiler-builtins/libm/src/math/scalbnf16.rs deleted file mode 100644 index 2209e1a1795..00000000000 --- a/library/compiler-builtins/libm/src/math/scalbnf16.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf16(x: f16, n: i32) -> f16 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs deleted file mode 100644 index c28a705e378..00000000000 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ /dev/null @@ -1,15 +0,0 @@ -/// The square root of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf(x: f32) -> f32 { - select_implementation! { - name: sqrtf, - use_arch: any( - all(target_arch = "aarch64", target_feature = "neon"), - all(target_arch = "wasm32", intrinsics_enabled), - target_feature = "sse2" - ), - args: x, - } - - super::generic::sqrt(x) -} diff --git a/library/compiler-builtins/libm/src/math/sqrtf128.rs b/library/compiler-builtins/libm/src/math/sqrtf128.rs deleted file mode 100644 index eaef6ae0c1c..00000000000 --- a/library/compiler-builtins/libm/src/math/sqrtf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// The square root of `x` (f128). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf128(x: f128) -> f128 { - return super::generic::sqrt(x); -} diff --git a/library/compiler-builtins/libm/src/math/sqrtf16.rs b/library/compiler-builtins/libm/src/math/sqrtf16.rs deleted file mode 100644 index 7bedb7f8bbb..00000000000 --- a/library/compiler-builtins/libm/src/math/sqrtf16.rs +++ /dev/null @@ -1,11 +0,0 @@ -/// The square root of `x` (f16). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf16(x: f16) -> f16 { - select_implementation! { - name: sqrtf16, - use_arch: all(target_arch = "aarch64", target_feature = "fp16"), - args: x, - } - - return super::generic::sqrt(x); -} diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs deleted file mode 100644 index 14533a26706..00000000000 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ /dev/null @@ -1,23 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f32). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf(x: f32) -> f32 { - select_implementation! { - name: truncf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::trunc(x) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::truncf(1.1), 1.0); - } -} diff --git a/library/compiler-builtins/libm/src/math/truncf128.rs b/library/compiler-builtins/libm/src/math/truncf128.rs deleted file mode 100644 index 9dccc0d0e9d..00000000000 --- a/library/compiler-builtins/libm/src/math/truncf128.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f128). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf128(x: f128) -> f128 { - super::generic::trunc(x) -} diff --git a/library/compiler-builtins/libm/src/math/truncf16.rs b/library/compiler-builtins/libm/src/math/truncf16.rs deleted file mode 100644 index d7c3d225cf9..00000000000 --- a/library/compiler-builtins/libm/src/math/truncf16.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f16). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf16(x: f16) -> f16 { - super::generic::trunc(x) -} -- cgit 1.4.1-3-g733a5 From eec894d3f9bf708d8c4c0679bc57ed899d6c37ab Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 1 May 2025 21:56:30 +0200 Subject: Fix future-incompatible lint group test --- tests/ui/future-incompatible-lint-group.rs | 10 +++---- tests/ui/future-incompatible-lint-group.stderr | 40 ++++++++++++++++++++------ 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/tests/ui/future-incompatible-lint-group.rs b/tests/ui/future-incompatible-lint-group.rs index c84538318f7..ed2c47bb609 100644 --- a/tests/ui/future-incompatible-lint-group.rs +++ b/tests/ui/future-incompatible-lint-group.rs @@ -2,16 +2,14 @@ // lints for changes that are not tied to an edition #![deny(future_incompatible)] +// Error since this is a `future_incompatible` lint +macro_rules! m { ($i) => {} } //~ ERROR missing fragment specifier + //~| WARN this was previously accepted + trait Tr { // Warn only since this is not a `future_incompatible` lint fn f(u8) {} //~ WARN anonymous parameters are deprecated //~| WARN this is accepted in the current edition } -pub mod submodule { - // Error since this is a `future_incompatible` lint - #![doc(test(some_test))] - //~^ ERROR this attribute can only be applied at the crate level -} - fn main() {} diff --git a/tests/ui/future-incompatible-lint-group.stderr b/tests/ui/future-incompatible-lint-group.stderr index 4e6c434fa29..4c867e0aab3 100644 --- a/tests/ui/future-incompatible-lint-group.stderr +++ b/tests/ui/future-incompatible-lint-group.stderr @@ -1,5 +1,20 @@ +error: missing fragment specifier + --> $DIR/future-incompatible-lint-group.rs:6:19 + | +LL | macro_rules! m { ($i) => {} } + | ^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 +note: the lint level is defined here + --> $DIR/future-incompatible-lint-group.rs:3:9 + | +LL | #![deny(future_incompatible)] + | ^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]` + warning: anonymous parameters are deprecated and will be removed in the next edition - --> $DIR/future-incompatible-lint-group.rs:7:10 + --> $DIR/future-incompatible-lint-group.rs:11:10 | LL | fn f(u8) {} | ^^ help: try naming the parameter or explicitly ignoring it: `_: u8` @@ -8,14 +23,21 @@ LL | fn f(u8) {} = note: for more information, see issue #41686 = note: `#[warn(anonymous_parameters)]` on by default -error: this attribute can only be applied at the crate level - --> $DIR/future-incompatible-lint-group.rs:13:12 +error: aborting due to 1 previous error; 1 warning emitted + +Future incompatibility report: Future breakage diagnostic: +error: missing fragment specifier + --> $DIR/future-incompatible-lint-group.rs:6:19 | -LL | #![doc(test(some_test))] - | ^^^^^^^^^^^^^^^ +LL | macro_rules! m { ($i) => {} } + | ^^ | - = note: read for more information - = note: `#[deny(invalid_doc_attributes)]` on by default - -error: aborting due to 1 previous error; 1 warning emitted + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 +note: the lint level is defined here + --> $DIR/future-incompatible-lint-group.rs:3:9 + | +LL | #![deny(future_incompatible)] + | ^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]` -- cgit 1.4.1-3-g733a5 From 80c6a0885079038caa0bc90670afbf5ead806c17 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 1 May 2025 17:24:00 +0200 Subject: Allow `#![doc(test(attr(..)))]` at module level too --- compiler/rustc_passes/messages.ftl | 5 +++ compiler/rustc_passes/src/check_attr.rs | 51 ++++++++++++++++++---- compiler/rustc_passes/src/errors.rs | 12 ++++- .../src/write-documentation/the-doc-attribute.md | 19 ++++++++ tests/rustdoc-ui/lints/invalid-doc-attr.rs | 4 ++ tests/rustdoc-ui/lints/invalid-doc-attr.stderr | 32 +++++++++----- tests/ui/rustdoc/doc-test-attr-pass.rs | 4 ++ 7 files changed, 107 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 6d815e510ea..2f264ed4fc0 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -46,6 +46,11 @@ passes_attr_crate_level = .suggestion = to apply to the crate, use an inner attribute .note = read for more information +passes_attr_mod_level = + this attribute can only be applied at module level + .suggestion = to apply to the crate, use an inner attribute at the crate level + .note = read for more information + passes_attr_only_in_functions = `{$attr}` attribute can only be used on functions diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5c0d0cf4796..376b424a1af 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1252,7 +1252,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let bang_span = attr.span().lo() + BytePos(1); let sugg = (attr.style() == AttrStyle::Outer && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID) - .then_some(errors::AttrCrateLevelOnlySugg { + .then_some(errors::AttrCrateLevelSugg { attr: attr.span().with_lo(bang_span).with_hi(bang_span), }); self.tcx.emit_node_span_lint( @@ -1266,13 +1266,50 @@ impl<'tcx> CheckAttrVisitor<'tcx> { true } - /// Checks that `doc(test(...))` attribute contains only valid attributes. Returns `true` if - /// valid. - fn check_test_attr(&self, meta: &MetaItemInner, hir_id: HirId) { + /// Checks that an attribute is used at module level. Returns `true` if valid. + fn check_attr_mod_level( + &self, + attr: &Attribute, + meta: &MetaItemInner, + hir_id: HirId, + target: Target, + ) -> bool { + if target != Target::Mod { + // insert a bang between `#` and `[...` + let bang_span = attr.span().lo() + BytePos(1); + let sugg = (attr.style() == AttrStyle::Outer + && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID) + .then_some(errors::AttrCrateLevelSugg { + attr: attr.span().with_lo(bang_span).with_hi(bang_span), + }); + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span(), + errors::AttrModLevelOnly { sugg }, + ); + return false; + } + true + } + + /// Checks that `doc(test(...))` attribute contains only valid attributes and are at the right place. + fn check_test_attr( + &self, + attr: &Attribute, + meta: &MetaItemInner, + hir_id: HirId, + target: Target, + ) { if let Some(metas) = meta.meta_item_list() { for i_meta in metas { match (i_meta.name(), i_meta.meta_item()) { - (Some(sym::attr | sym::no_crate_inject), _) => {} + (Some(sym::attr), _) => { + self.check_attr_mod_level(attr, meta, hir_id, target); + } + (Some(sym::no_crate_inject), _) => { + self.check_attr_crate_level(attr, meta, hir_id); + } (_, Some(m)) => { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, @@ -1359,9 +1396,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Some(sym::test) => { - if self.check_attr_crate_level(attr, meta, hir_id) { - self.check_test_attr(meta, hir_id); - } + self.check_test_attr(attr, meta, hir_id, target); } Some( diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 00682a9c7a7..38b0db37e12 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1890,12 +1890,20 @@ pub(crate) struct UnusedVarTryIgnoreSugg { #[note] pub(crate) struct AttrCrateLevelOnly { #[subdiagnostic] - pub sugg: Option, + pub sugg: Option, +} + +#[derive(LintDiagnostic)] +#[diag(passes_attr_mod_level)] +#[note] +pub(crate) struct AttrModLevelOnly { + #[subdiagnostic] + pub sugg: Option, } #[derive(Subdiagnostic)] #[suggestion(passes_suggestion, applicability = "maybe-incorrect", code = "!", style = "verbose")] -pub(crate) struct AttrCrateLevelOnlySugg { +pub(crate) struct AttrCrateLevelSugg { #[primary_span] pub attr: Span, } diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md index 45146993371..afbcf4000c5 100644 --- a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md +++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md @@ -141,6 +141,11 @@ But if you include this: it will not. +## At the module level + +These forms of the `#[doc]` attribute are used on individual modules, to control how +they are documented. + ### `test(attr(...))` This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For @@ -148,6 +153,20 @@ example, if you want your doctests to fail if they have dead code, you could add ```rust,no_run #![doc(test(attr(deny(dead_code))))] + +mod my_mod { + #![doc(test(attr(allow(dead_code))))] // but allow `dead_code` for this module +} +``` + +`test(attr(..))` attributes are appended to the parent module's, they do not replace the current +list of attributes. In the previous example, both attributes would be present: + +```rust,no_run +// For every doctest in `my_mod` + +#![deny(dead_code)] // from the crate-root +#![allow(dead_code)] // from `my_mod` ``` ## At the item level diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.rs b/tests/rustdoc-ui/lints/invalid-doc-attr.rs index e1cc08ca242..cd5ae44b126 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.rs +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.rs @@ -4,6 +4,10 @@ #![doc(masked)] //~^ ERROR this attribute can only be applied to an `extern crate` item +#[doc(test(attr(allow(warnings))))] +//~^ ERROR can only be applied at module level +//~| HELP to apply to the crate, use an inner attribute +//~| SUGGESTION ! #[doc(test(no_crate_inject))] //~^ ERROR can only be applied at the crate level //~| HELP to apply to the crate, use an inner attribute diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr index 7621999a8ca..0fd55ff94d8 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr @@ -1,18 +1,30 @@ -error: this attribute can only be applied at the crate level +error: this attribute can only be applied at module level --> $DIR/invalid-doc-attr.rs:7:7 | +LL | #[doc(test(attr(allow(warnings))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: read for more information + = note: `#[deny(invalid_doc_attributes)]` on by default +help: to apply to the crate, use an inner attribute at the crate level + | +LL | #![doc(test(attr(allow(warnings))))] + | + + +error: this attribute can only be applied at the crate level + --> $DIR/invalid-doc-attr.rs:11:7 + | LL | #[doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ | = note: read for more information - = note: `#[deny(invalid_doc_attributes)]` on by default help: to apply to the crate, use an inner attribute | LL | #![doc(test(no_crate_inject))] | + error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:11:7 + --> $DIR/invalid-doc-attr.rs:15:7 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -23,7 +35,7 @@ LL | pub fn foo() {} = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:16:12 + --> $DIR/invalid-doc-attr.rs:20:12 | LL | #![doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +43,7 @@ LL | #![doc(test(no_crate_inject))] = note: read for more information error: conflicting doc inlining attributes - --> $DIR/invalid-doc-attr.rs:26:7 + --> $DIR/invalid-doc-attr.rs:30:7 | LL | #[doc(inline)] | ^^^^^^ this attribute... @@ -41,7 +53,7 @@ LL | #[doc(no_inline)] = help: remove one of the conflicting attributes error: this attribute can only be applied to an `extern crate` item - --> $DIR/invalid-doc-attr.rs:32:7 + --> $DIR/invalid-doc-attr.rs:36:7 | LL | #[doc(masked)] | ^^^^^^ only applicable on `extern crate` items @@ -52,7 +64,7 @@ LL | pub struct Masked; = note: read for more information error: this attribute cannot be applied to an `extern crate self` item - --> $DIR/invalid-doc-attr.rs:36:7 + --> $DIR/invalid-doc-attr.rs:40:7 | LL | #[doc(masked)] | ^^^^^^ not applicable on `extern crate self` items @@ -69,7 +81,7 @@ LL | #![doc(masked)] = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:19:11 + --> $DIR/invalid-doc-attr.rs:23:11 | LL | #[doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ @@ -77,7 +89,7 @@ LL | #[doc(test(no_crate_inject))] = note: read for more information error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:21:11 + --> $DIR/invalid-doc-attr.rs:25:11 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -87,5 +99,5 @@ LL | pub fn baz() {} | = note: read for more information -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/rustdoc/doc-test-attr-pass.rs b/tests/ui/rustdoc/doc-test-attr-pass.rs index f0120b7c2d0..40ffd5b2572 100644 --- a/tests/ui/rustdoc/doc-test-attr-pass.rs +++ b/tests/ui/rustdoc/doc-test-attr-pass.rs @@ -6,4 +6,8 @@ #![doc(test(attr(deny(warnings))))] #![doc(test())] +mod test { + #![doc(test(attr(allow(warnings))))] +} + pub fn foo() {} -- cgit 1.4.1-3-g733a5 From 9d9705f4c360df5d8c77876496b0c5594cbc7fa0 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 1 May 2025 18:15:04 +0200 Subject: Collect and use `#![doc(test(attr(..)))]` at module level too --- src/librustdoc/doctest.rs | 18 ++---- src/librustdoc/doctest/extracted.rs | 5 +- src/librustdoc/doctest/make.rs | 21 ++++++- src/librustdoc/doctest/markdown.rs | 2 +- src/librustdoc/doctest/runner.rs | 11 +++- src/librustdoc/doctest/rust.rs | 40 ++++++++++++- src/librustdoc/doctest/tests.rs | 68 +++++++++++++--------- src/librustdoc/html/markdown.rs | 1 - tests/rustdoc-ui/doctest/dead-code-module-2.rs | 27 +++++++++ tests/rustdoc-ui/doctest/dead-code-module-2.stdout | 30 ++++++++++ tests/rustdoc-ui/doctest/dead-code-module.rs | 18 ++++++ tests/rustdoc-ui/doctest/dead-code-module.stdout | 29 +++++++++ .../doctest/doc-test-attr-pass-module.rs | 11 ++++ 13 files changed, 229 insertions(+), 52 deletions(-) create mode 100644 tests/rustdoc-ui/doctest/dead-code-module-2.rs create mode 100644 tests/rustdoc-ui/doctest/dead-code-module-2.stdout create mode 100644 tests/rustdoc-ui/doctest/dead-code-module.rs create mode 100644 tests/rustdoc-ui/doctest/dead-code-module.stdout create mode 100644 tests/rustdoc-ui/doctest/doc-test-attr-pass-module.rs diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index b2fe24db0a2..45e5c894bb9 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -45,8 +45,6 @@ pub(crate) struct GlobalTestOptions { /// Whether inserting extra indent spaces in code block, /// default is `false`, only `true` for generating code link of Rust playground pub(crate) insert_indent_space: bool, - /// Additional crate-level attributes to add to doctests. - pub(crate) attrs: Vec, /// Path to file containing arguments for the invocation of rustc. pub(crate) args_file: PathBuf, } @@ -371,12 +369,9 @@ fn scrape_test_config( attrs: &[hir::Attribute], args_file: PathBuf, ) -> GlobalTestOptions { - use rustc_ast_pretty::pprust; - let mut opts = GlobalTestOptions { crate_name, no_crate_inject: false, - attrs: Vec::new(), insert_indent_space: false, args_file, }; @@ -393,13 +388,7 @@ fn scrape_test_config( if attr.has_name(sym::no_crate_inject) { opts.no_crate_inject = true; } - if attr.has_name(sym::attr) - && let Some(l) = attr.meta_item_list() - { - for item in l { - opts.attrs.push(pprust::meta_list_item_to_string(item)); - } - } + // NOTE: `test(attr(..))` is handled when discovering the individual tests } opts @@ -848,6 +837,7 @@ pub(crate) struct ScrapedDocTest { text: String, name: String, span: Span, + global_crate_attrs: Vec, } impl ScrapedDocTest { @@ -858,6 +848,7 @@ impl ScrapedDocTest { langstr: LangString, text: String, span: Span, + global_crate_attrs: Vec, ) -> Self { let mut item_path = logical_path.join("::"); item_path.retain(|c| c != ' '); @@ -867,7 +858,7 @@ impl ScrapedDocTest { let name = format!("{} - {item_path}(line {line})", filename.prefer_remapped_unconditionaly()); - Self { filename, line, langstr, text, name, span } + Self { filename, line, langstr, text, name, span, global_crate_attrs } } fn edition(&self, opts: &RustdocOptions) -> Edition { self.langstr.edition.unwrap_or(opts.edition) @@ -949,6 +940,7 @@ impl CreateRunnableDocTests { let edition = scraped_test.edition(&self.rustdoc_options); let doctest = BuildDocTestBuilder::new(&scraped_test.text) .crate_name(&self.opts.crate_name) + .global_crate_attrs(scraped_test.global_crate_attrs.clone()) .edition(edition) .can_merge_doctests(self.can_merge_doctests) .test_id(test_id) diff --git a/src/librustdoc/doctest/extracted.rs b/src/librustdoc/doctest/extracted.rs index 3b17ccc78c7..ebe6bfd22ba 100644 --- a/src/librustdoc/doctest/extracted.rs +++ b/src/librustdoc/doctest/extracted.rs @@ -35,13 +35,16 @@ impl ExtractedDocTests { ) { let edition = scraped_test.edition(options); - let ScrapedDocTest { filename, line, langstr, text, name, .. } = scraped_test; + let ScrapedDocTest { filename, line, langstr, text, name, global_crate_attrs, .. } = + scraped_test; let doctest = BuildDocTestBuilder::new(&text) .crate_name(&opts.crate_name) + .global_crate_attrs(global_crate_attrs) .edition(edition) .lang_str(&langstr) .build(None); + let (full_test_code, size) = doctest.generate_unique_doctest( &text, langstr.test_harness, diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 66647b88018..5e571613d6f 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -45,6 +45,7 @@ pub(crate) struct BuildDocTestBuilder<'a> { test_id: Option, lang_str: Option<&'a LangString>, span: Span, + global_crate_attrs: Vec, } impl<'a> BuildDocTestBuilder<'a> { @@ -57,6 +58,7 @@ impl<'a> BuildDocTestBuilder<'a> { test_id: None, lang_str: None, span: DUMMY_SP, + global_crate_attrs: Vec::new(), } } @@ -96,6 +98,12 @@ impl<'a> BuildDocTestBuilder<'a> { self } + #[inline] + pub(crate) fn global_crate_attrs(mut self, global_crate_attrs: Vec) -> Self { + self.global_crate_attrs = global_crate_attrs; + self + } + pub(crate) fn build(self, dcx: Option>) -> DocTestBuilder { let BuildDocTestBuilder { source, @@ -106,6 +114,7 @@ impl<'a> BuildDocTestBuilder<'a> { test_id, lang_str, span, + global_crate_attrs, } = self; let can_merge_doctests = can_merge_doctests && lang_str.is_some_and(|lang_str| { @@ -133,6 +142,7 @@ impl<'a> BuildDocTestBuilder<'a> { // If the AST returned an error, we don't want this doctest to be merged with the // others. return DocTestBuilder::invalid( + Vec::new(), String::new(), String::new(), String::new(), @@ -155,6 +165,7 @@ impl<'a> BuildDocTestBuilder<'a> { DocTestBuilder { supports_color, has_main_fn, + global_crate_attrs, crate_attrs, maybe_crate_attrs, crates, @@ -173,6 +184,7 @@ pub(crate) struct DocTestBuilder { pub(crate) supports_color: bool, pub(crate) already_has_extern_crate: bool, pub(crate) has_main_fn: bool, + pub(crate) global_crate_attrs: Vec, pub(crate) crate_attrs: String, /// If this is a merged doctest, it will be put into `everything_else`, otherwise it will /// put into `crate_attrs`. @@ -186,6 +198,7 @@ pub(crate) struct DocTestBuilder { impl DocTestBuilder { fn invalid( + global_crate_attrs: Vec, crate_attrs: String, maybe_crate_attrs: String, crates: String, @@ -195,6 +208,7 @@ impl DocTestBuilder { Self { supports_color: false, has_main_fn: false, + global_crate_attrs, crate_attrs, maybe_crate_attrs, crates, @@ -224,7 +238,8 @@ impl DocTestBuilder { let mut line_offset = 0; let mut prog = String::new(); let everything_else = self.everything_else.trim(); - if opts.attrs.is_empty() { + + if self.global_crate_attrs.is_empty() { // If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some // lints that are commonly triggered in doctests. The crate-level test attributes are // commonly used to make tests fail in case they trigger warnings, so having this there in @@ -233,8 +248,8 @@ impl DocTestBuilder { line_offset += 1; } - // Next, any attributes that came from the crate root via #![doc(test(attr(...)))]. - for attr in &opts.attrs { + // Next, any attributes that came from #![doc(test(attr(...)))]. + for attr in &self.global_crate_attrs { prog.push_str(&format!("#![{attr}]\n")); line_offset += 1; } diff --git a/src/librustdoc/doctest/markdown.rs b/src/librustdoc/doctest/markdown.rs index e358a7e44e5..7f26605f256 100644 --- a/src/librustdoc/doctest/markdown.rs +++ b/src/librustdoc/doctest/markdown.rs @@ -31,6 +31,7 @@ impl DocTestVisitor for MdCollector { config, test, DUMMY_SP, + Vec::new(), )); } @@ -96,7 +97,6 @@ pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> { crate_name, no_crate_inject: true, insert_indent_space: false, - attrs: vec![], args_file, }; diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index 39a4f23560a..f0914474c79 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -12,6 +12,7 @@ use crate::html::markdown::{Ignore, LangString}; /// Convenient type to merge compatible doctests into one. pub(crate) struct DocTestRunner { crate_attrs: FxIndexSet, + global_crate_attrs: FxIndexSet, ids: String, output: String, output_merged_tests: String, @@ -23,6 +24,7 @@ impl DocTestRunner { pub(crate) fn new() -> Self { Self { crate_attrs: FxIndexSet::default(), + global_crate_attrs: FxIndexSet::default(), ids: String::new(), output: String::new(), output_merged_tests: String::new(), @@ -46,6 +48,9 @@ impl DocTestRunner { for line in doctest.crate_attrs.split('\n') { self.crate_attrs.insert(line.to_string()); } + for line in &doctest.global_crate_attrs { + self.global_crate_attrs.insert(line.to_string()); + } } self.ids.push_str(&format!( "tests.push({}::TEST);\n", @@ -85,7 +90,7 @@ impl DocTestRunner { code_prefix.push('\n'); } - if opts.attrs.is_empty() { + if self.global_crate_attrs.is_empty() { // If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some // lints that are commonly triggered in doctests. The crate-level test attributes are // commonly used to make tests fail in case they trigger warnings, so having this there in @@ -93,8 +98,8 @@ impl DocTestRunner { code_prefix.push_str("#![allow(unused)]\n"); } - // Next, any attributes that came from the crate root via #![doc(test(attr(...)))]. - for attr in &opts.attrs { + // Next, any attributes that came from #![doc(test(attr(...)))]. + for attr in &self.global_crate_attrs { code_prefix.push_str(&format!("#![{attr}]\n")); } diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index f9d2aa3d3b4..4e9b1ee36f3 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -4,6 +4,7 @@ use std::cell::Cell; use std::env; use std::sync::Arc; +use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{self as hir, CRATE_HIR_ID, intravisit}; @@ -11,7 +12,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_resolve::rustdoc::span_of_fragments; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span}; +use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span, sym}; use super::{DocTestVisitor, ScrapedDocTest}; use crate::clean::{Attributes, extract_cfg_from_attrs}; @@ -22,6 +23,7 @@ struct RustCollector { tests: Vec, cur_path: Vec, position: Span, + global_crate_attrs: Vec, } impl RustCollector { @@ -75,6 +77,7 @@ impl DocTestVisitor for RustCollector { config, test, span, + self.global_crate_attrs.clone(), )); } @@ -94,6 +97,7 @@ impl<'tcx> HirCollector<'tcx> { cur_path: vec![], position: DUMMY_SP, tests: vec![], + global_crate_attrs: Vec::new(), }; Self { codes, tcx, collector } } @@ -170,6 +174,40 @@ impl<'tcx> intravisit::Visitor<'tcx> for HirCollector<'tcx> { self.tcx } + fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _s: Span, hir_id: hir::HirId) { + let attrs = self.tcx.hir_attrs(hir_id); + + if !attrs.is_empty() { + // Try collecting `#![doc(test(attr(...)))]` from the attribute module + let old_len = self.collector.global_crate_attrs.len(); + for doc_test_attrs in attrs + .iter() + .filter(|a| a.has_name(sym::doc)) + .flat_map(|a| a.meta_item_list().unwrap_or_default()) + .filter(|a| a.has_name(sym::test)) + { + let Some(doc_test_attrs) = doc_test_attrs.meta_item_list() else { continue }; + for attr in doc_test_attrs + .iter() + .filter(|a| a.has_name(sym::attr)) + .flat_map(|a| a.meta_item_list().unwrap_or_default()) + .map(|i| pprust::meta_list_item_to_string(i)) + { + // Add the additional attributes to the global_crate_attrs vector + self.collector.global_crate_attrs.push(attr); + } + } + + let r = intravisit::walk_mod(self, m); + + // Restore global_crate_attrs to it's previous size/content + self.collector.global_crate_attrs.truncate(old_len); + r + } else { + intravisit::walk_mod(self, m) + } + } + fn visit_item(&mut self, item: &'tcx hir::Item<'_>) { let name = match &item.kind { hir::ItemKind::Impl(impl_) => { diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index 08248fdf39b..ce2984ced79 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -7,9 +7,11 @@ fn make_test( crate_name: Option<&str>, dont_insert_main: bool, opts: &GlobalTestOptions, + global_crate_attrs: Vec<&str>, test_id: Option<&str>, ) -> (String, usize) { - let mut builder = BuildDocTestBuilder::new(test_code); + let mut builder = BuildDocTestBuilder::new(test_code) + .global_crate_attrs(global_crate_attrs.into_iter().map(|a| a.to_string()).collect()); if let Some(crate_name) = crate_name { builder = builder.crate_name(crate_name); } @@ -28,7 +30,6 @@ fn default_global_opts(crate_name: impl Into) -> GlobalTestOptions { crate_name: crate_name.into(), no_crate_inject: false, insert_indent_space: false, - attrs: vec![], args_file: PathBuf::new(), } } @@ -43,7 +44,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -58,7 +59,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -77,7 +78,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 3)); } @@ -94,7 +95,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -112,7 +113,7 @@ use std::*; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("std"), false, &opts, None); + let (output, len) = make_test(input, Some("std"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -131,7 +132,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -148,7 +149,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -156,8 +157,7 @@ assert_eq!(2+2, 4); fn make_test_opts_attrs() { // If you supplied some doctest attributes with `#![doc(test(attr(...)))]`, it will use // those instead of the stock `#![allow(unused)]`. - let mut opts = default_global_opts("asdf"); - opts.attrs.push("feature(sick_rad)".to_string()); + let opts = default_global_opts("asdf"); let input = "use asdf::qwop; assert_eq!(2+2, 4);"; let expected = "#![feature(sick_rad)] @@ -168,11 +168,10 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = + make_test(input, Some("asdf"), false, &opts, vec!["feature(sick_rad)"], None); assert_eq!((output, len), (expected, 3)); - // Adding more will also bump the returned line offset. - opts.attrs.push("feature(hella_dope)".to_string()); let expected = "#![feature(sick_rad)] #![feature(hella_dope)] #[allow(unused_extern_crates)] @@ -182,7 +181,18 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test( + input, + Some("asdf"), + false, + &opts, + vec![ + "feature(sick_rad)", + // Adding more will also bump the returned line offset. + "feature(hella_dope)", + ], + None, + ); assert_eq!((output, len), (expected, 4)); } @@ -200,7 +210,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -216,7 +226,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -232,7 +242,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -246,7 +256,7 @@ assert_eq!(2+2, 4);"; //Ceci n'est pas une `fn main` assert_eq!(2+2, 4);" .to_string(); - let (output, len) = make_test(input, None, true, &opts, None); + let (output, len) = make_test(input, None, true, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -264,7 +274,7 @@ assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -284,7 +294,7 @@ assert_eq!(asdf::foo, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 3)); } @@ -302,7 +312,7 @@ test_wrapper! { }" .to_string(); - let (output, len) = make_test(input, Some("my_crate"), false, &opts, None); + let (output, len) = make_test(input, Some("my_crate"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -322,7 +332,7 @@ io::stdin().read_line(&mut input)?; Ok::<(), io:Error>(()) } _inner().unwrap() }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -336,7 +346,7 @@ fn main() { #[allow(non_snake_case)] fn _doctest_main__some_unique_name() { assert_eq!(2+2, 4); } _doctest_main__some_unique_name() }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, Some("_some_unique_name")); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), Some("_some_unique_name")); assert_eq!((output, len), (expected, 2)); } @@ -355,7 +365,7 @@ fn main() { eprintln!(\"hello anan\"); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -375,7 +385,7 @@ fn main() { eprintln!(\"hello anan\"); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -400,7 +410,7 @@ fn main() { }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); // And same, if there is a `main` function provided by the user, we ensure that it's @@ -420,7 +430,7 @@ fn main() {}"; fn main() {}" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -448,6 +458,6 @@ pub mod outer_module { } }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index ad7dfafd90c..b48082defa7 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -300,7 +300,6 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { crate_name: krate.map(String::from).unwrap_or_default(), no_crate_inject: false, insert_indent_space: true, - attrs: vec![], args_file: PathBuf::new(), }; let mut builder = doctest::BuildDocTestBuilder::new(&test).edition(edition); diff --git a/tests/rustdoc-ui/doctest/dead-code-module-2.rs b/tests/rustdoc-ui/doctest/dead-code-module-2.rs new file mode 100644 index 00000000000..de7b11b91ec --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-module-2.rs @@ -0,0 +1,27 @@ +// Same test as dead-code-module but with 2 doc(test(attr())) at different levels. + +//@ edition: 2024 +//@ compile-flags:--test +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +#![doc(test(attr(allow(unused_variables))))] + +mod my_mod { + #![doc(test(attr(deny(warnings))))] + + /// Example + /// + /// ```rust,no_run + /// trait T { fn f(); } + /// ``` + pub fn f() {} +} + +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarning { fn no_deny_warnings(); } +/// ``` +pub fn g() {} diff --git a/tests/rustdoc-ui/doctest/dead-code-module-2.stdout b/tests/rustdoc-ui/doctest/dead-code-module-2.stdout new file mode 100644 index 00000000000..36b8eaed22b --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-module-2.stdout @@ -0,0 +1,30 @@ + +running 2 tests +test $DIR/dead-code-module-2.rs - my_mod::f (line 16) - compile ... FAILED +test $DIR/dead-code-module-2.rs - g (line 24) - compile ... ok + +failures: + +---- $DIR/dead-code-module-2.rs - my_mod::f (line 16) stdout ---- +error: trait `T` is never used + --> $DIR/dead-code-module-2.rs:17:7 + | +LL | trait T { fn f(); } + | ^ + | +note: the lint level is defined here + --> $DIR/dead-code-module-2.rs:15:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code-module-2.rs - my_mod::f (line 16) + +test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/dead-code-module.rs b/tests/rustdoc-ui/doctest/dead-code-module.rs new file mode 100644 index 00000000000..f825749a6a2 --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-module.rs @@ -0,0 +1,18 @@ +// Same test as dead-code but inside a module. + +//@ edition: 2024 +//@ compile-flags:--test +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +mod my_mod { + #![doc(test(attr(allow(unused_variables), deny(warnings))))] + + /// Example + /// + /// ```rust,no_run + /// trait T { fn f(); } + /// ``` + pub fn f() {} +} diff --git a/tests/rustdoc-ui/doctest/dead-code-module.stdout b/tests/rustdoc-ui/doctest/dead-code-module.stdout new file mode 100644 index 00000000000..b5ccf225d25 --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-module.stdout @@ -0,0 +1,29 @@ + +running 1 test +test $DIR/dead-code-module.rs - my_mod::f (line 14) - compile ... FAILED + +failures: + +---- $DIR/dead-code-module.rs - my_mod::f (line 14) stdout ---- +error: trait `T` is never used + --> $DIR/dead-code-module.rs:15:7 + | +LL | trait T { fn f(); } + | ^ + | +note: the lint level is defined here + --> $DIR/dead-code-module.rs:13:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code-module.rs - my_mod::f (line 14) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/doc-test-attr-pass-module.rs b/tests/rustdoc-ui/doctest/doc-test-attr-pass-module.rs new file mode 100644 index 00000000000..e916ca41ea0 --- /dev/null +++ b/tests/rustdoc-ui/doctest/doc-test-attr-pass-module.rs @@ -0,0 +1,11 @@ +//@ check-pass + +#![crate_type = "lib"] +#![deny(invalid_doc_attributes)] +#![doc(test(no_crate_inject))] + +mod my_mod { + #![doc(test(attr(deny(warnings))))] + + pub fn foo() {} +} -- cgit 1.4.1-3-g733a5 From 041d95d4dca9f31c4abf6938bb5eb1d893917e5b Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 1 May 2025 18:44:38 +0200 Subject: Allow `#![doc(test(attr(..)))]` doctests to be again merged together --- src/librustdoc/doctest.rs | 31 +++++++++++++++++----- .../run-make/doctests-keep-binaries-2024/rmake.rs | 17 +++++++++++- tests/rustdoc-ui/doctest/dead-code-module-2.stdout | 11 +++++--- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 45e5c894bb9..a81d6020f71 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -5,6 +5,7 @@ mod runner; mod rust; use std::fs::File; +use std::hash::{Hash, Hasher}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::process::{self, Command, Stdio}; @@ -14,7 +15,7 @@ use std::{panic, str}; pub(crate) use make::{BuildDocTestBuilder, DocTestBuilder}; pub(crate) use markdown::test as test_markdown; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHasher, FxIndexMap, FxIndexSet}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagCtxtHandle}; use rustc_hir as hir; @@ -281,7 +282,7 @@ pub(crate) fn run_tests( rustdoc_options: &Arc, unused_extern_reports: &Arc>>, mut standalone_tests: Vec, - mergeable_tests: FxIndexMap>, + mergeable_tests: FxIndexMap>, // We pass this argument so we can drop it manually before using `exit`. mut temp_dir: Option, ) { @@ -296,7 +297,7 @@ pub(crate) fn run_tests( let mut ran_edition_tests = 0; let target_str = rustdoc_options.target.to_string(); - for (edition, mut doctests) in mergeable_tests { + for (MergeableTestKey { edition, global_crate_attrs_hash }, mut doctests) in mergeable_tests { if doctests.is_empty() { continue; } @@ -306,8 +307,8 @@ pub(crate) fn run_tests( let rustdoc_test_options = IndividualTestOptions::new( rustdoc_options, - &Some(format!("merged_doctest_{edition}")), - PathBuf::from(format!("doctest_{edition}.rs")), + &Some(format!("merged_doctest_{edition}_{global_crate_attrs_hash}")), + PathBuf::from(format!("doctest_{edition}_{global_crate_attrs_hash}.rs")), ); for (doctest, scraped_test) in &doctests { @@ -887,9 +888,15 @@ pub(crate) trait DocTestVisitor { fn visit_header(&mut self, _name: &str, _level: u32) {} } +#[derive(Clone, Debug, Hash, Eq, PartialEq)] +pub(crate) struct MergeableTestKey { + edition: Edition, + global_crate_attrs_hash: u64, +} + struct CreateRunnableDocTests { standalone_tests: Vec, - mergeable_tests: FxIndexMap>, + mergeable_tests: FxIndexMap>, rustdoc_options: Arc, opts: GlobalTestOptions, @@ -957,7 +964,17 @@ impl CreateRunnableDocTests { let test_desc = self.generate_test_desc_and_fn(doctest, scraped_test); self.standalone_tests.push(test_desc); } else { - self.mergeable_tests.entry(edition).or_default().push((doctest, scraped_test)); + self.mergeable_tests + .entry(MergeableTestKey { + edition, + global_crate_attrs_hash: { + let mut hasher = FxHasher::default(); + scraped_test.global_crate_attrs.hash(&mut hasher); + hasher.finish() + }, + }) + .or_default() + .push((doctest, scraped_test)); } } diff --git a/tests/run-make/doctests-keep-binaries-2024/rmake.rs b/tests/run-make/doctests-keep-binaries-2024/rmake.rs index 3e8ffcbf244..97324e1dcbc 100644 --- a/tests/run-make/doctests-keep-binaries-2024/rmake.rs +++ b/tests/run-make/doctests-keep-binaries-2024/rmake.rs @@ -16,7 +16,22 @@ fn setup_test_env(callback: F) { } fn check_generated_binaries() { - run("doctests/merged_doctest_2024/rust_out"); + let mut found_merged_doctest = false; + rfs::read_dir_entries("doctests/", |path| { + if path + .file_name() + .and_then(|name| name.to_str()) + .is_some_and(|name| name.starts_with("merged_doctest_2024")) + { + found_merged_doctest = true; + let rust_out = path.join("rust_out"); + let rust_out = rust_out.to_string_lossy(); + run(&*rust_out); + } + }); + if !found_merged_doctest { + panic!("no directory starting with `merged_doctest_2024` found under `doctests/`"); + } } fn main() { diff --git a/tests/rustdoc-ui/doctest/dead-code-module-2.stdout b/tests/rustdoc-ui/doctest/dead-code-module-2.stdout index 36b8eaed22b..d44068dcbf5 100644 --- a/tests/rustdoc-ui/doctest/dead-code-module-2.stdout +++ b/tests/rustdoc-ui/doctest/dead-code-module-2.stdout @@ -1,8 +1,13 @@ -running 2 tests -test $DIR/dead-code-module-2.rs - my_mod::f (line 16) - compile ... FAILED +running 1 test test $DIR/dead-code-module-2.rs - g (line 24) - compile ... ok +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + + +running 1 test +test $DIR/dead-code-module-2.rs - my_mod::f (line 16) - compile ... FAILED + failures: ---- $DIR/dead-code-module-2.rs - my_mod::f (line 16) stdout ---- @@ -26,5 +31,5 @@ Couldn't compile the test. failures: $DIR/dead-code-module-2.rs - my_mod::f (line 16) -test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME -- cgit 1.4.1-3-g733a5 From 316e62a05855d80c6800dac3437414f7675afbc9 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 5 May 2025 22:50:40 +0200 Subject: Allow `#![doc(test(attr(..)))]` at every level --- compiler/rustc_passes/messages.ftl | 5 -- compiler/rustc_passes/src/check_attr.rs | 41 ++---------- compiler/rustc_passes/src/errors.rs | 12 +--- .../src/write-documentation/the-doc-attribute.md | 51 +++++++-------- tests/rustdoc-ui/lints/invalid-doc-attr.rs | 4 -- tests/rustdoc-ui/lints/invalid-doc-attr.stderr | 32 +++------- tests/ui/lint/unused/useless-comment.rs | 7 +++ tests/ui/lint/unused/useless-comment.stderr | 73 +++++++++++++++++++--- tests/ui/rustdoc/doc-test-attr-pass.rs | 38 +++++++++++ 9 files changed, 147 insertions(+), 116 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 2f264ed4fc0..6d815e510ea 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -46,11 +46,6 @@ passes_attr_crate_level = .suggestion = to apply to the crate, use an inner attribute .note = read for more information -passes_attr_mod_level = - this attribute can only be applied at module level - .suggestion = to apply to the crate, use an inner attribute at the crate level - .note = read for more information - passes_attr_only_in_functions = `{$attr}` attribute can only be used on functions diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 376b424a1af..29063ea8d29 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1252,7 +1252,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let bang_span = attr.span().lo() + BytePos(1); let sugg = (attr.style() == AttrStyle::Outer && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID) - .then_some(errors::AttrCrateLevelSugg { + .then_some(errors::AttrCrateLevelOnlySugg { attr: attr.span().with_lo(bang_span).with_hi(bang_span), }); self.tcx.emit_node_span_lint( @@ -1266,46 +1266,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { true } - /// Checks that an attribute is used at module level. Returns `true` if valid. - fn check_attr_mod_level( - &self, - attr: &Attribute, - meta: &MetaItemInner, - hir_id: HirId, - target: Target, - ) -> bool { - if target != Target::Mod { - // insert a bang between `#` and `[...` - let bang_span = attr.span().lo() + BytePos(1); - let sugg = (attr.style() == AttrStyle::Outer - && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID) - .then_some(errors::AttrCrateLevelSugg { - attr: attr.span().with_lo(bang_span).with_hi(bang_span), - }); - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span(), - errors::AttrModLevelOnly { sugg }, - ); - return false; - } - true - } - /// Checks that `doc(test(...))` attribute contains only valid attributes and are at the right place. - fn check_test_attr( - &self, - attr: &Attribute, - meta: &MetaItemInner, - hir_id: HirId, - target: Target, - ) { + fn check_test_attr(&self, attr: &Attribute, meta: &MetaItemInner, hir_id: HirId) { if let Some(metas) = meta.meta_item_list() { for i_meta in metas { match (i_meta.name(), i_meta.meta_item()) { (Some(sym::attr), _) => { - self.check_attr_mod_level(attr, meta, hir_id, target); + // Allowed everywhere like `#[doc]` } (Some(sym::no_crate_inject), _) => { self.check_attr_crate_level(attr, meta, hir_id); @@ -1396,7 +1363,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Some(sym::test) => { - self.check_test_attr(attr, meta, hir_id, target); + self.check_test_attr(attr, meta, hir_id); } Some( diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 38b0db37e12..00682a9c7a7 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1890,20 +1890,12 @@ pub(crate) struct UnusedVarTryIgnoreSugg { #[note] pub(crate) struct AttrCrateLevelOnly { #[subdiagnostic] - pub sugg: Option, -} - -#[derive(LintDiagnostic)] -#[diag(passes_attr_mod_level)] -#[note] -pub(crate) struct AttrModLevelOnly { - #[subdiagnostic] - pub sugg: Option, + pub sugg: Option, } #[derive(Subdiagnostic)] #[suggestion(passes_suggestion, applicability = "maybe-incorrect", code = "!", style = "verbose")] -pub(crate) struct AttrCrateLevelSugg { +pub(crate) struct AttrCrateLevelOnlySugg { #[primary_span] pub attr: Span, } diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md index afbcf4000c5..a70861faa76 100644 --- a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md +++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md @@ -141,34 +141,6 @@ But if you include this: it will not. -## At the module level - -These forms of the `#[doc]` attribute are used on individual modules, to control how -they are documented. - -### `test(attr(...))` - -This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For -example, if you want your doctests to fail if they have dead code, you could add this: - -```rust,no_run -#![doc(test(attr(deny(dead_code))))] - -mod my_mod { - #![doc(test(attr(allow(dead_code))))] // but allow `dead_code` for this module -} -``` - -`test(attr(..))` attributes are appended to the parent module's, they do not replace the current -list of attributes. In the previous example, both attributes would be present: - -```rust,no_run -// For every doctest in `my_mod` - -#![deny(dead_code)] // from the crate-root -#![allow(dead_code)] // from `my_mod` -``` - ## At the item level These forms of the `#[doc]` attribute are used on individual items, to control how @@ -300,3 +272,26 @@ To get around this limitation, we just add `#[doc(alias = "lib_name_do_something on the `do_something` method and then it's all good! Users can now look for `lib_name_do_something` in our crate directly and find `Obj::do_something`. + +### `test(attr(...))` + +This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For +example, if you want your doctests to fail if they have dead code, you could add this: + +```rust,no_run +#![doc(test(attr(deny(dead_code))))] + +mod my_mod { + #![doc(test(attr(allow(dead_code))))] // but allow `dead_code` for this module +} +``` + +`test(attr(..))` attributes are appended to the parent module's, they do not replace the current +list of attributes. In the previous example, both attributes would be present: + +```rust,no_run +// For every doctest in `my_mod` + +#![deny(dead_code)] // from the crate-root +#![allow(dead_code)] // from `my_mod` +``` diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.rs b/tests/rustdoc-ui/lints/invalid-doc-attr.rs index cd5ae44b126..e1cc08ca242 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.rs +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.rs @@ -4,10 +4,6 @@ #![doc(masked)] //~^ ERROR this attribute can only be applied to an `extern crate` item -#[doc(test(attr(allow(warnings))))] -//~^ ERROR can only be applied at module level -//~| HELP to apply to the crate, use an inner attribute -//~| SUGGESTION ! #[doc(test(no_crate_inject))] //~^ ERROR can only be applied at the crate level //~| HELP to apply to the crate, use an inner attribute diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr index 0fd55ff94d8..7621999a8ca 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr @@ -1,30 +1,18 @@ -error: this attribute can only be applied at module level - --> $DIR/invalid-doc-attr.rs:7:7 - | -LL | #[doc(test(attr(allow(warnings))))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: read for more information - = note: `#[deny(invalid_doc_attributes)]` on by default -help: to apply to the crate, use an inner attribute at the crate level - | -LL | #![doc(test(attr(allow(warnings))))] - | + - error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:11:7 + --> $DIR/invalid-doc-attr.rs:7:7 | LL | #[doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ | = note: read for more information + = note: `#[deny(invalid_doc_attributes)]` on by default help: to apply to the crate, use an inner attribute | LL | #![doc(test(no_crate_inject))] | + error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:15:7 + --> $DIR/invalid-doc-attr.rs:11:7 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -35,7 +23,7 @@ LL | pub fn foo() {} = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:20:12 + --> $DIR/invalid-doc-attr.rs:16:12 | LL | #![doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +31,7 @@ LL | #![doc(test(no_crate_inject))] = note: read for more information error: conflicting doc inlining attributes - --> $DIR/invalid-doc-attr.rs:30:7 + --> $DIR/invalid-doc-attr.rs:26:7 | LL | #[doc(inline)] | ^^^^^^ this attribute... @@ -53,7 +41,7 @@ LL | #[doc(no_inline)] = help: remove one of the conflicting attributes error: this attribute can only be applied to an `extern crate` item - --> $DIR/invalid-doc-attr.rs:36:7 + --> $DIR/invalid-doc-attr.rs:32:7 | LL | #[doc(masked)] | ^^^^^^ only applicable on `extern crate` items @@ -64,7 +52,7 @@ LL | pub struct Masked; = note: read for more information error: this attribute cannot be applied to an `extern crate self` item - --> $DIR/invalid-doc-attr.rs:40:7 + --> $DIR/invalid-doc-attr.rs:36:7 | LL | #[doc(masked)] | ^^^^^^ not applicable on `extern crate self` items @@ -81,7 +69,7 @@ LL | #![doc(masked)] = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:23:11 + --> $DIR/invalid-doc-attr.rs:19:11 | LL | #[doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ @@ -89,7 +77,7 @@ LL | #[doc(test(no_crate_inject))] = note: read for more information error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:25:11 + --> $DIR/invalid-doc-attr.rs:21:11 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -99,5 +87,5 @@ LL | pub fn baz() {} | = note: read for more information -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/lint/unused/useless-comment.rs b/tests/ui/lint/unused/useless-comment.rs index 4ec52f20747..898665278e3 100644 --- a/tests/ui/lint/unused/useless-comment.rs +++ b/tests/ui/lint/unused/useless-comment.rs @@ -9,8 +9,13 @@ macro_rules! mac { /// foo //~ ERROR unused doc comment mac!(); +/// a //~ ERROR unused doc comment +#[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment +unsafe extern "C" { } + fn foo() { /// a //~ ERROR unused doc comment + #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment let x = 12; /// multi-line //~ ERROR unused doc comment @@ -19,6 +24,7 @@ fn foo() { match x { /// c //~ ERROR unused doc comment 1 => {}, + #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment _ => {} } @@ -32,6 +38,7 @@ fn foo() { /// bar //~ ERROR unused doc comment mac!(); + #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment let x = /** comment */ 47; //~ ERROR unused doc comment /// dox //~ ERROR unused doc comment diff --git a/tests/ui/lint/unused/useless-comment.stderr b/tests/ui/lint/unused/useless-comment.stderr index 8bb5bdaeb25..39873b82b75 100644 --- a/tests/ui/lint/unused/useless-comment.stderr +++ b/tests/ui/lint/unused/useless-comment.stderr @@ -12,7 +12,28 @@ LL | #![deny(unused_doc_comments)] | ^^^^^^^^^^^^^^^^^^^ error: unused doc comment - --> $DIR/useless-comment.rs:32:5 + --> $DIR/useless-comment.rs:12:1 + | +LL | /// a + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[doc(test(attr(allow(dead_code))))] +LL | unsafe extern "C" { } + | --------------------- rustdoc does not generate documentation for extern blocks + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:13:1 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe extern "C" { } + | --------------------- rustdoc does not generate documentation for extern blocks + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:38:5 | LL | /// bar | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macro invocations @@ -20,17 +41,28 @@ LL | /// bar = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion error: unused doc comment - --> $DIR/useless-comment.rs:13:5 + --> $DIR/useless-comment.rs:17:5 | LL | /// a | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[doc(test(attr(allow(dead_code))))] LL | let x = 12; | ----------- rustdoc does not generate documentation for statements | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:16:5 + --> $DIR/useless-comment.rs:18:5 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = 12; + | ----------- rustdoc does not generate documentation for statements + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:21:5 | LL | / /// multi-line LL | | /// doc comment @@ -39,6 +71,7 @@ LL | | /// that is unused LL | / match x { LL | | /// c LL | | 1 => {}, +LL | | #[doc(test(attr(allow(dead_code))))] LL | | _ => {} LL | | } | |_____- rustdoc does not generate documentation for expressions @@ -46,7 +79,7 @@ LL | | } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:20:9 + --> $DIR/useless-comment.rs:25:9 | LL | /// c | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +89,17 @@ LL | 1 => {}, = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:25:5 + --> $DIR/useless-comment.rs:27:9 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | _ => {} + | ------- rustdoc does not generate documentation for match arms + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:31:5 | LL | /// foo | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +109,7 @@ LL | unsafe {} = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:28:5 + --> $DIR/useless-comment.rs:34:5 | LL | #[doc = "foo"] | ^^^^^^^^^^^^^^ @@ -77,7 +120,7 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:29:5 + --> $DIR/useless-comment.rs:35:5 | LL | #[doc = "bar"] | ^^^^^^^^^^^^^^ @@ -87,7 +130,17 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:35:13 + --> $DIR/useless-comment.rs:41:5 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = /** comment */ 47; + | -------------------------- rustdoc does not generate documentation for statements + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:42:13 | LL | let x = /** comment */ 47; | ^^^^^^^^^^^^^^ -- rustdoc does not generate documentation for expressions @@ -95,7 +148,7 @@ LL | let x = /** comment */ 47; = help: use `/* */` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:37:5 + --> $DIR/useless-comment.rs:44:5 | LL | /// dox | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,5 +159,5 @@ LL | | } | = help: use `//` for a plain comment -error: aborting due to 10 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/rustdoc/doc-test-attr-pass.rs b/tests/ui/rustdoc/doc-test-attr-pass.rs index 40ffd5b2572..60d1e3722bd 100644 --- a/tests/ui/rustdoc/doc-test-attr-pass.rs +++ b/tests/ui/rustdoc/doc-test-attr-pass.rs @@ -10,4 +10,42 @@ mod test { #![doc(test(attr(allow(warnings))))] } +#[doc(test(attr(allow(dead_code))))] +static S: u32 = 5; + +#[doc(test(attr(allow(dead_code))))] +const C: u32 = 5; + +#[doc(test(attr(deny(dead_code))))] +struct A { + #[doc(test(attr(allow(dead_code))))] + field: u32 +} + +#[doc(test(attr(deny(dead_code))))] +union U { + #[doc(test(attr(allow(dead_code))))] + field: u32, + field2: u64, +} + +#[doc(test(attr(deny(dead_code))))] +enum Enum { + #[doc(test(attr(allow(dead_code))))] + Variant1, +} + +#[doc(test(attr(deny(dead_code))))] +impl A { + #[doc(test(attr(deny(dead_code))))] + fn method() {} +} + +#[doc(test(attr(deny(dead_code))))] +trait MyTrait { + #[doc(test(attr(deny(dead_code))))] + fn my_trait_fn(); +} + +#[doc(test(attr(deny(dead_code))))] pub fn foo() {} -- cgit 1.4.1-3-g733a5 From d96d3bed6fc14fa03b077b1b7acf493815a6ef31 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 5 May 2025 23:07:29 +0200 Subject: Collect and use `#[doc(test(attr(..)))]` at every level --- src/librustdoc/doctest/rust.rs | 57 ++++----- tests/rustdoc-ui/doctest/dead-code-items.rs | 116 +++++++++++++++++++ tests/rustdoc-ui/doctest/dead-code-items.stdout | 146 ++++++++++++++++++++++++ 3 files changed, 285 insertions(+), 34 deletions(-) create mode 100644 tests/rustdoc-ui/doctest/dead-code-items.rs create mode 100644 tests/rustdoc-ui/doctest/dead-code-items.stdout diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index 4e9b1ee36f3..96975105ac5 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -127,6 +127,26 @@ impl HirCollector<'_> { return; } + // Try collecting `#[doc(test(attr(...)))]` + let old_global_crate_attrs_len = self.collector.global_crate_attrs.len(); + for doc_test_attrs in ast_attrs + .iter() + .filter(|a| a.has_name(sym::doc)) + .flat_map(|a| a.meta_item_list().unwrap_or_default()) + .filter(|a| a.has_name(sym::test)) + { + let Some(doc_test_attrs) = doc_test_attrs.meta_item_list() else { continue }; + for attr in doc_test_attrs + .iter() + .filter(|a| a.has_name(sym::attr)) + .flat_map(|a| a.meta_item_list().unwrap_or_default()) + .map(|i| pprust::meta_list_item_to_string(i)) + { + // Add the additional attributes to the global_crate_attrs vector + self.collector.global_crate_attrs.push(attr); + } + } + let mut has_name = false; if let Some(name) = name { self.collector.cur_path.push(name); @@ -161,6 +181,9 @@ impl HirCollector<'_> { nested(self); + // Restore global_crate_attrs to it's previous size/content + self.collector.global_crate_attrs.truncate(old_global_crate_attrs_len); + if has_name { self.collector.cur_path.pop(); } @@ -174,40 +197,6 @@ impl<'tcx> intravisit::Visitor<'tcx> for HirCollector<'tcx> { self.tcx } - fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _s: Span, hir_id: hir::HirId) { - let attrs = self.tcx.hir_attrs(hir_id); - - if !attrs.is_empty() { - // Try collecting `#![doc(test(attr(...)))]` from the attribute module - let old_len = self.collector.global_crate_attrs.len(); - for doc_test_attrs in attrs - .iter() - .filter(|a| a.has_name(sym::doc)) - .flat_map(|a| a.meta_item_list().unwrap_or_default()) - .filter(|a| a.has_name(sym::test)) - { - let Some(doc_test_attrs) = doc_test_attrs.meta_item_list() else { continue }; - for attr in doc_test_attrs - .iter() - .filter(|a| a.has_name(sym::attr)) - .flat_map(|a| a.meta_item_list().unwrap_or_default()) - .map(|i| pprust::meta_list_item_to_string(i)) - { - // Add the additional attributes to the global_crate_attrs vector - self.collector.global_crate_attrs.push(attr); - } - } - - let r = intravisit::walk_mod(self, m); - - // Restore global_crate_attrs to it's previous size/content - self.collector.global_crate_attrs.truncate(old_len); - r - } else { - intravisit::walk_mod(self, m) - } - } - fn visit_item(&mut self, item: &'tcx hir::Item<'_>) { let name = match &item.kind { hir::ItemKind::Impl(impl_) => { diff --git a/tests/rustdoc-ui/doctest/dead-code-items.rs b/tests/rustdoc-ui/doctest/dead-code-items.rs new file mode 100644 index 00000000000..015504cbced --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-items.rs @@ -0,0 +1,116 @@ +// Same test as dead-code-module but with 2 doc(test(attr())) at different levels. + +//@ edition: 2024 +//@ compile-flags:--test --test-args=--test-threads=1 +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +#![doc(test(attr(deny(warnings))))] + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarning { fn no_deny_warnings(); } +/// ``` +static S: u32 = 5; + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// let unused_error = 5; +/// +/// fn dead_code_but_no_error() {} +/// ``` +const C: u32 = 5; + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarningAtA { fn no_deny_warnings(); } +/// ``` +struct A { + #[doc(test(attr(deny(dead_code))))] + /// Example + /// + /// ```rust,no_run + /// trait DeadCodeInField {} + /// ``` + field: u32 +} + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarningAtU { fn no_deny_warnings(); } +/// ``` +union U { + #[doc(test(attr(deny(dead_code))))] + /// Example + /// + /// ```rust,no_run + /// trait DeadCodeInUnionField {} + /// ``` + field: u32, + /// Example + /// + /// ```rust,no_run + /// trait NotDeadCodeInUnionField {} + /// ``` + field2: u64, +} + +#[doc(test(attr(deny(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// let not_dead_code_but_unused = 5; +/// ``` +enum Enum { + #[doc(test(attr(allow(dead_code))))] + /// Example + /// + /// ```rust,no_run + /// trait NotDeadCodeInVariant {} + /// + /// fn main() { let unused_in_variant = 5; } + /// ``` + Variant1, +} + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarningAtImplA { fn no_deny_warnings(); } +/// ``` +impl A { + /// Example + /// + /// ```rust,no_run + /// trait NotDeadCodeInImplMethod {} + /// ``` + fn method() {} +} + +#[doc(test(attr(deny(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait StillDeadCodeAtMyTrait { } +/// ``` +trait MyTrait { + #[doc(test(attr(allow(dead_code))))] + /// Example + /// + /// ```rust,no_run + /// trait NotDeadCodeAtImplFn {} + /// + /// fn main() { let unused_in_impl = 5; } + /// ``` + fn my_trait_fn(); +} diff --git a/tests/rustdoc-ui/doctest/dead-code-items.stdout b/tests/rustdoc-ui/doctest/dead-code-items.stdout new file mode 100644 index 00000000000..4b9d8be94dd --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-items.stdout @@ -0,0 +1,146 @@ + +running 13 tests +test $DIR/dead-code-items.rs - A (line 32) - compile ... ok +test $DIR/dead-code-items.rs - A (line 88) - compile ... ok +test $DIR/dead-code-items.rs - A::field (line 39) - compile ... FAILED +test $DIR/dead-code-items.rs - A::method (line 94) - compile ... ok +test $DIR/dead-code-items.rs - C (line 22) - compile ... FAILED +test $DIR/dead-code-items.rs - Enum (line 70) - compile ... FAILED +test $DIR/dead-code-items.rs - Enum::Variant1 (line 77) - compile ... FAILED +test $DIR/dead-code-items.rs - MyTrait (line 103) - compile ... FAILED +test $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110) - compile ... FAILED +test $DIR/dead-code-items.rs - S (line 14) - compile ... ok +test $DIR/dead-code-items.rs - U (line 48) - compile ... ok +test $DIR/dead-code-items.rs - U::field (line 55) - compile ... FAILED +test $DIR/dead-code-items.rs - U::field2 (line 61) - compile ... ok + +failures: + +---- $DIR/dead-code-items.rs - A::field (line 39) stdout ---- +error: trait `DeadCodeInField` is never used + --> $DIR/dead-code-items.rs:40:7 + | +LL | trait DeadCodeInField {} + | ^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:38:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - C (line 22) stdout ---- +error: unused variable: `unused_error` + --> $DIR/dead-code-items.rs:23:5 + | +LL | let unused_error = 5; + | ^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_error` + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:20:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - Enum (line 70) stdout ---- +error: unused variable: `not_dead_code_but_unused` + --> $DIR/dead-code-items.rs:71:5 + | +LL | let not_dead_code_but_unused = 5; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_not_dead_code_but_unused` + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:68:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - Enum::Variant1 (line 77) stdout ---- +error: unused variable: `unused_in_variant` + --> $DIR/dead-code-items.rs:80:17 + | +LL | fn main() { let unused_in_variant = 5; } + | ^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_in_variant` + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:75:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - MyTrait (line 103) stdout ---- +error: trait `StillDeadCodeAtMyTrait` is never used + --> $DIR/dead-code-items.rs:104:7 + | +LL | trait StillDeadCodeAtMyTrait { } + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:102:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110) stdout ---- +error: unused variable: `unused_in_impl` + --> $DIR/dead-code-items.rs:113:17 + | +LL | fn main() { let unused_in_impl = 5; } + | ^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_in_impl` + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:108:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - U::field (line 55) stdout ---- +error: trait `DeadCodeInUnionField` is never used + --> $DIR/dead-code-items.rs:56:7 + | +LL | trait DeadCodeInUnionField {} + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:54:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code-items.rs - A::field (line 39) + $DIR/dead-code-items.rs - C (line 22) + $DIR/dead-code-items.rs - Enum (line 70) + $DIR/dead-code-items.rs - Enum::Variant1 (line 77) + $DIR/dead-code-items.rs - MyTrait (line 103) + $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110) + $DIR/dead-code-items.rs - U::field (line 55) + +test result: FAILED. 6 passed; 7 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + -- cgit 1.4.1-3-g733a5 From a08f6f10d4ab94d53793480782e9e939b48a3ebe Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Fri, 23 May 2025 15:38:57 +0200 Subject: document representation of `Option` --- library/core/src/option.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index aed5a043c11..e2182e54b48 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -135,7 +135,7 @@ //! | [`ptr::NonNull`] | when `U: Sized` | //! | `#[repr(transparent)]` struct around one of the types in this list. | when it holds for the inner type | //! -//! [^extern_fn]: this remains true for any argument/return types and any other ABI: `extern "abi" fn` (_e.g._, `extern "system" fn`) +//! [^extern_fn]: this remains true for `unsafe` variants, any argument/return types, and any other ABI: `[unsafe] extern "abi" fn` (_e.g._, `extern "system" fn`) //! //! Under some conditions the above types `T` are also null pointer optimized when wrapped in a [`Result`][result_repr]. //! -- cgit 1.4.1-3-g733a5 From 8bf515330fb68ba10a54e9087a2b5629a968e766 Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 23 May 2025 18:00:09 +0200 Subject: std: abort the process on failure to allocate a TLS key The panic machinery uses TLS, so panicking if no TLS keys are left can lead to infinite recursion (see https://github.com/rust-lang/rust/issues/140798#issuecomment-2872307377). Rather than having separate logic for the panic count and the thread name, just always abort the process if a TLS key allocation fails. This also has the benefit of aligning the key-based TLS implementation with the documentation, which does not mention that a panic could also occur because of resource exhaustion. --- library/std/src/sys/thread_local/key/unix.rs | 4 +++- library/std/src/sys/thread_local/key/windows.rs | 17 +++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/library/std/src/sys/thread_local/key/unix.rs b/library/std/src/sys/thread_local/key/unix.rs index 93bd0d1f668..8fa24265e43 100644 --- a/library/std/src/sys/thread_local/key/unix.rs +++ b/library/std/src/sys/thread_local/key/unix.rs @@ -25,7 +25,9 @@ pub type Key = libc::pthread_key_t; #[inline] pub fn create(dtor: Option) -> Key { let mut key = 0; - assert_eq!(unsafe { libc::pthread_key_create(&mut key, mem::transmute(dtor)) }, 0); + if unsafe { libc::pthread_key_create(&mut key, mem::transmute(dtor)) } != 0 { + rtabort!("out of TLS keys"); + } key } diff --git a/library/std/src/sys/thread_local/key/windows.rs b/library/std/src/sys/thread_local/key/windows.rs index c34c7bc204f..2ff0fd1196e 100644 --- a/library/std/src/sys/thread_local/key/windows.rs +++ b/library/std/src/sys/thread_local/key/windows.rs @@ -81,15 +81,10 @@ impl LazyKey { } else { let key = unsafe { c::TlsAlloc() }; if key == c::TLS_OUT_OF_INDEXES { - // Wakeup the waiting threads before panicking to avoid deadlock. - unsafe { - c::InitOnceComplete( - self.once.get(), - c::INIT_ONCE_INIT_FAILED, - ptr::null_mut(), - ); - } - panic!("out of TLS indexes"); + // Since we abort the process, there is no need to wake up + // the waiting threads. If this were a panic, the wakeup + // would need to occur first in order to avoid deadlock. + rtabort!("out of TLS indexes"); } unsafe { @@ -112,7 +107,9 @@ impl LazyKey { // If there is no destructor to clean up, we can use racy initialization. let key = unsafe { c::TlsAlloc() }; - assert_ne!(key, c::TLS_OUT_OF_INDEXES, "out of TLS indexes"); + if key == c::TLS_OUT_OF_INDEXES { + rtabort!("out of TLS indexes"); + } match self.key.compare_exchange(0, key + 1, AcqRel, Acquire) { Ok(_) => key, -- cgit 1.4.1-3-g733a5 From fab206bf5852c532f85b9ad30f9eea8fc952e8e1 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Sat, 24 May 2025 22:33:11 +0200 Subject: make `OsString::new` and `PathBuf::new` unstably const --- library/std/src/ffi/os_str.rs | 3 ++- library/std/src/path.rs | 3 ++- library/std/src/sys/os_str/bytes.rs | 2 +- library/std/src/sys/os_str/wtf8.rs | 2 +- library/std/src/sys_common/wtf8.rs | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index ead48775127..22308224a2f 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -137,7 +137,8 @@ impl OsString { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[inline] - pub fn new() -> OsString { + #[rustc_const_unstable(feature = "const_pathbuf_osstring_new", issue = "141520")] + pub const fn new() -> OsString { OsString { inner: Buf::from_string(String::new()) } } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 7959c633858..3e347798ab9 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1191,7 +1191,8 @@ impl PathBuf { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[inline] - pub fn new() -> PathBuf { + #[rustc_const_unstable(feature = "const_pathbuf_osstring_new", issue = "141520")] + pub const fn new() -> PathBuf { PathBuf { inner: OsString::new() } } diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index 4a8808c9230..f8ab4543a3a 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -115,7 +115,7 @@ impl Buf { } #[inline] - pub fn from_string(s: String) -> Buf { + pub const fn from_string(s: String) -> Buf { Buf { inner: s.into_bytes() } } diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index 5174ea65d0c..4207a2db635 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -92,7 +92,7 @@ impl Buf { } #[inline] - pub fn from_string(s: String) -> Buf { + pub const fn from_string(s: String) -> Buf { Buf { inner: Wtf8Buf::from_string(s) } } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index f9ec112b197..50bde88b5a4 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -209,7 +209,7 @@ impl Wtf8Buf { /// /// Since WTF-8 is a superset of UTF-8, this always succeeds. #[inline] - pub fn from_string(string: String) -> Wtf8Buf { + pub const fn from_string(string: String) -> Wtf8Buf { Wtf8Buf { bytes: string.into_bytes(), is_known_utf8: true } } -- cgit 1.4.1-3-g733a5 From 6b5b97a4df3331e82ee7f57f2c33818b997f98d0 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 26 May 2025 13:47:53 +0800 Subject: Fix incorrect eq_unspanned in TokenStream --- compiler/rustc_ast/src/tokenstream.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 636c26bcde0..7f2ba28f81b 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -696,14 +696,8 @@ impl TokenStream { /// Compares two `TokenStream`s, checking equality without regarding span information. pub fn eq_unspanned(&self, other: &TokenStream) -> bool { - let mut iter1 = self.iter(); - let mut iter2 = other.iter(); - for (tt1, tt2) in iter::zip(&mut iter1, &mut iter2) { - if !tt1.eq_unspanned(tt2) { - return false; - } - } - iter1.next().is_none() && iter2.next().is_none() + self.len() == other.len() + && self.iter().zip(other.iter()).all(|(tt1, tt2)| tt1.eq_unspanned(tt2)) } /// Create a token stream containing a single token with alone spacing. The -- cgit 1.4.1-3-g733a5 From 44612c5f9cbd21ebe60dab93f3c536084c4bf495 Mon Sep 17 00:00:00 2001 From: vremyavnikuda Date: Sun, 25 May 2025 15:28:07 +0700 Subject: docs: add documentation for find_all_refs constructor search (#10725) --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 71 ++++++++++++++++- .../rust-analyzer/crates/ide/src/references.rs | 90 +++++++++++++++++++++- 2 files changed, 158 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index d649dffbd90..6e35084ceb3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -514,7 +514,76 @@ impl Analysis { self.with_db(|db| goto_type_definition::goto_type_definition(db, position)) } - /// Finds all usages of the reference at point. + /// Find all references to the item at the cursor position. + /// + /// # Examples + /// + /// Basic struct reference search: + /// ```rust + /// struct S { + /// pub x: usize, + /// } + /// + /// fn print_s(s: S) { + /// println!("{}", s.x) + /// } + /// + /// fn main() { + /// let s = S { x: 42 }; // This is a constructor usage + /// print_s(s); // This is a type reference + /// } + /// ``` + /// + /// To find only constructor/initialization usages: + /// 1. Position cursor on special tokens in struct/enum definition: + /// ```rust + /// // On '{' - finds record struct initializations + /// struct Point { // <- cursor here on '{' + /// x: i32, + /// y: i32, + /// } + /// + /// // On '(' - finds tuple struct initializations + /// struct Tuple(i32, i32); // <- cursor here on '(' + /// + /// // On ';' - finds unit struct initializations + /// struct Unit; // <- cursor here on ';' + /// ``` + /// + /// 2. Examples of what will be found: + /// ```rust + /// struct Point{x: i32, y: i32}; + /// struct Tuple(i32, i32); + /// struct Unit; + /// + /// + /// let p1 = Point { x: 0, y: 0 }; // Found when cursor on '{' + /// let p2 = Tuple(1, 2); // Found when cursor on '(' + /// let u = Unit; // Found when cursor on ';' + /// ``` + /// + /// 3. For enum variants: + /// ```rust + /// enum E { + /// Struct { // <- cursor here on '{' + /// x: i32 + /// }, + /// Tuple(i32), // <- cursor here on '(' + /// Unit // <- cursor here on identifier + /// } + /// + /// let e1 = E::Struct { x: 0 }; // Found for Struct variant + /// let e2 = E::Tuple(1); // Found for Tuple variant + /// let e3 = E::Unit; // Found for Unit variant + /// ``` + /// + /// # Parameters + /// * `position` - The position in the file to find references for + /// * `search_scope` - Optional scope to limit the search + /// + /// # Returns + /// Returns a vector of reference search results if references are found, + /// or None if no valid item is found at the position. pub fn find_all_refs( &self, position: FilePosition, diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 4fa116444b7..91f4d752c8d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -8,6 +8,14 @@ //! for text occurrences of the identifier. If there's an `ast::NameRef` //! at the index that the match starts at and its tree parent is //! resolved to the search element definition, we get a reference. +//! +//! Special handling for constructors/initializations: +//! When searching for references to a struct/enum/variant, if the cursor is positioned on: +//! - `{` after a struct/enum/variant definition +//! - `(` for tuple structs/variants +//! - `;` for unit structs +//! - The type name in a struct/enum/variant definition +//! Then only constructor/initialization usages will be shown, filtering out other references. use hir::{PathResolution, Semantics}; use ide_db::{ @@ -28,27 +36,76 @@ use syntax::{ use crate::{FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related}; +/// Result of a reference search operation. #[derive(Debug, Clone)] pub struct ReferenceSearchResult { + /// Information about the declaration site of the searched item. + /// For ADTs (structs/enums), this points to the type definition. + /// May be None for primitives or items without clear declaration sites. pub declaration: Option, + /// All references found, grouped by file. + /// For ADTs when searching from a constructor position (e.g. on '{', '(', ';'), + /// this only includes constructor/initialization usages. + /// The map key is the file ID, and the value is a vector of (range, category) pairs. + /// - range: The text range of the reference in the file + /// - category: Metadata about how the reference is used (read/write/etc) pub references: IntMap>, } +/// Information about the declaration site of a searched item. #[derive(Debug, Clone)] pub struct Declaration { + /// Navigation information to jump to the declaration pub nav: NavigationTarget, + /// Whether the declared item is mutable (relevant for variables) pub is_mut: bool, } // Feature: Find All References // -// Shows all references of the item at the cursor location +// Shows all references of the item at the cursor location. This includes: +// - Direct references to variables, functions, types, etc. +// - Constructor/initialization references when cursor is on struct/enum definition tokens +// - References in patterns and type contexts +// - References through dereferencing and borrowing +// - References in macro expansions +// +// Special handling for constructors: +// - When the cursor is on `{`, `(`, or `;` in a struct/enum definition +// - When the cursor is on the type name in a struct/enum definition +// These cases will show only constructor/initialization usages of the type // // | Editor | Shortcut | // |---------|----------| // | VS Code | Shift+Alt+F12 | // // ![Find All References](https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif) + +/// Find all references to the item at the given position. +/// +/// # Arguments +/// * `sema` - Semantic analysis context +/// * `position` - Position in the file where to look for the item +/// * `search_scope` - Optional scope to limit the search (e.g. current crate only) +/// +/// # Returns +/// Returns `None` if no valid item is found at the position. +/// Otherwise returns a vector of `ReferenceSearchResult`, usually with one element. +/// Multiple results can occur in case of ambiguity or when searching for trait items. +/// +/// # Special cases +/// - Control flow keywords (break, continue, etc): Shows all related jump points +/// - Constructor search: When on struct/enum definition tokens (`{`, `(`, `;`), shows only initialization sites +/// - Format string arguments: Shows template parameter usages +/// - Lifetime parameters: Shows lifetime constraint usages +/// +/// # Constructor search +/// When the cursor is on specific tokens in a struct/enum definition: +/// - `{` after struct/enum/variant: Shows record literal initializations +/// - `(` after tuple struct/variant: Shows tuple literal initializations +/// - `;` after unit struct: Shows unit literal initializations +/// - Type name in definition: Shows all initialization usages +/// In these cases, other kinds of references (like type references) are filtered out. pub(crate) fn find_all_refs( sema: &Semantics<'_, RootDatabase>, position: FilePosition, @@ -219,7 +276,19 @@ fn retain_adt_literal_usages( } } -/// Returns `Some` if the cursor is at a position for an item to search for all its constructor/literal usages +/// Returns `Some` if the cursor is at a position where we should search for constructor/initialization usages. +/// This is used to implement the special constructor search behavior when the cursor is on specific tokens +/// in a struct/enum/variant definition. +/// +/// # Returns +/// - `Some(name)` if the cursor is on: +/// - `{` after a struct/enum/variant definition +/// - `(` for tuple structs/variants +/// - `;` for unit structs +/// - The type name in a struct/enum/variant definition +/// - `None` otherwise +/// +/// The returned name is the name of the type whose constructor usages should be searched for. fn name_for_constructor_search(syntax: &SyntaxNode, position: FilePosition) -> Option { let token = syntax.token_at_offset(position.offset).right_biased()?; let token_parent = token.parent()?; @@ -257,6 +326,16 @@ fn name_for_constructor_search(syntax: &SyntaxNode, position: FilePosition) -> O } } +/// Checks if a name reference is part of an enum variant literal expression. +/// Used to filter references when searching for enum variant constructors. +/// +/// # Arguments +/// * `sema` - Semantic analysis context +/// * `enum_` - The enum type to check against +/// * `name_ref` - The name reference to check +/// +/// # Returns +/// `true` if the name reference is used as part of constructing a variant of the given enum. fn is_enum_lit_name_ref( sema: &Semantics<'_, RootDatabase>, enum_: hir::Enum, @@ -284,12 +363,19 @@ fn is_enum_lit_name_ref( .unwrap_or(false) } +/// Checks if a path ends with the given name reference. +/// Helper function for checking constructor usage patterns. fn path_ends_with(path: Option, name_ref: &ast::NameRef) -> bool { path.and_then(|path| path.segment()) .and_then(|segment| segment.name_ref()) .map_or(false, |segment| segment == *name_ref) } +/// Checks if a name reference is used in a literal (constructor) context. +/// Used to filter references when searching for struct/variant constructors. +/// +/// # Returns +/// `true` if the name reference is used as part of a struct/variant literal expression. fn is_lit_name_ref(name_ref: &ast::NameRef) -> bool { name_ref.syntax().ancestors().find_map(|ancestor| { match_ast! { -- cgit 1.4.1-3-g733a5 From 1e8eacd192022cd0bd8c90101569b32397722122 Mon Sep 17 00:00:00 2001 From: vremyavnikuda Date: Sun, 25 May 2025 15:55:58 +0700 Subject: fix: the lines are formatted according to clippy --- src/tools/rust-analyzer/crates/ide/src/references.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 91f4d752c8d..f7f00cf8317 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -15,7 +15,7 @@ //! - `(` for tuple structs/variants //! - `;` for unit structs //! - The type name in a struct/enum/variant definition -//! Then only constructor/initialization usages will be shown, filtering out other references. +//! Then only constructor/initialization usages will be shown, filtering out other references. use hir::{PathResolution, Semantics}; use ide_db::{ @@ -105,7 +105,7 @@ pub struct Declaration { /// - `(` after tuple struct/variant: Shows tuple literal initializations /// - `;` after unit struct: Shows unit literal initializations /// - Type name in definition: Shows all initialization usages -/// In these cases, other kinds of references (like type references) are filtered out. +/// In these cases, other kinds of references (like type references) are filtered out. pub(crate) fn find_all_refs( sema: &Semantics<'_, RootDatabase>, position: FilePosition, -- cgit 1.4.1-3-g733a5 From 693ff34702c2eb06bca073f2f7d3073da36c297b Mon Sep 17 00:00:00 2001 From: vremyavnikuda Date: Sun, 25 May 2025 15:55:58 +0700 Subject: fix: the lines are formatted according to clippy --- src/tools/rust-analyzer/crates/ide/src/references.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index f7f00cf8317..d9882d12210 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -105,7 +105,7 @@ pub struct Declaration { /// - `(` after tuple struct/variant: Shows tuple literal initializations /// - `;` after unit struct: Shows unit literal initializations /// - Type name in definition: Shows all initialization usages -/// In these cases, other kinds of references (like type references) are filtered out. +/// In these cases, other kinds of references (like type references) are filtered out. pub(crate) fn find_all_refs( sema: &Semantics<'_, RootDatabase>, position: FilePosition, -- cgit 1.4.1-3-g733a5 From d3347bb32b01e73db96d75579ec7ca16320d4317 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 26 May 2025 14:11:02 +0800 Subject: remove eq_unspanned from TokenStream --- compiler/rustc_ast/src/tokenstream.rs | 10 +++------- compiler/rustc_parse/src/parser/tokenstream/tests.rs | 8 ++++++-- src/tools/clippy/clippy_utils/src/ast_utils/mod.rs | 4 +++- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 7f2ba28f81b..3c231be20dc 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -57,7 +57,9 @@ impl TokenTree { match (self, other) { (TokenTree::Token(token, _), TokenTree::Token(token2, _)) => token.kind == token2.kind, (TokenTree::Delimited(.., delim, tts), TokenTree::Delimited(.., delim2, tts2)) => { - delim == delim2 && tts.eq_unspanned(tts2) + delim == delim2 + && tts.len() == tts2.len() + && tts.iter().zip(tts2.iter()).all(|(a, b)| a.eq_unspanned(b)) } _ => false, } @@ -694,12 +696,6 @@ impl TokenStream { TokenStreamIter::new(self) } - /// Compares two `TokenStream`s, checking equality without regarding span information. - pub fn eq_unspanned(&self, other: &TokenStream) -> bool { - self.len() == other.len() - && self.iter().zip(other.iter()).all(|(tt1, tt2)| tt1.eq_unspanned(tt2)) - } - /// Create a token stream containing a single token with alone spacing. The /// spacing used for the final token in a constructed stream doesn't matter /// because it's never used. In practice we arbitrarily use diff --git a/compiler/rustc_parse/src/parser/tokenstream/tests.rs b/compiler/rustc_parse/src/parser/tokenstream/tests.rs index aac75323ff3..19b2c98f5af 100644 --- a/compiler/rustc_parse/src/parser/tokenstream/tests.rs +++ b/compiler/rustc_parse/src/parser/tokenstream/tests.rs @@ -14,6 +14,10 @@ fn sp(a: u32, b: u32) -> Span { Span::with_root_ctxt(BytePos(a), BytePos(b)) } +fn cmp_token_stream(a: &TokenStream, b: &TokenStream) -> bool { + a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.eq_unspanned(y)) +} + #[test] fn test_concat() { create_default_session_globals_then(|| { @@ -25,7 +29,7 @@ fn test_concat() { eq_res.push_stream(test_snd); assert_eq!(test_res.iter().count(), 5); assert_eq!(eq_res.iter().count(), 5); - assert_eq!(test_res.eq_unspanned(&eq_res), true); + assert_eq!(cmp_token_stream(&test_res, &eq_res), true); }) } @@ -104,7 +108,7 @@ fn test_dotdotdot() { stream.push_tree(TokenTree::token_joint(token::Dot, sp(0, 1))); stream.push_tree(TokenTree::token_joint(token::Dot, sp(1, 2))); stream.push_tree(TokenTree::token_alone(token::Dot, sp(2, 3))); - assert!(stream.eq_unspanned(&string_to_ts("..."))); + assert!(cmp_token_stream(&stream, &string_to_ts("..."))); assert_eq!(stream.iter().count(), 1); }) } diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 8996b694ed8..01e916fb535 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -960,5 +960,7 @@ pub fn eq_attr_args(l: &AttrArgs, r: &AttrArgs) -> bool { } pub fn eq_delim_args(l: &DelimArgs, r: &DelimArgs) -> bool { - l.delim == r.delim && l.tokens.eq_unspanned(&r.tokens) + l.delim == r.delim + && l.tokens.len() == r.tokens.len() + && l.tokens.iter().zip(r.tokens.iter()).all(|(a, b)| a.eq_unspanned(b)) } -- cgit 1.4.1-3-g733a5 From 57707c22872c5518791905927153e0ff583f8ee8 Mon Sep 17 00:00:00 2001 From: vremyavnikuda Date: Mon, 26 May 2025 16:15:45 +0700 Subject: fix: formated to clippy --- src/tools/rust-analyzer/crates/ide/src/references.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index d9882d12210..f7f00cf8317 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -105,7 +105,7 @@ pub struct Declaration { /// - `(` after tuple struct/variant: Shows tuple literal initializations /// - `;` after unit struct: Shows unit literal initializations /// - Type name in definition: Shows all initialization usages -/// In these cases, other kinds of references (like type references) are filtered out. +/// In these cases, other kinds of references (like type references) are filtered out. pub(crate) fn find_all_refs( sema: &Semantics<'_, RootDatabase>, position: FilePosition, -- cgit 1.4.1-3-g733a5 From a35675d38f10cf19c9512d5d621338fc00530ad3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 May 2025 01:57:43 +1000 Subject: Remove `'static` bounds on `P`. These date back to 2014. I don't think they're needed any more. --- compiler/rustc_ast/src/ptr.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index dd923305cdf..1e6a5e91f23 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -32,11 +32,11 @@ pub struct P { /// Construct a `P` from a `T` value. #[allow(non_snake_case)] -pub fn P(value: T) -> P { +pub fn P(value: T) -> P { P { ptr: Box::new(value) } } -impl P { +impl P { /// Move out of the pointer. /// Intended for chaining transformations not covered by `map`. pub fn and_then(self, f: F) -> U @@ -86,7 +86,7 @@ impl DerefMut for P { } } -impl Clone for P { +impl Clone for P { fn clone(&self) -> P { P((**self).clone()) } @@ -110,7 +110,7 @@ impl fmt::Pointer for P { } } -impl> Decodable for P { +impl> Decodable for P { fn decode(d: &mut D) -> P { P(Decodable::decode(d)) } -- cgit 1.4.1-3-g733a5 From 6973fa08a3a4044c87b9da9e66cb1ca17f89b889 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 May 2025 01:42:51 +1000 Subject: Remove `P::map`. It's barely used, and the places that use it are better if they don't. --- compiler/rustc_ast/src/ast.rs | 7 ++--- compiler/rustc_ast/src/ptr.rs | 11 ------- .../rustc_builtin_macros/src/proc_macro_harness.rs | 36 ++++++++++------------ compiler/rustc_builtin_macros/src/test.rs | 5 +-- 4 files changed, 21 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a16219361c0..c4be07ba068 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1123,10 +1123,9 @@ impl Stmt { pub fn add_trailing_semicolon(mut self) -> Self { self.kind = match self.kind { StmtKind::Expr(expr) => StmtKind::Semi(expr), - StmtKind::MacCall(mac) => { - StmtKind::MacCall(mac.map(|MacCallStmt { mac, style: _, attrs, tokens }| { - MacCallStmt { mac, style: MacStmtStyle::Semicolon, attrs, tokens } - })) + StmtKind::MacCall(mut mac) => { + mac.style = MacStmtStyle::Semicolon; + StmtKind::MacCall(mac) } kind => kind, }; diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index 1e6a5e91f23..a1b265cf0a9 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -51,17 +51,6 @@ impl P { *self.ptr } - /// Produce a new `P` from `self` without reallocating. - pub fn map(mut self, f: F) -> P - where - F: FnOnce(T) -> T, - { - let x = f(*self.ptr); - *self.ptr = x; - - self - } - /// Optionally produce a new `P` from `self` without reallocating. pub fn filter_map(mut self, f: F) -> Option> where diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index a91f2d38a93..daf480a9ce4 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -354,30 +354,28 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { }) .collect(); - let decls_static = cx - .item_static( + let mut decls_static = cx.item_static( + span, + Ident::new(sym::_DECLS, span), + cx.ty_ref( span, - Ident::new(sym::_DECLS, span), - cx.ty_ref( + cx.ty( span, - cx.ty( - span, - ast::TyKind::Slice( - cx.ty_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty])), - ), + ast::TyKind::Slice( + cx.ty_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty])), ), - None, - ast::Mutability::Not, ), + None, ast::Mutability::Not, - cx.expr_array_ref(span, decls), - ) - .map(|mut i| { - i.attrs.push(cx.attr_word(sym::rustc_proc_macro_decls, span)); - i.attrs.push(cx.attr_word(sym::used, span)); - i.attrs.push(cx.attr_nested_word(sym::allow, sym::deprecated, span)); - i - }); + ), + ast::Mutability::Not, + cx.expr_array_ref(span, decls), + ); + decls_static.attrs.extend([ + cx.attr_word(sym::rustc_proc_macro_decls, span), + cx.attr_word(sym::used, span), + cx.attr_nested_word(sym::allow, sym::deprecated, span), + ]); let block = cx.expr_block( cx.block(span, thin_vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)]), diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 1cef4f9514c..fbe91531e5a 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -381,10 +381,7 @@ pub(crate) fn expand_test_or_bench( .into(), ), ); - test_const = test_const.map(|mut tc| { - tc.vis.kind = ast::VisibilityKind::Public; - tc - }); + test_const.vis.kind = ast::VisibilityKind::Public; // extern crate test let test_extern = -- cgit 1.4.1-3-g733a5 From 0f285e346f0432b08d82e85fc51419994b76504b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 May 2025 02:14:33 +1000 Subject: Remove the one use of `P<[T]>`. A `Vec` is fine, the additional word (vector vs. boxed slice) doesn't matter here. --- compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index c4be07ba068..4c821c00ad6 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1714,7 +1714,7 @@ pub enum ExprKind { /// /// Usually not written directly in user code but /// indirectly via the macro `core::mem::offset_of!(...)`. - OffsetOf(P, P<[Ident]>), + OffsetOf(P, Vec), /// A macro invocation; pre-expansion. MacCall(P), diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 2a7910a6af4..6e134bad7bd 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1119,7 +1119,7 @@ impl<'a> Parser<'a> { /// Parse the field access used in offset_of, matched by `$(e:expr)+`. /// Currently returns a list of idents. However, it should be possible in /// future to also do array indices, which might be arbitrary expressions. - fn parse_floating_field_access(&mut self) -> PResult<'a, P<[Ident]>> { + fn parse_floating_field_access(&mut self) -> PResult<'a, Vec> { let mut fields = Vec::new(); let mut trailing_dot = None; -- cgit 1.4.1-3-g733a5 From 68597509aa1e50f67000f7c36ccc3378b58e5f5d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 May 2025 02:16:52 +1000 Subject: Remove support for `P<[T]>`. It's no longer used. --- compiler/rustc_ast/src/ptr.rs | 79 +------------------------------------------ 1 file changed, 1 insertion(+), 78 deletions(-) diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index a1b265cf0a9..899d8eb7ca9 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -19,10 +19,10 @@ use std::fmt::{self, Debug, Display}; use std::ops::{Deref, DerefMut}; -use std::{slice, vec}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; + /// An owned smart pointer. /// /// See the [module level documentation][crate::ptr] for details. @@ -111,83 +111,6 @@ impl> Encodable for P { } } -impl P<[T]> { - // FIXME(const-hack) make this const again - pub fn new() -> P<[T]> { - P { ptr: Box::default() } - } - - #[inline(never)] - pub fn from_vec(v: Vec) -> P<[T]> { - P { ptr: v.into_boxed_slice() } - } - - #[inline(never)] - pub fn into_vec(self) -> Vec { - self.ptr.into_vec() - } -} - -impl Default for P<[T]> { - /// Creates an empty `P<[T]>`. - fn default() -> P<[T]> { - P::new() - } -} - -impl Clone for P<[T]> { - fn clone(&self) -> P<[T]> { - P::from_vec(self.to_vec()) - } -} - -impl From> for P<[T]> { - fn from(v: Vec) -> Self { - P::from_vec(v) - } -} - -impl From> for Vec { - fn from(val: P<[T]>) -> Self { - val.into_vec() - } -} - -impl FromIterator for P<[T]> { - fn from_iter>(iter: I) -> P<[T]> { - P::from_vec(iter.into_iter().collect()) - } -} - -impl IntoIterator for P<[T]> { - type Item = T; - type IntoIter = vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.into_vec().into_iter() - } -} - -impl<'a, T> IntoIterator for &'a P<[T]> { - type Item = &'a T; - type IntoIter = slice::Iter<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.ptr.iter() - } -} - -impl> Encodable for P<[T]> { - fn encode(&self, s: &mut S) { - Encodable::encode(&**self, s); - } -} - -impl> Decodable for P<[T]> { - fn decode(d: &mut D) -> P<[T]> { - P::from_vec(Decodable::decode(d)) - } -} - impl HashStable for P where T: ?Sized + HashStable, -- cgit 1.4.1-3-g733a5 From c42d1fc2c6ea5a35d8d74f909a1f69dee5d9ce56 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 May 2025 01:20:48 +1000 Subject: Remove unused `P` stuff. --- compiler/rustc_ast/src/ptr.rs | 44 ++----------------------------------------- 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index 899d8eb7ca9..91f29a4c289 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -17,10 +17,9 @@ //! heap, for example). Moreover, a switch to, e.g., `P<'a, T>` would be easy //! and mostly automated. -use std::fmt::{self, Debug, Display}; +use std::fmt::{self, Debug}; use std::ops::{Deref, DerefMut}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; /// An owned smart pointer. @@ -37,28 +36,10 @@ pub fn P(value: T) -> P { } impl P { - /// Move out of the pointer. - /// Intended for chaining transformations not covered by `map`. - pub fn and_then(self, f: F) -> U - where - F: FnOnce(T) -> U, - { - f(*self.ptr) - } - - /// Equivalent to `and_then(|x| x)`. + /// Consume the `P` and return the wrapped value. pub fn into_inner(self) -> T { *self.ptr } - - /// Optionally produce a new `P` from `self` without reallocating. - pub fn filter_map(mut self, f: F) -> Option> - where - F: FnOnce(T) -> Option, - { - *self.ptr = f(*self.ptr)?; - Some(self) - } } impl Deref for P { @@ -87,18 +68,6 @@ impl Debug for P { } } -impl Display for P { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(&**self, f) - } -} - -impl fmt::Pointer for P { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&self.ptr, f) - } -} - impl> Decodable for P { fn decode(d: &mut D) -> P { P(Decodable::decode(d)) @@ -110,12 +79,3 @@ impl> Encodable for P { (**self).encode(s); } } - -impl HashStable for P -where - T: ?Sized + HashStable, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - (**self).hash_stable(hcx, hasher); - } -} -- cgit 1.4.1-3-g733a5 From fdb660e8514ad09ebd9a478516d66b924c839f55 Mon Sep 17 00:00:00 2001 From: Diggory Blake Date: Sun, 25 May 2025 20:16:44 +0100 Subject: Limit the size of cgu names when using the `-Zhuman-readable-cgu-names` option Prior to this change, cgu names could be generated which would result in filenames longer than the limit imposed by the OS. --- compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_middle/src/mir/mono.rs | 26 ++++++++++++++++++++++++- compiler/rustc_monomorphize/src/partitioning.rs | 10 +++++----- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index cb3fdd4d3f7..7135b8f04a2 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -51,6 +51,7 @@ #![feature(negative_impls)] #![feature(never_type)] #![feature(ptr_alignment_type)] +#![feature(round_char_boundary)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![feature(trusted_len)] diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 7243f87ee63..47ba850d50d 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::fmt; use std::hash::Hash; @@ -468,6 +469,29 @@ impl<'tcx> CodegenUnit<'tcx> { hash.as_u128().to_base_fixed_len(CASE_INSENSITIVE) } + pub fn shorten_name(human_readable_name: &str) -> Cow<'_, str> { + // Set a limit a somewhat below the common platform limits for file names. + const MAX_CGU_NAME_LENGTH: usize = 200; + const TRUNCATED_NAME_PREFIX: &str = "-trunc-"; + if human_readable_name.len() > MAX_CGU_NAME_LENGTH { + let mangled_name = Self::mangle_name(human_readable_name); + // Determine a safe byte offset to truncate the name to + let truncate_to = human_readable_name.floor_char_boundary( + MAX_CGU_NAME_LENGTH - TRUNCATED_NAME_PREFIX.len() - mangled_name.len(), + ); + format!( + "{}{}{}", + &human_readable_name[..truncate_to], + TRUNCATED_NAME_PREFIX, + mangled_name + ) + .into() + } else { + // If the name is short enough, we can just return it as is. + human_readable_name.into() + } + } + pub fn compute_size_estimate(&mut self) { // The size of a codegen unit as the sum of the sizes of the items // within it. @@ -604,7 +628,7 @@ impl<'tcx> CodegenUnitNameBuilder<'tcx> { let cgu_name = self.build_cgu_name_no_mangle(cnum, components, special_suffix); if self.tcx.sess.opts.unstable_opts.human_readable_cgu_names { - cgu_name + Symbol::intern(&CodegenUnit::shorten_name(cgu_name.as_str())) } else { Symbol::intern(&CodegenUnit::mangle_name(cgu_name.as_str())) } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index b4169a060d4..49025673bbd 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -461,15 +461,15 @@ fn merge_codegen_units<'tcx>( for cgu in codegen_units.iter_mut() { if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { - if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names { - cgu.set_name(Symbol::intern(new_cgu_name)); + let new_cgu_name = if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names { + Symbol::intern(&CodegenUnit::shorten_name(new_cgu_name)) } else { // If we don't require CGU names to be human-readable, // we use a fixed length hash of the composite CGU name // instead. - let new_cgu_name = CodegenUnit::mangle_name(new_cgu_name); - cgu.set_name(Symbol::intern(&new_cgu_name)); - } + Symbol::intern(&CodegenUnit::mangle_name(new_cgu_name)) + }; + cgu.set_name(new_cgu_name); } } -- cgit 1.4.1-3-g733a5 From 991c91fdaa5862835799abfd9c2349e06277097e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 May 2025 02:32:22 +1000 Subject: Reduce `P` to a typedef of `Box`. Keep the `P` constructor function for now, to minimize immediate churn. All the `into_inner` calls are removed, which is nice. --- compiler/rustc_ast/src/attr/mod.rs | 2 +- compiler/rustc_ast/src/ptr.rs | 80 ++-------------------- compiler/rustc_builtin_macros/src/deriving/mod.rs | 2 +- compiler/rustc_builtin_macros/src/pattern_type.rs | 20 +++--- compiler/rustc_builtin_macros/src/test.rs | 8 +-- compiler/rustc_expand/src/base.rs | 2 +- compiler/rustc_expand/src/expand.rs | 37 +++++----- compiler/rustc_parse/src/parser/diagnostics.rs | 4 +- compiler/rustc_parse/src/parser/expr.rs | 6 +- compiler/rustc_parse/src/parser/item.rs | 4 +- compiler/rustc_parse/src/parser/pat.rs | 2 +- compiler/rustc_parse/src/parser/ty.rs | 6 +- .../clippy_lints/src/unnested_or_patterns.rs | 2 +- src/tools/rustfmt/src/modules.rs | 2 +- src/tools/rustfmt/src/parse/macros/cfg_if.rs | 2 +- 15 files changed, 48 insertions(+), 131 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index f165c4ddcdd..621e3042b62 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -63,7 +63,7 @@ impl Attribute { pub fn unwrap_normal_item(self) -> AttrItem { match self.kind { - AttrKind::Normal(normal) => normal.into_inner().item, + AttrKind::Normal(normal) => normal.item, AttrKind::DocComment(..) => panic!("unexpected doc comment"), } } diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index 91f29a4c289..fffeab8bbca 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -1,81 +1,11 @@ -//! The AST pointer. -//! -//! Provides [`P`][struct@P], an owned smart pointer. -//! -//! # Motivations and benefits -//! -//! * **Identity**: sharing AST nodes is problematic for the various analysis -//! passes (e.g., one may be able to bypass the borrow checker with a shared -//! `ExprKind::AddrOf` node taking a mutable borrow). -//! -//! * **Efficiency**: folding can reuse allocation space for `P` and `Vec`, -//! the latter even when the input and output types differ (as it would be the -//! case with arenas or a GADT AST using type parameters to toggle features). -//! -//! * **Maintainability**: `P` provides an interface, which can remain fully -//! functional even if the implementation changes (using a special thread-local -//! heap, for example). Moreover, a switch to, e.g., `P<'a, T>` would be easy -//! and mostly automated. - -use std::fmt::{self, Debug}; -use std::ops::{Deref, DerefMut}; - -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; - -/// An owned smart pointer. +/// A pointer type that uniquely owns a heap allocation of type T. /// -/// See the [module level documentation][crate::ptr] for details. -pub struct P { - ptr: Box, -} +/// This used to be its own type, but now it's just a typedef for `Box` and we are planning to +/// remove it soon. +pub type P = Box; /// Construct a `P` from a `T` value. #[allow(non_snake_case)] pub fn P(value: T) -> P { - P { ptr: Box::new(value) } -} - -impl P { - /// Consume the `P` and return the wrapped value. - pub fn into_inner(self) -> T { - *self.ptr - } -} - -impl Deref for P { - type Target = T; - - fn deref(&self) -> &T { - &self.ptr - } -} - -impl DerefMut for P { - fn deref_mut(&mut self) -> &mut T { - &mut self.ptr - } -} - -impl Clone for P { - fn clone(&self) -> P { - P((**self).clone()) - } -} - -impl Debug for P { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Debug::fmt(&self.ptr, f) - } -} - -impl> Decodable for P { - fn decode(d: &mut D) -> P { - P(Decodable::decode(d)) - } -} - -impl> Encodable for P { - fn encode(&self, s: &mut S) { - (**self).encode(s); - } + Box::new(value) } diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 50e7b989ed8..e45d09b5796 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -57,7 +57,7 @@ impl MultiItemModifier for BuiltinDerive { let mut items = Vec::new(); match item { Annotatable::Stmt(stmt) => { - if let ast::StmtKind::Item(item) = stmt.into_inner().kind { + if let ast::StmtKind::Item(item) = stmt.kind { (self.0)( ecx, span, diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index 3529e5525fc..b61af0b0aaa 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -30,14 +30,12 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P let pat = pat_to_ty_pat( cx, - parser - .parse_pat_no_top_guard( - None, - RecoverComma::No, - RecoverColon::No, - CommaRecoveryMode::EitherTupleOrPipe, - )? - .into_inner(), + *parser.parse_pat_no_top_guard( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::EitherTupleOrPipe, + )?, ); if parser.token != token::Eof { @@ -58,9 +56,9 @@ fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> P { end.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })), include_end, ), - ast::PatKind::Or(variants) => TyPatKind::Or( - variants.into_iter().map(|pat| pat_to_ty_pat(cx, pat.into_inner())).collect(), - ), + ast::PatKind::Or(variants) => { + TyPatKind::Or(variants.into_iter().map(|pat| pat_to_ty_pat(cx, *pat)).collect()) + } ast::PatKind::Err(guar) => TyPatKind::Err(guar), _ => TyPatKind::Err(cx.dcx().span_err(pat.span, "pattern not supported in pattern types")), }; diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index fbe91531e5a..b439fa34f5b 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -40,7 +40,7 @@ pub(crate) fn expand_test_case( let (mut item, is_stmt) = match anno_item { Annotatable::Item(item) => (item, false), Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => { - if let ast::StmtKind::Item(i) = stmt.into_inner().kind { + if let ast::StmtKind::Item(i) = stmt.kind { (i, true) } else { unreachable!() @@ -120,11 +120,7 @@ pub(crate) fn expand_test_or_bench( Annotatable::Item(i) => (i, false), Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => { // FIXME: Use an 'if let' guard once they are implemented - if let ast::StmtKind::Item(i) = stmt.into_inner().kind { - (i, true) - } else { - unreachable!() - } + if let ast::StmtKind::Item(i) = stmt.kind { (i, true) } else { unreachable!() } } other => { not_testable_error(cx, attr_sp, None); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 55751aa4908..058e45cdc4c 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -167,7 +167,7 @@ impl Annotatable { pub fn expect_stmt(self) -> ast::Stmt { match self { - Annotatable::Stmt(stmt) => stmt.into_inner(), + Annotatable::Stmt(stmt) => *stmt, _ => panic!("expected statement"), } } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 81d4d59ee04..4c7bc912f8f 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1188,9 +1188,8 @@ impl InvocationCollectorNode for P { matches!(self.kind, ItemKind::MacCall(..)) } fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { - let node = self.into_inner(); - match node.kind { - ItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + match self.kind { + ItemKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No), _ => unreachable!(), } } @@ -1344,7 +1343,7 @@ impl InvocationCollectorNode for AstNodeWrapper, TraitItemTag> matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { - let item = self.wrapped.into_inner(); + let item = self.wrapped; match item.kind { AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), _ => unreachable!(), @@ -1385,7 +1384,7 @@ impl InvocationCollectorNode for AstNodeWrapper, ImplItemTag> matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { - let item = self.wrapped.into_inner(); + let item = self.wrapped; match item.kind { AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), _ => unreachable!(), @@ -1426,7 +1425,7 @@ impl InvocationCollectorNode for AstNodeWrapper, TraitImplItem matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { - let item = self.wrapped.into_inner(); + let item = self.wrapped; match item.kind { AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), _ => unreachable!(), @@ -1464,9 +1463,8 @@ impl InvocationCollectorNode for P { matches!(self.kind, ForeignItemKind::MacCall(..)) } fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { - let node = self.into_inner(); - match node.kind { - ForeignItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + match self.kind { + ForeignItemKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No), _ => unreachable!(), } } @@ -1601,16 +1599,16 @@ impl InvocationCollectorNode for ast::Stmt { // `StmtKind`s and treat them as statement macro invocations, not as items or expressions. let (add_semicolon, mac, attrs) = match self.kind { StmtKind::MacCall(mac) => { - let ast::MacCallStmt { mac, style, attrs, .. } = mac.into_inner(); + let ast::MacCallStmt { mac, style, attrs, .. } = *mac; (style == MacStmtStyle::Semicolon, mac, attrs) } - StmtKind::Item(item) => match item.into_inner() { + StmtKind::Item(item) => match *item { ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => { (mac.args.need_semicolon(), mac, attrs) } _ => unreachable!(), }, - StmtKind::Semi(expr) => match expr.into_inner() { + StmtKind::Semi(expr) => match *expr { ast::Expr { kind: ExprKind::MacCall(mac), attrs, .. } => { (mac.args.need_semicolon(), mac, attrs) } @@ -1691,8 +1689,7 @@ impl InvocationCollectorNode for P { matches!(self.kind, ast::TyKind::MacCall(..)) } fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { - let node = self.into_inner(); - match node.kind { + match self.kind { TyKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No), _ => unreachable!(), } @@ -1715,8 +1712,7 @@ impl InvocationCollectorNode for P { matches!(self.kind, PatKind::MacCall(..)) } fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { - let node = self.into_inner(); - match node.kind { + match self.kind { PatKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No), _ => unreachable!(), } @@ -1742,9 +1738,8 @@ impl InvocationCollectorNode for P { matches!(self.kind, ExprKind::MacCall(..)) } fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { - let node = self.into_inner(); - match node.kind { - ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + match self.kind { + ExprKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No), _ => unreachable!(), } } @@ -1768,7 +1763,7 @@ impl InvocationCollectorNode for AstNodeWrapper, OptExprTag> { matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) } fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { - let node = self.wrapped.into_inner(); + let node = self.wrapped; match node.kind { ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), _ => unreachable!(), @@ -1806,7 +1801,7 @@ impl InvocationCollectorNode for AstNodeWrapper, MethodReceiverTag> matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) } fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) { - let node = self.wrapped.into_inner(); + let node = self.wrapped; match node.kind { ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), _ => unreachable!(), diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 6277dde7c97..b49a13ce584 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2273,9 +2273,9 @@ impl<'a> Parser<'a> { ), // Also catches `fn foo(&a)`. PatKind::Ref(ref inner_pat, mutab) - if matches!(inner_pat.clone().into_inner().kind, PatKind::Ident(..)) => + if matches!(inner_pat.clone().kind, PatKind::Ident(..)) => { - match inner_pat.clone().into_inner().kind { + match inner_pat.clone().kind { PatKind::Ident(_, ident, _) => { let mutab = mutab.prefix_str(); ( diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 6e134bad7bd..5824c2aa405 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3450,10 +3450,8 @@ impl<'a> Parser<'a> { // Detect and recover from `($pat if $cond) => $arm`. // FIXME(guard_patterns): convert this to a normal guard instead let span = pat.span; - let ast::PatKind::Paren(subpat) = pat.into_inner().kind else { unreachable!() }; - let ast::PatKind::Guard(_, mut cond) = subpat.into_inner().kind else { - unreachable!() - }; + let ast::PatKind::Paren(subpat) = pat.kind else { unreachable!() }; + let ast::PatKind::Guard(_, mut cond) = subpat.kind else { unreachable!() }; self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span); CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond); let right = self.prev_token.span; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index babc55ccc0f..e9654e61eb8 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -145,7 +145,7 @@ impl<'a> Parser<'a> { { let mut item = item.expect("an actual item"); attrs.prepend_to_nt_inner(&mut item.attrs); - return Ok(Some(item.into_inner())); + return Ok(Some(*item)); } self.collect_tokens(None, attrs, force_collect, |this, mut attrs| { @@ -637,7 +637,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(errors::MissingForInTraitImpl { span: missing_for_span }); } - let ty_first = ty_first.into_inner(); + let ty_first = *ty_first; let path = match ty_first.kind { // This notably includes paths passed through `ty` macro fragments (#46438). TyKind::Path(None, path) => path, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index d6ff80b2eb4..7a226136e23 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1086,7 +1086,7 @@ impl<'a> Parser<'a> { if matches!(pat.kind, PatKind::Ident(BindingMode(ByRef::Yes(_), Mutability::Mut), ..)) { self.psess.gated_spans.gate(sym::mut_ref, pat.span); } - Ok(pat.into_inner().kind) + Ok(pat.kind) } /// Turn all by-value immutable bindings in a pattern into mutable bindings. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 17481731b11..460cf23c393 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -404,7 +404,7 @@ impl<'a> Parser<'a> { })?; if ts.len() == 1 && matches!(trailing, Trailing::No) { - let ty = ts.into_iter().next().unwrap().into_inner(); + let ty = ts.into_iter().next().unwrap(); let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus(); match ty.kind { // `(TY_BOUND_NOPAREN) + BOUND + ...`. @@ -420,7 +420,7 @@ impl<'a> Parser<'a> { self.parse_remaining_bounds(bounds, true) } // `(TYPE)` - _ => Ok(TyKind::Paren(P(ty))), + _ => Ok(TyKind::Paren(ty)), } } else { Ok(TyKind::Tup(ts)) @@ -1295,7 +1295,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, ()> { let fn_path_segment = fn_path.segments.last_mut().unwrap(); let generic_args = if let Some(p_args) = &fn_path_segment.args { - p_args.clone().into_inner() + *p_args.clone() } else { // Normally it wouldn't come here because the upstream should have parsed // generic parameters (otherwise it's impossible to call this function). diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 9ad184450de..b839b6f5672 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -426,7 +426,7 @@ fn drain_matching( // Check if we should extract, but only if `idx >= start`. if idx > start && predicate(&alternatives[i].kind) { let pat = alternatives.remove(i); - tail_or.push(extract(pat.into_inner().kind)); + tail_or.push(extract(pat.kind)); } else { i += 1; } diff --git a/src/tools/rustfmt/src/modules.rs b/src/tools/rustfmt/src/modules.rs index bc5a6d3e704..44c8123517c 100644 --- a/src/tools/rustfmt/src/modules.rs +++ b/src/tools/rustfmt/src/modules.rs @@ -174,7 +174,7 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> { ) -> Result<(), ModuleResolutionError> { for item in items { if is_cfg_if(&item) { - self.visit_cfg_if(Cow::Owned(item.into_inner()))?; + self.visit_cfg_if(Cow::Owned(*item))?; continue; } diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs index 30b83373c17..26bf6c5326f 100644 --- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs +++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs @@ -62,7 +62,7 @@ fn parse_cfg_if_inner<'a>( while parser.token != TokenKind::CloseBrace && parser.token.kind != TokenKind::Eof { let item = match parser.parse_item(ForceCollect::No) { - Ok(Some(item_ptr)) => item_ptr.into_inner(), + Ok(Some(item_ptr)) => *item_ptr, Ok(None) => continue, Err(err) => { err.cancel(); -- cgit 1.4.1-3-g733a5 From d851cfab33b1efcd729db71961e4101b937cfa75 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 27 May 2025 20:30:52 +0200 Subject: Make the `dangerous_implicit_autorefs` lint deny-by-default --- compiler/rustc_lint/src/autorefs.rs | 4 +- tests/ui/lint/implicit_autorefs.fixed | 53 +++++++++++---------- tests/ui/lint/implicit_autorefs.rs | 53 +++++++++++---------- tests/ui/lint/implicit_autorefs.stderr | 84 +++++++++++++++++----------------- 4 files changed, 100 insertions(+), 94 deletions(-) diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs index 5de2cbf9939..845a1f1b81f 100644 --- a/compiler/rustc_lint/src/autorefs.rs +++ b/compiler/rustc_lint/src/autorefs.rs @@ -16,7 +16,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust + /// ```rust,compile_fail /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] { /// unsafe { &raw mut (*ptr)[..16] } /// // ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`, @@ -51,7 +51,7 @@ declare_lint! { /// } /// ``` pub DANGEROUS_IMPLICIT_AUTOREFS, - Warn, + Deny, "implicit reference to a dereference of a raw pointer", report_in_external_macro } diff --git a/tests/ui/lint/implicit_autorefs.fixed b/tests/ui/lint/implicit_autorefs.fixed index 454dfe76372..7aa21e77458 100644 --- a/tests/ui/lint/implicit_autorefs.fixed +++ b/tests/ui/lint/implicit_autorefs.fixed @@ -1,4 +1,4 @@ -//@ check-pass +//@ check-fail //@ run-rustfix #![allow(dead_code)] // For the rustfix-ed code. @@ -8,7 +8,7 @@ use std::ops::Deref; unsafe fn test_const(ptr: *const [u8]) { let _ = (&(*ptr))[..16]; - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } struct Test { @@ -17,36 +17,36 @@ struct Test { unsafe fn test_field(ptr: *const Test) -> *const [u8] { let l = (&(*ptr).field).len(); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref &raw const (&(*ptr).field)[..l - 1] - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } unsafe fn test_builtin_index(a: *mut [String]) { _ = (&(*a)[0]).len(); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref _ = (&(&(*a))[..1][0]).len(); - //~^ WARN implicit autoref - //~^^ WARN implicit autoref + //~^ ERROR implicit autoref + //~^^ ERROR implicit autoref } unsafe fn test_overloaded_deref_const(ptr: *const ManuallyDrop) { let _ = (&(*ptr)).field; - //~^ WARN implicit autoref + //~^ ERROR implicit autoref let _ = &raw const (&(*ptr)).field; - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } unsafe fn test_overloaded_deref_mut(ptr: *mut ManuallyDrop) { let _ = (&(*ptr)).field; - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } unsafe fn test_double_overloaded_deref_const(ptr: *const ManuallyDrop>) { let _ = (&(*ptr)).field; - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } unsafe fn test_manually_overloaded_deref() { @@ -54,52 +54,55 @@ unsafe fn test_manually_overloaded_deref() { impl Deref for W { type Target = T; - fn deref(&self) -> &T { &self.0 } + fn deref(&self) -> &T { + &self.0 + } } let w: W = W(5); let w = &raw const w; let _p: *const i32 = &raw const *(&**w); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } struct Test2 { // Derefs to `[u8]`. - field: &'static [u8] + field: &'static [u8], } fn test_more_manual_deref(ptr: *const Test2) -> usize { unsafe { (&(*ptr).field).len() } - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } unsafe fn test_no_attr(ptr: *mut ManuallyDrop) { - ptr.write(ManuallyDrop::new(1)); // Should not warn, as `ManuallyDrop::write` is not - // annotated with `#[rustc_no_implicit_auto_ref]` + // Should not warn, as `ManuallyDrop::write` is not + // annotated with `#[rustc_no_implicit_auto_ref]` + ptr.write(ManuallyDrop::new(1)); } unsafe fn test_vec_get(ptr: *mut Vec) { let _ = (&(*ptr)).get(0); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref let _ = (&(*ptr)).get_unchecked(0); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref let _ = (&mut (*ptr)).get_mut(0); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref let _ = (&mut (*ptr)).get_unchecked_mut(0); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } unsafe fn test_string(ptr: *mut String) { let _ = (&(*ptr)).len(); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref let _ = (&(*ptr)).is_empty(); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } unsafe fn slice_ptr_len_because_of_msrv(slice: *const [T]) { let _ = (&(&(*slice))[..]).len(); - //~^ WARN implicit autoref - //~^^ WARN implicit autoref + //~^ ERROR implicit autoref + //~^^ ERROR implicit autoref } fn main() {} diff --git a/tests/ui/lint/implicit_autorefs.rs b/tests/ui/lint/implicit_autorefs.rs index 507d6536828..f33cb08e985 100644 --- a/tests/ui/lint/implicit_autorefs.rs +++ b/tests/ui/lint/implicit_autorefs.rs @@ -1,4 +1,4 @@ -//@ check-pass +//@ check-fail //@ run-rustfix #![allow(dead_code)] // For the rustfix-ed code. @@ -8,7 +8,7 @@ use std::ops::Deref; unsafe fn test_const(ptr: *const [u8]) { let _ = (*ptr)[..16]; - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } struct Test { @@ -17,36 +17,36 @@ struct Test { unsafe fn test_field(ptr: *const Test) -> *const [u8] { let l = (*ptr).field.len(); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref &raw const (*ptr).field[..l - 1] - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } unsafe fn test_builtin_index(a: *mut [String]) { _ = (*a)[0].len(); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref _ = (*a)[..1][0].len(); - //~^ WARN implicit autoref - //~^^ WARN implicit autoref + //~^ ERROR implicit autoref + //~^^ ERROR implicit autoref } unsafe fn test_overloaded_deref_const(ptr: *const ManuallyDrop) { let _ = (*ptr).field; - //~^ WARN implicit autoref + //~^ ERROR implicit autoref let _ = &raw const (*ptr).field; - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } unsafe fn test_overloaded_deref_mut(ptr: *mut ManuallyDrop) { let _ = (*ptr).field; - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } unsafe fn test_double_overloaded_deref_const(ptr: *const ManuallyDrop>) { let _ = (*ptr).field; - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } unsafe fn test_manually_overloaded_deref() { @@ -54,52 +54,55 @@ unsafe fn test_manually_overloaded_deref() { impl Deref for W { type Target = T; - fn deref(&self) -> &T { &self.0 } + fn deref(&self) -> &T { + &self.0 + } } let w: W = W(5); let w = &raw const w; let _p: *const i32 = &raw const **w; - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } struct Test2 { // Derefs to `[u8]`. - field: &'static [u8] + field: &'static [u8], } fn test_more_manual_deref(ptr: *const Test2) -> usize { unsafe { (*ptr).field.len() } - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } unsafe fn test_no_attr(ptr: *mut ManuallyDrop) { - ptr.write(ManuallyDrop::new(1)); // Should not warn, as `ManuallyDrop::write` is not - // annotated with `#[rustc_no_implicit_auto_ref]` + // Should not warn, as `ManuallyDrop::write` is not + // annotated with `#[rustc_no_implicit_auto_ref]` + ptr.write(ManuallyDrop::new(1)); } unsafe fn test_vec_get(ptr: *mut Vec) { let _ = (*ptr).get(0); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref let _ = (*ptr).get_unchecked(0); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref let _ = (*ptr).get_mut(0); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref let _ = (*ptr).get_unchecked_mut(0); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } unsafe fn test_string(ptr: *mut String) { let _ = (*ptr).len(); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref let _ = (*ptr).is_empty(); - //~^ WARN implicit autoref + //~^ ERROR implicit autoref } unsafe fn slice_ptr_len_because_of_msrv(slice: *const [T]) { let _ = (*slice)[..].len(); - //~^ WARN implicit autoref - //~^^ WARN implicit autoref + //~^ ERROR implicit autoref + //~^^ ERROR implicit autoref } fn main() {} diff --git a/tests/ui/lint/implicit_autorefs.stderr b/tests/ui/lint/implicit_autorefs.stderr index 80ba8ae2fd2..bd914e2998a 100644 --- a/tests/ui/lint/implicit_autorefs.stderr +++ b/tests/ui/lint/implicit_autorefs.stderr @@ -1,4 +1,4 @@ -warning: implicit autoref creates a reference to the dereference of a raw pointer +error: implicit autoref creates a reference to the dereference of a raw pointer --> $DIR/implicit_autorefs.rs:10:13 | LL | let _ = (*ptr)[..16]; @@ -12,13 +12,13 @@ note: autoref is being applied to this expression, resulting in: `&[u8]` | LL | let _ = (*ptr)[..16]; | ^^^^^^ - = note: `#[warn(dangerous_implicit_autorefs)]` on by default + = note: `#[deny(dangerous_implicit_autorefs)]` on by default help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = (&(*ptr))[..16]; | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer +error: implicit autoref creates a reference to the dereference of a raw pointer --> $DIR/implicit_autorefs.rs:19:13 | LL | let l = (*ptr).field.len(); @@ -39,7 +39,7 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | let l = (&(*ptr).field).len(); | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer +error: implicit autoref creates a reference to the dereference of a raw pointer --> $DIR/implicit_autorefs.rs:22:16 | LL | &raw const (*ptr).field[..l - 1] @@ -58,7 +58,7 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | &raw const (&(*ptr).field)[..l - 1] | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer +error: implicit autoref creates a reference to the dereference of a raw pointer --> $DIR/implicit_autorefs.rs:27:9 | LL | _ = (*a)[0].len(); @@ -79,7 +79,7 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | _ = (&(*a)[0]).len(); | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer +error: implicit autoref creates a reference to the dereference of a raw pointer --> $DIR/implicit_autorefs.rs:30:9 | LL | _ = (*a)[..1][0].len(); @@ -100,7 +100,7 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | _ = (&(*a)[..1][0]).len(); | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer +error: implicit autoref creates a reference to the dereference of a raw pointer --> $DIR/implicit_autorefs.rs:30:9 | LL | _ = (*a)[..1][0].len(); @@ -119,7 +119,7 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | _ = (&(*a))[..1][0].len(); | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer +error: implicit autoref creates a reference to the dereference of a raw pointer --> $DIR/implicit_autorefs.rs:36:13 | LL | let _ = (*ptr).field; @@ -134,7 +134,7 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | let _ = (&(*ptr)).field; | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer +error: implicit autoref creates a reference to the dereference of a raw pointer --> $DIR/implicit_autorefs.rs:38:24 | LL | let _ = &raw const (*ptr).field; @@ -149,7 +149,7 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | let _ = &raw const (&(*ptr)).field; | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer +error: implicit autoref creates a reference to the dereference of a raw pointer --> $DIR/implicit_autorefs.rs:43:13 | LL | let _ = (*ptr).field; @@ -164,7 +164,7 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | let _ = (&(*ptr)).field; | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer +error: implicit autoref creates a reference to the dereference of a raw pointer --> $DIR/implicit_autorefs.rs:48:13 | LL | let _ = (*ptr).field; @@ -179,8 +179,8 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | let _ = (&(*ptr)).field; | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer - --> $DIR/implicit_autorefs.rs:62:26 +error: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:64:26 | LL | let _p: *const i32 = &raw const **w; | ^^^^^^^^^^^^^- @@ -189,7 +189,7 @@ LL | let _p: *const i32 = &raw const **w; | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements note: autoref is being applied to this expression, resulting in: `&W` - --> $DIR/implicit_autorefs.rs:62:38 + --> $DIR/implicit_autorefs.rs:64:38 | LL | let _p: *const i32 = &raw const **w; | ^^ @@ -198,8 +198,8 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | let _p: *const i32 = &raw const *(&**w); | +++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer - --> $DIR/implicit_autorefs.rs:72:14 +error: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:74:14 | LL | unsafe { (*ptr).field.len() } | ^^---^^^^^^^^^^^^^ @@ -208,7 +208,7 @@ LL | unsafe { (*ptr).field.len() } | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements note: autoref is being applied to this expression, resulting in: `&[u8]` - --> $DIR/implicit_autorefs.rs:72:14 + --> $DIR/implicit_autorefs.rs:74:14 | LL | unsafe { (*ptr).field.len() } | ^^^^^^^^^^^^ @@ -219,8 +219,8 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | unsafe { (&(*ptr).field).len() } | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer - --> $DIR/implicit_autorefs.rs:82:13 +error: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:85:13 | LL | let _ = (*ptr).get(0); | ^^---^^^^^^^^ @@ -229,7 +229,7 @@ LL | let _ = (*ptr).get(0); | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements note: autoref is being applied to this expression, resulting in: `&[u8]` - --> $DIR/implicit_autorefs.rs:82:13 + --> $DIR/implicit_autorefs.rs:85:13 | LL | let _ = (*ptr).get(0); | ^^^^^^ @@ -240,8 +240,8 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | let _ = (&(*ptr)).get(0); | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer - --> $DIR/implicit_autorefs.rs:84:13 +error: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:87:13 | LL | let _ = (*ptr).get_unchecked(0); | ^^---^^^^^^^^^^^^^^^^^^ @@ -250,7 +250,7 @@ LL | let _ = (*ptr).get_unchecked(0); | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements note: autoref is being applied to this expression, resulting in: `&[u8]` - --> $DIR/implicit_autorefs.rs:84:13 + --> $DIR/implicit_autorefs.rs:87:13 | LL | let _ = (*ptr).get_unchecked(0); | ^^^^^^ @@ -261,8 +261,8 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | let _ = (&(*ptr)).get_unchecked(0); | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer - --> $DIR/implicit_autorefs.rs:86:13 +error: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:89:13 | LL | let _ = (*ptr).get_mut(0); | ^^---^^^^^^^^^^^^ @@ -271,7 +271,7 @@ LL | let _ = (*ptr).get_mut(0); | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements note: autoref is being applied to this expression, resulting in: `&mut [u8]` - --> $DIR/implicit_autorefs.rs:86:13 + --> $DIR/implicit_autorefs.rs:89:13 | LL | let _ = (*ptr).get_mut(0); | ^^^^^^ @@ -282,8 +282,8 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | let _ = (&mut (*ptr)).get_mut(0); | +++++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer - --> $DIR/implicit_autorefs.rs:88:13 +error: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:91:13 | LL | let _ = (*ptr).get_unchecked_mut(0); | ^^---^^^^^^^^^^^^^^^^^^^^^^ @@ -292,7 +292,7 @@ LL | let _ = (*ptr).get_unchecked_mut(0); | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements note: autoref is being applied to this expression, resulting in: `&mut [u8]` - --> $DIR/implicit_autorefs.rs:88:13 + --> $DIR/implicit_autorefs.rs:91:13 | LL | let _ = (*ptr).get_unchecked_mut(0); | ^^^^^^ @@ -303,8 +303,8 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | let _ = (&mut (*ptr)).get_unchecked_mut(0); | +++++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer - --> $DIR/implicit_autorefs.rs:93:13 +error: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:96:13 | LL | let _ = (*ptr).len(); | ^^---^^^^^^^ @@ -313,7 +313,7 @@ LL | let _ = (*ptr).len(); | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements note: autoref is being applied to this expression, resulting in: `&String` - --> $DIR/implicit_autorefs.rs:93:13 + --> $DIR/implicit_autorefs.rs:96:13 | LL | let _ = (*ptr).len(); | ^^^^^^ @@ -324,8 +324,8 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | let _ = (&(*ptr)).len(); | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer - --> $DIR/implicit_autorefs.rs:95:13 +error: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:98:13 | LL | let _ = (*ptr).is_empty(); | ^^---^^^^^^^^^^^^ @@ -334,7 +334,7 @@ LL | let _ = (*ptr).is_empty(); | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements note: autoref is being applied to this expression, resulting in: `&String` - --> $DIR/implicit_autorefs.rs:95:13 + --> $DIR/implicit_autorefs.rs:98:13 | LL | let _ = (*ptr).is_empty(); | ^^^^^^ @@ -345,8 +345,8 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | let _ = (&(*ptr)).is_empty(); | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer - --> $DIR/implicit_autorefs.rs:100:13 +error: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:103:13 | LL | let _ = (*slice)[..].len(); | ^^-----^^^^^^^^^^^ @@ -355,7 +355,7 @@ LL | let _ = (*slice)[..].len(); | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements note: autoref is being applied to this expression, resulting in: `&[T]` - --> $DIR/implicit_autorefs.rs:100:13 + --> $DIR/implicit_autorefs.rs:103:13 | LL | let _ = (*slice)[..].len(); | ^^^^^^^^^^^^ @@ -366,8 +366,8 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | let _ = (&(*slice)[..]).len(); | ++ + -warning: implicit autoref creates a reference to the dereference of a raw pointer - --> $DIR/implicit_autorefs.rs:100:13 +error: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:103:13 | LL | let _ = (*slice)[..].len(); | ^^-----^^^^^ @@ -376,7 +376,7 @@ LL | let _ = (*slice)[..].len(); | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements note: autoref is being applied to this expression, resulting in: `&[T]` - --> $DIR/implicit_autorefs.rs:100:13 + --> $DIR/implicit_autorefs.rs:103:13 | LL | let _ = (*slice)[..].len(); | ^^^^^^^^ @@ -385,5 +385,5 @@ help: try using a raw pointer method instead; or if this reference is intentiona LL | let _ = (&(*slice))[..].len(); | ++ + -warning: 20 warnings emitted +error: aborting due to 20 previous errors -- cgit 1.4.1-3-g733a5 From 4c264c96ae30e45c503fbb24e452ea948c5229af Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 23 May 2025 17:26:39 +0000 Subject: Update `CmpResult` to use a pointer-sized return type As seen at [1], LLVM uses `long long` on LLP64 (to get a 64-bit integer matching pointer size) and `long` on everything else, with exceptions for AArch64 and AVR. Our current logic always uses an `i32`. This happens to work because LLVM uses 32-bit instructions to check the output on x86-64, but the GCC checks the full 64-bit register so garbage in the upper half leads to incorrect results. Update our return type to be `isize`, with exceptions for AArch64 and AVR. Fixes: https://github.com/rust-lang/compiler-builtins/issues/919 [1]: https://github.com/llvm/llvm-project/blob/0cf3c437c18ed27d9663d87804a9a15ff6874af2/compiler-rt/lib/builtins/fp_compare_impl.inc#L11-L27 --- .../builtins-test/benches/float_cmp.rs | 43 ++++++++++++++-------- .../compiler-builtins/builtins-test/src/bench.rs | 4 +- .../compiler-builtins/src/float/cmp.rs | 25 +++++++++---- .../compiler-builtins/libm/src/math/support/mod.rs | 2 + 4 files changed, 48 insertions(+), 26 deletions(-) diff --git a/library/compiler-builtins/builtins-test/benches/float_cmp.rs b/library/compiler-builtins/builtins-test/benches/float_cmp.rs index 42d6652397d..87a89efb5a4 100644 --- a/library/compiler-builtins/builtins-test/benches/float_cmp.rs +++ b/library/compiler-builtins/builtins-test/benches/float_cmp.rs @@ -1,12 +1,23 @@ #![cfg_attr(f128_enabled, feature(f128))] use builtins_test::float_bench; -use compiler_builtins::float::cmp; +use compiler_builtins::float::cmp::{self, CmpResult}; use criterion::{Criterion, criterion_main}; /// `gt` symbols are allowed to return differing results, they just get compared /// to 0. -fn gt_res_eq(a: i32, b: i32) -> bool { +fn gt_res_eq(mut a: CmpResult, mut b: CmpResult) -> bool { + // FIXME: Our CmpResult used to be `i32`, but GCC/LLVM expect `isize`. on 64-bit platforms, + // this means the top half of the word may be garbage if built with an old version of + // `compiler-builtins`, so add a hack around this. + // + // This can be removed once a version of `compiler-builtins` with the return type fix makes + // it upstream. + if size_of::() == 8 { + a = a as i32 as CmpResult; + b = b as i32 as CmpResult; + } + let a_lt_0 = a <= 0; let b_lt_0 = b <= 0; (a_lt_0 && b_lt_0) || (!a_lt_0 && !b_lt_0) @@ -14,14 +25,14 @@ fn gt_res_eq(a: i32, b: i32) -> bool { float_bench! { name: cmp_f32_gt, - sig: (a: f32, b: f32) -> i32, + sig: (a: f32, b: f32) -> CmpResult, crate_fn: cmp::__gtsf2, sys_fn: __gtsf2, sys_available: all(), output_eq: gt_res_eq, asm: [ #[cfg(target_arch = "x86_64")] { - let ret: i32; + let ret: CmpResult; asm!( "xor {ret:e}, {ret:e}", "ucomiss {a}, {b}", @@ -36,7 +47,7 @@ float_bench! { }; #[cfg(target_arch = "aarch64")] { - let ret: i32; + let ret: CmpResult; asm!( "fcmp {a:s}, {b:s}", "cset {ret:w}, gt", @@ -53,13 +64,13 @@ float_bench! { float_bench! { name: cmp_f32_unord, - sig: (a: f32, b: f32) -> i32, + sig: (a: f32, b: f32) -> CmpResult, crate_fn: cmp::__unordsf2, sys_fn: __unordsf2, sys_available: all(), asm: [ #[cfg(target_arch = "x86_64")] { - let ret: i32; + let ret: CmpResult; asm!( "xor {ret:e}, {ret:e}", "ucomiss {a}, {b}", @@ -74,7 +85,7 @@ float_bench! { }; #[cfg(target_arch = "aarch64")] { - let ret: i32; + let ret: CmpResult; asm!( "fcmp {a:s}, {b:s}", "cset {ret:w}, vs", @@ -91,14 +102,14 @@ float_bench! { float_bench! { name: cmp_f64_gt, - sig: (a: f64, b: f64) -> i32, + sig: (a: f64, b: f64) -> CmpResult, crate_fn: cmp::__gtdf2, sys_fn: __gtdf2, sys_available: all(), output_eq: gt_res_eq, asm: [ #[cfg(target_arch = "x86_64")] { - let ret: i32; + let ret: CmpResult; asm!( "xor {ret:e}, {ret:e}", "ucomisd {a}, {b}", @@ -113,7 +124,7 @@ float_bench! { }; #[cfg(target_arch = "aarch64")] { - let ret: i32; + let ret: CmpResult; asm!( "fcmp {a:d}, {b:d}", "cset {ret:w}, gt", @@ -130,13 +141,13 @@ float_bench! { float_bench! { name: cmp_f64_unord, - sig: (a: f64, b: f64) -> i32, + sig: (a: f64, b: f64) -> CmpResult, crate_fn: cmp::__unorddf2, sys_fn: __unorddf2, sys_available: all(), asm: [ #[cfg(target_arch = "x86_64")] { - let ret: i32; + let ret: CmpResult; asm!( "xor {ret:e}, {ret:e}", "ucomisd {a}, {b}", @@ -151,7 +162,7 @@ float_bench! { }; #[cfg(target_arch = "aarch64")] { - let ret: i32; + let ret: CmpResult; asm!( "fcmp {a:d}, {b:d}", "cset {ret:w}, vs", @@ -168,7 +179,7 @@ float_bench! { float_bench! { name: cmp_f128_gt, - sig: (a: f128, b: f128) -> i32, + sig: (a: f128, b: f128) -> CmpResult, crate_fn: cmp::__gttf2, crate_fn_ppc: cmp::__gtkf2, sys_fn: __gttf2, @@ -180,7 +191,7 @@ float_bench! { float_bench! { name: cmp_f128_unord, - sig: (a: f128, b: f128) -> i32, + sig: (a: f128, b: f128) -> CmpResult, crate_fn: cmp::__unordtf2, crate_fn_ppc: cmp::__unordkf2, sys_fn: __unordtf2, diff --git a/library/compiler-builtins/builtins-test/src/bench.rs b/library/compiler-builtins/builtins-test/src/bench.rs index 2348f6bc973..0987185670e 100644 --- a/library/compiler-builtins/builtins-test/src/bench.rs +++ b/library/compiler-builtins/builtins-test/src/bench.rs @@ -358,8 +358,8 @@ impl_testio!(float f16); impl_testio!(float f32, f64); #[cfg(f128_enabled)] impl_testio!(float f128); -impl_testio!(int i16, i32, i64, i128); -impl_testio!(int u16, u32, u64, u128); +impl_testio!(int i8, i16, i32, i64, i128, isize); +impl_testio!(int u8, u16, u32, u64, u128, usize); impl_testio!((float, int)(f32, i32)); impl_testio!((float, int)(f64, i32)); #[cfg(f128_enabled)] diff --git a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs index 296952821cb..f1e54dc1c83 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs @@ -2,14 +2,23 @@ use crate::float::Float; use crate::int::MinInt; - -// https://github.com/llvm/llvm-project/blob/1e6ba3cd2fe96be00b6ed6ba28b3d9f9271d784d/compiler-rt/lib/builtins/fp_compare_impl.inc#L22 -#[cfg(target_arch = "avr")] -pub type CmpResult = i8; - -// https://github.com/llvm/llvm-project/blob/1e6ba3cd2fe96be00b6ed6ba28b3d9f9271d784d/compiler-rt/lib/builtins/fp_compare_impl.inc#L25 -#[cfg(not(target_arch = "avr"))] -pub type CmpResult = i32; +use crate::support::cfg_if; + +// Taken from LLVM config: +// https://github.com/llvm/llvm-project/blob/0cf3c437c18ed27d9663d87804a9a15ff6874af2/compiler-rt/lib/builtins/fp_compare_impl.inc#L11-L27 +cfg_if! { + if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] { + // Aarch64 uses `int` rather than a pointer-sized value. + pub type CmpResult = i32; + } else if #[cfg(target_arch = "avr")] { + // AVR uses a single byte. + pub type CmpResult = i8; + } else { + // In compiler-rt, LLP64 ABIs use `long long` and everything else uses `long`. In effect, + // this means the return value is always pointer-sized. + pub type CmpResult = isize; + } +} #[derive(Clone, Copy)] enum Result { diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index a4f596ab844..2771cfd32c8 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -11,6 +11,8 @@ mod int_traits; #[allow(unused_imports)] pub use big::{i256, u256}; +#[allow(unused_imports)] +pub(crate) use cfg_if; pub use env::{FpResult, Round, Status}; #[allow(unused_imports)] pub use float_traits::{DFloat, Float, HFloat, IntTy}; -- cgit 1.4.1-3-g733a5 From 2b0797aef509e4e245128ff24277f72da23b133f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 May 2025 16:20:32 +0200 Subject: UnsafePinned: also include the effects of UnsafeCell --- library/core/src/pin/unsafe_pinned.rs | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/library/core/src/pin/unsafe_pinned.rs b/library/core/src/pin/unsafe_pinned.rs index f65e83662fe..dbcceb807ab 100644 --- a/library/core/src/pin/unsafe_pinned.rs +++ b/library/core/src/pin/unsafe_pinned.rs @@ -1,10 +1,13 @@ +use crate::cell::UnsafeCell; use crate::marker::{PointerLike, Unpin}; use crate::ops::{CoerceUnsized, DispatchFromDyn}; use crate::pin::Pin; use crate::{fmt, ptr}; -/// This type provides a way to opt-out of typical aliasing rules; +/// This type provides a way to entirely opt-out of typical aliasing rules; /// specifically, `&mut UnsafePinned` is not guaranteed to be a unique pointer. +/// This also subsumes the effects of `UnsafeCell`, i.e., `&UnsafePinned` may point to data +/// that is being mutated. /// /// However, even if you define your type like `pub struct Wrapper(UnsafePinned<...>)`, it is still /// very risky to have an `&mut Wrapper` that aliases anything else. Many functions that work @@ -17,38 +20,24 @@ use crate::{fmt, ptr}; /// the public API of a library. It is an internal implementation detail of libraries that need to /// support aliasing mutable references. /// -/// Further note that this does *not* lift the requirement that shared references must be read-only! -/// Use `UnsafeCell` for that. -/// /// This type blocks niches the same way `UnsafeCell` does. #[lang = "unsafe_pinned"] #[repr(transparent)] #[unstable(feature = "unsafe_pinned", issue = "125735")] pub struct UnsafePinned { - value: T, + value: UnsafeCell, } +// Override the manual `!Sync` in `UnsafeCell`. +#[unstable(feature = "unsafe_pinned", issue = "125735")] +unsafe impl Sync for UnsafePinned {} + /// When this type is used, that almost certainly means safe APIs need to use pinning to avoid the /// aliases from becoming invalidated. Therefore let's mark this as `!Unpin`. You can always opt /// back in to `Unpin` with an `impl` block, provided your API is still sound while unpinned. #[unstable(feature = "unsafe_pinned", issue = "125735")] impl !Unpin for UnsafePinned {} -/// The type is `Copy` when `T` is to avoid people assuming that `Copy` implies there is no -/// `UnsafePinned` anywhere. (This is an issue with `UnsafeCell`: people use `Copy` bounds to mean -/// `Freeze`.) Given that there is no `unsafe impl Copy for ...`, this is also the option that -/// leaves the user more choices (as they can always wrap this in a `!Copy` type). -// FIXME(unsafe_pinned): this may be unsound or a footgun? -#[unstable(feature = "unsafe_pinned", issue = "125735")] -impl Copy for UnsafePinned {} - -#[unstable(feature = "unsafe_pinned", issue = "125735")] -impl Clone for UnsafePinned { - fn clone(&self) -> Self { - *self - } -} - // `Send` and `Sync` are inherited from `T`. This is similar to `SyncUnsafeCell`, since // we eventually concluded that `UnsafeCell` implicitly making things `!Sync` is sometimes // unergonomic. A type that needs to be `!Send`/`!Sync` should really have an explicit @@ -63,7 +52,7 @@ impl UnsafePinned { #[must_use] #[unstable(feature = "unsafe_pinned", issue = "125735")] pub const fn new(value: T) -> Self { - UnsafePinned { value } + UnsafePinned { value: UnsafeCell::new(value) } } /// Unwraps the value, consuming this `UnsafePinned`. @@ -72,7 +61,7 @@ impl UnsafePinned { #[unstable(feature = "unsafe_pinned", issue = "125735")] #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_inner(self) -> T { - self.value + self.value.into_inner() } } -- cgit 1.4.1-3-g733a5 From 259d6f42179a9e0da3f2db1a088a290124eeb7c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 May 2025 16:44:50 +0200 Subject: add Miri tests --- src/tools/miri/tests/fail/async-shared-mutable.rs | 25 ++++++++++++ .../tests/fail/async-shared-mutable.stack.stderr | 43 ++++++++++++++++++++ .../tests/fail/async-shared-mutable.tree.stderr | 47 ++++++++++++++++++++++ .../miri/tests/pass/both_borrows/unsafe_pinned.rs | 16 ++++++++ 4 files changed, 131 insertions(+) create mode 100644 src/tools/miri/tests/fail/async-shared-mutable.rs create mode 100644 src/tools/miri/tests/fail/async-shared-mutable.stack.stderr create mode 100644 src/tools/miri/tests/fail/async-shared-mutable.tree.stderr create mode 100644 src/tools/miri/tests/pass/both_borrows/unsafe_pinned.rs diff --git a/src/tools/miri/tests/fail/async-shared-mutable.rs b/src/tools/miri/tests/fail/async-shared-mutable.rs new file mode 100644 index 00000000000..62780e7a11c --- /dev/null +++ b/src/tools/miri/tests/fail/async-shared-mutable.rs @@ -0,0 +1,25 @@ +//! FIXME: This test should pass! However, `async fn` does not yet use `UnsafePinned`. +//! This is a regression test for : +//! `UnsafePinned` must include the effects of `UnsafeCell`. +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows +//@normalize-stderr-test: "\[0x[a-fx\d.]+\]" -> "[OFFSET]" + +use core::future::Future; +use core::pin::{Pin, pin}; +use core::task::{Context, Poll, Waker}; + +fn main() { + let mut f = pin!(async move { + let x = &mut 0u8; + core::future::poll_fn(move |_| { + *x = 1; //~ERROR: write access + Poll::<()>::Pending + }) + .await + }); + let mut cx = Context::from_waker(&Waker::noop()); + assert_eq!(f.as_mut().poll(&mut cx), Poll::Pending); + let _: Pin<&_> = f.as_ref(); // Or: `f.as_mut().into_ref()`. + assert_eq!(f.as_mut().poll(&mut cx), Poll::Pending); +} diff --git a/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr b/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr new file mode 100644 index 00000000000..8f53a55cc3e --- /dev/null +++ b/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr @@ -0,0 +1,43 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[OFFSET], but that tag does not exist in the borrow stack for this location + --> tests/fail/async-shared-mutable.rs:LL:CC + | +LL | *x = 1; + | ^^^^^^ + | | + | attempting a write access using at ALLOC[OFFSET], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[OFFSET] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a Unique retag at offsets [OFFSET] + --> tests/fail/async-shared-mutable.rs:LL:CC + | +LL | / core::future::poll_fn(move |_| { +LL | | *x = 1; +LL | | Poll::<()>::Pending +LL | | }) +LL | | .await + | |______________^ +help: was later invalidated at offsets [OFFSET] by a SharedReadOnly retag + --> tests/fail/async-shared-mutable.rs:LL:CC + | +LL | let _: Pin<&_> = f.as_ref(); // Or: `f.as_mut().into_ref()`. + | ^^^^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside closure at tests/fail/async-shared-mutable.rs:LL:CC + = note: inside ` as std::future::Future>::poll` at RUSTLIB/core/src/future/poll_fn.rs:LL:CC +note: inside closure + --> tests/fail/async-shared-mutable.rs:LL:CC + | +LL | .await + | ^^^^^ +note: inside `main` + --> tests/fail/async-shared-mutable.rs:LL:CC + | +LL | assert_eq!(f.as_mut().poll(&mut cx), Poll::Pending); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr new file mode 100644 index 00000000000..d1e66a0d043 --- /dev/null +++ b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr @@ -0,0 +1,47 @@ +error: Undefined Behavior: write access through at ALLOC[OFFSET] is forbidden + --> tests/fail/async-shared-mutable.rs:LL:CC + | +LL | *x = 1; + | ^^^^^^ write access through at ALLOC[OFFSET] is forbidden + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: the accessed tag has state Frozen which forbids this child write access +help: the accessed tag was created here, in the initial state Reserved + --> tests/fail/async-shared-mutable.rs:LL:CC + | +LL | / core::future::poll_fn(move |_| { +LL | | *x = 1; +LL | | Poll::<()>::Pending +LL | | }) +LL | | .await + | |______________^ +help: the accessed tag later transitioned to Active due to a child write access at offsets [OFFSET] + --> tests/fail/async-shared-mutable.rs:LL:CC + | +LL | *x = 1; + | ^^^^^^ + = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference +help: the accessed tag later transitioned to Frozen due to a reborrow (acting as a foreign read access) at offsets [OFFSET] + --> tests/fail/async-shared-mutable.rs:LL:CC + | +LL | let _: Pin<&_> = f.as_ref(); // Or: `f.as_mut().into_ref()`. + | ^^^^^^^^^^ + = help: this transition corresponds to a loss of write permissions + = note: BACKTRACE (of the first span): + = note: inside closure at tests/fail/async-shared-mutable.rs:LL:CC + = note: inside ` as std::future::Future>::poll` at RUSTLIB/core/src/future/poll_fn.rs:LL:CC +note: inside closure + --> tests/fail/async-shared-mutable.rs:LL:CC + | +LL | .await + | ^^^^^ +note: inside `main` + --> tests/fail/async-shared-mutable.rs:LL:CC + | +LL | assert_eq!(f.as_mut().poll(&mut cx), Poll::Pending); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass/both_borrows/unsafe_pinned.rs b/src/tools/miri/tests/pass/both_borrows/unsafe_pinned.rs new file mode 100644 index 00000000000..0c75a07bfa2 --- /dev/null +++ b/src/tools/miri/tests/pass/both_borrows/unsafe_pinned.rs @@ -0,0 +1,16 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows +#![feature(unsafe_pinned)] + +use std::pin::UnsafePinned; + +fn mutate(x: &UnsafePinned) { + let ptr = x as *const _ as *mut i32; + unsafe { ptr.write(42) }; +} + +fn main() { + let x = UnsafePinned::new(0); + mutate(&x); + assert_eq!(x.into_inner(), 42); +} -- cgit 1.4.1-3-g733a5 From 6acbcee97ec4542c0b66c5cf460b8a4358647b4a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 18 May 2025 16:21:33 +0000 Subject: tidy: Skip pal and `#[test]` checks in compiler-builtins --- src/tools/tidy/src/pal.rs | 1 + src/tools/tidy/src/walk.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index c708ff7150c..9b915e0f737 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -36,6 +36,7 @@ use crate::walk::{filter_dirs, walk}; // Paths that may contain platform-specific code. const EXCEPTION_PATHS: &[&str] = &[ + "library/compiler-builtins", "library/windows_targets", "library/panic_abort", "library/panic_unwind", diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs index 08ee5c16c12..c2c9eb8d250 100644 --- a/src/tools/tidy/src/walk.rs +++ b/src/tools/tidy/src/walk.rs @@ -14,6 +14,7 @@ pub fn filter_dirs(path: &Path) -> bool { "compiler/rustc_codegen_gcc", "src/llvm-project", "library/backtrace", + "library/compiler-builtins", "library/portable-simd", "library/stdarch", "src/tools/cargo", -- cgit 1.4.1-3-g733a5 From d655ff0806623fb00ca518eae88655ccbfda76df Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 18 May 2025 17:12:13 +0000 Subject: clif: Provide better output messages for failed copies --- compiler/rustc_codegen_cranelift/build_system/utils.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/build_system/utils.rs b/compiler/rustc_codegen_cranelift/build_system/utils.rs index f2399768459..d9807155a3d 100644 --- a/compiler/rustc_codegen_cranelift/build_system/utils.rs +++ b/compiler/rustc_codegen_cranelift/build_system/utils.rs @@ -213,11 +213,13 @@ pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) { if filename == "." || filename == ".." { continue; } + let src = from.join(&filename); + let dst = to.join(&filename); if entry.metadata().unwrap().is_dir() { - fs::create_dir(to.join(&filename)).unwrap(); - copy_dir_recursively(&from.join(&filename), &to.join(&filename)); + fs::create_dir(&dst).unwrap_or_else(|e| panic!("failed to create {dst:?}: {e}")); + copy_dir_recursively(&src, &dst); } else { - fs::copy(from.join(&filename), to.join(&filename)).unwrap(); + fs::copy(&src, &dst).unwrap_or_else(|e| panic!("failed to copy {src:?}->{dst:?}: {e}")); } } } -- cgit 1.4.1-3-g733a5 From 430f75a8184f3ff7ae44d1f698e45003b5cbaf2e Mon Sep 17 00:00:00 2001 From: vremyavnikuda Date: Wed, 28 May 2025 22:17:29 +0700 Subject: docs:deleting duplicate documentation --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 70 --------------------------- 1 file changed, 70 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 6e35084ceb3..82dbcde4c06 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -514,76 +514,6 @@ impl Analysis { self.with_db(|db| goto_type_definition::goto_type_definition(db, position)) } - /// Find all references to the item at the cursor position. - /// - /// # Examples - /// - /// Basic struct reference search: - /// ```rust - /// struct S { - /// pub x: usize, - /// } - /// - /// fn print_s(s: S) { - /// println!("{}", s.x) - /// } - /// - /// fn main() { - /// let s = S { x: 42 }; // This is a constructor usage - /// print_s(s); // This is a type reference - /// } - /// ``` - /// - /// To find only constructor/initialization usages: - /// 1. Position cursor on special tokens in struct/enum definition: - /// ```rust - /// // On '{' - finds record struct initializations - /// struct Point { // <- cursor here on '{' - /// x: i32, - /// y: i32, - /// } - /// - /// // On '(' - finds tuple struct initializations - /// struct Tuple(i32, i32); // <- cursor here on '(' - /// - /// // On ';' - finds unit struct initializations - /// struct Unit; // <- cursor here on ';' - /// ``` - /// - /// 2. Examples of what will be found: - /// ```rust - /// struct Point{x: i32, y: i32}; - /// struct Tuple(i32, i32); - /// struct Unit; - /// - /// - /// let p1 = Point { x: 0, y: 0 }; // Found when cursor on '{' - /// let p2 = Tuple(1, 2); // Found when cursor on '(' - /// let u = Unit; // Found when cursor on ';' - /// ``` - /// - /// 3. For enum variants: - /// ```rust - /// enum E { - /// Struct { // <- cursor here on '{' - /// x: i32 - /// }, - /// Tuple(i32), // <- cursor here on '(' - /// Unit // <- cursor here on identifier - /// } - /// - /// let e1 = E::Struct { x: 0 }; // Found for Struct variant - /// let e2 = E::Tuple(1); // Found for Tuple variant - /// let e3 = E::Unit; // Found for Unit variant - /// ``` - /// - /// # Parameters - /// * `position` - The position in the file to find references for - /// * `search_scope` - Optional scope to limit the search - /// - /// # Returns - /// Returns a vector of reference search results if references are found, - /// or None if no valid item is found at the position. pub fn find_all_refs( &self, position: FilePosition, -- cgit 1.4.1-3-g733a5 From c04f133858c3208525ae8fe47057fb157c18d606 Mon Sep 17 00:00:00 2001 From: Dario Damiani <154735680+D-Dario0@users.noreply.github.com> Date: Wed, 28 May 2025 20:48:05 +0200 Subject: Typo in README.md Link to Apache License changed from htps:// to https:// --- library/compiler-builtins/libm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 349e892dfcf..77608db3d0d 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -34,7 +34,7 @@ Usage is under the MIT license, available at ### Contribution Contributions are licensed under both the MIT license and the Apache License, -Version 2.0, available at . Unless +Version 2.0, available at . Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as mentioned, without any additional terms or conditions. -- cgit 1.4.1-3-g733a5 From 5978b8b875f6c53af9ca4c72f4ea5fcf74d55c84 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 28 May 2025 21:08:41 +0000 Subject: aarch64: Add a note saying why we use `frintx` rather than `frintn` --- library/compiler-builtins/libm/src/math/arch/aarch64.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64.rs b/library/compiler-builtins/libm/src/math/arch/aarch64.rs index 020bb731cdc..8896804b504 100644 --- a/library/compiler-builtins/libm/src/math/arch/aarch64.rs +++ b/library/compiler-builtins/libm/src/math/arch/aarch64.rs @@ -30,6 +30,12 @@ pub fn fmaf(mut x: f32, y: f32, z: f32) -> f32 { x } +// NB: `frintx` is technically the correct instruction for C's `rint`. However, in Rust (and LLVM +// by default), `rint` is identical to `roundeven` (no fpenv interaction) so we use the +// side-effect-free `frintn`. +// +// In general, C code that calls Rust's libm should assume that fpenv is ignored. + pub fn rint(mut x: f64) -> f64 { // SAFETY: `frintn` is available with neon and has no side effects. // -- cgit 1.4.1-3-g733a5 From 2c9fb22f040094b4cb982c84254bb5d0589c38e8 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Wed, 28 May 2025 21:16:15 +0000 Subject: jsondoclint: Extract `Command`/`CommandKind` into its own file --- src/tools/jsondocck/src/directive.rs | 230 +++++++++++++++++++++++++++++++++++ src/tools/jsondocck/src/main.rs | 225 +--------------------------------- 2 files changed, 233 insertions(+), 222 deletions(-) create mode 100644 src/tools/jsondocck/src/directive.rs diff --git a/src/tools/jsondocck/src/directive.rs b/src/tools/jsondocck/src/directive.rs new file mode 100644 index 00000000000..8617379ed27 --- /dev/null +++ b/src/tools/jsondocck/src/directive.rs @@ -0,0 +1,230 @@ +use std::borrow::Cow; +use serde_json::Value; +use crate::cache::Cache; + +#[derive(Debug)] +pub struct Command { + pub kind: CommandKind, + pub path: String, + pub lineno: usize, +} + +#[derive(Debug)] +pub enum CommandKind { + /// `//@ has ` + /// + /// Checks the path exists. + HasPath, + + /// `//@ has ` + /// + /// Check one thing at the path is equal to the value. + HasValue { value: String }, + + /// `//@ !has ` + /// + /// Checks the path doesn't exist. + HasNotPath, + + /// `//@ !has ` + /// + /// Checks the path exists, but doesn't have the given value. + HasNotValue { value: String }, + + /// `//@ is ` + /// + /// Check the path is the given value. + Is { value: String }, + + /// `//@ is ...` + /// + /// Check that the path matches to exactly every given value. + IsMany { values: Vec }, + + /// `//@ !is ` + /// + /// Check the path isn't the given value. + IsNot { value: String }, + + /// `//@ count ` + /// + /// Check the path has the expected number of matches. + CountIs { expected: usize }, + + /// `//@ set = ` + Set { variable: String }, +} + +impl CommandKind { + /// Returns both the kind and the path. + /// + /// Returns `None` if the command isn't from jsondocck (e.g. from compiletest). + pub fn parse<'a>( + command_name: &str, + negated: bool, + args: &'a [String], + ) -> Option<(Self, &'a str)> { + let kind = match (command_name, negated) { + ("count", false) => { + assert_eq!(args.len(), 2); + let expected = args[1].parse().expect("invalid number for `count`"); + Self::CountIs { expected } + } + + ("ismany", false) => { + // FIXME: Make this >= 3, and migrate len(values)==1 cases to @is + assert!(args.len() >= 2, "Not enough args to `ismany`"); + let values = args[1..].to_owned(); + Self::IsMany { values } + } + + ("is", false) => { + assert_eq!(args.len(), 2); + Self::Is { value: args[1].clone() } + } + ("is", true) => { + assert_eq!(args.len(), 2); + Self::IsNot { value: args[1].clone() } + } + + ("set", false) => { + assert_eq!(args.len(), 3); + assert_eq!(args[1], "="); + return Some((Self::Set { variable: args[0].clone() }, &args[2])); + } + + ("has", false) => match args { + [_path] => Self::HasPath, + [_path, value] => Self::HasValue { value: value.clone() }, + _ => panic!("`//@ has` must have 2 or 3 arguments, but got {args:?}"), + }, + ("has", true) => match args { + [_path] => Self::HasNotPath, + [_path, value] => Self::HasNotValue { value: value.clone() }, + _ => panic!("`//@ !has` must have 2 or 3 arguments, but got {args:?}"), + }, + + (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&command_name) => { + return None; + } + _ => { + panic!("Invalid command `//@ {}{command_name}`", if negated { "!" } else { "" }) + } + }; + + Some((kind, &args[0])) + } +} + +impl Command { + /// Performs the actual work of ensuring a command passes. + pub fn check(&self, cache: &mut Cache) -> Result<(), String> { + let matches = cache.select(&self.path); + match &self.kind { + CommandKind::HasPath => { + if matches.is_empty() { + return Err("matched to no values".to_owned()); + } + } + CommandKind::HasNotPath => { + if !matches.is_empty() { + return Err(format!("matched to {matches:?}, but wanted no matches")); + } + } + CommandKind::HasValue { value } => { + let want_value = string_to_value(value, cache); + if !matches.contains(&want_value.as_ref()) { + return Err(format!( + "matched to {matches:?}, which didn't contain {want_value:?}" + )); + } + } + CommandKind::HasNotValue { value } => { + let wantnt_value = string_to_value(value, cache); + if matches.contains(&wantnt_value.as_ref()) { + return Err(format!( + "matched to {matches:?}, which contains unwanted {wantnt_value:?}" + )); + } else if matches.is_empty() { + return Err(format!( + "got no matches, but expected some matched (not containing {wantnt_value:?}" + )); + } + } + + CommandKind::Is { value } => { + let want_value = string_to_value(value, cache); + let matched = get_one(&matches)?; + if matched != want_value.as_ref() { + return Err(format!("matched to {matched:?} but want {want_value:?}")); + } + } + CommandKind::IsNot { value } => { + let wantnt_value = string_to_value(value, cache); + let matched = get_one(&matches)?; + if matched == wantnt_value.as_ref() { + return Err(format!("got value {wantnt_value:?}, but want anything else")); + } + } + + CommandKind::IsMany { values } => { + // Serde json doesn't implement Ord or Hash for Value, so we must + // use a Vec here. While in theory that makes setwize equality + // O(n^2), in practice n will never be large enough to matter. + let expected_values = + values.iter().map(|v| string_to_value(v, cache)).collect::>(); + if expected_values.len() != matches.len() { + return Err(format!( + "Expected {} values, but matched to {} values ({:?})", + expected_values.len(), + matches.len(), + matches + )); + }; + for got_value in matches { + if !expected_values.iter().any(|exp| &**exp == got_value) { + return Err(format!("has match {got_value:?}, which was not expected",)); + } + } + } + CommandKind::CountIs { expected } => { + if *expected != matches.len() { + return Err(format!( + "matched to `{matches:?}` with length {}, but expected length {expected}", + matches.len(), + )); + } + } + CommandKind::Set { variable } => { + let value = get_one(&matches)?; + let r = cache.variables.insert(variable.to_owned(), value.clone()); + assert!(r.is_none(), "name collision: {variable:?} is duplicated"); + } + } + + Ok(()) + } +} + +fn get_one<'a>(matches: &[&'a Value]) -> Result<&'a Value, String> { + match matches { + [] => Err("matched to no values".to_owned()), + [matched] => Ok(matched), + _ => Err(format!("matched to multiple values {matches:?}, but want exactly 1")), + } +} + +// FIXME: This setup is temporary until we figure out how to improve this situation. +// See . +include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/directive-list.rs")); + +fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> { + if s.starts_with("$") { + Cow::Borrowed(&cache.variables.get(&s[1..]).unwrap_or_else(|| { + // FIXME(adotinthevoid): Show line number + panic!("No variable: `{}`. Current state: `{:?}`", &s[1..], cache.variables) + })) + } else { + Cow::Owned(serde_json::from_str(s).expect(&format!("Cannot convert `{}` to json", s))) + } +} \ No newline at end of file diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 65ad38da98b..80557b68243 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -1,17 +1,17 @@ -use std::borrow::Cow; use std::process::ExitCode; use std::sync::LazyLock; use std::{env, fs}; use regex::{Regex, RegexBuilder}; -use serde_json::Value; mod cache; mod config; +mod directive; mod error; use cache::Cache; use config::parse_config; +use directive::{Command, CommandKind}; use error::CkError; fn main() -> ExitCode { @@ -25,7 +25,7 @@ fn main() -> ExitCode { }; for command in commands { - if let Err(message) = check_command(&command, &mut cache) { + if let Err(message) = command.check( &mut cache) { failed.push(CkError { command, message }); } } @@ -41,116 +41,6 @@ fn main() -> ExitCode { } } -#[derive(Debug)] -pub struct Command { - kind: CommandKind, - path: String, - lineno: usize, -} - -#[derive(Debug)] -enum CommandKind { - /// `//@ has ` - /// - /// Checks the path exists. - HasPath, - - /// `//@ has ` - /// - /// Check one thing at the path is equal to the value. - HasValue { value: String }, - - /// `//@ !has ` - /// - /// Checks the path doesn't exist. - HasNotPath, - - /// `//@ !has ` - /// - /// Checks the path exists, but doesn't have the given value. - HasNotValue { value: String }, - - /// `//@ is ` - /// - /// Check the path is the given value. - Is { value: String }, - - /// `//@ is ...` - /// - /// Check that the path matches to exactly every given value. - IsMany { values: Vec }, - - /// `//@ !is ` - /// - /// Check the path isn't the given value. - IsNot { value: String }, - - /// `//@ count ` - /// - /// Check the path has the expected number of matches. - CountIs { expected: usize }, - - /// `//@ set = ` - Set { variable: String }, -} - -impl CommandKind { - /// Returns both the kind and the path. - /// - /// Returns `None` if the command isn't from jsondocck (e.g. from compiletest). - fn parse<'a>(command_name: &str, negated: bool, args: &'a [String]) -> Option<(Self, &'a str)> { - let kind = match (command_name, negated) { - ("count", false) => { - assert_eq!(args.len(), 2); - let expected = args[1].parse().expect("invalid number for `count`"); - Self::CountIs { expected } - } - - ("ismany", false) => { - // FIXME: Make this >= 3, and migrate len(values)==1 cases to @is - assert!(args.len() >= 2, "Not enough args to `ismany`"); - let values = args[1..].to_owned(); - Self::IsMany { values } - } - - ("is", false) => { - assert_eq!(args.len(), 2); - Self::Is { value: args[1].clone() } - } - ("is", true) => { - assert_eq!(args.len(), 2); - Self::IsNot { value: args[1].clone() } - } - - ("set", false) => { - assert_eq!(args.len(), 3); - assert_eq!(args[1], "="); - return Some((Self::Set { variable: args[0].clone() }, &args[2])); - } - - ("has", false) => match args { - [_path] => Self::HasPath, - [_path, value] => Self::HasValue { value: value.clone() }, - _ => panic!("`//@ has` must have 2 or 3 arguments, but got {args:?}"), - }, - ("has", true) => match args { - [_path] => Self::HasNotPath, - [_path, value] => Self::HasNotValue { value: value.clone() }, - _ => panic!("`//@ !has` must have 2 or 3 arguments, but got {args:?}"), - }, - - (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&command_name) => { - return None; - } - _ => { - panic!("Invalid command `//@ {}{command_name}`", if negated { "!" } else { "" }) - } - }; - - Some((kind, &args[0])) - } -} - static LINE_PATTERN: LazyLock = LazyLock::new(|| { RegexBuilder::new( r#" @@ -183,10 +73,6 @@ fn print_err(msg: &str, lineno: usize) { eprintln!("Invalid command: {} on line {}", msg, lineno) } -// FIXME: This setup is temporary until we figure out how to improve this situation. -// See . -include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/directive-list.rs")); - /// Get a list of commands from a file. fn get_commands(template: &str) -> Result, ()> { let mut commands = Vec::new(); @@ -222,108 +108,3 @@ fn get_commands(template: &str) -> Result, ()> { if !errors { Ok(commands) } else { Err(()) } } - -/// Performs the actual work of ensuring a command passes. -fn check_command(command: &Command, cache: &mut Cache) -> Result<(), String> { - let matches = cache.select(&command.path); - match &command.kind { - CommandKind::HasPath => { - if matches.is_empty() { - return Err("matched to no values".to_owned()); - } - } - CommandKind::HasNotPath => { - if !matches.is_empty() { - return Err(format!("matched to {matches:?}, but wanted no matches")); - } - } - CommandKind::HasValue { value } => { - let want_value = string_to_value(value, cache); - if !matches.contains(&want_value.as_ref()) { - return Err(format!("matched to {matches:?}, which didn't contain {want_value:?}")); - } - } - CommandKind::HasNotValue { value } => { - let wantnt_value = string_to_value(value, cache); - if matches.contains(&wantnt_value.as_ref()) { - return Err(format!( - "matched to {matches:?}, which contains unwanted {wantnt_value:?}" - )); - } else if matches.is_empty() { - return Err(format!( - "got no matches, but expected some matched (not containing {wantnt_value:?}" - )); - } - } - - CommandKind::Is { value } => { - let want_value = string_to_value(value, cache); - let matched = get_one(&matches)?; - if matched != want_value.as_ref() { - return Err(format!("matched to {matched:?} but want {want_value:?}")); - } - } - CommandKind::IsNot { value } => { - let wantnt_value = string_to_value(value, cache); - let matched = get_one(&matches)?; - if matched == wantnt_value.as_ref() { - return Err(format!("got value {wantnt_value:?}, but want anything else")); - } - } - - CommandKind::IsMany { values } => { - // Serde json doesn't implement Ord or Hash for Value, so we must - // use a Vec here. While in theory that makes setwize equality - // O(n^2), in practice n will never be large enough to matter. - let expected_values = - values.iter().map(|v| string_to_value(v, cache)).collect::>(); - if expected_values.len() != matches.len() { - return Err(format!( - "Expected {} values, but matched to {} values ({:?})", - expected_values.len(), - matches.len(), - matches - )); - }; - for got_value in matches { - if !expected_values.iter().any(|exp| &**exp == got_value) { - return Err(format!("has match {got_value:?}, which was not expected",)); - } - } - } - CommandKind::CountIs { expected } => { - if *expected != matches.len() { - return Err(format!( - "matched to `{matches:?}` with length {}, but expected length {expected}", - matches.len(), - )); - } - } - CommandKind::Set { variable } => { - let value = get_one(&matches)?; - let r = cache.variables.insert(variable.to_owned(), value.clone()); - assert!(r.is_none(), "name collision: {variable:?} is duplicated"); - } - } - - Ok(()) -} - -fn get_one<'a>(matches: &[&'a Value]) -> Result<&'a Value, String> { - match matches { - [] => Err("matched to no values".to_owned()), - [matched] => Ok(matched), - _ => Err(format!("matched to multiple values {matches:?}, but want exactly 1")), - } -} - -fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> { - if s.starts_with("$") { - Cow::Borrowed(&cache.variables.get(&s[1..]).unwrap_or_else(|| { - // FIXME(adotinthevoid): Show line number - panic!("No variable: `{}`. Current state: `{:?}`", &s[1..], cache.variables) - })) - } else { - Cow::Owned(serde_json::from_str(s).expect(&format!("Cannot convert `{}` to json", s))) - } -} -- cgit 1.4.1-3-g733a5 From 851aa05aa0addf41507967952f1ac2d183751682 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Apr 2025 09:35:55 +0000 Subject: cleanup: Reuse `MinInt` and `Int` from `libm` in `compiler-builtins` Since the two crates are now in the same repo, it is easier to share code. Begin some deduplication with the integer traits. --- library/compiler-builtins/builtins-test/src/lib.rs | 78 +++++- .../compiler-builtins/src/float/add.rs | 22 +- .../compiler-builtins/src/float/conv.rs | 24 +- .../compiler-builtins/src/float/div.rs | 2 +- .../compiler-builtins/src/float/mul.rs | 2 +- .../compiler-builtins/src/float/traits.rs | 4 +- .../compiler-builtins/src/int/addsub.rs | 6 +- .../compiler-builtins/src/int/big.rs | 4 +- .../compiler-builtins/src/int/leading_zeros.rs | 64 +++-- .../compiler-builtins/src/int/trailing_zeros.rs | 25 +- .../compiler-builtins/src/int/traits.rs | 273 +-------------------- .../libm/src/math/support/int_traits.rs | 9 + 12 files changed, 168 insertions(+), 345 deletions(-) diff --git a/library/compiler-builtins/builtins-test/src/lib.rs b/library/compiler-builtins/builtins-test/src/lib.rs index c596ac21380..f1673133be2 100644 --- a/library/compiler-builtins/builtins-test/src/lib.rs +++ b/library/compiler-builtins/builtins-test/src/lib.rs @@ -40,6 +40,75 @@ pub const N: u32 = if cfg!(target_arch = "x86_64") && !cfg!(debug_assertions) { 10_000 }; +/// Additional constants that determine how the integer gets fuzzed. +trait FuzzInt: MinInt { + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// in `builtins-test`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96, + /// 111,112,119,120,125,126,127]. + const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(Self::BITS); + + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize = { + let log2 = Self::BITS.ilog2() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; +} + +impl FuzzInt for I where I: MinInt {} + +const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v +} + /// Random fuzzing step. When run several times, it results in excellent fuzzing entropy such as: /// 11110101010101011110111110011111 /// 10110101010100001011101011001010 @@ -92,10 +161,9 @@ fn fuzz_step(rng: &mut Xoshiro128StarStar, x: &mut I) { macro_rules! edge_cases { ($I:ident, $case:ident, $inner:block) => { for i0 in 0..$I::FUZZ_NUM { - let mask_lo = (!$I::UnsignedInt::ZERO).wrapping_shr($I::FUZZ_LENGTHS[i0] as u32); + let mask_lo = (!$I::Unsigned::ZERO).wrapping_shr($I::FUZZ_LENGTHS[i0] as u32); for i1 in i0..I::FUZZ_NUM { - let mask_hi = - (!$I::UnsignedInt::ZERO).wrapping_shl($I::FUZZ_LENGTHS[i1 - i0] as u32); + let mask_hi = (!$I::Unsigned::ZERO).wrapping_shl($I::FUZZ_LENGTHS[i1 - i0] as u32); let $case = I::from_unsigned(mask_lo & mask_hi); $inner } @@ -107,7 +175,7 @@ macro_rules! edge_cases { /// edge cases, followed by a more random fuzzer that runs `n` times. pub fn fuzz(n: u32, mut f: F) where - ::UnsignedInt: Int, + ::Unsigned: Int, { // edge case tester. Calls `f` 210 times for u128. // zero gets skipped by the loop @@ -128,7 +196,7 @@ where /// The same as `fuzz`, except `f` has two inputs. pub fn fuzz_2(n: u32, f: F) where - ::UnsignedInt: Int, + ::Unsigned: Int, { // Check cases where the first and second inputs are zero. Both call `f` 210 times for `u128`. edge_cases!(I, case, { diff --git a/library/compiler-builtins/compiler-builtins/src/float/add.rs b/library/compiler-builtins/compiler-builtins/src/float/add.rs index 0426c9cc44f..43e3ae931ff 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/add.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::{CastInto, Int, MinInt}; +use crate::int::{CastFrom, CastInto, Int, MinInt}; /// Returns `a + b` fn add(a: F, b: F) -> F @@ -12,7 +12,7 @@ where let one = F::Int::ONE; let zero = F::Int::ZERO; - let bits = F::BITS.cast(); + let bits: F::Int = F::BITS.cast(); let significand_bits = F::SIG_BITS; let max_exponent = F::EXP_SAT; @@ -115,9 +115,10 @@ where let align = a_exponent.wrapping_sub(b_exponent).cast(); if align != MinInt::ZERO { if align < bits { - let sticky = - F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != MinInt::ZERO); - b_significand = (b_significand >> align.cast()) | sticky; + let sticky = F::Int::from_bool( + b_significand << u32::cast_from(bits.wrapping_sub(align)) != MinInt::ZERO, + ); + b_significand = (b_significand >> u32::cast_from(align)) | sticky; } else { b_significand = one; // sticky; b is known to be non-zero. } @@ -132,8 +133,8 @@ where // If partial cancellation occured, we need to left-shift the result // and adjust the exponent: if a_significand < implicit_bit << 3 { - let shift = - a_significand.leading_zeros() as i32 - (implicit_bit << 3).leading_zeros() as i32; + let shift = a_significand.leading_zeros() as i32 + - (implicit_bit << 3u32).leading_zeros() as i32; a_significand <<= shift; a_exponent -= shift; } @@ -159,9 +160,10 @@ where // Result is denormal before rounding; the exponent is zero and we // need to shift the significand. let shift = (1 - a_exponent).cast(); - let sticky = - F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != MinInt::ZERO); - a_significand = (a_significand >> shift.cast()) | sticky; + let sticky = F::Int::from_bool( + (a_significand << u32::cast_from(bits.wrapping_sub(shift))) != MinInt::ZERO, + ); + a_significand = (a_significand >> u32::cast_from(shift)) | sticky; a_exponent = 0; } diff --git a/library/compiler-builtins/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/compiler-builtins/src/float/conv.rs index f5427a11390..9d732f2cdbc 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/conv.rs @@ -72,7 +72,7 @@ mod int_to_float { F: Float, I: Int, F::Int: CastFrom, - Conv: Fn(I::UnsignedInt) -> F::Int, + Conv: Fn(I::Unsigned) -> F::Int, { let sign_bit = F::Int::cast_from(i >> (I::BITS - 1)) << (F::BITS - 1); F::from_bits(conv(i.unsigned_abs()) | sign_bit) @@ -313,10 +313,10 @@ intrinsics! { fn float_to_unsigned_int(f: F) -> U where F: Float, - U: Int, + U: Int, F::Int: CastInto, F::Int: CastFrom, - F::Int: CastInto, + F::Int: CastInto, u32: CastFrom, { float_to_int_inner::(f.to_bits(), |i: U| i, || U::MAX) @@ -327,8 +327,8 @@ fn float_to_signed_int(f: F) -> I where F: Float, I: Int + Neg, - I::UnsignedInt: Int, - F::Int: CastInto, + I::Unsigned: Int, + F::Int: CastInto, F::Int: CastFrom, u32: CastFrom, { @@ -355,27 +355,27 @@ where I: Int, FnFoo: FnOnce(I) -> I, FnOob: FnOnce() -> I, - I::UnsignedInt: Int, - F::Int: CastInto, + I::Unsigned: Int, + F::Int: CastInto, F::Int: CastFrom, u32: CastFrom, { let int_max_exp = F::EXP_BIAS + I::MAX.ilog2() + 1; - let foobar = F::EXP_BIAS + I::UnsignedInt::BITS - 1; + let foobar = F::EXP_BIAS + I::Unsigned::BITS - 1; if fbits < F::ONE.to_bits() { // < 0 gets rounded to 0 I::ZERO } else if fbits < F::Int::cast_from(int_max_exp) << F::SIG_BITS { // >= 1, < integer max - let m_base = if I::UnsignedInt::BITS >= F::Int::BITS { - I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIG_BITS - 1) + let m_base = if I::Unsigned::BITS >= F::Int::BITS { + I::Unsigned::cast_from(fbits) << (I::BITS - F::SIG_BITS - 1) } else { - I::UnsignedInt::cast_from(fbits >> (F::SIG_BITS - I::BITS + 1)) + I::Unsigned::cast_from(fbits >> (F::SIG_BITS - I::BITS + 1)) }; // Set the implicit 1-bit. - let m: I::UnsignedInt = (I::UnsignedInt::ONE << (I::BITS - 1)) | m_base; + let m: I::Unsigned = (I::Unsigned::ONE << (I::BITS - 1)) | m_base; // Shift based on the exponent and bias. let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIG_BITS); diff --git a/library/compiler-builtins/compiler-builtins/src/float/div.rs b/library/compiler-builtins/compiler-builtins/src/float/div.rs index 5df637c7e0f..3e4f0e20d10 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/div.rs @@ -370,7 +370,7 @@ where let hi_corr: F::Int = corr_uq1 >> hw; // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1 - let mut x_uq0: F::Int = ((F::Int::from(x_uq0_hw) * hi_corr) << 1) + let mut x_uq0: F::Int = ((F::Int::from(x_uq0_hw) * hi_corr) << 1u32) .wrapping_add((F::Int::from(x_uq0_hw) * lo_corr) >> (hw - 1)) // 1 to account for the highest bit of corr_UQ1 can be 1 // 1 to account for possible carry diff --git a/library/compiler-builtins/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/compiler-builtins/src/float/mul.rs index 7f1f19d9bd7..c811f140670 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/mul.rs @@ -143,7 +143,7 @@ where // a zero of the appropriate sign. Mathematically there is no need to // handle this case separately, but we make it a special case to // simplify the shift logic. - let shift = one.wrapping_sub(product_exponent.cast()).cast(); + let shift: u32 = one.wrapping_sub(product_exponent.cast()).cast(); if shift >= bits { return F::from_bits(product_sign); } diff --git a/library/compiler-builtins/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/compiler-builtins/src/float/traits.rs index 8ccaa7bcbd7..a30d20900b1 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/traits.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/traits.rs @@ -20,10 +20,10 @@ pub trait Float: + ops::Rem { /// A uint of the same width as the float - type Int: Int; + type Int: Int; /// A int of the same width as the float - type SignedInt: Int + MinInt; + type SignedInt: Int + MinInt; /// An int capable of containing the exponent bits plus a sign bit. This is signed. type ExpInt: Int; diff --git a/library/compiler-builtins/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/compiler-builtins/src/int/addsub.rs index 1f84e8eb1e1..b2b21fc2c44 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/addsub.rs @@ -22,7 +22,7 @@ impl UAddSub for u128 {} trait AddSub: Int where - ::UnsignedInt: UAddSub, + ::Unsigned: UAddSub, { fn add(self, other: Self) -> Self { Self::from_unsigned(self.unsigned().uadd(other.unsigned())) @@ -37,7 +37,7 @@ impl AddSub for i128 {} trait Addo: AddSub where - ::UnsignedInt: UAddSub, + ::Unsigned: UAddSub, { fn addo(self, other: Self) -> (Self, bool) { let sum = AddSub::add(self, other); @@ -50,7 +50,7 @@ impl Addo for u128 {} trait Subo: AddSub where - ::UnsignedInt: UAddSub, + ::Unsigned: UAddSub, { fn subo(self, other: Self) -> (Self, bool) { let sum = AddSub::sub(self, other); diff --git a/library/compiler-builtins/compiler-builtins/src/int/big.rs b/library/compiler-builtins/compiler-builtins/src/int/big.rs index 1402efb8ed4..8e06009090c 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/big.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/big.rs @@ -45,7 +45,7 @@ impl i256 { impl MinInt for u256 { type OtherSign = i256; - type UnsignedInt = u256; + type Unsigned = u256; const SIGNED: bool = false; const BITS: u32 = 256; @@ -58,7 +58,7 @@ impl MinInt for u256 { impl MinInt for i256 { type OtherSign = u256; - type UnsignedInt = u256; + type Unsigned = u256; const SIGNED: bool = false; const BITS: u32 = 256; diff --git a/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs index 112f4d03613..aa5cb39935a 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs @@ -9,11 +9,14 @@ pub use implementation::{leading_zeros_default, leading_zeros_riscv}; pub(crate) use implementation::{leading_zeros_default, leading_zeros_riscv}; mod implementation { - use crate::int::{CastInto, Int}; + use crate::int::{CastFrom, Int}; /// Returns the number of leading binary zeros in `x`. #[allow(dead_code)] - pub fn leading_zeros_default>(x: T) -> usize { + pub fn leading_zeros_default(x: I) -> usize + where + usize: CastFrom, + { // The basic idea is to test if the higher bits of `x` are zero and bisect the number // of leading zeros. It is possible for all branches of the bisection to use the same // code path by conditionally shifting the higher parts down to let the next bisection @@ -23,44 +26,48 @@ mod implementation { // because it simplifies the final bisection step. let mut x = x; // the number of potential leading zeros - let mut z = T::BITS as usize; + let mut z = I::BITS as usize; // a temporary - let mut t: T; + let mut t: I; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { + const { assert!(I::BITS <= 64) }; + if I::BITS >= 64 { t = x >> 32; - if t != T::ZERO { + if t != I::ZERO { z -= 32; x = t; } } - if T::BITS >= 32 { + if I::BITS >= 32 { t = x >> 16; - if t != T::ZERO { + if t != I::ZERO { z -= 16; x = t; } } - const { assert!(T::BITS >= 16) }; + const { assert!(I::BITS >= 16) }; t = x >> 8; - if t != T::ZERO { + if t != I::ZERO { z -= 8; x = t; } t = x >> 4; - if t != T::ZERO { + if t != I::ZERO { z -= 4; x = t; } t = x >> 2; - if t != T::ZERO { + if t != I::ZERO { z -= 2; x = t; } // the last two bisections are combined into one conditional t = x >> 1; - if t != T::ZERO { z - 2 } else { z - x.cast() } + if t != I::ZERO { + z - 2 + } else { + z - usize::cast_from(x) + } // We could potentially save a few cycles by using the LUT trick from // "https://embeddedgurus.com/state-space/2014/09/ @@ -82,10 +89,13 @@ mod implementation { /// Returns the number of leading binary zeros in `x`. #[allow(dead_code)] - pub fn leading_zeros_riscv>(x: T) -> usize { + pub fn leading_zeros_riscv(x: I) -> usize + where + usize: CastFrom, + { let mut x = x; // the number of potential leading zeros - let mut z = T::BITS; + let mut z = I::BITS; // a temporary let mut t: u32; @@ -97,11 +107,11 @@ mod implementation { // right). If we try to save an instruction by using `x < imm` for each bisection, we // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, // but the immediate will never fit into 12 bits and never save an instruction. - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { + const { assert!(I::BITS <= 64) }; + if I::BITS >= 64 { // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise // `t` is set to 0. - t = ((x >= (T::ONE << 32)) as u32) << 5; + t = ((x >= (I::ONE << 32)) as u32) << 5; // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the // next step to process. x >>= t; @@ -109,27 +119,27 @@ mod implementation { // leading zeros z -= t; } - if T::BITS >= 32 { - t = ((x >= (T::ONE << 16)) as u32) << 4; + if I::BITS >= 32 { + t = ((x >= (I::ONE << 16)) as u32) << 4; x >>= t; z -= t; } - const { assert!(T::BITS >= 16) }; - t = ((x >= (T::ONE << 8)) as u32) << 3; + const { assert!(I::BITS >= 16) }; + t = ((x >= (I::ONE << 8)) as u32) << 3; x >>= t; z -= t; - t = ((x >= (T::ONE << 4)) as u32) << 2; + t = ((x >= (I::ONE << 4)) as u32) << 2; x >>= t; z -= t; - t = ((x >= (T::ONE << 2)) as u32) << 1; + t = ((x >= (I::ONE << 2)) as u32) << 1; x >>= t; z -= t; - t = (x >= (T::ONE << 1)) as u32; + t = (x >= (I::ONE << 1)) as u32; x >>= t; z -= t; // All bits except the LSB are guaranteed to be zero for this final bisection step. // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. - z as usize - x.cast() + z as usize - usize::cast_from(x) } } diff --git a/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs index c45d6b1cfe8..8f63c22c8f7 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs @@ -4,33 +4,38 @@ pub use implementation::trailing_zeros; pub(crate) use implementation::trailing_zeros; mod implementation { - use crate::int::{CastInto, Int}; + use crate::int::{CastFrom, Int}; /// Returns number of trailing binary zeros in `x`. #[allow(dead_code)] - pub fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + pub fn trailing_zeros(x: I) -> usize + where + u32: CastFrom, + u16: CastFrom, + u8: CastFrom, + { let mut x = x; let mut r: u32 = 0; let mut t: u32; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + const { assert!(I::BITS <= 64) }; + if I::BITS >= 64 { + r += ((u32::cast_from(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 x >>= r; // remove 32 zero bits } - if T::BITS >= 32 { - t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 + if I::BITS >= 32 { + t = ((u16::cast_from(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 r += t; x >>= t; // x = [0 - 0xFFFF] + higher garbage bits } - const { assert!(T::BITS >= 16) }; - t = ((CastInto::::cast(x) == 0) as u32) << 3; + const { assert!(I::BITS >= 16) }; + t = ((u8::cast_from(x) == 0) as u32) << 3; x >>= t; // x = [0 - 0xFF] + higher garbage bits r += t; - let mut x: u8 = x.cast(); + let mut x: u8 = x.cast_lossy(); t = (((x & 0x0F) == 0) as u32) << 2; x >>= t; // x = [0 - 0xF] + higher garbage bits diff --git a/library/compiler-builtins/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/compiler-builtins/src/int/traits.rs index 152cb2eee2e..b474df366eb 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/traits.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/traits.rs @@ -1,275 +1,4 @@ -use core::ops; - -/// Minimal integer implementations needed on all integer types, including wide integers. -#[allow(dead_code)] -pub trait MinInt: - Copy - + core::fmt::Debug - + ops::BitOr - + ops::Not - + ops::Shl -{ - /// Type with the same width but other signedness - type OtherSign: MinInt; - /// Unsigned version of Self - type UnsignedInt: MinInt; - - /// If `Self` is a signed integer - const SIGNED: bool; - - /// The bitwidth of the int type - const BITS: u32; - - const ZERO: Self; - const ONE: Self; - const MIN: Self; - const MAX: Self; -} - -/// Trait for some basic operations on integers -#[allow(dead_code)] -pub trait Int: - MinInt - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Shr - + ops::BitXor - + ops::BitAnd -{ - /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing - /// in `builtins-test`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96, - /// 111,112,119,120,125,126,127]. - const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); - - /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. - const FUZZ_NUM: usize = { - let log2 = (::BITS - 1).count_ones() as usize; - if log2 == 3 { - // case for u8 - 6 - } else { - // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate - // boundaries. - 8 + (4 * (log2 - 4)) - } - }; - - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; - fn unsigned_abs(self) -> Self::UnsignedInt; - - fn from_bool(b: bool) -> Self; - - /// Prevents the need for excessive conversions between signed and unsigned - fn logical_shr(self, other: u32) -> Self; - - /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; - - // copied from primitive integers, but put in a trait - fn is_zero(self) -> bool; - fn wrapping_neg(self) -> Self; - fn wrapping_add(self, other: Self) -> Self; - fn wrapping_mul(self, other: Self) -> Self; - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - fn ilog2(self) -> u32; -} - -pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { - let mut v = [0u8; 20]; - v[0] = 0; - v[1] = 1; - v[2] = 2; // important for parity and the iX::MIN case when reversed - let mut i = 3; - - // No need for any more until the byte boundary, because there should be no algorithms - // that are sensitive to anything not next to byte boundaries after 2. We also scale - // in powers of two, which is important to prevent u128 corner tests from getting too - // big. - let mut l = 8; - loop { - if l >= ((bits / 2) as u8) { - break; - } - // get both sides of the byte boundary - v[i] = l - 1; - i += 1; - v[i] = l; - i += 1; - l *= 2; - } - - if bits != 8 { - // add the lower side of the middle boundary - v[i] = ((bits / 2) - 1) as u8; - i += 1; - } - - // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS - // boundary because of algorithms that split the high part up. We reverse the scaling - // as we go to Self::BITS. - let mid = i; - let mut j = 1; - loop { - v[i] = (bits as u8) - (v[mid - j]) - 1; - if j == mid { - break; - } - i += 1; - j += 1; - } - v -} - -macro_rules! int_impl_common { - ($ty:ty) => { - fn from_bool(b: bool) -> Self { - b as $ty - } - - fn logical_shr(self, other: u32) -> Self { - Self::from_unsigned(self.unsigned().wrapping_shr(other)) - } - - fn is_zero(self) -> bool { - self == Self::ZERO - } - - fn wrapping_neg(self) -> Self { - ::wrapping_neg(self) - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn wrapping_shr(self, other: u32) -> Self { - ::wrapping_shr(self, other) - } - - fn rotate_left(self, other: u32) -> Self { - ::rotate_left(self, other) - } - - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - - fn ilog2(self) -> u32 { - ::ilog2(self) - } - }; -} - -macro_rules! int_impl { - ($ity:ty, $uty:ty) => { - impl MinInt for $uty { - type OtherSign = $ity; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $uty { - fn unsigned(self) -> $uty { - self - } - - // It makes writing macros easier if this is implemented for both signed and unsigned - #[allow(clippy::wrong_self_convention)] - fn from_unsigned(me: $uty) -> Self { - me - } - - fn unsigned_abs(self) -> Self { - self - } - - fn abs_diff(self, other: Self) -> Self { - self.abs_diff(other) - } - - int_impl_common!($uty); - } - - impl MinInt for $ity { - type OtherSign = $uty; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $ity { - fn unsigned(self) -> $uty { - self as $uty - } - - fn from_unsigned(me: $uty) -> Self { - me as $ity - } - - fn unsigned_abs(self) -> Self::UnsignedInt { - self.unsigned_abs() - } - - fn abs_diff(self, other: Self) -> $uty { - self.abs_diff(other) - } - - int_impl_common!($ity); - } - }; -} - -int_impl!(isize, usize); -int_impl!(i8, u8); -int_impl!(i16, u16); -int_impl!(i32, u32); -int_impl!(i64, u64); -int_impl!(i128, u128); +pub use crate::support::{Int, MinInt}; /// Trait for integers twice the bit width of another integer. This is implemented for all /// primitives except for `u8`, because there is not a smaller primitive. diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index 3ec1faba170..fa9e06066d7 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -78,6 +78,7 @@ pub trait Int: fn unsigned(self) -> Self::Unsigned; fn from_unsigned(unsigned: Self::Unsigned) -> Self; fn abs(self) -> Self; + fn unsigned_abs(self) -> Self::Unsigned; fn from_bool(b: bool) -> Self; @@ -203,6 +204,10 @@ macro_rules! int_impl { unimplemented!() } + fn unsigned_abs(self) -> Self { + unimplemented!() + } + // It makes writing macros easier if this is implemented for both signed and unsigned #[allow(clippy::wrong_self_convention)] fn from_unsigned(me: $uty) -> Self { @@ -242,6 +247,10 @@ macro_rules! int_impl { self.abs() } + fn unsigned_abs(self) -> Self::Unsigned { + self.unsigned_abs() + } + fn from_unsigned(me: $uty) -> Self { me as $ity } -- cgit 1.4.1-3-g733a5 From 877feef541542972f1bfeefe14624a17f23cef8d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 03:51:43 +0000 Subject: Reuse `libm`'s `Caat` and `CastFrom` in `compiler-builtins` --- .../compiler-builtins/src/float/add.rs | 2 +- .../compiler-builtins/src/float/conv.rs | 6 +-- .../compiler-builtins/src/float/div.rs | 2 +- .../compiler-builtins/src/float/mul.rs | 2 +- .../compiler-builtins/src/float/trunc.rs | 2 +- .../compiler-builtins/src/int/trailing_zeros.rs | 6 +-- .../compiler-builtins/src/int/traits.rs | 43 +--------------------- .../libm/src/math/support/int_traits.rs | 5 +++ 8 files changed, 16 insertions(+), 52 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/float/add.rs b/library/compiler-builtins/compiler-builtins/src/float/add.rs index 43e3ae931ff..0cc362f705b 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/add.rs @@ -168,7 +168,7 @@ where } // Low three bits are round, guard, and sticky. - let a_significand_i32: i32 = a_significand.cast(); + let a_significand_i32: i32 = a_significand.cast_lossy(); let round_guard_sticky: i32 = a_significand_i32 & 0x7; // Shift the significand into place, and mask off the implicit bit. diff --git a/library/compiler-builtins/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/compiler-builtins/src/float/conv.rs index 9d732f2cdbc..75ea7ce0242 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/conv.rs @@ -74,7 +74,7 @@ mod int_to_float { F::Int: CastFrom, Conv: Fn(I::Unsigned) -> F::Int, { - let sign_bit = F::Int::cast_from(i >> (I::BITS - 1)) << (F::BITS - 1); + let sign_bit = F::Int::cast_from_lossy(i >> (I::BITS - 1)) << (F::BITS - 1); F::from_bits(conv(i.unsigned_abs()) | sign_bit) } @@ -166,7 +166,7 @@ mod int_to_float { // Within the upper `F::BITS`, everything except for the signifcand // gets truncated - let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIG_BITS - 1)).cast(); + let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIG_BITS - 1)).cast_lossy(); // The entire rest of `i_m` gets truncated. Zero the upper `F::BITS` then just // check if it is nonzero. @@ -371,7 +371,7 @@ where let m_base = if I::Unsigned::BITS >= F::Int::BITS { I::Unsigned::cast_from(fbits) << (I::BITS - F::SIG_BITS - 1) } else { - I::Unsigned::cast_from(fbits >> (F::SIG_BITS - I::BITS + 1)) + I::Unsigned::cast_from_lossy(fbits >> (F::SIG_BITS - I::BITS + 1)) }; // Set the implicit 1-bit. diff --git a/library/compiler-builtins/compiler-builtins/src/float/div.rs b/library/compiler-builtins/compiler-builtins/src/float/div.rs index 3e4f0e20d10..fc1fc085105 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/div.rs @@ -482,7 +482,7 @@ where let ret = quotient.wrapping_shr(u32::cast_from(res_exponent.wrapping_neg()) + 1); residual_lo = a_significand - .wrapping_shl(significand_bits.wrapping_add(CastInto::::cast(res_exponent))) + .wrapping_shl(significand_bits.wrapping_add(CastInto::::cast_lossy(res_exponent))) .wrapping_sub(ret.wrapping_mul(b_significand) << 1); ret }; diff --git a/library/compiler-builtins/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/compiler-builtins/src/float/mul.rs index c811f140670..dbed3095cda 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/mul.rs @@ -143,7 +143,7 @@ where // a zero of the appropriate sign. Mathematically there is no need to // handle this case separately, but we make it a special case to // simplify the shift logic. - let shift: u32 = one.wrapping_sub(product_exponent.cast()).cast(); + let shift: u32 = one.wrapping_sub(product_exponent.cast_lossy()).cast(); if shift >= bits { return F::from_bits(product_sign); } diff --git a/library/compiler-builtins/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs index ca8a0f368b5..93db5d8bbde 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs @@ -50,7 +50,7 @@ where // The exponent of a is within the range of normal numbers in the // destination format. We can convert by simply right-shifting with // rounding and adjusting the exponent. - abs_result = (a_abs >> sig_bits_delta).cast(); + abs_result = (a_abs >> sig_bits_delta).cast_lossy(); // Cast before shifting to prevent overflow. let bias_diff: R::Int = src_exp_bias.wrapping_sub(dst_exp_bias).cast(); let tmp = bias_diff << R::SIG_BITS; diff --git a/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs index 8f63c22c8f7..1b0ae5b73ad 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs @@ -20,18 +20,18 @@ mod implementation { const { assert!(I::BITS <= 64) }; if I::BITS >= 64 { - r += ((u32::cast_from(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + r += ((u32::cast_from_lossy(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 x >>= r; // remove 32 zero bits } if I::BITS >= 32 { - t = ((u16::cast_from(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 + t = ((u16::cast_from_lossy(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 r += t; x >>= t; // x = [0 - 0xFFFF] + higher garbage bits } const { assert!(I::BITS >= 16) }; - t = ((u8::cast_from(x) == 0) as u32) << 3; + t = ((u8::cast_from_lossy(x) == 0) as u32) << 3; x >>= t; // x = [0 - 0xFF] + higher garbage bits r += t; diff --git a/library/compiler-builtins/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/compiler-builtins/src/int/traits.rs index b474df366eb..25b9718ad53 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/traits.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/traits.rs @@ -1,4 +1,4 @@ -pub use crate::support::{Int, MinInt}; +pub use crate::support::{CastFrom, CastInto, Int, MinInt}; /// Trait for integers twice the bit width of another integer. This is implemented for all /// primitives except for `u8`, because there is not a smaller primitive. @@ -97,44 +97,3 @@ impl_h_int!( i32 u32 i64, i64 u64 i128 ); - -/// Trait to express (possibly lossy) casting of integers -pub trait CastInto: Copy { - fn cast(self) -> T; -} - -pub trait CastFrom: Copy { - fn cast_from(value: T) -> Self; -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - self as $into - } - } - )*}; -} - -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index fa9e06066d7..716af748a9f 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -374,14 +374,19 @@ impl_h_int!( /// Trait to express (possibly lossy) casting of integers pub trait CastInto: Copy { /// By default, casts should be exact. + #[track_caller] fn cast(self) -> T; /// Call for casts that are expected to truncate. + /// + /// In practice, this is exactly the same as `cast`; the main difference is to document intent + /// in code. `cast` may panic in debug mode. fn cast_lossy(self) -> T; } pub trait CastFrom: Copy { /// By default, casts should be exact. + #[track_caller] fn cast_from(value: T) -> Self; /// Call for casts that are expected to truncate. -- cgit 1.4.1-3-g733a5 From d2bc36821f103cc33a668abc9e49f8e7e9d943de Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 28 May 2025 14:24:02 +0200 Subject: fix: Recognize salsa cycles in `thread_result_to_response` --- .../rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs index f04ada38893..40d05567fcc 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs @@ -6,7 +6,7 @@ use std::{ use ide_db::base_db::{ DbPanicContext, - salsa::{self, Cancelled}, + salsa::{self, Cancelled, UnexpectedCycle}, }; use lsp_server::{ExtractError, Response, ResponseError}; use serde::{Serialize, de::DeserializeOwned}; @@ -349,11 +349,14 @@ where let mut message = "request handler panicked".to_owned(); if let Some(panic_message) = panic_message { message.push_str(": "); - message.push_str(panic_message) + message.push_str(panic_message); + } else if let Some(cycle) = panic.downcast_ref::() { + tracing::error!("{cycle}"); + message.push_str(": unexpected cycle"); } else if let Ok(cancelled) = panic.downcast::() { tracing::error!("Cancellation propagated out of salsa! This is a bug"); return Err(HandlerCancelledError::Inner(*cancelled)); - } + }; Ok(lsp_server::Response::new_err( id, -- cgit 1.4.1-3-g733a5 From 087cfe3c9f31b50f120d662c767ad85748192595 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 28 May 2025 14:24:02 +0200 Subject: fix: Fix import insertion not being fully cfg aware --- .../crates/ide-assists/src/handlers/auto_import.rs | 38 ++++-- .../src/handlers/convert_bool_to_enum.rs | 8 +- .../convert_named_struct_to_tuple_struct.rs | 3 +- .../convert_tuple_struct_to_named_struct.rs | 3 +- .../ide-assists/src/handlers/extract_function.rs | 7 +- .../handlers/replace_qualified_name_with_use.rs | 6 +- .../src/handlers/unqualify_method_call.rs | 7 +- .../crates/ide-db/src/imports/insert_use.rs | 144 +++++++++------------ .../crates/ide-db/src/imports/insert_use/tests.rs | 101 +++++++++++++-- .../crates/ide-db/src/source_change.rs | 12 ++ .../src/handlers/json_is_not_rust.rs | 6 +- src/tools/rust-analyzer/crates/syntax/src/ted.rs | 7 + 12 files changed, 214 insertions(+), 128 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs index d310e11011b..f3243d369a0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs @@ -128,11 +128,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< format!("Import `{import_name}`"), range, |builder| { - let scope = match scope.clone() { - ImportScope::File(it) => ImportScope::File(builder.make_mut(it)), - ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), - ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)), - }; + let scope = builder.make_import_scope_mut(scope.clone()); insert_use(&scope, mod_path_to_ast(&import_path, edition), &ctx.config.insert_use); }, ); @@ -153,11 +149,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< format!("Import `{import_name} as _`"), range, |builder| { - let scope = match scope.clone() { - ImportScope::File(it) => ImportScope::File(builder.make_mut(it)), - ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), - ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)), - }; + let scope = builder.make_import_scope_mut(scope.clone()); insert_use_as_alias( &scope, mod_path_to_ast(&import_path, edition), @@ -1877,4 +1869,30 @@ fn main() { ", ); } + + #[test] + fn carries_cfg_attr() { + check_assist( + auto_import, + r#" +mod m { + pub struct S; +} + +#[cfg(test)] +fn foo(_: S$0) {} +"#, + r#" +#[cfg(test)] +use m::S; + +mod m { + pub struct S; +} + +#[cfg(test)] +fn foo(_: S) {} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs index 00e9fdf124d..f73b8c4fd0f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs @@ -312,12 +312,8 @@ fn replace_usages( } // add imports across modules where needed - if let Some((import_scope, path)) = import_data { - let scope = match import_scope { - ImportScope::File(it) => ImportScope::File(edit.make_mut(it)), - ImportScope::Module(it) => ImportScope::Module(edit.make_mut(it)), - ImportScope::Block(it) => ImportScope::Block(edit.make_mut(it)), - }; + if let Some((scope, path)) = import_data { + let scope = edit.make_import_scope_mut(scope); delayed_mutations.push((scope, path)); } }, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs index ed8aad7b2c6..5d75e445861 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs @@ -996,7 +996,8 @@ pub struct $0Foo { } "#, r#" -pub struct Foo(#[my_custom_attr] u32); +pub struct Foo(#[my_custom_attr] +u32); "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index 777e366da95..0c0b93bcfbc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -923,7 +923,8 @@ where pub struct $0Foo(#[my_custom_attr] u32); "#, r#" -pub struct Foo { #[my_custom_attr] field1: u32 } +pub struct Foo { #[my_custom_attr] +field1: u32 } "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index e977798c4fd..cf45ea0a30d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -204,12 +204,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op .kind .is_some_and(|kind| matches!(kind, FlowKind::Break(_, _) | FlowKind::Continue(_))) { - let scope = match scope { - ImportScope::File(it) => ImportScope::File(builder.make_mut(it)), - ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), - ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)), - }; - + let scope = builder.make_import_scope_mut(scope); let control_flow_enum = FamousDefs(&ctx.sema, module.krate()).core_ops_ControlFlow(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs index c067747bc1b..fa005a411d3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs @@ -81,11 +81,7 @@ pub(crate) fn replace_qualified_name_with_use( |builder| { // Now that we've brought the name into scope, re-qualify all paths that could be // affected (that is, all paths inside the node we added the `use` to). - let scope = match scope { - ImportScope::File(it) => ImportScope::File(builder.make_mut(it)), - ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), - ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)), - }; + let scope = builder.make_import_scope_mut(scope); shorten_paths(scope.as_syntax_node(), &original_path); let path = drop_generic_args(&original_path); let edition = ctx diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs index ebb8ef99100..1f89a3d5f17 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs @@ -1,4 +1,3 @@ -use ide_db::imports::insert_use::ImportScope; use syntax::{ TextRange, ast::{self, AstNode, HasArgList, prec::ExprPrecedence}, @@ -114,11 +113,7 @@ fn add_import( ); if let Some(scope) = scope { - let scope = match scope { - ImportScope::File(it) => ImportScope::File(edit.make_mut(it)), - ImportScope::Module(it) => ImportScope::Module(edit.make_mut(it)), - ImportScope::Block(it) => ImportScope::Block(edit.make_mut(it)), - }; + let scope = edit.make_import_scope_mut(scope); ide_db::imports::insert_use::insert_use(&scope, import, &ctx.config.insert_use); } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs index d26e5d62ced..813f38380f6 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs @@ -60,107 +60,87 @@ pub struct InsertUseConfig { } #[derive(Debug, Clone)] -pub enum ImportScope { +pub struct ImportScope { + pub kind: ImportScopeKind, + pub required_cfgs: Vec, +} + +#[derive(Debug, Clone)] +pub enum ImportScopeKind { File(ast::SourceFile), Module(ast::ItemList), Block(ast::StmtList), } impl ImportScope { - // FIXME: Remove this? - #[cfg(test)] - fn from(syntax: SyntaxNode) -> Option { - use syntax::match_ast; - fn contains_cfg_attr(attrs: &dyn HasAttrs) -> bool { - attrs.attrs().any(|attr| attr.as_simple_call().is_some_and(|(ident, _)| ident == "cfg")) - } - match_ast! { - match syntax { - ast::Module(module) => module.item_list().map(ImportScope::Module), - ast::SourceFile(file) => Some(ImportScope::File(file)), - ast::Fn(func) => contains_cfg_attr(&func).then(|| func.body().and_then(|it| it.stmt_list().map(ImportScope::Block))).flatten(), - ast::Const(konst) => contains_cfg_attr(&konst).then(|| match konst.body()? { - ast::Expr::BlockExpr(block) => Some(block), - _ => None, - }).flatten().and_then(|it| it.stmt_list().map(ImportScope::Block)), - ast::Static(statik) => contains_cfg_attr(&statik).then(|| match statik.body()? { - ast::Expr::BlockExpr(block) => Some(block), - _ => None, - }).flatten().and_then(|it| it.stmt_list().map(ImportScope::Block)), - _ => None, - - } - } - } - /// Determines the containing syntax node in which to insert a `use` statement affecting `position`. /// Returns the original source node inside attributes. pub fn find_insert_use_container( position: &SyntaxNode, sema: &Semantics<'_, RootDatabase>, ) -> Option { - fn contains_cfg_attr(attrs: &dyn HasAttrs) -> bool { - attrs.attrs().any(|attr| attr.as_simple_call().is_some_and(|(ident, _)| ident == "cfg")) - } - + // The closest block expression ancestor + let mut block = None; + let mut required_cfgs = Vec::new(); // Walk up the ancestor tree searching for a suitable node to do insertions on // with special handling on cfg-gated items, in which case we want to insert imports locally // or FIXME: annotate inserted imports with the same cfg for syntax in sema.ancestors_with_macros(position.clone()) { if let Some(file) = ast::SourceFile::cast(syntax.clone()) { - return Some(ImportScope::File(file)); - } else if let Some(item) = ast::Item::cast(syntax) { - return match item { - ast::Item::Const(konst) if contains_cfg_attr(&konst) => { - // FIXME: Instead of bailing out with None, we should note down that - // this import needs an attribute added - match sema.original_ast_node(konst)?.body()? { - ast::Expr::BlockExpr(block) => block, - _ => return None, + return Some(ImportScope { kind: ImportScopeKind::File(file), required_cfgs }); + } else if let Some(module) = ast::Module::cast(syntax.clone()) { + // early return is important here, if we can't find the original module + // in the input there is no way for us to insert an import anywhere. + return sema + .original_ast_node(module)? + .item_list() + .map(ImportScopeKind::Module) + .map(|kind| ImportScope { kind, required_cfgs }); + } else if let Some(has_attrs) = ast::AnyHasAttrs::cast(syntax) { + if block.is_none() { + if let Some(b) = ast::BlockExpr::cast(has_attrs.syntax().clone()) { + if let Some(b) = sema.original_ast_node(b) { + block = b.stmt_list(); } - .stmt_list() - .map(ImportScope::Block) } - ast::Item::Fn(func) if contains_cfg_attr(&func) => { - // FIXME: Instead of bailing out with None, we should note down that - // this import needs an attribute added - sema.original_ast_node(func)?.body()?.stmt_list().map(ImportScope::Block) - } - ast::Item::Static(statik) if contains_cfg_attr(&statik) => { - // FIXME: Instead of bailing out with None, we should note down that - // this import needs an attribute added - match sema.original_ast_node(statik)?.body()? { - ast::Expr::BlockExpr(block) => block, - _ => return None, - } - .stmt_list() - .map(ImportScope::Block) - } - ast::Item::Module(module) => { - // early return is important here, if we can't find the original module - // in the input there is no way for us to insert an import anywhere. - sema.original_ast_node(module)?.item_list().map(ImportScope::Module) + } + if has_attrs + .attrs() + .any(|attr| attr.as_simple_call().is_some_and(|(ident, _)| ident == "cfg")) + { + if let Some(b) = block { + return Some(ImportScope { + kind: ImportScopeKind::Block(b), + required_cfgs, + }); } - _ => continue, - }; + required_cfgs.extend(has_attrs.attrs().filter(|attr| { + attr.as_simple_call().is_some_and(|(ident, _)| ident == "cfg") + })); + } } } None } pub fn as_syntax_node(&self) -> &SyntaxNode { - match self { - ImportScope::File(file) => file.syntax(), - ImportScope::Module(item_list) => item_list.syntax(), - ImportScope::Block(block) => block.syntax(), + match &self.kind { + ImportScopeKind::File(file) => file.syntax(), + ImportScopeKind::Module(item_list) => item_list.syntax(), + ImportScopeKind::Block(block) => block.syntax(), } } pub fn clone_for_update(&self) -> Self { - match self { - ImportScope::File(file) => ImportScope::File(file.clone_for_update()), - ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()), - ImportScope::Block(block) => ImportScope::Block(block.clone_for_update()), + Self { + kind: match &self.kind { + ImportScopeKind::File(file) => ImportScopeKind::File(file.clone_for_update()), + ImportScopeKind::Module(item_list) => { + ImportScopeKind::Module(item_list.clone_for_update()) + } + ImportScopeKind::Block(block) => ImportScopeKind::Block(block.clone_for_update()), + }, + required_cfgs: self.required_cfgs.iter().map(|attr| attr.clone_for_update()).collect(), } } } @@ -216,6 +196,11 @@ fn insert_use_with_alias_option( use_tree.wrap_in_tree_list(); } let use_item = make::use_(None, use_tree).clone_for_update(); + for attr in + scope.required_cfgs.iter().map(|attr| attr.syntax().clone_subtree().clone_for_update()) + { + ted::insert(ted::Position::first_child_of(use_item.syntax()), attr); + } // merge into existing imports if possible if let Some(mb) = mb { @@ -229,7 +214,6 @@ fn insert_use_with_alias_option( } } } - // either we weren't allowed to merge or there is no import that fits the merge conditions // so look for the place we have to insert to insert_use_(scope, use_item, cfg.group); @@ -316,10 +300,10 @@ fn guess_granularity_from_scope(scope: &ImportScope) -> ImportGranularityGuess { } _ => None, }; - let mut use_stmts = match scope { - ImportScope::File(f) => f.items(), - ImportScope::Module(m) => m.items(), - ImportScope::Block(b) => b.items(), + let mut use_stmts = match &scope.kind { + ImportScopeKind::File(f) => f.items(), + ImportScopeKind::Module(m) => m.items(), + ImportScopeKind::Block(b) => b.items(), } .filter_map(use_stmt); let mut res = ImportGranularityGuess::Unknown; @@ -463,12 +447,12 @@ fn insert_use_(scope: &ImportScope, use_item: ast::Use, group_imports: bool) { } } - let l_curly = match scope { - ImportScope::File(_) => None, + let l_curly = match &scope.kind { + ImportScopeKind::File(_) => None, // don't insert the imports before the item list/block expr's opening curly brace - ImportScope::Module(item_list) => item_list.l_curly_token(), + ImportScopeKind::Module(item_list) => item_list.l_curly_token(), // don't insert the imports before the item list's opening curly brace - ImportScope::Block(block) => block.l_curly_token(), + ImportScopeKind::Block(block) => block.l_curly_token(), }; // there are no imports in this file at all // so put the import after all inner module attributes and possible license header comments diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs index 428ba1d5118..4a00854f01a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs @@ -23,7 +23,7 @@ struct Struct; } #[test] -fn respects_cfg_attr_fn() { +fn respects_cfg_attr_fn_body() { check( r"bar::Bar", r#" @@ -40,6 +40,25 @@ fn foo() { ); } +#[test] +fn respects_cfg_attr_fn_sig() { + check( + r"bar::Bar", + r#" +#[cfg(test)] +fn foo($0) {} +"#, + r#" +#[cfg(test)] +use bar::Bar; + +#[cfg(test)] +fn foo() {} +"#, + ImportGranularity::Crate, + ); +} + #[test] fn respects_cfg_attr_const() { check( @@ -58,6 +77,51 @@ const FOO: Bar = { ); } +#[test] +fn respects_cfg_attr_impl() { + check( + r"bar::Bar", + r#" +#[cfg(test)] +impl () {$0} +"#, + r#" +#[cfg(test)] +use bar::Bar; + +#[cfg(test)] +impl () {} +"#, + ImportGranularity::Crate, + ); +} + +#[test] +fn respects_cfg_attr_multiple_layers() { + check( + r"bar::Bar", + r#" +#[cfg(test)] +impl () { + #[cfg(test2)] + fn f($0) {} +} +"#, + r#" +#[cfg(test)] +#[cfg(test2)] +use bar::Bar; + +#[cfg(test)] +impl () { + #[cfg(test2)] + fn f() {} +} +"#, + ImportGranularity::Crate, + ); +} + #[test] fn insert_skips_lone_glob_imports() { check( @@ -813,7 +877,7 @@ use {std::io};", } #[test] -fn merge_groups_skip_attributed() { +fn merge_groups_cfg_vs_no_cfg() { check_crate( "std::io", r#" @@ -836,6 +900,25 @@ use {std::io}; ); } +#[test] +fn merge_groups_cfg_matching() { + check_crate( + "std::io", + r#" +#[cfg(feature = "gated")] use std::fmt::{Result, Display}; + +#[cfg(feature = "gated")] +fn f($0) {} +"#, + r#" +#[cfg(feature = "gated")] use std::{fmt::{Display, Result}, io}; + +#[cfg(feature = "gated")] +fn f() {} +"#, + ); +} + #[test] fn split_out_merge() { // FIXME: This is suboptimal, we want to get `use std::fmt::{self, Result}` @@ -1259,12 +1342,14 @@ fn check_with_config( }; let sema = &Semantics::new(&db); let source_file = sema.parse(file_id); - let syntax = source_file.syntax().clone_for_update(); let file = pos - .and_then(|pos| syntax.token_at_offset(pos.expect_offset()).next()?.parent()) + .and_then(|pos| source_file.syntax().token_at_offset(pos.expect_offset()).next()?.parent()) .and_then(|it| ImportScope::find_insert_use_container(&it, sema)) - .or_else(|| ImportScope::from(syntax)) - .unwrap(); + .unwrap_or_else(|| ImportScope { + kind: ImportScopeKind::File(source_file), + required_cfgs: vec![], + }) + .clone_for_update(); let path = ast::SourceFile::parse(&format!("use {path};"), span::Edition::CURRENT) .tree() .syntax() @@ -1349,7 +1434,7 @@ fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior } fn check_guess(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: ImportGranularityGuess) { - let syntax = ast::SourceFile::parse(ra_fixture, span::Edition::CURRENT).tree().syntax().clone(); - let file = ImportScope::from(syntax).unwrap(); + let syntax = ast::SourceFile::parse(ra_fixture, span::Edition::CURRENT).tree(); + let file = ImportScope { kind: ImportScopeKind::File(syntax), required_cfgs: vec![] }; assert_eq!(super::guess_granularity_from_scope(&file), expected); } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs index b1b58d6568c..16c0d8d97a7 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs @@ -5,6 +5,7 @@ use std::{collections::hash_map::Entry, fmt, iter, mem}; +use crate::imports::insert_use::{ImportScope, ImportScopeKind}; use crate::text_edit::{TextEdit, TextEditBuilder}; use crate::{SnippetCap, assists::Command, syntax_helpers::tree_diff::diff}; use base_db::AnchoredPathBuf; @@ -367,6 +368,17 @@ impl SourceChangeBuilder { pub fn make_mut(&mut self, node: N) -> N { self.mutated_tree.get_or_insert_with(|| TreeMutator::new(node.syntax())).make_mut(&node) } + + pub fn make_import_scope_mut(&mut self, scope: ImportScope) -> ImportScope { + ImportScope { + kind: match scope.kind.clone() { + ImportScopeKind::File(it) => ImportScopeKind::File(self.make_mut(it)), + ImportScopeKind::Module(it) => ImportScopeKind::Module(self.make_mut(it)), + ImportScopeKind::Block(it) => ImportScopeKind::Block(self.make_mut(it)), + }, + required_cfgs: scope.required_cfgs.iter().map(|it| self.make_mut(it.clone())).collect(), + } + } /// Returns a copy of the `node`, suitable for mutation. /// /// Syntax trees in rust-analyzer are typically immutable, and mutating diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index ac1b599c49e..87c9397fb77 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -137,11 +137,7 @@ pub(crate) fn json_in_items( ) .with_fixes(Some(vec![{ let mut scb = SourceChangeBuilder::new(vfs_file_id); - let scope = match import_scope { - ImportScope::File(it) => ImportScope::File(scb.make_mut(it)), - ImportScope::Module(it) => ImportScope::Module(scb.make_mut(it)), - ImportScope::Block(it) => ImportScope::Block(scb.make_mut(it)), - }; + let scope = scb.make_import_scope_mut(import_scope); let current_module = semantics_scope.module(); let cfg = ImportPathConfig { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ted.rs b/src/tools/rust-analyzer/crates/syntax/src/ted.rs index 64d5ea084c1..ad1d91bb0b2 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ted.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ted.rs @@ -207,5 +207,12 @@ fn ws_between(left: &SyntaxElement, right: &SyntaxElement) -> Option Date: Thu, 20 Feb 2025 05:46:52 +0000 Subject: Remove `i128` and `u128` from `improper_ctypes_definitions` Rust's 128-bit integers have historically been incompatible with C [1]. However, there have been a number of changes in Rust and LLVM that mean this is no longer the case: * Incorrect alignment of `i128` on x86 [1]: adjusting Rust's alignment proposed at https://github.com/rust-lang/compiler-team/issues/683, implemented at https://github.com/rust-lang/rust/pull/116672. * LLVM version of the above: resolved in LLVM, including ABI fix. Present in LLVM18 (our minimum supported version). * Incorrect alignment of `i128` on 64-bit PowerPC, SPARC, and MIPS [2]: Rust's data layouts adjusted at https://github.com/rust-lang/rust/pull/132422, https://github.com/rust-lang/rust/pull/132741, https://github.com/rust-lang/rust/pull/134115. * LLVM version of the above: done in LLVM 20 https://github.com/llvm/llvm-project/issues/102783. * Incorrect return convention of `i128` on Windows: adjusted to match GCC and Clang at https://github.com/rust-lang/rust/pull/134290. At [3], the lang team considered it acceptable to remove `i128` from `improper_ctypes_definitions` if the LLVM version is known to be compatible. Time has elapsed since then and we have dropped support for LLVM versions that do not have the x86 fixes, meaning a per-llvm-version lint should no longer be necessary. The PowerPC, SPARC, and MIPS changes only came in LLVM 20 but since Rust's datalayouts have also been updated to match, we will be using the correct alignment regardless of LLVM version. `repr(i128)` was added to this lint in [4], but is also removed here. Part of the decision is that `i128` should match `__int128` in C on platforms that provide it, which documentation is updated to indicate. We will not guarantee that `i128` matches `_BitInt(128)` since that can be different from `__int128`. Some platforms (usually 32-bit) do not provide `__int128`; if any ABIs are extended in the future to define it, we will need to make sure that our ABI matches. Closes: https://github.com/rust-lang/rust/issues/134288 Closes: https://github.com/rust-lang/rust/issues/128950 [1]: https://github.com/rust-lang/rust/issues/54341 [2]: https://github.com/rust-lang/rust/issues/128950 [3]: https://github.com/rust-lang/lang-team/issues/255#issuecomment-2088855084 [4]: https://github.com/rust-lang/rust/pull/138282 --- compiler/rustc_lint/messages.ftl | 2 - compiler/rustc_lint/src/types.rs | 16 +---- library/core/src/primitive_docs.rs | 14 ++++ tests/ui/asm/naked-functions-ffi.rs | 1 - tests/ui/asm/naked-functions-ffi.stderr | 10 +-- tests/ui/lint/lint-ctypes-enum.rs | 10 +-- tests/ui/lint/lint-ctypes-enum.stderr | 112 ++++++-------------------------- tests/ui/lint/lint-ctypes-fn.rs | 15 ++--- tests/ui/lint/lint-ctypes-fn.stderr | 48 ++++---------- tests/ui/lint/lint-ctypes.rs | 12 ++-- tests/ui/lint/lint-ctypes.stderr | 70 +++++--------------- 11 files changed, 75 insertions(+), 235 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 6913fa3e60b..c39ea4b04a3 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -374,8 +374,6 @@ lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe .label = not FFI-safe .note = the type is defined here -lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stable ABI - lint_improper_ctypes_array_help = consider passing a pointer to the array lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index af134622d38..441ff02d579 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,9 +1,7 @@ use std::iter; use std::ops::ControlFlow; -use rustc_abi::{ - BackendRepr, Integer, IntegerType, TagEncoding, VariantIdx, Variants, WrappingRange, -}; +use rustc_abi::{BackendRepr, TagEncoding, VariantIdx, Variants, WrappingRange}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::DiagMessage; use rustc_hir::intravisit::VisitorExt; @@ -1284,14 +1282,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } - if let Some(IntegerType::Fixed(Integer::I128, _)) = def.repr().int { - return FfiUnsafe { - ty, - reason: fluent::lint_improper_ctypes_128bit, - help: None, - }; - } - use improper_ctypes::check_non_exhaustive_variant; let non_exhaustive = def.variant_list_has_applicable_non_exhaustive(); @@ -1324,10 +1314,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // but only the base type is relevant for being representable in FFI. ty::Pat(base, ..) => self.check_type_for_ffi(acc, base), - ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => { - FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None } - } - // Primitive types with a stable representation. ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe, diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 17c4b488361..5be0e683538 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1428,6 +1428,18 @@ mod prim_i64 {} #[rustc_doc_primitive = "i128"] // /// The 128-bit signed integer type. +/// +/// # ABI compatibility +/// +/// Rust's `i128` is expected to be ABI-compatible with C's `__int128` on platforms where the type +/// is available, which includes most 64-bit architectures. If any platforms that do not specify +/// `__int128` are updated to introduce it, the Rust `i128` ABI on relevant targets will be changed +/// to match. +/// +/// It is important to note that in C, `__int128` is _not_ the same as `_BitInt(128)`, and the two +/// types are allowed to have different ABIs. In particular, on x86, `__int128` and `_BitInt(128)` +/// do not use the same alignment. `i128` is intended to always match `__int128` and does not +/// attempt to match `_BitInt(128)` on platforms without `__int128`. #[stable(feature = "i128", since = "1.26.0")] mod prim_i128 {} @@ -1458,6 +1470,8 @@ mod prim_u64 {} #[rustc_doc_primitive = "u128"] // /// The 128-bit unsigned integer type. +/// +/// Please see [the documentation for `i128`](prim@i128) for information on ABI compatibility. #[stable(feature = "i128", since = "1.26.0")] mod prim_u128 {} diff --git a/tests/ui/asm/naked-functions-ffi.rs b/tests/ui/asm/naked-functions-ffi.rs index 565c440022d..4ba5ccc57f6 100644 --- a/tests/ui/asm/naked-functions-ffi.rs +++ b/tests/ui/asm/naked-functions-ffi.rs @@ -7,6 +7,5 @@ use std::arch::naked_asm; #[unsafe(naked)] pub extern "C" fn naked(p: char) -> u128 { //~^ WARN uses type `char` - //~| WARN uses type `u128` naked_asm!("") } diff --git a/tests/ui/asm/naked-functions-ffi.stderr b/tests/ui/asm/naked-functions-ffi.stderr index 9df6185498e..f7893a3b8de 100644 --- a/tests/ui/asm/naked-functions-ffi.stderr +++ b/tests/ui/asm/naked-functions-ffi.stderr @@ -8,13 +8,5 @@ LL | pub extern "C" fn naked(p: char) -> u128 { = note: the `char` type has no C equivalent = note: `#[warn(improper_ctypes_definitions)]` on by default -warning: `extern` fn uses type `u128`, which is not FFI-safe - --> $DIR/naked-functions-ffi.rs:8:37 - | -LL | pub extern "C" fn naked(p: char) -> u128 { - | ^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - -warning: 2 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/lint/lint-ctypes-enum.rs b/tests/ui/lint/lint-ctypes-enum.rs index 612da86c956..f900f998d06 100644 --- a/tests/ui/lint/lint-ctypes-enum.rs +++ b/tests/ui/lint/lint-ctypes-enum.rs @@ -85,8 +85,8 @@ extern "C" { fn repr_c(x: ReprC); fn repr_u8(x: U8); fn repr_isize(x: Isize); - fn repr_u128(x: U128); //~ ERROR `extern` block uses type `U128` - fn repr_i128(x: I128); //~ ERROR `extern` block uses type `I128` + fn repr_u128(x: U128); + fn repr_i128(x: I128); fn option_ref(x: Option<&'static u8>); fn option_fn(x: Option); fn option_nonnull(x: Option>); @@ -96,14 +96,12 @@ extern "C" { fn option_nonzero_u32(x: Option>); fn option_nonzero_u64(x: Option>); fn option_nonzero_u128(x: Option>); - //~^ ERROR `extern` block uses type `u128` fn option_nonzero_usize(x: Option>); fn option_nonzero_i8(x: Option>); fn option_nonzero_i16(x: Option>); fn option_nonzero_i32(x: Option>); fn option_nonzero_i64(x: Option>); fn option_nonzero_i128(x: Option>); - //~^ ERROR `extern` block uses type `i128` fn option_nonzero_isize(x: Option>); fn option_transparent_struct(x: Option>>); fn option_transparent_enum(x: Option>>); @@ -121,14 +119,12 @@ extern "C" { fn result_nonzero_u32_t(x: Result, ()>); fn result_nonzero_u64_t(x: Result, ()>); fn result_nonzero_u128_t(x: Result, ()>); - //~^ ERROR `extern` block uses type `u128` fn result_nonzero_usize_t(x: Result, ()>); fn result_nonzero_i8_t(x: Result, ()>); fn result_nonzero_i16_t(x: Result, ()>); fn result_nonzero_i32_t(x: Result, ()>); fn result_nonzero_i64_t(x: Result, ()>); fn result_nonzero_i128_t(x: Result, ()>); - //~^ ERROR `extern` block uses type `i128` fn result_nonzero_isize_t(x: Result, ()>); fn result_transparent_struct_t(x: Result>, ()>); fn result_transparent_enum_t(x: Result>, ()>); @@ -159,14 +155,12 @@ extern "C" { fn result_nonzero_u32_e(x: Result<(), num::NonZero>); fn result_nonzero_u64_e(x: Result<(), num::NonZero>); fn result_nonzero_u128_e(x: Result<(), num::NonZero>); - //~^ ERROR `extern` block uses type `u128` fn result_nonzero_usize_e(x: Result<(), num::NonZero>); fn result_nonzero_i8_e(x: Result<(), num::NonZero>); fn result_nonzero_i16_e(x: Result<(), num::NonZero>); fn result_nonzero_i32_e(x: Result<(), num::NonZero>); fn result_nonzero_i64_e(x: Result<(), num::NonZero>); fn result_nonzero_i128_e(x: Result<(), num::NonZero>); - //~^ ERROR `extern` block uses type `i128` fn result_nonzero_isize_e(x: Result<(), num::NonZero>); fn result_transparent_struct_e(x: Result<(), TransparentStruct>>); fn result_transparent_enum_e(x: Result<(), TransparentEnum>>); diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr index 50a6f526f26..40d22723309 100644 --- a/tests/ui/lint/lint-ctypes-enum.stderr +++ b/tests/ui/lint/lint-ctypes-enum.stderr @@ -45,50 +45,8 @@ note: the type is defined here LL | enum T { | ^^^^^^ -error: `extern` block uses type `U128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:88:21 - | -LL | fn repr_u128(x: U128); - | ^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI -note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:44:1 - | -LL | enum U128 { - | ^^^^^^^^^ - -error: `extern` block uses type `I128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:89:21 - | -LL | fn repr_i128(x: I128); - | ^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI -note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:51:1 - | -LL | enum I128 { - | ^^^^^^^^^ - -error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:98:31 - | -LL | fn option_nonzero_u128(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - -error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:105:31 - | -LL | fn option_nonzero_i128(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - error: `extern` block uses type `Option>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:110:36 + --> $DIR/lint-ctypes-enum.rs:108:36 | LL | fn option_transparent_union(x: Option>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -97,7 +55,7 @@ LL | fn option_transparent_union(x: Option = note: enum has no representation hint error: `extern` block uses type `Option>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:112:28 + --> $DIR/lint-ctypes-enum.rs:110:28 | LL | fn option_repr_rust(x: Option>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -106,7 +64,7 @@ LL | fn option_repr_rust(x: Option>>); = note: enum has no representation hint error: `extern` block uses type `Option`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:113:21 + --> $DIR/lint-ctypes-enum.rs:111:21 | LL | fn option_u8(x: Option); | ^^^^^^^^^^ not FFI-safe @@ -114,24 +72,8 @@ LL | fn option_u8(x: Option); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:123:33 - | -LL | fn result_nonzero_u128_t(x: Result, ()>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - -error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:130:33 - | -LL | fn result_nonzero_i128_t(x: Result, ()>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - error: `extern` block uses type `Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:135:38 + --> $DIR/lint-ctypes-enum.rs:131:38 | LL | fn result_transparent_union_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -140,7 +82,7 @@ LL | fn result_transparent_union_t(x: Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:137:30 + --> $DIR/lint-ctypes-enum.rs:133:30 | LL | fn result_repr_rust_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -149,7 +91,7 @@ LL | fn result_repr_rust_t(x: Result>, ()>); = note: enum has no representation hint error: `extern` block uses type `Result, U>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:141:51 + --> $DIR/lint-ctypes-enum.rs:137:51 | LL | fn result_1zst_exhaustive_single_variant_t(x: Result, U>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -158,7 +100,7 @@ LL | fn result_1zst_exhaustive_single_variant_t(x: Result, = note: enum has no representation hint error: `extern` block uses type `Result, B>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:143:53 + --> $DIR/lint-ctypes-enum.rs:139:53 | LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result, B>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -167,7 +109,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result = note: enum has no representation hint error: `extern` block uses type `Result, NonExhaustive>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:145:51 + --> $DIR/lint-ctypes-enum.rs:141:51 | LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result, NonExhaustive>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -176,7 +118,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result, = note: enum has no representation hint error: `extern` block uses type `Result, Field>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:148:49 + --> $DIR/lint-ctypes-enum.rs:144:49 | LL | fn result_1zst_exhaustive_single_field_t(x: Result, Field>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -185,7 +127,7 @@ LL | fn result_1zst_exhaustive_single_field_t(x: Result, Fi = note: enum has no representation hint error: `extern` block uses type `Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:150:30 + --> $DIR/lint-ctypes-enum.rs:146:30 | LL | fn result_cascading_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -193,24 +135,8 @@ LL | fn result_cascading_t(x: Result>, ()>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:161:33 - | -LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - -error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:168:33 - | -LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - error: `extern` block uses type `Result<(), TransparentUnion>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:173:38 + --> $DIR/lint-ctypes-enum.rs:167:38 | LL | fn result_transparent_union_e(x: Result<(), TransparentUnion>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -219,7 +145,7 @@ LL | fn result_transparent_union_e(x: Result<(), TransparentUnion>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:175:30 + --> $DIR/lint-ctypes-enum.rs:169:30 | LL | fn result_repr_rust_e(x: Result<(), Rust>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -228,7 +154,7 @@ LL | fn result_repr_rust_e(x: Result<(), Rust>>); = note: enum has no representation hint error: `extern` block uses type `Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:179:51 + --> $DIR/lint-ctypes-enum.rs:173:51 | LL | fn result_1zst_exhaustive_single_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -237,7 +163,7 @@ LL | fn result_1zst_exhaustive_single_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:181:53 + --> $DIR/lint-ctypes-enum.rs:175:53 | LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -246,7 +172,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:183:51 + --> $DIR/lint-ctypes-enum.rs:177:51 | LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -255,7 +181,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:186:49 + --> $DIR/lint-ctypes-enum.rs:180:49 | LL | fn result_1zst_exhaustive_single_field_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -264,7 +190,7 @@ LL | fn result_1zst_exhaustive_single_field_e(x: Result>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:188:30 + --> $DIR/lint-ctypes-enum.rs:182:30 | LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -273,7 +199,7 @@ LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero>>); = note: enum has no representation hint error: `extern` block uses type `Result<(), ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:190:27 + --> $DIR/lint-ctypes-enum.rs:184:27 | LL | fn result_unit_t_e(x: Result<(), ()>); | ^^^^^^^^^^^^^^ not FFI-safe @@ -281,5 +207,5 @@ LL | fn result_unit_t_e(x: Result<(), ()>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: aborting due to 29 previous errors +error: aborting due to 21 previous errors diff --git a/tests/ui/lint/lint-ctypes-fn.rs b/tests/ui/lint/lint-ctypes-fn.rs index 73820c86d1a..0b84098e390 100644 --- a/tests/ui/lint/lint-ctypes-fn.rs +++ b/tests/ui/lint/lint-ctypes-fn.rs @@ -89,12 +89,6 @@ pub extern "C" fn boxed_trait(p: Box) { } pub extern "C" fn char_type(p: char) { } //~^ ERROR uses type `char` -pub extern "C" fn i128_type(p: i128) { } -//~^ ERROR uses type `i128` - -pub extern "C" fn u128_type(p: u128) { } -//~^ ERROR uses type `u128` - pub extern "C" fn tuple_type(p: (i32, i32)) { } //~^ ERROR uses type `(i32, i32)` @@ -120,9 +114,6 @@ pub extern "C" fn fn_type2(p: fn()) { } pub extern "C" fn fn_contained(p: RustBadRet) { } -pub extern "C" fn transparent_i128(p: TransparentI128) { } -//~^ ERROR: uses type `i128` - pub extern "C" fn transparent_str(p: TransparentStr) { } //~^ ERROR: uses type `str` @@ -161,6 +152,12 @@ pub extern "C" fn good17(p: TransparentCustomZst) { } #[allow(improper_ctypes_definitions)] pub extern "C" fn good18(_: &String) { } +pub extern "C" fn good_i128_type(p: i128) { } + +pub extern "C" fn good_u128_type(p: u128) { } + +pub extern "C" fn good_transparent_i128(p: TransparentI128) { } + #[cfg(not(target_arch = "wasm32"))] pub extern "C" fn good1(size: *const c_int) { } diff --git a/tests/ui/lint/lint-ctypes-fn.stderr b/tests/ui/lint/lint-ctypes-fn.stderr index a62533a4be1..a19c04a63b5 100644 --- a/tests/ui/lint/lint-ctypes-fn.stderr +++ b/tests/ui/lint/lint-ctypes-fn.stderr @@ -54,24 +54,8 @@ LL | pub extern "C" fn char_type(p: char) { } = help: consider using `u32` or `libc::wchar_t` instead = note: the `char` type has no C equivalent -error: `extern` fn uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:92:32 - | -LL | pub extern "C" fn i128_type(p: i128) { } - | ^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - -error: `extern` fn uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:95:32 - | -LL | pub extern "C" fn u128_type(p: u128) { } - | ^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:98:33 + --> $DIR/lint-ctypes-fn.rs:92:33 | LL | pub extern "C" fn tuple_type(p: (i32, i32)) { } | ^^^^^^^^^^ not FFI-safe @@ -80,7 +64,7 @@ LL | pub extern "C" fn tuple_type(p: (i32, i32)) { } = note: tuples have unspecified layout error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:101:34 + --> $DIR/lint-ctypes-fn.rs:95:34 | LL | pub extern "C" fn tuple_type2(p: I32Pair) { } | ^^^^^^^ not FFI-safe @@ -89,7 +73,7 @@ LL | pub extern "C" fn tuple_type2(p: I32Pair) { } = note: tuples have unspecified layout error: `extern` fn uses type `ZeroSize`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:104:32 + --> $DIR/lint-ctypes-fn.rs:98:32 | LL | pub extern "C" fn zero_size(p: ZeroSize) { } | ^^^^^^^^ not FFI-safe @@ -103,7 +87,7 @@ LL | pub struct ZeroSize; | ^^^^^^^^^^^^^^^^^^^ error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:107:40 + --> $DIR/lint-ctypes-fn.rs:101:40 | LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { } | ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -116,7 +100,7 @@ LL | pub struct ZeroSizeWithPhantomData(PhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` fn uses type `PhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:110:51 + --> $DIR/lint-ctypes-fn.rs:104:51 | LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData { | ^^^^^^^^^^^^^^^^^ not FFI-safe @@ -124,7 +108,7 @@ LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData { = note: composed only of `PhantomData` error: `extern` fn uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:115:30 + --> $DIR/lint-ctypes-fn.rs:109:30 | LL | pub extern "C" fn fn_type(p: RustFn) { } | ^^^^^^ not FFI-safe @@ -133,7 +117,7 @@ LL | pub extern "C" fn fn_type(p: RustFn) { } = note: this function pointer has Rust-specific calling convention error: `extern` fn uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:118:31 + --> $DIR/lint-ctypes-fn.rs:112:31 | LL | pub extern "C" fn fn_type2(p: fn()) { } | ^^^^ not FFI-safe @@ -141,16 +125,8 @@ LL | pub extern "C" fn fn_type2(p: fn()) { } = help: consider using an `extern fn(...) -> ...` function pointer instead = note: this function pointer has Rust-specific calling convention -error: `extern` fn uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:123:39 - | -LL | pub extern "C" fn transparent_i128(p: TransparentI128) { } - | ^^^^^^^^^^^^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - error: `extern` fn uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:126:38 + --> $DIR/lint-ctypes-fn.rs:117:38 | LL | pub extern "C" fn transparent_str(p: TransparentStr) { } | ^^^^^^^^^^^^^^ not FFI-safe @@ -159,7 +135,7 @@ LL | pub extern "C" fn transparent_str(p: TransparentStr) { } = note: string slices have no C equivalent error: `extern` fn uses type `PhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:172:43 + --> $DIR/lint-ctypes-fn.rs:169:43 | LL | pub extern "C" fn unused_generic2() -> PhantomData { | ^^^^^^^^^^^^^^^^^ not FFI-safe @@ -167,7 +143,7 @@ LL | pub extern "C" fn unused_generic2() -> PhantomData { = note: composed only of `PhantomData` error: `extern` fn uses type `Vec`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:185:39 + --> $DIR/lint-ctypes-fn.rs:182:39 | LL | pub extern "C" fn used_generic4(x: Vec) { } | ^^^^^^ not FFI-safe @@ -176,7 +152,7 @@ LL | pub extern "C" fn used_generic4(x: Vec) { } = note: this struct has unspecified layout error: `extern` fn uses type `Vec`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:188:41 + --> $DIR/lint-ctypes-fn.rs:185:41 | LL | pub extern "C" fn used_generic5() -> Vec { | ^^^^^^ not FFI-safe @@ -184,5 +160,5 @@ LL | pub extern "C" fn used_generic5() -> Vec { = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout -error: aborting due to 20 previous errors +error: aborting due to 17 previous errors diff --git a/tests/ui/lint/lint-ctypes.rs b/tests/ui/lint/lint-ctypes.rs index 6dd9be10a48..47586c826ab 100644 --- a/tests/ui/lint/lint-ctypes.rs +++ b/tests/ui/lint/lint-ctypes.rs @@ -54,8 +54,6 @@ extern "C" { pub fn opt_box_type(p: Option>); //~^ ERROR uses type `Option>` pub fn char_type(p: char); //~ ERROR uses type `char` - pub fn i128_type(p: i128); //~ ERROR uses type `i128` - pub fn u128_type(p: u128); //~ ERROR uses type `u128` pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `dyn Bar` pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)` pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)` @@ -67,7 +65,6 @@ extern "C" { pub fn fn_type(p: RustFn); //~ ERROR uses type `fn()` pub fn fn_type2(p: fn()); //~ ERROR uses type `fn()` pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `Box` - pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128` pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str` pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `Box` pub fn raw_array(arr: [u8; 8]); //~ ERROR: uses type `[u8; 8]` @@ -77,9 +74,6 @@ extern "C" { pub fn no_niche_b(b: Option>); //~^ ERROR: uses type `Option>` - pub static static_u128_type: u128; //~ ERROR: uses type `u128` - pub static static_u128_array_type: [u128; 16]; //~ ERROR: uses type `u128` - pub fn good3(fptr: Option); pub fn good4(aptr: &[u8; 4 as usize]); pub fn good5(s: StructWithProjection); @@ -99,7 +93,11 @@ extern "C" { pub fn good18(_: &String); pub fn good20(arr: *const [u8; 8]); pub static good21: [u8; 8]; - + pub fn good_i128_type(p: i128); + pub fn good_u128_type(p: u128); + pub fn good_transparent_i128(p: TransparentI128); + pub static good_static_u128_type: u128; + pub static good_static_u128_array_type: [u128; 16]; } #[allow(improper_ctypes)] diff --git a/tests/ui/lint/lint-ctypes.stderr b/tests/ui/lint/lint-ctypes.stderr index 8137ae868d3..3fb36647d4f 100644 --- a/tests/ui/lint/lint-ctypes.stderr +++ b/tests/ui/lint/lint-ctypes.stderr @@ -85,24 +85,8 @@ LL | pub fn char_type(p: char); = help: consider using `u32` or `libc::wchar_t` instead = note: the `char` type has no C equivalent -error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:57:25 - | -LL | pub fn i128_type(p: i128); - | ^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - -error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:58:25 - | -LL | pub fn u128_type(p: u128); - | ^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - error: `extern` block uses type `dyn Bar`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:59:26 + --> $DIR/lint-ctypes.rs:57:26 | LL | pub fn trait_type(p: &dyn Bar); | ^^^^^^^^ not FFI-safe @@ -110,7 +94,7 @@ LL | pub fn trait_type(p: &dyn Bar); = note: trait objects have no C equivalent error: `extern` block uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:60:26 + --> $DIR/lint-ctypes.rs:58:26 | LL | pub fn tuple_type(p: (i32, i32)); | ^^^^^^^^^^ not FFI-safe @@ -119,7 +103,7 @@ LL | pub fn tuple_type(p: (i32, i32)); = note: tuples have unspecified layout error: `extern` block uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:61:27 + --> $DIR/lint-ctypes.rs:59:27 | LL | pub fn tuple_type2(p: I32Pair); | ^^^^^^^ not FFI-safe @@ -128,7 +112,7 @@ LL | pub fn tuple_type2(p: I32Pair); = note: tuples have unspecified layout error: `extern` block uses type `ZeroSize`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:62:25 + --> $DIR/lint-ctypes.rs:60:25 | LL | pub fn zero_size(p: ZeroSize); | ^^^^^^^^ not FFI-safe @@ -142,7 +126,7 @@ LL | pub struct ZeroSize; | ^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:63:33 + --> $DIR/lint-ctypes.rs:61:33 | LL | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -155,7 +139,7 @@ LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `PhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:66:12 + --> $DIR/lint-ctypes.rs:64:12 | LL | -> ::std::marker::PhantomData; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -163,7 +147,7 @@ LL | -> ::std::marker::PhantomData; = note: composed only of `PhantomData` error: `extern` block uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:67:23 + --> $DIR/lint-ctypes.rs:65:23 | LL | pub fn fn_type(p: RustFn); | ^^^^^^ not FFI-safe @@ -172,7 +156,7 @@ LL | pub fn fn_type(p: RustFn); = note: this function pointer has Rust-specific calling convention error: `extern` block uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:68:24 + --> $DIR/lint-ctypes.rs:66:24 | LL | pub fn fn_type2(p: fn()); | ^^^^ not FFI-safe @@ -181,7 +165,7 @@ LL | pub fn fn_type2(p: fn()); = note: this function pointer has Rust-specific calling convention error: `extern` block uses type `Box`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:69:28 + --> $DIR/lint-ctypes.rs:67:28 | LL | pub fn fn_contained(p: RustBadRet); | ^^^^^^^^^^ not FFI-safe @@ -189,16 +173,8 @@ LL | pub fn fn_contained(p: RustBadRet); = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout -error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:70:32 - | -LL | pub fn transparent_i128(p: TransparentI128); - | ^^^^^^^^^^^^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - error: `extern` block uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:71:31 + --> $DIR/lint-ctypes.rs:68:31 | LL | pub fn transparent_str(p: TransparentStr); | ^^^^^^^^^^^^^^ not FFI-safe @@ -207,7 +183,7 @@ LL | pub fn transparent_str(p: TransparentStr); = note: string slices have no C equivalent error: `extern` block uses type `Box`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:72:30 + --> $DIR/lint-ctypes.rs:69:30 | LL | pub fn transparent_fn(p: TransparentBadFn); | ^^^^^^^^^^^^^^^^ not FFI-safe @@ -216,7 +192,7 @@ LL | pub fn transparent_fn(p: TransparentBadFn); = note: this struct has unspecified layout error: `extern` block uses type `[u8; 8]`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:73:27 + --> $DIR/lint-ctypes.rs:70:27 | LL | pub fn raw_array(arr: [u8; 8]); | ^^^^^^^ not FFI-safe @@ -225,7 +201,7 @@ LL | pub fn raw_array(arr: [u8; 8]); = note: passing raw arrays by value is not FFI-safe error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:75:26 + --> $DIR/lint-ctypes.rs:72:26 | LL | pub fn no_niche_a(a: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -234,7 +210,7 @@ LL | pub fn no_niche_a(a: Option>); = note: enum has no representation hint error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:77:26 + --> $DIR/lint-ctypes.rs:74:26 | LL | pub fn no_niche_b(b: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -242,21 +218,5 @@ LL | pub fn no_niche_b(b: Option>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:80:34 - | -LL | pub static static_u128_type: u128; - | ^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - -error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:81:40 - | -LL | pub static static_u128_array_type: [u128; 16]; - | ^^^^^^^^^^ not FFI-safe - | - = note: 128-bit integers don't currently have a known stable ABI - -error: aborting due to 27 previous errors +error: aborting due to 22 previous errors -- cgit 1.4.1-3-g733a5 From 97c0bebdf7094434c0fb2f941d7136c9c3ade986 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 28 May 2025 18:15:41 +0000 Subject: Remove unneeded C symbols These are now provided by `compiler-builtins`, so there is no need to also build the C versions. This was detected by checking for duplicate symbols and not excluding weak symbols (like CI currently does). --- library/compiler-builtins/compiler-builtins/build.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index 90d98ec7ce9..d37fdc5df50 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -555,7 +555,6 @@ mod c { if (target.arch == "aarch64" || target.arch == "arm64ec") && consider_float_intrinsics { sources.extend(&[ - ("__comparetf2", "comparetf2.c"), ("__fe_getround", "fp_mode.c"), ("__fe_raise_inexact", "fp_mode.c"), ]); @@ -570,11 +569,11 @@ mod c { } if target.arch == "mips64" { - sources.extend(&[("__netf2", "comparetf2.c"), ("__fe_getround", "fp_mode.c")]); + sources.extend(&[("__fe_getround", "fp_mode.c")]); } if target.arch == "loongarch64" { - sources.extend(&[("__netf2", "comparetf2.c"), ("__fe_getround", "fp_mode.c")]); + sources.extend(&[("__fe_getround", "fp_mode.c")]); } // Remove the assembly implementations that won't compile for the target -- cgit 1.4.1-3-g733a5 From a63f4826cf2ccceeedff5fb19ba0cbffc1ef5d65 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 07:38:43 +0000 Subject: Replace the `nm` symbol check with a Rust implementation This should be less error-prone and adaptable than the `nm` version, and have better cross-platform support without needing LLVM `nm` installed. --- library/compiler-builtins/Cargo.toml | 1 + library/compiler-builtins/ci/run.sh | 125 ++--------- .../crates/symbol-check/Cargo.toml | 13 ++ .../crates/symbol-check/src/main.rs | 231 +++++++++++++++++++++ 4 files changed, 262 insertions(+), 108 deletions(-) create mode 100644 library/compiler-builtins/crates/symbol-check/Cargo.toml create mode 100644 library/compiler-builtins/crates/symbol-check/src/main.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index b39ec8a25da..bc6b4bd2979 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -6,6 +6,7 @@ members = [ "crates/libm-macros", "crates/musl-math-sys", "crates/panic-handler", + "crates/symbol-check", "crates/util", "libm", "libm-test", diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 68d13c130bc..cf3f7dfda1d 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -47,87 +47,25 @@ else fi fi - -declare -a rlib_paths - -# Set the `rlib_paths` global array to a list of all compiler-builtins rlibs -update_rlib_paths() { - if [ -d /builtins-target ]; then - rlib_paths=( /builtins-target/"${target}"/debug/deps/libcompiler_builtins-*.rlib ) - else - rlib_paths=( target/"${target}"/debug/deps/libcompiler_builtins-*.rlib ) - fi -} - -# Remove any existing artifacts from previous tests that don't set #![compiler_builtins] -update_rlib_paths -rm -f "${rlib_paths[@]}" - -cargo build -p compiler_builtins --target "$target" -cargo build -p compiler_builtins --target "$target" --release -cargo build -p compiler_builtins --target "$target" --features c -cargo build -p compiler_builtins --target "$target" --features c --release -cargo build -p compiler_builtins --target "$target" --features no-asm -cargo build -p compiler_builtins --target "$target" --features no-asm --release -cargo build -p compiler_builtins --target "$target" --features no-f16-f128 -cargo build -p compiler_builtins --target "$target" --features no-f16-f128 --release - -PREFIX=${target//unknown-/}- -case "$target" in - armv7-*) - PREFIX=arm-linux-gnueabihf- - ;; - thumb*) - PREFIX=arm-none-eabi- - ;; - *86*-*) - PREFIX= - ;; -esac - -NM=$(find "$(rustc --print sysroot)" \( -name llvm-nm -o -name llvm-nm.exe \) ) -if [ "$NM" = "" ]; then - NM="${PREFIX}nm" -fi - -# i686-pc-windows-gnu tools have a dependency on some DLLs, so run it with -# rustup run to ensure that those are in PATH. -TOOLCHAIN="$(rustup show active-toolchain | sed 's/ (default)//')" -if [[ "$TOOLCHAIN" == *i686-pc-windows-gnu ]]; then - NM="rustup run $TOOLCHAIN $NM" -fi - -# Look out for duplicated symbols when we include the compiler-rt (C) implementation -update_rlib_paths -for rlib in "${rlib_paths[@]}"; do - set +x - echo "================================================================" - echo "checking $rlib for duplicate symbols" - echo "================================================================" - set -x - - duplicates_found=0 - - # NOTE On i586, It's normal that the get_pc_thunk symbol appears several - # times so ignore it - $NM -g --defined-only "$rlib" 2>&1 | - sort | - uniq -d | - grep -v __x86.get_pc_thunk --quiet | - grep 'T __' && duplicates_found=1 - - if [ "$duplicates_found" != 0 ]; then - echo "error: found duplicate symbols" - exit 1 - else - echo "success; no duplicate symbols found" - fi -done - -rm -f "${rlib_paths[@]}" +# Ensure there are no duplicate symbols or references to `core` when +# `compiler-builtins` is built with various features. Symcheck invokes Cargo to +# build with the arguments we provide it, then validates the built artifacts. +symcheck=(cargo run -p symbol-check --release) +[[ "$target" = "wasm"* ]] && symcheck+=(--features wasm) +symcheck+=(-- build-and-check) + +"${symcheck[@]}" -p compiler_builtins --target "$target" +"${symcheck[@]}" -p compiler_builtins --target "$target" --release +"${symcheck[@]}" -p compiler_builtins --target "$target" --features c +"${symcheck[@]}" -p compiler_builtins --target "$target" --features c --release +"${symcheck[@]}" -p compiler_builtins --target "$target" --features no-asm +"${symcheck[@]}" -p compiler_builtins --target "$target" --features no-asm --release +"${symcheck[@]}" -p compiler_builtins --target "$target" --features no-f16-f128 +"${symcheck[@]}" -p compiler_builtins --target "$target" --features no-f16-f128 --release build_intrinsics_test() { - cargo build \ + # symcheck also checks the results of builtins-test-intrinsics + "${symcheck[@]}" \ --target "$target" --verbose \ --manifest-path builtins-test-intrinsics/Cargo.toml "$@" } @@ -143,35 +81,6 @@ build_intrinsics_test --features c --release CARGO_PROFILE_DEV_LTO=true build_intrinsics_test CARGO_PROFILE_RELEASE_LTO=true build_intrinsics_test --release -# Ensure no references to any symbols from core -update_rlib_paths -for rlib in "${rlib_paths[@]}"; do - set +x - echo "================================================================" - echo "checking $rlib for references to core" - echo "================================================================" - set -x - - tmpdir="${CARGO_TARGET_DIR:-target}/tmp" - test -d "$tmpdir" || mkdir "$tmpdir" - defined="$tmpdir/defined_symbols.txt" - undefined="$tmpdir/defined_symbols.txt" - - $NM --quiet -U "$rlib" | grep 'T _ZN4core' | awk '{print $3}' | sort | uniq > "$defined" - $NM --quiet -u "$rlib" | grep 'U _ZN4core' | awk '{print $2}' | sort | uniq > "$undefined" - grep_has_results=0 - grep -v -F -x -f "$defined" "$undefined" && grep_has_results=1 - - if [ "$target" = "powerpc64-unknown-linux-gnu" ]; then - echo "FIXME: powerpc64 fails these tests" - elif [ "$grep_has_results" != 0 ]; then - echo "error: found unexpected references to core" - exit 1 - else - echo "success; no references to core found" - fi -done - # Test libm # Make sure a simple build works diff --git a/library/compiler-builtins/crates/symbol-check/Cargo.toml b/library/compiler-builtins/crates/symbol-check/Cargo.toml new file mode 100644 index 00000000000..30969ee406a --- /dev/null +++ b/library/compiler-builtins/crates/symbol-check/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "symbol-check" +version = "0.1.0" +edition = "2024" +publish = false + +[dependencies] +# FIXME: used as a git dependency since the latest release does not support wasm +object = { git = "https://github.com/gimli-rs/object.git", rev = "013fac75da56a684377af4151b8164b78c1790e0" } +serde_json = "1.0.140" + +[features] +wasm = ["object/wasm"] diff --git a/library/compiler-builtins/crates/symbol-check/src/main.rs b/library/compiler-builtins/crates/symbol-check/src/main.rs new file mode 100644 index 00000000000..104505438cc --- /dev/null +++ b/library/compiler-builtins/crates/symbol-check/src/main.rs @@ -0,0 +1,231 @@ +//! Tool used by CI to inspect compiler-builtins archives and help ensure we won't run into any +//! linking errors. + +use std::collections::{BTreeMap, BTreeSet}; +use std::fs; +use std::io::{BufRead, BufReader}; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; + +use object::read::archive::{ArchiveFile, ArchiveMember}; +use object::{Object, ObjectSymbol, Symbol, SymbolKind, SymbolScope, SymbolSection}; +use serde_json::Value; + +const CHECK_LIBRARIES: &[&str] = &["compiler_builtins", "builtins_test_intrinsics"]; +const CHECK_EXTENSIONS: &[Option<&str>] = &[Some("rlib"), Some("a"), Some("exe"), None]; + +const USAGE: &str = "Usage: + + symbol-check build-and-check CARGO_ARGS ... + +Cargo will get invoked with `CARGO_ARGS` and all output +`compiler_builtins*.rlib` files will be checked. +"; + +fn main() { + // Create a `&str` vec so we can match on it. + let args = std::env::args().collect::>(); + let args_ref = args.iter().map(String::as_str).collect::>(); + + match &args_ref[1..] { + ["build-and-check", rest @ ..] if !rest.is_empty() => { + let paths = exec_cargo_with_args(rest); + for path in paths { + println!("Checking {}", path.display()); + verify_no_duplicates(&path); + verify_core_symbols(&path); + } + } + _ => { + println!("{USAGE}"); + std::process::exit(1); + } + } +} + +/// Run `cargo build` with the provided additional arguments, collecting the list of created +/// libraries. +fn exec_cargo_with_args(args: &[&str]) -> Vec { + let mut cmd = Command::new("cargo") + .arg("build") + .arg("--message-format=json") + .args(args) + .stdout(Stdio::piped()) + .spawn() + .expect("failed to launch Cargo"); + + let stdout = cmd.stdout.take().unwrap(); + let reader = BufReader::new(stdout); + let mut check_files = Vec::new(); + + for line in reader.lines() { + let line = line.expect("failed to read line"); + println!("{line}"); // tee to stdout + + // Select only steps that create files + let j: Value = serde_json::from_str(&line).expect("failed to deserialize"); + if j["reason"] != "compiler-artifact" { + continue; + } + + // Find rlibs in the created file list that match our expected library names and + // extensions. + for fpath in j["filenames"].as_array().expect("filenames not an array") { + let path = fpath.as_str().expect("file name not a string"); + let path = PathBuf::from(path); + + if CHECK_EXTENSIONS.contains(&path.extension().map(|ex| ex.to_str().unwrap())) { + let fname = path.file_name().unwrap().to_str().unwrap(); + + if CHECK_LIBRARIES.iter().any(|lib| fname.contains(lib)) { + check_files.push(path); + } + } + } + } + + cmd.wait().expect("failed to wait on Cargo"); + + assert!(!check_files.is_empty(), "no compiler_builtins rlibs found"); + println!("Collected the following rlibs to check: {check_files:#?}"); + + check_files +} + +/// Information collected from `object`, for convenience. +#[expect(unused)] // only for printing +#[derive(Clone, Debug)] +struct SymInfo { + name: String, + kind: SymbolKind, + scope: SymbolScope, + section: SymbolSection, + is_undefined: bool, + is_global: bool, + is_local: bool, + is_weak: bool, + is_common: bool, + address: u64, + object: String, +} + +impl SymInfo { + fn new(sym: &Symbol, member: &ArchiveMember) -> Self { + Self { + name: sym.name().expect("missing name").to_owned(), + kind: sym.kind(), + scope: sym.scope(), + section: sym.section(), + is_undefined: sym.is_undefined(), + is_global: sym.is_global(), + is_local: sym.is_local(), + is_weak: sym.is_weak(), + is_common: sym.is_common(), + address: sym.address(), + object: String::from_utf8_lossy(member.name()).into_owned(), + } + } +} + +/// Ensure that the same global symbol isn't defined in multiple object files within an archive. +/// +/// Note that this will also locate cases where a symbol is weakly defined in more than one place. +/// Technically there are no linker errors that will come from this, but it keeps our binary more +/// straightforward and saves some distribution size. +fn verify_no_duplicates(path: &Path) { + let mut syms = BTreeMap::::new(); + let mut dups = Vec::new(); + let mut found_any = false; + + for_each_symbol(path, |symbol, member| { + // Only check defined globals + if !symbol.is_global() || symbol.is_undefined() { + return; + } + + let sym = SymInfo::new(&symbol, member); + + // x86-32 includes multiple copies of thunk symbols + if sym.name.starts_with("__x86.get_pc_thunk") { + return; + } + + // Windows has symbols for literal numeric constants, string literals, and MinGW pseudo- + // relocations. These are allowed to have repeated definitions. + let win_allowed_dup_pfx = ["__real@", "__xmm@", "??_C@_", ".refptr"]; + if win_allowed_dup_pfx + .iter() + .any(|pfx| sym.name.starts_with(pfx)) + { + return; + } + + match syms.get(&sym.name) { + Some(existing) => { + dups.push(sym); + dups.push(existing.clone()); + } + None => { + syms.insert(sym.name.clone(), sym); + } + } + + found_any = true; + }); + + assert!(found_any, "no symbols found"); + + if !dups.is_empty() { + dups.sort_unstable_by(|a, b| a.name.cmp(&b.name)); + panic!("found duplicate symbols: {dups:#?}"); + } + + println!(" success: no duplicate symbols found"); +} + +/// Ensure that there are no references to symbols from `core` that aren't also (somehow) defined. +fn verify_core_symbols(path: &Path) { + let mut defined = BTreeSet::new(); + let mut undefined = Vec::new(); + let mut has_symbols = false; + + for_each_symbol(path, |symbol, member| { + has_symbols = true; + + // Find only symbols from `core` + if !symbol.name().unwrap().contains("_ZN4core") { + return; + } + + let sym = SymInfo::new(&symbol, member); + if sym.is_undefined { + undefined.push(sym); + } else { + defined.insert(sym.name); + } + }); + + assert!(has_symbols, "no symbols found"); + + // Discard any symbols that are defined somewhere in the archive + undefined.retain(|sym| !defined.contains(&sym.name)); + + if !undefined.is_empty() { + undefined.sort_unstable_by(|a, b| a.name.cmp(&b.name)); + panic!("found undefined symbols from core: {undefined:#?}"); + } + + println!(" success: no undefined references to core found"); +} + +/// For a given archive path, do something with each symbol. +fn for_each_symbol(path: &Path, mut f: impl FnMut(Symbol, &ArchiveMember)) { + let data = fs::read(path).expect("reading file failed"); + let archive = ArchiveFile::parse(data.as_slice()).expect("archive parse failed"); + for member in archive.members() { + let member = member.expect("failed to access member"); + let obj_data = member.data(&*data).expect("failed to access object"); + let obj = object::File::parse(obj_data).expect("failed to parse object"); + obj.symbols().for_each(|sym| f(sym, &member)); + } +} -- cgit 1.4.1-3-g733a5 From 8db9bd6a59c8c59b8d04ee647f071e81f79f6225 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 28 May 2025 19:59:16 +0000 Subject: Remove the now-unneeded llvm-tools-preview Since a working `nm` is no longer needed as part of CI, the rustup component can be removed. --- library/compiler-builtins/.github/workflows/main.yaml | 1 - library/compiler-builtins/crates/symbol-check/src/main.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index d13dd6b0f64..567ad1205a5 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -119,7 +119,6 @@ jobs: rustup update "$channel" --no-self-update rustup default "$channel" rustup target add "${{ matrix.target }}" - rustup component add llvm-tools-preview - uses: taiki-e/install-action@nextest - uses: Swatinem/rust-cache@v2 with: diff --git a/library/compiler-builtins/crates/symbol-check/src/main.rs b/library/compiler-builtins/crates/symbol-check/src/main.rs index 104505438cc..4e6417fdf95 100644 --- a/library/compiler-builtins/crates/symbol-check/src/main.rs +++ b/library/compiler-builtins/crates/symbol-check/src/main.rs @@ -84,7 +84,7 @@ fn exec_cargo_with_args(args: &[&str]) -> Vec { } } - cmd.wait().expect("failed to wait on Cargo"); + assert!(cmd.wait().expect("failed to wait on Cargo").success()); assert!(!check_files.is_empty(), "no compiler_builtins rlibs found"); println!("Collected the following rlibs to check: {check_files:#?}"); -- cgit 1.4.1-3-g733a5 From 151b1cb04777e1e9630045d52f14bc0e7adf5787 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 15:40:05 +0000 Subject: Change `compiler-builtins` to edition 2024 Do the same for `builtins-test-intrinsics`. Mostly this means updating `extern` to `unsafe extern`, and fixing a few new Clippy lints. --- .../builtins-test-intrinsics/Cargo.toml | 2 +- .../builtins-test-intrinsics/src/main.rs | 6 ++++-- .../builtins-test/tests/aeabi_memclr.rs | 3 ++- .../builtins-test/tests/aeabi_memcpy.rs | 3 ++- .../builtins-test/tests/aeabi_memset.rs | 3 ++- library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/compiler-builtins/src/arm.rs | 7 +++++-- .../compiler-builtins/src/int/specialized_div_rem/mod.rs | 16 ++++++++-------- .../compiler-builtins/compiler-builtins/src/macros.rs | 4 ++-- .../compiler-builtins/src/probestack.rs | 4 +++- 10 files changed, 30 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 6e10628a41b..704de20c5ad 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "builtins-test-intrinsics" version = "0.1.0" -edition = "2021" +edition = "2024" publish = false license = "MIT OR Apache-2.0" diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs index 1fa7b00916f..96fe4a73851 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -15,9 +15,10 @@ extern crate panic_handler; +// SAFETY: no definitions, only used for linking #[cfg(all(not(thumb), not(windows), not(target_arch = "wasm32")))] #[link(name = "c")] -extern "C" {} +unsafe extern "C" {} // Every function in this module maps will be lowered to an intrinsic by LLVM, if the platform // doesn't have native support for the operation used in the function. ARM has a naming convention @@ -663,10 +664,11 @@ pub fn _start() -> ! { loop {} } +// SAFETY: no definitions, only used for linking #[cfg(windows)] #[link(name = "kernel32")] #[link(name = "msvcrt")] -extern "C" {} +unsafe extern "C" {} // ARM targets need these symbols #[unsafe(no_mangle)] diff --git a/library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs b/library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs index bfd15a391aa..0761feaffd9 100644 --- a/library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs +++ b/library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs @@ -24,7 +24,8 @@ macro_rules! panic { }; } -extern "C" { +// SAFETY: defined in compiler-builtins +unsafe extern "aapcs" { fn __aeabi_memclr4(dest: *mut u8, n: usize); fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); } diff --git a/library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs b/library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs index c892c5aba0f..e76e712a246 100644 --- a/library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs +++ b/library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs @@ -22,7 +22,8 @@ macro_rules! panic { }; } -extern "C" { +// SAFETY: defined in compiler-builtins +unsafe extern "aapcs" { fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize); fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize); } diff --git a/library/compiler-builtins/builtins-test/tests/aeabi_memset.rs b/library/compiler-builtins/builtins-test/tests/aeabi_memset.rs index 34ab3acc78c..8f9f80f969c 100644 --- a/library/compiler-builtins/builtins-test/tests/aeabi_memset.rs +++ b/library/compiler-builtins/builtins-test/tests/aeabi_memset.rs @@ -24,7 +24,8 @@ macro_rules! panic { }; } -extern "C" { +// SAFETY: defined in compiler-builtins +unsafe extern "aapcs" { fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); } diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index d65a22152ef..93eb3e01b3b 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -7,7 +7,7 @@ readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" homepage = "https://github.com/rust-lang/compiler-builtins" documentation = "https://docs.rs/compiler_builtins" -edition = "2021" +edition = "2024" description = "Compiler intrinsics used by the Rust compiler." links = "compiler-rt" diff --git a/library/compiler-builtins/compiler-builtins/src/arm.rs b/library/compiler-builtins/compiler-builtins/src/arm.rs index a9107e3cdfd..a7d84e49b34 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm.rs @@ -1,13 +1,16 @@ #![cfg(not(feature = "no-asm"))] // Interfaces used by naked trampolines. -extern "C" { +// SAFETY: these are defined in compiler-builtins +unsafe extern "C" { fn __udivmodsi4(a: u32, b: u32, rem: *mut u32) -> u32; fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64; fn __divmoddi4(a: i64, b: i64, rem: *mut i64) -> i64; } -extern "aapcs" { +// SAFETY: these are defined in compiler-builtins +// FIXME(extern_custom), this isn't always the correct ABI +unsafe extern "aapcs" { // AAPCS is not always the correct ABI for these intrinsics, but we only use this to // forward another `__aeabi_` call so it doesn't matter. fn __aeabi_idiv(a: i32, b: i32) -> i32; diff --git a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs index 43f466e75ba..7841e4f33cd 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -125,10 +125,10 @@ impl_normalization_shift!( /// dependencies. #[inline] fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { - if let Some(quo) = duo.checked_div(div) { - if let Some(rem) = duo.checked_rem(div) { - return (quo, rem); - } + if let Some(quo) = duo.checked_div(div) + && let Some(rem) = duo.checked_rem(div) + { + return (quo, rem); } zero_div_fn() } @@ -227,10 +227,10 @@ impl_asymmetric!( #[inline] #[allow(dead_code)] fn u32_by_u32_div_rem(duo: u32, div: u32) -> (u32, u32) { - if let Some(quo) = duo.checked_div(div) { - if let Some(rem) = duo.checked_rem(div) { - return (quo, rem); - } + if let Some(quo) = duo.checked_div(div) + && let Some(rem) = duo.checked_rem(div) + { + return (quo, rem); } zero_div_fn() } diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index 22e0dd27f2f..203cd0949ac 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -132,7 +132,7 @@ macro_rules! intrinsics { ) => ( #[cfg($name = "optimized-c")] pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - extern $abi { + unsafe extern $abi { fn $name($($argname: $ty),*) $(-> $ret)?; } unsafe { @@ -435,7 +435,7 @@ macro_rules! intrinsics { pub mod $name { #[unsafe(naked)] $(#[$($attr)*])* - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(not(feature = "mangled-names"), unsafe(no_mangle))] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* diff --git a/library/compiler-builtins/compiler-builtins/src/probestack.rs b/library/compiler-builtins/compiler-builtins/src/probestack.rs index 5b6abd21a1d..c9070cf55c6 100644 --- a/library/compiler-builtins/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/compiler-builtins/src/probestack.rs @@ -49,7 +49,9 @@ // We only define stack probing for these architectures today. #![cfg(any(target_arch = "x86_64", target_arch = "x86"))] -extern "C" { +// SAFETY: defined in this module. +// FIXME(extern_custom): the ABI is not correct. +unsafe extern "C" { pub fn __rust_probestack(); } -- cgit 1.4.1-3-g733a5 From af16553893152ba74b0391b02c31f083c2f519b1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 16:07:54 +0000 Subject: symcheck: Print the command to make reproducing errors easier --- library/compiler-builtins/crates/symbol-check/src/main.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/crates/symbol-check/src/main.rs b/library/compiler-builtins/crates/symbol-check/src/main.rs index 4e6417fdf95..d83cd318d6a 100644 --- a/library/compiler-builtins/crates/symbol-check/src/main.rs +++ b/library/compiler-builtins/crates/symbol-check/src/main.rs @@ -46,15 +46,16 @@ fn main() { /// Run `cargo build` with the provided additional arguments, collecting the list of created /// libraries. fn exec_cargo_with_args(args: &[&str]) -> Vec { - let mut cmd = Command::new("cargo") - .arg("build") + let mut cmd = Command::new("cargo"); + cmd.arg("build") .arg("--message-format=json") .args(args) - .stdout(Stdio::piped()) - .spawn() - .expect("failed to launch Cargo"); + .stdout(Stdio::piped()); - let stdout = cmd.stdout.take().unwrap(); + println!("running: {cmd:?}"); + let mut child = cmd.spawn().expect("failed to launch Cargo"); + + let stdout = child.stdout.take().unwrap(); let reader = BufReader::new(stdout); let mut check_files = Vec::new(); @@ -84,7 +85,7 @@ fn exec_cargo_with_args(args: &[&str]) -> Vec { } } - assert!(cmd.wait().expect("failed to wait on Cargo").success()); + assert!(child.wait().expect("failed to wait on Cargo").success()); assert!(!check_files.is_empty(), "no compiler_builtins rlibs found"); println!("Collected the following rlibs to check: {check_files:#?}"); -- cgit 1.4.1-3-g733a5 From 7db8cf1fea87dd42082ac6eeb405e609628ac6b1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 17:37:35 +0000 Subject: Add benchmarks for float parsing and printing As part of this, the u256 benchmarks are reorganized to a group. --- .../compiler-builtins/libm-test/benches/icount.rs | 100 +++++++++++++++++---- 1 file changed, 83 insertions(+), 17 deletions(-) diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index da8c6bfd15a..4bebbc41ccd 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -1,9 +1,11 @@ //! Benchmarks that use `iai-cachegrind` to be reasonably CI-stable. +#![feature(f16)] +#![feature(f128)] use std::hint::black_box; use iai_callgrind::{library_benchmark, library_benchmark_group, main}; -use libm::support::{HInt, u256}; +use libm::support::{HInt, Hexf, hf16, hf32, hf64, hf128, u256}; use libm_test::generate::spaced; use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, OpRustArgs, TupleCall, op}; @@ -109,11 +111,6 @@ fn icount_bench_u128_widen_mul(cases: Vec<(u128, u128)>) { } } -library_benchmark_group!( - name = icount_bench_u128_widen_mul_group; - benchmarks = icount_bench_u128_widen_mul -); - #[library_benchmark] #[bench::linspace(setup_u256_add())] fn icount_bench_u256_add(cases: Vec<(u256, u256)>) { @@ -122,11 +119,6 @@ fn icount_bench_u256_add(cases: Vec<(u256, u256)>) { } } -library_benchmark_group!( - name = icount_bench_u256_add_group; - benchmarks = icount_bench_u256_add -); - #[library_benchmark] #[bench::linspace(setup_u256_shift())] fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) { @@ -136,16 +128,90 @@ fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) { } library_benchmark_group!( - name = icount_bench_u256_shr_group; - benchmarks = icount_bench_u256_shr + name = icount_bench_u128_group; + benchmarks = icount_bench_u128_widen_mul, icount_bench_u256_add, icount_bench_u256_shr +); + +#[library_benchmark] +#[bench::short("0x12.34p+8")] +#[bench::max("0x1.ffcp+15")] +fn icount_bench_hf16(s: &str) -> f16 { + black_box(hf16(s)) +} + +#[library_benchmark] +#[bench::short("0x12.34p+8")] +#[bench::max("0x1.fffffep+127")] +fn icount_bench_hf32(s: &str) -> f32 { + black_box(hf32(s)) +} + +#[library_benchmark] +#[bench::short("0x12.34p+8")] +#[bench::max("0x1.fffffffffffffp+1023")] +fn icount_bench_hf64(s: &str) -> f64 { + black_box(hf64(s)) +} + +#[library_benchmark] +#[bench::short("0x12.34p+8")] +#[bench::max("0x1.ffffffffffffffffffffffffffffp+16383")] +fn icount_bench_hf128(s: &str) -> f128 { + black_box(hf128(s)) +} + +library_benchmark_group!( + name = icount_bench_hf_parse_group; + benchmarks = + icount_bench_hf16, + icount_bench_hf32, + icount_bench_hf64, + icount_bench_hf128 +); + +#[library_benchmark] +#[bench::short(1.015625)] +#[bench::max(f16::MAX)] +fn icount_bench_print_hf16(x: f16) -> String { + black_box(Hexf(x).to_string()) +} + +#[library_benchmark] +#[bench::short(1.015625)] +#[bench::max(f32::MAX)] +fn icount_bench_print_hf32(x: f32) -> String { + black_box(Hexf(x).to_string()) +} + +#[library_benchmark] +#[bench::short(1.015625)] +#[bench::max(f64::MAX)] +fn icount_bench_print_hf64(x: f64) -> String { + black_box(Hexf(x).to_string()) +} + +#[library_benchmark] +#[bench::short(1.015625)] +#[bench::max(f128::MAX)] +fn icount_bench_print_hf128(x: f128) -> String { + black_box(Hexf(x).to_string()) +} + +library_benchmark_group!( + name = icount_bench_hf_print_group; + benchmarks = + icount_bench_print_hf16, + icount_bench_print_hf32, + icount_bench_print_hf64, + icount_bench_print_hf128 ); main!( library_benchmark_groups = - // u256-related benchmarks - icount_bench_u128_widen_mul_group, - icount_bench_u256_add_group, - icount_bench_u256_shr_group, + // Benchmarks not related to public libm math + icount_bench_u128_group, + icount_bench_hf_parse_group, + icount_bench_hf_print_group, // verify-apilist-start // verify-sorted-start icount_bench_acos_group, -- cgit 1.4.1-3-g733a5 From c136fb7734716a078cd82a7364245128923eb7e4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Mar 2025 04:10:03 +0000 Subject: Run `builtins-test-intrinsics` when possible Currently we only build this, but it is possible to run the binary. Change the CI script to do so here. --- .../builtins-test-intrinsics/src/main.rs | 6 +++-- library/compiler-builtins/ci/run.sh | 30 ++++++++++++++-------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs index 96fe4a73851..66744a0817f 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -13,6 +13,8 @@ #![no_std] #![no_main] +// Ensure this `compiler_builtins` gets used, rather than the version injected from the sysroot. +extern crate compiler_builtins; extern crate panic_handler; // SAFETY: no definitions, only used for linking @@ -652,14 +654,14 @@ fn something_with_a_dtor(f: &dyn Fn()) { #[unsafe(no_mangle)] #[cfg(not(thumb))] -fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { +extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { run(); 0 } #[unsafe(no_mangle)] #[cfg(thumb)] -pub fn _start() -> ! { +extern "C" fn _start() -> ! { run(); loop {} } diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index cf3f7dfda1d..27b9686eac6 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -63,23 +63,33 @@ symcheck+=(-- build-and-check) "${symcheck[@]}" -p compiler_builtins --target "$target" --features no-f16-f128 "${symcheck[@]}" -p compiler_builtins --target "$target" --features no-f16-f128 --release -build_intrinsics_test() { - # symcheck also checks the results of builtins-test-intrinsics - "${symcheck[@]}" \ +run_intrinsics_test() { + args=( --target "$target" --verbose \ - --manifest-path builtins-test-intrinsics/Cargo.toml "$@" + --manifest-path builtins-test-intrinsics/Cargo.toml + ) + args+=( "$@" ) + + # symcheck also checks the results of builtins-test-intrinsics + "${symcheck[@]}" "${args[@]}" + + # FIXME: we get access violations on Windows, our entrypoint may need to + # be tweaked. + if [ "${BUILD_ONLY:-}" != "1" ] && ! [[ "$target" = *"windows"* ]]; then + cargo run "${args[@]}" + fi } # Verify that we haven't dropped any intrinsics/symbols -build_intrinsics_test -build_intrinsics_test --release -build_intrinsics_test --features c -build_intrinsics_test --features c --release +run_intrinsics_test +run_intrinsics_test --release +run_intrinsics_test --features c +run_intrinsics_test --features c --release # Verify that there are no undefined symbols to `panic` within our # implementations -CARGO_PROFILE_DEV_LTO=true build_intrinsics_test -CARGO_PROFILE_RELEASE_LTO=true build_intrinsics_test --release +CARGO_PROFILE_DEV_LTO=true run_intrinsics_test +CARGO_PROFILE_RELEASE_LTO=true run_intrinsics_test --release # Test libm -- cgit 1.4.1-3-g733a5 From 3464b4b231e3e4a09e102696228fe950eb1672e5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 19:01:03 +0000 Subject: ci: Allow concurrency outside of pull requests When multiple merges to `master` happen before a CI run completes, the in-progress job is getting canceled. Fix this by using the commit sha for the group key if a pull request number is not available, rather than `github.ref` (which is always `refs/head/master` after merge). This should prevent jobs running on previous commits from getting cancelled, while still ensuring there is only ever one active run per pull request. --- library/compiler-builtins/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 567ad1205a5..de433d8c74d 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -5,7 +5,7 @@ on: concurrency: # Make sure that new pushes cancel running jobs - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true env: -- cgit 1.4.1-3-g733a5 From 9f84e9904fd2be7e6b2c339b16ac9c2e5da8778b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 18:06:43 +0000 Subject: Increase the benchmark rustc version to 2025-05-28 We may soon want to use some new nightly features in `compiler-builtins` and `libm`, specifically `cfg_target_has_reliable_f16_f128` which was added in the past few weeks. This will mean we need a newer toolchain for benchmarks to continue building. Bump to the current latest nightly so we are not blocked on this down the line. --- library/compiler-builtins/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index de433d8c74d..8e89cb47292 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -13,7 +13,7 @@ env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings RUST_BACKTRACE: full - BENCHMARK_RUSTC: nightly-2025-01-16 # Pin the toolchain for reproducable results + BENCHMARK_RUSTC: nightly-2025-05-28 # Pin the toolchain for reproducable results jobs: # Determine which tests should be run based on changed files. -- cgit 1.4.1-3-g733a5 From 8edaa6e5c88e14df20b095016514d381c697e49a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 20:53:48 +0000 Subject: libm-test: Make `extensive` an attribute rather than a test type Currently we run logspace tests for extensive tests, but there isn't any reason we couldn't also run more kinds of tests more extensively (e.g. more edge cases, combine edge cases with logspace for multi-input functions, etc). As a first step toward making this possible, make `extensive` a new field in `CheckCtx`, and rename `QuickSpaced` to `Spaced`. --- .../compiler-builtins/libm-test/benches/icount.rs | 2 +- .../libm-test/examples/plot_domains.rs | 2 +- library/compiler-builtins/libm-test/src/run_cfg.rs | 74 ++++++++++++++++------ .../libm-test/tests/compare_built_musl.rs | 2 +- .../libm-test/tests/multiprecision.rs | 2 +- .../libm-test/tests/z_extensive/run.rs | 3 +- 6 files changed, 60 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index 4bebbc41ccd..a0928a29f99 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -23,7 +23,7 @@ macro_rules! icount_benches { let mut ctx = CheckCtx::new( Op::IDENTIFIER, CheckBasis::None, - GeneratorKind::QuickSpaced + GeneratorKind::Spaced ); ctx.override_iterations(BENCH_ITER_ITEMS); let ret = spaced::get_test_cases::(&ctx).0.collect::>(); diff --git a/library/compiler-builtins/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm-test/examples/plot_domains.rs index 3563103b8cd..7331d454f21 100644 --- a/library/compiler-builtins/libm-test/examples/plot_domains.rs +++ b/library/compiler-builtins/libm-test/examples/plot_domains.rs @@ -55,7 +55,7 @@ where Op: MathOp, Op::RustArgs: SpacedInput, { - let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::QuickSpaced); + let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::Spaced); plot_one_generator( out_dir, &ctx, diff --git a/library/compiler-builtins/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm-test/src/run_cfg.rs index 3345a01d2de..90f81195c85 100644 --- a/library/compiler-builtins/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm-test/src/run_cfg.rs @@ -22,13 +22,38 @@ static EXTENSIVE_ITER_OVERRIDE: LazyLock> = LazyLock::new(|| { /// Specific tests that need to have a reduced amount of iterations to complete in a reasonable /// amount of time. -/// -/// Contains the itentifier+generator combo to match on, plus the factor to reduce by. -const EXTEMELY_SLOW_TESTS: &[(Identifier, GeneratorKind, u64)] = &[ - (Identifier::Fmodf128, GeneratorKind::QuickSpaced, 50), - (Identifier::Fmodf128, GeneratorKind::Extensive, 50), +const EXTREMELY_SLOW_TESTS: &[SlowTest] = &[ + SlowTest { + ident: Identifier::Fmodf128, + gen_kind: GeneratorKind::Spaced, + extensive: false, + reduce_factor: 50, + }, + SlowTest { + ident: Identifier::Fmodf128, + gen_kind: GeneratorKind::Spaced, + extensive: true, + reduce_factor: 50, + }, ]; +/// A pattern to match a `CheckCtx`, plus a factor to reduce by. +struct SlowTest { + ident: Identifier, + gen_kind: GeneratorKind, + extensive: bool, + reduce_factor: u64, +} + +impl SlowTest { + /// True if the test in `CheckCtx` should be reduced by `reduce_factor`. + fn matches_ctx(&self, ctx: &CheckCtx) -> bool { + self.ident == ctx.fn_ident + && self.gen_kind == ctx.gen_kind + && self.extensive == ctx.extensive + } +} + /// Maximum number of iterations to run for a single routine. /// /// The default value of one greater than `u32::MAX` allows testing single-argument `f32` routines @@ -54,6 +79,7 @@ pub struct CheckCtx { /// Source of truth for tests. pub basis: CheckBasis, pub gen_kind: GeneratorKind, + pub extensive: bool, /// If specified, this value will override the value returned by [`iteration_count`]. pub override_iterations: Option, } @@ -69,12 +95,19 @@ impl CheckCtx { base_name_str: fn_ident.base_name().as_str(), basis, gen_kind, + extensive: false, override_iterations: None, }; ret.ulp = crate::default_ulp(&ret); ret } + /// Configure that this is an extensive test. + pub fn extensive(mut self, extensive: bool) -> Self { + self.extensive = extensive; + self + } + /// The number of input arguments for this function. pub fn input_count(&self) -> usize { self.fn_ident.math_op().rust_sig.args.len() @@ -100,14 +133,17 @@ pub enum CheckBasis { /// and quantity. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum GeneratorKind { + /// Extremes, zeros, nonstandard numbers, etc. EdgeCases, - Extensive, - QuickSpaced, + /// Spaced by logarithm (floats) or linear (integers). + Spaced, + /// Test inputs from an RNG. Random, + /// A provided test case list. List, } -/// A list of all functions that should get extensive tests. +/// A list of all functions that should get extensive tests, as configured by environment variable. /// /// This also supports the special test name `all` to run all tests, as well as `all_f16`, /// `all_f32`, `all_f64`, and `all_f128` to run all tests for a specific float type. @@ -216,17 +252,17 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { let random_iter_count = domain_iter_count / 100; let mut total_iterations = match ctx.gen_kind { - GeneratorKind::QuickSpaced => domain_iter_count, + GeneratorKind::Spaced if ctx.extensive => extensive_max_iterations(), + GeneratorKind::Spaced => domain_iter_count, GeneratorKind::Random => random_iter_count, - GeneratorKind::Extensive => extensive_max_iterations(), GeneratorKind::EdgeCases | GeneratorKind::List => { unimplemented!("shoudn't need `iteration_count` for {:?}", ctx.gen_kind) } }; // Larger float types get more iterations. - if t_env.large_float_ty && ctx.gen_kind != GeneratorKind::Extensive { - if ctx.gen_kind == GeneratorKind::Extensive { + if t_env.large_float_ty { + if ctx.extensive { // Extensive already has a pretty high test count. total_iterations *= 2; } else { @@ -244,13 +280,13 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { } // Some tests are significantly slower than others and need to be further reduced. - if let Some((_id, _gen, scale)) = EXTEMELY_SLOW_TESTS + if let Some(slow) = EXTREMELY_SLOW_TESTS .iter() - .find(|(id, generator, _scale)| *id == ctx.fn_ident && *generator == ctx.gen_kind) + .find(|slow| slow.matches_ctx(ctx)) { // However, do not override if the extensive iteration count has been manually set. - if !(ctx.gen_kind == GeneratorKind::Extensive && EXTENSIVE_ITER_OVERRIDE.is_some()) { - total_iterations /= scale; + if !(ctx.extensive && EXTENSIVE_ITER_OVERRIDE.is_some()) { + total_iterations /= slow.reduce_factor; } } @@ -279,7 +315,7 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { let total = ntests.pow(t_env.input_count.try_into().unwrap()); let seed_msg = match ctx.gen_kind { - GeneratorKind::QuickSpaced | GeneratorKind::Extensive => String::new(), + GeneratorKind::Spaced => String::new(), GeneratorKind::Random => { format!( " using `{SEED_ENV}={}`", @@ -327,8 +363,8 @@ pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { let extensive_range = (-0xfff)..=0xfffff; match ctx.gen_kind { - GeneratorKind::Extensive => extensive_range, - GeneratorKind::QuickSpaced | GeneratorKind::Random => non_extensive_range, + _ if ctx.extensive => extensive_range, + GeneratorKind::Spaced | GeneratorKind::Random => non_extensive_range, GeneratorKind::EdgeCases => extensive_range, GeneratorKind::List => unimplemented!("shoudn't need range for {:?}", ctx.gen_kind), } diff --git a/library/compiler-builtins/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm-test/tests/compare_built_musl.rs index 6ccbb6f4c51..86f3b8b711e 100644 --- a/library/compiler-builtins/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm-test/tests/compare_built_musl.rs @@ -65,7 +65,7 @@ macro_rules! musl_tests { $(#[$attr])* fn [< musl_quickspace_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::QuickSpaced); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Spaced); let cases = spaced::get_test_cases::(&ctx).0; musl_runner::(&ctx, cases, musl_math_sys::$fn_name); } diff --git a/library/compiler-builtins/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm-test/tests/multiprecision.rs index 80b2c78688e..60175ae6156 100644 --- a/library/compiler-builtins/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm-test/tests/multiprecision.rs @@ -55,7 +55,7 @@ macro_rules! mp_tests { $(#[$attr])* fn [< mp_quickspace_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::QuickSpaced); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Spaced); let cases = spaced::get_test_cases::(&ctx).0; mp_runner::(&ctx, cases); } diff --git a/library/compiler-builtins/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm-test/tests/z_extensive/run.rs index 59c806ce73e..f2ba6a4a0e3 100644 --- a/library/compiler-builtins/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm-test/tests/z_extensive/run.rs @@ -17,7 +17,6 @@ use rayon::prelude::*; use spaced::SpacedInput; const BASIS: CheckBasis = CheckBasis::Mpfr; -const GEN_KIND: GeneratorKind = GeneratorKind::Extensive; /// Run the extensive test suite. pub fn run() { @@ -77,7 +76,7 @@ where Op::RustArgs: SpacedInput + Send, { let test_name = format!("mp_extensive_{}", Op::NAME); - let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GEN_KIND); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Spaced).extensive(true); let skip = skip_extensive_test(&ctx); let runner = move || { -- cgit 1.4.1-3-g733a5 From 4d325e8b2cca0139370a809a76183a880db52b24 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 29 May 2025 21:22:47 +0000 Subject: ci: Allow for multiple icount benchmarks in the same run We don't actually need this for now, but eventually it would be nice to run icount benchmarks on multiple targets. Start tagging artifact names with the architecture, and allow passing `--tag` to `ci-util.py` in order to retrieve the correct one. --- library/compiler-builtins/.github/workflows/main.yaml | 12 ++++++++++-- library/compiler-builtins/ci/bench-icount.sh | 16 ++++++++++++++-- library/compiler-builtins/ci/ci-util.py | 17 +++++++++++++---- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 8e89cb47292..9f389d8b485 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -195,8 +195,14 @@ jobs: benchmarks: name: Benchmarks - runs-on: ubuntu-24.04 timeout-minutes: 20 + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-unknown-linux-gnu + os: ubuntu-24.04 + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@master with: @@ -215,12 +221,14 @@ jobs: cargo binstall -y iai-callgrind-runner --version "$iai_version" sudo apt-get install valgrind - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} - name: Run icount benchmarks env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} - run: ./ci/bench-icount.sh + run: ./ci/bench-icount.sh ${{ matrix.target }} - name: Upload the benchmark baseline uses: actions/upload-artifact@v4 diff --git a/library/compiler-builtins/ci/bench-icount.sh b/library/compiler-builtins/ci/bench-icount.sh index 4d93e257a6c..5b6974fe420 100755 --- a/library/compiler-builtins/ci/bench-icount.sh +++ b/library/compiler-builtins/ci/bench-icount.sh @@ -2,10 +2,21 @@ set -eux +target="${1:-}" + +if [ -z "$target" ]; then + host_target=$(rustc -vV | awk '/^host/ { print $2 }') + echo "Defaulted to host target $host_target" + target="$host_target" +fi + iai_home="iai-home" +# Use the arch as a tag to disambiguate artifacts +tag="$(echo "$target" | cut -d'-' -f1)" + # Download the baseline from master -./ci/ci-util.py locate-baseline --download --extract +./ci/ci-util.py locate-baseline --download --extract --tag "$tag" # Run benchmarks once function run_icount_benchmarks() { @@ -44,6 +55,7 @@ function run_icount_benchmarks() { # If this is for a pull request, ignore regressions if specified. ./ci/ci-util.py check-regressions --home "$iai_home" --allow-pr-override "$PR_NUMBER" else + # Disregard regressions after merge ./ci/ci-util.py check-regressions --home "$iai_home" || true fi } @@ -53,6 +65,6 @@ run_icount_benchmarks --features force-soft-floats -- --save-baseline=softfloat run_icount_benchmarks -- --save-baseline=hardfloat # Name and tar the new baseline -name="baseline-icount-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}" +name="baseline-icount-$tag-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}" echo "BASELINE_NAME=$name" >>"$GITHUB_ENV" tar cJf "$name.tar.xz" "$iai_home" diff --git a/library/compiler-builtins/ci/ci-util.py b/library/compiler-builtins/ci/ci-util.py index d785b2e9e1d..6c8b439805b 100755 --- a/library/compiler-builtins/ci/ci-util.py +++ b/library/compiler-builtins/ci/ci-util.py @@ -28,11 +28,14 @@ USAGE = cleandoc( Calculate a matrix of which functions had source change, print that as a JSON object. - locate-baseline [--download] [--extract] + locate-baseline [--download] [--extract] [--tag TAG] Locate the most recent benchmark baseline available in CI and, if flags specify, download and extract it. Never exits with nonzero status if downloading fails. + `--tag` can be specified to look for artifacts with a specific tag, such as + for a specific architecture. + Note that `--extract` will overwrite files in `iai-home`. check-regressions [--home iai-home] [--allow-pr-override pr_number] @@ -50,7 +53,7 @@ REPO_ROOT = Path(__file__).parent.parent GIT = ["git", "-C", REPO_ROOT] DEFAULT_BRANCH = "master" WORKFLOW_NAME = "CI" # Workflow that generates the benchmark artifacts -ARTIFACT_GLOB = "baseline-icount*" +ARTIFACT_PREFIX = "baseline-icount*" # Place this in a PR body to skip regression checks (must be at the start of a line). REGRESSION_DIRECTIVE = "ci: allow-regressions" # Place this in a PR body to skip extensive tests @@ -278,6 +281,7 @@ def locate_baseline(flags: list[str]) -> None: download = False extract = False + tag = "" while len(flags) > 0: match flags[0]: @@ -285,6 +289,9 @@ def locate_baseline(flags: list[str]) -> None: download = True case "--extract": extract = True + case "--tag": + tag = flags[1] + flags = flags[1:] case _: eprint(USAGE) exit(1) @@ -333,8 +340,10 @@ def locate_baseline(flags: list[str]) -> None: eprint("skipping download step") return + artifact_glob = f"{ARTIFACT_PREFIX}{f"-{tag}" if tag else ""}*" + sp.run( - ["gh", "run", "download", str(job_id), f"--pattern={ARTIFACT_GLOB}"], + ["gh", "run", "download", str(job_id), f"--pattern={artifact_glob}"], check=False, ) @@ -344,7 +353,7 @@ def locate_baseline(flags: list[str]) -> None: # Find the baseline with the most recent timestamp. GH downloads the files to e.g. # `some-dirname/some-dirname.tar.xz`, so just glob the whole thing together. - candidate_baselines = glob(f"{ARTIFACT_GLOB}/{ARTIFACT_GLOB}") + candidate_baselines = glob(f"{artifact_glob}/{artifact_glob}") if len(candidate_baselines) == 0: eprint("no possible baseline directories found") return -- cgit 1.4.1-3-g733a5 From 14db1b5b1c2b55dfa89c7b958e70efb936a33e7c Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Wed, 28 May 2025 21:22:21 +0000 Subject: jsondocck: command -> directive --- src/tools/jsondocck/src/config.rs | 2 +- src/tools/jsondocck/src/directive.rs | 44 +++++++++++++++++++----------------- src/tools/jsondocck/src/error.rs | 4 ++-- src/tools/jsondocck/src/main.rs | 30 ++++++++++++------------ 4 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/tools/jsondocck/src/config.rs b/src/tools/jsondocck/src/config.rs index 9b3ba3f3fbe..6bef37c2259 100644 --- a/src/tools/jsondocck/src/config.rs +++ b/src/tools/jsondocck/src/config.rs @@ -4,7 +4,7 @@ use getopts::Options; pub struct Config { /// The directory documentation output was generated in pub doc_dir: String, - /// The file documentation was generated for, with docck commands to check + /// The file documentation was generated for, with docck directives to check pub template: String, } diff --git a/src/tools/jsondocck/src/directive.rs b/src/tools/jsondocck/src/directive.rs index 8617379ed27..5269ffb469f 100644 --- a/src/tools/jsondocck/src/directive.rs +++ b/src/tools/jsondocck/src/directive.rs @@ -1,16 +1,18 @@ use std::borrow::Cow; + use serde_json::Value; + use crate::cache::Cache; #[derive(Debug)] -pub struct Command { - pub kind: CommandKind, +pub struct Directive { + pub kind: DirectiveKind, pub path: String, pub lineno: usize, } #[derive(Debug)] -pub enum CommandKind { +pub enum DirectiveKind { /// `//@ has ` /// /// Checks the path exists. @@ -55,16 +57,16 @@ pub enum CommandKind { Set { variable: String }, } -impl CommandKind { +impl DirectiveKind { /// Returns both the kind and the path. /// - /// Returns `None` if the command isn't from jsondocck (e.g. from compiletest). + /// Returns `None` if the directive isn't from jsondocck (e.g. from compiletest). pub fn parse<'a>( - command_name: &str, + directive_name: &str, negated: bool, args: &'a [String], ) -> Option<(Self, &'a str)> { - let kind = match (command_name, negated) { + let kind = match (directive_name, negated) { ("count", false) => { assert_eq!(args.len(), 2); let expected = args[1].parse().expect("invalid number for `count`"); @@ -104,11 +106,11 @@ impl CommandKind { _ => panic!("`//@ !has` must have 2 or 3 arguments, but got {args:?}"), }, - (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&command_name) => { + (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&directive_name) => { return None; } _ => { - panic!("Invalid command `//@ {}{command_name}`", if negated { "!" } else { "" }) + panic!("Invalid directive `//@ {}{directive_name}`", if negated { "!" } else { "" }) } }; @@ -116,22 +118,22 @@ impl CommandKind { } } -impl Command { - /// Performs the actual work of ensuring a command passes. +impl Directive { + /// Performs the actual work of ensuring a directive passes. pub fn check(&self, cache: &mut Cache) -> Result<(), String> { let matches = cache.select(&self.path); match &self.kind { - CommandKind::HasPath => { + DirectiveKind::HasPath => { if matches.is_empty() { return Err("matched to no values".to_owned()); } } - CommandKind::HasNotPath => { + DirectiveKind::HasNotPath => { if !matches.is_empty() { return Err(format!("matched to {matches:?}, but wanted no matches")); } } - CommandKind::HasValue { value } => { + DirectiveKind::HasValue { value } => { let want_value = string_to_value(value, cache); if !matches.contains(&want_value.as_ref()) { return Err(format!( @@ -139,7 +141,7 @@ impl Command { )); } } - CommandKind::HasNotValue { value } => { + DirectiveKind::HasNotValue { value } => { let wantnt_value = string_to_value(value, cache); if matches.contains(&wantnt_value.as_ref()) { return Err(format!( @@ -152,14 +154,14 @@ impl Command { } } - CommandKind::Is { value } => { + DirectiveKind::Is { value } => { let want_value = string_to_value(value, cache); let matched = get_one(&matches)?; if matched != want_value.as_ref() { return Err(format!("matched to {matched:?} but want {want_value:?}")); } } - CommandKind::IsNot { value } => { + DirectiveKind::IsNot { value } => { let wantnt_value = string_to_value(value, cache); let matched = get_one(&matches)?; if matched == wantnt_value.as_ref() { @@ -167,7 +169,7 @@ impl Command { } } - CommandKind::IsMany { values } => { + DirectiveKind::IsMany { values } => { // Serde json doesn't implement Ord or Hash for Value, so we must // use a Vec here. While in theory that makes setwize equality // O(n^2), in practice n will never be large enough to matter. @@ -187,7 +189,7 @@ impl Command { } } } - CommandKind::CountIs { expected } => { + DirectiveKind::CountIs { expected } => { if *expected != matches.len() { return Err(format!( "matched to `{matches:?}` with length {}, but expected length {expected}", @@ -195,7 +197,7 @@ impl Command { )); } } - CommandKind::Set { variable } => { + DirectiveKind::Set { variable } => { let value = get_one(&matches)?; let r = cache.variables.insert(variable.to_owned(), value.clone()); assert!(r.is_none(), "name collision: {variable:?} is duplicated"); @@ -227,4 +229,4 @@ fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> { } else { Cow::Owned(serde_json::from_str(s).expect(&format!("Cannot convert `{}` to json", s))) } -} \ No newline at end of file +} diff --git a/src/tools/jsondocck/src/error.rs b/src/tools/jsondocck/src/error.rs index 0a3e085b405..eb2932f7803 100644 --- a/src/tools/jsondocck/src/error.rs +++ b/src/tools/jsondocck/src/error.rs @@ -1,7 +1,7 @@ -use crate::Command; +use crate::Directive; #[derive(Debug)] pub struct CkError { pub message: String, - pub command: Command, + pub directive: Directive, } diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 80557b68243..d84be4d3a3a 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -11,7 +11,7 @@ mod error; use cache::Cache; use config::parse_config; -use directive::{Command, CommandKind}; +use directive::{Directive, DirectiveKind}; use error::CkError; fn main() -> ExitCode { @@ -19,14 +19,14 @@ fn main() -> ExitCode { let mut failed = Vec::new(); let mut cache = Cache::new(&config); - let Ok(commands) = get_commands(&config.template) else { + let Ok(directives) = get_directives(&config.template) else { eprintln!("Jsondocck failed for {}", &config.template); return ExitCode::FAILURE; }; - for command in commands { - if let Err(message) = command.check( &mut cache) { - failed.push(CkError { command, message }); + for directive in directives { + if let Err(message) = directive.check(&mut cache) { + failed.push(CkError { directive, message }); } } @@ -34,7 +34,7 @@ fn main() -> ExitCode { ExitCode::SUCCESS } else { for i in failed { - eprintln!("{}:{}, command failed", config.template, i.command.lineno); + eprintln!("{}:{}, directive failed", config.template, i.directive.lineno); eprintln!("{}", i.message) } ExitCode::FAILURE @@ -47,7 +47,7 @@ static LINE_PATTERN: LazyLock = LazyLock::new(|| { ^\s* //@\s+ (?P!?) - (?P[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*) + (?P[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*) (?P.*)$ "#, ) @@ -70,12 +70,12 @@ static DEPRECATED_LINE_PATTERN: LazyLock = LazyLock::new(|| { }); fn print_err(msg: &str, lineno: usize) { - eprintln!("Invalid command: {} on line {}", msg, lineno) + eprintln!("Invalid directive: {} on line {}", msg, lineno) } -/// Get a list of commands from a file. -fn get_commands(template: &str) -> Result, ()> { - let mut commands = Vec::new(); +/// Get a list of directives from a file. +fn get_directives(template: &str) -> Result, ()> { + let mut directives = Vec::new(); let mut errors = false; let file = fs::read_to_string(template).unwrap(); @@ -83,7 +83,7 @@ fn get_commands(template: &str) -> Result, ()> { let lineno = lineno + 1; if DEPRECATED_LINE_PATTERN.is_match(line) { - print_err("Deprecated command syntax, replace `// @` with `//@ `", lineno); + print_err("Deprecated directive syntax, replace `// @` with `//@ `", lineno); errors = true; continue; } @@ -101,10 +101,10 @@ fn get_commands(template: &str) -> Result, ()> { continue; }; - if let Some((kind, path)) = CommandKind::parse(&cap["cmd"], negated, &args) { - commands.push(Command { kind, lineno, path: path.to_owned() }) + if let Some((kind, path)) = DirectiveKind::parse(&cap["directive"], negated, &args) { + directives.push(Directive { kind, lineno, path: path.to_owned() }) } } - if !errors { Ok(commands) } else { Err(()) } + if !errors { Ok(directives) } else { Err(()) } } -- cgit 1.4.1-3-g733a5 From 0f1579b4bb21af7a79331a1a26dc2370ec182fc4 Mon Sep 17 00:00:00 2001 From: Petr Sumbera Date: Tue, 4 Mar 2025 12:19:22 +0000 Subject: build dist for x86_64-pc-solaris and sparcv9-sun-solaris --- .../host-x86_64/dist-sparcv9-solaris/Dockerfile | 36 +++++ .../docker/host-x86_64/dist-various-2/Dockerfile | 11 -- .../dist-various-2/build-solaris-toolchain.sh | 111 -------------- .../host-x86_64/dist-x86_64-illumos/Dockerfile | 1 + .../host-x86_64/dist-x86_64-solaris/Dockerfile | 36 +++++ src/ci/docker/scripts/illumos-toolchain.sh | 52 +------ src/ci/docker/scripts/shared.sh | 34 +++++ src/ci/docker/scripts/solaris-toolchain.sh | 162 +++++++++++++++++++++ src/ci/github-actions/jobs.yml | 6 + src/doc/rustc/src/platform-support.md | 4 +- src/doc/rustc/src/platform-support/solaris.md | 4 +- 11 files changed, 285 insertions(+), 172 deletions(-) create mode 100644 src/ci/docker/host-x86_64/dist-sparcv9-solaris/Dockerfile delete mode 100755 src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh create mode 100644 src/ci/docker/host-x86_64/dist-x86_64-solaris/Dockerfile create mode 100644 src/ci/docker/scripts/solaris-toolchain.sh diff --git a/src/ci/docker/host-x86_64/dist-sparcv9-solaris/Dockerfile b/src/ci/docker/host-x86_64/dist-sparcv9-solaris/Dockerfile new file mode 100644 index 00000000000..f7852c6364d --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-sparcv9-solaris/Dockerfile @@ -0,0 +1,36 @@ +FROM ubuntu:22.04 + +COPY scripts/cross-apt-packages.sh /tmp/ +RUN bash /tmp/cross-apt-packages.sh + +# Required gcc dependencies. +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + libgmp-dev \ + libmpfr-dev \ + libmpc-dev \ + && rm -rf /var/lib/apt/lists/* + +COPY scripts/shared.sh /tmp/ +COPY scripts/solaris-toolchain.sh /tmp/ + +RUN bash /tmp/solaris-toolchain.sh sparcv9 sysroot +RUN bash /tmp/solaris-toolchain.sh sparcv9 binutils +RUN bash /tmp/solaris-toolchain.sh sparcv9 gcc + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +COPY scripts/cmake.sh /scripts/ +RUN /scripts/cmake.sh + +ENV \ + AR_sparcv9_sun_solaris=sparcv9-solaris-ar \ + RANLIB_sparcv9_sun_solaris=sparcv9-solaris-ranlib \ + CC_sparcv9_sun_solaris=sparcv9-solaris-gcc \ + CXX_sparcv9_sun_solaris=sparcv9-solaris-g++ + +ENV HOSTS=sparcv9-sun-solaris + +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index 03ec77f507e..e1d83d36087 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -43,12 +43,6 @@ ENV \ CXX_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang++ \ CXXFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \ LDFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib" \ - AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \ - CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \ - CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \ - AR_x86_64_pc_solaris=x86_64-pc-solaris2.10-ar \ - CC_x86_64_pc_solaris=x86_64-pc-solaris2.10-gcc \ - CXX_x86_64_pc_solaris=x86_64-pc-solaris2.10-g++ \ CC_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-gcc-9 \ CXX_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-g++-9 \ AR_x86_64_fortanix_unknown_sgx=ar \ @@ -84,9 +78,6 @@ WORKDIR /tmp COPY scripts/shared.sh /tmp/ COPY scripts/build-fuchsia-toolchain.sh /tmp/ RUN /tmp/build-fuchsia-toolchain.sh -COPY host-x86_64/dist-various-2/build-solaris-toolchain.sh /tmp/ -RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386 pc -RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc sun COPY host-x86_64/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/ RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh @@ -118,8 +109,6 @@ ENV TARGETS=$TARGETS,wasm32-wasip1 ENV TARGETS=$TARGETS,wasm32-wasip1-threads ENV TARGETS=$TARGETS,wasm32-wasip2 ENV TARGETS=$TARGETS,wasm32v1-none -ENV TARGETS=$TARGETS,sparcv9-sun-solaris -ENV TARGETS=$TARGETS,x86_64-pc-solaris ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32 ENV TARGETS=$TARGETS,x86_64-fortanix-unknown-sgx ENV TARGETS=$TARGETS,nvptx64-nvidia-cuda diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh deleted file mode 100755 index d046b539036..00000000000 --- a/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env bash - -set -ex -source shared.sh - -ARCH=$1 -LIB_ARCH=$2 -APT_ARCH=$3 -MANUFACTURER=$4 -BINUTILS=2.28.1 -GCC=6.5.0 - -TARGET=${ARCH}-${MANUFACTURER}-solaris2.10 - -# First up, build binutils -mkdir binutils -cd binutils - -curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.xz | tar xJf - -mkdir binutils-build -cd binutils-build -hide_output ../binutils-$BINUTILS/configure --target=$TARGET -hide_output make -j10 -hide_output make install - -cd ../.. -rm -rf binutils - -# Next, download and install the relevant solaris packages -mkdir solaris -cd solaris - -dpkg --add-architecture $APT_ARCH -apt-get update -apt-get install -y --download-only \ - libc:$APT_ARCH \ - liblgrp:$APT_ARCH \ - libm-dev:$APT_ARCH \ - libpthread:$APT_ARCH \ - libresolv:$APT_ARCH \ - librt:$APT_ARCH \ - libsendfile:$APT_ARCH \ - libsocket:$APT_ARCH \ - system-crt:$APT_ARCH \ - system-header:$APT_ARCH - -for deb in /var/cache/apt/archives/*$APT_ARCH.deb; do - dpkg -x $deb . -done -apt-get clean - -# The -dev packages are not available from the apt repository we're using. -# However, those packages are just symlinks from *.so to *.so.. -# This makes all those symlinks. -for lib in $(find -name '*.so.*'); do - target=${lib%.so.*}.so - ln -s ${lib##*/} $target || echo "warning: silenced error symlinking $lib" -done - -# Remove Solaris 11 functions that are optionally used by libbacktrace. -# This is for Solaris 10 compatibility. -rm usr/include/link.h -patch -p0 << 'EOF' ---- usr/include/string.h -+++ usr/include/string10.h -@@ -93 +92,0 @@ --extern size_t strnlen(const char *, size_t); -EOF - -mkdir /usr/local/$TARGET/usr -mv usr/include /usr/local/$TARGET/usr/include -mv usr/lib/$LIB_ARCH/* /usr/local/$TARGET/lib -mv lib/$LIB_ARCH/* /usr/local/$TARGET/lib - -ln -s usr/include /usr/local/$TARGET/sys-include -ln -s usr/include /usr/local/$TARGET/include - -cd .. -rm -rf solaris - -# Finally, download and build gcc to target solaris -mkdir gcc -cd gcc - -curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.xz | tar xJf - -cd gcc-$GCC - -mkdir ../gcc-build -cd ../gcc-build -hide_output ../gcc-$GCC/configure \ - --enable-languages=c,c++ \ - --target=$TARGET \ - --with-gnu-as \ - --with-gnu-ld \ - --disable-multilib \ - --disable-nls \ - --disable-libgomp \ - --disable-libquadmath \ - --disable-libssp \ - --disable-libvtv \ - --disable-libcilkrts \ - --disable-libada \ - --disable-libsanitizer \ - --disable-libquadmath-support \ - --disable-lto - -hide_output make -j10 -hide_output make install - -cd ../.. -rm -rf gcc diff --git a/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile index 55fefd2b725..37a8dc56a5f 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile @@ -15,6 +15,7 @@ RUN apt-get update && \ python2.7 \ && rm -rf /var/lib/apt/lists/* +COPY scripts/shared.sh /tmp/ COPY scripts/illumos-toolchain.sh /tmp/ RUN bash /tmp/illumos-toolchain.sh x86_64 sysroot diff --git a/src/ci/docker/host-x86_64/dist-x86_64-solaris/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-solaris/Dockerfile new file mode 100644 index 00000000000..4d77f0aad26 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-x86_64-solaris/Dockerfile @@ -0,0 +1,36 @@ +FROM ubuntu:22.04 + +COPY scripts/cross-apt-packages.sh /tmp/ +RUN bash /tmp/cross-apt-packages.sh + +# Required gcc dependencies. +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + libgmp-dev \ + libmpfr-dev \ + libmpc-dev \ + && rm -rf /var/lib/apt/lists/* + +COPY scripts/shared.sh /tmp/ +COPY scripts/solaris-toolchain.sh /tmp/ + +RUN bash /tmp/solaris-toolchain.sh x86_64 sysroot +RUN bash /tmp/solaris-toolchain.sh x86_64 binutils +RUN bash /tmp/solaris-toolchain.sh x86_64 gcc + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +COPY scripts/cmake.sh /scripts/ +RUN /scripts/cmake.sh + +ENV \ + AR_x86_64_pc_solaris=x86_64-solaris-ar \ + RANLIB_x86_64_pc_solaris=x86_64-solaris-ranlib \ + CC_x86_64_pc_solaris=x86_64-solaris-gcc \ + CXX_x86_64_pc_solaris=x86_64-solaris-g++ + +ENV HOSTS=x86_64-pc-solaris + +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/scripts/illumos-toolchain.sh b/src/ci/docker/scripts/illumos-toolchain.sh index 0b2c09b3eed..7a3ca875554 100644 --- a/src/ci/docker/scripts/illumos-toolchain.sh +++ b/src/ci/docker/scripts/illumos-toolchain.sh @@ -4,6 +4,8 @@ set -o errexit set -o pipefail set -o xtrace +source /tmp/shared.sh + ARCH="$1" PHASE="$2" @@ -59,52 +61,13 @@ BINUTILS_TAR="$BINUTILS_BASE.tar.bz2" BINUTILS_URL="https://ftp.gnu.org/gnu/binutils/$BINUTILS_TAR" -download_file() { - local file="$1" - local url="$2" - local sum="$3" - - while :; do - if [[ -f "$file" ]]; then - if ! h="$(sha256sum "$file" | awk '{ print $1 }')"; then - printf 'ERROR: reading hash\n' >&2 - exit 1 - fi - - if [[ "$h" == "$sum" ]]; then - return 0 - fi - - printf 'WARNING: hash mismatch: %s != expected %s\n' \ - "$h" "$sum" >&2 - rm -f "$file" - fi - - printf 'Downloading: %s\n' "$url" - if ! curl -f -L -o "$file" "$url"; then - rm -f "$file" - sleep 1 - fi - done -} - - case "$PHASE" in sysroot) - download_file "/tmp/$SYSROOT_TAR" "$SYSROOT_URL" "$SYSROOT_SUM" - mkdir -p "$SYSROOT_DIR" - cd "$SYSROOT_DIR" - tar -xzf "/tmp/$SYSROOT_TAR" - rm -f "/tmp/$SYSROOT_TAR" + download_tar_and_extract_into_dir "$SYSROOT_URL" "$SYSROOT_SUM" "$SYSROOT_DIR" ;; binutils) - download_file "/tmp/$BINUTILS_TAR" "$BINUTILS_URL" "$BINUTILS_SUM" - mkdir -p /ws/src/binutils - cd /ws/src/binutils - tar -xjf "/tmp/$BINUTILS_TAR" - rm -f "/tmp/$BINUTILS_TAR" - + download_tar_and_extract_into_dir "$BINUTILS_URL" "$BINUTILS_SUM" /ws/src/binutils mkdir -p /ws/build/binutils cd /ws/build/binutils "/ws/src/binutils/$BINUTILS_BASE/configure" \ @@ -123,12 +86,7 @@ binutils) ;; gcc) - download_file "/tmp/$GCC_TAR" "$GCC_URL" "$GCC_SUM" - mkdir -p /ws/src/gcc - cd /ws/src/gcc - tar -xJf "/tmp/$GCC_TAR" - rm -f "/tmp/$GCC_TAR" - + download_tar_and_extract_into_dir "$GCC_URL" "$GCC_SUM" /ws/src/gcc mkdir -p /ws/build/gcc cd /ws/build/gcc export CFLAGS='-fPIC' diff --git a/src/ci/docker/scripts/shared.sh b/src/ci/docker/scripts/shared.sh index 9969659088d..6efdbb2070d 100644 --- a/src/ci/docker/scripts/shared.sh +++ b/src/ci/docker/scripts/shared.sh @@ -40,3 +40,37 @@ function retry { } done } + +download_tar_and_extract_into_dir() { + local url="$1" + local sum="$2" + local dir="$3" + local file=$(mktemp -u) + + while :; do + if [[ -f "$file" ]]; then + if ! h="$(sha256sum "$file" | awk '{ print $1 }')"; then + printf 'ERROR: reading hash\n' >&2 + exit 1 + fi + + if [[ "$h" == "$sum" ]]; then + break + fi + + printf 'WARNING: hash mismatch: %s != expected %s\n' "$h" "$sum" >&2 + rm -f "$file" + fi + + printf 'Downloading: %s\n' "$url" + if ! curl -f -L -o "$file" "$url"; then + rm -f "$file" + sleep 1 + fi + done + + mkdir -p "$dir" + cd "$dir" + tar -xf "$file" + rm -f "$file" +} diff --git a/src/ci/docker/scripts/solaris-toolchain.sh b/src/ci/docker/scripts/solaris-toolchain.sh new file mode 100644 index 00000000000..82f0f105523 --- /dev/null +++ b/src/ci/docker/scripts/solaris-toolchain.sh @@ -0,0 +1,162 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +set -o xtrace + +source /tmp/shared.sh + +ARCH="$1" +PHASE="$2" + +JOBS="$(getconf _NPROCESSORS_ONLN)" + +case "$ARCH" in +x86_64) + SYSROOT_MACH='i386' + ;; +sparcv9) + SYSROOT_MACH='sparc' + ;; +*) + printf 'ERROR: unknown architecture: %s\n' "$ARCH" + exit 1 +esac + +BUILD_TARGET="$ARCH-pc-solaris2.11" + +# +# The illumos and the Solaris build both use the same GCC-level host triple, +# though different versions of GCC are used and with different configuration +# options. To ensure as little accidental cross-pollination as possible, we +# build the illumos toolchain in a specific directory tree and just symlink the +# expected tools into /usr/local/bin at the end. We omit /usr/local/bin from +# PATH here for similar reasons. +# +PREFIX="/opt/solaris/$ARCH" +export PATH="$PREFIX/bin:/usr/bin:/bin:/usr/sbin:/sbin" + +# +# NOTE: The compiler version selected here is more specific than might appear. +# GCC 7.X releases do not appear to cross-compile correctly for Solaris +# targets, at least insofar as they refuse to enable TLS in libstdc++. When +# changing the GCC version in future, one must carefully verify that TLS is +# enabled in all of the static libraries we intend to include in output +# binaries. +# +GCC_VERSION='8.4.0' +GCC_SUM='e30a6e52d10e1f27ed55104ad233c30bd1e99cfb5ff98ab022dc941edd1b2dd4' +GCC_BASE="gcc-$GCC_VERSION" +GCC_TAR="gcc-$GCC_VERSION.tar.xz" +GCC_URL="https://ci-mirrors.rust-lang.org/rustc/$GCC_TAR" + +SYSROOT_VER='2025-02-21' +if [ $ARCH = "x86_64" ]; then +SYSROOT_SUM='e82b78c14464cc2dc71f3cdab312df3dd63441d7c23eeeaf34d41d8b947688d3' +SYSROOT_TAR="solaris-11.4.42.111.0-i386-sysroot-v$SYSROOT_VER.tar.bz2" +SYSROOT_DIR="$PREFIX/sysroot-x86_64" +else +SYSROOT_SUM='e249a7ef781b9b3297419bd014fa0574800703981d84e113d6af3a897a8b4ffc' +SYSROOT_TAR="solaris-11.4.42.111.0-sparc-sysroot-v$SYSROOT_VER.tar.bz2" +SYSROOT_DIR="$PREFIX/sysroot-sparcv9" +fi +SYSROOT_URL="https://ci-mirrors.rust-lang.org/rustc/$SYSROOT_TAR" + +BINUTILS_VERSION='2.44' +BINUTILS_SUM='ce2017e059d63e67ddb9240e9d4ec49c2893605035cd60e92ad53177f4377237' +BINUTILS_BASE="binutils-$BINUTILS_VERSION" +BINUTILS_TAR="$BINUTILS_BASE.tar.xz" +BINUTILS_URL="https://ci-mirrors.rust-lang.org/rustc/$BINUTILS_TAR" + + +case "$PHASE" in +sysroot) + download_tar_and_extract_into_dir "$SYSROOT_URL" "$SYSROOT_SUM" "$SYSROOT_DIR" + ;; + +binutils) + download_tar_and_extract_into_dir "$BINUTILS_URL" "$BINUTILS_SUM" /ws/src/binutils + cat > binutils.patch < 1 ++ || (vernum > 1 && strcmp(name, "logb") != 0 + && (!bfd_is_abs_section (sec) + || bed->is_function_type (ELF_ST_TYPE (isym->st_info))))) + { +EOF + f=binutils-$BINUTILS_VERSION/bfd/elflink.c && expand -t 4 "$f" > "$f.exp" + mv binutils-$BINUTILS_VERSION/bfd/elflink.c.exp binutils-$BINUTILS_VERSION/bfd/elflink.c + patch binutils-$BINUTILS_VERSION/bfd/elflink.c < binutils.patch + rm binutils.patch + + mkdir -p /ws/build/binutils + cd /ws/build/binutils + "/ws/src/binutils/$BINUTILS_BASE/configure" \ + --prefix="$PREFIX" \ + --target="$BUILD_TARGET" \ + --program-prefix="$ARCH-solaris-" \ + --with-sysroot="$SYSROOT_DIR" + + make -j "$JOBS" + + mkdir -p "$PREFIX" + make install + + cd + rm -rf /ws/src/binutils /ws/build/binutils + ;; + +gcc) + download_tar_and_extract_into_dir "$GCC_URL" "$GCC_SUM" /ws/src/gcc + mkdir -p /ws/build/gcc + cd /ws/build/gcc + export CFLAGS='-fPIC' + export CXXFLAGS='-fPIC' + export CXXFLAGS_FOR_TARGET='-fPIC' + export CFLAGS_FOR_TARGET='-fPIC' + "/ws/src/gcc/$GCC_BASE/configure" \ + --prefix="$PREFIX" \ + --target="$BUILD_TARGET" \ + --program-prefix="$ARCH-solaris-" \ + --with-sysroot="$SYSROOT_DIR" \ + --with-gnu-as \ + --with-gnu-ld \ + --disable-nls \ + --disable-libgomp \ + --disable-libquadmath \ + --disable-libssp \ + --disable-libvtv \ + --disable-libcilkrts \ + --disable-libada \ + --disable-libsanitizer \ + --disable-libquadmath-support \ + --disable-shared \ + --enable-tls + + make -j "$JOBS" + + mkdir -p "$PREFIX" + make install + + # + # Link toolchain commands into /usr/local/bin so that cmake and others + # can find them: + # + (cd "$PREFIX/bin" && ls -U) | grep "^$ARCH-solaris-" | + xargs -t -I% ln -s "$PREFIX/bin/%" '/usr/local/bin/' + + cd + rm -rf /ws/src/gcc /ws/build/gcc + ;; + +*) + printf 'ERROR: unknown phase "%s"\n' "$PHASE" >&2 + exit 100 + ;; +esac diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index f9a46396630..f133425b4f5 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -254,6 +254,12 @@ auto: - name: dist-x86_64-netbsd <<: *job-linux-4c + - name: dist-x86_64-solaris + <<: *job-linux-4c + + - name: dist-sparcv9-solaris + <<: *job-linux-4c + # The i686-gnu job is split into multiple jobs to run tests in parallel. # i686-gnu-1 skips tests that run in i686-gnu-2. - name: i686-gnu-1 diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 60002a5f9e5..e7dfaaf4fd5 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -110,6 +110,8 @@ target | notes `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3 [`x86_64-unknown-linux-ohos`](platform-support/openharmony.md) | x86_64 OpenHarmony [`x86_64-unknown-netbsd`](platform-support/netbsd.md) | NetBSD/amd64 +[`x86_64-pc-solaris`](platform-support/solaris.md) | 64-bit x86 Solaris 11.4 +[`sparcv9-sun-solaris`](platform-support/solaris.md) | SPARC V9 Solaris 11.4 ## Tier 2 without Host Tools @@ -183,7 +185,6 @@ target | std | notes `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA) `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23) -[`sparcv9-sun-solaris`](platform-support/solaris.md) | ✓ | SPARC V9 Solaris 11.4 [`thumbv6m-none-eabi`](platform-support/thumbv6m-none-eabi.md) | * | Bare Armv6-M [`thumbv7em-none-eabi`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M [`thumbv7em-none-eabihf`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M, hardfloat @@ -203,7 +204,6 @@ target | std | notes [`x86_64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ | Mac Catalyst on x86_64 [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX [`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android -[`x86_64-pc-solaris`](platform-support/solaris.md) | ✓ | 64-bit x86 Solaris 11.4 [`x86_64-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ✓ | 64-bit x86 MinGW (Windows 10+), LLVM ABI [`x86_64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | 64-bit x86 Fuchsia `x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27) diff --git a/src/doc/rustc/src/platform-support/solaris.md b/src/doc/rustc/src/platform-support/solaris.md index c22b5c24c12..1b2372eaa0e 100644 --- a/src/doc/rustc/src/platform-support/solaris.md +++ b/src/doc/rustc/src/platform-support/solaris.md @@ -12,7 +12,9 @@ Rust for Solaris operating system. ## Requirements -Binary built for this target is expected to run on sparcv9 or x86_64, and Solaris 11.4. +The `sparcv9-sun-solaris` and `x86_64-pc-solaris` targets are Tier 2 with host tools. + +Binary built for these targets are expected to run on sparcv9 or x86_64, and Solaris 11.4. ## Testing -- cgit 1.4.1-3-g733a5 From 1b809b73f68d0890b0cc785f42ceb0e8e3e4f4ac Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 30 May 2025 14:38:42 +0200 Subject: Add some more `hir_expand::files` conversions --- .../rust-analyzer/crates/hir-expand/src/files.rs | 52 +++++++++++++- .../rust-analyzer/crates/hir-expand/src/lib.rs | 18 +++-- .../hir-expand/src/prettify_macro_expansion_.rs | 80 ++++++++++++---------- src/tools/rust-analyzer/crates/mbe/src/tests.rs | 3 +- src/tools/rust-analyzer/crates/span/src/lib.rs | 5 +- .../syntax-bridge/src/prettify_macro_expansion.rs | 43 ++++++++---- 6 files changed, 137 insertions(+), 64 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs index 321ee8feb9a..8024823cbc5 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs @@ -42,6 +42,49 @@ impl FilePosition { FilePositionWrapper { file_id: self.file_id.file_id(db), offset: self.offset } } } + +impl From for HirFileRange { + fn from(value: FileRange) -> Self { + HirFileRange { file_id: value.file_id.into(), range: value.range } + } +} + +impl From for HirFilePosition { + fn from(value: FilePosition) -> Self { + HirFilePosition { file_id: value.file_id.into(), offset: value.offset } + } +} + +impl FilePositionWrapper { + pub fn with_edition(self, db: &dyn ExpandDatabase, edition: span::Edition) -> FilePosition { + FilePositionWrapper { + file_id: EditionedFileId::new(db, self.file_id, edition), + offset: self.offset, + } + } +} + +impl FileRangeWrapper { + pub fn with_edition(self, db: &dyn ExpandDatabase, edition: span::Edition) -> FileRange { + FileRangeWrapper { + file_id: EditionedFileId::new(db, self.file_id, edition), + range: self.range, + } + } +} + +impl InFileWrapper { + pub fn with_edition(self, db: &dyn ExpandDatabase, edition: span::Edition) -> InRealFile { + InRealFile { file_id: EditionedFileId::new(db, self.file_id, edition), value: self.value } + } +} + +impl HirFileRange { + pub fn file_range(self) -> Option { + Some(FileRange { file_id: self.file_id.file_id()?, range: self.range }) + } +} + #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub struct FileRangeWrapper { pub file_id: FileKind, @@ -194,6 +237,9 @@ impl InFileWrapper { pub fn syntax(&self) -> InFileWrapper { self.with_value(self.value.syntax()) } + pub fn node_file_range(&self) -> FileRangeWrapper { + FileRangeWrapper { file_id: self.file_id, range: self.value.syntax().text_range() } + } } impl InFileWrapper { @@ -204,9 +250,9 @@ impl InFileWrapper { } // region:specific impls -impl> InRealFile { - pub fn file_range(&self) -> FileRange { - FileRange { file_id: self.file_id, range: self.value.borrow().text_range() } +impl> InFileWrapper { + pub fn file_range(&self) -> FileRangeWrapper { + FileRangeWrapper { file_id: self.file_id, range: self.value.borrow().text_range() } } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index d844d8f41ee..6ecac1463f5 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -392,6 +392,10 @@ impl HirFileId { } } + pub fn call_node(self, db: &dyn ExpandDatabase) -> Option> { + Some(db.lookup_intern_macro_call(self.macro_file()?).to_node(db)) + } + pub fn as_builtin_derive_attr_node( &self, db: &dyn ExpandDatabase, @@ -848,7 +852,10 @@ impl ExpansionInfo { map_node_range_up(db, &self.exp_map, range) } - /// Maps up the text range out of the expansion into is macro call. + /// Maps up the text range out of the expansion into its macro call. + /// + /// Note that this may return multiple ranges as we lose the precise association between input to output + /// and as such we may consider inputs that are unrelated. pub fn map_range_up_once( &self, db: &dyn ExpandDatabase, @@ -864,11 +871,10 @@ impl ExpansionInfo { InFile { file_id, value: smallvec::smallvec![span.range + anchor_offset] } } SpanMap::ExpansionSpanMap(arg_map) => { - let arg_range = self - .arg - .value - .as_ref() - .map_or_else(|| TextRange::empty(TextSize::from(0)), |it| it.text_range()); + let Some(arg_node) = &self.arg.value else { + return InFile::new(self.arg.file_id, smallvec::smallvec![]); + }; + let arg_range = arg_node.text_range(); InFile::new( self.arg.file_id, arg_map diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs b/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs index 11cc434c2d8..6134c3a36b9 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs @@ -20,42 +20,46 @@ pub fn prettify_macro_expansion( let span_offset = syn.text_range().start(); let target_crate = target_crate_id.data(db); let mut syntax_ctx_id_to_dollar_crate_replacement = FxHashMap::default(); - syntax_bridge::prettify_macro_expansion::prettify_macro_expansion(syn, &mut |dollar_crate| { - let ctx = span_map.span_at(dollar_crate.text_range().start() + span_offset).ctx; - let replacement = - syntax_ctx_id_to_dollar_crate_replacement.entry(ctx).or_insert_with(|| { - let macro_call_id = - ctx.outer_expn(db).expect("`$crate` cannot come from `SyntaxContextId::ROOT`"); - let macro_call = db.lookup_intern_macro_call(macro_call_id.into()); - let macro_def_crate = macro_call.def.krate; - // First, if this is the same crate as the macro, nothing will work but `crate`. - // If not, if the target trait has the macro's crate as a dependency, using the dependency name - // will work in inserted code and match the user's expectation. - // If not, the crate's display name is what the dependency name is likely to be once such dependency - // is inserted, and also understandable to the user. - // Lastly, if nothing else found, resort to leaving `$crate`. - if target_crate_id == macro_def_crate { - make::tokens::crate_kw() - } else if let Some(dep) = - target_crate.dependencies.iter().find(|dep| dep.crate_id == macro_def_crate) - { - make::tokens::ident(dep.name.as_str()) - } else if let Some(crate_name) = ¯o_def_crate.extra_data(db).display_name { - make::tokens::ident(crate_name.crate_name().as_str()) - } else { - return dollar_crate.clone(); - } - }); - if replacement.text() == "$crate" { - // The parent may have many children, and looking for the token may yield incorrect results. - return dollar_crate.clone(); - } - // We need to `clone_subtree()` but rowan doesn't provide such operation for tokens. - let parent = replacement.parent().unwrap().clone_subtree().clone_for_update(); - parent - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|it| it.kind() == replacement.kind()) - .unwrap() - }) + syntax_bridge::prettify_macro_expansion::prettify_macro_expansion( + syn, + &mut |dollar_crate| { + let ctx = span_map.span_at(dollar_crate.text_range().start() + span_offset).ctx; + let replacement = + syntax_ctx_id_to_dollar_crate_replacement.entry(ctx).or_insert_with(|| { + let macro_call_id = ctx + .outer_expn(db) + .expect("`$crate` cannot come from `SyntaxContextId::ROOT`"); + let macro_call = db.lookup_intern_macro_call(macro_call_id.into()); + let macro_def_crate = macro_call.def.krate; + // First, if this is the same crate as the macro, nothing will work but `crate`. + // If not, if the target trait has the macro's crate as a dependency, using the dependency name + // will work in inserted code and match the user's expectation. + // If not, the crate's display name is what the dependency name is likely to be once such dependency + // is inserted, and also understandable to the user. + // Lastly, if nothing else found, resort to leaving `$crate`. + if target_crate_id == macro_def_crate { + make::tokens::crate_kw() + } else if let Some(dep) = + target_crate.dependencies.iter().find(|dep| dep.crate_id == macro_def_crate) + { + make::tokens::ident(dep.name.as_str()) + } else if let Some(crate_name) = ¯o_def_crate.extra_data(db).display_name { + make::tokens::ident(crate_name.crate_name().as_str()) + } else { + return dollar_crate.clone(); + } + }); + if replacement.text() == "$crate" { + // The parent may have many children, and looking for the token may yield incorrect results. + return None; + } + // We need to `clone_subtree()` but rowan doesn't provide such operation for tokens. + let parent = replacement.parent().unwrap().clone_subtree().clone_for_update(); + parent + .children_with_tokens() + .filter_map(NodeOrToken::into_token) + .find(|it| it.kind() == replacement.kind()) + }, + |_| (), + ) } diff --git a/src/tools/rust-analyzer/crates/mbe/src/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/tests.rs index 3369dfff281..769455faac0 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/tests.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/tests.rs @@ -74,7 +74,8 @@ fn check_( "{}", syntax_bridge::prettify_macro_expansion::prettify_macro_expansion( node.syntax_node(), - &mut |it| it.clone() + &mut |_| None, + |_| () ) ); expect.assert_eq(&expect_res); diff --git a/src/tools/rust-analyzer/crates/span/src/lib.rs b/src/tools/rust-analyzer/crates/span/src/lib.rs index 54f90908f36..f81648ac42c 100644 --- a/src/tools/rust-analyzer/crates/span/src/lib.rs +++ b/src/tools/rust-analyzer/crates/span/src/lib.rs @@ -112,7 +112,10 @@ pub struct EditionedFileId(u32); impl fmt::Debug for EditionedFileId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("EditionedFileId").field(&self.file_id()).field(&self.edition()).finish() + f.debug_tuple("EditionedFileId") + .field(&self.file_id().index()) + .field(&self.edition()) + .finish() } } diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/prettify_macro_expansion.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/prettify_macro_expansion.rs index e815e07d80a..0a5c8df0d0a 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/prettify_macro_expansion.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/prettify_macro_expansion.rs @@ -7,6 +7,13 @@ use syntax::{ ted::{self, Position}, }; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PrettifyWsKind { + Space, + Indent(usize), + Newline, +} + /// Renders a [`SyntaxNode`] with whitespace inserted between tokens that require them. /// /// This is an internal API that is only exported because `mbe` needs it for tests and cannot depend @@ -15,7 +22,8 @@ use syntax::{ #[deprecated = "use `hir_expand::prettify_macro_expansion()` instead"] pub fn prettify_macro_expansion( syn: SyntaxNode, - dollar_crate_replacement: &mut dyn FnMut(&SyntaxToken) -> SyntaxToken, + dollar_crate_replacement: &mut dyn FnMut(&SyntaxToken) -> Option, + inspect_mods: impl FnOnce(&[(Position, PrettifyWsKind)]), ) -> SyntaxNode { let mut indent = 0; let mut last: Option = None; @@ -27,14 +35,12 @@ pub fn prettify_macro_expansion( let after = Position::after; let do_indent = |pos: fn(_) -> Position, token: &SyntaxToken, indent| { - (pos(token.clone()), make::tokens::whitespace(&" ".repeat(4 * indent))) - }; - let do_ws = |pos: fn(_) -> Position, token: &SyntaxToken| { - (pos(token.clone()), make::tokens::single_space()) - }; - let do_nl = |pos: fn(_) -> Position, token: &SyntaxToken| { - (pos(token.clone()), make::tokens::single_newline()) + (pos(token.clone()), PrettifyWsKind::Indent(indent)) }; + let do_ws = + |pos: fn(_) -> Position, token: &SyntaxToken| (pos(token.clone()), PrettifyWsKind::Space); + let do_nl = + |pos: fn(_) -> Position, token: &SyntaxToken| (pos(token.clone()), PrettifyWsKind::Newline); for event in syn.preorder_with_tokens() { let token = match event { @@ -46,20 +52,19 @@ pub fn prettify_macro_expansion( ) => { if indent > 0 { - mods.push(( - Position::after(node.clone()), - make::tokens::whitespace(&" ".repeat(4 * indent)), - )); + mods.push((Position::after(node.clone()), PrettifyWsKind::Indent(indent))); } if node.parent().is_some() { - mods.push((Position::after(node), make::tokens::single_newline())); + mods.push((Position::after(node), PrettifyWsKind::Newline)); } continue; } _ => continue, }; if token.kind() == SyntaxKind::IDENT && token.text() == "$crate" { - dollar_crate_replacements.push((token.clone(), dollar_crate_replacement(&token))); + if let Some(replacement) = dollar_crate_replacement(&token) { + dollar_crate_replacements.push((token.clone(), replacement)); + } } let tok = &token; @@ -129,8 +134,16 @@ pub fn prettify_macro_expansion( last = Some(tok.kind()); } + inspect_mods(&mods); for (pos, insert) in mods { - ted::insert(pos, insert); + ted::insert_raw( + pos, + match insert { + PrettifyWsKind::Space => make::tokens::single_space(), + PrettifyWsKind::Indent(indent) => make::tokens::whitespace(&" ".repeat(4 * indent)), + PrettifyWsKind::Newline => make::tokens::single_newline(), + }, + ); } for (old, new) in dollar_crate_replacements { ted::replace(old, new); -- cgit 1.4.1-3-g733a5 From 7f50020e6b1cd6646738ab05ffe89fbc4d8f5d9e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 30 May 2025 14:50:29 +0000 Subject: Move naked asm check into typeck --- compiler/rustc_hir_typeck/messages.ftl | 3 +++ compiler/rustc_hir_typeck/src/errors.rs | 7 +++++++ compiler/rustc_hir_typeck/src/expr.rs | 16 ++++++++++----- compiler/rustc_passes/messages.ftl | 3 --- compiler/rustc_passes/src/errors.rs | 7 ------- compiler/rustc_passes/src/naked_functions.rs | 30 +--------------------------- 6 files changed, 22 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 5e79d10612d..90a53ab3c81 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -137,6 +137,9 @@ hir_typeck_lossy_provenance_ptr2int = hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}` +hir_typeck_naked_asm_outside_naked_fn = + the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` + hir_typeck_never_type_fallback_flowing_into_unsafe_call = never type fallback affects this call to an `unsafe` function .help = specify the type explicitly hir_typeck_never_type_fallback_flowing_into_unsafe_deref = never type fallback affects this raw pointer dereference diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 06103fe1c91..8ba2db0bf9f 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -983,3 +983,10 @@ pub(crate) struct RegisterTypeUnstable<'a> { pub span: Span, pub ty: Ty<'a>, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_naked_asm_outside_naked_fn)] +pub(crate) struct NakedAsmOutsideNakedFn { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 082ddac7e5a..a1287e8afec 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -44,9 +44,9 @@ use crate::errors::{ AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr, BaseExpressionDoubleDotEnableDefaultFieldValues, BaseExpressionDoubleDotRemove, CantDereference, FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, - HelpUseLatestEdition, NoFieldOnType, NoFieldOnVariant, ReturnLikeStatementKind, - ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, TypeMismatchFruTypo, - YieldExprOutsideOfCoroutine, + HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType, NoFieldOnVariant, + ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, + TypeMismatchFruTypo, YieldExprOutsideOfCoroutine, }; use crate::{ BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, GatherLocalsVisitor, Needs, @@ -524,7 +524,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::InlineAsm(asm) => { // We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars). self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id)); - self.check_expr_asm(asm) + self.check_expr_asm(asm, expr.span) } ExprKind::OffsetOf(container, fields) => { self.check_expr_offset_of(container, fields, expr) @@ -3761,7 +3761,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> { + fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) -> Ty<'tcx> { + if let rustc_ast::AsmMacro::NakedAsm = asm.asm_macro { + if !self.tcx.has_attr(self.body_id, sym::naked) { + self.tcx.dcx().emit_err(NakedAsmOutsideNakedFn { span }); + } + } + let mut diverge = asm.asm_macro.diverges(asm.options); for (op, _op_sp) in asm.operands { diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 6d815e510ea..f690af64b89 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -509,9 +509,6 @@ passes_must_not_suspend = passes_must_use_no_effect = `#[must_use]` has no effect when applied to {$article} {$target} -passes_naked_asm_outside_naked_fn = - the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` - passes_naked_functions_asm_block = naked functions must contain a single `naked_asm!` invocation .label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 00682a9c7a7..bb16eea0528 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1252,13 +1252,6 @@ pub(crate) struct NakedFunctionIncompatibleAttribute { pub attr: String, } -#[derive(Diagnostic)] -#[diag(passes_naked_asm_outside_naked_fn)] -pub(crate) struct NakedAsmOutsideNakedFn { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(passes_attr_only_in_functions)] pub(crate) struct AttrOnlyInFunctions { diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 3c9f8b72c36..e9e88424bcc 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -5,15 +5,13 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, HirIdSet, StmtKind}; -use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_span::{Span, sym}; use crate::errors::{ - NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, - ParamsNotAllowed, + NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, ParamsNotAllowed, }; pub(crate) fn provide(providers: &mut Providers) { @@ -45,10 +43,6 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { check_no_patterns(tcx, body.params); check_no_parameters_use(tcx, body); check_asm(tcx, def_id, body); - } else { - // `naked_asm!` is not allowed outside of functions marked as `#[naked]` - let mut visitor = CheckNakedAsmInNakedFn { tcx }; - visitor.visit_body(body); } } } @@ -231,25 +225,3 @@ impl<'tcx> Visitor<'tcx> for CheckInlineAssembly { self.check_expr(expr, expr.span); } } - -struct CheckNakedAsmInNakedFn<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> Visitor<'tcx> for CheckNakedAsmInNakedFn<'tcx> { - type NestedFilter = OnlyBodies; - - fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { - self.tcx - } - - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if let ExprKind::InlineAsm(inline_asm) = expr.kind { - if let rustc_ast::AsmMacro::NakedAsm = inline_asm.asm_macro { - self.tcx.dcx().emit_err(NakedAsmOutsideNakedFn { span: expr.span }); - } - } - - hir::intravisit::walk_expr(self, expr); - } -} -- cgit 1.4.1-3-g733a5 From 685d1c9e2904813876f233622148838d3575b518 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 30 May 2025 15:06:51 +0000 Subject: Change a per-module query to just run on the items it internally filters for --- compiler/rustc_hir_typeck/src/lib.rs | 6 ++++- compiler/rustc_interface/src/passes.rs | 1 - compiler/rustc_middle/src/hooks/mod.rs | 5 ++++ compiler/rustc_middle/src/query/mod.rs | 4 --- compiler/rustc_passes/src/lib.rs | 2 +- compiler/rustc_passes/src/naked_functions.rs | 39 ++++++---------------------- 6 files changed, 19 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 5a814822163..30651534d7b 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -55,8 +55,8 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config; -use rustc_span::Span; use rustc_span::def_id::LocalDefId; +use rustc_span::{Span, sym}; use tracing::{debug, instrument}; use typeck_root_ctxt::TypeckRootCtxt; @@ -170,6 +170,10 @@ fn typeck_with_inspect<'tcx>( .map(|(idx, ty)| fcx.normalize(arg_span(idx), ty)), ); + if tcx.has_attr(def_id, sym::naked) { + tcx.typeck_naked_fn(def_id, body); + } + check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params()); } else { let expected_type = if let Some(infer_ty) = infer_type_if_missing(&fcx, node) { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 75d92ae7a2e..696f4b493f2 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -960,7 +960,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { tcx.par_hir_for_each_module(|module| { tcx.ensure_ok().check_mod_loops(module); tcx.ensure_ok().check_mod_attrs(module); - tcx.ensure_ok().check_mod_naked_functions(module); tcx.ensure_ok().check_mod_unstable_api_usage(module); }); }, diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index c5ce6efcb81..12110c36044 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -102,6 +102,11 @@ declare_hooks! { /// Ensure the given scalar is valid for the given type. /// This checks non-recursive runtime validity. hook validate_scalar_in_layout(scalar: crate::ty::ScalarInt, ty: Ty<'tcx>) -> bool; + + /// Naked fns can only have trivial binding patterns in arguments, + /// may not actually use those arguments, and the body must consist of just + /// a single asm statement. + hook typeck_naked_fn(def_id: LocalDefId, body: &'tcx rustc_hir::Body<'tcx>) -> (); } #[cold] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 279033ee072..bb0b0a41d5a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1119,10 +1119,6 @@ rustc_queries! { desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) } } - query check_mod_naked_functions(key: LocalModDefId) { - desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) } - } - query check_mod_privacy(key: LocalModDefId) { desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) } } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index f9445485f60..aa4c56846c5 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -14,7 +14,7 @@ #![feature(try_blocks)] // tidy-alphabetical-end -use rustc_middle::query::Providers; +use rustc_middle::util::Providers; pub mod abi_test; mod check_attr; diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index e9e88424bcc..4397a323dfc 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -1,13 +1,12 @@ //! Checks validity of naked functions. use rustc_hir as hir; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::{LocalDefId, LocalModDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, HirIdSet, StmtKind}; -use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; +use rustc_middle::util::Providers; use rustc_span::{Span, sym}; use crate::errors::{ @@ -15,36 +14,14 @@ use crate::errors::{ }; pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { check_mod_naked_functions, ..*providers }; + providers.hooks.typeck_naked_fn = typeck_naked_fn; } -fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { - let items = tcx.hir_module_items(module_def_id); - for def_id in items.definitions() { - if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { - continue; - } - - let body = match tcx.hir_node_by_def_id(def_id) { - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn { body: body_id, .. }, .. - }) - | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)), - .. - }) - | hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(_, body_id), .. - }) => tcx.hir_body(*body_id), - _ => continue, - }; - - if tcx.has_attr(def_id, sym::naked) { - check_no_patterns(tcx, body.params); - check_no_parameters_use(tcx, body); - check_asm(tcx, def_id, body); - } - } +fn typeck_naked_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) { + debug_assert!(tcx.has_attr(def_id, sym::naked)); + check_no_patterns(tcx, body.params); + check_no_parameters_use(tcx, body); + check_asm(tcx, def_id, body); } /// Checks that parameters don't use patterns. Mirrors the checks for function declarations. -- cgit 1.4.1-3-g733a5 From 3c35505fe9c1a0f2c15c780709ed9812f8a332f0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 22:08:24 +0000 Subject: chore: release --- library/compiler-builtins/compiler-builtins/CHANGELOG.md | 15 +++++++++++++++ library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index a7c01c463ca..880e56c443e 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.160](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.159...compiler_builtins-v0.1.160) - 2025-05-29 + +### Other + +- Change `compiler-builtins` to edition 2024 +- Remove unneeded C symbols +- Reuse `libm`'s `Caat` and `CastFrom` in `compiler-builtins` +- Reuse `MinInt` and `Int` from `libm` in `compiler-builtins` +- Update `CmpResult` to use a pointer-sized return type +- Enable `__powitf2` on MSVC +- Fix `i256::MAX` +- Add a note saying why we use `frintx` rather than `frintn` +- Typo in README.md +- Clean up unused files + ## [0.1.159](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.158...compiler_builtins-v0.1.159) - 2025-05-12 ### Other diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 93eb3e01b3b..8ceef286f57 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.159" +version = "0.1.160" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -- cgit 1.4.1-3-g733a5 From 02e2766cc38e6df79ec45c9bb2012ab14a1ae8de Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 30 May 2025 15:19:58 +0000 Subject: Move naked fn checks to hir_typeck --- compiler/rustc_hir_typeck/messages.ftl | 16 ++ compiler/rustc_hir_typeck/src/errors.rs | 49 +++++- compiler/rustc_hir_typeck/src/lib.rs | 3 +- compiler/rustc_hir_typeck/src/naked_functions.rs | 206 +++++++++++++++++++++++ compiler/rustc_middle/src/hooks/mod.rs | 5 - compiler/rustc_passes/messages.ftl | 16 -- compiler/rustc_passes/src/errors.rs | 45 ----- compiler/rustc_passes/src/lib.rs | 2 - compiler/rustc_passes/src/naked_functions.rs | 204 ---------------------- 9 files changed, 271 insertions(+), 275 deletions(-) create mode 100644 compiler/rustc_hir_typeck/src/naked_functions.rs delete mode 100644 compiler/rustc_passes/src/naked_functions.rs diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 90a53ab3c81..6c33dfb4ec0 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -140,6 +140,15 @@ hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on hir_typeck_naked_asm_outside_naked_fn = the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` +hir_typeck_naked_functions_asm_block = + naked functions must contain a single `naked_asm!` invocation + .label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions + .label_non_asm = not allowed in naked functions + +hir_typeck_naked_functions_must_naked_asm = + the `asm!` macro is not allowed in naked functions + .label = consider using the `naked_asm!` macro instead + hir_typeck_never_type_fallback_flowing_into_unsafe_call = never type fallback affects this call to an `unsafe` function .help = specify the type explicitly hir_typeck_never_type_fallback_flowing_into_unsafe_deref = never type fallback affects this raw pointer dereference @@ -162,6 +171,9 @@ hir_typeck_no_field_on_variant = no field named `{$field}` on enum variant `{$co hir_typeck_no_field_on_variant_enum = this enum variant... hir_typeck_no_field_on_variant_field = ...does not have this field +hir_typeck_no_patterns = + patterns not allowed in naked function parameters + hir_typeck_note_caller_chooses_ty_for_ty_param = the caller chooses a type for `{$ty_param_name}` which can be different from `{$found_ty}` hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide @@ -170,6 +182,10 @@ hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expecte hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}` hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}` +hir_typeck_params_not_allowed = + referencing function parameters is not allowed in naked functions + .help = follow the calling convention in asm block to use parameters + hir_typeck_pass_to_variadic_function = can't pass `{$ty}` to variadic function .suggestion = cast the value to `{$cast_ty}` .teach_help = certain types, like `{$ty}`, must be cast before passing them to a variadic function to match the implicit cast that a C compiler would perform as part of C's numeric promotion rules diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 8ba2db0bf9f..97a90548fc5 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -4,8 +4,8 @@ use std::borrow::Cow; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg, MultiSpan, - Subdiagnostic, + Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, + EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -990,3 +990,48 @@ pub(crate) struct NakedAsmOutsideNakedFn { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_no_patterns)] +pub(crate) struct NoPatterns { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_params_not_allowed)] +#[help] +pub(crate) struct ParamsNotAllowed { + #[primary_span] + pub span: Span, +} + +pub(crate) struct NakedFunctionsAsmBlock { + pub span: Span, + pub multiple_asms: Vec, + pub non_asms: Vec, +} + +impl Diagnostic<'_, G> for NakedFunctionsAsmBlock { + #[track_caller] + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { + let mut diag = Diag::new(dcx, level, fluent::hir_typeck_naked_functions_asm_block); + diag.span(self.span); + diag.code(E0787); + for span in self.multiple_asms.iter() { + diag.span_label(*span, fluent::hir_typeck_label_multiple_asm); + } + for span in self.non_asms.iter() { + diag.span_label(*span, fluent::hir_typeck_label_non_asm); + } + diag + } +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_naked_functions_must_naked_asm, code = E0787)] +pub(crate) struct NakedFunctionsMustNakedAsm { + #[primary_span] + #[label] + pub span: Span, +} diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 30651534d7b..b0346f8d32e 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -31,6 +31,7 @@ mod fn_ctxt; mod gather_locals; mod intrinsicck; mod method; +mod naked_functions; mod op; mod opaque_types; mod pat; @@ -171,7 +172,7 @@ fn typeck_with_inspect<'tcx>( ); if tcx.has_attr(def_id, sym::naked) { - tcx.typeck_naked_fn(def_id, body); + naked_functions::typeck_naked_fn(tcx, def_id, body); } check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params()); diff --git a/compiler/rustc_hir_typeck/src/naked_functions.rs b/compiler/rustc_hir_typeck/src/naked_functions.rs new file mode 100644 index 00000000000..2518d6478e6 --- /dev/null +++ b/compiler/rustc_hir_typeck/src/naked_functions.rs @@ -0,0 +1,206 @@ +//! Checks validity of naked functions. + +use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::Visitor; +use rustc_hir::{ExprKind, HirIdSet, StmtKind}; +use rustc_middle::span_bug; +use rustc_middle::ty::TyCtxt; +use rustc_span::{Span, sym}; + +use crate::errors::{ + NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, ParamsNotAllowed, +}; + +/// Naked fns can only have trivial binding patterns in arguments, +/// may not actually use those arguments, and the body must consist of just +/// a single asm statement. +pub(crate) fn typeck_naked_fn<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + body: &'tcx hir::Body<'tcx>, +) { + debug_assert!(tcx.has_attr(def_id, sym::naked)); + check_no_patterns(tcx, body.params); + check_no_parameters_use(tcx, body); + check_asm(tcx, def_id, body); +} + +/// Checks that parameters don't use patterns. Mirrors the checks for function declarations. +fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) { + for param in params { + match param.pat.kind { + hir::PatKind::Wild | hir::PatKind::Binding(hir::BindingMode::NONE, _, _, None) => {} + _ => { + tcx.dcx().emit_err(NoPatterns { span: param.pat.span }); + } + } + } +} + +/// Checks that function parameters aren't used in the function body. +fn check_no_parameters_use<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) { + let mut params = HirIdSet::default(); + for param in body.params { + param.pat.each_binding(|_binding_mode, hir_id, _span, _ident| { + params.insert(hir_id); + }); + } + CheckParameters { tcx, params }.visit_body(body); +} + +struct CheckParameters<'tcx> { + tcx: TyCtxt<'tcx>, + params: HirIdSet, +} + +impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Path(hir::QPath::Resolved( + _, + hir::Path { res: hir::def::Res::Local(var_hir_id), .. }, + )) = expr.kind + { + if self.params.contains(var_hir_id) { + self.tcx.dcx().emit_err(ParamsNotAllowed { span: expr.span }); + return; + } + } + hir::intravisit::walk_expr(self, expr); + } +} + +/// Checks that function body contains a single inline assembly block. +fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) { + let mut this = CheckInlineAssembly { items: Vec::new() }; + this.visit_body(body); + if let [(ItemKind::NakedAsm | ItemKind::Err, _)] = this.items[..] { + // Ok. + } else { + let mut must_show_error = false; + let mut has_naked_asm = false; + let mut has_err = false; + let mut multiple_asms = vec![]; + let mut non_asms = vec![]; + for &(kind, span) in &this.items { + match kind { + ItemKind::NakedAsm if has_naked_asm => { + must_show_error = true; + multiple_asms.push(span); + } + ItemKind::NakedAsm => has_naked_asm = true, + ItemKind::InlineAsm => { + has_err = true; + + tcx.dcx().emit_err(NakedFunctionsMustNakedAsm { span }); + } + ItemKind::NonAsm => { + must_show_error = true; + non_asms.push(span); + } + ItemKind::Err => has_err = true, + } + } + + // If the naked function only contains a single asm block and a non-zero number of + // errors, then don't show an additional error. This allows for appending/prepending + // `compile_error!("...")` statements and reduces error noise. + if must_show_error || !has_err { + tcx.dcx().emit_err(NakedFunctionsAsmBlock { + span: tcx.def_span(def_id), + multiple_asms, + non_asms, + }); + } + } +} + +struct CheckInlineAssembly { + items: Vec<(ItemKind, Span)>, +} + +#[derive(Copy, Clone)] +enum ItemKind { + NakedAsm, + InlineAsm, + NonAsm, + Err, +} + +impl CheckInlineAssembly { + fn check_expr<'tcx>(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) { + match expr.kind { + ExprKind::ConstBlock(..) + | ExprKind::Array(..) + | ExprKind::Call(..) + | ExprKind::MethodCall(..) + | ExprKind::Use(..) + | ExprKind::Tup(..) + | ExprKind::Binary(..) + | ExprKind::Unary(..) + | ExprKind::Lit(..) + | ExprKind::Cast(..) + | ExprKind::Type(..) + | ExprKind::UnsafeBinderCast(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + | ExprKind::If(..) + | ExprKind::Closure { .. } + | ExprKind::Assign(..) + | ExprKind::AssignOp(..) + | ExprKind::Field(..) + | ExprKind::Index(..) + | ExprKind::Path(..) + | ExprKind::AddrOf(..) + | ExprKind::Let(..) + | ExprKind::Break(..) + | ExprKind::Continue(..) + | ExprKind::Ret(..) + | ExprKind::OffsetOf(..) + | ExprKind::Become(..) + | ExprKind::Struct(..) + | ExprKind::Repeat(..) + | ExprKind::Yield(..) => { + self.items.push((ItemKind::NonAsm, span)); + } + + ExprKind::InlineAsm(asm) => match asm.asm_macro { + rustc_ast::AsmMacro::Asm => { + self.items.push((ItemKind::InlineAsm, span)); + } + rustc_ast::AsmMacro::NakedAsm => { + self.items.push((ItemKind::NakedAsm, span)); + } + rustc_ast::AsmMacro::GlobalAsm => { + span_bug!(span, "`global_asm!` is not allowed in this position") + } + }, + + ExprKind::DropTemps(..) | ExprKind::Block(..) => { + hir::intravisit::walk_expr(self, expr); + } + + ExprKind::Err(_) => { + self.items.push((ItemKind::Err, span)); + } + } + } +} + +impl<'tcx> Visitor<'tcx> for CheckInlineAssembly { + fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { + match stmt.kind { + StmtKind::Item(..) => {} + StmtKind::Let(..) => { + self.items.push((ItemKind::NonAsm, stmt.span)); + } + StmtKind::Expr(expr) | StmtKind::Semi(expr) => { + self.check_expr(expr, stmt.span); + } + } + } + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + self.check_expr(expr, expr.span); + } +} diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index 12110c36044..c5ce6efcb81 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -102,11 +102,6 @@ declare_hooks! { /// Ensure the given scalar is valid for the given type. /// This checks non-recursive runtime validity. hook validate_scalar_in_layout(scalar: crate::ty::ScalarInt, ty: Ty<'tcx>) -> bool; - - /// Naked fns can only have trivial binding patterns in arguments, - /// may not actually use those arguments, and the body must consist of just - /// a single asm statement. - hook typeck_naked_fn(def_id: LocalDefId, body: &'tcx rustc_hir::Body<'tcx>) -> (); } #[cold] diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index f690af64b89..983e562cdf3 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -509,20 +509,11 @@ passes_must_not_suspend = passes_must_use_no_effect = `#[must_use]` has no effect when applied to {$article} {$target} -passes_naked_functions_asm_block = - naked functions must contain a single `naked_asm!` invocation - .label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions - .label_non_asm = not allowed in naked functions - passes_naked_functions_incompatible_attribute = attribute incompatible with `#[unsafe(naked)]` .label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]` .naked_attribute = function marked with `#[unsafe(naked)]` here -passes_naked_functions_must_naked_asm = - the `asm!` macro is not allowed in naked functions - .label = consider using the `naked_asm!` macro instead - passes_no_link = attribute should be applied to an `extern crate` item .label = not an `extern crate` item @@ -553,9 +544,6 @@ passes_no_mangle_foreign = .note = symbol names in extern blocks are not mangled .suggestion = remove this attribute -passes_no_patterns = - patterns not allowed in naked function parameters - passes_no_sanitize = `#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind} .label = not {$accepted_kind} @@ -603,10 +591,6 @@ passes_panic_unwind_without_std = .note = since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem .help = using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding -passes_params_not_allowed = - referencing function parameters is not allowed in naked functions - .help = follow the calling convention in asm block to use parameters - passes_parent_info = {$num -> [one] {$descr} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index bb16eea0528..b995781719b 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1196,51 +1196,6 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> { pub cf_type: &'a str, } -#[derive(Diagnostic)] -#[diag(passes_no_patterns)] -pub(crate) struct NoPatterns { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_params_not_allowed)] -#[help] -pub(crate) struct ParamsNotAllowed { - #[primary_span] - pub span: Span, -} - -pub(crate) struct NakedFunctionsAsmBlock { - pub span: Span, - pub multiple_asms: Vec, - pub non_asms: Vec, -} - -impl Diagnostic<'_, G> for NakedFunctionsAsmBlock { - #[track_caller] - fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { - let mut diag = Diag::new(dcx, level, fluent::passes_naked_functions_asm_block); - diag.span(self.span); - diag.code(E0787); - for span in self.multiple_asms.iter() { - diag.span_label(*span, fluent::passes_label_multiple_asm); - } - for span in self.non_asms.iter() { - diag.span_label(*span, fluent::passes_label_non_asm); - } - diag - } -} - -#[derive(Diagnostic)] -#[diag(passes_naked_functions_must_naked_asm, code = E0787)] -pub(crate) struct NakedFunctionsMustNakedAsm { - #[primary_span] - #[label] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(passes_naked_functions_incompatible_attribute, code = E0736)] pub(crate) struct NakedFunctionIncompatibleAttribute { diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index aa4c56846c5..639ca683cf6 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -32,7 +32,6 @@ pub mod layout_test; mod lib_features; mod liveness; pub mod loops; -mod naked_functions; mod reachable; pub mod stability; mod upvars; @@ -49,7 +48,6 @@ pub fn provide(providers: &mut Providers) { lang_items::provide(providers); lib_features::provide(providers); loops::provide(providers); - naked_functions::provide(providers); liveness::provide(providers); reachable::provide(providers); stability::provide(providers); diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs deleted file mode 100644 index 4397a323dfc..00000000000 --- a/compiler/rustc_passes/src/naked_functions.rs +++ /dev/null @@ -1,204 +0,0 @@ -//! Checks validity of naked functions. - -use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::Visitor; -use rustc_hir::{ExprKind, HirIdSet, StmtKind}; -use rustc_middle::span_bug; -use rustc_middle::ty::TyCtxt; -use rustc_middle::util::Providers; -use rustc_span::{Span, sym}; - -use crate::errors::{ - NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, ParamsNotAllowed, -}; - -pub(crate) fn provide(providers: &mut Providers) { - providers.hooks.typeck_naked_fn = typeck_naked_fn; -} - -fn typeck_naked_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) { - debug_assert!(tcx.has_attr(def_id, sym::naked)); - check_no_patterns(tcx, body.params); - check_no_parameters_use(tcx, body); - check_asm(tcx, def_id, body); -} - -/// Checks that parameters don't use patterns. Mirrors the checks for function declarations. -fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) { - for param in params { - match param.pat.kind { - hir::PatKind::Wild | hir::PatKind::Binding(hir::BindingMode::NONE, _, _, None) => {} - _ => { - tcx.dcx().emit_err(NoPatterns { span: param.pat.span }); - } - } - } -} - -/// Checks that function parameters aren't used in the function body. -fn check_no_parameters_use<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) { - let mut params = HirIdSet::default(); - for param in body.params { - param.pat.each_binding(|_binding_mode, hir_id, _span, _ident| { - params.insert(hir_id); - }); - } - CheckParameters { tcx, params }.visit_body(body); -} - -struct CheckParameters<'tcx> { - tcx: TyCtxt<'tcx>, - params: HirIdSet, -} - -impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Path(hir::QPath::Resolved( - _, - hir::Path { res: hir::def::Res::Local(var_hir_id), .. }, - )) = expr.kind - { - if self.params.contains(var_hir_id) { - self.tcx.dcx().emit_err(ParamsNotAllowed { span: expr.span }); - return; - } - } - hir::intravisit::walk_expr(self, expr); - } -} - -/// Checks that function body contains a single inline assembly block. -fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) { - let mut this = CheckInlineAssembly { items: Vec::new() }; - this.visit_body(body); - if let [(ItemKind::NakedAsm | ItemKind::Err, _)] = this.items[..] { - // Ok. - } else { - let mut must_show_error = false; - let mut has_naked_asm = false; - let mut has_err = false; - let mut multiple_asms = vec![]; - let mut non_asms = vec![]; - for &(kind, span) in &this.items { - match kind { - ItemKind::NakedAsm if has_naked_asm => { - must_show_error = true; - multiple_asms.push(span); - } - ItemKind::NakedAsm => has_naked_asm = true, - ItemKind::InlineAsm => { - has_err = true; - - tcx.dcx().emit_err(NakedFunctionsMustNakedAsm { span }); - } - ItemKind::NonAsm => { - must_show_error = true; - non_asms.push(span); - } - ItemKind::Err => has_err = true, - } - } - - // If the naked function only contains a single asm block and a non-zero number of - // errors, then don't show an additional error. This allows for appending/prepending - // `compile_error!("...")` statements and reduces error noise. - if must_show_error || !has_err { - tcx.dcx().emit_err(NakedFunctionsAsmBlock { - span: tcx.def_span(def_id), - multiple_asms, - non_asms, - }); - } - } -} - -struct CheckInlineAssembly { - items: Vec<(ItemKind, Span)>, -} - -#[derive(Copy, Clone)] -enum ItemKind { - NakedAsm, - InlineAsm, - NonAsm, - Err, -} - -impl CheckInlineAssembly { - fn check_expr<'tcx>(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) { - match expr.kind { - ExprKind::ConstBlock(..) - | ExprKind::Array(..) - | ExprKind::Call(..) - | ExprKind::MethodCall(..) - | ExprKind::Use(..) - | ExprKind::Tup(..) - | ExprKind::Binary(..) - | ExprKind::Unary(..) - | ExprKind::Lit(..) - | ExprKind::Cast(..) - | ExprKind::Type(..) - | ExprKind::UnsafeBinderCast(..) - | ExprKind::Loop(..) - | ExprKind::Match(..) - | ExprKind::If(..) - | ExprKind::Closure { .. } - | ExprKind::Assign(..) - | ExprKind::AssignOp(..) - | ExprKind::Field(..) - | ExprKind::Index(..) - | ExprKind::Path(..) - | ExprKind::AddrOf(..) - | ExprKind::Let(..) - | ExprKind::Break(..) - | ExprKind::Continue(..) - | ExprKind::Ret(..) - | ExprKind::OffsetOf(..) - | ExprKind::Become(..) - | ExprKind::Struct(..) - | ExprKind::Repeat(..) - | ExprKind::Yield(..) => { - self.items.push((ItemKind::NonAsm, span)); - } - - ExprKind::InlineAsm(asm) => match asm.asm_macro { - rustc_ast::AsmMacro::Asm => { - self.items.push((ItemKind::InlineAsm, span)); - } - rustc_ast::AsmMacro::NakedAsm => { - self.items.push((ItemKind::NakedAsm, span)); - } - rustc_ast::AsmMacro::GlobalAsm => { - span_bug!(span, "`global_asm!` is not allowed in this position") - } - }, - - ExprKind::DropTemps(..) | ExprKind::Block(..) => { - hir::intravisit::walk_expr(self, expr); - } - - ExprKind::Err(_) => { - self.items.push((ItemKind::Err, span)); - } - } - } -} - -impl<'tcx> Visitor<'tcx> for CheckInlineAssembly { - fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { - match stmt.kind { - StmtKind::Item(..) => {} - StmtKind::Let(..) => { - self.items.push((ItemKind::NonAsm, stmt.span)); - } - StmtKind::Expr(expr) | StmtKind::Semi(expr) => { - self.check_expr(expr, stmt.span); - } - } - } - - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - self.check_expr(expr, expr.span); - } -} -- cgit 1.4.1-3-g733a5 From 033ea63639e11e3af2bd33092129465e4b9d8113 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Fri, 30 May 2025 20:34:55 +0200 Subject: Do not run PGO/BOLT in x64 Linux alt builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Beránek --- src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile | 15 +++++++-------- src/ci/docker/host-x86_64/dist-x86_64-linux/dist-alt.sh | 8 ++++++++ src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh | 13 +++++++++++++ src/ci/github-actions/jobs.yml | 3 +++ 4 files changed, 31 insertions(+), 8 deletions(-) create mode 100755 src/ci/docker/host-x86_64/dist-x86_64-linux/dist-alt.sh create mode 100755 src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index bedf45c8630..44f6a8d2a15 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -96,14 +96,13 @@ ENV RUST_CONFIGURE_ARGS \ --set rust.lto=thin \ --set rust.codegen-units=1 -# Note that `rust.debug` is set to true *only* for `opt-dist` -ENV SCRIPT python3 ../x.py build --set rust.debug=true opt-dist && \ - ./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \ - --host $HOSTS --target $HOSTS \ - --include-default-paths \ - build-manifest bootstrap && \ - # Use GCC for building GCC, as it seems to behave badly when built with Clang - CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist gcc +ARG SCRIPT_ARG + +COPY host-x86_64/dist-x86_64-linux/dist.sh /scripts/ +COPY host-x86_64/dist-x86_64-linux/dist-alt.sh /scripts/ + +ENV SCRIPT /scripts/${SCRIPT_ARG} + ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang # This is the only builder which will create source tarballs diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist-alt.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist-alt.sh new file mode 100755 index 00000000000..8e756c32431 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist-alt.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +set -eux + +python3 ../x.py dist \ + --host $HOSTS --target $HOSTS \ + --include-default-paths \ + build-manifest bootstrap diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh new file mode 100755 index 00000000000..064ac5b0a5e --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -eux + +python3 ../x.py build --set rust.debug=true opt-dist + +./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \ + --host $HOSTS --target $HOSTS \ + --include-default-paths \ + build-manifest bootstrap + +# Use GCC for building GCC, as it seems to behave badly when built with Clang +CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist gcc diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index dc6a0e1ebad..56863b839df 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -141,6 +141,7 @@ try: - name: dist-x86_64-linux env: CODEGEN_BACKENDS: llvm,cranelift + DOCKER_SCRIPT: dist.sh <<: *job-linux-36c-codebuild # Main CI jobs that have to be green to merge a commit into master @@ -237,12 +238,14 @@ auto: - name: dist-x86_64-linux env: CODEGEN_BACKENDS: llvm,cranelift + DOCKER_SCRIPT: dist.sh <<: *job-linux-36c-codebuild - name: dist-x86_64-linux-alt env: IMAGE: dist-x86_64-linux CODEGEN_BACKENDS: llvm,cranelift + DOCKER_SCRIPT: dist-alt.sh <<: *job-linux-16c - name: dist-x86_64-musl -- cgit 1.4.1-3-g733a5 From 1383bca55c68a7b6b93047fb3bd2805fe0f666b5 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 30 May 2025 22:02:59 +0200 Subject: internal: Restructure some semantics APIs for virtual macro files --- .../rust-analyzer/crates/hir/src/semantics.rs | 219 ++++++++++++++------- .../crates/hir/src/source_analyzer.rs | 1 + .../rust-analyzer/crates/ide-db/src/search.rs | 14 +- .../crates/ide/src/goto_definition.rs | 2 +- .../crates/ide/src/goto_type_definition.rs | 4 +- .../crates/ide/src/highlight_related.rs | 2 +- src/tools/rust-analyzer/crates/ide/src/hover.rs | 2 +- .../rust-analyzer/crates/ide/src/references.rs | 2 +- src/tools/rust-analyzer/crates/ide/src/rename.rs | 2 +- .../crates/ide/src/syntax_highlighting.rs | 2 +- src/tools/rust-analyzer/crates/syntax/src/ted.rs | 7 + src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs | 7 + 12 files changed, 185 insertions(+), 79 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index aea22545ed5..e01774650b1 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -24,7 +24,7 @@ use hir_expand::{ attrs::collect_attrs, builtin::{BuiltinFnLikeExpander, EagerExpander}, db::ExpandDatabase, - files::{FileRangeWrapper, InRealFile}, + files::{FileRangeWrapper, HirFileRange, InRealFile}, inert_attr_macro::find_builtin_attr_idx, mod_path::{ModPath, PathKind}, name::AsName, @@ -262,6 +262,17 @@ impl Semantics<'_, DB> { self.imp.file_to_module_defs(file.into()) } + pub fn hir_file_to_module_def(&self, file: impl Into) -> Option { + self.imp.hir_file_to_module_defs(file.into()).next() + } + + pub fn hir_file_to_module_defs( + &self, + file: impl Into, + ) -> impl Iterator { + self.imp.hir_file_to_module_defs(file.into()) + } + pub fn to_adt_def(&self, a: &ast::Adt) -> Option { self.imp.to_def(a) } @@ -357,6 +368,15 @@ impl<'db> SemanticsImpl<'db> { tree } + pub fn adjust_edition(&self, file_id: HirFileId) -> HirFileId { + if let Some(editioned_file_id) = file_id.file_id() { + self.attach_first_edition(editioned_file_id.file_id(self.db)) + .map_or(file_id, Into::into) + } else { + file_id + } + } + pub fn find_parent_file(&self, file_id: HirFileId) -> Option> { match file_id { HirFileId::FileId(file_id) => { @@ -653,7 +673,7 @@ impl<'db> SemanticsImpl<'db> { string: &ast::String, ) -> Option>)>> { let string_start = string.syntax().text_range().start(); - let token = self.wrap_token_infile(string.syntax().clone()).into_real_file().ok()?; + let token = self.wrap_token_infile(string.syntax().clone()); self.descend_into_macros_breakable(token, |token, _| { (|| { let token = token.value; @@ -693,50 +713,95 @@ impl<'db> SemanticsImpl<'db> { } /// Retrieves the formatting part of the format_args! template string at the given offset. + /// + // FIXME: Type the return type + /// Returns the range (pre-expansion) in the string literal corresponding to the resolution, + /// absolute file range (post-expansion) + /// of the part in the format string, the corresponding string token and the resolution if it + /// exists. + // FIXME: Remove this in favor of `check_for_format_args_template_with_file` pub fn check_for_format_args_template( &self, original_token: SyntaxToken, offset: TextSize, - ) -> Option<(TextRange, Option>)> { - let string_start = original_token.text_range().start(); - let original_token = self.wrap_token_infile(original_token).into_real_file().ok()?; - self.descend_into_macros_breakable(original_token, |token, _| { - (|| { - let token = token.value; - self.resolve_offset_in_format_args( - ast::String::cast(token)?, - offset.checked_sub(string_start)?, - ) - .map(|(range, res)| (range + string_start, res)) - })() - .map_or(ControlFlow::Continue(()), ControlFlow::Break) - }) + ) -> Option<( + TextRange, + HirFileRange, + ast::String, + Option>, + )> { + let original_token = + self.wrap_token_infile(original_token).map(ast::String::cast).transpose()?; + self.check_for_format_args_template_with_file(original_token, offset) + } + + /// Retrieves the formatting part of the format_args! template string at the given offset. + /// + // FIXME: Type the return type + /// Returns the range (pre-expansion) in the string literal corresponding to the resolution, + /// absolute file range (post-expansion) + /// of the part in the format string, the corresponding string token and the resolution if it + /// exists. + pub fn check_for_format_args_template_with_file( + &self, + original_token: InFile, + offset: TextSize, + ) -> Option<( + TextRange, + HirFileRange, + ast::String, + Option>, + )> { + let relative_offset = + offset.checked_sub(original_token.value.syntax().text_range().start())?; + self.descend_into_macros_breakable( + original_token.as_ref().map(|it| it.syntax().clone()), + |token, _| { + (|| { + let token = token.map(ast::String::cast).transpose()?; + self.resolve_offset_in_format_args(token.as_ref(), relative_offset).map( + |(range, res)| { + ( + range + original_token.value.syntax().text_range().start(), + HirFileRange { + file_id: token.file_id, + range: range + token.value.syntax().text_range().start(), + }, + token.value, + res, + ) + }, + ) + })() + .map_or(ControlFlow::Continue(()), ControlFlow::Break) + }, + ) } fn resolve_offset_in_format_args( &self, - string: ast::String, + InFile { value: string, file_id }: InFile<&ast::String>, offset: TextSize, ) -> Option<(TextRange, Option>)> { debug_assert!(offset <= string.syntax().text_range().len()); let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?; let parent = literal.parent()?; if let Some(format_args) = ast::FormatArgsExpr::cast(parent.clone()) { - let source_analyzer = &self.analyze_no_infer(format_args.syntax())?; - let format_args = self.wrap_node_infile(format_args); + let source_analyzer = + &self.analyze_impl(InFile::new(file_id, format_args.syntax()), None, false)?; source_analyzer - .resolve_offset_in_format_args(self.db, format_args.as_ref(), offset) + .resolve_offset_in_format_args(self.db, InFile::new(file_id, &format_args), offset) .map(|(range, res)| (range, res.map(Either::Left))) } else { let asm = ast::AsmExpr::cast(parent)?; - let source_analyzer = &self.analyze_no_infer(asm.syntax())?; + let source_analyzer = + self.analyze_impl(InFile::new(file_id, asm.syntax()), None, false)?; let line = asm.template().position(|it| *it.syntax() == literal)?; - let asm = self.wrap_node_infile(asm); - source_analyzer.resolve_offset_in_asm_template(asm.as_ref(), line, offset).map( - |(owner, (expr, range, index))| { + source_analyzer + .resolve_offset_in_asm_template(InFile::new(file_id, &asm), line, offset) + .map(|(owner, (expr, range, index))| { (range, Some(Either::Right(InlineAsmOperand { owner, expr, index }))) - }, - ) + }) } } @@ -809,14 +874,11 @@ impl<'db> SemanticsImpl<'db> { None => return res, }; let file = self.find_file(node.syntax()); - let Some(file_id) = file.file_id.file_id() else { - return res; - }; if first == last { // node is just the token, so descend the token self.descend_into_macros_impl( - InRealFile::new(file_id, first), + InFile::new(file.file_id, first), &mut |InFile { value, .. }, _ctx| { if let Some(node) = value .parent_ancestors() @@ -831,14 +893,14 @@ impl<'db> SemanticsImpl<'db> { } else { // Descend first and last token, then zip them to look for the node they belong to let mut scratch: SmallVec<[_; 1]> = smallvec![]; - self.descend_into_macros_impl(InRealFile::new(file_id, first), &mut |token, _ctx| { + self.descend_into_macros_impl(InFile::new(file.file_id, first), &mut |token, _ctx| { scratch.push(token); CONTINUE_NO_BREAKS }); let mut scratch = scratch.into_iter(); self.descend_into_macros_impl( - InRealFile::new(file_id, last), + InFile::new(file.file_id, last), &mut |InFile { value: last, file_id: last_fid }, _ctx| { if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() { if first_fid == last_fid { @@ -900,22 +962,18 @@ impl<'db> SemanticsImpl<'db> { token: SyntaxToken, mut cb: impl FnMut(InFile, SyntaxContext), ) { - if let Ok(token) = self.wrap_token_infile(token).into_real_file() { - self.descend_into_macros_impl(token, &mut |t, ctx| { - cb(t, ctx); - CONTINUE_NO_BREAKS - }); - } + self.descend_into_macros_impl(self.wrap_token_infile(token), &mut |t, ctx| { + cb(t, ctx); + CONTINUE_NO_BREAKS + }); } pub fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> { let mut res = smallvec![]; - if let Ok(token) = self.wrap_token_infile(token.clone()).into_real_file() { - self.descend_into_macros_impl(token, &mut |t, _ctx| { - res.push(t.value); - CONTINUE_NO_BREAKS - }); - } + self.descend_into_macros_impl(self.wrap_token_infile(token.clone()), &mut |t, _ctx| { + res.push(t.value); + CONTINUE_NO_BREAKS + }); if res.is_empty() { res.push(token); } @@ -928,15 +986,13 @@ impl<'db> SemanticsImpl<'db> { ) -> SmallVec<[InFile; 1]> { let mut res = smallvec![]; let token = self.wrap_token_infile(token); - if let Ok(token) = token.clone().into_real_file() { - self.descend_into_macros_impl(token, &mut |t, ctx| { - if !ctx.is_opaque(self.db) { - // Don't descend into opaque contexts - res.push(t); - } - CONTINUE_NO_BREAKS - }); - } + self.descend_into_macros_impl(token.clone(), &mut |t, ctx| { + if !ctx.is_opaque(self.db) { + // Don't descend into opaque contexts + res.push(t); + } + CONTINUE_NO_BREAKS + }); if res.is_empty() { res.push(token); } @@ -945,7 +1001,7 @@ impl<'db> SemanticsImpl<'db> { pub fn descend_into_macros_breakable( &self, - token: InRealFile, + token: InFile, mut cb: impl FnMut(InFile, SyntaxContext) -> ControlFlow, ) -> Option { self.descend_into_macros_impl(token, &mut cb) @@ -974,33 +1030,58 @@ impl<'db> SemanticsImpl<'db> { r } + /// Descends the token into expansions, returning the tokens that matches the input + /// token's [`SyntaxKind`] and text. + pub fn descend_into_macros_exact_with_file( + &self, + token: SyntaxToken, + ) -> SmallVec<[InFile; 1]> { + let mut r = smallvec![]; + let text = token.text(); + let kind = token.kind(); + + self.descend_into_macros_cb(token.clone(), |InFile { value, file_id }, ctx| { + let mapped_kind = value.kind(); + let any_ident_match = || kind.is_any_identifier() && value.kind().is_any_identifier(); + let matches = (kind == mapped_kind || any_ident_match()) + && text == value.text() + && !ctx.is_opaque(self.db); + if matches { + r.push(InFile { value, file_id }); + } + }); + if r.is_empty() { + r.push(self.wrap_token_infile(token)); + } + r + } + /// Descends the token into expansions, returning the first token that matches the input /// token's [`SyntaxKind`] and text. pub fn descend_into_macros_single_exact(&self, token: SyntaxToken) -> SyntaxToken { let text = token.text(); let kind = token.kind(); - if let Ok(token) = self.wrap_token_infile(token.clone()).into_real_file() { - self.descend_into_macros_breakable(token, |InFile { value, file_id: _ }, _ctx| { + self.descend_into_macros_breakable( + self.wrap_token_infile(token.clone()), + |InFile { value, file_id: _ }, _ctx| { let mapped_kind = value.kind(); let any_ident_match = || kind.is_any_identifier() && value.kind().is_any_identifier(); let matches = (kind == mapped_kind || any_ident_match()) && text == value.text(); if matches { ControlFlow::Break(value) } else { ControlFlow::Continue(()) } - }) - } else { - None - } + }, + ) .unwrap_or(token) } fn descend_into_macros_impl( &self, - InRealFile { value: token, file_id }: InRealFile, + InFile { value: token, file_id }: InFile, f: &mut dyn FnMut(InFile, SyntaxContext) -> ControlFlow, ) -> Option { let _p = tracing::info_span!("descend_into_macros_impl").entered(); - let span = self.db.real_span_map(file_id).span_for_range(token.text_range()); + let span = self.db.span_map(file_id).span_for_range(token.text_range()); // Process the expansion of a call, pushing all tokens with our span in the expansion back onto our stack let process_expansion_for_token = |stack: &mut Vec<_>, macro_file| { @@ -1024,17 +1105,16 @@ impl<'db> SemanticsImpl<'db> { // the tokens themselves aren't that interesting as the span that is being used to map // things down never changes. let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![]; - let include = self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, file_id); + let include = file_id.file_id().and_then(|file_id| { + self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, file_id) + }); match include { Some(include) => { // include! inputs are always from real files, so they only need to be handled once upfront process_expansion_for_token(&mut stack, include)?; } None => { - stack.push(( - file_id.into(), - smallvec![(token, SyntaxContext::root(file_id.edition(self.db)))], - )); + stack.push((file_id, smallvec![(token, span.ctx)])); } } @@ -1678,6 +1758,11 @@ impl<'db> SemanticsImpl<'db> { self.with_ctx(|ctx| ctx.file_to_def(file).to_owned()).into_iter().map(Module::from) } + fn hir_file_to_module_defs(&self, file: HirFileId) -> impl Iterator { + // FIXME: Do we need to care about inline modules for macro expansions? + self.file_to_module_defs(file.original_file_respecting_includes(self.db).file_id(self.db)) + } + pub fn scope(&self, node: &SyntaxNode) -> Option> { self.analyze_no_infer(node).map(|SourceAnalyzer { file_id, resolver, .. }| SemanticsScope { db: self.db, diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index d22812d3c69..ec2ccf8cba0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -1303,6 +1303,7 @@ impl<'db> SourceAnalyzer<'db> { false } + /// Returns the range of the implicit template argument and its resolution at the given `offset` pub(crate) fn resolve_offset_in_format_args( &self, db: &'db dyn HirDatabase, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index d4ab7592927..c5ad64ed594 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -961,12 +961,16 @@ impl<'a> FindUsages<'a> { // Search for occurrences of the items name for offset in Self::match_indices(&text, finder, search_range) { let ret = tree.token_at_offset(offset).any(|token| { - let Some(str_token) = ast::String::cast(token.clone()) else { return false }; - if let Some((range, Some(nameres))) = - sema.check_for_format_args_template(token, offset) + if let Some((range, _frange, string_token, Some(nameres))) = + sema.check_for_format_args_template(token.clone(), offset) { - return self - .found_format_args_ref(file_id, range, str_token, nameres, sink); + return self.found_format_args_ref( + file_id, + range, + string_token, + nameres, + sink, + ); } false }); diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index c60ca3562f6..7917aab8bf7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -67,7 +67,7 @@ pub(crate) fn goto_definition( }); } - if let Some((range, resolution)) = + if let Some((range, _, _, resolution)) = sema.check_for_format_args_template(original_token.clone(), offset) { return Some(RangeInfo::new( diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs index a78f5cdc9d0..a6c7ea29b09 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs @@ -53,7 +53,9 @@ pub(crate) fn goto_type_definition( } }); }; - if let Some((range, resolution)) = sema.check_for_format_args_template(token.clone(), offset) { + if let Some((range, _, _, resolution)) = + sema.check_for_format_args_template(token.clone(), offset) + { if let Some(ty) = resolution.and_then(|res| match Definition::from(res) { Definition::Const(it) => Some(it.ty(db)), Definition::Static(it) => Some(it.ty(db)), diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index 520ba39a238..9fae250e969 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -160,7 +160,7 @@ fn highlight_references( FilePosition { file_id, offset }: FilePosition, vfs_file_id: FileId, ) -> Option> { - let defs = if let Some((range, resolution)) = + let defs = if let Some((range, _, _, resolution)) = sema.check_for_format_args_template(token.clone(), offset) { match resolution.map(Definition::from) { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 8bb1c708e25..5404a9dc2ce 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -200,7 +200,7 @@ fn hover_offset( }); } - if let Some((range, resolution)) = + if let Some((range, _, _, resolution)) = sema.check_for_format_args_template(original_token.clone(), offset) { let res = hover_for_definition( diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index f7f00cf8317..c6a323d4081 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -200,7 +200,7 @@ pub(crate) fn find_defs( ) })?; - if let Some((_, resolution)) = sema.check_for_format_args_template(token.clone(), offset) { + if let Some((.., resolution)) = sema.check_for_format_args_template(token.clone(), offset) { return resolution.map(Definition::from).map(|it| vec![it]); } diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index e6cda60cd95..0423e3da2c8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -203,7 +203,7 @@ fn find_definitions( ) -> RenameResult> { let token = syntax.token_at_offset(offset).find(|t| matches!(t.kind(), SyntaxKind::STRING)); - if let Some((range, Some(resolution))) = + if let Some((range, _, _, Some(resolution))) = token.and_then(|token| sema.check_for_format_args_template(token, offset)) { return Ok(vec![( diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs index e1bc76318f8..3ca172977cb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -542,7 +542,7 @@ fn descend_token( let mut t = None; let mut r = 0; - sema.descend_into_macros_breakable(token.clone(), |tok, _ctx| { + sema.descend_into_macros_breakable(token.clone().into(), |tok, _ctx| { // FIXME: Consider checking ctx transparency for being opaque? let my_rank = ranker.rank_token(&tok.value); diff --git a/src/tools/rust-analyzer/crates/syntax/src/ted.rs b/src/tools/rust-analyzer/crates/syntax/src/ted.rs index ad1d91bb0b2..6fcbdd006c2 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ted.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ted.rs @@ -5,6 +5,7 @@ use std::{mem, ops::RangeInclusive}; use parser::T; +use rowan::TextSize; use crate::{ SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, @@ -74,6 +75,12 @@ impl Position { }; Position { repr } } + pub fn offset(&self) -> TextSize { + match &self.repr { + PositionRepr::FirstChild(node) => node.text_range().start(), + PositionRepr::After(elem) => elem.text_range().end(), + } + } } pub fn insert(position: Position, elem: impl Element) { diff --git a/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs b/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs index c35b7f229f6..7e2c787afc7 100644 --- a/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs +++ b/src/tools/rust-analyzer/crates/vfs/src/vfs_path.rs @@ -39,6 +39,13 @@ impl VfsPath { } } + pub fn into_abs_path(self) -> Option { + match self.0 { + VfsPathRepr::PathBuf(it) => Some(it), + VfsPathRepr::VirtualPath(_) => None, + } + } + /// Creates a new `VfsPath` with `path` adjoined to `self`. pub fn join(&self, path: &str) -> Option { match &self.0 { -- cgit 1.4.1-3-g733a5 From 2d5d55a50ab6c6e1f5af65e42b73cd173536b03d Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 30 May 2025 15:53:35 -0700 Subject: bootstrap: build std with less frame pointers Sometimes leaf frame-pointers can impact LLVM inlining choices, and that can be a real problem for things like `mul_add`. --- src/bootstrap/src/core/build_steps/compile.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index d5ea96b43f5..38820e2f117 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -670,7 +670,8 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car // Enable frame pointers by default for the library. Note that they are still controlled by a // separate setting for the compiler. - cargo.rustflag("-Cforce-frame-pointers=yes"); + cargo.rustflag("-Zunstable-options"); + cargo.rustflag("-Cforce-frame-pointers=non-leaf"); let html_root = format!("-Zcrate-attr=doc(html_root_url=\"{}/\")", builder.doc_rust_lang_org_channel(),); -- cgit 1.4.1-3-g733a5 From ed508c74acf9b8ea4c17186367580c1218275dfa Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 31 May 2025 07:25:03 +0200 Subject: refactor: Remove unncessary duplication in highlight_related --- .../crates/ide/src/highlight_related.rs | 27 +++++++--------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index 520ba39a238..46a744dfaf0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -11,7 +11,6 @@ use ide_db::{ preorder_expr_with_ctx_checker, }, }; -use span::FileId; use syntax::{ AstNode, SyntaxKind::{self, IDENT, INT_NUMBER}, @@ -61,13 +60,12 @@ pub(crate) fn highlight_related( let file_id = sema .attach_first_edition(file_id) .unwrap_or_else(|| EditionedFileId::current_edition(sema.db, file_id)); - let span_file_id = file_id.editioned_file_id(sema.db); let syntax = sema.parse(file_id).syntax().clone(); let token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind { T![?] => 4, // prefer `?` when the cursor is sandwiched like in `await$0?` T![->] => 4, - kind if kind.is_keyword(span_file_id.edition()) => 3, + kind if kind.is_keyword(file_id.edition(sema.db)) => 3, IDENT | INT_NUMBER => 2, T![|] => 1, _ => 0, @@ -92,18 +90,11 @@ pub(crate) fn highlight_related( T![unsafe] if token.parent().and_then(ast::BlockExpr::cast).is_some() => { highlight_unsafe_points(sema, token).remove(&file_id) } - T![|] if config.closure_captures => { - highlight_closure_captures(sema, token, file_id, span_file_id.file_id()) + T![|] if config.closure_captures => highlight_closure_captures(sema, token, file_id), + T![move] if config.closure_captures => highlight_closure_captures(sema, token, file_id), + _ if config.references => { + highlight_references(sema, token, FilePosition { file_id, offset }) } - T![move] if config.closure_captures => { - highlight_closure_captures(sema, token, file_id, span_file_id.file_id()) - } - _ if config.references => highlight_references( - sema, - token, - FilePosition { file_id, offset }, - span_file_id.file_id(), - ), _ => None, } } @@ -112,7 +103,6 @@ fn highlight_closure_captures( sema: &Semantics<'_, RootDatabase>, token: SyntaxToken, file_id: EditionedFileId, - vfs_file_id: FileId, ) -> Option> { let closure = token.parent_ancestors().take(2).find_map(ast::ClosureExpr::cast)?; let search_range = closure.body()?.syntax().text_range(); @@ -145,7 +135,7 @@ fn highlight_closure_captures( .sources(sema.db) .into_iter() .flat_map(|x| x.to_nav(sema.db)) - .filter(|decl| decl.file_id == vfs_file_id) + .filter(|decl| decl.file_id == file_id.file_id(sema.db)) .filter_map(|decl| decl.focus_range) .map(move |range| HighlightedRange { range, category }) .chain(usages) @@ -158,7 +148,6 @@ fn highlight_references( sema: &Semantics<'_, RootDatabase>, token: SyntaxToken, FilePosition { file_id, offset }: FilePosition, - vfs_file_id: FileId, ) -> Option> { let defs = if let Some((range, resolution)) = sema.check_for_format_args_template(token.clone(), offset) @@ -270,7 +259,7 @@ fn highlight_references( .sources(sema.db) .into_iter() .flat_map(|x| x.to_nav(sema.db)) - .filter(|decl| decl.file_id == vfs_file_id) + .filter(|decl| decl.file_id == file_id.file_id(sema.db)) .filter_map(|decl| decl.focus_range) .map(|range| HighlightedRange { range, category }) .for_each(|x| { @@ -288,7 +277,7 @@ fn highlight_references( }, }; for nav in navs { - if nav.file_id != vfs_file_id { + if nav.file_id != file_id.file_id(sema.db) { continue; } let hl_range = nav.focus_range.map(|range| { -- cgit 1.4.1-3-g733a5 From 1b9fb33652b996614a531a3187bd792250a47cf0 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sat, 31 May 2025 12:29:50 +0300 Subject: Account for `Generate` actions when filtering the allowed ones --- src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs index fb8a9838290..02757616d4f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs @@ -103,6 +103,7 @@ pub(crate) fn file_range_uri( pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option { let assist_kind = match &kind { + k if k == &lsp_types::CodeActionKind::EMPTY => AssistKind::Generate, k if k == &lsp_types::CodeActionKind::QUICKFIX => AssistKind::QuickFix, k if k == &lsp_types::CodeActionKind::REFACTOR => AssistKind::Refactor, k if k == &lsp_types::CodeActionKind::REFACTOR_EXTRACT => AssistKind::RefactorExtract, -- cgit 1.4.1-3-g733a5 From 2428070096f9e48f805fba00af0e572f39bdda46 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 31 May 2025 14:36:10 +0200 Subject: fix: Fix manual not containing diagnostics documentation --- src/tools/rust-analyzer/xtask/src/codegen.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/xtask/src/codegen.rs b/src/tools/rust-analyzer/xtask/src/codegen.rs index bba7ad73f38..19ca62e8a32 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen.rs @@ -24,8 +24,8 @@ impl flags::Codegen { grammar::generate(self.check); assists_doc_tests::generate(self.check); parser_inline_tests::generate(self.check); - feature_docs::generate(self.check) - // diagnostics_docs::generate(self.check) doesn't generate any tests + feature_docs::generate(self.check); + diagnostics_docs::generate(self.check); // lints::generate(self.check) Updating clones the rust repo, so don't run it unless // explicitly asked for } -- cgit 1.4.1-3-g733a5 From 81f61acf77b539af47291f23d5eb2617878a3e2a Mon Sep 17 00:00:00 2001 From: Mateusz Mikuła Date: Sun, 27 Apr 2025 13:10:06 +0200 Subject: rustc_llvm: add Windows system libs only when cross-compiling from Windows This obviously doesn't work when cross-compiling from Linux. Split out from: https://github.com/rust-lang/rust/pull/140772 --- compiler/rustc_llvm/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index a662694ac38..9a6549379d3 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -228,10 +228,10 @@ fn main() { let mut cmd = Command::new(&llvm_config); cmd.arg(llvm_link_arg).arg("--libs"); - // Don't link system libs if cross-compiling unless targeting Windows. + // Don't link system libs if cross-compiling unless targeting Windows from Windows host. // On Windows system DLLs aren't linked directly, instead import libraries are used. // These import libraries are independent of the host. - if !is_crossed || target.contains("windows") { + if !is_crossed || target.contains("windows") && host.contains("windows") { cmd.arg("--system-libs"); } -- cgit 1.4.1-3-g733a5 From f57ed46bc6c9369a0fa9db1d53ed4f9a96696b7d Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 6 Mar 2025 13:49:36 -0800 Subject: compiler: add CanonAbi --- compiler/rustc_abi/src/canon_abi.rs | 136 +++++++++++++++++++++++++++++++++++ compiler/rustc_abi/src/extern_abi.rs | 7 +- compiler/rustc_abi/src/lib.rs | 13 +++- compiler/rustc_target/src/json.rs | 6 ++ 4 files changed, 155 insertions(+), 7 deletions(-) create mode 100644 compiler/rustc_abi/src/canon_abi.rs diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs new file mode 100644 index 00000000000..439603df0fa --- /dev/null +++ b/compiler/rustc_abi/src/canon_abi.rs @@ -0,0 +1,136 @@ +use std::fmt; + +#[cfg(feature = "nightly")] +use rustc_macros::HashStable_Generic; + +use crate::{AbiFromStrErr, ExternAbi}; + +/// Calling convention to determine codegen +/// +/// CanonAbi erases certain distinctions ExternAbi preserves, but remains target-dependent. +/// There are still both target-specific variants and aliasing variants, though much fewer. +/// The reason for this step is the frontend may wish to show an ExternAbi but implement that ABI +/// using a different ABI than the string per se, or describe irrelevant differences, e.g. +/// - extern "system" +/// - extern "cdecl" +/// - extern "C-unwind" +/// In that sense, this erases mere syntactic distinctions to create a canonical *directive*, +/// rather than picking the "actual" ABI. +#[derive(Copy, Clone, Debug)] +#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] +pub enum CanonAbi { + // NOTE: the use of nested variants for some ABIs is for many targets they don't matter, + // and this pushes the complexity of their reasoning to target-specific code, + // allowing a `match` to easily exhaustively ignore these subcategories of variants. + // Otherwise it is very tempting to avoid matching exhaustively! + C, + Rust, + RustCold, + + /// ABIs relevant to 32-bit Arm targets + Arm(ArmCall), + /// ABI relevant to GPUs: the entry point for a GPU kernel + GpuKernel, + + /// ABIs relevant to bare-metal interrupt targets + // FIXME(workingjubilee): a particular reason for this nesting is we might not need these? + // interrupt ABIs should have the same properties: + // - uncallable by Rust calls, as LLVM rejects it in most cases + // - uses a preserve-all-registers *callee* convention + // - should always return `-> !` (effectively... it can't use normal `ret`) + // what differs between targets is + // - allowed arguments: x86 differs slightly, having 2-3 arguments which are handled magically + // - may need special prologues/epilogues for some interrupts, without affecting "call ABI" + Interrupt(InterruptKind), + + /// ABIs relevant to Windows or x86 targets + X86(X86Call), +} + +impl fmt::Display for CanonAbi { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.to_erased_extern_abi().as_str().fmt(f) + } +} + +impl CanonAbi { + /// convert to the ExternAbi that *shares a string* with this CanonAbi + /// + /// A target-insensitive mapping of CanonAbi to ExternAbi, convenient for "forwarding" impls. + /// Importantly, the set of CanonAbi values is a logical *subset* of ExternAbi values, + /// so this is injective: if you take an ExternAbi to a CanonAbi and back, you have lost data. + const fn to_erased_extern_abi(self) -> ExternAbi { + match self { + CanonAbi::C => ExternAbi::C { unwind: false }, + CanonAbi::Rust => ExternAbi::Rust, + CanonAbi::RustCold => ExternAbi::RustCold, + CanonAbi::Arm(arm_call) => match arm_call { + ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false }, + ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall, + ArmCall::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry, + }, + CanonAbi::GpuKernel => ExternAbi::GpuKernel, + CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { + InterruptKind::Avr => ExternAbi::AvrInterrupt, + InterruptKind::AvrNonBlocking => ExternAbi::AvrNonBlockingInterrupt, + InterruptKind::Msp430 => ExternAbi::Msp430Interrupt, + InterruptKind::RiscvMachine => ExternAbi::RiscvInterruptM, + InterruptKind::RiscvSupervisor => ExternAbi::RiscvInterruptS, + InterruptKind::X86 => ExternAbi::X86Interrupt, + }, + CanonAbi::X86(x86_call) => match x86_call { + X86Call::Fastcall => ExternAbi::Fastcall { unwind: false }, + X86Call::Stdcall => ExternAbi::Stdcall { unwind: false }, + X86Call::SysV64 => ExternAbi::SysV64 { unwind: false }, + X86Call::Thiscall => ExternAbi::Thiscall { unwind: false }, + X86Call::Vectorcall => ExternAbi::Vectorcall { unwind: false }, + X86Call::Win64 => ExternAbi::Win64 { unwind: false }, + }, + } + } +} + +/// Callee codegen for interrupts +/// +/// This is named differently from the "Call" enums because it is different: +/// these "ABI" differences are not relevant to callers, since there is "no caller". +/// These only affect callee codegen. making their categorization as distinct ABIs a bit peculiar. +#[derive(Copy, Clone, Debug)] +#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] +pub enum InterruptKind { + Avr, + AvrNonBlocking, + Msp430, + RiscvMachine, + RiscvSupervisor, + X86, +} + +/// ABIs defined for x86-{32,64} +/// +/// One of SysV64 or Win64 may alias the C ABI, and arguably Win64 is cross-platform now? +#[derive(Clone, Copy, Debug)] +#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] +pub enum X86Call { + /// "fastcall" has both GNU and Windows variants + Fastcall, + /// "stdcall" has both GNU and Windows variants + Stdcall, + SysV64, + Thiscall, + Vectorcall, + Win64, +} + +/// ABIs defined for 32-bit Arm +#[derive(Copy, Clone, Debug)] +#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] +pub enum ArmCall { + Aapcs, + CCmseNonSecureCall, + CCmseNonSecureEntry, +} diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 55f4845d216..c48920e5f1b 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -7,6 +7,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd}; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable}; +use crate::AbiFromStrErr; + #[cfg(test)] mod tests; @@ -99,11 +101,6 @@ macro_rules! abi_impls { } } -#[derive(Debug)] -pub enum AbiFromStrErr { - Unknown, -} - abi_impls! { ExternAbi = { C { unwind: false } =><= "C", diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 59b74d29221..b806d0aba31 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -55,13 +55,14 @@ use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_Generic}; mod callconv; +mod canon_abi; +mod extern_abi; mod layout; #[cfg(test)] mod tests; -mod extern_abi; - pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind}; +pub use canon_abi::{ArmCall, CanonAbi, InterruptKind, X86Call}; pub use extern_abi::{ExternAbi, all_names}; #[cfg(feature = "nightly")] pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx}; @@ -1895,3 +1896,11 @@ pub enum StructKind { /// A univariant, but with a prefix of an arbitrary size & alignment (e.g., enum tag). Prefixed(Size, Align), } + +#[derive(Clone, Debug)] +pub enum AbiFromStrErr { + /// not a known ABI + Unknown, + /// no "-unwind" variant can be used here + NoExplicitUnwind, +} diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs index 8d6f8f4c6f6..154a6700ce5 100644 --- a/compiler/rustc_target/src/json.rs +++ b/compiler/rustc_target/src/json.rs @@ -140,3 +140,9 @@ impl ToJson for rustc_abi::Endian { self.as_str().to_json() } } + +impl ToJson for rustc_abi::CanonAbi { + fn to_json(&self) -> Json { + self.to_string().to_json() + } +} -- cgit 1.4.1-3-g733a5 From c33b08552b7741828488ada70afdce12122fd97b Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 1 Jun 2025 02:38:24 +0000 Subject: Add `visit_id` to ast `Visitor` This helps with efforts to deduplicate the `MutVisitor` and the `Visitor` code. All users of `Visitor`'s methods that have extra `NodeId` as parameters really just want to visit the id on its own. Also includes some methods deduplicated and cleaned up as a result of this change. --- compiler/rustc_ast/src/mut_visit.rs | 130 --------- compiler/rustc_ast/src/visit.rs | 376 +++++++++++++++----------- compiler/rustc_ast_lowering/src/delegation.rs | 8 +- compiler/rustc_lint/src/early.rs | 37 +-- compiler/rustc_resolve/src/late.rs | 8 +- 5 files changed, 232 insertions(+), 327 deletions(-) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index f1b183e25b5..08726ee6b41 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -12,7 +12,6 @@ use std::panic; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_span::source_map::Spanned; use rustc_span::{Ident, Span}; use smallvec::{Array, SmallVec, smallvec}; use thin_vec::ThinVec; @@ -499,58 +498,6 @@ fn walk_assoc_item_constraint( vis.visit_span(span); } -pub fn walk_ty(vis: &mut T, ty: &mut Ty) { - let Ty { id, kind, span, tokens: _ } = ty; - vis.visit_id(id); - match kind { - TyKind::Err(_guar) => {} - TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Never | TyKind::CVarArgs => { - } - TyKind::Slice(ty) => vis.visit_ty(ty), - TyKind::Ptr(MutTy { ty, mutbl: _ }) => vis.visit_ty(ty), - TyKind::Ref(lt, MutTy { ty, mutbl: _ }) | TyKind::PinnedRef(lt, MutTy { ty, mutbl: _ }) => { - visit_opt(lt, |lt| vis.visit_lifetime(lt)); - vis.visit_ty(ty); - } - TyKind::BareFn(bft) => { - let BareFnTy { safety, ext: _, generic_params, decl, decl_span } = bft.deref_mut(); - visit_safety(vis, safety); - generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - vis.visit_fn_decl(decl); - vis.visit_span(decl_span); - } - TyKind::UnsafeBinder(binder) => { - let UnsafeBinderTy { generic_params, inner_ty } = binder.deref_mut(); - generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - vis.visit_ty(inner_ty); - } - TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)), - TyKind::Paren(ty) => vis.visit_ty(ty), - TyKind::Pat(ty, pat) => { - vis.visit_ty(ty); - vis.visit_ty_pat(pat); - } - TyKind::Path(qself, path) => { - vis.visit_qself(qself); - vis.visit_path(path); - } - TyKind::Array(ty, length) => { - vis.visit_ty(ty); - vis.visit_anon_const(length); - } - TyKind::Typeof(expr) => vis.visit_anon_const(expr), - TyKind::TraitObject(bounds, _syntax) => { - visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::TraitObject)) - } - TyKind::ImplTrait(id, bounds) => { - vis.visit_id(id); - visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Impl)); - } - TyKind::MacCall(mac) => vis.visit_mac_call(mac), - } - vis.visit_span(span); -} - pub fn walk_ty_pat(vis: &mut T, ty: &mut TyPat) { let TyPat { id, kind, span, tokens: _ } = ty; vis.visit_id(id); @@ -588,13 +535,6 @@ fn walk_ident(vis: &mut T, Ident { name: _, span }: &mut Ident) { vis.visit_span(span); } -fn walk_path_segment(vis: &mut T, segment: &mut PathSegment) { - let PathSegment { ident, id, args } = segment; - vis.visit_id(id); - vis.visit_ident(ident); - visit_opt(args, |args| vis.visit_generic_args(args)); -} - fn walk_path(vis: &mut T, Path { segments, span, tokens: _ }: &mut Path) { for segment in segments { vis.visit_path_segment(segment); @@ -729,18 +669,6 @@ fn walk_closure_binder(vis: &mut T, binder: &mut ClosureBinder) { } } -fn walk_coroutine_kind(vis: &mut T, coroutine_kind: &mut CoroutineKind) { - match coroutine_kind { - CoroutineKind::Async { span, closure_id, return_impl_trait_id } - | CoroutineKind::Gen { span, closure_id, return_impl_trait_id } - | CoroutineKind::AsyncGen { span, closure_id, return_impl_trait_id } => { - vis.visit_id(closure_id); - vis.visit_id(return_impl_trait_id); - vis.visit_span(span); - } - } -} - fn walk_fn(vis: &mut T, kind: FnKind<'_>) { match kind { FnKind::Fn( @@ -991,13 +919,6 @@ pub fn walk_flat_map_expr_field( smallvec![f] } -pub fn walk_block(vis: &mut T, block: &mut Block) { - let Block { id, stmts, rules: _, span, tokens: _ } = block; - vis.visit_id(id); - stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); - vis.visit_span(span); -} - pub fn walk_item_kind( kind: &mut K, span: Span, @@ -1041,57 +962,6 @@ pub fn walk_flat_map_assoc_item( smallvec![item] } -pub fn walk_pat(vis: &mut T, pat: &mut Pat) { - let Pat { id, kind, span, tokens: _ } = pat; - vis.visit_id(id); - match kind { - PatKind::Err(_guar) => {} - PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {} - PatKind::Ident(_binding_mode, ident, sub) => { - vis.visit_ident(ident); - visit_opt(sub, |sub| vis.visit_pat(sub)); - } - PatKind::Expr(e) => vis.visit_expr(e), - PatKind::TupleStruct(qself, path, elems) => { - vis.visit_qself(qself); - vis.visit_path(path); - visit_thin_vec(elems, |elem| vis.visit_pat(elem)); - } - PatKind::Path(qself, path) => { - vis.visit_qself(qself); - vis.visit_path(path); - } - PatKind::Struct(qself, path, fields, _etc) => { - vis.visit_qself(qself); - vis.visit_path(path); - fields.flat_map_in_place(|field| vis.flat_map_pat_field(field)); - } - PatKind::Box(inner) => vis.visit_pat(inner), - PatKind::Deref(inner) => vis.visit_pat(inner), - PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner), - PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => { - visit_opt(e1, |e| vis.visit_expr(e)); - visit_opt(e2, |e| vis.visit_expr(e)); - vis.visit_span(span); - } - PatKind::Guard(p, e) => { - vis.visit_pat(p); - vis.visit_expr(e); - } - PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { - visit_thin_vec(elems, |elem| vis.visit_pat(elem)) - } - PatKind::Paren(inner) => vis.visit_pat(inner), - PatKind::MacCall(mac) => vis.visit_mac_call(mac), - } - vis.visit_span(span); -} - -fn walk_anon_const(vis: &mut T, AnonConst { id, value }: &mut AnonConst) { - vis.visit_id(id); - vis.visit_expr(value); -} - fn walk_inline_asm(vis: &mut T, asm: &mut InlineAsm) { // FIXME: Visit spans inside all this currently ignored stuff. let InlineAsm { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e1c2dd05324..908d9fd4bda 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -210,7 +210,7 @@ pub trait Visitor<'ast>: Sized { walk_poly_trait_ref(self, t) } fn visit_variant_data(&mut self, s: &'ast VariantData) -> Self::Result { - walk_struct_def(self, s) + walk_variant_data(self, s) } fn visit_field_def(&mut self, s: &'ast FieldDef) -> Self::Result { walk_field_def(self, s) @@ -233,10 +233,13 @@ pub trait Visitor<'ast>: Sized { fn visit_mac_call(&mut self, mac: &'ast MacCall) -> Self::Result { walk_mac(self, mac) } - fn visit_macro_def(&mut self, _mac: &'ast MacroDef, _id: NodeId) -> Self::Result { + fn visit_id(&mut self, _id: NodeId) -> Self::Result { Self::Result::output() } - fn visit_path(&mut self, path: &'ast Path, _id: NodeId) -> Self::Result { + fn visit_macro_def(&mut self, _mac: &'ast MacroDef) -> Self::Result { + Self::Result::output() + } + fn visit_path(&mut self, path: &'ast Path) -> Self::Result { walk_path(self, path) } fn visit_use_tree( @@ -295,8 +298,8 @@ pub trait Visitor<'ast>: Sized { fn visit_capture_by(&mut self, _capture_by: &'ast CaptureBy) -> Self::Result { Self::Result::output() } - fn visit_coroutine_kind(&mut self, _coroutine_kind: &'ast CoroutineKind) -> Self::Result { - Self::Result::output() + fn visit_coroutine_kind(&mut self, coroutine_kind: &'ast CoroutineKind) -> Self::Result { + walk_coroutine_kind(self, coroutine_kind) } fn visit_fn_decl(&mut self, fn_decl: &'ast FnDecl) -> Self::Result { walk_fn_decl(self, fn_decl) @@ -334,17 +337,14 @@ macro_rules! common_visitor_and_walkers { $(${ignore($lt)}V::Result::output())? } - // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier + /// helper since `Visitor` wants `NodeId` but `MutVisitor` wants `&mut NodeId` $(${ignore($lt)} - #[expect(unused, rustc::pass_by_value)] - #[inline] + #[expect(rustc::pass_by_value)] )? + #[inline] fn visit_id<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, id: &$($lt)? $($mut)? NodeId) $(-> >::Result)? { - $( - ${ignore($mut)} - visitor.visit_id(id); - )? - $(${ignore($lt)}V::Result::output())? + // deref `&NodeId` into `NodeId` only for `Visitor` + visitor.visit_id( $(${ignore($lt)} * )? id) } // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier @@ -577,8 +577,7 @@ macro_rules! common_visitor_and_walkers { ItemKind::MacCall(m) => vis.visit_mac_call(m), ItemKind::MacroDef(ident, def) => { try_visit!(vis.visit_ident(ident)); - // FIXME(fee1-dead) assymetry - vis.visit_macro_def(def$(${ignore($lt)}, id)?) + vis.visit_macro_def(def) } ItemKind::Delegation(box Delegation { id, @@ -591,7 +590,7 @@ macro_rules! common_visitor_and_walkers { }) => { try_visit!(visit_id(vis, id)); try_visit!(vis.visit_qself(qself)); - try_visit!(vis.visit_path(path$(${ignore($lt)}, *id)?)); + try_visit!(vis.visit_path(path)); try_visit!(vis.visit_ident(ident)); visit_opt!(vis, visit_ident, rename); visit_opt!(vis, visit_block, body); @@ -599,7 +598,7 @@ macro_rules! common_visitor_and_walkers { } ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { try_visit!(vis.visit_qself(qself)); - try_visit!(vis.visit_path(prefix$(${ignore($lt)}, id)?)); + try_visit!(vis.visit_path(prefix)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { try_visit!(vis.visit_ident(ident)); @@ -642,8 +641,7 @@ macro_rules! common_visitor_and_walkers { if let Some(define_opaque) = define_opaque { for (id, path) in define_opaque { try_visit!(visit_id(visitor, id)); - // FIXME(fee1-dead): look into this weird assymetry - try_visit!(visitor.visit_path(path$(${ignore($lt)}, *id)?)); + try_visit!(visitor.visit_path(path)); } } $(>::Result::output())? @@ -699,7 +697,7 @@ macro_rules! common_visitor_and_walkers { }) => { try_visit!(visit_id(vis, id)); try_visit!(vis.visit_qself(qself)); - try_visit!(vis.visit_path(path $(${ignore($lt)}, *id)?)); + try_visit!(vis.visit_path(path)); try_visit!(vis.visit_ident(ident)); visit_opt!(vis, visit_ident, rename); visit_opt!(vis, visit_block, body); @@ -707,7 +705,7 @@ macro_rules! common_visitor_and_walkers { } AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { try_visit!(vis.visit_qself(qself)); - try_visit!(vis.visit_path(prefix$(${ignore($lt)}, id)?)); + try_visit!(vis.visit_path(prefix)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { try_visit!(vis.visit_ident(ident)); @@ -773,6 +771,190 @@ macro_rules! common_visitor_and_walkers { } } } + + fn walk_coroutine_kind<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + coroutine_kind: &$($lt)? $($mut)? CoroutineKind, + ) $(-> >::Result)? { + match coroutine_kind { + CoroutineKind::Async { span, closure_id, return_impl_trait_id } + | CoroutineKind::Gen { span, closure_id, return_impl_trait_id } + | CoroutineKind::AsyncGen { span, closure_id, return_impl_trait_id } => { + try_visit!(visit_id(vis, closure_id)); + try_visit!(visit_id(vis, return_impl_trait_id)); + visit_span(vis, span) + } + } + } + + pub fn walk_pat<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + pattern: &$($lt)? $($mut)? Pat + ) $(-> >::Result)? { + let Pat { id, kind, span, tokens: _ } = pattern; + try_visit!(visit_id(vis, id)); + match kind { + PatKind::Err(_guar) => {} + PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {} + PatKind::Ident(_bmode, ident, optional_subpattern) => { + try_visit!(vis.visit_ident(ident)); + visit_opt!(vis, visit_pat, optional_subpattern); + } + PatKind::Expr(expression) => try_visit!(vis.visit_expr(expression)), + PatKind::TupleStruct(opt_qself, path, elems) => { + try_visit!(vis.visit_qself(opt_qself)); + try_visit!(vis.visit_path(path)); + walk_list!(vis, visit_pat, elems); + } + PatKind::Path(opt_qself, path) => { + try_visit!(vis.visit_qself(opt_qself)); + try_visit!(vis.visit_path(path)) + } + PatKind::Struct(opt_qself, path, fields, _rest) => { + try_visit!(vis.visit_qself(opt_qself)); + try_visit!(vis.visit_path(path)); + + $( + ${ignore($lt)} + walk_list!(vis, visit_pat_field, fields); + )? + $( + ${ignore($mut)} + fields.flat_map_in_place(|field| vis.flat_map_pat_field(field)); + )? + } + PatKind::Box(subpattern) | PatKind::Deref(subpattern) | PatKind::Paren(subpattern) => { + try_visit!(vis.visit_pat(subpattern)); + } + PatKind::Ref(subpattern, _ /*mutbl*/) => { + try_visit!(vis.visit_pat(subpattern)); + } + PatKind::Range(lower_bound, upper_bound, _end) => { + visit_opt!(vis, visit_expr, lower_bound); + visit_opt!(vis, visit_expr, upper_bound); + try_visit!(visit_span(vis, span)); + } + PatKind::Guard(subpattern, guard_condition) => { + try_visit!(vis.visit_pat(subpattern)); + try_visit!(vis.visit_expr(guard_condition)); + } + PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { + walk_list!(vis, visit_pat, elems); + } + PatKind::MacCall(mac) => try_visit!(vis.visit_mac_call(mac)), + } + visit_span(vis, span) + } + + pub fn walk_anon_const<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + constant: &$($lt)? $($mut)? AnonConst, + ) $(-> >::Result)? { + let AnonConst { id, value } = constant; + try_visit!(visit_id(vis, id)); + vis.visit_expr(value) + } + + pub fn walk_path_segment<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + segment: &$($lt)? $($mut)? PathSegment, + ) $(-> >::Result)? { + let PathSegment { ident, id, args } = segment; + try_visit!(visit_id(vis, id)); + try_visit!(vis.visit_ident(ident)); + visit_opt!(vis, visit_generic_args, args); + $(>::Result::output())? + } + + pub fn walk_block<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + block: &$($lt)? $($mut)? Block + ) $(-> >::Result)? { + let Block { stmts, id, rules: _, span, tokens: _ } = block; + try_visit!(visit_id(vis, id)); + $( + ${ignore($lt)} + walk_list!(vis, visit_stmt, stmts); + )? + $( + ${ignore($mut)} + stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); + )? + visit_span(vis, span) + } + + + pub fn walk_ty<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, ty: &$($lt)? $($mut)? Ty + ) $(-> >::Result)? { + let Ty { id, kind, span, tokens: _ } = ty; + try_visit!(visit_id(vis, id)); + match kind { + TyKind::Err(_guar) => {} + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Never | TyKind::CVarArgs => {} + TyKind::Slice(ty) | TyKind::Paren(ty) => try_visit!(vis.visit_ty(ty)), + TyKind::Ptr(MutTy { ty, mutbl: _ }) => try_visit!(vis.visit_ty(ty)), + TyKind::Ref(opt_lifetime, MutTy { ty, mutbl: _ }) + | TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl: _ }) => { + // FIXME(fee1-dead) asymmetry + visit_opt!(vis, visit_lifetime, opt_lifetime$(${ignore($lt)}, LifetimeCtxt::Ref)?); + try_visit!(vis.visit_ty(ty)); + } + TyKind::Tup(tuple_element_types) => { + walk_list!(vis, visit_ty, tuple_element_types); + } + TyKind::BareFn(function_declaration) => { + let BareFnTy { safety, ext: _, generic_params, decl, decl_span } = + &$($mut)? **function_declaration; + visit_safety(vis, safety); + $( + ${ignore($lt)} + walk_list!(vis, visit_generic_param, generic_params); + )? + $( + ${ignore($mut)} + generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); + )? + + try_visit!(vis.visit_fn_decl(decl)); + try_visit!(visit_span(vis, decl_span)); + } + TyKind::UnsafeBinder(binder) => { + $( + ${ignore($lt)} + walk_list!(vis, visit_generic_param, &binder.generic_params); + )? + $( + ${ignore($mut)} + binder.generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); + )? + try_visit!(vis.visit_ty(&$($mut)?binder.inner_ty)); + } + TyKind::Path(maybe_qself, path) => { + try_visit!(vis.visit_qself(maybe_qself)); + try_visit!(vis.visit_path(path)); + } + TyKind::Pat(ty, pat) => { + try_visit!(vis.visit_ty(ty)); + try_visit!(vis.visit_ty_pat(pat)); + } + TyKind::Array(ty, length) => { + try_visit!(vis.visit_ty(ty)); + try_visit!(vis.visit_anon_const(length)); + } + TyKind::TraitObject(bounds, _syntax) => { + walk_list!(vis, visit_param_bound, bounds, BoundKind::TraitObject); + } + TyKind::ImplTrait(id, bounds) => { + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_param_bound, bounds, BoundKind::Impl); + } + TyKind::Typeof(expression) => try_visit!(vis.visit_anon_const(expression)), + + TyKind::MacCall(mac) => try_visit!(vis.visit_mac_call(mac)), + } + visit_span(vis, span) + } }; } @@ -808,7 +990,8 @@ where pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitRef) -> V::Result { let TraitRef { path, ref_id } = trait_ref; - visitor.visit_path(path, *ref_id) + try_visit!(visitor.visit_path(path)); + visitor.visit_id(*ref_id) } pub fn walk_enum_def<'a, V: Visitor<'a>>( @@ -848,56 +1031,6 @@ pub fn walk_pat_field<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a PatField) -> V::Result::output() } -pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { - let Ty { id, kind, span: _, tokens: _ } = typ; - match kind { - TyKind::Slice(ty) | TyKind::Paren(ty) => try_visit!(visitor.visit_ty(ty)), - TyKind::Ptr(MutTy { ty, mutbl: _ }) => try_visit!(visitor.visit_ty(ty)), - TyKind::Ref(opt_lifetime, MutTy { ty, mutbl: _ }) - | TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl: _ }) => { - visit_opt!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref); - try_visit!(visitor.visit_ty(ty)); - } - TyKind::Tup(tuple_element_types) => { - walk_list!(visitor, visit_ty, tuple_element_types); - } - TyKind::BareFn(function_declaration) => { - let BareFnTy { safety: _, ext: _, generic_params, decl, decl_span: _ } = - &**function_declaration; - walk_list!(visitor, visit_generic_param, generic_params); - try_visit!(visitor.visit_fn_decl(decl)); - } - TyKind::UnsafeBinder(binder) => { - walk_list!(visitor, visit_generic_param, &binder.generic_params); - try_visit!(visitor.visit_ty(&binder.inner_ty)); - } - TyKind::Path(maybe_qself, path) => { - try_visit!(visitor.visit_qself(maybe_qself)); - try_visit!(visitor.visit_path(path, *id)); - } - TyKind::Pat(ty, pat) => { - try_visit!(visitor.visit_ty(ty)); - try_visit!(visitor.visit_ty_pat(pat)); - } - TyKind::Array(ty, length) => { - try_visit!(visitor.visit_ty(ty)); - try_visit!(visitor.visit_anon_const(length)); - } - TyKind::TraitObject(bounds, _syntax) => { - walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject); - } - TyKind::ImplTrait(_id, bounds) => { - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl); - } - TyKind::Typeof(expression) => try_visit!(visitor.visit_anon_const(expression)), - TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy => {} - TyKind::Err(_guar) => {} - TyKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), - TyKind::Never | TyKind::CVarArgs => {} - } - V::Result::output() -} - pub fn walk_ty_pat<'a, V: Visitor<'a>>(visitor: &mut V, tp: &'a TyPat) -> V::Result { let TyPat { id: _, kind, span: _, tokens: _ } = tp; match kind { @@ -931,7 +1064,8 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>( id: NodeId, ) -> V::Result { let UseTree { prefix, kind, span: _ } = use_tree; - try_visit!(visitor.visit_path(prefix, id)); + try_visit!(visitor.visit_id(id)); + try_visit!(visitor.visit_path(prefix)); match kind { UseTreeKind::Simple(rename) => { // The extra IDs are handled during AST lowering. @@ -947,16 +1081,6 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>( V::Result::output() } -pub fn walk_path_segment<'a, V: Visitor<'a>>( - visitor: &mut V, - segment: &'a PathSegment, -) -> V::Result { - let PathSegment { ident, id: _, args } = segment; - try_visit!(visitor.visit_ident(ident)); - visit_opt!(visitor, visit_generic_args, args); - V::Result::output() -} - pub fn walk_generic_args<'a, V>(visitor: &mut V, generic_args: &'a GenericArgs) -> V::Result where V: Visitor<'a>, @@ -1012,52 +1136,6 @@ pub fn walk_assoc_item_constraint<'a, V: Visitor<'a>>( V::Result::output() } -pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Result { - let Pat { id, kind, span: _, tokens: _ } = pattern; - match kind { - PatKind::TupleStruct(opt_qself, path, elems) => { - try_visit!(visitor.visit_qself(opt_qself)); - try_visit!(visitor.visit_path(path, *id)); - walk_list!(visitor, visit_pat, elems); - } - PatKind::Path(opt_qself, path) => { - try_visit!(visitor.visit_qself(opt_qself)); - try_visit!(visitor.visit_path(path, *id)) - } - PatKind::Struct(opt_qself, path, fields, _rest) => { - try_visit!(visitor.visit_qself(opt_qself)); - try_visit!(visitor.visit_path(path, *id)); - walk_list!(visitor, visit_pat_field, fields); - } - PatKind::Box(subpattern) | PatKind::Deref(subpattern) | PatKind::Paren(subpattern) => { - try_visit!(visitor.visit_pat(subpattern)); - } - PatKind::Ref(subpattern, _ /*mutbl*/) => { - try_visit!(visitor.visit_pat(subpattern)); - } - PatKind::Ident(_bmode, ident, optional_subpattern) => { - try_visit!(visitor.visit_ident(ident)); - visit_opt!(visitor, visit_pat, optional_subpattern); - } - PatKind::Expr(expression) => try_visit!(visitor.visit_expr(expression)), - PatKind::Range(lower_bound, upper_bound, _end) => { - visit_opt!(visitor, visit_expr, lower_bound); - visit_opt!(visitor, visit_expr, upper_bound); - } - PatKind::Guard(subpattern, guard_condition) => { - try_visit!(visitor.visit_pat(subpattern)); - try_visit!(visitor.visit_expr(guard_condition)); - } - PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {} - PatKind::Err(_guar) => {} - PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { - walk_list!(visitor, visit_pat, elems); - } - PatKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), - } - V::Result::output() -} - pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) -> V::Result { match bound { GenericBound::Trait(trait_ref) => visitor.visit_poly_trait_ref(trait_ref), @@ -1075,7 +1153,10 @@ pub fn walk_precise_capturing_arg<'a, V: Visitor<'a>>( ) -> V::Result { match arg { PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg), - PreciseCapturingArg::Arg(path, id) => visitor.visit_path(path, *id), + PreciseCapturingArg::Arg(path, id) => { + try_visit!(visitor.visit_id(*id)); + visitor.visit_path(path) + } } } @@ -1216,11 +1297,9 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu V::Result::output() } -pub fn walk_struct_def<'a, V: Visitor<'a>>( - visitor: &mut V, - struct_definition: &'a VariantData, -) -> V::Result { - walk_list!(visitor, visit_field_def, struct_definition.fields()); +pub fn walk_variant_data<'a, V: Visitor<'a>>(visitor: &mut V, data: &'a VariantData) -> V::Result { + visit_opt!(visitor, visit_id, data.ctor_node_id()); + walk_list!(visitor, visit_field_def, data.fields()); V::Result::output() } @@ -1235,12 +1314,6 @@ pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) V::Result::output() } -pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) -> V::Result { - let Block { stmts, id: _, rules: _, span: _, tokens: _ } = block; - walk_list!(visitor, visit_stmt, stmts); - V::Result::output() -} - pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V::Result { let Stmt { id: _, kind, span: _ } = statement; match kind { @@ -1259,12 +1332,7 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V: pub fn walk_mac<'a, V: Visitor<'a>>(visitor: &mut V, mac: &'a MacCall) -> V::Result { let MacCall { path, args: _ } = mac; - visitor.visit_path(path, DUMMY_NODE_ID) -} - -pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonConst) -> V::Result { - let AnonConst { id: _, value } = constant; - visitor.visit_expr(value) + visitor.visit_path(path) } pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) -> V::Result { @@ -1304,7 +1372,8 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>( InlineAsmSym { id, qself, path }: &'a InlineAsmSym, ) -> V::Result { try_visit!(visitor.visit_qself(qself)); - visitor.visit_path(path, *id) + try_visit!(visitor.visit_id(*id)); + visitor.visit_path(path) } pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs) -> V::Result { @@ -1336,7 +1405,8 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V ExprKind::Struct(se) => { let StructExpr { qself, path, fields, rest } = &**se; try_visit!(visitor.visit_qself(qself)); - try_visit!(visitor.visit_path(path, *id)); + try_visit!(visitor.visit_id(*id)); + try_visit!(visitor.visit_path(path)); walk_list!(visitor, visit_expr_field, fields); match rest { StructRest::Base(expr) => try_visit!(visitor.visit_expr(expr)), @@ -1446,7 +1516,8 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V ExprKind::Underscore => {} ExprKind::Path(maybe_qself, path) => { try_visit!(visitor.visit_qself(maybe_qself)); - try_visit!(visitor.visit_path(path, *id)); + try_visit!(visitor.visit_id(*id)); + try_visit!(visitor.visit_path(path)); } ExprKind::Break(opt_label, opt_expr) => { visit_opt!(visitor, visit_label, opt_label); @@ -1509,7 +1580,8 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) -> V:: let Visibility { kind, span: _, tokens: _ } = vis; match kind { VisibilityKind::Restricted { path, id, shorthand: _ } => { - try_visit!(visitor.visit_path(path, *id)); + try_visit!(visitor.visit_id(*id)); + try_visit!(visitor.visit_path(path)); } VisibilityKind::Public | VisibilityKind::Inherited => {} } @@ -1522,7 +1594,7 @@ pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) AttrKind::Normal(normal) => { let NormalAttr { item, tokens: _ } = &**normal; let AttrItem { unsafety: _, path, args, tokens: _ } = item; - try_visit!(visitor.visit_path(path, DUMMY_NODE_ID)); + try_visit!(visitor.visit_path(path)); try_visit!(walk_attr_args(visitor, args)); } AttrKind::DocComment(_kind, _sym) => {} diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 93c627f64c9..42d25b512f5 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -446,13 +446,7 @@ impl<'a> SelfResolver<'a> { } impl<'ast, 'a> Visitor<'ast> for SelfResolver<'a> { - fn visit_path(&mut self, path: &'ast Path, id: NodeId) { + fn visit_id(&mut self, id: NodeId) { self.try_replace_id(id); - visit::walk_path(self, path); - } - - fn visit_path_segment(&mut self, seg: &'ast PathSegment) { - self.try_replace_id(seg.id); - visit::walk_path_segment(self, seg); } } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 0c62c14af63..4978f293ab7 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -74,8 +74,8 @@ impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> { impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast> for EarlyContextAndPass<'ecx, 'tcx, T> { - fn visit_coroutine_kind(&mut self, coroutine_kind: &'ast ast::CoroutineKind) -> Self::Result { - self.check_id(coroutine_kind.closure_id()); + fn visit_id(&mut self, id: rustc_ast::NodeId) { + self.check_id(id); } fn visit_param(&mut self, param: &'ast ast::Param) { @@ -101,7 +101,6 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast> fn visit_pat(&mut self, p: &'ast ast::Pat) { lint_callback!(self, check_pat, p); - self.check_id(p.id); ast_visit::walk_pat(self, p); lint_callback!(self, check_pat_post, p); } @@ -112,11 +111,6 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast> }); } - fn visit_anon_const(&mut self, c: &'ast ast::AnonConst) { - self.check_id(c.id); - ast_visit::walk_anon_const(self, c); - } - fn visit_expr(&mut self, e: &'ast ast::Expr) { self.with_lint_attrs(e.id, &e.attrs, |cx| { lint_callback!(cx, check_expr, e); @@ -157,13 +151,6 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast> ast_visit::walk_fn(self, fk); } - fn visit_variant_data(&mut self, s: &'ast ast::VariantData) { - if let Some(ctor_node_id) = s.ctor_node_id() { - self.check_id(ctor_node_id); - } - ast_visit::walk_struct_def(self, s); - } - fn visit_field_def(&mut self, s: &'ast ast::FieldDef) { self.with_lint_attrs(s.id, &s.attrs, |cx| { ast_visit::walk_field_def(cx, s); @@ -179,7 +166,6 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast> fn visit_ty(&mut self, t: &'ast ast::Ty) { lint_callback!(self, check_ty, t); - self.check_id(t.id); ast_visit::walk_ty(self, t); } @@ -196,7 +182,6 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast> fn visit_block(&mut self, b: &'ast ast::Block) { lint_callback!(self, check_block, b); - self.check_id(b.id); ast_visit::walk_block(self, b); } @@ -257,29 +242,13 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast> }); } - fn visit_lifetime(&mut self, lt: &'ast ast::Lifetime, _: ast_visit::LifetimeCtxt) { - self.check_id(lt.id); - ast_visit::walk_lifetime(self, lt); - } - - fn visit_path(&mut self, p: &'ast ast::Path, id: ast::NodeId) { - self.check_id(id); - ast_visit::walk_path(self, p); - } - - fn visit_path_segment(&mut self, s: &'ast ast::PathSegment) { - self.check_id(s.id); - ast_visit::walk_path_segment(self, s); - } - fn visit_attribute(&mut self, attr: &'ast ast::Attribute) { lint_callback!(self, check_attribute, attr); ast_visit::walk_attribute(self, attr); } - fn visit_macro_def(&mut self, mac: &'ast ast::MacroDef, id: ast::NodeId) { + fn visit_macro_def(&mut self, mac: &'ast ast::MacroDef) { lint_callback!(self, check_mac_def, mac); - self.check_id(id); } fn visit_mac_call(&mut self, mac: &'ast ast::MacCall) { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index fb1534d0b27..bef0c2b6b14 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -870,7 +870,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r kind: LifetimeBinderKind::PolyTrait, span, }, - |this| this.visit_path(path, ty.id), + |this| this.visit_path(path), ); } else { visit::walk_ty(self, ty) @@ -1261,7 +1261,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r AnonConstKind::ConstArg(IsRepeatExpr::No), |this| { this.smart_resolve_path(ty.id, &None, path, PathSource::Expr(None)); - this.visit_path(path, ty.id); + this.visit_path(path); }, ); @@ -3636,7 +3636,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if let Some(qself) = &delegation.qself { self.visit_ty(&qself.ty); } - self.visit_path(&delegation.path, delegation.id); + self.visit_path(&delegation.path); let Some(body) = &delegation.body else { return }; self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { let span = delegation.path.segments.last().unwrap().ident.span; @@ -4860,7 +4860,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if let Some(qself) = &se.qself { self.visit_ty(&qself.ty); } - self.visit_path(&se.path, expr.id); + self.visit_path(&se.path); walk_list!(self, resolve_expr_field, &se.fields, expr); match &se.rest { StructRest::Base(expr) => self.visit_expr(expr), -- cgit 1.4.1-3-g733a5 From 861ee47551db67a05ad33ab633171f1dc7e6a500 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 1 Jun 2025 22:47:36 +0800 Subject: ci: switch `x86_64-msvc-{1,2}` back to Windows Server 2025 images New Windows Server 2025 images have been released (20250527). --- src/ci/github-actions/jobs.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index dc6a0e1ebad..4417c7ad10d 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -30,8 +30,6 @@ runners: os: windows-2022 <<: *base-job - # FIXME(#141022): Windows Server 2025 20250504.1.0 currently experiences - # insufficient disk space. - &job-windows-25 os: windows-2025 <<: *base-job @@ -492,17 +490,13 @@ auto: env: RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-sanitizers --enable-profiler SCRIPT: make ci-msvc-py - # FIXME(#141022): Windows Server 2025 20250504.1.0 currently experiences - # insufficient disk space. - <<: *job-windows + <<: *job-windows-25 - name: x86_64-msvc-2 env: RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-sanitizers --enable-profiler SCRIPT: make ci-msvc-ps1 - # FIXME(#141022): Windows Server 2025 20250504.1.0 currently experiences - # insufficient disk space. - <<: *job-windows + <<: *job-windows-25 # i686-msvc is split into two jobs to run tests in parallel. - name: i686-msvc-1 -- cgit 1.4.1-3-g733a5 From c6df6a72d8f2463985b6b130673536e6d4cc7cbf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 1 Jun 2025 19:41:03 +0000 Subject: Fix new `dead_code` warnings from recent nightlies --- .../libm/src/math/support/float_traits.rs | 1 + .../libm/src/math/support/hex_float.rs | 207 +++++++++++---------- .../libm/src/math/support/int_traits.rs | 1 + .../libm/src/math/support/macros.rs | 6 +- .../compiler-builtins/libm/src/math/support/mod.rs | 4 +- 5 files changed, 116 insertions(+), 103 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 4c866ef10bd..dd9f46209c1 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -6,6 +6,7 @@ use super::int_traits::{CastFrom, Int, MinInt}; /// Trait for some basic operations on floats // #[allow(dead_code)] +#[allow(dead_code)] // Some constants are only used with tests pub trait Float: Copy + fmt::Debug diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index 85569d98aef..c8558b90053 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -1,8 +1,6 @@ //! Utilities for working with hex float formats. -use core::fmt; - -use super::{Float, Round, Status, f32_from_bits, f64_from_bits}; +use super::{Round, Status, f32_from_bits, f64_from_bits}; /// Construct a 16-bit float from hex float representation (C-style) #[cfg(f16_enabled)] @@ -352,133 +350,143 @@ const fn u128_ilog2(v: u128) -> u32 { u128::BITS - 1 - v.leading_zeros() } -/// Format a floating point number as its IEEE hex (`%a`) representation. -pub struct Hexf(pub F); +#[cfg(any(test, feature = "unstable-public-internals"))] +mod hex_fmt { + use core::fmt; -// Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs -#[cfg(not(feature = "compiler-builtins"))] -fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if x.is_sign_negative() { - write!(f, "-")?; - } + use crate::support::Float; - if x.is_nan() { - return write!(f, "NaN"); - } else if x.is_infinite() { - return write!(f, "inf"); - } else if *x == F::ZERO { - return write!(f, "0x0p+0"); - } + /// Format a floating point number as its IEEE hex (`%a`) representation. + pub struct Hexf(pub F); - let mut exponent = x.exp_unbiased(); - let sig = x.to_bits() & F::SIG_MASK; - - let bias = F::EXP_BIAS as i32; - // The mantissa MSB needs to be shifted up to the nearest nibble. - let mshift = (4 - (F::SIG_BITS % 4)) % 4; - let sig = sig << mshift; - // The width is rounded up to the nearest char (4 bits) - let mwidth = (F::SIG_BITS as usize + 3) / 4; - let leading = if exponent == -bias { - // subnormal number means we shift our output by 1 bit. - exponent += 1; - "0." - } else { - "1." - }; + // Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs + #[cfg(not(feature = "compiler-builtins"))] + pub(super) fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if x.is_sign_negative() { + write!(f, "-")?; + } - write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") -} + if x.is_nan() { + return write!(f, "NaN"); + } else if x.is_infinite() { + return write!(f, "inf"); + } else if *x == F::ZERO { + return write!(f, "0x0p+0"); + } -#[cfg(feature = "compiler-builtins")] -fn fmt_any_hex(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() -} + let mut exponent = x.exp_unbiased(); + let sig = x.to_bits() & F::SIG_MASK; + + let bias = F::EXP_BIAS as i32; + // The mantissa MSB needs to be shifted up to the nearest nibble. + let mshift = (4 - (F::SIG_BITS % 4)) % 4; + let sig = sig << mshift; + // The width is rounded up to the nearest char (4 bits) + let mwidth = (F::SIG_BITS as usize + 3) / 4; + let leading = if exponent == -bias { + // subnormal number means we shift our output by 1 bit. + exponent += 1; + "0." + } else { + "1." + }; -impl fmt::LowerHex for Hexf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt_any_hex(&self.0, f) + write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") + } + + #[cfg(feature = "compiler-builtins")] + pub(super) fn fmt_any_hex(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() + } + + impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt_any_hex(&self.0, f) + } } } } -} -impl fmt::LowerHex for Hexf<(F, F)> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + impl fmt::LowerHex for Hexf<(F, F)> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + } } } } -} -impl fmt::LowerHex for Hexf<(F, i32)> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + impl fmt::LowerHex for Hexf<(F, i32)> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + } } } } -} -impl fmt::LowerHex for Hexf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(&self.0, f) + impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(&self.0, f) + } } } } -} -impl fmt::Debug for Hexf -where - Hexf: fmt::LowerHex, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(self, f) + impl fmt::Debug for Hexf + where + Hexf: fmt::LowerHex, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(self, f) + } } } } -} -impl fmt::Display for Hexf -where - Hexf: fmt::LowerHex, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(self, f) + impl fmt::Display for Hexf + where + Hexf: fmt::LowerHex, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(self, f) + } } } } } +#[cfg(any(test, feature = "unstable-public-internals"))] +pub use hex_fmt::*; + #[cfg(test)] mod parse_tests { extern crate std; @@ -1064,6 +1072,7 @@ mod print_tests { use std::string::ToString; use super::*; + use crate::support::Float; #[test] #[cfg(f16_enabled)] diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index 716af748a9f..9b29e2f4561 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -1,6 +1,7 @@ use core::{cmp, fmt, ops}; /// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] // Some constants are only used with tests pub trait MinInt: Copy + fmt::Debug diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index 0b72db0e46e..2b8fd580a50 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -137,12 +137,12 @@ macro_rules! hf128 { #[cfg(test)] macro_rules! assert_biteq { ($left:expr, $right:expr, $($tt:tt)*) => {{ - use $crate::support::Int; let l = $left; let r = $right; - let bits = Int::leading_zeros(l.to_bits() - l.to_bits()); // hack to get the width from the value + // hack to get width from a value + let bits = $crate::support::Int::leading_zeros(l.to_bits() - l.to_bits()); assert!( - l.biteq(r), + $crate::support::Float::biteq(l, r), "{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", format_args!($($tt)*), lb = l.to_bits(), diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 2771cfd32c8..2e7edd03c42 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -17,6 +17,8 @@ pub use env::{FpResult, Round, Status}; #[allow(unused_imports)] pub use float_traits::{DFloat, Float, HFloat, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; +#[cfg(any(test, feature = "unstable-public-internals"))] +pub use hex_float::Hexf; #[cfg(f16_enabled)] #[allow(unused_imports)] pub use hex_float::hf16; @@ -24,7 +26,7 @@ pub use hex_float::hf16; #[allow(unused_imports)] pub use hex_float::hf128; #[allow(unused_imports)] -pub use hex_float::{Hexf, hf32, hf64}; +pub use hex_float::{hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; /// Hint to the compiler that the current path is cold. -- cgit 1.4.1-3-g733a5 From 0a7e59265a3432d6544b35d93120b66f45a67159 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 1 Jun 2025 19:22:42 +0000 Subject: Upgrade all dependencies to the latest available version In particular, this includes a fix to `iai-callgrind` that will allow us to simplify our benchmark runner. --- library/compiler-builtins/builtins-test/Cargo.toml | 8 ++++---- library/compiler-builtins/compiler-builtins/Cargo.toml | 4 ++-- library/compiler-builtins/crates/libm-macros/Cargo.toml | 4 ++-- library/compiler-builtins/crates/musl-math-sys/Cargo.toml | 2 +- library/compiler-builtins/libm-test/Cargo.toml | 14 +++++++------- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index 10978c0bb7e..c7742aa2427 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -10,11 +10,11 @@ license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" # For fuzzing tests we want a deterministic seedable RNG. We also eliminate potential # problems with system RNGs on the variety of platforms this crate is tested on. # `xoshiro128**` is used for its quality, size, and speed at generating `u32` shift amounts. -rand_xoshiro = "0.6" +rand_xoshiro = "0.7" # To compare float builtins against -rustc_apfloat = "0.2.1" +rustc_apfloat = "0.2.2" # Really a dev dependency, but dev dependencies can't be optional -iai-callgrind = { version = "0.14.0", optional = true } +iai-callgrind = { version = "0.14.1", optional = true } [dependencies.compiler_builtins] path = "../compiler-builtins" @@ -22,7 +22,7 @@ default-features = false features = ["unstable-public-internals"] [dev-dependencies] -criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } +criterion = { version = "0.6.0", default-features = false, features = ["cargo_bench_support"] } paste = "1.0.15" [target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 8ceef286f57..6bee8da68a0 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -19,10 +19,10 @@ test = false [dependencies] # For more information on this dependency see # https://github.com/rust-lang/rust/tree/master/library/rustc-std-workspace-core -core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } +core = { version = "1.0.1", optional = true, package = "rustc-std-workspace-core" } [build-dependencies] -cc = { optional = true, version = "1.0" } +cc = { optional = true, version = "1.2" } [dev-dependencies] panic-handler = { path = "../crates/panic-handler" } diff --git a/library/compiler-builtins/crates/libm-macros/Cargo.toml b/library/compiler-builtins/crates/libm-macros/Cargo.toml index 3929854f08e..6bbf47784ff 100644 --- a/library/compiler-builtins/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/crates/libm-macros/Cargo.toml @@ -10,9 +10,9 @@ proc-macro = true [dependencies] heck = "0.5.0" -proc-macro2 = "1.0.94" +proc-macro2 = "1.0.95" quote = "1.0.40" -syn = { version = "2.0.100", features = ["full", "extra-traits", "visit-mut"] } +syn = { version = "2.0.101", features = ["full", "extra-traits", "visit-mut"] } [lints.rust] # Values used during testing diff --git a/library/compiler-builtins/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/crates/musl-math-sys/Cargo.toml index d3fb147e526..3b88117343b 100644 --- a/library/compiler-builtins/crates/musl-math-sys/Cargo.toml +++ b/library/compiler-builtins/crates/musl-math-sys/Cargo.toml @@ -11,4 +11,4 @@ license = "MIT OR Apache-2.0" libm = { path = "../../libm" } [build-dependencies] -cc = "1.2.16" +cc = "1.2.25" diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index 7a306e73557..01b45716b7a 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -28,28 +28,28 @@ icount = ["dep:iai-callgrind"] short-benchmarks = [] [dependencies] -anyhow = "1.0.97" +anyhow = "1.0.98" # This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. -gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } -iai-callgrind = { version = "0.14.0", optional = true } +gmp-mpfr-sys = { version = "1.6.5", optional = true, default-features = false } +iai-callgrind = { version = "0.14.1", optional = true } indicatif = { version = "0.17.11", default-features = false } libm = { path = "../libm", features = ["unstable-public-internals"] } libm-macros = { path = "../crates/libm-macros" } musl-math-sys = { path = "../crates/musl-math-sys", optional = true } paste = "1.0.15" -rand = "0.9.0" +rand = "0.9.1" rand_chacha = "0.9.0" rayon = "1.10.0" rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "integer", "std"] } [target.'cfg(target_family = "wasm")'.dependencies] -getrandom = { version = "0.3.2", features = ["wasm_js"] } +getrandom = { version = "0.3.3", features = ["wasm_js"] } [build-dependencies] -rand = { version = "0.9.0", optional = true } +rand = { version = "0.9.1", optional = true } [dev-dependencies] -criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } +criterion = { version = "0.6.0", default-features = false, features = ["cargo_bench_support"] } libtest-mimic = "0.8.1" [[bench]] -- cgit 1.4.1-3-g733a5 From 198e89b533240c6c70ed07e6de66e4f9869c406d Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sun, 25 May 2025 18:29:56 +0200 Subject: Improve documentation for codegen options This adds more information to many different codegen options. It should not add any new guarantees, just document existing behavior. --- src/doc/rustc/src/codegen-options/index.md | 52 ++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index a3b70e7f977..95e6afae8a1 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -192,6 +192,8 @@ to save information after compiling a crate to be reused when recompiling the crate, improving re-compile times. This takes a path to a directory where incremental files will be stored. +Using incremental compilation inhibits certain optimizations (for example by increasing the amount of codegen units) and is therefore not recommend for release builds. + ## inline-threshold This option is deprecated and does nothing. @@ -213,6 +215,8 @@ This flag lets you append a single extra argument to the linker invocation. "Append" is significant; you can pass this flag multiple times to add multiple arguments. +On Unix-like targets that use `cc` as the linker driver, use `-Clink-arg=-Wl,$ARG` to pass an argument to the actual linker. + ## link-args This flag lets you append multiple extra arguments to the linker invocation. The @@ -248,6 +252,10 @@ path to the linker executable. If this flag is not specified, the linker will be inferred based on the target. See also the [linker-flavor](#linker-flavor) flag for another way to specify the linker. +Note that on Unix-like targets (for example, `*-unknown-linux-gnu` or `*-unknown-freebsd`) +the C compiler (for example `cc` or `clang`) is used as the "linker" here, serving as a linker driver. +It will invoke the actual linker with all the necessary flags to be able to link against the system libraries like libc. + ## linker-flavor This flag controls the linker flavor used by `rustc`. If a linker is given with @@ -301,6 +309,12 @@ The list must be separated by spaces. Pass `--help` to see a list of options. +
+ +Because this flag directly talks to LLVM, it is not subject to the usual stability guarantees of rustc's CLI interface. + +
+ ## lto This flag controls whether LLVM uses [link time @@ -315,6 +329,7 @@ linking time. It takes one of the following values: LTO](http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html). This is similar to "fat", but takes substantially less time to run while still achieving performance gains similar to "fat". + For larger projects like the Rust compiler, ThinLTO can even result in better performance than fat LTO. If `-C lto` is not specified, then the compiler will attempt to perform "thin local LTO" which performs "thin" LTO on the local crate only across its @@ -343,6 +358,8 @@ between two different versions of the same crate being linked. This flag tells the pass manager to use an empty list of passes, instead of the usual pre-populated list of passes. +When combined with `-O --emit llvm-ir`, it can be used to see the optimized LLVM IR emitted by rustc before any optimizations are applied by LLVM. + ## no-redzone This flag allows you to disable [the @@ -379,7 +396,7 @@ This flag controls the optimization level. * `2`: some optimizations. * `3`: all optimizations. * `s`: optimize for binary size. -* `z`: optimize for binary size, but also turn off loop vectorization. +* `z`: optimize for binary size, but more aggressively. Often results in larger binaries than `s` Note: The [`-O` flag][option-o-optimize] is an alias for `-C opt-level=3`. @@ -407,6 +424,9 @@ This option lets you control what happens when the code panics. If not specified, the default depends on the target. +If any crate in the crate graph uses `abort`, the final binary (`bin`, `dylib`, `cdylib`, `staticlib`) must also use `abort`. +If `std` is used as a `dylib` with `unwind`, the final binary must also use `unwind`. + ## passes This flag can be used to add extra [LLVM @@ -416,6 +436,12 @@ The list must be separated by spaces. See also the [`no-prepopulate-passes`](#no-prepopulate-passes) flag. +
+ +Because this flag directly talks to LLVM, it not subject to the usual stability guarantees of rustc's CLI interface. + +
+ ## prefer-dynamic By default, `rustc` prefers to statically link dependencies. This option will @@ -523,12 +549,30 @@ The list of passes should be separated by spaces. ## rpath -This flag controls whether [`rpath`](https://en.wikipedia.org/wiki/Rpath) is -enabled. It takes one of the following values: +This flag controls whether rustc sets an [`rpath`](https://en.wikipedia.org/wiki/Rpath) for the binary. +It takes one of the following values: * `y`, `yes`, `on`, `true` or no value: enable rpath. * `n`, `no`, `off` or `false`: disable rpath (the default). +This flag only does something on Unix-like platforms (Mach-O and ELF), it is ignored on other platforms. + +If enabled, rustc will add output-relative (using `@load_path` on Mach-O and `$ORIGIN` on ELF respectively) rpaths to all `dylib` dependencies. + +For example, for the following directory structure, with `libdep.so` being a `dylib` crate compiled with `-Cprefer-dynamic`: + +```text +dep + |- libdep.so +a.rs +``` + +`rustc a.rs --extern dep=dep/libdep.so -Crpath` will, on x86-64 Linux, result in approximately the following `DT_RUNPATH`: `$ORIGIN/dep:$ORIGIN/$RELATIVE_PATH_TO_SYSROOT/lib/rustlib/x86_64-unknown-linux-gnu/lib` (where `RELATIVE_PATH_TO_SYSROOT` depends on the build directory location). + +This is primarily useful for local development, to ensure that all the `dylib` dependencies can be found appropriately. + +To set the rpath to a different value (which can be useful for distribution), `-Clink-arg` with a platform-specific linker argument can be used to set the rpath directly. + ## save-temps This flag controls whether temporary files generated during compilation are @@ -545,6 +589,8 @@ point instructions in software. It takes one of the following values: * `y`, `yes`, `on`, `true` or no value: use soft floats. * `n`, `no`, `off` or `false`: use hardware floats (the default). +This flag only works on `*eabihf` targets and **is unsound and deprecated**. + ## split-debuginfo This option controls the emission of "split debuginfo" for debug information -- cgit 1.4.1-3-g733a5 From 80e44de2d37c7f9597707cbba1287fdd03cdcae5 Mon Sep 17 00:00:00 2001 From: usamoi Date: Mon, 2 Jun 2025 17:49:28 +0800 Subject: remove f16: From --- library/core/src/convert/num.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index d5cb10a5d1c..50616732b77 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -175,7 +175,6 @@ impl_from!(u8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0") impl_from!(u8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u8 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(u16 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -- cgit 1.4.1-3-g733a5 From 6be3c3ceb7351677999c661dfba0110992b37132 Mon Sep 17 00:00:00 2001 From: Luca Palmieri <20745048+LukeMathWalker@users.noreply.github.com> Date: Mon, 2 Jun 2025 13:43:51 +0200 Subject: [rustdoc-json] Implement PartialOrd and Ord for rustdoc_types::Id --- src/rustdoc-json-types/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index c091c955ed5..f1c375bd2fe 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -388,7 +388,7 @@ pub enum AssocItemConstraintKind { /// Rustdoc makes no guarantees about the inner value of Id's. Applications /// should treat them as opaque keys to lookup items, and avoid attempting /// to parse them, or otherwise depend on any implementation details. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] // FIXME(aDotInTheVoid): Consider making this non-public in rustdoc-types. pub struct Id(pub u32); -- cgit 1.4.1-3-g733a5 From 0505ee514bdc10acb492bf5d3be500a84dd6f06e Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Mon, 2 Jun 2025 13:23:24 +0200 Subject: Use ccache for stage0 tool and rustc builds --- src/bootstrap/src/core/build_steps/compile.rs | 11 +++++++++++ src/bootstrap/src/core/build_steps/tool.rs | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index a782d0f6b1a..37d53ce476a 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1278,6 +1278,17 @@ pub fn rustc_cargo( )); } + // The stage0 compiler changes infrequently and does not directly depend on code + // in the current working directory. Therefore, caching it with sccache should be + // useful. + // This is only performed for non-incremental builds, as ccache cannot deal with these. + if let Some(ref ccache) = builder.config.ccache + && compiler.stage == 0 + && !builder.config.incremental + { + cargo.env("RUSTC_WRAPPER", ccache); + } + rustc_cargo_env(builder, cargo, target, compiler.stage); } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 173b3ff0816..acab02e0902 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -148,6 +148,17 @@ impl Step for ToolBuild { &self.extra_features, ); + // The stage0 compiler changes infrequently and does not directly depend on code + // in the current working directory. Therefore, caching it with sccache should be + // useful. + // This is only performed for non-incremental builds, as ccache cannot deal with these. + if let Some(ref ccache) = builder.config.ccache + && matches!(self.mode, Mode::ToolBootstrap) + && !builder.config.incremental + { + cargo.env("RUSTC_WRAPPER", ccache); + } + // Rustc tools (miri, clippy, cargo, rustfmt, rust-analyzer) // could use the additional optimizations. if self.mode == Mode::ToolRustc && is_lto_stage(&self.compiler) { -- cgit 1.4.1-3-g733a5 From a6a1c1b247aa0fa404983efa3c226c25cafdd704 Mon Sep 17 00:00:00 2001 From: Ell Date: Fri, 30 May 2025 10:57:08 +0300 Subject: Separately check equality of the scalar types and compound types in the order of declaration. --- compiler/rustc_ast/src/ast.rs | 33 ++++ .../src/deriving/cmp/partial_eq.rs | 215 +++++++++++++++------ .../src/deriving/generic/mod.rs | 5 +- tests/ui/deriving/deriving-all-codegen.rs | 30 +++ tests/ui/deriving/deriving-all-codegen.stdout | 165 ++++++++++++++++ 5 files changed, 390 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a16219361c0..1d4df97da58 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2452,6 +2452,39 @@ impl TyKind { None } } + + /// Returns `true` if this type is considered a scalar primitive (e.g., + /// `i32`, `u8`, `bool`, etc). + /// + /// This check is based on **symbol equality** and does **not** remove any + /// path prefixes or references. If a type alias or shadowing is present + /// (e.g., `type i32 = CustomType;`), this method will still return `true` + /// for `i32`, even though it may not refer to the primitive type. + pub fn maybe_scalar(&self) -> bool { + let Some(ty_sym) = self.is_simple_path() else { + // unit type + return self.is_unit(); + }; + matches!( + ty_sym, + sym::i8 + | sym::i16 + | sym::i32 + | sym::i64 + | sym::i128 + | sym::u8 + | sym::u16 + | sym::u32 + | sym::u64 + | sym::u128 + | sym::f16 + | sym::f32 + | sym::f64 + | sym::f128 + | sym::char + | sym::bool + ) + } } /// A pattern type pattern. diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 4b93b3414c7..b1d950b8d89 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -8,6 +8,8 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::{path_local, path_std}; +/// Expands a `#[derive(PartialEq)]` attribute into an implementation for the +/// target item. pub(crate) fn expand_deriving_partial_eq( cx: &ExtCtxt<'_>, span: Span, @@ -16,62 +18,6 @@ pub(crate) fn expand_deriving_partial_eq( push: &mut dyn FnMut(Annotatable), is_const: bool, ) { - fn cs_eq(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { - let base = true; - let expr = cs_fold( - true, // use foldl - cx, - span, - substr, - |cx, fold| match fold { - CsFold::Single(field) => { - let [other_expr] = &field.other_selflike_exprs[..] else { - cx.dcx() - .span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`"); - }; - - // We received arguments of type `&T`. Convert them to type `T` by stripping - // any leading `&`. This isn't necessary for type checking, but - // it results in better error messages if something goes wrong. - // - // Note: for arguments that look like `&{ x }`, which occur with packed - // structs, this would cause expressions like `{ self.x } == { other.x }`, - // which isn't valid Rust syntax. This wouldn't break compilation because these - // AST nodes are constructed within the compiler. But it would mean that code - // printed by `-Zunpretty=expanded` (or `cargo expand`) would have invalid - // syntax, which would be suboptimal. So we wrap these in parens, giving - // `({ self.x }) == ({ other.x })`, which is valid syntax. - let convert = |expr: &P| { - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = - &expr.kind - { - if let ExprKind::Block(..) = &inner.kind { - // `&{ x }` form: remove the `&`, add parens. - cx.expr_paren(field.span, inner.clone()) - } else { - // `&x` form: remove the `&`. - inner.clone() - } - } else { - expr.clone() - } - }; - cx.expr_binary( - field.span, - BinOpKind::Eq, - convert(&field.self_expr), - convert(other_expr), - ) - } - CsFold::Combine(span, expr1, expr2) => { - cx.expr_binary(span, BinOpKind::And, expr1, expr2) - } - CsFold::Fieldless => cx.expr_bool(span, base), - }, - ); - BlockOrExpr::new_expr(expr) - } - let structural_trait_def = TraitDef { span, path: path_std!(marker::StructuralPartialEq), @@ -97,7 +43,9 @@ pub(crate) fn expand_deriving_partial_eq( ret_ty: Path(path_local!(bool)), attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))), + combine_substructure: combine_substructure(Box::new(|a, b, c| { + BlockOrExpr::new_expr(get_substructure_equality_expr(a, b, c)) + })), }]; let trait_def = TraitDef { @@ -113,3 +61,156 @@ pub(crate) fn expand_deriving_partial_eq( }; trait_def.expand(cx, mitem, item, push) } + +/// Generates the equality expression for a struct or enum variant when deriving +/// `PartialEq`. +/// +/// This function generates an expression that checks if all fields of a struct +/// or enum variant are equal. +/// - Scalar fields are compared first for efficiency, followed by compound +/// fields. +/// - If there are no fields, returns `true` (fieldless types are always equal). +/// +/// Whether a field is considered "scalar" is determined by comparing the symbol +/// of its type to a set of known scalar type symbols (e.g., `i32`, `u8`, etc). +/// This check is based on the type's symbol. +/// +/// ### Example 1 +/// ``` +/// #[derive(PartialEq)] +/// struct i32; +/// +/// // Here, `field_2` is of type `i32`, but since it's a user-defined type (not +/// // the primitive), it will not be treated as scalar. The function will still +/// // check equality of `field_2` first because the symbol matches `i32`. +/// #[derive(PartialEq)] +/// struct Struct { +/// field_1: &'static str, +/// field_2: i32, +/// } +/// ``` +/// +/// ### Example 2 +/// ``` +/// mod ty { +/// pub type i32 = i32; +/// } +/// +/// // Here, `field_2` is of type `ty::i32`, which is a type alias for `i32`. +/// // However, the function will not reorder the fields because the symbol for +/// // `ty::i32` does not match the symbol for the primitive `i32` +/// // ("ty::i32" != "i32"). +/// #[derive(PartialEq)] +/// struct Struct { +/// field_1: &'static str, +/// field_2: ty::i32, +/// } +/// ``` +/// +/// For enums, the discriminant is compared first, then the rest of the fields. +/// +/// # Panics +/// +/// If called on static or all-fieldless enums/structs, which should not occur +/// during derive expansion. +fn get_substructure_equality_expr( + cx: &ExtCtxt<'_>, + span: Span, + substructure: &Substructure<'_>, +) -> P { + use SubstructureFields::*; + + match substructure.fields { + EnumMatching(.., fields) | Struct(.., fields) => { + let combine = move |acc, field| { + let rhs = get_field_equality_expr(cx, field); + if let Some(lhs) = acc { + // Combine the previous comparison with the current field + // using logical AND. + return Some(cx.expr_binary(field.span, BinOpKind::And, lhs, rhs)); + } + // Start the chain with the first field's comparison. + Some(rhs) + }; + + // First compare scalar fields, then compound fields, combining all + // with logical AND. + return fields + .iter() + .filter(|field| !field.maybe_scalar) + .fold(fields.iter().filter(|field| field.maybe_scalar).fold(None, combine), combine) + // If there are no fields, treat as always equal. + .unwrap_or_else(|| cx.expr_bool(span, true)); + } + EnumDiscr(disc, match_expr) => { + let lhs = get_field_equality_expr(cx, disc); + let Some(match_expr) = match_expr else { + return lhs; + }; + // Compare the discriminant first (cheaper), then the rest of the + // fields. + return cx.expr_binary(disc.span, BinOpKind::And, lhs, match_expr.clone()); + } + StaticEnum(..) => cx.dcx().span_bug( + span, + "unexpected static enum encountered during `derive(PartialEq)` expansion", + ), + StaticStruct(..) => cx.dcx().span_bug( + span, + "unexpected static struct encountered during `derive(PartialEq)` expansion", + ), + AllFieldlessEnum(..) => cx.dcx().span_bug( + span, + "unexpected all-fieldless enum encountered during `derive(PartialEq)` expansion", + ), + } +} + +/// Generates an equality comparison expression for a single struct or enum +/// field. +/// +/// This function produces an AST expression that compares the `self` and +/// `other` values for a field using `==`. It removes any leading references +/// from both sides for readability. If the field is a block expression, it is +/// wrapped in parentheses to ensure valid syntax. +/// +/// # Panics +/// +/// Panics if there are not exactly two arguments to compare (should be `self` +/// and `other`). +fn get_field_equality_expr(cx: &ExtCtxt<'_>, field: &FieldInfo) -> P { + let [rhs] = &field.other_selflike_exprs[..] else { + cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`"); + }; + + cx.expr_binary( + field.span, + BinOpKind::Eq, + wrap_block_expr(cx, peel_refs(&field.self_expr)), + wrap_block_expr(cx, peel_refs(rhs)), + ) +} + +/// Removes all leading immutable references from an expression. +/// +/// This is used to strip away any number of leading `&` from an expression +/// (e.g., `&&&T` becomes `T`). Only removes immutable references; mutable +/// references are preserved. +fn peel_refs(mut expr: &P) -> P { + while let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = &expr.kind { + expr = &inner; + } + expr.clone() +} + +/// Wraps a block expression in parentheses to ensure valid AST in macro +/// expansion output. +/// +/// If the given expression is a block, it is wrapped in parentheses; otherwise, +/// it is returned unchanged. +fn wrap_block_expr(cx: &ExtCtxt<'_>, expr: P) -> P { + if matches!(&expr.kind, ExprKind::Block(..)) { + return cx.expr_paren(expr.span, expr); + } + expr +} diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 9aa53f9e4f7..e0e44841acb 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -284,6 +284,7 @@ pub(crate) struct FieldInfo { /// The expressions corresponding to references to this field in /// the other selflike arguments. pub other_selflike_exprs: Vec>, + pub maybe_scalar: bool, } #[derive(Copy, Clone)] @@ -1220,7 +1221,8 @@ impl<'a> MethodDef<'a> { let self_expr = discr_exprs.remove(0); let other_selflike_exprs = discr_exprs; - let discr_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs }; + let discr_field = + FieldInfo { span, name: None, self_expr, other_selflike_exprs, maybe_scalar: true }; let discr_let_stmts: ThinVec<_> = iter::zip(&discr_idents, &selflike_args) .map(|(&ident, selflike_arg)| { @@ -1533,6 +1535,7 @@ impl<'a> TraitDef<'a> { name: struct_field.ident, self_expr, other_selflike_exprs, + maybe_scalar: struct_field.ty.peel_refs().kind.maybe_scalar(), } }) .collect() diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/deriving/deriving-all-codegen.rs index eab2b4f1f53..e2b6804fbd1 100644 --- a/tests/ui/deriving/deriving-all-codegen.rs +++ b/tests/ui/deriving/deriving-all-codegen.rs @@ -45,6 +45,22 @@ struct Big { b1: u32, b2: u32, b3: u32, b4: u32, b5: u32, b6: u32, b7: u32, b8: u32, } +// It is more efficient to compare scalar types before non-scalar types. +#[derive(PartialEq, PartialOrd)] +struct Reorder { + b1: Option, + b2: u16, + b3: &'static str, + b4: i8, + b5: u128, + _b: *mut &'static dyn FnMut() -> (), + b6: f64, + b7: &'static mut (), + b8: char, + b9: &'static [i64], + b10: &'static *const bool, +} + // A struct that doesn't impl `Copy`, which means it gets the non-simple // `clone` implemention that clones the fields individually. #[derive(Clone)] @@ -130,6 +146,20 @@ enum Mixed { S { d1: Option, d2: Option }, } +// When comparing enum variant it is more efficient to compare scalar types before non-scalar types. +#[derive(PartialEq, PartialOrd)] +enum ReorderEnum { + A(i32), + B, + C(i8), + D, + E, + F, + G(&'static mut str, *const u8, *const dyn Fn() -> ()), + H, + I, +} + // An enum with no fieldless variants. Note that `Default` cannot be derived // for this enum. #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index 6503c870990..fa8f249373d 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -419,6 +419,100 @@ impl ::core::cmp::Ord for Big { } } +// It is more efficient to compare scalar types before non-scalar types. +struct Reorder { + b1: Option, + b2: u16, + b3: &'static str, + b4: i8, + b5: u128, + _b: *mut &'static dyn FnMut() -> (), + b6: f64, + b7: &'static mut (), + b8: char, + b9: &'static [i64], + b10: &'static *const bool, +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for Reorder { } +#[automatically_derived] +impl ::core::cmp::PartialEq for Reorder { + #[inline] + fn eq(&self, other: &Reorder) -> bool { + self.b2 == other.b2 && self.b4 == other.b4 && self.b5 == other.b5 && + self.b6 == other.b6 && self.b7 == other.b7 && + self.b8 == other.b8 && self.b10 == other.b10 && + self.b1 == other.b1 && self.b3 == other.b3 && + self._b == other._b && self.b9 == other.b9 + } +} +#[automatically_derived] +impl ::core::cmp::PartialOrd for Reorder { + #[inline] + fn partial_cmp(&self, other: &Reorder) + -> ::core::option::Option<::core::cmp::Ordering> { + match ::core::cmp::PartialOrd::partial_cmp(&self.b1, &other.b1) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + match ::core::cmp::PartialOrd::partial_cmp(&self.b2, + &other.b2) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.b3, + &other.b3) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.b4, + &other.b4) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.b5, + &other.b5) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self._b, + &other._b) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.b6, + &other.b6) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.b7, + &other.b7) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.b8, + &other.b8) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.b9, + &other.b9) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + ::core::cmp::PartialOrd::partial_cmp(&self.b10, &other.b10), + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + } + } +} + // A struct that doesn't impl `Copy`, which means it gets the non-simple // `clone` implemention that clones the fields individually. struct NonCopy(u32); @@ -1167,6 +1261,77 @@ impl ::core::cmp::Ord for Mixed { } } +// When comparing enum variant it is more efficient to compare scalar types before non-scalar types. +enum ReorderEnum { + A(i32), + B, + C(i8), + D, + E, + F, + G(&'static mut str, *const u8, *const dyn Fn() -> ()), + H, + I, +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for ReorderEnum { } +#[automatically_derived] +impl ::core::cmp::PartialEq for ReorderEnum { + #[inline] + fn eq(&self, other: &ReorderEnum) -> bool { + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + __self_discr == __arg1_discr && + match (self, other) { + (ReorderEnum::A(__self_0), ReorderEnum::A(__arg1_0)) => + __self_0 == __arg1_0, + (ReorderEnum::C(__self_0), ReorderEnum::C(__arg1_0)) => + __self_0 == __arg1_0, + (ReorderEnum::G(__self_0, __self_1, __self_2), + ReorderEnum::G(__arg1_0, __arg1_1, __arg1_2)) => + __self_1 == __arg1_1 && __self_0 == __arg1_0 && + __self_2 == __arg1_2, + _ => true, + } + } +} +#[automatically_derived] +impl ::core::cmp::PartialOrd for ReorderEnum { + #[inline] + fn partial_cmp(&self, other: &ReorderEnum) + -> ::core::option::Option<::core::cmp::Ordering> { + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + match ::core::cmp::PartialOrd::partial_cmp(&__self_discr, + &__arg1_discr) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + match (self, other) { + (ReorderEnum::A(__self_0), ReorderEnum::A(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + (ReorderEnum::C(__self_0), ReorderEnum::C(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + (ReorderEnum::G(__self_0, __self_1, __self_2), + ReorderEnum::G(__arg1_0, __arg1_1, __arg1_2)) => + match ::core::cmp::PartialOrd::partial_cmp(__self_0, + __arg1_0) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(__self_1, + __arg1_1) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => ::core::cmp::PartialOrd::partial_cmp(__self_2, __arg1_2), + cmp => cmp, + }, + cmp => cmp, + }, + _ => + ::core::option::Option::Some(::core::cmp::Ordering::Equal), + }, + cmp => cmp, + } + } +} + // An enum with no fieldless variants. Note that `Default` cannot be derived // for this enum. enum Fielded { X(u32), Y(bool), Z(Option), } -- cgit 1.4.1-3-g733a5 From 65730a3c4b0cc25bb9cb89af110d112b52aa9994 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 2 Jun 2025 15:35:57 +0300 Subject: bootstrap: Remove `rustc_snapshot_libdir` from PATH in one more place --- src/bootstrap/src/core/build_steps/tool.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 173b3ff0816..4cf62bc8ddc 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1302,10 +1302,8 @@ impl Builder<'_> { // // Notably this munges the dynamic library lookup path to point to the // right location to run `compiler`. - let mut lib_paths: Vec = vec![ - self.build.rustc_snapshot_libdir(), - self.cargo_out(compiler, Mode::ToolBootstrap, *host).join("deps"), - ]; + let mut lib_paths: Vec = + vec![self.cargo_out(compiler, Mode::ToolBootstrap, *host).join("deps")]; // On MSVC a tool may invoke a C compiler (e.g., compiletest in run-make // mode) and that C compiler may need some extra PATH modification. Do -- cgit 1.4.1-3-g733a5 From ec9e560a3010a8424b241d1671bdd81d87011204 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Mon, 2 Jun 2025 15:08:39 +0200 Subject: Fix `create-docs-artifacts.sh` with new bors --- src/ci/scripts/create-doc-artifacts.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ci/scripts/create-doc-artifacts.sh b/src/ci/scripts/create-doc-artifacts.sh index 2516b0d8505..487a9ba428f 100755 --- a/src/ci/scripts/create-doc-artifacts.sh +++ b/src/ci/scripts/create-doc-artifacts.sh @@ -15,7 +15,8 @@ fi branch=$(git branch --show-current || echo) if [ -n "$branch" ]; then - branch="${branch}-" + # Strip automation/bors/ prefix if present + branch="${branch#automation/bors/}-" fi if [ "${GITHUB_EVENT_NAME:=none}" = "pull_request" ]; then -- cgit 1.4.1-3-g733a5 From b331b8b96d86a6433df957a3cc49ed51f3656135 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 28 May 2025 10:29:08 +0000 Subject: Use the informative error as the main const eval error message --- compiler/rustc_const_eval/src/const_eval/error.rs | 20 +- .../src/const_eval/eval_queries.rs | 34 +- compiler/rustc_const_eval/src/errors.rs | 32 - .../clippy/tests/ui/indexing_slicing_index.rs | 2 +- .../clippy/tests/ui/indexing_slicing_index.stderr | 4 +- src/tools/miri/tests/fail/const-ub-checks.rs | 2 +- src/tools/miri/tests/fail/const-ub-checks.stderr | 4 +- src/tools/miri/tests/fail/erroneous_const.rs | 2 +- src/tools/miri/tests/fail/erroneous_const.stderr | 4 +- src/tools/miri/tests/fail/erroneous_const2.rs | 2 +- src/tools/miri/tests/fail/erroneous_const2.stderr | 4 +- tests/rustdoc-ui/const-evalutation-ice.rs | 4 +- tests/rustdoc-ui/const-evalutation-ice.stderr | 4 +- tests/ui/array-slice-vec/array_const_index-0.rs | 3 +- .../ui/array-slice-vec/array_const_index-0.stderr | 4 +- tests/ui/array-slice-vec/array_const_index-1.rs | 3 +- .../ui/array-slice-vec/array_const_index-1.stderr | 4 +- tests/ui/asm/fail-const-eval-issue-121099.stderr | 8 +- .../associated-consts/defaults-not-assumed-fail.rs | 2 +- .../defaults-not-assumed-fail.stderr | 4 +- tests/ui/borrowck/issue-81899.rs | 2 +- tests/ui/borrowck/issue-81899.stderr | 4 +- tests/ui/borrowck/issue-88434-minimal-example.rs | 4 +- .../ui/borrowck/issue-88434-minimal-example.stderr | 4 +- .../issue-88434-removal-index-should-be-less.rs | 4 +- ...issue-88434-removal-index-should-be-less.stderr | 4 +- .../const-errs-dont-conflict-103369.stderr | 8 +- .../defaults/default-param-wf-concrete.next.stderr | 4 +- .../defaults/default-param-wf-concrete.old.stderr | 4 +- .../defaults/default-param-wf-concrete.rs | 2 +- tests/ui/const-generics/defaults/wfness.rs | 2 +- tests/ui/const-generics/defaults/wfness.stderr | 4 +- .../generic_const_exprs/from-sig-fail.rs | 2 +- .../generic_const_exprs/from-sig-fail.stderr | 4 +- .../generic_const_exprs/simple_fail.rs | 4 +- .../generic_const_exprs/simple_fail.stderr | 8 +- tests/ui/const-generics/issues/issue-100313.rs | 2 +- tests/ui/const-generics/issues/issue-100313.stderr | 4 +- .../invalid-patterns.32bit.stderr | 22 +- .../invalid-patterns.64bit.stderr | 22 +- .../min_const_generics/invalid-patterns.rs | 10 +- tests/ui/const-ptr/forbidden_slices.rs | 36 +- tests/ui/const-ptr/forbidden_slices.stderr | 80 +- tests/ui/const-ptr/out_of_bounds_read.rs | 6 +- tests/ui/const-ptr/out_of_bounds_read.stderr | 12 +- tests/ui/consts/assert-type-intrinsics.rs | 6 +- tests/ui/consts/assert-type-intrinsics.stderr | 12 +- tests/ui/consts/assoc_const_generic_impl.rs | 2 +- tests/ui/consts/assoc_const_generic_impl.stderr | 8 +- tests/ui/consts/const-array-oob.rs | 6 +- tests/ui/consts/const-array-oob.stderr | 10 +- tests/ui/consts/const-assert-unchecked-ub.rs | 2 +- tests/ui/consts/const-assert-unchecked-ub.stderr | 4 +- tests/ui/consts/const-compare-bytes-ub.rs | 16 +- tests/ui/consts/const-compare-bytes-ub.stderr | 32 +- tests/ui/consts/const-deref-ptr.rs | 5 +- tests/ui/consts/const-deref-ptr.stderr | 8 +- tests/ui/consts/const-err-early.rs | 10 +- tests/ui/consts/const-err-early.stderr | 20 +- tests/ui/consts/const-err-enum-discriminant.rs | 3 +- tests/ui/consts/const-err-enum-discriminant.stderr | 4 +- tests/ui/consts/const-err-late.rs | 4 +- tests/ui/consts/const-err-late.stderr | 8 +- tests/ui/consts/const-err-multi.rs | 4 +- tests/ui/consts/const-err-multi.stderr | 4 +- tests/ui/consts/const-eval-fail-too-big.rs | 2 +- tests/ui/consts/const-eval-fail-too-big.stderr | 4 +- .../assign-to-static-within-other-static.rs | 2 +- .../assign-to-static-within-other-static.stderr | 4 +- .../const-eval/conditional_array_execution.rs | 2 +- .../const-eval/conditional_array_execution.stderr | 4 +- .../ui/consts/const-eval/const-eval-overflow-2.rs | 2 +- .../consts/const-eval/const-eval-overflow-2.stderr | 4 +- .../ui/consts/const-eval/const-eval-overflow-3.rs | 2 +- .../consts/const-eval/const-eval-overflow-3.stderr | 4 +- .../ui/consts/const-eval/const-eval-overflow-4.rs | 2 +- .../consts/const-eval/const-eval-overflow-4.stderr | 4 +- tests/ui/consts/const-eval/const-eval-overflow2.rs | 16 +- .../consts/const-eval/const-eval-overflow2.stderr | 32 +- .../ui/consts/const-eval/const-eval-overflow2b.rs | 16 +- .../consts/const-eval/const-eval-overflow2b.stderr | 32 +- .../ui/consts/const-eval/const-eval-overflow2c.rs | 16 +- .../consts/const-eval/const-eval-overflow2c.stderr | 32 +- .../ui/consts/const-eval/const-eval-query-stack.rs | 2 +- .../const-eval/const-eval-query-stack.stderr | 4 +- ...st-pointer-values-in-various-types.64bit.stderr | 162 ++-- .../const-pointer-values-in-various-types.rs | 60 +- tests/ui/consts/const-eval/const_fn_ptr_fail2.rs | 8 +- .../ui/consts/const-eval/const_fn_ptr_fail2.stderr | 8 +- .../const_panic-normalize-tabs-115498.rs | 2 +- .../const_panic-normalize-tabs-115498.stderr | 4 +- tests/ui/consts/const-eval/const_panic.rs | 24 +- tests/ui/consts/const-eval/const_panic.stderr | 48 +- tests/ui/consts/const-eval/const_panic_2021.rs | 20 +- tests/ui/consts/const-eval/const_panic_2021.stderr | 40 +- .../consts/const-eval/const_panic_libcore_bin.rs | 6 +- .../const-eval/const_panic_libcore_bin.stderr | 12 +- .../consts/const-eval/const_panic_track_caller.rs | 4 +- .../const-eval/const_panic_track_caller.stderr | 4 +- tests/ui/consts/const-eval/const_raw_ptr_ops2.rs | 6 +- .../ui/consts/const-eval/const_raw_ptr_ops2.stderr | 10 +- .../const-eval/heap/alloc_intrinsic_errors.rs | 2 +- .../const-eval/heap/alloc_intrinsic_errors.stderr | 4 +- .../heap/alloc_intrinsic_uninit.32bit.stderr | 4 +- .../heap/alloc_intrinsic_uninit.64bit.stderr | 4 +- .../const-eval/heap/alloc_intrinsic_uninit.rs | 2 +- .../const-eval/heap/dealloc_intrinsic_dangling.rs | 4 +- .../heap/dealloc_intrinsic_dangling.stderr | 8 +- .../const-eval/heap/dealloc_intrinsic_duplicate.rs | 2 +- .../heap/dealloc_intrinsic_duplicate.stderr | 4 +- .../heap/dealloc_intrinsic_incorrect_layout.rs | 8 +- .../heap/dealloc_intrinsic_incorrect_layout.stderr | 16 +- .../const-eval/index-out-of-bounds-never-type.rs | 2 +- .../index-out-of-bounds-never-type.stderr | 4 +- .../consts/const-eval/index_out_of_bounds.stderr | 4 +- tests/ui/consts/const-eval/issue-43197.rs | 4 +- tests/ui/consts/const-eval/issue-43197.stderr | 8 +- tests/ui/consts/const-eval/issue-44578.rs | 2 +- tests/ui/consts/const-eval/issue-44578.stderr | 4 +- tests/ui/consts/const-eval/issue-49296.rs | 2 +- tests/ui/consts/const-eval/issue-49296.stderr | 4 +- .../consts/const-eval/issue-50814-2.mir-opt.stderr | 4 +- .../consts/const-eval/issue-50814-2.normal.stderr | 4 +- tests/ui/consts/const-eval/issue-50814-2.rs | 2 +- tests/ui/consts/const-eval/issue-50814.rs | 4 +- tests/ui/consts/const-eval/issue-50814.stderr | 8 +- tests/ui/consts/const-eval/issue-85155.rs | 2 +- tests/ui/consts/const-eval/issue-85155.stderr | 4 +- .../issue-91827-extern-types-field-offset.rs | 3 +- .../issue-91827-extern-types-field-offset.stderr | 4 +- .../consts/const-eval/mod-static-with-const-fn.rs | 2 +- .../const-eval/mod-static-with-const-fn.stderr | 4 +- tests/ui/consts/const-eval/nonnull_as_ref_ub.rs | 2 +- .../ui/consts/const-eval/nonnull_as_ref_ub.stderr | 4 +- .../ui/consts/const-eval/panic-assoc-never-type.rs | 2 +- .../const-eval/panic-assoc-never-type.stderr | 4 +- tests/ui/consts/const-eval/panic-never-type.rs | 2 +- tests/ui/consts/const-eval/panic-never-type.stderr | 4 +- tests/ui/consts/const-eval/parse_ints.rs | 4 +- tests/ui/consts/const-eval/parse_ints.stderr | 8 +- .../ui/consts/const-eval/partial_ptr_overwrite.rs | 3 +- .../consts/const-eval/partial_ptr_overwrite.stderr | 4 +- tests/ui/consts/const-eval/raw-bytes.32bit.stderr | 296 +++--- tests/ui/consts/const-eval/raw-bytes.64bit.stderr | 296 +++--- tests/ui/consts/const-eval/raw-bytes.rs | 116 +-- tests/ui/consts/const-eval/raw-pointer-ub.rs | 20 +- tests/ui/consts/const-eval/raw-pointer-ub.stderr | 20 +- .../const-eval/ref_to_int_match.32bit.stderr | 4 +- .../const-eval/ref_to_int_match.64bit.stderr | 4 +- tests/ui/consts/const-eval/ref_to_int_match.rs | 12 +- tests/ui/consts/const-eval/shift_overflow.stderr | 4 +- tests/ui/consts/const-eval/transmute-const.rs | 2 +- tests/ui/consts/const-eval/transmute-const.stderr | 4 +- .../consts/const-eval/transmute-size-mismatch.rs | 8 +- .../const-eval/transmute-size-mismatch.stderr | 8 +- tests/ui/consts/const-eval/ub-enum-overwrite.rs | 3 +- .../ui/consts/const-eval/ub-enum-overwrite.stderr | 4 +- tests/ui/consts/const-eval/ub-enum.rs | 38 +- tests/ui/consts/const-eval/ub-enum.stderr | 76 +- .../const-eval/ub-incorrect-vtable.32bit.stderr | 34 +- .../const-eval/ub-incorrect-vtable.64bit.stderr | 34 +- tests/ui/consts/const-eval/ub-incorrect-vtable.rs | 18 +- tests/ui/consts/const-eval/ub-int-array.rs | 9 +- tests/ui/consts/const-eval/ub-int-array.stderr | 16 +- tests/ui/consts/const-eval/ub-invalid-values.rs | 4 +- .../ui/consts/const-eval/ub-invalid-values.stderr | 4 +- tests/ui/consts/const-eval/ub-nonnull.rs | 17 +- tests/ui/consts/const-eval/ub-nonnull.stderr | 38 +- tests/ui/consts/const-eval/ub-ref-ptr.rs | 34 +- tests/ui/consts/const-eval/ub-ref-ptr.stderr | 92 +- tests/ui/consts/const-eval/ub-uninhabit.rs | 17 +- tests/ui/consts/const-eval/ub-uninhabit.stderr | 24 +- tests/ui/consts/const-eval/ub-upvars.32bit.stderr | 4 +- tests/ui/consts/const-eval/ub-upvars.64bit.stderr | 4 +- tests/ui/consts/const-eval/ub-upvars.rs | 2 +- tests/ui/consts/const-eval/ub-wide-ptr.rs | 75 +- tests/ui/consts/const-eval/ub-wide-ptr.stderr | 164 ++-- .../const-eval/ub-write-through-immutable.rs | 8 +- .../const-eval/ub-write-through-immutable.stderr | 10 +- .../ui/consts/const-eval/union-const-eval-field.rs | 3 +- .../const-eval/union-const-eval-field.stderr | 8 +- tests/ui/consts/const-eval/union-ice.rs | 12 +- tests/ui/consts/const-eval/union-ice.stderr | 16 +- tests/ui/consts/const-eval/union-ub.32bit.stderr | 12 +- tests/ui/consts/const-eval/union-ub.64bit.stderr | 12 +- tests/ui/consts/const-eval/union-ub.rs | 10 +- tests/ui/consts/const-eval/unused-broken-const.rs | 2 +- .../consts/const-eval/unused-broken-const.stderr | 4 +- tests/ui/consts/const-eval/unwind-abort.rs | 2 +- tests/ui/consts/const-eval/unwind-abort.stderr | 4 +- .../consts/const-eval/validate_uninhabited_zsts.rs | 4 +- .../const-eval/validate_uninhabited_zsts.stderr | 8 +- .../const-eval/validation-ice-extern-type-field.rs | 2 +- .../validation-ice-extern-type-field.stderr | 4 +- tests/ui/consts/const-external-macro-const-err.rs | 2 +- .../consts/const-external-macro-const-err.stderr | 4 +- tests/ui/consts/const-int-unchecked.rs | 99 +- tests/ui/consts/const-int-unchecked.stderr | 294 +++--- .../const-len-underflow-separate-spans.next.stderr | 4 +- .../const-len-underflow-separate-spans.old.stderr | 4 +- .../consts/const-len-underflow-separate-spans.rs | 6 +- tests/ui/consts/const-len-underflow-subspans.rs | 3 +- .../ui/consts/const-len-underflow-subspans.stderr | 4 +- tests/ui/consts/const-mut-refs/mut_ref_in_final.rs | 3 +- .../consts/const-mut-refs/mut_ref_in_final.stderr | 18 +- .../mut_ref_in_final_dynamic_check.rs | 13 +- .../mut_ref_in_final_dynamic_check.stderr | 28 +- tests/ui/consts/const-ptr-is-null.rs | 2 +- tests/ui/consts/const-ptr-is-null.stderr | 4 +- .../const-size_of_val-align_of_val-extern-type.rs | 4 +- ...nst-size_of_val-align_of_val-extern-type.stderr | 8 +- tests/ui/consts/const-slice-oob.rs | 5 +- tests/ui/consts/const-slice-oob.stderr | 4 +- tests/ui/consts/const-unwrap.rs | 6 +- tests/ui/consts/const-unwrap.stderr | 10 +- tests/ui/consts/const_refs_to_static_fail.rs | 9 +- tests/ui/consts/const_refs_to_static_fail.stderr | 12 +- .../ui/consts/const_refs_to_static_fail_invalid.rs | 9 +- .../const_refs_to_static_fail_invalid.stderr | 16 +- tests/ui/consts/const_unsafe_unreachable_ub.rs | 4 +- tests/ui/consts/const_unsafe_unreachable_ub.stderr | 4 +- tests/ui/consts/control-flow/assert.rs | 2 +- tests/ui/consts/control-flow/assert.stderr | 4 +- tests/ui/consts/copy-intrinsic.rs | 17 +- tests/ui/consts/copy-intrinsic.stderr | 22 +- tests/ui/consts/dangling-alloc-id-ice.rs | 2 +- tests/ui/consts/dangling-alloc-id-ice.stderr | 4 +- tests/ui/consts/dangling-zst-ice-issue-126393.rs | 2 +- .../ui/consts/dangling-zst-ice-issue-126393.stderr | 4 +- tests/ui/consts/eval-enum.rs | 10 +- tests/ui/consts/eval-enum.stderr | 14 +- tests/ui/consts/extra-const-ub/detect-extra-ub.rs | 24 +- .../detect-extra-ub.with_flag.stderr | 46 +- .../interior-mut-const-via-union.32bit.stderr | 4 +- .../interior-mut-const-via-union.64bit.stderr | 4 +- tests/ui/consts/interior-mut-const-via-union.rs | 4 +- tests/ui/consts/issue-17718-const-bad-values.rs | 3 +- .../ui/consts/issue-17718-const-bad-values.stderr | 4 +- tests/ui/consts/issue-32829.rs | 2 +- tests/ui/consts/issue-32829.stderr | 4 +- tests/ui/consts/issue-63952.32bit.stderr | 4 +- tests/ui/consts/issue-63952.64bit.stderr | 4 +- tests/ui/consts/issue-63952.rs | 2 +- tests/ui/consts/issue-64506.rs | 2 +- tests/ui/consts/issue-64506.stderr | 4 +- tests/ui/consts/issue-66693-panic-in-array-len.rs | 2 +- .../consts/issue-66693-panic-in-array-len.stderr | 4 +- tests/ui/consts/issue-66693.rs | 4 +- tests/ui/consts/issue-66693.stderr | 8 +- tests/ui/consts/issue-76064.rs | 2 +- tests/ui/consts/issue-76064.stderr | 4 +- tests/ui/consts/issue-79690.64bit.stderr | 4 +- tests/ui/consts/issue-79690.rs | 2 +- tests/ui/consts/issue-miri-1910.rs | 2 +- tests/ui/consts/issue-miri-1910.stderr | 4 +- tests/ui/consts/large_const_alloc.rs | 4 +- tests/ui/consts/large_const_alloc.stderr | 8 +- tests/ui/consts/miri_unleashed/abi-mismatch.rs | 4 +- tests/ui/consts/miri_unleashed/abi-mismatch.stderr | 4 +- tests/ui/consts/miri_unleashed/assoc_const.stderr | 4 +- tests/ui/consts/miri_unleashed/assoc_const_2.rs | 2 +- .../ui/consts/miri_unleashed/assoc_const_2.stderr | 4 +- tests/ui/consts/miri_unleashed/box.rs | 3 +- tests/ui/consts/miri_unleashed/box.stderr | 4 +- .../miri_unleashed/const_refers_to_static.rs | 9 +- .../miri_unleashed/const_refers_to_static.stderr | 16 +- .../const_refers_to_static_cross_crate.rs | 16 +- .../const_refers_to_static_cross_crate.stderr | 24 +- tests/ui/consts/miri_unleashed/drop.rs | 4 +- tests/ui/consts/miri_unleashed/drop.stderr | 4 +- tests/ui/consts/miri_unleashed/extern-static.rs | 6 +- .../ui/consts/miri_unleashed/extern-static.stderr | 10 +- tests/ui/consts/miri_unleashed/inline_asm.rs | 3 +- tests/ui/consts/miri_unleashed/inline_asm.stderr | 4 +- .../ui/consts/miri_unleashed/mutable_references.rs | 30 +- .../miri_unleashed/mutable_references.stderr | 98 +- tests/ui/consts/miri_unleashed/mutating_global.rs | 3 +- .../consts/miri_unleashed/mutating_global.stderr | 4 +- tests/ui/consts/miri_unleashed/non_const_fn.rs | 3 +- tests/ui/consts/miri_unleashed/non_const_fn.stderr | 4 +- tests/ui/consts/miri_unleashed/ptr_arith.rs | 6 +- tests/ui/consts/miri_unleashed/ptr_arith.stderr | 10 +- .../static-no-inner-mut.32bit.stderr | 16 +- .../static-no-inner-mut.64bit.stderr | 16 +- .../consts/miri_unleashed/static-no-inner-mut.rs | 8 +- tests/ui/consts/miri_unleashed/tls.rs | 6 +- tests/ui/consts/miri_unleashed/tls.stderr | 12 +- tests/ui/consts/missing_span_in_backtrace.rs | 2 +- tests/ui/consts/missing_span_in_backtrace.stderr | 8 +- tests/ui/consts/mono-reachable-invalid-const.rs | 3 +- .../ui/consts/mono-reachable-invalid-const.stderr | 6 +- .../no-ice-from-static-in-const-issue-52060.rs | 3 +- .../no-ice-from-static-in-const-issue-52060.stderr | 4 +- tests/ui/consts/offset_from_ub.rs | 53 +- tests/ui/consts/offset_from_ub.stderr | 82 +- tests/ui/consts/offset_ub.stderr | 44 +- tests/ui/consts/overflowing-consts.noopt.stderr | 1024 ++++++++++---------- tests/ui/consts/overflowing-consts.opt.stderr | 1024 ++++++++++---------- ...rflowing-consts.opt_with_overflow_checks.stderr | 1024 ++++++++++---------- tests/ui/consts/overflowing-consts.rs | 348 ++++--- .../promoted_running_out_of_memory_issue-130687.rs | 3 +- ...moted_running_out_of_memory_issue-130687.stderr | 4 +- tests/ui/consts/promoted_size_overflow.rs | 3 +- tests/ui/consts/promoted_size_overflow.stderr | 4 +- tests/ui/consts/qualif-indirect-mutation-fail.rs | 4 +- .../ui/consts/qualif-indirect-mutation-fail.stderr | 8 +- .../ui/consts/recursive-zst-static.default.stderr | 4 +- tests/ui/consts/recursive-zst-static.rs | 2 +- .../ui/consts/recursive-zst-static.unleash.stderr | 4 +- tests/ui/consts/recursive.rs | 2 +- tests/ui/consts/recursive.stderr | 4 +- .../collect-in-called-fn.noopt.stderr | 4 +- .../collect-in-called-fn.opt.stderr | 4 +- .../consts/required-consts/collect-in-called-fn.rs | 2 +- .../collect-in-dead-closure.noopt.stderr | 4 +- .../collect-in-dead-closure.opt.stderr | 4 +- .../required-consts/collect-in-dead-closure.rs | 2 +- .../collect-in-dead-drop.noopt.stderr | 4 +- .../collect-in-dead-drop.opt.stderr | 4 +- .../consts/required-consts/collect-in-dead-drop.rs | 2 +- ...llect-in-dead-fn-behind-assoc-type.noopt.stderr | 4 +- ...collect-in-dead-fn-behind-assoc-type.opt.stderr | 4 +- .../collect-in-dead-fn-behind-assoc-type.rs | 2 +- .../collect-in-dead-fn-behind-generic.noopt.stderr | 4 +- .../collect-in-dead-fn-behind-generic.opt.stderr | 4 +- .../collect-in-dead-fn-behind-generic.rs | 2 +- ...lect-in-dead-fn-behind-opaque-type.noopt.stderr | 4 +- ...ollect-in-dead-fn-behind-opaque-type.opt.stderr | 4 +- .../collect-in-dead-fn-behind-opaque-type.rs | 2 +- .../collect-in-dead-fn.noopt.stderr | 4 +- .../required-consts/collect-in-dead-fn.opt.stderr | 4 +- .../consts/required-consts/collect-in-dead-fn.rs | 2 +- .../collect-in-dead-fnptr-in-const.noopt.stderr | 4 +- .../collect-in-dead-fnptr-in-const.opt.stderr | 4 +- .../collect-in-dead-fnptr-in-const.rs | 2 +- .../collect-in-dead-fnptr.noopt.stderr | 4 +- .../collect-in-dead-fnptr.opt.stderr | 4 +- .../required-consts/collect-in-dead-fnptr.rs | 2 +- .../collect-in-dead-move.noopt.stderr | 4 +- .../collect-in-dead-move.opt.stderr | 4 +- .../consts/required-consts/collect-in-dead-move.rs | 2 +- .../collect-in-dead-vtable.noopt.stderr | 4 +- .../collect-in-dead-vtable.opt.stderr | 4 +- .../required-consts/collect-in-dead-vtable.rs | 2 +- .../collect-in-promoted-const.noopt.stderr | 4 +- .../collect-in-promoted-const.opt.stderr | 8 +- .../required-consts/collect-in-promoted-const.rs | 4 +- .../interpret-in-const-called-fn.noopt.stderr | 4 +- .../interpret-in-const-called-fn.opt.stderr | 4 +- .../interpret-in-const-called-fn.rs | 2 +- .../interpret-in-promoted.noopt.stderr | 4 +- .../interpret-in-promoted.opt.stderr | 4 +- .../required-consts/interpret-in-promoted.rs | 2 +- .../interpret-in-static.noopt.stderr | 4 +- .../required-consts/interpret-in-static.opt.stderr | 4 +- .../consts/required-consts/interpret-in-static.rs | 2 +- .../ui/consts/slice-index-overflow-issue-130284.rs | 3 +- .../slice-index-overflow-issue-130284.stderr | 4 +- tests/ui/consts/static_mut_containing_mut_ref2.rs | 2 +- .../consts/static_mut_containing_mut_ref2.stderr | 4 +- tests/ui/consts/static_mut_containing_mut_ref3.rs | 2 +- .../consts/static_mut_containing_mut_ref3.stderr | 4 +- tests/ui/consts/uninhabited-const-issue-61744.rs | 2 +- .../ui/consts/uninhabited-const-issue-61744.stderr | 4 +- tests/ui/consts/validate_never_arrays.rs | 6 +- tests/ui/consts/validate_never_arrays.stderr | 12 +- tests/ui/consts/write-to-static-mut-in-static.rs | 4 +- .../ui/consts/write-to-static-mut-in-static.stderr | 8 +- tests/ui/enum-discriminant/eval-error.rs | 2 +- tests/ui/enum-discriminant/eval-error.stderr | 4 +- tests/ui/error-codes/E0080.rs | 9 +- tests/ui/error-codes/E0080.stderr | 12 +- .../ctfe-id-unlimited.return.stderr | 4 +- tests/ui/explicit-tail-calls/ctfe-id-unlimited.rs | 2 +- .../ui/explicit-tail-calls/ctfe-tail-call-panic.rs | 4 +- .../ctfe-tail-call-panic.stderr | 4 +- tests/ui/extern/issue-28324.rs | 2 +- tests/ui/extern/issue-28324.stderr | 4 +- .../generic-const-items/def-site-eval.fail.stderr | 4 +- tests/ui/generic-const-items/def-site-eval.rs | 2 +- .../trivially-unsatisfied-bounds-0.rs | 2 +- .../trivially-unsatisfied-bounds-0.stderr | 4 +- .../trivially-unsatisfied-bounds-1.rs | 2 +- .../trivially-unsatisfied-bounds-1.stderr | 4 +- .../unsatisfied-evaluatable-bounds.rs | 2 +- .../unsatisfied-evaluatable-bounds.stderr | 4 +- .../post_monomorphization_error_backtrace.rs | 9 +- .../post_monomorphization_error_backtrace.stderr | 8 +- tests/ui/infinite/infinite-recursion-const-fn.rs | 2 +- .../ui/infinite/infinite-recursion-const-fn.stderr | 4 +- .../ui/inline-const/const-expr-generic-err.stderr | 8 +- tests/ui/inline-const/required-const.stderr | 4 +- tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs | 9 +- .../intrinsics/intrinsic-raw_eq-const-bad.stderr | 16 +- tests/ui/issues/issue-76191.rs | 2 +- tests/ui/issues/issue-76191.stderr | 4 +- tests/ui/layout/invalid-unsized-const-eval.rs | 2 +- tests/ui/layout/invalid-unsized-const-eval.stderr | 4 +- .../layout/invalid-unsized-in-always-sized-tail.rs | 3 +- .../invalid-unsized-in-always-sized-tail.stderr | 4 +- .../issue-unsized-tail-restatic-ice-122488.rs | 2 +- .../issue-unsized-tail-restatic-ice-122488.stderr | 4 +- ...ncomputable-due-to-trivial-bounds-ice-135138.rs | 2 +- ...putable-due-to-trivial-bounds-ice-135138.stderr | 4 +- tests/ui/layout/unknown-when-no-type-parameter.rs | 10 +- .../layout/unknown-when-no-type-parameter.stderr | 6 +- .../ui/layout/unknown-when-ptr-metadata-is-DST.rs | 2 +- .../layout/unknown-when-ptr-metadata-is-DST.stderr | 4 +- .../lazy-type-alias/def-site-param-defaults-wf.rs | 4 +- .../def-site-param-defaults-wf.stderr | 10 +- tests/ui/limits/huge-static.rs | 11 +- tests/ui/limits/huge-static.stderr | 12 +- tests/ui/limits/issue-55878.rs | 2 +- tests/ui/limits/issue-55878.stderr | 4 +- tests/ui/recursion/recursive-static-definition.rs | 4 +- .../recursion/recursive-static-definition.stderr | 8 +- tests/ui/simd/const-err-trumps-simd-err.rs | 3 +- tests/ui/simd/const-err-trumps-simd-err.stderr | 6 +- .../stack-overflow-trait-infer-98842.32bit.stderr | 4 +- .../stack-overflow-trait-infer-98842.64bit.stderr | 4 +- tests/ui/sized/stack-overflow-trait-infer-98842.rs | 2 +- tests/ui/statics/issue-14227.rs | 2 +- tests/ui/statics/issue-14227.stderr | 4 +- tests/ui/statics/mutable_memory_validation.rs | 2 +- tests/ui/statics/mutable_memory_validation.stderr | 4 +- tests/ui/statics/uninhabited-static.rs | 4 +- tests/ui/statics/uninhabited-static.stderr | 8 +- .../structs/default-field-values/invalid-const.rs | 4 +- .../default-field-values/invalid-const.stderr | 8 +- .../default-field-values/post-mono.direct.stderr | 4 +- .../default-field-values/post-mono.indirect.stderr | 4 +- tests/ui/structs/default-field-values/post-mono.rs | 2 +- tests/ui/transmutability/uninhabited.rs | 6 +- tests/ui/transmutability/uninhabited.stderr | 12 +- tests/ui/treat-err-as-bug/err.rs | 2 +- tests/ui/treat-err-as-bug/err.stderr | 4 +- tests/ui/type/pattern_types/literals.rs | 10 +- tests/ui/type/pattern_types/literals.stderr | 20 +- tests/ui/type/pattern_types/range_patterns.rs | 2 +- tests/ui/type/pattern_types/range_patterns.stderr | 4 +- tests/ui/type/pattern_types/reverse_range.rs | 3 +- tests/ui/type/pattern_types/reverse_range.stderr | 4 +- tests/ui/type/pattern_types/validity.rs | 16 +- tests/ui/type/pattern_types/validity.stderr | 32 +- 444 files changed, 4129 insertions(+), 4296 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index ffb32fa41eb..08fc03d9c46 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -1,6 +1,6 @@ use std::mem; -use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagArg}; +use rustc_errors::{Diag, DiagArgName, DiagArgValue, DiagMessage, IntoDiagArg}; use rustc_middle::mir::AssertKind; use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; @@ -131,10 +131,10 @@ pub fn get_span_and_frames<'tcx>( /// Create a diagnostic for a const eval error. /// -/// This will use the `mk` function for creating the error which will get passed labels according to -/// the `InterpError` and the span and a stacktrace of current execution according to -/// `get_span_and_frames`. -pub(super) fn report<'tcx, C, F, E>( +/// This will use the `mk` function for adding more information to the error. +/// You can use it to add a stacktrace of current execution according to +/// `get_span_and_frames` or just give context on where the const eval error happened. +pub(super) fn report<'tcx, C, F>( tcx: TyCtxt<'tcx>, error: InterpErrorKind<'tcx>, span: Span, @@ -143,8 +143,7 @@ pub(super) fn report<'tcx, C, F, E>( ) -> ErrorHandled where C: FnOnce() -> (Span, Vec), - F: FnOnce(Span, Vec) -> E, - E: Diagnostic<'tcx>, + F: FnOnce(&mut Diag<'_>, Span, Vec), { // Special handling for certain errors match error { @@ -163,8 +162,7 @@ where _ => { let (our_span, frames) = get_span_and_frames(); let span = span.substitute_dummy(our_span); - let err = mk(span, frames); - let mut err = tcx.dcx().create_err(err); + let mut err = tcx.dcx().struct_span_err(our_span, error.diagnostic_message()); // We allow invalid programs in infallible promoteds since invalid layouts can occur // anyway (e.g. due to size overflow). And we allow OOM as that can happen any time. let allowed_in_infallible = matches!( @@ -172,11 +170,9 @@ where InterpErrorKind::ResourceExhaustion(_) | InterpErrorKind::InvalidProgram(_) ); - let msg = error.diagnostic_message(); error.add_args(&mut err); - // Use *our* span to label the interp error - err.span_label(our_span, msg); + mk(&mut err, span, frames); let g = err.emit(); let reported = if allowed_in_infallible { ReportedErrorInfo::allowed_in_infallible(g) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index a79ba6a6342..01625b91353 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -2,6 +2,7 @@ use std::sync::atomic::Ordering::Relaxed; use either::{Left, Right}; use rustc_abi::{self as abi, BackendRepr}; +use rustc_errors::E0080; use rustc_hir::def::DefKind; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo}; use rustc_middle::mir::{self, ConstAlloc, ConstValue}; @@ -290,12 +291,18 @@ pub fn eval_to_const_value_raw_provider<'tcx>( |error| { let span = tcx.def_span(def_id); + // FIXME(oli-obk): why don't we have any tests for this code path? super::report( tcx, error.into_kind(), span, || (span, vec![]), - |span, _| errors::NullaryIntrinsicError { span }, + |diag, span, _| { + diag.span_label( + span, + crate::fluent_generated::const_eval_nullary_intrinsic_fail, + ); + }, ) }, ); @@ -443,11 +450,15 @@ fn report_eval_error<'tcx>( error, DUMMY_SP, || super::get_span_and_frames(ecx.tcx, ecx.stack()), - |span, frames| errors::ConstEvalError { - span, - error_kind: kind, - instance, - frame_notes: frames, + |diag, span, frames| { + // FIXME(oli-obk): figure out how to use structured diagnostics again. + diag.code(E0080); + diag.span_label(span, crate::fluent_generated::const_eval_error); + diag.arg("instance", instance); + diag.arg("error_kind", kind); + for frame in frames { + diag.subdiagnostic(frame); + } }, ) } @@ -477,6 +488,15 @@ fn report_validation_error<'tcx>( error, DUMMY_SP, || crate::const_eval::get_span_and_frames(ecx.tcx, ecx.stack()), - move |span, frames| errors::ValidationFailure { span, ub_note: (), frames, raw_bytes }, + move |diag, span, frames| { + // FIXME(oli-obk): figure out how to use structured diagnostics again. + diag.code(E0080); + diag.span_label(span, crate::fluent_generated::const_eval_validation_failure); + diag.note(crate::fluent_generated::const_eval_validation_failure_note); + for frame in frames { + diag.subdiagnostic(frame); + } + diag.subdiagnostic(raw_bytes); + }, ) } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 7c35e47bbf8..037cbf777e7 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -439,38 +439,6 @@ pub struct LiveDrop<'tcx> { pub dropped_at: Span, } -#[derive(Diagnostic)] -#[diag(const_eval_error, code = E0080)] -pub struct ConstEvalError { - #[primary_span] - pub span: Span, - /// One of "const", "const_with_path", and "static" - pub error_kind: &'static str, - pub instance: String, - #[subdiagnostic] - pub frame_notes: Vec, -} - -#[derive(Diagnostic)] -#[diag(const_eval_nullary_intrinsic_fail)] -pub struct NullaryIntrinsicError { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(const_eval_validation_failure, code = E0080)] -pub struct ValidationFailure { - #[primary_span] - pub span: Span, - #[note(const_eval_validation_failure_note)] - pub ub_note: (), - #[subdiagnostic] - pub frames: Vec, - #[subdiagnostic] - pub raw_bytes: RawBytesNote, -} - pub trait ReportErrorExt { /// Returns the diagnostic message for this error. fn diagnostic_message(&self) -> DiagMessage; diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.rs b/src/tools/clippy/tests/ui/indexing_slicing_index.rs index cfa1c2f7c75..ab6a8235008 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.rs +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.rs @@ -68,7 +68,7 @@ fn main() { // This should be linted, since `suppress-restriction-lint-in-const` default is false. const { &ARR[idx4()] }; //~^ ERROR: indexing may panic - //~| ERROR: evaluation of `main + //~| ERROR: index out of bounds let y = &x; // Ok, referencing shouldn't affect this lint. See the issue 6021 diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr index 50ee9b9edc7..453da135fff 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr @@ -9,11 +9,11 @@ LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-re = note: `-D clippy::indexing-slicing` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` -error[E0080]: evaluation of `main::{constant#3}` failed +error[E0080]: index out of bounds: the length is 2 but the index is 4 --> tests/ui/indexing_slicing_index.rs:69:14 | LL | const { &ARR[idx4()] }; - | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 + | ^^^^^^^^^^^ evaluation of `main::{constant#3}` failed note: erroneous constant encountered --> tests/ui/indexing_slicing_index.rs:69:5 diff --git a/src/tools/miri/tests/fail/const-ub-checks.rs b/src/tools/miri/tests/fail/const-ub-checks.rs index 9cc8b91ff50..004bbe9f5ea 100644 --- a/src/tools/miri/tests/fail/const-ub-checks.rs +++ b/src/tools/miri/tests/fail/const-ub-checks.rs @@ -1,7 +1,7 @@ const UNALIGNED_READ: () = unsafe { let x = &[0u8; 4]; let ptr = x.as_ptr().cast::(); - ptr.read(); //~ERROR: evaluation of constant value failed + ptr.read(); //~ERROR: accessing memory based on pointer with alignment 1, but alignment 4 is required }; fn main() { diff --git a/src/tools/miri/tests/fail/const-ub-checks.stderr b/src/tools/miri/tests/fail/const-ub-checks.stderr index e6b302dd28c..f2666f674dc 100644 --- a/src/tools/miri/tests/fail/const-ub-checks.stderr +++ b/src/tools/miri/tests/fail/const-ub-checks.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> tests/fail/const-ub-checks.rs:LL:CC | LL | ptr.read(); - | ^^^^^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required + | ^^^^^^^^^^ evaluation of constant value failed note: erroneous constant encountered --> tests/fail/const-ub-checks.rs:LL:CC diff --git a/src/tools/miri/tests/fail/erroneous_const.rs b/src/tools/miri/tests/fail/erroneous_const.rs index 65f7aafc3cc..6e126ed701f 100644 --- a/src/tools/miri/tests/fail/erroneous_const.rs +++ b/src/tools/miri/tests/fail/erroneous_const.rs @@ -4,7 +4,7 @@ struct PrintName(T); impl PrintName { - const VOID: ! = panic!(); //~ERROR: evaluation of `PrintName::::VOID` failed + const VOID: ! = panic!(); //~ERROR: explicit panic } fn no_codegen() { diff --git a/src/tools/miri/tests/fail/erroneous_const.stderr b/src/tools/miri/tests/fail/erroneous_const.stderr index 6f1e3529ccc..78ac49830c3 100644 --- a/src/tools/miri/tests/fail/erroneous_const.stderr +++ b/src/tools/miri/tests/fail/erroneous_const.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `PrintName::::VOID` failed +error[E0080]: evaluation panicked: explicit panic --> tests/fail/erroneous_const.rs:LL:CC | LL | const VOID: ! = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `PrintName::::VOID` failed note: erroneous constant encountered --> tests/fail/erroneous_const.rs:LL:CC diff --git a/src/tools/miri/tests/fail/erroneous_const2.rs b/src/tools/miri/tests/fail/erroneous_const2.rs index 9a1a970778f..ea98b64ad81 100644 --- a/src/tools/miri/tests/fail/erroneous_const2.rs +++ b/src/tools/miri/tests/fail/erroneous_const2.rs @@ -1,7 +1,7 @@ const X: u32 = 5; const Y: u32 = 6; const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; -//~^ERROR: evaluation of constant value failed +//~^ERROR: overflow #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 fn main() { diff --git a/src/tools/miri/tests/fail/erroneous_const2.stderr b/src/tools/miri/tests/fail/erroneous_const2.stderr index 76f8cbcd289..5d529e57197 100644 --- a/src/tools/miri/tests/fail/erroneous_const2.stderr +++ b/src/tools/miri/tests/fail/erroneous_const2.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `5_u32 - 6_u32`, which would overflow --> tests/fail/erroneous_const2.rs:LL:CC | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ^^^^^ attempt to compute `5_u32 - 6_u32`, which would overflow + | ^^^^^ evaluation of constant value failed note: erroneous constant encountered --> tests/fail/erroneous_const2.rs:LL:CC diff --git a/tests/rustdoc-ui/const-evalutation-ice.rs b/tests/rustdoc-ui/const-evalutation-ice.rs index 0dd3bcaa289..72bcbeb4c51 100644 --- a/tests/rustdoc-ui/const-evalutation-ice.rs +++ b/tests/rustdoc-ui/const-evalutation-ice.rs @@ -4,8 +4,8 @@ use std::cell::Cell; use std::mem; pub struct S { - s: Cell + s: Cell, } pub const N: usize = 0 - (mem::size_of::() != 400) as usize; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflow diff --git a/tests/rustdoc-ui/const-evalutation-ice.stderr b/tests/rustdoc-ui/const-evalutation-ice.stderr index e1cb3323856..7fb78b6a028 100644 --- a/tests/rustdoc-ui/const-evalutation-ice.stderr +++ b/tests/rustdoc-ui/const-evalutation-ice.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/const-evalutation-ice.rs:10:22 | LL | pub const N: usize = 0 - (mem::size_of::() != 400) as usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/array-slice-vec/array_const_index-0.rs b/tests/ui/array-slice-vec/array_const_index-0.rs index f4fe89a50c2..aef07d952fa 100644 --- a/tests/ui/array-slice-vec/array_const_index-0.rs +++ b/tests/ui/array-slice-vec/array_const_index-0.rs @@ -1,7 +1,6 @@ const A: &'static [i32] = &[]; const B: i32 = (&A)[1]; -//~^ NOTE index out of bounds: the length is 0 but the index is 1 -//~| ERROR evaluation of constant value failed +//~^ ERROR index out of bounds: the length is 0 but the index is 1 fn main() { let _ = B; diff --git a/tests/ui/array-slice-vec/array_const_index-0.stderr b/tests/ui/array-slice-vec/array_const_index-0.stderr index d16e8d50dfd..ed9d9917ebf 100644 --- a/tests/ui/array-slice-vec/array_const_index-0.stderr +++ b/tests/ui/array-slice-vec/array_const_index-0.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: index out of bounds: the length is 0 but the index is 1 --> $DIR/array_const_index-0.rs:2:16 | LL | const B: i32 = (&A)[1]; - | ^^^^^^^ index out of bounds: the length is 0 but the index is 1 + | ^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/array-slice-vec/array_const_index-1.rs b/tests/ui/array-slice-vec/array_const_index-1.rs index 0d4de137a6e..4adbd157ed0 100644 --- a/tests/ui/array-slice-vec/array_const_index-1.rs +++ b/tests/ui/array-slice-vec/array_const_index-1.rs @@ -1,7 +1,6 @@ const A: [i32; 0] = []; const B: i32 = A[1]; -//~^ NOTE index out of bounds: the length is 0 but the index is 1 -//~| ERROR evaluation of constant value failed +//~^ ERROR index out of bounds: the length is 0 but the index is 1 fn main() { let _ = B; diff --git a/tests/ui/array-slice-vec/array_const_index-1.stderr b/tests/ui/array-slice-vec/array_const_index-1.stderr index f9ba2f13911..d3db75bd061 100644 --- a/tests/ui/array-slice-vec/array_const_index-1.stderr +++ b/tests/ui/array-slice-vec/array_const_index-1.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: index out of bounds: the length is 0 but the index is 1 --> $DIR/array_const_index-1.rs:2:16 | LL | const B: i32 = A[1]; - | ^^^^ index out of bounds: the length is 0 but the index is 1 + | ^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/asm/fail-const-eval-issue-121099.stderr b/tests/ui/asm/fail-const-eval-issue-121099.stderr index eb662dadffb..995f33d06af 100644 --- a/tests/ui/asm/fail-const-eval-issue-121099.stderr +++ b/tests/ui/asm/fail-const-eval-issue-121099.stderr @@ -1,14 +1,14 @@ -error[E0080]: evaluation of `{global_asm#0}::{constant#0}` failed +error[E0080]: attempt to shift left by `500_i32`, which would overflow --> $DIR/fail-const-eval-issue-121099.rs:8:31 | LL | global_asm!("/* {} */", const 1 << 500); - | ^^^^^^^^ attempt to shift left by `500_i32`, which would overflow + | ^^^^^^^^ evaluation of `{global_asm#0}::{constant#0}` failed -error[E0080]: evaluation of `{global_asm#1}::{constant#0}` failed +error[E0080]: attempt to divide `1_i32` by zero --> $DIR/fail-const-eval-issue-121099.rs:10:31 | LL | global_asm!("/* {} */", const 1 / 0); - | ^^^^^ attempt to divide `1_i32` by zero + | ^^^^^ evaluation of `{global_asm#1}::{constant#0}` failed error: aborting due to 2 previous errors diff --git a/tests/ui/associated-consts/defaults-not-assumed-fail.rs b/tests/ui/associated-consts/defaults-not-assumed-fail.rs index 830fd4ab0e9..e63424e13e3 100644 --- a/tests/ui/associated-consts/defaults-not-assumed-fail.rs +++ b/tests/ui/associated-consts/defaults-not-assumed-fail.rs @@ -7,7 +7,7 @@ trait Tr { // This should not be a constant evaluation error (overflow). The value of // `Self::A` must not be assumed to hold inside the trait. const B: u8 = Self::A + 1; - //~^ ERROR evaluation of `<() as Tr>::B` failed + //~^ ERROR overflow } // An impl that doesn't override any constant will NOT cause a const eval error diff --git a/tests/ui/associated-consts/defaults-not-assumed-fail.stderr b/tests/ui/associated-consts/defaults-not-assumed-fail.stderr index 3386e81dc98..334ab19ada8 100644 --- a/tests/ui/associated-consts/defaults-not-assumed-fail.stderr +++ b/tests/ui/associated-consts/defaults-not-assumed-fail.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `<() as Tr>::B` failed +error[E0080]: attempt to compute `u8::MAX + 1_u8`, which would overflow --> $DIR/defaults-not-assumed-fail.rs:9:19 | LL | const B: u8 = Self::A + 1; - | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow + | ^^^^^^^^^^^ evaluation of `<() as Tr>::B` failed note: erroneous constant encountered --> $DIR/defaults-not-assumed-fail.rs:34:16 diff --git a/tests/ui/borrowck/issue-81899.rs b/tests/ui/borrowck/issue-81899.rs index 11755620d86..03d9b8cb6c6 100644 --- a/tests/ui/borrowck/issue-81899.rs +++ b/tests/ui/borrowck/issue-81899.rs @@ -3,7 +3,7 @@ //@ dont-require-annotations: NOTE -const _CONST: &[u8] = &f(&[], |_| {}); //~ ERROR evaluation of constant value failed +const _CONST: &[u8] = &f(&[], |_| {}); //~ ERROR explicit panic //~^ NOTE constant const fn f(_: &[u8], _: F) -> &[u8] diff --git a/tests/ui/borrowck/issue-81899.stderr b/tests/ui/borrowck/issue-81899.stderr index 97d463cb6a7..dcadeef4722 100644 --- a/tests/ui/borrowck/issue-81899.stderr +++ b/tests/ui/borrowck/issue-81899.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-81899.rs:6:24 | LL | const _CONST: &[u8] = &f(&[], |_| {}); - | ^^^^^^^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `f::<{closure@$DIR/issue-81899.rs:6:31: 6:34}>` --> $DIR/issue-81899.rs:13:5 diff --git a/tests/ui/borrowck/issue-88434-minimal-example.rs b/tests/ui/borrowck/issue-88434-minimal-example.rs index 7482b3fd612..901e0142c36 100644 --- a/tests/ui/borrowck/issue-88434-minimal-example.rs +++ b/tests/ui/borrowck/issue-88434-minimal-example.rs @@ -2,7 +2,7 @@ //@ dont-require-annotations: NOTE -const _CONST: &() = &f(&|_| {}); //~ ERROR evaluation of constant value failed +const _CONST: &() = &f(&|_| {}); //~ ERROR explicit panic //~^ NOTE constant const fn f(_: &F) @@ -12,4 +12,4 @@ where panic!() //~ NOTE inside `f } -fn main() { } +fn main() {} diff --git a/tests/ui/borrowck/issue-88434-minimal-example.stderr b/tests/ui/borrowck/issue-88434-minimal-example.stderr index 4c525b9ea2c..ec32b901e21 100644 --- a/tests/ui/borrowck/issue-88434-minimal-example.stderr +++ b/tests/ui/borrowck/issue-88434-minimal-example.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-88434-minimal-example.rs:5:22 | LL | const _CONST: &() = &f(&|_| {}); - | ^^^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^^^ evaluation of constant value failed | note: inside `f::<{closure@$DIR/issue-88434-minimal-example.rs:5:25: 5:28}>` --> $DIR/issue-88434-minimal-example.rs:12:5 diff --git a/tests/ui/borrowck/issue-88434-removal-index-should-be-less.rs b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.rs index 09b1f59c449..cce59124ade 100644 --- a/tests/ui/borrowck/issue-88434-removal-index-should-be-less.rs +++ b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.rs @@ -2,7 +2,7 @@ //@ dont-require-annotations: NOTE -const _CONST: &[u8] = &f(&[], |_| {}); //~ ERROR evaluation of constant value failed +const _CONST: &[u8] = &f(&[], |_| {}); //~ ERROR explicit panic //~^ NOTE constant const fn f(_: &[u8], _: F) -> &[u8] @@ -12,4 +12,4 @@ where panic!() //~ NOTE inside `f } -fn main() { } +fn main() {} diff --git a/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr index a22621c9c1b..8be693b84fe 100644 --- a/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr +++ b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-88434-removal-index-should-be-less.rs:5:24 | LL | const _CONST: &[u8] = &f(&[], |_| {}); - | ^^^^^^^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `f::<{closure@$DIR/issue-88434-removal-index-should-be-less.rs:5:31: 5:34}>` --> $DIR/issue-88434-removal-index-should-be-less.rs:12:5 diff --git a/tests/ui/coherence/const-errs-dont-conflict-103369.stderr b/tests/ui/coherence/const-errs-dont-conflict-103369.stderr index b2104299f65..236a6982b1c 100644 --- a/tests/ui/coherence/const-errs-dont-conflict-103369.stderr +++ b/tests/ui/coherence/const-errs-dont-conflict-103369.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: Some error occurred --> $DIR/const-errs-dont-conflict-103369.rs:5:25 | LL | impl ConstGenericTrait<{my_fn(1)}> for () {} - | ^^^^^^^^ evaluation panicked: Some error occurred + | ^^^^^^^^ evaluation of constant value failed | note: inside `my_fn` --> $DIR/const-errs-dont-conflict-103369.rs:10:5 @@ -10,11 +10,11 @@ note: inside `my_fn` LL | panic!("Some error occurred"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the failure occurred here -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: Some error occurred --> $DIR/const-errs-dont-conflict-103369.rs:7:25 | LL | impl ConstGenericTrait<{my_fn(2)}> for () {} - | ^^^^^^^^ evaluation panicked: Some error occurred + | ^^^^^^^^ evaluation of constant value failed | note: inside `my_fn` --> $DIR/const-errs-dont-conflict-103369.rs:10:5 diff --git a/tests/ui/const-generics/defaults/default-param-wf-concrete.next.stderr b/tests/ui/const-generics/defaults/default-param-wf-concrete.next.stderr index 35aae462443..9a4e284875b 100644 --- a/tests/ui/const-generics/defaults/default-param-wf-concrete.next.stderr +++ b/tests/ui/const-generics/defaults/default-param-wf-concrete.next.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `u8::MAX + 1_u8`, which would overflow --> $DIR/default-param-wf-concrete.rs:4:28 | LL | struct Foo; - | ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow + | ^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr b/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr index 35aae462443..9a4e284875b 100644 --- a/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr +++ b/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `u8::MAX + 1_u8`, which would overflow --> $DIR/default-param-wf-concrete.rs:4:28 | LL | struct Foo; - | ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow + | ^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/defaults/default-param-wf-concrete.rs b/tests/ui/const-generics/defaults/default-param-wf-concrete.rs index f181f582332..0385e55e3b2 100644 --- a/tests/ui/const-generics/defaults/default-param-wf-concrete.rs +++ b/tests/ui/const-generics/defaults/default-param-wf-concrete.rs @@ -2,5 +2,5 @@ //@[next] compile-flags: -Znext-solver struct Foo; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflow fn main() {} diff --git a/tests/ui/const-generics/defaults/wfness.rs b/tests/ui/const-generics/defaults/wfness.rs index a93f670815a..99e9452b46a 100644 --- a/tests/ui/const-generics/defaults/wfness.rs +++ b/tests/ui/const-generics/defaults/wfness.rs @@ -1,5 +1,5 @@ struct Ooopsies; -//~^ error: evaluation of constant value failed +//~^ error: overflow trait Trait {} impl Trait<3> for () {} diff --git a/tests/ui/const-generics/defaults/wfness.stderr b/tests/ui/const-generics/defaults/wfness.stderr index 290a80bd32f..f99180fcdae 100644 --- a/tests/ui/const-generics/defaults/wfness.stderr +++ b/tests/ui/const-generics/defaults/wfness.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `u8::MAX + 1_u8`, which would overflow --> $DIR/wfness.rs:1:33 | LL | struct Ooopsies; - | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed error[E0277]: the trait bound `(): Trait<2>` is not satisfied --> $DIR/wfness.rs:8:9 diff --git a/tests/ui/const-generics/generic_const_exprs/from-sig-fail.rs b/tests/ui/const-generics/generic_const_exprs/from-sig-fail.rs index b8f9827ec91..16753749702 100644 --- a/tests/ui/const-generics/generic_const_exprs/from-sig-fail.rs +++ b/tests/ui/const-generics/generic_const_exprs/from-sig-fail.rs @@ -2,7 +2,7 @@ #![allow(incomplete_features)] fn test() -> [u8; N - 1] { - //~^ ERROR evaluation of `test::<0>::{constant#0}` failed + //~^ ERROR overflow todo!() } diff --git a/tests/ui/const-generics/generic_const_exprs/from-sig-fail.stderr b/tests/ui/const-generics/generic_const_exprs/from-sig-fail.stderr index 080e920258d..c993b8c9bd7 100644 --- a/tests/ui/const-generics/generic_const_exprs/from-sig-fail.stderr +++ b/tests/ui/const-generics/generic_const_exprs/from-sig-fail.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `test::<0>::{constant#0}` failed +error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/from-sig-fail.rs:4:35 | LL | fn test() -> [u8; N - 1] { - | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow + | ^^^^^ evaluation of `test::<0>::{constant#0}` failed error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/simple_fail.rs b/tests/ui/const-generics/generic_const_exprs/simple_fail.rs index cae54df4c12..e89b5707fe2 100644 --- a/tests/ui/const-generics/generic_const_exprs/simple_fail.rs +++ b/tests/ui/const-generics/generic_const_exprs/simple_fail.rs @@ -2,12 +2,12 @@ #![allow(incomplete_features)] type Arr = [u8; N - 1]; -//~^ ERROR evaluation of `Arr::<0>::{constant#0}` failed +//~^ ERROR overflow fn test() -> Arr where [u8; N - 1]: Sized, - //~^ ERROR evaluation of `test::<0>::{constant#0}` failed + //~^ ERROR overflow { todo!() } diff --git a/tests/ui/const-generics/generic_const_exprs/simple_fail.stderr b/tests/ui/const-generics/generic_const_exprs/simple_fail.stderr index a25fa56b7d4..1e8343e9471 100644 --- a/tests/ui/const-generics/generic_const_exprs/simple_fail.stderr +++ b/tests/ui/const-generics/generic_const_exprs/simple_fail.stderr @@ -1,14 +1,14 @@ -error[E0080]: evaluation of `test::<0>::{constant#0}` failed +error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/simple_fail.rs:9:10 | LL | [u8; N - 1]: Sized, - | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow + | ^^^^^ evaluation of `test::<0>::{constant#0}` failed -error[E0080]: evaluation of `Arr::<0>::{constant#0}` failed +error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/simple_fail.rs:4:33 | LL | type Arr = [u8; N - 1]; - | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow + | ^^^^^ evaluation of `Arr::<0>::{constant#0}` failed error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/issues/issue-100313.rs b/tests/ui/const-generics/issues/issue-100313.rs index 7d43d7bee34..1f61356162c 100644 --- a/tests/ui/const-generics/issues/issue-100313.rs +++ b/tests/ui/const-generics/issues/issue-100313.rs @@ -15,7 +15,7 @@ impl T { const _: () = { let x = T::<{ &true }>; - x.set_false(); //~ ERROR evaluation of constant value failed [E0080] + x.set_false(); //~ ERROR writing to ALLOC0 which is read-only }; fn main() {} diff --git a/tests/ui/const-generics/issues/issue-100313.stderr b/tests/ui/const-generics/issues/issue-100313.stderr index 98c3ec5379b..08fef3d4d0e 100644 --- a/tests/ui/const-generics/issues/issue-100313.stderr +++ b/tests/ui/const-generics/issues/issue-100313.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: writing to ALLOC0 which is read-only --> $DIR/issue-100313.rs:18:5 | LL | x.set_false(); - | ^^^^^^^^^^^^^ writing to ALLOC0 which is read-only + | ^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `T::<&true>::set_false` --> $DIR/issue-100313.rs:11:13 diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr index d1f3b08dd36..11398a07a45 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr @@ -1,36 +1,36 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/invalid-patterns.rs:40:32 | LL | get_flag::(); - | ^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-patterns.rs:43:14 +error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean + --> $DIR/invalid-patterns.rs:42:14 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x42, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 42 │ B } -error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-patterns.rs:45:14 +error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean + --> $DIR/invalid-patterns.rs:44:14 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x42, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 42 │ B } -error[E0080]: evaluation of constant value failed - --> $DIR/invalid-patterns.rs:45:58 +error[E0080]: using uninitialized data, but this operation requires initialized memory + --> $DIR/invalid-patterns.rs:44:58 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); - | ^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error[E0308]: mismatched types --> $DIR/invalid-patterns.rs:31:21 diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr index d1f3b08dd36..11398a07a45 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr @@ -1,36 +1,36 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/invalid-patterns.rs:40:32 | LL | get_flag::(); - | ^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-patterns.rs:43:14 +error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean + --> $DIR/invalid-patterns.rs:42:14 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x42, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 42 │ B } -error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-patterns.rs:45:14 +error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean + --> $DIR/invalid-patterns.rs:44:14 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x42, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 42 │ B } -error[E0080]: evaluation of constant value failed - --> $DIR/invalid-patterns.rs:45:58 +error[E0080]: using uninitialized data, but this operation requires initialized memory + --> $DIR/invalid-patterns.rs:44:58 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); - | ^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error[E0308]: mismatched types --> $DIR/invalid-patterns.rs:31:21 diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.rs b/tests/ui/const-generics/min_const_generics/invalid-patterns.rs index 10b0d742a0a..85f019adf66 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.rs +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.rs @@ -38,12 +38,10 @@ fn main() { get_flag::(); - //~^ ERROR evaluation of constant value failed - //~| NOTE uninitialized + //~^ ERROR uninitialized get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); - //~^ ERROR it is undefined behavior + //~^ ERROR 0x42, but expected a boolean get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); - //~^ ERROR evaluation of constant value failed - //~| NOTE uninitialized - //~| ERROR it is undefined behavior + //~^ ERROR uninitialized + //~| ERROR 0x42, but expected a boolean } diff --git a/tests/ui/const-ptr/forbidden_slices.rs b/tests/ui/const-ptr/forbidden_slices.rs index 001cfd66ad1..fcb0dccf750 100644 --- a/tests/ui/const-ptr/forbidden_slices.rs +++ b/tests/ui/const-ptr/forbidden_slices.rs @@ -14,24 +14,24 @@ use std::{ // Null is never valid for references pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) }; -//~^ ERROR: it is undefined behavior to use this value +//~^ ERROR: null reference pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; -//~^ ERROR: it is undefined behavior to use this value +//~^ ERROR: null reference // Out of bounds pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; -//~^ ERROR: it is undefined behavior to use this value +//~^ ERROR: dangling reference (going beyond the bounds of its allocation) // Reading uninitialized data -pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; //~ ERROR: it is undefined behavior to use this value +pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; //~ ERROR: uninitialized memory // Reinterpret pointers as integers (UB in CTFE.) -pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) }; //~ ERROR: it is undefined behavior to use this value +pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) }; //~ ERROR: pointer, but expected an integer // Layout mismatch -pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; //~ ERROR: it is undefined behavior to use this value +pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; //~ ERROR: 0x11, but expected a boolean // Reading padding is not ok pub static S7: &[u16] = unsafe { - //~^ ERROR: it is undefined behavior to use this value + //~^ ERROR: uninitialized memory let ptr = (&D2 as *const Struct as *const u16).add(1); from_raw_parts(ptr, 4) @@ -39,53 +39,53 @@ pub static S7: &[u16] = unsafe { // Unaligned read pub static S8: &[u64] = unsafe { - //~^ ERROR: it is undefined behavior to use this value + //~^ ERROR: dangling reference (going beyond the bounds of its allocation) let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::(); from_raw_parts(ptr, 1) }; pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR encountered a null reference pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; // errors inside libcore -//~^ ERROR could not evaluate static initializer +//~^ ERROR 0 < pointee_size && pointee_size <= isize::MAX as usize pub static R2: &[u32] = unsafe { let ptr = &D0 as *const u32; from_ptr_range(ptr..ptr.add(2)) // errors inside libcore - //~^ ERROR could not evaluate static initializer + //~^ ERROR in-bounds pointer arithmetic failed }; pub static R4: &[u8] = unsafe { - //~^ ERROR: it is undefined behavior to use this value + //~^ ERROR: encountered uninitialized memory, but expected an integer let ptr = (&D1) as *const MaybeUninit<&u32> as *const u8; from_ptr_range(ptr..ptr.add(1)) }; pub static R5: &[u8] = unsafe { - //~^ ERROR: it is undefined behavior to use this value + //~^ ERROR: encountered a pointer, but expected an integer let ptr = &D3 as *const &u32; from_ptr_range(ptr.cast()..ptr.add(1).cast()) }; pub static R6: &[bool] = unsafe { - //~^ ERROR: it is undefined behavior to use this value + //~^ ERROR: 0x11, but expected a boolean let ptr = &D0 as *const u32 as *const bool; from_ptr_range(ptr..ptr.add(4)) }; pub static R7: &[u16] = unsafe { - //~^ ERROR: it is undefined behavior to use this value + //~^ ERROR: unaligned reference (required 2 byte alignment but found 1) let ptr = (&D2 as *const Struct as *const u16).byte_add(1); from_ptr_range(ptr..ptr.add(4)) }; pub static R8: &[u64] = unsafe { let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::(); from_ptr_range(ptr..ptr.add(1)) - //~^ ERROR could not evaluate static initializer + //~^ ERROR in-bounds pointer arithmetic failed }; // This is sneaky: &D0 and &D0 point to different objects // (even if at runtime they have the same address) pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) }; -//~^ ERROR could not evaluate static initializer +//~^ ERROR not both derived from the same allocation pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) }; -//~^ ERROR could not evaluate static initializer +//~^ ERROR not both derived from the same allocation const D0: u32 = 0x11111111; // Constant chosen for endianness-independent behavior. const D1: MaybeUninit<&u32> = MaybeUninit::uninit(); diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index e618fbf7e0f..229074053e2 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -1,179 +1,179 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered a null reference --> $DIR/forbidden_slices.rs:16:1 | LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) }; - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered a null reference --> $DIR/forbidden_slices.rs:18:1 | LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/forbidden_slices.rs:22:1 | LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer --> $DIR/forbidden_slices.rs:26:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .[0]: encountered a pointer, but expected an integer --> $DIR/forbidden_slices.rs:28:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .[0]: encountered 0x11, but expected a boolean --> $DIR/forbidden_slices.rs:30:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer --> $DIR/forbidden_slices.rs:33:1 | LL | pub static S7: &[u16] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/forbidden_slices.rs:41:1 | LL | pub static S8: &[u64] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered a null reference --> $DIR/forbidden_slices.rs:48:1 | LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: could not evaluate static initializer +error[E0080]: evaluation panicked: assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize --> $DIR/forbidden_slices.rs:50:33 | LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; // errors inside libcore - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer -error[E0080]: could not evaluate static initializer +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC10 which is only 4 bytes from the end of the allocation --> $DIR/forbidden_slices.rs:54:25 | LL | from_ptr_range(ptr..ptr.add(2)) // errors inside libcore - | ^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC10 which is only 4 bytes from the end of the allocation + | ^^^^^^^^^^ could not evaluate static initializer -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer --> $DIR/forbidden_slices.rs:57:1 | LL | pub static R4: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .[0]: encountered a pointer, but expected an integer --> $DIR/forbidden_slices.rs:62:1 | LL | pub static R5: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .[0]: encountered 0x11, but expected a boolean --> $DIR/forbidden_slices.rs:67:1 | LL | pub static R6: &[bool] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) --> $DIR/forbidden_slices.rs:72:1 | LL | pub static R7: &[u16] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: could not evaluate static initializer +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC11+0x1 which is only 7 bytes from the end of the allocation --> $DIR/forbidden_slices.rs:79:25 | LL | from_ptr_range(ptr..ptr.add(1)) - | ^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC11+0x1 which is only 7 bytes from the end of the allocation + | ^^^^^^^^^^ could not evaluate static initializer -error[E0080]: could not evaluate static initializer +error[E0080]: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation --> $DIR/forbidden_slices.rs:85:34 | LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer -error[E0080]: could not evaluate static initializer +error[E0080]: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation --> $DIR/forbidden_slices.rs:87:35 | LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer error: aborting due to 18 previous errors diff --git a/tests/ui/const-ptr/out_of_bounds_read.rs b/tests/ui/const-ptr/out_of_bounds_read.rs index ccf45bf324a..b09978badde 100644 --- a/tests/ui/const-ptr/out_of_bounds_read.rs +++ b/tests/ui/const-ptr/out_of_bounds_read.rs @@ -6,9 +6,9 @@ fn main() { const PAST_END_PTR: *const u32 = unsafe { DATA.as_ptr().add(1) }; const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR at or beyond the end of the allocation const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR at or beyond the end of the allocation const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR at or beyond the end of the allocation } diff --git a/tests/ui/const-ptr/out_of_bounds_read.stderr b/tests/ui/const-ptr/out_of_bounds_read.stderr index 8f93793802b..b6a74c888e2 100644 --- a/tests/ui/const-ptr/out_of_bounds_read.stderr +++ b/tests/ui/const-ptr/out_of_bounds_read.stderr @@ -1,20 +1,20 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes --> $DIR/out_of_bounds_read.rs:8:33 | LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes --> $DIR/out_of_bounds_read.rs:10:39 | LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; - | ^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes --> $DIR/out_of_bounds_read.rs:12:37 | LL | const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 3 previous errors diff --git a/tests/ui/consts/assert-type-intrinsics.rs b/tests/ui/consts/assert-type-intrinsics.rs index 32b5f5c92c5..91c8dd00e89 100644 --- a/tests/ui/consts/assert-type-intrinsics.rs +++ b/tests/ui/consts/assert-type-intrinsics.rs @@ -9,14 +9,14 @@ fn main() { const _BAD1: () = unsafe { MaybeUninit::::uninit().assume_init(); - //~^ERROR: evaluation of constant value failed + //~^ERROR: uninhabited }; const _BAD2: () = { intrinsics::assert_mem_uninitialized_valid::<&'static i32>(); - //~^ERROR: evaluation of constant value failed + //~^ERROR: uninitialized }; const _BAD3: () = { intrinsics::assert_zero_valid::<&'static i32>(); - //~^ERROR: evaluation of constant value failed + //~^ERROR: zero-initialize type `&i32` }; } diff --git a/tests/ui/consts/assert-type-intrinsics.stderr b/tests/ui/consts/assert-type-intrinsics.stderr index 92c0610a248..1e36eb5c25f 100644 --- a/tests/ui/consts/assert-type-intrinsics.stderr +++ b/tests/ui/consts/assert-type-intrinsics.stderr @@ -1,20 +1,20 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: aborted execution: attempted to instantiate uninhabited type `!` --> $DIR/assert-type-intrinsics.rs:11:9 | LL | MaybeUninit::::uninit().assume_init(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: aborted execution: attempted to instantiate uninhabited type `!` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: aborted execution: attempted to leave type `&i32` uninitialized, which is invalid --> $DIR/assert-type-intrinsics.rs:15:9 | LL | intrinsics::assert_mem_uninitialized_valid::<&'static i32>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: aborted execution: attempted to leave type `&i32` uninitialized, which is invalid + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: aborted execution: attempted to zero-initialize type `&i32`, which is invalid --> $DIR/assert-type-intrinsics.rs:19:9 | LL | intrinsics::assert_zero_valid::<&'static i32>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: aborted execution: attempted to zero-initialize type `&i32`, which is invalid + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 3 previous errors diff --git a/tests/ui/consts/assoc_const_generic_impl.rs b/tests/ui/consts/assoc_const_generic_impl.rs index 5820a724d07..a4904795254 100644 --- a/tests/ui/consts/assoc_const_generic_impl.rs +++ b/tests/ui/consts/assoc_const_generic_impl.rs @@ -6,7 +6,7 @@ trait ZeroSized: Sized { } impl ZeroSized for T { - const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::()]; //~ ERROR evaluation of `::I_AM_ZERO_SIZED` failed + const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::()]; //~ ERROR index out of bounds: the length is 1 but the index is 4 fn requires_zero_size(self) { Self::I_AM_ZERO_SIZED; println!("requires_zero_size called"); diff --git a/tests/ui/consts/assoc_const_generic_impl.stderr b/tests/ui/consts/assoc_const_generic_impl.stderr index 45219508396..e44997b624d 100644 --- a/tests/ui/consts/assoc_const_generic_impl.stderr +++ b/tests/ui/consts/assoc_const_generic_impl.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `::I_AM_ZERO_SIZED` failed - --> $DIR/assoc_const_generic_impl.rs:9:34 +error[E0080]: index out of bounds: the length is 1 but the index is 4 + --> $DIR/assoc_const_generic_impl.rs:9:33 | -LL | const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::()]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 4 +LL | const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::()]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `::I_AM_ZERO_SIZED` failed note: erroneous constant encountered --> $DIR/assoc_const_generic_impl.rs:11:9 diff --git a/tests/ui/consts/const-array-oob.rs b/tests/ui/consts/const-array-oob.rs index 4b457d1c23c..dc713b74d7f 100644 --- a/tests/ui/consts/const-array-oob.rs +++ b/tests/ui/consts/const-array-oob.rs @@ -1,11 +1,9 @@ const FOO: [usize; 3] = [1, 2, 3]; const BAR: usize = FOO[5]; -//~^ ERROR: evaluation of constant value failed -//~| NOTE index out of bounds: the length is 3 but the index is 5 +//~^ ERROR: index out of bounds: the length is 3 but the index is 5 const BLUB: [u32; FOO[4]] = [5, 6]; -//~^ ERROR evaluation of constant value failed [E0080] -//~| NOTE index out of bounds: the length is 3 but the index is 4 +//~^ ERROR index out of bounds: the length is 3 but the index is 4 fn main() { let _ = BAR; diff --git a/tests/ui/consts/const-array-oob.stderr b/tests/ui/consts/const-array-oob.stderr index 89427c051e7..80549d84822 100644 --- a/tests/ui/consts/const-array-oob.stderr +++ b/tests/ui/consts/const-array-oob.stderr @@ -1,14 +1,14 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/const-array-oob.rs:6:19 +error[E0080]: index out of bounds: the length is 3 but the index is 4 + --> $DIR/const-array-oob.rs:5:19 | LL | const BLUB: [u32; FOO[4]] = [5, 6]; - | ^^^^^^ index out of bounds: the length is 3 but the index is 4 + | ^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: index out of bounds: the length is 3 but the index is 5 --> $DIR/const-array-oob.rs:2:20 | LL | const BAR: usize = FOO[5]; - | ^^^^^^ index out of bounds: the length is 3 but the index is 5 + | ^^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-assert-unchecked-ub.rs b/tests/ui/consts/const-assert-unchecked-ub.rs index ffc02eedcb7..a62abcf12d6 100644 --- a/tests/ui/consts/const-assert-unchecked-ub.rs +++ b/tests/ui/consts/const-assert-unchecked-ub.rs @@ -1,6 +1,6 @@ const _: () = unsafe { let n = u32::MAX.count_ones(); - std::hint::assert_unchecked(n < 32); //~ ERROR evaluation of constant value failed + std::hint::assert_unchecked(n < 32); //~ ERROR `assume` called with `false` }; fn main() {} diff --git a/tests/ui/consts/const-assert-unchecked-ub.stderr b/tests/ui/consts/const-assert-unchecked-ub.stderr index 468f15f3472..877eef24d77 100644 --- a/tests/ui/consts/const-assert-unchecked-ub.stderr +++ b/tests/ui/consts/const-assert-unchecked-ub.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: `assume` called with `false` --> $DIR/const-assert-unchecked-ub.rs:3:5 | LL | std::hint::assert_unchecked(n < 32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `assume` called with `false` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-compare-bytes-ub.rs b/tests/ui/consts/const-compare-bytes-ub.rs index 9dafae1efd1..0bc8585a4ee 100644 --- a/tests/ui/consts/const-compare-bytes-ub.rs +++ b/tests/ui/consts/const-compare-bytes-ub.rs @@ -7,34 +7,34 @@ use std::mem::MaybeUninit; fn main() { const LHS_NULL: i32 = unsafe { compare_bytes(0 as *const u8, 2 as *const u8, 1) - //~^ ERROR evaluation of constant value failed + //~^ ERROR memory access failed }; const RHS_NULL: i32 = unsafe { compare_bytes(1 as *const u8, 0 as *const u8, 1) - //~^ ERROR evaluation of constant value failed + //~^ ERROR memory access failed }; const DANGLING_PTR_NON_ZERO_LENGTH: i32 = unsafe { compare_bytes(1 as *const u8, 2 as *const u8, 1) - //~^ ERROR evaluation of constant value failed + //~^ ERROR memory access failed }; const LHS_OUT_OF_BOUNDS: i32 = unsafe { compare_bytes([1, 2, 3].as_ptr(), [1, 2, 3, 4].as_ptr(), 4) - //~^ ERROR evaluation of constant value failed + //~^ ERROR memory access failed }; const RHS_OUT_OF_BOUNDS: i32 = unsafe { compare_bytes([1, 2, 3, 4].as_ptr(), [1, 2, 3].as_ptr(), 4) - //~^ ERROR evaluation of constant value failed + //~^ ERROR memory access failed }; const LHS_UNINIT: i32 = unsafe { compare_bytes(MaybeUninit::uninit().as_ptr(), [1].as_ptr(), 1) - //~^ ERROR evaluation of constant value failed + //~^ ERROR memory is uninitialized }; const RHS_UNINIT: i32 = unsafe { compare_bytes([1].as_ptr(), MaybeUninit::uninit().as_ptr(), 1) - //~^ ERROR evaluation of constant value failed + //~^ ERROR memory is uninitialized }; const WITH_PROVENANCE: i32 = unsafe { compare_bytes([&1].as_ptr().cast(), [&2].as_ptr().cast(), std::mem::size_of::()) - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer }; } diff --git a/tests/ui/consts/const-compare-bytes-ub.stderr b/tests/ui/consts/const-compare-bytes-ub.stderr index 0e77310c6ba..98ed4c96b83 100644 --- a/tests/ui/consts/const-compare-bytes-ub.stderr +++ b/tests/ui/consts/const-compare-bytes-ub.stderr @@ -1,50 +1,50 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: attempting to access 1 byte, but got null pointer --> $DIR/const-compare-bytes-ub.rs:9:9 | LL | compare_bytes(0 as *const u8, 2 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got null pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/const-compare-bytes-ub.rs:13:9 | LL | compare_bytes(1 as *const u8, 0 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/const-compare-bytes-ub.rs:17:9 | LL | compare_bytes(1 as *const u8, 2 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0 which is only 3 bytes from the end of the allocation --> $DIR/const-compare-bytes-ub.rs:21:9 | LL | compare_bytes([1, 2, 3].as_ptr(), [1, 2, 3, 4].as_ptr(), 4) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0 which is only 3 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC1 which is only 3 bytes from the end of the allocation --> $DIR/const-compare-bytes-ub.rs:25:9 | LL | compare_bytes([1, 2, 3, 4].as_ptr(), [1, 2, 3].as_ptr(), 4) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC1 which is only 3 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory --> $DIR/const-compare-bytes-ub.rs:29:9 | LL | compare_bytes(MaybeUninit::uninit().as_ptr(), [1].as_ptr(), 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: reading memory at ALLOC3[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory --> $DIR/const-compare-bytes-ub.rs:33:9 | LL | compare_bytes([1].as_ptr(), MaybeUninit::uninit().as_ptr(), 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC3[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/const-compare-bytes-ub.rs:37:9 | LL | compare_bytes([&1].as_ptr().cast(), [&2].as_ptr().cast(), std::mem::size_of::()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-deref-ptr.rs b/tests/ui/consts/const-deref-ptr.rs index c80cb95ea93..ae928f55ebd 100644 --- a/tests/ui/consts/const-deref-ptr.rs +++ b/tests/ui/consts/const-deref-ptr.rs @@ -1,8 +1,7 @@ // Check that you can't dereference invalid raw pointers in constants. fn main() { - static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; - //~^ ERROR could not evaluate static initializer - //~| NOTE dangling pointer + static C: u64 = unsafe { *(0xdeadbeef as *const u64) }; + //~^ ERROR dangling pointer println!("{}", C); } diff --git a/tests/ui/consts/const-deref-ptr.stderr b/tests/ui/consts/const-deref-ptr.stderr index 37502864947..8f70f207d51 100644 --- a/tests/ui/consts/const-deref-ptr.stderr +++ b/tests/ui/consts/const-deref-ptr.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer - --> $DIR/const-deref-ptr.rs:4:29 +error[E0080]: memory access failed: attempting to access 8 bytes, but got 0xdeadbeef[noalloc] which is a dangling pointer (it has no provenance) + --> $DIR/const-deref-ptr.rs:4:30 | -LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 8 bytes, but got 0xdeadbeef[noalloc] which is a dangling pointer (it has no provenance) +LL | static C: u64 = unsafe { *(0xdeadbeef as *const u64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-err-early.rs b/tests/ui/consts/const-err-early.rs index a3105b4fc4a..998ac951ea9 100644 --- a/tests/ui/consts/const-err-early.rs +++ b/tests/ui/consts/const-err-early.rs @@ -1,8 +1,8 @@ -pub const A: i8 = -i8::MIN; //~ ERROR constant -pub const B: u8 = 200u8 + 200u8; //~ ERROR constant -pub const C: u8 = 200u8 * 4; //~ ERROR constant -pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR constant -pub const E: u8 = [5u8][1]; //~ ERROR constant +pub const A: i8 = -i8::MIN; //~ ERROR overflow +pub const B: u8 = 200u8 + 200u8; //~ ERROR overflow +pub const C: u8 = 200u8 * 4; //~ ERROR overflow +pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR overflow +pub const E: u8 = [5u8][1]; //~ ERROR index out of bounds fn main() { let _a = A; diff --git a/tests/ui/consts/const-err-early.stderr b/tests/ui/consts/const-err-early.stderr index 59bf637b7ad..8fa94ad8e35 100644 --- a/tests/ui/consts/const-err-early.stderr +++ b/tests/ui/consts/const-err-early.stderr @@ -1,32 +1,32 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to negate `i8::MIN`, which would overflow --> $DIR/const-err-early.rs:1:19 | LL | pub const A: i8 = -i8::MIN; - | ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `200_u8 + 200_u8`, which would overflow --> $DIR/const-err-early.rs:2:19 | LL | pub const B: u8 = 200u8 + 200u8; - | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `200_u8 * 4_u8`, which would overflow --> $DIR/const-err-early.rs:3:19 | LL | pub const C: u8 = 200u8 * 4; - | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `42_u8 - 43_u8`, which would overflow --> $DIR/const-err-early.rs:4:19 | LL | pub const D: u8 = 42u8 - (42u8 + 1); - | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: index out of bounds: the length is 1 but the index is 1 --> $DIR/const-err-early.rs:5:19 | LL | pub const E: u8 = [5u8][1]; - | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | ^^^^^^^^ evaluation of constant value failed error: aborting due to 5 previous errors diff --git a/tests/ui/consts/const-err-enum-discriminant.rs b/tests/ui/consts/const-err-enum-discriminant.rs index 42165ff5346..190ef47f436 100644 --- a/tests/ui/consts/const-err-enum-discriminant.rs +++ b/tests/ui/consts/const-err-enum-discriminant.rs @@ -6,8 +6,7 @@ union Foo { enum Bar { Boo = [unsafe { Foo { b: () }.a }; 4][3], - //~^ ERROR evaluation of constant value failed - //~| NOTE uninitialized + //~^ ERROR uninitialized } fn main() { diff --git a/tests/ui/consts/const-err-enum-discriminant.stderr b/tests/ui/consts/const-err-enum-discriminant.stderr index 7cf34595dc9..66bc09b4f93 100644 --- a/tests/ui/consts/const-err-enum-discriminant.stderr +++ b/tests/ui/consts/const-err-enum-discriminant.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/const-err-enum-discriminant.rs:8:21 | LL | Boo = [unsafe { Foo { b: () }.a }; 4][3], - | ^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-err-late.rs b/tests/ui/consts/const-err-late.rs index f8bea388109..9cc2196a954 100644 --- a/tests/ui/consts/const-err-late.rs +++ b/tests/ui/consts/const-err-late.rs @@ -12,8 +12,8 @@ struct S(T); impl S { const FOO: u8 = [5u8][1]; - //~^ ERROR evaluation of `S::::FOO` failed - //~| ERROR evaluation of `S::::FOO` failed + //~^ ERROR index out of bounds: the length is 1 but the index is 1 + //~| ERROR index out of bounds: the length is 1 but the index is 1 } fn main() { diff --git a/tests/ui/consts/const-err-late.stderr b/tests/ui/consts/const-err-late.stderr index 0c021e8761e..0878df6ff2d 100644 --- a/tests/ui/consts/const-err-late.stderr +++ b/tests/ui/consts/const-err-late.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `S::::FOO` failed +error[E0080]: index out of bounds: the length is 1 but the index is 1 --> $DIR/const-err-late.rs:14:21 | LL | const FOO: u8 = [5u8][1]; - | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | ^^^^^^^^ evaluation of `S::::FOO` failed note: erroneous constant encountered --> $DIR/const-err-late.rs:20:16 @@ -10,11 +10,11 @@ note: erroneous constant encountered LL | black_box((S::::FOO, S::::FOO)); | ^^^^^^^^^^^^^ -error[E0080]: evaluation of `S::::FOO` failed +error[E0080]: index out of bounds: the length is 1 but the index is 1 --> $DIR/const-err-late.rs:14:21 | LL | const FOO: u8 = [5u8][1]; - | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | ^^^^^^^^ evaluation of `S::::FOO` failed note: erroneous constant encountered --> $DIR/const-err-late.rs:20:31 diff --git a/tests/ui/consts/const-err-multi.rs b/tests/ui/consts/const-err-multi.rs index f21cc97345c..2fb0d291245 100644 --- a/tests/ui/consts/const-err-multi.rs +++ b/tests/ui/consts/const-err-multi.rs @@ -1,6 +1,6 @@ pub const A: i8 = -i8::MIN; -//~^ ERROR constant -//~| NOTE attempt to negate `i8::MIN`, which would overflow +//~^ NOTE constant +//~| ERROR attempt to negate `i8::MIN`, which would overflow pub const B: i8 = A; //~^ NOTE constant pub const C: u8 = A as u8; diff --git a/tests/ui/consts/const-err-multi.stderr b/tests/ui/consts/const-err-multi.stderr index c60be59b87d..712c160a2c0 100644 --- a/tests/ui/consts/const-err-multi.stderr +++ b/tests/ui/consts/const-err-multi.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to negate `i8::MIN`, which would overflow --> $DIR/const-err-multi.rs:1:19 | LL | pub const A: i8 = -i8::MIN; - | ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow + | ^^^^^^^^ evaluation of constant value failed note: erroneous constant encountered --> $DIR/const-err-multi.rs:4:19 diff --git a/tests/ui/consts/const-eval-fail-too-big.rs b/tests/ui/consts/const-eval-fail-too-big.rs index 4b5dbc1d7a4..b14505135fb 100644 --- a/tests/ui/consts/const-eval-fail-too-big.rs +++ b/tests/ui/consts/const-eval-fail-too-big.rs @@ -2,7 +2,7 @@ struct B< A: Sized = [(); { let x = [0u8; !0usize]; - //~^ ERROR evaluation of constant value failed + //~^ ERROR too big for the target architecture 1 }], > { diff --git a/tests/ui/consts/const-eval-fail-too-big.stderr b/tests/ui/consts/const-eval-fail-too-big.stderr index ae666483233..6f9dd178857 100644 --- a/tests/ui/consts/const-eval-fail-too-big.stderr +++ b/tests/ui/consts/const-eval-fail-too-big.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture --> $DIR/const-eval-fail-too-big.rs:4:28 | LL | let x = [0u8; !0usize]; - | ^^^^^^^^^^^^^^ values of the type `[u8; usize::MAX]` are too big for the target architecture + | ^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/assign-to-static-within-other-static.rs b/tests/ui/consts/const-eval/assign-to-static-within-other-static.rs index 30e40bd8be1..7a7a2566940 100644 --- a/tests/ui/consts/const-eval/assign-to-static-within-other-static.rs +++ b/tests/ui/consts/const-eval/assign-to-static-within-other-static.rs @@ -6,7 +6,7 @@ use std::cell::UnsafeCell; static mut FOO: u32 = 42; static BOO: () = unsafe { FOO = 5; - //~^ ERROR could not evaluate static initializer [E0080] + //~^ ERROR modifying a static's initial value }; fn main() {} diff --git a/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr b/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr index 5300111a6b6..ceb7d910b57 100644 --- a/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr +++ b/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: modifying a static's initial value from another static's initializer --> $DIR/assign-to-static-within-other-static.rs:8:5 | LL | FOO = 5; - | ^^^^^^^ modifying a static's initial value from another static's initializer + | ^^^^^^^ could not evaluate static initializer error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/conditional_array_execution.rs b/tests/ui/consts/const-eval/conditional_array_execution.rs index 27d5383d6d4..1473efa7428 100644 --- a/tests/ui/consts/const-eval/conditional_array_execution.rs +++ b/tests/ui/consts/const-eval/conditional_array_execution.rs @@ -1,7 +1,7 @@ const X: u32 = 5; const Y: u32 = 6; const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; -//~^ ERROR constant +//~^ ERROR overflow fn main() { println!("{}", FOO); diff --git a/tests/ui/consts/const-eval/conditional_array_execution.stderr b/tests/ui/consts/const-eval/conditional_array_execution.stderr index 30034378079..d4f85ce7f56 100644 --- a/tests/ui/consts/const-eval/conditional_array_execution.stderr +++ b/tests/ui/consts/const-eval/conditional_array_execution.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `5_u32 - 6_u32`, which would overflow --> $DIR/conditional_array_execution.rs:3:19 | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ^^^^^ attempt to compute `5_u32 - 6_u32`, which would overflow + | ^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const-eval-overflow-2.rs b/tests/ui/consts/const-eval/const-eval-overflow-2.rs index bae8a7ce243..71ac655435b 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-2.rs +++ b/tests/ui/consts/const-eval/const-eval-overflow-2.rs @@ -8,7 +8,7 @@ use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; const NEG_128: i8 = -128; -const NEG_NEG_128: i8 = -NEG_128; //~ ERROR constant +const NEG_NEG_128: i8 = -NEG_128; //~ ERROR overflow fn main() { match -128i8 { diff --git a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr index 5599ff931e8..6bd2a7482d2 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to negate `i8::MIN`, which would overflow --> $DIR/const-eval-overflow-2.rs:11:25 | LL | const NEG_NEG_128: i8 = -NEG_128; - | ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow + | ^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3.rs b/tests/ui/consts/const-eval/const-eval-overflow-3.rs index bcc966dc962..bf7e791483a 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-3.rs +++ b/tests/ui/consts/const-eval/const-eval-overflow-3.rs @@ -16,7 +16,7 @@ use std::fmt; const A_I8_I : [u32; (i8::MAX as usize) + 1] = [0; (i8::MAX + 1) as usize]; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflow fn main() { foo(&A_I8_I[..]); diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3.stderr b/tests/ui/consts/const-eval/const-eval-overflow-3.stderr index 0437cd3adb4..07cc8c8df70 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-3.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-3.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `i8::MAX + 1_i8`, which would overflow --> $DIR/const-eval-overflow-3.rs:18:11 | LL | = [0; (i8::MAX + 1) as usize]; - | ^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4.rs b/tests/ui/consts/const-eval/const-eval-overflow-4.rs index 762c7a968a8..d42c29249af 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-4.rs +++ b/tests/ui/consts/const-eval/const-eval-overflow-4.rs @@ -9,7 +9,7 @@ use std::fmt; const A_I8_T : [u32; (i8::MAX as i8 + 1i8) as usize] - //~^ ERROR evaluation of constant value failed + //~^ ERROR overflow = [0; (i8::MAX as usize) + 1]; fn main() { diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4.stderr b/tests/ui/consts/const-eval/const-eval-overflow-4.stderr index ce5e59901c1..c4e4e6e10e6 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-4.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-4.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `i8::MAX + 1_i8`, which would overflow --> $DIR/const-eval-overflow-4.rs:11:13 | LL | : [u32; (i8::MAX as i8 + 1i8) as usize] - | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const-eval-overflow2.rs b/tests/ui/consts/const-eval/const-eval-overflow2.rs index 1676f7c2af6..348c8e06f66 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow2.rs +++ b/tests/ui/consts/const-eval/const-eval-overflow2.rs @@ -11,47 +11,47 @@ const VALS_I8: (i8,) = ( i8::MIN - 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_I16: (i16,) = ( i16::MIN - 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_I32: (i32,) = ( i32::MIN - 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_I64: (i64,) = ( i64::MIN - 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_U8: (u8,) = ( u8::MIN - 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_U16: (u16,) = ( u16::MIN - 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_U32: (u32,) = ( u32::MIN - 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_U64: (u64,) = ( u64::MIN - 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow fn main() { foo(VALS_I8); diff --git a/tests/ui/consts/const-eval/const-eval-overflow2.stderr b/tests/ui/consts/const-eval/const-eval-overflow2.stderr index 341c15daf65..fc0bbe3ed2a 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow2.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow2.stderr @@ -1,50 +1,50 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `i8::MIN - 1_i8`, which would overflow --> $DIR/const-eval-overflow2.rs:12:6 | LL | i8::MIN - 1, - | ^^^^^^^^^^^ attempt to compute `i8::MIN - 1_i8`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `i16::MIN - 1_i16`, which would overflow --> $DIR/const-eval-overflow2.rs:18:6 | LL | i16::MIN - 1, - | ^^^^^^^^^^^^ attempt to compute `i16::MIN - 1_i16`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `i32::MIN - 1_i32`, which would overflow --> $DIR/const-eval-overflow2.rs:24:6 | LL | i32::MIN - 1, - | ^^^^^^^^^^^^ attempt to compute `i32::MIN - 1_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `i64::MIN - 1_i64`, which would overflow --> $DIR/const-eval-overflow2.rs:30:6 | LL | i64::MIN - 1, - | ^^^^^^^^^^^^ attempt to compute `i64::MIN - 1_i64`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `0_u8 - 1_u8`, which would overflow --> $DIR/const-eval-overflow2.rs:36:6 | LL | u8::MIN - 1, - | ^^^^^^^^^^^ attempt to compute `0_u8 - 1_u8`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `0_u16 - 1_u16`, which would overflow --> $DIR/const-eval-overflow2.rs:41:6 | LL | u16::MIN - 1, - | ^^^^^^^^^^^^ attempt to compute `0_u16 - 1_u16`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `0_u32 - 1_u32`, which would overflow --> $DIR/const-eval-overflow2.rs:46:6 | LL | u32::MIN - 1, - | ^^^^^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `0_u64 - 1_u64`, which would overflow --> $DIR/const-eval-overflow2.rs:52:6 | LL | u64::MIN - 1, - | ^^^^^^^^^^^^ attempt to compute `0_u64 - 1_u64`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 8 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-overflow2b.rs b/tests/ui/consts/const-eval/const-eval-overflow2b.rs index 59d1df5680d..b05b0b11105 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow2b.rs +++ b/tests/ui/consts/const-eval/const-eval-overflow2b.rs @@ -11,47 +11,47 @@ const VALS_I8: (i8,) = ( i8::MAX + 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_I16: (i16,) = ( i16::MAX + 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_I32: (i32,) = ( i32::MAX + 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_I64: (i64,) = ( i64::MAX + 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_U8: (u8,) = ( u8::MAX + 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_U16: (u16,) = ( u16::MAX + 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_U32: (u32,) = ( u32::MAX + 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_U64: (u64,) = ( u64::MAX + 1, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow fn main() { foo(VALS_I8); diff --git a/tests/ui/consts/const-eval/const-eval-overflow2b.stderr b/tests/ui/consts/const-eval/const-eval-overflow2b.stderr index e661836b4b9..cd8fbc5ee1c 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow2b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow2b.stderr @@ -1,50 +1,50 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `i8::MAX + 1_i8`, which would overflow --> $DIR/const-eval-overflow2b.rs:12:6 | LL | i8::MAX + 1, - | ^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `i16::MAX + 1_i16`, which would overflow --> $DIR/const-eval-overflow2b.rs:18:6 | LL | i16::MAX + 1, - | ^^^^^^^^^^^^ attempt to compute `i16::MAX + 1_i16`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `i32::MAX + 1_i32`, which would overflow --> $DIR/const-eval-overflow2b.rs:24:6 | LL | i32::MAX + 1, - | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `i64::MAX + 1_i64`, which would overflow --> $DIR/const-eval-overflow2b.rs:30:6 | LL | i64::MAX + 1, - | ^^^^^^^^^^^^ attempt to compute `i64::MAX + 1_i64`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `u8::MAX + 1_u8`, which would overflow --> $DIR/const-eval-overflow2b.rs:36:6 | LL | u8::MAX + 1, - | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `u16::MAX + 1_u16`, which would overflow --> $DIR/const-eval-overflow2b.rs:41:6 | LL | u16::MAX + 1, - | ^^^^^^^^^^^^ attempt to compute `u16::MAX + 1_u16`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `u32::MAX + 1_u32`, which would overflow --> $DIR/const-eval-overflow2b.rs:46:6 | LL | u32::MAX + 1, - | ^^^^^^^^^^^^ attempt to compute `u32::MAX + 1_u32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `u64::MAX + 1_u64`, which would overflow --> $DIR/const-eval-overflow2b.rs:52:6 | LL | u64::MAX + 1, - | ^^^^^^^^^^^^ attempt to compute `u64::MAX + 1_u64`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 8 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-overflow2c.rs b/tests/ui/consts/const-eval/const-eval-overflow2c.rs index 33b89260115..ec87f5e066c 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow2c.rs +++ b/tests/ui/consts/const-eval/const-eval-overflow2c.rs @@ -11,47 +11,47 @@ const VALS_I8: (i8,) = ( i8::MIN * 2, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_I16: (i16,) = ( i16::MIN * 2, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_I32: (i32,) = ( i32::MIN * 2, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_I64: (i64,) = ( i64::MIN * 2, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_U8: (u8,) = ( u8::MAX * 2, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_U16: (u16,) = ( u16::MAX * 2, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_U32: (u32,) = ( u32::MAX * 2, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow const VALS_U64: (u64,) = ( u64::MAX * 2, ); - //~^^ ERROR evaluation of constant value failed + //~^^ ERROR overflow fn main() { foo(VALS_I8); diff --git a/tests/ui/consts/const-eval/const-eval-overflow2c.stderr b/tests/ui/consts/const-eval/const-eval-overflow2c.stderr index 1fad15492fb..5914c40326b 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow2c.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow2c.stderr @@ -1,50 +1,50 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `i8::MIN * 2_i8`, which would overflow --> $DIR/const-eval-overflow2c.rs:12:6 | LL | i8::MIN * 2, - | ^^^^^^^^^^^ attempt to compute `i8::MIN * 2_i8`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `i16::MIN * 2_i16`, which would overflow --> $DIR/const-eval-overflow2c.rs:18:6 | LL | i16::MIN * 2, - | ^^^^^^^^^^^^ attempt to compute `i16::MIN * 2_i16`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `i32::MIN * 2_i32`, which would overflow --> $DIR/const-eval-overflow2c.rs:24:6 | LL | i32::MIN * 2, - | ^^^^^^^^^^^^ attempt to compute `i32::MIN * 2_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `i64::MIN * 2_i64`, which would overflow --> $DIR/const-eval-overflow2c.rs:30:6 | LL | i64::MIN * 2, - | ^^^^^^^^^^^^ attempt to compute `i64::MIN * 2_i64`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `u8::MAX * 2_u8`, which would overflow --> $DIR/const-eval-overflow2c.rs:36:6 | LL | u8::MAX * 2, - | ^^^^^^^^^^^ attempt to compute `u8::MAX * 2_u8`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `u16::MAX * 2_u16`, which would overflow --> $DIR/const-eval-overflow2c.rs:41:6 | LL | u16::MAX * 2, - | ^^^^^^^^^^^^ attempt to compute `u16::MAX * 2_u16`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `u32::MAX * 2_u32`, which would overflow --> $DIR/const-eval-overflow2c.rs:46:6 | LL | u32::MAX * 2, - | ^^^^^^^^^^^^ attempt to compute `u32::MAX * 2_u32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `u64::MAX * 2_u64`, which would overflow --> $DIR/const-eval-overflow2c.rs:52:6 | LL | u64::MAX * 2, - | ^^^^^^^^^^^^ attempt to compute `u64::MAX * 2_u64`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 8 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-query-stack.rs b/tests/ui/consts/const-eval/const-eval-query-stack.rs index 8de398787b4..3728e2071d3 100644 --- a/tests/ui/consts/const-eval/const-eval-query-stack.rs +++ b/tests/ui/consts/const-eval/const-eval-query-stack.rs @@ -13,7 +13,7 @@ //@ normalize-stderr: ".*omitted \d{1,} frame.*\n" -> "" #![allow(unconditional_panic)] -const X: i32 = 1 / 0; //~ERROR constant +const X: i32 = 1 / 0; //~ERROR attempt to divide `1_i32` by zero fn main() { let x: &'static i32 = &X; diff --git a/tests/ui/consts/const-eval/const-eval-query-stack.stderr b/tests/ui/consts/const-eval/const-eval-query-stack.stderr index 5a71c770fdc..c8bec4d4100 100644 --- a/tests/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/tests/ui/consts/const-eval/const-eval-query-stack.stderr @@ -1,8 +1,8 @@ -error: internal compiler error[E0080]: evaluation of constant value failed +error: internal compiler error[E0080]: attempt to divide `1_i32` by zero --> $DIR/const-eval-query-stack.rs:16:16 | LL | const X: i32 = 1 / 0; - | ^^^^^ attempt to divide `1_i32` by zero + | ^^^^^ evaluation of constant value failed note: please make sure that you have updated to the latest nightly diff --git a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr index 3eccd596274..ae7e035e038 100644 --- a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr +++ b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr @@ -1,254 +1,254 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:27:49 | LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:30:43 | LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:33:45 | LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:36:45 | LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:39:45 | LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed +error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/const-pointer-values-in-various-types.rs:42:47 | LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:46:43 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:45:43 | LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:49:45 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:48:45 | LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:52:45 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:51:45 | LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:55:45 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:54:45 | LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:58:47 +error[E0080]: using uninitialized data, but this operation requires initialized memory + --> $DIR/const-pointer-values-in-various-types.rs:57:47 | LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:62:45 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:60:45 | LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:65:45 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:63:45 | LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:68:47 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:66:47 | LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:71:47 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:69:47 | LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:74:39 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:72:39 | LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:77:41 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:75:41 | LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:80:41 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:78:41 | LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:83:41 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:81:41 | LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:86:43 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:84:43 | LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:89:39 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:87:39 | LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:92:41 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:90:41 | LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:95:41 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:93:41 | LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:98:41 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:96:41 | LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:101:43 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:99:43 | LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:104:41 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:102:41 | LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:107:41 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:105:41 | LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:110:43 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:108:43 | LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/const-pointer-values-in-various-types.rs:113:43 +error[E0080]: unable to turn pointer into integer + --> $DIR/const-pointer-values-in-various-types.rs:111:43 | LL | const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.rs b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.rs index ce7380cd155..5720d6ea91e 100644 --- a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.rs +++ b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.rs @@ -25,91 +25,89 @@ union Nonsense { fn main() { const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 }; - //~^ ERROR evaluation of constant value failed - //~| NOTE uninitialized + //~^ ERROR uninitialized const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 }; - //~^ ERROR evaluation of constant value failed - //~| NOTE uninitialized + //~^ ERROR uninitialized const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character }; - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer } diff --git a/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs b/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs index c6ae3af4427..03976a05b75 100644 --- a/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs +++ b/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs @@ -14,11 +14,11 @@ const fn bar(x: fn(usize) -> usize, y: usize) -> usize { } const Y: usize = bar(X, 2); // FIXME: should fail to typeck someday -//~^ ERROR evaluation of constant value failed -//~| NOTE calling non-const function `double` +//~^ NOTE evaluation of constant value failed +//~| ERROR calling non-const function `double` const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday -//~^ ERROR evaluation of constant value failed -//~| NOTE calling non-const function `double` +//~^ NOTE evaluation of constant value failed +//~| ERROR calling non-const function `double` fn main() { assert_eq!(Y, 4); diff --git a/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr index a4d2e26c3af..caa0542b6aa 100644 --- a/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr +++ b/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: calling non-const function `double` --> $DIR/const_fn_ptr_fail2.rs:16:18 | LL | const Y: usize = bar(X, 2); // FIXME: should fail to typeck someday - | ^^^^^^^^^ calling non-const function `double` + | ^^^^^^^^^ evaluation of constant value failed | note: inside `bar` --> $DIR/const_fn_ptr_fail2.rs:9:5 @@ -10,11 +10,11 @@ note: inside `bar` LL | x(y) | ^^^^ the failure occurred here -error[E0080]: evaluation of constant value failed +error[E0080]: calling non-const function `double` --> $DIR/const_fn_ptr_fail2.rs:19:18 | LL | const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday - | ^^^^^^^^^^^^^^ calling non-const function `double` + | ^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `bar` --> $DIR/const_fn_ptr_fail2.rs:9:5 diff --git a/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.rs b/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.rs index 0bf2f0e6669..45298df0243 100644 --- a/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.rs +++ b/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.rs @@ -1,5 +1,5 @@ #![crate_type = "lib"] struct Bug([u8; panic!{"\t"}]); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked //~| NOTE: in this expansion of panic! diff --git a/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr b/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr index fae971c09f2..cda005bfd3b 100644 --- a/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr +++ b/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: --> $DIR/const_panic-normalize-tabs-115498.rs:3:17 | LL | struct Bug([u8; panic!{"\t"}]); - | ^^^^^^^^^^^^ evaluation panicked: + | ^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const_panic.rs b/tests/ui/consts/const-eval/const_panic.rs index 5b9a8f8e2a2..367396bab94 100644 --- a/tests/ui/consts/const-eval/const_panic.rs +++ b/tests/ui/consts/const-eval/const_panic.rs @@ -4,37 +4,37 @@ const MSG: &str = "hello"; const Z: () = std::panic!("cheese"); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const Z2: () = std::panic!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const Y: () = std::unreachable!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const X: () = std::unimplemented!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const W: () = std::panic!(MSG); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const W2: () = std::panic!("{}", MSG); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const Z_CORE: () = core::panic!("cheese"); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const Z2_CORE: () = core::panic!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const Y_CORE: () = core::unreachable!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const X_CORE: () = core::unimplemented!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const W_CORE: () = core::panic!(MSG); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const W2_CORE: () = core::panic!("{}", MSG); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked diff --git a/tests/ui/consts/const-eval/const_panic.stderr b/tests/ui/consts/const-eval/const_panic.stderr index 0874224e5f2..c37d035ab78 100644 --- a/tests/ui/consts/const-eval/const_panic.stderr +++ b/tests/ui/consts/const-eval/const_panic.stderr @@ -1,78 +1,78 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: cheese --> $DIR/const_panic.rs:6:15 | LL | const Z: () = std::panic!("cheese"); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: cheese + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/const_panic.rs:9:16 | LL | const Z2: () = std::panic!(); - | ^^^^^^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic.rs:12:15 | LL | const Y: () = std::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^ evaluation panicked: internal error: entered unreachable code + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic.rs:15:15 | LL | const X: () = std::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: not implemented + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = note: this error originates in the macro `std::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: hello --> $DIR/const_panic.rs:18:15 | LL | const W: () = std::panic!(MSG); - | ^^^^^^^^^^^^^^^^ evaluation panicked: hello + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: hello --> $DIR/const_panic.rs:21:16 | LL | const W2: () = std::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: hello + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: cheese --> $DIR/const_panic.rs:24:20 | LL | const Z_CORE: () = core::panic!("cheese"); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: cheese + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/const_panic.rs:27:21 | LL | const Z2_CORE: () = core::panic!(); - | ^^^^^^^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic.rs:30:20 | LL | const Y_CORE: () = core::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^^ evaluation panicked: internal error: entered unreachable code + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic.rs:33:20 | LL | const X_CORE: () = core::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: not implemented + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = note: this error originates in the macro `core::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: hello --> $DIR/const_panic.rs:36:20 | LL | const W_CORE: () = core::panic!(MSG); - | ^^^^^^^^^^^^^^^^^ evaluation panicked: hello + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: hello --> $DIR/const_panic.rs:39:21 | LL | const W2_CORE: () = core::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: hello + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 12 previous errors diff --git a/tests/ui/consts/const-eval/const_panic_2021.rs b/tests/ui/consts/const-eval/const_panic_2021.rs index 31a80e71b7c..845f78beef9 100644 --- a/tests/ui/consts/const-eval/const_panic_2021.rs +++ b/tests/ui/consts/const-eval/const_panic_2021.rs @@ -4,31 +4,31 @@ const MSG: &str = "hello"; const A: () = std::panic!("blåhaj"); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const B: () = std::panic!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const C: () = std::unreachable!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const D: () = std::unimplemented!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const E: () = std::panic!("{}", MSG); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const A_CORE: () = core::panic!("shark"); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const B_CORE: () = core::panic!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const C_CORE: () = core::unreachable!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const D_CORE: () = core::unimplemented!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const E_CORE: () = core::panic!("{}", MSG); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked diff --git a/tests/ui/consts/const-eval/const_panic_2021.stderr b/tests/ui/consts/const-eval/const_panic_2021.stderr index 1496df4445a..18423f2c7d2 100644 --- a/tests/ui/consts/const-eval/const_panic_2021.stderr +++ b/tests/ui/consts/const-eval/const_panic_2021.stderr @@ -1,66 +1,66 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: blåhaj --> $DIR/const_panic_2021.rs:6:15 | LL | const A: () = std::panic!("blåhaj"); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: blåhaj + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/const_panic_2021.rs:9:15 | LL | const B: () = std::panic!(); - | ^^^^^^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic_2021.rs:12:15 | LL | const C: () = std::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^ evaluation panicked: internal error: entered unreachable code + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic_2021.rs:15:15 | LL | const D: () = std::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: not implemented + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = note: this error originates in the macro `std::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: hello --> $DIR/const_panic_2021.rs:18:15 | LL | const E: () = std::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: hello + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: shark --> $DIR/const_panic_2021.rs:21:20 | LL | const A_CORE: () = core::panic!("shark"); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: shark + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/const_panic_2021.rs:24:20 | LL | const B_CORE: () = core::panic!(); - | ^^^^^^^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic_2021.rs:27:20 | LL | const C_CORE: () = core::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^^ evaluation panicked: internal error: entered unreachable code + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic_2021.rs:30:20 | LL | const D_CORE: () = core::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: not implemented + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = note: this error originates in the macro `core::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: hello --> $DIR/const_panic_2021.rs:33:20 | LL | const E_CORE: () = core::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: hello + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 10 previous errors diff --git a/tests/ui/consts/const-eval/const_panic_libcore_bin.rs b/tests/ui/consts/const-eval/const_panic_libcore_bin.rs index d4dc1a51d73..90ae5165d23 100644 --- a/tests/ui/consts/const-eval/const_panic_libcore_bin.rs +++ b/tests/ui/consts/const-eval/const_panic_libcore_bin.rs @@ -6,13 +6,13 @@ use core::panic::PanicInfo; const Z: () = panic!("cheese"); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const Y: () = unreachable!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked const X: () = unimplemented!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked #[lang = "eh_personality"] fn eh() {} diff --git a/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr b/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr index 2acab711290..9f76e15b645 100644 --- a/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr +++ b/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr @@ -1,20 +1,20 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: cheese --> $DIR/const_panic_libcore_bin.rs:8:15 | LL | const Z: () = panic!("cheese"); - | ^^^^^^^^^^^^^^^^ evaluation panicked: cheese + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic_libcore_bin.rs:11:15 | LL | const Y: () = unreachable!(); - | ^^^^^^^^^^^^^^ evaluation panicked: internal error: entered unreachable code + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic_libcore_bin.rs:14:15 | LL | const X: () = unimplemented!(); - | ^^^^^^^^^^^^^^^^ evaluation panicked: not implemented + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed | = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/const-eval/const_panic_track_caller.rs b/tests/ui/consts/const-eval/const_panic_track_caller.rs index 799a59d16ca..5f5d853eb97 100644 --- a/tests/ui/consts/const-eval/const_panic_track_caller.rs +++ b/tests/ui/consts/const-eval/const_panic_track_caller.rs @@ -17,5 +17,5 @@ const fn c() -> u32 { } const X: u32 = c(); -//~^ ERROR evaluation of constant value failed -//~| NOTE hey +//~^ NOTE evaluation of constant value failed +//~| ERROR hey diff --git a/tests/ui/consts/const-eval/const_panic_track_caller.stderr b/tests/ui/consts/const-eval/const_panic_track_caller.stderr index 8736a8c9409..621e8880e3c 100644 --- a/tests/ui/consts/const-eval/const_panic_track_caller.stderr +++ b/tests/ui/consts/const-eval/const_panic_track_caller.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: hey --> $DIR/const_panic_track_caller.rs:19:16 | LL | const X: u32 = c(); - | ^^^ evaluation panicked: hey + | ^^^ evaluation of constant value failed | note: inside `c` --> $DIR/const_panic_track_caller.rs:15:5 diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs b/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs index 0e88aa80c79..47998cf408c 100644 --- a/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs @@ -4,7 +4,5 @@ fn main() {} const Z: i32 = unsafe { *(&1 as *const i32) }; // bad, will thus error in miri -const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR evaluation of constant value failed -//~| NOTE dangling pointer -const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR evaluation of constant value failed -//~| NOTE dangling pointer +const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR dangling pointer +const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR dangling pointer diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr index a8a5560ccb9..152f3704810 100644 --- a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr @@ -1,14 +1,14 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: attempting to access 4 bytes, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/const_raw_ptr_ops2.rs:7:26 | LL | const Z2: i32 = unsafe { *(42 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const_raw_ptr_ops2.rs:9:26 +error[E0080]: memory access failed: attempting to access 4 bytes, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) + --> $DIR/const_raw_ptr_ops2.rs:8:26 | LL | const Z3: i32 = unsafe { *(44 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs index b47e2b3c1ed..d6e5a69671b 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs @@ -4,7 +4,7 @@ #![feature(const_heap)] use std::intrinsics; -const FOO: i32 = foo(); //~ ERROR evaluation of constant value failed +const FOO: i32 = foo(); //~ ERROR 3 is not a power of 2 const fn foo() -> i32 { unsafe { let _ = intrinsics::const_allocate(4, 3) as *mut i32; //~ NOTE inside `foo` diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr index 9f7546df3a2..08990f949f8 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: invalid align passed to `const_allocate`: 3 is not a power of 2 --> $DIR/alloc_intrinsic_errors.rs:7:18 | LL | const FOO: i32 = foo(); - | ^^^^^ invalid align passed to `const_allocate`: 3 is not a power of 2 + | ^^^^^ evaluation of constant value failed | note: inside `foo` --> $DIR/alloc_intrinsic_errors.rs:10:17 diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr index 271c8611091..11ed0841a00 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr @@ -1,8 +1,8 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected an integer --> $DIR/alloc_intrinsic_uninit.rs:7:1 | LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; - | ^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized memory, but expected an integer + | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr index ec7cc7d4140..691bde87d2f 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr @@ -1,8 +1,8 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected an integer --> $DIR/alloc_intrinsic_uninit.rs:7:1 | LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; - | ^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized memory, but expected an integer + | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs index c283a5fae7d..ffc35ca1ddc 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs @@ -5,5 +5,5 @@ use std::intrinsics; const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; -//~^ error: it is undefined behavior to use this value +//~^ ERROR: uninitialized memory fn main() {} diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs index 509c872f609..de9fc5d0921 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs @@ -9,7 +9,7 @@ use std::intrinsics; const _X: &'static u8 = unsafe { - //~^ error: it is undefined behavior to use this value + //~^ ERROR: dangling reference (use-after-free) let ptr = intrinsics::const_allocate(4, 4); intrinsics::const_deallocate(ptr, 4, 4); &*ptr @@ -20,7 +20,7 @@ const _Y: u8 = unsafe { let reference = &*ptr; intrinsics::const_deallocate(ptr, 4, 4); *reference - //~^ error: evaluation of constant value failed + //~^ ERROR: has been freed, so this pointer is dangling }; fn main() {} diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr index 0b0d2676dd3..d1d16fa4fda 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr @@ -1,19 +1,19 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered a dangling reference (use-after-free) --> $DIR/dealloc_intrinsic_dangling.rs:11:1 | LL | const _X: &'static u8 = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free) + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: ALLOC1 has been freed, so this pointer is dangling --> $DIR/dealloc_intrinsic_dangling.rs:22:5 | LL | *reference - | ^^^^^^^^^^ memory access failed: ALLOC1 has been freed, so this pointer is dangling + | ^^^^^^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs index 4010b476990..5b7cd039b9b 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs @@ -7,7 +7,7 @@ const _X: () = unsafe { let ptr = intrinsics::const_allocate(4, 4); intrinsics::const_deallocate(ptr, 4, 4); intrinsics::const_deallocate(ptr, 4, 4); - //~^ error: evaluation of constant value failed + //~^ ERROR: dangling }; fn main() {} diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr index d2d323e5a51..553b0fa09c9 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: ALLOC0 has been freed, so this pointer is dangling --> $DIR/dealloc_intrinsic_duplicate.rs:9:5 | LL | intrinsics::const_deallocate(ptr, 4, 4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC0 has been freed, so this pointer is dangling + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs index 031d70fdc88..75c3601f216 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs @@ -6,24 +6,24 @@ use std::intrinsics; const _X: () = unsafe { let ptr = intrinsics::const_allocate(4, 4); intrinsics::const_deallocate(ptr, 4, 2); - //~^ error: evaluation of constant value failed + //~^ error: incorrect layout on deallocation }; const _Y: () = unsafe { let ptr = intrinsics::const_allocate(4, 4); intrinsics::const_deallocate(ptr, 2, 4); - //~^ error: evaluation of constant value failed + //~^ error: incorrect layout on deallocation }; const _Z: () = unsafe { let ptr = intrinsics::const_allocate(4, 4); intrinsics::const_deallocate(ptr, 3, 4); - //~^ error: evaluation of constant value failed + //~^ error: incorrect layout on deallocation }; const _W: () = unsafe { let ptr = intrinsics::const_allocate(4, 4); intrinsics::const_deallocate(ptr, 4, 3); - //~^ error: evaluation of constant value failed + //~^ error: invalid align }; fn main() {} diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr index 4b1f0f686ca..04fa75d25c7 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr @@ -1,26 +1,26 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: incorrect layout on deallocation: ALLOC0 has size 4 and alignment 4, but gave size 4 and alignment 2 --> $DIR/dealloc_intrinsic_incorrect_layout.rs:8:5 | LL | intrinsics::const_deallocate(ptr, 4, 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC0 has size 4 and alignment 4, but gave size 4 and alignment 2 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: incorrect layout on deallocation: ALLOC1 has size 4 and alignment 4, but gave size 2 and alignment 4 --> $DIR/dealloc_intrinsic_incorrect_layout.rs:13:5 | LL | intrinsics::const_deallocate(ptr, 2, 4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC1 has size 4 and alignment 4, but gave size 2 and alignment 4 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: incorrect layout on deallocation: ALLOC2 has size 4 and alignment 4, but gave size 3 and alignment 4 --> $DIR/dealloc_intrinsic_incorrect_layout.rs:19:5 | LL | intrinsics::const_deallocate(ptr, 3, 4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC2 has size 4 and alignment 4, but gave size 3 and alignment 4 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: invalid align passed to `const_deallocate`: 3 is not a power of 2 --> $DIR/dealloc_intrinsic_incorrect_layout.rs:25:5 | LL | intrinsics::const_deallocate(ptr, 4, 3); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid align passed to `const_deallocate`: 3 is not a power of 2 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 4 previous errors diff --git a/tests/ui/consts/const-eval/index-out-of-bounds-never-type.rs b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.rs index 25ffc9cbdba..6777bee050a 100644 --- a/tests/ui/consts/const-eval/index-out-of-bounds-never-type.rs +++ b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.rs @@ -8,7 +8,7 @@ struct PrintName(T); impl PrintName { const VOID: ! = { let x = 0 * std::mem::size_of::(); [][x] }; - //~^ ERROR evaluation of `PrintName::<()>::VOID` failed + //~^ ERROR index out of bounds: the length is 0 but the index is 0 } diff --git a/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr index 7facb2d1a5c..fe34d211d52 100644 --- a/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr +++ b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `PrintName::<()>::VOID` failed +error[E0080]: index out of bounds: the length is 0 but the index is 0 --> $DIR/index-out-of-bounds-never-type.rs:10:61 | LL | const VOID: ! = { let x = 0 * std::mem::size_of::(); [][x] }; - | ^^^^^ index out of bounds: the length is 0 but the index is 0 + | ^^^^^ evaluation of `PrintName::<()>::VOID` failed note: erroneous constant encountered --> $DIR/index-out-of-bounds-never-type.rs:16:13 diff --git a/tests/ui/consts/const-eval/index_out_of_bounds.stderr b/tests/ui/consts/const-eval/index_out_of_bounds.stderr index d8df74fa010..9fe52f11d04 100644 --- a/tests/ui/consts/const-eval/index_out_of_bounds.stderr +++ b/tests/ui/consts/const-eval/index_out_of_bounds.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: index out of bounds: the length is 0 but the index is 0 --> $DIR/index_out_of_bounds.rs:1:19 | LL | static FOO: i32 = [][0]; - | ^^^^^ index out of bounds: the length is 0 but the index is 0 + | ^^^^^ could not evaluate static initializer error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/issue-43197.rs b/tests/ui/consts/const-eval/issue-43197.rs index 145463f0ae2..778a66facb8 100644 --- a/tests/ui/consts/const-eval/issue-43197.rs +++ b/tests/ui/consts/const-eval/issue-43197.rs @@ -4,8 +4,8 @@ const fn foo(x: u32) -> u32 { fn main() { const X: u32 = 0 - 1; - //~^ ERROR constant + //~^ ERROR overflow const Y: u32 = foo(0 - 1); - //~^ ERROR constant + //~^ ERROR overflow println!("{} {}", X, Y); } diff --git a/tests/ui/consts/const-eval/issue-43197.stderr b/tests/ui/consts/const-eval/issue-43197.stderr index c59f13e4888..f2211dfb388 100644 --- a/tests/ui/consts/const-eval/issue-43197.stderr +++ b/tests/ui/consts/const-eval/issue-43197.stderr @@ -1,14 +1,14 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `0_u32 - 1_u32`, which would overflow --> $DIR/issue-43197.rs:6:20 | LL | const X: u32 = 0 - 1; - | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | ^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `0_u32 - 1_u32`, which would overflow --> $DIR/issue-43197.rs:8:24 | LL | const Y: u32 = foo(0 - 1); - | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | ^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/issue-44578.rs b/tests/ui/consts/const-eval/issue-44578.rs index 565e1d3825b..ebd54f4079c 100644 --- a/tests/ui/consts/const-eval/issue-44578.rs +++ b/tests/ui/consts/const-eval/issue-44578.rs @@ -11,7 +11,7 @@ enum Bar { } impl Foo for Bar { - const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; //~ERROR evaluation of ` as Foo>::AMT` failed + const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; //~ERROR the length is 1 but the index is 1 } impl Foo for u8 { diff --git a/tests/ui/consts/const-eval/issue-44578.stderr b/tests/ui/consts/const-eval/issue-44578.stderr index 5093cec81c7..f558b7a5016 100644 --- a/tests/ui/consts/const-eval/issue-44578.stderr +++ b/tests/ui/consts/const-eval/issue-44578.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of ` as Foo>::AMT` failed +error[E0080]: index out of bounds: the length is 1 but the index is 1 --> $DIR/issue-44578.rs:14:24 | LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of ` as Foo>::AMT` failed note: erroneous constant encountered --> $DIR/issue-44578.rs:26:20 diff --git a/tests/ui/consts/const-eval/issue-49296.rs b/tests/ui/consts/const-eval/issue-49296.rs index 917777a32ff..a427b642899 100644 --- a/tests/ui/consts/const-eval/issue-49296.rs +++ b/tests/ui/consts/const-eval/issue-49296.rs @@ -7,7 +7,7 @@ const fn wat(x: u64) -> &'static u64 { } const X: u64 = *wat(42); -//~^ ERROR evaluation of constant value failed +//~^ ERROR dangling fn main() { println!("{}", X); diff --git a/tests/ui/consts/const-eval/issue-49296.stderr b/tests/ui/consts/const-eval/issue-49296.stderr index 485a11d1f3c..9c7f8997eaa 100644 --- a/tests/ui/consts/const-eval/issue-49296.stderr +++ b/tests/ui/consts/const-eval/issue-49296.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: ALLOC0 has been freed, so this pointer is dangling --> $DIR/issue-49296.rs:9:16 | LL | const X: u64 = *wat(42); - | ^^^^^^^^ memory access failed: ALLOC0 has been freed, so this pointer is dangling + | ^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr b/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr index 1f4f217b175..a333fe3423b 100644 --- a/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr +++ b/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of ` as Foo<()>>::BAR` failed +error[E0080]: index out of bounds: the length is 3 but the index is 42 --> $DIR/issue-50814-2.rs:17:24 | LL | const BAR: usize = [5, 6, 7][T::BOO]; - | ^^^^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 42 + | ^^^^^^^^^^^^^^^^^ evaluation of ` as Foo<()>>::BAR` failed note: erroneous constant encountered --> $DIR/issue-50814-2.rs:21:6 diff --git a/tests/ui/consts/const-eval/issue-50814-2.normal.stderr b/tests/ui/consts/const-eval/issue-50814-2.normal.stderr index f790862aef1..0ad4185be3a 100644 --- a/tests/ui/consts/const-eval/issue-50814-2.normal.stderr +++ b/tests/ui/consts/const-eval/issue-50814-2.normal.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of ` as Foo<()>>::BAR` failed +error[E0080]: index out of bounds: the length is 3 but the index is 42 --> $DIR/issue-50814-2.rs:17:24 | LL | const BAR: usize = [5, 6, 7][T::BOO]; - | ^^^^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 42 + | ^^^^^^^^^^^^^^^^^ evaluation of ` as Foo<()>>::BAR` failed note: erroneous constant encountered --> $DIR/issue-50814-2.rs:21:6 diff --git a/tests/ui/consts/const-eval/issue-50814-2.rs b/tests/ui/consts/const-eval/issue-50814-2.rs index 261dcd3aa4c..1b917a0916d 100644 --- a/tests/ui/consts/const-eval/issue-50814-2.rs +++ b/tests/ui/consts/const-eval/issue-50814-2.rs @@ -14,7 +14,7 @@ trait Foo { struct A(T); impl Foo for A { - const BAR: usize = [5, 6, 7][T::BOO]; //~ ERROR evaluation of ` as Foo<()>>::BAR` failed + const BAR: usize = [5, 6, 7][T::BOO]; //~ ERROR index out of bounds: the length is 3 but the index is 42 } fn foo() -> &'static usize { diff --git a/tests/ui/consts/const-eval/issue-50814.rs b/tests/ui/consts/const-eval/issue-50814.rs index 5495fb43bba..011f065ad81 100644 --- a/tests/ui/consts/const-eval/issue-50814.rs +++ b/tests/ui/consts/const-eval/issue-50814.rs @@ -14,8 +14,8 @@ struct Sum(A, B); impl Unsigned for Sum { const MAX: u8 = A::MAX + B::MAX; - //~^ ERROR evaluation of ` as Unsigned>::MAX` failed - //~| ERROR evaluation of ` as Unsigned>::MAX` failed + //~^ ERROR attempt to compute `u8::MAX + u8::MAX`, which would overflow + //~| ERROR attempt to compute `u8::MAX + u8::MAX`, which would overflow } fn foo(_: T) -> &'static u8 { diff --git a/tests/ui/consts/const-eval/issue-50814.stderr b/tests/ui/consts/const-eval/issue-50814.stderr index 5b23c48e450..27cc6458ec1 100644 --- a/tests/ui/consts/const-eval/issue-50814.stderr +++ b/tests/ui/consts/const-eval/issue-50814.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of ` as Unsigned>::MAX` failed +error[E0080]: attempt to compute `u8::MAX + u8::MAX`, which would overflow --> $DIR/issue-50814.rs:16:21 | LL | const MAX: u8 = A::MAX + B::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `u8::MAX + u8::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of ` as Unsigned>::MAX` failed note: erroneous constant encountered --> $DIR/issue-50814.rs:22:6 @@ -10,11 +10,11 @@ note: erroneous constant encountered LL | &Sum::::MAX | ^^^^^^^^^^^^^^^^^^ -error[E0080]: evaluation of ` as Unsigned>::MAX` failed +error[E0080]: attempt to compute `u8::MAX + u8::MAX`, which would overflow --> $DIR/issue-50814.rs:16:21 | LL | const MAX: u8 = A::MAX + B::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `u8::MAX + u8::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of ` as Unsigned>::MAX` failed | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/consts/const-eval/issue-85155.rs b/tests/ui/consts/const-eval/issue-85155.rs index cb5b3a08375..c47101d04c2 100644 --- a/tests/ui/consts/const-eval/issue-85155.rs +++ b/tests/ui/consts/const-eval/issue-85155.rs @@ -20,5 +20,5 @@ fn main() { //~^ NOTE the above error was encountered while instantiating } -//~? ERROR evaluation of `post_monomorphization_error::ValidateConstImm::<2, 0, 1>::VALID` failed +//~? ERROR attempt to divide `1_usize` by zero //~? NOTE erroneous constant encountered diff --git a/tests/ui/consts/const-eval/issue-85155.stderr b/tests/ui/consts/const-eval/issue-85155.stderr index 99836a3fac6..8aa99764fe0 100644 --- a/tests/ui/consts/const-eval/issue-85155.stderr +++ b/tests/ui/consts/const-eval/issue-85155.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `post_monomorphization_error::ValidateConstImm::<2, 0, 1>::VALID` failed +error[E0080]: attempt to divide `1_usize` by zero --> $DIR/auxiliary/post_monomorphization_error.rs:7:17 | LL | let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to divide `1_usize` by zero + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `post_monomorphization_error::ValidateConstImm::<2, 0, 1>::VALID` failed note: erroneous constant encountered --> $DIR/auxiliary/post_monomorphization_error.rs:19:5 diff --git a/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.rs b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.rs index 3a932343ddd..12effde1a9b 100644 --- a/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.rs +++ b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.rs @@ -36,8 +36,7 @@ const OFFSET: () = unsafe { // This needs to compute the field offset, but we don't know the type's alignment, so this // fails. let field = &x.a; - //~^ ERROR: evaluation of constant value failed - //~| NOTE does not have a known offset + //~^ ERROR: does not have a known offset }; fn main() {} diff --git a/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr index 54d45ee8ffb..185ef9c0750 100644 --- a/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr +++ b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: `extern type` field does not have a known offset --> $DIR/issue-91827-extern-types-field-offset.rs:38:17 | LL | let field = &x.a; - | ^^^^ `extern type` field does not have a known offset + | ^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/mod-static-with-const-fn.rs b/tests/ui/consts/const-eval/mod-static-with-const-fn.rs index 7de9d44305d..ce2ecaa2638 100644 --- a/tests/ui/consts/const-eval/mod-static-with-const-fn.rs +++ b/tests/ui/consts/const-eval/mod-static-with-const-fn.rs @@ -12,7 +12,7 @@ static FOO: Foo = Foo(UnsafeCell::new(42)); static BAR: () = unsafe { *FOO.0.get() = 5; - //~^ ERROR could not evaluate static initializer + //~^ ERROR modifying a static's initial value }; fn main() { diff --git a/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr b/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr index 47bfc235a1a..b882b902d96 100644 --- a/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr +++ b/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: modifying a static's initial value from another static's initializer --> $DIR/mod-static-with-const-fn.rs:14:5 | LL | *FOO.0.get() = 5; - | ^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer + | ^^^^^^^^^^^^^^^^ could not evaluate static initializer error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/nonnull_as_ref_ub.rs b/tests/ui/consts/const-eval/nonnull_as_ref_ub.rs index 19ab5239986..908833e6514 100644 --- a/tests/ui/consts/const-eval/nonnull_as_ref_ub.rs +++ b/tests/ui/consts/const-eval/nonnull_as_ref_ub.rs @@ -1,6 +1,6 @@ use std::ptr::NonNull; const NON_NULL: NonNull = unsafe { NonNull::dangling() }; -const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() }); //~ERROR: evaluation of constant value failed +const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() }); //~ERROR: dangling pointer (it has no provenance) fn main() {} diff --git a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr index 1996cd2721e..c4c8a76ddac 100644 --- a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr +++ b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/nonnull_as_ref_ub.rs:4:29 | LL | const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/panic-assoc-never-type.rs b/tests/ui/consts/const-eval/panic-assoc-never-type.rs index 79b5dafaf15..a0a5ba36bfe 100644 --- a/tests/ui/consts/const-eval/panic-assoc-never-type.rs +++ b/tests/ui/consts/const-eval/panic-assoc-never-type.rs @@ -8,7 +8,7 @@ struct PrintName; impl PrintName { const VOID: ! = panic!(); - //~^ ERROR evaluation of constant value failed + //~^ ERROR explicit panic } fn main() { diff --git a/tests/ui/consts/const-eval/panic-assoc-never-type.stderr b/tests/ui/consts/const-eval/panic-assoc-never-type.stderr index 03413f46b20..2d6bf96228b 100644 --- a/tests/ui/consts/const-eval/panic-assoc-never-type.stderr +++ b/tests/ui/consts/const-eval/panic-assoc-never-type.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/panic-assoc-never-type.rs:10:21 | LL | const VOID: ! = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of constant value failed note: erroneous constant encountered --> $DIR/panic-assoc-never-type.rs:15:13 diff --git a/tests/ui/consts/const-eval/panic-never-type.rs b/tests/ui/consts/const-eval/panic-never-type.rs index a9e9026d9bc..d9b46e70b35 100644 --- a/tests/ui/consts/const-eval/panic-never-type.rs +++ b/tests/ui/consts/const-eval/panic-never-type.rs @@ -2,7 +2,7 @@ #![feature(never_type)] const VOID: ! = panic!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR explicit panic fn main() { let _ = VOID; diff --git a/tests/ui/consts/const-eval/panic-never-type.stderr b/tests/ui/consts/const-eval/panic-never-type.stderr index 1d9bba9aea2..60712effbab 100644 --- a/tests/ui/consts/const-eval/panic-never-type.stderr +++ b/tests/ui/consts/const-eval/panic-never-type.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/panic-never-type.rs:4:17 | LL | const VOID: ! = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/parse_ints.rs b/tests/ui/consts/const-eval/parse_ints.rs index 309b7ee5d27..409fae9e51d 100644 --- a/tests/ui/consts/const-eval/parse_ints.rs +++ b/tests/ui/consts/const-eval/parse_ints.rs @@ -2,7 +2,7 @@ const _OK: () = match i32::from_str_radix("-1234", 10) { Ok(x) => assert!(x == -1234), Err(_) => panic!(), }; -const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); }; //~ ERROR evaluation of constant value failed -const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); }; //~ ERROR evaluation of constant value failed +const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); }; //~ ERROR radix must lie in the range `[2, 36]` +const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); }; //~ ERROR radix must lie in the range `[2, 36]` fn main () {} diff --git a/tests/ui/consts/const-eval/parse_ints.stderr b/tests/ui/consts/const-eval/parse_ints.stderr index 7a855bb9e5c..8b5ab23e182 100644 --- a/tests/ui/consts/const-eval/parse_ints.stderr +++ b/tests/ui/consts/const-eval/parse_ints.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: from_ascii_radix: radix must lie in the range `[2, 36]` --> $DIR/parse_ints.rs:5:24 | LL | const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: from_ascii_radix: radix must lie in the range `[2, 36]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `core::num::::from_str_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL @@ -10,11 +10,11 @@ note: inside `core::num::::from_ascii_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL = note: this error originates in the macro `from_str_int_impl` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: from_ascii_radix: radix must lie in the range `[2, 36]` --> $DIR/parse_ints.rs:6:25 | LL | const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: from_ascii_radix: radix must lie in the range `[2, 36]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `core::num::::from_str_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL diff --git a/tests/ui/consts/const-eval/partial_ptr_overwrite.rs b/tests/ui/consts/const-eval/partial_ptr_overwrite.rs index 9438de5e3fe..bd97bec0f71 100644 --- a/tests/ui/consts/const-eval/partial_ptr_overwrite.rs +++ b/tests/ui/consts/const-eval/partial_ptr_overwrite.rs @@ -4,8 +4,7 @@ const PARTIAL_OVERWRITE: () = { let mut p = &42; unsafe { let ptr: *mut _ = &mut p; - *(ptr as *mut u8) = 123; //~ ERROR constant - //~| NOTE unable to overwrite parts of a pointer + *(ptr as *mut u8) = 123; //~ ERROR unable to overwrite parts of a pointer } let x = *p; }; diff --git a/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr b/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr index 1443d353848..b5d1e4c113c 100644 --- a/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr +++ b/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: unable to overwrite parts of a pointer in memory at ALLOC0 --> $DIR/partial_ptr_overwrite.rs:7:9 | LL | *(ptr as *mut u8) = 123; - | ^^^^^^^^^^^^^^^^^^^^^^^ unable to overwrite parts of a pointer in memory at ALLOC0 + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr index 120a08acc33..36183e28921 100644 --- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -1,340 +1,340 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered 0x00000001, but expected a valid enum tag --> $DIR/raw-bytes.rs:23:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x00000001, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 01 00 00 00 │ .... } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered 0x00000000, but expected a valid enum tag --> $DIR/raw-bytes.rs:31:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x00000000, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 00 00 00 00 │ .... } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant --> $DIR/raw-bytes.rs:45:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 01 │ . } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant --> $DIR/raw-bytes.rs:47:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 03 │ . } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) --> $DIR/raw-bytes.rs:53:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { 78 00 00 00 ff ff ff ff │ x....... } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:58:1 | LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 00 00 00 00 │ .... } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:61:1 | LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 00 │ . } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:63:1 | LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 00 00 00 00 │ .... } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 42, but expected something in the range 10..=30 --> $DIR/raw-bytes.rs:69:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 2a 00 00 00 │ *... } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 --> $DIR/raw-bytes.rs:75:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 14 00 00 00 │ .... } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:78:1 | LL | const NULL_FAT_PTR: NonNull = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { 00 00 00 00 ╾ALLOC_ID╼ │ ....╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:86:1 +error[E0080]: constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) + --> $DIR/raw-bytes.rs:85:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC_ID╼ │ ╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:90:1 +error[E0080]: constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) + --> $DIR/raw-bytes.rs:88:1 | LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC_ID╼ │ ╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:94:1 +error[E0080]: constructing invalid value: encountered a null reference + --> $DIR/raw-bytes.rs:91:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference + | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 00 00 00 00 │ .... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:97:1 +error[E0080]: constructing invalid value: encountered a null box + --> $DIR/raw-bytes.rs:94:1 | LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box + | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 00 00 00 00 │ .... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:100:1 +error[E0080]: constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) + --> $DIR/raw-bytes.rs:97:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 39 05 00 00 │ 9... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:103:1 +error[E0080]: constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) + --> $DIR/raw-bytes.rs:100:1 | LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 39 05 00 00 │ 9... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:106:1 +error[E0080]: constructing invalid value: encountered null pointer, but expected a function pointer + --> $DIR/raw-bytes.rs:103:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 00 00 00 00 │ .... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:108:1 +error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected a function pointer + --> $DIR/raw-bytes.rs:105:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 0d 00 00 00 │ .... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:110:1 +error[E0080]: constructing invalid value: encountered ALLOC3, but expected a function pointer + --> $DIR/raw-bytes.rs:107:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC_ID╼ │ ╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:116:1 +error[E0080]: constructing invalid value: encountered a reference pointing to uninhabited type Bar + --> $DIR/raw-bytes.rs:113:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 01 00 00 00 │ .... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:141:1 +error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + --> $DIR/raw-bytes.rs:137:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:143:1 +error[E0080]: constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object + --> $DIR/raw-bytes.rs:139:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:145:1 +error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + --> $DIR/raw-bytes.rs:141:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:148:1 +error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected a string + --> $DIR/raw-bytes.rs:144:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized memory, but expected a string + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:150:1 +error[E0080]: constructing invalid value at ..0: encountered uninitialized memory, but expected a string + --> $DIR/raw-bytes.rs:146:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered uninitialized memory, but expected a string + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:152:1 +error[E0080]: constructing invalid value at ..0: encountered a pointer, but expected a string + --> $DIR/raw-bytes.rs:148:1 | LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a pointer, but expected a string + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:156:1 +error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + --> $DIR/raw-bytes.rs:152:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:158:1 +error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + --> $DIR/raw-bytes.rs:154:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ff ff ff 7f │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:161:1 +error[E0080]: constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) + --> $DIR/raw-bytes.rs:157:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:164:1 +error[E0080]: constructing invalid value at .[0]: encountered 0x03, but expected a boolean + --> $DIR/raw-bytes.rs:160:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -342,16 +342,16 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:164:40 + --> $DIR/raw-bytes.rs:160:40 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:170:1 +error[E0080]: constructing invalid value at ..0: encountered 0x03, but expected a boolean + --> $DIR/raw-bytes.rs:164:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -359,16 +359,16 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3 } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:170:42 + --> $DIR/raw-bytes.rs:164:42 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:174:1 +error[E0080]: constructing invalid value at ..1[0]: encountered 0x03, but expected a boolean + --> $DIR/raw-bytes.rs:167:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..1[0]: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -376,196 +376,196 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:174:42 + --> $DIR/raw-bytes.rs:167:42 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:179:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer + --> $DIR/raw-bytes.rs:171:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:183:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer + --> $DIR/raw-bytes.rs:174:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:187:1 +error[E0080]: constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer + --> $DIR/raw-bytes.rs:177:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:190:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer + --> $DIR/raw-bytes.rs:179:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:194:1 +error[E0080]: constructing invalid value at ..: encountered 0x03, but expected a boolean + --> $DIR/raw-bytes.rs:182:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:198:1 +error[E0080]: constructing invalid value: encountered null pointer, but expected a vtable pointer + --> $DIR/raw-bytes.rs:185:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 00 00 00 00 │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:201:1 +error[E0080]: constructing invalid value: encountered ALLOC27, but expected a vtable pointer + --> $DIR/raw-bytes.rs:187:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:206:1 +error[E0080]: constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] + --> $DIR/raw-bytes.rs:191:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] + | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 01 00 00 00 │ .... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:207:1 +error[E0080]: constructing invalid value at .[0]: encountered a value of the never type `!` + --> $DIR/raw-bytes.rs:192:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a value of the never type `!` + | ^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { 01 00 00 00 01 00 00 00 │ ........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:208:1 +error[E0080]: constructing invalid value at .[0]: encountered a value of the never type `!` + --> $DIR/raw-bytes.rs:193:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; - | ^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a value of the never type `!` + | ^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { 01 00 00 00 2a 00 00 00 │ ....*... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:212:1 +error[E0080]: constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer + --> $DIR/raw-bytes.rs:196:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:215:1 +error[E0080]: constructing invalid value at .[0]: encountered a pointer, but expected an integer + --> $DIR/raw-bytes.rs:199:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:218:1 +error[E0080]: constructing invalid value at .[0]: encountered 0x11, but expected a boolean + --> $DIR/raw-bytes.rs:202:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:222:1 +error[E0080]: constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer + --> $DIR/raw-bytes.rs:206:1 | LL | pub static S7: &[u16] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID+0x2╼ 04 00 00 00 │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:229:1 +error[E0080]: constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer + --> $DIR/raw-bytes.rs:213:1 | LL | pub static R4: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:234:1 +error[E0080]: constructing invalid value at .[0]: encountered a pointer, but expected an integer + --> $DIR/raw-bytes.rs:218:1 | LL | pub static R5: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:239:1 +error[E0080]: constructing invalid value at .[0]: encountered 0x11, but expected a boolean + --> $DIR/raw-bytes.rs:223:1 | LL | pub static R6: &[bool] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index d54ad7c8546..c53326534fd 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -1,340 +1,340 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered 0x0000000000000001, but expected a valid enum tag --> $DIR/raw-bytes.rs:23:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0000000000000001, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 01 00 00 00 00 00 00 00 │ ........ } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered 0x0000000000000000, but expected a valid enum tag --> $DIR/raw-bytes.rs:31:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0000000000000000, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 00 00 00 00 00 00 00 00 │ ........ } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant --> $DIR/raw-bytes.rs:45:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 01 │ . } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant --> $DIR/raw-bytes.rs:47:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 03 │ . } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) --> $DIR/raw-bytes.rs:53:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { 78 00 00 00 ff ff ff ff │ x....... } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:58:1 | LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 00 00 00 00 00 00 00 00 │ ........ } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:61:1 | LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 00 │ . } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:63:1 | LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 00 00 00 00 00 00 00 00 │ ........ } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 42, but expected something in the range 10..=30 --> $DIR/raw-bytes.rs:69:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 2a 00 00 00 │ *... } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 --> $DIR/raw-bytes.rs:75:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 14 00 00 00 │ .... } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 0, but expected something greater or equal to 1 --> $DIR/raw-bytes.rs:78:1 | LL | const NULL_FAT_PTR: NonNull = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { 00 00 00 00 00 00 00 00 ╾ALLOC_ID╼ │ ........╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:86:1 +error[E0080]: constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) + --> $DIR/raw-bytes.rs:85:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC_ID╼ │ ╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:90:1 +error[E0080]: constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) + --> $DIR/raw-bytes.rs:88:1 | LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC_ID╼ │ ╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:94:1 +error[E0080]: constructing invalid value: encountered a null reference + --> $DIR/raw-bytes.rs:91:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference + | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 00 00 00 00 00 00 00 00 │ ........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:97:1 +error[E0080]: constructing invalid value: encountered a null box + --> $DIR/raw-bytes.rs:94:1 | LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box + | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 00 00 00 00 00 00 00 00 │ ........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:100:1 +error[E0080]: constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) + --> $DIR/raw-bytes.rs:97:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 39 05 00 00 00 00 00 00 │ 9....... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:103:1 +error[E0080]: constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) + --> $DIR/raw-bytes.rs:100:1 | LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 39 05 00 00 00 00 00 00 │ 9....... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:106:1 +error[E0080]: constructing invalid value: encountered null pointer, but expected a function pointer + --> $DIR/raw-bytes.rs:103:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 00 00 00 00 00 00 00 00 │ ........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:108:1 +error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected a function pointer + --> $DIR/raw-bytes.rs:105:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 0d 00 00 00 00 00 00 00 │ ........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:110:1 +error[E0080]: constructing invalid value: encountered ALLOC3, but expected a function pointer + --> $DIR/raw-bytes.rs:107:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC_ID╼ │ ╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:116:1 +error[E0080]: constructing invalid value: encountered a reference pointing to uninhabited type Bar + --> $DIR/raw-bytes.rs:113:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 01 00 00 00 00 00 00 00 │ ........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:141:1 +error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + --> $DIR/raw-bytes.rs:137:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:143:1 +error[E0080]: constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object + --> $DIR/raw-bytes.rs:139:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:145:1 +error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + --> $DIR/raw-bytes.rs:141:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:148:1 +error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected a string + --> $DIR/raw-bytes.rs:144:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized memory, but expected a string + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:150:1 +error[E0080]: constructing invalid value at ..0: encountered uninitialized memory, but expected a string + --> $DIR/raw-bytes.rs:146:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered uninitialized memory, but expected a string + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:152:1 +error[E0080]: constructing invalid value at ..0: encountered a pointer, but expected a string + --> $DIR/raw-bytes.rs:148:1 | LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a pointer, but expected a string + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:156:1 +error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + --> $DIR/raw-bytes.rs:152:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:158:1 +error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + --> $DIR/raw-bytes.rs:154:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:161:1 +error[E0080]: constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) + --> $DIR/raw-bytes.rs:157:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:164:1 +error[E0080]: constructing invalid value at .[0]: encountered 0x03, but expected a boolean + --> $DIR/raw-bytes.rs:160:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -342,16 +342,16 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:164:40 + --> $DIR/raw-bytes.rs:160:40 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:170:1 +error[E0080]: constructing invalid value at ..0: encountered 0x03, but expected a boolean + --> $DIR/raw-bytes.rs:164:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -359,16 +359,16 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3 } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:170:42 + --> $DIR/raw-bytes.rs:164:42 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:174:1 +error[E0080]: constructing invalid value at ..1[0]: encountered 0x03, but expected a boolean + --> $DIR/raw-bytes.rs:167:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..1[0]: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -376,196 +376,196 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:174:42 + --> $DIR/raw-bytes.rs:167:42 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:179:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer + --> $DIR/raw-bytes.rs:171:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:183:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer + --> $DIR/raw-bytes.rs:174:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:187:1 +error[E0080]: constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer + --> $DIR/raw-bytes.rs:177:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:190:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer + --> $DIR/raw-bytes.rs:179:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:194:1 +error[E0080]: constructing invalid value at ..: encountered 0x03, but expected a boolean + --> $DIR/raw-bytes.rs:182:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:198:1 +error[E0080]: constructing invalid value: encountered null pointer, but expected a vtable pointer + --> $DIR/raw-bytes.rs:185:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:201:1 +error[E0080]: constructing invalid value: encountered ALLOC27, but expected a vtable pointer + --> $DIR/raw-bytes.rs:187:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:206:1 +error[E0080]: constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] + --> $DIR/raw-bytes.rs:191:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] + | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 01 00 00 00 00 00 00 00 │ ........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:207:1 +error[E0080]: constructing invalid value at .[0]: encountered a value of the never type `!` + --> $DIR/raw-bytes.rs:192:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a value of the never type `!` + | ^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:208:1 +error[E0080]: constructing invalid value at .[0]: encountered a value of the never type `!` + --> $DIR/raw-bytes.rs:193:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; - | ^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a value of the never type `!` + | ^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { 01 00 00 00 00 00 00 00 2a 00 00 00 00 00 00 00 │ ........*....... } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:212:1 +error[E0080]: constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer + --> $DIR/raw-bytes.rs:196:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:215:1 +error[E0080]: constructing invalid value at .[0]: encountered a pointer, but expected an integer + --> $DIR/raw-bytes.rs:199:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........ } - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:218:1 +error[E0080]: constructing invalid value at .[0]: encountered 0x11, but expected a boolean + --> $DIR/raw-bytes.rs:202:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:222:1 +error[E0080]: constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer + --> $DIR/raw-bytes.rs:206:1 | LL | pub static S7: &[u16] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID+0x2╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:229:1 +error[E0080]: constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer + --> $DIR/raw-bytes.rs:213:1 | LL | pub static R4: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:234:1 +error[E0080]: constructing invalid value at .[0]: encountered a pointer, but expected an integer + --> $DIR/raw-bytes.rs:218:1 | LL | pub static R5: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........ } - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:239:1 +error[E0080]: constructing invalid value at .[0]: encountered 0x11, but expected a boolean + --> $DIR/raw-bytes.rs:223:1 | LL | pub static R6: &[bool] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { diff --git a/tests/ui/consts/const-eval/raw-bytes.rs b/tests/ui/consts/const-eval/raw-bytes.rs index 1a585d55a5f..58ae763e017 100644 --- a/tests/ui/consts/const-eval/raw-bytes.rs +++ b/tests/ui/consts/const-eval/raw-bytes.rs @@ -21,7 +21,7 @@ enum Enum { A = 0, } const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; -//~^ ERROR is undefined behavior +//~^ ERROR constructing invalid value #[repr(usize)] #[derive(Copy, Clone)] @@ -29,7 +29,7 @@ enum Enum2 { A = 2, } const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; -//~^ ERROR is undefined behavior +//~^ ERROR constructing invalid value #[derive(Copy, Clone)] enum Never {} @@ -43,79 +43,75 @@ enum UninhDiscriminant { D(Never), } const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; -//~^ ERROR is undefined behavior +//~^ ERROR constructing invalid value const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; -//~^ ERROR is undefined behavior +//~^ ERROR constructing invalid value // Invalid enum field content (mostly to test printing of paths for enum tuple // variants and tuples). // Need to create something which does not clash with enum layout optimizations. const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); -//~^ ERROR is undefined behavior +//~^ ERROR constructing invalid value // # Bad pointers and references const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value #[rustc_layout_scalar_valid_range_start(10)] #[rustc_layout_scalar_valid_range_end(30)] struct RestrictedRange1(u32); const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value #[rustc_layout_scalar_valid_range_start(30)] #[rustc_layout_scalar_valid_range_end(10)] struct RestrictedRange2(u32); const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const NULL_FAT_PTR: NonNull = unsafe { -//~^ ERROR it is undefined behavior to use this value + //~^ ERROR constructing invalid value let x: &dyn Send = &42; let meta = std::ptr::metadata(x); mem::transmute((0_usize, meta)) }; - const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) +//~^ ERROR constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) +//~^ ERROR constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) const NULL: &u16 = unsafe { mem::transmute(0usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value #[derive(Copy, Clone)] enum Bar {} const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; -//~^ ERROR it is undefined behavior to use this value - +//~^ ERROR constructing invalid value /// A newtype wrapper to prevent MIR generation from inserting reborrows that would affect the error /// message. @@ -139,105 +135,93 @@ struct MySlice(bool, T); type MySliceBool = MySlice<[bool]>; const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; -//~^ ERROR: it is undefined behavior to use this value +//~^ ERROR: constructing invalid value // # slice const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value // bad slice box: length too big const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR constructing invalid value // bad data *inside* the slice const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE constant - +//~^ ERROR encountered 0x03, but expected a boolean // bad: sized field is not okay const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); -//~^ ERROR it is undefined behavior to use this value -//~| NOTE constant +//~^ ERROR encountered 0x03, but expected a boolean // bad: unsized part is not okay const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); -//~^ ERROR it is undefined behavior to use this value -//~| NOTE constant +//~^ ERROR encountered 0x03, but expected a boolean // bad trait object const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE expected a vtable +//~^ ERROR expected a vtable // bad trait object const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE expected a vtable +//~^ ERROR expected a vtable // bad trait object const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE expected a vtable +//~^ ERROR expected a vtable const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE expected a vtable +//~^ ERROR expected a vtable // bad data *inside* the trait object const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE expected a boolean +//~^ ERROR expected a boolean const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE null pointer +//~^ ERROR null pointer const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE vtable +//~^ ERROR vtable // Uninhabited types -const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior -const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior -const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; //~ ERROR undefined behavior - +const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR constructing invalid value +const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR constructing invalid value +const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; //~ ERROR constructing invalid value // Reading uninitialized data pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; -//~^ ERROR: it is undefined behavior to use this value +//~^ ERROR: constructing invalid value // Reinterpret pointers as integers (UB in CTFE.) pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; -//~^ ERROR: it is undefined behavior to use this value +//~^ ERROR: constructing invalid value // Layout mismatch pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; -//~^ ERROR: it is undefined behavior to use this value +//~^ ERROR: constructing invalid value // Reading padding is not ok pub static S7: &[u16] = unsafe { - //~^ ERROR: it is undefined behavior to use this value + //~^ ERROR: constructing invalid value let ptr = (&D2 as *const Struct as *const u16).add(1); from_raw_parts(ptr, 4) }; pub static R4: &[u8] = unsafe { - //~^ ERROR: it is undefined behavior to use this value + //~^ ERROR: constructing invalid value let ptr = (&D1) as *const mem::MaybeUninit<&u32> as *const u8; from_ptr_range(ptr..ptr.add(1)) }; pub static R5: &[u8] = unsafe { - //~^ ERROR: it is undefined behavior to use this value + //~^ ERROR: constructing invalid value let ptr = &D3 as *const &u32; from_ptr_range(ptr.cast()..ptr.add(1).cast()) }; pub static R6: &[bool] = unsafe { - //~^ ERROR: it is undefined behavior to use this value + //~^ ERROR: constructing invalid value let ptr = &D0 as *const u32 as *const bool; from_ptr_range(ptr..ptr.add(4)) }; diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs index 1e76104d515..c8d1e36e88b 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.rs +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -1,15 +1,15 @@ const MISALIGNED_LOAD: () = unsafe { let mem = [0u32; 8]; let ptr = mem.as_ptr().byte_add(1); - let _val = *ptr; //~ERROR: evaluation of constant value failed - //~^NOTE: based on pointer with alignment 1, but alignment 4 is required + let _val = *ptr; //~NOTE: evaluation of constant value failed + //~^ERROR: based on pointer with alignment 1, but alignment 4 is required }; const MISALIGNED_STORE: () = unsafe { let mut mem = [0u32; 8]; let ptr = mem.as_mut_ptr().byte_add(1); - *ptr = 0; //~ERROR: evaluation of constant value failed - //~^NOTE: based on pointer with alignment 1, but alignment 4 is required + *ptr = 0; //~NOTE: evaluation of constant value failed + //~^ERROR: based on pointer with alignment 1, but alignment 4 is required }; const MISALIGNED_COPY: () = unsafe { @@ -17,9 +17,9 @@ const MISALIGNED_COPY: () = unsafe { let y = x.as_ptr().cast::(); let mut z = 123; y.copy_to_nonoverlapping(&mut z, 1); - //~^ ERROR evaluation of constant value failed + //~^ NOTE evaluation of constant value failed //~| NOTE inside `std::ptr::copy_nonoverlapping::` - //~| NOTE accessing memory with alignment 1, but alignment 4 is required + //~| ERROR accessing memory with alignment 1, but alignment 4 is required // The actual error points into the implementation of `copy_to_nonoverlapping`. }; @@ -30,15 +30,15 @@ const MISALIGNED_FIELD: () = unsafe { let mem = [0f32; 8]; let ptr = mem.as_ptr().cast::(); // Accessing an f32 field but we still require the alignment of the pointer type. - let _val = (*ptr).0; //~ERROR: evaluation of constant value failed - //~^NOTE: based on pointer with alignment 4, but alignment 16 is required + let _val = (*ptr).0; //~NOTE: evaluation of constant value failed + //~^ERROR: based on pointer with alignment 4, but alignment 16 is required }; const OOB: () = unsafe { let mem = [0u32; 1]; let ptr = mem.as_ptr().cast::(); - let _val = *ptr; //~ERROR: evaluation of constant value failed - //~^NOTE: is only 4 bytes from the end of the allocation + let _val = *ptr; //~NOTE: evaluation of constant value failed + //~^ERROR: is only 4 bytes from the end of the allocation }; fn main() {} diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr index 01a8decc93b..162485a8adf 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -1,35 +1,35 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: accessing memory based on pointer with alignment 1, but alignment 4 is required --> $DIR/raw-pointer-ub.rs:4:16 | LL | let _val = *ptr; - | ^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required + | ^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: accessing memory based on pointer with alignment 1, but alignment 4 is required --> $DIR/raw-pointer-ub.rs:11:5 | LL | *ptr = 0; - | ^^^^^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: accessing memory with alignment 1, but alignment 4 is required --> $DIR/raw-pointer-ub.rs:19:5 | LL | y.copy_to_nonoverlapping(&mut z, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment 1, but alignment 4 is required + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `std::ptr::copy_nonoverlapping::` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -error[E0080]: evaluation of constant value failed +error[E0080]: accessing memory based on pointer with alignment 4, but alignment 16 is required --> $DIR/raw-pointer-ub.rs:33:16 | LL | let _val = (*ptr).0; - | ^^^^^^^^ accessing memory based on pointer with alignment 4, but alignment 16 is required + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: attempting to access 8 bytes, but got ALLOC0 which is only 4 bytes from the end of the allocation --> $DIR/raw-pointer-ub.rs:40:16 | LL | let _val = *ptr; - | ^^^^ memory access failed: attempting to access 8 bytes, but got ALLOC0 which is only 4 bytes from the end of the allocation + | ^^^^ evaluation of constant value failed error: aborting due to 5 previous errors diff --git a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr index 18935626af1..cf460d65e8d 100644 --- a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr +++ b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/ref_to_int_match.rs:24:27 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; - | ^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr index 18935626af1..cf460d65e8d 100644 --- a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr +++ b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/ref_to_int_match.rs:24:27 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; - | ^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/ref_to_int_match.rs b/tests/ui/consts/const-eval/ref_to_int_match.rs index be9420e0215..062df685f74 100644 --- a/tests/ui/consts/const-eval/ref_to_int_match.rs +++ b/tests/ui/consts/const-eval/ref_to_int_match.rs @@ -3,9 +3,9 @@ fn main() { let n: Int = 40; match n { - 0..=10 => {}, - 10..=BAR => {}, // ok, `const` error already emitted - _ => {}, + 0..=10 => {} + 10..=BAR => {} // ok, `const` error already emitted + _ => {} } } @@ -15,11 +15,11 @@ union Foo { r: &'static u32, } -#[cfg(target_pointer_width="64")] +#[cfg(target_pointer_width = "64")] type Int = u64; -#[cfg(target_pointer_width="32")] +#[cfg(target_pointer_width = "32")] type Int = u32; const BAR: Int = unsafe { Foo { r: &42 }.f }; -//~^ ERROR constant +//~^ ERROR unable to turn pointer into integer diff --git a/tests/ui/consts/const-eval/shift_overflow.stderr b/tests/ui/consts/const-eval/shift_overflow.stderr index 901bfa10ee8..1ba2feea976 100644 --- a/tests/ui/consts/const-eval/shift_overflow.stderr +++ b/tests/ui/consts/const-eval/shift_overflow.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to shift left by `4294967296_u64`, which would overflow --> $DIR/shift_overflow.rs:3:9 | LL | X = 1 << ((u32::MAX as u64) + 1), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left by `4294967296_u64`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/transmute-const.rs b/tests/ui/consts/const-eval/transmute-const.rs index fb6cb77675f..e67406a6563 100644 --- a/tests/ui/consts/const-eval/transmute-const.rs +++ b/tests/ui/consts/const-eval/transmute-const.rs @@ -2,6 +2,6 @@ use std::mem; static FOO: bool = unsafe { mem::transmute(3u8) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR 0x03, but expected a bool fn main() {} diff --git a/tests/ui/consts/const-eval/transmute-const.stderr b/tests/ui/consts/const-eval/transmute-const.stderr index 35a5cabaa67..ed3b3df70dd 100644 --- a/tests/ui/consts/const-eval/transmute-const.stderr +++ b/tests/ui/consts/const-eval/transmute-const.stderr @@ -1,8 +1,8 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 0x03, but expected a boolean --> $DIR/transmute-const.rs:4:1 | LL | static FOO: bool = unsafe { mem::transmute(3u8) }; - | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { diff --git a/tests/ui/consts/const-eval/transmute-size-mismatch.rs b/tests/ui/consts/const-eval/transmute-size-mismatch.rs index 8a7fd8257b0..ea5cdceda88 100644 --- a/tests/ui/consts/const-eval/transmute-size-mismatch.rs +++ b/tests/ui/consts/const-eval/transmute-size-mismatch.rs @@ -19,10 +19,10 @@ const unsafe fn mir_transmute(x: T) -> U { } } -const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) }; //~ ERROR evaluation of constant value failed -//~^ NOTE transmuting from 4-byte type to 2-byte type: `i32` -> `u16` +const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) }; //~ NOTE evaluation of constant value failed +//~^ ERROR transmuting from 4-byte type to 2-byte type: `i32` -> `u16` -const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) }; //~ ERROR evaluation of constant value failed -//~^ NOTE transmuting from 2-byte type to 4-byte type: `i16` -> `u32` +const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) }; //~ NOTE evaluation of constant value failed +//~^ ERROR transmuting from 2-byte type to 4-byte type: `i16` -> `u32` fn main() {} diff --git a/tests/ui/consts/const-eval/transmute-size-mismatch.stderr b/tests/ui/consts/const-eval/transmute-size-mismatch.stderr index 888df16ec4e..f44edef0f34 100644 --- a/tests/ui/consts/const-eval/transmute-size-mismatch.stderr +++ b/tests/ui/consts/const-eval/transmute-size-mismatch.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: transmuting from 4-byte type to 2-byte type: `i32` -> `u16` --> $DIR/transmute-size-mismatch.rs:22:35 | LL | const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^ transmuting from 4-byte type to 2-byte type: `i32` -> `u16` + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `mir_transmute::` --> $DIR/transmute-size-mismatch.rs:12:13 @@ -10,11 +10,11 @@ note: inside `mir_transmute::` LL | RET = CastTransmute(x); | ^^^^^^^^^^^^^^^^^^^^^^ the failure occurred here -error[E0080]: evaluation of constant value failed +error[E0080]: transmuting from 2-byte type to 4-byte type: `i16` -> `u32` --> $DIR/transmute-size-mismatch.rs:25:36 | LL | const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) }; - | ^^^^^^^^^^^^^^^^^^^^^^ transmuting from 2-byte type to 4-byte type: `i16` -> `u32` + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `mir_transmute::` --> $DIR/transmute-size-mismatch.rs:12:13 diff --git a/tests/ui/consts/const-eval/ub-enum-overwrite.rs b/tests/ui/consts/const-eval/ub-enum-overwrite.rs index e37c25718f8..005f3c78c1d 100644 --- a/tests/ui/consts/const-eval/ub-enum-overwrite.rs +++ b/tests/ui/consts/const-eval/ub-enum-overwrite.rs @@ -9,8 +9,7 @@ const _: u8 = { // Make sure overwriting `e` uninitializes other bytes e = E::B; unsafe { *p } - //~^ ERROR evaluation of constant value failed - //~| NOTE uninitialized + //~^ ERROR uninitialized }; fn main() {} diff --git a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr index 315e865df93..4953ac5935d 100644 --- a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr +++ b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/ub-enum-overwrite.rs:11:14 | LL | unsafe { *p } - | ^^ using uninitialized data, but this operation requires initialized memory + | ^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/ub-enum.rs b/tests/ui/consts/const-eval/ub-enum.rs index ac543430da9..52fc9945068 100644 --- a/tests/ui/consts/const-eval/ub-enum.rs +++ b/tests/ui/consts/const-eval/ub-enum.rs @@ -27,13 +27,13 @@ enum Enum { const GOOD_ENUM: Enum = unsafe { mem::transmute(0usize) }; const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; -//~^ ERROR is undefined behavior +//~^ ERROR expected a valid enum tag const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR unable to turn pointer into integer const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR unable to turn pointer into integer // # simple enum with discriminant 2 @@ -45,12 +45,12 @@ enum Enum2 { } const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; -//~^ ERROR is undefined behavior +//~^ ERROR expected a valid enum tag const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR unable to turn pointer into integer // something wrapping the enum so that we test layout first, not enum const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR unable to turn pointer into integer // Undef enum discriminant. #[repr(C)] @@ -58,13 +58,12 @@ union MaybeUninit { uninit: (), init: T, } -const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; -//~^ ERROR evaluation of constant value failed -//~| NOTE uninitialized +const BAD_ENUM2_UNDEF: Enum2 = unsafe { MaybeUninit { uninit: () }.init }; +//~^ ERROR uninitialized // Pointer value in an enum with a niche that is not just 0. const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR unable to turn pointer into integer // # valid discriminant for uninhabited variant @@ -81,9 +80,9 @@ const GOOD_INHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(0u8) const GOOD_INHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(2u8) }; // variant C const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; -//~^ ERROR is undefined behavior +//~^ ERROR uninhabited enum variant const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; -//~^ ERROR is undefined behavior +//~^ ERROR uninhabited enum variant // # other @@ -91,20 +90,21 @@ const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) // variants and tuples). // Need to create something which does not clash with enum layout optimizations. const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); -//~^ ERROR is undefined behavior +//~^ ERROR expected a valid unicode scalar // All variants are uninhabited but also have data. // Use `0` as constant to make behavior endianness-independent. const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR uninhabited enum variant const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR uninhabited enum variant const TEST_ICE_89765: () = { // This is a regression test for https://github.com/rust-lang/rust/issues/89765. - unsafe { std::mem::discriminant(&*(&() as *const () as *const Never)); }; - //~^ ERROR evaluation of constant value failed + unsafe { + std::mem::discriminant(&*(&() as *const () as *const Never)); + //~^ ERROR uninhabited enum variant + }; }; -fn main() { -} +fn main() {} diff --git a/tests/ui/consts/const-eval/ub-enum.stderr b/tests/ui/consts/const-eval/ub-enum.stderr index faec412b004..9964d8e1a9c 100644 --- a/tests/ui/consts/const-eval/ub-enum.stderr +++ b/tests/ui/consts/const-eval/ub-enum.stderr @@ -1,126 +1,126 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered 0x01, but expected a valid enum tag --> $DIR/ub-enum.rs:29:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x01, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/ub-enum.rs:32:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/ub-enum.rs:35:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered 0x0, but expected a valid enum tag --> $DIR/ub-enum.rs:47:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/ub-enum.rs:49:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/ub-enum.rs:52:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:61:42 +error[E0080]: using uninitialized data, but this operation requires initialized memory + --> $DIR/ub-enum.rs:61:41 | -LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | const BAD_ENUM2_UNDEF: Enum2 = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:66:1 +error[E0080]: unable to turn pointer into integer + --> $DIR/ub-enum.rs:65:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:83:1 +error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant + --> $DIR/ub-enum.rs:82:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:85:1 +error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant + --> $DIR/ub-enum.rs:84:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:93:1 +error[E0080]: constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + --> $DIR/ub-enum.rs:92:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:98:77 +error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant + --> $DIR/ub-enum.rs:97:77 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:100:77 +error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant + --> $DIR/ub-enum.rs:99:77 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:105:14 +error[E0080]: read discriminant of an uninhabited enum variant + --> $DIR/ub-enum.rs:105:9 | -LL | unsafe { std::mem::discriminant(&*(&() as *const () as *const Never)); }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ read discriminant of an uninhabited enum variant +LL | std::mem::discriminant(&*(&() as *const () as *const Never)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `discriminant::` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr index 5c47cbfdf3b..86d6f8c52bc 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr @@ -1,63 +1,63 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered ALLOC1, but expected a vtable pointer --> $DIR/ub-incorrect-vtable.rs:18:1 | LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──╼╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:23:1 +error[E0080]: constructing invalid value: encountered ALLOC3, but expected a vtable pointer + --> $DIR/ub-incorrect-vtable.rs:22:1 | LL | const INVALID_VTABLE_SIZE: &dyn Trait = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC2╼ ╾ALLOC3╼ │ ╾──╼╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:33:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC5, but expected a vtable pointer + --> $DIR/ub-incorrect-vtable.rs:31:1 | LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC4╼ ╾ALLOC5╼ │ ╾──╼╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:38:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC7, but expected a vtable pointer + --> $DIR/ub-incorrect-vtable.rs:35:1 | LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC6╼ ╾ALLOC7╼ │ ╾──╼╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:44:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC9, but expected a vtable pointer + --> $DIR/ub-incorrect-vtable.rs:40:1 | LL | const INVALID_VTABLE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC8╼ ╾ALLOC9╼ │ ╾──╼╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:91:1 +error[E0080]: constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) + --> $DIR/ub-incorrect-vtable.rs:86:1 | LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; - | ^^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr index f400073aca2..a9518216dbd 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr @@ -1,63 +1,63 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered ALLOC1, but expected a vtable pointer --> $DIR/ub-incorrect-vtable.rs:18:1 | LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:23:1 +error[E0080]: constructing invalid value: encountered ALLOC3, but expected a vtable pointer + --> $DIR/ub-incorrect-vtable.rs:22:1 | LL | const INVALID_VTABLE_SIZE: &dyn Trait = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC2╼ ╾ALLOC3╼ │ ╾──────╼╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:33:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC5, but expected a vtable pointer + --> $DIR/ub-incorrect-vtable.rs:31:1 | LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC4╼ ╾ALLOC5╼ │ ╾──────╼╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:38:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC7, but expected a vtable pointer + --> $DIR/ub-incorrect-vtable.rs:35:1 | LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC6╼ ╾ALLOC7╼ │ ╾──────╼╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:44:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC9, but expected a vtable pointer + --> $DIR/ub-incorrect-vtable.rs:40:1 | LL | const INVALID_VTABLE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC8╼ ╾ALLOC9╼ │ ╾──────╼╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:91:1 +error[E0080]: constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) + --> $DIR/ub-incorrect-vtable.rs:86:1 | LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; - | ^^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.rs b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs index 30c0ae3bb5a..4185b0261b2 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.rs +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs @@ -17,13 +17,11 @@ trait Trait {} const INVALID_VTABLE_ALIGNMENT: &dyn Trait = unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; -//~^^ ERROR it is undefined behavior to use this value -//~| NOTE vtable +//~^^ ERROR vtable const INVALID_VTABLE_SIZE: &dyn Trait = unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; -//~^^ ERROR it is undefined behavior to use this value -//~| NOTE vtable +//~^^ ERROR vtable #[repr(transparent)] struct W(T); @@ -32,19 +30,16 @@ fn drop_me(_: *mut usize) {} const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) }; -//~^^ ERROR it is undefined behavior to use this value -//~| NOTE expected a vtable pointer +//~^^ ERROR expected a vtable pointer const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) }; -//~^^ ERROR it is undefined behavior to use this value -//~| NOTE expected a vtable pointer +//~^^ ERROR expected a vtable pointer // Even if the vtable has a fn ptr and a reasonable size+align, it still does not work. const INVALID_VTABLE_UB: W<&dyn Trait> = unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1usize))) }; -//~^^ ERROR it is undefined behavior to use this value -//~| NOTE expected a vtable pointer +//~^^ ERROR expected a vtable pointer // Trying to access the data in a vtable does not work, either. @@ -89,8 +84,7 @@ union Transmute { const FOO: &dyn Bar = &Foo { foo: 128, bar: false }; const G: Wide = unsafe { Transmute { t: FOO }.u }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE encountered a dangling reference +//~^ ERROR encountered a dangling reference // (it is dangling because vtables do not contain memory that can be dereferenced) fn main() {} diff --git a/tests/ui/consts/const-eval/ub-int-array.rs b/tests/ui/consts/const-eval/ub-int-array.rs index 169ac7f1519..eebbccaa7c1 100644 --- a/tests/ui/consts/const-eval/ub-int-array.rs +++ b/tests/ui/consts/const-eval/ub-int-array.rs @@ -18,8 +18,7 @@ impl MaybeUninit { } const UNINIT_INT_0: [u32; 3] = unsafe { - //~^ ERROR it is undefined behavior to use this value - //~| NOTE invalid value at [0] + //~^ ERROR invalid value at [0] mem::transmute([ MaybeUninit { uninit: () }, // Constants chosen to achieve endianness-independent hex dump. @@ -28,8 +27,7 @@ const UNINIT_INT_0: [u32; 3] = unsafe { ]) }; const UNINIT_INT_1: [u32; 3] = unsafe { - //~^ ERROR it is undefined behavior to use this value - //~| NOTE invalid value at [1] + //~^ ERROR invalid value at [1] mem::transmute([ MaybeUninit::new(0u8), MaybeUninit::new(0u8), @@ -46,8 +44,7 @@ const UNINIT_INT_1: [u32; 3] = unsafe { ]) }; const UNINIT_INT_2: [u32; 3] = unsafe { - //~^ ERROR it is undefined behavior to use this value - //~| NOTE invalid value at [2] + //~^ ERROR invalid value at [2] mem::transmute([ MaybeUninit::new(0u8), MaybeUninit::new(0u8), diff --git a/tests/ui/consts/const-eval/ub-int-array.stderr b/tests/ui/consts/const-eval/ub-int-array.stderr index d6ef9bcfeba..10eb7c46c92 100644 --- a/tests/ui/consts/const-eval/ub-int-array.stderr +++ b/tests/ui/consts/const-eval/ub-int-array.stderr @@ -1,30 +1,30 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at [0]: encountered uninitialized memory, but expected an integer --> $DIR/ub-int-array.rs:20:1 | LL | const UNINIT_INT_0: [u32; 3] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 12, align: 4) { __ __ __ __ 11 11 11 11 22 22 22 22 │ ░░░░...."""" } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-int-array.rs:30:1 +error[E0080]: constructing invalid value at [1]: encountered uninitialized memory, but expected an integer + --> $DIR/ub-int-array.rs:29:1 | LL | const UNINIT_INT_1: [u32; 3] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [1]: encountered uninitialized memory, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 12, align: 4) { 00 00 00 00 01 __ 01 01 02 02 __ 02 │ .....░....░. } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-int-array.rs:48:1 +error[E0080]: constructing invalid value at [2]: encountered uninitialized memory, but expected an integer + --> $DIR/ub-int-array.rs:46:1 | LL | const UNINIT_INT_2: [u32; 3] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [2]: encountered uninitialized memory, but expected an integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 12, align: 4) { diff --git a/tests/ui/consts/const-eval/ub-invalid-values.rs b/tests/ui/consts/const-eval/ub-invalid-values.rs index c0b68d7619a..e5d387fa7cc 100644 --- a/tests/ui/consts/const-eval/ub-invalid-values.rs +++ b/tests/ui/consts/const-eval/ub-invalid-values.rs @@ -5,8 +5,8 @@ const fn bool_cast(ptr: *const bool) { unsafe { const _: () = { let v = 3_u8; - bool_cast(&v as *const u8 as *const bool); //~ ERROR: evaluation of constant value failed - //~^ NOTE interpreting an invalid 8-bit value as a bool + bool_cast(&v as *const u8 as *const bool); //~ NOTE: evaluation of constant value failed + //~^ ERROR interpreting an invalid 8-bit value as a bool }; fn main() {} diff --git a/tests/ui/consts/const-eval/ub-invalid-values.stderr b/tests/ui/consts/const-eval/ub-invalid-values.stderr index 76952c1f1a3..ceee06f05a4 100644 --- a/tests/ui/consts/const-eval/ub-invalid-values.stderr +++ b/tests/ui/consts/const-eval/ub-invalid-values.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: interpreting an invalid 8-bit value as a bool: 0x03 --> $DIR/ub-invalid-values.rs:8:5 | LL | bool_cast(&v as *const u8 as *const bool); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ interpreting an invalid 8-bit value as a bool: 0x03 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `bool_cast` --> $DIR/ub-invalid-values.rs:2:16 diff --git a/tests/ui/consts/const-eval/ub-nonnull.rs b/tests/ui/consts/const-eval/ub-nonnull.rs index 8ae913db1e4..91646842624 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.rs +++ b/tests/ui/consts/const-eval/ub-nonnull.rs @@ -14,19 +14,19 @@ const NON_NULL: NonNull = unsafe { mem::transmute(1usize) }; const NON_NULL_PTR: NonNull = unsafe { mem::transmute(&1) }; const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR invalid value const OUT_OF_BOUNDS_PTR: NonNull = { unsafe { let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle // Use address-of-element for pointer arithmetic. This could wrap around to null! - let out_of_bounds_ptr = &ptr[255]; //~ ERROR evaluation of constant value failed + let out_of_bounds_ptr = &ptr[255]; //~ ERROR in-bounds pointer arithmetic failed mem::transmute(out_of_bounds_ptr) } }; const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR invalid value const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR invalid value #[repr(C)] union MaybeUninit { @@ -34,8 +34,7 @@ union MaybeUninit { init: T, } const UNINIT: NonZero = unsafe { MaybeUninit { uninit: () }.init }; -//~^ ERROR evaluation of constant value failed -//~| NOTE uninitialized +//~^ ERROR uninitialized // Also test other uses of rustc_layout_scalar_valid_range_start @@ -43,16 +42,16 @@ const UNINIT: NonZero = unsafe { MaybeUninit { uninit: () }.init }; #[rustc_layout_scalar_valid_range_end(30)] struct RestrictedRange1(u32); const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR invalid value #[rustc_layout_scalar_valid_range_start(30)] #[rustc_layout_scalar_valid_range_end(10)] struct RestrictedRange2(u32); const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR invalid value const NULL_FAT_PTR: NonNull = unsafe { -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR invalid value let x: &dyn Send = &42; let meta = std::ptr::metadata(x); mem::transmute((0_usize, meta)) diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index 75dd0443ca4..0919c9906f7 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -1,75 +1,75 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 0, but expected something greater or equal to 1 --> $DIR/ub-nonnull.rs:16:1 | LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 255 bytes, but got ALLOC1 which is only 1 byte from the end of the allocation --> $DIR/ub-nonnull.rs:22:29 | LL | let out_of_bounds_ptr = &ptr[255]; - | ^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 255 bytes, but got ALLOC1 which is only 1 byte from the end of the allocation + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 --> $DIR/ub-nonnull.rs:26:1 | LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 --> $DIR/ub-nonnull.rs:28:1 | LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed +error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/ub-nonnull.rs:36:38 | LL | const UNINIT: NonZero = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:45:1 +error[E0080]: constructing invalid value: encountered 42, but expected something in the range 10..=30 + --> $DIR/ub-nonnull.rs:44:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:51:1 +error[E0080]: constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 + --> $DIR/ub-nonnull.rs:50:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:54:1 +error[E0080]: constructing invalid value: encountered 0, but expected something greater or equal to 1 + --> $DIR/ub-nonnull.rs:53:1 | LL | const NULL_FAT_PTR: NonNull = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.rs b/tests/ui/consts/const-eval/ub-ref-ptr.rs index 988e6c62e34..64b48939be6 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.rs +++ b/tests/ui/consts/const-eval/ub-ref-ptr.rs @@ -15,57 +15,53 @@ union MaybeUninit { } const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) +//~^ ERROR constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) +//~^ ERROR constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) const NULL: &u16 = unsafe { mem::transmute(0usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR invalid value const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR invalid value // It is very important that we reject this: We do promote `&(4 * REF_AS_USIZE)`, // but that would fail to compile; so we ended up breaking user code that would // have worked fine had we not promoted. const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR unable to turn pointer into integer const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; -//~^ ERROR evaluation of constant value failed +//~^ ERROR unable to turn pointer into integer const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR unable to turn pointer into integer const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR invalid value const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR invalid value const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; -//~^ ERROR evaluation of constant value failed -//~| NOTE uninitialized +//~^ ERROR uninitialized const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR invalid value const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; -//~^ ERROR evaluation of constant value failed -//~| NOTE uninitialized +//~^ ERROR uninitialized const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR invalid value const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR invalid value const UNALIGNED_READ: () = unsafe { let x = &[0u8; 4]; let ptr = x.as_ptr().cast::(); - ptr.read(); //~ ERROR evaluation of constant value failed + ptr.read(); //~ ERROR accessing memory }; diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index cfec1a42f28..31a216916d5 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -1,158 +1,158 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) --> $DIR/ub-ref-ptr.rs:17:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref-ptr.rs:21:1 +error[E0080]: constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) + --> $DIR/ub-ref-ptr.rs:20:1 | LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref-ptr.rs:25:1 +error[E0080]: constructing invalid value: encountered a null reference + --> $DIR/ub-ref-ptr.rs:23:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference + | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref-ptr.rs:28:1 +error[E0080]: constructing invalid value: encountered a null box + --> $DIR/ub-ref-ptr.rs:26:1 | LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box + | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-ref-ptr.rs:35:1 +error[E0080]: unable to turn pointer into integer + --> $DIR/ub-ref-ptr.rs:33:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/ub-ref-ptr.rs:38:39 +error[E0080]: unable to turn pointer into integer + --> $DIR/ub-ref-ptr.rs:36:39 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported note: erroneous constant encountered - --> $DIR/ub-ref-ptr.rs:38:38 + --> $DIR/ub-ref-ptr.rs:36:38 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: evaluation of constant value failed - --> $DIR/ub-ref-ptr.rs:41:86 +error[E0080]: unable to turn pointer into integer + --> $DIR/ub-ref-ptr.rs:39:86 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; - | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported note: erroneous constant encountered - --> $DIR/ub-ref-ptr.rs:41:85 + --> $DIR/ub-ref-ptr.rs:39:85 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; | ^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref-ptr.rs:44:1 +error[E0080]: constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) + --> $DIR/ub-ref-ptr.rs:42:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref-ptr.rs:47:1 +error[E0080]: constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) + --> $DIR/ub-ref-ptr.rs:45:1 | LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-ref-ptr.rs:50:41 +error[E0080]: using uninitialized data, but this operation requires initialized memory + --> $DIR/ub-ref-ptr.rs:48:41 | LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref-ptr.rs:54:1 +error[E0080]: constructing invalid value: encountered null pointer, but expected a function pointer + --> $DIR/ub-ref-ptr.rs:51:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-ref-ptr.rs:56:38 +error[E0080]: using uninitialized data, but this operation requires initialized memory + --> $DIR/ub-ref-ptr.rs:53:38 | LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref-ptr.rs:59:1 +error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected a function pointer + --> $DIR/ub-ref-ptr.rs:55:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref-ptr.rs:61:1 +error[E0080]: constructing invalid value: encountered ALLOC2, but expected a function pointer + --> $DIR/ub-ref-ptr.rs:57:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC2, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-ref-ptr.rs:68:5 +error[E0080]: accessing memory based on pointer with alignment 1, but alignment 4 is required + --> $DIR/ub-ref-ptr.rs:64:5 | LL | ptr.read(); - | ^^^^^^^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required + | ^^^^^^^^^^ evaluation of constant value failed error: aborting due to 15 previous errors diff --git a/tests/ui/consts/const-eval/ub-uninhabit.rs b/tests/ui/consts/const-eval/ub-uninhabit.rs index 3a5e291d5df..188ad768a0e 100644 --- a/tests/ui/consts/const-eval/ub-uninhabit.rs +++ b/tests/ui/consts/const-eval/ub-uninhabit.rs @@ -6,8 +6,7 @@ #![feature(core_intrinsics)] #![feature(never_type)] -use std::intrinsics; -use std::mem; +use std::{intrinsics, mem}; #[derive(Copy, Clone)] enum Bar {} @@ -19,25 +18,19 @@ union MaybeUninit { } const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; -//~^ ERROR evaluation of constant value failed -//~| NOTE constructing invalid value +//~^ ERROR constructing invalid value const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE constructing invalid value +//~^ ERROR constructing invalid value const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; -//~^ ERROR evaluation of constant value failed -//~| NOTE constructing invalid value - +//~^ ERROR constructing invalid value const READ_NEVER: () = unsafe { let mem = [0u32; 8]; let ptr = mem.as_ptr().cast::(); let _val = intrinsics::read_via_copy(ptr); - //~^ ERROR evaluation of constant value failed - //~| NOTE constructing invalid value + //~^ ERROR constructing invalid value }; - fn main() {} diff --git a/tests/ui/consts/const-eval/ub-uninhabit.stderr b/tests/ui/consts/const-eval/ub-uninhabit.stderr index 9d3f93279e5..38779ea164b 100644 --- a/tests/ui/consts/const-eval/ub-uninhabit.stderr +++ b/tests/ui/consts/const-eval/ub-uninhabit.stderr @@ -1,31 +1,31 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/ub-uninhabit.rs:21:35 +error[E0080]: constructing invalid value: encountered a value of uninhabited type `Bar` + --> $DIR/ub-uninhabit.rs:20:35 | LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type `Bar` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-uninhabit.rs:25:1 +error[E0080]: constructing invalid value: encountered a reference pointing to uninhabited type Bar + --> $DIR/ub-uninhabit.rs:23:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-uninhabit.rs:29:42 +error[E0080]: constructing invalid value at [0]: encountered a value of uninhabited type `Bar` + --> $DIR/ub-uninhabit.rs:26:42 | LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type `Bar` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/ub-uninhabit.rs:37:16 +error[E0080]: constructing invalid value: encountered a value of the never type `!` + --> $DIR/ub-uninhabit.rs:32:16 | LL | let _val = intrinsics::read_via_copy(ptr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of the never type `!` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 4 previous errors diff --git a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr index 5342fea66bd..ecd1c768c28 100644 --- a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr @@ -1,8 +1,8 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at ...: encountered a null reference --> $DIR/ub-upvars.rs:6:1 | LL | const BAD_UPVAR: &dyn FnOnce() = &{ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ...: encountered a null reference + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { diff --git a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr index a2496dfc287..108dfe6b27b 100644 --- a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr @@ -1,8 +1,8 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at ...: encountered a null reference --> $DIR/ub-upvars.rs:6:1 | LL | const BAD_UPVAR: &dyn FnOnce() = &{ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ...: encountered a null reference + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { diff --git a/tests/ui/consts/const-eval/ub-upvars.rs b/tests/ui/consts/const-eval/ub-upvars.rs index 817511180be..19722282984 100644 --- a/tests/ui/consts/const-eval/ub-upvars.rs +++ b/tests/ui/consts/const-eval/ub-upvars.rs @@ -3,7 +3,7 @@ use std::mem; -const BAD_UPVAR: &dyn FnOnce() = &{ //~ ERROR it is undefined behavior to use this value +const BAD_UPVAR: &dyn FnOnce() = &{ //~ ERROR null reference let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) }; let another_var = 13; move || { let _ = bad_ref; let _ = another_var; } diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.rs b/tests/ui/consts/const-eval/ub-wide-ptr.rs index 4b9bbb8066d..86235897e7e 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.rs +++ b/tests/ui/consts/const-eval/ub-wide-ptr.rs @@ -37,74 +37,69 @@ type MySliceBool = MySlice<[bool]>; const STR_VALID: &str = unsafe { mem::transmute((&42u8, 1usize)) }; // bad str const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR encountered a dangling reference (going beyond the bounds of its allocation) const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR slice is bigger than largest supported object // bad str const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR unable to turn pointer into integer // bad str in user-defined unsized type const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR unable to turn pointer into integer const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR slice is bigger than largest supported object // uninitialized byte const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR uninitialized memory, but expected a string // uninitialized byte in user-defined str-like const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR uninitialized memory, but expected a string // # slice // OK const SLICE_VALID: &[u8] = unsafe { mem::transmute((&42u8, 1usize)) }; // bad slice: length uninit const SLICE_LENGTH_UNINIT: &[u8] = unsafe { -//~^ ERROR evaluation of constant value failed -//~| NOTE uninitialized +//~^ ERROR uninitialized let uninit_len = MaybeUninit:: { uninit: () }; mem::transmute((42, uninit_len)) }; // bad slice: length too big const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR dangling reference (going beyond the bounds of its allocation) // bad slice: length computation overflows const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR slice is bigger than largest supported object // bad slice: length not an int const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR unable to turn pointer into integer // bad slice box: length too big const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR dangling box (going beyond the bounds of its allocation) // bad slice box: length not an int const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR unable to turn pointer into integer // bad data *inside* the slice const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE constant +//~^ ERROR 0x03, but expected a boolean // good MySliceBool const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]); // bad: sized field is not okay const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); -//~^ ERROR it is undefined behavior to use this value -//~| NOTE constant +//~^ ERROR 0x03, but expected a boolean // bad: unsized part is not okay const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); -//~^ ERROR it is undefined behavior to use this value -//~| NOTE constant +//~^ ERROR 0x03, but expected a boolean // # raw slice const RAW_SLICE_VALID: *const [u8] = unsafe { mem::transmute((&42u8, 1usize)) }; // ok const RAW_SLICE_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, 999usize)) }; // ok because raw const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, usize::MAX)) }; // ok because raw const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { -//~^ ERROR evaluation of constant value failed -//~| NOTE uninitialized +//~^ ERROR uninitialized let uninit_len = MaybeUninit:: { uninit: () }; mem::transmute((42, uninit_len)) }; @@ -112,41 +107,31 @@ const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { // # trait object // bad trait object const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE vtable +//~^ ERROR vtable // bad trait object const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE vtable +//~^ ERROR vtable // bad trait object const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE vtable +//~^ ERROR vtable const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE vtable +//~^ ERROR vtable const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE vtable +//~^ ERROR vtable const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE vtable +//~^ ERROR vtable const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE vtable +//~^ ERROR vtable // bad data *inside* the trait object const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE expected a boolean +//~^ ERROR expected a boolean // # raw trait object const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE null pointer +//~^ ERROR null pointer const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE vtable +//~^ ERROR vtable const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) } as *const dyn Trait; // ok because raw // Officially blessed way to get the vtable const DYN_METADATA: ptr::DynMetadata = ptr::metadata::(ptr::null::()); @@ -154,13 +139,11 @@ const DYN_METADATA: ptr::DynMetadata = ptr::metadata::(ptr:: static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe { mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - //~^^ ERROR it is undefined behavior to use this value - //~| NOTE null pointer + //~^^ ERROR null pointer }; static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) - //~^^ ERROR it is undefined behavior to use this value - //~| NOTE vtable + //~^^ ERROR vtable }; fn main() {} diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index 92f0029a5b3..7b7f013446f 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -1,138 +1,138 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/ub-wide-ptr.rs:39:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/ub-wide-ptr.rs:41:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/ub-wide-ptr.rs:44:1 | LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/ub-wide-ptr.rs:47:1 | LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/ub-wide-ptr.rs:49:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected a string --> $DIR/ub-wide-ptr.rs:53:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized memory, but expected a string + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at ..0: encountered uninitialized memory, but expected a string --> $DIR/ub-wide-ptr.rs:56:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered uninitialized memory, but expected a string + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed +error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/ub-wide-ptr.rs:63:1 | LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:70:1 +error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + --> $DIR/ub-wide-ptr.rs:69:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:73:1 +error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + --> $DIR/ub-wide-ptr.rs:72:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:76:1 +error[E0080]: unable to turn pointer into integer + --> $DIR/ub-wide-ptr.rs:75:1 | LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:79:1 +error[E0080]: constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) + --> $DIR/ub-wide-ptr.rs:78:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:82:1 +error[E0080]: unable to turn pointer into integer + --> $DIR/ub-wide-ptr.rs:81:1 | LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:86:1 +error[E0080]: constructing invalid value at .[0]: encountered 0x03, but expected a boolean + --> $DIR/ub-wide-ptr.rs:85:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -140,16 +140,16 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; } note: erroneous constant encountered - --> $DIR/ub-wide-ptr.rs:86:40 + --> $DIR/ub-wide-ptr.rs:85:40 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:93:1 +error[E0080]: constructing invalid value at ..0: encountered 0x03, but expected a boolean + --> $DIR/ub-wide-ptr.rs:91:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -157,16 +157,16 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3 } note: erroneous constant encountered - --> $DIR/ub-wide-ptr.rs:93:42 + --> $DIR/ub-wide-ptr.rs:91:42 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:97:1 +error[E0080]: constructing invalid value at ..1[0]: encountered 0x03, but expected a boolean + --> $DIR/ub-wide-ptr.rs:94:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..1[0]: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -174,143 +174,143 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran } note: erroneous constant encountered - --> $DIR/ub-wide-ptr.rs:97:42 + --> $DIR/ub-wide-ptr.rs:94:42 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:105:1 +error[E0080]: using uninitialized data, but this operation requires initialized memory + --> $DIR/ub-wide-ptr.rs:101:1 | LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:114:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC12, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:109:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC12, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:118:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC14, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:112:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC14, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:122:1 +error[E0080]: constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:115:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:125:1 +error[E0080]: constructing invalid value: encountered ALLOC17, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:117:1 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC17, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:128:1 +error[E0080]: constructing invalid value: encountered ALLOC19, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:119:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC19, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:131:1 +error[E0080]: constructing invalid value: encountered ALLOC21, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:121:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC21, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:134:1 +error[E0080]: constructing invalid value at .0: encountered ALLOC23, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:123:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC23, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:139:1 +error[E0080]: constructing invalid value at ..: encountered 0x03, but expected a boolean + --> $DIR/ub-wide-ptr.rs:127:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:144:1 +error[E0080]: constructing invalid value: encountered null pointer, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:131:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:147:1 +error[E0080]: constructing invalid value: encountered ALLOC28, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:133:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC28, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:155:1 +error[E0080]: constructing invalid value: encountered null pointer, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:140:1 | LL | static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:160:1 +error[E0080]: constructing invalid value: encountered ALLOC31, but expected a vtable pointer + --> $DIR/ub-wide-ptr.rs:144:1 | LL | static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC31, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { diff --git a/tests/ui/consts/const-eval/ub-write-through-immutable.rs b/tests/ui/consts/const-eval/ub-write-through-immutable.rs index 795ac602a1c..28c7a617a4d 100644 --- a/tests/ui/consts/const-eval/ub-write-through-immutable.rs +++ b/tests/ui/consts/const-eval/ub-write-through-immutable.rs @@ -1,21 +1,19 @@ //! Ensure we catch UB due to writing through a shared reference. #![allow(invalid_reference_casting)] -use std::mem; use std::cell::UnsafeCell; +use std::mem; const WRITE_AFTER_CAST: () = unsafe { let mut x = 0; let ptr = &x as *const i32 as *mut i32; - *ptr = 0; //~ERROR: evaluation of constant value failed - //~| NOTE immutable + *ptr = 0; //~ERROR: immutable }; const WRITE_AFTER_TRANSMUTE: () = unsafe { let mut x = 0; let ptr: *mut i32 = mem::transmute(&x); - *ptr = 0; //~ERROR: evaluation of constant value failed - //~| NOTE immutable + *ptr = 0; //~ERROR: immutable }; // it's okay when there is interior mutability; diff --git a/tests/ui/consts/const-eval/ub-write-through-immutable.stderr b/tests/ui/consts/const-eval/ub-write-through-immutable.stderr index d30df33bc55..a7b4aa5fac8 100644 --- a/tests/ui/consts/const-eval/ub-write-through-immutable.stderr +++ b/tests/ui/consts/const-eval/ub-write-through-immutable.stderr @@ -1,14 +1,14 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: writing through a pointer that was derived from a shared (immutable) reference --> $DIR/ub-write-through-immutable.rs:10:5 | LL | *ptr = 0; - | ^^^^^^^^ writing through a pointer that was derived from a shared (immutable) reference + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/ub-write-through-immutable.rs:17:5 +error[E0080]: writing through a pointer that was derived from a shared (immutable) reference + --> $DIR/ub-write-through-immutable.rs:16:5 | LL | *ptr = 0; - | ^^^^^^^^ writing through a pointer that was derived from a shared (immutable) reference + | ^^^^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/union-const-eval-field.rs b/tests/ui/consts/const-eval/union-const-eval-field.rs index 55e9abe72e0..0ad94eee7f4 100644 --- a/tests/ui/consts/const-eval/union-const-eval-field.rs +++ b/tests/ui/consts/const-eval/union-const-eval-field.rs @@ -26,8 +26,7 @@ const fn read_field2() -> Field2 { const fn read_field3() -> Field3 { const FIELD3: Field3 = unsafe { UNION.field3 }; - //~^ ERROR evaluation of constant value failed - //~| NOTE uninitialized + //~^ ERROR uninitialized FIELD3 } diff --git a/tests/ui/consts/const-eval/union-const-eval-field.stderr b/tests/ui/consts/const-eval/union-const-eval-field.stderr index 4fd6b80381c..060e3e314aa 100644 --- a/tests/ui/consts/const-eval/union-const-eval-field.stderr +++ b/tests/ui/consts/const-eval/union-const-eval-field.stderr @@ -1,17 +1,17 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/union-const-eval-field.rs:28:37 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; - | ^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^ evaluation of constant value failed note: erroneous constant encountered - --> $DIR/union-const-eval-field.rs:31:5 + --> $DIR/union-const-eval-field.rs:30:5 | LL | FIELD3 | ^^^^^^ note: erroneous constant encountered - --> $DIR/union-const-eval-field.rs:31:5 + --> $DIR/union-const-eval-field.rs:30:5 | LL | FIELD3 | ^^^^^^ diff --git a/tests/ui/consts/const-eval/union-ice.rs b/tests/ui/consts/const-eval/union-ice.rs index 8ce5f6d89a8..7a4909e8ce2 100644 --- a/tests/ui/consts/const-eval/union-ice.rs +++ b/tests/ui/consts/const-eval/union-ice.rs @@ -12,14 +12,12 @@ union DummyUnion { const UNION: DummyUnion = DummyUnion { field1: 1065353216 }; const FIELD3: Field3 = unsafe { UNION.field3 }; -//~^ ERROR evaluation of constant value failed -//~| NOTE uninitialized +//~^ ERROR uninitialized const FIELD_PATH: Struct = Struct { a: 42, b: unsafe { UNION.field3 }, - //~^ ERROR evaluation of constant value failed - //~| NOTE uninitialized + //~^ ERROR uninitialized }; struct Struct { @@ -31,8 +29,7 @@ const FIELD_PATH2: Struct2 = Struct2 { b: [ 21, unsafe { UNION.field3 }, - //~^ ERROR evaluation of constant value failed - //~| NOTE uninitialized + //~^ ERROR uninitialized 23, 24, ], @@ -44,5 +41,4 @@ struct Struct2 { a: u8, } -fn main() { -} +fn main() {} diff --git a/tests/ui/consts/const-eval/union-ice.stderr b/tests/ui/consts/const-eval/union-ice.stderr index bd39a05510b..a68f6c02945 100644 --- a/tests/ui/consts/const-eval/union-ice.stderr +++ b/tests/ui/consts/const-eval/union-ice.stderr @@ -1,20 +1,20 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/union-ice.rs:14:33 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; - | ^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/union-ice.rs:20:17 +error[E0080]: using uninitialized data, but this operation requires initialized memory + --> $DIR/union-ice.rs:19:17 | LL | b: unsafe { UNION.field3 }, - | ^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/union-ice.rs:33:18 +error[E0080]: using uninitialized data, but this operation requires initialized memory + --> $DIR/union-ice.rs:31:18 | LL | unsafe { UNION.field3 }, - | ^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const-eval/union-ub.32bit.stderr b/tests/ui/consts/const-eval/union-ub.32bit.stderr index 38ded4d65cf..2cc3f8bdaac 100644 --- a/tests/ui/consts/const-eval/union-ub.32bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.32bit.stderr @@ -1,19 +1,19 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 0x2a, but expected a boolean --> $DIR/union-ub.rs:33:1 | -LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool}; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x2a, but expected a boolean +LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool }; + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 2a │ * } -error[E0080]: evaluation of constant value failed +error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/union-ub.rs:35:36 | -LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/union-ub.64bit.stderr b/tests/ui/consts/const-eval/union-ub.64bit.stderr index 38ded4d65cf..2cc3f8bdaac 100644 --- a/tests/ui/consts/const-eval/union-ub.64bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.64bit.stderr @@ -1,19 +1,19 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 0x2a, but expected a boolean --> $DIR/union-ub.rs:33:1 | -LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool}; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x2a, but expected a boolean +LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool }; + | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 2a │ * } -error[E0080]: evaluation of constant value failed +error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/union-ub.rs:35:36 | -LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/union-ub.rs b/tests/ui/consts/const-eval/union-ub.rs index 7d8fd7446a0..0fa5d312856 100644 --- a/tests/ui/consts/const-eval/union-ub.rs +++ b/tests/ui/consts/const-eval/union-ub.rs @@ -30,15 +30,13 @@ union Bar { } // the value is not valid for bools -const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool}; -//~^ ERROR it is undefined behavior to use this value -const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool}; -//~^ ERROR evaluation of constant value failed -//~| NOTE uninitialized +const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool }; +//~^ ERROR invalid value +const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; +//~^ ERROR uninitialized // The value is not valid for any union variant, but that's fine // unions are just a convenient way to transmute bits around const BAD_UNION: Foo = unsafe { Bar { u8: 42 }.foo }; - fn main() {} diff --git a/tests/ui/consts/const-eval/unused-broken-const.rs b/tests/ui/consts/const-eval/unused-broken-const.rs index f7e229aa980..60206362665 100644 --- a/tests/ui/consts/const-eval/unused-broken-const.rs +++ b/tests/ui/consts/const-eval/unused-broken-const.rs @@ -3,6 +3,6 @@ //@ compile-flags: --emit=dep-info,metadata const FOO: i32 = [][0]; -//~^ ERROR evaluation of constant value failed +//~^ ERROR index out of bounds fn main() {} diff --git a/tests/ui/consts/const-eval/unused-broken-const.stderr b/tests/ui/consts/const-eval/unused-broken-const.stderr index fd0ee316fe2..74c713be4e4 100644 --- a/tests/ui/consts/const-eval/unused-broken-const.stderr +++ b/tests/ui/consts/const-eval/unused-broken-const.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: index out of bounds: the length is 0 but the index is 0 --> $DIR/unused-broken-const.rs:5:18 | LL | const FOO: i32 = [][0]; - | ^^^^^ index out of bounds: the length is 0 but the index is 0 + | ^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/unwind-abort.rs b/tests/ui/consts/const-eval/unwind-abort.rs index b239dba0239..688bb085356 100644 --- a/tests/ui/consts/const-eval/unwind-abort.rs +++ b/tests/ui/consts/const-eval/unwind-abort.rs @@ -4,7 +4,7 @@ const extern "C" fn foo() { panic!() //~ NOTE inside `foo` } -const _: () = foo(); //~ ERROR evaluation of constant value failed +const _: () = foo(); //~ ERROR explicit panic // Ensure that the CTFE engine handles calls to `extern "C"` aborting gracefully fn main() { diff --git a/tests/ui/consts/const-eval/unwind-abort.stderr b/tests/ui/consts/const-eval/unwind-abort.stderr index 5ed7467e84b..5468b56ec05 100644 --- a/tests/ui/consts/const-eval/unwind-abort.stderr +++ b/tests/ui/consts/const-eval/unwind-abort.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/unwind-abort.rs:7:15 | LL | const _: () = foo(); - | ^^^^^ evaluation panicked: explicit panic + | ^^^^^ evaluation of constant value failed | note: inside `foo` --> $DIR/unwind-abort.rs:4:5 diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs b/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs index 5f1d27b0de0..dbb165c64d9 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs @@ -15,10 +15,10 @@ pub mod empty { } const FOO: [empty::Empty; 3] = [foo(); 3]; -//~^ ERROR evaluation of constant value failed +//~^ ERROR value of the never type const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; -//~^ ERROR evaluation of constant value failed +//~^ ERROR value of uninhabited type fn main() { FOO; diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr index 0407ae5c323..cb006127741 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: constructing invalid value: encountered a value of the never type `!` --> $DIR/validate_uninhabited_zsts.rs:17:33 | LL | const FOO: [empty::Empty; 3] = [foo(); 3]; - | ^^^^^ constructing invalid value: encountered a value of the never type `!` + | ^^^^^ evaluation of constant value failed | note: inside `foo` --> $DIR/validate_uninhabited_zsts.rs:4:14 @@ -10,11 +10,11 @@ note: inside `foo` LL | unsafe { std::mem::transmute(()) } | ^^^^^^^^^^^^^^^^^^^^^^^ the failure occurred here -error[E0080]: evaluation of constant value failed +error[E0080]: constructing invalid value at .0: encountered a value of uninhabited type `Void` --> $DIR/validate_uninhabited_zsts.rs:20:42 | LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered a value of uninhabited type `Void` + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/validation-ice-extern-type-field.rs b/tests/ui/consts/const-eval/validation-ice-extern-type-field.rs index 8a32b170c40..3081689ee90 100644 --- a/tests/ui/consts/const-eval/validation-ice-extern-type-field.rs +++ b/tests/ui/consts/const-eval/validation-ice-extern-type-field.rs @@ -10,6 +10,6 @@ struct ThinDst { } const C1: &ThinDst = unsafe { std::mem::transmute(b"d".as_ptr()) }; -//~^ERROR: evaluation of constant value failed +//~^ERROR: `extern type` field does not have a known offset fn main() {} diff --git a/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr b/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr index 1ec36abc2ec..8456b04b306 100644 --- a/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr +++ b/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: `extern type` field does not have a known offset --> $DIR/validation-ice-extern-type-field.rs:12:1 | LL | const C1: &ThinDst = unsafe { std::mem::transmute(b"d".as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^ `extern type` field does not have a known offset + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-external-macro-const-err.rs b/tests/ui/consts/const-external-macro-const-err.rs index 3cb83823f1a..60cbe36071d 100644 --- a/tests/ui/consts/const-external-macro-const-err.rs +++ b/tests/ui/consts/const-external-macro-const-err.rs @@ -9,5 +9,5 @@ extern crate external_macro; use external_macro::static_assert; fn main() { - static_assert!(2 + 2 == 5); //~ ERROR constant + static_assert!(2 + 2 == 5); //~ ERROR index out of bounds: the length is 1 but the index is 1 } diff --git a/tests/ui/consts/const-external-macro-const-err.stderr b/tests/ui/consts/const-external-macro-const-err.stderr index 63f81ea18bc..c5374ae6b98 100644 --- a/tests/ui/consts/const-external-macro-const-err.stderr +++ b/tests/ui/consts/const-external-macro-const-err.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: index out of bounds: the length is 1 but the index is 1 --> $DIR/const-external-macro-const-err.rs:12:5 | LL | static_assert!(2 + 2 == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = note: this error originates in the macro `static_assert` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/const-int-unchecked.rs b/tests/ui/consts/const-int-unchecked.rs index 8de28aa2bb1..3fc58720cf1 100644 --- a/tests/ui/consts/const-int-unchecked.rs +++ b/tests/ui/consts/const-int-unchecked.rs @@ -1,6 +1,5 @@ #![feature(core_intrinsics)] - use std::intrinsics; // The documentation of `unchecked_shl` states that it: @@ -13,137 +12,137 @@ use std::intrinsics; // unsigned types: const SHL_U8: u8 = unsafe { intrinsics::unchecked_shl(5_u8, 8) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_U16: u16 = unsafe { intrinsics::unchecked_shl(5_u16, 16) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_U32: u32 = unsafe { intrinsics::unchecked_shl(5_u32, 32) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_U64: u64 = unsafe { intrinsics::unchecked_shl(5_u64, 64) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_U128: u128 = unsafe { intrinsics::unchecked_shl(5_u128, 128) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift // signed types: const SHL_I8: i8 = unsafe { intrinsics::unchecked_shl(5_i8, 8) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_i16, 16) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_I32: i32 = unsafe { intrinsics::unchecked_shl(5_i32, 32) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_I64: i64 = unsafe { intrinsics::unchecked_shl(5_i64, 64) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_I128: i128 = unsafe { intrinsics::unchecked_shl(5_i128, 128) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift // and make sure we capture y < 0: const SHL_I8_NEG: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -1) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -1) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_I32_NEG: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -1) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_I64_NEG: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -1) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_I128_NEG: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -1) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift // and that there's no special relation to the value -1 by picking some // negative values at random: const SHL_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -6) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -13) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -25) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -30) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHL_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -93) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift // Repeat it all over for `unchecked_shr` // unsigned types: const SHR_U8: u8 = unsafe { intrinsics::unchecked_shr(5_u8, 8) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_U16: u16 = unsafe { intrinsics::unchecked_shr(5_u16, 16) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_U32: u32 = unsafe { intrinsics::unchecked_shr(5_u32, 32) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_U64: u64 = unsafe { intrinsics::unchecked_shr(5_u64, 64) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_U128: u128 = unsafe { intrinsics::unchecked_shr(5_u128, 128) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift // signed types: const SHR_I8: i8 = unsafe { intrinsics::unchecked_shr(5_i8, 8) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_i16, 16) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_I32: i32 = unsafe { intrinsics::unchecked_shr(5_i32, 32) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_I64: i64 = unsafe { intrinsics::unchecked_shr(5_i64, 64) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_I128: i128 = unsafe { intrinsics::unchecked_shr(5_i128, 128) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift // and make sure we capture y < 0: const SHR_I8_NEG: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -1) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -1) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_I32_NEG: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -1) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_I64_NEG: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -1) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_I128_NEG: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -1) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift // and that there's no special relation to the value -1 by picking some // negative values at random: const SHR_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -6) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -13) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -25) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -30) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift const SHR_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -93) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflowing shift // Other arithmetic functions: const _: u16 = unsafe { std::intrinsics::unchecked_add(40000u16, 30000) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR arithmetic overflow const _: u32 = unsafe { std::intrinsics::unchecked_sub(14u32, 22) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR arithmetic overflow const _: u16 = unsafe { std::intrinsics::unchecked_mul(300u16, 250u16) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR arithmetic overflow const _: i32 = unsafe { std::intrinsics::unchecked_div(1, 0) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR dividing by zero const _: i32 = unsafe { std::intrinsics::unchecked_div(i32::MIN, -1) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflow in signed division (dividing MIN by -1) const _: i32 = unsafe { std::intrinsics::unchecked_rem(1, 0) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR calculating the remainder with a divisor of zero const _: i32 = unsafe { std::intrinsics::unchecked_rem(i32::MIN, -1) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR overflow in signed remainder (dividing MIN by -1) // capture fault with zero value const _: u32 = unsafe { std::intrinsics::ctlz_nonzero(0) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR `ctlz_nonzero` called on 0 const _: u32 = unsafe { std::intrinsics::cttz_nonzero(0) }; -//~^ ERROR evaluation of constant value failed +//~^ ERROR `cttz_nonzero` called on 0 fn main() {} diff --git a/tests/ui/consts/const-int-unchecked.stderr b/tests/ui/consts/const-int-unchecked.stderr index 3130603231e..29c6c829777 100644 --- a/tests/ui/consts/const-int-unchecked.stderr +++ b/tests/ui/consts/const-int-unchecked.stderr @@ -1,296 +1,296 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:15:29 +error[E0080]: overflowing shift by 8 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:14:29 | LL | const SHL_U8: u8 = unsafe { intrinsics::unchecked_shl(5_u8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 8 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:17:31 +error[E0080]: overflowing shift by 16 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:16:31 | LL | const SHL_U16: u16 = unsafe { intrinsics::unchecked_shl(5_u16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:19:31 +error[E0080]: overflowing shift by 32 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:18:31 | LL | const SHL_U32: u32 = unsafe { intrinsics::unchecked_shl(5_u32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 32 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:21:31 +error[E0080]: overflowing shift by 64 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:20:31 | LL | const SHL_U64: u64 = unsafe { intrinsics::unchecked_shl(5_u64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:23:33 +error[E0080]: overflowing shift by 128 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:22:33 | LL | const SHL_U128: u128 = unsafe { intrinsics::unchecked_shl(5_u128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 128 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:28:29 +error[E0080]: overflowing shift by 8 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:27:29 | LL | const SHL_I8: i8 = unsafe { intrinsics::unchecked_shl(5_i8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 8 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:30:31 +error[E0080]: overflowing shift by 16 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:29:31 | LL | const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_i16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:32:31 +error[E0080]: overflowing shift by 32 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:31:31 | LL | const SHL_I32: i32 = unsafe { intrinsics::unchecked_shl(5_i32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 32 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:34:31 +error[E0080]: overflowing shift by 64 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:33:31 | LL | const SHL_I64: i64 = unsafe { intrinsics::unchecked_shl(5_i64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:36:33 +error[E0080]: overflowing shift by 128 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:35:33 | LL | const SHL_I128: i128 = unsafe { intrinsics::unchecked_shl(5_i128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 128 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:41:33 +error[E0080]: overflowing shift by -1 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:40:33 | LL | const SHL_I8_NEG: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:43:35 +error[E0080]: overflowing shift by -1 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:42:35 | LL | const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:45:35 +error[E0080]: overflowing shift by -1 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:44:35 | LL | const SHL_I32_NEG: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:47:35 +error[E0080]: overflowing shift by -1 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:46:35 | LL | const SHL_I64_NEG: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:49:37 +error[E0080]: overflowing shift by -1 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:48:37 | LL | const SHL_I128_NEG: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:55:40 +error[E0080]: overflowing shift by -6 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:54:40 | LL | const SHL_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -6) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -6 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:57:42 +error[E0080]: overflowing shift by -13 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:56:42 | LL | const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -13 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:59:42 +error[E0080]: overflowing shift by -25 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:58:42 | LL | const SHL_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -25) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -25 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:61:42 +error[E0080]: overflowing shift by -30 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:60:42 | LL | const SHL_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -30) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -30 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:63:44 +error[E0080]: overflowing shift by -93 in `unchecked_shl` + --> $DIR/const-int-unchecked.rs:62:44 | LL | const SHL_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -93) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -93 in `unchecked_shl` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:70:29 +error[E0080]: overflowing shift by 8 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:69:29 | LL | const SHR_U8: u8 = unsafe { intrinsics::unchecked_shr(5_u8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 8 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:72:31 +error[E0080]: overflowing shift by 16 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:71:31 | LL | const SHR_U16: u16 = unsafe { intrinsics::unchecked_shr(5_u16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:74:31 +error[E0080]: overflowing shift by 32 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:73:31 | LL | const SHR_U32: u32 = unsafe { intrinsics::unchecked_shr(5_u32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 32 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:76:31 +error[E0080]: overflowing shift by 64 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:75:31 | LL | const SHR_U64: u64 = unsafe { intrinsics::unchecked_shr(5_u64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:78:33 +error[E0080]: overflowing shift by 128 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:77:33 | LL | const SHR_U128: u128 = unsafe { intrinsics::unchecked_shr(5_u128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 128 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:83:29 +error[E0080]: overflowing shift by 8 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:82:29 | LL | const SHR_I8: i8 = unsafe { intrinsics::unchecked_shr(5_i8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 8 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:85:31 +error[E0080]: overflowing shift by 16 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:84:31 | LL | const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_i16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:87:31 +error[E0080]: overflowing shift by 32 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:86:31 | LL | const SHR_I32: i32 = unsafe { intrinsics::unchecked_shr(5_i32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 32 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:89:31 +error[E0080]: overflowing shift by 64 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:88:31 | LL | const SHR_I64: i64 = unsafe { intrinsics::unchecked_shr(5_i64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:91:33 +error[E0080]: overflowing shift by 128 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:90:33 | LL | const SHR_I128: i128 = unsafe { intrinsics::unchecked_shr(5_i128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 128 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:96:33 +error[E0080]: overflowing shift by -1 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:95:33 | LL | const SHR_I8_NEG: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:98:35 +error[E0080]: overflowing shift by -1 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:97:35 | LL | const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:100:35 +error[E0080]: overflowing shift by -1 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:99:35 | LL | const SHR_I32_NEG: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:102:35 +error[E0080]: overflowing shift by -1 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:101:35 | LL | const SHR_I64_NEG: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:104:37 +error[E0080]: overflowing shift by -1 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:103:37 | LL | const SHR_I128_NEG: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -1 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:110:40 +error[E0080]: overflowing shift by -6 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:109:40 | LL | const SHR_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -6) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -6 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:112:42 +error[E0080]: overflowing shift by -13 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:111:42 | LL | const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -13 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:114:42 +error[E0080]: overflowing shift by -25 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:113:42 | LL | const SHR_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -25) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -25 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:116:42 +error[E0080]: overflowing shift by -30 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:115:42 | LL | const SHR_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -30) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -30 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:118:44 +error[E0080]: overflowing shift by -93 in `unchecked_shr` + --> $DIR/const-int-unchecked.rs:117:44 | LL | const SHR_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -93) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by -93 in `unchecked_shr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:123:25 +error[E0080]: arithmetic overflow in `unchecked_add` + --> $DIR/const-int-unchecked.rs:122:25 | LL | const _: u16 = unsafe { std::intrinsics::unchecked_add(40000u16, 30000) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ arithmetic overflow in `unchecked_add` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:126:25 +error[E0080]: arithmetic overflow in `unchecked_sub` + --> $DIR/const-int-unchecked.rs:125:25 | LL | const _: u32 = unsafe { std::intrinsics::unchecked_sub(14u32, 22) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ arithmetic overflow in `unchecked_sub` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:129:25 +error[E0080]: arithmetic overflow in `unchecked_mul` + --> $DIR/const-int-unchecked.rs:128:25 | LL | const _: u16 = unsafe { std::intrinsics::unchecked_mul(300u16, 250u16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ arithmetic overflow in `unchecked_mul` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:132:25 +error[E0080]: dividing by zero + --> $DIR/const-int-unchecked.rs:131:25 | LL | const _: i32 = unsafe { std::intrinsics::unchecked_div(1, 0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dividing by zero + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:134:25 +error[E0080]: overflow in signed division (dividing MIN by -1) + --> $DIR/const-int-unchecked.rs:133:25 | LL | const _: i32 = unsafe { std::intrinsics::unchecked_div(i32::MIN, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:137:25 +error[E0080]: calculating the remainder with a divisor of zero + --> $DIR/const-int-unchecked.rs:136:25 | LL | const _: i32 = unsafe { std::intrinsics::unchecked_rem(1, 0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:139:25 +error[E0080]: overflow in signed remainder (dividing MIN by -1) + --> $DIR/const-int-unchecked.rs:138:25 | LL | const _: i32 = unsafe { std::intrinsics::unchecked_rem(i32::MIN, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:144:25 +error[E0080]: `ctlz_nonzero` called on 0 + --> $DIR/const-int-unchecked.rs:143:25 | LL | const _: u32 = unsafe { std::intrinsics::ctlz_nonzero(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ctlz_nonzero` called on 0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-int-unchecked.rs:146:25 +error[E0080]: `cttz_nonzero` called on 0 + --> $DIR/const-int-unchecked.rs:145:25 | LL | const _: u32 = unsafe { std::intrinsics::cttz_nonzero(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `cttz_nonzero` called on 0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 49 previous errors diff --git a/tests/ui/consts/const-len-underflow-separate-spans.next.stderr b/tests/ui/consts/const-len-underflow-separate-spans.next.stderr index aacd74635e9..ada8f703349 100644 --- a/tests/ui/consts/const-len-underflow-separate-spans.next.stderr +++ b/tests/ui/consts/const-len-underflow-separate-spans.next.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `1_usize - 2_usize`, which would overflow --> $DIR/const-len-underflow-separate-spans.rs:10:20 | LL | const LEN: usize = ONE - TWO; - | ^^^^^^^^^ attempt to compute `1_usize - 2_usize`, which would overflow + | ^^^^^^^^^ evaluation of constant value failed note: erroneous constant encountered --> $DIR/const-len-underflow-separate-spans.rs:15:17 diff --git a/tests/ui/consts/const-len-underflow-separate-spans.old.stderr b/tests/ui/consts/const-len-underflow-separate-spans.old.stderr index aacd74635e9..ada8f703349 100644 --- a/tests/ui/consts/const-len-underflow-separate-spans.old.stderr +++ b/tests/ui/consts/const-len-underflow-separate-spans.old.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `1_usize - 2_usize`, which would overflow --> $DIR/const-len-underflow-separate-spans.rs:10:20 | LL | const LEN: usize = ONE - TWO; - | ^^^^^^^^^ attempt to compute `1_usize - 2_usize`, which would overflow + | ^^^^^^^^^ evaluation of constant value failed note: erroneous constant encountered --> $DIR/const-len-underflow-separate-spans.rs:15:17 diff --git a/tests/ui/consts/const-len-underflow-separate-spans.rs b/tests/ui/consts/const-len-underflow-separate-spans.rs index 14eb88b1427..a815ecaef70 100644 --- a/tests/ui/consts/const-len-underflow-separate-spans.rs +++ b/tests/ui/consts/const-len-underflow-separate-spans.rs @@ -8,10 +8,10 @@ const ONE: usize = 1; const TWO: usize = 2; const LEN: usize = ONE - TWO; -//~^ ERROR constant -//~| NOTE attempt to compute `1_usize - 2_usize`, which would overflow +//~^ NOTE constant +//~| ERROR attempt to compute `1_usize - 2_usize`, which would overflow fn main() { let a: [i8; LEN] = unimplemented!(); -//~^ NOTE constant + //~^ NOTE constant } diff --git a/tests/ui/consts/const-len-underflow-subspans.rs b/tests/ui/consts/const-len-underflow-subspans.rs index 5afb1bf89d0..1540bffa0ad 100644 --- a/tests/ui/consts/const-len-underflow-subspans.rs +++ b/tests/ui/consts/const-len-underflow-subspans.rs @@ -6,6 +6,5 @@ const TWO: usize = 2; fn main() { let a: [i8; ONE - TWO] = unimplemented!(); - //~^ ERROR evaluation of constant value failed - //~| NOTE attempt to compute `1_usize - 2_usize`, which would overflow + //~^ ERROR attempt to compute `1_usize - 2_usize`, which would overflow } diff --git a/tests/ui/consts/const-len-underflow-subspans.stderr b/tests/ui/consts/const-len-underflow-subspans.stderr index bfec056cc8a..b998c00135d 100644 --- a/tests/ui/consts/const-len-underflow-subspans.stderr +++ b/tests/ui/consts/const-len-underflow-subspans.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to compute `1_usize - 2_usize`, which would overflow --> $DIR/const-len-underflow-subspans.rs:8:17 | LL | let a: [i8; ONE - TWO] = unimplemented!(); - | ^^^^^^^^^ attempt to compute `1_usize - 2_usize`, which would overflow + | ^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs index bc534be6832..29474c76320 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs @@ -25,8 +25,7 @@ const B4: Option<&mut i32> = helper(&mut 42); //~ ERROR temporary value dropped // Not ok, since it points to read-only memory. const IMMUT_MUT_REF: &mut u16 = unsafe { mem::transmute(&13) }; -//~^ ERROR undefined behavior to use this value -//~| NOTE pointing to read-only memory +//~^ ERROR pointing to read-only memory // Ok, because no references to mutable data exist here, since the `{}` moves // its value and then takes a reference to that. diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr index 1f49f08c401..834ea3410f6 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr @@ -24,11 +24,11 @@ LL | const B4: Option<&mut i32> = helper(&mut 42); | | creates a temporary value which is freed while still in use | using this value as a constant requires that borrow lasts for `'static` -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory --> $DIR/mut_ref_in_final.rs:27:1 | LL | const IMMUT_MUT_REF: &mut u16 = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -36,7 +36,7 @@ LL | const IMMUT_MUT_REF: &mut u16 = unsafe { mem::transmute(&13) }; } error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:51:65 + --> $DIR/mut_ref_in_final.rs:50:65 | LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | -------------------------------^^-- @@ -46,7 +46,7 @@ LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | using this value as a constant requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:54:67 + --> $DIR/mut_ref_in_final.rs:53:67 | LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | -------------------------------^^-- @@ -56,7 +56,7 @@ LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | using this value as a static requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:57:71 + --> $DIR/mut_ref_in_final.rs:56:71 | LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | -------------------------------^^-- @@ -66,25 +66,25 @@ LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | using this value as a static requires that borrow lasts for `'static` error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/mut_ref_in_final.rs:70:53 + --> $DIR/mut_ref_in_final.rs:69:53 | LL | static RAW_MUT_CAST_S: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ^^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/mut_ref_in_final.rs:72:54 + --> $DIR/mut_ref_in_final.rs:71:54 | LL | static RAW_MUT_COERCE_S: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^ error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/mut_ref_in_final.rs:74:52 + --> $DIR/mut_ref_in_final.rs:73:52 | LL | const RAW_MUT_CAST_C: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ^^^^^^^ error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/mut_ref_in_final.rs:76:53 + --> $DIR/mut_ref_in_final.rs:75:53 | LL | const RAW_MUT_COERCE_C: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^ diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs index a58c4437e15..2707e8a14ec 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs @@ -16,24 +16,21 @@ static mut BUFFER: i32 = 42; const fn helper() -> Option<&'static mut i32> { unsafe { Some(&mut *std::ptr::addr_of_mut!(BUFFER)) } } -const MUT: Option<&mut i32> = helper(); //~ ERROR it is undefined behavior to use this value -//~^ NOTE encountered reference to mutable +const MUT: Option<&mut i32> = helper(); //~ ERROR encountered reference to mutable const fn helper_int2ptr() -> Option<&'static mut i32> { unsafe { // Undefined behaviour (integer as pointer), who doesn't love tests like this. Some(&mut *(42 as *mut i32)) } } -const INT2PTR: Option<&mut i32> = helper_int2ptr(); //~ ERROR it is undefined behavior to use this value -//~^ NOTE encountered a dangling reference -static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr(); //~ ERROR it is undefined behavior to use this value -//~^ NOTE encountered a dangling reference +const INT2PTR: Option<&mut i32> = helper_int2ptr(); //~ ERROR encountered a dangling reference +static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr(); //~ ERROR encountered a dangling reference const fn helper_dangling() -> Option<&'static mut i32> { unsafe { // Undefined behaviour (dangling pointer), who doesn't love tests like this. Some(&mut *(&mut 42 as *mut i32)) } } -const DANGLING: Option<&mut i32> = helper_dangling(); //~ ERROR it is undefined behavior to use this value -static DANGLING_STATIC: Option<&mut i32> = helper_dangling(); //~ ERROR it is undefined behavior to use this value +const DANGLING: Option<&mut i32> = helper_dangling(); //~ ERROR dangling reference +static DANGLING_STATIC: Option<&mut i32> = helper_dangling(); //~ ERROR dangling reference // These are fine! Just statics pointing to mutable statics, nothing fundamentally wrong with this. static MUT_STATIC: Option<&mut i32> = helper(); diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr index 4ea6fa62475..6456587b77a 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr @@ -1,52 +1,52 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at ..0: encountered reference to mutable memory in `const` --> $DIR/mut_ref_in_final_dynamic_check.rs:19:1 | LL | const MUT: Option<&mut i32> = helper(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered reference to mutable memory in `const` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/mut_ref_in_final_dynamic_check.rs:26:1 +error[E0080]: constructing invalid value at ..0: encountered a dangling reference (0x2a[noalloc] has no provenance) + --> $DIR/mut_ref_in_final_dynamic_check.rs:25:1 | LL | const INT2PTR: Option<&mut i32> = helper_int2ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a dangling reference (0x2a[noalloc] has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/mut_ref_in_final_dynamic_check.rs:28:1 +error[E0080]: constructing invalid value at ..0: encountered a dangling reference (0x2a[noalloc] has no provenance) + --> $DIR/mut_ref_in_final_dynamic_check.rs:26:1 | LL | static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a dangling reference (0x2a[noalloc] has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/mut_ref_in_final_dynamic_check.rs:35:1 +error[E0080]: constructing invalid value at ..0: encountered a dangling reference (use-after-free) + --> $DIR/mut_ref_in_final_dynamic_check.rs:32:1 | LL | const DANGLING: Option<&mut i32> = helper_dangling(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a dangling reference (use-after-free) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/mut_ref_in_final_dynamic_check.rs:36:1 +error[E0080]: constructing invalid value at ..0: encountered a dangling reference (use-after-free) + --> $DIR/mut_ref_in_final_dynamic_check.rs:33:1 | LL | static DANGLING_STATIC: Option<&mut i32> = helper_dangling(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a dangling reference (use-after-free) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { diff --git a/tests/ui/consts/const-ptr-is-null.rs b/tests/ui/consts/const-ptr-is-null.rs index 319f6b1a62b..7e7b74c3520 100644 --- a/tests/ui/consts/const-ptr-is-null.rs +++ b/tests/ui/consts/const-ptr-is-null.rs @@ -19,7 +19,7 @@ const MAYBE_NULL: () = { assert!(!ptr.wrapping_byte_sub(1).is_null()); // ... but once we shift outside the allocation, with an offset divisible by 4, // we might become null. - assert!(!ptr.wrapping_sub(512).is_null()); //~ ERROR evaluation of constant value failed + assert!(!ptr.wrapping_sub(512).is_null()); //~ ERROR null-ness of this pointer cannot be determined }; fn main() {} diff --git a/tests/ui/consts/const-ptr-is-null.stderr b/tests/ui/consts/const-ptr-is-null.stderr index 1a2be3b3cb1..9969430bde8 100644 --- a/tests/ui/consts/const-ptr-is-null.stderr +++ b/tests/ui/consts/const-ptr-is-null.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: null-ness of this pointer cannot be determined in const context --> $DIR/const-ptr-is-null.rs:22:14 | LL | assert!(!ptr.wrapping_sub(512).is_null()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: null-ness of this pointer cannot be determined in const context + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `std::ptr::const_ptr::::is_null` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs index 598904d3c44..14cdf6bb7c6 100644 --- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs +++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs @@ -7,7 +7,7 @@ extern "C" { type Opaque; } -const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR constant -const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR constant +const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout +const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout fn main() {} diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr index 4c0252123a4..f85893783a4 100644 --- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr +++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr @@ -1,14 +1,14 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: `extern type` does not have known layout --> $DIR/const-size_of_val-align_of_val-extern-type.rs:10:31 | LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `extern type` does not have known layout + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: `extern type` does not have known layout --> $DIR/const-size_of_val-align_of_val-extern-type.rs:11:32 | LL | const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `extern type` does not have known layout + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-slice-oob.rs b/tests/ui/consts/const-slice-oob.rs index 09202df72c0..6682c234eaf 100644 --- a/tests/ui/consts/const-slice-oob.rs +++ b/tests/ui/consts/const-slice-oob.rs @@ -1,7 +1,6 @@ -const FOO: &'static[u32] = &[1, 2, 3]; +const FOO: &'static [u32] = &[1, 2, 3]; const BAR: u32 = FOO[5]; -//~^ NOTE index out of bounds: the length is 3 but the index is 5 -//~| ERROR evaluation of constant value failed +//~^ ERROR index out of bounds: the length is 3 but the index is 5 fn main() { let _ = BAR; diff --git a/tests/ui/consts/const-slice-oob.stderr b/tests/ui/consts/const-slice-oob.stderr index 30ec340d2a2..13d4a434608 100644 --- a/tests/ui/consts/const-slice-oob.stderr +++ b/tests/ui/consts/const-slice-oob.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: index out of bounds: the length is 3 but the index is 5 --> $DIR/const-slice-oob.rs:2:18 | LL | const BAR: u32 = FOO[5]; - | ^^^^^^ index out of bounds: the length is 3 but the index is 5 + | ^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-unwrap.rs b/tests/ui/consts/const-unwrap.rs index d48078a0834..38ebd5dd230 100644 --- a/tests/ui/consts/const-unwrap.rs +++ b/tests/ui/consts/const-unwrap.rs @@ -4,12 +4,10 @@ const FOO: i32 = Some(42i32).unwrap(); const BAR: i32 = Option::::None.unwrap(); -//~^ ERROR: evaluation of constant value failed -//~| NOTE: called `Option::unwrap()` on a `None` value +//~^ ERROR: called `Option::unwrap()` on a `None` value const BAZ: i32 = Option::::None.expect("absolutely not!"); -//~^ ERROR: evaluation of constant value failed -//~| NOTE: absolutely not! +//~^ ERROR: absolutely not! fn main() { println!("{}", FOO); diff --git a/tests/ui/consts/const-unwrap.stderr b/tests/ui/consts/const-unwrap.stderr index 832c95992c8..7b8cc1ca856 100644 --- a/tests/ui/consts/const-unwrap.stderr +++ b/tests/ui/consts/const-unwrap.stderr @@ -1,14 +1,14 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: called `Option::unwrap()` on a `None` value --> $DIR/const-unwrap.rs:6:18 | LL | const BAR: i32 = Option::::None.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: called `Option::unwrap()` on a `None` value + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/const-unwrap.rs:10:18 +error[E0080]: evaluation panicked: absolutely not! + --> $DIR/const-unwrap.rs:9:18 | LL | const BAZ: i32 = Option::::None.expect("absolutely not!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: absolutely not! + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const_refs_to_static_fail.rs b/tests/ui/consts/const_refs_to_static_fail.rs index e1f2262ba29..b8bab91e005 100644 --- a/tests/ui/consts/const_refs_to_static_fail.rs +++ b/tests/ui/consts/const_refs_to_static_fail.rs @@ -9,16 +9,13 @@ use std::cell::SyncUnsafeCell; static S: SyncUnsafeCell = SyncUnsafeCell::new(0); static mut S_MUT: i32 = 0; -const C1: &SyncUnsafeCell = &S; //~ERROR undefined behavior -//~| NOTE encountered reference to mutable memory +const C1: &SyncUnsafeCell = &S; //~ERROR encountered reference to mutable memory const C1_READ: () = unsafe { assert!(*C1.get() == 0); }; const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) }; const C2_READ: () = unsafe { - assert!(*C2 == 0); //~ERROR evaluation of constant value failed - //~^ NOTE constant accesses mutable global memory + assert!(*C2 == 0); //~ERROR constant accesses mutable global memory }; -fn main() { -} +fn main() {} diff --git a/tests/ui/consts/const_refs_to_static_fail.stderr b/tests/ui/consts/const_refs_to_static_fail.stderr index 245806da5c6..bd406941061 100644 --- a/tests/ui/consts/const_refs_to_static_fail.stderr +++ b/tests/ui/consts/const_refs_to_static_fail.stderr @@ -1,8 +1,8 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered reference to mutable memory in `const` --> $DIR/const_refs_to_static_fail.rs:12:1 | LL | const C1: &SyncUnsafeCell = &S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -10,16 +10,16 @@ LL | const C1: &SyncUnsafeCell = &S; } note: erroneous constant encountered - --> $DIR/const_refs_to_static_fail.rs:15:14 + --> $DIR/const_refs_to_static_fail.rs:14:14 | LL | assert!(*C1.get() == 0); | ^^ -error[E0080]: evaluation of constant value failed - --> $DIR/const_refs_to_static_fail.rs:19:13 +error[E0080]: constant accesses mutable global memory + --> $DIR/const_refs_to_static_fail.rs:18:13 | LL | assert!(*C2 == 0); - | ^^^ constant accesses mutable global memory + | ^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.rs b/tests/ui/consts/const_refs_to_static_fail_invalid.rs index f6ccfbfc52f..34ed8540f3f 100644 --- a/tests/ui/consts/const_refs_to_static_fail_invalid.rs +++ b/tests/ui/consts/const_refs_to_static_fail_invalid.rs @@ -8,8 +8,7 @@ fn invalid() { static S: i8 = 10; const C: &bool = unsafe { std::mem::transmute(&S) }; - //~^ERROR: undefined behavior - //~| NOTE expected a boolean + //~^ERROR: expected a boolean // This must be rejected here (or earlier), since it's not a valid `&bool`. match &true { @@ -24,8 +23,7 @@ fn extern_() { } const C: &i8 = unsafe { &S }; - //~^ERROR: undefined behavior - //~| NOTE `extern` static + //~^ERROR: `extern` static // This must be rejected here (or earlier), since the pattern cannot be read. match &0 { @@ -38,8 +36,7 @@ fn mutable() { static mut S_MUT: i32 = 0; const C: &i32 = unsafe { &S_MUT }; - //~^ERROR: undefined behavior - //~| NOTE encountered reference to mutable memory + //~^ERROR: encountered reference to mutable memory // This *must not build*, the constant we are matching against // could change its value! diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr index e0086e07af7..8a034aa00bc 100644 --- a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr +++ b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr @@ -1,30 +1,30 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered 0x0a, but expected a boolean --> $DIR/const_refs_to_static_fail_invalid.rs:10:5 | LL | const C: &bool = unsafe { std::mem::transmute(&S) }; - | ^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0a, but expected a boolean + | ^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refs_to_static_fail_invalid.rs:26:5 +error[E0080]: constructing invalid value: encountered reference to `extern` static in `const` + --> $DIR/const_refs_to_static_fail_invalid.rs:25:5 | LL | const C: &i8 = unsafe { &S }; - | ^^^^^^^^^^^^ constructing invalid value: encountered reference to `extern` static in `const` + | ^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refs_to_static_fail_invalid.rs:40:5 +error[E0080]: constructing invalid value: encountered reference to mutable memory in `const` + --> $DIR/const_refs_to_static_fail_invalid.rs:38:5 | LL | const C: &i32 = unsafe { &S_MUT }; - | ^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` + | ^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { diff --git a/tests/ui/consts/const_unsafe_unreachable_ub.rs b/tests/ui/consts/const_unsafe_unreachable_ub.rs index 76c6c56d7c5..7c6c7a608b8 100644 --- a/tests/ui/consts/const_unsafe_unreachable_ub.rs +++ b/tests/ui/consts/const_unsafe_unreachable_ub.rs @@ -8,8 +8,8 @@ const unsafe fn foo(x: bool) -> bool { } const BAR: bool = unsafe { foo(false) }; -//~^ ERROR evaluation of constant value failed -//~| NOTE entering unreachable code +//~^ NOTE evaluation of constant value failed +//~| ERROR entering unreachable code fn main() { assert_eq!(BAR, true); diff --git a/tests/ui/consts/const_unsafe_unreachable_ub.stderr b/tests/ui/consts/const_unsafe_unreachable_ub.stderr index 42bf69aded0..116c2198914 100644 --- a/tests/ui/consts/const_unsafe_unreachable_ub.stderr +++ b/tests/ui/consts/const_unsafe_unreachable_ub.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: entering unreachable code --> $DIR/const_unsafe_unreachable_ub.rs:10:28 | LL | const BAR: bool = unsafe { foo(false) }; - | ^^^^^^^^^^ entering unreachable code + | ^^^^^^^^^^ evaluation of constant value failed | note: inside `foo` --> $DIR/const_unsafe_unreachable_ub.rs:4:18 diff --git a/tests/ui/consts/control-flow/assert.rs b/tests/ui/consts/control-flow/assert.rs index 9d17f65b93c..2c372075137 100644 --- a/tests/ui/consts/control-flow/assert.rs +++ b/tests/ui/consts/control-flow/assert.rs @@ -3,6 +3,6 @@ const _: () = assert!(true); const _: () = assert!(false); -//~^ ERROR evaluation of constant value failed +//~^ ERROR assertion failed fn main() {} diff --git a/tests/ui/consts/control-flow/assert.stderr b/tests/ui/consts/control-flow/assert.stderr index 3fa98b74bf6..95b237959c1 100644 --- a/tests/ui/consts/control-flow/assert.stderr +++ b/tests/ui/consts/control-flow/assert.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: assertion failed: false --> $DIR/assert.rs:5:15 | LL | const _: () = assert!(false); - | ^^^^^^^^^^^^^^ evaluation panicked: assertion failed: false + | ^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs index d0242f28544..480f1c5f460 100644 --- a/tests/ui/consts/copy-intrinsic.rs +++ b/tests/ui/consts/copy-intrinsic.rs @@ -1,8 +1,8 @@ // ignore-tidy-linelength #![feature(core_intrinsics)] -use std::mem; use std::intrinsics::{copy, copy_nonoverlapping}; +use std::mem; const COPY_ZERO: () = unsafe { // Since we are not copying anything, this should be allowed. @@ -17,8 +17,7 @@ const COPY_OOB_1: () = unsafe { // Zero-sized copy is fine. copy_nonoverlapping(0x100 as *const i32, dangle, 0); // Non-zero-sized copy is not. - copy_nonoverlapping(0x100 as *const i32, dangle, 1); //~ ERROR evaluation of constant value failed [E0080] - //~| NOTE which is a dangling pointer + copy_nonoverlapping(0x100 as *const i32, dangle, 1); //~ ERROR which is a dangling pointer }; const COPY_OOB_2: () = unsafe { let x = 0i32; @@ -26,22 +25,18 @@ const COPY_OOB_2: () = unsafe { // Zero-sized copy is fine. copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); // Non-zero-sized copy is not. - copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); //~ ERROR evaluation of constant value failed [E0080] - //~| NOTE is at or beyond the end of the allocation of size 4 bytes + copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); //~ ERROR is at or beyond the end of the allocation of size 4 bytes }; const COPY_SIZE_OVERFLOW: () = unsafe { let x = 0; let mut y = 0; - copy(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); //~ ERROR evaluation of constant value failed [E0080] - //~| NOTE overflow computing total size of `copy` + copy(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); //~ ERROR overflow computing total size of `copy` }; const COPY_NONOVERLAPPING_SIZE_OVERFLOW: () = unsafe { let x = 0; let mut y = 0; - copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); //~ ERROR evaluation of constant value failed [E0080] - //~| NOTE overflow computing total size of `copy_nonoverlapping` + copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); //~ ERROR overflow computing total size of `copy_nonoverlapping` }; -fn main() { -} +fn main() {} diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr index 8d586428e56..8d3d2752f60 100644 --- a/tests/ui/consts/copy-intrinsic.stderr +++ b/tests/ui/consts/copy-intrinsic.stderr @@ -1,26 +1,26 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: memory access failed: attempting to access 4 bytes, but got 0x100[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/copy-intrinsic.rs:20:5 | LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got 0x100[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:29:5 +error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes + --> $DIR/copy-intrinsic.rs:28:5 | LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:36:5 +error[E0080]: overflow computing total size of `copy` + --> $DIR/copy-intrinsic.rs:34:5 | LL | copy(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:42:5 +error[E0080]: overflow computing total size of `copy_nonoverlapping` + --> $DIR/copy-intrinsic.rs:39:5 | LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 4 previous errors diff --git a/tests/ui/consts/dangling-alloc-id-ice.rs b/tests/ui/consts/dangling-alloc-id-ice.rs index 8e9493c8d28..b77c5971b2b 100644 --- a/tests/ui/consts/dangling-alloc-id-ice.rs +++ b/tests/ui/consts/dangling-alloc-id-ice.rs @@ -10,7 +10,7 @@ union Foo<'a> { } const FOO: &() = { - //~^ ERROR it is undefined behavior to use this value + //~^ ERROR dangling reference let y = (); unsafe { Foo { y: &y }.long_live_the_unit } }; diff --git a/tests/ui/consts/dangling-alloc-id-ice.stderr b/tests/ui/consts/dangling-alloc-id-ice.stderr index 881c0b162ed..65a46b62dae 100644 --- a/tests/ui/consts/dangling-alloc-id-ice.stderr +++ b/tests/ui/consts/dangling-alloc-id-ice.stderr @@ -1,8 +1,8 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered a dangling reference (use-after-free) --> $DIR/dangling-alloc-id-ice.rs:12:1 | LL | const FOO: &() = { - | ^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free) + | ^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { diff --git a/tests/ui/consts/dangling-zst-ice-issue-126393.rs b/tests/ui/consts/dangling-zst-ice-issue-126393.rs index 4beee913a97..6b667fdfd35 100644 --- a/tests/ui/consts/dangling-zst-ice-issue-126393.rs +++ b/tests/ui/consts/dangling-zst-ice-issue-126393.rs @@ -5,7 +5,7 @@ pub struct Wrapper; pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { -//~^ERROR: it is undefined behavior to use this value + //~^ ERROR: dangling reference std::mem::transmute(&{ let y = 42; y diff --git a/tests/ui/consts/dangling-zst-ice-issue-126393.stderr b/tests/ui/consts/dangling-zst-ice-issue-126393.stderr index d32b427f14e..2f600e494c4 100644 --- a/tests/ui/consts/dangling-zst-ice-issue-126393.stderr +++ b/tests/ui/consts/dangling-zst-ice-issue-126393.stderr @@ -1,8 +1,8 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered a dangling reference (use-after-free) --> $DIR/dangling-zst-ice-issue-126393.rs:7:1 | LL | pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { diff --git a/tests/ui/consts/eval-enum.rs b/tests/ui/consts/eval-enum.rs index fa9ad6736e2..ae0296bd4c0 100644 --- a/tests/ui/consts/eval-enum.rs +++ b/tests/ui/consts/eval-enum.rs @@ -1,10 +1,8 @@ enum Test { - DivZero = 1/0, - //~^ NOTE attempt to divide `1_isize` by zero - //~| ERROR evaluation of constant value failed - RemZero = 1%0, - //~^ NOTE attempt to calculate the remainder of `1_isize` with a divisor of zero - //~| ERROR evaluation of constant value failed + DivZero = 1 / 0, + //~^ ERROR attempt to divide `1_isize` by zero + RemZero = 1 % 0, + //~^ ERROR attempt to calculate the remainder of `1_isize` with a divisor of zero } fn main() {} diff --git a/tests/ui/consts/eval-enum.stderr b/tests/ui/consts/eval-enum.stderr index fb4d903489f..eb55ad2a252 100644 --- a/tests/ui/consts/eval-enum.stderr +++ b/tests/ui/consts/eval-enum.stderr @@ -1,14 +1,14 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to divide `1_isize` by zero --> $DIR/eval-enum.rs:2:15 | -LL | DivZero = 1/0, - | ^^^ attempt to divide `1_isize` by zero +LL | DivZero = 1 / 0, + | ^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/eval-enum.rs:5:15 +error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero + --> $DIR/eval-enum.rs:4:15 | -LL | RemZero = 1%0, - | ^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero +LL | RemZero = 1 % 0, + | ^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.rs b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs index c3bd8301d5c..e17bac603b4 100644 --- a/tests/ui/consts/extra-const-ub/detect-extra-ub.rs +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs @@ -28,41 +28,35 @@ enum UninhDiscriminant { const INVALID_BOOL: () = unsafe { let _x: bool = transmute(3u8); - //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| NOTE invalid value + //[with_flag]~^ ERROR: invalid value }; const INVALID_PTR_IN_INT: () = unsafe { let _x: usize = transmute(&3u8); - //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| NOTE invalid value + //[with_flag]~^ ERROR: invalid value }; const INVALID_PTR_IN_ENUM: () = unsafe { let _x: PtrSizedEnum = transmute(&3u8); - //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| NOTE invalid value + //[with_flag]~^ ERROR: invalid value }; const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe { let x: &[u8] = &[0; 32]; let _x: (usize, usize) = transmute(x); - //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| NOTE invalid value + //[with_flag]~^ ERROR: invalid value }; const UNALIGNED_PTR: () = unsafe { let _x: &u32 = transmute(&[0u8; 4]); - //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| NOTE invalid value + //[with_flag]~^ ERROR: invalid value }; const UNINHABITED_VARIANT: () = unsafe { let data = [1u8]; // Not using transmute, we want to hit the ImmTy code path. let v = *addr_of!(data).cast::(); - //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| NOTE invalid value + //[with_flag]~^ ERROR: invalid value }; const PARTIAL_POINTER: () = unsafe { @@ -81,8 +75,7 @@ const PARTIAL_POINTER: () = unsafe { let mem = Packed { pad1: 0, ptr: &0u8 as *const u8, pad2: [0; 7] }; let mem = Align { p: mem, align: 0 }; let _val = *(&mem as *const Align as *const [*const u8; 2]); - //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| NOTE invalid value + //[with_flag]~^ ERROR: invalid value }; // Regression tests for an ICE (related to ). @@ -96,8 +89,7 @@ const VALID_ARRAY: [Option; 0] = { let e = [None; 0]; e }; const OVERSIZED_REF: () = { unsafe { let slice: *const [u8] = transmute((1usize, usize::MAX)); let _val = &*slice; - //[with_flag]~^ ERROR: evaluation of constant value failed - //[with_flag]~| NOTE slice is bigger than largest supported object + //[with_flag]~^ ERROR: slice is bigger than largest supported object } }; fn main() {} diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr index ea3b0e70b82..74669d3d549 100644 --- a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr @@ -1,62 +1,62 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: constructing invalid value: encountered 0x03, but expected a boolean --> $DIR/detect-extra-ub.rs:30:20 | LL | let _x: bool = transmute(3u8); - | ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:36:21 +error[E0080]: constructing invalid value: encountered a pointer, but expected an integer + --> $DIR/detect-extra-ub.rs:35:21 | LL | let _x: usize = transmute(&3u8); - | ^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected an integer + | ^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:42:28 +error[E0080]: constructing invalid value at .: encountered a pointer, but expected an integer + --> $DIR/detect-extra-ub.rs:40:28 | LL | let _x: PtrSizedEnum = transmute(&3u8); - | ^^^^^^^^^^^^^^^ constructing invalid value at .: encountered a pointer, but expected an integer + | ^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:49:30 +error[E0080]: constructing invalid value at .0: encountered a pointer, but expected an integer + --> $DIR/detect-extra-ub.rs:46:30 | LL | let _x: (usize, usize) = transmute(x); - | ^^^^^^^^^^^^ constructing invalid value at .0: encountered a pointer, but expected an integer + | ^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:55:20 +error[E0080]: constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1) + --> $DIR/detect-extra-ub.rs:51:20 | LL | let _x: &u32 = transmute(&[0u8; 4]); - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1) + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:63:13 +error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant + --> $DIR/detect-extra-ub.rs:58:13 | LL | let v = *addr_of!(data).cast::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:83:16 +error[E0080]: constructing invalid value at [0]: encountered a partial pointer or a mix of pointers + --> $DIR/detect-extra-ub.rs:77:16 | LL | let _val = *(&mem as *const Align as *const [*const u8; 2]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a partial pointer or a mix of pointers + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:98:16 +error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + --> $DIR/detect-extra-ub.rs:91:16 | LL | let _val = &*slice; - | ^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^ evaluation of constant value failed error: aborting due to 8 previous errors diff --git a/tests/ui/consts/interior-mut-const-via-union.32bit.stderr b/tests/ui/consts/interior-mut-const-via-union.32bit.stderr index fb06643df85..47bb2e5e879 100644 --- a/tests/ui/consts/interior-mut-const-via-union.32bit.stderr +++ b/tests/ui/consts/interior-mut-const-via-union.32bit.stderr @@ -1,8 +1,8 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at ..y..0: encountered `UnsafeCell` in read-only memory --> $DIR/interior-mut-const-via-union.rs:34:1 | LL | fn main() { - | ^^^^^^^^^ constructing invalid value at ..y..0: encountered `UnsafeCell` in read-only memory + | ^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { diff --git a/tests/ui/consts/interior-mut-const-via-union.64bit.stderr b/tests/ui/consts/interior-mut-const-via-union.64bit.stderr index f39ebe0afbd..b4c9a4bd47e 100644 --- a/tests/ui/consts/interior-mut-const-via-union.64bit.stderr +++ b/tests/ui/consts/interior-mut-const-via-union.64bit.stderr @@ -1,8 +1,8 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at ..y..0: encountered `UnsafeCell` in read-only memory --> $DIR/interior-mut-const-via-union.rs:34:1 | LL | fn main() { - | ^^^^^^^^^ constructing invalid value at ..y..0: encountered `UnsafeCell` in read-only memory + | ^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { diff --git a/tests/ui/consts/interior-mut-const-via-union.rs b/tests/ui/consts/interior-mut-const-via-union.rs index 6d40a9ba850..5e624671aee 100644 --- a/tests/ui/consts/interior-mut-const-via-union.rs +++ b/tests/ui/consts/interior-mut-const-via-union.rs @@ -31,7 +31,7 @@ const C: S = { s }; -fn main() { //~ ERROR it is undefined behavior to use this value - // FIXME the span here is wrong, sould be pointing at the line below, not above. +fn main() { //~ ERROR encountered `UnsafeCell` in read-only memory + // FIXME the span here is wrong, should be pointing at the line below, not above. let _: &'static _ = &C; } diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs index 286972365d5..40fc02cf644 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.rs +++ b/tests/ui/consts/issue-17718-const-bad-values.rs @@ -9,7 +9,6 @@ const C1: &'static mut [usize] = &mut []; static mut S: i32 = 3; const C2: &'static mut i32 = unsafe { &mut S }; -//~^ ERROR: it is undefined behavior to use this value -//~| NOTE reference to mutable memory +//~^ ERROR: reference to mutable memory fn main() {} diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr index 102491e90ba..effb614b15b 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.stderr +++ b/tests/ui/consts/issue-17718-const-bad-values.stderr @@ -4,11 +4,11 @@ error[E0764]: mutable references are not allowed in the final value of constants LL | const C1: &'static mut [usize] = &mut []; | ^^^^^^^ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered reference to mutable memory in `const` --> $DIR/issue-17718-const-bad-values.rs:11:1 | LL | const C2: &'static mut i32 = unsafe { &mut S }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $PTR, align: $PTR) { diff --git a/tests/ui/consts/issue-32829.rs b/tests/ui/consts/issue-32829.rs index 25f323b9803..e02db69c686 100644 --- a/tests/ui/consts/issue-32829.rs +++ b/tests/ui/consts/issue-32829.rs @@ -1,5 +1,5 @@ static S : u64 = { { panic!("foo"); 0 } }; -//~^ ERROR could not evaluate static initializer +//~^ ERROR evaluation panicked: foo fn main() { println!("{:?}", S); diff --git a/tests/ui/consts/issue-32829.stderr b/tests/ui/consts/issue-32829.stderr index 542dce19151..d10942d1e56 100644 --- a/tests/ui/consts/issue-32829.stderr +++ b/tests/ui/consts/issue-32829.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: evaluation panicked: foo --> $DIR/issue-32829.rs:1:22 | LL | static S : u64 = { { panic!("foo"); 0 } }; - | ^^^^^^^^^^^^^ evaluation panicked: foo + | ^^^^^^^^^^^^^ could not evaluate static initializer error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-63952.32bit.stderr b/tests/ui/consts/issue-63952.32bit.stderr index f562f9104e3..e5340788167 100644 --- a/tests/ui/consts/issue-63952.32bit.stderr +++ b/tests/ui/consts/issue-63952.32bit.stderr @@ -1,8 +1,8 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/issue-63952.rs:17:1 | LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { diff --git a/tests/ui/consts/issue-63952.64bit.stderr b/tests/ui/consts/issue-63952.64bit.stderr index fe66bec13a1..27e74833fc5 100644 --- a/tests/ui/consts/issue-63952.64bit.stderr +++ b/tests/ui/consts/issue-63952.64bit.stderr @@ -1,8 +1,8 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/issue-63952.rs:17:1 | LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { diff --git a/tests/ui/consts/issue-63952.rs b/tests/ui/consts/issue-63952.rs index aee06f8eb04..fce6013b4d3 100644 --- a/tests/ui/consts/issue-63952.rs +++ b/tests/ui/consts/issue-63952.rs @@ -14,7 +14,7 @@ union SliceTransmute { } // bad slice: length too big to even exist anywhere -const SLICE_WAY_TOO_LONG: &[u8] = unsafe { //~ ERROR: it is undefined behavior to use this value +const SLICE_WAY_TOO_LONG: &[u8] = unsafe { //~ ERROR: slice is bigger than largest supported object SliceTransmute { repr: SliceRepr { ptr: &42, diff --git a/tests/ui/consts/issue-64506.rs b/tests/ui/consts/issue-64506.rs index 096d29cbe49..8511c1edb30 100644 --- a/tests/ui/consts/issue-64506.rs +++ b/tests/ui/consts/issue-64506.rs @@ -14,7 +14,7 @@ const FOO: () = { b: (), } let x = unsafe { Foo { b: () }.a }; - //~^ ERROR: evaluation of constant value failed + //~^ ERROR: value of uninhabited type let x = &x.inner; }; diff --git a/tests/ui/consts/issue-64506.stderr b/tests/ui/consts/issue-64506.stderr index 4cc2b713741..22b8af9689d 100644 --- a/tests/ui/consts/issue-64506.stderr +++ b/tests/ui/consts/issue-64506.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: constructing invalid value at .inner: encountered a value of uninhabited type `AnonPipe` --> $DIR/issue-64506.rs:16:22 | LL | let x = unsafe { Foo { b: () }.a }; - | ^^^^^^^^^^^^^^^ constructing invalid value at .inner: encountered a value of uninhabited type `AnonPipe` + | ^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-66693-panic-in-array-len.rs b/tests/ui/consts/issue-66693-panic-in-array-len.rs index fc0dcd7a44d..2256970e337 100644 --- a/tests/ui/consts/issue-66693-panic-in-array-len.rs +++ b/tests/ui/consts/issue-66693-panic-in-array-len.rs @@ -8,7 +8,7 @@ fn main() { // ensure that conforming panics are handled correctly let _ = [false; panic!()]; - //~^ ERROR: evaluation of constant value failed + //~^ ERROR: explicit panic // typechecking halts before getting to this one let _ = ['a', panic!("panic in array len")]; diff --git a/tests/ui/consts/issue-66693-panic-in-array-len.stderr b/tests/ui/consts/issue-66693-panic-in-array-len.stderr index fdef515b6d4..f475ab0c495 100644 --- a/tests/ui/consts/issue-66693-panic-in-array-len.stderr +++ b/tests/ui/consts/issue-66693-panic-in-array-len.stderr @@ -4,11 +4,11 @@ error: argument to `panic!()` in a const context must have type `&str` LL | let _ = [0i32; panic!(2f32)]; | ^^^^^^^^^^^^ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-66693-panic-in-array-len.rs:10:21 | LL | let _ = [false; panic!()]; - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/consts/issue-66693.rs b/tests/ui/consts/issue-66693.rs index 416bd8ec72a..9d82d5a42bd 100644 --- a/tests/ui/consts/issue-66693.rs +++ b/tests/ui/consts/issue-66693.rs @@ -14,9 +14,9 @@ const fn _foo() { // ensure that conforming panics don't cause an error beyond the failure to const eval const _: () = panic!(); -//~^ ERROR: evaluation of constant value failed +//~^ ERROR: explicit panic static _BAR: () = panic!("panic in static"); -//~^ ERROR could not evaluate static initializer +//~^ ERROR panic in static const fn _bar() { panic!("panic in const fn"); diff --git a/tests/ui/consts/issue-66693.stderr b/tests/ui/consts/issue-66693.stderr index ea657ec34bd..7035f5653c7 100644 --- a/tests/ui/consts/issue-66693.stderr +++ b/tests/ui/consts/issue-66693.stderr @@ -10,17 +10,17 @@ error: argument to `panic!()` in a const context must have type `&str` LL | static _FOO: () = panic!(true); | ^^^^^^^^^^^^ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-66693.rs:16:15 | LL | const _: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: could not evaluate static initializer +error[E0080]: evaluation panicked: panic in static --> $DIR/issue-66693.rs:18:19 | LL | static _BAR: () = panic!("panic in static"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: panic in static + | ^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer error: argument to `panic!()` in a const context must have type `&str` --> $DIR/issue-66693.rs:11:5 diff --git a/tests/ui/consts/issue-76064.rs b/tests/ui/consts/issue-76064.rs index 3c153ad726e..b878629138c 100644 --- a/tests/ui/consts/issue-76064.rs +++ b/tests/ui/consts/issue-76064.rs @@ -1,3 +1,3 @@ -struct Bug([u8; panic!("panic")]); //~ ERROR evaluation of constant value failed +struct Bug([u8; panic!("panic")]); //~ ERROR panic fn main() {} diff --git a/tests/ui/consts/issue-76064.stderr b/tests/ui/consts/issue-76064.stderr index 786d4213f1e..c748678d43a 100644 --- a/tests/ui/consts/issue-76064.stderr +++ b/tests/ui/consts/issue-76064.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: panic --> $DIR/issue-76064.rs:1:17 | LL | struct Bug([u8; panic!("panic")]); - | ^^^^^^^^^^^^^^^ evaluation panicked: panic + | ^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-79690.64bit.stderr b/tests/ui/consts/issue-79690.64bit.stderr index d603a1dc291..7488f7b7752 100644 --- a/tests/ui/consts/issue-79690.64bit.stderr +++ b/tests/ui/consts/issue-79690.64bit.stderr @@ -1,8 +1,8 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/issue-79690.rs:30:1 | LL | const G: Fat = unsafe { Transmute { t: FOO }.u }; - | ^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { diff --git a/tests/ui/consts/issue-79690.rs b/tests/ui/consts/issue-79690.rs index 3da4cb73f11..24e3220155d 100644 --- a/tests/ui/consts/issue-79690.rs +++ b/tests/ui/consts/issue-79690.rs @@ -28,6 +28,6 @@ const FOO: &dyn Bar = &Foo { bar: false, }; const G: Fat = unsafe { Transmute { t: FOO }.u }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR dangling reference fn main() {} diff --git a/tests/ui/consts/issue-miri-1910.rs b/tests/ui/consts/issue-miri-1910.rs index d194dd3c78b..6eae885ea8a 100644 --- a/tests/ui/consts/issue-miri-1910.rs +++ b/tests/ui/consts/issue-miri-1910.rs @@ -5,7 +5,7 @@ const C: () = unsafe { let foo = Some(&42 as *const i32); let one_and_a_half_pointers = std::mem::size_of::<*const i32>()/2*3; (&foo as *const _ as *const u8).add(one_and_a_half_pointers).read(); - //~^ ERROR evaluation of constant value failed + //~^ ERROR unable to turn pointer into integer }; fn main() { diff --git a/tests/ui/consts/issue-miri-1910.stderr b/tests/ui/consts/issue-miri-1910.stderr index 52edad0c389..b541895dbcc 100644 --- a/tests/ui/consts/issue-miri-1910.stderr +++ b/tests/ui/consts/issue-miri-1910.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/issue-miri-1910.rs:7:5 | LL | (&foo as *const _ as *const u8).add(one_and_a_half_pointers).read(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/large_const_alloc.rs b/tests/ui/consts/large_const_alloc.rs index 3573a018630..c5b19dbc17f 100644 --- a/tests/ui/consts/large_const_alloc.rs +++ b/tests/ui/consts/large_const_alloc.rs @@ -9,12 +9,12 @@ const FOO: () = { // 128 TiB, unlikely anyone has that much RAM let x = [0_u8; (1 << 47) - 1]; - //~^ ERROR evaluation of constant value failed + //~^ ERROR tried to allocate more memory than available to compiler }; static FOO2: () = { let x = [0_u8; (1 << 47) - 1]; - //~^ ERROR could not evaluate static initializer + //~^ ERROR tried to allocate more memory than available to compiler }; fn main() { diff --git a/tests/ui/consts/large_const_alloc.stderr b/tests/ui/consts/large_const_alloc.stderr index f3f3de7af63..a9ef87d6c83 100644 --- a/tests/ui/consts/large_const_alloc.stderr +++ b/tests/ui/consts/large_const_alloc.stderr @@ -1,14 +1,14 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: tried to allocate more memory than available to compiler --> $DIR/large_const_alloc.rs:11:13 | LL | let x = [0_u8; (1 << 47) - 1]; - | ^^^^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: could not evaluate static initializer +error[E0080]: tried to allocate more memory than available to compiler --> $DIR/large_const_alloc.rs:16:13 | LL | let x = [0_u8; (1 << 47) - 1]; - | ^^^^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler + | ^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer error: aborting due to 2 previous errors diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.rs b/tests/ui/consts/miri_unleashed/abi-mismatch.rs index 6a46079b39b..d335991a5e6 100644 --- a/tests/ui/consts/miri_unleashed/abi-mismatch.rs +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.rs @@ -9,8 +9,8 @@ const fn call_rust_fn(my_fn: extern "Rust" fn()) { } static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); -//~^ ERROR could not evaluate static initializer -//~| NOTE calling a function with calling convention "C" using calling convention "Rust" +//~^ NOTE could not evaluate static initializer +//~| ERROR calling a function with calling convention "C" using calling convention "Rust" fn main() {} diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.stderr b/tests/ui/consts/miri_unleashed/abi-mismatch.stderr index 7d1fdcce526..d1efbad6fd4 100644 --- a/tests/ui/consts/miri_unleashed/abi-mismatch.stderr +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: calling a function with calling convention "C" using calling convention "Rust" --> $DIR/abi-mismatch.rs:11:18 | LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention "C" using calling convention "Rust" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer | note: inside `call_rust_fn` --> $DIR/abi-mismatch.rs:7:5 diff --git a/tests/ui/consts/miri_unleashed/assoc_const.stderr b/tests/ui/consts/miri_unleashed/assoc_const.stderr index 758f1a25339..9176e2e12fb 100644 --- a/tests/ui/consts/miri_unleashed/assoc_const.stderr +++ b/tests/ui/consts/miri_unleashed/assoc_const.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `drop_in_place::> - shim(Some(Vec))` failed +error[E0080]: calling non-const function ` as Drop>::drop` --> $DIR/assoc_const.rs:12:31 | LL | const F: u32 = (U::X, 42).1; - | ^ calling non-const function ` as Drop>::drop` + | ^ evaluation of `drop_in_place::> - shim(Some(Vec))` failed | note: inside `drop_in_place::<(Vec, u32)> - shim(Some((Vec, u32)))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/miri_unleashed/assoc_const_2.rs b/tests/ui/consts/miri_unleashed/assoc_const_2.rs index 1d8ed2065a4..fa8ed682d98 100644 --- a/tests/ui/consts/miri_unleashed/assoc_const_2.rs +++ b/tests/ui/consts/miri_unleashed/assoc_const_2.rs @@ -8,7 +8,7 @@ trait Foo { } trait Bar { - const F: u32 = 100 / U::X; //~ ERROR evaluation of `>::F` failed + const F: u32 = 100 / U::X; //~ ERROR attempt to divide `100_u32` by zero } impl Foo for () { diff --git a/tests/ui/consts/miri_unleashed/assoc_const_2.stderr b/tests/ui/consts/miri_unleashed/assoc_const_2.stderr index 5503f8e56f0..54baa4a00ee 100644 --- a/tests/ui/consts/miri_unleashed/assoc_const_2.stderr +++ b/tests/ui/consts/miri_unleashed/assoc_const_2.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `>::F` failed +error[E0080]: attempt to divide `100_u32` by zero --> $DIR/assoc_const_2.rs:11:20 | LL | const F: u32 = 100 / U::X; - | ^^^^^^^^^^ attempt to divide `100_u32` by zero + | ^^^^^^^^^^ evaluation of `>::F` failed note: erroneous constant encountered --> $DIR/assoc_const_2.rs:28:13 diff --git a/tests/ui/consts/miri_unleashed/box.rs b/tests/ui/consts/miri_unleashed/box.rs index 1539083f09c..d361870b58a 100644 --- a/tests/ui/consts/miri_unleashed/box.rs +++ b/tests/ui/consts/miri_unleashed/box.rs @@ -6,8 +6,7 @@ fn main() {} static TEST_BAD: &mut i32 = { &mut *(Box::new(0)) - //~^ ERROR could not evaluate static initializer - //~| NOTE calling non-const function `Box::::new` + //~^ ERROR calling non-const function `Box::::new` }; //~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/box.stderr b/tests/ui/consts/miri_unleashed/box.stderr index 25cefa036eb..d5db5eca655 100644 --- a/tests/ui/consts/miri_unleashed/box.stderr +++ b/tests/ui/consts/miri_unleashed/box.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: calling non-const function `Box::::new` --> $DIR/box.rs:8:11 | LL | &mut *(Box::new(0)) - | ^^^^^^^^^^^^^ calling non-const function `Box::::new` + | ^^^^^^^^^^^^^ could not evaluate static initializer warning: skipping const checks | diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static.rs index c66aaec8c56..6cc67094346 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.rs +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.rs @@ -8,20 +8,19 @@ use std::sync::atomic::Ordering; const MUTATE_INTERIOR_MUT: usize = { static FOO: AtomicUsize = AtomicUsize::new(0); - FOO.fetch_add(1, Ordering::Relaxed) //~ERROR evaluation of constant value failed + FOO.fetch_add(1, Ordering::Relaxed) //~ERROR calling non-const function `AtomicUsize::fetch_add` }; const READ_INTERIOR_MUT: usize = { static FOO: AtomicUsize = AtomicUsize::new(0); - unsafe { *(&FOO as *const _ as *const usize) } //~ERROR evaluation of constant value failed + unsafe { *(&FOO as *const _ as *const usize) } //~ERROR constant accesses mutable global memory }; static mut MUTABLE: u32 = 0; -const READ_MUT: u32 = unsafe { MUTABLE }; //~ERROR evaluation of constant value failed +const READ_MUT: u32 = unsafe { MUTABLE }; //~ERROR constant accesses mutable global memory // Evaluating this does not read anything mutable, but validation does, so this should error. -const REF_INTERIOR_MUT: &usize = { //~ ERROR undefined behavior - //~| NOTE encountered reference to mutable memory +const REF_INTERIOR_MUT: &usize = { //~ ERROR encountered reference to mutable memory static FOO: AtomicUsize = AtomicUsize::new(0); unsafe { &*(&FOO as *const _ as *const usize) } }; diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr index f647107094d..7765210c277 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr @@ -1,26 +1,26 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: calling non-const function `AtomicUsize::fetch_add` --> $DIR/const_refers_to_static.rs:11:5 | LL | FOO.fetch_add(1, Ordering::Relaxed) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling non-const function `AtomicUsize::fetch_add` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: constant accesses mutable global memory --> $DIR/const_refers_to_static.rs:16:14 | LL | unsafe { *(&FOO as *const _ as *const usize) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses mutable global memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: constant accesses mutable global memory --> $DIR/const_refers_to_static.rs:20:32 | LL | const READ_MUT: u32 = unsafe { MUTABLE }; - | ^^^^^^^ constant accesses mutable global memory + | ^^^^^^^ evaluation of constant value failed -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered reference to mutable memory in `const` --> $DIR/const_refers_to_static.rs:23:1 | LL | const REF_INTERIOR_MUT: &usize = { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs index 86d23d44bff..6c7e7835661 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs @@ -2,7 +2,6 @@ //@ aux-build:static_cross_crate.rs //@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" -//@ dont-require-annotations: NOTE #![feature(half_open_range_patterns_in_slices)] #![allow(static_mut_refs)] @@ -11,26 +10,25 @@ extern crate static_cross_crate; // Sneaky: reference to a mutable static. // Allowing this would be a disaster for pattern matching, we could violate exhaustiveness checking! -const SLICE_MUT: &[u8; 1] = { //~ ERROR undefined behavior - //~| NOTE encountered reference to mutable memory +const SLICE_MUT: &[u8; 1] = { + //~^ ERROR encountered reference to mutable memory unsafe { &static_cross_crate::ZERO } }; -const U8_MUT: &u8 = { //~ ERROR undefined behavior - //~| NOTE encountered reference to mutable memory +const U8_MUT: &u8 = { + //~^ ERROR encountered reference to mutable memory unsafe { &static_cross_crate::ZERO[0] } }; // Also test indirection that reads from other static. -const U8_MUT2: &u8 = { //~ ERROR undefined behavior - //~| NOTE encountered reference to mutable memory +const U8_MUT2: &u8 = { + //~^ ERROR encountered reference to mutable memory unsafe { &(*static_cross_crate::ZERO_REF)[0] } }; const U8_MUT3: &u8 = { unsafe { match static_cross_crate::OPT_ZERO { - //~^ ERROR evaluation of constant value failed - //~| NOTE constant accesses mutable global memory + //~^ ERROR constant accesses mutable global memory Some(ref u) => u, None => panic!(), } diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr index 4e5052ed470..32f8296e0fc 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr @@ -1,41 +1,41 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static_cross_crate.rs:14:1 +error[E0080]: constructing invalid value: encountered reference to mutable memory in `const` + --> $DIR/const_refers_to_static_cross_crate.rs:13:1 | LL | const SLICE_MUT: &[u8; 1] = { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static_cross_crate.rs:19:1 +error[E0080]: constructing invalid value: encountered reference to mutable memory in `const` + --> $DIR/const_refers_to_static_cross_crate.rs:18:1 | LL | const U8_MUT: &u8 = { - | ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` + | ^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static_cross_crate.rs:25:1 +error[E0080]: constructing invalid value: encountered reference to mutable memory in `const` + --> $DIR/const_refers_to_static_cross_crate.rs:24:1 | LL | const U8_MUT2: &u8 = { - | ^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` + | ^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed - --> $DIR/const_refers_to_static_cross_crate.rs:31:15 +error[E0080]: constant accesses mutable global memory + --> $DIR/const_refers_to_static_cross_crate.rs:30:15 | LL | match static_cross_crate::OPT_ZERO { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses mutable global memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 4 previous errors diff --git a/tests/ui/consts/miri_unleashed/drop.rs b/tests/ui/consts/miri_unleashed/drop.rs index ff9281358d4..c3b944ce6f1 100644 --- a/tests/ui/consts/miri_unleashed/drop.rs +++ b/tests/ui/consts/miri_unleashed/drop.rs @@ -13,8 +13,8 @@ static TEST_OK: () = { // The actual error is tested by the error-pattern above. static TEST_BAD: () = { let _v: Vec = Vec::new(); -}; //~ ERROR could not evaluate static initializer - //~| NOTE calling non-const function ` as Drop>::drop` +}; //~ NOTE could not evaluate static initializer + //~| ERROR calling non-const function ` as Drop>::drop` //~| NOTE inside `drop_in_place::> - shim(Some(Vec))` //~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/drop.stderr b/tests/ui/consts/miri_unleashed/drop.stderr index 0286c431279..e075781a15c 100644 --- a/tests/ui/consts/miri_unleashed/drop.stderr +++ b/tests/ui/consts/miri_unleashed/drop.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: calling non-const function ` as Drop>::drop` --> $DIR/drop.rs:16:1 | LL | }; - | ^ calling non-const function ` as Drop>::drop` + | ^ could not evaluate static initializer | note: inside `drop_in_place::> - shim(Some(Vec))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/miri_unleashed/extern-static.rs b/tests/ui/consts/miri_unleashed/extern-static.rs index c9d9397518e..e5d3b806487 100644 --- a/tests/ui/consts/miri_unleashed/extern-static.rs +++ b/tests/ui/consts/miri_unleashed/extern-static.rs @@ -9,13 +9,11 @@ extern "C" { // Make sure we catch accessing extern static. static TEST_READ: () = { unsafe { let _val = DATA; } - //~^ ERROR could not evaluate static initializer - //~| NOTE cannot access extern static + //~^ ERROR cannot access extern static }; static TEST_WRITE: () = { unsafe { DATA = 0; } - //~^ ERROR could not evaluate static initializer - //~| NOTE cannot access extern static + //~^ ERROR cannot access extern static }; // Just creating a reference is fine, as long as we are not reading or writing. diff --git a/tests/ui/consts/miri_unleashed/extern-static.stderr b/tests/ui/consts/miri_unleashed/extern-static.stderr index 4dbabbe44a2..44e15f71135 100644 --- a/tests/ui/consts/miri_unleashed/extern-static.stderr +++ b/tests/ui/consts/miri_unleashed/extern-static.stderr @@ -1,14 +1,14 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: cannot access extern static `DATA` --> $DIR/extern-static.rs:11:25 | LL | unsafe { let _val = DATA; } - | ^^^^ cannot access extern static `DATA` + | ^^^^ could not evaluate static initializer -error[E0080]: could not evaluate static initializer - --> $DIR/extern-static.rs:16:14 +error[E0080]: cannot access extern static `DATA` + --> $DIR/extern-static.rs:15:14 | LL | unsafe { DATA = 0; } - | ^^^^^^^^ cannot access extern static `DATA` + | ^^^^^^^^ could not evaluate static initializer error: aborting due to 2 previous errors diff --git a/tests/ui/consts/miri_unleashed/inline_asm.rs b/tests/ui/consts/miri_unleashed/inline_asm.rs index f1ce613b16e..51297aa6361 100644 --- a/tests/ui/consts/miri_unleashed/inline_asm.rs +++ b/tests/ui/consts/miri_unleashed/inline_asm.rs @@ -8,8 +8,7 @@ fn main() {} // Make sure we catch executing inline assembly. static TEST_BAD: () = { unsafe { asm!("nop"); } - //~^ ERROR could not evaluate static initializer - //~| NOTE inline assembly is not supported + //~^ ERROR inline assembly is not supported }; //~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/inline_asm.stderr b/tests/ui/consts/miri_unleashed/inline_asm.stderr index e9643f02840..df90d848432 100644 --- a/tests/ui/consts/miri_unleashed/inline_asm.stderr +++ b/tests/ui/consts/miri_unleashed/inline_asm.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: inline assembly is not supported --> $DIR/inline_asm.rs:10:14 | LL | unsafe { asm!("nop"); } - | ^^^^^^^^^^^ inline assembly is not supported + | ^^^^^^^^^^^ could not evaluate static initializer warning: skipping const checks | diff --git a/tests/ui/consts/miri_unleashed/mutable_references.rs b/tests/ui/consts/miri_unleashed/mutable_references.rs index 02a35487e8a..63d243f892c 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.rs +++ b/tests/ui/consts/miri_unleashed/mutable_references.rs @@ -11,11 +11,9 @@ use std::sync::atomic::*; // This requires walking nested statics. static FOO: &&mut u32 = &&mut 42; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE pointing to read-only memory +//~^ ERROR pointing to read-only memory static OH_YES: &mut i32 = &mut 42; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE pointing to read-only memory +//~^ ERROR pointing to read-only memory static BAR: &mut () = &mut (); //~^ ERROR encountered mutable pointer in final value of static @@ -25,12 +23,10 @@ static BOO: &mut Foo<()> = &mut Foo(()); //~^ ERROR encountered mutable pointer in final value of static const BLUNT: &mut i32 = &mut 42; -//~^ ERROR: it is undefined behavior to use this value -//~| NOTE pointing to read-only memory +//~^ ERROR: pointing to read-only memory const SUBTLE: &mut i32 = unsafe { - //~^ ERROR: it is undefined behavior to use this value - //~| NOTE constructing invalid value: encountered reference to mutable memory in `const` + //~^ ERROR: constructing invalid value: encountered reference to mutable memory in `const` static mut STATIC: i32 = 0; &mut STATIC }; @@ -42,14 +38,12 @@ struct Meh { } unsafe impl Sync for Meh {} static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; -//~^ ERROR it is undefined behavior to use this value -//~| NOTE `UnsafeCell` in read-only memory +//~^ ERROR `UnsafeCell` in read-only memory // Same with a const: // the following will never be ok! no interior mut behind consts, because // all allocs interned here will be marked immutable. const MUH: Meh = Meh { - //~^ ERROR it is undefined behavior to use this value - //~| NOTE `UnsafeCell` in read-only memory + //~^ ERROR `UnsafeCell` in read-only memory x: &UnsafeCell::new(42), }; @@ -60,25 +54,21 @@ unsafe impl Sync for Synced {} // Make sure we also catch this behind a type-erased `dyn Trait` reference. const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; -//~^ ERROR: it is undefined behavior to use this value -//~| NOTE `UnsafeCell` in read-only memory +//~^ ERROR: `UnsafeCell` in read-only memory // # Check for mutable references to read-only memory static READONLY: i32 = 0; static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; -//~^ ERROR: it is undefined behavior to use this value -//~| NOTE pointing to read-only memory +//~^ ERROR: pointing to read-only memory // # Check for consts pointing to mutable memory static mut MUTABLE: i32 = 42; -const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; //~ ERROR undefined behavior -//~| NOTE encountered reference to mutable memory +const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; //~ ERROR encountered reference to mutable memory static mut MUTABLE_REF: &mut i32 = &mut 42; const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; -//~^ ERROR evaluation of constant value failed -//~| NOTE accesses mutable global memory +//~^ ERROR accesses mutable global memory const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; //~^ ERROR mutable pointer in final value diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr index 3049be80adc..3375cc9189a 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references.stderr @@ -1,19 +1,19 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .: encountered mutable reference or box pointing to read-only memory --> $DIR/mutable_references.rs:13:1 | LL | static FOO: &&mut u32 = &&mut 42; - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered mutable reference or box pointing to read-only memory + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:16:1 +error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory + --> $DIR/mutable_references.rs:15:1 | LL | static OH_YES: &mut i32 = &mut 42; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -21,126 +21,126 @@ LL | static OH_YES: &mut i32 = &mut 42; } error: encountered mutable pointer in final value of static - --> $DIR/mutable_references.rs:19:1 + --> $DIR/mutable_references.rs:17:1 | LL | static BAR: &mut () = &mut (); | ^^^^^^^^^^^^^^^^^^^ error: encountered mutable pointer in final value of static - --> $DIR/mutable_references.rs:24:1 + --> $DIR/mutable_references.rs:22:1 | LL | static BOO: &mut Foo<()> = &mut Foo(()); | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:27:1 +error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory + --> $DIR/mutable_references.rs:25:1 | LL | const BLUNT: &mut i32 = &mut 42; - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:31:1 +error[E0080]: constructing invalid value: encountered reference to mutable memory in `const` + --> $DIR/mutable_references.rs:28:1 | LL | const SUBTLE: &mut i32 = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` + | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:44:1 +error[E0080]: constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory + --> $DIR/mutable_references.rs:40:1 | LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; - | ^^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory + | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:50:1 +error[E0080]: constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory + --> $DIR/mutable_references.rs:45:1 | LL | const MUH: Meh = Meh { - | ^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory + | ^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:62:1 +error[E0080]: constructing invalid value at ...x: encountered `UnsafeCell` in read-only memory + --> $DIR/mutable_references.rs:56:1 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ...x: encountered `UnsafeCell` in read-only memory + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:69:1 +error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory + --> $DIR/mutable_references.rs:62:1 | LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:76:1 +error[E0080]: constructing invalid value: encountered reference to mutable memory in `const` + --> $DIR/mutable_references.rs:68:1 | LL | const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: evaluation of constant value failed - --> $DIR/mutable_references.rs:79:43 +error[E0080]: constant accesses mutable global memory + --> $DIR/mutable_references.rs:70:43 | LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; - | ^^^^^^^^^^^^^ constant accesses mutable global memory + | ^^^^^^^^^^^^^ evaluation of constant value failed error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:83:1 + --> $DIR/mutable_references.rs:73:1 | LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:86:1 + --> $DIR/mutable_references.rs:76:1 | LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:106:1 + --> $DIR/mutable_references.rs:96:1 | LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:109:1 + --> $DIR/mutable_references.rs:99:1 | LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item - --> $DIR/mutable_references.rs:116:5 + --> $DIR/mutable_references.rs:106:5 | LL | *OH_YES = 99; | ^^^^^^^^^^^^ cannot assign @@ -153,67 +153,67 @@ help: skipping check that does not even have a feature gate LL | static FOO: &&mut u32 = &&mut 42; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:16:27 + --> $DIR/mutable_references.rs:15:27 | LL | static OH_YES: &mut i32 = &mut 42; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:19:23 + --> $DIR/mutable_references.rs:17:23 | LL | static BAR: &mut () = &mut (); | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:24:28 + --> $DIR/mutable_references.rs:22:28 | LL | static BOO: &mut Foo<()> = &mut Foo(()); | ^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:27:25 + --> $DIR/mutable_references.rs:25:25 | LL | const BLUNT: &mut i32 = &mut 42; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:44:28 + --> $DIR/mutable_references.rs:40:28 | LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:53:8 + --> $DIR/mutable_references.rs:47:8 | LL | x: &UnsafeCell::new(42), | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:62:27 + --> $DIR/mutable_references.rs:56:27 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:83:45 + --> $DIR/mutable_references.rs:73:45 | LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:86:46 + --> $DIR/mutable_references.rs:76:46 | LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:91:47 + --> $DIR/mutable_references.rs:81:47 | LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:103:51 + --> $DIR/mutable_references.rs:93:51 | LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; | ^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:106:49 + --> $DIR/mutable_references.rs:96:49 | LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:109:51 + --> $DIR/mutable_references.rs:99:51 | LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^ diff --git a/tests/ui/consts/miri_unleashed/mutating_global.rs b/tests/ui/consts/miri_unleashed/mutating_global.rs index 77781360374..9a88f584a58 100644 --- a/tests/ui/consts/miri_unleashed/mutating_global.rs +++ b/tests/ui/consts/miri_unleashed/mutating_global.rs @@ -7,8 +7,7 @@ static mut GLOBAL: i32 = 0; static MUTATING_GLOBAL: () = { unsafe { GLOBAL = 99 - //~^ ERROR could not evaluate static initializer - //~| NOTE modifying a static's initial value + //~^ ERROR modifying a static's initial value } }; diff --git a/tests/ui/consts/miri_unleashed/mutating_global.stderr b/tests/ui/consts/miri_unleashed/mutating_global.stderr index c38e2d44d89..bbf82543387 100644 --- a/tests/ui/consts/miri_unleashed/mutating_global.stderr +++ b/tests/ui/consts/miri_unleashed/mutating_global.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: modifying a static's initial value from another static's initializer --> $DIR/mutating_global.rs:9:9 | LL | GLOBAL = 99 - | ^^^^^^^^^^^ modifying a static's initial value from another static's initializer + | ^^^^^^^^^^^ could not evaluate static initializer error: aborting due to 1 previous error diff --git a/tests/ui/consts/miri_unleashed/non_const_fn.rs b/tests/ui/consts/miri_unleashed/non_const_fn.rs index 201647ac8d8..18bee124db4 100644 --- a/tests/ui/consts/miri_unleashed/non_const_fn.rs +++ b/tests/ui/consts/miri_unleashed/non_const_fn.rs @@ -5,8 +5,7 @@ fn foo() {} static C: () = foo(); -//~^ ERROR could not evaluate static initializer -//~| NOTE calling non-const function `foo` +//~^ ERROR calling non-const function `foo` fn main() {} diff --git a/tests/ui/consts/miri_unleashed/non_const_fn.stderr b/tests/ui/consts/miri_unleashed/non_const_fn.stderr index cc893896ecf..54e3ed9361a 100644 --- a/tests/ui/consts/miri_unleashed/non_const_fn.stderr +++ b/tests/ui/consts/miri_unleashed/non_const_fn.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: calling non-const function `foo` --> $DIR/non_const_fn.rs:7:16 | LL | static C: () = foo(); - | ^^^^^ calling non-const function `foo` + | ^^^^^ could not evaluate static initializer warning: skipping const checks | diff --git a/tests/ui/consts/miri_unleashed/ptr_arith.rs b/tests/ui/consts/miri_unleashed/ptr_arith.rs index 408aa5db24d..3f34102833b 100644 --- a/tests/ui/consts/miri_unleashed/ptr_arith.rs +++ b/tests/ui/consts/miri_unleashed/ptr_arith.rs @@ -5,16 +5,14 @@ static PTR_INT_CAST: () = { let x = &0 as *const _ as usize; - //~^ ERROR could not evaluate static initializer - //~| NOTE exposing pointers + //~^ ERROR exposing pointers let _v = x == x; }; static PTR_INT_TRANSMUTE: () = unsafe { let x: usize = std::mem::transmute(&0); let _v = x + 0; - //~^ ERROR could not evaluate static initializer - //~| NOTE unable to turn pointer into integer + //~^ ERROR unable to turn pointer into integer }; // I'd love to test pointer comparison, but that is not possible since diff --git a/tests/ui/consts/miri_unleashed/ptr_arith.stderr b/tests/ui/consts/miri_unleashed/ptr_arith.stderr index 213966f90b8..3092ab64795 100644 --- a/tests/ui/consts/miri_unleashed/ptr_arith.stderr +++ b/tests/ui/consts/miri_unleashed/ptr_arith.stderr @@ -1,14 +1,14 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: exposing pointers is not possible at compile-time --> $DIR/ptr_arith.rs:7:13 | LL | let x = &0 as *const _ as usize; - | ^^^^^^^^^^^^^^^^^^^^^^^ exposing pointers is not possible at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer -error[E0080]: could not evaluate static initializer - --> $DIR/ptr_arith.rs:15:14 +error[E0080]: unable to turn pointer into integer + --> $DIR/ptr_arith.rs:14:14 | LL | let _v = x + 0; - | ^ unable to turn pointer into integer + | ^ could not evaluate static initializer | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr b/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr index 88a734bc241..1ef20689985 100644 --- a/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr @@ -1,41 +1,41 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory --> $DIR/static-no-inner-mut.rs:8:1 | LL | static REF: &AtomicI32 = &AtomicI32::new(42); - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory + | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC0╼ │ ╾──╼ } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory --> $DIR/static-no-inner-mut.rs:11:1 | LL | static REFMUT: &mut i32 = &mut 0; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC1╼ │ ╾──╼ } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory --> $DIR/static-no-inner-mut.rs:15:1 | LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC2╼ │ ╾──╼ } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory --> $DIR/static-no-inner-mut.rs:17:1 | LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; - | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr b/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr index c4f3903e143..06f78e679b1 100644 --- a/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr @@ -1,41 +1,41 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory --> $DIR/static-no-inner-mut.rs:8:1 | LL | static REF: &AtomicI32 = &AtomicI32::new(42); - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory + | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC0╼ │ ╾──────╼ } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory --> $DIR/static-no-inner-mut.rs:11:1 | LL | static REFMUT: &mut i32 = &mut 0; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC1╼ │ ╾──────╼ } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory --> $DIR/static-no-inner-mut.rs:15:1 | LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..v: encountered `UnsafeCell` in read-only memory + | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC2╼ │ ╾──────╼ } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered mutable reference or box pointing to read-only memory --> $DIR/static-no-inner-mut.rs:17:1 | LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; - | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs b/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs index 7fa173d8d9d..0e87442f6a6 100644 --- a/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.rs @@ -6,16 +6,16 @@ use std::sync::atomic::*; static REF: &AtomicI32 = &AtomicI32::new(42); -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR `UnsafeCell` in read-only memory static REFMUT: &mut i32 = &mut 0; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR mutable reference or box pointing to read-only memory // Different way of writing this that avoids promotion. static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR `UnsafeCell` in read-only memory static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR mutable reference or box pointing to read-only memory // This one is obvious, since it is non-Sync. (It also suppresses the other errors, so it is // commented out.) diff --git a/tests/ui/consts/miri_unleashed/tls.rs b/tests/ui/consts/miri_unleashed/tls.rs index ab23a524998..8f8a1bd9618 100644 --- a/tests/ui/consts/miri_unleashed/tls.rs +++ b/tests/ui/consts/miri_unleashed/tls.rs @@ -9,8 +9,7 @@ static A: u8 = 0; // Make sure we catch accessing thread-local storage. static TEST_BAD: () = { unsafe { let _val = A; } - //~^ ERROR could not evaluate static initializer - //~| NOTE cannot access thread local static + //~^ ERROR cannot access thread local static }; // Make sure we catch taking a reference to thread-local storage. @@ -18,8 +17,7 @@ static TEST_BAD: () = { // sense at compile-time. static TEST_BAD_REF: () = { unsafe { let _val = &A; } - //~^ ERROR could not evaluate static initializer - //~| NOTE cannot access thread local static + //~^ ERROR cannot access thread local static }; fn main() {} diff --git a/tests/ui/consts/miri_unleashed/tls.stderr b/tests/ui/consts/miri_unleashed/tls.stderr index ef836544303..68b6e0745f3 100644 --- a/tests/ui/consts/miri_unleashed/tls.stderr +++ b/tests/ui/consts/miri_unleashed/tls.stderr @@ -1,14 +1,14 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: cannot access thread local static `A` --> $DIR/tls.rs:11:25 | LL | unsafe { let _val = A; } - | ^ cannot access thread local static `A` + | ^ could not evaluate static initializer -error[E0080]: could not evaluate static initializer - --> $DIR/tls.rs:20:26 +error[E0080]: cannot access thread local static `A` + --> $DIR/tls.rs:19:26 | LL | unsafe { let _val = &A; } - | ^ cannot access thread local static `A` + | ^ could not evaluate static initializer warning: skipping const checks | @@ -18,7 +18,7 @@ help: skipping check that does not even have a feature gate LL | unsafe { let _val = A; } | ^ help: skipping check that does not even have a feature gate - --> $DIR/tls.rs:20:26 + --> $DIR/tls.rs:19:26 | LL | unsafe { let _val = &A; } | ^ diff --git a/tests/ui/consts/missing_span_in_backtrace.rs b/tests/ui/consts/missing_span_in_backtrace.rs index 490eb57c24d..893dc321604 100644 --- a/tests/ui/consts/missing_span_in_backtrace.rs +++ b/tests/ui/consts/missing_span_in_backtrace.rs @@ -11,7 +11,7 @@ const X: () = { // Swap them, bytewise. unsafe { - ptr::swap_nonoverlapping( //~ ERROR evaluation of constant value failed + ptr::swap_nonoverlapping( //~ ERROR unable to copy parts of a pointer &mut ptr1 as *mut _ as *mut MaybeUninit, &mut ptr2 as *mut _ as *mut MaybeUninit, mem::size_of::<&i32>(), diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr index f802138c613..f2fc689078a 100644 --- a/tests/ui/consts/missing_span_in_backtrace.stderr +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -1,4 +1,4 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: unable to copy parts of a pointer from memory at ALLOC0 --> $DIR/missing_span_in_backtrace.rs:14:9 | 14 | / ptr::swap_nonoverlapping( @@ -6,16 +6,16 @@ error[E0080]: evaluation of constant value failed 16 | | &mut ptr2 as *mut _ as *mut MaybeUninit, 17 | | mem::size_of::<&i32>(), 18 | | ); - | |_________^ unable to copy parts of a pointer from memory at ALLOC0 + | |_________^ evaluation of constant value failed | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported note: inside `swap_nonoverlapping::compiletime::>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `std::ptr::swap_nonoverlapping_const::>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `std::ptr::copy_nonoverlapping::>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error: aborting due to 1 previous error diff --git a/tests/ui/consts/mono-reachable-invalid-const.rs b/tests/ui/consts/mono-reachable-invalid-const.rs index aabdb071bc9..aba41dabe71 100644 --- a/tests/ui/consts/mono-reachable-invalid-const.rs +++ b/tests/ui/consts/mono-reachable-invalid-const.rs @@ -5,7 +5,7 @@ struct Bar; impl Bar { const ASSERT: bool = { let b = std::convert::identity(1); - ["oops"][b]; //~ ERROR evaluation of `Bar::<0>::ASSERT` failed + ["oops"][b]; //~ ERROR index out of bounds: the length is 1 but the index is 1 true }; @@ -17,7 +17,6 @@ impl Bar { } } - fn main() { Bar::<0>::assert(); } diff --git a/tests/ui/consts/mono-reachable-invalid-const.stderr b/tests/ui/consts/mono-reachable-invalid-const.stderr index 6b7b25b59b8..c0e18766023 100644 --- a/tests/ui/consts/mono-reachable-invalid-const.stderr +++ b/tests/ui/consts/mono-reachable-invalid-const.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Bar::<0>::ASSERT` failed +error[E0080]: index out of bounds: the length is 1 but the index is 1 --> $DIR/mono-reachable-invalid-const.rs:8:9 | LL | ["oops"][b]; - | ^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | ^^^^^^^^^^^ evaluation of `Bar::<0>::ASSERT` failed note: erroneous constant encountered --> $DIR/mono-reachable-invalid-const.rs:13:19 @@ -19,7 +19,7 @@ LL | let val = Self::ASSERT; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` note: the above error was encountered while instantiating `fn Bar::<0>::assert` - --> $DIR/mono-reachable-invalid-const.rs:22:5 + --> $DIR/mono-reachable-invalid-const.rs:21:5 | LL | Bar::<0>::assert(); | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/no-ice-from-static-in-const-issue-52060.rs b/tests/ui/consts/no-ice-from-static-in-const-issue-52060.rs index e3cd8ec7d8a..2ad5d18d72d 100644 --- a/tests/ui/consts/no-ice-from-static-in-const-issue-52060.rs +++ b/tests/ui/consts/no-ice-from-static-in-const-issue-52060.rs @@ -3,7 +3,6 @@ static mut A: &'static [u32] = &[1]; static B: [u32; 1] = [0; unsafe { A.len() }]; -//~^ ERROR: evaluation of constant value failed -//~| NOTE mutable global memory +//~^ ERROR: mutable global memory fn main() {} diff --git a/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr b/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr index ca4d3224ec7..ca40b347af8 100644 --- a/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr +++ b/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: constant accesses mutable global memory --> $DIR/no-ice-from-static-in-const-issue-52060.rs:5:35 | LL | static B: [u32; 1] = [0; unsafe { A.len() }]; - | ^ constant accesses mutable global memory + | ^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs index 47511c0343d..ccbe591f97e 100644 --- a/tests/ui/consts/offset_from_ub.rs +++ b/tests/ui/consts/offset_from_ub.rs @@ -17,28 +17,30 @@ pub const DIFFERENT_ALLOC: usize = { let base_ptr: *const Struct = &uninit as *const _ as *const Struct; let uninit2 = std::mem::MaybeUninit::::uninit(); let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct; - let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) }; //~ERROR evaluation of constant value failed - //~| NOTE not both derived from the same allocation + let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) }; + //~^ ERROR not both derived from the same allocation offset as usize }; pub const NOT_PTR: usize = { - unsafe { (42 as *const u8).offset_from(&5u8) as usize } //~ ERROR evaluation of constant value failed + unsafe { (42 as *const u8).offset_from(&5u8) as usize } + //~^ ERROR not both derived from the same allocation }; pub const NOT_MULTIPLE_OF_SIZE: isize = { let data = [5u8, 6, 7]; let base_ptr = data.as_ptr(); let field_ptr = &data[1] as *const u8 as *const u16; - unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) } //~ERROR evaluation of constant value failed - //~| NOTE 1_isize cannot be divided by 2_isize without remainder + unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) } + //~^ ERROR 1_isize cannot be divided by 2_isize without remainder }; -pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC +pub const DIFFERENT_INT: isize = { + // offset_from with two different integers: like DIFFERENT_ALLOC let ptr1 = 8 as *const u8; let ptr2 = 16 as *const u8; - unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed - //~| NOTE not both derived from the same allocation + unsafe { ptr_offset_from(ptr2, ptr1) } + //~^ ERROR not both derived from the same allocation }; const OUT_OF_BOUNDS_1: isize = { @@ -46,8 +48,8 @@ const OUT_OF_BOUNDS_1: isize = { let length = 10; let end_ptr = (start_ptr).wrapping_add(length); // First ptr is out of bounds - unsafe { ptr_offset_from(end_ptr, start_ptr) } //~ERROR evaluation of constant value failed - //~| NOTE the memory range between them is not in-bounds of an allocation + unsafe { ptr_offset_from(end_ptr, start_ptr) } + //~^ ERROR the memory range between them is not in-bounds of an allocation }; const OUT_OF_BOUNDS_2: isize = { @@ -55,8 +57,8 @@ const OUT_OF_BOUNDS_2: isize = { let length = 10; let end_ptr = (start_ptr).wrapping_add(length); // Second ptr is out of bounds - unsafe { ptr_offset_from(start_ptr, end_ptr) } //~ERROR evaluation of constant value failed - //~| NOTE the memory range between them is not in-bounds of an allocation + unsafe { ptr_offset_from(start_ptr, end_ptr) } + //~^ ERROR the memory range between them is not in-bounds of an allocation }; pub const DIFFERENT_ALLOC_UNSIGNED: usize = { @@ -64,43 +66,42 @@ pub const DIFFERENT_ALLOC_UNSIGNED: usize = { let base_ptr: *const Struct = &uninit as *const _ as *const Struct; let uninit2 = std::mem::MaybeUninit::::uninit(); let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct; - unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } //~ERROR evaluation of constant value failed - //~| NOTE not both derived from the same allocation + unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } + //~^ ERROR not both derived from the same allocation }; pub const TOO_FAR_APART1: isize = { let ptr1 = &0u8 as *const u8; let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42); - unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed - //~| NOTE too far ahead + unsafe { ptr_offset_from(ptr2, ptr1) } + //~^ ERROR too far ahead }; pub const TOO_FAR_APART2: isize = { let ptr1 = &0u8 as *const u8; let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42); - unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed - //~| NOTE too far before + unsafe { ptr_offset_from(ptr1, ptr2) } + //~^ ERROR too far before }; pub const TOO_FAR_APART3: isize = { let ptr1 = &0u8 as *const u8; let ptr2 = ptr1.wrapping_offset(isize::MIN); // The result of this would be `isize::MIN`, which *does* fit in an `isize`, but its // absolute value does not. (Also anyway there cannot be an allocation of that size.) - unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed - //~| NOTE too far before + unsafe { ptr_offset_from(ptr1, ptr2) } + //~^ ERROR too far before }; const WRONG_ORDER_UNSIGNED: usize = { let a = ['a', 'b', 'c']; let p = a.as_ptr(); - unsafe { ptr_offset_from_unsigned(p, p.add(2) ) } //~ERROR evaluation of constant value failed - //~| NOTE first pointer has smaller offset than second: 0 < 8 + unsafe { ptr_offset_from_unsigned(p, p.add(2)) } + //~^ ERROR first pointer has smaller offset than second: 0 < 8 }; pub const TOO_FAR_APART_UNSIGNED: usize = { let ptr1 = &0u8 as *const u8; let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42); // This would fit into a `usize` but we still don't allow it. - unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } //~ERROR evaluation of constant value failed - //~| NOTE too far ahead + unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } //~ERROR too far ahead }; // These do NOT complain that pointers are too far apart; they pass that check (to then fail the @@ -109,13 +110,13 @@ pub const OFFSET_VERY_FAR1: isize = { let ptr1 = ptr::null::(); let ptr2 = ptr1.wrapping_offset(isize::MAX); unsafe { ptr2.offset_from(ptr1) } - //~^ ERROR evaluation of constant value failed + //~^ ERROR called on two different pointers that are not both derived from the same allocation }; pub const OFFSET_VERY_FAR2: isize = { let ptr1 = ptr::null::(); let ptr2 = ptr1.wrapping_offset(isize::MAX); unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) } - //~^ ERROR evaluation of constant value failed + //~^ ERROR ptr_offset_from` called when first pointer is too far before second }; // If the pointers are the same, OOB/null/UAF is fine. diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr index 5bfb9a1170c..134da19d81e 100644 --- a/tests/ui/consts/offset_from_ub.stderr +++ b/tests/ui/consts/offset_from_ub.stderr @@ -1,92 +1,92 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation --> $DIR/offset_from_ub.rs:20:27 | LL | let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation --> $DIR/offset_from_ub.rs:26:14 | LL | unsafe { (42 as *const u8).offset_from(&5u8) as usize } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:33:14 +error[E0080]: exact_div: 1_isize cannot be divided by 2_isize without remainder + --> $DIR/offset_from_ub.rs:34:14 | LL | unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 1_isize cannot be divided by 2_isize without remainder + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:40:14 +error[E0080]: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation + --> $DIR/offset_from_ub.rs:42:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:49:14 +error[E0080]: `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation + --> $DIR/offset_from_ub.rs:51:14 | LL | unsafe { ptr_offset_from(end_ptr, start_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:58:14 +error[E0080]: `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation + --> $DIR/offset_from_ub.rs:60:14 | LL | unsafe { ptr_offset_from(start_ptr, end_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:67:14 +error[E0080]: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation + --> $DIR/offset_from_ub.rs:69:14 | LL | unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:74:14 +error[E0080]: `ptr_offset_from` called when first pointer is too far ahead of second + --> $DIR/offset_from_ub.rs:76:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far ahead of second + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:80:14 +error[E0080]: `ptr_offset_from` called when first pointer is too far before second + --> $DIR/offset_from_ub.rs:82:14 | LL | unsafe { ptr_offset_from(ptr1, ptr2) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:88:14 +error[E0080]: `ptr_offset_from` called when first pointer is too far before second + --> $DIR/offset_from_ub.rs:90:14 | LL | unsafe { ptr_offset_from(ptr1, ptr2) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:95:14 +error[E0080]: `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8 + --> $DIR/offset_from_ub.rs:97:14 | -LL | unsafe { ptr_offset_from_unsigned(p, p.add(2) ) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8 +LL | unsafe { ptr_offset_from_unsigned(p, p.add(2)) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:102:14 +error[E0080]: `ptr_offset_from_unsigned` called when first pointer is too far ahead of second + --> $DIR/offset_from_ub.rs:104:14 | LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:111:14 +error[E0080]: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation + --> $DIR/offset_from_ub.rs:112:14 | LL | unsafe { ptr2.offset_from(ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL -error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:117:14 +error[E0080]: `ptr_offset_from` called when first pointer is too far before second + --> $DIR/offset_from_ub.rs:118:14 | LL | unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr index 31a2a36a669..86d43c80e66 100644 --- a/tests/ui/consts/offset_ub.stderr +++ b/tests/ui/consts/offset_ub.stderr @@ -1,68 +1,68 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC0 which is at the beginning of the allocation --> $DIR/offset_ub.rs:8:46 | LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC0 which is at the beginning of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got ALLOC1 which is only 1 byte from the end of the allocation --> $DIR/offset_ub.rs:9:43 | LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got ALLOC1 which is only 1 byte from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got ALLOC2 which is only $BYTES bytes from the end of the allocation --> $DIR/offset_ub.rs:10:45 | LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got ALLOC2 which is only $BYTES bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` --> $DIR/offset_ub.rs:12:43 | LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` --> $DIR/offset_ub.rs:13:44 | LL | pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/offset_ub.rs:14:56 | LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/offset_ub.rs:15:57 | LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which is only $BYTES bytes from the beginning of the allocation --> $DIR/offset_ub.rs:16:49 | LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which is only $BYTES bytes from the beginning of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes --> $DIR/offset_ub.rs:18:50 | LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/offset_ub.rs:19:42 | LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/offset_ub.rs:22:47 | LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 11 previous errors diff --git a/tests/ui/consts/overflowing-consts.noopt.stderr b/tests/ui/consts/overflowing-consts.noopt.stderr index 81f22944adb..134ebad5c7b 100644 --- a/tests/ui/consts/overflowing-consts.noopt.stderr +++ b/tests/ui/consts/overflowing-consts.noopt.stderr @@ -1,1022 +1,1022 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:19:22 +error[E0080]: attempt to shift left by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:18:22 | LL | const _NI8_SHL: i8 = 1i8 << 8; - | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:20:26 +error[E0080]: attempt to shift left by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:19:26 | LL | const _NI8_SHL_P: &i8 = &(1i8 << 8); - | ^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:22:24 +error[E0080]: attempt to shift left by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:21:24 | LL | const _NI16_SHL: i16 = 1i16 << 16; - | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:23:28 +error[E0080]: attempt to shift left by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:22:28 | LL | const _NI16_SHL_P: &i16 = &(1i16 << 16); - | ^^^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:25:24 +error[E0080]: attempt to shift left by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:24:24 | LL | const _NI32_SHL: i32 = 1i32 << 32; - | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:26:28 +error[E0080]: attempt to shift left by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:25:28 | LL | const _NI32_SHL_P: &i32 = &(1i32 << 32); - | ^^^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:28:24 +error[E0080]: attempt to shift left by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:27:24 | LL | const _NI64_SHL: i64 = 1i64 << 64; - | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:29:28 +error[E0080]: attempt to shift left by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:28:28 | LL | const _NI64_SHL_P: &i64 = &(1i64 << 64); - | ^^^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:31:26 +error[E0080]: attempt to shift left by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:30:26 | LL | const _NI128_SHL: i128 = 1i128 << 128; - | ^^^^^^^^^^^^ attempt to shift left by `128_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:32:30 +error[E0080]: attempt to shift left by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:31:30 | LL | const _NI128_SHL_P: &i128 = &(1i128 << 128); - | ^^^^^^^^^^^^^^ attempt to shift left by `128_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:34:22 +error[E0080]: attempt to shift left by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:33:22 | LL | const _NU8_SHL: u8 = 1u8 << 8; - | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:35:26 +error[E0080]: attempt to shift left by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:34:26 | LL | const _NU8_SHL_P: &u8 = &(1u8 << 8); - | ^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:37:24 +error[E0080]: attempt to shift left by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:36:24 | LL | const _NU16_SHL: u16 = 1u16 << 16; - | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:38:28 +error[E0080]: attempt to shift left by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:37:28 | LL | const _NU16_SHL_P: &u16 = &(1u16 << 16); - | ^^^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:40:24 +error[E0080]: attempt to shift left by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:39:24 | LL | const _NU32_SHL: u32 = 1u32 << 32; - | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:41:28 +error[E0080]: attempt to shift left by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:40:28 | LL | const _NU32_SHL_P: &u32 = &(1u32 << 32); - | ^^^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:43:24 +error[E0080]: attempt to shift left by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:42:24 | LL | const _NU64_SHL: u64 = 1u64 << 64; - | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:44:28 +error[E0080]: attempt to shift left by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:43:28 | LL | const _NU64_SHL_P: &u64 = &(1u64 << 64); - | ^^^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:46:26 +error[E0080]: attempt to shift left by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:45:26 | LL | const _NU128_SHL: u128 = 1u128 << 128; - | ^^^^^^^^^^^^ attempt to shift left by `128_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:47:30 +error[E0080]: attempt to shift left by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:46:30 | LL | const _NU128_SHL_P: &u128 = &(1u128 << 128); - | ^^^^^^^^^^^^^^ attempt to shift left by `128_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:49:28 +error[E0080]: attempt to shift left by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:48:28 | LL | const _NISIZE_SHL: isize = 1isize << BITS; - | ^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:50:32 +error[E0080]: attempt to shift left by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:49:32 | LL | const _NISIZE_SHL_P: &isize = &(1isize << BITS); - | ^^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:52:28 +error[E0080]: attempt to shift left by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:51:28 | LL | const _NUSIZE_SHL: usize = 1usize << BITS; - | ^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:53:32 +error[E0080]: attempt to shift left by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:52:32 | LL | const _NUSIZE_SHL_P: &usize = &(1usize << BITS); - | ^^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:57:22 +error[E0080]: attempt to shift right by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:55:22 | LL | const _NI8_SHR: i8 = 1i8 >> 8; - | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:58:26 +error[E0080]: attempt to shift right by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:56:26 | LL | const _NI8_SHR_P: &i8 = &(1i8 >> 8); - | ^^^^^^^^^^ attempt to shift right by `8_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:60:24 +error[E0080]: attempt to shift right by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:58:24 | LL | const _NI16_SHR: i16 = 1i16 >> 16; - | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:61:28 +error[E0080]: attempt to shift right by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:59:28 | LL | const _NI16_SHR_P: &i16 = &(1i16 >> 16); - | ^^^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:63:24 +error[E0080]: attempt to shift right by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:61:24 | LL | const _NI32_SHR: i32 = 1i32 >> 32; - | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:64:28 +error[E0080]: attempt to shift right by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:62:28 | LL | const _NI32_SHR_P: &i32 = &(1i32 >> 32); - | ^^^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:66:24 +error[E0080]: attempt to shift right by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:64:24 | LL | const _NI64_SHR: i64 = 1i64 >> 64; - | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:67:28 +error[E0080]: attempt to shift right by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:65:28 | LL | const _NI64_SHR_P: &i64 = &(1i64 >> 64); - | ^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:69:26 +error[E0080]: attempt to shift right by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:67:26 | LL | const _NI128_SHR: i128 = 1i128 >> 128; - | ^^^^^^^^^^^^ attempt to shift right by `128_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:70:30 +error[E0080]: attempt to shift right by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:68:30 | LL | const _NI128_SHR_P: &i128 = &(1i128 >> 128); - | ^^^^^^^^^^^^^^ attempt to shift right by `128_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:72:22 +error[E0080]: attempt to shift right by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:70:22 | LL | const _NU8_SHR: u8 = 1u8 >> 8; - | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:73:26 +error[E0080]: attempt to shift right by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:71:26 | LL | const _NU8_SHR_P: &u8 = &(1u8 >> 8); - | ^^^^^^^^^^ attempt to shift right by `8_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:75:24 +error[E0080]: attempt to shift right by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:73:24 | LL | const _NU16_SHR: u16 = 1u16 >> 16; - | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:76:28 +error[E0080]: attempt to shift right by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:74:28 | LL | const _NU16_SHR_P: &u16 = &(1u16 >> 16); - | ^^^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:78:24 +error[E0080]: attempt to shift right by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:76:24 | LL | const _NU32_SHR: u32 = 1u32 >> 32; - | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:79:28 +error[E0080]: attempt to shift right by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:77:28 | LL | const _NU32_SHR_P: &u32 = &(1u32 >> 32); - | ^^^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:81:24 +error[E0080]: attempt to shift right by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:79:24 | LL | const _NU64_SHR: u64 = 1u64 >> 64; - | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:82:28 +error[E0080]: attempt to shift right by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:80:28 | LL | const _NU64_SHR_P: &u64 = &(1u64 >> 64); - | ^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:84:26 +error[E0080]: attempt to shift right by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:82:26 | LL | const _NU128_SHR: u128 = 1u128 >> 128; - | ^^^^^^^^^^^^ attempt to shift right by `128_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:85:30 +error[E0080]: attempt to shift right by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:83:30 | LL | const _NU128_SHR_P: &u128 = &(1u128 >> 128); - | ^^^^^^^^^^^^^^ attempt to shift right by `128_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:87:28 +error[E0080]: attempt to shift right by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:85:28 | LL | const _NISIZE_SHR: isize = 1isize >> BITS; - | ^^^^^^^^^^^^^^ attempt to shift right by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:88:32 +error[E0080]: attempt to shift right by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:86:32 | LL | const _NISIZE_SHR_P: &isize = &(1isize >> BITS); - | ^^^^^^^^^^^^^^^^ attempt to shift right by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:90:28 +error[E0080]: attempt to shift right by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:88:28 | LL | const _NUSIZE_SHR: usize = 1usize >> BITS; - | ^^^^^^^^^^^^^^ attempt to shift right by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:91:32 +error[E0080]: attempt to shift right by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:89:32 | LL | const _NUSIZE_SHR_P: &usize = &(1usize >> BITS); - | ^^^^^^^^^^^^^^^^ attempt to shift right by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:95:22 +error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:92:22 | LL | const _NI8_ADD: i8 = 1i8 + i8::MAX; - | ^^^^^^^^^^^^^ attempt to compute `1_i8 + i8::MAX`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:96:26 +error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:93:26 | LL | const _NI8_ADD_P: &i8 = &(1i8 + i8::MAX); - | ^^^^^^^^^^^^^^^ attempt to compute `1_i8 + i8::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:98:24 +error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:95:24 | LL | const _NI16_ADD: i16 = 1i16 + i16::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_i16 + i16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:99:28 +error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:96:28 | LL | const _NI16_ADD_P: &i16 = &(1i16 + i16::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_i16 + i16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:101:24 +error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:98:24 | LL | const _NI32_ADD: i32 = 1i32 + i32::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_i32 + i32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:102:28 +error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:99:28 | LL | const _NI32_ADD_P: &i32 = &(1i32 + i32::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_i32 + i32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:104:24 +error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:101:24 | LL | const _NI64_ADD: i64 = 1i64 + i64::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_i64 + i64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:105:28 +error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:102:28 | LL | const _NI64_ADD_P: &i64 = &(1i64 + i64::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_i64 + i64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:107:26 +error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:104:26 | LL | const _NI128_ADD: i128 = 1i128 + i128::MAX; - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_i128 + i128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:108:30 +error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:105:30 | LL | const _NI128_ADD_P: &i128 = &(1i128 + i128::MAX); - | ^^^^^^^^^^^^^^^^^^^ attempt to compute `1_i128 + i128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:110:22 +error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:107:22 | LL | const _NU8_ADD: u8 = 1u8 + u8::MAX; - | ^^^^^^^^^^^^^ attempt to compute `1_u8 + u8::MAX`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:111:26 +error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:108:26 | LL | const _NU8_ADD_P: &u8 = &(1u8 + u8::MAX); - | ^^^^^^^^^^^^^^^ attempt to compute `1_u8 + u8::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:113:24 +error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:110:24 | LL | const _NU16_ADD: u16 = 1u16 + u16::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_u16 + u16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:114:28 +error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:111:28 | LL | const _NU16_ADD_P: &u16 = &(1u16 + u16::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_u16 + u16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:116:24 +error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:113:24 | LL | const _NU32_ADD: u32 = 1u32 + u32::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_u32 + u32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:117:28 +error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:114:28 | LL | const _NU32_ADD_P: &u32 = &(1u32 + u32::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_u32 + u32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:119:24 +error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:116:24 | LL | const _NU64_ADD: u64 = 1u64 + u64::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_u64 + u64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:120:28 +error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:117:28 | LL | const _NU64_ADD_P: &u64 = &(1u64 + u64::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_u64 + u64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:122:26 +error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:119:26 | LL | const _NU128_ADD: u128 = 1u128 + u128::MAX; - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_u128 + u128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:123:30 +error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:120:30 | LL | const _NU128_ADD_P: &u128 = &(1u128 + u128::MAX); - | ^^^^^^^^^^^^^^^^^^^ attempt to compute `1_u128 + u128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:125:28 +error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:122:28 | LL | const _NISIZE_ADD: isize = 1isize + isize::MAX; - | ^^^^^^^^^^^^^^^^^^^ attempt to compute `1_isize + isize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:126:32 +error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:123:32 | LL | const _NISIZE_ADD_P: &isize = &(1isize + isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `1_isize + isize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:128:28 +error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:125:28 | LL | const _NUSIZE_ADD: usize = 1usize + usize::MAX; - | ^^^^^^^^^^^^^^^^^^^ attempt to compute `1_usize + usize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:129:32 +error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:126:32 | LL | const _NUSIZE_ADD_P: &usize = &(1usize + usize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `1_usize + usize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:133:22 +error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:129:22 | LL | const _NI8_SUB: i8 = -5i8 - i8::MAX; - | ^^^^^^^^^^^^^^ attempt to compute `-5_i8 - i8::MAX`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:134:26 +error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:130:26 | LL | const _NI8_SUB_P: &i8 = &(-5i8 - i8::MAX); - | ^^^^^^^^^^^^^^^^ attempt to compute `-5_i8 - i8::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:136:24 +error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:132:24 | LL | const _NI16_SUB: i16 = -5i16 - i16::MAX; - | ^^^^^^^^^^^^^^^^ attempt to compute `-5_i16 - i16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:137:28 +error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:133:28 | LL | const _NI16_SUB_P: &i16 = &(-5i16 - i16::MAX); - | ^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i16 - i16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:139:24 +error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:135:24 | LL | const _NI32_SUB: i32 = -5i32 - i32::MAX; - | ^^^^^^^^^^^^^^^^ attempt to compute `-5_i32 - i32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:140:28 +error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:136:28 | LL | const _NI32_SUB_P: &i32 = &(-5i32 - i32::MAX); - | ^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i32 - i32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:142:24 +error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:138:24 | LL | const _NI64_SUB: i64 = -5i64 - i64::MAX; - | ^^^^^^^^^^^^^^^^ attempt to compute `-5_i64 - i64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:143:28 +error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:139:28 | LL | const _NI64_SUB_P: &i64 = &(-5i64 - i64::MAX); - | ^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i64 - i64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:145:26 +error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:141:26 | LL | const _NI128_SUB: i128 = -5i128 - i128::MAX; - | ^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i128 - i128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:146:30 +error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:142:30 | LL | const _NI128_SUB_P: &i128 = &(-5i128 - i128::MAX); - | ^^^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i128 - i128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:148:22 +error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow + --> $DIR/overflowing-consts.rs:144:22 | LL | const _NU8_SUB: u8 = 1u8 - 5; - | ^^^^^^^ attempt to compute `1_u8 - 5_u8`, which would overflow + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:149:26 +error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow + --> $DIR/overflowing-consts.rs:145:26 | LL | const _NU8_SUB_P: &u8 = &(1u8 - 5); - | ^^^^^^^^^ attempt to compute `1_u8 - 5_u8`, which would overflow + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:151:24 +error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow + --> $DIR/overflowing-consts.rs:147:24 | LL | const _NU16_SUB: u16 = 1u16 - 5; - | ^^^^^^^^ attempt to compute `1_u16 - 5_u16`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:152:28 +error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow + --> $DIR/overflowing-consts.rs:148:28 | LL | const _NU16_SUB_P: &u16 = &(1u16 - 5); - | ^^^^^^^^^^ attempt to compute `1_u16 - 5_u16`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:154:24 +error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow + --> $DIR/overflowing-consts.rs:150:24 | LL | const _NU32_SUB: u32 = 1u32 - 5; - | ^^^^^^^^ attempt to compute `1_u32 - 5_u32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:155:28 +error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow + --> $DIR/overflowing-consts.rs:151:28 | LL | const _NU32_SUB_P: &u32 = &(1u32 - 5); - | ^^^^^^^^^^ attempt to compute `1_u32 - 5_u32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:157:24 +error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow + --> $DIR/overflowing-consts.rs:153:24 | LL | const _NU64_SUB: u64 = 1u64 - 5; - | ^^^^^^^^ attempt to compute `1_u64 - 5_u64`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:158:28 +error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow + --> $DIR/overflowing-consts.rs:154:28 | LL | const _NU64_SUB_P: &u64 = &(1u64 - 5); - | ^^^^^^^^^^ attempt to compute `1_u64 - 5_u64`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:160:26 +error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow + --> $DIR/overflowing-consts.rs:156:26 | LL | const _NU128_SUB: u128 = 1u128 - 5; - | ^^^^^^^^^ attempt to compute `1_u128 - 5_u128`, which would overflow + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:161:30 +error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow + --> $DIR/overflowing-consts.rs:157:30 | LL | const _NU128_SUB_P: &u128 = &(1u128 - 5); - | ^^^^^^^^^^^ attempt to compute `1_u128 - 5_u128`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:163:28 +error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:159:28 | LL | const _NISIZE_SUB: isize = -5isize - isize::MAX; - | ^^^^^^^^^^^^^^^^^^^^ attempt to compute `-5_isize - isize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:164:32 +error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:160:32 | LL | const _NISIZE_SUB_P: &isize = &(-5isize - isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `-5_isize - isize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:166:28 +error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow + --> $DIR/overflowing-consts.rs:162:28 | -LL | const _NUSIZE_SUB: usize = 1usize - 5 ; - | ^^^^^^^^^^ attempt to compute `1_usize - 5_usize`, which would overflow +LL | const _NUSIZE_SUB: usize = 1usize - 5; + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:167:32 +error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow + --> $DIR/overflowing-consts.rs:163:32 | -LL | const _NUSIZE_SUB_P: &usize = &(1usize - 5 ); - | ^^^^^^^^^^^^^ attempt to compute `1_usize - 5_usize`, which would overflow +LL | const _NUSIZE_SUB_P: &usize = &(1usize - 5); + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:171:22 +error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow + --> $DIR/overflowing-consts.rs:166:22 | LL | const _NI8_MUL: i8 = i8::MAX * 5; - | ^^^^^^^^^^^ attempt to compute `i8::MAX * 5_i8`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:172:26 +error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow + --> $DIR/overflowing-consts.rs:167:26 | LL | const _NI8_MUL_P: &i8 = &(i8::MAX * 5); - | ^^^^^^^^^^^^^ attempt to compute `i8::MAX * 5_i8`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:174:24 +error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow + --> $DIR/overflowing-consts.rs:169:24 | LL | const _NI16_MUL: i16 = i16::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `i16::MAX * 5_i16`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:175:28 +error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow + --> $DIR/overflowing-consts.rs:170:28 | LL | const _NI16_MUL_P: &i16 = &(i16::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `i16::MAX * 5_i16`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:177:24 +error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow + --> $DIR/overflowing-consts.rs:172:24 | LL | const _NI32_MUL: i32 = i32::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `i32::MAX * 5_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:178:28 +error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow + --> $DIR/overflowing-consts.rs:173:28 | LL | const _NI32_MUL_P: &i32 = &(i32::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `i32::MAX * 5_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:180:24 +error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow + --> $DIR/overflowing-consts.rs:175:24 | LL | const _NI64_MUL: i64 = i64::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `i64::MAX * 5_i64`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:181:28 +error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow + --> $DIR/overflowing-consts.rs:176:28 | LL | const _NI64_MUL_P: &i64 = &(i64::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `i64::MAX * 5_i64`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:183:26 +error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow + --> $DIR/overflowing-consts.rs:178:26 | LL | const _NI128_MUL: i128 = i128::MAX * 5; - | ^^^^^^^^^^^^^ attempt to compute `i128::MAX * 5_i128`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:184:30 +error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow + --> $DIR/overflowing-consts.rs:179:30 | LL | const _NI128_MUL_P: &i128 = &(i128::MAX * 5); - | ^^^^^^^^^^^^^^^ attempt to compute `i128::MAX * 5_i128`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:186:22 +error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow + --> $DIR/overflowing-consts.rs:181:22 | LL | const _NU8_MUL: u8 = u8::MAX * 5; - | ^^^^^^^^^^^ attempt to compute `u8::MAX * 5_u8`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:187:26 +error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow + --> $DIR/overflowing-consts.rs:182:26 | LL | const _NU8_MUL_P: &u8 = &(u8::MAX * 5); - | ^^^^^^^^^^^^^ attempt to compute `u8::MAX * 5_u8`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:189:24 +error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow + --> $DIR/overflowing-consts.rs:184:24 | LL | const _NU16_MUL: u16 = u16::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `u16::MAX * 5_u16`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:190:28 +error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow + --> $DIR/overflowing-consts.rs:185:28 | LL | const _NU16_MUL_P: &u16 = &(u16::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `u16::MAX * 5_u16`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:192:24 +error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow + --> $DIR/overflowing-consts.rs:187:24 | LL | const _NU32_MUL: u32 = u32::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `u32::MAX * 5_u32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:193:28 +error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow + --> $DIR/overflowing-consts.rs:188:28 | LL | const _NU32_MUL_P: &u32 = &(u32::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `u32::MAX * 5_u32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:195:24 +error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow + --> $DIR/overflowing-consts.rs:190:24 | LL | const _NU64_MUL: u64 = u64::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `u64::MAX * 5_u64`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:196:28 +error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow + --> $DIR/overflowing-consts.rs:191:28 | LL | const _NU64_MUL_P: &u64 = &(u64::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `u64::MAX * 5_u64`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:198:26 +error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow + --> $DIR/overflowing-consts.rs:193:26 | LL | const _NU128_MUL: u128 = u128::MAX * 5; - | ^^^^^^^^^^^^^ attempt to compute `u128::MAX * 5_u128`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:199:30 +error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow + --> $DIR/overflowing-consts.rs:194:30 | LL | const _NU128_MUL_P: &u128 = &(u128::MAX * 5); - | ^^^^^^^^^^^^^^^ attempt to compute `u128::MAX * 5_u128`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:201:28 +error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow + --> $DIR/overflowing-consts.rs:196:28 | LL | const _NISIZE_MUL: isize = isize::MAX * 5; - | ^^^^^^^^^^^^^^ attempt to compute `isize::MAX * 5_isize`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:202:32 +error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow + --> $DIR/overflowing-consts.rs:197:32 | LL | const _NISIZE_MUL_P: &isize = &(isize::MAX * 5); - | ^^^^^^^^^^^^^^^^ attempt to compute `isize::MAX * 5_isize`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:204:28 +error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow + --> $DIR/overflowing-consts.rs:199:28 | LL | const _NUSIZE_MUL: usize = usize::MAX * 5; - | ^^^^^^^^^^^^^^ attempt to compute `usize::MAX * 5_usize`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:205:32 +error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow + --> $DIR/overflowing-consts.rs:200:32 | LL | const _NUSIZE_MUL_P: &usize = &(usize::MAX * 5); - | ^^^^^^^^^^^^^^^^ attempt to compute `usize::MAX * 5_usize`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:209:22 +error[E0080]: attempt to divide `1_i8` by zero + --> $DIR/overflowing-consts.rs:203:22 | LL | const _NI8_DIV: i8 = 1i8 / 0; - | ^^^^^^^ attempt to divide `1_i8` by zero + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:210:26 +error[E0080]: attempt to divide `1_i8` by zero + --> $DIR/overflowing-consts.rs:204:26 | LL | const _NI8_DIV_P: &i8 = &(1i8 / 0); - | ^^^^^^^^^ attempt to divide `1_i8` by zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:212:24 +error[E0080]: attempt to divide `1_i16` by zero + --> $DIR/overflowing-consts.rs:206:24 | LL | const _NI16_DIV: i16 = 1i16 / 0; - | ^^^^^^^^ attempt to divide `1_i16` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:213:28 +error[E0080]: attempt to divide `1_i16` by zero + --> $DIR/overflowing-consts.rs:207:28 | LL | const _NI16_DIV_P: &i16 = &(1i16 / 0); - | ^^^^^^^^^^ attempt to divide `1_i16` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:215:24 +error[E0080]: attempt to divide `1_i32` by zero + --> $DIR/overflowing-consts.rs:209:24 | LL | const _NI32_DIV: i32 = 1i32 / 0; - | ^^^^^^^^ attempt to divide `1_i32` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:216:28 +error[E0080]: attempt to divide `1_i32` by zero + --> $DIR/overflowing-consts.rs:210:28 | LL | const _NI32_DIV_P: &i32 = &(1i32 / 0); - | ^^^^^^^^^^ attempt to divide `1_i32` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:218:24 +error[E0080]: attempt to divide `1_i64` by zero + --> $DIR/overflowing-consts.rs:212:24 | LL | const _NI64_DIV: i64 = 1i64 / 0; - | ^^^^^^^^ attempt to divide `1_i64` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:219:28 +error[E0080]: attempt to divide `1_i64` by zero + --> $DIR/overflowing-consts.rs:213:28 | LL | const _NI64_DIV_P: &i64 = &(1i64 / 0); - | ^^^^^^^^^^ attempt to divide `1_i64` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:221:26 +error[E0080]: attempt to divide `1_i128` by zero + --> $DIR/overflowing-consts.rs:215:26 | LL | const _NI128_DIV: i128 = 1i128 / 0; - | ^^^^^^^^^ attempt to divide `1_i128` by zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:222:30 +error[E0080]: attempt to divide `1_i128` by zero + --> $DIR/overflowing-consts.rs:216:30 | LL | const _NI128_DIV_P: &i128 = &(1i128 / 0); - | ^^^^^^^^^^^ attempt to divide `1_i128` by zero + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:224:22 +error[E0080]: attempt to divide `1_u8` by zero + --> $DIR/overflowing-consts.rs:218:22 | LL | const _NU8_DIV: u8 = 1u8 / 0; - | ^^^^^^^ attempt to divide `1_u8` by zero + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:225:26 +error[E0080]: attempt to divide `1_u8` by zero + --> $DIR/overflowing-consts.rs:219:26 | LL | const _NU8_DIV_P: &u8 = &(1u8 / 0); - | ^^^^^^^^^ attempt to divide `1_u8` by zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:227:24 +error[E0080]: attempt to divide `1_u16` by zero + --> $DIR/overflowing-consts.rs:221:24 | LL | const _NU16_DIV: u16 = 1u16 / 0; - | ^^^^^^^^ attempt to divide `1_u16` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:228:28 +error[E0080]: attempt to divide `1_u16` by zero + --> $DIR/overflowing-consts.rs:222:28 | LL | const _NU16_DIV_P: &u16 = &(1u16 / 0); - | ^^^^^^^^^^ attempt to divide `1_u16` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:230:24 +error[E0080]: attempt to divide `1_u32` by zero + --> $DIR/overflowing-consts.rs:224:24 | LL | const _NU32_DIV: u32 = 1u32 / 0; - | ^^^^^^^^ attempt to divide `1_u32` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:231:28 +error[E0080]: attempt to divide `1_u32` by zero + --> $DIR/overflowing-consts.rs:225:28 | LL | const _NU32_DIV_P: &u32 = &(1u32 / 0); - | ^^^^^^^^^^ attempt to divide `1_u32` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:233:24 +error[E0080]: attempt to divide `1_u64` by zero + --> $DIR/overflowing-consts.rs:227:24 | LL | const _NU64_DIV: u64 = 1u64 / 0; - | ^^^^^^^^ attempt to divide `1_u64` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:234:28 +error[E0080]: attempt to divide `1_u64` by zero + --> $DIR/overflowing-consts.rs:228:28 | LL | const _NU64_DIV_P: &u64 = &(1u64 / 0); - | ^^^^^^^^^^ attempt to divide `1_u64` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:236:26 +error[E0080]: attempt to divide `1_u128` by zero + --> $DIR/overflowing-consts.rs:230:26 | LL | const _NU128_DIV: u128 = 1u128 / 0; - | ^^^^^^^^^ attempt to divide `1_u128` by zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:237:30 +error[E0080]: attempt to divide `1_u128` by zero + --> $DIR/overflowing-consts.rs:231:30 | LL | const _NU128_DIV_P: &u128 = &(1u128 / 0); - | ^^^^^^^^^^^ attempt to divide `1_u128` by zero + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:239:28 +error[E0080]: attempt to divide `1_isize` by zero + --> $DIR/overflowing-consts.rs:233:28 | LL | const _NISIZE_DIV: isize = 1isize / 0; - | ^^^^^^^^^^ attempt to divide `1_isize` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:240:32 +error[E0080]: attempt to divide `1_isize` by zero + --> $DIR/overflowing-consts.rs:234:32 | LL | const _NISIZE_DIV_P: &isize = &(1isize / 0); - | ^^^^^^^^^^^^ attempt to divide `1_isize` by zero + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:242:28 +error[E0080]: attempt to divide `1_usize` by zero + --> $DIR/overflowing-consts.rs:236:28 | LL | const _NUSIZE_DIV: usize = 1usize / 0; - | ^^^^^^^^^^ attempt to divide `1_usize` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:243:32 +error[E0080]: attempt to divide `1_usize` by zero + --> $DIR/overflowing-consts.rs:237:32 | LL | const _NUSIZE_DIV_P: &usize = &(1usize / 0); - | ^^^^^^^^^^^^ attempt to divide `1_usize` by zero + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:246:22 +error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero + --> $DIR/overflowing-consts.rs:240:22 | LL | const _NI8_MOD: i8 = 1i8 % 0; - | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:247:26 +error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero + --> $DIR/overflowing-consts.rs:241:26 | LL | const _NI8_MOD_P: &i8 = &(1i8 % 0); - | ^^^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:249:24 +error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero + --> $DIR/overflowing-consts.rs:243:24 | LL | const _NI16_MOD: i16 = 1i16 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:250:28 +error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero + --> $DIR/overflowing-consts.rs:244:28 | LL | const _NI16_MOD_P: &i16 = &(1i16 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:252:24 +error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero + --> $DIR/overflowing-consts.rs:246:24 | LL | const _NI32_MOD: i32 = 1i32 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:253:28 +error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero + --> $DIR/overflowing-consts.rs:247:28 | LL | const _NI32_MOD_P: &i32 = &(1i32 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:255:24 +error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero + --> $DIR/overflowing-consts.rs:249:24 | LL | const _NI64_MOD: i64 = 1i64 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:256:28 +error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero + --> $DIR/overflowing-consts.rs:250:28 | LL | const _NI64_MOD_P: &i64 = &(1i64 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:258:26 +error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero + --> $DIR/overflowing-consts.rs:252:26 | LL | const _NI128_MOD: i128 = 1i128 % 0; - | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:259:30 +error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero + --> $DIR/overflowing-consts.rs:253:30 | LL | const _NI128_MOD_P: &i128 = &(1i128 % 0); - | ^^^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:261:22 +error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero + --> $DIR/overflowing-consts.rs:255:22 | LL | const _NU8_MOD: u8 = 1u8 % 0; - | ^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:262:26 +error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero + --> $DIR/overflowing-consts.rs:256:26 | LL | const _NU8_MOD_P: &u8 = &(1u8 % 0); - | ^^^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:264:24 +error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero + --> $DIR/overflowing-consts.rs:258:24 | LL | const _NU16_MOD: u16 = 1u16 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:265:28 +error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero + --> $DIR/overflowing-consts.rs:259:28 | LL | const _NU16_MOD_P: &u16 = &(1u16 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:267:24 +error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero + --> $DIR/overflowing-consts.rs:261:24 | LL | const _NU32_MOD: u32 = 1u32 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:268:28 +error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero + --> $DIR/overflowing-consts.rs:262:28 | LL | const _NU32_MOD_P: &u32 = &(1u32 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:270:24 +error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero + --> $DIR/overflowing-consts.rs:264:24 | LL | const _NU64_MOD: u64 = 1u64 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:271:28 +error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero + --> $DIR/overflowing-consts.rs:265:28 | LL | const _NU64_MOD_P: &u64 = &(1u64 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:273:26 +error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero + --> $DIR/overflowing-consts.rs:267:26 | LL | const _NU128_MOD: u128 = 1u128 % 0; - | ^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:274:30 +error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero + --> $DIR/overflowing-consts.rs:268:30 | LL | const _NU128_MOD_P: &u128 = &(1u128 % 0); - | ^^^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:276:28 +error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero + --> $DIR/overflowing-consts.rs:270:28 | LL | const _NISIZE_MOD: isize = 1isize % 0; - | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:277:32 +error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero + --> $DIR/overflowing-consts.rs:271:32 | LL | const _NISIZE_MOD_P: &isize = &(1isize % 0); - | ^^^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:279:28 +error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero + --> $DIR/overflowing-consts.rs:273:28 | LL | const _NUSIZE_MOD: usize = 1usize % 0; - | ^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:280:32 +error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero + --> $DIR/overflowing-consts.rs:274:32 | LL | const _NUSIZE_MOD_P: &usize = &(1usize % 0); - | ^^^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:284:24 +error[E0080]: index out of bounds: the length is 3 but the index is 4 + --> $DIR/overflowing-consts.rs:277:24 | LL | const _NI32_OOB: i32 = [1, 2, 3][4]; - | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:285:28 +error[E0080]: index out of bounds: the length is 3 but the index is 4 + --> $DIR/overflowing-consts.rs:278:28 | LL | const _NI32_OOB_P: &i32 = &([1, 2, 3][4]); - | ^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 + | ^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 170 previous errors diff --git a/tests/ui/consts/overflowing-consts.opt.stderr b/tests/ui/consts/overflowing-consts.opt.stderr index 81f22944adb..134ebad5c7b 100644 --- a/tests/ui/consts/overflowing-consts.opt.stderr +++ b/tests/ui/consts/overflowing-consts.opt.stderr @@ -1,1022 +1,1022 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:19:22 +error[E0080]: attempt to shift left by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:18:22 | LL | const _NI8_SHL: i8 = 1i8 << 8; - | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:20:26 +error[E0080]: attempt to shift left by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:19:26 | LL | const _NI8_SHL_P: &i8 = &(1i8 << 8); - | ^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:22:24 +error[E0080]: attempt to shift left by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:21:24 | LL | const _NI16_SHL: i16 = 1i16 << 16; - | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:23:28 +error[E0080]: attempt to shift left by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:22:28 | LL | const _NI16_SHL_P: &i16 = &(1i16 << 16); - | ^^^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:25:24 +error[E0080]: attempt to shift left by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:24:24 | LL | const _NI32_SHL: i32 = 1i32 << 32; - | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:26:28 +error[E0080]: attempt to shift left by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:25:28 | LL | const _NI32_SHL_P: &i32 = &(1i32 << 32); - | ^^^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:28:24 +error[E0080]: attempt to shift left by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:27:24 | LL | const _NI64_SHL: i64 = 1i64 << 64; - | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:29:28 +error[E0080]: attempt to shift left by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:28:28 | LL | const _NI64_SHL_P: &i64 = &(1i64 << 64); - | ^^^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:31:26 +error[E0080]: attempt to shift left by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:30:26 | LL | const _NI128_SHL: i128 = 1i128 << 128; - | ^^^^^^^^^^^^ attempt to shift left by `128_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:32:30 +error[E0080]: attempt to shift left by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:31:30 | LL | const _NI128_SHL_P: &i128 = &(1i128 << 128); - | ^^^^^^^^^^^^^^ attempt to shift left by `128_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:34:22 +error[E0080]: attempt to shift left by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:33:22 | LL | const _NU8_SHL: u8 = 1u8 << 8; - | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:35:26 +error[E0080]: attempt to shift left by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:34:26 | LL | const _NU8_SHL_P: &u8 = &(1u8 << 8); - | ^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:37:24 +error[E0080]: attempt to shift left by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:36:24 | LL | const _NU16_SHL: u16 = 1u16 << 16; - | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:38:28 +error[E0080]: attempt to shift left by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:37:28 | LL | const _NU16_SHL_P: &u16 = &(1u16 << 16); - | ^^^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:40:24 +error[E0080]: attempt to shift left by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:39:24 | LL | const _NU32_SHL: u32 = 1u32 << 32; - | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:41:28 +error[E0080]: attempt to shift left by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:40:28 | LL | const _NU32_SHL_P: &u32 = &(1u32 << 32); - | ^^^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:43:24 +error[E0080]: attempt to shift left by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:42:24 | LL | const _NU64_SHL: u64 = 1u64 << 64; - | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:44:28 +error[E0080]: attempt to shift left by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:43:28 | LL | const _NU64_SHL_P: &u64 = &(1u64 << 64); - | ^^^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:46:26 +error[E0080]: attempt to shift left by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:45:26 | LL | const _NU128_SHL: u128 = 1u128 << 128; - | ^^^^^^^^^^^^ attempt to shift left by `128_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:47:30 +error[E0080]: attempt to shift left by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:46:30 | LL | const _NU128_SHL_P: &u128 = &(1u128 << 128); - | ^^^^^^^^^^^^^^ attempt to shift left by `128_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:49:28 +error[E0080]: attempt to shift left by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:48:28 | LL | const _NISIZE_SHL: isize = 1isize << BITS; - | ^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:50:32 +error[E0080]: attempt to shift left by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:49:32 | LL | const _NISIZE_SHL_P: &isize = &(1isize << BITS); - | ^^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:52:28 +error[E0080]: attempt to shift left by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:51:28 | LL | const _NUSIZE_SHL: usize = 1usize << BITS; - | ^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:53:32 +error[E0080]: attempt to shift left by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:52:32 | LL | const _NUSIZE_SHL_P: &usize = &(1usize << BITS); - | ^^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:57:22 +error[E0080]: attempt to shift right by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:55:22 | LL | const _NI8_SHR: i8 = 1i8 >> 8; - | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:58:26 +error[E0080]: attempt to shift right by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:56:26 | LL | const _NI8_SHR_P: &i8 = &(1i8 >> 8); - | ^^^^^^^^^^ attempt to shift right by `8_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:60:24 +error[E0080]: attempt to shift right by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:58:24 | LL | const _NI16_SHR: i16 = 1i16 >> 16; - | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:61:28 +error[E0080]: attempt to shift right by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:59:28 | LL | const _NI16_SHR_P: &i16 = &(1i16 >> 16); - | ^^^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:63:24 +error[E0080]: attempt to shift right by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:61:24 | LL | const _NI32_SHR: i32 = 1i32 >> 32; - | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:64:28 +error[E0080]: attempt to shift right by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:62:28 | LL | const _NI32_SHR_P: &i32 = &(1i32 >> 32); - | ^^^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:66:24 +error[E0080]: attempt to shift right by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:64:24 | LL | const _NI64_SHR: i64 = 1i64 >> 64; - | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:67:28 +error[E0080]: attempt to shift right by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:65:28 | LL | const _NI64_SHR_P: &i64 = &(1i64 >> 64); - | ^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:69:26 +error[E0080]: attempt to shift right by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:67:26 | LL | const _NI128_SHR: i128 = 1i128 >> 128; - | ^^^^^^^^^^^^ attempt to shift right by `128_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:70:30 +error[E0080]: attempt to shift right by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:68:30 | LL | const _NI128_SHR_P: &i128 = &(1i128 >> 128); - | ^^^^^^^^^^^^^^ attempt to shift right by `128_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:72:22 +error[E0080]: attempt to shift right by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:70:22 | LL | const _NU8_SHR: u8 = 1u8 >> 8; - | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:73:26 +error[E0080]: attempt to shift right by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:71:26 | LL | const _NU8_SHR_P: &u8 = &(1u8 >> 8); - | ^^^^^^^^^^ attempt to shift right by `8_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:75:24 +error[E0080]: attempt to shift right by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:73:24 | LL | const _NU16_SHR: u16 = 1u16 >> 16; - | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:76:28 +error[E0080]: attempt to shift right by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:74:28 | LL | const _NU16_SHR_P: &u16 = &(1u16 >> 16); - | ^^^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:78:24 +error[E0080]: attempt to shift right by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:76:24 | LL | const _NU32_SHR: u32 = 1u32 >> 32; - | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:79:28 +error[E0080]: attempt to shift right by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:77:28 | LL | const _NU32_SHR_P: &u32 = &(1u32 >> 32); - | ^^^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:81:24 +error[E0080]: attempt to shift right by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:79:24 | LL | const _NU64_SHR: u64 = 1u64 >> 64; - | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:82:28 +error[E0080]: attempt to shift right by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:80:28 | LL | const _NU64_SHR_P: &u64 = &(1u64 >> 64); - | ^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:84:26 +error[E0080]: attempt to shift right by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:82:26 | LL | const _NU128_SHR: u128 = 1u128 >> 128; - | ^^^^^^^^^^^^ attempt to shift right by `128_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:85:30 +error[E0080]: attempt to shift right by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:83:30 | LL | const _NU128_SHR_P: &u128 = &(1u128 >> 128); - | ^^^^^^^^^^^^^^ attempt to shift right by `128_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:87:28 +error[E0080]: attempt to shift right by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:85:28 | LL | const _NISIZE_SHR: isize = 1isize >> BITS; - | ^^^^^^^^^^^^^^ attempt to shift right by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:88:32 +error[E0080]: attempt to shift right by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:86:32 | LL | const _NISIZE_SHR_P: &isize = &(1isize >> BITS); - | ^^^^^^^^^^^^^^^^ attempt to shift right by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:90:28 +error[E0080]: attempt to shift right by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:88:28 | LL | const _NUSIZE_SHR: usize = 1usize >> BITS; - | ^^^^^^^^^^^^^^ attempt to shift right by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:91:32 +error[E0080]: attempt to shift right by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:89:32 | LL | const _NUSIZE_SHR_P: &usize = &(1usize >> BITS); - | ^^^^^^^^^^^^^^^^ attempt to shift right by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:95:22 +error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:92:22 | LL | const _NI8_ADD: i8 = 1i8 + i8::MAX; - | ^^^^^^^^^^^^^ attempt to compute `1_i8 + i8::MAX`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:96:26 +error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:93:26 | LL | const _NI8_ADD_P: &i8 = &(1i8 + i8::MAX); - | ^^^^^^^^^^^^^^^ attempt to compute `1_i8 + i8::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:98:24 +error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:95:24 | LL | const _NI16_ADD: i16 = 1i16 + i16::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_i16 + i16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:99:28 +error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:96:28 | LL | const _NI16_ADD_P: &i16 = &(1i16 + i16::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_i16 + i16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:101:24 +error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:98:24 | LL | const _NI32_ADD: i32 = 1i32 + i32::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_i32 + i32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:102:28 +error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:99:28 | LL | const _NI32_ADD_P: &i32 = &(1i32 + i32::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_i32 + i32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:104:24 +error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:101:24 | LL | const _NI64_ADD: i64 = 1i64 + i64::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_i64 + i64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:105:28 +error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:102:28 | LL | const _NI64_ADD_P: &i64 = &(1i64 + i64::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_i64 + i64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:107:26 +error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:104:26 | LL | const _NI128_ADD: i128 = 1i128 + i128::MAX; - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_i128 + i128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:108:30 +error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:105:30 | LL | const _NI128_ADD_P: &i128 = &(1i128 + i128::MAX); - | ^^^^^^^^^^^^^^^^^^^ attempt to compute `1_i128 + i128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:110:22 +error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:107:22 | LL | const _NU8_ADD: u8 = 1u8 + u8::MAX; - | ^^^^^^^^^^^^^ attempt to compute `1_u8 + u8::MAX`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:111:26 +error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:108:26 | LL | const _NU8_ADD_P: &u8 = &(1u8 + u8::MAX); - | ^^^^^^^^^^^^^^^ attempt to compute `1_u8 + u8::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:113:24 +error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:110:24 | LL | const _NU16_ADD: u16 = 1u16 + u16::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_u16 + u16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:114:28 +error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:111:28 | LL | const _NU16_ADD_P: &u16 = &(1u16 + u16::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_u16 + u16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:116:24 +error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:113:24 | LL | const _NU32_ADD: u32 = 1u32 + u32::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_u32 + u32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:117:28 +error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:114:28 | LL | const _NU32_ADD_P: &u32 = &(1u32 + u32::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_u32 + u32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:119:24 +error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:116:24 | LL | const _NU64_ADD: u64 = 1u64 + u64::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_u64 + u64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:120:28 +error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:117:28 | LL | const _NU64_ADD_P: &u64 = &(1u64 + u64::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_u64 + u64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:122:26 +error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:119:26 | LL | const _NU128_ADD: u128 = 1u128 + u128::MAX; - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_u128 + u128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:123:30 +error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:120:30 | LL | const _NU128_ADD_P: &u128 = &(1u128 + u128::MAX); - | ^^^^^^^^^^^^^^^^^^^ attempt to compute `1_u128 + u128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:125:28 +error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:122:28 | LL | const _NISIZE_ADD: isize = 1isize + isize::MAX; - | ^^^^^^^^^^^^^^^^^^^ attempt to compute `1_isize + isize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:126:32 +error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:123:32 | LL | const _NISIZE_ADD_P: &isize = &(1isize + isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `1_isize + isize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:128:28 +error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:125:28 | LL | const _NUSIZE_ADD: usize = 1usize + usize::MAX; - | ^^^^^^^^^^^^^^^^^^^ attempt to compute `1_usize + usize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:129:32 +error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:126:32 | LL | const _NUSIZE_ADD_P: &usize = &(1usize + usize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `1_usize + usize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:133:22 +error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:129:22 | LL | const _NI8_SUB: i8 = -5i8 - i8::MAX; - | ^^^^^^^^^^^^^^ attempt to compute `-5_i8 - i8::MAX`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:134:26 +error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:130:26 | LL | const _NI8_SUB_P: &i8 = &(-5i8 - i8::MAX); - | ^^^^^^^^^^^^^^^^ attempt to compute `-5_i8 - i8::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:136:24 +error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:132:24 | LL | const _NI16_SUB: i16 = -5i16 - i16::MAX; - | ^^^^^^^^^^^^^^^^ attempt to compute `-5_i16 - i16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:137:28 +error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:133:28 | LL | const _NI16_SUB_P: &i16 = &(-5i16 - i16::MAX); - | ^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i16 - i16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:139:24 +error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:135:24 | LL | const _NI32_SUB: i32 = -5i32 - i32::MAX; - | ^^^^^^^^^^^^^^^^ attempt to compute `-5_i32 - i32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:140:28 +error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:136:28 | LL | const _NI32_SUB_P: &i32 = &(-5i32 - i32::MAX); - | ^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i32 - i32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:142:24 +error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:138:24 | LL | const _NI64_SUB: i64 = -5i64 - i64::MAX; - | ^^^^^^^^^^^^^^^^ attempt to compute `-5_i64 - i64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:143:28 +error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:139:28 | LL | const _NI64_SUB_P: &i64 = &(-5i64 - i64::MAX); - | ^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i64 - i64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:145:26 +error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:141:26 | LL | const _NI128_SUB: i128 = -5i128 - i128::MAX; - | ^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i128 - i128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:146:30 +error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:142:30 | LL | const _NI128_SUB_P: &i128 = &(-5i128 - i128::MAX); - | ^^^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i128 - i128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:148:22 +error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow + --> $DIR/overflowing-consts.rs:144:22 | LL | const _NU8_SUB: u8 = 1u8 - 5; - | ^^^^^^^ attempt to compute `1_u8 - 5_u8`, which would overflow + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:149:26 +error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow + --> $DIR/overflowing-consts.rs:145:26 | LL | const _NU8_SUB_P: &u8 = &(1u8 - 5); - | ^^^^^^^^^ attempt to compute `1_u8 - 5_u8`, which would overflow + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:151:24 +error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow + --> $DIR/overflowing-consts.rs:147:24 | LL | const _NU16_SUB: u16 = 1u16 - 5; - | ^^^^^^^^ attempt to compute `1_u16 - 5_u16`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:152:28 +error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow + --> $DIR/overflowing-consts.rs:148:28 | LL | const _NU16_SUB_P: &u16 = &(1u16 - 5); - | ^^^^^^^^^^ attempt to compute `1_u16 - 5_u16`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:154:24 +error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow + --> $DIR/overflowing-consts.rs:150:24 | LL | const _NU32_SUB: u32 = 1u32 - 5; - | ^^^^^^^^ attempt to compute `1_u32 - 5_u32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:155:28 +error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow + --> $DIR/overflowing-consts.rs:151:28 | LL | const _NU32_SUB_P: &u32 = &(1u32 - 5); - | ^^^^^^^^^^ attempt to compute `1_u32 - 5_u32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:157:24 +error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow + --> $DIR/overflowing-consts.rs:153:24 | LL | const _NU64_SUB: u64 = 1u64 - 5; - | ^^^^^^^^ attempt to compute `1_u64 - 5_u64`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:158:28 +error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow + --> $DIR/overflowing-consts.rs:154:28 | LL | const _NU64_SUB_P: &u64 = &(1u64 - 5); - | ^^^^^^^^^^ attempt to compute `1_u64 - 5_u64`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:160:26 +error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow + --> $DIR/overflowing-consts.rs:156:26 | LL | const _NU128_SUB: u128 = 1u128 - 5; - | ^^^^^^^^^ attempt to compute `1_u128 - 5_u128`, which would overflow + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:161:30 +error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow + --> $DIR/overflowing-consts.rs:157:30 | LL | const _NU128_SUB_P: &u128 = &(1u128 - 5); - | ^^^^^^^^^^^ attempt to compute `1_u128 - 5_u128`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:163:28 +error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:159:28 | LL | const _NISIZE_SUB: isize = -5isize - isize::MAX; - | ^^^^^^^^^^^^^^^^^^^^ attempt to compute `-5_isize - isize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:164:32 +error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:160:32 | LL | const _NISIZE_SUB_P: &isize = &(-5isize - isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `-5_isize - isize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:166:28 +error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow + --> $DIR/overflowing-consts.rs:162:28 | -LL | const _NUSIZE_SUB: usize = 1usize - 5 ; - | ^^^^^^^^^^ attempt to compute `1_usize - 5_usize`, which would overflow +LL | const _NUSIZE_SUB: usize = 1usize - 5; + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:167:32 +error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow + --> $DIR/overflowing-consts.rs:163:32 | -LL | const _NUSIZE_SUB_P: &usize = &(1usize - 5 ); - | ^^^^^^^^^^^^^ attempt to compute `1_usize - 5_usize`, which would overflow +LL | const _NUSIZE_SUB_P: &usize = &(1usize - 5); + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:171:22 +error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow + --> $DIR/overflowing-consts.rs:166:22 | LL | const _NI8_MUL: i8 = i8::MAX * 5; - | ^^^^^^^^^^^ attempt to compute `i8::MAX * 5_i8`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:172:26 +error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow + --> $DIR/overflowing-consts.rs:167:26 | LL | const _NI8_MUL_P: &i8 = &(i8::MAX * 5); - | ^^^^^^^^^^^^^ attempt to compute `i8::MAX * 5_i8`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:174:24 +error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow + --> $DIR/overflowing-consts.rs:169:24 | LL | const _NI16_MUL: i16 = i16::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `i16::MAX * 5_i16`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:175:28 +error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow + --> $DIR/overflowing-consts.rs:170:28 | LL | const _NI16_MUL_P: &i16 = &(i16::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `i16::MAX * 5_i16`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:177:24 +error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow + --> $DIR/overflowing-consts.rs:172:24 | LL | const _NI32_MUL: i32 = i32::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `i32::MAX * 5_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:178:28 +error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow + --> $DIR/overflowing-consts.rs:173:28 | LL | const _NI32_MUL_P: &i32 = &(i32::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `i32::MAX * 5_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:180:24 +error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow + --> $DIR/overflowing-consts.rs:175:24 | LL | const _NI64_MUL: i64 = i64::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `i64::MAX * 5_i64`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:181:28 +error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow + --> $DIR/overflowing-consts.rs:176:28 | LL | const _NI64_MUL_P: &i64 = &(i64::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `i64::MAX * 5_i64`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:183:26 +error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow + --> $DIR/overflowing-consts.rs:178:26 | LL | const _NI128_MUL: i128 = i128::MAX * 5; - | ^^^^^^^^^^^^^ attempt to compute `i128::MAX * 5_i128`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:184:30 +error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow + --> $DIR/overflowing-consts.rs:179:30 | LL | const _NI128_MUL_P: &i128 = &(i128::MAX * 5); - | ^^^^^^^^^^^^^^^ attempt to compute `i128::MAX * 5_i128`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:186:22 +error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow + --> $DIR/overflowing-consts.rs:181:22 | LL | const _NU8_MUL: u8 = u8::MAX * 5; - | ^^^^^^^^^^^ attempt to compute `u8::MAX * 5_u8`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:187:26 +error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow + --> $DIR/overflowing-consts.rs:182:26 | LL | const _NU8_MUL_P: &u8 = &(u8::MAX * 5); - | ^^^^^^^^^^^^^ attempt to compute `u8::MAX * 5_u8`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:189:24 +error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow + --> $DIR/overflowing-consts.rs:184:24 | LL | const _NU16_MUL: u16 = u16::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `u16::MAX * 5_u16`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:190:28 +error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow + --> $DIR/overflowing-consts.rs:185:28 | LL | const _NU16_MUL_P: &u16 = &(u16::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `u16::MAX * 5_u16`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:192:24 +error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow + --> $DIR/overflowing-consts.rs:187:24 | LL | const _NU32_MUL: u32 = u32::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `u32::MAX * 5_u32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:193:28 +error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow + --> $DIR/overflowing-consts.rs:188:28 | LL | const _NU32_MUL_P: &u32 = &(u32::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `u32::MAX * 5_u32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:195:24 +error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow + --> $DIR/overflowing-consts.rs:190:24 | LL | const _NU64_MUL: u64 = u64::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `u64::MAX * 5_u64`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:196:28 +error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow + --> $DIR/overflowing-consts.rs:191:28 | LL | const _NU64_MUL_P: &u64 = &(u64::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `u64::MAX * 5_u64`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:198:26 +error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow + --> $DIR/overflowing-consts.rs:193:26 | LL | const _NU128_MUL: u128 = u128::MAX * 5; - | ^^^^^^^^^^^^^ attempt to compute `u128::MAX * 5_u128`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:199:30 +error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow + --> $DIR/overflowing-consts.rs:194:30 | LL | const _NU128_MUL_P: &u128 = &(u128::MAX * 5); - | ^^^^^^^^^^^^^^^ attempt to compute `u128::MAX * 5_u128`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:201:28 +error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow + --> $DIR/overflowing-consts.rs:196:28 | LL | const _NISIZE_MUL: isize = isize::MAX * 5; - | ^^^^^^^^^^^^^^ attempt to compute `isize::MAX * 5_isize`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:202:32 +error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow + --> $DIR/overflowing-consts.rs:197:32 | LL | const _NISIZE_MUL_P: &isize = &(isize::MAX * 5); - | ^^^^^^^^^^^^^^^^ attempt to compute `isize::MAX * 5_isize`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:204:28 +error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow + --> $DIR/overflowing-consts.rs:199:28 | LL | const _NUSIZE_MUL: usize = usize::MAX * 5; - | ^^^^^^^^^^^^^^ attempt to compute `usize::MAX * 5_usize`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:205:32 +error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow + --> $DIR/overflowing-consts.rs:200:32 | LL | const _NUSIZE_MUL_P: &usize = &(usize::MAX * 5); - | ^^^^^^^^^^^^^^^^ attempt to compute `usize::MAX * 5_usize`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:209:22 +error[E0080]: attempt to divide `1_i8` by zero + --> $DIR/overflowing-consts.rs:203:22 | LL | const _NI8_DIV: i8 = 1i8 / 0; - | ^^^^^^^ attempt to divide `1_i8` by zero + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:210:26 +error[E0080]: attempt to divide `1_i8` by zero + --> $DIR/overflowing-consts.rs:204:26 | LL | const _NI8_DIV_P: &i8 = &(1i8 / 0); - | ^^^^^^^^^ attempt to divide `1_i8` by zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:212:24 +error[E0080]: attempt to divide `1_i16` by zero + --> $DIR/overflowing-consts.rs:206:24 | LL | const _NI16_DIV: i16 = 1i16 / 0; - | ^^^^^^^^ attempt to divide `1_i16` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:213:28 +error[E0080]: attempt to divide `1_i16` by zero + --> $DIR/overflowing-consts.rs:207:28 | LL | const _NI16_DIV_P: &i16 = &(1i16 / 0); - | ^^^^^^^^^^ attempt to divide `1_i16` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:215:24 +error[E0080]: attempt to divide `1_i32` by zero + --> $DIR/overflowing-consts.rs:209:24 | LL | const _NI32_DIV: i32 = 1i32 / 0; - | ^^^^^^^^ attempt to divide `1_i32` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:216:28 +error[E0080]: attempt to divide `1_i32` by zero + --> $DIR/overflowing-consts.rs:210:28 | LL | const _NI32_DIV_P: &i32 = &(1i32 / 0); - | ^^^^^^^^^^ attempt to divide `1_i32` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:218:24 +error[E0080]: attempt to divide `1_i64` by zero + --> $DIR/overflowing-consts.rs:212:24 | LL | const _NI64_DIV: i64 = 1i64 / 0; - | ^^^^^^^^ attempt to divide `1_i64` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:219:28 +error[E0080]: attempt to divide `1_i64` by zero + --> $DIR/overflowing-consts.rs:213:28 | LL | const _NI64_DIV_P: &i64 = &(1i64 / 0); - | ^^^^^^^^^^ attempt to divide `1_i64` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:221:26 +error[E0080]: attempt to divide `1_i128` by zero + --> $DIR/overflowing-consts.rs:215:26 | LL | const _NI128_DIV: i128 = 1i128 / 0; - | ^^^^^^^^^ attempt to divide `1_i128` by zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:222:30 +error[E0080]: attempt to divide `1_i128` by zero + --> $DIR/overflowing-consts.rs:216:30 | LL | const _NI128_DIV_P: &i128 = &(1i128 / 0); - | ^^^^^^^^^^^ attempt to divide `1_i128` by zero + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:224:22 +error[E0080]: attempt to divide `1_u8` by zero + --> $DIR/overflowing-consts.rs:218:22 | LL | const _NU8_DIV: u8 = 1u8 / 0; - | ^^^^^^^ attempt to divide `1_u8` by zero + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:225:26 +error[E0080]: attempt to divide `1_u8` by zero + --> $DIR/overflowing-consts.rs:219:26 | LL | const _NU8_DIV_P: &u8 = &(1u8 / 0); - | ^^^^^^^^^ attempt to divide `1_u8` by zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:227:24 +error[E0080]: attempt to divide `1_u16` by zero + --> $DIR/overflowing-consts.rs:221:24 | LL | const _NU16_DIV: u16 = 1u16 / 0; - | ^^^^^^^^ attempt to divide `1_u16` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:228:28 +error[E0080]: attempt to divide `1_u16` by zero + --> $DIR/overflowing-consts.rs:222:28 | LL | const _NU16_DIV_P: &u16 = &(1u16 / 0); - | ^^^^^^^^^^ attempt to divide `1_u16` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:230:24 +error[E0080]: attempt to divide `1_u32` by zero + --> $DIR/overflowing-consts.rs:224:24 | LL | const _NU32_DIV: u32 = 1u32 / 0; - | ^^^^^^^^ attempt to divide `1_u32` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:231:28 +error[E0080]: attempt to divide `1_u32` by zero + --> $DIR/overflowing-consts.rs:225:28 | LL | const _NU32_DIV_P: &u32 = &(1u32 / 0); - | ^^^^^^^^^^ attempt to divide `1_u32` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:233:24 +error[E0080]: attempt to divide `1_u64` by zero + --> $DIR/overflowing-consts.rs:227:24 | LL | const _NU64_DIV: u64 = 1u64 / 0; - | ^^^^^^^^ attempt to divide `1_u64` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:234:28 +error[E0080]: attempt to divide `1_u64` by zero + --> $DIR/overflowing-consts.rs:228:28 | LL | const _NU64_DIV_P: &u64 = &(1u64 / 0); - | ^^^^^^^^^^ attempt to divide `1_u64` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:236:26 +error[E0080]: attempt to divide `1_u128` by zero + --> $DIR/overflowing-consts.rs:230:26 | LL | const _NU128_DIV: u128 = 1u128 / 0; - | ^^^^^^^^^ attempt to divide `1_u128` by zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:237:30 +error[E0080]: attempt to divide `1_u128` by zero + --> $DIR/overflowing-consts.rs:231:30 | LL | const _NU128_DIV_P: &u128 = &(1u128 / 0); - | ^^^^^^^^^^^ attempt to divide `1_u128` by zero + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:239:28 +error[E0080]: attempt to divide `1_isize` by zero + --> $DIR/overflowing-consts.rs:233:28 | LL | const _NISIZE_DIV: isize = 1isize / 0; - | ^^^^^^^^^^ attempt to divide `1_isize` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:240:32 +error[E0080]: attempt to divide `1_isize` by zero + --> $DIR/overflowing-consts.rs:234:32 | LL | const _NISIZE_DIV_P: &isize = &(1isize / 0); - | ^^^^^^^^^^^^ attempt to divide `1_isize` by zero + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:242:28 +error[E0080]: attempt to divide `1_usize` by zero + --> $DIR/overflowing-consts.rs:236:28 | LL | const _NUSIZE_DIV: usize = 1usize / 0; - | ^^^^^^^^^^ attempt to divide `1_usize` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:243:32 +error[E0080]: attempt to divide `1_usize` by zero + --> $DIR/overflowing-consts.rs:237:32 | LL | const _NUSIZE_DIV_P: &usize = &(1usize / 0); - | ^^^^^^^^^^^^ attempt to divide `1_usize` by zero + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:246:22 +error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero + --> $DIR/overflowing-consts.rs:240:22 | LL | const _NI8_MOD: i8 = 1i8 % 0; - | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:247:26 +error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero + --> $DIR/overflowing-consts.rs:241:26 | LL | const _NI8_MOD_P: &i8 = &(1i8 % 0); - | ^^^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:249:24 +error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero + --> $DIR/overflowing-consts.rs:243:24 | LL | const _NI16_MOD: i16 = 1i16 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:250:28 +error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero + --> $DIR/overflowing-consts.rs:244:28 | LL | const _NI16_MOD_P: &i16 = &(1i16 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:252:24 +error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero + --> $DIR/overflowing-consts.rs:246:24 | LL | const _NI32_MOD: i32 = 1i32 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:253:28 +error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero + --> $DIR/overflowing-consts.rs:247:28 | LL | const _NI32_MOD_P: &i32 = &(1i32 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:255:24 +error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero + --> $DIR/overflowing-consts.rs:249:24 | LL | const _NI64_MOD: i64 = 1i64 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:256:28 +error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero + --> $DIR/overflowing-consts.rs:250:28 | LL | const _NI64_MOD_P: &i64 = &(1i64 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:258:26 +error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero + --> $DIR/overflowing-consts.rs:252:26 | LL | const _NI128_MOD: i128 = 1i128 % 0; - | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:259:30 +error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero + --> $DIR/overflowing-consts.rs:253:30 | LL | const _NI128_MOD_P: &i128 = &(1i128 % 0); - | ^^^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:261:22 +error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero + --> $DIR/overflowing-consts.rs:255:22 | LL | const _NU8_MOD: u8 = 1u8 % 0; - | ^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:262:26 +error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero + --> $DIR/overflowing-consts.rs:256:26 | LL | const _NU8_MOD_P: &u8 = &(1u8 % 0); - | ^^^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:264:24 +error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero + --> $DIR/overflowing-consts.rs:258:24 | LL | const _NU16_MOD: u16 = 1u16 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:265:28 +error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero + --> $DIR/overflowing-consts.rs:259:28 | LL | const _NU16_MOD_P: &u16 = &(1u16 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:267:24 +error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero + --> $DIR/overflowing-consts.rs:261:24 | LL | const _NU32_MOD: u32 = 1u32 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:268:28 +error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero + --> $DIR/overflowing-consts.rs:262:28 | LL | const _NU32_MOD_P: &u32 = &(1u32 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:270:24 +error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero + --> $DIR/overflowing-consts.rs:264:24 | LL | const _NU64_MOD: u64 = 1u64 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:271:28 +error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero + --> $DIR/overflowing-consts.rs:265:28 | LL | const _NU64_MOD_P: &u64 = &(1u64 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:273:26 +error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero + --> $DIR/overflowing-consts.rs:267:26 | LL | const _NU128_MOD: u128 = 1u128 % 0; - | ^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:274:30 +error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero + --> $DIR/overflowing-consts.rs:268:30 | LL | const _NU128_MOD_P: &u128 = &(1u128 % 0); - | ^^^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:276:28 +error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero + --> $DIR/overflowing-consts.rs:270:28 | LL | const _NISIZE_MOD: isize = 1isize % 0; - | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:277:32 +error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero + --> $DIR/overflowing-consts.rs:271:32 | LL | const _NISIZE_MOD_P: &isize = &(1isize % 0); - | ^^^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:279:28 +error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero + --> $DIR/overflowing-consts.rs:273:28 | LL | const _NUSIZE_MOD: usize = 1usize % 0; - | ^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:280:32 +error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero + --> $DIR/overflowing-consts.rs:274:32 | LL | const _NUSIZE_MOD_P: &usize = &(1usize % 0); - | ^^^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:284:24 +error[E0080]: index out of bounds: the length is 3 but the index is 4 + --> $DIR/overflowing-consts.rs:277:24 | LL | const _NI32_OOB: i32 = [1, 2, 3][4]; - | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:285:28 +error[E0080]: index out of bounds: the length is 3 but the index is 4 + --> $DIR/overflowing-consts.rs:278:28 | LL | const _NI32_OOB_P: &i32 = &([1, 2, 3][4]); - | ^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 + | ^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 170 previous errors diff --git a/tests/ui/consts/overflowing-consts.opt_with_overflow_checks.stderr b/tests/ui/consts/overflowing-consts.opt_with_overflow_checks.stderr index 81f22944adb..134ebad5c7b 100644 --- a/tests/ui/consts/overflowing-consts.opt_with_overflow_checks.stderr +++ b/tests/ui/consts/overflowing-consts.opt_with_overflow_checks.stderr @@ -1,1022 +1,1022 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:19:22 +error[E0080]: attempt to shift left by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:18:22 | LL | const _NI8_SHL: i8 = 1i8 << 8; - | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:20:26 +error[E0080]: attempt to shift left by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:19:26 | LL | const _NI8_SHL_P: &i8 = &(1i8 << 8); - | ^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:22:24 +error[E0080]: attempt to shift left by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:21:24 | LL | const _NI16_SHL: i16 = 1i16 << 16; - | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:23:28 +error[E0080]: attempt to shift left by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:22:28 | LL | const _NI16_SHL_P: &i16 = &(1i16 << 16); - | ^^^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:25:24 +error[E0080]: attempt to shift left by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:24:24 | LL | const _NI32_SHL: i32 = 1i32 << 32; - | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:26:28 +error[E0080]: attempt to shift left by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:25:28 | LL | const _NI32_SHL_P: &i32 = &(1i32 << 32); - | ^^^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:28:24 +error[E0080]: attempt to shift left by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:27:24 | LL | const _NI64_SHL: i64 = 1i64 << 64; - | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:29:28 +error[E0080]: attempt to shift left by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:28:28 | LL | const _NI64_SHL_P: &i64 = &(1i64 << 64); - | ^^^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:31:26 +error[E0080]: attempt to shift left by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:30:26 | LL | const _NI128_SHL: i128 = 1i128 << 128; - | ^^^^^^^^^^^^ attempt to shift left by `128_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:32:30 +error[E0080]: attempt to shift left by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:31:30 | LL | const _NI128_SHL_P: &i128 = &(1i128 << 128); - | ^^^^^^^^^^^^^^ attempt to shift left by `128_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:34:22 +error[E0080]: attempt to shift left by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:33:22 | LL | const _NU8_SHL: u8 = 1u8 << 8; - | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:35:26 +error[E0080]: attempt to shift left by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:34:26 | LL | const _NU8_SHL_P: &u8 = &(1u8 << 8); - | ^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:37:24 +error[E0080]: attempt to shift left by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:36:24 | LL | const _NU16_SHL: u16 = 1u16 << 16; - | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:38:28 +error[E0080]: attempt to shift left by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:37:28 | LL | const _NU16_SHL_P: &u16 = &(1u16 << 16); - | ^^^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:40:24 +error[E0080]: attempt to shift left by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:39:24 | LL | const _NU32_SHL: u32 = 1u32 << 32; - | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:41:28 +error[E0080]: attempt to shift left by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:40:28 | LL | const _NU32_SHL_P: &u32 = &(1u32 << 32); - | ^^^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:43:24 +error[E0080]: attempt to shift left by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:42:24 | LL | const _NU64_SHL: u64 = 1u64 << 64; - | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:44:28 +error[E0080]: attempt to shift left by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:43:28 | LL | const _NU64_SHL_P: &u64 = &(1u64 << 64); - | ^^^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:46:26 +error[E0080]: attempt to shift left by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:45:26 | LL | const _NU128_SHL: u128 = 1u128 << 128; - | ^^^^^^^^^^^^ attempt to shift left by `128_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:47:30 +error[E0080]: attempt to shift left by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:46:30 | LL | const _NU128_SHL_P: &u128 = &(1u128 << 128); - | ^^^^^^^^^^^^^^ attempt to shift left by `128_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:49:28 +error[E0080]: attempt to shift left by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:48:28 | LL | const _NISIZE_SHL: isize = 1isize << BITS; - | ^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:50:32 +error[E0080]: attempt to shift left by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:49:32 | LL | const _NISIZE_SHL_P: &isize = &(1isize << BITS); - | ^^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:52:28 +error[E0080]: attempt to shift left by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:51:28 | LL | const _NUSIZE_SHL: usize = 1usize << BITS; - | ^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:53:32 +error[E0080]: attempt to shift left by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:52:32 | LL | const _NUSIZE_SHL_P: &usize = &(1usize << BITS); - | ^^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:57:22 +error[E0080]: attempt to shift right by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:55:22 | LL | const _NI8_SHR: i8 = 1i8 >> 8; - | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:58:26 +error[E0080]: attempt to shift right by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:56:26 | LL | const _NI8_SHR_P: &i8 = &(1i8 >> 8); - | ^^^^^^^^^^ attempt to shift right by `8_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:60:24 +error[E0080]: attempt to shift right by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:58:24 | LL | const _NI16_SHR: i16 = 1i16 >> 16; - | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:61:28 +error[E0080]: attempt to shift right by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:59:28 | LL | const _NI16_SHR_P: &i16 = &(1i16 >> 16); - | ^^^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:63:24 +error[E0080]: attempt to shift right by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:61:24 | LL | const _NI32_SHR: i32 = 1i32 >> 32; - | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:64:28 +error[E0080]: attempt to shift right by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:62:28 | LL | const _NI32_SHR_P: &i32 = &(1i32 >> 32); - | ^^^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:66:24 +error[E0080]: attempt to shift right by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:64:24 | LL | const _NI64_SHR: i64 = 1i64 >> 64; - | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:67:28 +error[E0080]: attempt to shift right by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:65:28 | LL | const _NI64_SHR_P: &i64 = &(1i64 >> 64); - | ^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:69:26 +error[E0080]: attempt to shift right by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:67:26 | LL | const _NI128_SHR: i128 = 1i128 >> 128; - | ^^^^^^^^^^^^ attempt to shift right by `128_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:70:30 +error[E0080]: attempt to shift right by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:68:30 | LL | const _NI128_SHR_P: &i128 = &(1i128 >> 128); - | ^^^^^^^^^^^^^^ attempt to shift right by `128_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:72:22 +error[E0080]: attempt to shift right by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:70:22 | LL | const _NU8_SHR: u8 = 1u8 >> 8; - | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:73:26 +error[E0080]: attempt to shift right by `8_i32`, which would overflow + --> $DIR/overflowing-consts.rs:71:26 | LL | const _NU8_SHR_P: &u8 = &(1u8 >> 8); - | ^^^^^^^^^^ attempt to shift right by `8_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:75:24 +error[E0080]: attempt to shift right by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:73:24 | LL | const _NU16_SHR: u16 = 1u16 >> 16; - | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:76:28 +error[E0080]: attempt to shift right by `16_i32`, which would overflow + --> $DIR/overflowing-consts.rs:74:28 | LL | const _NU16_SHR_P: &u16 = &(1u16 >> 16); - | ^^^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:78:24 +error[E0080]: attempt to shift right by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:76:24 | LL | const _NU32_SHR: u32 = 1u32 >> 32; - | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:79:28 +error[E0080]: attempt to shift right by `32_i32`, which would overflow + --> $DIR/overflowing-consts.rs:77:28 | LL | const _NU32_SHR_P: &u32 = &(1u32 >> 32); - | ^^^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:81:24 +error[E0080]: attempt to shift right by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:79:24 | LL | const _NU64_SHR: u64 = 1u64 >> 64; - | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:82:28 +error[E0080]: attempt to shift right by `64_i32`, which would overflow + --> $DIR/overflowing-consts.rs:80:28 | LL | const _NU64_SHR_P: &u64 = &(1u64 >> 64); - | ^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:84:26 +error[E0080]: attempt to shift right by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:82:26 | LL | const _NU128_SHR: u128 = 1u128 >> 128; - | ^^^^^^^^^^^^ attempt to shift right by `128_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:85:30 +error[E0080]: attempt to shift right by `128_i32`, which would overflow + --> $DIR/overflowing-consts.rs:83:30 | LL | const _NU128_SHR_P: &u128 = &(1u128 >> 128); - | ^^^^^^^^^^^^^^ attempt to shift right by `128_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:87:28 +error[E0080]: attempt to shift right by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:85:28 | LL | const _NISIZE_SHR: isize = 1isize >> BITS; - | ^^^^^^^^^^^^^^ attempt to shift right by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:88:32 +error[E0080]: attempt to shift right by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:86:32 | LL | const _NISIZE_SHR_P: &isize = &(1isize >> BITS); - | ^^^^^^^^^^^^^^^^ attempt to shift right by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:90:28 +error[E0080]: attempt to shift right by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:88:28 | LL | const _NUSIZE_SHR: usize = 1usize >> BITS; - | ^^^^^^^^^^^^^^ attempt to shift right by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:91:32 +error[E0080]: attempt to shift right by `%BITS%`, which would overflow + --> $DIR/overflowing-consts.rs:89:32 | LL | const _NUSIZE_SHR_P: &usize = &(1usize >> BITS); - | ^^^^^^^^^^^^^^^^ attempt to shift right by `%BITS%`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:95:22 +error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:92:22 | LL | const _NI8_ADD: i8 = 1i8 + i8::MAX; - | ^^^^^^^^^^^^^ attempt to compute `1_i8 + i8::MAX`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:96:26 +error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:93:26 | LL | const _NI8_ADD_P: &i8 = &(1i8 + i8::MAX); - | ^^^^^^^^^^^^^^^ attempt to compute `1_i8 + i8::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:98:24 +error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:95:24 | LL | const _NI16_ADD: i16 = 1i16 + i16::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_i16 + i16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:99:28 +error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:96:28 | LL | const _NI16_ADD_P: &i16 = &(1i16 + i16::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_i16 + i16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:101:24 +error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:98:24 | LL | const _NI32_ADD: i32 = 1i32 + i32::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_i32 + i32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:102:28 +error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:99:28 | LL | const _NI32_ADD_P: &i32 = &(1i32 + i32::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_i32 + i32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:104:24 +error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:101:24 | LL | const _NI64_ADD: i64 = 1i64 + i64::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_i64 + i64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:105:28 +error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:102:28 | LL | const _NI64_ADD_P: &i64 = &(1i64 + i64::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_i64 + i64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:107:26 +error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:104:26 | LL | const _NI128_ADD: i128 = 1i128 + i128::MAX; - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_i128 + i128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:108:30 +error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:105:30 | LL | const _NI128_ADD_P: &i128 = &(1i128 + i128::MAX); - | ^^^^^^^^^^^^^^^^^^^ attempt to compute `1_i128 + i128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:110:22 +error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:107:22 | LL | const _NU8_ADD: u8 = 1u8 + u8::MAX; - | ^^^^^^^^^^^^^ attempt to compute `1_u8 + u8::MAX`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:111:26 +error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:108:26 | LL | const _NU8_ADD_P: &u8 = &(1u8 + u8::MAX); - | ^^^^^^^^^^^^^^^ attempt to compute `1_u8 + u8::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:113:24 +error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:110:24 | LL | const _NU16_ADD: u16 = 1u16 + u16::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_u16 + u16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:114:28 +error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:111:28 | LL | const _NU16_ADD_P: &u16 = &(1u16 + u16::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_u16 + u16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:116:24 +error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:113:24 | LL | const _NU32_ADD: u32 = 1u32 + u32::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_u32 + u32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:117:28 +error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:114:28 | LL | const _NU32_ADD_P: &u32 = &(1u32 + u32::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_u32 + u32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:119:24 +error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:116:24 | LL | const _NU64_ADD: u64 = 1u64 + u64::MAX; - | ^^^^^^^^^^^^^^^ attempt to compute `1_u64 + u64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:120:28 +error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:117:28 | LL | const _NU64_ADD_P: &u64 = &(1u64 + u64::MAX); - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_u64 + u64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:122:26 +error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:119:26 | LL | const _NU128_ADD: u128 = 1u128 + u128::MAX; - | ^^^^^^^^^^^^^^^^^ attempt to compute `1_u128 + u128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:123:30 +error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:120:30 | LL | const _NU128_ADD_P: &u128 = &(1u128 + u128::MAX); - | ^^^^^^^^^^^^^^^^^^^ attempt to compute `1_u128 + u128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:125:28 +error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:122:28 | LL | const _NISIZE_ADD: isize = 1isize + isize::MAX; - | ^^^^^^^^^^^^^^^^^^^ attempt to compute `1_isize + isize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:126:32 +error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:123:32 | LL | const _NISIZE_ADD_P: &isize = &(1isize + isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `1_isize + isize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:128:28 +error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:125:28 | LL | const _NUSIZE_ADD: usize = 1usize + usize::MAX; - | ^^^^^^^^^^^^^^^^^^^ attempt to compute `1_usize + usize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:129:32 +error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:126:32 | LL | const _NUSIZE_ADD_P: &usize = &(1usize + usize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `1_usize + usize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:133:22 +error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:129:22 | LL | const _NI8_SUB: i8 = -5i8 - i8::MAX; - | ^^^^^^^^^^^^^^ attempt to compute `-5_i8 - i8::MAX`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:134:26 +error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:130:26 | LL | const _NI8_SUB_P: &i8 = &(-5i8 - i8::MAX); - | ^^^^^^^^^^^^^^^^ attempt to compute `-5_i8 - i8::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:136:24 +error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:132:24 | LL | const _NI16_SUB: i16 = -5i16 - i16::MAX; - | ^^^^^^^^^^^^^^^^ attempt to compute `-5_i16 - i16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:137:28 +error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:133:28 | LL | const _NI16_SUB_P: &i16 = &(-5i16 - i16::MAX); - | ^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i16 - i16::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:139:24 +error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:135:24 | LL | const _NI32_SUB: i32 = -5i32 - i32::MAX; - | ^^^^^^^^^^^^^^^^ attempt to compute `-5_i32 - i32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:140:28 +error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:136:28 | LL | const _NI32_SUB_P: &i32 = &(-5i32 - i32::MAX); - | ^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i32 - i32::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:142:24 +error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:138:24 | LL | const _NI64_SUB: i64 = -5i64 - i64::MAX; - | ^^^^^^^^^^^^^^^^ attempt to compute `-5_i64 - i64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:143:28 +error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:139:28 | LL | const _NI64_SUB_P: &i64 = &(-5i64 - i64::MAX); - | ^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i64 - i64::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:145:26 +error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:141:26 | LL | const _NI128_SUB: i128 = -5i128 - i128::MAX; - | ^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i128 - i128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:146:30 +error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:142:30 | LL | const _NI128_SUB_P: &i128 = &(-5i128 - i128::MAX); - | ^^^^^^^^^^^^^^^^^^^^ attempt to compute `-5_i128 - i128::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:148:22 +error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow + --> $DIR/overflowing-consts.rs:144:22 | LL | const _NU8_SUB: u8 = 1u8 - 5; - | ^^^^^^^ attempt to compute `1_u8 - 5_u8`, which would overflow + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:149:26 +error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow + --> $DIR/overflowing-consts.rs:145:26 | LL | const _NU8_SUB_P: &u8 = &(1u8 - 5); - | ^^^^^^^^^ attempt to compute `1_u8 - 5_u8`, which would overflow + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:151:24 +error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow + --> $DIR/overflowing-consts.rs:147:24 | LL | const _NU16_SUB: u16 = 1u16 - 5; - | ^^^^^^^^ attempt to compute `1_u16 - 5_u16`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:152:28 +error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow + --> $DIR/overflowing-consts.rs:148:28 | LL | const _NU16_SUB_P: &u16 = &(1u16 - 5); - | ^^^^^^^^^^ attempt to compute `1_u16 - 5_u16`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:154:24 +error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow + --> $DIR/overflowing-consts.rs:150:24 | LL | const _NU32_SUB: u32 = 1u32 - 5; - | ^^^^^^^^ attempt to compute `1_u32 - 5_u32`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:155:28 +error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow + --> $DIR/overflowing-consts.rs:151:28 | LL | const _NU32_SUB_P: &u32 = &(1u32 - 5); - | ^^^^^^^^^^ attempt to compute `1_u32 - 5_u32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:157:24 +error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow + --> $DIR/overflowing-consts.rs:153:24 | LL | const _NU64_SUB: u64 = 1u64 - 5; - | ^^^^^^^^ attempt to compute `1_u64 - 5_u64`, which would overflow + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:158:28 +error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow + --> $DIR/overflowing-consts.rs:154:28 | LL | const _NU64_SUB_P: &u64 = &(1u64 - 5); - | ^^^^^^^^^^ attempt to compute `1_u64 - 5_u64`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:160:26 +error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow + --> $DIR/overflowing-consts.rs:156:26 | LL | const _NU128_SUB: u128 = 1u128 - 5; - | ^^^^^^^^^ attempt to compute `1_u128 - 5_u128`, which would overflow + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:161:30 +error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow + --> $DIR/overflowing-consts.rs:157:30 | LL | const _NU128_SUB_P: &u128 = &(1u128 - 5); - | ^^^^^^^^^^^ attempt to compute `1_u128 - 5_u128`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:163:28 +error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:159:28 | LL | const _NISIZE_SUB: isize = -5isize - isize::MAX; - | ^^^^^^^^^^^^^^^^^^^^ attempt to compute `-5_isize - isize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:164:32 +error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow + --> $DIR/overflowing-consts.rs:160:32 | LL | const _NISIZE_SUB_P: &isize = &(-5isize - isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `-5_isize - isize::MAX`, which would overflow + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:166:28 +error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow + --> $DIR/overflowing-consts.rs:162:28 | -LL | const _NUSIZE_SUB: usize = 1usize - 5 ; - | ^^^^^^^^^^ attempt to compute `1_usize - 5_usize`, which would overflow +LL | const _NUSIZE_SUB: usize = 1usize - 5; + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:167:32 +error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow + --> $DIR/overflowing-consts.rs:163:32 | -LL | const _NUSIZE_SUB_P: &usize = &(1usize - 5 ); - | ^^^^^^^^^^^^^ attempt to compute `1_usize - 5_usize`, which would overflow +LL | const _NUSIZE_SUB_P: &usize = &(1usize - 5); + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:171:22 +error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow + --> $DIR/overflowing-consts.rs:166:22 | LL | const _NI8_MUL: i8 = i8::MAX * 5; - | ^^^^^^^^^^^ attempt to compute `i8::MAX * 5_i8`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:172:26 +error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow + --> $DIR/overflowing-consts.rs:167:26 | LL | const _NI8_MUL_P: &i8 = &(i8::MAX * 5); - | ^^^^^^^^^^^^^ attempt to compute `i8::MAX * 5_i8`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:174:24 +error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow + --> $DIR/overflowing-consts.rs:169:24 | LL | const _NI16_MUL: i16 = i16::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `i16::MAX * 5_i16`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:175:28 +error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow + --> $DIR/overflowing-consts.rs:170:28 | LL | const _NI16_MUL_P: &i16 = &(i16::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `i16::MAX * 5_i16`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:177:24 +error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow + --> $DIR/overflowing-consts.rs:172:24 | LL | const _NI32_MUL: i32 = i32::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `i32::MAX * 5_i32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:178:28 +error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow + --> $DIR/overflowing-consts.rs:173:28 | LL | const _NI32_MUL_P: &i32 = &(i32::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `i32::MAX * 5_i32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:180:24 +error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow + --> $DIR/overflowing-consts.rs:175:24 | LL | const _NI64_MUL: i64 = i64::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `i64::MAX * 5_i64`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:181:28 +error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow + --> $DIR/overflowing-consts.rs:176:28 | LL | const _NI64_MUL_P: &i64 = &(i64::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `i64::MAX * 5_i64`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:183:26 +error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow + --> $DIR/overflowing-consts.rs:178:26 | LL | const _NI128_MUL: i128 = i128::MAX * 5; - | ^^^^^^^^^^^^^ attempt to compute `i128::MAX * 5_i128`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:184:30 +error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow + --> $DIR/overflowing-consts.rs:179:30 | LL | const _NI128_MUL_P: &i128 = &(i128::MAX * 5); - | ^^^^^^^^^^^^^^^ attempt to compute `i128::MAX * 5_i128`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:186:22 +error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow + --> $DIR/overflowing-consts.rs:181:22 | LL | const _NU8_MUL: u8 = u8::MAX * 5; - | ^^^^^^^^^^^ attempt to compute `u8::MAX * 5_u8`, which would overflow + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:187:26 +error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow + --> $DIR/overflowing-consts.rs:182:26 | LL | const _NU8_MUL_P: &u8 = &(u8::MAX * 5); - | ^^^^^^^^^^^^^ attempt to compute `u8::MAX * 5_u8`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:189:24 +error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow + --> $DIR/overflowing-consts.rs:184:24 | LL | const _NU16_MUL: u16 = u16::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `u16::MAX * 5_u16`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:190:28 +error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow + --> $DIR/overflowing-consts.rs:185:28 | LL | const _NU16_MUL_P: &u16 = &(u16::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `u16::MAX * 5_u16`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:192:24 +error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow + --> $DIR/overflowing-consts.rs:187:24 | LL | const _NU32_MUL: u32 = u32::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `u32::MAX * 5_u32`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:193:28 +error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow + --> $DIR/overflowing-consts.rs:188:28 | LL | const _NU32_MUL_P: &u32 = &(u32::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `u32::MAX * 5_u32`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:195:24 +error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow + --> $DIR/overflowing-consts.rs:190:24 | LL | const _NU64_MUL: u64 = u64::MAX * 5; - | ^^^^^^^^^^^^ attempt to compute `u64::MAX * 5_u64`, which would overflow + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:196:28 +error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow + --> $DIR/overflowing-consts.rs:191:28 | LL | const _NU64_MUL_P: &u64 = &(u64::MAX * 5); - | ^^^^^^^^^^^^^^ attempt to compute `u64::MAX * 5_u64`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:198:26 +error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow + --> $DIR/overflowing-consts.rs:193:26 | LL | const _NU128_MUL: u128 = u128::MAX * 5; - | ^^^^^^^^^^^^^ attempt to compute `u128::MAX * 5_u128`, which would overflow + | ^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:199:30 +error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow + --> $DIR/overflowing-consts.rs:194:30 | LL | const _NU128_MUL_P: &u128 = &(u128::MAX * 5); - | ^^^^^^^^^^^^^^^ attempt to compute `u128::MAX * 5_u128`, which would overflow + | ^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:201:28 +error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow + --> $DIR/overflowing-consts.rs:196:28 | LL | const _NISIZE_MUL: isize = isize::MAX * 5; - | ^^^^^^^^^^^^^^ attempt to compute `isize::MAX * 5_isize`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:202:32 +error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow + --> $DIR/overflowing-consts.rs:197:32 | LL | const _NISIZE_MUL_P: &isize = &(isize::MAX * 5); - | ^^^^^^^^^^^^^^^^ attempt to compute `isize::MAX * 5_isize`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:204:28 +error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow + --> $DIR/overflowing-consts.rs:199:28 | LL | const _NUSIZE_MUL: usize = usize::MAX * 5; - | ^^^^^^^^^^^^^^ attempt to compute `usize::MAX * 5_usize`, which would overflow + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:205:32 +error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow + --> $DIR/overflowing-consts.rs:200:32 | LL | const _NUSIZE_MUL_P: &usize = &(usize::MAX * 5); - | ^^^^^^^^^^^^^^^^ attempt to compute `usize::MAX * 5_usize`, which would overflow + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:209:22 +error[E0080]: attempt to divide `1_i8` by zero + --> $DIR/overflowing-consts.rs:203:22 | LL | const _NI8_DIV: i8 = 1i8 / 0; - | ^^^^^^^ attempt to divide `1_i8` by zero + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:210:26 +error[E0080]: attempt to divide `1_i8` by zero + --> $DIR/overflowing-consts.rs:204:26 | LL | const _NI8_DIV_P: &i8 = &(1i8 / 0); - | ^^^^^^^^^ attempt to divide `1_i8` by zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:212:24 +error[E0080]: attempt to divide `1_i16` by zero + --> $DIR/overflowing-consts.rs:206:24 | LL | const _NI16_DIV: i16 = 1i16 / 0; - | ^^^^^^^^ attempt to divide `1_i16` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:213:28 +error[E0080]: attempt to divide `1_i16` by zero + --> $DIR/overflowing-consts.rs:207:28 | LL | const _NI16_DIV_P: &i16 = &(1i16 / 0); - | ^^^^^^^^^^ attempt to divide `1_i16` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:215:24 +error[E0080]: attempt to divide `1_i32` by zero + --> $DIR/overflowing-consts.rs:209:24 | LL | const _NI32_DIV: i32 = 1i32 / 0; - | ^^^^^^^^ attempt to divide `1_i32` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:216:28 +error[E0080]: attempt to divide `1_i32` by zero + --> $DIR/overflowing-consts.rs:210:28 | LL | const _NI32_DIV_P: &i32 = &(1i32 / 0); - | ^^^^^^^^^^ attempt to divide `1_i32` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:218:24 +error[E0080]: attempt to divide `1_i64` by zero + --> $DIR/overflowing-consts.rs:212:24 | LL | const _NI64_DIV: i64 = 1i64 / 0; - | ^^^^^^^^ attempt to divide `1_i64` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:219:28 +error[E0080]: attempt to divide `1_i64` by zero + --> $DIR/overflowing-consts.rs:213:28 | LL | const _NI64_DIV_P: &i64 = &(1i64 / 0); - | ^^^^^^^^^^ attempt to divide `1_i64` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:221:26 +error[E0080]: attempt to divide `1_i128` by zero + --> $DIR/overflowing-consts.rs:215:26 | LL | const _NI128_DIV: i128 = 1i128 / 0; - | ^^^^^^^^^ attempt to divide `1_i128` by zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:222:30 +error[E0080]: attempt to divide `1_i128` by zero + --> $DIR/overflowing-consts.rs:216:30 | LL | const _NI128_DIV_P: &i128 = &(1i128 / 0); - | ^^^^^^^^^^^ attempt to divide `1_i128` by zero + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:224:22 +error[E0080]: attempt to divide `1_u8` by zero + --> $DIR/overflowing-consts.rs:218:22 | LL | const _NU8_DIV: u8 = 1u8 / 0; - | ^^^^^^^ attempt to divide `1_u8` by zero + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:225:26 +error[E0080]: attempt to divide `1_u8` by zero + --> $DIR/overflowing-consts.rs:219:26 | LL | const _NU8_DIV_P: &u8 = &(1u8 / 0); - | ^^^^^^^^^ attempt to divide `1_u8` by zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:227:24 +error[E0080]: attempt to divide `1_u16` by zero + --> $DIR/overflowing-consts.rs:221:24 | LL | const _NU16_DIV: u16 = 1u16 / 0; - | ^^^^^^^^ attempt to divide `1_u16` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:228:28 +error[E0080]: attempt to divide `1_u16` by zero + --> $DIR/overflowing-consts.rs:222:28 | LL | const _NU16_DIV_P: &u16 = &(1u16 / 0); - | ^^^^^^^^^^ attempt to divide `1_u16` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:230:24 +error[E0080]: attempt to divide `1_u32` by zero + --> $DIR/overflowing-consts.rs:224:24 | LL | const _NU32_DIV: u32 = 1u32 / 0; - | ^^^^^^^^ attempt to divide `1_u32` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:231:28 +error[E0080]: attempt to divide `1_u32` by zero + --> $DIR/overflowing-consts.rs:225:28 | LL | const _NU32_DIV_P: &u32 = &(1u32 / 0); - | ^^^^^^^^^^ attempt to divide `1_u32` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:233:24 +error[E0080]: attempt to divide `1_u64` by zero + --> $DIR/overflowing-consts.rs:227:24 | LL | const _NU64_DIV: u64 = 1u64 / 0; - | ^^^^^^^^ attempt to divide `1_u64` by zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:234:28 +error[E0080]: attempt to divide `1_u64` by zero + --> $DIR/overflowing-consts.rs:228:28 | LL | const _NU64_DIV_P: &u64 = &(1u64 / 0); - | ^^^^^^^^^^ attempt to divide `1_u64` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:236:26 +error[E0080]: attempt to divide `1_u128` by zero + --> $DIR/overflowing-consts.rs:230:26 | LL | const _NU128_DIV: u128 = 1u128 / 0; - | ^^^^^^^^^ attempt to divide `1_u128` by zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:237:30 +error[E0080]: attempt to divide `1_u128` by zero + --> $DIR/overflowing-consts.rs:231:30 | LL | const _NU128_DIV_P: &u128 = &(1u128 / 0); - | ^^^^^^^^^^^ attempt to divide `1_u128` by zero + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:239:28 +error[E0080]: attempt to divide `1_isize` by zero + --> $DIR/overflowing-consts.rs:233:28 | LL | const _NISIZE_DIV: isize = 1isize / 0; - | ^^^^^^^^^^ attempt to divide `1_isize` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:240:32 +error[E0080]: attempt to divide `1_isize` by zero + --> $DIR/overflowing-consts.rs:234:32 | LL | const _NISIZE_DIV_P: &isize = &(1isize / 0); - | ^^^^^^^^^^^^ attempt to divide `1_isize` by zero + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:242:28 +error[E0080]: attempt to divide `1_usize` by zero + --> $DIR/overflowing-consts.rs:236:28 | LL | const _NUSIZE_DIV: usize = 1usize / 0; - | ^^^^^^^^^^ attempt to divide `1_usize` by zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:243:32 +error[E0080]: attempt to divide `1_usize` by zero + --> $DIR/overflowing-consts.rs:237:32 | LL | const _NUSIZE_DIV_P: &usize = &(1usize / 0); - | ^^^^^^^^^^^^ attempt to divide `1_usize` by zero + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:246:22 +error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero + --> $DIR/overflowing-consts.rs:240:22 | LL | const _NI8_MOD: i8 = 1i8 % 0; - | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:247:26 +error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero + --> $DIR/overflowing-consts.rs:241:26 | LL | const _NI8_MOD_P: &i8 = &(1i8 % 0); - | ^^^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:249:24 +error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero + --> $DIR/overflowing-consts.rs:243:24 | LL | const _NI16_MOD: i16 = 1i16 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:250:28 +error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero + --> $DIR/overflowing-consts.rs:244:28 | LL | const _NI16_MOD_P: &i16 = &(1i16 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:252:24 +error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero + --> $DIR/overflowing-consts.rs:246:24 | LL | const _NI32_MOD: i32 = 1i32 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:253:28 +error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero + --> $DIR/overflowing-consts.rs:247:28 | LL | const _NI32_MOD_P: &i32 = &(1i32 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:255:24 +error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero + --> $DIR/overflowing-consts.rs:249:24 | LL | const _NI64_MOD: i64 = 1i64 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:256:28 +error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero + --> $DIR/overflowing-consts.rs:250:28 | LL | const _NI64_MOD_P: &i64 = &(1i64 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:258:26 +error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero + --> $DIR/overflowing-consts.rs:252:26 | LL | const _NI128_MOD: i128 = 1i128 % 0; - | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:259:30 +error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero + --> $DIR/overflowing-consts.rs:253:30 | LL | const _NI128_MOD_P: &i128 = &(1i128 % 0); - | ^^^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:261:22 +error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero + --> $DIR/overflowing-consts.rs:255:22 | LL | const _NU8_MOD: u8 = 1u8 % 0; - | ^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero + | ^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:262:26 +error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero + --> $DIR/overflowing-consts.rs:256:26 | LL | const _NU8_MOD_P: &u8 = &(1u8 % 0); - | ^^^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:264:24 +error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero + --> $DIR/overflowing-consts.rs:258:24 | LL | const _NU16_MOD: u16 = 1u16 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:265:28 +error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero + --> $DIR/overflowing-consts.rs:259:28 | LL | const _NU16_MOD_P: &u16 = &(1u16 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:267:24 +error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero + --> $DIR/overflowing-consts.rs:261:24 | LL | const _NU32_MOD: u32 = 1u32 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:268:28 +error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero + --> $DIR/overflowing-consts.rs:262:28 | LL | const _NU32_MOD_P: &u32 = &(1u32 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:270:24 +error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero + --> $DIR/overflowing-consts.rs:264:24 | LL | const _NU64_MOD: u64 = 1u64 % 0; - | ^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero + | ^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:271:28 +error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero + --> $DIR/overflowing-consts.rs:265:28 | LL | const _NU64_MOD_P: &u64 = &(1u64 % 0); - | ^^^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:273:26 +error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero + --> $DIR/overflowing-consts.rs:267:26 | LL | const _NU128_MOD: u128 = 1u128 % 0; - | ^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero + | ^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:274:30 +error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero + --> $DIR/overflowing-consts.rs:268:30 | LL | const _NU128_MOD_P: &u128 = &(1u128 % 0); - | ^^^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero + | ^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:276:28 +error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero + --> $DIR/overflowing-consts.rs:270:28 | LL | const _NISIZE_MOD: isize = 1isize % 0; - | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:277:32 +error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero + --> $DIR/overflowing-consts.rs:271:32 | LL | const _NISIZE_MOD_P: &isize = &(1isize % 0); - | ^^^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:279:28 +error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero + --> $DIR/overflowing-consts.rs:273:28 | LL | const _NUSIZE_MOD: usize = 1usize % 0; - | ^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:280:32 +error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero + --> $DIR/overflowing-consts.rs:274:32 | LL | const _NUSIZE_MOD_P: &usize = &(1usize % 0); - | ^^^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:284:24 +error[E0080]: index out of bounds: the length is 3 but the index is 4 + --> $DIR/overflowing-consts.rs:277:24 | LL | const _NI32_OOB: i32 = [1, 2, 3][4]; - | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 + | ^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/overflowing-consts.rs:285:28 +error[E0080]: index out of bounds: the length is 3 but the index is 4 + --> $DIR/overflowing-consts.rs:278:28 | LL | const _NI32_OOB_P: &i32 = &([1, 2, 3][4]); - | ^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 + | ^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 170 previous errors diff --git a/tests/ui/consts/overflowing-consts.rs b/tests/ui/consts/overflowing-consts.rs index 5ff205ce58e..7c008573b87 100644 --- a/tests/ui/consts/overflowing-consts.rs +++ b/tests/ui/consts/overflowing-consts.rs @@ -9,280 +9,272 @@ //@ normalize-stderr: "shift left by `(64|32)_usize`, which" -> "shift left by `%BITS%`, which" //@ normalize-stderr: "shift right by `(64|32)_usize`, which" -> "shift right by `%BITS%`, which" - #[cfg(target_pointer_width = "32")] const BITS: usize = 32; #[cfg(target_pointer_width = "64")] const BITS: usize = 64; // Shift left -const _NI8_SHL: i8 = 1i8 << 8; //~ ERROR: evaluation of constant value failed -const _NI8_SHL_P: &i8 = &(1i8 << 8); //~ ERROR: evaluation of constant value failed - -const _NI16_SHL: i16 = 1i16 << 16; //~ ERROR: evaluation of constant value failed -const _NI16_SHL_P: &i16 = &(1i16 << 16); //~ ERROR: evaluation of constant value failed +const _NI8_SHL: i8 = 1i8 << 8; //~ ERROR: overflow +const _NI8_SHL_P: &i8 = &(1i8 << 8); //~ ERROR: overflow -const _NI32_SHL: i32 = 1i32 << 32; //~ ERROR: evaluation of constant value failed -const _NI32_SHL_P: &i32 = &(1i32 << 32); //~ ERROR: evaluation of constant value failed +const _NI16_SHL: i16 = 1i16 << 16; //~ ERROR: overflow +const _NI16_SHL_P: &i16 = &(1i16 << 16); //~ ERROR: overflow -const _NI64_SHL: i64 = 1i64 << 64; //~ ERROR: evaluation of constant value failed -const _NI64_SHL_P: &i64 = &(1i64 << 64); //~ ERROR: evaluation of constant value failed +const _NI32_SHL: i32 = 1i32 << 32; //~ ERROR: overflow +const _NI32_SHL_P: &i32 = &(1i32 << 32); //~ ERROR: overflow -const _NI128_SHL: i128 = 1i128 << 128; //~ ERROR: evaluation of constant value failed -const _NI128_SHL_P: &i128 = &(1i128 << 128); //~ ERROR: evaluation of constant value failed +const _NI64_SHL: i64 = 1i64 << 64; //~ ERROR: overflow +const _NI64_SHL_P: &i64 = &(1i64 << 64); //~ ERROR: overflow -const _NU8_SHL: u8 = 1u8 << 8; //~ ERROR: evaluation of constant value failed -const _NU8_SHL_P: &u8 = &(1u8 << 8); //~ ERROR: evaluation of constant value failed +const _NI128_SHL: i128 = 1i128 << 128; //~ ERROR: overflow +const _NI128_SHL_P: &i128 = &(1i128 << 128); //~ ERROR: overflow -const _NU16_SHL: u16 = 1u16 << 16; //~ ERROR: evaluation of constant value failed -const _NU16_SHL_P: &u16 = &(1u16 << 16); //~ ERROR: evaluation of constant value failed +const _NU8_SHL: u8 = 1u8 << 8; //~ ERROR: overflow +const _NU8_SHL_P: &u8 = &(1u8 << 8); //~ ERROR: overflow -const _NU32_SHL: u32 = 1u32 << 32; //~ ERROR: evaluation of constant value failed -const _NU32_SHL_P: &u32 = &(1u32 << 32); //~ ERROR: evaluation of constant value failed +const _NU16_SHL: u16 = 1u16 << 16; //~ ERROR: overflow +const _NU16_SHL_P: &u16 = &(1u16 << 16); //~ ERROR: overflow -const _NU64_SHL: u64 = 1u64 << 64; //~ ERROR: evaluation of constant value failed -const _NU64_SHL_P: &u64 = &(1u64 << 64); //~ ERROR: evaluation of constant value failed +const _NU32_SHL: u32 = 1u32 << 32; //~ ERROR: overflow +const _NU32_SHL_P: &u32 = &(1u32 << 32); //~ ERROR: overflow -const _NU128_SHL: u128 = 1u128 << 128; //~ ERROR: evaluation of constant value failed -const _NU128_SHL_P: &u128 = &(1u128 << 128); //~ ERROR: evaluation of constant value failed +const _NU64_SHL: u64 = 1u64 << 64; //~ ERROR: overflow +const _NU64_SHL_P: &u64 = &(1u64 << 64); //~ ERROR: overflow -const _NISIZE_SHL: isize = 1isize << BITS; //~ ERROR: evaluation of constant value failed -const _NISIZE_SHL_P: &isize = &(1isize << BITS); //~ ERROR: evaluation of constant value failed +const _NU128_SHL: u128 = 1u128 << 128; //~ ERROR: overflow +const _NU128_SHL_P: &u128 = &(1u128 << 128); //~ ERROR: overflow -const _NUSIZE_SHL: usize = 1usize << BITS; //~ ERROR: evaluation of constant value failed -const _NUSIZE_SHL_P: &usize = &(1usize << BITS); //~ ERROR: evaluation of constant value failed +const _NISIZE_SHL: isize = 1isize << BITS; //~ ERROR: overflow +const _NISIZE_SHL_P: &isize = &(1isize << BITS); //~ ERROR: overflow +const _NUSIZE_SHL: usize = 1usize << BITS; //~ ERROR: overflow +const _NUSIZE_SHL_P: &usize = &(1usize << BITS); //~ ERROR: overflow // Shift right -const _NI8_SHR: i8 = 1i8 >> 8; //~ ERROR: evaluation of constant value failed -const _NI8_SHR_P: &i8 = &(1i8 >> 8); //~ ERROR: evaluation of constant value failed +const _NI8_SHR: i8 = 1i8 >> 8; //~ ERROR: overflow +const _NI8_SHR_P: &i8 = &(1i8 >> 8); //~ ERROR: overflow -const _NI16_SHR: i16 = 1i16 >> 16; //~ ERROR: evaluation of constant value failed -const _NI16_SHR_P: &i16 = &(1i16 >> 16); //~ ERROR: evaluation of constant value failed +const _NI16_SHR: i16 = 1i16 >> 16; //~ ERROR: overflow +const _NI16_SHR_P: &i16 = &(1i16 >> 16); //~ ERROR: overflow -const _NI32_SHR: i32 = 1i32 >> 32; //~ ERROR: evaluation of constant value failed -const _NI32_SHR_P: &i32 = &(1i32 >> 32); //~ ERROR: evaluation of constant value failed +const _NI32_SHR: i32 = 1i32 >> 32; //~ ERROR: overflow +const _NI32_SHR_P: &i32 = &(1i32 >> 32); //~ ERROR: overflow -const _NI64_SHR: i64 = 1i64 >> 64; //~ ERROR: evaluation of constant value failed -const _NI64_SHR_P: &i64 = &(1i64 >> 64); //~ ERROR: evaluation of constant value failed +const _NI64_SHR: i64 = 1i64 >> 64; //~ ERROR: overflow +const _NI64_SHR_P: &i64 = &(1i64 >> 64); //~ ERROR: overflow -const _NI128_SHR: i128 = 1i128 >> 128; //~ ERROR: evaluation of constant value failed -const _NI128_SHR_P: &i128 = &(1i128 >> 128); //~ ERROR: evaluation of constant value failed +const _NI128_SHR: i128 = 1i128 >> 128; //~ ERROR: overflow +const _NI128_SHR_P: &i128 = &(1i128 >> 128); //~ ERROR: overflow -const _NU8_SHR: u8 = 1u8 >> 8; //~ ERROR: evaluation of constant value failed -const _NU8_SHR_P: &u8 = &(1u8 >> 8); //~ ERROR: evaluation of constant value failed +const _NU8_SHR: u8 = 1u8 >> 8; //~ ERROR: overflow +const _NU8_SHR_P: &u8 = &(1u8 >> 8); //~ ERROR: overflow -const _NU16_SHR: u16 = 1u16 >> 16; //~ ERROR: evaluation of constant value failed -const _NU16_SHR_P: &u16 = &(1u16 >> 16); //~ ERROR: evaluation of constant value failed +const _NU16_SHR: u16 = 1u16 >> 16; //~ ERROR: overflow +const _NU16_SHR_P: &u16 = &(1u16 >> 16); //~ ERROR: overflow -const _NU32_SHR: u32 = 1u32 >> 32; //~ ERROR: evaluation of constant value failed -const _NU32_SHR_P: &u32 = &(1u32 >> 32); //~ ERROR: evaluation of constant value failed +const _NU32_SHR: u32 = 1u32 >> 32; //~ ERROR: overflow +const _NU32_SHR_P: &u32 = &(1u32 >> 32); //~ ERROR: overflow -const _NU64_SHR: u64 = 1u64 >> 64; //~ ERROR: evaluation of constant value failed -const _NU64_SHR_P: &u64 = &(1u64 >> 64); //~ ERROR: evaluation of constant value failed +const _NU64_SHR: u64 = 1u64 >> 64; //~ ERROR: overflow +const _NU64_SHR_P: &u64 = &(1u64 >> 64); //~ ERROR: overflow -const _NU128_SHR: u128 = 1u128 >> 128; //~ ERROR: evaluation of constant value failed -const _NU128_SHR_P: &u128 = &(1u128 >> 128); //~ ERROR: evaluation of constant value failed +const _NU128_SHR: u128 = 1u128 >> 128; //~ ERROR: overflow +const _NU128_SHR_P: &u128 = &(1u128 >> 128); //~ ERROR: overflow -const _NISIZE_SHR: isize = 1isize >> BITS; //~ ERROR: evaluation of constant value failed -const _NISIZE_SHR_P: &isize = &(1isize >> BITS); //~ ERROR: evaluation of constant value failed - -const _NUSIZE_SHR: usize = 1usize >> BITS; //~ ERROR: evaluation of constant value failed -const _NUSIZE_SHR_P: &usize = &(1usize >> BITS); //~ ERROR: evaluation of constant value failed +const _NISIZE_SHR: isize = 1isize >> BITS; //~ ERROR: overflow +const _NISIZE_SHR_P: &isize = &(1isize >> BITS); //~ ERROR: overflow +const _NUSIZE_SHR: usize = 1usize >> BITS; //~ ERROR: overflow +const _NUSIZE_SHR_P: &usize = &(1usize >> BITS); //~ ERROR: overflow // Addition -const _NI8_ADD: i8 = 1i8 + i8::MAX; //~ ERROR: evaluation of constant value failed -const _NI8_ADD_P: &i8 = &(1i8 + i8::MAX); //~ ERROR: evaluation of constant value failed - -const _NI16_ADD: i16 = 1i16 + i16::MAX; //~ ERROR: evaluation of constant value failed -const _NI16_ADD_P: &i16 = &(1i16 + i16::MAX); //~ ERROR: evaluation of constant value failed +const _NI8_ADD: i8 = 1i8 + i8::MAX; //~ ERROR: overflow +const _NI8_ADD_P: &i8 = &(1i8 + i8::MAX); //~ ERROR: overflow -const _NI32_ADD: i32 = 1i32 + i32::MAX; //~ ERROR: evaluation of constant value failed -const _NI32_ADD_P: &i32 = &(1i32 + i32::MAX); //~ ERROR: evaluation of constant value failed +const _NI16_ADD: i16 = 1i16 + i16::MAX; //~ ERROR: overflow +const _NI16_ADD_P: &i16 = &(1i16 + i16::MAX); //~ ERROR: overflow -const _NI64_ADD: i64 = 1i64 + i64::MAX; //~ ERROR: evaluation of constant value failed -const _NI64_ADD_P: &i64 = &(1i64 + i64::MAX); //~ ERROR: evaluation of constant value failed +const _NI32_ADD: i32 = 1i32 + i32::MAX; //~ ERROR: overflow +const _NI32_ADD_P: &i32 = &(1i32 + i32::MAX); //~ ERROR: overflow -const _NI128_ADD: i128 = 1i128 + i128::MAX; //~ ERROR: evaluation of constant value failed -const _NI128_ADD_P: &i128 = &(1i128 + i128::MAX); //~ ERROR: evaluation of constant value failed +const _NI64_ADD: i64 = 1i64 + i64::MAX; //~ ERROR: overflow +const _NI64_ADD_P: &i64 = &(1i64 + i64::MAX); //~ ERROR: overflow -const _NU8_ADD: u8 = 1u8 + u8::MAX; //~ ERROR: evaluation of constant value failed -const _NU8_ADD_P: &u8 = &(1u8 + u8::MAX); //~ ERROR: evaluation of constant value failed +const _NI128_ADD: i128 = 1i128 + i128::MAX; //~ ERROR: overflow +const _NI128_ADD_P: &i128 = &(1i128 + i128::MAX); //~ ERROR: overflow -const _NU16_ADD: u16 = 1u16 + u16::MAX; //~ ERROR: evaluation of constant value failed -const _NU16_ADD_P: &u16 = &(1u16 + u16::MAX); //~ ERROR: evaluation of constant value failed +const _NU8_ADD: u8 = 1u8 + u8::MAX; //~ ERROR: overflow +const _NU8_ADD_P: &u8 = &(1u8 + u8::MAX); //~ ERROR: overflow -const _NU32_ADD: u32 = 1u32 + u32::MAX; //~ ERROR: evaluation of constant value failed -const _NU32_ADD_P: &u32 = &(1u32 + u32::MAX); //~ ERROR: evaluation of constant value failed +const _NU16_ADD: u16 = 1u16 + u16::MAX; //~ ERROR: overflow +const _NU16_ADD_P: &u16 = &(1u16 + u16::MAX); //~ ERROR: overflow -const _NU64_ADD: u64 = 1u64 + u64::MAX; //~ ERROR: evaluation of constant value failed -const _NU64_ADD_P: &u64 = &(1u64 + u64::MAX); //~ ERROR: evaluation of constant value failed +const _NU32_ADD: u32 = 1u32 + u32::MAX; //~ ERROR: overflow +const _NU32_ADD_P: &u32 = &(1u32 + u32::MAX); //~ ERROR: overflow -const _NU128_ADD: u128 = 1u128 + u128::MAX; //~ ERROR: evaluation of constant value failed -const _NU128_ADD_P: &u128 = &(1u128 + u128::MAX); //~ ERROR: evaluation of constant value failed +const _NU64_ADD: u64 = 1u64 + u64::MAX; //~ ERROR: overflow +const _NU64_ADD_P: &u64 = &(1u64 + u64::MAX); //~ ERROR: overflow -const _NISIZE_ADD: isize = 1isize + isize::MAX; //~ ERROR: evaluation of constant value failed -const _NISIZE_ADD_P: &isize = &(1isize + isize::MAX); //~ ERROR: evaluation of constant value failed +const _NU128_ADD: u128 = 1u128 + u128::MAX; //~ ERROR: overflow +const _NU128_ADD_P: &u128 = &(1u128 + u128::MAX); //~ ERROR: overflow -const _NUSIZE_ADD: usize = 1usize + usize::MAX; //~ ERROR: evaluation of constant value failed -const _NUSIZE_ADD_P: &usize = &(1usize + usize::MAX); //~ ERROR: evaluation of constant value failed +const _NISIZE_ADD: isize = 1isize + isize::MAX; //~ ERROR: overflow +const _NISIZE_ADD_P: &isize = &(1isize + isize::MAX); //~ ERROR: overflow +const _NUSIZE_ADD: usize = 1usize + usize::MAX; //~ ERROR: overflow +const _NUSIZE_ADD_P: &usize = &(1usize + usize::MAX); //~ ERROR: overflow // Subtraction -const _NI8_SUB: i8 = -5i8 - i8::MAX; //~ ERROR: evaluation of constant value failed -const _NI8_SUB_P: &i8 = &(-5i8 - i8::MAX); //~ ERROR: evaluation of constant value failed +const _NI8_SUB: i8 = -5i8 - i8::MAX; //~ ERROR: overflow +const _NI8_SUB_P: &i8 = &(-5i8 - i8::MAX); //~ ERROR: overflow -const _NI16_SUB: i16 = -5i16 - i16::MAX; //~ ERROR: evaluation of constant value failed -const _NI16_SUB_P: &i16 = &(-5i16 - i16::MAX); //~ ERROR: evaluation of constant value failed +const _NI16_SUB: i16 = -5i16 - i16::MAX; //~ ERROR: overflow +const _NI16_SUB_P: &i16 = &(-5i16 - i16::MAX); //~ ERROR: overflow -const _NI32_SUB: i32 = -5i32 - i32::MAX; //~ ERROR: evaluation of constant value failed -const _NI32_SUB_P: &i32 = &(-5i32 - i32::MAX); //~ ERROR: evaluation of constant value failed +const _NI32_SUB: i32 = -5i32 - i32::MAX; //~ ERROR: overflow +const _NI32_SUB_P: &i32 = &(-5i32 - i32::MAX); //~ ERROR: overflow -const _NI64_SUB: i64 = -5i64 - i64::MAX; //~ ERROR: evaluation of constant value failed -const _NI64_SUB_P: &i64 = &(-5i64 - i64::MAX); //~ ERROR: evaluation of constant value failed +const _NI64_SUB: i64 = -5i64 - i64::MAX; //~ ERROR: overflow +const _NI64_SUB_P: &i64 = &(-5i64 - i64::MAX); //~ ERROR: overflow -const _NI128_SUB: i128 = -5i128 - i128::MAX; //~ ERROR: evaluation of constant value failed -const _NI128_SUB_P: &i128 = &(-5i128 - i128::MAX); //~ ERROR: evaluation of constant value failed +const _NI128_SUB: i128 = -5i128 - i128::MAX; //~ ERROR: overflow +const _NI128_SUB_P: &i128 = &(-5i128 - i128::MAX); //~ ERROR: overflow -const _NU8_SUB: u8 = 1u8 - 5; //~ ERROR: evaluation of constant value failed -const _NU8_SUB_P: &u8 = &(1u8 - 5); //~ ERROR: evaluation of constant value failed +const _NU8_SUB: u8 = 1u8 - 5; //~ ERROR: overflow +const _NU8_SUB_P: &u8 = &(1u8 - 5); //~ ERROR: overflow -const _NU16_SUB: u16 = 1u16 - 5; //~ ERROR: evaluation of constant value failed -const _NU16_SUB_P: &u16 = &(1u16 - 5); //~ ERROR: evaluation of constant value failed +const _NU16_SUB: u16 = 1u16 - 5; //~ ERROR: overflow +const _NU16_SUB_P: &u16 = &(1u16 - 5); //~ ERROR: overflow -const _NU32_SUB: u32 = 1u32 - 5; //~ ERROR: evaluation of constant value failed -const _NU32_SUB_P: &u32 = &(1u32 - 5); //~ ERROR: evaluation of constant value failed +const _NU32_SUB: u32 = 1u32 - 5; //~ ERROR: overflow +const _NU32_SUB_P: &u32 = &(1u32 - 5); //~ ERROR: overflow -const _NU64_SUB: u64 = 1u64 - 5; //~ ERROR: evaluation of constant value failed -const _NU64_SUB_P: &u64 = &(1u64 - 5); //~ ERROR: evaluation of constant value failed +const _NU64_SUB: u64 = 1u64 - 5; //~ ERROR: overflow +const _NU64_SUB_P: &u64 = &(1u64 - 5); //~ ERROR: overflow -const _NU128_SUB: u128 = 1u128 - 5; //~ ERROR: evaluation of constant value failed -const _NU128_SUB_P: &u128 = &(1u128 - 5); //~ ERROR: evaluation of constant value failed +const _NU128_SUB: u128 = 1u128 - 5; //~ ERROR: overflow +const _NU128_SUB_P: &u128 = &(1u128 - 5); //~ ERROR: overflow -const _NISIZE_SUB: isize = -5isize - isize::MAX; //~ ERROR: evaluation of constant value failed -const _NISIZE_SUB_P: &isize = &(-5isize - isize::MAX); //~ ERROR: evaluation of constant value failed - -const _NUSIZE_SUB: usize = 1usize - 5 ; //~ ERROR: evaluation of constant value failed -const _NUSIZE_SUB_P: &usize = &(1usize - 5 ); //~ ERROR: evaluation of constant value failed +const _NISIZE_SUB: isize = -5isize - isize::MAX; //~ ERROR: overflow +const _NISIZE_SUB_P: &isize = &(-5isize - isize::MAX); //~ ERROR: overflow +const _NUSIZE_SUB: usize = 1usize - 5; //~ ERROR: overflow +const _NUSIZE_SUB_P: &usize = &(1usize - 5); //~ ERROR: overflow // Multiplication -const _NI8_MUL: i8 = i8::MAX * 5; //~ ERROR: evaluation of constant value failed -const _NI8_MUL_P: &i8 = &(i8::MAX * 5); //~ ERROR: evaluation of constant value failed - -const _NI16_MUL: i16 = i16::MAX * 5; //~ ERROR: evaluation of constant value failed -const _NI16_MUL_P: &i16 = &(i16::MAX * 5); //~ ERROR: evaluation of constant value failed +const _NI8_MUL: i8 = i8::MAX * 5; //~ ERROR: overflow +const _NI8_MUL_P: &i8 = &(i8::MAX * 5); //~ ERROR: overflow -const _NI32_MUL: i32 = i32::MAX * 5; //~ ERROR: evaluation of constant value failed -const _NI32_MUL_P: &i32 = &(i32::MAX * 5); //~ ERROR: evaluation of constant value failed +const _NI16_MUL: i16 = i16::MAX * 5; //~ ERROR: overflow +const _NI16_MUL_P: &i16 = &(i16::MAX * 5); //~ ERROR: overflow -const _NI64_MUL: i64 = i64::MAX * 5; //~ ERROR: evaluation of constant value failed -const _NI64_MUL_P: &i64 = &(i64::MAX * 5); //~ ERROR: evaluation of constant value failed +const _NI32_MUL: i32 = i32::MAX * 5; //~ ERROR: overflow +const _NI32_MUL_P: &i32 = &(i32::MAX * 5); //~ ERROR: overflow -const _NI128_MUL: i128 = i128::MAX * 5; //~ ERROR: evaluation of constant value failed -const _NI128_MUL_P: &i128 = &(i128::MAX * 5); //~ ERROR: evaluation of constant value failed +const _NI64_MUL: i64 = i64::MAX * 5; //~ ERROR: overflow +const _NI64_MUL_P: &i64 = &(i64::MAX * 5); //~ ERROR: overflow -const _NU8_MUL: u8 = u8::MAX * 5; //~ ERROR: evaluation of constant value failed -const _NU8_MUL_P: &u8 = &(u8::MAX * 5); //~ ERROR: evaluation of constant value failed +const _NI128_MUL: i128 = i128::MAX * 5; //~ ERROR: overflow +const _NI128_MUL_P: &i128 = &(i128::MAX * 5); //~ ERROR: overflow -const _NU16_MUL: u16 = u16::MAX * 5; //~ ERROR: evaluation of constant value failed -const _NU16_MUL_P: &u16 = &(u16::MAX * 5); //~ ERROR: evaluation of constant value failed +const _NU8_MUL: u8 = u8::MAX * 5; //~ ERROR: overflow +const _NU8_MUL_P: &u8 = &(u8::MAX * 5); //~ ERROR: overflow -const _NU32_MUL: u32 = u32::MAX * 5; //~ ERROR: evaluation of constant value failed -const _NU32_MUL_P: &u32 = &(u32::MAX * 5); //~ ERROR: evaluation of constant value failed +const _NU16_MUL: u16 = u16::MAX * 5; //~ ERROR: overflow +const _NU16_MUL_P: &u16 = &(u16::MAX * 5); //~ ERROR: overflow -const _NU64_MUL: u64 = u64::MAX * 5; //~ ERROR: evaluation of constant value failed -const _NU64_MUL_P: &u64 = &(u64::MAX * 5); //~ ERROR: evaluation of constant value failed +const _NU32_MUL: u32 = u32::MAX * 5; //~ ERROR: overflow +const _NU32_MUL_P: &u32 = &(u32::MAX * 5); //~ ERROR: overflow -const _NU128_MUL: u128 = u128::MAX * 5; //~ ERROR: evaluation of constant value failed -const _NU128_MUL_P: &u128 = &(u128::MAX * 5); //~ ERROR: evaluation of constant value failed +const _NU64_MUL: u64 = u64::MAX * 5; //~ ERROR: overflow +const _NU64_MUL_P: &u64 = &(u64::MAX * 5); //~ ERROR: overflow -const _NISIZE_MUL: isize = isize::MAX * 5; //~ ERROR: evaluation of constant value failed -const _NISIZE_MUL_P: &isize = &(isize::MAX * 5); //~ ERROR: evaluation of constant value failed +const _NU128_MUL: u128 = u128::MAX * 5; //~ ERROR: overflow +const _NU128_MUL_P: &u128 = &(u128::MAX * 5); //~ ERROR: overflow -const _NUSIZE_MUL: usize = usize::MAX * 5; //~ ERROR: evaluation of constant value failed -const _NUSIZE_MUL_P: &usize = &(usize::MAX * 5); //~ ERROR: evaluation of constant value failed +const _NISIZE_MUL: isize = isize::MAX * 5; //~ ERROR: overflow +const _NISIZE_MUL_P: &isize = &(isize::MAX * 5); //~ ERROR: overflow +const _NUSIZE_MUL: usize = usize::MAX * 5; //~ ERROR: overflow +const _NUSIZE_MUL_P: &usize = &(usize::MAX * 5); //~ ERROR: overflow // Division -const _NI8_DIV: i8 = 1i8 / 0; //~ ERROR: evaluation of constant value failed -const _NI8_DIV_P: &i8 = &(1i8 / 0); //~ ERROR: evaluation of constant value failed +const _NI8_DIV: i8 = 1i8 / 0; //~ ERROR: by zero +const _NI8_DIV_P: &i8 = &(1i8 / 0); //~ ERROR: by zero -const _NI16_DIV: i16 = 1i16 / 0; //~ ERROR: evaluation of constant value failed -const _NI16_DIV_P: &i16 = &(1i16 / 0); //~ ERROR: evaluation of constant value failed +const _NI16_DIV: i16 = 1i16 / 0; //~ ERROR: by zero +const _NI16_DIV_P: &i16 = &(1i16 / 0); //~ ERROR: by zero -const _NI32_DIV: i32 = 1i32 / 0; //~ ERROR: evaluation of constant value failed -const _NI32_DIV_P: &i32 = &(1i32 / 0); //~ ERROR: evaluation of constant value failed +const _NI32_DIV: i32 = 1i32 / 0; //~ ERROR: by zero +const _NI32_DIV_P: &i32 = &(1i32 / 0); //~ ERROR: by zero -const _NI64_DIV: i64 = 1i64 / 0; //~ ERROR: evaluation of constant value failed -const _NI64_DIV_P: &i64 = &(1i64 / 0); //~ ERROR: evaluation of constant value failed +const _NI64_DIV: i64 = 1i64 / 0; //~ ERROR: by zero +const _NI64_DIV_P: &i64 = &(1i64 / 0); //~ ERROR: by zero -const _NI128_DIV: i128 = 1i128 / 0; //~ ERROR: evaluation of constant value failed -const _NI128_DIV_P: &i128 = &(1i128 / 0); //~ ERROR: evaluation of constant value failed +const _NI128_DIV: i128 = 1i128 / 0; //~ ERROR: by zero +const _NI128_DIV_P: &i128 = &(1i128 / 0); //~ ERROR: by zero -const _NU8_DIV: u8 = 1u8 / 0; //~ ERROR: evaluation of constant value failed -const _NU8_DIV_P: &u8 = &(1u8 / 0); //~ ERROR: evaluation of constant value failed +const _NU8_DIV: u8 = 1u8 / 0; //~ ERROR: by zero +const _NU8_DIV_P: &u8 = &(1u8 / 0); //~ ERROR: by zero -const _NU16_DIV: u16 = 1u16 / 0; //~ ERROR: evaluation of constant value failed -const _NU16_DIV_P: &u16 = &(1u16 / 0); //~ ERROR: evaluation of constant value failed +const _NU16_DIV: u16 = 1u16 / 0; //~ ERROR: by zero +const _NU16_DIV_P: &u16 = &(1u16 / 0); //~ ERROR: by zero -const _NU32_DIV: u32 = 1u32 / 0; //~ ERROR: evaluation of constant value failed -const _NU32_DIV_P: &u32 = &(1u32 / 0); //~ ERROR: evaluation of constant value failed +const _NU32_DIV: u32 = 1u32 / 0; //~ ERROR: by zero +const _NU32_DIV_P: &u32 = &(1u32 / 0); //~ ERROR: by zero -const _NU64_DIV: u64 = 1u64 / 0; //~ ERROR: evaluation of constant value failed -const _NU64_DIV_P: &u64 = &(1u64 / 0); //~ ERROR: evaluation of constant value failed +const _NU64_DIV: u64 = 1u64 / 0; //~ ERROR: by zero +const _NU64_DIV_P: &u64 = &(1u64 / 0); //~ ERROR: by zero -const _NU128_DIV: u128 = 1u128 / 0; //~ ERROR: evaluation of constant value failed -const _NU128_DIV_P: &u128 = &(1u128 / 0); //~ ERROR: evaluation of constant value failed +const _NU128_DIV: u128 = 1u128 / 0; //~ ERROR: by zero +const _NU128_DIV_P: &u128 = &(1u128 / 0); //~ ERROR: by zero -const _NISIZE_DIV: isize = 1isize / 0; //~ ERROR: evaluation of constant value failed -const _NISIZE_DIV_P: &isize = &(1isize / 0); //~ ERROR: evaluation of constant value failed +const _NISIZE_DIV: isize = 1isize / 0; //~ ERROR: by zero +const _NISIZE_DIV_P: &isize = &(1isize / 0); //~ ERROR: by zero -const _NUSIZE_DIV: usize = 1usize / 0; //~ ERROR: evaluation of constant value failed -const _NUSIZE_DIV_P: &usize = &(1usize / 0); //~ ERROR: evaluation of constant value failed +const _NUSIZE_DIV: usize = 1usize / 0; //~ ERROR: by zero +const _NUSIZE_DIV_P: &usize = &(1usize / 0); //~ ERROR: by zero // Modulus -const _NI8_MOD: i8 = 1i8 % 0; //~ ERROR: evaluation of constant value failed -const _NI8_MOD_P: &i8 = &(1i8 % 0); //~ ERROR: evaluation of constant value failed +const _NI8_MOD: i8 = 1i8 % 0; //~ ERROR: divisor of zero +const _NI8_MOD_P: &i8 = &(1i8 % 0); //~ ERROR: divisor of zero -const _NI16_MOD: i16 = 1i16 % 0; //~ ERROR: evaluation of constant value failed -const _NI16_MOD_P: &i16 = &(1i16 % 0); //~ ERROR: evaluation of constant value failed +const _NI16_MOD: i16 = 1i16 % 0; //~ ERROR: divisor of zero +const _NI16_MOD_P: &i16 = &(1i16 % 0); //~ ERROR: divisor of zero -const _NI32_MOD: i32 = 1i32 % 0; //~ ERROR: evaluation of constant value failed -const _NI32_MOD_P: &i32 = &(1i32 % 0); //~ ERROR: evaluation of constant value failed +const _NI32_MOD: i32 = 1i32 % 0; //~ ERROR: divisor of zero +const _NI32_MOD_P: &i32 = &(1i32 % 0); //~ ERROR: divisor of zero -const _NI64_MOD: i64 = 1i64 % 0; //~ ERROR: evaluation of constant value failed -const _NI64_MOD_P: &i64 = &(1i64 % 0); //~ ERROR: evaluation of constant value failed +const _NI64_MOD: i64 = 1i64 % 0; //~ ERROR: divisor of zero +const _NI64_MOD_P: &i64 = &(1i64 % 0); //~ ERROR: divisor of zero -const _NI128_MOD: i128 = 1i128 % 0; //~ ERROR: evaluation of constant value failed -const _NI128_MOD_P: &i128 = &(1i128 % 0); //~ ERROR: evaluation of constant value failed +const _NI128_MOD: i128 = 1i128 % 0; //~ ERROR: divisor of zero +const _NI128_MOD_P: &i128 = &(1i128 % 0); //~ ERROR: divisor of zero -const _NU8_MOD: u8 = 1u8 % 0; //~ ERROR: evaluation of constant value failed -const _NU8_MOD_P: &u8 = &(1u8 % 0); //~ ERROR: evaluation of constant value failed +const _NU8_MOD: u8 = 1u8 % 0; //~ ERROR: divisor of zero +const _NU8_MOD_P: &u8 = &(1u8 % 0); //~ ERROR: divisor of zero -const _NU16_MOD: u16 = 1u16 % 0; //~ ERROR: evaluation of constant value failed -const _NU16_MOD_P: &u16 = &(1u16 % 0); //~ ERROR: evaluation of constant value failed +const _NU16_MOD: u16 = 1u16 % 0; //~ ERROR: divisor of zero +const _NU16_MOD_P: &u16 = &(1u16 % 0); //~ ERROR: divisor of zero -const _NU32_MOD: u32 = 1u32 % 0; //~ ERROR: evaluation of constant value failed -const _NU32_MOD_P: &u32 = &(1u32 % 0); //~ ERROR: evaluation of constant value failed +const _NU32_MOD: u32 = 1u32 % 0; //~ ERROR: divisor of zero +const _NU32_MOD_P: &u32 = &(1u32 % 0); //~ ERROR: divisor of zero -const _NU64_MOD: u64 = 1u64 % 0; //~ ERROR: evaluation of constant value failed -const _NU64_MOD_P: &u64 = &(1u64 % 0); //~ ERROR: evaluation of constant value failed +const _NU64_MOD: u64 = 1u64 % 0; //~ ERROR: divisor of zero +const _NU64_MOD_P: &u64 = &(1u64 % 0); //~ ERROR: divisor of zero -const _NU128_MOD: u128 = 1u128 % 0; //~ ERROR: evaluation of constant value failed -const _NU128_MOD_P: &u128 = &(1u128 % 0); //~ ERROR: evaluation of constant value failed +const _NU128_MOD: u128 = 1u128 % 0; //~ ERROR: divisor of zero +const _NU128_MOD_P: &u128 = &(1u128 % 0); //~ ERROR: divisor of zero -const _NISIZE_MOD: isize = 1isize % 0; //~ ERROR: evaluation of constant value failed -const _NISIZE_MOD_P: &isize = &(1isize % 0); //~ ERROR: evaluation of constant value failed - -const _NUSIZE_MOD: usize = 1usize % 0; //~ ERROR: evaluation of constant value failed -const _NUSIZE_MOD_P: &usize = &(1usize % 0); //~ ERROR: evaluation of constant value failed +const _NISIZE_MOD: isize = 1isize % 0; //~ ERROR: divisor of zero +const _NISIZE_MOD_P: &isize = &(1isize % 0); //~ ERROR: divisor of zero +const _NUSIZE_MOD: usize = 1usize % 0; //~ ERROR: divisor of zero +const _NUSIZE_MOD_P: &usize = &(1usize % 0); //~ ERROR: divisor of zero // Out of bounds access -const _NI32_OOB: i32 = [1, 2, 3][4]; //~ ERROR: evaluation of constant value failed -const _NI32_OOB_P: &i32 = &([1, 2, 3][4]); //~ ERROR: evaluation of constant value failed - +const _NI32_OOB: i32 = [1, 2, 3][4]; //~ ERROR: the length is 3 but the index is 4 +const _NI32_OOB_P: &i32 = &([1, 2, 3][4]); //~ ERROR: the length is 3 but the index is 4 pub fn main() {} diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs index e458a6f98ad..d7977bfba77 100644 --- a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs +++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs @@ -11,7 +11,6 @@ pub struct Data([u8; (1 << 47) - 1]); const _: &'static Data = &Data([0; (1 << 47) - 1]); -//~^ERROR: evaluation of constant value failed -//~| NOTE tried to allocate more memory than available to compiler +//~^ ERROR: tried to allocate more memory than available to compiler fn main() {} diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr index 02180c1e4c6..c0e06e9efdf 100644 --- a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr +++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: tried to allocate more memory than available to compiler --> $DIR/promoted_running_out_of_memory_issue-130687.rs:13:32 | LL | const _: &'static Data = &Data([0; (1 << 47) - 1]); - | ^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/promoted_size_overflow.rs b/tests/ui/consts/promoted_size_overflow.rs index ebd5ab06487..232fb76c75b 100644 --- a/tests/ui/consts/promoted_size_overflow.rs +++ b/tests/ui/consts/promoted_size_overflow.rs @@ -1,7 +1,6 @@ //@ only-64bit pub struct Data([u8; usize::MAX >> 2]); const _: &'static [Data] = &[]; -//~^ERROR: evaluation of constant value failed -//~| NOTE too big for the target architecture +//~^ ERROR: too big for the target architecture fn main() {} diff --git a/tests/ui/consts/promoted_size_overflow.stderr b/tests/ui/consts/promoted_size_overflow.stderr index cfb8260bed0..688dd0c2cab 100644 --- a/tests/ui/consts/promoted_size_overflow.stderr +++ b/tests/ui/consts/promoted_size_overflow.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: values of the type `[u8; 4611686018427387903]` are too big for the target architecture --> $DIR/promoted_size_overflow.rs:3:29 | LL | const _: &'static [Data] = &[]; - | ^^ values of the type `[u8; 4611686018427387903]` are too big for the target architecture + | ^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.rs b/tests/ui/consts/qualif-indirect-mutation-fail.rs index 4abb231c29f..b70fca7b864 100644 --- a/tests/ui/consts/qualif-indirect-mutation-fail.rs +++ b/tests/ui/consts/qualif-indirect-mutation-fail.rs @@ -15,7 +15,7 @@ pub const A1: () = { let b = &mut y; std::mem::swap(a, b); std::mem::forget(y); -}; //~ ERROR evaluation of constant value failed +}; //~ ERROR calling non-const function ` as Drop>::drop` // Mutable borrow of a type with drop impl. pub const A2: () = { @@ -26,7 +26,7 @@ pub const A2: () = { std::mem::swap(a, b); std::mem::forget(y); let _z = x; //~ ERROR destructor of -}; //~ ERROR evaluation of constant value failed +}; //~ ERROR calling non-const function ` as Drop>::drop` // Shared borrow of a type that might be !Freeze and Drop. pub const fn g1() { diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.stderr b/tests/ui/consts/qualif-indirect-mutation-fail.stderr index dd575e07c20..bdb5ad9dc11 100644 --- a/tests/ui/consts/qualif-indirect-mutation-fail.stderr +++ b/tests/ui/consts/qualif-indirect-mutation-fail.stderr @@ -7,11 +7,11 @@ LL | let mut x = None; LL | }; | - value is dropped here -error[E0080]: evaluation of constant value failed +error[E0080]: calling non-const function ` as Drop>::drop` --> $DIR/qualif-indirect-mutation-fail.rs:18:1 | LL | }; - | ^ calling non-const function ` as Drop>::drop` + | ^ evaluation of constant value failed | note: inside `drop_in_place::> - shim(Some(Option))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -28,11 +28,11 @@ LL | let _z = x; LL | }; | - value is dropped here -error[E0080]: evaluation of constant value failed +error[E0080]: calling non-const function ` as Drop>::drop` --> $DIR/qualif-indirect-mutation-fail.rs:29:1 | LL | }; - | ^ calling non-const function ` as Drop>::drop` + | ^ evaluation of constant value failed | note: inside `drop_in_place::> - shim(Some(Option))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/recursive-zst-static.default.stderr b/tests/ui/consts/recursive-zst-static.default.stderr index dedca16db8d..af97c945b92 100644 --- a/tests/ui/consts/recursive-zst-static.default.stderr +++ b/tests/ui/consts/recursive-zst-static.default.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; - | ^^^ encountered static that tried to initialize itself with itself + | ^^^ could not evaluate static initializer error[E0391]: cycle detected when evaluating initializer of static `A` --> $DIR/recursive-zst-static.rs:13:16 diff --git a/tests/ui/consts/recursive-zst-static.rs b/tests/ui/consts/recursive-zst-static.rs index a52624fada8..852caae9493 100644 --- a/tests/ui/consts/recursive-zst-static.rs +++ b/tests/ui/consts/recursive-zst-static.rs @@ -8,7 +8,7 @@ // See https://github.com/rust-lang/rust/issues/71078 for more details. static FOO: () = FOO; -//~^ ERROR could not evaluate static initializer +//~^ ERROR encountered static that tried to initialize itself with itself static A: () = B; //~ ERROR cycle detected when evaluating initializer of static `A` static B: () = A; diff --git a/tests/ui/consts/recursive-zst-static.unleash.stderr b/tests/ui/consts/recursive-zst-static.unleash.stderr index dedca16db8d..af97c945b92 100644 --- a/tests/ui/consts/recursive-zst-static.unleash.stderr +++ b/tests/ui/consts/recursive-zst-static.unleash.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; - | ^^^ encountered static that tried to initialize itself with itself + | ^^^ could not evaluate static initializer error[E0391]: cycle detected when evaluating initializer of static `A` --> $DIR/recursive-zst-static.rs:13:16 diff --git a/tests/ui/consts/recursive.rs b/tests/ui/consts/recursive.rs index b5703d11310..ed23baf0768 100644 --- a/tests/ui/consts/recursive.rs +++ b/tests/ui/consts/recursive.rs @@ -4,6 +4,6 @@ const fn f(x: T) { //~ WARN function cannot return without recursing f(x); } -const X: () = f(1); //~ ERROR evaluation of constant value failed +const X: () = f(1); //~ ERROR reached the configured maximum number of stack frames fn main() {} diff --git a/tests/ui/consts/recursive.stderr b/tests/ui/consts/recursive.stderr index fd38b078b94..7721d153729 100644 --- a/tests/ui/consts/recursive.stderr +++ b/tests/ui/consts/recursive.stderr @@ -9,11 +9,11 @@ LL | f(x); = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error[E0080]: evaluation of constant value failed +error[E0080]: reached the configured maximum number of stack frames --> $DIR/recursive.rs:7:15 | LL | const X: () = f(1); - | ^^^^ reached the configured maximum number of stack frames + | ^^^^ evaluation of constant value failed | note: [... 126 additional calls inside `f::` ...] --> $DIR/recursive.rs:4:5 diff --git a/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr b/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr index 6812b3734ef..3d908b54287 100644 --- a/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-called-fn.rs:10:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-called-fn.rs:19:17 diff --git a/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr b/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr index 6812b3734ef..3d908b54287 100644 --- a/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-called-fn.rs:10:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-called-fn.rs:19:17 diff --git a/tests/ui/consts/required-consts/collect-in-called-fn.rs b/tests/ui/consts/required-consts/collect-in-called-fn.rs index 93947950af2..2045b8266c7 100644 --- a/tests/ui/consts/required-consts/collect-in-called-fn.rs +++ b/tests/ui/consts/required-consts/collect-in-called-fn.rs @@ -7,7 +7,7 @@ struct Fail(T); impl Fail { - const C: () = panic!(); //~ERROR evaluation of `Fail::::C` failed + const C: () = panic!(); //~ERROR evaluation panicked: explicit panic } #[inline(never)] diff --git a/tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr index 661aea71604..f0670f7a746 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-closure.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-closure.rs:17:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr index 661aea71604..f0670f7a746 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-closure.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-closure.rs:17:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-closure.rs b/tests/ui/consts/required-consts/collect-in-dead-closure.rs index a00214c62db..5f8b6bbb174 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-closure.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-closure.rs @@ -6,7 +6,7 @@ struct Fail(T); impl Fail { - const C: () = panic!(); //~ERROR evaluation of `Fail::::C` failed + const C: () = panic!(); //~ERROR evaluation panicked: explicit panic } // This function is not actually called, but it is mentioned in a closure that is coerced to a diff --git a/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr index 31e6b2f487f..dbf330ada04 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-drop.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-drop.rs:16:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-drop.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-drop.opt.stderr index 31e6b2f487f..dbf330ada04 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-drop.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-drop.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-drop.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-drop.rs:16:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-drop.rs b/tests/ui/consts/required-consts/collect-in-dead-drop.rs index 389fcf5dfc9..f7293d162df 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-drop.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-drop.rs @@ -6,7 +6,7 @@ struct Fail(T); impl Fail { - const C: () = panic!(); //~ERROR evaluation of `Fail::::C` failed + const C: () = panic!(); //~ERROR evaluation panicked: explicit panic } // This function is not actually called, but is mentioned implicitly as destructor in dead code in a diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.noopt.stderr index 32dc1cb304b..178ffa20612 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn-behind-assoc-type.rs:10:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-fn-behind-assoc-type.rs:16:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.opt.stderr index 32dc1cb304b..178ffa20612 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn-behind-assoc-type.rs:10:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-fn-behind-assoc-type.rs:16:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.rs b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.rs index 9c36af50bb7..e6be9f56cb7 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.rs @@ -7,7 +7,7 @@ struct Fail(T); impl Fail { - const C: () = panic!(); //~ERROR evaluation of `Fail::::C` failed + const C: () = panic!(); //~ERROR evaluation panicked: explicit panic } #[inline(never)] diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.noopt.stderr index d22cf579448..78336273a73 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn-behind-generic.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-fn-behind-generic.rs:15:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.opt.stderr index d22cf579448..78336273a73 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn-behind-generic.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-fn-behind-generic.rs:15:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.rs b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.rs index 5829d914ee1..a86902af526 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.rs @@ -6,7 +6,7 @@ struct Fail(T); impl Fail { - const C: () = panic!(); //~ERROR evaluation of `Fail::::C` failed + const C: () = panic!(); //~ERROR evaluation panicked: explicit panic } #[inline(never)] diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.noopt.stderr index 91daa2f9bc3..825f646630a 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `m::Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn-behind-opaque-type.rs:11:23 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `m::Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-fn-behind-opaque-type.rs:19:21 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.opt.stderr index 91daa2f9bc3..825f646630a 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `m::Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn-behind-opaque-type.rs:11:23 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `m::Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-fn-behind-opaque-type.rs:19:21 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.rs b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.rs index f333f3462c7..4cdb2741354 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.rs @@ -8,7 +8,7 @@ mod m { struct Fail(T); impl Fail { - const C: () = panic!(); //~ERROR evaluation of `m::Fail::::C` failed + const C: () = panic!(); //~ERROR: evaluation panicked: explicit panic } pub type NotCalledFn = impl Fn(); diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr index d254fc60c0c..f2a0bd91e78 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-fn.rs:19:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn.opt.stderr index d254fc60c0c..f2a0bd91e78 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-fn.rs:19:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn.rs b/tests/ui/consts/required-consts/collect-in-dead-fn.rs index 1c95e0c303f..0c479580106 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-fn.rs @@ -6,7 +6,7 @@ struct Fail(T); impl Fail { - const C: () = panic!(); //~ERROR evaluation of `Fail::::C` failed + const C: () = panic!(); //~ERROR evaluation panicked: explicit panic } // This function is not actually called, but it is mentioned in dead code in a function that is diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.noopt.stderr index c14837ce442..7235cfe0d7c 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Late::::FAIL` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fnptr-in-const.rs:9:22 | LL | const FAIL: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Late::::FAIL` failed note: erroneous constant encountered --> $DIR/collect-in-dead-fnptr-in-const.rs:10:28 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.opt.stderr index c14837ce442..7235cfe0d7c 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Late::::FAIL` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fnptr-in-const.rs:9:22 | LL | const FAIL: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Late::::FAIL` failed note: erroneous constant encountered --> $DIR/collect-in-dead-fnptr-in-const.rs:10:28 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.rs b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.rs index 8b6344c93f3..04544cb4139 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.rs @@ -6,7 +6,7 @@ struct Late(T); impl Late { - const FAIL: () = panic!(); //~ERROR evaluation of `Late::::FAIL` failed + const FAIL: () = panic!(); //~ERROR evaluation panicked: explicit panic const FNPTR: fn() = || Self::FAIL; } diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fnptr.noopt.stderr index 284e1a70a20..50dc52625c1 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fnptr.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fnptr.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-fnptr.rs:18:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fnptr.opt.stderr index 284e1a70a20..50dc52625c1 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fnptr.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fnptr.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-fnptr.rs:18:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr.rs b/tests/ui/consts/required-consts/collect-in-dead-fnptr.rs index acbe34829e8..4cdb50f4385 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fnptr.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr.rs @@ -6,7 +6,7 @@ struct Fail(T); impl Fail { - const C: () = panic!(); //~ERROR evaluation of `Fail::::C` failed + const C: () = panic!(); //~ERROR evaluation panicked: explicit panic } // This function is not actually called, but it is mentioned in dead code in a function that is diff --git a/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr index 8b43c67c085..96fa3b7f4ce 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-move.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-move.rs:16:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-move.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-move.opt.stderr index 8b43c67c085..96fa3b7f4ce 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-move.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-move.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-move.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-move.rs:16:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-move.rs b/tests/ui/consts/required-consts/collect-in-dead-move.rs index 6a224a375cf..4e2d959db32 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-move.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-move.rs @@ -6,7 +6,7 @@ struct Fail(T); impl Fail { - const C: () = panic!(); //~ERROR evaluation of `Fail::::C` failed + const C: () = panic!(); //~ERROR evaluation panicked: explicit panic } // This function is not actually called, but is mentioned implicitly as destructor in dead code in a diff --git a/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr index 4056f28541d..a036b7bdd5f 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-vtable.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-vtable.rs:22:21 diff --git a/tests/ui/consts/required-consts/collect-in-dead-vtable.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-vtable.opt.stderr index 4056f28541d..a036b7bdd5f 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-vtable.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-vtable.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-vtable.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-dead-vtable.rs:22:21 diff --git a/tests/ui/consts/required-consts/collect-in-dead-vtable.rs b/tests/ui/consts/required-consts/collect-in-dead-vtable.rs index f63207eafec..d4ad7308377 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-vtable.rs +++ b/tests/ui/consts/required-consts/collect-in-dead-vtable.rs @@ -6,7 +6,7 @@ struct Fail(T); impl Fail { - const C: () = panic!(); //~ERROR evaluation of `Fail::::C` failed + const C: () = panic!(); //~ERROR evaluation panicked: explicit panic } trait MyTrait { diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr b/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr index c5f3b0009f5..9e9d4b34124 100644 --- a/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-promoted-const.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-promoted-const.rs:20:21 diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr b/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr index 6f36aaf314d..d97604f29e6 100644 --- a/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-promoted-const.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-promoted-const.rs:20:21 @@ -10,11 +10,11 @@ note: erroneous constant encountered LL | let _val = &Fail::::C; | ^^^^^^^^^^^^ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-promoted-const.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/collect-in-promoted-const.rs:20:21 diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.rs b/tests/ui/consts/required-consts/collect-in-promoted-const.rs index 4a3ce92e8f9..25c8cb7e804 100644 --- a/tests/ui/consts/required-consts/collect-in-promoted-const.rs +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.rs @@ -6,8 +6,8 @@ struct Fail(T); impl Fail { - const C: () = panic!(); //~ERROR evaluation of `Fail::::C` failed - //[opt]~^ ERROR evaluation of `Fail::::C` failed + const C: () = panic!(); //~ERROR evaluation panicked: explicit panic + //[opt]~^ ERROR evaluation panicked: explicit panic // (Not sure why optimizations lead to this being emitted twice, but as long as compilation // fails either way it's fine.) } diff --git a/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr index f98e2c17202..6b864e7e51f 100644 --- a/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/interpret-in-const-called-fn.rs:8:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/interpret-in-const-called-fn.rs:18:9 diff --git a/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr b/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr index f98e2c17202..6b864e7e51f 100644 --- a/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/interpret-in-const-called-fn.rs:8:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/interpret-in-const-called-fn.rs:18:9 diff --git a/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs b/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs index 1ed6853f0a4..9309457e22a 100644 --- a/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs +++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs @@ -5,7 +5,7 @@ struct Fail(T); impl Fail { - const C: () = panic!(); //~ERROR evaluation of `Fail::::C` failed + const C: () = panic!(); //~ERROR explicit panic //~| NOTE in this expansion of panic! } diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr index 1375ac751f2..569e1970ad1 100644 --- a/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: entering unreachable code --> $DIR/interpret-in-promoted.rs:15:28 | LL | let _x: &'static () = &ub(); - | ^^^^ entering unreachable code + | ^^^^ evaluation of constant value failed | note: inside `ub` --> $DIR/interpret-in-promoted.rs:9:5 diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr b/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr index 1375ac751f2..569e1970ad1 100644 --- a/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: entering unreachable code --> $DIR/interpret-in-promoted.rs:15:28 | LL | let _x: &'static () = &ub(); - | ^^^^ entering unreachable code + | ^^^^ evaluation of constant value failed | note: inside `ub` --> $DIR/interpret-in-promoted.rs:9:5 diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.rs b/tests/ui/consts/required-consts/interpret-in-promoted.rs index 85d2ea3418c..b223e6d16aa 100644 --- a/tests/ui/consts/required-consts/interpret-in-promoted.rs +++ b/tests/ui/consts/required-consts/interpret-in-promoted.rs @@ -12,7 +12,7 @@ const unsafe fn ub() { pub const FOO: () = unsafe { // Make sure that this gets promoted and then fails to evaluate, and we deal with that // correctly. - let _x: &'static () = &ub(); //~ ERROR evaluation of constant value failed + let _x: &'static () = &ub(); //~ ERROR unreachable code }; fn main() {} diff --git a/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr index 28daf265af4..e9294054be6 100644 --- a/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/interpret-in-static.rs:8:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/interpret-in-static.rs:17:9 diff --git a/tests/ui/consts/required-consts/interpret-in-static.opt.stderr b/tests/ui/consts/required-consts/interpret-in-static.opt.stderr index 28daf265af4..e9294054be6 100644 --- a/tests/ui/consts/required-consts/interpret-in-static.opt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-static.opt.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Fail::::C` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/interpret-in-static.rs:8:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `Fail::::C` failed note: erroneous constant encountered --> $DIR/interpret-in-static.rs:17:9 diff --git a/tests/ui/consts/required-consts/interpret-in-static.rs b/tests/ui/consts/required-consts/interpret-in-static.rs index 7ddf15f9121..19ad6be1c9f 100644 --- a/tests/ui/consts/required-consts/interpret-in-static.rs +++ b/tests/ui/consts/required-consts/interpret-in-static.rs @@ -5,7 +5,7 @@ struct Fail(T); impl Fail { - const C: () = panic!(); //~ERROR evaluation of `Fail::::C` failed + const C: () = panic!(); //~ERROR explicit panic //~| NOTE in this expansion of panic! } diff --git a/tests/ui/consts/slice-index-overflow-issue-130284.rs b/tests/ui/consts/slice-index-overflow-issue-130284.rs index 6877ebe1476..f5235b0e1f1 100644 --- a/tests/ui/consts/slice-index-overflow-issue-130284.rs +++ b/tests/ui/consts/slice-index-overflow-issue-130284.rs @@ -5,8 +5,7 @@ const C: () = { unsafe { // This used to ICE, but it should just report UB. let _ice = (*fat)[usize::MAX - 1]; - //~^ERROR: constant value failed - //~| NOTE overflow + //~^ERROR: overflow } }; diff --git a/tests/ui/consts/slice-index-overflow-issue-130284.stderr b/tests/ui/consts/slice-index-overflow-issue-130284.stderr index e3e676c8949..50d325bf4d2 100644 --- a/tests/ui/consts/slice-index-overflow-issue-130284.stderr +++ b/tests/ui/consts/slice-index-overflow-issue-130284.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` --> $DIR/slice-index-overflow-issue-130284.rs:7:20 | LL | let _ice = (*fat)[usize::MAX - 1]; - | ^^^^^^^^^^^^^^^^^^^^^^ overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.rs b/tests/ui/consts/static_mut_containing_mut_ref2.rs index 2b1fe55df78..e9910816fc1 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.rs +++ b/tests/ui/consts/static_mut_containing_mut_ref2.rs @@ -4,7 +4,7 @@ static mut STDERR_BUFFER_SPACE: u8 = 0; pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; - //~^ ERROR could not evaluate static initializer + //~^ ERROR modifying a static's initial value }; fn main() {} diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.stderr index 37cd2b51ad1..ecdf9ce3890 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref2.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: modifying a static's initial value from another static's initializer --> $DIR/static_mut_containing_mut_ref2.rs:6:5 | LL | *(&mut STDERR_BUFFER_SPACE) = 42; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer error: aborting due to 1 previous error diff --git a/tests/ui/consts/static_mut_containing_mut_ref3.rs b/tests/ui/consts/static_mut_containing_mut_ref3.rs index c24c7e27920..42a4d04cde6 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref3.rs +++ b/tests/ui/consts/static_mut_containing_mut_ref3.rs @@ -1,6 +1,6 @@ static mut FOO: (u8, u8) = (42, 43); static mut BAR: () = unsafe { FOO.0 = 99; }; -//~^ ERROR could not evaluate static initializer +//~^ ERROR modifying a static's initial value fn main() {} diff --git a/tests/ui/consts/static_mut_containing_mut_ref3.stderr b/tests/ui/consts/static_mut_containing_mut_ref3.stderr index be84608acf7..7ad56e27805 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref3.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref3.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: modifying a static's initial value from another static's initializer --> $DIR/static_mut_containing_mut_ref3.rs:3:31 | LL | static mut BAR: () = unsafe { FOO.0 = 99; }; - | ^^^^^^^^^^ modifying a static's initial value from another static's initializer + | ^^^^^^^^^^ could not evaluate static initializer error: aborting due to 1 previous error diff --git a/tests/ui/consts/uninhabited-const-issue-61744.rs b/tests/ui/consts/uninhabited-const-issue-61744.rs index 802d422888b..d33f9c268a5 100644 --- a/tests/ui/consts/uninhabited-const-issue-61744.rs +++ b/tests/ui/consts/uninhabited-const-issue-61744.rs @@ -10,7 +10,7 @@ pub const unsafe fn hint_unreachable() -> ! { } trait Const { - const CONSTANT: i32 = unsafe { fake_type() }; //~ ERROR evaluation of `fake_type::` failed + const CONSTANT: i32 = unsafe { fake_type() }; //~ ERROR reached the configured maximum number of stack frames } impl Const for T {} diff --git a/tests/ui/consts/uninhabited-const-issue-61744.stderr b/tests/ui/consts/uninhabited-const-issue-61744.stderr index d0e90f9a423..95d8ceebcd7 100644 --- a/tests/ui/consts/uninhabited-const-issue-61744.stderr +++ b/tests/ui/consts/uninhabited-const-issue-61744.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `fake_type::` failed +error[E0080]: reached the configured maximum number of stack frames --> $DIR/uninhabited-const-issue-61744.rs:13:36 | LL | const CONSTANT: i32 = unsafe { fake_type() }; - | ^^^^^^^^^^^ reached the configured maximum number of stack frames + | ^^^^^^^^^^^ evaluation of `fake_type::` failed | note: inside `fake_type::` --> $DIR/uninhabited-const-issue-61744.rs:5:5 diff --git a/tests/ui/consts/validate_never_arrays.rs b/tests/ui/consts/validate_never_arrays.rs index 055bb1c69c8..b0ea064188b 100644 --- a/tests/ui/consts/validate_never_arrays.rs +++ b/tests/ui/consts/validate_never_arrays.rs @@ -3,10 +3,10 @@ //@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" #![feature(never_type)] -const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior +const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR invalid value const _: &[!; 0] = unsafe { &*(1_usize as *const [!; 0]) }; // ok const _: &[!] = unsafe { &*(1_usize as *const [!; 0]) }; // ok -const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior -const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; //~ ERROR undefined behavior +const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR invalid value +const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; //~ ERROR invalid value fn main() {} diff --git a/tests/ui/consts/validate_never_arrays.stderr b/tests/ui/consts/validate_never_arrays.stderr index 12090e483a4..0f503df4060 100644 --- a/tests/ui/consts/validate_never_arrays.stderr +++ b/tests/ui/consts/validate_never_arrays.stderr @@ -1,30 +1,30 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] --> $DIR/validate_never_arrays.rs:6:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] + | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .[0]: encountered a value of the never type `!` --> $DIR/validate_never_arrays.rs:9:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a value of the never type `!` + | ^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .[0]: encountered a value of the never type `!` --> $DIR/validate_never_arrays.rs:10:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; - | ^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a value of the never type `!` + | ^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { diff --git a/tests/ui/consts/write-to-static-mut-in-static.rs b/tests/ui/consts/write-to-static-mut-in-static.rs index a2985d05a79..ce15d9e912b 100644 --- a/tests/ui/consts/write-to-static-mut-in-static.rs +++ b/tests/ui/consts/write-to-static-mut-in-static.rs @@ -1,10 +1,10 @@ pub static mut A: u32 = 0; pub static mut B: () = unsafe { A = 1; }; -//~^ ERROR could not evaluate static initializer +//~^ ERROR modifying a static's initial value pub static mut C: u32 = unsafe { C = 1; 0 }; pub static D: u32 = D; -//~^ ERROR could not evaluate static initializer +//~^ ERROR static that tried to initialize itself with itself fn main() {} diff --git a/tests/ui/consts/write-to-static-mut-in-static.stderr b/tests/ui/consts/write-to-static-mut-in-static.stderr index 9616f8eeeb7..7d2aa0e3422 100644 --- a/tests/ui/consts/write-to-static-mut-in-static.stderr +++ b/tests/ui/consts/write-to-static-mut-in-static.stderr @@ -1,14 +1,14 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: modifying a static's initial value from another static's initializer --> $DIR/write-to-static-mut-in-static.rs:2:33 | LL | pub static mut B: () = unsafe { A = 1; }; - | ^^^^^ modifying a static's initial value from another static's initializer + | ^^^^^ could not evaluate static initializer -error[E0080]: could not evaluate static initializer +error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/write-to-static-mut-in-static.rs:7:21 | LL | pub static D: u32 = D; - | ^ encountered static that tried to initialize itself with itself + | ^ could not evaluate static initializer error: aborting due to 2 previous errors diff --git a/tests/ui/enum-discriminant/eval-error.rs b/tests/ui/enum-discriminant/eval-error.rs index 08b71d52a8b..45ac9472a4b 100644 --- a/tests/ui/enum-discriminant/eval-error.rs +++ b/tests/ui/enum-discriminant/eval-error.rs @@ -6,7 +6,7 @@ union Foo { enum Bar { Boo = { - let _: Option = None; //~ ERROR evaluation of constant value failed + let _: Option = None; //~ ERROR `Foo` has an unknown layout 0 }, } diff --git a/tests/ui/enum-discriminant/eval-error.stderr b/tests/ui/enum-discriminant/eval-error.stderr index 6bec2c8b420..7e15a5e0c76 100644 --- a/tests/ui/enum-discriminant/eval-error.stderr +++ b/tests/ui/enum-discriminant/eval-error.stderr @@ -45,11 +45,11 @@ help: wrap the field type in `ManuallyDrop<...>` LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + -error[E0080]: evaluation of constant value failed +error[E0080]: the type `Foo` has an unknown layout --> $DIR/eval-error.rs:9:30 | LL | let _: Option = None; - | ^^^^ the type `Foo` has an unknown layout + | ^^^^ evaluation of constant value failed error: aborting due to 5 previous errors diff --git a/tests/ui/error-codes/E0080.rs b/tests/ui/error-codes/E0080.rs index 55f45055f01..0d19f02a9f1 100644 --- a/tests/ui/error-codes/E0080.rs +++ b/tests/ui/error-codes/E0080.rs @@ -1,9 +1,6 @@ enum Enum { - X = (1 << 500), //~ ERROR E0080 - //~| NOTE attempt to shift left by `500_i32`, which would overflow - Y = (1 / 0) //~ ERROR E0080 - //~| NOTE attempt to divide `1_isize` by zero + X = (1 << 500), //~ ERROR attempt to shift left by `500_i32`, which would overflow + Y = (1 / 0), //~ ERROR attempt to divide `1_isize` by zero } -fn main() { -} +fn main() {} diff --git a/tests/ui/error-codes/E0080.stderr b/tests/ui/error-codes/E0080.stderr index 60ed9a4358f..da364332a70 100644 --- a/tests/ui/error-codes/E0080.stderr +++ b/tests/ui/error-codes/E0080.stderr @@ -1,14 +1,14 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: attempt to shift left by `500_i32`, which would overflow --> $DIR/E0080.rs:2:9 | LL | X = (1 << 500), - | ^^^^^^^^^^ attempt to shift left by `500_i32`, which would overflow + | ^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/E0080.rs:4:9 +error[E0080]: attempt to divide `1_isize` by zero + --> $DIR/E0080.rs:3:9 | -LL | Y = (1 / 0) - | ^^^^^^^ attempt to divide `1_isize` by zero +LL | Y = (1 / 0), + | ^^^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr b/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr index 8fb51f5b637..ab6af9349dc 100644 --- a/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr +++ b/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: reached the configured maximum number of stack frames --> $DIR/ctfe-id-unlimited.rs:28:20 | LL | const ID_ED: u32 = rec_id(ORIGINAL); - | ^^^^^^^^^^^^^^^^ reached the configured maximum number of stack frames + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `rec_id` --> $DIR/ctfe-id-unlimited.rs:21:5 diff --git a/tests/ui/explicit-tail-calls/ctfe-id-unlimited.rs b/tests/ui/explicit-tail-calls/ctfe-id-unlimited.rs index 9e89f4066bb..53cccb38e2b 100644 --- a/tests/ui/explicit-tail-calls/ctfe-id-unlimited.rs +++ b/tests/ui/explicit-tail-calls/ctfe-id-unlimited.rs @@ -25,7 +25,7 @@ const fn rec_id(n: u32) -> u32 { const ORIGINAL: u32 = 12345; // Original number, but with identity function applied // (this is the same, but requires execution of the recursion) -const ID_ED: u32 = rec_id(ORIGINAL); //[return]~ error: evaluation of constant value failed +const ID_ED: u32 = rec_id(ORIGINAL); //[return]~ ERROR: reached the configured maximum number of stack frames // Assert to make absolutely sure the computation actually happens const ASSERT: () = assert!(ORIGINAL == ID_ED); diff --git a/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs index e7038a01d2d..bf32232cee3 100644 --- a/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs +++ b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs @@ -10,7 +10,7 @@ const fn g() { //~^ NOTE in this expansion of panic! } -const _: () = f(); //~ ERROR evaluation of constant value failed -//~^ NOTE explicit panic +const _: () = f(); //~ NOTE evaluation of constant value failed +//~^ ERROR explicit panic fn main() {} diff --git a/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr index 3bdd09e9683..c30818c8340 100644 --- a/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr +++ b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/ctfe-tail-call-panic.rs:13:15 | LL | const _: () = f(); - | ^^^ evaluation panicked: explicit panic + | ^^^ evaluation of constant value failed | note: inside `g` --> $DIR/ctfe-tail-call-panic.rs:9:5 diff --git a/tests/ui/extern/issue-28324.rs b/tests/ui/extern/issue-28324.rs index a5e240fa283..4af400d823b 100644 --- a/tests/ui/extern/issue-28324.rs +++ b/tests/ui/extern/issue-28324.rs @@ -4,6 +4,6 @@ extern "C" { pub static BAZ: u32 = *&error_message_count; //~^ ERROR use of extern static is unsafe and requires -//~| ERROR could not evaluate static initializer +//~| ERROR cannot access extern static fn main() {} diff --git a/tests/ui/extern/issue-28324.stderr b/tests/ui/extern/issue-28324.stderr index 93eb6ff8174..8ad3ac57152 100644 --- a/tests/ui/extern/issue-28324.stderr +++ b/tests/ui/extern/issue-28324.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: cannot access extern static `error_message_count` --> $DIR/issue-28324.rs:5:23 | LL | pub static BAZ: u32 = *&error_message_count; - | ^^^^^^^^^^^^^^^^^^^^^ cannot access extern static `error_message_count` + | ^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer error[E0133]: use of extern static is unsafe and requires unsafe function or block --> $DIR/issue-28324.rs:5:25 diff --git a/tests/ui/generic-const-items/def-site-eval.fail.stderr b/tests/ui/generic-const-items/def-site-eval.fail.stderr index 4e7d9d8154a..d9cf2f15dd7 100644 --- a/tests/ui/generic-const-items/def-site-eval.fail.stderr +++ b/tests/ui/generic-const-items/def-site-eval.fail.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/def-site-eval.rs:13:20 | LL | const _<'_a>: () = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/generic-const-items/def-site-eval.rs b/tests/ui/generic-const-items/def-site-eval.rs index b95e40c05d4..fa3ef5907b2 100644 --- a/tests/ui/generic-const-items/def-site-eval.rs +++ b/tests/ui/generic-const-items/def-site-eval.rs @@ -10,6 +10,6 @@ const _<_T>: () = panic!(); const _: () = panic!(); #[cfg(fail)] -const _<'_a>: () = panic!(); //[fail]~ ERROR evaluation of constant value failed +const _<'_a>: () = panic!(); //[fail]~ ERROR evaluation panicked: explicit panic fn main() {} diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs index 93f01c9577c..102c7b1e5f9 100644 --- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs +++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs @@ -3,7 +3,7 @@ // Ensure that we check if trivial bounds on const items hold or not. -const UNUSABLE: () = () //~ ERROR evaluation of constant value failed +const UNUSABLE: () = () //~ ERROR entering unreachable code where String: Copy; diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr index 407682fee56..e2df1559d07 100644 --- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr +++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr @@ -1,10 +1,10 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: entering unreachable code --> $DIR/trivially-unsatisfied-bounds-0.rs:6:1 | LL | / const UNUSABLE: () = () LL | | where LL | | String: Copy; - | |_________________^ entering unreachable code + | |_________________^ evaluation of constant value failed error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/trivially-unsatisfied-bounds-0.rs:11:13 diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.rs b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.rs index 9243deac870..ebe97a65bbf 100644 --- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.rs +++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.rs @@ -7,6 +7,6 @@ const UNUSED: () = () where String: Copy; -//~^^^ ERROR evaluation of constant value failed +//~^^^ ERROR unreachable code fn main() {} diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr index b8438a0589c..83254da8644 100644 --- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr +++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr @@ -1,10 +1,10 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: entering unreachable code --> $DIR/trivially-unsatisfied-bounds-1.rs:7:1 | LL | / const UNUSED: () = () LL | | where LL | | String: Copy; - | |_________________^ entering unreachable code + | |_________________^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/generic-const-items/unsatisfied-evaluatable-bounds.rs b/tests/ui/generic-const-items/unsatisfied-evaluatable-bounds.rs index 961e5b4aeeb..13ce1f7de5b 100644 --- a/tests/ui/generic-const-items/unsatisfied-evaluatable-bounds.rs +++ b/tests/ui/generic-const-items/unsatisfied-evaluatable-bounds.rs @@ -5,7 +5,7 @@ const POSITIVE: usize = N where - [(); N - 1]:; //~ ERROR evaluation of `POSITIVE::<0>::{constant#0}` failed + [(); N - 1]:; //~ ERROR overflow fn main() { let _ = POSITIVE::<0>; diff --git a/tests/ui/generic-const-items/unsatisfied-evaluatable-bounds.stderr b/tests/ui/generic-const-items/unsatisfied-evaluatable-bounds.stderr index f522190e8aa..b6c80301944 100644 --- a/tests/ui/generic-const-items/unsatisfied-evaluatable-bounds.stderr +++ b/tests/ui/generic-const-items/unsatisfied-evaluatable-bounds.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `POSITIVE::<0>::{constant#0}` failed +error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/unsatisfied-evaluatable-bounds.rs:8:10 | LL | [(); N - 1]:; - | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow + | ^^^^^ evaluation of `POSITIVE::<0>::{constant#0}` failed error: aborting due to 1 previous error diff --git a/tests/ui/generics/post_monomorphization_error_backtrace.rs b/tests/ui/generics/post_monomorphization_error_backtrace.rs index f5f36ef03ae..9f53751584b 100644 --- a/tests/ui/generics/post_monomorphization_error_backtrace.rs +++ b/tests/ui/generics/post_monomorphization_error_backtrace.rs @@ -4,12 +4,12 @@ fn assert_zst() { struct F(T); impl F { const V: () = assert!(std::mem::size_of::() == 0); - //~^ ERROR: evaluation of `assert_zst::F::::V` failed [E0080] + //~^ NOTE: evaluation of `assert_zst::F::::V` failed //~| NOTE: in this expansion of assert! - //~| NOTE: assertion failed - //~| ERROR: evaluation of `assert_zst::F::::V` failed [E0080] + //~| ERROR: assertion failed + //~| NOTE: evaluation of `assert_zst::F::::V` failed //~| NOTE: in this expansion of assert! - //~| NOTE: assertion failed + //~| ERROR: assertion failed } F::::V; //~^NOTE: erroneous constant @@ -23,7 +23,6 @@ fn foo() { //~| NOTE: the above error was encountered while instantiating `fn assert_zst::` } - fn bar() { foo::() } diff --git a/tests/ui/generics/post_monomorphization_error_backtrace.stderr b/tests/ui/generics/post_monomorphization_error_backtrace.stderr index 96aa04ee359..f2146df1f8d 100644 --- a/tests/ui/generics/post_monomorphization_error_backtrace.stderr +++ b/tests/ui/generics/post_monomorphization_error_backtrace.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `assert_zst::F::::V` failed +error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::() == 0 --> $DIR/post_monomorphization_error_backtrace.rs:6:23 | LL | const V: () = assert!(std::mem::size_of::() == 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: assertion failed: std::mem::size_of::() == 0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::::V` failed note: erroneous constant encountered --> $DIR/post_monomorphization_error_backtrace.rs:14:5 @@ -16,11 +16,11 @@ note: the above error was encountered while instantiating `fn assert_zst::` LL | assert_zst::() | ^^^^^^^^^^^^^^^^^ -error[E0080]: evaluation of `assert_zst::F::::V` failed +error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::() == 0 --> $DIR/post_monomorphization_error_backtrace.rs:6:23 | LL | const V: () = assert!(std::mem::size_of::() == 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: assertion failed: std::mem::size_of::() == 0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::::V` failed note: erroneous constant encountered --> $DIR/post_monomorphization_error_backtrace.rs:14:5 diff --git a/tests/ui/infinite/infinite-recursion-const-fn.rs b/tests/ui/infinite/infinite-recursion-const-fn.rs index 7b7f6fafab5..3c0b3b9741b 100644 --- a/tests/ui/infinite/infinite-recursion-const-fn.rs +++ b/tests/ui/infinite/infinite-recursion-const-fn.rs @@ -6,6 +6,6 @@ const fn a() -> usize { const fn b() -> usize { a() } -const ARR: [i32; a()] = [5; 6]; //~ ERROR evaluation of constant value failed [E0080] +const ARR: [i32; a()] = [5; 6]; //~ ERROR reached the configured maximum number of stack frames fn main() {} diff --git a/tests/ui/infinite/infinite-recursion-const-fn.stderr b/tests/ui/infinite/infinite-recursion-const-fn.stderr index 524abdf4d7a..c61dacee437 100644 --- a/tests/ui/infinite/infinite-recursion-const-fn.stderr +++ b/tests/ui/infinite/infinite-recursion-const-fn.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: reached the configured maximum number of stack frames --> $DIR/infinite-recursion-const-fn.rs:9:18 | LL | const ARR: [i32; a()] = [5; 6]; - | ^^^ reached the configured maximum number of stack frames + | ^^^ evaluation of constant value failed | note: inside `a` --> $DIR/infinite-recursion-const-fn.rs:4:5 diff --git a/tests/ui/inline-const/const-expr-generic-err.stderr b/tests/ui/inline-const/const-expr-generic-err.stderr index a40e8bceb36..d703e7e2c9d 100644 --- a/tests/ui/inline-const/const-expr-generic-err.stderr +++ b/tests/ui/inline-const/const-expr-generic-err.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `foo::::{constant#0}` failed +error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::() == 0 --> $DIR/const-expr-generic-err.rs:4:13 | LL | const { assert!(std::mem::size_of::() == 0); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: assertion failed: std::mem::size_of::() == 0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `foo::::{constant#0}` failed note: erroneous constant encountered --> $DIR/const-expr-generic-err.rs:4:5 @@ -16,11 +16,11 @@ note: the above error was encountered while instantiating `fn foo::` LL | foo::(); | ^^^^^^^^^^^^ -error[E0080]: evaluation of `bar::<0>::{constant#0}` failed +error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/const-expr-generic-err.rs:8:13 | LL | const { N - 1 } - | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow + | ^^^^^ evaluation of `bar::<0>::{constant#0}` failed note: erroneous constant encountered --> $DIR/const-expr-generic-err.rs:8:5 diff --git a/tests/ui/inline-const/required-const.stderr b/tests/ui/inline-const/required-const.stderr index 2f618e54ed3..06c7c370654 100644 --- a/tests/ui/inline-const/required-const.stderr +++ b/tests/ui/inline-const/required-const.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `foo::::{constant#0}` failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/required-const.rs:6:17 | LL | const { panic!() } - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of `foo::::{constant#0}` failed note: erroneous constant encountered --> $DIR/required-const.rs:6:9 diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs index fdb25a3ae3f..15f4a9a778e 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs @@ -2,22 +2,19 @@ const RAW_EQ_PADDING: bool = unsafe { std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) -//~^ ERROR evaluation of constant value failed -//~| NOTE requires initialized memory +//~^ ERROR requires initialized memory }; const RAW_EQ_PTR: bool = unsafe { std::intrinsics::raw_eq(&(&0), &(&1)) -//~^ ERROR evaluation of constant value failed -//~| NOTE unable to turn pointer into integer +//~^ ERROR unable to turn pointer into integer }; const RAW_EQ_NOT_ALIGNED: bool = unsafe { let arr = [0u8; 4]; let aref = &*arr.as_ptr().cast::(); std::intrinsics::raw_eq(aref, aref) -//~^ ERROR evaluation of constant value failed -//~| NOTE alignment +//~^ ERROR alignment }; pub fn main() { diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr index b8fdfe7bef3..cf899b29eae 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr @@ -1,23 +1,23 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory --> $DIR/intrinsic-raw_eq-const-bad.rs:4:5 | LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed - --> $DIR/intrinsic-raw_eq-const-bad.rs:10:5 +error[E0080]: unable to turn pointer into integer + --> $DIR/intrinsic-raw_eq-const-bad.rs:9:5 | LL | std::intrinsics::raw_eq(&(&0), &(&1)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: evaluation of constant value failed - --> $DIR/intrinsic-raw_eq-const-bad.rs:18:5 +error[E0080]: accessing memory with alignment 1, but alignment 4 is required + --> $DIR/intrinsic-raw_eq-const-bad.rs:16:5 | LL | std::intrinsics::raw_eq(aref, aref) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment 1, but alignment 4 is required + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 3 previous errors diff --git a/tests/ui/issues/issue-76191.rs b/tests/ui/issues/issue-76191.rs index 277624c005a..d2de44380c3 100644 --- a/tests/ui/issues/issue-76191.rs +++ b/tests/ui/issues/issue-76191.rs @@ -6,7 +6,7 @@ use std::ops::RangeInclusive; const RANGE: RangeInclusive = 0..=255; const RANGE2: RangeInclusive = panic!(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR evaluation panicked: explicit panic fn main() { let n: i32 = 1; diff --git a/tests/ui/issues/issue-76191.stderr b/tests/ui/issues/issue-76191.stderr index ac1bdfaa847..24513901401 100644 --- a/tests/ui/issues/issue-76191.stderr +++ b/tests/ui/issues/issue-76191.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-76191.rs:8:37 | LL | const RANGE2: RangeInclusive = panic!(); - | ^^^^^^^^ evaluation panicked: explicit panic + | ^^^^^^^^ evaluation of constant value failed error[E0308]: mismatched types --> $DIR/issue-76191.rs:14:9 diff --git a/tests/ui/layout/invalid-unsized-const-eval.rs b/tests/ui/layout/invalid-unsized-const-eval.rs index 1f664d30055..94fa6449e67 100644 --- a/tests/ui/layout/invalid-unsized-const-eval.rs +++ b/tests/ui/layout/invalid-unsized-const-eval.rs @@ -10,6 +10,6 @@ struct LazyLock { } static EMPTY_SET: LazyLock = todo!(); -//~^ ERROR could not evaluate static initializer +//~^ ERROR the type `(dyn Sync, ())` has an unknown layout fn main() {} diff --git a/tests/ui/layout/invalid-unsized-const-eval.stderr b/tests/ui/layout/invalid-unsized-const-eval.stderr index a434ca9b2c7..c430a69766a 100644 --- a/tests/ui/layout/invalid-unsized-const-eval.stderr +++ b/tests/ui/layout/invalid-unsized-const-eval.stderr @@ -7,11 +7,11 @@ LL | data: (dyn Sync, ()), = help: the trait `Sized` is not implemented for `(dyn Sync + 'static)` = note: only the last element of a tuple may have a dynamically sized type -error[E0080]: could not evaluate static initializer +error[E0080]: the type `(dyn Sync, ())` has an unknown layout --> $DIR/invalid-unsized-const-eval.rs:12:1 | LL | static EMPTY_SET: LazyLock = todo!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the type `(dyn Sync, ())` has an unknown layout + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer error: aborting due to 2 previous errors diff --git a/tests/ui/layout/invalid-unsized-in-always-sized-tail.rs b/tests/ui/layout/invalid-unsized-in-always-sized-tail.rs index c6d5f2bfa0e..8da2bb385ef 100644 --- a/tests/ui/layout/invalid-unsized-in-always-sized-tail.rs +++ b/tests/ui/layout/invalid-unsized-in-always-sized-tail.rs @@ -12,6 +12,7 @@ struct P2 { //~^ ERROR: the size for values of type `[bool]` cannot be known at compilation time } -static CHECK: () = assert!(align_of::() == 1); //~ ERROR could not evaluate static initializer +static CHECK: () = assert!(align_of::() == 1); +//~^ ERROR the type `MySlice<[bool]>` has an unknown layout fn main() {} diff --git a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr index 3a4735e4832..2cdd79c488e 100644 --- a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr +++ b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr @@ -18,11 +18,11 @@ LL | struct MySlice(T); | | | this could be changed to `T: ?Sized`... -error[E0080]: could not evaluate static initializer +error[E0080]: the type `MySlice<[bool]>` has an unknown layout --> $DIR/invalid-unsized-in-always-sized-tail.rs:15:28 | LL | static CHECK: () = assert!(align_of::() == 1); - | ^^^^^^^^^^^^^^^^ the type `MySlice<[bool]>` has an unknown layout + | ^^^^^^^^^^^^^^^^ could not evaluate static initializer | note: inside `align_of::` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs index f84c10d8e5c..92295704615 100644 --- a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs +++ b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs @@ -6,6 +6,6 @@ struct ArenaSet::Target>(V, U); //~^ ERROR the size for values of type `V` cannot be known at compilation time const DATA: *const ArenaSet> = std::ptr::null_mut(); -//~^ ERROR evaluation of constant value failed +//~^ ERROR the type `ArenaSet, [u8]>` has an unknown layout pub fn main() {} diff --git a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr index 220951fab86..32dd2310a7e 100644 --- a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr +++ b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr @@ -22,11 +22,11 @@ help: the `Box` type always has a statically known size and allocates its conten LL | struct ArenaSet::Target>(Box, U); | ++++ + -error[E0080]: evaluation of constant value failed +error[E0080]: the type `ArenaSet, [u8]>` has an unknown layout --> $DIR/issue-unsized-tail-restatic-ice-122488.rs:8:1 | LL | const DATA: *const ArenaSet> = std::ptr::null_mut(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the type `ArenaSet, [u8]>` has an unknown layout + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.rs b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.rs index 91280e49dcd..4423b83e24d 100644 --- a/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.rs +++ b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.rs @@ -5,7 +5,7 @@ where str: Sized, { [(); { let _a: Option = None; 0 }]; - //~^ ERROR evaluation of constant value failed + //~^ ERROR the type `Option` has an unknown layout } fn main() {} diff --git a/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr index 6c7c51db8df..b12f1a18245 100644 --- a/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr +++ b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: the type `Option` has an unknown layout --> $DIR/uncomputable-due-to-trivial-bounds-ice-135138.rs:7:16 | LL | [(); { let _a: Option = None; 0 }]; - | ^^ the type `Option` has an unknown layout + | ^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/layout/unknown-when-no-type-parameter.rs b/tests/ui/layout/unknown-when-no-type-parameter.rs index 87f90aa438a..81386feaacf 100644 --- a/tests/ui/layout/unknown-when-no-type-parameter.rs +++ b/tests/ui/layout/unknown-when-no-type-parameter.rs @@ -4,10 +4,14 @@ trait Project { type Assoc; } -fn foo() where (): Project { - [(); size_of::<<() as Project>::Assoc>()]; //~ ERROR evaluation of constant value failed - //~| NOTE the type `<() as Project>::Assoc` has an unknown layout +fn foo() +where + (): Project, +{ + [(); size_of::<<() as Project>::Assoc>()]; + //~^ ERROR the type `<() as Project>::Assoc` has an unknown layout //~| NOTE inside `std::mem::size_of::<<() as Project>::Assoc>` + //~| NOTE evaluation of constant value failed } fn main() {} diff --git a/tests/ui/layout/unknown-when-no-type-parameter.stderr b/tests/ui/layout/unknown-when-no-type-parameter.stderr index 35fbb11f156..7b4d6d1ac0e 100644 --- a/tests/ui/layout/unknown-when-no-type-parameter.stderr +++ b/tests/ui/layout/unknown-when-no-type-parameter.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/unknown-when-no-type-parameter.rs:8:10 +error[E0080]: the type `<() as Project>::Assoc` has an unknown layout + --> $DIR/unknown-when-no-type-parameter.rs:11:10 | LL | [(); size_of::<<() as Project>::Assoc>()]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the type `<() as Project>::Assoc` has an unknown layout + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `std::mem::size_of::<<() as Project>::Assoc>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/layout/unknown-when-ptr-metadata-is-DST.rs b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.rs index 973235fe65a..54f339711d5 100644 --- a/tests/ui/layout/unknown-when-ptr-metadata-is-DST.rs +++ b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.rs @@ -6,7 +6,7 @@ where str: std::ptr::Pointee, { [(); { let _a: Option<&str> = None; 0 }]; - //~^ ERROR evaluation of constant value failed + //~^ ERROR the type `str` has an unknown layout } fn main() {} diff --git a/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr index 68bba2e9678..ef2a624fa87 100644 --- a/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr +++ b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: the type `str` has an unknown layout --> $DIR/unknown-when-ptr-metadata-is-DST.rs:8:16 | LL | [(); { let _a: Option<&str> = None; 0 }]; - | ^^ the type `str` has an unknown layout + | ^^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/lazy-type-alias/def-site-param-defaults-wf.rs b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.rs index 90bb0a294f8..7f417de5fd3 100644 --- a/tests/ui/lazy-type-alias/def-site-param-defaults-wf.rs +++ b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.rs @@ -2,8 +2,8 @@ #![feature(lazy_type_alias)] #![allow(incomplete_features)] -type Alias, const N: usize = {0 - 1}> = T; -//~^ ERROR evaluation of constant value failed +type Alias, const N: usize = { 0 - 1 }> = T; +//~^ ERROR attempt to compute `0_usize - 1_usize`, which would overflow //~| ERROR the size for values of type `str` cannot be known at compilation time fn main() {} diff --git a/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr index da0021ccaf4..a91cb4f45cb 100644 --- a/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr +++ b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr @@ -1,13 +1,13 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/def-site-param-defaults-wf.rs:5:44 +error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow + --> $DIR/def-site-param-defaults-wf.rs:5:45 | -LL | type Alias, const N: usize = {0 - 1}> = T; - | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow +LL | type Alias, const N: usize = { 0 - 1 }> = T; + | ^^^^^ evaluation of constant value failed error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/def-site-param-defaults-wf.rs:5:16 | -LL | type Alias, const N: usize = {0 - 1}> = T; +LL | type Alias, const N: usize = { 0 - 1 }> = T; | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` diff --git a/tests/ui/limits/huge-static.rs b/tests/ui/limits/huge-static.rs index 4c3641ac7d4..1473fd6054e 100644 --- a/tests/ui/limits/huge-static.rs +++ b/tests/ui/limits/huge-static.rs @@ -5,22 +5,19 @@ const HUGE_SIZE: usize = 1 << 61; - pub struct TooBigArray { arr: [u8; HUGE_SIZE], } impl TooBigArray { pub const fn new() -> Self { - TooBigArray { arr: [0x00; HUGE_SIZE], } + TooBigArray { arr: [0x00; HUGE_SIZE] } } } static MY_TOO_BIG_ARRAY_1: TooBigArray = TooBigArray::new(); -//~^ ERROR could not evaluate static initializer -//~| NOTE too big +//~^ ERROR too big static MY_TOO_BIG_ARRAY_2: [u8; HUGE_SIZE] = [0x00; HUGE_SIZE]; -//~^ ERROR could not evaluate static initializer -//~| NOTE too big +//~^ ERROR too big -fn main() { } +fn main() {} diff --git a/tests/ui/limits/huge-static.stderr b/tests/ui/limits/huge-static.stderr index 684efeeb4a3..b953866f0d3 100644 --- a/tests/ui/limits/huge-static.stderr +++ b/tests/ui/limits/huge-static.stderr @@ -1,14 +1,14 @@ -error[E0080]: could not evaluate static initializer - --> $DIR/huge-static.rs:19:1 +error[E0080]: values of the type `[u8; 2305843009213693952]` are too big for the target architecture + --> $DIR/huge-static.rs:18:1 | LL | static MY_TOO_BIG_ARRAY_1: TooBigArray = TooBigArray::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843009213693952]` are too big for the target architecture + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer -error[E0080]: could not evaluate static initializer - --> $DIR/huge-static.rs:22:1 +error[E0080]: values of the type `[u8; 2305843009213693952]` are too big for the target architecture + --> $DIR/huge-static.rs:20:1 | LL | static MY_TOO_BIG_ARRAY_2: [u8; HUGE_SIZE] = [0x00; HUGE_SIZE]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843009213693952]` are too big for the target architecture + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer error: aborting due to 2 previous errors diff --git a/tests/ui/limits/issue-55878.rs b/tests/ui/limits/issue-55878.rs index 614ff328bf5..9e75f00a408 100644 --- a/tests/ui/limits/issue-55878.rs +++ b/tests/ui/limits/issue-55878.rs @@ -2,5 +2,5 @@ fn main() { println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>()); - //~^ ERROR evaluation of constant value failed + //~^ ERROR too big for the target architecture } diff --git a/tests/ui/limits/issue-55878.stderr b/tests/ui/limits/issue-55878.stderr index 9b3922d7933..e39dd42e2ff 100644 --- a/tests/ui/limits/issue-55878.stderr +++ b/tests/ui/limits/issue-55878.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture --> $DIR/issue-55878.rs:4:26 | LL | println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; usize::MAX]` are too big for the target architecture + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | note: inside `std::mem::size_of::<[u8; usize::MAX]>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/recursion/recursive-static-definition.rs b/tests/ui/recursion/recursive-static-definition.rs index 5317c47076e..55db6a86bf1 100644 --- a/tests/ui/recursion/recursive-static-definition.rs +++ b/tests/ui/recursion/recursive-static-definition.rs @@ -1,5 +1,5 @@ pub static FOO: u32 = FOO; -//~^ ERROR could not evaluate static initializer +//~^ ERROR encountered static that tried to initialize itself with itself #[derive(Copy, Clone)] pub union Foo { @@ -7,6 +7,6 @@ pub union Foo { } pub static BAR: Foo = BAR; -//~^ ERROR could not evaluate static initializer +//~^ ERROR encountered static that tried to initialize itself with itself fn main() {} diff --git a/tests/ui/recursion/recursive-static-definition.stderr b/tests/ui/recursion/recursive-static-definition.stderr index 86a22c990e9..28df85ffaaf 100644 --- a/tests/ui/recursion/recursive-static-definition.stderr +++ b/tests/ui/recursion/recursive-static-definition.stderr @@ -1,14 +1,14 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/recursive-static-definition.rs:1:23 | LL | pub static FOO: u32 = FOO; - | ^^^ encountered static that tried to initialize itself with itself + | ^^^ could not evaluate static initializer -error[E0080]: could not evaluate static initializer +error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/recursive-static-definition.rs:9:23 | LL | pub static BAR: Foo = BAR; - | ^^^ encountered static that tried to initialize itself with itself + | ^^^ could not evaluate static initializer error: aborting due to 2 previous errors diff --git a/tests/ui/simd/const-err-trumps-simd-err.rs b/tests/ui/simd/const-err-trumps-simd-err.rs index 05a224d037a..8d9870855f8 100644 --- a/tests/ui/simd/const-err-trumps-simd-err.rs +++ b/tests/ui/simd/const-err-trumps-simd-err.rs @@ -16,8 +16,7 @@ struct int8x4_t([u8; 4]); fn get_elem(a: int8x4_t) -> u8 { const { assert!(LANE < 4); } // the error should be here... - //~^ ERROR failed - //~| NOTE assertion failed + //~^ ERROR assertion failed unsafe { simd_extract(a, LANE) } // ...not here } diff --git a/tests/ui/simd/const-err-trumps-simd-err.stderr b/tests/ui/simd/const-err-trumps-simd-err.stderr index 389f75492c6..b648cadef01 100644 --- a/tests/ui/simd/const-err-trumps-simd-err.stderr +++ b/tests/ui/simd/const-err-trumps-simd-err.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `get_elem::<4>::{constant#0}` failed +error[E0080]: evaluation panicked: assertion failed: LANE < 4 --> $DIR/const-err-trumps-simd-err.rs:18:13 | LL | const { assert!(LANE < 4); } // the error should be here... - | ^^^^^^^^^^^^^^^^^ evaluation panicked: assertion failed: LANE < 4 + | ^^^^^^^^^^^^^^^^^ evaluation of `get_elem::<4>::{constant#0}` failed note: erroneous constant encountered --> $DIR/const-err-trumps-simd-err.rs:18:5 @@ -11,7 +11,7 @@ LL | const { assert!(LANE < 4); } // the error should be here... | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: the above error was encountered while instantiating `fn get_elem::<4>` - --> $DIR/const-err-trumps-simd-err.rs:25:5 + --> $DIR/const-err-trumps-simd-err.rs:24:5 | LL | get_elem::<4>(int8x4_t([0, 0, 0, 0])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr index c01b2ccd163..1c112061fb6 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr @@ -9,11 +9,11 @@ LL | const _: *const Foo = 0 as _; | ^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0080]: evaluation of constant value failed +error[E0080]: a cycle occurred during layout computation --> $DIR/stack-overflow-trait-infer-98842.rs:14:1 | LL | const _: *const Foo = 0 as _; - | ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr index c01b2ccd163..1c112061fb6 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr @@ -9,11 +9,11 @@ LL | const _: *const Foo = 0 as _; | ^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0080]: evaluation of constant value failed +error[E0080]: a cycle occurred during layout computation --> $DIR/stack-overflow-trait-infer-98842.rs:14:1 | LL | const _: *const Foo = 0 as _; - | ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed error: aborting due to 2 previous errors diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.rs b/tests/ui/sized/stack-overflow-trait-infer-98842.rs index 8a958870b0e..1c9f6c593f4 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.rs +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.rs @@ -12,6 +12,6 @@ struct Foo(<&'static Foo as ::core::ops::Deref>::Target); // and it will infinitely recurse somewhere trying to figure out the // size of this pointer (is my guess): const _: *const Foo = 0 as _; -//~^ ERROR evaluation of constant value failed +//~^ ERROR a cycle occurred during layout computation pub fn main() {} diff --git a/tests/ui/statics/issue-14227.rs b/tests/ui/statics/issue-14227.rs index 8a70f51d3b4..84994f033d1 100644 --- a/tests/ui/statics/issue-14227.rs +++ b/tests/ui/statics/issue-14227.rs @@ -3,6 +3,6 @@ extern "C" { } static CRASH: u32 = symbol; //~^ ERROR use of extern static is unsafe and requires -//~| ERROR could not evaluate static initializer +//~| ERROR cannot access extern static `symbol` fn main() {} diff --git a/tests/ui/statics/issue-14227.stderr b/tests/ui/statics/issue-14227.stderr index 3551821a3da..119e70e7b23 100644 --- a/tests/ui/statics/issue-14227.stderr +++ b/tests/ui/statics/issue-14227.stderr @@ -1,8 +1,8 @@ -error[E0080]: could not evaluate static initializer +error[E0080]: cannot access extern static `symbol` --> $DIR/issue-14227.rs:4:21 | LL | static CRASH: u32 = symbol; - | ^^^^^^ cannot access extern static `symbol` + | ^^^^^^ could not evaluate static initializer error[E0133]: use of extern static is unsafe and requires unsafe function or block --> $DIR/issue-14227.rs:4:21 diff --git a/tests/ui/statics/mutable_memory_validation.rs b/tests/ui/statics/mutable_memory_validation.rs index 3bb572d38bc..033c2bc2839 100644 --- a/tests/ui/statics/mutable_memory_validation.rs +++ b/tests/ui/statics/mutable_memory_validation.rs @@ -11,7 +11,7 @@ struct Meh { } const MUH: Meh = Meh { x: unsafe { &mut *(&READONLY as *const _ as *mut _) } }; -//~^ ERROR: it is undefined behavior to use this value +//~^ ERROR: invalid value at .x.: encountered `UnsafeCell` in read-only memory static READONLY: i32 = 0; diff --git a/tests/ui/statics/mutable_memory_validation.stderr b/tests/ui/statics/mutable_memory_validation.stderr index 76e1827ea12..df36287cc69 100644 --- a/tests/ui/statics/mutable_memory_validation.stderr +++ b/tests/ui/statics/mutable_memory_validation.stderr @@ -1,8 +1,8 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory --> $DIR/mutable_memory_validation.rs:13:1 | LL | const MUH: Meh = Meh { x: unsafe { &mut *(&READONLY as *const _ as *mut _) } }; - | ^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory + | ^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { diff --git a/tests/ui/statics/uninhabited-static.rs b/tests/ui/statics/uninhabited-static.rs index 0f7c5ae6ef4..955d489d313 100644 --- a/tests/ui/statics/uninhabited-static.rs +++ b/tests/ui/statics/uninhabited-static.rs @@ -11,9 +11,9 @@ extern "C" { static VOID2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type //~| WARN: previously accepted -//~| ERROR could not evaluate static initializer +//~| ERROR value of uninhabited type `Void` static NEVER2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type //~| WARN: previously accepted -//~| ERROR could not evaluate static initializer +//~| ERROR value of uninhabited type `Void` fn main() {} diff --git a/tests/ui/statics/uninhabited-static.stderr b/tests/ui/statics/uninhabited-static.stderr index f891c0ce25b..e285df0c7ed 100644 --- a/tests/ui/statics/uninhabited-static.stderr +++ b/tests/ui/statics/uninhabited-static.stderr @@ -43,17 +43,17 @@ LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; = note: for more information, see issue #74840 = note: uninhabited statics cannot be initialized, and any access would be an immediate error -error[E0080]: could not evaluate static initializer +error[E0080]: constructing invalid value: encountered a value of uninhabited type `Void` --> $DIR/uninhabited-static.rs:12:31 | LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type `Void` + | ^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer -error[E0080]: could not evaluate static initializer +error[E0080]: constructing invalid value: encountered a value of uninhabited type `Void` --> $DIR/uninhabited-static.rs:15:32 | LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type `Void` + | ^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer error: aborting due to 6 previous errors diff --git a/tests/ui/structs/default-field-values/invalid-const.rs b/tests/ui/structs/default-field-values/invalid-const.rs index 203a712868b..ddb73f68865 100644 --- a/tests/ui/structs/default-field-values/invalid-const.rs +++ b/tests/ui/structs/default-field-values/invalid-const.rs @@ -3,13 +3,13 @@ pub struct Bat { pub bax: u8 = panic!("asdf"), - //~^ ERROR evaluation of constant value failed + //~^ ERROR evaluation panicked: asdf } pub struct Baz { pub bax: u8 = 130 + C, // ok pub bat: u8 = 130 + 130, - //~^ ERROR evaluation of `Baz::::bat::{constant#0}` failed + //~^ ERROR attempt to compute `130_u8 + 130_u8`, which would overflow pub bay: u8 = 1, // ok } diff --git a/tests/ui/structs/default-field-values/invalid-const.stderr b/tests/ui/structs/default-field-values/invalid-const.stderr index 030bdbfcc3e..93f08c4c562 100644 --- a/tests/ui/structs/default-field-values/invalid-const.stderr +++ b/tests/ui/structs/default-field-values/invalid-const.stderr @@ -1,14 +1,14 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: asdf --> $DIR/invalid-const.rs:5:19 | LL | pub bax: u8 = panic!("asdf"), - | ^^^^^^^^^^^^^^ evaluation panicked: asdf + | ^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of `Baz::::bat::{constant#0}` failed +error[E0080]: attempt to compute `130_u8 + 130_u8`, which would overflow --> $DIR/invalid-const.rs:11:19 | LL | pub bat: u8 = 130 + 130, - | ^^^^^^^^^ attempt to compute `130_u8 + 130_u8`, which would overflow + | ^^^^^^^^^ evaluation of `Baz::::bat::{constant#0}` failed error: aborting due to 2 previous errors diff --git a/tests/ui/structs/default-field-values/post-mono.direct.stderr b/tests/ui/structs/default-field-values/post-mono.direct.stderr index cdd80620c48..f177f1e7bbc 100644 --- a/tests/ui/structs/default-field-values/post-mono.direct.stderr +++ b/tests/ui/structs/default-field-values/post-mono.direct.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Z::<1>::post_mono::{constant#0}` failed +error[E0080]: attempt to divide `1_usize` by zero --> $DIR/post-mono.rs:7:24 | LL | post_mono: usize = X / 0, - | ^^^^^ attempt to divide `1_usize` by zero + | ^^^^^ evaluation of `Z::<1>::post_mono::{constant#0}` failed note: erroneous constant encountered --> $DIR/post-mono.rs:17:19 diff --git a/tests/ui/structs/default-field-values/post-mono.indirect.stderr b/tests/ui/structs/default-field-values/post-mono.indirect.stderr index 56c27a6e5dc..574f539659b 100644 --- a/tests/ui/structs/default-field-values/post-mono.indirect.stderr +++ b/tests/ui/structs/default-field-values/post-mono.indirect.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of `Z::<1>::post_mono::{constant#0}` failed +error[E0080]: attempt to divide `1_usize` by zero --> $DIR/post-mono.rs:7:24 | LL | post_mono: usize = X / 0, - | ^^^^^ attempt to divide `1_usize` by zero + | ^^^^^ evaluation of `Z::<1>::post_mono::{constant#0}` failed note: erroneous constant encountered --> $DIR/post-mono.rs:12:19 diff --git a/tests/ui/structs/default-field-values/post-mono.rs b/tests/ui/structs/default-field-values/post-mono.rs index 4de31f6e2fb..68dfa391bb4 100644 --- a/tests/ui/structs/default-field-values/post-mono.rs +++ b/tests/ui/structs/default-field-values/post-mono.rs @@ -5,7 +5,7 @@ struct Z { post_mono: usize = X / 0, - //~^ ERROR evaluation of `Z::<1>::post_mono::{constant#0}` failed + //~^ ERROR attempt to divide `1_usize` by zero } fn indirect() { diff --git a/tests/ui/transmutability/uninhabited.rs b/tests/ui/transmutability/uninhabited.rs index 274104ffb39..4e48b590c42 100644 --- a/tests/ui/transmutability/uninhabited.rs +++ b/tests/ui/transmutability/uninhabited.rs @@ -38,7 +38,7 @@ fn yawning_void_struct() { const _: () = { assert!(std::mem::size_of::() == std::mem::size_of::()); // Just to be sure the above constant actually evaluated: - assert!(false); //~ ERROR: evaluation of constant value failed + assert!(false); //~ ERROR: evaluation panicked: assertion failed: false }; // This transmutation is vacuously acceptable; since one cannot construct a @@ -60,7 +60,7 @@ fn yawning_void_enum() { const _: () = { assert!(std::mem::size_of::() == std::mem::size_of::()); // Just to be sure the above constant actually evaluated: - assert!(false); //~ ERROR: evaluation of constant value failed + assert!(false); //~ ERROR: evaluation panicked: assertion failed: false }; // This transmutation is vacuously acceptable; since one cannot construct a @@ -84,7 +84,7 @@ fn distant_void() { const _: () = { assert!(std::mem::size_of::() == std::mem::size_of::()); // Just to be sure the above constant actually evaluated: - assert!(false); //~ ERROR: evaluation of constant value failed + assert!(false); //~ ERROR: evaluation panicked: assertion failed: false }; assert::is_maybe_transmutable::(); diff --git a/tests/ui/transmutability/uninhabited.stderr b/tests/ui/transmutability/uninhabited.stderr index 3044b502d31..70bb48de56d 100644 --- a/tests/ui/transmutability/uninhabited.stderr +++ b/tests/ui/transmutability/uninhabited.stderr @@ -40,11 +40,11 @@ LL | | lifetimes: true, LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: assertion failed: false --> $DIR/uninhabited.rs:41:9 | LL | assert!(false); - | ^^^^^^^^^^^^^^ evaluation panicked: assertion failed: false + | ^^^^^^^^^^^^^^ evaluation of constant value failed error[E0277]: `()` cannot be safely transmuted into `yawning_void_enum::Void` --> $DIR/uninhabited.rs:71:41 @@ -67,11 +67,11 @@ LL | | lifetimes: true, LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: assertion failed: false --> $DIR/uninhabited.rs:63:9 | LL | assert!(false); - | ^^^^^^^^^^^^^^ evaluation panicked: assertion failed: false + | ^^^^^^^^^^^^^^ evaluation of constant value failed error[E0277]: `u128` cannot be safely transmuted into `DistantVoid` --> $DIR/uninhabited.rs:92:43 @@ -94,11 +94,11 @@ LL | | lifetimes: true, LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: assertion failed: false --> $DIR/uninhabited.rs:87:9 | LL | assert!(false); - | ^^^^^^^^^^^^^^ evaluation panicked: assertion failed: false + | ^^^^^^^^^^^^^^ evaluation of constant value failed error[E0277]: `Src` cannot be safely transmuted into `issue_126267::Error` --> $DIR/uninhabited.rs:108:42 diff --git a/tests/ui/treat-err-as-bug/err.rs b/tests/ui/treat-err-as-bug/err.rs index 7868c06fee1..6f0e3c55fbb 100644 --- a/tests/ui/treat-err-as-bug/err.rs +++ b/tests/ui/treat-err-as-bug/err.rs @@ -7,7 +7,7 @@ #![crate_type = "rlib"] pub static C: u32 = 0 - 1; -//~^ ERROR could not evaluate static initializer +//~^ ERROR attempt to compute `0_u32 - 1_u32`, which would overflow //~? RAW aborting due to `-Z treat-err-as-bug=1` //~? RAW [eval_static_initializer] evaluating initializer of static `C` diff --git a/tests/ui/treat-err-as-bug/err.stderr b/tests/ui/treat-err-as-bug/err.stderr index 2049df22000..69c33cf8927 100644 --- a/tests/ui/treat-err-as-bug/err.stderr +++ b/tests/ui/treat-err-as-bug/err.stderr @@ -1,8 +1,8 @@ -error: internal compiler error[E0080]: could not evaluate static initializer +error: internal compiler error[E0080]: attempt to compute `0_u32 - 1_u32`, which would overflow --> $DIR/err.rs:9:21 | LL | pub static C: u32 = 0 - 1; - | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | ^^^^^ could not evaluate static initializer error: the compiler unexpectedly panicked. this is a bug. diff --git a/tests/ui/type/pattern_types/literals.rs b/tests/ui/type/pattern_types/literals.rs index b2a83a2a8bd..fbca421aa9a 100644 --- a/tests/ui/type/pattern_types/literals.rs +++ b/tests/ui/type/pattern_types/literals.rs @@ -84,12 +84,12 @@ fn single_element_range_exclusive() -> pattern_type!(u32 is 0..1) { } fn empty_range_at_base_type_min() -> pattern_type!(u32 is 0..0) { - //~^ ERROR evaluation of constant value failed + //~^ ERROR evaluation panicked: exclusive range end at minimum value of type 0 } fn empty_range_at_base_type_min2() -> pattern_type!(u32 is 0..0) { - //~^ ERROR evaluation of constant value failed + //~^ ERROR evaluation panicked: exclusive range end at minimum value of type 1 } @@ -104,17 +104,17 @@ fn empty_range2() -> pattern_type!(u32 is 1..1) { } fn wraparound_range_at_base_ty_end() -> pattern_type!(u32 is 1..0) { - //~^ ERROR evaluation of constant value failed + //~^ ERROR evaluation panicked: exclusive range end at minimum value of type 1 } fn wraparound_range_at_base_ty_end2() -> pattern_type!(u32 is 1..0) { - //~^ ERROR evaluation of constant value failed + //~^ ERROR evaluation panicked: exclusive range end at minimum value of type 0 } fn wraparound_range_at_base_ty_end3() -> pattern_type!(u32 is 1..0) { - //~^ ERROR evaluation of constant value failed + //~^ ERROR evaluation panicked: exclusive range end at minimum value of type 2 } diff --git a/tests/ui/type/pattern_types/literals.stderr b/tests/ui/type/pattern_types/literals.stderr index 5c926742f3c..4eb5bf4565d 100644 --- a/tests/ui/type/pattern_types/literals.stderr +++ b/tests/ui/type/pattern_types/literals.stderr @@ -1,32 +1,32 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:86:62 | LL | fn empty_range_at_base_type_min() -> pattern_type!(u32 is 0..0) { - | ^ evaluation panicked: exclusive range end at minimum value of type + | ^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:91:63 | LL | fn empty_range_at_base_type_min2() -> pattern_type!(u32 is 0..0) { - | ^ evaluation panicked: exclusive range end at minimum value of type + | ^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:106:65 | LL | fn wraparound_range_at_base_ty_end() -> pattern_type!(u32 is 1..0) { - | ^ evaluation panicked: exclusive range end at minimum value of type + | ^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:111:66 | LL | fn wraparound_range_at_base_ty_end2() -> pattern_type!(u32 is 1..0) { - | ^ evaluation panicked: exclusive range end at minimum value of type + | ^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:116:66 | LL | fn wraparound_range_at_base_ty_end3() -> pattern_type!(u32 is 1..0) { - | ^ evaluation panicked: exclusive range end at minimum value of type + | ^ evaluation of constant value failed error[E0308]: mismatched types --> $DIR/literals.rs:9:5 diff --git a/tests/ui/type/pattern_types/range_patterns.rs b/tests/ui/type/pattern_types/range_patterns.rs index 21c1454d6cd..86b618a8d24 100644 --- a/tests/ui/type/pattern_types/range_patterns.rs +++ b/tests/ui/type/pattern_types/range_patterns.rs @@ -23,7 +23,7 @@ type EMPTY = pattern_type!(u32 is 1..1); //~ ERROR unknown layout #[rustc_layout(debug)] type WRAP = pattern_type!(u32 is 1..0); //~ ERROR unknown layout -//~^ ERROR: evaluation of constant value failed +//~^ ERROR: evaluation panicked: exclusive range end at minimum value of type #[rustc_layout(debug)] type WRAP2 = pattern_type!(u32 is 5..2); //~ ERROR unknown layout diff --git a/tests/ui/type/pattern_types/range_patterns.stderr b/tests/ui/type/pattern_types/range_patterns.stderr index a05995a33f9..632ca689fc0 100644 --- a/tests/ui/type/pattern_types/range_patterns.stderr +++ b/tests/ui/type/pattern_types/range_patterns.stderr @@ -365,11 +365,11 @@ error: the type has an unknown layout LL | type EMPTY = pattern_type!(u32 is 1..1); | ^^^^^^^^^^ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/range_patterns.rs:25:37 | LL | type WRAP = pattern_type!(u32 is 1..0); - | ^ evaluation panicked: exclusive range end at minimum value of type + | ^ evaluation of constant value failed error: the type has an unknown layout --> $DIR/range_patterns.rs:25:1 diff --git a/tests/ui/type/pattern_types/reverse_range.rs b/tests/ui/type/pattern_types/reverse_range.rs index e698e9dd541..34c931e4e96 100644 --- a/tests/ui/type/pattern_types/reverse_range.rs +++ b/tests/ui/type/pattern_types/reverse_range.rs @@ -5,7 +5,6 @@ use std::pat::pattern_type; const NONE: pattern_type!(u8 is 1..0) = unsafe { std::mem::transmute(3_u8) }; -//~^ NOTE: exclusive range end at minimum value of type -//~| ERROR: evaluation of constant value failed +//~^ ERROR: exclusive range end at minimum value of type fn main() {} diff --git a/tests/ui/type/pattern_types/reverse_range.stderr b/tests/ui/type/pattern_types/reverse_range.stderr index 90f8ef3261a..640296eb891 100644 --- a/tests/ui/type/pattern_types/reverse_range.stderr +++ b/tests/ui/type/pattern_types/reverse_range.stderr @@ -1,8 +1,8 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/reverse_range.rs:7:36 | LL | const NONE: pattern_type!(u8 is 1..0) = unsafe { std::mem::transmute(3_u8) }; - | ^ evaluation panicked: exclusive range end at minimum value of type + | ^ evaluation of constant value failed error: aborting due to 1 previous error diff --git a/tests/ui/type/pattern_types/validity.rs b/tests/ui/type/pattern_types/validity.rs index c61bb71ac25..a4e49692c98 100644 --- a/tests/ui/type/pattern_types/validity.rs +++ b/tests/ui/type/pattern_types/validity.rs @@ -8,32 +8,32 @@ use std::pat::pattern_type; const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) }; -//~^ ERROR: it is undefined behavior to use this value +//~^ ERROR: constructing invalid value: encountered 0 const BAD_UNINIT: pattern_type!(u32 is 1..) = - //~^ ERROR: evaluation of constant value failed + //~^ ERROR: using uninitialized data, but this operation requires initialized memory unsafe { std::mem::transmute(std::mem::MaybeUninit::::uninit()) }; const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(&42) }; -//~^ ERROR: evaluation of constant value failed +//~^ ERROR: unable to turn pointer into integer const BAD_AGGREGATE: (pattern_type!(u32 is 1..), u32) = (unsafe { std::mem::transmute(0) }, 0); -//~^ ERROR: it is undefined behavior to use this value +//~^ ERROR: constructing invalid value at .0: encountered 0 struct Foo(Bar); struct Bar(pattern_type!(u32 is 1..)); const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) })); -//~^ ERROR: it is undefined behavior to use this value +//~^ ERROR: constructing invalid value at .0.0: encountered 0 const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = - //~^ ERROR: evaluation of constant value failed + //~^ ERROR: using uninitialized data, but this operation requires initialized memory unsafe { std::mem::transmute(std::mem::MaybeUninit::::uninit()) }; const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') }; -//~^ ERROR: it is undefined behavior to use this value +//~^ ERROR: constructing invalid value: encountered 97, but expected something in the range 65..=89 const CHAR_OOB: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute(u32::MAX) }; -//~^ ERROR: it is undefined behavior to use this value +//~^ ERROR: constructing invalid value: encountered 0xffffffff fn main() {} diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr index b990ec2d368..3219a2858c5 100644 --- a/tests/ui/type/pattern_types/validity.stderr +++ b/tests/ui/type/pattern_types/validity.stderr @@ -1,73 +1,73 @@ -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 0, but expected something greater or equal to 1 --> $DIR/validity.rs:10:1 | LL | const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { HEX_DUMP } -error[E0080]: evaluation of constant value failed +error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/validity.rs:13:1 | LL | const BAD_UNINIT: pattern_type!(u32 is 1..) = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: evaluation of constant value failed +error[E0080]: unable to turn pointer into integer --> $DIR/validity.rs:17:1 | LL | const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(&42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 --> $DIR/validity.rs:20:1 | LL | const BAD_AGGREGATE: (pattern_type!(u32 is 1..), u32) = (unsafe { std::mem::transmute(0) }, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 --> $DIR/validity.rs:26:1 | LL | const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) })); - | ^^^^^^^^^^^^^^^^^^ constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { HEX_DUMP } -error[E0080]: evaluation of constant value failed +error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/validity.rs:29:1 | LL | const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 97, but expected something in the range 65..=89 --> $DIR/validity.rs:33:1 | LL | const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 97, but expected something in the range 65..=89 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { HEX_DUMP } -error[E0080]: it is undefined behavior to use this value +error[E0080]: constructing invalid value: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) --> $DIR/validity.rs:36:1 | LL | const CHAR_OOB: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute(u32::MAX) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { -- cgit 1.4.1-3-g733a5 From 020216c31c1e4f1f56a689df8f04580504354613 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 30 May 2025 14:06:35 +0000 Subject: Clarify why we are talking about a failed const eval at a random place --- compiler/rustc_const_eval/messages.ftl | 6 +- .../clippy/tests/ui/indexing_slicing_index.stderr | 2 +- src/tools/miri/tests/fail/const-ub-checks.stderr | 2 +- src/tools/miri/tests/fail/erroneous_const.stderr | 2 +- src/tools/miri/tests/fail/erroneous_const2.stderr | 2 +- tests/rustdoc-ui/const-evalutation-ice.stderr | 2 +- .../ui/array-slice-vec/array_const_index-0.stderr | 2 +- .../ui/array-slice-vec/array_const_index-1.stderr | 2 +- tests/ui/asm/fail-const-eval-issue-121099.stderr | 4 +- .../defaults-not-assumed-fail.stderr | 2 +- tests/ui/borrowck/issue-81899.stderr | 2 +- .../ui/borrowck/issue-88434-minimal-example.stderr | 2 +- ...issue-88434-removal-index-should-be-less.stderr | 2 +- .../const-errs-dont-conflict-103369.stderr | 4 +- .../defaults/default-param-wf-concrete.next.stderr | 2 +- .../defaults/default-param-wf-concrete.old.stderr | 2 +- tests/ui/const-generics/defaults/wfness.stderr | 2 +- .../generic_const_exprs/from-sig-fail.stderr | 2 +- .../generic_const_exprs/simple_fail.stderr | 4 +- tests/ui/const-generics/issues/issue-100313.stderr | 2 +- .../invalid-patterns.32bit.stderr | 4 +- .../invalid-patterns.64bit.stderr | 4 +- tests/ui/const-ptr/forbidden_slices.stderr | 10 +- tests/ui/const-ptr/out_of_bounds_read.stderr | 6 +- tests/ui/consts/assert-type-intrinsics.stderr | 6 +- tests/ui/consts/assoc_const_generic_impl.stderr | 2 +- tests/ui/consts/const-array-oob.stderr | 4 +- tests/ui/consts/const-assert-unchecked-ub.stderr | 2 +- tests/ui/consts/const-compare-bytes-ub.stderr | 16 +- tests/ui/consts/const-deref-ptr.stderr | 2 +- tests/ui/consts/const-err-early.stderr | 10 +- tests/ui/consts/const-err-enum-discriminant.stderr | 2 +- tests/ui/consts/const-err-late.stderr | 4 +- tests/ui/consts/const-err-multi.stderr | 2 +- tests/ui/consts/const-eval-fail-too-big.stderr | 2 +- .../assign-to-static-within-other-static.stderr | 2 +- .../const-eval/conditional_array_execution.stderr | 2 +- .../consts/const-eval/const-eval-overflow-2.stderr | 2 +- .../consts/const-eval/const-eval-overflow-3.stderr | 2 +- .../consts/const-eval/const-eval-overflow-4.stderr | 2 +- .../consts/const-eval/const-eval-overflow2.stderr | 16 +- .../consts/const-eval/const-eval-overflow2b.stderr | 16 +- .../consts/const-eval/const-eval-overflow2c.stderr | 16 +- .../const-eval/const-eval-query-stack.stderr | 2 +- ...st-pointer-values-in-various-types.64bit.stderr | 58 ++-- .../ui/consts/const-eval/const_fn_ptr_fail2.stderr | 4 +- .../const_panic-normalize-tabs-115498.stderr | 2 +- tests/ui/consts/const-eval/const_panic.stderr | 24 +- tests/ui/consts/const-eval/const_panic_2021.stderr | 20 +- .../const-eval/const_panic_libcore_bin.stderr | 6 +- .../const-eval/const_panic_track_caller.stderr | 2 +- .../ui/consts/const-eval/const_raw_ptr_ops2.stderr | 4 +- .../const-eval/heap/alloc_intrinsic_errors.stderr | 2 +- .../heap/dealloc_intrinsic_dangling.stderr | 2 +- .../heap/dealloc_intrinsic_duplicate.stderr | 2 +- .../heap/dealloc_intrinsic_incorrect_layout.stderr | 8 +- .../index-out-of-bounds-never-type.stderr | 2 +- .../consts/const-eval/index_out_of_bounds.stderr | 2 +- tests/ui/consts/const-eval/issue-43197.stderr | 4 +- tests/ui/consts/const-eval/issue-44578.stderr | 2 +- tests/ui/consts/const-eval/issue-49296.stderr | 2 +- .../consts/const-eval/issue-50814-2.mir-opt.stderr | 2 +- .../consts/const-eval/issue-50814-2.normal.stderr | 2 +- tests/ui/consts/const-eval/issue-50814.stderr | 4 +- tests/ui/consts/const-eval/issue-85155.stderr | 2 +- .../issue-91827-extern-types-field-offset.stderr | 2 +- .../const-eval/mod-static-with-const-fn.stderr | 2 +- .../ui/consts/const-eval/nonnull_as_ref_ub.stderr | 2 +- .../const-eval/panic-assoc-never-type.stderr | 2 +- tests/ui/consts/const-eval/panic-never-type.stderr | 2 +- tests/ui/consts/const-eval/parse_ints.stderr | 4 +- .../consts/const-eval/partial_ptr_overwrite.stderr | 2 +- tests/ui/consts/const-eval/raw-pointer-ub.stderr | 10 +- .../const-eval/ref_to_int_match.32bit.stderr | 2 +- .../const-eval/ref_to_int_match.64bit.stderr | 2 +- tests/ui/consts/const-eval/shift_overflow.stderr | 2 +- .../const-eval/transmute-size-mismatch.stderr | 4 +- .../ui/consts/const-eval/ub-enum-overwrite.stderr | 2 +- tests/ui/consts/const-eval/ub-enum.stderr | 18 +- .../ui/consts/const-eval/ub-invalid-values.stderr | 2 +- tests/ui/consts/const-eval/ub-nonnull.stderr | 4 +- tests/ui/consts/const-eval/ub-ref-ptr.stderr | 12 +- tests/ui/consts/const-eval/ub-uninhabit.stderr | 6 +- tests/ui/consts/const-eval/ub-wide-ptr.stderr | 12 +- .../const-eval/ub-write-through-immutable.stderr | 4 +- .../const-eval/union-const-eval-field.stderr | 2 +- tests/ui/consts/const-eval/union-ice.stderr | 6 +- tests/ui/consts/const-eval/union-ub.32bit.stderr | 2 +- tests/ui/consts/const-eval/union-ub.64bit.stderr | 2 +- .../consts/const-eval/unused-broken-const.stderr | 2 +- tests/ui/consts/const-eval/unwind-abort.stderr | 2 +- .../const-eval/validate_uninhabited_zsts.stderr | 4 +- .../validation-ice-extern-type-field.stderr | 2 +- .../consts/const-external-macro-const-err.stderr | 2 +- tests/ui/consts/const-int-unchecked.stderr | 98 +++--- .../const-len-underflow-separate-spans.next.stderr | 2 +- .../const-len-underflow-separate-spans.old.stderr | 2 +- .../ui/consts/const-len-underflow-subspans.stderr | 2 +- tests/ui/consts/const-ptr-is-null.stderr | 2 +- ...nst-size_of_val-align_of_val-extern-type.stderr | 4 +- tests/ui/consts/const-slice-oob.stderr | 2 +- tests/ui/consts/const-unwrap.stderr | 4 +- tests/ui/consts/const_refs_to_static_fail.stderr | 2 +- tests/ui/consts/const_unsafe_unreachable_ub.stderr | 2 +- tests/ui/consts/control-flow/assert.stderr | 2 +- tests/ui/consts/copy-intrinsic.stderr | 8 +- tests/ui/consts/eval-enum.stderr | 4 +- .../detect-extra-ub.with_flag.stderr | 16 +- tests/ui/consts/issue-32829.stderr | 2 +- tests/ui/consts/issue-64506.stderr | 2 +- .../consts/issue-66693-panic-in-array-len.stderr | 2 +- tests/ui/consts/issue-66693.stderr | 4 +- tests/ui/consts/issue-76064.stderr | 2 +- tests/ui/consts/issue-miri-1910.stderr | 2 +- tests/ui/consts/large_const_alloc.stderr | 4 +- tests/ui/consts/miri_unleashed/abi-mismatch.rs | 2 +- tests/ui/consts/miri_unleashed/abi-mismatch.stderr | 2 +- tests/ui/consts/miri_unleashed/assoc_const.stderr | 2 +- .../ui/consts/miri_unleashed/assoc_const_2.stderr | 2 +- tests/ui/consts/miri_unleashed/box.stderr | 2 +- .../miri_unleashed/const_refers_to_static.stderr | 6 +- .../const_refers_to_static_cross_crate.stderr | 2 +- tests/ui/consts/miri_unleashed/drop.rs | 2 +- tests/ui/consts/miri_unleashed/drop.stderr | 2 +- .../ui/consts/miri_unleashed/extern-static.stderr | 4 +- tests/ui/consts/miri_unleashed/inline_asm.stderr | 2 +- .../miri_unleashed/mutable_references.stderr | 2 +- .../consts/miri_unleashed/mutating_global.stderr | 2 +- tests/ui/consts/miri_unleashed/non_const_fn.stderr | 2 +- tests/ui/consts/miri_unleashed/ptr_arith.stderr | 4 +- tests/ui/consts/miri_unleashed/tls.stderr | 4 +- tests/ui/consts/missing_span_in_backtrace.stderr | 2 +- .../ui/consts/mono-reachable-invalid-const.stderr | 2 +- .../no-ice-from-static-in-const-issue-52060.stderr | 2 +- tests/ui/consts/offset_from_ub.stderr | 28 +- tests/ui/consts/offset_ub.stderr | 22 +- tests/ui/consts/overflowing-consts.noopt.stderr | 340 ++++++++++----------- tests/ui/consts/overflowing-consts.opt.stderr | 340 ++++++++++----------- ...rflowing-consts.opt_with_overflow_checks.stderr | 340 ++++++++++----------- ...moted_running_out_of_memory_issue-130687.stderr | 2 +- tests/ui/consts/promoted_size_overflow.stderr | 2 +- .../ui/consts/qualif-indirect-mutation-fail.stderr | 4 +- .../ui/consts/recursive-zst-static.default.stderr | 2 +- .../ui/consts/recursive-zst-static.unleash.stderr | 2 +- tests/ui/consts/recursive.stderr | 2 +- .../collect-in-called-fn.noopt.stderr | 2 +- .../collect-in-called-fn.opt.stderr | 2 +- .../collect-in-dead-closure.noopt.stderr | 2 +- .../collect-in-dead-closure.opt.stderr | 2 +- .../collect-in-dead-drop.noopt.stderr | 2 +- .../collect-in-dead-drop.opt.stderr | 2 +- ...llect-in-dead-fn-behind-assoc-type.noopt.stderr | 2 +- ...collect-in-dead-fn-behind-assoc-type.opt.stderr | 2 +- .../collect-in-dead-fn-behind-generic.noopt.stderr | 2 +- .../collect-in-dead-fn-behind-generic.opt.stderr | 2 +- ...lect-in-dead-fn-behind-opaque-type.noopt.stderr | 2 +- ...ollect-in-dead-fn-behind-opaque-type.opt.stderr | 2 +- .../collect-in-dead-fn.noopt.stderr | 2 +- .../required-consts/collect-in-dead-fn.opt.stderr | 2 +- .../collect-in-dead-fnptr-in-const.noopt.stderr | 2 +- .../collect-in-dead-fnptr-in-const.opt.stderr | 2 +- .../collect-in-dead-fnptr.noopt.stderr | 2 +- .../collect-in-dead-fnptr.opt.stderr | 2 +- .../collect-in-dead-move.noopt.stderr | 2 +- .../collect-in-dead-move.opt.stderr | 2 +- .../collect-in-dead-vtable.noopt.stderr | 2 +- .../collect-in-dead-vtable.opt.stderr | 2 +- .../collect-in-promoted-const.noopt.stderr | 2 +- .../collect-in-promoted-const.opt.stderr | 4 +- .../interpret-in-const-called-fn.noopt.stderr | 2 +- .../interpret-in-const-called-fn.opt.stderr | 2 +- .../interpret-in-promoted.noopt.stderr | 2 +- .../interpret-in-promoted.opt.stderr | 2 +- .../interpret-in-static.noopt.stderr | 2 +- .../required-consts/interpret-in-static.opt.stderr | 2 +- .../slice-index-overflow-issue-130284.stderr | 2 +- .../consts/static_mut_containing_mut_ref2.stderr | 2 +- .../consts/static_mut_containing_mut_ref3.stderr | 2 +- .../ui/consts/uninhabited-const-issue-61744.stderr | 2 +- .../ui/consts/write-to-static-mut-in-static.stderr | 4 +- tests/ui/enum-discriminant/eval-error.stderr | 2 +- tests/ui/error-codes/E0080.stderr | 4 +- .../ctfe-id-unlimited.return.stderr | 2 +- .../ctfe-tail-call-panic.stderr | 2 +- tests/ui/extern/issue-28324.stderr | 2 +- .../generic-const-items/def-site-eval.fail.stderr | 2 +- .../trivially-unsatisfied-bounds-0.stderr | 2 +- .../trivially-unsatisfied-bounds-1.stderr | 2 +- .../unsatisfied-evaluatable-bounds.stderr | 2 +- .../post_monomorphization_error_backtrace.stderr | 4 +- .../ui/infinite/infinite-recursion-const-fn.stderr | 2 +- .../ui/inline-const/const-expr-generic-err.stderr | 4 +- tests/ui/inline-const/required-const.stderr | 2 +- .../intrinsics/intrinsic-raw_eq-const-bad.stderr | 6 +- tests/ui/issues/issue-76191.stderr | 2 +- tests/ui/layout/invalid-unsized-const-eval.stderr | 2 +- .../invalid-unsized-in-always-sized-tail.stderr | 2 +- .../issue-unsized-tail-restatic-ice-122488.stderr | 2 +- ...putable-due-to-trivial-bounds-ice-135138.stderr | 2 +- .../layout/unknown-when-no-type-parameter.stderr | 2 +- .../layout/unknown-when-ptr-metadata-is-DST.stderr | 2 +- .../def-site-param-defaults-wf.stderr | 2 +- tests/ui/limits/huge-static.stderr | 4 +- tests/ui/limits/issue-55878.stderr | 2 +- .../recursion/recursive-static-definition.stderr | 4 +- tests/ui/simd/const-err-trumps-simd-err.stderr | 2 +- .../stack-overflow-trait-infer-98842.32bit.stderr | 2 +- .../stack-overflow-trait-infer-98842.64bit.stderr | 2 +- tests/ui/statics/issue-14227.stderr | 2 +- tests/ui/statics/uninhabited-static.stderr | 4 +- .../default-field-values/invalid-const.stderr | 4 +- .../default-field-values/post-mono.direct.stderr | 2 +- .../default-field-values/post-mono.indirect.stderr | 2 +- tests/ui/transmutability/uninhabited.stderr | 6 +- tests/ui/treat-err-as-bug/err.stderr | 2 +- tests/ui/type/pattern_types/literals.stderr | 10 +- tests/ui/type/pattern_types/range_patterns.stderr | 2 +- tests/ui/type/pattern_types/reverse_range.stderr | 2 +- tests/ui/type/pattern_types/validity.stderr | 6 +- 219 files changed, 974 insertions(+), 974 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 7d4afc9d3d9..6b7165bb24b 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -89,9 +89,9 @@ const_eval_dyn_call_not_a_method = `dyn` call trying to call something that is not a method const_eval_error = {$error_kind -> - [static] could not evaluate static initializer - [const] evaluation of constant value failed - [const_with_path] evaluation of `{$instance}` failed + [static] evaluation of static initializer failed here + [const] evaluation of constant value failed here + [const_with_path] evaluation of `{$instance}` failed here *[other] {""} } diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr index 453da135fff..8e24b898ed5 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr @@ -13,7 +13,7 @@ error[E0080]: index out of bounds: the length is 2 but the index is 4 --> tests/ui/indexing_slicing_index.rs:69:14 | LL | const { &ARR[idx4()] }; - | ^^^^^^^^^^^ evaluation of `main::{constant#3}` failed + | ^^^^^^^^^^^ evaluation of `main::{constant#3}` failed here note: erroneous constant encountered --> tests/ui/indexing_slicing_index.rs:69:5 diff --git a/src/tools/miri/tests/fail/const-ub-checks.stderr b/src/tools/miri/tests/fail/const-ub-checks.stderr index f2666f674dc..9bac524bd45 100644 --- a/src/tools/miri/tests/fail/const-ub-checks.stderr +++ b/src/tools/miri/tests/fail/const-ub-checks.stderr @@ -2,7 +2,7 @@ error[E0080]: accessing memory based on pointer with alignment ALIGN, but alignm --> tests/fail/const-ub-checks.rs:LL:CC | LL | ptr.read(); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here note: erroneous constant encountered --> tests/fail/const-ub-checks.rs:LL:CC diff --git a/src/tools/miri/tests/fail/erroneous_const.stderr b/src/tools/miri/tests/fail/erroneous_const.stderr index 78ac49830c3..1aa87dd7188 100644 --- a/src/tools/miri/tests/fail/erroneous_const.stderr +++ b/src/tools/miri/tests/fail/erroneous_const.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> tests/fail/erroneous_const.rs:LL:CC | LL | const VOID: ! = panic!(); - | ^^^^^^^^ evaluation of `PrintName::::VOID` failed + | ^^^^^^^^ evaluation of `PrintName::::VOID` failed here note: erroneous constant encountered --> tests/fail/erroneous_const.rs:LL:CC diff --git a/src/tools/miri/tests/fail/erroneous_const2.stderr b/src/tools/miri/tests/fail/erroneous_const2.stderr index 5d529e57197..9d3f1b13bee 100644 --- a/src/tools/miri/tests/fail/erroneous_const2.stderr +++ b/src/tools/miri/tests/fail/erroneous_const2.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `5_u32 - 6_u32`, which would overflow --> tests/fail/erroneous_const2.rs:LL:CC | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ^^^^^ evaluation of constant value failed + | ^^^^^ evaluation of constant value failed here note: erroneous constant encountered --> tests/fail/erroneous_const2.rs:LL:CC diff --git a/tests/rustdoc-ui/const-evalutation-ice.stderr b/tests/rustdoc-ui/const-evalutation-ice.stderr index 7fb78b6a028..2410782000d 100644 --- a/tests/rustdoc-ui/const-evalutation-ice.stderr +++ b/tests/rustdoc-ui/const-evalutation-ice.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/const-evalutation-ice.rs:10:22 | LL | pub const N: usize = 0 - (mem::size_of::() != 400) as usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/array-slice-vec/array_const_index-0.stderr b/tests/ui/array-slice-vec/array_const_index-0.stderr index ed9d9917ebf..1080705713b 100644 --- a/tests/ui/array-slice-vec/array_const_index-0.stderr +++ b/tests/ui/array-slice-vec/array_const_index-0.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 0 but the index is 1 --> $DIR/array_const_index-0.rs:2:16 | LL | const B: i32 = (&A)[1]; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/array-slice-vec/array_const_index-1.stderr b/tests/ui/array-slice-vec/array_const_index-1.stderr index d3db75bd061..56299848d92 100644 --- a/tests/ui/array-slice-vec/array_const_index-1.stderr +++ b/tests/ui/array-slice-vec/array_const_index-1.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 0 but the index is 1 --> $DIR/array_const_index-1.rs:2:16 | LL | const B: i32 = A[1]; - | ^^^^ evaluation of constant value failed + | ^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/asm/fail-const-eval-issue-121099.stderr b/tests/ui/asm/fail-const-eval-issue-121099.stderr index 995f33d06af..7e2718c9eac 100644 --- a/tests/ui/asm/fail-const-eval-issue-121099.stderr +++ b/tests/ui/asm/fail-const-eval-issue-121099.stderr @@ -2,13 +2,13 @@ error[E0080]: attempt to shift left by `500_i32`, which would overflow --> $DIR/fail-const-eval-issue-121099.rs:8:31 | LL | global_asm!("/* {} */", const 1 << 500); - | ^^^^^^^^ evaluation of `{global_asm#0}::{constant#0}` failed + | ^^^^^^^^ evaluation of `{global_asm#0}::{constant#0}` failed here error[E0080]: attempt to divide `1_i32` by zero --> $DIR/fail-const-eval-issue-121099.rs:10:31 | LL | global_asm!("/* {} */", const 1 / 0); - | ^^^^^ evaluation of `{global_asm#1}::{constant#0}` failed + | ^^^^^ evaluation of `{global_asm#1}::{constant#0}` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/associated-consts/defaults-not-assumed-fail.stderr b/tests/ui/associated-consts/defaults-not-assumed-fail.stderr index 334ab19ada8..40f5f889f36 100644 --- a/tests/ui/associated-consts/defaults-not-assumed-fail.stderr +++ b/tests/ui/associated-consts/defaults-not-assumed-fail.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `u8::MAX + 1_u8`, which would overflow --> $DIR/defaults-not-assumed-fail.rs:9:19 | LL | const B: u8 = Self::A + 1; - | ^^^^^^^^^^^ evaluation of `<() as Tr>::B` failed + | ^^^^^^^^^^^ evaluation of `<() as Tr>::B` failed here note: erroneous constant encountered --> $DIR/defaults-not-assumed-fail.rs:34:16 diff --git a/tests/ui/borrowck/issue-81899.stderr b/tests/ui/borrowck/issue-81899.stderr index dcadeef4722..d236a17e0aa 100644 --- a/tests/ui/borrowck/issue-81899.stderr +++ b/tests/ui/borrowck/issue-81899.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-81899.rs:6:24 | LL | const _CONST: &[u8] = &f(&[], |_| {}); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `f::<{closure@$DIR/issue-81899.rs:6:31: 6:34}>` --> $DIR/issue-81899.rs:13:5 diff --git a/tests/ui/borrowck/issue-88434-minimal-example.stderr b/tests/ui/borrowck/issue-88434-minimal-example.stderr index ec32b901e21..3d9cc966047 100644 --- a/tests/ui/borrowck/issue-88434-minimal-example.stderr +++ b/tests/ui/borrowck/issue-88434-minimal-example.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-88434-minimal-example.rs:5:22 | LL | const _CONST: &() = &f(&|_| {}); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here | note: inside `f::<{closure@$DIR/issue-88434-minimal-example.rs:5:25: 5:28}>` --> $DIR/issue-88434-minimal-example.rs:12:5 diff --git a/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr index 8be693b84fe..90d7f36938e 100644 --- a/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr +++ b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-88434-removal-index-should-be-less.rs:5:24 | LL | const _CONST: &[u8] = &f(&[], |_| {}); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `f::<{closure@$DIR/issue-88434-removal-index-should-be-less.rs:5:31: 5:34}>` --> $DIR/issue-88434-removal-index-should-be-less.rs:12:5 diff --git a/tests/ui/coherence/const-errs-dont-conflict-103369.stderr b/tests/ui/coherence/const-errs-dont-conflict-103369.stderr index 236a6982b1c..e577a36cc10 100644 --- a/tests/ui/coherence/const-errs-dont-conflict-103369.stderr +++ b/tests/ui/coherence/const-errs-dont-conflict-103369.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: Some error occurred --> $DIR/const-errs-dont-conflict-103369.rs:5:25 | LL | impl ConstGenericTrait<{my_fn(1)}> for () {} - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here | note: inside `my_fn` --> $DIR/const-errs-dont-conflict-103369.rs:10:5 @@ -14,7 +14,7 @@ error[E0080]: evaluation panicked: Some error occurred --> $DIR/const-errs-dont-conflict-103369.rs:7:25 | LL | impl ConstGenericTrait<{my_fn(2)}> for () {} - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here | note: inside `my_fn` --> $DIR/const-errs-dont-conflict-103369.rs:10:5 diff --git a/tests/ui/const-generics/defaults/default-param-wf-concrete.next.stderr b/tests/ui/const-generics/defaults/default-param-wf-concrete.next.stderr index 9a4e284875b..3299c27a0e7 100644 --- a/tests/ui/const-generics/defaults/default-param-wf-concrete.next.stderr +++ b/tests/ui/const-generics/defaults/default-param-wf-concrete.next.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `u8::MAX + 1_u8`, which would overflow --> $DIR/default-param-wf-concrete.rs:4:28 | LL | struct Foo; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr b/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr index 9a4e284875b..3299c27a0e7 100644 --- a/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr +++ b/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `u8::MAX + 1_u8`, which would overflow --> $DIR/default-param-wf-concrete.rs:4:28 | LL | struct Foo; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/defaults/wfness.stderr b/tests/ui/const-generics/defaults/wfness.stderr index f99180fcdae..ef5167cfc00 100644 --- a/tests/ui/const-generics/defaults/wfness.stderr +++ b/tests/ui/const-generics/defaults/wfness.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `u8::MAX + 1_u8`, which would overflow --> $DIR/wfness.rs:1:33 | LL | struct Ooopsies; - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0277]: the trait bound `(): Trait<2>` is not satisfied --> $DIR/wfness.rs:8:9 diff --git a/tests/ui/const-generics/generic_const_exprs/from-sig-fail.stderr b/tests/ui/const-generics/generic_const_exprs/from-sig-fail.stderr index c993b8c9bd7..72f2dac8fa2 100644 --- a/tests/ui/const-generics/generic_const_exprs/from-sig-fail.stderr +++ b/tests/ui/const-generics/generic_const_exprs/from-sig-fail.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/from-sig-fail.rs:4:35 | LL | fn test() -> [u8; N - 1] { - | ^^^^^ evaluation of `test::<0>::{constant#0}` failed + | ^^^^^ evaluation of `test::<0>::{constant#0}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/simple_fail.stderr b/tests/ui/const-generics/generic_const_exprs/simple_fail.stderr index 1e8343e9471..94a91159e95 100644 --- a/tests/ui/const-generics/generic_const_exprs/simple_fail.stderr +++ b/tests/ui/const-generics/generic_const_exprs/simple_fail.stderr @@ -2,13 +2,13 @@ error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/simple_fail.rs:9:10 | LL | [u8; N - 1]: Sized, - | ^^^^^ evaluation of `test::<0>::{constant#0}` failed + | ^^^^^ evaluation of `test::<0>::{constant#0}` failed here error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/simple_fail.rs:4:33 | LL | type Arr = [u8; N - 1]; - | ^^^^^ evaluation of `Arr::<0>::{constant#0}` failed + | ^^^^^ evaluation of `Arr::<0>::{constant#0}` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/issues/issue-100313.stderr b/tests/ui/const-generics/issues/issue-100313.stderr index 08fef3d4d0e..2ae4c30e15f 100644 --- a/tests/ui/const-generics/issues/issue-100313.stderr +++ b/tests/ui/const-generics/issues/issue-100313.stderr @@ -2,7 +2,7 @@ error[E0080]: writing to ALLOC0 which is read-only --> $DIR/issue-100313.rs:18:5 | LL | x.set_false(); - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `T::<&true>::set_false` --> $DIR/issue-100313.rs:11:13 diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr index 11398a07a45..172fd37fa69 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/invalid-patterns.rs:40:32 | LL | get_flag::(); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean --> $DIR/invalid-patterns.rs:42:14 @@ -30,7 +30,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/invalid-patterns.rs:44:58 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0308]: mismatched types --> $DIR/invalid-patterns.rs:31:21 diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr index 11398a07a45..172fd37fa69 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/invalid-patterns.rs:40:32 | LL | get_flag::(); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean --> $DIR/invalid-patterns.rs:42:14 @@ -30,7 +30,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/invalid-patterns.rs:44:58 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0308]: mismatched types --> $DIR/invalid-patterns.rs:31:21 diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index 229074053e2..d4dcc6e66b1 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -103,13 +103,13 @@ error[E0080]: evaluation panicked: assertion failed: 0 < pointee_size && pointee --> $DIR/forbidden_slices.rs:50:33 | LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; // errors inside libcore - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC10 which is only 4 bytes from the end of the allocation --> $DIR/forbidden_slices.rs:54:25 | LL | from_ptr_range(ptr..ptr.add(2)) // errors inside libcore - | ^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^ evaluation of static initializer failed here error[E0080]: constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer --> $DIR/forbidden_slices.rs:57:1 @@ -161,19 +161,19 @@ error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer --> $DIR/forbidden_slices.rs:79:25 | LL | from_ptr_range(ptr..ptr.add(1)) - | ^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^ evaluation of static initializer failed here error[E0080]: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation --> $DIR/forbidden_slices.rs:85:34 | LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error[E0080]: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation --> $DIR/forbidden_slices.rs:87:35 | LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error: aborting due to 18 previous errors diff --git a/tests/ui/const-ptr/out_of_bounds_read.stderr b/tests/ui/const-ptr/out_of_bounds_read.stderr index b6a74c888e2..e921a5f4987 100644 --- a/tests/ui/const-ptr/out_of_bounds_read.stderr +++ b/tests/ui/const-ptr/out_of_bounds_read.stderr @@ -2,19 +2,19 @@ error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0 --> $DIR/out_of_bounds_read.rs:8:33 | LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes --> $DIR/out_of_bounds_read.rs:10:39 | LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes --> $DIR/out_of_bounds_read.rs:12:37 | LL | const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 3 previous errors diff --git a/tests/ui/consts/assert-type-intrinsics.stderr b/tests/ui/consts/assert-type-intrinsics.stderr index 1e36eb5c25f..90f003716d1 100644 --- a/tests/ui/consts/assert-type-intrinsics.stderr +++ b/tests/ui/consts/assert-type-intrinsics.stderr @@ -2,19 +2,19 @@ error[E0080]: evaluation panicked: aborted execution: attempted to instantiate u --> $DIR/assert-type-intrinsics.rs:11:9 | LL | MaybeUninit::::uninit().assume_init(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: aborted execution: attempted to leave type `&i32` uninitialized, which is invalid --> $DIR/assert-type-intrinsics.rs:15:9 | LL | intrinsics::assert_mem_uninitialized_valid::<&'static i32>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: aborted execution: attempted to zero-initialize type `&i32`, which is invalid --> $DIR/assert-type-intrinsics.rs:19:9 | LL | intrinsics::assert_zero_valid::<&'static i32>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 3 previous errors diff --git a/tests/ui/consts/assoc_const_generic_impl.stderr b/tests/ui/consts/assoc_const_generic_impl.stderr index e44997b624d..fc8986a34c5 100644 --- a/tests/ui/consts/assoc_const_generic_impl.stderr +++ b/tests/ui/consts/assoc_const_generic_impl.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 1 but the index is 4 --> $DIR/assoc_const_generic_impl.rs:9:33 | LL | const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::()]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `::I_AM_ZERO_SIZED` failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `::I_AM_ZERO_SIZED` failed here note: erroneous constant encountered --> $DIR/assoc_const_generic_impl.rs:11:9 diff --git a/tests/ui/consts/const-array-oob.stderr b/tests/ui/consts/const-array-oob.stderr index 80549d84822..d4a02664490 100644 --- a/tests/ui/consts/const-array-oob.stderr +++ b/tests/ui/consts/const-array-oob.stderr @@ -2,13 +2,13 @@ error[E0080]: index out of bounds: the length is 3 but the index is 4 --> $DIR/const-array-oob.rs:5:19 | LL | const BLUB: [u32; FOO[4]] = [5, 6]; - | ^^^^^^ evaluation of constant value failed + | ^^^^^^ evaluation of constant value failed here error[E0080]: index out of bounds: the length is 3 but the index is 5 --> $DIR/const-array-oob.rs:2:20 | LL | const BAR: usize = FOO[5]; - | ^^^^^^ evaluation of constant value failed + | ^^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-assert-unchecked-ub.stderr b/tests/ui/consts/const-assert-unchecked-ub.stderr index 877eef24d77..0a785942cf4 100644 --- a/tests/ui/consts/const-assert-unchecked-ub.stderr +++ b/tests/ui/consts/const-assert-unchecked-ub.stderr @@ -2,7 +2,7 @@ error[E0080]: `assume` called with `false` --> $DIR/const-assert-unchecked-ub.rs:3:5 | LL | std::hint::assert_unchecked(n < 32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-compare-bytes-ub.stderr b/tests/ui/consts/const-compare-bytes-ub.stderr index 98ed4c96b83..1b3824f22d0 100644 --- a/tests/ui/consts/const-compare-bytes-ub.stderr +++ b/tests/ui/consts/const-compare-bytes-ub.stderr @@ -2,49 +2,49 @@ error[E0080]: memory access failed: attempting to access 1 byte, but got null po --> $DIR/const-compare-bytes-ub.rs:9:9 | LL | compare_bytes(0 as *const u8, 2 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/const-compare-bytes-ub.rs:13:9 | LL | compare_bytes(1 as *const u8, 0 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/const-compare-bytes-ub.rs:17:9 | LL | compare_bytes(1 as *const u8, 2 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0 which is only 3 bytes from the end of the allocation --> $DIR/const-compare-bytes-ub.rs:21:9 | LL | compare_bytes([1, 2, 3].as_ptr(), [1, 2, 3, 4].as_ptr(), 4) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC1 which is only 3 bytes from the end of the allocation --> $DIR/const-compare-bytes-ub.rs:25:9 | LL | compare_bytes([1, 2, 3, 4].as_ptr(), [1, 2, 3].as_ptr(), 4) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory --> $DIR/const-compare-bytes-ub.rs:29:9 | LL | compare_bytes(MaybeUninit::uninit().as_ptr(), [1].as_ptr(), 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: reading memory at ALLOC3[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory --> $DIR/const-compare-bytes-ub.rs:33:9 | LL | compare_bytes([1].as_ptr(), MaybeUninit::uninit().as_ptr(), 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: unable to turn pointer into integer --> $DIR/const-compare-bytes-ub.rs:37:9 | LL | compare_bytes([&1].as_ptr().cast(), [&2].as_ptr().cast(), std::mem::size_of::()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-deref-ptr.stderr b/tests/ui/consts/const-deref-ptr.stderr index 8f70f207d51..f233b7d94bd 100644 --- a/tests/ui/consts/const-deref-ptr.stderr +++ b/tests/ui/consts/const-deref-ptr.stderr @@ -2,7 +2,7 @@ error[E0080]: memory access failed: attempting to access 8 bytes, but got 0xdead --> $DIR/const-deref-ptr.rs:4:30 | LL | static C: u64 = unsafe { *(0xdeadbeef as *const u64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-err-early.stderr b/tests/ui/consts/const-err-early.stderr index 8fa94ad8e35..98f9b4fbd2a 100644 --- a/tests/ui/consts/const-err-early.stderr +++ b/tests/ui/consts/const-err-early.stderr @@ -2,31 +2,31 @@ error[E0080]: attempt to negate `i8::MIN`, which would overflow --> $DIR/const-err-early.rs:1:19 | LL | pub const A: i8 = -i8::MIN; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `200_u8 + 200_u8`, which would overflow --> $DIR/const-err-early.rs:2:19 | LL | pub const B: u8 = 200u8 + 200u8; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `200_u8 * 4_u8`, which would overflow --> $DIR/const-err-early.rs:3:19 | LL | pub const C: u8 = 200u8 * 4; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `42_u8 - 43_u8`, which would overflow --> $DIR/const-err-early.rs:4:19 | LL | pub const D: u8 = 42u8 - (42u8 + 1); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: index out of bounds: the length is 1 but the index is 1 --> $DIR/const-err-early.rs:5:19 | LL | pub const E: u8 = [5u8][1]; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error: aborting due to 5 previous errors diff --git a/tests/ui/consts/const-err-enum-discriminant.stderr b/tests/ui/consts/const-err-enum-discriminant.stderr index 66bc09b4f93..702d85b2f93 100644 --- a/tests/ui/consts/const-err-enum-discriminant.stderr +++ b/tests/ui/consts/const-err-enum-discriminant.stderr @@ -2,7 +2,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/const-err-enum-discriminant.rs:8:21 | LL | Boo = [unsafe { Foo { b: () }.a }; 4][3], - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-err-late.stderr b/tests/ui/consts/const-err-late.stderr index 0878df6ff2d..02be7bbe10c 100644 --- a/tests/ui/consts/const-err-late.stderr +++ b/tests/ui/consts/const-err-late.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 1 but the index is 1 --> $DIR/const-err-late.rs:14:21 | LL | const FOO: u8 = [5u8][1]; - | ^^^^^^^^ evaluation of `S::::FOO` failed + | ^^^^^^^^ evaluation of `S::::FOO` failed here note: erroneous constant encountered --> $DIR/const-err-late.rs:20:16 @@ -14,7 +14,7 @@ error[E0080]: index out of bounds: the length is 1 but the index is 1 --> $DIR/const-err-late.rs:14:21 | LL | const FOO: u8 = [5u8][1]; - | ^^^^^^^^ evaluation of `S::::FOO` failed + | ^^^^^^^^ evaluation of `S::::FOO` failed here note: erroneous constant encountered --> $DIR/const-err-late.rs:20:31 diff --git a/tests/ui/consts/const-err-multi.stderr b/tests/ui/consts/const-err-multi.stderr index 712c160a2c0..9e1554eb265 100644 --- a/tests/ui/consts/const-err-multi.stderr +++ b/tests/ui/consts/const-err-multi.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to negate `i8::MIN`, which would overflow --> $DIR/const-err-multi.rs:1:19 | LL | pub const A: i8 = -i8::MIN; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here note: erroneous constant encountered --> $DIR/const-err-multi.rs:4:19 diff --git a/tests/ui/consts/const-eval-fail-too-big.stderr b/tests/ui/consts/const-eval-fail-too-big.stderr index 6f9dd178857..3bc20ded5bf 100644 --- a/tests/ui/consts/const-eval-fail-too-big.stderr +++ b/tests/ui/consts/const-eval-fail-too-big.stderr @@ -2,7 +2,7 @@ error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target a --> $DIR/const-eval-fail-too-big.rs:4:28 | LL | let x = [0u8; !0usize]; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr b/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr index ceb7d910b57..b19d0eaa116 100644 --- a/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr +++ b/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr @@ -2,7 +2,7 @@ error[E0080]: modifying a static's initial value from another static's initializ --> $DIR/assign-to-static-within-other-static.rs:8:5 | LL | FOO = 5; - | ^^^^^^^ could not evaluate static initializer + | ^^^^^^^ evaluation of static initializer failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/conditional_array_execution.stderr b/tests/ui/consts/const-eval/conditional_array_execution.stderr index d4f85ce7f56..65ae9a9fb8a 100644 --- a/tests/ui/consts/const-eval/conditional_array_execution.stderr +++ b/tests/ui/consts/const-eval/conditional_array_execution.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `5_u32 - 6_u32`, which would overflow --> $DIR/conditional_array_execution.rs:3:19 | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ^^^^^ evaluation of constant value failed + | ^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr index 6bd2a7482d2..90b94600aed 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to negate `i8::MIN`, which would overflow --> $DIR/const-eval-overflow-2.rs:11:25 | LL | const NEG_NEG_128: i8 = -NEG_128; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3.stderr b/tests/ui/consts/const-eval/const-eval-overflow-3.stderr index 07cc8c8df70..5ad7d08bdb3 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-3.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-3.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `i8::MAX + 1_i8`, which would overflow --> $DIR/const-eval-overflow-3.rs:18:11 | LL | = [0; (i8::MAX + 1) as usize]; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4.stderr b/tests/ui/consts/const-eval/const-eval-overflow-4.stderr index c4e4e6e10e6..c14a880849f 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-4.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-4.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `i8::MAX + 1_i8`, which would overflow --> $DIR/const-eval-overflow-4.rs:11:13 | LL | : [u32; (i8::MAX as i8 + 1i8) as usize] - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const-eval-overflow2.stderr b/tests/ui/consts/const-eval/const-eval-overflow2.stderr index fc0bbe3ed2a..a705604e383 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow2.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow2.stderr @@ -2,49 +2,49 @@ error[E0080]: attempt to compute `i8::MIN - 1_i8`, which would overflow --> $DIR/const-eval-overflow2.rs:12:6 | LL | i8::MIN - 1, - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i16::MIN - 1_i16`, which would overflow --> $DIR/const-eval-overflow2.rs:18:6 | LL | i16::MIN - 1, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i32::MIN - 1_i32`, which would overflow --> $DIR/const-eval-overflow2.rs:24:6 | LL | i32::MIN - 1, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i64::MIN - 1_i64`, which would overflow --> $DIR/const-eval-overflow2.rs:30:6 | LL | i64::MIN - 1, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `0_u8 - 1_u8`, which would overflow --> $DIR/const-eval-overflow2.rs:36:6 | LL | u8::MIN - 1, - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `0_u16 - 1_u16`, which would overflow --> $DIR/const-eval-overflow2.rs:41:6 | LL | u16::MIN - 1, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `0_u32 - 1_u32`, which would overflow --> $DIR/const-eval-overflow2.rs:46:6 | LL | u32::MIN - 1, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `0_u64 - 1_u64`, which would overflow --> $DIR/const-eval-overflow2.rs:52:6 | LL | u64::MIN - 1, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 8 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-overflow2b.stderr b/tests/ui/consts/const-eval/const-eval-overflow2b.stderr index cd8fbc5ee1c..33de4b6ed32 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow2b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow2b.stderr @@ -2,49 +2,49 @@ error[E0080]: attempt to compute `i8::MAX + 1_i8`, which would overflow --> $DIR/const-eval-overflow2b.rs:12:6 | LL | i8::MAX + 1, - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i16::MAX + 1_i16`, which would overflow --> $DIR/const-eval-overflow2b.rs:18:6 | LL | i16::MAX + 1, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i32::MAX + 1_i32`, which would overflow --> $DIR/const-eval-overflow2b.rs:24:6 | LL | i32::MAX + 1, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i64::MAX + 1_i64`, which would overflow --> $DIR/const-eval-overflow2b.rs:30:6 | LL | i64::MAX + 1, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u8::MAX + 1_u8`, which would overflow --> $DIR/const-eval-overflow2b.rs:36:6 | LL | u8::MAX + 1, - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u16::MAX + 1_u16`, which would overflow --> $DIR/const-eval-overflow2b.rs:41:6 | LL | u16::MAX + 1, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u32::MAX + 1_u32`, which would overflow --> $DIR/const-eval-overflow2b.rs:46:6 | LL | u32::MAX + 1, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u64::MAX + 1_u64`, which would overflow --> $DIR/const-eval-overflow2b.rs:52:6 | LL | u64::MAX + 1, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 8 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-overflow2c.stderr b/tests/ui/consts/const-eval/const-eval-overflow2c.stderr index 5914c40326b..69949b57904 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow2c.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow2c.stderr @@ -2,49 +2,49 @@ error[E0080]: attempt to compute `i8::MIN * 2_i8`, which would overflow --> $DIR/const-eval-overflow2c.rs:12:6 | LL | i8::MIN * 2, - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i16::MIN * 2_i16`, which would overflow --> $DIR/const-eval-overflow2c.rs:18:6 | LL | i16::MIN * 2, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i32::MIN * 2_i32`, which would overflow --> $DIR/const-eval-overflow2c.rs:24:6 | LL | i32::MIN * 2, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i64::MIN * 2_i64`, which would overflow --> $DIR/const-eval-overflow2c.rs:30:6 | LL | i64::MIN * 2, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u8::MAX * 2_u8`, which would overflow --> $DIR/const-eval-overflow2c.rs:36:6 | LL | u8::MAX * 2, - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u16::MAX * 2_u16`, which would overflow --> $DIR/const-eval-overflow2c.rs:41:6 | LL | u16::MAX * 2, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u32::MAX * 2_u32`, which would overflow --> $DIR/const-eval-overflow2c.rs:46:6 | LL | u32::MAX * 2, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u64::MAX * 2_u64`, which would overflow --> $DIR/const-eval-overflow2c.rs:52:6 | LL | u64::MAX * 2, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 8 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-query-stack.stderr b/tests/ui/consts/const-eval/const-eval-query-stack.stderr index c8bec4d4100..d5b7e67724d 100644 --- a/tests/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/tests/ui/consts/const-eval/const-eval-query-stack.stderr @@ -2,7 +2,7 @@ error: internal compiler error[E0080]: attempt to divide `1_i32` by zero --> $DIR/const-eval-query-stack.rs:16:16 | LL | const X: i32 = 1 / 0; - | ^^^^^ evaluation of constant value failed + | ^^^^^ evaluation of constant value failed here note: please make sure that you have updated to the latest nightly diff --git a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr index ae7e035e038..3a1e8c734d4 100644 --- a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr +++ b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:27:49 | LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -11,7 +11,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:30:43 | LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -20,7 +20,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:33:45 | LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -29,7 +29,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:36:45 | LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -38,7 +38,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:39:45 | LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -47,13 +47,13 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/const-pointer-values-in-various-types.rs:42:47 | LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:45:43 | LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -62,7 +62,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:48:45 | LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -71,7 +71,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:51:45 | LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -80,7 +80,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:54:45 | LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -89,13 +89,13 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/const-pointer-values-in-various-types.rs:57:47 | LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:60:45 | LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -104,7 +104,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:63:45 | LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -113,7 +113,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:66:47 | LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -122,7 +122,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:69:47 | LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -131,7 +131,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:72:39 | LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -140,7 +140,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:75:41 | LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -149,7 +149,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:78:41 | LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -158,7 +158,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:81:41 | LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -167,7 +167,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:84:43 | LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -176,7 +176,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:87:39 | LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -185,7 +185,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:90:41 | LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -194,7 +194,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:93:41 | LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -203,7 +203,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:96:41 | LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -212,7 +212,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:99:43 | LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -221,7 +221,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:102:41 | LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -230,7 +230,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:105:41 | LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -239,7 +239,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:108:43 | LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -248,7 +248,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:111:43 | LL | const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr index caa0542b6aa..6eddb72bae8 100644 --- a/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr +++ b/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr @@ -2,7 +2,7 @@ error[E0080]: calling non-const function `double` --> $DIR/const_fn_ptr_fail2.rs:16:18 | LL | const Y: usize = bar(X, 2); // FIXME: should fail to typeck someday - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here | note: inside `bar` --> $DIR/const_fn_ptr_fail2.rs:9:5 @@ -14,7 +14,7 @@ error[E0080]: calling non-const function `double` --> $DIR/const_fn_ptr_fail2.rs:19:18 | LL | const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `bar` --> $DIR/const_fn_ptr_fail2.rs:9:5 diff --git a/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr b/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr index cda005bfd3b..6e5e0e727fb 100644 --- a/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr +++ b/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: --> $DIR/const_panic-normalize-tabs-115498.rs:3:17 | LL | struct Bug([u8; panic!{"\t"}]); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const_panic.stderr b/tests/ui/consts/const-eval/const_panic.stderr index c37d035ab78..1b5421276c3 100644 --- a/tests/ui/consts/const-eval/const_panic.stderr +++ b/tests/ui/consts/const-eval/const_panic.stderr @@ -2,25 +2,25 @@ error[E0080]: evaluation panicked: cheese --> $DIR/const_panic.rs:6:15 | LL | const Z: () = std::panic!("cheese"); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: explicit panic --> $DIR/const_panic.rs:9:16 | LL | const Z2: () = std::panic!(); - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic.rs:12:15 | LL | const Y: () = std::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic.rs:15:15 | LL | const X: () = std::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = note: this error originates in the macro `std::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -28,37 +28,37 @@ error[E0080]: evaluation panicked: hello --> $DIR/const_panic.rs:18:15 | LL | const W: () = std::panic!(MSG); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: hello --> $DIR/const_panic.rs:21:16 | LL | const W2: () = std::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: cheese --> $DIR/const_panic.rs:24:20 | LL | const Z_CORE: () = core::panic!("cheese"); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: explicit panic --> $DIR/const_panic.rs:27:21 | LL | const Z2_CORE: () = core::panic!(); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic.rs:30:20 | LL | const Y_CORE: () = core::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic.rs:33:20 | LL | const X_CORE: () = core::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = note: this error originates in the macro `core::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -66,13 +66,13 @@ error[E0080]: evaluation panicked: hello --> $DIR/const_panic.rs:36:20 | LL | const W_CORE: () = core::panic!(MSG); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: hello --> $DIR/const_panic.rs:39:21 | LL | const W2_CORE: () = core::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 12 previous errors diff --git a/tests/ui/consts/const-eval/const_panic_2021.stderr b/tests/ui/consts/const-eval/const_panic_2021.stderr index 18423f2c7d2..15b173f9400 100644 --- a/tests/ui/consts/const-eval/const_panic_2021.stderr +++ b/tests/ui/consts/const-eval/const_panic_2021.stderr @@ -2,25 +2,25 @@ error[E0080]: evaluation panicked: blåhaj --> $DIR/const_panic_2021.rs:6:15 | LL | const A: () = std::panic!("blåhaj"); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: explicit panic --> $DIR/const_panic_2021.rs:9:15 | LL | const B: () = std::panic!(); - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic_2021.rs:12:15 | LL | const C: () = std::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic_2021.rs:15:15 | LL | const D: () = std::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = note: this error originates in the macro `std::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -28,31 +28,31 @@ error[E0080]: evaluation panicked: hello --> $DIR/const_panic_2021.rs:18:15 | LL | const E: () = std::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: shark --> $DIR/const_panic_2021.rs:21:20 | LL | const A_CORE: () = core::panic!("shark"); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: explicit panic --> $DIR/const_panic_2021.rs:24:20 | LL | const B_CORE: () = core::panic!(); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic_2021.rs:27:20 | LL | const C_CORE: () = core::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic_2021.rs:30:20 | LL | const D_CORE: () = core::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = note: this error originates in the macro `core::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -60,7 +60,7 @@ error[E0080]: evaluation panicked: hello --> $DIR/const_panic_2021.rs:33:20 | LL | const E_CORE: () = core::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 10 previous errors diff --git a/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr b/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr index 9f76e15b645..3c308e38850 100644 --- a/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr +++ b/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr @@ -2,19 +2,19 @@ error[E0080]: evaluation panicked: cheese --> $DIR/const_panic_libcore_bin.rs:8:15 | LL | const Z: () = panic!("cheese"); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic_libcore_bin.rs:11:15 | LL | const Y: () = unreachable!(); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic_libcore_bin.rs:14:15 | LL | const X: () = unimplemented!(); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/const-eval/const_panic_track_caller.stderr b/tests/ui/consts/const-eval/const_panic_track_caller.stderr index 621e8880e3c..b4017ccf8da 100644 --- a/tests/ui/consts/const-eval/const_panic_track_caller.stderr +++ b/tests/ui/consts/const-eval/const_panic_track_caller.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: hey --> $DIR/const_panic_track_caller.rs:19:16 | LL | const X: u32 = c(); - | ^^^ evaluation of constant value failed + | ^^^ evaluation of constant value failed here | note: inside `c` --> $DIR/const_panic_track_caller.rs:15:5 diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr index 152f3704810..6f096ee5ce7 100644 --- a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr @@ -2,13 +2,13 @@ error[E0080]: memory access failed: attempting to access 4 bytes, but got 0x2a[n --> $DIR/const_raw_ptr_ops2.rs:7:26 | LL | const Z2: i32 = unsafe { *(42 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: memory access failed: attempting to access 4 bytes, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/const_raw_ptr_ops2.rs:8:26 | LL | const Z3: i32 = unsafe { *(44 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr index 08990f949f8..9132c7e9cd4 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr @@ -2,7 +2,7 @@ error[E0080]: invalid align passed to `const_allocate`: 3 is not a power of 2 --> $DIR/alloc_intrinsic_errors.rs:7:18 | LL | const FOO: i32 = foo(); - | ^^^^^ evaluation of constant value failed + | ^^^^^ evaluation of constant value failed here | note: inside `foo` --> $DIR/alloc_intrinsic_errors.rs:10:17 diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr index d1d16fa4fda..cb419f2f739 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr @@ -13,7 +13,7 @@ error[E0080]: memory access failed: ALLOC1 has been freed, so this pointer is da --> $DIR/dealloc_intrinsic_dangling.rs:22:5 | LL | *reference - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr index 553b0fa09c9..3038d60f202 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr @@ -2,7 +2,7 @@ error[E0080]: memory access failed: ALLOC0 has been freed, so this pointer is da --> $DIR/dealloc_intrinsic_duplicate.rs:9:5 | LL | intrinsics::const_deallocate(ptr, 4, 4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr index 04fa75d25c7..dea55c6086e 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr @@ -2,25 +2,25 @@ error[E0080]: incorrect layout on deallocation: ALLOC0 has size 4 and alignment --> $DIR/dealloc_intrinsic_incorrect_layout.rs:8:5 | LL | intrinsics::const_deallocate(ptr, 4, 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: incorrect layout on deallocation: ALLOC1 has size 4 and alignment 4, but gave size 2 and alignment 4 --> $DIR/dealloc_intrinsic_incorrect_layout.rs:13:5 | LL | intrinsics::const_deallocate(ptr, 2, 4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: incorrect layout on deallocation: ALLOC2 has size 4 and alignment 4, but gave size 3 and alignment 4 --> $DIR/dealloc_intrinsic_incorrect_layout.rs:19:5 | LL | intrinsics::const_deallocate(ptr, 3, 4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: invalid align passed to `const_deallocate`: 3 is not a power of 2 --> $DIR/dealloc_intrinsic_incorrect_layout.rs:25:5 | LL | intrinsics::const_deallocate(ptr, 4, 3); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 4 previous errors diff --git a/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr index fe34d211d52..7e57e16aa4f 100644 --- a/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr +++ b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 0 but the index is 0 --> $DIR/index-out-of-bounds-never-type.rs:10:61 | LL | const VOID: ! = { let x = 0 * std::mem::size_of::(); [][x] }; - | ^^^^^ evaluation of `PrintName::<()>::VOID` failed + | ^^^^^ evaluation of `PrintName::<()>::VOID` failed here note: erroneous constant encountered --> $DIR/index-out-of-bounds-never-type.rs:16:13 diff --git a/tests/ui/consts/const-eval/index_out_of_bounds.stderr b/tests/ui/consts/const-eval/index_out_of_bounds.stderr index 9fe52f11d04..f4ec4c516fd 100644 --- a/tests/ui/consts/const-eval/index_out_of_bounds.stderr +++ b/tests/ui/consts/const-eval/index_out_of_bounds.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 0 but the index is 0 --> $DIR/index_out_of_bounds.rs:1:19 | LL | static FOO: i32 = [][0]; - | ^^^^^ could not evaluate static initializer + | ^^^^^ evaluation of static initializer failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/issue-43197.stderr b/tests/ui/consts/const-eval/issue-43197.stderr index f2211dfb388..cad23becff7 100644 --- a/tests/ui/consts/const-eval/issue-43197.stderr +++ b/tests/ui/consts/const-eval/issue-43197.stderr @@ -2,13 +2,13 @@ error[E0080]: attempt to compute `0_u32 - 1_u32`, which would overflow --> $DIR/issue-43197.rs:6:20 | LL | const X: u32 = 0 - 1; - | ^^^^^ evaluation of constant value failed + | ^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `0_u32 - 1_u32`, which would overflow --> $DIR/issue-43197.rs:8:24 | LL | const Y: u32 = foo(0 - 1); - | ^^^^^ evaluation of constant value failed + | ^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/issue-44578.stderr b/tests/ui/consts/const-eval/issue-44578.stderr index f558b7a5016..fd0b9ae1e17 100644 --- a/tests/ui/consts/const-eval/issue-44578.stderr +++ b/tests/ui/consts/const-eval/issue-44578.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 1 but the index is 1 --> $DIR/issue-44578.rs:14:24 | LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of ` as Foo>::AMT` failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of ` as Foo>::AMT` failed here note: erroneous constant encountered --> $DIR/issue-44578.rs:26:20 diff --git a/tests/ui/consts/const-eval/issue-49296.stderr b/tests/ui/consts/const-eval/issue-49296.stderr index 9c7f8997eaa..4a66ec6c940 100644 --- a/tests/ui/consts/const-eval/issue-49296.stderr +++ b/tests/ui/consts/const-eval/issue-49296.stderr @@ -2,7 +2,7 @@ error[E0080]: memory access failed: ALLOC0 has been freed, so this pointer is da --> $DIR/issue-49296.rs:9:16 | LL | const X: u64 = *wat(42); - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr b/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr index a333fe3423b..6c0d6cf8b21 100644 --- a/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr +++ b/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 3 but the index is 42 --> $DIR/issue-50814-2.rs:17:24 | LL | const BAR: usize = [5, 6, 7][T::BOO]; - | ^^^^^^^^^^^^^^^^^ evaluation of ` as Foo<()>>::BAR` failed + | ^^^^^^^^^^^^^^^^^ evaluation of ` as Foo<()>>::BAR` failed here note: erroneous constant encountered --> $DIR/issue-50814-2.rs:21:6 diff --git a/tests/ui/consts/const-eval/issue-50814-2.normal.stderr b/tests/ui/consts/const-eval/issue-50814-2.normal.stderr index 0ad4185be3a..749c9dde1ce 100644 --- a/tests/ui/consts/const-eval/issue-50814-2.normal.stderr +++ b/tests/ui/consts/const-eval/issue-50814-2.normal.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 3 but the index is 42 --> $DIR/issue-50814-2.rs:17:24 | LL | const BAR: usize = [5, 6, 7][T::BOO]; - | ^^^^^^^^^^^^^^^^^ evaluation of ` as Foo<()>>::BAR` failed + | ^^^^^^^^^^^^^^^^^ evaluation of ` as Foo<()>>::BAR` failed here note: erroneous constant encountered --> $DIR/issue-50814-2.rs:21:6 diff --git a/tests/ui/consts/const-eval/issue-50814.stderr b/tests/ui/consts/const-eval/issue-50814.stderr index 27cc6458ec1..1287c83ae0f 100644 --- a/tests/ui/consts/const-eval/issue-50814.stderr +++ b/tests/ui/consts/const-eval/issue-50814.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `u8::MAX + u8::MAX`, which would overflow --> $DIR/issue-50814.rs:16:21 | LL | const MAX: u8 = A::MAX + B::MAX; - | ^^^^^^^^^^^^^^^ evaluation of ` as Unsigned>::MAX` failed + | ^^^^^^^^^^^^^^^ evaluation of ` as Unsigned>::MAX` failed here note: erroneous constant encountered --> $DIR/issue-50814.rs:22:6 @@ -14,7 +14,7 @@ error[E0080]: attempt to compute `u8::MAX + u8::MAX`, which would overflow --> $DIR/issue-50814.rs:16:21 | LL | const MAX: u8 = A::MAX + B::MAX; - | ^^^^^^^^^^^^^^^ evaluation of ` as Unsigned>::MAX` failed + | ^^^^^^^^^^^^^^^ evaluation of ` as Unsigned>::MAX` failed here | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/consts/const-eval/issue-85155.stderr b/tests/ui/consts/const-eval/issue-85155.stderr index 8aa99764fe0..f7777bfac02 100644 --- a/tests/ui/consts/const-eval/issue-85155.stderr +++ b/tests/ui/consts/const-eval/issue-85155.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to divide `1_usize` by zero --> $DIR/auxiliary/post_monomorphization_error.rs:7:17 | LL | let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `post_monomorphization_error::ValidateConstImm::<2, 0, 1>::VALID` failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `post_monomorphization_error::ValidateConstImm::<2, 0, 1>::VALID` failed here note: erroneous constant encountered --> $DIR/auxiliary/post_monomorphization_error.rs:19:5 diff --git a/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr index 185ef9c0750..ffff7594e3d 100644 --- a/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr +++ b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr @@ -2,7 +2,7 @@ error[E0080]: `extern type` field does not have a known offset --> $DIR/issue-91827-extern-types-field-offset.rs:38:17 | LL | let field = &x.a; - | ^^^^ evaluation of constant value failed + | ^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr b/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr index b882b902d96..f8cf6096095 100644 --- a/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr +++ b/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr @@ -2,7 +2,7 @@ error[E0080]: modifying a static's initial value from another static's initializ --> $DIR/mod-static-with-const-fn.rs:14:5 | LL | *FOO.0.get() = 5; - | ^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr index c4c8a76ddac..32ae9475560 100644 --- a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr +++ b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr @@ -2,7 +2,7 @@ error[E0080]: memory access failed: attempting to access 1 byte, but got 0x1[noa --> $DIR/nonnull_as_ref_ub.rs:4:29 | LL | const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/panic-assoc-never-type.stderr b/tests/ui/consts/const-eval/panic-assoc-never-type.stderr index 2d6bf96228b..64c9f92d5ee 100644 --- a/tests/ui/consts/const-eval/panic-assoc-never-type.stderr +++ b/tests/ui/consts/const-eval/panic-assoc-never-type.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/panic-assoc-never-type.rs:10:21 | LL | const VOID: ! = panic!(); - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here note: erroneous constant encountered --> $DIR/panic-assoc-never-type.rs:15:13 diff --git a/tests/ui/consts/const-eval/panic-never-type.stderr b/tests/ui/consts/const-eval/panic-never-type.stderr index 60712effbab..cacce93babe 100644 --- a/tests/ui/consts/const-eval/panic-never-type.stderr +++ b/tests/ui/consts/const-eval/panic-never-type.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/panic-never-type.rs:4:17 | LL | const VOID: ! = panic!(); - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/parse_ints.stderr b/tests/ui/consts/const-eval/parse_ints.stderr index 8b5ab23e182..99aad805a2d 100644 --- a/tests/ui/consts/const-eval/parse_ints.stderr +++ b/tests/ui/consts/const-eval/parse_ints.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: from_ascii_radix: radix must lie in the range --> $DIR/parse_ints.rs:5:24 | LL | const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `core::num::::from_str_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL @@ -14,7 +14,7 @@ error[E0080]: evaluation panicked: from_ascii_radix: radix must lie in the range --> $DIR/parse_ints.rs:6:25 | LL | const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `core::num::::from_str_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL diff --git a/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr b/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr index b5d1e4c113c..4d514495e73 100644 --- a/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr +++ b/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr @@ -2,7 +2,7 @@ error[E0080]: unable to overwrite parts of a pointer in memory at ALLOC0 --> $DIR/partial_ptr_overwrite.rs:7:9 | LL | *(ptr as *mut u8) = 123; - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr index 162485a8adf..e424924e14b 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -2,19 +2,19 @@ error[E0080]: accessing memory based on pointer with alignment 1, but alignment --> $DIR/raw-pointer-ub.rs:4:16 | LL | let _val = *ptr; - | ^^^^ evaluation of constant value failed + | ^^^^ evaluation of constant value failed here error[E0080]: accessing memory based on pointer with alignment 1, but alignment 4 is required --> $DIR/raw-pointer-ub.rs:11:5 | LL | *ptr = 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: accessing memory with alignment 1, but alignment 4 is required --> $DIR/raw-pointer-ub.rs:19:5 | LL | y.copy_to_nonoverlapping(&mut z, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `std::ptr::copy_nonoverlapping::` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -23,13 +23,13 @@ error[E0080]: accessing memory based on pointer with alignment 4, but alignment --> $DIR/raw-pointer-ub.rs:33:16 | LL | let _val = (*ptr).0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: memory access failed: attempting to access 8 bytes, but got ALLOC0 which is only 4 bytes from the end of the allocation --> $DIR/raw-pointer-ub.rs:40:16 | LL | let _val = *ptr; - | ^^^^ evaluation of constant value failed + | ^^^^ evaluation of constant value failed here error: aborting due to 5 previous errors diff --git a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr index cf460d65e8d..be86541434b 100644 --- a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr +++ b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ref_to_int_match.rs:24:27 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr index cf460d65e8d..be86541434b 100644 --- a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr +++ b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ref_to_int_match.rs:24:27 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/shift_overflow.stderr b/tests/ui/consts/const-eval/shift_overflow.stderr index 1ba2feea976..e5703fb1d77 100644 --- a/tests/ui/consts/const-eval/shift_overflow.stderr +++ b/tests/ui/consts/const-eval/shift_overflow.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to shift left by `4294967296_u64`, which would overflow --> $DIR/shift_overflow.rs:3:9 | LL | X = 1 << ((u32::MAX as u64) + 1), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/transmute-size-mismatch.stderr b/tests/ui/consts/const-eval/transmute-size-mismatch.stderr index f44edef0f34..92088a4749a 100644 --- a/tests/ui/consts/const-eval/transmute-size-mismatch.stderr +++ b/tests/ui/consts/const-eval/transmute-size-mismatch.stderr @@ -2,7 +2,7 @@ error[E0080]: transmuting from 4-byte type to 2-byte type: `i32` -> `u16` --> $DIR/transmute-size-mismatch.rs:22:35 | LL | const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `mir_transmute::` --> $DIR/transmute-size-mismatch.rs:12:13 @@ -14,7 +14,7 @@ error[E0080]: transmuting from 2-byte type to 4-byte type: `i16` -> `u32` --> $DIR/transmute-size-mismatch.rs:25:36 | LL | const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) }; - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `mir_transmute::` --> $DIR/transmute-size-mismatch.rs:12:13 diff --git a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr index 4953ac5935d..0c1a606904c 100644 --- a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr +++ b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr @@ -2,7 +2,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/ub-enum-overwrite.rs:11:14 | LL | unsafe { *p } - | ^^ evaluation of constant value failed + | ^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/ub-enum.stderr b/tests/ui/consts/const-eval/ub-enum.stderr index 9964d8e1a9c..7015102a50a 100644 --- a/tests/ui/consts/const-eval/ub-enum.stderr +++ b/tests/ui/consts/const-eval/ub-enum.stderr @@ -13,7 +13,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-enum.rs:32:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -22,7 +22,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-enum.rs:35:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -42,7 +42,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-enum.rs:49:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -51,7 +51,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-enum.rs:52:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -60,13 +60,13 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/ub-enum.rs:61:41 | LL | const BAD_ENUM2_UNDEF: Enum2 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: unable to turn pointer into integer --> $DIR/ub-enum.rs:65:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -108,19 +108,19 @@ error[E0080]: constructing invalid value at .: encountered an uninhabi --> $DIR/ub-enum.rs:97:77 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant --> $DIR/ub-enum.rs:99:77 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: read discriminant of an uninhabited enum variant --> $DIR/ub-enum.rs:105:9 | LL | std::mem::discriminant(&*(&() as *const () as *const Never)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `discriminant::` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/consts/const-eval/ub-invalid-values.stderr b/tests/ui/consts/const-eval/ub-invalid-values.stderr index ceee06f05a4..83879eeb716 100644 --- a/tests/ui/consts/const-eval/ub-invalid-values.stderr +++ b/tests/ui/consts/const-eval/ub-invalid-values.stderr @@ -2,7 +2,7 @@ error[E0080]: interpreting an invalid 8-bit value as a bool: 0x03 --> $DIR/ub-invalid-values.rs:8:5 | LL | bool_cast(&v as *const u8 as *const bool); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `bool_cast` --> $DIR/ub-invalid-values.rs:2:16 diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index 0919c9906f7..0a02dbb16bf 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -13,7 +13,7 @@ error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer --> $DIR/ub-nonnull.rs:22:29 | LL | let out_of_bounds_ptr = &ptr[255]; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 --> $DIR/ub-nonnull.rs:26:1 @@ -41,7 +41,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/ub-nonnull.rs:36:38 | LL | const UNINIT: NonZero = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value: encountered 42, but expected something in the range 10..=30 --> $DIR/ub-nonnull.rs:44:1 diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index 31a216916d5..e10f21b02af 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -46,7 +46,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-ref-ptr.rs:33:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -55,7 +55,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-ref-ptr.rs:36:39 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -70,7 +70,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-ref-ptr.rs:39:86 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -107,7 +107,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/ub-ref-ptr.rs:48:41 | LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value: encountered null pointer, but expected a function pointer --> $DIR/ub-ref-ptr.rs:51:1 @@ -124,7 +124,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/ub-ref-ptr.rs:53:38 | LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected a function pointer --> $DIR/ub-ref-ptr.rs:55:1 @@ -152,7 +152,7 @@ error[E0080]: accessing memory based on pointer with alignment 1, but alignment --> $DIR/ub-ref-ptr.rs:64:5 | LL | ptr.read(); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 15 previous errors diff --git a/tests/ui/consts/const-eval/ub-uninhabit.stderr b/tests/ui/consts/const-eval/ub-uninhabit.stderr index 38779ea164b..582a7a07be9 100644 --- a/tests/ui/consts/const-eval/ub-uninhabit.stderr +++ b/tests/ui/consts/const-eval/ub-uninhabit.stderr @@ -2,7 +2,7 @@ error[E0080]: constructing invalid value: encountered a value of uninhabited typ --> $DIR/ub-uninhabit.rs:20:35 | LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value: encountered a reference pointing to uninhabited type Bar --> $DIR/ub-uninhabit.rs:23:1 @@ -19,13 +19,13 @@ error[E0080]: constructing invalid value at [0]: encountered a value of uninhabi --> $DIR/ub-uninhabit.rs:26:42 | LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value: encountered a value of the never type `!` --> $DIR/ub-uninhabit.rs:32:16 | LL | let _val = intrinsics::read_via_copy(ptr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 4 previous errors diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index 7b7f013446f..a586f154ca1 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -24,7 +24,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-wide-ptr.rs:44:1 | LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -33,7 +33,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-wide-ptr.rs:47:1 | LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -75,7 +75,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/ub-wide-ptr.rs:63:1 | LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/ub-wide-ptr.rs:69:1 @@ -103,7 +103,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-wide-ptr.rs:75:1 | LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -123,7 +123,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-wide-ptr.rs:81:1 | LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -183,7 +183,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/ub-wide-ptr.rs:101:1 | LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value at .0: encountered ALLOC12, but expected a vtable pointer --> $DIR/ub-wide-ptr.rs:109:1 diff --git a/tests/ui/consts/const-eval/ub-write-through-immutable.stderr b/tests/ui/consts/const-eval/ub-write-through-immutable.stderr index a7b4aa5fac8..dbcd07110cc 100644 --- a/tests/ui/consts/const-eval/ub-write-through-immutable.stderr +++ b/tests/ui/consts/const-eval/ub-write-through-immutable.stderr @@ -2,13 +2,13 @@ error[E0080]: writing through a pointer that was derived from a shared (immutabl --> $DIR/ub-write-through-immutable.rs:10:5 | LL | *ptr = 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: writing through a pointer that was derived from a shared (immutable) reference --> $DIR/ub-write-through-immutable.rs:16:5 | LL | *ptr = 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/union-const-eval-field.stderr b/tests/ui/consts/const-eval/union-const-eval-field.stderr index 060e3e314aa..eb3906a4ecc 100644 --- a/tests/ui/consts/const-eval/union-const-eval-field.stderr +++ b/tests/ui/consts/const-eval/union-const-eval-field.stderr @@ -2,7 +2,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/union-const-eval-field.rs:28:37 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here note: erroneous constant encountered --> $DIR/union-const-eval-field.rs:30:5 diff --git a/tests/ui/consts/const-eval/union-ice.stderr b/tests/ui/consts/const-eval/union-ice.stderr index a68f6c02945..86c42713095 100644 --- a/tests/ui/consts/const-eval/union-ice.stderr +++ b/tests/ui/consts/const-eval/union-ice.stderr @@ -2,19 +2,19 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/union-ice.rs:14:33 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/union-ice.rs:19:17 | LL | b: unsafe { UNION.field3 }, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/union-ice.rs:31:18 | LL | unsafe { UNION.field3 }, - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const-eval/union-ub.32bit.stderr b/tests/ui/consts/const-eval/union-ub.32bit.stderr index 2cc3f8bdaac..7b263c20d33 100644 --- a/tests/ui/consts/const-eval/union-ub.32bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.32bit.stderr @@ -13,7 +13,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/union-ub.rs:35:36 | LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/union-ub.64bit.stderr b/tests/ui/consts/const-eval/union-ub.64bit.stderr index 2cc3f8bdaac..7b263c20d33 100644 --- a/tests/ui/consts/const-eval/union-ub.64bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.64bit.stderr @@ -13,7 +13,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/union-ub.rs:35:36 | LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/unused-broken-const.stderr b/tests/ui/consts/const-eval/unused-broken-const.stderr index 74c713be4e4..5745539cb56 100644 --- a/tests/ui/consts/const-eval/unused-broken-const.stderr +++ b/tests/ui/consts/const-eval/unused-broken-const.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 0 but the index is 0 --> $DIR/unused-broken-const.rs:5:18 | LL | const FOO: i32 = [][0]; - | ^^^^^ evaluation of constant value failed + | ^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/unwind-abort.stderr b/tests/ui/consts/const-eval/unwind-abort.stderr index 5468b56ec05..94cf3acec45 100644 --- a/tests/ui/consts/const-eval/unwind-abort.stderr +++ b/tests/ui/consts/const-eval/unwind-abort.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/unwind-abort.rs:7:15 | LL | const _: () = foo(); - | ^^^^^ evaluation of constant value failed + | ^^^^^ evaluation of constant value failed here | note: inside `foo` --> $DIR/unwind-abort.rs:4:5 diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr index cb006127741..4557b392907 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr @@ -2,7 +2,7 @@ error[E0080]: constructing invalid value: encountered a value of the never type --> $DIR/validate_uninhabited_zsts.rs:17:33 | LL | const FOO: [empty::Empty; 3] = [foo(); 3]; - | ^^^^^ evaluation of constant value failed + | ^^^^^ evaluation of constant value failed here | note: inside `foo` --> $DIR/validate_uninhabited_zsts.rs:4:14 @@ -14,7 +14,7 @@ error[E0080]: constructing invalid value at .0: encountered a value of uninhabit --> $DIR/validate_uninhabited_zsts.rs:20:42 | LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr b/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr index 8456b04b306..08d791f4953 100644 --- a/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr +++ b/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr @@ -2,7 +2,7 @@ error[E0080]: `extern type` field does not have a known offset --> $DIR/validation-ice-extern-type-field.rs:12:1 | LL | const C1: &ThinDst = unsafe { std::mem::transmute(b"d".as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-external-macro-const-err.stderr b/tests/ui/consts/const-external-macro-const-err.stderr index c5374ae6b98..7cd646b1c45 100644 --- a/tests/ui/consts/const-external-macro-const-err.stderr +++ b/tests/ui/consts/const-external-macro-const-err.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 1 but the index is 1 --> $DIR/const-external-macro-const-err.rs:12:5 | LL | static_assert!(2 + 2 == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = note: this error originates in the macro `static_assert` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/const-int-unchecked.stderr b/tests/ui/consts/const-int-unchecked.stderr index 29c6c829777..20c109b9265 100644 --- a/tests/ui/consts/const-int-unchecked.stderr +++ b/tests/ui/consts/const-int-unchecked.stderr @@ -2,295 +2,295 @@ error[E0080]: overflowing shift by 8 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:14:29 | LL | const SHL_U8: u8 = unsafe { intrinsics::unchecked_shl(5_u8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 16 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:16:31 | LL | const SHL_U16: u16 = unsafe { intrinsics::unchecked_shl(5_u16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 32 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:18:31 | LL | const SHL_U32: u32 = unsafe { intrinsics::unchecked_shl(5_u32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 64 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:20:31 | LL | const SHL_U64: u64 = unsafe { intrinsics::unchecked_shl(5_u64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 128 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:22:33 | LL | const SHL_U128: u128 = unsafe { intrinsics::unchecked_shl(5_u128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 8 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:27:29 | LL | const SHL_I8: i8 = unsafe { intrinsics::unchecked_shl(5_i8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 16 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:29:31 | LL | const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_i16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 32 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:31:31 | LL | const SHL_I32: i32 = unsafe { intrinsics::unchecked_shl(5_i32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 64 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:33:31 | LL | const SHL_I64: i64 = unsafe { intrinsics::unchecked_shl(5_i64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 128 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:35:33 | LL | const SHL_I128: i128 = unsafe { intrinsics::unchecked_shl(5_i128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -1 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:40:33 | LL | const SHL_I8_NEG: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -1 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:42:35 | LL | const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -1 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:44:35 | LL | const SHL_I32_NEG: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -1 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:46:35 | LL | const SHL_I64_NEG: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -1 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:48:37 | LL | const SHL_I128_NEG: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -6 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:54:40 | LL | const SHL_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -6) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -13 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:56:42 | LL | const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -25 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:58:42 | LL | const SHL_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -25) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -30 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:60:42 | LL | const SHL_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -30) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -93 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:62:44 | LL | const SHL_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -93) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 8 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:69:29 | LL | const SHR_U8: u8 = unsafe { intrinsics::unchecked_shr(5_u8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 16 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:71:31 | LL | const SHR_U16: u16 = unsafe { intrinsics::unchecked_shr(5_u16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 32 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:73:31 | LL | const SHR_U32: u32 = unsafe { intrinsics::unchecked_shr(5_u32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 64 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:75:31 | LL | const SHR_U64: u64 = unsafe { intrinsics::unchecked_shr(5_u64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 128 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:77:33 | LL | const SHR_U128: u128 = unsafe { intrinsics::unchecked_shr(5_u128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 8 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:82:29 | LL | const SHR_I8: i8 = unsafe { intrinsics::unchecked_shr(5_i8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 16 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:84:31 | LL | const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_i16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 32 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:86:31 | LL | const SHR_I32: i32 = unsafe { intrinsics::unchecked_shr(5_i32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 64 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:88:31 | LL | const SHR_I64: i64 = unsafe { intrinsics::unchecked_shr(5_i64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by 128 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:90:33 | LL | const SHR_I128: i128 = unsafe { intrinsics::unchecked_shr(5_i128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -1 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:95:33 | LL | const SHR_I8_NEG: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -1 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:97:35 | LL | const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -1 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:99:35 | LL | const SHR_I32_NEG: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -1 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:101:35 | LL | const SHR_I64_NEG: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -1 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:103:37 | LL | const SHR_I128_NEG: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -6 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:109:40 | LL | const SHR_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -6) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -13 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:111:42 | LL | const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -25 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:113:42 | LL | const SHR_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -25) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -30 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:115:42 | LL | const SHR_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -30) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing shift by -93 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:117:44 | LL | const SHR_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -93) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: arithmetic overflow in `unchecked_add` --> $DIR/const-int-unchecked.rs:122:25 | LL | const _: u16 = unsafe { std::intrinsics::unchecked_add(40000u16, 30000) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: arithmetic overflow in `unchecked_sub` --> $DIR/const-int-unchecked.rs:125:25 | LL | const _: u32 = unsafe { std::intrinsics::unchecked_sub(14u32, 22) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: arithmetic overflow in `unchecked_mul` --> $DIR/const-int-unchecked.rs:128:25 | LL | const _: u16 = unsafe { std::intrinsics::unchecked_mul(300u16, 250u16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: dividing by zero --> $DIR/const-int-unchecked.rs:131:25 | LL | const _: i32 = unsafe { std::intrinsics::unchecked_div(1, 0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflow in signed division (dividing MIN by -1) --> $DIR/const-int-unchecked.rs:133:25 | LL | const _: i32 = unsafe { std::intrinsics::unchecked_div(i32::MIN, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: calculating the remainder with a divisor of zero --> $DIR/const-int-unchecked.rs:136:25 | LL | const _: i32 = unsafe { std::intrinsics::unchecked_rem(1, 0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflow in signed remainder (dividing MIN by -1) --> $DIR/const-int-unchecked.rs:138:25 | LL | const _: i32 = unsafe { std::intrinsics::unchecked_rem(i32::MIN, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: `ctlz_nonzero` called on 0 --> $DIR/const-int-unchecked.rs:143:25 | LL | const _: u32 = unsafe { std::intrinsics::ctlz_nonzero(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: `cttz_nonzero` called on 0 --> $DIR/const-int-unchecked.rs:145:25 | LL | const _: u32 = unsafe { std::intrinsics::cttz_nonzero(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 49 previous errors diff --git a/tests/ui/consts/const-len-underflow-separate-spans.next.stderr b/tests/ui/consts/const-len-underflow-separate-spans.next.stderr index ada8f703349..510b9cdc406 100644 --- a/tests/ui/consts/const-len-underflow-separate-spans.next.stderr +++ b/tests/ui/consts/const-len-underflow-separate-spans.next.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `1_usize - 2_usize`, which would overflow --> $DIR/const-len-underflow-separate-spans.rs:10:20 | LL | const LEN: usize = ONE - TWO; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here note: erroneous constant encountered --> $DIR/const-len-underflow-separate-spans.rs:15:17 diff --git a/tests/ui/consts/const-len-underflow-separate-spans.old.stderr b/tests/ui/consts/const-len-underflow-separate-spans.old.stderr index ada8f703349..510b9cdc406 100644 --- a/tests/ui/consts/const-len-underflow-separate-spans.old.stderr +++ b/tests/ui/consts/const-len-underflow-separate-spans.old.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `1_usize - 2_usize`, which would overflow --> $DIR/const-len-underflow-separate-spans.rs:10:20 | LL | const LEN: usize = ONE - TWO; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here note: erroneous constant encountered --> $DIR/const-len-underflow-separate-spans.rs:15:17 diff --git a/tests/ui/consts/const-len-underflow-subspans.stderr b/tests/ui/consts/const-len-underflow-subspans.stderr index b998c00135d..42d744147d6 100644 --- a/tests/ui/consts/const-len-underflow-subspans.stderr +++ b/tests/ui/consts/const-len-underflow-subspans.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `1_usize - 2_usize`, which would overflow --> $DIR/const-len-underflow-subspans.rs:8:17 | LL | let a: [i8; ONE - TWO] = unimplemented!(); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-ptr-is-null.stderr b/tests/ui/consts/const-ptr-is-null.stderr index 9969430bde8..9d83f8d51a7 100644 --- a/tests/ui/consts/const-ptr-is-null.stderr +++ b/tests/ui/consts/const-ptr-is-null.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: null-ness of this pointer cannot be determine --> $DIR/const-ptr-is-null.rs:22:14 | LL | assert!(!ptr.wrapping_sub(512).is_null()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `std::ptr::const_ptr::::is_null` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr index f85893783a4..714d85bb394 100644 --- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr +++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr @@ -2,13 +2,13 @@ error[E0080]: `extern type` does not have known layout --> $DIR/const-size_of_val-align_of_val-extern-type.rs:10:31 | LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: `extern type` does not have known layout --> $DIR/const-size_of_val-align_of_val-extern-type.rs:11:32 | LL | const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-slice-oob.stderr b/tests/ui/consts/const-slice-oob.stderr index 13d4a434608..d93c4783e27 100644 --- a/tests/ui/consts/const-slice-oob.stderr +++ b/tests/ui/consts/const-slice-oob.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 3 but the index is 5 --> $DIR/const-slice-oob.rs:2:18 | LL | const BAR: u32 = FOO[5]; - | ^^^^^^ evaluation of constant value failed + | ^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-unwrap.stderr b/tests/ui/consts/const-unwrap.stderr index 7b8cc1ca856..88c9185eeb6 100644 --- a/tests/ui/consts/const-unwrap.stderr +++ b/tests/ui/consts/const-unwrap.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation panicked: called `Option::unwrap()` on a `None` value --> $DIR/const-unwrap.rs:6:18 | LL | const BAR: i32 = Option::::None.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: absolutely not! --> $DIR/const-unwrap.rs:9:18 | LL | const BAZ: i32 = Option::::None.expect("absolutely not!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const_refs_to_static_fail.stderr b/tests/ui/consts/const_refs_to_static_fail.stderr index bd406941061..96a6593279d 100644 --- a/tests/ui/consts/const_refs_to_static_fail.stderr +++ b/tests/ui/consts/const_refs_to_static_fail.stderr @@ -19,7 +19,7 @@ error[E0080]: constant accesses mutable global memory --> $DIR/const_refs_to_static_fail.rs:18:13 | LL | assert!(*C2 == 0); - | ^^^ evaluation of constant value failed + | ^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const_unsafe_unreachable_ub.stderr b/tests/ui/consts/const_unsafe_unreachable_ub.stderr index 116c2198914..6d9f8c1d73b 100644 --- a/tests/ui/consts/const_unsafe_unreachable_ub.stderr +++ b/tests/ui/consts/const_unsafe_unreachable_ub.stderr @@ -2,7 +2,7 @@ error[E0080]: entering unreachable code --> $DIR/const_unsafe_unreachable_ub.rs:10:28 | LL | const BAR: bool = unsafe { foo(false) }; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here | note: inside `foo` --> $DIR/const_unsafe_unreachable_ub.rs:4:18 diff --git a/tests/ui/consts/control-flow/assert.stderr b/tests/ui/consts/control-flow/assert.stderr index 95b237959c1..6b68f706f90 100644 --- a/tests/ui/consts/control-flow/assert.stderr +++ b/tests/ui/consts/control-flow/assert.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: assertion failed: false --> $DIR/assert.rs:5:15 | LL | const _: () = assert!(false); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr index 8d3d2752f60..b9d89cf78ba 100644 --- a/tests/ui/consts/copy-intrinsic.stderr +++ b/tests/ui/consts/copy-intrinsic.stderr @@ -2,25 +2,25 @@ error[E0080]: memory access failed: attempting to access 4 bytes, but got 0x100[ --> $DIR/copy-intrinsic.rs:20:5 | LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes --> $DIR/copy-intrinsic.rs:28:5 | LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflow computing total size of `copy` --> $DIR/copy-intrinsic.rs:34:5 | LL | copy(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflow computing total size of `copy_nonoverlapping` --> $DIR/copy-intrinsic.rs:39:5 | LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 4 previous errors diff --git a/tests/ui/consts/eval-enum.stderr b/tests/ui/consts/eval-enum.stderr index eb55ad2a252..adfb7c79fea 100644 --- a/tests/ui/consts/eval-enum.stderr +++ b/tests/ui/consts/eval-enum.stderr @@ -2,13 +2,13 @@ error[E0080]: attempt to divide `1_isize` by zero --> $DIR/eval-enum.rs:2:15 | LL | DivZero = 1 / 0, - | ^^^^^ evaluation of constant value failed + | ^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero --> $DIR/eval-enum.rs:4:15 | LL | RemZero = 1 % 0, - | ^^^^^ evaluation of constant value failed + | ^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr index 74669d3d549..0d8fd5aece9 100644 --- a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr @@ -2,13 +2,13 @@ error[E0080]: constructing invalid value: encountered 0x03, but expected a boole --> $DIR/detect-extra-ub.rs:30:20 | LL | let _x: bool = transmute(3u8); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value: encountered a pointer, but expected an integer --> $DIR/detect-extra-ub.rs:35:21 | LL | let _x: usize = transmute(&3u8); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -17,7 +17,7 @@ error[E0080]: constructing invalid value at .: encountered a pointer, --> $DIR/detect-extra-ub.rs:40:28 | LL | let _x: PtrSizedEnum = transmute(&3u8); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .0: encountered a pointer, but expec --> $DIR/detect-extra-ub.rs:46:30 | LL | let _x: (usize, usize) = transmute(x); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -35,19 +35,19 @@ error[E0080]: constructing invalid value: encountered an unaligned reference (re --> $DIR/detect-extra-ub.rs:51:20 | LL | let _x: &u32 = transmute(&[0u8; 4]); - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant --> $DIR/detect-extra-ub.rs:58:13 | LL | let v = *addr_of!(data).cast::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value at [0]: encountered a partial pointer or a mix of pointers --> $DIR/detect-extra-ub.rs:77:16 | LL | let _val = *(&mem as *const Align as *const [*const u8; 2]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -56,7 +56,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata --> $DIR/detect-extra-ub.rs:91:16 | LL | let _val = &*slice; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error: aborting due to 8 previous errors diff --git a/tests/ui/consts/issue-32829.stderr b/tests/ui/consts/issue-32829.stderr index d10942d1e56..0a04c66df96 100644 --- a/tests/ui/consts/issue-32829.stderr +++ b/tests/ui/consts/issue-32829.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: foo --> $DIR/issue-32829.rs:1:22 | LL | static S : u64 = { { panic!("foo"); 0 } }; - | ^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^ evaluation of static initializer failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-64506.stderr b/tests/ui/consts/issue-64506.stderr index 22b8af9689d..dfb2c454031 100644 --- a/tests/ui/consts/issue-64506.stderr +++ b/tests/ui/consts/issue-64506.stderr @@ -2,7 +2,7 @@ error[E0080]: constructing invalid value at .inner: encountered a value of uninh --> $DIR/issue-64506.rs:16:22 | LL | let x = unsafe { Foo { b: () }.a }; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-66693-panic-in-array-len.stderr b/tests/ui/consts/issue-66693-panic-in-array-len.stderr index f475ab0c495..e0db2138d74 100644 --- a/tests/ui/consts/issue-66693-panic-in-array-len.stderr +++ b/tests/ui/consts/issue-66693-panic-in-array-len.stderr @@ -8,7 +8,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-66693-panic-in-array-len.rs:10:21 | LL | let _ = [false; panic!()]; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/issue-66693.stderr b/tests/ui/consts/issue-66693.stderr index 7035f5653c7..6d6edf8a513 100644 --- a/tests/ui/consts/issue-66693.stderr +++ b/tests/ui/consts/issue-66693.stderr @@ -14,13 +14,13 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-66693.rs:16:15 | LL | const _: () = panic!(); - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: evaluation panicked: panic in static --> $DIR/issue-66693.rs:18:19 | LL | static _BAR: () = panic!("panic in static"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error: argument to `panic!()` in a const context must have type `&str` --> $DIR/issue-66693.rs:11:5 diff --git a/tests/ui/consts/issue-76064.stderr b/tests/ui/consts/issue-76064.stderr index c748678d43a..97225178ee0 100644 --- a/tests/ui/consts/issue-76064.stderr +++ b/tests/ui/consts/issue-76064.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: panic --> $DIR/issue-76064.rs:1:17 | LL | struct Bug([u8; panic!("panic")]); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-miri-1910.stderr b/tests/ui/consts/issue-miri-1910.stderr index b541895dbcc..8166b68d2e0 100644 --- a/tests/ui/consts/issue-miri-1910.stderr +++ b/tests/ui/consts/issue-miri-1910.stderr @@ -2,7 +2,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/issue-miri-1910.rs:7:5 | LL | (&foo as *const _ as *const u8).add(one_and_a_half_pointers).read(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/large_const_alloc.stderr b/tests/ui/consts/large_const_alloc.stderr index a9ef87d6c83..8f19def22e7 100644 --- a/tests/ui/consts/large_const_alloc.stderr +++ b/tests/ui/consts/large_const_alloc.stderr @@ -2,13 +2,13 @@ error[E0080]: tried to allocate more memory than available to compiler --> $DIR/large_const_alloc.rs:11:13 | LL | let x = [0_u8; (1 << 47) - 1]; - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: tried to allocate more memory than available to compiler --> $DIR/large_const_alloc.rs:16:13 | LL | let x = [0_u8; (1 << 47) - 1]; - | ^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.rs b/tests/ui/consts/miri_unleashed/abi-mismatch.rs index d335991a5e6..91115f8511d 100644 --- a/tests/ui/consts/miri_unleashed/abi-mismatch.rs +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.rs @@ -9,7 +9,7 @@ const fn call_rust_fn(my_fn: extern "Rust" fn()) { } static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); -//~^ NOTE could not evaluate static initializer +//~^ NOTE evaluation of static initializer failed here //~| ERROR calling a function with calling convention "C" using calling convention "Rust" fn main() {} diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.stderr b/tests/ui/consts/miri_unleashed/abi-mismatch.stderr index d1efbad6fd4..6cd2a0b4bc5 100644 --- a/tests/ui/consts/miri_unleashed/abi-mismatch.stderr +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.stderr @@ -2,7 +2,7 @@ error[E0080]: calling a function with calling convention "C" using calling conve --> $DIR/abi-mismatch.rs:11:18 | LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here | note: inside `call_rust_fn` --> $DIR/abi-mismatch.rs:7:5 diff --git a/tests/ui/consts/miri_unleashed/assoc_const.stderr b/tests/ui/consts/miri_unleashed/assoc_const.stderr index 9176e2e12fb..b6dcb86f360 100644 --- a/tests/ui/consts/miri_unleashed/assoc_const.stderr +++ b/tests/ui/consts/miri_unleashed/assoc_const.stderr @@ -2,7 +2,7 @@ error[E0080]: calling non-const function ` as Drop>::drop` --> $DIR/assoc_const.rs:12:31 | LL | const F: u32 = (U::X, 42).1; - | ^ evaluation of `drop_in_place::> - shim(Some(Vec))` failed + | ^ evaluation of `drop_in_place::> - shim(Some(Vec))` failed here | note: inside `drop_in_place::<(Vec, u32)> - shim(Some((Vec, u32)))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/miri_unleashed/assoc_const_2.stderr b/tests/ui/consts/miri_unleashed/assoc_const_2.stderr index 54baa4a00ee..a38fe346da6 100644 --- a/tests/ui/consts/miri_unleashed/assoc_const_2.stderr +++ b/tests/ui/consts/miri_unleashed/assoc_const_2.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to divide `100_u32` by zero --> $DIR/assoc_const_2.rs:11:20 | LL | const F: u32 = 100 / U::X; - | ^^^^^^^^^^ evaluation of `>::F` failed + | ^^^^^^^^^^ evaluation of `>::F` failed here note: erroneous constant encountered --> $DIR/assoc_const_2.rs:28:13 diff --git a/tests/ui/consts/miri_unleashed/box.stderr b/tests/ui/consts/miri_unleashed/box.stderr index d5db5eca655..d6ceeebf87f 100644 --- a/tests/ui/consts/miri_unleashed/box.stderr +++ b/tests/ui/consts/miri_unleashed/box.stderr @@ -2,7 +2,7 @@ error[E0080]: calling non-const function `Box::::new` --> $DIR/box.rs:8:11 | LL | &mut *(Box::new(0)) - | ^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^ evaluation of static initializer failed here warning: skipping const checks | diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr index 7765210c277..f0161988b76 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr @@ -2,19 +2,19 @@ error[E0080]: calling non-const function `AtomicUsize::fetch_add` --> $DIR/const_refers_to_static.rs:11:5 | LL | FOO.fetch_add(1, Ordering::Relaxed) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constant accesses mutable global memory --> $DIR/const_refers_to_static.rs:16:14 | LL | unsafe { *(&FOO as *const _ as *const usize) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constant accesses mutable global memory --> $DIR/const_refers_to_static.rs:20:32 | LL | const READ_MUT: u32 = unsafe { MUTABLE }; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value: encountered reference to mutable memory in `const` --> $DIR/const_refers_to_static.rs:23:1 diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr index 32f8296e0fc..8c176d562ee 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr @@ -35,7 +35,7 @@ error[E0080]: constant accesses mutable global memory --> $DIR/const_refers_to_static_cross_crate.rs:30:15 | LL | match static_cross_crate::OPT_ZERO { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 4 previous errors diff --git a/tests/ui/consts/miri_unleashed/drop.rs b/tests/ui/consts/miri_unleashed/drop.rs index c3b944ce6f1..6921ffa4f94 100644 --- a/tests/ui/consts/miri_unleashed/drop.rs +++ b/tests/ui/consts/miri_unleashed/drop.rs @@ -13,7 +13,7 @@ static TEST_OK: () = { // The actual error is tested by the error-pattern above. static TEST_BAD: () = { let _v: Vec = Vec::new(); -}; //~ NOTE could not evaluate static initializer +}; //~ NOTE evaluation of static initializer failed here //~| ERROR calling non-const function ` as Drop>::drop` //~| NOTE inside `drop_in_place::> - shim(Some(Vec))` diff --git a/tests/ui/consts/miri_unleashed/drop.stderr b/tests/ui/consts/miri_unleashed/drop.stderr index e075781a15c..f0a776d8702 100644 --- a/tests/ui/consts/miri_unleashed/drop.stderr +++ b/tests/ui/consts/miri_unleashed/drop.stderr @@ -2,7 +2,7 @@ error[E0080]: calling non-const function ` as Drop>::drop` --> $DIR/drop.rs:16:1 | LL | }; - | ^ could not evaluate static initializer + | ^ evaluation of static initializer failed here | note: inside `drop_in_place::> - shim(Some(Vec))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/miri_unleashed/extern-static.stderr b/tests/ui/consts/miri_unleashed/extern-static.stderr index 44e15f71135..a1e4be5bd9c 100644 --- a/tests/ui/consts/miri_unleashed/extern-static.stderr +++ b/tests/ui/consts/miri_unleashed/extern-static.stderr @@ -2,13 +2,13 @@ error[E0080]: cannot access extern static `DATA` --> $DIR/extern-static.rs:11:25 | LL | unsafe { let _val = DATA; } - | ^^^^ could not evaluate static initializer + | ^^^^ evaluation of static initializer failed here error[E0080]: cannot access extern static `DATA` --> $DIR/extern-static.rs:15:14 | LL | unsafe { DATA = 0; } - | ^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^ evaluation of static initializer failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/miri_unleashed/inline_asm.stderr b/tests/ui/consts/miri_unleashed/inline_asm.stderr index df90d848432..2f9d2dc2143 100644 --- a/tests/ui/consts/miri_unleashed/inline_asm.stderr +++ b/tests/ui/consts/miri_unleashed/inline_asm.stderr @@ -2,7 +2,7 @@ error[E0080]: inline assembly is not supported --> $DIR/inline_asm.rs:10:14 | LL | unsafe { asm!("nop"); } - | ^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^ evaluation of static initializer failed here warning: skipping const checks | diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr index 3375cc9189a..aaea7bda332 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references.stderr @@ -113,7 +113,7 @@ error[E0080]: constant accesses mutable global memory --> $DIR/mutable_references.rs:70:43 | LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error: encountered mutable pointer in final value of constant --> $DIR/mutable_references.rs:73:1 diff --git a/tests/ui/consts/miri_unleashed/mutating_global.stderr b/tests/ui/consts/miri_unleashed/mutating_global.stderr index bbf82543387..706bc8e5d23 100644 --- a/tests/ui/consts/miri_unleashed/mutating_global.stderr +++ b/tests/ui/consts/miri_unleashed/mutating_global.stderr @@ -2,7 +2,7 @@ error[E0080]: modifying a static's initial value from another static's initializ --> $DIR/mutating_global.rs:9:9 | LL | GLOBAL = 99 - | ^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^ evaluation of static initializer failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/miri_unleashed/non_const_fn.stderr b/tests/ui/consts/miri_unleashed/non_const_fn.stderr index 54e3ed9361a..f490e51f546 100644 --- a/tests/ui/consts/miri_unleashed/non_const_fn.stderr +++ b/tests/ui/consts/miri_unleashed/non_const_fn.stderr @@ -2,7 +2,7 @@ error[E0080]: calling non-const function `foo` --> $DIR/non_const_fn.rs:7:16 | LL | static C: () = foo(); - | ^^^^^ could not evaluate static initializer + | ^^^^^ evaluation of static initializer failed here warning: skipping const checks | diff --git a/tests/ui/consts/miri_unleashed/ptr_arith.stderr b/tests/ui/consts/miri_unleashed/ptr_arith.stderr index 3092ab64795..280c76c42c1 100644 --- a/tests/ui/consts/miri_unleashed/ptr_arith.stderr +++ b/tests/ui/consts/miri_unleashed/ptr_arith.stderr @@ -2,13 +2,13 @@ error[E0080]: exposing pointers is not possible at compile-time --> $DIR/ptr_arith.rs:7:13 | LL | let x = &0 as *const _ as usize; - | ^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error[E0080]: unable to turn pointer into integer --> $DIR/ptr_arith.rs:14:14 | LL | let _v = x + 0; - | ^ could not evaluate static initializer + | ^ evaluation of static initializer failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/miri_unleashed/tls.stderr b/tests/ui/consts/miri_unleashed/tls.stderr index 68b6e0745f3..cdfe8bfff4e 100644 --- a/tests/ui/consts/miri_unleashed/tls.stderr +++ b/tests/ui/consts/miri_unleashed/tls.stderr @@ -2,13 +2,13 @@ error[E0080]: cannot access thread local static `A` --> $DIR/tls.rs:11:25 | LL | unsafe { let _val = A; } - | ^ could not evaluate static initializer + | ^ evaluation of static initializer failed here error[E0080]: cannot access thread local static `A` --> $DIR/tls.rs:19:26 | LL | unsafe { let _val = &A; } - | ^ could not evaluate static initializer + | ^ evaluation of static initializer failed here warning: skipping const checks | diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr index f2fc689078a..5ba5e34b4c1 100644 --- a/tests/ui/consts/missing_span_in_backtrace.stderr +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -6,7 +6,7 @@ error[E0080]: unable to copy parts of a pointer from memory at ALLOC0 16 | | &mut ptr2 as *mut _ as *mut MaybeUninit, 17 | | mem::size_of::<&i32>(), 18 | | ); - | |_________^ evaluation of constant value failed + | |_________^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/mono-reachable-invalid-const.stderr b/tests/ui/consts/mono-reachable-invalid-const.stderr index c0e18766023..e357fd096fd 100644 --- a/tests/ui/consts/mono-reachable-invalid-const.stderr +++ b/tests/ui/consts/mono-reachable-invalid-const.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 1 but the index is 1 --> $DIR/mono-reachable-invalid-const.rs:8:9 | LL | ["oops"][b]; - | ^^^^^^^^^^^ evaluation of `Bar::<0>::ASSERT` failed + | ^^^^^^^^^^^ evaluation of `Bar::<0>::ASSERT` failed here note: erroneous constant encountered --> $DIR/mono-reachable-invalid-const.rs:13:19 diff --git a/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr b/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr index ca40b347af8..318082f5452 100644 --- a/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr +++ b/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr @@ -2,7 +2,7 @@ error[E0080]: constant accesses mutable global memory --> $DIR/no-ice-from-static-in-const-issue-52060.rs:5:35 | LL | static B: [u32; 1] = [0; unsafe { A.len() }]; - | ^ evaluation of constant value failed + | ^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr index 134da19d81e..842698e239d 100644 --- a/tests/ui/consts/offset_from_ub.stderr +++ b/tests/ui/consts/offset_from_ub.stderr @@ -2,13 +2,13 @@ error[E0080]: `ptr_offset_from` called on two different pointers that are not bo --> $DIR/offset_from_ub.rs:20:27 | LL | let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation --> $DIR/offset_from_ub.rs:26:14 | LL | unsafe { (42 as *const u8).offset_from(&5u8) as usize } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -17,67 +17,67 @@ error[E0080]: exact_div: 1_isize cannot be divided by 2_isize without remainder --> $DIR/offset_from_ub.rs:34:14 | LL | unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation --> $DIR/offset_from_ub.rs:42:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation --> $DIR/offset_from_ub.rs:51:14 | LL | unsafe { ptr_offset_from(end_ptr, start_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation --> $DIR/offset_from_ub.rs:60:14 | LL | unsafe { ptr_offset_from(start_ptr, end_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation --> $DIR/offset_from_ub.rs:69:14 | LL | unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: `ptr_offset_from` called when first pointer is too far ahead of second --> $DIR/offset_from_ub.rs:76:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: `ptr_offset_from` called when first pointer is too far before second --> $DIR/offset_from_ub.rs:82:14 | LL | unsafe { ptr_offset_from(ptr1, ptr2) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: `ptr_offset_from` called when first pointer is too far before second --> $DIR/offset_from_ub.rs:90:14 | LL | unsafe { ptr_offset_from(ptr1, ptr2) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8 --> $DIR/offset_from_ub.rs:97:14 | LL | unsafe { ptr_offset_from_unsigned(p, p.add(2)) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: `ptr_offset_from_unsigned` called when first pointer is too far ahead of second --> $DIR/offset_from_ub.rs:104:14 | LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation --> $DIR/offset_from_ub.rs:112:14 | LL | unsafe { ptr2.offset_from(ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -86,7 +86,7 @@ error[E0080]: `ptr_offset_from` called when first pointer is too far before seco --> $DIR/offset_from_ub.rs:118:14 | LL | unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr index 86d43c80e66..4135804da20 100644 --- a/tests/ui/consts/offset_ub.stderr +++ b/tests/ui/consts/offset_ub.stderr @@ -2,67 +2,67 @@ error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer --> $DIR/offset_ub.rs:8:46 | LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got ALLOC1 which is only 1 byte from the end of the allocation --> $DIR/offset_ub.rs:9:43 | LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got ALLOC2 which is only $BYTES bytes from the end of the allocation --> $DIR/offset_ub.rs:10:45 | LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` --> $DIR/offset_ub.rs:12:43 | LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` --> $DIR/offset_ub.rs:13:44 | LL | pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/offset_ub.rs:14:56 | LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/offset_ub.rs:15:57 | LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which is only $BYTES bytes from the beginning of the allocation --> $DIR/offset_ub.rs:16:49 | LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes --> $DIR/offset_ub.rs:18:50 | LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/offset_ub.rs:19:42 | LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/offset_ub.rs:22:47 | LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 11 previous errors diff --git a/tests/ui/consts/overflowing-consts.noopt.stderr b/tests/ui/consts/overflowing-consts.noopt.stderr index 134ebad5c7b..e317060a141 100644 --- a/tests/ui/consts/overflowing-consts.noopt.stderr +++ b/tests/ui/consts/overflowing-consts.noopt.stderr @@ -2,1021 +2,1021 @@ error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:18:22 | LL | const _NI8_SHL: i8 = 1i8 << 8; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:19:26 | LL | const _NI8_SHL_P: &i8 = &(1i8 << 8); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:21:24 | LL | const _NI16_SHL: i16 = 1i16 << 16; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:22:28 | LL | const _NI16_SHL_P: &i16 = &(1i16 << 16); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:24:24 | LL | const _NI32_SHL: i32 = 1i32 << 32; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:25:28 | LL | const _NI32_SHL_P: &i32 = &(1i32 << 32); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:27:24 | LL | const _NI64_SHL: i64 = 1i64 << 64; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:28:28 | LL | const _NI64_SHL_P: &i64 = &(1i64 << 64); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:30:26 | LL | const _NI128_SHL: i128 = 1i128 << 128; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:31:30 | LL | const _NI128_SHL_P: &i128 = &(1i128 << 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:33:22 | LL | const _NU8_SHL: u8 = 1u8 << 8; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:34:26 | LL | const _NU8_SHL_P: &u8 = &(1u8 << 8); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:36:24 | LL | const _NU16_SHL: u16 = 1u16 << 16; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:37:28 | LL | const _NU16_SHL_P: &u16 = &(1u16 << 16); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:39:24 | LL | const _NU32_SHL: u32 = 1u32 << 32; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:40:28 | LL | const _NU32_SHL_P: &u32 = &(1u32 << 32); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:42:24 | LL | const _NU64_SHL: u64 = 1u64 << 64; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:43:28 | LL | const _NU64_SHL_P: &u64 = &(1u64 << 64); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:45:26 | LL | const _NU128_SHL: u128 = 1u128 << 128; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:46:30 | LL | const _NU128_SHL_P: &u128 = &(1u128 << 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:48:28 | LL | const _NISIZE_SHL: isize = 1isize << BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:49:32 | LL | const _NISIZE_SHL_P: &isize = &(1isize << BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:51:28 | LL | const _NUSIZE_SHL: usize = 1usize << BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:52:32 | LL | const _NUSIZE_SHL_P: &usize = &(1usize << BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:55:22 | LL | const _NI8_SHR: i8 = 1i8 >> 8; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:56:26 | LL | const _NI8_SHR_P: &i8 = &(1i8 >> 8); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:58:24 | LL | const _NI16_SHR: i16 = 1i16 >> 16; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:59:28 | LL | const _NI16_SHR_P: &i16 = &(1i16 >> 16); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:61:24 | LL | const _NI32_SHR: i32 = 1i32 >> 32; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:62:28 | LL | const _NI32_SHR_P: &i32 = &(1i32 >> 32); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:64:24 | LL | const _NI64_SHR: i64 = 1i64 >> 64; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:65:28 | LL | const _NI64_SHR_P: &i64 = &(1i64 >> 64); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:67:26 | LL | const _NI128_SHR: i128 = 1i128 >> 128; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:68:30 | LL | const _NI128_SHR_P: &i128 = &(1i128 >> 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:70:22 | LL | const _NU8_SHR: u8 = 1u8 >> 8; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:71:26 | LL | const _NU8_SHR_P: &u8 = &(1u8 >> 8); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:73:24 | LL | const _NU16_SHR: u16 = 1u16 >> 16; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:74:28 | LL | const _NU16_SHR_P: &u16 = &(1u16 >> 16); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:76:24 | LL | const _NU32_SHR: u32 = 1u32 >> 32; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:77:28 | LL | const _NU32_SHR_P: &u32 = &(1u32 >> 32); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:79:24 | LL | const _NU64_SHR: u64 = 1u64 >> 64; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:80:28 | LL | const _NU64_SHR_P: &u64 = &(1u64 >> 64); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:82:26 | LL | const _NU128_SHR: u128 = 1u128 >> 128; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:83:30 | LL | const _NU128_SHR_P: &u128 = &(1u128 >> 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:85:28 | LL | const _NISIZE_SHR: isize = 1isize >> BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:86:32 | LL | const _NISIZE_SHR_P: &isize = &(1isize >> BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:88:28 | LL | const _NUSIZE_SHR: usize = 1usize >> BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:89:32 | LL | const _NUSIZE_SHR_P: &usize = &(1usize >> BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:92:22 | LL | const _NI8_ADD: i8 = 1i8 + i8::MAX; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:93:26 | LL | const _NI8_ADD_P: &i8 = &(1i8 + i8::MAX); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:95:24 | LL | const _NI16_ADD: i16 = 1i16 + i16::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:96:28 | LL | const _NI16_ADD_P: &i16 = &(1i16 + i16::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:98:24 | LL | const _NI32_ADD: i32 = 1i32 + i32::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:99:28 | LL | const _NI32_ADD_P: &i32 = &(1i32 + i32::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:101:24 | LL | const _NI64_ADD: i64 = 1i64 + i64::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:102:28 | LL | const _NI64_ADD_P: &i64 = &(1i64 + i64::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:104:26 | LL | const _NI128_ADD: i128 = 1i128 + i128::MAX; - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:105:30 | LL | const _NI128_ADD_P: &i128 = &(1i128 + i128::MAX); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:107:22 | LL | const _NU8_ADD: u8 = 1u8 + u8::MAX; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:108:26 | LL | const _NU8_ADD_P: &u8 = &(1u8 + u8::MAX); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:110:24 | LL | const _NU16_ADD: u16 = 1u16 + u16::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:111:28 | LL | const _NU16_ADD_P: &u16 = &(1u16 + u16::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:113:24 | LL | const _NU32_ADD: u32 = 1u32 + u32::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:114:28 | LL | const _NU32_ADD_P: &u32 = &(1u32 + u32::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:116:24 | LL | const _NU64_ADD: u64 = 1u64 + u64::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:117:28 | LL | const _NU64_ADD_P: &u64 = &(1u64 + u64::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:119:26 | LL | const _NU128_ADD: u128 = 1u128 + u128::MAX; - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:120:30 | LL | const _NU128_ADD_P: &u128 = &(1u128 + u128::MAX); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:122:28 | LL | const _NISIZE_ADD: isize = 1isize + isize::MAX; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:123:32 | LL | const _NISIZE_ADD_P: &isize = &(1isize + isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:125:28 | LL | const _NUSIZE_ADD: usize = 1usize + usize::MAX; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:126:32 | LL | const _NUSIZE_ADD_P: &usize = &(1usize + usize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:129:22 | LL | const _NI8_SUB: i8 = -5i8 - i8::MAX; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:130:26 | LL | const _NI8_SUB_P: &i8 = &(-5i8 - i8::MAX); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:132:24 | LL | const _NI16_SUB: i16 = -5i16 - i16::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:133:28 | LL | const _NI16_SUB_P: &i16 = &(-5i16 - i16::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:135:24 | LL | const _NI32_SUB: i32 = -5i32 - i32::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:136:28 | LL | const _NI32_SUB_P: &i32 = &(-5i32 - i32::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:138:24 | LL | const _NI64_SUB: i64 = -5i64 - i64::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:139:28 | LL | const _NI64_SUB_P: &i64 = &(-5i64 - i64::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:141:26 | LL | const _NI128_SUB: i128 = -5i128 - i128::MAX; - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:142:30 | LL | const _NI128_SUB_P: &i128 = &(-5i128 - i128::MAX); - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:144:22 | LL | const _NU8_SUB: u8 = 1u8 - 5; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:145:26 | LL | const _NU8_SUB_P: &u8 = &(1u8 - 5); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:147:24 | LL | const _NU16_SUB: u16 = 1u16 - 5; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:148:28 | LL | const _NU16_SUB_P: &u16 = &(1u16 - 5); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:150:24 | LL | const _NU32_SUB: u32 = 1u32 - 5; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:151:28 | LL | const _NU32_SUB_P: &u32 = &(1u32 - 5); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:153:24 | LL | const _NU64_SUB: u64 = 1u64 - 5; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:154:28 | LL | const _NU64_SUB_P: &u64 = &(1u64 - 5); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:156:26 | LL | const _NU128_SUB: u128 = 1u128 - 5; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:157:30 | LL | const _NU128_SUB_P: &u128 = &(1u128 - 5); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:159:28 | LL | const _NISIZE_SUB: isize = -5isize - isize::MAX; - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:160:32 | LL | const _NISIZE_SUB_P: &isize = &(-5isize - isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:162:28 | LL | const _NUSIZE_SUB: usize = 1usize - 5; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:163:32 | LL | const _NUSIZE_SUB_P: &usize = &(1usize - 5); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow --> $DIR/overflowing-consts.rs:166:22 | LL | const _NI8_MUL: i8 = i8::MAX * 5; - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow --> $DIR/overflowing-consts.rs:167:26 | LL | const _NI8_MUL_P: &i8 = &(i8::MAX * 5); - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow --> $DIR/overflowing-consts.rs:169:24 | LL | const _NI16_MUL: i16 = i16::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow --> $DIR/overflowing-consts.rs:170:28 | LL | const _NI16_MUL_P: &i16 = &(i16::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow --> $DIR/overflowing-consts.rs:172:24 | LL | const _NI32_MUL: i32 = i32::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow --> $DIR/overflowing-consts.rs:173:28 | LL | const _NI32_MUL_P: &i32 = &(i32::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow --> $DIR/overflowing-consts.rs:175:24 | LL | const _NI64_MUL: i64 = i64::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow --> $DIR/overflowing-consts.rs:176:28 | LL | const _NI64_MUL_P: &i64 = &(i64::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow --> $DIR/overflowing-consts.rs:178:26 | LL | const _NI128_MUL: i128 = i128::MAX * 5; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow --> $DIR/overflowing-consts.rs:179:30 | LL | const _NI128_MUL_P: &i128 = &(i128::MAX * 5); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:181:22 | LL | const _NU8_MUL: u8 = u8::MAX * 5; - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:182:26 | LL | const _NU8_MUL_P: &u8 = &(u8::MAX * 5); - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:184:24 | LL | const _NU16_MUL: u16 = u16::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:185:28 | LL | const _NU16_MUL_P: &u16 = &(u16::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:187:24 | LL | const _NU32_MUL: u32 = u32::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:188:28 | LL | const _NU32_MUL_P: &u32 = &(u32::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:190:24 | LL | const _NU64_MUL: u64 = u64::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:191:28 | LL | const _NU64_MUL_P: &u64 = &(u64::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:193:26 | LL | const _NU128_MUL: u128 = u128::MAX * 5; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:194:30 | LL | const _NU128_MUL_P: &u128 = &(u128::MAX * 5); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow --> $DIR/overflowing-consts.rs:196:28 | LL | const _NISIZE_MUL: isize = isize::MAX * 5; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow --> $DIR/overflowing-consts.rs:197:32 | LL | const _NISIZE_MUL_P: &isize = &(isize::MAX * 5); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:199:28 | LL | const _NUSIZE_MUL: usize = usize::MAX * 5; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:200:32 | LL | const _NUSIZE_MUL_P: &usize = &(usize::MAX * 5); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i8` by zero --> $DIR/overflowing-consts.rs:203:22 | LL | const _NI8_DIV: i8 = 1i8 / 0; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i8` by zero --> $DIR/overflowing-consts.rs:204:26 | LL | const _NI8_DIV_P: &i8 = &(1i8 / 0); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i16` by zero --> $DIR/overflowing-consts.rs:206:24 | LL | const _NI16_DIV: i16 = 1i16 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i16` by zero --> $DIR/overflowing-consts.rs:207:28 | LL | const _NI16_DIV_P: &i16 = &(1i16 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i32` by zero --> $DIR/overflowing-consts.rs:209:24 | LL | const _NI32_DIV: i32 = 1i32 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i32` by zero --> $DIR/overflowing-consts.rs:210:28 | LL | const _NI32_DIV_P: &i32 = &(1i32 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i64` by zero --> $DIR/overflowing-consts.rs:212:24 | LL | const _NI64_DIV: i64 = 1i64 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i64` by zero --> $DIR/overflowing-consts.rs:213:28 | LL | const _NI64_DIV_P: &i64 = &(1i64 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i128` by zero --> $DIR/overflowing-consts.rs:215:26 | LL | const _NI128_DIV: i128 = 1i128 / 0; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i128` by zero --> $DIR/overflowing-consts.rs:216:30 | LL | const _NI128_DIV_P: &i128 = &(1i128 / 0); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u8` by zero --> $DIR/overflowing-consts.rs:218:22 | LL | const _NU8_DIV: u8 = 1u8 / 0; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u8` by zero --> $DIR/overflowing-consts.rs:219:26 | LL | const _NU8_DIV_P: &u8 = &(1u8 / 0); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u16` by zero --> $DIR/overflowing-consts.rs:221:24 | LL | const _NU16_DIV: u16 = 1u16 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u16` by zero --> $DIR/overflowing-consts.rs:222:28 | LL | const _NU16_DIV_P: &u16 = &(1u16 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u32` by zero --> $DIR/overflowing-consts.rs:224:24 | LL | const _NU32_DIV: u32 = 1u32 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u32` by zero --> $DIR/overflowing-consts.rs:225:28 | LL | const _NU32_DIV_P: &u32 = &(1u32 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u64` by zero --> $DIR/overflowing-consts.rs:227:24 | LL | const _NU64_DIV: u64 = 1u64 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u64` by zero --> $DIR/overflowing-consts.rs:228:28 | LL | const _NU64_DIV_P: &u64 = &(1u64 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u128` by zero --> $DIR/overflowing-consts.rs:230:26 | LL | const _NU128_DIV: u128 = 1u128 / 0; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u128` by zero --> $DIR/overflowing-consts.rs:231:30 | LL | const _NU128_DIV_P: &u128 = &(1u128 / 0); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_isize` by zero --> $DIR/overflowing-consts.rs:233:28 | LL | const _NISIZE_DIV: isize = 1isize / 0; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_isize` by zero --> $DIR/overflowing-consts.rs:234:32 | LL | const _NISIZE_DIV_P: &isize = &(1isize / 0); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_usize` by zero --> $DIR/overflowing-consts.rs:236:28 | LL | const _NUSIZE_DIV: usize = 1usize / 0; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_usize` by zero --> $DIR/overflowing-consts.rs:237:32 | LL | const _NUSIZE_DIV_P: &usize = &(1usize / 0); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero --> $DIR/overflowing-consts.rs:240:22 | LL | const _NI8_MOD: i8 = 1i8 % 0; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero --> $DIR/overflowing-consts.rs:241:26 | LL | const _NI8_MOD_P: &i8 = &(1i8 % 0); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero --> $DIR/overflowing-consts.rs:243:24 | LL | const _NI16_MOD: i16 = 1i16 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero --> $DIR/overflowing-consts.rs:244:28 | LL | const _NI16_MOD_P: &i16 = &(1i16 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero --> $DIR/overflowing-consts.rs:246:24 | LL | const _NI32_MOD: i32 = 1i32 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero --> $DIR/overflowing-consts.rs:247:28 | LL | const _NI32_MOD_P: &i32 = &(1i32 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero --> $DIR/overflowing-consts.rs:249:24 | LL | const _NI64_MOD: i64 = 1i64 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero --> $DIR/overflowing-consts.rs:250:28 | LL | const _NI64_MOD_P: &i64 = &(1i64 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero --> $DIR/overflowing-consts.rs:252:26 | LL | const _NI128_MOD: i128 = 1i128 % 0; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero --> $DIR/overflowing-consts.rs:253:30 | LL | const _NI128_MOD_P: &i128 = &(1i128 % 0); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero --> $DIR/overflowing-consts.rs:255:22 | LL | const _NU8_MOD: u8 = 1u8 % 0; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero --> $DIR/overflowing-consts.rs:256:26 | LL | const _NU8_MOD_P: &u8 = &(1u8 % 0); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero --> $DIR/overflowing-consts.rs:258:24 | LL | const _NU16_MOD: u16 = 1u16 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero --> $DIR/overflowing-consts.rs:259:28 | LL | const _NU16_MOD_P: &u16 = &(1u16 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero --> $DIR/overflowing-consts.rs:261:24 | LL | const _NU32_MOD: u32 = 1u32 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero --> $DIR/overflowing-consts.rs:262:28 | LL | const _NU32_MOD_P: &u32 = &(1u32 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero --> $DIR/overflowing-consts.rs:264:24 | LL | const _NU64_MOD: u64 = 1u64 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero --> $DIR/overflowing-consts.rs:265:28 | LL | const _NU64_MOD_P: &u64 = &(1u64 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero --> $DIR/overflowing-consts.rs:267:26 | LL | const _NU128_MOD: u128 = 1u128 % 0; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero --> $DIR/overflowing-consts.rs:268:30 | LL | const _NU128_MOD_P: &u128 = &(1u128 % 0); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero --> $DIR/overflowing-consts.rs:270:28 | LL | const _NISIZE_MOD: isize = 1isize % 0; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero --> $DIR/overflowing-consts.rs:271:32 | LL | const _NISIZE_MOD_P: &isize = &(1isize % 0); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero --> $DIR/overflowing-consts.rs:273:28 | LL | const _NUSIZE_MOD: usize = 1usize % 0; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero --> $DIR/overflowing-consts.rs:274:32 | LL | const _NUSIZE_MOD_P: &usize = &(1usize % 0); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: index out of bounds: the length is 3 but the index is 4 --> $DIR/overflowing-consts.rs:277:24 | LL | const _NI32_OOB: i32 = [1, 2, 3][4]; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: index out of bounds: the length is 3 but the index is 4 --> $DIR/overflowing-consts.rs:278:28 | LL | const _NI32_OOB_P: &i32 = &([1, 2, 3][4]); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 170 previous errors diff --git a/tests/ui/consts/overflowing-consts.opt.stderr b/tests/ui/consts/overflowing-consts.opt.stderr index 134ebad5c7b..e317060a141 100644 --- a/tests/ui/consts/overflowing-consts.opt.stderr +++ b/tests/ui/consts/overflowing-consts.opt.stderr @@ -2,1021 +2,1021 @@ error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:18:22 | LL | const _NI8_SHL: i8 = 1i8 << 8; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:19:26 | LL | const _NI8_SHL_P: &i8 = &(1i8 << 8); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:21:24 | LL | const _NI16_SHL: i16 = 1i16 << 16; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:22:28 | LL | const _NI16_SHL_P: &i16 = &(1i16 << 16); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:24:24 | LL | const _NI32_SHL: i32 = 1i32 << 32; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:25:28 | LL | const _NI32_SHL_P: &i32 = &(1i32 << 32); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:27:24 | LL | const _NI64_SHL: i64 = 1i64 << 64; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:28:28 | LL | const _NI64_SHL_P: &i64 = &(1i64 << 64); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:30:26 | LL | const _NI128_SHL: i128 = 1i128 << 128; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:31:30 | LL | const _NI128_SHL_P: &i128 = &(1i128 << 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:33:22 | LL | const _NU8_SHL: u8 = 1u8 << 8; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:34:26 | LL | const _NU8_SHL_P: &u8 = &(1u8 << 8); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:36:24 | LL | const _NU16_SHL: u16 = 1u16 << 16; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:37:28 | LL | const _NU16_SHL_P: &u16 = &(1u16 << 16); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:39:24 | LL | const _NU32_SHL: u32 = 1u32 << 32; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:40:28 | LL | const _NU32_SHL_P: &u32 = &(1u32 << 32); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:42:24 | LL | const _NU64_SHL: u64 = 1u64 << 64; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:43:28 | LL | const _NU64_SHL_P: &u64 = &(1u64 << 64); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:45:26 | LL | const _NU128_SHL: u128 = 1u128 << 128; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:46:30 | LL | const _NU128_SHL_P: &u128 = &(1u128 << 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:48:28 | LL | const _NISIZE_SHL: isize = 1isize << BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:49:32 | LL | const _NISIZE_SHL_P: &isize = &(1isize << BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:51:28 | LL | const _NUSIZE_SHL: usize = 1usize << BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:52:32 | LL | const _NUSIZE_SHL_P: &usize = &(1usize << BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:55:22 | LL | const _NI8_SHR: i8 = 1i8 >> 8; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:56:26 | LL | const _NI8_SHR_P: &i8 = &(1i8 >> 8); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:58:24 | LL | const _NI16_SHR: i16 = 1i16 >> 16; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:59:28 | LL | const _NI16_SHR_P: &i16 = &(1i16 >> 16); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:61:24 | LL | const _NI32_SHR: i32 = 1i32 >> 32; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:62:28 | LL | const _NI32_SHR_P: &i32 = &(1i32 >> 32); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:64:24 | LL | const _NI64_SHR: i64 = 1i64 >> 64; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:65:28 | LL | const _NI64_SHR_P: &i64 = &(1i64 >> 64); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:67:26 | LL | const _NI128_SHR: i128 = 1i128 >> 128; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:68:30 | LL | const _NI128_SHR_P: &i128 = &(1i128 >> 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:70:22 | LL | const _NU8_SHR: u8 = 1u8 >> 8; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:71:26 | LL | const _NU8_SHR_P: &u8 = &(1u8 >> 8); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:73:24 | LL | const _NU16_SHR: u16 = 1u16 >> 16; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:74:28 | LL | const _NU16_SHR_P: &u16 = &(1u16 >> 16); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:76:24 | LL | const _NU32_SHR: u32 = 1u32 >> 32; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:77:28 | LL | const _NU32_SHR_P: &u32 = &(1u32 >> 32); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:79:24 | LL | const _NU64_SHR: u64 = 1u64 >> 64; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:80:28 | LL | const _NU64_SHR_P: &u64 = &(1u64 >> 64); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:82:26 | LL | const _NU128_SHR: u128 = 1u128 >> 128; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:83:30 | LL | const _NU128_SHR_P: &u128 = &(1u128 >> 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:85:28 | LL | const _NISIZE_SHR: isize = 1isize >> BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:86:32 | LL | const _NISIZE_SHR_P: &isize = &(1isize >> BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:88:28 | LL | const _NUSIZE_SHR: usize = 1usize >> BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:89:32 | LL | const _NUSIZE_SHR_P: &usize = &(1usize >> BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:92:22 | LL | const _NI8_ADD: i8 = 1i8 + i8::MAX; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:93:26 | LL | const _NI8_ADD_P: &i8 = &(1i8 + i8::MAX); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:95:24 | LL | const _NI16_ADD: i16 = 1i16 + i16::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:96:28 | LL | const _NI16_ADD_P: &i16 = &(1i16 + i16::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:98:24 | LL | const _NI32_ADD: i32 = 1i32 + i32::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:99:28 | LL | const _NI32_ADD_P: &i32 = &(1i32 + i32::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:101:24 | LL | const _NI64_ADD: i64 = 1i64 + i64::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:102:28 | LL | const _NI64_ADD_P: &i64 = &(1i64 + i64::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:104:26 | LL | const _NI128_ADD: i128 = 1i128 + i128::MAX; - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:105:30 | LL | const _NI128_ADD_P: &i128 = &(1i128 + i128::MAX); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:107:22 | LL | const _NU8_ADD: u8 = 1u8 + u8::MAX; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:108:26 | LL | const _NU8_ADD_P: &u8 = &(1u8 + u8::MAX); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:110:24 | LL | const _NU16_ADD: u16 = 1u16 + u16::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:111:28 | LL | const _NU16_ADD_P: &u16 = &(1u16 + u16::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:113:24 | LL | const _NU32_ADD: u32 = 1u32 + u32::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:114:28 | LL | const _NU32_ADD_P: &u32 = &(1u32 + u32::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:116:24 | LL | const _NU64_ADD: u64 = 1u64 + u64::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:117:28 | LL | const _NU64_ADD_P: &u64 = &(1u64 + u64::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:119:26 | LL | const _NU128_ADD: u128 = 1u128 + u128::MAX; - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:120:30 | LL | const _NU128_ADD_P: &u128 = &(1u128 + u128::MAX); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:122:28 | LL | const _NISIZE_ADD: isize = 1isize + isize::MAX; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:123:32 | LL | const _NISIZE_ADD_P: &isize = &(1isize + isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:125:28 | LL | const _NUSIZE_ADD: usize = 1usize + usize::MAX; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:126:32 | LL | const _NUSIZE_ADD_P: &usize = &(1usize + usize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:129:22 | LL | const _NI8_SUB: i8 = -5i8 - i8::MAX; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:130:26 | LL | const _NI8_SUB_P: &i8 = &(-5i8 - i8::MAX); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:132:24 | LL | const _NI16_SUB: i16 = -5i16 - i16::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:133:28 | LL | const _NI16_SUB_P: &i16 = &(-5i16 - i16::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:135:24 | LL | const _NI32_SUB: i32 = -5i32 - i32::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:136:28 | LL | const _NI32_SUB_P: &i32 = &(-5i32 - i32::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:138:24 | LL | const _NI64_SUB: i64 = -5i64 - i64::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:139:28 | LL | const _NI64_SUB_P: &i64 = &(-5i64 - i64::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:141:26 | LL | const _NI128_SUB: i128 = -5i128 - i128::MAX; - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:142:30 | LL | const _NI128_SUB_P: &i128 = &(-5i128 - i128::MAX); - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:144:22 | LL | const _NU8_SUB: u8 = 1u8 - 5; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:145:26 | LL | const _NU8_SUB_P: &u8 = &(1u8 - 5); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:147:24 | LL | const _NU16_SUB: u16 = 1u16 - 5; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:148:28 | LL | const _NU16_SUB_P: &u16 = &(1u16 - 5); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:150:24 | LL | const _NU32_SUB: u32 = 1u32 - 5; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:151:28 | LL | const _NU32_SUB_P: &u32 = &(1u32 - 5); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:153:24 | LL | const _NU64_SUB: u64 = 1u64 - 5; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:154:28 | LL | const _NU64_SUB_P: &u64 = &(1u64 - 5); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:156:26 | LL | const _NU128_SUB: u128 = 1u128 - 5; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:157:30 | LL | const _NU128_SUB_P: &u128 = &(1u128 - 5); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:159:28 | LL | const _NISIZE_SUB: isize = -5isize - isize::MAX; - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:160:32 | LL | const _NISIZE_SUB_P: &isize = &(-5isize - isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:162:28 | LL | const _NUSIZE_SUB: usize = 1usize - 5; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:163:32 | LL | const _NUSIZE_SUB_P: &usize = &(1usize - 5); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow --> $DIR/overflowing-consts.rs:166:22 | LL | const _NI8_MUL: i8 = i8::MAX * 5; - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow --> $DIR/overflowing-consts.rs:167:26 | LL | const _NI8_MUL_P: &i8 = &(i8::MAX * 5); - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow --> $DIR/overflowing-consts.rs:169:24 | LL | const _NI16_MUL: i16 = i16::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow --> $DIR/overflowing-consts.rs:170:28 | LL | const _NI16_MUL_P: &i16 = &(i16::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow --> $DIR/overflowing-consts.rs:172:24 | LL | const _NI32_MUL: i32 = i32::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow --> $DIR/overflowing-consts.rs:173:28 | LL | const _NI32_MUL_P: &i32 = &(i32::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow --> $DIR/overflowing-consts.rs:175:24 | LL | const _NI64_MUL: i64 = i64::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow --> $DIR/overflowing-consts.rs:176:28 | LL | const _NI64_MUL_P: &i64 = &(i64::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow --> $DIR/overflowing-consts.rs:178:26 | LL | const _NI128_MUL: i128 = i128::MAX * 5; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow --> $DIR/overflowing-consts.rs:179:30 | LL | const _NI128_MUL_P: &i128 = &(i128::MAX * 5); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:181:22 | LL | const _NU8_MUL: u8 = u8::MAX * 5; - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:182:26 | LL | const _NU8_MUL_P: &u8 = &(u8::MAX * 5); - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:184:24 | LL | const _NU16_MUL: u16 = u16::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:185:28 | LL | const _NU16_MUL_P: &u16 = &(u16::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:187:24 | LL | const _NU32_MUL: u32 = u32::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:188:28 | LL | const _NU32_MUL_P: &u32 = &(u32::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:190:24 | LL | const _NU64_MUL: u64 = u64::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:191:28 | LL | const _NU64_MUL_P: &u64 = &(u64::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:193:26 | LL | const _NU128_MUL: u128 = u128::MAX * 5; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:194:30 | LL | const _NU128_MUL_P: &u128 = &(u128::MAX * 5); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow --> $DIR/overflowing-consts.rs:196:28 | LL | const _NISIZE_MUL: isize = isize::MAX * 5; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow --> $DIR/overflowing-consts.rs:197:32 | LL | const _NISIZE_MUL_P: &isize = &(isize::MAX * 5); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:199:28 | LL | const _NUSIZE_MUL: usize = usize::MAX * 5; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:200:32 | LL | const _NUSIZE_MUL_P: &usize = &(usize::MAX * 5); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i8` by zero --> $DIR/overflowing-consts.rs:203:22 | LL | const _NI8_DIV: i8 = 1i8 / 0; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i8` by zero --> $DIR/overflowing-consts.rs:204:26 | LL | const _NI8_DIV_P: &i8 = &(1i8 / 0); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i16` by zero --> $DIR/overflowing-consts.rs:206:24 | LL | const _NI16_DIV: i16 = 1i16 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i16` by zero --> $DIR/overflowing-consts.rs:207:28 | LL | const _NI16_DIV_P: &i16 = &(1i16 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i32` by zero --> $DIR/overflowing-consts.rs:209:24 | LL | const _NI32_DIV: i32 = 1i32 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i32` by zero --> $DIR/overflowing-consts.rs:210:28 | LL | const _NI32_DIV_P: &i32 = &(1i32 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i64` by zero --> $DIR/overflowing-consts.rs:212:24 | LL | const _NI64_DIV: i64 = 1i64 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i64` by zero --> $DIR/overflowing-consts.rs:213:28 | LL | const _NI64_DIV_P: &i64 = &(1i64 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i128` by zero --> $DIR/overflowing-consts.rs:215:26 | LL | const _NI128_DIV: i128 = 1i128 / 0; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i128` by zero --> $DIR/overflowing-consts.rs:216:30 | LL | const _NI128_DIV_P: &i128 = &(1i128 / 0); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u8` by zero --> $DIR/overflowing-consts.rs:218:22 | LL | const _NU8_DIV: u8 = 1u8 / 0; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u8` by zero --> $DIR/overflowing-consts.rs:219:26 | LL | const _NU8_DIV_P: &u8 = &(1u8 / 0); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u16` by zero --> $DIR/overflowing-consts.rs:221:24 | LL | const _NU16_DIV: u16 = 1u16 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u16` by zero --> $DIR/overflowing-consts.rs:222:28 | LL | const _NU16_DIV_P: &u16 = &(1u16 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u32` by zero --> $DIR/overflowing-consts.rs:224:24 | LL | const _NU32_DIV: u32 = 1u32 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u32` by zero --> $DIR/overflowing-consts.rs:225:28 | LL | const _NU32_DIV_P: &u32 = &(1u32 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u64` by zero --> $DIR/overflowing-consts.rs:227:24 | LL | const _NU64_DIV: u64 = 1u64 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u64` by zero --> $DIR/overflowing-consts.rs:228:28 | LL | const _NU64_DIV_P: &u64 = &(1u64 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u128` by zero --> $DIR/overflowing-consts.rs:230:26 | LL | const _NU128_DIV: u128 = 1u128 / 0; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u128` by zero --> $DIR/overflowing-consts.rs:231:30 | LL | const _NU128_DIV_P: &u128 = &(1u128 / 0); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_isize` by zero --> $DIR/overflowing-consts.rs:233:28 | LL | const _NISIZE_DIV: isize = 1isize / 0; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_isize` by zero --> $DIR/overflowing-consts.rs:234:32 | LL | const _NISIZE_DIV_P: &isize = &(1isize / 0); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_usize` by zero --> $DIR/overflowing-consts.rs:236:28 | LL | const _NUSIZE_DIV: usize = 1usize / 0; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_usize` by zero --> $DIR/overflowing-consts.rs:237:32 | LL | const _NUSIZE_DIV_P: &usize = &(1usize / 0); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero --> $DIR/overflowing-consts.rs:240:22 | LL | const _NI8_MOD: i8 = 1i8 % 0; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero --> $DIR/overflowing-consts.rs:241:26 | LL | const _NI8_MOD_P: &i8 = &(1i8 % 0); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero --> $DIR/overflowing-consts.rs:243:24 | LL | const _NI16_MOD: i16 = 1i16 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero --> $DIR/overflowing-consts.rs:244:28 | LL | const _NI16_MOD_P: &i16 = &(1i16 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero --> $DIR/overflowing-consts.rs:246:24 | LL | const _NI32_MOD: i32 = 1i32 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero --> $DIR/overflowing-consts.rs:247:28 | LL | const _NI32_MOD_P: &i32 = &(1i32 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero --> $DIR/overflowing-consts.rs:249:24 | LL | const _NI64_MOD: i64 = 1i64 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero --> $DIR/overflowing-consts.rs:250:28 | LL | const _NI64_MOD_P: &i64 = &(1i64 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero --> $DIR/overflowing-consts.rs:252:26 | LL | const _NI128_MOD: i128 = 1i128 % 0; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero --> $DIR/overflowing-consts.rs:253:30 | LL | const _NI128_MOD_P: &i128 = &(1i128 % 0); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero --> $DIR/overflowing-consts.rs:255:22 | LL | const _NU8_MOD: u8 = 1u8 % 0; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero --> $DIR/overflowing-consts.rs:256:26 | LL | const _NU8_MOD_P: &u8 = &(1u8 % 0); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero --> $DIR/overflowing-consts.rs:258:24 | LL | const _NU16_MOD: u16 = 1u16 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero --> $DIR/overflowing-consts.rs:259:28 | LL | const _NU16_MOD_P: &u16 = &(1u16 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero --> $DIR/overflowing-consts.rs:261:24 | LL | const _NU32_MOD: u32 = 1u32 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero --> $DIR/overflowing-consts.rs:262:28 | LL | const _NU32_MOD_P: &u32 = &(1u32 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero --> $DIR/overflowing-consts.rs:264:24 | LL | const _NU64_MOD: u64 = 1u64 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero --> $DIR/overflowing-consts.rs:265:28 | LL | const _NU64_MOD_P: &u64 = &(1u64 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero --> $DIR/overflowing-consts.rs:267:26 | LL | const _NU128_MOD: u128 = 1u128 % 0; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero --> $DIR/overflowing-consts.rs:268:30 | LL | const _NU128_MOD_P: &u128 = &(1u128 % 0); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero --> $DIR/overflowing-consts.rs:270:28 | LL | const _NISIZE_MOD: isize = 1isize % 0; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero --> $DIR/overflowing-consts.rs:271:32 | LL | const _NISIZE_MOD_P: &isize = &(1isize % 0); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero --> $DIR/overflowing-consts.rs:273:28 | LL | const _NUSIZE_MOD: usize = 1usize % 0; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero --> $DIR/overflowing-consts.rs:274:32 | LL | const _NUSIZE_MOD_P: &usize = &(1usize % 0); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: index out of bounds: the length is 3 but the index is 4 --> $DIR/overflowing-consts.rs:277:24 | LL | const _NI32_OOB: i32 = [1, 2, 3][4]; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: index out of bounds: the length is 3 but the index is 4 --> $DIR/overflowing-consts.rs:278:28 | LL | const _NI32_OOB_P: &i32 = &([1, 2, 3][4]); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 170 previous errors diff --git a/tests/ui/consts/overflowing-consts.opt_with_overflow_checks.stderr b/tests/ui/consts/overflowing-consts.opt_with_overflow_checks.stderr index 134ebad5c7b..e317060a141 100644 --- a/tests/ui/consts/overflowing-consts.opt_with_overflow_checks.stderr +++ b/tests/ui/consts/overflowing-consts.opt_with_overflow_checks.stderr @@ -2,1021 +2,1021 @@ error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:18:22 | LL | const _NI8_SHL: i8 = 1i8 << 8; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:19:26 | LL | const _NI8_SHL_P: &i8 = &(1i8 << 8); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:21:24 | LL | const _NI16_SHL: i16 = 1i16 << 16; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:22:28 | LL | const _NI16_SHL_P: &i16 = &(1i16 << 16); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:24:24 | LL | const _NI32_SHL: i32 = 1i32 << 32; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:25:28 | LL | const _NI32_SHL_P: &i32 = &(1i32 << 32); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:27:24 | LL | const _NI64_SHL: i64 = 1i64 << 64; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:28:28 | LL | const _NI64_SHL_P: &i64 = &(1i64 << 64); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:30:26 | LL | const _NI128_SHL: i128 = 1i128 << 128; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:31:30 | LL | const _NI128_SHL_P: &i128 = &(1i128 << 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:33:22 | LL | const _NU8_SHL: u8 = 1u8 << 8; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:34:26 | LL | const _NU8_SHL_P: &u8 = &(1u8 << 8); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:36:24 | LL | const _NU16_SHL: u16 = 1u16 << 16; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:37:28 | LL | const _NU16_SHL_P: &u16 = &(1u16 << 16); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:39:24 | LL | const _NU32_SHL: u32 = 1u32 << 32; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:40:28 | LL | const _NU32_SHL_P: &u32 = &(1u32 << 32); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:42:24 | LL | const _NU64_SHL: u64 = 1u64 << 64; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:43:28 | LL | const _NU64_SHL_P: &u64 = &(1u64 << 64); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:45:26 | LL | const _NU128_SHL: u128 = 1u128 << 128; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:46:30 | LL | const _NU128_SHL_P: &u128 = &(1u128 << 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:48:28 | LL | const _NISIZE_SHL: isize = 1isize << BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:49:32 | LL | const _NISIZE_SHL_P: &isize = &(1isize << BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:51:28 | LL | const _NUSIZE_SHL: usize = 1usize << BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:52:32 | LL | const _NUSIZE_SHL_P: &usize = &(1usize << BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:55:22 | LL | const _NI8_SHR: i8 = 1i8 >> 8; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:56:26 | LL | const _NI8_SHR_P: &i8 = &(1i8 >> 8); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:58:24 | LL | const _NI16_SHR: i16 = 1i16 >> 16; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:59:28 | LL | const _NI16_SHR_P: &i16 = &(1i16 >> 16); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:61:24 | LL | const _NI32_SHR: i32 = 1i32 >> 32; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:62:28 | LL | const _NI32_SHR_P: &i32 = &(1i32 >> 32); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:64:24 | LL | const _NI64_SHR: i64 = 1i64 >> 64; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:65:28 | LL | const _NI64_SHR_P: &i64 = &(1i64 >> 64); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:67:26 | LL | const _NI128_SHR: i128 = 1i128 >> 128; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:68:30 | LL | const _NI128_SHR_P: &i128 = &(1i128 >> 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:70:22 | LL | const _NU8_SHR: u8 = 1u8 >> 8; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:71:26 | LL | const _NU8_SHR_P: &u8 = &(1u8 >> 8); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:73:24 | LL | const _NU16_SHR: u16 = 1u16 >> 16; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:74:28 | LL | const _NU16_SHR_P: &u16 = &(1u16 >> 16); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:76:24 | LL | const _NU32_SHR: u32 = 1u32 >> 32; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:77:28 | LL | const _NU32_SHR_P: &u32 = &(1u32 >> 32); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:79:24 | LL | const _NU64_SHR: u64 = 1u64 >> 64; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:80:28 | LL | const _NU64_SHR_P: &u64 = &(1u64 >> 64); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:82:26 | LL | const _NU128_SHR: u128 = 1u128 >> 128; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:83:30 | LL | const _NU128_SHR_P: &u128 = &(1u128 >> 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:85:28 | LL | const _NISIZE_SHR: isize = 1isize >> BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:86:32 | LL | const _NISIZE_SHR_P: &isize = &(1isize >> BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:88:28 | LL | const _NUSIZE_SHR: usize = 1usize >> BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:89:32 | LL | const _NUSIZE_SHR_P: &usize = &(1usize >> BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:92:22 | LL | const _NI8_ADD: i8 = 1i8 + i8::MAX; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:93:26 | LL | const _NI8_ADD_P: &i8 = &(1i8 + i8::MAX); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:95:24 | LL | const _NI16_ADD: i16 = 1i16 + i16::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:96:28 | LL | const _NI16_ADD_P: &i16 = &(1i16 + i16::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:98:24 | LL | const _NI32_ADD: i32 = 1i32 + i32::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:99:28 | LL | const _NI32_ADD_P: &i32 = &(1i32 + i32::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:101:24 | LL | const _NI64_ADD: i64 = 1i64 + i64::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:102:28 | LL | const _NI64_ADD_P: &i64 = &(1i64 + i64::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:104:26 | LL | const _NI128_ADD: i128 = 1i128 + i128::MAX; - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:105:30 | LL | const _NI128_ADD_P: &i128 = &(1i128 + i128::MAX); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:107:22 | LL | const _NU8_ADD: u8 = 1u8 + u8::MAX; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:108:26 | LL | const _NU8_ADD_P: &u8 = &(1u8 + u8::MAX); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:110:24 | LL | const _NU16_ADD: u16 = 1u16 + u16::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:111:28 | LL | const _NU16_ADD_P: &u16 = &(1u16 + u16::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:113:24 | LL | const _NU32_ADD: u32 = 1u32 + u32::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:114:28 | LL | const _NU32_ADD_P: &u32 = &(1u32 + u32::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:116:24 | LL | const _NU64_ADD: u64 = 1u64 + u64::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:117:28 | LL | const _NU64_ADD_P: &u64 = &(1u64 + u64::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:119:26 | LL | const _NU128_ADD: u128 = 1u128 + u128::MAX; - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:120:30 | LL | const _NU128_ADD_P: &u128 = &(1u128 + u128::MAX); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:122:28 | LL | const _NISIZE_ADD: isize = 1isize + isize::MAX; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:123:32 | LL | const _NISIZE_ADD_P: &isize = &(1isize + isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:125:28 | LL | const _NUSIZE_ADD: usize = 1usize + usize::MAX; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:126:32 | LL | const _NUSIZE_ADD_P: &usize = &(1usize + usize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:129:22 | LL | const _NI8_SUB: i8 = -5i8 - i8::MAX; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:130:26 | LL | const _NI8_SUB_P: &i8 = &(-5i8 - i8::MAX); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:132:24 | LL | const _NI16_SUB: i16 = -5i16 - i16::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:133:28 | LL | const _NI16_SUB_P: &i16 = &(-5i16 - i16::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:135:24 | LL | const _NI32_SUB: i32 = -5i32 - i32::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:136:28 | LL | const _NI32_SUB_P: &i32 = &(-5i32 - i32::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:138:24 | LL | const _NI64_SUB: i64 = -5i64 - i64::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:139:28 | LL | const _NI64_SUB_P: &i64 = &(-5i64 - i64::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:141:26 | LL | const _NI128_SUB: i128 = -5i128 - i128::MAX; - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:142:30 | LL | const _NI128_SUB_P: &i128 = &(-5i128 - i128::MAX); - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:144:22 | LL | const _NU8_SUB: u8 = 1u8 - 5; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:145:26 | LL | const _NU8_SUB_P: &u8 = &(1u8 - 5); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:147:24 | LL | const _NU16_SUB: u16 = 1u16 - 5; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:148:28 | LL | const _NU16_SUB_P: &u16 = &(1u16 - 5); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:150:24 | LL | const _NU32_SUB: u32 = 1u32 - 5; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:151:28 | LL | const _NU32_SUB_P: &u32 = &(1u32 - 5); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:153:24 | LL | const _NU64_SUB: u64 = 1u64 - 5; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:154:28 | LL | const _NU64_SUB_P: &u64 = &(1u64 - 5); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:156:26 | LL | const _NU128_SUB: u128 = 1u128 - 5; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:157:30 | LL | const _NU128_SUB_P: &u128 = &(1u128 - 5); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:159:28 | LL | const _NISIZE_SUB: isize = -5isize - isize::MAX; - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:160:32 | LL | const _NISIZE_SUB_P: &isize = &(-5isize - isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:162:28 | LL | const _NUSIZE_SUB: usize = 1usize - 5; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:163:32 | LL | const _NUSIZE_SUB_P: &usize = &(1usize - 5); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow --> $DIR/overflowing-consts.rs:166:22 | LL | const _NI8_MUL: i8 = i8::MAX * 5; - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow --> $DIR/overflowing-consts.rs:167:26 | LL | const _NI8_MUL_P: &i8 = &(i8::MAX * 5); - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow --> $DIR/overflowing-consts.rs:169:24 | LL | const _NI16_MUL: i16 = i16::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow --> $DIR/overflowing-consts.rs:170:28 | LL | const _NI16_MUL_P: &i16 = &(i16::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow --> $DIR/overflowing-consts.rs:172:24 | LL | const _NI32_MUL: i32 = i32::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow --> $DIR/overflowing-consts.rs:173:28 | LL | const _NI32_MUL_P: &i32 = &(i32::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow --> $DIR/overflowing-consts.rs:175:24 | LL | const _NI64_MUL: i64 = i64::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow --> $DIR/overflowing-consts.rs:176:28 | LL | const _NI64_MUL_P: &i64 = &(i64::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow --> $DIR/overflowing-consts.rs:178:26 | LL | const _NI128_MUL: i128 = i128::MAX * 5; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow --> $DIR/overflowing-consts.rs:179:30 | LL | const _NI128_MUL_P: &i128 = &(i128::MAX * 5); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:181:22 | LL | const _NU8_MUL: u8 = u8::MAX * 5; - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:182:26 | LL | const _NU8_MUL_P: &u8 = &(u8::MAX * 5); - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:184:24 | LL | const _NU16_MUL: u16 = u16::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:185:28 | LL | const _NU16_MUL_P: &u16 = &(u16::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:187:24 | LL | const _NU32_MUL: u32 = u32::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:188:28 | LL | const _NU32_MUL_P: &u32 = &(u32::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:190:24 | LL | const _NU64_MUL: u64 = u64::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:191:28 | LL | const _NU64_MUL_P: &u64 = &(u64::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:193:26 | LL | const _NU128_MUL: u128 = u128::MAX * 5; - | ^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:194:30 | LL | const _NU128_MUL_P: &u128 = &(u128::MAX * 5); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow --> $DIR/overflowing-consts.rs:196:28 | LL | const _NISIZE_MUL: isize = isize::MAX * 5; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow --> $DIR/overflowing-consts.rs:197:32 | LL | const _NISIZE_MUL_P: &isize = &(isize::MAX * 5); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:199:28 | LL | const _NUSIZE_MUL: usize = usize::MAX * 5; - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:200:32 | LL | const _NUSIZE_MUL_P: &usize = &(usize::MAX * 5); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i8` by zero --> $DIR/overflowing-consts.rs:203:22 | LL | const _NI8_DIV: i8 = 1i8 / 0; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i8` by zero --> $DIR/overflowing-consts.rs:204:26 | LL | const _NI8_DIV_P: &i8 = &(1i8 / 0); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i16` by zero --> $DIR/overflowing-consts.rs:206:24 | LL | const _NI16_DIV: i16 = 1i16 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i16` by zero --> $DIR/overflowing-consts.rs:207:28 | LL | const _NI16_DIV_P: &i16 = &(1i16 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i32` by zero --> $DIR/overflowing-consts.rs:209:24 | LL | const _NI32_DIV: i32 = 1i32 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i32` by zero --> $DIR/overflowing-consts.rs:210:28 | LL | const _NI32_DIV_P: &i32 = &(1i32 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i64` by zero --> $DIR/overflowing-consts.rs:212:24 | LL | const _NI64_DIV: i64 = 1i64 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i64` by zero --> $DIR/overflowing-consts.rs:213:28 | LL | const _NI64_DIV_P: &i64 = &(1i64 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i128` by zero --> $DIR/overflowing-consts.rs:215:26 | LL | const _NI128_DIV: i128 = 1i128 / 0; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_i128` by zero --> $DIR/overflowing-consts.rs:216:30 | LL | const _NI128_DIV_P: &i128 = &(1i128 / 0); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u8` by zero --> $DIR/overflowing-consts.rs:218:22 | LL | const _NU8_DIV: u8 = 1u8 / 0; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u8` by zero --> $DIR/overflowing-consts.rs:219:26 | LL | const _NU8_DIV_P: &u8 = &(1u8 / 0); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u16` by zero --> $DIR/overflowing-consts.rs:221:24 | LL | const _NU16_DIV: u16 = 1u16 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u16` by zero --> $DIR/overflowing-consts.rs:222:28 | LL | const _NU16_DIV_P: &u16 = &(1u16 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u32` by zero --> $DIR/overflowing-consts.rs:224:24 | LL | const _NU32_DIV: u32 = 1u32 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u32` by zero --> $DIR/overflowing-consts.rs:225:28 | LL | const _NU32_DIV_P: &u32 = &(1u32 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u64` by zero --> $DIR/overflowing-consts.rs:227:24 | LL | const _NU64_DIV: u64 = 1u64 / 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u64` by zero --> $DIR/overflowing-consts.rs:228:28 | LL | const _NU64_DIV_P: &u64 = &(1u64 / 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u128` by zero --> $DIR/overflowing-consts.rs:230:26 | LL | const _NU128_DIV: u128 = 1u128 / 0; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_u128` by zero --> $DIR/overflowing-consts.rs:231:30 | LL | const _NU128_DIV_P: &u128 = &(1u128 / 0); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_isize` by zero --> $DIR/overflowing-consts.rs:233:28 | LL | const _NISIZE_DIV: isize = 1isize / 0; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_isize` by zero --> $DIR/overflowing-consts.rs:234:32 | LL | const _NISIZE_DIV_P: &isize = &(1isize / 0); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_usize` by zero --> $DIR/overflowing-consts.rs:236:28 | LL | const _NUSIZE_DIV: usize = 1usize / 0; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_usize` by zero --> $DIR/overflowing-consts.rs:237:32 | LL | const _NUSIZE_DIV_P: &usize = &(1usize / 0); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero --> $DIR/overflowing-consts.rs:240:22 | LL | const _NI8_MOD: i8 = 1i8 % 0; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero --> $DIR/overflowing-consts.rs:241:26 | LL | const _NI8_MOD_P: &i8 = &(1i8 % 0); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero --> $DIR/overflowing-consts.rs:243:24 | LL | const _NI16_MOD: i16 = 1i16 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero --> $DIR/overflowing-consts.rs:244:28 | LL | const _NI16_MOD_P: &i16 = &(1i16 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero --> $DIR/overflowing-consts.rs:246:24 | LL | const _NI32_MOD: i32 = 1i32 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero --> $DIR/overflowing-consts.rs:247:28 | LL | const _NI32_MOD_P: &i32 = &(1i32 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero --> $DIR/overflowing-consts.rs:249:24 | LL | const _NI64_MOD: i64 = 1i64 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero --> $DIR/overflowing-consts.rs:250:28 | LL | const _NI64_MOD_P: &i64 = &(1i64 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero --> $DIR/overflowing-consts.rs:252:26 | LL | const _NI128_MOD: i128 = 1i128 % 0; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero --> $DIR/overflowing-consts.rs:253:30 | LL | const _NI128_MOD_P: &i128 = &(1i128 % 0); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero --> $DIR/overflowing-consts.rs:255:22 | LL | const _NU8_MOD: u8 = 1u8 % 0; - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero --> $DIR/overflowing-consts.rs:256:26 | LL | const _NU8_MOD_P: &u8 = &(1u8 % 0); - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero --> $DIR/overflowing-consts.rs:258:24 | LL | const _NU16_MOD: u16 = 1u16 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero --> $DIR/overflowing-consts.rs:259:28 | LL | const _NU16_MOD_P: &u16 = &(1u16 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero --> $DIR/overflowing-consts.rs:261:24 | LL | const _NU32_MOD: u32 = 1u32 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero --> $DIR/overflowing-consts.rs:262:28 | LL | const _NU32_MOD_P: &u32 = &(1u32 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero --> $DIR/overflowing-consts.rs:264:24 | LL | const _NU64_MOD: u64 = 1u64 % 0; - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero --> $DIR/overflowing-consts.rs:265:28 | LL | const _NU64_MOD_P: &u64 = &(1u64 % 0); - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero --> $DIR/overflowing-consts.rs:267:26 | LL | const _NU128_MOD: u128 = 1u128 % 0; - | ^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero --> $DIR/overflowing-consts.rs:268:30 | LL | const _NU128_MOD_P: &u128 = &(1u128 % 0); - | ^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero --> $DIR/overflowing-consts.rs:270:28 | LL | const _NISIZE_MOD: isize = 1isize % 0; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero --> $DIR/overflowing-consts.rs:271:32 | LL | const _NISIZE_MOD_P: &isize = &(1isize % 0); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero --> $DIR/overflowing-consts.rs:273:28 | LL | const _NUSIZE_MOD: usize = 1usize % 0; - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero --> $DIR/overflowing-consts.rs:274:32 | LL | const _NUSIZE_MOD_P: &usize = &(1usize % 0); - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: index out of bounds: the length is 3 but the index is 4 --> $DIR/overflowing-consts.rs:277:24 | LL | const _NI32_OOB: i32 = [1, 2, 3][4]; - | ^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: index out of bounds: the length is 3 but the index is 4 --> $DIR/overflowing-consts.rs:278:28 | LL | const _NI32_OOB_P: &i32 = &([1, 2, 3][4]); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 170 previous errors diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr index c0e06e9efdf..6c09a1faed2 100644 --- a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr +++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr @@ -2,7 +2,7 @@ error[E0080]: tried to allocate more memory than available to compiler --> $DIR/promoted_running_out_of_memory_issue-130687.rs:13:32 | LL | const _: &'static Data = &Data([0; (1 << 47) - 1]); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/promoted_size_overflow.stderr b/tests/ui/consts/promoted_size_overflow.stderr index 688dd0c2cab..226c78ec01b 100644 --- a/tests/ui/consts/promoted_size_overflow.stderr +++ b/tests/ui/consts/promoted_size_overflow.stderr @@ -2,7 +2,7 @@ error[E0080]: values of the type `[u8; 4611686018427387903]` are too big for the --> $DIR/promoted_size_overflow.rs:3:29 | LL | const _: &'static [Data] = &[]; - | ^^ evaluation of constant value failed + | ^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.stderr b/tests/ui/consts/qualif-indirect-mutation-fail.stderr index bdb5ad9dc11..6cd7741103f 100644 --- a/tests/ui/consts/qualif-indirect-mutation-fail.stderr +++ b/tests/ui/consts/qualif-indirect-mutation-fail.stderr @@ -11,7 +11,7 @@ error[E0080]: calling non-const function ` as Drop>::drop` --> $DIR/qualif-indirect-mutation-fail.rs:18:1 | LL | }; - | ^ evaluation of constant value failed + | ^ evaluation of constant value failed here | note: inside `drop_in_place::> - shim(Some(Option))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -32,7 +32,7 @@ error[E0080]: calling non-const function ` as Drop>::drop` --> $DIR/qualif-indirect-mutation-fail.rs:29:1 | LL | }; - | ^ evaluation of constant value failed + | ^ evaluation of constant value failed here | note: inside `drop_in_place::> - shim(Some(Option))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/recursive-zst-static.default.stderr b/tests/ui/consts/recursive-zst-static.default.stderr index af97c945b92..80661825d53 100644 --- a/tests/ui/consts/recursive-zst-static.default.stderr +++ b/tests/ui/consts/recursive-zst-static.default.stderr @@ -2,7 +2,7 @@ error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; - | ^^^ could not evaluate static initializer + | ^^^ evaluation of static initializer failed here error[E0391]: cycle detected when evaluating initializer of static `A` --> $DIR/recursive-zst-static.rs:13:16 diff --git a/tests/ui/consts/recursive-zst-static.unleash.stderr b/tests/ui/consts/recursive-zst-static.unleash.stderr index af97c945b92..80661825d53 100644 --- a/tests/ui/consts/recursive-zst-static.unleash.stderr +++ b/tests/ui/consts/recursive-zst-static.unleash.stderr @@ -2,7 +2,7 @@ error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; - | ^^^ could not evaluate static initializer + | ^^^ evaluation of static initializer failed here error[E0391]: cycle detected when evaluating initializer of static `A` --> $DIR/recursive-zst-static.rs:13:16 diff --git a/tests/ui/consts/recursive.stderr b/tests/ui/consts/recursive.stderr index 7721d153729..97fa9e7e75e 100644 --- a/tests/ui/consts/recursive.stderr +++ b/tests/ui/consts/recursive.stderr @@ -13,7 +13,7 @@ error[E0080]: reached the configured maximum number of stack frames --> $DIR/recursive.rs:7:15 | LL | const X: () = f(1); - | ^^^^ evaluation of constant value failed + | ^^^^ evaluation of constant value failed here | note: [... 126 additional calls inside `f::` ...] --> $DIR/recursive.rs:4:5 diff --git a/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr b/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr index 3d908b54287..7d7bbbc5e36 100644 --- a/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-called-fn.rs:10:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-called-fn.rs:19:17 diff --git a/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr b/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr index 3d908b54287..7d7bbbc5e36 100644 --- a/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-called-fn.rs:10:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-called-fn.rs:19:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr index f0670f7a746..239e9cb1472 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-closure.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-closure.rs:17:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr index f0670f7a746..239e9cb1472 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-closure.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-closure.rs:17:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr index dbf330ada04..7c6219ccf93 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-drop.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-drop.rs:16:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-drop.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-drop.opt.stderr index dbf330ada04..7c6219ccf93 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-drop.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-drop.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-drop.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-drop.rs:16:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.noopt.stderr index 178ffa20612..e1a82fd5231 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn-behind-assoc-type.rs:10:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-fn-behind-assoc-type.rs:16:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.opt.stderr index 178ffa20612..e1a82fd5231 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn-behind-assoc-type.rs:10:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-fn-behind-assoc-type.rs:16:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.noopt.stderr index 78336273a73..1d2af342a44 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn-behind-generic.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-fn-behind-generic.rs:15:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.opt.stderr index 78336273a73..1d2af342a44 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn-behind-generic.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-fn-behind-generic.rs:15:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.noopt.stderr index 825f646630a..a480a8c5a39 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn-behind-opaque-type.rs:11:23 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `m::Fail::::C` failed + | ^^^^^^^^ evaluation of `m::Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-fn-behind-opaque-type.rs:19:21 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.opt.stderr index 825f646630a..a480a8c5a39 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn-behind-opaque-type.rs:11:23 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `m::Fail::::C` failed + | ^^^^^^^^ evaluation of `m::Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-fn-behind-opaque-type.rs:19:21 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr index f2a0bd91e78..f253a7cbbee 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-fn.rs:19:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn.opt.stderr index f2a0bd91e78..f253a7cbbee 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fn.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fn.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fn.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-fn.rs:19:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.noopt.stderr index 7235cfe0d7c..b962630ca01 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fnptr-in-const.rs:9:22 | LL | const FAIL: () = panic!(); - | ^^^^^^^^ evaluation of `Late::::FAIL` failed + | ^^^^^^^^ evaluation of `Late::::FAIL` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-fnptr-in-const.rs:10:28 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.opt.stderr index 7235cfe0d7c..b962630ca01 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fnptr-in-const.rs:9:22 | LL | const FAIL: () = panic!(); - | ^^^^^^^^ evaluation of `Late::::FAIL` failed + | ^^^^^^^^ evaluation of `Late::::FAIL` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-fnptr-in-const.rs:10:28 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fnptr.noopt.stderr index 50dc52625c1..29e6711153c 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fnptr.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fnptr.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-fnptr.rs:18:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fnptr.opt.stderr index 50dc52625c1..29e6711153c 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-fnptr.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-fnptr.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-fnptr.rs:18:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr index 96fa3b7f4ce..6c8edc00260 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-move.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-move.rs:16:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-move.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-move.opt.stderr index 96fa3b7f4ce..6c8edc00260 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-move.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-move.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-move.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-move.rs:16:17 diff --git a/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr index a036b7bdd5f..4e35beadbf4 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-vtable.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-vtable.rs:22:21 diff --git a/tests/ui/consts/required-consts/collect-in-dead-vtable.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-vtable.opt.stderr index a036b7bdd5f..4e35beadbf4 100644 --- a/tests/ui/consts/required-consts/collect-in-dead-vtable.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-dead-vtable.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-dead-vtable.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-dead-vtable.rs:22:21 diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr b/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr index 9e9d4b34124..67f5009c4ff 100644 --- a/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-promoted-const.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-promoted-const.rs:20:21 diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr b/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr index d97604f29e6..5c3edf68d95 100644 --- a/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-promoted-const.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-promoted-const.rs:20:21 @@ -14,7 +14,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/collect-in-promoted-const.rs:9:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/collect-in-promoted-const.rs:20:21 diff --git a/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr index 6b864e7e51f..c9fd476bd8b 100644 --- a/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/interpret-in-const-called-fn.rs:8:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/interpret-in-const-called-fn.rs:18:9 diff --git a/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr b/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr index 6b864e7e51f..c9fd476bd8b 100644 --- a/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/interpret-in-const-called-fn.rs:8:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/interpret-in-const-called-fn.rs:18:9 diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr index 569e1970ad1..b14c9aff7ba 100644 --- a/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: entering unreachable code --> $DIR/interpret-in-promoted.rs:15:28 | LL | let _x: &'static () = &ub(); - | ^^^^ evaluation of constant value failed + | ^^^^ evaluation of constant value failed here | note: inside `ub` --> $DIR/interpret-in-promoted.rs:9:5 diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr b/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr index 569e1970ad1..b14c9aff7ba 100644 --- a/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: entering unreachable code --> $DIR/interpret-in-promoted.rs:15:28 | LL | let _x: &'static () = &ub(); - | ^^^^ evaluation of constant value failed + | ^^^^ evaluation of constant value failed here | note: inside `ub` --> $DIR/interpret-in-promoted.rs:9:5 diff --git a/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr index e9294054be6..8b8d375250d 100644 --- a/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/interpret-in-static.rs:8:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/interpret-in-static.rs:17:9 diff --git a/tests/ui/consts/required-consts/interpret-in-static.opt.stderr b/tests/ui/consts/required-consts/interpret-in-static.opt.stderr index e9294054be6..8b8d375250d 100644 --- a/tests/ui/consts/required-consts/interpret-in-static.opt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-static.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/interpret-in-static.rs:8:19 | LL | const C: () = panic!(); - | ^^^^^^^^ evaluation of `Fail::::C` failed + | ^^^^^^^^ evaluation of `Fail::::C` failed here note: erroneous constant encountered --> $DIR/interpret-in-static.rs:17:9 diff --git a/tests/ui/consts/slice-index-overflow-issue-130284.stderr b/tests/ui/consts/slice-index-overflow-issue-130284.stderr index 50d325bf4d2..641aed349dd 100644 --- a/tests/ui/consts/slice-index-overflow-issue-130284.stderr +++ b/tests/ui/consts/slice-index-overflow-issue-130284.stderr @@ -2,7 +2,7 @@ error[E0080]: overflowing pointer arithmetic: the total offset in bytes does not --> $DIR/slice-index-overflow-issue-130284.rs:7:20 | LL | let _ice = (*fat)[usize::MAX - 1]; - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.stderr index ecdf9ce3890..49b35dacd3a 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref2.stderr @@ -2,7 +2,7 @@ error[E0080]: modifying a static's initial value from another static's initializ --> $DIR/static_mut_containing_mut_ref2.rs:6:5 | LL | *(&mut STDERR_BUFFER_SPACE) = 42; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/static_mut_containing_mut_ref3.stderr b/tests/ui/consts/static_mut_containing_mut_ref3.stderr index 7ad56e27805..71d701434a3 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref3.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref3.stderr @@ -2,7 +2,7 @@ error[E0080]: modifying a static's initial value from another static's initializ --> $DIR/static_mut_containing_mut_ref3.rs:3:31 | LL | static mut BAR: () = unsafe { FOO.0 = 99; }; - | ^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^ evaluation of static initializer failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/uninhabited-const-issue-61744.stderr b/tests/ui/consts/uninhabited-const-issue-61744.stderr index 95d8ceebcd7..3c5b5196aeb 100644 --- a/tests/ui/consts/uninhabited-const-issue-61744.stderr +++ b/tests/ui/consts/uninhabited-const-issue-61744.stderr @@ -2,7 +2,7 @@ error[E0080]: reached the configured maximum number of stack frames --> $DIR/uninhabited-const-issue-61744.rs:13:36 | LL | const CONSTANT: i32 = unsafe { fake_type() }; - | ^^^^^^^^^^^ evaluation of `fake_type::` failed + | ^^^^^^^^^^^ evaluation of `fake_type::` failed here | note: inside `fake_type::` --> $DIR/uninhabited-const-issue-61744.rs:5:5 diff --git a/tests/ui/consts/write-to-static-mut-in-static.stderr b/tests/ui/consts/write-to-static-mut-in-static.stderr index 7d2aa0e3422..c98c7d895fc 100644 --- a/tests/ui/consts/write-to-static-mut-in-static.stderr +++ b/tests/ui/consts/write-to-static-mut-in-static.stderr @@ -2,13 +2,13 @@ error[E0080]: modifying a static's initial value from another static's initializ --> $DIR/write-to-static-mut-in-static.rs:2:33 | LL | pub static mut B: () = unsafe { A = 1; }; - | ^^^^^ could not evaluate static initializer + | ^^^^^ evaluation of static initializer failed here error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/write-to-static-mut-in-static.rs:7:21 | LL | pub static D: u32 = D; - | ^ could not evaluate static initializer + | ^ evaluation of static initializer failed here error: aborting due to 2 previous errors diff --git a/tests/ui/enum-discriminant/eval-error.stderr b/tests/ui/enum-discriminant/eval-error.stderr index 7e15a5e0c76..b4061d7777b 100644 --- a/tests/ui/enum-discriminant/eval-error.stderr +++ b/tests/ui/enum-discriminant/eval-error.stderr @@ -49,7 +49,7 @@ error[E0080]: the type `Foo` has an unknown layout --> $DIR/eval-error.rs:9:30 | LL | let _: Option = None; - | ^^^^ evaluation of constant value failed + | ^^^^ evaluation of constant value failed here error: aborting due to 5 previous errors diff --git a/tests/ui/error-codes/E0080.stderr b/tests/ui/error-codes/E0080.stderr index da364332a70..431d4e04454 100644 --- a/tests/ui/error-codes/E0080.stderr +++ b/tests/ui/error-codes/E0080.stderr @@ -2,13 +2,13 @@ error[E0080]: attempt to shift left by `500_i32`, which would overflow --> $DIR/E0080.rs:2:9 | LL | X = (1 << 500), - | ^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to divide `1_isize` by zero --> $DIR/E0080.rs:3:9 | LL | Y = (1 / 0), - | ^^^^^^^ evaluation of constant value failed + | ^^^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr b/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr index ab6af9349dc..2d558e9a561 100644 --- a/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr +++ b/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr @@ -2,7 +2,7 @@ error[E0080]: reached the configured maximum number of stack frames --> $DIR/ctfe-id-unlimited.rs:28:20 | LL | const ID_ED: u32 = rec_id(ORIGINAL); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `rec_id` --> $DIR/ctfe-id-unlimited.rs:21:5 diff --git a/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr index c30818c8340..457290b76b8 100644 --- a/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr +++ b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/ctfe-tail-call-panic.rs:13:15 | LL | const _: () = f(); - | ^^^ evaluation of constant value failed + | ^^^ evaluation of constant value failed here | note: inside `g` --> $DIR/ctfe-tail-call-panic.rs:9:5 diff --git a/tests/ui/extern/issue-28324.stderr b/tests/ui/extern/issue-28324.stderr index 8ad3ac57152..89dfab945be 100644 --- a/tests/ui/extern/issue-28324.stderr +++ b/tests/ui/extern/issue-28324.stderr @@ -2,7 +2,7 @@ error[E0080]: cannot access extern static `error_message_count` --> $DIR/issue-28324.rs:5:23 | LL | pub static BAZ: u32 = *&error_message_count; - | ^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error[E0133]: use of extern static is unsafe and requires unsafe function or block --> $DIR/issue-28324.rs:5:25 diff --git a/tests/ui/generic-const-items/def-site-eval.fail.stderr b/tests/ui/generic-const-items/def-site-eval.fail.stderr index d9cf2f15dd7..b8616547390 100644 --- a/tests/ui/generic-const-items/def-site-eval.fail.stderr +++ b/tests/ui/generic-const-items/def-site-eval.fail.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/def-site-eval.rs:13:20 | LL | const _<'_a>: () = panic!(); - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr index e2df1559d07..a89356fadfd 100644 --- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr +++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr @@ -4,7 +4,7 @@ error[E0080]: entering unreachable code LL | / const UNUSABLE: () = () LL | | where LL | | String: Copy; - | |_________________^ evaluation of constant value failed + | |_________________^ evaluation of constant value failed here error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/trivially-unsatisfied-bounds-0.rs:11:13 diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr index 83254da8644..3aa26eb1656 100644 --- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr +++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr @@ -4,7 +4,7 @@ error[E0080]: entering unreachable code LL | / const UNUSED: () = () LL | | where LL | | String: Copy; - | |_________________^ evaluation of constant value failed + | |_________________^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/generic-const-items/unsatisfied-evaluatable-bounds.stderr b/tests/ui/generic-const-items/unsatisfied-evaluatable-bounds.stderr index b6c80301944..a9f11ac31c3 100644 --- a/tests/ui/generic-const-items/unsatisfied-evaluatable-bounds.stderr +++ b/tests/ui/generic-const-items/unsatisfied-evaluatable-bounds.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/unsatisfied-evaluatable-bounds.rs:8:10 | LL | [(); N - 1]:; - | ^^^^^ evaluation of `POSITIVE::<0>::{constant#0}` failed + | ^^^^^ evaluation of `POSITIVE::<0>::{constant#0}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/generics/post_monomorphization_error_backtrace.stderr b/tests/ui/generics/post_monomorphization_error_backtrace.stderr index f2146df1f8d..6953414f0c2 100644 --- a/tests/ui/generics/post_monomorphization_error_backtrace.stderr +++ b/tests/ui/generics/post_monomorphization_error_backtrace.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::() == --> $DIR/post_monomorphization_error_backtrace.rs:6:23 | LL | const V: () = assert!(std::mem::size_of::() == 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::::V` failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::::V` failed here note: erroneous constant encountered --> $DIR/post_monomorphization_error_backtrace.rs:14:5 @@ -20,7 +20,7 @@ error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::() == --> $DIR/post_monomorphization_error_backtrace.rs:6:23 | LL | const V: () = assert!(std::mem::size_of::() == 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::::V` failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::::V` failed here note: erroneous constant encountered --> $DIR/post_monomorphization_error_backtrace.rs:14:5 diff --git a/tests/ui/infinite/infinite-recursion-const-fn.stderr b/tests/ui/infinite/infinite-recursion-const-fn.stderr index c61dacee437..529bad510c9 100644 --- a/tests/ui/infinite/infinite-recursion-const-fn.stderr +++ b/tests/ui/infinite/infinite-recursion-const-fn.stderr @@ -2,7 +2,7 @@ error[E0080]: reached the configured maximum number of stack frames --> $DIR/infinite-recursion-const-fn.rs:9:18 | LL | const ARR: [i32; a()] = [5; 6]; - | ^^^ evaluation of constant value failed + | ^^^ evaluation of constant value failed here | note: inside `a` --> $DIR/infinite-recursion-const-fn.rs:4:5 diff --git a/tests/ui/inline-const/const-expr-generic-err.stderr b/tests/ui/inline-const/const-expr-generic-err.stderr index d703e7e2c9d..26039ba6d44 100644 --- a/tests/ui/inline-const/const-expr-generic-err.stderr +++ b/tests/ui/inline-const/const-expr-generic-err.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::() == --> $DIR/const-expr-generic-err.rs:4:13 | LL | const { assert!(std::mem::size_of::() == 0); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `foo::::{constant#0}` failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `foo::::{constant#0}` failed here note: erroneous constant encountered --> $DIR/const-expr-generic-err.rs:4:5 @@ -20,7 +20,7 @@ error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/const-expr-generic-err.rs:8:13 | LL | const { N - 1 } - | ^^^^^ evaluation of `bar::<0>::{constant#0}` failed + | ^^^^^ evaluation of `bar::<0>::{constant#0}` failed here note: erroneous constant encountered --> $DIR/const-expr-generic-err.rs:8:5 diff --git a/tests/ui/inline-const/required-const.stderr b/tests/ui/inline-const/required-const.stderr index 06c7c370654..a517ea2fec0 100644 --- a/tests/ui/inline-const/required-const.stderr +++ b/tests/ui/inline-const/required-const.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/required-const.rs:6:17 | LL | const { panic!() } - | ^^^^^^^^ evaluation of `foo::::{constant#0}` failed + | ^^^^^^^^ evaluation of `foo::::{constant#0}` failed here note: erroneous constant encountered --> $DIR/required-const.rs:6:9 diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr index cf899b29eae..1d2c263baf1 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr @@ -2,13 +2,13 @@ error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at --> $DIR/intrinsic-raw_eq-const-bad.rs:4:5 | LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: unable to turn pointer into integer --> $DIR/intrinsic-raw_eq-const-bad.rs:9:5 | LL | std::intrinsics::raw_eq(&(&0), &(&1)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -17,7 +17,7 @@ error[E0080]: accessing memory with alignment 1, but alignment 4 is required --> $DIR/intrinsic-raw_eq-const-bad.rs:16:5 | LL | std::intrinsics::raw_eq(aref, aref) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 3 previous errors diff --git a/tests/ui/issues/issue-76191.stderr b/tests/ui/issues/issue-76191.stderr index 24513901401..1f19db49c43 100644 --- a/tests/ui/issues/issue-76191.stderr +++ b/tests/ui/issues/issue-76191.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-76191.rs:8:37 | LL | const RANGE2: RangeInclusive = panic!(); - | ^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^ evaluation of constant value failed here error[E0308]: mismatched types --> $DIR/issue-76191.rs:14:9 diff --git a/tests/ui/layout/invalid-unsized-const-eval.stderr b/tests/ui/layout/invalid-unsized-const-eval.stderr index c430a69766a..073568883c4 100644 --- a/tests/ui/layout/invalid-unsized-const-eval.stderr +++ b/tests/ui/layout/invalid-unsized-const-eval.stderr @@ -11,7 +11,7 @@ error[E0080]: the type `(dyn Sync, ())` has an unknown layout --> $DIR/invalid-unsized-const-eval.rs:12:1 | LL | static EMPTY_SET: LazyLock = todo!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error: aborting due to 2 previous errors diff --git a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr index 2cdd79c488e..e08107f5f8e 100644 --- a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr +++ b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr @@ -22,7 +22,7 @@ error[E0080]: the type `MySlice<[bool]>` has an unknown layout --> $DIR/invalid-unsized-in-always-sized-tail.rs:15:28 | LL | static CHECK: () = assert!(align_of::() == 1); - | ^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^ evaluation of static initializer failed here | note: inside `align_of::` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr index 32dd2310a7e..c85c40d5bda 100644 --- a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr +++ b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr @@ -26,7 +26,7 @@ error[E0080]: the type `ArenaSet, [u8]>` has an unknown layout --> $DIR/issue-unsized-tail-restatic-ice-122488.rs:8:1 | LL | const DATA: *const ArenaSet> = std::ptr::null_mut(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr index b12f1a18245..fa58b1f8fe4 100644 --- a/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr +++ b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr @@ -2,7 +2,7 @@ error[E0080]: the type `Option` has an unknown layout --> $DIR/uncomputable-due-to-trivial-bounds-ice-135138.rs:7:16 | LL | [(); { let _a: Option = None; 0 }]; - | ^^ evaluation of constant value failed + | ^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/layout/unknown-when-no-type-parameter.stderr b/tests/ui/layout/unknown-when-no-type-parameter.stderr index 7b4d6d1ac0e..f0a64960c6a 100644 --- a/tests/ui/layout/unknown-when-no-type-parameter.stderr +++ b/tests/ui/layout/unknown-when-no-type-parameter.stderr @@ -2,7 +2,7 @@ error[E0080]: the type `<() as Project>::Assoc` has an unknown layout --> $DIR/unknown-when-no-type-parameter.rs:11:10 | LL | [(); size_of::<<() as Project>::Assoc>()]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `std::mem::size_of::<<() as Project>::Assoc>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr index ef2a624fa87..8cf5ce7c22d 100644 --- a/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr +++ b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr @@ -2,7 +2,7 @@ error[E0080]: the type `str` has an unknown layout --> $DIR/unknown-when-ptr-metadata-is-DST.rs:8:16 | LL | [(); { let _a: Option<&str> = None; 0 }]; - | ^^ evaluation of constant value failed + | ^^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr index a91cb4f45cb..e0d25742502 100644 --- a/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr +++ b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/def-site-param-defaults-wf.rs:5:45 | LL | type Alias, const N: usize = { 0 - 1 }> = T; - | ^^^^^ evaluation of constant value failed + | ^^^^^ evaluation of constant value failed here error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/def-site-param-defaults-wf.rs:5:16 diff --git a/tests/ui/limits/huge-static.stderr b/tests/ui/limits/huge-static.stderr index b953866f0d3..63d04b75d99 100644 --- a/tests/ui/limits/huge-static.stderr +++ b/tests/ui/limits/huge-static.stderr @@ -2,13 +2,13 @@ error[E0080]: values of the type `[u8; 2305843009213693952]` are too big for the --> $DIR/huge-static.rs:18:1 | LL | static MY_TOO_BIG_ARRAY_1: TooBigArray = TooBigArray::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error[E0080]: values of the type `[u8; 2305843009213693952]` are too big for the target architecture --> $DIR/huge-static.rs:20:1 | LL | static MY_TOO_BIG_ARRAY_2: [u8; HUGE_SIZE] = [0x00; HUGE_SIZE]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error: aborting due to 2 previous errors diff --git a/tests/ui/limits/issue-55878.stderr b/tests/ui/limits/issue-55878.stderr index e39dd42e2ff..27357796c18 100644 --- a/tests/ui/limits/issue-55878.stderr +++ b/tests/ui/limits/issue-55878.stderr @@ -2,7 +2,7 @@ error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target a --> $DIR/issue-55878.rs:4:26 | LL | println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | note: inside `std::mem::size_of::<[u8; usize::MAX]>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/recursion/recursive-static-definition.stderr b/tests/ui/recursion/recursive-static-definition.stderr index 28df85ffaaf..7063e5c3c66 100644 --- a/tests/ui/recursion/recursive-static-definition.stderr +++ b/tests/ui/recursion/recursive-static-definition.stderr @@ -2,13 +2,13 @@ error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/recursive-static-definition.rs:1:23 | LL | pub static FOO: u32 = FOO; - | ^^^ could not evaluate static initializer + | ^^^ evaluation of static initializer failed here error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/recursive-static-definition.rs:9:23 | LL | pub static BAR: Foo = BAR; - | ^^^ could not evaluate static initializer + | ^^^ evaluation of static initializer failed here error: aborting due to 2 previous errors diff --git a/tests/ui/simd/const-err-trumps-simd-err.stderr b/tests/ui/simd/const-err-trumps-simd-err.stderr index b648cadef01..d4ba54a28da 100644 --- a/tests/ui/simd/const-err-trumps-simd-err.stderr +++ b/tests/ui/simd/const-err-trumps-simd-err.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: assertion failed: LANE < 4 --> $DIR/const-err-trumps-simd-err.rs:18:13 | LL | const { assert!(LANE < 4); } // the error should be here... - | ^^^^^^^^^^^^^^^^^ evaluation of `get_elem::<4>::{constant#0}` failed + | ^^^^^^^^^^^^^^^^^ evaluation of `get_elem::<4>::{constant#0}` failed here note: erroneous constant encountered --> $DIR/const-err-trumps-simd-err.rs:18:5 diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr index 1c112061fb6..354ca78c7be 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr @@ -13,7 +13,7 @@ error[E0080]: a cycle occurred during layout computation --> $DIR/stack-overflow-trait-infer-98842.rs:14:1 | LL | const _: *const Foo = 0 as _; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr index 1c112061fb6..354ca78c7be 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr @@ -13,7 +13,7 @@ error[E0080]: a cycle occurred during layout computation --> $DIR/stack-overflow-trait-infer-98842.rs:14:1 | LL | const _: *const Foo = 0 as _; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error: aborting due to 2 previous errors diff --git a/tests/ui/statics/issue-14227.stderr b/tests/ui/statics/issue-14227.stderr index 119e70e7b23..372a06ae1ed 100644 --- a/tests/ui/statics/issue-14227.stderr +++ b/tests/ui/statics/issue-14227.stderr @@ -2,7 +2,7 @@ error[E0080]: cannot access extern static `symbol` --> $DIR/issue-14227.rs:4:21 | LL | static CRASH: u32 = symbol; - | ^^^^^^ could not evaluate static initializer + | ^^^^^^ evaluation of static initializer failed here error[E0133]: use of extern static is unsafe and requires unsafe function or block --> $DIR/issue-14227.rs:4:21 diff --git a/tests/ui/statics/uninhabited-static.stderr b/tests/ui/statics/uninhabited-static.stderr index e285df0c7ed..60268ad3562 100644 --- a/tests/ui/statics/uninhabited-static.stderr +++ b/tests/ui/statics/uninhabited-static.stderr @@ -47,13 +47,13 @@ error[E0080]: constructing invalid value: encountered a value of uninhabited typ --> $DIR/uninhabited-static.rs:12:31 | LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error[E0080]: constructing invalid value: encountered a value of uninhabited type `Void` --> $DIR/uninhabited-static.rs:15:32 | LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ could not evaluate static initializer + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here error: aborting due to 6 previous errors diff --git a/tests/ui/structs/default-field-values/invalid-const.stderr b/tests/ui/structs/default-field-values/invalid-const.stderr index 93f08c4c562..f4a74ef9fdc 100644 --- a/tests/ui/structs/default-field-values/invalid-const.stderr +++ b/tests/ui/structs/default-field-values/invalid-const.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation panicked: asdf --> $DIR/invalid-const.rs:5:19 | LL | pub bax: u8 = panic!("asdf"), - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: attempt to compute `130_u8 + 130_u8`, which would overflow --> $DIR/invalid-const.rs:11:19 | LL | pub bat: u8 = 130 + 130, - | ^^^^^^^^^ evaluation of `Baz::::bat::{constant#0}` failed + | ^^^^^^^^^ evaluation of `Baz::::bat::{constant#0}` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/structs/default-field-values/post-mono.direct.stderr b/tests/ui/structs/default-field-values/post-mono.direct.stderr index f177f1e7bbc..74e37795f06 100644 --- a/tests/ui/structs/default-field-values/post-mono.direct.stderr +++ b/tests/ui/structs/default-field-values/post-mono.direct.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to divide `1_usize` by zero --> $DIR/post-mono.rs:7:24 | LL | post_mono: usize = X / 0, - | ^^^^^ evaluation of `Z::<1>::post_mono::{constant#0}` failed + | ^^^^^ evaluation of `Z::<1>::post_mono::{constant#0}` failed here note: erroneous constant encountered --> $DIR/post-mono.rs:17:19 diff --git a/tests/ui/structs/default-field-values/post-mono.indirect.stderr b/tests/ui/structs/default-field-values/post-mono.indirect.stderr index 574f539659b..c8af9c959c1 100644 --- a/tests/ui/structs/default-field-values/post-mono.indirect.stderr +++ b/tests/ui/structs/default-field-values/post-mono.indirect.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to divide `1_usize` by zero --> $DIR/post-mono.rs:7:24 | LL | post_mono: usize = X / 0, - | ^^^^^ evaluation of `Z::<1>::post_mono::{constant#0}` failed + | ^^^^^ evaluation of `Z::<1>::post_mono::{constant#0}` failed here note: erroneous constant encountered --> $DIR/post-mono.rs:12:19 diff --git a/tests/ui/transmutability/uninhabited.stderr b/tests/ui/transmutability/uninhabited.stderr index 70bb48de56d..79cd75ce279 100644 --- a/tests/ui/transmutability/uninhabited.stderr +++ b/tests/ui/transmutability/uninhabited.stderr @@ -44,7 +44,7 @@ error[E0080]: evaluation panicked: assertion failed: false --> $DIR/uninhabited.rs:41:9 | LL | assert!(false); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0277]: `()` cannot be safely transmuted into `yawning_void_enum::Void` --> $DIR/uninhabited.rs:71:41 @@ -71,7 +71,7 @@ error[E0080]: evaluation panicked: assertion failed: false --> $DIR/uninhabited.rs:63:9 | LL | assert!(false); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0277]: `u128` cannot be safely transmuted into `DistantVoid` --> $DIR/uninhabited.rs:92:43 @@ -98,7 +98,7 @@ error[E0080]: evaluation panicked: assertion failed: false --> $DIR/uninhabited.rs:87:9 | LL | assert!(false); - | ^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0277]: `Src` cannot be safely transmuted into `issue_126267::Error` --> $DIR/uninhabited.rs:108:42 diff --git a/tests/ui/treat-err-as-bug/err.stderr b/tests/ui/treat-err-as-bug/err.stderr index 69c33cf8927..3279392e1f4 100644 --- a/tests/ui/treat-err-as-bug/err.stderr +++ b/tests/ui/treat-err-as-bug/err.stderr @@ -2,7 +2,7 @@ error: internal compiler error[E0080]: attempt to compute `0_u32 - 1_u32`, which --> $DIR/err.rs:9:21 | LL | pub static C: u32 = 0 - 1; - | ^^^^^ could not evaluate static initializer + | ^^^^^ evaluation of static initializer failed here error: the compiler unexpectedly panicked. this is a bug. diff --git a/tests/ui/type/pattern_types/literals.stderr b/tests/ui/type/pattern_types/literals.stderr index 4eb5bf4565d..72c812ed3ba 100644 --- a/tests/ui/type/pattern_types/literals.stderr +++ b/tests/ui/type/pattern_types/literals.stderr @@ -2,31 +2,31 @@ error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:86:62 | LL | fn empty_range_at_base_type_min() -> pattern_type!(u32 is 0..0) { - | ^ evaluation of constant value failed + | ^ evaluation of constant value failed here error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:91:63 | LL | fn empty_range_at_base_type_min2() -> pattern_type!(u32 is 0..0) { - | ^ evaluation of constant value failed + | ^ evaluation of constant value failed here error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:106:65 | LL | fn wraparound_range_at_base_ty_end() -> pattern_type!(u32 is 1..0) { - | ^ evaluation of constant value failed + | ^ evaluation of constant value failed here error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:111:66 | LL | fn wraparound_range_at_base_ty_end2() -> pattern_type!(u32 is 1..0) { - | ^ evaluation of constant value failed + | ^ evaluation of constant value failed here error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:116:66 | LL | fn wraparound_range_at_base_ty_end3() -> pattern_type!(u32 is 1..0) { - | ^ evaluation of constant value failed + | ^ evaluation of constant value failed here error[E0308]: mismatched types --> $DIR/literals.rs:9:5 diff --git a/tests/ui/type/pattern_types/range_patterns.stderr b/tests/ui/type/pattern_types/range_patterns.stderr index 632ca689fc0..bcb602a70dd 100644 --- a/tests/ui/type/pattern_types/range_patterns.stderr +++ b/tests/ui/type/pattern_types/range_patterns.stderr @@ -369,7 +369,7 @@ error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/range_patterns.rs:25:37 | LL | type WRAP = pattern_type!(u32 is 1..0); - | ^ evaluation of constant value failed + | ^ evaluation of constant value failed here error: the type has an unknown layout --> $DIR/range_patterns.rs:25:1 diff --git a/tests/ui/type/pattern_types/reverse_range.stderr b/tests/ui/type/pattern_types/reverse_range.stderr index 640296eb891..8f5b86c7db9 100644 --- a/tests/ui/type/pattern_types/reverse_range.stderr +++ b/tests/ui/type/pattern_types/reverse_range.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/reverse_range.rs:7:36 | LL | const NONE: pattern_type!(u8 is 1..0) = unsafe { std::mem::transmute(3_u8) }; - | ^ evaluation of constant value failed + | ^ evaluation of constant value failed here error: aborting due to 1 previous error diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr index 3219a2858c5..7ba73aacc24 100644 --- a/tests/ui/type/pattern_types/validity.stderr +++ b/tests/ui/type/pattern_types/validity.stderr @@ -13,13 +13,13 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/validity.rs:13:1 | LL | const BAD_UNINIT: pattern_type!(u32 is 1..) = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: unable to turn pointer into integer --> $DIR/validity.rs:17:1 | LL | const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(&42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -50,7 +50,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/validity.rs:29:1 | LL | const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here error[E0080]: constructing invalid value: encountered 97, but expected something in the range 65..=89 --> $DIR/validity.rs:33:1 -- cgit 1.4.1-3-g733a5 From b0041b8a05e2d6090dbf59f715b52cba3ca73359 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 2 Jun 2025 08:49:54 -0700 Subject: Disable f64 minimum/maximum tests for arm 32 This disables the f64 minimum/maximum tests for the arm-unknown-linux-gnueabihf job. The next release will be supporting cross-compiled doctests, and these tests fail on that platform. It looks like this was just fixed via https://github.com/llvm/llvm-project/pull/142170, but I assume that will not trickle down to our copy of llvm in the next couple of weeks. Assuming that does get fixed when llvm is updated, then these can be removed. cc https://github.com/rust-lang/rust/issues/141087 --- library/core/src/num/f64.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 0a63ed828ae..be933cfa41a 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -943,7 +943,7 @@ impl f64 { /// This returns NaN when *either* argument is NaN, as opposed to /// [`f64::max`] which only returns NaN when *both* arguments are NaN. /// - /// ``` + /// ```ignore-arm-unknown-linux-gnueabihf (see https://github.com/rust-lang/rust/issues/141087) /// #![feature(float_minimum_maximum)] /// let x = 1.0_f64; /// let y = 2.0_f64; @@ -970,7 +970,7 @@ impl f64 { /// This returns NaN when *either* argument is NaN, as opposed to /// [`f64::min`] which only returns NaN when *both* arguments are NaN. /// - /// ``` + /// ```ignore-arm-unknown-linux-gnueabihf (see https://github.com/rust-lang/rust/issues/141087) /// #![feature(float_minimum_maximum)] /// let x = 1.0_f64; /// let y = 2.0_f64; -- cgit 1.4.1-3-g733a5 From e83ca863412a950f19fbc4e8fc632f19107dd0a2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 2 Jun 2025 16:10:49 +0000 Subject: cleanup: Use `x.biteq(y)` rather than `x.to_bits() == y.to_bits()` --- library/compiler-builtins/libm-test/src/precision.rs | 2 +- library/compiler-builtins/libm-test/src/test_traits.rs | 5 +---- library/compiler-builtins/libm/src/math/generic/fmaximum.rs | 2 +- .../compiler-builtins/libm/src/math/generic/fmaximum_num.rs | 11 +++++------ library/compiler-builtins/libm/src/math/generic/fminimum.rs | 2 +- .../compiler-builtins/libm/src/math/generic/fminimum_num.rs | 11 +++++------ 6 files changed, 14 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index f5fb5f6707b..f6cdd015a59 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -381,7 +381,7 @@ fn unop_common( } // abs and copysign require signaling NaNs to be propagated, so verify bit equality. - if actual.to_bits() == expected.to_bits() { + if actual.biteq(expected) { return CheckAction::Custom(Ok(())); } else { return CheckAction::Custom(Err(anyhow::anyhow!("NaNs have different bitpatterns"))); diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index dbb97016153..2af6af60ba2 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -328,10 +328,7 @@ where // Check when both are NaNs if actual.is_nan() && expected.is_nan() { if require_biteq && ctx.basis == CheckBasis::None { - ensure!( - actual.to_bits() == expected.to_bits(), - "mismatched NaN bitpatterns" - ); + ensure!(actual.biteq(expected), "mismatched NaN bitpatterns"); } // By default, NaNs have nothing special to check. return Ok(()); diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs index 4b6295bc0c6..898828b80c7 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs @@ -17,7 +17,7 @@ pub fn fmaximum(x: F, y: F) -> F { x } else if y.is_nan() { y - } else if x > y || (y.to_bits() == F::NEG_ZERO.to_bits() && x.is_sign_positive()) { + } else if x > y || (y.biteq(F::NEG_ZERO) && x.is_sign_positive()) { x } else { y diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs index 2e97ff6d369..05df6cbd464 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs @@ -15,12 +15,11 @@ use crate::support::Float; #[inline] pub fn fmaximum_num(x: F, y: F) -> F { - let res = - if x.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { - y - } else { - x - }; + let res = if x.is_nan() || x < y || (x.biteq(F::NEG_ZERO) && y.is_sign_positive()) { + y + } else { + x + }; // Canonicalize res * F::ONE diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs index 9dc0b64be3f..8592ac5460e 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum.rs @@ -17,7 +17,7 @@ pub fn fminimum(x: F, y: F) -> F { x } else if y.is_nan() { y - } else if x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { + } else if x < y || (x.biteq(F::NEG_ZERO) && y.is_sign_positive()) { x } else { y diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs index 40db8b18957..6777bbf8772 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs @@ -15,12 +15,11 @@ use crate::support::Float; #[inline] pub fn fminimum_num(x: F, y: F) -> F { - let res = - if y.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { - x - } else { - y - }; + let res = if y.is_nan() || x < y || (x.biteq(F::NEG_ZERO) && y.is_sign_positive()) { + x + } else { + y + }; // Canonicalize res * F::ONE -- cgit 1.4.1-3-g733a5 From bb5de7d72b7965d8bbd80b024f644b0dfcdd0e5b Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 2 Jun 2025 19:01:18 +0200 Subject: Update books --- src/doc/book | 2 +- src/doc/embedded-book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book b/src/doc/book index 230c68bc1e0..634724ea85e 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 230c68bc1e08f5f3228384a28cc228c81dfbd10d +Subproject commit 634724ea85ebb08a542970bf8871ac8b0f77fd15 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index 0b8219ac23a..10fa1e08436 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit 0b8219ac23a3e09464e4e0166c768cf1c4bba0d5 +Subproject commit 10fa1e084365f23f24ad0000df541923385b73b6 diff --git a/src/doc/nomicon b/src/doc/nomicon index c76a20f0d98..8b61acfaea8 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit c76a20f0d987145dcedf05c5c073ce8d91f2e82a +Subproject commit 8b61acfaea822e9ac926190bc8f15791c33336e8 diff --git a/src/doc/reference b/src/doc/reference index 118fd1f1f08..8e0f593a30f 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 118fd1f1f0854f50e3ae1fe4b64862aad23009ca +Subproject commit 8e0f593a30f3b56ddb0908fb7ab9249974e08738 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index c9d151f9147..21f4e32b8b4 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit c9d151f9147c4808c77f0375ba3fa5d54443cb9e +Subproject commit 21f4e32b8b40d36453fae16ec07ad4b857c445b6 -- cgit 1.4.1-3-g733a5 From a20cf473e7b888f9ef7995971f0c5613a81e68ff Mon Sep 17 00:00:00 2001 From: Sidney Cammeresi Date: Mon, 2 Jun 2025 09:43:48 -0700 Subject: Lightly tweak docs for BTree{Map,Set}::extract_if - Move explanations into comments to match style - Explain the second examples - Make variable names match the data structure --- library/alloc/src/collections/btree/map.rs | 4 ++-- library/alloc/src/collections/btree/set.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 52b98291ff9..17c16e4aaff 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1416,18 +1416,18 @@ impl BTreeMap { /// /// # Examples /// - /// Splitting a map into even and odd keys, reusing the original map: - /// /// ``` /// #![feature(btree_extract_if)] /// use std::collections::BTreeMap; /// + /// // Splitting a map into even and odd keys, reusing the original map: /// let mut map: BTreeMap = (0..8).map(|x| (x, x)).collect(); /// let evens: BTreeMap<_, _> = map.extract_if(.., |k, _v| k % 2 == 0).collect(); /// let odds = map; /// assert_eq!(evens.keys().copied().collect::>(), [0, 2, 4, 6]); /// assert_eq!(odds.keys().copied().collect::>(), [1, 3, 5, 7]); /// + /// // Splitting a map into low and high halves, reusing the original map: /// let mut map: BTreeMap = (0..8).map(|x| (x, x)).collect(); /// let low: BTreeMap<_, _> = map.extract_if(0..4, |_k, _v| true).collect(); /// let high = map; diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 780bd8b0dd1..51418036f42 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1201,21 +1201,21 @@ impl BTreeSet { /// [`retain`]: BTreeSet::retain /// # Examples /// - /// Splitting a set into even and odd values, reusing the original set: - /// /// ``` /// #![feature(btree_extract_if)] /// use std::collections::BTreeSet; /// + /// // Splitting a set into even and odd values, reusing the original set: /// let mut set: BTreeSet = (0..8).collect(); /// let evens: BTreeSet<_> = set.extract_if(.., |v| v % 2 == 0).collect(); /// let odds = set; /// assert_eq!(evens.into_iter().collect::>(), vec![0, 2, 4, 6]); /// assert_eq!(odds.into_iter().collect::>(), vec![1, 3, 5, 7]); /// - /// let mut map: BTreeSet = (0..8).collect(); - /// let low: BTreeSet<_> = map.extract_if(0..4, |_v| true).collect(); - /// let high = map; + /// // Splitting a set into low and high halves, reusing the original set: + /// let mut set: BTreeSet = (0..8).collect(); + /// let low: BTreeSet<_> = set.extract_if(0..4, |_v| true).collect(); + /// let high = set; /// assert_eq!(low.into_iter().collect::>(), [0, 1, 2, 3]); /// assert_eq!(high.into_iter().collect::>(), [4, 5, 6, 7]); /// ``` -- cgit 1.4.1-3-g733a5 From 19e02c82119cf25f92fe6325d7caa483fa84b4bb Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 2 Jun 2025 10:19:58 -0700 Subject: Remove bootstrap cfgs from library/ --- library/core/src/intrinsics/mod.rs | 48 ++++++-------------------------- library/core/src/lib.rs | 2 -- library/core/src/macros/mod.rs | 2 -- library/core/src/slice/index.rs | 57 +++----------------------------------- library/core/src/sync/atomic.rs | 17 ------------ library/coretests/tests/num/mod.rs | 6 ---- library/std/src/lib.rs | 3 +- 7 files changed, 13 insertions(+), 122 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index d147cf889cc..bde90464acb 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -413,38 +413,7 @@ pub unsafe fn atomic_cxchgweak_seqcst_seqcst(dst: *mut T, old: T, src: /// [`atomic`] types via the `load` method. For example, [`AtomicBool::load`]. #[rustc_intrinsic] #[rustc_nounwind] -#[cfg(not(bootstrap))] pub unsafe fn atomic_load(src: *const T) -> T; -/// Loads the current value of the pointer. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `load` method by passing -/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::load`]. -#[rustc_intrinsic] -#[rustc_nounwind] -#[cfg(bootstrap)] -pub unsafe fn atomic_load_seqcst(src: *const T) -> T; -/// Loads the current value of the pointer. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `load` method by passing -/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::load`]. -#[rustc_intrinsic] -#[rustc_nounwind] -#[cfg(bootstrap)] -pub unsafe fn atomic_load_acquire(src: *const T) -> T; -/// Loads the current value of the pointer. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `load` method by passing -/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::load`]. -#[rustc_intrinsic] -#[rustc_nounwind] -#[cfg(bootstrap)] -pub unsafe fn atomic_load_relaxed(src: *const T) -> T; /// Stores the value at the specified memory location. /// `T` must be an integer or pointer type. @@ -1767,7 +1736,6 @@ pub const unsafe fn arith_offset(dst: *const T, offset: isize) -> *const T; /// - `index < PtrMetadata(slice_ptr)`, so the indexing is in-bounds for the slice /// - the resulting offsetting is in-bounds of the allocated object, which is /// always the case for references, but needs to be upheld manually for pointers -#[cfg(not(bootstrap))] #[rustc_nounwind] #[rustc_intrinsic] pub const unsafe fn slice_get_unchecked< @@ -3710,7 +3678,7 @@ pub const fn minnumf128(x: f128, y: f128) -> f128; /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[rustc_nounwind] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[rustc_intrinsic] pub const fn minimumf16(x: f16, y: f16) -> f16 { if x < y { x @@ -3731,7 +3699,7 @@ pub const fn minimumf16(x: f16, y: f16) -> f16 { /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[rustc_nounwind] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[rustc_intrinsic] pub const fn minimumf32(x: f32, y: f32) -> f32 { if x < y { x @@ -3752,7 +3720,7 @@ pub const fn minimumf32(x: f32, y: f32) -> f32 { /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[rustc_nounwind] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[rustc_intrinsic] pub const fn minimumf64(x: f64, y: f64) -> f64 { if x < y { x @@ -3773,7 +3741,7 @@ pub const fn minimumf64(x: f64, y: f64) -> f64 { /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[rustc_nounwind] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[rustc_intrinsic] pub const fn minimumf128(x: f128, y: f128) -> f128 { if x < y { x @@ -3848,7 +3816,7 @@ pub const fn maxnumf128(x: f128, y: f128) -> f128; /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[rustc_nounwind] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[rustc_intrinsic] pub const fn maximumf16(x: f16, y: f16) -> f16 { if x > y { x @@ -3868,7 +3836,7 @@ pub const fn maximumf16(x: f16, y: f16) -> f16 { /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[rustc_nounwind] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[rustc_intrinsic] pub const fn maximumf32(x: f32, y: f32) -> f32 { if x > y { x @@ -3888,7 +3856,7 @@ pub const fn maximumf32(x: f32, y: f32) -> f32 { /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[rustc_nounwind] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[rustc_intrinsic] pub const fn maximumf64(x: f64, y: f64) -> f64 { if x > y { x @@ -3908,7 +3876,7 @@ pub const fn maximumf64(x: f64, y: f64) -> f64 { /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[rustc_nounwind] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[rustc_intrinsic] pub const fn maximumf128(x: f128, y: f128) -> f128 { if x > y { x diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 989ab80b77d..f2a5c40bada 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -187,7 +187,6 @@ // // Target features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(avx512_target_feature))] #![feature(aarch64_unstable_target_feature)] #![feature(arm_target_feature)] #![feature(hexagon_target_feature)] @@ -225,7 +224,6 @@ pub mod assert_matches { // We don't export this through #[macro_export] for now, to avoid breakage. #[unstable(feature = "autodiff", issue = "124509")] -#[cfg(not(bootstrap))] /// Unstable module containing the unstable `autodiff` macro. pub mod autodiff { #[unstable(feature = "autodiff", issue = "124509")] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index e70a1dab6e9..d5efb03cfbc 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1533,7 +1533,6 @@ pub(crate) mod builtin { #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] - #[cfg(not(bootstrap))] pub macro autodiff_forward($item:item) { /* compiler built-in */ } @@ -1552,7 +1551,6 @@ pub(crate) mod builtin { #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] - #[cfg(not(bootstrap))] pub macro autodiff_reverse($item:item) { /* compiler built-in */ } diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 69160a911b2..f725c3fdd94 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -1,6 +1,5 @@ //! Indexing implementations for `[T]`. -#[cfg(not(bootstrap))] use crate::intrinsics::slice_get_unchecked; use crate::panic::const_panic; use crate::ub_checks::assert_unsafe_precondition; @@ -85,22 +84,6 @@ const fn slice_end_index_overflow_fail() -> ! { // Both the safe and unsafe public methods share these helpers, // which use intrinsics directly to get *no* extra checks. -#[cfg(bootstrap)] -#[inline(always)] -const unsafe fn get_noubcheck(ptr: *const [T], index: usize) -> *const T { - let ptr = ptr as *const T; - // SAFETY: The caller already checked these preconditions - unsafe { crate::intrinsics::offset(ptr, index) } -} - -#[cfg(bootstrap)] -#[inline(always)] -const unsafe fn get_mut_noubcheck(ptr: *mut [T], index: usize) -> *mut T { - let ptr = ptr as *mut T; - // SAFETY: The caller already checked these preconditions - unsafe { crate::intrinsics::offset(ptr, index) } -} - #[inline(always)] const unsafe fn get_offset_len_noubcheck( ptr: *const [T], @@ -231,16 +214,8 @@ unsafe impl SliceIndex<[T]> for usize { #[inline] fn get(self, slice: &[T]) -> Option<&T> { if self < slice.len() { - #[cfg(bootstrap)] - // SAFETY: `self` is checked to be in bounds. - unsafe { - Some(&*get_noubcheck(slice, self)) - } - #[cfg(not(bootstrap))] // SAFETY: `self` is checked to be in bounds. - unsafe { - Some(slice_get_unchecked(slice, self)) - } + unsafe { Some(slice_get_unchecked(slice, self)) } } else { None } @@ -249,16 +224,8 @@ unsafe impl SliceIndex<[T]> for usize { #[inline] fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { if self < slice.len() { - #[cfg(bootstrap)] // SAFETY: `self` is checked to be in bounds. - unsafe { - Some(&mut *get_mut_noubcheck(slice, self)) - } - #[cfg(not(bootstrap))] - // SAFETY: `self` is checked to be in bounds. - unsafe { - Some(slice_get_unchecked(slice, self)) - } + unsafe { Some(slice_get_unchecked(slice, self)) } } else { None } @@ -280,14 +247,7 @@ unsafe impl SliceIndex<[T]> for usize { // Use intrinsics::assume instead of hint::assert_unchecked so that we don't check the // precondition of this function twice. crate::intrinsics::assume(self < slice.len()); - #[cfg(bootstrap)] - { - get_noubcheck(slice, self) - } - #[cfg(not(bootstrap))] - { - slice_get_unchecked(slice, self) - } + slice_get_unchecked(slice, self) } } @@ -300,16 +260,7 @@ unsafe impl SliceIndex<[T]> for usize { (this: usize = self, len: usize = slice.len()) => this < len ); // SAFETY: see comments for `get_unchecked` above. - unsafe { - #[cfg(bootstrap)] - { - get_mut_noubcheck(slice, self) - } - #[cfg(not(bootstrap))] - { - slice_get_unchecked(slice, self) - } - } + unsafe { slice_get_unchecked(slice, self) } } #[inline] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index b43f3bad6e2..ea459f6d92d 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -3822,23 +3822,6 @@ unsafe fn atomic_store(dst: *mut T, val: T, order: Ordering) { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -#[cfg(bootstrap)] -unsafe fn atomic_load(dst: *const T, order: Ordering) -> T { - // SAFETY: the caller must uphold the safety contract for `atomic_load`. - unsafe { - match order { - Relaxed => intrinsics::atomic_load_relaxed(dst), - Acquire => intrinsics::atomic_load_acquire(dst), - SeqCst => intrinsics::atomic_load_seqcst(dst), - Release => panic!("there is no such thing as a release load"), - AcqRel => panic!("there is no such thing as an acquire-release load"), - } - } -} - -#[inline] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -#[cfg(not(bootstrap))] unsafe fn atomic_load(dst: *const T, order: Ordering) -> T { use intrinsics::AtomicOrdering; // SAFETY: the caller must uphold the safety contract for `atomic_load`. diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs index fa05bbdd9b7..c68b569f86b 100644 --- a/library/coretests/tests/num/mod.rs +++ b/library/coretests/tests/num/mod.rs @@ -951,7 +951,6 @@ macro_rules! test_float { assert!(<$fty>::NAN.div_euclid(<$fty>::INFINITY).is_nan()); } #[test] - #[cfg(not(bootstrap))] fn floor() { $fassert!((0.0 as $fty).floor(), 0.0); $fassert!((0.0 as $fty).floor().is_sign_positive()); @@ -969,7 +968,6 @@ macro_rules! test_float { $fassert!(<$fty>::NEG_INFINITY.floor(), <$fty>::NEG_INFINITY); } #[test] - #[cfg(not(bootstrap))] fn ceil() { $fassert!((0.0 as $fty).ceil(), 0.0); $fassert!((0.0 as $fty).ceil().is_sign_positive()); @@ -986,7 +984,6 @@ macro_rules! test_float { $fassert!(<$fty>::NEG_INFINITY.ceil(), <$fty>::NEG_INFINITY); } #[test] - #[cfg(not(bootstrap))] fn round() { $fassert!((0.0 as $fty).round(), 0.0); $fassert!((0.0 as $fty).round().is_sign_positive()); @@ -1003,7 +1000,6 @@ macro_rules! test_float { $fassert!(<$fty>::NEG_INFINITY.round(), <$fty>::NEG_INFINITY); } #[test] - #[cfg(not(bootstrap))] fn round_ties_even() { $fassert!((0.0 as $fty).round_ties_even(), 0.0); $fassert!((0.0 as $fty).round_ties_even().is_sign_positive()); @@ -1022,7 +1018,6 @@ macro_rules! test_float { $fassert!(<$fty>::NEG_INFINITY.round_ties_even(), <$fty>::NEG_INFINITY); } #[test] - #[cfg(not(bootstrap))] fn trunc() { $fassert!((0.0 as $fty).trunc(), 0.0); $fassert!((0.0 as $fty).trunc().is_sign_positive()); @@ -1041,7 +1036,6 @@ macro_rules! test_float { $fassert!(<$fty>::NEG_INFINITY.trunc(), <$fty>::NEG_INFINITY); } #[test] - #[cfg(not(bootstrap))] fn fract() { $fassert!((0.0 as $fty).fract(), 0.0); $fassert!((0.0 as $fty).fract().is_sign_positive()); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 74a34339860..f729c2ab433 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -276,12 +276,12 @@ // tidy-alphabetical-start // stabilization was reverted after it hit beta -#![cfg_attr(not(bootstrap), feature(autodiff))] #![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(asm_experimental_arch)] +#![feature(autodiff)] #![feature(cfg_sanitizer_cfi)] #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] @@ -641,7 +641,6 @@ pub mod simd { } #[unstable(feature = "autodiff", issue = "124509")] -#[cfg(not(bootstrap))] /// This module provides support for automatic differentiation. pub mod autodiff { /// This macro handles automatic differentiation. -- cgit 1.4.1-3-g733a5 From 53e0232edecedb2640c361ab33069cbbb4e20a66 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 2 Jun 2025 21:22:25 +0200 Subject: Enable triagebot `[concern]` functionality --- triagebot.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index a8d529cae77..2bd0c185ad7 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1441,3 +1441,8 @@ days-threshold = 14 # Prevents mentions in commits to avoid users being spammed # Documentation at: https://forge.rust-lang.org/triagebot/no-mentions.html [no-mentions] + +# Allow members to formally register concerns (`@rustbot concern my concern`) +# Documentation at: https://forge.rust-lang.org/triagebot/concern.html +[concern] +labels = ["S-waiting-on-concerns"] -- cgit 1.4.1-3-g733a5 From 3418d5db3aa619f19f59f4ee341f6683ed6743b4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 28 May 2025 11:14:43 +0000 Subject: Fast path for stalled obligations on self ty --- compiler/rustc_infer/src/infer/opaque_types/table.rs | 2 +- compiler/rustc_trait_selection/src/solve/delegate.rs | 10 ++++++++++ .../next-solver/coherence/coherence-fulfill-overflow.stderr | 7 ++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index ab65da3913d..df5a66243fc 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -53,7 +53,7 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { assert!(entry.is_some()); } - pub(crate) fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; opaque_types.is_empty() && duplicate_entries.is_empty() } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index e92e37b8738..406acdb7d88 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -64,6 +64,16 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< span: Span, ) -> Option { if let Some(trait_pred) = goal.predicate.as_trait_clause() { + if self.shallow_resolve(trait_pred.self_ty().skip_binder()).is_ty_var() + // We don't do this fast path when opaques are defined since we may + // eventually use opaques to incompletely guide inference via ty var + // self types. + // FIXME: Properly consider opaques here. + && self.inner.borrow_mut().opaque_types().is_empty() + { + return Some(Certainty::AMBIGUOUS); + } + if trait_pred.polarity() == ty::PredicatePolarity::Positive { match self.0.tcx.as_lang_item(trait_pred.def_id()) { Some(LangItem::Sized) diff --git a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr index 57cba790b55..7d39c82d22f 100644 --- a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr +++ b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr @@ -1,13 +1,10 @@ -error[E0119]: conflicting implementations of trait `Trait` for type `W>>>>>>>>>>>>>>>>>>>>` +error[E0119]: conflicting implementations of trait `Trait` for type `W>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/coherence-fulfill-overflow.rs:12:1 | LL | impl Trait for W {} | ------------------------------------- first implementation here LL | impl Trait for T {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W>>>>>>>>>>>>>>>>>>>>` - | - = note: overflow evaluating the requirement `W>>>>>>>>>>>>>>>>>>>>: TwoW` - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W>>>>>>>>>>>>>>>>>>>>>>` error: aborting due to 1 previous error -- cgit 1.4.1-3-g733a5 From 9899464906c577ae39e267d1cfb6f55cbe6067cc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 28 May 2025 22:33:57 +0000 Subject: Fast path for subtype and coercion goals --- compiler/rustc_trait_selection/src/solve/delegate.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 406acdb7d88..69a0c0809b5 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -125,6 +125,17 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< Some(Certainty::Yes) } + ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, .. }) + | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { + if self.shallow_resolve(a).is_ty_var() && self.shallow_resolve(b).is_ty_var() { + // FIXME: We also need to register a subtype relation between these vars + // when those are added, and if they aren't in the same sub root then + // we should mark this goal as `has_changed`. + Some(Certainty::AMBIGUOUS) + } else { + None + } + } _ => None, } } -- cgit 1.4.1-3-g733a5 From ba7cdb681468ef7617bfa5a2bde7e3fb3d79a2be Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 1 Jun 2025 19:52:57 +0000 Subject: ci: Refactor benchmark regression checks iai-callgrind now correctly exits with error if regressions were found [1], so we no longer need to check for regressions manually. Remove this check and instead exit based on the exit status of the benchmark run. [1] https://github.com/iai-callgrind/iai-callgrind/issues/337 --- library/compiler-builtins/ci/bench-icount.sh | 19 ++++--- library/compiler-builtins/ci/ci-util.py | 84 +++++++--------------------- 2 files changed, 29 insertions(+), 74 deletions(-) diff --git a/library/compiler-builtins/ci/bench-icount.sh b/library/compiler-builtins/ci/bench-icount.sh index 5b6974fe420..5724955fe36 100755 --- a/library/compiler-builtins/ci/bench-icount.sh +++ b/library/compiler-builtins/ci/bench-icount.sh @@ -46,17 +46,18 @@ function run_icount_benchmarks() { shift done - # Run iai-callgrind benchmarks - cargo bench "${cargo_args[@]}" -- "${iai_args[@]}" + # Run iai-callgrind benchmarks. Do this in a subshell with `&& true` to + # capture rather than exit on error. + (cargo bench "${cargo_args[@]}" -- "${iai_args[@]}") && true + exit_code="$?" - # NB: iai-callgrind should exit on error but does not, so we inspect the sumary - # for errors. See https://github.com/iai-callgrind/iai-callgrind/issues/337 - if [ -n "${PR_NUMBER:-}" ]; then - # If this is for a pull request, ignore regressions if specified. - ./ci/ci-util.py check-regressions --home "$iai_home" --allow-pr-override "$PR_NUMBER" - else + if [ "$exit_code" -eq 0 ]; then + echo "Benchmarks completed with no regressions" + elif [ -z "${PR_NUMBER:-}" ]; then # Disregard regressions after merge - ./ci/ci-util.py check-regressions --home "$iai_home" || true + echo "Benchmarks completed with regressions; ignoring (not in a PR)" + else + ./ci/ci-util.py handle-banch-regressions "$PR_NUMBER" fi } diff --git a/library/compiler-builtins/ci/ci-util.py b/library/compiler-builtins/ci/ci-util.py index 6c8b439805b..3437d304f48 100755 --- a/library/compiler-builtins/ci/ci-util.py +++ b/library/compiler-builtins/ci/ci-util.py @@ -11,7 +11,7 @@ import re import subprocess as sp import sys from dataclasses import dataclass -from glob import glob, iglob +from glob import glob from inspect import cleandoc from os import getenv from pathlib import Path @@ -38,14 +38,10 @@ USAGE = cleandoc( Note that `--extract` will overwrite files in `iai-home`. - check-regressions [--home iai-home] [--allow-pr-override pr_number] - Check `iai-home` (or `iai-home` if unspecified) for `summary.json` - files and see if there are any regressions. This is used as a workaround - for `iai-callgrind` not exiting with error status; see - . - - If `--allow-pr-override` is specified, the regression check will not exit - with failure if any line in the PR starts with `allow-regressions`. + handle-bench-regressions PR_NUMBER + Exit with success if the pull request contains a line starting with + `ci: allow-regressions`, indicating that regressions in benchmarks should + be accepted. Otherwise, exit 1. """ ) @@ -365,64 +361,22 @@ def locate_baseline(flags: list[str]) -> None: eprint("baseline extracted successfully") -def check_iai_regressions(args: list[str]): - """Find regressions in iai summary.json files, exit with failure if any are - found. - """ - - iai_home_str = "iai-home" - pr_number = None - - while len(args) > 0: - match args: - case ["--home", home, *rest]: - iai_home_str = home - args = rest - case ["--allow-pr-override", pr_num, *rest]: - pr_number = pr_num - args = rest - case _: - eprint(USAGE) - exit(1) - - iai_home = Path(iai_home_str) - - found_summaries = False - regressions: list[dict] = [] - for summary_path in iglob("**/summary.json", root_dir=iai_home, recursive=True): - found_summaries = True - with open(iai_home / summary_path, "r") as f: - summary = json.load(f) - - summary_regs = [] - run = summary["callgrind_summary"]["callgrind_run"] - fname = summary["function_name"] - id = summary["id"] - name_entry = {"name": f"{fname}.{id}"} - - for segment in run["segments"]: - summary_regs.extend(segment["regressions"]) +def handle_bench_regressions(args: list[str]): + """Exit with error unless the PR message contains an ignore directive.""" - summary_regs.extend(run["total"]["regressions"]) - - regressions.extend(name_entry | reg for reg in summary_regs) - - if not found_summaries: - eprint(f"did not find any summary.json files within {iai_home}") - exit(1) + match args: + case [pr_number]: + pr_number = pr_number + case _: + eprint(USAGE) + exit(1) - if len(regressions) == 0: - eprint("No regressions found") + pr = PrInfo.load(pr_number) + if pr.contains_directive(REGRESSION_DIRECTIVE): + eprint("PR allows regressions") return - eprint("Found regressions:", json.dumps(regressions, indent=4)) - - if pr_number is not None: - pr = PrInfo.load(pr_number) - if pr.contains_directive(REGRESSION_DIRECTIVE): - eprint("PR allows regressions, returning") - return - + eprint("Regressions were found; benchmark failed") exit(1) @@ -433,8 +387,8 @@ def main(): ctx.emit_workflow_output() case ["locate-baseline", *flags]: locate_baseline(flags) - case ["check-regressions", *args]: - check_iai_regressions(args) + case ["handle-bench-regressions", *args]: + handle_bench_regressions(args) case ["--help" | "-h"]: print(USAGE) exit() -- cgit 1.4.1-3-g733a5 From c87b072952b75f2cfb05882efca49c58894f20aa Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 2 Jun 2025 14:30:00 -0700 Subject: Remove more library bootstrap --- library/alloc/Cargo.toml | 1 - library/alloc/src/lib.rs | 1 - library/alloctests/Cargo.toml | 1 - library/core/Cargo.toml | 1 - library/core/src/pin.rs | 1 - library/std/Cargo.toml | 1 - library/std/src/lib.rs | 7 +------ 7 files changed, 1 insertion(+), 12 deletions(-) diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 365c9dc00df..31b6014af7c 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -32,7 +32,6 @@ optimize_for_size = ["core/optimize_for_size"] [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - 'cfg(bootstrap)', 'cfg(no_global_oom_handling)', 'cfg(no_rc)', 'cfg(no_sync)', diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index abda5aefab6..30540f48aa1 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -66,7 +66,6 @@ )] #![doc(cfg_hide( not(test), - not(any(test, bootstrap)), no_global_oom_handling, not(no_global_oom_handling), not(no_rc), diff --git a/library/alloctests/Cargo.toml b/library/alloctests/Cargo.toml index 306375f5f01..07c45d1b824 100644 --- a/library/alloctests/Cargo.toml +++ b/library/alloctests/Cargo.toml @@ -39,7 +39,6 @@ harness = false [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - 'cfg(bootstrap)', 'cfg(no_global_oom_handling)', 'cfg(no_rc)', 'cfg(no_sync)', diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index 83ba17b93f5..f88661ee001 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -29,7 +29,6 @@ debug_typeid = [] [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - 'cfg(bootstrap)', 'cfg(no_fp_fmt_parse)', # core use #[path] imports to portable-simd `core_simd` crate # and to stdarch `core_arch` crate which messes-up with Cargo list diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index aad073cc8cd..ba687434bf1 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1092,7 +1092,6 @@ pub use self::unsafe_pinned::UnsafePinned; #[rustc_pub_transparent] #[derive(Copy, Clone)] pub struct Pin { - /// Only public for bootstrap. pointer: Ptr, } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 31371f06b38..196b904d56a 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -157,7 +157,6 @@ test = true [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - 'cfg(bootstrap)', # std use #[path] imports to portable-simd `std_float` crate # and to the `backtrace` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index f729c2ab433..7c54e731edc 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -235,12 +235,7 @@ test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] #![doc(rust_logo)] -#![doc(cfg_hide( - not(test), - not(any(test, bootstrap)), - no_global_oom_handling, - not(no_global_oom_handling) -))] +#![doc(cfg_hide(not(test), no_global_oom_handling, not(no_global_oom_handling)))] // Don't link to std. We are std. #![no_std] // Tell the compiler to link to either panic_abort or panic_unwind -- cgit 1.4.1-3-g733a5 From 57786431746f495f4205e26ee1badd142a380fff Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 2 Jun 2025 20:20:23 +0000 Subject: libm-test: Fix unintentional skips in `binop_common` `binop_common` emits a `SKIP` that is intended to apply only to `copysign`, but is instead applying to all binary operators. Correct the general case but leave the currently-failing `maximum_num` tests as a FIXME, to be resolved separately in [1]. Also simplify skip logic and NaN checking, and add a few more `copysign` checks. [1]: https://github.com/rust-lang/compiler-builtins/pull/939 --- .../libm-test/src/generate/edge_cases.rs | 1 + library/compiler-builtins/libm-test/src/precision.rs | 15 ++++++++++----- .../compiler-builtins/libm-test/src/test_traits.rs | 20 ++++++++++++++------ library/compiler-builtins/libm/src/math/copysign.rs | 10 +++++++++- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs index 2fb0746388c..4e4a782a169 100644 --- a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs +++ b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs @@ -51,6 +51,7 @@ where // Check some special values that aren't included in the above ranges values.push(Op::FTy::NAN); + values.push(Op::FTy::NEG_NAN); values.extend(Op::FTy::consts().iter()); // Check around the maximum subnormal value diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index f6cdd015a59..32825b15d47 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -444,13 +444,18 @@ fn binop_common( expected: F2, ctx: &CheckCtx, ) -> CheckAction { - // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. Skip if - // the first input (magnitude source) is NaN and the output is also a NaN, or if the second - // input (sign source) is NaN. - if ctx.basis == CheckBasis::Mpfr + // MPFR only has one NaN bitpattern; skip tests in cases where the first argument would take + // the sign of a NaN second argument. The default NaN checks cover other cases. + if ctx.base_name == BaseName::Copysign && ctx.basis == CheckBasis::Mpfr && input.1.is_nan() { + return SKIP; + } + + // FIXME(#939): this should not be skipped, there is a bug in our implementationi. + if ctx.base_name == BaseName::FmaximumNum + && ctx.basis == CheckBasis::Mpfr && ((input.0.is_nan() && actual.is_nan() && expected.is_nan()) || input.1.is_nan()) { - return SKIP; + return XFAIL_NOCHECK; } /* FIXME(#439): our fmin and fmax do not compare signed zeros */ diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index 2af6af60ba2..278274d917b 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -312,12 +312,9 @@ where let mut inner = || -> TestResult { let mut allowed_ulp = ctx.ulp; - // Forbid overrides if the items came from an explicit list, as long as we are checking - // against either MPFR or the result itself. - let require_biteq = ctx.gen_kind == GeneratorKind::List && ctx.basis != CheckBasis::Musl; - match SpecialCase::check_float(input, actual, expected, ctx) { - _ if require_biteq => (), + // Forbid overrides if the items came from an explicit list + _ if ctx.gen_kind == GeneratorKind::List => (), CheckAction::AssertSuccess => (), CheckAction::AssertFailure(msg) => assert_failure_msg = Some(msg), CheckAction::Custom(res) => return res, @@ -327,9 +324,20 @@ where // Check when both are NaNs if actual.is_nan() && expected.is_nan() { - if require_biteq && ctx.basis == CheckBasis::None { + // Don't assert NaN bitwise equality if: + // + // * Testing against MPFR (there is a single NaN representation) + // * Testing against Musl except for explicit tests (Musl does some NaN quieting) + // + // In these cases, just the check that actual and expected are both NaNs is + // sufficient. + let skip_nan_biteq = ctx.basis == CheckBasis::Mpfr + || (ctx.basis == CheckBasis::Musl && ctx.gen_kind != GeneratorKind::List); + + if !skip_nan_biteq { ensure!(actual.biteq(expected), "mismatched NaN bitpatterns"); } + // By default, NaNs have nothing special to check. return Ok(()); } else if actual.is_nan() || expected.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs index d2a86e7fd54..d093d610727 100644 --- a/library/compiler-builtins/libm/src/math/copysign.rs +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -59,9 +59,17 @@ mod tests { // Not required but we expect it assert_biteq!(f(F::NAN, F::NAN), F::NAN); - assert_biteq!(f(F::NEG_NAN, F::NAN), F::NAN); + assert_biteq!(f(F::NAN, F::ONE), F::NAN); + assert_biteq!(f(F::NAN, F::NEG_ONE), F::NEG_NAN); assert_biteq!(f(F::NAN, F::NEG_NAN), F::NEG_NAN); + assert_biteq!(f(F::NEG_NAN, F::NAN), F::NAN); + assert_biteq!(f(F::NEG_NAN, F::ONE), F::NAN); + assert_biteq!(f(F::NEG_NAN, F::NEG_ONE), F::NEG_NAN); assert_biteq!(f(F::NEG_NAN, F::NEG_NAN), F::NEG_NAN); + assert_biteq!(f(F::ONE, F::NAN), F::ONE); + assert_biteq!(f(F::ONE, F::NEG_NAN), F::NEG_ONE); + assert_biteq!(f(F::NEG_ONE, F::NAN), F::ONE); + assert_biteq!(f(F::NEG_ONE, F::NEG_NAN), F::NEG_ONE); } #[test] -- cgit 1.4.1-3-g733a5 From aff21f659f5abeba49b05368affd8c829807b1f1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 20 May 2025 13:31:31 +0000 Subject: compiler-builtins: Eliminate symlinks compiler-builtins has a symlink to the `libm` source directory so the two crates can share files but still act as two separate crates. This causes problems with some sysroot-related tooling, however, since directory symlinks seem to not be supported. The reason this was a symlink in the first place is that there isn't an easy for Cargo to publish two crates that share source (building works fine but publishing rejects `include`d files from parent directories, as well as nested package roots). However, after the switch to a subtree, we no longer need to publish compiler-builtins; this means that we can eliminate the link and just use `#[path]`. Similarly, the LICENSE file was symlinked so it could live in the repository root but be included in the package. This is also removed as it caused problems with the dist job (error from bootstrap's `tarball.rs`, "generated a symlink in a tarball"). If we need to publish compiler-builtins again for any reason, it would be easy to revert these changes in a preprocess step. --- library/compiler-builtins/compiler-builtins/LICENSE.txt | 1 - library/compiler-builtins/compiler-builtins/src/math/libm_math | 1 - library/compiler-builtins/compiler-builtins/src/math/mod.rs | 1 + 3 files changed, 1 insertion(+), 2 deletions(-) delete mode 120000 library/compiler-builtins/compiler-builtins/LICENSE.txt delete mode 120000 library/compiler-builtins/compiler-builtins/src/math/libm_math diff --git a/library/compiler-builtins/compiler-builtins/LICENSE.txt b/library/compiler-builtins/compiler-builtins/LICENSE.txt deleted file mode 120000 index 4ab43736a83..00000000000 --- a/library/compiler-builtins/compiler-builtins/LICENSE.txt +++ /dev/null @@ -1 +0,0 @@ -../LICENSE.txt \ No newline at end of file diff --git a/library/compiler-builtins/compiler-builtins/src/math/libm_math b/library/compiler-builtins/compiler-builtins/src/math/libm_math deleted file mode 120000 index 4d65313c232..00000000000 --- a/library/compiler-builtins/compiler-builtins/src/math/libm_math +++ /dev/null @@ -1 +0,0 @@ -../../../libm/src/math \ No newline at end of file diff --git a/library/compiler-builtins/compiler-builtins/src/math/mod.rs b/library/compiler-builtins/compiler-builtins/src/math/mod.rs index 078feb9ff9e..62d72967410 100644 --- a/library/compiler-builtins/compiler-builtins/src/math/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/math/mod.rs @@ -2,6 +2,7 @@ #[allow(dead_code)] #[allow(unused_imports)] #[allow(clippy::all)] +#[path = "../../../libm/src/math/mod.rs"] pub(crate) mod libm_math; macro_rules! libm_intrinsics { -- cgit 1.4.1-3-g733a5 From e7e884b0a4b5f012864562b0bb550d80d3e5f03b Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Sun, 1 Jun 2025 00:03:54 +0500 Subject: cleaned up some tests --- .../autoderef-vec-to-slice-by-value.rs | 18 ++++++++++ tests/ui/bind-by-move.rs | 13 ------- tests/ui/bitwise.rs | 34 ------------------ tests/ui/bogus-tag.rs | 10 ------ tests/ui/bogus-tag.stderr | 12 ------- tests/ui/borrow-by-val-method-receiver.rs | 14 -------- tests/ui/bounds-lifetime.rs | 7 ---- tests/ui/bounds-lifetime.stderr | 41 ---------------------- .../higher-ranked/higher-ranked-invalid-bounds.rs | 9 +++++ .../higher-ranked-invalid-bounds.stderr | 41 ++++++++++++++++++++++ .../ui/numbers-arithmetic/bitwise-ops-platform.rs | 36 +++++++++++++++++++ tests/ui/pattern/pattern-match-arc-move.rs | 15 ++++++++ tests/ui/pattern/pattern-match-invalid-variant.rs | 19 ++++++++++ .../pattern/pattern-match-invalid-variant.stderr | 12 +++++++ 14 files changed, 150 insertions(+), 131 deletions(-) create mode 100644 tests/ui/autoref-autoderef/autoderef-vec-to-slice-by-value.rs delete mode 100644 tests/ui/bind-by-move.rs delete mode 100644 tests/ui/bitwise.rs delete mode 100644 tests/ui/bogus-tag.rs delete mode 100644 tests/ui/bogus-tag.stderr delete mode 100644 tests/ui/borrow-by-val-method-receiver.rs delete mode 100644 tests/ui/bounds-lifetime.rs delete mode 100644 tests/ui/bounds-lifetime.stderr create mode 100644 tests/ui/higher-ranked/higher-ranked-invalid-bounds.rs create mode 100644 tests/ui/higher-ranked/higher-ranked-invalid-bounds.stderr create mode 100644 tests/ui/numbers-arithmetic/bitwise-ops-platform.rs create mode 100644 tests/ui/pattern/pattern-match-arc-move.rs create mode 100644 tests/ui/pattern/pattern-match-invalid-variant.rs create mode 100644 tests/ui/pattern/pattern-match-invalid-variant.stderr diff --git a/tests/ui/autoref-autoderef/autoderef-vec-to-slice-by-value.rs b/tests/ui/autoref-autoderef/autoderef-vec-to-slice-by-value.rs new file mode 100644 index 00000000000..4d67c3a6733 --- /dev/null +++ b/tests/ui/autoref-autoderef/autoderef-vec-to-slice-by-value.rs @@ -0,0 +1,18 @@ +//! Tests that a `Vec` can call a method defined in a trait (`Foo`) +//! implemented for `&[isize]` with a by-value receiver (`self`), relying on auto-dereferencing +//! from `Vec` to `&[isize]` during method resolution. + +//@ run-pass + +trait Foo { + fn foo(self); +} + +impl<'a> Foo for &'a [isize] { + fn foo(self) {} +} + +pub fn main() { + let items = vec![ 3, 5, 1, 2, 4 ]; + items.foo(); +} diff --git a/tests/ui/bind-by-move.rs b/tests/ui/bind-by-move.rs deleted file mode 100644 index 99f3536e533..00000000000 --- a/tests/ui/bind-by-move.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass - -use std::sync::Arc; -fn dispose(_x: Arc) { } - -pub fn main() { - let p = Arc::new(true); - let x = Some(p); - match x { - Some(z) => { dispose(z); }, - None => panic!() - } -} diff --git a/tests/ui/bitwise.rs b/tests/ui/bitwise.rs deleted file mode 100644 index 0779e7f229c..00000000000 --- a/tests/ui/bitwise.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@ run-pass - -#[cfg(any(target_pointer_width = "32"))] -fn target() { - assert_eq!(-1000isize as usize >> 3_usize, 536870787_usize); -} - -#[cfg(any(target_pointer_width = "64"))] -fn target() { - assert_eq!(-1000isize as usize >> 3_usize, 2305843009213693827_usize); -} - -fn general() { - let mut a: isize = 1; - let mut b: isize = 2; - a ^= b; - b ^= a; - a = a ^ b; - println!("{}", a); - println!("{}", b); - assert_eq!(b, 1); - assert_eq!(a, 2); - assert_eq!(!0xf0_isize & 0xff, 0xf); - assert_eq!(0xf0_isize | 0xf, 0xff); - assert_eq!(0xf_isize << 4, 0xf0); - assert_eq!(0xf0_isize >> 4, 0xf); - assert_eq!(-16 >> 2, -4); - assert_eq!(0b1010_1010_isize | 0b0101_0101, 0xff); -} - -pub fn main() { - general(); - target(); -} diff --git a/tests/ui/bogus-tag.rs b/tests/ui/bogus-tag.rs deleted file mode 100644 index c594385eec2..00000000000 --- a/tests/ui/bogus-tag.rs +++ /dev/null @@ -1,10 +0,0 @@ -enum Color { Rgb(isize, isize, isize), Rgba(isize, isize, isize, isize), } - -fn main() { - let red: Color = Color::Rgb(255, 0, 0); - match red { - Color::Rgb(r, g, b) => { println!("rgb"); } - Color::Hsl(h, s, l) => { println!("hsl"); } - //~^ ERROR no variant - } -} diff --git a/tests/ui/bogus-tag.stderr b/tests/ui/bogus-tag.stderr deleted file mode 100644 index d94bd489ec6..00000000000 --- a/tests/ui/bogus-tag.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0599]: no variant or associated item named `Hsl` found for enum `Color` in the current scope - --> $DIR/bogus-tag.rs:7:16 - | -LL | enum Color { Rgb(isize, isize, isize), Rgba(isize, isize, isize, isize), } - | ---------- variant or associated item `Hsl` not found for this enum -... -LL | Color::Hsl(h, s, l) => { println!("hsl"); } - | ^^^ variant or associated item not found in `Color` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/borrow-by-val-method-receiver.rs b/tests/ui/borrow-by-val-method-receiver.rs deleted file mode 100644 index aee1108d96d..00000000000 --- a/tests/ui/borrow-by-val-method-receiver.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ run-pass - -trait Foo { - fn foo(self); -} - -impl<'a> Foo for &'a [isize] { - fn foo(self) {} -} - -pub fn main() { - let items = vec![ 3, 5, 1, 2, 4 ]; - items.foo(); -} diff --git a/tests/ui/bounds-lifetime.rs b/tests/ui/bounds-lifetime.rs deleted file mode 100644 index f26976066ac..00000000000 --- a/tests/ui/bounds-lifetime.rs +++ /dev/null @@ -1,7 +0,0 @@ -type A = for<'b, 'a: 'b> fn(); //~ ERROR bounds cannot be used in this context -type B = for<'b, 'a: 'b,> fn(); //~ ERROR bounds cannot be used in this context -type C = for<'b, 'a: 'b +> fn(); //~ ERROR bounds cannot be used in this context -type D = for<'a, T> fn(); //~ ERROR only lifetime parameters can be used in this context -type E = dyn for Fn(); //~ ERROR only lifetime parameters can be used in this context - -fn main() {} diff --git a/tests/ui/bounds-lifetime.stderr b/tests/ui/bounds-lifetime.stderr deleted file mode 100644 index 01b314f3d1b..00000000000 --- a/tests/ui/bounds-lifetime.stderr +++ /dev/null @@ -1,41 +0,0 @@ -error: bounds cannot be used in this context - --> $DIR/bounds-lifetime.rs:1:22 - | -LL | type A = for<'b, 'a: 'b> fn(); - | ^^ - -error: bounds cannot be used in this context - --> $DIR/bounds-lifetime.rs:2:22 - | -LL | type B = for<'b, 'a: 'b,> fn(); - | ^^ - -error: bounds cannot be used in this context - --> $DIR/bounds-lifetime.rs:3:22 - | -LL | type C = for<'b, 'a: 'b +> fn(); - | ^^ - -error[E0658]: only lifetime parameters can be used in this context - --> $DIR/bounds-lifetime.rs:4:18 - | -LL | type D = for<'a, T> fn(); - | ^ - | - = note: see issue #108185 for more information - = help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: only lifetime parameters can be used in this context - --> $DIR/bounds-lifetime.rs:5:18 - | -LL | type E = dyn for Fn(); - | ^ ^ - | - = note: see issue #108185 for more information - = help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/higher-ranked/higher-ranked-invalid-bounds.rs b/tests/ui/higher-ranked/higher-ranked-invalid-bounds.rs new file mode 100644 index 00000000000..be161aeb53d --- /dev/null +++ b/tests/ui/higher-ranked/higher-ranked-invalid-bounds.rs @@ -0,0 +1,9 @@ +//! Tests invalid lifetime bounds and generic parameters in higher-ranked types. + +type A = for<'b, 'a: 'b> fn(); //~ ERROR bounds cannot be used in this context +type B = for<'b, 'a: 'b,> fn(); //~ ERROR bounds cannot be used in this context +type C = for<'b, 'a: 'b +> fn(); //~ ERROR bounds cannot be used in this context +type D = for<'a, T> fn(); //~ ERROR only lifetime parameters can be used in this context +type E = dyn for Fn(); //~ ERROR only lifetime parameters can be used in this context + +fn main() {} diff --git a/tests/ui/higher-ranked/higher-ranked-invalid-bounds.stderr b/tests/ui/higher-ranked/higher-ranked-invalid-bounds.stderr new file mode 100644 index 00000000000..60ee7a7cf76 --- /dev/null +++ b/tests/ui/higher-ranked/higher-ranked-invalid-bounds.stderr @@ -0,0 +1,41 @@ +error: bounds cannot be used in this context + --> $DIR/higher-ranked-invalid-bounds.rs:3:22 + | +LL | type A = for<'b, 'a: 'b> fn(); + | ^^ + +error: bounds cannot be used in this context + --> $DIR/higher-ranked-invalid-bounds.rs:4:22 + | +LL | type B = for<'b, 'a: 'b,> fn(); + | ^^ + +error: bounds cannot be used in this context + --> $DIR/higher-ranked-invalid-bounds.rs:5:22 + | +LL | type C = for<'b, 'a: 'b +> fn(); + | ^^ + +error[E0658]: only lifetime parameters can be used in this context + --> $DIR/higher-ranked-invalid-bounds.rs:6:18 + | +LL | type D = for<'a, T> fn(); + | ^ + | + = note: see issue #108185 for more information + = help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: only lifetime parameters can be used in this context + --> $DIR/higher-ranked-invalid-bounds.rs:7:18 + | +LL | type E = dyn for Fn(); + | ^ ^ + | + = note: see issue #108185 for more information + = help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/numbers-arithmetic/bitwise-ops-platform.rs b/tests/ui/numbers-arithmetic/bitwise-ops-platform.rs new file mode 100644 index 00000000000..60d552e904b --- /dev/null +++ b/tests/ui/numbers-arithmetic/bitwise-ops-platform.rs @@ -0,0 +1,36 @@ +//! Tests bitwise operations with platform-specific and negative number behavior. + +//@ run-pass + +#[cfg(any(target_pointer_width = "32"))] +fn target() { + assert_eq!(-1000isize as usize >> 3_usize, 536870787_usize); +} + +#[cfg(any(target_pointer_width = "64"))] +fn target() { + assert_eq!(-1000isize as usize >> 3_usize, 2305843009213693827_usize); +} + +fn general() { + let mut a: isize = 1; + let mut b: isize = 2; + a ^= b; + b ^= a; + a = a ^ b; + println!("{}", a); + println!("{}", b); + assert_eq!(b, 1); + assert_eq!(a, 2); + assert_eq!(!0xf0_isize & 0xff, 0xf); + assert_eq!(0xf0_isize | 0xf, 0xff); + assert_eq!(0xf_isize << 4, 0xf0); + assert_eq!(0xf0_isize >> 4, 0xf); + assert_eq!(-16 >> 2, -4); + assert_eq!(0b1010_1010_isize | 0b0101_0101, 0xff); +} + +pub fn main() { + general(); + target(); +} diff --git a/tests/ui/pattern/pattern-match-arc-move.rs b/tests/ui/pattern/pattern-match-arc-move.rs new file mode 100644 index 00000000000..bc79401e4e3 --- /dev/null +++ b/tests/ui/pattern/pattern-match-arc-move.rs @@ -0,0 +1,15 @@ +//! Tests moving an `Arc` value out of an `Option` in a match expression. + +//@ run-pass + +use std::sync::Arc; +fn dispose(_x: Arc) { } + +pub fn main() { + let p = Arc::new(true); + let x = Some(p); + match x { + Some(z) => { dispose(z); }, + None => panic!() + } +} diff --git a/tests/ui/pattern/pattern-match-invalid-variant.rs b/tests/ui/pattern/pattern-match-invalid-variant.rs new file mode 100644 index 00000000000..183031553c0 --- /dev/null +++ b/tests/ui/pattern/pattern-match-invalid-variant.rs @@ -0,0 +1,19 @@ +//! Tests invalid enum variant in a match expression. + +enum Color { + Rgb(isize, isize, isize), + Rgba(isize, isize, isize, isize), +} + +fn main() { + let red: Color = Color::Rgb(255, 0, 0); + match red { + Color::Rgb(r, g, b) => { + println!("rgb"); + } + Color::Hsl(h, s, l) => { + //~^ ERROR no variant + println!("hsl"); + } + } +} diff --git a/tests/ui/pattern/pattern-match-invalid-variant.stderr b/tests/ui/pattern/pattern-match-invalid-variant.stderr new file mode 100644 index 00000000000..08a99f696f6 --- /dev/null +++ b/tests/ui/pattern/pattern-match-invalid-variant.stderr @@ -0,0 +1,12 @@ +error[E0599]: no variant or associated item named `Hsl` found for enum `Color` in the current scope + --> $DIR/pattern-match-invalid-variant.rs:14:16 + | +LL | enum Color { + | ---------- variant or associated item `Hsl` not found for this enum +... +LL | Color::Hsl(h, s, l) => { + | ^^^ variant or associated item not found in `Color` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. -- cgit 1.4.1-3-g733a5 From e87f1386d962732f2ffe69e876add4393e06d5a1 Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Mon, 2 Jun 2025 20:37:55 -0400 Subject: add tests --- library/coretests/tests/lib.rs | 1 + library/coretests/tests/num/int_macros.rs | 24 ++++++++++++++++++++++++ library/coretests/tests/num/uint_macros.rs | 23 +++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index dd7cdd79c0d..92b920dd775 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -30,6 +30,7 @@ #![feature(duration_constructors)] #![feature(duration_constructors_lite)] #![feature(error_generic_member_access)] +#![feature(exact_div)] #![feature(exact_size_is_empty)] #![feature(extend_one)] #![feature(extern_types)] diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs index 0d9fb9e797e..719d29e4e7c 100644 --- a/library/coretests/tests/num/int_macros.rs +++ b/library/coretests/tests/num/int_macros.rs @@ -683,5 +683,29 @@ macro_rules! int_module { assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0); } } + + const EXACT_DIV_SUCCESS_DIVIDEND1: $T = 42; + const EXACT_DIV_SUCCESS_DIVISOR1: $T = 6; + const EXACT_DIV_SUCCESS_QUOTIENT1: $T = 7; + const EXACT_DIV_SUCCESS_DIVIDEND2: $T = 18; + const EXACT_DIV_SUCCESS_DIVISOR2: $T = 3; + const EXACT_DIV_SUCCESS_QUOTIENT2: $T = 6; + + test_runtime_and_compiletime! { + fn test_exact_div() { + // 42 / 6 + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), Some(EXACT_DIV_SUCCESS_QUOTIENT1)); + assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), EXACT_DIV_SUCCESS_QUOTIENT1); + + // 18 / 3 + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), Some(EXACT_DIV_SUCCESS_QUOTIENT2)); + assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), EXACT_DIV_SUCCESS_QUOTIENT2); + + // failures + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(1, 2), None); + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(<$T>::MIN, -1), None); + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(0, 0), None); + } + } }; } diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs index 2e35e8bf534..6f3d160964f 100644 --- a/library/coretests/tests/num/uint_macros.rs +++ b/library/coretests/tests/num/uint_macros.rs @@ -516,5 +516,28 @@ macro_rules! uint_module { assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0); } } + + const EXACT_DIV_SUCCESS_DIVIDEND1: $T = 42; + const EXACT_DIV_SUCCESS_DIVISOR1: $T = 6; + const EXACT_DIV_SUCCESS_QUOTIENT1: $T = 7; + const EXACT_DIV_SUCCESS_DIVIDEND2: $T = 18; + const EXACT_DIV_SUCCESS_DIVISOR2: $T = 3; + const EXACT_DIV_SUCCESS_QUOTIENT2: $T = 6; + + test_runtime_and_compiletime! { + fn test_exact_div() { + // 42 / 6 + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), Some(EXACT_DIV_SUCCESS_QUOTIENT1)); + assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), EXACT_DIV_SUCCESS_QUOTIENT1); + + // 18 / 3 + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), Some(EXACT_DIV_SUCCESS_QUOTIENT2)); + assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), EXACT_DIV_SUCCESS_QUOTIENT2); + + // failures + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(1, 2), None); + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(0, 0), None); + } + } }; } -- cgit 1.4.1-3-g733a5 From 02a86dbd1d929b1235b57ef26198f95ec1d41e51 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 3 Jun 2025 10:19:31 +1000 Subject: Remove pre-expansion AST stats. They're very little value, because they only measure the top-level `main.rs` or `lib.rs` file. (Other `.rs` files don't get read and parsed until expansion occurs.) I saw an example recently where the pre-expansion AST was 3KB in size and the post-expansion AST was 66MB. I kept the "POST EXPANSION" in the output header, I think that's useful information to avoid possible confusion about when the measurement happens. --- compiler/rustc_interface/src/passes.rs | 6 +- tests/ui/stats/input-stats.stderr | 177 +++++++++++---------------------- 2 files changed, 61 insertions(+), 122 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 75d92ae7a2e..ada3bf96a62 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -60,10 +60,6 @@ pub fn parse<'a>(sess: &'a Session) -> ast::Crate { guar.raise_fatal(); }); - if sess.opts.unstable_opts.input_stats { - input_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1"); - } - rustc_builtin_macros::cmdline_attrs::inject( &mut krate, &sess.psess, @@ -298,7 +294,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { let mut lint_buffer = resolver.lint_buffer.steal(); if sess.opts.unstable_opts.input_stats { - input_stats::print_ast_stats(krate, "POST EXPANSION AST STATS", "ast-stats-2"); + input_stats::print_ast_stats(krate, "POST EXPANSION AST STATS", "ast-stats"); } // Needs to go *after* expansion to be able to check the results of macro expansion. diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index 58ab1a72556..f2598bd7eaf 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -1,120 +1,63 @@ -ast-stats-1 PRE EXPANSION AST STATS -ast-stats-1 Name Accumulated Size Count Item Size -ast-stats-1 ---------------------------------------------------------------- -ast-stats-1 Crate 40 (NN.N%) 1 40 -ast-stats-1 GenericArgs 40 (NN.N%) 1 40 -ast-stats-1 - AngleBracketed 40 (NN.N%) 1 -ast-stats-1 ExprField 48 (NN.N%) 1 48 -ast-stats-1 Attribute 64 (NN.N%) 2 32 -ast-stats-1 - DocComment 32 (NN.N%) 1 -ast-stats-1 - Normal 32 (NN.N%) 1 -ast-stats-1 WherePredicate 72 (NN.N%) 1 72 -ast-stats-1 - BoundPredicate 72 (NN.N%) 1 -ast-stats-1 ForeignItem 80 (NN.N%) 1 80 -ast-stats-1 - Fn 80 (NN.N%) 1 -ast-stats-1 Arm 96 (NN.N%) 2 48 -ast-stats-1 Local 96 (NN.N%) 1 96 -ast-stats-1 FnDecl 120 (NN.N%) 5 24 -ast-stats-1 Param 160 (NN.N%) 4 40 -ast-stats-1 Stmt 160 (NN.N%) 5 32 -ast-stats-1 - Let 32 (NN.N%) 1 -ast-stats-1 - MacCall 32 (NN.N%) 1 -ast-stats-1 - Expr 96 (NN.N%) 3 -ast-stats-1 Block 192 (NN.N%) 6 32 -ast-stats-1 FieldDef 208 (NN.N%) 2 104 -ast-stats-1 Variant 208 (NN.N%) 2 104 -ast-stats-1 AssocItem 320 (NN.N%) 4 80 -ast-stats-1 - Fn 160 (NN.N%) 2 -ast-stats-1 - Type 160 (NN.N%) 2 -ast-stats-1 GenericBound 352 (NN.N%) 4 88 -ast-stats-1 - Trait 352 (NN.N%) 4 -ast-stats-1 GenericParam 480 (NN.N%) 5 96 -ast-stats-1 Pat 504 (NN.N%) 7 72 -ast-stats-1 - Struct 72 (NN.N%) 1 -ast-stats-1 - Wild 72 (NN.N%) 1 -ast-stats-1 - Ident 360 (NN.N%) 5 -ast-stats-1 Expr 576 (NN.N%) 8 72 -ast-stats-1 - Match 72 (NN.N%) 1 -ast-stats-1 - Path 72 (NN.N%) 1 -ast-stats-1 - Struct 72 (NN.N%) 1 -ast-stats-1 - Lit 144 (NN.N%) 2 -ast-stats-1 - Block 216 (NN.N%) 3 -ast-stats-1 PathSegment 744 (NN.N%) 31 24 -ast-stats-1 Ty 896 (NN.N%) 14 64 -ast-stats-1 - Ptr 64 (NN.N%) 1 -ast-stats-1 - Ref 64 (NN.N%) 1 -ast-stats-1 - ImplicitSelf 128 (NN.N%) 2 -ast-stats-1 - Path 640 (NN.N%) 10 -ast-stats-1 Item 1_296 (NN.N%) 9 144 -ast-stats-1 - Enum 144 (NN.N%) 1 -ast-stats-1 - ForeignMod 144 (NN.N%) 1 -ast-stats-1 - Impl 144 (NN.N%) 1 -ast-stats-1 - Trait 144 (NN.N%) 1 -ast-stats-1 - Fn 288 (NN.N%) 2 -ast-stats-1 - Use 432 (NN.N%) 3 -ast-stats-1 ---------------------------------------------------------------- -ast-stats-1 Total 6_752 116 -ast-stats-1 -ast-stats-2 POST EXPANSION AST STATS -ast-stats-2 Name Accumulated Size Count Item Size -ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 Crate 40 (NN.N%) 1 40 -ast-stats-2 GenericArgs 40 (NN.N%) 1 40 -ast-stats-2 - AngleBracketed 40 (NN.N%) 1 -ast-stats-2 ExprField 48 (NN.N%) 1 48 -ast-stats-2 WherePredicate 72 (NN.N%) 1 72 -ast-stats-2 - BoundPredicate 72 (NN.N%) 1 -ast-stats-2 ForeignItem 80 (NN.N%) 1 80 -ast-stats-2 - Fn 80 (NN.N%) 1 -ast-stats-2 Arm 96 (NN.N%) 2 48 -ast-stats-2 Local 96 (NN.N%) 1 96 -ast-stats-2 FnDecl 120 (NN.N%) 5 24 -ast-stats-2 InlineAsm 120 (NN.N%) 1 120 -ast-stats-2 Attribute 128 (NN.N%) 4 32 -ast-stats-2 - DocComment 32 (NN.N%) 1 -ast-stats-2 - Normal 96 (NN.N%) 3 -ast-stats-2 Param 160 (NN.N%) 4 40 -ast-stats-2 Stmt 160 (NN.N%) 5 32 -ast-stats-2 - Let 32 (NN.N%) 1 -ast-stats-2 - Semi 32 (NN.N%) 1 -ast-stats-2 - Expr 96 (NN.N%) 3 -ast-stats-2 Block 192 (NN.N%) 6 32 -ast-stats-2 FieldDef 208 (NN.N%) 2 104 -ast-stats-2 Variant 208 (NN.N%) 2 104 -ast-stats-2 AssocItem 320 (NN.N%) 4 80 -ast-stats-2 - Fn 160 (NN.N%) 2 -ast-stats-2 - Type 160 (NN.N%) 2 -ast-stats-2 GenericBound 352 (NN.N%) 4 88 -ast-stats-2 - Trait 352 (NN.N%) 4 -ast-stats-2 GenericParam 480 (NN.N%) 5 96 -ast-stats-2 Pat 504 (NN.N%) 7 72 -ast-stats-2 - Struct 72 (NN.N%) 1 -ast-stats-2 - Wild 72 (NN.N%) 1 -ast-stats-2 - Ident 360 (NN.N%) 5 -ast-stats-2 Expr 648 (NN.N%) 9 72 -ast-stats-2 - InlineAsm 72 (NN.N%) 1 -ast-stats-2 - Match 72 (NN.N%) 1 -ast-stats-2 - Path 72 (NN.N%) 1 -ast-stats-2 - Struct 72 (NN.N%) 1 -ast-stats-2 - Lit 144 (NN.N%) 2 -ast-stats-2 - Block 216 (NN.N%) 3 -ast-stats-2 PathSegment 864 (NN.N%) 36 24 -ast-stats-2 Ty 896 (NN.N%) 14 64 -ast-stats-2 - Ptr 64 (NN.N%) 1 -ast-stats-2 - Ref 64 (NN.N%) 1 -ast-stats-2 - ImplicitSelf 128 (NN.N%) 2 -ast-stats-2 - Path 640 (NN.N%) 10 -ast-stats-2 Item 1_584 (NN.N%) 11 144 -ast-stats-2 - Enum 144 (NN.N%) 1 -ast-stats-2 - ExternCrate 144 (NN.N%) 1 -ast-stats-2 - ForeignMod 144 (NN.N%) 1 -ast-stats-2 - Impl 144 (NN.N%) 1 -ast-stats-2 - Trait 144 (NN.N%) 1 -ast-stats-2 - Fn 288 (NN.N%) 2 -ast-stats-2 - Use 576 (NN.N%) 4 -ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 Total 7_416 127 -ast-stats-2 +ast-stats POST EXPANSION AST STATS +ast-stats Name Accumulated Size Count Item Size +ast-stats ---------------------------------------------------------------- +ast-stats Crate 40 (NN.N%) 1 40 +ast-stats GenericArgs 40 (NN.N%) 1 40 +ast-stats - AngleBracketed 40 (NN.N%) 1 +ast-stats ExprField 48 (NN.N%) 1 48 +ast-stats WherePredicate 72 (NN.N%) 1 72 +ast-stats - BoundPredicate 72 (NN.N%) 1 +ast-stats ForeignItem 80 (NN.N%) 1 80 +ast-stats - Fn 80 (NN.N%) 1 +ast-stats Arm 96 (NN.N%) 2 48 +ast-stats Local 96 (NN.N%) 1 96 +ast-stats FnDecl 120 (NN.N%) 5 24 +ast-stats InlineAsm 120 (NN.N%) 1 120 +ast-stats Attribute 128 (NN.N%) 4 32 +ast-stats - DocComment 32 (NN.N%) 1 +ast-stats - Normal 96 (NN.N%) 3 +ast-stats Param 160 (NN.N%) 4 40 +ast-stats Stmt 160 (NN.N%) 5 32 +ast-stats - Let 32 (NN.N%) 1 +ast-stats - Semi 32 (NN.N%) 1 +ast-stats - Expr 96 (NN.N%) 3 +ast-stats Block 192 (NN.N%) 6 32 +ast-stats FieldDef 208 (NN.N%) 2 104 +ast-stats Variant 208 (NN.N%) 2 104 +ast-stats AssocItem 320 (NN.N%) 4 80 +ast-stats - Fn 160 (NN.N%) 2 +ast-stats - Type 160 (NN.N%) 2 +ast-stats GenericBound 352 (NN.N%) 4 88 +ast-stats - Trait 352 (NN.N%) 4 +ast-stats GenericParam 480 (NN.N%) 5 96 +ast-stats Pat 504 (NN.N%) 7 72 +ast-stats - Struct 72 (NN.N%) 1 +ast-stats - Wild 72 (NN.N%) 1 +ast-stats - Ident 360 (NN.N%) 5 +ast-stats Expr 648 (NN.N%) 9 72 +ast-stats - InlineAsm 72 (NN.N%) 1 +ast-stats - Match 72 (NN.N%) 1 +ast-stats - Path 72 (NN.N%) 1 +ast-stats - Struct 72 (NN.N%) 1 +ast-stats - Lit 144 (NN.N%) 2 +ast-stats - Block 216 (NN.N%) 3 +ast-stats PathSegment 864 (NN.N%) 36 24 +ast-stats Ty 896 (NN.N%) 14 64 +ast-stats - Ptr 64 (NN.N%) 1 +ast-stats - Ref 64 (NN.N%) 1 +ast-stats - ImplicitSelf 128 (NN.N%) 2 +ast-stats - Path 640 (NN.N%) 10 +ast-stats Item 1_584 (NN.N%) 11 144 +ast-stats - Enum 144 (NN.N%) 1 +ast-stats - ExternCrate 144 (NN.N%) 1 +ast-stats - ForeignMod 144 (NN.N%) 1 +ast-stats - Impl 144 (NN.N%) 1 +ast-stats - Trait 144 (NN.N%) 1 +ast-stats - Fn 288 (NN.N%) 2 +ast-stats - Use 576 (NN.N%) 4 +ast-stats ---------------------------------------------------------------- +ast-stats Total 7_416 127 +ast-stats hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size hir-stats ---------------------------------------------------------------- -- cgit 1.4.1-3-g733a5 From 04391045d0ecfad794481b27a49032c48d2ff2ca Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 3 Jun 2025 15:21:33 +1000 Subject: Remove `Path::is_ident`. It checks that a path has a single segment that matches the given symbol, and that there are zero generic arguments. It has a single use. We also have `impl PartialEq for Path` which does exactly the same thing *except* it doesn't check for zero generic arguments, which seems like an oversight. It has numerous uses. This commit removes `Path::is_ident`, adds a test for zero generic arguments to `PartialEq for Path`, and changes the single use of `is_ident` to instead use `==`. --- compiler/rustc_ast/src/ast.rs | 22 +++++++++------------- compiler/rustc_parse/src/parser/expr.rs | 2 +- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7b103126e45..023bf9bb677 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -99,8 +99,15 @@ pub struct Path { impl PartialEq for Path { #[inline] - fn eq(&self, symbol: &Symbol) -> bool { - matches!(&self.segments[..], [segment] if segment.ident.name == *symbol) + fn eq(&self, name: &Symbol) -> bool { + if let [segment] = self.segments.as_ref() + && segment.args.is_none() + && segment.ident.name == *name + { + true + } else { + false + } } } @@ -120,17 +127,6 @@ impl Path { Path { segments: thin_vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None } } - pub fn is_ident(&self, name: Symbol) -> bool { - if let [segment] = self.segments.as_ref() - && segment.args.is_none() - && segment.ident.name == name - { - true - } else { - false - } - } - pub fn is_global(&self) -> bool { self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1a44f4af8a6..adfea3641e6 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -834,7 +834,7 @@ impl<'a> Parser<'a> { // guides recovery in case we write `&raw expr`. if borrow_kind == ast::BorrowKind::Ref && mutbl == ast::Mutability::Not - && matches!(&expr.kind, ExprKind::Path(None, p) if p.is_ident(kw::Raw)) + && matches!(&expr.kind, ExprKind::Path(None, p) if *p == kw::Raw) { self.expected_token_types.insert(TokenType::KwMut); self.expected_token_types.insert(TokenType::KwConst); -- cgit 1.4.1-3-g733a5 From 4e71f24a6bdda70c1608604ca552fb1b8636649b Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 3 Jun 2025 10:53:12 +0300 Subject: make `x check` to use stage0 by default Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 899ffde8adf..99e82ba7658 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2531,7 +2531,10 @@ impl Config { || bench_stage.is_some(); // See https://github.com/rust-lang/compiler-team/issues/326 config.stage = match config.cmd { - Subcommand::Check { .. } | Subcommand::Clippy { .. } | Subcommand::Fix => { + Subcommand::Check { .. } => { + flags.stage.or(check_stage).unwrap_or(0) + } + Subcommand::Clippy { .. } | Subcommand::Fix => { flags.stage.or(check_stage).unwrap_or(1) } // `download-rustc` only has a speed-up for stage2 builds. Default to stage2 unless explicitly overridden. -- cgit 1.4.1-3-g733a5 From 8a65d9febb86539e502faee868870f0dcd444693 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 3 Jun 2025 10:55:13 +0300 Subject: make library profile to use stage 1 on `x check` Signed-off-by: onur-ozkan --- src/bootstrap/defaults/bootstrap.library.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/defaults/bootstrap.library.toml b/src/bootstrap/defaults/bootstrap.library.toml index 6edd00922ae..895e50b9a20 100644 --- a/src/bootstrap/defaults/bootstrap.library.toml +++ b/src/bootstrap/defaults/bootstrap.library.toml @@ -1,8 +1,9 @@ # These defaults are meant for contributors to the standard library and documentation. [build] +bench-stage = 1 build-stage = 1 +check-stage = 1 test-stage = 1 -bench-stage = 1 [rust] # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. -- cgit 1.4.1-3-g733a5 From 59fbe04a5249d2da56b19bf0e7f4f017064a3866 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 3 Jun 2025 10:38:15 +0300 Subject: move `test-float-parse` tool into `src/tools` dir Obviously `test-float-parse` is a tool like any other in `src/tools`. Signed-off-by: onur-ozkan --- Cargo.toml | 2 +- library/core/src/num/dec2flt/mod.rs | 2 +- src/bootstrap/mk/Makefile.in | 2 +- src/bootstrap/src/core/build_steps/check.rs | 2 +- src/bootstrap/src/core/build_steps/clippy.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 4 +- src/bootstrap/src/core/build_steps/tool.rs | 4 +- src/etc/test-float-parse/Cargo.lock | 75 ---- src/etc/test-float-parse/Cargo.toml | 22 -- src/etc/test-float-parse/README.md | 55 --- src/etc/test-float-parse/src/gen_/exhaustive.rs | 42 --- src/etc/test-float-parse/src/gen_/exponents.rs | 95 ----- src/etc/test-float-parse/src/gen_/fuzz.rs | 87 ----- src/etc/test-float-parse/src/gen_/integers.rs | 104 ----- .../test-float-parse/src/gen_/long_fractions.rs | 58 --- src/etc/test-float-parse/src/gen_/many_digits.rs | 84 ----- src/etc/test-float-parse/src/gen_/sparse.rs | 99 ----- src/etc/test-float-parse/src/gen_/spot_checks.rs | 101 ----- src/etc/test-float-parse/src/gen_/subnorm.rs | 108 ------ src/etc/test-float-parse/src/lib.rs | 419 --------------------- src/etc/test-float-parse/src/main.rs | 129 ------- src/etc/test-float-parse/src/traits.rs | 206 ---------- src/etc/test-float-parse/src/ui.rs | 168 --------- src/etc/test-float-parse/src/validate.rs | 394 ------------------- src/etc/test-float-parse/src/validate/tests.rs | 149 -------- src/tools/test-float-parse/Cargo.lock | 75 ++++ src/tools/test-float-parse/Cargo.toml | 22 ++ src/tools/test-float-parse/README.md | 55 +++ src/tools/test-float-parse/src/gen_/exhaustive.rs | 42 +++ src/tools/test-float-parse/src/gen_/exponents.rs | 95 +++++ src/tools/test-float-parse/src/gen_/fuzz.rs | 87 +++++ src/tools/test-float-parse/src/gen_/integers.rs | 104 +++++ .../test-float-parse/src/gen_/long_fractions.rs | 58 +++ src/tools/test-float-parse/src/gen_/many_digits.rs | 84 +++++ src/tools/test-float-parse/src/gen_/sparse.rs | 99 +++++ src/tools/test-float-parse/src/gen_/spot_checks.rs | 101 +++++ src/tools/test-float-parse/src/gen_/subnorm.rs | 108 ++++++ src/tools/test-float-parse/src/lib.rs | 419 +++++++++++++++++++++ src/tools/test-float-parse/src/main.rs | 129 +++++++ src/tools/test-float-parse/src/traits.rs | 206 ++++++++++ src/tools/test-float-parse/src/ui.rs | 168 +++++++++ src/tools/test-float-parse/src/validate.rs | 394 +++++++++++++++++++ src/tools/test-float-parse/src/validate/tests.rs | 149 ++++++++ src/tools/tidy/src/deps.rs | 2 +- 44 files changed, 2405 insertions(+), 2405 deletions(-) delete mode 100644 src/etc/test-float-parse/Cargo.lock delete mode 100644 src/etc/test-float-parse/Cargo.toml delete mode 100644 src/etc/test-float-parse/README.md delete mode 100644 src/etc/test-float-parse/src/gen_/exhaustive.rs delete mode 100644 src/etc/test-float-parse/src/gen_/exponents.rs delete mode 100644 src/etc/test-float-parse/src/gen_/fuzz.rs delete mode 100644 src/etc/test-float-parse/src/gen_/integers.rs delete mode 100644 src/etc/test-float-parse/src/gen_/long_fractions.rs delete mode 100644 src/etc/test-float-parse/src/gen_/many_digits.rs delete mode 100644 src/etc/test-float-parse/src/gen_/sparse.rs delete mode 100644 src/etc/test-float-parse/src/gen_/spot_checks.rs delete mode 100644 src/etc/test-float-parse/src/gen_/subnorm.rs delete mode 100644 src/etc/test-float-parse/src/lib.rs delete mode 100644 src/etc/test-float-parse/src/main.rs delete mode 100644 src/etc/test-float-parse/src/traits.rs delete mode 100644 src/etc/test-float-parse/src/ui.rs delete mode 100644 src/etc/test-float-parse/src/validate.rs delete mode 100644 src/etc/test-float-parse/src/validate/tests.rs create mode 100644 src/tools/test-float-parse/Cargo.lock create mode 100644 src/tools/test-float-parse/Cargo.toml create mode 100644 src/tools/test-float-parse/README.md create mode 100644 src/tools/test-float-parse/src/gen_/exhaustive.rs create mode 100644 src/tools/test-float-parse/src/gen_/exponents.rs create mode 100644 src/tools/test-float-parse/src/gen_/fuzz.rs create mode 100644 src/tools/test-float-parse/src/gen_/integers.rs create mode 100644 src/tools/test-float-parse/src/gen_/long_fractions.rs create mode 100644 src/tools/test-float-parse/src/gen_/many_digits.rs create mode 100644 src/tools/test-float-parse/src/gen_/sparse.rs create mode 100644 src/tools/test-float-parse/src/gen_/spot_checks.rs create mode 100644 src/tools/test-float-parse/src/gen_/subnorm.rs create mode 100644 src/tools/test-float-parse/src/lib.rs create mode 100644 src/tools/test-float-parse/src/main.rs create mode 100644 src/tools/test-float-parse/src/traits.rs create mode 100644 src/tools/test-float-parse/src/ui.rs create mode 100644 src/tools/test-float-parse/src/validate.rs create mode 100644 src/tools/test-float-parse/src/validate/tests.rs diff --git a/Cargo.toml b/Cargo.toml index 16ff0f61593..c4d2a06f4cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ members = [ # tidy-alphabetical-start "compiler/rustc", "src/build_helper", - "src/etc/test-float-parse", "src/rustc-std-workspace/rustc-std-workspace-alloc", "src/rustc-std-workspace/rustc-std-workspace-core", "src/rustc-std-workspace/rustc-std-workspace-std", @@ -41,6 +40,7 @@ members = [ "src/tools/rustdoc-themes", "src/tools/rustfmt", "src/tools/suggest-tests", + "src/tools/test-float-parse", "src/tools/tidy", "src/tools/tier-check", "src/tools/unicode-table-generator", diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index abad7acb104..1844cd98082 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -58,7 +58,7 @@ //! //! There are unit tests but they are woefully inadequate at ensuring correctness, they only cover //! a small percentage of possible errors. Far more extensive tests are located in the directory -//! `src/etc/test-float-parse` as a Rust program. +//! `src/tools/test-float-parse` as a Rust program. //! //! A note on integer overflow: Many parts of this file perform arithmetic with the decimal //! exponent `e`. Primarily, we shift the decimal point around: Before the first decimal digit, diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 08a288170fa..5473d9e6340 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -51,7 +51,7 @@ check-aux: $(Q)$(BOOTSTRAP) test --stage 2 \ src/tools/cargo \ src/tools/cargotest \ - src/etc/test-float-parse \ + src/tools/test-float-parse \ $(BOOTSTRAP_ARGS) # Run standard library tests in Miri. $(Q)$(BOOTSTRAP) miri --stage 2 \ diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 922578f309a..5b64212e314 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -528,7 +528,7 @@ tool_check_step!(Miri { path: "src/tools/miri" }); tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri" }); tool_check_step!(Rustfmt { path: "src/tools/rustfmt" }); tool_check_step!(MiroptTestTools { path: "src/tools/miropt-test-tools" }); -tool_check_step!(TestFloatParse { path: "src/etc/test-float-parse" }); +tool_check_step!(TestFloatParse { path: "src/tools/test-float-parse" }); tool_check_step!(FeaturesStatusDump { path: "src/tools/features-status-dump" }); tool_check_step!(Bootstrap { path: "src/bootstrap", default: false }); diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 5e8d6bba841..0652c08ff49 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -355,7 +355,7 @@ lint_any!( Rustfmt, "src/tools/rustfmt", "rustfmt"; RustInstaller, "src/tools/rust-installer", "rust-installer"; Tidy, "src/tools/tidy", "tidy"; - TestFloatParse, "src/etc/test-float-parse", "test-float-parse"; + TestFloatParse, "src/tools/test-float-parse", "test-float-parse"; ); #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 22ab3e56a9c..22a458bac98 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3544,7 +3544,7 @@ impl Step for CodegenGCC { } /// Test step that does two things: -/// - Runs `cargo test` for the `src/etc/test-float-parse` tool. +/// - Runs `cargo test` for the `src/tools/test-float-parse` tool. /// - Invokes the `test-float-parse` tool to test the standard library's /// float parsing routines. #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -3559,7 +3559,7 @@ impl Step for TestFloatParse { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/etc/test-float-parse") + run.path("src/tools/test-float-parse") } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 173b3ff0816..6643d87882f 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1269,7 +1269,7 @@ impl Step for TestFloatParse { const DEFAULT: bool = false; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/etc/test-float-parse") + run.path("src/tools/test-float-parse") } fn run(self, builder: &Builder<'_>) -> ToolBuildResult { @@ -1281,7 +1281,7 @@ impl Step for TestFloatParse { target: bootstrap_host, tool: "test-float-parse", mode: Mode::ToolStd, - path: "src/etc/test-float-parse", + path: "src/tools/test-float-parse", source_type: SourceType::InTree, extra_features: Vec::new(), allow_features: Self::ALLOW_FEATURES, diff --git a/src/etc/test-float-parse/Cargo.lock b/src/etc/test-float-parse/Cargo.lock deleted file mode 100644 index 3f60423fed3..00000000000 --- a/src/etc/test-float-parse/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "getrandom" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "libc" -version = "0.2.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "test-float-parse" -version = "0.1.0" -dependencies = [ - "rand", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/src/etc/test-float-parse/Cargo.toml b/src/etc/test-float-parse/Cargo.toml deleted file mode 100644 index e407e322f9e..00000000000 --- a/src/etc/test-float-parse/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "test-float-parse" -version = "0.1.0" -edition = "2024" -publish = false - -[dependencies] -indicatif = { version = "0.17.8", default-features = false } -num = "0.4.3" -rand = "0.9.0" -rand_chacha = "0.9.0" -rayon = "1" - -[lib] -name = "test_float_parse" - -[lints.rust.unexpected_cfgs] -level = "warn" -check-cfg = [ - # Internal features aren't marked known config by default - 'cfg(target_has_reliable_f16)', -] diff --git a/src/etc/test-float-parse/README.md b/src/etc/test-float-parse/README.md deleted file mode 100644 index 5e2c43d1cad..00000000000 --- a/src/etc/test-float-parse/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Float Parsing Tests - -These are tests designed to test decimal to float conversions (`dec2flt`) used -by the standard library. - -It consists of a collection of test generators that each generate a set of -patterns intended to test a specific property. In addition, there are exhaustive -tests (for <= `f32`) and fuzzers (for anything that can't be run exhaustively). - -The generators work as follows: - -- Each generator is a struct that lives somewhere in the `gen` module. Usually - it is generic over a float type. -- These generators must implement `Iterator`, which should return a context type - that can be used to construct a test string (but usually not the string - itself). -- They must also implement the `Generator` trait, which provides a method to - write test context to a string as a test case, as well as some extra metadata. - - The split between context generation and string construction is so that we can - reuse string allocations. -- Each generator gets registered once for each float type. Each of these - generators then get their iterator called, and each test case checked against - the float type's parse implementation. - -Some generators produce decimal strings, others create bit patterns that need to -be bitcasted to the float type, which then uses its `Display` implementation to -write to a string. For these, float to decimal (`flt2dec`) conversions also get -tested, if unintentionally. - -For each test case, the following is done: - -- The test string is parsed to the float type using the standard library's - implementation. -- The test string is parsed separately to a `BigRational`, which acts as a - representation with infinite precision. -- The rational value then gets checked that it is within the float's - representable values (absolute value greater than the smallest number to round - to zero, but less less than the first value to round to infinity). If these - limits are exceeded, check that the parsed float reflects that. -- For real nonzero numbers, the parsed float is converted into a rational using - `significand * 2^exponent`. It is then checked against the actual rational - value, and verified to be within half a bit's precision of the parsed value. - Also it is checked that ties round to even. - -This is all highly parallelized with `rayon`; test generators can run in -parallel, and their tests get chunked and run in parallel. - -There is a simple command line that allows filtering which tests are run, -setting the number of iterations for fuzzing tests, limiting failures, setting -timeouts, etc. See `main.rs` or run with `--help` for options. - -Note that when running via `./x`, only tests that take less than a few minutes -are run by default. Navigate to the crate (or pass `-C` to Cargo) and run it -directly to run all tests or pass specific arguments. diff --git a/src/etc/test-float-parse/src/gen_/exhaustive.rs b/src/etc/test-float-parse/src/gen_/exhaustive.rs deleted file mode 100644 index 01458fb0b60..00000000000 --- a/src/etc/test-float-parse/src/gen_/exhaustive.rs +++ /dev/null @@ -1,42 +0,0 @@ -use std::fmt::Write; -use std::ops::RangeInclusive; - -use crate::{Float, Generator, Int}; - -/// Test every possible bit pattern. This is infeasible to run on any float types larger than -/// `f32` (which takes about an hour). -pub struct Exhaustive { - iter: RangeInclusive, -} - -impl Generator for Exhaustive -where - RangeInclusive: Iterator, -{ - const SHORT_NAME: &'static str = "exhaustive"; - - type WriteCtx = F; - - fn total_tests() -> u64 { - 1u64.checked_shl(F::Int::BITS).expect("More than u64::MAX tests") - } - - fn new() -> Self { - Self { iter: F::Int::ZERO..=F::Int::MAX } - } - - fn write_string(s: &mut String, ctx: Self::WriteCtx) { - write!(s, "{ctx:e}").unwrap(); - } -} - -impl Iterator for Exhaustive -where - RangeInclusive: Iterator, -{ - type Item = F; - - fn next(&mut self) -> Option { - Some(F::from_bits(self.iter.next()?)) - } -} diff --git a/src/etc/test-float-parse/src/gen_/exponents.rs b/src/etc/test-float-parse/src/gen_/exponents.rs deleted file mode 100644 index 3748e9d380c..00000000000 --- a/src/etc/test-float-parse/src/gen_/exponents.rs +++ /dev/null @@ -1,95 +0,0 @@ -use std::fmt::Write; -use std::ops::RangeInclusive; - -use crate::traits::BoxGenIter; -use crate::{Float, Generator}; - -const SMALL_COEFF_MAX: i32 = 10_000; -const SMALL_EXP_MAX: i32 = 300; - -const SMALL_COEFF_RANGE: RangeInclusive = (-SMALL_COEFF_MAX)..=SMALL_COEFF_MAX; -const SMALL_EXP_RANGE: RangeInclusive = (-SMALL_EXP_MAX)..=SMALL_EXP_MAX; - -const LARGE_COEFF_RANGE: RangeInclusive = 0..=100_000; -const LARGE_EXP_RANGE: RangeInclusive = 300..=350; - -/// Check exponential values around zero. -pub struct SmallExponents { - iter: BoxGenIter, -} - -impl Generator for SmallExponents { - const NAME: &'static str = "small exponents"; - const SHORT_NAME: &'static str = "small exp"; - - /// `(coefficient, exponent)` - type WriteCtx = (i32, i32); - - fn total_tests() -> u64 { - ((1 + SMALL_COEFF_RANGE.end() - SMALL_COEFF_RANGE.start()) - * (1 + SMALL_EXP_RANGE.end() - SMALL_EXP_RANGE.start())) - .try_into() - .unwrap() - } - - fn new() -> Self { - let iter = SMALL_EXP_RANGE.flat_map(|exp| SMALL_COEFF_RANGE.map(move |coeff| (coeff, exp))); - - Self { iter: Box::new(iter) } - } - - fn write_string(s: &mut String, ctx: Self::WriteCtx) { - let (coeff, exp) = ctx; - write!(s, "{coeff}e{exp}").unwrap(); - } -} - -impl Iterator for SmallExponents { - type Item = (i32, i32); - - fn next(&mut self) -> Option { - self.iter.next() - } -} - -/// Check exponential values further from zero. -pub struct LargeExponents { - iter: BoxGenIter, -} - -impl Generator for LargeExponents { - const NAME: &'static str = "large positive exponents"; - const SHORT_NAME: &'static str = "large exp"; - - /// `(coefficient, exponent, is_positive)` - type WriteCtx = (u32, u32, bool); - - fn total_tests() -> u64 { - ((1 + LARGE_EXP_RANGE.end() - LARGE_EXP_RANGE.start()) - * (1 + LARGE_COEFF_RANGE.end() - LARGE_COEFF_RANGE.start()) - * 2) - .into() - } - - fn new() -> Self { - let iter = LARGE_EXP_RANGE - .flat_map(|exp| LARGE_COEFF_RANGE.map(move |coeff| (coeff, exp))) - .flat_map(|(coeff, exp)| [(coeff, exp, false), (coeff, exp, true)]); - - Self { iter: Box::new(iter) } - } - - fn write_string(s: &mut String, ctx: Self::WriteCtx) { - let (coeff, exp, is_positive) = ctx; - let sign = if is_positive { "" } else { "-" }; - write!(s, "{sign}{coeff}e{exp}").unwrap(); - } -} - -impl Iterator for LargeExponents { - type Item = (u32, u32, bool); - - fn next(&mut self) -> Option { - self.iter.next() - } -} diff --git a/src/etc/test-float-parse/src/gen_/fuzz.rs b/src/etc/test-float-parse/src/gen_/fuzz.rs deleted file mode 100644 index 1d6c5562a14..00000000000 --- a/src/etc/test-float-parse/src/gen_/fuzz.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::any::{TypeId, type_name}; -use std::collections::BTreeMap; -use std::fmt::Write; -use std::marker::PhantomData; -use std::ops::Range; -use std::sync::Mutex; - -use rand::Rng; -use rand::distr::{Distribution, StandardUniform}; -use rand_chacha::ChaCha8Rng; -use rand_chacha::rand_core::SeedableRng; - -use crate::{Float, Generator, Int, SEED}; - -/// Mapping of float types to the number of iterations that should be run. -/// -/// We could probably make `Generator::new` take an argument instead of the global state, -/// but we only load this once so it works. -static FUZZ_COUNTS: Mutex> = Mutex::new(BTreeMap::new()); - -/// Generic fuzzer; just tests deterministic random bit patterns N times. -pub struct Fuzz { - iter: Range, - rng: ChaCha8Rng, - /// Allow us to use generics in `Iterator`. - marker: PhantomData, -} - -impl Fuzz { - /// Register how many iterations the fuzzer should run for a type. Uses some logic by - /// default, but if `from_cfg` is `Some`, that will be used instead. - pub fn set_iterations(from_cfg: Option) { - let count = if let Some(cfg_count) = from_cfg { - cfg_count - } else if F::BITS <= crate::MAX_BITS_FOR_EXHAUUSTIVE { - // If we run exhaustively, still fuzz but only do half as many bits. The only goal here is - // to catch failures from e.g. high bit patterns before exhaustive tests would get to them. - (F::Int::MAX >> (F::BITS / 2)).try_into().unwrap() - } else { - // Eveything bigger gets a fuzz test with as many iterations as `f32` exhaustive. - u32::MAX.into() - }; - - let _ = FUZZ_COUNTS.lock().unwrap().insert(TypeId::of::(), count); - } -} - -impl Generator for Fuzz -where - StandardUniform: Distribution<::Int>, -{ - const SHORT_NAME: &'static str = "fuzz"; - - type WriteCtx = F; - - fn total_tests() -> u64 { - *FUZZ_COUNTS - .lock() - .unwrap() - .get(&TypeId::of::()) - .unwrap_or_else(|| panic!("missing fuzz count for {}", type_name::())) - } - - fn new() -> Self { - let rng = ChaCha8Rng::from_seed(SEED); - - Self { iter: 0..Self::total_tests(), rng, marker: PhantomData } - } - - fn write_string(s: &mut String, ctx: Self::WriteCtx) { - write!(s, "{ctx:e}").unwrap(); - } -} - -impl Iterator for Fuzz -where - StandardUniform: Distribution<::Int>, -{ - type Item = >::WriteCtx; - - fn next(&mut self) -> Option { - let _ = self.iter.next()?; - let i: F::Int = self.rng.random(); - - Some(F::from_bits(i)) - } -} diff --git a/src/etc/test-float-parse/src/gen_/integers.rs b/src/etc/test-float-parse/src/gen_/integers.rs deleted file mode 100644 index 070d188e88c..00000000000 --- a/src/etc/test-float-parse/src/gen_/integers.rs +++ /dev/null @@ -1,104 +0,0 @@ -use std::fmt::Write; -use std::ops::{Range, RangeInclusive}; - -use crate::traits::BoxGenIter; -use crate::{Float, Generator}; - -const SMALL_MAX_POW2: u32 = 19; - -/// All values up to the max power of two -const SMALL_VALUES: RangeInclusive = { - let max = 1i32 << SMALL_MAX_POW2; - (-max)..=max -}; - -/// Large values only get tested around powers of two -const LARGE_POWERS: Range = SMALL_MAX_POW2..128; - -/// We perturbe each large value around these ranges -const LARGE_PERTURBATIONS: RangeInclusive = -256..=256; - -/// Test all integers up to `2 ^ MAX_POW2` -pub struct SmallInt { - iter: RangeInclusive, -} - -impl Generator for SmallInt { - const NAME: &'static str = "small integer values"; - const SHORT_NAME: &'static str = "int small"; - - type WriteCtx = i32; - - fn total_tests() -> u64 { - (SMALL_VALUES.end() + 1 - SMALL_VALUES.start()).try_into().unwrap() - } - - fn new() -> Self { - Self { iter: SMALL_VALUES } - } - - fn write_string(s: &mut String, ctx: Self::WriteCtx) { - write!(s, "{ctx}").unwrap(); - } -} - -impl Iterator for SmallInt { - type Item = i32; - - fn next(&mut self) -> Option { - self.iter.next() - } -} - -/// Test much bigger integers than [`SmallInt`]. -pub struct LargeInt { - iter: BoxGenIter, -} - -impl LargeInt { - const EDGE_CASES: [i128; 7] = [ - i32::MIN as i128, - i32::MAX as i128, - i64::MIN as i128, - i64::MAX as i128, - u64::MAX as i128, - i128::MIN, - i128::MAX, - ]; -} - -impl Generator for LargeInt { - const NAME: &'static str = "large integer values"; - const SHORT_NAME: &'static str = "int large"; - - type WriteCtx = i128; - - fn total_tests() -> u64 { - u64::try_from( - (i128::from(LARGE_POWERS.end - LARGE_POWERS.start) - + i128::try_from(Self::EDGE_CASES.len()).unwrap()) - * (LARGE_PERTURBATIONS.end() + 1 - LARGE_PERTURBATIONS.start()), - ) - .unwrap() - } - - fn new() -> Self { - let iter = LARGE_POWERS - .map(|pow| 1i128 << pow) - .chain(Self::EDGE_CASES) - .flat_map(|base| LARGE_PERTURBATIONS.map(move |perturb| base.saturating_add(perturb))); - - Self { iter: Box::new(iter) } - } - - fn write_string(s: &mut String, ctx: Self::WriteCtx) { - write!(s, "{ctx}").unwrap(); - } -} -impl Iterator for LargeInt { - type Item = i128; - - fn next(&mut self) -> Option { - self.iter.next() - } -} diff --git a/src/etc/test-float-parse/src/gen_/long_fractions.rs b/src/etc/test-float-parse/src/gen_/long_fractions.rs deleted file mode 100644 index b75148b779c..00000000000 --- a/src/etc/test-float-parse/src/gen_/long_fractions.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::char; -use std::fmt::Write; - -use crate::{Float, Generator}; - -/// Number of decimal digits to check (all of them). -const MAX_DIGIT: u32 = 9; -/// Test with this many decimals in the string. -const MAX_DECIMALS: usize = 410; -const PREFIX: &str = "0."; - -/// Test e.g. `0.1`, `0.11`, `0.111`, `0.1111`, ..., `0.2`, `0.22`, ... -pub struct RepeatingDecimal { - digit: u32, - buf: String, -} - -impl Generator for RepeatingDecimal { - const NAME: &'static str = "repeating decimal"; - const SHORT_NAME: &'static str = "dec rep"; - - type WriteCtx = String; - - fn total_tests() -> u64 { - u64::from(MAX_DIGIT + 1) * u64::try_from(MAX_DECIMALS + 1).unwrap() + 1 - } - - fn new() -> Self { - Self { digit: 0, buf: PREFIX.to_owned() } - } - - fn write_string(s: &mut String, ctx: Self::WriteCtx) { - *s = ctx; - } -} - -impl Iterator for RepeatingDecimal { - type Item = String; - - fn next(&mut self) -> Option { - if self.digit > MAX_DIGIT { - return None; - } - - let digit = self.digit; - let inc_digit = self.buf.len() - PREFIX.len() > MAX_DECIMALS; - - if inc_digit { - // Reset the string - self.buf.clear(); - self.digit += 1; - self.buf.write_str(PREFIX).unwrap(); - } - - self.buf.push(char::from_digit(digit, 10).unwrap()); - Some(self.buf.clone()) - } -} diff --git a/src/etc/test-float-parse/src/gen_/many_digits.rs b/src/etc/test-float-parse/src/gen_/many_digits.rs deleted file mode 100644 index 741e11437fe..00000000000 --- a/src/etc/test-float-parse/src/gen_/many_digits.rs +++ /dev/null @@ -1,84 +0,0 @@ -use std::char; -use std::fmt::Write; -use std::marker::PhantomData; -use std::ops::{Range, RangeInclusive}; - -use rand::distr::{Distribution, Uniform}; -use rand::{Rng, SeedableRng}; -use rand_chacha::ChaCha8Rng; - -use crate::{Float, Generator, SEED}; - -/// Total iterations -const ITERATIONS: u64 = 5_000_000; - -/// Possible lengths of the string, excluding decimals and exponents -const POSSIBLE_NUM_DIGITS: RangeInclusive = 100..=400; - -/// Range of possible exponents -const EXP_RANGE: Range = -4500..4500; - -/// Try strings of random digits. -pub struct RandDigits { - rng: ChaCha8Rng, - iter: Range, - uniform: Uniform, - /// Allow us to use generics in `Iterator`. - marker: PhantomData, -} - -impl Generator for RandDigits { - const NAME: &'static str = "random digits"; - - const SHORT_NAME: &'static str = "rand digits"; - - type WriteCtx = String; - - fn total_tests() -> u64 { - ITERATIONS - } - - fn new() -> Self { - let rng = ChaCha8Rng::from_seed(SEED); - let range = Uniform::try_from(0..10).unwrap(); - - Self { rng, iter: 0..ITERATIONS, uniform: range, marker: PhantomData } - } - - fn write_string(s: &mut String, ctx: Self::WriteCtx) { - *s = ctx; - } -} - -impl Iterator for RandDigits { - type Item = String; - - fn next(&mut self) -> Option { - let _ = self.iter.next()?; - let num_digits = self.rng.random_range(POSSIBLE_NUM_DIGITS); - let has_decimal = self.rng.random_bool(0.2); - let has_exp = self.rng.random_bool(0.2); - - let dec_pos = if has_decimal { Some(self.rng.random_range(0..num_digits)) } else { None }; - - let mut s = String::with_capacity(num_digits); - - for pos in 0..num_digits { - let digit = char::from_digit(self.uniform.sample(&mut self.rng), 10).unwrap(); - s.push(digit); - - if let Some(dec_pos) = dec_pos { - if pos == dec_pos { - s.push('.'); - } - } - } - - if has_exp { - let exp = self.rng.random_range(EXP_RANGE); - write!(s, "e{exp}").unwrap(); - } - - Some(s) - } -} diff --git a/src/etc/test-float-parse/src/gen_/sparse.rs b/src/etc/test-float-parse/src/gen_/sparse.rs deleted file mode 100644 index 72b65d4ce7f..00000000000 --- a/src/etc/test-float-parse/src/gen_/sparse.rs +++ /dev/null @@ -1,99 +0,0 @@ -use std::fmt::Write; - -use crate::traits::BoxGenIter; -use crate::{Float, Generator}; - -const POWERS_OF_TWO: [u128; 128] = make_powers_of_two(); - -const fn make_powers_of_two() -> [u128; 128] { - let mut ret = [0; 128]; - let mut i = 0; - while i < 128 { - ret[i] = 1 << i; - i += 1; - } - - ret -} - -/// Can't clone this result because of lifetime errors, just use a macro. -macro_rules! pow_iter { - () => { - (0..F::BITS).map(|i| F::Int::try_from(POWERS_OF_TWO[i as usize]).unwrap()) - }; -} - -/// Test all numbers that include three 1s in the binary representation as integers. -pub struct FewOnesInt -where - FewOnesInt: Generator, -{ - iter: BoxGenIter, -} - -impl Generator for FewOnesInt -where - >::Error: std::fmt::Debug, -{ - const SHORT_NAME: &'static str = "few ones int"; - - type WriteCtx = F::Int; - - fn total_tests() -> u64 { - u64::from(F::BITS).pow(3) - } - - fn new() -> Self { - let iter = pow_iter!() - .flat_map(move |a| pow_iter!().map(move |b| (a, b))) - .flat_map(move |(a, b)| pow_iter!().map(move |c| (a, b, c))) - .map(|(a, b, c)| a | b | c); - - Self { iter: Box::new(iter) } - } - - fn write_string(s: &mut String, ctx: Self::WriteCtx) { - write!(s, "{ctx}").unwrap(); - } -} - -impl Iterator for FewOnesInt { - type Item = F::Int; - - fn next(&mut self) -> Option { - self.iter.next() - } -} - -/// Similar to `FewOnesInt` except test those bit patterns as a float. -pub struct FewOnesFloat(FewOnesInt); - -impl Generator for FewOnesFloat -where - >::Error: std::fmt::Debug, -{ - const NAME: &'static str = "few ones float"; - const SHORT_NAME: &'static str = "few ones float"; - - type WriteCtx = F; - - fn total_tests() -> u64 { - FewOnesInt::::total_tests() - } - - fn new() -> Self { - Self(FewOnesInt::new()) - } - - fn write_string(s: &mut String, ctx: Self::WriteCtx) { - write!(s, "{ctx:e}").unwrap(); - } -} - -impl Iterator for FewOnesFloat { - type Item = F; - - fn next(&mut self) -> Option { - self.0.next().map(|i| F::from_bits(i)) - } -} diff --git a/src/etc/test-float-parse/src/gen_/spot_checks.rs b/src/etc/test-float-parse/src/gen_/spot_checks.rs deleted file mode 100644 index 18691f9d6cf..00000000000 --- a/src/etc/test-float-parse/src/gen_/spot_checks.rs +++ /dev/null @@ -1,101 +0,0 @@ -use std::fmt::Write; - -use crate::traits::{Float, Generator}; - -const SPECIAL: &[&str] = &[ - "inf", "Inf", "iNf", "INF", "-inf", "-Inf", "-iNf", "-INF", "+inf", "+Inf", "+iNf", "+INF", - "nan", "NaN", "NAN", "nAn", "-nan", "-NaN", "-NAN", "-nAn", "+nan", "+NaN", "+NAN", "+nAn", - "1", "-1", "+1", "1e1", "-1e1", "+1e1", "1e-1", "-1e-1", "+1e-1", "1e+1", "-1e+1", "+1e+1", - "1E1", "-1E1", "+1E1", "1E-1", "-1E-1", "+1E-1", "1E+1", "-1E+1", "+1E+1", "0", "-0", "+0", -]; - -/// Check various non-numeric special strings. -pub struct Special { - iter: std::slice::Iter<'static, &'static str>, -} - -impl Generator for Special { - const NAME: &'static str = "special values"; - - const SHORT_NAME: &'static str = "special"; - - type WriteCtx = &'static str; - - fn total_tests() -> u64 { - SPECIAL.len().try_into().unwrap() - } - - fn new() -> Self { - Self { iter: SPECIAL.iter() } - } - - fn write_string(s: &mut String, ctx: Self::WriteCtx) { - s.write_str(ctx).unwrap(); - } -} - -impl Iterator for Special { - type Item = &'static str; - - fn next(&mut self) -> Option { - self.iter.next().copied() - } -} - -/// Strings that we know have failed in the past -const REGRESSIONS: &[&str] = &[ - // From - "1234567890123456789012345678901234567890e-340", - "2.225073858507201136057409796709131975934819546351645648023426109724822222021076945516529523908135087914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012981122451451889849057222307285255133155755015914397476397983411801999323962548289017107081850690630666655994938275772572015763062690663332647565300009245888316433037779791869612049497390377829704905051080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621572289880258182545180325707018860872113128079512233426288368622321503775666622503982534335974568884423900265498198385487948292206894721689831099698365846814022854243330660339850886445804001034933970427567186443383770486037861622771738545623065874679014086723327636718749999999999999999999999999999999999999e-308", - "2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508791414915891303962110687008643869459464552765720740782062174337998814106326732925355228688137214901298112245145188984905722230728525513315575501591439747639798341180199932396254828901710708185069063066665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505108060994073026293712895895000358379996720725430436028407889577179615094551674824347103070260914462157228988025818254518032570701886087211312807951223342628836862232150377566662250398253433597456888442390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042756718644338377048603786162277173854562306587467901408672332763671875e-308", - "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000222507385850720138309023271733240406421921598046233183055332741688720443481391819585428315901251102056406733973103581100515243416155346010885601238537771882113077799353200233047961014744258363607192156504694250373420837525080665061665815894872049117996859163964850063590877011830487479978088775374994945158045160505091539985658247081864511353793580499211598108576605199243335211435239014879569960959128889160299264151106346631339366347758651302937176204732563178148566435087212282863764204484681140761391147706280168985324411002416144742161856716615054015428508471675290190316132277889672970737312333408698898317506783884692609277397797285865965494109136909540613646756870239867831529068098461721092462539672851562500000000000000001", - "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.9999999999999999999999999999999999999999999999999999999999999999999999", - "2.47032822920623272e-324", - "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316", - "3.237883913302901289588352412501532174863037669423108059901297049552301970670676565786835742587799557860615776559838283435514391084153169252689190564396459577394618038928365305143463955100356696665629202017331344031730044369360205258345803431471660032699580731300954848363975548690010751530018881758184174569652173110473696022749934638425380623369774736560008997404060967498028389191878963968575439222206416981462690113342524002724385941651051293552601421155333430225237291523843322331326138431477823591142408800030775170625915670728657003151953664260769822494937951845801530895238439819708403389937873241463484205608000027270531106827387907791444918534771598750162812548862768493201518991668028251730299953143924168545708663913273994694463908672332763671875E-319", - "6.953355807847677105972805215521891690222119817145950754416205607980030131549636688806115726399441880065386399864028691275539539414652831584795668560082999889551357784961446896042113198284213107935110217162654939802416034676213829409720583759540476786936413816541621287843248433202369209916612249676005573022703244799714622116542188837770376022371172079559125853382801396219552418839469770514904192657627060319372847562301074140442660237844114174497210955449896389180395827191602886654488182452409583981389442783377001505462015745017848754574668342161759496661766020028752888783387074850773192997102997936619876226688096314989645766000479009083731736585750335262099860150896718774401964796827166283225641992040747894382698751809812609536720628966577351093292236328125E-310", - "3.339068557571188581835713701280943911923401916998521771655656997328440314559615318168849149074662609099998113009465566426808170378434065722991659642619467706034884424989741080790766778456332168200464651593995817371782125010668346652995912233993254584461125868481633343674905074271064409763090708017856584019776878812425312008812326260363035474811532236853359905334625575404216060622858633280744301892470300555678734689978476870369853549413277156622170245846166991655321535529623870646888786637528995592800436177901746286272273374471701452991433047257863864601424252024791567368195056077320885329384322332391564645264143400798619665040608077549162173963649264049738362290606875883456826586710961041737908872035803481241600376705491726170293986797332763671875E-319", - "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999e-324", - "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125e-324", - "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125001e-324", - "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984374999e-324", - "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375e-324", - "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375001e-324", - "94393431193180696942841837085033647913224148539854e-358", - "104308485241983990666713401708072175773165034278685682646111762292409330928739751702404658197872319129036519947435319418387839758990478549477777586673075945844895981012024387992135617064532141489278815239849108105951619997829153633535314849999674266169258928940692239684771590065027025835804863585454872499320500023126142553932654370362024104462255244034053203998964360882487378334860197725139151265590832887433736189468858614521708567646743455601905935595381852723723645799866672558576993978025033590728687206296379801363024094048327273913079612469982585674824156000783167963081616214710691759864332339239688734656548790656486646106983450809073750535624894296242072010195710276073042036425579852459556183541199012652571123898996574563824424330960027873516082763671875e-1075", - "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247032822920623272088284396434110686182529901307162382212792841250337753635104375932649918180817996189898282347722858865463328355177969898199387398005390939063150356595155702263922908583924491051844359318028499365361525003193704576782492193656236698636584807570015857692699037063119282795585513329278343384093519780155312465972635795746227664652728272200563740064854999770965994704540208281662262378573934507363390079677619305775067401763246736009689513405355374585166611342237666786041621596804619144672918403005300575308490487653917113865916462395249126236538818796362393732804238910186723484976682350898633885879256283027559956575244555072551893136908362547791869486679949683240497058210285131854513962138377228261454376934125320985913276672363281249", - "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247032822920623272088284396434110686182529901307162382212792841250337753635104375932649918180817996189898282347722858865463328355177969898199387398005390939063150356595155702263922908583924491051844359318028499365361525003193704576782492193656236698636584807570015857692699037063119282795585513329278343384093519780155312465972635795746227664652728272200563740064854999770965994704540208281662262378573934507363390079677619305775067401763246736009689513405355374585166611342237666786041621596804619144672918403005300575308490487653917113865916462395249126236538818796362393732804238910186723484976682350898633885879256283027559956575244555072551893136908362547791869486679949683240497058210285131854513962138377228261454376934125320985913276672363281251", -]; - -/// Check items that failed in the past. -pub struct RegressionCheck { - iter: std::slice::Iter<'static, &'static str>, -} - -impl Generator for RegressionCheck { - const NAME: &'static str = "regression check"; - - const SHORT_NAME: &'static str = "regression"; - - type WriteCtx = &'static str; - - fn total_tests() -> u64 { - REGRESSIONS.len().try_into().unwrap() - } - - fn new() -> Self { - Self { iter: REGRESSIONS.iter() } - } - - fn write_string(s: &mut String, ctx: Self::WriteCtx) { - s.write_str(ctx).unwrap(); - } -} - -impl Iterator for RegressionCheck { - type Item = &'static str; - - fn next(&mut self) -> Option { - self.iter.next().copied() - } -} diff --git a/src/etc/test-float-parse/src/gen_/subnorm.rs b/src/etc/test-float-parse/src/gen_/subnorm.rs deleted file mode 100644 index 654f324b9b0..00000000000 --- a/src/etc/test-float-parse/src/gen_/subnorm.rs +++ /dev/null @@ -1,108 +0,0 @@ -use std::fmt::Write; -use std::ops::RangeInclusive; - -use crate::{Float, Generator, Int}; - -/// Spot check some edge cases for subnormals. -pub struct SubnormEdgeCases { - cases: [F::Int; 6], - index: usize, -} - -impl SubnormEdgeCases { - /// Shorthand - const I1: F::Int = F::Int::ONE; - - fn edge_cases() -> [F::Int; 6] { - // Comments use an 8-bit mantissa as a demo - [ - // 0b00000001 - Self::I1, - // 0b10000000 - Self::I1 << (F::MAN_BITS - 1), - // 0b00001000 - Self::I1 << ((F::MAN_BITS / 2) - 1), - // 0b00001111 - Self::I1 << ((F::MAN_BITS / 2) - 1), - // 0b00001111 - Self::I1 << ((F::MAN_BITS / 2) - 1), - // 0b11111111 - F::MAN_MASK, - ] - } -} - -impl Generator for SubnormEdgeCases { - const NAME: &'static str = "subnormal edge cases"; - const SHORT_NAME: &'static str = "subnorm edge"; - - type WriteCtx = F; - - fn new() -> Self { - Self { cases: Self::edge_cases(), index: 0 } - } - - fn total_tests() -> u64 { - Self::edge_cases().len().try_into().unwrap() - } - - fn write_string(s: &mut String, ctx: Self::WriteCtx) { - write!(s, "{ctx:e}").unwrap(); - } -} - -impl Iterator for SubnormEdgeCases { - type Item = F; - - fn next(&mut self) -> Option { - let i = self.cases.get(self.index)?; - self.index += 1; - - Some(F::from_bits(*i)) - } -} - -/// Test all subnormals up to `1 << 22`. -pub struct SubnormComplete { - iter: RangeInclusive, -} - -impl Generator for SubnormComplete -where - RangeInclusive: Iterator, -{ - const NAME: &'static str = "subnormal"; - const SHORT_NAME: &'static str = "subnorm "; - - type WriteCtx = F; - - fn total_tests() -> u64 { - let iter = Self::new().iter; - (F::Int::ONE + *iter.end() - *iter.start()).try_into().unwrap() - } - - fn new() -> Self { - let upper_lim = if F::MAN_BITS >= 22 { - F::Int::ONE << 22 - } else { - (F::Int::ONE << F::MAN_BITS) - F::Int::ONE - }; - - Self { iter: F::Int::ZERO..=upper_lim } - } - - fn write_string(s: &mut String, ctx: Self::WriteCtx) { - write!(s, "{ctx:e}").unwrap(); - } -} - -impl Iterator for SubnormComplete -where - RangeInclusive: Iterator, -{ - type Item = F; - - fn next(&mut self) -> Option { - Some(F::from_bits(self.iter.next()?)) - } -} diff --git a/src/etc/test-float-parse/src/lib.rs b/src/etc/test-float-parse/src/lib.rs deleted file mode 100644 index f590149523b..00000000000 --- a/src/etc/test-float-parse/src/lib.rs +++ /dev/null @@ -1,419 +0,0 @@ -#![feature(f16)] -#![feature(cfg_target_has_reliable_f16_f128)] -#![expect(internal_features)] // reliable_f16_f128 - -mod traits; -mod ui; -mod validate; - -use std::any::type_name; -use std::cmp::min; -use std::ops::RangeInclusive; -use std::process::ExitCode; -use std::sync::OnceLock; -use std::sync::atomic::{AtomicU64, Ordering}; -use std::{fmt, time}; - -use rand::distr::{Distribution, StandardUniform}; -use rayon::prelude::*; -use time::{Duration, Instant}; -use traits::{Float, Generator, Int}; -use validate::CheckError; - -/// Test generators. -mod gen_ { - pub mod exhaustive; - pub mod exponents; - pub mod fuzz; - pub mod integers; - pub mod long_fractions; - pub mod many_digits; - pub mod sparse; - pub mod spot_checks; - pub mod subnorm; -} - -/// How many failures to exit after if unspecified. -const DEFAULT_MAX_FAILURES: u64 = 20; - -/// Register exhaustive tests only for <= 32 bits. No more because it would take years. -const MAX_BITS_FOR_EXHAUUSTIVE: u32 = 32; - -/// If there are more tests than this threshold, the test will be deferred until after all -/// others run (so as to avoid thread pool starvation). They also can be excluded with -/// `--skip-huge`. -const HUGE_TEST_CUTOFF: u64 = 5_000_000; - -/// Seed for tests that use a deterministic RNG. -const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; - -/// Global configuration. -#[derive(Debug)] -pub struct Config { - pub timeout: Duration, - /// Failures per test - pub max_failures: u64, - pub disable_max_failures: bool, - /// If `None`, the default will be used - pub fuzz_count: Option, - pub skip_huge: bool, -} - -impl Default for Config { - fn default() -> Self { - Self { - timeout: Duration::from_secs(60 * 60 * 3), - max_failures: DEFAULT_MAX_FAILURES, - disable_max_failures: false, - fuzz_count: None, - skip_huge: false, - } - } -} - -/// Collect, filter, and launch all tests. -pub fn run(cfg: Config, include: &[String], exclude: &[String]) -> ExitCode { - // With default parallelism, the CPU doesn't saturate. We don't need to be nice to - // other processes, so do 1.5x to make sure we use all available resources. - let threads = std::thread::available_parallelism().map(Into::into).unwrap_or(0) * 3 / 2; - rayon::ThreadPoolBuilder::new().num_threads(threads).build_global().unwrap(); - - let mut tests = register_tests(&cfg); - println!("registered"); - let initial_tests: Vec<_> = tests.iter().map(|t| t.name.clone()).collect(); - - let unmatched: Vec<_> = include - .iter() - .chain(exclude.iter()) - .filter(|filt| !tests.iter().any(|t| t.matches(filt))) - .collect(); - - assert!( - unmatched.is_empty(), - "filters were provided that have no matching tests: {unmatched:#?}" - ); - - tests.retain(|test| !exclude.iter().any(|exc| test.matches(exc))); - - if cfg.skip_huge { - tests.retain(|test| !test.is_huge_test()); - } - - if !include.is_empty() { - tests.retain(|test| include.iter().any(|inc| test.matches(inc))); - } - - for exc in initial_tests.iter().filter(|orig_name| !tests.iter().any(|t| t.name == **orig_name)) - { - println!("Skipping test '{exc}'"); - } - - println!("Launching all"); - let elapsed = launch_tests(&mut tests, &cfg); - ui::finish_all(&tests, elapsed, &cfg) -} - -/// Enumerate tests to run but don't actually run them. -pub fn register_tests(cfg: &Config) -> Vec { - let mut tests = Vec::new(); - - // Register normal generators for all floats. - - #[cfg(not(bootstrap))] - #[cfg(target_has_reliable_f16)] - register_float::(&mut tests, cfg); - register_float::(&mut tests, cfg); - register_float::(&mut tests, cfg); - - tests.sort_unstable_by_key(|t| (t.float_name, t.gen_name)); - for i in 0..(tests.len() - 1) { - if tests[i].gen_name == tests[i + 1].gen_name { - panic!("duplicate test name {}", tests[i].gen_name); - } - } - - tests -} - -/// Register all generators for a single float. -fn register_float(tests: &mut Vec, cfg: &Config) -where - RangeInclusive: Iterator, - >::Error: std::fmt::Debug, - StandardUniform: Distribution<::Int>, -{ - if F::BITS <= MAX_BITS_FOR_EXHAUUSTIVE { - // Only run exhaustive tests if there is a chance of completion. - TestInfo::register::>(tests); - } - - gen_::fuzz::Fuzz::::set_iterations(cfg.fuzz_count); - - TestInfo::register::>(tests); - TestInfo::register::>(tests); - TestInfo::register::>(tests); - TestInfo::register::>(tests); - TestInfo::register::(tests); - TestInfo::register::(tests); - TestInfo::register::>(tests); - TestInfo::register::>(tests); - TestInfo::register::>(tests); - TestInfo::register::(tests); - TestInfo::register::(tests); - TestInfo::register::>(tests); - TestInfo::register::>(tests); -} - -/// Configuration for a single test. -#[derive(Debug)] -pub struct TestInfo { - pub name: String, - float_name: &'static str, - float_bits: u32, - gen_name: &'static str, - /// Name for display in the progress bar. - short_name: String, - /// Pad the short name to a common width for progress bar use. - short_name_padded: String, - total_tests: u64, - /// Function to launch this test. - launch: fn(&TestInfo, &Config), - /// Progress bar to be updated. - progress: Option, - /// Once completed, this will be set. - completed: OnceLock, -} - -impl TestInfo { - /// Check if either the name or short name is a match, for filtering. - fn matches(&self, pat: &str) -> bool { - self.short_name.contains(pat) || self.name.contains(pat) - } - - /// Create a `TestInfo` for a given float and generator, then add it to a list. - fn register>(v: &mut Vec) { - let f_name = type_name::(); - let gen_name = G::NAME; - let gen_short_name = G::SHORT_NAME; - let name = format!("{f_name} {gen_name}"); - let short_name = format!("{f_name} {gen_short_name}"); - let short_name_padded = format!("{short_name:18}"); - - let info = TestInfo { - float_name: f_name, - float_bits: F::BITS, - gen_name, - progress: None, - name, - short_name_padded, - short_name, - launch: test_runner::, - total_tests: G::total_tests(), - completed: OnceLock::new(), - }; - v.push(info); - } - - /// True if this should be run after all others. - fn is_huge_test(&self) -> bool { - self.total_tests >= HUGE_TEST_CUTOFF - } - - /// When the test is finished, update progress bar messages and finalize. - fn complete(&self, c: Completed) { - self.progress.as_ref().unwrap().complete(&c, 0); - self.completed.set(c).unwrap(); - } -} - -/// Result of an input did not parsing successfully. -#[derive(Clone, Debug)] -enum CheckFailure { - /// Above the zero cutoff but got rounded to zero. - UnexpectedZero, - /// Below the infinity cutoff but got rounded to infinity. - UnexpectedInf, - /// Above the negative infinity cutoff but got rounded to negative infinity. - UnexpectedNegInf, - /// Got a `NaN` when none was expected. - UnexpectedNan, - /// Expected `NaN`, got none. - ExpectedNan, - /// Expected infinity, got finite. - ExpectedInf, - /// Expected negative infinity, got finite. - ExpectedNegInf, - /// The value exceeded its error tolerance. - InvalidReal { - /// Error from the expected value, as a float. - error_float: Option, - /// Error as a rational string (since it can't always be represented as a float). - error_str: Box, - /// True if the error was caused by not rounding to even at the midpoint between - /// two representable values. - incorrect_midpoint_rounding: bool, - }, - /// String did not parse successfully. - ParsingFailed(Box), - /// A panic was caught. - Panic(Box), -} - -impl fmt::Display for CheckFailure { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - CheckFailure::UnexpectedZero => { - write!(f, "incorrectly rounded to 0 (expected nonzero)") - } - CheckFailure::UnexpectedInf => { - write!(f, "incorrectly rounded to +inf (expected finite)") - } - CheckFailure::UnexpectedNegInf => { - write!(f, "incorrectly rounded to -inf (expected finite)") - } - CheckFailure::UnexpectedNan => write!(f, "got a NaN where none was expected"), - CheckFailure::ExpectedNan => write!(f, "expected a NaN but did not get it"), - CheckFailure::ExpectedInf => write!(f, "expected +inf but did not get it"), - CheckFailure::ExpectedNegInf => write!(f, "expected -inf but did not get it"), - CheckFailure::InvalidReal { error_float, error_str, incorrect_midpoint_rounding } => { - if *incorrect_midpoint_rounding { - write!( - f, - "midpoint between two representable values did not correctly \ - round to even; error: {error_str}" - )?; - } else { - write!(f, "real number did not parse correctly; error: {error_str}")?; - } - - if let Some(float) = error_float { - write!(f, " ({float})")?; - } - Ok(()) - } - CheckFailure::ParsingFailed(e) => write!(f, "parsing failed: {e}"), - CheckFailure::Panic(e) => write!(f, "function panicked: {e}"), - } - } -} - -/// Information about a completed test generator. -#[derive(Clone, Debug)] -struct Completed { - /// Finished tests (both successful and failed). - executed: u64, - /// Failed tests. - failures: u64, - /// Extra exit information if unsuccessful. - result: Result, - /// If there is something to warn about (e.g bad estimate), leave it here. - warning: Option>, - /// Total time to run the test. - elapsed: Duration, -} - -/// Marker for completing all tests (used in `Result` types). -#[derive(Clone, Debug)] -struct FinishedAll; - -/// Reasons for exiting early. -#[derive(Clone, Debug)] -enum EarlyExit { - Timeout, - MaxFailures, -} - -/// Run all tests in `tests`. -/// -/// This launches a main thread that receives messages and handlees UI updates, and uses the -/// rest of the thread pool to execute the tests. -fn launch_tests(tests: &mut [TestInfo], cfg: &Config) -> Duration { - // Run shorter tests and smaller float types first. - tests.sort_unstable_by_key(|test| (test.total_tests, test.float_bits)); - - for test in tests.iter() { - println!("Launching test '{}'", test.name); - } - - let mut all_progress_bars = Vec::new(); - let start = Instant::now(); - - for test in tests.iter_mut() { - test.progress = Some(ui::Progress::new(test, &mut all_progress_bars)); - ui::set_panic_hook(&all_progress_bars); - ((test.launch)(test, cfg)); - } - - start.elapsed() -} - -/// Test runer for a single generator. -/// -/// This calls the generator's iterator multiple times (in parallel) and validates each output. -fn test_runner>(test: &TestInfo, cfg: &Config) { - let gen_ = G::new(); - let executed = AtomicU64::new(0); - let failures = AtomicU64::new(0); - - let checks_per_update = min(test.total_tests, 1000); - let started = Instant::now(); - - // Function to execute for a single test iteration. - let check_one = |buf: &mut String, ctx: G::WriteCtx| { - let executed = executed.fetch_add(1, Ordering::Relaxed); - buf.clear(); - G::write_string(buf, ctx); - - match validate::validate::(buf) { - Ok(()) => (), - Err(e) => { - let CheckError { fail, input, float_res } = e; - test.progress.as_ref().unwrap().println(&format!( - "Failure in '{}': {fail}. parsing '{input}'. Parsed as: {float_res}", - test.name - )); - - let f = failures.fetch_add(1, Ordering::Relaxed); - // End early if the limit is exceeded. - if f >= cfg.max_failures { - return Err(EarlyExit::MaxFailures); - } - } - }; - - // Send periodic updates - if executed % checks_per_update == 0 { - let failures = failures.load(Ordering::Relaxed); - test.progress.as_ref().unwrap().update(executed, failures); - if started.elapsed() > cfg.timeout { - return Err(EarlyExit::Timeout); - } - } - - Ok(()) - }; - - // Run the test iterations in parallel. Each thread gets a string buffer to write - // its check values to. - let res = gen_.par_bridge().try_for_each_init(String::new, check_one); - - let elapsed = started.elapsed(); - let executed = executed.into_inner(); - let failures = failures.into_inner(); - - // Warn about bad estimates if relevant. - let warning = if executed != test.total_tests && res.is_ok() { - let msg = format!( - "executed tests != estimated ({executed} != {}) for {}", - test.total_tests, - G::NAME - ); - - Some(msg.into()) - } else { - None - }; - - let result = res.map(|()| FinishedAll); - test.complete(Completed { executed, failures, result, warning, elapsed }); -} diff --git a/src/etc/test-float-parse/src/main.rs b/src/etc/test-float-parse/src/main.rs deleted file mode 100644 index 9c6cad7324f..00000000000 --- a/src/etc/test-float-parse/src/main.rs +++ /dev/null @@ -1,129 +0,0 @@ -use std::process::ExitCode; -use std::time::Duration; - -use test_float_parse as tfp; - -static HELP: &str = r#"Usage: - - ./test-float-parse [--timeout x] [--exclude x] [--max-failures x] [INCLUDE ...] - ./test-float-parse [--fuzz-count x] [INCLUDE ...] - ./test-float-parse [--skip-huge] [INCLUDE ...] - ./test-float-parse --list - -Args: - - INCLUDE Include only tests with names containing these - strings. If this argument is not specified, all tests - are run. - --timeout N Exit after this amount of time (in seconds). - --exclude FILTER Skip tests containing this string. May be specified - more than once. - --list List available tests. - --max-failures N Limit to N failures per test. Defaults to 20. Pass - "--max-failures none" to remove this limit. - --fuzz-count N Run the fuzzer with N iterations. Only has an effect - if fuzz tests are enabled. Pass `--fuzz-count none` - to remove this limit. - --skip-huge Skip tests that run for a long time. - --all Reset previous `--exclude`, `--skip-huge`, and - `INCLUDE` arguments (useful for running all tests - via `./x`). -"#; - -enum ArgMode { - Any, - Timeout, - Exclude, - FuzzCount, - MaxFailures, -} - -fn main() -> ExitCode { - if cfg!(debug_assertions) { - println!( - "WARNING: running in debug mode. Release mode is recommended to reduce test duration." - ); - std::thread::sleep(Duration::from_secs(2)); - } - - let args: Vec<_> = std::env::args().skip(1).collect(); - if args.iter().any(|arg| arg == "--help" || arg == "-h") { - println!("{HELP}"); - return ExitCode::SUCCESS; - } - - if args.iter().any(|arg| arg == "--list") { - let tests = tfp::register_tests(&tfp::Config::default()); - println!("Available tests:"); - for t in tests { - println!("{}", t.name); - } - - return ExitCode::SUCCESS; - } - - let (cfg, include, exclude) = parse_args(args); - - tfp::run(cfg, &include, &exclude) -} - -/// Simple command argument parser -fn parse_args(args: Vec) -> (tfp::Config, Vec, Vec) { - let mut cfg = tfp::Config::default(); - - let mut mode = ArgMode::Any; - let mut include = Vec::new(); - let mut exclude = Vec::new(); - - for arg in args { - mode = match mode { - ArgMode::Any if arg == "--timeout" => ArgMode::Timeout, - ArgMode::Any if arg == "--exclude" => ArgMode::Exclude, - ArgMode::Any if arg == "--max-failures" => ArgMode::MaxFailures, - ArgMode::Any if arg == "--fuzz-count" => ArgMode::FuzzCount, - ArgMode::Any if arg == "--skip-huge" => { - cfg.skip_huge = true; - ArgMode::Any - } - ArgMode::Any if arg == "--all" => { - cfg.skip_huge = false; - include.clear(); - exclude.clear(); - ArgMode::Any - } - ArgMode::Any if arg.starts_with('-') => { - panic!("Unknown argument {arg}. Usage:\n{HELP}") - } - ArgMode::Any => { - include.push(arg); - ArgMode::Any - } - ArgMode::Timeout => { - cfg.timeout = Duration::from_secs(arg.parse().unwrap()); - ArgMode::Any - } - ArgMode::MaxFailures => { - if arg == "none" { - cfg.disable_max_failures = true; - } else { - cfg.max_failures = arg.parse().unwrap(); - } - ArgMode::Any - } - ArgMode::FuzzCount => { - if arg == "none" { - cfg.fuzz_count = Some(u64::MAX); - } else { - cfg.fuzz_count = Some(arg.parse().unwrap()); - } - ArgMode::Any - } - ArgMode::Exclude => { - exclude.push(arg); - ArgMode::Any - } - } - } - - (cfg, include, exclude) -} diff --git a/src/etc/test-float-parse/src/traits.rs b/src/etc/test-float-parse/src/traits.rs deleted file mode 100644 index 16484f8fe2c..00000000000 --- a/src/etc/test-float-parse/src/traits.rs +++ /dev/null @@ -1,206 +0,0 @@ -//! Interfaces used throughout this crate. - -use std::str::FromStr; -use std::{fmt, ops}; - -use num::Integer; -use num::bigint::ToBigInt; - -use crate::validate::Constants; - -/// Integer types. -#[allow(dead_code)] // Some functions only used for testing -pub trait Int: - Clone - + Copy - + fmt::Debug - + fmt::Display - + fmt::LowerHex - + ops::Add - + ops::Sub - + ops::Shl - + ops::Shr - + ops::BitAnd - + ops::BitOr - + ops::Not - + ops::AddAssign - + ops::BitAndAssign - + ops::BitOrAssign - + From - + TryFrom - + TryFrom - + TryFrom - + TryFrom - + TryInto - + TryInto - + ToBigInt - + PartialOrd - + Integer - + Send - + 'static -{ - type Signed: Int; - type Bytes: Default + AsMut<[u8]>; - - const BITS: u32; - const ZERO: Self; - const ONE: Self; - const MAX: Self; - - fn to_signed(self) -> Self::Signed; - fn wrapping_neg(self) -> Self; - fn trailing_zeros(self) -> u32; - - fn hex(self) -> String { - format!("{self:x}") - } -} - -macro_rules! impl_int { - ($($uty:ty, $sty:ty);+) => { - $( - impl Int for $uty { - type Signed = $sty; - type Bytes = [u8; Self::BITS as usize / 8]; - const BITS: u32 = Self::BITS; - const ZERO: Self = 0; - const ONE: Self = 1; - const MAX: Self = Self::MAX; - fn to_signed(self) -> Self::Signed { - self.try_into().unwrap() - } - fn wrapping_neg(self) -> Self { - self.wrapping_neg() - } - fn trailing_zeros(self) -> u32 { - self.trailing_zeros() - } - } - - impl Int for $sty { - type Signed = Self; - type Bytes = [u8; Self::BITS as usize / 8]; - const BITS: u32 = Self::BITS; - const ZERO: Self = 0; - const ONE: Self = 1; - const MAX: Self = Self::MAX; - fn to_signed(self) -> Self::Signed { - self - } - fn wrapping_neg(self) -> Self { - self.wrapping_neg() - } - fn trailing_zeros(self) -> u32 { - self.trailing_zeros() - } - } - )+ - } -} - -impl_int!(u16, i16; u32, i32; u64, i64); - -/// Floating point types. -pub trait Float: - Copy + fmt::Debug + fmt::LowerExp + FromStr + Sized + Send + 'static -{ - /// Unsigned integer of same width - type Int: Int; - type SInt: Int; - - /// Total bits - const BITS: u32; - - /// (Stored) bits in the mantissa) - const MAN_BITS: u32; - - /// Bits in the exponent - const EXP_BITS: u32 = Self::BITS - Self::MAN_BITS - 1; - - /// A saturated exponent (all ones) - const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; - - /// The exponent bias, also its maximum value - const EXP_BIAS: u32 = Self::EXP_SAT >> 1; - - const MAN_MASK: Self::Int; - const SIGN_MASK: Self::Int; - - fn from_bits(i: Self::Int) -> Self; - fn to_bits(self) -> Self::Int; - - /// Rational constants associated with this float type. - fn constants() -> &'static Constants; - - fn is_sign_negative(self) -> bool { - (self.to_bits() & Self::SIGN_MASK) > Self::Int::ZERO - } - - /// Exponent without adjustment for bias. - fn exponent(self) -> u32 { - ((self.to_bits() >> Self::MAN_BITS) & Self::EXP_SAT.try_into().unwrap()).try_into().unwrap() - } - - fn mantissa(self) -> Self::Int { - self.to_bits() & Self::MAN_MASK - } -} - -macro_rules! impl_float { - ($($fty:ty, $ity:ty);+) => { - $( - impl Float for $fty { - type Int = $ity; - type SInt = ::Signed; - const BITS: u32 = <$ity>::BITS; - const MAN_BITS: u32 = Self::MANTISSA_DIGITS - 1; - const MAN_MASK: Self::Int = (Self::Int::ONE << Self::MAN_BITS) - Self::Int::ONE; - const SIGN_MASK: Self::Int = Self::Int::ONE << (Self::BITS-1); - fn from_bits(i: Self::Int) -> Self { Self::from_bits(i) } - fn to_bits(self) -> Self::Int { self.to_bits() } - fn constants() -> &'static Constants { - use std::sync::LazyLock; - static CONSTANTS: LazyLock = LazyLock::new(Constants::new::<$fty>); - &CONSTANTS - } - } - )+ - } -} - -impl_float!(f32, u32; f64, u64); - -#[cfg(not(bootstrap))] -#[cfg(target_has_reliable_f16)] -impl_float!(f16, u16); - -/// A test generator. Should provide an iterator that produces unique patterns to parse. -/// -/// The iterator needs to provide a `WriteCtx` (could be anything), which is then used to -/// write the string at a later step. This is done separately so that we can reuse string -/// allocations (which otherwise turn out to be a pretty expensive part of these tests). -pub trait Generator: Iterator + Send + 'static { - /// Full display and filtering name - const NAME: &'static str = Self::SHORT_NAME; - - /// Name for display with the progress bar - const SHORT_NAME: &'static str; - - /// The context needed to create a test string. - type WriteCtx: Send; - - /// Number of tests that will be run. - fn total_tests() -> u64; - - /// Constructor for this test generator. - fn new() -> Self; - - /// Create a test string given write context, which was produced as a step from the iterator. - /// - /// `s` will be provided empty. - fn write_string(s: &mut String, ctx: Self::WriteCtx); -} - -/// For tests that use iterator combinators, it is easier to just to box the iterator than trying -/// to specify its type. This is a shorthand for the usual type. -pub type BoxGenIter = Box>::WriteCtx> + Send>; diff --git a/src/etc/test-float-parse/src/ui.rs b/src/etc/test-float-parse/src/ui.rs deleted file mode 100644 index 73473eef0bf..00000000000 --- a/src/etc/test-float-parse/src/ui.rs +++ /dev/null @@ -1,168 +0,0 @@ -//! Progress bars and such. - -use std::any::type_name; -use std::fmt; -use std::io::{self, Write}; -use std::process::ExitCode; -use std::time::Duration; - -use indicatif::{ProgressBar, ProgressStyle}; - -use crate::{Completed, Config, EarlyExit, FinishedAll, TestInfo}; - -/// Templates for progress bars. -const PB_TEMPLATE: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \ - {human_pos:>8}/{human_len:8} {msg} f {per_sec:14} eta {eta:8}"; -const PB_TEMPLATE_FINAL: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \ - {human_pos:>8}/{human_len:8} {msg:.COLOR} {per_sec:18} {elapsed_precise}"; - -/// Thin abstraction over our usage of a `ProgressBar`. -#[derive(Debug)] -pub struct Progress { - pb: ProgressBar, - make_final_style: NoDebug ProgressStyle + Sync>>, -} - -impl Progress { - /// Create a new progress bar within a multiprogress bar. - pub fn new(test: &TestInfo, all_bars: &mut Vec) -> Self { - let initial_template = PB_TEMPLATE.replace("NAME", &test.short_name_padded); - let final_template = PB_TEMPLATE_FINAL.replace("NAME", &test.short_name_padded); - let initial_style = - ProgressStyle::with_template(&initial_template).unwrap().progress_chars("##-"); - let make_final_style = move |color| { - ProgressStyle::with_template(&final_template.replace("COLOR", color)) - .unwrap() - .progress_chars("##-") - }; - - let pb = ProgressBar::new(test.total_tests); - pb.set_style(initial_style); - pb.set_length(test.total_tests); - pb.set_message("0"); - all_bars.push(pb.clone()); - - Progress { pb, make_final_style: NoDebug(Box::new(make_final_style)) } - } - - /// Completed a out of b tests. - pub fn update(&self, completed: u64, failures: u64) { - // Infrequently update the progress bar. - if completed % 5_000 == 0 || failures > 0 { - self.pb.set_position(completed); - } - - if failures > 0 { - self.pb.set_message(format! {"{failures}"}); - } - } - - /// Finalize the progress bar. - pub fn complete(&self, c: &Completed, real_total: u64) { - let f = c.failures; - let (color, msg, finish_fn): (&str, String, fn(&ProgressBar)) = match &c.result { - Ok(FinishedAll) if f > 0 => { - ("red", format!("{f} f (completed with errors)",), ProgressBar::finish) - } - Ok(FinishedAll) => { - ("green", format!("{f} f (completed successfully)",), ProgressBar::finish) - } - Err(EarlyExit::Timeout) => ("red", format!("{f} f (timed out)"), ProgressBar::abandon), - Err(EarlyExit::MaxFailures) => { - ("red", format!("{f} f (failure limit)"), ProgressBar::abandon) - } - }; - - self.pb.set_position(real_total); - self.pb.set_style(self.make_final_style.0(color)); - self.pb.set_message(msg); - finish_fn(&self.pb); - } - - /// Print a message to stdout above the current progress bar. - pub fn println(&self, msg: &str) { - self.pb.suspend(|| println!("{msg}")); - } -} - -/// Print final messages after all tests are complete. -pub fn finish_all(tests: &[TestInfo], total_elapsed: Duration, cfg: &Config) -> ExitCode { - println!("\n\nResults:"); - - let mut failed_generators = 0; - let mut stopped_generators = 0; - - for t in tests { - let Completed { executed, failures, elapsed, warning, result } = t.completed.get().unwrap(); - - let stat = if result.is_err() { - stopped_generators += 1; - "STOPPED" - } else if *failures > 0 { - failed_generators += 1; - "FAILURE" - } else { - "SUCCESS" - }; - - println!( - " {stat} for generator '{name}'. {passed}/{executed} passed in {elapsed:?}", - name = t.name, - passed = executed - failures, - ); - - if let Some(warning) = warning { - println!(" warning: {warning}"); - } - - match result { - Ok(FinishedAll) => (), - Err(EarlyExit::Timeout) => { - println!(" exited early; exceded {:?} timeout", cfg.timeout) - } - Err(EarlyExit::MaxFailures) => { - println!(" exited early; exceeded {:?} max failures", cfg.max_failures) - } - } - } - - println!( - "{passed}/{} tests succeeded in {total_elapsed:?} ({passed} passed, {} failed, {} stopped)", - tests.len(), - failed_generators, - stopped_generators, - passed = tests.len() - failed_generators - stopped_generators, - ); - - if failed_generators > 0 || stopped_generators > 0 { - ExitCode::FAILURE - } else { - ExitCode::SUCCESS - } -} - -/// indicatif likes to eat panic messages. This workaround isn't ideal, but it improves things. -/// . -pub fn set_panic_hook(drop_bars: &[ProgressBar]) { - let hook = std::panic::take_hook(); - let drop_bars = drop_bars.to_owned(); - std::panic::set_hook(Box::new(move |info| { - for bar in &drop_bars { - bar.abandon(); - println!(); - io::stdout().flush().unwrap(); - io::stderr().flush().unwrap(); - } - hook(info); - })); -} - -/// Allow non-Debug items in a `derive(Debug)` struct. -#[derive(Clone)] -struct NoDebug(T); - -impl fmt::Debug for NoDebug { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(type_name::()) - } -} diff --git a/src/etc/test-float-parse/src/validate.rs b/src/etc/test-float-parse/src/validate.rs deleted file mode 100644 index 40dda274e3b..00000000000 --- a/src/etc/test-float-parse/src/validate.rs +++ /dev/null @@ -1,394 +0,0 @@ -//! Everything related to verifying that parsed outputs are correct. - -use std::any::{Any, type_name}; -use std::collections::BTreeMap; -use std::ops::RangeInclusive; -use std::str::FromStr; -use std::sync::LazyLock; - -use num::bigint::ToBigInt; -use num::{BigInt, BigRational, FromPrimitive, Signed, ToPrimitive}; - -use crate::{CheckFailure, Float, Int}; - -/// Powers of two that we store for constants. Account for binary128 which has a 15-bit exponent. -const POWERS_OF_TWO_RANGE: RangeInclusive = (-(2 << 15))..=(2 << 15); - -/// Powers of ten that we cache. Account for binary128, which can fit +4932/-4931 -const POWERS_OF_TEN_RANGE: RangeInclusive = -5_000..=5_000; - -/// Cached powers of 10 so we can look them up rather than recreating. -static POWERS_OF_TEN: LazyLock> = LazyLock::new(|| { - POWERS_OF_TEN_RANGE.map(|exp| (exp, BigRational::from_u32(10).unwrap().pow(exp))).collect() -}); - -/// Rational property-related constants for a specific float type. -#[allow(dead_code)] -#[derive(Debug)] -pub struct Constants { - /// The minimum positive value (a subnormal). - min_subnormal: BigRational, - /// The maximum possible finite value. - max: BigRational, - /// Cutoff between rounding to zero and rounding to the minimum value (min subnormal). - zero_cutoff: BigRational, - /// Cutoff between rounding to the max value and rounding to infinity. - inf_cutoff: BigRational, - /// Opposite of `inf_cutoff` - neg_inf_cutoff: BigRational, - /// The powers of two for all relevant integers. - powers_of_two: BTreeMap, - /// Half of each power of two. ULP = "unit in last position". - /// - /// This is a mapping from integers to half the precision available at that exponent. In other - /// words, `0.5 * 2^n` = `2^(n-1)`, which is half the distance between `m * 2^n` and - /// `(m + 1) * 2^n`, m ∈ ℤ. - /// - /// So, this is the maximum error from a real number to its floating point representation, - /// assuming the float type can represent the exponent. - half_ulp: BTreeMap, - /// Handy to have around so we don't need to reallocate for it - two: BigInt, -} - -impl Constants { - pub fn new() -> Self { - let two_int = &BigInt::from_u32(2).unwrap(); - let two = &BigRational::from_integer(2.into()); - - // The minimum subnormal (aka minimum positive) value. Most negative power of two is the - // minimum exponent (bias - 1) plus the extra from shifting within the mantissa bits. - let min_subnormal = two.pow(-(F::EXP_BIAS + F::MAN_BITS - 1).to_signed()); - - // The maximum value is the maximum exponent with a fully saturated mantissa. This - // is easiest to calculate by evaluating what the next value up would be if representable - // (zeroed mantissa, exponent increments by one, i.e. `2^(bias + 1)`), and subtracting - // a single LSB (`2 ^ (-mantissa_bits)`). - let max = (two - two.pow(-F::MAN_BITS.to_signed())) * (two.pow(F::EXP_BIAS.to_signed())); - let zero_cutoff = &min_subnormal / two_int; - - let inf_cutoff = &max + two_int.pow(F::EXP_BIAS - F::MAN_BITS - 1); - let neg_inf_cutoff = -&inf_cutoff; - - let powers_of_two: BTreeMap = - (POWERS_OF_TWO_RANGE).map(|n| (n, two.pow(n))).collect(); - let mut half_ulp = powers_of_two.clone(); - half_ulp.iter_mut().for_each(|(_k, v)| *v = &*v / two_int); - - Self { - min_subnormal, - max, - zero_cutoff, - inf_cutoff, - neg_inf_cutoff, - powers_of_two, - half_ulp, - two: two_int.clone(), - } - } -} - -/// Validate that a string parses correctly -pub fn validate(input: &str) -> Result<(), CheckError> { - // Catch panics in case debug assertions within `std` fail. - let parsed = std::panic::catch_unwind(|| { - input.parse::().map_err(|e| CheckError { - fail: CheckFailure::ParsingFailed(e.to_string().into()), - input: input.into(), - float_res: "none".into(), - }) - }) - .map_err(|e| convert_panic_error(&e, input))??; - - // Parsed float, decoded into significand and exponent - let decoded = decode(parsed); - - // Float parsed separately into a rational - let rational = Rational::parse(input); - - // Verify that the values match - decoded.check(rational, input) -} - -/// Turn panics into concrete error types. -fn convert_panic_error(e: &dyn Any, input: &str) -> CheckError { - let msg = e - .downcast_ref::() - .map(|s| s.as_str()) - .or_else(|| e.downcast_ref::<&str>().copied()) - .unwrap_or("(no contents)"); - - CheckError { - fail: CheckFailure::Panic(msg.into()), - input: input.into(), - float_res: "none".into(), - } -} - -/// The result of parsing a string to a float type. -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum FloatRes { - Inf, - NegInf, - Zero, - Nan, - /// A real number with significand and exponent. Value is `sig * 2 ^ exp`. - Real { - sig: F::SInt, - exp: i32, - }, -} - -#[derive(Clone, Debug)] -pub struct CheckError { - pub fail: CheckFailure, - /// String for which parsing was attempted. - pub input: Box, - /// The parsed & decomposed `FloatRes`, already stringified so we don't need generics here. - pub float_res: Box, -} - -impl FloatRes { - /// Given a known exact rational, check that this representation is accurate within the - /// limits of the float representation. If not, construct a failure `Update` to send. - fn check(self, expected: Rational, input: &str) -> Result<(), CheckError> { - let consts = F::constants(); - // let bool_helper = |cond: bool, err| cond.then_some(()).ok_or(err); - - let res = match (expected, self) { - // Easy correct cases - (Rational::Inf, FloatRes::Inf) - | (Rational::NegInf, FloatRes::NegInf) - | (Rational::Nan, FloatRes::Nan) => Ok(()), - - // Easy incorrect cases - ( - Rational::Inf, - FloatRes::NegInf | FloatRes::Zero | FloatRes::Nan | FloatRes::Real { .. }, - ) => Err(CheckFailure::ExpectedInf), - ( - Rational::NegInf, - FloatRes::Inf | FloatRes::Zero | FloatRes::Nan | FloatRes::Real { .. }, - ) => Err(CheckFailure::ExpectedNegInf), - ( - Rational::Nan, - FloatRes::Inf | FloatRes::NegInf | FloatRes::Zero | FloatRes::Real { .. }, - ) => Err(CheckFailure::ExpectedNan), - (Rational::Finite(_), FloatRes::Nan) => Err(CheckFailure::UnexpectedNan), - - // Cases near limits - (Rational::Finite(r), FloatRes::Zero) => { - if r <= consts.zero_cutoff { - Ok(()) - } else { - Err(CheckFailure::UnexpectedZero) - } - } - (Rational::Finite(r), FloatRes::Inf) => { - if r >= consts.inf_cutoff { - Ok(()) - } else { - Err(CheckFailure::UnexpectedInf) - } - } - (Rational::Finite(r), FloatRes::NegInf) => { - if r <= consts.neg_inf_cutoff { - Ok(()) - } else { - Err(CheckFailure::UnexpectedNegInf) - } - } - - // Actual numbers - (Rational::Finite(r), FloatRes::Real { sig, exp }) => Self::validate_real(r, sig, exp), - }; - - res.map_err(|fail| CheckError { - fail, - input: input.into(), - float_res: format!("{self:?}").into(), - }) - } - - /// Check that `sig * 2^exp` is the same as `rational`, within the float's error margin. - fn validate_real(rational: BigRational, sig: F::SInt, exp: i32) -> Result<(), CheckFailure> { - let consts = F::constants(); - - // `2^exp`. Use cached powers of two to be faster. - let two_exp = consts - .powers_of_two - .get(&exp) - .unwrap_or_else(|| panic!("missing exponent {exp} for {}", type_name::())); - - // Rational from the parsed value, `sig * 2^exp` - let parsed_rational = two_exp * sig.to_bigint().unwrap(); - let error = (parsed_rational - &rational).abs(); - - // Determine acceptable error at this exponent, which is halfway between this value - // (`sig * 2^exp`) and the next value up (`(sig+1) * 2^exp`). - let half_ulp = consts.half_ulp.get(&exp).unwrap(); - - // If we are within one error value (but not equal) then we rounded correctly. - if &error < half_ulp { - return Ok(()); - } - - // For values where we are exactly between two representable values, meaning that the error - // is exactly one half of the precision at that exponent, we need to round to an even - // binary value (i.e. mantissa ends in 0). - let incorrect_midpoint_rounding = if &error == half_ulp { - if sig & F::SInt::ONE == F::SInt::ZERO { - return Ok(()); - } - - // We rounded to odd rather than even; failing based on midpoint rounding. - true - } else { - // We are out of spec for some other reason. - false - }; - - let one_ulp = consts.half_ulp.get(&(exp + 1)).unwrap(); - assert_eq!(one_ulp, &(half_ulp * &consts.two), "ULP values are incorrect"); - - let relative_error = error / one_ulp; - - Err(CheckFailure::InvalidReal { - error_float: relative_error.to_f64(), - error_str: relative_error.to_string().into(), - incorrect_midpoint_rounding, - }) - } - - /// Remove trailing zeros in the significand and adjust the exponent - #[cfg(test)] - fn normalize(self) -> Self { - use std::cmp::min; - - match self { - Self::Real { sig, exp } => { - // If there are trailing zeroes, remove them and increment the exponent instead - let shift = min(sig.trailing_zeros(), exp.wrapping_neg().try_into().unwrap()); - Self::Real { sig: sig >> shift, exp: exp + i32::try_from(shift).unwrap() } - } - _ => self, - } - } -} - -/// Decompose a float into its integral components. This includes the implicit bit. -/// -/// If `allow_nan` is `false`, panic if `NaN` values are reached. -fn decode(f: F) -> FloatRes { - let ione = F::SInt::ONE; - let izero = F::SInt::ZERO; - - let mut exponent_biased = f.exponent(); - let mut mantissa = f.mantissa().to_signed(); - - if exponent_biased == 0 { - if mantissa == izero { - return FloatRes::Zero; - } - - exponent_biased += 1; - } else if exponent_biased == F::EXP_SAT { - if mantissa != izero { - return FloatRes::Nan; - } - - if f.is_sign_negative() { - return FloatRes::NegInf; - } - - return FloatRes::Inf; - } else { - // Set implicit bit - mantissa |= ione << F::MAN_BITS; - } - - let mut exponent = i32::try_from(exponent_biased).unwrap(); - - // Adjust for bias and the rnage of the mantissa - exponent -= i32::try_from(F::EXP_BIAS + F::MAN_BITS).unwrap(); - - if f.is_sign_negative() { - mantissa = mantissa.wrapping_neg(); - } - - FloatRes::Real { sig: mantissa, exp: exponent } -} - -/// A rational or its unrepresentable values. -#[derive(Clone, Debug, PartialEq)] -enum Rational { - Inf, - NegInf, - Nan, - Finite(BigRational), -} - -impl Rational { - /// Turn a string into a rational. `None` if `NaN`. - fn parse(s: &str) -> Rational { - let mut s = s; // lifetime rules - - if s.strip_prefix('+').unwrap_or(s).eq_ignore_ascii_case("nan") - || s.eq_ignore_ascii_case("-nan") - { - return Rational::Nan; - } - - if s.strip_prefix('+').unwrap_or(s).eq_ignore_ascii_case("inf") { - return Rational::Inf; - } - - if s.eq_ignore_ascii_case("-inf") { - return Rational::NegInf; - } - - // Fast path; no decimals or exponents ot parse - if s.bytes().all(|b| b.is_ascii_digit() || b == b'-') { - return Rational::Finite(BigRational::from_str(s).unwrap()); - } - - let mut ten_exp: i32 = 0; - - // Remove and handle e.g. `e-4`, `e+10`, `e5` suffixes - if let Some(pos) = s.bytes().position(|b| b == b'e' || b == b'E') { - let (dec, exp) = s.split_at(pos); - s = dec; - ten_exp = exp[1..].parse().unwrap(); - } - - // Remove the decimal and instead change our exponent - // E.g. "12.3456" becomes "123456 * 10^-4" - let mut s_owned; - if let Some(pos) = s.bytes().position(|b| b == b'.') { - ten_exp = ten_exp.checked_sub((s.len() - pos - 1).try_into().unwrap()).unwrap(); - s_owned = s.to_owned(); - s_owned.remove(pos); - s = &s_owned; - } - - // let pow = BigRational::from_u32(10).unwrap().pow(ten_exp); - let pow = - POWERS_OF_TEN.get(&ten_exp).unwrap_or_else(|| panic!("missing power of ten {ten_exp}")); - let r = pow - * BigInt::from_str(s) - .unwrap_or_else(|e| panic!("`BigInt::from_str(\"{s}\")` failed with {e}")); - Rational::Finite(r) - } - - #[cfg(test)] - fn expect_finite(self) -> BigRational { - let Self::Finite(r) = self else { - panic!("got non rational: {self:?}"); - }; - - r - } -} - -#[cfg(test)] -mod tests; diff --git a/src/etc/test-float-parse/src/validate/tests.rs b/src/etc/test-float-parse/src/validate/tests.rs deleted file mode 100644 index ab0e7d8a7ba..00000000000 --- a/src/etc/test-float-parse/src/validate/tests.rs +++ /dev/null @@ -1,149 +0,0 @@ -use num::ToPrimitive; - -use super::*; - -#[test] -fn test_parse_rational() { - assert_eq!(Rational::parse("1234").expect_finite(), BigRational::new(1234.into(), 1.into())); - assert_eq!( - Rational::parse("-1234").expect_finite(), - BigRational::new((-1234).into(), 1.into()) - ); - assert_eq!(Rational::parse("1e+6").expect_finite(), BigRational::new(1000000.into(), 1.into())); - assert_eq!(Rational::parse("1e-6").expect_finite(), BigRational::new(1.into(), 1000000.into())); - assert_eq!( - Rational::parse("10.4e6").expect_finite(), - BigRational::new(10400000.into(), 1.into()) - ); - assert_eq!( - Rational::parse("10.4e+6").expect_finite(), - BigRational::new(10400000.into(), 1.into()) - ); - assert_eq!( - Rational::parse("10.4e-6").expect_finite(), - BigRational::new(13.into(), 1250000.into()) - ); - assert_eq!( - Rational::parse("10.4243566462342456234124").expect_finite(), - BigRational::new(104243566462342456234124_i128.into(), 10000000000000000000000_i128.into()) - ); - assert_eq!(Rational::parse("inf"), Rational::Inf); - assert_eq!(Rational::parse("+inf"), Rational::Inf); - assert_eq!(Rational::parse("-inf"), Rational::NegInf); - assert_eq!(Rational::parse("NaN"), Rational::Nan); -} - -#[test] -fn test_decode() { - assert_eq!(decode(0f32), FloatRes::Zero); - assert_eq!(decode(f32::INFINITY), FloatRes::Inf); - assert_eq!(decode(f32::NEG_INFINITY), FloatRes::NegInf); - assert_eq!(decode(1.0f32).normalize(), FloatRes::Real { sig: 1, exp: 0 }); - assert_eq!(decode(-1.0f32).normalize(), FloatRes::Real { sig: -1, exp: 0 }); - assert_eq!(decode(100.0f32).normalize(), FloatRes::Real { sig: 100, exp: 0 }); - assert_eq!(decode(100.5f32).normalize(), FloatRes::Real { sig: 201, exp: -1 }); - assert_eq!(decode(-4.004f32).normalize(), FloatRes::Real { sig: -8396997, exp: -21 }); - assert_eq!(decode(0.0004f32).normalize(), FloatRes::Real { sig: 13743895, exp: -35 }); - assert_eq!(decode(f32::from_bits(0x1)).normalize(), FloatRes::Real { sig: 1, exp: -149 }); -} - -#[test] -fn test_validate() { - validate::("0").unwrap(); - validate::("-0").unwrap(); - validate::("1").unwrap(); - validate::("-1").unwrap(); - validate::("1.1").unwrap(); - validate::("-1.1").unwrap(); - validate::("1e10").unwrap(); - validate::("1e1000").unwrap(); - validate::("-1e1000").unwrap(); - validate::("1e-1000").unwrap(); - validate::("-1e-1000").unwrap(); -} - -#[test] -fn test_validate_real() { - // Most of the arbitrary values come from checking against . - let r = &BigRational::from_float(10.0).unwrap(); - FloatRes::::validate_real(r.clone(), 10, 0).unwrap(); - FloatRes::::validate_real(r.clone(), 10, -1).unwrap_err(); - FloatRes::::validate_real(r.clone(), 10, 1).unwrap_err(); - - let r = &BigRational::from_float(0.25).unwrap(); - FloatRes::::validate_real(r.clone(), 1, -2).unwrap(); - FloatRes::::validate_real(r.clone(), 2, -2).unwrap_err(); - - let r = &BigRational::from_float(1234.5678).unwrap(); - FloatRes::::validate_real(r.clone(), 0b100110100101001000101011, -13).unwrap(); - FloatRes::::validate_real(r.clone(), 0b100110100101001000101010, -13).unwrap_err(); - FloatRes::::validate_real(r.clone(), 0b100110100101001000101100, -13).unwrap_err(); - - let r = &BigRational::from_float(-1234.5678).unwrap(); - FloatRes::::validate_real(r.clone(), -0b100110100101001000101011, -13).unwrap(); - FloatRes::::validate_real(r.clone(), -0b100110100101001000101010, -13).unwrap_err(); - FloatRes::::validate_real(r.clone(), -0b100110100101001000101100, -13).unwrap_err(); -} - -#[test] -#[allow(unused)] -fn test_validate_real_rounding() { - // Check that we catch when values don't round to even. - - // For f32, the cutoff between 1.0 and the next value up (1.0000001) is - // 1.000000059604644775390625. Anything below it should round down, anything above it should - // round up, and the value itself should round _down_ because `1.0` has an even significand but - // 1.0000001 is odd. - let v1_low_down = Rational::parse("1.00000005960464477539062499999").expect_finite(); - let v1_mid_down = Rational::parse("1.000000059604644775390625").expect_finite(); - let v1_high_up = Rational::parse("1.00000005960464477539062500001").expect_finite(); - - let exp = -(f32::MAN_BITS as i32); - let v1_down_sig = 1 << f32::MAN_BITS; - let v1_up_sig = (1 << f32::MAN_BITS) | 0b1; - - FloatRes::::validate_real(v1_low_down.clone(), v1_down_sig, exp).unwrap(); - FloatRes::::validate_real(v1_mid_down.clone(), v1_down_sig, exp).unwrap(); - FloatRes::::validate_real(v1_high_up.clone(), v1_up_sig, exp).unwrap(); - FloatRes::::validate_real(-v1_low_down.clone(), -v1_down_sig, exp).unwrap(); - FloatRes::::validate_real(-v1_mid_down.clone(), -v1_down_sig, exp).unwrap(); - FloatRes::::validate_real(-v1_high_up.clone(), -v1_up_sig, exp).unwrap(); - - // 1.000000178813934326171875 is between 1.0000001 and the next value up, 1.0000002. The middle - // value here should round _up_ since 1.0000002 has an even mantissa. - let v2_low_down = Rational::parse("1.00000017881393432617187499999").expect_finite(); - let v2_mid_up = Rational::parse("1.000000178813934326171875").expect_finite(); - let v2_high_up = Rational::parse("1.00000017881393432617187500001").expect_finite(); - - let v2_down_sig = v1_up_sig; - let v2_up_sig = (1 << f32::MAN_BITS) | 0b10; - - FloatRes::::validate_real(v2_low_down.clone(), v2_down_sig, exp).unwrap(); - FloatRes::::validate_real(v2_mid_up.clone(), v2_up_sig, exp).unwrap(); - FloatRes::::validate_real(v2_high_up.clone(), v2_up_sig, exp).unwrap(); - FloatRes::::validate_real(-v2_low_down.clone(), -v2_down_sig, exp).unwrap(); - FloatRes::::validate_real(-v2_mid_up.clone(), -v2_up_sig, exp).unwrap(); - FloatRes::::validate_real(-v2_high_up.clone(), -v2_up_sig, exp).unwrap(); - - // Rounding the wrong direction should error - for res in [ - FloatRes::::validate_real(v1_mid_down.clone(), v1_up_sig, exp), - FloatRes::::validate_real(v2_mid_up.clone(), v2_down_sig, exp), - FloatRes::::validate_real(-v1_mid_down.clone(), -v1_up_sig, exp), - FloatRes::::validate_real(-v2_mid_up.clone(), -v2_down_sig, exp), - ] { - let e = res.unwrap_err(); - let CheckFailure::InvalidReal { incorrect_midpoint_rounding: true, .. } = e else { - panic!("{e:?}"); - }; - } -} - -/// Just a quick check that the constants are what we expect. -#[test] -fn check_constants() { - assert_eq!(f32::constants().max.to_f32().unwrap(), f32::MAX); - assert_eq!(f32::constants().min_subnormal.to_f32().unwrap(), f32::from_bits(0x1)); - assert_eq!(f64::constants().max.to_f64().unwrap(), f64::MAX); - assert_eq!(f64::constants().min_subnormal.to_f64().unwrap(), f64::from_bits(0x1)); -} diff --git a/src/tools/test-float-parse/Cargo.lock b/src/tools/test-float-parse/Cargo.lock new file mode 100644 index 00000000000..3f60423fed3 --- /dev/null +++ b/src/tools/test-float-parse/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "test-float-parse" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/src/tools/test-float-parse/Cargo.toml b/src/tools/test-float-parse/Cargo.toml new file mode 100644 index 00000000000..e407e322f9e --- /dev/null +++ b/src/tools/test-float-parse/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "test-float-parse" +version = "0.1.0" +edition = "2024" +publish = false + +[dependencies] +indicatif = { version = "0.17.8", default-features = false } +num = "0.4.3" +rand = "0.9.0" +rand_chacha = "0.9.0" +rayon = "1" + +[lib] +name = "test_float_parse" + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + # Internal features aren't marked known config by default + 'cfg(target_has_reliable_f16)', +] diff --git a/src/tools/test-float-parse/README.md b/src/tools/test-float-parse/README.md new file mode 100644 index 00000000000..5e2c43d1cad --- /dev/null +++ b/src/tools/test-float-parse/README.md @@ -0,0 +1,55 @@ +# Float Parsing Tests + +These are tests designed to test decimal to float conversions (`dec2flt`) used +by the standard library. + +It consists of a collection of test generators that each generate a set of +patterns intended to test a specific property. In addition, there are exhaustive +tests (for <= `f32`) and fuzzers (for anything that can't be run exhaustively). + +The generators work as follows: + +- Each generator is a struct that lives somewhere in the `gen` module. Usually + it is generic over a float type. +- These generators must implement `Iterator`, which should return a context type + that can be used to construct a test string (but usually not the string + itself). +- They must also implement the `Generator` trait, which provides a method to + write test context to a string as a test case, as well as some extra metadata. + + The split between context generation and string construction is so that we can + reuse string allocations. +- Each generator gets registered once for each float type. Each of these + generators then get their iterator called, and each test case checked against + the float type's parse implementation. + +Some generators produce decimal strings, others create bit patterns that need to +be bitcasted to the float type, which then uses its `Display` implementation to +write to a string. For these, float to decimal (`flt2dec`) conversions also get +tested, if unintentionally. + +For each test case, the following is done: + +- The test string is parsed to the float type using the standard library's + implementation. +- The test string is parsed separately to a `BigRational`, which acts as a + representation with infinite precision. +- The rational value then gets checked that it is within the float's + representable values (absolute value greater than the smallest number to round + to zero, but less less than the first value to round to infinity). If these + limits are exceeded, check that the parsed float reflects that. +- For real nonzero numbers, the parsed float is converted into a rational using + `significand * 2^exponent`. It is then checked against the actual rational + value, and verified to be within half a bit's precision of the parsed value. + Also it is checked that ties round to even. + +This is all highly parallelized with `rayon`; test generators can run in +parallel, and their tests get chunked and run in parallel. + +There is a simple command line that allows filtering which tests are run, +setting the number of iterations for fuzzing tests, limiting failures, setting +timeouts, etc. See `main.rs` or run with `--help` for options. + +Note that when running via `./x`, only tests that take less than a few minutes +are run by default. Navigate to the crate (or pass `-C` to Cargo) and run it +directly to run all tests or pass specific arguments. diff --git a/src/tools/test-float-parse/src/gen_/exhaustive.rs b/src/tools/test-float-parse/src/gen_/exhaustive.rs new file mode 100644 index 00000000000..01458fb0b60 --- /dev/null +++ b/src/tools/test-float-parse/src/gen_/exhaustive.rs @@ -0,0 +1,42 @@ +use std::fmt::Write; +use std::ops::RangeInclusive; + +use crate::{Float, Generator, Int}; + +/// Test every possible bit pattern. This is infeasible to run on any float types larger than +/// `f32` (which takes about an hour). +pub struct Exhaustive { + iter: RangeInclusive, +} + +impl Generator for Exhaustive +where + RangeInclusive: Iterator, +{ + const SHORT_NAME: &'static str = "exhaustive"; + + type WriteCtx = F; + + fn total_tests() -> u64 { + 1u64.checked_shl(F::Int::BITS).expect("More than u64::MAX tests") + } + + fn new() -> Self { + Self { iter: F::Int::ZERO..=F::Int::MAX } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx:e}").unwrap(); + } +} + +impl Iterator for Exhaustive +where + RangeInclusive: Iterator, +{ + type Item = F; + + fn next(&mut self) -> Option { + Some(F::from_bits(self.iter.next()?)) + } +} diff --git a/src/tools/test-float-parse/src/gen_/exponents.rs b/src/tools/test-float-parse/src/gen_/exponents.rs new file mode 100644 index 00000000000..3748e9d380c --- /dev/null +++ b/src/tools/test-float-parse/src/gen_/exponents.rs @@ -0,0 +1,95 @@ +use std::fmt::Write; +use std::ops::RangeInclusive; + +use crate::traits::BoxGenIter; +use crate::{Float, Generator}; + +const SMALL_COEFF_MAX: i32 = 10_000; +const SMALL_EXP_MAX: i32 = 300; + +const SMALL_COEFF_RANGE: RangeInclusive = (-SMALL_COEFF_MAX)..=SMALL_COEFF_MAX; +const SMALL_EXP_RANGE: RangeInclusive = (-SMALL_EXP_MAX)..=SMALL_EXP_MAX; + +const LARGE_COEFF_RANGE: RangeInclusive = 0..=100_000; +const LARGE_EXP_RANGE: RangeInclusive = 300..=350; + +/// Check exponential values around zero. +pub struct SmallExponents { + iter: BoxGenIter, +} + +impl Generator for SmallExponents { + const NAME: &'static str = "small exponents"; + const SHORT_NAME: &'static str = "small exp"; + + /// `(coefficient, exponent)` + type WriteCtx = (i32, i32); + + fn total_tests() -> u64 { + ((1 + SMALL_COEFF_RANGE.end() - SMALL_COEFF_RANGE.start()) + * (1 + SMALL_EXP_RANGE.end() - SMALL_EXP_RANGE.start())) + .try_into() + .unwrap() + } + + fn new() -> Self { + let iter = SMALL_EXP_RANGE.flat_map(|exp| SMALL_COEFF_RANGE.map(move |coeff| (coeff, exp))); + + Self { iter: Box::new(iter) } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + let (coeff, exp) = ctx; + write!(s, "{coeff}e{exp}").unwrap(); + } +} + +impl Iterator for SmallExponents { + type Item = (i32, i32); + + fn next(&mut self) -> Option { + self.iter.next() + } +} + +/// Check exponential values further from zero. +pub struct LargeExponents { + iter: BoxGenIter, +} + +impl Generator for LargeExponents { + const NAME: &'static str = "large positive exponents"; + const SHORT_NAME: &'static str = "large exp"; + + /// `(coefficient, exponent, is_positive)` + type WriteCtx = (u32, u32, bool); + + fn total_tests() -> u64 { + ((1 + LARGE_EXP_RANGE.end() - LARGE_EXP_RANGE.start()) + * (1 + LARGE_COEFF_RANGE.end() - LARGE_COEFF_RANGE.start()) + * 2) + .into() + } + + fn new() -> Self { + let iter = LARGE_EXP_RANGE + .flat_map(|exp| LARGE_COEFF_RANGE.map(move |coeff| (coeff, exp))) + .flat_map(|(coeff, exp)| [(coeff, exp, false), (coeff, exp, true)]); + + Self { iter: Box::new(iter) } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + let (coeff, exp, is_positive) = ctx; + let sign = if is_positive { "" } else { "-" }; + write!(s, "{sign}{coeff}e{exp}").unwrap(); + } +} + +impl Iterator for LargeExponents { + type Item = (u32, u32, bool); + + fn next(&mut self) -> Option { + self.iter.next() + } +} diff --git a/src/tools/test-float-parse/src/gen_/fuzz.rs b/src/tools/test-float-parse/src/gen_/fuzz.rs new file mode 100644 index 00000000000..1d6c5562a14 --- /dev/null +++ b/src/tools/test-float-parse/src/gen_/fuzz.rs @@ -0,0 +1,87 @@ +use std::any::{TypeId, type_name}; +use std::collections::BTreeMap; +use std::fmt::Write; +use std::marker::PhantomData; +use std::ops::Range; +use std::sync::Mutex; + +use rand::Rng; +use rand::distr::{Distribution, StandardUniform}; +use rand_chacha::ChaCha8Rng; +use rand_chacha::rand_core::SeedableRng; + +use crate::{Float, Generator, Int, SEED}; + +/// Mapping of float types to the number of iterations that should be run. +/// +/// We could probably make `Generator::new` take an argument instead of the global state, +/// but we only load this once so it works. +static FUZZ_COUNTS: Mutex> = Mutex::new(BTreeMap::new()); + +/// Generic fuzzer; just tests deterministic random bit patterns N times. +pub struct Fuzz { + iter: Range, + rng: ChaCha8Rng, + /// Allow us to use generics in `Iterator`. + marker: PhantomData, +} + +impl Fuzz { + /// Register how many iterations the fuzzer should run for a type. Uses some logic by + /// default, but if `from_cfg` is `Some`, that will be used instead. + pub fn set_iterations(from_cfg: Option) { + let count = if let Some(cfg_count) = from_cfg { + cfg_count + } else if F::BITS <= crate::MAX_BITS_FOR_EXHAUUSTIVE { + // If we run exhaustively, still fuzz but only do half as many bits. The only goal here is + // to catch failures from e.g. high bit patterns before exhaustive tests would get to them. + (F::Int::MAX >> (F::BITS / 2)).try_into().unwrap() + } else { + // Eveything bigger gets a fuzz test with as many iterations as `f32` exhaustive. + u32::MAX.into() + }; + + let _ = FUZZ_COUNTS.lock().unwrap().insert(TypeId::of::(), count); + } +} + +impl Generator for Fuzz +where + StandardUniform: Distribution<::Int>, +{ + const SHORT_NAME: &'static str = "fuzz"; + + type WriteCtx = F; + + fn total_tests() -> u64 { + *FUZZ_COUNTS + .lock() + .unwrap() + .get(&TypeId::of::()) + .unwrap_or_else(|| panic!("missing fuzz count for {}", type_name::())) + } + + fn new() -> Self { + let rng = ChaCha8Rng::from_seed(SEED); + + Self { iter: 0..Self::total_tests(), rng, marker: PhantomData } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx:e}").unwrap(); + } +} + +impl Iterator for Fuzz +where + StandardUniform: Distribution<::Int>, +{ + type Item = >::WriteCtx; + + fn next(&mut self) -> Option { + let _ = self.iter.next()?; + let i: F::Int = self.rng.random(); + + Some(F::from_bits(i)) + } +} diff --git a/src/tools/test-float-parse/src/gen_/integers.rs b/src/tools/test-float-parse/src/gen_/integers.rs new file mode 100644 index 00000000000..070d188e88c --- /dev/null +++ b/src/tools/test-float-parse/src/gen_/integers.rs @@ -0,0 +1,104 @@ +use std::fmt::Write; +use std::ops::{Range, RangeInclusive}; + +use crate::traits::BoxGenIter; +use crate::{Float, Generator}; + +const SMALL_MAX_POW2: u32 = 19; + +/// All values up to the max power of two +const SMALL_VALUES: RangeInclusive = { + let max = 1i32 << SMALL_MAX_POW2; + (-max)..=max +}; + +/// Large values only get tested around powers of two +const LARGE_POWERS: Range = SMALL_MAX_POW2..128; + +/// We perturbe each large value around these ranges +const LARGE_PERTURBATIONS: RangeInclusive = -256..=256; + +/// Test all integers up to `2 ^ MAX_POW2` +pub struct SmallInt { + iter: RangeInclusive, +} + +impl Generator for SmallInt { + const NAME: &'static str = "small integer values"; + const SHORT_NAME: &'static str = "int small"; + + type WriteCtx = i32; + + fn total_tests() -> u64 { + (SMALL_VALUES.end() + 1 - SMALL_VALUES.start()).try_into().unwrap() + } + + fn new() -> Self { + Self { iter: SMALL_VALUES } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx}").unwrap(); + } +} + +impl Iterator for SmallInt { + type Item = i32; + + fn next(&mut self) -> Option { + self.iter.next() + } +} + +/// Test much bigger integers than [`SmallInt`]. +pub struct LargeInt { + iter: BoxGenIter, +} + +impl LargeInt { + const EDGE_CASES: [i128; 7] = [ + i32::MIN as i128, + i32::MAX as i128, + i64::MIN as i128, + i64::MAX as i128, + u64::MAX as i128, + i128::MIN, + i128::MAX, + ]; +} + +impl Generator for LargeInt { + const NAME: &'static str = "large integer values"; + const SHORT_NAME: &'static str = "int large"; + + type WriteCtx = i128; + + fn total_tests() -> u64 { + u64::try_from( + (i128::from(LARGE_POWERS.end - LARGE_POWERS.start) + + i128::try_from(Self::EDGE_CASES.len()).unwrap()) + * (LARGE_PERTURBATIONS.end() + 1 - LARGE_PERTURBATIONS.start()), + ) + .unwrap() + } + + fn new() -> Self { + let iter = LARGE_POWERS + .map(|pow| 1i128 << pow) + .chain(Self::EDGE_CASES) + .flat_map(|base| LARGE_PERTURBATIONS.map(move |perturb| base.saturating_add(perturb))); + + Self { iter: Box::new(iter) } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx}").unwrap(); + } +} +impl Iterator for LargeInt { + type Item = i128; + + fn next(&mut self) -> Option { + self.iter.next() + } +} diff --git a/src/tools/test-float-parse/src/gen_/long_fractions.rs b/src/tools/test-float-parse/src/gen_/long_fractions.rs new file mode 100644 index 00000000000..b75148b779c --- /dev/null +++ b/src/tools/test-float-parse/src/gen_/long_fractions.rs @@ -0,0 +1,58 @@ +use std::char; +use std::fmt::Write; + +use crate::{Float, Generator}; + +/// Number of decimal digits to check (all of them). +const MAX_DIGIT: u32 = 9; +/// Test with this many decimals in the string. +const MAX_DECIMALS: usize = 410; +const PREFIX: &str = "0."; + +/// Test e.g. `0.1`, `0.11`, `0.111`, `0.1111`, ..., `0.2`, `0.22`, ... +pub struct RepeatingDecimal { + digit: u32, + buf: String, +} + +impl Generator for RepeatingDecimal { + const NAME: &'static str = "repeating decimal"; + const SHORT_NAME: &'static str = "dec rep"; + + type WriteCtx = String; + + fn total_tests() -> u64 { + u64::from(MAX_DIGIT + 1) * u64::try_from(MAX_DECIMALS + 1).unwrap() + 1 + } + + fn new() -> Self { + Self { digit: 0, buf: PREFIX.to_owned() } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + *s = ctx; + } +} + +impl Iterator for RepeatingDecimal { + type Item = String; + + fn next(&mut self) -> Option { + if self.digit > MAX_DIGIT { + return None; + } + + let digit = self.digit; + let inc_digit = self.buf.len() - PREFIX.len() > MAX_DECIMALS; + + if inc_digit { + // Reset the string + self.buf.clear(); + self.digit += 1; + self.buf.write_str(PREFIX).unwrap(); + } + + self.buf.push(char::from_digit(digit, 10).unwrap()); + Some(self.buf.clone()) + } +} diff --git a/src/tools/test-float-parse/src/gen_/many_digits.rs b/src/tools/test-float-parse/src/gen_/many_digits.rs new file mode 100644 index 00000000000..741e11437fe --- /dev/null +++ b/src/tools/test-float-parse/src/gen_/many_digits.rs @@ -0,0 +1,84 @@ +use std::char; +use std::fmt::Write; +use std::marker::PhantomData; +use std::ops::{Range, RangeInclusive}; + +use rand::distr::{Distribution, Uniform}; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; + +use crate::{Float, Generator, SEED}; + +/// Total iterations +const ITERATIONS: u64 = 5_000_000; + +/// Possible lengths of the string, excluding decimals and exponents +const POSSIBLE_NUM_DIGITS: RangeInclusive = 100..=400; + +/// Range of possible exponents +const EXP_RANGE: Range = -4500..4500; + +/// Try strings of random digits. +pub struct RandDigits { + rng: ChaCha8Rng, + iter: Range, + uniform: Uniform, + /// Allow us to use generics in `Iterator`. + marker: PhantomData, +} + +impl Generator for RandDigits { + const NAME: &'static str = "random digits"; + + const SHORT_NAME: &'static str = "rand digits"; + + type WriteCtx = String; + + fn total_tests() -> u64 { + ITERATIONS + } + + fn new() -> Self { + let rng = ChaCha8Rng::from_seed(SEED); + let range = Uniform::try_from(0..10).unwrap(); + + Self { rng, iter: 0..ITERATIONS, uniform: range, marker: PhantomData } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + *s = ctx; + } +} + +impl Iterator for RandDigits { + type Item = String; + + fn next(&mut self) -> Option { + let _ = self.iter.next()?; + let num_digits = self.rng.random_range(POSSIBLE_NUM_DIGITS); + let has_decimal = self.rng.random_bool(0.2); + let has_exp = self.rng.random_bool(0.2); + + let dec_pos = if has_decimal { Some(self.rng.random_range(0..num_digits)) } else { None }; + + let mut s = String::with_capacity(num_digits); + + for pos in 0..num_digits { + let digit = char::from_digit(self.uniform.sample(&mut self.rng), 10).unwrap(); + s.push(digit); + + if let Some(dec_pos) = dec_pos { + if pos == dec_pos { + s.push('.'); + } + } + } + + if has_exp { + let exp = self.rng.random_range(EXP_RANGE); + write!(s, "e{exp}").unwrap(); + } + + Some(s) + } +} diff --git a/src/tools/test-float-parse/src/gen_/sparse.rs b/src/tools/test-float-parse/src/gen_/sparse.rs new file mode 100644 index 00000000000..72b65d4ce7f --- /dev/null +++ b/src/tools/test-float-parse/src/gen_/sparse.rs @@ -0,0 +1,99 @@ +use std::fmt::Write; + +use crate::traits::BoxGenIter; +use crate::{Float, Generator}; + +const POWERS_OF_TWO: [u128; 128] = make_powers_of_two(); + +const fn make_powers_of_two() -> [u128; 128] { + let mut ret = [0; 128]; + let mut i = 0; + while i < 128 { + ret[i] = 1 << i; + i += 1; + } + + ret +} + +/// Can't clone this result because of lifetime errors, just use a macro. +macro_rules! pow_iter { + () => { + (0..F::BITS).map(|i| F::Int::try_from(POWERS_OF_TWO[i as usize]).unwrap()) + }; +} + +/// Test all numbers that include three 1s in the binary representation as integers. +pub struct FewOnesInt +where + FewOnesInt: Generator, +{ + iter: BoxGenIter, +} + +impl Generator for FewOnesInt +where + >::Error: std::fmt::Debug, +{ + const SHORT_NAME: &'static str = "few ones int"; + + type WriteCtx = F::Int; + + fn total_tests() -> u64 { + u64::from(F::BITS).pow(3) + } + + fn new() -> Self { + let iter = pow_iter!() + .flat_map(move |a| pow_iter!().map(move |b| (a, b))) + .flat_map(move |(a, b)| pow_iter!().map(move |c| (a, b, c))) + .map(|(a, b, c)| a | b | c); + + Self { iter: Box::new(iter) } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx}").unwrap(); + } +} + +impl Iterator for FewOnesInt { + type Item = F::Int; + + fn next(&mut self) -> Option { + self.iter.next() + } +} + +/// Similar to `FewOnesInt` except test those bit patterns as a float. +pub struct FewOnesFloat(FewOnesInt); + +impl Generator for FewOnesFloat +where + >::Error: std::fmt::Debug, +{ + const NAME: &'static str = "few ones float"; + const SHORT_NAME: &'static str = "few ones float"; + + type WriteCtx = F; + + fn total_tests() -> u64 { + FewOnesInt::::total_tests() + } + + fn new() -> Self { + Self(FewOnesInt::new()) + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx:e}").unwrap(); + } +} + +impl Iterator for FewOnesFloat { + type Item = F; + + fn next(&mut self) -> Option { + self.0.next().map(|i| F::from_bits(i)) + } +} diff --git a/src/tools/test-float-parse/src/gen_/spot_checks.rs b/src/tools/test-float-parse/src/gen_/spot_checks.rs new file mode 100644 index 00000000000..18691f9d6cf --- /dev/null +++ b/src/tools/test-float-parse/src/gen_/spot_checks.rs @@ -0,0 +1,101 @@ +use std::fmt::Write; + +use crate::traits::{Float, Generator}; + +const SPECIAL: &[&str] = &[ + "inf", "Inf", "iNf", "INF", "-inf", "-Inf", "-iNf", "-INF", "+inf", "+Inf", "+iNf", "+INF", + "nan", "NaN", "NAN", "nAn", "-nan", "-NaN", "-NAN", "-nAn", "+nan", "+NaN", "+NAN", "+nAn", + "1", "-1", "+1", "1e1", "-1e1", "+1e1", "1e-1", "-1e-1", "+1e-1", "1e+1", "-1e+1", "+1e+1", + "1E1", "-1E1", "+1E1", "1E-1", "-1E-1", "+1E-1", "1E+1", "-1E+1", "+1E+1", "0", "-0", "+0", +]; + +/// Check various non-numeric special strings. +pub struct Special { + iter: std::slice::Iter<'static, &'static str>, +} + +impl Generator for Special { + const NAME: &'static str = "special values"; + + const SHORT_NAME: &'static str = "special"; + + type WriteCtx = &'static str; + + fn total_tests() -> u64 { + SPECIAL.len().try_into().unwrap() + } + + fn new() -> Self { + Self { iter: SPECIAL.iter() } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + s.write_str(ctx).unwrap(); + } +} + +impl Iterator for Special { + type Item = &'static str; + + fn next(&mut self) -> Option { + self.iter.next().copied() + } +} + +/// Strings that we know have failed in the past +const REGRESSIONS: &[&str] = &[ + // From + "1234567890123456789012345678901234567890e-340", + "2.225073858507201136057409796709131975934819546351645648023426109724822222021076945516529523908135087914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012981122451451889849057222307285255133155755015914397476397983411801999323962548289017107081850690630666655994938275772572015763062690663332647565300009245888316433037779791869612049497390377829704905051080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621572289880258182545180325707018860872113128079512233426288368622321503775666622503982534335974568884423900265498198385487948292206894721689831099698365846814022854243330660339850886445804001034933970427567186443383770486037861622771738545623065874679014086723327636718749999999999999999999999999999999999999e-308", + "2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508791414915891303962110687008643869459464552765720740782062174337998814106326732925355228688137214901298112245145188984905722230728525513315575501591439747639798341180199932396254828901710708185069063066665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505108060994073026293712895895000358379996720725430436028407889577179615094551674824347103070260914462157228988025818254518032570701886087211312807951223342628836862232150377566662250398253433597456888442390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042756718644338377048603786162277173854562306587467901408672332763671875e-308", + "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000222507385850720138309023271733240406421921598046233183055332741688720443481391819585428315901251102056406733973103581100515243416155346010885601238537771882113077799353200233047961014744258363607192156504694250373420837525080665061665815894872049117996859163964850063590877011830487479978088775374994945158045160505091539985658247081864511353793580499211598108576605199243335211435239014879569960959128889160299264151106346631339366347758651302937176204732563178148566435087212282863764204484681140761391147706280168985324411002416144742161856716615054015428508471675290190316132277889672970737312333408698898317506783884692609277397797285865965494109136909540613646756870239867831529068098461721092462539672851562500000000000000001", + "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.9999999999999999999999999999999999999999999999999999999999999999999999", + "2.47032822920623272e-324", + "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316", + "3.237883913302901289588352412501532174863037669423108059901297049552301970670676565786835742587799557860615776559838283435514391084153169252689190564396459577394618038928365305143463955100356696665629202017331344031730044369360205258345803431471660032699580731300954848363975548690010751530018881758184174569652173110473696022749934638425380623369774736560008997404060967498028389191878963968575439222206416981462690113342524002724385941651051293552601421155333430225237291523843322331326138431477823591142408800030775170625915670728657003151953664260769822494937951845801530895238439819708403389937873241463484205608000027270531106827387907791444918534771598750162812548862768493201518991668028251730299953143924168545708663913273994694463908672332763671875E-319", + "6.953355807847677105972805215521891690222119817145950754416205607980030131549636688806115726399441880065386399864028691275539539414652831584795668560082999889551357784961446896042113198284213107935110217162654939802416034676213829409720583759540476786936413816541621287843248433202369209916612249676005573022703244799714622116542188837770376022371172079559125853382801396219552418839469770514904192657627060319372847562301074140442660237844114174497210955449896389180395827191602886654488182452409583981389442783377001505462015745017848754574668342161759496661766020028752888783387074850773192997102997936619876226688096314989645766000479009083731736585750335262099860150896718774401964796827166283225641992040747894382698751809812609536720628966577351093292236328125E-310", + "3.339068557571188581835713701280943911923401916998521771655656997328440314559615318168849149074662609099998113009465566426808170378434065722991659642619467706034884424989741080790766778456332168200464651593995817371782125010668346652995912233993254584461125868481633343674905074271064409763090708017856584019776878812425312008812326260363035474811532236853359905334625575404216060622858633280744301892470300555678734689978476870369853549413277156622170245846166991655321535529623870646888786637528995592800436177901746286272273374471701452991433047257863864601424252024791567368195056077320885329384322332391564645264143400798619665040608077549162173963649264049738362290606875883456826586710961041737908872035803481241600376705491726170293986797332763671875E-319", + "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999e-324", + "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125e-324", + "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125001e-324", + "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984374999e-324", + "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375e-324", + "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375001e-324", + "94393431193180696942841837085033647913224148539854e-358", + "104308485241983990666713401708072175773165034278685682646111762292409330928739751702404658197872319129036519947435319418387839758990478549477777586673075945844895981012024387992135617064532141489278815239849108105951619997829153633535314849999674266169258928940692239684771590065027025835804863585454872499320500023126142553932654370362024104462255244034053203998964360882487378334860197725139151265590832887433736189468858614521708567646743455601905935595381852723723645799866672558576993978025033590728687206296379801363024094048327273913079612469982585674824156000783167963081616214710691759864332339239688734656548790656486646106983450809073750535624894296242072010195710276073042036425579852459556183541199012652571123898996574563824424330960027873516082763671875e-1075", + "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247032822920623272088284396434110686182529901307162382212792841250337753635104375932649918180817996189898282347722858865463328355177969898199387398005390939063150356595155702263922908583924491051844359318028499365361525003193704576782492193656236698636584807570015857692699037063119282795585513329278343384093519780155312465972635795746227664652728272200563740064854999770965994704540208281662262378573934507363390079677619305775067401763246736009689513405355374585166611342237666786041621596804619144672918403005300575308490487653917113865916462395249126236538818796362393732804238910186723484976682350898633885879256283027559956575244555072551893136908362547791869486679949683240497058210285131854513962138377228261454376934125320985913276672363281249", + "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247032822920623272088284396434110686182529901307162382212792841250337753635104375932649918180817996189898282347722858865463328355177969898199387398005390939063150356595155702263922908583924491051844359318028499365361525003193704576782492193656236698636584807570015857692699037063119282795585513329278343384093519780155312465972635795746227664652728272200563740064854999770965994704540208281662262378573934507363390079677619305775067401763246736009689513405355374585166611342237666786041621596804619144672918403005300575308490487653917113865916462395249126236538818796362393732804238910186723484976682350898633885879256283027559956575244555072551893136908362547791869486679949683240497058210285131854513962138377228261454376934125320985913276672363281251", +]; + +/// Check items that failed in the past. +pub struct RegressionCheck { + iter: std::slice::Iter<'static, &'static str>, +} + +impl Generator for RegressionCheck { + const NAME: &'static str = "regression check"; + + const SHORT_NAME: &'static str = "regression"; + + type WriteCtx = &'static str; + + fn total_tests() -> u64 { + REGRESSIONS.len().try_into().unwrap() + } + + fn new() -> Self { + Self { iter: REGRESSIONS.iter() } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + s.write_str(ctx).unwrap(); + } +} + +impl Iterator for RegressionCheck { + type Item = &'static str; + + fn next(&mut self) -> Option { + self.iter.next().copied() + } +} diff --git a/src/tools/test-float-parse/src/gen_/subnorm.rs b/src/tools/test-float-parse/src/gen_/subnorm.rs new file mode 100644 index 00000000000..654f324b9b0 --- /dev/null +++ b/src/tools/test-float-parse/src/gen_/subnorm.rs @@ -0,0 +1,108 @@ +use std::fmt::Write; +use std::ops::RangeInclusive; + +use crate::{Float, Generator, Int}; + +/// Spot check some edge cases for subnormals. +pub struct SubnormEdgeCases { + cases: [F::Int; 6], + index: usize, +} + +impl SubnormEdgeCases { + /// Shorthand + const I1: F::Int = F::Int::ONE; + + fn edge_cases() -> [F::Int; 6] { + // Comments use an 8-bit mantissa as a demo + [ + // 0b00000001 + Self::I1, + // 0b10000000 + Self::I1 << (F::MAN_BITS - 1), + // 0b00001000 + Self::I1 << ((F::MAN_BITS / 2) - 1), + // 0b00001111 + Self::I1 << ((F::MAN_BITS / 2) - 1), + // 0b00001111 + Self::I1 << ((F::MAN_BITS / 2) - 1), + // 0b11111111 + F::MAN_MASK, + ] + } +} + +impl Generator for SubnormEdgeCases { + const NAME: &'static str = "subnormal edge cases"; + const SHORT_NAME: &'static str = "subnorm edge"; + + type WriteCtx = F; + + fn new() -> Self { + Self { cases: Self::edge_cases(), index: 0 } + } + + fn total_tests() -> u64 { + Self::edge_cases().len().try_into().unwrap() + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx:e}").unwrap(); + } +} + +impl Iterator for SubnormEdgeCases { + type Item = F; + + fn next(&mut self) -> Option { + let i = self.cases.get(self.index)?; + self.index += 1; + + Some(F::from_bits(*i)) + } +} + +/// Test all subnormals up to `1 << 22`. +pub struct SubnormComplete { + iter: RangeInclusive, +} + +impl Generator for SubnormComplete +where + RangeInclusive: Iterator, +{ + const NAME: &'static str = "subnormal"; + const SHORT_NAME: &'static str = "subnorm "; + + type WriteCtx = F; + + fn total_tests() -> u64 { + let iter = Self::new().iter; + (F::Int::ONE + *iter.end() - *iter.start()).try_into().unwrap() + } + + fn new() -> Self { + let upper_lim = if F::MAN_BITS >= 22 { + F::Int::ONE << 22 + } else { + (F::Int::ONE << F::MAN_BITS) - F::Int::ONE + }; + + Self { iter: F::Int::ZERO..=upper_lim } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx:e}").unwrap(); + } +} + +impl Iterator for SubnormComplete +where + RangeInclusive: Iterator, +{ + type Item = F; + + fn next(&mut self) -> Option { + Some(F::from_bits(self.iter.next()?)) + } +} diff --git a/src/tools/test-float-parse/src/lib.rs b/src/tools/test-float-parse/src/lib.rs new file mode 100644 index 00000000000..f590149523b --- /dev/null +++ b/src/tools/test-float-parse/src/lib.rs @@ -0,0 +1,419 @@ +#![feature(f16)] +#![feature(cfg_target_has_reliable_f16_f128)] +#![expect(internal_features)] // reliable_f16_f128 + +mod traits; +mod ui; +mod validate; + +use std::any::type_name; +use std::cmp::min; +use std::ops::RangeInclusive; +use std::process::ExitCode; +use std::sync::OnceLock; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::{fmt, time}; + +use rand::distr::{Distribution, StandardUniform}; +use rayon::prelude::*; +use time::{Duration, Instant}; +use traits::{Float, Generator, Int}; +use validate::CheckError; + +/// Test generators. +mod gen_ { + pub mod exhaustive; + pub mod exponents; + pub mod fuzz; + pub mod integers; + pub mod long_fractions; + pub mod many_digits; + pub mod sparse; + pub mod spot_checks; + pub mod subnorm; +} + +/// How many failures to exit after if unspecified. +const DEFAULT_MAX_FAILURES: u64 = 20; + +/// Register exhaustive tests only for <= 32 bits. No more because it would take years. +const MAX_BITS_FOR_EXHAUUSTIVE: u32 = 32; + +/// If there are more tests than this threshold, the test will be deferred until after all +/// others run (so as to avoid thread pool starvation). They also can be excluded with +/// `--skip-huge`. +const HUGE_TEST_CUTOFF: u64 = 5_000_000; + +/// Seed for tests that use a deterministic RNG. +const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; + +/// Global configuration. +#[derive(Debug)] +pub struct Config { + pub timeout: Duration, + /// Failures per test + pub max_failures: u64, + pub disable_max_failures: bool, + /// If `None`, the default will be used + pub fuzz_count: Option, + pub skip_huge: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { + timeout: Duration::from_secs(60 * 60 * 3), + max_failures: DEFAULT_MAX_FAILURES, + disable_max_failures: false, + fuzz_count: None, + skip_huge: false, + } + } +} + +/// Collect, filter, and launch all tests. +pub fn run(cfg: Config, include: &[String], exclude: &[String]) -> ExitCode { + // With default parallelism, the CPU doesn't saturate. We don't need to be nice to + // other processes, so do 1.5x to make sure we use all available resources. + let threads = std::thread::available_parallelism().map(Into::into).unwrap_or(0) * 3 / 2; + rayon::ThreadPoolBuilder::new().num_threads(threads).build_global().unwrap(); + + let mut tests = register_tests(&cfg); + println!("registered"); + let initial_tests: Vec<_> = tests.iter().map(|t| t.name.clone()).collect(); + + let unmatched: Vec<_> = include + .iter() + .chain(exclude.iter()) + .filter(|filt| !tests.iter().any(|t| t.matches(filt))) + .collect(); + + assert!( + unmatched.is_empty(), + "filters were provided that have no matching tests: {unmatched:#?}" + ); + + tests.retain(|test| !exclude.iter().any(|exc| test.matches(exc))); + + if cfg.skip_huge { + tests.retain(|test| !test.is_huge_test()); + } + + if !include.is_empty() { + tests.retain(|test| include.iter().any(|inc| test.matches(inc))); + } + + for exc in initial_tests.iter().filter(|orig_name| !tests.iter().any(|t| t.name == **orig_name)) + { + println!("Skipping test '{exc}'"); + } + + println!("Launching all"); + let elapsed = launch_tests(&mut tests, &cfg); + ui::finish_all(&tests, elapsed, &cfg) +} + +/// Enumerate tests to run but don't actually run them. +pub fn register_tests(cfg: &Config) -> Vec { + let mut tests = Vec::new(); + + // Register normal generators for all floats. + + #[cfg(not(bootstrap))] + #[cfg(target_has_reliable_f16)] + register_float::(&mut tests, cfg); + register_float::(&mut tests, cfg); + register_float::(&mut tests, cfg); + + tests.sort_unstable_by_key(|t| (t.float_name, t.gen_name)); + for i in 0..(tests.len() - 1) { + if tests[i].gen_name == tests[i + 1].gen_name { + panic!("duplicate test name {}", tests[i].gen_name); + } + } + + tests +} + +/// Register all generators for a single float. +fn register_float(tests: &mut Vec, cfg: &Config) +where + RangeInclusive: Iterator, + >::Error: std::fmt::Debug, + StandardUniform: Distribution<::Int>, +{ + if F::BITS <= MAX_BITS_FOR_EXHAUUSTIVE { + // Only run exhaustive tests if there is a chance of completion. + TestInfo::register::>(tests); + } + + gen_::fuzz::Fuzz::::set_iterations(cfg.fuzz_count); + + TestInfo::register::>(tests); + TestInfo::register::>(tests); + TestInfo::register::>(tests); + TestInfo::register::>(tests); + TestInfo::register::(tests); + TestInfo::register::(tests); + TestInfo::register::>(tests); + TestInfo::register::>(tests); + TestInfo::register::>(tests); + TestInfo::register::(tests); + TestInfo::register::(tests); + TestInfo::register::>(tests); + TestInfo::register::>(tests); +} + +/// Configuration for a single test. +#[derive(Debug)] +pub struct TestInfo { + pub name: String, + float_name: &'static str, + float_bits: u32, + gen_name: &'static str, + /// Name for display in the progress bar. + short_name: String, + /// Pad the short name to a common width for progress bar use. + short_name_padded: String, + total_tests: u64, + /// Function to launch this test. + launch: fn(&TestInfo, &Config), + /// Progress bar to be updated. + progress: Option, + /// Once completed, this will be set. + completed: OnceLock, +} + +impl TestInfo { + /// Check if either the name or short name is a match, for filtering. + fn matches(&self, pat: &str) -> bool { + self.short_name.contains(pat) || self.name.contains(pat) + } + + /// Create a `TestInfo` for a given float and generator, then add it to a list. + fn register>(v: &mut Vec) { + let f_name = type_name::(); + let gen_name = G::NAME; + let gen_short_name = G::SHORT_NAME; + let name = format!("{f_name} {gen_name}"); + let short_name = format!("{f_name} {gen_short_name}"); + let short_name_padded = format!("{short_name:18}"); + + let info = TestInfo { + float_name: f_name, + float_bits: F::BITS, + gen_name, + progress: None, + name, + short_name_padded, + short_name, + launch: test_runner::, + total_tests: G::total_tests(), + completed: OnceLock::new(), + }; + v.push(info); + } + + /// True if this should be run after all others. + fn is_huge_test(&self) -> bool { + self.total_tests >= HUGE_TEST_CUTOFF + } + + /// When the test is finished, update progress bar messages and finalize. + fn complete(&self, c: Completed) { + self.progress.as_ref().unwrap().complete(&c, 0); + self.completed.set(c).unwrap(); + } +} + +/// Result of an input did not parsing successfully. +#[derive(Clone, Debug)] +enum CheckFailure { + /// Above the zero cutoff but got rounded to zero. + UnexpectedZero, + /// Below the infinity cutoff but got rounded to infinity. + UnexpectedInf, + /// Above the negative infinity cutoff but got rounded to negative infinity. + UnexpectedNegInf, + /// Got a `NaN` when none was expected. + UnexpectedNan, + /// Expected `NaN`, got none. + ExpectedNan, + /// Expected infinity, got finite. + ExpectedInf, + /// Expected negative infinity, got finite. + ExpectedNegInf, + /// The value exceeded its error tolerance. + InvalidReal { + /// Error from the expected value, as a float. + error_float: Option, + /// Error as a rational string (since it can't always be represented as a float). + error_str: Box, + /// True if the error was caused by not rounding to even at the midpoint between + /// two representable values. + incorrect_midpoint_rounding: bool, + }, + /// String did not parse successfully. + ParsingFailed(Box), + /// A panic was caught. + Panic(Box), +} + +impl fmt::Display for CheckFailure { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CheckFailure::UnexpectedZero => { + write!(f, "incorrectly rounded to 0 (expected nonzero)") + } + CheckFailure::UnexpectedInf => { + write!(f, "incorrectly rounded to +inf (expected finite)") + } + CheckFailure::UnexpectedNegInf => { + write!(f, "incorrectly rounded to -inf (expected finite)") + } + CheckFailure::UnexpectedNan => write!(f, "got a NaN where none was expected"), + CheckFailure::ExpectedNan => write!(f, "expected a NaN but did not get it"), + CheckFailure::ExpectedInf => write!(f, "expected +inf but did not get it"), + CheckFailure::ExpectedNegInf => write!(f, "expected -inf but did not get it"), + CheckFailure::InvalidReal { error_float, error_str, incorrect_midpoint_rounding } => { + if *incorrect_midpoint_rounding { + write!( + f, + "midpoint between two representable values did not correctly \ + round to even; error: {error_str}" + )?; + } else { + write!(f, "real number did not parse correctly; error: {error_str}")?; + } + + if let Some(float) = error_float { + write!(f, " ({float})")?; + } + Ok(()) + } + CheckFailure::ParsingFailed(e) => write!(f, "parsing failed: {e}"), + CheckFailure::Panic(e) => write!(f, "function panicked: {e}"), + } + } +} + +/// Information about a completed test generator. +#[derive(Clone, Debug)] +struct Completed { + /// Finished tests (both successful and failed). + executed: u64, + /// Failed tests. + failures: u64, + /// Extra exit information if unsuccessful. + result: Result, + /// If there is something to warn about (e.g bad estimate), leave it here. + warning: Option>, + /// Total time to run the test. + elapsed: Duration, +} + +/// Marker for completing all tests (used in `Result` types). +#[derive(Clone, Debug)] +struct FinishedAll; + +/// Reasons for exiting early. +#[derive(Clone, Debug)] +enum EarlyExit { + Timeout, + MaxFailures, +} + +/// Run all tests in `tests`. +/// +/// This launches a main thread that receives messages and handlees UI updates, and uses the +/// rest of the thread pool to execute the tests. +fn launch_tests(tests: &mut [TestInfo], cfg: &Config) -> Duration { + // Run shorter tests and smaller float types first. + tests.sort_unstable_by_key(|test| (test.total_tests, test.float_bits)); + + for test in tests.iter() { + println!("Launching test '{}'", test.name); + } + + let mut all_progress_bars = Vec::new(); + let start = Instant::now(); + + for test in tests.iter_mut() { + test.progress = Some(ui::Progress::new(test, &mut all_progress_bars)); + ui::set_panic_hook(&all_progress_bars); + ((test.launch)(test, cfg)); + } + + start.elapsed() +} + +/// Test runer for a single generator. +/// +/// This calls the generator's iterator multiple times (in parallel) and validates each output. +fn test_runner>(test: &TestInfo, cfg: &Config) { + let gen_ = G::new(); + let executed = AtomicU64::new(0); + let failures = AtomicU64::new(0); + + let checks_per_update = min(test.total_tests, 1000); + let started = Instant::now(); + + // Function to execute for a single test iteration. + let check_one = |buf: &mut String, ctx: G::WriteCtx| { + let executed = executed.fetch_add(1, Ordering::Relaxed); + buf.clear(); + G::write_string(buf, ctx); + + match validate::validate::(buf) { + Ok(()) => (), + Err(e) => { + let CheckError { fail, input, float_res } = e; + test.progress.as_ref().unwrap().println(&format!( + "Failure in '{}': {fail}. parsing '{input}'. Parsed as: {float_res}", + test.name + )); + + let f = failures.fetch_add(1, Ordering::Relaxed); + // End early if the limit is exceeded. + if f >= cfg.max_failures { + return Err(EarlyExit::MaxFailures); + } + } + }; + + // Send periodic updates + if executed % checks_per_update == 0 { + let failures = failures.load(Ordering::Relaxed); + test.progress.as_ref().unwrap().update(executed, failures); + if started.elapsed() > cfg.timeout { + return Err(EarlyExit::Timeout); + } + } + + Ok(()) + }; + + // Run the test iterations in parallel. Each thread gets a string buffer to write + // its check values to. + let res = gen_.par_bridge().try_for_each_init(String::new, check_one); + + let elapsed = started.elapsed(); + let executed = executed.into_inner(); + let failures = failures.into_inner(); + + // Warn about bad estimates if relevant. + let warning = if executed != test.total_tests && res.is_ok() { + let msg = format!( + "executed tests != estimated ({executed} != {}) for {}", + test.total_tests, + G::NAME + ); + + Some(msg.into()) + } else { + None + }; + + let result = res.map(|()| FinishedAll); + test.complete(Completed { executed, failures, result, warning, elapsed }); +} diff --git a/src/tools/test-float-parse/src/main.rs b/src/tools/test-float-parse/src/main.rs new file mode 100644 index 00000000000..9c6cad7324f --- /dev/null +++ b/src/tools/test-float-parse/src/main.rs @@ -0,0 +1,129 @@ +use std::process::ExitCode; +use std::time::Duration; + +use test_float_parse as tfp; + +static HELP: &str = r#"Usage: + + ./test-float-parse [--timeout x] [--exclude x] [--max-failures x] [INCLUDE ...] + ./test-float-parse [--fuzz-count x] [INCLUDE ...] + ./test-float-parse [--skip-huge] [INCLUDE ...] + ./test-float-parse --list + +Args: + + INCLUDE Include only tests with names containing these + strings. If this argument is not specified, all tests + are run. + --timeout N Exit after this amount of time (in seconds). + --exclude FILTER Skip tests containing this string. May be specified + more than once. + --list List available tests. + --max-failures N Limit to N failures per test. Defaults to 20. Pass + "--max-failures none" to remove this limit. + --fuzz-count N Run the fuzzer with N iterations. Only has an effect + if fuzz tests are enabled. Pass `--fuzz-count none` + to remove this limit. + --skip-huge Skip tests that run for a long time. + --all Reset previous `--exclude`, `--skip-huge`, and + `INCLUDE` arguments (useful for running all tests + via `./x`). +"#; + +enum ArgMode { + Any, + Timeout, + Exclude, + FuzzCount, + MaxFailures, +} + +fn main() -> ExitCode { + if cfg!(debug_assertions) { + println!( + "WARNING: running in debug mode. Release mode is recommended to reduce test duration." + ); + std::thread::sleep(Duration::from_secs(2)); + } + + let args: Vec<_> = std::env::args().skip(1).collect(); + if args.iter().any(|arg| arg == "--help" || arg == "-h") { + println!("{HELP}"); + return ExitCode::SUCCESS; + } + + if args.iter().any(|arg| arg == "--list") { + let tests = tfp::register_tests(&tfp::Config::default()); + println!("Available tests:"); + for t in tests { + println!("{}", t.name); + } + + return ExitCode::SUCCESS; + } + + let (cfg, include, exclude) = parse_args(args); + + tfp::run(cfg, &include, &exclude) +} + +/// Simple command argument parser +fn parse_args(args: Vec) -> (tfp::Config, Vec, Vec) { + let mut cfg = tfp::Config::default(); + + let mut mode = ArgMode::Any; + let mut include = Vec::new(); + let mut exclude = Vec::new(); + + for arg in args { + mode = match mode { + ArgMode::Any if arg == "--timeout" => ArgMode::Timeout, + ArgMode::Any if arg == "--exclude" => ArgMode::Exclude, + ArgMode::Any if arg == "--max-failures" => ArgMode::MaxFailures, + ArgMode::Any if arg == "--fuzz-count" => ArgMode::FuzzCount, + ArgMode::Any if arg == "--skip-huge" => { + cfg.skip_huge = true; + ArgMode::Any + } + ArgMode::Any if arg == "--all" => { + cfg.skip_huge = false; + include.clear(); + exclude.clear(); + ArgMode::Any + } + ArgMode::Any if arg.starts_with('-') => { + panic!("Unknown argument {arg}. Usage:\n{HELP}") + } + ArgMode::Any => { + include.push(arg); + ArgMode::Any + } + ArgMode::Timeout => { + cfg.timeout = Duration::from_secs(arg.parse().unwrap()); + ArgMode::Any + } + ArgMode::MaxFailures => { + if arg == "none" { + cfg.disable_max_failures = true; + } else { + cfg.max_failures = arg.parse().unwrap(); + } + ArgMode::Any + } + ArgMode::FuzzCount => { + if arg == "none" { + cfg.fuzz_count = Some(u64::MAX); + } else { + cfg.fuzz_count = Some(arg.parse().unwrap()); + } + ArgMode::Any + } + ArgMode::Exclude => { + exclude.push(arg); + ArgMode::Any + } + } + } + + (cfg, include, exclude) +} diff --git a/src/tools/test-float-parse/src/traits.rs b/src/tools/test-float-parse/src/traits.rs new file mode 100644 index 00000000000..16484f8fe2c --- /dev/null +++ b/src/tools/test-float-parse/src/traits.rs @@ -0,0 +1,206 @@ +//! Interfaces used throughout this crate. + +use std::str::FromStr; +use std::{fmt, ops}; + +use num::Integer; +use num::bigint::ToBigInt; + +use crate::validate::Constants; + +/// Integer types. +#[allow(dead_code)] // Some functions only used for testing +pub trait Int: + Clone + + Copy + + fmt::Debug + + fmt::Display + + fmt::LowerHex + + ops::Add + + ops::Sub + + ops::Shl + + ops::Shr + + ops::BitAnd + + ops::BitOr + + ops::Not + + ops::AddAssign + + ops::BitAndAssign + + ops::BitOrAssign + + From + + TryFrom + + TryFrom + + TryFrom + + TryFrom + + TryInto + + TryInto + + ToBigInt + + PartialOrd + + Integer + + Send + + 'static +{ + type Signed: Int; + type Bytes: Default + AsMut<[u8]>; + + const BITS: u32; + const ZERO: Self; + const ONE: Self; + const MAX: Self; + + fn to_signed(self) -> Self::Signed; + fn wrapping_neg(self) -> Self; + fn trailing_zeros(self) -> u32; + + fn hex(self) -> String { + format!("{self:x}") + } +} + +macro_rules! impl_int { + ($($uty:ty, $sty:ty);+) => { + $( + impl Int for $uty { + type Signed = $sty; + type Bytes = [u8; Self::BITS as usize / 8]; + const BITS: u32 = Self::BITS; + const ZERO: Self = 0; + const ONE: Self = 1; + const MAX: Self = Self::MAX; + fn to_signed(self) -> Self::Signed { + self.try_into().unwrap() + } + fn wrapping_neg(self) -> Self { + self.wrapping_neg() + } + fn trailing_zeros(self) -> u32 { + self.trailing_zeros() + } + } + + impl Int for $sty { + type Signed = Self; + type Bytes = [u8; Self::BITS as usize / 8]; + const BITS: u32 = Self::BITS; + const ZERO: Self = 0; + const ONE: Self = 1; + const MAX: Self = Self::MAX; + fn to_signed(self) -> Self::Signed { + self + } + fn wrapping_neg(self) -> Self { + self.wrapping_neg() + } + fn trailing_zeros(self) -> u32 { + self.trailing_zeros() + } + } + )+ + } +} + +impl_int!(u16, i16; u32, i32; u64, i64); + +/// Floating point types. +pub trait Float: + Copy + fmt::Debug + fmt::LowerExp + FromStr + Sized + Send + 'static +{ + /// Unsigned integer of same width + type Int: Int; + type SInt: Int; + + /// Total bits + const BITS: u32; + + /// (Stored) bits in the mantissa) + const MAN_BITS: u32; + + /// Bits in the exponent + const EXP_BITS: u32 = Self::BITS - Self::MAN_BITS - 1; + + /// A saturated exponent (all ones) + const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; + + /// The exponent bias, also its maximum value + const EXP_BIAS: u32 = Self::EXP_SAT >> 1; + + const MAN_MASK: Self::Int; + const SIGN_MASK: Self::Int; + + fn from_bits(i: Self::Int) -> Self; + fn to_bits(self) -> Self::Int; + + /// Rational constants associated with this float type. + fn constants() -> &'static Constants; + + fn is_sign_negative(self) -> bool { + (self.to_bits() & Self::SIGN_MASK) > Self::Int::ZERO + } + + /// Exponent without adjustment for bias. + fn exponent(self) -> u32 { + ((self.to_bits() >> Self::MAN_BITS) & Self::EXP_SAT.try_into().unwrap()).try_into().unwrap() + } + + fn mantissa(self) -> Self::Int { + self.to_bits() & Self::MAN_MASK + } +} + +macro_rules! impl_float { + ($($fty:ty, $ity:ty);+) => { + $( + impl Float for $fty { + type Int = $ity; + type SInt = ::Signed; + const BITS: u32 = <$ity>::BITS; + const MAN_BITS: u32 = Self::MANTISSA_DIGITS - 1; + const MAN_MASK: Self::Int = (Self::Int::ONE << Self::MAN_BITS) - Self::Int::ONE; + const SIGN_MASK: Self::Int = Self::Int::ONE << (Self::BITS-1); + fn from_bits(i: Self::Int) -> Self { Self::from_bits(i) } + fn to_bits(self) -> Self::Int { self.to_bits() } + fn constants() -> &'static Constants { + use std::sync::LazyLock; + static CONSTANTS: LazyLock = LazyLock::new(Constants::new::<$fty>); + &CONSTANTS + } + } + )+ + } +} + +impl_float!(f32, u32; f64, u64); + +#[cfg(not(bootstrap))] +#[cfg(target_has_reliable_f16)] +impl_float!(f16, u16); + +/// A test generator. Should provide an iterator that produces unique patterns to parse. +/// +/// The iterator needs to provide a `WriteCtx` (could be anything), which is then used to +/// write the string at a later step. This is done separately so that we can reuse string +/// allocations (which otherwise turn out to be a pretty expensive part of these tests). +pub trait Generator: Iterator + Send + 'static { + /// Full display and filtering name + const NAME: &'static str = Self::SHORT_NAME; + + /// Name for display with the progress bar + const SHORT_NAME: &'static str; + + /// The context needed to create a test string. + type WriteCtx: Send; + + /// Number of tests that will be run. + fn total_tests() -> u64; + + /// Constructor for this test generator. + fn new() -> Self; + + /// Create a test string given write context, which was produced as a step from the iterator. + /// + /// `s` will be provided empty. + fn write_string(s: &mut String, ctx: Self::WriteCtx); +} + +/// For tests that use iterator combinators, it is easier to just to box the iterator than trying +/// to specify its type. This is a shorthand for the usual type. +pub type BoxGenIter = Box>::WriteCtx> + Send>; diff --git a/src/tools/test-float-parse/src/ui.rs b/src/tools/test-float-parse/src/ui.rs new file mode 100644 index 00000000000..73473eef0bf --- /dev/null +++ b/src/tools/test-float-parse/src/ui.rs @@ -0,0 +1,168 @@ +//! Progress bars and such. + +use std::any::type_name; +use std::fmt; +use std::io::{self, Write}; +use std::process::ExitCode; +use std::time::Duration; + +use indicatif::{ProgressBar, ProgressStyle}; + +use crate::{Completed, Config, EarlyExit, FinishedAll, TestInfo}; + +/// Templates for progress bars. +const PB_TEMPLATE: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \ + {human_pos:>8}/{human_len:8} {msg} f {per_sec:14} eta {eta:8}"; +const PB_TEMPLATE_FINAL: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \ + {human_pos:>8}/{human_len:8} {msg:.COLOR} {per_sec:18} {elapsed_precise}"; + +/// Thin abstraction over our usage of a `ProgressBar`. +#[derive(Debug)] +pub struct Progress { + pb: ProgressBar, + make_final_style: NoDebug ProgressStyle + Sync>>, +} + +impl Progress { + /// Create a new progress bar within a multiprogress bar. + pub fn new(test: &TestInfo, all_bars: &mut Vec) -> Self { + let initial_template = PB_TEMPLATE.replace("NAME", &test.short_name_padded); + let final_template = PB_TEMPLATE_FINAL.replace("NAME", &test.short_name_padded); + let initial_style = + ProgressStyle::with_template(&initial_template).unwrap().progress_chars("##-"); + let make_final_style = move |color| { + ProgressStyle::with_template(&final_template.replace("COLOR", color)) + .unwrap() + .progress_chars("##-") + }; + + let pb = ProgressBar::new(test.total_tests); + pb.set_style(initial_style); + pb.set_length(test.total_tests); + pb.set_message("0"); + all_bars.push(pb.clone()); + + Progress { pb, make_final_style: NoDebug(Box::new(make_final_style)) } + } + + /// Completed a out of b tests. + pub fn update(&self, completed: u64, failures: u64) { + // Infrequently update the progress bar. + if completed % 5_000 == 0 || failures > 0 { + self.pb.set_position(completed); + } + + if failures > 0 { + self.pb.set_message(format! {"{failures}"}); + } + } + + /// Finalize the progress bar. + pub fn complete(&self, c: &Completed, real_total: u64) { + let f = c.failures; + let (color, msg, finish_fn): (&str, String, fn(&ProgressBar)) = match &c.result { + Ok(FinishedAll) if f > 0 => { + ("red", format!("{f} f (completed with errors)",), ProgressBar::finish) + } + Ok(FinishedAll) => { + ("green", format!("{f} f (completed successfully)",), ProgressBar::finish) + } + Err(EarlyExit::Timeout) => ("red", format!("{f} f (timed out)"), ProgressBar::abandon), + Err(EarlyExit::MaxFailures) => { + ("red", format!("{f} f (failure limit)"), ProgressBar::abandon) + } + }; + + self.pb.set_position(real_total); + self.pb.set_style(self.make_final_style.0(color)); + self.pb.set_message(msg); + finish_fn(&self.pb); + } + + /// Print a message to stdout above the current progress bar. + pub fn println(&self, msg: &str) { + self.pb.suspend(|| println!("{msg}")); + } +} + +/// Print final messages after all tests are complete. +pub fn finish_all(tests: &[TestInfo], total_elapsed: Duration, cfg: &Config) -> ExitCode { + println!("\n\nResults:"); + + let mut failed_generators = 0; + let mut stopped_generators = 0; + + for t in tests { + let Completed { executed, failures, elapsed, warning, result } = t.completed.get().unwrap(); + + let stat = if result.is_err() { + stopped_generators += 1; + "STOPPED" + } else if *failures > 0 { + failed_generators += 1; + "FAILURE" + } else { + "SUCCESS" + }; + + println!( + " {stat} for generator '{name}'. {passed}/{executed} passed in {elapsed:?}", + name = t.name, + passed = executed - failures, + ); + + if let Some(warning) = warning { + println!(" warning: {warning}"); + } + + match result { + Ok(FinishedAll) => (), + Err(EarlyExit::Timeout) => { + println!(" exited early; exceded {:?} timeout", cfg.timeout) + } + Err(EarlyExit::MaxFailures) => { + println!(" exited early; exceeded {:?} max failures", cfg.max_failures) + } + } + } + + println!( + "{passed}/{} tests succeeded in {total_elapsed:?} ({passed} passed, {} failed, {} stopped)", + tests.len(), + failed_generators, + stopped_generators, + passed = tests.len() - failed_generators - stopped_generators, + ); + + if failed_generators > 0 || stopped_generators > 0 { + ExitCode::FAILURE + } else { + ExitCode::SUCCESS + } +} + +/// indicatif likes to eat panic messages. This workaround isn't ideal, but it improves things. +/// . +pub fn set_panic_hook(drop_bars: &[ProgressBar]) { + let hook = std::panic::take_hook(); + let drop_bars = drop_bars.to_owned(); + std::panic::set_hook(Box::new(move |info| { + for bar in &drop_bars { + bar.abandon(); + println!(); + io::stdout().flush().unwrap(); + io::stderr().flush().unwrap(); + } + hook(info); + })); +} + +/// Allow non-Debug items in a `derive(Debug)` struct. +#[derive(Clone)] +struct NoDebug(T); + +impl fmt::Debug for NoDebug { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(type_name::()) + } +} diff --git a/src/tools/test-float-parse/src/validate.rs b/src/tools/test-float-parse/src/validate.rs new file mode 100644 index 00000000000..40dda274e3b --- /dev/null +++ b/src/tools/test-float-parse/src/validate.rs @@ -0,0 +1,394 @@ +//! Everything related to verifying that parsed outputs are correct. + +use std::any::{Any, type_name}; +use std::collections::BTreeMap; +use std::ops::RangeInclusive; +use std::str::FromStr; +use std::sync::LazyLock; + +use num::bigint::ToBigInt; +use num::{BigInt, BigRational, FromPrimitive, Signed, ToPrimitive}; + +use crate::{CheckFailure, Float, Int}; + +/// Powers of two that we store for constants. Account for binary128 which has a 15-bit exponent. +const POWERS_OF_TWO_RANGE: RangeInclusive = (-(2 << 15))..=(2 << 15); + +/// Powers of ten that we cache. Account for binary128, which can fit +4932/-4931 +const POWERS_OF_TEN_RANGE: RangeInclusive = -5_000..=5_000; + +/// Cached powers of 10 so we can look them up rather than recreating. +static POWERS_OF_TEN: LazyLock> = LazyLock::new(|| { + POWERS_OF_TEN_RANGE.map(|exp| (exp, BigRational::from_u32(10).unwrap().pow(exp))).collect() +}); + +/// Rational property-related constants for a specific float type. +#[allow(dead_code)] +#[derive(Debug)] +pub struct Constants { + /// The minimum positive value (a subnormal). + min_subnormal: BigRational, + /// The maximum possible finite value. + max: BigRational, + /// Cutoff between rounding to zero and rounding to the minimum value (min subnormal). + zero_cutoff: BigRational, + /// Cutoff between rounding to the max value and rounding to infinity. + inf_cutoff: BigRational, + /// Opposite of `inf_cutoff` + neg_inf_cutoff: BigRational, + /// The powers of two for all relevant integers. + powers_of_two: BTreeMap, + /// Half of each power of two. ULP = "unit in last position". + /// + /// This is a mapping from integers to half the precision available at that exponent. In other + /// words, `0.5 * 2^n` = `2^(n-1)`, which is half the distance between `m * 2^n` and + /// `(m + 1) * 2^n`, m ∈ ℤ. + /// + /// So, this is the maximum error from a real number to its floating point representation, + /// assuming the float type can represent the exponent. + half_ulp: BTreeMap, + /// Handy to have around so we don't need to reallocate for it + two: BigInt, +} + +impl Constants { + pub fn new() -> Self { + let two_int = &BigInt::from_u32(2).unwrap(); + let two = &BigRational::from_integer(2.into()); + + // The minimum subnormal (aka minimum positive) value. Most negative power of two is the + // minimum exponent (bias - 1) plus the extra from shifting within the mantissa bits. + let min_subnormal = two.pow(-(F::EXP_BIAS + F::MAN_BITS - 1).to_signed()); + + // The maximum value is the maximum exponent with a fully saturated mantissa. This + // is easiest to calculate by evaluating what the next value up would be if representable + // (zeroed mantissa, exponent increments by one, i.e. `2^(bias + 1)`), and subtracting + // a single LSB (`2 ^ (-mantissa_bits)`). + let max = (two - two.pow(-F::MAN_BITS.to_signed())) * (two.pow(F::EXP_BIAS.to_signed())); + let zero_cutoff = &min_subnormal / two_int; + + let inf_cutoff = &max + two_int.pow(F::EXP_BIAS - F::MAN_BITS - 1); + let neg_inf_cutoff = -&inf_cutoff; + + let powers_of_two: BTreeMap = + (POWERS_OF_TWO_RANGE).map(|n| (n, two.pow(n))).collect(); + let mut half_ulp = powers_of_two.clone(); + half_ulp.iter_mut().for_each(|(_k, v)| *v = &*v / two_int); + + Self { + min_subnormal, + max, + zero_cutoff, + inf_cutoff, + neg_inf_cutoff, + powers_of_two, + half_ulp, + two: two_int.clone(), + } + } +} + +/// Validate that a string parses correctly +pub fn validate(input: &str) -> Result<(), CheckError> { + // Catch panics in case debug assertions within `std` fail. + let parsed = std::panic::catch_unwind(|| { + input.parse::().map_err(|e| CheckError { + fail: CheckFailure::ParsingFailed(e.to_string().into()), + input: input.into(), + float_res: "none".into(), + }) + }) + .map_err(|e| convert_panic_error(&e, input))??; + + // Parsed float, decoded into significand and exponent + let decoded = decode(parsed); + + // Float parsed separately into a rational + let rational = Rational::parse(input); + + // Verify that the values match + decoded.check(rational, input) +} + +/// Turn panics into concrete error types. +fn convert_panic_error(e: &dyn Any, input: &str) -> CheckError { + let msg = e + .downcast_ref::() + .map(|s| s.as_str()) + .or_else(|| e.downcast_ref::<&str>().copied()) + .unwrap_or("(no contents)"); + + CheckError { + fail: CheckFailure::Panic(msg.into()), + input: input.into(), + float_res: "none".into(), + } +} + +/// The result of parsing a string to a float type. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FloatRes { + Inf, + NegInf, + Zero, + Nan, + /// A real number with significand and exponent. Value is `sig * 2 ^ exp`. + Real { + sig: F::SInt, + exp: i32, + }, +} + +#[derive(Clone, Debug)] +pub struct CheckError { + pub fail: CheckFailure, + /// String for which parsing was attempted. + pub input: Box, + /// The parsed & decomposed `FloatRes`, already stringified so we don't need generics here. + pub float_res: Box, +} + +impl FloatRes { + /// Given a known exact rational, check that this representation is accurate within the + /// limits of the float representation. If not, construct a failure `Update` to send. + fn check(self, expected: Rational, input: &str) -> Result<(), CheckError> { + let consts = F::constants(); + // let bool_helper = |cond: bool, err| cond.then_some(()).ok_or(err); + + let res = match (expected, self) { + // Easy correct cases + (Rational::Inf, FloatRes::Inf) + | (Rational::NegInf, FloatRes::NegInf) + | (Rational::Nan, FloatRes::Nan) => Ok(()), + + // Easy incorrect cases + ( + Rational::Inf, + FloatRes::NegInf | FloatRes::Zero | FloatRes::Nan | FloatRes::Real { .. }, + ) => Err(CheckFailure::ExpectedInf), + ( + Rational::NegInf, + FloatRes::Inf | FloatRes::Zero | FloatRes::Nan | FloatRes::Real { .. }, + ) => Err(CheckFailure::ExpectedNegInf), + ( + Rational::Nan, + FloatRes::Inf | FloatRes::NegInf | FloatRes::Zero | FloatRes::Real { .. }, + ) => Err(CheckFailure::ExpectedNan), + (Rational::Finite(_), FloatRes::Nan) => Err(CheckFailure::UnexpectedNan), + + // Cases near limits + (Rational::Finite(r), FloatRes::Zero) => { + if r <= consts.zero_cutoff { + Ok(()) + } else { + Err(CheckFailure::UnexpectedZero) + } + } + (Rational::Finite(r), FloatRes::Inf) => { + if r >= consts.inf_cutoff { + Ok(()) + } else { + Err(CheckFailure::UnexpectedInf) + } + } + (Rational::Finite(r), FloatRes::NegInf) => { + if r <= consts.neg_inf_cutoff { + Ok(()) + } else { + Err(CheckFailure::UnexpectedNegInf) + } + } + + // Actual numbers + (Rational::Finite(r), FloatRes::Real { sig, exp }) => Self::validate_real(r, sig, exp), + }; + + res.map_err(|fail| CheckError { + fail, + input: input.into(), + float_res: format!("{self:?}").into(), + }) + } + + /// Check that `sig * 2^exp` is the same as `rational`, within the float's error margin. + fn validate_real(rational: BigRational, sig: F::SInt, exp: i32) -> Result<(), CheckFailure> { + let consts = F::constants(); + + // `2^exp`. Use cached powers of two to be faster. + let two_exp = consts + .powers_of_two + .get(&exp) + .unwrap_or_else(|| panic!("missing exponent {exp} for {}", type_name::())); + + // Rational from the parsed value, `sig * 2^exp` + let parsed_rational = two_exp * sig.to_bigint().unwrap(); + let error = (parsed_rational - &rational).abs(); + + // Determine acceptable error at this exponent, which is halfway between this value + // (`sig * 2^exp`) and the next value up (`(sig+1) * 2^exp`). + let half_ulp = consts.half_ulp.get(&exp).unwrap(); + + // If we are within one error value (but not equal) then we rounded correctly. + if &error < half_ulp { + return Ok(()); + } + + // For values where we are exactly between two representable values, meaning that the error + // is exactly one half of the precision at that exponent, we need to round to an even + // binary value (i.e. mantissa ends in 0). + let incorrect_midpoint_rounding = if &error == half_ulp { + if sig & F::SInt::ONE == F::SInt::ZERO { + return Ok(()); + } + + // We rounded to odd rather than even; failing based on midpoint rounding. + true + } else { + // We are out of spec for some other reason. + false + }; + + let one_ulp = consts.half_ulp.get(&(exp + 1)).unwrap(); + assert_eq!(one_ulp, &(half_ulp * &consts.two), "ULP values are incorrect"); + + let relative_error = error / one_ulp; + + Err(CheckFailure::InvalidReal { + error_float: relative_error.to_f64(), + error_str: relative_error.to_string().into(), + incorrect_midpoint_rounding, + }) + } + + /// Remove trailing zeros in the significand and adjust the exponent + #[cfg(test)] + fn normalize(self) -> Self { + use std::cmp::min; + + match self { + Self::Real { sig, exp } => { + // If there are trailing zeroes, remove them and increment the exponent instead + let shift = min(sig.trailing_zeros(), exp.wrapping_neg().try_into().unwrap()); + Self::Real { sig: sig >> shift, exp: exp + i32::try_from(shift).unwrap() } + } + _ => self, + } + } +} + +/// Decompose a float into its integral components. This includes the implicit bit. +/// +/// If `allow_nan` is `false`, panic if `NaN` values are reached. +fn decode(f: F) -> FloatRes { + let ione = F::SInt::ONE; + let izero = F::SInt::ZERO; + + let mut exponent_biased = f.exponent(); + let mut mantissa = f.mantissa().to_signed(); + + if exponent_biased == 0 { + if mantissa == izero { + return FloatRes::Zero; + } + + exponent_biased += 1; + } else if exponent_biased == F::EXP_SAT { + if mantissa != izero { + return FloatRes::Nan; + } + + if f.is_sign_negative() { + return FloatRes::NegInf; + } + + return FloatRes::Inf; + } else { + // Set implicit bit + mantissa |= ione << F::MAN_BITS; + } + + let mut exponent = i32::try_from(exponent_biased).unwrap(); + + // Adjust for bias and the rnage of the mantissa + exponent -= i32::try_from(F::EXP_BIAS + F::MAN_BITS).unwrap(); + + if f.is_sign_negative() { + mantissa = mantissa.wrapping_neg(); + } + + FloatRes::Real { sig: mantissa, exp: exponent } +} + +/// A rational or its unrepresentable values. +#[derive(Clone, Debug, PartialEq)] +enum Rational { + Inf, + NegInf, + Nan, + Finite(BigRational), +} + +impl Rational { + /// Turn a string into a rational. `None` if `NaN`. + fn parse(s: &str) -> Rational { + let mut s = s; // lifetime rules + + if s.strip_prefix('+').unwrap_or(s).eq_ignore_ascii_case("nan") + || s.eq_ignore_ascii_case("-nan") + { + return Rational::Nan; + } + + if s.strip_prefix('+').unwrap_or(s).eq_ignore_ascii_case("inf") { + return Rational::Inf; + } + + if s.eq_ignore_ascii_case("-inf") { + return Rational::NegInf; + } + + // Fast path; no decimals or exponents ot parse + if s.bytes().all(|b| b.is_ascii_digit() || b == b'-') { + return Rational::Finite(BigRational::from_str(s).unwrap()); + } + + let mut ten_exp: i32 = 0; + + // Remove and handle e.g. `e-4`, `e+10`, `e5` suffixes + if let Some(pos) = s.bytes().position(|b| b == b'e' || b == b'E') { + let (dec, exp) = s.split_at(pos); + s = dec; + ten_exp = exp[1..].parse().unwrap(); + } + + // Remove the decimal and instead change our exponent + // E.g. "12.3456" becomes "123456 * 10^-4" + let mut s_owned; + if let Some(pos) = s.bytes().position(|b| b == b'.') { + ten_exp = ten_exp.checked_sub((s.len() - pos - 1).try_into().unwrap()).unwrap(); + s_owned = s.to_owned(); + s_owned.remove(pos); + s = &s_owned; + } + + // let pow = BigRational::from_u32(10).unwrap().pow(ten_exp); + let pow = + POWERS_OF_TEN.get(&ten_exp).unwrap_or_else(|| panic!("missing power of ten {ten_exp}")); + let r = pow + * BigInt::from_str(s) + .unwrap_or_else(|e| panic!("`BigInt::from_str(\"{s}\")` failed with {e}")); + Rational::Finite(r) + } + + #[cfg(test)] + fn expect_finite(self) -> BigRational { + let Self::Finite(r) = self else { + panic!("got non rational: {self:?}"); + }; + + r + } +} + +#[cfg(test)] +mod tests; diff --git a/src/tools/test-float-parse/src/validate/tests.rs b/src/tools/test-float-parse/src/validate/tests.rs new file mode 100644 index 00000000000..ab0e7d8a7ba --- /dev/null +++ b/src/tools/test-float-parse/src/validate/tests.rs @@ -0,0 +1,149 @@ +use num::ToPrimitive; + +use super::*; + +#[test] +fn test_parse_rational() { + assert_eq!(Rational::parse("1234").expect_finite(), BigRational::new(1234.into(), 1.into())); + assert_eq!( + Rational::parse("-1234").expect_finite(), + BigRational::new((-1234).into(), 1.into()) + ); + assert_eq!(Rational::parse("1e+6").expect_finite(), BigRational::new(1000000.into(), 1.into())); + assert_eq!(Rational::parse("1e-6").expect_finite(), BigRational::new(1.into(), 1000000.into())); + assert_eq!( + Rational::parse("10.4e6").expect_finite(), + BigRational::new(10400000.into(), 1.into()) + ); + assert_eq!( + Rational::parse("10.4e+6").expect_finite(), + BigRational::new(10400000.into(), 1.into()) + ); + assert_eq!( + Rational::parse("10.4e-6").expect_finite(), + BigRational::new(13.into(), 1250000.into()) + ); + assert_eq!( + Rational::parse("10.4243566462342456234124").expect_finite(), + BigRational::new(104243566462342456234124_i128.into(), 10000000000000000000000_i128.into()) + ); + assert_eq!(Rational::parse("inf"), Rational::Inf); + assert_eq!(Rational::parse("+inf"), Rational::Inf); + assert_eq!(Rational::parse("-inf"), Rational::NegInf); + assert_eq!(Rational::parse("NaN"), Rational::Nan); +} + +#[test] +fn test_decode() { + assert_eq!(decode(0f32), FloatRes::Zero); + assert_eq!(decode(f32::INFINITY), FloatRes::Inf); + assert_eq!(decode(f32::NEG_INFINITY), FloatRes::NegInf); + assert_eq!(decode(1.0f32).normalize(), FloatRes::Real { sig: 1, exp: 0 }); + assert_eq!(decode(-1.0f32).normalize(), FloatRes::Real { sig: -1, exp: 0 }); + assert_eq!(decode(100.0f32).normalize(), FloatRes::Real { sig: 100, exp: 0 }); + assert_eq!(decode(100.5f32).normalize(), FloatRes::Real { sig: 201, exp: -1 }); + assert_eq!(decode(-4.004f32).normalize(), FloatRes::Real { sig: -8396997, exp: -21 }); + assert_eq!(decode(0.0004f32).normalize(), FloatRes::Real { sig: 13743895, exp: -35 }); + assert_eq!(decode(f32::from_bits(0x1)).normalize(), FloatRes::Real { sig: 1, exp: -149 }); +} + +#[test] +fn test_validate() { + validate::("0").unwrap(); + validate::("-0").unwrap(); + validate::("1").unwrap(); + validate::("-1").unwrap(); + validate::("1.1").unwrap(); + validate::("-1.1").unwrap(); + validate::("1e10").unwrap(); + validate::("1e1000").unwrap(); + validate::("-1e1000").unwrap(); + validate::("1e-1000").unwrap(); + validate::("-1e-1000").unwrap(); +} + +#[test] +fn test_validate_real() { + // Most of the arbitrary values come from checking against . + let r = &BigRational::from_float(10.0).unwrap(); + FloatRes::::validate_real(r.clone(), 10, 0).unwrap(); + FloatRes::::validate_real(r.clone(), 10, -1).unwrap_err(); + FloatRes::::validate_real(r.clone(), 10, 1).unwrap_err(); + + let r = &BigRational::from_float(0.25).unwrap(); + FloatRes::::validate_real(r.clone(), 1, -2).unwrap(); + FloatRes::::validate_real(r.clone(), 2, -2).unwrap_err(); + + let r = &BigRational::from_float(1234.5678).unwrap(); + FloatRes::::validate_real(r.clone(), 0b100110100101001000101011, -13).unwrap(); + FloatRes::::validate_real(r.clone(), 0b100110100101001000101010, -13).unwrap_err(); + FloatRes::::validate_real(r.clone(), 0b100110100101001000101100, -13).unwrap_err(); + + let r = &BigRational::from_float(-1234.5678).unwrap(); + FloatRes::::validate_real(r.clone(), -0b100110100101001000101011, -13).unwrap(); + FloatRes::::validate_real(r.clone(), -0b100110100101001000101010, -13).unwrap_err(); + FloatRes::::validate_real(r.clone(), -0b100110100101001000101100, -13).unwrap_err(); +} + +#[test] +#[allow(unused)] +fn test_validate_real_rounding() { + // Check that we catch when values don't round to even. + + // For f32, the cutoff between 1.0 and the next value up (1.0000001) is + // 1.000000059604644775390625. Anything below it should round down, anything above it should + // round up, and the value itself should round _down_ because `1.0` has an even significand but + // 1.0000001 is odd. + let v1_low_down = Rational::parse("1.00000005960464477539062499999").expect_finite(); + let v1_mid_down = Rational::parse("1.000000059604644775390625").expect_finite(); + let v1_high_up = Rational::parse("1.00000005960464477539062500001").expect_finite(); + + let exp = -(f32::MAN_BITS as i32); + let v1_down_sig = 1 << f32::MAN_BITS; + let v1_up_sig = (1 << f32::MAN_BITS) | 0b1; + + FloatRes::::validate_real(v1_low_down.clone(), v1_down_sig, exp).unwrap(); + FloatRes::::validate_real(v1_mid_down.clone(), v1_down_sig, exp).unwrap(); + FloatRes::::validate_real(v1_high_up.clone(), v1_up_sig, exp).unwrap(); + FloatRes::::validate_real(-v1_low_down.clone(), -v1_down_sig, exp).unwrap(); + FloatRes::::validate_real(-v1_mid_down.clone(), -v1_down_sig, exp).unwrap(); + FloatRes::::validate_real(-v1_high_up.clone(), -v1_up_sig, exp).unwrap(); + + // 1.000000178813934326171875 is between 1.0000001 and the next value up, 1.0000002. The middle + // value here should round _up_ since 1.0000002 has an even mantissa. + let v2_low_down = Rational::parse("1.00000017881393432617187499999").expect_finite(); + let v2_mid_up = Rational::parse("1.000000178813934326171875").expect_finite(); + let v2_high_up = Rational::parse("1.00000017881393432617187500001").expect_finite(); + + let v2_down_sig = v1_up_sig; + let v2_up_sig = (1 << f32::MAN_BITS) | 0b10; + + FloatRes::::validate_real(v2_low_down.clone(), v2_down_sig, exp).unwrap(); + FloatRes::::validate_real(v2_mid_up.clone(), v2_up_sig, exp).unwrap(); + FloatRes::::validate_real(v2_high_up.clone(), v2_up_sig, exp).unwrap(); + FloatRes::::validate_real(-v2_low_down.clone(), -v2_down_sig, exp).unwrap(); + FloatRes::::validate_real(-v2_mid_up.clone(), -v2_up_sig, exp).unwrap(); + FloatRes::::validate_real(-v2_high_up.clone(), -v2_up_sig, exp).unwrap(); + + // Rounding the wrong direction should error + for res in [ + FloatRes::::validate_real(v1_mid_down.clone(), v1_up_sig, exp), + FloatRes::::validate_real(v2_mid_up.clone(), v2_down_sig, exp), + FloatRes::::validate_real(-v1_mid_down.clone(), -v1_up_sig, exp), + FloatRes::::validate_real(-v2_mid_up.clone(), -v2_down_sig, exp), + ] { + let e = res.unwrap_err(); + let CheckFailure::InvalidReal { incorrect_midpoint_rounding: true, .. } = e else { + panic!("{e:?}"); + }; + } +} + +/// Just a quick check that the constants are what we expect. +#[test] +fn check_constants() { + assert_eq!(f32::constants().max.to_f32().unwrap(), f32::MAX); + assert_eq!(f32::constants().min_subnormal.to_f32().unwrap(), f32::from_bits(0x1)); + assert_eq!(f64::constants().max.to_f64().unwrap(), f64::MAX); + assert_eq!(f64::constants().min_subnormal.to_f64().unwrap(), f64::from_bits(0x1)); +} diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 9f333cc43cf..fdca7a7a40e 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -74,13 +74,13 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>, ("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None, &[]), ("src/bootstrap", EXCEPTIONS_BOOTSTRAP, None, &[]), ("src/ci/docker/host-x86_64/test-various/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None, &[]), - ("src/etc/test-float-parse", EXCEPTIONS, None, &[]), ("src/tools/cargo", EXCEPTIONS_CARGO, None, &["src/tools/cargo"]), //("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored //("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored ("src/tools/rust-analyzer", EXCEPTIONS_RUST_ANALYZER, None, &[]), ("src/tools/rustbook", EXCEPTIONS_RUSTBOOK, None, &["src/doc/book", "src/doc/reference"]), ("src/tools/rustc-perf", EXCEPTIONS_RUSTC_PERF, None, &["src/tools/rustc-perf"]), + ("src/tools/test-float-parse", EXCEPTIONS, None, &[]), // tidy-alphabetical-end ]; -- cgit 1.4.1-3-g733a5 From 8a0fdbd4071eee08034d9ae8c83d13666a6a872e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 3 Jun 2025 07:54:47 +0000 Subject: Move coroutine_by_move_body_def_id into the big check_crate body owner loop --- compiler/rustc_hir_analysis/src/lib.rs | 9 +++++++-- compiler/rustc_interface/src/passes.rs | 7 ------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index a64c24f5455..39a3f427c0b 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -194,10 +194,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(()); }); - // Make sure we evaluate all static and (non-associated) const items, even if unused. - // If any of these fail to evaluate, we do not want this crate to pass compilation. tcx.par_hir_body_owners(|item_def_id| { let def_kind = tcx.def_kind(item_def_id); + // Make sure we evaluate all static and (non-associated) const items, even if unused. + // If any of these fail to evaluate, we do not want this crate to pass compilation. match def_kind { DefKind::Static { .. } => { tcx.ensure_ok().eval_static_initializer(item_def_id); @@ -217,6 +217,11 @@ pub fn check_crate(tcx: TyCtxt<'_>) { if !matches!(def_kind, DefKind::AnonConst) { tcx.ensure_ok().typeck(item_def_id); } + // Ensure we generate the new `DefId` before finishing `check_crate`. + // Afterwards we freeze the list of `DefId`s. + if tcx.needs_coroutine_by_move_body_def_id(item_def_id.to_def_id()) { + tcx.ensure_done().coroutine_by_move_body_def_id(item_def_id); + } }); if tcx.features().rustc_attrs() { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 5bc7559d29a..b1db5d25760 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -981,13 +981,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { }); rustc_hir_analysis::check_crate(tcx); - sess.time("MIR_coroutine_by_move_body", || { - tcx.par_hir_body_owners(|def_id| { - if tcx.needs_coroutine_by_move_body_def_id(def_id.to_def_id()) { - tcx.ensure_done().coroutine_by_move_body_def_id(def_id); - } - }); - }); // Freeze definitions as we don't add new ones at this point. // We need to wait until now since we synthesize a by-move body // for all coroutine-closures. -- cgit 1.4.1-3-g733a5 From 23d523160748045ca24a5d1acd7372dd444eaa6e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 2 Jun 2025 10:11:10 +0200 Subject: Use non-2015 edition paths in tests that do not test for their resolution This allows for testing these tests on editions other than 2015 --- tests/ui/autoref-autoderef/autoderef-privacy.rs | 16 +++++++-------- .../auxiliary/crate-method-reexport-grrrrrrr2.rs | 2 +- tests/ui/auxiliary/pub-and-stability.rs | 8 ++++---- tests/ui/coherence/coherence_inherent.rs | 6 +++--- tests/ui/consts/const-blocks/migrate-fail.rs | 2 +- tests/ui/consts/const-blocks/migrate-pass.rs | 4 ++-- tests/ui/consts/const-blocks/nll-fail.rs | 2 +- tests/ui/consts/const-blocks/nll-pass.rs | 4 ++-- .../auxiliary/static_priv_by_default.rs | 10 ++++----- tests/ui/dep-graph/dep-graph-assoc-type-codegen.rs | 4 ++-- tests/ui/dep-graph/dep-graph-caller-callee.rs | 4 ++-- tests/ui/dep-graph/dep-graph-struct-signature.rs | 4 ++-- .../dep-graph-trait-impl-two-traits-same-method.rs | 6 +++--- .../dep-graph/dep-graph-trait-impl-two-traits.rs | 6 +++--- tests/ui/dep-graph/dep-graph-trait-impl.rs | 6 +++--- tests/ui/derived-errors/issue-31997.rs | 2 +- tests/ui/derived-errors/issue-31997.stderr | 6 +++--- .../ui/drop/issue-23338-ensure-param-drop-order.rs | 2 +- tests/ui/drop/issue-23611-enum-swap-in-drop.rs | 2 +- tests/ui/dropck/dropck_trait_cycle_checked.rs | 2 +- tests/ui/error-codes/E0659.rs | 4 ++-- tests/ui/error-codes/E0659.stderr | 8 ++++---- tests/ui/explore-issue-38412.stderr | 8 ++++---- tests/ui/imports/duplicate.rs | 18 ++++++++-------- tests/ui/imports/duplicate.stderr | 24 +++++++++++----------- tests/ui/imports/export-glob-imports-target.rs | 2 +- tests/ui/imports/glob-cycles.rs | 6 +++--- tests/ui/imports/glob-shadowing.rs | 6 +++--- tests/ui/imports/glob-shadowing.stderr | 12 +++++------ tests/ui/imports/import-glob-1.rs | 2 +- tests/ui/imports/import-glob-circular.rs | 6 +++--- tests/ui/imports/import-loop-2.rs | 4 ++-- tests/ui/imports/import-loop-2.stderr | 6 +++--- tests/ui/imports/import-loop.rs | 2 +- tests/ui/imports/import-loop.stderr | 6 +++--- tests/ui/imports/import-rpass.rs | 4 ++-- tests/ui/imports/import4.rs | 4 ++-- tests/ui/imports/import4.stderr | 6 +++--- tests/ui/imports/import5.rs | 2 +- tests/ui/imports/import6.rs | 2 +- tests/ui/imports/imports.rs | 21 ++++++++++--------- tests/ui/imports/issue-18083.rs | 4 ++-- tests/ui/imports/issue-19498.rs | 2 +- tests/ui/imports/issue-19498.stderr | 8 ++++---- tests/ui/imports/issue-32222.rs | 2 +- tests/ui/imports/issue-4366-2.rs | 4 ++-- tests/ui/imports/issue-4366.rs | 4 ++-- tests/ui/imports/issue-4865-1.rs | 8 ++++---- tests/ui/imports/issue-4865-2.rs | 2 +- tests/ui/imports/issue-4865-3.rs | 4 ++-- tests/ui/imports/issue-8208.rs | 2 +- tests/ui/imports/issue-8208.stderr | 6 +++--- tests/ui/imports/issue-8640.rs | 2 +- tests/ui/imports/issue-8640.stderr | 8 ++++---- .../ui/imports/local-modularized-tricky-fail-2.rs | 4 ++-- .../imports/local-modularized-tricky-fail-2.stderr | 8 ++++---- tests/ui/imports/macros.rs | 4 ++-- tests/ui/imports/macros.stderr | 4 ++-- tests/ui/imports/reexport-star.rs | 2 +- tests/ui/imports/reexports.rs | 4 ++-- tests/ui/imports/reexports.stderr | 12 +++++------ tests/ui/imports/shadow_builtin_macros.rs | 10 ++++----- tests/ui/imports/shadow_builtin_macros.stderr | 12 +++++------ tests/ui/intrinsics/intrinsic-alignment.rs | 20 +++++++++--------- 64 files changed, 194 insertions(+), 193 deletions(-) diff --git a/tests/ui/autoref-autoderef/autoderef-privacy.rs b/tests/ui/autoref-autoderef/autoderef-privacy.rs index d2a217257e5..5fa28750f73 100644 --- a/tests/ui/autoref-autoderef/autoderef-privacy.rs +++ b/tests/ui/autoref-autoderef/autoderef-privacy.rs @@ -14,28 +14,28 @@ impl Bar2 { mod foo { #[derive(Default)] - pub struct Bar { i: ::Bar2 } + pub struct Bar { i: crate::Bar2 } #[derive(Default)] - pub struct Baz(::Baz2); + pub struct Baz(crate::Baz2); impl Bar { fn f(&self) -> bool { false } } impl ::std::ops::Deref for Bar { - type Target = ::Bar2; - fn deref(&self) -> &::Bar2 { &self.i } + type Target = crate::Bar2; + fn deref(&self) -> &crate::Bar2 { &self.i } } impl ::std::ops::Deref for Baz { - type Target = ::Baz2; - fn deref(&self) -> &::Baz2 { &self.0 } + type Target = crate::Baz2; + fn deref(&self) -> &crate::Baz2 { &self.0 } } pub fn f(bar: &Bar, baz: &Baz) { // Since the private fields and methods are visible here, there should be no autoderefs. - let _: &::Bar2 = &bar.i; - let _: &::Baz2 = &baz.0; + let _: &crate::Bar2 = &bar.i; + let _: &crate::Baz2 = &baz.0; assert!(!bar.f()); } } diff --git a/tests/ui/auxiliary/crate-method-reexport-grrrrrrr2.rs b/tests/ui/auxiliary/crate-method-reexport-grrrrrrr2.rs index d08504005a5..06413e13526 100644 --- a/tests/ui/auxiliary/crate-method-reexport-grrrrrrr2.rs +++ b/tests/ui/auxiliary/crate-method-reexport-grrrrrrr2.rs @@ -16,7 +16,7 @@ pub mod name_pool { } pub mod rust { - pub use name_pool::add; + pub use crate::name_pool::add; pub type rt = Box<()>; diff --git a/tests/ui/auxiliary/pub-and-stability.rs b/tests/ui/auxiliary/pub-and-stability.rs index d2d07f99398..8866233b61e 100644 --- a/tests/ui/auxiliary/pub-and-stability.rs +++ b/tests/ui/auxiliary/pub-and-stability.rs @@ -44,7 +44,7 @@ mod m { #[unstable(feature = "unstable_undeclared", issue = "38412")] // SILLY pub(crate) b_crate: i32, #[unstable(feature = "unstable_declared", issue = "38412")] // SILLY - pub(in m) c_mod: i32, + pub(in crate::m) c_mod: i32, #[stable(feature = "unit_test", since = "1.0.0")] // SILLY d_priv: i32 } @@ -60,7 +60,7 @@ mod m { pub i32, pub(crate) i32, - pub(in m) i32, + pub(in crate::m) i32, i32); impl Record { @@ -113,7 +113,7 @@ mod m { #[unstable(feature = "unstable_undeclared", issue = "38412")] // SILLY pub(crate) fn pub_crate(&self) -> i32 { self.d_priv } #[unstable(feature = "unstable_declared", issue = "38412")] // SILLY - pub(in m) fn pub_mod(&self) -> i32 { self.d_priv } + pub(in crate::m) fn pub_mod(&self) -> i32 { self.d_priv } #[stable(feature = "unit_test", since = "1.0.0")] // SILLY fn private(&self) -> i32 { self.d_priv } } @@ -127,7 +127,7 @@ mod m { pub fn stable(&self) -> i32 { self.0 } pub(crate) fn pub_crate(&self) -> i32 { self.0 } - pub(in m) fn pub_mod(&self) -> i32 { self.0 } + pub(in crate::m) fn pub_mod(&self) -> i32 { self.0 } fn private(&self) -> i32 { self.0 } } } diff --git a/tests/ui/coherence/coherence_inherent.rs b/tests/ui/coherence/coherence_inherent.rs index f3ebf000386..b2007e3437d 100644 --- a/tests/ui/coherence/coherence_inherent.rs +++ b/tests/ui/coherence/coherence_inherent.rs @@ -15,8 +15,8 @@ mod Lib { mod Import { // Trait is in scope here: - use Lib::TheStruct; - use Lib::TheTrait; + use crate::Lib::TheStruct; + use crate::Lib::TheTrait; fn call_the_fn(s: &TheStruct) { s.the_fn(); @@ -25,7 +25,7 @@ mod Import { mod NoImport { // Trait is not in scope here: - use Lib::TheStruct; + use crate::Lib::TheStruct; fn call_the_fn(s: &TheStruct) { s.the_fn(); diff --git a/tests/ui/consts/const-blocks/migrate-fail.rs b/tests/ui/consts/const-blocks/migrate-fail.rs index fddbfbb9d32..e7dbb68d920 100644 --- a/tests/ui/consts/const-blocks/migrate-fail.rs +++ b/tests/ui/consts/const-blocks/migrate-fail.rs @@ -4,7 +4,7 @@ struct Bar; mod non_constants { - use Bar; + use crate::Bar; fn no_impl_copy_empty_value_multiple_elements() { let x = None; diff --git a/tests/ui/consts/const-blocks/migrate-pass.rs b/tests/ui/consts/const-blocks/migrate-pass.rs index 308834bd646..629d4db0dc6 100644 --- a/tests/ui/consts/const-blocks/migrate-pass.rs +++ b/tests/ui/consts/const-blocks/migrate-pass.rs @@ -5,7 +5,7 @@ struct Bar; mod constants { - use Bar; + use crate::Bar; fn no_impl_copy_empty_value_no_elements() { const FOO: Option = None; @@ -69,7 +69,7 @@ mod constants { } mod non_constants { - use Bar; + use crate::Bar; fn no_impl_copy_empty_value_no_elements() { let x = None; diff --git a/tests/ui/consts/const-blocks/nll-fail.rs b/tests/ui/consts/const-blocks/nll-fail.rs index fddbfbb9d32..e7dbb68d920 100644 --- a/tests/ui/consts/const-blocks/nll-fail.rs +++ b/tests/ui/consts/const-blocks/nll-fail.rs @@ -4,7 +4,7 @@ struct Bar; mod non_constants { - use Bar; + use crate::Bar; fn no_impl_copy_empty_value_multiple_elements() { let x = None; diff --git a/tests/ui/consts/const-blocks/nll-pass.rs b/tests/ui/consts/const-blocks/nll-pass.rs index 308834bd646..629d4db0dc6 100644 --- a/tests/ui/consts/const-blocks/nll-pass.rs +++ b/tests/ui/consts/const-blocks/nll-pass.rs @@ -5,7 +5,7 @@ struct Bar; mod constants { - use Bar; + use crate::Bar; fn no_impl_copy_empty_value_no_elements() { const FOO: Option = None; @@ -69,7 +69,7 @@ mod constants { } mod non_constants { - use Bar; + use crate::Bar; fn no_impl_copy_empty_value_no_elements() { let x = None; diff --git a/tests/ui/cross-crate/auxiliary/static_priv_by_default.rs b/tests/ui/cross-crate/auxiliary/static_priv_by_default.rs index 39f912066ec..fe9aef42feb 100644 --- a/tests/ui/cross-crate/auxiliary/static_priv_by_default.rs +++ b/tests/ui/cross-crate/auxiliary/static_priv_by_default.rs @@ -31,11 +31,11 @@ mod foo { } pub mod bar { - pub use foo::reexported_a as e; - pub use foo::reexported_b as f; - pub use foo::reexported_c as g; - pub use foo::reexported_d as h; - pub use foo::reexported_e as i; + pub use crate::foo::reexported_a as e; + pub use crate::foo::reexported_b as f; + pub use crate::foo::reexported_c as g; + pub use crate::foo::reexported_d as h; + pub use crate::foo::reexported_e as i; } pub static a: isize = 0; diff --git a/tests/ui/dep-graph/dep-graph-assoc-type-codegen.rs b/tests/ui/dep-graph/dep-graph-assoc-type-codegen.rs index 9525ff2e5ef..9a7a10529fa 100644 --- a/tests/ui/dep-graph/dep-graph-assoc-type-codegen.rs +++ b/tests/ui/dep-graph/dep-graph-assoc-type-codegen.rs @@ -15,7 +15,7 @@ pub trait Foo: Sized { } mod x { - use Foo; + use crate::Foo; #[rustc_if_this_changed] impl Foo for char { type T = char; } @@ -24,7 +24,7 @@ mod x { } mod y { - use Foo; + use crate::Foo; #[rustc_then_this_would_need(typeck)] //~ ERROR OK pub fn use_char_assoc() { diff --git a/tests/ui/dep-graph/dep-graph-caller-callee.rs b/tests/ui/dep-graph/dep-graph-caller-callee.rs index e56cd5202e5..b1318a169d9 100644 --- a/tests/ui/dep-graph/dep-graph-caller-callee.rs +++ b/tests/ui/dep-graph/dep-graph-caller-callee.rs @@ -15,7 +15,7 @@ mod x { } mod y { - use x; + use crate::x; // These dependencies SHOULD exist: #[rustc_then_this_would_need(typeck)] //~ ERROR OK @@ -25,7 +25,7 @@ mod y { } mod z { - use y; + use crate::y; // These are expected to yield errors, because changes to `x` // affect the BODY of `y`, but not its signature. diff --git a/tests/ui/dep-graph/dep-graph-struct-signature.rs b/tests/ui/dep-graph/dep-graph-struct-signature.rs index 5303c6d2e53..eea81b26f9f 100644 --- a/tests/ui/dep-graph/dep-graph-struct-signature.rs +++ b/tests/ui/dep-graph/dep-graph-struct-signature.rs @@ -23,7 +23,7 @@ struct WontChange { // these are valid dependencies mod signatures { - use WillChange; + use crate::WillChange; #[rustc_then_this_would_need(type_of)] //~ ERROR no path #[rustc_then_this_would_need(associated_item)] //~ ERROR no path @@ -70,7 +70,7 @@ mod signatures { } mod invalid_signatures { - use WontChange; + use crate::WontChange; #[rustc_then_this_would_need(type_of)] //~ ERROR no path trait A { diff --git a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs index b3e8e9a512e..eab4c792105 100644 --- a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs +++ b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs @@ -19,7 +19,7 @@ pub trait Bar: Sized { } mod x { - use {Foo, Bar}; + use crate::{Foo, Bar}; #[rustc_if_this_changed] impl Foo for u32 { } @@ -28,7 +28,7 @@ mod x { } mod y { - use {Foo, Bar}; + use crate::{Foo, Bar}; #[rustc_then_this_would_need(typeck)] //~ ERROR OK pub fn with_char() { @@ -37,7 +37,7 @@ mod y { } mod z { - use y; + use crate::y; #[rustc_then_this_would_need(typeck)] //~ ERROR no path pub fn z() { diff --git a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.rs b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.rs index 7c612158bf0..859505a4a7a 100644 --- a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.rs +++ b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.rs @@ -18,7 +18,7 @@ pub trait Bar: Sized { } mod x { - use {Foo, Bar}; + use crate::{Foo, Bar}; #[rustc_if_this_changed] impl Foo for char { } @@ -27,7 +27,7 @@ mod x { } mod y { - use {Foo, Bar}; + use crate::{Foo, Bar}; #[rustc_then_this_would_need(typeck)] //~ ERROR no path pub fn call_bar() { @@ -36,7 +36,7 @@ mod y { } mod z { - use y; + use crate::y; #[rustc_then_this_would_need(typeck)] //~ ERROR no path pub fn z() { diff --git a/tests/ui/dep-graph/dep-graph-trait-impl.rs b/tests/ui/dep-graph/dep-graph-trait-impl.rs index 38cc88e567d..5cf0d34e007 100644 --- a/tests/ui/dep-graph/dep-graph-trait-impl.rs +++ b/tests/ui/dep-graph/dep-graph-trait-impl.rs @@ -14,7 +14,7 @@ pub trait Foo: Sized { } mod x { - use Foo; + use crate::Foo; #[rustc_if_this_changed] impl Foo for char { } @@ -23,7 +23,7 @@ mod x { } mod y { - use Foo; + use crate::Foo; #[rustc_then_this_would_need(typeck)] //~ ERROR OK pub fn with_char() { @@ -49,7 +49,7 @@ mod y { } mod z { - use y; + use crate::y; // These are expected to yield errors, because changes to `x` // affect the BODY of `y`, but not its signature. diff --git a/tests/ui/derived-errors/issue-31997.rs b/tests/ui/derived-errors/issue-31997.rs index ff619313afb..59f19e4fde2 100644 --- a/tests/ui/derived-errors/issue-31997.rs +++ b/tests/ui/derived-errors/issue-31997.rs @@ -11,7 +11,7 @@ fn closure(x: F) -> Result } fn foo() -> Result<(), ()> { - try!(closure(|| bar(core::ptr::null_mut()))); //~ ERROR cannot find function `bar` in this scope + closure(|| bar(core::ptr::null_mut()))?; //~ ERROR cannot find function `bar` in this scope Ok(()) } diff --git a/tests/ui/derived-errors/issue-31997.stderr b/tests/ui/derived-errors/issue-31997.stderr index 7d6415fef83..f5afb94fbd6 100644 --- a/tests/ui/derived-errors/issue-31997.stderr +++ b/tests/ui/derived-errors/issue-31997.stderr @@ -1,8 +1,8 @@ error[E0425]: cannot find function `bar` in this scope - --> $DIR/issue-31997.rs:14:21 + --> $DIR/issue-31997.rs:14:16 | -LL | try!(closure(|| bar(core::ptr::null_mut()))); - | ^^^ not found in this scope +LL | closure(|| bar(core::ptr::null_mut()))?; + | ^^^ not found in this scope error: aborting due to 1 previous error diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs index 6fee4520cbc..54a9d3324b9 100644 --- a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs +++ b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs @@ -163,7 +163,7 @@ pub mod d { }; self.log.borrow_mut().push(self.uid); indent_println(self.trail, &format!("+-- Drop {}", self)); - indent_println(::PREF_INDENT, ""); + indent_println(super::PREF_INDENT, ""); } } } diff --git a/tests/ui/drop/issue-23611-enum-swap-in-drop.rs b/tests/ui/drop/issue-23611-enum-swap-in-drop.rs index 410b07b16fc..208c6e2ada3 100644 --- a/tests/ui/drop/issue-23611-enum-swap-in-drop.rs +++ b/tests/ui/drop/issue-23611-enum-swap-in-drop.rs @@ -256,7 +256,7 @@ pub mod d { }; self.log.borrow_mut().push(self.uid); indent_println(self.trail, &format!("+-- Drop {}", self)); - indent_println(::PREF_INDENT, ""); + indent_println(super::PREF_INDENT, ""); } } } diff --git a/tests/ui/dropck/dropck_trait_cycle_checked.rs b/tests/ui/dropck/dropck_trait_cycle_checked.rs index be6ec3e4ed1..ffe43480b12 100644 --- a/tests/ui/dropck/dropck_trait_cycle_checked.rs +++ b/tests/ui/dropck/dropck_trait_cycle_checked.rs @@ -17,7 +17,7 @@ mod s { } mod id { - use s; + use crate::s; #[derive(Debug)] pub struct Id { orig_count: usize, diff --git a/tests/ui/error-codes/E0659.rs b/tests/ui/error-codes/E0659.rs index c00026bb7a7..d056f1d96dd 100644 --- a/tests/ui/error-codes/E0659.rs +++ b/tests/ui/error-codes/E0659.rs @@ -7,8 +7,8 @@ mod earth { } mod collider { - pub use moon::*; - pub use earth::*; + pub use crate::moon::*; + pub use crate::earth::*; } fn main() { diff --git a/tests/ui/error-codes/E0659.stderr b/tests/ui/error-codes/E0659.stderr index dbb72bb6759..371250b811b 100644 --- a/tests/ui/error-codes/E0659.stderr +++ b/tests/ui/error-codes/E0659.stderr @@ -8,14 +8,14 @@ LL | collider::foo(); note: `foo` could refer to the function imported here --> $DIR/E0659.rs:10:13 | -LL | pub use moon::*; - | ^^^^^^^ +LL | pub use crate::moon::*; + | ^^^^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate note: `foo` could also refer to the function imported here --> $DIR/E0659.rs:11:13 | -LL | pub use earth::*; - | ^^^^^^^^ +LL | pub use crate::earth::*; + | ^^^^^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate error: aborting due to 1 previous error diff --git a/tests/ui/explore-issue-38412.stderr b/tests/ui/explore-issue-38412.stderr index 884184ec16e..fca5c738d27 100644 --- a/tests/ui/explore-issue-38412.stderr +++ b/tests/ui/explore-issue-38412.stderr @@ -103,8 +103,8 @@ LL | r.pub_mod(); | ::: $DIR/auxiliary/pub-and-stability.rs:116:9 | -LL | pub(in m) fn pub_mod(&self) -> i32 { self.d_priv } - | ---------------------------------- private method defined here +LL | pub(in crate::m) fn pub_mod(&self) -> i32 { self.d_priv } + | ----------------------------------------- private method defined here error[E0624]: method `private` is private --> $DIR/explore-issue-38412.rs:50:7 @@ -156,8 +156,8 @@ LL | t.pub_mod(); | ::: $DIR/auxiliary/pub-and-stability.rs:130:9 | -LL | pub(in m) fn pub_mod(&self) -> i32 { self.0 } - | ---------------------------------- private method defined here +LL | pub(in crate::m) fn pub_mod(&self) -> i32 { self.0 } + | ----------------------------------------- private method defined here error[E0624]: method `private` is private --> $DIR/explore-issue-38412.rs:63:7 diff --git a/tests/ui/imports/duplicate.rs b/tests/ui/imports/duplicate.rs index 0c5a376da38..69ec82aafbd 100644 --- a/tests/ui/imports/duplicate.rs +++ b/tests/ui/imports/duplicate.rs @@ -7,27 +7,27 @@ mod b { } mod c { - pub use a::foo; + pub use crate::a::foo; } mod d { - use a::foo; - use a::foo; //~ ERROR the name `foo` is defined multiple times + use crate::a::foo; + use crate::a::foo; //~ ERROR the name `foo` is defined multiple times } mod e { - pub use a::*; - pub use c::*; // ok + pub use crate::a::*; + pub use crate::c::*; // ok } mod f { - pub use a::*; - pub use b::*; + pub use crate::a::*; + pub use crate::b::*; } mod g { - pub use a::*; - pub use f::*; + pub use crate::a::*; + pub use crate::f::*; } fn main() { diff --git a/tests/ui/imports/duplicate.stderr b/tests/ui/imports/duplicate.stderr index d7a7dfce921..f7dc7312b9d 100644 --- a/tests/ui/imports/duplicate.stderr +++ b/tests/ui/imports/duplicate.stderr @@ -1,10 +1,10 @@ error[E0252]: the name `foo` is defined multiple times --> $DIR/duplicate.rs:15:9 | -LL | use a::foo; - | ------ previous import of the value `foo` here -LL | use a::foo; - | ^^^^^^ `foo` reimported here +LL | use crate::a::foo; + | ------------- previous import of the value `foo` here +LL | use crate::a::foo; + | ^^^^^^^^^^^^^ `foo` reimported here | = note: `foo` must be defined only once in the value namespace of this module @@ -38,14 +38,14 @@ LL | f::foo(); note: `foo` could refer to the function imported here --> $DIR/duplicate.rs:24:13 | -LL | pub use a::*; - | ^^^^ +LL | pub use crate::a::*; + | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate note: `foo` could also refer to the function imported here --> $DIR/duplicate.rs:25:13 | -LL | pub use b::*; - | ^^^^ +LL | pub use crate::b::*; + | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate error[E0659]: `foo` is ambiguous @@ -80,14 +80,14 @@ LL | g::foo(); note: `foo` could refer to the function imported here --> $DIR/duplicate.rs:24:13 | -LL | pub use a::*; - | ^^^^ +LL | pub use crate::a::*; + | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate note: `foo` could also refer to the function imported here --> $DIR/duplicate.rs:25:13 | -LL | pub use b::*; - | ^^^^ +LL | pub use crate::b::*; + | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate = note: `#[warn(ambiguous_glob_imports)]` on by default diff --git a/tests/ui/imports/export-glob-imports-target.rs b/tests/ui/imports/export-glob-imports-target.rs index 6fde9fef0b6..84b9ffa83ff 100644 --- a/tests/ui/imports/export-glob-imports-target.rs +++ b/tests/ui/imports/export-glob-imports-target.rs @@ -9,7 +9,7 @@ mod foo { - use foo::bar::*; + use crate::foo::bar::*; pub mod bar { pub static a : isize = 10; } diff --git a/tests/ui/imports/glob-cycles.rs b/tests/ui/imports/glob-cycles.rs index 066aa3b53ea..d9850bec4ca 100644 --- a/tests/ui/imports/glob-cycles.rs +++ b/tests/ui/imports/glob-cycles.rs @@ -1,12 +1,12 @@ //@ check-pass mod foo { - pub use bar::*; - pub use main as f; + pub use crate::bar::*; + pub use crate::main as f; } mod bar { - pub use foo::*; + pub use crate::foo::*; } pub use foo::*; diff --git a/tests/ui/imports/glob-shadowing.rs b/tests/ui/imports/glob-shadowing.rs index 3a33b592b00..72848aac511 100644 --- a/tests/ui/imports/glob-shadowing.rs +++ b/tests/ui/imports/glob-shadowing.rs @@ -6,7 +6,7 @@ mod m { } mod glob_in_normal_module { - use m::*; + use crate::m::*; fn check() { let x = env!("PATH"); //~ ERROR `env` is ambiguous } @@ -14,7 +14,7 @@ mod glob_in_normal_module { mod glob_in_block_module { fn block() { - use m::*; + use crate::m::*; fn check() { let x = env!("PATH"); //~ ERROR `env` is ambiguous } @@ -24,7 +24,7 @@ mod glob_in_block_module { mod glob_shadows_item { pub macro fenv($e: expr) { $e } fn block() { - use m::*; + use crate::m::*; fn check() { let x = fenv!(); //~ ERROR `fenv` is ambiguous } diff --git a/tests/ui/imports/glob-shadowing.stderr b/tests/ui/imports/glob-shadowing.stderr index aff2eff68ac..0ce8d4f54f8 100644 --- a/tests/ui/imports/glob-shadowing.stderr +++ b/tests/ui/imports/glob-shadowing.stderr @@ -9,8 +9,8 @@ LL | let x = env!("PATH"); note: `env` could also refer to the macro imported here --> $DIR/glob-shadowing.rs:9:9 | -LL | use m::*; - | ^^^^ +LL | use crate::m::*; + | ^^^^^^^^^^^ = help: consider adding an explicit import of `env` to disambiguate = help: or use `self::env` to refer to this macro unambiguously @@ -25,8 +25,8 @@ LL | let x = env!("PATH"); note: `env` could also refer to the macro imported here --> $DIR/glob-shadowing.rs:17:13 | -LL | use m::*; - | ^^^^ +LL | use crate::m::*; + | ^^^^^^^^^^^ = help: consider adding an explicit import of `env` to disambiguate error[E0659]: `fenv` is ambiguous @@ -39,8 +39,8 @@ LL | let x = fenv!(); note: `fenv` could refer to the macro imported here --> $DIR/glob-shadowing.rs:27:13 | -LL | use m::*; - | ^^^^ +LL | use crate::m::*; + | ^^^^^^^^^^^ = help: consider adding an explicit import of `fenv` to disambiguate note: `fenv` could also refer to the macro defined here --> $DIR/glob-shadowing.rs:25:5 diff --git a/tests/ui/imports/import-glob-1.rs b/tests/ui/imports/import-glob-1.rs index 510f3814567..8beec4ce469 100644 --- a/tests/ui/imports/import-glob-1.rs +++ b/tests/ui/imports/import-glob-1.rs @@ -21,7 +21,7 @@ mod bar { } mod foo { - use bar::Baz::{Baz1, Baz2}; + use crate::bar::Baz::{Baz1, Baz2}; } fn main() {} diff --git a/tests/ui/imports/import-glob-circular.rs b/tests/ui/imports/import-glob-circular.rs index e47fa870c06..2dcfc7721fa 100644 --- a/tests/ui/imports/import-glob-circular.rs +++ b/tests/ui/imports/import-glob-circular.rs @@ -1,17 +1,17 @@ mod circ1 { - pub use circ2::f2; + pub use crate::circ2::f2; pub fn f1() { println!("f1"); } pub fn common() -> usize { return 0; } } mod circ2 { - pub use circ1::f1; + pub use crate::circ1::f1; pub fn f2() { println!("f2"); } pub fn common() -> usize { return 1; } } mod test { - use circ1::*; + use crate::circ1::*; fn test() { f1066(); } //~ ERROR cannot find function `f1066` in this scope } diff --git a/tests/ui/imports/import-loop-2.rs b/tests/ui/imports/import-loop-2.rs index 1bd0f06c671..42f9a07fff3 100644 --- a/tests/ui/imports/import-loop-2.rs +++ b/tests/ui/imports/import-loop-2.rs @@ -1,9 +1,9 @@ mod a { - pub use b::x; + pub use crate::b::x; } mod b { - pub use a::x; //~ ERROR unresolved import `a::x` + pub use crate::a::x; //~ ERROR unresolved import `crate::a::x` fn main() { let y = x; } } diff --git a/tests/ui/imports/import-loop-2.stderr b/tests/ui/imports/import-loop-2.stderr index 2521b6e7c04..2ef40c4e218 100644 --- a/tests/ui/imports/import-loop-2.stderr +++ b/tests/ui/imports/import-loop-2.stderr @@ -1,8 +1,8 @@ -error[E0432]: unresolved import `a::x` +error[E0432]: unresolved import `crate::a::x` --> $DIR/import-loop-2.rs:6:13 | -LL | pub use a::x; - | ^^^^ no `x` in `a` +LL | pub use crate::a::x; + | ^^^^^^^^^^^ no `x` in `a` error: aborting due to 1 previous error diff --git a/tests/ui/imports/import-loop.rs b/tests/ui/imports/import-loop.rs index fc5bd32adee..92483770711 100644 --- a/tests/ui/imports/import-loop.rs +++ b/tests/ui/imports/import-loop.rs @@ -1,7 +1,7 @@ use y::x; mod y { - pub use y::x; //~ ERROR unresolved import `y::x` + pub use crate::y::x; //~ ERROR unresolved import `crate::y::x` } fn main() { } diff --git a/tests/ui/imports/import-loop.stderr b/tests/ui/imports/import-loop.stderr index 801fc2552b6..888ca11293c 100644 --- a/tests/ui/imports/import-loop.stderr +++ b/tests/ui/imports/import-loop.stderr @@ -1,8 +1,8 @@ -error[E0432]: unresolved import `y::x` +error[E0432]: unresolved import `crate::y::x` --> $DIR/import-loop.rs:4:13 | -LL | pub use y::x; - | ^^^^ no `x` in `y` +LL | pub use crate::y::x; + | ^^^^^^^^^^^ no `x` in `y` error: aborting due to 1 previous error diff --git a/tests/ui/imports/import-rpass.rs b/tests/ui/imports/import-rpass.rs index 97c64fd9c63..f03f974d573 100644 --- a/tests/ui/imports/import-rpass.rs +++ b/tests/ui/imports/import-rpass.rs @@ -4,8 +4,8 @@ mod foo { } mod bar { - use foo::x; - use foo::x as z; + use crate::foo::x; + use crate::foo::x as z; pub fn thing() { x(10); z(10); } } diff --git a/tests/ui/imports/import4.rs b/tests/ui/imports/import4.rs index 01535fc6f45..f670cc06201 100644 --- a/tests/ui/imports/import4.rs +++ b/tests/ui/imports/import4.rs @@ -1,4 +1,4 @@ -mod a { pub use b::foo; } -mod b { pub use a::foo; } //~ ERROR unresolved import `a::foo` +mod a { pub use crate::b::foo; } +mod b { pub use crate::a::foo; } //~ ERROR unresolved import `crate::a::foo` fn main() { println!("loop"); } diff --git a/tests/ui/imports/import4.stderr b/tests/ui/imports/import4.stderr index c979d6c9ae2..4faa5f0520a 100644 --- a/tests/ui/imports/import4.stderr +++ b/tests/ui/imports/import4.stderr @@ -1,8 +1,8 @@ -error[E0432]: unresolved import `a::foo` +error[E0432]: unresolved import `crate::a::foo` --> $DIR/import4.rs:2:17 | -LL | mod b { pub use a::foo; } - | ^^^^^^ no `foo` in `a` +LL | mod b { pub use crate::a::foo; } + | ^^^^^^^^^^^^^ no `foo` in `a` error: aborting due to 1 previous error diff --git a/tests/ui/imports/import5.rs b/tests/ui/imports/import5.rs index 96d6c62d48a..7c7d99d7175 100644 --- a/tests/ui/imports/import5.rs +++ b/tests/ui/imports/import5.rs @@ -1,7 +1,7 @@ //@ run-pass use foo::bar; mod foo { - pub use foo::zed::bar; + pub use crate::foo::zed::bar; pub mod zed { pub fn bar() { println!("foo"); } } diff --git a/tests/ui/imports/import6.rs b/tests/ui/imports/import6.rs index 8632c21e5f7..1677003c0ec 100644 --- a/tests/ui/imports/import6.rs +++ b/tests/ui/imports/import6.rs @@ -10,6 +10,6 @@ mod foo { } } mod bar { - pub use foo::zed::baz; + pub use crate::foo::zed::baz; } pub fn main() { baz(); } diff --git a/tests/ui/imports/imports.rs b/tests/ui/imports/imports.rs index a770103c212..b5c25eb0447 100644 --- a/tests/ui/imports/imports.rs +++ b/tests/ui/imports/imports.rs @@ -3,7 +3,7 @@ // Like other items, private imports can be imported and used non-lexically in paths. mod a { - use a as foo; + use crate::a as foo; use self::foo::foo as bar; mod b { @@ -18,22 +18,22 @@ pub fn f() -> bool { true } // Items and explicit imports shadow globs. fn g() { - use foo::*; - use bar::*; + use crate::foo::*; + use crate::bar::*; fn f() -> bool { true } let _: bool = f(); } fn h() { - use foo::*; - use bar::*; - use f; + use crate::foo::*; + use crate::bar::*; + use crate::f; let _: bool = f(); } // Here, there appears to be shadowing but isn't because of namespaces. mod b { - use foo::*; // This imports `f` in the value namespace. + use crate::foo::*; // This imports `f` in the value namespace. use super::b as f; // This imports `f` only in the type namespace, fn test() { self::f(); } // so the glob isn't shadowed. } @@ -55,12 +55,13 @@ mod c { // Unused names can be ambiguous. mod d { - pub use foo::*; // This imports `f` in the value namespace. - pub use bar::*; // This also imports `f` in the value namespace. + pub use crate::foo::*; // This imports `f` in the value namespace. + pub use crate::bar::*; // This also imports `f` in the value namespace. } mod e { - pub use d::*; // n.b. Since `e::f` is not used, this is not considered to be a use of `d::f`. + pub use crate::d::*; // n.b. Since `e::f` is not used, + // this is not considered to be a use of `d::f`. } fn main() {} diff --git a/tests/ui/imports/issue-18083.rs b/tests/ui/imports/issue-18083.rs index 97c0bc83ad5..c111c9b5aa8 100644 --- a/tests/ui/imports/issue-18083.rs +++ b/tests/ui/imports/issue-18083.rs @@ -5,7 +5,7 @@ // each other and be reported as unresolved. mod a { - use b::{B}; + use crate::b::{B}; pub use self::inner::A; mod inner { @@ -14,7 +14,7 @@ mod a { } mod b { - use a::{A}; + use crate::a::{A}; pub use self::inner::B; mod inner { diff --git a/tests/ui/imports/issue-19498.rs b/tests/ui/imports/issue-19498.rs index 5b9ce85fd8b..ae4e5fd35e5 100644 --- a/tests/ui/imports/issue-19498.rs +++ b/tests/ui/imports/issue-19498.rs @@ -7,7 +7,7 @@ mod A {} //~ ERROR the name `A` is defined multiple times pub mod B {} //~ ERROR the name `B` is defined multiple times //~| NOTE `B` redefined here mod C { - use C::D; + use crate::C::D; mod D {} //~ ERROR the name `D` is defined multiple times //~| NOTE `D` redefined here } diff --git a/tests/ui/imports/issue-19498.stderr b/tests/ui/imports/issue-19498.stderr index eb0d68a24c9..a4ddff3ed99 100644 --- a/tests/ui/imports/issue-19498.stderr +++ b/tests/ui/imports/issue-19498.stderr @@ -31,16 +31,16 @@ LL | use self::B as OtherB; error[E0255]: the name `D` is defined multiple times --> $DIR/issue-19498.rs:11:5 | -LL | use C::D; - | ---- previous import of the module `D` here +LL | use crate::C::D; + | ----------- previous import of the module `D` here LL | mod D {} | ^^^^^ `D` redefined here | = note: `D` must be defined only once in the type namespace of this module help: you can use `as` to change the binding name of the import | -LL | use C::D as OtherD; - | +++++++++ +LL | use crate::C::D as OtherD; + | +++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/imports/issue-32222.rs b/tests/ui/imports/issue-32222.rs index 8c528bc0a1e..6f5530a065c 100644 --- a/tests/ui/imports/issue-32222.rs +++ b/tests/ui/imports/issue-32222.rs @@ -16,7 +16,7 @@ mod a { } mod b { - pub use a::bar; + pub use crate::a::bar; } fn main() {} diff --git a/tests/ui/imports/issue-4366-2.rs b/tests/ui/imports/issue-4366-2.rs index c777b750252..e92d964f889 100644 --- a/tests/ui/imports/issue-4366-2.rs +++ b/tests/ui/imports/issue-4366-2.rs @@ -7,11 +7,11 @@ mod foo { } mod a { pub mod b { - use foo::foo; + use crate::foo::foo; type Bar = isize; } pub mod sub { - use a::b::*; + use crate::a::b::*; fn sub() -> Bar { 1 } //~^ ERROR cannot find type `Bar` in this scope } diff --git a/tests/ui/imports/issue-4366.rs b/tests/ui/imports/issue-4366.rs index 9ec2e58ecad..e2d89fdaff3 100644 --- a/tests/ui/imports/issue-4366.rs +++ b/tests/ui/imports/issue-4366.rs @@ -10,11 +10,11 @@ mod foo { } mod a { pub mod b { - use foo::foo; + use crate::foo::foo; type Bar = isize; } pub mod sub { - use a::b::*; + use crate::a::b::*; fn sub() -> isize { foo(); 1 } //~ ERROR cannot find function `foo` in this scope } } diff --git a/tests/ui/imports/issue-4865-1.rs b/tests/ui/imports/issue-4865-1.rs index 1a72b1b5e3f..7c34d105550 100644 --- a/tests/ui/imports/issue-4865-1.rs +++ b/tests/ui/imports/issue-4865-1.rs @@ -6,16 +6,16 @@ // because these previous imports were not resolved. pub mod a { - use b::fn_b; - use c::*; + use crate::b::fn_b; + use crate::c::*; pub fn fn_a(){ } } pub mod b { - use a::fn_a; - use c::*; + use crate::a::fn_a; + use crate::c::*; pub fn fn_b(){ } diff --git a/tests/ui/imports/issue-4865-2.rs b/tests/ui/imports/issue-4865-2.rs index 746a74658dd..60ce2a468d9 100644 --- a/tests/ui/imports/issue-4865-2.rs +++ b/tests/ui/imports/issue-4865-2.rs @@ -12,7 +12,7 @@ pub mod say { } pub mod hello { - use say; + use crate::say; pub fn hello() { say::hello(); diff --git a/tests/ui/imports/issue-4865-3.rs b/tests/ui/imports/issue-4865-3.rs index 130223558cb..d9d17f4dd47 100644 --- a/tests/ui/imports/issue-4865-3.rs +++ b/tests/ui/imports/issue-4865-3.rs @@ -4,11 +4,11 @@ // they are not `pub`. pub mod a { - use b::*; + use crate::b::*; } pub mod b { - use a::*; + use crate::a::*; } use a::*; diff --git a/tests/ui/imports/issue-8208.rs b/tests/ui/imports/issue-8208.rs index 997d4d227b3..f6d88f830f2 100644 --- a/tests/ui/imports/issue-8208.rs +++ b/tests/ui/imports/issue-8208.rs @@ -2,7 +2,7 @@ use self::*; //~ ERROR: unresolved import `self::*` [E0432] //~^ NOTE cannot glob-import a module into itself mod foo { - use foo::*; //~ ERROR: unresolved import `foo::*` [E0432] + use crate::foo::*; //~ ERROR: unresolved import `crate::foo::*` [E0432] //~^ NOTE cannot glob-import a module into itself mod bar { diff --git a/tests/ui/imports/issue-8208.stderr b/tests/ui/imports/issue-8208.stderr index e59aea12cda..0fbe4d35fab 100644 --- a/tests/ui/imports/issue-8208.stderr +++ b/tests/ui/imports/issue-8208.stderr @@ -4,11 +4,11 @@ error[E0432]: unresolved import `self::*` LL | use self::*; | ^^^^^^^ cannot glob-import a module into itself -error[E0432]: unresolved import `foo::*` +error[E0432]: unresolved import `crate::foo::*` --> $DIR/issue-8208.rs:5:9 | -LL | use foo::*; - | ^^^^^^ cannot glob-import a module into itself +LL | use crate::foo::*; + | ^^^^^^^^^^^^^ cannot glob-import a module into itself error[E0432]: unresolved import `super::bar::*` --> $DIR/issue-8208.rs:9:13 diff --git a/tests/ui/imports/issue-8640.rs b/tests/ui/imports/issue-8640.rs index 51a02a32ec8..7cf73d0e93e 100644 --- a/tests/ui/imports/issue-8640.rs +++ b/tests/ui/imports/issue-8640.rs @@ -1,7 +1,7 @@ #[allow(unused_imports)] mod foo { - use baz::bar; + use crate::baz::bar; mod bar {} //~^ ERROR the name `bar` is defined multiple times } diff --git a/tests/ui/imports/issue-8640.stderr b/tests/ui/imports/issue-8640.stderr index d22fddb1a69..3ce57e3a44a 100644 --- a/tests/ui/imports/issue-8640.stderr +++ b/tests/ui/imports/issue-8640.stderr @@ -1,16 +1,16 @@ error[E0255]: the name `bar` is defined multiple times --> $DIR/issue-8640.rs:5:5 | -LL | use baz::bar; - | -------- previous import of the module `bar` here +LL | use crate::baz::bar; + | --------------- previous import of the module `bar` here LL | mod bar {} | ^^^^^^^ `bar` redefined here | = note: `bar` must be defined only once in the type namespace of this module help: you can use `as` to change the binding name of the import | -LL | use baz::bar as other_bar; - | ++++++++++++ +LL | use crate::baz::bar as other_bar; + | ++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/imports/local-modularized-tricky-fail-2.rs b/tests/ui/imports/local-modularized-tricky-fail-2.rs index 386de88bc3d..80b242b456c 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-2.rs +++ b/tests/ui/imports/local-modularized-tricky-fail-2.rs @@ -10,13 +10,13 @@ macro_rules! define_exported { () => { define_exported!(); mod m { - use exported; + use crate::exported; //~^ ERROR macro-expanded `macro_export` macros from the current crate cannot //~| WARN this was previously accepted } fn main() { - ::exported!(); + crate::exported!(); //~^ ERROR macro-expanded `macro_export` macros from the current crate cannot //~| WARN this was previously accepted } diff --git a/tests/ui/imports/local-modularized-tricky-fail-2.stderr b/tests/ui/imports/local-modularized-tricky-fail-2.stderr index 2c1965ac0a4..49f5c72947f 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-2.stderr +++ b/tests/ui/imports/local-modularized-tricky-fail-2.stderr @@ -1,8 +1,8 @@ error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths --> $DIR/local-modularized-tricky-fail-2.rs:13:9 | -LL | use exported; - | ^^^^^^^^ +LL | use crate::exported; + | ^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #52234 @@ -22,8 +22,8 @@ LL | define_exported!(); error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths --> $DIR/local-modularized-tricky-fail-2.rs:19:5 | -LL | ::exported!(); - | ^^^^^^^^^^ +LL | crate::exported!(); + | ^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #52234 diff --git a/tests/ui/imports/macros.rs b/tests/ui/imports/macros.rs index 7f479571e5e..cf67e08c87a 100644 --- a/tests/ui/imports/macros.rs +++ b/tests/ui/imports/macros.rs @@ -8,13 +8,13 @@ mod foo { mod m1 { m!(use two_macros::*;); - use foo::m; // This shadows the glob import + use crate::foo::m; // This shadows the glob import } mod m2 { use two_macros::*; m! { //~ ERROR ambiguous - use foo::m; + use crate::foo::m; } } diff --git a/tests/ui/imports/macros.stderr b/tests/ui/imports/macros.stderr index e34e5359b48..25a678c6b37 100644 --- a/tests/ui/imports/macros.stderr +++ b/tests/ui/imports/macros.stderr @@ -8,8 +8,8 @@ LL | m! { note: `m` could refer to the macro imported here --> $DIR/macros.rs:17:13 | -LL | use foo::m; - | ^^^^^^ +LL | use crate::foo::m; + | ^^^^^^^^^^^^^ note: `m` could also refer to the macro imported here --> $DIR/macros.rs:15:9 | diff --git a/tests/ui/imports/reexport-star.rs b/tests/ui/imports/reexport-star.rs index 461dc23b4dc..9bf4a6ce0c4 100644 --- a/tests/ui/imports/reexport-star.rs +++ b/tests/ui/imports/reexport-star.rs @@ -6,7 +6,7 @@ mod a { } mod b { - pub use a::*; + pub use crate::a::*; } pub fn main() { diff --git a/tests/ui/imports/reexports.rs b/tests/ui/imports/reexports.rs index 2a1a62834ce..6ad704b53fc 100644 --- a/tests/ui/imports/reexports.rs +++ b/tests/ui/imports/reexports.rs @@ -33,8 +33,8 @@ mod b { mod c { // Test that `foo` is not re-exported. - use b::a::foo::S; //~ ERROR `foo` - use b::b::foo::S as T; //~ ERROR `foo` + use crate::b::a::foo::S; //~ ERROR `foo` + use crate::b::b::foo::S as T; //~ ERROR `foo` } fn main() {} diff --git a/tests/ui/imports/reexports.stderr b/tests/ui/imports/reexports.stderr index fa05c0c0f8e..0ebcf8e58d6 100644 --- a/tests/ui/imports/reexports.stderr +++ b/tests/ui/imports/reexports.stderr @@ -11,10 +11,10 @@ LL | pub use super::foo; | ^^^^^^^^^^ error[E0603]: module import `foo` is private - --> $DIR/reexports.rs:36:15 + --> $DIR/reexports.rs:36:22 | -LL | use b::a::foo::S; - | ^^^ private module import +LL | use crate::b::a::foo::S; + | ^^^ private module import | note: the module import `foo` is defined here... --> $DIR/reexports.rs:24:17 @@ -28,10 +28,10 @@ LL | mod foo { | ^^^^^^^ error[E0603]: module import `foo` is private - --> $DIR/reexports.rs:37:15 + --> $DIR/reexports.rs:37:22 | -LL | use b::b::foo::S as T; - | ^^^ private module import +LL | use crate::b::b::foo::S as T; + | ^^^ private module import | note: the module import `foo` is defined here... --> $DIR/reexports.rs:29:17 diff --git a/tests/ui/imports/shadow_builtin_macros.rs b/tests/ui/imports/shadow_builtin_macros.rs index 5a149067408..7d318dfdb43 100644 --- a/tests/ui/imports/shadow_builtin_macros.rs +++ b/tests/ui/imports/shadow_builtin_macros.rs @@ -6,17 +6,17 @@ mod foo { } mod m1 { - use foo::panic; // ok + use crate::foo::panic; // ok fn f() { panic!(); } } mod m2 { - use foo::*; + use crate::foo::*; fn f() { panic!(); } //~ ERROR ambiguous } mod m3 { - ::two_macros::m!(use foo::panic;); + ::two_macros::m!(use crate::foo::panic;); fn f() { panic!(); } //~ ERROR ambiguous } @@ -40,12 +40,12 @@ mod bar { } mod m6 { - use bar::n; // ok + use crate::bar::n; // ok n!(); } mod m7 { - use bar::*; + use crate::bar::*; n!(); //~ ERROR ambiguous } diff --git a/tests/ui/imports/shadow_builtin_macros.stderr b/tests/ui/imports/shadow_builtin_macros.stderr index 6ffb31c20e6..c828b1193d8 100644 --- a/tests/ui/imports/shadow_builtin_macros.stderr +++ b/tests/ui/imports/shadow_builtin_macros.stderr @@ -9,8 +9,8 @@ LL | fn f() { panic!(); } note: `panic` could also refer to the macro imported here --> $DIR/shadow_builtin_macros.rs:14:9 | -LL | use foo::*; - | ^^^^^^ +LL | use crate::foo::*; + | ^^^^^^^^^^^^^ = help: consider adding an explicit import of `panic` to disambiguate = help: or use `self::panic` to refer to this macro unambiguously @@ -42,8 +42,8 @@ LL | n!(); note: `n` could refer to the macro imported here --> $DIR/shadow_builtin_macros.rs:48:9 | -LL | use bar::*; - | ^^^^^^ +LL | use crate::bar::*; + | ^^^^^^^^^^^^^ = help: consider adding an explicit import of `n` to disambiguate = help: or use `self::n` to refer to this macro unambiguously note: `n` could also refer to the macro imported here @@ -63,8 +63,8 @@ LL | fn f() { panic!(); } note: `panic` could also refer to the macro imported here --> $DIR/shadow_builtin_macros.rs:19:26 | -LL | ::two_macros::m!(use foo::panic;); - | ^^^^^^^^^^ +LL | ::two_macros::m!(use crate::foo::panic;); + | ^^^^^^^^^^^^^^^^^ = help: use `self::panic` to refer to this macro unambiguously error: aborting due to 4 previous errors diff --git a/tests/ui/intrinsics/intrinsic-alignment.rs b/tests/ui/intrinsics/intrinsic-alignment.rs index c42a4b94e29..a467c445d61 100644 --- a/tests/ui/intrinsics/intrinsic-alignment.rs +++ b/tests/ui/intrinsics/intrinsic-alignment.rs @@ -24,16 +24,16 @@ mod m { #[cfg(target_arch = "x86")] pub fn main() { unsafe { - assert_eq!(::rusti::pref_align_of::(), 8); - assert_eq!(::rusti::min_align_of::(), 4); + assert_eq!(crate::rusti::pref_align_of::(), 8); + assert_eq!(crate::rusti::min_align_of::(), 4); } } #[cfg(not(target_arch = "x86"))] pub fn main() { unsafe { - assert_eq!(::rusti::pref_align_of::(), 8); - assert_eq!(::rusti::min_align_of::(), 8); + assert_eq!(crate::rusti::pref_align_of::(), 8); + assert_eq!(crate::rusti::min_align_of::(), 8); } } } @@ -43,8 +43,8 @@ mod m { #[cfg(target_arch = "x86_64")] pub fn main() { unsafe { - assert_eq!(::rusti::pref_align_of::(), 8); - assert_eq!(::rusti::min_align_of::(), 8); + assert_eq!(crate::rusti::pref_align_of::(), 8); + assert_eq!(crate::rusti::min_align_of::(), 8); } } } @@ -53,8 +53,8 @@ mod m { mod m { pub fn main() { unsafe { - assert_eq!(::rusti::pref_align_of::(), 8); - assert_eq!(::rusti::min_align_of::(), 8); + assert_eq!(crate::rusti::pref_align_of::(), 8); + assert_eq!(crate::rusti::min_align_of::(), 8); } } } @@ -63,8 +63,8 @@ mod m { mod m { pub fn main() { unsafe { - assert_eq!(::rusti::pref_align_of::(), 8); - assert_eq!(::rusti::min_align_of::(), 8); + assert_eq!(crate::rusti::pref_align_of::(), 8); + assert_eq!(crate::rusti::min_align_of::(), 8); } } } -- cgit 1.4.1-3-g733a5 From 8a807cd498e24fcbe34f6bdb72ff28f4bddf89a5 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 3 Jun 2025 13:45:23 +0530 Subject: This commit adds a `toml` module that represents various subsections of `bootstrap.toml`. The module primarily defines the TOML representations of these subsections and their corresponding configuration parsing implementations, which are ultimately integrated into the main configuration. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `mod.rs` – Serves as the entry point for the TOML configuration and defines the `TomlConfig` struct along with its parsing implementation. - `rust.rs` – Defines the `Rust` subsection struct and its configuration parsing implementation. - `target.rs` – Defines the `Target` subsection struct and its configuration parsing implementation. - `llvm.rs` – Defines the `Llvm` subsection struct and its configuration parsing implementation. - `install.rs` – Defines the `Install` subsection struct and its configuration parsing implementation. - `gcc.rs` – Defines the `Gcc` subsection struct and its configuration parsing implementation. - `dist.rs` – Defines the `Dist` subsection struct and its configuration parsing implementation. - `build.rs` – Defines the `Build` subsection struct and its configuration parsing implementation. --- src/bootstrap/src/core/config/toml/build.rs | 72 +++ src/bootstrap/src/core/config/toml/change_id.rs | 34 ++ src/bootstrap/src/core/config/toml/dist.rs | 52 ++ src/bootstrap/src/core/config/toml/gcc.rs | 34 ++ src/bootstrap/src/core/config/toml/install.rs | 43 ++ src/bootstrap/src/core/config/toml/llvm.rs | 284 ++++++++++ src/bootstrap/src/core/config/toml/mod.rs | 184 +++++++ src/bootstrap/src/core/config/toml/rust.rs | 664 ++++++++++++++++++++++++ src/bootstrap/src/core/config/toml/target.rs | 174 +++++++ 9 files changed, 1541 insertions(+) create mode 100644 src/bootstrap/src/core/config/toml/build.rs create mode 100644 src/bootstrap/src/core/config/toml/change_id.rs create mode 100644 src/bootstrap/src/core/config/toml/dist.rs create mode 100644 src/bootstrap/src/core/config/toml/gcc.rs create mode 100644 src/bootstrap/src/core/config/toml/install.rs create mode 100644 src/bootstrap/src/core/config/toml/llvm.rs create mode 100644 src/bootstrap/src/core/config/toml/mod.rs create mode 100644 src/bootstrap/src/core/config/toml/rust.rs create mode 100644 src/bootstrap/src/core/config/toml/target.rs diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs new file mode 100644 index 00000000000..85ded3c87d9 --- /dev/null +++ b/src/bootstrap/src/core/config/toml/build.rs @@ -0,0 +1,72 @@ +//! This module defines the `Build` struct, which represents the `[build]` table +//! in the `bootstrap.toml` configuration file. +//! +//! The `[build]` table contains global options that influence the overall build process, +//! such as default host and target triples, paths to tools, build directories, and +//! various feature flags. These options apply across different stages and components +//! unless specifically overridden by other configuration sections or command-line flags. + +use serde::{Deserialize, Deserializer}; + +use crate::core::config::toml::ReplaceOpt; +use crate::core::config::{Merge, StringOrBool}; +use crate::{HashSet, PathBuf, define_config, exit}; + +define_config! { + /// TOML representation of various global build decisions. + #[derive(Default)] + struct Build { + build: Option = "build", + description: Option = "description", + host: Option> = "host", + target: Option> = "target", + build_dir: Option = "build-dir", + cargo: Option = "cargo", + rustc: Option = "rustc", + rustfmt: Option = "rustfmt", + cargo_clippy: Option = "cargo-clippy", + docs: Option = "docs", + compiler_docs: Option = "compiler-docs", + library_docs_private_items: Option = "library-docs-private-items", + docs_minification: Option = "docs-minification", + submodules: Option = "submodules", + gdb: Option = "gdb", + lldb: Option = "lldb", + nodejs: Option = "nodejs", + npm: Option = "npm", + python: Option = "python", + reuse: Option = "reuse", + locked_deps: Option = "locked-deps", + vendor: Option = "vendor", + full_bootstrap: Option = "full-bootstrap", + bootstrap_cache_path: Option = "bootstrap-cache-path", + extended: Option = "extended", + tools: Option> = "tools", + verbose: Option = "verbose", + sanitizers: Option = "sanitizers", + profiler: Option = "profiler", + cargo_native_static: Option = "cargo-native-static", + low_priority: Option = "low-priority", + configure_args: Option> = "configure-args", + local_rebuild: Option = "local-rebuild", + print_step_timings: Option = "print-step-timings", + print_step_rusage: Option = "print-step-rusage", + check_stage: Option = "check-stage", + doc_stage: Option = "doc-stage", + build_stage: Option = "build-stage", + test_stage: Option = "test-stage", + install_stage: Option = "install-stage", + dist_stage: Option = "dist-stage", + bench_stage: Option = "bench-stage", + patch_binaries_for_nix: Option = "patch-binaries-for-nix", + // NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally + metrics: Option = "metrics", + android_ndk: Option = "android-ndk", + optimized_compiler_builtins: Option = "optimized-compiler-builtins", + jobs: Option = "jobs", + compiletest_diff_tool: Option = "compiletest-diff-tool", + compiletest_use_stage0_libtest: Option = "compiletest-use-stage0-libtest", + ccache: Option = "ccache", + exclude: Option> = "exclude", + } +} diff --git a/src/bootstrap/src/core/config/toml/change_id.rs b/src/bootstrap/src/core/config/toml/change_id.rs new file mode 100644 index 00000000000..41dd2531d43 --- /dev/null +++ b/src/bootstrap/src/core/config/toml/change_id.rs @@ -0,0 +1,34 @@ +use serde::{Deserialize, Deserializer}; +use serde_derive::Deserialize; + +/// This enum is used for deserializing change IDs from TOML, allowing both numeric values and the string `"ignore"`. +#[derive(Clone, Debug, PartialEq)] +pub enum ChangeId { + Ignore, + Id(usize), +} + +/// Since we use `#[serde(deny_unknown_fields)]` on `TomlConfig`, we need a wrapper type +/// for the "change-id" field to parse it even if other fields are invalid. This ensures +/// that if deserialization fails due to other fields, we can still provide the changelogs +/// to allow developers to potentially find the reason for the failure in the logs.. +#[derive(Deserialize, Default)] +pub(crate) struct ChangeIdWrapper { + #[serde(alias = "change-id", default, deserialize_with = "deserialize_change_id")] + pub(crate) inner: Option, +} + +fn deserialize_change_id<'de, D: Deserializer<'de>>( + deserializer: D, +) -> Result, D::Error> { + let value = toml::Value::deserialize(deserializer)?; + Ok(match value { + toml::Value::String(s) if s == "ignore" => Some(ChangeId::Ignore), + toml::Value::Integer(i) => Some(ChangeId::Id(i as usize)), + _ => { + return Err(serde::de::Error::custom( + "expected \"ignore\" or an integer for change-id", + )); + } + }) +} diff --git a/src/bootstrap/src/core/config/toml/dist.rs b/src/bootstrap/src/core/config/toml/dist.rs new file mode 100644 index 00000000000..b1429ef1861 --- /dev/null +++ b/src/bootstrap/src/core/config/toml/dist.rs @@ -0,0 +1,52 @@ +//! This module defines the `Dist` struct, which represents the `[dist]` table +//! in the `bootstrap.toml` configuration file. +//! +//! The `[dist]` table contains options related to the distribution process, +//! including signing, uploading artifacts, source tarballs, compression settings, +//! and inclusion of specific tools. + +use serde::{Deserialize, Deserializer}; + +use crate::core::config::toml::ReplaceOpt; +use crate::core::config::{Merge, set}; +use crate::{Config, HashSet, PathBuf, define_config, exit}; + +define_config! { + struct Dist { + sign_folder: Option = "sign-folder", + upload_addr: Option = "upload-addr", + src_tarball: Option = "src-tarball", + compression_formats: Option> = "compression-formats", + compression_profile: Option = "compression-profile", + include_mingw_linker: Option = "include-mingw-linker", + vendor: Option = "vendor", + } +} + +impl Config { + /// Applies distribution-related configuration from the `Dist` struct + /// to the global `Config` structure. + pub fn apply_dist_config(&mut self, toml_dist: Option) { + if let Some(dist) = toml_dist { + let Dist { + sign_folder, + upload_addr, + src_tarball, + compression_formats, + compression_profile, + include_mingw_linker, + vendor, + } = dist; + self.dist_sign_folder = sign_folder.map(PathBuf::from); + self.dist_upload_addr = upload_addr; + self.dist_compression_formats = compression_formats; + set(&mut self.dist_compression_profile, compression_profile); + set(&mut self.rust_dist_src, src_tarball); + set(&mut self.dist_include_mingw_linker, include_mingw_linker); + self.dist_vendor = vendor.unwrap_or_else(|| { + // If we're building from git or tarball sources, enable it by default. + self.rust_info.is_managed_git_subrepository() || self.rust_info.is_from_tarball() + }); + } + } +} diff --git a/src/bootstrap/src/core/config/toml/gcc.rs b/src/bootstrap/src/core/config/toml/gcc.rs new file mode 100644 index 00000000000..bb817c2aaef --- /dev/null +++ b/src/bootstrap/src/core/config/toml/gcc.rs @@ -0,0 +1,34 @@ +//! This module defines the `Gcc` struct, which represents the `[gcc]` table +//! in the `bootstrap.toml` configuration file. +//! +//! The `[gcc]` table contains options specifically related to building or +//! acquiring the GCC compiler for use within the Rust build process. + +use serde::{Deserialize, Deserializer}; + +use crate::core::config::toml::ReplaceOpt; +use crate::core::config::{GccCiMode, Merge}; +use crate::{Config, HashSet, PathBuf, define_config, exit}; + +define_config! { + /// TOML representation of how the GCC build is configured. + struct Gcc { + download_ci_gcc: Option = "download-ci-gcc", + } +} + +impl Config { + /// Applies GCC-related configuration from the `TomlGcc` struct to the + /// global `Config` structure. + pub fn apply_gcc_config(&mut self, toml_gcc: Option) { + if let Some(gcc) = toml_gcc { + self.gcc_ci_mode = match gcc.download_ci_gcc { + Some(value) => match value { + true => GccCiMode::DownloadFromCi, + false => GccCiMode::BuildLocally, + }, + None => GccCiMode::default(), + }; + } + } +} diff --git a/src/bootstrap/src/core/config/toml/install.rs b/src/bootstrap/src/core/config/toml/install.rs new file mode 100644 index 00000000000..6b9ab87a0b6 --- /dev/null +++ b/src/bootstrap/src/core/config/toml/install.rs @@ -0,0 +1,43 @@ +//! This module defines the `Install` struct, which represents the `[install]` table +//! in the `bootstrap.toml` configuration file. +//! +//! The `[install]` table contains options that specify the installation paths +//! for various components of the Rust toolchain. These paths determine where +//! executables, libraries, documentation, and other files will be placed +//! during the `install` stage of the build. + +use serde::{Deserialize, Deserializer}; + +use crate::core::config::toml::ReplaceOpt; +use crate::core::config::{Merge, set}; +use crate::{Config, HashSet, PathBuf, define_config, exit}; + +define_config! { + /// TOML representation of various global install decisions. + struct Install { + prefix: Option = "prefix", + sysconfdir: Option = "sysconfdir", + docdir: Option = "docdir", + bindir: Option = "bindir", + libdir: Option = "libdir", + mandir: Option = "mandir", + datadir: Option = "datadir", + } +} + +impl Config { + /// Applies installation-related configuration from the `Install` struct + /// to the global `Config` structure. + pub fn apply_install_config(&mut self, toml_install: Option) { + if let Some(install) = toml_install { + let Install { prefix, sysconfdir, docdir, bindir, libdir, mandir, datadir } = install; + self.prefix = prefix.map(PathBuf::from); + self.sysconfdir = sysconfdir.map(PathBuf::from); + self.datadir = datadir.map(PathBuf::from); + self.docdir = docdir.map(PathBuf::from); + set(&mut self.bindir, bindir.map(PathBuf::from)); + self.libdir = libdir.map(PathBuf::from); + self.mandir = mandir.map(PathBuf::from); + } + } +} diff --git a/src/bootstrap/src/core/config/toml/llvm.rs b/src/bootstrap/src/core/config/toml/llvm.rs new file mode 100644 index 00000000000..4774e202bd8 --- /dev/null +++ b/src/bootstrap/src/core/config/toml/llvm.rs @@ -0,0 +1,284 @@ +//! This module defines the `Llvm` struct, which represents the `[llvm]` table +//! in the `bootstrap.toml` configuration file. + +use serde::{Deserialize, Deserializer}; + +use crate::core::config::toml::{Merge, ReplaceOpt, TomlConfig}; +use crate::core::config::{StringOrBool, set}; +use crate::{Config, HashMap, HashSet, PathBuf, define_config, exit}; + +define_config! { + /// TOML representation of how the LLVM build is configured. + struct Llvm { + optimize: Option = "optimize", + thin_lto: Option = "thin-lto", + release_debuginfo: Option = "release-debuginfo", + assertions: Option = "assertions", + tests: Option = "tests", + enzyme: Option = "enzyme", + plugins: Option = "plugins", + // FIXME: Remove this field at Q2 2025, it has been replaced by build.ccache + ccache: Option = "ccache", + static_libstdcpp: Option = "static-libstdcpp", + libzstd: Option = "libzstd", + ninja: Option = "ninja", + targets: Option = "targets", + experimental_targets: Option = "experimental-targets", + link_jobs: Option = "link-jobs", + link_shared: Option = "link-shared", + version_suffix: Option = "version-suffix", + clang_cl: Option = "clang-cl", + cflags: Option = "cflags", + cxxflags: Option = "cxxflags", + ldflags: Option = "ldflags", + use_libcxx: Option = "use-libcxx", + use_linker: Option = "use-linker", + allow_old_toolchain: Option = "allow-old-toolchain", + offload: Option = "offload", + polly: Option = "polly", + clang: Option = "clang", + enable_warnings: Option = "enable-warnings", + download_ci_llvm: Option = "download-ci-llvm", + build_config: Option> = "build-config", + } +} + +/// Compares the current `Llvm` options against those in the CI LLVM builder and detects any incompatible options. +/// It does this by destructuring the `Llvm` instance to make sure every `Llvm` field is covered and not missing. +#[cfg(not(test))] +pub fn check_incompatible_options_for_ci_llvm( + current_config_toml: TomlConfig, + ci_config_toml: TomlConfig, +) -> Result<(), String> { + macro_rules! err { + ($current:expr, $expected:expr) => { + if let Some(current) = &$current { + if Some(current) != $expected.as_ref() { + return Err(format!( + "ERROR: Setting `llvm.{}` is incompatible with `llvm.download-ci-llvm`. \ + Current value: {:?}, Expected value(s): {}{:?}", + stringify!($expected).replace("_", "-"), + $current, + if $expected.is_some() { "None/" } else { "" }, + $expected, + )); + }; + }; + }; + } + + macro_rules! warn { + ($current:expr, $expected:expr) => { + if let Some(current) = &$current { + if Some(current) != $expected.as_ref() { + println!( + "WARNING: `llvm.{}` has no effect with `llvm.download-ci-llvm`. \ + Current value: {:?}, Expected value(s): {}{:?}", + stringify!($expected).replace("_", "-"), + $current, + if $expected.is_some() { "None/" } else { "" }, + $expected, + ); + }; + }; + }; + } + + let (Some(current_llvm_config), Some(ci_llvm_config)) = + (current_config_toml.llvm, ci_config_toml.llvm) + else { + return Ok(()); + }; + + let Llvm { + optimize, + thin_lto, + release_debuginfo, + assertions: _, + tests: _, + plugins, + ccache: _, + static_libstdcpp: _, + libzstd, + ninja: _, + targets, + experimental_targets, + link_jobs: _, + link_shared: _, + version_suffix, + clang_cl, + cflags, + cxxflags, + ldflags, + use_libcxx, + use_linker, + allow_old_toolchain, + offload, + polly, + clang, + enable_warnings, + download_ci_llvm: _, + build_config, + enzyme, + } = ci_llvm_config; + + err!(current_llvm_config.optimize, optimize); + err!(current_llvm_config.thin_lto, thin_lto); + err!(current_llvm_config.release_debuginfo, release_debuginfo); + err!(current_llvm_config.libzstd, libzstd); + err!(current_llvm_config.targets, targets); + err!(current_llvm_config.experimental_targets, experimental_targets); + err!(current_llvm_config.clang_cl, clang_cl); + err!(current_llvm_config.version_suffix, version_suffix); + err!(current_llvm_config.cflags, cflags); + err!(current_llvm_config.cxxflags, cxxflags); + err!(current_llvm_config.ldflags, ldflags); + err!(current_llvm_config.use_libcxx, use_libcxx); + err!(current_llvm_config.use_linker, use_linker); + err!(current_llvm_config.allow_old_toolchain, allow_old_toolchain); + err!(current_llvm_config.offload, offload); + err!(current_llvm_config.polly, polly); + err!(current_llvm_config.clang, clang); + err!(current_llvm_config.build_config, build_config); + err!(current_llvm_config.plugins, plugins); + err!(current_llvm_config.enzyme, enzyme); + + warn!(current_llvm_config.enable_warnings, enable_warnings); + + Ok(()) +} + +impl Config { + pub fn apply_llvm_config( + &mut self, + toml_llvm: Option, + ccache: &mut Option, + ) { + let mut llvm_tests = None; + let mut llvm_enzyme = None; + let mut llvm_offload = None; + let mut llvm_plugins = None; + + if let Some(llvm) = toml_llvm { + let Llvm { + optimize: optimize_toml, + thin_lto, + release_debuginfo, + assertions: _, + tests, + enzyme, + plugins, + ccache: llvm_ccache, + static_libstdcpp, + libzstd, + ninja, + targets, + experimental_targets, + link_jobs, + link_shared, + version_suffix, + clang_cl, + cflags, + cxxflags, + ldflags, + use_libcxx, + use_linker, + allow_old_toolchain, + offload, + polly, + clang, + enable_warnings, + download_ci_llvm, + build_config, + } = llvm; + if llvm_ccache.is_some() { + eprintln!("Warning: llvm.ccache is deprecated. Use build.ccache instead."); + } + + if ccache.is_none() { + *ccache = llvm_ccache; + } + set(&mut self.ninja_in_file, ninja); + llvm_tests = tests; + llvm_enzyme = enzyme; + llvm_offload = offload; + llvm_plugins = plugins; + set(&mut self.llvm_optimize, optimize_toml); + set(&mut self.llvm_thin_lto, thin_lto); + set(&mut self.llvm_release_debuginfo, release_debuginfo); + set(&mut self.llvm_static_stdcpp, static_libstdcpp); + set(&mut self.llvm_libzstd, libzstd); + if let Some(v) = link_shared { + self.llvm_link_shared.set(Some(v)); + } + self.llvm_targets.clone_from(&targets); + self.llvm_experimental_targets.clone_from(&experimental_targets); + self.llvm_link_jobs = link_jobs; + self.llvm_version_suffix.clone_from(&version_suffix); + self.llvm_clang_cl.clone_from(&clang_cl); + + self.llvm_cflags.clone_from(&cflags); + self.llvm_cxxflags.clone_from(&cxxflags); + self.llvm_ldflags.clone_from(&ldflags); + set(&mut self.llvm_use_libcxx, use_libcxx); + self.llvm_use_linker.clone_from(&use_linker); + self.llvm_allow_old_toolchain = allow_old_toolchain.unwrap_or(false); + self.llvm_offload = offload.unwrap_or(false); + self.llvm_polly = polly.unwrap_or(false); + self.llvm_clang = clang.unwrap_or(false); + self.llvm_enable_warnings = enable_warnings.unwrap_or(false); + self.llvm_build_config = build_config.clone().unwrap_or(Default::default()); + + self.llvm_from_ci = self.parse_download_ci_llvm(download_ci_llvm, self.llvm_assertions); + + if self.llvm_from_ci { + let warn = |option: &str| { + println!( + "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build." + ); + println!( + "HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false." + ); + }; + + if static_libstdcpp.is_some() { + warn("static-libstdcpp"); + } + + if link_shared.is_some() { + warn("link-shared"); + } + + // FIXME(#129153): instead of all the ad-hoc `download-ci-llvm` checks that follow, + // use the `builder-config` present in tarballs since #128822 to compare the local + // config to the ones used to build the LLVM artifacts on CI, and only notify users + // if they've chosen a different value. + + if libzstd.is_some() { + println!( + "WARNING: when using `download-ci-llvm`, the local `llvm.libzstd` option, \ + like almost all `llvm.*` options, will be ignored and set by the LLVM CI \ + artifacts builder config." + ); + println!( + "HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false." + ); + } + } + + if !self.llvm_from_ci && self.llvm_thin_lto && link_shared.is_none() { + // If we're building with ThinLTO on, by default we want to link + // to LLVM shared, to avoid re-doing ThinLTO (which happens in + // the link step) with each stage. + self.llvm_link_shared.set(Some(true)); + } + } else { + self.llvm_from_ci = self.parse_download_ci_llvm(None, false); + } + + self.llvm_tests = llvm_tests.unwrap_or(false); + self.llvm_enzyme = llvm_enzyme.unwrap_or(false); + self.llvm_offload = llvm_offload.unwrap_or(false); + self.llvm_plugins = llvm_plugins.unwrap_or(false); + } +} diff --git a/src/bootstrap/src/core/config/toml/mod.rs b/src/bootstrap/src/core/config/toml/mod.rs new file mode 100644 index 00000000000..ac4e249e580 --- /dev/null +++ b/src/bootstrap/src/core/config/toml/mod.rs @@ -0,0 +1,184 @@ +//! This module defines the structures that directly mirror the `bootstrap.toml` +//! file's format. These types are used for `serde` deserialization. +//! +//! Crucially, this module also houses the core logic for loading, parsing, and merging +//! these raw TOML configurations from various sources (the main `bootstrap.toml`, +//! included files, profile defaults, and command-line overrides). This processed +//! TOML data then serves as an intermediate representation, which is further +//! transformed and applied to the final [`Config`] struct. + +use serde::Deserialize; +use serde_derive::Deserialize; +pub mod build; +pub mod change_id; +pub mod dist; +pub mod gcc; +pub mod install; +pub mod llvm; +pub mod rust; +pub mod target; + +use build::Build; +use change_id::{ChangeId, ChangeIdWrapper}; +use dist::Dist; +use gcc::Gcc; +use install::Install; +use llvm::Llvm; +use rust::Rust; +use target::TomlTarget; + +use crate::core::config::{Merge, ReplaceOpt}; +use crate::{Config, HashMap, HashSet, Path, PathBuf, exit, fs, t}; + +/// Structure of the `bootstrap.toml` file that configuration is read from. +/// +/// This structure uses `Decodable` to automatically decode a TOML configuration +/// file into this format, and then this is traversed and written into the above +/// `Config` structure. +#[derive(Deserialize, Default)] +#[serde(deny_unknown_fields, rename_all = "kebab-case")] +pub(crate) struct TomlConfig { + #[serde(flatten)] + pub(crate) change_id: ChangeIdWrapper, + pub(super) build: Option, + pub(super) install: Option, + pub(super) llvm: Option, + pub(super) gcc: Option, + pub(super) rust: Option, + pub(super) target: Option>, + pub(super) dist: Option, + pub(super) profile: Option, + pub(super) include: Option>, +} + +impl Merge for TomlConfig { + fn merge( + &mut self, + parent_config_path: Option, + included_extensions: &mut HashSet, + TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id, include }: Self, + replace: ReplaceOpt, + ) { + fn do_merge(x: &mut Option, y: Option, replace: ReplaceOpt) { + if let Some(new) = y { + if let Some(original) = x { + original.merge(None, &mut Default::default(), new, replace); + } else { + *x = Some(new); + } + } + } + + self.change_id.inner.merge(None, &mut Default::default(), change_id.inner, replace); + self.profile.merge(None, &mut Default::default(), profile, replace); + + do_merge(&mut self.build, build, replace); + do_merge(&mut self.install, install, replace); + do_merge(&mut self.llvm, llvm, replace); + do_merge(&mut self.gcc, gcc, replace); + do_merge(&mut self.rust, rust, replace); + do_merge(&mut self.dist, dist, replace); + + match (self.target.as_mut(), target) { + (_, None) => {} + (None, Some(target)) => self.target = Some(target), + (Some(original_target), Some(new_target)) => { + for (triple, new) in new_target { + if let Some(original) = original_target.get_mut(&triple) { + original.merge(None, &mut Default::default(), new, replace); + } else { + original_target.insert(triple, new); + } + } + } + } + + let parent_dir = parent_config_path + .as_ref() + .and_then(|p| p.parent().map(ToOwned::to_owned)) + .unwrap_or_default(); + + // `include` handled later since we ignore duplicates using `ReplaceOpt::IgnoreDuplicate` to + // keep the upper-level configuration to take precedence. + for include_path in include.clone().unwrap_or_default().iter().rev() { + let include_path = parent_dir.join(include_path); + let include_path = include_path.canonicalize().unwrap_or_else(|e| { + eprintln!("ERROR: Failed to canonicalize '{}' path: {e}", include_path.display()); + exit!(2); + }); + + let included_toml = Config::get_toml_inner(&include_path).unwrap_or_else(|e| { + eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display()); + exit!(2); + }); + + assert!( + included_extensions.insert(include_path.clone()), + "Cyclic inclusion detected: '{}' is being included again before its previous inclusion was fully processed.", + include_path.display() + ); + + self.merge( + Some(include_path.clone()), + included_extensions, + included_toml, + // Ensures that parent configuration always takes precedence + // over child configurations. + ReplaceOpt::IgnoreDuplicate, + ); + + included_extensions.remove(&include_path); + } + } +} + +/// This file is embedded in the overlay directory of the tarball sources. It is +/// useful in scenarios where developers want to see how the tarball sources were +/// generated. +/// +/// We also use this file to compare the host's bootstrap.toml against the CI rustc builder +/// configuration to detect any incompatible options. +pub const BUILDER_CONFIG_FILENAME: &str = "builder-config"; + +impl Config { + pub(crate) fn get_builder_toml(&self, build_name: &str) -> Result { + if self.dry_run() { + return Ok(TomlConfig::default()); + } + + let builder_config_path = + self.out.join(self.build.triple).join(build_name).join(BUILDER_CONFIG_FILENAME); + Self::get_toml(&builder_config_path) + } + + pub(crate) fn get_toml(file: &Path) -> Result { + #[cfg(test)] + return Ok(TomlConfig::default()); + + #[cfg(not(test))] + Self::get_toml_inner(file) + } + + pub(crate) fn get_toml_inner(file: &Path) -> Result { + let contents = + t!(fs::read_to_string(file), format!("config file {} not found", file.display())); + // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of + // TomlConfig and sub types to be monomorphized 5x by toml. + toml::from_str(&contents) + .and_then(|table: toml::Value| TomlConfig::deserialize(table)) + .inspect_err(|_| { + if let Ok(ChangeIdWrapper { inner: Some(ChangeId::Id(id)) }) = + toml::from_str::(&contents) + .and_then(|table: toml::Value| ChangeIdWrapper::deserialize(table)) + { + let changes = crate::find_recent_config_change_ids(id); + if !changes.is_empty() { + println!( + "WARNING: There have been changes to x.py since you last updated:\n{}", + crate::human_readable_changes(changes) + ); + } + } + }) + } +} diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs new file mode 100644 index 00000000000..81f95f356a5 --- /dev/null +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -0,0 +1,664 @@ +//! This module defines the `Rust` struct, which represents the `[rust]` table +//! in the `bootstrap.toml` configuration file. + +use std::str::FromStr; + +use serde::{Deserialize, Deserializer}; + +use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; +use crate::core::config::toml::TomlConfig; +use crate::core::config::{ + DebuginfoLevel, Merge, ReplaceOpt, RustcLto, StringOrBool, set, threads_from_config, +}; +use crate::flags::Warnings; +use crate::{BTreeSet, Config, HashSet, PathBuf, TargetSelection, define_config, exit}; + +define_config! { + /// TOML representation of how the Rust build is configured. + struct Rust { + optimize: Option = "optimize", + debug: Option = "debug", + codegen_units: Option = "codegen-units", + codegen_units_std: Option = "codegen-units-std", + rustc_debug_assertions: Option = "debug-assertions", + randomize_layout: Option = "randomize-layout", + std_debug_assertions: Option = "debug-assertions-std", + tools_debug_assertions: Option = "debug-assertions-tools", + overflow_checks: Option = "overflow-checks", + overflow_checks_std: Option = "overflow-checks-std", + debug_logging: Option = "debug-logging", + debuginfo_level: Option = "debuginfo-level", + debuginfo_level_rustc: Option = "debuginfo-level-rustc", + debuginfo_level_std: Option = "debuginfo-level-std", + debuginfo_level_tools: Option = "debuginfo-level-tools", + debuginfo_level_tests: Option = "debuginfo-level-tests", + backtrace: Option = "backtrace", + incremental: Option = "incremental", + default_linker: Option = "default-linker", + channel: Option = "channel", + // FIXME: Remove this field at Q2 2025, it has been replaced by build.description + description: Option = "description", + musl_root: Option = "musl-root", + rpath: Option = "rpath", + strip: Option = "strip", + frame_pointers: Option = "frame-pointers", + stack_protector: Option = "stack-protector", + verbose_tests: Option = "verbose-tests", + optimize_tests: Option = "optimize-tests", + codegen_tests: Option = "codegen-tests", + omit_git_hash: Option = "omit-git-hash", + dist_src: Option = "dist-src", + save_toolstates: Option = "save-toolstates", + codegen_backends: Option> = "codegen-backends", + llvm_bitcode_linker: Option = "llvm-bitcode-linker", + lld: Option = "lld", + lld_mode: Option = "use-lld", + llvm_tools: Option = "llvm-tools", + deny_warnings: Option = "deny-warnings", + backtrace_on_ice: Option = "backtrace-on-ice", + verify_llvm_ir: Option = "verify-llvm-ir", + thin_lto_import_instr_limit: Option = "thin-lto-import-instr-limit", + remap_debuginfo: Option = "remap-debuginfo", + jemalloc: Option = "jemalloc", + test_compare_mode: Option = "test-compare-mode", + llvm_libunwind: Option = "llvm-libunwind", + control_flow_guard: Option = "control-flow-guard", + ehcont_guard: Option = "ehcont-guard", + new_symbol_mangling: Option = "new-symbol-mangling", + profile_generate: Option = "profile-generate", + profile_use: Option = "profile-use", + // ignored; this is set from an env var set by bootstrap.py + download_rustc: Option = "download-rustc", + lto: Option = "lto", + validate_mir_opts: Option = "validate-mir-opts", + std_features: Option> = "std-features", + } +} + +/// LLD in bootstrap works like this: +/// - Self-contained lld: use `rust-lld` from the compiler's sysroot +/// - External: use an external `lld` binary +/// +/// It is configured depending on the target: +/// 1) Everything except MSVC +/// - Self-contained: `-Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker` +/// - External: `-Clinker-flavor=gnu-lld-cc` +/// 2) MSVC +/// - Self-contained: `-Clinker=` +/// - External: `-Clinker=lld` +#[derive(Copy, Clone, Default, Debug, PartialEq)] +pub enum LldMode { + /// Do not use LLD + #[default] + Unused, + /// Use `rust-lld` from the compiler's sysroot + SelfContained, + /// Use an externally provided `lld` binary. + /// Note that the linker name cannot be overridden, the binary has to be named `lld` and it has + /// to be in $PATH. + External, +} + +impl LldMode { + pub fn is_used(&self) -> bool { + match self { + LldMode::SelfContained | LldMode::External => true, + LldMode::Unused => false, + } + } +} + +impl<'de> Deserialize<'de> for LldMode { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct LldModeVisitor; + + impl serde::de::Visitor<'_> for LldModeVisitor { + type Value = LldMode; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("one of true, 'self-contained' or 'external'") + } + + fn visit_bool(self, v: bool) -> Result + where + E: serde::de::Error, + { + Ok(if v { LldMode::External } else { LldMode::Unused }) + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + match v { + "external" => Ok(LldMode::External), + "self-contained" => Ok(LldMode::SelfContained), + _ => Err(E::custom(format!("unknown mode {v}"))), + } + } + } + + deserializer.deserialize_any(LldModeVisitor) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum RustOptimize { + String(String), + Int(u8), + Bool(bool), +} + +impl Default for RustOptimize { + fn default() -> RustOptimize { + RustOptimize::Bool(false) + } +} + +impl<'de> Deserialize<'de> for RustOptimize { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(OptimizeVisitor) + } +} + +struct OptimizeVisitor; + +impl serde::de::Visitor<'_> for OptimizeVisitor { + type Value = RustOptimize; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str(r#"one of: 0, 1, 2, 3, "s", "z", true, false"#) + } + + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + if matches!(value, "s" | "z") { + Ok(RustOptimize::String(value.to_string())) + } else { + Err(serde::de::Error::custom(format_optimize_error_msg(value))) + } + } + + fn visit_i64(self, value: i64) -> Result + where + E: serde::de::Error, + { + if matches!(value, 0..=3) { + Ok(RustOptimize::Int(value as u8)) + } else { + Err(serde::de::Error::custom(format_optimize_error_msg(value))) + } + } + + fn visit_bool(self, value: bool) -> Result + where + E: serde::de::Error, + { + Ok(RustOptimize::Bool(value)) + } +} + +fn format_optimize_error_msg(v: impl std::fmt::Display) -> String { + format!( + r#"unrecognized option for rust optimize: "{v}", expected one of 0, 1, 2, 3, "s", "z", true, false"# + ) +} + +impl RustOptimize { + pub(crate) fn is_release(&self) -> bool { + match &self { + RustOptimize::Bool(true) | RustOptimize::String(_) => true, + RustOptimize::Int(i) => *i > 0, + RustOptimize::Bool(false) => false, + } + } + + pub(crate) fn get_opt_level(&self) -> Option { + match &self { + RustOptimize::String(s) => Some(s.clone()), + RustOptimize::Int(i) => Some(i.to_string()), + RustOptimize::Bool(_) => None, + } + } +} + +/// Compares the current Rust options against those in the CI rustc builder and detects any incompatible options. +/// It does this by destructuring the `Rust` instance to make sure every `Rust` field is covered and not missing. +pub fn check_incompatible_options_for_ci_rustc( + host: TargetSelection, + current_config_toml: TomlConfig, + ci_config_toml: TomlConfig, +) -> Result<(), String> { + macro_rules! err { + ($current:expr, $expected:expr, $config_section:expr) => { + if let Some(current) = &$current { + if Some(current) != $expected.as_ref() { + return Err(format!( + "ERROR: Setting `{}` is incompatible with `rust.download-rustc`. \ + Current value: {:?}, Expected value(s): {}{:?}", + format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")), + $current, + if $expected.is_some() { "None/" } else { "" }, + $expected, + )); + }; + }; + }; + } + + macro_rules! warn { + ($current:expr, $expected:expr, $config_section:expr) => { + if let Some(current) = &$current { + if Some(current) != $expected.as_ref() { + println!( + "WARNING: `{}` has no effect with `rust.download-rustc`. \ + Current value: {:?}, Expected value(s): {}{:?}", + format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")), + $current, + if $expected.is_some() { "None/" } else { "" }, + $expected, + ); + }; + }; + }; + } + + let current_profiler = current_config_toml.build.as_ref().and_then(|b| b.profiler); + let profiler = ci_config_toml.build.as_ref().and_then(|b| b.profiler); + err!(current_profiler, profiler, "build"); + + let current_optimized_compiler_builtins = + current_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins); + let optimized_compiler_builtins = + ci_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins); + err!(current_optimized_compiler_builtins, optimized_compiler_builtins, "build"); + + // We always build the in-tree compiler on cross targets, so we only care + // about the host target here. + let host_str = host.to_string(); + if let Some(current_cfg) = current_config_toml.target.as_ref().and_then(|c| c.get(&host_str)) + && current_cfg.profiler.is_some() + { + let ci_target_toml = ci_config_toml.target.as_ref().and_then(|c| c.get(&host_str)); + let ci_cfg = ci_target_toml.ok_or(format!( + "Target specific config for '{host_str}' is not present for CI-rustc" + ))?; + + let profiler = &ci_cfg.profiler; + err!(current_cfg.profiler, profiler, "build"); + + let optimized_compiler_builtins = &ci_cfg.optimized_compiler_builtins; + err!(current_cfg.optimized_compiler_builtins, optimized_compiler_builtins, "build"); + } + + let (Some(current_rust_config), Some(ci_rust_config)) = + (current_config_toml.rust, ci_config_toml.rust) + else { + return Ok(()); + }; + + let Rust { + // Following options are the CI rustc incompatible ones. + optimize, + randomize_layout, + debug_logging, + debuginfo_level_rustc, + llvm_tools, + llvm_bitcode_linker, + lto, + stack_protector, + strip, + lld_mode, + jemalloc, + rpath, + channel, + description, + incremental, + default_linker, + std_features, + + // Rest of the options can simply be ignored. + debug: _, + codegen_units: _, + codegen_units_std: _, + rustc_debug_assertions: _, + std_debug_assertions: _, + tools_debug_assertions: _, + overflow_checks: _, + overflow_checks_std: _, + debuginfo_level: _, + debuginfo_level_std: _, + debuginfo_level_tools: _, + debuginfo_level_tests: _, + backtrace: _, + musl_root: _, + verbose_tests: _, + optimize_tests: _, + codegen_tests: _, + omit_git_hash: _, + dist_src: _, + save_toolstates: _, + codegen_backends: _, + lld: _, + deny_warnings: _, + backtrace_on_ice: _, + verify_llvm_ir: _, + thin_lto_import_instr_limit: _, + remap_debuginfo: _, + test_compare_mode: _, + llvm_libunwind: _, + control_flow_guard: _, + ehcont_guard: _, + new_symbol_mangling: _, + profile_generate: _, + profile_use: _, + download_rustc: _, + validate_mir_opts: _, + frame_pointers: _, + } = ci_rust_config; + + // There are two kinds of checks for CI rustc incompatible options: + // 1. Checking an option that may change the compiler behaviour/output. + // 2. Checking an option that have no effect on the compiler behaviour/output. + // + // If the option belongs to the first category, we call `err` macro for a hard error; + // otherwise, we just print a warning with `warn` macro. + + err!(current_rust_config.optimize, optimize, "rust"); + err!(current_rust_config.randomize_layout, randomize_layout, "rust"); + err!(current_rust_config.debug_logging, debug_logging, "rust"); + err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc, "rust"); + err!(current_rust_config.rpath, rpath, "rust"); + err!(current_rust_config.strip, strip, "rust"); + err!(current_rust_config.lld_mode, lld_mode, "rust"); + err!(current_rust_config.llvm_tools, llvm_tools, "rust"); + err!(current_rust_config.llvm_bitcode_linker, llvm_bitcode_linker, "rust"); + err!(current_rust_config.jemalloc, jemalloc, "rust"); + err!(current_rust_config.default_linker, default_linker, "rust"); + err!(current_rust_config.stack_protector, stack_protector, "rust"); + err!(current_rust_config.lto, lto, "rust"); + err!(current_rust_config.std_features, std_features, "rust"); + + warn!(current_rust_config.channel, channel, "rust"); + warn!(current_rust_config.description, description, "rust"); + warn!(current_rust_config.incremental, incremental, "rust"); + + Ok(()) +} + +impl Config { + pub fn apply_rust_config( + &mut self, + toml_rust: Option, + warnings: Warnings, + description: &mut Option, + ) { + let mut debug = None; + let mut rustc_debug_assertions = None; + let mut std_debug_assertions = None; + let mut tools_debug_assertions = None; + let mut overflow_checks = None; + let mut overflow_checks_std = None; + let mut debug_logging = None; + let mut debuginfo_level = None; + let mut debuginfo_level_rustc = None; + let mut debuginfo_level_std = None; + let mut debuginfo_level_tools = None; + let mut debuginfo_level_tests = None; + let mut optimize = None; + let mut lld_enabled = None; + let mut std_features = None; + + if let Some(rust) = toml_rust { + let Rust { + optimize: optimize_toml, + debug: debug_toml, + codegen_units, + codegen_units_std, + rustc_debug_assertions: rustc_debug_assertions_toml, + std_debug_assertions: std_debug_assertions_toml, + tools_debug_assertions: tools_debug_assertions_toml, + overflow_checks: overflow_checks_toml, + overflow_checks_std: overflow_checks_std_toml, + debug_logging: debug_logging_toml, + debuginfo_level: debuginfo_level_toml, + debuginfo_level_rustc: debuginfo_level_rustc_toml, + debuginfo_level_std: debuginfo_level_std_toml, + debuginfo_level_tools: debuginfo_level_tools_toml, + debuginfo_level_tests: debuginfo_level_tests_toml, + backtrace, + incremental, + randomize_layout, + default_linker, + channel: _, // already handled above + description: rust_description, + musl_root, + rpath, + verbose_tests, + optimize_tests, + codegen_tests, + omit_git_hash: _, // already handled above + dist_src, + save_toolstates, + codegen_backends, + lld: lld_enabled_toml, + llvm_tools, + llvm_bitcode_linker, + deny_warnings, + backtrace_on_ice, + verify_llvm_ir, + thin_lto_import_instr_limit, + remap_debuginfo, + jemalloc, + test_compare_mode, + llvm_libunwind, + control_flow_guard, + ehcont_guard, + new_symbol_mangling, + profile_generate, + profile_use, + download_rustc, + lto, + validate_mir_opts, + frame_pointers, + stack_protector, + strip, + lld_mode, + std_features: std_features_toml, + } = rust; + + // FIXME(#133381): alt rustc builds currently do *not* have rustc debug assertions + // enabled. We should not download a CI alt rustc if we need rustc to have debug + // assertions (e.g. for crashes test suite). This can be changed once something like + // [Enable debug assertions on alt + // builds](https://github.com/rust-lang/rust/pull/131077) lands. + // + // Note that `rust.debug = true` currently implies `rust.debug-assertions = true`! + // + // This relies also on the fact that the global default for `download-rustc` will be + // `false` if it's not explicitly set. + let debug_assertions_requested = matches!(rustc_debug_assertions_toml, Some(true)) + || (matches!(debug_toml, Some(true)) + && !matches!(rustc_debug_assertions_toml, Some(false))); + + if debug_assertions_requested + && let Some(ref opt) = download_rustc + && opt.is_string_or_true() + { + eprintln!( + "WARN: currently no CI rustc builds have rustc debug assertions \ + enabled. Please either set `rust.debug-assertions` to `false` if you \ + want to use download CI rustc or set `rust.download-rustc` to `false`." + ); + } + + self.download_rustc_commit = self.download_ci_rustc_commit( + download_rustc, + debug_assertions_requested, + self.llvm_assertions, + ); + + debug = debug_toml; + rustc_debug_assertions = rustc_debug_assertions_toml; + std_debug_assertions = std_debug_assertions_toml; + tools_debug_assertions = tools_debug_assertions_toml; + overflow_checks = overflow_checks_toml; + overflow_checks_std = overflow_checks_std_toml; + debug_logging = debug_logging_toml; + debuginfo_level = debuginfo_level_toml; + debuginfo_level_rustc = debuginfo_level_rustc_toml; + debuginfo_level_std = debuginfo_level_std_toml; + debuginfo_level_tools = debuginfo_level_tools_toml; + debuginfo_level_tests = debuginfo_level_tests_toml; + lld_enabled = lld_enabled_toml; + std_features = std_features_toml; + + optimize = optimize_toml; + self.rust_new_symbol_mangling = new_symbol_mangling; + set(&mut self.rust_optimize_tests, optimize_tests); + set(&mut self.codegen_tests, codegen_tests); + set(&mut self.rust_rpath, rpath); + set(&mut self.rust_strip, strip); + set(&mut self.rust_frame_pointers, frame_pointers); + self.rust_stack_protector = stack_protector; + set(&mut self.jemalloc, jemalloc); + set(&mut self.test_compare_mode, test_compare_mode); + set(&mut self.backtrace, backtrace); + if rust_description.is_some() { + eprintln!( + "Warning: rust.description is deprecated. Use build.description instead." + ); + } + if description.is_none() { + *description = rust_description; + } + set(&mut self.rust_dist_src, dist_src); + set(&mut self.verbose_tests, verbose_tests); + // in the case "false" is set explicitly, do not overwrite the command line args + if let Some(true) = incremental { + self.incremental = true; + } + set(&mut self.lld_mode, lld_mode); + set(&mut self.llvm_bitcode_linker_enabled, llvm_bitcode_linker); + + self.rust_randomize_layout = randomize_layout.unwrap_or_default(); + self.llvm_tools_enabled = llvm_tools.unwrap_or(true); + + self.llvm_enzyme = self.channel == "dev" || self.channel == "nightly"; + self.rustc_default_linker = default_linker; + self.musl_root = musl_root.map(PathBuf::from); + self.save_toolstates = save_toolstates.map(PathBuf::from); + set( + &mut self.deny_warnings, + match warnings { + Warnings::Deny => Some(true), + Warnings::Warn => Some(false), + Warnings::Default => deny_warnings, + }, + ); + set(&mut self.backtrace_on_ice, backtrace_on_ice); + set(&mut self.rust_verify_llvm_ir, verify_llvm_ir); + self.rust_thin_lto_import_instr_limit = thin_lto_import_instr_limit; + set(&mut self.rust_remap_debuginfo, remap_debuginfo); + set(&mut self.control_flow_guard, control_flow_guard); + set(&mut self.ehcont_guard, ehcont_guard); + self.llvm_libunwind_default = + llvm_libunwind.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")); + + if let Some(ref backends) = codegen_backends { + let available_backends = ["llvm", "cranelift", "gcc"]; + + self.rust_codegen_backends = backends.iter().map(|s| { + if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) { + if available_backends.contains(&backend) { + panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'."); + } else { + println!("HELP: '{s}' for 'rust.codegen-backends' might fail. \ + Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ + In this case, it would be referred to as '{backend}'."); + } + } + + s.clone() + }).collect(); + } + + self.rust_codegen_units = codegen_units.map(threads_from_config); + self.rust_codegen_units_std = codegen_units_std.map(threads_from_config); + + if self.rust_profile_use.is_none() { + self.rust_profile_use = profile_use; + } + + if self.rust_profile_generate.is_none() { + self.rust_profile_generate = profile_generate; + } + + self.rust_lto = + lto.as_deref().map(|value| RustcLto::from_str(value).unwrap()).unwrap_or_default(); + self.rust_validate_mir_opts = validate_mir_opts; + } + + self.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true)); + + // We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will + // build our internal lld and use it as the default linker, by setting the `rust.lld` config + // to true by default: + // - on the `x86_64-unknown-linux-gnu` target + // - on the `dev` and `nightly` channels + // - when building our in-tree llvm (i.e. the target has not set an `llvm-config`), so that + // we're also able to build the corresponding lld + // - or when using an external llvm that's downloaded from CI, which also contains our prebuilt + // lld + // - otherwise, we'd be using an external llvm, and lld would not necessarily available and + // thus, disabled + // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g. + // when the config sets `rust.lld = false` + if self.build.triple == "x86_64-unknown-linux-gnu" + && self.hosts == [self.build] + && (self.channel == "dev" || self.channel == "nightly") + { + let no_llvm_config = self + .target_config + .get(&self.build) + .is_some_and(|target_config| target_config.llvm_config.is_none()); + let enable_lld = self.llvm_from_ci || no_llvm_config; + // Prefer the config setting in case an explicit opt-out is needed. + self.lld_enabled = lld_enabled.unwrap_or(enable_lld); + } else { + set(&mut self.lld_enabled, lld_enabled); + } + + let default_std_features = BTreeSet::from([String::from("panic-unwind")]); + self.rust_std_features = std_features.unwrap_or(default_std_features); + + let default = debug == Some(true); + self.rustc_debug_assertions = rustc_debug_assertions.unwrap_or(default); + self.std_debug_assertions = std_debug_assertions.unwrap_or(self.rustc_debug_assertions); + self.tools_debug_assertions = tools_debug_assertions.unwrap_or(self.rustc_debug_assertions); + self.rust_overflow_checks = overflow_checks.unwrap_or(default); + self.rust_overflow_checks_std = overflow_checks_std.unwrap_or(self.rust_overflow_checks); + + self.rust_debug_logging = debug_logging.unwrap_or(self.rustc_debug_assertions); + + let with_defaults = |debuginfo_level_specific: Option<_>| { + debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) { + DebuginfoLevel::Limited + } else { + DebuginfoLevel::None + }) + }; + self.rust_debuginfo_level_rustc = with_defaults(debuginfo_level_rustc); + self.rust_debuginfo_level_std = with_defaults(debuginfo_level_std); + self.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools); + self.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(DebuginfoLevel::None); + } +} diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs new file mode 100644 index 00000000000..7f074d1b25e --- /dev/null +++ b/src/bootstrap/src/core/config/toml/target.rs @@ -0,0 +1,174 @@ +//! This module defines the structures and logic for handling target-specific configuration +//! within the `bootstrap.toml` file. This allows you to customize build settings, tools, +//! and flags for individual compilation targets. +//! +//! It includes: +//! +//! * [`TomlTarget`]: This struct directly mirrors the `[target.]` sections in your +//! `bootstrap.toml`. It's used for deserializing raw TOML data for a specific target. +//! * [`Target`]: This struct represents the processed and validated configuration for a +//! build target, which is is stored in the main [`Config`] structure. +//! * [`Config::apply_target_config`]: This method processes the `TomlTarget` data and +//! applies it to the global [`Config`], ensuring proper path resolution, validation, +//! and integration with other build settings. + +use std::collections::HashMap; + +use serde::{Deserialize, Deserializer}; + +use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; +use crate::core::config::{LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool}; +use crate::{Config, HashSet, PathBuf, TargetSelection, define_config, exit}; + +define_config! { + /// TOML representation of how each build target is configured. + struct TomlTarget { + cc: Option = "cc", + cxx: Option = "cxx", + ar: Option = "ar", + ranlib: Option = "ranlib", + default_linker: Option = "default-linker", + linker: Option = "linker", + split_debuginfo: Option = "split-debuginfo", + llvm_config: Option = "llvm-config", + llvm_has_rust_patches: Option = "llvm-has-rust-patches", + llvm_filecheck: Option = "llvm-filecheck", + llvm_libunwind: Option = "llvm-libunwind", + sanitizers: Option = "sanitizers", + profiler: Option = "profiler", + rpath: Option = "rpath", + crt_static: Option = "crt-static", + musl_root: Option = "musl-root", + musl_libdir: Option = "musl-libdir", + wasi_root: Option = "wasi-root", + qemu_rootfs: Option = "qemu-rootfs", + no_std: Option = "no-std", + codegen_backends: Option> = "codegen-backends", + runner: Option = "runner", + optimized_compiler_builtins: Option = "optimized-compiler-builtins", + jemalloc: Option = "jemalloc", + } +} + +/// Per-target configuration stored in the global configuration structure. +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub struct Target { + /// Some(path to llvm-config) if using an external LLVM. + pub llvm_config: Option, + pub llvm_has_rust_patches: Option, + /// Some(path to FileCheck) if one was specified. + pub llvm_filecheck: Option, + pub llvm_libunwind: Option, + pub cc: Option, + pub cxx: Option, + pub ar: Option, + pub ranlib: Option, + pub default_linker: Option, + pub linker: Option, + pub split_debuginfo: Option, + pub sanitizers: Option, + pub profiler: Option, + pub rpath: Option, + pub crt_static: Option, + pub musl_root: Option, + pub musl_libdir: Option, + pub wasi_root: Option, + pub qemu_rootfs: Option, + pub runner: Option, + pub no_std: bool, + pub codegen_backends: Option>, + pub optimized_compiler_builtins: Option, + pub jemalloc: Option, +} + +impl Target { + pub fn from_triple(triple: &str) -> Self { + let mut target: Self = Default::default(); + if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") { + target.no_std = true; + } + if triple.contains("emscripten") { + target.runner = Some("node".into()); + } + target + } +} + +impl Config { + pub fn apply_target_config(&mut self, toml_target: Option>) { + if let Some(t) = toml_target { + for (triple, cfg) in t { + let mut target = Target::from_triple(&triple); + + if let Some(ref s) = cfg.llvm_config { + if self.download_rustc_commit.is_some() && triple == *self.build.triple { + panic!( + "setting llvm_config for the host is incompatible with download-rustc" + ); + } + target.llvm_config = Some(self.src.join(s)); + } + if let Some(patches) = cfg.llvm_has_rust_patches { + assert!( + self.submodules == Some(false) || cfg.llvm_config.is_some(), + "use of `llvm-has-rust-patches` is restricted to cases where either submodules are disabled or llvm-config been provided" + ); + target.llvm_has_rust_patches = Some(patches); + } + if let Some(ref s) = cfg.llvm_filecheck { + target.llvm_filecheck = Some(self.src.join(s)); + } + target.llvm_libunwind = cfg.llvm_libunwind.as_ref().map(|v| { + v.parse().unwrap_or_else(|_| { + panic!("failed to parse target.{triple}.llvm-libunwind") + }) + }); + if let Some(s) = cfg.no_std { + target.no_std = s; + } + target.cc = cfg.cc.map(PathBuf::from); + target.cxx = cfg.cxx.map(PathBuf::from); + target.ar = cfg.ar.map(PathBuf::from); + target.ranlib = cfg.ranlib.map(PathBuf::from); + target.linker = cfg.linker.map(PathBuf::from); + target.crt_static = cfg.crt_static; + target.musl_root = cfg.musl_root.map(PathBuf::from); + target.musl_libdir = cfg.musl_libdir.map(PathBuf::from); + target.wasi_root = cfg.wasi_root.map(PathBuf::from); + target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from); + target.runner = cfg.runner; + target.sanitizers = cfg.sanitizers; + target.profiler = cfg.profiler; + target.rpath = cfg.rpath; + target.optimized_compiler_builtins = cfg.optimized_compiler_builtins; + target.jemalloc = cfg.jemalloc; + + if let Some(ref backends) = cfg.codegen_backends { + let available_backends = ["llvm", "cranelift", "gcc"]; + + target.codegen_backends = Some(backends.iter().map(|s| { + if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) { + if available_backends.contains(&backend) { + panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'."); + } else { + println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \ + Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ + In this case, it would be referred to as '{backend}'."); + } + } + + s.clone() + }).collect()); + } + + target.split_debuginfo = cfg.split_debuginfo.as_ref().map(|v| { + v.parse().unwrap_or_else(|_| { + panic!("invalid value for target.{triple}.split-debuginfo") + }) + }); + + self.target_config.insert(TargetSelection::from_user(&triple), target); + } + } + } +} -- cgit 1.4.1-3-g733a5 From cc301233642d745564df3867f2a1f1f540b021d2 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 3 Jun 2025 13:46:23 +0530 Subject: move target selection to its separate module --- src/bootstrap/src/core/config/target_selection.rs | 147 ++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 src/bootstrap/src/core/config/target_selection.rs diff --git a/src/bootstrap/src/core/config/target_selection.rs b/src/bootstrap/src/core/config/target_selection.rs new file mode 100644 index 00000000000..ebd3fe7a8c6 --- /dev/null +++ b/src/bootstrap/src/core/config/target_selection.rs @@ -0,0 +1,147 @@ +use std::fmt; + +use crate::core::config::SplitDebuginfo; +use crate::utils::cache::{INTERNER, Interned}; +use crate::{Path, env}; + +#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +// N.B.: This type is used everywhere, and the entire codebase relies on it being Copy. +// Making !Copy is highly nontrivial! +pub struct TargetSelection { + pub triple: Interned, + pub file: Option>, + pub synthetic: bool, +} + +/// Newtype over `Vec` so we can implement custom parsing logic +#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct TargetSelectionList(pub Vec); + +pub fn target_selection_list(s: &str) -> Result { + Ok(TargetSelectionList( + s.split(',').filter(|s| !s.is_empty()).map(TargetSelection::from_user).collect(), + )) +} + +impl TargetSelection { + pub fn from_user(selection: &str) -> Self { + let path = Path::new(selection); + + let (triple, file) = if path.exists() { + let triple = path + .file_stem() + .expect("Target specification file has no file stem") + .to_str() + .expect("Target specification file stem is not UTF-8"); + + (triple, Some(selection)) + } else { + (selection, None) + }; + + let triple = INTERNER.intern_str(triple); + let file = file.map(|f| INTERNER.intern_str(f)); + + Self { triple, file, synthetic: false } + } + + pub fn create_synthetic(triple: &str, file: &str) -> Self { + Self { + triple: INTERNER.intern_str(triple), + file: Some(INTERNER.intern_str(file)), + synthetic: true, + } + } + + pub fn rustc_target_arg(&self) -> &str { + self.file.as_ref().unwrap_or(&self.triple) + } + + pub fn contains(&self, needle: &str) -> bool { + self.triple.contains(needle) + } + + pub fn starts_with(&self, needle: &str) -> bool { + self.triple.starts_with(needle) + } + + pub fn ends_with(&self, needle: &str) -> bool { + self.triple.ends_with(needle) + } + + // See src/bootstrap/synthetic_targets.rs + pub fn is_synthetic(&self) -> bool { + self.synthetic + } + + pub fn is_msvc(&self) -> bool { + self.contains("msvc") + } + + pub fn is_windows(&self) -> bool { + self.contains("windows") + } + + pub fn is_windows_gnu(&self) -> bool { + self.ends_with("windows-gnu") + } + + pub fn is_cygwin(&self) -> bool { + self.is_windows() && + // ref. https://cygwin.com/pipermail/cygwin/2022-February/250802.html + env::var("OSTYPE").is_ok_and(|v| v.to_lowercase().contains("cygwin")) + } + + pub fn needs_crt_begin_end(&self) -> bool { + self.contains("musl") && !self.contains("unikraft") + } + + /// Path to the file defining the custom target, if any. + pub fn filepath(&self) -> Option<&Path> { + self.file.as_ref().map(Path::new) + } +} + +impl fmt::Display for TargetSelection { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.triple)?; + if let Some(file) = self.file { + write!(f, "({file})")?; + } + Ok(()) + } +} + +impl fmt::Debug for TargetSelection { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{self}") + } +} + +impl PartialEq<&str> for TargetSelection { + fn eq(&self, other: &&str) -> bool { + self.triple == *other + } +} + +// Targets are often used as directory names throughout bootstrap. +// This impl makes it more ergonomics to use them as such. +impl AsRef for TargetSelection { + fn as_ref(&self) -> &Path { + self.triple.as_ref() + } +} + +impl SplitDebuginfo { + /// Returns the default `-Csplit-debuginfo` value for the current target. See the comment for + /// `rust.split-debuginfo` in `bootstrap.example.toml`. + pub fn default_for_platform(target: TargetSelection) -> Self { + if target.contains("apple") { + SplitDebuginfo::Unpacked + } else if target.is_windows() { + SplitDebuginfo::Packed + } else { + SplitDebuginfo::Off + } + } +} -- cgit 1.4.1-3-g733a5 From 0de60ddd2a0fba166122bf1b864fa822611fbd50 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 3 Jun 2025 13:46:54 +0530 Subject: Move all common types, macros and utility method to config/mod.rs --- src/bootstrap/src/core/config/mod.rs | 411 +++++++++++++++++++++++++++++++++++ 1 file changed, 411 insertions(+) diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 179e15e778b..8fe7b53068b 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -1,7 +1,418 @@ +//! Entry point for the `config` module. +//! +//! This module defines two macros: +//! +//! - `define_config!`: A declarative macro used instead of `#[derive(Deserialize)]` to reduce +//! compile time and binary size, especially for the bootstrap binary. +//! +//! - `check_ci_llvm!`: A compile-time assertion macro that ensures certain settings are +//! not enabled when `download-ci-llvm` is active. +//! +//! A declarative macro is used here in place of a procedural derive macro to minimize +//! the compile time of the bootstrap process. +//! +//! Additionally, this module defines common types, enums, and helper functions used across +//! various TOML configuration sections in `bootstrap.toml`. +//! +//! It provides shared definitions for: +//! - Data types deserialized from TOML. +//! - Utility enums for specific configuration options. +//! - Helper functions for managing configuration values. + #[expect(clippy::module_inception)] mod config; pub mod flags; +pub mod target_selection; #[cfg(test)] mod tests; +pub mod toml; + +use std::collections::HashSet; +use std::path::PathBuf; +use build_helper::exit; pub use config::*; +use serde::{Deserialize, Deserializer}; +use serde_derive::Deserialize; +pub use target_selection::TargetSelection; +pub use toml::BUILDER_CONFIG_FILENAME; +pub use toml::change_id::ChangeId; +pub use toml::rust::LldMode; +pub use toml::target::Target; +#[cfg(feature = "tracing")] +use tracing::{instrument, span}; + +use crate::Display; +use crate::str::FromStr; + +// We are using a decl macro instead of a derive proc macro here to reduce the compile time of bootstrap. +#[macro_export] +macro_rules! define_config { + ($(#[$attr:meta])* struct $name:ident { + $($field:ident: Option<$field_ty:ty> = $field_key:literal,)* + }) => { + $(#[$attr])* + pub struct $name { + $(pub $field: Option<$field_ty>,)* + } + + impl Merge for $name { + fn merge( + &mut self, + _parent_config_path: Option, + _included_extensions: &mut HashSet, + other: Self, + replace: ReplaceOpt + ) { + $( + match replace { + ReplaceOpt::IgnoreDuplicate => { + if self.$field.is_none() { + self.$field = other.$field; + } + }, + ReplaceOpt::Override => { + if other.$field.is_some() { + self.$field = other.$field; + } + } + ReplaceOpt::ErrorOnDuplicate => { + if other.$field.is_some() { + if self.$field.is_some() { + if cfg!(test) { + panic!("overriding existing option") + } else { + eprintln!("overriding existing option: `{}`", stringify!($field)); + exit!(2); + } + } else { + self.$field = other.$field; + } + } + } + } + )* + } + } + + // The following is a trimmed version of what serde_derive generates. All parts not relevant + // for toml deserialization have been removed. This reduces the binary size and improves + // compile time of bootstrap. + impl<'de> Deserialize<'de> for $name { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct Field; + impl<'de> serde::de::Visitor<'de> for Field { + type Value = $name; + fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(concat!("struct ", stringify!($name))) + } + + #[inline] + fn visit_map
(self, mut map: A) -> Result + where + A: serde::de::MapAccess<'de>, + { + $(let mut $field: Option<$field_ty> = None;)* + while let Some(key) = + match serde::de::MapAccess::next_key::(&mut map) { + Ok(val) => val, + Err(err) => { + return Err(err); + } + } + { + match &*key { + $($field_key => { + if $field.is_some() { + return Err(::duplicate_field( + $field_key, + )); + } + $field = match serde::de::MapAccess::next_value::<$field_ty>( + &mut map, + ) { + Ok(val) => Some(val), + Err(err) => { + return Err(err); + } + }; + })* + key => { + return Err(serde::de::Error::unknown_field(key, FIELDS)); + } + } + } + Ok($name { $($field),* }) + } + } + const FIELDS: &'static [&'static str] = &[ + $($field_key,)* + ]; + Deserializer::deserialize_struct( + deserializer, + stringify!($name), + FIELDS, + Field, + ) + } + } + } +} + +#[macro_export] +macro_rules! check_ci_llvm { + ($name:expr) => { + assert!( + $name.is_none(), + "setting {} is incompatible with download-ci-llvm.", + stringify!($name).replace("_", "-") + ); + }; +} + +pub(crate) trait Merge { + fn merge( + &mut self, + parent_config_path: Option, + included_extensions: &mut HashSet, + other: Self, + replace: ReplaceOpt, + ); +} + +impl Merge for Option { + fn merge( + &mut self, + _parent_config_path: Option, + _included_extensions: &mut HashSet, + other: Self, + replace: ReplaceOpt, + ) { + match replace { + ReplaceOpt::IgnoreDuplicate => { + if self.is_none() { + *self = other; + } + } + ReplaceOpt::Override => { + if other.is_some() { + *self = other; + } + } + ReplaceOpt::ErrorOnDuplicate => { + if other.is_some() { + if self.is_some() { + if cfg!(test) { + panic!("overriding existing option") + } else { + eprintln!("overriding existing option"); + exit!(2); + } + } else { + *self = other; + } + } + } + } + } +} + +#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)] +pub enum DebuginfoLevel { + #[default] + None, + LineDirectivesOnly, + LineTablesOnly, + Limited, + Full, +} + +// NOTE: can't derive(Deserialize) because the intermediate trip through toml::Value only +// deserializes i64, and derive() only generates visit_u64 +impl<'de> Deserialize<'de> for DebuginfoLevel { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de::Error; + + Ok(match Deserialize::deserialize(deserializer)? { + StringOrInt::String(s) if s == "none" => DebuginfoLevel::None, + StringOrInt::Int(0) => DebuginfoLevel::None, + StringOrInt::String(s) if s == "line-directives-only" => { + DebuginfoLevel::LineDirectivesOnly + } + StringOrInt::String(s) if s == "line-tables-only" => DebuginfoLevel::LineTablesOnly, + StringOrInt::String(s) if s == "limited" => DebuginfoLevel::Limited, + StringOrInt::Int(1) => DebuginfoLevel::Limited, + StringOrInt::String(s) if s == "full" => DebuginfoLevel::Full, + StringOrInt::Int(2) => DebuginfoLevel::Full, + StringOrInt::Int(n) => { + let other = serde::de::Unexpected::Signed(n); + return Err(D::Error::invalid_value(other, &"expected 0, 1, or 2")); + } + StringOrInt::String(s) => { + let other = serde::de::Unexpected::Str(&s); + return Err(D::Error::invalid_value( + other, + &"expected none, line-tables-only, limited, or full", + )); + } + }) + } +} + +/// Suitable for passing to `-C debuginfo` +impl Display for DebuginfoLevel { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use DebuginfoLevel::*; + f.write_str(match self { + None => "0", + LineDirectivesOnly => "line-directives-only", + LineTablesOnly => "line-tables-only", + Limited => "1", + Full => "2", + }) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq)] +#[serde(untagged)] +pub enum StringOrBool { + String(String), + Bool(bool), +} + +impl Default for StringOrBool { + fn default() -> StringOrBool { + StringOrBool::Bool(false) + } +} + +impl StringOrBool { + pub fn is_string_or_true(&self) -> bool { + matches!(self, Self::String(_) | Self::Bool(true)) + } +} + +#[derive(Deserialize)] +#[serde(untagged)] +pub enum StringOrInt { + String(String), + Int(i64), +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +pub enum LlvmLibunwind { + #[default] + No, + InTree, + System, +} + +impl FromStr for LlvmLibunwind { + type Err = String; + + fn from_str(value: &str) -> Result { + match value { + "no" => Ok(Self::No), + "in-tree" => Ok(Self::InTree), + "system" => Ok(Self::System), + invalid => Err(format!("Invalid value '{invalid}' for rust.llvm-libunwind config.")), + } + } +} + +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum SplitDebuginfo { + Packed, + Unpacked, + #[default] + Off, +} + +impl std::str::FromStr for SplitDebuginfo { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "packed" => Ok(SplitDebuginfo::Packed), + "unpacked" => Ok(SplitDebuginfo::Unpacked), + "off" => Ok(SplitDebuginfo::Off), + _ => Err(()), + } + } +} + +/// Describes how to handle conflicts in merging two [`TomlConfig`] +#[derive(Copy, Clone, Debug)] +pub enum ReplaceOpt { + /// Silently ignore a duplicated value + IgnoreDuplicate, + /// Override the current value, even if it's `Some` + Override, + /// Exit with an error on duplicate values + ErrorOnDuplicate, +} + +#[derive(Clone, Default)] +pub enum DryRun { + /// This isn't a dry run. + #[default] + Disabled, + /// This is a dry run enabled by bootstrap itself, so it can verify that no work is done. + SelfCheck, + /// This is a dry run enabled by the `--dry-run` flag. + UserSelected, +} + +/// LTO mode used for compiling rustc itself. +#[derive(Default, Clone, PartialEq, Debug)] +pub enum RustcLto { + Off, + #[default] + ThinLocal, + Thin, + Fat, +} + +impl std::str::FromStr for RustcLto { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "thin-local" => Ok(RustcLto::ThinLocal), + "thin" => Ok(RustcLto::Thin), + "fat" => Ok(RustcLto::Fat), + "off" => Ok(RustcLto::Off), + _ => Err(format!("Invalid value for rustc LTO: {s}")), + } + } +} + +/// Determines how will GCC be provided. +#[derive(Default, Clone)] +pub enum GccCiMode { + /// Build GCC from the local `src/gcc` submodule. + #[default] + BuildLocally, + /// Try to download GCC from CI. + /// If it is not available on CI, it will be built locally instead. + DownloadFromCi, +} + +pub fn set(field: &mut T, val: Option) { + if let Some(v) = val { + *field = v; + } +} + +pub fn threads_from_config(v: u32) -> u32 { + match v { + 0 => std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32, + n => n, + } +} -- cgit 1.4.1-3-g733a5 From edada367a0a8cd19148e4abc4072ce4ed61ab10d Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 3 Jun 2025 13:53:05 +0530 Subject: add config.rs with new module structuring --- src/bootstrap/src/core/config/config.rs | 2124 ++----------------------------- 1 file changed, 132 insertions(+), 1992 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 899ffde8adf..90c9e20197a 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1,36 +1,56 @@ -//! Serialized configuration of a build. +//! This module defines the central `Config` struct, which aggregates all components +//! of the bootstrap configuration into a single unit. //! -//! This module implements parsing `bootstrap.toml` configuration files to tweak -//! how the build runs. +//! It serves as the primary public interface for accessing the bootstrap configuration. +//! The module coordinates the overall configuration parsing process using logic from `parsing.rs` +//! and provides top-level methods such as `Config::parse()` for initialization, as well as +//! utility methods for querying and manipulating the complete configuration state. +//! +//! Additionally, this module contains the core logic for parsing, validating, and inferring +//! the final `Config` from various raw inputs. +//! +//! It manages the process of reading command-line arguments, environment variables, +//! and the `bootstrap.toml` file—merging them, applying defaults, and performing +//! cross-component validation. The main `parse_inner` function and its supporting +//! helpers reside here, transforming raw `Toml` data into the structured `Config` type. use std::cell::Cell; use std::collections::{BTreeSet, HashMap, HashSet}; -use std::fmt::{self, Display}; -use std::hash::Hash; use std::io::IsTerminal; use std::path::{Path, PathBuf, absolute}; -use std::process::Command; use std::str::FromStr; -use std::sync::{Arc, Mutex, OnceLock}; +use std::sync::{Arc, Mutex}; use std::{cmp, env, fs}; use build_helper::ci::CiEnv; use build_helper::exit; use build_helper::git::{GitConfig, PathFreshness, check_path_modifications, output_result}; -use serde::{Deserialize, Deserializer}; -use serde_derive::Deserialize; +use serde::Deserialize; +#[cfg(feature = "tracing")] +use tracing::{instrument, span}; #[cfg(feature = "tracing")] use tracing::{instrument, span}; -use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; use crate::core::build_steps::llvm; use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS; pub use crate::core::config::flags::Subcommand; -use crate::core::config::flags::{Color, Flags, Warnings}; +use crate::core::config::flags::{Color, Flags}; +use crate::core::config::target_selection::TargetSelectionList; +use crate::core::config::toml::TomlConfig; +use crate::core::config::toml::build::Build; +use crate::core::config::toml::change_id::ChangeId; +use crate::core::config::toml::rust::{ + LldMode, RustOptimize, check_incompatible_options_for_ci_rustc, +}; +use crate::core::config::toml::target::Target; +use crate::core::config::{ + DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, RustcLto, SplitDebuginfo, + StringOrBool, set, threads_from_config, +}; use crate::core::download::is_download_ci_available; -use crate::utils::cache::{INTERNER, Interned}; -use crate::utils::channel::{self, GitInfo}; -use crate::utils::helpers::{self, exe, output, t}; +use crate::utils::channel; +use crate::utils::helpers::exe; +use crate::{Command, GitInfo, OnceLock, TargetSelection, check_ci_llvm, helpers, output, t}; /// Each path in this list is considered "allowed" in the `download-rustc="if-unchanged"` logic. /// This means they can be modified and changes to these paths should never trigger a compiler build @@ -44,7 +64,7 @@ use crate::utils::helpers::{self, exe, output, t}; /// For example, "src/bootstrap" should never be included in this list as it plays a crucial role in the /// final output/compiler, which can be significantly affected by changes made to the bootstrap sources. #[rustfmt::skip] // We don't want rustfmt to oneline this list -pub(crate) const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[ +pub const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[ ":!library", ":!src/tools", ":!src/librustdoc", @@ -53,138 +73,6 @@ pub(crate) const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[ ":!triagebot.toml", ]; -macro_rules! check_ci_llvm { - ($name:expr) => { - assert!( - $name.is_none(), - "setting {} is incompatible with download-ci-llvm.", - stringify!($name).replace("_", "-") - ); - }; -} - -/// This file is embedded in the overlay directory of the tarball sources. It is -/// useful in scenarios where developers want to see how the tarball sources were -/// generated. -/// -/// We also use this file to compare the host's bootstrap.toml against the CI rustc builder -/// configuration to detect any incompatible options. -pub(crate) const BUILDER_CONFIG_FILENAME: &str = "builder-config"; - -#[derive(Clone, Default)] -pub enum DryRun { - /// This isn't a dry run. - #[default] - Disabled, - /// This is a dry run enabled by bootstrap itself, so it can verify that no work is done. - SelfCheck, - /// This is a dry run enabled by the `--dry-run` flag. - UserSelected, -} - -#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)] -pub enum DebuginfoLevel { - #[default] - None, - LineDirectivesOnly, - LineTablesOnly, - Limited, - Full, -} - -// NOTE: can't derive(Deserialize) because the intermediate trip through toml::Value only -// deserializes i64, and derive() only generates visit_u64 -impl<'de> Deserialize<'de> for DebuginfoLevel { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - use serde::de::Error; - - Ok(match Deserialize::deserialize(deserializer)? { - StringOrInt::String(s) if s == "none" => DebuginfoLevel::None, - StringOrInt::Int(0) => DebuginfoLevel::None, - StringOrInt::String(s) if s == "line-directives-only" => { - DebuginfoLevel::LineDirectivesOnly - } - StringOrInt::String(s) if s == "line-tables-only" => DebuginfoLevel::LineTablesOnly, - StringOrInt::String(s) if s == "limited" => DebuginfoLevel::Limited, - StringOrInt::Int(1) => DebuginfoLevel::Limited, - StringOrInt::String(s) if s == "full" => DebuginfoLevel::Full, - StringOrInt::Int(2) => DebuginfoLevel::Full, - StringOrInt::Int(n) => { - let other = serde::de::Unexpected::Signed(n); - return Err(D::Error::invalid_value(other, &"expected 0, 1, or 2")); - } - StringOrInt::String(s) => { - let other = serde::de::Unexpected::Str(&s); - return Err(D::Error::invalid_value( - other, - &"expected none, line-tables-only, limited, or full", - )); - } - }) - } -} - -/// Suitable for passing to `-C debuginfo` -impl Display for DebuginfoLevel { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use DebuginfoLevel::*; - f.write_str(match self { - None => "0", - LineDirectivesOnly => "line-directives-only", - LineTablesOnly => "line-tables-only", - Limited => "1", - Full => "2", - }) - } -} - -/// LLD in bootstrap works like this: -/// - Self-contained lld: use `rust-lld` from the compiler's sysroot -/// - External: use an external `lld` binary -/// -/// It is configured depending on the target: -/// 1) Everything except MSVC -/// - Self-contained: `-Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker` -/// - External: `-Clinker-flavor=gnu-lld-cc` -/// 2) MSVC -/// - Self-contained: `-Clinker=` -/// - External: `-Clinker=lld` -#[derive(Copy, Clone, Default, Debug, PartialEq)] -pub enum LldMode { - /// Do not use LLD - #[default] - Unused, - /// Use `rust-lld` from the compiler's sysroot - SelfContained, - /// Use an externally provided `lld` binary. - /// Note that the linker name cannot be overridden, the binary has to be named `lld` and it has - /// to be in $PATH. - External, -} - -impl LldMode { - pub fn is_used(&self) -> bool { - match self { - LldMode::SelfContained | LldMode::External => true, - LldMode::Unused => false, - } - } -} - -/// Determines how will GCC be provided. -#[derive(Default, Clone)] -pub enum GccCiMode { - /// Build GCC from the local `src/gcc` submodule. - #[default] - BuildLocally, - /// Try to download GCC from CI. - /// If it is not available on CI, it will be built locally instead. - DownloadFromCi, -} - /// Global configuration for the entire build and/or bootstrap. /// /// This structure is parsed from `bootstrap.toml`, and some of the fields are inferred from `git` or build-time parameters. @@ -250,9 +138,6 @@ pub struct Config { pub free_args: Vec, /// `None` if we shouldn't download CI compiler artifacts, or the commit to download if we should. - #[cfg(not(test))] - download_rustc_commit: Option, - #[cfg(test)] pub download_rustc_commit: Option, pub deny_warnings: bool, @@ -269,10 +154,6 @@ pub struct Config { pub llvm_release_debuginfo: bool, pub llvm_static_stdcpp: bool, pub llvm_libzstd: bool, - /// `None` if `llvm_from_ci` is true and we haven't yet downloaded llvm. - #[cfg(not(test))] - llvm_link_shared: Cell>, - #[cfg(test)] pub llvm_link_shared: Cell>, pub llvm_clang_cl: Option, pub llvm_targets: Option, @@ -345,9 +226,6 @@ pub struct Config { pub hosts: Vec, pub targets: Vec, pub local_rebuild: bool, - #[cfg(not(test))] - jemalloc: bool, - #[cfg(test)] pub jemalloc: bool, pub control_flow_guard: bool, pub ehcont_guard: bool, @@ -425,932 +303,6 @@ pub struct Config { pub path_modification_cache: Arc, PathFreshness>>>, } -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] -pub enum LlvmLibunwind { - #[default] - No, - InTree, - System, -} - -impl FromStr for LlvmLibunwind { - type Err = String; - - fn from_str(value: &str) -> Result { - match value { - "no" => Ok(Self::No), - "in-tree" => Ok(Self::InTree), - "system" => Ok(Self::System), - invalid => Err(format!("Invalid value '{invalid}' for rust.llvm-libunwind config.")), - } - } -} - -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum SplitDebuginfo { - Packed, - Unpacked, - #[default] - Off, -} - -impl std::str::FromStr for SplitDebuginfo { - type Err = (); - - fn from_str(s: &str) -> Result { - match s { - "packed" => Ok(SplitDebuginfo::Packed), - "unpacked" => Ok(SplitDebuginfo::Unpacked), - "off" => Ok(SplitDebuginfo::Off), - _ => Err(()), - } - } -} - -impl SplitDebuginfo { - /// Returns the default `-Csplit-debuginfo` value for the current target. See the comment for - /// `rust.split-debuginfo` in `bootstrap.example.toml`. - fn default_for_platform(target: TargetSelection) -> Self { - if target.contains("apple") { - SplitDebuginfo::Unpacked - } else if target.is_windows() { - SplitDebuginfo::Packed - } else { - SplitDebuginfo::Off - } - } -} - -/// LTO mode used for compiling rustc itself. -#[derive(Default, Clone, PartialEq, Debug)] -pub enum RustcLto { - Off, - #[default] - ThinLocal, - Thin, - Fat, -} - -impl std::str::FromStr for RustcLto { - type Err = String; - - fn from_str(s: &str) -> Result { - match s { - "thin-local" => Ok(RustcLto::ThinLocal), - "thin" => Ok(RustcLto::Thin), - "fat" => Ok(RustcLto::Fat), - "off" => Ok(RustcLto::Off), - _ => Err(format!("Invalid value for rustc LTO: {s}")), - } - } -} - -#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -// N.B.: This type is used everywhere, and the entire codebase relies on it being Copy. -// Making !Copy is highly nontrivial! -pub struct TargetSelection { - pub triple: Interned, - file: Option>, - synthetic: bool, -} - -/// Newtype over `Vec` so we can implement custom parsing logic -#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub struct TargetSelectionList(Vec); - -pub fn target_selection_list(s: &str) -> Result { - Ok(TargetSelectionList( - s.split(',').filter(|s| !s.is_empty()).map(TargetSelection::from_user).collect(), - )) -} - -impl TargetSelection { - pub fn from_user(selection: &str) -> Self { - let path = Path::new(selection); - - let (triple, file) = if path.exists() { - let triple = path - .file_stem() - .expect("Target specification file has no file stem") - .to_str() - .expect("Target specification file stem is not UTF-8"); - - (triple, Some(selection)) - } else { - (selection, None) - }; - - let triple = INTERNER.intern_str(triple); - let file = file.map(|f| INTERNER.intern_str(f)); - - Self { triple, file, synthetic: false } - } - - pub fn create_synthetic(triple: &str, file: &str) -> Self { - Self { - triple: INTERNER.intern_str(triple), - file: Some(INTERNER.intern_str(file)), - synthetic: true, - } - } - - pub fn rustc_target_arg(&self) -> &str { - self.file.as_ref().unwrap_or(&self.triple) - } - - pub fn contains(&self, needle: &str) -> bool { - self.triple.contains(needle) - } - - pub fn starts_with(&self, needle: &str) -> bool { - self.triple.starts_with(needle) - } - - pub fn ends_with(&self, needle: &str) -> bool { - self.triple.ends_with(needle) - } - - // See src/bootstrap/synthetic_targets.rs - pub fn is_synthetic(&self) -> bool { - self.synthetic - } - - pub fn is_msvc(&self) -> bool { - self.contains("msvc") - } - - pub fn is_windows(&self) -> bool { - self.contains("windows") - } - - pub fn is_windows_gnu(&self) -> bool { - self.ends_with("windows-gnu") - } - - pub fn is_cygwin(&self) -> bool { - self.is_windows() && - // ref. https://cygwin.com/pipermail/cygwin/2022-February/250802.html - env::var("OSTYPE").is_ok_and(|v| v.to_lowercase().contains("cygwin")) - } - - pub fn needs_crt_begin_end(&self) -> bool { - self.contains("musl") && !self.contains("unikraft") - } - - /// Path to the file defining the custom target, if any. - pub fn filepath(&self) -> Option<&Path> { - self.file.as_ref().map(Path::new) - } -} - -impl fmt::Display for TargetSelection { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.triple)?; - if let Some(file) = self.file { - write!(f, "({file})")?; - } - Ok(()) - } -} - -impl fmt::Debug for TargetSelection { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{self}") - } -} - -impl PartialEq<&str> for TargetSelection { - fn eq(&self, other: &&str) -> bool { - self.triple == *other - } -} - -// Targets are often used as directory names throughout bootstrap. -// This impl makes it more ergonomics to use them as such. -impl AsRef for TargetSelection { - fn as_ref(&self) -> &Path { - self.triple.as_ref() - } -} - -/// Per-target configuration stored in the global configuration structure. -#[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct Target { - /// Some(path to llvm-config) if using an external LLVM. - pub llvm_config: Option, - pub llvm_has_rust_patches: Option, - /// Some(path to FileCheck) if one was specified. - pub llvm_filecheck: Option, - pub llvm_libunwind: Option, - pub cc: Option, - pub cxx: Option, - pub ar: Option, - pub ranlib: Option, - pub default_linker: Option, - pub linker: Option, - pub split_debuginfo: Option, - pub sanitizers: Option, - pub profiler: Option, - pub rpath: Option, - pub crt_static: Option, - pub musl_root: Option, - pub musl_libdir: Option, - pub wasi_root: Option, - pub qemu_rootfs: Option, - pub runner: Option, - pub no_std: bool, - pub codegen_backends: Option>, - pub optimized_compiler_builtins: Option, - pub jemalloc: Option, -} - -impl Target { - pub fn from_triple(triple: &str) -> Self { - let mut target: Self = Default::default(); - if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") { - target.no_std = true; - } - if triple.contains("emscripten") { - target.runner = Some("node".into()); - } - target - } -} -/// Structure of the `bootstrap.toml` file that configuration is read from. -/// -/// This structure uses `Decodable` to automatically decode a TOML configuration -/// file into this format, and then this is traversed and written into the above -/// `Config` structure. -#[derive(Deserialize, Default)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] -pub(crate) struct TomlConfig { - #[serde(flatten)] - change_id: ChangeIdWrapper, - build: Option, - install: Option, - llvm: Option, - gcc: Option, - rust: Option, - target: Option>, - dist: Option, - profile: Option, - include: Option>, -} - -/// This enum is used for deserializing change IDs from TOML, allowing both numeric values and the string `"ignore"`. -#[derive(Clone, Debug, PartialEq)] -pub enum ChangeId { - Ignore, - Id(usize), -} - -/// Since we use `#[serde(deny_unknown_fields)]` on `TomlConfig`, we need a wrapper type -/// for the "change-id" field to parse it even if other fields are invalid. This ensures -/// that if deserialization fails due to other fields, we can still provide the changelogs -/// to allow developers to potentially find the reason for the failure in the logs.. -#[derive(Deserialize, Default)] -pub(crate) struct ChangeIdWrapper { - #[serde(alias = "change-id", default, deserialize_with = "deserialize_change_id")] - pub(crate) inner: Option, -} - -fn deserialize_change_id<'de, D: Deserializer<'de>>( - deserializer: D, -) -> Result, D::Error> { - let value = toml::Value::deserialize(deserializer)?; - Ok(match value { - toml::Value::String(s) if s == "ignore" => Some(ChangeId::Ignore), - toml::Value::Integer(i) => Some(ChangeId::Id(i as usize)), - _ => { - return Err(serde::de::Error::custom( - "expected \"ignore\" or an integer for change-id", - )); - } - }) -} - -/// Describes how to handle conflicts in merging two [`TomlConfig`] -#[derive(Copy, Clone, Debug)] -enum ReplaceOpt { - /// Silently ignore a duplicated value - IgnoreDuplicate, - /// Override the current value, even if it's `Some` - Override, - /// Exit with an error on duplicate values - ErrorOnDuplicate, -} - -trait Merge { - fn merge( - &mut self, - parent_config_path: Option, - included_extensions: &mut HashSet, - other: Self, - replace: ReplaceOpt, - ); -} - -impl Merge for TomlConfig { - fn merge( - &mut self, - parent_config_path: Option, - included_extensions: &mut HashSet, - TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id, include }: Self, - replace: ReplaceOpt, - ) { - fn do_merge(x: &mut Option, y: Option, replace: ReplaceOpt) { - if let Some(new) = y { - if let Some(original) = x { - original.merge(None, &mut Default::default(), new, replace); - } else { - *x = Some(new); - } - } - } - - self.change_id.inner.merge(None, &mut Default::default(), change_id.inner, replace); - self.profile.merge(None, &mut Default::default(), profile, replace); - - do_merge(&mut self.build, build, replace); - do_merge(&mut self.install, install, replace); - do_merge(&mut self.llvm, llvm, replace); - do_merge(&mut self.gcc, gcc, replace); - do_merge(&mut self.rust, rust, replace); - do_merge(&mut self.dist, dist, replace); - - match (self.target.as_mut(), target) { - (_, None) => {} - (None, Some(target)) => self.target = Some(target), - (Some(original_target), Some(new_target)) => { - for (triple, new) in new_target { - if let Some(original) = original_target.get_mut(&triple) { - original.merge(None, &mut Default::default(), new, replace); - } else { - original_target.insert(triple, new); - } - } - } - } - - let parent_dir = parent_config_path - .as_ref() - .and_then(|p| p.parent().map(ToOwned::to_owned)) - .unwrap_or_default(); - - // `include` handled later since we ignore duplicates using `ReplaceOpt::IgnoreDuplicate` to - // keep the upper-level configuration to take precedence. - for include_path in include.clone().unwrap_or_default().iter().rev() { - let include_path = parent_dir.join(include_path); - let include_path = include_path.canonicalize().unwrap_or_else(|e| { - eprintln!("ERROR: Failed to canonicalize '{}' path: {e}", include_path.display()); - exit!(2); - }); - - let included_toml = Config::get_toml_inner(&include_path).unwrap_or_else(|e| { - eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display()); - exit!(2); - }); - - assert!( - included_extensions.insert(include_path.clone()), - "Cyclic inclusion detected: '{}' is being included again before its previous inclusion was fully processed.", - include_path.display() - ); - - self.merge( - Some(include_path.clone()), - included_extensions, - included_toml, - // Ensures that parent configuration always takes precedence - // over child configurations. - ReplaceOpt::IgnoreDuplicate, - ); - - included_extensions.remove(&include_path); - } - } -} - -// We are using a decl macro instead of a derive proc macro here to reduce the compile time of bootstrap. -macro_rules! define_config { - ($(#[$attr:meta])* struct $name:ident { - $($field:ident: Option<$field_ty:ty> = $field_key:literal,)* - }) => { - $(#[$attr])* - struct $name { - $($field: Option<$field_ty>,)* - } - - impl Merge for $name { - fn merge( - &mut self, - _parent_config_path: Option, - _included_extensions: &mut HashSet, - other: Self, - replace: ReplaceOpt - ) { - $( - match replace { - ReplaceOpt::IgnoreDuplicate => { - if self.$field.is_none() { - self.$field = other.$field; - } - }, - ReplaceOpt::Override => { - if other.$field.is_some() { - self.$field = other.$field; - } - } - ReplaceOpt::ErrorOnDuplicate => { - if other.$field.is_some() { - if self.$field.is_some() { - if cfg!(test) { - panic!("overriding existing option") - } else { - eprintln!("overriding existing option: `{}`", stringify!($field)); - exit!(2); - } - } else { - self.$field = other.$field; - } - } - } - } - )* - } - } - - // The following is a trimmed version of what serde_derive generates. All parts not relevant - // for toml deserialization have been removed. This reduces the binary size and improves - // compile time of bootstrap. - impl<'de> Deserialize<'de> for $name { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct Field; - impl<'de> serde::de::Visitor<'de> for Field { - type Value = $name; - fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(concat!("struct ", stringify!($name))) - } - - #[inline] - fn visit_map(self, mut map: A) -> Result - where - A: serde::de::MapAccess<'de>, - { - $(let mut $field: Option<$field_ty> = None;)* - while let Some(key) = - match serde::de::MapAccess::next_key::(&mut map) { - Ok(val) => val, - Err(err) => { - return Err(err); - } - } - { - match &*key { - $($field_key => { - if $field.is_some() { - return Err(::duplicate_field( - $field_key, - )); - } - $field = match serde::de::MapAccess::next_value::<$field_ty>( - &mut map, - ) { - Ok(val) => Some(val), - Err(err) => { - return Err(err); - } - }; - })* - key => { - return Err(serde::de::Error::unknown_field(key, FIELDS)); - } - } - } - Ok($name { $($field),* }) - } - } - const FIELDS: &'static [&'static str] = &[ - $($field_key,)* - ]; - Deserializer::deserialize_struct( - deserializer, - stringify!($name), - FIELDS, - Field, - ) - } - } - } -} - -impl Merge for Option { - fn merge( - &mut self, - _parent_config_path: Option, - _included_extensions: &mut HashSet, - other: Self, - replace: ReplaceOpt, - ) { - match replace { - ReplaceOpt::IgnoreDuplicate => { - if self.is_none() { - *self = other; - } - } - ReplaceOpt::Override => { - if other.is_some() { - *self = other; - } - } - ReplaceOpt::ErrorOnDuplicate => { - if other.is_some() { - if self.is_some() { - if cfg!(test) { - panic!("overriding existing option") - } else { - eprintln!("overriding existing option"); - exit!(2); - } - } else { - *self = other; - } - } - } - } - } -} - -define_config! { - /// TOML representation of various global build decisions. - #[derive(Default)] - struct Build { - build: Option = "build", - description: Option = "description", - host: Option> = "host", - target: Option> = "target", - build_dir: Option = "build-dir", - cargo: Option = "cargo", - rustc: Option = "rustc", - rustfmt: Option = "rustfmt", - cargo_clippy: Option = "cargo-clippy", - docs: Option = "docs", - compiler_docs: Option = "compiler-docs", - library_docs_private_items: Option = "library-docs-private-items", - docs_minification: Option = "docs-minification", - submodules: Option = "submodules", - gdb: Option = "gdb", - lldb: Option = "lldb", - nodejs: Option = "nodejs", - npm: Option = "npm", - python: Option = "python", - reuse: Option = "reuse", - locked_deps: Option = "locked-deps", - vendor: Option = "vendor", - full_bootstrap: Option = "full-bootstrap", - bootstrap_cache_path: Option = "bootstrap-cache-path", - extended: Option = "extended", - tools: Option> = "tools", - verbose: Option = "verbose", - sanitizers: Option = "sanitizers", - profiler: Option = "profiler", - cargo_native_static: Option = "cargo-native-static", - low_priority: Option = "low-priority", - configure_args: Option> = "configure-args", - local_rebuild: Option = "local-rebuild", - print_step_timings: Option = "print-step-timings", - print_step_rusage: Option = "print-step-rusage", - check_stage: Option = "check-stage", - doc_stage: Option = "doc-stage", - build_stage: Option = "build-stage", - test_stage: Option = "test-stage", - install_stage: Option = "install-stage", - dist_stage: Option = "dist-stage", - bench_stage: Option = "bench-stage", - patch_binaries_for_nix: Option = "patch-binaries-for-nix", - // NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally - metrics: Option = "metrics", - android_ndk: Option = "android-ndk", - optimized_compiler_builtins: Option = "optimized-compiler-builtins", - jobs: Option = "jobs", - compiletest_diff_tool: Option = "compiletest-diff-tool", - compiletest_use_stage0_libtest: Option = "compiletest-use-stage0-libtest", - ccache: Option = "ccache", - exclude: Option> = "exclude", - } -} - -define_config! { - /// TOML representation of various global install decisions. - struct Install { - prefix: Option = "prefix", - sysconfdir: Option = "sysconfdir", - docdir: Option = "docdir", - bindir: Option = "bindir", - libdir: Option = "libdir", - mandir: Option = "mandir", - datadir: Option = "datadir", - } -} - -define_config! { - /// TOML representation of how the LLVM build is configured. - struct Llvm { - optimize: Option = "optimize", - thin_lto: Option = "thin-lto", - release_debuginfo: Option = "release-debuginfo", - assertions: Option = "assertions", - tests: Option = "tests", - enzyme: Option = "enzyme", - plugins: Option = "plugins", - // FIXME: Remove this field at Q2 2025, it has been replaced by build.ccache - ccache: Option = "ccache", - static_libstdcpp: Option = "static-libstdcpp", - libzstd: Option = "libzstd", - ninja: Option = "ninja", - targets: Option = "targets", - experimental_targets: Option = "experimental-targets", - link_jobs: Option = "link-jobs", - link_shared: Option = "link-shared", - version_suffix: Option = "version-suffix", - clang_cl: Option = "clang-cl", - cflags: Option = "cflags", - cxxflags: Option = "cxxflags", - ldflags: Option = "ldflags", - use_libcxx: Option = "use-libcxx", - use_linker: Option = "use-linker", - allow_old_toolchain: Option = "allow-old-toolchain", - offload: Option = "offload", - polly: Option = "polly", - clang: Option = "clang", - enable_warnings: Option = "enable-warnings", - download_ci_llvm: Option = "download-ci-llvm", - build_config: Option> = "build-config", - } -} - -define_config! { - /// TOML representation of how the GCC build is configured. - struct Gcc { - download_ci_gcc: Option = "download-ci-gcc", - } -} - -define_config! { - struct Dist { - sign_folder: Option = "sign-folder", - upload_addr: Option = "upload-addr", - src_tarball: Option = "src-tarball", - compression_formats: Option> = "compression-formats", - compression_profile: Option = "compression-profile", - include_mingw_linker: Option = "include-mingw-linker", - vendor: Option = "vendor", - } -} - -#[derive(Clone, Debug, Deserialize, PartialEq, Eq)] -#[serde(untagged)] -pub enum StringOrBool { - String(String), - Bool(bool), -} - -impl Default for StringOrBool { - fn default() -> StringOrBool { - StringOrBool::Bool(false) - } -} - -impl StringOrBool { - fn is_string_or_true(&self) -> bool { - matches!(self, Self::String(_) | Self::Bool(true)) - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum RustOptimize { - String(String), - Int(u8), - Bool(bool), -} - -impl Default for RustOptimize { - fn default() -> RustOptimize { - RustOptimize::Bool(false) - } -} - -impl<'de> Deserialize<'de> for RustOptimize { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_any(OptimizeVisitor) - } -} - -struct OptimizeVisitor; - -impl serde::de::Visitor<'_> for OptimizeVisitor { - type Value = RustOptimize; - - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str(r#"one of: 0, 1, 2, 3, "s", "z", true, false"#) - } - - fn visit_str(self, value: &str) -> Result - where - E: serde::de::Error, - { - if matches!(value, "s" | "z") { - Ok(RustOptimize::String(value.to_string())) - } else { - Err(serde::de::Error::custom(format_optimize_error_msg(value))) - } - } - - fn visit_i64(self, value: i64) -> Result - where - E: serde::de::Error, - { - if matches!(value, 0..=3) { - Ok(RustOptimize::Int(value as u8)) - } else { - Err(serde::de::Error::custom(format_optimize_error_msg(value))) - } - } - - fn visit_bool(self, value: bool) -> Result - where - E: serde::de::Error, - { - Ok(RustOptimize::Bool(value)) - } -} - -fn format_optimize_error_msg(v: impl std::fmt::Display) -> String { - format!( - r#"unrecognized option for rust optimize: "{v}", expected one of 0, 1, 2, 3, "s", "z", true, false"# - ) -} - -impl RustOptimize { - pub(crate) fn is_release(&self) -> bool { - match &self { - RustOptimize::Bool(true) | RustOptimize::String(_) => true, - RustOptimize::Int(i) => *i > 0, - RustOptimize::Bool(false) => false, - } - } - - pub(crate) fn get_opt_level(&self) -> Option { - match &self { - RustOptimize::String(s) => Some(s.clone()), - RustOptimize::Int(i) => Some(i.to_string()), - RustOptimize::Bool(_) => None, - } - } -} - -#[derive(Deserialize)] -#[serde(untagged)] -enum StringOrInt { - String(String), - Int(i64), -} - -impl<'de> Deserialize<'de> for LldMode { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct LldModeVisitor; - - impl serde::de::Visitor<'_> for LldModeVisitor { - type Value = LldMode; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("one of true, 'self-contained' or 'external'") - } - - fn visit_bool(self, v: bool) -> Result - where - E: serde::de::Error, - { - Ok(if v { LldMode::External } else { LldMode::Unused }) - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - match v { - "external" => Ok(LldMode::External), - "self-contained" => Ok(LldMode::SelfContained), - _ => Err(E::custom(format!("unknown mode {v}"))), - } - } - } - - deserializer.deserialize_any(LldModeVisitor) - } -} - -define_config! { - /// TOML representation of how the Rust build is configured. - struct Rust { - optimize: Option = "optimize", - debug: Option = "debug", - codegen_units: Option = "codegen-units", - codegen_units_std: Option = "codegen-units-std", - rustc_debug_assertions: Option = "debug-assertions", - randomize_layout: Option = "randomize-layout", - std_debug_assertions: Option = "debug-assertions-std", - tools_debug_assertions: Option = "debug-assertions-tools", - overflow_checks: Option = "overflow-checks", - overflow_checks_std: Option = "overflow-checks-std", - debug_logging: Option = "debug-logging", - debuginfo_level: Option = "debuginfo-level", - debuginfo_level_rustc: Option = "debuginfo-level-rustc", - debuginfo_level_std: Option = "debuginfo-level-std", - debuginfo_level_tools: Option = "debuginfo-level-tools", - debuginfo_level_tests: Option = "debuginfo-level-tests", - backtrace: Option = "backtrace", - incremental: Option = "incremental", - default_linker: Option = "default-linker", - channel: Option = "channel", - // FIXME: Remove this field at Q2 2025, it has been replaced by build.description - description: Option = "description", - musl_root: Option = "musl-root", - rpath: Option = "rpath", - strip: Option = "strip", - frame_pointers: Option = "frame-pointers", - stack_protector: Option = "stack-protector", - verbose_tests: Option = "verbose-tests", - optimize_tests: Option = "optimize-tests", - codegen_tests: Option = "codegen-tests", - omit_git_hash: Option = "omit-git-hash", - dist_src: Option = "dist-src", - save_toolstates: Option = "save-toolstates", - codegen_backends: Option> = "codegen-backends", - llvm_bitcode_linker: Option = "llvm-bitcode-linker", - lld: Option = "lld", - lld_mode: Option = "use-lld", - llvm_tools: Option = "llvm-tools", - deny_warnings: Option = "deny-warnings", - backtrace_on_ice: Option = "backtrace-on-ice", - verify_llvm_ir: Option = "verify-llvm-ir", - thin_lto_import_instr_limit: Option = "thin-lto-import-instr-limit", - remap_debuginfo: Option = "remap-debuginfo", - jemalloc: Option = "jemalloc", - test_compare_mode: Option = "test-compare-mode", - llvm_libunwind: Option = "llvm-libunwind", - control_flow_guard: Option = "control-flow-guard", - ehcont_guard: Option = "ehcont-guard", - new_symbol_mangling: Option = "new-symbol-mangling", - profile_generate: Option = "profile-generate", - profile_use: Option = "profile-use", - // ignored; this is set from an env var set by bootstrap.py - download_rustc: Option = "download-rustc", - lto: Option = "lto", - validate_mir_opts: Option = "validate-mir-opts", - std_features: Option> = "std-features", - } -} - -define_config! { - /// TOML representation of how each build target is configured. - struct TomlTarget { - cc: Option = "cc", - cxx: Option = "cxx", - ar: Option = "ar", - ranlib: Option = "ranlib", - default_linker: Option = "default-linker", - linker: Option = "linker", - split_debuginfo: Option = "split-debuginfo", - llvm_config: Option = "llvm-config", - llvm_has_rust_patches: Option = "llvm-has-rust-patches", - llvm_filecheck: Option = "llvm-filecheck", - llvm_libunwind: Option = "llvm-libunwind", - sanitizers: Option = "sanitizers", - profiler: Option = "profiler", - rpath: Option = "rpath", - crt_static: Option = "crt-static", - musl_root: Option = "musl-root", - musl_libdir: Option = "musl-libdir", - wasi_root: Option = "wasi-root", - qemu_rootfs: Option = "qemu-rootfs", - no_std: Option = "no-std", - codegen_backends: Option> = "codegen-backends", - runner: Option = "runner", - optimized_compiler_builtins: Option = "optimized-compiler-builtins", - jemalloc: Option = "jemalloc", - } -} - impl Config { #[cfg_attr( feature = "tracing", @@ -1405,47 +357,6 @@ impl Config { } } - pub(crate) fn get_builder_toml(&self, build_name: &str) -> Result { - if self.dry_run() { - return Ok(TomlConfig::default()); - } - - let builder_config_path = - self.out.join(self.build.triple).join(build_name).join(BUILDER_CONFIG_FILENAME); - Self::get_toml(&builder_config_path) - } - - pub(crate) fn get_toml(file: &Path) -> Result { - #[cfg(test)] - return Ok(TomlConfig::default()); - - #[cfg(not(test))] - Self::get_toml_inner(file) - } - - fn get_toml_inner(file: &Path) -> Result { - let contents = - t!(fs::read_to_string(file), format!("config file {} not found", file.display())); - // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of - // TomlConfig and sub types to be monomorphized 5x by toml. - toml::from_str(&contents) - .and_then(|table: toml::Value| TomlConfig::deserialize(table)) - .inspect_err(|_| { - if let Ok(ChangeIdWrapper { inner: Some(ChangeId::Id(id)) }) = - toml::from_str::(&contents) - .and_then(|table: toml::Value| ChangeIdWrapper::deserialize(table)) - { - let changes = crate::find_recent_config_change_ids(id); - if !changes.is_empty() { - println!( - "WARNING: There have been changes to x.py since you last updated:\n{}", - crate::human_readable_changes(changes) - ); - } - } - }) - } - #[cfg_attr( feature = "tracing", instrument(target = "CONFIG_HANDLING", level = "trace", name = "Config::parse", skip_all) @@ -1906,42 +817,11 @@ impl Config { // Verbose flag is a good default for `rust.verbose-tests`. config.verbose_tests = config.is_verbose(); - if let Some(install) = toml.install { - let Install { prefix, sysconfdir, docdir, bindir, libdir, mandir, datadir } = install; - config.prefix = prefix.map(PathBuf::from); - config.sysconfdir = sysconfdir.map(PathBuf::from); - config.datadir = datadir.map(PathBuf::from); - config.docdir = docdir.map(PathBuf::from); - set(&mut config.bindir, bindir.map(PathBuf::from)); - config.libdir = libdir.map(PathBuf::from); - config.mandir = mandir.map(PathBuf::from); - } + config.apply_install_config(toml.install); config.llvm_assertions = toml.llvm.as_ref().is_some_and(|llvm| llvm.assertions.unwrap_or(false)); - // Store off these values as options because if they're not provided - // we'll infer default values for them later - let mut llvm_tests = None; - let mut llvm_enzyme = None; - let mut llvm_offload = None; - let mut llvm_plugins = None; - let mut debug = None; - let mut rustc_debug_assertions = None; - let mut std_debug_assertions = None; - let mut tools_debug_assertions = None; - let mut overflow_checks = None; - let mut overflow_checks_std = None; - let mut debug_logging = None; - let mut debuginfo_level = None; - let mut debuginfo_level_rustc = None; - let mut debuginfo_level_std = None; - let mut debuginfo_level_tools = None; - let mut debuginfo_level_tests = None; - let mut optimize = None; - let mut lld_enabled = None; - let mut std_features = None; - let file_content = t!(fs::read_to_string(config.src.join("src/ci/channel"))); let ci_channel = file_content.trim_end(); @@ -1973,203 +853,23 @@ impl Config { config.enzyme_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/enzyme")); config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project")); - config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc")); - - config.vendor = vendor.unwrap_or( - config.rust_info.is_from_tarball() - && config.src.join("vendor").exists() - && config.src.join(".cargo/config.toml").exists(), - ); - - if !is_user_configured_rust_channel && config.rust_info.is_from_tarball() { - config.channel = ci_channel.into(); - } - - if let Some(rust) = toml.rust { - let Rust { - optimize: optimize_toml, - debug: debug_toml, - codegen_units, - codegen_units_std, - rustc_debug_assertions: rustc_debug_assertions_toml, - std_debug_assertions: std_debug_assertions_toml, - tools_debug_assertions: tools_debug_assertions_toml, - overflow_checks: overflow_checks_toml, - overflow_checks_std: overflow_checks_std_toml, - debug_logging: debug_logging_toml, - debuginfo_level: debuginfo_level_toml, - debuginfo_level_rustc: debuginfo_level_rustc_toml, - debuginfo_level_std: debuginfo_level_std_toml, - debuginfo_level_tools: debuginfo_level_tools_toml, - debuginfo_level_tests: debuginfo_level_tests_toml, - backtrace, - incremental, - randomize_layout, - default_linker, - channel: _, // already handled above - description: rust_description, - musl_root, - rpath, - verbose_tests, - optimize_tests, - codegen_tests, - omit_git_hash: _, // already handled above - dist_src, - save_toolstates, - codegen_backends, - lld: lld_enabled_toml, - llvm_tools, - llvm_bitcode_linker, - deny_warnings, - backtrace_on_ice, - verify_llvm_ir, - thin_lto_import_instr_limit, - remap_debuginfo, - jemalloc, - test_compare_mode, - llvm_libunwind, - control_flow_guard, - ehcont_guard, - new_symbol_mangling, - profile_generate, - profile_use, - download_rustc, - lto, - validate_mir_opts, - frame_pointers, - stack_protector, - strip, - lld_mode, - std_features: std_features_toml, - } = rust; - - // FIXME(#133381): alt rustc builds currently do *not* have rustc debug assertions - // enabled. We should not download a CI alt rustc if we need rustc to have debug - // assertions (e.g. for crashes test suite). This can be changed once something like - // [Enable debug assertions on alt - // builds](https://github.com/rust-lang/rust/pull/131077) lands. - // - // Note that `rust.debug = true` currently implies `rust.debug-assertions = true`! - // - // This relies also on the fact that the global default for `download-rustc` will be - // `false` if it's not explicitly set. - let debug_assertions_requested = matches!(rustc_debug_assertions_toml, Some(true)) - || (matches!(debug_toml, Some(true)) - && !matches!(rustc_debug_assertions_toml, Some(false))); - - if debug_assertions_requested - && let Some(ref opt) = download_rustc - && opt.is_string_or_true() - { - eprintln!( - "WARN: currently no CI rustc builds have rustc debug assertions \ - enabled. Please either set `rust.debug-assertions` to `false` if you \ - want to use download CI rustc or set `rust.download-rustc` to `false`." - ); - } - - config.download_rustc_commit = config.download_ci_rustc_commit( - download_rustc, - debug_assertions_requested, - config.llvm_assertions, - ); - - debug = debug_toml; - rustc_debug_assertions = rustc_debug_assertions_toml; - std_debug_assertions = std_debug_assertions_toml; - tools_debug_assertions = tools_debug_assertions_toml; - overflow_checks = overflow_checks_toml; - overflow_checks_std = overflow_checks_std_toml; - debug_logging = debug_logging_toml; - debuginfo_level = debuginfo_level_toml; - debuginfo_level_rustc = debuginfo_level_rustc_toml; - debuginfo_level_std = debuginfo_level_std_toml; - debuginfo_level_tools = debuginfo_level_tools_toml; - debuginfo_level_tests = debuginfo_level_tests_toml; - lld_enabled = lld_enabled_toml; - std_features = std_features_toml; - - optimize = optimize_toml; - config.rust_new_symbol_mangling = new_symbol_mangling; - set(&mut config.rust_optimize_tests, optimize_tests); - set(&mut config.codegen_tests, codegen_tests); - set(&mut config.rust_rpath, rpath); - set(&mut config.rust_strip, strip); - set(&mut config.rust_frame_pointers, frame_pointers); - config.rust_stack_protector = stack_protector; - set(&mut config.jemalloc, jemalloc); - set(&mut config.test_compare_mode, test_compare_mode); - set(&mut config.backtrace, backtrace); - if rust_description.is_some() { - eprintln!( - "Warning: rust.description is deprecated. Use build.description instead." - ); - } - description = description.or(rust_description); - set(&mut config.rust_dist_src, dist_src); - set(&mut config.verbose_tests, verbose_tests); - // in the case "false" is set explicitly, do not overwrite the command line args - if let Some(true) = incremental { - config.incremental = true; - } - set(&mut config.lld_mode, lld_mode); - set(&mut config.llvm_bitcode_linker_enabled, llvm_bitcode_linker); - - config.rust_randomize_layout = randomize_layout.unwrap_or_default(); - config.llvm_tools_enabled = llvm_tools.unwrap_or(true); - - config.llvm_enzyme = - llvm_enzyme.unwrap_or(config.channel == "dev" || config.channel == "nightly"); - config.rustc_default_linker = default_linker; - config.musl_root = musl_root.map(PathBuf::from); - config.save_toolstates = save_toolstates.map(PathBuf::from); - set( - &mut config.deny_warnings, - match flags.warnings { - Warnings::Deny => Some(true), - Warnings::Warn => Some(false), - Warnings::Default => deny_warnings, - }, - ); - set(&mut config.backtrace_on_ice, backtrace_on_ice); - set(&mut config.rust_verify_llvm_ir, verify_llvm_ir); - config.rust_thin_lto_import_instr_limit = thin_lto_import_instr_limit; - set(&mut config.rust_remap_debuginfo, remap_debuginfo); - set(&mut config.control_flow_guard, control_flow_guard); - set(&mut config.ehcont_guard, ehcont_guard); - config.llvm_libunwind_default = - llvm_libunwind.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")); - - if let Some(ref backends) = codegen_backends { - let available_backends = ["llvm", "cranelift", "gcc"]; - - config.rust_codegen_backends = backends.iter().map(|s| { - if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) { - if available_backends.contains(&backend) { - panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'."); - } else { - println!("HELP: '{s}' for 'rust.codegen-backends' might fail. \ - Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ - In this case, it would be referred to as '{backend}'."); - } - } + config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc")); - s.clone() - }).collect(); - } + config.vendor = vendor.unwrap_or( + config.rust_info.is_from_tarball() + && config.src.join("vendor").exists() + && config.src.join(".cargo/config.toml").exists(), + ); - config.rust_codegen_units = codegen_units.map(threads_from_config); - config.rust_codegen_units_std = codegen_units_std.map(threads_from_config); - config.rust_profile_use = flags.rust_profile_use.or(profile_use); - config.rust_profile_generate = flags.rust_profile_generate.or(profile_generate); - config.rust_lto = - lto.as_deref().map(|value| RustcLto::from_str(value).unwrap()).unwrap_or_default(); - config.rust_validate_mir_opts = validate_mir_opts; - } else { - config.rust_profile_use = flags.rust_profile_use; - config.rust_profile_generate = flags.rust_profile_generate; + if !is_user_configured_rust_channel && config.rust_info.is_from_tarball() { + config.channel = ci_channel.into(); } + config.rust_profile_use = flags.rust_profile_use; + config.rust_profile_generate = flags.rust_profile_generate; + + config.apply_rust_config(toml.rust, flags.warnings, &mut description); + config.reproducible_artifacts = flags.reproducible_artifact; config.description = description; @@ -2189,206 +889,11 @@ impl Config { config.channel = channel; } - if let Some(llvm) = toml.llvm { - let Llvm { - optimize: optimize_toml, - thin_lto, - release_debuginfo, - assertions: _, - tests, - enzyme, - plugins, - ccache: llvm_ccache, - static_libstdcpp, - libzstd, - ninja, - targets, - experimental_targets, - link_jobs, - link_shared, - version_suffix, - clang_cl, - cflags, - cxxflags, - ldflags, - use_libcxx, - use_linker, - allow_old_toolchain, - offload, - polly, - clang, - enable_warnings, - download_ci_llvm, - build_config, - } = llvm; - if llvm_ccache.is_some() { - eprintln!("Warning: llvm.ccache is deprecated. Use build.ccache instead."); - } - - ccache = ccache.or(llvm_ccache); - set(&mut config.ninja_in_file, ninja); - llvm_tests = tests; - llvm_enzyme = enzyme; - llvm_offload = offload; - llvm_plugins = plugins; - set(&mut config.llvm_optimize, optimize_toml); - set(&mut config.llvm_thin_lto, thin_lto); - set(&mut config.llvm_release_debuginfo, release_debuginfo); - set(&mut config.llvm_static_stdcpp, static_libstdcpp); - set(&mut config.llvm_libzstd, libzstd); - if let Some(v) = link_shared { - config.llvm_link_shared.set(Some(v)); - } - config.llvm_targets.clone_from(&targets); - config.llvm_experimental_targets.clone_from(&experimental_targets); - config.llvm_link_jobs = link_jobs; - config.llvm_version_suffix.clone_from(&version_suffix); - config.llvm_clang_cl.clone_from(&clang_cl); - - config.llvm_cflags.clone_from(&cflags); - config.llvm_cxxflags.clone_from(&cxxflags); - config.llvm_ldflags.clone_from(&ldflags); - set(&mut config.llvm_use_libcxx, use_libcxx); - config.llvm_use_linker.clone_from(&use_linker); - config.llvm_allow_old_toolchain = allow_old_toolchain.unwrap_or(false); - config.llvm_offload = offload.unwrap_or(false); - config.llvm_polly = polly.unwrap_or(false); - config.llvm_clang = clang.unwrap_or(false); - config.llvm_enable_warnings = enable_warnings.unwrap_or(false); - config.llvm_build_config = build_config.clone().unwrap_or(Default::default()); - - config.llvm_from_ci = - config.parse_download_ci_llvm(download_ci_llvm, config.llvm_assertions); - - if config.llvm_from_ci { - let warn = |option: &str| { - println!( - "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build." - ); - println!( - "HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false." - ); - }; - - if static_libstdcpp.is_some() { - warn("static-libstdcpp"); - } - - if link_shared.is_some() { - warn("link-shared"); - } - - // FIXME(#129153): instead of all the ad-hoc `download-ci-llvm` checks that follow, - // use the `builder-config` present in tarballs since #128822 to compare the local - // config to the ones used to build the LLVM artifacts on CI, and only notify users - // if they've chosen a different value. - - if libzstd.is_some() { - println!( - "WARNING: when using `download-ci-llvm`, the local `llvm.libzstd` option, \ - like almost all `llvm.*` options, will be ignored and set by the LLVM CI \ - artifacts builder config." - ); - println!( - "HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false." - ); - } - } - - if !config.llvm_from_ci && config.llvm_thin_lto && link_shared.is_none() { - // If we're building with ThinLTO on, by default we want to link - // to LLVM shared, to avoid re-doing ThinLTO (which happens in - // the link step) with each stage. - config.llvm_link_shared.set(Some(true)); - } - } else { - config.llvm_from_ci = config.parse_download_ci_llvm(None, false); - } - - if let Some(gcc) = toml.gcc { - config.gcc_ci_mode = match gcc.download_ci_gcc { - Some(value) => match value { - true => GccCiMode::DownloadFromCi, - false => GccCiMode::BuildLocally, - }, - None => GccCiMode::default(), - }; - } - - if let Some(t) = toml.target { - for (triple, cfg) in t { - let mut target = Target::from_triple(&triple); - - if let Some(ref s) = cfg.llvm_config { - if config.download_rustc_commit.is_some() && triple == *config.build.triple { - panic!( - "setting llvm_config for the host is incompatible with download-rustc" - ); - } - target.llvm_config = Some(config.src.join(s)); - } - if let Some(patches) = cfg.llvm_has_rust_patches { - assert!( - config.submodules == Some(false) || cfg.llvm_config.is_some(), - "use of `llvm-has-rust-patches` is restricted to cases where either submodules are disabled or llvm-config been provided" - ); - target.llvm_has_rust_patches = Some(patches); - } - if let Some(ref s) = cfg.llvm_filecheck { - target.llvm_filecheck = Some(config.src.join(s)); - } - target.llvm_libunwind = cfg.llvm_libunwind.as_ref().map(|v| { - v.parse().unwrap_or_else(|_| { - panic!("failed to parse target.{triple}.llvm-libunwind") - }) - }); - if let Some(s) = cfg.no_std { - target.no_std = s; - } - target.cc = cfg.cc.map(PathBuf::from); - target.cxx = cfg.cxx.map(PathBuf::from); - target.ar = cfg.ar.map(PathBuf::from); - target.ranlib = cfg.ranlib.map(PathBuf::from); - target.linker = cfg.linker.map(PathBuf::from); - target.crt_static = cfg.crt_static; - target.musl_root = cfg.musl_root.map(PathBuf::from); - target.musl_libdir = cfg.musl_libdir.map(PathBuf::from); - target.wasi_root = cfg.wasi_root.map(PathBuf::from); - target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from); - target.runner = cfg.runner; - target.sanitizers = cfg.sanitizers; - target.profiler = cfg.profiler; - target.rpath = cfg.rpath; - target.optimized_compiler_builtins = cfg.optimized_compiler_builtins; - target.jemalloc = cfg.jemalloc; - - if let Some(ref backends) = cfg.codegen_backends { - let available_backends = ["llvm", "cranelift", "gcc"]; - - target.codegen_backends = Some(backends.iter().map(|s| { - if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) { - if available_backends.contains(&backend) { - panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'."); - } else { - println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \ - Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ - In this case, it would be referred to as '{backend}'."); - } - } - - s.clone() - }).collect()); - } + config.apply_llvm_config(toml.llvm, &mut ccache); - target.split_debuginfo = cfg.split_debuginfo.as_ref().map(|v| { - v.parse().unwrap_or_else(|_| { - panic!("invalid value for target.{triple}.split-debuginfo") - }) - }); + config.apply_gcc_config(toml.gcc); - config.target_config.insert(TargetSelection::from_user(&triple), target); - } - } + config.apply_target_config(toml.target); match ccache { Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()), @@ -2412,69 +917,11 @@ impl Config { build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", config.build))); } - if let Some(dist) = toml.dist { - let Dist { - sign_folder, - upload_addr, - src_tarball, - compression_formats, - compression_profile, - include_mingw_linker, - vendor, - } = dist; - config.dist_sign_folder = sign_folder.map(PathBuf::from); - config.dist_upload_addr = upload_addr; - config.dist_compression_formats = compression_formats; - set(&mut config.dist_compression_profile, compression_profile); - set(&mut config.rust_dist_src, src_tarball); - set(&mut config.dist_include_mingw_linker, include_mingw_linker); - config.dist_vendor = vendor.unwrap_or_else(|| { - // If we're building from git or tarball sources, enable it by default. - config.rust_info.is_managed_git_subrepository() - || config.rust_info.is_from_tarball() - }); - } + config.apply_dist_config(toml.dist); config.initial_rustfmt = if let Some(r) = rustfmt { Some(r) } else { config.maybe_download_rustfmt() }; - // Now that we've reached the end of our configuration, infer the - // default values for all options that we haven't otherwise stored yet. - - config.llvm_tests = llvm_tests.unwrap_or(false); - config.llvm_enzyme = llvm_enzyme.unwrap_or(false); - config.llvm_offload = llvm_offload.unwrap_or(false); - config.llvm_plugins = llvm_plugins.unwrap_or(false); - config.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true)); - - // We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will - // build our internal lld and use it as the default linker, by setting the `rust.lld` config - // to true by default: - // - on the `x86_64-unknown-linux-gnu` target - // - on the `dev` and `nightly` channels - // - when building our in-tree llvm (i.e. the target has not set an `llvm-config`), so that - // we're also able to build the corresponding lld - // - or when using an external llvm that's downloaded from CI, which also contains our prebuilt - // lld - // - otherwise, we'd be using an external llvm, and lld would not necessarily available and - // thus, disabled - // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g. - // when the config sets `rust.lld = false` - if config.build.triple == "x86_64-unknown-linux-gnu" - && config.hosts == [config.build] - && (config.channel == "dev" || config.channel == "nightly") - { - let no_llvm_config = config - .target_config - .get(&config.build) - .is_some_and(|target_config| target_config.llvm_config.is_none()); - let enable_lld = config.llvm_from_ci || no_llvm_config; - // Prefer the config setting in case an explicit opt-out is needed. - config.lld_enabled = lld_enabled.unwrap_or(enable_lld); - } else { - set(&mut config.lld_enabled, lld_enabled); - } - if matches!(config.lld_mode, LldMode::SelfContained) && !config.lld_enabled && flags.stage.unwrap_or(0) > 0 @@ -2490,31 +937,6 @@ impl Config { ); } - let default_std_features = BTreeSet::from([String::from("panic-unwind")]); - config.rust_std_features = std_features.unwrap_or(default_std_features); - - let default = debug == Some(true); - config.rustc_debug_assertions = rustc_debug_assertions.unwrap_or(default); - config.std_debug_assertions = std_debug_assertions.unwrap_or(config.rustc_debug_assertions); - config.tools_debug_assertions = - tools_debug_assertions.unwrap_or(config.rustc_debug_assertions); - config.rust_overflow_checks = overflow_checks.unwrap_or(default); - config.rust_overflow_checks_std = - overflow_checks_std.unwrap_or(config.rust_overflow_checks); - - config.rust_debug_logging = debug_logging.unwrap_or(config.rustc_debug_assertions); - - let with_defaults = |debuginfo_level_specific: Option<_>| { - debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) { - DebuginfoLevel::Limited - } else { - DebuginfoLevel::None - }) - }; - config.rust_debuginfo_level_rustc = with_defaults(debuginfo_level_rustc); - config.rust_debuginfo_level_std = with_defaults(debuginfo_level_std); - config.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools); - config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(DebuginfoLevel::None); config.optimized_compiler_builtins = optimized_compiler_builtins.unwrap_or(config.channel != "dev"); config.compiletest_diff_tool = compiletest_diff_tool; @@ -2840,75 +1262,17 @@ impl Config { } } - pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool { - self.target_config.get(&target).and_then(|t| t.sanitizers).unwrap_or(self.sanitizers) - } - - pub fn needs_sanitizer_runtime_built(&self, target: TargetSelection) -> bool { - // MSVC uses the Microsoft-provided sanitizer runtime, but all other runtimes we build. - !target.is_msvc() && self.sanitizers_enabled(target) - } - pub fn any_sanitizers_to_build(&self) -> bool { self.target_config .iter() .any(|(ts, t)| !ts.is_msvc() && t.sanitizers.unwrap_or(self.sanitizers)) } - pub fn profiler_path(&self, target: TargetSelection) -> Option<&str> { - match self.target_config.get(&target)?.profiler.as_ref()? { - StringOrBool::String(s) => Some(s), - StringOrBool::Bool(_) => None, - } - } - - pub fn profiler_enabled(&self, target: TargetSelection) -> bool { - self.target_config - .get(&target) - .and_then(|t| t.profiler.as_ref()) - .map(StringOrBool::is_string_or_true) - .unwrap_or(self.profiler) - } - pub fn any_profiler_enabled(&self) -> bool { self.target_config.values().any(|t| matches!(&t.profiler, Some(p) if p.is_string_or_true())) || self.profiler } - pub fn rpath_enabled(&self, target: TargetSelection) -> bool { - self.target_config.get(&target).and_then(|t| t.rpath).unwrap_or(self.rust_rpath) - } - - pub fn optimized_compiler_builtins(&self, target: TargetSelection) -> bool { - self.target_config - .get(&target) - .and_then(|t| t.optimized_compiler_builtins) - .unwrap_or(self.optimized_compiler_builtins) - } - - pub fn llvm_enabled(&self, target: TargetSelection) -> bool { - self.codegen_backends(target).contains(&"llvm".to_owned()) - } - - pub fn llvm_libunwind(&self, target: TargetSelection) -> LlvmLibunwind { - self.target_config - .get(&target) - .and_then(|t| t.llvm_libunwind) - .or(self.llvm_libunwind_default) - .unwrap_or(if target.contains("fuchsia") { - LlvmLibunwind::InTree - } else { - LlvmLibunwind::No - }) - } - - pub fn split_debuginfo(&self, target: TargetSelection) -> SplitDebuginfo { - self.target_config - .get(&target) - .and_then(|t| t.split_debuginfo) - .unwrap_or_else(|| SplitDebuginfo::default_for_platform(target)) - } - /// Returns whether or not submodules should be managed by bootstrap. pub fn submodules(&self) -> bool { // If not specified in config, the default is to only manage @@ -2916,21 +1280,6 @@ impl Config { self.submodules.unwrap_or(self.rust_info.is_managed_git_subrepository()) } - pub fn codegen_backends(&self, target: TargetSelection) -> &[String] { - self.target_config - .get(&target) - .and_then(|cfg| cfg.codegen_backends.as_deref()) - .unwrap_or(&self.rust_codegen_backends) - } - - pub fn jemalloc(&self, target: TargetSelection) -> bool { - self.target_config.get(&target).and_then(|cfg| cfg.jemalloc).unwrap_or(self.jemalloc) - } - - pub fn default_codegen_backend(&self, target: TargetSelection) -> Option { - self.codegen_backends(target).first().cloned() - } - pub fn git_config(&self) -> GitConfig<'_> { GitConfig { nightly_branch: &self.stage0_metadata.config.nightly_branch, @@ -3114,7 +1463,7 @@ impl Config { } /// Returns the commit to download, or `None` if we shouldn't download CI artifacts. - fn download_ci_rustc_commit( + pub fn download_ci_rustc_commit( &self, download_rustc: Option, debug_assertions_requested: bool, @@ -3194,7 +1543,7 @@ impl Config { Some(commit) } - fn parse_download_ci_llvm( + pub fn parse_download_ci_llvm( &self, download_ci_llvm: Option, asserts: bool, @@ -3277,6 +1626,83 @@ impl Config { .clone() } + pub fn ci_env(&self) -> CiEnv { + if self.is_running_on_ci { CiEnv::GitHubActions } else { CiEnv::None } + } + + pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool { + self.target_config.get(&target).and_then(|t| t.sanitizers).unwrap_or(self.sanitizers) + } + + pub fn needs_sanitizer_runtime_built(&self, target: TargetSelection) -> bool { + // MSVC uses the Microsoft-provided sanitizer runtime, but all other runtimes we build. + !target.is_msvc() && self.sanitizers_enabled(target) + } + + pub fn profiler_path(&self, target: TargetSelection) -> Option<&str> { + match self.target_config.get(&target)?.profiler.as_ref()? { + StringOrBool::String(s) => Some(s), + StringOrBool::Bool(_) => None, + } + } + + pub fn profiler_enabled(&self, target: TargetSelection) -> bool { + self.target_config + .get(&target) + .and_then(|t| t.profiler.as_ref()) + .map(StringOrBool::is_string_or_true) + .unwrap_or(self.profiler) + } + + pub fn codegen_backends(&self, target: TargetSelection) -> &[String] { + self.target_config + .get(&target) + .and_then(|cfg| cfg.codegen_backends.as_deref()) + .unwrap_or(&self.rust_codegen_backends) + } + + pub fn jemalloc(&self, target: TargetSelection) -> bool { + self.target_config.get(&target).and_then(|cfg| cfg.jemalloc).unwrap_or(self.jemalloc) + } + + pub fn default_codegen_backend(&self, target: TargetSelection) -> Option { + self.codegen_backends(target).first().cloned() + } + + pub fn rpath_enabled(&self, target: TargetSelection) -> bool { + self.target_config.get(&target).and_then(|t| t.rpath).unwrap_or(self.rust_rpath) + } + + pub fn optimized_compiler_builtins(&self, target: TargetSelection) -> bool { + self.target_config + .get(&target) + .and_then(|t| t.optimized_compiler_builtins) + .unwrap_or(self.optimized_compiler_builtins) + } + + pub fn llvm_enabled(&self, target: TargetSelection) -> bool { + self.codegen_backends(target).contains(&"llvm".to_owned()) + } + + pub fn llvm_libunwind(&self, target: TargetSelection) -> LlvmLibunwind { + self.target_config + .get(&target) + .and_then(|t| t.llvm_libunwind) + .or(self.llvm_libunwind_default) + .unwrap_or(if target.contains("fuchsia") { + LlvmLibunwind::InTree + } else { + LlvmLibunwind::No + }) + } + + pub fn split_debuginfo(&self, target: TargetSelection) -> SplitDebuginfo { + self.target_config + .get(&target) + .and_then(|t| t.split_debuginfo) + .unwrap_or_else(|| SplitDebuginfo::default_for_platform(target)) + } + /// Checks if the given target is the same as the host target. pub fn is_host_target(&self, target: TargetSelection) -> bool { self.build == target @@ -3312,290 +1738,4 @@ impl Config { _ => !self.is_system_llvm(target), } } - - pub fn ci_env(&self) -> CiEnv { - if self.is_running_on_ci { CiEnv::GitHubActions } else { CiEnv::None } - } -} - -/// Compares the current `Llvm` options against those in the CI LLVM builder and detects any incompatible options. -/// It does this by destructuring the `Llvm` instance to make sure every `Llvm` field is covered and not missing. -#[cfg(not(test))] -pub(crate) fn check_incompatible_options_for_ci_llvm( - current_config_toml: TomlConfig, - ci_config_toml: TomlConfig, -) -> Result<(), String> { - macro_rules! err { - ($current:expr, $expected:expr) => { - if let Some(current) = &$current { - if Some(current) != $expected.as_ref() { - return Err(format!( - "ERROR: Setting `llvm.{}` is incompatible with `llvm.download-ci-llvm`. \ - Current value: {:?}, Expected value(s): {}{:?}", - stringify!($expected).replace("_", "-"), - $current, - if $expected.is_some() { "None/" } else { "" }, - $expected, - )); - }; - }; - }; - } - - macro_rules! warn { - ($current:expr, $expected:expr) => { - if let Some(current) = &$current { - if Some(current) != $expected.as_ref() { - println!( - "WARNING: `llvm.{}` has no effect with `llvm.download-ci-llvm`. \ - Current value: {:?}, Expected value(s): {}{:?}", - stringify!($expected).replace("_", "-"), - $current, - if $expected.is_some() { "None/" } else { "" }, - $expected, - ); - }; - }; - }; - } - - let (Some(current_llvm_config), Some(ci_llvm_config)) = - (current_config_toml.llvm, ci_config_toml.llvm) - else { - return Ok(()); - }; - - let Llvm { - optimize, - thin_lto, - release_debuginfo, - assertions: _, - tests: _, - plugins, - ccache: _, - static_libstdcpp: _, - libzstd, - ninja: _, - targets, - experimental_targets, - link_jobs: _, - link_shared: _, - version_suffix, - clang_cl, - cflags, - cxxflags, - ldflags, - use_libcxx, - use_linker, - allow_old_toolchain, - offload, - polly, - clang, - enable_warnings, - download_ci_llvm: _, - build_config, - enzyme, - } = ci_llvm_config; - - err!(current_llvm_config.optimize, optimize); - err!(current_llvm_config.thin_lto, thin_lto); - err!(current_llvm_config.release_debuginfo, release_debuginfo); - err!(current_llvm_config.libzstd, libzstd); - err!(current_llvm_config.targets, targets); - err!(current_llvm_config.experimental_targets, experimental_targets); - err!(current_llvm_config.clang_cl, clang_cl); - err!(current_llvm_config.version_suffix, version_suffix); - err!(current_llvm_config.cflags, cflags); - err!(current_llvm_config.cxxflags, cxxflags); - err!(current_llvm_config.ldflags, ldflags); - err!(current_llvm_config.use_libcxx, use_libcxx); - err!(current_llvm_config.use_linker, use_linker); - err!(current_llvm_config.allow_old_toolchain, allow_old_toolchain); - err!(current_llvm_config.offload, offload); - err!(current_llvm_config.polly, polly); - err!(current_llvm_config.clang, clang); - err!(current_llvm_config.build_config, build_config); - err!(current_llvm_config.plugins, plugins); - err!(current_llvm_config.enzyme, enzyme); - - warn!(current_llvm_config.enable_warnings, enable_warnings); - - Ok(()) -} - -/// Compares the current Rust options against those in the CI rustc builder and detects any incompatible options. -/// It does this by destructuring the `Rust` instance to make sure every `Rust` field is covered and not missing. -fn check_incompatible_options_for_ci_rustc( - host: TargetSelection, - current_config_toml: TomlConfig, - ci_config_toml: TomlConfig, -) -> Result<(), String> { - macro_rules! err { - ($current:expr, $expected:expr, $config_section:expr) => { - if let Some(current) = &$current { - if Some(current) != $expected.as_ref() { - return Err(format!( - "ERROR: Setting `{}` is incompatible with `rust.download-rustc`. \ - Current value: {:?}, Expected value(s): {}{:?}", - format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")), - $current, - if $expected.is_some() { "None/" } else { "" }, - $expected, - )); - }; - }; - }; - } - - macro_rules! warn { - ($current:expr, $expected:expr, $config_section:expr) => { - if let Some(current) = &$current { - if Some(current) != $expected.as_ref() { - println!( - "WARNING: `{}` has no effect with `rust.download-rustc`. \ - Current value: {:?}, Expected value(s): {}{:?}", - format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")), - $current, - if $expected.is_some() { "None/" } else { "" }, - $expected, - ); - }; - }; - }; - } - - let current_profiler = current_config_toml.build.as_ref().and_then(|b| b.profiler); - let profiler = ci_config_toml.build.as_ref().and_then(|b| b.profiler); - err!(current_profiler, profiler, "build"); - - let current_optimized_compiler_builtins = - current_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins); - let optimized_compiler_builtins = - ci_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins); - err!(current_optimized_compiler_builtins, optimized_compiler_builtins, "build"); - - // We always build the in-tree compiler on cross targets, so we only care - // about the host target here. - let host_str = host.to_string(); - if let Some(current_cfg) = current_config_toml.target.as_ref().and_then(|c| c.get(&host_str)) - && current_cfg.profiler.is_some() - { - let ci_target_toml = ci_config_toml.target.as_ref().and_then(|c| c.get(&host_str)); - let ci_cfg = ci_target_toml.ok_or(format!( - "Target specific config for '{host_str}' is not present for CI-rustc" - ))?; - - let profiler = &ci_cfg.profiler; - err!(current_cfg.profiler, profiler, "build"); - - let optimized_compiler_builtins = &ci_cfg.optimized_compiler_builtins; - err!(current_cfg.optimized_compiler_builtins, optimized_compiler_builtins, "build"); - } - - let (Some(current_rust_config), Some(ci_rust_config)) = - (current_config_toml.rust, ci_config_toml.rust) - else { - return Ok(()); - }; - - let Rust { - // Following options are the CI rustc incompatible ones. - optimize, - randomize_layout, - debug_logging, - debuginfo_level_rustc, - llvm_tools, - llvm_bitcode_linker, - lto, - stack_protector, - strip, - lld_mode, - jemalloc, - rpath, - channel, - description, - incremental, - default_linker, - std_features, - - // Rest of the options can simply be ignored. - debug: _, - codegen_units: _, - codegen_units_std: _, - rustc_debug_assertions: _, - std_debug_assertions: _, - tools_debug_assertions: _, - overflow_checks: _, - overflow_checks_std: _, - debuginfo_level: _, - debuginfo_level_std: _, - debuginfo_level_tools: _, - debuginfo_level_tests: _, - backtrace: _, - musl_root: _, - verbose_tests: _, - optimize_tests: _, - codegen_tests: _, - omit_git_hash: _, - dist_src: _, - save_toolstates: _, - codegen_backends: _, - lld: _, - deny_warnings: _, - backtrace_on_ice: _, - verify_llvm_ir: _, - thin_lto_import_instr_limit: _, - remap_debuginfo: _, - test_compare_mode: _, - llvm_libunwind: _, - control_flow_guard: _, - ehcont_guard: _, - new_symbol_mangling: _, - profile_generate: _, - profile_use: _, - download_rustc: _, - validate_mir_opts: _, - frame_pointers: _, - } = ci_rust_config; - - // There are two kinds of checks for CI rustc incompatible options: - // 1. Checking an option that may change the compiler behaviour/output. - // 2. Checking an option that have no effect on the compiler behaviour/output. - // - // If the option belongs to the first category, we call `err` macro for a hard error; - // otherwise, we just print a warning with `warn` macro. - - err!(current_rust_config.optimize, optimize, "rust"); - err!(current_rust_config.randomize_layout, randomize_layout, "rust"); - err!(current_rust_config.debug_logging, debug_logging, "rust"); - err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc, "rust"); - err!(current_rust_config.rpath, rpath, "rust"); - err!(current_rust_config.strip, strip, "rust"); - err!(current_rust_config.lld_mode, lld_mode, "rust"); - err!(current_rust_config.llvm_tools, llvm_tools, "rust"); - err!(current_rust_config.llvm_bitcode_linker, llvm_bitcode_linker, "rust"); - err!(current_rust_config.jemalloc, jemalloc, "rust"); - err!(current_rust_config.default_linker, default_linker, "rust"); - err!(current_rust_config.stack_protector, stack_protector, "rust"); - err!(current_rust_config.lto, lto, "rust"); - err!(current_rust_config.std_features, std_features, "rust"); - - warn!(current_rust_config.channel, channel, "rust"); - warn!(current_rust_config.description, description, "rust"); - warn!(current_rust_config.incremental, incremental, "rust"); - - Ok(()) -} - -fn set(field: &mut T, val: Option) { - if let Some(v) = val { - *field = v; - } -} - -fn threads_from_config(v: u32) -> u32 { - match v { - 0 => std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32, - n => n, - } } -- cgit 1.4.1-3-g733a5 From 8f22a507c1e7fd7313c1421db25d80057f07bac3 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Fri, 30 May 2025 22:13:47 +0200 Subject: Use 4-core large disk runner for the alt job --- src/ci/github-actions/jobs.yml | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 56863b839df..8d5f4647301 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -10,6 +10,10 @@ runners: free_disk: true <<: *base-job + - &job-linux-4c-largedisk + os: ubuntu-24.04-4core-16gb + <<: *base-job + - &job-linux-8c os: ubuntu-24.04-8core-32gb <<: *base-job @@ -107,6 +111,15 @@ envs: pr: PR_CI_JOB: 1 +jobs: + dist-x86_64-linux: &job-dist-x86_64-linux + name: dist-x86_64-linux + env: + CODEGEN_BACKENDS: llvm,cranelift + DOCKER_SCRIPT: dist.sh + <<: *job-linux-36c-codebuild + + # Jobs that run on each push to a pull request (PR) # These jobs automatically inherit envs.pr, to avoid repeating # it in each job definition. @@ -138,11 +151,7 @@ pr: # These jobs automatically inherit envs.try, to avoid repeating # it in each job definition. try: - - name: dist-x86_64-linux - env: - CODEGEN_BACKENDS: llvm,cranelift - DOCKER_SCRIPT: dist.sh - <<: *job-linux-36c-codebuild + - <<: *job-dist-x86_64-linux # Main CI jobs that have to be green to merge a commit into master # These jobs automatically inherit envs.auto, to avoid repeating @@ -235,18 +244,14 @@ auto: - name: dist-x86_64-illumos <<: *job-linux-4c - - name: dist-x86_64-linux - env: - CODEGEN_BACKENDS: llvm,cranelift - DOCKER_SCRIPT: dist.sh - <<: *job-linux-36c-codebuild + - <<: *job-dist-x86_64-linux - name: dist-x86_64-linux-alt env: IMAGE: dist-x86_64-linux CODEGEN_BACKENDS: llvm,cranelift DOCKER_SCRIPT: dist-alt.sh - <<: *job-linux-16c + <<: *job-linux-4c-largedisk - name: dist-x86_64-musl env: -- cgit 1.4.1-3-g733a5 From 9b7da4deb2868eae4a8c4154045ae3e67ee74de7 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Tue, 3 Jun 2025 01:29:36 +0200 Subject: decouple "reporting in deps" from future incompatibility reason --- compiler/rustc_lint/src/levels.rs | 2 +- compiler/rustc_lint_defs/src/builtin.rs | 65 ++++++++++++++++------------ compiler/rustc_lint_defs/src/lib.rs | 77 +++++++++++---------------------- compiler/rustc_middle/src/lint.rs | 5 +-- 4 files changed, 67 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 00775647ac6..c52dbd892bf 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -126,7 +126,7 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> UnordSet { .filter(|lint| { // Lints that show up in future-compat reports must always be run. let has_future_breakage = - lint.future_incompatible.is_some_and(|fut| fut.reason.has_future_breakage()); + lint.future_incompatible.is_some_and(|fut| fut.report_in_deps); !has_future_breakage && !lint.eval_always }) .filter(|lint| { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 7c7ba85d484..1b14157c5f0 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -178,8 +178,9 @@ declare_lint! { Warn, "applying forbid to lint-groups", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #81670 ", + report_in_deps: true, }; } @@ -214,7 +215,7 @@ declare_lint! { Deny, "ill-formed attribute inputs that were previously accepted and used in practice", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #57571 ", }; crate_level_only @@ -251,8 +252,9 @@ declare_lint! { Deny, "conflicts between `#[repr(..)]` hints that were previously accepted and used in practice", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #68585 ", + report_in_deps: true, }; } @@ -1240,8 +1242,9 @@ declare_lint! { Deny, "detect public re-exports of private extern crates", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #127909 ", + report_in_deps: true, }; } @@ -1270,8 +1273,9 @@ declare_lint! { Deny, "type parameter default erroneously allowed in invalid location", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #36887 ", + report_in_deps: true, }; } @@ -1409,7 +1413,7 @@ declare_lint! { Deny, "patterns in functions without body were erroneously allowed", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #35203 ", }; } @@ -1453,8 +1457,9 @@ declare_lint! { Deny, "detects missing fragment specifiers in unused `macro_rules!` patterns", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #40107 ", + report_in_deps: true, }; } @@ -1495,7 +1500,7 @@ declare_lint! { Warn, "detects generic lifetime arguments in path segments with late bound lifetime parameters", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #42868 ", }; } @@ -2122,8 +2127,9 @@ declare_lint! { Deny, "detects proc macro derives using inaccessible names from parent modules", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #83583 ", + report_in_deps: true, }; } @@ -2225,7 +2231,7 @@ declare_lint! { "macro-expanded `macro_export` macros from the current crate \ cannot be referred to by absolute paths", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #52234 ", }; crate_level_only @@ -2346,7 +2352,7 @@ declare_lint! { Deny, "ambiguous associated items", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #57644 ", }; } @@ -2362,8 +2368,9 @@ declare_lint! { Deny, "a feature gate that doesn't break dependent crates", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #64266 ", + report_in_deps: true, }; } @@ -2674,7 +2681,7 @@ declare_lint! { Warn, "detects a generic constant is used in a type without a emitting a warning", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #76200 ", }; } @@ -2733,7 +2740,7 @@ declare_lint! { Warn, "uninhabited static", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #74840 ", }; } @@ -2866,7 +2873,7 @@ declare_lint! { Warn, "detect unsupported use of `Self` from outer item", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #124186 ", }; } @@ -2912,8 +2919,9 @@ declare_lint! { Warn, "trailing semicolon in macro body used as expression", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #79813 ", + report_in_deps: true, }; } @@ -2959,7 +2967,7 @@ declare_lint! { Warn, "detects derive helper attributes that are used before they are introduced", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #79202 ", }; } @@ -3126,7 +3134,7 @@ declare_lint! { Warn, "transparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #78586 ", }; } @@ -3177,7 +3185,7 @@ declare_lint! { Warn, "unstable syntax can change at any point in the future, causing a hard error!", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #65860 ", }; } @@ -3685,8 +3693,9 @@ declare_lint! { Warn, "use of unsupported calling convention for function pointer", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #130260 ", + report_in_deps: true, }; } @@ -4368,7 +4377,7 @@ declare_lint! { Warn, "detects certain glob imports that require reporting an ambiguity error", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #114095 ", }; } @@ -4523,7 +4532,7 @@ declare_lint! { Deny, "elided lifetimes cannot be used in associated constants in impls", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #115010 ", }; } @@ -4570,7 +4579,7 @@ declare_lint! { Warn, "detects certain macro bindings that should not be re-exported", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #120192 ", }; } @@ -4635,7 +4644,7 @@ declare_lint! { Warn, "impl contains type parameters that are not covered", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #124559 ", }; } @@ -4799,7 +4808,7 @@ declare_lint! { Warn, "detects out of scope calls to `macro_rules` in key-value attributes", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #124535 ", }; } @@ -5040,8 +5049,9 @@ declare_lint! { Warn, "detects code relying on rustc's non-spec-compliant wasm C ABI", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #138762 ", + report_in_deps: true, }; } @@ -5081,7 +5091,8 @@ declare_lint! { Warn, "detects code that could be affected by ABI issues on aarch64 softfloat targets", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #134375 ", + report_in_deps: true, }; } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 6cbdc245d21..e19bf59e543 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -361,6 +361,18 @@ pub struct FutureIncompatibleInfo { /// Set to false for lints that already include a more detailed /// explanation. pub explain_reason: bool, + /// If set to `true`, this will make future incompatibility warnings show up in cargo's + /// reports. + /// + /// When a future incompatibility warning is first inroduced, set this to `false` + /// (or, rather, don't override the default). This allows crate developers an opportunity + /// to fix the warning before blasting all dependents with a warning they can't fix + /// (dependents have to wait for a new release of the affected crate to be published). + /// + /// After a lint has been in this state for a while, consider setting this to true, so it + /// warns for everyone. It is a good signal that it is ready if you can determine that all + /// or most affected crates on crates.io have been updated. + pub report_in_deps: bool, } /// The reason for future incompatibility @@ -380,46 +392,24 @@ pub struct FutureIncompatibleInfo { pub enum FutureIncompatibilityReason { /// This will be an error in a future release for all editions /// - /// This will *not* show up in cargo's future breakage report. - /// The warning will hence only be seen in local crates, not in dependencies. - /// /// Choose this variant when you are first introducing a "future /// incompatible" warning that is intended to eventually be fixed in the - /// future. This allows crate developers an opportunity to fix the warning - /// before blasting all dependents with a warning they can't fix - /// (dependents have to wait for a new release of the affected crate to be - /// published). - /// - /// After a lint has been in this state for a while, consider graduating - /// it to [`FutureIncompatibilityReason::FutureReleaseErrorReportInDeps`]. - FutureReleaseErrorDontReportInDeps, - /// This will be an error in a future release, and - /// Cargo should create a report even for dependencies + /// future. /// - /// This is the *only* reason that will make future incompatibility warnings show up in cargo's - /// reports. All other future incompatibility warnings are not visible when they occur in a - /// dependency. - /// - /// Choose this variant after the lint has been sitting in the - /// [`FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps`] - /// state for a while, and you feel like it is ready to graduate to - /// warning everyone. It is a good signal that it is ready if you can - /// determine that all or most affected crates on crates.io have been - /// updated. + /// After a lint has been in this state for a while and you feel like it is ready to graduate + /// to warning everyone, consider setting [`FutureIncompatibleInfo::report_in_deps`] to true. + /// (see it's documentation for more guidance) /// /// After some period of time, lints with this variant can be turned into /// hard errors (and the lint removed). Preferably when there is some /// confidence that the number of impacted projects is very small (few /// should have a broken dependency in their dependency tree). - /// - /// [`EditionAndFutureReleaseError`]: FutureIncompatibilityReason::EditionAndFutureReleaseError - FutureReleaseErrorReportInDeps, + FutureReleaseError, /// Code that changes meaning in some way in a /// future release. /// /// Choose this variant when the semantics of existing code is changing, - /// (as opposed to - /// [`FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps`], + /// (as opposed to [`FutureIncompatibilityReason::FutureReleaseError`], /// which is for when code is going to be rejected in the future). FutureReleaseSemanticsChange, /// Previously accepted code that will become an @@ -454,13 +444,12 @@ pub enum FutureIncompatibilityReason { /// This will be an error in the provided edition *and* in a future /// release. /// - /// This variant a combination of [`FutureReleaseErrorDontReportInDeps`] - /// and [`EditionError`]. This is useful in rare cases when we - /// want to have "preview" of a breaking change in an edition, but do a - /// breaking change later on all editions anyway. + /// This variant a combination of [`FutureReleaseError`] and [`EditionError`]. + /// This is useful in rare cases when we want to have "preview" of a breaking + /// change in an edition, but do a breaking change later on all editions anyway. /// /// [`EditionError`]: FutureIncompatibilityReason::EditionError - /// [`FutureReleaseErrorDontReportInDeps`]: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps + /// [`FutureReleaseError`]: FutureIncompatibilityReason::FutureReleaseError EditionAndFutureReleaseError(Edition), /// This will change meaning in the provided edition *and* in a future /// release. @@ -478,7 +467,7 @@ pub enum FutureIncompatibilityReason { /// Choose this variant if the built-in text of the diagnostic of the /// other variants doesn't match your situation. This is behaviorally /// equivalent to - /// [`FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps`]. + /// [`FutureIncompatibilityReason::FutureReleaseError`]. Custom(&'static str), } @@ -490,34 +479,20 @@ impl FutureIncompatibilityReason { | Self::EditionAndFutureReleaseError(e) | Self::EditionAndFutureReleaseSemanticsChange(e) => Some(e), - FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps - | FutureIncompatibilityReason::FutureReleaseErrorReportInDeps + FutureIncompatibilityReason::FutureReleaseError | FutureIncompatibilityReason::FutureReleaseSemanticsChange | FutureIncompatibilityReason::Custom(_) => None, } } - - pub fn has_future_breakage(self) -> bool { - match self { - FutureIncompatibilityReason::FutureReleaseErrorReportInDeps => true, - - FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps - | FutureIncompatibilityReason::FutureReleaseSemanticsChange - | FutureIncompatibilityReason::EditionError(_) - | FutureIncompatibilityReason::EditionSemanticsChange(_) - | FutureIncompatibilityReason::EditionAndFutureReleaseError(_) - | FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(_) - | FutureIncompatibilityReason::Custom(_) => false, - } - } } impl FutureIncompatibleInfo { pub const fn default_fields_for_macro() -> Self { FutureIncompatibleInfo { reference: "", - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseError, explain_reason: true, + report_in_deps: false, } } } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index d5a408fdfa6..341a735f88f 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -299,7 +299,7 @@ pub fn lint_level( let has_future_breakage = future_incompatible.map_or( // Default allow lints trigger too often for testing. sess.opts.unstable_opts.future_incompat_test && lint.default_level != Level::Allow, - |incompat| incompat.reason.has_future_breakage(), + |incompat| incompat.report_in_deps, ); // Convert lint level to error level. @@ -370,8 +370,7 @@ pub fn lint_level( if let Some(future_incompatible) = future_incompatible { let explanation = match future_incompatible.reason { - FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps - | FutureIncompatibilityReason::FutureReleaseErrorReportInDeps => { + FutureIncompatibilityReason::FutureReleaseError => { "this was previously accepted by the compiler but is being phased out; \ it will become a hard error in a future release!" .to_owned() -- cgit 1.4.1-3-g733a5 From ecc7dde80aeee02c6915057620739a2cea3c3e23 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 2 Jun 2025 16:40:10 +0300 Subject: handle stage0 on `Std::check` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/check.rs | 27 ++++++++++++++++++++++----- src/bootstrap/src/core/config/config.rs | 8 ++------ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 922578f309a..b64f0658c0e 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -31,6 +31,8 @@ pub struct Std { } impl Std { + const CRATE_OR_DEPS: &[&str] = &["sysroot", "coretests", "alloctests"]; + pub fn new(target: TargetSelection) -> Self { Self { target, crates: vec![], override_build_kind: None } } @@ -47,11 +49,13 @@ impl Step for Std { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let stage = run.builder.top_stage; - run.crate_or_deps("sysroot") - .crate_or_deps("coretests") - .crate_or_deps("alloctests") - .path("library") - .default_condition(stage != 0) + + let mut run = run; + for c in Std::CRATE_OR_DEPS { + run = run.crate_or_deps(c); + } + + run.path("library").default_condition(stage != 0) } fn make_run(run: RunConfig<'_>) { @@ -66,6 +70,19 @@ impl Step for Std { let compiler = builder.compiler(builder.top_stage, builder.config.build); if builder.top_stage == 0 { + let mut is_explicitly_called = + builder.paths.iter().any(|p| p.starts_with("library") || p.starts_with("std")); + + if !is_explicitly_called { + for c in Std::CRATE_OR_DEPS { + is_explicitly_called = builder.paths.iter().any(|p| p.starts_with(c)); + } + } + + if is_explicitly_called { + eprintln!("WARNING: stage 0 std is precompiled and does nothing during `x check`."); + } + // Reuse the stage0 libstd builder.ensure(compile::Std::new(compiler, target)); return; diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 99e82ba7658..03044d4fc80 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2531,12 +2531,8 @@ impl Config { || bench_stage.is_some(); // See https://github.com/rust-lang/compiler-team/issues/326 config.stage = match config.cmd { - Subcommand::Check { .. } => { - flags.stage.or(check_stage).unwrap_or(0) - } - Subcommand::Clippy { .. } | Subcommand::Fix => { - flags.stage.or(check_stage).unwrap_or(1) - } + Subcommand::Check { .. } => flags.stage.or(check_stage).unwrap_or(0), + Subcommand::Clippy { .. } | Subcommand::Fix => flags.stage.or(check_stage).unwrap_or(1), // `download-rustc` only has a speed-up for stage2 builds. Default to stage2 unless explicitly overridden. Subcommand::Doc { .. } => { flags.stage.or(doc_stage).unwrap_or(if download_rustc { 2 } else { 1 }) -- cgit 1.4.1-3-g733a5 From 9505178d5090447c32f24ed9bbf60645c0a9d733 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 3 Jun 2025 11:03:56 +0300 Subject: run `x check` on mingw-check-2 Signed-off-by: onur-ozkan --- src/ci/docker/host-x86_64/mingw-check-2/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile index 0c75f116aa0..11a66a1c013 100644 --- a/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile @@ -27,6 +27,7 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV SCRIPT \ + python3 ../x.py check && \ python3 ../x.py clippy ci && \ python3 ../x.py test --stage 1 core alloc std test proc_macro && \ # Build both public and internal documentation. -- cgit 1.4.1-3-g733a5 From 49969468b59287f905a001097de66ff9659b7b79 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 3 Jun 2025 09:54:30 +0200 Subject: Add missing 2015 edition directives These tests specifically test 2015 edition behavior, so ensure that they can only be run with this edition --- tests/ui/issues/issue-10806.rs | 1 + tests/ui/issues/issue-12729.rs | 1 + tests/ui/issues/issue-13105.rs | 1 + tests/ui/issues/issue-13775.rs | 1 + tests/ui/issues/issue-15774.rs | 1 + tests/ui/issues/issue-34074.rs | 1 + tests/ui/issues/issue-50571.fixed | 1 + tests/ui/issues/issue-50571.rs | 1 + tests/ui/issues/issue-50571.stderr | 2 +- tests/ui/issues/issue-86756.rs | 1 + tests/ui/issues/issue-86756.stderr | 10 +++++----- tests/ui/lexer/lex-bad-str-literal-as-char-3.rs | 1 + .../lex-bad-str-literal-as-char-3.rust2015.stderr | 2 +- .../lex-bad-str-literal-as-char-3.rust2018.stderr | 2 +- .../lex-bad-str-literal-as-char-3.rust2021.stderr | 4 ++-- tests/ui/lifetimes/bare-trait-object-borrowck.rs | 4 +++- tests/ui/lifetimes/bare-trait-object.rs | 1 + tests/ui/lint/bare-trait-objects-path.rs | 1 + tests/ui/lint/bare-trait-objects-path.stderr | 10 +++++----- tests/ui/lint/lint-pre-expansion-extern-module.rs | 1 + tests/ui/lint/lint-qualification.fixed | 1 + tests/ui/lint/lint-qualification.rs | 1 + tests/ui/lint/lint-qualification.stderr | 18 +++++++++--------- .../use-redundant/use-redundant-prelude-rust-2015.rs | 1 + .../use-redundant-prelude-rust-2015.stderr | 10 +++++----- tests/ui/macros/try-macro.rs | 1 + tests/ui/parser/dyn-trait-compatibility.rs | 2 ++ tests/ui/parser/dyn-trait-compatibility.stderr | 16 ++++++++-------- tests/ui/parser/extern-crate-async.rs | 3 ++- tests/ui/parser/fn-field-parse-error-ice.rs | 1 + tests/ui/parser/fn-field-parse-error-ice.stderr | 6 +++--- tests/ui/parser/issues/issue-114219.rs | 2 ++ tests/ui/parser/issues/issue-114219.stderr | 2 +- tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs | 2 ++ tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr | 6 +++--- tests/ui/proc-macro/trait-fn-args-2015.rs | 1 + 36 files changed, 74 insertions(+), 46 deletions(-) diff --git a/tests/ui/issues/issue-10806.rs b/tests/ui/issues/issue-10806.rs index 72d99ae3a79..31315dc7c93 100644 --- a/tests/ui/issues/issue-10806.rs +++ b/tests/ui/issues/issue-10806.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-pass #![allow(unused_imports)] diff --git a/tests/ui/issues/issue-12729.rs b/tests/ui/issues/issue-12729.rs index 74014981df5..4d45846bc60 100644 --- a/tests/ui/issues/issue-12729.rs +++ b/tests/ui/issues/issue-12729.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ check-pass #![allow(dead_code)] diff --git a/tests/ui/issues/issue-13105.rs b/tests/ui/issues/issue-13105.rs index 0dd78372a26..d119aa9c788 100644 --- a/tests/ui/issues/issue-13105.rs +++ b/tests/ui/issues/issue-13105.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ check-pass trait Foo { diff --git a/tests/ui/issues/issue-13775.rs b/tests/ui/issues/issue-13775.rs index 500ec6782a8..1477dab9e21 100644 --- a/tests/ui/issues/issue-13775.rs +++ b/tests/ui/issues/issue-13775.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ check-pass trait Foo { diff --git a/tests/ui/issues/issue-15774.rs b/tests/ui/issues/issue-15774.rs index 8eb327a0d5e..dadd59cc077 100644 --- a/tests/ui/issues/issue-15774.rs +++ b/tests/ui/issues/issue-15774.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-pass #![deny(warnings)] diff --git a/tests/ui/issues/issue-34074.rs b/tests/ui/issues/issue-34074.rs index 9b3dee11d9b..d642c74d412 100644 --- a/tests/ui/issues/issue-34074.rs +++ b/tests/ui/issues/issue-34074.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ check-pass // Make sure several unnamed function parameters don't conflict with each other diff --git a/tests/ui/issues/issue-50571.fixed b/tests/ui/issues/issue-50571.fixed index 37ed729be81..6d73f17cca4 100644 --- a/tests/ui/issues/issue-50571.fixed +++ b/tests/ui/issues/issue-50571.fixed @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![allow(dead_code)] diff --git a/tests/ui/issues/issue-50571.rs b/tests/ui/issues/issue-50571.rs index 97a042d3ec1..dd840ffe4d1 100644 --- a/tests/ui/issues/issue-50571.rs +++ b/tests/ui/issues/issue-50571.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![allow(dead_code)] diff --git a/tests/ui/issues/issue-50571.stderr b/tests/ui/issues/issue-50571.stderr index 86709410670..9b00fe0f5db 100644 --- a/tests/ui/issues/issue-50571.stderr +++ b/tests/ui/issues/issue-50571.stderr @@ -1,5 +1,5 @@ error[E0642]: patterns aren't allowed in methods without bodies - --> $DIR/issue-50571.rs:5:12 + --> $DIR/issue-50571.rs:6:12 | LL | fn foo([a, b]: [i32; 2]) {} | ^^^^^^ diff --git a/tests/ui/issues/issue-86756.rs b/tests/ui/issues/issue-86756.rs index 7f864eb2850..55a6c144839 100644 --- a/tests/ui/issues/issue-86756.rs +++ b/tests/ui/issues/issue-86756.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 trait Foo {} //~^ ERROR the name `T` is already used for a generic parameter in this item's generic parameters diff --git a/tests/ui/issues/issue-86756.stderr b/tests/ui/issues/issue-86756.stderr index 728d7ea7095..0f68b764850 100644 --- a/tests/ui/issues/issue-86756.stderr +++ b/tests/ui/issues/issue-86756.stderr @@ -1,5 +1,5 @@ error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters - --> $DIR/issue-86756.rs:1:14 + --> $DIR/issue-86756.rs:2:14 | LL | trait Foo {} | - ^ already used @@ -7,13 +7,13 @@ LL | trait Foo {} | first use of `T` error[E0412]: cannot find type `dyn` in this scope - --> $DIR/issue-86756.rs:5:10 + --> $DIR/issue-86756.rs:6:10 | LL | eq:: | ^^^ not found in this scope warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-86756.rs:5:15 + --> $DIR/issue-86756.rs:6:15 | LL | eq:: | ^^^ @@ -27,13 +27,13 @@ LL | eq:: | +++ error[E0107]: missing generics for trait `Foo` - --> $DIR/issue-86756.rs:5:15 + --> $DIR/issue-86756.rs:6:15 | LL | eq:: | ^^^ expected at least 1 generic argument | note: trait defined here, with at least 1 generic parameter: `T` - --> $DIR/issue-86756.rs:1:7 + --> $DIR/issue-86756.rs:2:7 | LL | trait Foo {} | ^^^ - diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs index 52781d9c6d8..5b290899a70 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs @@ -1,4 +1,5 @@ //@ revisions: rust2015 rust2018 rust2021 +//@[rust2015] edition:2015 //@[rust2018] edition:2018 //@[rust2021] edition:2021 fn main() { diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr index 2f92225de1f..be3b114baf9 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr @@ -1,5 +1,5 @@ error[E0762]: unterminated character literal - --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 + --> $DIR/lex-bad-str-literal-as-char-3.rs:6:26 | LL | println!('hello world'); | ^^^ diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr index 2f92225de1f..be3b114baf9 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr @@ -1,5 +1,5 @@ error[E0762]: unterminated character literal - --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 + --> $DIR/lex-bad-str-literal-as-char-3.rs:6:26 | LL | println!('hello world'); | ^^^ diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr index e10046e58e4..605cb66df1c 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr @@ -1,5 +1,5 @@ error: prefix `world` is unknown - --> $DIR/lex-bad-str-literal-as-char-3.rs:5:21 + --> $DIR/lex-bad-str-literal-as-char-3.rs:6:21 | LL | println!('hello world'); | ^^^^^ unknown prefix @@ -12,7 +12,7 @@ LL + println!("hello world"); | error[E0762]: unterminated character literal - --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 + --> $DIR/lex-bad-str-literal-as-char-3.rs:6:26 | LL | println!('hello world'); | ^^^ diff --git a/tests/ui/lifetimes/bare-trait-object-borrowck.rs b/tests/ui/lifetimes/bare-trait-object-borrowck.rs index c54d3effffe..4b81b66118a 100644 --- a/tests/ui/lifetimes/bare-trait-object-borrowck.rs +++ b/tests/ui/lifetimes/bare-trait-object-borrowck.rs @@ -1,5 +1,7 @@ -#![allow(bare_trait_objects)] +//@ edition: 2015 //@ check-pass +#![allow(bare_trait_objects)] + pub struct FormatWith<'a, I, F> { sep: &'a str, /// FormatWith uses interior mutability because Display::fmt takes &self. diff --git a/tests/ui/lifetimes/bare-trait-object.rs b/tests/ui/lifetimes/bare-trait-object.rs index 2feb8a880b1..e74f8ac03ea 100644 --- a/tests/ui/lifetimes/bare-trait-object.rs +++ b/tests/ui/lifetimes/bare-trait-object.rs @@ -1,4 +1,5 @@ // Verify that lifetime resolution correctly accounts for `Fn` bare trait objects. +//@ edition: 2015 //@ check-pass #![allow(bare_trait_objects)] diff --git a/tests/ui/lint/bare-trait-objects-path.rs b/tests/ui/lint/bare-trait-objects-path.rs index 0e2294715cd..9643c48c9b8 100644 --- a/tests/ui/lint/bare-trait-objects-path.rs +++ b/tests/ui/lint/bare-trait-objects-path.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 #![feature(associated_type_defaults)] trait Assoc { diff --git a/tests/ui/lint/bare-trait-objects-path.stderr b/tests/ui/lint/bare-trait-objects-path.stderr index e611abd31f3..25f3e857806 100644 --- a/tests/ui/lint/bare-trait-objects-path.stderr +++ b/tests/ui/lint/bare-trait-objects-path.stderr @@ -1,5 +1,5 @@ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/bare-trait-objects-path.rs:14:5 + --> $DIR/bare-trait-objects-path.rs:15:5 | LL | Dyn::func(); | ^^^ @@ -13,7 +13,7 @@ LL | ::func(); | ++++ + warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/bare-trait-objects-path.rs:17:5 + --> $DIR/bare-trait-objects-path.rs:18:5 | LL | ::Dyn::func(); | ^^^^^ @@ -26,7 +26,7 @@ LL | ::func(); | ++++++ ++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/bare-trait-objects-path.rs:20:5 + --> $DIR/bare-trait-objects-path.rs:21:5 | LL | Dyn::CONST; | ^^^ @@ -39,7 +39,7 @@ LL | ::CONST; | ++++ + warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/bare-trait-objects-path.rs:23:12 + --> $DIR/bare-trait-objects-path.rs:24:12 | LL | let _: Dyn::Ty; | ^^^ @@ -52,7 +52,7 @@ LL | let _: ::Ty; | ++++ + error[E0223]: ambiguous associated type - --> $DIR/bare-trait-objects-path.rs:23:12 + --> $DIR/bare-trait-objects-path.rs:24:12 | LL | let _: Dyn::Ty; | ^^^^^^^ diff --git a/tests/ui/lint/lint-pre-expansion-extern-module.rs b/tests/ui/lint/lint-pre-expansion-extern-module.rs index f1ab0cf3b74..e85261befbc 100644 --- a/tests/ui/lint/lint-pre-expansion-extern-module.rs +++ b/tests/ui/lint/lint-pre-expansion-extern-module.rs @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: -W rust-2018-compatibility +//@ edition: 2015 fn main() {} diff --git a/tests/ui/lint/lint-qualification.fixed b/tests/ui/lint/lint-qualification.fixed index 7c8fd5236e6..04067b6b6ff 100644 --- a/tests/ui/lint/lint-qualification.fixed +++ b/tests/ui/lint/lint-qualification.fixed @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![deny(unused_qualifications)] #![deny(unused_imports)] diff --git a/tests/ui/lint/lint-qualification.rs b/tests/ui/lint/lint-qualification.rs index 009b3080d5c..20c261bf878 100644 --- a/tests/ui/lint/lint-qualification.rs +++ b/tests/ui/lint/lint-qualification.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![deny(unused_qualifications)] #![deny(unused_imports)] diff --git a/tests/ui/lint/lint-qualification.stderr b/tests/ui/lint/lint-qualification.stderr index cefa54a12ae..1e8b8da1e86 100644 --- a/tests/ui/lint/lint-qualification.stderr +++ b/tests/ui/lint/lint-qualification.stderr @@ -1,11 +1,11 @@ error: unnecessary qualification - --> $DIR/lint-qualification.rs:12:5 + --> $DIR/lint-qualification.rs:13:5 | LL | foo::bar(); | ^^^^^^^^ | note: the lint level is defined here - --> $DIR/lint-qualification.rs:2:9 + --> $DIR/lint-qualification.rs:3:9 | LL | #![deny(unused_qualifications)] | ^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL + bar(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:13:5 + --> $DIR/lint-qualification.rs:14:5 | LL | crate::foo::bar(); | ^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL + bar(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:18:13 + --> $DIR/lint-qualification.rs:19:13 | LL | let _ = std::string::String::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL + let _ = String::new(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:20:12 + --> $DIR/lint-qualification.rs:21:12 | LL | let _: std::vec::Vec = std::vec::Vec::::new(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL + let _: Vec = std::vec::Vec::::new(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:20:36 + --> $DIR/lint-qualification.rs:21:36 | LL | let _: std::vec::Vec = std::vec::Vec::::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,19 +64,19 @@ LL + let _: std::vec::Vec = Vec::::new(); | error: unused import: `std::fmt` - --> $DIR/lint-qualification.rs:24:9 + --> $DIR/lint-qualification.rs:25:9 | LL | use std::fmt; | ^^^^^^^^ | note: the lint level is defined here - --> $DIR/lint-qualification.rs:3:9 + --> $DIR/lint-qualification.rs:4:9 | LL | #![deny(unused_imports)] | ^^^^^^^^^^^^^^ error: unnecessary qualification - --> $DIR/lint-qualification.rs:29:13 + --> $DIR/lint-qualification.rs:30:13 | LL | let _ = ::default(); // issue #121999 (modified) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs index 6abe3602abe..7dc9ba0afea 100644 --- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs +++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ check-pass #![warn(redundant_imports)] diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr index 2b0e16a87dc..48d5c275055 100644 --- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr +++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr @@ -1,5 +1,5 @@ warning: the item `Some` is imported redundantly - --> $DIR/use-redundant-prelude-rust-2015.rs:5:5 + --> $DIR/use-redundant-prelude-rust-2015.rs:6:5 | LL | use std::option::Option::Some; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,13 +8,13 @@ LL | use std::option::Option::Some; = note: the item `Some` is already defined here | note: the lint level is defined here - --> $DIR/use-redundant-prelude-rust-2015.rs:2:9 + --> $DIR/use-redundant-prelude-rust-2015.rs:3:9 | LL | #![warn(redundant_imports)] | ^^^^^^^^^^^^^^^^^ warning: the item `None` is imported redundantly - --> $DIR/use-redundant-prelude-rust-2015.rs:6:5 + --> $DIR/use-redundant-prelude-rust-2015.rs:7:5 | LL | use std::option::Option::None; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | use std::option::Option::None; = note: the item `None` is already defined here warning: the item `Ok` is imported redundantly - --> $DIR/use-redundant-prelude-rust-2015.rs:8:5 + --> $DIR/use-redundant-prelude-rust-2015.rs:9:5 | LL | use std::result::Result::Ok; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | use std::result::Result::Ok; = note: the item `Ok` is already defined here warning: the item `Err` is imported redundantly - --> $DIR/use-redundant-prelude-rust-2015.rs:9:5 + --> $DIR/use-redundant-prelude-rust-2015.rs:10:5 | LL | use std::result::Result::Err; | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/macros/try-macro.rs b/tests/ui/macros/try-macro.rs index b579143583e..f6268654cfc 100644 --- a/tests/ui/macros/try-macro.rs +++ b/tests/ui/macros/try-macro.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ edition: 2015 #![allow(deprecated)] // for deprecated `try!()` macro use std::num::{ParseFloatError, ParseIntError}; diff --git a/tests/ui/parser/dyn-trait-compatibility.rs b/tests/ui/parser/dyn-trait-compatibility.rs index 717b14c5941..c6e84284fbe 100644 --- a/tests/ui/parser/dyn-trait-compatibility.rs +++ b/tests/ui/parser/dyn-trait-compatibility.rs @@ -1,3 +1,5 @@ +//@ edition: 2015 + type A0 = dyn; //~^ ERROR cannot find type `dyn` in this scope type A1 = dyn::dyn; diff --git a/tests/ui/parser/dyn-trait-compatibility.stderr b/tests/ui/parser/dyn-trait-compatibility.stderr index 08e0a50010a..a57c033c1e1 100644 --- a/tests/ui/parser/dyn-trait-compatibility.stderr +++ b/tests/ui/parser/dyn-trait-compatibility.stderr @@ -1,47 +1,47 @@ error[E0412]: cannot find type `dyn` in this scope - --> $DIR/dyn-trait-compatibility.rs:1:11 + --> $DIR/dyn-trait-compatibility.rs:3:11 | LL | type A0 = dyn; | ^^^ not found in this scope error[E0412]: cannot find type `dyn` in this scope - --> $DIR/dyn-trait-compatibility.rs:5:11 + --> $DIR/dyn-trait-compatibility.rs:7:11 | LL | type A2 = dyn; | ^^^ not found in this scope error[E0412]: cannot find type `dyn` in this scope - --> $DIR/dyn-trait-compatibility.rs:5:15 + --> $DIR/dyn-trait-compatibility.rs:7:15 | LL | type A2 = dyn; | ^^^ not found in this scope error[E0412]: cannot find type `dyn` in this scope - --> $DIR/dyn-trait-compatibility.rs:5:20 + --> $DIR/dyn-trait-compatibility.rs:7:20 | LL | type A2 = dyn; | ^^^ not found in this scope error[E0412]: cannot find type `dyn` in this scope - --> $DIR/dyn-trait-compatibility.rs:9:11 + --> $DIR/dyn-trait-compatibility.rs:11:11 | LL | type A3 = dyn<::dyn>; | ^^^ not found in this scope error[E0405]: cannot find trait `dyn` in this scope - --> $DIR/dyn-trait-compatibility.rs:9:23 + --> $DIR/dyn-trait-compatibility.rs:11:23 | LL | type A3 = dyn<::dyn>; | ^^^ not found in this scope error[E0412]: cannot find type `dyn` in this scope - --> $DIR/dyn-trait-compatibility.rs:9:16 + --> $DIR/dyn-trait-compatibility.rs:11:16 | LL | type A3 = dyn<::dyn>; | ^^^ not found in this scope error[E0433]: failed to resolve: use of unresolved module or unlinked crate `dyn` - --> $DIR/dyn-trait-compatibility.rs:3:11 + --> $DIR/dyn-trait-compatibility.rs:5:11 | LL | type A1 = dyn::dyn; | ^^^ use of unresolved module or unlinked crate `dyn` diff --git a/tests/ui/parser/extern-crate-async.rs b/tests/ui/parser/extern-crate-async.rs index 529e0f1ab5c..13bd786d092 100644 --- a/tests/ui/parser/extern-crate-async.rs +++ b/tests/ui/parser/extern-crate-async.rs @@ -1,6 +1,7 @@ -// Make sure that we don't parse `extern crate async` +// Make sure that we don't parse `extern crate async` as // the front matter of a function leading us astray. +//@ edition: 2015 //@ check-pass fn main() {} diff --git a/tests/ui/parser/fn-field-parse-error-ice.rs b/tests/ui/parser/fn-field-parse-error-ice.rs index 188257ea53a..f1bc561b89f 100644 --- a/tests/ui/parser/fn-field-parse-error-ice.rs +++ b/tests/ui/parser/fn-field-parse-error-ice.rs @@ -1,4 +1,5 @@ // Regression test for #85794 +//@ edition: 2015 struct Baz { inner : dyn fn () diff --git a/tests/ui/parser/fn-field-parse-error-ice.stderr b/tests/ui/parser/fn-field-parse-error-ice.stderr index 3bf68e8cc04..6f033e2b0c6 100644 --- a/tests/ui/parser/fn-field-parse-error-ice.stderr +++ b/tests/ui/parser/fn-field-parse-error-ice.stderr @@ -1,11 +1,11 @@ error: expected `,`, or `}`, found keyword `fn` - --> $DIR/fn-field-parse-error-ice.rs:4:16 + --> $DIR/fn-field-parse-error-ice.rs:5:16 | LL | inner : dyn fn () | ^ help: try adding a comma: `,` error: expected identifier, found keyword `fn` - --> $DIR/fn-field-parse-error-ice.rs:4:17 + --> $DIR/fn-field-parse-error-ice.rs:5:17 | LL | struct Baz { | --- while parsing this struct @@ -18,7 +18,7 @@ LL | inner : dyn r#fn () | ++ error[E0412]: cannot find type `dyn` in this scope - --> $DIR/fn-field-parse-error-ice.rs:4:13 + --> $DIR/fn-field-parse-error-ice.rs:5:13 | LL | inner : dyn fn () | ^^^ not found in this scope diff --git a/tests/ui/parser/issues/issue-114219.rs b/tests/ui/parser/issues/issue-114219.rs index 332258b628c..3f7e0f685ac 100644 --- a/tests/ui/parser/issues/issue-114219.rs +++ b/tests/ui/parser/issues/issue-114219.rs @@ -1,3 +1,5 @@ +//@ edition: 2015 + fn main() { async move {}; //~^ ERROR `async move` blocks are only allowed in Rust 2018 or later diff --git a/tests/ui/parser/issues/issue-114219.stderr b/tests/ui/parser/issues/issue-114219.stderr index 02323cb99cb..1243ef8b180 100644 --- a/tests/ui/parser/issues/issue-114219.stderr +++ b/tests/ui/parser/issues/issue-114219.stderr @@ -1,5 +1,5 @@ error: `async move` blocks are only allowed in Rust 2018 or later - --> $DIR/issue-114219.rs:2:5 + --> $DIR/issue-114219.rs:4:5 | LL | async move {}; | ^^^^^^^^^^ diff --git a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs index b9e3c5783eb..b78832bbe3d 100644 --- a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs +++ b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs @@ -1,3 +1,5 @@ +//@ edition: 2015 + trait Trait {} fn test(_: &for<'a> dyn Trait) {} diff --git a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr index a012220e8c7..3745cf8b077 100644 --- a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr +++ b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr @@ -1,5 +1,5 @@ error: `for<...>` expected after `dyn`, not before - --> $DIR/recover-hrtb-before-dyn-impl-kw.rs:3:21 + --> $DIR/recover-hrtb-before-dyn-impl-kw.rs:5:21 | LL | fn test(_: &for<'a> dyn Trait) {} | ^^^ @@ -11,7 +11,7 @@ LL + fn test(_: &dyn for<'a> Trait) {} | error: `for<...>` expected after `impl`, not before - --> $DIR/recover-hrtb-before-dyn-impl-kw.rs:6:21 + --> $DIR/recover-hrtb-before-dyn-impl-kw.rs:8:21 | LL | fn test2(_: for<'a> impl Trait) {} | ^^^^ @@ -23,7 +23,7 @@ LL + fn test2(_: impl for<'a> Trait) {} | error: expected identifier, found `>` - --> $DIR/recover-hrtb-before-dyn-impl-kw.rs:10:24 + --> $DIR/recover-hrtb-before-dyn-impl-kw.rs:12:24 | LL | type A2 = dyn dyn>; | ^ expected identifier diff --git a/tests/ui/proc-macro/trait-fn-args-2015.rs b/tests/ui/proc-macro/trait-fn-args-2015.rs index c25bd768efe..010d986a86d 100644 --- a/tests/ui/proc-macro/trait-fn-args-2015.rs +++ b/tests/ui/proc-macro/trait-fn-args-2015.rs @@ -1,6 +1,7 @@ // Unnamed arguments in trait functions can be passed through proc macros on 2015 edition. //@ check-pass +//@ edition: 2015 //@ proc-macro: test-macros.rs #![allow(anonymous_parameters)] -- cgit 1.4.1-3-g733a5 From 59d993b6c7b00ed6300292343271f8c3f9c2164f Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 3 Jun 2025 08:54:46 +0000 Subject: use better default stage for `check::Std` when stage isn't explicit Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/check.rs | 29 +++++++++++++++++++++-------- src/bootstrap/src/lib.rs | 9 ++++++++- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index b64f0658c0e..f30e26d9cc2 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -48,7 +48,12 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let stage = run.builder.top_stage; + let builder = run.builder; + let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 { + builder.top_stage + } else { + 1 + }; let mut run = run; for c in Std::CRATE_OR_DEPS { @@ -66,10 +71,16 @@ impl Step for Std { fn run(self, builder: &Builder<'_>) { builder.require_submodule("library/stdarch", None); + let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 { + builder.top_stage + } else { + 1 + }; + let target = self.target; - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(stage, builder.config.build); - if builder.top_stage == 0 { + if stage == 0 { let mut is_explicitly_called = builder.paths.iter().any(|p| p.starts_with("library") || p.starts_with("std")); @@ -110,6 +121,7 @@ impl Step for Std { let _guard = builder.msg_check( format_args!("library artifacts{}", crate_description(&self.crates)), target, + Some(stage), ); let stamp = build_stamp::libstd_stamp(builder, compiler, target).with_prefix("check"); @@ -162,7 +174,7 @@ impl Step for Std { } let stamp = build_stamp::libstd_stamp(builder, compiler, target).with_prefix("check-test"); - let _guard = builder.msg_check("library test/bench/example targets", target); + let _guard = builder.msg_check("library test/bench/example targets", target, Some(stage)); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } } @@ -263,6 +275,7 @@ impl Step for Rustc { let _guard = builder.msg_check( format_args!("compiler artifacts{}", crate_description(&self.crates)), target, + None, ); let stamp = build_stamp::librustc_stamp(builder, compiler, target).with_prefix("check"); @@ -323,7 +336,7 @@ impl Step for CodegenBackend { .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml"))); rustc_cargo_env(builder, &mut cargo, target, compiler.stage); - let _guard = builder.msg_check(backend, target); + let _guard = builder.msg_check(backend, target, None); let stamp = build_stamp::codegen_backend_stamp(builder, compiler, target, backend) .with_prefix("check"); @@ -390,7 +403,7 @@ impl Step for RustAnalyzer { let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target)) .with_prefix("rust-analyzer-check"); - let _guard = builder.msg_check("rust-analyzer artifacts", target); + let _guard = builder.msg_check("rust-analyzer artifacts", target, None); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } } @@ -453,7 +466,7 @@ impl Step for Compiletest { let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, self.target)) .with_prefix("compiletest-check"); - let _guard = builder.msg_check("compiletest artifacts", self.target); + let _guard = builder.msg_check("compiletest artifacts", self.target, None); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } } @@ -531,7 +544,7 @@ fn run_tool_check_step( let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target)) .with_prefix(&format!("{}-check", step_type_name.to_lowercase())); - let _guard = builder.msg_check(format!("{display_name} artifacts"), target); + let _guard = builder.msg_check(format!("{display_name} artifacts"), target, None); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index e4643653d97..cfb968f79ba 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1104,8 +1104,15 @@ Executed at: {executed_at}"#, &self, what: impl Display, target: impl Into>, + custom_stage: Option, ) -> Option { - self.msg(Kind::Check, self.config.stage, what, self.config.build, target) + self.msg( + Kind::Check, + custom_stage.unwrap_or(self.config.stage), + what, + self.config.build, + target, + ) } #[must_use = "Groups should not be dropped until the Step finishes running"] -- cgit 1.4.1-3-g733a5 From 00a88b903d3728517dff8f0044160d18a0322ab4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 3 Jun 2025 10:00:11 +0000 Subject: Remove get_dbg_loc from DebugInfoBuilderMethods It is only used within cg_llvm. --- compiler/rustc_codegen_gcc/src/debuginfo.rs | 4 ---- compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | 10 ++++++---- compiler/rustc_codegen_ssa/src/traits/debuginfo.rs | 1 - 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index e0597d0030d..3a265fbc64f 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -52,10 +52,6 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { fn clear_dbg_loc(&mut self) { self.location = None; } - - fn get_dbg_loc(&self) -> Option { - self.location - } } /// Generate the `debug_context` in an MIR Body. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index c5085927923..5ca2505cec4 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -147,6 +147,12 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { } } +impl<'ll> Builder<'_, 'll, '_> { + pub(crate) fn get_dbg_loc(&self) -> Option<&'ll DILocation> { + unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) } + } +} + impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). @@ -209,10 +215,6 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { } } - fn get_dbg_loc(&self) -> Option<&'ll DILocation> { - unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) } - } - fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { gdb::insert_reference_to_gdb_debug_scripts_section_global(self) } diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index 30d77c206a5..b9d4950e0ad 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -81,7 +81,6 @@ pub trait DebugInfoBuilderMethods: BackendTypes { ); fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation); fn clear_dbg_loc(&mut self); - fn get_dbg_loc(&self) -> Option; fn insert_reference_to_gdb_debug_scripts_section_global(&mut self); fn set_var_name(&mut self, value: Self::Value, name: &str); } -- cgit 1.4.1-3-g733a5 From 2e8401ae5f293070f57b964252db7b38d3f2fc2a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 3 Jun 2025 10:00:56 +0000 Subject: Remove type_test from IntrinsicCallBuilderMethods It is only used within cg_llvm. --- compiler/rustc_codegen_gcc/src/intrinsic/mod.rs | 5 ----- compiler/rustc_codegen_llvm/src/builder.rs | 7 +++++-- compiler/rustc_codegen_llvm/src/intrinsic.rs | 7 ------- compiler/rustc_codegen_ssa/src/traits/intrinsic.rs | 2 -- 4 files changed, 5 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 73be25ba92b..9e05b8f23aa 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -524,11 +524,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc cond } - fn type_test(&mut self, _pointer: Self::Value, _typeid: Self::Value) -> Self::Value { - // Unsupported. - self.context.new_rvalue_from_int(self.int_type, 0) - } - fn type_checked_load( &mut self, _llvtable: Self::Value, diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 167678c2ff1..ec006b59192 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1815,8 +1815,11 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap(); let dbg_loc = self.get_dbg_loc(); - // Test whether the function pointer is associated with the type identifier. - let cond = self.type_test(llfn, typeid_metadata); + // Test whether the function pointer is associated with the type identifier using the + // llvm.type.test intrinsic. The LowerTypeTests link-time optimization pass replaces + // calls to this intrinsic with code to test type membership. + let typeid = self.get_metadata_value(typeid_metadata); + let cond = self.call_intrinsic("llvm.type.test", &[llfn, typeid]); let bb_pass = self.append_sibling_block("type_test.pass"); let bb_fail = self.append_sibling_block("type_test.fail"); self.cond_br(cond, bb_pass, bb_fail); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 989752eb78e..10697b9a71f 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -636,13 +636,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } - fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value { - // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time - // optimization pass replaces calls to this intrinsic with code to test type membership. - let typeid = self.get_metadata_value(typeid); - self.call_intrinsic("llvm.type.test", &[pointer, typeid]) - } - fn type_checked_load( &mut self, llvtable: &'ll Value, diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index a07c569a032..7d0c6be4c65 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -22,8 +22,6 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes { fn abort(&mut self); fn assume(&mut self, val: Self::Value); fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; - /// Trait method used to test whether a given pointer is associated with a type identifier. - fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value; /// Trait method used to load a function while testing if it is associated with a type /// identifier. fn type_checked_load( -- cgit 1.4.1-3-g733a5 From aca36fd12a3277ce17eb94e4e89567843bf137f7 Mon Sep 17 00:00:00 2001 From: Amanda Stjerna Date: Tue, 29 Apr 2025 17:12:12 +0200 Subject: Move placeholder handling to a proper preprocessing step This commit breaks out the logic of placheolder rewriting into its own preprocessing step. The only functional change from this is that the preprocessing step (where extra `r: 'static` constraints are added) is performed upstream of Polonius legacy, finally affecting Polonius. That is mostly a by-product, though. --- compiler/rustc_borrowck/src/constraints/mod.rs | 110 +----- .../rustc_borrowck/src/eliminate_placeholders.rs | 371 +++++++++++++++++++++ compiler/rustc_borrowck/src/lib.rs | 1 + compiler/rustc_borrowck/src/nll.rs | 17 +- compiler/rustc_borrowck/src/polonius/legacy/mod.rs | 6 +- compiler/rustc_borrowck/src/region_infer/mod.rs | 208 ++---------- 6 files changed, 414 insertions(+), 299 deletions(-) create mode 100644 compiler/rustc_borrowck/src/eliminate_placeholders.rs diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index 514bbfe359b..99ddccabd15 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -5,11 +5,9 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo}; use rustc_span::Span; -use tracing::{debug, instrument}; +use tracing::debug; -use crate::region_infer::{AnnotatedSccs, ConstraintSccs, RegionDefinition, SccAnnotations}; use crate::type_check::Locations; -use crate::universal_regions::UniversalRegions; pub(crate) mod graph; @@ -53,112 +51,6 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { ) -> &IndexSlice> { &self.outlives } - - /// Computes cycles (SCCs) in the graph of regions. In particular, - /// find all regions R1, R2 such that R1: R2 and R2: R1 and group - /// them into an SCC, and find the relationships between SCCs. - pub(crate) fn compute_sccs( - &self, - static_region: RegionVid, - definitions: &IndexVec>, - ) -> AnnotatedSccs { - let constraint_graph = self.graph(definitions.len()); - let region_graph = &constraint_graph.region_graph(self, static_region); - let mut annotation_visitor = SccAnnotations::new(definitions); - ( - ConstraintSccs::new_with_annotation(®ion_graph, &mut annotation_visitor), - annotation_visitor.scc_to_annotation, - ) - } - - /// This method handles Universe errors by rewriting the constraint - /// graph. For each strongly connected component in the constraint - /// graph such that there is a series of constraints - /// A: B: C: ... : X where - /// A's universe is smaller than X's and A is a placeholder, - /// add a constraint that A: 'static. This is a safe upper bound - /// in the face of borrow checker/trait solver limitations that will - /// eventually go away. - /// - /// For a more precise definition, see the documentation for - /// [`crate::region_infer::RegionTracker`]. - /// - /// This edge case used to be handled during constraint propagation - /// by iterating over the strongly connected components in the constraint - /// graph while maintaining a set of bookkeeping mappings similar - /// to what is stored in `RegionTracker` and manually adding 'static as - /// needed. - /// - /// It was rewritten as part of the Polonius project with the goal of moving - /// higher-kindedness concerns out of the path of the borrow checker, - /// for two reasons: - /// - /// 1. Implementing Polonius is difficult enough without also - /// handling them. - /// 2. The long-term goal is to handle higher-kinded concerns - /// in the trait solver, where they belong. This avoids - /// logic duplication and allows future trait solvers - /// to compute better bounds than for example our - /// "must outlive 'static" here. - /// - /// This code is a stop-gap measure in preparation for the future trait solver. - /// - /// Every constraint added by this method is an - /// internal `IllegalUniverse` constraint. - #[instrument(skip(self, universal_regions, definitions))] - pub(crate) fn add_outlives_static( - &mut self, - universal_regions: &UniversalRegions<'tcx>, - definitions: &IndexVec>, - ) -> AnnotatedSccs { - let fr_static = universal_regions.fr_static; - let (sccs, annotations) = self.compute_sccs(fr_static, definitions); - - // Changed to `true` if we added any constraints to `self` and need to - // recompute SCCs. - let mut added_constraints = false; - - for scc in sccs.all_sccs() { - // No point in adding 'static: 'static! - // This micro-optimisation makes somewhat sense - // because static outlives *everything*. - if scc == sccs.scc(fr_static) { - continue; - } - - let annotation = annotations[scc]; - - // If this SCC participates in a universe violation, - // e.g. if it reaches a region with a universe smaller than - // the largest region reached, add a requirement that it must - // outlive `'static`. - if annotation.has_incompatible_universes() { - // Optimisation opportunity: this will add more constraints than - // needed for correctness, since an SCC upstream of another with - // a universe violation will "infect" its downstream SCCs to also - // outlive static. - added_constraints = true; - let scc_representative_outlives_static = OutlivesConstraint { - sup: annotation.representative, - sub: fr_static, - category: ConstraintCategory::IllegalUniverse, - locations: Locations::All(rustc_span::DUMMY_SP), - span: rustc_span::DUMMY_SP, - variance_info: VarianceDiagInfo::None, - from_closure: false, - }; - self.push(scc_representative_outlives_static); - } - } - - if added_constraints { - // We changed the constraint set and so must recompute SCCs. - self.compute_sccs(fr_static, definitions) - } else { - // If we didn't add any back-edges; no more work needs doing - (sccs, annotations) - } - } } impl<'tcx> Index for OutlivesConstraintSet<'tcx> { diff --git a/compiler/rustc_borrowck/src/eliminate_placeholders.rs b/compiler/rustc_borrowck/src/eliminate_placeholders.rs new file mode 100644 index 00000000000..e8e1acbd7a5 --- /dev/null +++ b/compiler/rustc_borrowck/src/eliminate_placeholders.rs @@ -0,0 +1,371 @@ +//! Logic for lowering higher-kinded outlives constraints +//! (with placeholders and universes) and turn them into regular +//! outlives constraints. +//! +//! This logic is provisional and should be removed once the trait +//! solver can handle this kind of constraint. +use rustc_data_structures::frozen::Frozen; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::graph::scc; +use rustc_data_structures::graph::scc::Sccs; +use rustc_index::IndexVec; +use rustc_middle::mir::ConstraintCategory; +use rustc_middle::ty::{RegionVid, UniverseIndex}; +use tracing::debug; + +use crate::constraints::{ConstraintSccIndex, OutlivesConstraintSet}; +use crate::consumers::OutlivesConstraint; +use crate::diagnostics::UniverseInfo; +use crate::member_constraints::MemberConstraintSet; +use crate::region_infer::values::{LivenessValues, PlaceholderIndices}; +use crate::region_infer::{ConstraintSccs, RegionDefinition, TypeTest}; +use crate::ty::VarianceDiagInfo; +use crate::type_check::free_region_relations::UniversalRegionRelations; +use crate::type_check::{Locations, MirTypeckRegionConstraints}; +use crate::universal_regions::UniversalRegions; +use crate::{BorrowckInferCtxt, NllRegionVariableOrigin}; + +/// A set of outlives constraints after rewriting to remove +/// higher-kinded constraints. +pub(crate) struct LoweredConstraints<'tcx> { + pub(crate) constraint_sccs: Sccs, + pub(crate) definitions: Frozen>>, + pub(crate) scc_annotations: IndexVec, + pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>, + pub(crate) outlives_constraints: OutlivesConstraintSet<'tcx>, + pub(crate) type_tests: Vec>, + pub(crate) liveness_constraints: LivenessValues, + pub(crate) universe_causes: FxIndexMap>, + pub(crate) placeholder_indices: PlaceholderIndices, +} + +impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> { + pub(crate) fn init(definitions: &'d IndexVec>) -> Self { + Self { scc_to_annotation: IndexVec::new(), definitions } + } +} + +/// A Visitor for SCC annotation construction. +pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> { + pub(crate) scc_to_annotation: IndexVec, + definitions: &'d IndexVec>, +} + +impl scc::Annotations for SccAnnotations<'_, '_, RegionTracker> { + fn new(&self, element: RegionVid) -> RegionTracker { + RegionTracker::new(element, &self.definitions[element]) + } + + fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: RegionTracker) { + let idx = self.scc_to_annotation.push(annotation); + assert!(idx == scc); + } + + type Ann = RegionTracker; + type SccIdx = ConstraintSccIndex; +} + +/// An annotation for region graph SCCs that tracks +/// the values of its elements. This annotates a single SCC. +#[derive(Copy, Debug, Clone)] +pub(crate) struct RegionTracker { + /// The largest universe of a placeholder reached from this SCC. + /// This includes placeholders within this SCC. + max_placeholder_universe_reached: UniverseIndex, + + /// The smallest universe index reachable form the nodes of this SCC. + min_reachable_universe: UniverseIndex, + + /// The representative Region Variable Id for this SCC. We prefer + /// placeholders over existentially quantified variables, otherwise + /// it's the one with the smallest Region Variable ID. + pub(crate) representative: RegionVid, + + /// Is the current representative a placeholder? + representative_is_placeholder: bool, + + /// Is the current representative existentially quantified? + representative_is_existential: bool, +} + +impl RegionTracker { + pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self { + let (representative_is_placeholder, representative_is_existential) = match definition.origin + { + NllRegionVariableOrigin::FreeRegion => (false, false), + NllRegionVariableOrigin::Placeholder(_) => (true, false), + NllRegionVariableOrigin::Existential { .. } => (false, true), + }; + + let placeholder_universe = + if representative_is_placeholder { definition.universe } else { UniverseIndex::ROOT }; + + Self { + max_placeholder_universe_reached: placeholder_universe, + min_reachable_universe: definition.universe, + representative: rvid, + representative_is_placeholder, + representative_is_existential, + } + } + + /// The smallest-indexed universe reachable from and/or in this SCC. + pub(crate) fn min_universe(self) -> UniverseIndex { + self.min_reachable_universe + } + + fn merge_min_max_seen(&mut self, other: &Self) { + self.max_placeholder_universe_reached = std::cmp::max( + self.max_placeholder_universe_reached, + other.max_placeholder_universe_reached, + ); + + self.min_reachable_universe = + std::cmp::min(self.min_reachable_universe, other.min_reachable_universe); + } + + /// Returns `true` if during the annotated SCC reaches a placeholder + /// with a universe larger than the smallest reachable one, `false` otherwise. + pub(crate) fn has_incompatible_universes(&self) -> bool { + self.min_universe().cannot_name(self.max_placeholder_universe_reached) + } + + /// Determine if the tracked universes of the two SCCs + /// are compatible. + pub(crate) fn universe_compatible_with(&self, other: Self) -> bool { + self.min_universe().can_name(other.min_universe()) + || self.min_universe().can_name(other.max_placeholder_universe_reached) + } +} + +impl scc::Annotation for RegionTracker { + fn merge_scc(mut self, mut other: Self) -> Self { + // Prefer any placeholder over any existential + if other.representative_is_placeholder && self.representative_is_existential { + other.merge_min_max_seen(&self); + return other; + } + + if self.representative_is_placeholder && other.representative_is_existential + || (self.representative <= other.representative) + { + self.merge_min_max_seen(&other); + return self; + } + other.merge_min_max_seen(&self); + other + } + + fn merge_reached(mut self, other: Self) -> Self { + // No update to in-component values, only add seen values. + self.merge_min_max_seen(&other); + self + } +} + +/// Determines if the region variable definitions contain +/// placeholers, and compute them for later use. +fn region_definitions<'tcx>( + universal_regions: &UniversalRegions<'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, +) -> (Frozen>>, bool) { + let var_infos = infcx.get_region_var_infos(); + // Create a RegionDefinition for each inference variable. This happens here because + // it allows us to sneak in a cheap check for placeholders. Otherwise, its proper home + // is in `RegionInferenceContext::new()`, probably. + let mut definitions = IndexVec::with_capacity(var_infos.len()); + let mut has_placeholders = false; + + for info in var_infos.iter() { + let definition = RegionDefinition::new(info); + has_placeholders |= matches!(definition.origin, NllRegionVariableOrigin::Placeholder(_)); + definitions.push(definition); + } + + // Add external names from universal regions in fun function definitions. + for (external_name, variable) in universal_regions.named_universal_regions_iter() { + debug!("region {:?} has external name {:?}", variable, external_name); + definitions[variable].external_name = Some(external_name); + } + (Frozen::freeze(definitions), has_placeholders) +} + +/// This method handles Universe errors by rewriting the constraint +/// graph. For each strongly connected component in the constraint +/// graph such that there is a series of constraints +/// A: B: C: ... : X where +/// A's universe is smaller than X's and A is a placeholder, +/// add a constraint that A: 'static. This is a safe upper bound +/// in the face of borrow checker/trait solver limitations that will +/// eventually go away. +/// +/// For a more precise definition, see the documentation for +/// [`RegionTracker`] and its methods!. +/// +/// Since universes can also be involved in errors (if one placeholder +/// transitively outlives another), this function also flags those. +/// +/// Additionally, it similarly rewrites type-tests. +/// +/// This edge case used to be handled during constraint propagation +/// by iterating over the strongly connected components in the constraint +/// graph while maintaining a set of bookkeeping mappings similar +/// to what is stored in `RegionTracker` and manually adding 'sttaic as +/// needed. +/// +/// It was rewritten as part of the Polonius project with the goal of moving +/// higher-kindedness concerns out of the path of the borrow checker, +/// for two reasons: +/// +/// 1. Implementing Polonius is difficult enough without also +/// handling them. +/// 2. The long-term goal is to handle higher-kinded concerns +/// in the trait solver, where they belong. This avoids +/// logic duplication and allows future trait solvers +/// to compute better bounds than for example our +/// "must outlive 'static" here. +/// +/// This code is a stop-gap measure in preparation for the future trait solver. +/// +/// Every constraint added by this method is an internal `IllegalUniverse` constraint. +pub(crate) fn rewrite_higher_kinded_outlives_as_constraints<'tcx>( + constraints: MirTypeckRegionConstraints<'tcx>, + universal_region_relations: &Frozen>, + infcx: &BorrowckInferCtxt<'tcx>, +) -> LoweredConstraints<'tcx> { + let universal_regions = &universal_region_relations.universal_regions; + let (definitions, has_placeholders) = region_definitions(universal_regions, infcx); + + let MirTypeckRegionConstraints { + placeholder_indices, + placeholder_index_to_region: _, + liveness_constraints, + mut outlives_constraints, + mut member_constraints, + universe_causes, + type_tests, + } = constraints; + + if let Some(guar) = universal_regions.tainted_by_errors() { + debug!("Universal regions tainted by errors; removing constraints!"); + // Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all + // outlives bounds that we may end up checking. + outlives_constraints = Default::default(); + member_constraints = Default::default(); + + // Also taint the entire scope. + infcx.set_tainted_by_errors(guar); + } + + let fr_static = universal_regions.fr_static; + let compute_sccs = + |constraints: &OutlivesConstraintSet<'tcx>, + annotations: &mut SccAnnotations<'_, 'tcx, RegionTracker>| { + ConstraintSccs::new_with_annotation( + &constraints.graph(definitions.len()).region_graph(constraints, fr_static), + annotations, + ) + }; + + // This code structure is a bit convoluted because it allows for a planned + // future change where the early return here has a different type of annotation + // that does much less work. + if !has_placeholders { + debug!("No placeholder regions found; skipping rewriting logic!"); + let mut scc_annotations = SccAnnotations::init(&definitions); + let constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations); + + return LoweredConstraints { + type_tests, + member_constraints, + constraint_sccs, + scc_annotations: scc_annotations.scc_to_annotation, + definitions, + outlives_constraints, + liveness_constraints, + universe_causes, + placeholder_indices, + }; + } + debug!("Placeholders present; activating placeholder handling logic!"); + + let mut annotations = SccAnnotations::init(&definitions); + let sccs = compute_sccs(&outlives_constraints, &mut annotations); + + let outlives_static = + rewrite_outlives(&sccs, &annotations, fr_static, &mut outlives_constraints); + + let (sccs, scc_annotations) = if !outlives_static.is_empty() { + debug!("The following SCCs had :'static constraints added: {:?}", outlives_static); + let mut annotations = SccAnnotations::init(&definitions); + + // We changed the constraint set and so must recompute SCCs. + // Optimisation opportunity: if we can add them incrementally (and that's + // possible because edges to 'static always only merge SCCs into 'static), + // we would potentially save a lot of work here. + (compute_sccs(&outlives_constraints, &mut annotations), annotations.scc_to_annotation) + } else { + // If we didn't add any back-edges; no more work needs doing + debug!("No constraints rewritten!"); + (sccs, annotations.scc_to_annotation) + }; + + LoweredConstraints { + constraint_sccs: sccs, + definitions, + scc_annotations, + member_constraints, + outlives_constraints, + type_tests, + liveness_constraints, + universe_causes, + placeholder_indices, + } +} + +fn rewrite_outlives<'tcx>( + sccs: &Sccs, + annotations: &SccAnnotations<'_, '_, RegionTracker>, + fr_static: RegionVid, + outlives_constraints: &mut OutlivesConstraintSet<'tcx>, +) -> FxHashSet { + // Changed to `true` if we added any constraints to `self` and need to + // recompute SCCs. + let mut outlives_static = FxHashSet::default(); + + let annotations = &annotations.scc_to_annotation; + + for scc in sccs.all_sccs() { + // No point in adding 'static: 'static! + // This micro-optimisation makes somewhat sense + // because static outlives *everything*. + if scc == sccs.scc(fr_static) { + continue; + } + + let annotation = annotations[scc]; + + // If this SCC participates in a universe violation, + // e.g. if it reaches a region with a universe smaller than + // the largest region reached, add a requirement that it must + // outlive `'static`. + if annotation.has_incompatible_universes() { + // Optimisation opportunity: this will add more constraints than + // needed for correctness, since an SCC upstream of another with + // a universe violation will "infect" its downstream SCCs to also + // outlive static. + outlives_static.insert(scc); + let scc_representative_outlives_static = OutlivesConstraint { + sup: annotation.representative, + sub: fr_static, + category: ConstraintCategory::IllegalUniverse, + locations: Locations::All(rustc_span::DUMMY_SP), + span: rustc_span::DUMMY_SP, + variance_info: VarianceDiagInfo::None, + from_closure: false, + }; + outlives_constraints.push(scc_representative_outlives_static); + } + } + outlives_static +} diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 44af1b76539..edf5494e886 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -75,6 +75,7 @@ mod constraints; mod dataflow; mod def_use; mod diagnostics; +mod eliminate_placeholders; mod member_constraints; mod nll; mod path_utils; diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index fe899bb054f..9b1a5df8d06 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -22,6 +22,7 @@ use tracing::{debug, instrument}; use crate::borrow_set::BorrowSet; use crate::consumers::ConsumerOptions; use crate::diagnostics::RegionErrors; +use crate::eliminate_placeholders::rewrite_higher_kinded_outlives_as_constraints; use crate::polonius::PoloniusDiagnosticsContext; use crate::polonius::legacy::{ PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput, @@ -117,6 +118,12 @@ pub(crate) fn compute_regions<'a, 'tcx>( Rc::clone(&location_map), ); + let lowered_constraints = rewrite_higher_kinded_outlives_as_constraints( + constraints, + &universal_region_relations, + infcx, + ); + // If requested, emit legacy polonius facts. polonius::legacy::emit_facts( &mut polonius_facts, @@ -126,11 +133,15 @@ pub(crate) fn compute_regions<'a, 'tcx>( borrow_set, move_data, &universal_region_relations, - &constraints, + &lowered_constraints, ); - let mut regioncx = - RegionInferenceContext::new(infcx, constraints, universal_region_relations, location_map); + let mut regioncx = RegionInferenceContext::new( + infcx, + lowered_constraints, + universal_region_relations, + location_map, + ); // If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints // and use them to compute loan liveness. diff --git a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs index 95820c07a02..67da43ca578 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs @@ -13,7 +13,7 @@ use tracing::debug; use crate::borrow_set::BorrowSet; use crate::constraints::OutlivesConstraint; -use crate::type_check::MirTypeckRegionConstraints; +use crate::eliminate_placeholders::LoweredConstraints; use crate::type_check::free_region_relations::UniversalRegionRelations; use crate::universal_regions::UniversalRegions; @@ -43,7 +43,7 @@ pub(crate) fn emit_facts<'tcx>( borrow_set: &BorrowSet<'tcx>, move_data: &MoveData<'tcx>, universal_region_relations: &UniversalRegionRelations<'tcx>, - constraints: &MirTypeckRegionConstraints<'tcx>, + constraints: &LoweredConstraints<'tcx>, ) { let Some(facts) = facts else { // We don't do anything if there are no facts to fill. @@ -203,7 +203,7 @@ pub(crate) fn emit_drop_facts<'tcx>( fn emit_outlives_facts<'tcx>( facts: &mut PoloniusFacts, location_table: &PoloniusLocationTable, - constraints: &MirTypeckRegionConstraints<'tcx>, + constraints: &LoweredConstraints<'tcx>, ) { facts.subset_base.extend(constraints.outlives_constraints.outlives().iter().flat_map( |constraint: &OutlivesConstraint<'_>| { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index b4ff3d66f3d..cfad071460b 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -4,12 +4,14 @@ use std::rc::Rc; use rustc_data_structures::binary_search_util; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::graph::scc::{self, Sccs}; +use rustc_data_structures::graph::scc::Sccs; use rustc_errors::Diag; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_index::IndexVec; use rustc_infer::infer::outlives::test_type_match; -use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound, VerifyIfEq}; +use rustc_infer::infer::region_constraints::{ + GenericKind, RegionVariableInfo, VerifyBound, VerifyIfEq, +}; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; use rustc_middle::bug; use rustc_middle::mir::{ @@ -27,13 +29,14 @@ use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph}; use crate::constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet}; use crate::dataflow::BorrowIndex; use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo}; +use crate::eliminate_placeholders::{LoweredConstraints, RegionTracker}; use crate::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}; use crate::polonius::LiveLoans; use crate::polonius::legacy::PoloniusOutput; use crate::region_infer::reverse_sccs::ReverseSccGraph; use crate::region_infer::values::{LivenessValues, RegionElement, RegionValues, ToElementIndex}; +use crate::type_check::Locations; use crate::type_check::free_region_relations::UniversalRegionRelations; -use crate::type_check::{Locations, MirTypeckRegionConstraints}; use crate::universal_regions::UniversalRegions; use crate::{ BorrowckInferCtxt, ClosureOutlivesRequirement, ClosureOutlivesSubject, @@ -48,124 +51,6 @@ mod reverse_sccs; pub(crate) mod values; pub(crate) type ConstraintSccs = Sccs; -pub(crate) type AnnotatedSccs = (ConstraintSccs, IndexVec); - -/// An annotation for region graph SCCs that tracks -/// the values of its elements. This annotates a single SCC. -#[derive(Copy, Debug, Clone)] -pub(crate) struct RegionTracker { - /// The largest universe of a placeholder reached from this SCC. - /// This includes placeholders within this SCC. - max_placeholder_universe_reached: UniverseIndex, - - /// The smallest universe index reachable form the nodes of this SCC. - min_reachable_universe: UniverseIndex, - - /// The representative Region Variable Id for this SCC. We prefer - /// placeholders over existentially quantified variables, otherwise - /// it's the one with the smallest Region Variable ID. - pub(crate) representative: RegionVid, - - /// Is the current representative a placeholder? - representative_is_placeholder: bool, - - /// Is the current representative existentially quantified? - representative_is_existential: bool, -} - -impl scc::Annotation for RegionTracker { - fn merge_scc(mut self, mut other: Self) -> Self { - // Prefer any placeholder over any existential - if other.representative_is_placeholder && self.representative_is_existential { - other.merge_min_max_seen(&self); - return other; - } - - if self.representative_is_placeholder && other.representative_is_existential - || (self.representative <= other.representative) - { - self.merge_min_max_seen(&other); - return self; - } - other.merge_min_max_seen(&self); - other - } - - fn merge_reached(mut self, other: Self) -> Self { - // No update to in-component values, only add seen values. - self.merge_min_max_seen(&other); - self - } -} - -/// A Visitor for SCC annotation construction. -pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> { - pub(crate) scc_to_annotation: IndexVec, - definitions: &'d IndexVec>, -} - -impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> { - pub(crate) fn new(definitions: &'d IndexVec>) -> Self { - Self { scc_to_annotation: IndexVec::new(), definitions } - } -} - -impl scc::Annotations for SccAnnotations<'_, '_, RegionTracker> { - fn new(&self, element: RegionVid) -> RegionTracker { - RegionTracker::new(element, &self.definitions[element]) - } - - fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: RegionTracker) { - let idx = self.scc_to_annotation.push(annotation); - assert!(idx == scc); - } - - type Ann = RegionTracker; - type SccIdx = ConstraintSccIndex; -} - -impl RegionTracker { - pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self { - let (representative_is_placeholder, representative_is_existential) = match definition.origin - { - NllRegionVariableOrigin::FreeRegion => (false, false), - NllRegionVariableOrigin::Placeholder(_) => (true, false), - NllRegionVariableOrigin::Existential { .. } => (false, true), - }; - - let placeholder_universe = - if representative_is_placeholder { definition.universe } else { UniverseIndex::ROOT }; - - Self { - max_placeholder_universe_reached: placeholder_universe, - min_reachable_universe: definition.universe, - representative: rvid, - representative_is_placeholder, - representative_is_existential, - } - } - - /// The smallest-indexed universe reachable from and/or in this SCC. - fn min_universe(self) -> UniverseIndex { - self.min_reachable_universe - } - - fn merge_min_max_seen(&mut self, other: &Self) { - self.max_placeholder_universe_reached = std::cmp::max( - self.max_placeholder_universe_reached, - other.max_placeholder_universe_reached, - ); - - self.min_reachable_universe = - std::cmp::min(self.min_reachable_universe, other.min_reachable_universe); - } - - /// Returns `true` if during the annotated SCC reaches a placeholder - /// with a universe larger than the smallest reachable one, `false` otherwise. - pub(crate) fn has_incompatible_universes(&self) -> bool { - self.min_universe().cannot_name(self.max_placeholder_universe_reached) - } -} pub struct RegionInferenceContext<'tcx> { /// Contains the definition for every region variable. Region @@ -413,26 +298,6 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) { debug!("SCC edges {:#?}", scc_node_to_edges); } -fn create_definitions<'tcx>( - infcx: &BorrowckInferCtxt<'tcx>, - universal_regions: &UniversalRegions<'tcx>, -) -> Frozen>> { - // Create a RegionDefinition for each inference variable. - let mut definitions: IndexVec<_, _> = infcx - .get_region_var_infos() - .iter() - .map(|info| RegionDefinition::new(info.universe, info.origin)) - .collect(); - - // Add the external name for all universal regions. - for (external_name, variable) in universal_regions.named_universal_regions_iter() { - debug!("region {variable:?} has external name {external_name:?}"); - definitions[variable].external_name = Some(external_name); - } - - Frozen::freeze(definitions) -} - impl<'tcx> RegionInferenceContext<'tcx> { /// Creates a new region inference context with a total of /// `num_region_variables` valid inference variables; the first N @@ -443,42 +308,30 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// of constraints produced by the MIR type check. pub(crate) fn new( infcx: &BorrowckInferCtxt<'tcx>, - constraints: MirTypeckRegionConstraints<'tcx>, + lowered_constraints: LoweredConstraints<'tcx>, universal_region_relations: Frozen>, location_map: Rc, ) -> Self { let universal_regions = &universal_region_relations.universal_regions; - let MirTypeckRegionConstraints { - placeholder_indices, - placeholder_index_to_region: _, + + let LoweredConstraints { + constraint_sccs, + definitions, + outlives_constraints, + scc_annotations, + type_tests, liveness_constraints, - mut outlives_constraints, - mut member_constraints, universe_causes, - type_tests, - } = constraints; + placeholder_indices, + member_constraints, + } = lowered_constraints; debug!("universal_regions: {:#?}", universal_region_relations.universal_regions); debug!("outlives constraints: {:#?}", outlives_constraints); debug!("placeholder_indices: {:#?}", placeholder_indices); debug!("type tests: {:#?}", type_tests); - if let Some(guar) = universal_region_relations.universal_regions.tainted_by_errors() { - // Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all - // outlives bounds that we may end up checking. - outlives_constraints = Default::default(); - member_constraints = Default::default(); - - // Also taint the entire scope. - infcx.set_tainted_by_errors(guar); - } - - let definitions = create_definitions(infcx, &universal_regions); - - let (constraint_sccs, scc_annotations) = - outlives_constraints.add_outlives_static(&universal_regions, &definitions); - let constraints = Frozen::freeze(outlives_constraints); - let constraint_graph = Frozen::freeze(constraints.graph(definitions.len())); + let constraint_graph = Frozen::freeze(outlives_constraints.graph(definitions.len())); if cfg!(debug_assertions) { sccs_info(infcx, &constraint_sccs); @@ -498,7 +351,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut result = Self { definitions, liveness_constraints, - constraints, + constraints: Frozen::freeze(outlives_constraints), constraint_graph, constraint_sccs, scc_annotations, @@ -904,20 +757,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// in `scc_a`. Used during constraint propagation, and only once /// the value of `scc_b` has been computed. fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool { - let a_annotation = self.scc_annotations[scc_a]; - let b_annotation = self.scc_annotations[scc_b]; - let a_universe = a_annotation.min_universe(); - - // If scc_b's declared universe is a subset of - // scc_a's declared universe (typically, both are ROOT), then - // it cannot contain any problematic universe elements. - if a_universe.can_name(b_annotation.min_universe()) { - return true; - } - - // Otherwise, there can be no placeholder in `b` with a too high - // universe index to name from `a`. - a_universe.can_name(b_annotation.max_placeholder_universe_reached) + self.scc_annotations[scc_a].universe_compatible_with(self.scc_annotations[scc_b]) } /// Once regions have been propagated, this method is used to see @@ -2269,17 +2109,17 @@ impl<'tcx> RegionInferenceContext<'tcx> { } impl<'tcx> RegionDefinition<'tcx> { - fn new(universe: ty::UniverseIndex, rv_origin: RegionVariableOrigin) -> Self { + pub(crate) fn new(rv_info: &RegionVariableInfo) -> Self { // Create a new region definition. Note that, for free // regions, the `external_name` field gets updated later in - // `init_free_and_bound_regions`. + // [[crate::eliminate_placeholders]]. - let origin = match rv_origin { + let origin = match rv_info.origin { RegionVariableOrigin::Nll(origin) => origin, _ => NllRegionVariableOrigin::Existential { from_forall: false }, }; - Self { origin, universe, external_name: None } + Self { origin, universe: rv_info.universe, external_name: None } } } -- cgit 1.4.1-3-g733a5 From ee99fba21d724c9db9b57aed1af03fa53b711dc4 Mon Sep 17 00:00:00 2001 From: ArtemIsmagilov Date: Mon, 2 Jun 2025 19:32:02 +0400 Subject: Deconstruct values in the THIR visitor --- compiler/rustc_middle/src/thir/visit.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index f3da2a5cc8e..4da4dc3c02e 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -41,7 +41,8 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( expr: &'thir Expr<'tcx>, ) { use ExprKind::*; - match expr.kind { + let Expr { kind, ty: _, temp_lifetime: _, span: _ } = expr; + match *kind { Scope { value, region_scope: _, lint_level: _ } => { visitor.visit_expr(&visitor.thir()[value]) } @@ -191,7 +192,8 @@ pub fn walk_stmt<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor: &mut V, stmt: &'thir Stmt<'tcx>, ) { - match &stmt.kind { + let Stmt { kind } = stmt; + match kind { StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]), StmtKind::Let { initializer, @@ -217,11 +219,13 @@ pub fn walk_block<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor: &mut V, block: &'thir Block, ) { - for &stmt in &*block.stmts { + let Block { stmts, expr, targeted_by_break: _, region_scope: _, span: _, safety_mode: _ } = + block; + for &stmt in &*stmts { visitor.visit_stmt(&visitor.thir()[stmt]); } - if let Some(expr) = block.expr { - visitor.visit_expr(&visitor.thir()[expr]); + if let Some(expr) = expr { + visitor.visit_expr(&visitor.thir()[*expr]); } } @@ -229,11 +233,12 @@ pub fn walk_arm<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor: &mut V, arm: &'thir Arm<'tcx>, ) { - if let Some(expr) = arm.guard { - visitor.visit_expr(&visitor.thir()[expr]) + let Arm { guard, pattern, body, lint_level: _, span: _, scope: _ } = arm; + if let Some(expr) = guard { + visitor.visit_expr(&visitor.thir()[*expr]) } - visitor.visit_pat(&arm.pattern); - visitor.visit_expr(&visitor.thir()[arm.body]); + visitor.visit_pat(pattern); + visitor.visit_expr(&visitor.thir()[*body]); } pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( @@ -249,7 +254,8 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( pat: &'a Pat<'tcx>, mut callback: impl FnMut(&'a Pat<'tcx>), ) { - match &pat.kind { + let Pat { kind, ty: _, span: _ } = pat; + match kind { PatKind::Missing | PatKind::Wild | PatKind::Binding { subpattern: None, .. } -- cgit 1.4.1-3-g733a5 From 624e1cde83569f45bca245dcc1765b82242a5e7b Mon Sep 17 00:00:00 2001 From: ArtemIsmagilov Date: Tue, 3 Jun 2025 00:01:07 +0400 Subject: Deconstruct values in the THIR visitor --- compiler/rustc_hir/src/intravisit.rs | 237 ++++++++++++++++++++++------------- 1 file changed, 147 insertions(+), 90 deletions(-) diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 1fd44e44b9c..93f9166ca12 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -527,13 +527,15 @@ pub trait VisitorExt<'v>: Visitor<'v> { impl<'v, V: Visitor<'v>> VisitorExt<'v> for V {} pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> V::Result { - try_visit!(visitor.visit_id(param.hir_id)); - visitor.visit_pat(param.pat) + let Param { hir_id, pat, ty_span: _, span: _ } = param; + try_visit!(visitor.visit_id(*hir_id)); + visitor.visit_pat(pat) } pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result { + let Item { owner_id: _, kind, span: _, vis_span: _ } = item; try_visit!(visitor.visit_id(item.hir_id())); - match item.kind { + match *kind { ItemKind::ExternCrate(orig_name, ident) => { visit_opt!(visitor, visit_name, orig_name); try_visit!(visitor.visit_ident(ident)); @@ -631,8 +633,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: } pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &Body<'v>) -> V::Result { - walk_list!(visitor, visit_param, body.params); - visitor.visit_expr(body.value) + let Body { params, value } = body; + walk_list!(visitor, visit_param, *params); + visitor.visit_expr(*value) } pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) -> V::Result { @@ -640,7 +643,8 @@ pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) -> V::Resul } pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>) -> V::Result { - walk_list!(visitor, visit_nested_item, module.item_ids.iter().copied()); + let Mod { spans: _, item_ids } = module; + walk_list!(visitor, visit_nested_item, item_ids.iter().copied()); V::Result::output() } @@ -648,10 +652,11 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>( visitor: &mut V, foreign_item: &'v ForeignItem<'v>, ) -> V::Result { + let ForeignItem { ident, kind, owner_id: _, span: _, vis_span: _ } = foreign_item; try_visit!(visitor.visit_id(foreign_item.hir_id())); - try_visit!(visitor.visit_ident(foreign_item.ident)); + try_visit!(visitor.visit_ident(*ident)); - match foreign_item.kind { + match *kind { ForeignItemKind::Fn(ref sig, param_idents, ref generics) => { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_fn_decl(sig.decl)); @@ -670,24 +675,27 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>( pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v LetStmt<'v>) -> V::Result { // Intentionally visiting the expr first - the initialization expr // dominates the local's definition. - visit_opt!(visitor, visit_expr, local.init); - try_visit!(visitor.visit_id(local.hir_id)); - try_visit!(visitor.visit_pat(local.pat)); - visit_opt!(visitor, visit_block, local.els); - visit_opt!(visitor, visit_ty_unambig, local.ty); + let LetStmt { super_: _, pat, ty, init, els, hir_id, span: _, source: _ } = local; + visit_opt!(visitor, visit_expr, *init); + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_pat(*pat)); + visit_opt!(visitor, visit_block, *els); + visit_opt!(visitor, visit_ty_unambig, *ty); V::Result::output() } pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) -> V::Result { - try_visit!(visitor.visit_id(block.hir_id)); - walk_list!(visitor, visit_stmt, block.stmts); - visit_opt!(visitor, visit_expr, block.expr); + let Block { stmts, expr, hir_id, rules: _, span: _, targeted_by_break: _ } = block; + try_visit!(visitor.visit_id(*hir_id)); + walk_list!(visitor, visit_stmt, *stmts); + visit_opt!(visitor, visit_expr, *expr); V::Result::output() } pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) -> V::Result { - try_visit!(visitor.visit_id(statement.hir_id)); - match statement.kind { + let Stmt { kind, hir_id, span: _ } = statement; + try_visit!(visitor.visit_id(*hir_id)); + match *kind { StmtKind::Let(ref local) => visitor.visit_local(local), StmtKind::Item(item) => visitor.visit_nested_item(item), StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => { @@ -697,15 +705,17 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) - } pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) -> V::Result { - try_visit!(visitor.visit_id(arm.hir_id)); - try_visit!(visitor.visit_pat(arm.pat)); - visit_opt!(visitor, visit_expr, arm.guard); - visitor.visit_expr(arm.body) + let Arm { hir_id, span: _, pat, guard, body } = arm; + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_pat(*pat)); + visit_opt!(visitor, visit_expr, *guard); + visitor.visit_expr(*body) } pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>) -> V::Result { - try_visit!(visitor.visit_id(pattern.hir_id)); - match pattern.kind { + let TyPat { kind, hir_id, span: _ } = pattern; + try_visit!(visitor.visit_id(*hir_id)); + match *kind { TyPatKind::Range(lower_bound, upper_bound) => { try_visit!(visitor.visit_const_arg_unambig(lower_bound)); try_visit!(visitor.visit_const_arg_unambig(upper_bound)); @@ -717,14 +727,15 @@ pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>) } pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V::Result { - try_visit!(visitor.visit_id(pattern.hir_id)); - match pattern.kind { + let Pat { hir_id, kind, span, default_binding_modes: _ } = pattern; + try_visit!(visitor.visit_id(*hir_id)); + match *kind { PatKind::TupleStruct(ref qpath, children, _) => { - try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span)); + try_visit!(visitor.visit_qpath(qpath, *hir_id, *span)); walk_list!(visitor, visit_pat, children); } PatKind::Struct(ref qpath, fields, _) => { - try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span)); + try_visit!(visitor.visit_qpath(qpath, *hir_id, *span)); walk_list!(visitor, visit_pat_field, fields); } PatKind::Or(pats) => walk_list!(visitor, visit_pat, pats), @@ -760,36 +771,41 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V: } pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'v>) -> V::Result { - try_visit!(visitor.visit_id(field.hir_id)); - try_visit!(visitor.visit_ident(field.ident)); - visitor.visit_pat(field.pat) + let PatField { hir_id, ident, pat, is_shorthand: _, span: _ } = field; + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_ident(*ident)); + visitor.visit_pat(*pat) } pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>) -> V::Result { - try_visit!(visitor.visit_id(expr.hir_id)); - match &expr.kind { - PatExprKind::Lit { lit, negated } => visitor.visit_lit(expr.hir_id, lit, *negated), + let PatExpr { hir_id, span, kind } = expr; + try_visit!(visitor.visit_id(*hir_id)); + match kind { + PatExprKind::Lit { lit, negated } => visitor.visit_lit(*hir_id, lit, *negated), PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c), - PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, expr.hir_id, expr.span), + PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, *span), } } pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) -> V::Result { - try_visit!(visitor.visit_id(constant.hir_id)); - visitor.visit_nested_body(constant.body) + let AnonConst { hir_id, def_id: _, body, span: _ } = constant; + try_visit!(visitor.visit_id(*hir_id)); + visitor.visit_nested_body(*body) } pub fn walk_inline_const<'v, V: Visitor<'v>>( visitor: &mut V, constant: &'v ConstBlock, ) -> V::Result { - try_visit!(visitor.visit_id(constant.hir_id)); - visitor.visit_nested_body(constant.body) + let ConstBlock { hir_id, def_id: _, body } = constant; + try_visit!(visitor.visit_id(*hir_id)); + visitor.visit_nested_body(*body) } pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result { - try_visit!(visitor.visit_id(expression.hir_id)); - match expression.kind { + let Expr { hir_id, kind, span } = expression; + try_visit!(visitor.visit_id(*hir_id)); + match *kind { ExprKind::Array(subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } @@ -801,7 +817,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) try_visit!(visitor.visit_const_arg_unambig(count)); } ExprKind::Struct(ref qpath, fields, ref optional_base) => { - try_visit!(visitor.visit_qpath(qpath, expression.hir_id, expression.span)); + try_visit!(visitor.visit_qpath(qpath, *hir_id, *span)); walk_list!(visitor, visit_expr_field, fields); match optional_base { StructTailExpr::Base(base) => try_visit!(visitor.visit_expr(base)), @@ -869,7 +885,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) constness: _, }) => { walk_list!(visitor, visit_generic_param, bound_generic_params); - try_visit!(visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, def_id)); + try_visit!(visitor.visit_fn(FnKind::Closure, fn_decl, body, *span, def_id)); } ExprKind::Block(ref block, ref opt_label) => { visit_opt!(visitor, visit_label, opt_label); @@ -892,7 +908,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) try_visit!(visitor.visit_expr(index_expression)); } ExprKind::Path(ref qpath) => { - try_visit!(visitor.visit_qpath(qpath, expression.hir_id, expression.span)); + try_visit!(visitor.visit_qpath(qpath, *hir_id, *span)); } ExprKind::Break(ref destination, ref opt_expr) => { visit_opt!(visitor, visit_label, &destination.label); @@ -906,7 +922,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) } ExprKind::Become(ref expr) => try_visit!(visitor.visit_expr(expr)), ExprKind::InlineAsm(ref asm) => { - try_visit!(visitor.visit_inline_asm(asm, expression.hir_id)); + try_visit!(visitor.visit_inline_asm(asm, *hir_id)); } ExprKind::OffsetOf(ref container, ref fields) => { try_visit!(visitor.visit_ty_unambig(container)); @@ -919,16 +935,17 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) try_visit!(visitor.visit_expr(expr)); visit_opt!(visitor, visit_ty_unambig, ty); } - ExprKind::Lit(lit) => try_visit!(visitor.visit_lit(expression.hir_id, lit, false)), + ExprKind::Lit(lit) => try_visit!(visitor.visit_lit(*hir_id, lit, false)), ExprKind::Err(_) => {} } V::Result::output() } pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) -> V::Result { - try_visit!(visitor.visit_id(field.hir_id)); - try_visit!(visitor.visit_ident(field.ident)); - visitor.visit_expr(field.expr) + let ExprField { hir_id, ident, expr, span: _, is_shorthand: _ } = field; + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_ident(*ident)); + visitor.visit_expr(*expr) } /// We track whether an infer var is from a [`Ty`], [`ConstArg`], or [`GenericArg`] so that /// HIR visitors overriding [`Visitor::visit_infer`] can determine what kind of infer is being visited @@ -946,7 +963,10 @@ pub fn walk_generic_arg<'v, V: Visitor<'v>>( GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt), GenericArg::Type(ty) => visitor.visit_ty(ty), GenericArg::Const(ct) => visitor.visit_const_arg(ct), - GenericArg::Infer(inf) => visitor.visit_infer(inf.hir_id, inf.span, InferKind::Ambig(inf)), + GenericArg::Infer(inf) => { + let InferArg { hir_id, span } = inf; + visitor.visit_infer(*hir_id, *span, InferKind::Ambig(inf)) + } } } @@ -954,16 +974,18 @@ pub fn walk_unambig_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> match typ.try_as_ambig_ty() { Some(ambig_ty) => visitor.visit_ty(ambig_ty), None => { - try_visit!(visitor.visit_id(typ.hir_id)); - visitor.visit_infer(typ.hir_id, typ.span, InferKind::Ty(typ)) + let Ty { hir_id, span, kind: _ } = typ; + try_visit!(visitor.visit_id(*hir_id)); + visitor.visit_infer(*hir_id, *span, InferKind::Ty(typ)) } } } pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) -> V::Result { - try_visit!(visitor.visit_id(typ.hir_id)); + let Ty { hir_id, span: _, kind } = typ; + try_visit!(visitor.visit_id(*hir_id)); - match typ.kind { + match *kind { TyKind::Slice(ref ty) => try_visit!(visitor.visit_ty_unambig(ty)), TyKind::Ptr(ref mutable_type) => try_visit!(visitor.visit_ty_unambig(mutable_type.ty)), TyKind::Ref(ref lifetime, ref mutable_type) => { @@ -1018,8 +1040,9 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( match const_arg.try_as_ambig_ct() { Some(ambig_ct) => visitor.visit_const_arg(ambig_ct), None => { - try_visit!(visitor.visit_id(const_arg.hir_id)); - visitor.visit_infer(const_arg.hir_id, const_arg.span(), InferKind::Const(const_arg)) + let ConstArg { hir_id, kind: _ } = const_arg; + try_visit!(visitor.visit_id(*hir_id)); + visitor.visit_infer(*hir_id, const_arg.span(), InferKind::Const(const_arg)) } } } @@ -1028,9 +1051,10 @@ pub fn walk_ambig_const_arg<'v, V: Visitor<'v>>( visitor: &mut V, const_arg: &'v ConstArg<'v, AmbigArg>, ) -> V::Result { - try_visit!(visitor.visit_id(const_arg.hir_id)); - match &const_arg.kind { - ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, const_arg.hir_id, qpath.span()), + let ConstArg { hir_id, kind } = const_arg; + try_visit!(visitor.visit_id(*hir_id)); + match kind { + ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()), ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon), } } @@ -1039,12 +1063,22 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>( visitor: &mut V, param: &'v GenericParam<'v>, ) -> V::Result { - try_visit!(visitor.visit_id(param.hir_id)); - match param.name { + let GenericParam { + hir_id, + def_id: _, + name, + span: _, + pure_wrt_drop: _, + kind, + colon_span: _, + source: _, + } = param; + try_visit!(visitor.visit_id(*hir_id)); + match *name { ParamName::Plain(ident) | ParamName::Error(ident) => try_visit!(visitor.visit_ident(ident)), ParamName::Fresh => {} } - match param.kind { + match *kind { GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { ref default, .. } => { visit_opt!(visitor, visit_ty_unambig, default) @@ -1052,7 +1086,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>( GenericParamKind::Const { ref ty, ref default, synthetic: _ } => { try_visit!(visitor.visit_ty_unambig(ty)); if let Some(default) = default { - try_visit!(visitor.visit_const_param_default(param.hir_id, default)); + try_visit!(visitor.visit_const_param_default(*hir_id, default)); } } } @@ -1067,8 +1101,15 @@ pub fn walk_const_param_default<'v, V: Visitor<'v>>( } pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) -> V::Result { - walk_list!(visitor, visit_generic_param, generics.params); - walk_list!(visitor, visit_where_predicate, generics.predicates); + let &Generics { + params, + predicates, + has_where_clause_predicates: _, + where_clause_span: _, + span: _, + } = generics; + walk_list!(visitor, visit_generic_param, params); + walk_list!(visitor, visit_where_predicate, predicates); V::Result::output() } @@ -1109,8 +1150,10 @@ pub fn walk_fn_decl<'v, V: Visitor<'v>>( visitor: &mut V, function_declaration: &'v FnDecl<'v>, ) -> V::Result { - walk_list!(visitor, visit_ty_unambig, function_declaration.inputs); - visitor.visit_fn_ret_ty(&function_declaration.output) + let FnDecl { inputs, output, c_variadic: _, implicit_self: _, lifetime_elision_allowed: _ } = + function_declaration; + walk_list!(visitor, visit_ty_unambig, *inputs); + visitor.visit_fn_ret_ty(output) } pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FnRetTy<'v>) -> V::Result { @@ -1264,8 +1307,9 @@ pub fn walk_trait_ref<'v, V: Visitor<'v>>( visitor: &mut V, trait_ref: &'v TraitRef<'v>, ) -> V::Result { - try_visit!(visitor.visit_id(trait_ref.hir_ref_id)); - visitor.visit_path(trait_ref.path, trait_ref.hir_ref_id) + let TraitRef { hir_ref_id, path } = trait_ref; + try_visit!(visitor.visit_id(*hir_ref_id)); + visitor.visit_path(*path, *hir_ref_id) } pub fn walk_param_bound<'v, V: Visitor<'v>>( @@ -1288,7 +1332,10 @@ pub fn walk_precise_capturing_arg<'v, V: Visitor<'v>>( ) -> V::Result { match *arg { PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt), - PreciseCapturingArg::Param(param) => visitor.visit_id(param.hir_id), + PreciseCapturingArg::Param(param) => { + let PreciseCapturingNonLifetimeArg { hir_id, ident: _, res: _ } = param; + visitor.visit_id(hir_id) + } } } @@ -1296,8 +1343,9 @@ pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>( visitor: &mut V, trait_ref: &'v PolyTraitRef<'v>, ) -> V::Result { - walk_list!(visitor, visit_generic_param, trait_ref.bound_generic_params); - visitor.visit_trait_ref(&trait_ref.trait_ref) + let PolyTraitRef { bound_generic_params, modifiers: _, trait_ref, span: _ } = trait_ref; + walk_list!(visitor, visit_generic_param, *bound_generic_params); + visitor.visit_trait_ref(trait_ref) } pub fn walk_opaque_ty<'v, V: Visitor<'v>>(visitor: &mut V, opaque: &'v OpaqueTy<'v>) -> V::Result { @@ -1330,29 +1378,34 @@ pub fn walk_enum_def<'v, V: Visitor<'v>>( visitor: &mut V, enum_definition: &'v EnumDef<'v>, ) -> V::Result { - walk_list!(visitor, visit_variant, enum_definition.variants); + let EnumDef { variants } = enum_definition; + walk_list!(visitor, visit_variant, *variants); V::Result::output() } pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) -> V::Result { - try_visit!(visitor.visit_ident(variant.ident)); - try_visit!(visitor.visit_id(variant.hir_id)); - try_visit!(visitor.visit_variant_data(&variant.data)); - visit_opt!(visitor, visit_anon_const, &variant.disr_expr); + let Variant { ident, hir_id, def_id: _, data, disr_expr, span: _ } = variant; + try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_variant_data(data)); + visit_opt!(visitor, visit_anon_const, disr_expr); V::Result::output() } pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) -> V::Result { - visitor.visit_ident(label.ident) + let Label { ident } = label; + visitor.visit_ident(*ident) } pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) -> V::Result { - visitor.visit_id(inf.hir_id) + let InferArg { hir_id, span: _ } = inf; + visitor.visit_id(*hir_id) } pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) -> V::Result { - try_visit!(visitor.visit_id(lifetime.hir_id)); - visitor.visit_ident(lifetime.ident) + let Lifetime { hir_id, ident, kind: _, source: _, syntax: _ } = lifetime; + try_visit!(visitor.visit_id(*hir_id)); + visitor.visit_ident(*ident) } pub fn walk_qpath<'v, V: Visitor<'v>>( @@ -1374,7 +1427,8 @@ pub fn walk_qpath<'v, V: Visitor<'v>>( } pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &Path<'v>) -> V::Result { - walk_list!(visitor, visit_path_segment, path.segments); + let Path { segments, span: _, res: _ } = path; + walk_list!(visitor, visit_path_segment, *segments); V::Result::output() } @@ -1382,9 +1436,10 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>( visitor: &mut V, segment: &'v PathSegment<'v>, ) -> V::Result { - try_visit!(visitor.visit_ident(segment.ident)); - try_visit!(visitor.visit_id(segment.hir_id)); - visit_opt!(visitor, visit_generic_args, segment.args); + let PathSegment { ident, hir_id, res: _, args, infer_args: _ } = segment; + try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_id(*hir_id)); + visit_opt!(visitor, visit_generic_args, *args); V::Result::output() } @@ -1392,8 +1447,9 @@ pub fn walk_generic_args<'v, V: Visitor<'v>>( visitor: &mut V, generic_args: &'v GenericArgs<'v>, ) -> V::Result { - walk_list!(visitor, visit_generic_arg, generic_args.args); - walk_list!(visitor, visit_assoc_item_constraint, generic_args.constraints); + let GenericArgs { args, constraints, parenthesized: _, span_ext: _ } = generic_args; + walk_list!(visitor, visit_generic_arg, *args); + walk_list!(visitor, visit_assoc_item_constraint, *constraints); V::Result::output() } @@ -1401,9 +1457,10 @@ pub fn walk_assoc_item_constraint<'v, V: Visitor<'v>>( visitor: &mut V, constraint: &'v AssocItemConstraint<'v>, ) -> V::Result { - try_visit!(visitor.visit_id(constraint.hir_id)); - try_visit!(visitor.visit_ident(constraint.ident)); - try_visit!(visitor.visit_generic_args(constraint.gen_args)); + let AssocItemConstraint { hir_id, ident, gen_args, kind: _, span: _ } = constraint; + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_generic_args(*gen_args)); match constraint.kind { AssocItemConstraintKind::Equality { ref term } => match term { Term::Ty(ty) => try_visit!(visitor.visit_ty_unambig(ty)), -- cgit 1.4.1-3-g733a5 From 4fc62e0d5697b8c59297fd34fdf7c4ad8e0efe0d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 3 Jun 2025 09:48:03 +0200 Subject: Add missing `dyn` keywords to tests that do not test for them Part 2 --- tests/ui/issues/auxiliary/issue-11224.rs | 2 +- tests/ui/issues/auxiliary/issue-13507.rs | 2 +- tests/ui/issues/auxiliary/issue-17662.rs | 6 +++--- tests/ui/issues/auxiliary/issue-2380.rs | 4 ++-- tests/ui/issues/auxiliary/issue-25467.rs | 2 +- tests/ui/issues/auxiliary/issue-34796-aux.rs | 2 +- tests/ui/issues/auxiliary/issue-38226-aux.rs | 2 +- tests/ui/issues/auxiliary/issue-8401.rs | 4 ++-- tests/ui/issues/issue-34373.rs | 2 +- tests/ui/issues/issue-34373.stderr | 14 +++++++------- .../auxiliary/lifetime_bound_will_change_warning_lib.rs | 5 ++--- tests/ui/parser/bounds-obj-parens.rs | 4 +--- tests/ui/parser/trailing-plus-in-bounds.rs | 4 +--- tests/ui/regions/region-object-lifetime-1.rs | 2 +- tests/ui/regions/region-object-lifetime-3.rs | 2 +- 15 files changed, 26 insertions(+), 31 deletions(-) diff --git a/tests/ui/issues/auxiliary/issue-11224.rs b/tests/ui/issues/auxiliary/issue-11224.rs index 63543621a80..94fb1f3abd5 100644 --- a/tests/ui/issues/auxiliary/issue-11224.rs +++ b/tests/ui/issues/auxiliary/issue-11224.rs @@ -11,6 +11,6 @@ mod inner { } pub fn foo() { - let a = &1isize as &inner::Trait; + let a = &1isize as &dyn inner::Trait; a.f(); } diff --git a/tests/ui/issues/auxiliary/issue-13507.rs b/tests/ui/issues/auxiliary/issue-13507.rs index c91013043eb..4160cf99f53 100644 --- a/tests/ui/issues/auxiliary/issue-13507.rs +++ b/tests/ui/issues/auxiliary/issue-13507.rs @@ -16,7 +16,7 @@ pub mod testtypes { TypeId::of::(), TypeId::of::(), TypeId::of::(), - TypeId::of::(), + TypeId::of::(), TypeId::of::(), TypeId::of::() ] diff --git a/tests/ui/issues/auxiliary/issue-17662.rs b/tests/ui/issues/auxiliary/issue-17662.rs index 75efe110cdf..5ecec31deb0 100644 --- a/tests/ui/issues/auxiliary/issue-17662.rs +++ b/tests/ui/issues/auxiliary/issue-17662.rs @@ -4,9 +4,9 @@ pub trait Foo<'a, T> { fn foo(&'a self) -> T; } -pub fn foo<'a, T>(x: &'a Foo<'a, T>) -> T { - let x: &'a Foo = x; - // ^ the lifetime parameter of Foo is left to be inferred. +pub fn foo<'a, T>(x: &'a dyn Foo<'a, T>) -> T { + let x: &'a dyn Foo = x; + // ^ the lifetime parameter of Foo is left to be inferred. x.foo() // ^ encoding this method call in metadata triggers an ICE. } diff --git a/tests/ui/issues/auxiliary/issue-2380.rs b/tests/ui/issues/auxiliary/issue-2380.rs index 79fd62d1633..9ec829b417f 100644 --- a/tests/ui/issues/auxiliary/issue-2380.rs +++ b/tests/ui/issues/auxiliary/issue-2380.rs @@ -6,8 +6,8 @@ pub trait i fn dummy(&self, t: T) -> T { panic!() } } -pub fn f() -> Box+'static> { +pub fn f() -> Box+'static> { impl i for () { } - Box::new(()) as Box+'static> + Box::new(()) as Box+'static> } diff --git a/tests/ui/issues/auxiliary/issue-25467.rs b/tests/ui/issues/auxiliary/issue-25467.rs index ca9b3097c83..16c2869dc75 100644 --- a/tests/ui/issues/auxiliary/issue-25467.rs +++ b/tests/ui/issues/auxiliary/issue-25467.rs @@ -7,4 +7,4 @@ pub trait Trait { type Issue25467BarT; } -pub type Object = Option>>; +pub type Object = Option>>; diff --git a/tests/ui/issues/auxiliary/issue-34796-aux.rs b/tests/ui/issues/auxiliary/issue-34796-aux.rs index 09c69b90329..0e91bb4bcdc 100644 --- a/tests/ui/issues/auxiliary/issue-34796-aux.rs +++ b/tests/ui/issues/auxiliary/issue-34796-aux.rs @@ -9,7 +9,7 @@ impl Future for u32 { type Error = Box<()>; } -fn foo() -> Box>> { +fn foo() -> Box>> { Box::new(0u32) } diff --git a/tests/ui/issues/auxiliary/issue-38226-aux.rs b/tests/ui/issues/auxiliary/issue-38226-aux.rs index f968017199f..a8e964e016f 100644 --- a/tests/ui/issues/auxiliary/issue-38226-aux.rs +++ b/tests/ui/issues/auxiliary/issue-38226-aux.rs @@ -2,7 +2,7 @@ #[inline(never)] pub fn foo() { - let _: Box = Box::new(SomeTraitImpl); + let _: Box = Box::new(SomeTraitImpl); } pub fn bar() { diff --git a/tests/ui/issues/auxiliary/issue-8401.rs b/tests/ui/issues/auxiliary/issue-8401.rs index e35dbbfabfc..7d0eb5cd876 100644 --- a/tests/ui/issues/auxiliary/issue-8401.rs +++ b/tests/ui/issues/auxiliary/issue-8401.rs @@ -8,9 +8,9 @@ trait A { struct B; impl A for B {} -fn bar(_: &mut A, _: &T) {} +fn bar(_: &mut dyn A, _: &T) {} fn foo(t: &T) { let mut b = B; - bar(&mut b as &mut A, t) + bar(&mut b as &mut dyn A, t) } diff --git a/tests/ui/issues/issue-34373.rs b/tests/ui/issues/issue-34373.rs index 707aa8cf338..5b05811a4eb 100644 --- a/tests/ui/issues/issue-34373.rs +++ b/tests/ui/issues/issue-34373.rs @@ -4,7 +4,7 @@ trait Trait { fn foo(_: T) {} } -pub struct Foo>>; //~ ERROR cycle detected +pub struct Foo>>; //~ ERROR cycle detected //~^ ERROR `T` is never used type DefaultFoo = Foo; diff --git a/tests/ui/issues/issue-34373.stderr b/tests/ui/issues/issue-34373.stderr index 06365558217..03d77193134 100644 --- a/tests/ui/issues/issue-34373.stderr +++ b/tests/ui/issues/issue-34373.stderr @@ -1,8 +1,8 @@ error[E0391]: cycle detected when computing type of `Foo::T` - --> $DIR/issue-34373.rs:7:30 + --> $DIR/issue-34373.rs:7:34 | -LL | pub struct Foo>>; - | ^^^^^^^^^^ +LL | pub struct Foo>>; + | ^^^^^^^^^^ | note: ...which requires expanding type alias `DefaultFoo`... --> $DIR/issue-34373.rs:9:19 @@ -13,15 +13,15 @@ LL | type DefaultFoo = Foo; note: cycle used when checking that `Foo` is well-formed --> $DIR/issue-34373.rs:7:1 | -LL | pub struct Foo>>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub struct Foo>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error[E0392]: type parameter `T` is never used --> $DIR/issue-34373.rs:7:16 | -LL | pub struct Foo>>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unused type parameter +LL | pub struct Foo>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead diff --git a/tests/ui/lifetimes/auxiliary/lifetime_bound_will_change_warning_lib.rs b/tests/ui/lifetimes/auxiliary/lifetime_bound_will_change_warning_lib.rs index 58f1b81cf4d..e351cc9e8fe 100644 --- a/tests/ui/lifetimes/auxiliary/lifetime_bound_will_change_warning_lib.rs +++ b/tests/ui/lifetimes/auxiliary/lifetime_bound_will_change_warning_lib.rs @@ -3,9 +3,8 @@ // Helper for testing that we get suitable warnings when lifetime // bound change will cause breakage. -pub fn just_ref(x: &Fn()) { -} +pub fn just_ref(x: &dyn Fn()) {} -pub fn ref_obj(x: &Box) { +pub fn ref_obj(x: &Box) { // this will change to &Box... } diff --git a/tests/ui/parser/bounds-obj-parens.rs b/tests/ui/parser/bounds-obj-parens.rs index eea4bccdc09..5ba90b50d2f 100644 --- a/tests/ui/parser/bounds-obj-parens.rs +++ b/tests/ui/parser/bounds-obj-parens.rs @@ -1,7 +1,5 @@ //@ check-pass -#![allow(bare_trait_objects)] - -type A = Box<(Fn(u8) -> u8) + 'static + Send + Sync>; // OK (but see #39318) +type A = Box u8) + 'static + Send + Sync>; // OK (but see #39318) fn main() {} diff --git a/tests/ui/parser/trailing-plus-in-bounds.rs b/tests/ui/parser/trailing-plus-in-bounds.rs index ef9bdadb282..aa5bc3aca59 100644 --- a/tests/ui/parser/trailing-plus-in-bounds.rs +++ b/tests/ui/parser/trailing-plus-in-bounds.rs @@ -1,9 +1,7 @@ //@ check-pass -#![allow(bare_trait_objects)] - use std::fmt::Debug; fn main() { - let x: Box = Box::new(3) as Box; // Trailing `+` is OK + let x: Box = Box::new(3) as Box; // Trailing `+` is OK } diff --git a/tests/ui/regions/region-object-lifetime-1.rs b/tests/ui/regions/region-object-lifetime-1.rs index 11e3c8a1a33..7ff37d7a525 100644 --- a/tests/ui/regions/region-object-lifetime-1.rs +++ b/tests/ui/regions/region-object-lifetime-1.rs @@ -10,7 +10,7 @@ trait Foo { // Here the receiver and return value all have the same lifetime, // so no error results. -fn borrowed_receiver_same_lifetime<'a>(x: &'a Foo) -> &'a () { +fn borrowed_receiver_same_lifetime<'a>(x: &'a dyn Foo) -> &'a () { x.borrowed() } diff --git a/tests/ui/regions/region-object-lifetime-3.rs b/tests/ui/regions/region-object-lifetime-3.rs index ddeeec902f1..fee32f92059 100644 --- a/tests/ui/regions/region-object-lifetime-3.rs +++ b/tests/ui/regions/region-object-lifetime-3.rs @@ -10,7 +10,7 @@ trait Foo { // Borrowed receiver with two distinct lifetimes, but we know that // 'b:'a, hence &'a () is permitted. -fn borrowed_receiver_related_lifetimes<'a,'b>(x: &'a (Foo+'b)) -> &'a () { +fn borrowed_receiver_related_lifetimes<'a,'b>(x: &'a (dyn Foo+'b)) -> &'a () { x.borrowed() } -- cgit 1.4.1-3-g733a5 From eae7fe1bdb5ca2fa3c37c84c5e93d5fb3cbeab8d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 3 Jun 2025 10:03:42 +0200 Subject: Use non-2015 edition paths in tests that do not test for their resolution This allows for testing these tests on editions other than 2015 --- tests/ui/issues/issue-20427.rs | 2 +- tests/ui/issues/issue-28983.rs | 2 +- tests/ui/issues/issue-31776.rs | 6 +- tests/ui/issues/issue-32797.rs | 2 +- tests/ui/issues/issue-41053.rs | 2 +- tests/ui/issues/issue-47364.rs | 24 +++--- tests/ui/issues/issue-50187.rs | 14 ++-- tests/ui/issues/issue-50761.rs | 2 +- tests/ui/issues/issue-6936.rs | 10 +-- tests/ui/issues/issue-6936.stderr | 12 +-- tests/ui/issues/issue-7663.rs | 4 +- .../lint-directives-on-use-items-issue-10534.rs | 8 +- ...lint-directives-on-use-items-issue-10534.stderr | 12 +-- tests/ui/lint/lint-missing-doc.rs | 8 +- tests/ui/lint/lint-unnecessary-import-braces.rs | 6 +- .../ui/lint/lint-unnecessary-import-braces.stderr | 4 +- tests/ui/lint/unused/lint-unused-imports.rs | 8 +- tests/ui/lint/unused/lint-unused-imports.stderr | 12 +-- tests/ui/macros/macro-pub-matcher.rs | 18 ++-- tests/ui/macros/paths-in-macro-invocations.rs | 12 +-- tests/ui/moves/issue-34721.fixed | 6 +- tests/ui/moves/issue-34721.rs | 6 +- .../namespaced-enum-glob-import-no-impls.rs | 4 +- tests/ui/pattern/issue-14221.rs | 2 +- tests/ui/pattern/issue-22546.rs | 4 +- tests/ui/pattern/issue-6449.rs | 40 ++++----- tests/ui/pattern/missing_lifetime.rs | 2 +- tests/ui/pattern/usefulness/uninhabited.rs | 2 +- tests/ui/privacy/auxiliary/pub_use_mods_xcrate.rs | 2 +- tests/ui/privacy/crate-private-reexport.rs | 18 ++-- tests/ui/privacy/crate-private-reexport.stderr | 56 ++++++------- tests/ui/privacy/issue-30079.rs | 8 +- tests/ui/privacy/issue-30079.stderr | 4 +- .../issue-46209-private-enum-variant-reexport.rs | 2 +- tests/ui/privacy/legacy-ctor-visibility.rs | 2 +- tests/ui/privacy/privacy-in-paths.rs | 8 +- tests/ui/privacy/privacy-in-paths.stderr | 28 +++---- tests/ui/privacy/privacy-ufcs.rs | 2 +- tests/ui/privacy/privacy-ufcs.stderr | 10 +-- tests/ui/privacy/privacy1.rs | 36 ++++---- tests/ui/privacy/privacy1.stderr | 96 +++++++++++----------- tests/ui/privacy/privacy2.rs | 2 +- tests/ui/privacy/privacy2.stderr | 4 +- tests/ui/privacy/private-inferred-type-1.rs | 6 +- .../privacy/restricted/lookup-ignores-private.rs | 8 +- tests/ui/privacy/restricted/private-in-public.rs | 2 +- .../ui/privacy/restricted/struct-literal-field.rs | 4 +- tests/ui/proc-macro/crate-var.rs | 4 +- .../ui/proc-macro/helper-attr-blocked-by-import.rs | 4 +- tests/ui/proc-macro/issue-50493.rs | 2 +- tests/ui/proc-macro/issue-50493.stderr | 4 +- tests/ui/proc-macro/issue-53481.rs | 2 +- tests/ui/pub/pub-reexport-priv-extern-crate.rs | 4 +- tests/ui/pub/pub-reexport-priv-extern-crate.stderr | 12 +-- tests/ui/pub/pub-restricted.rs | 6 +- tests/ui/pub/pub-restricted.stderr | 4 +- .../ui/recursion/auxiliary/recursive_reexports.rs | 2 +- tests/ui/recursion_limit/issue-40003.rs | 4 +- 58 files changed, 290 insertions(+), 290 deletions(-) diff --git a/tests/ui/issues/issue-20427.rs b/tests/ui/issues/issue-20427.rs index ff84023ebf2..4018043c371 100644 --- a/tests/ui/issues/issue-20427.rs +++ b/tests/ui/issues/issue-20427.rs @@ -59,7 +59,7 @@ mod reuse { pub fn check() { assert_eq!(size_of::(), 8); - assert_eq!(size_of::<::u64>(), 0); + assert_eq!(size_of::(), 0); assert_eq!(size_of::(), 3 * size_of::<*const ()>()); assert_eq!(size_of::(), 0); } diff --git a/tests/ui/issues/issue-28983.rs b/tests/ui/issues/issue-28983.rs index 5273dab16c1..90a4793787d 100644 --- a/tests/ui/issues/issue-28983.rs +++ b/tests/ui/issues/issue-28983.rs @@ -7,7 +7,7 @@ impl Test for u32 { pub mod export { #[no_mangle] - pub extern "C" fn issue_28983(t: ::T) -> i32 { t*3 } + pub extern "C" fn issue_28983(t: ::T) -> i32 { t*3 } } // to test both exporting and importing functions, import diff --git a/tests/ui/issues/issue-31776.rs b/tests/ui/issues/issue-31776.rs index 4b342a0e3b2..abe6c7ecee5 100644 --- a/tests/ui/issues/issue-31776.rs +++ b/tests/ui/issues/issue-31776.rs @@ -8,7 +8,7 @@ struct S; mod m { fn f() { - impl ::S { + impl crate::S { pub fn s(&self) {} } } @@ -24,7 +24,7 @@ pub struct S1; fn f() { pub struct Z; - impl ::Tr for ::S1 { + impl crate::Tr for crate::S1 { type A = Z; // Private-in-public error unless `struct Z` is pub } } @@ -43,7 +43,7 @@ mod m1 { pub field: u8 } - impl ::Tr1 for ::S2 { + impl crate::Tr1 for crate::S2 { type A = Z; fn pull(&self) -> Self::A { Z{field: 10} } } diff --git a/tests/ui/issues/issue-32797.rs b/tests/ui/issues/issue-32797.rs index 6711a8f9fe5..470d661cb28 100644 --- a/tests/ui/issues/issue-32797.rs +++ b/tests/ui/issues/issue-32797.rs @@ -7,7 +7,7 @@ mod bar { pub use baz::*; mod baz { - pub use main as f; + pub use crate::main as f; } pub fn main() {} diff --git a/tests/ui/issues/issue-41053.rs b/tests/ui/issues/issue-41053.rs index 18f9e209c33..42b0b008ce9 100644 --- a/tests/ui/issues/issue-41053.rs +++ b/tests/ui/issues/issue-41053.rs @@ -11,7 +11,7 @@ impl Iterator for Foo { type Item = Box; fn next(&mut self) -> Option> { extern crate issue_41053; - impl ::Trait for issue_41053::Test { + impl crate::Trait for issue_41053::Test { fn foo(&self) {} } Some(Box::new(issue_41053::Test)) diff --git a/tests/ui/issues/issue-47364.rs b/tests/ui/issues/issue-47364.rs index b657b3d3bde..79cd5ed92a8 100644 --- a/tests/ui/issues/issue-47364.rs +++ b/tests/ui/issues/issue-47364.rs @@ -18,18 +18,18 @@ pub enum IResult { Incomplete(u32, u64) } -pub fn multispace(input: T) -> ::IResult { - ::IResult::Done(0, 0) +pub fn multispace(input: T) -> crate::IResult { + crate::IResult::Done(0, 0) } mod nom_sql { - fn where_clause(i: &[u8]) -> ::IResult<&[u8], Option> { - let X = match ::multispace(i) { - ::IResult::Done(..) => ::IResult::Done(i, None::), - _ => ::IResult::Error(::Err::NodePosition(0)), + fn where_clause(i: &[u8]) -> crate::IResult<&[u8], Option> { + let X = match crate::multispace(i) { + crate::IResult::Done(..) => crate::IResult::Done(i, None::), + _ => crate::IResult::Error(crate::Err::NodePosition(0)), }; match X { - ::IResult::Done(_, _) => ::IResult::Done(i, None), + crate::IResult::Done(_, _) => crate::IResult::Done(i, None), _ => X } } @@ -39,16 +39,16 @@ mod nom_sql { match { where_clause(i) } { - ::IResult::Done(_, o) => ::IResult::Done(i, Some(o)), - ::IResult::Error(_) => ::IResult::Done(i, None), - _ => ::IResult::Incomplete(0, 0), + crate::IResult::Done(_, o) => crate::IResult::Done(i, Some(o)), + crate::IResult::Error(_) => crate::IResult::Done(i, None), + _ => crate::IResult::Incomplete(0, 0), } } { - ::IResult::Done(z, _) => ::IResult::Done(z, None::), + crate::IResult::Done(z, _) => crate::IResult::Done(z, None::), _ => return () }; match Y { - ::IResult::Done(x, _) => { + crate::IResult::Done(x, _) => { let bytes = b"; "; let len = x.len(); bytes[len]; diff --git a/tests/ui/issues/issue-50187.rs b/tests/ui/issues/issue-50187.rs index 7304903b954..478416f86dc 100644 --- a/tests/ui/issues/issue-50187.rs +++ b/tests/ui/issues/issue-50187.rs @@ -13,20 +13,20 @@ mod macro_ns { } mod merge2 { - pub use type_ns::A; - pub use value_ns::A; + pub use crate::type_ns::A; + pub use crate::value_ns::A; } mod merge3 { - pub use type_ns::A; - pub use value_ns::A; - pub use macro_ns::A; + pub use crate::type_ns::A; + pub use crate::value_ns::A; + pub use crate::macro_ns::A; } mod use2 { - pub use merge2::A; + pub use crate::merge2::A; } mod use3 { - pub use merge3::A; + pub use crate::merge3::A; } fn main() { diff --git a/tests/ui/issues/issue-50761.rs b/tests/ui/issues/issue-50761.rs index 6911bfa0265..8f5a32e0a00 100644 --- a/tests/ui/issues/issue-50761.rs +++ b/tests/ui/issues/issue-50761.rs @@ -14,7 +14,7 @@ mod b { } impl Builder { - pub fn with_a(&mut self, _a: fn() -> dyn (::a::A)) {} + pub fn with_a(&mut self, _a: fn() -> dyn (crate::a::A)) {} } } diff --git a/tests/ui/issues/issue-6936.rs b/tests/ui/issues/issue-6936.rs index 26531bba9ec..e9aa80b4eb3 100644 --- a/tests/ui/issues/issue-6936.rs +++ b/tests/ui/issues/issue-6936.rs @@ -1,22 +1,22 @@ struct T; mod t1 { - type Foo = ::T; + type Foo = crate::T; mod Foo {} //~ ERROR the name `Foo` is defined multiple times } mod t2 { - type Foo = ::T; + type Foo = crate::T; struct Foo; //~ ERROR the name `Foo` is defined multiple times } mod t3 { - type Foo = ::T; + type Foo = crate::T; enum Foo {} //~ ERROR the name `Foo` is defined multiple times } mod t4 { - type Foo = ::T; + type Foo = crate::T; fn Foo() {} // ok } @@ -26,7 +26,7 @@ mod t5 { } mod t6 { - type Foo = ::T; + type Foo = crate::T; impl Foo {} // ok } diff --git a/tests/ui/issues/issue-6936.stderr b/tests/ui/issues/issue-6936.stderr index 9292d60ca68..03cc50636b4 100644 --- a/tests/ui/issues/issue-6936.stderr +++ b/tests/ui/issues/issue-6936.stderr @@ -1,8 +1,8 @@ error[E0428]: the name `Foo` is defined multiple times --> $DIR/issue-6936.rs:5:5 | -LL | type Foo = ::T; - | --------------- previous definition of the type `Foo` here +LL | type Foo = crate::T; + | -------------------- previous definition of the type `Foo` here LL | mod Foo {} | ^^^^^^^ `Foo` redefined here | @@ -11,8 +11,8 @@ LL | mod Foo {} error[E0428]: the name `Foo` is defined multiple times --> $DIR/issue-6936.rs:10:5 | -LL | type Foo = ::T; - | --------------- previous definition of the type `Foo` here +LL | type Foo = crate::T; + | -------------------- previous definition of the type `Foo` here LL | struct Foo; | ^^^^^^^^^^^ `Foo` redefined here | @@ -21,8 +21,8 @@ LL | struct Foo; error[E0428]: the name `Foo` is defined multiple times --> $DIR/issue-6936.rs:15:5 | -LL | type Foo = ::T; - | --------------- previous definition of the type `Foo` here +LL | type Foo = crate::T; + | -------------------- previous definition of the type `Foo` here LL | enum Foo {} | ^^^^^^^^ `Foo` redefined here | diff --git a/tests/ui/issues/issue-7663.rs b/tests/ui/issues/issue-7663.rs index ad52ea21127..d2b2c727cab 100644 --- a/tests/ui/issues/issue-7663.rs +++ b/tests/ui/issues/issue-7663.rs @@ -8,7 +8,7 @@ mod test1 { mod bar { pub fn p() -> isize { 2 } } pub mod baz { - use test1::bar::p; + use crate::test1::bar::p; pub fn my_main() { assert_eq!(p(), 2); } } @@ -20,7 +20,7 @@ mod test2 { mod bar { pub fn p() -> isize { 2 } } pub mod baz { - use test2::bar::p; + use crate::test2::bar::p; pub fn my_main() { assert_eq!(p(), 2); } } diff --git a/tests/ui/lint/lint-directives-on-use-items-issue-10534.rs b/tests/ui/lint/lint-directives-on-use-items-issue-10534.rs index e5cb0d3df0e..55ecb564beb 100644 --- a/tests/ui/lint/lint-directives-on-use-items-issue-10534.rs +++ b/tests/ui/lint/lint-directives-on-use-items-issue-10534.rs @@ -9,16 +9,16 @@ mod a { pub static x: isize = 3; pub static y: isize = 4; } mod b { - use a::x; //~ ERROR: unused import + use crate::a::x; //~ ERROR: unused import #[allow(unused_imports)] - use a::y; // no error here + use crate::a::y; // no error here } #[allow(unused_imports)] mod c { - use a::x; + use crate::a::x; #[deny(unused_imports)] - use a::y; //~ ERROR: unused import + use crate::a::y; //~ ERROR: unused import } fn main() {} diff --git a/tests/ui/lint/lint-directives-on-use-items-issue-10534.stderr b/tests/ui/lint/lint-directives-on-use-items-issue-10534.stderr index ccb139e0ed6..c394d1e7932 100644 --- a/tests/ui/lint/lint-directives-on-use-items-issue-10534.stderr +++ b/tests/ui/lint/lint-directives-on-use-items-issue-10534.stderr @@ -1,8 +1,8 @@ -error: unused import: `a::x` +error: unused import: `crate::a::x` --> $DIR/lint-directives-on-use-items-issue-10534.rs:12:9 | -LL | use a::x; - | ^^^^ +LL | use crate::a::x; + | ^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/lint-directives-on-use-items-issue-10534.rs:1:9 @@ -10,11 +10,11 @@ note: the lint level is defined here LL | #![deny(unused_imports)] | ^^^^^^^^^^^^^^ -error: unused import: `a::y` +error: unused import: `crate::a::y` --> $DIR/lint-directives-on-use-items-issue-10534.rs:21:9 | -LL | use a::y; - | ^^^^ +LL | use crate::a::y; + | ^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/lint-directives-on-use-items-issue-10534.rs:20:12 diff --git a/tests/ui/lint/lint-missing-doc.rs b/tests/ui/lint/lint-missing-doc.rs index 0b7c99e5012..b8655994fc2 100644 --- a/tests/ui/lint/lint-missing-doc.rs +++ b/tests/ui/lint/lint-missing-doc.rs @@ -184,10 +184,10 @@ mod internal_impl { } /// dox pub mod public_interface { - pub use internal_impl::documented as foo; - pub use internal_impl::undocumented1 as bar; - pub use internal_impl::{documented, undocumented2}; - pub use internal_impl::globbed::*; + pub use crate::internal_impl::documented as foo; + pub use crate::internal_impl::undocumented1 as bar; + pub use crate::internal_impl::{documented, undocumented2}; + pub use crate::internal_impl::globbed::*; } extern "C" { diff --git a/tests/ui/lint/lint-unnecessary-import-braces.rs b/tests/ui/lint/lint-unnecessary-import-braces.rs index 9a3398a8734..a9c8da85a22 100644 --- a/tests/ui/lint/lint-unnecessary-import-braces.rs +++ b/tests/ui/lint/lint-unnecessary-import-braces.rs @@ -1,10 +1,10 @@ #![deny(unused_import_braces)] -use test::{A}; //~ ERROR braces around A is unnecessary +use crate::test::{A}; //~ ERROR braces around A is unnecessary mod test { - use test::{self}; // OK - use test::{self as rename}; // OK + use crate::test::{self}; // OK + use crate::test::{self as rename}; // OK pub struct A; } diff --git a/tests/ui/lint/lint-unnecessary-import-braces.stderr b/tests/ui/lint/lint-unnecessary-import-braces.stderr index 5f441ef4a66..dc470551cd4 100644 --- a/tests/ui/lint/lint-unnecessary-import-braces.stderr +++ b/tests/ui/lint/lint-unnecessary-import-braces.stderr @@ -1,8 +1,8 @@ error: braces around A is unnecessary --> $DIR/lint-unnecessary-import-braces.rs:3:1 | -LL | use test::{A}; - | ^^^^^^^^^^^^^^ +LL | use crate::test::{A}; + | ^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/lint-unnecessary-import-braces.rs:1:9 diff --git a/tests/ui/lint/unused/lint-unused-imports.rs b/tests/ui/lint/unused/lint-unused-imports.rs index 710fb7a5ed1..d09a84b59a3 100644 --- a/tests/ui/lint/unused/lint-unused-imports.rs +++ b/tests/ui/lint/unused/lint-unused-imports.rs @@ -48,8 +48,8 @@ pub mod bar { pub struct Square; pub mod c { - use foo::Point; - use foo::Square; //~ ERROR unused import: `foo::Square` + use crate::foo::Point; + use crate::foo::Square; //~ ERROR unused import: `crate::foo::Square` pub fn cc(_p: Point) -> super::Square { fn f() -> super::Square { super::Square @@ -74,7 +74,7 @@ fn g() { // cf. issue #35135. #[allow(unused_variables)] fn h() { - use test2::foo; //~ ERROR unused import: `test2::foo` + use crate::test2::foo; //~ ERROR unused import: `crate::test2::foo` let foo = 0; } @@ -83,6 +83,6 @@ fn main() { let mut a = 3; let mut b = 4; swap(&mut a, &mut b); - test::C.b(); + crate::test::C.b(); foo(); } diff --git a/tests/ui/lint/unused/lint-unused-imports.stderr b/tests/ui/lint/unused/lint-unused-imports.stderr index a848fb31eba..750bc059de0 100644 --- a/tests/ui/lint/unused/lint-unused-imports.stderr +++ b/tests/ui/lint/unused/lint-unused-imports.stderr @@ -28,11 +28,11 @@ error: unused import: `bar` LL | use test2::{foo, bar}; | ^^^ -error: unused import: `foo::Square` +error: unused import: `crate::foo::Square` --> $DIR/lint-unused-imports.rs:52:13 | -LL | use foo::Square; - | ^^^^^^^^^^^ +LL | use crate::foo::Square; + | ^^^^^^^^^^^^^^^^^^ error: unused import: `self::g` --> $DIR/lint-unused-imports.rs:68:9 @@ -40,11 +40,11 @@ error: unused import: `self::g` LL | use self::g; | ^^^^^^^ -error: unused import: `test2::foo` +error: unused import: `crate::test2::foo` --> $DIR/lint-unused-imports.rs:77:9 | -LL | use test2::foo; - | ^^^^^^^^^^ +LL | use crate::test2::foo; + | ^^^^^^^^^^^^^^^^^ error: unused import: `test::B2` --> $DIR/lint-unused-imports.rs:20:5 diff --git a/tests/ui/macros/macro-pub-matcher.rs b/tests/ui/macros/macro-pub-matcher.rs index 538f55cc98d..e0b03dbbeb1 100644 --- a/tests/ui/macros/macro-pub-matcher.rs +++ b/tests/ui/macros/macro-pub-matcher.rs @@ -68,15 +68,15 @@ mod with_crate { mod garden { mod with_pub_restricted_path { - vis_passthru! { pub(in garden) const A: i32 = 0; } - vis_passthru! { pub(in garden) enum B {} } - vis_passthru! { pub(in garden) extern "C" fn c() {} } - vis_passthru! { pub(in garden) mod d {} } - vis_passthru! { pub(in garden) static E: i32 = 0; } - vis_passthru! { pub(in garden) struct F; } - vis_passthru! { pub(in garden) trait G {} } - vis_passthru! { pub(in garden) type H = i32; } - vis_passthru! { pub(in garden) use A as I; } + vis_passthru! { pub(in crate::garden) const A: i32 = 0; } + vis_passthru! { pub(in crate::garden) enum B {} } + vis_passthru! { pub(in crate::garden) extern "C" fn c() {} } + vis_passthru! { pub(in crate::garden) mod d {} } + vis_passthru! { pub(in crate::garden) static E: i32 = 0; } + vis_passthru! { pub(in crate::garden) struct F; } + vis_passthru! { pub(in crate::garden) trait G {} } + vis_passthru! { pub(in crate::garden) type H = i32; } + vis_passthru! { pub(in crate::garden) use A as I; } } } diff --git a/tests/ui/macros/paths-in-macro-invocations.rs b/tests/ui/macros/paths-in-macro-invocations.rs index c1b7789d6de..b8f4784298d 100644 --- a/tests/ui/macros/paths-in-macro-invocations.rs +++ b/tests/ui/macros/paths-in-macro-invocations.rs @@ -11,26 +11,26 @@ mod foo { pub use two_macros::macro_one as bar; } trait T { foo::bar!(); - ::foo::bar!(); + crate::foo::bar!(); } struct S { x: foo::bar!(i32), - y: ::foo::bar!(i32), + y: crate::foo::bar!(i32), } impl S { foo::bar!(); - ::foo::bar!(); + crate::foo::bar!(); } fn main() { foo::bar!(); - ::foo::bar!(); + crate::foo::bar!(); let _ = foo::bar!(0); - let _ = ::foo::bar!(0); + let _ = crate::foo::bar!(0); let foo::bar!(_) = 0; - let ::foo::bar!(_) = 0; + let crate::foo::bar!(_) = 0; } diff --git a/tests/ui/moves/issue-34721.fixed b/tests/ui/moves/issue-34721.fixed index 995fd920da7..4fdbee4d60b 100644 --- a/tests/ui/moves/issue-34721.fixed +++ b/tests/ui/moves/issue-34721.fixed @@ -9,15 +9,15 @@ impl Foo for u32 { } pub mod bar { - pub use Foo; + pub use crate::Foo; pub fn bar(x: T) -> T { x.zero() } } mod baz { - use bar; - use Foo; + use crate::bar; + use crate::Foo; pub fn baz(x: T) -> T { if 0 == 1 { bar::bar(x.zero()) diff --git a/tests/ui/moves/issue-34721.rs b/tests/ui/moves/issue-34721.rs index 747b15b4e02..4591b545b23 100644 --- a/tests/ui/moves/issue-34721.rs +++ b/tests/ui/moves/issue-34721.rs @@ -9,15 +9,15 @@ impl Foo for u32 { } pub mod bar { - pub use Foo; + pub use crate::Foo; pub fn bar(x: T) -> T { x.zero() } } mod baz { - use bar; - use Foo; + use crate::bar; + use crate::Foo; pub fn baz(x: T) -> T { if 0 == 1 { bar::bar(x.zero()) diff --git a/tests/ui/namespace/namespaced-enum-glob-import-no-impls.rs b/tests/ui/namespace/namespaced-enum-glob-import-no-impls.rs index ab24f36f9a1..1586dd8bd59 100644 --- a/tests/ui/namespace/namespaced-enum-glob-import-no-impls.rs +++ b/tests/ui/namespace/namespaced-enum-glob-import-no-impls.rs @@ -12,11 +12,11 @@ mod m2 { } mod m { - pub use m2::Foo::*; + pub use crate::m2::Foo::*; } pub fn main() { - use m2::Foo::*; + use crate::m2::Foo::*; foo(); //~ ERROR cannot find function `foo` in this scope m::foo(); //~ ERROR cannot find function `foo` in module `m` diff --git a/tests/ui/pattern/issue-14221.rs b/tests/ui/pattern/issue-14221.rs index 13427d2c9b2..f5f419a6314 100644 --- a/tests/ui/pattern/issue-14221.rs +++ b/tests/ui/pattern/issue-14221.rs @@ -8,7 +8,7 @@ pub enum E { } pub mod b { - pub fn key(e: ::E) -> &'static str { + pub fn key(e: crate::E) -> &'static str { match e { A => "A", //~^ ERROR pattern binding `A` is named the same as one of the variants of the type `E` diff --git a/tests/ui/pattern/issue-22546.rs b/tests/ui/pattern/issue-22546.rs index fd1d5fb6c47..81908017b4e 100644 --- a/tests/ui/pattern/issue-22546.rs +++ b/tests/ui/pattern/issue-22546.rs @@ -7,7 +7,7 @@ use std::default::Default; #[derive(Default)] pub struct Foo(T, T); -impl Foo { +impl Foo { fn foo(&self) { match *self { Foo::(ref x, ref y) => println!("Goodbye, World! {} {}", x, y) @@ -36,7 +36,7 @@ fn main() { let w = Wrapper { value: Foo(10u8, 11u8) }; match w { Wrapper::> { value: Foo(10, 11) } => {}, - ::Wrapper::< as Tr>::U> { value: Foo::(11, 16) } => { panic!() }, + crate::Wrapper::< as Tr>::U> { value: Foo::(11, 16) } => { panic!() }, _ => { panic!() } } diff --git a/tests/ui/pattern/issue-6449.rs b/tests/ui/pattern/issue-6449.rs index 38399a18793..25152cf5d29 100644 --- a/tests/ui/pattern/issue-6449.rs +++ b/tests/ui/pattern/issue-6449.rs @@ -13,32 +13,32 @@ enum Other { fn main() { match Foo::Baz { - ::Foo::Bar(3) => panic!(), - ::Foo::Bar(_) if false => panic!(), - ::Foo::Bar(..) if false => panic!(), - ::Foo::Bar(_n) => panic!(), - ::Foo::Baz => {} + crate::Foo::Bar(3) => panic!(), + crate::Foo::Bar(_) if false => panic!(), + crate::Foo::Bar(..) if false => panic!(), + crate::Foo::Bar(_n) => panic!(), + crate::Foo::Baz => {} } match Foo::Bar(3) { - ::Foo::Bar(3) => {} - ::Foo::Bar(_) if false => panic!(), - ::Foo::Bar(..) if false => panic!(), - ::Foo::Bar(_n) => panic!(), - ::Foo::Baz => panic!(), + crate::Foo::Bar(3) => {} + crate::Foo::Bar(_) if false => panic!(), + crate::Foo::Bar(..) if false => panic!(), + crate::Foo::Bar(_n) => panic!(), + crate::Foo::Baz => panic!(), } match Foo::Bar(4) { - ::Foo::Bar(3) => panic!(), - ::Foo::Bar(_) if false => panic!(), - ::Foo::Bar(..) if false => panic!(), - ::Foo::Bar(n) => assert_eq!(n, 4), - ::Foo::Baz => panic!(), + crate::Foo::Bar(3) => panic!(), + crate::Foo::Bar(_) if false => panic!(), + crate::Foo::Bar(..) if false => panic!(), + crate::Foo::Bar(n) => assert_eq!(n, 4), + crate::Foo::Baz => panic!(), } match Other::Other1(Foo::Baz) { - ::Other::Other1(::Foo::Baz) => {} - ::Other::Other1(::Foo::Bar(_)) => {} - ::Other::Other2(::Foo::Baz, ::Foo::Bar(_)) => {} - ::Other::Other2(::Foo::Bar(..), ::Foo::Baz) => {} - ::Other::Other2(..) => {} + crate::Other::Other1(crate::Foo::Baz) => {} + crate::Other::Other1(crate::Foo::Bar(_)) => {} + crate::Other::Other2(crate::Foo::Baz, crate::Foo::Bar(_)) => {} + crate::Other::Other2(crate::Foo::Bar(..), crate::Foo::Baz) => {} + crate::Other::Other2(..) => {} } } diff --git a/tests/ui/pattern/missing_lifetime.rs b/tests/ui/pattern/missing_lifetime.rs index 081f667d8f6..53f8e155019 100644 --- a/tests/ui/pattern/missing_lifetime.rs +++ b/tests/ui/pattern/missing_lifetime.rs @@ -20,6 +20,6 @@ enum Other { fn main() { match Other::Other1(Foo::Baz) { - ::Other::Other2(::Foo::Bar(..)) => {} + crate::Other::Other2(crate::Foo::Bar(..)) => {} } } diff --git a/tests/ui/pattern/usefulness/uninhabited.rs b/tests/ui/pattern/usefulness/uninhabited.rs index 5c774b7874a..0e2793fb448 100644 --- a/tests/ui/pattern/usefulness/uninhabited.rs +++ b/tests/ui/pattern/usefulness/uninhabited.rs @@ -120,7 +120,7 @@ mod visibility { mod c { use super::*; pub struct AlsoSecretlyUninhabited { - _priv: ::Struct1, + _priv: crate::Struct1, } assert_empty!(SometimesEmptyStruct); assert_non_empty!(SometimesEmptyEnum); diff --git a/tests/ui/privacy/auxiliary/pub_use_mods_xcrate.rs b/tests/ui/privacy/auxiliary/pub_use_mods_xcrate.rs index 74d3504d5be..f754c01f3d5 100644 --- a/tests/ui/privacy/auxiliary/pub_use_mods_xcrate.rs +++ b/tests/ui/privacy/auxiliary/pub_use_mods_xcrate.rs @@ -1,5 +1,5 @@ pub mod a { - pub use a::b::c; + pub use crate::a::b::c; pub mod b { pub mod c { diff --git a/tests/ui/privacy/crate-private-reexport.rs b/tests/ui/privacy/crate-private-reexport.rs index fa4f88666d8..db0314683a0 100644 --- a/tests/ui/privacy/crate-private-reexport.rs +++ b/tests/ui/privacy/crate-private-reexport.rs @@ -5,10 +5,10 @@ struct S1 { bar: i32, } mod m1 { - pub use ::f1; //~ ERROR `f1` is only public within the crate, and cannot be re-exported outside - pub use ::S1; //~ ERROR `S1` is only public within the crate, and cannot be re-exported outside - pub use ::E1; //~ ERROR `E1` is only public within the crate, and cannot be re-exported outside - pub use ::E1::V; //~ ERROR `V` is only public within the crate, and cannot be re-exported outside + pub use crate::f1; //~ ERROR `f1` is only public within the crate, and cannot be re-exported outside + pub use crate::S1; //~ ERROR `S1` is only public within the crate, and cannot be re-exported outside + pub use crate::E1; //~ ERROR `E1` is only public within the crate, and cannot be re-exported outside + pub use crate::E1::V; //~ ERROR `V` is only public within the crate, and cannot be re-exported outside } pub(crate) fn f2() {} @@ -20,10 +20,10 @@ pub(crate) struct S2 { bar: i32, } mod m2 { - pub use ::f2; //~ ERROR `f2` is only public within the crate, and cannot be re-exported outside - pub use ::S2; //~ ERROR `S2` is only public within the crate, and cannot be re-exported outside - pub use ::E2; //~ ERROR `E2` is only public within the crate, and cannot be re-exported outside - pub use ::E2::V; //~ ERROR `V` is only public within the crate, and cannot be re-exported outside + pub use crate::f2; //~ ERROR `f2` is only public within the crate, and cannot be re-exported outside + pub use crate::S2; //~ ERROR `S2` is only public within the crate, and cannot be re-exported outside + pub use crate::E2; //~ ERROR `E2` is only public within the crate, and cannot be re-exported outside + pub use crate::E2::V; //~ ERROR `V` is only public within the crate, and cannot be re-exported outside } mod m3 { @@ -42,7 +42,7 @@ pub use m3::E3; //~ ERROR `E3` is only public within the crate, and cannot be re pub use m3::E3::V; //~ ERROR `V` is only public within the crate, and cannot be re-exported outside pub(self) fn f4() {} -pub use ::f4 as f5; //~ ERROR `f4` is only public within the crate, and cannot be re-exported outside +pub use crate::f4 as f5; //~ ERROR `f4` is only public within the crate, and cannot be re-exported outside pub mod m10 { pub mod m { diff --git a/tests/ui/privacy/crate-private-reexport.stderr b/tests/ui/privacy/crate-private-reexport.stderr index 66e11e82107..9b2626efacd 100644 --- a/tests/ui/privacy/crate-private-reexport.stderr +++ b/tests/ui/privacy/crate-private-reexport.stderr @@ -1,82 +1,82 @@ error[E0364]: `f1` is only public within the crate, and cannot be re-exported outside --> $DIR/crate-private-reexport.rs:8:13 | -LL | pub use ::f1; - | ^^^^ +LL | pub use crate::f1; + | ^^^^^^^^^ | note: consider marking `f1` as `pub` in the imported module --> $DIR/crate-private-reexport.rs:8:13 | -LL | pub use ::f1; - | ^^^^ +LL | pub use crate::f1; + | ^^^^^^^^^ error[E0365]: `S1` is only public within the crate, and cannot be re-exported outside --> $DIR/crate-private-reexport.rs:9:13 | -LL | pub use ::S1; - | ^^^^ re-export of crate public `S1` +LL | pub use crate::S1; + | ^^^^^^^^^ re-export of crate public `S1` | = note: consider declaring type or module `S1` with `pub` error[E0365]: `E1` is only public within the crate, and cannot be re-exported outside --> $DIR/crate-private-reexport.rs:10:13 | -LL | pub use ::E1; - | ^^^^ re-export of crate public `E1` +LL | pub use crate::E1; + | ^^^^^^^^^ re-export of crate public `E1` | = note: consider declaring type or module `E1` with `pub` error[E0364]: `V` is only public within the crate, and cannot be re-exported outside --> $DIR/crate-private-reexport.rs:11:13 | -LL | pub use ::E1::V; - | ^^^^^^^ +LL | pub use crate::E1::V; + | ^^^^^^^^^^^^ | note: consider marking `V` as `pub` in the imported module --> $DIR/crate-private-reexport.rs:11:13 | -LL | pub use ::E1::V; - | ^^^^^^^ +LL | pub use crate::E1::V; + | ^^^^^^^^^^^^ error[E0364]: `f2` is only public within the crate, and cannot be re-exported outside --> $DIR/crate-private-reexport.rs:23:13 | -LL | pub use ::f2; - | ^^^^ +LL | pub use crate::f2; + | ^^^^^^^^^ | note: consider marking `f2` as `pub` in the imported module --> $DIR/crate-private-reexport.rs:23:13 | -LL | pub use ::f2; - | ^^^^ +LL | pub use crate::f2; + | ^^^^^^^^^ error[E0365]: `S2` is only public within the crate, and cannot be re-exported outside --> $DIR/crate-private-reexport.rs:24:13 | -LL | pub use ::S2; - | ^^^^ re-export of crate public `S2` +LL | pub use crate::S2; + | ^^^^^^^^^ re-export of crate public `S2` | = note: consider declaring type or module `S2` with `pub` error[E0365]: `E2` is only public within the crate, and cannot be re-exported outside --> $DIR/crate-private-reexport.rs:25:13 | -LL | pub use ::E2; - | ^^^^ re-export of crate public `E2` +LL | pub use crate::E2; + | ^^^^^^^^^ re-export of crate public `E2` | = note: consider declaring type or module `E2` with `pub` error[E0364]: `V` is only public within the crate, and cannot be re-exported outside --> $DIR/crate-private-reexport.rs:26:13 | -LL | pub use ::E2::V; - | ^^^^^^^ +LL | pub use crate::E2::V; + | ^^^^^^^^^^^^ | note: consider marking `V` as `pub` in the imported module --> $DIR/crate-private-reexport.rs:26:13 | -LL | pub use ::E2::V; - | ^^^^^^^ +LL | pub use crate::E2::V; + | ^^^^^^^^^^^^ error[E0364]: `f3` is only public within the crate, and cannot be re-exported outside --> $DIR/crate-private-reexport.rs:39:9 @@ -121,14 +121,14 @@ LL | pub use m3::E3::V; error[E0364]: `f4` is only public within the crate, and cannot be re-exported outside --> $DIR/crate-private-reexport.rs:45:9 | -LL | pub use ::f4 as f5; - | ^^^^^^^^^^ +LL | pub use crate::f4 as f5; + | ^^^^^^^^^^^^^^^ | note: consider marking `f4` as `pub` in the imported module --> $DIR/crate-private-reexport.rs:45:9 | -LL | pub use ::f4 as f5; - | ^^^^^^^^^^ +LL | pub use crate::f4 as f5; + | ^^^^^^^^^^^^^^^ error[E0364]: `f6` is private, and cannot be re-exported --> $DIR/crate-private-reexport.rs:53:13 diff --git a/tests/ui/privacy/issue-30079.rs b/tests/ui/privacy/issue-30079.rs index ddba629f528..3725540c24b 100644 --- a/tests/ui/privacy/issue-30079.rs +++ b/tests/ui/privacy/issue-30079.rs @@ -2,7 +2,7 @@ struct SemiPriv; mod m1 { struct Priv; - impl ::SemiPriv { + impl crate::SemiPriv { pub fn f(_: Priv) {} //~ WARN type `m1::Priv` is more private than the item `m1::::f` } @@ -13,12 +13,12 @@ mod m1 { mod m2 { struct Priv; - impl ::std::ops::Deref for ::SemiPriv { + impl std::ops::Deref for crate::SemiPriv { type Target = Priv; //~ ERROR private type `m2::Priv` in public interface fn deref(&self) -> &Self::Target { unimplemented!() } } - impl ::std::ops::Deref for Priv { + impl std::ops::Deref for Priv { type Target = Priv; // ok fn deref(&self) -> &Self::Target { unimplemented!() } } @@ -30,7 +30,7 @@ trait SemiPrivTrait { mod m3 { struct Priv; - impl ::SemiPrivTrait for () { + impl crate::SemiPrivTrait for () { type Assoc = Priv; //~ ERROR private type `m3::Priv` in public interface } } diff --git a/tests/ui/privacy/issue-30079.stderr b/tests/ui/privacy/issue-30079.stderr index f1facba7cd2..fcee1b5a93c 100644 --- a/tests/ui/privacy/issue-30079.stderr +++ b/tests/ui/privacy/issue-30079.stderr @@ -16,7 +16,7 @@ error[E0446]: private type `m2::Priv` in public interface | LL | struct Priv; | ----------- `m2::Priv` declared as private -LL | impl ::std::ops::Deref for ::SemiPriv { +LL | impl std::ops::Deref for crate::SemiPriv { LL | type Target = Priv; | ^^^^^^^^^^^ can't leak private type @@ -25,7 +25,7 @@ error[E0446]: private type `m3::Priv` in public interface | LL | struct Priv; | ----------- `m3::Priv` declared as private -LL | impl ::SemiPrivTrait for () { +LL | impl crate::SemiPrivTrait for () { LL | type Assoc = Priv; | ^^^^^^^^^^ can't leak private type diff --git a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs index 796ba4d2332..1800648b954 100644 --- a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs +++ b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs @@ -26,7 +26,7 @@ mod rank { Full, } - pub(in rank) enum PettyOfficer { + pub(in crate::rank) enum PettyOfficer { SecondClass, FirstClass, Chief, diff --git a/tests/ui/privacy/legacy-ctor-visibility.rs b/tests/ui/privacy/legacy-ctor-visibility.rs index 5732b6446fe..e698a481173 100644 --- a/tests/ui/privacy/legacy-ctor-visibility.rs +++ b/tests/ui/privacy/legacy-ctor-visibility.rs @@ -4,7 +4,7 @@ mod m { pub struct S(u8); mod n { - use S; + use crate::S; fn f() { S(10); //~^ ERROR expected function, tuple struct or tuple variant, found struct `S` diff --git a/tests/ui/privacy/privacy-in-paths.rs b/tests/ui/privacy/privacy-in-paths.rs index 9cee2b89dd5..4baa9758bbe 100644 --- a/tests/ui/privacy/privacy-in-paths.rs +++ b/tests/ui/privacy/privacy-in-paths.rs @@ -2,7 +2,7 @@ mod foo { pub use self::bar::S; mod bar { pub struct S; - pub use baz; + pub use crate::baz; } trait T { @@ -21,9 +21,9 @@ pub mod baz { fn f() {} fn g() { - ::foo::bar::baz::f(); //~ERROR module `bar` is private - ::foo::bar::S::f(); //~ERROR module `bar` is private - <() as ::foo::T>::Assoc::f(); //~ERROR trait `T` is private + crate::foo::bar::baz::f(); //~ERROR module `bar` is private + crate::foo::bar::S::f(); //~ERROR module `bar` is private + <() as crate::foo::T>::Assoc::f(); //~ERROR trait `T` is private } } diff --git a/tests/ui/privacy/privacy-in-paths.stderr b/tests/ui/privacy/privacy-in-paths.stderr index e6ece35865d..4acb9baa66c 100644 --- a/tests/ui/privacy/privacy-in-paths.stderr +++ b/tests/ui/privacy/privacy-in-paths.stderr @@ -1,10 +1,10 @@ error[E0603]: module `bar` is private - --> $DIR/privacy-in-paths.rs:24:16 + --> $DIR/privacy-in-paths.rs:24:21 | -LL | ::foo::bar::baz::f(); - | ^^^ - function `f` is not publicly re-exported - | | - | private module +LL | crate::foo::bar::baz::f(); + | ^^^ - function `f` is not publicly re-exported + | | + | private module | note: the module `bar` is defined here --> $DIR/privacy-in-paths.rs:3:5 @@ -13,10 +13,10 @@ LL | mod bar { | ^^^^^^^ error[E0603]: module `bar` is private - --> $DIR/privacy-in-paths.rs:25:16 + --> $DIR/privacy-in-paths.rs:25:21 | -LL | ::foo::bar::S::f(); - | ^^^ private module +LL | crate::foo::bar::S::f(); + | ^^^ private module | note: the module `bar` is defined here --> $DIR/privacy-in-paths.rs:3:5 @@ -25,17 +25,17 @@ LL | mod bar { | ^^^^^^^ help: consider importing this struct through its public re-export instead | -LL - ::foo::bar::S::f(); +LL - crate::foo::bar::S::f(); LL + foo::S::f(); | error[E0603]: trait `T` is private - --> $DIR/privacy-in-paths.rs:26:23 + --> $DIR/privacy-in-paths.rs:26:28 | -LL | <() as ::foo::T>::Assoc::f(); - | ^ ----- associated type `Assoc` is not publicly re-exported - | | - | private trait +LL | <() as crate::foo::T>::Assoc::f(); + | ^ ----- associated type `Assoc` is not publicly re-exported + | | + | private trait | note: the trait `T` is defined here --> $DIR/privacy-in-paths.rs:8:5 diff --git a/tests/ui/privacy/privacy-ufcs.rs b/tests/ui/privacy/privacy-ufcs.rs index fec7f41340a..0ba682dde15 100644 --- a/tests/ui/privacy/privacy-ufcs.rs +++ b/tests/ui/privacy/privacy-ufcs.rs @@ -9,5 +9,5 @@ mod foo { } fn main() { - ::baz(); //~ERROR trait `Bar` is private + ::baz(); //~ERROR trait `Bar` is private } diff --git a/tests/ui/privacy/privacy-ufcs.stderr b/tests/ui/privacy/privacy-ufcs.stderr index 5c986895d64..0608c06e8a4 100644 --- a/tests/ui/privacy/privacy-ufcs.stderr +++ b/tests/ui/privacy/privacy-ufcs.stderr @@ -1,10 +1,10 @@ error[E0603]: trait `Bar` is private - --> $DIR/privacy-ufcs.rs:12:20 + --> $DIR/privacy-ufcs.rs:12:25 | -LL | ::baz(); - | ^^^ --- associated function `baz` is not publicly re-exported - | | - | private trait +LL | ::baz(); + | ^^^ --- associated function `baz` is not publicly re-exported + | | + | private trait | note: the trait `Bar` is defined here --> $DIR/privacy-ufcs.rs:4:5 diff --git a/tests/ui/privacy/privacy1.rs b/tests/ui/privacy/privacy1.rs index 9436441ecc6..6cd12b80782 100644 --- a/tests/ui/privacy/privacy1.rs +++ b/tests/ui/privacy/privacy1.rs @@ -98,34 +98,34 @@ fn lol() { mod foo { fn test() { - ::bar::A::foo(); - ::bar::A::bar(); //~ ERROR: associated function `bar` is private - ::bar::A.foo2(); - ::bar::baz::A::foo(); //~ ERROR: module `baz` is private - ::bar::baz::A::bar(); //~ ERROR: module `baz` is private + crate::bar::A::foo(); + crate::bar::A::bar(); //~ ERROR: associated function `bar` is private + crate::bar::A.foo2(); + crate::bar::baz::A::foo(); //~ ERROR: module `baz` is private + crate::bar::baz::A::bar(); //~ ERROR: module `baz` is private //~^ ERROR: associated function `bar` is private - ::bar::baz::A.foo2(); //~ ERROR: module `baz` is private - ::bar::baz::A.bar2(); //~ ERROR: module `baz` is private + crate::bar::baz::A.foo2(); //~ ERROR: module `baz` is private + crate::bar::baz::A.bar2(); //~ ERROR: module `baz` is private //~^ ERROR: method `bar2` is private let _: isize = - ::bar::B::foo(); //~ ERROR: trait `B` is private - ::lol(); + crate::bar::B::foo(); //~ ERROR: trait `B` is private + crate::lol(); - ::bar::Enum::Pub; + crate::bar::Enum::Pub; unsafe { - ::bar::epriv(); //~ ERROR: function `epriv` is private - ::bar::epub(); + crate::bar::epriv(); //~ ERROR: function `epriv` is private + crate::bar::epub(); } - ::bar::foo(); - ::bar::bar(); + crate::bar::foo(); + crate::bar::bar(); - ::bar::gpub(); + crate::bar::gpub(); - ::bar::baz::foo(); //~ ERROR: module `baz` is private - ::bar::baz::bar(); //~ ERROR: module `baz` is private + crate::bar::baz::foo(); //~ ERROR: module `baz` is private + crate::bar::baz::bar(); //~ ERROR: module `baz` is private } fn test2() { @@ -154,7 +154,7 @@ mod foo { bar::bar(); } - impl ::bar::B for f32 { fn foo() -> f32 { 1.0 } } + impl crate::bar::B for f32 { fn foo() -> f32 { 1.0 } } //~^ ERROR: trait `B` is private } diff --git a/tests/ui/privacy/privacy1.stderr b/tests/ui/privacy/privacy1.stderr index cb7b858e54d..1f2f4a92c48 100644 --- a/tests/ui/privacy/privacy1.stderr +++ b/tests/ui/privacy/privacy1.stderr @@ -48,12 +48,12 @@ LL | mod i { | ^^^^^ error[E0603]: module `baz` is private - --> $DIR/privacy1.rs:104:16 + --> $DIR/privacy1.rs:104:21 | -LL | ::bar::baz::A::foo(); - | ^^^ - struct `A` is not publicly re-exported - | | - | private module +LL | crate::bar::baz::A::foo(); + | ^^^ - struct `A` is not publicly re-exported + | | + | private module | note: the module `baz` is defined here --> $DIR/privacy1.rs:50:5 @@ -62,12 +62,12 @@ LL | mod baz { | ^^^^^^^ error[E0603]: module `baz` is private - --> $DIR/privacy1.rs:105:16 + --> $DIR/privacy1.rs:105:21 | -LL | ::bar::baz::A::bar(); - | ^^^ - struct `A` is not publicly re-exported - | | - | private module +LL | crate::bar::baz::A::bar(); + | ^^^ - struct `A` is not publicly re-exported + | | + | private module | note: the module `baz` is defined here --> $DIR/privacy1.rs:50:5 @@ -76,12 +76,12 @@ LL | mod baz { | ^^^^^^^ error[E0603]: module `baz` is private - --> $DIR/privacy1.rs:107:16 + --> $DIR/privacy1.rs:107:21 | -LL | ::bar::baz::A.foo2(); - | ^^^ - unit struct `A` is not publicly re-exported - | | - | private module +LL | crate::bar::baz::A.foo2(); + | ^^^ - unit struct `A` is not publicly re-exported + | | + | private module | note: the module `baz` is defined here --> $DIR/privacy1.rs:50:5 @@ -90,12 +90,12 @@ LL | mod baz { | ^^^^^^^ error[E0603]: module `baz` is private - --> $DIR/privacy1.rs:108:16 + --> $DIR/privacy1.rs:108:21 | -LL | ::bar::baz::A.bar2(); - | ^^^ - unit struct `A` is not publicly re-exported - | | - | private module +LL | crate::bar::baz::A.bar2(); + | ^^^ - unit struct `A` is not publicly re-exported + | | + | private module | note: the module `baz` is defined here --> $DIR/privacy1.rs:50:5 @@ -104,12 +104,12 @@ LL | mod baz { | ^^^^^^^ error[E0603]: trait `B` is private - --> $DIR/privacy1.rs:112:16 + --> $DIR/privacy1.rs:112:21 | -LL | ::bar::B::foo(); - | ^ --- associated function `foo` is not publicly re-exported - | | - | private trait +LL | crate::bar::B::foo(); + | ^ --- associated function `foo` is not publicly re-exported + | | + | private trait | note: the trait `B` is defined here --> $DIR/privacy1.rs:40:5 @@ -118,10 +118,10 @@ LL | trait B { | ^^^^^^^ error[E0603]: function `epriv` is private - --> $DIR/privacy1.rs:118:20 + --> $DIR/privacy1.rs:118:25 | -LL | ::bar::epriv(); - | ^^^^^ private function +LL | crate::bar::epriv(); + | ^^^^^ private function | note: the function `epriv` is defined here --> $DIR/privacy1.rs:65:9 @@ -130,10 +130,10 @@ LL | fn epriv(); | ^^^^^^^^^^^ error[E0603]: module `baz` is private - --> $DIR/privacy1.rs:127:16 + --> $DIR/privacy1.rs:127:21 | -LL | ::bar::baz::foo(); - | ^^^ private module +LL | crate::bar::baz::foo(); + | ^^^ private module | note: the module `baz` is defined here --> $DIR/privacy1.rs:50:5 @@ -142,15 +142,15 @@ LL | mod baz { | ^^^^^^^ help: consider importing this function through its public re-export instead | -LL - ::bar::baz::foo(); +LL - crate::bar::baz::foo(); LL + bar::foo(); | error[E0603]: module `baz` is private - --> $DIR/privacy1.rs:128:16 + --> $DIR/privacy1.rs:128:21 | -LL | ::bar::baz::bar(); - | ^^^ private module +LL | crate::bar::baz::bar(); + | ^^^ private module | note: the module `baz` is defined here --> $DIR/privacy1.rs:50:5 @@ -159,15 +159,15 @@ LL | mod baz { | ^^^^^^^ help: consider importing this function through its public re-export instead | -LL - ::bar::baz::bar(); +LL - crate::bar::baz::bar(); LL + bar::bar(); | error[E0603]: trait `B` is private - --> $DIR/privacy1.rs:157:17 + --> $DIR/privacy1.rs:157:22 | -LL | impl ::bar::B for f32 { fn foo() -> f32 { 1.0 } } - | ^ private trait +LL | impl crate::bar::B for f32 { fn foo() -> f32 { 1.0 } } + | ^ private trait | note: the trait `B` is defined here --> $DIR/privacy1.rs:40:5 @@ -194,31 +194,31 @@ LL | bar::A::bar(); | ^^^ private associated function error[E0624]: associated function `bar` is private - --> $DIR/privacy1.rs:102:19 + --> $DIR/privacy1.rs:102:24 | LL | fn bar() {} | -------- private associated function defined here ... -LL | ::bar::A::bar(); - | ^^^ private associated function +LL | crate::bar::A::bar(); + | ^^^ private associated function error[E0624]: associated function `bar` is private - --> $DIR/privacy1.rs:105:24 + --> $DIR/privacy1.rs:105:29 | LL | fn bar() {} | -------- private associated function defined here ... -LL | ::bar::baz::A::bar(); - | ^^^ private associated function +LL | crate::bar::baz::A::bar(); + | ^^^ private associated function error[E0624]: method `bar2` is private - --> $DIR/privacy1.rs:108:23 + --> $DIR/privacy1.rs:108:28 | LL | fn bar2(&self) {} | -------------- private method defined here ... -LL | ::bar::baz::A.bar2(); - | ^^^^ private method +LL | crate::bar::baz::A.bar2(); + | ^^^^ private method error: aborting due to 18 previous errors diff --git a/tests/ui/privacy/privacy2.rs b/tests/ui/privacy/privacy2.rs index e44100a8059..d4c4faf8ac4 100644 --- a/tests/ui/privacy/privacy2.rs +++ b/tests/ui/privacy/privacy2.rs @@ -10,7 +10,7 @@ mod bar { pub use self::glob::*; pub mod glob { - use foo; + use crate::foo; } } diff --git a/tests/ui/privacy/privacy2.stderr b/tests/ui/privacy/privacy2.stderr index b70134965fa..3d36f26f784 100644 --- a/tests/ui/privacy/privacy2.stderr +++ b/tests/ui/privacy/privacy2.stderr @@ -13,8 +13,8 @@ LL | use bar::glob::foo; note: the function import `foo` is defined here... --> $DIR/privacy2.rs:13:13 | -LL | use foo; - | ^^^ +LL | use crate::foo; + | ^^^^^^^^^^ note: ...and refers to the function `foo` which is defined here --> $DIR/privacy2.rs:17:1 | diff --git a/tests/ui/privacy/private-inferred-type-1.rs b/tests/ui/privacy/private-inferred-type-1.rs index b3eba53dd13..c5d90d50df4 100644 --- a/tests/ui/privacy/private-inferred-type-1.rs +++ b/tests/ui/privacy/private-inferred-type-1.rs @@ -12,9 +12,9 @@ trait Ref { mod m { struct Priv; - impl ::Arr0 for [Priv; 0] { fn arr0_secret(&self) {} } - impl ::TyParam for Option { fn ty_param_secret(&self) {} } - impl<'a> ::Ref for &'a Priv { fn ref_secret(self) {} } + impl crate::Arr0 for [Priv; 0] { fn arr0_secret(&self) {} } + impl crate::TyParam for Option { fn ty_param_secret(&self) {} } + impl<'a> crate::Ref for &'a Priv { fn ref_secret(self) {} } } fn anyref<'a, T>() -> &'a T { panic!() } diff --git a/tests/ui/privacy/restricted/lookup-ignores-private.rs b/tests/ui/privacy/restricted/lookup-ignores-private.rs index 7060db0092f..40fd8ff45b5 100644 --- a/tests/ui/privacy/restricted/lookup-ignores-private.rs +++ b/tests/ui/privacy/restricted/lookup-ignores-private.rs @@ -2,14 +2,14 @@ #![allow(warnings)] mod foo { - pub use foo::bar::S; + pub use crate::foo::bar::S; mod bar { #[derive(Default)] pub struct S { - pub(in foo) x: i32, + pub(in crate::foo) x: i32, } impl S { - pub(in foo) fn f(&self) -> i32 { 0 } + pub(in crate::foo) fn f(&self) -> i32 { 0 } } pub struct S2 { @@ -19,7 +19,7 @@ mod foo { pub(crate) fn f(&self) -> bool { false } } - impl ::std::ops::Deref for S { + impl std::ops::Deref for S { type Target = S2; fn deref(&self) -> &S2 { unimplemented!() } } diff --git a/tests/ui/privacy/restricted/private-in-public.rs b/tests/ui/privacy/restricted/private-in-public.rs index fa8371436b5..f54ab1d5a4a 100644 --- a/tests/ui/privacy/restricted/private-in-public.rs +++ b/tests/ui/privacy/restricted/private-in-public.rs @@ -2,7 +2,7 @@ mod foo { struct Priv; mod bar { - use foo::Priv; + use crate::foo::Priv; pub(super) fn f(_: Priv) {} pub(crate) fn g(_: Priv) {} pub(crate) fn h(_: Priv) {} diff --git a/tests/ui/privacy/restricted/struct-literal-field.rs b/tests/ui/privacy/restricted/struct-literal-field.rs index 9c6104755a4..2bb2a7fe95f 100644 --- a/tests/ui/privacy/restricted/struct-literal-field.rs +++ b/tests/ui/privacy/restricted/struct-literal-field.rs @@ -3,7 +3,7 @@ mod foo { pub mod bar { pub struct S { - pub(in foo) x: i32, + pub(in crate::foo) x: i32, } } @@ -14,6 +14,6 @@ mod foo { } fn main() { - use foo::bar::S; + use crate::foo::bar::S; S { x: 0 }; //~ ERROR private } diff --git a/tests/ui/proc-macro/crate-var.rs b/tests/ui/proc-macro/crate-var.rs index cea5d48e080..56e9affae8b 100644 --- a/tests/ui/proc-macro/crate-var.rs +++ b/tests/ui/proc-macro/crate-var.rs @@ -31,7 +31,7 @@ macro_rules! local { () => { mod qself { #[derive(Double)] - struct QSelf(<::Foo as $crate::Trait>::Assoc); + struct QSelf(::Assoc); } mod qself_recurse { @@ -43,7 +43,7 @@ macro_rules! local { () => { #[derive(Double)] #[repr(u32)] enum QSelfInConst { - Variant = <::Foo as $crate::Trait>::CONST, + Variant = ::CONST, } } } } diff --git a/tests/ui/proc-macro/helper-attr-blocked-by-import.rs b/tests/ui/proc-macro/helper-attr-blocked-by-import.rs index 53c079fd19c..bb5006d1c11 100644 --- a/tests/ui/proc-macro/helper-attr-blocked-by-import.rs +++ b/tests/ui/proc-macro/helper-attr-blocked-by-import.rs @@ -10,7 +10,7 @@ use self::two::*; mod empty_helper {} mod one { - use empty_helper; + use crate::empty_helper; #[derive(Empty)] #[empty_helper] @@ -18,7 +18,7 @@ mod one { } mod two { - use empty_helper; + use crate::empty_helper; #[derive(Empty)] #[empty_helper] diff --git a/tests/ui/proc-macro/issue-50493.rs b/tests/ui/proc-macro/issue-50493.rs index 4a88eee2185..2621e595baa 100644 --- a/tests/ui/proc-macro/issue-50493.rs +++ b/tests/ui/proc-macro/issue-50493.rs @@ -5,7 +5,7 @@ extern crate issue_50493; #[derive(Derive)] struct Restricted { - pub(in restricted) field: usize, //~ ERROR visibilities can only be restricted to ancestor modules + pub(in crate::restricted) field: usize, //~ ERROR visibilities can only be restricted to ancestor modules } mod restricted {} diff --git a/tests/ui/proc-macro/issue-50493.stderr b/tests/ui/proc-macro/issue-50493.stderr index 1cd3583135b..fc76e207bc7 100644 --- a/tests/ui/proc-macro/issue-50493.stderr +++ b/tests/ui/proc-macro/issue-50493.stderr @@ -1,8 +1,8 @@ error[E0742]: visibilities can only be restricted to ancestor modules --> $DIR/issue-50493.rs:8:12 | -LL | pub(in restricted) field: usize, - | ^^^^^^^^^^ +LL | pub(in crate::restricted) field: usize, + | ^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/proc-macro/issue-53481.rs b/tests/ui/proc-macro/issue-53481.rs index 11e11e2e6b6..ab5f175faf4 100644 --- a/tests/ui/proc-macro/issue-53481.rs +++ b/tests/ui/proc-macro/issue-53481.rs @@ -5,7 +5,7 @@ extern crate test_macros; mod m1 { - use m2::Empty; + use crate::m2::Empty; #[derive(Empty)] struct A {} diff --git a/tests/ui/pub/pub-reexport-priv-extern-crate.rs b/tests/ui/pub/pub-reexport-priv-extern-crate.rs index fb495be4001..9d615be30f4 100644 --- a/tests/ui/pub/pub-reexport-priv-extern-crate.rs +++ b/tests/ui/pub/pub-reexport-priv-extern-crate.rs @@ -7,14 +7,14 @@ mod foo1 { } mod foo2 { - use foo1::core; //~ ERROR crate import `core` is private + use crate::foo1::core; //~ ERROR crate import `core` is private pub mod bar { extern crate core; } } mod baz { - pub use foo2::bar::core; //~ ERROR crate import `core` is private + pub use crate::foo2::bar::core; //~ ERROR crate import `core` is private } fn main() {} diff --git a/tests/ui/pub/pub-reexport-priv-extern-crate.stderr b/tests/ui/pub/pub-reexport-priv-extern-crate.stderr index 8ab6e83641d..9bb64a3325b 100644 --- a/tests/ui/pub/pub-reexport-priv-extern-crate.stderr +++ b/tests/ui/pub/pub-reexport-priv-extern-crate.stderr @@ -1,8 +1,8 @@ error[E0603]: crate import `core` is private - --> $DIR/pub-reexport-priv-extern-crate.rs:10:15 + --> $DIR/pub-reexport-priv-extern-crate.rs:10:22 | -LL | use foo1::core; - | ^^^^ private crate import +LL | use crate::foo1::core; + | ^^^^ private crate import | note: the crate import `core` is defined here --> $DIR/pub-reexport-priv-extern-crate.rs:6:5 @@ -11,10 +11,10 @@ LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ error[E0603]: crate import `core` is private - --> $DIR/pub-reexport-priv-extern-crate.rs:17:24 + --> $DIR/pub-reexport-priv-extern-crate.rs:17:31 | -LL | pub use foo2::bar::core; - | ^^^^ private crate import +LL | pub use crate::foo2::bar::core; + | ^^^^ private crate import | note: the crate import `core` is defined here --> $DIR/pub-reexport-priv-extern-crate.rs:12:9 diff --git a/tests/ui/pub/pub-restricted.rs b/tests/ui/pub/pub-restricted.rs index 2aa24121335..4d5eda69de5 100644 --- a/tests/ui/pub/pub-restricted.rs +++ b/tests/ui/pub/pub-restricted.rs @@ -7,7 +7,7 @@ pub (crate::a) fn cfn() {} //~ ERROR incorrect visibility restriction pub fn privfn() {} mod x { mod y { - pub (in x) fn foo() {} + pub (in crate::x) fn foo() {} pub (super) fn bar() {} pub (crate) fn qux() {} } @@ -18,9 +18,9 @@ mod y { pub (crate) c: usize, pub (super) s: usize, valid_private: usize, - pub (in y) valid_in_x: usize, + pub (in crate::y) valid_in_x: usize, pub (a) invalid: usize, //~ ERROR incorrect visibility restriction - pub (in x) non_parent_invalid: usize, //~ ERROR visibilities can only be restricted + pub (in crate::x) non_parent_invalid: usize, //~ ERROR visibilities can only be restricted } } diff --git a/tests/ui/pub/pub-restricted.stderr b/tests/ui/pub/pub-restricted.stderr index 6c913938bb8..0548116362b 100644 --- a/tests/ui/pub/pub-restricted.stderr +++ b/tests/ui/pub/pub-restricted.stderr @@ -76,8 +76,8 @@ LL | pub (in xyz) fn xyz() {} error[E0742]: visibilities can only be restricted to ancestor modules --> $DIR/pub-restricted.rs:23:17 | -LL | pub (in x) non_parent_invalid: usize, - | ^ +LL | pub (in crate::x) non_parent_invalid: usize, + | ^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/recursion/auxiliary/recursive_reexports.rs b/tests/ui/recursion/auxiliary/recursive_reexports.rs index f98fa71009f..47a79090f4d 100644 --- a/tests/ui/recursion/auxiliary/recursive_reexports.rs +++ b/tests/ui/recursion/auxiliary/recursive_reexports.rs @@ -1,3 +1,3 @@ pub mod foo { - pub use foo; + pub use crate::foo; } diff --git a/tests/ui/recursion_limit/issue-40003.rs b/tests/ui/recursion_limit/issue-40003.rs index 5032d0c9db3..6bc40690dad 100644 --- a/tests/ui/recursion_limit/issue-40003.rs +++ b/tests/ui/recursion_limit/issue-40003.rs @@ -17,7 +17,7 @@ use future::{Future, IntoFuture}; mod future { use std::result; - use {stream, Stream}; + use crate::{stream, Stream}; pub trait Future { type Item; @@ -100,7 +100,7 @@ mod future { } mod stream { - use IntoFuture; + use crate::IntoFuture; pub trait Stream { type Item; -- cgit 1.4.1-3-g733a5 From d2bf16ad6d80827800798a00ba584f95e9689573 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Fri, 9 May 2025 09:38:17 -0400 Subject: Rename `LifetimeSyntax` variants to lang-team-approved names --- compiler/rustc_ast_lowering/src/lib.rs | 6 +-- compiler/rustc_hir/src/hir.rs | 72 +++++++++++++--------------- compiler/rustc_hir/src/hir/tests.rs | 2 +- compiler/rustc_trait_selection/src/errors.rs | 2 +- 4 files changed, 39 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index f41627e479f..64d4a00ea4d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1406,7 +1406,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi(); let region = Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }; - (region, LifetimeSyntax::Hidden) + (region, LifetimeSyntax::Implicit) } }; self.lower_lifetime(®ion, LifetimeSource::Reference, syntax) @@ -1790,7 +1790,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id, Ident::new(kw::UnderscoreLifetime, span), LifetimeSource::Path { angle_brackets }, - LifetimeSyntax::Hidden, + LifetimeSyntax::Implicit, ) } @@ -2422,7 +2422,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { Ident::new(kw::UnderscoreLifetime, self.lower_span(span)), hir::LifetimeKind::ImplicitObjectLifetimeDefault, LifetimeSource::Other, - LifetimeSyntax::Hidden, + LifetimeSyntax::Implicit, ); debug!("elided_dyn_bound: r={:?}", r); self.arena.alloc(r) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4f05e1c816c..974c24ef0f8 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -72,13 +72,13 @@ pub enum LifetimeSource { #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] pub enum LifetimeSyntax { /// E.g. `&Type`, `ContainsLifetime` - Hidden, + Implicit, /// E.g. `&'_ Type`, `ContainsLifetime<'_>`, `impl Trait + '_`, `impl Trait + use<'_>` - Anonymous, + ExplicitAnonymous, /// E.g. `&'a Type`, `ContainsLifetime<'a>`, `impl Trait + 'a`, `impl Trait + use<'a>` - Named, + ExplicitBound, } impl From for LifetimeSyntax { @@ -88,10 +88,10 @@ impl From for LifetimeSyntax { if name == sym::empty { unreachable!("A lifetime name should never be empty"); } else if name == kw::UnderscoreLifetime { - LifetimeSyntax::Anonymous + LifetimeSyntax::ExplicitAnonymous } else { debug_assert!(name.as_str().starts_with('\'')); - LifetimeSyntax::Named + LifetimeSyntax::ExplicitBound } } } @@ -102,48 +102,48 @@ impl From for LifetimeSyntax { /// /// ``` /// #[repr(C)] -/// struct S<'a>(&'a u32); // res=Param, name='a, source=Reference, syntax=Named +/// struct S<'a>(&'a u32); // res=Param, name='a, source=Reference, syntax=ExplicitBound /// unsafe extern "C" { -/// fn f1(s: S); // res=Param, name='_, source=Path, syntax=Hidden -/// fn f2(s: S<'_>); // res=Param, name='_, source=Path, syntax=Anonymous -/// fn f3<'a>(s: S<'a>); // res=Param, name='a, source=Path, syntax=Named +/// fn f1(s: S); // res=Param, name='_, source=Path, syntax=Implicit +/// fn f2(s: S<'_>); // res=Param, name='_, source=Path, syntax=ExplicitAnonymous +/// fn f3<'a>(s: S<'a>); // res=Param, name='a, source=Path, syntax=ExplicitBound /// } /// -/// struct St<'a> { x: &'a u32 } // res=Param, name='a, source=Reference, syntax=Named +/// struct St<'a> { x: &'a u32 } // res=Param, name='a, source=Reference, syntax=ExplicitBound /// fn f() { -/// _ = St { x: &0 }; // res=Infer, name='_, source=Path, syntax=Hidden -/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, source=Path, syntax=Anonymous +/// _ = St { x: &0 }; // res=Infer, name='_, source=Path, syntax=Implicit +/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, source=Path, syntax=ExplicitAnonymous /// } /// -/// struct Name<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=Named -/// const A: Name = Name("a"); // res=Static, name='_, source=Path, syntax=Hidden -/// const B: &str = ""; // res=Static, name='_, source=Reference, syntax=Hidden -/// static C: &'_ str = ""; // res=Static, name='_, source=Reference, syntax=Anonymous -/// static D: &'static str = ""; // res=Static, name='static, source=Reference, syntax=Named +/// struct Name<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=ExplicitBound +/// const A: Name = Name("a"); // res=Static, name='_, source=Path, syntax=Implicit +/// const B: &str = ""; // res=Static, name='_, source=Reference, syntax=Implicit +/// static C: &'_ str = ""; // res=Static, name='_, source=Reference, syntax=ExplicitAnonymous +/// static D: &'static str = ""; // res=Static, name='static, source=Reference, syntax=ExplicitBound /// /// trait Tr {} -/// fn tr(_: Box) {} // res=ImplicitObjectLifetimeDefault, name='_, source=Other, syntax=Hidden +/// fn tr(_: Box) {} // res=ImplicitObjectLifetimeDefault, name='_, source=Other, syntax=Implicit /// /// fn capture_outlives<'a>() -> -/// impl FnOnce() + 'a // res=Param, ident='a, source=OutlivesBound, syntax=Named +/// impl FnOnce() + 'a // res=Param, ident='a, source=OutlivesBound, syntax=ExplicitBound /// { /// || {} /// } /// /// fn capture_precise<'a>() -> -/// impl FnOnce() + use<'a> // res=Param, ident='a, source=PreciseCapturing, syntax=Named +/// impl FnOnce() + use<'a> // res=Param, ident='a, source=PreciseCapturing, syntax=ExplicitBound /// { /// || {} /// } /// /// // (commented out because these cases trigger errors) -/// // struct S1<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=Named -/// // struct S2(S1); // res=Error, name='_, source=Path, syntax=Hidden -/// // struct S3(S1<'_>); // res=Error, name='_, source=Path, syntax=Anonymous -/// // struct S4(S1<'a>); // res=Error, name='a, source=Path, syntax=Named +/// // struct S1<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=ExplicitBound +/// // struct S2(S1); // res=Error, name='_, source=Path, syntax=Implicit +/// // struct S3(S1<'_>); // res=Error, name='_, source=Path, syntax=ExplicitAnonymous +/// // struct S4(S1<'a>); // res=Error, name='a, source=Path, syntax=ExplicitBound /// ``` /// -/// Some combinations that cannot occur are `LifetimeSyntax::Hidden` with +/// Some combinations that cannot occur are `LifetimeSyntax::Implicit` with /// `LifetimeSource::OutlivesBound` or `LifetimeSource::PreciseCapturing` /// — there's no way to "elide" these lifetimes. #[derive(Debug, Copy, Clone, HashStable_Generic)] @@ -287,12 +287,8 @@ impl Lifetime { self.ident.name == kw::UnderscoreLifetime } - pub fn is_syntactically_hidden(&self) -> bool { - matches!(self.syntax, LifetimeSyntax::Hidden) - } - - pub fn is_syntactically_anonymous(&self) -> bool { - matches!(self.syntax, LifetimeSyntax::Anonymous) + pub fn is_implicit(&self) -> bool { + matches!(self.syntax, LifetimeSyntax::Implicit) } pub fn is_static(&self) -> bool { @@ -307,28 +303,28 @@ impl Lifetime { match (self.syntax, self.source) { // The user wrote `'a` or `'_`. - (Named | Anonymous, _) => (self.ident.span, format!("{new_lifetime}")), + (ExplicitBound | ExplicitAnonymous, _) => (self.ident.span, format!("{new_lifetime}")), // The user wrote `Path`, and omitted the `'_,`. - (Hidden, Path { angle_brackets: AngleBrackets::Full }) => { + (Implicit, Path { angle_brackets: AngleBrackets::Full }) => { (self.ident.span, format!("{new_lifetime}, ")) } // The user wrote `Path<>`, and omitted the `'_`.. - (Hidden, Path { angle_brackets: AngleBrackets::Empty }) => { + (Implicit, Path { angle_brackets: AngleBrackets::Empty }) => { (self.ident.span, format!("{new_lifetime}")) } // The user wrote `Path` and omitted the `<'_>`. - (Hidden, Path { angle_brackets: AngleBrackets::Missing }) => { + (Implicit, Path { angle_brackets: AngleBrackets::Missing }) => { (self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>")) } // The user wrote `&type` or `&mut type`. - (Hidden, Reference) => (self.ident.span, format!("{new_lifetime} ")), + (Implicit, Reference) => (self.ident.span, format!("{new_lifetime} ")), - (Hidden, source) => { - unreachable!("can't suggest for a hidden lifetime of {source:?}") + (Implicit, source) => { + unreachable!("can't suggest for a implicit lifetime of {source:?}") } } } diff --git a/compiler/rustc_hir/src/hir/tests.rs b/compiler/rustc_hir/src/hir/tests.rs index 8684adee29c..1fd793bc161 100644 --- a/compiler/rustc_hir/src/hir/tests.rs +++ b/compiler/rustc_hir/src/hir/tests.rs @@ -55,7 +55,7 @@ fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) { ident: Ident::new(sym::name, DUMMY_SP), kind: LifetimeKind::Static, source: LifetimeSource::Other, - syntax: LifetimeSyntax::Hidden, + syntax: LifetimeSyntax::Implicit, }; let unambig = TyKind::TraitObject::<'_, ()>(&[], TaggedRef::new(<, syntax)); let unambig_to_ambig = unsafe { std::mem::transmute::<_, TyKind<'_, AmbigArg>>(unambig) }; diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 779c861637a..ee79d31ac69 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -592,7 +592,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { matches!( arg, hir::GenericArg::Lifetime(lifetime) - if lifetime.is_syntactically_hidden() + if lifetime.is_implicit() ) }) { self.suggestions.push(( -- cgit 1.4.1-3-g733a5 From 41fdc80dcecded3eb4716eefbe17680db9b37e22 Mon Sep 17 00:00:00 2001 From: sayantn Date: Tue, 3 Jun 2025 18:54:56 +0530 Subject: Update stdarch submodule --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index b6e2249e388..5c1c436524c 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit b6e2249e388f520627544812649b77b0944e1a2e +Subproject commit 5c1c436524c0bbc8db83577f42f8bea9006a7b75 -- cgit 1.4.1-3-g733a5 From d91c1af24b551d5fead9fb7b9e2125574aab8b5c Mon Sep 17 00:00:00 2001 From: sayantn Date: Tue, 3 Jun 2025 20:37:10 +0530 Subject: Add impl for `llvm.roundeven` in cg_clif - remove unused `llvm.aarch64.neon.frintn` from cg_clif --- compiler/rustc_codegen_cranelift/example/neon.rs | 2 +- compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs | 8 ++++++++ compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs | 8 -------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/example/neon.rs b/compiler/rustc_codegen_cranelift/example/neon.rs index 69ce17d3d75..704f866e2c4 100644 --- a/compiler/rustc_codegen_cranelift/example/neon.rs +++ b/compiler/rustc_codegen_cranelift/example/neon.rs @@ -233,7 +233,7 @@ unsafe fn test_vaddvq_f32() { #[cfg(target_arch = "aarch64")] unsafe fn test_vrndnq_f32() { - // AArch64 llvm intrinsic: llvm.aarch64.neon.frintn.v4f32 + // llvm intrinsic: llvm.roundeven.v4f32 let a = f32x4::from([0.1, -1.9, 4.5, 5.5]); let e = f32x4::from([0., -2., 4., 6.]); let r: f32x4 = transmute(vrndnq_f32(transmute(a))); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index 2e02e85a997..81dc038a551 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -62,6 +62,14 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( }); } + _ if intrinsic.starts_with("llvm.roundeven.v") => { + intrinsic_args!(fx, args => (v); intrinsic); + + simd_for_each_lane(fx, v, ret, &|fx, _lane_ty, _res_lane_ty, lane| { + fx.bcx.ins().nearest(lane) + }); + } + _ => { fx.tcx .dcx() diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs index d22483cf177..5448f1b1e90 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs @@ -264,14 +264,6 @@ pub(super) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().fadd(a, b)); } - _ if intrinsic.starts_with("llvm.aarch64.neon.frintn.v") => { - intrinsic_args!(fx, args => (v); intrinsic); - - simd_for_each_lane(fx, v, ret, &|fx, _lane_ty, _res_lane_ty, lane| { - fx.bcx.ins().nearest(lane) - }); - } - _ if intrinsic.starts_with("llvm.aarch64.neon.smaxv.i") => { intrinsic_args!(fx, args => (v); intrinsic); -- cgit 1.4.1-3-g733a5 From 82ed50c2943661abb664fe494d4c5209f8e1818c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 3 Jun 2025 15:06:04 +0000 Subject: Run wfcheck in one big loop instead of per module --- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 13 +++--- compiler/rustc_hir_analysis/src/lib.rs | 4 +- compiler/rustc_middle/src/query/mod.rs | 4 +- src/librustdoc/core.rs | 4 +- .../impl-trait/in-assoc-type-unconstrained.stderr | 16 +++---- ...-alias-impl-trait-declaration-too-subtle.stderr | 26 +++++------ tests/ui/privacy/privacy3.stderr | 12 ++--- .../type-alias-impl-trait/constrain_inputs.stderr | 52 +++++++++++----------- 8 files changed, 63 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b764b714fe1..3e872607e31 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -7,7 +7,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::{AmbigArg, ItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; @@ -2402,8 +2402,8 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { } } -fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> { - let items = tcx.hir_module_items(module); +fn check_type_wf(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuaranteed> { + let items = tcx.hir_crate_items(()); let res = items .par_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)) .and(items.par_impl_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id))) @@ -2412,9 +2412,8 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error items.par_foreign_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)), ) .and(items.par_opaques(|item| tcx.ensure_ok().check_well_formed(item))); - if module == LocalModDefId::CRATE_DEF_ID { - super::entry::check_for_entry_fn(tcx); - } + super::entry::check_for_entry_fn(tcx); + res } @@ -2552,5 +2551,5 @@ struct RedundantLifetimeArgsLint<'tcx> { } pub fn provide(providers: &mut Providers) { - *providers = Providers { check_mod_type_wf, check_well_formed, ..*providers }; + *providers = Providers { check_type_wf, check_well_formed, ..*providers }; } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index a64c24f5455..f255817bffc 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -182,9 +182,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { // what we are intending to discard, to help future type-based refactoring. type R = Result<(), ErrorGuaranteed>; - tcx.par_hir_for_each_module(|module| { - let _: R = tcx.ensure_ok().check_mod_type_wf(module); - }); + let _: R = tcx.ensure_ok().check_type_wf(()); for &trait_def_id in tcx.all_local_trait_impls(()).keys() { let _: R = tcx.ensure_ok().coherent_trait(trait_def_id); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 542653efd30..d900e16b005 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1148,8 +1148,8 @@ rustc_queries! { desc { |tcx| "checking deathness of variables in {}", describe_as_module(key, tcx) } } - query check_mod_type_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> { - desc { |tcx| "checking that types are well-formed in {}", describe_as_module(key, tcx) } + query check_type_wf(key: ()) -> Result<(), ErrorGuaranteed> { + desc { "checking that types are well-formed" } return_result_from_ensure_ok } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 9d1c9ff00b1..204f8decffc 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -345,9 +345,7 @@ pub(crate) fn run_global_ctxt( // (see `override_queries` in the `config`) // NOTE: These are copy/pasted from typeck/lib.rs and should be kept in sync with those changes. - let _ = tcx.sess.time("wf_checking", || { - tcx.try_par_hir_for_each_module(|module| tcx.ensure_ok().check_mod_type_wf(module)) - }); + let _ = tcx.sess.time("wf_checking", || tcx.ensure_ok().check_type_wf(())); tcx.dcx().abort_if_errors(); diff --git a/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr index c9e657b87d5..2f417d57752 100644 --- a/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr +++ b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr @@ -12,14 +12,6 @@ note: required by a bound in `compare_ty::Trait::Ty` LL | type Ty: IntoIterator; | ^^^^^^^^^ required by this bound in `Trait::Ty` -error: unconstrained opaque type - --> $DIR/in-assoc-type-unconstrained.rs:8:26 - | -LL | type Ty = Option; - | ^^^^^^^^^^ - | - = note: `Ty` must be used in combination with a concrete type within the same impl - error[E0053]: method `method` has an incompatible type for trait --> $DIR/in-assoc-type-unconstrained.rs:22:24 | @@ -42,6 +34,14 @@ LL - fn method() -> () {} LL + fn method() -> <() as compare_method::Trait>::Ty {} | +error: unconstrained opaque type + --> $DIR/in-assoc-type-unconstrained.rs:8:26 + | +LL | type Ty = Option; + | ^^^^^^^^^^ + | + = note: `Ty` must be used in combination with a concrete type within the same impl + error: unconstrained opaque type --> $DIR/in-assoc-type-unconstrained.rs:20:19 | diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr index 7f642fa1bed..ce6f68f535b 100644 --- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr @@ -15,19 +15,6 @@ LL - fn eq(&self, _other: &(Foo, i32)) -> bool { LL + fn eq(&self, _other: &(a::Bar, i32)) -> bool { | -error: item does not constrain `a::Foo::{opaque#0}` - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:12 - | -LL | fn eq(&self, _other: &(Foo, i32)) -> bool { - | ^^ - | - = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` -note: this opaque type is supposed to be constrained - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16 - | -LL | type Foo = impl PartialEq<(Foo, i32)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0053]: method `eq` has an incompatible type for trait --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:25:30 | @@ -50,6 +37,19 @@ LL - fn eq(&self, _other: &(Bar, i32)) -> bool { LL + fn eq(&self, _other: &(b::Foo, i32)) -> bool { | +error: item does not constrain `a::Foo::{opaque#0}` + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:12 + | +LL | fn eq(&self, _other: &(Foo, i32)) -> bool { + | ^^ + | + = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` +note: this opaque type is supposed to be constrained + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16 + | +LL | type Foo = impl PartialEq<(Foo, i32)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: unconstrained opaque type --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:19:16 | diff --git a/tests/ui/privacy/privacy3.stderr b/tests/ui/privacy/privacy3.stderr index 06a287d35ea..4530dfe447b 100644 --- a/tests/ui/privacy/privacy3.stderr +++ b/tests/ui/privacy/privacy3.stderr @@ -4,6 +4,12 @@ error[E0432]: unresolved import `bar::gpriv` LL | use bar::gpriv; | ^^^^^^^^^^ no `gpriv` in `bar` +error: requires `sized` lang_item + --> $DIR/privacy3.rs:13:20 + | +LL | fn gpriv() {} + | ^^ + error: requires `sized` lang_item --> $DIR/privacy3.rs:18:14 | @@ -28,12 +34,6 @@ error: requires `sized` lang_item LL | fn main() {} | ^^ -error: requires `sized` lang_item - --> $DIR/privacy3.rs:13:20 - | -LL | fn gpriv() {} - | ^^ - error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/type-alias-impl-trait/constrain_inputs.stderr b/tests/ui/type-alias-impl-trait/constrain_inputs.stderr index b016715b129..cb299a2021e 100644 --- a/tests/ui/type-alias-impl-trait/constrain_inputs.stderr +++ b/tests/ui/type-alias-impl-trait/constrain_inputs.stderr @@ -25,19 +25,6 @@ LL | type BadTraitRef = dyn Fn(Ty<'_>) -> &str; = note: lifetimes appearing in an associated or opaque type are not considered constrained = note: consider introducing a named lifetime parameter -error: item does not constrain `lifetime_params::Ty::{opaque#0}` - --> $DIR/constrain_inputs.rs:8:8 - | -LL | fn execute(ty: Ty<'_>) -> &str { todo!() } - | ^^^^^^^ - | - = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` -note: this opaque type is supposed to be constrained - --> $DIR/constrain_inputs.rs:4:19 - | -LL | type Ty<'a> = impl Sized; - | ^^^^^^^^^^ - error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types --> $DIR/constrain_inputs.rs:23:31 | @@ -47,19 +34,6 @@ LL | fn execute(ty: Ty<'_>) -> &str { ty() } = note: lifetimes appearing in an associated or opaque type are not considered constrained = note: consider introducing a named lifetime parameter -error: item does not constrain `lifetime_params_2::Ty::{opaque#0}` - --> $DIR/constrain_inputs.rs:23:8 - | -LL | fn execute(ty: Ty<'_>) -> &str { ty() } - | ^^^^^^^ - | - = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` -note: this opaque type is supposed to be constrained - --> $DIR/constrain_inputs.rs:19:19 - | -LL | type Ty<'a> = impl FnOnce() -> &'a str; - | ^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types --> $DIR/constrain_inputs.rs:34:37 | @@ -78,6 +52,32 @@ LL | type BadTraitRef = dyn Fn(Ty<&str>) -> &str; = note: lifetimes appearing in an associated or opaque type are not considered constrained = note: consider introducing a named lifetime parameter +error: item does not constrain `lifetime_params::Ty::{opaque#0}` + --> $DIR/constrain_inputs.rs:8:8 + | +LL | fn execute(ty: Ty<'_>) -> &str { todo!() } + | ^^^^^^^ + | + = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` +note: this opaque type is supposed to be constrained + --> $DIR/constrain_inputs.rs:4:19 + | +LL | type Ty<'a> = impl Sized; + | ^^^^^^^^^^ + +error: item does not constrain `lifetime_params_2::Ty::{opaque#0}` + --> $DIR/constrain_inputs.rs:23:8 + | +LL | fn execute(ty: Ty<'_>) -> &str { ty() } + | ^^^^^^^ + | + = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` +note: this opaque type is supposed to be constrained + --> $DIR/constrain_inputs.rs:19:19 + | +LL | type Ty<'a> = impl FnOnce() -> &'a str; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 8 previous errors Some errors have detailed explanations: E0581, E0582. -- cgit 1.4.1-3-g733a5 From fbc15c1e136c402c82a65c6df5fea552fe006cb0 Mon Sep 17 00:00:00 2001 From: sayantn Date: Tue, 3 Jun 2025 21:34:59 +0530 Subject: Remove uses of `stdarch_x86_avx512` --- src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs | 2 -- src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs | 2 -- src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs | 1 - src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs | 1 - tests/ui/asm/x86_64/evex512-implicit-feature.rs | 2 -- 5 files changed, 8 deletions(-) diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs index 48633c0a7fe..8936ae8e912 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs @@ -2,8 +2,6 @@ //@only-target: x86_64 i686 //@compile-flags: -C target-feature=+aes,+vaes,+avx512f -#![feature(stdarch_x86_avx512)] - use core::mem::transmute; #[cfg(target_arch = "x86")] use std::arch::x86::*; diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs index 0ec2f679d80..65d7b57d1ce 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs @@ -2,8 +2,6 @@ //@only-target: x86_64 i686 //@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq -#![feature(stdarch_x86_avx512)] - #[cfg(target_arch = "x86")] use std::arch::x86::*; #[cfg(target_arch = "x86_64")] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs index b58d68e2ef9..48958ef5810 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs @@ -6,7 +6,6 @@ // be interpreted as integers; signedness does not make sense for them, but // __mXXXi happens to be defined in terms of signed integers. #![allow(overflowing_literals)] -#![feature(stdarch_x86_avx512)] #[cfg(target_arch = "x86")] use std::arch::x86::*; diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs index c7c9eb5e395..e2a045bf81f 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs @@ -8,7 +8,6 @@ // be interpreted as integers; signedness does not make sense for them, but // __mXXXi happens to be defined in terms of signed integers. #![allow(overflowing_literals)] -#![feature(stdarch_x86_avx512)] #[cfg(target_arch = "x86")] use std::arch::x86::*; diff --git a/tests/ui/asm/x86_64/evex512-implicit-feature.rs b/tests/ui/asm/x86_64/evex512-implicit-feature.rs index ec5da7c7fa4..1f678b2387a 100644 --- a/tests/ui/asm/x86_64/evex512-implicit-feature.rs +++ b/tests/ui/asm/x86_64/evex512-implicit-feature.rs @@ -2,8 +2,6 @@ //@ only-x86_64 //@ compile-flags: --crate-type=lib -C target-cpu=skylake -#![feature(stdarch_x86_avx512)] - use std::arch::x86_64::*; #[target_feature(enable = "avx512f")] -- cgit 1.4.1-3-g733a5 From 2b2f66afc44b23d65dab2adc9a1bf77d409d5d33 Mon Sep 17 00:00:00 2001 From: León Orell Valerian Liehr Date: Tue, 3 Jun 2025 18:10:34 +0200 Subject: Triagebot: Remove `assign.users_on_vacation` --- triagebot.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 2bd0c185ad7..cff709dc042 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1174,10 +1174,6 @@ cc = ["@m-ou-se"] [assign] warn_non_default_branch.enable = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" -users_on_vacation = [ - "fmease", - "jyn514", -] [[assign.warn_non_default_branch.exceptions]] title = "[beta" -- cgit 1.4.1-3-g733a5 From 143d81362b42dcb70bcfef09f8da1427dfb3ef12 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 3 Jun 2025 19:12:51 +0300 Subject: implement new `x` flag: `--skip-std-check-if-no-download-rustc` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/check.rs | 7 +++++++ src/bootstrap/src/core/config/config.rs | 4 ++++ src/bootstrap/src/core/config/flags.rs | 3 +++ 3 files changed, 14 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 922578f309a..1647df54411 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -60,6 +60,13 @@ impl Step for Std { } fn run(self, builder: &Builder<'_>) { + if !builder.download_rustc() && builder.config.skip_std_check_if_no_download_rustc { + eprintln!( + "WARNING: `--skip-std-check-if-no-download-rustc` flag was passed and `rust.download-rustc` is not available. Skipping." + ); + return; + } + builder.require_submodule("library/stdarch", None); let target = self.target; diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 899ffde8adf..fa683a48fae 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -423,6 +423,9 @@ pub struct Config { /// Cache for determining path modifications pub path_modification_cache: Arc, PathFreshness>>>, + + /// Skip checking std if `rust.download-rustc` isn't available. + pub skip_std_check_if_no_download_rustc: bool, } #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] @@ -1507,6 +1510,7 @@ impl Config { config.enable_bolt_settings = flags.enable_bolt_settings; config.bypass_bootstrap_lock = flags.bypass_bootstrap_lock; config.is_running_on_ci = flags.ci.unwrap_or(CiEnv::is_ci()); + config.skip_std_check_if_no_download_rustc = flags.skip_std_check_if_no_download_rustc; // Infer the rest of the configuration. diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 08bd87e03a1..bb851129770 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -182,6 +182,9 @@ pub struct Flags { /// Make bootstrap to behave as it's running on the CI environment or not. #[arg(global = true, long, value_name = "bool")] pub ci: Option, + /// Skip checking std if `rust.download-rustc` isn't available. + #[arg(global = true, long)] + pub skip_std_check_if_no_download_rustc: bool, } impl Flags { -- cgit 1.4.1-3-g733a5 From f1e6afdc4cc324ea9576cef88cc392a2c88fa1a3 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 3 Jun 2025 19:13:11 +0300 Subject: bless tidy Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 2 +- src/bootstrap/src/core/config/flags.rs | 2 +- src/etc/completions/x.fish | 25 +++++++++++++++++- src/etc/completions/x.ps1 | 23 +++++++++++++++++ src/etc/completions/x.py.fish | 25 +++++++++++++++++- src/etc/completions/x.py.ps1 | 23 +++++++++++++++++ src/etc/completions/x.py.sh | 46 ++++++++++++++++----------------- src/etc/completions/x.py.zsh | 23 +++++++++++++++++ src/etc/completions/x.sh | 46 ++++++++++++++++----------------- src/etc/completions/x.zsh | 23 +++++++++++++++++ 10 files changed, 188 insertions(+), 50 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index fa683a48fae..7457dc0bfed 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -424,7 +424,7 @@ pub struct Config { /// Cache for determining path modifications pub path_modification_cache: Arc, PathFreshness>>>, - /// Skip checking std if `rust.download-rustc` isn't available. + /// Skip checking std if `rust.download-rustc` isn't available, mostly for RA pub skip_std_check_if_no_download_rustc: bool, } diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index bb851129770..72073cd69f4 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -182,7 +182,7 @@ pub struct Flags { /// Make bootstrap to behave as it's running on the CI environment or not. #[arg(global = true, long, value_name = "bool")] pub ci: Option, - /// Skip checking std if `rust.download-rustc` isn't available. + /// Skip checking std if `rust.download-rustc` isn't available, mostly for RA #[arg(global = true, long)] pub skip_std_check_if_no_download_rustc: bool, } diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index 4f22bc511de..19a1a598a5d 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -1,6 +1,6 @@ # Print an optspec for argparse to handle cmd's options that are independent of any subcommand. function __fish_x_global_optspecs - string join \n v/verbose i/incremental config= build-dir= build= host= target= exclude= skip= include-default-paths rustc-error-format= on-fail= dry-run dump-bootstrap-shims stage= keep-stage= keep-stage-std= src= j/jobs= warnings= error-format= json-output color= bypass-bootstrap-lock rust-profile-generate= rust-profile-use= llvm-profile-use= llvm-profile-generate enable-bolt-settings skip-stage0-validation reproducible-artifact= set= ci= h/help + string join \n v/verbose i/incremental config= build-dir= build= host= target= exclude= skip= include-default-paths rustc-error-format= on-fail= dry-run dump-bootstrap-shims stage= keep-stage= keep-stage-std= src= j/jobs= warnings= error-format= json-output color= bypass-bootstrap-lock rust-profile-generate= rust-profile-use= llvm-profile-use= llvm-profile-generate enable-bolt-settings skip-stage0-validation reproducible-artifact= set= ci= skip-std-check-if-no-download-rustc h/help end function __fish_x_needs_command @@ -57,6 +57,7 @@ complete -c x -n "__fish_x_needs_command" -l bypass-bootstrap-lock -d 'Bootstrap complete -c x -n "__fish_x_needs_command" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_needs_command" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_needs_command" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_needs_command" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_needs_command" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_needs_command" -a "build" -d 'Compile either the compiler or libraries' complete -c x -n "__fish_x_needs_command" -a "check" -d 'Compile either the compiler or libraries, using cargo check' @@ -108,6 +109,7 @@ complete -c x -n "__fish_x_using_subcommand build" -l bypass-bootstrap-lock -d ' complete -c x -n "__fish_x_using_subcommand build" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand build" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand build" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand build" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand build" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand check" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand check" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -143,6 +145,7 @@ complete -c x -n "__fish_x_using_subcommand check" -l bypass-bootstrap-lock -d ' complete -c x -n "__fish_x_using_subcommand check" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand check" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand check" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand check" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand check" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand clippy" -s A -d 'clippy lints to allow' -r complete -c x -n "__fish_x_using_subcommand clippy" -s D -d 'clippy lints to deny' -r @@ -184,6 +187,7 @@ complete -c x -n "__fish_x_using_subcommand clippy" -l bypass-bootstrap-lock -d complete -c x -n "__fish_x_using_subcommand clippy" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand clippy" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand clippy" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand clippy" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand clippy" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand fix" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand fix" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -218,6 +222,7 @@ complete -c x -n "__fish_x_using_subcommand fix" -l bypass-bootstrap-lock -d 'Bo complete -c x -n "__fish_x_using_subcommand fix" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand fix" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand fix" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand fix" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand fix" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand fmt" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand fmt" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -254,6 +259,7 @@ complete -c x -n "__fish_x_using_subcommand fmt" -l bypass-bootstrap-lock -d 'Bo complete -c x -n "__fish_x_using_subcommand fmt" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand fmt" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand fmt" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand fmt" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand fmt" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand doc" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand doc" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -290,6 +296,7 @@ complete -c x -n "__fish_x_using_subcommand doc" -l bypass-bootstrap-lock -d 'Bo complete -c x -n "__fish_x_using_subcommand doc" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand doc" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand doc" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand doc" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand doc" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r complete -c x -n "__fish_x_using_subcommand test" -l compiletest-rustc-args -d 'extra options to pass the compiler when running compiletest tests' -r @@ -338,6 +345,7 @@ complete -c x -n "__fish_x_using_subcommand test" -l bypass-bootstrap-lock -d 'B complete -c x -n "__fish_x_using_subcommand test" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand test" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand test" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand test" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand test" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand miri" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r complete -c x -n "__fish_x_using_subcommand miri" -l config -d 'TOML configuration file for build' -r -F @@ -376,6 +384,7 @@ complete -c x -n "__fish_x_using_subcommand miri" -l bypass-bootstrap-lock -d 'B complete -c x -n "__fish_x_using_subcommand miri" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand miri" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand miri" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand miri" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand miri" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand bench" -l test-args -r complete -c x -n "__fish_x_using_subcommand bench" -l config -d 'TOML configuration file for build' -r -F @@ -411,6 +420,7 @@ complete -c x -n "__fish_x_using_subcommand bench" -l bypass-bootstrap-lock -d ' complete -c x -n "__fish_x_using_subcommand bench" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand bench" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand bench" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand bench" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand bench" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand clean" -l stage -d 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used' -r complete -c x -n "__fish_x_using_subcommand clean" -l config -d 'TOML configuration file for build' -r -F @@ -446,6 +456,7 @@ complete -c x -n "__fish_x_using_subcommand clean" -l bypass-bootstrap-lock -d ' complete -c x -n "__fish_x_using_subcommand clean" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand clean" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand clean" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand clean" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand clean" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand dist" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand dist" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -480,6 +491,7 @@ complete -c x -n "__fish_x_using_subcommand dist" -l bypass-bootstrap-lock -d 'B complete -c x -n "__fish_x_using_subcommand dist" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand dist" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand dist" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand dist" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand dist" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand install" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand install" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -514,6 +526,7 @@ complete -c x -n "__fish_x_using_subcommand install" -l bypass-bootstrap-lock -d complete -c x -n "__fish_x_using_subcommand install" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand install" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand install" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand install" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand run" -l args -d 'arguments for the tool' -r complete -c x -n "__fish_x_using_subcommand run" -l config -d 'TOML configuration file for build' -r -F @@ -549,6 +562,7 @@ complete -c x -n "__fish_x_using_subcommand run" -l bypass-bootstrap-lock -d 'Bo complete -c x -n "__fish_x_using_subcommand run" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand run" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand run" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand run" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand run" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand setup" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand setup" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -583,6 +597,7 @@ complete -c x -n "__fish_x_using_subcommand setup" -l bypass-bootstrap-lock -d ' complete -c x -n "__fish_x_using_subcommand setup" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand setup" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand setup" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand setup" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -618,6 +633,7 @@ complete -c x -n "__fish_x_using_subcommand suggest" -l bypass-bootstrap-lock -d complete -c x -n "__fish_x_using_subcommand suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand suggest" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand suggest" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand suggest" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand suggest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F complete -c x -n "__fish_x_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F @@ -654,6 +670,7 @@ complete -c x -n "__fish_x_using_subcommand vendor" -l bypass-bootstrap-lock -d complete -c x -n "__fish_x_using_subcommand vendor" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand vendor" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand vendor" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand vendor" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand vendor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -688,6 +705,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -a "eprintln" -d 'Run `profile_local eprintln`. This executes the compiler on the given benchmarks and stores its stderr output' complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -a "samply" -d 'Run `profile_local samply` This executes the compiler on the given benchmarks and profiles it with `samply`. You need to install `samply`, e.g. using `cargo install samply`' @@ -730,6 +748,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l include -d 'Select the benchmarks that you want to run (separated by commas). If unspecified, all benchmarks will be executed' -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r @@ -767,6 +786,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l include -d 'Select the benchmarks that you want to run (separated by commas). If unspecified, all benchmarks will be executed' -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r @@ -804,6 +824,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l include -d 'Select the benchmarks that you want to run (separated by commas). If unspecified, all benchmarks will be executed' -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r @@ -841,6 +862,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -875,4 +897,5 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -s h -l help -d 'Print help (see more with \'--help\')' diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index 638b87edfb2..805ab7fa61a 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -57,6 +57,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('build', 'build', [CompletionResultType]::ParameterValue, 'Compile either the compiler or libraries') @@ -115,6 +116,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -157,6 +159,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -205,6 +208,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -246,6 +250,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -289,6 +294,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -332,6 +338,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -387,6 +394,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -432,6 +440,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -474,6 +483,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -516,6 +526,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -557,6 +568,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -598,6 +610,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -640,6 +653,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -681,6 +695,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -723,6 +738,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -766,6 +782,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -807,6 +824,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('eprintln', 'eprintln', [CompletionResultType]::ParameterValue, 'Run `profile_local eprintln`. This executes the compiler on the given benchmarks and stores its stderr output') @@ -856,6 +874,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -900,6 +919,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -944,6 +964,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -988,6 +1009,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -1029,6 +1051,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 75771ec9a81..1da37b4a5b4 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -1,6 +1,6 @@ # Print an optspec for argparse to handle cmd's options that are independent of any subcommand. function __fish_x.py_global_optspecs - string join \n v/verbose i/incremental config= build-dir= build= host= target= exclude= skip= include-default-paths rustc-error-format= on-fail= dry-run dump-bootstrap-shims stage= keep-stage= keep-stage-std= src= j/jobs= warnings= error-format= json-output color= bypass-bootstrap-lock rust-profile-generate= rust-profile-use= llvm-profile-use= llvm-profile-generate enable-bolt-settings skip-stage0-validation reproducible-artifact= set= ci= h/help + string join \n v/verbose i/incremental config= build-dir= build= host= target= exclude= skip= include-default-paths rustc-error-format= on-fail= dry-run dump-bootstrap-shims stage= keep-stage= keep-stage-std= src= j/jobs= warnings= error-format= json-output color= bypass-bootstrap-lock rust-profile-generate= rust-profile-use= llvm-profile-use= llvm-profile-generate enable-bolt-settings skip-stage0-validation reproducible-artifact= set= ci= skip-std-check-if-no-download-rustc h/help end function __fish_x.py_needs_command @@ -57,6 +57,7 @@ complete -c x.py -n "__fish_x.py_needs_command" -l bypass-bootstrap-lock -d 'Boo complete -c x.py -n "__fish_x.py_needs_command" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_needs_command" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_needs_command" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_needs_command" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_needs_command" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_needs_command" -a "build" -d 'Compile either the compiler or libraries' complete -c x.py -n "__fish_x.py_needs_command" -a "check" -d 'Compile either the compiler or libraries, using cargo check' @@ -108,6 +109,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand build" -l bypass-bootstrap-loc complete -c x.py -n "__fish_x.py_using_subcommand build" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand build" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand build" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand build" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand build" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand check" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand check" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -143,6 +145,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand check" -l bypass-bootstrap-loc complete -c x.py -n "__fish_x.py_using_subcommand check" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand check" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand check" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand check" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand check" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand clippy" -s A -d 'clippy lints to allow' -r complete -c x.py -n "__fish_x.py_using_subcommand clippy" -s D -d 'clippy lints to deny' -r @@ -184,6 +187,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l bypass-bootstrap-lo complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand clippy" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand fix" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand fix" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -218,6 +222,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand fix" -l bypass-bootstrap-lock complete -c x.py -n "__fish_x.py_using_subcommand fix" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand fix" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand fix" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand fix" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand fix" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -254,6 +259,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l bypass-bootstrap-lock complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand fmt" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand doc" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand doc" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -290,6 +296,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand doc" -l bypass-bootstrap-lock complete -c x.py -n "__fish_x.py_using_subcommand doc" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand doc" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand doc" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand doc" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand doc" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r complete -c x.py -n "__fish_x.py_using_subcommand test" -l compiletest-rustc-args -d 'extra options to pass the compiler when running compiletest tests' -r @@ -338,6 +345,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -l bypass-bootstrap-lock complete -c x.py -n "__fish_x.py_using_subcommand test" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand test" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand test" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand test" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand test" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand miri" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r complete -c x.py -n "__fish_x.py_using_subcommand miri" -l config -d 'TOML configuration file for build' -r -F @@ -376,6 +384,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand miri" -l bypass-bootstrap-lock complete -c x.py -n "__fish_x.py_using_subcommand miri" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand miri" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand miri" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand miri" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand miri" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand bench" -l test-args -r complete -c x.py -n "__fish_x.py_using_subcommand bench" -l config -d 'TOML configuration file for build' -r -F @@ -411,6 +420,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand bench" -l bypass-bootstrap-loc complete -c x.py -n "__fish_x.py_using_subcommand bench" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand bench" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand bench" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand bench" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand bench" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand clean" -l stage -d 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used' -r complete -c x.py -n "__fish_x.py_using_subcommand clean" -l config -d 'TOML configuration file for build' -r -F @@ -446,6 +456,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand clean" -l bypass-bootstrap-loc complete -c x.py -n "__fish_x.py_using_subcommand clean" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand clean" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand clean" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand clean" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand clean" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand dist" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand dist" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -480,6 +491,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand dist" -l bypass-bootstrap-lock complete -c x.py -n "__fish_x.py_using_subcommand dist" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand dist" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand dist" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand dist" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand dist" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand install" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand install" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -514,6 +526,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand install" -l bypass-bootstrap-l complete -c x.py -n "__fish_x.py_using_subcommand install" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand install" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand install" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand install" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand run" -l args -d 'arguments for the tool' -r complete -c x.py -n "__fish_x.py_using_subcommand run" -l config -d 'TOML configuration file for build' -r -F @@ -549,6 +562,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand run" -l bypass-bootstrap-lock complete -c x.py -n "__fish_x.py_using_subcommand run" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand run" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand run" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand run" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand run" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand setup" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand setup" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -583,6 +597,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand setup" -l bypass-bootstrap-loc complete -c x.py -n "__fish_x.py_using_subcommand setup" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand setup" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -618,6 +633,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l bypass-bootstrap-l complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F @@ -654,6 +670,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l bypass-bootstrap-lo complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand vendor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -688,6 +705,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subc complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -a "eprintln" -d 'Run `profile_local eprintln`. This executes the compiler on the given benchmarks and stores its stderr output' complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -a "samply" -d 'Run `profile_local samply` This executes the compiler on the given benchmarks and profiles it with `samply`. You need to install `samply`, e.g. using `cargo install samply`' @@ -730,6 +748,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l include -d 'Select the benchmarks that you want to run (separated by commas). If unspecified, all benchmarks will be executed' -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r @@ -767,6 +786,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l include -d 'Select the benchmarks that you want to run (separated by commas). If unspecified, all benchmarks will be executed' -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r @@ -804,6 +824,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l include -d 'Select the benchmarks that you want to run (separated by commas). If unspecified, all benchmarks will be executed' -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r @@ -841,6 +862,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -875,4 +897,5 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -s h -l help -d 'Print help (see more with \'--help\')' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index 0a716619106..8444716ae86 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -57,6 +57,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('build', 'build', [CompletionResultType]::ParameterValue, 'Compile either the compiler or libraries') @@ -115,6 +116,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -157,6 +159,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -205,6 +208,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -246,6 +250,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -289,6 +294,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -332,6 +338,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -387,6 +394,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -432,6 +440,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -474,6 +483,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -516,6 +526,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -557,6 +568,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -598,6 +610,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -640,6 +653,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -681,6 +695,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -723,6 +738,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -766,6 +782,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -807,6 +824,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('eprintln', 'eprintln', [CompletionResultType]::ParameterValue, 'Run `profile_local eprintln`. This executes the compiler on the given benchmarks and stores its stderr output') @@ -856,6 +874,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -900,6 +919,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -944,6 +964,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -988,6 +1009,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -1029,6 +1051,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 79b239c672d..568bf2fcc6d 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -85,7 +85,7 @@ _x.py() { case "${cmd}" in x.py) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -278,7 +278,7 @@ _x.py() { return 0 ;; x.py__bench) - opts="-v -i -j -h --test-args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --test-args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -475,7 +475,7 @@ _x.py() { return 0 ;; x.py__build) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -668,7 +668,7 @@ _x.py() { return 0 ;; x.py__check) - opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -861,7 +861,7 @@ _x.py() { return 0 ;; x.py__clean) - opts="-v -i -j -h --all --stage --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --all --stage --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1051,7 +1051,7 @@ _x.py() { return 0 ;; x.py__clippy) - opts="-A -D -W -F -v -i -j -h --fix --allow-dirty --allow-staged --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-A -D -W -F -v -i -j -h --fix --allow-dirty --allow-staged --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1260,7 +1260,7 @@ _x.py() { return 0 ;; x.py__dist) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1453,7 +1453,7 @@ _x.py() { return 0 ;; x.py__doc) - opts="-v -i -j -h --open --json --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --open --json --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1646,7 +1646,7 @@ _x.py() { return 0 ;; x.py__fix) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1839,7 +1839,7 @@ _x.py() { return 0 ;; x.py__fmt) - opts="-v -i -j -h --check --all --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --check --all --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2032,7 +2032,7 @@ _x.py() { return 0 ;; x.py__install) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2225,7 +2225,7 @@ _x.py() { return 0 ;; x.py__miri) - opts="-v -i -j -h --no-fail-fast --test-args --no-doc --doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --no-doc --doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2422,7 +2422,7 @@ _x.py() { return 0 ;; x.py__perf) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]... eprintln samply cachegrind benchmark compare" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... eprintln samply cachegrind benchmark compare" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2615,7 +2615,7 @@ _x.py() { return 0 ;; x.py__perf__benchmark) - opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2820,7 +2820,7 @@ _x.py() { return 0 ;; x.py__perf__cachegrind) - opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3025,7 +3025,7 @@ _x.py() { return 0 ;; x.py__perf__compare) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3218,7 +3218,7 @@ _x.py() { return 0 ;; x.py__perf__eprintln) - opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3423,7 +3423,7 @@ _x.py() { return 0 ;; x.py__perf__samply) - opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3628,7 +3628,7 @@ _x.py() { return 0 ;; x.py__run) - opts="-v -i -j -h --args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3825,7 +3825,7 @@ _x.py() { return 0 ;; x.py__setup) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [|hook|editor|link] [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [|hook|editor|link] [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4018,7 +4018,7 @@ _x.py() { return 0 ;; x.py__suggest) - opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4211,7 +4211,7 @@ _x.py() { return 0 ;; x.py__test) - opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4428,7 +4428,7 @@ _x.py() { return 0 ;; x.py__vendor) - opts="-v -i -j -h --sync --versioned-dirs --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --sync --versioned-dirs --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index fccea8484d7..c5385911538 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -51,6 +51,7 @@ _x.py() { '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::paths -- paths for the subcommand:_files' \ @@ -102,6 +103,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -146,6 +148,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -196,6 +199,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -239,6 +243,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -284,6 +289,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -329,6 +335,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -386,6 +393,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -433,6 +441,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -477,6 +486,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -521,6 +531,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -564,6 +575,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -607,6 +619,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -651,6 +664,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -694,6 +708,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::profile -- Either the profile for `bootstrap.toml` or another setup action. May be omitted to set up interactively:_files' \ @@ -739,6 +754,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -784,6 +800,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -827,6 +844,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::paths -- paths for the subcommand:_files' \ @@ -882,6 +900,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -928,6 +947,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -974,6 +994,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -1020,6 +1041,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':benchmark-id -- Identifier to associate benchmark results with:_default' \ @@ -1064,6 +1086,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':base -- The name of the base artifact to be compared:_default' \ diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh index 2dd322bcfc1..d48c29e6298 100644 --- a/src/etc/completions/x.sh +++ b/src/etc/completions/x.sh @@ -85,7 +85,7 @@ _x() { case "${cmd}" in x) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -278,7 +278,7 @@ _x() { return 0 ;; x__bench) - opts="-v -i -j -h --test-args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --test-args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -475,7 +475,7 @@ _x() { return 0 ;; x__build) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -668,7 +668,7 @@ _x() { return 0 ;; x__check) - opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -861,7 +861,7 @@ _x() { return 0 ;; x__clean) - opts="-v -i -j -h --all --stage --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --all --stage --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1051,7 +1051,7 @@ _x() { return 0 ;; x__clippy) - opts="-A -D -W -F -v -i -j -h --fix --allow-dirty --allow-staged --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-A -D -W -F -v -i -j -h --fix --allow-dirty --allow-staged --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1260,7 +1260,7 @@ _x() { return 0 ;; x__dist) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1453,7 +1453,7 @@ _x() { return 0 ;; x__doc) - opts="-v -i -j -h --open --json --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --open --json --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1646,7 +1646,7 @@ _x() { return 0 ;; x__fix) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1839,7 +1839,7 @@ _x() { return 0 ;; x__fmt) - opts="-v -i -j -h --check --all --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --check --all --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2032,7 +2032,7 @@ _x() { return 0 ;; x__install) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2225,7 +2225,7 @@ _x() { return 0 ;; x__miri) - opts="-v -i -j -h --no-fail-fast --test-args --no-doc --doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --no-doc --doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2422,7 +2422,7 @@ _x() { return 0 ;; x__perf) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]... eprintln samply cachegrind benchmark compare" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... eprintln samply cachegrind benchmark compare" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2615,7 +2615,7 @@ _x() { return 0 ;; x__perf__benchmark) - opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2820,7 +2820,7 @@ _x() { return 0 ;; x__perf__cachegrind) - opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3025,7 +3025,7 @@ _x() { return 0 ;; x__perf__compare) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3218,7 +3218,7 @@ _x() { return 0 ;; x__perf__eprintln) - opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3423,7 +3423,7 @@ _x() { return 0 ;; x__perf__samply) - opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --include --exclude --scenarios --profiles --verbose --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3628,7 +3628,7 @@ _x() { return 0 ;; x__run) - opts="-v -i -j -h --args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3825,7 +3825,7 @@ _x() { return 0 ;; x__setup) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [|hook|editor|link] [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [|hook|editor|link] [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4018,7 +4018,7 @@ _x() { return 0 ;; x__suggest) - opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4211,7 +4211,7 @@ _x() { return 0 ;; x__test) - opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4428,7 +4428,7 @@ _x() { return 0 ;; x__vendor) - opts="-v -i -j -h --sync --versioned-dirs --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --sync --versioned-dirs --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index 32b297b6cd5..e76db1ca4e0 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -51,6 +51,7 @@ _x() { '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::paths -- paths for the subcommand:_files' \ @@ -102,6 +103,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -146,6 +148,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -196,6 +199,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -239,6 +243,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -284,6 +289,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -329,6 +335,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -386,6 +393,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -433,6 +441,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -477,6 +486,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -521,6 +531,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -564,6 +575,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -607,6 +619,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -651,6 +664,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -694,6 +708,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::profile -- Either the profile for `bootstrap.toml` or another setup action. May be omitted to set up interactively:_files' \ @@ -739,6 +754,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -784,6 +800,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -827,6 +844,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::paths -- paths for the subcommand:_files' \ @@ -882,6 +900,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -928,6 +947,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -974,6 +994,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -1020,6 +1041,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':benchmark-id -- Identifier to associate benchmark results with:_default' \ @@ -1064,6 +1086,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ +'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':base -- The name of the base artifact to be compared:_default' \ -- cgit 1.4.1-3-g733a5 From 9e162fe0abcb3c84fd276afef914332320682016 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 3 Jun 2025 19:22:33 +0300 Subject: add change-entry Signed-off-by: onur-ozkan --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 459a34d14cc..e939a8362ad 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -416,4 +416,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "Stage0 library no longer matches the in-tree library, which means stage1 compiler now uses the beta library.", }, + ChangeInfo { + change_id: 141970, + severity: ChangeSeverity::Info, + summary: "Added new bootstrap flag `--skip-std-check-if-no-download-rustc` that skips std checks when download-rustc is unavailable. Mainly intended for developers to reduce RA overhead.", + }, ]; -- cgit 1.4.1-3-g733a5 From c04e2490ef147b052375abedea95a9ec9b6a45a6 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 6 Mar 2025 13:58:25 -0800 Subject: compiler: add AbiMap - Add AbiMapping for encoding the nuance of deprecated ABIs --- compiler/rustc_target/src/callconv/mod.rs | 1 + compiler/rustc_target/src/spec/abi_map.rs | 187 ++++++++++++++++++++++++++++++ compiler/rustc_target/src/spec/json.rs | 1 - compiler/rustc_target/src/spec/mod.rs | 2 + 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_target/src/spec/abi_map.rs diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 907614520a2..5e510ef38be 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -8,6 +8,7 @@ use rustc_abi::{ }; use rustc_macros::HashStable_Generic; +pub use crate::spec::AbiMap; use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, RustcAbi, WasmCAbi}; mod aarch64; diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs new file mode 100644 index 00000000000..d9101f79f04 --- /dev/null +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -0,0 +1,187 @@ +use rustc_abi::{ArmCall, CanonAbi, ExternAbi, InterruptKind, X86Call}; + +use crate::spec::Target; + +/// Mapping for ExternAbi to CanonAbi according to a Target +/// +/// A maybe-transitional structure circa 2025 for hosting future experiments in +/// encapsulating arch-specific ABI lowering details to make them more testable. +#[derive(Clone, Debug)] +pub struct AbiMap { + arch: Arch, + os: OsKind, +} + +#[derive(Copy, Clone, Debug)] +pub enum AbiMapping { + /// this ABI is exactly mapped for this platform + Direct(CanonAbi), + /// we don't yet warn on this, but we will + Deprecated(CanonAbi), + Invalid, +} + +impl AbiMapping { + pub fn into_option(self) -> Option { + match self { + Self::Direct(abi) | Self::Deprecated(abi) => Some(abi), + Self::Invalid => None, + } + } + + pub fn unwrap(self) -> CanonAbi { + self.into_option().unwrap() + } + + pub fn is_mapped(self) -> bool { + self.into_option().is_some() + } +} + +impl AbiMap { + pub fn from_target(target: &Target) -> Self { + // the purpose of this little exercise is to force listing what affects these mappings + let arch = match &*target.arch { + "aarch64" => Arch::Aarch64, + "amdgpu" => Arch::Amdgpu, + "arm" if target.llvm_target.starts_with("thumbv8m") => Arch::Arm(ArmVer::ThumbV8M), + "arm" => Arch::Arm(ArmVer::Other), + "avr" => Arch::Avr, + "msp430" => Arch::Msp430, + "nvptx64" => Arch::Nvptx, + "riscv32" | "riscv64" => Arch::Riscv, + "x86" => Arch::X86, + "x86_64" => Arch::X86_64, + _ => Arch::Other, + }; + let os = if target.is_like_windows { OsKind::Windows } else { OsKind::Other }; + AbiMap { arch, os } + } + + pub fn canonize_abi(&self, extern_abi: ExternAbi, has_c_varargs: bool) -> AbiMapping { + let AbiMap { os, arch } = *self; + + let canon_abi = match (extern_abi, arch) { + // infallible lowerings + (ExternAbi::C { .. }, _) => CanonAbi::C, + (ExternAbi::Rust | ExternAbi::RustCall, _) => CanonAbi::Rust, + (ExternAbi::Unadjusted, _) => CanonAbi::C, + + (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust, + (ExternAbi::RustCold, _) => CanonAbi::RustCold, + + (ExternAbi::System { .. }, Arch::X86) if os == OsKind::Windows && !has_c_varargs => { + CanonAbi::X86(X86Call::Stdcall) + } + (ExternAbi::System { .. }, _) => CanonAbi::C, + + // fallible lowerings + (ExternAbi::EfiApi, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs), + (ExternAbi::EfiApi, Arch::X86_64) => CanonAbi::X86(X86Call::Win64), + (ExternAbi::EfiApi, Arch::Aarch64 | Arch::Riscv | Arch::X86) => CanonAbi::C, + (ExternAbi::EfiApi, _) => return AbiMapping::Invalid, + + (ExternAbi::Aapcs { .. }, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs), + (ExternAbi::Aapcs { .. }, _) => return AbiMapping::Invalid, + + (ExternAbi::CCmseNonSecureCall, Arch::Arm(ArmVer::ThumbV8M)) => { + CanonAbi::Arm(ArmCall::CCmseNonSecureCall) + } + (ExternAbi::CCmseNonSecureEntry, Arch::Arm(ArmVer::ThumbV8M)) => { + CanonAbi::Arm(ArmCall::CCmseNonSecureEntry) + } + (ExternAbi::CCmseNonSecureCall | ExternAbi::CCmseNonSecureEntry, ..) => { + return AbiMapping::Invalid; + } + + (ExternAbi::Cdecl { .. }, Arch::X86) => CanonAbi::C, + (ExternAbi::Cdecl { .. }, _) => return AbiMapping::Deprecated(CanonAbi::C), + + (ExternAbi::Fastcall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Fastcall), + (ExternAbi::Fastcall { .. }, _) if os == OsKind::Windows => { + return AbiMapping::Deprecated(CanonAbi::C); + } + (ExternAbi::Fastcall { .. }, _) => return AbiMapping::Invalid, + + (ExternAbi::Stdcall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Stdcall), + (ExternAbi::Stdcall { .. }, _) if os == OsKind::Windows => { + return AbiMapping::Deprecated(CanonAbi::C); + } + (ExternAbi::Stdcall { .. }, _) => return AbiMapping::Invalid, + + (ExternAbi::Thiscall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Thiscall), + (ExternAbi::Thiscall { .. }, _) => return AbiMapping::Invalid, + + (ExternAbi::Vectorcall { .. }, Arch::X86 | Arch::X86_64) => { + CanonAbi::X86(X86Call::Vectorcall) + } + (ExternAbi::Vectorcall { .. }, _) if os == OsKind::Windows => { + return AbiMapping::Deprecated(CanonAbi::C); + } + (ExternAbi::Vectorcall { .. }, _) => return AbiMapping::Invalid, + + (ExternAbi::SysV64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::SysV64), + (ExternAbi::Win64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::Win64), + (ExternAbi::SysV64 { .. } | ExternAbi::Win64 { .. }, _) => return AbiMapping::Invalid, + + (ExternAbi::PtxKernel, Arch::Nvptx) => CanonAbi::GpuKernel, + (ExternAbi::GpuKernel, Arch::Amdgpu | Arch::Nvptx) => CanonAbi::GpuKernel, + (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid, + + (ExternAbi::AvrInterrupt, Arch::Avr) => CanonAbi::Interrupt(InterruptKind::Avr), + (ExternAbi::AvrNonBlockingInterrupt, Arch::Avr) => { + CanonAbi::Interrupt(InterruptKind::AvrNonBlocking) + } + (ExternAbi::Msp430Interrupt, Arch::Msp430) => { + CanonAbi::Interrupt(InterruptKind::Msp430) + } + (ExternAbi::RiscvInterruptM, Arch::Riscv) => { + CanonAbi::Interrupt(InterruptKind::RiscvMachine) + } + (ExternAbi::RiscvInterruptS, Arch::Riscv) => { + CanonAbi::Interrupt(InterruptKind::RiscvSupervisor) + } + (ExternAbi::X86Interrupt, Arch::X86 | Arch::X86_64) => { + CanonAbi::Interrupt(InterruptKind::X86) + } + ( + ExternAbi::AvrInterrupt + | ExternAbi::AvrNonBlockingInterrupt + | ExternAbi::Msp430Interrupt + | ExternAbi::RiscvInterruptM + | ExternAbi::RiscvInterruptS + | ExternAbi::X86Interrupt, + _, + ) => return AbiMapping::Invalid, + }; + + AbiMapping::Direct(canon_abi) + } +} + +#[derive(Debug, PartialEq, Copy, Clone)] +enum Arch { + Aarch64, + Amdgpu, + Arm(ArmVer), + Avr, + Msp430, + Nvptx, + Riscv, + X86, + X86_64, + /// Architectures which don't need other considerations for ABI lowering + Other, +} + +#[derive(Debug, PartialEq, Copy, Clone)] +enum OsKind { + Windows, + Other, +} + +#[derive(Debug, PartialEq, Copy, Clone)] +enum ArmVer { + ThumbV8M, + Other, +} diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index be71da76b4a..82d1eea21cd 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -546,7 +546,6 @@ impl Target { incorrect_type.push("frame-pointer".into()) } } - key!(c_int_width = "target-c-int-width"); key!(c_enum_min_bits, Option); // if None, matches c_int_width key!(os); diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 303be54a6d7..e45787a3a49 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -59,9 +59,11 @@ use crate::spec::crt_objects::CrtObjects; pub mod crt_objects; +mod abi_map; mod base; mod json; +pub use abi_map::AbiMap; pub use base::apple; pub use base::avr::ef_avr_arch; -- cgit 1.4.1-3-g733a5 From 2d637f70a8e8c87d0844e2cc35d2cd48be39b2d6 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Wed, 21 May 2025 21:14:40 +0200 Subject: compiler: use CanonAbi for entry_abi makes entry_abi a lowering of the ABI string, so now it can be ```json "entry_abi": "C", "entry_abi": "win64", "entry_abi": "aapcs", ``` --- compiler/rustc_abi/src/canon_abi.rs | 2 +- compiler/rustc_target/src/spec/json.rs | 31 +++++++++++++--------- compiler/rustc_target/src/spec/mod.rs | 11 ++++---- .../src/spec/targets/x86_64_unknown_uefi.rs | 5 ++-- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs index 439603df0fa..2cf7648a859 100644 --- a/compiler/rustc_abi/src/canon_abi.rs +++ b/compiler/rustc_abi/src/canon_abi.rs @@ -3,7 +3,7 @@ use std::fmt; #[cfg(feature = "nightly")] use rustc_macros::HashStable_Generic; -use crate::{AbiFromStrErr, ExternAbi}; +use crate::ExternAbi; /// Calling convention to determine codegen /// diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index 82d1eea21cd..54b06d9f9b4 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -2,10 +2,12 @@ use std::borrow::Cow; use std::collections::BTreeMap; use std::str::FromStr; +use rustc_abi::ExternAbi; use serde_json::Value; use super::{Target, TargetKind, TargetOptions, TargetWarnings}; use crate::json::{Json, ToJson}; +use crate::spec::AbiMap; impl Target { /// Loads a target descriptor from a JSON object. @@ -515,18 +517,6 @@ impl Target { } } } ); - ($key_name:ident, Conv) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match super::Conv::from_str(s) { - Ok(c) => { - base.$key_name = c; - Some(Ok(())) - } - Err(e) => Some(Err(e)) - } - })).unwrap_or(Ok(())) - } ); } if let Some(j) = obj.remove("target-endian") { @@ -546,6 +536,7 @@ impl Target { incorrect_type.push("frame-pointer".into()) } } + key!(c_int_width = "target-c-int-width"); key!(c_enum_min_bits, Option); // if None, matches c_int_width key!(os); @@ -659,9 +650,23 @@ impl Target { key!(supports_stack_protector, bool); key!(small_data_threshold_support, SmallDataThresholdSupport)?; key!(entry_name); - key!(entry_abi, Conv)?; key!(supports_xray, bool); + // we're going to run `update_from_cli`, but that won't change the target's AbiMap + // FIXME: better factor the Target definition so we enforce this on a type level + let abi_map = AbiMap::from_target(&base); + + if let Some(abi_str) = obj.remove("entry-abi") { + if let Json::String(abi_str) = abi_str { + match abi_str.parse::() { + Ok(abi) => base.options.entry_abi = abi_map.canonize_abi(abi, false).unwrap(), + Err(_) => return Err(format!("{abi_str} is not a valid ExternAbi")), + } + } else { + incorrect_type.push("entry-abi".to_owned()) + } + } + base.update_from_cli(); base.check_consistency(TargetKind::Json)?; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index e45787a3a49..c1d908fe25e 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -43,7 +43,7 @@ use std::str::FromStr; use std::{fmt, io}; use rustc_abi::{ - Align, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors, + Align, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors, }; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_fs_util::try_canonicalize; @@ -53,7 +53,6 @@ use rustc_span::{Symbol, kw, sym}; use serde_json::Value; use tracing::debug; -use crate::callconv::Conv; use crate::json::{Json, ToJson}; use crate::spec::crt_objects::CrtObjects; @@ -2657,9 +2656,9 @@ pub struct TargetOptions { /// Default value is "main" pub entry_name: StaticCow, - /// The ABI of entry function. - /// Default value is `Conv::C`, i.e. C call convention - pub entry_abi: Conv, + /// The ABI of the entry function. + /// Default value is `CanonAbi::C` + pub entry_abi: CanonAbi, /// Whether the target supports XRay instrumentation. pub supports_xray: bool, @@ -2890,7 +2889,7 @@ impl Default for TargetOptions { generate_arange_section: true, supports_stack_protector: true, entry_name: "main".into(), - entry_abi: Conv::C, + entry_abi: CanonAbi::C, supports_xray: false, small_data_threshold_support: SmallDataThresholdSupport::DefaultForArch, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs index 07f853dacaf..0cf6a879462 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs @@ -5,7 +5,8 @@ // The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with // LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features. -use crate::callconv::Conv; +use rustc_abi::{CanonAbi, X86Call}; + use crate::spec::{RustcAbi, Target, TargetMetadata, base}; pub(crate) fn target() -> Target { @@ -13,7 +14,7 @@ pub(crate) fn target() -> Target { base.cpu = "x86-64".into(); base.plt_by_default = false; base.max_atomic_width = Some(64); - base.entry_abi = Conv::X86_64Win64; + base.entry_abi = CanonAbi::X86(X86Call::Win64); // We disable MMX and SSE for now, even though UEFI allows using them. Problem is, you have to // enable these CPU features explicitly before their first use, otherwise their instructions -- cgit 1.4.1-3-g733a5 From 72ecde27ff3f0c02a738acd45d94d5588cb446cc Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Wed, 21 May 2025 22:50:21 +0200 Subject: compiler: change Conv to CanonAbi --- .../rustc_codegen_ssa/src/back/symbol_export.rs | 20 +++++----- compiler/rustc_const_eval/messages.ftl | 2 +- .../src/mono_checks/abi_check.rs | 8 ++-- .../src/cfi/typeid/itanium_cxx_abi/mod.rs | 5 ++- compiler/rustc_smir/src/rustc_smir/convert/abi.rs | 38 ++++++++++++++++++- compiler/rustc_target/src/callconv/arm.rs | 6 +-- compiler/rustc_target/src/callconv/mod.rs | 6 +-- compiler/rustc_ty_utils/src/abi.rs | 44 ++-------------------- 8 files changed, 64 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index e26f999773d..92b9b6e132e 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -1,5 +1,6 @@ use std::collections::hash_map::Entry::*; +use rustc_abi::{CanonAbi, X86Call}; use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name}; use rustc_data_structures::unord::UnordMap; use rustc_hir::def::DefKind; @@ -14,7 +15,6 @@ use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolNam use rustc_middle::util::Providers; use rustc_session::config::{CrateType, OomStrategy}; use rustc_symbol_mangling::mangle_internal_symbol; -use rustc_target::callconv::Conv; use rustc_target::spec::{SanitizerSet, TlsModel}; use tracing::debug; @@ -652,7 +652,7 @@ pub(crate) fn symbol_name_for_instance_in_crate<'tcx>( fn calling_convention_for_symbol<'tcx>( tcx: TyCtxt<'tcx>, symbol: ExportedSymbol<'tcx>, -) -> (Conv, &'tcx [rustc_target::callconv::ArgAbi<'tcx, Ty<'tcx>>]) { +) -> (CanonAbi, &'tcx [rustc_target::callconv::ArgAbi<'tcx, Ty<'tcx>>]) { let instance = match symbol { ExportedSymbol::NonGeneric(def_id) | ExportedSymbol::Generic(def_id, _) if tcx.is_static(def_id) => @@ -683,7 +683,7 @@ fn calling_convention_for_symbol<'tcx>( }) .map(|fnabi| (fnabi.conv, &fnabi.args[..])) // FIXME(workingjubilee): why don't we know the convention here? - .unwrap_or((Conv::Rust, &[])) + .unwrap_or((CanonAbi::Rust, &[])) } /// This is the symbol name of the given instance as seen by the linker. @@ -717,14 +717,14 @@ pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>( _ => return undecorated, }; - let (conv, args) = calling_convention_for_symbol(tcx, symbol); + let (callconv, args) = calling_convention_for_symbol(tcx, symbol); // Decorate symbols with prefixes, suffixes and total number of bytes of arguments. // Reference: https://docs.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170 - let (prefix, suffix) = match conv { - Conv::X86Fastcall => ("@", "@"), - Conv::X86Stdcall => ("_", "@"), - Conv::X86VectorCall => ("", "@@"), + let (prefix, suffix) = match callconv { + CanonAbi::X86(X86Call::Fastcall) => ("@", "@"), + CanonAbi::X86(X86Call::Stdcall) => ("_", "@"), + CanonAbi::X86(X86Call::Vectorcall) => ("", "@@"), _ => { if let Some(prefix) = prefix { undecorated.insert(0, prefix); @@ -758,9 +758,9 @@ pub(crate) fn extend_exported_symbols<'tcx>( symbol: ExportedSymbol<'tcx>, instantiating_crate: CrateNum, ) { - let (conv, _) = calling_convention_for_symbol(tcx, symbol); + let (callconv, _) = calling_convention_for_symbol(tcx, symbol); - if conv != Conv::GpuKernel || tcx.sess.target.os != "amdhsa" { + if callconv != CanonAbi::GpuKernel || tcx.sess.target.os != "amdhsa" { return; } diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index f4defd2aa13..abecea13520 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -118,7 +118,7 @@ const_eval_frame_note_inner = inside {$where_ -> const_eval_frame_note_last = the failure occurred here const_eval_incompatible_calling_conventions = - calling a function with calling convention {$callee_conv} using calling convention {$caller_conv} + calling a function with calling convention "{$callee_conv}" using calling convention "{$caller_conv}" const_eval_incompatible_return_types = calling a function with return type {$callee_ty} passing return place of type {$caller_ty} diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index cfeaee07776..5478e54a606 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -1,6 +1,6 @@ //! This module ensures that if a function's ABI requires a particular target feature, //! that target feature is enabled both on the callee and all callers. -use rustc_abi::{BackendRepr, RegKind}; +use rustc_abi::{BackendRepr, CanonAbi, RegKind, X86Call}; use rustc_hir::{CRATE_HIR_ID, HirId}; use rustc_middle::mir::{self, Location, traversal}; use rustc_middle::ty::layout::LayoutCx; @@ -8,7 +8,7 @@ use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypingEnv}; use rustc_session::lint::builtin::WASM_C_ABI; use rustc_span::def_id::DefId; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; -use rustc_target::callconv::{ArgAbi, Conv, FnAbi, PassMode}; +use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; use rustc_target::spec::{HasWasmCAbiOpt, WasmCAbi}; use crate::errors; @@ -72,7 +72,7 @@ fn do_check_simd_vector_abi<'tcx>( } } // The `vectorcall` ABI is special in that it requires SSE2 no matter which types are being passed. - if abi.conv == Conv::X86VectorCall && !have_feature(sym::sse2) { + if abi.conv == CanonAbi::X86(X86Call::Vectorcall) && !have_feature(sym::sse2) { let (span, _hir_id) = loc(); tcx.dcx().emit_err(errors::AbiRequiredTargetFeature { span, @@ -128,7 +128,7 @@ fn do_check_wasm_abi<'tcx>( if !(tcx.sess.target.arch == "wasm32" && tcx.sess.target.os == "unknown" && tcx.wasm_c_abi_opt() == WasmCAbi::Legacy { with_lint: true } - && abi.conv == Conv::C) + && abi.conv == CanonAbi::C) { return; } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs index 562e288afaa..82e18ad497b 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs @@ -4,10 +4,11 @@ //! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, //! see design document in the tracking issue #89653. +use rustc_abi::CanonAbi; use rustc_data_structures::fx::FxHashMap; use rustc_middle::bug; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; -use rustc_target::callconv::{Conv, FnAbi, PassMode}; +use rustc_target::callconv::{FnAbi, PassMode}; use tracing::instrument; mod encode; @@ -45,7 +46,7 @@ pub fn typeid_for_fnabi<'tcx>( let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits()) .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); match fn_abi.conv { - Conv::C => { + CanonAbi::C => { encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C); } _ => { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 7ccc785a400..a0c70e81fa4 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -2,6 +2,7 @@ #![allow(rustc::usage_of_qualified_ty)] +use rustc_abi::{ArmCall, CanonAbi, InterruptKind, X86Call}; use rustc_middle::ty; use rustc_target::callconv::{self, Conv}; use stable_mir::abi::{ @@ -69,7 +70,7 @@ impl<'tcx> Stable<'tcx> for callconv::FnAbi<'tcx, ty::Ty<'tcx>> { fn stable(&self, tables: &mut Tables<'_>) -> Self::T { assert!(self.args.len() >= self.fixed_count as usize); - assert!(!self.c_variadic || matches!(self.conv, Conv::C)); + assert!(!self.c_variadic || matches!(self.conv, CanonAbi::C)); FnAbi { args: self.args.as_ref().stable(tables), ret: self.ret.stable(tables), @@ -121,6 +122,41 @@ impl<'tcx> Stable<'tcx> for callconv::Conv { } } +impl<'tcx> Stable<'tcx> for CanonAbi { + type T = CallConvention; + + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { + match self { + CanonAbi::C => CallConvention::C, + CanonAbi::Rust => CallConvention::Rust, + CanonAbi::RustCold => CallConvention::Cold, + CanonAbi::Arm(arm_call) => match arm_call { + ArmCall::Aapcs => CallConvention::ArmAapcs, + ArmCall::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall, + ArmCall::CCmseNonSecureEntry => CallConvention::CCmseNonSecureEntry, + }, + CanonAbi::GpuKernel => CallConvention::GpuKernel, + CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { + InterruptKind::Avr => CallConvention::AvrInterrupt, + InterruptKind::AvrNonBlocking => CallConvention::AvrNonBlockingInterrupt, + InterruptKind::Msp430 => CallConvention::Msp430Intr, + InterruptKind::RiscvMachine | InterruptKind::RiscvSupervisor => { + CallConvention::RiscvInterrupt + } + InterruptKind::X86 => CallConvention::X86Intr, + }, + CanonAbi::X86(x86_call) => match x86_call { + X86Call::Fastcall => CallConvention::X86Fastcall, + X86Call::Stdcall => CallConvention::X86Stdcall, + X86Call::SysV64 => CallConvention::X86_64SysV, + X86Call::Thiscall => CallConvention::X86ThisCall, + X86Call::Vectorcall => CallConvention::X86VectorCall, + X86Call::Win64 => CallConvention::X86_64Win64, + }, + } + } +} + impl<'tcx> Stable<'tcx> for callconv::PassMode { type T = PassMode; diff --git a/compiler/rustc_target/src/callconv/arm.rs b/compiler/rustc_target/src/callconv/arm.rs index 0a5dcc66347..70830fa07b6 100644 --- a/compiler/rustc_target/src/callconv/arm.rs +++ b/compiler/rustc_target/src/callconv/arm.rs @@ -1,6 +1,6 @@ -use rustc_abi::{HasDataLayout, TyAbiInterface}; +use rustc_abi::{ArmCall, CanonAbi, HasDataLayout, TyAbiInterface}; -use crate::callconv::{ArgAbi, Conv, FnAbi, Reg, RegKind, Uniform}; +use crate::callconv::{ArgAbi, FnAbi, Reg, RegKind, Uniform}; use crate::spec::HasTargetSpec; fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option @@ -90,7 +90,7 @@ where // If this is a target with a hard-float ABI, and the function is not explicitly // `extern "aapcs"`, then we must use the VFP registers for homogeneous aggregates. let vfp = cx.target_spec().llvm_target.ends_with("hf") - && fn_abi.conv != Conv::ArmAapcs + && fn_abi.conv != CanonAbi::Arm(ArmCall::Aapcs) && !fn_abi.c_variadic; if !fn_abi.ret.is_ignore() { diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 5e510ef38be..c3ca11c2d88 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -3,8 +3,8 @@ use std::str::FromStr; use std::{fmt, iter}; use rustc_abi::{ - AddressSpace, Align, BackendRepr, ExternAbi, HasDataLayout, Primitive, Reg, RegKind, Scalar, - Size, TyAbiInterface, TyAndLayout, + AddressSpace, Align, BackendRepr, CanonAbi, ExternAbi, HasDataLayout, Primitive, Reg, RegKind, + Scalar, Size, TyAbiInterface, TyAndLayout, }; use rustc_macros::HashStable_Generic; @@ -606,7 +606,7 @@ pub struct FnAbi<'a, Ty> { /// This can be used to know whether an argument is variadic or not. pub fixed_count: u32, /// The calling convention of this function. - pub conv: Conv, + pub conv: CanonAbi, /// Indicates if an unwind may happen across a call to this function. pub can_unwind: bool, } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 2b49d7ac8b5..83d7416b03e 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt}; use rustc_session::config::OptLevel; use rustc_span::def_id::DefId; use rustc_target::callconv::{ - ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, RiscvInterruptKind, + AbiMap, ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, FnAbi, PassMode, }; use tracing::debug; @@ -240,45 +240,6 @@ fn fn_sig_for_fn_abi<'tcx>( } } -#[inline] -fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: ExternAbi, c_variadic: bool) -> Conv { - use rustc_abi::ExternAbi::*; - match tcx.sess.target.adjust_abi(abi, c_variadic) { - Rust | RustCall => Conv::Rust, - - // This is intentionally not using `Conv::Cold`, as that has to preserve - // even SIMD registers, which is generally not a good trade-off. - RustCold => Conv::PreserveMost, - - // It's the ABI's job to select this, not ours. - System { .. } => bug!("system abi should be selected elsewhere"), - EfiApi => bug!("eficall abi should be selected elsewhere"), - - Stdcall { .. } => Conv::X86Stdcall, - Fastcall { .. } => Conv::X86Fastcall, - Vectorcall { .. } => Conv::X86VectorCall, - Thiscall { .. } => Conv::X86ThisCall, - C { .. } => Conv::C, - Unadjusted => Conv::C, - Win64 { .. } => Conv::X86_64Win64, - SysV64 { .. } => Conv::X86_64SysV, - Aapcs { .. } => Conv::ArmAapcs, - CCmseNonSecureCall => Conv::CCmseNonSecureCall, - CCmseNonSecureEntry => Conv::CCmseNonSecureEntry, - PtxKernel => Conv::GpuKernel, - Msp430Interrupt => Conv::Msp430Intr, - X86Interrupt => Conv::X86Intr, - GpuKernel => Conv::GpuKernel, - AvrInterrupt => Conv::AvrInterrupt, - AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt, - RiscvInterruptM => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine }, - RiscvInterruptS => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor }, - - // These API constants ought to be more specific... - Cdecl { .. } => Conv::C, - } -} - fn fn_abi_of_fn_ptr<'tcx>( tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List>)>, @@ -529,7 +490,8 @@ fn fn_abi_new_uncached<'tcx>( }; let sig = tcx.normalize_erasing_regions(cx.typing_env, sig); - let conv = conv_from_spec_abi(cx.tcx(), sig.abi, sig.c_variadic); + let abi_map = AbiMap::from_target(&tcx.sess.target); + let conv = abi_map.canonize_abi(sig.abi, sig.c_variadic).unwrap(); let mut inputs = sig.inputs(); let extra_args = if sig.abi == ExternAbi::RustCall { -- cgit 1.4.1-3-g733a5 From e0b07a88a3cd4eb646b0792878e0b37baee1cf36 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Wed, 21 May 2025 23:05:58 +0200 Subject: cg_llvm: convert to CanonAbi --- compiler/rustc_codegen_llvm/src/abi.rs | 69 ++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 8294e29d07d..c41b3f7f55c 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -2,7 +2,10 @@ use std::borrow::Borrow; use std::cmp; use libc::c_uint; -use rustc_abi::{BackendRepr, HasDataLayout, Primitive, Reg, RegKind, Size}; +use rustc_abi::{ + ArmCall, BackendRepr, CanonAbi, HasDataLayout, InterruptKind, Primitive, Reg, RegKind, Size, + X86Call, +}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; @@ -12,7 +15,7 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_middle::{bug, ty}; use rustc_session::config; use rustc_target::callconv::{ - ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, Conv, FnAbi, PassMode, + ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode, }; use rustc_target::spec::SanitizerSet; use smallvec::SmallVec; @@ -419,11 +422,17 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { if !self.can_unwind { func_attrs.push(llvm::AttributeKind::NoUnwind.create_attr(cx.llcx)); } - if let Conv::RiscvInterrupt { kind } = self.conv { - func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", kind.as_str())); - } - if let Conv::CCmseNonSecureEntry = self.conv { - func_attrs.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry")) + match self.conv { + CanonAbi::Interrupt(InterruptKind::RiscvMachine) => { + func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", "machine")) + } + CanonAbi::Interrupt(InterruptKind::RiscvSupervisor) => { + func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", "supervisor")) + } + CanonAbi::Arm(ArmCall::CCmseNonSecureEntry) => { + func_attrs.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry")) + } + _ => (), } attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &{ func_attrs }); @@ -610,7 +619,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { llvm::SetInstructionCallConv(callsite, cconv); } - if self.conv == Conv::CCmseNonSecureCall { + if self.conv == CanonAbi::Arm(ArmCall::CCmseNonSecureCall) { // This will probably get ignored on all targets but those supporting the TrustZone-M // extension (thumbv8m targets). let cmse_nonsecure_call = llvm::CreateAttrString(bx.cx.llcx, "cmse_nonsecure_call"); @@ -646,17 +655,11 @@ impl AbiBuilderMethods for Builder<'_, '_, '_> { } impl llvm::CallConv { - pub(crate) fn from_conv(conv: Conv, arch: &str) -> Self { + pub(crate) fn from_conv(conv: CanonAbi, arch: &str) -> Self { match conv { - Conv::C - | Conv::Rust - | Conv::CCmseNonSecureCall - | Conv::CCmseNonSecureEntry - | Conv::RiscvInterrupt { .. } => llvm::CCallConv, - Conv::Cold => llvm::ColdCallConv, - Conv::PreserveMost => llvm::PreserveMost, - Conv::PreserveAll => llvm::PreserveAll, - Conv::GpuKernel => { + CanonAbi::C | CanonAbi::Rust => llvm::CCallConv, + CanonAbi::RustCold => llvm::PreserveMost, + CanonAbi::GpuKernel => { if arch == "amdgpu" { llvm::AmdgpuKernel } else if arch == "nvptx64" { @@ -665,17 +668,25 @@ impl llvm::CallConv { panic!("Architecture {arch} does not support GpuKernel calling convention"); } } - Conv::AvrInterrupt => llvm::AvrInterrupt, - Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt, - Conv::ArmAapcs => llvm::ArmAapcsCallConv, - Conv::Msp430Intr => llvm::Msp430Intr, - Conv::X86Fastcall => llvm::X86FastcallCallConv, - Conv::X86Intr => llvm::X86_Intr, - Conv::X86Stdcall => llvm::X86StdcallCallConv, - Conv::X86ThisCall => llvm::X86_ThisCall, - Conv::X86VectorCall => llvm::X86_VectorCall, - Conv::X86_64SysV => llvm::X86_64_SysV, - Conv::X86_64Win64 => llvm::X86_64_Win64, + CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { + InterruptKind::Avr => llvm::AvrInterrupt, + InterruptKind::AvrNonBlocking => llvm::AvrNonBlockingInterrupt, + InterruptKind::Msp430 => llvm::Msp430Intr, + InterruptKind::RiscvMachine | InterruptKind::RiscvSupervisor => llvm::CCallConv, + InterruptKind::X86 => llvm::X86_Intr, + }, + CanonAbi::Arm(arm_call) => match arm_call { + ArmCall::Aapcs => llvm::ArmAapcsCallConv, + ArmCall::CCmseNonSecureCall | ArmCall::CCmseNonSecureEntry => llvm::CCallConv, + }, + CanonAbi::X86(x86_call) => match x86_call { + X86Call::Fastcall => llvm::X86FastcallCallConv, + X86Call::Stdcall => llvm::X86StdcallCallConv, + X86Call::SysV64 => llvm::X86_64_SysV, + X86Call::Thiscall => llvm::X86_ThisCall, + X86Call::Vectorcall => llvm::X86_VectorCall, + X86Call::Win64 => llvm::X86_64_Win64, + }, } } } -- cgit 1.4.1-3-g733a5 From 0d8959f48d335a491ad2da2859ab341a724e95fd Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Wed, 21 May 2025 23:29:37 +0200 Subject: cg_clif: convert to CanonAbi --- compiler/rustc_codegen_cranelift/src/abi/mod.rs | 49 +++++++++++-------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 5f7bf3821d7..fe5b220117f 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -10,7 +10,7 @@ use std::mem; use cranelift_codegen::ir::{ArgumentPurpose, SigRef}; use cranelift_codegen::isa::CallConv; use cranelift_module::ModuleError; -use rustc_abi::ExternAbi; +use rustc_abi::{CanonAbi, ExternAbi, X86Call}; use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -19,7 +19,7 @@ use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::Session; use rustc_span::source_map::Spanned; -use rustc_target::callconv::{Conv, FnAbi, PassMode}; +use rustc_target::callconv::{FnAbi, PassMode}; use smallvec::SmallVec; use self::pass_mode::*; @@ -42,32 +42,27 @@ fn clif_sig_from_fn_abi<'tcx>( Signature { params, returns, call_conv } } -pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv { +pub(crate) fn conv_to_call_conv( + sess: &Session, + c: CanonAbi, + default_call_conv: CallConv, +) -> CallConv { match c { - Conv::Rust | Conv::C => default_call_conv, - Conv::Cold | Conv::PreserveMost | Conv::PreserveAll => CallConv::Cold, - Conv::X86_64SysV => CallConv::SystemV, - Conv::X86_64Win64 => CallConv::WindowsFastcall, - - // Should already get a back compat warning - Conv::X86Fastcall | Conv::X86Stdcall | Conv::X86ThisCall | Conv::X86VectorCall => { - default_call_conv - } - - Conv::X86Intr | Conv::RiscvInterrupt { .. } => { - sess.dcx().fatal(format!("interrupt call conv {c:?} not yet implemented")) + CanonAbi::Rust | CanonAbi::C => default_call_conv, + CanonAbi::RustCold => CallConv::Cold, + + CanonAbi::X86(x86_call) => match x86_call { + X86Call::SysV64 => CallConv::SystemV, + X86Call::Win64 => CallConv::WindowsFastcall, + // Should already get a back compat warning + _ => default_call_conv, + }, + + CanonAbi::Interrupt(_) | CanonAbi::Arm(_) => { + sess.dcx().fatal("call conv {c:?} is not yet implemented") } - - Conv::ArmAapcs => sess.dcx().fatal("aapcs call conv not yet implemented"), - Conv::CCmseNonSecureCall => { - sess.dcx().fatal("C-cmse-nonsecure-call call conv is not yet implemented"); - } - Conv::CCmseNonSecureEntry => { - sess.dcx().fatal("C-cmse-nonsecure-entry call conv is not yet implemented"); - } - - Conv::Msp430Intr | Conv::GpuKernel | Conv::AvrInterrupt | Conv::AvrNonBlockingInterrupt => { - unreachable!("tried to use {c:?} call conv which only exists on an unsupported target"); + CanonAbi::GpuKernel => { + unreachable!("tried to use {c:?} call conv which only exists on an unsupported target") } } } @@ -610,7 +605,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( target: CallTarget, call_args: &mut Vec, ) { - if fn_abi.conv != Conv::C { + if fn_abi.conv != CanonAbi::C { fx.tcx.dcx().span_fatal( source_info.span, format!("Variadic call for non-C abi {:?}", fn_abi.conv), -- cgit 1.4.1-3-g733a5 From 87fa1ea9d20373f8e26ea5f5f24b9b79d6f25a17 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Wed, 21 May 2025 23:30:02 +0200 Subject: cg_gcc: convert to CanonAbi --- compiler/rustc_codegen_gcc/src/abi.rs | 73 ++++++++++++++--------------------- compiler/rustc_codegen_gcc/src/int.rs | 6 +-- 2 files changed, 31 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index d882d3eecf4..ef902055007 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -1,7 +1,7 @@ #[cfg(feature = "master")] use gccjit::FnAttribute; use gccjit::{ToLValue, ToRValue, Type}; -use rustc_abi::{Reg, RegKind}; +use rustc_abi::{ArmCall, CanonAbi, InterruptKind, Reg, RegKind, X86Call}; use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeCodegenMethods}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; @@ -10,8 +10,6 @@ use rustc_middle::ty::layout::LayoutOf; #[cfg(feature = "master")] use rustc_session::config; use rustc_target::callconv::{ArgAttributes, CastTarget, FnAbi, PassMode}; -#[cfg(feature = "master")] -use rustc_target::callconv::{Conv, RiscvInterruptKind}; use crate::builder::Builder; use crate::context::CodegenCx; @@ -239,29 +237,16 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } #[cfg(feature = "master")] -pub fn conv_to_fn_attribute<'gcc>(conv: Conv, arch: &str) -> Option> { +pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &str) -> Option> { let attribute = match conv { - Conv::C | Conv::Rust => return None, - Conv::CCmseNonSecureCall => { - if arch == "arm" { - FnAttribute::ArmCmseNonsecureCall - } else { - return None; - } - } - Conv::CCmseNonSecureEntry => { - if arch == "arm" { - FnAttribute::ArmCmseNonsecureEntry - } else { - return None; - } - } - Conv::Cold => FnAttribute::Cold, - // NOTE: the preserve attributes are not yet implemented in GCC: - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110899 - Conv::PreserveMost => return None, - Conv::PreserveAll => return None, - Conv::GpuKernel => { + CanonAbi::C | CanonAbi::Rust => return None, + CanonAbi::Arm(arm_call) => match arm_call { + ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall, + ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry, + ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"), + }, + CanonAbi::RustCold => FnAttribute::Cold, + CanonAbi::GpuKernel => { if arch == "amdgpu" { FnAttribute::GcnAmdGpuHsaKernel } else if arch == "nvptx64" { @@ -271,26 +256,24 @@ pub fn conv_to_fn_attribute<'gcc>(conv: Conv, arch: &str) -> Option FnAttribute::AvrSignal, - Conv::AvrNonBlockingInterrupt => FnAttribute::AvrInterrupt, - Conv::ArmAapcs => FnAttribute::ArmPcs("aapcs"), - Conv::Msp430Intr => FnAttribute::Msp430Interrupt, - Conv::RiscvInterrupt { kind } => { - let kind = match kind { - RiscvInterruptKind::Machine => "machine", - RiscvInterruptKind::Supervisor => "supervisor", - }; - FnAttribute::RiscvInterrupt(kind) - } - Conv::X86Fastcall => FnAttribute::X86FastCall, - Conv::X86Intr => FnAttribute::X86Interrupt, - Conv::X86Stdcall => FnAttribute::X86Stdcall, - Conv::X86ThisCall => FnAttribute::X86ThisCall, - // NOTE: the vectorcall calling convention is not yet implemented in GCC: - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485 - Conv::X86VectorCall => return None, - Conv::X86_64SysV => FnAttribute::X86SysvAbi, - Conv::X86_64Win64 => FnAttribute::X86MsAbi, + CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { + InterruptKind::Avr => FnAttribute::AvrSignal, + InterruptKind::AvrNonBlocking => FnAttribute::AvrInterrupt, + InterruptKind::Msp430 => FnAttribute::Msp430Interrupt, + InterruptKind::RiscvMachine => FnAttribute::RiscvInterrupt("machine"), + InterruptKind::RiscvSupervisor => FnAttribute::RiscvInterrupt("supervisor"), + InterruptKind::X86 => FnAttribute::X86Interrupt, + }, + CanonAbi::X86(x86_call) => match x86_call { + X86Call::Fastcall => FnAttribute::X86FastCall, + X86Call::Stdcall => FnAttribute::X86Stdcall, + X86Call::Thiscall => FnAttribute::X86ThisCall, + // // NOTE: the vectorcall calling convention is not yet implemented in GCC: + // // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485 + X86Call::Vectorcall => return None, + X86Call::SysV64 => FnAttribute::X86SysvAbi, + X86Call::Win64 => FnAttribute::X86MsAbi, + }, }; Some(attribute) } diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index 9b5b0fde6e2..eb4acd8ade9 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -3,11 +3,11 @@ //! 128-bit integers on 32-bit platforms and thus require to be handled manually. use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp}; -use rustc_abi::{Endian, ExternAbi}; +use rustc_abi::{CanonAbi, Endian, ExternAbi}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, BuilderMethods, OverflowOp}; use rustc_middle::ty::{self, Ty}; -use rustc_target::callconv::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode}; +use rustc_target::callconv::{ArgAbi, ArgAttributes, FnAbi, PassMode}; use crate::builder::{Builder, ToGccComp}; use crate::common::{SignType, TypeReflection}; @@ -397,7 +397,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { ret: arg_abi, c_variadic: false, fixed_count: 3, - conv: Conv::C, + conv: CanonAbi::C, can_unwind: false, }; fn_abi.adjust_for_foreign_abi(self.cx, ExternAbi::C { unwind: false }); -- cgit 1.4.1-3-g733a5 From 9d42e35e8d8127328eb7e340ab4bf4828ffc6ce0 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Wed, 21 May 2025 23:58:34 +0200 Subject: miri: sed to CanonAbi --- src/tools/miri/src/helpers.rs | 14 +-- src/tools/miri/src/shims/aarch64.rs | 7 +- src/tools/miri/src/shims/backtrace.rs | 12 +- src/tools/miri/src/shims/foreign_items.rs | 79 ++++++------- .../miri/src/shims/unix/android/foreign_items.rs | 13 ++- src/tools/miri/src/shims/unix/android/thread.rs | 6 +- src/tools/miri/src/shims/unix/foreign_items.rs | 124 +++++++++++---------- .../miri/src/shims/unix/freebsd/foreign_items.rs | 23 ++-- .../miri/src/shims/unix/linux/foreign_items.rs | 38 ++++--- .../miri/src/shims/unix/linux_like/syscall.rs | 5 +- .../miri/src/shims/unix/macos/foreign_items.rs | 65 +++++------ .../miri/src/shims/unix/solarish/foreign_items.rs | 33 +++--- src/tools/miri/src/shims/wasi/foreign_items.rs | 7 +- src/tools/miri/src/shims/windows/foreign_items.rs | 12 +- src/tools/miri/src/shims/x86/aesni.rs | 13 ++- src/tools/miri/src/shims/x86/avx.rs | 41 +++---- src/tools/miri/src/shims/x86/avx2.rs | 43 +++---- src/tools/miri/src/shims/x86/bmi.rs | 5 +- src/tools/miri/src/shims/x86/gfni.rs | 9 +- src/tools/miri/src/shims/x86/mod.rs | 12 +- src/tools/miri/src/shims/x86/sha.rs | 9 +- src/tools/miri/src/shims/x86/sse.rs | 21 ++-- src/tools/miri/src/shims/x86/sse2.rs | 31 +++--- src/tools/miri/src/shims/x86/sse3.rs | 7 +- src/tools/miri/src/shims/x86/sse41.rs | 23 ++-- src/tools/miri/src/shims/x86/sse42.rs | 14 +-- src/tools/miri/src/shims/x86/ssse3.rs | 15 +-- 27 files changed, 354 insertions(+), 327 deletions(-) diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 6a6adc966a8..2032a5a5aa3 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -3,7 +3,7 @@ use std::time::Duration; use std::{cmp, iter}; use rand::RngCore; -use rustc_abi::{Align, ExternAbi, FieldIdx, FieldsShape, Size, Variants}; +use rustc_abi::{Align, CanonAbi, ExternAbi, FieldIdx, FieldsShape, Size, Variants}; use rustc_apfloat::Float; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_hir::Safety; @@ -18,7 +18,7 @@ use rustc_middle::ty::{self, Binder, FloatTy, FnSig, IntTy, Ty, TyCtxt, UintTy}; use rustc_session::config::CrateType; use rustc_span::{Span, Symbol}; use rustc_symbol_mangling::mangle_internal_symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use crate::*; @@ -936,11 +936,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn check_callconv<'a>( &self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - exp_abi: Conv, + exp_abi: CanonAbi, ) -> InterpResult<'a, ()> { if fn_abi.conv != exp_abi { throw_ub_format!( - "calling a function with calling convention {exp_abi} using caller calling convention {}", + r#"calling a function with calling convention "{exp_abi}" using caller calling convention "{}""#, fn_abi.conv ); } @@ -973,7 +973,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn check_abi_and_shim_symbol_clash( &mut self, abi: &FnAbi<'tcx, Ty<'tcx>>, - exp_abi: Conv, + exp_abi: CanonAbi, link_name: Symbol, ) -> InterpResult<'tcx, ()> { self.check_callconv(abi, exp_abi)?; @@ -998,7 +998,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn check_shim<'a, const N: usize>( &mut self, abi: &FnAbi<'tcx, Ty<'tcx>>, - exp_abi: Conv, + exp_abi: CanonAbi, link_name: Symbol, args: &'a [OpTy<'tcx>], ) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> { @@ -1098,7 +1098,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn check_shim_variadic<'a, const N: usize>( &mut self, abi: &FnAbi<'tcx, Ty<'tcx>>, - exp_abi: Conv, + exp_abi: CanonAbi, link_name: Symbol, args: &'a [OpTy<'tcx>], ) -> InterpResult<'tcx, (&'a [OpTy<'tcx>; N], &'a [OpTy<'tcx>])> diff --git a/src/tools/miri/src/shims/aarch64.rs b/src/tools/miri/src/shims/aarch64.rs index 7cccc9e51d8..44ad5081ad5 100644 --- a/src/tools/miri/src/shims/aarch64.rs +++ b/src/tools/miri/src/shims/aarch64.rs @@ -1,7 +1,8 @@ +use rustc_abi::CanonAbi; use rustc_middle::mir::BinOp; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use crate::*; @@ -19,7 +20,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let unprefixed_name = link_name.as_str().strip_prefix("llvm.aarch64.").unwrap(); match unprefixed_name { "isb" => { - let [arg] = this.check_shim(abi, Conv::C, link_name, args)?; + let [arg] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { // SY ("full system scope") @@ -37,7 +38,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `left` input, the second half of the output from the `right` input. // https://developer.arm.com/architectures/instruction-sets/intrinsics/vpmaxq_u8 "neon.umaxp.v16i8" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index 9f3bc06771f..ab11553df63 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -1,8 +1,8 @@ -use rustc_abi::Size; +use rustc_abi::{CanonAbi, Size}; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{BytePos, Loc, Symbol, hygiene}; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use crate::*; @@ -16,7 +16,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let [flags] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [flags] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { @@ -38,7 +38,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ptr_ty = this.machine.layouts.mut_raw_ptr.ty; let ptr_layout = this.layout_of(ptr_ty)?; - let [flags, buf] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [flags, buf] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; let buf_place = this.deref_pointer_as(buf, ptr_layout)?; @@ -118,7 +118,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let [ptr, flags] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [ptr, flags] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; @@ -190,7 +190,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let [ptr, flags, name_ptr, filename_ptr] = - this.check_shim(abi, Conv::Rust, link_name, args)?; + this.check_shim(abi, CanonAbi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index a81f459e5e1..17eb697eaf2 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -2,7 +2,7 @@ use std::collections::hash_map::Entry; use std::io::Write; use std::path::Path; -use rustc_abi::{Align, AlignFromBytesError, Size}; +use rustc_abi::{Align, AlignFromBytesError, CanonAbi, Size}; use rustc_apfloat::Float; use rustc_ast::expand::allocator::alloc_error_handler_name; use rustc_hir::def::DefKind; @@ -12,7 +12,7 @@ use rustc_middle::mir::interpret::AllocInit; use rustc_middle::ty::{Instance, Ty}; use rustc_middle::{mir, ty}; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use self::helpers::{ToHost, ToSoft}; use super::alloc::EvalContextExt as _; @@ -247,7 +247,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // When adding a new shim, you should follow the following pattern: // ``` // "shim_name" => { - // let [arg1, arg2, arg3] = this.check_shim(abi, Conv::::C , link_name, args)?; + // let [arg1, arg2, arg3] = this.check_shim(abi, CanonAbi::C , link_name, args)?; // let result = this.shim_name(arg1, arg2, arg3)?; // this.write_scalar(result, dest)?; // } @@ -285,16 +285,16 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // Miri-specific extern functions "miri_start_unwind" => { - let [payload] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [payload] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; this.handle_miri_start_unwind(payload)?; return interp_ok(EmulateItemResult::NeedsUnwind); } "miri_run_provenance_gc" => { - let [] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; this.run_provenance_gc(); } "miri_get_alloc_id" => { - let [ptr] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [ptr] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr, 0).map_err_kind(|_e| { err_machine_stop!(TerminationInfo::Abort(format!( @@ -304,7 +304,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?; } "miri_print_borrow_state" => { - let [id, show_unnamed] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [id, show_unnamed] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; let id = this.read_scalar(id)?.to_u64()?; let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?; if let Some(id) = std::num::NonZero::new(id).map(AllocId) @@ -318,7 +318,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { "miri_pointer_name" => { // This associates a name to a tag. Very useful for debugging, and also makes // tests more strict. - let [ptr, nth_parent, name] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [ptr, nth_parent, name] = + this.check_shim(abi, CanonAbi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let nth_parent = this.read_scalar(nth_parent)?.to_u8()?; let name = this.read_immediate(name)?; @@ -331,7 +332,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.give_pointer_debug_name(ptr, nth_parent, &name)?; } "miri_static_root" => { - let [ptr] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [ptr] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr, 0)?; if offset != Size::ZERO { @@ -342,7 +343,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.machine.static_roots.push(alloc_id); } "miri_host_to_target_path" => { - let [ptr, out, out_size] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [ptr, out, out_size] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let out = this.read_pointer(out)?; let out_size = this.read_scalar(out_size)?.to_target_usize(this)?; @@ -378,7 +379,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Writes some bytes to the interpreter's stdout/stderr. See the // README for details. "miri_write_to_stdout" | "miri_write_to_stderr" => { - let [msg] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [msg] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; let msg = this.read_immediate(msg)?; let msg = this.read_byte_slice(&msg)?; // Note: we're ignoring errors writing to host stdout/stderr. @@ -392,7 +393,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { "miri_promise_symbolic_alignment" => { use rustc_abi::AlignFromBytesError; - let [ptr, align] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [ptr, align] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let align = this.read_target_usize(align)?; if !align.is_power_of_two() { @@ -433,12 +434,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Aborting the process. "exit" => { - let [code] = this.check_shim(abi, Conv::C, link_name, args)?; + let [code] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false }); } "abort" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) @@ -446,7 +447,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Standard C allocation "malloc" => { - let [size] = this.check_shim(abi, Conv::C, link_name, args)?; + let [size] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let size = this.read_target_usize(size)?; if size <= this.max_size_of_val().bytes() { let res = this.malloc(size, AllocInit::Uninit)?; @@ -460,7 +461,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "calloc" => { - let [items, elem_size] = this.check_shim(abi, Conv::C, link_name, args)?; + let [items, elem_size] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let items = this.read_target_usize(items)?; let elem_size = this.read_target_usize(elem_size)?; if let Some(size) = this.compute_size_in_bytes(Size::from_bytes(elem_size), items) { @@ -475,12 +476,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "free" => { - let [ptr] = this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; this.free(ptr)?; } "realloc" => { - let [old_ptr, new_size] = this.check_shim(abi, Conv::C, link_name, args)?; + let [old_ptr, new_size] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let old_ptr = this.read_pointer(old_ptr)?; let new_size = this.read_target_usize(new_size)?; if new_size <= this.max_size_of_val().bytes() { @@ -500,7 +501,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let default = |ecx: &mut MiriInterpCx<'tcx>| { // Only call `check_shim` when `#[global_allocator]` isn't used. When that // macro is used, we act like no shim exists, so that the exported function can run. - let [size, align] = ecx.check_shim(abi, Conv::Rust, link_name, args)?; + let [size, align] = ecx.check_shim(abi, CanonAbi::Rust, link_name, args)?; let size = ecx.read_target_usize(size)?; let align = ecx.read_target_usize(align)?; @@ -533,7 +534,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { return this.emulate_allocator(|this| { // See the comment for `__rust_alloc` why `check_shim` is only called in the // default case. - let [size, align] = this.check_shim(abi, Conv::Rust, link_name, args)?; + let [size, align] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; let size = this.read_target_usize(size)?; let align = this.read_target_usize(align)?; @@ -555,7 +556,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // See the comment for `__rust_alloc` why `check_shim` is only called in the // default case. let [ptr, old_size, align] = - ecx.check_shim(abi, Conv::Rust, link_name, args)?; + ecx.check_shim(abi, CanonAbi::Rust, link_name, args)?; let ptr = ecx.read_pointer(ptr)?; let old_size = ecx.read_target_usize(old_size)?; let align = ecx.read_target_usize(align)?; @@ -586,7 +587,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // See the comment for `__rust_alloc` why `check_shim` is only called in the // default case. let [ptr, old_size, align, new_size] = - this.check_shim(abi, Conv::Rust, link_name, args)?; + this.check_shim(abi, CanonAbi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let old_size = this.read_target_usize(old_size)?; let align = this.read_target_usize(align)?; @@ -610,7 +611,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // C memory handling functions "memcmp" => { - let [left, right, n] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, n] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let left = this.read_pointer(left)?; let right = this.read_pointer(right)?; let n = Size::from_bytes(this.read_target_usize(n)?); @@ -634,7 +635,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - let [ptr, val, num] = this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr, val, num] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; let val = this.read_scalar(val)?.to_i32()?; let num = this.read_target_usize(num)?; @@ -660,7 +661,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "memchr" => { - let [ptr, val, num] = this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr, val, num] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; let val = this.read_scalar(val)?.to_i32()?; let num = this.read_target_usize(num)?; @@ -683,7 +684,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "strlen" => { - let [ptr] = this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; // This reads at least 1 byte, so we are already enforcing that this is a valid pointer. let n = this.read_c_str(ptr)?.len(); @@ -693,7 +694,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; } "wcslen" => { - let [ptr] = this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; // This reads at least 1 byte, so we are already enforcing that this is a valid pointer. let n = this.read_wchar_t_str(ptr)?.len(); @@ -703,7 +704,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; } "memcpy" => { - let [ptr_dest, ptr_src, n] = this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr_dest, ptr_src, n] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let ptr_dest = this.read_pointer(ptr_dest)?; let ptr_src = this.read_pointer(ptr_src)?; let n = this.read_target_usize(n)?; @@ -717,7 +718,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(ptr_dest, dest)?; } "strcpy" => { - let [ptr_dest, ptr_src] = this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr_dest, ptr_src] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let ptr_dest = this.read_pointer(ptr_dest)?; let ptr_src = this.read_pointer(ptr_src)?; @@ -748,7 +749,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { | "erff" | "erfcf" => { - let [f] = this.check_shim(abi, Conv::C , link_name, args)?; + let [f] = this.check_shim(abi, CanonAbi::C , link_name, args)?; let f = this.read_scalar(f)?.to_f32()?; // Using host floats (but it's fine, these operations do not have guaranteed precision). let f_host = f.to_host(); @@ -786,7 +787,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { | "atan2f" | "fdimf" => { - let [f1, f2] = this.check_shim(abi, Conv::C , link_name, args)?; + let [f1, f2] = this.check_shim(abi, CanonAbi::C , link_name, args)?; let f1 = this.read_scalar(f1)?.to_f32()?; let f2 = this.read_scalar(f2)?.to_f32()?; // underscore case for windows, here and below @@ -825,7 +826,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { | "erf" | "erfc" => { - let [f] = this.check_shim(abi, Conv::C , link_name, args)?; + let [f] = this.check_shim(abi, CanonAbi::C , link_name, args)?; let f = this.read_scalar(f)?.to_f64()?; // Using host floats (but it's fine, these operations do not have guaranteed precision). let f_host = f.to_host(); @@ -863,7 +864,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { | "atan2" | "fdim" => { - let [f1, f2] = this.check_shim(abi, Conv::C , link_name, args)?; + let [f1, f2] = this.check_shim(abi, CanonAbi::C , link_name, args)?; let f1 = this.read_scalar(f1)?.to_f64()?; let f2 = this.read_scalar(f2)?.to_f64()?; // underscore case for windows, here and below @@ -892,7 +893,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { | "ldexp" | "scalbn" => { - let [x, exp] = this.check_shim(abi, Conv::C , link_name, args)?; + let [x, exp] = this.check_shim(abi, CanonAbi::C , link_name, args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; let exp = this.read_scalar(exp)?.to_i32()?; @@ -902,7 +903,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "lgammaf_r" => { - let [x, signp] = this.check_shim(abi, Conv::C, link_name, args)?; + let [x, signp] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let x = this.read_scalar(x)?.to_f32()?; let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?; @@ -918,7 +919,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "lgamma_r" => { - let [x, signp] = this.check_shim(abi, Conv::C, link_name, args)?; + let [x, signp] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let x = this.read_scalar(x)?.to_f64()?; let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?; @@ -936,7 +937,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // LLVM intrinsics "llvm.prefetch" => { - let [p, rw, loc, ty] = this.check_shim(abi, Conv::C, link_name, args)?; + let [p, rw, loc, ty] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let _ = this.read_pointer(p)?; let rw = this.read_scalar(rw)?.to_i32()?; @@ -963,7 +964,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the x86 `_mm{,256,512}_popcnt_epi{8,16,32,64}` and wasm // `{i,u}8x16_popcnt` functions. name if name.starts_with("llvm.ctpop.v") => { - let [op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (op, op_len) = this.project_to_simd(op)?; let (dest, dest_len) = this.project_to_simd(dest)?; @@ -999,7 +1000,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } // FIXME: Move this to an `arm` submodule. "llvm.arm.hint" if this.tcx.sess.target.arch == "arm" => { - let [arg] = this.check_shim(abi, Conv::C, link_name, args)?; + let [arg] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let arg = this.read_scalar(arg)?.to_i32()?; // Note that different arguments might have different target feature requirements. match arg { diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index 0e7cf7153f5..690b5295681 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -1,6 +1,7 @@ +use rustc_abi::CanonAbi; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use crate::shims::unix::android::thread::prctl; use crate::shims::unix::linux_like::epoll::EvalContextExt as _; @@ -25,29 +26,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // epoll, eventfd "epoll_create1" => { - let [flag] = this.check_shim(abi, Conv::C, link_name, args)?; + let [flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.epoll_create1(flag)?; this.write_scalar(result, dest)?; } "epoll_ctl" => { - let [epfd, op, fd, event] = this.check_shim(abi, Conv::C, link_name, args)?; + let [epfd, op, fd, event] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.epoll_ctl(epfd, op, fd, event)?; this.write_scalar(result, dest)?; } "epoll_wait" => { let [epfd, events, maxevents, timeout] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; this.epoll_wait(epfd, events, maxevents, timeout, dest)?; } "eventfd" => { - let [val, flag] = this.check_shim(abi, Conv::C, link_name, args)?; + let [val, flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.eventfd(val, flag)?; this.write_scalar(result, dest)?; } // Miscellaneous "__errno" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs index aa3a05ead85..5d17d6c8517 100644 --- a/src/tools/miri/src/shims/unix/android/thread.rs +++ b/src/tools/miri/src/shims/unix/android/thread.rs @@ -1,7 +1,7 @@ -use rustc_abi::Size; +use rustc_abi::{CanonAbi, Size}; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use crate::helpers::check_min_vararg_count; use crate::shims::unix::thread::{EvalContextExt as _, ThreadNameResult}; @@ -16,7 +16,7 @@ pub fn prctl<'tcx>( args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { - let ([op], varargs) = ecx.check_shim_variadic(abi, Conv::C, link_name, args)?; + let ([op], varargs) = ecx.check_shim_variadic(abi, CanonAbi::C, link_name, args)?; // FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch. let pr_set_name = 15; diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 026aa1f9503..9106ef94c43 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -1,11 +1,11 @@ use std::ffi::OsStr; use std::str; -use rustc_abi::{ExternAbi, Size}; +use rustc_abi::{CanonAbi, ExternAbi, Size}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use self::shims::unix::android::foreign_items as android; use self::shims::unix::freebsd::foreign_items as freebsd; @@ -334,7 +334,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "fcntl" => { let ([fd_num, cmd], varargs) = - this.check_shim_variadic(abi, Conv::C, link_name, args)?; + this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?; let result = this.fcntl(fd_num, cmd, varargs)?; this.write_scalar(result, dest)?; } @@ -387,7 +387,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `open` is variadic, the third argument is only present when the second argument // has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set let ([path_raw, flag], varargs) = - this.check_shim_variadic(abi, Conv::C, link_name, args)?; + this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?; let result = this.open(path_raw, flag, varargs)?; this.write_scalar(result, dest)?; } @@ -701,20 +701,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Allocation "posix_memalign" => { - let [memptr, align, size] = this.check_shim(abi, Conv::C, link_name, args)?; + let [memptr, align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.posix_memalign(memptr, align, size)?; this.write_scalar(result, dest)?; } "mmap" => { let [addr, length, prot, flags, fd, offset] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; let ptr = this.mmap(addr, length, prot, flags, fd, offset)?; this.write_scalar(ptr, dest)?; } "munmap" => { - let [addr, length] = this.check_shim(abi, Conv::C, link_name, args)?; + let [addr, length] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.munmap(addr, length)?; this.write_scalar(result, dest)?; } @@ -722,7 +722,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "reallocarray" => { // Currently this function does not exist on all Unixes, e.g. on macOS. this.check_target_os(&["linux", "freebsd", "android"], link_name)?; - let [ptr, nmemb, size] = this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr, nmemb, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; let nmemb = this.read_target_usize(nmemb)?; let size = this.read_target_usize(size)?; @@ -745,14 +745,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "aligned_alloc" => { // This is a C11 function, we assume all Unixes have it. // (MSVC explicitly does not support this.) - let [align, size] = this.check_shim(abi, Conv::C, link_name, args)?; + let [align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let res = this.aligned_alloc(align, size)?; this.write_pointer(res, dest)?; } // Dynamic symbol loading "dlsym" => { - let [handle, symbol] = this.check_shim(abi, Conv::C, link_name, args)?; + let [handle, symbol] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.read_target_usize(handle)?; let symbol = this.read_pointer(symbol)?; let name = this.read_c_str(symbol)?; @@ -768,7 +768,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Thread-local storage "pthread_key_create" => { - let [key, dtor] = this.check_shim(abi, Conv::C, link_name, args)?; + let [key, dtor] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?; let dtor = this.read_pointer(dtor)?; @@ -796,21 +796,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } "pthread_key_delete" => { - let [key] = this.check_shim(abi, Conv::C, link_name, args)?; + let [key] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let [key] = this.check_shim(abi, Conv::C, link_name, args)?; + let [key] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; let active_thread = this.active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let [key, new_ptr] = this.check_shim(abi, Conv::C, link_name, args)?; + let [key, new_ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; let active_thread = this.active_thread(); let new_data = this.read_scalar(new_ptr)?; @@ -822,156 +822,157 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Synchronization primitives "pthread_mutexattr_init" => { - let [attr] = this.check_shim(abi, Conv::C, link_name, args)?; + let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_mutexattr_init(attr)?; this.write_null(dest)?; } "pthread_mutexattr_settype" => { - let [attr, kind] = this.check_shim(abi, Conv::C, link_name, args)?; + let [attr, kind] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(result, dest)?; } "pthread_mutexattr_destroy" => { - let [attr] = this.check_shim(abi, Conv::C, link_name, args)?; + let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_mutexattr_destroy(attr)?; this.write_null(dest)?; } "pthread_mutex_init" => { - let [mutex, attr] = this.check_shim(abi, Conv::C, link_name, args)?; + let [mutex, attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_mutex_init(mutex, attr)?; this.write_null(dest)?; } "pthread_mutex_lock" => { - let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?; + let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_mutex_lock(mutex, dest)?; } "pthread_mutex_trylock" => { - let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?; + let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(result, dest)?; } "pthread_mutex_unlock" => { - let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?; + let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(result, dest)?; } "pthread_mutex_destroy" => { - let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?; + let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_mutex_destroy(mutex)?; this.write_int(0, dest)?; } "pthread_rwlock_rdlock" => { - let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?; + let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_rwlock_rdlock(rwlock, dest)?; } "pthread_rwlock_tryrdlock" => { - let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?; + let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(result, dest)?; } "pthread_rwlock_wrlock" => { - let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?; + let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_rwlock_wrlock(rwlock, dest)?; } "pthread_rwlock_trywrlock" => { - let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?; + let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(result, dest)?; } "pthread_rwlock_unlock" => { - let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?; + let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_rwlock_unlock(rwlock)?; this.write_null(dest)?; } "pthread_rwlock_destroy" => { - let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?; + let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_rwlock_destroy(rwlock)?; this.write_null(dest)?; } "pthread_condattr_init" => { - let [attr] = this.check_shim(abi, Conv::C, link_name, args)?; + let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_condattr_init(attr)?; this.write_null(dest)?; } "pthread_condattr_setclock" => { - let [attr, clock_id] = this.check_shim(abi, Conv::C, link_name, args)?; + let [attr, clock_id] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(result, dest)?; } "pthread_condattr_getclock" => { - let [attr, clock_id] = this.check_shim(abi, Conv::C, link_name, args)?; + let [attr, clock_id] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_condattr_getclock(attr, clock_id)?; this.write_null(dest)?; } "pthread_condattr_destroy" => { - let [attr] = this.check_shim(abi, Conv::C, link_name, args)?; + let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_condattr_destroy(attr)?; this.write_null(dest)?; } "pthread_cond_init" => { - let [cond, attr] = this.check_shim(abi, Conv::C, link_name, args)?; + let [cond, attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_cond_init(cond, attr)?; this.write_null(dest)?; } "pthread_cond_signal" => { - let [cond] = this.check_shim(abi, Conv::C, link_name, args)?; + let [cond] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_cond_signal(cond)?; this.write_null(dest)?; } "pthread_cond_broadcast" => { - let [cond] = this.check_shim(abi, Conv::C, link_name, args)?; + let [cond] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_cond_broadcast(cond)?; this.write_null(dest)?; } "pthread_cond_wait" => { - let [cond, mutex] = this.check_shim(abi, Conv::C, link_name, args)?; + let [cond, mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_cond_wait(cond, mutex, dest)?; } "pthread_cond_timedwait" => { - let [cond, mutex, abstime] = this.check_shim(abi, Conv::C, link_name, args)?; + let [cond, mutex, abstime] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - let [cond] = this.check_shim(abi, Conv::C, link_name, args)?; + let [cond] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_cond_destroy(cond)?; this.write_null(dest)?; } // Threading "pthread_create" => { - let [thread, attr, start, arg] = this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, attr, start, arg] = + this.check_shim(abi, CanonAbi::C, link_name, args)?; this.pthread_create(thread, attr, start, arg)?; this.write_null(dest)?; } "pthread_join" => { - let [thread, retval] = this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, retval] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let res = this.pthread_join(thread, retval)?; this.write_scalar(res, dest)?; } "pthread_detach" => { - let [thread] = this.check_shim(abi, Conv::C, link_name, args)?; + let [thread] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let res = this.pthread_detach(thread)?; this.write_scalar(res, dest)?; } "pthread_self" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let res = this.pthread_self()?; this.write_scalar(res, dest)?; } "sched_yield" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.sched_yield()?; this.write_null(dest)?; } "nanosleep" => { - let [req, rem] = this.check_shim(abi, Conv::C, link_name, args)?; + let [req, rem] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(result, dest)?; } "sched_getaffinity" => { // Currently this function does not exist on all Unixes, e.g. on macOS. this.check_target_os(&["linux", "freebsd", "android"], link_name)?; - let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?; + let [pid, cpusetsize, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let pid = this.read_scalar(pid)?.to_u32()?; let cpusetsize = this.read_target_usize(cpusetsize)?; let mask = this.read_pointer(mask)?; @@ -1008,7 +1009,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "sched_setaffinity" => { // Currently this function does not exist on all Unixes, e.g. on macOS. this.check_target_os(&["linux", "freebsd", "android"], link_name)?; - let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?; + let [pid, cpusetsize, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let pid = this.read_scalar(pid)?.to_u32()?; let cpusetsize = this.read_target_usize(cpusetsize)?; let mask = this.read_pointer(mask)?; @@ -1048,12 +1049,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miscellaneous "isatty" => { - let [fd] = this.check_shim(abi, Conv::C, link_name, args)?; + let [fd] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.isatty(fd)?; this.write_scalar(result, dest)?; } "pthread_atfork" => { - let [prepare, parent, child] = this.check_shim(abi, Conv::C, link_name, args)?; + let [prepare, parent, child] = + this.check_shim(abi, CanonAbi::C, link_name, args)?; this.read_pointer(prepare)?; this.read_pointer(parent)?; this.read_pointer(child)?; @@ -1067,7 +1069,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &["linux", "macos", "freebsd", "illumos", "solaris", "android"], link_name, )?; - let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?; + let [buf, bufsize] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let buf = this.read_pointer(buf)?; let bufsize = this.read_target_usize(bufsize)?; @@ -1085,7 +1087,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "strerror_r" => { - let [errnum, buf, buflen] = this.check_shim(abi, Conv::C, link_name, args)?; + let [errnum, buf, buflen] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.strerror_r(errnum, buf, buflen)?; this.write_scalar(result, dest)?; } @@ -1097,7 +1099,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &["linux", "freebsd", "illumos", "solaris", "android"], link_name, )?; - let [ptr, len, flags] = this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr, len, flags] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_target_usize(len)?; let _flags = this.read_scalar(flags)?.to_i32()?; @@ -1109,7 +1111,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // This function is non-standard but exists with the same signature and // same behavior (eg never fails) on FreeBSD and Solaris/Illumos. this.check_target_os(&["freebsd", "illumos", "solaris"], link_name)?; - let [ptr, len] = this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_target_usize(len)?; this.gen_random(ptr, len)?; @@ -1133,12 +1135,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { link_name, )?; // This function looks and behaves excatly like miri_start_unwind. - let [payload] = this.check_shim(abi, Conv::C, link_name, args)?; + let [payload] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.handle_miri_start_unwind(payload)?; return interp_ok(EmulateItemResult::NeedsUnwind); } "getuid" | "geteuid" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; // For now, just pretend we always have this fixed UID. this.write_int(UID, dest)?; } @@ -1146,7 +1148,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame_in_std() => { - let [_attr, guard_size] = this.check_shim(abi, Conv::C, link_name, args)?; + let [_attr, guard_size] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let guard_size_layout = this.machine.layouts.usize; let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?; this.write_scalar( @@ -1159,11 +1161,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => { - let [_] = this.check_shim(abi, Conv::C, link_name, args)?; + let [_] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.write_null(dest)?; } "pthread_attr_setstacksize" if this.frame_in_std() => { - let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?; + let [_, _] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.write_null(dest)?; } @@ -1171,7 +1173,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. // Hence we can mostly ignore the input `attr_place`. let [attr_place, addr_place, size_place] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; let _attr_place = this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?; let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?; @@ -1191,18 +1193,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "signal" | "sigaltstack" if this.frame_in_std() => { - let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?; + let [_, _] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.write_null(dest)?; } "sigaction" | "mprotect" if this.frame_in_std() => { - let [_, _, _] = this.check_shim(abi, Conv::C, link_name, args)?; + let [_, _, _] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.write_null(dest)?; } "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => { // getpwuid_r is the standard name, __posix_getpwuid_r is used on solarish let [uid, pwd, buf, buflen, result] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; this.check_no_isolation("`getpwuid_r`")?; let uid = this.read_scalar(uid)?.to_u32()?; diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 533a741fea3..42502d5bf09 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -1,6 +1,7 @@ +use rustc_abi::CanonAbi; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use super::sync::EvalContextExt as _; use crate::shims::unix::*; @@ -23,7 +24,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // Threading "pthread_setname_np" => { - let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, name] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let max_len = u64::MAX; // FreeBSD does not seem to have a limit. let res = match this.pthread_setname_np( this.read_scalar(thread)?, @@ -38,7 +39,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "pthread_getname_np" => { - let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?; // FreeBSD's pthread_getname_np uses strlcpy, which truncates the resulting value, // but always adds a null terminator (except for zero-sized buffers). // https://github.com/freebsd/freebsd-src/blob/c2d93a803acef634bd0eede6673aeea59e90c277/lib/libthr/thread/thr_info.c#L119-L144 @@ -59,7 +60,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "cpuset_getaffinity" => { // The "same" kind of api as `sched_getaffinity` but more fine grained control for FreeBSD specifically. let [level, which, id, set_size, mask] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; let level = this.read_scalar(level)?.to_i32()?; let which = this.read_scalar(which)?.to_i32()?; @@ -123,7 +124,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Synchronization primitives "_umtx_op" => { let [obj, op, val, uaddr, uaddr2] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; this._umtx_op(obj, op, val, uaddr, uaddr2, dest)?; } @@ -131,29 +132,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // For those, we both intercept `func` and `call@FBSD_1.0` symbols cases // since freebsd 12 the former form can be expected. "stat" | "stat@FBSD_1.0" => { - let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; + let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_solarish_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat@FBSD_1.0" => { - let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; + let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_solarish_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat@FBSD_1.0" => { - let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?; + let [fd, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_solarish_fstat(fd, buf)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r@FBSD_1.0" => { - let [dirp, entry, result] = this.check_shim(abi, Conv::C, link_name, args)?; + let [dirp, entry, result] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; this.write_scalar(result, dest)?; } // Miscellaneous "__error" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } @@ -161,7 +162,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_attr_get_np" if this.frame_in_std() => { - let [_thread, _attr] = this.check_shim(abi, Conv::C, link_name, args)?; + let [_thread, _attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.write_null(dest)?; } diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index 51c2434d68a..aeaff1cb13a 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -1,6 +1,7 @@ +use rustc_abi::CanonAbi; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use self::shims::unix::linux::mem::EvalContextExt as _; use self::shims::unix::linux_like::epoll::EvalContextExt as _; @@ -36,47 +37,48 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // File related shims "readdir64" => { - let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?; + let [dirp] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.linux_solarish_readdir64("dirent64", dirp)?; this.write_scalar(result, dest)?; } "sync_file_range" => { - let [fd, offset, nbytes, flags] = this.check_shim(abi, Conv::C, link_name, args)?; + let [fd, offset, nbytes, flags] = + this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(result, dest)?; } "statx" => { let [dirfd, pathname, flags, mask, statxbuf] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?; this.write_scalar(result, dest)?; } // epoll, eventfd "epoll_create1" => { - let [flag] = this.check_shim(abi, Conv::C, link_name, args)?; + let [flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.epoll_create1(flag)?; this.write_scalar(result, dest)?; } "epoll_ctl" => { - let [epfd, op, fd, event] = this.check_shim(abi, Conv::C, link_name, args)?; + let [epfd, op, fd, event] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.epoll_ctl(epfd, op, fd, event)?; this.write_scalar(result, dest)?; } "epoll_wait" => { let [epfd, events, maxevents, timeout] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; this.epoll_wait(epfd, events, maxevents, timeout, dest)?; } "eventfd" => { - let [val, flag] = this.check_shim(abi, Conv::C, link_name, args)?; + let [val, flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.eventfd(val, flag)?; this.write_scalar(result, dest)?; } // Threading "pthread_setname_np" => { - let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, name] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let res = match this.pthread_setname_np( this.read_scalar(thread)?, this.read_scalar(name)?, @@ -91,7 +93,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "pthread_getname_np" => { - let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?; // The function's behavior isn't portable between platforms. // In case of glibc, the length of the output buffer must // be not shorter than TASK_COMM_LEN. @@ -114,7 +116,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "gettid" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.linux_gettid()?; this.write_scalar(result, dest)?; } @@ -127,34 +129,34 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miscellaneous "mmap64" => { let [addr, length, prot, flags, fd, offset] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; let offset = this.read_scalar(offset)?.to_i64()?; let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?; this.write_scalar(ptr, dest)?; } "mremap" => { let ([old_address, old_size, new_size, flags], _) = - this.check_shim_variadic(abi, Conv::C, link_name, args)?; + this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?; let ptr = this.mremap(old_address, old_size, new_size, flags)?; this.write_scalar(ptr, dest)?; } "__xpg_strerror_r" => { - let [errnum, buf, buflen] = this.check_shim(abi, Conv::C, link_name, args)?; + let [errnum, buf, buflen] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.strerror_r(errnum, buf, buflen)?; this.write_scalar(result, dest)?; } "__errno_location" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } "__libc_current_sigrtmin" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.write_int(SIGRTMIN, dest)?; } "__libc_current_sigrtmax" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.write_int(SIGRTMAX, dest)?; } @@ -162,7 +164,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame_in_std() => { - let [_thread, _attr] = this.check_shim(abi, Conv::C, link_name, args)?; + let [_thread, _attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.write_null(dest)?; } diff --git a/src/tools/miri/src/shims/unix/linux_like/syscall.rs b/src/tools/miri/src/shims/unix/linux_like/syscall.rs index 22c6dc97507..d42d6b9073e 100644 --- a/src/tools/miri/src/shims/unix/linux_like/syscall.rs +++ b/src/tools/miri/src/shims/unix/linux_like/syscall.rs @@ -1,6 +1,7 @@ +use rustc_abi::CanonAbi; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use crate::helpers::check_min_vararg_count; use crate::shims::unix::linux_like::eventfd::EvalContextExt as _; @@ -14,7 +15,7 @@ pub fn syscall<'tcx>( args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { - let ([op], varargs) = ecx.check_shim_variadic(abi, Conv::C, link_name, args)?; + let ([op], varargs) = ecx.check_shim_variadic(abi, CanonAbi::C, link_name, args)?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. The important check is that when we use an // argument, we have to also check all arguments *before* it to ensure that they diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 0281bb9f71d..ae921a013a4 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -1,6 +1,7 @@ +use rustc_abi::CanonAbi; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use super::sync::{EvalContextExt as _, MacOsFutexTimeout}; use crate::shims::unix::*; @@ -34,64 +35,64 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // errno "__error" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } // File related shims "close$NOCANCEL" => { - let [result] = this.check_shim(abi, Conv::C, link_name, args)?; + let [result] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.close(result)?; this.write_scalar(result, dest)?; } "stat" | "stat64" | "stat$INODE64" => { - let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; + let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_solarish_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat64" | "lstat$INODE64" => { - let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; + let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_solarish_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat64" | "fstat$INODE64" => { - let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?; + let [fd, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_solarish_fstat(fd, buf)?; this.write_scalar(result, dest)?; } "opendir$INODE64" => { - let [name] = this.check_shim(abi, Conv::C, link_name, args)?; + let [name] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { - let [dirp, entry, result] = this.check_shim(abi, Conv::C, link_name, args)?; + let [dirp, entry, result] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; this.write_scalar(result, dest)?; } "realpath$DARWIN_EXTSN" => { - let [path, resolved_path] = this.check_shim(abi, Conv::C, link_name, args)?; + let [path, resolved_path] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.realpath(path, resolved_path)?; this.write_scalar(result, dest)?; } "ioctl" => { let ([fd_num, cmd], varargs) = - this.check_shim_variadic(abi, Conv::C, link_name, args)?; + this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?; let result = this.ioctl(fd_num, cmd, varargs)?; this.write_scalar(result, dest)?; } // Environment related shims "_NSGetEnviron" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let environ = this.machine.env_vars.unix().environ(); this.write_pointer(environ, dest)?; } // Random data generation "CCRandomGenerateBytes" => { - let [bytes, count] = this.check_shim(abi, Conv::C, link_name, args)?; + let [bytes, count] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let bytes = this.read_pointer(bytes)?; let count = this.read_target_usize(count)?; let success = this.eval_libc_i32("kCCSuccess"); @@ -101,28 +102,28 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Time related shims "mach_absolute_time" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.mach_absolute_time()?; this.write_scalar(result, dest)?; } "mach_timebase_info" => { - let [info] = this.check_shim(abi, Conv::C, link_name, args)?; + let [info] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(result, dest)?; } // Access to command-line arguments "_NSGetArgc" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.write_pointer(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?; } "_NSGetExecutablePath" => { - let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?; + let [buf, bufsize] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.check_no_isolation("`_NSGetExecutablePath`")?; let buf_ptr = this.read_pointer(buf)?; @@ -147,7 +148,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Thread-local storage "_tlv_atexit" => { - let [dtor, data] = this.check_shim(abi, Conv::C, link_name, args)?; + let [dtor, data] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let dtor = this.read_pointer(dtor)?; let dtor = this.get_ptr_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?; @@ -157,13 +158,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Querying system information "pthread_get_stackaddr_np" => { - let [thread] = this.check_shim(abi, Conv::C, link_name, args)?; + let [thread] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.read_target_usize(thread)?; let stack_addr = Scalar::from_uint(this.machine.stack_addr, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - let [thread] = this.check_shim(abi, Conv::C, link_name, args)?; + let [thread] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.read_target_usize(thread)?; let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size()); this.write_scalar(stack_size, dest)?; @@ -171,7 +172,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Threading "pthread_setname_np" => { - let [name] = this.check_shim(abi, Conv::C, link_name, args)?; + let [name] = this.check_shim(abi, CanonAbi::C, link_name, args)?; // The real implementation has logic in two places: // * in userland at https://github.com/apple-oss-distributions/libpthread/blob/c032e0b076700a0a47db75528a282b8d3a06531a/src/pthread.c#L1178-L1200, @@ -198,7 +199,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "pthread_getname_np" => { - let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?; // The function's behavior isn't portable between platforms. // In case of macOS, a truncated name (due to a too small buffer) @@ -225,7 +226,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Synchronization primitives "os_sync_wait_on_address" => { let [addr_op, value_op, size_op, flags_op] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; this.os_sync_wait_on_address( addr_op, value_op, @@ -237,7 +238,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "os_sync_wait_on_address_with_deadline" => { let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; this.os_sync_wait_on_address( addr_op, value_op, @@ -249,7 +250,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "os_sync_wait_on_address_with_timeout" => { let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; this.os_sync_wait_on_address( addr_op, value_op, @@ -261,36 +262,36 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "os_sync_wake_by_address_any" => { let [addr_op, size_op, flags_op] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; this.os_sync_wake_by_address( addr_op, size_op, flags_op, /* all */ false, dest, )?; } "os_sync_wake_by_address_all" => { let [addr_op, size_op, flags_op] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; this.os_sync_wake_by_address( addr_op, size_op, flags_op, /* all */ true, dest, )?; } "os_unfair_lock_lock" => { - let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.os_unfair_lock_lock(lock_op)?; } "os_unfair_lock_trylock" => { - let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.os_unfair_lock_trylock(lock_op, dest)?; } "os_unfair_lock_unlock" => { - let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.os_unfair_lock_unlock(lock_op)?; } "os_unfair_lock_assert_owner" => { - let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.os_unfair_lock_assert_owner(lock_op)?; } "os_unfair_lock_assert_not_owner" => { - let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.os_unfair_lock_assert_not_owner(lock_op)?; } diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index 21d4f41f485..e3d15b89be6 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -1,6 +1,7 @@ +use rustc_abi::CanonAbi; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use crate::shims::unix::foreign_items::EvalContextExt as _; use crate::shims::unix::linux_like::epoll::EvalContextExt as _; @@ -26,32 +27,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // epoll, eventfd (NOT available on Solaris!) "epoll_create1" => { this.assert_target_os("illumos", "epoll_create1"); - let [flag] = this.check_shim(abi, Conv::C, link_name, args)?; + let [flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.epoll_create1(flag)?; this.write_scalar(result, dest)?; } "epoll_ctl" => { this.assert_target_os("illumos", "epoll_ctl"); - let [epfd, op, fd, event] = this.check_shim(abi, Conv::C, link_name, args)?; + let [epfd, op, fd, event] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.epoll_ctl(epfd, op, fd, event)?; this.write_scalar(result, dest)?; } "epoll_wait" => { this.assert_target_os("illumos", "epoll_wait"); let [epfd, events, maxevents, timeout] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; this.epoll_wait(epfd, events, maxevents, timeout, dest)?; } "eventfd" => { this.assert_target_os("illumos", "eventfd"); - let [val, flag] = this.check_shim(abi, Conv::C, link_name, args)?; + let [val, flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.eventfd(val, flag)?; this.write_scalar(result, dest)?; } // Threading "pthread_setname_np" => { - let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, name] = this.check_shim(abi, CanonAbi::C, link_name, args)?; // THREAD_NAME_MAX allows a thread name of 31+1 length // https://github.com/illumos/illumos-gate/blob/7671517e13b8123748eda4ef1ee165c6d9dba7fe/usr/src/uts/common/sys/thread.h#L613 let max_len = 32; @@ -69,7 +70,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "pthread_getname_np" => { - let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?; + let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?; // See https://illumos.org/man/3C/pthread_getname_np for the error codes. let res = match this.pthread_getname_np( this.read_scalar(thread)?, @@ -86,22 +87,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File related shims "stat" | "stat64" => { - let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; + let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_solarish_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat64" => { - let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; + let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_solarish_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat64" => { - let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?; + let [fd, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.macos_fbsd_solarish_fstat(fd, buf)?; this.write_scalar(result, dest)?; } "readdir" => { - let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?; + let [dirp] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.linux_solarish_readdir64("dirent", dirp)?; this.write_scalar(result, dest)?; } @@ -109,20 +110,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Sockets and pipes "__xnet_socketpair" => { let [domain, type_, protocol, sv] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.socketpair(domain, type_, protocol, sv)?; this.write_scalar(result, dest)?; } // Miscellaneous "___errno" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } "stack_getbounds" => { - let [stack] = this.check_shim(abi, Conv::C, link_name, args)?; + let [stack] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let stack = this.deref_pointer_as(stack, this.libc_ty_layout("stack_t"))?; this.write_int_fields_named( @@ -140,7 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pset_info" => { - let [pset, tpe, cpus, list] = this.check_shim(abi, Conv::C, link_name, args)?; + let [pset, tpe, cpus, list] = this.check_shim(abi, CanonAbi::C, link_name, args)?; // We do not need to handle the current process cpu mask, available_parallelism // implementation pass null anyway. We only care for the number of // cpus. @@ -169,7 +170,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "__sysconf_xpg7" => { - let [val] = this.check_shim(abi, Conv::C, link_name, args)?; + let [val] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.sysconf(val)?; this.write_scalar(result, dest)?; } diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs index 90de62b9e57..8d92d0f3381 100644 --- a/src/tools/miri/src/shims/wasi/foreign_items.rs +++ b/src/tools/miri/src/shims/wasi/foreign_items.rs @@ -1,6 +1,7 @@ +use rustc_abi::CanonAbi; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use crate::shims::alloc::EvalContextExt as _; use crate::*; @@ -22,12 +23,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // Allocation "posix_memalign" => { - let [memptr, align, size] = this.check_shim(abi, Conv::C, link_name, args)?; + let [memptr, align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let result = this.posix_memalign(memptr, align, size)?; this.write_scalar(result, dest)?; } "aligned_alloc" => { - let [align, size] = this.check_shim(abi, Conv::C, link_name, args)?; + let [align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let res = this.aligned_alloc(align, size)?; this.write_pointer(res, dest)?; } diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index d822dd07fcd..29671eb8149 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -2,10 +2,10 @@ use std::ffi::OsStr; use std::path::{self, Path, PathBuf}; use std::{io, iter, str}; -use rustc_abi::{Align, Size}; +use rustc_abi::{Align, CanonAbi, Size, X86Call}; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use self::shims::windows::handle::{Handle, PseudoHandle}; use crate::shims::os_str::bytes_to_os_str; @@ -140,7 +140,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://github.com/rust-lang/rust/blob/fb00adbdb69266f10df95a4527b767b0ad35ea48/compiler/rustc_target/src/spec/mod.rs#L2766-L2768, // x86-32 Windows uses a different calling convention than other Windows targets // for the "system" ABI. - let sys_conv = if this.tcx.sess.target.arch == "x86" { Conv::X86Stdcall } else { Conv::C }; + let sys_conv = if this.tcx.sess.target.arch == "x86" { + CanonAbi::X86(X86Call::Stdcall) + } else { + CanonAbi::C + }; // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. @@ -834,7 +838,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } // This function looks and behaves excatly like miri_start_unwind. - let [payload] = this.check_shim(abi, Conv::C, link_name, args)?; + let [payload] = this.check_shim(abi, CanonAbi::C, link_name, args)?; this.handle_miri_start_unwind(payload)?; return interp_ok(EmulateItemResult::NeedsUnwind); } diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs index c6784db67fb..7191284b5a3 100644 --- a/src/tools/miri/src/shims/x86/aesni.rs +++ b/src/tools/miri/src/shims/x86/aesni.rs @@ -1,7 +1,8 @@ +use rustc_abi::CanonAbi; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf as _; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use crate::*; @@ -26,7 +27,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `state` with the corresponding 128-bit key of `key`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdec_si128 "aesdec" | "aesdec.256" | "aesdec.512" => { - let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?; + let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?; aes_round(this, state, key, dest, |state, key| { let key = aes::Block::from(key.to_le_bytes()); let mut state = aes::Block::from(state.to_le_bytes()); @@ -42,7 +43,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `state` with the corresponding 128-bit key of `key`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdeclast_si128 "aesdeclast" | "aesdeclast.256" | "aesdeclast.512" => { - let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?; + let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?; aes_round(this, state, key, dest, |state, key| { let mut state = aes::Block::from(state.to_le_bytes()); @@ -66,7 +67,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `state` with the corresponding 128-bit key of `key`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenc_si128 "aesenc" | "aesenc.256" | "aesenc.512" => { - let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?; + let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?; aes_round(this, state, key, dest, |state, key| { let key = aes::Block::from(key.to_le_bytes()); let mut state = aes::Block::from(state.to_le_bytes()); @@ -82,7 +83,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `state` with the corresponding 128-bit key of `key`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenclast_si128 "aesenclast" | "aesenclast.256" | "aesenclast.512" => { - let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?; + let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?; aes_round(this, state, key, dest, |state, key| { let mut state = aes::Block::from(state.to_le_bytes()); // `aes::hazmat::cipher_round` does the following operations: @@ -102,7 +103,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm_aesimc_si128 function. // Performs the AES InvMixColumns operation on `op` "aesimc" => { - let [op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; // Transmute to `u128` let op = op.transmute(this.machine.layouts.u128, this)?; let dest = dest.transmute(this.machine.layouts.u128, this)?; diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs index 3aeb2b429da..37539fec748 100644 --- a/src/tools/miri/src/shims/x86/avx.rs +++ b/src/tools/miri/src/shims/x86/avx.rs @@ -1,9 +1,10 @@ +use rustc_abi::CanonAbi; use rustc_apfloat::ieee::{Double, Single}; use rustc_middle::mir; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf as _; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use super::{ FloatBinOp, FloatUnaryOp, bin_op_simd_float_all, conditional_dot_product, convert_float_to_int, @@ -33,7 +34,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // matches the IEEE min/max operations, while x86 has different // semantics. "min.ps.256" | "max.ps.256" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = match unprefixed_name { "min.ps.256" => FloatBinOp::Min, @@ -45,7 +46,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Used to implement _mm256_min_pd and _mm256_max_pd functions. "min.pd.256" | "max.pd.256" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = match unprefixed_name { "min.pd.256" => FloatBinOp::Min, @@ -58,21 +59,21 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm256_round_ps function. // Rounds the elements of `op` according to `rounding`. "round.ps.256" => { - let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?; round_all::(this, op, rounding, dest)?; } // Used to implement the _mm256_round_pd function. // Rounds the elements of `op` according to `rounding`. "round.pd.256" => { - let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?; round_all::(this, op, rounding, dest)?; } // Used to implement _mm256_{rcp,rsqrt}_ps functions. // Performs the operations on all components of `op`. "rcp.ps.256" | "rsqrt.ps.256" => { - let [op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = match unprefixed_name { "rcp.ps.256" => FloatUnaryOp::Rcp, @@ -84,7 +85,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Used to implement the _mm256_dp_ps function. "dp.ps.256" => { - let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; conditional_dot_product(this, left, right, imm, dest)?; } @@ -92,7 +93,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Horizontally add/subtract adjacent floating point values // in `left` and `right`. "hadd.ps.256" | "hadd.pd.256" | "hsub.ps.256" | "hsub.pd.256" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = match unprefixed_name { "hadd.ps.256" | "hadd.pd.256" => mir::BinOp::Add, @@ -107,7 +108,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // and `right`. For each component, returns 0 if false or u32::MAX // if true. "cmp.ps.256" => { - let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -119,7 +120,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // and `right`. For each component, returns 0 if false or u64::MAX // if true. "cmp.pd.256" => { - let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -130,7 +131,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // and _mm256_cvttpd_epi32 functions. // Converts packed f32/f64 to packed i32. "cvt.ps2dq.256" | "cvtt.ps2dq.256" | "cvt.pd2dq.256" | "cvtt.pd2dq.256" => { - let [op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let rnd = match unprefixed_name { // "current SSE rounding mode", assume nearest @@ -148,7 +149,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // sequence of 4-element arrays, and we shuffle each of these arrays, where // `control` determines which element of the current `data` array is written. "vpermilvar.ps" | "vpermilvar.ps.256" => { - let [data, control] = this.check_shim(abi, Conv::C, link_name, args)?; + let [data, control] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (data, data_len) = this.project_to_simd(data)?; let (control, control_len) = this.project_to_simd(control)?; @@ -181,7 +182,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // where `right` determines which element of the current `left` array is // written. "vpermilvar.pd" | "vpermilvar.pd.256" => { - let [data, control] = this.check_shim(abi, Conv::C, link_name, args)?; + let [data, control] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (data, data_len) = this.project_to_simd(data)?; let (control, control_len) = this.project_to_simd(control)?; @@ -213,7 +214,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // For each 128-bit element of `dest`, copies one from `left`, `right` or // zero, according to `imm`. "vperm2f128.ps.256" | "vperm2f128.pd.256" | "vperm2f128.si.256" => { - let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; assert_eq!(dest.layout, left.layout); assert_eq!(dest.layout, right.layout); @@ -256,7 +257,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is one, it is loaded from `ptr.wrapping_add(i)`, otherwise zero is // loaded. "maskload.ps" | "maskload.pd" | "maskload.ps.256" | "maskload.pd.256" => { - let [ptr, mask] = this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?; mask_load(this, ptr, mask, dest)?; } @@ -266,7 +267,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is one, it is stored into `ptr.wapping_add(i)`. // Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores. "maskstore.ps" | "maskstore.pd" | "maskstore.ps.256" | "maskstore.pd.256" => { - let [ptr, mask, value] = this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr, mask, value] = this.check_shim(abi, CanonAbi::C, link_name, args)?; mask_store(this, ptr, mask, value)?; } @@ -276,7 +277,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // the data crosses a cache line, but for Miri this is just a regular // unaligned read. "ldu.dq.256" => { - let [src_ptr] = this.check_shim(abi, Conv::C, link_name, args)?; + let [src_ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let src_ptr = this.read_pointer(src_ptr)?; let dest = dest.force_mplace(this)?; @@ -288,7 +289,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Tests `op & mask == 0`, `op & mask == mask` or // `op & mask != 0 && op & mask != mask` "ptestz.256" | "ptestc.256" | "ptestnzc.256" => { - let [op, mask] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (all_zero, masked_set) = test_bits_masked(this, op, mask)?; let res = match unprefixed_name { @@ -311,7 +312,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "vtestz.pd.256" | "vtestc.pd.256" | "vtestnzc.pd.256" | "vtestz.pd" | "vtestc.pd" | "vtestnzc.pd" | "vtestz.ps.256" | "vtestc.ps.256" | "vtestnzc.ps.256" | "vtestz.ps" | "vtestc.ps" | "vtestnzc.ps" => { - let [op, mask] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (direct, negated) = test_high_bits_masked(this, op, mask)?; let res = match unprefixed_name { @@ -333,7 +334,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // compiler, making these functions no-ops. // The only thing that needs to be ensured is the correct calling convention. - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; } _ => return interp_ok(EmulateItemResult::NotSupported), } diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs index c79899285cd..5dfe5cc2c54 100644 --- a/src/tools/miri/src/shims/x86/avx2.rs +++ b/src/tools/miri/src/shims/x86/avx2.rs @@ -1,8 +1,9 @@ +use rustc_abi::CanonAbi; use rustc_middle::mir; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf as _; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use super::{ ShiftOp, horizontal_bin_op, int_abs, mask_load, mask_store, mpsadbw, packssdw, packsswb, @@ -28,7 +29,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm256_abs_epi{8,16,32} functions. // Calculates the absolute value of packed 8/16/32-bit integers. "pabs.b" | "pabs.w" | "pabs.d" => { - let [op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; int_abs(this, op, dest)?; } @@ -36,7 +37,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Horizontally add / add with saturation / subtract adjacent 16/32-bit // integer values in `left` and `right`. "phadd.w" | "phadd.sw" | "phadd.d" | "phsub.w" | "phsub.sw" | "phsub.d" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (which, saturating) = match unprefixed_name { "phadd.w" | "phadd.d" => (mir::BinOp::Add, false), @@ -57,7 +58,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "gather.d.pd.256" | "gather.q.pd" | "gather.q.pd.256" | "gather.d.ps" | "gather.d.ps.256" | "gather.q.ps" | "gather.q.ps.256" => { let [src, slice, offsets, mask, scale] = - this.check_shim(abi, Conv::C, link_name, args)?; + this.check_shim(abi, CanonAbi::C, link_name, args)?; assert_eq!(dest.layout, src.layout); @@ -114,7 +115,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // intermediate signed 32-bit integers. Horizontally add adjacent pairs of // intermediate 32-bit integers, and pack the results in `dest`. "pmadd.wd" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -150,7 +151,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // the saturating sum of the products with indices `2*i` and `2*i+1` // produces the output at index `i`. "pmadd.ub.sw" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -184,7 +185,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is one, it is loaded from `ptr.wrapping_add(i)`, otherwise zero is // loaded. "maskload.d" | "maskload.q" | "maskload.d.256" | "maskload.q.256" => { - let [ptr, mask] = this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?; mask_load(this, ptr, mask, dest)?; } @@ -194,7 +195,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is one, it is stored into `ptr.wapping_add(i)`. // Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores. "maskstore.d" | "maskstore.q" | "maskstore.d.256" | "maskstore.q.256" => { - let [ptr, mask, value] = this.check_shim(abi, Conv::C, link_name, args)?; + let [ptr, mask, value] = this.check_shim(abi, CanonAbi::C, link_name, args)?; mask_store(this, ptr, mask, value)?; } @@ -205,7 +206,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // offsets specified in `imm`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mpsadbw_epu8 "mpsadbw" => { - let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; mpsadbw(this, left, right, imm, dest)?; } @@ -216,7 +217,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // 1 and then taking the bits `1..=16`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mulhrs_epi16 "pmul.hr.sw" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; pmulhrsw(this, left, right, dest)?; } @@ -224,7 +225,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts two 16-bit integer vectors to a single 8-bit integer // vector with signed saturation. "packsswb" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; packsswb(this, left, right, dest)?; } @@ -232,7 +233,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts two 32-bit integer vectors to a single 16-bit integer // vector with signed saturation. "packssdw" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; packssdw(this, left, right, dest)?; } @@ -240,7 +241,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts two 16-bit signed integer vectors to a single 8-bit // unsigned integer vector with saturation. "packuswb" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; packuswb(this, left, right, dest)?; } @@ -248,7 +249,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Concatenates two 32-bit signed integer vectors and converts // the result to a 16-bit unsigned integer vector with saturation. "packusdw" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; packusdw(this, left, right, dest)?; } @@ -257,7 +258,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Shuffles `left` using the three low bits of each element of `right` // as indices. "permd" | "permps" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -277,7 +278,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm256_permute2x128_si256 function. // Shuffles 128-bit blocks of `a` and `b` using `imm` as pattern. "vperm2i128" => { - let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; assert_eq!(left.layout.size.bits(), 256); assert_eq!(right.layout.size.bits(), 256); @@ -314,7 +315,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // in `dest`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_sad_epu8 "psad.bw" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -346,7 +347,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Shuffles bytes from `left` using `right` as pattern. // Each 128-bit block is shuffled independently. "pshuf.b" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -377,7 +378,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is writen to the corresponding output element. // Basically, we multiply `left` with `right.signum()`. "psign.b" | "psign.w" | "psign.d" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; psign(this, left, right, dest)?; } @@ -391,7 +392,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is copied to remaining bits. "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q" | "psrl.q" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = match unprefixed_name { "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left, @@ -406,7 +407,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // (except _mm{,256}_srav_epi64, which are not available in AVX2). "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" | "psrlv.d" | "psrlv.d.256" | "psrlv.q" | "psrlv.q.256" | "psrav.d" | "psrav.d.256" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = match unprefixed_name { "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" => ShiftOp::Left, diff --git a/src/tools/miri/src/shims/x86/bmi.rs b/src/tools/miri/src/shims/x86/bmi.rs index 8af59df0a68..80b1b2e16e6 100644 --- a/src/tools/miri/src/shims/x86/bmi.rs +++ b/src/tools/miri/src/shims/x86/bmi.rs @@ -1,6 +1,7 @@ +use rustc_abi::CanonAbi; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use crate::*; @@ -34,7 +35,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(EmulateItemResult::NotSupported); } - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let left = this.read_scalar(left)?; let right = this.read_scalar(right)?; diff --git a/src/tools/miri/src/shims/x86/gfni.rs b/src/tools/miri/src/shims/x86/gfni.rs index a91c74283fd..f83ce560c84 100644 --- a/src/tools/miri/src/shims/x86/gfni.rs +++ b/src/tools/miri/src/shims/x86/gfni.rs @@ -1,6 +1,7 @@ +use rustc_abi::CanonAbi; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use crate::*; @@ -30,14 +31,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // See `affine_transform` for details. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affine_ "vgf2p8affineqb.128" | "vgf2p8affineqb.256" | "vgf2p8affineqb.512" => { - let [left, right, imm8] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm8] = this.check_shim(abi, CanonAbi::C, link_name, args)?; affine_transform(this, left, right, imm8, dest, /* inverse */ false)?; } // Used to implement the `_mm{, 256, 512}_gf2p8affineinv_epi64_epi8` functions. // See `affine_transform` for details. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affineinv "vgf2p8affineinvqb.128" | "vgf2p8affineinvqb.256" | "vgf2p8affineinvqb.512" => { - let [left, right, imm8] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm8] = this.check_shim(abi, CanonAbi::C, link_name, args)?; affine_transform(this, left, right, imm8, dest, /* inverse */ true)?; } // Used to implement the `_mm{, 256, 512}_gf2p8mul_epi8` functions. @@ -46,7 +47,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul "vgf2p8mulb.128" | "vgf2p8mulb.256" | "vgf2p8mulb.512" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; let (dest, dest_len) = this.project_to_simd(dest)?; diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index ac59cc2dfeb..7dee8ddd23c 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -1,11 +1,11 @@ -use rustc_abi::Size; +use rustc_abi::{CanonAbi, Size}; use rustc_apfloat::Float; use rustc_apfloat::ieee::Single; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::{mir, ty}; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use self::helpers::bool_to_simd_element; use crate::*; @@ -46,7 +46,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(EmulateItemResult::NotSupported); } - let [cb_in, a, b] = this.check_shim(abi, Conv::C, link_name, args)?; + let [cb_in, a, b] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let op = if unprefixed_name.starts_with("add") { mir::BinOp::AddWithOverflow } else { @@ -68,7 +68,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if is_u64 && this.tcx.sess.target.arch != "x86_64" { return interp_ok(EmulateItemResult::NotSupported); } - let [c_in, a, b, out] = this.check_shim(abi, Conv::C, link_name, args)?; + let [c_in, a, b, out] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let out = this.deref_pointer_as( out, if is_u64 { this.machine.layouts.u64 } else { this.machine.layouts.u32 }, @@ -85,7 +85,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // the instruction behaves like a no-op, so it is always safe to call the // intrinsic. "sse2.pause" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?; // Only exhibit the spin-loop hint behavior when SSE2 is enabled. if this.tcx.sess.unstable_target_features.contains(&Symbol::intern("sse2")) { this.yield_active_thread(); @@ -104,7 +104,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { len = 8; } - let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; pclmulqdq(this, left, right, imm, dest, len)?; } diff --git a/src/tools/miri/src/shims/x86/sha.rs b/src/tools/miri/src/shims/x86/sha.rs index 23c83553f3b..d37fad3e6c7 100644 --- a/src/tools/miri/src/shims/x86/sha.rs +++ b/src/tools/miri/src/shims/x86/sha.rs @@ -4,9 +4,10 @@ //! //! [RustCrypto's sha256 module]: https://github.com/RustCrypto/hashes/blob/6be8466247e936c415d8aafb848697f39894a386/sha2/src/sha256/soft.rs +use rustc_abi::CanonAbi; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use crate::*; @@ -52,7 +53,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match unprefixed_name { // Used to implement the _mm_sha256rnds2_epu32 function. "256rnds2" => { - let [a, b, k] = this.check_shim(abi, Conv::C, link_name, args)?; + let [a, b, k] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (a_reg, a_len) = this.project_to_simd(a)?; let (b_reg, b_len) = this.project_to_simd(b)?; @@ -73,7 +74,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Used to implement the _mm_sha256msg1_epu32 function. "256msg1" => { - let [a, b] = this.check_shim(abi, Conv::C, link_name, args)?; + let [a, b] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (a_reg, a_len) = this.project_to_simd(a)?; let (b_reg, b_len) = this.project_to_simd(b)?; @@ -91,7 +92,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Used to implement the _mm_sha256msg2_epu32 function. "256msg2" => { - let [a, b] = this.check_shim(abi, Conv::C, link_name, args)?; + let [a, b] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (a_reg, a_len) = this.project_to_simd(a)?; let (b_reg, b_len) = this.project_to_simd(b)?; diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index fd7aba2437a..1ec15d609c6 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -1,7 +1,8 @@ +use rustc_abi::CanonAbi; use rustc_apfloat::ieee::Single; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use super::{ FloatBinOp, FloatUnaryOp, bin_op_simd_float_all, bin_op_simd_float_first, unary_op_ps, @@ -33,7 +34,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Performs the operations on the first component of `left` and // `right` and copies the remaining components from `left`. "min.ss" | "max.ss" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = match unprefixed_name { "min.ss" => FloatBinOp::Min, @@ -49,7 +50,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // matches the IEEE min/max operations, while x86 has different // semantics. "min.ps" | "max.ps" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = match unprefixed_name { "min.ps" => FloatBinOp::Min, @@ -63,7 +64,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Performs the operations on the first component of `op` and // copies the remaining components from `op`. "rcp.ss" | "rsqrt.ss" => { - let [op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = match unprefixed_name { "rcp.ss" => FloatUnaryOp::Rcp, @@ -76,7 +77,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement _mm_{sqrt,rcp,rsqrt}_ps functions. // Performs the operations on all components of `op`. "rcp.ps" | "rsqrt.ps" => { - let [op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = match unprefixed_name { "rcp.ps" => FloatUnaryOp::Rcp, @@ -95,7 +96,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ss are SSE functions // with hard-coded operations. "cmp.ss" => { - let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -111,7 +112,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ps are SSE functions // with hard-coded operations. "cmp.ps" => { - let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -124,7 +125,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "comieq.ss" | "comilt.ss" | "comile.ss" | "comigt.ss" | "comige.ss" | "comineq.ss" | "ucomieq.ss" | "ucomilt.ss" | "ucomile.ss" | "ucomigt.ss" | "ucomige.ss" | "ucomineq.ss" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -152,7 +153,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cvtss_si64 and _mm_cvttss_si64 functions. // Converts the first component of `op` from f32 to i32/i64. "cvtss2si" | "cvttss2si" | "cvtss2si64" | "cvttss2si64" => { - let [op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (op, _) = this.project_to_simd(op)?; let op = this.read_immediate(&this.project_index(&op, 0)?)?; @@ -180,7 +181,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // are copied from `left`. // https://www.felixcloutier.com/x86/cvtsi2ss "cvtsi2ss" | "cvtsi642ss" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (dest, dest_len) = this.project_to_simd(dest)?; diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index e0695b7cb7b..d6052f83077 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -1,7 +1,8 @@ +use rustc_abi::CanonAbi; use rustc_apfloat::ieee::Double; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use super::{ FloatBinOp, ShiftOp, bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, @@ -40,7 +41,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // intermediate signed 32-bit integers. Horizontally add adjacent pairs of // intermediate 32-bit integers, and pack the results in `dest`. "pmadd.wd" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -78,7 +79,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sad_epu8 "psad.bw" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -116,7 +117,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is copied to remaining bits. "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q" | "psrl.q" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = match unprefixed_name { "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left, @@ -131,7 +132,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // and _mm_cvttpd_epi32 functions. // Converts packed f32/f64 to packed i32. "cvtps2dq" | "cvttps2dq" | "cvtpd2dq" | "cvttpd2dq" => { - let [op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (op_len, _) = op.layout.ty.simd_size_and_type(*this.tcx); let (dest_len, _) = dest.layout.ty.simd_size_and_type(*this.tcx); @@ -168,7 +169,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts two 16-bit integer vectors to a single 8-bit integer // vector with signed saturation. "packsswb.128" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; packsswb(this, left, right, dest)?; } @@ -176,7 +177,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts two 16-bit signed integer vectors to a single 8-bit // unsigned integer vector with saturation. "packuswb.128" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; packuswb(this, left, right, dest)?; } @@ -184,7 +185,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts two 32-bit integer vectors to a single 16-bit integer // vector with signed saturation. "packssdw.128" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; packssdw(this, left, right, dest)?; } @@ -194,7 +195,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // matches the IEEE min/max operations, while x86 has different // semantics. "min.sd" | "max.sd" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = match unprefixed_name { "min.sd" => FloatBinOp::Min, @@ -210,7 +211,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // matches the IEEE min/max operations, while x86 has different // semantics. "min.pd" | "max.pd" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = match unprefixed_name { "min.pd" => FloatBinOp::Min, @@ -229,7 +230,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_sd are SSE2 functions // with hard-coded operations. "cmp.sd" => { - let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -245,7 +246,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_pd are SSE2 functions // with hard-coded operations. "cmp.pd" => { - let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; @@ -258,7 +259,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "comieq.sd" | "comilt.sd" | "comile.sd" | "comigt.sd" | "comige.sd" | "comineq.sd" | "ucomieq.sd" | "ucomilt.sd" | "ucomile.sd" | "ucomigt.sd" | "ucomige.sd" | "ucomineq.sd" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -286,7 +287,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cvtsd_si64 and _mm_cvttsd_si64 functions. // Converts the first component of `op` from f64 to i32/i64. "cvtsd2si" | "cvttsd2si" | "cvtsd2si64" | "cvttsd2si64" => { - let [op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (op, _) = this.project_to_simd(op)?; let op = this.read_immediate(&this.project_index(&op, 0)?)?; @@ -312,7 +313,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Converts the first f64/f32 from `right` to f32/f64 and copies // the remaining elements from `left` "cvtsd2ss" | "cvtss2sd" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, _) = this.project_to_simd(right)?; diff --git a/src/tools/miri/src/shims/x86/sse3.rs b/src/tools/miri/src/shims/x86/sse3.rs index 60b7764a01e..ebf3cb5c3ee 100644 --- a/src/tools/miri/src/shims/x86/sse3.rs +++ b/src/tools/miri/src/shims/x86/sse3.rs @@ -1,7 +1,8 @@ +use rustc_abi::CanonAbi; use rustc_middle::mir; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use super::horizontal_bin_op; use crate::*; @@ -25,7 +26,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Horizontally add/subtract adjacent floating point values // in `left` and `right`. "hadd.ps" | "hadd.pd" | "hsub.ps" | "hsub.pd" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let which = match unprefixed_name { "hadd.ps" | "hadd.pd" => mir::BinOp::Add, @@ -41,7 +42,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // the data crosses a cache line, but for Miri this is just a regular // unaligned read. "ldu.dq" => { - let [src_ptr] = this.check_shim(abi, Conv::C, link_name, args)?; + let [src_ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let src_ptr = this.read_pointer(src_ptr)?; let dest = dest.force_mplace(this)?; diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs index 93d689a3044..6797039cf56 100644 --- a/src/tools/miri/src/shims/x86/sse41.rs +++ b/src/tools/miri/src/shims/x86/sse41.rs @@ -1,6 +1,7 @@ +use rustc_abi::CanonAbi; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use super::{conditional_dot_product, mpsadbw, packusdw, round_all, round_first, test_bits_masked}; use crate::*; @@ -27,7 +28,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // bits `4..=5` if `imm`, and `i`th bit specifies whether element // `i` is zeroed. "insertps" => { - let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -62,7 +63,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Concatenates two 32-bit signed integer vectors and converts // the result to a 16-bit unsigned integer vector with saturation. "packusdw" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; packusdw(this, left, right, dest)?; } @@ -72,7 +73,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // products, and conditionally stores the sum in `dest` using the low // 4 bits of `imm`. "dpps" | "dppd" => { - let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; conditional_dot_product(this, left, right, imm, dest)?; } @@ -80,14 +81,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // functions. Rounds the first element of `right` according to `rounding` // and copies the remaining elements from `left`. "round.ss" => { - let [left, right, rounding] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?; round_first::(this, left, right, rounding, dest)?; } // Used to implement the _mm_floor_ps, _mm_ceil_ps and _mm_round_ps // functions. Rounds the elements of `op` according to `rounding`. "round.ps" => { - let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?; round_all::(this, op, rounding, dest)?; } @@ -95,14 +96,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // functions. Rounds the first element of `right` according to `rounding` // and copies the remaining elements from `left`. "round.sd" => { - let [left, right, rounding] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?; round_first::(this, left, right, rounding, dest)?; } // Used to implement the _mm_floor_pd, _mm_ceil_pd and _mm_round_pd // functions. Rounds the elements of `op` according to `rounding`. "round.pd" => { - let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?; round_all::(this, op, rounding, dest)?; } @@ -110,7 +111,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Find the minimum unsinged 16-bit integer in `op` and // returns its value and position. "phminposuw" => { - let [op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (op, op_len) = this.project_to_simd(op)?; let (dest, dest_len) = this.project_to_simd(dest)?; @@ -144,7 +145,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // offsets specified in `imm`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mpsadbw_epu8 "mpsadbw" => { - let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; mpsadbw(this, left, right, imm, dest)?; } @@ -153,7 +154,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Tests `(op & mask) == 0`, `(op & mask) == mask` or // `(op & mask) != 0 && (op & mask) != mask` "ptestz" | "ptestc" | "ptestnzc" => { - let [op, mask] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (all_zero, masked_set) = test_bits_masked(this, op, mask)?; let res = match unprefixed_name { diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs index 66bff328626..830513f0291 100644 --- a/src/tools/miri/src/shims/x86/sse42.rs +++ b/src/tools/miri/src/shims/x86/sse42.rs @@ -1,9 +1,9 @@ -use rustc_abi::Size; +use rustc_abi::{CanonAbi, Size}; use rustc_middle::mir; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf as _; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use crate::*; @@ -223,7 +223,7 @@ fn deconstruct_args<'tcx>( }; if is_explicit { - let [str1, len1, str2, len2, imm] = ecx.check_shim(abi, Conv::C, link_name, args)?; + let [str1, len1, str2, len2, imm] = ecx.check_shim(abi, CanonAbi::C, link_name, args)?; let imm = ecx.read_scalar(imm)?.to_u8()?; let default_len = default_len::(imm); @@ -236,7 +236,7 @@ fn deconstruct_args<'tcx>( interp_ok((str1, str2, Some((len1, len2)), imm)) } else { - let [str1, str2, imm] = ecx.check_shim(abi, Conv::C, link_name, args)?; + let [str1, str2, imm] = ecx.check_shim(abi, CanonAbi::C, link_name, args)?; let imm = ecx.read_scalar(imm)?.to_u8()?; let array_layout = array_layout_fn(ecx, imm)?; @@ -386,7 +386,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // search for a null terminator (see `deconstruct_args` for more details). // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=924,925 "pcmpistriz128" | "pcmpistris128" => { - let [str1, str2, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [str1, str2, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let imm = this.read_scalar(imm)?.to_u8()?; let str = if unprefixed_name == "pcmpistris128" { str1 } else { str2 }; @@ -406,7 +406,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // than 16 for byte-sized operands or 8 for word-sized operands. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=1046,1047 "pcmpestriz128" | "pcmpestris128" => { - let [_, len1, _, len2, imm] = this.check_shim(abi, Conv::C, link_name, args)?; + let [_, len1, _, len2, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let len = if unprefixed_name == "pcmpestris128" { len1 } else { len2 }; let len = this.read_scalar(len)?.to_i32()?; let imm = this.read_scalar(imm)?.to_u8()?; @@ -433,7 +433,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(EmulateItemResult::NotSupported); } - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let left = this.read_scalar(left)?; let right = this.read_scalar(right)?; diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs index f3e9ac0e5dc..310d6b8f765 100644 --- a/src/tools/miri/src/shims/x86/ssse3.rs +++ b/src/tools/miri/src/shims/x86/ssse3.rs @@ -1,7 +1,8 @@ +use rustc_abi::CanonAbi; use rustc_middle::mir; use rustc_middle::ty::Ty; use rustc_span::Symbol; -use rustc_target::callconv::{Conv, FnAbi}; +use rustc_target::callconv::FnAbi; use super::{horizontal_bin_op, int_abs, pmulhrsw, psign}; use crate::*; @@ -24,7 +25,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm_abs_epi{8,16,32} functions. // Calculates the absolute value of packed 8/16/32-bit integers. "pabs.b.128" | "pabs.w.128" | "pabs.d.128" => { - let [op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?; int_abs(this, op, dest)?; } @@ -32,7 +33,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Shuffles bytes from `left` using `right` as pattern. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_shuffle_epi8 "pshuf.b.128" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -61,7 +62,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // integer values in `left` and `right`. "phadd.w.128" | "phadd.sw.128" | "phadd.d.128" | "phsub.w.128" | "phsub.sw.128" | "phsub.d.128" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (which, saturating) = match unprefixed_name { "phadd.w.128" | "phadd.d.128" => (mir::BinOp::Add, false), @@ -80,7 +81,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // produces the output at index `i`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_maddubs_epi16 "pmadd.ub.sw.128" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; let (left, left_len) = this.project_to_simd(left)?; let (right, right_len) = this.project_to_simd(right)?; @@ -115,7 +116,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // 1 and then taking the bits `1..=16`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mulhrs_epi16 "pmul.hr.sw.128" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; pmulhrsw(this, left, right, dest)?; } @@ -125,7 +126,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is writen to the corresponding output element. // Basically, we multiply `left` with `right.signum()`. "psign.b.128" | "psign.w.128" | "psign.d.128" => { - let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?; + let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?; psign(this, left, right, dest)?; } -- cgit 1.4.1-3-g733a5 From 2ad64b4c1763edf7172d3d52821c6a00c0fccff1 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 22 May 2025 20:32:03 +0200 Subject: bless test for CanonAbi::X86(SysV64) change --- tests/ui/abi/sysv64-zst.stderr | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/ui/abi/sysv64-zst.stderr b/tests/ui/abi/sysv64-zst.stderr index 59d7b004417..f91d1b5fa63 100644 --- a/tests/ui/abi/sysv64-zst.stderr +++ b/tests/ui/abi/sysv64-zst.stderr @@ -59,7 +59,9 @@ error: fn_abi_of(pass_zst) = FnAbi { }, c_variadic: false, fixed_count: 1, - conv: X86_64SysV, + conv: X86( + SysV64, + ), can_unwind: false, } --> $DIR/sysv64-zst.rs:8:1 -- cgit 1.4.1-3-g733a5 From 2351a3e5b4e323db9a8cc7d3da254f7c934558b8 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 25 May 2025 20:40:18 -0700 Subject: compiler: simplify TargetOptions ABI functions `adjust_abi` is not needed and `is_abi_supported` can be a 1-liner. --- compiler/rustc_target/src/callconv/mod.rs | 1 - compiler/rustc_target/src/spec/mod.rs | 109 +----------------------------- 2 files changed, 2 insertions(+), 108 deletions(-) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index c3ca11c2d88..d2a38b86a7a 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -697,7 +697,6 @@ impl<'a, Ty> FnAbi<'a, Ty> { "sparc" => sparc::compute_abi_info(cx, self), "sparc64" => sparc64::compute_abi_info(cx, self), "nvptx64" => { - let abi = cx.target_spec().adjust_abi(abi, self.c_variadic); if abi == ExternAbi::PtxKernel || abi == ExternAbi::GpuKernel { nvptx64::compute_ptx_kernel_abi_info(cx, self) } else { diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index c1d908fe25e..6529c2d72c8 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2915,114 +2915,9 @@ impl DerefMut for Target { } impl Target { - /// Given a function ABI, turn it into the correct ABI for this target. - pub fn adjust_abi(&self, abi: ExternAbi, c_variadic: bool) -> ExternAbi { - use ExternAbi::*; - match abi { - // On Windows, `extern "system"` behaves like msvc's `__stdcall`. - // `__stdcall` only applies on x86 and on non-variadic functions: - // https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 - System { unwind } => { - if self.is_like_windows && self.arch == "x86" && !c_variadic { - Stdcall { unwind } - } else { - C { unwind } - } - } - - EfiApi => { - if self.arch == "arm" { - Aapcs { unwind: false } - } else if self.arch == "x86_64" { - Win64 { unwind: false } - } else { - C { unwind: false } - } - } - - // See commentary in `is_abi_supported`. - Stdcall { unwind } | Thiscall { unwind } | Fastcall { unwind } => { - if self.arch == "x86" { abi } else { C { unwind } } - } - Vectorcall { unwind } => { - if ["x86", "x86_64"].contains(&&*self.arch) { - abi - } else { - C { unwind } - } - } - - // The Windows x64 calling convention we use for `extern "Rust"` - // - // expects the callee to save `xmm6` through `xmm15`, but `PreserveMost` - // (that we use by default for `extern "rust-cold"`) doesn't save any of those. - // So to avoid bloating callers, just use the Rust convention here. - RustCold if self.is_like_windows && self.arch == "x86_64" => Rust, - - abi => abi, - } - } - pub fn is_abi_supported(&self, abi: ExternAbi) -> bool { - use ExternAbi::*; - match abi { - Rust | C { .. } | System { .. } | RustCall | Unadjusted | Cdecl { .. } | RustCold => { - true - } - EfiApi => { - ["arm", "aarch64", "riscv32", "riscv64", "x86", "x86_64"].contains(&&self.arch[..]) - } - X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]), - Aapcs { .. } => "arm" == self.arch, - CCmseNonSecureCall | CCmseNonSecureEntry => { - ["thumbv8m.main-none-eabi", "thumbv8m.main-none-eabihf", "thumbv8m.base-none-eabi"] - .contains(&&self.llvm_target[..]) - } - Win64 { .. } | SysV64 { .. } => self.arch == "x86_64", - PtxKernel => self.arch == "nvptx64", - GpuKernel => ["amdgpu", "nvptx64"].contains(&&self.arch[..]), - Msp430Interrupt => self.arch == "msp430", - RiscvInterruptM | RiscvInterruptS => ["riscv32", "riscv64"].contains(&&self.arch[..]), - AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr", - Thiscall { .. } => self.arch == "x86", - // On windows these fall-back to platform native calling convention (C) when the - // architecture is not supported. - // - // This is I believe a historical accident that has occurred as part of Microsoft - // striving to allow most of the code to "just" compile when support for 64-bit x86 - // was added and then later again, when support for ARM architectures was added. - // - // This is well documented across MSDN. Support for this in Rust has been added in - // #54576. This makes much more sense in context of Microsoft's C++ than it does in - // Rust, but there isn't much leeway remaining here to change it back at the time this - // comment has been written. - // - // Following are the relevant excerpts from the MSDN documentation. - // - // > The __vectorcall calling convention is only supported in native code on x86 and - // x64 processors that include Streaming SIMD Extensions 2 (SSE2) and above. - // > ... - // > On ARM machines, __vectorcall is accepted and ignored by the compiler. - // - // -- https://docs.microsoft.com/en-us/cpp/cpp/vectorcall?view=msvc-160 - // - // > On ARM and x64 processors, __stdcall is accepted and ignored by the compiler; - // - // -- https://docs.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-160 - // - // > In most cases, keywords or compiler switches that specify an unsupported - // > convention on a particular platform are ignored, and the platform default - // > convention is used. - // - // -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions - Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } if self.is_like_windows => true, - // Outside of Windows we want to only support these calling conventions for the - // architectures for which these calling conventions are actually well defined. - Stdcall { .. } | Fastcall { .. } if self.arch == "x86" => true, - Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => true, - // Reject these calling conventions everywhere else. - Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } => false, - } + let abi_map = AbiMap::from_target(self); + abi_map.canonize_abi(abi, false).is_mapped() } /// Minimum integer size in bits that this target can perform atomic -- cgit 1.4.1-3-g733a5 From 307a18dc537fa3f5ee406f0d21c60c26bea18ec8 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 30 May 2025 13:00:21 -0700 Subject: compiler: actually remove Conv now that it is irrelevant --- compiler/rustc_smir/src/rustc_smir/convert/abi.rs | 31 +------ compiler/rustc_target/src/callconv/mod.rs | 101 ---------------------- compiler/rustc_target/src/json.rs | 32 ------- 3 files changed, 1 insertion(+), 163 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index a0c70e81fa4..06dfaf079a3 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -4,7 +4,7 @@ use rustc_abi::{ArmCall, CanonAbi, InterruptKind, X86Call}; use rustc_middle::ty; -use rustc_target::callconv::{self, Conv}; +use rustc_target::callconv; use stable_mir::abi::{ AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout, LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape, @@ -93,35 +93,6 @@ impl<'tcx> Stable<'tcx> for callconv::ArgAbi<'tcx, ty::Ty<'tcx>> { } } -impl<'tcx> Stable<'tcx> for callconv::Conv { - type T = CallConvention; - - fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { - match self { - Conv::C => CallConvention::C, - Conv::Rust => CallConvention::Rust, - Conv::Cold => CallConvention::Cold, - Conv::PreserveMost => CallConvention::PreserveMost, - Conv::PreserveAll => CallConvention::PreserveAll, - Conv::ArmAapcs => CallConvention::ArmAapcs, - Conv::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall, - Conv::CCmseNonSecureEntry => CallConvention::CCmseNonSecureEntry, - Conv::Msp430Intr => CallConvention::Msp430Intr, - Conv::X86Fastcall => CallConvention::X86Fastcall, - Conv::X86Intr => CallConvention::X86Intr, - Conv::X86Stdcall => CallConvention::X86Stdcall, - Conv::X86ThisCall => CallConvention::X86ThisCall, - Conv::X86VectorCall => CallConvention::X86VectorCall, - Conv::X86_64SysV => CallConvention::X86_64SysV, - Conv::X86_64Win64 => CallConvention::X86_64Win64, - Conv::GpuKernel => CallConvention::GpuKernel, - Conv::AvrInterrupt => CallConvention::AvrInterrupt, - Conv::AvrNonBlockingInterrupt => CallConvention::AvrNonBlockingInterrupt, - Conv::RiscvInterrupt { .. } => CallConvention::RiscvInterrupt, - } - } -} - impl<'tcx> Stable<'tcx> for CanonAbi { type T = CallConvention; diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index d2a38b86a7a..d2e49cea647 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -1,5 +1,3 @@ -use std::fmt::Display; -use std::str::FromStr; use std::{fmt, iter}; use rustc_abi::{ @@ -530,41 +528,6 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] -pub enum Conv { - // General language calling conventions, for which every target - // should have its own backend (e.g. LLVM) support. - C, - Rust, - - Cold, - PreserveMost, - PreserveAll, - - // Target-specific calling conventions. - ArmAapcs, - CCmseNonSecureCall, - CCmseNonSecureEntry, - - Msp430Intr, - - GpuKernel, - - X86Fastcall, - X86Intr, - X86Stdcall, - X86ThisCall, - X86VectorCall, - - X86_64SysV, - X86_64Win64, - - AvrInterrupt, - AvrNonBlockingInterrupt, - - RiscvInterrupt { kind: RiscvInterruptKind }, -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub enum RiscvInterruptKind { Machine, @@ -863,70 +826,6 @@ impl<'a, Ty> FnAbi<'a, Ty> { } } -impl FromStr for Conv { - type Err = String; - - fn from_str(s: &str) -> Result { - match s { - "C" => Ok(Conv::C), - "Rust" => Ok(Conv::Rust), - "RustCold" => Ok(Conv::Rust), - "ArmAapcs" => Ok(Conv::ArmAapcs), - "CCmseNonSecureCall" => Ok(Conv::CCmseNonSecureCall), - "CCmseNonSecureEntry" => Ok(Conv::CCmseNonSecureEntry), - "Msp430Intr" => Ok(Conv::Msp430Intr), - "X86Fastcall" => Ok(Conv::X86Fastcall), - "X86Intr" => Ok(Conv::X86Intr), - "X86Stdcall" => Ok(Conv::X86Stdcall), - "X86ThisCall" => Ok(Conv::X86ThisCall), - "X86VectorCall" => Ok(Conv::X86VectorCall), - "X86_64SysV" => Ok(Conv::X86_64SysV), - "X86_64Win64" => Ok(Conv::X86_64Win64), - "GpuKernel" => Ok(Conv::GpuKernel), - "AvrInterrupt" => Ok(Conv::AvrInterrupt), - "AvrNonBlockingInterrupt" => Ok(Conv::AvrNonBlockingInterrupt), - "RiscvInterrupt(machine)" => { - Ok(Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine }) - } - "RiscvInterrupt(supervisor)" => { - Ok(Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor }) - } - _ => Err(format!("'{s}' is not a valid value for entry function call convention.")), - } - } -} - -fn conv_to_externabi(conv: &Conv) -> ExternAbi { - match conv { - Conv::C => ExternAbi::C { unwind: false }, - Conv::Rust => ExternAbi::Rust, - Conv::PreserveMost => ExternAbi::RustCold, - Conv::ArmAapcs => ExternAbi::Aapcs { unwind: false }, - Conv::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall, - Conv::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry, - Conv::Msp430Intr => ExternAbi::Msp430Interrupt, - Conv::GpuKernel => ExternAbi::GpuKernel, - Conv::X86Fastcall => ExternAbi::Fastcall { unwind: false }, - Conv::X86Intr => ExternAbi::X86Interrupt, - Conv::X86Stdcall => ExternAbi::Stdcall { unwind: false }, - Conv::X86ThisCall => ExternAbi::Thiscall { unwind: false }, - Conv::X86VectorCall => ExternAbi::Vectorcall { unwind: false }, - Conv::X86_64SysV => ExternAbi::SysV64 { unwind: false }, - Conv::X86_64Win64 => ExternAbi::Win64 { unwind: false }, - Conv::AvrInterrupt => ExternAbi::AvrInterrupt, - Conv::AvrNonBlockingInterrupt => ExternAbi::AvrNonBlockingInterrupt, - Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine } => ExternAbi::RiscvInterruptM, - Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor } => ExternAbi::RiscvInterruptS, - Conv::Cold | Conv::PreserveAll => unreachable!(), - } -} - -impl Display for Conv { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", conv_to_externabi(self)) - } -} - // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs index 154a6700ce5..4fcc477921b 100644 --- a/compiler/rustc_target/src/json.rs +++ b/compiler/rustc_target/src/json.rs @@ -92,38 +92,6 @@ impl ToJson for Option { } } -impl ToJson for crate::callconv::Conv { - fn to_json(&self) -> Json { - let buf: String; - let s = match self { - Self::C => "C", - Self::Rust => "Rust", - Self::Cold => "Cold", - Self::PreserveMost => "PreserveMost", - Self::PreserveAll => "PreserveAll", - Self::ArmAapcs => "ArmAapcs", - Self::CCmseNonSecureCall => "CCmseNonSecureCall", - Self::CCmseNonSecureEntry => "CCmseNonSecureEntry", - Self::Msp430Intr => "Msp430Intr", - Self::X86Fastcall => "X86Fastcall", - Self::X86Intr => "X86Intr", - Self::X86Stdcall => "X86Stdcall", - Self::X86ThisCall => "X86ThisCall", - Self::X86VectorCall => "X86VectorCall", - Self::X86_64SysV => "X86_64SysV", - Self::X86_64Win64 => "X86_64Win64", - Self::GpuKernel => "GpuKernel", - Self::AvrInterrupt => "AvrInterrupt", - Self::AvrNonBlockingInterrupt => "AvrNonBlockingInterrupt", - Self::RiscvInterrupt { kind } => { - buf = format!("RiscvInterrupt({})", kind.as_str()); - &buf - } - }; - Json::String(s.to_owned()) - } -} - impl ToJson for TargetMetadata { fn to_json(&self) -> Json { json!({ -- cgit 1.4.1-3-g733a5 From 0479e745fbc4502eb10e69733f82021efae91c02 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 3 Jun 2025 17:29:05 +0000 Subject: Rework collect_and_apply to not rely on size hint for optimization --- compiler/rustc_type_ir/src/interner.rs | 136 ++++++++++++++++++++++----------- 1 file changed, 90 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index a9917192144..05ca6f10323 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -4,7 +4,6 @@ use std::ops::Deref; use rustc_ast_ir::Movability; use rustc_index::bit_set::DenseBitSet; -use smallvec::SmallVec; use crate::fold::TypeFoldable; use crate::inherent::*; @@ -382,28 +381,45 @@ impl CollectAndApply for T { F: FnOnce(&[T]) -> R, { // This code is hot enough that it's worth specializing for the most - // common length lists, to avoid the overhead of `SmallVec` creation. - // Lengths 0, 1, and 2 typically account for ~95% of cases. If - // `size_hint` is incorrect a panic will occur via an `unwrap` or an - // `assert`. - match iter.size_hint() { - (0, Some(0)) => { - assert!(iter.next().is_none()); - f(&[]) - } - (1, Some(1)) => { - let t0 = iter.next().unwrap(); - assert!(iter.next().is_none()); - f(&[t0]) - } - (2, Some(2)) => { - let t0 = iter.next().unwrap(); - let t1 = iter.next().unwrap(); - assert!(iter.next().is_none()); - f(&[t0, t1]) - } - _ => f(&iter.collect::>()), - } + // common length lists, to avoid the overhead of `Vec` creation. + + let Some(t0) = iter.next() else { + return f(&[]); + }; + + let Some(t1) = iter.next() else { + return f(&[t0]); + }; + + let Some(t2) = iter.next() else { + return f(&[t0, t1]); + }; + + let Some(t3) = iter.next() else { + return f(&[t0, t1, t2]); + }; + + let Some(t4) = iter.next() else { + return f(&[t0, t1, t2, t3]); + }; + + let Some(t5) = iter.next() else { + return f(&[t0, t1, t2, t3, t4]); + }; + + let Some(t6) = iter.next() else { + return f(&[t0, t1, t2, t3, t4, t5]); + }; + + let Some(t7) = iter.next() else { + return f(&[t0, t1, t2, t3, t4, t5, t6]); + }; + + let Some(t8) = iter.next() else { + return f(&[t0, t1, t2, t3, t4, t5, t6, t7]); + }; + + f(&[t0, t1, t2, t3, t4, t5, t6, t7, t8].into_iter().chain(iter).collect::>()) } } @@ -419,29 +435,57 @@ impl CollectAndApply for Result { F: FnOnce(&[T]) -> R, { // This code is hot enough that it's worth specializing for the most - // common length lists, to avoid the overhead of `SmallVec` creation. - // Lengths 0, 1, and 2 typically account for ~95% of cases. If - // `size_hint` is incorrect a panic will occur via an `unwrap` or an - // `assert`, unless a failure happens first, in which case the result - // will be an error anyway. - Ok(match iter.size_hint() { - (0, Some(0)) => { - assert!(iter.next().is_none()); - f(&[]) - } - (1, Some(1)) => { - let t0 = iter.next().unwrap()?; - assert!(iter.next().is_none()); - f(&[t0]) - } - (2, Some(2)) => { - let t0 = iter.next().unwrap()?; - let t1 = iter.next().unwrap()?; - assert!(iter.next().is_none()); - f(&[t0, t1]) - } - _ => f(&iter.collect::, _>>()?), - }) + // common length lists, to avoid the overhead of `Vec` creation. + + let Some(t0) = iter.next() else { + return Ok(f(&[])); + }; + let t0 = t0?; + + let Some(t1) = iter.next() else { + return Ok(f(&[t0])); + }; + let t1 = t1?; + + let Some(t2) = iter.next() else { + return Ok(f(&[t0, t1])); + }; + let t2 = t2?; + + let Some(t3) = iter.next() else { + return Ok(f(&[t0, t1, t2])); + }; + let t3 = t3?; + + let Some(t4) = iter.next() else { + return Ok(f(&[t0, t1, t2, t3])); + }; + let t4 = t4?; + + let Some(t5) = iter.next() else { + return Ok(f(&[t0, t1, t2, t3, t4])); + }; + let t5 = t5?; + + let Some(t6) = iter.next() else { + return Ok(f(&[t0, t1, t2, t3, t4, t5])); + }; + let t6 = t6?; + + let Some(t7) = iter.next() else { + return Ok(f(&[t0, t1, t2, t3, t4, t5, t6])); + }; + let t7 = t7?; + + let Some(t8) = iter.next() else { + return Ok(f(&[t0, t1, t2, t3, t4, t5, t6, t7])); + }; + let t8 = t8?; + + Ok(f(&[Ok(t0), Ok(t1), Ok(t2), Ok(t3), Ok(t4), Ok(t5), Ok(t6), Ok(t7), Ok(t8)] + .into_iter() + .chain(iter) + .collect::, _>>()?)) } } -- cgit 1.4.1-3-g733a5 From 5fbdfc3e1018072e0c272d19308d72ac5165f01a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Feb 2025 09:51:23 +0000 Subject: Add `iter` macro This adds an `iter!` macro that can be used to create movable generators. This also adds a yield_expr feature so the `yield` keyword can be used within iter! macro bodies. This was needed because several unstable features each need `yield` expressions, so this allows us to stabilize them separately from any individual feature. Co-authored-by: Oli Scherer Co-authored-by: Jieyou Xu Co-authored-by: Travis Cross --- compiler/rustc_ast_lowering/src/expr.rs | 15 ++--- compiler/rustc_ast_passes/src/feature_gate.rs | 7 ++- .../rustc_borrowck/src/type_check/input_output.rs | 2 +- compiler/rustc_builtin_macros/src/iter.rs | 53 ++++++++++++++++ compiler/rustc_builtin_macros/src/lib.rs | 2 + .../rustc_const_eval/src/check_consts/check.rs | 7 +-- compiler/rustc_const_eval/src/check_consts/ops.rs | 21 ++++--- compiler/rustc_hir/src/hir.rs | 11 +++- compiler/rustc_hir_typeck/src/closure.rs | 20 ++++-- compiler/rustc_parse/src/parser/stmt.rs | 2 +- compiler/rustc_trait_selection/messages.ftl | 4 +- .../error_reporting/traits/fulfillment_errors.rs | 15 +++-- compiler/rustc_trait_selection/src/errors.rs | 5 +- .../src/traits/select/candidate_assembly.rs | 22 ++++++- library/core/src/iter/mod.rs | 2 + library/core/src/iter/sources.rs | 3 + library/core/src/iter/sources/generator.rs | 29 +++++++++ src/tools/miri/tests/pass/iter_macro.rs | 22 +++++++ tests/ui/coroutine/const_gen_fn.rs | 2 + tests/ui/coroutine/const_gen_fn.stderr | 16 ++++- tests/ui/coroutine/gen_block.none.stderr | 4 +- .../feature-gate-coroutines.e2024.stderr | 8 +-- .../feature-gate-coroutines.none.stderr | 8 +-- .../feature-gates/feature-gate-yield-expr.stderr | 2 +- tests/ui/iterators/generator.rs | 24 ++++++++ tests/ui/iterators/generator_args.rs | 24 ++++++++ tests/ui/iterators/generator_capture.rs | 27 ++++++++ tests/ui/iterators/generator_capture_.rs | 26 ++++++++ tests/ui/iterators/generator_capture_.stderr | 25 ++++++++ tests/ui/iterators/generator_capture_fail.rs | 25 ++++++++ tests/ui/iterators/generator_capture_fail.stderr | 20 ++++++ tests/ui/iterators/generator_capture_fnonce.rs | 32 ++++++++++ tests/ui/iterators/generator_capture_no_lend.rs | 30 +++++++++ tests/ui/iterators/generator_returned_from_fn.rs | 63 +++++++++++++++++++ .../ui/iterators/generator_returned_from_fn.stderr | 70 +++++++++++++++++++++ ...acro-not-async-closure-simplified.narrow.stderr | 18 ++++++ .../iter-macro-not-async-closure-simplified.rs | 29 +++++++++ ...-macro-not-async-closure-simplified.wide.stderr | 17 +++++ .../iter-macro-not-async-closure.narrow.stderr | 72 ++++++++++++++++++++++ tests/ui/iterators/iter-macro-not-async-closure.rs | 32 ++++++++++ .../iterators/iter-macro-not-async-closure.stderr | 67 ++++++++++++++++++++ tests/ui/suggestions/unnamable-types.rs | 2 +- .../issue-53678-coroutine-and-const-fn.rs | 2 +- 43 files changed, 826 insertions(+), 61 deletions(-) create mode 100644 compiler/rustc_builtin_macros/src/iter.rs create mode 100644 library/core/src/iter/sources/generator.rs create mode 100644 src/tools/miri/tests/pass/iter_macro.rs create mode 100644 tests/ui/iterators/generator.rs create mode 100644 tests/ui/iterators/generator_args.rs create mode 100644 tests/ui/iterators/generator_capture.rs create mode 100644 tests/ui/iterators/generator_capture_.rs create mode 100644 tests/ui/iterators/generator_capture_.stderr create mode 100644 tests/ui/iterators/generator_capture_fail.rs create mode 100644 tests/ui/iterators/generator_capture_fail.stderr create mode 100644 tests/ui/iterators/generator_capture_fnonce.rs create mode 100644 tests/ui/iterators/generator_capture_no_lend.rs create mode 100644 tests/ui/iterators/generator_returned_from_fn.rs create mode 100644 tests/ui/iterators/generator_returned_from_fn.stderr create mode 100644 tests/ui/iterators/iter-macro-not-async-closure-simplified.narrow.stderr create mode 100644 tests/ui/iterators/iter-macro-not-async-closure-simplified.rs create mode 100644 tests/ui/iterators/iter-macro-not-async-closure-simplified.wide.stderr create mode 100644 tests/ui/iterators/iter-macro-not-async-closure.narrow.stderr create mode 100644 tests/ui/iterators/iter-macro-not-async-closure.rs create mode 100644 tests/ui/iterators/iter-macro-not-async-closure.stderr diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 9f3aed9216c..537d4a2a6af 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,4 +1,3 @@ -use std::assert_matches::assert_matches; use std::ops::ControlFlow; use std::sync::Arc; @@ -1199,11 +1198,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let closure_def_id = self.local_def_id(closure_id); let (binder_clause, generic_params) = self.lower_closure_binder(binder); - assert_matches!( - coroutine_kind, - CoroutineKind::Async { .. }, - "only async closures are supported currently" - ); + let coroutine_desugaring = match coroutine_kind { + CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async, + CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen, + CoroutineKind::AsyncGen { span, .. } => { + span_bug!(span, "only async closures and `iter!` closures are supported currently") + } + }; let body = self.with_new_scopes(fn_decl_span, |this| { let inner_decl = @@ -1247,7 +1248,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Lower this as a `CoroutineClosure`. That will ensure that HIR typeck // knows that a `FnDecl` output type like `-> &str` actually means // "coroutine that returns &str", rather than directly returning a `&str`. - kind: hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async), + kind: hir::ClosureKind::CoroutineClosure(coroutine_desugaring), constness: hir::Constness::NotConst, }); hir::ExprKind::Closure(c) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 915613a3913..3682d25d341 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -477,11 +477,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { for span in spans { if (!visitor.features.coroutines() && !span.allows_unstable(sym::coroutines)) && (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks)) + && (!visitor.features.yield_expr() && !span.allows_unstable(sym::yield_expr)) { #[allow(rustc::untranslatable_diagnostic)] - // Don't know which of the two features to include in the - // error message, so I am arbitrarily picking one. - feature_err(&visitor.sess, sym::coroutines, *span, "yield syntax is experimental") + // Emit yield_expr as the error, since that will be sufficient. You can think of it + // as coroutines and gen_blocks imply yield_expr. + feature_err(&visitor.sess, sym::yield_expr, *span, "yield syntax is experimental") .emit(); } } diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index c6b29fe36fd..0c46e0c0c22 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -52,7 +52,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { assert_matches!( self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(mir_def_id)), Some(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Closure )), "this needs to be modified if we're lowering non-async closures" diff --git a/compiler/rustc_builtin_macros/src/iter.rs b/compiler/rustc_builtin_macros/src/iter.rs new file mode 100644 index 00000000000..7ad83903a1b --- /dev/null +++ b/compiler/rustc_builtin_macros/src/iter.rs @@ -0,0 +1,53 @@ +use rustc_ast::ptr::P; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{CoroutineKind, DUMMY_NODE_ID, Expr, ast, token}; +use rustc_errors::PResult; +use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; +use rustc_span::Span; + +pub(crate) fn expand<'cx>( + cx: &'cx mut ExtCtxt<'_>, + sp: Span, + tts: TokenStream, +) -> MacroExpanderResult<'cx> { + let closure = match parse_closure(cx, sp, tts) { + Ok(parsed) => parsed, + Err(err) => { + return ExpandResult::Ready(DummyResult::any(sp, err.emit())); + } + }; + + ExpandResult::Ready(base::MacEager::expr(closure)) +} + +fn parse_closure<'a>( + cx: &mut ExtCtxt<'a>, + span: Span, + stream: TokenStream, +) -> PResult<'a, P> { + let mut closure_parser = cx.new_parser_from_tts(stream); + + let coroutine_kind = Some(CoroutineKind::Gen { + span, + closure_id: DUMMY_NODE_ID, + return_impl_trait_id: DUMMY_NODE_ID, + }); + + let mut closure = closure_parser.parse_expr()?; + match &mut closure.kind { + ast::ExprKind::Closure(c) => { + if let Some(kind) = c.coroutine_kind { + cx.dcx().span_err(kind.span(), "only plain closures allowed in `iter!`"); + } + c.coroutine_kind = coroutine_kind; + if closure_parser.token != token::Eof { + closure_parser.unexpected()?; + } + Ok(closure) + } + _ => { + cx.dcx().span_err(closure.span, "`iter!` body must be a closure"); + Err(closure_parser.unexpected().unwrap_err()) + } + } +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 667d90429f2..aa52c3bd281 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -47,6 +47,7 @@ mod errors; mod format; mod format_foreign; mod global_allocator; +mod iter; mod log_syntax; mod pattern_type; mod source_util; @@ -95,6 +96,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { include: source_util::expand_include, include_bytes: source_util::expand_include_bytes, include_str: source_util::expand_include_str, + iter: iter::expand, line: source_util::expand_line, log_syntax: log_syntax::expand_log_syntax, module_path: source_util::expand_mod, diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index b67a3ce03a9..6167f8cd4b5 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -589,12 +589,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Aggregate(kind, ..) => { if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref() - && let Some( - coroutine_kind @ hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - _, - ), - ) = self.tcx.coroutine_kind(def_id) + && let Some(coroutine_kind) = self.tcx.coroutine_kind(def_id) { self.check_op(ops::Coroutine(coroutine_kind)); } diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 177ba56b165..d701646719a 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -486,24 +486,25 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable { pub(crate) struct Coroutine(pub hir::CoroutineKind); impl<'tcx> NonConstOp<'tcx> for Coroutine { fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - if let hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Block, - ) = self.0 - { - Status::Unstable { + match self.0 { + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Block, + ) + // FIXME(coroutines): eventually we want to gate const coroutine coroutines behind a + // different feature. + | hir::CoroutineKind::Coroutine(_) => Status::Unstable { gate: sym::const_async_blocks, gate_already_checked: false, safe_to_expose_on_stable: false, is_function_call: false, - } - } else { - Status::Forbidden + }, + _ => Status::Forbidden, } } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind()); + let msg = format!("{} are not allowed in {}s", self.0.to_plural_string(), ccx.const_kind()); if let Status::Unstable { gate, .. } = self.status_in_item(ccx) { ccx.tcx.sess.create_feature_err(errors::UnallowedOpInConstContext { span, msg }, gate) } else { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4f05e1c816c..433d5f98829 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2061,12 +2061,19 @@ impl CoroutineKind { CoroutineKind::Coroutine(mov) => mov, } } -} -impl CoroutineKind { pub fn is_fn_like(self) -> bool { matches!(self, CoroutineKind::Desugared(_, CoroutineSource::Fn)) } + + pub fn to_plural_string(&self) -> String { + match self { + CoroutineKind::Desugared(d, CoroutineSource::Fn) => format!("{d:#}fn bodies"), + CoroutineKind::Desugared(d, CoroutineSource::Block) => format!("{d:#}blocks"), + CoroutineKind::Desugared(d, CoroutineSource::Closure) => format!("{d:#}closure bodies"), + CoroutineKind::Coroutine(_) => "coroutines".to_string(), + } + } } impl fmt::Display for CoroutineKind { diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index b1cb3ef4d79..cd3746be1d1 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -204,14 +204,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } hir::ClosureKind::CoroutineClosure(kind) => { - // async closures always return the type ascribed after the `->` (if present), - // and yield `()`. let (bound_return_ty, bound_yield_ty) = match kind { + hir::CoroutineDesugaring::Gen => { + // `iter!` closures always return unit and yield the `Iterator::Item` type + // that we have to infer. + (tcx.types.unit, self.infcx.next_ty_var(expr_span)) + } hir::CoroutineDesugaring::Async => { + // async closures always return the type ascribed after the `->` (if present), + // and yield `()`. (bound_sig.skip_binder().output(), tcx.types.unit) } - hir::CoroutineDesugaring::Gen | hir::CoroutineDesugaring::AsyncGen => { - todo!("`gen` and `async gen` closures not supported yet") + hir::CoroutineDesugaring::AsyncGen => { + todo!("`async gen` closures not supported yet") } }; // Compute all of the variables that will be used to populate the coroutine. @@ -465,7 +470,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(trait_def_id) = trait_def_id { let found_kind = match closure_kind { - hir::ClosureKind::Closure => self.tcx.fn_trait_kind_from_def_id(trait_def_id), + hir::ClosureKind::Closure + // FIXME(iter_macro): Someday we'll probably want iterator closures instead of + // just using Fn* for iterators. + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => { + self.tcx.fn_trait_kind_from_def_id(trait_def_id) + } hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => self .tcx .async_fn_trait_kind_from_def_id(trait_def_id) diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index ccc3410674b..c37cb0881c3 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -713,7 +713,7 @@ impl<'a> Parser<'a> { /// Parses the rest of a block expression or function body. /// Precondition: already parsed the '{'. - pub(crate) fn parse_block_tail( + pub fn parse_block_tail( &mut self, lo: Span, s: BlockCheckMode, diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 9b949a0a795..8232da4df43 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -72,8 +72,6 @@ trait_selection_adjust_signature_remove_borrow = consider adjusting the signatur trait_selection_ascribe_user_type_prove_predicate = ...so that the where clause holds -trait_selection_async_closure_not_fn = async closure does not implement `{$kind}` because it captures state from its environment - trait_selection_await_both_futures = consider `await`ing on both `Future`s trait_selection_await_future = consider `await`ing on the `Future` trait_selection_await_note = calling an async function returns a future @@ -123,6 +121,8 @@ trait_selection_closure_kind_requirement = the requirement to implement `{$trait trait_selection_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait trait_selection_consider_specifying_length = consider specifying the actual array length +trait_selection_coro_closure_not_fn = {$coro_kind}closure does not implement `{$kind}` because it captures state from its environment + trait_selection_data_flows = ...but data{$label_var1_exists -> [true] {" "}from `{$label_var1}` *[false] {""} diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 9b5e421e0e4..fc5be111144 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -42,9 +42,7 @@ use super::{ use crate::error_reporting::TypeErrCtxt; use crate::error_reporting::infer::TyCategory; use crate::error_reporting::traits::report_dyn_incompatibility; -use crate::errors::{ - AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, -}; +use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, CoroClosureNotFn}; use crate::infer::{self, InferCtxt, InferCtxtExt as _}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::{ @@ -886,9 +884,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // is unimplemented is because async closures don't implement `Fn`/`FnMut` // if they have captures. if has_self_borrows && expected_kind != ty::ClosureKind::FnOnce { - let mut err = self.dcx().create_err(AsyncClosureNotFn { + let coro_kind = match self + .tcx + .coroutine_kind(self.tcx.coroutine_for_closure(closure_def_id)) + .unwrap() + { + rustc_hir::CoroutineKind::Desugared(desugaring, _) => desugaring.to_string(), + coro => coro.to_string(), + }; + let mut err = self.dcx().create_err(CoroClosureNotFn { span: self.tcx.def_span(closure_def_id), kind: expected_kind.as_str(), + coro_kind, }); self.note_obligation_cause(&mut err, &obligation); return Some(err.emit()); diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 779c861637a..0bea308ed5c 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -201,11 +201,12 @@ pub struct ClosureFnMutLabel { } #[derive(Diagnostic)] -#[diag(trait_selection_async_closure_not_fn)] -pub(crate) struct AsyncClosureNotFn { +#[diag(trait_selection_coro_closure_not_fn)] +pub(crate) struct CoroClosureNotFn { #[primary_span] pub span: Span, pub kind: &'static str, + pub coro_kind: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 7d869b27445..97ecf9702e6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -11,7 +11,7 @@ use std::ops::ControlFlow; use hir::LangItem; use hir::def_id::DefId; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; -use rustc_hir as hir; +use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind}; use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode, elaborate}; @@ -438,6 +438,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + #[instrument(level = "debug", skip(self, candidates))] fn assemble_async_closure_candidates( &mut self, obligation: &PolyTraitObligation<'tcx>, @@ -446,15 +447,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let goal_kind = self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap(); + debug!("self_ty = {:?}", obligation.self_ty().skip_binder().kind()); match *obligation.self_ty().skip_binder().kind() { - ty::CoroutineClosure(_, args) => { + ty::CoroutineClosure(def_id, args) => { if let Some(closure_kind) = args.as_coroutine_closure().kind_ty().to_opt_closure_kind() && !closure_kind.extends(goal_kind) { return; } - candidates.vec.push(AsyncClosureCandidate); + + // Make sure this is actually an async closure. + let Some(coroutine_kind) = + self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(def_id)) + else { + bug!("coroutine with no kind"); + }; + + debug!(?coroutine_kind); + match coroutine_kind { + CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { + candidates.vec.push(AsyncClosureCandidate); + } + _ => (), + } } // Closures and fn pointers implement `AsyncFn*` if their return types // implement `Future`, which is checked later. diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index d62a445d704..b85841295da 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -420,6 +420,8 @@ pub use self::adapters::{Intersperse, IntersperseWith}; issue = "42168" )] pub use self::range::Step; +#[unstable(feature = "iter_macro", issue = "none", reason = "generators are unstable")] +pub use self::sources::iter; #[stable(feature = "iter_empty", since = "1.2.0")] pub use self::sources::{Empty, empty}; #[unstable( diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs index 1eb4367b183..fd9330201ff 100644 --- a/library/core/src/iter/sources.rs +++ b/library/core/src/iter/sources.rs @@ -1,6 +1,7 @@ mod empty; mod from_coroutine; mod from_fn; +mod generator; mod once; mod once_with; mod repeat; @@ -18,6 +19,8 @@ pub use self::empty::{Empty, empty}; pub use self::from_coroutine::{FromCoroutine, from_coroutine}; #[stable(feature = "iter_from_fn", since = "1.34.0")] pub use self::from_fn::{FromFn, from_fn}; +#[unstable(feature = "iter_macro", issue = "none", reason = "generators are unstable")] +pub use self::generator::iter; #[stable(feature = "iter_once", since = "1.2.0")] pub use self::once::{Once, once}; #[stable(feature = "iter_once_with", since = "1.43.0")] diff --git a/library/core/src/iter/sources/generator.rs b/library/core/src/iter/sources/generator.rs new file mode 100644 index 00000000000..c94232e09eb --- /dev/null +++ b/library/core/src/iter/sources/generator.rs @@ -0,0 +1,29 @@ +/// Creates a new closure that returns an iterator where each iteration steps the given +/// generator to the next `yield` statement. +/// +/// Similar to [`iter::from_fn`], but allows arbitrary control flow. +/// +/// [`iter::from_fn`]: crate::iter::from_fn +/// +/// # Examples +/// +/// ``` +/// #![feature(iter_macro, coroutines)] +/// # #[cfg(not(bootstrap))] +/// # { +/// +/// let it = std::iter::iter!{|| { +/// yield 1; +/// yield 2; +/// yield 3; +/// } }(); +/// let v: Vec<_> = it.collect(); +/// assert_eq!(v, [1, 2, 3]); +/// # } +/// ``` +#[unstable(feature = "iter_macro", issue = "none", reason = "generators are unstable")] +#[allow_internal_unstable(coroutines, iter_from_coroutine)] +#[cfg_attr(not(bootstrap), rustc_builtin_macro)] +pub macro iter($($t:tt)*) { + /* compiler-builtin */ +} diff --git a/src/tools/miri/tests/pass/iter_macro.rs b/src/tools/miri/tests/pass/iter_macro.rs new file mode 100644 index 00000000000..367c13f9969 --- /dev/null +++ b/src/tools/miri/tests/pass/iter_macro.rs @@ -0,0 +1,22 @@ +#![feature(iter_macro, yield_expr)] + +use std::iter::iter; + +fn main() { + let i = iter! { || { + yield 0; + for x in 5..10 { + yield x * 2; + } + } }; + let mut i = i(); + assert_eq!(i.next(), Some(0)); + assert_eq!(i.next(), Some(10)); + assert_eq!(i.next(), Some(12)); + assert_eq!(i.next(), Some(14)); + assert_eq!(i.next(), Some(16)); + assert_eq!(i.next(), Some(18)); + assert_eq!(i.next(), None); + assert_eq!(i.next(), None); + assert_eq!(i.next(), None); +} diff --git a/tests/ui/coroutine/const_gen_fn.rs b/tests/ui/coroutine/const_gen_fn.rs index 2701139ffed..b044c185e0f 100644 --- a/tests/ui/coroutine/const_gen_fn.rs +++ b/tests/ui/coroutine/const_gen_fn.rs @@ -4,8 +4,10 @@ const gen fn a() {} //~^ ERROR functions cannot be both `const` and `gen` +//~^^ ERROR `gen` fn bodies are not allowed in constant functions const async gen fn b() {} //~^ ERROR functions cannot be both `const` and `async gen` +//~^^ ERROR `async gen` fn bodies are not allowed in constant functions fn main() {} diff --git a/tests/ui/coroutine/const_gen_fn.stderr b/tests/ui/coroutine/const_gen_fn.stderr index 4f3c73d1678..400ee216d06 100644 --- a/tests/ui/coroutine/const_gen_fn.stderr +++ b/tests/ui/coroutine/const_gen_fn.stderr @@ -8,7 +8,7 @@ LL | const gen fn a() {} | `const` because of this error: functions cannot be both `const` and `async gen` - --> $DIR/const_gen_fn.rs:8:1 + --> $DIR/const_gen_fn.rs:9:1 | LL | const async gen fn b() {} | ^^^^^-^^^^^^^^^---------- @@ -16,5 +16,17 @@ LL | const async gen fn b() {} | | `async gen` because of this | `const` because of this -error: aborting due to 2 previous errors +error: `gen` fn bodies are not allowed in constant functions + --> $DIR/const_gen_fn.rs:5:18 + | +LL | const gen fn a() {} + | ^^ + +error: `async gen` fn bodies are not allowed in constant functions + --> $DIR/const_gen_fn.rs:9:24 + | +LL | const async gen fn b() {} + | ^^ + +error: aborting due to 4 previous errors diff --git a/tests/ui/coroutine/gen_block.none.stderr b/tests/ui/coroutine/gen_block.none.stderr index ed744f2957a..b793033b521 100644 --- a/tests/ui/coroutine/gen_block.none.stderr +++ b/tests/ui/coroutine/gen_block.none.stderr @@ -31,7 +31,7 @@ LL | let _ = || yield true; | ^^^^^^^^^^ | = note: see issue #43122 for more information - = help: add `#![feature(coroutines)]` to the crate attributes to enable + = help: add `#![feature(yield_expr)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental @@ -41,7 +41,7 @@ LL | let _ = #[coroutine] || yield true; | ^^^^^^^^^^ | = note: see issue #43122 for more information - = help: add `#![feature(coroutines)]` to the crate attributes to enable + = help: add `#![feature(yield_expr)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `#[coroutine]` attribute is an experimental feature diff --git a/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr b/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr index 381e7a210be..c29c328ac14 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr +++ b/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr @@ -5,7 +5,7 @@ LL | yield true; | ^^^^^^^^^^ | = note: see issue #43122 for more information - = help: add `#![feature(coroutines)]` to the crate attributes to enable + = help: add `#![feature(yield_expr)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental @@ -15,7 +15,7 @@ LL | let _ = || yield true; | ^^^^^^^^^^ | = note: see issue #43122 for more information - = help: add `#![feature(coroutines)]` to the crate attributes to enable + = help: add `#![feature(yield_expr)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental @@ -25,7 +25,7 @@ LL | yield; | ^^^^^ | = note: see issue #43122 for more information - = help: add `#![feature(coroutines)]` to the crate attributes to enable + = help: add `#![feature(yield_expr)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental @@ -35,7 +35,7 @@ LL | yield 0; | ^^^^^^^ | = note: see issue #43122 for more information - = help: add `#![feature(coroutines)]` to the crate attributes to enable + = help: add `#![feature(yield_expr)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental diff --git a/tests/ui/feature-gates/feature-gate-coroutines.none.stderr b/tests/ui/feature-gates/feature-gate-coroutines.none.stderr index 381e7a210be..c29c328ac14 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.none.stderr +++ b/tests/ui/feature-gates/feature-gate-coroutines.none.stderr @@ -5,7 +5,7 @@ LL | yield true; | ^^^^^^^^^^ | = note: see issue #43122 for more information - = help: add `#![feature(coroutines)]` to the crate attributes to enable + = help: add `#![feature(yield_expr)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental @@ -15,7 +15,7 @@ LL | let _ = || yield true; | ^^^^^^^^^^ | = note: see issue #43122 for more information - = help: add `#![feature(coroutines)]` to the crate attributes to enable + = help: add `#![feature(yield_expr)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental @@ -25,7 +25,7 @@ LL | yield; | ^^^^^ | = note: see issue #43122 for more information - = help: add `#![feature(coroutines)]` to the crate attributes to enable + = help: add `#![feature(yield_expr)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental @@ -35,7 +35,7 @@ LL | yield 0; | ^^^^^^^ | = note: see issue #43122 for more information - = help: add `#![feature(coroutines)]` to the crate attributes to enable + = help: add `#![feature(yield_expr)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental diff --git a/tests/ui/feature-gates/feature-gate-yield-expr.stderr b/tests/ui/feature-gates/feature-gate-yield-expr.stderr index ad8a15a0f36..bfac9e49803 100644 --- a/tests/ui/feature-gates/feature-gate-yield-expr.stderr +++ b/tests/ui/feature-gates/feature-gate-yield-expr.stderr @@ -5,7 +5,7 @@ LL | yield (); | ^^^^^^^^ | = note: see issue #43122 for more information - = help: add `#![feature(coroutines)]` to the crate attributes to enable + = help: add `#![feature(yield_expr)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental diff --git a/tests/ui/iterators/generator.rs b/tests/ui/iterators/generator.rs new file mode 100644 index 00000000000..e633efb11c1 --- /dev/null +++ b/tests/ui/iterators/generator.rs @@ -0,0 +1,24 @@ +//@ run-pass + +#![feature(iter_macro, yield_expr)] + +use std::iter::iter; + +fn main() { + let i = iter! { || { + yield 0; + for x in 5..10 { + yield x * 2; + } + } }; + let mut i = i(); + assert_eq!(i.next(), Some(0)); + assert_eq!(i.next(), Some(10)); + assert_eq!(i.next(), Some(12)); + assert_eq!(i.next(), Some(14)); + assert_eq!(i.next(), Some(16)); + assert_eq!(i.next(), Some(18)); + assert_eq!(i.next(), None); + assert_eq!(i.next(), None); + assert_eq!(i.next(), None); +} diff --git a/tests/ui/iterators/generator_args.rs b/tests/ui/iterators/generator_args.rs new file mode 100644 index 00000000000..c9da9e5fba6 --- /dev/null +++ b/tests/ui/iterators/generator_args.rs @@ -0,0 +1,24 @@ +//@ run-pass + +#![feature(iter_macro, yield_expr)] + +use std::iter::iter; + +fn main() { + let i = iter! {|foo| { + yield foo; + for x in 5..10 { + yield x * 2; + } + }}; + let mut i = i(3); + assert_eq!(i.next(), Some(3)); + assert_eq!(i.next(), Some(10)); + assert_eq!(i.next(), Some(12)); + assert_eq!(i.next(), Some(14)); + assert_eq!(i.next(), Some(16)); + assert_eq!(i.next(), Some(18)); + assert_eq!(i.next(), None); + assert_eq!(i.next(), None); + assert_eq!(i.next(), None); +} diff --git a/tests/ui/iterators/generator_capture.rs b/tests/ui/iterators/generator_capture.rs new file mode 100644 index 00000000000..c790b7a4b96 --- /dev/null +++ b/tests/ui/iterators/generator_capture.rs @@ -0,0 +1,27 @@ +//@ run-pass + +#![feature(iter_macro, yield_expr)] + +use std::iter::iter; + +fn main() { + let i = { + let s = String::new(); + iter! { move || { + yield s.len(); + for x in 5..10 { + yield x * 2; + } + }} + }; + let mut i = i(); + assert_eq!(i.next(), Some(0)); + assert_eq!(i.next(), Some(10)); + assert_eq!(i.next(), Some(12)); + assert_eq!(i.next(), Some(14)); + assert_eq!(i.next(), Some(16)); + assert_eq!(i.next(), Some(18)); + assert_eq!(i.next(), None); + assert_eq!(i.next(), None); + assert_eq!(i.next(), None); +} diff --git a/tests/ui/iterators/generator_capture_.rs b/tests/ui/iterators/generator_capture_.rs new file mode 100644 index 00000000000..f630bc64b97 --- /dev/null +++ b/tests/ui/iterators/generator_capture_.rs @@ -0,0 +1,26 @@ +// This test exercises lending behavior for iterator closures which is not yet supported. + +#![feature(iter_macro, yield_expr)] + +use std::iter::iter; + +fn main() { + let f = { + let s = "foo".to_string(); + iter! { move || { + for c in s.chars() { + yield c; + } + }} + }; + let mut i = f(); + assert_eq!(i.next(), Some('f')); + assert_eq!(i.next(), Some('o')); + assert_eq!(i.next(), Some('o')); + assert_eq!(i.next(), None); + let mut i = f(); //~ ERROR use of moved value: `f` + assert_eq!(i.next(), Some('f')); + assert_eq!(i.next(), Some('o')); + assert_eq!(i.next(), Some('o')); + assert_eq!(i.next(), None); +} diff --git a/tests/ui/iterators/generator_capture_.stderr b/tests/ui/iterators/generator_capture_.stderr new file mode 100644 index 00000000000..3d9647ae16f --- /dev/null +++ b/tests/ui/iterators/generator_capture_.stderr @@ -0,0 +1,25 @@ +error[E0382]: use of moved value: `f` + --> $DIR/generator_capture_.rs:21:17 + | +LL | let f = { + | - move occurs because `f` has type `{gen closure@$DIR/generator_capture_.rs:10:17: 10:24}`, which does not implement the `Copy` trait +... +LL | let mut i = f(); + | --- `f` moved due to this call +... +LL | let mut i = f(); + | ^ value used here after move + | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/generator_capture_.rs:16:17 + | +LL | let mut i = f(); + | ^ +help: consider cloning the value if the performance cost is acceptable + | +LL | let mut i = f.clone()(); + | ++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/iterators/generator_capture_fail.rs b/tests/ui/iterators/generator_capture_fail.rs new file mode 100644 index 00000000000..d987b2df011 --- /dev/null +++ b/tests/ui/iterators/generator_capture_fail.rs @@ -0,0 +1,25 @@ +#![feature(iter_macro, yield_expr)] + +use std::iter::iter; + +fn main() { + let i = { + let s = String::new(); + iter! { || { //~ ERROR `s` does not live long enough + yield s.len(); + for x in 5..10 { + yield x * 2; + } + } } + }; + let mut i = i(); + assert_eq!(i.next(), Some(0)); + assert_eq!(i.next(), Some(10)); + assert_eq!(i.next(), Some(12)); + assert_eq!(i.next(), Some(14)); + assert_eq!(i.next(), Some(16)); + assert_eq!(i.next(), Some(18)); + assert_eq!(i.next(), None); + assert_eq!(i.next(), None); + assert_eq!(i.next(), None); +} diff --git a/tests/ui/iterators/generator_capture_fail.stderr b/tests/ui/iterators/generator_capture_fail.stderr new file mode 100644 index 00000000000..225a385d6a0 --- /dev/null +++ b/tests/ui/iterators/generator_capture_fail.stderr @@ -0,0 +1,20 @@ +error[E0597]: `s` does not live long enough + --> $DIR/generator_capture_fail.rs:8:17 + | +LL | let i = { + | - borrow later stored here +LL | let s = String::new(); +LL | iter! { || { + | _________________^ +LL | | yield s.len(); +LL | | for x in 5..10 { +LL | | yield x * 2; +LL | | } +LL | | } } + | |_________^ borrowed value does not live long enough +LL | }; + | - `s` dropped here while still borrowed + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/iterators/generator_capture_fnonce.rs b/tests/ui/iterators/generator_capture_fnonce.rs new file mode 100644 index 00000000000..090727eb9b7 --- /dev/null +++ b/tests/ui/iterators/generator_capture_fnonce.rs @@ -0,0 +1,32 @@ +//@ run-pass + +#![feature(iter_macro, yield_expr)] + +use std::iter::iter; + +fn main() { + let i = { + let s = String::new(); + iter! { move || { + yield s.len(); + for x in 5..10 { + yield x * 2; + } + }} + }; + test_iterator(i); +} + +/// Exercise the iterator in a separate function to ensure it's not capturing anything it shoudln't. +fn test_iterator>(i: impl FnOnce() -> I) { + let mut i = i(); + assert_eq!(i.next(), Some(0)); + assert_eq!(i.next(), Some(10)); + assert_eq!(i.next(), Some(12)); + assert_eq!(i.next(), Some(14)); + assert_eq!(i.next(), Some(16)); + assert_eq!(i.next(), Some(18)); + assert_eq!(i.next(), None); + assert_eq!(i.next(), None); + assert_eq!(i.next(), None); +} diff --git a/tests/ui/iterators/generator_capture_no_lend.rs b/tests/ui/iterators/generator_capture_no_lend.rs new file mode 100644 index 00000000000..822db58d48d --- /dev/null +++ b/tests/ui/iterators/generator_capture_no_lend.rs @@ -0,0 +1,30 @@ +//@ run-pass + +#![feature(iter_macro, yield_expr)] + +// This test creates an iterator that captures a reference and ensure that doesn't force the +// iterator to become lending. + +use std::iter::iter; + +fn main() { + let s = "foo".to_string(); + let f = iter! { || { + for c in s.chars() { + yield c; + } + }}; + + let mut i = f(); + let mut j = f(); + + assert_eq!(i.next(), Some('f')); + assert_eq!(i.next(), Some('o')); + assert_eq!(i.next(), Some('o')); + assert_eq!(i.next(), None); + + assert_eq!(j.next(), Some('f')); + assert_eq!(j.next(), Some('o')); + assert_eq!(j.next(), Some('o')); + assert_eq!(j.next(), None); +} diff --git a/tests/ui/iterators/generator_returned_from_fn.rs b/tests/ui/iterators/generator_returned_from_fn.rs new file mode 100644 index 00000000000..bd0317b1ffb --- /dev/null +++ b/tests/ui/iterators/generator_returned_from_fn.rs @@ -0,0 +1,63 @@ +#![feature(iter_macro, impl_trait_in_fn_trait_return, yield_expr)] + +use std::iter::iter; + +fn plain() -> impl Fn() -> impl Iterator { + iter! { || { + yield 0; + for x in 5..10 { + yield x * 2; + } + } } +} + +fn arg() -> impl Fn(u32) -> impl Iterator { + iter! { |arg| { + yield arg; + for x in 5..10 { + yield x * 2; + } + } } +} + +fn capture<'a>(a: &'a u32) -> impl Fn() -> (impl Iterator + 'a) { + iter! { || { //~ ERROR cannot return reference to function parameter `a` + yield *a; + for x in 5..10 { + yield x * 2; + } + } } +} + +fn capture_move(a: &u32) -> impl Fn() -> impl Iterator { + iter! { move || { //~ ERROR does not implement `Fn` because it captures + yield *a; + for x in 5..10 { + yield x * 2; + } + } } +} + +fn capture_move_once(a: &u32) -> impl FnOnce() -> impl Iterator { + iter! { move || { + //~^ ERROR captures lifetime + //~| ERROR: captures lifetime + yield *a; + for x in 5..10 { + yield x * 2; + } + } } +} + +fn capture_move_once_lifetimes<'a>( + a: &'a u32, +) -> impl FnOnce() -> (impl Iterator + 'a) { + iter! { move || { + yield *a; + for x in 5..10 { + yield x * 2; + } + } } +} + +fn main() {} diff --git a/tests/ui/iterators/generator_returned_from_fn.stderr b/tests/ui/iterators/generator_returned_from_fn.stderr new file mode 100644 index 00000000000..b2324af6d5e --- /dev/null +++ b/tests/ui/iterators/generator_returned_from_fn.stderr @@ -0,0 +1,70 @@ +error[E0515]: cannot return reference to function parameter `a` + --> $DIR/generator_returned_from_fn.rs:24:13 + | +LL | iter! { || { + | _____________^ +LL | | yield *a; +LL | | for x in 5..10 { +LL | | yield x * 2; +LL | | } +LL | | } } + | |_____^ returns a reference to data owned by the current function + +error: gen closure does not implement `Fn` because it captures state from its environment + --> $DIR/generator_returned_from_fn.rs:33:13 + | +LL | iter! { move || { + | _____________-^^^^^^ +LL | | yield *a; +LL | | for x in 5..10 { +LL | | yield x * 2; +LL | | } +LL | | } } + | |_____- return type was inferred to be `{gen closure@$DIR/generator_returned_from_fn.rs:33:13: 33:20}` here + +error[E0700]: hidden type for `impl FnOnce() -> impl Iterator` captures lifetime that does not appear in bounds + --> $DIR/generator_returned_from_fn.rs:42:13 + | +LL | fn capture_move_once(a: &u32) -> impl FnOnce() -> impl Iterator { + | ---- ------------------------------------------ opaque type defined here + | | + | hidden type `{gen closure@$DIR/generator_returned_from_fn.rs:42:13: 42:20}` captures the anonymous lifetime defined here +LL | iter! { move || { + | _____________^ +LL | | +LL | | +LL | | yield *a; +... | +LL | | } } + | |_____^ + | +help: add a `use<...>` bound to explicitly capture `'_` + | +LL | fn capture_move_once(a: &u32) -> impl FnOnce() -> impl Iterator + use<'_> { + | +++++++++ + +error[E0700]: hidden type for `impl Iterator` captures lifetime that does not appear in bounds + --> $DIR/generator_returned_from_fn.rs:42:13 + | +LL | fn capture_move_once(a: &u32) -> impl FnOnce() -> impl Iterator { + | ---- ------------------------- opaque type defined here + | | + | hidden type `{gen closure body@$DIR/generator_returned_from_fn.rs:42:21: 49:6}` captures the anonymous lifetime defined here +LL | iter! { move || { + | _____________^ +LL | | +LL | | +LL | | yield *a; +... | +LL | | } } + | |_____^ + | +help: add a `use<...>` bound to explicitly capture `'_` + | +LL | fn capture_move_once(a: &u32) -> impl FnOnce() -> impl Iterator + use<'_> { + | +++++++++ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0515, E0700. +For more information about an error, try `rustc --explain E0515`. diff --git a/tests/ui/iterators/iter-macro-not-async-closure-simplified.narrow.stderr b/tests/ui/iterators/iter-macro-not-async-closure-simplified.narrow.stderr new file mode 100644 index 00000000000..4e0dabade2d --- /dev/null +++ b/tests/ui/iterators/iter-macro-not-async-closure-simplified.narrow.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure-simplified.rs:21:21: 21:28}: AsyncFnOnce()` is not satisfied + --> $DIR/iter-macro-not-async-closure-simplified.rs:27:21 + | +LL | call_async_once(f); + | --------------- ^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | + = help: the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure-simplified.rs:21:21: 21:28}` +note: required by a bound in `call_async_once` + --> $DIR/iter-macro-not-async-closure-simplified.rs:18:28 + | +LL | ...pl AsyncFnOnce()) {} + | ^^^^^^^^^^^^^ required by this bound in `call_async_once` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/iterators/iter-macro-not-async-closure-simplified.rs b/tests/ui/iterators/iter-macro-not-async-closure-simplified.rs new file mode 100644 index 00000000000..4fa14fda661 --- /dev/null +++ b/tests/ui/iterators/iter-macro-not-async-closure-simplified.rs @@ -0,0 +1,29 @@ +// This test ensures iterators created with the `iter!` macro are not +// accidentally async closures. +// +// We test this both in a `narrow` and `wide` configuration because +// the way that the diagnostic is emitted varies depending on the +// diagnostic width. If it's too narrow to fit the explanation, that +// explanation is moved to the `help` instead of the span label. +// +//@ edition: 2024 +//@ revisions: narrow wide +//@[narrow] compile-flags: --diagnostic-width=20 +//@[wide] compile-flags: --diagnostic-width=300 + +#![feature(yield_expr, iter_macro)] + +use std::iter::iter; + +fn call_async_once(_: impl AsyncFnOnce()) {} + +fn main() { + let f = iter! { move || { + for i in 0..10 { + yield i; + } + }}; + + call_async_once(f); + //~^ ERROR AsyncFnOnce()` is not satisfied +} diff --git a/tests/ui/iterators/iter-macro-not-async-closure-simplified.wide.stderr b/tests/ui/iterators/iter-macro-not-async-closure-simplified.wide.stderr new file mode 100644 index 00000000000..a6c239c181b --- /dev/null +++ b/tests/ui/iterators/iter-macro-not-async-closure-simplified.wide.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure-simplified.rs:21:21: 21:28}: AsyncFnOnce()` is not satisfied + --> $DIR/iter-macro-not-async-closure-simplified.rs:27:21 + | +LL | call_async_once(f); + | --------------- ^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure-simplified.rs:21:21: 21:28}` + | | + | required by a bound introduced by this call + | +note: required by a bound in `call_async_once` + --> $DIR/iter-macro-not-async-closure-simplified.rs:18:28 + | +LL | fn call_async_once(_: impl AsyncFnOnce()) {} + | ^^^^^^^^^^^^^ required by this bound in `call_async_once` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/iterators/iter-macro-not-async-closure.narrow.stderr b/tests/ui/iterators/iter-macro-not-async-closure.narrow.stderr new file mode 100644 index 00000000000..af3289c3d4e --- /dev/null +++ b/tests/ui/iterators/iter-macro-not-async-closure.narrow.stderr @@ -0,0 +1,72 @@ +error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}: AsyncFnOnce()` is not satisfied + --> $DIR/iter-macro-not-async-closure.rs:32:34 + | +LL | ...n!(call_async_once(f)); + | --------------- ^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | + = help: the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}` +note: required by a bound in `call_async_once` + --> $DIR/iter-macro-not-async-closure.rs:21:34 + | +LL | ...pl AsyncFnOnce()) { + | ^^^^^^^^^^^^^ required by this bound in `call_async_once` + +error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}: AsyncFnOnce()` is not satisfied + --> $DIR/iter-macro-not-async-closure.rs:32:18 + | +LL | ...n!(call_async_once(f)); + | ^^^^^^^^^^^^^^^^^^ unsatisfied trait bound + | + = help: the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}` +note: required by a bound in `call_async_once` + --> $DIR/iter-macro-not-async-closure.rs:21:34 + | +LL | ...pl AsyncFnOnce()) { + | ^^^^^^^^^^^^^ required by this bound in `call_async_once` + +error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}: AsyncFnOnce()` is not satisfied + --> $DIR/iter-macro-not-async-closure.rs:32:13 + | +LL | ... = pin!(call_async_once(f)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound + | + = help: the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}` +note: required by a bound in `call_async_once` + --> $DIR/iter-macro-not-async-closure.rs:21:34 + | +LL | ...pl AsyncFnOnce()) { + | ^^^^^^^^^^^^^ required by this bound in `call_async_once` + = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}: AsyncFnOnce()` is not satisfied + --> $DIR/iter-macro-not-async-closure.rs:32:13 + | +LL | ... = pin!(call_async_once(f)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound + | + = help: the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}` +note: required by a bound in `call_async_once` + --> $DIR/iter-macro-not-async-closure.rs:21:34 + | +LL | ...pl AsyncFnOnce()) { + | ^^^^^^^^^^^^^ required by this bound in `call_async_once` + = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}: AsyncFnOnce()` is not satisfied + --> $DIR/iter-macro-not-async-closure.rs:37:5 + | +LL | ...::noop())); + | ...^^^^^^^^^^ unsatisfied trait bound + | + = help: the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}` +note: required by a bound in `call_async_once` + --> $DIR/iter-macro-not-async-closure.rs:21:34 + | +LL | ...pl AsyncFnOnce()) { + | ^^^^^^^^^^^^^ required by this bound in `call_async_once` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/iterators/iter-macro-not-async-closure.rs b/tests/ui/iterators/iter-macro-not-async-closure.rs new file mode 100644 index 00000000000..634391883ea --- /dev/null +++ b/tests/ui/iterators/iter-macro-not-async-closure.rs @@ -0,0 +1,32 @@ +// This test ensures iterators created with the `iter!` macro are not +// accidentally async closures. +// +//@ edition: 2024 +//@ remap-src-base + +#![feature(yield_expr, iter_macro)] + +use std::task::{Waker, Context}; +use std::iter::iter; +use std::pin::pin; +use std::future::Future; + +async fn call_async_once(f: impl AsyncFnOnce()) { + f().await +} + +fn main() { + let f = iter! { move || { + for i in 0..10 { + yield i; + } + }}; + + let x = pin!(call_async_once(f)); + //~^ ERROR AsyncFnOnce()` is not satisfied + //~^^ ERROR AsyncFnOnce()` is not satisfied + //~^^^ ERROR AsyncFnOnce()` is not satisfied + //~^^^^ ERROR AsyncFnOnce()` is not satisfied + x.poll(&mut Context::from_waker(Waker::noop())); + //~^ ERROR AsyncFnOnce()` is not satisfied +} diff --git a/tests/ui/iterators/iter-macro-not-async-closure.stderr b/tests/ui/iterators/iter-macro-not-async-closure.stderr new file mode 100644 index 00000000000..2f0343a2d0d --- /dev/null +++ b/tests/ui/iterators/iter-macro-not-async-closure.stderr @@ -0,0 +1,67 @@ +error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}: AsyncFnOnce()` is not satisfied + --> $DIR/iter-macro-not-async-closure.rs:25:34 + | +LL | let x = pin!(call_async_once(f)); + | --------------- ^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}` + | | + | required by a bound introduced by this call + | +note: required by a bound in `call_async_once` + --> $DIR/iter-macro-not-async-closure.rs:14:34 + | +LL | async fn call_async_once(f: impl AsyncFnOnce()) { + | ^^^^^^^^^^^^^ required by this bound in `call_async_once` + +error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}: AsyncFnOnce()` is not satisfied + --> $DIR/iter-macro-not-async-closure.rs:25:18 + | +LL | let x = pin!(call_async_once(f)); + | ^^^^^^^^^^^^^^^^^^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}` + | +note: required by a bound in `call_async_once` + --> $DIR/iter-macro-not-async-closure.rs:14:34 + | +LL | async fn call_async_once(f: impl AsyncFnOnce()) { + | ^^^^^^^^^^^^^ required by this bound in `call_async_once` + +error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}: AsyncFnOnce()` is not satisfied + --> $DIR/iter-macro-not-async-closure.rs:25:13 + | +LL | let x = pin!(call_async_once(f)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}` + | +note: required by a bound in `call_async_once` + --> $DIR/iter-macro-not-async-closure.rs:14:34 + | +LL | async fn call_async_once(f: impl AsyncFnOnce()) { + | ^^^^^^^^^^^^^ required by this bound in `call_async_once` + = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}: AsyncFnOnce()` is not satisfied + --> $DIR/iter-macro-not-async-closure.rs:25:13 + | +LL | let x = pin!(call_async_once(f)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}` + | +note: required by a bound in `call_async_once` + --> $DIR/iter-macro-not-async-closure.rs:14:34 + | +LL | async fn call_async_once(f: impl AsyncFnOnce()) { + | ^^^^^^^^^^^^^ required by this bound in `call_async_once` + = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}: AsyncFnOnce()` is not satisfied + --> $DIR/iter-macro-not-async-closure.rs:30:5 + | +LL | x.poll(&mut Context::from_waker(Waker::noop())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}` + | +note: required by a bound in `call_async_once` + --> $DIR/iter-macro-not-async-closure.rs:14:34 + | +LL | async fn call_async_once(f: impl AsyncFnOnce()) { + | ^^^^^^^^^^^^^ required by this bound in `call_async_once` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/suggestions/unnamable-types.rs b/tests/ui/suggestions/unnamable-types.rs index 094584ff850..6772217a2f6 100644 --- a/tests/ui/suggestions/unnamable-types.rs +++ b/tests/ui/suggestions/unnamable-types.rs @@ -1,7 +1,7 @@ // Test that we do not suggest to add type annotations for unnamable types. #![crate_type="lib"] -#![feature(coroutines, stmt_expr_attributes)] +#![feature(coroutines, stmt_expr_attributes, const_async_blocks)] const A = 5; //~^ ERROR: missing type for `const` item diff --git a/tests/ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs b/tests/ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs index f02ccbbb93c..b258d2e156d 100644 --- a/tests/ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs +++ b/tests/ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait, rustc_attrs)] +#![feature(coroutines, coroutine_trait, rustc_attrs, const_async_blocks)] #![feature(type_alias_impl_trait)] //@ check-pass -- cgit 1.4.1-3-g733a5 From 674a4358e8d37bcf859f55f5f23e61d0e1be7a63 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Tue, 3 Jun 2025 13:10:58 -0700 Subject: update gpu offload build command --- src/bootstrap/src/core/build_steps/llvm.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 20a4d1a1515..2b7703000cb 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -443,23 +443,26 @@ impl Step for Llvm { // See https://github.com/rust-lang/rust/pull/50104 cfg.define("LLVM_ENABLE_LIBXML2", "OFF"); - if !enabled_llvm_projects.is_empty() { - enabled_llvm_projects.sort(); - enabled_llvm_projects.dedup(); - cfg.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects.join(";")); - } - let mut enabled_llvm_runtimes = Vec::new(); if helpers::forcing_clang_based_tests() { enabled_llvm_runtimes.push("compiler-rt"); } + // This is an experimental flag, which likely builds more than necessary. + // We will optimize it when we get closer to releasing it on nightly. if builder.config.llvm_offload { enabled_llvm_runtimes.push("offload"); //FIXME(ZuseZ4): LLVM intends to drop the offload dependency on openmp. //Remove this line once they achieved it. enabled_llvm_runtimes.push("openmp"); + enabled_llvm_projects.push("compiler-rt"); + } + + if !enabled_llvm_projects.is_empty() { + enabled_llvm_projects.sort(); + enabled_llvm_projects.dedup(); + cfg.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects.join(";")); } if !enabled_llvm_runtimes.is_empty() { -- cgit 1.4.1-3-g733a5 From f7db329e81c4501d8f70f11e8bfcc16dd2214219 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 3 Jun 2025 20:56:45 +0000 Subject: Add a test to reproduce ICE --- tests/incremental/print-dep-node-cycle.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/incremental/print-dep-node-cycle.rs diff --git a/tests/incremental/print-dep-node-cycle.rs b/tests/incremental/print-dep-node-cycle.rs new file mode 100644 index 00000000000..931d3da521e --- /dev/null +++ b/tests/incremental/print-dep-node-cycle.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Z query-dep-graph +//@ revisions: rpass1 + +// Exercises a debug-assertions-only query cycle that when printing a valtree const in +// a dep node's debug representation, we end up invoking a query that also has a valtree +// const in its dep node's debug representation, which leads to a cycle (and ICE, since +// deps are not tracked when printing dep nodes' debug representations). + +#![feature(adt_const_params)] + +use std::marker::ConstParamTy; + +#[derive(Debug, ConstParamTy, PartialEq, Eq)] +enum Foo { + A1, +} + +#[inline(never)] +fn hello() { + println!("{:#?}", F); +} + +fn main() { + hello::<{ Foo::A1 }>(); +} -- cgit 1.4.1-3-g733a5 From cbb3a847d25f998486248a8db201773eeb489d60 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 31 May 2025 11:48:29 +0000 Subject: Ensure query keys are printed with reduced queries --- compiler/rustc_middle/src/dep_graph/mod.rs | 5 +++++ compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- compiler/rustc_query_system/src/dep_graph/dep_node.rs | 11 ++++++----- compiler/rustc_query_system/src/dep_graph/mod.rs | 2 ++ .../structs/repr/transmute_infinitely_recursive_type.stderr | 2 +- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 931d67087ac..0a8e6153817 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -2,6 +2,7 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_query_system::ich::StableHashingContext; use rustc_session::Session; +use crate::ty::print::with_reduced_queries; use crate::ty::{self, TyCtxt}; #[macro_use] @@ -84,4 +85,8 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { fn dep_kind_info(&self, dk: DepKind) -> &DepKindStruct<'tcx> { &self.query_kinds[dk.as_usize()] } + + fn with_reduced_queries(self, f: impl FnOnce() -> T) -> T { + with_reduced_queries!(f()) + } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 877bea095f9..673a89a8134 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1886,7 +1886,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ) -> Result<(), PrintError> { define_scoped_cx!(self); - if self.should_print_verbose() { + if with_reduced_queries() || self.should_print_verbose() { p!(write("ValTree({:?}: ", cv.valtree), print(cv.ty), ")"); return Ok(()); } diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index c0b3bd43e25..bdd1d5f3e88 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -178,9 +178,7 @@ pub trait DepNodeParams: fmt::Debug + Sized { panic!("Not implemented. Accidentally called on anonymous node?") } - fn to_debug_str(&self, _: Tcx) -> String { - format!("{self:?}") - } + fn to_debug_str(&self, tcx: Tcx) -> String; /// This method tries to recover the query key from the given `DepNode`, /// something which is needed when forcing `DepNode`s during red-green @@ -210,8 +208,11 @@ where } #[inline(always)] - default fn to_debug_str(&self, _: Tcx) -> String { - format!("{:?}", *self) + default fn to_debug_str(&self, tcx: Tcx) -> String { + // Make sure to print dep node params with reduced queries since printing + // may themselves call queries, which may lead to (possibly untracked!) + // query cycles. + tcx.with_reduced_queries(|| format!("{self:?}")) } #[inline(always)] diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 89d1db87809..512034a8b2f 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -88,6 +88,8 @@ pub trait DepContext: Copy { f(self, dep_node) } } + + fn with_reduced_queries(self, _: impl FnOnce() -> T) -> T; } pub trait Deps: DynSync { diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr index bdf2d3b6a58..1a0563b469c 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr @@ -12,7 +12,7 @@ LL | struct ExplicitlyPadded(Box); error[E0391]: cycle detected when computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` | = note: ...which immediately requires computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` again - = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::TransmuteFrom` + = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::TransmuteFrom` = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From 763663ad56672b0f0635ad25c0c1a52e7773e0b9 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Tue, 3 Jun 2025 21:17:33 +0000 Subject: rustdoc-json-type: Depend on `serde` and `serde_derive` seperately Before this commit, serde_derive is built before serde. But serde does not depend on serde_derive, so that is not needed. Instead, build serde and serde_derive in parallel. This speeds up compilation for users depending on rustdoc-json-types out of tree. Imports: https://www.github.com/rust-lang/rustdoc-types/pull/49 Co-authored-by: Martin Nordholts --- Cargo.lock | 1 + src/rustdoc-json-types/Cargo.toml | 3 ++- src/rustdoc-json-types/lib.rs | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 43f5f40925b..164617c909f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4673,6 +4673,7 @@ dependencies = [ "bincode", "rustc-hash 2.1.1", "serde", + "serde_derive", "serde_json", ] diff --git a/src/rustdoc-json-types/Cargo.toml b/src/rustdoc-json-types/Cargo.toml index 14ff1d08816..a38d34ef0e7 100644 --- a/src/rustdoc-json-types/Cargo.toml +++ b/src/rustdoc-json-types/Cargo.toml @@ -10,7 +10,8 @@ path = "lib.rs" default = ["rustc-hash"] [dependencies] -serde = { version = "1.0", features = ["derive"] } +serde = "1.0" +serde_derive = "1.0" rustc-hash = { version = "2.0", optional = true } [dev-dependencies] diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index f1c375bd2fe..8a3ab6f8640 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -21,7 +21,7 @@ use std::path::PathBuf; #[cfg(feature = "rustc-hash")] use rustc_hash::FxHashMap as HashMap; -use serde::{Deserialize, Serialize}; +use serde_derive::{Deserialize, Serialize}; pub type FxHashMap = HashMap; // re-export for use in src/librustdoc -- cgit 1.4.1-3-g733a5 From 252ad18415723a7485b0e2950f1b641109c9d4ef Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 7 Feb 2025 14:53:34 +0100 Subject: Improve the documentation of `Display` and `FromStr`, and their interactions In particular: - `Display` is not necessarily lossless - The output of `Display` might not be parseable by `FromStr`, and might not produce the same value if it is. - Calling `.parse()` on the output of `Display` is usually a mistake unless a type's documented output and input formats match. - The input formats accepted by `FromStr` depend on the type. --- library/core/src/fmt/mod.rs | 9 +++++++++ library/core/src/str/traits.rs | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 5978cb660f6..c25ef9ba512 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -928,6 +928,15 @@ pub use macros::Debug; /// [tostring]: ../../std/string/trait.ToString.html /// [tostring_function]: ../../std/string/trait.ToString.html#tymethod.to_string /// +/// # Completeness and parseability +/// +/// `Display` for a type might not necessarily be a lossless or complete representation of the type. +/// It may omit internal state, precision, or other information the type does not consider important +/// for user-facing output, as determined by the type. As such, the output of `Display` might not be +/// possible to parse, and even if it is, the result of parsing might not exactly match the original +/// value. Calling `.parse()` on the output from `Display` is usually a mistake, unless the type has +/// provided and documented additional guarantees about its `Display` and `FromStr` implementations. +/// /// # Internationalization /// /// Because a type can only have one `Display` implementation, it is often preferable diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 4baf9aacad7..85d5fa1ef92 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -756,6 +756,15 @@ unsafe impl SliceIndex for ops::RangeToInclusive { /// parse an `i32` with `FromStr`, but not a `&i32`. You can parse a struct that /// contains an `i32`, but not one that contains an `&i32`. /// +/// # Input format +/// +/// The input format expected by a type's `FromStr` implementation depends on the type. Check the +/// type's documentation for the input formats it knows how to parse. Note that the input format of +/// a type's `FromStr` implementation might not necessarily accept the output format of its +/// `Display` implementation; thus, calling `.parse()` on the output from `Display` is usually a +/// mistake, unless the type has provided and documented additional guarantees about its `Display` +/// and `FromStr` implementations. +/// /// # Examples /// /// Basic implementation of `FromStr` on an example `Point` type: -- cgit 1.4.1-3-g733a5 From f412d05e50d0a682502e225b41db77bf4aa302e2 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 7 Feb 2025 15:31:55 +0100 Subject: Add some more description of interactions between `Display` and `FromStr` --- library/core/src/str/traits.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 85d5fa1ef92..2f425c82dc8 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -765,6 +765,12 @@ unsafe impl SliceIndex for ops::RangeToInclusive { /// mistake, unless the type has provided and documented additional guarantees about its `Display` /// and `FromStr` implementations. /// +/// If a type happens to have a lossless `Display` implementation whose output is meant to be +/// conveniently machine-parseable and not just meant for human consumption, then the type may wish +/// to accept the same format in `FromStr`, and document that usage. Having both `Display` and +/// `FromStr` implementations where the result of `Display` cannot be parsed with `FromStr` may +/// surprise users. (However, the result of such parsing may not have the same value as the input.) +/// /// # Examples /// /// Basic implementation of `FromStr` on an example `Point` type: -- cgit 1.4.1-3-g733a5 From 7ba5d26636b61ffbbefe1999254e66348e652c1a Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 3 Jun 2025 15:34:37 -0700 Subject: `FromStr`: Rework explanation of `FromStr`/`Display` round-tripping - Drop the phrasing "usually a mistake". - Mention that `Display` may not be lossless. - Drop a misplaced parenthetical about round-tripping that didn't fit the paragraph it was in. --- library/core/src/str/traits.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 2f425c82dc8..b9559c83171 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -756,20 +756,19 @@ unsafe impl SliceIndex for ops::RangeToInclusive { /// parse an `i32` with `FromStr`, but not a `&i32`. You can parse a struct that /// contains an `i32`, but not one that contains an `&i32`. /// -/// # Input format +/// # Input format and round-tripping /// /// The input format expected by a type's `FromStr` implementation depends on the type. Check the /// type's documentation for the input formats it knows how to parse. Note that the input format of /// a type's `FromStr` implementation might not necessarily accept the output format of its -/// `Display` implementation; thus, calling `.parse()` on the output from `Display` is usually a -/// mistake, unless the type has provided and documented additional guarantees about its `Display` -/// and `FromStr` implementations. +/// `Display` implementation, and even if it does, the `Display` implementation may not be lossless +/// so the round-trip may lose information. /// -/// If a type happens to have a lossless `Display` implementation whose output is meant to be +/// However, if a type has a lossless `Display` implementation whose output is meant to be /// conveniently machine-parseable and not just meant for human consumption, then the type may wish /// to accept the same format in `FromStr`, and document that usage. Having both `Display` and /// `FromStr` implementations where the result of `Display` cannot be parsed with `FromStr` may -/// surprise users. (However, the result of such parsing may not have the same value as the input.) +/// surprise users. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 742014e7e3576f3053e7c63fc930c4d5b5b7a477 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 3 Jun 2025 15:39:46 -0700 Subject: `Display`: Rework explanation of `FromStr`/`Display` round-tripping - Drop "usually a mistake" - Add phrasing from `FromStr` about round-tripping, and about how the inability to round-trip may surprise users. --- library/core/src/fmt/mod.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index c25ef9ba512..145e581d1fb 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -934,8 +934,13 @@ pub use macros::Debug; /// It may omit internal state, precision, or other information the type does not consider important /// for user-facing output, as determined by the type. As such, the output of `Display` might not be /// possible to parse, and even if it is, the result of parsing might not exactly match the original -/// value. Calling `.parse()` on the output from `Display` is usually a mistake, unless the type has -/// provided and documented additional guarantees about its `Display` and `FromStr` implementations. +/// value. +/// +/// However, if a type has a lossless `Display` implementation whose output is meant to be +/// conveniently machine-parseable and not just meant for human consumption, then the type may wish +/// to accept the same format in `FromStr`, and document that usage. Having both `Display` and +/// `FromStr` implementations where the result of `Display` cannot be parsed with `FromStr` may +/// surprise users. /// /// # Internationalization /// -- cgit 1.4.1-3-g733a5 From a0c19ee577542cbc9dbdead54c91e661aa6396de Mon Sep 17 00:00:00 2001 From: Nia Espera Date: Sat, 31 May 2025 10:13:09 +0200 Subject: index: add method for checking range on DenseBitSet --- compiler/rustc_index/src/bit_set.rs | 26 ++++++++++++++++++++++++++ compiler/rustc_index/src/bit_set/tests.rs | 19 +++++++++++++++++++ src/tools/miri/src/alloc/isolated_alloc.rs | 5 +---- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 07934389158..a4885aabe1f 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -234,6 +234,32 @@ impl DenseBitSet { self.clear_excess_bits(); } + /// Checks whether any bit in the given range is a 1. + #[inline] + pub fn contains_any(&self, elems: impl RangeBounds) -> bool { + let Some((start, end)) = inclusive_start_end(elems, self.domain_size) else { + return false; + }; + let (start_word_index, start_mask) = word_index_and_mask(start); + let (end_word_index, end_mask) = word_index_and_mask(end); + + if start_word_index == end_word_index { + self.words[start_word_index] & (end_mask | (end_mask - start_mask)) != 0 + } else { + if self.words[start_word_index] & !(start_mask - 1) != 0 { + return true; + } + + let remaining = start_word_index + 1..end_word_index; + if remaining.start <= remaining.end { + self.words[remaining].iter().any(|&w| w != 0) + || self.words[end_word_index] & (end_mask | (end_mask - 1)) != 0 + } else { + false + } + } + } + /// Returns `true` if the set has changed. #[inline] pub fn remove(&mut self, elem: T) -> bool { diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs index 323a66ddc6f..9ce4cf4293f 100644 --- a/compiler/rustc_index/src/bit_set/tests.rs +++ b/compiler/rustc_index/src/bit_set/tests.rs @@ -692,6 +692,25 @@ fn dense_last_set_before() { } } +#[test] +fn dense_contains_any() { + let mut set: DenseBitSet = DenseBitSet::new_empty(300); + assert!(!set.contains_any(0..300)); + set.insert_range(10..20); + set.insert_range(60..70); + set.insert_range(150..=250); + + assert!(set.contains_any(0..30)); + assert!(set.contains_any(5..100)); + assert!(set.contains_any(250..255)); + + assert!(!set.contains_any(20..59)); + assert!(!set.contains_any(256..290)); + + set.insert(22); + assert!(set.contains_any(20..59)); +} + #[bench] fn bench_insert(b: &mut Bencher) { let mut bs = DenseBitSet::new_filled(99999usize); diff --git a/src/tools/miri/src/alloc/isolated_alloc.rs b/src/tools/miri/src/alloc/isolated_alloc.rs index 7b74d171373..3a7879f372a 100644 --- a/src/tools/miri/src/alloc/isolated_alloc.rs +++ b/src/tools/miri/src/alloc/isolated_alloc.rs @@ -145,10 +145,7 @@ impl IsolatedAlloc { if pinfo.domain_size() < offset_pinfo + size_pinfo { break; } - // FIXME: is there a more efficient way to check whether the entire range is unset - // in the bitset? - let range_avail = !(offset_pinfo..offset_pinfo + size_pinfo).any(|i| pinfo.contains(i)); - if range_avail { + if !pinfo.contains_any(offset_pinfo..offset_pinfo + size_pinfo) { pinfo.insert_range(offset_pinfo..offset_pinfo + size_pinfo); // SAFETY: We checked the available bytes after `idx` in the call // to `domain_size` above and asserted there are at least `idx + -- cgit 1.4.1-3-g733a5 From 21a739fbf71ac118da144431f4c12b3714f875b9 Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Tue, 3 Jun 2025 21:02:04 -0400 Subject: add tests for negative numbers --- library/coretests/tests/num/int_macros.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs index 719d29e4e7c..41d399c1ad9 100644 --- a/library/coretests/tests/num/int_macros.rs +++ b/library/coretests/tests/num/int_macros.rs @@ -690,6 +690,12 @@ macro_rules! int_module { const EXACT_DIV_SUCCESS_DIVIDEND2: $T = 18; const EXACT_DIV_SUCCESS_DIVISOR2: $T = 3; const EXACT_DIV_SUCCESS_QUOTIENT2: $T = 6; + const EXACT_DIV_SUCCESS_DIVIDEND3: $T = -91; + const EXACT_DIV_SUCCESS_DIVISOR3: $T = 13; + const EXACT_DIV_SUCCESS_QUOTIENT3: $T = -7; + const EXACT_DIV_SUCCESS_DIVIDEND4: $T = -57; + const EXACT_DIV_SUCCESS_DIVISOR4: $T = -3; + const EXACT_DIV_SUCCESS_QUOTIENT4: $T = 19; test_runtime_and_compiletime! { fn test_exact_div() { @@ -701,6 +707,14 @@ macro_rules! int_module { assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), Some(EXACT_DIV_SUCCESS_QUOTIENT2)); assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), EXACT_DIV_SUCCESS_QUOTIENT2); + // -91 / 13 + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND3, EXACT_DIV_SUCCESS_DIVISOR3), Some(EXACT_DIV_SUCCESS_QUOTIENT3)); + assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND3, EXACT_DIV_SUCCESS_DIVISOR3), EXACT_DIV_SUCCESS_QUOTIENT3); + + // -57 / -3 + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND4, EXACT_DIV_SUCCESS_DIVISOR4), Some(EXACT_DIV_SUCCESS_QUOTIENT4)); + assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND4, EXACT_DIV_SUCCESS_DIVISOR4), EXACT_DIV_SUCCESS_QUOTIENT4); + // failures assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(1, 2), None); assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(<$T>::MIN, -1), None); -- cgit 1.4.1-3-g733a5 From f9c2a454fd1d632ea90718306f7250e2b0db2514 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 4 Jun 2025 12:33:49 +1000 Subject: Visit the ident in `PreciseCapturingNonLifetimeArg`. It's currently skipped, presumably by accident. --- compiler/rustc_hir/src/intravisit.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index b9932a7334e..d12050ea4bb 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1333,8 +1333,9 @@ pub fn walk_precise_capturing_arg<'v, V: Visitor<'v>>( match *arg { PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt), PreciseCapturingArg::Param(param) => { - let PreciseCapturingNonLifetimeArg { hir_id, ident: _, res: _ } = param; - visitor.visit_id(hir_id) + let PreciseCapturingNonLifetimeArg { hir_id, ident, res: _ } = param; + try_visit!(visitor.visit_id(hir_id)); + visitor.visit_ident(ident) } } } -- cgit 1.4.1-3-g733a5 From bded7010e849680b56d897bcf32d09c999b98fd0 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Jun 2025 06:57:12 +0300 Subject: run `check::Std` as the final step Signed-off-by: onur-ozkan --- src/bootstrap/src/core/builder/mod.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index af3e3cc37b9..19b79bfe818 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -945,7 +945,6 @@ impl<'a> Builder<'a> { clippy::CI, ), Kind::Check | Kind::Fix => describe!( - check::Std, check::Rustc, check::Rustdoc, check::CodegenBackend, @@ -961,6 +960,13 @@ impl<'a> Builder<'a> { check::Compiletest, check::FeaturesStatusDump, check::CoverageDump, + // This has special staging logic, it may run on stage 1 while others run on stage 0. + // It takes quite some time to build stage 1, so put this at the end. + // + // FIXME: This also helps bootstrap to not interfere with stage 0 builds. We should probably fix + // that issue somewhere else, but we still want to keep `check::Std` at the end so that the + // quicker steps run before this. + check::Std, ), Kind::Test => describe!( crate::core::build_steps::toolstate::ToolStateCheck, -- cgit 1.4.1-3-g733a5 From e66948c4febb538ebd73b7f09733e947545fbf2c Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Jun 2025 06:58:28 +0300 Subject: make it possible to request stage 0 std with `Builder::ensure` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/check.rs | 34 ++++++++++++++++------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 833cbedd5cf..a3bac5bfe7a 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -28,13 +28,16 @@ pub struct Std { /// passing `Builder::kind` to cargo invocations would run clippy on the entire compiler and library, /// which is not useful if we only want to lint a few crates with specific rules. override_build_kind: Option, + /// Never use this from outside calls. It is intended for internal use only within `check::Std::make_run` + /// and `check::Std::run`. + custom_stage: Option, } impl Std { const CRATE_OR_DEPS: &[&str] = &["sysroot", "coretests", "alloctests"]; pub fn new(target: TargetSelection) -> Self { - Self { target, crates: vec![], override_build_kind: None } + Self { target, crates: vec![], override_build_kind: None, custom_stage: None } } pub fn build_kind(mut self, kind: Option) -> Self { @@ -48,34 +51,35 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let builder = run.builder; - let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 { - builder.top_stage - } else { - 1 - }; - let mut run = run; for c in Std::CRATE_OR_DEPS { run = run.crate_or_deps(c); } - run.path("library").default_condition(stage != 0) + run.path("library") } fn make_run(run: RunConfig<'_>) { let crates = std_crates_for_run_make(&run); - run.builder.ensure(Std { target: run.target, crates, override_build_kind: None }); + + let stage = if run.builder.config.is_explicit_stage() || run.builder.top_stage >= 1 { + run.builder.top_stage + } else { + 1 + }; + + run.builder.ensure(Std { + target: run.target, + crates, + override_build_kind: None, + custom_stage: Some(stage), + }); } fn run(self, builder: &Builder<'_>) { builder.require_submodule("library/stdarch", None); - let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 { - builder.top_stage - } else { - 1 - }; + let stage = self.custom_stage.unwrap_or(builder.top_stage); let target = self.target; let compiler = builder.compiler(stage, builder.config.build); -- cgit 1.4.1-3-g733a5 From 556c0962edd7655f1532bc82d8a8287bf14950e9 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Tue, 3 Jun 2025 20:48:42 -0400 Subject: bootstrap: don't symlink source dir into stage0 sysroot In StdLink::run we subsequently recursively copy the initial sysroot lib directory into the stage0-sysroot lib directory. If the initial sysroot is a toolchain that includes the `rust-src` component (in lib/rustlib/src/rust), if we add this symlink, that recursive copy will overwrite the repo sources with the toolchain's sources. --- src/bootstrap/src/core/build_steps/compile.rs | 30 +++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 37d53ce476a..d52b9dd1f3a 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1878,23 +1878,27 @@ impl Step for Sysroot { // so that any tools relying on `rust-src` also work for local builds, // and also for translating the virtual `/rustc/$hash` back to the real // directory (for running tests with `rust.remap-debuginfo = true`). - let sysroot_lib_rustlib_src = sysroot.join("lib/rustlib/src"); - t!(fs::create_dir_all(&sysroot_lib_rustlib_src)); - let sysroot_lib_rustlib_src_rust = sysroot_lib_rustlib_src.join("rust"); - if let Err(e) = symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_src_rust) { - eprintln!( - "ERROR: creating symbolic link `{}` to `{}` failed with {}", - sysroot_lib_rustlib_src_rust.display(), - builder.src.display(), - e, - ); - if builder.config.rust_remap_debuginfo { + if compiler.stage != 0 { + let sysroot_lib_rustlib_src = sysroot.join("lib/rustlib/src"); + t!(fs::create_dir_all(&sysroot_lib_rustlib_src)); + let sysroot_lib_rustlib_src_rust = sysroot_lib_rustlib_src.join("rust"); + if let Err(e) = + symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_src_rust) + { eprintln!( - "ERROR: some `tests/ui` tests will fail when lacking `{}`", + "ERROR: creating symbolic link `{}` to `{}` failed with {}", sysroot_lib_rustlib_src_rust.display(), + builder.src.display(), + e, ); + if builder.config.rust_remap_debuginfo { + eprintln!( + "ERROR: some `tests/ui` tests will fail when lacking `{}`", + sysroot_lib_rustlib_src_rust.display(), + ); + } + build_helper::exit!(1); } - build_helper::exit!(1); } // rustc-src component is already part of CI rustc's sysroot -- cgit 1.4.1-3-g733a5 From 7af12a19a8b7362df651fee890db0db1ef8d2a17 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Jun 2025 07:15:45 +0300 Subject: remove outdated RUSTC_SYSROOT handling for ci-rustc Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/test.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 22a458bac98..dddce8fe05d 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2707,16 +2707,6 @@ impl Step for Crate { .arg(builder.src.join("library/sysroot/Cargo.toml")); } else { compile::std_cargo(builder, target, compiler.stage, &mut cargo); - // `std_cargo` actually does the wrong thing: it passes `--sysroot build/host/stage2`, - // but we want to use the force-recompile std we just built in `build/host/stage2-test-sysroot`. - // Override it. - if builder.download_rustc() && compiler.stage > 0 { - let sysroot = builder - .out - .join(compiler.host) - .join(format!("stage{}-test-sysroot", compiler.stage)); - cargo.env("RUSTC_SYSROOT", sysroot); - } } } Mode::Rustc => { -- cgit 1.4.1-3-g733a5 From 321db85fb4fa58fc03e86a3a7a901ff7fb624583 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 May 2025 21:53:57 +0200 Subject: x86 (32/64): go back to passing SIMD vectors by-ptr --- compiler/rustc_target/src/callconv/mod.rs | 27 ++++------------------ tests/codegen/abi-x86-sse.rs | 5 ++-- .../simd-intrinsic-transmute-array.rs | 20 ++++------------ tests/codegen/simd/packed-simd.rs | 16 +++++++------ 4 files changed, 22 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index d2e49cea647..dcb79cce759 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -7,7 +7,7 @@ use rustc_abi::{ use rustc_macros::HashStable_Generic; pub use crate::spec::AbiMap; -use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, RustcAbi, WasmCAbi}; +use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi}; mod aarch64; mod amdgpu; @@ -696,24 +696,6 @@ impl<'a, Ty> FnAbi<'a, Ty> { _ => {} }; - // Decides whether we can pass the given SIMD argument via `PassMode::Direct`. - // May only return `true` if the target will always pass those arguments the same way, - // no matter what the user does with `-Ctarget-feature`! In other words, whatever - // target features are required to pass a SIMD value in registers must be listed in - // the `abi_required_features` for the current target and ABI. - let can_pass_simd_directly = |arg: &ArgAbi<'_, Ty>| match &*spec.arch { - // On x86, if we have SSE2 (which we have by default for x86_64), we can always pass up - // to 128-bit-sized vectors. - "x86" if spec.rustc_abi == Some(RustcAbi::X86Sse2) => arg.layout.size.bits() <= 128, - "x86_64" if spec.rustc_abi != Some(RustcAbi::X86Softfloat) => { - // FIXME once https://github.com/bytecodealliance/wasmtime/issues/10254 is fixed - // accept vectors up to 128bit rather than vectors of exactly 128bit. - arg.layout.size.bits() == 128 - } - // So far, we haven't implemented this logic for any other target. - _ => false, - }; - for (arg_idx, arg) in self .args .iter_mut() @@ -813,9 +795,10 @@ impl<'a, Ty> FnAbi<'a, Ty> { // target feature sets. Some more information about this // issue can be found in #44367. // - // Note that the intrinsic ABI is exempt here as those are not - // real functions anyway, and the backend expects very specific types. - if spec.simd_types_indirect && !can_pass_simd_directly(arg) { + // We *could* do better in some cases, e.g. on x86_64 targets where SSE2 is + // required. However, it turns out that that makes LLVM worse at optimizing this + // code, so we pass things indirectly even there. See #139029 for more on that. + if spec.simd_types_indirect { arg.make_indirect(); } } diff --git a/tests/codegen/abi-x86-sse.rs b/tests/codegen/abi-x86-sse.rs index 837bf6134b0..90757e601af 100644 --- a/tests/codegen/abi-x86-sse.rs +++ b/tests/codegen/abi-x86-sse.rs @@ -27,8 +27,9 @@ trait Copy {} #[repr(simd)] pub struct Sse([f32; 4]); -// x86-64: <4 x float> @sse_id(<4 x float> {{[^,]*}}) -// x86-32: <4 x float> @sse_id(<4 x float> {{[^,]*}}) +// FIXME: due to #139029 we are passing them all indirectly. +// x86-64: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}}) +// x86-32: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}}) // x86-32-nosse: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}}) #[no_mangle] pub fn sse_id(x: Sse) -> Sse { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs index d3853361de9..977bf3379b7 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs @@ -1,14 +1,8 @@ // //@ compile-flags: -C no-prepopulate-passes -// LLVM IR isn't very portable and the one tested here depends on the ABI -// which is different between x86 (where we use SSE registers) and others. -// `x86-64` and `x86-32-sse2` are identical, but compiletest does not support -// taking the union of multiple `only` annotations. -//@ revisions: x86-64 x86-32-sse2 other -//@[x86-64] only-x86_64 -//@[x86-32-sse2] only-rustc_abi-x86-sse2 -//@[other] ignore-rustc_abi-x86-sse2 -//@[other] ignore-x86_64 +// 32bit MSVC does not align things properly so we suppress high alignment annotations (#112480) +//@ ignore-i686-pc-windows-msvc +//@ ignore-i686-pc-windows-gnu #![crate_type = "lib"] #![allow(non_camel_case_types)] @@ -47,9 +41,7 @@ pub fn build_array_s(x: [f32; 4]) -> S<4> { #[no_mangle] pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> { // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]] - // x86-32: ret <4 x float> %[[VAL:.+]] - // x86-64: ret <4 x float> %[[VAL:.+]] - // other: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]] + // CHECK: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]] unsafe { std::mem::transmute(x) } } @@ -64,8 +56,6 @@ pub fn build_array_t(x: [f32; 4]) -> T { #[no_mangle] pub fn build_array_transmute_t(x: [f32; 4]) -> T { // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]] - // x86-32: ret <4 x float> %[[VAL:.+]] - // x86-64: ret <4 x float> %[[VAL:.+]] - // other: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]] + // CHECK: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]] unsafe { std::mem::transmute(x) } } diff --git a/tests/codegen/simd/packed-simd.rs b/tests/codegen/simd/packed-simd.rs index a27d5e3af45..73e0d29d7d6 100644 --- a/tests/codegen/simd/packed-simd.rs +++ b/tests/codegen/simd/packed-simd.rs @@ -30,16 +30,18 @@ fn load(v: PackedSimd) -> FullSimd { } } -// CHECK-LABEL: define <3 x float> @square_packed_full(ptr{{[a-z_ ]*}} align 4 {{[^,]*}}) +// CHECK-LABEL: square_packed_full +// CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align (8|16)]]{{[^%]*}} [[RET_VREG:%[_0-9]*]] +// CHECK-SAME: ptr{{[a-z_ ]*}} align 4 #[no_mangle] pub fn square_packed_full(x: PackedSimd) -> FullSimd { - // The unoptimized version of this is not very interesting to check - // since `load` does not get inlined. - // opt3-NEXT: start: - // opt3-NEXT: load <3 x float> + // CHECK-NEXT: start + // noopt: alloca [[RET_TYPE]], [[RET_ALIGN]] + // CHECK: load <3 x float> let x = load(x); - // opt3-NEXT: [[VREG:%[a-z0-9_]+]] = fmul <3 x float> - // opt3-NEXT: ret <3 x float> [[VREG:%[a-z0-9_]+]] + // CHECK: [[VREG:%[a-z0-9_]+]] = fmul <3 x float> + // CHECK-NEXT: store <3 x float> [[VREG]], ptr [[RET_VREG]], [[RET_ALIGN]] + // CHECK-NEXT: ret void unsafe { intrinsics::simd_mul(x, x) } } -- cgit 1.4.1-3-g733a5 From f01bbfc5e78b4abefe5b386dcf8e83ced4cbe664 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Jun 2025 10:42:37 +0200 Subject: abi_check: tweak some comments --- .../rustc_monomorphize/src/mono_checks/abi_check.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index 5478e54a606..8dbbb4d1713 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -35,8 +35,6 @@ fn do_check_simd_vector_abi<'tcx>( is_call: bool, loc: impl Fn() -> (Span, HirId), ) { - // We check this on all functions, including those using the "Rust" ABI. - // For the "Rust" ABI it would be a bug if the lint ever triggered, but better safe than sorry. let feature_def = tcx.sess.target.features_for_correct_vector_abi(); let codegen_attrs = tcx.codegen_fn_attrs(def_id); let have_feature = |feat: Symbol| { @@ -123,8 +121,9 @@ fn do_check_wasm_abi<'tcx>( is_call: bool, loc: impl Fn() -> (Span, HirId), ) { - // Only proceed for `extern "C" fn` on wasm32-unknown-unknown (same check as what `adjust_for_foreign_abi` uses to call `compute_wasm_abi_info`), - // and only proceed if `wasm_c_abi_opt` indicates we should emit the lint. + // Only proceed for `extern "C" fn` on wasm32-unknown-unknown (same check as what + // `adjust_for_foreign_abi` uses to call `compute_wasm_abi_info`), and only proceed if + // `wasm_c_abi_opt` indicates we should emit the lint. if !(tcx.sess.target.arch == "wasm32" && tcx.sess.target.os == "unknown" && tcx.wasm_c_abi_opt() == WasmCAbi::Legacy { with_lint: true } @@ -157,8 +156,15 @@ fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { else { // An error will be reported during codegen if we cannot determine the ABI of this // function. + tcx.dcx().delayed_bug("ABI computation failure should lead to compilation failure"); return; }; + // Unlike the call-site check, we do also check "Rust" ABI functions here. + // This should never trigger, *except* if we start making use of vector registers + // for the "Rust" ABI and the user disables those vector registers (which should trigger a + // warning as that's clearly disabling a "required" target feature for this target). + // Using such a function is where disabling the vector register actually can start leading + // to soundness issues, so erroring here seems good. let loc = || { let def_id = instance.def_id(); ( @@ -179,7 +185,8 @@ fn check_call_site_abi<'tcx>( loc: impl Fn() -> (Span, HirId) + Copy, ) { if callee.fn_sig(tcx).abi().is_rustic_abi() { - // we directly handle the soundness of Rust ABIs + // We directly handle the soundness of Rust ABIs -- so let's skip the majority of + // call sites to avoid a perf regression. return; } let typing_env = ty::TypingEnv::fully_monomorphized(); -- cgit 1.4.1-3-g733a5 From ed300d8ad881acc54f56a965e9c8f8a9e75a06d8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 4 Jun 2025 16:40:00 +1000 Subject: Improve some `Visitor` comments. For AST/HIR/THIR visitors, explain the use of deconstruction. --- compiler/rustc_ast/src/visit.rs | 4 ++++ compiler/rustc_hir/src/intravisit.rs | 9 ++++----- compiler/rustc_middle/src/thir/visit.rs | 3 +++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 908d9fd4bda..1f7c97380dc 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -121,6 +121,10 @@ pub enum LifetimeCtxt { /// explicitly, you need to override each method. (And you also need /// to monitor future changes to `Visitor` in case a new method with a /// new default implementation gets introduced.) +/// +/// Every `walk_*` method uses deconstruction to access fields of structs and +/// enums. This will result in a compile error if a field is added, which makes +/// it more likely the appropriate visit call will be added for it. pub trait Visitor<'ast>: Sized { /// The result type of the `visit_*` methods. Can be either `()`, /// or `ControlFlow`. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index b9932a7334e..42f6fb7aec1 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -200,6 +200,10 @@ use nested_filter::NestedFilter; /// explicitly, you need to override each method. (And you also need /// to monitor future changes to `Visitor` in case a new method with a /// new default implementation gets introduced.) +/// +/// Every `walk_*` method uses deconstruction to access fields of structs and +/// enums. This will result in a compile error if a field is added, which makes +/// it more likely the appropriate visit call will be added for it. pub trait Visitor<'v>: Sized { // This type should not be overridden, it exists for convenient usage as `Self::MaybeTyCtxt`. type MaybeTyCtxt: HirTyCtxt<'v> = >::MaybeTyCtxt; @@ -1201,7 +1205,6 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>( visitor: &mut V, trait_item: &'v TraitItem<'v>, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item; let hir_id = trait_item.hir_id(); try_visit!(visitor.visit_ident(ident)); @@ -1240,7 +1243,6 @@ pub fn walk_trait_item_ref<'v, V: Visitor<'v>>( visitor: &mut V, trait_item_ref: &'v TraitItemRef, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let TraitItemRef { id, ident, ref kind, span: _ } = *trait_item_ref; try_visit!(visitor.visit_nested_trait_item(id)); try_visit!(visitor.visit_ident(ident)); @@ -1251,7 +1253,6 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>( visitor: &mut V, impl_item: &'v ImplItem<'v>, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let ImplItem { owner_id: _, ident, @@ -1286,7 +1287,6 @@ pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>( visitor: &mut V, foreign_item_ref: &'v ForeignItemRef, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let ForeignItemRef { id, ident, span: _ } = *foreign_item_ref; try_visit!(visitor.visit_nested_foreign_item(id)); visitor.visit_ident(ident) @@ -1296,7 +1296,6 @@ pub fn walk_impl_item_ref<'v, V: Visitor<'v>>( visitor: &mut V, impl_item_ref: &'v ImplItemRef, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let ImplItemRef { id, ident, ref kind, span: _, trait_item_def_id: _ } = *impl_item_ref; try_visit!(visitor.visit_nested_impl_item(id)); try_visit!(visitor.visit_ident(ident)); diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 4da4dc3c02e..d8743814d79 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -3,6 +3,9 @@ use super::{ Pat, PatKind, Stmt, StmtKind, Thir, }; +/// Every `walk_*` method uses deconstruction to access fields of structs and +/// enums. This will result in a compile error if a field is added, which makes +/// it more likely the appropriate visit call will be added for it. pub trait Visitor<'thir, 'tcx: 'thir>: Sized { fn thir(&self) -> &'thir Thir<'tcx>; -- cgit 1.4.1-3-g733a5 From ee9901e65c78f70b93dab5bd1e04bd77273b7c40 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 3 Jun 2025 23:42:21 -0700 Subject: Change `tag_field` to `FieldIdx` in `Variants::Multiple` It was already available as a generic parameter anyway, and it's not like we'll ever put a tag in the 5-billionth field. --- compiler/rustc_abi/src/layout.rs | 4 ++-- compiler/rustc_abi/src/layout/coroutine.rs | 4 ++-- compiler/rustc_abi/src/lib.rs | 2 +- compiler/rustc_codegen_cranelift/src/discriminant.rs | 6 +++--- .../src/debuginfo/metadata/enums/cpp_like.rs | 14 +++++++------- .../src/debuginfo/metadata/enums/native.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/operand.rs | 4 ++-- compiler/rustc_codegen_ssa/src/mir/place.rs | 4 ++-- compiler/rustc_const_eval/src/interpret/discriminant.rs | 8 ++++---- compiler/rustc_const_eval/src/interpret/validity.rs | 2 +- compiler/rustc_middle/src/ty/layout.rs | 8 +++++--- compiler/rustc_smir/src/rustc_smir/convert/abi.rs | 2 +- compiler/rustc_transmute/src/layout/tree.rs | 2 +- compiler/rustc_ty_utils/src/layout.rs | 2 +- 14 files changed, 33 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 42250aa173b..21fd6be39fa 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -758,7 +758,7 @@ impl LayoutCalculator { niche_variants, niche_start, }, - tag_field: 0, + tag_field: FieldIdx::new(0), variants: IndexVec::new(), }, fields: FieldsShape::Arbitrary { @@ -1072,7 +1072,7 @@ impl LayoutCalculator { variants: Variants::Multiple { tag, tag_encoding: TagEncoding::Direct, - tag_field: 0, + tag_field: FieldIdx::new(0), variants: IndexVec::new(), }, fields: FieldsShape::Arbitrary { diff --git a/compiler/rustc_abi/src/layout/coroutine.rs b/compiler/rustc_abi/src/layout/coroutine.rs index 27e704d538c..2b22276d4ae 100644 --- a/compiler/rustc_abi/src/layout/coroutine.rs +++ b/compiler/rustc_abi/src/layout/coroutine.rs @@ -158,7 +158,7 @@ pub(super) fn layout< // Build a prefix layout, including "promoting" all ineligible // locals as part of the prefix. We compute the layout of all of // these fields at once to get optimal packing. - let tag_index = prefix_layouts.len(); + let tag_index = prefix_layouts.next_index(); // `variant_fields` already accounts for the reserved variants, so no need to add them. let max_discr = (variant_fields.len() - 1) as u128; @@ -187,7 +187,7 @@ pub(super) fn layout< // "a" (`0..b_start`) and "b" (`b_start..`) correspond to // "outer" and "promoted" fields respectively. - let b_start = FieldIdx::new(tag_index + 1); + let b_start = tag_index.plus(1); let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.index())); let offsets_a = offsets; diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index b806d0aba31..46b7a0c1e77 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1573,7 +1573,7 @@ pub enum Variants { Multiple { tag: Scalar, tag_encoding: TagEncoding, - tag_field: usize, + tag_field: FieldIdx, variants: IndexVec>, }, } diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs index 4d0d5dc60eb..a08b0e0cbfc 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -28,7 +28,7 @@ pub(crate) fn codegen_set_discriminant<'tcx>( tag_encoding: TagEncoding::Direct, variants: _, } => { - let ptr = place.place_field(fx, FieldIdx::new(tag_field)); + let ptr = place.place_field(fx, tag_field); let to = layout.ty.discriminant_for_variant(fx.tcx, variant_index).unwrap().val; let to = match ptr.layout().ty.kind() { ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => { @@ -53,7 +53,7 @@ pub(crate) fn codegen_set_discriminant<'tcx>( variants: _, } => { if variant_index != untagged_variant { - let niche = place.place_field(fx, FieldIdx::new(tag_field)); + let niche = place.place_field(fx, tag_field); let niche_type = fx.clif_type(niche.layout().ty).unwrap(); let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); let niche_value = (niche_value as u128).wrapping_add(niche_start); @@ -118,7 +118,7 @@ pub(crate) fn codegen_get_discriminant<'tcx>( let cast_to = fx.clif_type(dest_layout.ty).unwrap(); // Read the tag/niche-encoded discriminant from memory. - let tag = value.value_field(fx, FieldIdx::new(tag_field)); + let tag = value.value_field(fx, tag_field); let tag = tag.load_scalar(fx); // Decode the discriminant (specifically if it's niche-encoded). diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index e9574108696..a5c80895741 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use libc::c_uint; -use rustc_abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants}; +use rustc_abi::{Align, Endian, FieldIdx, Size, TagEncoding, VariantIdx, Variants}; use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name; use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo}; use rustc_codegen_ssa::traits::{ConstCodegenMethods, MiscCodegenMethods}; @@ -401,7 +401,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>( enum_type_and_layout: TyAndLayout<'tcx>, enum_type_di_node: &'ll DIType, variant_indices: impl Iterator + Clone, - tag_field: usize, + tag_field: FieldIdx, untagged_variant_index: Option, ) -> SmallVec<&'ll DIType> { let tag_base_type = tag_base_type(cx.tcx, enum_type_and_layout); @@ -805,7 +805,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>( variant_field_infos: &[VariantFieldInfo<'ll>], discr_type_di_node: &'ll DIType, tag_base_type: Ty<'tcx>, - tag_field: usize, + tag_field: FieldIdx, untagged_variant_index: Option, di_flags: DIFlags, ) -> SmallVec<&'ll DIType> { @@ -858,7 +858,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>( })); assert_eq!( - cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty), + cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field.as_usize()).ty), cx.size_and_align_of(self::tag_base_type(cx.tcx, enum_type_and_layout)) ); @@ -875,7 +875,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>( Endian::Big => (8, 0), }; - let tag_field_offset = enum_type_and_layout.fields.offset(tag_field).bytes(); + let tag_field_offset = enum_type_and_layout.fields.offset(tag_field.as_usize()).bytes(); let lo_offset = Size::from_bytes(tag_field_offset + lo_offset); let hi_offset = Size::from_bytes(tag_field_offset + hi_offset); @@ -905,8 +905,8 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>( cx, enum_type_di_node, TAG_FIELD_NAME, - enum_type_and_layout.field(cx, tag_field), - enum_type_and_layout.fields.offset(tag_field), + enum_type_and_layout.field(cx, tag_field.as_usize()), + enum_type_and_layout.fields.offset(tag_field.as_usize()), di_flags, tag_base_type_di_node, None, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index 20a841f2287..62d38d463ab 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -373,7 +373,7 @@ fn build_discr_member_di_node<'ll, 'tcx>( file, UNKNOWN_LINE_NUMBER, layout, - enum_or_coroutine_type_and_layout.fields.offset(tag_field), + enum_or_coroutine_type_and_layout.fields.offset(tag_field.as_usize()), DIFlags::FlagArtificial, ty, )) diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index eade9e52de9..b7f2277bfda 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -462,10 +462,10 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let tag_op = match self.val { OperandValue::ZeroSized => bug!(), OperandValue::Immediate(_) | OperandValue::Pair(_, _) => { - self.extract_field(fx, bx, tag_field) + self.extract_field(fx, bx, tag_field.as_usize()) } OperandValue::Ref(place) => { - let tag = place.with_type(self.layout).project_field(bx, tag_field); + let tag = place.with_type(self.layout).project_field(bx, tag_field.as_usize()); bx.load_operand(tag) } }; diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 31db7fa9a18..937063c24a6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -250,7 +250,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { Variants::Single { index } => assert_eq!(index, variant_index), Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => { - let ptr = self.project_field(bx, tag_field); + let ptr = self.project_field(bx, tag_field.as_usize()); let to = self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val; bx.store_to_place( @@ -265,7 +265,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { .. } => { if variant_index != untagged_variant { - let niche = self.project_field(bx, tag_field); + let niche = self.project_field(bx, tag_field.as_usize()); let niche_llty = bx.cx().immediate_backend_type(niche.layout); let BackendRepr::Scalar(scalar) = niche.layout.backend_repr else { bug!("expected a scalar placeref for the niche"); diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 2f0b1cb6d1e..020cd65d75d 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -1,6 +1,6 @@ //! Functions for reading and writing discriminants of multi-variant layouts (enums and coroutines). -use rustc_abi::{self as abi, TagEncoding, VariantIdx, Variants}; +use rustc_abi::{self as abi, FieldIdx, TagEncoding, VariantIdx, Variants}; use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout}; use rustc_middle::ty::{self, CoroutineArgsExt, ScalarInt, Ty}; use rustc_middle::{mir, span_bug}; @@ -26,7 +26,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // No need to validate that the discriminant here because the // `TyAndLayout::for_variant()` call earlier already checks the // variant is valid. - let tag_dest = self.project_field(dest, tag_field)?; + let tag_dest = self.project_field(dest, tag_field.as_usize())?; self.write_scalar(tag, &tag_dest) } None => { @@ -96,7 +96,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let tag_layout = self.layout_of(tag_scalar_layout.primitive().to_int_ty(*self.tcx))?; // Read tag and sanity-check `tag_layout`. - let tag_val = self.read_immediate(&self.project_field(op, tag_field)?)?; + let tag_val = self.read_immediate(&self.project_field(op, tag_field.as_usize())?)?; assert_eq!(tag_layout.size, tag_val.layout.size); assert_eq!(tag_layout.backend_repr.is_signed(), tag_val.layout.backend_repr.is_signed()); trace!("tag value: {}", tag_val); @@ -231,7 +231,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &self, layout: TyAndLayout<'tcx>, variant_index: VariantIdx, - ) -> InterpResult<'tcx, Option<(ScalarInt, usize)>> { + ) -> InterpResult<'tcx, Option<(ScalarInt, FieldIdx)>> { // Layout computation excludes uninhabited variants from consideration. // Therefore, there's no way to represent those variants in the given layout. // Essentially, uninhabited variants do not have a tag that corresponds to their diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 8f39afa642a..7d76d925ef2 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -294,7 +294,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // First, check if we are projecting to a variant. match layout.variants { Variants::Multiple { tag_field, .. } => { - if tag_field == field { + if tag_field.as_usize() == field { return match layout.ty.kind() { ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag, ty::Coroutine(..) => PathElem::CoroutineTag, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 7ebfebea44e..c2ae6b06192 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -934,7 +934,7 @@ where .unwrap(), ), Variants::Multiple { tag, tag_field, .. } => { - if i == tag_field { + if FieldIdx::from_usize(i) == tag_field { return TyMaybeWithLayout::TyAndLayout(tag_layout(tag)); } TyMaybeWithLayout::Ty(args.as_coroutine().prefix_tys()[i]) @@ -1060,8 +1060,10 @@ where tag_field, variants, .. - } if variants.len() == 2 && this.fields.offset(*tag_field) == offset => { - let tagged_variant = if untagged_variant.as_u32() == 0 { + } if variants.len() == 2 + && this.fields.offset(tag_field.as_usize()) == offset => + { + let tagged_variant = if *untagged_variant == VariantIdx::ZERO { VariantIdx::from_u32(1) } else { VariantIdx::from_u32(0) diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 06dfaf079a3..64901ee0502 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -180,7 +180,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Variants( // However, if the discriminant is placed past the end of the variant, then we need // to factor in the size of the discriminant manually. This really should be refactored // better, but this "works" for now. - if layout.fields.offset(tag_field) >= variant_size { + if layout.fields.offset(tag_field.as_usize()) >= variant_size { variant_size += match tag_encoding { TagEncoding::Direct => tag.size(cx), _ => Size::ZERO, -- cgit 1.4.1-3-g733a5 From be70a4b16e08de96fb221904bfe8abd72419abf1 Mon Sep 17 00:00:00 2001 From: Rageking8 <106309953+Rageking8@users.noreply.github.com> Date: Wed, 4 Jun 2025 16:16:29 +0800 Subject: Fix incorrect use of "recommend" over "recommended" --- src/doc/rustc/src/codegen-options/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 95e6afae8a1..bb109adf76f 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -192,7 +192,7 @@ to save information after compiling a crate to be reused when recompiling the crate, improving re-compile times. This takes a path to a directory where incremental files will be stored. -Using incremental compilation inhibits certain optimizations (for example by increasing the amount of codegen units) and is therefore not recommend for release builds. +Using incremental compilation inhibits certain optimizations (for example by increasing the amount of codegen units) and is therefore not recommended for release builds. ## inline-threshold -- cgit 1.4.1-3-g733a5 From d88c6dbb30219385fc56ad92efc4786d11ddc1f1 Mon Sep 17 00:00:00 2001 From: Derukugi <159861671+Derukugis@users.noreply.github.com> Date: Mon, 2 Jun 2025 19:24:14 +1000 Subject: Add link to correct documentation in htmldocck.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix typo in src/etc/htmldocck.py Co-authored-by: León Orell Valerian Liehr Change documentation link to the correct section in src/etc/htmldocck.py Co-authored-by: León Orell Valerian Liehr Remove all top-level docs from htmldocck.py --- src/etc/htmldocck.py | 116 +-------------------------------------------------- 1 file changed, 2 insertions(+), 114 deletions(-) diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index 06fc6518e3b..1806e2be9bb 100755 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -2,120 +2,8 @@ # -*- coding: utf-8 -*- r""" -htmldocck.py is a custom checker script for Rustdoc HTML outputs. - -# How and why? - -The principle is simple: This script receives a path to generated HTML -documentation and a "template" script, which has a series of check -commands like `@has` or `@matches`. Each command is used to check if -some pattern is present or not present in the particular file or in -a particular node of the HTML tree. In many cases, the template script -happens to be the source code given to rustdoc. - -While it indeed is possible to test in smaller portions, it has been -hard to construct tests in this fashion and major rendering errors were -discovered much later. This script is designed to make black-box and -regression testing of Rustdoc easy. This does not preclude the needs for -unit testing, but can be used to complement related tests by quickly -showing the expected renderings. - -In order to avoid one-off dependencies for this task, this script uses -a reasonably working HTML parser and the existing XPath implementation -from Python's standard library. Hopefully, we won't render -non-well-formed HTML. - -# Commands - -Commands start with an `@` followed by a command name (letters and -hyphens), and zero or more arguments separated by one or more whitespace -characters and optionally delimited with single or double quotes. The `@` -mark cannot be preceded by a non-whitespace character. Other lines -(including every text up to the first `@`) are ignored, but it is -recommended to avoid the use of `@` in the template file. - -There are a number of supported commands: - -* `@has PATH` checks for the existence of the given file. - - `PATH` is relative to the output directory. It can be given as `-` - which repeats the most recently used `PATH`. - -* `@hasraw PATH PATTERN` and `@matchesraw PATH PATTERN` checks - for the occurrence of the given pattern `PATTERN` in the specified file. - Only one occurrence of the pattern is enough. - - For `@hasraw`, `PATTERN` is a whitespace-normalized (every consecutive - whitespace being replaced by one single space character) string. - The entire file is also whitespace-normalized including newlines. - - For `@matchesraw`, `PATTERN` is a Python-supported regular expression. - The file remains intact but the regexp is matched without the `MULTILINE` - and `IGNORECASE` options. You can still use a prefix `(?m)` or `(?i)` - to override them, and `\A` and `\Z` for definitely matching - the beginning and end of the file. - - (The same distinction goes to other variants of these commands.) - -* `@has PATH XPATH PATTERN` and `@matches PATH XPATH PATTERN` checks for - the presence of the given XPath `XPATH` in the specified HTML file, - and also the occurrence of the given pattern `PATTERN` in the matching - node or attribute. Only one occurrence of the pattern in the match - is enough. - - `PATH` should be a valid and well-formed HTML file. It does *not* - accept arbitrary HTML5; it should have matching open and close tags - and correct entity references at least. - - `XPATH` is an XPath expression to match. The XPath is fairly limited: - `tag`, `*`, `.`, `//`, `..`, `[@attr]`, `[@attr='value']`, `[tag]`, - `[POS]` (element located in given `POS`), `[last()-POS]`, `text()` - and `@attr` (both as the last segment) are supported. Some examples: - - - `//pre` or `.//pre` matches any element with a name `pre`. - - `//a[@href]` matches any element with an `href` attribute. - - `//*[@class="impl"]//code` matches any element with a name `code`, - which is an ancestor of some element which `class` attr is `impl`. - - `//h1[@class="fqn"]/span[1]/a[last()]/@class` matches a value of - `class` attribute in the last `a` element (can be followed by more - elements that are not `a`) inside the first `span` in the `h1` with - a class of `fqn`. Note that there cannot be any additional elements - between them due to the use of `/` instead of `//`. - - Do not try to use non-absolute paths, it won't work due to the flawed - ElementTree implementation. The script rejects them. - - For the text matches (i.e. paths not ending with `@attr`), any - subelements are flattened into one string; this is handy for ignoring - highlights for example. If you want to simply check for the presence of - a given node or attribute, use an empty string (`""`) as a `PATTERN`. - -* `@count PATH XPATH COUNT` checks for the occurrence of the given XPath - in the specified file. The number of occurrences must match the given - count. - -* `@count PATH XPATH TEXT COUNT` checks for the occurrence of the given XPath - with the given text in the specified file. The number of occurrences must - match the given count. - -* `@snapshot NAME PATH XPATH` creates a snapshot test named NAME. - A snapshot test captures a subtree of the DOM, at the location - determined by the XPath, and compares it to a pre-recorded value - in a file. The file's name is the test's name with the `.rs` extension - replaced with `.NAME.html`, where NAME is the snapshot's name. - - htmldocck supports the `--bless` option to accept the current subtree - as expected, saving it to the file determined by the snapshot's name. - compiletest's `--bless` flag is forwarded to htmldocck. - -* `@has-dir PATH` checks for the existence of the given directory. - -* `@files FOLDER_PATH [ENTRIES]`, checks that `FOLDER_PATH` contains exactly - `[ENTRIES]`. - -All conditions can be negated with `!`. `@!has foo/type.NoSuch.html` -checks if the given file does not exist, for example. - +For documentation and usage instructions, please see +https://rustc-dev-guide.rust-lang.org/rustdoc-internals/rustdoc-test-suite.html """ from __future__ import absolute_import, print_function, unicode_literals -- cgit 1.4.1-3-g733a5 From f455c4fc39bcc04d104bc440ebc1c23f183f20f9 Mon Sep 17 00:00:00 2001 From: Amanda Stjerna Date: Fri, 2 May 2025 10:50:03 +0200 Subject: Use an enum for SCC representatives, plus other code review Co-authored-by: lcnr --- .../rustc_borrowck/src/eliminate_placeholders.rs | 371 --------------------- compiler/rustc_borrowck/src/handle_placeholders.rs | 348 +++++++++++++++++++ compiler/rustc_borrowck/src/lib.rs | 2 +- compiler/rustc_borrowck/src/nll.rs | 4 +- compiler/rustc_borrowck/src/polonius/legacy/mod.rs | 2 +- .../rustc_borrowck/src/region_infer/dump_mir.rs | 2 +- compiler/rustc_borrowck/src/region_infer/mod.rs | 90 +++-- .../src/region_infer/opaque_types.rs | 2 +- 8 files changed, 408 insertions(+), 413 deletions(-) delete mode 100644 compiler/rustc_borrowck/src/eliminate_placeholders.rs create mode 100644 compiler/rustc_borrowck/src/handle_placeholders.rs diff --git a/compiler/rustc_borrowck/src/eliminate_placeholders.rs b/compiler/rustc_borrowck/src/eliminate_placeholders.rs deleted file mode 100644 index e8e1acbd7a5..00000000000 --- a/compiler/rustc_borrowck/src/eliminate_placeholders.rs +++ /dev/null @@ -1,371 +0,0 @@ -//! Logic for lowering higher-kinded outlives constraints -//! (with placeholders and universes) and turn them into regular -//! outlives constraints. -//! -//! This logic is provisional and should be removed once the trait -//! solver can handle this kind of constraint. -use rustc_data_structures::frozen::Frozen; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_data_structures::graph::scc; -use rustc_data_structures::graph::scc::Sccs; -use rustc_index::IndexVec; -use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::{RegionVid, UniverseIndex}; -use tracing::debug; - -use crate::constraints::{ConstraintSccIndex, OutlivesConstraintSet}; -use crate::consumers::OutlivesConstraint; -use crate::diagnostics::UniverseInfo; -use crate::member_constraints::MemberConstraintSet; -use crate::region_infer::values::{LivenessValues, PlaceholderIndices}; -use crate::region_infer::{ConstraintSccs, RegionDefinition, TypeTest}; -use crate::ty::VarianceDiagInfo; -use crate::type_check::free_region_relations::UniversalRegionRelations; -use crate::type_check::{Locations, MirTypeckRegionConstraints}; -use crate::universal_regions::UniversalRegions; -use crate::{BorrowckInferCtxt, NllRegionVariableOrigin}; - -/// A set of outlives constraints after rewriting to remove -/// higher-kinded constraints. -pub(crate) struct LoweredConstraints<'tcx> { - pub(crate) constraint_sccs: Sccs, - pub(crate) definitions: Frozen>>, - pub(crate) scc_annotations: IndexVec, - pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>, - pub(crate) outlives_constraints: OutlivesConstraintSet<'tcx>, - pub(crate) type_tests: Vec>, - pub(crate) liveness_constraints: LivenessValues, - pub(crate) universe_causes: FxIndexMap>, - pub(crate) placeholder_indices: PlaceholderIndices, -} - -impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> { - pub(crate) fn init(definitions: &'d IndexVec>) -> Self { - Self { scc_to_annotation: IndexVec::new(), definitions } - } -} - -/// A Visitor for SCC annotation construction. -pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> { - pub(crate) scc_to_annotation: IndexVec, - definitions: &'d IndexVec>, -} - -impl scc::Annotations for SccAnnotations<'_, '_, RegionTracker> { - fn new(&self, element: RegionVid) -> RegionTracker { - RegionTracker::new(element, &self.definitions[element]) - } - - fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: RegionTracker) { - let idx = self.scc_to_annotation.push(annotation); - assert!(idx == scc); - } - - type Ann = RegionTracker; - type SccIdx = ConstraintSccIndex; -} - -/// An annotation for region graph SCCs that tracks -/// the values of its elements. This annotates a single SCC. -#[derive(Copy, Debug, Clone)] -pub(crate) struct RegionTracker { - /// The largest universe of a placeholder reached from this SCC. - /// This includes placeholders within this SCC. - max_placeholder_universe_reached: UniverseIndex, - - /// The smallest universe index reachable form the nodes of this SCC. - min_reachable_universe: UniverseIndex, - - /// The representative Region Variable Id for this SCC. We prefer - /// placeholders over existentially quantified variables, otherwise - /// it's the one with the smallest Region Variable ID. - pub(crate) representative: RegionVid, - - /// Is the current representative a placeholder? - representative_is_placeholder: bool, - - /// Is the current representative existentially quantified? - representative_is_existential: bool, -} - -impl RegionTracker { - pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self { - let (representative_is_placeholder, representative_is_existential) = match definition.origin - { - NllRegionVariableOrigin::FreeRegion => (false, false), - NllRegionVariableOrigin::Placeholder(_) => (true, false), - NllRegionVariableOrigin::Existential { .. } => (false, true), - }; - - let placeholder_universe = - if representative_is_placeholder { definition.universe } else { UniverseIndex::ROOT }; - - Self { - max_placeholder_universe_reached: placeholder_universe, - min_reachable_universe: definition.universe, - representative: rvid, - representative_is_placeholder, - representative_is_existential, - } - } - - /// The smallest-indexed universe reachable from and/or in this SCC. - pub(crate) fn min_universe(self) -> UniverseIndex { - self.min_reachable_universe - } - - fn merge_min_max_seen(&mut self, other: &Self) { - self.max_placeholder_universe_reached = std::cmp::max( - self.max_placeholder_universe_reached, - other.max_placeholder_universe_reached, - ); - - self.min_reachable_universe = - std::cmp::min(self.min_reachable_universe, other.min_reachable_universe); - } - - /// Returns `true` if during the annotated SCC reaches a placeholder - /// with a universe larger than the smallest reachable one, `false` otherwise. - pub(crate) fn has_incompatible_universes(&self) -> bool { - self.min_universe().cannot_name(self.max_placeholder_universe_reached) - } - - /// Determine if the tracked universes of the two SCCs - /// are compatible. - pub(crate) fn universe_compatible_with(&self, other: Self) -> bool { - self.min_universe().can_name(other.min_universe()) - || self.min_universe().can_name(other.max_placeholder_universe_reached) - } -} - -impl scc::Annotation for RegionTracker { - fn merge_scc(mut self, mut other: Self) -> Self { - // Prefer any placeholder over any existential - if other.representative_is_placeholder && self.representative_is_existential { - other.merge_min_max_seen(&self); - return other; - } - - if self.representative_is_placeholder && other.representative_is_existential - || (self.representative <= other.representative) - { - self.merge_min_max_seen(&other); - return self; - } - other.merge_min_max_seen(&self); - other - } - - fn merge_reached(mut self, other: Self) -> Self { - // No update to in-component values, only add seen values. - self.merge_min_max_seen(&other); - self - } -} - -/// Determines if the region variable definitions contain -/// placeholers, and compute them for later use. -fn region_definitions<'tcx>( - universal_regions: &UniversalRegions<'tcx>, - infcx: &BorrowckInferCtxt<'tcx>, -) -> (Frozen>>, bool) { - let var_infos = infcx.get_region_var_infos(); - // Create a RegionDefinition for each inference variable. This happens here because - // it allows us to sneak in a cheap check for placeholders. Otherwise, its proper home - // is in `RegionInferenceContext::new()`, probably. - let mut definitions = IndexVec::with_capacity(var_infos.len()); - let mut has_placeholders = false; - - for info in var_infos.iter() { - let definition = RegionDefinition::new(info); - has_placeholders |= matches!(definition.origin, NllRegionVariableOrigin::Placeholder(_)); - definitions.push(definition); - } - - // Add external names from universal regions in fun function definitions. - for (external_name, variable) in universal_regions.named_universal_regions_iter() { - debug!("region {:?} has external name {:?}", variable, external_name); - definitions[variable].external_name = Some(external_name); - } - (Frozen::freeze(definitions), has_placeholders) -} - -/// This method handles Universe errors by rewriting the constraint -/// graph. For each strongly connected component in the constraint -/// graph such that there is a series of constraints -/// A: B: C: ... : X where -/// A's universe is smaller than X's and A is a placeholder, -/// add a constraint that A: 'static. This is a safe upper bound -/// in the face of borrow checker/trait solver limitations that will -/// eventually go away. -/// -/// For a more precise definition, see the documentation for -/// [`RegionTracker`] and its methods!. -/// -/// Since universes can also be involved in errors (if one placeholder -/// transitively outlives another), this function also flags those. -/// -/// Additionally, it similarly rewrites type-tests. -/// -/// This edge case used to be handled during constraint propagation -/// by iterating over the strongly connected components in the constraint -/// graph while maintaining a set of bookkeeping mappings similar -/// to what is stored in `RegionTracker` and manually adding 'sttaic as -/// needed. -/// -/// It was rewritten as part of the Polonius project with the goal of moving -/// higher-kindedness concerns out of the path of the borrow checker, -/// for two reasons: -/// -/// 1. Implementing Polonius is difficult enough without also -/// handling them. -/// 2. The long-term goal is to handle higher-kinded concerns -/// in the trait solver, where they belong. This avoids -/// logic duplication and allows future trait solvers -/// to compute better bounds than for example our -/// "must outlive 'static" here. -/// -/// This code is a stop-gap measure in preparation for the future trait solver. -/// -/// Every constraint added by this method is an internal `IllegalUniverse` constraint. -pub(crate) fn rewrite_higher_kinded_outlives_as_constraints<'tcx>( - constraints: MirTypeckRegionConstraints<'tcx>, - universal_region_relations: &Frozen>, - infcx: &BorrowckInferCtxt<'tcx>, -) -> LoweredConstraints<'tcx> { - let universal_regions = &universal_region_relations.universal_regions; - let (definitions, has_placeholders) = region_definitions(universal_regions, infcx); - - let MirTypeckRegionConstraints { - placeholder_indices, - placeholder_index_to_region: _, - liveness_constraints, - mut outlives_constraints, - mut member_constraints, - universe_causes, - type_tests, - } = constraints; - - if let Some(guar) = universal_regions.tainted_by_errors() { - debug!("Universal regions tainted by errors; removing constraints!"); - // Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all - // outlives bounds that we may end up checking. - outlives_constraints = Default::default(); - member_constraints = Default::default(); - - // Also taint the entire scope. - infcx.set_tainted_by_errors(guar); - } - - let fr_static = universal_regions.fr_static; - let compute_sccs = - |constraints: &OutlivesConstraintSet<'tcx>, - annotations: &mut SccAnnotations<'_, 'tcx, RegionTracker>| { - ConstraintSccs::new_with_annotation( - &constraints.graph(definitions.len()).region_graph(constraints, fr_static), - annotations, - ) - }; - - // This code structure is a bit convoluted because it allows for a planned - // future change where the early return here has a different type of annotation - // that does much less work. - if !has_placeholders { - debug!("No placeholder regions found; skipping rewriting logic!"); - let mut scc_annotations = SccAnnotations::init(&definitions); - let constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations); - - return LoweredConstraints { - type_tests, - member_constraints, - constraint_sccs, - scc_annotations: scc_annotations.scc_to_annotation, - definitions, - outlives_constraints, - liveness_constraints, - universe_causes, - placeholder_indices, - }; - } - debug!("Placeholders present; activating placeholder handling logic!"); - - let mut annotations = SccAnnotations::init(&definitions); - let sccs = compute_sccs(&outlives_constraints, &mut annotations); - - let outlives_static = - rewrite_outlives(&sccs, &annotations, fr_static, &mut outlives_constraints); - - let (sccs, scc_annotations) = if !outlives_static.is_empty() { - debug!("The following SCCs had :'static constraints added: {:?}", outlives_static); - let mut annotations = SccAnnotations::init(&definitions); - - // We changed the constraint set and so must recompute SCCs. - // Optimisation opportunity: if we can add them incrementally (and that's - // possible because edges to 'static always only merge SCCs into 'static), - // we would potentially save a lot of work here. - (compute_sccs(&outlives_constraints, &mut annotations), annotations.scc_to_annotation) - } else { - // If we didn't add any back-edges; no more work needs doing - debug!("No constraints rewritten!"); - (sccs, annotations.scc_to_annotation) - }; - - LoweredConstraints { - constraint_sccs: sccs, - definitions, - scc_annotations, - member_constraints, - outlives_constraints, - type_tests, - liveness_constraints, - universe_causes, - placeholder_indices, - } -} - -fn rewrite_outlives<'tcx>( - sccs: &Sccs, - annotations: &SccAnnotations<'_, '_, RegionTracker>, - fr_static: RegionVid, - outlives_constraints: &mut OutlivesConstraintSet<'tcx>, -) -> FxHashSet { - // Changed to `true` if we added any constraints to `self` and need to - // recompute SCCs. - let mut outlives_static = FxHashSet::default(); - - let annotations = &annotations.scc_to_annotation; - - for scc in sccs.all_sccs() { - // No point in adding 'static: 'static! - // This micro-optimisation makes somewhat sense - // because static outlives *everything*. - if scc == sccs.scc(fr_static) { - continue; - } - - let annotation = annotations[scc]; - - // If this SCC participates in a universe violation, - // e.g. if it reaches a region with a universe smaller than - // the largest region reached, add a requirement that it must - // outlive `'static`. - if annotation.has_incompatible_universes() { - // Optimisation opportunity: this will add more constraints than - // needed for correctness, since an SCC upstream of another with - // a universe violation will "infect" its downstream SCCs to also - // outlive static. - outlives_static.insert(scc); - let scc_representative_outlives_static = OutlivesConstraint { - sup: annotation.representative, - sub: fr_static, - category: ConstraintCategory::IllegalUniverse, - locations: Locations::All(rustc_span::DUMMY_SP), - span: rustc_span::DUMMY_SP, - variance_info: VarianceDiagInfo::None, - from_closure: false, - }; - outlives_constraints.push(scc_representative_outlives_static); - } - } - outlives_static -} diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs new file mode 100644 index 00000000000..aaaf2f45c86 --- /dev/null +++ b/compiler/rustc_borrowck/src/handle_placeholders.rs @@ -0,0 +1,348 @@ +//! Logic for lowering higher-kinded outlives constraints +//! (with placeholders and universes) and turn them into regular +//! outlives constraints. + +use rustc_data_structures::frozen::Frozen; +use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::graph::scc; +use rustc_data_structures::graph::scc::Sccs; +use rustc_index::IndexVec; +use rustc_infer::infer::RegionVariableOrigin; +use rustc_middle::mir::ConstraintCategory; +use rustc_middle::ty::{RegionVid, UniverseIndex}; +use tracing::debug; + +use crate::constraints::{ConstraintSccIndex, OutlivesConstraintSet}; +use crate::consumers::OutlivesConstraint; +use crate::diagnostics::UniverseInfo; +use crate::member_constraints::MemberConstraintSet; +use crate::region_infer::values::{LivenessValues, PlaceholderIndices}; +use crate::region_infer::{ConstraintSccs, RegionDefinition, Representative, TypeTest}; +use crate::ty::VarianceDiagInfo; +use crate::type_check::free_region_relations::UniversalRegionRelations; +use crate::type_check::{Locations, MirTypeckRegionConstraints}; +use crate::universal_regions::UniversalRegions; +use crate::{BorrowckInferCtxt, NllRegionVariableOrigin}; + +/// A set of outlives constraints after rewriting to remove +/// higher-kinded constraints. +pub(crate) struct LoweredConstraints<'tcx> { + pub(crate) constraint_sccs: Sccs, + pub(crate) definitions: Frozen>>, + pub(crate) scc_annotations: IndexVec, + pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>, + pub(crate) outlives_constraints: Frozen>, + pub(crate) type_tests: Vec>, + pub(crate) liveness_constraints: LivenessValues, + pub(crate) universe_causes: FxIndexMap>, + pub(crate) placeholder_indices: PlaceholderIndices, +} + +impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> { + pub(crate) fn init(definitions: &'d IndexVec>) -> Self { + Self { scc_to_annotation: IndexVec::new(), definitions } + } +} + +/// A Visitor for SCC annotation construction. +pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> { + pub(crate) scc_to_annotation: IndexVec, + definitions: &'d IndexVec>, +} + +impl scc::Annotations for SccAnnotations<'_, '_, RegionTracker> { + fn new(&self, element: RegionVid) -> RegionTracker { + RegionTracker::new(element, &self.definitions[element]) + } + + fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: RegionTracker) { + let idx = self.scc_to_annotation.push(annotation); + assert!(idx == scc); + } + + type Ann = RegionTracker; + type SccIdx = ConstraintSccIndex; +} + +/// An annotation for region graph SCCs that tracks +/// the values of its elements. This annotates a single SCC. +#[derive(Copy, Debug, Clone)] +pub(crate) struct RegionTracker { + /// The largest universe of a placeholder reached from this SCC. + /// This includes placeholders within this SCC. + max_placeholder_universe_reached: UniverseIndex, + + /// The largest universe nameable from this SCC. + /// It is the smallest nameable universes of all + /// existential regions reachable from it. + max_nameable_universe: UniverseIndex, + + /// The representative Region Variable Id for this SCC. + pub(crate) representative: Representative, +} + +impl RegionTracker { + pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self { + let placeholder_universe = + if matches!(definition.origin, NllRegionVariableOrigin::Placeholder(_)) { + definition.universe + } else { + UniverseIndex::ROOT + }; + + Self { + max_placeholder_universe_reached: placeholder_universe, + max_nameable_universe: definition.universe, + representative: Representative::new(rvid, definition), + } + } + + /// The largest universe this SCC can name. It's the smallest + /// largest nameable uninverse of any reachable region. + pub(crate) fn max_nameable_universe(self) -> UniverseIndex { + self.max_nameable_universe + } + + fn merge_min_max_seen(&mut self, other: &Self) { + self.max_placeholder_universe_reached = std::cmp::max( + self.max_placeholder_universe_reached, + other.max_placeholder_universe_reached, + ); + + self.max_nameable_universe = + std::cmp::min(self.max_nameable_universe, other.max_nameable_universe); + } + + /// Returns `true` if during the annotated SCC reaches a placeholder + /// with a universe larger than the smallest nameable universe of any + /// reachable existential region. + pub(crate) fn has_incompatible_universes(&self) -> bool { + self.max_nameable_universe().cannot_name(self.max_placeholder_universe_reached) + } + + /// Determine if the tracked universes of the two SCCs are compatible. + pub(crate) fn universe_compatible_with(&self, other: Self) -> bool { + self.max_nameable_universe().can_name(other.max_nameable_universe()) + || self.max_nameable_universe().can_name(other.max_placeholder_universe_reached) + } +} + +impl scc::Annotation for RegionTracker { + fn merge_scc(mut self, other: Self) -> Self { + self.representative = self.representative.merge_scc(other.representative); + self.merge_min_max_seen(&other); + self + } + + fn merge_reached(mut self, other: Self) -> Self { + // No update to in-component values, only add seen values. + self.merge_min_max_seen(&other); + self + } +} + +/// Determines if the region variable definitions contain +/// placeholders, and compute them for later use. +fn region_definitions<'tcx>( + universal_regions: &UniversalRegions<'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, +) -> (Frozen>>, bool) { + let var_infos = infcx.get_region_var_infos(); + // Create a RegionDefinition for each inference variable. This happens here because + // it allows us to sneak in a cheap check for placeholders. Otherwise, its proper home + // is in `RegionInferenceContext::new()`, probably. + let mut definitions = IndexVec::with_capacity(var_infos.len()); + let mut has_placeholders = false; + + for info in var_infos.iter() { + let origin = match info.origin { + RegionVariableOrigin::Nll(origin) => origin, + _ => NllRegionVariableOrigin::Existential { from_forall: false }, + }; + + let definition = RegionDefinition { origin, universe: info.universe, external_name: None }; + + has_placeholders |= matches!(origin, NllRegionVariableOrigin::Placeholder(_)); + definitions.push(definition); + } + + // Add external names from universal regions in fun function definitions. + // FIXME: this two-step method is annoying, but I don't know how to avoid it. + for (external_name, variable) in universal_regions.named_universal_regions_iter() { + debug!("region {:?} has external name {:?}", variable, external_name); + definitions[variable].external_name = Some(external_name); + } + (Frozen::freeze(definitions), has_placeholders) +} + +/// This method handles placeholders by rewriting the constraint +/// graph. For each strongly connected component in the constraint +/// graph such that there is a series of constraints +/// A: B: C: ... : X where +/// A contains a placeholder whose universe cannot be named by X, +/// add a constraint that A: 'static. This is a safe upper bound +/// in the face of borrow checker/trait solver limitations that will +/// eventually go away. +/// +/// For a more precise definition, see the documentation for +/// [`RegionTracker`] and its methods! +/// +/// This edge case used to be handled during constraint propagation. +/// It was rewritten as part of the Polonius project with the goal of moving +/// higher-kindedness concerns out of the path of the borrow checker, +/// for two reasons: +/// +/// 1. Implementing Polonius is difficult enough without also +/// handling them. +/// 2. The long-term goal is to handle higher-kinded concerns +/// in the trait solver, where they belong. This avoids +/// logic duplication and allows future trait solvers +/// to compute better bounds than for example our +/// "must outlive 'static" here. +/// +/// This code is a stop-gap measure in preparation for the future trait solver. +/// +/// Every constraint added by this method is an internal `IllegalUniverse` constraint. +pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>( + constraints: MirTypeckRegionConstraints<'tcx>, + universal_region_relations: &Frozen>, + infcx: &BorrowckInferCtxt<'tcx>, +) -> LoweredConstraints<'tcx> { + let universal_regions = &universal_region_relations.universal_regions; + let (definitions, has_placeholders) = region_definitions(universal_regions, infcx); + + let MirTypeckRegionConstraints { + placeholder_indices, + placeholder_index_to_region: _, + liveness_constraints, + mut outlives_constraints, + mut member_constraints, + universe_causes, + type_tests, + } = constraints; + + if let Some(guar) = universal_regions.tainted_by_errors() { + debug!("Universal regions tainted by errors; removing constraints!"); + // Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all + // outlives bounds that we may end up checking. + outlives_constraints = Default::default(); + member_constraints = Default::default(); + + // Also taint the entire scope. + infcx.set_tainted_by_errors(guar); + } + + let fr_static = universal_regions.fr_static; + let compute_sccs = + |constraints: &OutlivesConstraintSet<'tcx>, + annotations: &mut SccAnnotations<'_, 'tcx, RegionTracker>| { + ConstraintSccs::new_with_annotation( + &constraints.graph(definitions.len()).region_graph(constraints, fr_static), + annotations, + ) + }; + + let mut scc_annotations = SccAnnotations::init(&definitions); + let constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations); + + // This code structure is a bit convoluted because it allows for a planned + // future change where the early return here has a different type of annotation + // that does much less work. + if !has_placeholders { + debug!("No placeholder regions found; skipping rewriting logic!"); + + return LoweredConstraints { + type_tests, + member_constraints, + constraint_sccs, + scc_annotations: scc_annotations.scc_to_annotation, + definitions, + outlives_constraints: Frozen::freeze(outlives_constraints), + liveness_constraints, + universe_causes, + placeholder_indices, + }; + } + debug!("Placeholders present; activating placeholder handling logic!"); + + let added_constraints = rewrite_placeholder_outlives( + &constraint_sccs, + &scc_annotations, + fr_static, + &mut outlives_constraints, + ); + + let (constraint_sccs, scc_annotations) = if added_constraints { + let mut annotations = SccAnnotations::init(&definitions); + + // We changed the constraint set and so must recompute SCCs. + // Optimisation opportunity: if we can add them incrementally (and that's + // possible because edges to 'static always only merge SCCs into 'static), + // we would potentially save a lot of work here. + (compute_sccs(&outlives_constraints, &mut annotations), annotations.scc_to_annotation) + } else { + // If we didn't add any back-edges; no more work needs doing + debug!("No constraints rewritten!"); + (constraint_sccs, scc_annotations.scc_to_annotation) + }; + + LoweredConstraints { + constraint_sccs, + definitions, + scc_annotations, + member_constraints, + outlives_constraints: Frozen::freeze(outlives_constraints), + type_tests, + liveness_constraints, + universe_causes, + placeholder_indices, + } +} + +fn rewrite_placeholder_outlives<'tcx>( + sccs: &Sccs, + annotations: &SccAnnotations<'_, '_, RegionTracker>, + fr_static: RegionVid, + outlives_constraints: &mut OutlivesConstraintSet<'tcx>, +) -> bool { + // Changed to `true` if we added any constraints and need to + // recompute SCCs. + let mut added_constraints = false; + + let annotations = &annotations.scc_to_annotation; + + for scc in sccs.all_sccs() { + // No point in adding 'static: 'static! + // This micro-optimisation makes somewhat sense + // because static outlives *everything*. + if scc == sccs.scc(fr_static) { + continue; + } + + let annotation = annotations[scc]; + + // If this SCC participates in a universe violation, + // e.g. if it reaches a region with a universe smaller than + // the largest region reached, add a requirement that it must + // outlive `'static`. + if annotation.has_incompatible_universes() { + // Optimisation opportunity: this will add more constraints than + // needed for correctness, since an SCC upstream of another with + // a universe violation will "infect" its downstream SCCs to also + // outlive static. + let scc_representative_outlives_static = OutlivesConstraint { + sup: annotation.representative.rvid(), + sub: fr_static, + category: ConstraintCategory::IllegalUniverse, + locations: Locations::All(rustc_span::DUMMY_SP), + span: rustc_span::DUMMY_SP, + variance_info: VarianceDiagInfo::None, + from_closure: false, + }; + outlives_constraints.push(scc_representative_outlives_static); + added_constraints = true; + debug!("Added {:?}: 'static!", annotation.representative.rvid()); + } + } + added_constraints +} diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index edf5494e886..8c4d5c0debe 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -75,7 +75,7 @@ mod constraints; mod dataflow; mod def_use; mod diagnostics; -mod eliminate_placeholders; +mod handle_placeholders; mod member_constraints; mod nll; mod path_utils; diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 9b1a5df8d06..66ab39476b1 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -22,7 +22,7 @@ use tracing::{debug, instrument}; use crate::borrow_set::BorrowSet; use crate::consumers::ConsumerOptions; use crate::diagnostics::RegionErrors; -use crate::eliminate_placeholders::rewrite_higher_kinded_outlives_as_constraints; +use crate::handle_placeholders::compute_sccs_applying_placeholder_outlives_constraints; use crate::polonius::PoloniusDiagnosticsContext; use crate::polonius::legacy::{ PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput, @@ -118,7 +118,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( Rc::clone(&location_map), ); - let lowered_constraints = rewrite_higher_kinded_outlives_as_constraints( + let lowered_constraints = compute_sccs_applying_placeholder_outlives_constraints( constraints, &universal_region_relations, infcx, diff --git a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs index 67da43ca578..05fd6e39476 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs @@ -13,7 +13,7 @@ use tracing::debug; use crate::borrow_set::BorrowSet; use crate::constraints::OutlivesConstraint; -use crate::eliminate_placeholders::LoweredConstraints; +use crate::handle_placeholders::LoweredConstraints; use crate::type_check::free_region_relations::UniversalRegionRelations; use crate::universal_regions::UniversalRegions; diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs index ef3d6309c19..a9ab30fd8fa 100644 --- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs +++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs @@ -46,7 +46,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { "| {r:rw$?} | {ui:4?} | {v}", r = region, rw = REGION_WIDTH, - ui = self.region_universe(region), + ui = self.max_nameable_universe(self.constraint_sccs.scc(region)), v = self.region_value_str(region), )?; } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index cfad071460b..dcb09d5be14 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -4,15 +4,13 @@ use std::rc::Rc; use rustc_data_structures::binary_search_util; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::graph::scc::Sccs; +use rustc_data_structures::graph::scc::{self, Sccs}; use rustc_errors::Diag; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_index::IndexVec; use rustc_infer::infer::outlives::test_type_match; -use rustc_infer::infer::region_constraints::{ - GenericKind, RegionVariableInfo, VerifyBound, VerifyIfEq, -}; -use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; +use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound, VerifyIfEq}; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_middle::bug; use rustc_middle::mir::{ AnnotationSource, BasicBlock, Body, ConstraintCategory, Local, Location, ReturnConstraint, @@ -29,7 +27,7 @@ use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph}; use crate::constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet}; use crate::dataflow::BorrowIndex; use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo}; -use crate::eliminate_placeholders::{LoweredConstraints, RegionTracker}; +use crate::handle_placeholders::{LoweredConstraints, RegionTracker}; use crate::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}; use crate::polonius::LiveLoans; use crate::polonius::legacy::PoloniusOutput; @@ -50,6 +48,47 @@ mod reverse_sccs; pub(crate) mod values; +/// The representative region variable for an SCC, tagged by its origin. +/// We prefer placeholders over existentially quantified variables, otherwise +/// it's the one with the smallest Region Variable ID. In other words, +/// the order of this enumeration really matters! +#[derive(Copy, Debug, Clone, PartialEq, PartialOrd, Eq, Ord)] +pub(crate) enum Representative { + FreeRegion(RegionVid), + Placeholder(RegionVid), + Existential(RegionVid), +} + +impl Representative { + pub(crate) fn rvid(self) -> RegionVid { + match self { + Representative::FreeRegion(region_vid) + | Representative::Placeholder(region_vid) + | Representative::Existential(region_vid) => region_vid, + } + } + + pub(crate) fn new(r: RegionVid, definition: &RegionDefinition<'_>) -> Self { + match definition.origin { + NllRegionVariableOrigin::FreeRegion => Representative::FreeRegion(r), + NllRegionVariableOrigin::Placeholder(_) => Representative::Placeholder(r), + NllRegionVariableOrigin::Existential { .. } => Representative::Existential(r), + } + } +} + +impl scc::Annotation for Representative { + fn merge_scc(self, other: Self) -> Self { + // Just pick the smallest one. Note that we order by tag first! + std::cmp::min(self, other) + } + + // For reachability, we do nothing since the representative doesn't change. + fn merge_reached(self, _other: Self) -> Self { + self + } +} + pub(crate) type ConstraintSccs = Sccs; pub struct RegionInferenceContext<'tcx> { @@ -351,7 +390,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut result = Self { definitions, liveness_constraints, - constraints: Frozen::freeze(outlives_constraints), + constraints: outlives_constraints, constraint_graph, constraint_sccs, scc_annotations, @@ -510,11 +549,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.scc_values.placeholders_contained_in(scc) } - /// Returns access to the value of `r` for debugging purposes. - pub(crate) fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex { - self.scc_universe(self.constraint_sccs.scc(r)) - } - /// Once region solving has completed, this function will return the member constraints that /// were applied to the value of a given SCC `scc`. See `AppliedMemberConstraint`. pub(crate) fn applied_member_constraints( @@ -681,7 +715,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // If the member region lives in a higher universe, we currently choose // the most conservative option by leaving it unchanged. - if !self.scc_universe(scc).is_root() { + if !self.max_nameable_universe(scc).is_root() { return; } @@ -861,7 +895,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { "lower_bound = {:?} r_scc={:?} universe={:?}", lower_bound, r_scc, - self.scc_universe(r_scc) + self.max_nameable_universe(r_scc) ); // If the type test requires that `T: 'a` where `'a` is a // placeholder from another universe, that effectively requires @@ -1339,10 +1373,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - /// The minimum universe of any variable reachable from this - /// SCC, inside or outside of it. - fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex { - self.scc_annotations[scc].min_universe() + /// The largest universe of any region nameable from this SCC. + fn max_nameable_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex { + self.scc_annotations[scc].max_nameable_universe() } /// Checks the final value for the free region `fr` to see if it @@ -1364,7 +1397,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Because this free region must be in the ROOT universe, we // know it cannot contain any bound universes. - assert!(self.scc_universe(longer_fr_scc).is_root()); + assert!(self.max_nameable_universe(longer_fr_scc).is_root()); // Only check all of the relations for the main representative of each // SCC, otherwise just check that we outlive said representative. This @@ -1755,7 +1788,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { #[instrument(skip(self), level = "trace", ret)] pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, location: Location) -> RegionVid { trace!(scc = ?self.constraint_sccs.scc(fr1)); - trace!(universe = ?self.region_universe(fr1)); + trace!(universe = ?self.max_nameable_universe(self.constraint_sccs.scc(fr1))); self.find_constraint_paths_between_regions(fr1, |r| { // First look for some `r` such that `fr1: r` and `r` is live at `location` trace!(?r, liveness_constraints=?self.liveness_constraints.pretty_print_live_points(r)); @@ -2086,7 +2119,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// they *must* be equal (though not having the same repr does not /// mean they are unequal). fn scc_representative(&self, scc: ConstraintSccIndex) -> RegionVid { - self.scc_annotations[scc].representative + self.scc_annotations[scc].representative.rvid() } pub(crate) fn liveness_constraints(&self) -> &LivenessValues { @@ -2108,21 +2141,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } -impl<'tcx> RegionDefinition<'tcx> { - pub(crate) fn new(rv_info: &RegionVariableInfo) -> Self { - // Create a new region definition. Note that, for free - // regions, the `external_name` field gets updated later in - // [[crate::eliminate_placeholders]]. - - let origin = match rv_info.origin { - RegionVariableOrigin::Nll(origin) => origin, - _ => NllRegionVariableOrigin::Existential { from_forall: false }, - }; - - Self { origin, universe: rv_info.universe, external_name: None } - } -} - #[derive(Clone, Debug)] pub(crate) struct BlameConstraint<'tcx> { pub category: ConstraintCategory<'tcx>, diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 550c57338d3..3c05fa2ae0f 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -191,7 +191,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let scc = self.constraint_sccs.scc(vid); // Special handling of higher-ranked regions. - if !self.scc_universe(scc).is_root() { + if !self.max_nameable_universe(scc).is_root() { match self.scc_values.placeholders_contained_in(scc).enumerate().last() { // If the region contains a single placeholder then they're equal. Some((0, placeholder)) => { -- cgit 1.4.1-3-g733a5 From d5a9a005188322cd08dca018402e1593d3a5ebd5 Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Tue, 3 Jun 2025 03:27:21 +0700 Subject: Fix for async drop inside async gen fn --- compiler/rustc_mir_transform/src/coroutine/drop.rs | 34 ++++++++++++++++++---- tests/crashes/140530.rs | 8 ----- .../async-drop/assign-incompatible-types.rs | 9 ++++++ 3 files changed, 37 insertions(+), 14 deletions(-) delete mode 100644 tests/crashes/140530.rs create mode 100644 tests/ui/async-await/async-drop/assign-incompatible-types.rs diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs index 6b266da5a69..625e53f9959 100644 --- a/compiler/rustc_mir_transform/src/coroutine/drop.rs +++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs @@ -382,12 +382,34 @@ pub(super) fn expand_async_drops<'tcx>( dropline_call_bb = Some(drop_call_bb); } - // value needed only for return-yields or gen-coroutines, so just const here - let value = Operand::Constant(Box::new(ConstOperand { - span: body.span, - user_ty: None, - const_: Const::from_bool(tcx, false), - })); + let value = + if matches!(coroutine_kind, CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) + { + // For AsyncGen we need `yield Poll::Pending` + let full_yield_ty = body.yield_ty().unwrap(); + let ty::Adt(_poll_adt, args) = *full_yield_ty.kind() else { bug!() }; + let ty::Adt(_option_adt, args) = *args.type_at(0).kind() else { bug!() }; + let yield_ty = args.type_at(0); + Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + const_: Const::Unevaluated( + UnevaluatedConst::new( + tcx.require_lang_item(LangItem::AsyncGenPending, None), + tcx.mk_args(&[yield_ty.into()]), + ), + full_yield_ty, + ), + user_ty: None, + })) + } else { + // value needed only for return-yields or gen-coroutines, so just const here + Operand::Constant(Box::new(ConstOperand { + span: body.span, + user_ty: None, + const_: Const::from_bool(tcx, false), + })) + }; + use rustc_middle::mir::AssertKind::ResumedAfterDrop; let panic_bb = insert_panic_block(tcx, body, ResumedAfterDrop(coroutine_kind)); diff --git a/tests/crashes/140530.rs b/tests/crashes/140530.rs deleted file mode 100644 index 7e0372a4bd8..00000000000 --- a/tests/crashes/140530.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #140530 -//@ edition: 2024 - -#![feature(async_drop, gen_blocks)] -async gen fn a() { - _ = async {} -} -fn main() {} diff --git a/tests/ui/async-await/async-drop/assign-incompatible-types.rs b/tests/ui/async-await/async-drop/assign-incompatible-types.rs new file mode 100644 index 00000000000..359939ff9ac --- /dev/null +++ b/tests/ui/async-await/async-drop/assign-incompatible-types.rs @@ -0,0 +1,9 @@ +// ex-ice: #140530 +//@ edition: 2024 +//@ build-pass +#![feature(async_drop, gen_blocks)] +#![allow(incomplete_features)] +async gen fn a() { + _ = async {} +} +fn main() {} -- cgit 1.4.1-3-g733a5 From 0ca1be9273e3595bb1233fdf96fc5cdeccc5a66c Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Jun 2025 15:16:57 +0300 Subject: document `skip-std-check-if-no-download-rustc` in rustc-dev-guide Signed-off-by: onur-ozkan --- src/doc/rustc-dev-guide/src/building/suggested.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index 76c39608449..bfb2f4d1084 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -59,6 +59,14 @@ always overrides the inner ones. ## Configuring `rust-analyzer` for `rustc` +### Checking the "library" tree + +Checking the "library" tree requires a stage1 compiler, which can be a heavy process on some computers. +For this reason, bootstrap has a flag called `--skip-std-check-if-no-download-rustc` that skips checking the +"library" tree if `rust.download-rustc` isn't available. If you want to avoid putting a heavy load on your computer +with `rust-analyzer`, you can add the `--skip-std-check-if-no-download-rustc` flag to your `./x check` command in +the `rust-analyzer` configuration. + ### Project-local rust-analyzer setup `rust-analyzer` can help you check and format your code whenever you save a -- cgit 1.4.1-3-g733a5 From c843bec230d70ee8823568b67e2317ec1e9d1d8a Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Jun 2025 15:29:00 +0300 Subject: update `skip_std_check_if_no_download_rustc` doc-comments Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 4 ++- src/bootstrap/src/core/config/flags.rs | 4 ++- src/etc/completions/x.fish | 46 ++++++++++++++++----------------- src/etc/completions/x.ps1 | 46 ++++++++++++++++----------------- src/etc/completions/x.py.fish | 46 ++++++++++++++++----------------- src/etc/completions/x.py.ps1 | 46 ++++++++++++++++----------------- src/etc/completions/x.py.zsh | 46 ++++++++++++++++----------------- src/etc/completions/x.zsh | 46 ++++++++++++++++----------------- 8 files changed, 144 insertions(+), 140 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 7457dc0bfed..c6e377f5565 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -424,7 +424,9 @@ pub struct Config { /// Cache for determining path modifications pub path_modification_cache: Arc, PathFreshness>>>, - /// Skip checking std if `rust.download-rustc` isn't available, mostly for RA + /// Skip checking the standard library if `rust.download-rustc` isn't available. + /// This is mostly for RA as building the stage1 compiler to check the library tree + /// on each code change might be too much for some computers. pub skip_std_check_if_no_download_rustc: bool, } diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 72073cd69f4..45a0836ee67 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -182,7 +182,9 @@ pub struct Flags { /// Make bootstrap to behave as it's running on the CI environment or not. #[arg(global = true, long, value_name = "bool")] pub ci: Option, - /// Skip checking std if `rust.download-rustc` isn't available, mostly for RA + /// Skip checking the standard library if `rust.download-rustc` isn't available. + /// This is mostly for RA as building the stage1 compiler to check the library tree + /// on each code change might be too much for some computers. #[arg(global = true, long)] pub skip_std_check_if_no_download_rustc: bool, } diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index 19a1a598a5d..10a4e684e33 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -57,7 +57,7 @@ complete -c x -n "__fish_x_needs_command" -l bypass-bootstrap-lock -d 'Bootstrap complete -c x -n "__fish_x_needs_command" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_needs_command" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_needs_command" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_needs_command" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_needs_command" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_needs_command" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_needs_command" -a "build" -d 'Compile either the compiler or libraries' complete -c x -n "__fish_x_needs_command" -a "check" -d 'Compile either the compiler or libraries, using cargo check' @@ -109,7 +109,7 @@ complete -c x -n "__fish_x_using_subcommand build" -l bypass-bootstrap-lock -d ' complete -c x -n "__fish_x_using_subcommand build" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand build" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand build" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand build" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand build" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand build" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand check" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand check" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -145,7 +145,7 @@ complete -c x -n "__fish_x_using_subcommand check" -l bypass-bootstrap-lock -d ' complete -c x -n "__fish_x_using_subcommand check" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand check" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand check" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand check" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand check" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand check" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand clippy" -s A -d 'clippy lints to allow' -r complete -c x -n "__fish_x_using_subcommand clippy" -s D -d 'clippy lints to deny' -r @@ -187,7 +187,7 @@ complete -c x -n "__fish_x_using_subcommand clippy" -l bypass-bootstrap-lock -d complete -c x -n "__fish_x_using_subcommand clippy" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand clippy" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand clippy" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand clippy" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand clippy" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand clippy" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand fix" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand fix" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -222,7 +222,7 @@ complete -c x -n "__fish_x_using_subcommand fix" -l bypass-bootstrap-lock -d 'Bo complete -c x -n "__fish_x_using_subcommand fix" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand fix" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand fix" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand fix" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand fix" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand fix" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand fmt" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand fmt" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -259,7 +259,7 @@ complete -c x -n "__fish_x_using_subcommand fmt" -l bypass-bootstrap-lock -d 'Bo complete -c x -n "__fish_x_using_subcommand fmt" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand fmt" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand fmt" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand fmt" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand fmt" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand fmt" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand doc" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand doc" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -296,7 +296,7 @@ complete -c x -n "__fish_x_using_subcommand doc" -l bypass-bootstrap-lock -d 'Bo complete -c x -n "__fish_x_using_subcommand doc" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand doc" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand doc" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand doc" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand doc" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand doc" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r complete -c x -n "__fish_x_using_subcommand test" -l compiletest-rustc-args -d 'extra options to pass the compiler when running compiletest tests' -r @@ -345,7 +345,7 @@ complete -c x -n "__fish_x_using_subcommand test" -l bypass-bootstrap-lock -d 'B complete -c x -n "__fish_x_using_subcommand test" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand test" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand test" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand test" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand test" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand test" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand miri" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r complete -c x -n "__fish_x_using_subcommand miri" -l config -d 'TOML configuration file for build' -r -F @@ -384,7 +384,7 @@ complete -c x -n "__fish_x_using_subcommand miri" -l bypass-bootstrap-lock -d 'B complete -c x -n "__fish_x_using_subcommand miri" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand miri" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand miri" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand miri" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand miri" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand miri" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand bench" -l test-args -r complete -c x -n "__fish_x_using_subcommand bench" -l config -d 'TOML configuration file for build' -r -F @@ -420,7 +420,7 @@ complete -c x -n "__fish_x_using_subcommand bench" -l bypass-bootstrap-lock -d ' complete -c x -n "__fish_x_using_subcommand bench" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand bench" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand bench" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand bench" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand bench" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand bench" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand clean" -l stage -d 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used' -r complete -c x -n "__fish_x_using_subcommand clean" -l config -d 'TOML configuration file for build' -r -F @@ -456,7 +456,7 @@ complete -c x -n "__fish_x_using_subcommand clean" -l bypass-bootstrap-lock -d ' complete -c x -n "__fish_x_using_subcommand clean" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand clean" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand clean" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand clean" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand clean" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand clean" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand dist" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand dist" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -491,7 +491,7 @@ complete -c x -n "__fish_x_using_subcommand dist" -l bypass-bootstrap-lock -d 'B complete -c x -n "__fish_x_using_subcommand dist" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand dist" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand dist" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand dist" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand dist" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand dist" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand install" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand install" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -526,7 +526,7 @@ complete -c x -n "__fish_x_using_subcommand install" -l bypass-bootstrap-lock -d complete -c x -n "__fish_x_using_subcommand install" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand install" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand install" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand install" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand install" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand run" -l args -d 'arguments for the tool' -r complete -c x -n "__fish_x_using_subcommand run" -l config -d 'TOML configuration file for build' -r -F @@ -562,7 +562,7 @@ complete -c x -n "__fish_x_using_subcommand run" -l bypass-bootstrap-lock -d 'Bo complete -c x -n "__fish_x_using_subcommand run" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand run" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand run" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand run" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand run" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand run" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand setup" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand setup" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -597,7 +597,7 @@ complete -c x -n "__fish_x_using_subcommand setup" -l bypass-bootstrap-lock -d ' complete -c x -n "__fish_x_using_subcommand setup" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand setup" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand setup" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand setup" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand setup" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -633,7 +633,7 @@ complete -c x -n "__fish_x_using_subcommand suggest" -l bypass-bootstrap-lock -d complete -c x -n "__fish_x_using_subcommand suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand suggest" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand suggest" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand suggest" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand suggest" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand suggest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F complete -c x -n "__fish_x_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F @@ -670,7 +670,7 @@ complete -c x -n "__fish_x_using_subcommand vendor" -l bypass-bootstrap-lock -d complete -c x -n "__fish_x_using_subcommand vendor" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand vendor" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand vendor" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand vendor" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand vendor" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand vendor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -705,7 +705,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -a "eprintln" -d 'Run `profile_local eprintln`. This executes the compiler on the given benchmarks and stores its stderr output' complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -a "samply" -d 'Run `profile_local samply` This executes the compiler on the given benchmarks and profiles it with `samply`. You need to install `samply`, e.g. using `cargo install samply`' @@ -748,7 +748,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l include -d 'Select the benchmarks that you want to run (separated by commas). If unspecified, all benchmarks will be executed' -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r @@ -786,7 +786,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l include -d 'Select the benchmarks that you want to run (separated by commas). If unspecified, all benchmarks will be executed' -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r @@ -824,7 +824,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l include -d 'Select the benchmarks that you want to run (separated by commas). If unspecified, all benchmarks will be executed' -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r @@ -862,7 +862,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -897,5 +897,5 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -s h -l help -d 'Print help (see more with \'--help\')' diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index 805ab7fa61a..23d8fe0cdd3 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -57,7 +57,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('build', 'build', [CompletionResultType]::ParameterValue, 'Compile either the compiler or libraries') @@ -116,7 +116,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -159,7 +159,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -208,7 +208,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -250,7 +250,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -294,7 +294,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -338,7 +338,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -394,7 +394,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -440,7 +440,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -483,7 +483,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -526,7 +526,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -568,7 +568,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -610,7 +610,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -653,7 +653,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -695,7 +695,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -738,7 +738,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -782,7 +782,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -824,7 +824,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('eprintln', 'eprintln', [CompletionResultType]::ParameterValue, 'Run `profile_local eprintln`. This executes the compiler on the given benchmarks and stores its stderr output') @@ -874,7 +874,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -919,7 +919,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -964,7 +964,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -1009,7 +1009,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -1051,7 +1051,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 1da37b4a5b4..1fc5bb12cfb 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -57,7 +57,7 @@ complete -c x.py -n "__fish_x.py_needs_command" -l bypass-bootstrap-lock -d 'Boo complete -c x.py -n "__fish_x.py_needs_command" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_needs_command" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_needs_command" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_needs_command" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_needs_command" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_needs_command" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_needs_command" -a "build" -d 'Compile either the compiler or libraries' complete -c x.py -n "__fish_x.py_needs_command" -a "check" -d 'Compile either the compiler or libraries, using cargo check' @@ -109,7 +109,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand build" -l bypass-bootstrap-loc complete -c x.py -n "__fish_x.py_using_subcommand build" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand build" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand build" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand build" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand build" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand build" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand check" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand check" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -145,7 +145,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand check" -l bypass-bootstrap-loc complete -c x.py -n "__fish_x.py_using_subcommand check" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand check" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand check" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand check" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand check" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand check" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand clippy" -s A -d 'clippy lints to allow' -r complete -c x.py -n "__fish_x.py_using_subcommand clippy" -s D -d 'clippy lints to deny' -r @@ -187,7 +187,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l bypass-bootstrap-lo complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand clippy" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand fix" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand fix" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -222,7 +222,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand fix" -l bypass-bootstrap-lock complete -c x.py -n "__fish_x.py_using_subcommand fix" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand fix" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand fix" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand fix" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand fix" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand fix" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -259,7 +259,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l bypass-bootstrap-lock complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand fmt" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand doc" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand doc" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -296,7 +296,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand doc" -l bypass-bootstrap-lock complete -c x.py -n "__fish_x.py_using_subcommand doc" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand doc" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand doc" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand doc" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand doc" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand doc" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r complete -c x.py -n "__fish_x.py_using_subcommand test" -l compiletest-rustc-args -d 'extra options to pass the compiler when running compiletest tests' -r @@ -345,7 +345,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -l bypass-bootstrap-lock complete -c x.py -n "__fish_x.py_using_subcommand test" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand test" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand test" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand test" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand test" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand test" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand miri" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r complete -c x.py -n "__fish_x.py_using_subcommand miri" -l config -d 'TOML configuration file for build' -r -F @@ -384,7 +384,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand miri" -l bypass-bootstrap-lock complete -c x.py -n "__fish_x.py_using_subcommand miri" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand miri" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand miri" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand miri" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand miri" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand miri" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand bench" -l test-args -r complete -c x.py -n "__fish_x.py_using_subcommand bench" -l config -d 'TOML configuration file for build' -r -F @@ -420,7 +420,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand bench" -l bypass-bootstrap-loc complete -c x.py -n "__fish_x.py_using_subcommand bench" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand bench" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand bench" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand bench" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand bench" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand bench" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand clean" -l stage -d 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used' -r complete -c x.py -n "__fish_x.py_using_subcommand clean" -l config -d 'TOML configuration file for build' -r -F @@ -456,7 +456,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand clean" -l bypass-bootstrap-loc complete -c x.py -n "__fish_x.py_using_subcommand clean" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand clean" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand clean" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand clean" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand clean" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand clean" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand dist" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand dist" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -491,7 +491,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand dist" -l bypass-bootstrap-lock complete -c x.py -n "__fish_x.py_using_subcommand dist" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand dist" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand dist" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand dist" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand dist" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand dist" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand install" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand install" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -526,7 +526,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand install" -l bypass-bootstrap-l complete -c x.py -n "__fish_x.py_using_subcommand install" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand install" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand install" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand install" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand install" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand run" -l args -d 'arguments for the tool' -r complete -c x.py -n "__fish_x.py_using_subcommand run" -l config -d 'TOML configuration file for build' -r -F @@ -562,7 +562,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand run" -l bypass-bootstrap-lock complete -c x.py -n "__fish_x.py_using_subcommand run" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand run" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand run" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand run" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand run" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand run" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand setup" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand setup" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -597,7 +597,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand setup" -l bypass-bootstrap-loc complete -c x.py -n "__fish_x.py_using_subcommand setup" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand setup" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -633,7 +633,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l bypass-bootstrap-l complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F @@ -670,7 +670,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l bypass-bootstrap-lo complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand vendor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -705,7 +705,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subc complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -a "eprintln" -d 'Run `profile_local eprintln`. This executes the compiler on the given benchmarks and stores its stderr output' complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -a "samply" -d 'Run `profile_local samply` This executes the compiler on the given benchmarks and profiles it with `samply`. You need to install `samply`, e.g. using `cargo install samply`' @@ -748,7 +748,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l include -d 'Select the benchmarks that you want to run (separated by commas). If unspecified, all benchmarks will be executed' -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r @@ -786,7 +786,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l include -d 'Select the benchmarks that you want to run (separated by commas). If unspecified, all benchmarks will be executed' -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r @@ -824,7 +824,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l include -d 'Select the benchmarks that you want to run (separated by commas). If unspecified, all benchmarks will be executed' -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r @@ -862,7 +862,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" @@ -897,5 +897,5 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l skip-std-check-if-no-download-rustc -d 'Skip checking std if `rust.download-rustc` isn\'t available, mostly for RA' +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -s h -l help -d 'Print help (see more with \'--help\')' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index 8444716ae86..5d224ac6df4 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -57,7 +57,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('build', 'build', [CompletionResultType]::ParameterValue, 'Compile either the compiler or libraries') @@ -116,7 +116,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -159,7 +159,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -208,7 +208,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -250,7 +250,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -294,7 +294,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -338,7 +338,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -394,7 +394,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -440,7 +440,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -483,7 +483,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -526,7 +526,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -568,7 +568,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -610,7 +610,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -653,7 +653,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -695,7 +695,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -738,7 +738,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -782,7 +782,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -824,7 +824,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('eprintln', 'eprintln', [CompletionResultType]::ParameterValue, 'Run `profile_local eprintln`. This executes the compiler on the given benchmarks and stores its stderr output') @@ -874,7 +874,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -919,7 +919,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -964,7 +964,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -1009,7 +1009,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -1051,7 +1051,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking std if `rust.download-rustc` isn''t available, mostly for RA') + [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index c5385911538..bc55280d038 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -51,7 +51,7 @@ _x.py() { '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::paths -- paths for the subcommand:_files' \ @@ -103,7 +103,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -148,7 +148,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -199,7 +199,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -243,7 +243,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -289,7 +289,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -335,7 +335,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -393,7 +393,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -441,7 +441,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -486,7 +486,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -531,7 +531,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -575,7 +575,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -619,7 +619,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -664,7 +664,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -708,7 +708,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::profile -- Either the profile for `bootstrap.toml` or another setup action. May be omitted to set up interactively:_files' \ @@ -754,7 +754,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -800,7 +800,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -844,7 +844,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::paths -- paths for the subcommand:_files' \ @@ -900,7 +900,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -947,7 +947,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -994,7 +994,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -1041,7 +1041,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':benchmark-id -- Identifier to associate benchmark results with:_default' \ @@ -1086,7 +1086,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':base -- The name of the base artifact to be compared:_default' \ diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index e76db1ca4e0..2e3094fc379 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -51,7 +51,7 @@ _x() { '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::paths -- paths for the subcommand:_files' \ @@ -103,7 +103,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -148,7 +148,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -199,7 +199,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -243,7 +243,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -289,7 +289,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -335,7 +335,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -393,7 +393,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -441,7 +441,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -486,7 +486,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -531,7 +531,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -575,7 +575,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -619,7 +619,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -664,7 +664,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -708,7 +708,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::profile -- Either the profile for `bootstrap.toml` or another setup action. May be omitted to set up interactively:_files' \ @@ -754,7 +754,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -800,7 +800,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -844,7 +844,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::paths -- paths for the subcommand:_files' \ @@ -900,7 +900,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -947,7 +947,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -994,7 +994,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ @@ -1041,7 +1041,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':benchmark-id -- Identifier to associate benchmark results with:_default' \ @@ -1086,7 +1086,7 @@ _arguments "${_arguments_options[@]}" : \ '--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ '--enable-bolt-settings[Enable BOLT link flags]' \ '--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking std if \`rust.download-rustc\` isn'\''t available, mostly for RA]' \ +'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':base -- The name of the base artifact to be compared:_default' \ -- cgit 1.4.1-3-g733a5 From ff005610d5956cee82d4b2d162c3ee8da71e8164 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 3 Jun 2025 17:47:38 +0500 Subject: cleaned up some tests --- tests/ui/break-diverging-value.rs | 37 ------------- tests/ui/break-diverging-value.stderr | 19 ------- tests/ui/builtin-clone-unwind.rs | 61 ---------------------- tests/ui/can-copy-pod.rs | 15 ------ tests/ui/cancel-clean-via-immediate-rvalue-ref.rs | 9 ---- tests/ui/cannot-mutate-captured-non-mut-var.rs | 15 ------ tests/ui/cannot-mutate-captured-non-mut-var.stderr | 26 --------- tests/ui/closures/closure-immut-capture-error.rs | 23 ++++++++ .../ui/closures/closure-immut-capture-error.stderr | 26 +++++++++ tests/ui/codegen/rvalue-mut-ref-box-drop.rs | 13 +++++ tests/ui/loops/loop-break-never-type-mismatch.rs | 56 ++++++++++++++++++++ .../ui/loops/loop-break-never-type-mismatch.stderr | 19 +++++++ tests/ui/traits/clone-unwind-rc-cleanup.rs | 46 ++++++++++++++++ tests/ui/traits/copy-trait-implicit-copy.rs | 15 ++++++ 14 files changed, 198 insertions(+), 182 deletions(-) delete mode 100644 tests/ui/break-diverging-value.rs delete mode 100644 tests/ui/break-diverging-value.stderr delete mode 100644 tests/ui/builtin-clone-unwind.rs delete mode 100644 tests/ui/can-copy-pod.rs delete mode 100644 tests/ui/cancel-clean-via-immediate-rvalue-ref.rs delete mode 100644 tests/ui/cannot-mutate-captured-non-mut-var.rs delete mode 100644 tests/ui/cannot-mutate-captured-non-mut-var.stderr create mode 100644 tests/ui/closures/closure-immut-capture-error.rs create mode 100644 tests/ui/closures/closure-immut-capture-error.stderr create mode 100644 tests/ui/codegen/rvalue-mut-ref-box-drop.rs create mode 100644 tests/ui/loops/loop-break-never-type-mismatch.rs create mode 100644 tests/ui/loops/loop-break-never-type-mismatch.stderr create mode 100644 tests/ui/traits/clone-unwind-rc-cleanup.rs create mode 100644 tests/ui/traits/copy-trait-implicit-copy.rs diff --git a/tests/ui/break-diverging-value.rs b/tests/ui/break-diverging-value.rs deleted file mode 100644 index d070fddaffc..00000000000 --- a/tests/ui/break-diverging-value.rs +++ /dev/null @@ -1,37 +0,0 @@ -#![feature(never_type)] - -fn loop_break_return() -> i32 { - let loop_value = loop { break return 0 }; // ok -} - -fn loop_break_loop() -> i32 { - let loop_value = loop { break loop {} }; // ok -} - -fn loop_break_break() -> i32 { //~ ERROR mismatched types - let loop_value = loop { break break }; -} - -fn loop_break_return_2() -> i32 { - let loop_value = loop { break { return 0; () } }; // ok -} - -enum Void {} - -fn get_void() -> Void { - panic!() -} - -fn loop_break_void() -> i32 { //~ ERROR mismatched types - let loop_value = loop { break get_void() }; -} - -fn get_never() -> ! { - panic!() -} - -fn loop_break_never() -> i32 { - let loop_value = loop { break get_never() }; // ok -} - -fn main() {} diff --git a/tests/ui/break-diverging-value.stderr b/tests/ui/break-diverging-value.stderr deleted file mode 100644 index 69edcd24080..00000000000 --- a/tests/ui/break-diverging-value.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/break-diverging-value.rs:11:26 - | -LL | fn loop_break_break() -> i32 { - | ---------------- ^^^ expected `i32`, found `()` - | | - | implicitly returns `()` as its body has no tail or `return` expression - -error[E0308]: mismatched types - --> $DIR/break-diverging-value.rs:25:25 - | -LL | fn loop_break_void() -> i32 { - | --------------- ^^^ expected `i32`, found `()` - | | - | implicitly returns `()` as its body has no tail or `return` expression - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/builtin-clone-unwind.rs b/tests/ui/builtin-clone-unwind.rs deleted file mode 100644 index 507ea045b4f..00000000000 --- a/tests/ui/builtin-clone-unwind.rs +++ /dev/null @@ -1,61 +0,0 @@ -//@ run-pass -//@ needs-unwind - -#![allow(unused_variables)] -#![allow(unused_imports)] - -// Test that builtin implementations of `Clone` cleanup everything -// in case of unwinding. - -use std::thread; -use std::rc::Rc; - -struct S(Rc<()>); - -impl Clone for S { - fn clone(&self) -> Self { - if Rc::strong_count(&self.0) == 7 { - panic!("oops"); - } - - S(self.0.clone()) - } -} - -fn main() { - let counter = Rc::new(()); - - // Unwinding with tuples... - let ccounter = counter.clone(); - let result = std::panic::catch_unwind(move || { - let _ = ( - S(ccounter.clone()), - S(ccounter.clone()), - S(ccounter.clone()), - S(ccounter) - ).clone(); - }); - - assert!(result.is_err()); - assert_eq!( - 1, - Rc::strong_count(&counter) - ); - - // ... and with arrays. - let ccounter = counter.clone(); - let child = std::panic::catch_unwind(move || { - let _ = [ - S(ccounter.clone()), - S(ccounter.clone()), - S(ccounter.clone()), - S(ccounter) - ].clone(); - }); - - assert!(child.is_err()); - assert_eq!( - 1, - Rc::strong_count(&counter) - ); -} diff --git a/tests/ui/can-copy-pod.rs b/tests/ui/can-copy-pod.rs deleted file mode 100644 index ffb8a08fa98..00000000000 --- a/tests/ui/can-copy-pod.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ run-pass - -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Tests that type parameters with the `Copy` are implicitly copyable. - -#![allow(dead_code)] - -fn can_copy_copy(v: T) { - let _a = v; - let _b = v; -} - -pub fn main() {} diff --git a/tests/ui/cancel-clean-via-immediate-rvalue-ref.rs b/tests/ui/cancel-clean-via-immediate-rvalue-ref.rs deleted file mode 100644 index 12d143bd989..00000000000 --- a/tests/ui/cancel-clean-via-immediate-rvalue-ref.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass - -fn foo(x: &mut Box) { - *x = Box::new(5); -} - -pub fn main() { - foo(&mut Box::new(4)); -} diff --git a/tests/ui/cannot-mutate-captured-non-mut-var.rs b/tests/ui/cannot-mutate-captured-non-mut-var.rs deleted file mode 100644 index 952dab25bf9..00000000000 --- a/tests/ui/cannot-mutate-captured-non-mut-var.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(unboxed_closures, tuple_trait)] - -use std::io::Read; - -fn to_fn_once>(f: F) -> F { f } - -fn main() { - let x = 1; - to_fn_once(move|| { x = 2; }); - //~^ ERROR: cannot assign to `x`, as it is not declared as mutable - - let s = std::io::stdin(); - to_fn_once(move|| { s.read_to_end(&mut Vec::new()); }); - //~^ ERROR: cannot borrow `s` as mutable, as it is not declared as mutable -} diff --git a/tests/ui/cannot-mutate-captured-non-mut-var.stderr b/tests/ui/cannot-mutate-captured-non-mut-var.stderr deleted file mode 100644 index 8d794f8251f..00000000000 --- a/tests/ui/cannot-mutate-captured-non-mut-var.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/cannot-mutate-captured-non-mut-var.rs:9:25 - | -LL | to_fn_once(move|| { x = 2; }); - | ^^^^^ cannot assign - | -help: consider changing this to be mutable - | -LL | let mut x = 1; - | +++ - -error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable - --> $DIR/cannot-mutate-captured-non-mut-var.rs:13:25 - | -LL | to_fn_once(move|| { s.read_to_end(&mut Vec::new()); }); - | ^ cannot borrow as mutable - | -help: consider changing this to be mutable - | -LL | let mut s = std::io::stdin(); - | +++ - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0594, E0596. -For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/closures/closure-immut-capture-error.rs b/tests/ui/closures/closure-immut-capture-error.rs new file mode 100644 index 00000000000..19fe599f241 --- /dev/null +++ b/tests/ui/closures/closure-immut-capture-error.rs @@ -0,0 +1,23 @@ +//! Tests that mutation of captured immutable variables in closures are not permitted. + +#![feature(unboxed_closures, tuple_trait)] + +use std::io::Read; + +fn to_fn_once>(f: F) -> F { + f +} + +fn main() { + let x = 1; + to_fn_once(move || { + x = 2; + //~^ ERROR: cannot assign to `x`, as it is not declared as mutable + }); + + let s = std::io::stdin(); + to_fn_once(move || { + s.read_to_end(&mut Vec::new()); + //~^ ERROR: cannot borrow `s` as mutable, as it is not declared as mutable + }); +} diff --git a/tests/ui/closures/closure-immut-capture-error.stderr b/tests/ui/closures/closure-immut-capture-error.stderr new file mode 100644 index 00000000000..516cf7c074e --- /dev/null +++ b/tests/ui/closures/closure-immut-capture-error.stderr @@ -0,0 +1,26 @@ +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/closure-immut-capture-error.rs:14:9 + | +LL | x = 2; + | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut x = 1; + | +++ + +error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable + --> $DIR/closure-immut-capture-error.rs:20:9 + | +LL | s.read_to_end(&mut Vec::new()); + | ^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut s = std::io::stdin(); + | +++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/codegen/rvalue-mut-ref-box-drop.rs b/tests/ui/codegen/rvalue-mut-ref-box-drop.rs new file mode 100644 index 00000000000..441820ad64e --- /dev/null +++ b/tests/ui/codegen/rvalue-mut-ref-box-drop.rs @@ -0,0 +1,13 @@ +//! Tests cleanup of a temporary `Box` rvalue passed as a mutable reference. +//! +//! - Issue: . + +//@ run-pass + +fn foo(x: &mut Box) { + *x = Box::new(5); +} + +pub fn main() { + foo(&mut Box::new(4)); +} diff --git a/tests/ui/loops/loop-break-never-type-mismatch.rs b/tests/ui/loops/loop-break-never-type-mismatch.rs new file mode 100644 index 00000000000..2be4e4f4ac5 --- /dev/null +++ b/tests/ui/loops/loop-break-never-type-mismatch.rs @@ -0,0 +1,56 @@ +//! Tests type mismatches with `break` and diverging types in loops + +#![feature(never_type)] + +fn loop_break_return() -> i32 { + let loop_value = loop { + break return 0; + }; // ok +} + +fn loop_break_loop() -> i32 { + let loop_value = loop { + break loop {}; + }; // ok +} + +fn loop_break_break() -> i32 { + //~^ ERROR mismatched types + let loop_value = loop { + break break; + }; +} + +fn loop_break_return_2() -> i32 { + let loop_value = loop { + break { + return 0; + () + }; + }; // ok +} + +enum Void {} + +fn get_void() -> Void { + panic!() +} + +fn loop_break_void() -> i32 { + //~^ ERROR mismatched types + let loop_value = loop { + break get_void(); + }; +} + +fn get_never() -> ! { + panic!() +} + +fn loop_break_never() -> i32 { + let loop_value = loop { + break get_never(); + }; // ok +} + +fn main() {} diff --git a/tests/ui/loops/loop-break-never-type-mismatch.stderr b/tests/ui/loops/loop-break-never-type-mismatch.stderr new file mode 100644 index 00000000000..e6868f375e2 --- /dev/null +++ b/tests/ui/loops/loop-break-never-type-mismatch.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/loop-break-never-type-mismatch.rs:17:26 + | +LL | fn loop_break_break() -> i32 { + | ---------------- ^^^ expected `i32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error[E0308]: mismatched types + --> $DIR/loop-break-never-type-mismatch.rs:39:25 + | +LL | fn loop_break_void() -> i32 { + | --------------- ^^^ expected `i32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/clone-unwind-rc-cleanup.rs b/tests/ui/traits/clone-unwind-rc-cleanup.rs new file mode 100644 index 00000000000..cd02050ea27 --- /dev/null +++ b/tests/ui/traits/clone-unwind-rc-cleanup.rs @@ -0,0 +1,46 @@ +//! Tests cleanup behavior of the built-in `Clone` impl for tuples during unwinding. + +//@ run-pass +//@ needs-unwind + +#![allow(unused_variables)] +#![allow(unused_imports)] + +use std::rc::Rc; +use std::thread; + +struct S(Rc<()>); + +impl Clone for S { + fn clone(&self) -> Self { + if Rc::strong_count(&self.0) == 7 { + panic!("oops"); + } + + S(self.0.clone()) + } +} + +fn main() { + let counter = Rc::new(()); + + // Unwinding with tuples... + let ccounter = counter.clone(); + let result = std::panic::catch_unwind(move || { + let _ = + (S(ccounter.clone()), S(ccounter.clone()), S(ccounter.clone()), S(ccounter)).clone(); + }); + + assert!(result.is_err()); + assert_eq!(1, Rc::strong_count(&counter)); + + // ... and with arrays. + let ccounter = counter.clone(); + let child = std::panic::catch_unwind(move || { + let _ = + [S(ccounter.clone()), S(ccounter.clone()), S(ccounter.clone()), S(ccounter)].clone(); + }); + + assert!(child.is_err()); + assert_eq!(1, Rc::strong_count(&counter)); +} diff --git a/tests/ui/traits/copy-trait-implicit-copy.rs b/tests/ui/traits/copy-trait-implicit-copy.rs new file mode 100644 index 00000000000..e06385587b4 --- /dev/null +++ b/tests/ui/traits/copy-trait-implicit-copy.rs @@ -0,0 +1,15 @@ +//! Tests that type parameters with the `Copy` are implicitly copyable. + +//@ run-pass + +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +#![allow(dead_code)] + +fn can_copy_copy(v: T) { + let _a = v; + let _b = v; +} + +pub fn main() {} -- cgit 1.4.1-3-g733a5 From fcfa9b0ba00cfeb17f050f26428aebe770cb4417 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 4 Jun 2025 15:02:31 +0200 Subject: Don't refer to 'local binding' in extern macro. The user has no clue what 'local binding' the compiler is talking about, if they don't know the expansion of the macro. --- compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs | 8 +++++++- tests/ui/macros/return_from_external_macro.rs | 2 +- tests/ui/macros/return_from_external_macro.stderr | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 3b7d31b1b13..b7b6a2da549 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3314,7 +3314,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { "function parameter".to_string(), "function parameter borrowed here".to_string(), ), - LocalKind::Temp if self.body.local_decls[local].is_user_variable() => { + LocalKind::Temp + if self.body.local_decls[local].is_user_variable() + && !self.body.local_decls[local] + .source_info + .span + .in_external_macro(self.infcx.tcx.sess.source_map()) => + { ("local binding".to_string(), "local binding introduced here".to_string()) } LocalKind::ReturnPointer | LocalKind::Temp => { diff --git a/tests/ui/macros/return_from_external_macro.rs b/tests/ui/macros/return_from_external_macro.rs index 43fe99e63ad..91d0c4c64fd 100644 --- a/tests/ui/macros/return_from_external_macro.rs +++ b/tests/ui/macros/return_from_external_macro.rs @@ -5,7 +5,7 @@ extern crate ret_from_ext; fn foo() -> impl Sized { drop(|| ret_from_ext::foo!()); - //~^ ERROR cannot return reference to local binding + //~^ ERROR cannot return reference to temporary value ret_from_ext::foo!() //~^ ERROR temporary value dropped while borrowed diff --git a/tests/ui/macros/return_from_external_macro.stderr b/tests/ui/macros/return_from_external_macro.stderr index b6010b8ec79..6f707b9f52b 100644 --- a/tests/ui/macros/return_from_external_macro.stderr +++ b/tests/ui/macros/return_from_external_macro.stderr @@ -1,11 +1,11 @@ -error[E0515]: cannot return reference to local binding +error[E0515]: cannot return reference to temporary value --> $DIR/return_from_external_macro.rs:7:13 | LL | drop(|| ret_from_ext::foo!()); | ^^^^^^^^^^^^^^^^^^^^ | | | returns a reference to data owned by the current function - | local binding introduced here + | temporary value created here | = note: this error originates in the macro `ret_from_ext::foo` (in Nightly builds, run with -Z macro-backtrace for more info) -- cgit 1.4.1-3-g733a5 From da2e33b4065c3356260a0c1671a945a3bf0a2f35 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 4 Jun 2025 14:45:32 +0200 Subject: Don't refer to 'this tail expression' in expansion. The user has no clue what tail expression the compiler is talking about: it is an implementation detail of the macro that it uses a block with tail expression. --- .../rustc_trait_selection/src/error_reporting/traits/suggestions.rs | 4 +++- tests/ui/never_type/feature-gate-never_type_fallback.stderr | 6 ++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index c4f1f7d712a..9c301373cf9 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3841,7 +3841,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .expr_ty_adjusted_opt(inner_expr) .unwrap_or(Ty::new_misc_error(tcx)); let span = inner_expr.span; - if Some(span) != err.span.primary_span() { + if Some(span) != err.span.primary_span() + && !span.in_external_macro(tcx.sess.source_map()) + { err.span_label( span, if ty.references_error() { diff --git a/tests/ui/never_type/feature-gate-never_type_fallback.stderr b/tests/ui/never_type/feature-gate-never_type_fallback.stderr index cbb670ea708..8dbd43e121b 100644 --- a/tests/ui/never_type/feature-gate-never_type_fallback.stderr +++ b/tests/ui/never_type/feature-gate-never_type_fallback.stderr @@ -2,10 +2,8 @@ error[E0277]: the trait bound `(): T` is not satisfied --> $DIR/feature-gate-never_type_fallback.rs:10:9 | LL | foo(panic!()) - | --- ^^^^^^^^ - | | | - | | the trait `T` is not implemented for `()` - | | this tail expression is of type `()` + | --- ^^^^^^^^ the trait `T` is not implemented for `()` + | | | required by a bound introduced by this call | help: this trait has no implementations, consider adding one -- cgit 1.4.1-3-g733a5 From 9091a94ff042d501b627f6244444f472a32fc972 Mon Sep 17 00:00:00 2001 From: smpdt <206221751+smpdt@users.noreply.github.com> Date: Wed, 4 Jun 2025 10:00:20 -0400 Subject: bootstrap: Fix file permissions when dereferencing symlinks --- src/bootstrap/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index cfb968f79ba..07772b8932d 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1795,11 +1795,12 @@ Executed at: {executed_at}"#, let now = t!(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)); let _ = fs::rename(dst, format!("{}-{}", dst.display(), now.as_nanos())); } - let metadata = t!(src.symlink_metadata(), format!("src = {}", src.display())); + let mut metadata = t!(src.symlink_metadata(), format!("src = {}", src.display())); let mut src = src.to_path_buf(); if metadata.file_type().is_symlink() { if dereference_symlinks { src = t!(fs::canonicalize(src)); + metadata = t!(fs::metadata(&src), format!("target = {}", src.display())); } else { let link = t!(fs::read_link(src)); t!(self.symlink_file(link, dst)); -- cgit 1.4.1-3-g733a5 From 06ab34e51604ae09d56b42cb4576a87dd44db5be Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 3 Jun 2025 20:59:42 +0500 Subject: cleaned up some tests --- tests/ui/cenum_impl_drop_cast.rs | 15 ------ tests/ui/cenum_impl_drop_cast.stderr | 8 --- tests/ui/char.rs | 13 ----- tests/ui/class-cast-to-trait.rs | 54 -------------------- tests/ui/class-cast-to-trait.stderr | 9 ---- tests/ui/class-method-missing.rs | 21 -------- tests/ui/class-method-missing.stderr | 12 ----- tests/ui/cleanup-rvalue-for-scope.rs | 60 ----------------------- tests/ui/drop/for-expr-temporary-drop-scope.rs | 33 +++++++++++++ tests/ui/enum/enum-drop-cast-error.rs | 19 +++++++ tests/ui/enum/enum-drop-cast-error.stderr | 8 +++ tests/ui/privacy/trait-object-method-error.rs | 20 ++++++++ tests/ui/privacy/trait-object-method-error.stderr | 15 ++++++ tests/ui/traits/trait-impl-missing-method.rs | 13 +++++ tests/ui/traits/trait-impl-missing-method.stderr | 12 +++++ 15 files changed, 120 insertions(+), 192 deletions(-) delete mode 100644 tests/ui/cenum_impl_drop_cast.rs delete mode 100644 tests/ui/cenum_impl_drop_cast.stderr delete mode 100644 tests/ui/char.rs delete mode 100644 tests/ui/class-cast-to-trait.rs delete mode 100644 tests/ui/class-cast-to-trait.stderr delete mode 100644 tests/ui/class-method-missing.rs delete mode 100644 tests/ui/class-method-missing.stderr delete mode 100644 tests/ui/cleanup-rvalue-for-scope.rs create mode 100644 tests/ui/drop/for-expr-temporary-drop-scope.rs create mode 100644 tests/ui/enum/enum-drop-cast-error.rs create mode 100644 tests/ui/enum/enum-drop-cast-error.stderr create mode 100644 tests/ui/privacy/trait-object-method-error.rs create mode 100644 tests/ui/privacy/trait-object-method-error.stderr create mode 100644 tests/ui/traits/trait-impl-missing-method.rs create mode 100644 tests/ui/traits/trait-impl-missing-method.stderr diff --git a/tests/ui/cenum_impl_drop_cast.rs b/tests/ui/cenum_impl_drop_cast.rs deleted file mode 100644 index f681434dd86..00000000000 --- a/tests/ui/cenum_impl_drop_cast.rs +++ /dev/null @@ -1,15 +0,0 @@ -enum E { - A = 0, -} - -impl Drop for E { - fn drop(&mut self) { - println!("Drop"); - } -} - -fn main() { - let e = E::A; - let i = e as u32; - //~^ ERROR cannot cast enum `E` into integer `u32` because it implements `Drop` -} diff --git a/tests/ui/cenum_impl_drop_cast.stderr b/tests/ui/cenum_impl_drop_cast.stderr deleted file mode 100644 index 35c69f4b4b7..00000000000 --- a/tests/ui/cenum_impl_drop_cast.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: cannot cast enum `E` into integer `u32` because it implements `Drop` - --> $DIR/cenum_impl_drop_cast.rs:13:13 - | -LL | let i = e as u32; - | ^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/char.rs b/tests/ui/char.rs deleted file mode 100644 index a7842f16fa7..00000000000 --- a/tests/ui/char.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass - -pub fn main() { - let c: char = 'x'; - let d: char = 'x'; - assert_eq!(c, 'x'); - assert_eq!('x', c); - assert_eq!(c, c); - assert_eq!(c, d); - assert_eq!(d, c); - assert_eq!(d, 'x'); - assert_eq!('x', d); -} diff --git a/tests/ui/class-cast-to-trait.rs b/tests/ui/class-cast-to-trait.rs deleted file mode 100644 index ca98e4c9003..00000000000 --- a/tests/ui/class-cast-to-trait.rs +++ /dev/null @@ -1,54 +0,0 @@ -trait Noisy { - fn speak(&mut self); -} - -struct Cat { - meows : usize, - - how_hungry : isize, - name : String, -} - -impl Cat { - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } - else { - println!("Not hungry!"); - return false; - } - } -} - -impl Noisy for Cat { - fn speak(&mut self) { self.meow(); } - -} - -impl Cat { - fn meow(&mut self) { - println!("Meow"); - self.meows += 1; - if self.meows % 5 == 0 { - self.how_hungry += 1; - } - } -} - -fn cat(in_x : usize, in_y : isize, in_name: String) -> Cat { - Cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } -} - - - -fn main() { - let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; - nyan.eat(); //~ ERROR no method named `eat` found -} diff --git a/tests/ui/class-cast-to-trait.stderr b/tests/ui/class-cast-to-trait.stderr deleted file mode 100644 index 4ea0f41c3ed..00000000000 --- a/tests/ui/class-cast-to-trait.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0599]: no method named `eat` found for struct `Box` in the current scope - --> $DIR/class-cast-to-trait.rs:53:8 - | -LL | nyan.eat(); - | ^^^ method not found in `Box` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/class-method-missing.rs b/tests/ui/class-method-missing.rs deleted file mode 100644 index 5dc18328f31..00000000000 --- a/tests/ui/class-method-missing.rs +++ /dev/null @@ -1,21 +0,0 @@ -trait Animal { - fn eat(&self); -} - -struct Cat { - meows: usize, -} - -impl Animal for Cat { - //~^ ERROR not all trait items implemented, missing: `eat` -} - -fn cat(in_x : usize) -> Cat { - Cat { - meows: in_x - } -} - -fn main() { - let nyan = cat(0); -} diff --git a/tests/ui/class-method-missing.stderr b/tests/ui/class-method-missing.stderr deleted file mode 100644 index 42bd22e18a1..00000000000 --- a/tests/ui/class-method-missing.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0046]: not all trait items implemented, missing: `eat` - --> $DIR/class-method-missing.rs:9:1 - | -LL | fn eat(&self); - | -------------- `eat` from trait -... -LL | impl Animal for Cat { - | ^^^^^^^^^^^^^^^^^^^ missing `eat` in implementation - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/cleanup-rvalue-for-scope.rs b/tests/ui/cleanup-rvalue-for-scope.rs deleted file mode 100644 index 8f5ee8723fd..00000000000 --- a/tests/ui/cleanup-rvalue-for-scope.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ run-pass - -#![allow(non_snake_case)] -#![allow(dead_code)] -#![allow(unused_variables)] -// Test that the lifetime of rvalues in for loops is extended -// to the for loop itself. -static mut FLAGS: u64 = 0; - -struct Box { f: T } -struct AddFlags { bits: u64 } - -fn AddFlags(bits: u64) -> AddFlags { - AddFlags { bits: bits } -} - -fn arg(exp: u64, _x: &AddFlags) { - check_flags(exp); -} - -fn pass(v: T) -> T { - v -} - -fn check_flags(exp: u64) { - unsafe { - let x = FLAGS; - FLAGS = 0; - println!("flags {}, expected {}", x, exp); - assert_eq!(x, exp); - } -} - -impl AddFlags { - fn check_flags(&self, exp: u64) -> &AddFlags { - check_flags(exp); - self - } - - fn bits(&self) -> u64 { - self.bits - } -} - -impl Drop for AddFlags { - fn drop(&mut self) { - unsafe { - FLAGS = FLAGS + self.bits; - } - } -} - -pub fn main() { - // The array containing [AddFlags] should not be dropped until - // after the for loop: - for x in &[AddFlags(1)] { - check_flags(0); - } - check_flags(1); -} diff --git a/tests/ui/drop/for-expr-temporary-drop-scope.rs b/tests/ui/drop/for-expr-temporary-drop-scope.rs new file mode 100644 index 00000000000..c6f80842ee6 --- /dev/null +++ b/tests/ui/drop/for-expr-temporary-drop-scope.rs @@ -0,0 +1,33 @@ +//! Check that temporaries in the for into-iterable expr are not dropped +//! until the end of the for expr. + +//@ run-pass + +static mut FLAGS: u64 = 0; + +struct AddFlags { + bits: u64, +} + +impl Drop for AddFlags { + fn drop(&mut self) { + unsafe { + FLAGS += self.bits; + } + } +} + +fn check_flags(expected: u64) { + unsafe { + let actual = FLAGS; + FLAGS = 0; + assert_eq!(actual, expected, "flags {}, expected {}", actual, expected); + } +} + +fn main() { + for _ in &[AddFlags { bits: 1 }] { + check_flags(0); + } + check_flags(1); +} diff --git a/tests/ui/enum/enum-drop-cast-error.rs b/tests/ui/enum/enum-drop-cast-error.rs new file mode 100644 index 00000000000..36101573624 --- /dev/null +++ b/tests/ui/enum/enum-drop-cast-error.rs @@ -0,0 +1,19 @@ +//! Check that trying to cast an enum with a Drop impl to an integer is rejected. +//! +//! Issue: + +enum E { + A = 0, +} + +impl Drop for E { + fn drop(&mut self) { + println!("Drop"); + } +} + +fn main() { + let e = E::A; + let i = e as u32; + //~^ ERROR cannot cast enum `E` into integer `u32` because it implements `Drop` +} diff --git a/tests/ui/enum/enum-drop-cast-error.stderr b/tests/ui/enum/enum-drop-cast-error.stderr new file mode 100644 index 00000000000..b58abbd39d3 --- /dev/null +++ b/tests/ui/enum/enum-drop-cast-error.stderr @@ -0,0 +1,8 @@ +error: cannot cast enum `E` into integer `u32` because it implements `Drop` + --> $DIR/enum-drop-cast-error.rs:17:13 + | +LL | let i = e as u32; + | ^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/privacy/trait-object-method-error.rs b/tests/ui/privacy/trait-object-method-error.rs new file mode 100644 index 00000000000..f0214dc6361 --- /dev/null +++ b/tests/ui/privacy/trait-object-method-error.rs @@ -0,0 +1,20 @@ +//! Trait objects only allow access to methods defined in the trait. + +trait MyTrait { + fn trait_method(&mut self); +} + +struct ImplType; + +impl MyTrait for ImplType { + fn trait_method(&mut self) {} +} + +impl ImplType { + fn struct_impl_method(&mut self) {} +} + +fn main() { + let obj: Box = Box::new(ImplType); + obj.struct_impl_method(); //~ ERROR no method named `struct_impl_method` found +} diff --git a/tests/ui/privacy/trait-object-method-error.stderr b/tests/ui/privacy/trait-object-method-error.stderr new file mode 100644 index 00000000000..40dde8fc47e --- /dev/null +++ b/tests/ui/privacy/trait-object-method-error.stderr @@ -0,0 +1,15 @@ +error[E0599]: no method named `struct_impl_method` found for struct `Box` in the current scope + --> $DIR/trait-object-method-error.rs:19:9 + | +LL | obj.struct_impl_method(); + | ^^^^^^^^^^^^^^^^^^ + | +help: there is a method `trait_method` with a similar name + | +LL - obj.struct_impl_method(); +LL + obj.trait_method(); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/traits/trait-impl-missing-method.rs b/tests/ui/traits/trait-impl-missing-method.rs new file mode 100644 index 00000000000..1f03a332c4a --- /dev/null +++ b/tests/ui/traits/trait-impl-missing-method.rs @@ -0,0 +1,13 @@ +//! Trait impls must define all required methods. + +trait MyTrait { + fn trait_method(&self); +} + +struct ImplType; + +impl MyTrait for ImplType {} //~ ERROR not all trait items implemented, missing: `trait_method` + +fn main() { + let _ = ImplType; +} diff --git a/tests/ui/traits/trait-impl-missing-method.stderr b/tests/ui/traits/trait-impl-missing-method.stderr new file mode 100644 index 00000000000..ae11c3665ee --- /dev/null +++ b/tests/ui/traits/trait-impl-missing-method.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `trait_method` + --> $DIR/trait-impl-missing-method.rs:9:1 + | +LL | fn trait_method(&self); + | ----------------------- `trait_method` from trait +... +LL | impl MyTrait for ImplType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ missing `trait_method` in implementation + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0046`. -- cgit 1.4.1-3-g733a5 From 7742d0e230b602a0a73d38b32de47449f3306450 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Jun 2025 15:56:33 +0200 Subject: coretests: move float tests from num to floats module and use a more flexible macro to generate them --- library/coretests/tests/floats/mod.rs | 548 ++++++++++++++++++++++++++++++++++ library/coretests/tests/num/mod.rs | 353 ---------------------- 2 files changed, 548 insertions(+), 353 deletions(-) diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 7e27028a2a2..f9b6c85f871 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -52,6 +52,119 @@ macro_rules! assert_biteq { }; } +mod const_asserts { + // Shadow some assert implementations that would otherwise not compile in a const-context. + // Every macro added here also needs to be added in the `float_test!` macro below. + macro_rules! assert_eq { + ($left:expr, $right:expr $(,)?) => { + std::assert!($left == $right) + }; + ($left:expr, $right:expr, $($arg:tt)+) => { + std::assert!($left == $right, $($arg)+) + }; + } + + pub(crate) use assert_eq; +} + +/// Generate float tests for all our float types, for compile-time and run-time behavior. +/// +/// By default all tests run for all float types. Configuration can be applied via `attrs`. +/// +/// ```ignore (this is only a sketch) +/// float_test! { +/// name: fn_name, /* function under test */ +/// attrs: { +/// // Apply a configuration to the test for a single type +/// f16: #[cfg(target_has_reliable_f16_math)], +/// // Types can be excluded with `cfg(false)` +/// f64: #[cfg(false)], +/// }, +/// test { +/// /* write tests here, using `Float` as the type */ +/// } +/// } +macro_rules! float_test { + ( + name: $name:ident, + attrs: { + $(const: #[ $($const_meta:meta),+ ] ,)? + $(f16: #[ $($f16_meta:meta),+ ] ,)? + $(const f16: #[ $($f16_const_meta:meta),+ ] ,)? + $(f32: #[ $($f32_meta:meta),+ ] ,)? + $(const f32: #[ $($f32_const_meta:meta),+ ] ,)? + $(f64: #[ $($f64_meta:meta),+ ] ,)? + $(const f64: #[ $($f64_const_meta:meta),+ ] ,)? + $(f128: #[ $($f128_meta:meta),+ ] ,)? + $(const f128: #[ $($f128_const_meta:meta),+ ] ,)? + }, + test<$fty:ident> $test:block + ) => { + mod $name { + #[test] + $( $( #[$f16_meta] )+ )? + fn test_f16() { + type $fty = f16; + $test + } + + #[test] + $( $( #[$f32_meta] )+ )? + fn test_f32() { + type $fty = f32; + $test + } + + #[test] + $( $( #[$f64_meta] )+ )? + fn test_f64() { + type $fty = f64; + $test + } + + #[test] + $( $( #[$f128_meta] )+ )? + fn test_f128() { + type $fty = f128; + $test + } + + $( $( #[$const_meta] )+ )? + mod const_ { + use $crate::floats::const_asserts::assert_eq; + + #[test] + $( $( #[$f16_const_meta] )+ )? + fn test_f16() { + type $fty = f16; + const { $test } + } + + #[test] + $( $( #[$f32_const_meta] )+ )? + fn test_f32() { + type $fty = f32; + const { $test } + } + + #[test] + $( $( #[$f64_const_meta] )+ )? + fn test_f64() { + type $fty = f64; + const { $test } + } + + #[test] + $( $( #[$f128_const_meta] )+ )? + fn test_f128() { + type $fty = f128; + const { $test } + } + } + } + }; +} + /// Helper function for testing numeric operations pub fn test_num(ten: T, two: T) where @@ -75,3 +188,438 @@ mod f128; mod f16; mod f32; mod f64; + +float_test! { + name: min, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).min(0.0), 0.0); + assert!((0.0 as Float).min(0.0).is_sign_positive()); + assert_eq!((-0.0 as Float).min(-0.0), -0.0); + assert!((-0.0 as Float).min(-0.0).is_sign_negative()); + assert_eq!((9.0 as Float).min(9.0), 9.0); + assert_eq!((-9.0 as Float).min(0.0), -9.0); + assert_eq!((0.0 as Float).min(9.0), 0.0); + assert!((0.0 as Float).min(9.0).is_sign_positive()); + assert_eq!((-0.0 as Float).min(9.0), -0.0); + assert!((-0.0 as Float).min(9.0).is_sign_negative()); + assert_eq!((-0.0 as Float).min(-9.0), -9.0); + assert_eq!(Float::INFINITY.min(9.0), 9.0); + assert_eq!((9.0 as Float).min(Float::INFINITY), 9.0); + assert_eq!(Float::INFINITY.min(-9.0), -9.0); + assert_eq!((-9.0 as Float).min(Float::INFINITY), -9.0); + assert_eq!(Float::NEG_INFINITY.min(9.0), Float::NEG_INFINITY); + assert_eq!((9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_eq!(Float::NEG_INFINITY.min(-9.0), Float::NEG_INFINITY); + assert_eq!((-9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_eq!(Float::NAN.min(9.0), 9.0); + assert_eq!(Float::NAN.min(-9.0), -9.0); + assert_eq!((9.0 as Float).min(Float::NAN), 9.0); + assert_eq!((-9.0 as Float).min(Float::NAN), -9.0); + assert!(Float::NAN.min(Float::NAN).is_nan()); + } +} + +float_test! { + name: max, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).max(0.0), 0.0); + assert!((0.0 as Float).max(0.0).is_sign_positive()); + assert_eq!((-0.0 as Float).max(-0.0), -0.0); + assert!((-0.0 as Float).max(-0.0).is_sign_negative()); + assert_eq!((9.0 as Float).max(9.0), 9.0); + assert_eq!((-9.0 as Float).max(0.0), 0.0); + assert!((-9.0 as Float).max(0.0).is_sign_positive()); + assert_eq!((-9.0 as Float).max(-0.0), -0.0); + assert!((-9.0 as Float).max(-0.0).is_sign_negative()); + assert_eq!((0.0 as Float).max(9.0), 9.0); + assert_eq!((0.0 as Float).max(-9.0), 0.0); + assert!((0.0 as Float).max(-9.0).is_sign_positive()); + assert_eq!((-0.0 as Float).max(-9.0), -0.0); + assert!((-0.0 as Float).max(-9.0).is_sign_negative()); + assert_eq!(Float::INFINITY.max(9.0), Float::INFINITY); + assert_eq!((9.0 as Float).max(Float::INFINITY), Float::INFINITY); + assert_eq!(Float::INFINITY.max(-9.0), Float::INFINITY); + assert_eq!((-9.0 as Float).max(Float::INFINITY), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.max(9.0), 9.0); + assert_eq!((9.0 as Float).max(Float::NEG_INFINITY), 9.0); + assert_eq!(Float::NEG_INFINITY.max(-9.0), -9.0); + assert_eq!((-9.0 as Float).max(Float::NEG_INFINITY), -9.0); + assert_eq!(Float::NAN.max(9.0), 9.0); + assert_eq!(Float::NAN.max(-9.0), -9.0); + assert_eq!((9.0 as Float).max(Float::NAN), 9.0); + assert_eq!((-9.0 as Float).max(Float::NAN), -9.0); + assert!(Float::NAN.max(Float::NAN).is_nan()); + } +} + +float_test! { + name: minimum, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).minimum(0.0), 0.0); + assert!((0.0 as Float).minimum(0.0).is_sign_positive()); + assert_eq!((-0.0 as Float).minimum(0.0), -0.0); + assert!((-0.0 as Float).minimum(0.0).is_sign_negative()); + assert_eq!((-0.0 as Float).minimum(-0.0), -0.0); + assert!((-0.0 as Float).minimum(-0.0).is_sign_negative()); + assert_eq!((9.0 as Float).minimum(9.0), 9.0); + assert_eq!((-9.0 as Float).minimum(0.0), -9.0); + assert_eq!((0.0 as Float).minimum(9.0), 0.0); + assert!((0.0 as Float).minimum(9.0).is_sign_positive()); + assert_eq!((-0.0 as Float).minimum(9.0), -0.0); + assert!((-0.0 as Float).minimum(9.0).is_sign_negative()); + assert_eq!((-0.0 as Float).minimum(-9.0), -9.0); + assert_eq!(Float::INFINITY.minimum(9.0), 9.0); + assert_eq!((9.0 as Float).minimum(Float::INFINITY), 9.0); + assert_eq!(Float::INFINITY.minimum(-9.0), -9.0); + assert_eq!((-9.0 as Float).minimum(Float::INFINITY), -9.0); + assert_eq!(Float::NEG_INFINITY.minimum(9.0), Float::NEG_INFINITY); + assert_eq!((9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_eq!(Float::NEG_INFINITY.minimum(-9.0), Float::NEG_INFINITY); + assert_eq!((-9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert!(Float::NAN.minimum(9.0).is_nan()); + assert!(Float::NAN.minimum(-9.0).is_nan()); + assert!((9.0 as Float).minimum(Float::NAN).is_nan()); + assert!((-9.0 as Float).minimum(Float::NAN).is_nan()); + assert!(Float::NAN.minimum(Float::NAN).is_nan()); + } +} + +float_test! { + name: maximum, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).maximum(0.0), 0.0); + assert!((0.0 as Float).maximum(0.0).is_sign_positive()); + assert_eq!((-0.0 as Float).maximum(0.0), 0.0); + assert!((-0.0 as Float).maximum(0.0).is_sign_positive()); + assert_eq!((-0.0 as Float).maximum(-0.0), -0.0); + assert!((-0.0 as Float).maximum(-0.0).is_sign_negative()); + assert_eq!((9.0 as Float).maximum(9.0), 9.0); + assert_eq!((-9.0 as Float).maximum(0.0), 0.0); + assert!((-9.0 as Float).maximum(0.0).is_sign_positive()); + assert_eq!((-9.0 as Float).maximum(-0.0), -0.0); + assert!((-9.0 as Float).maximum(-0.0).is_sign_negative()); + assert_eq!((0.0 as Float).maximum(9.0), 9.0); + assert_eq!((0.0 as Float).maximum(-9.0), 0.0); + assert!((0.0 as Float).maximum(-9.0).is_sign_positive()); + assert_eq!((-0.0 as Float).maximum(-9.0), -0.0); + assert!((-0.0 as Float).maximum(-9.0).is_sign_negative()); + assert_eq!(Float::INFINITY.maximum(9.0), Float::INFINITY); + assert_eq!((9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); + assert_eq!(Float::INFINITY.maximum(-9.0), Float::INFINITY); + assert_eq!((-9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.maximum(9.0), 9.0); + assert_eq!((9.0 as Float).maximum(Float::NEG_INFINITY), 9.0); + assert_eq!(Float::NEG_INFINITY.maximum(-9.0), -9.0); + assert_eq!((-9.0 as Float).maximum(Float::NEG_INFINITY), -9.0); + assert!(Float::NAN.maximum(9.0).is_nan()); + assert!(Float::NAN.maximum(-9.0).is_nan()); + assert!((9.0 as Float).maximum(Float::NAN).is_nan()); + assert!((-9.0 as Float).maximum(Float::NAN).is_nan()); + assert!(Float::NAN.maximum(Float::NAN).is_nan()); + } +} + +float_test! { + name: midpoint, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.5 as Float).midpoint(0.5), 0.5); + assert_eq!((0.5 as Float).midpoint(2.5), 1.5); + assert_eq!((3.0 as Float).midpoint(4.0), 3.5); + assert_eq!((-3.0 as Float).midpoint(4.0), 0.5); + assert_eq!((3.0 as Float).midpoint(-4.0), -0.5); + assert_eq!((-3.0 as Float).midpoint(-4.0), -3.5); + assert_eq!((0.0 as Float).midpoint(0.0), 0.0); + assert_eq!((-0.0 as Float).midpoint(-0.0), -0.0); + assert_eq!((-5.0 as Float).midpoint(5.0), 0.0); + assert_eq!(Float::MAX.midpoint(Float::MIN), 0.0); + assert_eq!(Float::MIN.midpoint(Float::MAX), -0.0); + assert_eq!(Float::MAX.midpoint(Float::MIN_POSITIVE), Float::MAX / 2.); + assert_eq!((-Float::MAX).midpoint(Float::MIN_POSITIVE), -Float::MAX / 2.); + assert_eq!(Float::MAX.midpoint(-Float::MIN_POSITIVE), Float::MAX / 2.); + assert_eq!((-Float::MAX).midpoint(-Float::MIN_POSITIVE), -Float::MAX / 2.); + assert_eq!((Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); + assert_eq!((Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); + assert_eq!((-Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); + assert_eq!((-Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); + assert_eq!(Float::MAX.midpoint(Float::MAX), Float::MAX); + assert_eq!( + (Float::MIN_POSITIVE).midpoint(Float::MIN_POSITIVE), + Float::MIN_POSITIVE + ); + assert_eq!( + (-Float::MIN_POSITIVE).midpoint(-Float::MIN_POSITIVE), + -Float::MIN_POSITIVE + ); + assert_eq!(Float::MAX.midpoint(5.0), Float::MAX / 2.0 + 2.5); + assert_eq!(Float::MAX.midpoint(-5.0), Float::MAX / 2.0 - 2.5); + assert_eq!(Float::INFINITY.midpoint(Float::INFINITY), Float::INFINITY); + assert_eq!( + Float::NEG_INFINITY.midpoint(Float::NEG_INFINITY), + Float::NEG_INFINITY + ); + assert!(Float::NAN.midpoint(1.0).is_nan()); + assert!((1.0 as Float).midpoint(Float::NAN).is_nan()); + assert!(Float::NAN.midpoint(Float::NAN).is_nan()); + } +} + +// Separate test since the `for` loops cannot be run in `const`. +float_test! { + name: midpoint_large_magnitude, + attrs: { + const: #[cfg(false)], + // FIXME(f16_f128): `powi` does not work in Miri for these types + f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], + f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], + }, + test { + // test if large differences in magnitude are still correctly computed. + // NOTE: that because of how small x and y are, x + y can never overflow + // so (x + y) / 2.0 is always correct + // in particular, `2.pow(i)` will never be at the max exponent, so it could + // be safely doubled, while j is significantly smaller. + for i in Float::MAX_EXP.saturating_sub(64)..Float::MAX_EXP { + for j in 0..64u8 { + let large = (2.0 as Float).powi(i); + // a much smaller number, such that there is no chance of overflow to test + // potential double rounding in midpoint's implementation. + let small = (2.0 as Float).powi(Float::MAX_EXP - 1) + * Float::EPSILON + * Float::from(j); + + let naive = (large + small) / 2.0; + let midpoint = large.midpoint(small); + + assert_eq!(naive, midpoint); + } + } + } +} + +float_test! { + name: abs, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((-1.0 as Float).abs(), 1.0); + assert_eq!((1.0 as Float).abs(), 1.0); + assert_eq!(Float::NEG_INFINITY.abs(), Float::INFINITY); + assert_eq!(Float::INFINITY.abs(), Float::INFINITY); + } +} + +float_test! { + name: copysign, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((1.0 as Float).copysign(-2.0), -1.0); + assert_eq!((-1.0 as Float).copysign(2.0), 1.0); + assert_eq!(Float::INFINITY.copysign(-0.0), Float::NEG_INFINITY); + assert_eq!(Float::NEG_INFINITY.copysign(0.0), Float::INFINITY); + } +} + +float_test! { + name: rem_euclid, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert!(Float::INFINITY.rem_euclid(42.0 as Float).is_nan()); + assert_eq!((42.0 as Float).rem_euclid(Float::INFINITY), (42.0 as Float)); + assert!((42.0 as Float).rem_euclid(Float::NAN).is_nan()); + assert!(Float::INFINITY.rem_euclid(Float::INFINITY).is_nan()); + assert!(Float::INFINITY.rem_euclid(Float::NAN).is_nan()); + assert!(Float::NAN.rem_euclid(Float::INFINITY).is_nan()); + } +} + +float_test! { + name: div_euclid, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((42.0 as Float).div_euclid(Float::INFINITY), 0.0); + assert!((42.0 as Float).div_euclid(Float::NAN).is_nan()); + assert!(Float::INFINITY.div_euclid(Float::INFINITY).is_nan()); + assert!(Float::INFINITY.div_euclid(Float::NAN).is_nan()); + assert!(Float::NAN.div_euclid(Float::INFINITY).is_nan()); + } +} + +float_test! { + name: floor, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).floor(), 0.0); + assert!((0.0 as Float).floor().is_sign_positive()); + assert_eq!((-0.0 as Float).floor(), -0.0); + assert!((-0.0 as Float).floor().is_sign_negative()); + assert_eq!((0.5 as Float).floor(), 0.0); + assert_eq!((-0.5 as Float).floor(), -1.0); + assert_eq!((1.5 as Float).floor(), 1.0); + assert_eq!(Float::MAX.floor(), Float::MAX); + assert_eq!(Float::MIN.floor(), Float::MIN); + assert_eq!(Float::MIN_POSITIVE.floor(), 0.0); + assert_eq!((-Float::MIN_POSITIVE).floor(), -1.0); + assert!(Float::NAN.floor().is_nan()); + assert_eq!(Float::INFINITY.floor(), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.floor(), Float::NEG_INFINITY); + } +} + +float_test! { + name: ceil, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).ceil(), 0.0); + assert!((0.0 as Float).ceil().is_sign_positive()); + assert_eq!((-0.0 as Float).ceil(), 0.0); + assert!((-0.0 as Float).ceil().is_sign_negative()); + assert_eq!((0.5 as Float).ceil(), 1.0); + assert_eq!((-0.5 as Float).ceil(), 0.0); + assert_eq!(Float::MAX.ceil(), Float::MAX); + assert_eq!(Float::MIN.ceil(), Float::MIN); + assert_eq!(Float::MIN_POSITIVE.ceil(), 1.0); + assert_eq!((-Float::MIN_POSITIVE).ceil(), 0.0); + assert!(Float::NAN.ceil().is_nan()); + assert_eq!(Float::INFINITY.ceil(), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.ceil(), Float::NEG_INFINITY); + } +} + +float_test! { + name: round, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).round(), 0.0); + assert!((0.0 as Float).round().is_sign_positive()); + assert_eq!((-0.0 as Float).round(), -0.0); + assert!((-0.0 as Float).round().is_sign_negative()); + assert_eq!((0.5 as Float).round(), 1.0); + assert_eq!((-0.5 as Float).round(), -1.0); + assert_eq!(Float::MAX.round(), Float::MAX); + assert_eq!(Float::MIN.round(), Float::MIN); + assert_eq!(Float::MIN_POSITIVE.round(), 0.0); + assert_eq!((-Float::MIN_POSITIVE).round(), 0.0); + assert!(Float::NAN.round().is_nan()); + assert_eq!(Float::INFINITY.round(), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.round(), Float::NEG_INFINITY); + } +} + +float_test! { + name: round_ties_even, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).round_ties_even(), 0.0); + assert!((0.0 as Float).round_ties_even().is_sign_positive()); + assert_eq!((-0.0 as Float).round_ties_even(), -0.0); + assert!((-0.0 as Float).round_ties_even().is_sign_negative()); + assert_eq!((0.5 as Float).round_ties_even(), 0.0); + assert!((0.5 as Float).round_ties_even().is_sign_positive()); + assert_eq!((-0.5 as Float).round_ties_even(), -0.0); + assert!((-0.5 as Float).round_ties_even().is_sign_negative()); + assert_eq!(Float::MAX.round_ties_even(), Float::MAX); + assert_eq!(Float::MIN.round_ties_even(), Float::MIN); + assert_eq!(Float::MIN_POSITIVE.round_ties_even(), 0.0); + assert_eq!((-Float::MIN_POSITIVE).round_ties_even(), 0.0); + assert!(Float::NAN.round_ties_even().is_nan()); + assert_eq!(Float::INFINITY.round_ties_even(), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.round_ties_even(), Float::NEG_INFINITY); + } +} + +float_test! { + name: trunc, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).trunc(), 0.0); + assert!((0.0 as Float).trunc().is_sign_positive()); + assert_eq!((-0.0 as Float).trunc(), -0.0); + assert!((-0.0 as Float).trunc().is_sign_negative()); + assert_eq!((0.5 as Float).trunc(), 0.0); + assert!((0.5 as Float).trunc().is_sign_positive()); + assert_eq!((-0.5 as Float).trunc(), -0.0); + assert!((-0.5 as Float).trunc().is_sign_negative()); + assert_eq!(Float::MAX.trunc(), Float::MAX); + assert_eq!(Float::MIN.trunc(), Float::MIN); + assert_eq!(Float::MIN_POSITIVE.trunc(), 0.0); + assert_eq!((-Float::MIN_POSITIVE).trunc(), 0.0); + assert!(Float::NAN.trunc().is_nan()); + assert_eq!(Float::INFINITY.trunc(), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.trunc(), Float::NEG_INFINITY); + } +} + +float_test! { + name: fract, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).fract(), 0.0); + assert!((0.0 as Float).fract().is_sign_positive()); + assert_eq!((-0.0 as Float).fract(), 0.0); + assert!((-0.0 as Float).fract().is_sign_positive()); + assert_eq!((0.5 as Float).fract(), 0.5); + assert!((0.5 as Float).fract().is_sign_positive()); + assert_eq!((-0.5 as Float).fract(), -0.5); + assert!((-0.5 as Float).fract().is_sign_negative()); + assert_eq!(Float::MAX.fract(), 0.0); + assert_eq!(Float::MIN.fract(), 0.0); + assert_eq!(Float::MIN_POSITIVE.fract(), Float::MIN_POSITIVE); + assert!(Float::MIN_POSITIVE.fract().is_sign_positive()); + assert_eq!((-Float::MIN_POSITIVE).fract(), -Float::MIN_POSITIVE); + assert!((-Float::MIN_POSITIVE).fract().is_sign_negative()); + assert!(Float::NAN.fract().is_nan()); + assert!(Float::INFINITY.fract().is_nan()); + assert!(Float::NEG_INFINITY.fract().is_nan()); + } +} diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs index c68b569f86b..6611aa57866 100644 --- a/library/coretests/tests/num/mod.rs +++ b/library/coretests/tests/num/mod.rs @@ -730,356 +730,3 @@ assume_usize_width! { } } } - -// FIXME(141726): there is a lot of duplication between the following tests and -// the tests in `coretests/tests/floats/f*.rs` -// See issue https://github.com/rust-lang/rust/issues/141726 for more details. -macro_rules! test_float { - ($modname: ident, $fassert: ident, $fty: ty) => { - mod $modname { - #[test] - fn min() { - $fassert!((0.0 as $fty).min(0.0), 0.0); - $fassert!((0.0 as $fty).min(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).min(-0.0), -0.0); - $fassert!((-0.0 as $fty).min(-0.0).is_sign_negative()); - $fassert!((9.0 as $fty).min(9.0), 9.0); - $fassert!((-9.0 as $fty).min(0.0), -9.0); - $fassert!((0.0 as $fty).min(9.0), 0.0); - $fassert!((0.0 as $fty).min(9.0).is_sign_positive()); - $fassert!((-0.0 as $fty).min(9.0), -0.0); - $fassert!((-0.0 as $fty).min(9.0).is_sign_negative()); - $fassert!((-0.0 as $fty).min(-9.0), -9.0); - $fassert!(<$fty>::INFINITY.min(9.0), 9.0); - $fassert!((9.0 as $fty).min(<$fty>::INFINITY), 9.0); - $fassert!(<$fty>::INFINITY.min(-9.0), -9.0); - $fassert!((-9.0 as $fty).min(<$fty>::INFINITY), -9.0); - $fassert!(<$fty>::NEG_INFINITY.min(9.0), <$fty>::NEG_INFINITY); - $fassert!((9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NEG_INFINITY.min(-9.0), <$fty>::NEG_INFINITY); - $fassert!((-9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NAN.min(9.0), 9.0); - $fassert!(<$fty>::NAN.min(-9.0), -9.0); - $fassert!((9.0 as $fty).min(<$fty>::NAN), 9.0); - $fassert!((-9.0 as $fty).min(<$fty>::NAN), -9.0); - $fassert!(<$fty>::NAN.min(<$fty>::NAN).is_nan()); - } - #[test] - fn max() { - $fassert!((0.0 as $fty).max(0.0), 0.0); - $fassert!((0.0 as $fty).max(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).max(-0.0), -0.0); - $fassert!((-0.0 as $fty).max(-0.0).is_sign_negative()); - $fassert!((9.0 as $fty).max(9.0), 9.0); - $fassert!((-9.0 as $fty).max(0.0), 0.0); - $fassert!((-9.0 as $fty).max(0.0).is_sign_positive()); - $fassert!((-9.0 as $fty).max(-0.0), -0.0); - $fassert!((-9.0 as $fty).max(-0.0).is_sign_negative()); - $fassert!((0.0 as $fty).max(9.0), 9.0); - $fassert!((0.0 as $fty).max(-9.0), 0.0); - $fassert!((0.0 as $fty).max(-9.0).is_sign_positive()); - $fassert!((-0.0 as $fty).max(-9.0), -0.0); - $fassert!((-0.0 as $fty).max(-9.0).is_sign_negative()); - $fassert!(<$fty>::INFINITY.max(9.0), <$fty>::INFINITY); - $fassert!((9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!(<$fty>::INFINITY.max(-9.0), <$fty>::INFINITY); - $fassert!((-9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.max(9.0), 9.0); - $fassert!((9.0 as $fty).max(<$fty>::NEG_INFINITY), 9.0); - $fassert!(<$fty>::NEG_INFINITY.max(-9.0), -9.0); - $fassert!((-9.0 as $fty).max(<$fty>::NEG_INFINITY), -9.0); - $fassert!(<$fty>::NAN.max(9.0), 9.0); - $fassert!(<$fty>::NAN.max(-9.0), -9.0); - $fassert!((9.0 as $fty).max(<$fty>::NAN), 9.0); - $fassert!((-9.0 as $fty).max(<$fty>::NAN), -9.0); - $fassert!(<$fty>::NAN.max(<$fty>::NAN).is_nan()); - } - #[test] - fn minimum() { - $fassert!((0.0 as $fty).minimum(0.0), 0.0); - $fassert!((0.0 as $fty).minimum(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).minimum(0.0), -0.0); - $fassert!((-0.0 as $fty).minimum(0.0).is_sign_negative()); - $fassert!((-0.0 as $fty).minimum(-0.0), -0.0); - $fassert!((-0.0 as $fty).minimum(-0.0).is_sign_negative()); - $fassert!((9.0 as $fty).minimum(9.0), 9.0); - $fassert!((-9.0 as $fty).minimum(0.0), -9.0); - $fassert!((0.0 as $fty).minimum(9.0), 0.0); - $fassert!((0.0 as $fty).minimum(9.0).is_sign_positive()); - $fassert!((-0.0 as $fty).minimum(9.0), -0.0); - $fassert!((-0.0 as $fty).minimum(9.0).is_sign_negative()); - $fassert!((-0.0 as $fty).minimum(-9.0), -9.0); - $fassert!(<$fty>::INFINITY.minimum(9.0), 9.0); - $fassert!((9.0 as $fty).minimum(<$fty>::INFINITY), 9.0); - $fassert!(<$fty>::INFINITY.minimum(-9.0), -9.0); - $fassert!((-9.0 as $fty).minimum(<$fty>::INFINITY), -9.0); - $fassert!(<$fty>::NEG_INFINITY.minimum(9.0), <$fty>::NEG_INFINITY); - $fassert!((9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NEG_INFINITY.minimum(-9.0), <$fty>::NEG_INFINITY); - $fassert!((-9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NAN.minimum(9.0).is_nan()); - $fassert!(<$fty>::NAN.minimum(-9.0).is_nan()); - $fassert!((9.0 as $fty).minimum(<$fty>::NAN).is_nan()); - $fassert!((-9.0 as $fty).minimum(<$fty>::NAN).is_nan()); - $fassert!(<$fty>::NAN.minimum(<$fty>::NAN).is_nan()); - } - #[test] - fn maximum() { - $fassert!((0.0 as $fty).maximum(0.0), 0.0); - $fassert!((0.0 as $fty).maximum(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).maximum(0.0), 0.0); - $fassert!((-0.0 as $fty).maximum(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).maximum(-0.0), -0.0); - $fassert!((-0.0 as $fty).maximum(-0.0).is_sign_negative()); - $fassert!((9.0 as $fty).maximum(9.0), 9.0); - $fassert!((-9.0 as $fty).maximum(0.0), 0.0); - $fassert!((-9.0 as $fty).maximum(0.0).is_sign_positive()); - $fassert!((-9.0 as $fty).maximum(-0.0), -0.0); - $fassert!((-9.0 as $fty).maximum(-0.0).is_sign_negative()); - $fassert!((0.0 as $fty).maximum(9.0), 9.0); - $fassert!((0.0 as $fty).maximum(-9.0), 0.0); - $fassert!((0.0 as $fty).maximum(-9.0).is_sign_positive()); - $fassert!((-0.0 as $fty).maximum(-9.0), -0.0); - $fassert!((-0.0 as $fty).maximum(-9.0).is_sign_negative()); - $fassert!(<$fty>::INFINITY.maximum(9.0), <$fty>::INFINITY); - $fassert!((9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!(<$fty>::INFINITY.maximum(-9.0), <$fty>::INFINITY); - $fassert!((-9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.maximum(9.0), 9.0); - $fassert!((9.0 as $fty).maximum(<$fty>::NEG_INFINITY), 9.0); - $fassert!(<$fty>::NEG_INFINITY.maximum(-9.0), -9.0); - $fassert!((-9.0 as $fty).maximum(<$fty>::NEG_INFINITY), -9.0); - $fassert!(<$fty>::NAN.maximum(9.0).is_nan()); - $fassert!(<$fty>::NAN.maximum(-9.0).is_nan()); - $fassert!((9.0 as $fty).maximum(<$fty>::NAN).is_nan()); - $fassert!((-9.0 as $fty).maximum(<$fty>::NAN).is_nan()); - $fassert!(<$fty>::NAN.maximum(<$fty>::NAN).is_nan()); - } - #[test] - fn midpoint() { - $fassert!((0.5 as $fty).midpoint(0.5), 0.5); - $fassert!((0.5 as $fty).midpoint(2.5), 1.5); - $fassert!((3.0 as $fty).midpoint(4.0), 3.5); - $fassert!((-3.0 as $fty).midpoint(4.0), 0.5); - $fassert!((3.0 as $fty).midpoint(-4.0), -0.5); - $fassert!((-3.0 as $fty).midpoint(-4.0), -3.5); - $fassert!((0.0 as $fty).midpoint(0.0), 0.0); - $fassert!((-0.0 as $fty).midpoint(-0.0), -0.0); - $fassert!((-5.0 as $fty).midpoint(5.0), 0.0); - $fassert!(<$fty>::MAX.midpoint(<$fty>::MIN), 0.0); - $fassert!(<$fty>::MIN.midpoint(<$fty>::MAX), -0.0); - $fassert!(<$fty>::MAX.midpoint(<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); - $fassert!((-<$fty>::MAX).midpoint(<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.); - $fassert!(<$fty>::MAX.midpoint(-<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); - $fassert!((-<$fty>::MAX).midpoint(-<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.); - $fassert!((<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.); - $fassert!((<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.); - $fassert!((-<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.); - $fassert!((-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.); - $fassert!(<$fty>::MAX.midpoint(<$fty>::MAX), <$fty>::MAX); - $fassert!( - (<$fty>::MIN_POSITIVE).midpoint(<$fty>::MIN_POSITIVE), - <$fty>::MIN_POSITIVE - ); - $fassert!( - (-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MIN_POSITIVE), - -<$fty>::MIN_POSITIVE - ); - $fassert!(<$fty>::MAX.midpoint(5.0), <$fty>::MAX / 2.0 + 2.5); - $fassert!(<$fty>::MAX.midpoint(-5.0), <$fty>::MAX / 2.0 - 2.5); - $fassert!(<$fty>::INFINITY.midpoint(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!( - <$fty>::NEG_INFINITY.midpoint(<$fty>::NEG_INFINITY), - <$fty>::NEG_INFINITY - ); - $fassert!(<$fty>::NAN.midpoint(1.0).is_nan()); - $fassert!((1.0 as $fty).midpoint(<$fty>::NAN).is_nan()); - $fassert!(<$fty>::NAN.midpoint(<$fty>::NAN).is_nan()); - - // test if large differences in magnitude are still correctly computed. - // NOTE: that because of how small x and y are, x + y can never overflow - // so (x + y) / 2.0 is always correct - // in particular, `2.pow(i)` will never be at the max exponent, so it could - // be safely doubled, while j is significantly smaller. - for i in <$fty>::MAX_EXP.saturating_sub(64)..<$fty>::MAX_EXP { - for j in 0..64u8 { - let large = (2.0 as $fty).powi(i); - // a much smaller number, such that there is no chance of overflow to test - // potential double rounding in midpoint's implementation. - let small = (2.0 as $fty).powi(<$fty>::MAX_EXP - 1) - * <$fty>::EPSILON - * <$fty>::from(j); - - let naive = (large + small) / 2.0; - let midpoint = large.midpoint(small); - - assert_eq!(naive, midpoint); - } - } - } - #[test] - fn abs() { - $fassert!((-1.0 as $fty).abs(), 1.0); - $fassert!((1.0 as $fty).abs(), 1.0); - $fassert!(<$fty>::NEG_INFINITY.abs(), <$fty>::INFINITY); - $fassert!(<$fty>::INFINITY.abs(), <$fty>::INFINITY); - } - #[test] - fn copysign() { - $fassert!((1.0 as $fty).copysign(-2.0), -1.0); - $fassert!((-1.0 as $fty).copysign(2.0), 1.0); - $fassert!(<$fty>::INFINITY.copysign(-0.0), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NEG_INFINITY.copysign(0.0), <$fty>::INFINITY); - } - #[test] - fn rem_euclid() { - // FIXME: Use $fassert when rem_euclid becomes const - assert!(<$fty>::INFINITY.rem_euclid((42.0 as $fty)).is_nan()); - assert_eq!((42.0 as $fty).rem_euclid(<$fty>::INFINITY), (42.0 as $fty)); - assert!((42.0 as $fty).rem_euclid(<$fty>::NAN).is_nan()); - assert!(<$fty>::INFINITY.rem_euclid(<$fty>::INFINITY).is_nan()); - assert!(<$fty>::INFINITY.rem_euclid(<$fty>::NAN).is_nan()); - assert!(<$fty>::NAN.rem_euclid(<$fty>::INFINITY).is_nan()); - } - #[test] - fn div_euclid() { - // FIXME: Use $fassert when div_euclid becomes const - assert_eq!((42.0 as $fty).div_euclid(<$fty>::INFINITY), 0.0); - assert!((42.0 as $fty).div_euclid(<$fty>::NAN).is_nan()); - assert!(<$fty>::INFINITY.div_euclid(<$fty>::INFINITY).is_nan()); - assert!(<$fty>::INFINITY.div_euclid(<$fty>::NAN).is_nan()); - assert!(<$fty>::NAN.div_euclid(<$fty>::INFINITY).is_nan()); - } - #[test] - fn floor() { - $fassert!((0.0 as $fty).floor(), 0.0); - $fassert!((0.0 as $fty).floor().is_sign_positive()); - $fassert!((-0.0 as $fty).floor(), -0.0); - $fassert!((-0.0 as $fty).floor().is_sign_negative()); - $fassert!((0.5 as $fty).floor(), 0.0); - $fassert!((-0.5 as $fty).floor(), -1.0); - $fassert!((1.5 as $fty).floor(), 1.0); - $fassert!(<$fty>::MAX.floor(), <$fty>::MAX); - $fassert!(<$fty>::MIN.floor(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.floor(), 0.0); - $fassert!((-<$fty>::MIN_POSITIVE).floor(), -1.0); - $fassert!(<$fty>::NAN.floor().is_nan()); - $fassert!(<$fty>::INFINITY.floor(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.floor(), <$fty>::NEG_INFINITY); - } - #[test] - fn ceil() { - $fassert!((0.0 as $fty).ceil(), 0.0); - $fassert!((0.0 as $fty).ceil().is_sign_positive()); - $fassert!((-0.0 as $fty).ceil(), 0.0); - $fassert!((-0.0 as $fty).ceil().is_sign_negative()); - $fassert!((0.5 as $fty).ceil(), 1.0); - $fassert!((-0.5 as $fty).ceil(), 0.0); - $fassert!(<$fty>::MAX.ceil(), <$fty>::MAX); - $fassert!(<$fty>::MIN.ceil(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.ceil(), 1.0); - $fassert!((-<$fty>::MIN_POSITIVE).ceil(), 0.0); - $fassert!(<$fty>::NAN.ceil().is_nan()); - $fassert!(<$fty>::INFINITY.ceil(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.ceil(), <$fty>::NEG_INFINITY); - } - #[test] - fn round() { - $fassert!((0.0 as $fty).round(), 0.0); - $fassert!((0.0 as $fty).round().is_sign_positive()); - $fassert!((-0.0 as $fty).round(), -0.0); - $fassert!((-0.0 as $fty).round().is_sign_negative()); - $fassert!((0.5 as $fty).round(), 1.0); - $fassert!((-0.5 as $fty).round(), -1.0); - $fassert!(<$fty>::MAX.round(), <$fty>::MAX); - $fassert!(<$fty>::MIN.round(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.round(), 0.0); - $fassert!((-<$fty>::MIN_POSITIVE).round(), 0.0); - $fassert!(<$fty>::NAN.round().is_nan()); - $fassert!(<$fty>::INFINITY.round(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.round(), <$fty>::NEG_INFINITY); - } - #[test] - fn round_ties_even() { - $fassert!((0.0 as $fty).round_ties_even(), 0.0); - $fassert!((0.0 as $fty).round_ties_even().is_sign_positive()); - $fassert!((-0.0 as $fty).round_ties_even(), -0.0); - $fassert!((-0.0 as $fty).round_ties_even().is_sign_negative()); - $fassert!((0.5 as $fty).round_ties_even(), 0.0); - $fassert!((0.5 as $fty).round_ties_even().is_sign_positive()); - $fassert!((-0.5 as $fty).round_ties_even(), -0.0); - $fassert!((-0.5 as $fty).round_ties_even().is_sign_negative()); - $fassert!(<$fty>::MAX.round_ties_even(), <$fty>::MAX); - $fassert!(<$fty>::MIN.round_ties_even(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.round_ties_even(), 0.0); - $fassert!((-<$fty>::MIN_POSITIVE).round_ties_even(), 0.0); - $fassert!(<$fty>::NAN.round_ties_even().is_nan()); - $fassert!(<$fty>::INFINITY.round_ties_even(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.round_ties_even(), <$fty>::NEG_INFINITY); - } - #[test] - fn trunc() { - $fassert!((0.0 as $fty).trunc(), 0.0); - $fassert!((0.0 as $fty).trunc().is_sign_positive()); - $fassert!((-0.0 as $fty).trunc(), -0.0); - $fassert!((-0.0 as $fty).trunc().is_sign_negative()); - $fassert!((0.5 as $fty).trunc(), 0.0); - $fassert!((0.5 as $fty).trunc().is_sign_positive()); - $fassert!((-0.5 as $fty).trunc(), -0.0); - $fassert!((-0.5 as $fty).trunc().is_sign_negative()); - $fassert!(<$fty>::MAX.trunc(), <$fty>::MAX); - $fassert!(<$fty>::MIN.trunc(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.trunc(), 0.0); - $fassert!((-<$fty>::MIN_POSITIVE).trunc(), 0.0); - $fassert!(<$fty>::NAN.trunc().is_nan()); - $fassert!(<$fty>::INFINITY.trunc(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.trunc(), <$fty>::NEG_INFINITY); - } - #[test] - fn fract() { - $fassert!((0.0 as $fty).fract(), 0.0); - $fassert!((0.0 as $fty).fract().is_sign_positive()); - $fassert!((-0.0 as $fty).fract(), 0.0); - $fassert!((-0.0 as $fty).fract().is_sign_positive()); - $fassert!((0.5 as $fty).fract(), 0.5); - $fassert!((0.5 as $fty).fract().is_sign_positive()); - $fassert!((-0.5 as $fty).fract(), -0.5); - $fassert!((-0.5 as $fty).fract().is_sign_negative()); - $fassert!(<$fty>::MAX.fract(), 0.0); - $fassert!(<$fty>::MIN.fract(), 0.0); - $fassert!(<$fty>::MIN_POSITIVE.fract(), <$fty>::MIN_POSITIVE); - $fassert!(<$fty>::MIN_POSITIVE.fract().is_sign_positive()); - $fassert!((-<$fty>::MIN_POSITIVE).fract(), -<$fty>::MIN_POSITIVE); - $fassert!((-<$fty>::MIN_POSITIVE).fract().is_sign_negative()); - $fassert!(<$fty>::NAN.fract().is_nan()); - $fassert!(<$fty>::INFINITY.fract().is_nan()); - $fassert!(<$fty>::NEG_INFINITY.fract().is_nan()); - } - } - }; -} - -// Custom assert macro that distribute between assert! and assert_eq! in a non-const context -macro_rules! float_assert { - ($b:expr) => { - assert!($b); - }; - ($left:expr, $right:expr) => { - assert_eq!($left, $right); - }; -} - -// Custom assert macro that only uses assert! in a const context -macro_rules! float_const_assert { - ($b:expr) => { - assert!(const { $b }); - }; - ($left:expr, $right:expr) => { - assert!(const { $left == $right }); - }; -} - -test_float!(f32, float_assert, f32); -test_float!(f32_const, float_const_assert, f32); -test_float!(f64, float_assert, f64); -test_float!(f64_const, float_const_assert, f64); -- cgit 1.4.1-3-g733a5 From 9a50cb4a0caa07b7b751afb70464066e4d6985d3 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Fri, 28 Mar 2025 16:12:07 -0400 Subject: Introduce the `mismatched_lifetime_syntaxes` lint --- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_lint/messages.ftl | 22 + compiler/rustc_lint/src/lib.rs | 3 + compiler/rustc_lint/src/lifetime_syntax.rs | 503 +++++++++++++++++++++ compiler/rustc_lint/src/lints.rs | 125 +++++ src/tools/miri/tests/pass/fat_ptr.rs | 4 +- tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs | 318 +++++++++++++ .../lifetimes/mismatched-lifetime-syntaxes.stderr | 473 +++++++++++++++++++ 8 files changed, 1447 insertions(+), 3 deletions(-) create mode 100644 compiler/rustc_lint/src/lifetime_syntax.rs create mode 100644 tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs create mode 100644 tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 974c24ef0f8..2b197c716cd 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -206,7 +206,7 @@ impl ParamName { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)] pub enum LifetimeKind { /// User-given names or fresh (synthetic) names. Param(LocalDefId), diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 17485a838f3..ac9c772c427 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -518,6 +518,28 @@ lint_metavariable_still_repeating = variable `{$name}` is still repeating at thi lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator +lint_mismatched_lifetime_syntaxes = + lifetime flowing from input to output with different syntax can be confusing + .label_mismatched_lifetime_syntaxes_inputs = + {$n_inputs -> + [one] this lifetime flows + *[other] these lifetimes flow + } to the output + .label_mismatched_lifetime_syntaxes_outputs = + the {$n_outputs -> + [one] lifetime gets + *[other] lifetimes get + } resolved as `{$lifetime_name}` + +lint_mismatched_lifetime_syntaxes_suggestion_explicit = + one option is to consistently use `{$lifetime_name}` + +lint_mismatched_lifetime_syntaxes_suggestion_implicit = + one option is to consistently remove the lifetime + +lint_mismatched_lifetime_syntaxes_suggestion_mixed = + one option is to remove the lifetime for references and use the anonymous lifetime for paths + lint_missing_fragment_specifier = missing fragment specifier lint_missing_unsafe_on_extern = extern blocks should be unsafe diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 0a52e42e442..0439befc6ba 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -55,6 +55,7 @@ mod invalid_from_utf8; mod late; mod let_underscore; mod levels; +mod lifetime_syntax; mod lints; mod macro_expr_fragment_specifier_2024_migration; mod map_unit_fn; @@ -96,6 +97,7 @@ use impl_trait_overcaptures::ImplTraitOvercaptures; use internal::*; use invalid_from_utf8::*; use let_underscore::*; +use lifetime_syntax::*; use macro_expr_fragment_specifier_2024_migration::*; use map_unit_fn::*; use multiple_supertrait_upcastable::*; @@ -246,6 +248,7 @@ late_lint_methods!( StaticMutRefs: StaticMutRefs, UnqualifiedLocalImports: UnqualifiedLocalImports, CheckTransmutes: CheckTransmutes, + LifetimeSyntax: LifetimeSyntax, ] ] ); diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs new file mode 100644 index 00000000000..f895cdb2a54 --- /dev/null +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -0,0 +1,503 @@ +use rustc_data_structures::fx::FxIndexMap; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::{self as hir, LifetimeSource}; +use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::Span; +use tracing::instrument; + +use crate::{LateContext, LateLintPass, LintContext, lints}; + +declare_lint! { + /// The `mismatched_lifetime_syntaxes` lint detects when the same + /// lifetime is referred to by different syntaxes between function + /// arguments and return values. + /// + /// The three kinds of syntaxes are: + /// + /// 1. Named lifetimes. These are references (`&'a str`) or paths + /// (`Person<'a>`) that use a lifetime with a name, such as + /// `'static` or `'a`. + /// + /// 2. Elided lifetimes. These are references with no explicit + /// lifetime (`&str`), references using the anonymous lifetime + /// (`&'_ str`), and paths using the anonymous lifetime + /// (`Person<'_>`). + /// + /// 3. Hidden lifetimes. These are paths that do not contain any + /// visual indication that it contains a lifetime (`Person`). + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(mismatched_lifetime_syntaxes)] + /// + /// pub fn mixing_named_with_elided(v: &'static u8) -> &u8 { + /// v + /// } + /// + /// struct Person<'a> { + /// name: &'a str, + /// } + /// + /// pub fn mixing_hidden_with_elided(v: Person) -> Person<'_> { + /// v + /// } + /// + /// struct Foo; + /// + /// impl Foo { + /// // Lifetime elision results in the output lifetime becoming + /// // `'static`, which is not what was intended. + /// pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { + /// unsafe { &mut *(x as *mut _) } + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Lifetime elision is useful because it frees you from having to + /// give each lifetime its own name and show the relation of input + /// and output lifetimes for common cases. However, a lifetime + /// that uses inconsistent syntax between related arguments and + /// return values is more confusing. + /// + /// In certain `unsafe` code, lifetime elision combined with + /// inconsistent lifetime syntax may result in unsound code. + pub MISMATCHED_LIFETIME_SYNTAXES, + Allow, + "detects when a lifetime uses different syntax between arguments and return values" +} + +declare_lint_pass!(LifetimeSyntax => [MISMATCHED_LIFETIME_SYNTAXES]); + +impl<'tcx> LateLintPass<'tcx> for LifetimeSyntax { + #[instrument(skip_all)] + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + _: hir::intravisit::FnKind<'tcx>, + fd: &'tcx hir::FnDecl<'tcx>, + _: &'tcx hir::Body<'tcx>, + _: rustc_span::Span, + _: rustc_span::def_id::LocalDefId, + ) { + let mut input_map = Default::default(); + let mut output_map = Default::default(); + + for input in fd.inputs { + LifetimeInfoCollector::collect(input, &mut input_map); + } + + if let hir::FnRetTy::Return(output) = fd.output { + LifetimeInfoCollector::collect(output, &mut output_map); + } + + report_mismatches(cx, &input_map, &output_map); + } +} + +#[instrument(skip_all)] +fn report_mismatches<'tcx>( + cx: &LateContext<'tcx>, + inputs: &LifetimeInfoMap<'tcx>, + outputs: &LifetimeInfoMap<'tcx>, +) { + for (resolved_lifetime, output_info) in outputs { + if let Some(input_info) = inputs.get(resolved_lifetime) { + if !lifetimes_use_matched_syntax(input_info, output_info) { + emit_mismatch_diagnostic(cx, input_info, output_info); + } + } + } +} + +fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool { + // Categorize lifetimes into source/syntax buckets. + let mut n_hidden = 0; + let mut n_elided = 0; + let mut n_named = 0; + + for info in input_info.iter().chain(output_info) { + use LifetimeSource::*; + use hir::LifetimeSyntax::*; + + let syntax_source = (info.lifetime.syntax, info.lifetime.source); + + match syntax_source { + // Ignore any other kind of lifetime. + (_, Other) => continue, + + // E.g. `&T`. + (Implicit, Reference | OutlivesBound | PreciseCapturing) | + // E.g. `&'_ T`. + (ExplicitAnonymous, Reference | OutlivesBound | PreciseCapturing) | + // E.g. `ContainsLifetime<'_>`. + (ExplicitAnonymous, Path { .. }) => n_elided += 1, + + // E.g. `ContainsLifetime`. + (Implicit, Path { .. }) => n_hidden += 1, + + // E.g. `&'a T`. + (ExplicitBound, Reference | OutlivesBound | PreciseCapturing) | + // E.g. `ContainsLifetime<'a>`. + (ExplicitBound, Path { .. }) => n_named += 1, + }; + } + + let syntax_counts = (n_hidden, n_elided, n_named); + tracing::debug!(?syntax_counts); + + matches!(syntax_counts, (_, 0, 0) | (0, _, 0) | (0, 0, _)) +} + +fn emit_mismatch_diagnostic<'tcx>( + cx: &LateContext<'tcx>, + input_info: &[Info<'_>], + output_info: &[Info<'_>], +) { + // There can only ever be zero or one bound lifetime + // for a given lifetime resolution. + let mut bound_lifetime = None; + + // We offer the following kinds of suggestions (when appropriate + // such that the suggestion wouldn't violate the lint): + // + // 1. Every lifetime becomes named, when there is already a + // user-provided name. + // + // 2. A "mixed" signature, where references become implicit + // and paths become explicitly anonymous. + // + // 3. Every lifetime becomes implicit. + // + // 4. Every lifetime becomes explicitly anonymous. + // + // Number 2 is arguably the most common pattern and the one we + // should push strongest. Number 3 is likely the next most common, + // followed by number 1. Coming in at a distant last would be + // number 4. + // + // Beyond these, there are variants of acceptable signatures that + // we won't suggest because they are very low-value. For example, + // we will never suggest `fn(&T1, &'_ T2) -> &T3` even though that + // would pass the lint. + // + // The following collections are the lifetime instances that we + // suggest changing to a given alternate style. + + // 1. Convert all to named. + let mut suggest_change_to_explicit_bound = Vec::new(); + + // 2. Convert to mixed. We track each kind of change separately. + let mut suggest_change_to_mixed_implicit = Vec::new(); + let mut suggest_change_to_mixed_explicit_anonymous = Vec::new(); + + // 3. Convert all to implicit. + let mut suggest_change_to_implicit = Vec::new(); + + // 4. Convert all to explicit anonymous. + let mut suggest_change_to_explicit_anonymous = Vec::new(); + + // Some styles prevent using implicit syntax at all. + let mut allow_suggesting_implicit = true; + + // It only makes sense to suggest mixed if we have both sources. + let mut saw_a_reference = false; + let mut saw_a_path = false; + + for info in input_info.iter().chain(output_info) { + use LifetimeSource::*; + use hir::LifetimeSyntax::*; + + let syntax_source = (info.lifetime.syntax, info.lifetime.source); + + if let (_, Other) = syntax_source { + // Ignore any other kind of lifetime. + continue; + } + + if let (ExplicitBound, _) = syntax_source { + bound_lifetime = Some(info); + } + + match syntax_source { + // E.g. `&T`. + (Implicit, Reference) => { + suggest_change_to_explicit_anonymous.push(info); + suggest_change_to_explicit_bound.push(info); + } + + // E.g. `&'_ T`. + (ExplicitAnonymous, Reference) => { + suggest_change_to_implicit.push(info); + suggest_change_to_mixed_implicit.push(info); + suggest_change_to_explicit_bound.push(info); + } + + // E.g. `ContainsLifetime`. + (Implicit, Path { .. }) => { + suggest_change_to_mixed_explicit_anonymous.push(info); + suggest_change_to_explicit_anonymous.push(info); + suggest_change_to_explicit_bound.push(info); + } + + // E.g. `ContainsLifetime<'_>`. + (ExplicitAnonymous, Path { .. }) => { + suggest_change_to_explicit_bound.push(info); + } + + // E.g. `&'a T`. + (ExplicitBound, Reference) => { + suggest_change_to_implicit.push(info); + suggest_change_to_mixed_implicit.push(info); + suggest_change_to_explicit_anonymous.push(info); + } + + // E.g. `ContainsLifetime<'a>`. + (ExplicitBound, Path { .. }) => { + suggest_change_to_mixed_explicit_anonymous.push(info); + suggest_change_to_explicit_anonymous.push(info); + } + + (Implicit, OutlivesBound | PreciseCapturing) => { + panic!("This syntax / source combination is not possible"); + } + + // E.g. `+ '_`, `+ use<'_>`. + (ExplicitAnonymous, OutlivesBound | PreciseCapturing) => { + suggest_change_to_explicit_bound.push(info); + } + + // E.g. `+ 'a`, `+ use<'a>`. + (ExplicitBound, OutlivesBound | PreciseCapturing) => { + suggest_change_to_mixed_explicit_anonymous.push(info); + suggest_change_to_explicit_anonymous.push(info); + } + + (_, Other) => { + panic!("This syntax / source combination has already been skipped"); + } + } + + if matches!(syntax_source, (_, Path { .. } | OutlivesBound | PreciseCapturing)) { + allow_suggesting_implicit = false; + } + + match syntax_source { + (_, Reference) => saw_a_reference = true, + (_, Path { .. }) => saw_a_path = true, + _ => {} + } + } + + let make_implicit_suggestions = + |infos: &[&Info<'_>]| infos.iter().map(|i| i.removing_span()).collect::>(); + + let inputs = input_info.iter().map(|info| info.reporting_span()).collect(); + let outputs = output_info.iter().map(|info| info.reporting_span()).collect(); + + let explicit_bound_suggestion = bound_lifetime.map(|info| { + build_mismatch_suggestion(info.lifetime_name(), &suggest_change_to_explicit_bound) + }); + + let is_bound_static = bound_lifetime.is_some_and(|info| info.is_static()); + + tracing::debug!(?bound_lifetime, ?explicit_bound_suggestion, ?is_bound_static); + + let should_suggest_mixed = + // Do we have a mixed case? + (saw_a_reference && saw_a_path) && + // Is there anything to change? + (!suggest_change_to_mixed_implicit.is_empty() || + !suggest_change_to_mixed_explicit_anonymous.is_empty()) && + // If we have `'static`, we don't want to remove it. + !is_bound_static; + + let mixed_suggestion = should_suggest_mixed.then(|| { + let implicit_suggestions = make_implicit_suggestions(&suggest_change_to_mixed_implicit); + + let explicit_anonymous_suggestions = suggest_change_to_mixed_explicit_anonymous + .iter() + .map(|info| info.suggestion("'_")) + .collect(); + + lints::MismatchedLifetimeSyntaxesSuggestion::Mixed { + implicit_suggestions, + explicit_anonymous_suggestions, + tool_only: false, + } + }); + + tracing::debug!( + ?suggest_change_to_mixed_implicit, + ?suggest_change_to_mixed_explicit_anonymous, + ?mixed_suggestion, + ); + + let should_suggest_implicit = + // Is there anything to change? + !suggest_change_to_implicit.is_empty() && + // We never want to hide the lifetime in a path (or similar). + allow_suggesting_implicit && + // If we have `'static`, we don't want to remove it. + !is_bound_static; + + let implicit_suggestion = should_suggest_implicit.then(|| { + let suggestions = make_implicit_suggestions(&suggest_change_to_implicit); + + lints::MismatchedLifetimeSyntaxesSuggestion::Implicit { suggestions, tool_only: false } + }); + + tracing::debug!( + ?should_suggest_implicit, + ?suggest_change_to_implicit, + allow_suggesting_implicit, + ?implicit_suggestion, + ); + + let should_suggest_explicit_anonymous = + // Is there anything to change? + !suggest_change_to_explicit_anonymous.is_empty() && + // If we have `'static`, we don't want to remove it. + !is_bound_static; + + let explicit_anonymous_suggestion = should_suggest_explicit_anonymous + .then(|| build_mismatch_suggestion("'_", &suggest_change_to_explicit_anonymous)); + + tracing::debug!( + ?should_suggest_explicit_anonymous, + ?suggest_change_to_explicit_anonymous, + ?explicit_anonymous_suggestion, + ); + + let lifetime_name = bound_lifetime.map(|info| info.lifetime_name()).unwrap_or("'_").to_owned(); + + // We can produce a number of suggestions which may overwhelm + // the user. Instead, we order the suggestions based on Rust + // idioms. The "best" choice is shown to the user and the + // remaining choices are shown to tools only. + let mut suggestions = Vec::new(); + suggestions.extend(explicit_bound_suggestion); + suggestions.extend(mixed_suggestion); + suggestions.extend(implicit_suggestion); + suggestions.extend(explicit_anonymous_suggestion); + + cx.emit_span_lint( + MISMATCHED_LIFETIME_SYNTAXES, + Vec::clone(&inputs), + lints::MismatchedLifetimeSyntaxes { lifetime_name, inputs, outputs, suggestions }, + ); +} + +fn build_mismatch_suggestion( + lifetime_name: &str, + infos: &[&Info<'_>], +) -> lints::MismatchedLifetimeSyntaxesSuggestion { + let lifetime_name = lifetime_name.to_owned(); + + let suggestions = infos.iter().map(|info| info.suggestion(&lifetime_name)).collect(); + + lints::MismatchedLifetimeSyntaxesSuggestion::Explicit { + lifetime_name, + suggestions, + tool_only: false, + } +} + +#[derive(Debug)] +struct Info<'tcx> { + type_span: Span, + referenced_type_span: Option, + lifetime: &'tcx hir::Lifetime, +} + +impl<'tcx> Info<'tcx> { + fn lifetime_name(&self) -> &str { + self.lifetime.ident.as_str() + } + + fn is_static(&self) -> bool { + self.lifetime.is_static() + } + + /// When reporting a lifetime that is implicit, we expand the span + /// to include the type. Otherwise we end up pointing at nothing, + /// which is a bit confusing. + fn reporting_span(&self) -> Span { + if self.lifetime.is_implicit() { self.type_span } else { self.lifetime.ident.span } + } + + /// When removing an explicit lifetime from a reference, + /// we want to remove the whitespace after the lifetime. + /// + /// ```rust + /// fn x(a: &'_ u8) {} + /// ``` + /// + /// Should become: + /// + /// ```rust + /// fn x(a: &u8) {} + /// ``` + // FIXME: Ideally, we'd also remove the lifetime declaration. + fn removing_span(&self) -> Span { + let mut span = self.suggestion("'dummy").0; + + if let Some(referenced_type_span) = self.referenced_type_span { + span = span.until(referenced_type_span); + } + + span + } + + fn suggestion(&self, lifetime_name: &str) -> (Span, String) { + self.lifetime.suggestion(lifetime_name) + } +} + +type LifetimeInfoMap<'tcx> = FxIndexMap<&'tcx hir::LifetimeKind, Vec>>; + +struct LifetimeInfoCollector<'a, 'tcx> { + type_span: Span, + referenced_type_span: Option, + map: &'a mut LifetimeInfoMap<'tcx>, +} + +impl<'a, 'tcx> LifetimeInfoCollector<'a, 'tcx> { + fn collect(ty: &'tcx hir::Ty<'tcx>, map: &'a mut LifetimeInfoMap<'tcx>) { + let mut this = Self { type_span: ty.span, referenced_type_span: None, map }; + + intravisit::walk_unambig_ty(&mut this, ty); + } +} + +impl<'a, 'tcx> Visitor<'tcx> for LifetimeInfoCollector<'a, 'tcx> { + #[instrument(skip(self))] + fn visit_lifetime(&mut self, lifetime: &'tcx hir::Lifetime) { + let type_span = self.type_span; + let referenced_type_span = self.referenced_type_span; + + let info = Info { type_span, referenced_type_span, lifetime }; + + self.map.entry(&lifetime.kind).or_default().push(info); + } + + #[instrument(skip(self))] + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) -> Self::Result { + let old_type_span = self.type_span; + let old_referenced_type_span = self.referenced_type_span; + + self.type_span = ty.span; + if let hir::TyKind::Ref(_, ty) = ty.kind { + self.referenced_type_span = Some(ty.ty.span); + } + + intravisit::walk_ty(self, ty); + + self.type_span = old_type_span; + self.referenced_type_span = old_referenced_type_span; + } +} diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 10d0e2c93a8..53fbe158885 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3241,3 +3241,128 @@ pub(crate) struct ReservedMultihash { #[suggestion(code = " ", applicability = "machine-applicable")] pub suggestion: Span, } + +#[derive(Debug)] +pub(crate) struct MismatchedLifetimeSyntaxes { + pub lifetime_name: String, + pub inputs: Vec, + pub outputs: Vec, + + pub suggestions: Vec, +} + +impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSyntaxes { + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) { + diag.primary_message(fluent::lint_mismatched_lifetime_syntaxes); + + diag.arg("lifetime_name", self.lifetime_name); + + diag.arg("n_inputs", self.inputs.len()); + for input in self.inputs { + let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_inputs); + diag.span_label(input, a); + } + + diag.arg("n_outputs", self.outputs.len()); + for output in self.outputs { + let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_outputs); + diag.span_label(output, a); + } + + let mut suggestions = self.suggestions.into_iter(); + if let Some(s) = suggestions.next() { + diag.subdiagnostic(s); + + for mut s in suggestions { + s.make_tool_only(); + diag.subdiagnostic(s); + } + } + } +} + +#[derive(Debug)] +pub(crate) enum MismatchedLifetimeSyntaxesSuggestion { + Implicit { + suggestions: Vec, + tool_only: bool, + }, + + Mixed { + implicit_suggestions: Vec, + explicit_anonymous_suggestions: Vec<(Span, String)>, + tool_only: bool, + }, + + Explicit { + lifetime_name: String, + suggestions: Vec<(Span, String)>, + tool_only: bool, + }, +} + +impl MismatchedLifetimeSyntaxesSuggestion { + fn make_tool_only(&mut self) { + use MismatchedLifetimeSyntaxesSuggestion::*; + + let tool_only = match self { + Implicit { tool_only, .. } | Mixed { tool_only, .. } | Explicit { tool_only, .. } => { + tool_only + } + }; + + *tool_only = true; + } +} + +impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { + use MismatchedLifetimeSyntaxesSuggestion::*; + + let style = |tool_only| { + if tool_only { SuggestionStyle::CompletelyHidden } else { SuggestionStyle::ShowAlways } + }; + + match self { + Implicit { suggestions, tool_only } => { + let suggestions = suggestions.into_iter().map(|s| (s, String::new())).collect(); + diag.multipart_suggestion_with_style( + fluent::lint_mismatched_lifetime_syntaxes_suggestion_implicit, + suggestions, + Applicability::MachineApplicable, + style(tool_only), + ); + } + + Mixed { implicit_suggestions, explicit_anonymous_suggestions, tool_only } => { + let implicit_suggestions = + implicit_suggestions.into_iter().map(|s| (s, String::new())); + + let suggestions = + implicit_suggestions.chain(explicit_anonymous_suggestions).collect(); + + diag.multipart_suggestion_with_style( + fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed, + suggestions, + Applicability::MachineApplicable, + style(tool_only), + ); + } + + Explicit { lifetime_name, suggestions, tool_only } => { + diag.arg("lifetime_name", lifetime_name); + + let msg = diag.eagerly_translate( + fluent::lint_mismatched_lifetime_syntaxes_suggestion_explicit, + ); + + diag.multipart_suggestion_with_style( + msg, + suggestions, + Applicability::MachineApplicable, + style(tool_only), + ); + } + } + } +} diff --git a/src/tools/miri/tests/pass/fat_ptr.rs b/src/tools/miri/tests/pass/fat_ptr.rs index c5603d2cf80..13608b8f898 100644 --- a/src/tools/miri/tests/pass/fat_ptr.rs +++ b/src/tools/miri/tests/pass/fat_ptr.rs @@ -19,11 +19,11 @@ fn fat_ptr_via_local(a: &[u8]) -> &[u8] { x } -fn fat_ptr_from_struct(s: FatPtrContainer) -> &[u8] { +fn fat_ptr_from_struct(s: FatPtrContainer<'_>) -> &[u8] { s.ptr } -fn fat_ptr_to_struct(a: &[u8]) -> FatPtrContainer { +fn fat_ptr_to_struct(a: &[u8]) -> FatPtrContainer<'_> { FatPtrContainer { ptr: a } } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs new file mode 100644 index 00000000000..ffeaab36bf3 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs @@ -0,0 +1,318 @@ +#![deny(mismatched_lifetime_syntaxes)] + +// `elided_named_lifetimes` overlaps with `lifetime_style_mismatch`, ignore it for now +#![allow(elided_named_lifetimes)] + +#[derive(Copy, Clone)] +struct ContainsLifetime<'a>(&'a u8); + +struct S(u8); + +fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v +} + +fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v +} + +// --- + +fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> { + //~^ ERROR lifetime flowing from input to output with different syntax + v +} + +fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + v +} + +fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + v +} + +fn explicit_bound_path_to_explicit_anonymous_path<'a>( + v: ContainsLifetime<'a>, + //~^ ERROR lifetime flowing from input to output with different syntax +) -> ContainsLifetime<'_> { + v +} + +// --- + +fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(v) +} + +fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(v) +} + +fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(v) +} + +fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(v) +} + +// --- + +fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v.0 +} + +fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v.0 +} + +fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v.0 +} + +fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v.0 +} + +impl S { + fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + &self.0 + } + + fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + &self.0 + } + + // --- + + fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(&self.0) + } + + fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(&self.0) + } + + fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(&self.0) + } +} + +// If a function uses the `'static` lifetime, we should not suggest +// replacing it with an explicitly anonymous or implicit +// lifetime. Only suggest using `'static` everywhere. +mod static_suggestions { + #[derive(Copy, Clone)] + struct ContainsLifetime<'a>(&'a u8); + + struct S(u8); + + fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v + } + + fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + v + } + + fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(v) + } + + fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(v) + } + + impl S { + fn static_ref_to_implicit_ref(&'static self) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + &self.0 + } + + fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + &self.0 + } + + fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(&self.0) + } + + fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> { + //~^ ERROR lifetime flowing from input to output with different syntax + ContainsLifetime(&self.0) + } + } +} + +/// `impl Trait` uses lifetimes in some additional ways. +mod impl_trait { + #[derive(Copy, Clone)] + struct ContainsLifetime<'a>(&'a u8); + + fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { + //~^ ERROR lifetime flowing from input to output with different syntax + move || _ = v + } + + fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { + //~^ ERROR lifetime flowing from input to output with different syntax + move || _ = v + } + + fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { + //~^ ERROR lifetime flowing from input to output with different syntax + move || _ = v + } + + fn explicit_bound_path_to_impl_trait_precise_capture<'a>( + v: ContainsLifetime<'a>, + //~^ ERROR lifetime flowing from input to output with different syntax + ) -> impl FnOnce() + use<'_> { + move || _ = v + } +} + +/// `dyn Trait` uses lifetimes in some additional ways. +mod dyn_trait { + use std::iter; + + #[derive(Copy, Clone)] + struct ContainsLifetime<'a>(&'a u8); + + fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box + '_> { + //~^ ERROR lifetime flowing from input to output with different syntax + Box::new(iter::once(v)) + } + + fn explicit_bound_path_to_dyn_trait_bound<'a>( + v: ContainsLifetime<'a>, + //~^ ERROR lifetime flowing from input to output with different syntax + ) -> Box + '_> { + Box::new(iter::once(v)) + } +} + +/// These tests serve to exercise edge cases of the lint formatting +mod diagnostic_output { + fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) { + //~^ ERROR lifetime flowing from input to output with different syntax + (v, v) + } +} + +/// These usages are expected to **not** trigger the lint +mod acceptable_uses { + #[derive(Copy, Clone)] + struct ContainsLifetime<'a>(&'a u8); + + struct S(u8); + + fn implicit_ref_to_implicit_ref(v: &u8) -> &u8 { + v + } + + fn explicit_anonymous_ref_to_explicit_anonymous_ref(v: &'_ u8) -> &'_ u8 { + v + } + + fn explicit_bound_ref_to_explicit_bound_ref<'a>(v: &'a u8) -> &'a u8 { + v + } + + fn implicit_path_to_implicit_path(v: ContainsLifetime) -> ContainsLifetime { + v + } + + fn explicit_anonymous_path_to_explicit_anonymous_path( + v: ContainsLifetime<'_>, + ) -> ContainsLifetime<'_> { + v + } + + fn explicit_bound_path_to_explicit_bound_path<'a>( + v: ContainsLifetime<'a>, + ) -> ContainsLifetime<'a> { + v + } + + fn explicit_anonymous_ref_to_explicit_anonymous_path(v: &'_ u8) -> ContainsLifetime<'_> { + ContainsLifetime(v) + } + + fn explicit_bound_ref_to_explicit_bound_path<'a>(v: &'a u8) -> ContainsLifetime<'a> { + ContainsLifetime(v) + } + + fn explicit_anonymous_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &'_ u8 { + v.0 + } + + fn explicit_bound_path_to_explicit_bound_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 { + v.0 + } + + // These may be surprising, but ampersands count as enough of a + // visual indicator that a reference exists that we treat + // references with implicit lifetimes the same as if they were + // explicitly anonymous. + fn implicit_ref_to_explicit_anonymous_ref(v: &u8) -> &'_ u8 { + v + } + + fn explicit_anonymous_ref_to_implicit_ref(v: &'_ u8) -> &u8 { + v + } + + fn implicit_ref_to_explicit_anonymous_path(v: &u8) -> ContainsLifetime<'_> { + ContainsLifetime(v) + } + + fn explicit_anonymous_path_to_implicit_ref(v: ContainsLifetime<'_>) -> &u8 { + v.0 + } + + impl S { + fn method_implicit_ref_to_explicit_anonymous_ref(&self) -> &'_ u8 { + &self.0 + } + + fn method_explicit_anonymous_ref_to_implicit_ref(&'_ self) -> &u8 { + &self.0 + } + + fn method_implicit_ref_to_explicit_anonymous_path(&self) -> ContainsLifetime<'_> { + ContainsLifetime(&self.0) + } + } + + // `dyn Trait` has an "embedded" lifetime that we should **not** + // lint about. + fn dyn_trait_does_not_have_a_lifetime_generic(v: &u8) -> &dyn core::fmt::Debug { + v + } +} + +fn main() {} diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr new file mode 100644 index 00000000000..57af0ac93cf --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr @@ -0,0 +1,473 @@ +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:11:47 + | +LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 { + | ^^ --- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +note: the lint level is defined here + --> $DIR/mismatched-lifetime-syntaxes.rs:1:9 + | +LL | #![deny(mismatched_lifetime_syntaxes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: one option is to consistently use `'a` + | +LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &'a u8 { + | ++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:16:57 + | +LL | fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { + | ^^ -- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { +LL + fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'a u8 { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:23:48 + | +LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> { + | ^^^^^^^^^^^^^^^^ -- the lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'_` + | +LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> { + | ++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:28:65 + | +LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime { + | ^^ ---------------- the lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'_` + | +LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> { + | ++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:33:65 + | +LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime { + | ^^ ---------------- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime<'a> { + | ++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:39:25 + | +LL | v: ContainsLifetime<'a>, + | ^^ this lifetime flows to the output +LL | +LL | ) -> ContainsLifetime<'_> { + | -- the lifetime gets resolved as `'a` + | +help: one option is to consistently use `'a` + | +LL - ) -> ContainsLifetime<'_> { +LL + ) -> ContainsLifetime<'a> { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:47:37 + | +LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { + | ^^^ ---------------- the lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + | +LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> { + | ++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:52:48 + | +LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime { + | ^^ ---------------- the lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + | +LL - fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime { +LL + fn explicit_anonymous_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:57:48 + | +LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime { + | ^^ ---------------- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime<'a> { + | ++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:62:58 + | +LL | fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { + | ^^ -- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { +LL + fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'a> { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:69:37 + | +LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 { + | ^^^^^^^^^^^^^^^^ --- the lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + | +LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime<'_>) -> &u8 { + | ++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:74:47 + | +LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { + | ^^^^^^^^^^^^^^^^ -- the lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + | +LL - fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { +LL + fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &u8 { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:79:64 + | +LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 { + | ^^ --- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 { + | ++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:84:74 + | +LL | fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { + | ^^ -- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { +LL + fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:90:55 + | +LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 { + | ^^ --- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &'a u8 { + | ++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:95:65 + | +LL | fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 { + | ^^ -- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 { +LL + fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'a u8 { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:102:56 + | +LL | fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime { + | ^^ ---------------- the lifetime gets resolved as `'_` + | | + | this lifetime flows to the output + | +help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + | +LL - fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime { +LL + fn method_explicit_anonymous_ref_to_implicit_path(&self) -> ContainsLifetime<'_> { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:107:56 + | +LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime { + | ^^ ---------------- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime<'a> { + | ++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:112:66 + | +LL | fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { + | ^^ -- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { +LL + fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'a> { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:127:39 + | +LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 { + | ^^^^^^^ --- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &'static u8 { + | +++++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:132:49 + | +LL | fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 { + | ^^^^^^^ -- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL - fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 { +LL + fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'static u8 { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:137:40 + | +LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime { + | ^^^^^^^ ---------------- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime<'static> { + | +++++++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:142:50 + | +LL | fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { + | ^^^^^^^ -- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL - fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { +LL + fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'static> { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:148:40 + | +LL | fn static_ref_to_implicit_ref(&'static self) -> &u8 { + | ^^^^^^^ --- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL | fn static_ref_to_implicit_ref(&'static self) -> &'static u8 { + | +++++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:153:50 + | +LL | fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 { + | ^^^^^^^ -- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL - fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 { +LL + fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'static u8 { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:158:41 + | +LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime { + | ^^^^^^^ ---------------- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime<'static> { + | +++++++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:163:51 + | +LL | fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> { + | ^^^^^^^ -- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL - fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> { +LL + fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'static> { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:175:55 + | +LL | fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { + | ^^ -- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { +LL + fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + 'a { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:180:65 + | +LL | fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { + | ^^ -- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { +LL + fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'a> { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:185:72 + | +LL | fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { + | ^^ -- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { +LL + fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + 'a { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:191:29 + | +LL | v: ContainsLifetime<'a>, + | ^^ this lifetime flows to the output +LL | +LL | ) -> impl FnOnce() + use<'_> { + | -- the lifetime gets resolved as `'a` + | +help: one option is to consistently use `'a` + | +LL - ) -> impl FnOnce() + use<'_> { +LL + ) -> impl FnOnce() + use<'a> { + | + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:205:54 + | +LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box + '_> { + | ^^ --- -- the lifetimes get resolved as `'a` + | | | + | | the lifetimes get resolved as `'a` + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box + '_> { + | ++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:211:29 + | +LL | v: ContainsLifetime<'a>, + | ^^ this lifetime flows to the output +LL | +LL | ) -> Box + '_> { + | ---------------- -- the lifetimes get resolved as `'a` + | | + | the lifetimes get resolved as `'a` + | +help: one option is to consistently use `'a` + | +LL | ) -> Box> + '_> { + | ++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:220:33 + | +LL | fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) { + | ^^ --- --- the lifetimes get resolved as `'a` + | | | + | | the lifetimes get resolved as `'a` + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn multiple_outputs<'a>(v: &'a u8) -> (&'a u8, &'a u8) { + | ++ ++ + +error: aborting due to 34 previous errors + -- cgit 1.4.1-3-g733a5 From d35ad948492146f0811d43606db66c65c55980a9 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Mon, 17 Mar 2025 12:43:55 -0400 Subject: Replace `elided_named_lifetimes` with `mismatched_lifetime_syntaxes` --- compiler/rustc_hir/src/def.rs | 7 +-- compiler/rustc_lint/messages.ftl | 5 -- compiler/rustc_lint/src/early/diagnostics.rs | 17 +----- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/lifetime_syntax.rs | 2 +- compiler/rustc_lint/src/lints.rs | 56 +----------------- compiler/rustc_lint_defs/src/builtin.rs | 33 ----------- compiler/rustc_lint_defs/src/lib.rs | 12 +--- compiler/rustc_resolve/src/late.rs | 61 ++----------------- compiler/rustc_resolve/src/late/diagnostics.rs | 4 +- src/tools/clippy/tests/ui/explicit_iter_loop.fixed | 4 +- src/tools/clippy/tests/ui/explicit_iter_loop.rs | 4 +- src/tools/clippy/tests/ui/iter_next_loop.rs | 2 +- .../clippy/tests/ui/iter_not_returning_iterator.rs | 2 +- src/tools/clippy/tests/ui/methods.rs | 2 +- src/tools/clippy/tests/ui/needless_lifetimes.fixed | 2 +- src/tools/clippy/tests/ui/needless_lifetimes.rs | 2 +- src/tools/clippy/tests/ui/ptr_arg.rs | 2 +- src/tools/clippy/tests/ui/ptr_arg.stderr | 25 +++++--- .../tests/ui/significant_drop_in_scrutinee.rs | 12 ++-- .../tests/ui/trivially_copy_pass_by_ref.fixed | 1 + .../clippy/tests/ui/trivially_copy_pass_by_ref.rs | 1 + .../tests/ui/trivially_copy_pass_by_ref.stderr | 36 ++++++------ src/tools/clippy/tests/ui/use_self.fixed | 2 +- src/tools/clippy/tests/ui/use_self.rs | 2 +- .../associated-types-impl-redirect.rs | 2 +- .../associated-types-normalize-in-bounds-ufcs.rs | 4 +- .../associated-types-normalize-in-bounds.rs | 22 ++++--- ...associated-types-where-clause-impl-ambiguity.rs | 2 +- tests/ui/associated-types/cache/elision.rs | 2 +- .../associated-types/project-defer-unification.rs | 2 +- tests/ui/async-await/issues/issue-63388-1.rs | 2 +- tests/ui/async-await/issues/issue-63388-1.stderr | 13 +---- tests/ui/borrowck/copy-suggestion-region-vid.fixed | 2 +- tests/ui/borrowck/copy-suggestion-region-vid.rs | 2 +- .../type-dependent/issue-71348.full.stderr | 15 +++-- .../type-dependent/issue-71348.min.stderr | 10 +--- .../const-generics/type-dependent/issue-71348.rs | 2 +- tests/ui/drop/drop-order-comparisons.e2021.fixed | 2 +- tests/ui/drop/drop-order-comparisons.rs | 2 +- tests/ui/drop/drop_order.rs | 4 +- tests/ui/drop/drop_order_if_let_rescope.rs | 2 +- tests/ui/drop/issue-2735-2.rs | 2 +- tests/ui/drop/issue-2735-3.rs | 2 +- tests/ui/drop/issue-979.rs | 2 +- tests/ui/drop/tail-expr-drop-order.rs | 4 +- tests/ui/generics/export-name-on-generics.fixed | 2 +- tests/ui/generics/export-name-on-generics.rs | 2 +- tests/ui/generics/generic-no-mangle.fixed | 2 +- tests/ui/generics/generic-no-mangle.rs | 2 +- .../normalize-under-binder/issue-62529-1.rs | 2 +- tests/ui/impl-trait/impl-fn-hrtb-bounds.rs | 1 - tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr | 12 +--- .../ui/impl-trait/impl-fn-predefined-lifetimes.rs | 1 - .../impl-trait/impl-fn-predefined-lifetimes.stderr | 13 +---- .../ui/impl-trait/rpit-assoc-pair-with-lifetime.rs | 2 +- .../rpit-assoc-pair-with-lifetime.stderr | 12 ++-- tests/ui/issues/issue-2502.rs | 2 +- tests/ui/issues/issue-42552.rs | 2 +- tests/ui/issues/issue-5708.rs | 2 +- ...me-bound-on-trait-object-using-type-alias.fixed | 1 + ...etime-bound-on-trait-object-using-type-alias.rs | 1 + ...e-bound-on-trait-object-using-type-alias.stderr | 2 +- ...ision-return-type-requires-explicit-lifetime.rs | 1 - ...n-return-type-requires-explicit-lifetime.stderr | 12 +--- ...eturn-one-existing-name-if-else-using-impl-3.rs | 4 -- ...n-one-existing-name-if-else-using-impl-3.stderr | 15 +---- .../example-from-issue48686.rs | 12 ++++ .../example-from-issue48686.stderr | 20 +++++++ .../missing-lifetime-kind.rs | 27 +++++++++ .../missing-lifetime-kind.stderr | 60 +++++++++++++++++++ .../not-tied-to-crate.rs | 20 +++++++ .../not-tied-to-crate.stderr | 38 ++++++++++++ .../mismatched-lifetime-syntaxes-details/static.rs | 46 +++++++++++++++ .../static.stderr | 60 +++++++++++++++++++ tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs | 3 - .../lifetimes/mismatched-lifetime-syntaxes.stderr | 68 +++++++++++----------- .../example-from-issue48686.rs | 12 ---- .../example-from-issue48686.stderr | 18 ------ .../missing-lifetime-kind.rs | 27 --------- .../missing-lifetime-kind.stderr | 40 ------------- .../elided-named-lifetimes/not-tied-to-crate.rs | 17 ------ .../not-tied-to-crate.stderr | 34 ----------- tests/ui/lint/elided-named-lifetimes/static.rs | 46 --------------- tests/ui/lint/elided-named-lifetimes/static.stderr | 52 ----------------- tests/ui/macros/format-args-temporaries.rs | 2 +- tests/ui/mir/mir_fat_ptr.rs | 4 +- tests/ui/nll/issue-53570.rs | 2 +- tests/ui/nll/issue-54556-niconii.rs | 2 +- .../object-lifetime-default-elision.rs | 2 - .../object-lifetime-default-elision.stderr | 14 +---- tests/ui/regions/init-res-into-things.rs | 2 +- tests/ui/regions/regions-nullary-variant.rs | 2 +- tests/ui/resource-assign-is-not-copy.rs | 2 +- tests/ui/resource-destruct.rs | 2 +- .../rfc-2294-if-let-guard/temporary-early-drop.rs | 2 +- .../rfc-2497-if-let-chains/edition-gate-macro.rs | 2 +- .../rfc-2497-if-let-chains/temporary-early-drop.rs | 2 +- .../self/elision/ignore-non-reference-lifetimes.rs | 4 +- .../elision/ignore-non-reference-lifetimes.stderr | 27 ++++++--- tests/ui/self/elision/lt-ref-self-async.fixed | 2 +- tests/ui/self/elision/lt-ref-self-async.rs | 2 +- tests/ui/self/self_lifetime-async.rs | 4 +- tests/ui/self/self_lifetime-async.stderr | 29 ++++++--- tests/ui/self/self_lifetime.rs | 4 +- tests/ui/self/self_lifetime.stderr | 29 ++++++--- .../impl-trait-missing-lifetime-gated.rs | 1 - .../impl-trait-missing-lifetime-gated.stderr | 10 +--- .../lifetimes/missing-lifetimes-in-signature.rs | 1 - .../missing-lifetimes-in-signature.stderr | 10 +--- .../missing_lifetime_bound.rs | 2 +- .../missing_lifetime_bound.stderr | 12 +--- tests/ui/type-id-higher-rank-2.rs | 2 +- tests/ui/underscore-lifetimes.rs | 2 +- 114 files changed, 551 insertions(+), 720 deletions(-) create mode 100644 tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs create mode 100644 tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr create mode 100644 tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs create mode 100644 tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr create mode 100644 tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs create mode 100644 tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr create mode 100644 tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs create mode 100644 tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr delete mode 100644 tests/ui/lint/elided-named-lifetimes/example-from-issue48686.rs delete mode 100644 tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr delete mode 100644 tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.rs delete mode 100644 tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.stderr delete mode 100644 tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.rs delete mode 100644 tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr delete mode 100644 tests/ui/lint/elided-named-lifetimes/static.rs delete mode 100644 tests/ui/lint/elided-named-lifetimes/static.stderr diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 98ec1ccd6ba..459fe5935e0 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -852,12 +852,7 @@ pub enum LifetimeRes { /// late resolution. Those lifetimes will be inferred by typechecking. Infer, /// `'static` lifetime. - Static { - /// We do not want to emit `elided_named_lifetimes` - /// when we are inside of a const item or a static, - /// because it would get too annoying. - suppress_elision_warning: bool, - }, + Static, /// Resolution failure. Error, /// HACK: This is used to recover the NodeId of an elided lifetime. diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index ac9c772c427..3b1cd475e07 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -253,11 +253,6 @@ lint_duplicate_macro_attribute = lint_duplicate_matcher_binding = duplicate matcher binding -lint_elided_named_lifetime = elided lifetime has a name - .label_elided = this elided lifetime gets resolved as `{$name}` - .label_named = lifetime `{$name}` declared here - .suggestion = consider specifying it explicitly - lint_enum_intrinsics_mem_discriminant = the return value of `mem::discriminant` is unspecified when called with a non-enum type .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 71b621e8d20..60c477dd6c7 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -10,11 +10,11 @@ use rustc_errors::{ use rustc_middle::middle::stability; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_session::lint::{BuiltinLintDiag, ElidedLifetimeResolution}; -use rustc_span::{BytePos, kw}; +use rustc_session::lint::BuiltinLintDiag; +use rustc_span::BytePos; use tracing::debug; -use crate::lints::{self, ElidedNamedLifetime}; +use crate::lints; mod check_cfg; @@ -471,16 +471,5 @@ pub fn decorate_builtin_lint( BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => { lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag) } - BuiltinLintDiag::ElidedNamedLifetimes { elided: (span, kind), resolution } => { - match resolution { - ElidedLifetimeResolution::Static => { - ElidedNamedLifetime { span, kind, name: kw::StaticLifetime, declaration: None } - } - ElidedLifetimeResolution::Param(name, declaration) => { - ElidedNamedLifetime { span, kind, name, declaration: Some(declaration) } - } - } - .decorate_lint(diag) - } } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 0439befc6ba..c86f66cc9b0 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -356,6 +356,7 @@ fn register_builtins(store: &mut LintStore) { store.register_renamed("unused_tuple_struct_fields", "dead_code"); store.register_renamed("static_mut_ref", "static_mut_refs"); store.register_renamed("temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"); + store.register_renamed("elided_named_lifetimes", "mismatched_lifetime_syntaxes"); // These were moved to tool lints, but rustc still sees them when compiling normally, before // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index f895cdb2a54..31b038e6a46 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -67,7 +67,7 @@ declare_lint! { /// In certain `unsafe` code, lifetime elision combined with /// inconsistent lifetime syntax may result in unsound code. pub MISMATCHED_LIFETIME_SYNTAXES, - Allow, + Warn, "detects when a lifetime uses different syntax between arguments and return values" } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 53fbe158885..9d3c74a9a2b 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -8,17 +8,17 @@ use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, MultiSpan, Subdiagnostic, SuggestionStyle, }; +use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::VisitorExt; -use rustc_hir::{self as hir, MissingLifetimeKind}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::inhabitedness::InhabitedPredicate; use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; use rustc_session::lint::AmbiguityErrorDiag; use rustc_span::edition::Edition; -use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, kw, sym}; +use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym}; use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds}; use crate::errors::{OverruledAttributeSub, RequestedLevel}; @@ -2752,58 +2752,6 @@ pub(crate) struct ElidedLifetimesInPaths { pub subdiag: ElidedLifetimeInPathSubdiag, } -pub(crate) struct ElidedNamedLifetime { - pub span: Span, - pub kind: MissingLifetimeKind, - pub name: Symbol, - pub declaration: Option, -} - -impl LintDiagnostic<'_, G> for ElidedNamedLifetime { - fn decorate_lint(self, diag: &mut rustc_errors::Diag<'_, G>) { - let Self { span, kind, name, declaration } = self; - diag.primary_message(fluent::lint_elided_named_lifetime); - diag.arg("name", name); - diag.span_label(span, fluent::lint_label_elided); - if let Some(declaration) = declaration { - diag.span_label(declaration, fluent::lint_label_named); - } - // FIXME(GrigorenkoPV): this `if` and `return` should be removed, - // but currently this lint's suggestions can conflict with those of `clippy::needless_lifetimes`: - // https://github.com/rust-lang/rust/pull/129840#issuecomment-2323349119 - // HACK: `'static` suggestions will never sonflict, emit only those for now. - if name != kw::StaticLifetime { - return; - } - match kind { - MissingLifetimeKind::Underscore => diag.span_suggestion_verbose( - span, - fluent::lint_suggestion, - format!("{name}"), - Applicability::MachineApplicable, - ), - MissingLifetimeKind::Ampersand => diag.span_suggestion_verbose( - span.shrink_to_hi(), - fluent::lint_suggestion, - format!("{name} "), - Applicability::MachineApplicable, - ), - MissingLifetimeKind::Comma => diag.span_suggestion_verbose( - span.shrink_to_hi(), - fluent::lint_suggestion, - format!("{name}, "), - Applicability::MachineApplicable, - ), - MissingLifetimeKind::Brackets => diag.span_suggestion_verbose( - span.shrink_to_hi(), - fluent::lint_suggestion, - format!("<{name}>"), - Applicability::MachineApplicable, - ), - }; - } -} - #[derive(LintDiagnostic)] #[diag(lint_invalid_crate_type_value)] pub(crate) struct UnknownCrateTypes { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 7c7ba85d484..fbe311b4195 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -40,7 +40,6 @@ declare_lint_pass! { DUPLICATE_MACRO_ATTRIBUTES, ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, ELIDED_LIFETIMES_IN_PATHS, - ELIDED_NAMED_LIFETIMES, EXPLICIT_BUILTIN_CFGS_IN_FLAGS, EXPORTED_PRIVATE_DEPENDENCIES, FFI_UNWIND_CALLS, @@ -1827,38 +1826,6 @@ declare_lint! { "hidden lifetime parameters in types are deprecated" } -declare_lint! { - /// The `elided_named_lifetimes` lint detects when an elided - /// lifetime ends up being a named lifetime, such as `'static` - /// or some lifetime parameter `'a`. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(elided_named_lifetimes)] - /// struct Foo; - /// impl Foo { - /// pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { - /// unsafe { &mut *(x as *mut _) } - /// } - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Lifetime elision is quite useful, because it frees you from having - /// to give each lifetime its own name, but sometimes it can produce - /// somewhat surprising resolutions. In safe code, it is mostly okay, - /// because the borrow checker prevents any unsoundness, so the worst - /// case scenario is you get a confusing error message in some other place. - /// But with `unsafe` code, such unexpected resolutions may lead to unsound code. - pub ELIDED_NAMED_LIFETIMES, - Warn, - "detects when an elided lifetime gets resolved to be `'static` or some named parameter" -} - declare_lint! { /// The `bare_trait_objects` lint suggests using `dyn Trait` for trait /// objects. diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 6cbdc245d21..16fd092f251 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -9,7 +9,7 @@ use rustc_data_structures::stable_hasher::{ use rustc_error_messages::{DiagMessage, MultiSpan}; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefPathHash; -use rustc_hir::{HashStableContext, HirId, ItemLocalId, MissingLifetimeKind}; +use rustc_hir::{HashStableContext, HirId, ItemLocalId}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; pub use rustc_span::edition::Edition; use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym}; @@ -635,12 +635,6 @@ pub enum DeprecatedSinceKind { InVersion(String), } -#[derive(Debug)] -pub enum ElidedLifetimeResolution { - Static, - Param(Symbol, Span), -} - // This could be a closure, but then implementing derive trait // becomes hacky (and it gets allocated). #[derive(Debug)] @@ -653,10 +647,6 @@ pub enum BuiltinLintDiag { }, MacroExpandedMacroExportsAccessedByAbsolutePaths(Span), ElidedLifetimesInPaths(usize, Span, bool, Span), - ElidedNamedLifetimes { - elided: (Span, MissingLifetimeKind), - resolution: ElidedLifetimeResolution, - }, UnknownCrateTypes { span: Span, candidate: Option, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 23ede3cdbad..26742f5401f 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1729,7 +1729,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if ident.name == kw::StaticLifetime { self.record_lifetime_res( lifetime.id, - LifetimeRes::Static { suppress_elision_warning: false }, + LifetimeRes::Static, LifetimeElisionCandidate::Named, ); return; @@ -1877,8 +1877,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if lifetimes_in_scope.is_empty() { self.record_lifetime_res( lifetime.id, - // We are inside a const item, so do not warn. - LifetimeRes::Static { suppress_elision_warning: true }, + LifetimeRes::Static, elision_candidate, ); return; @@ -2225,47 +2224,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { panic!("lifetime {id:?} resolved multiple times ({prev_res:?} before, {res:?} now)") } - match candidate { - LifetimeElisionCandidate::Missing(missing @ MissingLifetime { .. }) => { - debug_assert_eq!(id, missing.id); - match res { - LifetimeRes::Static { suppress_elision_warning } => { - if !suppress_elision_warning { - self.r.lint_buffer.buffer_lint( - lint::builtin::ELIDED_NAMED_LIFETIMES, - missing.id_for_lint, - missing.span, - BuiltinLintDiag::ElidedNamedLifetimes { - elided: (missing.span, missing.kind), - resolution: lint::ElidedLifetimeResolution::Static, - }, - ); - } - } - LifetimeRes::Param { param, binder: _ } => { - let tcx = self.r.tcx(); - self.r.lint_buffer.buffer_lint( - lint::builtin::ELIDED_NAMED_LIFETIMES, - missing.id_for_lint, - missing.span, - BuiltinLintDiag::ElidedNamedLifetimes { - elided: (missing.span, missing.kind), - resolution: lint::ElidedLifetimeResolution::Param( - tcx.item_name(param.into()), - tcx.source_span(param), - ), - }, - ); - } - LifetimeRes::Fresh { .. } - | LifetimeRes::Infer - | LifetimeRes::Error - | LifetimeRes::ElidedAnchor { .. } => {} - } - } - LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => {} - } - match res { LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static { .. } => { if let Some(ref mut candidates) = self.lifetime_elision_candidates { @@ -2788,14 +2746,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { .. }) => { self.with_static_rib(def_kind, |this| { - this.with_lifetime_rib( - LifetimeRibKind::Elided(LifetimeRes::Static { - suppress_elision_warning: true, - }), - |this| { - this.visit_ty(ty); - }, - ); + this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { + this.visit_ty(ty); + }); if let Some(expr) = expr { // We already forbid generic params because of the above item rib, // so it doesn't matter whether this is a trivial constant. @@ -2832,9 +2785,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.visit_generics(generics); this.with_lifetime_rib( - LifetimeRibKind::Elided(LifetimeRes::Static { - suppress_elision_warning: true, - }), + LifetimeRibKind::Elided(LifetimeRes::Static), |this| this.visit_ty(ty), ); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 97a45fcf233..2f6aed35f25 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3440,7 +3440,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { maybe_static = true; in_scope_lifetimes = vec![( Ident::with_dummy_span(kw::StaticLifetime), - (DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }), + (DUMMY_NODE_ID, LifetimeRes::Static), )]; } } else if elided_len == 0 { @@ -3452,7 +3452,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { maybe_static = true; in_scope_lifetimes = vec![( Ident::with_dummy_span(kw::StaticLifetime), - (DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }), + (DUMMY_NODE_ID, LifetimeRes::Static), )]; } } else if num_params == 1 { diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.fixed b/src/tools/clippy/tests/ui/explicit_iter_loop.fixed index f246ec61800..bffa1c4cf40 100644 --- a/src/tools/clippy/tests/ui/explicit_iter_loop.fixed +++ b/src/tools/clippy/tests/ui/explicit_iter_loop.fixed @@ -77,11 +77,11 @@ fn main() { struct NoIntoIter(); impl NoIntoIter { - fn iter(&self) -> slice::Iter { + fn iter(&self) -> slice::Iter<'_, u8> { unimplemented!() } - fn iter_mut(&mut self) -> slice::IterMut { + fn iter_mut(&mut self) -> slice::IterMut<'_, u8> { unimplemented!() } } diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.rs b/src/tools/clippy/tests/ui/explicit_iter_loop.rs index 35f4fb7097d..6a5a3dd00ba 100644 --- a/src/tools/clippy/tests/ui/explicit_iter_loop.rs +++ b/src/tools/clippy/tests/ui/explicit_iter_loop.rs @@ -77,11 +77,11 @@ fn main() { struct NoIntoIter(); impl NoIntoIter { - fn iter(&self) -> slice::Iter { + fn iter(&self) -> slice::Iter<'_, u8> { unimplemented!() } - fn iter_mut(&mut self) -> slice::IterMut { + fn iter_mut(&mut self) -> slice::IterMut<'_, u8> { unimplemented!() } } diff --git a/src/tools/clippy/tests/ui/iter_next_loop.rs b/src/tools/clippy/tests/ui/iter_next_loop.rs index 8e62ed963b9..969c51006af 100644 --- a/src/tools/clippy/tests/ui/iter_next_loop.rs +++ b/src/tools/clippy/tests/ui/iter_next_loop.rs @@ -8,7 +8,7 @@ fn main() { struct Unrelated(&'static [u8]); impl Unrelated { - fn next(&self) -> std::slice::Iter { + fn next(&self) -> std::slice::Iter<'_, u8> { self.0.iter() } } diff --git a/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs b/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs index 5c8c8eb4a43..d2497ed4330 100644 --- a/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs +++ b/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs @@ -71,7 +71,7 @@ impl S { struct S2([u8]); impl S2 { - fn iter(&self) -> core::slice::Iter { + fn iter(&self) -> core::slice::Iter<'_, u8> { self.0.iter() } } diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs index 2f4004181f6..f73fe288b0f 100644 --- a/src/tools/clippy/tests/ui/methods.rs +++ b/src/tools/clippy/tests/ui/methods.rs @@ -49,7 +49,7 @@ struct Lt2<'a> { impl<'a> Lt2<'a> { // The lifetime is different, but that’s irrelevant; see issue #734. - pub fn new(s: &str) -> Lt2 { + pub fn new(s: &str) -> Lt2<'_> { unimplemented!() } } diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed index e9d811986aa..ceea4480d0d 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.fixed +++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed @@ -10,7 +10,7 @@ clippy::unnecessary_wraps, dyn_drop, clippy::get_first, - elided_named_lifetimes + mismatched_lifetime_syntaxes, )] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs index 0b6eb9755b9..8432f9e6d2f 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.rs +++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs @@ -10,7 +10,7 @@ clippy::unnecessary_wraps, dyn_drop, clippy::get_first, - elided_named_lifetimes + mismatched_lifetime_syntaxes, )] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs index 2d77bf06ff9..65f3f05d6cb 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.rs +++ b/src/tools/clippy/tests/ui/ptr_arg.rs @@ -312,7 +312,7 @@ mod issue_9218 { // Inferred to be `&'a str`, afaik. fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { - //~^ ERROR: elided lifetime has a name + //~^ ERROR: lifetime flowing from input to output with different syntax todo!() } } diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index 741e60cbd74..600343754e1 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -1,12 +1,3 @@ -error: elided lifetime has a name - --> tests/ui/ptr_arg.rs:314:56 - | -LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` - | - = note: `-D elided-named-lifetimes` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]` - error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do --> tests/ui/ptr_arg.rs:13:14 | @@ -240,5 +231,21 @@ error: writing `&String` instead of `&str` involves a new object where a slice w LL | fn good(v1: &String, v2: &String) { | ^^^^^^^ help: change this to: `&str` +error: lifetime flowing from input to output with different syntax can be confusing + --> tests/ui/ptr_arg.rs:314:36 + | +LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { + | ^^ ^^ ---- the lifetime gets resolved as `'a` + | | | + | | these lifetimes flow to the output + | these lifetimes flow to the output + | + = note: `-D mismatched-lifetime-syntaxes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(mismatched_lifetime_syntaxes)]` +help: one option is to consistently use `'a` + | +LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &'a str { + | ++ + error: aborting due to 27 previous errors diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs index 4f65a06680d..78fc365bd5b 100644 --- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs @@ -191,7 +191,7 @@ struct CounterWrapper<'a> { } impl<'a> CounterWrapper<'a> { - fn new(counter: &Counter) -> CounterWrapper { + fn new(counter: &Counter) -> CounterWrapper<'_> { counter.i.fetch_add(1, Ordering::Relaxed); CounterWrapper { counter } } @@ -204,7 +204,7 @@ impl<'a> Drop for CounterWrapper<'a> { } impl Counter { - fn temp_increment(&self) -> Vec { + fn temp_increment(&self) -> Vec> { vec![CounterWrapper::new(self), CounterWrapper::new(self)] } } @@ -480,7 +480,7 @@ impl StateWithBoxedMutexGuard { fn new() -> StateWithBoxedMutexGuard { StateWithBoxedMutexGuard { u: Mutex::new(42) } } - fn lock(&self) -> Box> { + fn lock(&self) -> Box> { Box::new(self.u.lock().unwrap()) } } @@ -507,7 +507,7 @@ impl StateStringWithBoxedMutexGuard { s: Mutex::new("A String".to_owned()), } } - fn lock(&self) -> Box> { + fn lock(&self) -> Box> { Box::new(self.s.lock().unwrap()) } } @@ -686,11 +686,11 @@ struct Guard<'a, T>(MutexGuard<'a, T>); struct Ref<'a, T>(&'a T); impl<'a, T> Guard<'a, T> { - fn guard(&self) -> &MutexGuard { + fn guard(&self) -> &MutexGuard<'_, T> { &self.0 } - fn guard_ref(&self) -> Ref> { + fn guard_ref(&self) -> Ref<'_, MutexGuard<'_, T>> { Ref(&self.0) } diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.fixed b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.fixed index af7d82130f0..1a07f119398 100644 --- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.fixed +++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.fixed @@ -41,6 +41,7 @@ fn good_return_explicit_lt_ref<'a>(foo: &'a Foo) -> &'a u32 { &foo.0 } +#[allow(mismatched_lifetime_syntaxes)] fn good_return_implicit_lt_struct(foo: &Foo) -> FooRef { FooRef { foo } } diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs index 00e11a1ea28..07b1842bbf8 100644 --- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs +++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs @@ -41,6 +41,7 @@ fn good_return_explicit_lt_ref<'a>(foo: &'a Foo) -> &'a u32 { &foo.0 } +#[allow(mismatched_lifetime_syntaxes)] fn good_return_implicit_lt_struct(foo: &Foo) -> FooRef { FooRef { foo } } diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr index f101ac5ccd6..36247d3fe0b 100644 --- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr +++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr @@ -1,5 +1,5 @@ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:53:11 + --> tests/ui/trivially_copy_pass_by_ref.rs:54:11 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` @@ -11,103 +11,103 @@ LL | #![deny(clippy::trivially_copy_pass_by_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:53:20 + --> tests/ui/trivially_copy_pass_by_ref.rs:54:20 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:53:29 + --> tests/ui/trivially_copy_pass_by_ref.rs:54:29 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:63:12 + --> tests/ui/trivially_copy_pass_by_ref.rs:64:12 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^^ help: consider passing by value instead: `self` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:63:22 + --> tests/ui/trivially_copy_pass_by_ref.rs:64:22 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:63:31 + --> tests/ui/trivially_copy_pass_by_ref.rs:64:31 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:63:40 + --> tests/ui/trivially_copy_pass_by_ref.rs:64:40 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:69:16 + --> tests/ui/trivially_copy_pass_by_ref.rs:70:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:69:25 + --> tests/ui/trivially_copy_pass_by_ref.rs:70:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:69:34 + --> tests/ui/trivially_copy_pass_by_ref.rs:70:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:74:35 + --> tests/ui/trivially_copy_pass_by_ref.rs:75:35 | LL | fn bad_issue7518(self, other: &Self) {} | ^^^^^ help: consider passing by value instead: `Self` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:87:16 + --> tests/ui/trivially_copy_pass_by_ref.rs:88:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:87:25 + --> tests/ui/trivially_copy_pass_by_ref.rs:88:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:87:34 + --> tests/ui/trivially_copy_pass_by_ref.rs:88:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:94:33 + --> tests/ui/trivially_copy_pass_by_ref.rs:95:33 | LL | fn trait_method(&self, foo: &Foo); | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:132:21 + --> tests/ui/trivially_copy_pass_by_ref.rs:133:21 | LL | fn foo_never(x: &i32) { | ^^^^ help: consider passing by value instead: `i32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:138:15 + --> tests/ui/trivially_copy_pass_by_ref.rs:139:15 | LL | fn foo(x: &i32) { | ^^^^ help: consider passing by value instead: `i32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:164:36 + --> tests/ui/trivially_copy_pass_by_ref.rs:165:36 | LL | fn unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 { | ^^^^^^^ help: consider passing by value instead: `u32` diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed index f15e5e0a5bb..cccb6bffabb 100644 --- a/src/tools/clippy/tests/ui/use_self.fixed +++ b/src/tools/clippy/tests/ui/use_self.fixed @@ -69,7 +69,7 @@ mod lifetimes { impl<'a> Foo<'a> { // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) -> // Foo<'b>` - fn foo(s: &str) -> Foo { + fn foo(s: &str) -> Foo<'_> { Foo { foo_str: s } } // cannot replace with `Self`, because that's `Foo<'a>` diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs index b6376938611..09288677aa7 100644 --- a/src/tools/clippy/tests/ui/use_self.rs +++ b/src/tools/clippy/tests/ui/use_self.rs @@ -69,7 +69,7 @@ mod lifetimes { impl<'a> Foo<'a> { // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) -> // Foo<'b>` - fn foo(s: &str) -> Foo { + fn foo(s: &str) -> Foo<'_> { Foo { foo_str: s } } // cannot replace with `Self`, because that's `Foo<'a>` diff --git a/tests/ui/associated-types/associated-types-impl-redirect.rs b/tests/ui/associated-types/associated-types-impl-redirect.rs index 65e6a094b77..2cbe0d72540 100644 --- a/tests/ui/associated-types/associated-types-impl-redirect.rs +++ b/tests/ui/associated-types/associated-types-impl-redirect.rs @@ -21,7 +21,7 @@ trait Iterator { } trait IteratorExt: Iterator + Sized { - fn by_ref(&mut self) -> ByRef { + fn by_ref(&mut self) -> ByRef<'_, Self> { ByRef(self) } } diff --git a/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs b/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs index f15de0d9a28..b32323181b5 100644 --- a/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs +++ b/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs @@ -21,11 +21,11 @@ trait SliceExt2 { impl SliceExt2 for [T] { type Item = T; - fn split2

(&self, pred: P) -> Splits where P: FnMut(&T) -> bool { + fn split2

(&self, pred: P) -> Splits<'_, T, P> where P: FnMut(&T) -> bool { loop {} } - fn splitn2

(&self, n: u32, pred: P) -> SplitsN> where P: FnMut(&T) -> bool { + fn splitn2

(&self, n: u32, pred: P) -> SplitsN> where P: FnMut(&T) -> bool { SliceExt2::split2(self, pred); loop {} } diff --git a/tests/ui/associated-types/associated-types-normalize-in-bounds.rs b/tests/ui/associated-types/associated-types-normalize-in-bounds.rs index 7e94d3a011f..6844c5f9adb 100644 --- a/tests/ui/associated-types/associated-types-normalize-in-bounds.rs +++ b/tests/ui/associated-types/associated-types-normalize-in-bounds.rs @@ -3,32 +3,40 @@ // Test that we normalize associated types that appear in bounds; if // we didn't, the call to `self.split2()` fails to type check. - use std::marker::PhantomData; -struct Splits<'a, T, P>(PhantomData<(&'a(),T,P)>); +struct Splits<'a, T, P>(PhantomData<(&'a (), T, P)>); struct SplitsN(PhantomData); trait SliceExt2 { type Item; fn split2<'a, P>(&'a self, pred: P) -> Splits<'a, Self::Item, P> - where P: FnMut(&Self::Item) -> bool; + where + P: FnMut(&Self::Item) -> bool; + fn splitn2<'a, P>(&'a self, n: usize, pred: P) -> SplitsN> - where P: FnMut(&Self::Item) -> bool; + where + P: FnMut(&Self::Item) -> bool; } impl SliceExt2 for [T] { type Item = T; - fn split2

(&self, pred: P) -> Splits where P: FnMut(&T) -> bool { + fn split2

(&self, pred: P) -> Splits<'_, T, P> + where + P: FnMut(&T) -> bool, + { loop {} } - fn splitn2

(&self, n: usize, pred: P) -> SplitsN> where P: FnMut(&T) -> bool { + fn splitn2

(&self, n: usize, pred: P) -> SplitsN> + where + P: FnMut(&T) -> bool, + { self.split2(pred); loop {} } } -fn main() { } +fn main() {} diff --git a/tests/ui/associated-types/associated-types-where-clause-impl-ambiguity.rs b/tests/ui/associated-types/associated-types-where-clause-impl-ambiguity.rs index dcfa3532cdf..34c269d4d90 100644 --- a/tests/ui/associated-types/associated-types-where-clause-impl-ambiguity.rs +++ b/tests/ui/associated-types/associated-types-where-clause-impl-ambiguity.rs @@ -20,7 +20,7 @@ trait Iterator { } trait IteratorExt: Iterator + Sized { - fn by_ref(&mut self) -> ByRef { + fn by_ref(&mut self) -> ByRef<'_, Self> { ByRef(self) } } diff --git a/tests/ui/associated-types/cache/elision.rs b/tests/ui/associated-types/cache/elision.rs index 12765fc5811..7ddb32ea874 100644 --- a/tests/ui/associated-types/cache/elision.rs +++ b/tests/ui/associated-types/cache/elision.rs @@ -14,7 +14,7 @@ pub trait UnicodeStr { impl UnicodeStr for str { #[inline] - fn split_whitespace(&self) -> SplitWhitespace { + fn split_whitespace(&self) -> SplitWhitespace<'_> { unimplemented!() } } diff --git a/tests/ui/associated-types/project-defer-unification.rs b/tests/ui/associated-types/project-defer-unification.rs index b51228ef411..a949171db12 100644 --- a/tests/ui/associated-types/project-defer-unification.rs +++ b/tests/ui/associated-types/project-defer-unification.rs @@ -50,7 +50,7 @@ where P: Pixel + 'static, loop { } } - pub fn pixels_mut(&mut self) -> PixelsMut

{ + pub fn pixels_mut(&mut self) -> PixelsMut<'_, P> { loop { } } } diff --git a/tests/ui/async-await/issues/issue-63388-1.rs b/tests/ui/async-await/issues/issue-63388-1.rs index acfc64baff9..3a89f3ebfd2 100644 --- a/tests/ui/async-await/issues/issue-63388-1.rs +++ b/tests/ui/async-await/issues/issue-63388-1.rs @@ -9,7 +9,7 @@ trait Foo {} impl Xyz { async fn do_sth<'a>( &'a self, foo: &dyn Foo - ) -> &dyn Foo //~ WARNING elided lifetime has a name + ) -> &dyn Foo { foo //~^ ERROR explicit lifetime required in the type of `foo` [E0621] diff --git a/tests/ui/async-await/issues/issue-63388-1.stderr b/tests/ui/async-await/issues/issue-63388-1.stderr index 579caa45bc9..277f7fa6f63 100644 --- a/tests/ui/async-await/issues/issue-63388-1.stderr +++ b/tests/ui/async-await/issues/issue-63388-1.stderr @@ -1,14 +1,3 @@ -warning: elided lifetime has a name - --> $DIR/issue-63388-1.rs:12:10 - | -LL | async fn do_sth<'a>( - | -- lifetime `'a` declared here -LL | &'a self, foo: &dyn Foo -LL | ) -> &dyn Foo - | ^ this elided lifetime gets resolved as `'a` - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error[E0621]: explicit lifetime required in the type of `foo` --> $DIR/issue-63388-1.rs:14:9 | @@ -18,6 +7,6 @@ LL | &'a self, foo: &dyn Foo LL | foo | ^^^ lifetime `'a` required -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0621`. diff --git a/tests/ui/borrowck/copy-suggestion-region-vid.fixed b/tests/ui/borrowck/copy-suggestion-region-vid.fixed index 7fe18615408..2bc8a74086e 100644 --- a/tests/ui/borrowck/copy-suggestion-region-vid.fixed +++ b/tests/ui/borrowck/copy-suggestion-region-vid.fixed @@ -7,7 +7,7 @@ pub struct HelperStruct<'n> { } impl DataStruct { - pub fn f(&self) -> HelperStruct { + pub fn f(&self) -> HelperStruct<'_> { let helpers = [vec![], vec![]]; HelperStruct { helpers: helpers.clone(), is_empty: helpers[0].is_empty() } diff --git a/tests/ui/borrowck/copy-suggestion-region-vid.rs b/tests/ui/borrowck/copy-suggestion-region-vid.rs index daafba71ece..248ce80d22b 100644 --- a/tests/ui/borrowck/copy-suggestion-region-vid.rs +++ b/tests/ui/borrowck/copy-suggestion-region-vid.rs @@ -7,7 +7,7 @@ pub struct HelperStruct<'n> { } impl DataStruct { - pub fn f(&self) -> HelperStruct { + pub fn f(&self) -> HelperStruct<'_> { let helpers = [vec![], vec![]]; HelperStruct { helpers, is_empty: helpers[0].is_empty() } diff --git a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr index 177ff20fbf9..f68fdb3b651 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr +++ b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr @@ -1,10 +1,17 @@ -warning: elided lifetime has a name - --> $DIR/issue-71348.rs:18:68 +warning: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/issue-71348.rs:18:40 | LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` + | ^^ -- ------------------------ the lifetimes get resolved as `'a` + | | | + | | the lifetimes get resolved as `'a` + | this lifetime flows to the output | - = note: `#[warn(elided_named_lifetimes)]` on by default + = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default +help: one option is to consistently use `'a` + | +LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target + | +++ warning: 1 warning emitted diff --git a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr index 8995c415863..c491469bcbd 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr +++ b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr @@ -1,11 +1,3 @@ -warning: elided lifetime has a name - --> $DIR/issue-71348.rs:18:68 - | -LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error: `&'static str` is forbidden as the type of a const generic parameter --> $DIR/issue-71348.rs:10:24 | @@ -38,5 +30,5 @@ help: add `#![feature(unsized_const_params)]` to the crate attributes to enable LL + #![feature(unsized_const_params)] | -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/type-dependent/issue-71348.rs b/tests/ui/const-generics/type-dependent/issue-71348.rs index 97e786405fe..c6563c80305 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.rs +++ b/tests/ui/const-generics/type-dependent/issue-71348.rs @@ -17,7 +17,7 @@ trait Get<'a, const N: &'static str> { impl Foo { fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target //[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter - //~^^ WARNING elided lifetime has a name + //[full]~^^ WARNING lifetime flowing from input to output with different syntax where Self: Get<'a, N>, { diff --git a/tests/ui/drop/drop-order-comparisons.e2021.fixed b/tests/ui/drop/drop-order-comparisons.e2021.fixed index 6c8d2d3fa9c..42f805923ec 100644 --- a/tests/ui/drop/drop-order-comparisons.e2021.fixed +++ b/tests/ui/drop/drop-order-comparisons.e2021.fixed @@ -589,7 +589,7 @@ impl Events { Ok(LogDrop(self, m)) } /// Return an `Err` value that logs its drop. - fn err(&self, m: u64) -> Result { + fn err(&self, m: u64) -> Result, LogDrop<'_>> { Err(LogDrop(self, m)) } /// Log an event. diff --git a/tests/ui/drop/drop-order-comparisons.rs b/tests/ui/drop/drop-order-comparisons.rs index 9a10a08a3ff..e7425159aa2 100644 --- a/tests/ui/drop/drop-order-comparisons.rs +++ b/tests/ui/drop/drop-order-comparisons.rs @@ -589,7 +589,7 @@ impl Events { Ok(LogDrop(self, m)) } /// Return an `Err` value that logs its drop. - fn err(&self, m: u64) -> Result { + fn err(&self, m: u64) -> Result, LogDrop<'_>> { Err(LogDrop(self, m)) } /// Log an event. diff --git a/tests/ui/drop/drop_order.rs b/tests/ui/drop/drop_order.rs index b96e55a2535..34b1a0e8f75 100644 --- a/tests/ui/drop/drop_order.rs +++ b/tests/ui/drop/drop_order.rs @@ -23,11 +23,11 @@ impl Drop for LoudDrop<'_> { } impl DropOrderCollector { - fn option_loud_drop(&self, n: u32) -> Option { + fn option_loud_drop(&self, n: u32) -> Option> { Some(LoudDrop(self, n)) } - fn loud_drop(&self, n: u32) -> LoudDrop { + fn loud_drop(&self, n: u32) -> LoudDrop<'_> { LoudDrop(self, n) } diff --git a/tests/ui/drop/drop_order_if_let_rescope.rs b/tests/ui/drop/drop_order_if_let_rescope.rs index 27bced5fa62..e96ceedd5cb 100644 --- a/tests/ui/drop/drop_order_if_let_rescope.rs +++ b/tests/ui/drop/drop_order_if_let_rescope.rs @@ -18,7 +18,7 @@ impl Drop for LoudDrop<'_> { } impl DropOrderCollector { - fn option_loud_drop(&self, n: u32) -> Option { + fn option_loud_drop(&self, n: u32) -> Option> { Some(LoudDrop(self, n)) } diff --git a/tests/ui/drop/issue-2735-2.rs b/tests/ui/drop/issue-2735-2.rs index 7a6ed6ea2f8..66025956e08 100644 --- a/tests/ui/drop/issue-2735-2.rs +++ b/tests/ui/drop/issue-2735-2.rs @@ -14,7 +14,7 @@ impl<'a> Drop for defer<'a> { } } -fn defer(b: &Cell) -> defer { +fn defer(b: &Cell) -> defer<'_> { defer { b: b } diff --git a/tests/ui/drop/issue-2735-3.rs b/tests/ui/drop/issue-2735-3.rs index 3bb4536537c..c9535168653 100644 --- a/tests/ui/drop/issue-2735-3.rs +++ b/tests/ui/drop/issue-2735-3.rs @@ -14,7 +14,7 @@ impl<'a> Drop for defer<'a> { } } -fn defer(b: &Cell) -> defer { +fn defer(b: &Cell) -> defer<'_> { defer { b: b } diff --git a/tests/ui/drop/issue-979.rs b/tests/ui/drop/issue-979.rs index 8d98ac4df23..70052708be6 100644 --- a/tests/ui/drop/issue-979.rs +++ b/tests/ui/drop/issue-979.rs @@ -13,7 +13,7 @@ impl<'a> Drop for r<'a> { } } -fn r(b: &Cell) -> r { +fn r(b: &Cell) -> r<'_> { r { b: b } diff --git a/tests/ui/drop/tail-expr-drop-order.rs b/tests/ui/drop/tail-expr-drop-order.rs index f74530fce1e..a6807b16b50 100644 --- a/tests/ui/drop/tail-expr-drop-order.rs +++ b/tests/ui/drop/tail-expr-drop-order.rs @@ -28,11 +28,11 @@ impl Drop for LoudDrop<'_> { } impl DropOrderCollector { - fn option_loud_drop(&self, n: u32) -> Option { + fn option_loud_drop(&self, n: u32) -> Option> { Some(LoudDrop(self, n)) } - fn loud_drop(&self, n: u32) -> LoudDrop { + fn loud_drop(&self, n: u32) -> LoudDrop<'_> { LoudDrop(self, n) } diff --git a/tests/ui/generics/export-name-on-generics.fixed b/tests/ui/generics/export-name-on-generics.fixed index 4430cd9a299..c8a3fd5798f 100644 --- a/tests/ui/generics/export-name-on-generics.fixed +++ b/tests/ui/generics/export-name-on-generics.fixed @@ -1,5 +1,5 @@ //@ run-rustfix -#![allow(dead_code, elided_named_lifetimes)] +#![allow(dead_code, mismatched_lifetime_syntaxes)] #![deny(no_mangle_generic_items)] pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled diff --git a/tests/ui/generics/export-name-on-generics.rs b/tests/ui/generics/export-name-on-generics.rs index cbf11021960..8b38037fe12 100644 --- a/tests/ui/generics/export-name-on-generics.rs +++ b/tests/ui/generics/export-name-on-generics.rs @@ -1,5 +1,5 @@ //@ run-rustfix -#![allow(dead_code, elided_named_lifetimes)] +#![allow(dead_code, mismatched_lifetime_syntaxes)] #![deny(no_mangle_generic_items)] #[export_name = "foo"] diff --git a/tests/ui/generics/generic-no-mangle.fixed b/tests/ui/generics/generic-no-mangle.fixed index 2776848c45f..e3e41eb9d0d 100644 --- a/tests/ui/generics/generic-no-mangle.fixed +++ b/tests/ui/generics/generic-no-mangle.fixed @@ -1,5 +1,5 @@ //@ run-rustfix -#![allow(dead_code, elided_named_lifetimes)] +#![allow(dead_code, mismatched_lifetime_syntaxes)] #![deny(no_mangle_generic_items)] pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled diff --git a/tests/ui/generics/generic-no-mangle.rs b/tests/ui/generics/generic-no-mangle.rs index 5314005d31f..085f8610a54 100644 --- a/tests/ui/generics/generic-no-mangle.rs +++ b/tests/ui/generics/generic-no-mangle.rs @@ -1,5 +1,5 @@ //@ run-rustfix -#![allow(dead_code, elided_named_lifetimes)] +#![allow(dead_code, mismatched_lifetime_syntaxes)] #![deny(no_mangle_generic_items)] #[no_mangle] diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs index c368f265062..e00a31e26aa 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs @@ -25,7 +25,7 @@ where impl Inject for RefMutFamily { type I = Self; - fn inject(_: &()) -> ::Out { + fn inject(_: &()) -> >::Out { unimplemented!() } } diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs b/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs index a7f38b5c16a..da7530b4e7a 100644 --- a/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs +++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs @@ -13,7 +13,6 @@ fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) { fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) { //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - //~| WARNING elided lifetime has a name |x| x } diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr index 31f39eb9004..40cb6b647d1 100644 --- a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr +++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifier - --> $DIR/impl-fn-hrtb-bounds.rs:20:38 + --> $DIR/impl-fn-hrtb-bounds.rs:19:38 | LL | fn d() -> impl Fn() -> (impl Debug + '_) { | ^^ expected named lifetime parameter @@ -11,14 +11,6 @@ LL - fn d() -> impl Fn() -> (impl Debug + '_) { LL + fn d() -> impl Fn() -> (impl Debug + 'static) { | -warning: elided lifetime has a name - --> $DIR/impl-fn-hrtb-bounds.rs:14:52 - | -LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) { - | -- lifetime `'a` declared here ^^ this elided lifetime gets resolved as `'a` - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` --> $DIR/impl-fn-hrtb-bounds.rs:4:41 | @@ -55,7 +47,7 @@ note: lifetime declared here LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) { | ^^ -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors Some errors have detailed explanations: E0106, E0657. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs index 776bb7278ce..199cbbf4fcc 100644 --- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs +++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs @@ -2,7 +2,6 @@ use std::fmt::Debug; fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { - //~^ WARNING elided lifetime has a name |x| x //~^ ERROR expected generic lifetime parameter, found `'_` } diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr index 209186db4cc..6064b09ef09 100644 --- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr +++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr @@ -1,20 +1,11 @@ -warning: elided lifetime has a name - --> $DIR/impl-fn-predefined-lifetimes.rs:4:48 - | -LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { - | -- lifetime `'a` declared here ^^ this elided lifetime gets resolved as `'a` - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error[E0792]: expected generic lifetime parameter, found `'_` - --> $DIR/impl-fn-predefined-lifetimes.rs:6:9 + --> $DIR/impl-fn-predefined-lifetimes.rs:5:9 | LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { | -- this generic parameter must be used with a generic lifetime parameter -LL | LL | |x| x | ^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs index e48441f533d..1ac3c593dbe 100644 --- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs +++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs @@ -1,7 +1,7 @@ //@ check-pass pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator { - //~^ WARNING elided lifetime has a name + //~^ WARNING lifetime flowing from input to output with different syntax v.into_iter() } diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr index bff3ffd934a..b9d8674992c 100644 --- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr +++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr @@ -1,10 +1,14 @@ -warning: elided lifetime has a name - --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:82 +warning: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:31 | LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator { - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` + | ^^ this lifetime flows to the output ---- the lifetime gets resolved as `'a` | - = note: `#[warn(elided_named_lifetimes)]` on by default + = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default +help: one option is to consistently use `'a` + | +LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator { + | ++ warning: 1 warning emitted diff --git a/tests/ui/issues/issue-2502.rs b/tests/ui/issues/issue-2502.rs index dfc0995104e..98a52a3b5a7 100644 --- a/tests/ui/issues/issue-2502.rs +++ b/tests/ui/issues/issue-2502.rs @@ -14,7 +14,7 @@ impl<'a> font<'a> { } } -fn font(fontbuf: &Vec ) -> font { +fn font(fontbuf: &Vec ) -> font<'_> { font { fontbuf: fontbuf } diff --git a/tests/ui/issues/issue-42552.rs b/tests/ui/issues/issue-42552.rs index 998cde44be0..734921d9b01 100644 --- a/tests/ui/issues/issue-42552.rs +++ b/tests/ui/issues/issue-42552.rs @@ -1,7 +1,7 @@ //@ run-pass // Regression test for an obscure issue with the projection cache. -fn into_iter(a: &I) -> Groups { +fn into_iter(a: &I) -> Groups<'_, I> { Groups { _a: a } } diff --git a/tests/ui/issues/issue-5708.rs b/tests/ui/issues/issue-5708.rs index ce9ef78ffcd..6fa3cfa4724 100644 --- a/tests/ui/issues/issue-5708.rs +++ b/tests/ui/issues/issue-5708.rs @@ -25,7 +25,7 @@ struct Outer<'a> { } impl<'a> Outer<'a> { - fn new(inner: &dyn Inner) -> Outer { + fn new(inner: &dyn Inner) -> Outer<'_> { Outer { inner: inner } diff --git a/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.fixed b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.fixed index 2ceaaf0339d..bcc4abc47e1 100644 --- a/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.fixed +++ b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.fixed @@ -28,6 +28,7 @@ impl Greeter1 for FixedGreeter<'_> { struct Greetings(pub Vec); impl Greetings { + #[expect(mismatched_lifetime_syntaxes)] pub fn get(&self, i: usize) -> BoxedGreeter { (Box::new(FixedGreeter(&self.0[i])), Box::new(FixedGreeter(&self.0[i]))) //~^ ERROR lifetime may not live long enough diff --git a/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs index e7d427517b5..9ca6077f47f 100644 --- a/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs +++ b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs @@ -28,6 +28,7 @@ impl Greeter1 for FixedGreeter<'_> { struct Greetings(pub Vec); impl Greetings { + #[expect(mismatched_lifetime_syntaxes)] pub fn get(&self, i: usize) -> BoxedGreeter { (Box::new(FixedGreeter(&self.0[i])), Box::new(FixedGreeter(&self.0[i]))) //~^ ERROR lifetime may not live long enough diff --git a/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.stderr b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.stderr index 24bb9e2ef7d..2eba3ff418b 100644 --- a/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.stderr +++ b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs:32:9 + --> $DIR/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs:33:9 | LL | pub fn get(&self, i: usize) -> BoxedGreeter { | - let's call the lifetime of this reference `'1` diff --git a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs index 63a2c9be9eb..d0a8fe795ef 100644 --- a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs +++ b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs @@ -47,6 +47,5 @@ fn l<'a>(_: &'a str, _: &'a str) -> &str { "" } // This is ok because both `'a` are for the same parameter. fn m<'a>(_: &'a Foo<'a>) -> &str { "" } -//~^ WARNING elided lifetime has a name fn main() {} diff --git a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr index f835d2655bb..23ef36888f0 100644 --- a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr +++ b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr @@ -105,16 +105,6 @@ help: consider using the `'a` lifetime LL | fn l<'a>(_: &'a str, _: &'a str) -> &'a str { "" } | ++ -warning: elided lifetime has a name - --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:49:29 - | -LL | fn m<'a>(_: &'a Foo<'a>) -> &str { "" } - | -- ^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - | - = note: `#[warn(elided_named_lifetimes)]` on by default - -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs index 598633d7576..5dbc0c556fb 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs @@ -4,12 +4,8 @@ struct Foo { impl Foo { fn foo<'a>(&'a self, x: &i32) -> &i32 { - //~^ WARNING elided lifetime has a name - if true { &self.field } else { x } //~ ERROR explicit lifetime - } - } fn main() { } diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr index 2d5d4fb0e72..071bda24ef8 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr @@ -1,22 +1,11 @@ -warning: elided lifetime has a name - --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:6:36 - | -LL | fn foo<'a>(&'a self, x: &i32) -> &i32 { - | -- ^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:9:36 + --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:7:36 | LL | fn foo<'a>(&'a self, x: &i32) -> &i32 { | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32` -... LL | if true { &self.field } else { x } | ^ lifetime `'a` required -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0621`. diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs new file mode 100644 index 00000000000..1804003d367 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs @@ -0,0 +1,12 @@ +#![deny(mismatched_lifetime_syntaxes)] + +struct Foo; + +impl Foo { + pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + unsafe { &mut *(x as *mut _) } + } +} + +fn main() {} diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr new file mode 100644 index 00000000000..7c7411651d0 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr @@ -0,0 +1,20 @@ +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/example-from-issue48686.rs:6:21 + | +LL | pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { + | ^^^^^^^ ------- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +note: the lint level is defined here + --> $DIR/example-from-issue48686.rs:1:9 + | +LL | #![deny(mismatched_lifetime_syntaxes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: one option is to consistently use `'static` + | +LL | pub fn get_mut(&'static self, x: &mut u8) -> &'static mut u8 { + | +++++++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs new file mode 100644 index 00000000000..3d5aab5c829 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs @@ -0,0 +1,27 @@ +#![deny(mismatched_lifetime_syntaxes)] + +fn ampersand<'a>(x: &'a u8) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + x +} + +struct Brackets<'a>(&'a u8); + +fn brackets<'a>(x: &'a u8) -> Brackets { + //~^ ERROR lifetime flowing from input to output with different syntax + Brackets(x) +} + +struct Comma<'a, T>(&'a T); + +fn comma<'a>(x: &'a u8) -> Comma { + //~^ ERROR lifetime flowing from input to output with different syntax + Comma(x) +} + +fn underscore<'a>(x: &'a u8) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + x +} + +fn main() {} diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr new file mode 100644 index 00000000000..681b3c97052 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr @@ -0,0 +1,60 @@ +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/missing-lifetime-kind.rs:3:22 + | +LL | fn ampersand<'a>(x: &'a u8) -> &u8 { + | ^^ --- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +note: the lint level is defined here + --> $DIR/missing-lifetime-kind.rs:1:9 + | +LL | #![deny(mismatched_lifetime_syntaxes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: one option is to consistently use `'a` + | +LL | fn ampersand<'a>(x: &'a u8) -> &'a u8 { + | ++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/missing-lifetime-kind.rs:10:21 + | +LL | fn brackets<'a>(x: &'a u8) -> Brackets { + | ^^ -------- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn brackets<'a>(x: &'a u8) -> Brackets<'a> { + | ++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/missing-lifetime-kind.rs:17:18 + | +LL | fn comma<'a>(x: &'a u8) -> Comma { + | ^^ --------- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn comma<'a>(x: &'a u8) -> Comma<'a, u8> { + | +++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/missing-lifetime-kind.rs:22:23 + | +LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 { + | ^^ -- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL - fn underscore<'a>(x: &'a u8) -> &'_ u8 { +LL + fn underscore<'a>(x: &'a u8) -> &'a u8 { + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs new file mode 100644 index 00000000000..cc398ab7888 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs @@ -0,0 +1,20 @@ +#![allow(mismatched_lifetime_syntaxes)] + +//! Ensure that the lint level of `mismatched_lifetime_syntaxes` can +//! be adjusted by attributes not applied at the crate-level. + +#[warn(mismatched_lifetime_syntaxes)] +mod foo { + fn bar(x: &'static u8) -> &u8 { + //~^ WARNING lifetime flowing from input to output with different syntax + x + } + + #[deny(mismatched_lifetime_syntaxes)] + fn baz(x: &'static u8) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + x + } +} + +fn main() {} diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr new file mode 100644 index 00000000000..da691225c17 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr @@ -0,0 +1,38 @@ +warning: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/not-tied-to-crate.rs:8:16 + | +LL | fn bar(x: &'static u8) -> &u8 { + | ^^^^^^^ --- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +note: the lint level is defined here + --> $DIR/not-tied-to-crate.rs:6:8 + | +LL | #[warn(mismatched_lifetime_syntaxes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: one option is to consistently use `'static` + | +LL | fn bar(x: &'static u8) -> &'static u8 { + | +++++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/not-tied-to-crate.rs:14:16 + | +LL | fn baz(x: &'static u8) -> &u8 { + | ^^^^^^^ --- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +note: the lint level is defined here + --> $DIR/not-tied-to-crate.rs:13:12 + | +LL | #[deny(mismatched_lifetime_syntaxes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: one option is to consistently use `'static` + | +LL | fn baz(x: &'static u8) -> &'static u8 { + | +++++++ + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs new file mode 100644 index 00000000000..47ae258f138 --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs @@ -0,0 +1,46 @@ +#![deny(mismatched_lifetime_syntaxes)] + +use std::borrow::Cow; + +const A: &[u8] = &[]; +static B: &str = "hello"; + +trait Trait { + const C: &u8 = &0; +} + +impl Trait for () { + const C: &u8 = &1; +} + +fn ampersand(x: &'static u8) -> &u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + x +} + +struct Brackets<'a>(&'a u8); + +fn brackets(x: &'static u8) -> Brackets { + //~^ ERROR lifetime flowing from input to output with different syntax + Brackets(x) +} + +struct Comma<'a, T>(&'a T); + +fn comma(x: &'static u8) -> Comma { + //~^ ERROR lifetime flowing from input to output with different syntax + Comma(x) +} + +fn underscore(x: &'static u8) -> &'_ u8 { + //~^ ERROR lifetime flowing from input to output with different syntax + x +} + +const NESTED: &Vec<&Box>> = &vec![]; + +fn main() { + const HELLO: &str = "Hello"; + static WORLD: &str = "world"; + println!("{HELLO}, {WORLD}!") +} diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr new file mode 100644 index 00000000000..5b9a986bcbe --- /dev/null +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr @@ -0,0 +1,60 @@ +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/static.rs:16:18 + | +LL | fn ampersand(x: &'static u8) -> &u8 { + | ^^^^^^^ --- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +note: the lint level is defined here + --> $DIR/static.rs:1:9 + | +LL | #![deny(mismatched_lifetime_syntaxes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: one option is to consistently use `'static` + | +LL | fn ampersand(x: &'static u8) -> &'static u8 { + | +++++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/static.rs:23:17 + | +LL | fn brackets(x: &'static u8) -> Brackets { + | ^^^^^^^ -------- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL | fn brackets(x: &'static u8) -> Brackets<'static> { + | +++++++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/static.rs:30:14 + | +LL | fn comma(x: &'static u8) -> Comma { + | ^^^^^^^ --------- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL | fn comma(x: &'static u8) -> Comma<'static, u8> { + | ++++++++ + +error: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/static.rs:35:19 + | +LL | fn underscore(x: &'static u8) -> &'_ u8 { + | ^^^^^^^ -- the lifetime gets resolved as `'static` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'static` + | +LL - fn underscore(x: &'static u8) -> &'_ u8 { +LL + fn underscore(x: &'static u8) -> &'static u8 { + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs index ffeaab36bf3..6d8487b99c6 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs @@ -1,8 +1,5 @@ #![deny(mismatched_lifetime_syntaxes)] -// `elided_named_lifetimes` overlaps with `lifetime_style_mismatch`, ignore it for now -#![allow(elided_named_lifetimes)] - #[derive(Copy, Clone)] struct ContainsLifetime<'a>(&'a u8); diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr index 57af0ac93cf..0ec16a266b6 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr @@ -1,5 +1,5 @@ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:11:47 + --> $DIR/mismatched-lifetime-syntaxes.rs:8:47 | LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 { | ^^ --- the lifetime gets resolved as `'a` @@ -17,7 +17,7 @@ LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &'a u8 { | ++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:16:57 + --> $DIR/mismatched-lifetime-syntaxes.rs:13:57 | LL | fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { | ^^ -- the lifetime gets resolved as `'a` @@ -31,7 +31,7 @@ LL + fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'a u8 { | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:23:48 + --> $DIR/mismatched-lifetime-syntaxes.rs:20:48 | LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> { | ^^^^^^^^^^^^^^^^ -- the lifetime gets resolved as `'_` @@ -44,7 +44,7 @@ LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime<'_>) -> Con | ++++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:28:65 + --> $DIR/mismatched-lifetime-syntaxes.rs:25:65 | LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime { | ^^ ---------------- the lifetime gets resolved as `'_` @@ -57,7 +57,7 @@ LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> Con | ++++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:33:65 + --> $DIR/mismatched-lifetime-syntaxes.rs:30:65 | LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime { | ^^ ---------------- the lifetime gets resolved as `'a` @@ -70,7 +70,7 @@ LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> Con | ++++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:39:25 + --> $DIR/mismatched-lifetime-syntaxes.rs:36:25 | LL | v: ContainsLifetime<'a>, | ^^ this lifetime flows to the output @@ -85,7 +85,7 @@ LL + ) -> ContainsLifetime<'a> { | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:47:37 + --> $DIR/mismatched-lifetime-syntaxes.rs:44:37 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { | ^^^ ---------------- the lifetime gets resolved as `'_` @@ -98,7 +98,7 @@ LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> { | ++++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:52:48 + --> $DIR/mismatched-lifetime-syntaxes.rs:49:48 | LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime { | ^^ ---------------- the lifetime gets resolved as `'_` @@ -112,7 +112,7 @@ LL + fn explicit_anonymous_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:57:48 + --> $DIR/mismatched-lifetime-syntaxes.rs:54:48 | LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime { | ^^ ---------------- the lifetime gets resolved as `'a` @@ -125,7 +125,7 @@ LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime<' | ++++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:62:58 + --> $DIR/mismatched-lifetime-syntaxes.rs:59:58 | LL | fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { | ^^ -- the lifetime gets resolved as `'a` @@ -139,7 +139,7 @@ LL + fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> Contains | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:69:37 + --> $DIR/mismatched-lifetime-syntaxes.rs:66:37 | LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 { | ^^^^^^^^^^^^^^^^ --- the lifetime gets resolved as `'_` @@ -152,7 +152,7 @@ LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime<'_>) -> &u8 { | ++++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:74:47 + --> $DIR/mismatched-lifetime-syntaxes.rs:71:47 | LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { | ^^^^^^^^^^^^^^^^ -- the lifetime gets resolved as `'_` @@ -166,7 +166,7 @@ LL + fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &u8 | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:79:64 + --> $DIR/mismatched-lifetime-syntaxes.rs:76:64 | LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 { | ^^ --- the lifetime gets resolved as `'a` @@ -179,7 +179,7 @@ LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &'a | ++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:84:74 + --> $DIR/mismatched-lifetime-syntaxes.rs:81:74 | LL | fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { | ^^ -- the lifetime gets resolved as `'a` @@ -193,7 +193,7 @@ LL + fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:90:55 + --> $DIR/mismatched-lifetime-syntaxes.rs:87:55 | LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 { | ^^ --- the lifetime gets resolved as `'a` @@ -206,7 +206,7 @@ LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &'a u8 { | ++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:95:65 + --> $DIR/mismatched-lifetime-syntaxes.rs:92:65 | LL | fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 { | ^^ -- the lifetime gets resolved as `'a` @@ -220,7 +220,7 @@ LL + fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:102:56 + --> $DIR/mismatched-lifetime-syntaxes.rs:99:56 | LL | fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime { | ^^ ---------------- the lifetime gets resolved as `'_` @@ -234,7 +234,7 @@ LL + fn method_explicit_anonymous_ref_to_implicit_path(&self) -> ContainsLif | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:107:56 + --> $DIR/mismatched-lifetime-syntaxes.rs:104:56 | LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime { | ^^ ---------------- the lifetime gets resolved as `'a` @@ -247,7 +247,7 @@ LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> Contains | ++++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:112:66 + --> $DIR/mismatched-lifetime-syntaxes.rs:109:66 | LL | fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { | ^^ -- the lifetime gets resolved as `'a` @@ -261,7 +261,7 @@ LL + fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) - | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:127:39 + --> $DIR/mismatched-lifetime-syntaxes.rs:124:39 | LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 { | ^^^^^^^ --- the lifetime gets resolved as `'static` @@ -274,7 +274,7 @@ LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &'static u8 { | +++++++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:132:49 + --> $DIR/mismatched-lifetime-syntaxes.rs:129:49 | LL | fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 { | ^^^^^^^ -- the lifetime gets resolved as `'static` @@ -288,7 +288,7 @@ LL + fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'static u8 | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:137:40 + --> $DIR/mismatched-lifetime-syntaxes.rs:134:40 | LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime { | ^^^^^^^ ---------------- the lifetime gets resolved as `'static` @@ -301,7 +301,7 @@ LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime<'sta | +++++++++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:142:50 + --> $DIR/mismatched-lifetime-syntaxes.rs:139:50 | LL | fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { | ^^^^^^^ -- the lifetime gets resolved as `'static` @@ -315,7 +315,7 @@ LL + fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLif | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:148:40 + --> $DIR/mismatched-lifetime-syntaxes.rs:145:40 | LL | fn static_ref_to_implicit_ref(&'static self) -> &u8 { | ^^^^^^^ --- the lifetime gets resolved as `'static` @@ -328,7 +328,7 @@ LL | fn static_ref_to_implicit_ref(&'static self) -> &'static u8 { | +++++++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:153:50 + --> $DIR/mismatched-lifetime-syntaxes.rs:150:50 | LL | fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 { | ^^^^^^^ -- the lifetime gets resolved as `'static` @@ -342,7 +342,7 @@ LL + fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'static | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:158:41 + --> $DIR/mismatched-lifetime-syntaxes.rs:155:41 | LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime { | ^^^^^^^ ---------------- the lifetime gets resolved as `'static` @@ -355,7 +355,7 @@ LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime<' | +++++++++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:163:51 + --> $DIR/mismatched-lifetime-syntaxes.rs:160:51 | LL | fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> { | ^^^^^^^ -- the lifetime gets resolved as `'static` @@ -369,7 +369,7 @@ LL + fn static_ref_to_explicit_anonymous_path(&'static self) -> Contains | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:175:55 + --> $DIR/mismatched-lifetime-syntaxes.rs:172:55 | LL | fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { | ^^ -- the lifetime gets resolved as `'a` @@ -383,7 +383,7 @@ LL + fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:180:65 + --> $DIR/mismatched-lifetime-syntaxes.rs:177:65 | LL | fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { | ^^ -- the lifetime gets resolved as `'a` @@ -397,7 +397,7 @@ LL + fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> i | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:185:72 + --> $DIR/mismatched-lifetime-syntaxes.rs:182:72 | LL | fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { | ^^ -- the lifetime gets resolved as `'a` @@ -411,7 +411,7 @@ LL + fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:191:29 + --> $DIR/mismatched-lifetime-syntaxes.rs:188:29 | LL | v: ContainsLifetime<'a>, | ^^ this lifetime flows to the output @@ -426,7 +426,7 @@ LL + ) -> impl FnOnce() + use<'a> { | error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:205:54 + --> $DIR/mismatched-lifetime-syntaxes.rs:202:54 | LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box + '_> { | ^^ --- -- the lifetimes get resolved as `'a` @@ -440,7 +440,7 @@ LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box $DIR/mismatched-lifetime-syntaxes.rs:211:29 + --> $DIR/mismatched-lifetime-syntaxes.rs:208:29 | LL | v: ContainsLifetime<'a>, | ^^ this lifetime flows to the output @@ -456,7 +456,7 @@ LL | ) -> Box> + '_> { | ++++ error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:220:33 + --> $DIR/mismatched-lifetime-syntaxes.rs:217:33 | LL | fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) { | ^^ --- --- the lifetimes get resolved as `'a` diff --git a/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.rs b/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.rs deleted file mode 100644 index eac7c32a9aa..00000000000 --- a/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![deny(elided_named_lifetimes)] - -struct Foo; - -impl Foo { - pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { - //~^ ERROR elided lifetime has a name - unsafe { &mut *(x as *mut _) } - } -} - -fn main() {} diff --git a/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr b/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr deleted file mode 100644 index 2d8c6e99643..00000000000 --- a/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: elided lifetime has a name - --> $DIR/example-from-issue48686.rs:6:50 - | -LL | pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { - | ^ this elided lifetime gets resolved as `'static` - | -note: the lint level is defined here - --> $DIR/example-from-issue48686.rs:1:9 - | -LL | #![deny(elided_named_lifetimes)] - | ^^^^^^^^^^^^^^^^^^^^^^ -help: consider specifying it explicitly - | -LL | pub fn get_mut(&'static self, x: &mut u8) -> &'static mut u8 { - | +++++++ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.rs b/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.rs deleted file mode 100644 index 2f9083ed65f..00000000000 --- a/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![deny(elided_named_lifetimes)] - -fn ampersand<'a>(x: &'a u8) -> &u8 { - //~^ ERROR elided lifetime has a name - x -} - -struct Brackets<'a>(&'a u8); - -fn brackets<'a>(x: &'a u8) -> Brackets { - //~^ ERROR elided lifetime has a name - Brackets(x) -} - -struct Comma<'a, T>(&'a T); - -fn comma<'a>(x: &'a u8) -> Comma { - //~^ ERROR elided lifetime has a name - Comma(x) -} - -fn underscore<'a>(x: &'a u8) -> &'_ u8 { - //~^ ERROR elided lifetime has a name - x -} - -fn main() {} diff --git a/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.stderr b/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.stderr deleted file mode 100644 index 249ae146b16..00000000000 --- a/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.stderr +++ /dev/null @@ -1,40 +0,0 @@ -error: elided lifetime has a name - --> $DIR/missing-lifetime-kind.rs:3:32 - | -LL | fn ampersand<'a>(x: &'a u8) -> &u8 { - | -- ^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - | -note: the lint level is defined here - --> $DIR/missing-lifetime-kind.rs:1:9 - | -LL | #![deny(elided_named_lifetimes)] - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: elided lifetime has a name - --> $DIR/missing-lifetime-kind.rs:10:31 - | -LL | fn brackets<'a>(x: &'a u8) -> Brackets { - | -- ^^^^^^^^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - -error: elided lifetime has a name - --> $DIR/missing-lifetime-kind.rs:17:33 - | -LL | fn comma<'a>(x: &'a u8) -> Comma { - | -- ^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - -error: elided lifetime has a name - --> $DIR/missing-lifetime-kind.rs:22:34 - | -LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 { - | -- ^^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - -error: aborting due to 4 previous errors - diff --git a/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.rs b/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.rs deleted file mode 100644 index 4f9218130fb..00000000000 --- a/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![allow(elided_named_lifetimes)] - -#[warn(elided_named_lifetimes)] -mod foo { - fn bar(x: &'static u8) -> &u8 { - //~^ WARNING elided lifetime has a name - x - } - - #[deny(elided_named_lifetimes)] - fn baz(x: &'static u8) -> &u8 { - //~^ ERROR elided lifetime has a name - x - } -} - -fn main() {} diff --git a/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr b/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr deleted file mode 100644 index 3c01375d501..00000000000 --- a/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr +++ /dev/null @@ -1,34 +0,0 @@ -warning: elided lifetime has a name - --> $DIR/not-tied-to-crate.rs:5:31 - | -LL | fn bar(x: &'static u8) -> &u8 { - | ^ this elided lifetime gets resolved as `'static` - | -note: the lint level is defined here - --> $DIR/not-tied-to-crate.rs:3:8 - | -LL | #[warn(elided_named_lifetimes)] - | ^^^^^^^^^^^^^^^^^^^^^^ -help: consider specifying it explicitly - | -LL | fn bar(x: &'static u8) -> &'static u8 { - | +++++++ - -error: elided lifetime has a name - --> $DIR/not-tied-to-crate.rs:11:31 - | -LL | fn baz(x: &'static u8) -> &u8 { - | ^ this elided lifetime gets resolved as `'static` - | -note: the lint level is defined here - --> $DIR/not-tied-to-crate.rs:10:12 - | -LL | #[deny(elided_named_lifetimes)] - | ^^^^^^^^^^^^^^^^^^^^^^ -help: consider specifying it explicitly - | -LL | fn baz(x: &'static u8) -> &'static u8 { - | +++++++ - -error: aborting due to 1 previous error; 1 warning emitted - diff --git a/tests/ui/lint/elided-named-lifetimes/static.rs b/tests/ui/lint/elided-named-lifetimes/static.rs deleted file mode 100644 index dc8222c6e6e..00000000000 --- a/tests/ui/lint/elided-named-lifetimes/static.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![deny(elided_named_lifetimes)] - -use std::borrow::Cow; - -const A: &[u8] = &[]; -static B: &str = "hello"; - -trait Trait { - const C: &u8 = &0; -} - -impl Trait for () { - const C: &u8 = &1; -} - -fn ampersand(x: &'static u8) -> &u8 { - //~^ ERROR elided lifetime has a name - x -} - -struct Brackets<'a>(&'a u8); - -fn brackets(x: &'static u8) -> Brackets { - //~^ ERROR elided lifetime has a name - Brackets(x) -} - -struct Comma<'a, T>(&'a T); - -fn comma(x: &'static u8) -> Comma { - //~^ ERROR elided lifetime has a name - Comma(x) -} - -fn underscore(x: &'static u8) -> &'_ u8 { - //~^ ERROR elided lifetime has a name - x -} - -const NESTED: &Vec<&Box>> = &vec![]; - -fn main() { - const HELLO: &str = "Hello"; - static WORLD: &str = "world"; - println!("{HELLO}, {WORLD}!") -} diff --git a/tests/ui/lint/elided-named-lifetimes/static.stderr b/tests/ui/lint/elided-named-lifetimes/static.stderr deleted file mode 100644 index 7ad08dbf04b..00000000000 --- a/tests/ui/lint/elided-named-lifetimes/static.stderr +++ /dev/null @@ -1,52 +0,0 @@ -error: elided lifetime has a name - --> $DIR/static.rs:16:33 - | -LL | fn ampersand(x: &'static u8) -> &u8 { - | ^ this elided lifetime gets resolved as `'static` - | -note: the lint level is defined here - --> $DIR/static.rs:1:9 - | -LL | #![deny(elided_named_lifetimes)] - | ^^^^^^^^^^^^^^^^^^^^^^ -help: consider specifying it explicitly - | -LL | fn ampersand(x: &'static u8) -> &'static u8 { - | +++++++ - -error: elided lifetime has a name - --> $DIR/static.rs:23:32 - | -LL | fn brackets(x: &'static u8) -> Brackets { - | ^^^^^^^^ this elided lifetime gets resolved as `'static` - | -help: consider specifying it explicitly - | -LL | fn brackets(x: &'static u8) -> Brackets<'static> { - | +++++++++ - -error: elided lifetime has a name - --> $DIR/static.rs:30:34 - | -LL | fn comma(x: &'static u8) -> Comma { - | ^ this elided lifetime gets resolved as `'static` - | -help: consider specifying it explicitly - | -LL | fn comma(x: &'static u8) -> Comma<'static, u8> { - | ++++++++ - -error: elided lifetime has a name - --> $DIR/static.rs:35:35 - | -LL | fn underscore(x: &'static u8) -> &'_ u8 { - | ^^ this elided lifetime gets resolved as `'static` - | -help: consider specifying it explicitly - | -LL - fn underscore(x: &'static u8) -> &'_ u8 { -LL + fn underscore(x: &'static u8) -> &'static u8 { - | - -error: aborting due to 4 previous errors - diff --git a/tests/ui/macros/format-args-temporaries.rs b/tests/ui/macros/format-args-temporaries.rs index ad9792bc796..74714be7653 100644 --- a/tests/ui/macros/format-args-temporaries.rs +++ b/tests/ui/macros/format-args-temporaries.rs @@ -5,7 +5,7 @@ use std::fmt::{self, Display}; struct Mutex; impl Mutex { - fn lock(&self) -> MutexGuard { + fn lock(&self) -> MutexGuard<'_> { MutexGuard(self) } } diff --git a/tests/ui/mir/mir_fat_ptr.rs b/tests/ui/mir/mir_fat_ptr.rs index f2dd9e6fe40..af9831570d1 100644 --- a/tests/ui/mir/mir_fat_ptr.rs +++ b/tests/ui/mir/mir_fat_ptr.rs @@ -20,11 +20,11 @@ fn fat_ptr_via_local(a: &[u8]) -> &[u8] { x } -fn fat_ptr_from_struct(s: FatPtrContainer) -> &[u8] { +fn fat_ptr_from_struct(s: FatPtrContainer<'_>) -> &[u8] { s.ptr } -fn fat_ptr_to_struct(a: &[u8]) -> FatPtrContainer { +fn fat_ptr_to_struct(a: &[u8]) -> FatPtrContainer<'_> { FatPtrContainer { ptr: a } } diff --git a/tests/ui/nll/issue-53570.rs b/tests/ui/nll/issue-53570.rs index 882ce9e1c31..cfc1edd217d 100644 --- a/tests/ui/nll/issue-53570.rs +++ b/tests/ui/nll/issue-53570.rs @@ -22,7 +22,7 @@ struct Scratchpad<'a> { } impl<'a> Scratchpad<'a> { - fn get>(&self) -> Ref<[T]> + fn get>(&self) -> Ref<'_, [T]> where T: 'a { Ref::map(self.buffers.borrow(), |x| T::unwrap(x.as_ref())) diff --git a/tests/ui/nll/issue-54556-niconii.rs b/tests/ui/nll/issue-54556-niconii.rs index 9d37adede6a..dc641524b15 100644 --- a/tests/ui/nll/issue-54556-niconii.rs +++ b/tests/ui/nll/issue-54556-niconii.rs @@ -18,7 +18,7 @@ impl Drop for Mutex { fn drop(&mut self) { println!("Mutex::drop"); } } impl<'a> Drop for MutexGuard<'a> { fn drop(&mut self) { println!("MutexGuard::drop"); } } impl Mutex { - fn lock(&self) -> Result { Ok(MutexGuard(self)) } + fn lock(&self) -> Result, ()> { Ok(MutexGuard(self)) } } fn main() { diff --git a/tests/ui/object-lifetime/object-lifetime-default-elision.rs b/tests/ui/object-lifetime/object-lifetime-default-elision.rs index ede6af51174..f7c0261cfbb 100644 --- a/tests/ui/object-lifetime/object-lifetime-default-elision.rs +++ b/tests/ui/object-lifetime/object-lifetime-default-elision.rs @@ -46,8 +46,6 @@ fn load1(ss: &dyn SomeTrait) -> &dyn SomeTrait { } fn load2<'a>(ss: &'a dyn SomeTrait) -> &dyn SomeTrait { - //~^ WARNING elided lifetime has a name - // Same as `load1` but with an explicit name thrown in for fun. ss diff --git a/tests/ui/object-lifetime/object-lifetime-default-elision.stderr b/tests/ui/object-lifetime/object-lifetime-default-elision.stderr index b44a184c684..b5995687927 100644 --- a/tests/ui/object-lifetime/object-lifetime-default-elision.stderr +++ b/tests/ui/object-lifetime/object-lifetime-default-elision.stderr @@ -1,15 +1,5 @@ -warning: elided lifetime has a name - --> $DIR/object-lifetime-default-elision.rs:48:40 - | -LL | fn load2<'a>(ss: &'a dyn SomeTrait) -> &dyn SomeTrait { - | -- ^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error: lifetime may not live long enough - --> $DIR/object-lifetime-default-elision.rs:73:5 + --> $DIR/object-lifetime-default-elision.rs:71:5 | LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait { | -- -- lifetime `'b` defined here @@ -21,5 +11,5 @@ LL | ss | = help: consider adding the following bound: `'a: 'b` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/regions/init-res-into-things.rs b/tests/ui/regions/init-res-into-things.rs index 64909b32919..7b100d32533 100644 --- a/tests/ui/regions/init-res-into-things.rs +++ b/tests/ui/regions/init-res-into-things.rs @@ -20,7 +20,7 @@ impl<'a> Drop for r<'a> { } } -fn r(i: &Cell) -> r { +fn r(i: &Cell) -> r<'_> { r { i: i } diff --git a/tests/ui/regions/regions-nullary-variant.rs b/tests/ui/regions/regions-nullary-variant.rs index 8624f9961f6..24c5c6765a8 100644 --- a/tests/ui/regions/regions-nullary-variant.rs +++ b/tests/ui/regions/regions-nullary-variant.rs @@ -7,7 +7,7 @@ enum roption<'a> { a, b(&'a usize) } -fn mk(cond: bool, ptr: &usize) -> roption { +fn mk(cond: bool, ptr: &usize) -> roption<'_> { if cond {roption::a} else {roption::b(ptr)} } diff --git a/tests/ui/resource-assign-is-not-copy.rs b/tests/ui/resource-assign-is-not-copy.rs index 078824cea1b..ab426016901 100644 --- a/tests/ui/resource-assign-is-not-copy.rs +++ b/tests/ui/resource-assign-is-not-copy.rs @@ -14,7 +14,7 @@ impl<'a> Drop for r<'a> { } } -fn r(i: &Cell) -> r { +fn r(i: &Cell) -> r<'_> { r { i: i } diff --git a/tests/ui/resource-destruct.rs b/tests/ui/resource-destruct.rs index cbb17bb6ba6..480cbe091a7 100644 --- a/tests/ui/resource-destruct.rs +++ b/tests/ui/resource-destruct.rs @@ -17,7 +17,7 @@ impl<'a> shrinky_pointer<'a> { pub fn look_at(&self) -> isize { return self.i.get(); } } -fn shrinky_pointer(i: &Cell) -> shrinky_pointer { +fn shrinky_pointer(i: &Cell) -> shrinky_pointer<'_> { shrinky_pointer { i: i } diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/temporary-early-drop.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/temporary-early-drop.rs index 9edbc3243c7..9bf6cfcccba 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/temporary-early-drop.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/temporary-early-drop.rs @@ -10,7 +10,7 @@ struct Pd; impl Pd { - fn it(&self) -> It { + fn it(&self) -> It<'_> { todo!() } } diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro.rs index 5dd928dbce5..a61be38a23a 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro.rs @@ -33,7 +33,7 @@ impl DropOrderCollector { println!("{n}"); self.0.borrow_mut().push(n) } - fn some_loud(&self, n: u32) -> Option { + fn some_loud(&self, n: u32) -> Option> { Some(LoudDrop(self, n)) } diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs index 7d8dfe37135..3e4fae2e84e 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs @@ -8,7 +8,7 @@ struct Pd; impl Pd { - fn it(&self) -> It { + fn it(&self) -> It<'_> { todo!() } } diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs index cedc6f0f9bc..ecd669059ed 100644 --- a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs +++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs @@ -4,11 +4,11 @@ struct Foo<'a>(&'a str); impl<'b> Foo<'b> { fn a<'a>(self: Self, a: &'a str) -> &str { - //~^ WARNING elided lifetime has a name + //~^ WARNING lifetime flowing from input to output with different syntax a } fn b<'a>(self: Foo<'b>, a: &'a str) -> &str { - //~^ WARNING elided lifetime has a name + //~^ WARNING lifetime flowing from input to output with different syntax a } } diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr index 4465dbae529..5351bf3c94c 100644 --- a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr +++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr @@ -1,16 +1,29 @@ -warning: elided lifetime has a name - --> $DIR/ignore-non-reference-lifetimes.rs:6:41 +warning: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/ignore-non-reference-lifetimes.rs:6:30 | LL | fn a<'a>(self: Self, a: &'a str) -> &str { - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` + | ^^ ---- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output | - = note: `#[warn(elided_named_lifetimes)]` on by default + = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default +help: one option is to consistently use `'a` + | +LL | fn a<'a>(self: Self, a: &'a str) -> &'a str { + | ++ -warning: elided lifetime has a name - --> $DIR/ignore-non-reference-lifetimes.rs:10:44 +warning: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/ignore-non-reference-lifetimes.rs:10:33 | LL | fn b<'a>(self: Foo<'b>, a: &'a str) -> &str { - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` + | ^^ ---- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn b<'a>(self: Foo<'b>, a: &'a str) -> &'a str { + | ++ warning: 2 warnings emitted diff --git a/tests/ui/self/elision/lt-ref-self-async.fixed b/tests/ui/self/elision/lt-ref-self-async.fixed index aae94f7a6cc..191610336de 100644 --- a/tests/ui/self/elision/lt-ref-self-async.fixed +++ b/tests/ui/self/elision/lt-ref-self-async.fixed @@ -1,6 +1,6 @@ //@ edition:2018 //@ run-rustfix -#![allow(non_snake_case, dead_code, elided_named_lifetimes)] +#![allow(non_snake_case, dead_code, mismatched_lifetime_syntaxes)] use std::pin::Pin; diff --git a/tests/ui/self/elision/lt-ref-self-async.rs b/tests/ui/self/elision/lt-ref-self-async.rs index 0c11b271c35..c910a5d6d7e 100644 --- a/tests/ui/self/elision/lt-ref-self-async.rs +++ b/tests/ui/self/elision/lt-ref-self-async.rs @@ -1,6 +1,6 @@ //@ edition:2018 //@ run-rustfix -#![allow(non_snake_case, dead_code, elided_named_lifetimes)] +#![allow(non_snake_case, dead_code, mismatched_lifetime_syntaxes)] use std::pin::Pin; diff --git a/tests/ui/self/self_lifetime-async.rs b/tests/ui/self/self_lifetime-async.rs index fd690207118..f839ab03a60 100644 --- a/tests/ui/self/self_lifetime-async.rs +++ b/tests/ui/self/self_lifetime-async.rs @@ -4,13 +4,13 @@ struct Foo<'a>(&'a ()); impl<'a> Foo<'a> { async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - //~^ WARNING elided lifetime has a name + //~^ WARNING lifetime flowing from input to output with different syntax } type Alias = Foo<'static>; impl Alias { async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - //~^ WARNING elided lifetime has a name + //~^ WARNING lifetime flowing from input to output with different syntax } fn main() {} diff --git a/tests/ui/self/self_lifetime-async.stderr b/tests/ui/self/self_lifetime-async.stderr index 32de3fd18c9..a9c1be2e808 100644 --- a/tests/ui/self/self_lifetime-async.stderr +++ b/tests/ui/self/self_lifetime-async.stderr @@ -1,18 +1,29 @@ -warning: elided lifetime has a name - --> $DIR/self_lifetime-async.rs:6:44 +warning: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/self_lifetime-async.rs:6:29 | LL | async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - | -- ^ this elided lifetime gets resolved as `'b` - | | - | lifetime `'b` declared here + | ^^ --- the lifetime gets resolved as `'b` + | | + | this lifetime flows to the output | - = note: `#[warn(elided_named_lifetimes)]` on by default + = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default +help: one option is to consistently use `'b` + | +LL | async fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 } + | ++ -warning: elided lifetime has a name - --> $DIR/self_lifetime-async.rs:12:52 +warning: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/self_lifetime-async.rs:12:42 | LL | async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` + | ^^ --- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | async fn bar<'a>(self: &Alias, arg: &'a ()) -> &'a () { arg } + | ++ warning: 2 warnings emitted diff --git a/tests/ui/self/self_lifetime.rs b/tests/ui/self/self_lifetime.rs index 0607c3b9317..aaa31f85ad5 100644 --- a/tests/ui/self/self_lifetime.rs +++ b/tests/ui/self/self_lifetime.rs @@ -5,13 +5,13 @@ struct Foo<'a>(&'a ()); impl<'a> Foo<'a> { fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - //~^ WARNING elided lifetime has a name + //~^ WARNING lifetime flowing from input to output with different syntax } type Alias = Foo<'static>; impl Alias { fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - //~^ WARNING elided lifetime has a name + //~^ WARNING lifetime flowing from input to output with different syntax } fn main() {} diff --git a/tests/ui/self/self_lifetime.stderr b/tests/ui/self/self_lifetime.stderr index cd8f4d8adf8..ec676e69cf6 100644 --- a/tests/ui/self/self_lifetime.stderr +++ b/tests/ui/self/self_lifetime.stderr @@ -1,18 +1,29 @@ -warning: elided lifetime has a name - --> $DIR/self_lifetime.rs:7:38 +warning: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/self_lifetime.rs:7:23 | LL | fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - | -- ^ this elided lifetime gets resolved as `'b` - | | - | lifetime `'b` declared here + | ^^ --- the lifetime gets resolved as `'b` + | | + | this lifetime flows to the output | - = note: `#[warn(elided_named_lifetimes)]` on by default + = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default +help: one option is to consistently use `'b` + | +LL | fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 } + | ++ -warning: elided lifetime has a name - --> $DIR/self_lifetime.rs:13:46 +warning: lifetime flowing from input to output with different syntax can be confusing + --> $DIR/self_lifetime.rs:13:36 | LL | fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` + | ^^ --- the lifetime gets resolved as `'a` + | | + | this lifetime flows to the output + | +help: one option is to consistently use `'a` + | +LL | fn bar<'a>(self: &Alias, arg: &'a ()) -> &'a () { arg } + | ++ warning: 2 warnings emitted diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs index f5c3da847c7..f176d52c087 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs @@ -73,7 +73,6 @@ mod in_path { // This must not err, as the `&` actually resolves to `'a`. fn resolved_anonymous<'a, T: 'a>(f: impl Fn(&'a str) -> &T) { - //~^ WARNING elided lifetime has a name f("f"); } diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr index 92996ca8467..f29107b297a 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr @@ -149,14 +149,6 @@ LL - fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() } LL + fn g(mut x: impl Foo<()>) -> Option<()> { x.next() } | -warning: elided lifetime has a name - --> $DIR/impl-trait-missing-lifetime-gated.rs:75:57 - | -LL | fn resolved_anonymous<'a, T: 'a>(f: impl Fn(&'a str) -> &T) { - | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error[E0658]: anonymous lifetimes in `impl Trait` are unstable --> $DIR/impl-trait-missing-lifetime-gated.rs:6:35 | @@ -289,7 +281,7 @@ help: consider introducing a named lifetime parameter LL | fn g<'a>(mut x: impl Foo<'a, ()>) -> Option<&()> { x.next() } | ++++ +++ -error: aborting due to 17 previous errors; 1 warning emitted +error: aborting due to 17 previous errors Some errors have detailed explanations: E0106, E0658. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs index b61bea16e3b..b641f5941dc 100644 --- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs +++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs @@ -100,7 +100,6 @@ where // This also works. The `'_` isn't necessary but it's where we arrive to following the suggestions: fn ok2<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a -//~^ WARNING elided lifetime has a name where G: Get, { diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index b92719e8033..41cb2ee46bb 100644 --- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -6,14 +6,6 @@ LL | fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ | | | help: consider introducing lifetime `'a` here: `'a,` -warning: elided lifetime has a name - --> $DIR/missing-lifetimes-in-signature.rs:102:64 - | -LL | fn ok2<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a - | -- lifetime `'a` declared here ^^ this elided lifetime gets resolved as `'a` - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error[E0700]: hidden type for `impl FnOnce()` captures lifetime that does not appear in bounds --> $DIR/missing-lifetimes-in-signature.rs:19:5 | @@ -136,7 +128,7 @@ help: consider adding an explicit lifetime bound LL | G: Get + 'a, | ++++ -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 8 previous errors Some errors have detailed explanations: E0261, E0309, E0311, E0621, E0700. For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/type-alias-impl-trait/missing_lifetime_bound.rs b/tests/ui/type-alias-impl-trait/missing_lifetime_bound.rs index d77efa39aeb..60d9521621f 100644 --- a/tests/ui/type-alias-impl-trait/missing_lifetime_bound.rs +++ b/tests/ui/type-alias-impl-trait/missing_lifetime_bound.rs @@ -3,7 +3,7 @@ type Opaque2 = impl Sized; type Opaque<'a, T> = Opaque2; #[define_opaque(Opaque)] -fn defining<'a, T>(x: &'a i32) -> Opaque { x } //~ WARNING elided lifetime has a name +fn defining<'a, T>(x: &'a i32) -> Opaque { x } //~^ ERROR: hidden type for `Opaque2` captures lifetime that does not appear in bounds fn main() {} diff --git a/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr b/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr index 61eb76ffc5a..b73e6b8c101 100644 --- a/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr +++ b/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr @@ -1,13 +1,3 @@ -warning: elided lifetime has a name - --> $DIR/missing_lifetime_bound.rs:6:41 - | -LL | fn defining<'a, T>(x: &'a i32) -> Opaque { x } - | -- ^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - | - = note: `#[warn(elided_named_lifetimes)]` on by default - error[E0700]: hidden type for `Opaque2` captures lifetime that does not appear in bounds --> $DIR/missing_lifetime_bound.rs:6:47 | @@ -19,6 +9,6 @@ LL | fn defining<'a, T>(x: &'a i32) -> Opaque { x } | | | hidden type `&'a i32` captures the lifetime `'a` as defined here -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/type-id-higher-rank-2.rs b/tests/ui/type-id-higher-rank-2.rs index 4a76b737e8c..7b0c7b53940 100644 --- a/tests/ui/type-id-higher-rank-2.rs +++ b/tests/ui/type-id-higher-rank-2.rs @@ -5,7 +5,7 @@ use std::any::Any; struct Foo<'a>(&'a str); -fn good(s: &String) -> Foo { Foo(s) } +fn good(s: &String) -> Foo<'_> { Foo(s) } fn bad1(s: String) -> Option<&'static str> { let a: Box = Box::new(good as fn(&String) -> Foo); diff --git a/tests/ui/underscore-lifetimes.rs b/tests/ui/underscore-lifetimes.rs index 6174f8ce036..a372851f9cf 100644 --- a/tests/ui/underscore-lifetimes.rs +++ b/tests/ui/underscore-lifetimes.rs @@ -1,6 +1,6 @@ //@ run-pass -#![allow(dead_code)] +#![allow(dead_code, mismatched_lifetime_syntaxes)] struct Foo<'a>(&'a u8); fn foo(x: &u8) -> Foo<'_> { -- cgit 1.4.1-3-g733a5 From 64172481da44e0dd6a705afcea22b58b45b42c5a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 4 Jun 2025 08:12:54 +0000 Subject: Report the actual item that evaluation failed for --- compiler/rustc_const_eval/src/const_eval/eval_queries.rs | 5 +++-- tests/ui/consts/miri_unleashed/assoc_const.stderr | 2 +- tests/ui/consts/uninhabited-const-issue-61744.rs | 1 + tests/ui/consts/uninhabited-const-issue-61744.stderr | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 01625b91353..2556e57a58f 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -454,11 +454,12 @@ fn report_eval_error<'tcx>( // FIXME(oli-obk): figure out how to use structured diagnostics again. diag.code(E0080); diag.span_label(span, crate::fluent_generated::const_eval_error); - diag.arg("instance", instance); - diag.arg("error_kind", kind); for frame in frames { diag.subdiagnostic(frame); } + // Add after the frame rendering above, as it adds its own `instance` args. + diag.arg("instance", instance); + diag.arg("error_kind", kind); }, ) } diff --git a/tests/ui/consts/miri_unleashed/assoc_const.stderr b/tests/ui/consts/miri_unleashed/assoc_const.stderr index b6dcb86f360..e843615bd6d 100644 --- a/tests/ui/consts/miri_unleashed/assoc_const.stderr +++ b/tests/ui/consts/miri_unleashed/assoc_const.stderr @@ -2,7 +2,7 @@ error[E0080]: calling non-const function ` as Drop>::drop` --> $DIR/assoc_const.rs:12:31 | LL | const F: u32 = (U::X, 42).1; - | ^ evaluation of `drop_in_place::> - shim(Some(Vec))` failed here + | ^ evaluation of `, std::string::String>>::F` failed here | note: inside `drop_in_place::<(Vec, u32)> - shim(Some((Vec, u32)))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/uninhabited-const-issue-61744.rs b/tests/ui/consts/uninhabited-const-issue-61744.rs index d33f9c268a5..698245b5cb8 100644 --- a/tests/ui/consts/uninhabited-const-issue-61744.rs +++ b/tests/ui/consts/uninhabited-const-issue-61744.rs @@ -11,6 +11,7 @@ pub const unsafe fn hint_unreachable() -> ! { trait Const { const CONSTANT: i32 = unsafe { fake_type() }; //~ ERROR reached the configured maximum number of stack frames + //~^ NOTE evaluation of `::CONSTANT` failed here } impl Const for T {} diff --git a/tests/ui/consts/uninhabited-const-issue-61744.stderr b/tests/ui/consts/uninhabited-const-issue-61744.stderr index 3c5b5196aeb..f13f6126e94 100644 --- a/tests/ui/consts/uninhabited-const-issue-61744.stderr +++ b/tests/ui/consts/uninhabited-const-issue-61744.stderr @@ -2,7 +2,7 @@ error[E0080]: reached the configured maximum number of stack frames --> $DIR/uninhabited-const-issue-61744.rs:13:36 | LL | const CONSTANT: i32 = unsafe { fake_type() }; - | ^^^^^^^^^^^ evaluation of `fake_type::` failed here + | ^^^^^^^^^^^ evaluation of `::CONSTANT` failed here | note: inside `fake_type::` --> $DIR/uninhabited-const-issue-61744.rs:5:5 -- cgit 1.4.1-3-g733a5 From 55f59fb0e329d0815a06d51dd469d774eb455cba Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 4 Jun 2025 15:51:36 +0000 Subject: Fix parsing of frontmatters with inner hyphens --- compiler/rustc_lexer/src/lib.rs | 4 +++- tests/ui/frontmatter/frontmatter-inner-hyphens-1.rs | 10 ++++++++++ tests/ui/frontmatter/frontmatter-inner-hyphens-2.rs | 11 +++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 tests/ui/frontmatter/frontmatter-inner-hyphens-1.rs create mode 100644 tests/ui/frontmatter/frontmatter-inner-hyphens-2.rs diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 2374f388250..ece3f9107b0 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -545,11 +545,12 @@ impl Cursor<'_> { let mut s = self.as_str(); let mut found = false; + let mut size = 0; while let Some(closing) = s.find(&"-".repeat(length_opening as usize)) { let preceding_chars_start = s[..closing].rfind("\n").map_or(0, |i| i + 1); if s[preceding_chars_start..closing].chars().all(is_whitespace) { // candidate found - self.bump_bytes(closing); + self.bump_bytes(size + closing); // in case like // ---cargo // --- blahblah @@ -562,6 +563,7 @@ impl Cursor<'_> { break; } else { s = &s[closing + length_opening as usize..]; + size += closing + length_opening as usize; } } diff --git a/tests/ui/frontmatter/frontmatter-inner-hyphens-1.rs b/tests/ui/frontmatter/frontmatter-inner-hyphens-1.rs new file mode 100644 index 00000000000..985b1cfe988 --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-inner-hyphens-1.rs @@ -0,0 +1,10 @@ +--- +x ---🚧️ +--- + +// Regression test for #141483 +//@check-pass + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/frontmatter-inner-hyphens-2.rs b/tests/ui/frontmatter/frontmatter-inner-hyphens-2.rs new file mode 100644 index 00000000000..3d5fb453872 --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-inner-hyphens-2.rs @@ -0,0 +1,11 @@ +--- +x ---y +--- + +// Test that hypens are allowed inside frontmatters if there is some +// non-whitespace character preceding them. +//@check-pass + +#![feature(frontmatter)] + +fn main() {} -- cgit 1.4.1-3-g733a5 From b541f93372c24bcbf036efc2b454cff6f6b8f8c5 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Thu, 2 Jan 2025 17:47:10 -0800 Subject: Add Location::file_with_nul This is useful for C/C++ APIs which expect the const char* returned from __FILE__ or std::source_location::file_name. --- .../rustc_const_eval/src/util/caller_location.rs | 21 ++++++----- library/core/src/panic/location.rs | 41 +++++++++++++--------- .../file-is-nul-terminated.rs | 25 +++++++++++++ 3 files changed, 63 insertions(+), 24 deletions(-) create mode 100644 tests/ui/rfcs/rfc-2091-track-caller/file-is-nul-terminated.rs diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index e926040e9ba..9c867cc615e 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -15,15 +15,20 @@ fn alloc_caller_location<'tcx>( line: u32, col: u32, ) -> MPlaceTy<'tcx> { + // Ensure that the filename itself does not contain nul bytes. + // This isn't possible via POSIX or Windows, but we should ensure no one + // ever does such a thing. + assert!(!filename.as_str().as_bytes().contains(&0)); + let loc_details = ecx.tcx.sess.opts.unstable_opts.location_detail; - // This can fail if rustc runs out of memory right here. Trying to emit an error would be - // pointless, since that would require allocating more memory than these short strings. - let file = if loc_details.file { - ecx.allocate_str_dedup(filename.as_str()).unwrap() - } else { - ecx.allocate_str_dedup("").unwrap() + let file_wide_ptr = { + let filename = if loc_details.file { filename.as_str() } else { "" }; + let filename_with_nul = filename.to_owned() + "\0"; + // This can fail if rustc runs out of memory right here. Trying to emit an error would be + // pointless, since that would require allocating more memory than these short strings. + let file_ptr = ecx.allocate_bytes_dedup(filename_with_nul.as_bytes()).unwrap(); + Immediate::new_slice(file_ptr.into(), filename_with_nul.len().try_into().unwrap(), ecx) }; - let file = file.map_provenance(CtfeProvenance::as_immutable); let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) }; let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) }; @@ -36,7 +41,7 @@ fn alloc_caller_location<'tcx>( let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap(); // Initialize fields. - ecx.write_immediate(file.to_ref(ecx), &ecx.project_field(&location, 0).unwrap()) + ecx.write_immediate(file_wide_ptr, &ecx.project_field(&location, 0).unwrap()) .expect("writing to memory we just allocated cannot fail"); ecx.write_scalar(line, &ecx.project_field(&location, 1).unwrap()) .expect("writing to memory we just allocated cannot fail"); diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs index 1ad5c07d15c..94cfd667ffa 100644 --- a/library/core/src/panic/location.rs +++ b/library/core/src/panic/location.rs @@ -1,3 +1,4 @@ +use crate::ffi::CStr; use crate::fmt; /// A struct containing information about the location of a panic. @@ -32,7 +33,12 @@ use crate::fmt; #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[stable(feature = "panic_hooks", since = "1.10.0")] pub struct Location<'a> { - file: &'a str, + // Note: this filename will have exactly one nul byte at its end, but otherwise + // it must never contain interior nul bytes. This is relied on for the conversion + // to `CStr` below. + // + // The prefix of the string without the trailing nul byte will be a regular UTF8 `str`. + file_bytes_with_nul: &'a [u8], line: u32, col: u32, } @@ -125,9 +131,24 @@ impl<'a> Location<'a> { #[must_use] #[stable(feature = "panic_hooks", since = "1.10.0")] #[rustc_const_stable(feature = "const_location_fields", since = "1.79.0")] - #[inline] pub const fn file(&self) -> &str { - self.file + let str_len = self.file_bytes_with_nul.len() - 1; + // SAFETY: `file_bytes_with_nul` without the trailing nul byte is guaranteed to be + // valid UTF8. + unsafe { crate::str::from_raw_parts(self.file_bytes_with_nul.as_ptr(), str_len) } + } + + /// Returns the name of the source file as a nul-terminated `CStr`. + /// + /// This is useful for interop with APIs that expect C/C++ `__FILE__` or + /// `std::source_location::file_name`, both of which return a nul-terminated `const char*`. + #[must_use] + #[unstable(feature = "file_with_nul", issue = "141727")] + #[inline] + pub const fn file_with_nul(&self) -> &CStr { + // SAFETY: `file_bytes_with_nul` is guaranteed to have a trailing nul byte and no + // interior nul bytes. + unsafe { CStr::from_bytes_with_nul_unchecked(self.file_bytes_with_nul) } } /// Returns the line number from which the panic originated. @@ -181,22 +202,10 @@ impl<'a> Location<'a> { } } -#[unstable( - feature = "panic_internals", - reason = "internal details of the implementation of the `panic!` and related macros", - issue = "none" -)] -impl<'a> Location<'a> { - #[doc(hidden)] - pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self { - Location { file, line, col } - } -} - #[stable(feature = "panic_hook_display", since = "1.26.0")] impl fmt::Display for Location<'_> { #[inline] fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "{}:{}:{}", self.file, self.line, self.col) + write!(formatter, "{}:{}:{}", self.file(), self.line, self.col) } } diff --git a/tests/ui/rfcs/rfc-2091-track-caller/file-is-nul-terminated.rs b/tests/ui/rfcs/rfc-2091-track-caller/file-is-nul-terminated.rs new file mode 100644 index 00000000000..65e61a21f1a --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/file-is-nul-terminated.rs @@ -0,0 +1,25 @@ +//@ run-pass +#![feature(file_with_nul)] + +#[track_caller] +const fn assert_file_has_trailing_zero() { + let caller = core::panic::Location::caller(); + let file_str = caller.file(); + let file_with_nul = caller.file_with_nul(); + if file_str.len() != file_with_nul.count_bytes() { + panic!("mismatched lengths"); + } + let trailing_byte: core::ffi::c_char = unsafe { + *file_with_nul.as_ptr().offset(file_with_nul.count_bytes() as _) + }; + if trailing_byte != 0 { + panic!("trailing byte was nonzero") + } +} + +#[allow(dead_code)] +const _: () = assert_file_has_trailing_zero(); + +fn main() { + assert_file_has_trailing_zero(); +} -- cgit 1.4.1-3-g733a5 From e1e3cc24a22d0951e802b413b00bfd104ea22c7e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 4 Jun 2025 08:20:08 +0000 Subject: Replace the musl submodule with a download script The submodule was causing issues in rust-lang/rust, so eliminiate it here. `build-musl` is also removed from `libm-test`'s default features so the crate doesn't need to be built by default. --- .../compiler-builtins/.github/workflows/main.yaml | 22 ++++++++++------------ library/compiler-builtins/.gitignore | 3 +++ library/compiler-builtins/.gitmodules | 4 ---- library/compiler-builtins/ci/update-musl.sh | 15 +++++++++++++++ .../crates/musl-math-sys/build.rs | 2 +- .../compiler-builtins/crates/musl-math-sys/musl | 1 - library/compiler-builtins/libm-test/Cargo.toml | 2 +- 7 files changed, 30 insertions(+), 19 deletions(-) delete mode 100644 library/compiler-builtins/.gitmodules create mode 100755 library/compiler-builtins/ci/update-musl.sh delete mode 160000 library/compiler-builtins/crates/musl-math-sys/musl diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 9f389d8b485..95b0962b082 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -108,8 +108,6 @@ jobs: - name: Print runner information run: uname -a - uses: actions/checkout@v4 - with: - submodules: true - name: Install Rust (rustup) shell: bash run: | @@ -146,6 +144,10 @@ jobs: shell: bash - run: echo "RUST_COMPILER_RT_ROOT=$(realpath ./compiler-rt)" >> "$GITHUB_ENV" shell: bash + + - name: Download musl source + run: ./ci/update-musl.sh + shell: bash - name: Verify API list if: matrix.os == 'ubuntu-24.04' @@ -182,8 +184,6 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v4 - with: - submodules: true # Unlike rustfmt, stable clippy does not work on code with nightly features. - name: Install nightly `clippy` run: | @@ -191,6 +191,8 @@ jobs: rustup default nightly rustup component add clippy - uses: Swatinem/rust-cache@v2 + - name: Download musl source + run: ./ci/update-musl.sh - run: cargo clippy --workspace --all-targets benchmarks: @@ -205,8 +207,6 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@master - with: - submodules: true - uses: taiki-e/install-action@cargo-binstall - name: Set up dependencies @@ -223,6 +223,8 @@ jobs: - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} + - name: Download musl source + run: ./ci/update-musl.sh - name: Run icount benchmarks env: @@ -256,8 +258,6 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v4 - with: - submodules: true - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly shell: bash @@ -292,8 +292,6 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v4 - with: - submodules: true - name: Install stable `rustfmt` run: rustup set profile minimal && rustup default stable && rustup component add rustfmt - run: cargo fmt -- --check @@ -317,13 +315,13 @@ jobs: TO_TEST: ${{ matrix.to_test }} steps: - uses: actions/checkout@v4 - with: - submodules: true - name: Install Rust run: | rustup update nightly --no-self-update rustup default nightly - uses: Swatinem/rust-cache@v2 + - name: download musl source + run: ./ci/update-musl.sh - name: Run extensive tests run: ./ci/run-extensive.sh - name: Print test logs if available diff --git a/library/compiler-builtins/.gitignore b/library/compiler-builtins/.gitignore index 5287a6c72be..f12b871c2f7 100644 --- a/library/compiler-builtins/.gitignore +++ b/library/compiler-builtins/.gitignore @@ -14,3 +14,6 @@ iai-home *.bk *.rs.bk .#* + +# Manually managed +crates/musl-math-sys/musl diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules deleted file mode 100644 index 792ed9ab21f..00000000000 --- a/library/compiler-builtins/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "crates/musl-math-sys/musl"] - path = crates/musl-math-sys/musl - url = https://git.musl-libc.org/git/musl - shallow = true diff --git a/library/compiler-builtins/ci/update-musl.sh b/library/compiler-builtins/ci/update-musl.sh new file mode 100755 index 00000000000..b71cf577830 --- /dev/null +++ b/library/compiler-builtins/ci/update-musl.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# Download musl to a repository for `musl-math-sys` + +set -eux + +url=git://git.musl-libc.org/musl +ref=c47ad25ea3b484e10326f933e927c0bc8cded3da +dst=crates/musl-math-sys/musl + +if ! [ -d "$dst" ]; then + git clone "$url" "$dst" --single-branch --depth=1000 +fi + +git -C "$dst" fetch "$url" --depth=1 +git -C "$dst" checkout "$ref" diff --git a/library/compiler-builtins/crates/musl-math-sys/build.rs b/library/compiler-builtins/crates/musl-math-sys/build.rs index b00dbc73e28..59e42f2d2e6 100644 --- a/library/compiler-builtins/crates/musl-math-sys/build.rs +++ b/library/compiler-builtins/crates/musl-math-sys/build.rs @@ -120,7 +120,7 @@ fn build_musl_math(cfg: &Config) { let arch_dir = musl_dir.join("arch").join(&cfg.musl_arch); assert!( math.exists(), - "musl source not found. Is the submodule up to date?" + "musl source not found. You may need to run `./ci/update-musl.sh`." ); let source_map = find_math_source(&math, cfg); diff --git a/library/compiler-builtins/crates/musl-math-sys/musl b/library/compiler-builtins/crates/musl-math-sys/musl deleted file mode 160000 index c47ad25ea3b..00000000000 --- a/library/compiler-builtins/crates/musl-math-sys/musl +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c47ad25ea3b484e10326f933e927c0bc8cded3da diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index 01b45716b7a..05fcc3234e0 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -6,7 +6,7 @@ publish = false license = "MIT OR Apache-2.0" [features] -default = ["build-mpfr", "build-musl", "unstable-float"] +default = ["build-mpfr", "unstable-float"] # Propagated from libm because this affects which functions we test. unstable-float = ["libm/unstable-float", "rug?/nightly-float"] -- cgit 1.4.1-3-g733a5 From f67ca0fe37eb7de1a6ed748a926122f177ed6472 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 28 May 2025 14:45:14 +0000 Subject: Add an empty rust-version file This will be used by `josh` tooling. --- library/compiler-builtins/rust-version | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 library/compiler-builtins/rust-version diff --git a/library/compiler-builtins/rust-version b/library/compiler-builtins/rust-version new file mode 100644 index 00000000000..e69de29bb2d -- cgit 1.4.1-3-g733a5 From 3353a891e328715673f7687b3ccc7f90c52d1dca Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 18 May 2025 17:30:58 +0000 Subject: Add tooling for `josh` syncs Create a crate that handles pulling from and pushing to rust-lang/rust. This can be invoked with the following: $ cargo run -p josh-sync -- rustc-pull $ RUSTC_GIT=/path/to/rust/checkout cargo run -p josh-sync -- rustc-push --- library/compiler-builtins/Cargo.toml | 1 + .../compiler-builtins/crates/josh-sync/Cargo.toml | 7 + .../compiler-builtins/crates/josh-sync/src/main.rs | 45 +++ .../compiler-builtins/crates/josh-sync/src/sync.rs | 371 +++++++++++++++++++++ 4 files changed, 424 insertions(+) create mode 100644 library/compiler-builtins/crates/josh-sync/Cargo.toml create mode 100644 library/compiler-builtins/crates/josh-sync/src/main.rs create mode 100644 library/compiler-builtins/crates/josh-sync/src/sync.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index bc6b4bd2979..fb638f2fb37 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -3,6 +3,7 @@ resolver = "2" members = [ "builtins-test", "compiler-builtins", + "crates/josh-sync", "crates/libm-macros", "crates/musl-math-sys", "crates/panic-handler", diff --git a/library/compiler-builtins/crates/josh-sync/Cargo.toml b/library/compiler-builtins/crates/josh-sync/Cargo.toml new file mode 100644 index 00000000000..1f3bb376d6d --- /dev/null +++ b/library/compiler-builtins/crates/josh-sync/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "josh-sync" +edition = "2024" +publish = false + +[dependencies] +directories = "6.0.0" diff --git a/library/compiler-builtins/crates/josh-sync/src/main.rs b/library/compiler-builtins/crates/josh-sync/src/main.rs new file mode 100644 index 00000000000..7f0b1190033 --- /dev/null +++ b/library/compiler-builtins/crates/josh-sync/src/main.rs @@ -0,0 +1,45 @@ +use std::io::{Read, Write}; +use std::process::exit; +use std::{env, io}; + +use crate::sync::{GitSync, Josh}; + +mod sync; + +const USAGE: &str = r#"Utility for synchroniing compiler-builtins with rust-lang/rust + +Usage: + + josh-sync rustc-pull + + Pull from rust-lang/rust to compiler-builtins. Creates a commit + updating the version file, followed by a merge commit. + + josh-sync rustc-push GITHUB_USERNAME [BRANCH] + + Create a branch off of rust-lang/rust updating compiler-builtins. +"#; + +fn main() { + let sync = GitSync::from_current_dir(); + + // Collect args, then recollect as str refs so we can match on them + let args: Vec<_> = env::args().collect(); + let args: Vec<&str> = args.iter().map(String::as_str).collect(); + + match args.as_slice()[1..] { + ["rustc-pull"] => sync.rustc_pull(None), + ["rustc-push", github_user, branch] => sync.rustc_push(github_user, Some(branch)), + ["rustc-push", github_user] => sync.rustc_push(github_user, None), + ["start-josh"] => { + let _josh = Josh::start(); + println!("press enter to stop"); + io::stdout().flush().unwrap(); + let _ = io::stdin().read(&mut [0u8]).unwrap(); + } + _ => { + println!("{USAGE}"); + exit(1); + } + } +} diff --git a/library/compiler-builtins/crates/josh-sync/src/sync.rs b/library/compiler-builtins/crates/josh-sync/src/sync.rs new file mode 100644 index 00000000000..003cf187d83 --- /dev/null +++ b/library/compiler-builtins/crates/josh-sync/src/sync.rs @@ -0,0 +1,371 @@ +use std::net::{SocketAddr, TcpStream}; +use std::process::{Command, Stdio, exit}; +use std::time::Duration; +use std::{env, fs, process, thread}; + +const JOSH_PORT: u16 = 42042; +const DEFAULT_PR_BRANCH: &str = "update-builtins"; + +pub struct GitSync { + upstream_repo: String, + upstream_ref: String, + upstream_url: String, + josh_filter: String, + josh_url_base: String, +} + +/// This code was adapted from the miri repository, via the rustc-dev-guide +/// () +impl GitSync { + pub fn from_current_dir() -> Self { + let upstream_repo = + env::var("UPSTREAM_ORG").unwrap_or_else(|_| "rust-lang".to_owned()) + "/rust"; + + Self { + upstream_url: format!("https://github.com/{upstream_repo}"), + upstream_repo, + upstream_ref: env::var("UPSTREAM_REF").unwrap_or_else(|_| "HEAD".to_owned()), + josh_filter: ":/library/compiler-builtins".to_owned(), + josh_url_base: format!("http://localhost:{JOSH_PORT}"), + } + } + + /// Pull from rust-lang/rust to compiler-builtins. + pub fn rustc_pull(&self, commit: Option) { + let Self { + upstream_ref, + upstream_url, + upstream_repo, + .. + } = self; + + let new_upstream_base = commit.unwrap_or_else(|| { + let out = check_output(["git", "ls-remote", upstream_url, upstream_ref]); + out.split_whitespace() + .next() + .unwrap_or_else(|| panic!("could not split output: '{out}'")) + .to_owned() + }); + + ensure_clean(); + + // Make sure josh is running. + let _josh = Josh::start(); + let josh_url_filtered = self.josh_url( + &self.upstream_repo, + Some(&new_upstream_base), + Some(&self.josh_filter), + ); + + let previous_upstream_base = fs::read_to_string("rust-version") + .expect("failed to read `rust-version`") + .trim() + .to_string(); + assert_ne!(previous_upstream_base, new_upstream_base, "nothing to pull"); + + let orig_head = check_output(["git", "rev-parse", "HEAD"]); + println!("original upstream base: {previous_upstream_base}"); + println!("new upstream base: {new_upstream_base}"); + println!("original HEAD: {orig_head}"); + + // Fetch the latest upstream HEAD so we can get a summary. Use the Josh URL for caching. + run([ + "git", + "fetch", + &self.josh_url(&self.upstream_repo, Some(&new_upstream_base), Some(":/")), + &new_upstream_base, + "--depth=1", + ]); + let new_summary = check_output(["git", "log", "-1", "--format=%h %s", &new_upstream_base]); + + // Update rust-version file. As a separate commit, since making it part of + // the merge has confused the heck out of josh in the past. + // We pass `--no-verify` to avoid running git hooks. + // We do this before the merge so that if there are merge conflicts, we have + // the right rust-version file while resolving them. + fs::write("rust-version", format!("{new_upstream_base}\n")) + .expect("failed to write rust-version"); + + let prep_message = format!( + "Update the upstream Rust version\n\n\ + To prepare for merging from {upstream_repo}, set the version file to:\n\n \ + {new_summary}\n\ + ", + ); + run([ + "git", + "commit", + "rust-version", + "--no-verify", + "-m", + &prep_message, + ]); + + // Fetch given rustc commit. + run(["git", "fetch", &josh_url_filtered]); + let incoming_ref = check_output(["git", "rev-parse", "FETCH_HEAD"]); + println!("incoming ref: {incoming_ref}"); + + let merge_message = format!( + "Merge ref '{upstream_head_short}{filter}' from {upstream_url}\n\n\ + Pull recent changes from {upstream_repo} via Josh.\n\n\ + Upstream ref: {new_upstream_base}\n\ + Filtered ref: {incoming_ref}\n\ + ", + upstream_head_short = &new_upstream_base[..12], + filter = self.josh_filter + ); + + // This should not add any new root commits. So count those before and after merging. + let num_roots = || -> u32 { + let out = check_output(["git", "rev-list", "HEAD", "--max-parents=0", "--count"]); + out.trim() + .parse::() + .unwrap_or_else(|e| panic!("failed to parse `{out}`: {e}")) + }; + let num_roots_before = num_roots(); + + let pre_merge_sha = check_output(["git", "rev-parse", "HEAD"]); + println!("pre-merge HEAD: {pre_merge_sha}"); + + // Merge the fetched commit. + run([ + "git", + "merge", + "FETCH_HEAD", + "--no-verify", + "--no-ff", + "-m", + &merge_message, + ]); + + let current_sha = check_output(["git", "rev-parse", "HEAD"]); + if current_sha == pre_merge_sha { + run(["git", "reset", "--hard", &orig_head]); + eprintln!( + "No merge was performed, no changes to pull were found. \ + Rolled back the preparation commit." + ); + exit(1); + } + + // Check that the number of roots did not increase. + assert_eq!( + num_roots(), + num_roots_before, + "Josh created a new root commit. This is probably not the history you want." + ); + } + + /// Construct an update to rust-lang/rust from compiler-builtins. + pub fn rustc_push(&self, github_user: &str, branch: Option<&str>) { + let Self { + josh_filter, + upstream_url, + .. + } = self; + + let branch = branch.unwrap_or(DEFAULT_PR_BRANCH); + let josh_url = self.josh_url(&format!("{github_user}/rust"), None, Some(josh_filter)); + let user_upstream_url = format!("git@github.com:{github_user}/rust.git"); + + let Ok(rustc_git) = env::var("RUSTC_GIT") else { + panic!("the RUSTC_GIT environment variable must be set to a rust-lang/rust checkout") + }; + + ensure_clean(); + let base = fs::read_to_string("rust-version") + .expect("failed to read `rust-version`") + .trim() + .to_string(); + + // Make sure josh is running. + let _josh = Josh::start(); + + // Prepare the branch. Pushing works much better if we use as base exactly + // the commit that we pulled from last time, so we use the `rust-version` + // file to find out which commit that would be. + println!("Preparing {github_user}/rust (base: {base})..."); + + if Command::new("git") + .args(["-C", &rustc_git, "fetch", &user_upstream_url, branch]) + .output() // capture output + .expect("could not run fetch") + .status + .success() + { + panic!( + "The branch '{branch}' seems to already exist in '{user_upstream_url}'. \ + Please delete it and try again." + ); + } + + run(["git", "-C", &rustc_git, "fetch", upstream_url, &base]); + + run_cfg("git", |c| { + c.args([ + "-C", + &rustc_git, + "push", + &user_upstream_url, + &format!("{base}:refs/heads/{branch}"), + ]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) // silence the "create GitHub PR" message + }); + println!("pushed PR branch"); + + // Do the actual push. + println!("Pushing changes..."); + run(["git", "push", &josh_url, &format!("HEAD:{branch}")]); + println!(); + + // Do a round-trip check to make sure the push worked as expected. + run(["git", "fetch", &josh_url, branch]); + + let head = check_output(["git", "rev-parse", "HEAD"]); + let fetch_head = check_output(["git", "rev-parse", "FETCH_HEAD"]); + assert_eq!( + head, fetch_head, + "Josh created a non-roundtrip push! Do NOT merge this into rustc!\n\ + Expected {head}, got {fetch_head}." + ); + println!( + "Confirmed that the push round-trips back to compiler-builtins properly. Please \ + create a rustc PR:" + ); + // Open PR with `subtree update` title to silence the `no-merges` triagebot check + println!( + " {upstream_url}/compare/{github_user}:{branch}?quick_pull=1\ + &title=Update%20the%20%60compiler-builtins%60%20subtree\ + &body=Update%20the%20Josh%20subtree%20to%20https%3A%2F%2Fgithub.com%2Frust-lang%2F\ + compiler-builtins%2Fcommit%2F{head_short}.%0A%0Ar%3F%20%40ghost", + head_short = &head[..12], + ); + } + + /// Construct a url to the local Josh server with (optionally) + fn josh_url(&self, repo: &str, rev: Option<&str>, filter: Option<&str>) -> String { + format!( + "{base}/{repo}.git{at}{rev}{filter}{filt_git}", + base = self.josh_url_base, + at = if rev.is_some() { "@" } else { "" }, + rev = rev.unwrap_or_default(), + filter = filter.unwrap_or_default(), + filt_git = if filter.is_some() { ".git" } else { "" } + ) + } +} + +/// Fail if there are files that need to be checked in. +fn ensure_clean() { + let read = check_output(["git", "status", "--untracked-files=no", "--porcelain"]); + assert!( + read.is_empty(), + "working directory must be clean before performing rustc pull" + ); +} + +/* Helpers for running commands with logged invocations */ + +/// Run a command from an array, passing its output through. +fn run<'a, Args: AsRef<[&'a str]>>(l: Args) { + let l = l.as_ref(); + run_cfg(l[0], |c| c.args(&l[1..])); +} + +/// Run a command from an array, collecting its output. +fn check_output<'a, Args: AsRef<[&'a str]>>(l: Args) -> String { + let l = l.as_ref(); + check_output_cfg(l[0], |c| c.args(&l[1..])) +} + +/// [`run`] with configuration. +fn run_cfg(prog: &str, f: impl FnOnce(&mut Command) -> &mut Command) { + // self.read(l.as_ref()); + check_output_cfg(prog, |c| f(c.stdout(Stdio::inherit()))); +} + +/// [`read`] with configuration. All shell helpers print the command and pass stderr. +fn check_output_cfg(prog: &str, f: impl FnOnce(&mut Command) -> &mut Command) -> String { + let mut cmd = Command::new(prog); + cmd.stderr(Stdio::inherit()); + f(&mut cmd); + eprintln!("+ {cmd:?}"); + let out = cmd.output().expect("command failed"); + assert!(out.status.success()); + String::from_utf8(out.stdout.trim_ascii().to_vec()).expect("non-UTF8 output") +} + +/// Create a wrapper that stops Josh on drop. +pub struct Josh(process::Child); + +impl Josh { + pub fn start() -> Self { + // Determine cache directory. + let user_dirs = + directories::ProjectDirs::from("org", "rust-lang", "rustc-compiler-builtins-josh") + .unwrap(); + let local_dir = user_dirs.cache_dir().to_owned(); + + // Start josh, silencing its output. + #[expect(clippy::zombie_processes, reason = "clippy can't handle the loop")] + let josh = process::Command::new("josh-proxy") + .arg("--local") + .arg(local_dir) + .args([ + "--remote=https://github.com", + &format!("--port={JOSH_PORT}"), + "--no-background", + ]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .expect("failed to start josh-proxy, make sure it is installed"); + + // Wait until the port is open. We try every 10ms until 1s passed. + for _ in 0..100 { + // This will generally fail immediately when the port is still closed. + let addr = SocketAddr::from(([127, 0, 0, 1], JOSH_PORT)); + let josh_ready = TcpStream::connect_timeout(&addr, Duration::from_millis(1)); + + if josh_ready.is_ok() { + println!("josh up and running"); + return Josh(josh); + } + + // Not ready yet. + thread::sleep(Duration::from_millis(10)); + } + panic!("Even after waiting for 1s, josh-proxy is still not available.") + } +} + +impl Drop for Josh { + fn drop(&mut self) { + if cfg!(unix) { + // Try to gracefully shut it down. + Command::new("kill") + .args(["-s", "INT", &self.0.id().to_string()]) + .output() + .expect("failed to SIGINT josh-proxy"); + // Sadly there is no "wait with timeout"... so we just give it some time to finish. + thread::sleep(Duration::from_millis(100)); + // Now hopefully it is gone. + if self + .0 + .try_wait() + .expect("failed to wait for josh-proxy") + .is_some() + { + return; + } + } + // If that didn't work (or we're not on Unix), kill it hard. + eprintln!( + "I have to kill josh-proxy the hard way, let's hope this does not \ + break anything." + ); + self.0.kill().expect("failed to SIGKILL josh-proxy"); + } +} -- cgit 1.4.1-3-g733a5 From eb45e57afe52ba549a3929b58dc9060541bf0a20 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 4 Jun 2025 18:10:07 +0000 Subject: Update the upstream Rust version To prepare for merging from rust-lang/rust, set the version file to: df8102fe5f Auto merge of #142002 - onur-ozkan:follow-ups2, r=jieyouxu --- library/compiler-builtins/rust-version | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/rust-version b/library/compiler-builtins/rust-version index e69de29bb2d..e05aaa0573c 100644 --- a/library/compiler-builtins/rust-version +++ b/library/compiler-builtins/rust-version @@ -0,0 +1 @@ +df8102fe5f24f28a918660b0cd918d7331c3896e -- cgit 1.4.1-3-g733a5 From 35cb28b7cfd2659bb1ac5ebed026694770199d0d Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Wed, 4 Jun 2025 21:23:11 +0000 Subject: Verbose suggestion to make param `const` ``` error[E0747]: type provided when a constant was expected --> $DIR/invalid-const-arguments.rs:10:19 | LL | impl Foo for B {} | ^ | help: consider changing this type parameter to a const parameter | LL - impl Foo for B {} LL + impl Foo for B {} | ``` --- .../src/hir_ty_lowering/generics.rs | 2 +- .../early/invalid-const-arguments.stderr | 10 +++++++--- tests/ui/const-generics/kind_mismatch.stderr | 20 ++++++++++++++------ 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 21f0f9648ea..3a26b8331f8 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -73,7 +73,7 @@ fn generic_arg_mismatch_err( let param_name = tcx.hir_ty_param_name(param_local_id); let param_type = tcx.type_of(param.def_id).instantiate_identity(); if param_type.is_suggestable(tcx, false) { - err.span_suggestion( + err.span_suggestion_verbose( tcx.def_span(src_def_id), "consider changing this type parameter to a const parameter", format!("const {param_name}: {param_type}"), diff --git a/tests/ui/const-generics/early/invalid-const-arguments.stderr b/tests/ui/const-generics/early/invalid-const-arguments.stderr index 86b4d006454..3a9868836ec 100644 --- a/tests/ui/const-generics/early/invalid-const-arguments.stderr +++ b/tests/ui/const-generics/early/invalid-const-arguments.stderr @@ -51,9 +51,13 @@ error[E0747]: type provided when a constant was expected --> $DIR/invalid-const-arguments.rs:10:19 | LL | impl Foo for B {} - | - ^ - | | - | help: consider changing this type parameter to a const parameter: `const N: u8` + | ^ + | +help: consider changing this type parameter to a const parameter + | +LL - impl Foo for B {} +LL + impl Foo for B {} + | error[E0747]: unresolved item provided when a constant was expected --> $DIR/invalid-const-arguments.rs:14:32 diff --git a/tests/ui/const-generics/kind_mismatch.stderr b/tests/ui/const-generics/kind_mismatch.stderr index 1487b189619..12a2ab141a6 100644 --- a/tests/ui/const-generics/kind_mismatch.stderr +++ b/tests/ui/const-generics/kind_mismatch.stderr @@ -2,17 +2,25 @@ error[E0747]: type provided when a constant was expected --> $DIR/kind_mismatch.rs:11:38 | LL | impl ContainsKey for KeyHolder {} - | - ^ - | | - | help: consider changing this type parameter to a const parameter: `const K: u8` + | ^ + | +help: consider changing this type parameter to a const parameter + | +LL - impl ContainsKey for KeyHolder {} +LL + impl ContainsKey for KeyHolder {} + | error[E0747]: type provided when a constant was expected --> $DIR/kind_mismatch.rs:11:21 | LL | impl ContainsKey for KeyHolder {} - | - ^ - | | - | help: consider changing this type parameter to a const parameter: `const K: u8` + | ^ + | +help: consider changing this type parameter to a const parameter + | +LL - impl ContainsKey for KeyHolder {} +LL + impl ContainsKey for KeyHolder {} + | error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From ab453db3c4e7a49d0ed3811c12ae658cf578f78b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 4 Jun 2025 21:17:51 +0000 Subject: `panic-handler`: Remove the `no_core` feature This was introduced before `#[panic_handler]` was stable, but should no longer be needed. Additionally, we only need it for `builtins-test-intrinsics`, not as a dependency of `compiler-builtins`. --- library/compiler-builtins/builtins-test-intrinsics/Cargo.toml | 2 +- library/compiler-builtins/compiler-builtins/Cargo.toml | 3 --- library/compiler-builtins/crates/panic-handler/src/lib.rs | 7 ++----- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 704de20c5ad..064b7cad2f6 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -6,7 +6,7 @@ publish = false license = "MIT OR Apache-2.0" [dependencies] -compiler_builtins = { path = "../compiler-builtins", features = ["compiler-builtins"]} +compiler_builtins = { path = "../compiler-builtins", features = ["compiler-builtins"] } panic-handler = { path = "../crates/panic-handler" } [features] diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 6bee8da68a0..11ee9195438 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -24,9 +24,6 @@ core = { version = "1.0.1", optional = true, package = "rustc-std-workspace-core [build-dependencies] cc = { optional = true, version = "1.2" } -[dev-dependencies] -panic-handler = { path = "../crates/panic-handler" } - [features] default = ["compiler-builtins"] diff --git a/library/compiler-builtins/crates/panic-handler/src/lib.rs b/library/compiler-builtins/crates/panic-handler/src/lib.rs index 673e005224b..f4d7c839740 100644 --- a/library/compiler-builtins/crates/panic-handler/src/lib.rs +++ b/library/compiler-builtins/crates/panic-handler/src/lib.rs @@ -1,11 +1,8 @@ //! This is needed for tests on targets that require a `#[panic_handler]` function -#![feature(no_core)] -#![no_core] - -extern crate core; +#![no_std] #[panic_handler] -fn panic(_: &core::panic::PanicInfo) -> ! { +fn panic(_: &core::panic::PanicInfo<'_>) -> ! { loop {} } -- cgit 1.4.1-3-g733a5 From 925e76167ce2465c5c9d990d97c2db99f459640b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 4 Jun 2025 15:03:19 -0700 Subject: Ensure stack in `ThirBuildCx::mirror_exprs` This solve a stack overflow found on Fedora s390x when building `tests/ui/parser/survive-peano-lesson-queue.rs`. Note that the singular `mirror_expr` method already has this stack check, but in this case the plural method was the one recursing too deeply. --- compiler/rustc_mir_build/src/thir/cx/expr.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 226dc920a49..78c168778ac 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -38,7 +38,10 @@ impl<'tcx> ThirBuildCx<'tcx> { } pub(crate) fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> { - exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect() + // `mirror_exprs` may also recurse deeply, so it needs protection from stack overflow. + // Note that we *could* forward to `mirror_expr` for that, but we can consolidate the + // overhead of stack growth by doing it outside the iteration. + ensure_sufficient_stack(|| exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect()) } #[instrument(level = "trace", skip(self, hir_expr))] -- cgit 1.4.1-3-g733a5 From af2a85bd75c011fb3453a4963400918e096e1896 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 4 Jun 2025 15:16:38 -0700 Subject: Ensure stack in `Parser::parse_ty` This solve a stack overflow found on Fedora s390x when building `tests/ui/associated-consts/issue-93775.rs`. --- compiler/rustc_parse/src/parser/ty.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 17481731b11..6eaec2e29ad 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -7,6 +7,7 @@ use rustc_ast::{ Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, UnsafeBinderTy, }; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult}; use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -104,14 +105,17 @@ fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool { impl<'a> Parser<'a> { /// Parses a type. pub fn parse_ty(&mut self) -> PResult<'a, P> { - self.parse_ty_common( - AllowPlus::Yes, - AllowCVariadic::No, - RecoverQPath::Yes, - RecoverReturnSign::Yes, - None, - RecoverQuestionMark::Yes, - ) + // Make sure deeply nested types don't overflow the stack. + ensure_sufficient_stack(|| { + self.parse_ty_common( + AllowPlus::Yes, + AllowCVariadic::No, + RecoverQPath::Yes, + RecoverReturnSign::Yes, + None, + RecoverQuestionMark::Yes, + ) + }) } pub(super) fn parse_ty_with_generics_recovery( -- cgit 1.4.1-3-g733a5 From 64df9e3c8a38e6975a6376ba0384d0a7bd4949ea Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Wed, 4 Jun 2025 14:25:38 -0700 Subject: compiler: Document the offset invariant of `OperandValue::Pair` --- compiler/rustc_codegen_ssa/src/mir/operand.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index eade9e52de9..29d030b7461 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -45,9 +45,15 @@ pub enum OperandValue { Immediate(V), /// A pair of immediate LLVM values. Used by wide pointers too. /// - /// An `OperandValue` *must* be this variant for any type for which + /// # Invariants + /// - For `Pair(a, b)`, `a` is always at offset 0, but may have `FieldIdx(1..)` + /// - `b` is not at offset 0, because `V` is not a 1ZST type. + /// - `a` and `b` will have a different FieldIdx, but otherwise `b`'s may be lower + /// or they may not be adjacent, due to arbitrary numbers of 1ZST fields that + /// will not affect the shape of the data which determines if `Pair` will be used. + /// - An `OperandValue` *must* be this variant for any type for which /// [`LayoutTypeCodegenMethods::is_backend_scalar_pair`] returns `true`. - /// The backend values in this variant must be the *immediate* backend types, + /// - The backend values in this variant must be the *immediate* backend types, /// as returned by [`LayoutTypeCodegenMethods::scalar_pair_element_backend_type`] /// with `immediate: true`. Pair(V, V), -- cgit 1.4.1-3-g733a5 From 53c13011b74eec49f856b8d6e6571d4f330e0fbb Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Thu, 5 Jun 2025 07:09:16 +0000 Subject: Stabilize `const_eq_ignore_ascii_case` --- library/core/src/slice/ascii.rs | 2 +- library/core/src/str/mod.rs | 2 +- .../rust-analyzer/crates/ide-db/src/generated/lints.rs | 14 -------------- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 91befdb8c78..d91f8bba548 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -52,7 +52,7 @@ impl [u8] { /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, /// but without allocating and copying temporaries. #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_unstable(feature = "const_eq_ignore_ascii_case", issue = "131719")] + #[rustc_const_stable(feature = "const_eq_ignore_ascii_case", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 06161cb6c7c..41834793d22 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2671,7 +2671,7 @@ impl str { /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS")); /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_unstable(feature = "const_eq_ignore_ascii_case", issue = "131719")] + #[rustc_const_stable(feature = "const_eq_ignore_ascii_case", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn eq_ignore_ascii_case(&self, other: &str) -> bool { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index f9ff3921266..de8a42979bb 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -4451,20 +4451,6 @@ The tracking issue for this feature is: [#133214] [#133214]: https://github.com/rust-lang/rust/issues/133214 ------------------------- -"##, - default_severity: Severity::Allow, - warn_since: None, - deny_since: None, - }, - Lint { - label: "const_eq_ignore_ascii_case", - description: r##"# `const_eq_ignore_ascii_case` - -The tracking issue for this feature is: [#131719] - -[#131719]: https://github.com/rust-lang/rust/issues/131719 - ------------------------ "##, default_severity: Severity::Allow, -- cgit 1.4.1-3-g733a5 From 51acc5778df121adb1e4a8eea7467400dd7fda5b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 5 Jun 2025 10:03:22 +0200 Subject: canon_abi: make to_erased_extern_abi just a detail in formatting --- compiler/rustc_abi/src/canon_abi.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs index 2cf7648a859..03eeb645489 100644 --- a/compiler/rustc_abi/src/canon_abi.rs +++ b/compiler/rustc_abi/src/canon_abi.rs @@ -50,18 +50,10 @@ pub enum CanonAbi { impl fmt::Display for CanonAbi { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.to_erased_extern_abi().as_str().fmt(f) - } -} - -impl CanonAbi { - /// convert to the ExternAbi that *shares a string* with this CanonAbi - /// - /// A target-insensitive mapping of CanonAbi to ExternAbi, convenient for "forwarding" impls. - /// Importantly, the set of CanonAbi values is a logical *subset* of ExternAbi values, - /// so this is injective: if you take an ExternAbi to a CanonAbi and back, you have lost data. - const fn to_erased_extern_abi(self) -> ExternAbi { - match self { + // convert to the ExternAbi that *shares a string* with this CanonAbi. + // FIXME: ideally we'd avoid printing `CanonAbi`, and preserve `ExternAbi` everywhere + // that we need to generate error messages. + let erased_abi = match self { CanonAbi::C => ExternAbi::C { unwind: false }, CanonAbi::Rust => ExternAbi::Rust, CanonAbi::RustCold => ExternAbi::RustCold, @@ -87,7 +79,8 @@ impl CanonAbi { X86Call::Vectorcall => ExternAbi::Vectorcall { unwind: false }, X86Call::Win64 => ExternAbi::Win64 { unwind: false }, }, - } + }; + erased_abi.as_str().fmt(f) } } -- cgit 1.4.1-3-g733a5 From 1e49ad386289ef1d904861157bdffa29da3fce89 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Thu, 5 Jun 2025 13:20:02 +0800 Subject: Clean `rustc_attr_parsing` documentation Signed-off-by: xizheyin --- compiler/rustc_attr_parsing/src/attributes/mod.rs | 2 +- compiler/rustc_attr_parsing/src/lib.rs | 72 +++++++++++------------ 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index f45cf984f71..bf18e10e19f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -74,7 +74,7 @@ pub(crate) trait AttributeParser: Default + 'static { pub(crate) trait SingleAttributeParser: 'static { const PATH: &'static [Symbol]; - /// Caled when a duplicate attribute is found. + /// Called when a duplicate attribute is found. /// /// `first_span` is the span of the first occurrence of this attribute. // FIXME(jdonszelmann): default error diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 63bccf52018..15037e802ff 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -1,31 +1,38 @@ //! Centralized logic for parsing and attributes. //! -//! Part of a series of crates: -//! - rustc_attr_data_structures: contains types that the parsers parse into -//! - rustc_attr_parsing: this crate -//! - (in the future): rustc_attr_validation +//! ## Architecture +//! This crate is part of a series of crates that handle attribute processing. +//! - [rustc_attr_data_structures](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_data_structures/index.html): Defines the data structures that store parsed attributes +//! - [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html): This crate, handles the parsing of attributes +//! - (planned) rustc_attr_validation: Will handle attribute validation //! -//! History: Check out [#131229](https://github.com/rust-lang/rust/issues/131229). -//! There used to be only one definition of attributes in the compiler: `ast::Attribute`. -//! These were then parsed or validated or both in places distributed all over the compiler. -//! This was a mess... +//! The separation between data structures and parsing follows the principle of separation of concerns. +//! Data structures (`rustc_attr_data_structures`) define what attributes look like after parsing. +//! This crate (`rustc_attr_parsing`) handles how to convert raw tokens into those structures. +//! This split allows other parts of the compiler to use the data structures without needing +//! the parsing logic, making the codebase more modular and maintainable. //! -//! Attributes are markers on items. -//! Many of them are actually attribute-like proc-macros, and are expanded to some other rust syntax. -//! This could either be a user provided proc macro, or something compiler provided. -//! `derive` is an example of one that the compiler provides. -//! These are built-in, but they have a valid expansion to Rust tokens and are thus called "active". -//! I personally like calling these *active* compiler-provided attributes, built-in *macros*, -//! because they still expand, and this helps to differentiate them from built-in *attributes*. -//! However, I'll be the first to admit that the naming here can be confusing. +//! ## Background +//! Previously, the compiler had a single attribute definition (`ast::Attribute`) with parsing and +//! validation scattered throughout the codebase. This was reorganized for better maintainability +//! (see [#131229](https://github.com/rust-lang/rust/issues/131229)). //! -//! The alternative to active attributes, are inert attributes. -//! These can occur in user code (proc-macro helper attributes). -//! But what's important is, many built-in attributes are inert like this. -//! There is nothing they expand to during the macro expansion process, -//! sometimes because they literally cannot expand to something that is valid Rust. -//! They are really just markers to guide the compilation process. -//! An example is `#[inline(...)]` which changes how code for functions is generated. +//! ## Types of Attributes +//! In Rust, attributes are markers that can be attached to items. They come in two main categories. +//! +//! ### 1. Active Attributes +//! These are attribute-like proc-macros that expand into other Rust code. +//! They can be either user-defined or compiler-provided. Examples of compiler-provided active attributes: +//! - `#[derive(...)]`: Expands into trait implementations +//! - `#[cfg()]`: Expands based on configuration +//! - `#[cfg_attr()]`: Conditional attribute application +//! +//! ### 2. Inert Attributes +//! These are pure markers that don't expand into other code. They guide the compilation process. +//! They can be user-defined (in proc-macro helpers) or built-in. Examples of built-in inert attributes: +//! - `#[stable()]`: Marks stable API items +//! - `#[inline()]`: Suggests function inlining +//! - `#[repr()]`: Controls type representation //! //! ```text //! Active Inert @@ -33,27 +40,21 @@ //! │ (mostly in) │ these are parsed │ //! │ rustc_builtin_macros │ here! │ //! │ │ │ -//! │ │ │ //! │ #[derive(...)] │ #[stable()] │ //! Built-in │ #[cfg()] │ #[inline()] │ //! │ #[cfg_attr()] │ #[repr()] │ //! │ │ │ -//! │ │ │ -//! │ │ │ //! ├──────────────────────┼──────────────────────┤ //! │ │ │ -//! │ │ │ //! │ │ `b` in │ //! │ │ #[proc_macro_derive( │ //! User created │ #[proc_macro_attr()] │ a, │ //! │ │ attributes(b) │ //! │ │ ] │ -//! │ │ │ -//! │ │ │ -//! │ │ │ //! └──────────────────────┴──────────────────────┘ //! ``` //! +//! ## How This Crate Works //! In this crate, syntactical attributes (sequences of tokens that look like //! `#[something(something else)]`) are parsed into more semantic attributes, markers on items. //! Multiple syntactic attributes might influence a single semantic attribute. For example, @@ -63,18 +64,17 @@ //! and `#[unstable()]` syntactic attributes, and at the end produce a single //! [`AttributeKind::Stability`](rustc_attr_data_structures::AttributeKind::Stability). //! -//! As a rule of thumb, when a syntactical attribute can be applied more than once, they should be -//! combined into a single semantic attribute. For example: +//! When multiple instances of the same attribute are allowed, they're combined into a single +//! semantic attribute. For example: //! -//! ``` +//! ```rust //! #[repr(C)] //! #[repr(packed)] //! struct Meow {} //! ``` //! -//! should result in a single `AttributeKind::Repr` containing a list of repr annotations, in this -//! case `C` and `packed`. This is equivalent to writing `#[repr(C, packed)]` in a single -//! syntactical annotation. +//! This is equivalent to `#[repr(C, packed)]` and results in a single `AttributeKind::Repr` +//! containing both `C` and `packed` annotations. // tidy-alphabetical-start #![allow(internal_features)] -- cgit 1.4.1-3-g733a5 From 79fbc38867529b3dc29fa0542a1e2b3e4ee592b5 Mon Sep 17 00:00:00 2001 From: maflcko <6399679+maflcko@users.noreply.github.com> Date: Thu, 5 Jun 2025 12:27:08 +0200 Subject: doc: Fix inverted meaning in E0783.md --- compiler/rustc_error_codes/src/error_codes/E0783.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0783.md b/compiler/rustc_error_codes/src/error_codes/E0783.md index 73981e59e0d..ac8641cfc5a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0783.md +++ b/compiler/rustc_error_codes/src/error_codes/E0783.md @@ -9,7 +9,7 @@ match 2u8 { } ``` -Older Rust code using previous editions allowed `...` to stand for exclusive +Older Rust code using previous editions allowed `...` to stand for inclusive ranges which are now signified using `..=`. To make this code compile replace the `...` with `..=`. -- cgit 1.4.1-3-g733a5 From bfe4c5f78c686a239bce276ae0404097da65ce0d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 5 Jun 2025 10:01:07 +0000 Subject: Move opaque type checks from the hir item types visitor onto the wfcheck of the opaqe type itself --- compiler/rustc_hir_analysis/src/check/check.rs | 11 ++ compiler/rustc_hir_analysis/src/collect.rs | 17 --- .../issue-109299-1.stderr | 16 +- tests/ui/associated-type-bounds/duplicate.stderr | 168 ++++++++++----------- tests/ui/query-system/issue-83479.rs | 1 + tests/ui/query-system/issue-83479.stderr | 19 ++- ...alid-assoc-type-suggestion-in-trait-impl.stderr | 34 ++--- .../ui/traits/const-traits/const-impl-trait.stderr | 26 ++-- 8 files changed, 151 insertions(+), 141 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 846eacce9e1..a1210fe6d52 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -770,6 +770,17 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { } else { check_opaque(tcx, def_id); } + + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().predicates_of(def_id); + tcx.ensure_ok().explicit_item_bounds(def_id); + tcx.ensure_ok().explicit_item_self_bounds(def_id); + tcx.ensure_ok().item_bounds(def_id); + tcx.ensure_ok().item_self_bounds(def_id); + if tcx.is_conditionally_const(def_id) { + tcx.ensure_ok().explicit_implied_const_bounds(def_id); + tcx.ensure_ok().const_conditions(def_id); + } } DefKind::TyAlias => { check_type_alias_type_params_are_used(tcx, def_id); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index a649e7d67af..bac876b1cbb 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -321,23 +321,6 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { intravisit::walk_expr(self, expr); } - /// Don't call `type_of` on opaque types, since that depends on type checking function bodies. - /// `check_item_type` ensures that it's called instead. - fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) { - let def_id = opaque.def_id; - self.tcx.ensure_ok().generics_of(def_id); - self.tcx.ensure_ok().predicates_of(def_id); - self.tcx.ensure_ok().explicit_item_bounds(def_id); - self.tcx.ensure_ok().explicit_item_self_bounds(def_id); - self.tcx.ensure_ok().item_bounds(def_id); - self.tcx.ensure_ok().item_self_bounds(def_id); - if self.tcx.is_conditionally_const(def_id) { - self.tcx.ensure_ok().explicit_implied_const_bounds(def_id); - self.tcx.ensure_ok().const_conditions(def_id); - } - intravisit::walk_opaque_ty(self, opaque); - } - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { lower_trait_item(self.tcx, trait_item.trait_item_id()); intravisit::walk_trait_item(self, trait_item); diff --git a/tests/ui/associated-inherent-types/issue-109299-1.stderr b/tests/ui/associated-inherent-types/issue-109299-1.stderr index 940ccd7e400..6bc7a539680 100644 --- a/tests/ui/associated-inherent-types/issue-109299-1.stderr +++ b/tests/ui/associated-inherent-types/issue-109299-1.stderr @@ -1,3 +1,11 @@ +error: unconstrained opaque type + --> $DIR/issue-109299-1.rs:10:10 + | +LL | type X = impl for Fn() -> Lexer::Cursor; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `X` must be used in combination with a concrete type within the same crate + error[E0220]: associated type `Cursor` not found for `Lexer` in the current scope --> $DIR/issue-109299-1.rs:10:40 | @@ -23,14 +31,6 @@ LL | type X = impl for Fn() -> Lexer::Cursor; - `Lexer` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: unconstrained opaque type - --> $DIR/issue-109299-1.rs:10:10 - | -LL | type X = impl for Fn() -> Lexer::Cursor; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `X` must be used in combination with a concrete type within the same crate - error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-type-bounds/duplicate.stderr b/tests/ui/associated-type-bounds/duplicate.stderr index 1ce212a9ff3..68fbb345f6f 100644 --- a/tests/ui/associated-type-bounds/duplicate.stderr +++ b/tests/ui/associated-type-bounds/duplicate.stderr @@ -198,16 +198,6 @@ LL | fn FRPIT1() -> impl Iterator { | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:133:42 - | -LL | fn FRPIT1() -> impl Iterator { - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified --> $DIR/duplicate.rs:139:42 | @@ -216,24 +206,6 @@ LL | fn FRPIT2() -> impl Iterator { | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:139:42 - | -LL | fn FRPIT2() -> impl Iterator { - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:145:45 - | -LL | fn FRPIT3() -> impl Iterator { - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified --> $DIR/duplicate.rs:145:45 | @@ -241,8 +213,6 @@ LL | fn FRPIT3() -> impl Iterator { | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified --> $DIR/duplicate.rs:151:40 @@ -340,60 +310,6 @@ LL | type ETAI3> = impl Copy; | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:189:40 - | -LL | type ETAI4 = impl Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:189:40 - | -LL | type ETAI4 = impl Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:193:40 - | -LL | type ETAI5 = impl Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:193:40 - | -LL | type ETAI5 = impl Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:197:43 - | -LL | type ETAI6 = impl Iterator; - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:197:43 - | -LL | type ETAI6 = impl Iterator; - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified --> $DIR/duplicate.rs:202:36 | @@ -664,6 +580,16 @@ LL | type A: Iterator; | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:133:42 + | +LL | fn FRPIT1() -> impl Iterator { + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0282]: type annotations needed --> $DIR/duplicate.rs:136:5 | @@ -675,6 +601,16 @@ help: consider specifying the generic argument LL | iter::empty::() | +++++ +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:139:42 + | +LL | fn FRPIT2() -> impl Iterator { + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0282]: type annotations needed --> $DIR/duplicate.rs:142:5 | @@ -686,6 +622,16 @@ help: consider specifying the generic argument LL | iter::empty::() | +++++ +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:145:45 + | +LL | fn FRPIT3() -> impl Iterator { + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0282]: type annotations needed --> $DIR/duplicate.rs:148:5 | @@ -729,6 +675,24 @@ LL | type ETAI4 = impl Iterator; | = note: `ETAI4` must be used in combination with a concrete type within the same crate +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:189:40 + | +LL | type ETAI4 = impl Iterator; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:189:40 + | +LL | type ETAI4 = impl Iterator; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: unconstrained opaque type --> $DIR/duplicate.rs:193:14 | @@ -737,6 +701,24 @@ LL | type ETAI5 = impl Iterator; | = note: `ETAI5` must be used in combination with a concrete type within the same crate +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:193:40 + | +LL | type ETAI5 = impl Iterator; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:193:40 + | +LL | type ETAI5 = impl Iterator; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: unconstrained opaque type --> $DIR/duplicate.rs:197:14 | @@ -745,6 +727,24 @@ LL | type ETAI6 = impl Iterator; | = note: `ETAI6` must be used in combination with a concrete type within the same crate +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:197:43 + | +LL | type ETAI6 = impl Iterator; + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:197:43 + | +LL | type ETAI6 = impl Iterator; + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: aborting due to 87 previous errors Some errors have detailed explanations: E0282, E0719. diff --git a/tests/ui/query-system/issue-83479.rs b/tests/ui/query-system/issue-83479.rs index 32676dfe9c8..94ceccf49f4 100644 --- a/tests/ui/query-system/issue-83479.rs +++ b/tests/ui/query-system/issue-83479.rs @@ -8,6 +8,7 @@ type PairCoupledTypes: Trait< }], > = impl Trait< //~^ ERROR: cannot find trait `Trait` in this scope + //~| ERROR: unconstrained opaque type [u32; { static FOO: usize; //~ ERROR: free static item without body }], diff --git a/tests/ui/query-system/issue-83479.stderr b/tests/ui/query-system/issue-83479.stderr index 7cb41f5cbe5..79764d01b3b 100644 --- a/tests/ui/query-system/issue-83479.stderr +++ b/tests/ui/query-system/issue-83479.stderr @@ -20,7 +20,7 @@ LL | static FOO: usize; | help: provide a definition for the static: `= ;` error: free static item without body - --> $DIR/issue-83479.rs:12:9 + --> $DIR/issue-83479.rs:13:9 | LL | static FOO: usize; | ^^^^^^^^^^^^^^^^^- @@ -39,6 +39,21 @@ error[E0405]: cannot find trait `Trait` in this scope LL | > = impl Trait< | ^^^^^ not found in this scope -error: aborting due to 5 previous errors +error: unconstrained opaque type + --> $DIR/issue-83479.rs:9:5 + | +LL | > = impl Trait< + | _____^ +LL | | +LL | | +LL | | [u32; { +LL | | static FOO: usize; +LL | | }], +LL | | >; + | |_^ + | + = note: `PairCoupledTypes` must be used in combination with a concrete type within the same crate + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0405`. diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr index a22d88b7c59..eedaae43f9a 100644 --- a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr +++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr @@ -48,23 +48,6 @@ help: replace the generic bound with the associated type LL | fn func>(t: T) -> impl Trait<(), Assoc = i32> { | +++++++ -error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:19:46 - | -LL | fn func>(t: T) -> impl Trait<(), i32> { - | ^^^^^ expected 1 generic argument - | -note: trait defined here, with 1 generic parameter: `T` - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11 - | -LL | pub trait Trait { - | ^^^^^ - - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: replace the generic bound with the associated type - | -LL | fn func>(t: T) -> impl Trait<(), Assoc = i32> { - | +++++++ - error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:26:18 | @@ -127,6 +110,23 @@ note: struct defined here, with 1 generic parameter: `T` LL | struct Struct> { | ^^^^^^ - +error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:19:46 + | +LL | fn func>(t: T) -> impl Trait<(), i32> { + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11 + | +LL | pub trait Trait { + | ^^^^^ - + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: replace the generic bound with the associated type + | +LL | fn func>(t: T) -> impl Trait<(), Assoc = i32> { + | +++++++ + error: aborting due to 9 previous errors Some errors have detailed explanations: E0107, E0207. diff --git a/tests/ui/traits/const-traits/const-impl-trait.stderr b/tests/ui/traits/const-traits/const-impl-trait.stderr index 27d7957c001..6783cec3960 100644 --- a/tests/ui/traits/const-traits/const-impl-trait.stderr +++ b/tests/ui/traits/const-traits/const-impl-trait.stderr @@ -33,13 +33,14 @@ note: `PartialEq` can't be used with `~const` because it isn't annotated with `# --> $SRC_DIR/core/src/cmp.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:17:11 + --> $DIR/const-impl-trait.rs:16:13 | -LL | ) -> impl ~const PartialEq + ~const Destruct { - | ^^^^^^ can't be applied to `PartialEq` +LL | x: impl ~const PartialEq + ~const Destruct, + | ^^^^^^ can't be applied to `PartialEq` | note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` --> $SRC_DIR/core/src/cmp.rs:LL:COL + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-impl-trait.rs:17:11 @@ -49,7 +50,6 @@ LL | ) -> impl ~const PartialEq + ~const Destruct { | note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-impl-trait.rs:17:11 @@ -62,32 +62,32 @@ note: `PartialEq` can't be used with `~const` because it isn't annotated with `# = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:16:13 + --> $DIR/const-impl-trait.rs:23:22 | -LL | x: impl ~const PartialEq + ~const Destruct, - | ^^^^^^ can't be applied to `PartialEq` +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^ can't be applied to `PartialEq` | note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:23:22 + --> $DIR/const-impl-trait.rs:27:22 | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { | ^^^^^^ can't be applied to `PartialEq` | note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` --> $SRC_DIR/core/src/cmp.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:27:22 + --> $DIR/const-impl-trait.rs:17:11 | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { - | ^^^^^^ can't be applied to `PartialEq` +LL | ) -> impl ~const PartialEq + ~const Destruct { + | ^^^^^^ can't be applied to `PartialEq` | note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` --> $SRC_DIR/core/src/cmp.rs:LL:COL + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-impl-trait.rs:27:22 -- cgit 1.4.1-3-g733a5 From 3667dbd5f9480bcf114a06d1093385a77211085d Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 3 Jun 2025 13:53:42 +0530 Subject: correct the imports in flags, tests and download --- src/bootstrap/src/core/config/flags.rs | 3 ++- src/bootstrap/src/core/config/mod.rs | 2 +- src/bootstrap/src/core/config/tests.rs | 6 ++++-- src/bootstrap/src/core/download.rs | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 08bd87e03a1..1e7197be4bd 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -12,7 +12,8 @@ use tracing::instrument; use crate::core::build_steps::perf::PerfArgs; use crate::core::build_steps::setup::Profile; use crate::core::builder::{Builder, Kind}; -use crate::core::config::{Config, TargetSelectionList, target_selection_list}; +use crate::core::config::Config; +use crate::core::config::target_selection::{TargetSelectionList, target_selection_list}; use crate::{Build, DocTests}; #[derive(Copy, Clone, Default, Debug, ValueEnum)] diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 8fe7b53068b..f39e7b02ccc 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -347,7 +347,7 @@ impl std::str::FromStr for SplitDebuginfo { } } -/// Describes how to handle conflicts in merging two [`TomlConfig`] +/// Describes how to handle conflicts in merging two `TomlConfig` #[derive(Copy, Clone, Debug)] pub enum ReplaceOpt { /// Silently ignore a duplicated value diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 96ac8a6d52f..50eba12aba7 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -10,12 +10,14 @@ use clap::CommandFactory; use serde::Deserialize; use super::flags::Flags; -use super::{ChangeIdWrapper, Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS}; +use super::toml::change_id::ChangeIdWrapper; +use super::{Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS}; use crate::ChangeId; use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order}; use crate::core::build_steps::llvm; use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS; -use crate::core::config::{LldMode, Target, TargetSelection, TomlConfig}; +use crate::core::config::toml::TomlConfig; +use crate::core::config::{LldMode, Target, TargetSelection}; use crate::utils::tests::git::git_test; pub(crate) fn parse(config: &str) -> Config { diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index d942334d1c3..ba00b405c61 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -727,7 +727,7 @@ download-rustc = false use build_helper::git::PathFreshness; use crate::core::build_steps::llvm::detect_llvm_freshness; - use crate::core::config::check_incompatible_options_for_ci_llvm; + use crate::core::config::toml::llvm::check_incompatible_options_for_ci_llvm; if !self.llvm_from_ci { return; -- cgit 1.4.1-3-g733a5 From b1acf6217ab47227a7401d2305315adc014e0664 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Thu, 5 Jun 2025 13:13:59 +0200 Subject: Check documentation of bootstrap in PR CI --- src/ci/docker/host-x86_64/mingw-check-2/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile index 11a66a1c013..a1d04bd984c 100644 --- a/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile @@ -30,6 +30,7 @@ ENV SCRIPT \ python3 ../x.py check && \ python3 ../x.py clippy ci && \ python3 ../x.py test --stage 1 core alloc std test proc_macro && \ + python3 ../x.py doc --stage 0 bootstrap && \ # Build both public and internal documentation. RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 compiler && \ RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 1 library && \ -- cgit 1.4.1-3-g733a5 From 91ad4bf08784916edfb4e498c3749bed76b0686a Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Thu, 5 Jun 2025 11:33:38 +0000 Subject: jsondocck: Explain what `KNOWN_DIRECTIVE_NAMES` is doing --- src/tools/jsondocck/src/directive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/jsondocck/src/directive.rs b/src/tools/jsondocck/src/directive.rs index 5269ffb469f..fdb2fa6dbbe 100644 --- a/src/tools/jsondocck/src/directive.rs +++ b/src/tools/jsondocck/src/directive.rs @@ -105,7 +105,7 @@ impl DirectiveKind { [_path, value] => Self::HasNotValue { value: value.clone() }, _ => panic!("`//@ !has` must have 2 or 3 arguments, but got {args:?}"), }, - + // Ignore compiletest directives, like //@ edition (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&directive_name) => { return None; } -- cgit 1.4.1-3-g733a5 From f8e9778eb12573eabac183f5d617e1a7404505c7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 9 May 2025 20:37:06 +0000 Subject: Make #[used(linker)] the default on ELF too #[used] currently is an alias for #[used(linker)] on all platforms except ELF based ones where it is an alias for #[used(compiler)]. The latter has surprising behavior and the LLVM LangRef explicitly states that it "should only be used in rare circumstances, and should not be exposed to source languages." The reason #[used] still was an alias to #[used(compiler)] on ELF is because the gold linker has issues with it. Luckily gold has been deprecated with GCC 15 and seems to be unable to bootstrap rustc anyway. As such we shouldn't really care about supporting gold. --- compiler/rustc_codegen_llvm/src/consts.rs | 12 ++++----- compiler/rustc_codegen_ssa/src/back/link.rs | 5 ++-- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 33 +++---------------------- 3 files changed, 13 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index fe2f2027327..866696276e1 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -541,12 +541,12 @@ impl<'ll> CodegenCx<'ll, '_> { // in the handling of `.init_array` (the static constructor list) in versions of // the gold linker (prior to the one released with binutils 2.36). // - // That said, we only ever emit these when compiling for ELF targets, unless - // `#[used(compiler)]` is explicitly requested. This is to avoid similar breakage - // on other targets, in particular MachO targets have *their* static constructor - // lists broken if `llvm.compiler.used` is emitted rather than `llvm.used`. However, - // that check happens when assigning the `CodegenFnAttrFlags` in - // `rustc_hir_analysis`, so we don't need to take care of it here. + // That said, we only ever emit these when `#[used(compiler)]` is explicitly + // requested. This is to avoid similar breakage on other targets, in particular + // MachO targets have *their* static constructor lists broken if `llvm.compiler.used` + // is emitted rather than `llvm.used`. However, that check happens when assigning + // the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to + // take care of it here. self.add_compiler_used_global(g); } if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index c5792da2678..30128c4bea2 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1986,7 +1986,7 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor /// This method creates a synthetic object file, which contains undefined references to all symbols /// that are necessary for the linking. They are only present in symbol table but not actually /// used in any sections, so the linker will therefore pick relevant rlibs for linking, but -/// unused `#[no_mangle]` or `#[used]` can still be discard by GC sections. +/// unused `#[no_mangle]` or `#[used(compiler)]` can still be discard by GC sections. /// /// There's a few internal crates in the standard library (aka libcore and /// libstd) which actually have a circular dependence upon one another. This @@ -2020,7 +2020,8 @@ fn add_linked_symbol_object( if file.format() == object::BinaryFormat::MachO { // Divide up the sections into sub-sections via symbols for dead code stripping. - // Without this flag, unused `#[no_mangle]` or `#[used]` cannot be discard on MachO targets. + // Without this flag, unused `#[no_mangle]` or `#[used(compiler)]` cannot be + // discard on MachO targets. file.set_subsections_via_symbols(); } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 4bcafa3be36..0b31fa8fa88 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -195,35 +195,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span() }); } None => { - // Unfortunately, unconditionally using `llvm.used` causes - // issues in handling `.init_array` with the gold linker, - // but using `llvm.compiler.used` caused a nontrivial amount - // of unintentional ecosystem breakage -- particularly on - // Mach-O targets. - // - // As a result, we emit `llvm.compiler.used` only on ELF - // targets. This is somewhat ad-hoc, but actually follows - // our pre-LLVM 13 behavior (prior to the ecosystem - // breakage), and seems to match `clang`'s behavior as well - // (both before and after LLVM 13), possibly because they - // have similar compatibility concerns to us. See - // https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146 - // and following comments for some discussion of this, as - // well as the comments in `rustc_codegen_llvm` where these - // flags are handled. - // - // Anyway, to be clear: this is still up in the air - // somewhat, and is subject to change in the future (which - // is a good thing, because this would ideally be a bit - // more firmed up). - let is_like_elf = !(tcx.sess.target.is_like_darwin - || tcx.sess.target.is_like_windows - || tcx.sess.target.is_like_wasm); - codegen_fn_attrs.flags |= if is_like_elf { - CodegenFnAttrFlags::USED_COMPILER - } else { - CodegenFnAttrFlags::USED_LINKER - }; + // Unconditionally using `llvm.used` causes issues in handling + // `.init_array` with the gold linker. Luckily gold has been + // deprecated with GCC 15 and rustc now warns about using gold. + codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER } } } -- cgit 1.4.1-3-g733a5 From 9949ea73c16e2de911ece49d3fceb649a6c11ef0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 5 Jun 2025 10:26:30 +0000 Subject: Move generic arg checks from the hir item types visitor to ty wfcheck --- compiler/rustc_hir_analysis/src/check/check.rs | 24 +++++++++++++++++++++++- compiler/rustc_hir_analysis/src/collect.rs | 23 ----------------------- tests/crashes/121429.rs | 14 -------------- 3 files changed, 23 insertions(+), 38 deletions(-) delete mode 100644 tests/crashes/121429.rs diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a1210fe6d52..6a2d353dbbb 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -702,6 +702,29 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) { } pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { + let generics = tcx.generics_of(def_id); + + for param in &generics.own_params { + match param.kind { + ty::GenericParamDefKind::Lifetime { .. } => {} + ty::GenericParamDefKind::Type { has_default, .. } => { + if has_default { + tcx.ensure_ok().type_of(param.def_id); + } + } + ty::GenericParamDefKind::Const { has_default, .. } => { + tcx.ensure_ok().type_of(param.def_id); + if has_default { + // need to store default and type of default + let ct = tcx.const_param_default(param.def_id).skip_binder(); + if let ty::ConstKind::Unevaluated(uv) = ct.kind() { + tcx.ensure_ok().type_of(uv.def); + } + } + } + } + } + match tcx.def_kind(def_id) { DefKind::Static { .. } => { check_static_inhabited(tcx, def_id); @@ -771,7 +794,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_opaque(tcx, def_id); } - tcx.ensure_ok().generics_of(def_id); tcx.ensure_ok().predicates_of(def_id); tcx.ensure_ok().explicit_item_bounds(def_id); tcx.ensure_ok().explicit_item_self_bounds(def_id); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index bac876b1cbb..bab8732f0b1 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -287,29 +287,6 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { intravisit::walk_item(self, item); } - fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { - for param in generics.params { - match param.kind { - hir::GenericParamKind::Lifetime { .. } => {} - hir::GenericParamKind::Type { default: Some(_), .. } => { - self.tcx.ensure_ok().type_of(param.def_id); - } - hir::GenericParamKind::Type { .. } => {} - hir::GenericParamKind::Const { default, .. } => { - self.tcx.ensure_ok().type_of(param.def_id); - if let Some(default) = default { - // need to store default and type of default - self.tcx.ensure_ok().const_param_default(param.def_id); - if let hir::ConstArgKind::Anon(ac) = default.kind { - self.tcx.ensure_ok().type_of(ac.def_id); - } - } - } - } - } - intravisit::walk_generics(self, generics); - } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { if let hir::ExprKind::Closure(closure) = expr.kind { self.tcx.ensure_ok().generics_of(closure.def_id); diff --git a/tests/crashes/121429.rs b/tests/crashes/121429.rs deleted file mode 100644 index e407754db5c..00000000000 --- a/tests/crashes/121429.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ known-bug: #121429 - -#![feature(generic_const_exprs)] - -struct FixedI8; -const FRAC_LHS: usize = 0; -const FRAC_RHS: usize = 1; - -pub trait True {} - -impl PartialEq> for FixedI8 where - If<{}>: True -{ -} -- cgit 1.4.1-3-g733a5 From c83bd8b5f3207b25207408be24fc940afc3d8c24 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 5 Jun 2025 10:33:13 +0000 Subject: wfcheck closures --- compiler/rustc_hir_analysis/src/check/check.rs | 9 +++++++++ compiler/rustc_hir_analysis/src/check/wfcheck.rs | 5 ++++- compiler/rustc_hir_analysis/src/collect.rs | 11 ----------- compiler/rustc_middle/src/hir/mod.rs | 9 +++++++++ 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 6a2d353dbbb..bcf0353498e 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -860,6 +860,15 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { } } } + DefKind::Closure => { + // This is guaranteed to be called by metadata encoding, + // we still call it in wfcheck eagerly to ensure errors in codegen + // attrs prevent lints from spamming the output. + tcx.ensure_ok().codegen_fn_attrs(def_id); + // We do not call `type_of` for closures here as that + // depends on typecheck and would therefore hide + // any further errors in case one typeck fails. + } _ => {} } } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 3e872607e31..91486a1a0e4 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -195,7 +195,9 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua hir::Node::TraitItem(item) => check_trait_item(tcx, item), hir::Node::ImplItem(item) => check_impl_item(tcx, item), hir::Node::ForeignItem(item) => check_foreign_item(tcx, item), - hir::Node::OpaqueTy(_) => Ok(crate::check::check::check_item_type(tcx, def_id)), + hir::Node::ConstBlock(_) | hir::Node::Expr(_) | hir::Node::OpaqueTy(_) => { + Ok(crate::check::check::check_item_type(tcx, def_id)) + } _ => unreachable!("{node:?}"), }; @@ -2411,6 +2413,7 @@ fn check_type_wf(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuaranteed> { .and( items.par_foreign_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)), ) + .and(items.par_nested_bodies(|item| tcx.ensure_ok().check_well_formed(item))) .and(items.par_opaques(|item| tcx.ensure_ok().check_well_formed(item))); super::entry::check_for_entry_fn(tcx); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index bab8732f0b1..e2ef7b90ff4 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -287,17 +287,6 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { intravisit::walk_item(self, item); } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Closure(closure) = expr.kind { - self.tcx.ensure_ok().generics_of(closure.def_id); - self.tcx.ensure_ok().codegen_fn_attrs(closure.def_id); - // We do not call `type_of` for closures here as that - // depends on typecheck and would therefore hide - // any further errors in case one typeck fails. - } - intravisit::walk_expr(self, expr); - } - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { lower_trait_item(self.tcx, trait_item.trait_item_id()); intravisit::walk_trait_item(self, trait_item); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index a28dcb0cb8e..d1f5caaafb2 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -71,6 +71,7 @@ impl ModuleItems { self.opaques.iter().copied() } + /// Closures and inline consts pub fn nested_bodies(&self) -> impl Iterator { self.nested_bodies.iter().copied() } @@ -79,6 +80,14 @@ impl ModuleItems { self.owners().map(|id| id.def_id) } + /// Closures and inline consts + pub fn par_nested_bodies( + &self, + f: impl Fn(LocalDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, + ) -> Result<(), ErrorGuaranteed> { + try_par_for_each_in(&self.nested_bodies[..], |&&id| f(id)) + } + pub fn par_items( &self, f: impl Fn(ItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, -- cgit 1.4.1-3-g733a5 From fa282f4928f88060159f8599106c055ba0c94a19 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 5 Jun 2025 10:52:24 +0000 Subject: Remove CollectItemTypesVisitor --- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 10 +++--- compiler/rustc_hir_analysis/src/collect.rs | 39 +++--------------------- 2 files changed, 9 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 91486a1a0e4..00316682df8 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -40,7 +40,6 @@ use tracing::{debug, instrument}; use {rustc_ast as ast, rustc_hir as hir}; use crate::autoderef::Autoderef; -use crate::collect::CollectItemTypesVisitor; use crate::constrained_generic_params::{Parameter, identify_constrained_generic_params}; use crate::errors::InvalidReceiverTyHint; use crate::{errors, fluent_generated as fluent}; @@ -231,7 +230,8 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() ?item.owner_id, item.name = ? tcx.def_path_str(def_id) ); - CollectItemTypesVisitor { tcx }.visit_item(item); + crate::collect::lower_item(tcx, item.item_id()); + crate::collect::reject_placeholder_type_signatures_in_item(tcx, item); let res = match item.kind { // Right now we check that every default trait implementation @@ -352,8 +352,6 @@ fn check_foreign_item<'tcx>( ) -> Result<(), ErrorGuaranteed> { let def_id = item.owner_id.def_id; - CollectItemTypesVisitor { tcx }.visit_foreign_item(item); - debug!( ?item.owner_id, item.name = ? tcx.def_path_str(def_id) @@ -376,7 +374,7 @@ fn check_trait_item<'tcx>( ) -> Result<(), ErrorGuaranteed> { let def_id = trait_item.owner_id.def_id; - CollectItemTypesVisitor { tcx }.visit_trait_item(trait_item); + crate::collect::lower_trait_item(tcx, trait_item.trait_item_id()); let (method_sig, span) = match trait_item.kind { hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span), @@ -941,7 +939,7 @@ fn check_impl_item<'tcx>( tcx: TyCtxt<'tcx>, impl_item: &'tcx hir::ImplItem<'tcx>, ) -> Result<(), ErrorGuaranteed> { - CollectItemTypesVisitor { tcx }.visit_impl_item(impl_item); + crate::collect::lower_impl_item(tcx, impl_item.impl_item_id()); let (method_sig, span) = match impl_item.kind { hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span), diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e2ef7b90ff4..e1df0d60452 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -28,11 +28,10 @@ use rustc_errors::{ }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt, walk_generics}; +use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_generics}; use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgKind}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause}; -use rustc_middle::hir::nested_filter; use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode, fold_regions}; @@ -148,10 +147,6 @@ impl<'v> Visitor<'v> for HirPlaceholderCollector { } } -pub(crate) struct CollectItemTypesVisitor<'tcx> { - pub tcx: TyCtxt<'tcx>, -} - /// If there are any placeholder types (`_`), emit an error explaining that this is not allowed /// and suggest adding type parameters in the appropriate place, taking into consideration any and /// all already existing generic type parameters to avoid suggesting a name that is already in use. @@ -243,7 +238,7 @@ pub(crate) fn placeholder_type_error_diag<'cx, 'tcx>( err } -fn reject_placeholder_type_signatures_in_item<'tcx>( +pub(super) fn reject_placeholder_type_signatures_in_item<'tcx>( tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>, ) { @@ -274,30 +269,6 @@ fn reject_placeholder_type_signatures_in_item<'tcx>( ); } -impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { - type NestedFilter = nested_filter::OnlyBodies; - - fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { - self.tcx - } - - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - lower_item(self.tcx, item.item_id()); - reject_placeholder_type_signatures_in_item(self.tcx, item); - intravisit::walk_item(self, item); - } - - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { - lower_trait_item(self.tcx, trait_item.trait_item_id()); - intravisit::walk_trait_item(self, trait_item); - } - - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { - lower_impl_item(self.tcx, impl_item.impl_item_id()); - intravisit::walk_impl_item(self, impl_item); - } -} - /////////////////////////////////////////////////////////////////////////// // Utility types and common code for the above passes. @@ -618,7 +589,7 @@ fn get_new_lifetime_name<'tcx>( } #[instrument(level = "debug", skip_all)] -fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { +pub(super) fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { let it = tcx.hir_item(item_id); debug!(item = ?it.kind.ident(), id = %it.hir_id()); let def_id = item_id.owner_id.def_id; @@ -739,7 +710,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { } } -fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { +pub(crate) fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { let trait_item = tcx.hir_trait_item(trait_item_id); let def_id = trait_item_id.owner_id; tcx.ensure_ok().generics_of(def_id); @@ -810,7 +781,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { tcx.ensure_ok().predicates_of(def_id); } -fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { +pub(super) fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { let def_id = impl_item_id.owner_id; tcx.ensure_ok().generics_of(def_id); tcx.ensure_ok().type_of(def_id); -- cgit 1.4.1-3-g733a5 From 91b77e080fbb8f48d5cdd0807f32689b4e8a90e4 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 5 Jun 2025 13:47:21 +0000 Subject: use helper macro for flat_map vs visit_list, initial dedups --- compiler/rustc_ast/src/mut_visit.rs | 98 +++++------------- compiler/rustc_ast/src/visit.rs | 194 +++++++++++++++++++++--------------- 2 files changed, 139 insertions(+), 153 deletions(-) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 08726ee6b41..bb95a23c863 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -211,10 +211,6 @@ pub trait MutVisitor: Sized { walk_ident(self, i); } - fn visit_modifiers(&mut self, m: &mut TraitBoundModifiers) { - walk_modifiers(self, m); - } - fn visit_path(&mut self, p: &mut Path) { walk_path(self, p); } @@ -367,6 +363,28 @@ pub trait MutVisitor: Sized { super::common_visitor_and_walkers!((mut) MutVisitor); +macro_rules! generate_flat_map_visitor_fns { + ($($name:ident, $Ty:ty, $flat_map_fn:ident;)+) => { + $( + fn $name( + vis: &mut V, + values: &mut ThinVec<$Ty>, + ) { + values.flat_map_in_place(|value| vis.$flat_map_fn(value)); + } + )+ + } +} + +generate_flat_map_visitor_fns! { + visit_items, P, flat_map_item; + visit_foreign_items, P, flat_map_foreign_item; + visit_generic_params, GenericParam, flat_map_generic_param; + visit_stmts, Stmt, flat_map_stmt; + visit_exprs, P, filter_map_expr; + visit_pat_fields, PatField, flat_map_pat_field; +} + #[inline] fn visit_vec(elems: &mut Vec, mut visit_elem: F) where @@ -403,15 +421,6 @@ fn visit_attrs(vis: &mut T, attrs: &mut AttrVec) { } } -#[allow(unused)] -fn visit_exprs(vis: &mut T, exprs: &mut Vec>) { - exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr)) -} - -fn visit_thin_exprs(vis: &mut T, exprs: &mut ThinVec>) { - exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr)) -} - fn visit_attr_args(vis: &mut T, args: &mut AttrArgs) { match args { AttrArgs::Empty => {} @@ -583,27 +592,6 @@ fn walk_parenthesized_parameter_data(vis: &mut T, args: &mut Pare vis.visit_span(inputs_span); } -fn walk_local(vis: &mut T, local: &mut Local) { - let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens: _ } = local; - visit_opt(super_, |sp| vis.visit_span(sp)); - vis.visit_id(id); - visit_attrs(vis, attrs); - vis.visit_pat(pat); - visit_opt(ty, |ty| vis.visit_ty(ty)); - match kind { - LocalKind::Decl => {} - LocalKind::Init(init) => { - vis.visit_expr(init); - } - LocalKind::InitElse(init, els) => { - vis.visit_expr(init); - vis.visit_block(els); - } - } - visit_opt(colon_sp, |sp| vis.visit_span(sp)); - vis.visit_span(span); -} - fn walk_attribute(vis: &mut T, attr: &mut Attribute) { let Attribute { kind, id: _, style: _, span } = attr; match kind { @@ -858,30 +846,6 @@ fn walk_trait_ref(vis: &mut T, TraitRef { path, ref_id }: &mut Tr vis.visit_path(path); } -fn walk_poly_trait_ref(vis: &mut T, p: &mut PolyTraitRef) { - let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span } = p; - vis.visit_modifiers(modifiers); - bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - vis.visit_trait_ref(trait_ref); - vis.visit_span(span); -} - -fn walk_modifiers(vis: &mut V, m: &mut TraitBoundModifiers) { - let TraitBoundModifiers { constness, asyncness, polarity } = m; - match constness { - BoundConstness::Never => {} - BoundConstness::Always(span) | BoundConstness::Maybe(span) => vis.visit_span(span), - } - match asyncness { - BoundAsyncness::Normal => {} - BoundAsyncness::Async(span) => vis.visit_span(span), - } - match polarity { - BoundPolarity::Positive => {} - BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => vis.visit_span(span), - } -} - pub fn walk_field_def(visitor: &mut T, fd: &mut FieldDef) { let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety, default } = fd; visitor.visit_id(id); @@ -930,16 +894,6 @@ pub fn walk_item_kind( kind.walk(span, id, visibility, ctxt, vis) } -pub fn walk_crate(vis: &mut T, krate: &mut Crate) { - let Crate { attrs, items, spans, id, is_placeholder: _ } = krate; - vis.visit_id(id); - visit_attrs(vis, attrs); - items.flat_map_in_place(|item| vis.flat_map_item(item)); - let ModSpans { inner_span, inject_use_span } = spans; - vis.visit_span(inner_span); - vis.visit_span(inject_use_span); -} - pub fn walk_flat_map_item(vis: &mut impl MutVisitor, mut item: P) -> SmallVec<[P; 1]> { vis.visit_item(&mut item); smallvec![item] @@ -1021,7 +975,7 @@ pub fn walk_expr(vis: &mut T, Expr { kind, id, span, attrs, token vis.visit_id(id); visit_attrs(vis, attrs); match kind { - ExprKind::Array(exprs) => visit_thin_exprs(vis, exprs), + ExprKind::Array(exprs) => visit_exprs(vis, exprs), ExprKind::ConstBlock(anon_const) => { vis.visit_anon_const(anon_const); } @@ -1029,10 +983,10 @@ pub fn walk_expr(vis: &mut T, Expr { kind, id, span, attrs, token vis.visit_expr(expr); vis.visit_anon_const(count); } - ExprKind::Tup(exprs) => visit_thin_exprs(vis, exprs), + ExprKind::Tup(exprs) => visit_exprs(vis, exprs), ExprKind::Call(f, args) => { vis.visit_expr(f); - visit_thin_exprs(vis, args); + visit_exprs(vis, args); } ExprKind::MethodCall(box MethodCall { seg: PathSegment { ident, id, args: seg_args }, @@ -1044,7 +998,7 @@ pub fn walk_expr(vis: &mut T, Expr { kind, id, span, attrs, token vis.visit_id(id); vis.visit_ident(ident); visit_opt(seg_args, |args| vis.visit_generic_args(args)); - visit_thin_exprs(vis, call_args); + visit_exprs(vis, call_args); vis.visit_span(span); } ExprKind::Binary(binop, lhs, rhs) => { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 1f7c97380dc..82c58a72be3 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -378,13 +378,39 @@ macro_rules! common_visitor_and_walkers { } } - fn visit_polarity<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, polarity: &$($lt)? $($mut)? ImplPolarity) $(-> >::Result)? { + fn visit_polarity<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + polarity: &$($lt)? $($mut)? ImplPolarity, + ) $(-> >::Result)? { match polarity { ImplPolarity::Positive => { $(>::Result::output())? } ImplPolarity::Negative(span) => visit_span(vis, span), } } + $(${ignore($lt)} + #[inline] + )? + fn visit_modifiers<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + m: &$($lt)? $($mut)? TraitBoundModifiers + ) $(-> >::Result)? { + let TraitBoundModifiers { constness, asyncness, polarity } = m; + match constness { + BoundConstness::Never => {} + BoundConstness::Always(span) | BoundConstness::Maybe(span) => try_visit!(visit_span(vis, span)), + } + match asyncness { + BoundAsyncness::Normal => {} + BoundAsyncness::Async(span) => try_visit!(visit_span(vis, span)), + } + match polarity { + BoundPolarity::Positive => {} + BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => try_visit!(visit_span(vis, span)), + } + $(>::Result::output())? + } + fn visit_bounds<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, bounds: &$($lt)? $($mut)? GenericBounds, ctxt: BoundKind) $(-> >::Result)? { walk_list!(visitor, visit_param_bound, bounds, ctxt); $(>::Result::output())? @@ -478,12 +504,7 @@ macro_rules! common_visitor_and_walkers { ModSpans { inner_span, inject_use_span }, _, ) => { - $(${ignore($mut)} - items.flat_map_in_place(|item| vis.flat_map_item(item)); - )? - $(${ignore($lt)} - walk_list!(vis, visit_item, items); - )? + try_visit!(visit_items(vis, items)); try_visit!(visit_span(vis, inner_span)); try_visit!(visit_span(vis, inject_use_span)); } @@ -616,7 +637,10 @@ macro_rules! common_visitor_and_walkers { } } - fn walk_const_item<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, item: &$($lt)? $($mut)? ConstItem) $(-> >::Result)? { + fn walk_const_item<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + item: &$($lt)? $($mut)? ConstItem, + ) $(-> >::Result)? { let ConstItem { defaultness, ident, generics, ty, expr, define_opaque } = item; try_visit!(visit_defaultness(vis, defaultness)); try_visit!(vis.visit_ident(ident)); @@ -629,13 +653,7 @@ macro_rules! common_visitor_and_walkers { fn walk_foreign_mod<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, foreign_mod: &$($lt)? $($mut)? ForeignMod) $(-> >::Result)? { let ForeignMod { extern_span: _, safety, abi: _, items } = foreign_mod; try_visit!(visit_safety(vis, safety)); - $(${ignore($mut)} - items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); - )? - $( - walk_list!(vis, visit_foreign_item, items); - >::Result::output() - )? + visit_foreign_items(vis, items) } fn walk_define_opaques<$($lt,)? V: $Visitor$(<$lt>)?>( @@ -780,15 +798,13 @@ macro_rules! common_visitor_and_walkers { vis: &mut V, coroutine_kind: &$($lt)? $($mut)? CoroutineKind, ) $(-> >::Result)? { - match coroutine_kind { - CoroutineKind::Async { span, closure_id, return_impl_trait_id } + let (CoroutineKind::Async { span, closure_id, return_impl_trait_id } | CoroutineKind::Gen { span, closure_id, return_impl_trait_id } - | CoroutineKind::AsyncGen { span, closure_id, return_impl_trait_id } => { - try_visit!(visit_id(vis, closure_id)); - try_visit!(visit_id(vis, return_impl_trait_id)); - visit_span(vis, span) - } - } + | CoroutineKind::AsyncGen { span, closure_id, return_impl_trait_id }) + = coroutine_kind; + try_visit!(visit_id(vis, closure_id)); + try_visit!(visit_id(vis, return_impl_trait_id)); + visit_span(vis, span) } pub fn walk_pat<$($lt,)? V: $Visitor$(<$lt>)?>( @@ -817,15 +833,7 @@ macro_rules! common_visitor_and_walkers { PatKind::Struct(opt_qself, path, fields, _rest) => { try_visit!(vis.visit_qself(opt_qself)); try_visit!(vis.visit_path(path)); - - $( - ${ignore($lt)} - walk_list!(vis, visit_pat_field, fields); - )? - $( - ${ignore($mut)} - fields.flat_map_in_place(|field| vis.flat_map_pat_field(field)); - )? + try_visit!(visit_pat_fields(vis, fields)); } PatKind::Box(subpattern) | PatKind::Deref(subpattern) | PatKind::Paren(subpattern) => { try_visit!(vis.visit_pat(subpattern)); @@ -876,14 +884,7 @@ macro_rules! common_visitor_and_walkers { ) $(-> >::Result)? { let Block { stmts, id, rules: _, span, tokens: _ } = block; try_visit!(visit_id(vis, id)); - $( - ${ignore($lt)} - walk_list!(vis, visit_stmt, stmts); - )? - $( - ${ignore($mut)} - stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); - )? + try_visit!(visit_stmts(vis, stmts)); visit_span(vis, span) } @@ -911,28 +912,13 @@ macro_rules! common_visitor_and_walkers { let BareFnTy { safety, ext: _, generic_params, decl, decl_span } = &$($mut)? **function_declaration; visit_safety(vis, safety); - $( - ${ignore($lt)} - walk_list!(vis, visit_generic_param, generic_params); - )? - $( - ${ignore($mut)} - generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - )? - + try_visit!(visit_generic_params(vis, generic_params)); try_visit!(vis.visit_fn_decl(decl)); try_visit!(visit_span(vis, decl_span)); } TyKind::UnsafeBinder(binder) => { - $( - ${ignore($lt)} - walk_list!(vis, visit_generic_param, &binder.generic_params); - )? - $( - ${ignore($mut)} - binder.generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - )? - try_visit!(vis.visit_ty(&$($mut)?binder.inner_ty)); + try_visit!(visit_generic_params(vis, &$($mut)? binder.generic_params)); + try_visit!(vis.visit_ty(&$($mut)? binder.inner_ty)); } TyKind::Path(maybe_qself, path) => { try_visit!(vis.visit_qself(maybe_qself)); @@ -959,37 +945,83 @@ macro_rules! common_visitor_and_walkers { } visit_span(vis, span) } + + pub fn walk_crate<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + krate: &$($lt)? $($mut)? Crate, + ) $(-> >::Result)? { + let Crate { attrs, items, spans, id, is_placeholder: _ } = krate; + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(visit_items(vis, items)); + let ModSpans { inner_span, inject_use_span } = spans; + try_visit!(visit_span(vis, inner_span)); + visit_span(vis, inject_use_span) + } + + pub fn walk_local<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + local: &$($lt)? $($mut)? Local, + ) $(-> >::Result)? { + let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens: _ } = local; + if let Some(sp) = super_ { + try_visit!(visit_span(vis, sp)); + } + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(vis.visit_pat(pat)); + visit_opt!(vis, visit_ty, ty); + match kind { + LocalKind::Decl => {} + LocalKind::Init(init) => { + try_visit!(vis.visit_expr(init)) + } + LocalKind::InitElse(init, els) => { + try_visit!(vis.visit_expr(init)); + try_visit!(vis.visit_block(els)); + } + } + if let Some(sp) = colon_sp { + try_visit!(visit_span(vis, sp)); + } + visit_span(vis, span) + } + + fn walk_poly_trait_ref<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + p: &$($lt)? $($mut)? PolyTraitRef, + ) $(-> >::Result)? { + let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span } = p; + try_visit!(visit_modifiers(vis, modifiers)); + try_visit!(visit_generic_params(vis, bound_generic_params)); + try_visit!(vis.visit_trait_ref(trait_ref)); + visit_span(vis, span) + } }; } common_visitor_and_walkers!(Visitor<'a>); -pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result { - let Crate { attrs, items, spans: _, id: _, is_placeholder: _ } = krate; - walk_list!(visitor, visit_attribute, attrs); - walk_list!(visitor, visit_item, items); - V::Result::output() -} - -pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::Result { - let Local { id: _, super_: _, pat, ty, kind, span: _, colon_sp: _, attrs, tokens: _ } = local; - walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_pat(pat)); - visit_opt!(visitor, visit_ty, ty); - if let Some((init, els)) = kind.init_else_opt() { - try_visit!(visitor.visit_expr(init)); - visit_opt!(visitor, visit_block, els); +macro_rules! generate_list_visit_fns { + ($($name:ident, $Ty:ty, $visit_fn:ident;)+) => { + $( + fn $name<'a, V: Visitor<'a>>( + vis: &mut V, + values: &'a ThinVec<$Ty>, + ) -> V::Result { + walk_list!(vis, $visit_fn, values); + V::Result::output() + } + )+ } - V::Result::output() } -pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) -> V::Result -where - V: Visitor<'a>, -{ - let PolyTraitRef { bound_generic_params, modifiers: _, trait_ref, span: _ } = trait_ref; - walk_list!(visitor, visit_generic_param, bound_generic_params); - visitor.visit_trait_ref(trait_ref) +generate_list_visit_fns! { + visit_items, P, visit_item; + visit_foreign_items, P, visit_foreign_item; + visit_generic_params, GenericParam, visit_generic_param; + visit_stmts, Stmt, visit_stmt; + visit_pat_fields, PatField, visit_pat_field; } pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitRef) -> V::Result { -- cgit 1.4.1-3-g733a5 From fd3da4bebdff63b7529483ff7025986ef16bf463 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 4 Jun 2025 06:26:56 +0000 Subject: Replace some `Option` with `Span` and use DUMMY_SP instead of None --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- .../src/diagnostics/conflict_errors.rs | 4 +-- compiler/rustc_borrowck/src/type_check/mod.rs | 22 +++++------- compiler/rustc_borrowck/src/universal_regions.rs | 8 ++--- compiler/rustc_codegen_cranelift/src/base.rs | 16 ++++----- .../rustc_codegen_cranelift/src/intrinsics/llvm.rs | 2 +- .../src/intrinsics/llvm_aarch64.rs | 2 +- .../src/intrinsics/llvm_x86.rs | 2 +- .../rustc_codegen_cranelift/src/intrinsics/mod.rs | 6 ++-- compiler/rustc_codegen_cranelift/src/main_shim.rs | 4 +-- compiler/rustc_codegen_cranelift/src/num.rs | 2 +- compiler/rustc_codegen_cranelift/src/unsize.rs | 2 +- compiler/rustc_codegen_ssa/src/base.rs | 2 +- compiler/rustc_codegen_ssa/src/common.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 9 ++--- compiler/rustc_codegen_ssa/src/size_of_val.rs | 3 +- compiler/rustc_const_eval/src/check_consts/ops.rs | 6 +--- .../rustc_const_eval/src/check_consts/qualifs.rs | 4 +-- .../rustc_const_eval/src/const_eval/machine.rs | 2 +- compiler/rustc_const_eval/src/interpret/operand.rs | 3 +- .../rustc_const_eval/src/util/caller_location.rs | 2 +- compiler/rustc_hir_analysis/src/check/check.rs | 2 +- compiler/rustc_hir_analysis/src/check/intrinsic.rs | 8 ++--- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 20 +++++------ .../rustc_hir_analysis/src/coherence/builtin.rs | 10 +++--- .../rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 2 +- compiler/rustc_hir_typeck/src/callee.rs | 2 +- compiler/rustc_hir_typeck/src/check.rs | 4 +-- compiler/rustc_hir_typeck/src/closure.rs | 6 ++-- compiler/rustc_hir_typeck/src/coercion.rs | 5 ++- compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 6 ++-- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 5 ++- .../rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 2 +- compiler/rustc_hir_typeck/src/pat.rs | 8 ++--- compiler/rustc_hir_typeck/src/upvar.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 5 +-- compiler/rustc_middle/src/error.rs | 2 +- compiler/rustc_middle/src/middle/lang_items.rs | 2 +- compiler/rustc_middle/src/mir/statement.rs | 2 +- compiler/rustc_middle/src/ty/adjustment.rs | 4 +-- compiler/rustc_middle/src/ty/context.rs | 8 ++--- compiler/rustc_middle/src/ty/instance.rs | 6 ++-- compiler/rustc_middle/src/ty/sty.rs | 14 ++++---- .../rustc_mir_build/src/builder/expr/as_rvalue.rs | 2 +- compiler/rustc_mir_build/src/builder/expr/into.rs | 2 +- .../rustc_mir_build/src/builder/matches/test.rs | 4 +-- compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 +- compiler/rustc_mir_build/src/thir/cx/mod.rs | 2 +- .../src/thir/pattern/const_to_pat.rs | 7 ++-- compiler/rustc_mir_transform/src/coroutine.rs | 31 +++++++++-------- compiler/rustc_mir_transform/src/coroutine/drop.rs | 39 +++++++++++----------- compiler/rustc_mir_transform/src/elaborate_drop.rs | 13 +++----- compiler/rustc_mir_transform/src/shim.rs | 2 +- .../src/shim/async_destructor_ctor.rs | 12 +++---- compiler/rustc_mir_transform/src/validate.rs | 2 +- compiler/rustc_monomorphize/src/collector.rs | 4 +-- compiler/rustc_monomorphize/src/lib.rs | 2 +- .../src/cfi/typeid/itanium_cxx_abi/transform.rs | 8 ++--- .../src/error_reporting/infer/mod.rs | 4 +-- .../src/error_reporting/traits/call_kind.rs | 6 ++-- .../src/error_reporting/traits/suggestions.rs | 6 ++-- compiler/rustc_trait_selection/src/infer.rs | 8 ++--- .../rustc_trait_selection/src/traits/effects.rs | 4 +-- compiler/rustc_trait_selection/src/traits/misc.rs | 4 +-- .../rustc_trait_selection/src/traits/project.rs | 34 ++++++++++--------- .../src/traits/select/confirmation.rs | 28 ++++++++-------- compiler/rustc_trait_selection/src/traits/wf.rs | 4 +-- compiler/rustc_ty_utils/src/abi.rs | 13 ++++---- compiler/rustc_ty_utils/src/common_traits.rs | 3 +- compiler/rustc_ty_utils/src/structural_match.rs | 3 +- compiler/rustc_ty_utils/src/ty.rs | 2 +- src/librustdoc/clean/types.rs | 2 +- .../clippy_utils/src/qualify_min_const_fn.rs | 2 +- src/tools/miri/src/shims/panic.rs | 2 +- .../lang-items/lang-item-generic-requirements.rs | 3 +- .../lang-item-generic-requirements.stderr | 8 +++-- 77 files changed, 250 insertions(+), 250 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index f41627e479f..ca110719a72 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -732,7 +732,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, args: Option<&'hir hir::GenericArgs<'hir>>, ) -> &'hir hir::Path<'hir> { - let def_id = self.tcx.require_lang_item(lang_item, Some(span)); + let def_id = self.tcx.require_lang_item(lang_item, span); let def_kind = self.tcx.def_kind(def_id); let res = Res::Def(def_kind, def_id); self.arena.alloc(hir::Path { diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index b7b6a2da549..1b4bb11d87b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -263,7 +263,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // something that already has `Fn`-like bounds (or is a closure), so we can't // restrict anyways. } else { - let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, Some(span)); + let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, span); self.suggest_adding_bounds(&mut err, ty, copy_did, span); } @@ -1915,7 +1915,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let local_ty = self.body.local_decls[place.local].ty; let typeck_results = tcx.typeck(self.mir_def_id()); - let clone = tcx.require_lang_item(LangItem::Clone, Some(body.span)); + let clone = tcx.require_lang_item(LangItem::Clone, body.span); for expr in expr_finder.clones { if let hir::ExprKind::MethodCall(_, rcvr, _, span) = expr.kind && let Some(rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 4f5baeff7c3..4f75dd7e992 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -688,7 +688,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if !self.unsized_feature_enabled() { let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), + tcx.require_lang_item(LangItem::Sized, self.last_span), [place_ty], ); self.prove_trait_ref( @@ -1010,7 +1010,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let ty = place.ty(self.body, tcx).ty; let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Copy, Some(span)), + tcx.require_lang_item(LangItem::Copy, span), [ty], ); @@ -1025,11 +1025,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => { - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::Sized, Some(span)), - [ty], - ); + let trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, span), [ty]); self.prove_trait_ref( trait_ref, @@ -1041,11 +1038,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { &Rvalue::NullaryOp(NullOp::UbChecks, _) => {} Rvalue::ShallowInitBox(_operand, ty) => { - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::Sized, Some(span)), - [*ty], - ); + let trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, span), [*ty]); self.prove_trait_ref( trait_ref, @@ -1222,7 +1216,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let &ty = ty; let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)), + tcx.require_lang_item(LangItem::CoerceUnsized, span), [op.ty(self.body, tcx), ty], ); @@ -1811,7 +1805,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Copy, Some(self.last_span)), + tcx.require_lang_item(LangItem::Copy, self.last_span), [place_ty.ty], ); diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index c11e14d214c..846299711be 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -544,10 +544,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // (as it's created inside the body itself, not passed in from outside). if let DefiningTy::FnDef(def_id, _) = defining_ty { if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() { - let va_list_did = self.infcx.tcx.require_lang_item( - LangItem::VaList, - Some(self.infcx.tcx.def_span(self.mir_def)), - ); + let va_list_did = self + .infcx + .tcx + .require_lang_item(LangItem::VaList, self.infcx.tcx.def_span(self.mir_def)); let reg_vid = self .infcx diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 4617304105a..0b641ba64b7 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -380,7 +380,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { rustc_hir::LangItem::PanicBoundsCheck, &[index, len, location], *unwind, - Some(source_info.span), + source_info.span, ); } AssertKind::MisalignedPointerDereference { ref required, ref found } => { @@ -393,7 +393,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { rustc_hir::LangItem::PanicMisalignedPointerDereference, &[required, found, location], *unwind, - Some(source_info.span), + source_info.span, ); } AssertKind::NullPointerDereference => { @@ -404,7 +404,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { rustc_hir::LangItem::PanicNullPointerDereference, &[location], *unwind, - Some(source_info.span), + source_info.span, ) } _ => { @@ -415,7 +415,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { msg.panic_function(), &[location], *unwind, - Some(source_info.span), + source_info.span, ); } } @@ -531,7 +531,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { ); } TerminatorKind::UnwindTerminate(reason) => { - codegen_unwind_terminate(fx, Some(source_info.span), *reason); + codegen_unwind_terminate(fx, source_info.span, *reason); } TerminatorKind::UnwindResume => { // FIXME implement unwinding @@ -1074,7 +1074,7 @@ pub(crate) fn codegen_operand<'tcx>( pub(crate) fn codegen_panic_nounwind<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, - span: Option, + span: Span, ) { let msg_ptr = fx.anonymous_str(msg_str); let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap()); @@ -1091,7 +1091,7 @@ pub(crate) fn codegen_panic_nounwind<'tcx>( pub(crate) fn codegen_unwind_terminate<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, - span: Option, + span: Span, reason: UnwindTerminateReason, ) { codegen_panic_inner(fx, reason.lang_item(), &[], UnwindAction::Unreachable, span); @@ -1102,7 +1102,7 @@ fn codegen_panic_inner<'tcx>( lang_item: rustc_hir::LangItem, args: &[Value], _unwind: UnwindAction, - span: Option, + span: Span, ) { fx.bcx.set_cold_block(fx.bcx.current_block().unwrap()); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index 2e02e85a997..99a5518d0b6 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -71,7 +71,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" ); - crate::base::codegen_panic_nounwind(fx, &msg, None); + crate::base::codegen_panic_nounwind(fx, &msg, span); return; } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs index d22483cf177..c22f2a7b873 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs @@ -512,7 +512,7 @@ pub(super) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" ); - crate::base::codegen_panic_nounwind(fx, &msg, None); + crate::base::codegen_panic_nounwind(fx, &msg, fx.mir.span); return; } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index 3d67913a8ff..615f6c47d90 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -1321,7 +1321,7 @@ pub(super) fn codegen_x86_llvm_intrinsic_call<'tcx>( See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" ); - crate::base::codegen_panic_nounwind(fx, &msg, None); + crate::base::codegen_panic_nounwind(fx, &msg, span); return; } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 0de23e55e81..27a5df8b152 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -785,7 +785,7 @@ fn codegen_regular_intrinsic_call<'tcx>( } }) }); - crate::base::codegen_panic_nounwind(fx, &msg_str, Some(source_info.span)); + crate::base::codegen_panic_nounwind(fx, &msg_str, source_info.span); return Ok(()); } } @@ -884,7 +884,7 @@ fn codegen_regular_intrinsic_call<'tcx>( crate::base::codegen_panic_nounwind( fx, "128bit atomics not yet supported", - None, + source_info.span, ); return Ok(()); } else { @@ -919,7 +919,7 @@ fn codegen_regular_intrinsic_call<'tcx>( crate::base::codegen_panic_nounwind( fx, "128bit atomics not yet supported", - None, + source_info.span, ); return Ok(()); } else { diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 6eef97c14dd..bf756860b64 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -101,7 +101,7 @@ pub(crate) fn maybe_create_entry_wrapper( let call_inst = bcx.ins().call(main_func_ref, &[]); let call_results = bcx.func.dfg.inst_results(call_inst).to_owned(); - let termination_trait = tcx.require_lang_item(LangItem::Termination, None); + let termination_trait = tcx.require_lang_item(LangItem::Termination, DUMMY_SP); let report = tcx .associated_items(termination_trait) .find_by_ident_and_kind( @@ -136,7 +136,7 @@ pub(crate) fn maybe_create_entry_wrapper( } } else { // Regular main fn invoked via start lang item. - let start_def_id = tcx.require_lang_item(LangItem::Start, None); + let start_def_id = tcx.require_lang_item(LangItem::Start, DUMMY_SP); let start_instance = Instance::expect_resolve( tcx, ty::TypingEnv::fully_monomorphized(), diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index f53045df6e7..95d44dfb6d9 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -54,7 +54,7 @@ fn codegen_three_way_compare<'tcx>( let gt = fx.bcx.ins().icmp(gt_cc, lhs, rhs); let lt = fx.bcx.ins().icmp(lt_cc, lhs, rhs); let val = fx.bcx.ins().isub(gt, lt); - CValue::by_val(val, fx.layout_of(fx.tcx.ty_ordering_enum(Some(fx.mir.span)))) + CValue::by_val(val, fx.layout_of(fx.tcx.ty_ordering_enum(fx.mir.span))) } fn codegen_compare_bin_op<'tcx>( diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index f8bbb214920..662546e4999 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -240,7 +240,7 @@ pub(crate) fn size_and_align_of<'tcx>( }) }); - codegen_panic_nounwind(fx, &msg_str, None); + codegen_panic_nounwind(fx, &msg_str, fx.mir.span); fx.bcx.switch_to_block(next_block); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f7863fe4ae2..c2d6a26de0f 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -561,7 +561,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let EntryFnType::Main { sigpipe } = entry_type; let (start_fn, start_ty, args, instance) = { - let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None); + let start_def_id = cx.tcx().require_lang_item(LangItem::Start, DUMMY_SP); let start_instance = ty::Instance::expect_resolve( cx.tcx(), cx.typing_env(), diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index ef0d565333e..48565e0b4de 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -110,7 +110,7 @@ mod temp_stable_hash_impls { pub(crate) fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &Bx, - span: Option, + span: Span, li: LangItem, ) -> (Bx::FnAbiOfResult, Bx::Value, Instance<'tcx>) { let tcx = bx.tcx(); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1baab62ae43..bfc367f7a4d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -783,7 +783,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }; - let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), lang_item); + let (fn_abi, llfn, instance) = common::build_langcall(bx, span, lang_item); // Codegen the actual panic invoke/call. let merging_succ = @@ -803,7 +803,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.set_debug_loc(bx, terminator.source_info); // Obtain the panic entry point. - let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), reason.lang_item()); + let (fn_abi, llfn, instance) = common::build_langcall(bx, span, reason.lang_item()); // Codegen the actual panic invoke/call. let merging_succ = helper.do_call( @@ -871,7 +871,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Obtain the panic entry point. let (fn_abi, llfn, instance) = - common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind); + common::build_langcall(bx, source_info.span, LangItem::PanicNounwind); // Codegen the actual panic invoke/call. Some(helper.do_call( @@ -1830,7 +1830,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span)); - let (fn_abi, fn_ptr, instance) = common::build_langcall(&bx, None, reason.lang_item()); + let (fn_abi, fn_ptr, instance) = + common::build_langcall(&bx, self.mir.span, reason.lang_item()); if is_call_from_compiler_builtins_to_upstream_monomorphization(bx.tcx(), instance) { bx.abort(); } else { diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index ac2366340fb..577012151e4 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -5,6 +5,7 @@ use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Ty}; +use rustc_span::DUMMY_SP; use tracing::{debug, trace}; use crate::common::IntPredicate; @@ -62,7 +63,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Obtain the panic entry point. let (fn_abi, llfn, _instance) = - common::build_langcall(bx, None, LangItem::PanicNounwind); + common::build_langcall(bx, DUMMY_SP, LangItem::PanicNounwind); // Generate the call. Cannot use `do_call` since we don't have a MIR terminator so we // can't create a `TerminationCodegenHelper`. (But we are in good company, this code is diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index d701646719a..9c30dbff99e 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -345,11 +345,7 @@ fn build_error_for_const_call<'tcx>( non_or_conditionally, }); - note_trait_if_possible( - &mut err, - self_ty, - tcx.require_lang_item(LangItem::Deref, Some(span)), - ); + note_trait_if_possible(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, span)); err } _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::FmtArgumentsNew) => { diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index dfcd1969a73..c1a37ab6a83 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -99,7 +99,7 @@ impl Qualif for HasMutInterior { // requires borrowck, which in turn will invoke mir_const_qualifs again, causing a cycle error. // Instead we invoke an obligation context manually, and provide the opaque type inference settings // that allow the trait solver to just error out instead of cycling. - let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, Some(cx.body.span)); + let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, cx.body.span); // FIXME(#132279): Once we've got a typing mode which reveals opaque types using the HIR // typeck results without causing query cycles, we should use this here instead of defining // opaque types. @@ -180,7 +180,7 @@ impl Qualif for NeedsNonConstDrop { // that the components of this type are also `~const Destruct`. This // amounts to verifying that there are no values in this ADT that may have // a non-const drop. - let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span)); + let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, cx.body.span); let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(cx.typing_env); let ocx = ObligationCtxt::new(&infcx); ocx.register_obligation(Obligation::new( diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 3922b33ea84..a68dcf29988 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -249,7 +249,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { return Err(ConstEvalErrKind::Panic { msg, file, line, col }).into(); } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) { // For panic_fmt, call const_panic_fmt instead. - let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None); + let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, self.tcx.span); let new_instance = ty::Instance::expect_resolve( *self.tcx, self.typing_env(), diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 39755169e6c..77667ba823a 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -12,6 +12,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug, ty}; +use rustc_span::DUMMY_SP; use tracing::trace; use super::{ @@ -307,7 +308,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self { // Can use any typing env, since `Ordering` is always monomorphic. - let ty = tcx.ty_ordering_enum(None); + let ty = tcx.ty_ordering_enum(DUMMY_SP); let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap(); Self::from_scalar(Scalar::Int(c.into()), layout) diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index e926040e9ba..9575bd43661 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -30,7 +30,7 @@ fn alloc_caller_location<'tcx>( // Allocate memory for `CallerLocation` struct. let loc_ty = ecx .tcx - .type_of(ecx.tcx.require_lang_item(LangItem::PanicLocation, None)) + .type_of(ecx.tcx.require_lang_item(LangItem::PanicLocation, ecx.tcx.span)) .instantiate(*ecx.tcx, ecx.tcx.mk_args(&[ecx.tcx.lifetimes.re_erased.into()])); let loc_layout = ecx.layout_of(loc_ty).unwrap(); let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap(); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 846eacce9e1..77f6204d595 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -97,7 +97,7 @@ fn allowed_union_or_unsafe_field<'tcx>( let def_id = tcx .lang_items() .get(LangItem::BikeshedGuaranteedNoDrop) - .unwrap_or_else(|| tcx.require_lang_item(LangItem::Copy, Some(span))); + .unwrap_or_else(|| tcx.require_lang_item(LangItem::Copy, span)); let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, ty) else { tcx.dcx().span_delayed_bug(span, "could not normalize field type"); return true; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 09610a2f3ec..234520c1583 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -180,7 +180,7 @@ pub(crate) fn check_intrinsic_type( ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv), ]); let mk_va_list_ty = |mutbl| { - let did = tcx.require_lang_item(LangItem::VaList, Some(span)); + let did = tcx.require_lang_item(LangItem::VaList, span); let region = ty::Region::new_bound( tcx, ty::INNERMOST, @@ -442,9 +442,7 @@ pub(crate) fn check_intrinsic_type( sym::bswap | sym::bitreverse => (1, 0, vec![param(0)], param(0)), - sym::three_way_compare => { - (1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(Some(span))) - } + sym::three_way_compare => (1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(span)), sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { (1, 0, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool])) @@ -520,7 +518,7 @@ pub(crate) fn check_intrinsic_type( sym::discriminant_value => { let assoc_items = tcx.associated_item_def_ids( - tcx.require_lang_item(hir::LangItem::DiscriminantKind, None), + tcx.require_lang_item(hir::LangItem::DiscriminantKind, span), ); let discriminant_def_id = assoc_items[0]; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 3e872607e31..237b8ae8b89 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -969,7 +969,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::UnsizedConstParamTy, Some(hir_ty.span)), + tcx.require_lang_item(LangItem::UnsizedConstParamTy, hir_ty.span), ); Ok(()) }) @@ -983,7 +983,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span)), + tcx.require_lang_item(LangItem::ConstParamTy, hir_ty.span), ); Ok(()) }) @@ -1232,7 +1232,7 @@ fn check_type_defn<'tcx>( ), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::Sized, Some(hir_ty.span)), + tcx.require_lang_item(LangItem::Sized, hir_ty.span), ); } @@ -1356,7 +1356,7 @@ fn check_static_item( ), wfcx.param_env, item_ty, - tcx.require_lang_item(LangItem::Sized, Some(ty_span)), + tcx.require_lang_item(LangItem::Sized, ty_span), ); } @@ -1375,7 +1375,7 @@ fn check_static_item( ), wfcx.param_env, item_ty, - tcx.require_lang_item(LangItem::Sync, Some(ty_span)), + tcx.require_lang_item(LangItem::Sync, ty_span), ); } Ok(()) @@ -1401,7 +1401,7 @@ fn check_const_item( ), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::Sized, None), + tcx.require_lang_item(LangItem::Sized, ty_span), ); check_where_clauses(wfcx, item_span, def_id); @@ -1725,13 +1725,13 @@ fn check_fn_or_method<'tcx>( ObligationCause::new(span, wfcx.body_def_id, ObligationCauseCode::RustCall), wfcx.param_env, *ty, - tcx.require_lang_item(hir::LangItem::Tuple, Some(span)), + tcx.require_lang_item(hir::LangItem::Tuple, span), ); wfcx.register_bound( ObligationCause::new(span, wfcx.body_def_id, ObligationCauseCode::RustCall), wfcx.param_env, *ty, - tcx.require_lang_item(hir::LangItem::Sized, Some(span)), + tcx.require_lang_item(hir::LangItem::Sized, span), ); } else { tcx.dcx().span_err( @@ -1776,7 +1776,7 @@ fn check_sized_if_body<'tcx>( ObligationCause::new(span, def_id, code), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::Sized, Some(span)), + tcx.require_lang_item(LangItem::Sized, span), ); } } @@ -2013,7 +2013,7 @@ fn receiver_is_valid<'tcx>( // deref chain implement `LegacyReceiver`. if arbitrary_self_types_enabled.is_none() { let legacy_receiver_trait_def_id = - tcx.require_lang_item(LangItem::LegacyReceiver, Some(span)); + tcx.require_lang_item(LangItem::LegacyReceiver, span); if !legacy_receiver_is_implemented( wfcx, legacy_receiver_trait_def_id, diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index b92d1d7104f..4779f4fb702 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -225,7 +225,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() // redundant errors for `DispatchFromDyn`. This is best effort, though. let mut res = Ok(()); tcx.for_each_relevant_impl( - tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)), + tcx.require_lang_item(LangItem::CoerceUnsized, span), source, |impl_def_id| { res = res.and(tcx.ensure_ok().coerce_unsized_info(impl_def_id)); @@ -379,8 +379,8 @@ pub(crate) fn coerce_unsized_info<'tcx>( let span = tcx.def_span(impl_did); let trait_name = "CoerceUnsized"; - let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)); - let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span)); + let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, span); + let unsize_trait = tcx.require_lang_item(LangItem::Unsize, span); let source = tcx.type_of(impl_did).instantiate_identity(); let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity(); @@ -591,7 +591,7 @@ fn infringing_fields_error<'tcx>( impl_did: LocalDefId, impl_span: Span, ) -> ErrorGuaranteed { - let trait_did = tcx.require_lang_item(lang_item, Some(impl_span)); + let trait_did = tcx.require_lang_item(lang_item, impl_span); let trait_name = tcx.def_path_str(trait_did); @@ -748,7 +748,7 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err ObligationCause::misc(impl_span, checker.impl_def_id), param_env, nontrivial_field_ty, - tcx.require_lang_item(LangItem::PointerLike, Some(impl_span)), + tcx.require_lang_item(LangItem::PointerLike, impl_span), ); // FIXME(dyn-star): We should regionck this implementation. if ocx.select_all_or_error().is_empty() { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 2a37a8bdbd4..4c65d0d0510 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2590,7 +2590,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) } &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => { - let def_id = tcx.require_lang_item(lang_item, Some(span)); + let def_id = tcx.require_lang_item(lang_item, span); let (args, _) = self.lower_generic_args_of_path( span, def_id, diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index f555d116c52..d173fe7c2c2 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -508,7 +508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(ty) = fn_sig.inputs().last().copied() { self.register_bound( ty, - self.tcx.require_lang_item(hir::LangItem::Tuple, Some(sp)), + self.tcx.require_lang_item(hir::LangItem::Tuple, sp), self.cause(sp, ObligationCauseCode::RustCall), ); self.require_type_is_sized(ty, sp, ObligationCauseCode::RustCall); diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 99103f14d68..ac42eebf08c 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -57,7 +57,7 @@ pub(super) fn check_fn<'a, 'tcx>( // (as it's created inside the body itself, not passed in from outside). let maybe_va_list = fn_sig.c_variadic.then(|| { let span = body.params.last().unwrap().span; - let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span)); + let va_list_did = tcx.require_lang_item(LangItem::VaList, span); let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); tcx.type_of(va_list_did).instantiate(tcx, &[region.into()]) @@ -178,7 +178,7 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_> tcx.dcx().span_err(span, "should have no const parameters"); } - let panic_info_did = tcx.require_lang_item(hir::LangItem::PanicInfo, Some(span)); + let panic_info_did = tcx.require_lang_item(hir::LangItem::PanicInfo, span); // build type `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !` let panic_info_ty = tcx.type_of(panic_info_did).instantiate( diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index cd3746be1d1..459c0498d50 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -142,13 +142,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ty::new_adt( tcx, - tcx.adt_def( - tcx.require_lang_item(hir::LangItem::Poll, Some(expr_span)), - ), + tcx.adt_def(tcx.require_lang_item(hir::LangItem::Poll, expr_span)), tcx.mk_args(&[Ty::new_adt( tcx, tcx.adt_def( - tcx.require_lang_item(hir::LangItem::Option, Some(expr_span)), + tcx.require_lang_item(hir::LangItem::Option, expr_span), ), tcx.mk_args(&[yield_ty.into()]), ) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index ddc80fab2ce..d9fa56fefeb 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -760,8 +760,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.param_env, ty::TraitRef::new( self.tcx, - self.tcx - .require_lang_item(hir::LangItem::PointerLike, Some(self.cause.span)), + self.tcx.require_lang_item(hir::LangItem::PointerLike, self.cause.span), [a], ), ), @@ -1969,7 +1968,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fcx.param_env, ty::TraitRef::new( fcx.tcx, - fcx.tcx.require_lang_item(hir::LangItem::Sized, None), + fcx.tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP), [sig.output()], ), )) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 082ddac7e5a..b17d5977e06 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1407,7 +1407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let lhs_deref_ty_is_sized = self .infcx .type_implements_trait( - self.tcx.require_lang_item(LangItem::Sized, None), + self.tcx.require_lang_item(LangItem::Sized, span), [lhs_deref_ty], self.param_env, ) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 362c7d8efac..8a90e768d70 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -409,7 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { code: traits::ObligationCauseCode<'tcx>, ) { if !ty.references_error() { - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + let lang_item = self.tcx.require_lang_item(LangItem::Sized, span); self.require_type_meets(ty, span, code, lang_item); } } @@ -443,7 +443,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Nothing else is required here. } else { // We can't be sure, let's required full `Sized`. - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + let lang_item = self.tcx.require_lang_item(LangItem::Sized, span); self.require_type_meets(ty, span, ObligationCauseCode::Misc, lang_item); } } @@ -732,7 +732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, hir_id: HirId, ) -> (Res, Ty<'tcx>) { - let def_id = self.tcx.require_lang_item(lang_item, Some(span)); + let def_id = self.tcx.require_lang_item(lang_item, span); let def_kind = self.tcx.def_kind(def_id); let item_ty = if let DefKind::Variant = def_kind { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 59aba6fae5e..95c7f251c88 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -165,7 +165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => traits::IsConstable::No, }; - let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); + let lang_item = self.tcx.require_lang_item(LangItem::Copy, element.span); let code = traits::ObligationCauseCode::RepeatElementCopy { is_constable, elt_span: element.span, @@ -1680,8 +1680,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ast::LitKind::CStr(_, _) => Ty::new_imm_ref( tcx, tcx.lifetimes.re_static, - tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span))) - .skip_binder(), + tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, lit.span)).skip_binder(), ), ast::LitKind::Err(guar) => Ty::new_error(tcx, guar), } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1c3bc338d85..66af085cfd4 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2679,7 +2679,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut sugg_sp = sp; if let hir::ExprKind::MethodCall(segment, receiver, args, _) = expr.kind { let clone_trait = - self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span)); + self.tcx.require_lang_item(LangItem::Clone, segment.ident.span); if args.is_empty() && self .typeck_results diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 17d48184dd9..432eeae8016 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -796,7 +796,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if *negated { self.register_bound( ty, - self.tcx.require_lang_item(LangItem::Neg, Some(lt.span)), + self.tcx.require_lang_item(LangItem::Neg, lt.span), ObligationCause::dummy_with_span(lt.span), ); } @@ -2553,13 +2553,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; self.register_bound( source_ty, - tcx.require_lang_item(hir::LangItem::DerefPure, Some(span)), + tcx.require_lang_item(hir::LangItem::DerefPure, span), self.misc(span), ); // The expected type for the deref pat's inner pattern is `::Target`. let target_ty = Ty::new_projection( tcx, - tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)), + tcx.require_lang_item(hir::LangItem::DerefTarget, span), [source_ty], ); let target_ty = self.normalize(span, target_ty); @@ -2580,7 +2580,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for mutably_derefed_ty in derefed_tys { self.register_bound( mutably_derefed_ty, - self.tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)), + self.tcx.require_lang_item(hir::LangItem::DerefMut, span), self.misc(span), ); } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 4b2e87f5674..5b5253c7e7e 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -1560,7 +1560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let is_drop_defined_for_ty = |ty: Ty<'tcx>| { - let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, Some(closure_span)); + let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, closure_span); self.infcx .type_implements_trait(drop_trait, [ty], self.tcx.param_env(closure_def_id)) .must_apply_modulo_regions() diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 47b80135bae..69e9f8e1b2c 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -39,7 +39,7 @@ pub use rustc_session::lint::builtin::*; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; -use rustc_span::{BytePos, Ident, InnerSpan, Span, Symbol, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Ident, InnerSpan, Span, Symbol, kw, sym}; use rustc_target::asm::InlineAsmArch; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy; @@ -635,7 +635,8 @@ fn type_implements_negative_copy_modulo_regions<'tcx>( typing_env: ty::TypingEnv<'tcx>, ) -> bool { let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); - let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, None), [ty]); + let trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, DUMMY_SP), [ty]); let pred = ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Negative }; let obligation = traits::Obligation { cause: traits::ObligationCause::dummy(), diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index bd315577efb..6c6b12fed67 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -95,7 +95,7 @@ pub(crate) struct StrictCoherenceNeedsNegativeCoherence { #[diag(middle_requires_lang_item)] pub(crate) struct RequiresLangItem { #[primary_span] - pub span: Option, + pub span: Span, pub name: Symbol, } diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 0f92c1910f1..93264f02cc2 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -17,7 +17,7 @@ use crate::ty::{self, TyCtxt}; impl<'tcx> TyCtxt<'tcx> { /// Returns the `DefId` for a given `LangItem`. /// If not found, fatally aborts compilation. - pub fn require_lang_item(self, lang_item: LangItem, span: Option) -> DefId { + pub fn require_lang_item(self, lang_item: LangItem, span: Span) -> DefId { self.lang_items().get(lang_item).unwrap_or_else(|| { self.dcx().emit_fatal(crate::error::RequiresLangItem { span, name: lang_item.name() }); }) diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 06e41e64fdc..d98b40f0fcf 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -835,7 +835,7 @@ impl<'tcx> BinOp { &BinOp::Cmp => { // these should be integer-like types of the same size. assert_eq!(lhs_ty, rhs_ty); - tcx.ty_ordering_enum(None) + tcx.ty_ordering_enum(DUMMY_SP) } } } diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index a61a6c571a2..3bacdfe5ac8 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -128,8 +128,8 @@ impl OverloadedDeref { /// for this overloaded deref's mutability. pub fn method_call<'tcx>(&self, tcx: TyCtxt<'tcx>) -> DefId { let trait_def_id = match self.mutbl { - hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, None), - hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, None), + hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, self.span), + hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, self.span), }; tcx.associated_items(trait_def_id) .in_definition_order() diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 57b20a1bba6..0b1e9852d2a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -458,7 +458,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { } fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId { - self.require_lang_item(trait_lang_item_to_lang_item(lang_item), None) + self.require_lang_item(trait_lang_item_to_lang_item(lang_item), DUMMY_SP) } fn is_lang_item(self, def_id: DefId, lang_item: TraitSolverLangItem) -> bool { @@ -1710,7 +1710,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Gets a `Ty` representing the [`LangItem::OrderingEnum`] #[track_caller] - pub fn ty_ordering_enum(self, span: Option) -> Ty<'tcx> { + pub fn ty_ordering_enum(self, span: Span) -> Ty<'tcx> { let ordering_enum = self.require_lang_item(hir::LangItem::OrderingEnum, span); self.type_of(ordering_enum).no_bound_vars().unwrap() } @@ -2253,7 +2253,7 @@ impl<'tcx> TyCtxt<'tcx> { Ty::new_imm_ref( self, self.lifetimes.re_static, - self.type_of(self.require_lang_item(LangItem::PanicLocation, None)) + self.type_of(self.require_lang_item(LangItem::PanicLocation, DUMMY_SP)) .instantiate(self, self.mk_args(&[self.lifetimes.re_static.into()])), ) } @@ -2712,7 +2712,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given a `ty`, return whether it's an `impl Future<...>`. pub fn ty_is_opaque_future(self, ty: Ty<'_>) -> bool { let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false }; - let future_trait = self.require_lang_item(LangItem::Future, None); + let future_trait = self.require_lang_item(LangItem::Future, DUMMY_SP); self.explicit_item_self_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| { let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 0d99a1b5149..5ba4e5446e9 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -786,7 +786,7 @@ impl<'tcx> Instance<'tcx> { } pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { - let def_id = tcx.require_lang_item(LangItem::DropInPlace, None); + let def_id = tcx.require_lang_item(LangItem::DropInPlace, DUMMY_SP); let args = tcx.mk_args(&[ty.into()]); Instance::expect_resolve( tcx, @@ -798,7 +798,7 @@ impl<'tcx> Instance<'tcx> { } pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { - let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, None); + let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, DUMMY_SP); let args = tcx.mk_args(&[ty.into()]); Instance::expect_resolve( tcx, @@ -824,7 +824,7 @@ impl<'tcx> Instance<'tcx> { closure_did: DefId, args: ty::GenericArgsRef<'tcx>, ) -> Instance<'tcx> { - let fn_once = tcx.require_lang_item(LangItem::FnOnce, None); + let fn_once = tcx.require_lang_item(LangItem::FnOnce, DUMMY_SP); let call_once = tcx .associated_items(fn_once) .in_definition_order() diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 404674c359e..cbf545c01c5 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -593,7 +593,7 @@ impl<'tcx> Ty<'tcx> { ty: Ty<'tcx>, mutbl: ty::Mutability, ) -> Ty<'tcx> { - let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None)); + let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, DUMMY_SP)); Ty::new_adt(tcx, pin, tcx.mk_args(&[Ty::new_ref(tcx, r, ty, mutbl).into()])) } @@ -857,19 +857,19 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn new_box(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = tcx.require_lang_item(LangItem::OwnedBox, None); + let def_id = tcx.require_lang_item(LangItem::OwnedBox, DUMMY_SP); Ty::new_generic_adt(tcx, def_id, ty) } #[inline] pub fn new_maybe_uninit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None); + let def_id = tcx.require_lang_item(LangItem::MaybeUninit, DUMMY_SP); Ty::new_generic_adt(tcx, def_id, ty) } /// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes. pub fn new_task_context(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - let context_did = tcx.require_lang_item(LangItem::Context, None); + let context_did = tcx.require_lang_item(LangItem::Context, DUMMY_SP); let context_adt_ref = tcx.adt_def(context_did); let context_args = tcx.mk_args(&[tcx.lifetimes.re_erased.into()]); let context_ty = Ty::new_adt(tcx, context_adt_ref, context_args); @@ -1549,7 +1549,7 @@ impl<'tcx> Ty<'tcx> { ty::Param(_) | ty::Alias(..) | ty::Infer(ty::TyVar(_)) => { let assoc_items = tcx.associated_item_def_ids( - tcx.require_lang_item(hir::LangItem::DiscriminantKind, None), + tcx.require_lang_item(hir::LangItem::DiscriminantKind, DUMMY_SP), ); Ty::new_projection_from_args(tcx, assoc_items[0], tcx.mk_args(&[self.into()])) } @@ -1629,7 +1629,7 @@ impl<'tcx> Ty<'tcx> { ty::Str | ty::Slice(_) => Ok(tcx.types.usize), ty::Dynamic(_, _, ty::Dyn) => { - let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); + let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, DUMMY_SP); Ok(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()])) } @@ -1683,7 +1683,7 @@ impl<'tcx> Ty<'tcx> { match pointee_ty.ptr_metadata_ty_or_tail(tcx, |x| x) { Ok(metadata_ty) => metadata_ty, Err(tail_ty) => { - let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); + let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, DUMMY_SP); Ty::new_projection(tcx, metadata_def_id, [tail_ty]) } } diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index 5a97b08db28..b23bc089cd4 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -145,7 +145,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // malloc some memory of suitable size and align: let exchange_malloc = Operand::function_handle( tcx, - tcx.require_lang_item(LangItem::ExchangeMalloc, Some(expr_span)), + tcx.require_lang_item(LangItem::ExchangeMalloc, expr_span), [], expr_span, ); diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index a9a07997410..2074fbce0ae 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -307,7 +307,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else if this.infcx.type_is_use_cloned_modulo_regions(this.param_env, ty) { // Convert `expr.use` to a call like `Clone::clone(&expr)` let success = this.cfg.start_new_block(); - let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None); + let clone_trait = this.tcx.require_lang_item(LangItem::Clone, span); let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0]; let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span); let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty); diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 210b9cce581..a4609a6053e 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -364,7 +364,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let borrow_kind = super::util::ref_pat_borrow_kind(mutability); let source_info = self.source_info(span); let re_erased = self.tcx.lifetimes.re_erased; - let trait_item = self.tcx.require_lang_item(trait_item, None); + let trait_item = self.tcx.require_lang_item(trait_item, span); let method = trait_method(self.tcx, trait_item, method, [ty]); let ref_src = self.temp(Ty::new_ref(self.tcx, re_erased, ty, mutability), span); // `let ref_src = &src_place;` @@ -437,7 +437,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { val: Operand<'tcx>, ) { let str_ty = self.tcx.types.str_; - let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span)); + let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, source_info.span); let method = trait_method(self.tcx, eq_def_id, sym::eq, [str_ty, str_ty]); let bool_ty = self.tcx.types.bool; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 226dc920a49..03448933fa9 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -220,7 +220,7 @@ impl<'tcx> ThirBuildCx<'tcx> { }); // kind = Pin { __pointer: pointer } - let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, Some(span)); + let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, span); let args = self.tcx.mk_args(&[new_pin_target.into()]); let kind = ExprKind::Adt(Box::new(AdtExpr { adt_def: self.tcx.adt_def(pin_did), diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 8c817605847..24d4136c642 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -189,7 +189,7 @@ impl<'tcx> ThirBuildCx<'tcx> { // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // (as it's created inside the body itself, not passed in from outside). let ty = if fn_decl.c_variadic && index == fn_decl.inputs.len() { - let va_list_did = self.tcx.require_lang_item(LangItem::VaList, Some(param.span)); + let va_list_did = self.tcx.require_lang_item(LangItem::VaList, param.span); self.tcx .type_of(va_list_did) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 84a0190a7fa..003ad170861 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{ }; use rustc_middle::{mir, span_bug}; use rustc_span::def_id::DefId; -use rustc_span::{Span, sym}; +use rustc_span::{DUMMY_SP, Span, sym}; use rustc_trait_selection::traits::ObligationCause; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use tracing::{debug, instrument, trace}; @@ -480,8 +480,9 @@ fn type_has_partial_eq_impl<'tcx>( // (If there isn't, then we can safely issue a hard // error, because that's never worked, due to compiler // using `PartialEq::eq` in this scenario in the past.) - let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, None); - let structural_partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::StructuralPeq, None); + let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, DUMMY_SP); + let structural_partial_eq_trait_id = + tcx.require_lang_item(hir::LangItem::StructuralPeq, DUMMY_SP); let partial_eq_obligation = Obligation::new( tcx, diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index cddb2f84778..d5d0d56f528 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -225,7 +225,7 @@ impl<'tcx> TransformVisitor<'tcx> { CoroutineKind::Coroutine(_) => span_bug!(body.span, "`Coroutine`s cannot be fused"), // `gen` continues return `None` CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { - let option_def_id = self.tcx.require_lang_item(LangItem::Option, None); + let option_def_id = self.tcx.require_lang_item(LangItem::Option, body.span); make_aggregate_adt( option_def_id, VariantIdx::ZERO, @@ -242,7 +242,7 @@ impl<'tcx> TransformVisitor<'tcx> { span: source_info.span, const_: Const::Unevaluated( UnevaluatedConst::new( - self.tcx.require_lang_item(LangItem::AsyncGenFinished, None), + self.tcx.require_lang_item(LangItem::AsyncGenFinished, body.span), self.tcx.mk_args(&[yield_ty.into()]), ), self.old_yield_ty, @@ -282,7 +282,7 @@ impl<'tcx> TransformVisitor<'tcx> { const ONE: VariantIdx = VariantIdx::from_usize(1); let rvalue = match self.coroutine_kind { CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { - let poll_def_id = self.tcx.require_lang_item(LangItem::Poll, None); + let poll_def_id = self.tcx.require_lang_item(LangItem::Poll, source_info.span); let args = self.tcx.mk_args(&[self.old_ret_ty.into()]); let (variant_idx, operands) = if is_return { (ZERO, IndexVec::from_raw(vec![val])) // Poll::Ready(val) @@ -292,7 +292,7 @@ impl<'tcx> TransformVisitor<'tcx> { make_aggregate_adt(poll_def_id, variant_idx, args, operands) } CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { - let option_def_id = self.tcx.require_lang_item(LangItem::Option, None); + let option_def_id = self.tcx.require_lang_item(LangItem::Option, source_info.span); let args = self.tcx.mk_args(&[self.old_yield_ty.into()]); let (variant_idx, operands) = if is_return { (ZERO, IndexVec::new()) // None @@ -310,7 +310,10 @@ impl<'tcx> TransformVisitor<'tcx> { span: source_info.span, const_: Const::Unevaluated( UnevaluatedConst::new( - self.tcx.require_lang_item(LangItem::AsyncGenFinished, None), + self.tcx.require_lang_item( + LangItem::AsyncGenFinished, + source_info.span, + ), self.tcx.mk_args(&[yield_ty.into()]), ), self.old_yield_ty, @@ -323,7 +326,7 @@ impl<'tcx> TransformVisitor<'tcx> { } CoroutineKind::Coroutine(_) => { let coroutine_state_def_id = - self.tcx.require_lang_item(LangItem::CoroutineState, None); + self.tcx.require_lang_item(LangItem::CoroutineState, source_info.span); let args = self.tcx.mk_args(&[self.old_yield_ty.into(), self.old_ret_ty.into()]); let variant_idx = if is_return { ONE // CoroutineState::Complete(val) @@ -496,7 +499,7 @@ fn make_coroutine_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Bo fn make_coroutine_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let ref_coroutine_ty = body.local_decls.raw[1].ty; - let pin_did = tcx.require_lang_item(LangItem::Pin, Some(body.span)); + let pin_did = tcx.require_lang_item(LangItem::Pin, body.span); let pin_adt_ref = tcx.adt_def(pin_did); let args = tcx.mk_args(&[ref_coroutine_ty.into()]); let pin_ref_coroutine_ty = Ty::new_adt(tcx, pin_adt_ref, args); @@ -557,7 +560,7 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> Ty // replace the type of the `resume` argument replace_resume_ty_local(tcx, body, CTX_ARG, context_mut_ref); - let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None); + let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, body.span); for bb in body.basic_blocks.indices() { let bb_data = &body[bb]; @@ -618,7 +621,7 @@ fn replace_resume_ty_local<'tcx>( #[cfg(debug_assertions)] { if let ty::Adt(resume_ty_adt, _) = local_ty.kind() { - let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, body.span)); assert_eq!(*resume_ty_adt, expected_adt); } else { panic!("expected `ResumeTy`, found `{:?}`", local_ty); @@ -1095,7 +1098,7 @@ fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> fn return_poll_ready_assign<'tcx>(tcx: TyCtxt<'tcx>, source_info: SourceInfo) -> Statement<'tcx> { // Poll::Ready(()) - let poll_def_id = tcx.require_lang_item(LangItem::Poll, None); + let poll_def_id = tcx.require_lang_item(LangItem::Poll, source_info.span); let args = tcx.mk_args(&[tcx.types.unit.into()]); let val = Operand::Constant(Box::new(ConstOperand { span: source_info.span, @@ -1437,7 +1440,7 @@ fn check_field_tys_sized<'tcx>( ), param_env, field_ty.ty, - tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)), + tcx.require_lang_item(hir::LangItem::Sized, field_ty.source_info.span), ); } @@ -1473,14 +1476,14 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { let new_ret_ty = match coroutine_kind { CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { // Compute Poll - let poll_did = tcx.require_lang_item(LangItem::Poll, None); + let poll_did = tcx.require_lang_item(LangItem::Poll, body.span); let poll_adt_ref = tcx.adt_def(poll_did); let poll_args = tcx.mk_args(&[old_ret_ty.into()]); Ty::new_adt(tcx, poll_adt_ref, poll_args) } CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { // Compute Option - let option_did = tcx.require_lang_item(LangItem::Option, None); + let option_did = tcx.require_lang_item(LangItem::Option, body.span); let option_adt_ref = tcx.adt_def(option_did); let option_args = tcx.mk_args(&[old_yield_ty.into()]); Ty::new_adt(tcx, option_adt_ref, option_args) @@ -1491,7 +1494,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { } CoroutineKind::Coroutine(_) => { // Compute CoroutineState - let state_did = tcx.require_lang_item(LangItem::CoroutineState, None); + let state_did = tcx.require_lang_item(LangItem::CoroutineState, body.span); let state_adt_ref = tcx.adt_def(state_did); let state_args = tcx.mk_args(&[old_yield_ty.into(), old_ret_ty.into()]); Ty::new_adt(tcx, state_adt_ref, state_args) diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs index 625e53f9959..6021e795d21 100644 --- a/compiler/rustc_mir_transform/src/coroutine/drop.rs +++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs @@ -42,7 +42,7 @@ fn build_poll_call<'tcx>( context_ref_place: &Place<'tcx>, unwind: UnwindAction, ) -> BasicBlock { - let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, None); + let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, DUMMY_SP); let poll_fn = Ty::new_fn_def(tcx, poll_fn, [fut_ty]); let poll_fn = Operand::Constant(Box::new(ConstOperand { span: DUMMY_SP, @@ -77,11 +77,8 @@ fn build_pin_fut<'tcx>( let fut_ty = fut_place.ty(&body.local_decls, tcx).ty; let fut_ref_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, fut_ty); let fut_ref_place = Place::from(body.local_decls.push(LocalDecl::new(fut_ref_ty, span))); - let pin_fut_new_unchecked_fn = Ty::new_fn_def( - tcx, - tcx.require_lang_item(LangItem::PinNewUnchecked, Some(span)), - [fut_ref_ty], - ); + let pin_fut_new_unchecked_fn = + Ty::new_fn_def(tcx, tcx.require_lang_item(LangItem::PinNewUnchecked, span), [fut_ref_ty]); let fut_pin_ty = pin_fut_new_unchecked_fn.fn_sig(tcx).output().skip_binder(); let fut_pin_place = Place::from(body.local_decls.push(LocalDecl::new(fut_pin_ty, span))); let pin_fut_new_unchecked_fn = Operand::Constant(Box::new(ConstOperand { @@ -143,13 +140,15 @@ fn build_poll_switch<'tcx>( let Discr { val: poll_ready_discr, ty: poll_discr_ty } = poll_enum .discriminant_for_variant( tcx, - poll_enum_adt.variant_index_with_id(tcx.require_lang_item(LangItem::PollReady, None)), + poll_enum_adt + .variant_index_with_id(tcx.require_lang_item(LangItem::PollReady, DUMMY_SP)), ) .unwrap(); let poll_pending_discr = poll_enum .discriminant_for_variant( tcx, - poll_enum_adt.variant_index_with_id(tcx.require_lang_item(LangItem::PollPending, None)), + poll_enum_adt + .variant_index_with_id(tcx.require_lang_item(LangItem::PollPending, DUMMY_SP)), ) .unwrap() .val; @@ -316,16 +315,17 @@ pub(super) fn expand_async_drops<'tcx>( // pending => return rv (yield) // ready => *continue_bb|drop_bb* + let source_info = body[bb].terminator.as_ref().unwrap().source_info; + // Compute Poll<> (aka Poll with void return) - let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)); + let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, source_info.span)); let poll_enum = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()])); - let poll_decl = LocalDecl::new(poll_enum, body.span); + let poll_decl = LocalDecl::new(poll_enum, source_info.span); let poll_unit_place = Place::from(body.local_decls.push(poll_decl)); // First state-loop yield for mainline let context_ref_place = - Place::from(body.local_decls.push(LocalDecl::new(context_mut_ref, body.span))); - let source_info = body[bb].terminator.as_ref().unwrap().source_info; + Place::from(body.local_decls.push(LocalDecl::new(context_mut_ref, source_info.span))); let arg = Rvalue::Use(Operand::Move(Place::from(CTX_ARG))); body[bb].statements.push(Statement { source_info, @@ -353,8 +353,9 @@ pub(super) fn expand_async_drops<'tcx>( let mut dropline_context_ref: Option> = None; let mut dropline_call_bb: Option = None; if !is_dropline_bb { - let context_ref_place2: Place<'_> = - Place::from(body.local_decls.push(LocalDecl::new(context_mut_ref, body.span))); + let context_ref_place2: Place<'_> = Place::from( + body.local_decls.push(LocalDecl::new(context_mut_ref, source_info.span)), + ); let drop_yield_block = insert_term_block(body, TerminatorKind::Unreachable); // `kind` replaced later to yield let drop_switch_block = build_poll_switch( tcx, @@ -394,7 +395,7 @@ pub(super) fn expand_async_drops<'tcx>( span: source_info.span, const_: Const::Unevaluated( UnevaluatedConst::new( - tcx.require_lang_item(LangItem::AsyncGenPending, None), + tcx.require_lang_item(LangItem::AsyncGenPending, source_info.span), tcx.mk_args(&[yield_ty.into()]), ), full_yield_ty, @@ -404,7 +405,7 @@ pub(super) fn expand_async_drops<'tcx>( } else { // value needed only for return-yields or gen-coroutines, so just const here Operand::Constant(Box::new(ConstOperand { - span: body.span, + span: source_info.span, user_ty: None, const_: Const::from_bool(tcx, false), })) @@ -595,7 +596,7 @@ pub(super) fn create_coroutine_drop_shim<'tcx>( // Update the body's def to become the drop glue. let coroutine_instance = body.source.instance; - let drop_in_place = tcx.require_lang_item(LangItem::DropInPlace, None); + let drop_in_place = tcx.require_lang_item(LangItem::DropInPlace, body.span); let drop_instance = InstanceKind::DropGlue(drop_in_place, Some(coroutine_ty)); // Temporary change MirSource to coroutine's instance so that dump_mir produces more sensible @@ -666,7 +667,7 @@ pub(super) fn create_coroutine_drop_shim_async<'tcx>( } // Replace the return variable: Poll to Poll<()> - let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)); + let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, body.span)); let poll_enum = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()])); body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(poll_enum, source_info); @@ -717,7 +718,7 @@ pub(super) fn create_coroutine_drop_shim_proxy_async<'tcx>( let source_info = SourceInfo::outermost(body.span); // Replace the return variable: Poll to Poll<()> - let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)); + let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, body.span)); let poll_enum = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()])); body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(poll_enum, source_info); diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index c15d7d6f732..3a5e2620b14 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -235,11 +235,8 @@ where let (fut_ty, drop_fn_def_id, trait_args) = if call_destructor_only { // Resolving obj.() - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::AsyncDrop, Some(span)), - [drop_ty], - ); + let trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::AsyncDrop, span), [drop_ty]); let (drop_trait, trait_args) = match tcx.codegen_select_candidate( ty::TypingEnv::fully_monomorphized().as_query_input(trait_ref), ) { @@ -292,7 +289,7 @@ where (sig.output(), drop_fn_def_id, trait_args) } else { // Resolving async_drop_in_place function for drop_ty - let drop_fn_def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, Some(span)); + let drop_fn_def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, span); let trait_args = tcx.mk_args(&[drop_ty.into()]); let sig = tcx.fn_sig(drop_fn_def_id).instantiate(tcx, trait_args); let sig = tcx.instantiate_bound_regions_with_erased(sig); @@ -319,7 +316,7 @@ where // pin_obj_place preparation let pin_obj_new_unchecked_fn = Ty::new_fn_def( tcx, - tcx.require_lang_item(LangItem::PinNewUnchecked, Some(span)), + tcx.require_lang_item(LangItem::PinNewUnchecked, span), [GenericArg::from(obj_ref_ty)], ); let pin_obj_ty = pin_obj_new_unchecked_fn.fn_sig(tcx).output().no_bound_vars().unwrap(); @@ -937,7 +934,7 @@ where fn destructor_call_block_sync(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> BasicBlock { debug!("destructor_call_block_sync({:?}, {:?})", self, succ); let tcx = self.tcx(); - let drop_trait = tcx.require_lang_item(LangItem::Drop, None); + let drop_trait = tcx.require_lang_item(LangItem::Drop, DUMMY_SP); let drop_fn = tcx.associated_item_def_ids(drop_trait)[0]; let ty = self.place_ty(self.place); diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 9688ac8ed2e..6d45bbc6e16 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -98,7 +98,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< build_call_shim(tcx, instance, None, CallKind::Direct(def_id)) } ty::InstanceKind::ClosureOnceShim { call_once: _, track_caller: _ } => { - let fn_mut = tcx.require_lang_item(LangItem::FnMut, None); + let fn_mut = tcx.require_lang_item(LangItem::FnMut, DUMMY_SP); let call_mut = tcx .associated_items(fn_mut) .in_definition_order() diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index fbc8ee9b06c..fd7b7362cd9 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -64,7 +64,7 @@ pub(super) fn build_async_drop_shim<'tcx>( let needs_async_drop = drop_ty.needs_async_drop(tcx, typing_env); let needs_sync_drop = !needs_async_drop && drop_ty.needs_drop(tcx, typing_env); - let resume_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + let resume_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP)); let resume_ty = Ty::new_adt(tcx, resume_adt, ty::List::empty()); let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig( @@ -220,7 +220,7 @@ fn build_adrop_for_coroutine_shim<'tcx>( body.source.instance = instance; body.phase = MirPhase::Runtime(RuntimePhase::Initial); body.var_debug_info.clear(); - let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, Some(span))); + let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span)); let args = tcx.mk_args(&[proxy_ref.into()]); let pin_proxy_ref = Ty::new_adt(tcx, pin_adt_ref, args); @@ -308,10 +308,10 @@ fn build_adrop_for_adrop_shim<'tcx>( let cor_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, impl_ty); // ret_ty = `Poll<()>` - let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)); + let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, span)); let ret_ty = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()])); // env_ty = `Pin<&mut proxy_ty>` - let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None)); + let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span)); let env_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[proxy_ref.into()])); // sig = `fn (Pin<&mut proxy_ty>, &mut Context) -> Poll<()>` let sig = tcx.mk_fn_sig( @@ -376,7 +376,7 @@ fn build_adrop_for_adrop_shim<'tcx>( let cor_pin_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[cor_ref.into()])); let cor_pin_place = Place::from(locals.push(LocalDecl::new(cor_pin_ty, span))); - let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, Some(span)); + let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, span); // call Pin::new_unchecked(&mut impl_cor) blocks.push(BasicBlockData { statements, @@ -396,7 +396,7 @@ fn build_adrop_for_adrop_shim<'tcx>( }); // When dropping async drop coroutine, we continue its execution: // we call impl::poll (impl_layout, ctx) - let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, None); + let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, span); let resume_ctx = Place::from(Local::new(2)); blocks.push(BasicBlockData { statements: vec![], diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index c8aa7588d03..fd91508cc11 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1253,7 +1253,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.tcx, self.tcx.require_lang_item( LangItem::CoerceUnsized, - Some(self.body.source_info(location).span), + self.body.source_info(location).span, ), [op_ty, *target_type], )) { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 1ee977a5457..173030e0326 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -781,7 +781,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { let tcx = self.tcx; let push_mono_lang_item = |this: &mut Self, lang_item: LangItem| { - let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source))); + let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, source)); if tcx.should_codegen_locally(instance) { this.used_items.push(create_fn_mono_item(tcx, instance, source)); } @@ -921,7 +921,7 @@ fn visit_instance_use<'tcx>( // be lowered in codegen to nothing or a call to panic_nounwind. So if we encounter any // of those intrinsics, we need to include a mono item for panic_nounwind, else we may try to // codegen a call to that function without generating code for the function itself. - let def_id = tcx.require_lang_item(LangItem::PanicNounwind, None); + let def_id = tcx.require_lang_item(LangItem::PanicNounwind, source); let panic_instance = Instance::mono(tcx, def_id); if tcx.should_codegen_locally(panic_instance) { output.push(create_fn_mono_item(tcx, panic_instance, source)); diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 5c66017bc61..05683940cba 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -29,7 +29,7 @@ fn custom_coerce_unsize_info<'tcx>( ) -> Result { let trait_ref = ty::TraitRef::new( tcx.tcx, - tcx.require_lang_item(LangItem::CoerceUnsized, Some(tcx.span)), + tcx.require_lang_item(LangItem::CoerceUnsized, tcx.span), [source_ty, target_ty], ); diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index d2917478e4e..c69991f3fb2 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{ TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UintTy, }; use rustc_span::def_id::DefId; -use rustc_span::sym; +use rustc_span::{DUMMY_SP, sym}; use rustc_trait_selection::traits; use tracing::{debug, instrument}; @@ -414,7 +414,7 @@ pub(crate) fn transform_instance<'tcx>( } ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() { hir::CoroutineKind::Coroutine(..) => ( - tcx.require_lang_item(LangItem::Coroutine, None), + tcx.require_lang_item(LangItem::Coroutine, DUMMY_SP), Some(instance.args.as_coroutine().resume_ty()), ), hir::CoroutineKind::Desugared(desugaring, _) => { @@ -423,11 +423,11 @@ pub(crate) fn transform_instance<'tcx>( hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator, hir::CoroutineDesugaring::Gen => LangItem::Iterator, }; - (tcx.require_lang_item(lang_item, None), None) + (tcx.require_lang_item(lang_item, DUMMY_SP), None) } }, ty::CoroutineClosure(..) => ( - tcx.require_lang_item(LangItem::FnOnce, None), + tcx.require_lang_item(LangItem::FnOnce, DUMMY_SP), Some( tcx.instantiate_bound_regions_with_erased( instance.args.as_coroutine_closure().coroutine_closure_sig(), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 8e2137da655..2c16672d786 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -73,7 +73,7 @@ use rustc_middle::ty::{ TypeVisitableExt, }; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::{BytePos, DesugaringKind, Pos, Span, sym}; +use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym}; use tracing::{debug, instrument}; use crate::error_reporting::TypeErrCtxt; @@ -194,7 +194,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => return None, }; - let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + let future_trait = self.tcx.require_lang_item(LangItem::Future, DUMMY_SP); let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; self.tcx diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs index d8b405e904c..8a67e4ccd45 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs @@ -6,7 +6,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::{LangItem, lang_items}; use rustc_middle::ty::{AssocItemContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv}; -use rustc_span::{DesugaringKind, Ident, Span, sym}; +use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, sym}; use tracing::debug; use crate::traits::specialization_graph; @@ -31,9 +31,9 @@ impl CallDesugaringKind { pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId { match self { Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(), - Self::ForLoopNext => tcx.require_lang_item(LangItem::Iterator, None), + Self::ForLoopNext => tcx.require_lang_item(LangItem::Iterator, DUMMY_SP), Self::QuestionBranch | Self::TryBlockFromOutput => { - tcx.require_lang_item(LangItem::Try, None) + tcx.require_lang_item(LangItem::Try, DUMMY_SP) } Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(), Self::Await => tcx.get_diagnostic_item(sym::IntoFuture).unwrap(), diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 9c301373cf9..3b7fd8b7a20 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -955,7 +955,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return false; }; - let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None); + let clone_trait = self.tcx.require_lang_item(LangItem::Clone, obligation.cause.span); let has_clone = |ty| { self.type_implements_trait(clone_trait, [ty], obligation.param_env) .must_apply_modulo_regions() @@ -3625,7 +3625,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, span: Span, ) { - let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + let future_trait = self.tcx.require_lang_item(LangItem::Future, span); let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); let impls_future = self.type_implements_trait( @@ -4141,7 +4141,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let pred = ty::Binder::dummy(ty::TraitPredicate { trait_ref: ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Clone, Some(span)), + tcx.require_lang_item(LangItem::Clone, span), [*ty], ), polarity: ty::PredicatePolarity::Positive, diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 0dab3adadb0..0118321befb 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -38,7 +38,7 @@ impl<'tcx> InferCtxt<'tcx> { return self.tcx.type_is_copy_modulo_regions(self.typing_env(param_env), ty); } - let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None); + let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, DUMMY_SP); // This can get called from typeck (by euv), and `moves_by_default` // rightly refuses to work with inference variables, but @@ -49,7 +49,7 @@ impl<'tcx> InferCtxt<'tcx> { fn type_is_clone_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); - let clone_def_id = self.tcx.require_lang_item(LangItem::Clone, None); + let clone_def_id = self.tcx.require_lang_item(LangItem::Clone, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, clone_def_id) } @@ -59,12 +59,12 @@ impl<'tcx> InferCtxt<'tcx> { ty: Ty<'tcx>, ) -> bool { let ty = self.resolve_vars_if_possible(ty); - let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, None); + let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, use_cloned_def_id) } fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + let lang_item = self.tcx.require_lang_item(LangItem::Sized, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item) } diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index cc5861b5a1f..e77d9e32cb9 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -248,7 +248,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( obligation: &HostEffectObligation<'tcx>, ) -> Result>, EvaluationFailure> { let tcx = selcx.tcx(); - let destruct_def_id = tcx.require_lang_item(LangItem::Destruct, None); + let destruct_def_id = tcx.require_lang_item(LangItem::Destruct, obligation.cause.span); let self_ty = obligation.predicate.self_ty(); let const_conditions = match *self_ty.kind() { @@ -267,7 +267,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution), // `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold. Some(hir::Constness::Const) => { - let drop_def_id = tcx.require_lang_item(LangItem::Drop, None); + let drop_def_id = tcx.require_lang_item(LangItem::Drop, obligation.cause.span); let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]); const_conditions.push(drop_trait_ref); } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index a4b6f330b9d..393f458bea2 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -157,7 +157,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( parent_cause.clone(), param_env, inner_ty, - tcx.require_lang_item(lang_item, Some(parent_cause.span)), + tcx.require_lang_item(lang_item, parent_cause.span), ); let errors = ocx.select_all_or_error(); @@ -193,7 +193,7 @@ pub fn all_fields_implement_trait<'tcx>( parent_cause: ObligationCause<'tcx>, lang_item: LangItem, ) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> { - let trait_def_id = tcx.require_lang_item(lang_item, Some(parent_cause.span)); + let trait_def_id = tcx.require_lang_item(lang_item, parent_cause.span); let mut infringing = Vec::new(); for variant in adt.variants() { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index ed0f34b5aa9..6dd80551980 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1117,7 +1117,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( selcx.tcx(), selcx.tcx().require_lang_item( LangItem::Sized, - Some(obligation.cause.span), + obligation.cause.span, ), [self_ty], ), @@ -1317,7 +1317,7 @@ fn confirm_coroutine_candidate<'cx, 'tcx>( let tcx = selcx.tcx(); - let coroutine_def_id = tcx.require_lang_item(LangItem::Coroutine, None); + let coroutine_def_id = tcx.require_lang_item(LangItem::Coroutine, obligation.cause.span); let (trait_ref, yield_ty, return_ty) = super::util::coroutine_trait_ref_and_outputs( tcx, @@ -1375,7 +1375,7 @@ fn confirm_future_candidate<'cx, 'tcx>( debug!(?obligation, ?coroutine_sig, ?obligations, "confirm_future_candidate"); let tcx = selcx.tcx(); - let fut_def_id = tcx.require_lang_item(LangItem::Future, None); + let fut_def_id = tcx.require_lang_item(LangItem::Future, obligation.cause.span); let (trait_ref, return_ty) = super::util::future_trait_ref_and_outputs( tcx, @@ -1421,7 +1421,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>( debug!(?obligation, ?gen_sig, ?obligations, "confirm_iterator_candidate"); let tcx = selcx.tcx(); - let iter_def_id = tcx.require_lang_item(LangItem::Iterator, None); + let iter_def_id = tcx.require_lang_item(LangItem::Iterator, obligation.cause.span); let (trait_ref, yield_ty) = super::util::iterator_trait_ref_and_outputs( tcx, @@ -1467,7 +1467,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>( debug!(?obligation, ?gen_sig, ?obligations, "confirm_async_iterator_candidate"); let tcx = selcx.tcx(); - let iter_def_id = tcx.require_lang_item(LangItem::AsyncIterator, None); + let iter_def_id = tcx.require_lang_item(LangItem::AsyncIterator, obligation.cause.span); let (trait_ref, yield_ty) = super::util::async_iterator_trait_ref_and_outputs( tcx, @@ -1511,12 +1511,13 @@ fn confirm_builtin_candidate<'cx, 'tcx>( let trait_def_id = tcx.trait_of_item(item_def_id).unwrap(); let args = tcx.mk_args(&[self_ty.into()]); let (term, obligations) = if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) { - let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); + let discriminant_def_id = + tcx.require_lang_item(LangItem::Discriminant, obligation.cause.span); assert_eq!(discriminant_def_id, item_def_id); (self_ty.discriminant_ty(tcx).into(), PredicateObligations::new()) } else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) { - let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); + let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, obligation.cause.span); assert_eq!(metadata_def_id, item_def_id); let mut obligations = PredicateObligations::new(); @@ -1538,7 +1539,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( // exist. Instead, `Pointee` should be a supertrait of `Sized`. let sized_predicate = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)), + tcx.require_lang_item(LangItem::Sized, obligation.cause.span), [self_ty], ); obligations.push(obligation.with(tcx, sized_predicate)); @@ -1620,7 +1621,7 @@ fn confirm_closure_candidate<'cx, 'tcx>( ) } else { let upvars_projection_def_id = - tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); + tcx.require_lang_item(LangItem::AsyncFnKindUpvars, obligation.cause.span); let tupled_upvars_ty = Ty::new_projection( tcx, upvars_projection_def_id, @@ -1681,8 +1682,9 @@ fn confirm_callable_candidate<'cx, 'tcx>( debug!(?obligation, ?fn_sig, "confirm_callable_candidate"); - let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, None); - let fn_once_output_def_id = tcx.require_lang_item(LangItem::FnOnceOutput, None); + let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, obligation.cause.span); + let fn_once_output_def_id = + tcx.require_lang_item(LangItem::FnOnceOutput, obligation.cause.span); let predicate = super::util::closure_trait_ref_and_return_type( tcx, @@ -1740,8 +1742,8 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( args.coroutine_captures_by_ref_ty(), ) } else { - let upvars_projection_def_id = - tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); + let upvars_projection_def_id = tcx + .require_lang_item(LangItem::AsyncFnKindUpvars, obligation.cause.span); // When we don't know the closure kind (and therefore also the closure's upvars, // which are computed at the same time), we must delay the computation of the // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait @@ -1798,7 +1800,8 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let term = match item_name { sym::CallOnceFuture | sym::CallRefFuture => sig.output(), sym::Output => { - let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None); + let future_output_def_id = + tcx.require_lang_item(LangItem::FutureOutput, obligation.cause.span); Ty::new_projection(tcx, future_output_def_id, [sig.output()]) } name => bug!("no such associated type: {name}"), @@ -1831,7 +1834,8 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let term = match item_name { sym::CallOnceFuture | sym::CallRefFuture => sig.output(), sym::Output => { - let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None); + let future_output_def_id = + tcx.require_lang_item(LangItem::FutureOutput, obligation.cause.span); Ty::new_projection(tcx, future_output_def_id, [sig.output()]) } name => bug!("no such associated type: {name}"), diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index c9169127e0b..7acf0f990d1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -318,7 +318,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let make_freeze_obl = |ty| { let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Freeze, None), + tcx.require_lang_item(LangItem::Freeze, obligation.cause.span), [ty::GenericArg::from(ty)], ); Obligation::with_depth( @@ -657,7 +657,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); let tr = ty::TraitRef::new( self.tcx(), - self.tcx().require_lang_item(LangItem::Sized, Some(cause.span)), + self.tcx().require_lang_item(LangItem::Sized, cause.span), [output_ty], ); nested.push(Obligation::new(self.infcx.tcx, cause, obligation.param_env, tr)); @@ -877,14 +877,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); // We must additionally check that the return type impls `Future + Sized`. - let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + let future_trait_def_id = + tcx.require_lang_item(LangItem::Future, obligation.cause.span); nested.push(obligation.with( tcx, sig.output().map_bound(|output_ty| { ty::TraitRef::new(tcx, future_trait_def_id, [output_ty]) }), )); - let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, None); + let sized_trait_def_id = + tcx.require_lang_item(LangItem::Sized, obligation.cause.span); nested.push(obligation.with( tcx, sig.output().map_bound(|output_ty| { @@ -906,13 +908,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); // We must additionally check that the return type impls `Future + Sized`. - let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + let future_trait_def_id = + tcx.require_lang_item(LangItem::Future, obligation.cause.span); let placeholder_output_ty = self.infcx.enter_forall_and_leak_universe(sig.output()); nested.push(obligation.with( tcx, ty::TraitRef::new(tcx, future_trait_def_id, [placeholder_output_ty]), )); - let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, None); + let sized_trait_def_id = + tcx.require_lang_item(LangItem::Sized, obligation.cause.span); nested.push(obligation.with( tcx, sig.output().map_bound(|output_ty| { @@ -946,10 +950,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, ty::TraitRef::new( self.tcx(), - self.tcx().require_lang_item( - LangItem::AsyncFnKindHelper, - Some(obligation.cause.span), - ), + self.tcx() + .require_lang_item(LangItem::AsyncFnKindHelper, obligation.cause.span), [kind_ty, Ty::from_closure_kind(self.tcx(), goal_kind)], ), )); @@ -1165,7 +1167,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We can only make objects from sized types. let tr = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)), + tcx.require_lang_item(LangItem::Sized, obligation.cause.span), [source], ); nested.push(predicate_to_obligation(tr.upcast(tcx))); @@ -1359,7 +1361,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self_ty.map_bound(|ty| { ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Copy, Some(obligation.cause.span)), + tcx.require_lang_item(LangItem::Copy, obligation.cause.span), [ty], ) }), @@ -1411,7 +1413,7 @@ fn pointer_like_goal_for_rpitit<'tcx>( ty::Binder::bind_with_vars( ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::PointerLike, Some(cause.span)), + tcx.require_lang_item(LangItem::PointerLike, cause.span), [Ty::new_projection_from_args(tcx, rpitit_item, args)], ), tcx.mk_bound_variable_kinds(&bound_vars), diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 3018dad8e09..416865e861e 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -541,7 +541,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let cause = self.cause(cause); let trait_ref = ty::TraitRef::new( self.tcx(), - self.tcx().require_lang_item(LangItem::Sized, Some(cause.span)), + self.tcx().require_lang_item(LangItem::Sized, cause.span), [subty], ); self.out.push(traits::Obligation::with_depth( @@ -895,7 +895,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { self.tcx(), self.tcx().require_lang_item( LangItem::BikeshedGuaranteedNoDrop, - Some(self.span), + self.span, ), [ty], ) diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 83d7416b03e..bb5187e4f5c 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -11,6 +11,7 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt}; use rustc_session::config::OptLevel; +use rustc_span::DUMMY_SP; use rustc_span::def_id::DefId; use rustc_target::callconv::{ AbiMap, ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, FnAbi, PassMode, @@ -124,7 +125,7 @@ fn fn_sig_for_fn_abi<'tcx>( let env_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty); - let pin_did = tcx.require_lang_item(LangItem::Pin, None); + let pin_did = tcx.require_lang_item(LangItem::Pin, DUMMY_SP); let pin_adt_ref = tcx.adt_def(pin_did); let pin_args = tcx.mk_args(&[env_ty.into()]); let env_ty = match coroutine_kind { @@ -149,7 +150,7 @@ fn fn_sig_for_fn_abi<'tcx>( // The signature should be `Future::poll(_, &mut Context<'_>) -> Poll` assert_eq!(sig.yield_ty, tcx.types.unit); - let poll_did = tcx.require_lang_item(LangItem::Poll, None); + let poll_did = tcx.require_lang_item(LangItem::Poll, DUMMY_SP); let poll_adt_ref = tcx.adt_def(poll_did); let poll_args = tcx.mk_args(&[sig.return_ty.into()]); let ret_ty = Ty::new_adt(tcx, poll_adt_ref, poll_args); @@ -160,7 +161,7 @@ fn fn_sig_for_fn_abi<'tcx>( { if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() { let expected_adt = - tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP)); assert_eq!(*resume_ty_adt, expected_adt); } else { panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty); @@ -172,7 +173,7 @@ fn fn_sig_for_fn_abi<'tcx>( } hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => { // The signature should be `Iterator::next(_) -> Option` - let option_did = tcx.require_lang_item(LangItem::Option, None); + let option_did = tcx.require_lang_item(LangItem::Option, DUMMY_SP); let option_adt_ref = tcx.adt_def(option_did); let option_args = tcx.mk_args(&[sig.yield_ty.into()]); let ret_ty = Ty::new_adt(tcx, option_adt_ref, option_args); @@ -196,7 +197,7 @@ fn fn_sig_for_fn_abi<'tcx>( { if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() { let expected_adt = - tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP)); assert_eq!(*resume_ty_adt, expected_adt); } else { panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty); @@ -208,7 +209,7 @@ fn fn_sig_for_fn_abi<'tcx>( } hir::CoroutineKind::Coroutine(_) => { // The signature should be `Coroutine::resume(_, Resume) -> CoroutineState` - let state_did = tcx.require_lang_item(LangItem::CoroutineState, None); + let state_did = tcx.require_lang_item(LangItem::CoroutineState, DUMMY_SP); let state_adt_ref = tcx.adt_def(state_did); let state_args = tcx.mk_args(&[sig.yield_ty.into(), sig.return_ty.into()]); let ret_ty = Ty::new_adt(tcx, state_adt_ref, state_args); diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index bb2c4172b08..7219f40710e 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -4,6 +4,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::DUMMY_SP; use rustc_trait_selection::traits; fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { @@ -42,7 +43,7 @@ fn is_item_raw<'tcx>( item: LangItem, ) -> bool { let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(query.typing_env); - let trait_def_id = tcx.require_lang_item(item, None); + let trait_def_id = tcx.require_lang_item(item, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, query.value, trait_def_id) } diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs index 0b4efab1d9c..e900264a76c 100644 --- a/compiler/rustc_ty_utils/src/structural_match.rs +++ b/compiler/rustc_ty_utils/src/structural_match.rs @@ -16,8 +16,7 @@ fn has_structural_eq_impl<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool { let ocx = ObligationCtxt::new(infcx); // require `#[derive(PartialEq)]` - let structural_peq_def_id = - infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span)); + let structural_peq_def_id = infcx.tcx.require_lang_item(LangItem::StructuralPeq, cause.span); ocx.register_bound(cause.clone(), ty::ParamEnv::empty(), adt_ty, structural_peq_def_id); // We deliberately skip *reporting* fulfillment errors (via diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 330aaa25d13..e39fd6b947b 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -104,7 +104,7 @@ fn adt_sized_constraint<'tcx>( // perf hack: if there is a `constraint_ty: Sized` bound, then we know // that the type is sized and do not need to check it on the impl. - let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, None); + let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, DUMMY_SP); let predicates = tcx.predicates_of(def.did()).predicates; if predicates.iter().any(|(p, _)| { p.as_trait_clause().is_some_and(|trait_pred| { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9e46d0b47e9..4030bd45866 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1277,7 +1277,7 @@ impl GenericBound { } fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound { - let did = cx.tcx.require_lang_item(LangItem::Sized, None); + let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP); let empty = ty::Binder::dummy(ty::GenericArgs::empty()); let path = clean_middle_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 5b4ec12cbec..8e16f943e9f 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -439,7 +439,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx> tcx, ObligationCause::dummy_with_span(body.span), param_env, - TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]), + TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, body.span), [ty]), ); let mut selcx = SelectionContext::new(&infcx); diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 549d859a6e1..a6bce830149 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -247,7 +247,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => { // Call the lang item associated with this message. - let fn_item = this.tcx.require_lang_item(msg.panic_function(), None); + let fn_item = this.tcx.require_lang_item(msg.panic_function(), this.tcx.span); let instance = ty::Instance::mono(this.tcx.tcx, fn_item); this.call_function( instance, diff --git a/tests/ui/lang-items/lang-item-generic-requirements.rs b/tests/ui/lang-items/lang-item-generic-requirements.rs index 7676b5557d2..25a4ff283ba 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.rs +++ b/tests/ui/lang-items/lang-item-generic-requirements.rs @@ -48,6 +48,7 @@ fn ice() { // Use index let arr = [0; 5]; + //~^ ERROR requires `copy` lang_item let _ = arr[2]; //~^ ERROR cannot index into a value of type `[{integer}; 5]` @@ -61,5 +62,3 @@ fn ice() { // use `start` fn main() {} - -//~? ERROR requires `copy` lang_item diff --git a/tests/ui/lang-items/lang-item-generic-requirements.stderr b/tests/ui/lang-items/lang-item-generic-requirements.stderr index 409fa05d637..c82bdb00fd1 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.stderr +++ b/tests/ui/lang-items/lang-item-generic-requirements.stderr @@ -77,13 +77,13 @@ LL | r + a; | {integer} error[E0608]: cannot index into a value of type `[{integer}; 5]` - --> $DIR/lang-item-generic-requirements.rs:51:16 + --> $DIR/lang-item-generic-requirements.rs:52:16 | LL | let _ = arr[2]; | ^^^ error[E0308]: mismatched types - --> $DIR/lang-item-generic-requirements.rs:58:17 + --> $DIR/lang-item-generic-requirements.rs:59:17 | LL | let _: () = Foo; | -- ^^^ expected `()`, found `Foo` @@ -91,6 +91,10 @@ LL | let _: () = Foo; | expected due to this error: requires `copy` lang_item + --> $DIR/lang-item-generic-requirements.rs:50:16 + | +LL | let arr = [0; 5]; + | ^ error: aborting due to 12 previous errors -- cgit 1.4.1-3-g733a5 From fde8a8d518e3bd9124bfe4028e3c45f7dcf34593 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 13 May 2024 20:32:33 +0200 Subject: Optimize `Seek::stream_len` impl for `File` It uses the file metadata on Unix with a fallback for files incorrectly reported as zero-sized. It uses `GetFileSizeEx` on Windows. This reduces the number of syscalls needed for determining the file size of an open file from 3 to 1. --- library/std/src/fs.rs | 36 ++++++++++++++++++++++++ library/std/src/io/mod.rs | 24 +++++++++------- library/std/src/sys/fs/hermit.rs | 4 +++ library/std/src/sys/fs/solid.rs | 4 +++ library/std/src/sys/fs/uefi.rs | 4 +++ library/std/src/sys/fs/unix.rs | 9 ++++++ library/std/src/sys/fs/unsupported.rs | 4 +++ library/std/src/sys/fs/wasi.rs | 4 +++ library/std/src/sys/fs/windows.rs | 8 ++++++ library/std/src/sys/pal/windows/c/bindings.txt | 1 + library/std/src/sys/pal/windows/c/windows_sys.rs | 1 + 11 files changed, 89 insertions(+), 10 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 711efc7d011..6cbf8301e01 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1311,9 +1311,39 @@ impl Write for &File { } #[stable(feature = "rust1", since = "1.0.0")] impl Seek for &File { + /// Seek to an offset, in bytes in a file. + /// + /// See [`Seek::seek`] docs for more info. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `lseek64` function on Unix + /// and the `SetFilePointerEx` function on Windows. Note that this [may + /// change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior fn seek(&mut self, pos: SeekFrom) -> io::Result { self.inner.seek(pos) } + + /// Returns the length of this file (in bytes). + /// + /// See [`Seek::stream_len`] docs for more info. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `statx` function on Linux + /// (with fallbacks) and the `GetFileSizeEx` function on Windows. Note that + /// this [may change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior + fn stream_len(&mut self) -> io::Result { + if let Some(result) = self.inner.size() { + return result; + } + io::stream_len_default(self) + } + fn stream_position(&mut self) -> io::Result { self.inner.tell() } @@ -1363,6 +1393,9 @@ impl Seek for File { fn seek(&mut self, pos: SeekFrom) -> io::Result { (&*self).seek(pos) } + fn stream_len(&mut self) -> io::Result { + (&*self).stream_len() + } fn stream_position(&mut self) -> io::Result { (&*self).stream_position() } @@ -1412,6 +1445,9 @@ impl Seek for Arc { fn seek(&mut self, pos: SeekFrom) -> io::Result { (&**self).seek(pos) } + fn stream_len(&mut self) -> io::Result { + (&**self).stream_len() + } fn stream_position(&mut self) -> io::Result { (&**self).stream_position() } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 03f5f838311..859f189a6c8 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2062,16 +2062,7 @@ pub trait Seek { /// ``` #[unstable(feature = "seek_stream_len", issue = "59359")] fn stream_len(&mut self) -> Result { - let old_pos = self.stream_position()?; - let len = self.seek(SeekFrom::End(0))?; - - // Avoid seeking a third time when we were already at the end of the - // stream. The branch is usually way cheaper than a seek operation. - if old_pos != len { - self.seek(SeekFrom::Start(old_pos))?; - } - - Ok(len) + stream_len_default(self) } /// Returns the current seek position from the start of the stream. @@ -2132,6 +2123,19 @@ pub trait Seek { } } +pub(crate) fn stream_len_default(self_: &mut T) -> Result { + let old_pos = self_.stream_position()?; + let len = self_.seek(SeekFrom::End(0))?; + + // Avoid seeking a third time when we were already at the end of the + // stream. The branch is usually way cheaper than a seek operation. + if old_pos != len { + self_.seek(SeekFrom::Start(old_pos))?; + } + + Ok(len) +} + /// Enumeration of possible methods to seek within an I/O object. /// /// It is used by the [`Seek`] trait. diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index a9774bef9e3..175d919c289 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -422,6 +422,10 @@ impl File { self.0.seek(pos) } + pub fn size(&self) -> Option> { + None + } + pub fn tell(&self) -> io::Result { self.0.tell() } diff --git a/library/std/src/sys/fs/solid.rs b/library/std/src/sys/fs/solid.rs index 3bfb39bac95..808a9582911 100644 --- a/library/std/src/sys/fs/solid.rs +++ b/library/std/src/sys/fs/solid.rs @@ -459,6 +459,10 @@ impl File { self.tell() } + pub fn size(&self) -> Option> { + None + } + pub fn tell(&self) -> io::Result { unsafe { let mut out_offset = MaybeUninit::uninit(); diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 416c90b98b6..5763d7862f5 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -280,6 +280,10 @@ impl File { self.0 } + pub fn size(&self) -> Option> { + self.0 + } + pub fn tell(&self) -> io::Result { self.0 } diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index a3e520fdeef..dc278274f00 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1464,6 +1464,15 @@ impl File { Ok(n as u64) } + pub fn size(&self) -> Option> { + match self.file_attr().map(|attr| attr.size()) { + // Fall back to default implementation if the returned size is 0, + // we might be in a proc mount. + Ok(0) => None, + result => Some(result), + } + } + pub fn tell(&self) -> io::Result { self.seek(SeekFrom::Current(0)) } diff --git a/library/std/src/sys/fs/unsupported.rs b/library/std/src/sys/fs/unsupported.rs index 0ff9533c047..efaddb51b37 100644 --- a/library/std/src/sys/fs/unsupported.rs +++ b/library/std/src/sys/fs/unsupported.rs @@ -259,6 +259,10 @@ impl File { self.0 } + pub fn size(&self) -> Option> { + self.0 + } + pub fn tell(&self) -> io::Result { self.0 } diff --git a/library/std/src/sys/fs/wasi.rs b/library/std/src/sys/fs/wasi.rs index ebfc7377a2e..b65d86de12a 100644 --- a/library/std/src/sys/fs/wasi.rs +++ b/library/std/src/sys/fs/wasi.rs @@ -516,6 +516,10 @@ impl File { self.fd.seek(pos) } + pub fn size(&self) -> Option> { + None + } + pub fn tell(&self) -> io::Result { self.fd.tell() } diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index d01a572ac73..a95709b4891 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -616,6 +616,14 @@ impl File { Ok(newpos as u64) } + pub fn size(&self) -> Option> { + let mut result = 0; + Some( + cvt(unsafe { c::GetFileSizeEx(self.handle.as_raw_handle(), &mut result) }) + .map(|_| result as u64), + ) + } + pub fn tell(&self) -> io::Result { self.seek(SeekFrom::Current(0)) } diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index d5fbb453c6f..a99c474c763 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2156,6 +2156,7 @@ GetExitCodeProcess GetFileAttributesW GetFileInformationByHandle GetFileInformationByHandleEx +GetFileSizeEx GetFileType GETFINALPATHNAMEBYHANDLE_FLAGS GetFinalPathNameByHandleW diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index eb2914b8644..95bf8040229 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -44,6 +44,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetExitCodeProcess(hprocess : windows_targets::link!("kernel32.dll" "system" fn GetFileAttributesW(lpfilename : PCWSTR) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandle(hfile : HANDLE, lpfileinformation : *mut BY_HANDLE_FILE_INFORMATION) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandleEx(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *mut core::ffi::c_void, dwbuffersize : u32) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn GetFileSizeEx(hfile : HANDLE, lpfilesize : *mut i64) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn GetFileType(hfile : HANDLE) -> FILE_TYPE); windows_targets::link!("kernel32.dll" "system" fn GetFinalPathNameByHandleW(hfile : HANDLE, lpszfilepath : PWSTR, cchfilepath : u32, dwflags : GETFINALPATHNAMEBYHANDLE_FLAGS) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetFullPathNameW(lpfilename : PCWSTR, nbufferlength : u32, lpbuffer : PWSTR, lpfilepart : *mut PWSTR) -> u32); -- cgit 1.4.1-3-g733a5 From 4b1e28b21f78491d4ae187a52ebd5436edef6281 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 9 Jan 2025 10:31:03 +0100 Subject: Clarify description of `Seek::stream_len` It can only describe the inner workings of the default implementation, other implementations might not be implemented using seeks at all. --- library/std/src/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 859f189a6c8..20c82b64bcc 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2028,7 +2028,7 @@ pub trait Seek { /// Returns the length of this stream (in bytes). /// - /// This method is implemented using up to three seek operations. If this + /// The default implementation uses up to three seek operations. If this /// method returns successfully, the seek position is unchanged (i.e. the /// position before calling this method is the same as afterwards). /// However, if this method returns an error, the seek position is -- cgit 1.4.1-3-g733a5 From 7b8f5197940ac627f54fde4eaef98274f58f48fd Mon Sep 17 00:00:00 2001 From: Jana Dönszelmann Date: Thu, 5 Jun 2025 16:39:22 +0200 Subject: add myself to rotation --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index a8d529cae77..bab0b1c8fc4 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1200,6 +1200,7 @@ compiler = [ "@fee1-dead", "@fmease", "@jieyouxu", + "@jdonszelmann", "@lcnr", "@Nadrieril", "@nnethercote", -- cgit 1.4.1-3-g733a5 From 9770f9bb0703add138a180fe05b2d809f3b2c178 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 3 Jun 2025 23:35:08 +0500 Subject: cleaned up some tests --- tests/ui/borrowck/rvalue-borrow-scope-error.rs | 39 +++++++ tests/ui/borrowck/rvalue-borrow-scope-error.stderr | 122 ++++++++++++++++++++ tests/ui/cleanup-rvalue-scopes-cf.rs | 35 ------ tests/ui/cleanup-rvalue-scopes-cf.stderr | 122 -------------------- tests/ui/cleanup-rvalue-scopes.rs | 128 --------------------- .../cleanup-rvalue-temp-during-incomplete-alloc.rs | 47 -------- tests/ui/cleanup-shortcircuit.rs | 23 ---- tests/ui/close-over-big-then-small-data.rs | 39 ------- tests/ui/command-line-diagnostics.rs | 7 -- tests/ui/command-line-diagnostics.stderr | 16 --- .../command-line-error-format-human.rs | 8 ++ .../command-line-error-format-human.stderr | 16 +++ tests/ui/lifetimes/rvalue-cleanup-shortcircuit.rs | 24 ++++ tests/ui/lifetimes/rvalue-lifetime-drop-timing.rs | 104 +++++++++++++++++ tests/ui/panics/rvalue-cleanup-during-box-panic.rs | 51 ++++++++ 15 files changed, 364 insertions(+), 417 deletions(-) create mode 100644 tests/ui/borrowck/rvalue-borrow-scope-error.rs create mode 100644 tests/ui/borrowck/rvalue-borrow-scope-error.stderr delete mode 100644 tests/ui/cleanup-rvalue-scopes-cf.rs delete mode 100644 tests/ui/cleanup-rvalue-scopes-cf.stderr delete mode 100644 tests/ui/cleanup-rvalue-scopes.rs delete mode 100644 tests/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs delete mode 100644 tests/ui/cleanup-shortcircuit.rs delete mode 100644 tests/ui/close-over-big-then-small-data.rs delete mode 100644 tests/ui/command-line-diagnostics.rs delete mode 100644 tests/ui/command-line-diagnostics.stderr create mode 100644 tests/ui/diagnostic-width/command-line-error-format-human.rs create mode 100644 tests/ui/diagnostic-width/command-line-error-format-human.stderr create mode 100644 tests/ui/lifetimes/rvalue-cleanup-shortcircuit.rs create mode 100644 tests/ui/lifetimes/rvalue-lifetime-drop-timing.rs create mode 100644 tests/ui/panics/rvalue-cleanup-during-box-panic.rs diff --git a/tests/ui/borrowck/rvalue-borrow-scope-error.rs b/tests/ui/borrowck/rvalue-borrow-scope-error.rs new file mode 100644 index 00000000000..5bf96e800d3 --- /dev/null +++ b/tests/ui/borrowck/rvalue-borrow-scope-error.rs @@ -0,0 +1,39 @@ +//! Test that the borrow checker prevents pointers to temporaries +//! with statement lifetimes from escaping. + +use std::ops::Drop; + +static mut FLAGS: u64 = 0; + +struct StackBox { + f: T, +} +struct AddFlags { + bits: u64, +} + +fn AddFlags(bits: u64) -> AddFlags { + AddFlags { bits } +} + +fn arg(x: &AddFlags) -> &AddFlags { + x +} + +impl AddFlags { + fn get(&self) -> &AddFlags { + self + } +} + +pub fn main() { + let x1 = arg(&AddFlags(1)); //~ ERROR temporary value dropped while borrowed + let x2 = AddFlags(1).get(); //~ ERROR temporary value dropped while borrowed + let x3 = &*arg(&AddFlags(1)); //~ ERROR temporary value dropped while borrowed + let ref x4 = *arg(&AddFlags(1)); //~ ERROR temporary value dropped while borrowed + let &ref x5 = arg(&AddFlags(1)); //~ ERROR temporary value dropped while borrowed + let x6 = AddFlags(1).get(); //~ ERROR temporary value dropped while borrowed + let StackBox { f: x7 } = StackBox { f: AddFlags(1).get() }; + //~^ ERROR temporary value dropped while borrowed + (x1, x2, x3, x4, x5, x6, x7); +} diff --git a/tests/ui/borrowck/rvalue-borrow-scope-error.stderr b/tests/ui/borrowck/rvalue-borrow-scope-error.stderr new file mode 100644 index 00000000000..bedcfce4541 --- /dev/null +++ b/tests/ui/borrowck/rvalue-borrow-scope-error.stderr @@ -0,0 +1,122 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/rvalue-borrow-scope-error.rs:30:19 + | +LL | let x1 = arg(&AddFlags(1)); + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | (x1, x2, x3, x4, x5, x6, x7); + | -- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let x1 = arg(&binding); + | + +error[E0716]: temporary value dropped while borrowed + --> $DIR/rvalue-borrow-scope-error.rs:31:14 + | +LL | let x2 = AddFlags(1).get(); + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | (x1, x2, x3, x4, x5, x6, x7); + | -- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let x2 = binding.get(); + | + +error[E0716]: temporary value dropped while borrowed + --> $DIR/rvalue-borrow-scope-error.rs:32:21 + | +LL | let x3 = &*arg(&AddFlags(1)); + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | (x1, x2, x3, x4, x5, x6, x7); + | -- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let x3 = &*arg(&binding); + | + +error[E0716]: temporary value dropped while borrowed + --> $DIR/rvalue-borrow-scope-error.rs:33:24 + | +LL | let ref x4 = *arg(&AddFlags(1)); + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | (x1, x2, x3, x4, x5, x6, x7); + | -- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let ref x4 = *arg(&binding); + | + +error[E0716]: temporary value dropped while borrowed + --> $DIR/rvalue-borrow-scope-error.rs:34:24 + | +LL | let &ref x5 = arg(&AddFlags(1)); + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | (x1, x2, x3, x4, x5, x6, x7); + | -- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let &ref x5 = arg(&binding); + | + +error[E0716]: temporary value dropped while borrowed + --> $DIR/rvalue-borrow-scope-error.rs:35:14 + | +LL | let x6 = AddFlags(1).get(); + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | (x1, x2, x3, x4, x5, x6, x7); + | -- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let x6 = binding.get(); + | + +error[E0716]: temporary value dropped while borrowed + --> $DIR/rvalue-borrow-scope-error.rs:36:44 + | +LL | let StackBox { f: x7 } = StackBox { f: AddFlags(1).get() }; + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +LL | +LL | (x1, x2, x3, x4, x5, x6, x7); + | -- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let StackBox { f: x7 } = StackBox { f: binding.get() }; + | + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/cleanup-rvalue-scopes-cf.rs b/tests/ui/cleanup-rvalue-scopes-cf.rs deleted file mode 100644 index e3cecb1bffe..00000000000 --- a/tests/ui/cleanup-rvalue-scopes-cf.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Test that the borrow checker prevents pointers to temporaries -// with statement lifetimes from escaping. - -use std::ops::Drop; - -static mut FLAGS: u64 = 0; - -struct StackBox { f: T } -struct AddFlags { bits: u64 } - -fn AddFlags(bits: u64) -> AddFlags { - AddFlags { bits: bits } -} - -fn arg(x: &AddFlags) -> &AddFlags { - x -} - -impl AddFlags { - fn get(&self) -> &AddFlags { - self - } -} - -pub fn main() { - let x1 = arg(&AddFlags(1)); //~ ERROR temporary value dropped while borrowed - let x2 = AddFlags(1).get(); //~ ERROR temporary value dropped while borrowed - let x3 = &*arg(&AddFlags(1)); //~ ERROR temporary value dropped while borrowed - let ref x4 = *arg(&AddFlags(1)); //~ ERROR temporary value dropped while borrowed - let &ref x5 = arg(&AddFlags(1)); //~ ERROR temporary value dropped while borrowed - let x6 = AddFlags(1).get(); //~ ERROR temporary value dropped while borrowed - let StackBox { f: x7 } = StackBox { f: AddFlags(1).get() }; - //~^ ERROR temporary value dropped while borrowed - (x1, x2, x3, x4, x5, x6, x7); -} diff --git a/tests/ui/cleanup-rvalue-scopes-cf.stderr b/tests/ui/cleanup-rvalue-scopes-cf.stderr deleted file mode 100644 index 425cd75141c..00000000000 --- a/tests/ui/cleanup-rvalue-scopes-cf.stderr +++ /dev/null @@ -1,122 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/cleanup-rvalue-scopes-cf.rs:26:19 - | -LL | let x1 = arg(&AddFlags(1)); - | ^^^^^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary value which is freed while still in use -... -LL | (x1, x2, x3, x4, x5, x6, x7); - | -- borrow later used here - | -help: consider using a `let` binding to create a longer lived value - | -LL ~ let binding = AddFlags(1); -LL ~ let x1 = arg(&binding); - | - -error[E0716]: temporary value dropped while borrowed - --> $DIR/cleanup-rvalue-scopes-cf.rs:27:14 - | -LL | let x2 = AddFlags(1).get(); - | ^^^^^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary value which is freed while still in use -... -LL | (x1, x2, x3, x4, x5, x6, x7); - | -- borrow later used here - | -help: consider using a `let` binding to create a longer lived value - | -LL ~ let binding = AddFlags(1); -LL ~ let x2 = binding.get(); - | - -error[E0716]: temporary value dropped while borrowed - --> $DIR/cleanup-rvalue-scopes-cf.rs:28:21 - | -LL | let x3 = &*arg(&AddFlags(1)); - | ^^^^^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary value which is freed while still in use -... -LL | (x1, x2, x3, x4, x5, x6, x7); - | -- borrow later used here - | -help: consider using a `let` binding to create a longer lived value - | -LL ~ let binding = AddFlags(1); -LL ~ let x3 = &*arg(&binding); - | - -error[E0716]: temporary value dropped while borrowed - --> $DIR/cleanup-rvalue-scopes-cf.rs:29:24 - | -LL | let ref x4 = *arg(&AddFlags(1)); - | ^^^^^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary value which is freed while still in use -... -LL | (x1, x2, x3, x4, x5, x6, x7); - | -- borrow later used here - | -help: consider using a `let` binding to create a longer lived value - | -LL ~ let binding = AddFlags(1); -LL ~ let ref x4 = *arg(&binding); - | - -error[E0716]: temporary value dropped while borrowed - --> $DIR/cleanup-rvalue-scopes-cf.rs:30:24 - | -LL | let &ref x5 = arg(&AddFlags(1)); - | ^^^^^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary value which is freed while still in use -... -LL | (x1, x2, x3, x4, x5, x6, x7); - | -- borrow later used here - | -help: consider using a `let` binding to create a longer lived value - | -LL ~ let binding = AddFlags(1); -LL ~ let &ref x5 = arg(&binding); - | - -error[E0716]: temporary value dropped while borrowed - --> $DIR/cleanup-rvalue-scopes-cf.rs:31:14 - | -LL | let x6 = AddFlags(1).get(); - | ^^^^^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary value which is freed while still in use -... -LL | (x1, x2, x3, x4, x5, x6, x7); - | -- borrow later used here - | -help: consider using a `let` binding to create a longer lived value - | -LL ~ let binding = AddFlags(1); -LL ~ let x6 = binding.get(); - | - -error[E0716]: temporary value dropped while borrowed - --> $DIR/cleanup-rvalue-scopes-cf.rs:32:44 - | -LL | let StackBox { f: x7 } = StackBox { f: AddFlags(1).get() }; - | ^^^^^^^^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary value which is freed while still in use -LL | -LL | (x1, x2, x3, x4, x5, x6, x7); - | -- borrow later used here - | -help: consider using a `let` binding to create a longer lived value - | -LL ~ let binding = AddFlags(1); -LL ~ let StackBox { f: x7 } = StackBox { f: binding.get() }; - | - -error: aborting due to 7 previous errors - -For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/cleanup-rvalue-scopes.rs b/tests/ui/cleanup-rvalue-scopes.rs deleted file mode 100644 index 09ceda065b9..00000000000 --- a/tests/ui/cleanup-rvalue-scopes.rs +++ /dev/null @@ -1,128 +0,0 @@ -//@ run-pass -#![allow(unused_braces)] -#![allow(non_snake_case)] -#![allow(unused_variables)] -// Test that destructors for rvalue temporaries run either at end of -// statement or end of block, as appropriate given the temporary -// lifetime rules. - -#![feature(box_patterns)] - -static mut FLAGS: u64 = 0; - -struct Box { f: T } -struct AddFlags { bits: u64 } - -fn AddFlags(bits: u64) -> AddFlags { - AddFlags { bits: bits } -} - -fn arg(exp: u64, _x: &AddFlags) { - check_flags(exp); -} - -fn pass(v: T) -> T { - v -} - -fn check_flags(exp: u64) { - unsafe { - let x = FLAGS; - FLAGS = 0; - println!("flags {}, expected {}", x, exp); - assert_eq!(x, exp); - } -} - -impl AddFlags { - fn check_flags<'a>(&'a self, exp: u64) -> &'a AddFlags { - check_flags(exp); - self - } - - fn bits(&self) -> u64 { - self.bits - } -} - -impl Drop for AddFlags { - fn drop(&mut self) { - unsafe { - FLAGS = FLAGS + self.bits; - } - } -} - -macro_rules! end_of_block { - ($pat:pat, $expr:expr) => ( - { - println!("end_of_block({})", stringify!({let $pat = $expr;})); - - { - // Destructor here does not run until exit from the block. - let $pat = $expr; - check_flags(0); - } - check_flags(1); - } - ) -} - -macro_rules! end_of_stmt { - ($pat:pat, $expr:expr) => ( - { - println!("end_of_stmt({})", stringify!($expr)); - - { - // Destructor here run after `let` statement - // terminates. - let $pat = $expr; - check_flags(1); - } - - check_flags(0); - } - ) -} - -pub fn main() { - - // In all these cases, we trip over the rules designed to cover - // the case where we are taking addr of rvalue and storing that - // addr into a stack slot, either via `let ref` or via a `&` in - // the initializer. - - end_of_block!(_x, AddFlags(1)); - end_of_block!(_x, &AddFlags(1)); - end_of_block!(_x, & &AddFlags(1)); - end_of_block!(_x, Box { f: AddFlags(1) }); - end_of_block!(_x, Box { f: &AddFlags(1) }); - end_of_block!(_x, Box { f: &AddFlags(1) }); - end_of_block!(_x, pass(AddFlags(1))); - end_of_block!(ref _x, AddFlags(1)); - end_of_block!(AddFlags { bits: ref _x }, AddFlags(1)); - end_of_block!(&AddFlags { bits }, &AddFlags(1)); - end_of_block!((_, ref _y), (AddFlags(1), 22)); - end_of_block!(box ref _x, std::boxed::Box::new(AddFlags(1))); - end_of_block!(box _x, std::boxed::Box::new(AddFlags(1))); - end_of_block!(_, { { check_flags(0); &AddFlags(1) } }); - end_of_block!(_, &((Box { f: AddFlags(1) }).f)); - end_of_block!(_, &(([AddFlags(1)])[0])); - - // LHS does not create a ref binding, so temporary lives as long - // as statement, and we do not move the AddFlags out: - end_of_stmt!(_, AddFlags(1)); - end_of_stmt!((_, _), (AddFlags(1), 22)); - - // `&` operator appears inside an arg to a function, - // so it is not prolonged: - end_of_stmt!(ref _x, arg(0, &AddFlags(1))); - - // autoref occurs inside receiver, so temp lifetime is not - // prolonged: - end_of_stmt!(ref _x, AddFlags(1).check_flags(0).bits()); - - // No reference is created on LHS, thus RHS is moved into - // a temporary that lives just as long as the statement. - end_of_stmt!(AddFlags { bits }, AddFlags(1)); -} diff --git a/tests/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs b/tests/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs deleted file mode 100644 index 4c59df24e4b..00000000000 --- a/tests/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs +++ /dev/null @@ -1,47 +0,0 @@ -//@ run-pass -//@ needs-unwind - -#![allow(unused_must_use)] -#![allow(dead_code)] -#![allow(unused_variables)] -// Test cleanup of rvalue temporary that occurs while `box` construction -// is in progress. This scenario revealed a rather terrible bug. The -// ingredients are: -// -// 1. Partial cleanup of `box` is in scope, -// 2. cleanup of return value from `get_bar()` is in scope, -// 3. do_it() panics. -// -// This led to a bug because `the top-most frame that was to be -// cleaned (which happens to be the partial cleanup of `box`) required -// multiple basic blocks, which led to us dropping part of the cleanup -// from the top-most frame. -// -// It's unclear how likely such a bug is to recur, but it seems like a -// scenario worth testing. - -//@ needs-threads - -use std::thread; - -enum Conzabble { - Bickwick(Foo) -} - -struct Foo { field: Box } - -fn do_it(x: &[usize]) -> Foo { - panic!() -} - -fn get_bar(x: usize) -> Vec { vec![x * 2] } - -pub fn fails() { - let x = 2; - let mut y: Vec> = Vec::new(); - y.push(Box::new(Conzabble::Bickwick(do_it(&get_bar(x))))); -} - -pub fn main() { - thread::spawn(fails).join(); -} diff --git a/tests/ui/cleanup-shortcircuit.rs b/tests/ui/cleanup-shortcircuit.rs deleted file mode 100644 index 40a5dfa94e3..00000000000 --- a/tests/ui/cleanup-shortcircuit.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ run-pass -// Test that cleanups for the RHS of shortcircuiting operators work. - - -#![allow(deref_nullptr)] - - -use std::env; - -pub fn main() { - let args: Vec = env::args().collect(); - - // Here, the rvalue `"signal".to_string()` requires cleanup. Older versions - // of the code had a problem that the cleanup scope for this - // expression was the end of the `if`, and as the `"signal".to_string()` - // expression was never evaluated, we wound up trying to clean - // uninitialized memory. - - if args.len() >= 2 && args[1] == "signal" { - // Raise a segfault. - unsafe { *std::ptr::null_mut::() = 0; } - } -} diff --git a/tests/ui/close-over-big-then-small-data.rs b/tests/ui/close-over-big-then-small-data.rs deleted file mode 100644 index d3cb1db8886..00000000000 --- a/tests/ui/close-over-big-then-small-data.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@ run-pass - -#![allow(dead_code)] -// If we use GEPi rather than GEP_tup_like when -// storing closure data (as we used to do), the u64 would -// overwrite the u16. - -struct Pair { - a: A, b: B -} - -struct Invoker { - a: A, - b: u16, -} - -trait Invokable { - fn f(&self) -> (A, u16); -} - -impl Invokable for Invoker { - fn f(&self) -> (A, u16) { - (self.a.clone(), self.b) - } -} - -fn f(a: A, b: u16) -> Box+'static> { - Box::new(Invoker { - a: a, - b: b, - }) as Box+'static> -} - -pub fn main() { - let (a, b) = f(22_u64, 44u16).f(); - println!("a={} b={}", a, b); - assert_eq!(a, 22u64); - assert_eq!(b, 44u16); -} diff --git a/tests/ui/command-line-diagnostics.rs b/tests/ui/command-line-diagnostics.rs deleted file mode 100644 index 8a6cf5b8e32..00000000000 --- a/tests/ui/command-line-diagnostics.rs +++ /dev/null @@ -1,7 +0,0 @@ -// This test checks the output format without the intermediate json representation -//@ compile-flags: --error-format=human - -pub fn main() { - let x = 42; - x = 43; -} diff --git a/tests/ui/command-line-diagnostics.stderr b/tests/ui/command-line-diagnostics.stderr deleted file mode 100644 index 6d33fb4172f..00000000000 --- a/tests/ui/command-line-diagnostics.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/command-line-diagnostics.rs:6:5 - | -LL | let x = 42; - | - first assignment to `x` -LL | x = 43; - | ^^^^^^ cannot assign twice to immutable variable - | -help: consider making this binding mutable - | -LL | let mut x = 42; - | +++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0384`. diff --git a/tests/ui/diagnostic-width/command-line-error-format-human.rs b/tests/ui/diagnostic-width/command-line-error-format-human.rs new file mode 100644 index 00000000000..a2cfbbcbeb1 --- /dev/null +++ b/tests/ui/diagnostic-width/command-line-error-format-human.rs @@ -0,0 +1,8 @@ +//! This test checks the output format without the intermediate json representation + +//@ compile-flags: --error-format=human + +pub fn main() { + let x = 42; + x = 43; +} diff --git a/tests/ui/diagnostic-width/command-line-error-format-human.stderr b/tests/ui/diagnostic-width/command-line-error-format-human.stderr new file mode 100644 index 00000000000..b4b78239f88 --- /dev/null +++ b/tests/ui/diagnostic-width/command-line-error-format-human.stderr @@ -0,0 +1,16 @@ +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/command-line-error-format-human.rs:7:5 + | +LL | let x = 42; + | - first assignment to `x` +LL | x = 43; + | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut x = 42; + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0384`. diff --git a/tests/ui/lifetimes/rvalue-cleanup-shortcircuit.rs b/tests/ui/lifetimes/rvalue-cleanup-shortcircuit.rs new file mode 100644 index 00000000000..dba899585c4 --- /dev/null +++ b/tests/ui/lifetimes/rvalue-cleanup-shortcircuit.rs @@ -0,0 +1,24 @@ +//! Test that cleanups for the RHS of shortcircuiting operators work. + +//@ run-pass + +#![allow(deref_nullptr)] + +use std::env; + +pub fn main() { + let args: Vec = env::args().collect(); + + // Here, the rvalue `"signal".to_string()` requires cleanup. Older versions + // of the code had a problem that the cleanup scope for this + // expression was the end of the `if`, and as the `"signal".to_string()` + // expression was never evaluated, we wound up trying to clean + // uninitialized memory. + + if args.len() >= 2 && args[1] == "signal" { + // Raise a segfault. + unsafe { + *std::ptr::null_mut::() = 0; + } + } +} diff --git a/tests/ui/lifetimes/rvalue-lifetime-drop-timing.rs b/tests/ui/lifetimes/rvalue-lifetime-drop-timing.rs new file mode 100644 index 00000000000..9e7b84bfccf --- /dev/null +++ b/tests/ui/lifetimes/rvalue-lifetime-drop-timing.rs @@ -0,0 +1,104 @@ +//! Test that destructors for temporaries run either at end of +//! statement or end of block as appropriate. + +//@ run-pass + +#![feature(box_patterns)] + +static mut FLAGS: u64 = 0; + +struct Box { + f: T, +} + +struct AddFlags { + bits: u64, +} + +fn add_flags(bits: u64) -> AddFlags { + AddFlags { bits } +} + +fn arg(expected: u64, _x: &AddFlags) { + check_flags(expected); +} + +fn pass(v: T) -> T { + v +} + +fn check_flags(expected: u64) { + unsafe { + let actual = FLAGS; + FLAGS = 0; + assert_eq!(actual, expected, "flags {}, expected {}", actual, expected); + } +} + +impl AddFlags { + fn check_flags(&self, expected: u64) -> &AddFlags { + check_flags(expected); + self + } + + fn bits(&self) -> u64 { + self.bits + } +} + +impl Drop for AddFlags { + fn drop(&mut self) { + unsafe { + FLAGS += self.bits; + } + } +} + +macro_rules! end_of_block { + ($pat:pat, $expr:expr) => {{ + { + let $pat = $expr; + check_flags(0); + } + check_flags(1); + }}; +} + +macro_rules! end_of_stmt { + ($pat:pat, $expr:expr) => {{ + { + let $pat = $expr; + check_flags(1); + } + check_flags(0); + }}; +} + +fn main() { + end_of_block!(_x, add_flags(1)); + end_of_block!(_x, &add_flags(1)); + end_of_block!(_x, &&add_flags(1)); + end_of_block!(_x, Box { f: add_flags(1) }); + end_of_block!(_x, Box { f: &add_flags(1) }); + end_of_block!(_x, pass(add_flags(1))); + end_of_block!(ref _x, add_flags(1)); + end_of_block!(AddFlags { bits: ref _x }, add_flags(1)); + end_of_block!(&AddFlags { bits: _ }, &add_flags(1)); + end_of_block!((_, ref _y), (add_flags(1), 22)); + end_of_block!(box ref _x, std::boxed::Box::new(add_flags(1))); + end_of_block!(box _x, std::boxed::Box::new(add_flags(1))); + end_of_block!(_, { + { + check_flags(0); + &add_flags(1) + } + }); + end_of_block!(_, &((Box { f: add_flags(1) }).f)); + end_of_block!(_, &(([add_flags(1)])[0])); + + end_of_stmt!(_, add_flags(1)); + end_of_stmt!((_, _), (add_flags(1), 22)); + end_of_stmt!(ref _x, arg(0, &add_flags(1))); + end_of_stmt!(ref _x, add_flags(1).check_flags(0).bits()); + end_of_stmt!(AddFlags { bits: _ }, add_flags(1)); +} diff --git a/tests/ui/panics/rvalue-cleanup-during-box-panic.rs b/tests/ui/panics/rvalue-cleanup-during-box-panic.rs new file mode 100644 index 00000000000..84c5d85d7e0 --- /dev/null +++ b/tests/ui/panics/rvalue-cleanup-during-box-panic.rs @@ -0,0 +1,51 @@ +//@ run-pass +//@ needs-unwind + +#![allow(unused_must_use)] +#![allow(dead_code)] +#![allow(unused_variables)] +// Test cleanup of rvalue temporary that occurs while `box` construction +// is in progress. This scenario revealed a rather terrible bug. The +// ingredients are: +// +// 1. Partial cleanup of `box` is in scope, +// 2. cleanup of return value from `get_bar()` is in scope, +// 3. do_it() panics. +// +// This led to a bug because `the top-most frame that was to be +// cleaned (which happens to be the partial cleanup of `box`) required +// multiple basic blocks, which led to us dropping part of the cleanup +// from the top-most frame. +// +// It's unclear how likely such a bug is to recur, but it seems like a +// scenario worth testing. + +//@ needs-threads + +use std::thread; + +enum Conzabble { + Bickwick(Foo), +} + +struct Foo { + field: Box, +} + +fn do_it(x: &[usize]) -> Foo { + panic!() +} + +fn get_bar(x: usize) -> Vec { + vec![x * 2] +} + +pub fn fails() { + let x = 2; + let mut y: Vec> = Vec::new(); + y.push(Box::new(Conzabble::Bickwick(do_it(&get_bar(x))))); +} + +pub fn main() { + thread::spawn(fails).join(); +} -- cgit 1.4.1-3-g733a5 From 911d4a0c06bad14c8320344175a82451d26cbdaf Mon Sep 17 00:00:00 2001 From: León Orell Valerian Liehr Date: Thu, 5 Jun 2025 16:03:22 +0200 Subject: Rename `should_show_cast` to `should_fully_qualify` --- src/librustdoc/clean/mod.rs | 23 ++++++++++++----------- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/html/format.rs | 6 +++--- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e8cf25b1906..0ddb0466c29 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -503,16 +503,16 @@ fn clean_projection<'tcx>( } else { self_type.def_id(&cx.cache) }; - let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type); + let should_fully_qualify = should_fully_qualify_path(self_def_id, &trait_, &self_type); Type::QPath(Box::new(QPathData { assoc: projection_to_path_segment(ty, cx), - should_show_cast, + should_fully_qualify, self_type, trait_: Some(trait_), })) } -fn compute_should_show_cast(self_def_id: Option, trait_: &Path, self_type: &Type) -> bool { +fn should_fully_qualify_path(self_def_id: Option, trait_: &Path, self_type: &Type) -> bool { !trait_.segments.is_empty() && self_def_id .zip(Some(trait_.def_id())) @@ -1695,10 +1695,11 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type register_res(cx, trait_.res); let self_def_id = DefId::local(qself.hir_id.owner.def_id.local_def_index); let self_type = clean_ty(qself, cx); - let should_show_cast = compute_should_show_cast(Some(self_def_id), &trait_, &self_type); + let should_fully_qualify = + should_fully_qualify_path(Some(self_def_id), &trait_, &self_type); Type::QPath(Box::new(QPathData { assoc: clean_path_segment(p.segments.last().expect("segments were empty"), cx), - should_show_cast, + should_fully_qualify, self_type, trait_: Some(trait_), })) @@ -1707,16 +1708,16 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type let ty = lower_ty(cx.tcx, hir_ty); let self_type = clean_ty(qself, cx); - let (trait_, should_show_cast) = match ty.kind() { + let (trait_, should_fully_qualify) = match ty.kind() { ty::Alias(ty::Projection, proj) => { let res = Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id); let trait_ = clean_path(&hir::Path { span, res, segments: &[] }, cx); register_res(cx, trait_.res); let self_def_id = res.opt_def_id(); - let should_show_cast = - compute_should_show_cast(self_def_id, &trait_, &self_type); + let should_fully_qualify = + should_fully_qualify_path(self_def_id, &trait_, &self_type); - (Some(trait_), should_show_cast) + (Some(trait_), should_fully_qualify) } ty::Alias(ty::Inherent, _) => (None, false), // Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s. @@ -1726,7 +1727,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type Type::QPath(Box::new(QPathData { assoc: clean_path_segment(segment, cx), - should_show_cast, + should_fully_qualify, self_type, trait_, })) @@ -2207,7 +2208,7 @@ pub(crate) fn clean_middle_ty<'tcx>( constraints: Default::default(), }, }, - should_show_cast: false, + should_fully_qualify: false, self_type, trait_: None, })) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9e46d0b47e9..8a6bcdff6f3 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1746,7 +1746,7 @@ pub(crate) struct QPathData { pub assoc: PathSegment, pub self_type: Type, /// FIXME: compute this field on demand. - pub should_show_cast: bool, + pub should_fully_qualify: bool, pub trait_: Option, } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index e9a7f4367a3..31e3cb73fa2 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1023,14 +1023,14 @@ fn fmt_type( ref assoc, ref self_type, ref trait_, - should_show_cast, + should_fully_qualify, }) => { // FIXME(inherent_associated_types): Once we support non-ADT self-types (#106719), // we need to surround them with angle brackets in some cases (e.g. `::P`). if f.alternate() { if let Some(trait_) = trait_ - && should_show_cast + && should_fully_qualify { write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))? } else { @@ -1038,7 +1038,7 @@ fn fmt_type( } } else { if let Some(trait_) = trait_ - && should_show_cast + && should_fully_qualify { write!(f, "<{} as {}>::", self_type.print(cx), trait_.print(cx))? } else { -- cgit 1.4.1-3-g733a5 From 95bf1275f599cc7bbec45f20c8d547366aaa9b39 Mon Sep 17 00:00:00 2001 From: León Orell Valerian Liehr Date: Thu, 5 Jun 2025 19:16:32 +0200 Subject: Support middle::ty assoc const eq predicates again --- src/librustdoc/clean/mod.rs | 129 ++++++++------------- src/librustdoc/clean/simplify.rs | 7 +- src/librustdoc/clean/types.rs | 10 +- src/librustdoc/html/format.rs | 41 ++++--- src/librustdoc/json/conversions.rs | 23 +++- tests/rustdoc/inline_cross/assoc-const-equality.rs | 1 - 6 files changed, 92 insertions(+), 119 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0ddb0466c29..7658e7ad35f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -371,10 +371,9 @@ fn clean_where_predicate<'tcx>( bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), }, - hir::WherePredicateKind::EqPredicate(wrp) => WherePredicate::EqPredicate { - lhs: clean_ty(wrp.lhs_ty, cx), - rhs: clean_ty(wrp.rhs_ty, cx).into(), - }, + // We should never actually reach this case because these predicates should've already been + // rejected in an earlier compiler pass. This feature isn't fully implemented (#20041). + hir::WherePredicateKind::EqPredicate(_) => bug!("EqPredicate"), }) } @@ -470,46 +469,34 @@ fn clean_projection_predicate<'tcx>( cx: &mut DocContext<'tcx>, ) -> WherePredicate { WherePredicate::EqPredicate { - lhs: clean_projection( - pred.map_bound(|p| { - // FIXME: This needs to be made resilient for `AliasTerm`s that - // are associated consts. - p.projection_term.expect_ty(cx.tcx) - }), - cx, - None, - ), + lhs: clean_projection(pred.map_bound(|p| p.projection_term), cx, None), rhs: clean_middle_term(pred.map_bound(|p| p.term), cx), } } fn clean_projection<'tcx>( - ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>, + proj: ty::Binder<'tcx, ty::AliasTerm<'tcx>>, cx: &mut DocContext<'tcx>, - def_id: Option, -) -> Type { - if cx.tcx.is_impl_trait_in_trait(ty.skip_binder().def_id) { - return clean_middle_opaque_bounds(cx, ty.skip_binder().def_id, ty.skip_binder().args); - } - + parent_def_id: Option, +) -> QPathData { let trait_ = clean_trait_ref_with_constraints( cx, - ty.map_bound(|ty| ty.trait_ref(cx.tcx)), + proj.map_bound(|proj| proj.trait_ref(cx.tcx)), ThinVec::new(), ); - let self_type = clean_middle_ty(ty.map_bound(|ty| ty.self_ty()), cx, None, None); - let self_def_id = if let Some(def_id) = def_id { - cx.tcx.opt_parent(def_id).or(Some(def_id)) - } else { - self_type.def_id(&cx.cache) + let self_type = clean_middle_ty(proj.map_bound(|proj| proj.self_ty()), cx, None, None); + let self_def_id = match parent_def_id { + Some(parent_def_id) => cx.tcx.opt_parent(parent_def_id).or(Some(parent_def_id)), + None => self_type.def_id(&cx.cache), }; let should_fully_qualify = should_fully_qualify_path(self_def_id, &trait_, &self_type); - Type::QPath(Box::new(QPathData { - assoc: projection_to_path_segment(ty, cx), - should_fully_qualify, + + QPathData { + assoc: projection_to_path_segment(proj, cx), self_type, + should_fully_qualify, trait_: Some(trait_), - })) + } } fn should_fully_qualify_path(self_def_id: Option, trait_: &Path, self_type: &Type) -> bool { @@ -520,18 +507,17 @@ fn should_fully_qualify_path(self_def_id: Option, trait_: &Path, self_typ } fn projection_to_path_segment<'tcx>( - ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>, + proj: ty::Binder<'tcx, ty::AliasTerm<'tcx>>, cx: &mut DocContext<'tcx>, ) -> PathSegment { - let def_id = ty.skip_binder().def_id; - let item = cx.tcx.associated_item(def_id); + let def_id = proj.skip_binder().def_id; let generics = cx.tcx.generics_of(def_id); PathSegment { - name: item.name(), + name: cx.tcx.item_name(def_id), args: GenericArgs::AngleBracketed { args: clean_middle_generic_args( cx, - ty.map_bound(|ty| &ty.args[generics.parent_count..]), + proj.map_bound(|ty| &ty.args[generics.parent_count..]), false, def_id, ), @@ -845,7 +831,7 @@ fn clean_ty_generics<'tcx>( .predicates .iter() .flat_map(|(pred, _)| { - let mut projection = None; + let mut proj_pred = None; let param_idx = { let bound_p = pred.kind(); match bound_p.skip_binder() { @@ -860,7 +846,7 @@ fn clean_ty_generics<'tcx>( ty::ClauseKind::Projection(p) if let ty::Param(param) = p.projection_term.self_ty().kind() => { - projection = Some(bound_p.rebind(p)); + proj_pred = Some(bound_p.rebind(p)); Some(param.index) } _ => None, @@ -874,22 +860,12 @@ fn clean_ty_generics<'tcx>( bounds.extend(pred.get_bounds().into_iter().flatten().cloned()); - if let Some(proj) = projection - && let lhs = clean_projection( - proj.map_bound(|p| { - // FIXME: This needs to be made resilient for `AliasTerm`s that - // are associated consts. - p.projection_term.expect_ty(cx.tcx) - }), - cx, - None, - ) - && let Some((_, trait_did, name)) = lhs.projection() - { + if let Some(pred) = proj_pred { + let lhs = clean_projection(pred.map_bound(|p| p.projection_term), cx, None); impl_trait_proj.entry(param_idx).or_default().push(( - trait_did, - name, - proj.map_bound(|p| p.term), + lhs.trait_.unwrap().def_id(), + lhs.assoc, + pred.map_bound(|p| p.term), )); } @@ -2146,14 +2122,8 @@ pub(crate) fn clean_middle_ty<'tcx>( .map(|pb| AssocItemConstraint { assoc: projection_to_path_segment( pb.map_bound(|pb| { - pb - // HACK(compiler-errors): Doesn't actually matter what self - // type we put here, because we're only using the GAT's args. - .with_self_ty(cx.tcx, cx.tcx.types.self_param) + pb.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self) .projection_term - // FIXME: This needs to be made resilient for `AliasTerm`s - // that are associated consts. - .expect_ty(cx.tcx) }), cx, ), @@ -2186,18 +2156,25 @@ pub(crate) fn clean_middle_ty<'tcx>( Tuple(t.iter().map(|t| clean_middle_ty(bound_ty.rebind(t), cx, None, None)).collect()) } - ty::Alias(ty::Projection, data) => { - clean_projection(bound_ty.rebind(data), cx, parent_def_id) + ty::Alias(ty::Projection, alias_ty @ ty::AliasTy { def_id, args, .. }) => { + if cx.tcx.is_impl_trait_in_trait(def_id) { + clean_middle_opaque_bounds(cx, def_id, args) + } else { + Type::QPath(Box::new(clean_projection( + bound_ty.rebind(alias_ty.into()), + cx, + parent_def_id, + ))) + } } - ty::Alias(ty::Inherent, alias_ty) => { - let def_id = alias_ty.def_id; + ty::Alias(ty::Inherent, alias_ty @ ty::AliasTy { def_id, .. }) => { let alias_ty = bound_ty.rebind(alias_ty); let self_type = clean_middle_ty(alias_ty.map_bound(|ty| ty.self_ty()), cx, None, None); Type::QPath(Box::new(QPathData { assoc: PathSegment { - name: cx.tcx.associated_item(def_id).name(), + name: cx.tcx.item_name(def_id), args: GenericArgs::AngleBracketed { args: clean_middle_generic_args( cx, @@ -2214,20 +2191,15 @@ pub(crate) fn clean_middle_ty<'tcx>( })) } - ty::Alias(ty::Free, data) => { + ty::Alias(ty::Free, ty::AliasTy { def_id, args, .. }) => { if cx.tcx.features().lazy_type_alias() { // Free type alias `data` represents the `type X` in `type X = Y`. If we need `Y`, // we need to use `type_of`. - let path = clean_middle_path( - cx, - data.def_id, - false, - ThinVec::new(), - bound_ty.rebind(data.args), - ); + let path = + clean_middle_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(args)); Type::Path { path } } else { - let ty = cx.tcx.type_of(data.def_id).instantiate(cx.tcx, data.args); + let ty = cx.tcx.type_of(def_id).instantiate(cx.tcx, args); clean_middle_ty(bound_ty.rebind(ty), cx, None, None) } } @@ -2314,18 +2286,17 @@ fn clean_middle_opaque_bounds<'tcx>( let bindings: ThinVec<_> = bounds .iter() .filter_map(|(bound, _)| { - if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() - && proj.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder() + let bound = bound.kind(); + if let ty::ClauseKind::Projection(proj_pred) = bound.skip_binder() + && proj_pred.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder() { return Some(AssocItemConstraint { assoc: projection_to_path_segment( - // FIXME: This needs to be made resilient for `AliasTerm`s that - // are associated consts. - bound.kind().rebind(proj.projection_term.expect_ty(cx.tcx)), + bound.rebind(proj_pred.projection_term), cx, ), kind: AssocItemConstraintKind::Equality { - term: clean_middle_term(bound.kind().rebind(proj.term), cx), + term: clean_middle_term(bound.rebind(proj_pred.term), cx), }, }); } diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 41943b94d1e..40efa997868 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -46,11 +46,8 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: ThinVec) -> ThinVe // Look for equality predicates on associated types that can be merged into // general bound predicates. equalities.retain(|(lhs, rhs)| { - let Some((ty, trait_did, name)) = lhs.projection() else { - return true; - }; - let Some((bounds, _)) = tybounds.get_mut(ty) else { return true }; - merge_bounds(cx, bounds, trait_did, name, rhs) + let Some((bounds, _)) = tybounds.get_mut(&lhs.self_type) else { return true }; + merge_bounds(cx, bounds, lhs.trait_.as_ref().unwrap().def_id(), lhs.assoc.clone(), rhs) }); // And finally, let's reassemble everything diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 8a6bcdff6f3..7ba75d4a8c9 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1341,7 +1341,7 @@ impl PreciseCapturingArg { pub(crate) enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec, bound_params: Vec }, RegionPredicate { lifetime: Lifetime, bounds: Vec }, - EqPredicate { lhs: Type, rhs: Term }, + EqPredicate { lhs: QPathData, rhs: Term }, } impl WherePredicate { @@ -1704,14 +1704,6 @@ impl Type { matches!(self, Type::Tuple(v) if v.is_empty()) } - pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> { - if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self { - Some((self_type, trait_.as_ref()?.def_id(), assoc.clone())) - } else { - None - } - } - /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s. /// /// [clean]: crate::clean diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 31e3cb73fa2..6ab1520386d 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1019,12 +1019,27 @@ fn fmt_type( f.write_str("impl ")?; print_generic_bounds(bounds, cx).fmt(f) } - &clean::QPath(box clean::QPathData { - ref assoc, - ref self_type, - ref trait_, - should_fully_qualify, - }) => { + clean::QPath(qpath) => qpath.print(cx).fmt(f), + } +} + +impl clean::Type { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { + fmt::from_fn(move |f| fmt_type(self, f, false, cx)) + } +} + +impl clean::Path { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { + fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx)) + } +} + +impl clean::QPathData { + fn print(&self, cx: &Context<'_>) -> impl Display { + let Self { ref assoc, ref self_type, should_fully_qualify, ref trait_ } = *self; + + fmt::from_fn(move |f| { // FIXME(inherent_associated_types): Once we support non-ADT self-types (#106719), // we need to surround them with angle brackets in some cases (e.g. `::P`). @@ -1090,19 +1105,7 @@ fn fmt_type( }?; assoc.args.print(cx).fmt(f) - } - } -} - -impl clean::Type { - pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { - fmt::from_fn(move |f| fmt_type(self, f, false, cx)) - } -} - -impl clean::Path { - pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { - fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx)) + }) } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index bfcb794b89a..3ade40940bc 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -468,6 +468,9 @@ impl FromClean for WherePredicate { .collect(), }, EqPredicate { lhs, rhs } => WherePredicate::EqPredicate { + // The LHS currently has type `Type` but it should be a `QualifiedPath` since it may + // refer to an associated const. However, `EqPredicate` shouldn't exist in the first + // place: . lhs: lhs.into_json(renderer), rhs: rhs.into_json(renderer), }, @@ -557,12 +560,7 @@ impl FromClean for Type { is_mutable: mutability == ast::Mutability::Mut, type_: Box::new((*type_).into_json(renderer)), }, - QPath(box clean::QPathData { assoc, self_type, trait_, .. }) => Type::QualifiedPath { - name: assoc.name.to_string(), - args: Box::new(assoc.args.into_json(renderer)), - self_type: Box::new(self_type.into_json(renderer)), - trait_: trait_.map(|trait_| trait_.into_json(renderer)), - }, + QPath(qpath) => (*qpath).into_json(renderer), // FIXME(unsafe_binder): Implement rustdoc-json. UnsafeBinder(_) => todo!(), } @@ -579,6 +577,19 @@ impl FromClean for Path { } } +impl FromClean for Type { + fn from_clean(qpath: clean::QPathData, renderer: &JsonRenderer<'_>) -> Self { + let clean::QPathData { assoc, self_type, should_fully_qualify: _, trait_ } = qpath; + + Self::QualifiedPath { + name: assoc.name.to_string(), + args: Box::new(assoc.args.into_json(renderer)), + self_type: Box::new(self_type.into_json(renderer)), + trait_: trait_.map(|trait_| trait_.into_json(renderer)), + } + } +} + impl FromClean for Term { fn from_clean(term: clean::Term, renderer: &JsonRenderer<'_>) -> Term { match term { diff --git a/tests/rustdoc/inline_cross/assoc-const-equality.rs b/tests/rustdoc/inline_cross/assoc-const-equality.rs index ec5c2f748ef..36ab027ef71 100644 --- a/tests/rustdoc/inline_cross/assoc-const-equality.rs +++ b/tests/rustdoc/inline_cross/assoc-const-equality.rs @@ -1,6 +1,5 @@ //@ aux-crate:assoc_const_equality=assoc-const-equality.rs //@ edition:2021 -//@ ignore-test (FIXME: #125092) #![crate_name = "user"] -- cgit 1.4.1-3-g733a5 From 46ce08ef061b74d7609a4c069ddbc5f4fe8d398c Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Thu, 5 Jun 2025 10:29:50 -0700 Subject: Fix AIX build --- library/std/src/sys/pal/unix/os.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 48609030aed..850bdfdf5b5 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -282,7 +282,7 @@ pub fn current_exe() -> io::Result { return getcwd().map(|cwd| cwd.join(path))?.canonicalize(); } // Search PATH to infer current_exe. - if let Some(p) = getenv(OsStr::from_bytes("PATH".as_bytes())) { + if let Some(p) = env::var_os(OsStr::from_bytes("PATH".as_bytes())) { for search_path in split_paths(&p) { let pb = search_path.join(&path); if pb.is_file() -- cgit 1.4.1-3-g733a5 From 43ee7cd57c1706b949c92d6b29a7034b40dff533 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 5 Jun 2025 12:02:04 -0700 Subject: Simplify and optimize `SlotIndex::from_index` Break out bucket 0 (containing `idx < 4096`) as an early return, which simplifies the remainder of the function, and allows optimizing the `checked_ilog2` since it can no longer return `None`. This reduces the runtime of `vec_cache::tests::slot_index_exhaustive` (which calls `SlotIndex::from_index` for every `u32`, twice) from ~15.5s to ~13.3s. --- compiler/rustc_data_structures/src/vec_cache.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs index 2ff60ab7f36..cc6973fb42e 100644 --- a/compiler/rustc_data_structures/src/vec_cache.rs +++ b/compiler/rustc_data_structures/src/vec_cache.rs @@ -68,22 +68,13 @@ impl SlotIndex { // slots (see `slot_index_exhaustive` in tests). #[inline] const fn from_index(idx: u32) -> Self { - let mut bucket = match idx.checked_ilog2() { - Some(x) => x as usize, - None => 0, - }; - let entries; - let running_sum; - if bucket <= 11 { - entries = 1 << 12; - running_sum = 0; - bucket = 0; - } else { - entries = 1 << bucket; - running_sum = entries; - bucket = bucket - 11; + if idx < 4096 { + return SlotIndex { bucket_idx: 0, entries: 4096, index_in_bucket: idx as usize }; } - SlotIndex { bucket_idx: bucket, entries, index_in_bucket: idx as usize - running_sum } + // SAFETY: We already ruled out idx 0, so `checked_ilog2` can't return `None`. + let bucket = unsafe { idx.checked_ilog2().unwrap_unchecked() as usize }; + let entries = 1 << bucket; + SlotIndex { bucket_idx: bucket - 11, entries, index_in_bucket: idx as usize - entries } } // SAFETY: Buckets must be managed solely by functions here (i.e., get/put on SlotIndex) and -- cgit 1.4.1-3-g733a5 From 9837c3c3f8accf763704cc56e2b13398e86db282 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 5 Jun 2025 12:06:21 -0700 Subject: Simplify `vec_cache::tests::slot_index_exhaustive` by pulling out 0 case `slot_index_exhaustive` has additional complexity in its loop that only applies for index 0. Pull that case out of the loop. --- compiler/rustc_data_structures/src/vec_cache/tests.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_data_structures/src/vec_cache/tests.rs b/compiler/rustc_data_structures/src/vec_cache/tests.rs index 3b65c14162e..9b60913ec92 100644 --- a/compiler/rustc_data_structures/src/vec_cache/tests.rs +++ b/compiler/rustc_data_structures/src/vec_cache/tests.rs @@ -75,24 +75,21 @@ fn slot_index_exhaustive() { for idx in 0..=u32::MAX { buckets[SlotIndex::from_index(idx).bucket_idx] += 1; } - let mut prev = None::; - for idx in 0..=u32::MAX { + let slot_idx = SlotIndex::from_index(0); + assert_eq!(slot_idx.index_in_bucket, 0); + assert_eq!(slot_idx.bucket_idx, 0); + let mut prev = slot_idx; + for idx in 1..=u32::MAX { let slot_idx = SlotIndex::from_index(idx); - if let Some(p) = prev { - if p.bucket_idx == slot_idx.bucket_idx { - assert_eq!(p.index_in_bucket + 1, slot_idx.index_in_bucket); - } else { - assert_eq!(slot_idx.index_in_bucket, 0); - } + if prev.bucket_idx == slot_idx.bucket_idx { + assert_eq!(prev.index_in_bucket + 1, slot_idx.index_in_bucket); } else { - assert_eq!(idx, 0); assert_eq!(slot_idx.index_in_bucket, 0); - assert_eq!(slot_idx.bucket_idx, 0); } assert_eq!(buckets[slot_idx.bucket_idx], slot_idx.entries as u32); assert_eq!(ENTRIES_BY_BUCKET[slot_idx.bucket_idx], slot_idx.entries, "{}", idx); - prev = Some(slot_idx); + prev = slot_idx; } } -- cgit 1.4.1-3-g733a5 From dcf22aa7cb1bad0a759465ab1eba2e5bb4d13aef Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 2 Jun 2025 18:00:37 +0000 Subject: Clear nested candidates in select if certainty is yes --- compiler/rustc_trait_selection/src/solve/select.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/solve/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs index 21812c8017d..09d00136f53 100644 --- a/compiler/rustc_trait_selection/src/solve/select.rs +++ b/compiler/rustc_trait_selection/src/solve/select.rs @@ -10,6 +10,7 @@ use rustc_infer::traits::{ use rustc_macros::extension; use rustc_middle::{bug, span_bug}; use rustc_span::Span; +use thin_vec::ThinVec; use crate::solve::inspect::{self, ProofTreeInferCtxtExt}; @@ -147,7 +148,7 @@ fn to_selection<'tcx>( } let (nested, impl_args) = cand.instantiate_nested_goals_and_opt_impl_args(span); - let nested = nested + let mut nested: ThinVec<_> = nested .into_iter() .map(|nested| { Obligation::new( @@ -159,6 +160,10 @@ fn to_selection<'tcx>( }) .collect(); + if let Ok(Certainty::Yes) = cand.result() { + nested.clear(); + } + Some(match cand.kind() { ProbeKind::TraitCandidate { source, result: _ } => match source { CandidateSource::Impl(impl_def_id) => { -- cgit 1.4.1-3-g733a5 From 1e5cd122f0ef0f5787a22186cb6d83d427b112c3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 5 Jun 2025 17:07:32 +0000 Subject: Only instantiate impl args --- .../src/solve/inspect/analyse.rs | 81 ++++++++++++++-------- compiler/rustc_trait_selection/src/solve/select.rs | 35 +++++----- 2 files changed, 70 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 1193a9059ca..e2282a5bfbc 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -133,45 +133,25 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { /// Instantiate the nested goals for the candidate without rolling back their /// inference constraints. This function modifies the state of the `infcx`. /// - /// See [`Self::instantiate_nested_goals_and_opt_impl_args`] if you need the impl args too. - pub fn instantiate_nested_goals(&self, span: Span) -> Vec> { - self.instantiate_nested_goals_and_opt_impl_args(span).0 - } - - /// Instantiate the nested goals for the candidate without rolling back their - /// inference constraints, and optionally the args of an impl if this candidate - /// came from a `CandidateSource::Impl`. This function modifies the state of the - /// `infcx`. + /// See [`Self::instantiate_impl_args`] if you need the impl args too. #[instrument( level = "debug", skip_all, fields(goal = ?self.goal.goal, steps = ?self.steps) )] - pub fn instantiate_nested_goals_and_opt_impl_args( - &self, - span: Span, - ) -> (Vec>, Option>) { + pub fn instantiate_nested_goals(&self, span: Span) -> Vec> { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; let mut orig_values = self.goal.orig_values.to_vec(); let mut instantiated_goals = vec![]; - let mut opt_impl_args = None; for step in &self.steps { match **step { inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push(( source, instantiate_canonical_state(infcx, span, param_env, &mut orig_values, goal), )), - inspect::ProbeStep::RecordImplArgs { impl_args } => { - opt_impl_args = Some(instantiate_canonical_state( - infcx, - span, - param_env, - &mut orig_values, - impl_args, - )); - } + inspect::ProbeStep::RecordImplArgs { .. } => {} inspect::ProbeStep::MakeCanonicalResponse { .. } | inspect::ProbeStep::NestedProbe(_) => unreachable!(), } @@ -187,14 +167,59 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { let _ = term_hack.constrain(infcx, span, param_env); } - let opt_impl_args = opt_impl_args.map(|impl_args| eager_resolve_vars(infcx, impl_args)); - - let goals = instantiated_goals + instantiated_goals .into_iter() .map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal, span)) - .collect(); + .collect() + } + + /// Instantiate the args of an impl if this candidate came from a + /// `CandidateSource::Impl`. This function modifies the state of the + /// `infcx`. + #[instrument( + level = "debug", + skip_all, + fields(goal = ?self.goal.goal, steps = ?self.steps) + )] + pub fn instantiate_impl_args(&self, span: Span) -> ty::GenericArgsRef<'tcx> { + let infcx = self.goal.infcx; + let param_env = self.goal.goal.param_env; + let mut orig_values = self.goal.orig_values.to_vec(); + + for step in &self.steps { + match **step { + inspect::ProbeStep::RecordImplArgs { impl_args } => { + let impl_args = instantiate_canonical_state( + infcx, + span, + param_env, + &mut orig_values, + impl_args, + ); + + let () = instantiate_canonical_state( + infcx, + span, + param_env, + &mut orig_values, + self.final_state, + ); + + // No reason we couldn't support this, but we don't need to for select. + assert!( + self.goal.normalizes_to_term_hack.is_none(), + "cannot use `instantiate_impl_args` with a `NormalizesTo` goal" + ); + + return eager_resolve_vars(infcx, impl_args); + } + inspect::ProbeStep::AddGoal(..) => {} + inspect::ProbeStep::MakeCanonicalResponse { .. } + | inspect::ProbeStep::NestedProbe(_) => unreachable!(), + } + } - (goals, opt_impl_args) + bug!("expected impl args probe step for `instantiate_impl_args`"); } pub fn instantiate_proof_tree_for_nested_goal( diff --git a/compiler/rustc_trait_selection/src/solve/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs index 09d00136f53..fb1adc2fd2a 100644 --- a/compiler/rustc_trait_selection/src/solve/select.rs +++ b/compiler/rustc_trait_selection/src/solve/select.rs @@ -10,7 +10,7 @@ use rustc_infer::traits::{ use rustc_macros::extension; use rustc_middle::{bug, span_bug}; use rustc_span::Span; -use thin_vec::ThinVec; +use thin_vec::thin_vec; use crate::solve::inspect::{self, ProofTreeInferCtxtExt}; @@ -147,22 +147,21 @@ fn to_selection<'tcx>( return None; } - let (nested, impl_args) = cand.instantiate_nested_goals_and_opt_impl_args(span); - let mut nested: ThinVec<_> = nested - .into_iter() - .map(|nested| { - Obligation::new( - nested.infcx().tcx, - ObligationCause::dummy_with_span(span), - nested.goal().param_env, - nested.goal().predicate, - ) - }) - .collect(); - - if let Ok(Certainty::Yes) = cand.result() { - nested.clear(); - } + let nested = match cand.result().expect("expected positive result") { + Certainty::Yes => thin_vec![], + Certainty::Maybe(_) => cand + .instantiate_nested_goals(span) + .into_iter() + .map(|nested| { + Obligation::new( + nested.infcx().tcx, + ObligationCause::dummy_with_span(span), + nested.goal().param_env, + nested.goal().predicate, + ) + }) + .collect(), + }; Some(match cand.kind() { ProbeKind::TraitCandidate { source, result: _ } => match source { @@ -171,7 +170,7 @@ fn to_selection<'tcx>( // For impl candidates, we do the rematch manually to compute the args. ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id, - args: impl_args.expect("expected recorded impl args for impl candidate"), + args: cand.instantiate_impl_args(span), nested, }) } -- cgit 1.4.1-3-g733a5 From 8a56ed4c89d38618e065f7d9ec6be0390fdabe31 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 5 Jun 2025 16:57:59 -0700 Subject: `SlotIndex::from_index`: Factor out a constant for the first bucket size --- compiler/rustc_data_structures/src/vec_cache.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs index cc6973fb42e..3b448c056b7 100644 --- a/compiler/rustc_data_structures/src/vec_cache.rs +++ b/compiler/rustc_data_structures/src/vec_cache.rs @@ -68,13 +68,22 @@ impl SlotIndex { // slots (see `slot_index_exhaustive` in tests). #[inline] const fn from_index(idx: u32) -> Self { - if idx < 4096 { - return SlotIndex { bucket_idx: 0, entries: 4096, index_in_bucket: idx as usize }; + const FIRST_BUCKET_SHIFT: usize = 12; + if idx < (1 << FIRST_BUCKET_SHIFT) { + return SlotIndex { + bucket_idx: 0, + entries: 1 << FIRST_BUCKET_SHIFT, + index_in_bucket: idx as usize, + }; } // SAFETY: We already ruled out idx 0, so `checked_ilog2` can't return `None`. let bucket = unsafe { idx.checked_ilog2().unwrap_unchecked() as usize }; let entries = 1 << bucket; - SlotIndex { bucket_idx: bucket - 11, entries, index_in_bucket: idx as usize - entries } + SlotIndex { + bucket_idx: bucket - FIRST_BUCKET_SHIFT + 1, + entries, + index_in_bucket: idx as usize - entries, + } } // SAFETY: Buckets must be managed solely by functions here (i.e., get/put on SlotIndex) and -- cgit 1.4.1-3-g733a5 From 8bce2255e826a11d1aa345d1786f85d22c5f921a Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 4 Jun 2025 01:44:40 -0700 Subject: Update `InterpCx::project_field` to take `FieldIdx` As suggested by Ralf in 142005. --- compiler/rustc_abi/src/layout/ty.rs | 11 +++++++++-- compiler/rustc_codegen_cranelift/src/inline_asm.rs | 2 +- compiler/rustc_codegen_cranelift/src/vtable.rs | 5 ++--- compiler/rustc_codegen_ssa/src/mir/block.rs | 4 ++-- compiler/rustc_const_eval/src/const_eval/mod.rs | 4 ++-- .../rustc_const_eval/src/const_eval/valtrees.rs | 6 +++--- compiler/rustc_const_eval/src/interpret/call.rs | 9 ++++----- compiler/rustc_const_eval/src/interpret/cast.rs | 3 ++- .../rustc_const_eval/src/interpret/discriminant.rs | 4 ++-- .../rustc_const_eval/src/interpret/projection.rs | 18 +++++++++--------- compiler/rustc_const_eval/src/interpret/step.rs | 2 +- compiler/rustc_const_eval/src/interpret/traits.rs | 6 +++--- compiler/rustc_const_eval/src/interpret/visitor.rs | 21 ++++++++++++--------- .../rustc_const_eval/src/util/caller_location.rs | 12 ++++++++---- compiler/rustc_hir_analysis/src/check/check.rs | 2 +- compiler/rustc_hir_typeck/src/inline_asm.rs | 2 +- .../rustc_mir_transform/src/dataflow_const_prop.rs | 7 ++++--- compiler/rustc_mir_transform/src/gvn.rs | 8 +++++--- compiler/rustc_mir_transform/src/jump_threading.rs | 2 +- src/tools/miri/src/eval.rs | 8 ++++---- src/tools/miri/src/helpers.rs | 7 ++++--- src/tools/miri/src/shims/backtrace.rs | 12 ++++++------ src/tools/miri/src/shims/unix/env.rs | 7 ++++--- src/tools/miri/src/shims/unix/freebsd/sync.rs | 8 +++++--- src/tools/miri/src/shims/unix/linux_like/epoll.rs | 6 ++++-- src/tools/miri/src/shims/x86/mod.rs | 6 +++--- 26 files changed, 102 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index 4f43c0e6f8e..eb49b977257 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -39,6 +39,13 @@ rustc_index::newtype_index! { pub struct FieldIdx {} } +impl FieldIdx { + /// The second field. + /// + /// For use alongside [`FieldIdx::ZERO`], particularly with scalar pairs. + pub const ONE: FieldIdx = FieldIdx::from_u32(1); +} + rustc_index::newtype_index! { /// The *source-order* index of a variant in a type. /// @@ -274,7 +281,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { /// Finds the one field that is not a 1-ZST. /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields. - pub fn non_1zst_field(&self, cx: &C) -> Option<(usize, Self)> + pub fn non_1zst_field(&self, cx: &C) -> Option<(FieldIdx, Self)> where Ty: TyAbiInterface<'a, C> + Copy, { @@ -288,7 +295,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { // More than one non-1-ZST field. return None; } - found = Some((field_idx, field)); + found = Some((FieldIdx::from_usize(field_idx), field)); } found } diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index afee5095549..120d6ff9e38 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -850,7 +850,7 @@ fn asm_clif_type<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> Option { let fields = &adt.non_enum_variant().fields; - let ty = fields[FieldIdx::from_u32(1)].ty(fx.tcx, args); + let ty = fields[FieldIdx::ONE].ty(fx.tcx, args); let ty::Adt(ty, args) = ty.kind() else { unreachable!("expected first field of `MaybeUninit` to be an ADT") }; diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 9d9e0462a9b..05a8e3c3342 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -53,7 +53,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( .layout() .non_1zst_field(fx) .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type"); - arg = arg.value_field(fx, FieldIdx::new(idx)); + arg = arg.value_field(fx, idx); } } @@ -62,8 +62,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap()); let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout); let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr(); - let vtable = - dyn_star.place_field(fx, FieldIdx::new(1)).to_cvalue(fx).load_scalar(fx); + let vtable = dyn_star.place_field(fx, FieldIdx::ONE).to_cvalue(fx).load_scalar(fx); break 'block (ptr, vtable); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1baab62ae43..7cea48ce1cc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1077,7 +1077,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (idx, _) = op.layout.non_1zst_field(bx).expect( "not exactly one non-1-ZST field in a `DispatchFromDyn` type", ); - op = op.extract_field(self, bx, idx); + op = op.extract_field(self, bx, idx.as_usize()); } // Now that we have `*dyn Trait` or `&dyn Trait`, split it up into its @@ -1109,7 +1109,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (idx, _) = op.layout.non_1zst_field(bx).expect( "not exactly one non-1-ZST field in a `DispatchFromDyn` type", ); - op = op.extract_field(self, bx, idx); + op = op.extract_field(self, bx, idx.as_usize()); } // Make sure that we've actually unwrapped the rcvr down diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index c0438fb3ff8..6fd0b9d26e3 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -1,6 +1,6 @@ // Not in interpret to make sure we do not use private implementation details -use rustc_abi::VariantIdx; +use rustc_abi::{FieldIdx, VariantIdx}; use rustc_middle::query::Key; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -60,7 +60,7 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( let fields_iter = (0..field_count) .map(|i| { - let field_op = ecx.project_field(&down, i).discard_err()?; + let field_op = ecx.project_field(&down, FieldIdx::from_usize(i)).discard_err()?; let val = op_to_const(&ecx, &field_op, /* for diagnostics */ true); Some((val, field_op.layout.ty)) }) diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 34239ae1d15..58d230af683 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -1,4 +1,4 @@ -use rustc_abi::{BackendRepr, VariantIdx}; +use rustc_abi::{BackendRepr, FieldIdx, VariantIdx}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ReportedErrorInfo}; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; @@ -40,7 +40,7 @@ fn branches<'tcx>( } for i in 0..field_count { - let field = ecx.project_field(&place, i).unwrap(); + let field = ecx.project_field(&place, FieldIdx::from_usize(i)).unwrap(); let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?; branches.push(valtree); } @@ -437,7 +437,7 @@ fn valtree_into_mplace<'tcx>( ty::Str | ty::Slice(_) | ty::Array(..) => { ecx.project_index(place, i as u64).unwrap() } - _ => ecx.project_field(&place_adjusted, i).unwrap(), + _ => ecx.project_field(&place_adjusted, FieldIdx::from_usize(i)).unwrap(), }; debug!(?place_inner); diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 789baea0734..37677f9e048 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -62,7 +62,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub(super) fn fn_arg_field( &self, arg: &FnArg<'tcx, M::Provenance>, - field: usize, + field: FieldIdx, ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> { interp_ok(match arg { FnArg::Copy(op) => FnArg::Copy(self.project_field(op, field)?), @@ -600,10 +600,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Cow::from( args.iter() .map(|a| interp_ok(a.clone())) - .chain( - (0..untuple_arg.layout().fields.count()) - .map(|i| self.fn_arg_field(untuple_arg, i)), - ) + .chain((0..untuple_arg.layout().fields.count()).map(|i| { + self.fn_arg_field(untuple_arg, FieldIdx::from_usize(i)) + })) .collect::>>()?, ) } else { diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 643a5805019..9e15f4572d7 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -1,6 +1,6 @@ use std::assert_matches::assert_matches; -use rustc_abi::Integer; +use rustc_abi::{FieldIdx, Integer}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::{Float, FloatConvert}; use rustc_middle::mir::CastKind; @@ -484,6 +484,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let mut found_cast_field = false; for i in 0..src.layout.fields.count() { let cast_ty_field = cast_ty.field(self, i); + let i = FieldIdx::from_usize(i); let src_field = self.project_field(src, i)?; let dst_field = self.project_field(dest, i)?; if src_field.layout.is_1zst() && cast_ty_field.is_1zst() { diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 020cd65d75d..6c4b000e16b 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -26,7 +26,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // No need to validate that the discriminant here because the // `TyAndLayout::for_variant()` call earlier already checks the // variant is valid. - let tag_dest = self.project_field(dest, tag_field.as_usize())?; + let tag_dest = self.project_field(dest, tag_field)?; self.write_scalar(tag, &tag_dest) } None => { @@ -96,7 +96,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let tag_layout = self.layout_of(tag_scalar_layout.primitive().to_int_ty(*self.tcx))?; // Read tag and sanity-check `tag_layout`. - let tag_val = self.read_immediate(&self.project_field(op, tag_field.as_usize())?)?; + let tag_val = self.read_immediate(&self.project_field(op, tag_field)?)?; assert_eq!(tag_layout.size, tag_val.layout.size); assert_eq!(tag_layout.backend_repr.is_signed(), tag_val.layout.backend_repr.is_signed()); trace!("tag value: {}", tag_val); diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 8ecb3e13d5c..ad47a19a14d 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -10,7 +10,7 @@ use std::marker::PhantomData; use std::ops::Range; -use rustc_abi::{self as abi, Size, VariantIdx}; +use rustc_abi::{self as abi, FieldIdx, Size, VariantIdx}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::{bug, mir, span_bug, ty}; @@ -144,22 +144,22 @@ where /// always possible without allocating, so it can take `&self`. Also return the field's layout. /// This supports both struct and array fields, but not slices! /// - /// This also works for arrays, but then the `usize` index type is restricting. - /// For indexing into arrays, use `mplace_index`. + /// This also works for arrays, but then the `FieldIdx` index type is restricting. + /// For indexing into arrays, use [`Self::project_index`]. pub fn project_field>( &self, base: &P, - field: usize, + field: FieldIdx, ) -> InterpResult<'tcx, P> { // Slices nominally have length 0, so they will panic somewhere in `fields.offset`. debug_assert!( !matches!(base.layout().ty.kind(), ty::Slice(..)), "`field` projection called on a slice -- call `index` projection instead" ); - let offset = base.layout().fields.offset(field); + let offset = base.layout().fields.offset(field.as_usize()); // Computing the layout does normalization, so we get a normalized type out of this // even if the field type is non-normalized (possible e.g. via associated types). - let field_layout = base.layout().field(self, field); + let field_layout = base.layout().field(self, field.as_usize()); // Offset may need adjustment for unsized fields. let (meta, offset) = if field_layout.is_unsized() { @@ -244,7 +244,7 @@ where } _ => span_bug!( self.cur_span(), - "`mplace_index` called on non-array type {:?}", + "`project_index` called on non-array type {:?}", base.layout().ty ), }; @@ -260,7 +260,7 @@ where ) -> InterpResult<'tcx, (P, u64)> { assert!(base.layout().ty.ty_adt_def().unwrap().repr().simd()); // SIMD types must be newtypes around arrays, so all we have to do is project to their only field. - let array = self.project_field(base, 0)?; + let array = self.project_field(base, FieldIdx::ZERO)?; let len = array.len(self)?; interp_ok((array, len)) } @@ -384,7 +384,7 @@ where UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?, // We don't want anything happening here, this is here as a dummy. Subtype(_) => base.transmute(base.layout(), self)?, - Field(field, _) => self.project_field(base, field.index())?, + Field(field, _) => self.project_field(base, field)?, Downcast(_, variant) => self.project_downcast(base, variant)?, Deref => self.deref_pointer(&base.to_op(self)?)?.into(), Index(local) => { diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 975325b0c1e..833fcc38817 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -333,7 +333,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } for (field_index, operand) in operands.iter_enumerated() { let field_index = active_field_index.unwrap_or(field_index); - let field_dest = self.project_field(&variant_dest, field_index.as_usize())?; + let field_dest = self.project_field(&variant_dest, field_index)?; let op = self.eval_operand(operand, Some(field_dest.layout))?; self.copy_op(&op, &field_dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index a5029eea5a7..7249ef23bf6 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -1,4 +1,4 @@ -use rustc_abi::{Align, Size}; +use rustc_abi::{Align, FieldIdx, Size}; use rustc_middle::mir::interpret::{InterpResult, Pointer}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt, Ty, TyCtxt, VtblEntry}; @@ -137,8 +137,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)), "`unpack_dyn_star` only makes sense on `dyn*` types" ); - let data = self.project_field(val, 0)?; - let vtable = self.project_field(val, 1)?; + let data = self.project_field(val, FieldIdx::ZERO)?; + let vtable = self.project_field(val, FieldIdx::ONE)?; let vtable = self.read_pointer(&vtable.to_op(self)?)?; let ty = self.get_ptr_vtable_ty(vtable, Some(expected_trait))?; // `data` is already the right thing but has the wrong type. So we transmute it. diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 3647c109a6e..5aea91233bd 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -112,8 +112,10 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { // So we transmute it to a raw pointer. let raw_ptr_ty = Ty::new_mut_ptr(*self.ecx().tcx, self.ecx().tcx.types.unit); let raw_ptr_ty = self.ecx().layout_of(raw_ptr_ty)?; - let vtable_field = - self.ecx().project_field(v, 1)?.transmute(raw_ptr_ty, self.ecx())?; + let vtable_field = self + .ecx() + .project_field(v, FieldIdx::ONE)? + .transmute(raw_ptr_ty, self.ecx())?; self.visit_field(v, 1, &vtable_field)?; // Then unpack the first field, and continue. @@ -140,14 +142,16 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { // `Box` has two fields: the pointer we care about, and the allocator. assert_eq!(v.layout().fields.count(), 2, "`Box` must have exactly 2 fields"); - let (unique_ptr, alloc) = - (self.ecx().project_field(v, 0)?, self.ecx().project_field(v, 1)?); + let (unique_ptr, alloc) = ( + self.ecx().project_field(v, FieldIdx::ZERO)?, + self.ecx().project_field(v, FieldIdx::ONE)?, + ); // Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`... // (which means another 2 fields, the second of which is a `PhantomData`) assert_eq!(unique_ptr.layout().fields.count(), 2); let (nonnull_ptr, phantom) = ( - self.ecx().project_field(&unique_ptr, 0)?, - self.ecx().project_field(&unique_ptr, 1)?, + self.ecx().project_field(&unique_ptr, FieldIdx::ZERO)?, + self.ecx().project_field(&unique_ptr, FieldIdx::ONE)?, ); assert!( phantom.layout().ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()), @@ -156,7 +160,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { ); // ... that contains a `NonNull`... (gladly, only a single field here) assert_eq!(nonnull_ptr.layout().fields.count(), 1); - let raw_ptr = self.ecx().project_field(&nonnull_ptr, 0)?; // the actual raw ptr + let raw_ptr = self.ecx().project_field(&nonnull_ptr, FieldIdx::ZERO)?; // the actual raw ptr // ... whose only field finally is a raw ptr we can dereference. self.visit_box(ty, &raw_ptr)?; @@ -188,9 +192,8 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { } FieldsShape::Arbitrary { memory_index, .. } => { for idx in Self::aggregate_field_iter(memory_index) { - let idx = idx.as_usize(); let field = self.ecx().project_field(v, idx)?; - self.visit_field(v, idx, &field)?; + self.visit_field(v, idx.as_usize(), &field)?; } } FieldsShape::Array { .. } => { diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index 9c867cc615e..65d02d3bafa 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -1,3 +1,4 @@ +use rustc_abi::FieldIdx; use rustc_hir::LangItem; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, TyCtxt}; @@ -41,11 +42,14 @@ fn alloc_caller_location<'tcx>( let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap(); // Initialize fields. - ecx.write_immediate(file_wide_ptr, &ecx.project_field(&location, 0).unwrap()) + ecx.write_immediate( + file_wide_ptr, + &ecx.project_field(&location, FieldIdx::from_u32(0)).unwrap(), + ) + .expect("writing to memory we just allocated cannot fail"); + ecx.write_scalar(line, &ecx.project_field(&location, FieldIdx::from_u32(1)).unwrap()) .expect("writing to memory we just allocated cannot fail"); - ecx.write_scalar(line, &ecx.project_field(&location, 1).unwrap()) - .expect("writing to memory we just allocated cannot fail"); - ecx.write_scalar(col, &ecx.project_field(&location, 2).unwrap()) + ecx.write_scalar(col, &ecx.project_field(&location, FieldIdx::from_u32(2)).unwrap()) .expect("writing to memory we just allocated cannot fail"); location diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 846eacce9e1..5d42de74f6c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1100,7 +1100,7 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { return; }; - if let Some(second_field) = fields.get(FieldIdx::from_u32(1)) { + if let Some(second_field) = fields.get(FieldIdx::ONE) { struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot have multiple fields") .with_span_label(tcx.def_span(second_field.did), "excess field") .emit(); diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index 6399f0a78ae..b59c1752c25 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -171,7 +171,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { _ if ty.references_error() => return None, ty::Adt(adt, args) if self.tcx().is_lang_item(adt.did(), LangItem::MaybeUninit) => { let fields = &adt.non_enum_variant().fields; - let ty = fields[FieldIdx::from_u32(1)].ty(self.tcx(), args); + let ty = fields[FieldIdx::ONE].ty(self.tcx(), args); // FIXME: Are we just trying to map to the `T` in `MaybeUninit`? // If so, just get it from the args. let ty::Adt(ty, args) = ty.kind() else { diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 99b95e7312b..0cf8142a560 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -616,7 +616,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { place, operand, &mut |elem, op| match elem { - TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).discard_err(), + TrackElem::Field(idx) => self.ecx.project_field(op, idx).discard_err(), TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(), TrackElem::Discriminant => { let variant = self.ecx.read_discriminant(op).discard_err()?; @@ -890,7 +890,8 @@ fn try_write_constant<'tcx>( ty::Tuple(elem_tys) => { for (i, elem) in elem_tys.iter().enumerate() { - let Some(field) = map.apply(place, TrackElem::Field(FieldIdx::from_usize(i))) else { + let i = FieldIdx::from_usize(i); + let Some(field) = map.apply(place, TrackElem::Field(i)) else { throw_machine_stop_str!("missing field in tuple") }; let field_dest = ecx.project_field(dest, i)?; @@ -928,7 +929,7 @@ fn try_write_constant<'tcx>( let Some(field) = map.apply(variant_place, TrackElem::Field(i)) else { throw_machine_stop_str!("missing field in ADT") }; - let field_dest = ecx.project_field(&variant_dest, i.as_usize())?; + let field_dest = ecx.project_field(&variant_dest, i)?; try_write_constant(ecx, &field_dest, field, ty, state, map)?; } ecx.write_discriminant(variant_idx, dest)?; diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index a91d46ec406..92c30d239b5 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -438,8 +438,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { dest.clone() }; for (field_index, op) in fields.into_iter().enumerate() { - let field_dest = - self.ecx.project_field(&variant_dest, field_index).discard_err()?; + let field_dest = self + .ecx + .project_field(&variant_dest, FieldIdx::from_usize(field_index)) + .discard_err()?; self.ecx.copy_op(op, &field_dest).discard_err()?; } self.ecx @@ -1583,7 +1585,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // We needed to check the variant to avoid trying to read the tag // field from an enum where no fields have variants, since that tag // field isn't in the `Aggregate` from which we're getting values. - Some((FieldIdx::from_usize(field_idx), field_layout.ty)) + Some((field_idx, field_layout.ty)) } else if let ty::Adt(adt, args) = ty.kind() && adt.is_struct() && adt.repr().transparent() diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 31b361ec1a9..48db536c122 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -388,7 +388,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { lhs, constant, &mut |elem, op| match elem { - TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).discard_err(), + TrackElem::Field(idx) => self.ecx.project_field(op, idx).discard_err(), TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(), TrackElem::Discriminant => { let variant = self.ecx.read_discriminant(op).discard_err()?; diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 8fe034d2582..5880e5fbc37 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -359,8 +359,8 @@ pub fn create_ecx<'tcx>( let argvs_layout = ecx.layout_of(Ty::new_array(tcx, u8_ptr_type, u64::try_from(argvs.len()).unwrap()))?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?; - for (idx, arg) in argvs.into_iter().enumerate() { - let place = ecx.project_field(&argvs_place, idx)?; + for (arg, idx) in argvs.into_iter().zip(0..) { + let place = ecx.project_index(&argvs_place, idx)?; ecx.write_immediate(arg, &place)?; } ecx.mark_immutable(&argvs_place); @@ -389,8 +389,8 @@ pub fn create_ecx<'tcx>( ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?; ecx.machine.cmd_line = Some(cmd_place.ptr()); // Store the UTF-16 string. We just allocated so we know the bounds are fine. - for (idx, &c) in cmd_utf16.iter().enumerate() { - let place = ecx.project_field(&cmd_place, idx)?; + for (&c, idx) in cmd_utf16.iter().zip(0..) { + let place = ecx.project_index(&cmd_place, idx)?; ecx.write_scalar(Scalar::from_u16(c), &place)?; } ecx.mark_immutable(&cmd_place); diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 20ea239b7e5..4edecc864dd 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -326,7 +326,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, Option

> { let this = self.eval_context_ref(); let adt = base.layout().ty.ty_adt_def().unwrap(); - for (idx, field) in adt.non_enum_variant().fields.iter().enumerate() { + for (idx, field) in adt.non_enum_variant().fields.iter_enumerated() { if field.name.as_str() == name { return interp_ok(Some(this.project_field(base, idx)?)); } @@ -376,6 +376,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); for (idx, &val) in values.iter().enumerate() { + let idx = FieldIdx::from_usize(idx); let field = this.project_field(dest, idx)?; this.write_int(val, &field)?; } @@ -763,10 +764,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// `EINVAL` in this case. fn read_timespec(&mut self, tp: &MPlaceTy<'tcx>) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); - let seconds_place = this.project_field(tp, 0)?; + let seconds_place = this.project_field(tp, FieldIdx::ZERO)?; let seconds_scalar = this.read_scalar(&seconds_place)?; let seconds = seconds_scalar.to_target_isize(this)?; - let nanoseconds_place = this.project_field(tp, 1)?; + let nanoseconds_place = this.project_field(tp, FieldIdx::ONE)?; let nanoseconds_scalar = this.read_scalar(&nanoseconds_place)?; let nanoseconds = nanoseconds_scalar.to_target_isize(this)?; diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index ab11553df63..8606735c913 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -1,4 +1,4 @@ -use rustc_abi::{CanonAbi, Size}; +use rustc_abi::{CanonAbi, FieldIdx, Size}; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{BytePos, Loc, Symbol, hygiene}; @@ -159,23 +159,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { 1 => { this.write_scalar( Scalar::from_target_usize(name.len().to_u64(), this), - &this.project_field(dest, 0)?, + &this.project_field(dest, FieldIdx::from_u32(0))?, )?; this.write_scalar( Scalar::from_target_usize(filename.len().to_u64(), this), - &this.project_field(dest, 1)?, + &this.project_field(dest, FieldIdx::from_u32(1))?, )?; } _ => throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags), } - this.write_scalar(Scalar::from_u32(lineno), &this.project_field(dest, 2)?)?; - this.write_scalar(Scalar::from_u32(colno), &this.project_field(dest, 3)?)?; + this.write_scalar(Scalar::from_u32(lineno), &this.project_field(dest, FieldIdx::from_u32(2))?)?; + this.write_scalar(Scalar::from_u32(colno), &this.project_field(dest, FieldIdx::from_u32(3))?)?; // Support a 4-field struct for now - this is deprecated // and slated for removal. if num_fields == 5 { - this.write_pointer(fn_ptr, &this.project_field(dest, 4)?)?; + this.write_pointer(fn_ptr, &this.project_field(dest, FieldIdx::from_u32(4))?)?; } interp_ok(()) diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index aebb5757aec..62ac7ee3806 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -2,8 +2,9 @@ use std::ffi::{OsStr, OsString}; use std::io::ErrorKind; use std::{env, mem}; -use rustc_abi::Size; +use rustc_abi::{FieldIdx, Size}; use rustc_data_structures::fx::FxHashMap; +use rustc_index::IndexVec; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; @@ -118,7 +119,7 @@ fn alloc_env_var<'tcx>( /// Allocates an `environ` block with the given list of pointers. fn alloc_environ_block<'tcx>( ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>, - mut vars: Vec, + mut vars: IndexVec, ) -> InterpResult<'tcx, Pointer> { // Add trailing null. vars.push(Pointer::null()); @@ -129,7 +130,7 @@ fn alloc_environ_block<'tcx>( u64::try_from(vars.len()).unwrap(), ))?; let vars_place = ecx.allocate(vars_layout, MiriMemoryKind::Runtime.into())?; - for (idx, var) in vars.into_iter().enumerate() { + for (idx, var) in vars.into_iter_enumerated() { let place = ecx.project_field(&vars_place, idx)?; ecx.write_pointer(var, &place)?; } diff --git a/src/tools/miri/src/shims/unix/freebsd/sync.rs b/src/tools/miri/src/shims/unix/freebsd/sync.rs index 54650f35b2c..f4e7d9e58f9 100644 --- a/src/tools/miri/src/shims/unix/freebsd/sync.rs +++ b/src/tools/miri/src/shims/unix/freebsd/sync.rs @@ -2,6 +2,8 @@ use core::time::Duration; +use rustc_abi::FieldIdx; + use crate::concurrency::sync::FutexRef; use crate::*; @@ -214,18 +216,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Only flag allowed is UMTX_ABSTIME. let abs_time = this.eval_libc_u32("UMTX_ABSTIME"); - let timespec_place = this.project_field(ut, 0)?; + let timespec_place = this.project_field(ut, FieldIdx::from_u32(0))?; // Inner `timespec` must still be valid. let duration = match this.read_timespec(×pec_place)? { Some(dur) => dur, None => return interp_ok(None), }; - let flags_place = this.project_field(ut, 1)?; + let flags_place = this.project_field(ut, FieldIdx::from_u32(1))?; let flags = this.read_scalar(&flags_place)?.to_u32()?; let abs_time_flag = flags == abs_time; - let clock_id_place = this.project_field(ut, 2)?; + let clock_id_place = this.project_field(ut, FieldIdx::from_u32(2))?; let clock_id = this.read_scalar(&clock_id_place)?.to_i32()?; let timeout_clock = this.translate_umtx_time_clock_id(clock_id)?; diff --git a/src/tools/miri/src/shims/unix/linux_like/epoll.rs b/src/tools/miri/src/shims/unix/linux_like/epoll.rs index b489595b4cd..f971fb10b19 100644 --- a/src/tools/miri/src/shims/unix/linux_like/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux_like/epoll.rs @@ -4,6 +4,8 @@ use std::io; use std::rc::{Rc, Weak}; use std::time::Duration; +use rustc_abi::FieldIdx; + use crate::concurrency::VClock; use crate::shims::files::{ DynFileDescriptionRef, FdId, FileDescription, FileDescriptionRef, WeakFileDescriptionRef, @@ -284,8 +286,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if op == epoll_ctl_add || op == epoll_ctl_mod { // Read event bitmask and data from epoll_event passed by caller. - let mut events = this.read_scalar(&this.project_field(&event, 0)?)?.to_u32()?; - let data = this.read_scalar(&this.project_field(&event, 1)?)?.to_u64()?; + let mut events = this.read_scalar(&this.project_field(&event, FieldIdx::ZERO)?)?.to_u32()?; + let data = this.read_scalar(&this.project_field(&event, FieldIdx::ONE)?)?.to_u64()?; // Unset the flag we support to discover if any unsupported flags are used. let mut flags = events; diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 7dee8ddd23c..1e82f521249 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -1,4 +1,4 @@ -use rustc_abi::{CanonAbi, Size}; +use rustc_abi::{CanonAbi, FieldIdx, Size}; use rustc_apfloat::Float; use rustc_apfloat::ieee::Single; use rustc_middle::ty::Ty; @@ -54,8 +54,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let (sum, cb_out) = carrying_add(this, cb_in, a, b, op)?; - this.write_scalar(cb_out, &this.project_field(dest, 0)?)?; - this.write_immediate(*sum, &this.project_field(dest, 1)?)?; + this.write_scalar(cb_out, &this.project_field(dest, FieldIdx::ZERO)?)?; + this.write_immediate(*sum, &this.project_field(dest, FieldIdx::ONE)?)?; } // Used to implement the `_addcarryx_u{32, 64}` functions. They are semantically identical with the `_addcarry_u{32, 64}` functions, -- cgit 1.4.1-3-g733a5 From 0ffff4657ac85612195a6ce1144cc21fc48eca4f Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Fri, 6 Jun 2025 06:39:51 +0200 Subject: remove extraneous text "Basic usage" implies there is an example that shows advanced usage --- library/alloc/src/slice.rs | 2 -- library/alloc/src/str.rs | 4 ---- library/core/src/num/nonzero.rs | 33 --------------------------------- 3 files changed, 39 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index b49b3f41a76..b4da56578c8 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -493,8 +493,6 @@ impl [T] { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]); /// ``` diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index f1b1734b8b2..22cdd8ecde0 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -246,8 +246,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "this is old"; /// @@ -303,8 +301,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "foo foo 123 foo"; /// assert_eq!("new new 123 foo", s.replacen("foo", "new", 2)); diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index a279f002772..511807b409f 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -551,8 +551,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// # use std::num::NonZero; /// # @@ -583,8 +581,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// # use std::num::NonZero; /// # @@ -612,8 +608,6 @@ macro_rules! nonzero_integer { /// /// # Example /// - /// Basic usage: - /// /// ``` /// #![feature(isolate_most_least_significant_one)] /// @@ -644,8 +638,6 @@ macro_rules! nonzero_integer { /// /// # Example /// - /// Basic usage: - /// /// ``` /// #![feature(isolate_most_least_significant_one)] /// @@ -676,8 +668,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// # use std::num::NonZero; /// # @@ -713,8 +703,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -746,8 +734,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -775,8 +761,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -805,8 +789,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -837,8 +819,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -872,8 +852,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -907,8 +885,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -942,8 +918,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -1635,8 +1609,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// # use std::num::NonZero; /// # @@ -1666,7 +1638,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// /// # Examples /// - /// Basic usage: /// ``` /// # use std::num::NonZero; /// # @@ -1699,8 +1670,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// # use std::num::NonZero; /// @@ -2138,8 +2107,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// # use std::num::NonZero; /// -- cgit 1.4.1-3-g733a5 From 8a7262c42688e3737bf7dc8fd5c0858374f1251e Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 5 Jun 2025 15:48:37 +0000 Subject: deduplicate more `walk_*` methods in AST visit --- compiler/rustc_ast/src/mut_visit.rs | 100 ++--------- compiler/rustc_ast/src/visit.rs | 263 ++++++++++++++-------------- compiler/rustc_passes/src/lang_items.rs | 20 +-- compiler/rustc_resolve/src/check_unused.rs | 53 +++--- compiler/rustc_resolve/src/def_collector.rs | 9 +- 5 files changed, 188 insertions(+), 257 deletions(-) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index bb95a23c863..77cbdde61a4 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -208,7 +208,7 @@ pub trait MutVisitor: Sized { } fn visit_ident(&mut self, i: &mut Ident) { - walk_ident(self, i); + self.visit_span(&mut i.span); } fn visit_path(&mut self, p: &mut Path) { @@ -364,13 +364,16 @@ pub trait MutVisitor: Sized { super::common_visitor_and_walkers!((mut) MutVisitor); macro_rules! generate_flat_map_visitor_fns { - ($($name:ident, $Ty:ty, $flat_map_fn:ident;)+) => { + ($($name:ident, $Ty:ty, $flat_map_fn:ident$(, $param:ident: $ParamTy:ty)*;)+) => { $( fn $name( vis: &mut V, values: &mut ThinVec<$Ty>, + $( + $param: $ParamTy, + )* ) { - values.flat_map_in_place(|value| vis.$flat_map_fn(value)); + values.flat_map_in_place(|value| vis.$flat_map_fn(value$(,$param)*)); } )+ } @@ -383,6 +386,8 @@ generate_flat_map_visitor_fns! { visit_stmts, Stmt, flat_map_stmt; visit_exprs, P, filter_map_expr; visit_pat_fields, PatField, flat_map_pat_field; + visit_variants, Variant, flat_map_variant; + visit_assoc_items, P, flat_map_assoc_item, ctxt: AssocCtxt; } #[inline] @@ -439,15 +444,6 @@ fn visit_delim_args(vis: &mut T, args: &mut DelimArgs) { vis.visit_span(close); } -pub fn walk_pat_field(vis: &mut T, fp: &mut PatField) { - let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = fp; - vis.visit_id(id); - visit_attrs(vis, attrs); - vis.visit_ident(ident); - vis.visit_pat(pat); - vis.visit_span(span); -} - pub fn walk_flat_map_pat_field( vis: &mut T, mut fp: PatField, @@ -456,21 +452,13 @@ pub fn walk_flat_map_pat_field( smallvec![fp] } -fn walk_use_tree(vis: &mut T, use_tree: &mut UseTree) { - let UseTree { prefix, kind, span } = use_tree; - vis.visit_path(prefix); - match kind { - UseTreeKind::Simple(rename) => visit_opt(rename, |rename| vis.visit_ident(rename)), - UseTreeKind::Nested { items, span } => { - for (tree, id) in items { - vis.visit_id(id); - vis.visit_use_tree(tree); - } - vis.visit_span(span); - } - UseTreeKind::Glob => {} - } - vis.visit_span(span); +fn visit_nested_use_tree( + vis: &mut V, + nested_tree: &mut UseTree, + nested_id: &mut NodeId, +) { + vis.visit_id(nested_id); + vis.visit_use_tree(nested_tree); } pub fn walk_arm(vis: &mut T, arm: &mut Arm) { @@ -507,31 +495,6 @@ fn walk_assoc_item_constraint( vis.visit_span(span); } -pub fn walk_ty_pat(vis: &mut T, ty: &mut TyPat) { - let TyPat { id, kind, span, tokens: _ } = ty; - vis.visit_id(id); - match kind { - TyPatKind::Range(start, end, _include_end) => { - visit_opt(start, |c| vis.visit_anon_const(c)); - visit_opt(end, |c| vis.visit_anon_const(c)); - } - TyPatKind::Or(variants) => visit_thin_vec(variants, |p| vis.visit_ty_pat(p)), - TyPatKind::Err(_) => {} - } - vis.visit_span(span); -} - -pub fn walk_variant(visitor: &mut T, variant: &mut Variant) { - let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = variant; - visitor.visit_id(id); - visit_attrs(visitor, attrs); - visitor.visit_vis(vis); - visitor.visit_ident(ident); - visitor.visit_variant_data(data); - visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr)); - visitor.visit_span(span); -} - pub fn walk_flat_map_variant( vis: &mut T, mut variant: Variant, @@ -540,25 +503,6 @@ pub fn walk_flat_map_variant( smallvec![variant] } -fn walk_ident(vis: &mut T, Ident { name: _, span }: &mut Ident) { - vis.visit_span(span); -} - -fn walk_path(vis: &mut T, Path { segments, span, tokens: _ }: &mut Path) { - for segment in segments { - vis.visit_path_segment(segment); - } - vis.visit_span(span); -} - -fn walk_qself(vis: &mut T, qself: &mut Option>) { - visit_opt(qself, |qself| { - let QSelf { ty, path_span, position: _ } = &mut **qself; - vis.visit_ty(ty); - vis.visit_span(path_span); - }) -} - fn walk_generic_args(vis: &mut T, generic_args: &mut GenericArgs) { match generic_args { GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data), @@ -841,11 +785,6 @@ fn walk_variant_data(vis: &mut T, vdata: &mut VariantData) { } } -fn walk_trait_ref(vis: &mut T, TraitRef { path, ref_id }: &mut TraitRef) { - vis.visit_id(ref_id); - vis.visit_path(path); -} - pub fn walk_field_def(visitor: &mut T, fd: &mut FieldDef) { let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety, default } = fd; visitor.visit_id(id); @@ -866,15 +805,6 @@ pub fn walk_flat_map_field_def( smallvec![fd] } -pub fn walk_expr_field(vis: &mut T, f: &mut ExprField) { - let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = f; - vis.visit_id(id); - visit_attrs(vis, attrs); - vis.visit_ident(ident); - vis.visit_expr(expr); - vis.visit_span(span); -} - pub fn walk_flat_map_expr_field( vis: &mut T, mut f: ExprField, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 82c58a72be3..d2f22b04a67 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -219,9 +219,6 @@ pub trait Visitor<'ast>: Sized { fn visit_field_def(&mut self, s: &'ast FieldDef) -> Self::Result { walk_field_def(self, s) } - fn visit_enum_def(&mut self, enum_definition: &'ast EnumDef) -> Self::Result { - walk_enum_def(self, enum_definition) - } fn visit_variant(&mut self, v: &'ast Variant) -> Self::Result { walk_variant(self, v) } @@ -246,13 +243,12 @@ pub trait Visitor<'ast>: Sized { fn visit_path(&mut self, path: &'ast Path) -> Self::Result { walk_path(self, path) } - fn visit_use_tree( - &mut self, - use_tree: &'ast UseTree, - id: NodeId, - _nested: bool, - ) -> Self::Result { - walk_use_tree(self, use_tree, id) + fn visit_use_tree(&mut self, use_tree: &'ast UseTree) -> Self::Result { + walk_use_tree(self, use_tree) + } + fn visit_nested_use_tree(&mut self, use_tree: &'ast UseTree, id: NodeId) -> Self::Result { + try_visit!(self.visit_id(id)); + self.visit_use_tree(use_tree) } fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) -> Self::Result { walk_path_segment(self, path_segment) @@ -472,8 +468,7 @@ macro_rules! common_visitor_and_walkers { ) $(-> >::Result)? { match self { ItemKind::ExternCrate(_orig_name, ident) => vis.visit_ident(ident), - // FIXME(fee1-dead): look into this weird assymetry - ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree$(${ignore($lt)}, id, false)?), + ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), ItemKind::Static(box StaticItem { ident, ty, @@ -536,10 +531,7 @@ macro_rules! common_visitor_and_walkers { ItemKind::Enum(ident, generics, enum_definition) => { try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_generics(generics)); - $(${ignore($mut)} - enum_definition.variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); - )? - $(${ignore($lt)}vis.visit_enum_def(enum_definition))? + visit_variants(vis, &$($mut)? enum_definition.variants) } ItemKind::Struct(ident, generics, variant_data) | ItemKind::Union(ident, generics, variant_data) => { @@ -564,35 +556,14 @@ macro_rules! common_visitor_and_walkers { try_visit!(visit_polarity(vis, polarity)); visit_opt!(vis, visit_trait_ref, of_trait); try_visit!(vis.visit_ty(self_ty)); - $(${ignore($mut)} - items.flat_map_in_place(|item| { - vis.flat_map_assoc_item(item, AssocCtxt::Impl { of_trait: of_trait.is_some() }) - }); - )? - $(${ignore($lt)} - walk_list!( - vis, - visit_assoc_item, - items, - AssocCtxt::Impl { of_trait: of_trait.is_some() } - ); - >::Result::output() - )? + visit_assoc_items(vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() }) } ItemKind::Trait(box Trait { safety, is_auto: _, ident, generics, bounds, items }) => { try_visit!(visit_safety(vis, safety)); try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_generics(generics)); try_visit!(visit_bounds(vis, bounds, BoundKind::Bound)); - $(${ignore($mut)} - items.flat_map_in_place(|item| { - vis.flat_map_assoc_item(item, AssocCtxt::Trait) - }); - )? - $(${ignore($lt)} - walk_list!(vis, visit_assoc_item, items, AssocCtxt::Trait); - >::Result::output() - )? + visit_assoc_items(vis, items, AssocCtxt::Trait) } ItemKind::TraitAlias(ident, generics, bounds) => { try_visit!(vis.visit_ident(ident)); @@ -987,7 +958,7 @@ macro_rules! common_visitor_and_walkers { visit_span(vis, span) } - fn walk_poly_trait_ref<$($lt,)? V: $Visitor$(<$lt>)?>( + pub fn walk_poly_trait_ref<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, p: &$($lt)? $($mut)? PolyTraitRef, ) $(-> >::Result)? { @@ -997,19 +968,129 @@ macro_rules! common_visitor_and_walkers { try_visit!(vis.visit_trait_ref(trait_ref)); visit_span(vis, span) } + + pub fn walk_trait_ref<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + TraitRef { path, ref_id }: &$($lt)? $($mut)? TraitRef, + ) $(-> >::Result)? { + try_visit!(vis.visit_path(path)); + visit_id(vis, ref_id) + } + + pub fn walk_variant<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + variant: &$($lt)? $($mut)? Variant, + ) $(-> >::Result)? { + let Variant { attrs, id, span, vis: visibility, ident, data, disr_expr, is_placeholder: _ } = variant; + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(vis.visit_vis(visibility)); + try_visit!(vis.visit_ident(ident)); + try_visit!(vis.visit_variant_data(data)); + $(${ignore($lt)} visit_opt!(vis, visit_variant_discr, disr_expr); )? + $(${ignore($mut)} visit_opt!(vis, visit_anon_const, disr_expr); )? + visit_span(vis, span) + } + + pub fn walk_expr_field<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + f: &$($lt)? $($mut)? ExprField, + ) $(-> >::Result)? { + let ExprField { attrs, id, span, ident, expr, is_shorthand: _, is_placeholder: _ } = f; + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(vis.visit_ident(ident)); + try_visit!(vis.visit_expr(expr)); + visit_span(vis, span) + } + + pub fn walk_pat_field<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + fp: &$($lt)? $($mut)? PatField, + ) $(-> >::Result)? { + let PatField { ident, pat, is_shorthand: _, attrs, id, span, is_placeholder: _ } = fp; + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(vis.visit_ident(ident)); + try_visit!(vis.visit_pat(pat)); + visit_span(vis, span) + } + + pub fn walk_ty_pat<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + tp: &$($lt)? $($mut)? TyPat, + ) $(-> >::Result)? { + let TyPat { id, kind, span, tokens: _ } = tp; + try_visit!(visit_id(vis, id)); + match kind { + TyPatKind::Range(start, end, _include_end) => { + visit_opt!(vis, visit_anon_const, start); + visit_opt!(vis, visit_anon_const, end); + } + TyPatKind::Or(variants) => walk_list!(vis, visit_ty_pat, variants), + TyPatKind::Err(_) => {} + } + visit_span(vis, span) + } + + fn walk_qself<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + qself: &$($lt)? $($mut)? Option>, + ) $(-> >::Result)? { + if let Some(qself) = qself { + let QSelf { ty, path_span, position: _ } = &$($mut)? **qself; + try_visit!(vis.visit_ty(ty)); + try_visit!(visit_span(vis, path_span)); + } + $(>::Result::output())? + } + + pub fn walk_path<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + path: &$($lt)? $($mut)? Path, + ) $(-> >::Result)? { + let Path { span, segments, tokens: _ } = path; + walk_list!(vis, visit_path_segment, segments); + visit_span(vis, span) + } + + pub fn walk_use_tree<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + use_tree: &$($lt)? $($mut)? UseTree, + ) $(-> >::Result)? { + let UseTree { prefix, kind, span } = use_tree; + try_visit!(vis.visit_path(prefix)); + match kind { + UseTreeKind::Simple(rename) => { + // The extra IDs are handled during AST lowering. + visit_opt!(vis, visit_ident, rename); + } + UseTreeKind::Glob => {} + UseTreeKind::Nested { items, span } => { + for (nested_tree, nested_id) in items { + try_visit!(visit_nested_use_tree(vis, nested_tree, nested_id)); + } + try_visit!(visit_span(vis, span)); + } + } + visit_span(vis, span) + } }; } common_visitor_and_walkers!(Visitor<'a>); macro_rules! generate_list_visit_fns { - ($($name:ident, $Ty:ty, $visit_fn:ident;)+) => { + ($($name:ident, $Ty:ty, $visit_fn:ident$(, $param:ident: $ParamTy:ty)*;)+) => { $( fn $name<'a, V: Visitor<'a>>( vis: &mut V, values: &'a ThinVec<$Ty>, + $( + $param: $ParamTy, + )* ) -> V::Result { - walk_list!(vis, $visit_fn, values); + walk_list!(vis, $visit_fn, values$(,$param)*); V::Result::output() } )+ @@ -1022,99 +1103,17 @@ generate_list_visit_fns! { visit_generic_params, GenericParam, visit_generic_param; visit_stmts, Stmt, visit_stmt; visit_pat_fields, PatField, visit_pat_field; + visit_variants, Variant, visit_variant; + visit_assoc_items, P, visit_assoc_item, ctxt: AssocCtxt; } -pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitRef) -> V::Result { - let TraitRef { path, ref_id } = trait_ref; - try_visit!(visitor.visit_path(path)); - visitor.visit_id(*ref_id) -} - -pub fn walk_enum_def<'a, V: Visitor<'a>>( - visitor: &mut V, - EnumDef { variants }: &'a EnumDef, +#[expect(rustc::pass_by_value)] // needed for symmetry with mut_visit +fn visit_nested_use_tree<'a, V: Visitor<'a>>( + vis: &mut V, + nested_tree: &'a UseTree, + &nested_id: &NodeId, ) -> V::Result { - walk_list!(visitor, visit_variant, variants); - V::Result::output() -} - -pub fn walk_variant<'a, V: Visitor<'a>>(visitor: &mut V, variant: &'a Variant) -> V::Result -where - V: Visitor<'a>, -{ - let Variant { attrs, id: _, span: _, vis, ident, data, disr_expr, is_placeholder: _ } = variant; - walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_vis(vis)); - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_variant_data(data)); - visit_opt!(visitor, visit_variant_discr, disr_expr); - V::Result::output() -} - -pub fn walk_expr_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a ExprField) -> V::Result { - let ExprField { attrs, id: _, span: _, ident, expr, is_shorthand: _, is_placeholder: _ } = f; - walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_expr(expr)); - V::Result::output() -} - -pub fn walk_pat_field<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a PatField) -> V::Result { - let PatField { ident, pat, is_shorthand: _, attrs, id: _, span: _, is_placeholder: _ } = fp; - walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_pat(pat)); - V::Result::output() -} - -pub fn walk_ty_pat<'a, V: Visitor<'a>>(visitor: &mut V, tp: &'a TyPat) -> V::Result { - let TyPat { id: _, kind, span: _, tokens: _ } = tp; - match kind { - TyPatKind::Range(start, end, _include_end) => { - visit_opt!(visitor, visit_anon_const, start); - visit_opt!(visitor, visit_anon_const, end); - } - TyPatKind::Or(variants) => walk_list!(visitor, visit_ty_pat, variants), - TyPatKind::Err(_) => {} - } - V::Result::output() -} - -fn walk_qself<'a, V: Visitor<'a>>(visitor: &mut V, qself: &'a Option>) -> V::Result { - if let Some(qself) = qself { - let QSelf { ty, path_span: _, position: _ } = &**qself; - try_visit!(visitor.visit_ty(ty)); - } - V::Result::output() -} - -pub fn walk_path<'a, V: Visitor<'a>>(visitor: &mut V, path: &'a Path) -> V::Result { - let Path { span: _, segments, tokens: _ } = path; - walk_list!(visitor, visit_path_segment, segments); - V::Result::output() -} - -pub fn walk_use_tree<'a, V: Visitor<'a>>( - visitor: &mut V, - use_tree: &'a UseTree, - id: NodeId, -) -> V::Result { - let UseTree { prefix, kind, span: _ } = use_tree; - try_visit!(visitor.visit_id(id)); - try_visit!(visitor.visit_path(prefix)); - match kind { - UseTreeKind::Simple(rename) => { - // The extra IDs are handled during AST lowering. - visit_opt!(visitor, visit_ident, rename); - } - UseTreeKind::Glob => {} - UseTreeKind::Nested { items, span: _ } => { - for &(ref nested_tree, nested_id) in items { - try_visit!(visitor.visit_use_tree(nested_tree, nested_id, true)); - } - } - } - V::Result::output() + vis.visit_nested_use_tree(nested_tree, nested_id) } pub fn walk_generic_args<'a, V>(visitor: &mut V, generic_args: &'a GenericArgs) -> V::Result diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 275714c2d0e..3afed9784de 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -307,18 +307,14 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { self.parent_item = parent_item; } - fn visit_enum_def(&mut self, enum_definition: &'ast ast::EnumDef) { - for variant in &enum_definition.variants { - self.check_for_lang( - Target::Variant, - self.resolver.node_id_to_def_id[&variant.id], - &variant.attrs, - variant.span, - None, - ); - } - - visit::walk_enum_def(self, enum_definition); + fn visit_variant(&mut self, variant: &'ast ast::Variant) { + self.check_for_lang( + Target::Variant, + self.resolver.node_id_to_def_id[&variant.id], + &variant.attrs, + variant.span, + None, + ); } fn visit_assoc_item(&mut self, i: &'ast ast::AssocItem, ctxt: visit::AssocCtxt) { diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 9b824572b66..2e870c47f8e 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -100,6 +100,21 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { } } + fn check_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId) { + if self.r.effective_visibilities.is_exported(self.r.local_def_id(id)) { + self.check_import_as_underscore(use_tree, id); + return; + } + + if let ast::UseTreeKind::Nested { ref items, .. } = use_tree.kind { + if items.is_empty() { + self.unused_import(self.base_id).add(id); + } + } else { + self.check_import(id); + } + } + fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport { let use_tree_id = self.base_id; let use_tree = self.base_use_tree.unwrap().clone(); @@ -225,13 +240,21 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { impl<'a, 'ra, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'ra, 'tcx> { fn visit_item(&mut self, item: &'a ast::Item) { - match item.kind { + self.item_span = item.span_with_attributes(); + match &item.kind { // Ignore is_public import statements because there's no way to be sure // whether they're used or not. Also ignore imports with a dummy span // because this means that they were generated in some fashion by the // compiler and we don't need to consider them. ast::ItemKind::Use(..) if item.span.is_dummy() => return, - ast::ItemKind::ExternCrate(orig_name, ident) => { + // Use the base UseTree's NodeId as the item id + // This allows the grouping of all the lints in the same item + ast::ItemKind::Use(use_tree) => { + self.base_id = item.id; + self.base_use_tree = Some(use_tree); + self.check_use_tree(use_tree, item.id); + } + &ast::ItemKind::ExternCrate(orig_name, ident) => { self.extern_crate_items.push(ExternCrateToLint { id: item.id, span: item.span, @@ -245,32 +268,12 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'ra, 'tcx> { _ => {} } - self.item_span = item.span_with_attributes(); visit::walk_item(self, item); } - fn visit_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId, nested: bool) { - // Use the base UseTree's NodeId as the item id - // This allows the grouping of all the lints in the same item - if !nested { - self.base_id = id; - self.base_use_tree = Some(use_tree); - } - - if self.r.effective_visibilities.is_exported(self.r.local_def_id(id)) { - self.check_import_as_underscore(use_tree, id); - return; - } - - if let ast::UseTreeKind::Nested { ref items, .. } = use_tree.kind { - if items.is_empty() { - self.unused_import(self.base_id).add(id); - } - } else { - self.check_import(id); - } - - visit::walk_use_tree(self, use_tree, id); + fn visit_nested_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId) { + self.check_use_tree(use_tree, id); + visit::walk_use_tree(self, use_tree); } } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 25485be5622..dc16fe212b1 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -147,7 +147,10 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { DefKind::Macro(macro_kind) } ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, - ItemKind::Use(..) => return visit::walk_item(self, i), + ItemKind::Use(use_tree) => { + self.create_def(i.id, None, DefKind::Use, use_tree.span); + return visit::walk_item(self, i); + } ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => { return self.visit_macro_invoc(i.id); } @@ -232,9 +235,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } } - fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) { + fn visit_nested_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId) { self.create_def(id, None, DefKind::Use, use_tree.span); - visit::walk_use_tree(self, use_tree, id); + visit::walk_use_tree(self, use_tree); } fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { -- cgit 1.4.1-3-g733a5 From f9cf0964db531b234e374dfd6330e0aa0c427db0 Mon Sep 17 00:00:00 2001 From: scottmcm Date: Fri, 6 Jun 2025 09:30:40 +0000 Subject: Update compiler/rustc_abi/src/layout/ty.rs Co-authored-by: Ralf Jung --- compiler/rustc_abi/src/layout/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index eb49b977257..b5f93351d68 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -40,7 +40,7 @@ rustc_index::newtype_index! { } impl FieldIdx { - /// The second field. + /// The second field, at index 1. /// /// For use alongside [`FieldIdx::ZERO`], particularly with scalar pairs. pub const ONE: FieldIdx = FieldIdx::from_u32(1); -- cgit 1.4.1-3-g733a5 From 523cf1291bb260fffb428227821edba6b0f83eb7 Mon Sep 17 00:00:00 2001 From: Petr Sumbera Date: Fri, 6 Jun 2025 10:35:38 +0200 Subject: add solaris targets to build-manifest --- src/tools/build-manifest/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 741d7e3fa16..f8209f2c8cd 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -40,7 +40,9 @@ static HOSTS: &[&str] = &[ "powerpc64le-unknown-linux-musl", "riscv64gc-unknown-linux-gnu", "s390x-unknown-linux-gnu", + "sparcv9-sun-solaris", "x86_64-apple-darwin", + "x86_64-pc-solaris", "x86_64-pc-windows-gnu", "x86_64-pc-windows-msvc", "x86_64-unknown-freebsd", -- cgit 1.4.1-3-g733a5 From b28590847209d93a42fed462cb007a5461e95baa Mon Sep 17 00:00:00 2001 From: Ada Alakbarova <58857108+ada4a@users.noreply.github.com> Date: Fri, 6 Jun 2025 13:15:46 +0200 Subject: fix typo --- compiler/rustc_middle/src/ty/typeck_results.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index cc3887079d8..88583407d25 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -199,7 +199,7 @@ pub struct TypeckResults<'tcx> { /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions /// by applying extended parameter rules. - /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`. + /// Details may be found in `rustc_hir_analysis::check::rvalue_scopes`. pub rvalue_scopes: RvalueScopes, /// Stores the predicates that apply on coroutine witness types. -- cgit 1.4.1-3-g733a5 From 28a2e1e9c9e03b9b640fd771a58de6c2e1c3ff21 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 6 Jun 2025 14:28:37 +0200 Subject: Compute number of digits instead of relying on constant value for u128 display code --- library/core/src/fmt/num.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index ba30518d70b..dd9c379b666 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -678,8 +678,8 @@ impl fmt::Display for i128 { /// It also has to handle 1 last item, as 10^40 > 2^128 > 10^39, whereas /// 10^20 > 2^64 > 10^19. fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // 2^128 is about 3*10^38, so 39 gives an extra byte of space - let mut buf = [MaybeUninit::::uninit(); 39]; + const MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1; + let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; let mut curr = buf.len(); let (n, rem) = udiv_1e19(n); -- cgit 1.4.1-3-g733a5 From 8fc1bed0c8b6aab76d07e7576b0c1c1f29b934bf Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Thu, 29 May 2025 09:38:44 -0400 Subject: Reduce confusion of some drop order tests In addition to adhering to normal Rust casing idioms, I ran `rustfmt`. --- tests/ui/drop/issue-2735-2.rs | 13 +++++-------- tests/ui/drop/issue-2735-3.rs | 11 ++++------- tests/ui/drop/issue-2735.rs | 12 +++++------- tests/ui/drop/issue-979.rs | 11 ++++------- 4 files changed, 18 insertions(+), 29 deletions(-) diff --git a/tests/ui/drop/issue-2735-2.rs b/tests/ui/drop/issue-2735-2.rs index 66025956e08..43fbafe7a0e 100644 --- a/tests/ui/drop/issue-2735-2.rs +++ b/tests/ui/drop/issue-2735-2.rs @@ -1,27 +1,24 @@ //@ run-pass -#![allow(non_camel_case_types)] use std::cell::Cell; // This test should behave exactly like issue-2735-3 -struct defer<'a> { +struct Defer<'a> { b: &'a Cell, } -impl<'a> Drop for defer<'a> { +impl<'a> Drop for Defer<'a> { fn drop(&mut self) { self.b.set(true); } } -fn defer(b: &Cell) -> defer<'_> { - defer { - b: b - } +fn defer(b: &Cell) -> Defer<'_> { + Defer { b } } pub fn main() { let dtor_ran = &Cell::new(false); - let _ = defer(dtor_ran); + let _ = defer(dtor_ran); assert!(dtor_ran.get()); } diff --git a/tests/ui/drop/issue-2735-3.rs b/tests/ui/drop/issue-2735-3.rs index c9535168653..cc28f96d2b0 100644 --- a/tests/ui/drop/issue-2735-3.rs +++ b/tests/ui/drop/issue-2735-3.rs @@ -1,23 +1,20 @@ //@ run-pass -#![allow(non_camel_case_types)] use std::cell::Cell; // This test should behave exactly like issue-2735-2 -struct defer<'a> { +struct Defer<'a> { b: &'a Cell, } -impl<'a> Drop for defer<'a> { +impl<'a> Drop for Defer<'a> { fn drop(&mut self) { self.b.set(true); } } -fn defer(b: &Cell) -> defer<'_> { - defer { - b: b - } +fn defer(b: &Cell) -> Defer<'_> { + Defer { b } } pub fn main() { diff --git a/tests/ui/drop/issue-2735.rs b/tests/ui/drop/issue-2735.rs index cd7e0b8f461..838b9da109b 100644 --- a/tests/ui/drop/issue-2735.rs +++ b/tests/ui/drop/issue-2735.rs @@ -1,15 +1,13 @@ //@ run-pass #![allow(dead_code)] -#![allow(non_camel_case_types)] - -trait hax { - fn dummy(&self) { } +trait Hax { + fn dummy(&self) {} } -impl hax for A { } +impl Hax for A {} -fn perform_hax(x: Box) -> Box { - Box::new(x) as Box +fn perform_hax(x: Box) -> Box { + Box::new(x) as Box } fn deadcode() { diff --git a/tests/ui/drop/issue-979.rs b/tests/ui/drop/issue-979.rs index 70052708be6..abbcc71de18 100644 --- a/tests/ui/drop/issue-979.rs +++ b/tests/ui/drop/issue-979.rs @@ -1,22 +1,19 @@ //@ run-pass -#![allow(non_camel_case_types)] use std::cell::Cell; -struct r<'a> { +struct R<'a> { b: &'a Cell, } -impl<'a> Drop for r<'a> { +impl<'a> Drop for R<'a> { fn drop(&mut self) { self.b.set(self.b.get() + 1); } } -fn r(b: &Cell) -> r<'_> { - r { - b: b - } +fn r(b: &Cell) -> R<'_> { + R { b } } pub fn main() { -- cgit 1.4.1-3-g733a5 From 46a936a353d1418d572669d6aa3f63ccb0f99bea Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 6 Jun 2025 20:49:55 +0800 Subject: bootstrap: fix tracing imports --- src/bootstrap/src/core/config/config.rs | 2 -- src/bootstrap/src/core/config/mod.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 491f55ccaf3..a92d58ef9e8 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -28,8 +28,6 @@ use build_helper::git::{GitConfig, PathFreshness, check_path_modifications, outp use serde::Deserialize; #[cfg(feature = "tracing")] use tracing::{instrument, span}; -#[cfg(feature = "tracing")] -use tracing::{instrument, span}; use crate::core::build_steps::llvm; use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS; diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index f39e7b02ccc..285d20917e7 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -39,8 +39,6 @@ pub use toml::BUILDER_CONFIG_FILENAME; pub use toml::change_id::ChangeId; pub use toml::rust::LldMode; pub use toml::target::Target; -#[cfg(feature = "tracing")] -use tracing::{instrument, span}; use crate::Display; use crate::str::FromStr; -- cgit 1.4.1-3-g733a5 From 2a5225a369e87ebaac3d34583603479064e2623d Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 6 Jun 2025 13:06:59 +0000 Subject: rustc_lexer: typo fix + small cleanups --- compiler/rustc_lexer/src/cursor.rs | 2 +- compiler/rustc_lexer/src/lib.rs | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs index 526693d3de1..165262b82c7 100644 --- a/compiler/rustc_lexer/src/cursor.rs +++ b/compiler/rustc_lexer/src/cursor.rs @@ -68,7 +68,7 @@ impl<'a> Cursor<'a> { /// Peeks the third symbol from the input stream without consuming it. pub fn third(&self) -> char { - // `.next()` optimizes better than `.nth(1)` + // `.next()` optimizes better than `.nth(2)` let mut iter = self.chars.clone(); iter.next(); iter.next(); diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index ece3f9107b0..b2bd5e188ef 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -30,14 +30,13 @@ mod cursor; #[cfg(test)] mod tests; +use LiteralKind::*; +use TokenKind::*; +use cursor::EOF_CHAR; +pub use cursor::{Cursor, FrontmatterAllowed}; use unicode_properties::UnicodeEmoji; pub use unicode_xid::UNICODE_VERSION as UNICODE_XID_VERSION; -use self::LiteralKind::*; -use self::TokenKind::*; -use crate::cursor::EOF_CHAR; -pub use crate::cursor::{Cursor, FrontmatterAllowed}; - /// Parsed token. /// It doesn't contain information about data that has been parsed, /// only the type of the token and its size. @@ -372,9 +371,8 @@ pub fn is_ident(string: &str) -> bool { impl Cursor<'_> { /// Parses a token from the input string. pub fn advance_token(&mut self) -> Token { - let first_char = match self.bump() { - Some(c) => c, - None => return Token::new(TokenKind::Eof, 0), + let Some(first_char) = self.bump() else { + return Token::new(TokenKind::Eof, 0); }; let token_kind = match first_char { @@ -788,7 +786,7 @@ impl Cursor<'_> { } else { // No base prefix, parse number in the usual way. self.eat_decimal_digits(); - }; + } match self.first() { // Don't be greedy if this is actually an -- cgit 1.4.1-3-g733a5 From 8addb6f3be3cd166bf40919c766cde2efc19fbaa Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 5 Jun 2025 16:36:47 +0000 Subject: Filter out universals and lifetimes from stalled_vars --- compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs | 13 ++++++++++++- .../src/solve/fulfill/derive_errors.rs | 6 ++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 38d7ff576a5..345ece20b7e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -544,8 +544,19 @@ where // to recompute this goal. HasChanged::Yes => None, HasChanged::No => { - // Remove the unconstrained RHS arg, which is expected to have changed. let mut stalled_vars = orig_values; + + // Remove the canonicalized universal vars, since we only care about stalled existentials. + stalled_vars.retain(|arg| match arg.kind() { + ty::GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Infer(_)), + ty::GenericArgKind::Const(ct) => { + matches!(ct.kind(), ty::ConstKind::Infer(_)) + } + // Lifetimes can never stall goals. + ty::GenericArgKind::Lifetime(_) => false, + }); + + // Remove the unconstrained RHS arg, which is expected to have changed. if let Some(normalizes_to) = goal.predicate.as_normalizes_to() { let normalizes_to = normalizes_to.skip_binder(); let rhs_arg: I::GenericArg = normalizes_to.term.into(); diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 1c9d69da322..36a8ae675c0 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -120,13 +120,15 @@ pub(super) fn fulfillment_error_for_stalled<'tcx>( false, ), Ok(GoalEvaluation { certainty: Certainty::Yes, .. }) => { - bug!( + span_bug!( + root_obligation.cause.span, "did not expect successful goal when collecting ambiguity errors for `{:?}`", infcx.resolve_vars_if_possible(root_obligation.predicate), ) } Err(_) => { - bug!( + span_bug!( + root_obligation.cause.span, "did not expect selection error when collecting ambiguity errors for `{:?}`", infcx.resolve_vars_if_possible(root_obligation.predicate), ) -- cgit 1.4.1-3-g733a5 From db1cecaacc9c8ac7716a2ee86733d9a3daf089ef Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 6 Jun 2025 16:59:04 +0000 Subject: Don't walk into Certainty::Yes subgoals in NestedObligationsForSelfTy --- .../rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index e068e607902..7f1f3c3c802 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -4,6 +4,7 @@ use rustc_infer::traits::{self, ObligationCause, PredicateObligations}; use rustc_middle::traits::solve::GoalSource; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_span::Span; +use rustc_trait_selection::solve::Certainty; use rustc_trait_selection::solve::inspect::{ InspectConfig, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor, }; @@ -117,6 +118,20 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> { } fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) { + // No need to walk into goal subtrees that certainly hold, since they + // wouldn't then be stalled on an infer var. + // FIXME: We also walk into normalizes-to goals since their certainty + // is forced to `Certainty::Yes` since they pass down ambiguous subgoals + // to their parent. + if inspect_goal.result() == Ok(Certainty::Yes) + && !matches!( + inspect_goal.goal().predicate.kind().skip_binder(), + ty::PredicateKind::NormalizesTo(_) + ) + { + return; + } + let tcx = self.fcx.tcx; let goal = inspect_goal.goal(); if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty) -- cgit 1.4.1-3-g733a5 From b25aa2629892a71cd81c822e9ef4a07249aeb89d Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 30 May 2025 14:40:44 -0700 Subject: compiler: set Apple frame pointers by architecture Apple targets can now overriding this configuration and instead use the default based on their architecture, which means aarch64 targets now have less frame pointers in leaf functions. --- compiler/rustc_target/src/spec/base/apple/mod.rs | 8 +++++++- compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs | 3 +-- compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs | 3 +-- .../rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs | 3 +-- compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs | 3 +-- compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs | 3 +-- compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs | 3 +-- compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs | 3 +-- .../rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs | 3 +-- .../rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs | 3 +-- compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs | 3 +-- compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs | 3 +-- compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs | 3 +-- compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs | 9 ++------- compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs | 3 +-- compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs | 3 +-- 16 files changed, 23 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index 46fcd7d5c51..aa6d1ec7009 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -124,7 +124,13 @@ pub(crate) fn base( // to v4, so we do the same. // https://github.com/llvm/llvm-project/blob/378778a0d10c2f8d5df8ceff81f95b6002984a4b/clang/lib/Driver/ToolChains/Darwin.cpp#L1203 default_dwarf_version: 4, - frame_pointer: FramePointer::Always, + frame_pointer: match arch { + // clang ignores `-fomit-frame-pointer` for Armv7, it only accepts `-momit-leaf-frame-pointer` + Armv7k | Armv7s => FramePointer::Always, + // clang supports omitting frame pointers for the rest, but... don't? + Arm64 | Arm64e | Arm64_32 => FramePointer::NonLeaf, + I386 | I686 | X86_64 | X86_64h => FramePointer::Always, + }, has_rpath: true, dll_suffix: ".dylib".into(), archive_format: "darwin".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs index 6587abb2ba7..4dd39877715 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("macos", Arch::Arm64, TargetAbi::Normal); @@ -17,7 +17,6 @@ pub(crate) fn target() -> Target { arch, options: TargetOptions { mcount: "\u{1}mcount".into(), - frame_pointer: FramePointer::NonLeaf, cpu: "apple-m1".into(), max_atomic_width: Some(128), // FIXME: The leak sanitizer currently fails the tests, see #88132. diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs index 183a6c6f2d7..769a7b6c391 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::Normal); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, ..opts }, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs index ce9ae03e699..4bb2f73e4f9 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::MacCatalyst); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a12".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD, ..opts }, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs index 4405e3fec02..7d04034e759 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::Simulator); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, ..opts }, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs index 037685db1b3..ec92a40e255 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions}; +use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetAbi::Normal); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, ..opts }, } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs index a386220e6fc..74fbe5a89ca 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions}; +use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetAbi::Simulator); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, ..opts }, } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs index 2c1dfdd55ed..dc595fbe7b6 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetAbi::Normal); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a16".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, ..opts }, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs index c0b8b409797..06ff1bfb2f0 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetAbi::Simulator); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a16".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, ..opts }, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs index 62968f5b555..bad9f6c1485 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions}; +use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("watchos", Arch::Arm64, TargetAbi::Simulator); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, ..opts }, } diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs index 79b95dbde52..326f2b16d59 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("macos", Arch::Arm64e, TargetAbi::Normal); @@ -17,7 +17,6 @@ pub(crate) fn target() -> Target { arch, options: TargetOptions { mcount: "\u{1}mcount".into(), - frame_pointer: FramePointer::NonLeaf, cpu: "apple-m1".into(), max_atomic_width: Some(128), // FIXME: The leak sanitizer currently fails the tests, see #88132. diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs index 848dbeec199..01c6f0b888d 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("ios", Arch::Arm64e, TargetAbi::Normal); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a12,+v8.3a,+pauth".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, ..opts }, diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs index 3dbe169e826..cad3650bda1 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions}; +use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("tvos", Arch::Arm64e, TargetAbi::Normal); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a12,+v8.3a,+pauth".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, ..opts }, } diff --git a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs index 161db9a08bb..d1339c57b00 100644 --- a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions}; +use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("macos", Arch::I686, TargetAbi::Normal); @@ -16,11 +16,6 @@ pub(crate) fn target() -> Target { i128:128-f64:32:64-f80:128-n8:16:32-S128" .into(), arch, - options: TargetOptions { - mcount: "\u{1}mcount".into(), - max_atomic_width: Some(64), - frame_pointer: FramePointer::Always, - ..opts - }, + options: TargetOptions { mcount: "\u{1}mcount".into(), max_atomic_width: Some(64), ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs index 64c17054780..eba595ba7dd 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("macos", Arch::X86_64, TargetAbi::Normal); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { mcount: "\u{1}mcount".into(), max_atomic_width: Some(128), // penryn+ supports cmpxchg16b - frame_pointer: FramePointer::Always, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK diff --git a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs index 11010b7d92f..e64556c4132 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs @@ -1,10 +1,9 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (mut opts, llvm_target, arch) = base("macos", Arch::X86_64h, TargetAbi::Normal); opts.max_atomic_width = Some(128); - opts.frame_pointer = FramePointer::Always; opts.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD; -- cgit 1.4.1-3-g733a5 From 7efd90a1a56f5f4cf5a73f40b1b84032407873a1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 6 Jun 2025 17:00:06 +0000 Subject: Treat normalizing consts like normalizing types in deeply normalize --- .../rustc_trait_selection/src/solve/normalize.rs | 47 +++++++++++----------- tests/crashes/140571.rs | 14 ------- .../overlap-due-to-unsatisfied-const-bound.rs | 21 ++++++++++ .../overlap-due-to-unsatisfied-const-bound.stderr | 21 ++++++++++ 4 files changed, 66 insertions(+), 37 deletions(-) delete mode 100644 tests/crashes/140571.rs create mode 100644 tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs create mode 100644 tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index d903f94b489..a8d32221204 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -16,7 +16,6 @@ use tracing::instrument; use super::{FulfillmentCtxt, NextSolverError}; use crate::error_reporting::InferCtxtErrorExt; use crate::error_reporting::traits::OverflowCause; -use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError}; /// Deeply normalize all aliases in `value`. This does not handle inference and expects @@ -143,12 +142,18 @@ where fn normalize_unevaluated_const( &mut self, - uv: ty::UnevaluatedConst<'tcx>, + alias_ct: ty::Const<'tcx>, ) -> Result, Vec> { + assert_matches!(alias_ct.kind(), ty::ConstKind::Unevaluated(..)); + let infcx = self.at.infcx; let tcx = infcx.tcx; let recursion_limit = tcx.recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { + let ty::ConstKind::Unevaluated(uv) = alias_ct.kind() else { + unreachable!(); + }; + self.at.infcx.err_ctxt().report_overflow_error( OverflowCause::DeeplyNormalize(uv.into()), self.at.cause.span, @@ -164,21 +169,20 @@ where tcx, self.at.cause.clone(), self.at.param_env, - ty::NormalizesTo { alias: uv.into(), term: new_infer_ct.into() }, + ty::PredicateKind::AliasRelate( + alias_ct.into(), + new_infer_ct.into(), + ty::AliasRelationDirection::Equate, + ), ); - let result = if infcx.predicate_may_hold(&obligation) { - self.fulfill_cx.register_predicate_obligation(infcx, obligation); - let errors = self.fulfill_cx.select_where_possible(infcx); - if !errors.is_empty() { - return Err(errors); - } - let ct = infcx.resolve_vars_if_possible(new_infer_ct); - ct.try_fold_with(self)? - } else { - ty::Const::new_unevaluated(tcx, uv).try_super_fold_with(self)? - }; + self.fulfill_cx.register_predicate_obligation(infcx, obligation); + self.select_all_and_stall_coroutine_predicates()?; + // Alias is guaranteed to be fully structurally resolved, + // so we can super fold here. + let ct = infcx.resolve_vars_if_possible(new_infer_ct); + let result = ct.try_super_fold_with(self)?; self.depth -= 1; Ok(result) } @@ -260,15 +264,12 @@ where return Ok(ct); } - let uv = match ct.kind() { - ty::ConstKind::Unevaluated(ct) => ct, - _ => return ct.try_super_fold_with(self), - }; + let ty::ConstKind::Unevaluated(..) = ct.kind() else { return ct.try_super_fold_with(self) }; - if uv.has_escaping_bound_vars() { - let (uv, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, uv); - let result = ensure_sufficient_stack(|| self.normalize_unevaluated_const(uv))?; + if ct.has_escaping_bound_vars() { + let (ct, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ct); + let result = ensure_sufficient_stack(|| self.normalize_unevaluated_const(ct))?; Ok(PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, @@ -278,7 +279,7 @@ where result, )) } else { - ensure_sufficient_stack(|| self.normalize_unevaluated_const(uv)) + ensure_sufficient_stack(|| self.normalize_unevaluated_const(ct)) } } } diff --git a/tests/crashes/140571.rs b/tests/crashes/140571.rs deleted file mode 100644 index 97fa1d8432d..00000000000 --- a/tests/crashes/140571.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ known-bug: #140571 -pub trait IsVoid { - const IS_VOID: bool; -} -impl IsVoid for T { - default const IS_VOID: bool = false; -} -impl Maybe for () where T: NotVoid + ?Sized {} - -pub trait NotVoid {} -impl NotVoid for T where T: IsVoid + ?Sized {} - -pub trait Maybe {} -impl Maybe for T {} diff --git a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs new file mode 100644 index 00000000000..f4cde1d62b2 --- /dev/null +++ b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs @@ -0,0 +1,21 @@ +// Regression test for #140571. The compiler used to ICE + +#![feature(associated_const_equality, specialization)] +//~^ WARN the feature `specialization` is incomplete + +pub trait IsVoid { + const IS_VOID: bool; +} +impl IsVoid for T { + default const IS_VOID: bool = false; +} + +pub trait NotVoid {} +impl NotVoid for T where T: IsVoid + ?Sized {} + +pub trait Maybe {} +impl Maybe for T {} +impl Maybe for () where T: NotVoid + ?Sized {} +//~^ ERROR conflicting implementations of trait `Maybe<()>` for type `()` + +fn main() {} diff --git a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr new file mode 100644 index 00000000000..a26b30fbb63 --- /dev/null +++ b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr @@ -0,0 +1,21 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:39 + | +LL | #![feature(associated_const_equality, specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0119]: conflicting implementations of trait `Maybe<()>` for type `()` + --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:18:1 + | +LL | impl Maybe for T {} + | ---------------------- first implementation here +LL | impl Maybe for () where T: NotVoid + ?Sized {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0119`. -- cgit 1.4.1-3-g733a5 From eba3a6106728e131286e3751459fccd7594102ef Mon Sep 17 00:00:00 2001 From: schvv31n Date: Tue, 4 Mar 2025 21:29:45 +0000 Subject: Stabilised `os_string_pathbuf_leak` --- library/std/src/ffi/os_str.rs | 2 +- library/std/src/path.rs | 2 +- library/std/tests/path.rs | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 21d5b7292e8..3cc225004ea 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -568,7 +568,7 @@ impl OsString { /// However, keep in mind that trimming the capacity may result in a reallocation and copy. /// /// [`into_boxed_os_str`]: Self::into_boxed_os_str - #[unstable(feature = "os_string_pathbuf_leak", issue = "125965")] + #[stable(feature = "os_string_pathbuf_leak", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn leak<'a>(self) -> &'a mut OsStr { OsStr::from_inner_mut(self.inner.leak()) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 014b56d28f4..826d9f0f39d 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1252,7 +1252,7 @@ impl PathBuf { /// However, keep in mind that trimming the capacity may result in a reallocation and copy. /// /// [`into_boxed_path`]: Self::into_boxed_path - #[unstable(feature = "os_string_pathbuf_leak", issue = "125965")] + #[stable(feature = "os_string_pathbuf_leak", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn leak<'a>(self) -> &'a mut Path { Path::from_inner_mut(self.inner.leak()) diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index 781855a2d14..be0dda1d426 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -3,7 +3,6 @@ path_add_extension, path_file_prefix, maybe_uninit_slice, - os_string_pathbuf_leak, normalize_lexically )] -- cgit 1.4.1-3-g733a5 From 24dcfaf71ffe08a0b5acfcc5b5b4d2419e79b847 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 6 Jun 2025 19:39:48 +0000 Subject: Make cast suggestions verbose ``` error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/E0604.rs:2:5 | LL | 1u32 as char; | ^^^^^^^^^^^^ invalid cast | help: try `char::from_u32` instead | LL - 1u32 as char; LL + char::from_u32(1u32); | ``` ``` error[E0620]: cast to unsized type: `&[u8]` as `[char]` --> $DIR/cast-to-slice.rs:6:5 | LL | arr as [char]; | ^^^^^^^^^^^^^ | help: try casting to a reference instead | LL | arr as &[char]; | + ``` ``` error[E0620]: cast to unsized type: `Box<{integer}>` as `dyn Send` --> $DIR/cast-to-unsized-trait-object-suggestion.rs:3:5 | LL | Box::new(1) as dyn Send; | ^^^^^^^^^^^^^^^^^^^^^^^ | help: you can cast to a `Box` instead | LL | Box::new(1) as Box; | ++++ + ``` --- compiler/rustc_hir_typeck/src/cast.rs | 105 ++++++++------------- tests/ui/cast/cast-to-slice.stderr | 18 ++-- .../cast-to-unsized-trait-object-suggestion.stderr | 18 ++-- tests/ui/coercion/issue-73886.stderr | 3 +- tests/ui/coercion/non-primitive-cast-135412.stderr | 6 +- tests/ui/error-codes/E0604.stderr | 11 ++- tests/ui/error-codes/E0620.stderr | 9 +- tests/ui/error-emitter/error-festival.stderr | 11 ++- tests/ui/issues/issue-16048.stderr | 8 +- tests/ui/issues/issue-17441.stderr | 18 ++-- tests/ui/mismatched_types/cast-rfc0401.stderr | 11 ++- tests/ui/nonscalar-cast.stderr | 8 +- tests/ui/tag-variant-cast-non-nullary.stderr | 8 +- 13 files changed, 122 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index e144a6ab599..3884691cbbd 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -380,16 +380,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.span_label(self.span, "invalid cast"); if self.expr_ty.is_numeric() { if self.expr_ty == fcx.tcx.types.u32 { - match fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { - Ok(snippet) => err.span_suggestion( - self.span, - "try `char::from_u32` instead", - format!("char::from_u32({snippet})"), - Applicability::MachineApplicable, - ), - - Err(_) => err.span_help(self.span, "try `char::from_u32` instead"), - }; + err.multipart_suggestion( + "try `char::from_u32` instead", + vec![ + (self.expr_span.shrink_to_lo(), "char::from_u32(".to_string()), + (self.expr_span.shrink_to_hi().to(self.cast_span), ")".to_string()), + ], + Applicability::MachineApplicable, + ); } else if self.expr_ty == fcx.tcx.types.i8 { err.span_help(self.span, "try casting from `u8` instead"); } else { @@ -494,11 +492,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.cast_ty.kind(), ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) ) { - let mut label = true; // Check `impl From for self.cast_ty {}` for accurate suggestion: - if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) - && let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) - { + if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) { let ty = fcx.resolve_vars_if_possible(self.cast_ty); let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); if fcx @@ -506,26 +501,22 @@ impl<'a, 'tcx> CastCheck<'tcx> { .type_implements_trait(from_trait, [ty, expr_ty], fcx.param_env) .must_apply_modulo_regions() { - label = false; - if let ty::Adt(def, args) = self.cast_ty.kind() { - err.span_suggestion_verbose( - self.span, - "consider using the `From` trait instead", - format!( - "{}::from({})", - fcx.tcx.value_path_str_with_args(def.did(), args), - snippet - ), - Applicability::MaybeIncorrect, - ); + let to_ty = if let ty::Adt(def, args) = self.cast_ty.kind() { + fcx.tcx.value_path_str_with_args(def.did(), args) } else { - err.span_suggestion( - self.span, - "consider using the `From` trait instead", - format!("{}::from({})", self.cast_ty, snippet), - Applicability::MaybeIncorrect, - ); + self.cast_ty.to_string() }; + err.multipart_suggestion( + "consider using the `From` trait instead", + vec![ + (self.expr_span.shrink_to_lo(), format!("{to_ty}::from(")), + ( + self.expr_span.shrink_to_hi().to(self.cast_span), + ")".to_string(), + ), + ], + Applicability::MaybeIncorrect, + ); } } @@ -548,11 +539,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ) }; - if label { - err.span_label(self.span, msg); - } else { - err.note(msg); - } + err.span_label(self.span, msg); if let Some(note) = note { err.note(note); @@ -654,38 +641,22 @@ impl<'a, 'tcx> CastCheck<'tcx> { match self.expr_ty.kind() { ty::Ref(_, _, mt) => { let mtstr = mt.prefix_str(); - match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) { - Ok(s) => { - err.span_suggestion( - self.cast_span, - "try casting to a reference instead", - format!("&{mtstr}{s}"), - Applicability::MachineApplicable, - ); - } - Err(_) => { - let msg = format!("did you mean `&{mtstr}{tstr}`?"); - err.span_help(self.cast_span, msg); - } - } + err.span_suggestion_verbose( + self.cast_span.shrink_to_lo(), + "try casting to a reference instead", + format!("&{mtstr}"), + Applicability::MachineApplicable, + ); } ty::Adt(def, ..) if def.is_box() => { - match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) { - Ok(s) => { - err.span_suggestion( - self.cast_span, - "you can cast to a `Box` instead", - format!("Box<{s}>"), - Applicability::MachineApplicable, - ); - } - Err(_) => { - err.span_help( - self.cast_span, - format!("you might have meant `Box<{tstr}>`"), - ); - } - } + err.multipart_suggestion( + "you can cast to a `Box` instead", + vec![ + (self.cast_span.shrink_to_lo(), "Box<".to_string()), + (self.cast_span.shrink_to_hi(), ">".to_string()), + ], + Applicability::MachineApplicable, + ); } _ => { err.span_help(self.expr_span, "consider using a box or reference as appropriate"); diff --git a/tests/ui/cast/cast-to-slice.stderr b/tests/ui/cast/cast-to-slice.stderr index 8f862c00014..1033f77ee0c 100644 --- a/tests/ui/cast/cast-to-slice.stderr +++ b/tests/ui/cast/cast-to-slice.stderr @@ -2,17 +2,23 @@ error[E0620]: cast to unsized type: `&[u8]` as `[char]` --> $DIR/cast-to-slice.rs:2:5 | LL | "example".as_bytes() as [char]; - | ^^^^^^^^^^^^^^^^^^^^^^^^------ - | | - | help: try casting to a reference instead: `&[char]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try casting to a reference instead + | +LL | "example".as_bytes() as &[char]; + | + error[E0620]: cast to unsized type: `&[u8]` as `[char]` --> $DIR/cast-to-slice.rs:6:5 | LL | arr as [char]; - | ^^^^^^^------ - | | - | help: try casting to a reference instead: `&[char]` + | ^^^^^^^^^^^^^ + | +help: try casting to a reference instead + | +LL | arr as &[char]; + | + error: aborting due to 2 previous errors diff --git a/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr b/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr index 3b5b8ea69c1..cc96055abeb 100644 --- a/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr +++ b/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr @@ -2,17 +2,23 @@ error[E0620]: cast to unsized type: `&{integer}` as `dyn Send` --> $DIR/cast-to-unsized-trait-object-suggestion.rs:2:5 | LL | &1 as dyn Send; - | ^^^^^^-------- - | | - | help: try casting to a reference instead: `&dyn Send` + | ^^^^^^^^^^^^^^ + | +help: try casting to a reference instead + | +LL | &1 as &dyn Send; + | + error[E0620]: cast to unsized type: `Box<{integer}>` as `dyn Send` --> $DIR/cast-to-unsized-trait-object-suggestion.rs:3:5 | LL | Box::new(1) as dyn Send; - | ^^^^^^^^^^^^^^^-------- - | | - | help: you can cast to a `Box` instead: `Box` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: you can cast to a `Box` instead + | +LL | Box::new(1) as Box; + | ++++ + error: aborting due to 2 previous errors diff --git a/tests/ui/coercion/issue-73886.stderr b/tests/ui/coercion/issue-73886.stderr index a287aa29e11..891931d0bf8 100644 --- a/tests/ui/coercion/issue-73886.stderr +++ b/tests/ui/coercion/issue-73886.stderr @@ -10,9 +10,8 @@ error[E0605]: non-primitive cast: `u32` as `Option<_>` --> $DIR/issue-73886.rs:4:13 | LL | let _ = 7u32 as Option<_>; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object | - = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object help: consider using the `From` trait instead | LL - let _ = 7u32 as Option<_>; diff --git a/tests/ui/coercion/non-primitive-cast-135412.stderr b/tests/ui/coercion/non-primitive-cast-135412.stderr index 7e5861f83e9..e5e9ee13459 100644 --- a/tests/ui/coercion/non-primitive-cast-135412.stderr +++ b/tests/ui/coercion/non-primitive-cast-135412.stderr @@ -2,9 +2,8 @@ error[E0605]: non-primitive cast: `u32` as `Option<_>` --> $DIR/non-primitive-cast-135412.rs:6:13 | LL | let _ = 7u32 as Option<_>; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object | - = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object help: consider using the `From` trait instead | LL - let _ = 7u32 as Option<_>; @@ -15,9 +14,8 @@ error[E0605]: non-primitive cast: `&'static str` as `Arc` --> $DIR/non-primitive-cast-135412.rs:8:13 | LL | let _ = "String" as Arc; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object | - = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object help: consider using the `From` trait instead | LL - let _ = "String" as Arc; diff --git a/tests/ui/error-codes/E0604.stderr b/tests/ui/error-codes/E0604.stderr index e91f74d6b3f..b949ed973cd 100644 --- a/tests/ui/error-codes/E0604.stderr +++ b/tests/ui/error-codes/E0604.stderr @@ -2,10 +2,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/E0604.rs:2:5 | LL | 1u32 as char; - | ^^^^^^^^^^^^ - | | - | invalid cast - | help: try `char::from_u32` instead: `char::from_u32(1u32)` + | ^^^^^^^^^^^^ invalid cast + | +help: try `char::from_u32` instead + | +LL - 1u32 as char; +LL + char::from_u32(1u32); + | error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0620.stderr b/tests/ui/error-codes/E0620.stderr index 644ba813c96..b2efe02f3aa 100644 --- a/tests/ui/error-codes/E0620.stderr +++ b/tests/ui/error-codes/E0620.stderr @@ -2,9 +2,12 @@ error[E0620]: cast to unsized type: `&[usize; 2]` as `[usize]` --> $DIR/E0620.rs:2:16 | LL | let _foo = &[1_usize, 2] as [usize]; - | ^^^^^^^^^^^^^^^^^------- - | | - | help: try casting to a reference instead: `&[usize]` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try casting to a reference instead + | +LL | let _foo = &[1_usize, 2] as &[usize]; + | + error: aborting due to 1 previous error diff --git a/tests/ui/error-emitter/error-festival.stderr b/tests/ui/error-emitter/error-festival.stderr index be484bc8094..d2afae69c07 100644 --- a/tests/ui/error-emitter/error-festival.stderr +++ b/tests/ui/error-emitter/error-festival.stderr @@ -58,10 +58,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/error-festival.rs:27:5 | LL | 0u32 as char; - | ^^^^^^^^^^^^ - | | - | invalid cast - | help: try `char::from_u32` instead: `char::from_u32(0u32)` + | ^^^^^^^^^^^^ invalid cast + | +help: try `char::from_u32` instead + | +LL - 0u32 as char; +LL + char::from_u32(0u32); + | error[E0605]: non-primitive cast: `u8` as `Vec` --> $DIR/error-festival.rs:31:5 diff --git a/tests/ui/issues/issue-16048.stderr b/tests/ui/issues/issue-16048.stderr index 73610942d7a..f97f13152bc 100644 --- a/tests/ui/issues/issue-16048.stderr +++ b/tests/ui/issues/issue-16048.stderr @@ -11,9 +11,13 @@ error[E0605]: non-primitive cast: `Foo<'a>` as `T` --> $DIR/issue-16048.rs:24:16 | LL | return *self as T; - | ^^^^^^^^^^ help: consider using the `From` trait instead: `T::from(*self)` + | ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + | +help: consider using the `From` trait instead + | +LL - return *self as T; +LL + return T::from(*self); | - = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-17441.stderr b/tests/ui/issues/issue-17441.stderr index 29e50b91c7c..c96b13d62dc 100644 --- a/tests/ui/issues/issue-17441.stderr +++ b/tests/ui/issues/issue-17441.stderr @@ -2,17 +2,23 @@ error[E0620]: cast to unsized type: `&[usize; 2]` as `[usize]` --> $DIR/issue-17441.rs:2:16 | LL | let _foo = &[1_usize, 2] as [usize]; - | ^^^^^^^^^^^^^^^^^------- - | | - | help: try casting to a reference instead: `&[usize]` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try casting to a reference instead + | +LL | let _foo = &[1_usize, 2] as &[usize]; + | + error[E0620]: cast to unsized type: `Box` as `dyn Debug` --> $DIR/issue-17441.rs:5:16 | LL | let _bar = Box::new(1_usize) as dyn std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^^------------------- - | | - | help: you can cast to a `Box` instead: `Box` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: you can cast to a `Box` instead + | +LL | let _bar = Box::new(1_usize) as Box; + | ++++ + error[E0620]: cast to unsized type: `usize` as `dyn Debug` --> $DIR/issue-17441.rs:8:16 diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr index a4276395944..eb95d659840 100644 --- a/tests/ui/mismatched_types/cast-rfc0401.stderr +++ b/tests/ui/mismatched_types/cast-rfc0401.stderr @@ -104,10 +104,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/cast-rfc0401.rs:41:13 | LL | let _ = 0x61u32 as char; - | ^^^^^^^^^^^^^^^ - | | - | invalid cast - | help: try `char::from_u32` instead: `char::from_u32(0x61u32)` + | ^^^^^^^^^^^^^^^ invalid cast + | +help: try `char::from_u32` instead + | +LL - let _ = 0x61u32 as char; +LL + let _ = char::from_u32(0x61u32); + | error[E0606]: casting `bool` as `f32` is invalid --> $DIR/cast-rfc0401.rs:43:13 diff --git a/tests/ui/nonscalar-cast.stderr b/tests/ui/nonscalar-cast.stderr index 01b4a9a7ce0..834d4ea241c 100644 --- a/tests/ui/nonscalar-cast.stderr +++ b/tests/ui/nonscalar-cast.stderr @@ -2,9 +2,13 @@ error[E0605]: non-primitive cast: `Foo` as `isize` --> $DIR/nonscalar-cast.rs:15:20 | LL | println!("{}", Foo { x: 1 } as isize); - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(Foo { x: 1 })` + | ^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + | +help: consider using the `From` trait instead + | +LL - println!("{}", Foo { x: 1 } as isize); +LL + println!("{}", isize::from(Foo { x: 1 })); | - = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to 1 previous error diff --git a/tests/ui/tag-variant-cast-non-nullary.stderr b/tests/ui/tag-variant-cast-non-nullary.stderr index 2e1dde27d0f..8ec1c5f11ec 100644 --- a/tests/ui/tag-variant-cast-non-nullary.stderr +++ b/tests/ui/tag-variant-cast-non-nullary.stderr @@ -2,10 +2,14 @@ error[E0605]: non-primitive cast: `NonNullary` as `isize` --> $DIR/tag-variant-cast-non-nullary.rs:19:15 | LL | let val = v as isize; - | ^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(v)` + | ^^^^^^^^^^ an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less | - = note: an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less = note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information +help: consider using the `From` trait instead + | +LL - let val = v as isize; +LL + let val = isize::from(v); + | error: aborting due to 1 previous error -- cgit 1.4.1-3-g733a5 From ac980cace8038f3fa3be1953092e92bede52a5bb Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Wed, 4 Jun 2025 21:39:29 +0000 Subject: Make obligation cause code suggestions verbose ``` error[E0277]: `()` is not a future --> $DIR/unnecessary-await.rs:28:10 | LL | e!().await; | ^^^^^ `()` is not a future | = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` help: remove the `.await` | LL - e!().await; LL + e!(); | ``` ``` error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/const-fn-in-vec.rs:1:47 | LL | static _MAYBE_STRINGS: [Option; 5] = [None; 5]; | ^^^^ the trait `Copy` is not implemented for `String` | = note: required for `Option` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array help: create an inline `const` block | LL | static _MAYBE_STRINGS: [Option; 5] = [const { None }; 5]; | +++++++ + ``` --- .../src/error_reporting/traits/suggestions.rs | 20 ++++++++-------- ...debug-ice-attempted-to-add-with-overflow.stderr | 10 ++++---- .../async-await/drop-track-bad-field-in-fru.stderr | 10 ++++---- tests/ui/async-await/issue-101715.stderr | 9 ++++---- tests/ui/async-await/unnecessary-await.stderr | 20 +++++++++------- .../const-blocks/fn-call-in-non-const.stderr | 5 ++-- tests/ui/consts/const-blocks/trait-error.stderr | 9 ++++---- tests/ui/consts/const-fn-in-vec.stderr | 27 ++++++++++++---------- tests/ui/coroutine/unresolved-ct-var.stderr | 11 +++++---- .../copy-check-when-count-inferred-later.stderr | 9 ++++---- .../constrain_in_projection2.next.stderr | 7 +++++- 11 files changed, 80 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index c4f1f7d712a..aa113f3835b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1411,7 +1411,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - err.span_suggestion( + err.span_suggestion_verbose( obligation.cause.span.shrink_to_lo(), format!( "consider borrowing the value, since `&{self_ty}` can be coerced into `{target_ty}`" @@ -1574,7 +1574,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .span_extend_while_whitespace(expr_span) .shrink_to_hi() .to(await_expr.span.shrink_to_hi()); - err.span_suggestion( + err.span_suggestion_verbose( removal_span, "remove the `.await`", "", @@ -2126,7 +2126,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { )); if !assoc_item.is_impl_trait_in_trait() { - err.span_suggestion( + err.span_suggestion_verbose( span, "use the fully qualified path to an implementation", format!( @@ -2924,12 +2924,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); let sm = tcx.sess.source_map(); if matches!(is_constable, IsConstable::Fn | IsConstable::Ctor) - && let Ok(snip) = sm.span_to_snippet(elt_span) + && let Ok(_) = sm.span_to_snippet(elt_span) { - err.span_suggestion( - elt_span, + err.multipart_suggestion( "create an inline `const` block", - format!("const {{ {snip} }}"), + vec![ + (elt_span.shrink_to_lo(), "const { ".to_string()), + (elt_span.shrink_to_hi(), " }".to_string()), + ], Applicability::MachineApplicable, ); } else { @@ -3127,13 +3129,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } err.help("change the field's type to have a statically known size"); - err.span_suggestion( + err.span_suggestion_verbose( span.shrink_to_lo(), "borrowed types always have a statically known size", "&", Applicability::MachineApplicable, ); - err.multipart_suggestion( + err.multipart_suggestion_verbose( "the `Box` type always has a statically known size and allocates its contents \ in the heap", vec![ diff --git a/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr b/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr index 8c9d06c79ca..40d44db205f 100644 --- a/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr +++ b/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr @@ -2,14 +2,16 @@ error[E0277]: `[usize; usize::MAX]` is not a future --> $DIR/debug-ice-attempted-to-add-with-overflow.rs:8:37 | LL | [0usize; 0xffff_ffff_ffff_ffff].await; - | -^^^^^ - | || - | |`[usize; usize::MAX]` is not a future - | help: remove the `.await` + | ^^^^^ `[usize; usize::MAX]` is not a future | = help: the trait `Future` is not implemented for `[usize; usize::MAX]` = note: [usize; usize::MAX] must be a future or must implement `IntoFuture` to be awaited = note: required for `[usize; usize::MAX]` to implement `IntoFuture` +help: remove the `.await` + | +LL - [0usize; 0xffff_ffff_ffff_ffff].await; +LL + [0usize; 0xffff_ffff_ffff_ffff]; + | error[E0752]: `main` function is not allowed to be `async` --> $DIR/debug-ice-attempted-to-add-with-overflow.rs:6:1 diff --git a/tests/ui/async-await/drop-track-bad-field-in-fru.stderr b/tests/ui/async-await/drop-track-bad-field-in-fru.stderr index 721e0106293..644a7c7717c 100644 --- a/tests/ui/async-await/drop-track-bad-field-in-fru.stderr +++ b/tests/ui/async-await/drop-track-bad-field-in-fru.stderr @@ -10,14 +10,16 @@ error[E0277]: `Option<_>` is not a future --> $DIR/drop-track-bad-field-in-fru.rs:6:46 | LL | None { value: (), ..Default::default() }.await; - | -^^^^^ - | || - | |`Option<_>` is not a future - | help: remove the `.await` + | ^^^^^ `Option<_>` is not a future | = help: the trait `Future` is not implemented for `Option<_>` = note: Option<_> must be a future or must implement `IntoFuture` to be awaited = note: required for `Option<_>` to implement `IntoFuture` +help: remove the `.await` + | +LL - None { value: (), ..Default::default() }.await; +LL + None { value: (), ..Default::default() }; + | error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/issue-101715.stderr b/tests/ui/async-await/issue-101715.stderr index f6af15c00d6..87302dce130 100644 --- a/tests/ui/async-await/issue-101715.stderr +++ b/tests/ui/async-await/issue-101715.stderr @@ -2,14 +2,15 @@ error[E0277]: `()` is not a future --> $DIR/issue-101715.rs:11:10 | LL | .await - | -^^^^^ - | || - | |`()` is not a future - | help: remove the `.await` + | ^^^^^ `()` is not a future | = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` +help: remove the `.await` + | +LL - .await + | error: aborting due to 1 previous error diff --git a/tests/ui/async-await/unnecessary-await.stderr b/tests/ui/async-await/unnecessary-await.stderr index 620370a6113..f60b4ecb990 100644 --- a/tests/ui/async-await/unnecessary-await.stderr +++ b/tests/ui/async-await/unnecessary-await.stderr @@ -23,14 +23,16 @@ error[E0277]: `()` is not a future --> $DIR/unnecessary-await.rs:28:10 | LL | e!().await; - | -^^^^^ - | || - | |`()` is not a future - | help: remove the `.await` + | ^^^^^ `()` is not a future | = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` +help: remove the `.await` + | +LL - e!().await; +LL + e!(); + | error[E0277]: `()` is not a future --> $DIR/unnecessary-await.rs:22:15 @@ -53,14 +55,16 @@ error[E0277]: `()` is not a future --> $DIR/unnecessary-await.rs:36:20 | LL | for x in [] {}.await - | -^^^^^ - | || - | |`()` is not a future - | help: remove the `.await` + | ^^^^^ `()` is not a future | = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` +help: remove the `.await` + | +LL - for x in [] {}.await +LL + for x in [] {} + | error: aborting due to 4 previous errors diff --git a/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr b/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr index a3d5054ced3..54982391b66 100644 --- a/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr +++ b/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr @@ -13,9 +13,8 @@ LL | struct Bar; | help: create an inline `const` block | -LL - let _: [Option; 2] = [no_copy(); 2]; -LL + let _: [Option; 2] = [const { no_copy() }; 2]; - | +LL | let _: [Option; 2] = [const { no_copy() }; 2]; + | +++++++ + error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-blocks/trait-error.stderr b/tests/ui/consts/const-blocks/trait-error.stderr index 58ddc047d03..601d067e3d8 100644 --- a/tests/ui/consts/const-blocks/trait-error.stderr +++ b/tests/ui/consts/const-blocks/trait-error.stderr @@ -2,10 +2,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/trait-error.rs:5:6 | LL | [Foo(String::new()); 4]; - | ^^^^^^^^^^^^^^^^^^ - | | - | the trait `Copy` is not implemented for `String` - | help: create an inline `const` block: `const { Foo(String::new()) }` + | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | note: required for `Foo` to implement `Copy` --> $DIR/trait-error.rs:1:10 @@ -13,6 +10,10 @@ note: required for `Foo` to implement `Copy` LL | #[derive(Copy, Clone)] | ^^^^ unsatisfied trait bound introduced in this `derive` macro = note: the `Copy` trait is required because this value will be copied for each element of the array +help: create an inline `const` block + | +LL | [const { Foo(String::new()) }; 4]; + | +++++++ + error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-fn-in-vec.stderr b/tests/ui/consts/const-fn-in-vec.stderr index 5be26d7c121..890eb8040b9 100644 --- a/tests/ui/consts/const-fn-in-vec.stderr +++ b/tests/ui/consts/const-fn-in-vec.stderr @@ -2,36 +2,39 @@ error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/const-fn-in-vec.rs:1:47 | LL | static _MAYBE_STRINGS: [Option; 5] = [None; 5]; - | ^^^^ - | | - | the trait `Copy` is not implemented for `String` - | help: create an inline `const` block: `const { None }` + | ^^^^ the trait `Copy` is not implemented for `String` | = note: required for `Option` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array +help: create an inline `const` block + | +LL | static _MAYBE_STRINGS: [Option; 5] = [const { None }; 5]; + | +++++++ + error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/const-fn-in-vec.rs:7:34 | LL | let _strings: [String; 5] = [String::new(); 5]; - | ^^^^^^^^^^^^^ - | | - | the trait `Copy` is not implemented for `String` - | help: create an inline `const` block: `const { String::new() }` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | = note: the `Copy` trait is required because this value will be copied for each element of the array +help: create an inline `const` block + | +LL | let _strings: [String; 5] = [const { String::new() }; 5]; + | +++++++ + error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/const-fn-in-vec.rs:12:48 | LL | let _maybe_strings: [Option; 5] = [None; 5]; - | ^^^^ - | | - | the trait `Copy` is not implemented for `String` - | help: create an inline `const` block: `const { None }` + | ^^^^ the trait `Copy` is not implemented for `String` | = note: required for `Option` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array +help: create an inline `const` block + | +LL | let _maybe_strings: [Option; 5] = [const { None }; 5]; + | +++++++ + error: aborting due to 3 previous errors diff --git a/tests/ui/coroutine/unresolved-ct-var.stderr b/tests/ui/coroutine/unresolved-ct-var.stderr index da2ec272f9f..86b73e4b062 100644 --- a/tests/ui/coroutine/unresolved-ct-var.stderr +++ b/tests/ui/coroutine/unresolved-ct-var.stderr @@ -2,15 +2,18 @@ error[E0277]: `[(); _]` is not a future --> $DIR/unresolved-ct-var.rs:6:45 | LL | let s = std::array::from_fn(|_| ()).await; - | ----------------------------^^^^^ - | | || - | | |`[(); _]` is not a future - | | help: remove the `.await` + | --------------------------- ^^^^^ `[(); _]` is not a future + | | | this call returns `[(); _]` | = help: the trait `Future` is not implemented for `[(); _]` = note: [(); _] must be a future or must implement `IntoFuture` to be awaited = note: required for `[(); _]` to implement `IntoFuture` +help: remove the `.await` + | +LL - let s = std::array::from_fn(|_| ()).await; +LL + let s = std::array::from_fn(|_| ()); + | error: aborting due to 1 previous error diff --git a/tests/ui/repeat-expr/copy-check-when-count-inferred-later.stderr b/tests/ui/repeat-expr/copy-check-when-count-inferred-later.stderr index d974f5add50..1c862f2b606 100644 --- a/tests/ui/repeat-expr/copy-check-when-count-inferred-later.stderr +++ b/tests/ui/repeat-expr/copy-check-when-count-inferred-later.stderr @@ -2,12 +2,13 @@ error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/copy-check-when-count-inferred-later.rs:8:14 | LL | let a = [String::new(); _]; - | ^^^^^^^^^^^^^ - | | - | the trait `Copy` is not implemented for `String` - | help: create an inline `const` block: `const { String::new() }` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | = note: the `Copy` trait is required because this value will be copied for each element of the array +help: create an inline `const` block + | +LL | let a = [const { String::new() }; _]; + | +++++++ + error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr b/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr index 7c09ab6a91a..72a253c4be8 100644 --- a/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr +++ b/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr @@ -2,7 +2,7 @@ error[E0283]: type annotations needed: cannot satisfy `Foo: Trait` --> $DIR/constrain_in_projection2.rs:28:14 | LL | let x = >::Assoc::default(); - | ^^^ help: use the fully qualified path to an implementation: `::Assoc` + | ^^^ | note: multiple `impl`s satisfying `Foo: Trait` found --> $DIR/constrain_in_projection2.rs:18:1 @@ -13,6 +13,11 @@ LL | impl Trait<()> for Foo { LL | impl Trait for Foo { | ^^^^^^^^^^^^^^^^^^^^^^^ = note: associated types cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl` +help: use the fully qualified path to an implementation + | +LL - let x = >::Assoc::default(); +LL + let x = <::Assoc as Trait>::Assoc::default(); + | error: aborting due to 1 previous error -- cgit 1.4.1-3-g733a5 From 910a59dfae6c60bae36a1c0eb478f46c624512ba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 May 2025 22:48:50 +0200 Subject: unsafe keyword docs: emphasize that an unsafe fn in a trait does not get to choose its safety contract --- library/std/src/keyword_docs.rs | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 79b25040ef6..1c55824ab90 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1916,10 +1916,6 @@ mod type_keyword {} /// - and to declare that a programmer has checked that these contracts have been upheld (`unsafe /// {}` and `unsafe impl`, but also `unsafe fn` -- see below). /// -/// They are not mutually exclusive, as can be seen in `unsafe fn`: the body of an `unsafe fn` is, -/// by default, treated like an unsafe block. The `unsafe_op_in_unsafe_fn` lint can be enabled to -/// change that. -/// /// # Unsafe abilities /// /// **No matter what, Safe Rust can't cause Undefined Behavior**. This is @@ -1961,13 +1957,6 @@ mod type_keyword {} /// - `unsafe impl`: the contract necessary to implement the trait has been /// checked by the programmer and is guaranteed to be respected. /// -/// By default, `unsafe fn` also acts like an `unsafe {}` block -/// around the code inside the function. This means it is not just a signal to -/// the caller, but also promises that the preconditions for the operations -/// inside the function are upheld. Mixing these two meanings can be confusing, so the -/// `unsafe_op_in_unsafe_fn` lint can be enabled to warn against that and require explicit unsafe -/// blocks even inside `unsafe fn`. -/// /// See the [Rustonomicon] and the [Reference] for more information. /// /// # Examples @@ -2109,6 +2098,7 @@ mod type_keyword {} /// impl Indexable for i32 { /// const LEN: usize = 1; /// +/// /// See `Indexable` for the safety contract. /// unsafe fn idx_unchecked(&self, idx: usize) -> i32 { /// debug_assert_eq!(idx, 0); /// *self @@ -2120,6 +2110,7 @@ mod type_keyword {} /// impl Indexable for [i32; 42] { /// const LEN: usize = 42; /// +/// /// See `Indexable` for the safety contract. /// unsafe fn idx_unchecked(&self, idx: usize) -> i32 { /// // SAFETY: As per this trait's documentation, the caller ensures /// // that `idx < 42`. @@ -2132,6 +2123,7 @@ mod type_keyword {} /// impl Indexable for ! { /// const LEN: usize = 0; /// +/// /// See `Indexable` for the safety contract. /// unsafe fn idx_unchecked(&self, idx: usize) -> i32 { /// // SAFETY: As per this trait's documentation, the caller ensures /// // that `idx < 0`, which is impossible, so this is dead code. @@ -2153,11 +2145,14 @@ mod type_keyword {} /// contract of `idx_unchecked`. Implementing `Indexable` is safe because when writing /// `idx_unchecked`, we don't have to worry: our *callers* need to discharge a proof obligation /// (like `use_indexable` does), but the *implementation* of `get_unchecked` has no proof obligation -/// to contend with. Of course, the implementation of `Indexable` may choose to call other unsafe -/// operations, and then it needs an `unsafe` *block* to indicate it discharged the proof -/// obligations of its callees. (We enabled `unsafe_op_in_unsafe_fn`, so the body of `idx_unchecked` -/// is not implicitly an unsafe block.) For that purpose it can make use of the contract that all -/// its callers must uphold -- the fact that `idx < LEN`. +/// to contend with. Of course, the implementation may choose to call other unsafe operations, and +/// then it needs an `unsafe` *block* to indicate it discharged the proof obligations of its +/// callees. For that purpose it can make use of the contract that all its callers must uphold -- +/// the fact that `idx < LEN`. +/// +/// Note that unlike normal `unsafe fn`, an `unsafe fn` in a trait implementation does not get to +/// just pick an arbitrary safety contract! It *has* to use the safety contract defined by the trait +/// (or one with weaker preconditions). /// /// Formally speaking, an `unsafe fn` in a trait is a function with *preconditions* that go beyond /// those encoded by the argument types (such as `idx < LEN`), whereas an `unsafe trait` can declare -- cgit 1.4.1-3-g733a5 From 3c049e21ca75134b7cab84507c93c18ce38ff275 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 6 Jun 2025 20:52:34 +0000 Subject: reword suggestion message --- compiler/rustc_hir_typeck/src/cast.rs | 11 +++++++---- tests/ui/cast/cast-to-slice.stderr | 4 ++-- tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr | 2 +- tests/ui/consts/const-eval/const-eval-overflow-4b.stderr | 2 +- tests/ui/error-codes/E0604.stderr | 2 +- tests/ui/error-codes/E0620.stderr | 2 +- tests/ui/error-emitter/error-festival.stderr | 2 +- tests/ui/issues/issue-17441.stderr | 2 +- tests/ui/mismatched_types/cast-rfc0401.stderr | 2 +- 9 files changed, 16 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 3884691cbbd..e17cfc15a43 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -381,7 +381,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { if self.expr_ty.is_numeric() { if self.expr_ty == fcx.tcx.types.u32 { err.multipart_suggestion( - "try `char::from_u32` instead", + "consider using `char::from_u32` instead", vec![ (self.expr_span.shrink_to_lo(), "char::from_u32(".to_string()), (self.expr_span.shrink_to_hi().to(self.cast_span), ")".to_string()), @@ -389,9 +389,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { Applicability::MachineApplicable, ); } else if self.expr_ty == fcx.tcx.types.i8 { - err.span_help(self.span, "try casting from `u8` instead"); + err.span_help(self.span, "consider casting from `u8` instead"); } else { - err.span_help(self.span, "try `char::from_u32` instead (via a `u32`)"); + err.span_help( + self.span, + "consider using `char::from_u32` instead (via a `u32`)", + ); }; } err.emit(); @@ -643,7 +646,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { let mtstr = mt.prefix_str(); err.span_suggestion_verbose( self.cast_span.shrink_to_lo(), - "try casting to a reference instead", + "consider casting to a reference instead", format!("&{mtstr}"), Applicability::MachineApplicable, ); diff --git a/tests/ui/cast/cast-to-slice.stderr b/tests/ui/cast/cast-to-slice.stderr index 1033f77ee0c..382ccc3d10c 100644 --- a/tests/ui/cast/cast-to-slice.stderr +++ b/tests/ui/cast/cast-to-slice.stderr @@ -4,7 +4,7 @@ error[E0620]: cast to unsized type: `&[u8]` as `[char]` LL | "example".as_bytes() as [char]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: try casting to a reference instead +help: consider casting to a reference instead | LL | "example".as_bytes() as &[char]; | + @@ -15,7 +15,7 @@ error[E0620]: cast to unsized type: `&[u8]` as `[char]` LL | arr as [char]; | ^^^^^^^^^^^^^ | -help: try casting to a reference instead +help: consider casting to a reference instead | LL | arr as &[char]; | + diff --git a/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr b/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr index cc96055abeb..2803c3380d7 100644 --- a/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr +++ b/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr @@ -4,7 +4,7 @@ error[E0620]: cast to unsized type: `&{integer}` as `dyn Send` LL | &1 as dyn Send; | ^^^^^^^^^^^^^^ | -help: try casting to a reference instead +help: consider casting to a reference instead | LL | &1 as &dyn Send; | + diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr index 1a0832b8ba0..b996370ea3d 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -23,7 +23,7 @@ error[E0604]: only `u8` can be cast as `char`, not `i8` LL | : [u32; 5i8 as char as usize] | ^^^^^^^^^^^ invalid cast | -help: try casting from `u8` instead +help: consider casting from `u8` instead --> $DIR/const-eval-overflow-4b.rs:24:13 | LL | : [u32; 5i8 as char as usize] diff --git a/tests/ui/error-codes/E0604.stderr b/tests/ui/error-codes/E0604.stderr index b949ed973cd..67bbb25958f 100644 --- a/tests/ui/error-codes/E0604.stderr +++ b/tests/ui/error-codes/E0604.stderr @@ -4,7 +4,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` LL | 1u32 as char; | ^^^^^^^^^^^^ invalid cast | -help: try `char::from_u32` instead +help: consider using `char::from_u32` instead | LL - 1u32 as char; LL + char::from_u32(1u32); diff --git a/tests/ui/error-codes/E0620.stderr b/tests/ui/error-codes/E0620.stderr index b2efe02f3aa..696407c6f7e 100644 --- a/tests/ui/error-codes/E0620.stderr +++ b/tests/ui/error-codes/E0620.stderr @@ -4,7 +4,7 @@ error[E0620]: cast to unsized type: `&[usize; 2]` as `[usize]` LL | let _foo = &[1_usize, 2] as [usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^ | -help: try casting to a reference instead +help: consider casting to a reference instead | LL | let _foo = &[1_usize, 2] as &[usize]; | + diff --git a/tests/ui/error-emitter/error-festival.stderr b/tests/ui/error-emitter/error-festival.stderr index d2afae69c07..6c661eb17a8 100644 --- a/tests/ui/error-emitter/error-festival.stderr +++ b/tests/ui/error-emitter/error-festival.stderr @@ -60,7 +60,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` LL | 0u32 as char; | ^^^^^^^^^^^^ invalid cast | -help: try `char::from_u32` instead +help: consider using `char::from_u32` instead | LL - 0u32 as char; LL + char::from_u32(0u32); diff --git a/tests/ui/issues/issue-17441.stderr b/tests/ui/issues/issue-17441.stderr index c96b13d62dc..96aad879e24 100644 --- a/tests/ui/issues/issue-17441.stderr +++ b/tests/ui/issues/issue-17441.stderr @@ -4,7 +4,7 @@ error[E0620]: cast to unsized type: `&[usize; 2]` as `[usize]` LL | let _foo = &[1_usize, 2] as [usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^ | -help: try casting to a reference instead +help: consider casting to a reference instead | LL | let _foo = &[1_usize, 2] as &[usize]; | + diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr index eb95d659840..a188b7791fd 100644 --- a/tests/ui/mismatched_types/cast-rfc0401.stderr +++ b/tests/ui/mismatched_types/cast-rfc0401.stderr @@ -106,7 +106,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` LL | let _ = 0x61u32 as char; | ^^^^^^^^^^^^^^^ invalid cast | -help: try `char::from_u32` instead +help: consider using `char::from_u32` instead | LL - let _ = 0x61u32 as char; LL + let _ = char::from_u32(0x61u32); -- cgit 1.4.1-3-g733a5 From aa1b296dd6ff158a8fac8e33fb575b24d960ede9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 6 Jun 2025 18:05:29 +0000 Subject: Unify normalization of terms in deeply normalize --- compiler/rustc_infer/src/infer/mod.rs | 7 ++ .../src/solve/inspect/analyse.rs | 5 +- .../rustc_trait_selection/src/solve/normalize.rs | 84 ++++++---------------- .../src/traits/structural_normalize.rs | 5 +- 4 files changed, 30 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 96e03e3bea5..e9b58eb959b 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -823,6 +823,13 @@ impl<'tcx> InferCtxt<'tcx> { ty::Region::new_var(self.tcx, region_var) } + pub fn next_term_var_of_kind(&self, term: ty::Term<'tcx>, span: Span) -> ty::Term<'tcx> { + match term.kind() { + ty::TermKind::Ty(_) => self.next_ty_var(span).into(), + ty::TermKind::Const(_) => self.next_const_var(span).into(), + } + } + /// Return the universe that the region `r` was created in. For /// most regions (e.g., `'static`, named regions from the user, /// etc) this is the root universe U0. For inference variables or diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 1193a9059ca..de1bd724052 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -206,10 +206,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { let infcx = self.goal.infcx; match goal.predicate.kind().no_bound_vars() { Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => { - let unconstrained_term = match term.kind() { - ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(), - ty::TermKind::Const(_) => infcx.next_const_var(span).into(), - }; + let unconstrained_term = infcx.next_term_var_of_kind(term, span); let goal = goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term }); // We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index a8d32221204..8f44c26b70d 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -1,4 +1,3 @@ -use std::assert_matches::assert_matches; use std::fmt::Debug; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -96,66 +95,18 @@ impl<'tcx, E> NormalizationFolder<'_, 'tcx, E> where E: FromSolverError<'tcx, NextSolverError<'tcx>>, { - fn normalize_alias_ty(&mut self, alias_ty: Ty<'tcx>) -> Result, Vec> { - assert_matches!(alias_ty.kind(), ty::Alias(..)); - - let infcx = self.at.infcx; - let tcx = infcx.tcx; - let recursion_limit = tcx.recursion_limit(); - if !recursion_limit.value_within_limit(self.depth) { - let ty::Alias(_, data) = *alias_ty.kind() else { - unreachable!(); - }; - - self.at.infcx.err_ctxt().report_overflow_error( - OverflowCause::DeeplyNormalize(data.into()), - self.at.cause.span, - true, - |_| {}, - ); - } - - self.depth += 1; - - let new_infer_ty = infcx.next_ty_var(self.at.cause.span); - let obligation = Obligation::new( - tcx, - self.at.cause.clone(), - self.at.param_env, - ty::PredicateKind::AliasRelate( - alias_ty.into(), - new_infer_ty.into(), - ty::AliasRelationDirection::Equate, - ), - ); - - self.fulfill_cx.register_predicate_obligation(infcx, obligation); - self.select_all_and_stall_coroutine_predicates()?; - - // Alias is guaranteed to be fully structurally resolved, - // so we can super fold here. - let ty = infcx.resolve_vars_if_possible(new_infer_ty); - let result = ty.try_super_fold_with(self)?; - self.depth -= 1; - Ok(result) - } - - fn normalize_unevaluated_const( + fn normalize_alias_term( &mut self, - alias_ct: ty::Const<'tcx>, - ) -> Result, Vec> { - assert_matches!(alias_ct.kind(), ty::ConstKind::Unevaluated(..)); - + alias_term: ty::Term<'tcx>, + ) -> Result, Vec> { let infcx = self.at.infcx; let tcx = infcx.tcx; let recursion_limit = tcx.recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { - let ty::ConstKind::Unevaluated(uv) = alias_ct.kind() else { - unreachable!(); - }; + let term = alias_term.to_alias_term().unwrap(); self.at.infcx.err_ctxt().report_overflow_error( - OverflowCause::DeeplyNormalize(uv.into()), + OverflowCause::DeeplyNormalize(term), self.at.cause.span, true, |_| {}, @@ -164,14 +115,14 @@ where self.depth += 1; - let new_infer_ct = infcx.next_const_var(self.at.cause.span); + let infer_term = infcx.next_term_var_of_kind(alias_term, self.at.cause.span); let obligation = Obligation::new( tcx, self.at.cause.clone(), self.at.param_env, ty::PredicateKind::AliasRelate( - alias_ct.into(), - new_infer_ct.into(), + alias_term.into(), + infer_term.into(), ty::AliasRelationDirection::Equate, ), ); @@ -181,8 +132,13 @@ where // Alias is guaranteed to be fully structurally resolved, // so we can super fold here. - let ct = infcx.resolve_vars_if_possible(new_infer_ct); - let result = ct.try_super_fold_with(self)?; + let term = infcx.resolve_vars_if_possible(infer_term); + // super-folding the `term` will directly fold the `Ty` or `Const` so + // we have to match on the term and super-fold them manually. + let result = match term.kind() { + ty::TermKind::Ty(ty) => ty.try_super_fold_with(self)?.into(), + ty::TermKind::Const(ct) => ct.try_super_fold_with(self)?.into(), + }; self.depth -= 1; Ok(result) } @@ -242,7 +198,8 @@ where if ty.has_escaping_bound_vars() { let (ty, mapped_regions, mapped_types, mapped_consts) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ty); - let result = ensure_sufficient_stack(|| self.normalize_alias_ty(ty))?; + let result = + ensure_sufficient_stack(|| self.normalize_alias_term(ty.into()))?.expect_type(); Ok(PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, @@ -252,7 +209,7 @@ where result, )) } else { - ensure_sufficient_stack(|| self.normalize_alias_ty(ty)) + Ok(ensure_sufficient_stack(|| self.normalize_alias_term(ty.into()))?.expect_type()) } } @@ -269,7 +226,8 @@ where if ct.has_escaping_bound_vars() { let (ct, mapped_regions, mapped_types, mapped_consts) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ct); - let result = ensure_sufficient_stack(|| self.normalize_unevaluated_const(ct))?; + let result = + ensure_sufficient_stack(|| self.normalize_alias_term(ct.into()))?.expect_const(); Ok(PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, @@ -279,7 +237,7 @@ where result, )) } else { - ensure_sufficient_stack(|| self.normalize_unevaluated_const(ct)) + Ok(ensure_sufficient_stack(|| self.normalize_alias_term(ct.into()))?.expect_const()) } } } diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index 3f741345404..2e20ede2f50 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -39,10 +39,7 @@ impl<'tcx> At<'_, 'tcx> { return Ok(term); } - let new_infer = match term.kind() { - ty::TermKind::Ty(_) => self.infcx.next_ty_var(self.cause.span).into(), - ty::TermKind::Const(_) => self.infcx.next_const_var(self.cause.span).into(), - }; + let new_infer = self.infcx.next_term_var_of_kind(term, self.cause.span); // We simply emit an `alias-eq` goal here, since that will take care of // normalizing the LHS of the projection until it is a rigid projection -- cgit 1.4.1-3-g733a5 From 8aafcc8021fe2ff3a4c986a8f388120589221e9a Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 6 Jun 2025 21:35:52 -0700 Subject: compiler: Sort and doc ExternAbi variants --- compiler/rustc_abi/src/extern_abi.rs | 95 +++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index c48920e5f1b..75bfcff4462 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -14,64 +14,93 @@ mod tests; use ExternAbi as Abi; +/// ABI we expect to see within `extern "{abi}"` #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "nightly", derive(Encodable, Decodable))] pub enum ExternAbi { - // Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the - // hashing tests. These are used in many places, so giving them stable values reduces test - // churn. The specific values are meaningless. - Rust, + /* universal */ + /// presumed C ABI for the platform C { unwind: bool, }, - Cdecl { + /// ABI of the "system" interface, e.g. the Win32 API, always "aliasing" + System { unwind: bool, }, - Stdcall { + + /// that's us! + Rust, + /// the mostly-unused `unboxed_closures` ABI, effectively now an impl detail unless someone + /// puts in the work to make it viable again... but would we need a special ABI? + RustCall, + /// For things unlikely to be called, where reducing register pressure in + /// `extern "Rust"` callers is worth paying extra cost in the callee. + /// Stronger than just `#[cold]` because `fn` pointers might be incompatible. + RustCold, + + /// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM. + /// Even normally-compatible Rust types can become ABI-incompatible with this ABI! + Unadjusted, + + /// UEFI ABI, usually an alias of C, but sometimes an arch-specific alias + /// and only valid on platforms that have a UEFI standard + EfiApi, + + /* arm */ + /// Arm Architecture Procedure Call Standard, sometimes `ExternAbi::C` is an alias for this + Aapcs { unwind: bool, }, - Fastcall { + /// extremely constrained barely-C ABI for TrustZone + CCmseNonSecureCall, + /// extremely constrained barely-C ABI for TrustZone + CCmseNonSecureEntry, + + /* gpu */ + /// An entry-point function called by the GPU's host + // FIXME: should not be callable from Rust on GPU targets, is for host's use only + GpuKernel, + /// An entry-point function called by the GPU's host + // FIXME: why do we have two of these? + PtxKernel, + + /* interrupt */ + AvrInterrupt, + AvrNonBlockingInterrupt, + Msp430Interrupt, + RiscvInterruptM, + RiscvInterruptS, + X86Interrupt, + + /* x86 */ + /// `ExternAbi::C` but spelled funny because x86 + Cdecl { unwind: bool, }, - Vectorcall { + /// gnu-stdcall on "unix" and win-stdcall on "windows" + Stdcall { unwind: bool, }, - Thiscall { + /// gnu-fastcall on "unix" and win-fastcall on "windows" + Fastcall { unwind: bool, }, - Aapcs { + /// windows C++ ABI + Thiscall { unwind: bool, }, - Win64 { + /// uses AVX and stuff + Vectorcall { unwind: bool, }, + + /* x86_64 */ SysV64 { unwind: bool, }, - PtxKernel, - Msp430Interrupt, - X86Interrupt, - /// An entry-point function called by the GPU's host - // FIXME: should not be callable from Rust on GPU targets, is for host's use only - GpuKernel, - EfiApi, - AvrInterrupt, - AvrNonBlockingInterrupt, - CCmseNonSecureCall, - CCmseNonSecureEntry, - System { + Win64 { unwind: bool, }, - RustCall, - /// *Not* a stable ABI, just directly use the Rust types to describe the ABI for LLVM. Even - /// normally ABI-compatible Rust types can become ABI-incompatible with this ABI! - Unadjusted, - /// For things unlikely to be called, where reducing register pressure in - /// `extern "Rust"` callers is worth paying extra cost in the callee. - /// Stronger than just `#[cold]` because `fn` pointers might be incompatible. - RustCold, - RiscvInterruptM, - RiscvInterruptS, } macro_rules! abi_impls { -- cgit 1.4.1-3-g733a5 From f66487b669a5b8ba0169af6c48d0fadaa06a57a9 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 6 Jun 2025 21:52:16 -0700 Subject: compiler: Remove superfluous renaming import of ExternAbi --- compiler/rustc_abi/src/extern_abi.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 75bfcff4462..0bc1c8a0930 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -12,8 +12,6 @@ use crate::AbiFromStrErr; #[cfg(test)] mod tests; -use ExternAbi as Abi; - /// ABI we expect to see within `extern "{abi}"` #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "nightly", derive(Encodable, Decodable))] @@ -253,7 +251,7 @@ pub fn all_names() -> Vec<&'static str> { impl ExternAbi { /// Default ABI chosen for `extern fn` declarations without an explicit ABI. - pub const FALLBACK: Abi = Abi::C { unwind: false }; + pub const FALLBACK: ExternAbi = ExternAbi::C { unwind: false }; pub fn name(self) -> &'static str { self.as_str() -- cgit 1.4.1-3-g733a5 From 5bab0d2e66f77e34865026856dcd5ae21f0b2d2f Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 7 Jun 2025 00:44:08 -0700 Subject: compiler: Treat ForceWarning as a Warning for diagnostic level This silences an ICE. --- compiler/rustc_errors/src/lib.rs | 2 +- tests/ui/lint/force-warn/ice-free.rs | 9 +++++++++ tests/ui/lint/force-warn/ice-free.stderr | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/force-warn/ice-free.rs create mode 100644 tests/ui/lint/force-warn/ice-free.stderr diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index bd421a441f9..6f0090a0bd6 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1529,7 +1529,7 @@ impl DiagCtxtInner { // Future breakages aren't emitted if they're `Level::Allow` or // `Level::Expect`, but they still need to be constructed and // stashed below, so they'll trigger the must_produce_diag check. - assert_matches!(diagnostic.level, Error | Warning | Allow | Expect); + assert_matches!(diagnostic.level, Error | ForceWarning | Warning | Allow | Expect); self.future_breakage_diagnostics.push(diagnostic.clone()); } diff --git a/tests/ui/lint/force-warn/ice-free.rs b/tests/ui/lint/force-warn/ice-free.rs new file mode 100644 index 00000000000..99b79f44648 --- /dev/null +++ b/tests/ui/lint/force-warn/ice-free.rs @@ -0,0 +1,9 @@ +//@ compile-flags: --force-warn pub_use_of_private_extern_crate +//@ check-pass + +extern crate core; +pub use core as reexported_core; +//~^ warning: extern crate `core` is private +//~| warning: this was previously accepted by the compiler + +fn main() {} diff --git a/tests/ui/lint/force-warn/ice-free.stderr b/tests/ui/lint/force-warn/ice-free.stderr new file mode 100644 index 00000000000..b64e3b138a2 --- /dev/null +++ b/tests/ui/lint/force-warn/ice-free.stderr @@ -0,0 +1,32 @@ +warning[E0365]: extern crate `core` is private and cannot be re-exported + --> $DIR/ice-free.rs:5:9 + | +LL | pub use core as reexported_core; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #127909 + = note: requested on the command line with `--force-warn pub-use-of-private-extern-crate` +help: consider making the `extern crate` item publicly accessible + | +LL | pub extern crate core; + | +++ + +warning: 1 warning emitted + +For more information about this error, try `rustc --explain E0365`. +Future incompatibility report: Future breakage diagnostic: +warning[E0365]: extern crate `core` is private and cannot be re-exported + --> $DIR/ice-free.rs:5:9 + | +LL | pub use core as reexported_core; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #127909 + = note: requested on the command line with `--force-warn pub-use-of-private-extern-crate` +help: consider making the `extern crate` item publicly accessible + | +LL | pub extern crate core; + | +++ + -- cgit 1.4.1-3-g733a5 From 6a6c595be68dbd9c205f7f2f5a4226d9aee7cd19 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Jun 2025 12:15:25 +0200 Subject: get rid of spurious cfg(bootstrap) --- library/core/src/iter/sources/generator.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/core/src/iter/sources/generator.rs b/library/core/src/iter/sources/generator.rs index c94232e09eb..155fa9368ad 100644 --- a/library/core/src/iter/sources/generator.rs +++ b/library/core/src/iter/sources/generator.rs @@ -9,8 +9,6 @@ /// /// ``` /// #![feature(iter_macro, coroutines)] -/// # #[cfg(not(bootstrap))] -/// # { /// /// let it = std::iter::iter!{|| { /// yield 1; @@ -19,7 +17,6 @@ /// } }(); /// let v: Vec<_> = it.collect(); /// assert_eq!(v, [1, 2, 3]); -/// # } /// ``` #[unstable(feature = "iter_macro", issue = "none", reason = "generators are unstable")] #[allow_internal_unstable(coroutines, iter_from_coroutine)] -- cgit 1.4.1-3-g733a5 From 17946c22b1d7abd2dd990bf6998c8491b534fe62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Jun 2025 11:32:09 +0200 Subject: const-eval error: always say in which item the error occurred also adjust the wording a little so that we don't say "the error occurred here" for two different spans --- compiler/rustc_const_eval/messages.ftl | 8 +- .../src/const_eval/eval_queries.rs | 18 +- src/tools/miri/tests/fail/const-ub-checks.stderr | 2 +- src/tools/miri/tests/fail/erroneous_const2.stderr | 2 +- tests/rustdoc-ui/const-evalutation-ice.stderr | 2 +- .../ui/array-slice-vec/array_const_index-0.stderr | 2 +- .../ui/array-slice-vec/array_const_index-1.stderr | 2 +- tests/ui/borrowck/issue-81899.stderr | 2 +- .../ui/borrowck/issue-88434-minimal-example.stderr | 2 +- ...issue-88434-removal-index-should-be-less.stderr | 2 +- .../const-errs-dont-conflict-103369.stderr | 4 +- .../defaults/default-param-wf-concrete.next.stderr | 2 +- .../defaults/default-param-wf-concrete.old.stderr | 2 +- tests/ui/const-generics/defaults/wfness.stderr | 2 +- tests/ui/const-generics/issues/issue-100313.stderr | 2 +- .../invalid-patterns.32bit.stderr | 4 +- .../invalid-patterns.64bit.stderr | 4 +- tests/ui/const-ptr/forbidden_slices.stderr | 10 +- tests/ui/const-ptr/out_of_bounds_read.stderr | 6 +- tests/ui/consts/assert-type-intrinsics.stderr | 6 +- tests/ui/consts/const-array-oob.stderr | 4 +- tests/ui/consts/const-assert-unchecked-ub.stderr | 2 +- tests/ui/consts/const-compare-bytes-ub.stderr | 16 +- tests/ui/consts/const-deref-ptr.stderr | 2 +- tests/ui/consts/const-err-early.stderr | 10 +- tests/ui/consts/const-err-enum-discriminant.stderr | 2 +- tests/ui/consts/const-err-multi.rs | 8 +- tests/ui/consts/const-err-multi.stderr | 2 +- tests/ui/consts/const-eval-fail-too-big.stderr | 2 +- .../assign-to-static-within-other-static.stderr | 2 +- .../const-eval/conditional_array_execution.stderr | 2 +- .../consts/const-eval/const-eval-overflow-2.stderr | 2 +- .../consts/const-eval/const-eval-overflow-3.stderr | 2 +- .../consts/const-eval/const-eval-overflow-4.stderr | 2 +- .../consts/const-eval/const-eval-overflow2.stderr | 16 +- .../consts/const-eval/const-eval-overflow2b.stderr | 16 +- .../consts/const-eval/const-eval-overflow2c.stderr | 16 +- .../const-eval/const-eval-query-stack.stderr | 2 +- ...st-pointer-values-in-various-types.64bit.stderr | 58 ++-- tests/ui/consts/const-eval/const_fn_ptr_fail2.rs | 4 +- .../ui/consts/const-eval/const_fn_ptr_fail2.stderr | 4 +- .../const_panic-normalize-tabs-115498.stderr | 2 +- tests/ui/consts/const-eval/const_panic.stderr | 24 +- tests/ui/consts/const-eval/const_panic_2021.stderr | 20 +- .../const-eval/const_panic_libcore_bin.stderr | 6 +- .../consts/const-eval/const_panic_track_caller.rs | 2 +- .../const-eval/const_panic_track_caller.stderr | 2 +- .../ui/consts/const-eval/const_raw_ptr_ops2.stderr | 4 +- .../const-eval/heap/alloc_intrinsic_errors.stderr | 2 +- .../heap/dealloc_intrinsic_dangling.stderr | 2 +- .../heap/dealloc_intrinsic_duplicate.stderr | 2 +- .../heap/dealloc_intrinsic_incorrect_layout.stderr | 8 +- .../consts/const-eval/index_out_of_bounds.stderr | 2 +- tests/ui/consts/const-eval/issue-43197.stderr | 4 +- tests/ui/consts/const-eval/issue-49296.stderr | 2 +- .../issue-91827-extern-types-field-offset.stderr | 2 +- .../const-eval/mod-static-with-const-fn.stderr | 2 +- .../ui/consts/const-eval/nonnull_as_ref_ub.stderr | 2 +- .../const-eval/panic-assoc-never-type.stderr | 2 +- tests/ui/consts/const-eval/panic-never-type.stderr | 2 +- tests/ui/consts/const-eval/parse_ints.stderr | 4 +- .../consts/const-eval/partial_ptr_overwrite.stderr | 2 +- tests/ui/consts/const-eval/raw-pointer-ub.rs | 10 +- tests/ui/consts/const-eval/raw-pointer-ub.stderr | 10 +- .../const-eval/ref_to_int_match.32bit.stderr | 2 +- .../const-eval/ref_to_int_match.64bit.stderr | 2 +- tests/ui/consts/const-eval/shift_overflow.stderr | 2 +- .../consts/const-eval/transmute-size-mismatch.rs | 4 +- .../const-eval/transmute-size-mismatch.stderr | 4 +- .../ui/consts/const-eval/ub-enum-overwrite.stderr | 2 +- tests/ui/consts/const-eval/ub-enum.stderr | 18 +- tests/ui/consts/const-eval/ub-invalid-values.rs | 2 +- .../ui/consts/const-eval/ub-invalid-values.stderr | 2 +- tests/ui/consts/const-eval/ub-nonnull.stderr | 4 +- tests/ui/consts/const-eval/ub-ref-ptr.stderr | 12 +- tests/ui/consts/const-eval/ub-uninhabit.stderr | 6 +- tests/ui/consts/const-eval/ub-wide-ptr.stderr | 12 +- .../const-eval/ub-write-through-immutable.stderr | 4 +- .../const-eval/union-const-eval-field.stderr | 2 +- tests/ui/consts/const-eval/union-ice.stderr | 6 +- tests/ui/consts/const-eval/union-ub.32bit.stderr | 2 +- tests/ui/consts/const-eval/union-ub.64bit.stderr | 2 +- .../consts/const-eval/unused-broken-const.stderr | 2 +- tests/ui/consts/const-eval/unwind-abort.stderr | 2 +- .../const-eval/validate_uninhabited_zsts.stderr | 4 +- .../validation-ice-extern-type-field.stderr | 2 +- .../consts/const-external-macro-const-err.stderr | 2 +- tests/ui/consts/const-int-unchecked.stderr | 98 +++--- .../const-len-underflow-separate-spans.next.stderr | 2 +- .../const-len-underflow-separate-spans.old.stderr | 2 +- .../consts/const-len-underflow-separate-spans.rs | 2 +- .../ui/consts/const-len-underflow-subspans.stderr | 2 +- tests/ui/consts/const-ptr-is-null.stderr | 2 +- ...nst-size_of_val-align_of_val-extern-type.stderr | 4 +- tests/ui/consts/const-slice-oob.stderr | 2 +- tests/ui/consts/const-unwrap.stderr | 4 +- tests/ui/consts/const_refs_to_static_fail.stderr | 2 +- tests/ui/consts/const_unsafe_unreachable_ub.rs | 2 +- tests/ui/consts/const_unsafe_unreachable_ub.stderr | 2 +- tests/ui/consts/control-flow/assert.stderr | 2 +- tests/ui/consts/copy-intrinsic.stderr | 8 +- tests/ui/consts/eval-enum.stderr | 4 +- .../detect-extra-ub.with_flag.stderr | 16 +- tests/ui/consts/issue-32829.stderr | 2 +- tests/ui/consts/issue-64506.stderr | 2 +- .../consts/issue-66693-panic-in-array-len.stderr | 2 +- tests/ui/consts/issue-66693.stderr | 4 +- tests/ui/consts/issue-76064.stderr | 2 +- tests/ui/consts/issue-miri-1910.stderr | 2 +- tests/ui/consts/large_const_alloc.stderr | 4 +- tests/ui/consts/miri_unleashed/abi-mismatch.rs | 2 +- tests/ui/consts/miri_unleashed/abi-mismatch.stderr | 2 +- tests/ui/consts/miri_unleashed/assoc_const.stderr | 2 +- tests/ui/consts/miri_unleashed/box.stderr | 2 +- .../miri_unleashed/const_refers_to_static.stderr | 6 +- .../const_refers_to_static_cross_crate.stderr | 2 +- tests/ui/consts/miri_unleashed/drop.rs | 2 +- tests/ui/consts/miri_unleashed/drop.stderr | 2 +- .../ui/consts/miri_unleashed/extern-static.stderr | 4 +- tests/ui/consts/miri_unleashed/inline_asm.stderr | 2 +- .../miri_unleashed/mutable_references.stderr | 2 +- .../consts/miri_unleashed/mutating_global.stderr | 2 +- tests/ui/consts/miri_unleashed/non_const_fn.stderr | 2 +- tests/ui/consts/miri_unleashed/ptr_arith.stderr | 4 +- tests/ui/consts/miri_unleashed/tls.stderr | 4 +- tests/ui/consts/missing_span_in_backtrace.stderr | 2 +- .../no-ice-from-static-in-const-issue-52060.stderr | 2 +- tests/ui/consts/offset_from_ub.stderr | 28 +- tests/ui/consts/offset_ub.stderr | 22 +- tests/ui/consts/overflowing-consts.noopt.stderr | 340 ++++++++++----------- tests/ui/consts/overflowing-consts.opt.stderr | 340 ++++++++++----------- ...rflowing-consts.opt_with_overflow_checks.stderr | 340 ++++++++++----------- ...moted_running_out_of_memory_issue-130687.stderr | 2 +- tests/ui/consts/promoted_size_overflow.stderr | 2 +- .../ui/consts/qualif-indirect-mutation-fail.stderr | 4 +- .../ui/consts/recursive-zst-static.default.stderr | 2 +- .../ui/consts/recursive-zst-static.unleash.stderr | 2 +- tests/ui/consts/recursive.stderr | 2 +- .../interpret-in-promoted.noopt.stderr | 2 +- .../interpret-in-promoted.opt.stderr | 2 +- .../slice-index-overflow-issue-130284.stderr | 2 +- .../consts/static_mut_containing_mut_ref2.stderr | 2 +- .../consts/static_mut_containing_mut_ref3.stderr | 2 +- tests/ui/consts/uninhabited-const-issue-61744.rs | 2 +- .../ui/consts/uninhabited-const-issue-61744.stderr | 2 +- .../ui/consts/write-to-static-mut-in-static.stderr | 4 +- tests/ui/enum-discriminant/eval-error.stderr | 2 +- tests/ui/error-codes/E0080.stderr | 4 +- .../ctfe-id-unlimited.return.stderr | 2 +- .../ui/explicit-tail-calls/ctfe-tail-call-panic.rs | 2 +- .../ctfe-tail-call-panic.stderr | 2 +- tests/ui/extern/issue-28324.stderr | 2 +- .../generic-const-items/def-site-eval.fail.stderr | 2 +- .../trivially-unsatisfied-bounds-0.stderr | 2 +- .../trivially-unsatisfied-bounds-1.stderr | 2 +- .../ui/infinite/infinite-recursion-const-fn.stderr | 2 +- .../intrinsics/intrinsic-raw_eq-const-bad.stderr | 6 +- tests/ui/issues/issue-76191.stderr | 2 +- tests/ui/layout/invalid-unsized-const-eval.stderr | 2 +- .../invalid-unsized-in-always-sized-tail.stderr | 2 +- .../issue-unsized-tail-restatic-ice-122488.stderr | 2 +- ...putable-due-to-trivial-bounds-ice-135138.stderr | 2 +- tests/ui/layout/unknown-when-no-type-parameter.rs | 2 +- .../layout/unknown-when-no-type-parameter.stderr | 2 +- .../layout/unknown-when-ptr-metadata-is-DST.stderr | 2 +- .../def-site-param-defaults-wf.stderr | 2 +- tests/ui/limits/huge-static.stderr | 4 +- tests/ui/limits/issue-55878.stderr | 2 +- .../recursion/recursive-static-definition.stderr | 4 +- .../stack-overflow-trait-infer-98842.32bit.stderr | 2 +- .../stack-overflow-trait-infer-98842.64bit.stderr | 2 +- tests/ui/statics/issue-14227.stderr | 2 +- tests/ui/statics/uninhabited-static.stderr | 4 +- .../default-field-values/invalid-const.stderr | 2 +- tests/ui/transmutability/uninhabited.stderr | 6 +- tests/ui/treat-err-as-bug/err.stderr | 2 +- tests/ui/type/pattern_types/literals.stderr | 10 +- tests/ui/type/pattern_types/range_patterns.stderr | 2 +- tests/ui/type/pattern_types/reverse_range.stderr | 2 +- tests/ui/type/pattern_types/validity.stderr | 6 +- 180 files changed, 938 insertions(+), 952 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 5bce6fb7ab2..7f9abe8aa8e 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -88,11 +88,9 @@ const_eval_division_overflow = const_eval_dyn_call_not_a_method = `dyn` call trying to call something that is not a method -const_eval_error = {$error_kind -> - [static] evaluation of static initializer failed here - [const] evaluation of constant value failed here - [const_with_path] evaluation of `{$instance}` failed here - *[other] {""} +const_eval_error = evaluation of `{$instance}` failed {$num_frames -> + [0] here + *[other] inside this call } const_eval_exact_div_has_remainder = diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 2556e57a58f..be840191547 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -430,20 +430,7 @@ fn report_eval_error<'tcx>( let (error, backtrace) = error.into_parts(); backtrace.print_backtrace(); - let (kind, instance) = if ecx.tcx.is_static(cid.instance.def_id()) { - ("static", String::new()) - } else { - // If the current item has generics, we'd like to enrich the message with the - // instance and its args: to show the actual compile-time values, in addition to - // the expression, leading to the const eval error. - let instance = &cid.instance; - if !instance.args.is_empty() { - let instance = with_no_trimmed_paths!(instance.to_string()); - ("const_with_path", instance) - } else { - ("const", String::new()) - } - }; + let instance = with_no_trimmed_paths!(cid.instance.to_string()); super::report( *ecx.tcx, @@ -451,6 +438,7 @@ fn report_eval_error<'tcx>( DUMMY_SP, || super::get_span_and_frames(ecx.tcx, ecx.stack()), |diag, span, frames| { + let num_frames = frames.len(); // FIXME(oli-obk): figure out how to use structured diagnostics again. diag.code(E0080); diag.span_label(span, crate::fluent_generated::const_eval_error); @@ -459,7 +447,7 @@ fn report_eval_error<'tcx>( } // Add after the frame rendering above, as it adds its own `instance` args. diag.arg("instance", instance); - diag.arg("error_kind", kind); + diag.arg("num_frames", num_frames); }, ) } diff --git a/src/tools/miri/tests/fail/const-ub-checks.stderr b/src/tools/miri/tests/fail/const-ub-checks.stderr index 9bac524bd45..df2d5653d2d 100644 --- a/src/tools/miri/tests/fail/const-ub-checks.stderr +++ b/src/tools/miri/tests/fail/const-ub-checks.stderr @@ -2,7 +2,7 @@ error[E0080]: accessing memory based on pointer with alignment ALIGN, but alignm --> tests/fail/const-ub-checks.rs:LL:CC | LL | ptr.read(); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `UNALIGNED_READ` failed here note: erroneous constant encountered --> tests/fail/const-ub-checks.rs:LL:CC diff --git a/src/tools/miri/tests/fail/erroneous_const2.stderr b/src/tools/miri/tests/fail/erroneous_const2.stderr index 9d3f1b13bee..08d2cc124f1 100644 --- a/src/tools/miri/tests/fail/erroneous_const2.stderr +++ b/src/tools/miri/tests/fail/erroneous_const2.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `5_u32 - 6_u32`, which would overflow --> tests/fail/erroneous_const2.rs:LL:CC | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ^^^^^ evaluation of constant value failed here + | ^^^^^ evaluation of `FOO` failed here note: erroneous constant encountered --> tests/fail/erroneous_const2.rs:LL:CC diff --git a/tests/rustdoc-ui/const-evalutation-ice.stderr b/tests/rustdoc-ui/const-evalutation-ice.stderr index 2410782000d..51958319f5f 100644 --- a/tests/rustdoc-ui/const-evalutation-ice.stderr +++ b/tests/rustdoc-ui/const-evalutation-ice.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/const-evalutation-ice.rs:10:22 | LL | pub const N: usize = 0 - (mem::size_of::() != 400) as usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `N` failed here error: aborting due to 1 previous error diff --git a/tests/ui/array-slice-vec/array_const_index-0.stderr b/tests/ui/array-slice-vec/array_const_index-0.stderr index 1080705713b..04cb6849663 100644 --- a/tests/ui/array-slice-vec/array_const_index-0.stderr +++ b/tests/ui/array-slice-vec/array_const_index-0.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 0 but the index is 1 --> $DIR/array_const_index-0.rs:2:16 | LL | const B: i32 = (&A)[1]; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `B` failed here error: aborting due to 1 previous error diff --git a/tests/ui/array-slice-vec/array_const_index-1.stderr b/tests/ui/array-slice-vec/array_const_index-1.stderr index 56299848d92..68b02673b01 100644 --- a/tests/ui/array-slice-vec/array_const_index-1.stderr +++ b/tests/ui/array-slice-vec/array_const_index-1.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 0 but the index is 1 --> $DIR/array_const_index-1.rs:2:16 | LL | const B: i32 = A[1]; - | ^^^^ evaluation of constant value failed here + | ^^^^ evaluation of `B` failed here error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/issue-81899.stderr b/tests/ui/borrowck/issue-81899.stderr index d236a17e0aa..96fe2ad709a 100644 --- a/tests/ui/borrowck/issue-81899.stderr +++ b/tests/ui/borrowck/issue-81899.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-81899.rs:6:24 | LL | const _CONST: &[u8] = &f(&[], |_| {}); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_CONST` failed inside this call | note: inside `f::<{closure@$DIR/issue-81899.rs:6:31: 6:34}>` --> $DIR/issue-81899.rs:13:5 diff --git a/tests/ui/borrowck/issue-88434-minimal-example.stderr b/tests/ui/borrowck/issue-88434-minimal-example.stderr index 3d9cc966047..3921c47640e 100644 --- a/tests/ui/borrowck/issue-88434-minimal-example.stderr +++ b/tests/ui/borrowck/issue-88434-minimal-example.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-88434-minimal-example.rs:5:22 | LL | const _CONST: &() = &f(&|_| {}); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_CONST` failed inside this call | note: inside `f::<{closure@$DIR/issue-88434-minimal-example.rs:5:25: 5:28}>` --> $DIR/issue-88434-minimal-example.rs:12:5 diff --git a/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr index 90d7f36938e..c7f945dc6ef 100644 --- a/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr +++ b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-88434-removal-index-should-be-less.rs:5:24 | LL | const _CONST: &[u8] = &f(&[], |_| {}); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_CONST` failed inside this call | note: inside `f::<{closure@$DIR/issue-88434-removal-index-should-be-less.rs:5:31: 5:34}>` --> $DIR/issue-88434-removal-index-should-be-less.rs:12:5 diff --git a/tests/ui/coherence/const-errs-dont-conflict-103369.stderr b/tests/ui/coherence/const-errs-dont-conflict-103369.stderr index e577a36cc10..c8ed75abf72 100644 --- a/tests/ui/coherence/const-errs-dont-conflict-103369.stderr +++ b/tests/ui/coherence/const-errs-dont-conflict-103369.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: Some error occurred --> $DIR/const-errs-dont-conflict-103369.rs:5:25 | LL | impl ConstGenericTrait<{my_fn(1)}> for () {} - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `<() as ConstGenericTrait<{my_fn(1)}>>::{constant#0}` failed inside this call | note: inside `my_fn` --> $DIR/const-errs-dont-conflict-103369.rs:10:5 @@ -14,7 +14,7 @@ error[E0080]: evaluation panicked: Some error occurred --> $DIR/const-errs-dont-conflict-103369.rs:7:25 | LL | impl ConstGenericTrait<{my_fn(2)}> for () {} - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `<() as ConstGenericTrait<{my_fn(2)}>>::{constant#0}` failed inside this call | note: inside `my_fn` --> $DIR/const-errs-dont-conflict-103369.rs:10:5 diff --git a/tests/ui/const-generics/defaults/default-param-wf-concrete.next.stderr b/tests/ui/const-generics/defaults/default-param-wf-concrete.next.stderr index 3299c27a0e7..133d8f6b0f0 100644 --- a/tests/ui/const-generics/defaults/default-param-wf-concrete.next.stderr +++ b/tests/ui/const-generics/defaults/default-param-wf-concrete.next.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `u8::MAX + 1_u8`, which would overflow --> $DIR/default-param-wf-concrete.rs:4:28 | LL | struct Foo; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `Foo::{constant#0}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr b/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr index 3299c27a0e7..133d8f6b0f0 100644 --- a/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr +++ b/tests/ui/const-generics/defaults/default-param-wf-concrete.old.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `u8::MAX + 1_u8`, which would overflow --> $DIR/default-param-wf-concrete.rs:4:28 | LL | struct Foo; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `Foo::{constant#0}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/defaults/wfness.stderr b/tests/ui/const-generics/defaults/wfness.stderr index ef5167cfc00..4f42afed81d 100644 --- a/tests/ui/const-generics/defaults/wfness.stderr +++ b/tests/ui/const-generics/defaults/wfness.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `u8::MAX + 1_u8`, which would overflow --> $DIR/wfness.rs:1:33 | LL | struct Ooopsies; - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `Ooopsies::{constant#0}` failed here error[E0277]: the trait bound `(): Trait<2>` is not satisfied --> $DIR/wfness.rs:8:9 diff --git a/tests/ui/const-generics/issues/issue-100313.stderr b/tests/ui/const-generics/issues/issue-100313.stderr index 2ae4c30e15f..d1a0249728e 100644 --- a/tests/ui/const-generics/issues/issue-100313.stderr +++ b/tests/ui/const-generics/issues/issue-100313.stderr @@ -2,7 +2,7 @@ error[E0080]: writing to ALLOC0 which is read-only --> $DIR/issue-100313.rs:18:5 | LL | x.set_false(); - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_` failed inside this call | note: inside `T::<&true>::set_false` --> $DIR/issue-100313.rs:11:13 diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr index 172fd37fa69..92b226fe0f7 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/invalid-patterns.rs:40:32 | LL | get_flag::(); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `main::{constant#7}` failed here error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean --> $DIR/invalid-patterns.rs:42:14 @@ -30,7 +30,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/invalid-patterns.rs:44:58 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `main::{constant#11}` failed here error[E0308]: mismatched types --> $DIR/invalid-patterns.rs:31:21 diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr index 172fd37fa69..92b226fe0f7 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/invalid-patterns.rs:40:32 | LL | get_flag::(); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `main::{constant#7}` failed here error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean --> $DIR/invalid-patterns.rs:42:14 @@ -30,7 +30,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/invalid-patterns.rs:44:58 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `main::{constant#11}` failed here error[E0308]: mismatched types --> $DIR/invalid-patterns.rs:31:21 diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index d4dcc6e66b1..25d6f0461a9 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -103,13 +103,13 @@ error[E0080]: evaluation panicked: assertion failed: 0 < pointee_size && pointee --> $DIR/forbidden_slices.rs:50:33 | LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; // errors inside libcore - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `R1` failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC10 which is only 4 bytes from the end of the allocation --> $DIR/forbidden_slices.rs:54:25 | LL | from_ptr_range(ptr..ptr.add(2)) // errors inside libcore - | ^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^ evaluation of `R2` failed here error[E0080]: constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer --> $DIR/forbidden_slices.rs:57:1 @@ -161,19 +161,19 @@ error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer --> $DIR/forbidden_slices.rs:79:25 | LL | from_ptr_range(ptr..ptr.add(1)) - | ^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^ evaluation of `R8` failed here error[E0080]: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation --> $DIR/forbidden_slices.rs:85:34 | LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `R9` failed here error[E0080]: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation --> $DIR/forbidden_slices.rs:87:35 | LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `R10` failed here error: aborting due to 18 previous errors diff --git a/tests/ui/const-ptr/out_of_bounds_read.stderr b/tests/ui/const-ptr/out_of_bounds_read.stderr index e921a5f4987..a98765b15f2 100644 --- a/tests/ui/const-ptr/out_of_bounds_read.stderr +++ b/tests/ui/const-ptr/out_of_bounds_read.stderr @@ -2,19 +2,19 @@ error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0 --> $DIR/out_of_bounds_read.rs:8:33 | LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::_READ` failed here error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes --> $DIR/out_of_bounds_read.rs:10:39 | LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `main::_CONST_READ` failed here error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes --> $DIR/out_of_bounds_read.rs:12:37 | LL | const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::_MUT_READ` failed here error: aborting due to 3 previous errors diff --git a/tests/ui/consts/assert-type-intrinsics.stderr b/tests/ui/consts/assert-type-intrinsics.stderr index 90f003716d1..92fc90aebe4 100644 --- a/tests/ui/consts/assert-type-intrinsics.stderr +++ b/tests/ui/consts/assert-type-intrinsics.stderr @@ -2,19 +2,19 @@ error[E0080]: evaluation panicked: aborted execution: attempted to instantiate u --> $DIR/assert-type-intrinsics.rs:11:9 | LL | MaybeUninit::::uninit().assume_init(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::_BAD1` failed here error[E0080]: evaluation panicked: aborted execution: attempted to leave type `&i32` uninitialized, which is invalid --> $DIR/assert-type-intrinsics.rs:15:9 | LL | intrinsics::assert_mem_uninitialized_valid::<&'static i32>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::_BAD2` failed here error[E0080]: evaluation panicked: aborted execution: attempted to zero-initialize type `&i32`, which is invalid --> $DIR/assert-type-intrinsics.rs:19:9 | LL | intrinsics::assert_zero_valid::<&'static i32>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::_BAD3` failed here error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const-array-oob.stderr b/tests/ui/consts/const-array-oob.stderr index d4a02664490..7d5f23473c1 100644 --- a/tests/ui/consts/const-array-oob.stderr +++ b/tests/ui/consts/const-array-oob.stderr @@ -2,13 +2,13 @@ error[E0080]: index out of bounds: the length is 3 but the index is 4 --> $DIR/const-array-oob.rs:5:19 | LL | const BLUB: [u32; FOO[4]] = [5, 6]; - | ^^^^^^ evaluation of constant value failed here + | ^^^^^^ evaluation of `BLUB::{constant#0}` failed here error[E0080]: index out of bounds: the length is 3 but the index is 5 --> $DIR/const-array-oob.rs:2:20 | LL | const BAR: usize = FOO[5]; - | ^^^^^^ evaluation of constant value failed here + | ^^^^^^ evaluation of `BAR` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-assert-unchecked-ub.stderr b/tests/ui/consts/const-assert-unchecked-ub.stderr index 0a785942cf4..d8e68fc9bee 100644 --- a/tests/ui/consts/const-assert-unchecked-ub.stderr +++ b/tests/ui/consts/const-assert-unchecked-ub.stderr @@ -2,7 +2,7 @@ error[E0080]: `assume` called with `false` --> $DIR/const-assert-unchecked-ub.rs:3:5 | LL | std::hint::assert_unchecked(n < 32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-compare-bytes-ub.stderr b/tests/ui/consts/const-compare-bytes-ub.stderr index 1b3824f22d0..c1706a8c4b0 100644 --- a/tests/ui/consts/const-compare-bytes-ub.stderr +++ b/tests/ui/consts/const-compare-bytes-ub.stderr @@ -2,49 +2,49 @@ error[E0080]: memory access failed: attempting to access 1 byte, but got null po --> $DIR/const-compare-bytes-ub.rs:9:9 | LL | compare_bytes(0 as *const u8, 2 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::LHS_NULL` failed here error[E0080]: memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/const-compare-bytes-ub.rs:13:9 | LL | compare_bytes(1 as *const u8, 0 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::RHS_NULL` failed here error[E0080]: memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/const-compare-bytes-ub.rs:17:9 | LL | compare_bytes(1 as *const u8, 2 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::DANGLING_PTR_NON_ZERO_LENGTH` failed here error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0 which is only 3 bytes from the end of the allocation --> $DIR/const-compare-bytes-ub.rs:21:9 | LL | compare_bytes([1, 2, 3].as_ptr(), [1, 2, 3, 4].as_ptr(), 4) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::LHS_OUT_OF_BOUNDS` failed here error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC1 which is only 3 bytes from the end of the allocation --> $DIR/const-compare-bytes-ub.rs:25:9 | LL | compare_bytes([1, 2, 3, 4].as_ptr(), [1, 2, 3].as_ptr(), 4) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::RHS_OUT_OF_BOUNDS` failed here error[E0080]: reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory --> $DIR/const-compare-bytes-ub.rs:29:9 | LL | compare_bytes(MaybeUninit::uninit().as_ptr(), [1].as_ptr(), 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::LHS_UNINIT` failed here error[E0080]: reading memory at ALLOC3[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory --> $DIR/const-compare-bytes-ub.rs:33:9 | LL | compare_bytes([1].as_ptr(), MaybeUninit::uninit().as_ptr(), 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::RHS_UNINIT` failed here error[E0080]: unable to turn pointer into integer --> $DIR/const-compare-bytes-ub.rs:37:9 | LL | compare_bytes([&1].as_ptr().cast(), [&2].as_ptr().cast(), std::mem::size_of::()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::WITH_PROVENANCE` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-deref-ptr.stderr b/tests/ui/consts/const-deref-ptr.stderr index f233b7d94bd..aa89aedac31 100644 --- a/tests/ui/consts/const-deref-ptr.stderr +++ b/tests/ui/consts/const-deref-ptr.stderr @@ -2,7 +2,7 @@ error[E0080]: memory access failed: attempting to access 8 bytes, but got 0xdead --> $DIR/const-deref-ptr.rs:4:30 | LL | static C: u64 = unsafe { *(0xdeadbeef as *const u64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::C` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-err-early.stderr b/tests/ui/consts/const-err-early.stderr index 98f9b4fbd2a..2d8dd08c1c8 100644 --- a/tests/ui/consts/const-err-early.stderr +++ b/tests/ui/consts/const-err-early.stderr @@ -2,31 +2,31 @@ error[E0080]: attempt to negate `i8::MIN`, which would overflow --> $DIR/const-err-early.rs:1:19 | LL | pub const A: i8 = -i8::MIN; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `A` failed here error[E0080]: attempt to compute `200_u8 + 200_u8`, which would overflow --> $DIR/const-err-early.rs:2:19 | LL | pub const B: u8 = 200u8 + 200u8; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `B` failed here error[E0080]: attempt to compute `200_u8 * 4_u8`, which would overflow --> $DIR/const-err-early.rs:3:19 | LL | pub const C: u8 = 200u8 * 4; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `C` failed here error[E0080]: attempt to compute `42_u8 - 43_u8`, which would overflow --> $DIR/const-err-early.rs:4:19 | LL | pub const D: u8 = 42u8 - (42u8 + 1); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `D` failed here error[E0080]: index out of bounds: the length is 1 but the index is 1 --> $DIR/const-err-early.rs:5:19 | LL | pub const E: u8 = [5u8][1]; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `E` failed here error: aborting due to 5 previous errors diff --git a/tests/ui/consts/const-err-enum-discriminant.stderr b/tests/ui/consts/const-err-enum-discriminant.stderr index 702d85b2f93..8724333ad7a 100644 --- a/tests/ui/consts/const-err-enum-discriminant.stderr +++ b/tests/ui/consts/const-err-enum-discriminant.stderr @@ -2,7 +2,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/const-err-enum-discriminant.rs:8:21 | LL | Boo = [unsafe { Foo { b: () }.a }; 4][3], - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `Bar::Boo::{constant#0}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-err-multi.rs b/tests/ui/consts/const-err-multi.rs index 2fb0d291245..90214b656ab 100644 --- a/tests/ui/consts/const-err-multi.rs +++ b/tests/ui/consts/const-err-multi.rs @@ -1,12 +1,12 @@ pub const A: i8 = -i8::MIN; -//~^ NOTE constant +//~^ NOTE failed here //~| ERROR attempt to negate `i8::MIN`, which would overflow pub const B: i8 = A; -//~^ NOTE constant +//~^ NOTE erroneous constant pub const C: u8 = A as u8; -//~^ NOTE constant +//~^ NOTE erroneous constant pub const D: i8 = 50 - A; -//~^ NOTE constant +//~^ NOTE erroneous constant fn main() { let _ = (A, B, C, D); diff --git a/tests/ui/consts/const-err-multi.stderr b/tests/ui/consts/const-err-multi.stderr index 9e1554eb265..515316523f6 100644 --- a/tests/ui/consts/const-err-multi.stderr +++ b/tests/ui/consts/const-err-multi.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to negate `i8::MIN`, which would overflow --> $DIR/const-err-multi.rs:1:19 | LL | pub const A: i8 = -i8::MIN; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `A` failed here note: erroneous constant encountered --> $DIR/const-err-multi.rs:4:19 diff --git a/tests/ui/consts/const-eval-fail-too-big.stderr b/tests/ui/consts/const-eval-fail-too-big.stderr index 3bc20ded5bf..d58efbf6d8c 100644 --- a/tests/ui/consts/const-eval-fail-too-big.stderr +++ b/tests/ui/consts/const-eval-fail-too-big.stderr @@ -2,7 +2,7 @@ error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target a --> $DIR/const-eval-fail-too-big.rs:4:28 | LL | let x = [0u8; !0usize]; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `B::{constant#0}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr b/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr index b19d0eaa116..b232cbf25e7 100644 --- a/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr +++ b/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr @@ -2,7 +2,7 @@ error[E0080]: modifying a static's initial value from another static's initializ --> $DIR/assign-to-static-within-other-static.rs:8:5 | LL | FOO = 5; - | ^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^ evaluation of `BOO` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/conditional_array_execution.stderr b/tests/ui/consts/const-eval/conditional_array_execution.stderr index 65ae9a9fb8a..9a0a7527277 100644 --- a/tests/ui/consts/const-eval/conditional_array_execution.stderr +++ b/tests/ui/consts/const-eval/conditional_array_execution.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `5_u32 - 6_u32`, which would overflow --> $DIR/conditional_array_execution.rs:3:19 | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ^^^^^ evaluation of constant value failed here + | ^^^^^ evaluation of `FOO` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr index 90b94600aed..ffb8cade923 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to negate `i8::MIN`, which would overflow --> $DIR/const-eval-overflow-2.rs:11:25 | LL | const NEG_NEG_128: i8 = -NEG_128; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `NEG_NEG_128` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3.stderr b/tests/ui/consts/const-eval/const-eval-overflow-3.stderr index 5ad7d08bdb3..aeb88716f16 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-3.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-3.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `i8::MAX + 1_i8`, which would overflow --> $DIR/const-eval-overflow-3.rs:18:11 | LL | = [0; (i8::MAX + 1) as usize]; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `A_I8_I::{constant#1}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4.stderr b/tests/ui/consts/const-eval/const-eval-overflow-4.stderr index c14a880849f..daabb33e0f3 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-4.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-4.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `i8::MAX + 1_i8`, which would overflow --> $DIR/const-eval-overflow-4.rs:11:13 | LL | : [u32; (i8::MAX as i8 + 1i8) as usize] - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `A_I8_T::{constant#0}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const-eval-overflow2.stderr b/tests/ui/consts/const-eval/const-eval-overflow2.stderr index a705604e383..6ec3fa73cb7 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow2.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow2.stderr @@ -2,49 +2,49 @@ error[E0080]: attempt to compute `i8::MIN - 1_i8`, which would overflow --> $DIR/const-eval-overflow2.rs:12:6 | LL | i8::MIN - 1, - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `VALS_I8` failed here error[E0080]: attempt to compute `i16::MIN - 1_i16`, which would overflow --> $DIR/const-eval-overflow2.rs:18:6 | LL | i16::MIN - 1, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_I16` failed here error[E0080]: attempt to compute `i32::MIN - 1_i32`, which would overflow --> $DIR/const-eval-overflow2.rs:24:6 | LL | i32::MIN - 1, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_I32` failed here error[E0080]: attempt to compute `i64::MIN - 1_i64`, which would overflow --> $DIR/const-eval-overflow2.rs:30:6 | LL | i64::MIN - 1, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_I64` failed here error[E0080]: attempt to compute `0_u8 - 1_u8`, which would overflow --> $DIR/const-eval-overflow2.rs:36:6 | LL | u8::MIN - 1, - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `VALS_U8` failed here error[E0080]: attempt to compute `0_u16 - 1_u16`, which would overflow --> $DIR/const-eval-overflow2.rs:41:6 | LL | u16::MIN - 1, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_U16` failed here error[E0080]: attempt to compute `0_u32 - 1_u32`, which would overflow --> $DIR/const-eval-overflow2.rs:46:6 | LL | u32::MIN - 1, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_U32` failed here error[E0080]: attempt to compute `0_u64 - 1_u64`, which would overflow --> $DIR/const-eval-overflow2.rs:52:6 | LL | u64::MIN - 1, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_U64` failed here error: aborting due to 8 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-overflow2b.stderr b/tests/ui/consts/const-eval/const-eval-overflow2b.stderr index 33de4b6ed32..5b8e559d046 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow2b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow2b.stderr @@ -2,49 +2,49 @@ error[E0080]: attempt to compute `i8::MAX + 1_i8`, which would overflow --> $DIR/const-eval-overflow2b.rs:12:6 | LL | i8::MAX + 1, - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `VALS_I8` failed here error[E0080]: attempt to compute `i16::MAX + 1_i16`, which would overflow --> $DIR/const-eval-overflow2b.rs:18:6 | LL | i16::MAX + 1, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_I16` failed here error[E0080]: attempt to compute `i32::MAX + 1_i32`, which would overflow --> $DIR/const-eval-overflow2b.rs:24:6 | LL | i32::MAX + 1, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_I32` failed here error[E0080]: attempt to compute `i64::MAX + 1_i64`, which would overflow --> $DIR/const-eval-overflow2b.rs:30:6 | LL | i64::MAX + 1, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_I64` failed here error[E0080]: attempt to compute `u8::MAX + 1_u8`, which would overflow --> $DIR/const-eval-overflow2b.rs:36:6 | LL | u8::MAX + 1, - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `VALS_U8` failed here error[E0080]: attempt to compute `u16::MAX + 1_u16`, which would overflow --> $DIR/const-eval-overflow2b.rs:41:6 | LL | u16::MAX + 1, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_U16` failed here error[E0080]: attempt to compute `u32::MAX + 1_u32`, which would overflow --> $DIR/const-eval-overflow2b.rs:46:6 | LL | u32::MAX + 1, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_U32` failed here error[E0080]: attempt to compute `u64::MAX + 1_u64`, which would overflow --> $DIR/const-eval-overflow2b.rs:52:6 | LL | u64::MAX + 1, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_U64` failed here error: aborting due to 8 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-overflow2c.stderr b/tests/ui/consts/const-eval/const-eval-overflow2c.stderr index 69949b57904..99eeadf6b0d 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow2c.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow2c.stderr @@ -2,49 +2,49 @@ error[E0080]: attempt to compute `i8::MIN * 2_i8`, which would overflow --> $DIR/const-eval-overflow2c.rs:12:6 | LL | i8::MIN * 2, - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `VALS_I8` failed here error[E0080]: attempt to compute `i16::MIN * 2_i16`, which would overflow --> $DIR/const-eval-overflow2c.rs:18:6 | LL | i16::MIN * 2, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_I16` failed here error[E0080]: attempt to compute `i32::MIN * 2_i32`, which would overflow --> $DIR/const-eval-overflow2c.rs:24:6 | LL | i32::MIN * 2, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_I32` failed here error[E0080]: attempt to compute `i64::MIN * 2_i64`, which would overflow --> $DIR/const-eval-overflow2c.rs:30:6 | LL | i64::MIN * 2, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_I64` failed here error[E0080]: attempt to compute `u8::MAX * 2_u8`, which would overflow --> $DIR/const-eval-overflow2c.rs:36:6 | LL | u8::MAX * 2, - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `VALS_U8` failed here error[E0080]: attempt to compute `u16::MAX * 2_u16`, which would overflow --> $DIR/const-eval-overflow2c.rs:41:6 | LL | u16::MAX * 2, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_U16` failed here error[E0080]: attempt to compute `u32::MAX * 2_u32`, which would overflow --> $DIR/const-eval-overflow2c.rs:46:6 | LL | u32::MAX * 2, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_U32` failed here error[E0080]: attempt to compute `u64::MAX * 2_u64`, which would overflow --> $DIR/const-eval-overflow2c.rs:52:6 | LL | u64::MAX * 2, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `VALS_U64` failed here error: aborting due to 8 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-query-stack.stderr b/tests/ui/consts/const-eval/const-eval-query-stack.stderr index d5b7e67724d..96206dc5078 100644 --- a/tests/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/tests/ui/consts/const-eval/const-eval-query-stack.stderr @@ -2,7 +2,7 @@ error: internal compiler error[E0080]: attempt to divide `1_i32` by zero --> $DIR/const-eval-query-stack.rs:16:16 | LL | const X: i32 = 1 / 0; - | ^^^^^ evaluation of constant value failed here + | ^^^^^ evaluation of `X` failed here note: please make sure that you have updated to the latest nightly diff --git a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr index 3a1e8c734d4..d28d6841ca9 100644 --- a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr +++ b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:27:49 | LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_USIZE_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -11,7 +11,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:30:43 | LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_U8_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -20,7 +20,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:33:45 | LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_U16_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -29,7 +29,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:36:45 | LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_U32_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -38,7 +38,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:39:45 | LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_U64_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -47,13 +47,13 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/const-pointer-values-in-various-types.rs:42:47 | LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_U128_UNION` failed here error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:45:43 | LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_I8_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -62,7 +62,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:48:45 | LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_I16_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -71,7 +71,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:51:45 | LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_I32_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -80,7 +80,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:54:45 | LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_I64_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -89,13 +89,13 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/const-pointer-values-in-various-types.rs:57:47 | LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_I128_UNION` failed here error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:60:45 | LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_F32_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -104,7 +104,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:63:45 | LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_F64_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -113,7 +113,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:66:47 | LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_BOOL_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -122,7 +122,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:69:47 | LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_CHAR_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -131,7 +131,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:72:39 | LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::STR_U8_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -140,7 +140,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:75:41 | LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::STR_U16_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -149,7 +149,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:78:41 | LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::STR_U32_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -158,7 +158,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:81:41 | LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::STR_U64_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -167,7 +167,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:84:43 | LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::STR_U128_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -176,7 +176,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:87:39 | LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::STR_I8_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -185,7 +185,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:90:41 | LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::STR_I16_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -194,7 +194,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:93:41 | LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::STR_I32_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -203,7 +203,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:96:41 | LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::STR_I64_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -212,7 +212,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:99:43 | LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::STR_I128_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -221,7 +221,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:102:41 | LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::STR_F32_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -230,7 +230,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:105:41 | LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::STR_F64_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -239,7 +239,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:108:43 | LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::STR_BOOL_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -248,7 +248,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/const-pointer-values-in-various-types.rs:111:43 | LL | const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::STR_CHAR_UNION` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs b/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs index 03976a05b75..8d928e26378 100644 --- a/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs +++ b/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs @@ -14,10 +14,10 @@ const fn bar(x: fn(usize) -> usize, y: usize) -> usize { } const Y: usize = bar(X, 2); // FIXME: should fail to typeck someday -//~^ NOTE evaluation of constant value failed +//~^ NOTE failed inside this call //~| ERROR calling non-const function `double` const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday -//~^ NOTE evaluation of constant value failed +//~^ NOTE failed inside this call //~| ERROR calling non-const function `double` fn main() { diff --git a/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr index 6eddb72bae8..3ac96b40994 100644 --- a/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr +++ b/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr @@ -2,7 +2,7 @@ error[E0080]: calling non-const function `double` --> $DIR/const_fn_ptr_fail2.rs:16:18 | LL | const Y: usize = bar(X, 2); // FIXME: should fail to typeck someday - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `Y` failed inside this call | note: inside `bar` --> $DIR/const_fn_ptr_fail2.rs:9:5 @@ -14,7 +14,7 @@ error[E0080]: calling non-const function `double` --> $DIR/const_fn_ptr_fail2.rs:19:18 | LL | const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `Z` failed inside this call | note: inside `bar` --> $DIR/const_fn_ptr_fail2.rs:9:5 diff --git a/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr b/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr index 6e5e0e727fb..7e7b59ce43f 100644 --- a/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr +++ b/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: --> $DIR/const_panic-normalize-tabs-115498.rs:3:17 | LL | struct Bug([u8; panic!{"\t"}]); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `Bug::0::{constant#0}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const_panic.stderr b/tests/ui/consts/const-eval/const_panic.stderr index 1b5421276c3..46b36ecfa6a 100644 --- a/tests/ui/consts/const-eval/const_panic.stderr +++ b/tests/ui/consts/const-eval/const_panic.stderr @@ -2,25 +2,25 @@ error[E0080]: evaluation panicked: cheese --> $DIR/const_panic.rs:6:15 | LL | const Z: () = std::panic!("cheese"); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `Z` failed here error[E0080]: evaluation panicked: explicit panic --> $DIR/const_panic.rs:9:16 | LL | const Z2: () = std::panic!(); - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `Z2` failed here error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic.rs:12:15 | LL | const Y: () = std::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic.rs:15:15 | LL | const X: () = std::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `X` failed here | = note: this error originates in the macro `std::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -28,37 +28,37 @@ error[E0080]: evaluation panicked: hello --> $DIR/const_panic.rs:18:15 | LL | const W: () = std::panic!(MSG); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `W` failed here error[E0080]: evaluation panicked: hello --> $DIR/const_panic.rs:21:16 | LL | const W2: () = std::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `W2` failed here error[E0080]: evaluation panicked: cheese --> $DIR/const_panic.rs:24:20 | LL | const Z_CORE: () = core::panic!("cheese"); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Z_CORE` failed here error[E0080]: evaluation panicked: explicit panic --> $DIR/const_panic.rs:27:21 | LL | const Z2_CORE: () = core::panic!(); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `Z2_CORE` failed here error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic.rs:30:20 | LL | const Y_CORE: () = core::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^ evaluation of `Y_CORE` failed here error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic.rs:33:20 | LL | const X_CORE: () = core::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `X_CORE` failed here | = note: this error originates in the macro `core::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -66,13 +66,13 @@ error[E0080]: evaluation panicked: hello --> $DIR/const_panic.rs:36:20 | LL | const W_CORE: () = core::panic!(MSG); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `W_CORE` failed here error[E0080]: evaluation panicked: hello --> $DIR/const_panic.rs:39:21 | LL | const W2_CORE: () = core::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `W2_CORE` failed here error: aborting due to 12 previous errors diff --git a/tests/ui/consts/const-eval/const_panic_2021.stderr b/tests/ui/consts/const-eval/const_panic_2021.stderr index 15b173f9400..ba771a35d03 100644 --- a/tests/ui/consts/const-eval/const_panic_2021.stderr +++ b/tests/ui/consts/const-eval/const_panic_2021.stderr @@ -2,25 +2,25 @@ error[E0080]: evaluation panicked: blåhaj --> $DIR/const_panic_2021.rs:6:15 | LL | const A: () = std::panic!("blåhaj"); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `A` failed here error[E0080]: evaluation panicked: explicit panic --> $DIR/const_panic_2021.rs:9:15 | LL | const B: () = std::panic!(); - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `B` failed here error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic_2021.rs:12:15 | LL | const C: () = std::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `C` failed here error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic_2021.rs:15:15 | LL | const D: () = std::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `D` failed here | = note: this error originates in the macro `std::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -28,31 +28,31 @@ error[E0080]: evaluation panicked: hello --> $DIR/const_panic_2021.rs:18:15 | LL | const E: () = std::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `E` failed here error[E0080]: evaluation panicked: shark --> $DIR/const_panic_2021.rs:21:20 | LL | const A_CORE: () = core::panic!("shark"); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `A_CORE` failed here error[E0080]: evaluation panicked: explicit panic --> $DIR/const_panic_2021.rs:24:20 | LL | const B_CORE: () = core::panic!(); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `B_CORE` failed here error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic_2021.rs:27:20 | LL | const C_CORE: () = core::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^ evaluation of `C_CORE` failed here error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic_2021.rs:30:20 | LL | const D_CORE: () = core::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `D_CORE` failed here | = note: this error originates in the macro `core::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -60,7 +60,7 @@ error[E0080]: evaluation panicked: hello --> $DIR/const_panic_2021.rs:33:20 | LL | const E_CORE: () = core::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `E_CORE` failed here error: aborting due to 10 previous errors diff --git a/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr b/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr index 3c308e38850..e07b172d426 100644 --- a/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr +++ b/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr @@ -2,19 +2,19 @@ error[E0080]: evaluation panicked: cheese --> $DIR/const_panic_libcore_bin.rs:8:15 | LL | const Z: () = panic!("cheese"); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `Z` failed here error[E0080]: evaluation panicked: internal error: entered unreachable code --> $DIR/const_panic_libcore_bin.rs:11:15 | LL | const Y: () = unreachable!(); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `Y` failed here error[E0080]: evaluation panicked: not implemented --> $DIR/const_panic_libcore_bin.rs:14:15 | LL | const X: () = unimplemented!(); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `X` failed here | = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/const-eval/const_panic_track_caller.rs b/tests/ui/consts/const-eval/const_panic_track_caller.rs index 5f5d853eb97..f5ede567b82 100644 --- a/tests/ui/consts/const-eval/const_panic_track_caller.rs +++ b/tests/ui/consts/const-eval/const_panic_track_caller.rs @@ -17,5 +17,5 @@ const fn c() -> u32 { } const X: u32 = c(); -//~^ NOTE evaluation of constant value failed +//~^ NOTE failed inside this call //~| ERROR hey diff --git a/tests/ui/consts/const-eval/const_panic_track_caller.stderr b/tests/ui/consts/const-eval/const_panic_track_caller.stderr index b4017ccf8da..4793c5398fc 100644 --- a/tests/ui/consts/const-eval/const_panic_track_caller.stderr +++ b/tests/ui/consts/const-eval/const_panic_track_caller.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: hey --> $DIR/const_panic_track_caller.rs:19:16 | LL | const X: u32 = c(); - | ^^^ evaluation of constant value failed here + | ^^^ evaluation of `X` failed inside this call | note: inside `c` --> $DIR/const_panic_track_caller.rs:15:5 diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr index 6f096ee5ce7..6341292789c 100644 --- a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr @@ -2,13 +2,13 @@ error[E0080]: memory access failed: attempting to access 4 bytes, but got 0x2a[n --> $DIR/const_raw_ptr_ops2.rs:7:26 | LL | const Z2: i32 = unsafe { *(42 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `Z2` failed here error[E0080]: memory access failed: attempting to access 4 bytes, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/const_raw_ptr_ops2.rs:8:26 | LL | const Z3: i32 = unsafe { *(44 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `Z3` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr index 9132c7e9cd4..a1f0b7b2beb 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr @@ -2,7 +2,7 @@ error[E0080]: invalid align passed to `const_allocate`: 3 is not a power of 2 --> $DIR/alloc_intrinsic_errors.rs:7:18 | LL | const FOO: i32 = foo(); - | ^^^^^ evaluation of constant value failed here + | ^^^^^ evaluation of `FOO` failed inside this call | note: inside `foo` --> $DIR/alloc_intrinsic_errors.rs:10:17 diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr index cb419f2f739..d4039e1952c 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr @@ -13,7 +13,7 @@ error[E0080]: memory access failed: ALLOC1 has been freed, so this pointer is da --> $DIR/dealloc_intrinsic_dangling.rs:22:5 | LL | *reference - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_Y` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr index 3038d60f202..803b772615f 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr @@ -2,7 +2,7 @@ error[E0080]: memory access failed: ALLOC0 has been freed, so this pointer is da --> $DIR/dealloc_intrinsic_duplicate.rs:9:5 | LL | intrinsics::const_deallocate(ptr, 4, 4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_X` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr index dea55c6086e..2d61f06ac5c 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr @@ -2,25 +2,25 @@ error[E0080]: incorrect layout on deallocation: ALLOC0 has size 4 and alignment --> $DIR/dealloc_intrinsic_incorrect_layout.rs:8:5 | LL | intrinsics::const_deallocate(ptr, 4, 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_X` failed here error[E0080]: incorrect layout on deallocation: ALLOC1 has size 4 and alignment 4, but gave size 2 and alignment 4 --> $DIR/dealloc_intrinsic_incorrect_layout.rs:13:5 | LL | intrinsics::const_deallocate(ptr, 2, 4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_Y` failed here error[E0080]: incorrect layout on deallocation: ALLOC2 has size 4 and alignment 4, but gave size 3 and alignment 4 --> $DIR/dealloc_intrinsic_incorrect_layout.rs:19:5 | LL | intrinsics::const_deallocate(ptr, 3, 4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_Z` failed here error[E0080]: invalid align passed to `const_deallocate`: 3 is not a power of 2 --> $DIR/dealloc_intrinsic_incorrect_layout.rs:25:5 | LL | intrinsics::const_deallocate(ptr, 4, 3); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_W` failed here error: aborting due to 4 previous errors diff --git a/tests/ui/consts/const-eval/index_out_of_bounds.stderr b/tests/ui/consts/const-eval/index_out_of_bounds.stderr index f4ec4c516fd..56e340cfebd 100644 --- a/tests/ui/consts/const-eval/index_out_of_bounds.stderr +++ b/tests/ui/consts/const-eval/index_out_of_bounds.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 0 but the index is 0 --> $DIR/index_out_of_bounds.rs:1:19 | LL | static FOO: i32 = [][0]; - | ^^^^^ evaluation of static initializer failed here + | ^^^^^ evaluation of `FOO` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/issue-43197.stderr b/tests/ui/consts/const-eval/issue-43197.stderr index cad23becff7..c525fd1c13b 100644 --- a/tests/ui/consts/const-eval/issue-43197.stderr +++ b/tests/ui/consts/const-eval/issue-43197.stderr @@ -2,13 +2,13 @@ error[E0080]: attempt to compute `0_u32 - 1_u32`, which would overflow --> $DIR/issue-43197.rs:6:20 | LL | const X: u32 = 0 - 1; - | ^^^^^ evaluation of constant value failed here + | ^^^^^ evaluation of `main::X` failed here error[E0080]: attempt to compute `0_u32 - 1_u32`, which would overflow --> $DIR/issue-43197.rs:8:24 | LL | const Y: u32 = foo(0 - 1); - | ^^^^^ evaluation of constant value failed here + | ^^^^^ evaluation of `main::Y` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/issue-49296.stderr b/tests/ui/consts/const-eval/issue-49296.stderr index 4a66ec6c940..9da3e3d6d30 100644 --- a/tests/ui/consts/const-eval/issue-49296.stderr +++ b/tests/ui/consts/const-eval/issue-49296.stderr @@ -2,7 +2,7 @@ error[E0080]: memory access failed: ALLOC0 has been freed, so this pointer is da --> $DIR/issue-49296.rs:9:16 | LL | const X: u64 = *wat(42); - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `X` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr index ffff7594e3d..d2c1e4fde9c 100644 --- a/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr +++ b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr @@ -2,7 +2,7 @@ error[E0080]: `extern type` field does not have a known offset --> $DIR/issue-91827-extern-types-field-offset.rs:38:17 | LL | let field = &x.a; - | ^^^^ evaluation of constant value failed here + | ^^^^ evaluation of `OFFSET` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr b/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr index f8cf6096095..f8a6fa24a36 100644 --- a/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr +++ b/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr @@ -2,7 +2,7 @@ error[E0080]: modifying a static's initial value from another static's initializ --> $DIR/mod-static-with-const-fn.rs:14:5 | LL | *FOO.0.get() = 5; - | ^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^ evaluation of `BAR` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr index 32ae9475560..8dbb05c1572 100644 --- a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr +++ b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr @@ -2,7 +2,7 @@ error[E0080]: memory access failed: attempting to access 1 byte, but got 0x1[noa --> $DIR/nonnull_as_ref_ub.rs:4:29 | LL | const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/panic-assoc-never-type.stderr b/tests/ui/consts/const-eval/panic-assoc-never-type.stderr index 64c9f92d5ee..d3a29314928 100644 --- a/tests/ui/consts/const-eval/panic-assoc-never-type.stderr +++ b/tests/ui/consts/const-eval/panic-assoc-never-type.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/panic-assoc-never-type.rs:10:21 | LL | const VOID: ! = panic!(); - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `PrintName::VOID` failed here note: erroneous constant encountered --> $DIR/panic-assoc-never-type.rs:15:13 diff --git a/tests/ui/consts/const-eval/panic-never-type.stderr b/tests/ui/consts/const-eval/panic-never-type.stderr index cacce93babe..317be64205e 100644 --- a/tests/ui/consts/const-eval/panic-never-type.stderr +++ b/tests/ui/consts/const-eval/panic-never-type.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/panic-never-type.rs:4:17 | LL | const VOID: ! = panic!(); - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `VOID` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/parse_ints.stderr b/tests/ui/consts/const-eval/parse_ints.stderr index 99aad805a2d..7e529c03725 100644 --- a/tests/ui/consts/const-eval/parse_ints.stderr +++ b/tests/ui/consts/const-eval/parse_ints.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: from_ascii_radix: radix must lie in the range --> $DIR/parse_ints.rs:5:24 | LL | const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_TOO_LOW` failed inside this call | note: inside `core::num::::from_str_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL @@ -14,7 +14,7 @@ error[E0080]: evaluation panicked: from_ascii_radix: radix must lie in the range --> $DIR/parse_ints.rs:6:25 | LL | const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_TOO_HIGH` failed inside this call | note: inside `core::num::::from_str_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL diff --git a/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr b/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr index 4d514495e73..6ef1cfd35c8 100644 --- a/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr +++ b/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr @@ -2,7 +2,7 @@ error[E0080]: unable to overwrite parts of a pointer in memory at ALLOC0 --> $DIR/partial_ptr_overwrite.rs:7:9 | LL | *(ptr as *mut u8) = 123; - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `PARTIAL_OVERWRITE` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs index c8d1e36e88b..df7bc2fe4fb 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.rs +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -1,14 +1,14 @@ const MISALIGNED_LOAD: () = unsafe { let mem = [0u32; 8]; let ptr = mem.as_ptr().byte_add(1); - let _val = *ptr; //~NOTE: evaluation of constant value failed + let _val = *ptr; //~NOTE: failed here //~^ERROR: based on pointer with alignment 1, but alignment 4 is required }; const MISALIGNED_STORE: () = unsafe { let mut mem = [0u32; 8]; let ptr = mem.as_mut_ptr().byte_add(1); - *ptr = 0; //~NOTE: evaluation of constant value failed + *ptr = 0; //~NOTE: failed here //~^ERROR: based on pointer with alignment 1, but alignment 4 is required }; @@ -17,7 +17,7 @@ const MISALIGNED_COPY: () = unsafe { let y = x.as_ptr().cast::(); let mut z = 123; y.copy_to_nonoverlapping(&mut z, 1); - //~^ NOTE evaluation of constant value failed + //~^ NOTE failed inside this call //~| NOTE inside `std::ptr::copy_nonoverlapping::` //~| ERROR accessing memory with alignment 1, but alignment 4 is required // The actual error points into the implementation of `copy_to_nonoverlapping`. @@ -30,14 +30,14 @@ const MISALIGNED_FIELD: () = unsafe { let mem = [0f32; 8]; let ptr = mem.as_ptr().cast::(); // Accessing an f32 field but we still require the alignment of the pointer type. - let _val = (*ptr).0; //~NOTE: evaluation of constant value failed + let _val = (*ptr).0; //~NOTE: failed here //~^ERROR: based on pointer with alignment 4, but alignment 16 is required }; const OOB: () = unsafe { let mem = [0u32; 1]; let ptr = mem.as_ptr().cast::(); - let _val = *ptr; //~NOTE: evaluation of constant value failed + let _val = *ptr; //~NOTE: failed here //~^ERROR: is only 4 bytes from the end of the allocation }; diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr index e424924e14b..00af20a722d 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -2,19 +2,19 @@ error[E0080]: accessing memory based on pointer with alignment 1, but alignment --> $DIR/raw-pointer-ub.rs:4:16 | LL | let _val = *ptr; - | ^^^^ evaluation of constant value failed here + | ^^^^ evaluation of `MISALIGNED_LOAD` failed here error[E0080]: accessing memory based on pointer with alignment 1, but alignment 4 is required --> $DIR/raw-pointer-ub.rs:11:5 | LL | *ptr = 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `MISALIGNED_STORE` failed here error[E0080]: accessing memory with alignment 1, but alignment 4 is required --> $DIR/raw-pointer-ub.rs:19:5 | LL | y.copy_to_nonoverlapping(&mut z, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `MISALIGNED_COPY` failed inside this call | note: inside `std::ptr::copy_nonoverlapping::` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -23,13 +23,13 @@ error[E0080]: accessing memory based on pointer with alignment 4, but alignment --> $DIR/raw-pointer-ub.rs:33:16 | LL | let _val = (*ptr).0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `MISALIGNED_FIELD` failed here error[E0080]: memory access failed: attempting to access 8 bytes, but got ALLOC0 which is only 4 bytes from the end of the allocation --> $DIR/raw-pointer-ub.rs:40:16 | LL | let _val = *ptr; - | ^^^^ evaluation of constant value failed here + | ^^^^ evaluation of `OOB` failed here error: aborting due to 5 previous errors diff --git a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr index be86541434b..e435a1ed7ec 100644 --- a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr +++ b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ref_to_int_match.rs:24:27 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `BAR` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr index be86541434b..e435a1ed7ec 100644 --- a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr +++ b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ref_to_int_match.rs:24:27 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `BAR` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/shift_overflow.stderr b/tests/ui/consts/const-eval/shift_overflow.stderr index e5703fb1d77..8c32ddb5908 100644 --- a/tests/ui/consts/const-eval/shift_overflow.stderr +++ b/tests/ui/consts/const-eval/shift_overflow.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to shift left by `4294967296_u64`, which would overflow --> $DIR/shift_overflow.rs:3:9 | LL | X = 1 << ((u32::MAX as u64) + 1), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Foo::X::{constant#0}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/transmute-size-mismatch.rs b/tests/ui/consts/const-eval/transmute-size-mismatch.rs index ea5cdceda88..15b69af14e9 100644 --- a/tests/ui/consts/const-eval/transmute-size-mismatch.rs +++ b/tests/ui/consts/const-eval/transmute-size-mismatch.rs @@ -19,10 +19,10 @@ const unsafe fn mir_transmute(x: T) -> U { } } -const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) }; //~ NOTE evaluation of constant value failed +const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) }; //~ NOTE failed inside this call //~^ ERROR transmuting from 4-byte type to 2-byte type: `i32` -> `u16` -const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) }; //~ NOTE evaluation of constant value failed +const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) }; //~ NOTE failed inside this call //~^ ERROR transmuting from 2-byte type to 4-byte type: `i16` -> `u32` fn main() {} diff --git a/tests/ui/consts/const-eval/transmute-size-mismatch.stderr b/tests/ui/consts/const-eval/transmute-size-mismatch.stderr index 92088a4749a..d0457e3ebee 100644 --- a/tests/ui/consts/const-eval/transmute-size-mismatch.stderr +++ b/tests/ui/consts/const-eval/transmute-size-mismatch.stderr @@ -2,7 +2,7 @@ error[E0080]: transmuting from 4-byte type to 2-byte type: `i32` -> `u16` --> $DIR/transmute-size-mismatch.rs:22:35 | LL | const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `FROM_BIGGER` failed inside this call | note: inside `mir_transmute::` --> $DIR/transmute-size-mismatch.rs:12:13 @@ -14,7 +14,7 @@ error[E0080]: transmuting from 2-byte type to 4-byte type: `i16` -> `u32` --> $DIR/transmute-size-mismatch.rs:25:36 | LL | const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) }; - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `FROM_SMALLER` failed inside this call | note: inside `mir_transmute::` --> $DIR/transmute-size-mismatch.rs:12:13 diff --git a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr index 0c1a606904c..52af52d3236 100644 --- a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr +++ b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr @@ -2,7 +2,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/ub-enum-overwrite.rs:11:14 | LL | unsafe { *p } - | ^^ evaluation of constant value failed here + | ^^ evaluation of `_` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/ub-enum.stderr b/tests/ui/consts/const-eval/ub-enum.stderr index 7015102a50a..29f7a1f051a 100644 --- a/tests/ui/consts/const-eval/ub-enum.stderr +++ b/tests/ui/consts/const-eval/ub-enum.stderr @@ -13,7 +13,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-enum.rs:32:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM_PTR` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -22,7 +22,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-enum.rs:35:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM_WRAPPED` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -42,7 +42,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-enum.rs:49:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM2_PTR` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -51,7 +51,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-enum.rs:52:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM2_WRAPPED` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -60,13 +60,13 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/ub-enum.rs:61:41 | LL | const BAD_ENUM2_UNDEF: Enum2 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM2_UNDEF` failed here error[E0080]: unable to turn pointer into integer --> $DIR/ub-enum.rs:65:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM2_OPTION_PTR` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -108,19 +108,19 @@ error[E0080]: constructing invalid value at .: encountered an uninhabi --> $DIR/ub-enum.rs:97:77 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_UNINHABITED_WITH_DATA1` failed here error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant --> $DIR/ub-enum.rs:99:77 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_UNINHABITED_WITH_DATA2` failed here error[E0080]: read discriminant of an uninhabited enum variant --> $DIR/ub-enum.rs:105:9 | LL | std::mem::discriminant(&*(&() as *const () as *const Never)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `TEST_ICE_89765` failed inside this call | note: inside `discriminant::` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/consts/const-eval/ub-invalid-values.rs b/tests/ui/consts/const-eval/ub-invalid-values.rs index e5d387fa7cc..8c47b1119f4 100644 --- a/tests/ui/consts/const-eval/ub-invalid-values.rs +++ b/tests/ui/consts/const-eval/ub-invalid-values.rs @@ -5,7 +5,7 @@ const fn bool_cast(ptr: *const bool) { unsafe { const _: () = { let v = 3_u8; - bool_cast(&v as *const u8 as *const bool); //~ NOTE: evaluation of constant value failed + bool_cast(&v as *const u8 as *const bool); //~ NOTE: failed inside this call //~^ ERROR interpreting an invalid 8-bit value as a bool }; diff --git a/tests/ui/consts/const-eval/ub-invalid-values.stderr b/tests/ui/consts/const-eval/ub-invalid-values.stderr index 83879eeb716..3a3b9bc16b8 100644 --- a/tests/ui/consts/const-eval/ub-invalid-values.stderr +++ b/tests/ui/consts/const-eval/ub-invalid-values.stderr @@ -2,7 +2,7 @@ error[E0080]: interpreting an invalid 8-bit value as a bool: 0x03 --> $DIR/ub-invalid-values.rs:8:5 | LL | bool_cast(&v as *const u8 as *const bool); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed inside this call | note: inside `bool_cast` --> $DIR/ub-invalid-values.rs:2:16 diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index 0a02dbb16bf..314141e4837 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -13,7 +13,7 @@ error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer --> $DIR/ub-nonnull.rs:22:29 | LL | let out_of_bounds_ptr = &ptr[255]; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `OUT_OF_BOUNDS_PTR` failed here error[E0080]: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 --> $DIR/ub-nonnull.rs:26:1 @@ -41,7 +41,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/ub-nonnull.rs:36:38 | LL | const UNINIT: NonZero = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT` failed here error[E0080]: constructing invalid value: encountered 42, but expected something in the range 10..=30 --> $DIR/ub-nonnull.rs:44:1 diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index e10f21b02af..d5ccc396b90 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -46,7 +46,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-ref-ptr.rs:33:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -55,7 +55,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-ref-ptr.rs:36:39 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE_SLICE` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -70,7 +70,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-ref-ptr.rs:39:86 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE_BOX_SLICE` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -107,7 +107,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/ub-ref-ptr.rs:48:41 | LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_PTR` failed here error[E0080]: constructing invalid value: encountered null pointer, but expected a function pointer --> $DIR/ub-ref-ptr.rs:51:1 @@ -124,7 +124,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/ub-ref-ptr.rs:53:38 | LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_FN_PTR` failed here error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected a function pointer --> $DIR/ub-ref-ptr.rs:55:1 @@ -152,7 +152,7 @@ error[E0080]: accessing memory based on pointer with alignment 1, but alignment --> $DIR/ub-ref-ptr.rs:64:5 | LL | ptr.read(); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `UNALIGNED_READ` failed here error: aborting due to 15 previous errors diff --git a/tests/ui/consts/const-eval/ub-uninhabit.stderr b/tests/ui/consts/const-eval/ub-uninhabit.stderr index 582a7a07be9..b0f475fe938 100644 --- a/tests/ui/consts/const-eval/ub-uninhabit.stderr +++ b/tests/ui/consts/const-eval/ub-uninhabit.stderr @@ -2,7 +2,7 @@ error[E0080]: constructing invalid value: encountered a value of uninhabited typ --> $DIR/ub-uninhabit.rs:20:35 | LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_BAD_BAD` failed here error[E0080]: constructing invalid value: encountered a reference pointing to uninhabited type Bar --> $DIR/ub-uninhabit.rs:23:1 @@ -19,13 +19,13 @@ error[E0080]: constructing invalid value at [0]: encountered a value of uninhabi --> $DIR/ub-uninhabit.rs:26:42 | LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_BAD_ARRAY` failed here error[E0080]: constructing invalid value: encountered a value of the never type `!` --> $DIR/ub-uninhabit.rs:32:16 | LL | let _val = intrinsics::read_via_copy(ptr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `READ_NEVER` failed here error: aborting due to 4 previous errors diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index a586f154ca1..8724dd9a3c0 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -24,7 +24,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-wide-ptr.rs:44:1 | LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `STR_LENGTH_PTR` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -33,7 +33,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-wide-ptr.rs:47:1 | LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `MY_STR_LENGTH_PTR` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -75,7 +75,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/ub-wide-ptr.rs:63:1 | LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SLICE_LENGTH_UNINIT` failed here error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/ub-wide-ptr.rs:69:1 @@ -103,7 +103,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-wide-ptr.rs:75:1 | LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SLICE_LENGTH_PTR` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -123,7 +123,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/ub-wide-ptr.rs:81:1 | LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SLICE_LENGTH_PTR_BOX` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -183,7 +183,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/ub-wide-ptr.rs:101:1 | LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_SLICE_LENGTH_UNINIT` failed here error[E0080]: constructing invalid value at .0: encountered ALLOC12, but expected a vtable pointer --> $DIR/ub-wide-ptr.rs:109:1 diff --git a/tests/ui/consts/const-eval/ub-write-through-immutable.stderr b/tests/ui/consts/const-eval/ub-write-through-immutable.stderr index dbcd07110cc..13b2585d4dc 100644 --- a/tests/ui/consts/const-eval/ub-write-through-immutable.stderr +++ b/tests/ui/consts/const-eval/ub-write-through-immutable.stderr @@ -2,13 +2,13 @@ error[E0080]: writing through a pointer that was derived from a shared (immutabl --> $DIR/ub-write-through-immutable.rs:10:5 | LL | *ptr = 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `WRITE_AFTER_CAST` failed here error[E0080]: writing through a pointer that was derived from a shared (immutable) reference --> $DIR/ub-write-through-immutable.rs:16:5 | LL | *ptr = 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `WRITE_AFTER_TRANSMUTE` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/union-const-eval-field.stderr b/tests/ui/consts/const-eval/union-const-eval-field.stderr index eb3906a4ecc..07ff4c3ca36 100644 --- a/tests/ui/consts/const-eval/union-const-eval-field.stderr +++ b/tests/ui/consts/const-eval/union-const-eval-field.stderr @@ -2,7 +2,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/union-const-eval-field.rs:28:37 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `read_field3::FIELD3` failed here note: erroneous constant encountered --> $DIR/union-const-eval-field.rs:30:5 diff --git a/tests/ui/consts/const-eval/union-ice.stderr b/tests/ui/consts/const-eval/union-ice.stderr index 86c42713095..b00fcc91d68 100644 --- a/tests/ui/consts/const-eval/union-ice.stderr +++ b/tests/ui/consts/const-eval/union-ice.stderr @@ -2,19 +2,19 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/union-ice.rs:14:33 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `FIELD3` failed here error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/union-ice.rs:19:17 | LL | b: unsafe { UNION.field3 }, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `FIELD_PATH` failed here error[E0080]: using uninitialized data, but this operation requires initialized memory --> $DIR/union-ice.rs:31:18 | LL | unsafe { UNION.field3 }, - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `FIELD_PATH2` failed here error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const-eval/union-ub.32bit.stderr b/tests/ui/consts/const-eval/union-ub.32bit.stderr index 7b263c20d33..9f0697984e4 100644 --- a/tests/ui/consts/const-eval/union-ub.32bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.32bit.stderr @@ -13,7 +13,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/union-ub.rs:35:36 | LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_BOOL` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/union-ub.64bit.stderr b/tests/ui/consts/const-eval/union-ub.64bit.stderr index 7b263c20d33..9f0697984e4 100644 --- a/tests/ui/consts/const-eval/union-ub.64bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.64bit.stderr @@ -13,7 +13,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/union-ub.rs:35:36 | LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_BOOL` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/unused-broken-const.stderr b/tests/ui/consts/const-eval/unused-broken-const.stderr index 5745539cb56..57bce6ce650 100644 --- a/tests/ui/consts/const-eval/unused-broken-const.stderr +++ b/tests/ui/consts/const-eval/unused-broken-const.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 0 but the index is 0 --> $DIR/unused-broken-const.rs:5:18 | LL | const FOO: i32 = [][0]; - | ^^^^^ evaluation of constant value failed here + | ^^^^^ evaluation of `FOO` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/unwind-abort.stderr b/tests/ui/consts/const-eval/unwind-abort.stderr index 94cf3acec45..cccfe569acb 100644 --- a/tests/ui/consts/const-eval/unwind-abort.stderr +++ b/tests/ui/consts/const-eval/unwind-abort.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/unwind-abort.rs:7:15 | LL | const _: () = foo(); - | ^^^^^ evaluation of constant value failed here + | ^^^^^ evaluation of `_` failed inside this call | note: inside `foo` --> $DIR/unwind-abort.rs:4:5 diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr index 4557b392907..848c65f4764 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr @@ -2,7 +2,7 @@ error[E0080]: constructing invalid value: encountered a value of the never type --> $DIR/validate_uninhabited_zsts.rs:17:33 | LL | const FOO: [empty::Empty; 3] = [foo(); 3]; - | ^^^^^ evaluation of constant value failed here + | ^^^^^ evaluation of `FOO` failed inside this call | note: inside `foo` --> $DIR/validate_uninhabited_zsts.rs:4:14 @@ -14,7 +14,7 @@ error[E0080]: constructing invalid value at .0: encountered a value of uninhabit --> $DIR/validate_uninhabited_zsts.rs:20:42 | LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAR` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr b/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr index 08d791f4953..61087392b76 100644 --- a/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr +++ b/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr @@ -2,7 +2,7 @@ error[E0080]: `extern type` field does not have a known offset --> $DIR/validation-ice-extern-type-field.rs:12:1 | LL | const C1: &ThinDst = unsafe { std::mem::transmute(b"d".as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `C1` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-external-macro-const-err.stderr b/tests/ui/consts/const-external-macro-const-err.stderr index 7cd646b1c45..3ec9e4f3200 100644 --- a/tests/ui/consts/const-external-macro-const-err.stderr +++ b/tests/ui/consts/const-external-macro-const-err.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 1 but the index is 1 --> $DIR/const-external-macro-const-err.rs:12:5 | LL | static_assert!(2 + 2 == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::_` failed here | = note: this error originates in the macro `static_assert` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/const-int-unchecked.stderr b/tests/ui/consts/const-int-unchecked.stderr index 20c109b9265..65a116295c7 100644 --- a/tests/ui/consts/const-int-unchecked.stderr +++ b/tests/ui/consts/const-int-unchecked.stderr @@ -2,295 +2,295 @@ error[E0080]: overflowing shift by 8 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:14:29 | LL | const SHL_U8: u8 = unsafe { intrinsics::unchecked_shl(5_u8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_U8` failed here error[E0080]: overflowing shift by 16 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:16:31 | LL | const SHL_U16: u16 = unsafe { intrinsics::unchecked_shl(5_u16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_U16` failed here error[E0080]: overflowing shift by 32 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:18:31 | LL | const SHL_U32: u32 = unsafe { intrinsics::unchecked_shl(5_u32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_U32` failed here error[E0080]: overflowing shift by 64 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:20:31 | LL | const SHL_U64: u64 = unsafe { intrinsics::unchecked_shl(5_u64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_U64` failed here error[E0080]: overflowing shift by 128 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:22:33 | LL | const SHL_U128: u128 = unsafe { intrinsics::unchecked_shl(5_u128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_U128` failed here error[E0080]: overflowing shift by 8 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:27:29 | LL | const SHL_I8: i8 = unsafe { intrinsics::unchecked_shl(5_i8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I8` failed here error[E0080]: overflowing shift by 16 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:29:31 | LL | const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_i16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I16` failed here error[E0080]: overflowing shift by 32 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:31:31 | LL | const SHL_I32: i32 = unsafe { intrinsics::unchecked_shl(5_i32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I32` failed here error[E0080]: overflowing shift by 64 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:33:31 | LL | const SHL_I64: i64 = unsafe { intrinsics::unchecked_shl(5_i64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I64` failed here error[E0080]: overflowing shift by 128 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:35:33 | LL | const SHL_I128: i128 = unsafe { intrinsics::unchecked_shl(5_i128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I128` failed here error[E0080]: overflowing shift by -1 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:40:33 | LL | const SHL_I8_NEG: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I8_NEG` failed here error[E0080]: overflowing shift by -1 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:42:35 | LL | const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I16_NEG` failed here error[E0080]: overflowing shift by -1 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:44:35 | LL | const SHL_I32_NEG: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I32_NEG` failed here error[E0080]: overflowing shift by -1 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:46:35 | LL | const SHL_I64_NEG: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I64_NEG` failed here error[E0080]: overflowing shift by -1 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:48:37 | LL | const SHL_I128_NEG: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I128_NEG` failed here error[E0080]: overflowing shift by -6 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:54:40 | LL | const SHL_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -6) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I8_NEG_RANDOM` failed here error[E0080]: overflowing shift by -13 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:56:42 | LL | const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_i16, -13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I16_NEG_RANDOM` failed here error[E0080]: overflowing shift by -25 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:58:42 | LL | const SHL_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -25) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I32_NEG_RANDOM` failed here error[E0080]: overflowing shift by -30 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:60:42 | LL | const SHL_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -30) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I64_NEG_RANDOM` failed here error[E0080]: overflowing shift by -93 in `unchecked_shl` --> $DIR/const-int-unchecked.rs:62:44 | LL | const SHL_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -93) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHL_I128_NEG_RANDOM` failed here error[E0080]: overflowing shift by 8 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:69:29 | LL | const SHR_U8: u8 = unsafe { intrinsics::unchecked_shr(5_u8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_U8` failed here error[E0080]: overflowing shift by 16 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:71:31 | LL | const SHR_U16: u16 = unsafe { intrinsics::unchecked_shr(5_u16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_U16` failed here error[E0080]: overflowing shift by 32 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:73:31 | LL | const SHR_U32: u32 = unsafe { intrinsics::unchecked_shr(5_u32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_U32` failed here error[E0080]: overflowing shift by 64 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:75:31 | LL | const SHR_U64: u64 = unsafe { intrinsics::unchecked_shr(5_u64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_U64` failed here error[E0080]: overflowing shift by 128 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:77:33 | LL | const SHR_U128: u128 = unsafe { intrinsics::unchecked_shr(5_u128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_U128` failed here error[E0080]: overflowing shift by 8 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:82:29 | LL | const SHR_I8: i8 = unsafe { intrinsics::unchecked_shr(5_i8, 8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I8` failed here error[E0080]: overflowing shift by 16 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:84:31 | LL | const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_i16, 16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I16` failed here error[E0080]: overflowing shift by 32 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:86:31 | LL | const SHR_I32: i32 = unsafe { intrinsics::unchecked_shr(5_i32, 32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I32` failed here error[E0080]: overflowing shift by 64 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:88:31 | LL | const SHR_I64: i64 = unsafe { intrinsics::unchecked_shr(5_i64, 64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I64` failed here error[E0080]: overflowing shift by 128 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:90:33 | LL | const SHR_I128: i128 = unsafe { intrinsics::unchecked_shr(5_i128, 128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I128` failed here error[E0080]: overflowing shift by -1 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:95:33 | LL | const SHR_I8_NEG: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I8_NEG` failed here error[E0080]: overflowing shift by -1 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:97:35 | LL | const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I16_NEG` failed here error[E0080]: overflowing shift by -1 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:99:35 | LL | const SHR_I32_NEG: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I32_NEG` failed here error[E0080]: overflowing shift by -1 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:101:35 | LL | const SHR_I64_NEG: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I64_NEG` failed here error[E0080]: overflowing shift by -1 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:103:37 | LL | const SHR_I128_NEG: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I128_NEG` failed here error[E0080]: overflowing shift by -6 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:109:40 | LL | const SHR_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -6) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I8_NEG_RANDOM` failed here error[E0080]: overflowing shift by -13 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:111:42 | LL | const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_i16, -13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I16_NEG_RANDOM` failed here error[E0080]: overflowing shift by -25 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:113:42 | LL | const SHR_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -25) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I32_NEG_RANDOM` failed here error[E0080]: overflowing shift by -30 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:115:42 | LL | const SHR_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -30) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I64_NEG_RANDOM` failed here error[E0080]: overflowing shift by -93 in `unchecked_shr` --> $DIR/const-int-unchecked.rs:117:44 | LL | const SHR_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -93) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SHR_I128_NEG_RANDOM` failed here error[E0080]: arithmetic overflow in `unchecked_add` --> $DIR/const-int-unchecked.rs:122:25 | LL | const _: u16 = unsafe { std::intrinsics::unchecked_add(40000u16, 30000) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error[E0080]: arithmetic overflow in `unchecked_sub` --> $DIR/const-int-unchecked.rs:125:25 | LL | const _: u32 = unsafe { std::intrinsics::unchecked_sub(14u32, 22) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error[E0080]: arithmetic overflow in `unchecked_mul` --> $DIR/const-int-unchecked.rs:128:25 | LL | const _: u16 = unsafe { std::intrinsics::unchecked_mul(300u16, 250u16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error[E0080]: dividing by zero --> $DIR/const-int-unchecked.rs:131:25 | LL | const _: i32 = unsafe { std::intrinsics::unchecked_div(1, 0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error[E0080]: overflow in signed division (dividing MIN by -1) --> $DIR/const-int-unchecked.rs:133:25 | LL | const _: i32 = unsafe { std::intrinsics::unchecked_div(i32::MIN, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error[E0080]: calculating the remainder with a divisor of zero --> $DIR/const-int-unchecked.rs:136:25 | LL | const _: i32 = unsafe { std::intrinsics::unchecked_rem(1, 0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error[E0080]: overflow in signed remainder (dividing MIN by -1) --> $DIR/const-int-unchecked.rs:138:25 | LL | const _: i32 = unsafe { std::intrinsics::unchecked_rem(i32::MIN, -1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error[E0080]: `ctlz_nonzero` called on 0 --> $DIR/const-int-unchecked.rs:143:25 | LL | const _: u32 = unsafe { std::intrinsics::ctlz_nonzero(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error[E0080]: `cttz_nonzero` called on 0 --> $DIR/const-int-unchecked.rs:145:25 | LL | const _: u32 = unsafe { std::intrinsics::cttz_nonzero(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error: aborting due to 49 previous errors diff --git a/tests/ui/consts/const-len-underflow-separate-spans.next.stderr b/tests/ui/consts/const-len-underflow-separate-spans.next.stderr index 510b9cdc406..ef46522f7f5 100644 --- a/tests/ui/consts/const-len-underflow-separate-spans.next.stderr +++ b/tests/ui/consts/const-len-underflow-separate-spans.next.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `1_usize - 2_usize`, which would overflow --> $DIR/const-len-underflow-separate-spans.rs:10:20 | LL | const LEN: usize = ONE - TWO; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `LEN` failed here note: erroneous constant encountered --> $DIR/const-len-underflow-separate-spans.rs:15:17 diff --git a/tests/ui/consts/const-len-underflow-separate-spans.old.stderr b/tests/ui/consts/const-len-underflow-separate-spans.old.stderr index 510b9cdc406..ef46522f7f5 100644 --- a/tests/ui/consts/const-len-underflow-separate-spans.old.stderr +++ b/tests/ui/consts/const-len-underflow-separate-spans.old.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `1_usize - 2_usize`, which would overflow --> $DIR/const-len-underflow-separate-spans.rs:10:20 | LL | const LEN: usize = ONE - TWO; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `LEN` failed here note: erroneous constant encountered --> $DIR/const-len-underflow-separate-spans.rs:15:17 diff --git a/tests/ui/consts/const-len-underflow-separate-spans.rs b/tests/ui/consts/const-len-underflow-separate-spans.rs index a815ecaef70..ee8c79dafa7 100644 --- a/tests/ui/consts/const-len-underflow-separate-spans.rs +++ b/tests/ui/consts/const-len-underflow-separate-spans.rs @@ -8,7 +8,7 @@ const ONE: usize = 1; const TWO: usize = 2; const LEN: usize = ONE - TWO; -//~^ NOTE constant +//~^ NOTE failed here //~| ERROR attempt to compute `1_usize - 2_usize`, which would overflow fn main() { diff --git a/tests/ui/consts/const-len-underflow-subspans.stderr b/tests/ui/consts/const-len-underflow-subspans.stderr index 42d744147d6..51825a03db8 100644 --- a/tests/ui/consts/const-len-underflow-subspans.stderr +++ b/tests/ui/consts/const-len-underflow-subspans.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `1_usize - 2_usize`, which would overflow --> $DIR/const-len-underflow-subspans.rs:8:17 | LL | let a: [i8; ONE - TWO] = unimplemented!(); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `main::{constant#0}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-ptr-is-null.stderr b/tests/ui/consts/const-ptr-is-null.stderr index 9d83f8d51a7..be0a1346c64 100644 --- a/tests/ui/consts/const-ptr-is-null.stderr +++ b/tests/ui/consts/const-ptr-is-null.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: null-ness of this pointer cannot be determine --> $DIR/const-ptr-is-null.rs:22:14 | LL | assert!(!ptr.wrapping_sub(512).is_null()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `MAYBE_NULL` failed inside this call | note: inside `std::ptr::const_ptr::::is_null` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr index 714d85bb394..64b7a4129e0 100644 --- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr +++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr @@ -2,13 +2,13 @@ error[E0080]: `extern type` does not have known layout --> $DIR/const-size_of_val-align_of_val-extern-type.rs:10:31 | LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_SIZE` failed here error[E0080]: `extern type` does not have known layout --> $DIR/const-size_of_val-align_of_val-extern-type.rs:11:32 | LL | const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_ALIGN` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-slice-oob.stderr b/tests/ui/consts/const-slice-oob.stderr index d93c4783e27..9435baa0407 100644 --- a/tests/ui/consts/const-slice-oob.stderr +++ b/tests/ui/consts/const-slice-oob.stderr @@ -2,7 +2,7 @@ error[E0080]: index out of bounds: the length is 3 but the index is 5 --> $DIR/const-slice-oob.rs:2:18 | LL | const BAR: u32 = FOO[5]; - | ^^^^^^ evaluation of constant value failed here + | ^^^^^^ evaluation of `BAR` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-unwrap.stderr b/tests/ui/consts/const-unwrap.stderr index 88c9185eeb6..0b3e92d389f 100644 --- a/tests/ui/consts/const-unwrap.stderr +++ b/tests/ui/consts/const-unwrap.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation panicked: called `Option::unwrap()` on a `None` value --> $DIR/const-unwrap.rs:6:18 | LL | const BAR: i32 = Option::::None.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAR` failed here error[E0080]: evaluation panicked: absolutely not! --> $DIR/const-unwrap.rs:9:18 | LL | const BAZ: i32 = Option::::None.expect("absolutely not!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAZ` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const_refs_to_static_fail.stderr b/tests/ui/consts/const_refs_to_static_fail.stderr index 96a6593279d..86d6c11dc0c 100644 --- a/tests/ui/consts/const_refs_to_static_fail.stderr +++ b/tests/ui/consts/const_refs_to_static_fail.stderr @@ -19,7 +19,7 @@ error[E0080]: constant accesses mutable global memory --> $DIR/const_refs_to_static_fail.rs:18:13 | LL | assert!(*C2 == 0); - | ^^^ evaluation of constant value failed here + | ^^^ evaluation of `C2_READ` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const_unsafe_unreachable_ub.rs b/tests/ui/consts/const_unsafe_unreachable_ub.rs index 7c6c7a608b8..39f05395127 100644 --- a/tests/ui/consts/const_unsafe_unreachable_ub.rs +++ b/tests/ui/consts/const_unsafe_unreachable_ub.rs @@ -8,7 +8,7 @@ const unsafe fn foo(x: bool) -> bool { } const BAR: bool = unsafe { foo(false) }; -//~^ NOTE evaluation of constant value failed +//~^ NOTE failed inside this call //~| ERROR entering unreachable code fn main() { diff --git a/tests/ui/consts/const_unsafe_unreachable_ub.stderr b/tests/ui/consts/const_unsafe_unreachable_ub.stderr index 6d9f8c1d73b..7d2448cc3c6 100644 --- a/tests/ui/consts/const_unsafe_unreachable_ub.stderr +++ b/tests/ui/consts/const_unsafe_unreachable_ub.stderr @@ -2,7 +2,7 @@ error[E0080]: entering unreachable code --> $DIR/const_unsafe_unreachable_ub.rs:10:28 | LL | const BAR: bool = unsafe { foo(false) }; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `BAR` failed inside this call | note: inside `foo` --> $DIR/const_unsafe_unreachable_ub.rs:4:18 diff --git a/tests/ui/consts/control-flow/assert.stderr b/tests/ui/consts/control-flow/assert.stderr index 6b68f706f90..026097a6ba0 100644 --- a/tests/ui/consts/control-flow/assert.stderr +++ b/tests/ui/consts/control-flow/assert.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: assertion failed: false --> $DIR/assert.rs:5:15 | LL | const _: () = assert!(false); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr index b9d89cf78ba..41cf7e51357 100644 --- a/tests/ui/consts/copy-intrinsic.stderr +++ b/tests/ui/consts/copy-intrinsic.stderr @@ -2,25 +2,25 @@ error[E0080]: memory access failed: attempting to access 4 bytes, but got 0x100[ --> $DIR/copy-intrinsic.rs:20:5 | LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `COPY_OOB_1` failed here error[E0080]: memory access failed: attempting to access 4 bytes, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes --> $DIR/copy-intrinsic.rs:28:5 | LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `COPY_OOB_2` failed here error[E0080]: overflow computing total size of `copy` --> $DIR/copy-intrinsic.rs:34:5 | LL | copy(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `COPY_SIZE_OVERFLOW` failed here error[E0080]: overflow computing total size of `copy_nonoverlapping` --> $DIR/copy-intrinsic.rs:39:5 | LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `COPY_NONOVERLAPPING_SIZE_OVERFLOW` failed here error: aborting due to 4 previous errors diff --git a/tests/ui/consts/eval-enum.stderr b/tests/ui/consts/eval-enum.stderr index adfb7c79fea..d647485bc5d 100644 --- a/tests/ui/consts/eval-enum.stderr +++ b/tests/ui/consts/eval-enum.stderr @@ -2,13 +2,13 @@ error[E0080]: attempt to divide `1_isize` by zero --> $DIR/eval-enum.rs:2:15 | LL | DivZero = 1 / 0, - | ^^^^^ evaluation of constant value failed here + | ^^^^^ evaluation of `Test::DivZero::{constant#0}` failed here error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero --> $DIR/eval-enum.rs:4:15 | LL | RemZero = 1 % 0, - | ^^^^^ evaluation of constant value failed here + | ^^^^^ evaluation of `Test::RemZero::{constant#0}` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr index 0d8fd5aece9..6af72868045 100644 --- a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr @@ -2,13 +2,13 @@ error[E0080]: constructing invalid value: encountered 0x03, but expected a boole --> $DIR/detect-extra-ub.rs:30:20 | LL | let _x: bool = transmute(3u8); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `INVALID_BOOL` failed here error[E0080]: constructing invalid value: encountered a pointer, but expected an integer --> $DIR/detect-extra-ub.rs:35:21 | LL | let _x: usize = transmute(&3u8); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `INVALID_PTR_IN_INT` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -17,7 +17,7 @@ error[E0080]: constructing invalid value at .: encountered a pointer, --> $DIR/detect-extra-ub.rs:40:28 | LL | let _x: PtrSizedEnum = transmute(&3u8); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `INVALID_PTR_IN_ENUM` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .0: encountered a pointer, but expec --> $DIR/detect-extra-ub.rs:46:30 | LL | let _x: (usize, usize) = transmute(x); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `INVALID_SLICE_TO_USIZE_TRANSMUTE` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -35,19 +35,19 @@ error[E0080]: constructing invalid value: encountered an unaligned reference (re --> $DIR/detect-extra-ub.rs:51:20 | LL | let _x: &u32 = transmute(&[0u8; 4]); - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^ evaluation of `UNALIGNED_PTR` failed here error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant --> $DIR/detect-extra-ub.rs:58:13 | LL | let v = *addr_of!(data).cast::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINHABITED_VARIANT` failed here error[E0080]: constructing invalid value at [0]: encountered a partial pointer or a mix of pointers --> $DIR/detect-extra-ub.rs:77:16 | LL | let _val = *(&mem as *const Align as *const [*const u8; 2]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `PARTIAL_POINTER` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -56,7 +56,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata --> $DIR/detect-extra-ub.rs:91:16 | LL | let _val = &*slice; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `OVERSIZED_REF` failed here error: aborting due to 8 previous errors diff --git a/tests/ui/consts/issue-32829.stderr b/tests/ui/consts/issue-32829.stderr index 0a04c66df96..b02b9122cec 100644 --- a/tests/ui/consts/issue-32829.stderr +++ b/tests/ui/consts/issue-32829.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: foo --> $DIR/issue-32829.rs:1:22 | LL | static S : u64 = { { panic!("foo"); 0 } }; - | ^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^ evaluation of `S` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-64506.stderr b/tests/ui/consts/issue-64506.stderr index dfb2c454031..9fce07c5850 100644 --- a/tests/ui/consts/issue-64506.stderr +++ b/tests/ui/consts/issue-64506.stderr @@ -2,7 +2,7 @@ error[E0080]: constructing invalid value at .inner: encountered a value of uninh --> $DIR/issue-64506.rs:16:22 | LL | let x = unsafe { Foo { b: () }.a }; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `FOO` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-66693-panic-in-array-len.stderr b/tests/ui/consts/issue-66693-panic-in-array-len.stderr index e0db2138d74..241643a83be 100644 --- a/tests/ui/consts/issue-66693-panic-in-array-len.stderr +++ b/tests/ui/consts/issue-66693-panic-in-array-len.stderr @@ -8,7 +8,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-66693-panic-in-array-len.rs:10:21 | LL | let _ = [false; panic!()]; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `main::{constant#1}` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/issue-66693.stderr b/tests/ui/consts/issue-66693.stderr index 6d6edf8a513..5540d4f2d22 100644 --- a/tests/ui/consts/issue-66693.stderr +++ b/tests/ui/consts/issue-66693.stderr @@ -14,13 +14,13 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-66693.rs:16:15 | LL | const _: () = panic!(); - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_` failed here error[E0080]: evaluation panicked: panic in static --> $DIR/issue-66693.rs:18:19 | LL | static _BAR: () = panic!("panic in static"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_BAR` failed here error: argument to `panic!()` in a const context must have type `&str` --> $DIR/issue-66693.rs:11:5 diff --git a/tests/ui/consts/issue-76064.stderr b/tests/ui/consts/issue-76064.stderr index 97225178ee0..17dcb22aa1a 100644 --- a/tests/ui/consts/issue-76064.stderr +++ b/tests/ui/consts/issue-76064.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: panic --> $DIR/issue-76064.rs:1:17 | LL | struct Bug([u8; panic!("panic")]); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `Bug::0::{constant#0}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-miri-1910.stderr b/tests/ui/consts/issue-miri-1910.stderr index 8166b68d2e0..140b1861bb4 100644 --- a/tests/ui/consts/issue-miri-1910.stderr +++ b/tests/ui/consts/issue-miri-1910.stderr @@ -2,7 +2,7 @@ error[E0080]: unable to turn pointer into integer --> $DIR/issue-miri-1910.rs:7:5 | LL | (&foo as *const _ as *const u8).add(one_and_a_half_pointers).read(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `C` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/large_const_alloc.stderr b/tests/ui/consts/large_const_alloc.stderr index 8f19def22e7..a0b21555608 100644 --- a/tests/ui/consts/large_const_alloc.stderr +++ b/tests/ui/consts/large_const_alloc.stderr @@ -2,13 +2,13 @@ error[E0080]: tried to allocate more memory than available to compiler --> $DIR/large_const_alloc.rs:11:13 | LL | let x = [0_u8; (1 << 47) - 1]; - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `FOO` failed here error[E0080]: tried to allocate more memory than available to compiler --> $DIR/large_const_alloc.rs:16:13 | LL | let x = [0_u8; (1 << 47) - 1]; - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `FOO2` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.rs b/tests/ui/consts/miri_unleashed/abi-mismatch.rs index 91115f8511d..843de1e63c6 100644 --- a/tests/ui/consts/miri_unleashed/abi-mismatch.rs +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.rs @@ -9,7 +9,7 @@ const fn call_rust_fn(my_fn: extern "Rust" fn()) { } static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); -//~^ NOTE evaluation of static initializer failed here +//~^ NOTE failed inside this call //~| ERROR calling a function with calling convention "C" using calling convention "Rust" fn main() {} diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.stderr b/tests/ui/consts/miri_unleashed/abi-mismatch.stderr index 6cd2a0b4bc5..4576eed2c88 100644 --- a/tests/ui/consts/miri_unleashed/abi-mismatch.stderr +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.stderr @@ -2,7 +2,7 @@ error[E0080]: calling a function with calling convention "C" using calling conve --> $DIR/abi-mismatch.rs:11:18 | LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `VAL` failed inside this call | note: inside `call_rust_fn` --> $DIR/abi-mismatch.rs:7:5 diff --git a/tests/ui/consts/miri_unleashed/assoc_const.stderr b/tests/ui/consts/miri_unleashed/assoc_const.stderr index e843615bd6d..1ba4f3b2896 100644 --- a/tests/ui/consts/miri_unleashed/assoc_const.stderr +++ b/tests/ui/consts/miri_unleashed/assoc_const.stderr @@ -2,7 +2,7 @@ error[E0080]: calling non-const function ` as Drop>::drop` --> $DIR/assoc_const.rs:12:31 | LL | const F: u32 = (U::X, 42).1; - | ^ evaluation of `, std::string::String>>::F` failed here + | ^ evaluation of `, std::string::String>>::F` failed inside this call | note: inside `drop_in_place::<(Vec, u32)> - shim(Some((Vec, u32)))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/miri_unleashed/box.stderr b/tests/ui/consts/miri_unleashed/box.stderr index d6ceeebf87f..25b717660ea 100644 --- a/tests/ui/consts/miri_unleashed/box.stderr +++ b/tests/ui/consts/miri_unleashed/box.stderr @@ -2,7 +2,7 @@ error[E0080]: calling non-const function `Box::::new` --> $DIR/box.rs:8:11 | LL | &mut *(Box::new(0)) - | ^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^ evaluation of `TEST_BAD` failed here warning: skipping const checks | diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr index f0161988b76..eed3b4d9065 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr @@ -2,19 +2,19 @@ error[E0080]: calling non-const function `AtomicUsize::fetch_add` --> $DIR/const_refers_to_static.rs:11:5 | LL | FOO.fetch_add(1, Ordering::Relaxed) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `MUTATE_INTERIOR_MUT` failed here error[E0080]: constant accesses mutable global memory --> $DIR/const_refers_to_static.rs:16:14 | LL | unsafe { *(&FOO as *const _ as *const usize) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `READ_INTERIOR_MUT` failed here error[E0080]: constant accesses mutable global memory --> $DIR/const_refers_to_static.rs:20:32 | LL | const READ_MUT: u32 = unsafe { MUTABLE }; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `READ_MUT` failed here error[E0080]: constructing invalid value: encountered reference to mutable memory in `const` --> $DIR/const_refers_to_static.rs:23:1 diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr index 8c176d562ee..8af3a1948f0 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr @@ -35,7 +35,7 @@ error[E0080]: constant accesses mutable global memory --> $DIR/const_refers_to_static_cross_crate.rs:30:15 | LL | match static_cross_crate::OPT_ZERO { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `U8_MUT3` failed here error: aborting due to 4 previous errors diff --git a/tests/ui/consts/miri_unleashed/drop.rs b/tests/ui/consts/miri_unleashed/drop.rs index 6921ffa4f94..46af3388a96 100644 --- a/tests/ui/consts/miri_unleashed/drop.rs +++ b/tests/ui/consts/miri_unleashed/drop.rs @@ -13,7 +13,7 @@ static TEST_OK: () = { // The actual error is tested by the error-pattern above. static TEST_BAD: () = { let _v: Vec = Vec::new(); -}; //~ NOTE evaluation of static initializer failed here +}; //~ NOTE failed inside this call //~| ERROR calling non-const function ` as Drop>::drop` //~| NOTE inside `drop_in_place::> - shim(Some(Vec))` diff --git a/tests/ui/consts/miri_unleashed/drop.stderr b/tests/ui/consts/miri_unleashed/drop.stderr index f0a776d8702..a66422956be 100644 --- a/tests/ui/consts/miri_unleashed/drop.stderr +++ b/tests/ui/consts/miri_unleashed/drop.stderr @@ -2,7 +2,7 @@ error[E0080]: calling non-const function ` as Drop>::drop` --> $DIR/drop.rs:16:1 | LL | }; - | ^ evaluation of static initializer failed here + | ^ evaluation of `TEST_BAD` failed inside this call | note: inside `drop_in_place::> - shim(Some(Vec))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/miri_unleashed/extern-static.stderr b/tests/ui/consts/miri_unleashed/extern-static.stderr index a1e4be5bd9c..57b4f07b2fc 100644 --- a/tests/ui/consts/miri_unleashed/extern-static.stderr +++ b/tests/ui/consts/miri_unleashed/extern-static.stderr @@ -2,13 +2,13 @@ error[E0080]: cannot access extern static `DATA` --> $DIR/extern-static.rs:11:25 | LL | unsafe { let _val = DATA; } - | ^^^^ evaluation of static initializer failed here + | ^^^^ evaluation of `TEST_READ` failed here error[E0080]: cannot access extern static `DATA` --> $DIR/extern-static.rs:15:14 | LL | unsafe { DATA = 0; } - | ^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^ evaluation of `TEST_WRITE` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/miri_unleashed/inline_asm.stderr b/tests/ui/consts/miri_unleashed/inline_asm.stderr index 2f9d2dc2143..49e54825695 100644 --- a/tests/ui/consts/miri_unleashed/inline_asm.stderr +++ b/tests/ui/consts/miri_unleashed/inline_asm.stderr @@ -2,7 +2,7 @@ error[E0080]: inline assembly is not supported --> $DIR/inline_asm.rs:10:14 | LL | unsafe { asm!("nop"); } - | ^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^ evaluation of `TEST_BAD` failed here warning: skipping const checks | diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr index aaea7bda332..22860e4f6d9 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references.stderr @@ -113,7 +113,7 @@ error[E0080]: constant accesses mutable global memory --> $DIR/mutable_references.rs:70:43 | LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `POINTS_TO_MUTABLE2` failed here error: encountered mutable pointer in final value of constant --> $DIR/mutable_references.rs:73:1 diff --git a/tests/ui/consts/miri_unleashed/mutating_global.stderr b/tests/ui/consts/miri_unleashed/mutating_global.stderr index 706bc8e5d23..f97f88a4b90 100644 --- a/tests/ui/consts/miri_unleashed/mutating_global.stderr +++ b/tests/ui/consts/miri_unleashed/mutating_global.stderr @@ -2,7 +2,7 @@ error[E0080]: modifying a static's initial value from another static's initializ --> $DIR/mutating_global.rs:9:9 | LL | GLOBAL = 99 - | ^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^ evaluation of `MUTATING_GLOBAL` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/miri_unleashed/non_const_fn.stderr b/tests/ui/consts/miri_unleashed/non_const_fn.stderr index f490e51f546..7755183cef0 100644 --- a/tests/ui/consts/miri_unleashed/non_const_fn.stderr +++ b/tests/ui/consts/miri_unleashed/non_const_fn.stderr @@ -2,7 +2,7 @@ error[E0080]: calling non-const function `foo` --> $DIR/non_const_fn.rs:7:16 | LL | static C: () = foo(); - | ^^^^^ evaluation of static initializer failed here + | ^^^^^ evaluation of `C` failed here warning: skipping const checks | diff --git a/tests/ui/consts/miri_unleashed/ptr_arith.stderr b/tests/ui/consts/miri_unleashed/ptr_arith.stderr index 280c76c42c1..661a8de6a15 100644 --- a/tests/ui/consts/miri_unleashed/ptr_arith.stderr +++ b/tests/ui/consts/miri_unleashed/ptr_arith.stderr @@ -2,13 +2,13 @@ error[E0080]: exposing pointers is not possible at compile-time --> $DIR/ptr_arith.rs:7:13 | LL | let x = &0 as *const _ as usize; - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `PTR_INT_CAST` failed here error[E0080]: unable to turn pointer into integer --> $DIR/ptr_arith.rs:14:14 | LL | let _v = x + 0; - | ^ evaluation of static initializer failed here + | ^ evaluation of `PTR_INT_TRANSMUTE` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/miri_unleashed/tls.stderr b/tests/ui/consts/miri_unleashed/tls.stderr index cdfe8bfff4e..08e069dc3ff 100644 --- a/tests/ui/consts/miri_unleashed/tls.stderr +++ b/tests/ui/consts/miri_unleashed/tls.stderr @@ -2,13 +2,13 @@ error[E0080]: cannot access thread local static `A` --> $DIR/tls.rs:11:25 | LL | unsafe { let _val = A; } - | ^ evaluation of static initializer failed here + | ^ evaluation of `TEST_BAD` failed here error[E0080]: cannot access thread local static `A` --> $DIR/tls.rs:19:26 | LL | unsafe { let _val = &A; } - | ^ evaluation of static initializer failed here + | ^ evaluation of `TEST_BAD_REF` failed here warning: skipping const checks | diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr index 5ba5e34b4c1..de4acbffa28 100644 --- a/tests/ui/consts/missing_span_in_backtrace.stderr +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -6,7 +6,7 @@ error[E0080]: unable to copy parts of a pointer from memory at ALLOC0 16 | | &mut ptr2 as *mut _ as *mut MaybeUninit, 17 | | mem::size_of::<&i32>(), 18 | | ); - | |_________^ evaluation of constant value failed here + | |_________^ evaluation of `X` failed inside this call | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr b/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr index 318082f5452..210bb345e7b 100644 --- a/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr +++ b/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr @@ -2,7 +2,7 @@ error[E0080]: constant accesses mutable global memory --> $DIR/no-ice-from-static-in-const-issue-52060.rs:5:35 | LL | static B: [u32; 1] = [0; unsafe { A.len() }]; - | ^ evaluation of constant value failed here + | ^ evaluation of `B::{constant#1}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr index 842698e239d..558e1ea02c6 100644 --- a/tests/ui/consts/offset_from_ub.stderr +++ b/tests/ui/consts/offset_from_ub.stderr @@ -2,13 +2,13 @@ error[E0080]: `ptr_offset_from` called on two different pointers that are not bo --> $DIR/offset_from_ub.rs:20:27 | LL | let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `DIFFERENT_ALLOC` failed here error[E0080]: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation --> $DIR/offset_from_ub.rs:26:14 | LL | unsafe { (42 as *const u8).offset_from(&5u8) as usize } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NOT_PTR` failed inside this call | note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -17,67 +17,67 @@ error[E0080]: exact_div: 1_isize cannot be divided by 2_isize without remainder --> $DIR/offset_from_ub.rs:34:14 | LL | unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NOT_MULTIPLE_OF_SIZE` failed here error[E0080]: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation --> $DIR/offset_from_ub.rs:42:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `DIFFERENT_INT` failed here error[E0080]: `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation --> $DIR/offset_from_ub.rs:51:14 | LL | unsafe { ptr_offset_from(end_ptr, start_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `OUT_OF_BOUNDS_1` failed here error[E0080]: `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation --> $DIR/offset_from_ub.rs:60:14 | LL | unsafe { ptr_offset_from(start_ptr, end_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `OUT_OF_BOUNDS_2` failed here error[E0080]: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation --> $DIR/offset_from_ub.rs:69:14 | LL | unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `DIFFERENT_ALLOC_UNSIGNED` failed here error[E0080]: `ptr_offset_from` called when first pointer is too far ahead of second --> $DIR/offset_from_ub.rs:76:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `TOO_FAR_APART1` failed here error[E0080]: `ptr_offset_from` called when first pointer is too far before second --> $DIR/offset_from_ub.rs:82:14 | LL | unsafe { ptr_offset_from(ptr1, ptr2) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `TOO_FAR_APART2` failed here error[E0080]: `ptr_offset_from` called when first pointer is too far before second --> $DIR/offset_from_ub.rs:90:14 | LL | unsafe { ptr_offset_from(ptr1, ptr2) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `TOO_FAR_APART3` failed here error[E0080]: `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8 --> $DIR/offset_from_ub.rs:97:14 | LL | unsafe { ptr_offset_from_unsigned(p, p.add(2)) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `WRONG_ORDER_UNSIGNED` failed here error[E0080]: `ptr_offset_from_unsigned` called when first pointer is too far ahead of second --> $DIR/offset_from_ub.rs:104:14 | LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `TOO_FAR_APART_UNSIGNED` failed here error[E0080]: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation --> $DIR/offset_from_ub.rs:112:14 | LL | unsafe { ptr2.offset_from(ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `OFFSET_VERY_FAR1` failed inside this call | note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -86,7 +86,7 @@ error[E0080]: `ptr_offset_from` called when first pointer is too far before seco --> $DIR/offset_from_ub.rs:118:14 | LL | unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `OFFSET_VERY_FAR2` failed inside this call | note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr index 4135804da20..255583ce91c 100644 --- a/tests/ui/consts/offset_ub.stderr +++ b/tests/ui/consts/offset_ub.stderr @@ -2,67 +2,67 @@ error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer --> $DIR/offset_ub.rs:8:46 | LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BEFORE_START` failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got ALLOC1 which is only 1 byte from the end of the allocation --> $DIR/offset_ub.rs:9:43 | LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `AFTER_END` failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got ALLOC2 which is only $BYTES bytes from the end of the allocation --> $DIR/offset_ub.rs:10:45 | LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `AFTER_ARRAY` failed here error[E0080]: overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` --> $DIR/offset_ub.rs:12:43 | LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `OVERFLOW` failed here error[E0080]: overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` --> $DIR/offset_ub.rs:13:44 | LL | pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNDERFLOW` failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/offset_ub.rs:14:56 | LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `OVERFLOW_ADDRESS_SPACE` failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/offset_ub.rs:15:57 | LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNDERFLOW_ADDRESS_SPACE` failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which is only $BYTES bytes from the beginning of the allocation --> $DIR/offset_ub.rs:16:49 | LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NEGATIVE_OFFSET` failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes --> $DIR/offset_ub.rs:18:50 | LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ZERO_SIZED_ALLOC` failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/offset_ub.rs:19:42 | LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `DANGLING` failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/offset_ub.rs:22:47 | LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNDERFLOW_ABS` failed here error: aborting due to 11 previous errors diff --git a/tests/ui/consts/overflowing-consts.noopt.stderr b/tests/ui/consts/overflowing-consts.noopt.stderr index e317060a141..1ef2a60b647 100644 --- a/tests/ui/consts/overflowing-consts.noopt.stderr +++ b/tests/ui/consts/overflowing-consts.noopt.stderr @@ -2,1021 +2,1021 @@ error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:18:22 | LL | const _NI8_SHL: i8 = 1i8 << 8; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI8_SHL` failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:19:26 | LL | const _NI8_SHL_P: &i8 = &(1i8 << 8); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI8_SHL_P` failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:21:24 | LL | const _NI16_SHL: i16 = 1i16 << 16; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI16_SHL` failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:22:28 | LL | const _NI16_SHL_P: &i16 = &(1i16 << 16); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI16_SHL_P` failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:24:24 | LL | const _NI32_SHL: i32 = 1i32 << 32; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI32_SHL` failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:25:28 | LL | const _NI32_SHL_P: &i32 = &(1i32 << 32); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI32_SHL_P` failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:27:24 | LL | const _NI64_SHL: i64 = 1i64 << 64; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI64_SHL` failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:28:28 | LL | const _NI64_SHL_P: &i64 = &(1i64 << 64); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI64_SHL_P` failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:30:26 | LL | const _NI128_SHL: i128 = 1i128 << 128; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI128_SHL` failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:31:30 | LL | const _NI128_SHL_P: &i128 = &(1i128 << 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI128_SHL_P` failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:33:22 | LL | const _NU8_SHL: u8 = 1u8 << 8; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU8_SHL` failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:34:26 | LL | const _NU8_SHL_P: &u8 = &(1u8 << 8); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU8_SHL_P` failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:36:24 | LL | const _NU16_SHL: u16 = 1u16 << 16; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_SHL` failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:37:28 | LL | const _NU16_SHL_P: &u16 = &(1u16 << 16); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU16_SHL_P` failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:39:24 | LL | const _NU32_SHL: u32 = 1u32 << 32; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_SHL` failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:40:28 | LL | const _NU32_SHL_P: &u32 = &(1u32 << 32); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU32_SHL_P` failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:42:24 | LL | const _NU64_SHL: u64 = 1u64 << 64; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_SHL` failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:43:28 | LL | const _NU64_SHL_P: &u64 = &(1u64 << 64); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU64_SHL_P` failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:45:26 | LL | const _NU128_SHL: u128 = 1u128 << 128; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU128_SHL` failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:46:30 | LL | const _NU128_SHL_P: &u128 = &(1u128 << 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU128_SHL_P` failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:48:28 | LL | const _NISIZE_SHL: isize = 1isize << BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NISIZE_SHL` failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:49:32 | LL | const _NISIZE_SHL_P: &isize = &(1isize << BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_SHL_P` failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:51:28 | LL | const _NUSIZE_SHL: usize = 1usize << BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NUSIZE_SHL` failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:52:32 | LL | const _NUSIZE_SHL_P: &usize = &(1usize << BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_SHL_P` failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:55:22 | LL | const _NI8_SHR: i8 = 1i8 >> 8; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI8_SHR` failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:56:26 | LL | const _NI8_SHR_P: &i8 = &(1i8 >> 8); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI8_SHR_P` failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:58:24 | LL | const _NI16_SHR: i16 = 1i16 >> 16; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI16_SHR` failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:59:28 | LL | const _NI16_SHR_P: &i16 = &(1i16 >> 16); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI16_SHR_P` failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:61:24 | LL | const _NI32_SHR: i32 = 1i32 >> 32; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI32_SHR` failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:62:28 | LL | const _NI32_SHR_P: &i32 = &(1i32 >> 32); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI32_SHR_P` failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:64:24 | LL | const _NI64_SHR: i64 = 1i64 >> 64; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI64_SHR` failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:65:28 | LL | const _NI64_SHR_P: &i64 = &(1i64 >> 64); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI64_SHR_P` failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:67:26 | LL | const _NI128_SHR: i128 = 1i128 >> 128; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI128_SHR` failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:68:30 | LL | const _NI128_SHR_P: &i128 = &(1i128 >> 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI128_SHR_P` failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:70:22 | LL | const _NU8_SHR: u8 = 1u8 >> 8; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU8_SHR` failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:71:26 | LL | const _NU8_SHR_P: &u8 = &(1u8 >> 8); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU8_SHR_P` failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:73:24 | LL | const _NU16_SHR: u16 = 1u16 >> 16; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_SHR` failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:74:28 | LL | const _NU16_SHR_P: &u16 = &(1u16 >> 16); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU16_SHR_P` failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:76:24 | LL | const _NU32_SHR: u32 = 1u32 >> 32; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_SHR` failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:77:28 | LL | const _NU32_SHR_P: &u32 = &(1u32 >> 32); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU32_SHR_P` failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:79:24 | LL | const _NU64_SHR: u64 = 1u64 >> 64; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_SHR` failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:80:28 | LL | const _NU64_SHR_P: &u64 = &(1u64 >> 64); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU64_SHR_P` failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:82:26 | LL | const _NU128_SHR: u128 = 1u128 >> 128; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU128_SHR` failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:83:30 | LL | const _NU128_SHR_P: &u128 = &(1u128 >> 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU128_SHR_P` failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:85:28 | LL | const _NISIZE_SHR: isize = 1isize >> BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NISIZE_SHR` failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:86:32 | LL | const _NISIZE_SHR_P: &isize = &(1isize >> BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_SHR_P` failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:88:28 | LL | const _NUSIZE_SHR: usize = 1usize >> BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NUSIZE_SHR` failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:89:32 | LL | const _NUSIZE_SHR_P: &usize = &(1usize >> BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_SHR_P` failed here error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:92:22 | LL | const _NI8_ADD: i8 = 1i8 + i8::MAX; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NI8_ADD` failed here error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:93:26 | LL | const _NI8_ADD_P: &i8 = &(1i8 + i8::MAX); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI8_ADD_P` failed here error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:95:24 | LL | const _NI16_ADD: i16 = 1i16 + i16::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI16_ADD` failed here error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:96:28 | LL | const _NI16_ADD_P: &i16 = &(1i16 + i16::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NI16_ADD_P` failed here error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:98:24 | LL | const _NI32_ADD: i32 = 1i32 + i32::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI32_ADD` failed here error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:99:28 | LL | const _NI32_ADD_P: &i32 = &(1i32 + i32::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NI32_ADD_P` failed here error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:101:24 | LL | const _NI64_ADD: i64 = 1i64 + i64::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI64_ADD` failed here error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:102:28 | LL | const _NI64_ADD_P: &i64 = &(1i64 + i64::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NI64_ADD_P` failed here error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:104:26 | LL | const _NI128_ADD: i128 = 1i128 + i128::MAX; - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NI128_ADD` failed here error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:105:30 | LL | const _NI128_ADD_P: &i128 = &(1i128 + i128::MAX); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_NI128_ADD_P` failed here error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:107:22 | LL | const _NU8_ADD: u8 = 1u8 + u8::MAX; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NU8_ADD` failed here error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:108:26 | LL | const _NU8_ADD_P: &u8 = &(1u8 + u8::MAX); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU8_ADD_P` failed here error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:110:24 | LL | const _NU16_ADD: u16 = 1u16 + u16::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU16_ADD` failed here error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:111:28 | LL | const _NU16_ADD_P: &u16 = &(1u16 + u16::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NU16_ADD_P` failed here error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:113:24 | LL | const _NU32_ADD: u32 = 1u32 + u32::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU32_ADD` failed here error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:114:28 | LL | const _NU32_ADD_P: &u32 = &(1u32 + u32::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NU32_ADD_P` failed here error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:116:24 | LL | const _NU64_ADD: u64 = 1u64 + u64::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU64_ADD` failed here error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:117:28 | LL | const _NU64_ADD_P: &u64 = &(1u64 + u64::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NU64_ADD_P` failed here error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:119:26 | LL | const _NU128_ADD: u128 = 1u128 + u128::MAX; - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NU128_ADD` failed here error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:120:30 | LL | const _NU128_ADD_P: &u128 = &(1u128 + u128::MAX); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_NU128_ADD_P` failed here error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:122:28 | LL | const _NISIZE_ADD: isize = 1isize + isize::MAX; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_ADD` failed here error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:123:32 | LL | const _NISIZE_ADD_P: &isize = &(1isize + isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_ADD_P` failed here error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:125:28 | LL | const _NUSIZE_ADD: usize = 1usize + usize::MAX; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_ADD` failed here error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:126:32 | LL | const _NUSIZE_ADD_P: &usize = &(1usize + usize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_ADD_P` failed here error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:129:22 | LL | const _NI8_SUB: i8 = -5i8 - i8::MAX; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI8_SUB` failed here error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:130:26 | LL | const _NI8_SUB_P: &i8 = &(-5i8 - i8::MAX); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NI8_SUB_P` failed here error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:132:24 | LL | const _NI16_SUB: i16 = -5i16 - i16::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NI16_SUB` failed here error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:133:28 | LL | const _NI16_SUB_P: &i16 = &(-5i16 - i16::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `_NI16_SUB_P` failed here error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:135:24 | LL | const _NI32_SUB: i32 = -5i32 - i32::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NI32_SUB` failed here error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:136:28 | LL | const _NI32_SUB_P: &i32 = &(-5i32 - i32::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `_NI32_SUB_P` failed here error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:138:24 | LL | const _NI64_SUB: i64 = -5i64 - i64::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NI64_SUB` failed here error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:139:28 | LL | const _NI64_SUB_P: &i64 = &(-5i64 - i64::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `_NI64_SUB_P` failed here error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:141:26 | LL | const _NI128_SUB: i128 = -5i128 - i128::MAX; - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `_NI128_SUB` failed here error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:142:30 | LL | const _NI128_SUB_P: &i128 = &(-5i128 - i128::MAX); - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^ evaluation of `_NI128_SUB_P` failed here error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:144:22 | LL | const _NU8_SUB: u8 = 1u8 - 5; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NU8_SUB` failed here error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:145:26 | LL | const _NU8_SUB_P: &u8 = &(1u8 - 5); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU8_SUB_P` failed here error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:147:24 | LL | const _NU16_SUB: u16 = 1u16 - 5; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU16_SUB` failed here error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:148:28 | LL | const _NU16_SUB_P: &u16 = &(1u16 - 5); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_SUB_P` failed here error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:150:24 | LL | const _NU32_SUB: u32 = 1u32 - 5; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU32_SUB` failed here error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:151:28 | LL | const _NU32_SUB_P: &u32 = &(1u32 - 5); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_SUB_P` failed here error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:153:24 | LL | const _NU64_SUB: u64 = 1u64 - 5; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU64_SUB` failed here error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:154:28 | LL | const _NU64_SUB_P: &u64 = &(1u64 - 5); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_SUB_P` failed here error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:156:26 | LL | const _NU128_SUB: u128 = 1u128 - 5; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU128_SUB` failed here error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:157:30 | LL | const _NU128_SUB_P: &u128 = &(1u128 - 5); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NU128_SUB_P` failed here error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:159:28 | LL | const _NISIZE_SUB: isize = -5isize - isize::MAX; - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_SUB` failed here error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:160:32 | LL | const _NISIZE_SUB_P: &isize = &(-5isize - isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_SUB_P` failed here error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:162:28 | LL | const _NUSIZE_SUB: usize = 1usize - 5; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NUSIZE_SUB` failed here error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:163:32 | LL | const _NUSIZE_SUB_P: &usize = &(1usize - 5); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NUSIZE_SUB_P` failed here error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow --> $DIR/overflowing-consts.rs:166:22 | LL | const _NI8_MUL: i8 = i8::MAX * 5; - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NI8_MUL` failed here error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow --> $DIR/overflowing-consts.rs:167:26 | LL | const _NI8_MUL_P: &i8 = &(i8::MAX * 5); - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NI8_MUL_P` failed here error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow --> $DIR/overflowing-consts.rs:169:24 | LL | const _NI16_MUL: i16 = i16::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI16_MUL` failed here error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow --> $DIR/overflowing-consts.rs:170:28 | LL | const _NI16_MUL_P: &i16 = &(i16::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI16_MUL_P` failed here error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow --> $DIR/overflowing-consts.rs:172:24 | LL | const _NI32_MUL: i32 = i32::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI32_MUL` failed here error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow --> $DIR/overflowing-consts.rs:173:28 | LL | const _NI32_MUL_P: &i32 = &(i32::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI32_MUL_P` failed here error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow --> $DIR/overflowing-consts.rs:175:24 | LL | const _NI64_MUL: i64 = i64::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI64_MUL` failed here error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow --> $DIR/overflowing-consts.rs:176:28 | LL | const _NI64_MUL_P: &i64 = &(i64::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI64_MUL_P` failed here error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow --> $DIR/overflowing-consts.rs:178:26 | LL | const _NI128_MUL: i128 = i128::MAX * 5; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NI128_MUL` failed here error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow --> $DIR/overflowing-consts.rs:179:30 | LL | const _NI128_MUL_P: &i128 = &(i128::MAX * 5); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI128_MUL_P` failed here error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:181:22 | LL | const _NU8_MUL: u8 = u8::MAX * 5; - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NU8_MUL` failed here error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:182:26 | LL | const _NU8_MUL_P: &u8 = &(u8::MAX * 5); - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NU8_MUL_P` failed here error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:184:24 | LL | const _NU16_MUL: u16 = u16::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU16_MUL` failed here error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:185:28 | LL | const _NU16_MUL_P: &u16 = &(u16::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU16_MUL_P` failed here error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:187:24 | LL | const _NU32_MUL: u32 = u32::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU32_MUL` failed here error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:188:28 | LL | const _NU32_MUL_P: &u32 = &(u32::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU32_MUL_P` failed here error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:190:24 | LL | const _NU64_MUL: u64 = u64::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU64_MUL` failed here error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:191:28 | LL | const _NU64_MUL_P: &u64 = &(u64::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU64_MUL_P` failed here error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:193:26 | LL | const _NU128_MUL: u128 = u128::MAX * 5; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NU128_MUL` failed here error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:194:30 | LL | const _NU128_MUL_P: &u128 = &(u128::MAX * 5); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU128_MUL_P` failed here error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow --> $DIR/overflowing-consts.rs:196:28 | LL | const _NISIZE_MUL: isize = isize::MAX * 5; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NISIZE_MUL` failed here error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow --> $DIR/overflowing-consts.rs:197:32 | LL | const _NISIZE_MUL_P: &isize = &(isize::MAX * 5); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_MUL_P` failed here error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:199:28 | LL | const _NUSIZE_MUL: usize = usize::MAX * 5; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NUSIZE_MUL` failed here error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:200:32 | LL | const _NUSIZE_MUL_P: &usize = &(usize::MAX * 5); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_MUL_P` failed here error[E0080]: attempt to divide `1_i8` by zero --> $DIR/overflowing-consts.rs:203:22 | LL | const _NI8_DIV: i8 = 1i8 / 0; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NI8_DIV` failed here error[E0080]: attempt to divide `1_i8` by zero --> $DIR/overflowing-consts.rs:204:26 | LL | const _NI8_DIV_P: &i8 = &(1i8 / 0); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NI8_DIV_P` failed here error[E0080]: attempt to divide `1_i16` by zero --> $DIR/overflowing-consts.rs:206:24 | LL | const _NI16_DIV: i16 = 1i16 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI16_DIV` failed here error[E0080]: attempt to divide `1_i16` by zero --> $DIR/overflowing-consts.rs:207:28 | LL | const _NI16_DIV_P: &i16 = &(1i16 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI16_DIV_P` failed here error[E0080]: attempt to divide `1_i32` by zero --> $DIR/overflowing-consts.rs:209:24 | LL | const _NI32_DIV: i32 = 1i32 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI32_DIV` failed here error[E0080]: attempt to divide `1_i32` by zero --> $DIR/overflowing-consts.rs:210:28 | LL | const _NI32_DIV_P: &i32 = &(1i32 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI32_DIV_P` failed here error[E0080]: attempt to divide `1_i64` by zero --> $DIR/overflowing-consts.rs:212:24 | LL | const _NI64_DIV: i64 = 1i64 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI64_DIV` failed here error[E0080]: attempt to divide `1_i64` by zero --> $DIR/overflowing-consts.rs:213:28 | LL | const _NI64_DIV_P: &i64 = &(1i64 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI64_DIV_P` failed here error[E0080]: attempt to divide `1_i128` by zero --> $DIR/overflowing-consts.rs:215:26 | LL | const _NI128_DIV: i128 = 1i128 / 0; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NI128_DIV` failed here error[E0080]: attempt to divide `1_i128` by zero --> $DIR/overflowing-consts.rs:216:30 | LL | const _NI128_DIV_P: &i128 = &(1i128 / 0); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NI128_DIV_P` failed here error[E0080]: attempt to divide `1_u8` by zero --> $DIR/overflowing-consts.rs:218:22 | LL | const _NU8_DIV: u8 = 1u8 / 0; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NU8_DIV` failed here error[E0080]: attempt to divide `1_u8` by zero --> $DIR/overflowing-consts.rs:219:26 | LL | const _NU8_DIV_P: &u8 = &(1u8 / 0); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU8_DIV_P` failed here error[E0080]: attempt to divide `1_u16` by zero --> $DIR/overflowing-consts.rs:221:24 | LL | const _NU16_DIV: u16 = 1u16 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU16_DIV` failed here error[E0080]: attempt to divide `1_u16` by zero --> $DIR/overflowing-consts.rs:222:28 | LL | const _NU16_DIV_P: &u16 = &(1u16 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_DIV_P` failed here error[E0080]: attempt to divide `1_u32` by zero --> $DIR/overflowing-consts.rs:224:24 | LL | const _NU32_DIV: u32 = 1u32 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU32_DIV` failed here error[E0080]: attempt to divide `1_u32` by zero --> $DIR/overflowing-consts.rs:225:28 | LL | const _NU32_DIV_P: &u32 = &(1u32 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_DIV_P` failed here error[E0080]: attempt to divide `1_u64` by zero --> $DIR/overflowing-consts.rs:227:24 | LL | const _NU64_DIV: u64 = 1u64 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU64_DIV` failed here error[E0080]: attempt to divide `1_u64` by zero --> $DIR/overflowing-consts.rs:228:28 | LL | const _NU64_DIV_P: &u64 = &(1u64 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_DIV_P` failed here error[E0080]: attempt to divide `1_u128` by zero --> $DIR/overflowing-consts.rs:230:26 | LL | const _NU128_DIV: u128 = 1u128 / 0; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU128_DIV` failed here error[E0080]: attempt to divide `1_u128` by zero --> $DIR/overflowing-consts.rs:231:30 | LL | const _NU128_DIV_P: &u128 = &(1u128 / 0); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NU128_DIV_P` failed here error[E0080]: attempt to divide `1_isize` by zero --> $DIR/overflowing-consts.rs:233:28 | LL | const _NISIZE_DIV: isize = 1isize / 0; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NISIZE_DIV` failed here error[E0080]: attempt to divide `1_isize` by zero --> $DIR/overflowing-consts.rs:234:32 | LL | const _NISIZE_DIV_P: &isize = &(1isize / 0); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NISIZE_DIV_P` failed here error[E0080]: attempt to divide `1_usize` by zero --> $DIR/overflowing-consts.rs:236:28 | LL | const _NUSIZE_DIV: usize = 1usize / 0; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NUSIZE_DIV` failed here error[E0080]: attempt to divide `1_usize` by zero --> $DIR/overflowing-consts.rs:237:32 | LL | const _NUSIZE_DIV_P: &usize = &(1usize / 0); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NUSIZE_DIV_P` failed here error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero --> $DIR/overflowing-consts.rs:240:22 | LL | const _NI8_MOD: i8 = 1i8 % 0; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NI8_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero --> $DIR/overflowing-consts.rs:241:26 | LL | const _NI8_MOD_P: &i8 = &(1i8 % 0); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NI8_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero --> $DIR/overflowing-consts.rs:243:24 | LL | const _NI16_MOD: i16 = 1i16 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI16_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero --> $DIR/overflowing-consts.rs:244:28 | LL | const _NI16_MOD_P: &i16 = &(1i16 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI16_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero --> $DIR/overflowing-consts.rs:246:24 | LL | const _NI32_MOD: i32 = 1i32 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI32_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero --> $DIR/overflowing-consts.rs:247:28 | LL | const _NI32_MOD_P: &i32 = &(1i32 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI32_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero --> $DIR/overflowing-consts.rs:249:24 | LL | const _NI64_MOD: i64 = 1i64 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI64_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero --> $DIR/overflowing-consts.rs:250:28 | LL | const _NI64_MOD_P: &i64 = &(1i64 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI64_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero --> $DIR/overflowing-consts.rs:252:26 | LL | const _NI128_MOD: i128 = 1i128 % 0; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NI128_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero --> $DIR/overflowing-consts.rs:253:30 | LL | const _NI128_MOD_P: &i128 = &(1i128 % 0); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NI128_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero --> $DIR/overflowing-consts.rs:255:22 | LL | const _NU8_MOD: u8 = 1u8 % 0; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NU8_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero --> $DIR/overflowing-consts.rs:256:26 | LL | const _NU8_MOD_P: &u8 = &(1u8 % 0); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU8_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero --> $DIR/overflowing-consts.rs:258:24 | LL | const _NU16_MOD: u16 = 1u16 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU16_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero --> $DIR/overflowing-consts.rs:259:28 | LL | const _NU16_MOD_P: &u16 = &(1u16 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero --> $DIR/overflowing-consts.rs:261:24 | LL | const _NU32_MOD: u32 = 1u32 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU32_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero --> $DIR/overflowing-consts.rs:262:28 | LL | const _NU32_MOD_P: &u32 = &(1u32 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero --> $DIR/overflowing-consts.rs:264:24 | LL | const _NU64_MOD: u64 = 1u64 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU64_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero --> $DIR/overflowing-consts.rs:265:28 | LL | const _NU64_MOD_P: &u64 = &(1u64 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero --> $DIR/overflowing-consts.rs:267:26 | LL | const _NU128_MOD: u128 = 1u128 % 0; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU128_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero --> $DIR/overflowing-consts.rs:268:30 | LL | const _NU128_MOD_P: &u128 = &(1u128 % 0); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NU128_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero --> $DIR/overflowing-consts.rs:270:28 | LL | const _NISIZE_MOD: isize = 1isize % 0; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NISIZE_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero --> $DIR/overflowing-consts.rs:271:32 | LL | const _NISIZE_MOD_P: &isize = &(1isize % 0); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NISIZE_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero --> $DIR/overflowing-consts.rs:273:28 | LL | const _NUSIZE_MOD: usize = 1usize % 0; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NUSIZE_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero --> $DIR/overflowing-consts.rs:274:32 | LL | const _NUSIZE_MOD_P: &usize = &(1usize % 0); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NUSIZE_MOD_P` failed here error[E0080]: index out of bounds: the length is 3 but the index is 4 --> $DIR/overflowing-consts.rs:277:24 | LL | const _NI32_OOB: i32 = [1, 2, 3][4]; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI32_OOB` failed here error[E0080]: index out of bounds: the length is 3 but the index is 4 --> $DIR/overflowing-consts.rs:278:28 | LL | const _NI32_OOB_P: &i32 = &([1, 2, 3][4]); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI32_OOB_P` failed here error: aborting due to 170 previous errors diff --git a/tests/ui/consts/overflowing-consts.opt.stderr b/tests/ui/consts/overflowing-consts.opt.stderr index e317060a141..1ef2a60b647 100644 --- a/tests/ui/consts/overflowing-consts.opt.stderr +++ b/tests/ui/consts/overflowing-consts.opt.stderr @@ -2,1021 +2,1021 @@ error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:18:22 | LL | const _NI8_SHL: i8 = 1i8 << 8; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI8_SHL` failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:19:26 | LL | const _NI8_SHL_P: &i8 = &(1i8 << 8); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI8_SHL_P` failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:21:24 | LL | const _NI16_SHL: i16 = 1i16 << 16; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI16_SHL` failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:22:28 | LL | const _NI16_SHL_P: &i16 = &(1i16 << 16); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI16_SHL_P` failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:24:24 | LL | const _NI32_SHL: i32 = 1i32 << 32; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI32_SHL` failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:25:28 | LL | const _NI32_SHL_P: &i32 = &(1i32 << 32); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI32_SHL_P` failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:27:24 | LL | const _NI64_SHL: i64 = 1i64 << 64; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI64_SHL` failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:28:28 | LL | const _NI64_SHL_P: &i64 = &(1i64 << 64); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI64_SHL_P` failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:30:26 | LL | const _NI128_SHL: i128 = 1i128 << 128; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI128_SHL` failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:31:30 | LL | const _NI128_SHL_P: &i128 = &(1i128 << 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI128_SHL_P` failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:33:22 | LL | const _NU8_SHL: u8 = 1u8 << 8; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU8_SHL` failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:34:26 | LL | const _NU8_SHL_P: &u8 = &(1u8 << 8); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU8_SHL_P` failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:36:24 | LL | const _NU16_SHL: u16 = 1u16 << 16; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_SHL` failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:37:28 | LL | const _NU16_SHL_P: &u16 = &(1u16 << 16); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU16_SHL_P` failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:39:24 | LL | const _NU32_SHL: u32 = 1u32 << 32; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_SHL` failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:40:28 | LL | const _NU32_SHL_P: &u32 = &(1u32 << 32); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU32_SHL_P` failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:42:24 | LL | const _NU64_SHL: u64 = 1u64 << 64; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_SHL` failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:43:28 | LL | const _NU64_SHL_P: &u64 = &(1u64 << 64); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU64_SHL_P` failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:45:26 | LL | const _NU128_SHL: u128 = 1u128 << 128; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU128_SHL` failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:46:30 | LL | const _NU128_SHL_P: &u128 = &(1u128 << 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU128_SHL_P` failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:48:28 | LL | const _NISIZE_SHL: isize = 1isize << BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NISIZE_SHL` failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:49:32 | LL | const _NISIZE_SHL_P: &isize = &(1isize << BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_SHL_P` failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:51:28 | LL | const _NUSIZE_SHL: usize = 1usize << BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NUSIZE_SHL` failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:52:32 | LL | const _NUSIZE_SHL_P: &usize = &(1usize << BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_SHL_P` failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:55:22 | LL | const _NI8_SHR: i8 = 1i8 >> 8; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI8_SHR` failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:56:26 | LL | const _NI8_SHR_P: &i8 = &(1i8 >> 8); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI8_SHR_P` failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:58:24 | LL | const _NI16_SHR: i16 = 1i16 >> 16; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI16_SHR` failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:59:28 | LL | const _NI16_SHR_P: &i16 = &(1i16 >> 16); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI16_SHR_P` failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:61:24 | LL | const _NI32_SHR: i32 = 1i32 >> 32; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI32_SHR` failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:62:28 | LL | const _NI32_SHR_P: &i32 = &(1i32 >> 32); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI32_SHR_P` failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:64:24 | LL | const _NI64_SHR: i64 = 1i64 >> 64; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI64_SHR` failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:65:28 | LL | const _NI64_SHR_P: &i64 = &(1i64 >> 64); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI64_SHR_P` failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:67:26 | LL | const _NI128_SHR: i128 = 1i128 >> 128; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI128_SHR` failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:68:30 | LL | const _NI128_SHR_P: &i128 = &(1i128 >> 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI128_SHR_P` failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:70:22 | LL | const _NU8_SHR: u8 = 1u8 >> 8; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU8_SHR` failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:71:26 | LL | const _NU8_SHR_P: &u8 = &(1u8 >> 8); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU8_SHR_P` failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:73:24 | LL | const _NU16_SHR: u16 = 1u16 >> 16; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_SHR` failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:74:28 | LL | const _NU16_SHR_P: &u16 = &(1u16 >> 16); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU16_SHR_P` failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:76:24 | LL | const _NU32_SHR: u32 = 1u32 >> 32; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_SHR` failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:77:28 | LL | const _NU32_SHR_P: &u32 = &(1u32 >> 32); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU32_SHR_P` failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:79:24 | LL | const _NU64_SHR: u64 = 1u64 >> 64; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_SHR` failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:80:28 | LL | const _NU64_SHR_P: &u64 = &(1u64 >> 64); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU64_SHR_P` failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:82:26 | LL | const _NU128_SHR: u128 = 1u128 >> 128; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU128_SHR` failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:83:30 | LL | const _NU128_SHR_P: &u128 = &(1u128 >> 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU128_SHR_P` failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:85:28 | LL | const _NISIZE_SHR: isize = 1isize >> BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NISIZE_SHR` failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:86:32 | LL | const _NISIZE_SHR_P: &isize = &(1isize >> BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_SHR_P` failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:88:28 | LL | const _NUSIZE_SHR: usize = 1usize >> BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NUSIZE_SHR` failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:89:32 | LL | const _NUSIZE_SHR_P: &usize = &(1usize >> BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_SHR_P` failed here error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:92:22 | LL | const _NI8_ADD: i8 = 1i8 + i8::MAX; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NI8_ADD` failed here error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:93:26 | LL | const _NI8_ADD_P: &i8 = &(1i8 + i8::MAX); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI8_ADD_P` failed here error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:95:24 | LL | const _NI16_ADD: i16 = 1i16 + i16::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI16_ADD` failed here error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:96:28 | LL | const _NI16_ADD_P: &i16 = &(1i16 + i16::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NI16_ADD_P` failed here error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:98:24 | LL | const _NI32_ADD: i32 = 1i32 + i32::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI32_ADD` failed here error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:99:28 | LL | const _NI32_ADD_P: &i32 = &(1i32 + i32::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NI32_ADD_P` failed here error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:101:24 | LL | const _NI64_ADD: i64 = 1i64 + i64::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI64_ADD` failed here error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:102:28 | LL | const _NI64_ADD_P: &i64 = &(1i64 + i64::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NI64_ADD_P` failed here error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:104:26 | LL | const _NI128_ADD: i128 = 1i128 + i128::MAX; - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NI128_ADD` failed here error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:105:30 | LL | const _NI128_ADD_P: &i128 = &(1i128 + i128::MAX); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_NI128_ADD_P` failed here error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:107:22 | LL | const _NU8_ADD: u8 = 1u8 + u8::MAX; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NU8_ADD` failed here error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:108:26 | LL | const _NU8_ADD_P: &u8 = &(1u8 + u8::MAX); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU8_ADD_P` failed here error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:110:24 | LL | const _NU16_ADD: u16 = 1u16 + u16::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU16_ADD` failed here error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:111:28 | LL | const _NU16_ADD_P: &u16 = &(1u16 + u16::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NU16_ADD_P` failed here error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:113:24 | LL | const _NU32_ADD: u32 = 1u32 + u32::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU32_ADD` failed here error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:114:28 | LL | const _NU32_ADD_P: &u32 = &(1u32 + u32::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NU32_ADD_P` failed here error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:116:24 | LL | const _NU64_ADD: u64 = 1u64 + u64::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU64_ADD` failed here error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:117:28 | LL | const _NU64_ADD_P: &u64 = &(1u64 + u64::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NU64_ADD_P` failed here error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:119:26 | LL | const _NU128_ADD: u128 = 1u128 + u128::MAX; - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NU128_ADD` failed here error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:120:30 | LL | const _NU128_ADD_P: &u128 = &(1u128 + u128::MAX); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_NU128_ADD_P` failed here error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:122:28 | LL | const _NISIZE_ADD: isize = 1isize + isize::MAX; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_ADD` failed here error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:123:32 | LL | const _NISIZE_ADD_P: &isize = &(1isize + isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_ADD_P` failed here error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:125:28 | LL | const _NUSIZE_ADD: usize = 1usize + usize::MAX; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_ADD` failed here error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:126:32 | LL | const _NUSIZE_ADD_P: &usize = &(1usize + usize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_ADD_P` failed here error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:129:22 | LL | const _NI8_SUB: i8 = -5i8 - i8::MAX; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI8_SUB` failed here error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:130:26 | LL | const _NI8_SUB_P: &i8 = &(-5i8 - i8::MAX); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NI8_SUB_P` failed here error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:132:24 | LL | const _NI16_SUB: i16 = -5i16 - i16::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NI16_SUB` failed here error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:133:28 | LL | const _NI16_SUB_P: &i16 = &(-5i16 - i16::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `_NI16_SUB_P` failed here error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:135:24 | LL | const _NI32_SUB: i32 = -5i32 - i32::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NI32_SUB` failed here error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:136:28 | LL | const _NI32_SUB_P: &i32 = &(-5i32 - i32::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `_NI32_SUB_P` failed here error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:138:24 | LL | const _NI64_SUB: i64 = -5i64 - i64::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NI64_SUB` failed here error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:139:28 | LL | const _NI64_SUB_P: &i64 = &(-5i64 - i64::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `_NI64_SUB_P` failed here error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:141:26 | LL | const _NI128_SUB: i128 = -5i128 - i128::MAX; - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `_NI128_SUB` failed here error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:142:30 | LL | const _NI128_SUB_P: &i128 = &(-5i128 - i128::MAX); - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^ evaluation of `_NI128_SUB_P` failed here error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:144:22 | LL | const _NU8_SUB: u8 = 1u8 - 5; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NU8_SUB` failed here error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:145:26 | LL | const _NU8_SUB_P: &u8 = &(1u8 - 5); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU8_SUB_P` failed here error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:147:24 | LL | const _NU16_SUB: u16 = 1u16 - 5; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU16_SUB` failed here error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:148:28 | LL | const _NU16_SUB_P: &u16 = &(1u16 - 5); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_SUB_P` failed here error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:150:24 | LL | const _NU32_SUB: u32 = 1u32 - 5; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU32_SUB` failed here error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:151:28 | LL | const _NU32_SUB_P: &u32 = &(1u32 - 5); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_SUB_P` failed here error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:153:24 | LL | const _NU64_SUB: u64 = 1u64 - 5; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU64_SUB` failed here error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:154:28 | LL | const _NU64_SUB_P: &u64 = &(1u64 - 5); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_SUB_P` failed here error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:156:26 | LL | const _NU128_SUB: u128 = 1u128 - 5; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU128_SUB` failed here error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:157:30 | LL | const _NU128_SUB_P: &u128 = &(1u128 - 5); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NU128_SUB_P` failed here error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:159:28 | LL | const _NISIZE_SUB: isize = -5isize - isize::MAX; - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_SUB` failed here error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:160:32 | LL | const _NISIZE_SUB_P: &isize = &(-5isize - isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_SUB_P` failed here error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:162:28 | LL | const _NUSIZE_SUB: usize = 1usize - 5; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NUSIZE_SUB` failed here error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:163:32 | LL | const _NUSIZE_SUB_P: &usize = &(1usize - 5); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NUSIZE_SUB_P` failed here error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow --> $DIR/overflowing-consts.rs:166:22 | LL | const _NI8_MUL: i8 = i8::MAX * 5; - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NI8_MUL` failed here error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow --> $DIR/overflowing-consts.rs:167:26 | LL | const _NI8_MUL_P: &i8 = &(i8::MAX * 5); - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NI8_MUL_P` failed here error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow --> $DIR/overflowing-consts.rs:169:24 | LL | const _NI16_MUL: i16 = i16::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI16_MUL` failed here error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow --> $DIR/overflowing-consts.rs:170:28 | LL | const _NI16_MUL_P: &i16 = &(i16::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI16_MUL_P` failed here error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow --> $DIR/overflowing-consts.rs:172:24 | LL | const _NI32_MUL: i32 = i32::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI32_MUL` failed here error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow --> $DIR/overflowing-consts.rs:173:28 | LL | const _NI32_MUL_P: &i32 = &(i32::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI32_MUL_P` failed here error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow --> $DIR/overflowing-consts.rs:175:24 | LL | const _NI64_MUL: i64 = i64::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI64_MUL` failed here error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow --> $DIR/overflowing-consts.rs:176:28 | LL | const _NI64_MUL_P: &i64 = &(i64::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI64_MUL_P` failed here error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow --> $DIR/overflowing-consts.rs:178:26 | LL | const _NI128_MUL: i128 = i128::MAX * 5; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NI128_MUL` failed here error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow --> $DIR/overflowing-consts.rs:179:30 | LL | const _NI128_MUL_P: &i128 = &(i128::MAX * 5); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI128_MUL_P` failed here error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:181:22 | LL | const _NU8_MUL: u8 = u8::MAX * 5; - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NU8_MUL` failed here error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:182:26 | LL | const _NU8_MUL_P: &u8 = &(u8::MAX * 5); - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NU8_MUL_P` failed here error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:184:24 | LL | const _NU16_MUL: u16 = u16::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU16_MUL` failed here error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:185:28 | LL | const _NU16_MUL_P: &u16 = &(u16::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU16_MUL_P` failed here error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:187:24 | LL | const _NU32_MUL: u32 = u32::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU32_MUL` failed here error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:188:28 | LL | const _NU32_MUL_P: &u32 = &(u32::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU32_MUL_P` failed here error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:190:24 | LL | const _NU64_MUL: u64 = u64::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU64_MUL` failed here error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:191:28 | LL | const _NU64_MUL_P: &u64 = &(u64::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU64_MUL_P` failed here error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:193:26 | LL | const _NU128_MUL: u128 = u128::MAX * 5; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NU128_MUL` failed here error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:194:30 | LL | const _NU128_MUL_P: &u128 = &(u128::MAX * 5); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU128_MUL_P` failed here error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow --> $DIR/overflowing-consts.rs:196:28 | LL | const _NISIZE_MUL: isize = isize::MAX * 5; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NISIZE_MUL` failed here error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow --> $DIR/overflowing-consts.rs:197:32 | LL | const _NISIZE_MUL_P: &isize = &(isize::MAX * 5); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_MUL_P` failed here error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:199:28 | LL | const _NUSIZE_MUL: usize = usize::MAX * 5; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NUSIZE_MUL` failed here error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:200:32 | LL | const _NUSIZE_MUL_P: &usize = &(usize::MAX * 5); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_MUL_P` failed here error[E0080]: attempt to divide `1_i8` by zero --> $DIR/overflowing-consts.rs:203:22 | LL | const _NI8_DIV: i8 = 1i8 / 0; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NI8_DIV` failed here error[E0080]: attempt to divide `1_i8` by zero --> $DIR/overflowing-consts.rs:204:26 | LL | const _NI8_DIV_P: &i8 = &(1i8 / 0); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NI8_DIV_P` failed here error[E0080]: attempt to divide `1_i16` by zero --> $DIR/overflowing-consts.rs:206:24 | LL | const _NI16_DIV: i16 = 1i16 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI16_DIV` failed here error[E0080]: attempt to divide `1_i16` by zero --> $DIR/overflowing-consts.rs:207:28 | LL | const _NI16_DIV_P: &i16 = &(1i16 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI16_DIV_P` failed here error[E0080]: attempt to divide `1_i32` by zero --> $DIR/overflowing-consts.rs:209:24 | LL | const _NI32_DIV: i32 = 1i32 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI32_DIV` failed here error[E0080]: attempt to divide `1_i32` by zero --> $DIR/overflowing-consts.rs:210:28 | LL | const _NI32_DIV_P: &i32 = &(1i32 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI32_DIV_P` failed here error[E0080]: attempt to divide `1_i64` by zero --> $DIR/overflowing-consts.rs:212:24 | LL | const _NI64_DIV: i64 = 1i64 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI64_DIV` failed here error[E0080]: attempt to divide `1_i64` by zero --> $DIR/overflowing-consts.rs:213:28 | LL | const _NI64_DIV_P: &i64 = &(1i64 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI64_DIV_P` failed here error[E0080]: attempt to divide `1_i128` by zero --> $DIR/overflowing-consts.rs:215:26 | LL | const _NI128_DIV: i128 = 1i128 / 0; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NI128_DIV` failed here error[E0080]: attempt to divide `1_i128` by zero --> $DIR/overflowing-consts.rs:216:30 | LL | const _NI128_DIV_P: &i128 = &(1i128 / 0); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NI128_DIV_P` failed here error[E0080]: attempt to divide `1_u8` by zero --> $DIR/overflowing-consts.rs:218:22 | LL | const _NU8_DIV: u8 = 1u8 / 0; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NU8_DIV` failed here error[E0080]: attempt to divide `1_u8` by zero --> $DIR/overflowing-consts.rs:219:26 | LL | const _NU8_DIV_P: &u8 = &(1u8 / 0); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU8_DIV_P` failed here error[E0080]: attempt to divide `1_u16` by zero --> $DIR/overflowing-consts.rs:221:24 | LL | const _NU16_DIV: u16 = 1u16 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU16_DIV` failed here error[E0080]: attempt to divide `1_u16` by zero --> $DIR/overflowing-consts.rs:222:28 | LL | const _NU16_DIV_P: &u16 = &(1u16 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_DIV_P` failed here error[E0080]: attempt to divide `1_u32` by zero --> $DIR/overflowing-consts.rs:224:24 | LL | const _NU32_DIV: u32 = 1u32 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU32_DIV` failed here error[E0080]: attempt to divide `1_u32` by zero --> $DIR/overflowing-consts.rs:225:28 | LL | const _NU32_DIV_P: &u32 = &(1u32 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_DIV_P` failed here error[E0080]: attempt to divide `1_u64` by zero --> $DIR/overflowing-consts.rs:227:24 | LL | const _NU64_DIV: u64 = 1u64 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU64_DIV` failed here error[E0080]: attempt to divide `1_u64` by zero --> $DIR/overflowing-consts.rs:228:28 | LL | const _NU64_DIV_P: &u64 = &(1u64 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_DIV_P` failed here error[E0080]: attempt to divide `1_u128` by zero --> $DIR/overflowing-consts.rs:230:26 | LL | const _NU128_DIV: u128 = 1u128 / 0; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU128_DIV` failed here error[E0080]: attempt to divide `1_u128` by zero --> $DIR/overflowing-consts.rs:231:30 | LL | const _NU128_DIV_P: &u128 = &(1u128 / 0); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NU128_DIV_P` failed here error[E0080]: attempt to divide `1_isize` by zero --> $DIR/overflowing-consts.rs:233:28 | LL | const _NISIZE_DIV: isize = 1isize / 0; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NISIZE_DIV` failed here error[E0080]: attempt to divide `1_isize` by zero --> $DIR/overflowing-consts.rs:234:32 | LL | const _NISIZE_DIV_P: &isize = &(1isize / 0); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NISIZE_DIV_P` failed here error[E0080]: attempt to divide `1_usize` by zero --> $DIR/overflowing-consts.rs:236:28 | LL | const _NUSIZE_DIV: usize = 1usize / 0; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NUSIZE_DIV` failed here error[E0080]: attempt to divide `1_usize` by zero --> $DIR/overflowing-consts.rs:237:32 | LL | const _NUSIZE_DIV_P: &usize = &(1usize / 0); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NUSIZE_DIV_P` failed here error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero --> $DIR/overflowing-consts.rs:240:22 | LL | const _NI8_MOD: i8 = 1i8 % 0; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NI8_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero --> $DIR/overflowing-consts.rs:241:26 | LL | const _NI8_MOD_P: &i8 = &(1i8 % 0); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NI8_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero --> $DIR/overflowing-consts.rs:243:24 | LL | const _NI16_MOD: i16 = 1i16 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI16_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero --> $DIR/overflowing-consts.rs:244:28 | LL | const _NI16_MOD_P: &i16 = &(1i16 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI16_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero --> $DIR/overflowing-consts.rs:246:24 | LL | const _NI32_MOD: i32 = 1i32 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI32_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero --> $DIR/overflowing-consts.rs:247:28 | LL | const _NI32_MOD_P: &i32 = &(1i32 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI32_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero --> $DIR/overflowing-consts.rs:249:24 | LL | const _NI64_MOD: i64 = 1i64 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI64_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero --> $DIR/overflowing-consts.rs:250:28 | LL | const _NI64_MOD_P: &i64 = &(1i64 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI64_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero --> $DIR/overflowing-consts.rs:252:26 | LL | const _NI128_MOD: i128 = 1i128 % 0; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NI128_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero --> $DIR/overflowing-consts.rs:253:30 | LL | const _NI128_MOD_P: &i128 = &(1i128 % 0); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NI128_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero --> $DIR/overflowing-consts.rs:255:22 | LL | const _NU8_MOD: u8 = 1u8 % 0; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NU8_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero --> $DIR/overflowing-consts.rs:256:26 | LL | const _NU8_MOD_P: &u8 = &(1u8 % 0); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU8_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero --> $DIR/overflowing-consts.rs:258:24 | LL | const _NU16_MOD: u16 = 1u16 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU16_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero --> $DIR/overflowing-consts.rs:259:28 | LL | const _NU16_MOD_P: &u16 = &(1u16 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero --> $DIR/overflowing-consts.rs:261:24 | LL | const _NU32_MOD: u32 = 1u32 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU32_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero --> $DIR/overflowing-consts.rs:262:28 | LL | const _NU32_MOD_P: &u32 = &(1u32 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero --> $DIR/overflowing-consts.rs:264:24 | LL | const _NU64_MOD: u64 = 1u64 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU64_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero --> $DIR/overflowing-consts.rs:265:28 | LL | const _NU64_MOD_P: &u64 = &(1u64 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero --> $DIR/overflowing-consts.rs:267:26 | LL | const _NU128_MOD: u128 = 1u128 % 0; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU128_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero --> $DIR/overflowing-consts.rs:268:30 | LL | const _NU128_MOD_P: &u128 = &(1u128 % 0); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NU128_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero --> $DIR/overflowing-consts.rs:270:28 | LL | const _NISIZE_MOD: isize = 1isize % 0; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NISIZE_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero --> $DIR/overflowing-consts.rs:271:32 | LL | const _NISIZE_MOD_P: &isize = &(1isize % 0); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NISIZE_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero --> $DIR/overflowing-consts.rs:273:28 | LL | const _NUSIZE_MOD: usize = 1usize % 0; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NUSIZE_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero --> $DIR/overflowing-consts.rs:274:32 | LL | const _NUSIZE_MOD_P: &usize = &(1usize % 0); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NUSIZE_MOD_P` failed here error[E0080]: index out of bounds: the length is 3 but the index is 4 --> $DIR/overflowing-consts.rs:277:24 | LL | const _NI32_OOB: i32 = [1, 2, 3][4]; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI32_OOB` failed here error[E0080]: index out of bounds: the length is 3 but the index is 4 --> $DIR/overflowing-consts.rs:278:28 | LL | const _NI32_OOB_P: &i32 = &([1, 2, 3][4]); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI32_OOB_P` failed here error: aborting due to 170 previous errors diff --git a/tests/ui/consts/overflowing-consts.opt_with_overflow_checks.stderr b/tests/ui/consts/overflowing-consts.opt_with_overflow_checks.stderr index e317060a141..1ef2a60b647 100644 --- a/tests/ui/consts/overflowing-consts.opt_with_overflow_checks.stderr +++ b/tests/ui/consts/overflowing-consts.opt_with_overflow_checks.stderr @@ -2,1021 +2,1021 @@ error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:18:22 | LL | const _NI8_SHL: i8 = 1i8 << 8; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI8_SHL` failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:19:26 | LL | const _NI8_SHL_P: &i8 = &(1i8 << 8); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI8_SHL_P` failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:21:24 | LL | const _NI16_SHL: i16 = 1i16 << 16; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI16_SHL` failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:22:28 | LL | const _NI16_SHL_P: &i16 = &(1i16 << 16); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI16_SHL_P` failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:24:24 | LL | const _NI32_SHL: i32 = 1i32 << 32; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI32_SHL` failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:25:28 | LL | const _NI32_SHL_P: &i32 = &(1i32 << 32); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI32_SHL_P` failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:27:24 | LL | const _NI64_SHL: i64 = 1i64 << 64; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI64_SHL` failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:28:28 | LL | const _NI64_SHL_P: &i64 = &(1i64 << 64); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI64_SHL_P` failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:30:26 | LL | const _NI128_SHL: i128 = 1i128 << 128; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI128_SHL` failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:31:30 | LL | const _NI128_SHL_P: &i128 = &(1i128 << 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI128_SHL_P` failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:33:22 | LL | const _NU8_SHL: u8 = 1u8 << 8; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU8_SHL` failed here error[E0080]: attempt to shift left by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:34:26 | LL | const _NU8_SHL_P: &u8 = &(1u8 << 8); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU8_SHL_P` failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:36:24 | LL | const _NU16_SHL: u16 = 1u16 << 16; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_SHL` failed here error[E0080]: attempt to shift left by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:37:28 | LL | const _NU16_SHL_P: &u16 = &(1u16 << 16); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU16_SHL_P` failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:39:24 | LL | const _NU32_SHL: u32 = 1u32 << 32; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_SHL` failed here error[E0080]: attempt to shift left by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:40:28 | LL | const _NU32_SHL_P: &u32 = &(1u32 << 32); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU32_SHL_P` failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:42:24 | LL | const _NU64_SHL: u64 = 1u64 << 64; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_SHL` failed here error[E0080]: attempt to shift left by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:43:28 | LL | const _NU64_SHL_P: &u64 = &(1u64 << 64); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU64_SHL_P` failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:45:26 | LL | const _NU128_SHL: u128 = 1u128 << 128; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU128_SHL` failed here error[E0080]: attempt to shift left by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:46:30 | LL | const _NU128_SHL_P: &u128 = &(1u128 << 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU128_SHL_P` failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:48:28 | LL | const _NISIZE_SHL: isize = 1isize << BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NISIZE_SHL` failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:49:32 | LL | const _NISIZE_SHL_P: &isize = &(1isize << BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_SHL_P` failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:51:28 | LL | const _NUSIZE_SHL: usize = 1usize << BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NUSIZE_SHL` failed here error[E0080]: attempt to shift left by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:52:32 | LL | const _NUSIZE_SHL_P: &usize = &(1usize << BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_SHL_P` failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:55:22 | LL | const _NI8_SHR: i8 = 1i8 >> 8; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI8_SHR` failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:56:26 | LL | const _NI8_SHR_P: &i8 = &(1i8 >> 8); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI8_SHR_P` failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:58:24 | LL | const _NI16_SHR: i16 = 1i16 >> 16; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI16_SHR` failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:59:28 | LL | const _NI16_SHR_P: &i16 = &(1i16 >> 16); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI16_SHR_P` failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:61:24 | LL | const _NI32_SHR: i32 = 1i32 >> 32; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI32_SHR` failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:62:28 | LL | const _NI32_SHR_P: &i32 = &(1i32 >> 32); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI32_SHR_P` failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:64:24 | LL | const _NI64_SHR: i64 = 1i64 >> 64; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI64_SHR` failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:65:28 | LL | const _NI64_SHR_P: &i64 = &(1i64 >> 64); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI64_SHR_P` failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:67:26 | LL | const _NI128_SHR: i128 = 1i128 >> 128; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI128_SHR` failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:68:30 | LL | const _NI128_SHR_P: &i128 = &(1i128 >> 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI128_SHR_P` failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:70:22 | LL | const _NU8_SHR: u8 = 1u8 >> 8; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU8_SHR` failed here error[E0080]: attempt to shift right by `8_i32`, which would overflow --> $DIR/overflowing-consts.rs:71:26 | LL | const _NU8_SHR_P: &u8 = &(1u8 >> 8); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU8_SHR_P` failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:73:24 | LL | const _NU16_SHR: u16 = 1u16 >> 16; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_SHR` failed here error[E0080]: attempt to shift right by `16_i32`, which would overflow --> $DIR/overflowing-consts.rs:74:28 | LL | const _NU16_SHR_P: &u16 = &(1u16 >> 16); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU16_SHR_P` failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:76:24 | LL | const _NU32_SHR: u32 = 1u32 >> 32; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_SHR` failed here error[E0080]: attempt to shift right by `32_i32`, which would overflow --> $DIR/overflowing-consts.rs:77:28 | LL | const _NU32_SHR_P: &u32 = &(1u32 >> 32); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU32_SHR_P` failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:79:24 | LL | const _NU64_SHR: u64 = 1u64 >> 64; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_SHR` failed here error[E0080]: attempt to shift right by `64_i32`, which would overflow --> $DIR/overflowing-consts.rs:80:28 | LL | const _NU64_SHR_P: &u64 = &(1u64 >> 64); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU64_SHR_P` failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:82:26 | LL | const _NU128_SHR: u128 = 1u128 >> 128; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU128_SHR` failed here error[E0080]: attempt to shift right by `128_i32`, which would overflow --> $DIR/overflowing-consts.rs:83:30 | LL | const _NU128_SHR_P: &u128 = &(1u128 >> 128); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU128_SHR_P` failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:85:28 | LL | const _NISIZE_SHR: isize = 1isize >> BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NISIZE_SHR` failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:86:32 | LL | const _NISIZE_SHR_P: &isize = &(1isize >> BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_SHR_P` failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:88:28 | LL | const _NUSIZE_SHR: usize = 1usize >> BITS; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NUSIZE_SHR` failed here error[E0080]: attempt to shift right by `%BITS%`, which would overflow --> $DIR/overflowing-consts.rs:89:32 | LL | const _NUSIZE_SHR_P: &usize = &(1usize >> BITS); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_SHR_P` failed here error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:92:22 | LL | const _NI8_ADD: i8 = 1i8 + i8::MAX; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NI8_ADD` failed here error[E0080]: attempt to compute `1_i8 + i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:93:26 | LL | const _NI8_ADD_P: &i8 = &(1i8 + i8::MAX); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI8_ADD_P` failed here error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:95:24 | LL | const _NI16_ADD: i16 = 1i16 + i16::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI16_ADD` failed here error[E0080]: attempt to compute `1_i16 + i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:96:28 | LL | const _NI16_ADD_P: &i16 = &(1i16 + i16::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NI16_ADD_P` failed here error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:98:24 | LL | const _NI32_ADD: i32 = 1i32 + i32::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI32_ADD` failed here error[E0080]: attempt to compute `1_i32 + i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:99:28 | LL | const _NI32_ADD_P: &i32 = &(1i32 + i32::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NI32_ADD_P` failed here error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:101:24 | LL | const _NI64_ADD: i64 = 1i64 + i64::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI64_ADD` failed here error[E0080]: attempt to compute `1_i64 + i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:102:28 | LL | const _NI64_ADD_P: &i64 = &(1i64 + i64::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NI64_ADD_P` failed here error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:104:26 | LL | const _NI128_ADD: i128 = 1i128 + i128::MAX; - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NI128_ADD` failed here error[E0080]: attempt to compute `1_i128 + i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:105:30 | LL | const _NI128_ADD_P: &i128 = &(1i128 + i128::MAX); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_NI128_ADD_P` failed here error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:107:22 | LL | const _NU8_ADD: u8 = 1u8 + u8::MAX; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NU8_ADD` failed here error[E0080]: attempt to compute `1_u8 + u8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:108:26 | LL | const _NU8_ADD_P: &u8 = &(1u8 + u8::MAX); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU8_ADD_P` failed here error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:110:24 | LL | const _NU16_ADD: u16 = 1u16 + u16::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU16_ADD` failed here error[E0080]: attempt to compute `1_u16 + u16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:111:28 | LL | const _NU16_ADD_P: &u16 = &(1u16 + u16::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NU16_ADD_P` failed here error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:113:24 | LL | const _NU32_ADD: u32 = 1u32 + u32::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU32_ADD` failed here error[E0080]: attempt to compute `1_u32 + u32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:114:28 | LL | const _NU32_ADD_P: &u32 = &(1u32 + u32::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NU32_ADD_P` failed here error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:116:24 | LL | const _NU64_ADD: u64 = 1u64 + u64::MAX; - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU64_ADD` failed here error[E0080]: attempt to compute `1_u64 + u64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:117:28 | LL | const _NU64_ADD_P: &u64 = &(1u64 + u64::MAX); - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NU64_ADD_P` failed here error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:119:26 | LL | const _NU128_ADD: u128 = 1u128 + u128::MAX; - | ^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `_NU128_ADD` failed here error[E0080]: attempt to compute `1_u128 + u128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:120:30 | LL | const _NU128_ADD_P: &u128 = &(1u128 + u128::MAX); - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_NU128_ADD_P` failed here error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:122:28 | LL | const _NISIZE_ADD: isize = 1isize + isize::MAX; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_ADD` failed here error[E0080]: attempt to compute `1_isize + isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:123:32 | LL | const _NISIZE_ADD_P: &isize = &(1isize + isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_ADD_P` failed here error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:125:28 | LL | const _NUSIZE_ADD: usize = 1usize + usize::MAX; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_ADD` failed here error[E0080]: attempt to compute `1_usize + usize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:126:32 | LL | const _NUSIZE_ADD_P: &usize = &(1usize + usize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_ADD_P` failed here error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:129:22 | LL | const _NI8_SUB: i8 = -5i8 - i8::MAX; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI8_SUB` failed here error[E0080]: attempt to compute `-5_i8 - i8::MAX`, which would overflow --> $DIR/overflowing-consts.rs:130:26 | LL | const _NI8_SUB_P: &i8 = &(-5i8 - i8::MAX); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NI8_SUB_P` failed here error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:132:24 | LL | const _NI16_SUB: i16 = -5i16 - i16::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NI16_SUB` failed here error[E0080]: attempt to compute `-5_i16 - i16::MAX`, which would overflow --> $DIR/overflowing-consts.rs:133:28 | LL | const _NI16_SUB_P: &i16 = &(-5i16 - i16::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `_NI16_SUB_P` failed here error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:135:24 | LL | const _NI32_SUB: i32 = -5i32 - i32::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NI32_SUB` failed here error[E0080]: attempt to compute `-5_i32 - i32::MAX`, which would overflow --> $DIR/overflowing-consts.rs:136:28 | LL | const _NI32_SUB_P: &i32 = &(-5i32 - i32::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `_NI32_SUB_P` failed here error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:138:24 | LL | const _NI64_SUB: i64 = -5i64 - i64::MAX; - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NI64_SUB` failed here error[E0080]: attempt to compute `-5_i64 - i64::MAX`, which would overflow --> $DIR/overflowing-consts.rs:139:28 | LL | const _NI64_SUB_P: &i64 = &(-5i64 - i64::MAX); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `_NI64_SUB_P` failed here error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:141:26 | LL | const _NI128_SUB: i128 = -5i128 - i128::MAX; - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `_NI128_SUB` failed here error[E0080]: attempt to compute `-5_i128 - i128::MAX`, which would overflow --> $DIR/overflowing-consts.rs:142:30 | LL | const _NI128_SUB_P: &i128 = &(-5i128 - i128::MAX); - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^ evaluation of `_NI128_SUB_P` failed here error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:144:22 | LL | const _NU8_SUB: u8 = 1u8 - 5; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NU8_SUB` failed here error[E0080]: attempt to compute `1_u8 - 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:145:26 | LL | const _NU8_SUB_P: &u8 = &(1u8 - 5); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU8_SUB_P` failed here error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:147:24 | LL | const _NU16_SUB: u16 = 1u16 - 5; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU16_SUB` failed here error[E0080]: attempt to compute `1_u16 - 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:148:28 | LL | const _NU16_SUB_P: &u16 = &(1u16 - 5); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_SUB_P` failed here error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:150:24 | LL | const _NU32_SUB: u32 = 1u32 - 5; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU32_SUB` failed here error[E0080]: attempt to compute `1_u32 - 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:151:28 | LL | const _NU32_SUB_P: &u32 = &(1u32 - 5); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_SUB_P` failed here error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:153:24 | LL | const _NU64_SUB: u64 = 1u64 - 5; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU64_SUB` failed here error[E0080]: attempt to compute `1_u64 - 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:154:28 | LL | const _NU64_SUB_P: &u64 = &(1u64 - 5); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_SUB_P` failed here error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:156:26 | LL | const _NU128_SUB: u128 = 1u128 - 5; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU128_SUB` failed here error[E0080]: attempt to compute `1_u128 - 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:157:30 | LL | const _NU128_SUB_P: &u128 = &(1u128 - 5); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NU128_SUB_P` failed here error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:159:28 | LL | const _NISIZE_SUB: isize = -5isize - isize::MAX; - | ^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_SUB` failed here error[E0080]: attempt to compute `-5_isize - isize::MAX`, which would overflow --> $DIR/overflowing-consts.rs:160:32 | LL | const _NISIZE_SUB_P: &isize = &(-5isize - isize::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_SUB_P` failed here error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:162:28 | LL | const _NUSIZE_SUB: usize = 1usize - 5; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NUSIZE_SUB` failed here error[E0080]: attempt to compute `1_usize - 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:163:32 | LL | const _NUSIZE_SUB_P: &usize = &(1usize - 5); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NUSIZE_SUB_P` failed here error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow --> $DIR/overflowing-consts.rs:166:22 | LL | const _NI8_MUL: i8 = i8::MAX * 5; - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NI8_MUL` failed here error[E0080]: attempt to compute `i8::MAX * 5_i8`, which would overflow --> $DIR/overflowing-consts.rs:167:26 | LL | const _NI8_MUL_P: &i8 = &(i8::MAX * 5); - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NI8_MUL_P` failed here error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow --> $DIR/overflowing-consts.rs:169:24 | LL | const _NI16_MUL: i16 = i16::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI16_MUL` failed here error[E0080]: attempt to compute `i16::MAX * 5_i16`, which would overflow --> $DIR/overflowing-consts.rs:170:28 | LL | const _NI16_MUL_P: &i16 = &(i16::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI16_MUL_P` failed here error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow --> $DIR/overflowing-consts.rs:172:24 | LL | const _NI32_MUL: i32 = i32::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI32_MUL` failed here error[E0080]: attempt to compute `i32::MAX * 5_i32`, which would overflow --> $DIR/overflowing-consts.rs:173:28 | LL | const _NI32_MUL_P: &i32 = &(i32::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI32_MUL_P` failed here error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow --> $DIR/overflowing-consts.rs:175:24 | LL | const _NI64_MUL: i64 = i64::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI64_MUL` failed here error[E0080]: attempt to compute `i64::MAX * 5_i64`, which would overflow --> $DIR/overflowing-consts.rs:176:28 | LL | const _NI64_MUL_P: &i64 = &(i64::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI64_MUL_P` failed here error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow --> $DIR/overflowing-consts.rs:178:26 | LL | const _NI128_MUL: i128 = i128::MAX * 5; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NI128_MUL` failed here error[E0080]: attempt to compute `i128::MAX * 5_i128`, which would overflow --> $DIR/overflowing-consts.rs:179:30 | LL | const _NI128_MUL_P: &i128 = &(i128::MAX * 5); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NI128_MUL_P` failed here error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:181:22 | LL | const _NU8_MUL: u8 = u8::MAX * 5; - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NU8_MUL` failed here error[E0080]: attempt to compute `u8::MAX * 5_u8`, which would overflow --> $DIR/overflowing-consts.rs:182:26 | LL | const _NU8_MUL_P: &u8 = &(u8::MAX * 5); - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NU8_MUL_P` failed here error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:184:24 | LL | const _NU16_MUL: u16 = u16::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU16_MUL` failed here error[E0080]: attempt to compute `u16::MAX * 5_u16`, which would overflow --> $DIR/overflowing-consts.rs:185:28 | LL | const _NU16_MUL_P: &u16 = &(u16::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU16_MUL_P` failed here error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:187:24 | LL | const _NU32_MUL: u32 = u32::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU32_MUL` failed here error[E0080]: attempt to compute `u32::MAX * 5_u32`, which would overflow --> $DIR/overflowing-consts.rs:188:28 | LL | const _NU32_MUL_P: &u32 = &(u32::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU32_MUL_P` failed here error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:190:24 | LL | const _NU64_MUL: u64 = u64::MAX * 5; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NU64_MUL` failed here error[E0080]: attempt to compute `u64::MAX * 5_u64`, which would overflow --> $DIR/overflowing-consts.rs:191:28 | LL | const _NU64_MUL_P: &u64 = &(u64::MAX * 5); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NU64_MUL_P` failed here error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:193:26 | LL | const _NU128_MUL: u128 = u128::MAX * 5; - | ^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^ evaluation of `_NU128_MUL` failed here error[E0080]: attempt to compute `u128::MAX * 5_u128`, which would overflow --> $DIR/overflowing-consts.rs:194:30 | LL | const _NU128_MUL_P: &u128 = &(u128::MAX * 5); - | ^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^ evaluation of `_NU128_MUL_P` failed here error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow --> $DIR/overflowing-consts.rs:196:28 | LL | const _NISIZE_MUL: isize = isize::MAX * 5; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NISIZE_MUL` failed here error[E0080]: attempt to compute `isize::MAX * 5_isize`, which would overflow --> $DIR/overflowing-consts.rs:197:32 | LL | const _NISIZE_MUL_P: &isize = &(isize::MAX * 5); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NISIZE_MUL_P` failed here error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:199:28 | LL | const _NUSIZE_MUL: usize = usize::MAX * 5; - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NUSIZE_MUL` failed here error[E0080]: attempt to compute `usize::MAX * 5_usize`, which would overflow --> $DIR/overflowing-consts.rs:200:32 | LL | const _NUSIZE_MUL_P: &usize = &(usize::MAX * 5); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `_NUSIZE_MUL_P` failed here error[E0080]: attempt to divide `1_i8` by zero --> $DIR/overflowing-consts.rs:203:22 | LL | const _NI8_DIV: i8 = 1i8 / 0; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NI8_DIV` failed here error[E0080]: attempt to divide `1_i8` by zero --> $DIR/overflowing-consts.rs:204:26 | LL | const _NI8_DIV_P: &i8 = &(1i8 / 0); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NI8_DIV_P` failed here error[E0080]: attempt to divide `1_i16` by zero --> $DIR/overflowing-consts.rs:206:24 | LL | const _NI16_DIV: i16 = 1i16 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI16_DIV` failed here error[E0080]: attempt to divide `1_i16` by zero --> $DIR/overflowing-consts.rs:207:28 | LL | const _NI16_DIV_P: &i16 = &(1i16 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI16_DIV_P` failed here error[E0080]: attempt to divide `1_i32` by zero --> $DIR/overflowing-consts.rs:209:24 | LL | const _NI32_DIV: i32 = 1i32 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI32_DIV` failed here error[E0080]: attempt to divide `1_i32` by zero --> $DIR/overflowing-consts.rs:210:28 | LL | const _NI32_DIV_P: &i32 = &(1i32 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI32_DIV_P` failed here error[E0080]: attempt to divide `1_i64` by zero --> $DIR/overflowing-consts.rs:212:24 | LL | const _NI64_DIV: i64 = 1i64 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI64_DIV` failed here error[E0080]: attempt to divide `1_i64` by zero --> $DIR/overflowing-consts.rs:213:28 | LL | const _NI64_DIV_P: &i64 = &(1i64 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI64_DIV_P` failed here error[E0080]: attempt to divide `1_i128` by zero --> $DIR/overflowing-consts.rs:215:26 | LL | const _NI128_DIV: i128 = 1i128 / 0; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NI128_DIV` failed here error[E0080]: attempt to divide `1_i128` by zero --> $DIR/overflowing-consts.rs:216:30 | LL | const _NI128_DIV_P: &i128 = &(1i128 / 0); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NI128_DIV_P` failed here error[E0080]: attempt to divide `1_u8` by zero --> $DIR/overflowing-consts.rs:218:22 | LL | const _NU8_DIV: u8 = 1u8 / 0; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NU8_DIV` failed here error[E0080]: attempt to divide `1_u8` by zero --> $DIR/overflowing-consts.rs:219:26 | LL | const _NU8_DIV_P: &u8 = &(1u8 / 0); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU8_DIV_P` failed here error[E0080]: attempt to divide `1_u16` by zero --> $DIR/overflowing-consts.rs:221:24 | LL | const _NU16_DIV: u16 = 1u16 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU16_DIV` failed here error[E0080]: attempt to divide `1_u16` by zero --> $DIR/overflowing-consts.rs:222:28 | LL | const _NU16_DIV_P: &u16 = &(1u16 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_DIV_P` failed here error[E0080]: attempt to divide `1_u32` by zero --> $DIR/overflowing-consts.rs:224:24 | LL | const _NU32_DIV: u32 = 1u32 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU32_DIV` failed here error[E0080]: attempt to divide `1_u32` by zero --> $DIR/overflowing-consts.rs:225:28 | LL | const _NU32_DIV_P: &u32 = &(1u32 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_DIV_P` failed here error[E0080]: attempt to divide `1_u64` by zero --> $DIR/overflowing-consts.rs:227:24 | LL | const _NU64_DIV: u64 = 1u64 / 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU64_DIV` failed here error[E0080]: attempt to divide `1_u64` by zero --> $DIR/overflowing-consts.rs:228:28 | LL | const _NU64_DIV_P: &u64 = &(1u64 / 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_DIV_P` failed here error[E0080]: attempt to divide `1_u128` by zero --> $DIR/overflowing-consts.rs:230:26 | LL | const _NU128_DIV: u128 = 1u128 / 0; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU128_DIV` failed here error[E0080]: attempt to divide `1_u128` by zero --> $DIR/overflowing-consts.rs:231:30 | LL | const _NU128_DIV_P: &u128 = &(1u128 / 0); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NU128_DIV_P` failed here error[E0080]: attempt to divide `1_isize` by zero --> $DIR/overflowing-consts.rs:233:28 | LL | const _NISIZE_DIV: isize = 1isize / 0; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NISIZE_DIV` failed here error[E0080]: attempt to divide `1_isize` by zero --> $DIR/overflowing-consts.rs:234:32 | LL | const _NISIZE_DIV_P: &isize = &(1isize / 0); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NISIZE_DIV_P` failed here error[E0080]: attempt to divide `1_usize` by zero --> $DIR/overflowing-consts.rs:236:28 | LL | const _NUSIZE_DIV: usize = 1usize / 0; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NUSIZE_DIV` failed here error[E0080]: attempt to divide `1_usize` by zero --> $DIR/overflowing-consts.rs:237:32 | LL | const _NUSIZE_DIV_P: &usize = &(1usize / 0); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NUSIZE_DIV_P` failed here error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero --> $DIR/overflowing-consts.rs:240:22 | LL | const _NI8_MOD: i8 = 1i8 % 0; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NI8_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i8` with a divisor of zero --> $DIR/overflowing-consts.rs:241:26 | LL | const _NI8_MOD_P: &i8 = &(1i8 % 0); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NI8_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero --> $DIR/overflowing-consts.rs:243:24 | LL | const _NI16_MOD: i16 = 1i16 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI16_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i16` with a divisor of zero --> $DIR/overflowing-consts.rs:244:28 | LL | const _NI16_MOD_P: &i16 = &(1i16 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI16_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero --> $DIR/overflowing-consts.rs:246:24 | LL | const _NI32_MOD: i32 = 1i32 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI32_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i32` with a divisor of zero --> $DIR/overflowing-consts.rs:247:28 | LL | const _NI32_MOD_P: &i32 = &(1i32 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI32_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero --> $DIR/overflowing-consts.rs:249:24 | LL | const _NI64_MOD: i64 = 1i64 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NI64_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i64` with a divisor of zero --> $DIR/overflowing-consts.rs:250:28 | LL | const _NI64_MOD_P: &i64 = &(1i64 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NI64_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero --> $DIR/overflowing-consts.rs:252:26 | LL | const _NI128_MOD: i128 = 1i128 % 0; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NI128_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_i128` with a divisor of zero --> $DIR/overflowing-consts.rs:253:30 | LL | const _NI128_MOD_P: &i128 = &(1i128 % 0); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NI128_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero --> $DIR/overflowing-consts.rs:255:22 | LL | const _NU8_MOD: u8 = 1u8 % 0; - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `_NU8_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u8` with a divisor of zero --> $DIR/overflowing-consts.rs:256:26 | LL | const _NU8_MOD_P: &u8 = &(1u8 % 0); - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU8_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero --> $DIR/overflowing-consts.rs:258:24 | LL | const _NU16_MOD: u16 = 1u16 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU16_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u16` with a divisor of zero --> $DIR/overflowing-consts.rs:259:28 | LL | const _NU16_MOD_P: &u16 = &(1u16 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU16_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero --> $DIR/overflowing-consts.rs:261:24 | LL | const _NU32_MOD: u32 = 1u32 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU32_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u32` with a divisor of zero --> $DIR/overflowing-consts.rs:262:28 | LL | const _NU32_MOD_P: &u32 = &(1u32 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU32_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero --> $DIR/overflowing-consts.rs:264:24 | LL | const _NU64_MOD: u64 = 1u64 % 0; - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_NU64_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u64` with a divisor of zero --> $DIR/overflowing-consts.rs:265:28 | LL | const _NU64_MOD_P: &u64 = &(1u64 % 0); - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NU64_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero --> $DIR/overflowing-consts.rs:267:26 | LL | const _NU128_MOD: u128 = 1u128 % 0; - | ^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^ evaluation of `_NU128_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_u128` with a divisor of zero --> $DIR/overflowing-consts.rs:268:30 | LL | const _NU128_MOD_P: &u128 = &(1u128 % 0); - | ^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^ evaluation of `_NU128_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero --> $DIR/overflowing-consts.rs:270:28 | LL | const _NISIZE_MOD: isize = 1isize % 0; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NISIZE_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_isize` with a divisor of zero --> $DIR/overflowing-consts.rs:271:32 | LL | const _NISIZE_MOD_P: &isize = &(1isize % 0); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NISIZE_MOD_P` failed here error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero --> $DIR/overflowing-consts.rs:273:28 | LL | const _NUSIZE_MOD: usize = 1usize % 0; - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `_NUSIZE_MOD` failed here error[E0080]: attempt to calculate the remainder of `1_usize` with a divisor of zero --> $DIR/overflowing-consts.rs:274:32 | LL | const _NUSIZE_MOD_P: &usize = &(1usize % 0); - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NUSIZE_MOD_P` failed here error[E0080]: index out of bounds: the length is 3 but the index is 4 --> $DIR/overflowing-consts.rs:277:24 | LL | const _NI32_OOB: i32 = [1, 2, 3][4]; - | ^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^ evaluation of `_NI32_OOB` failed here error[E0080]: index out of bounds: the length is 3 but the index is 4 --> $DIR/overflowing-consts.rs:278:28 | LL | const _NI32_OOB_P: &i32 = &([1, 2, 3][4]); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `_NI32_OOB_P` failed here error: aborting due to 170 previous errors diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr index 6c09a1faed2..a5a50c580d0 100644 --- a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr +++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr @@ -2,7 +2,7 @@ error[E0080]: tried to allocate more memory than available to compiler --> $DIR/promoted_running_out_of_memory_issue-130687.rs:13:32 | LL | const _: &'static Data = &Data([0; (1 << 47) - 1]); - | ^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/promoted_size_overflow.stderr b/tests/ui/consts/promoted_size_overflow.stderr index 226c78ec01b..529b232c77c 100644 --- a/tests/ui/consts/promoted_size_overflow.stderr +++ b/tests/ui/consts/promoted_size_overflow.stderr @@ -2,7 +2,7 @@ error[E0080]: values of the type `[u8; 4611686018427387903]` are too big for the --> $DIR/promoted_size_overflow.rs:3:29 | LL | const _: &'static [Data] = &[]; - | ^^ evaluation of constant value failed here + | ^^ evaluation of `_` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.stderr b/tests/ui/consts/qualif-indirect-mutation-fail.stderr index 6cd7741103f..79724ee8d6a 100644 --- a/tests/ui/consts/qualif-indirect-mutation-fail.stderr +++ b/tests/ui/consts/qualif-indirect-mutation-fail.stderr @@ -11,7 +11,7 @@ error[E0080]: calling non-const function ` as Drop>::drop` --> $DIR/qualif-indirect-mutation-fail.rs:18:1 | LL | }; - | ^ evaluation of constant value failed here + | ^ evaluation of `A1` failed inside this call | note: inside `drop_in_place::> - shim(Some(Option))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -32,7 +32,7 @@ error[E0080]: calling non-const function ` as Drop>::drop` --> $DIR/qualif-indirect-mutation-fail.rs:29:1 | LL | }; - | ^ evaluation of constant value failed here + | ^ evaluation of `A2` failed inside this call | note: inside `drop_in_place::> - shim(Some(Option))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/recursive-zst-static.default.stderr b/tests/ui/consts/recursive-zst-static.default.stderr index 80661825d53..fee33a892d0 100644 --- a/tests/ui/consts/recursive-zst-static.default.stderr +++ b/tests/ui/consts/recursive-zst-static.default.stderr @@ -2,7 +2,7 @@ error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; - | ^^^ evaluation of static initializer failed here + | ^^^ evaluation of `FOO` failed here error[E0391]: cycle detected when evaluating initializer of static `A` --> $DIR/recursive-zst-static.rs:13:16 diff --git a/tests/ui/consts/recursive-zst-static.unleash.stderr b/tests/ui/consts/recursive-zst-static.unleash.stderr index 80661825d53..fee33a892d0 100644 --- a/tests/ui/consts/recursive-zst-static.unleash.stderr +++ b/tests/ui/consts/recursive-zst-static.unleash.stderr @@ -2,7 +2,7 @@ error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; - | ^^^ evaluation of static initializer failed here + | ^^^ evaluation of `FOO` failed here error[E0391]: cycle detected when evaluating initializer of static `A` --> $DIR/recursive-zst-static.rs:13:16 diff --git a/tests/ui/consts/recursive.stderr b/tests/ui/consts/recursive.stderr index 97fa9e7e75e..a382fabf7b7 100644 --- a/tests/ui/consts/recursive.stderr +++ b/tests/ui/consts/recursive.stderr @@ -13,7 +13,7 @@ error[E0080]: reached the configured maximum number of stack frames --> $DIR/recursive.rs:7:15 | LL | const X: () = f(1); - | ^^^^ evaluation of constant value failed here + | ^^^^ evaluation of `X` failed inside this call | note: [... 126 additional calls inside `f::` ...] --> $DIR/recursive.rs:4:5 diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr index b14c9aff7ba..12c5acd02a4 100644 --- a/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr @@ -2,7 +2,7 @@ error[E0080]: entering unreachable code --> $DIR/interpret-in-promoted.rs:15:28 | LL | let _x: &'static () = &ub(); - | ^^^^ evaluation of constant value failed here + | ^^^^ evaluation of `FOO` failed inside this call | note: inside `ub` --> $DIR/interpret-in-promoted.rs:9:5 diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr b/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr index b14c9aff7ba..12c5acd02a4 100644 --- a/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr @@ -2,7 +2,7 @@ error[E0080]: entering unreachable code --> $DIR/interpret-in-promoted.rs:15:28 | LL | let _x: &'static () = &ub(); - | ^^^^ evaluation of constant value failed here + | ^^^^ evaluation of `FOO` failed inside this call | note: inside `ub` --> $DIR/interpret-in-promoted.rs:9:5 diff --git a/tests/ui/consts/slice-index-overflow-issue-130284.stderr b/tests/ui/consts/slice-index-overflow-issue-130284.stderr index 641aed349dd..63c355b4b0f 100644 --- a/tests/ui/consts/slice-index-overflow-issue-130284.stderr +++ b/tests/ui/consts/slice-index-overflow-issue-130284.stderr @@ -2,7 +2,7 @@ error[E0080]: overflowing pointer arithmetic: the total offset in bytes does not --> $DIR/slice-index-overflow-issue-130284.rs:7:20 | LL | let _ice = (*fat)[usize::MAX - 1]; - | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `C` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.stderr index 49b35dacd3a..556a4d956ed 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref2.stderr @@ -2,7 +2,7 @@ error[E0080]: modifying a static's initial value from another static's initializ --> $DIR/static_mut_containing_mut_ref2.rs:6:5 | LL | *(&mut STDERR_BUFFER_SPACE) = 42; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `STDERR_BUFFER` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/static_mut_containing_mut_ref3.stderr b/tests/ui/consts/static_mut_containing_mut_ref3.stderr index 71d701434a3..b8ad2310a78 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref3.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref3.stderr @@ -2,7 +2,7 @@ error[E0080]: modifying a static's initial value from another static's initializ --> $DIR/static_mut_containing_mut_ref3.rs:3:31 | LL | static mut BAR: () = unsafe { FOO.0 = 99; }; - | ^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^ evaluation of `BAR` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/uninhabited-const-issue-61744.rs b/tests/ui/consts/uninhabited-const-issue-61744.rs index 698245b5cb8..56f0939ef18 100644 --- a/tests/ui/consts/uninhabited-const-issue-61744.rs +++ b/tests/ui/consts/uninhabited-const-issue-61744.rs @@ -11,7 +11,7 @@ pub const unsafe fn hint_unreachable() -> ! { trait Const { const CONSTANT: i32 = unsafe { fake_type() }; //~ ERROR reached the configured maximum number of stack frames - //~^ NOTE evaluation of `::CONSTANT` failed here + //~^ NOTE evaluation of `::CONSTANT` failed inside this call } impl Const for T {} diff --git a/tests/ui/consts/uninhabited-const-issue-61744.stderr b/tests/ui/consts/uninhabited-const-issue-61744.stderr index f13f6126e94..cae4f8c3323 100644 --- a/tests/ui/consts/uninhabited-const-issue-61744.stderr +++ b/tests/ui/consts/uninhabited-const-issue-61744.stderr @@ -2,7 +2,7 @@ error[E0080]: reached the configured maximum number of stack frames --> $DIR/uninhabited-const-issue-61744.rs:13:36 | LL | const CONSTANT: i32 = unsafe { fake_type() }; - | ^^^^^^^^^^^ evaluation of `::CONSTANT` failed here + | ^^^^^^^^^^^ evaluation of `::CONSTANT` failed inside this call | note: inside `fake_type::` --> $DIR/uninhabited-const-issue-61744.rs:5:5 diff --git a/tests/ui/consts/write-to-static-mut-in-static.stderr b/tests/ui/consts/write-to-static-mut-in-static.stderr index c98c7d895fc..bb5e217afb9 100644 --- a/tests/ui/consts/write-to-static-mut-in-static.stderr +++ b/tests/ui/consts/write-to-static-mut-in-static.stderr @@ -2,13 +2,13 @@ error[E0080]: modifying a static's initial value from another static's initializ --> $DIR/write-to-static-mut-in-static.rs:2:33 | LL | pub static mut B: () = unsafe { A = 1; }; - | ^^^^^ evaluation of static initializer failed here + | ^^^^^ evaluation of `B` failed here error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/write-to-static-mut-in-static.rs:7:21 | LL | pub static D: u32 = D; - | ^ evaluation of static initializer failed here + | ^ evaluation of `D` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/enum-discriminant/eval-error.stderr b/tests/ui/enum-discriminant/eval-error.stderr index b4061d7777b..c29d258a90b 100644 --- a/tests/ui/enum-discriminant/eval-error.stderr +++ b/tests/ui/enum-discriminant/eval-error.stderr @@ -49,7 +49,7 @@ error[E0080]: the type `Foo` has an unknown layout --> $DIR/eval-error.rs:9:30 | LL | let _: Option = None; - | ^^^^ evaluation of constant value failed here + | ^^^^ evaluation of `Bar::Boo::{constant#0}` failed here error: aborting due to 5 previous errors diff --git a/tests/ui/error-codes/E0080.stderr b/tests/ui/error-codes/E0080.stderr index 431d4e04454..c78454620d1 100644 --- a/tests/ui/error-codes/E0080.stderr +++ b/tests/ui/error-codes/E0080.stderr @@ -2,13 +2,13 @@ error[E0080]: attempt to shift left by `500_i32`, which would overflow --> $DIR/E0080.rs:2:9 | LL | X = (1 << 500), - | ^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^ evaluation of `Enum::X::{constant#0}` failed here error[E0080]: attempt to divide `1_isize` by zero --> $DIR/E0080.rs:3:9 | LL | Y = (1 / 0), - | ^^^^^^^ evaluation of constant value failed here + | ^^^^^^^ evaluation of `Enum::Y::{constant#0}` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr b/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr index 2d558e9a561..25e30397c83 100644 --- a/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr +++ b/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr @@ -2,7 +2,7 @@ error[E0080]: reached the configured maximum number of stack frames --> $DIR/ctfe-id-unlimited.rs:28:20 | LL | const ID_ED: u32 = rec_id(ORIGINAL); - | ^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^ evaluation of `ID_ED` failed inside this call | note: inside `rec_id` --> $DIR/ctfe-id-unlimited.rs:21:5 diff --git a/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs index bf32232cee3..26fb7b16a55 100644 --- a/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs +++ b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs @@ -10,7 +10,7 @@ const fn g() { //~^ NOTE in this expansion of panic! } -const _: () = f(); //~ NOTE evaluation of constant value failed +const _: () = f(); //~ NOTE failed inside this call //~^ ERROR explicit panic fn main() {} diff --git a/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr index 457290b76b8..380c2bfb98c 100644 --- a/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr +++ b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/ctfe-tail-call-panic.rs:13:15 | LL | const _: () = f(); - | ^^^ evaluation of constant value failed here + | ^^^ evaluation of `_` failed inside this call | note: inside `g` --> $DIR/ctfe-tail-call-panic.rs:9:5 diff --git a/tests/ui/extern/issue-28324.stderr b/tests/ui/extern/issue-28324.stderr index 89dfab945be..4637163bc5c 100644 --- a/tests/ui/extern/issue-28324.stderr +++ b/tests/ui/extern/issue-28324.stderr @@ -2,7 +2,7 @@ error[E0080]: cannot access extern static `error_message_count` --> $DIR/issue-28324.rs:5:23 | LL | pub static BAZ: u32 = *&error_message_count; - | ^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAZ` failed here error[E0133]: use of extern static is unsafe and requires unsafe function or block --> $DIR/issue-28324.rs:5:25 diff --git a/tests/ui/generic-const-items/def-site-eval.fail.stderr b/tests/ui/generic-const-items/def-site-eval.fail.stderr index b8616547390..e39fbdf7802 100644 --- a/tests/ui/generic-const-items/def-site-eval.fail.stderr +++ b/tests/ui/generic-const-items/def-site-eval.fail.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/def-site-eval.rs:13:20 | LL | const _<'_a>: () = panic!(); - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `_` failed here error: aborting due to 1 previous error diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr index a89356fadfd..e5c3bbb0c7d 100644 --- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr +++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr @@ -4,7 +4,7 @@ error[E0080]: entering unreachable code LL | / const UNUSABLE: () = () LL | | where LL | | String: Copy; - | |_________________^ evaluation of constant value failed here + | |_________________^ evaluation of `UNUSABLE` failed here error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/trivially-unsatisfied-bounds-0.rs:11:13 diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr index 3aa26eb1656..a5f6dd980bd 100644 --- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr +++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr @@ -4,7 +4,7 @@ error[E0080]: entering unreachable code LL | / const UNUSED: () = () LL | | where LL | | String: Copy; - | |_________________^ evaluation of constant value failed here + | |_________________^ evaluation of `UNUSED` failed here error: aborting due to 1 previous error diff --git a/tests/ui/infinite/infinite-recursion-const-fn.stderr b/tests/ui/infinite/infinite-recursion-const-fn.stderr index 529bad510c9..f5f6e2a58fd 100644 --- a/tests/ui/infinite/infinite-recursion-const-fn.stderr +++ b/tests/ui/infinite/infinite-recursion-const-fn.stderr @@ -2,7 +2,7 @@ error[E0080]: reached the configured maximum number of stack frames --> $DIR/infinite-recursion-const-fn.rs:9:18 | LL | const ARR: [i32; a()] = [5; 6]; - | ^^^ evaluation of constant value failed here + | ^^^ evaluation of `ARR::{constant#0}` failed inside this call | note: inside `a` --> $DIR/infinite-recursion-const-fn.rs:4:5 diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr index 1d2c263baf1..10f4d8d1a71 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr @@ -2,13 +2,13 @@ error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at --> $DIR/intrinsic-raw_eq-const-bad.rs:4:5 | LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_EQ_PADDING` failed here error[E0080]: unable to turn pointer into integer --> $DIR/intrinsic-raw_eq-const-bad.rs:9:5 | LL | std::intrinsics::raw_eq(&(&0), &(&1)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_EQ_PTR` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -17,7 +17,7 @@ error[E0080]: accessing memory with alignment 1, but alignment 4 is required --> $DIR/intrinsic-raw_eq-const-bad.rs:16:5 | LL | std::intrinsics::raw_eq(aref, aref) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_EQ_NOT_ALIGNED` failed here error: aborting due to 3 previous errors diff --git a/tests/ui/issues/issue-76191.stderr b/tests/ui/issues/issue-76191.stderr index 1f19db49c43..d8b54be88f4 100644 --- a/tests/ui/issues/issue-76191.stderr +++ b/tests/ui/issues/issue-76191.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: explicit panic --> $DIR/issue-76191.rs:8:37 | LL | const RANGE2: RangeInclusive = panic!(); - | ^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^ evaluation of `RANGE2` failed here error[E0308]: mismatched types --> $DIR/issue-76191.rs:14:9 diff --git a/tests/ui/layout/invalid-unsized-const-eval.stderr b/tests/ui/layout/invalid-unsized-const-eval.stderr index 073568883c4..d5a294d11f4 100644 --- a/tests/ui/layout/invalid-unsized-const-eval.stderr +++ b/tests/ui/layout/invalid-unsized-const-eval.stderr @@ -11,7 +11,7 @@ error[E0080]: the type `(dyn Sync, ())` has an unknown layout --> $DIR/invalid-unsized-const-eval.rs:12:1 | LL | static EMPTY_SET: LazyLock = todo!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `EMPTY_SET` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr index e08107f5f8e..1a43fd4ad18 100644 --- a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr +++ b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr @@ -22,7 +22,7 @@ error[E0080]: the type `MySlice<[bool]>` has an unknown layout --> $DIR/invalid-unsized-in-always-sized-tail.rs:15:28 | LL | static CHECK: () = assert!(align_of::() == 1); - | ^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^ evaluation of `CHECK` failed inside this call | note: inside `align_of::` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr index c85c40d5bda..ea29320002b 100644 --- a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr +++ b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr @@ -26,7 +26,7 @@ error[E0080]: the type `ArenaSet, [u8]>` has an unknown layout --> $DIR/issue-unsized-tail-restatic-ice-122488.rs:8:1 | LL | const DATA: *const ArenaSet> = std::ptr::null_mut(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `DATA` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr index fa58b1f8fe4..43fe9e3a7a7 100644 --- a/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr +++ b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr @@ -2,7 +2,7 @@ error[E0080]: the type `Option` has an unknown layout --> $DIR/uncomputable-due-to-trivial-bounds-ice-135138.rs:7:16 | LL | [(); { let _a: Option = None; 0 }]; - | ^^ evaluation of constant value failed here + | ^^ evaluation of `return_str::{constant#0}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/layout/unknown-when-no-type-parameter.rs b/tests/ui/layout/unknown-when-no-type-parameter.rs index 81386feaacf..f787998868d 100644 --- a/tests/ui/layout/unknown-when-no-type-parameter.rs +++ b/tests/ui/layout/unknown-when-no-type-parameter.rs @@ -11,7 +11,7 @@ where [(); size_of::<<() as Project>::Assoc>()]; //~^ ERROR the type `<() as Project>::Assoc` has an unknown layout //~| NOTE inside `std::mem::size_of::<<() as Project>::Assoc>` - //~| NOTE evaluation of constant value failed + //~| NOTE failed inside this call } fn main() {} diff --git a/tests/ui/layout/unknown-when-no-type-parameter.stderr b/tests/ui/layout/unknown-when-no-type-parameter.stderr index f0a64960c6a..9bb42c46ec3 100644 --- a/tests/ui/layout/unknown-when-no-type-parameter.stderr +++ b/tests/ui/layout/unknown-when-no-type-parameter.stderr @@ -2,7 +2,7 @@ error[E0080]: the type `<() as Project>::Assoc` has an unknown layout --> $DIR/unknown-when-no-type-parameter.rs:11:10 | LL | [(); size_of::<<() as Project>::Assoc>()]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `foo::{constant#0}` failed inside this call | note: inside `std::mem::size_of::<<() as Project>::Assoc>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr index 8cf5ce7c22d..fd9eedc9267 100644 --- a/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr +++ b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr @@ -2,7 +2,7 @@ error[E0080]: the type `str` has an unknown layout --> $DIR/unknown-when-ptr-metadata-is-DST.rs:8:16 | LL | [(); { let _a: Option<&str> = None; 0 }]; - | ^^ evaluation of constant value failed here + | ^^ evaluation of `return_str::{constant#0}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr index e0d25742502..b97f770c97f 100644 --- a/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr +++ b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr @@ -2,7 +2,7 @@ error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow --> $DIR/def-site-param-defaults-wf.rs:5:45 | LL | type Alias, const N: usize = { 0 - 1 }> = T; - | ^^^^^ evaluation of constant value failed here + | ^^^^^ evaluation of `Alias::{constant#0}` failed here error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/def-site-param-defaults-wf.rs:5:16 diff --git a/tests/ui/limits/huge-static.stderr b/tests/ui/limits/huge-static.stderr index 63d04b75d99..9073d7b03e9 100644 --- a/tests/ui/limits/huge-static.stderr +++ b/tests/ui/limits/huge-static.stderr @@ -2,13 +2,13 @@ error[E0080]: values of the type `[u8; 2305843009213693952]` are too big for the --> $DIR/huge-static.rs:18:1 | LL | static MY_TOO_BIG_ARRAY_1: TooBigArray = TooBigArray::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `MY_TOO_BIG_ARRAY_1` failed here error[E0080]: values of the type `[u8; 2305843009213693952]` are too big for the target architecture --> $DIR/huge-static.rs:20:1 | LL | static MY_TOO_BIG_ARRAY_2: [u8; HUGE_SIZE] = [0x00; HUGE_SIZE]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `MY_TOO_BIG_ARRAY_2` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/limits/issue-55878.stderr b/tests/ui/limits/issue-55878.stderr index 27357796c18..a529efa2ad0 100644 --- a/tests/ui/limits/issue-55878.stderr +++ b/tests/ui/limits/issue-55878.stderr @@ -2,7 +2,7 @@ error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target a --> $DIR/issue-55878.rs:4:26 | LL | println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main` failed inside this call | note: inside `std::mem::size_of::<[u8; usize::MAX]>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/recursion/recursive-static-definition.stderr b/tests/ui/recursion/recursive-static-definition.stderr index 7063e5c3c66..ce93c41bc67 100644 --- a/tests/ui/recursion/recursive-static-definition.stderr +++ b/tests/ui/recursion/recursive-static-definition.stderr @@ -2,13 +2,13 @@ error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/recursive-static-definition.rs:1:23 | LL | pub static FOO: u32 = FOO; - | ^^^ evaluation of static initializer failed here + | ^^^ evaluation of `FOO` failed here error[E0080]: encountered static that tried to initialize itself with itself --> $DIR/recursive-static-definition.rs:9:23 | LL | pub static BAR: Foo = BAR; - | ^^^ evaluation of static initializer failed here + | ^^^ evaluation of `BAR` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr index 354ca78c7be..d097b809b56 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr @@ -13,7 +13,7 @@ error[E0080]: a cycle occurred during layout computation --> $DIR/stack-overflow-trait-infer-98842.rs:14:1 | LL | const _: *const Foo = 0 as _; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr index 354ca78c7be..d097b809b56 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr @@ -13,7 +13,7 @@ error[E0080]: a cycle occurred during layout computation --> $DIR/stack-overflow-trait-infer-98842.rs:14:1 | LL | const _: *const Foo = 0 as _; - | ^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/statics/issue-14227.stderr b/tests/ui/statics/issue-14227.stderr index 372a06ae1ed..f5ab2314494 100644 --- a/tests/ui/statics/issue-14227.stderr +++ b/tests/ui/statics/issue-14227.stderr @@ -2,7 +2,7 @@ error[E0080]: cannot access extern static `symbol` --> $DIR/issue-14227.rs:4:21 | LL | static CRASH: u32 = symbol; - | ^^^^^^ evaluation of static initializer failed here + | ^^^^^^ evaluation of `CRASH` failed here error[E0133]: use of extern static is unsafe and requires unsafe function or block --> $DIR/issue-14227.rs:4:21 diff --git a/tests/ui/statics/uninhabited-static.stderr b/tests/ui/statics/uninhabited-static.stderr index 60268ad3562..f799a82f139 100644 --- a/tests/ui/statics/uninhabited-static.stderr +++ b/tests/ui/statics/uninhabited-static.stderr @@ -47,13 +47,13 @@ error[E0080]: constructing invalid value: encountered a value of uninhabited typ --> $DIR/uninhabited-static.rs:12:31 | LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `VOID2` failed here error[E0080]: constructing invalid value: encountered a value of uninhabited type `Void` --> $DIR/uninhabited-static.rs:15:32 | LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of static initializer failed here + | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NEVER2` failed here error: aborting due to 6 previous errors diff --git a/tests/ui/structs/default-field-values/invalid-const.stderr b/tests/ui/structs/default-field-values/invalid-const.stderr index f4a74ef9fdc..545783e6c74 100644 --- a/tests/ui/structs/default-field-values/invalid-const.stderr +++ b/tests/ui/structs/default-field-values/invalid-const.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: asdf --> $DIR/invalid-const.rs:5:19 | LL | pub bax: u8 = panic!("asdf"), - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `Bat::bax::{constant#0}` failed here error[E0080]: attempt to compute `130_u8 + 130_u8`, which would overflow --> $DIR/invalid-const.rs:11:19 diff --git a/tests/ui/transmutability/uninhabited.stderr b/tests/ui/transmutability/uninhabited.stderr index 79cd75ce279..4757daec997 100644 --- a/tests/ui/transmutability/uninhabited.stderr +++ b/tests/ui/transmutability/uninhabited.stderr @@ -44,7 +44,7 @@ error[E0080]: evaluation panicked: assertion failed: false --> $DIR/uninhabited.rs:41:9 | LL | assert!(false); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `yawning_void_struct::_` failed here error[E0277]: `()` cannot be safely transmuted into `yawning_void_enum::Void` --> $DIR/uninhabited.rs:71:41 @@ -71,7 +71,7 @@ error[E0080]: evaluation panicked: assertion failed: false --> $DIR/uninhabited.rs:63:9 | LL | assert!(false); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `yawning_void_enum::_` failed here error[E0277]: `u128` cannot be safely transmuted into `DistantVoid` --> $DIR/uninhabited.rs:92:43 @@ -98,7 +98,7 @@ error[E0080]: evaluation panicked: assertion failed: false --> $DIR/uninhabited.rs:87:9 | LL | assert!(false); - | ^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^ evaluation of `distant_void::_` failed here error[E0277]: `Src` cannot be safely transmuted into `issue_126267::Error` --> $DIR/uninhabited.rs:108:42 diff --git a/tests/ui/treat-err-as-bug/err.stderr b/tests/ui/treat-err-as-bug/err.stderr index 3279392e1f4..0052dd75626 100644 --- a/tests/ui/treat-err-as-bug/err.stderr +++ b/tests/ui/treat-err-as-bug/err.stderr @@ -2,7 +2,7 @@ error: internal compiler error[E0080]: attempt to compute `0_u32 - 1_u32`, which --> $DIR/err.rs:9:21 | LL | pub static C: u32 = 0 - 1; - | ^^^^^ evaluation of static initializer failed here + | ^^^^^ evaluation of `C` failed here error: the compiler unexpectedly panicked. this is a bug. diff --git a/tests/ui/type/pattern_types/literals.stderr b/tests/ui/type/pattern_types/literals.stderr index 72c812ed3ba..7ab7b81ac23 100644 --- a/tests/ui/type/pattern_types/literals.stderr +++ b/tests/ui/type/pattern_types/literals.stderr @@ -2,31 +2,31 @@ error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:86:62 | LL | fn empty_range_at_base_type_min() -> pattern_type!(u32 is 0..0) { - | ^ evaluation of constant value failed here + | ^ evaluation of `empty_range_at_base_type_min::{constant#1}` failed here error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:91:63 | LL | fn empty_range_at_base_type_min2() -> pattern_type!(u32 is 0..0) { - | ^ evaluation of constant value failed here + | ^ evaluation of `empty_range_at_base_type_min2::{constant#1}` failed here error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:106:65 | LL | fn wraparound_range_at_base_ty_end() -> pattern_type!(u32 is 1..0) { - | ^ evaluation of constant value failed here + | ^ evaluation of `wraparound_range_at_base_ty_end::{constant#1}` failed here error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:111:66 | LL | fn wraparound_range_at_base_ty_end2() -> pattern_type!(u32 is 1..0) { - | ^ evaluation of constant value failed here + | ^ evaluation of `wraparound_range_at_base_ty_end2::{constant#1}` failed here error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/literals.rs:116:66 | LL | fn wraparound_range_at_base_ty_end3() -> pattern_type!(u32 is 1..0) { - | ^ evaluation of constant value failed here + | ^ evaluation of `wraparound_range_at_base_ty_end3::{constant#1}` failed here error[E0308]: mismatched types --> $DIR/literals.rs:9:5 diff --git a/tests/ui/type/pattern_types/range_patterns.stderr b/tests/ui/type/pattern_types/range_patterns.stderr index bcb602a70dd..7b9e1fe9dd1 100644 --- a/tests/ui/type/pattern_types/range_patterns.stderr +++ b/tests/ui/type/pattern_types/range_patterns.stderr @@ -369,7 +369,7 @@ error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/range_patterns.rs:25:37 | LL | type WRAP = pattern_type!(u32 is 1..0); - | ^ evaluation of constant value failed here + | ^ evaluation of `WRAP::{constant#1}` failed here error: the type has an unknown layout --> $DIR/range_patterns.rs:25:1 diff --git a/tests/ui/type/pattern_types/reverse_range.stderr b/tests/ui/type/pattern_types/reverse_range.stderr index 8f5b86c7db9..6e6e34409a3 100644 --- a/tests/ui/type/pattern_types/reverse_range.stderr +++ b/tests/ui/type/pattern_types/reverse_range.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation panicked: exclusive range end at minimum value of type --> $DIR/reverse_range.rs:7:36 | LL | const NONE: pattern_type!(u8 is 1..0) = unsafe { std::mem::transmute(3_u8) }; - | ^ evaluation of constant value failed here + | ^ evaluation of `NONE::{constant#1}` failed here error: aborting due to 1 previous error diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr index 7ba73aacc24..4f4c16028f6 100644 --- a/tests/ui/type/pattern_types/validity.stderr +++ b/tests/ui/type/pattern_types/validity.stderr @@ -13,13 +13,13 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/validity.rs:13:1 | LL | const BAD_UNINIT: pattern_type!(u32 is 1..) = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_UNINIT` failed here error[E0080]: unable to turn pointer into integer --> $DIR/validity.rs:17:1 | LL | const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(&42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_PTR` failed here | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported @@ -50,7 +50,7 @@ error[E0080]: using uninitialized data, but this operation requires initialized --> $DIR/validity.rs:29:1 | LL | const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of constant value failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `CHAR_UNINIT` failed here error[E0080]: constructing invalid value: encountered 97, but expected something in the range 65..=89 --> $DIR/validity.rs:33:1 -- cgit 1.4.1-3-g733a5 From 8808c9d34b04c8c9404aafaba2aeec4142963fa5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 May 2025 18:37:58 +0200 Subject: intrinsics: use const generic to set atomic ordering --- .../rustc_codegen_cranelift/src/intrinsics/mod.rs | 28 +- compiler/rustc_codegen_ssa/messages.ftl | 8 - compiler/rustc_codegen_ssa/src/errors.rs | 16 - compiler/rustc_codegen_ssa/src/mir/intrinsic.rs | 322 +++---- .../rustc_error_codes/src/error_codes/E0092.md | 15 +- .../rustc_error_codes/src/error_codes/E0093.md | 17 +- .../rustc_error_codes/src/error_codes/E0622.md | 4 +- compiler/rustc_hir_analysis/messages.ftl | 4 - compiler/rustc_hir_analysis/src/check/intrinsic.rs | 59 +- compiler/rustc_hir_analysis/src/errors.rs | 9 - compiler/rustc_span/src/symbol.rs | 16 + library/core/src/intrinsics/mod.rs | 964 ++------------------- library/core/src/sync/atomic.rs | 270 +++--- library/panic_unwind/src/seh.rs | 12 +- src/tools/miri/src/intrinsics/atomic.rs | 153 ++-- .../run-make/atomic-lock-free/atomic_lock_free.rs | 42 +- tests/ui/error-codes/E0092.rs | 6 - tests/ui/error-codes/E0092.stderr | 9 - .../feature-gated-feature-in-macro-arg.stderr | 2 +- tests/ui/intrinsics/auxiliary/cci_intrinsic.rs | 19 +- tests/ui/intrinsics/intrinsic-atomics.rs | 40 +- tests/ui/intrinsics/non-integer-atomic.rs | 52 +- tests/ui/intrinsics/non-integer-atomic.stderr | 88 +- 23 files changed, 667 insertions(+), 1488 deletions(-) delete mode 100644 tests/ui/error-codes/E0092.rs delete mode 100644 tests/ui/error-codes/E0092.stderr diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 27a5df8b152..a0f96d85dc3 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -875,7 +875,6 @@ fn codegen_regular_intrinsic_call<'tcx>( let ptr = ptr.load_scalar(fx); let ty = generic_args.type_at(0); - let _ord = generic_args.const_at(1).to_value(); // FIXME: forward this to cranelift once they support that match ty.kind() { ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => { // FIXME implement 128bit atomics @@ -906,7 +905,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(ty)); ret.write_cvalue(fx, val); } - _ if intrinsic.as_str().starts_with("atomic_store") => { + sym::atomic_store => { intrinsic_args!(fx, args => (ptr, val); intrinsic); let ptr = ptr.load_scalar(fx); @@ -939,7 +938,7 @@ fn codegen_regular_intrinsic_call<'tcx>( fx.bcx.ins().atomic_store(MemFlags::trusted(), val, ptr); } - _ if intrinsic.as_str().starts_with("atomic_xchg") => { + sym::atomic_xchg => { intrinsic_args!(fx, args => (ptr, new); intrinsic); let ptr = ptr.load_scalar(fx); @@ -960,8 +959,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_cxchg") => { - // both atomic_cxchg_* and atomic_cxchgweak_* + sym::atomic_cxchg | sym::atomic_cxchgweak => { intrinsic_args!(fx, args => (ptr, test_old, new); intrinsic); let ptr = ptr.load_scalar(fx); @@ -984,7 +982,7 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, ret_val) } - _ if intrinsic.as_str().starts_with("atomic_xadd") => { + sym::atomic_xadd => { intrinsic_args!(fx, args => (ptr, amount); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1006,7 +1004,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_xsub") => { + sym::atomic_xsub => { intrinsic_args!(fx, args => (ptr, amount); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1028,7 +1026,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_and") => { + sym::atomic_and => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1049,7 +1047,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_or") => { + sym::atomic_or => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1070,7 +1068,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_xor") => { + sym::atomic_xor => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1091,7 +1089,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_nand") => { + sym::atomic_nand => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1112,7 +1110,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_max") => { + sym::atomic_max => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1133,7 +1131,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_umax") => { + sym::atomic_umax => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1154,7 +1152,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_min") => { + sym::atomic_min => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1175,7 +1173,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_umin") => { + sym::atomic_umin => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index acb4cbaa13f..91f6af7fb93 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -8,8 +8,6 @@ codegen_ssa_aix_strip_not_used = using host's `strip` binary to cross-compile to codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$error} -codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering - codegen_ssa_autodiff_without_lto = using the autodiff feature requires using fat-lto codegen_ssa_bare_instruction_set = `#[instruction_set]` requires an argument @@ -206,8 +204,6 @@ codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be m codegen_ssa_missing_features = add the missing features in a `target_feature` attribute -codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering - codegen_ssa_missing_query_depgraph = found CGU-reuse attribute but `-Zquery-dep-graph` was not specified @@ -374,10 +370,6 @@ codegen_ssa_unexpected_parameter_name = unexpected parameter name codegen_ssa_unknown_archive_kind = Don't know how to build archive of type: {$kind} -codegen_ssa_unknown_atomic_operation = unknown atomic operation - -codegen_ssa_unknown_atomic_ordering = unknown ordering in atomic intrinsic - codegen_ssa_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified codegen_ssa_unsupported_instruction_set = target does not support `#[instruction_set]` diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 572d7b1e06a..f843347db92 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -796,22 +796,6 @@ pub(crate) struct ShuffleIndicesEvaluation { pub span: Span, } -#[derive(Diagnostic)] -#[diag(codegen_ssa_missing_memory_ordering)] -pub(crate) struct MissingMemoryOrdering; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_unknown_atomic_ordering)] -pub(crate) struct UnknownAtomicOrdering; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_atomic_compare_exchange)] -pub(crate) struct AtomicCompareExchange; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_unknown_atomic_operation)] -pub(crate) struct UnknownAtomicOperation; - #[derive(Diagnostic)] pub enum InvalidMonomorphization<'tcx> { #[diag(codegen_ssa_invalid_monomorphization_basic_integer_type, code = E0511)] diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 8c6f52084c2..a3f09f64a3e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -8,9 +8,10 @@ use rustc_span::sym; use super::FunctionCx; use super::operand::OperandRef; use super::place::PlaceRef; +use crate::common::{AtomicRmwBinOp, SynchronizationScope}; use crate::errors::InvalidMonomorphization; use crate::traits::*; -use crate::{MemFlags, errors, meth, size_of_val}; +use crate::{MemFlags, meth, size_of_val}; fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, @@ -62,7 +63,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let span = source_info.span; let name = bx.tcx().item_name(instance.def_id()); - let name_str = name.as_str(); let fn_args = instance.args; // If we're swapping something that's *not* an `OperandValue::Ref`, @@ -89,14 +89,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - let ret_llval = |bx: &mut Bx, llval| { - if result.layout.ty.is_bool() { - let val = bx.from_immediate(llval); - bx.store_to_place(val, result.val); - } else if !result.layout.ty.is_unit() { - bx.store_to_place(llval, result.val); - } - Ok(()) + let invalid_monomorphization_int_type = |ty| { + bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty }); + }; + + let parse_atomic_ordering = |ord: ty::Value<'tcx>| { + let discr = ord.valtree.unwrap_branch()[0].unwrap_leaf(); + discr.to_atomic_ordering() }; let llval = match name { @@ -336,184 +335,145 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - // This requires that atomic intrinsics follow a specific naming pattern: - // "atomic_[_]" - name if let Some(atomic) = name_str.strip_prefix("atomic_") => { - use rustc_middle::ty::AtomicOrdering::*; - - use crate::common::{AtomicRmwBinOp, SynchronizationScope}; + sym::atomic_load => { + let ty = fn_args.type_at(0); + if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) { + invalid_monomorphization_int_type(ty); + return Ok(()); + } + let ordering = fn_args.const_at(1).to_value(); + let layout = bx.layout_of(ty); + let source = args[0].immediate(); + bx.atomic_load( + bx.backend_type(layout), + source, + parse_atomic_ordering(ordering), + layout.size, + ) + } + sym::atomic_store => { + let ty = fn_args.type_at(0); + if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) { + invalid_monomorphization_int_type(ty); + return Ok(()); + } + let ordering = fn_args.const_at(1).to_value(); + let size = bx.layout_of(ty).size; + let val = args[1].immediate(); + let ptr = args[0].immediate(); + bx.atomic_store(val, ptr, parse_atomic_ordering(ordering), size); + return Ok(()); + } + sym::atomic_cxchg | sym::atomic_cxchgweak => { + let ty = fn_args.type_at(0); + if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) { + invalid_monomorphization_int_type(ty); + return Ok(()); + } + let succ_ordering = fn_args.const_at(1).to_value(); + let fail_ordering = fn_args.const_at(2).to_value(); + let weak = name == sym::atomic_cxchgweak; + let dst = args[0].immediate(); + let cmp = args[1].immediate(); + let src = args[2].immediate(); + let (val, success) = bx.atomic_cmpxchg( + dst, + cmp, + src, + parse_atomic_ordering(succ_ordering), + parse_atomic_ordering(fail_ordering), + weak, + ); + let val = bx.from_immediate(val); + let success = bx.from_immediate(success); - let invalid_monomorphization = |ty| { - bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerType { - span, - name, - ty, - }); - }; + let dest = result.project_field(bx, 0); + bx.store_to_place(val, dest.val); + let dest = result.project_field(bx, 1); + bx.store_to_place(success, dest.val); - let parse_const_generic_ordering = |ord: ty::Value<'tcx>| { - let discr = ord.valtree.unwrap_branch()[0].unwrap_leaf(); - discr.to_atomic_ordering() + return Ok(()); + } + // These are all AtomicRMW ops + sym::atomic_max | sym::atomic_min => { + let atom_op = if name == sym::atomic_max { + AtomicRmwBinOp::AtomicMax + } else { + AtomicRmwBinOp::AtomicMin }; - // Some intrinsics have the ordering already converted to a const generic parameter, we handle those first. - match name { - sym::atomic_load => { - let ty = fn_args.type_at(0); - let ordering = fn_args.const_at(1).to_value(); - if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) { - invalid_monomorphization(ty); - return Ok(()); - } - let layout = bx.layout_of(ty); - let source = args[0].immediate(); - let llval = bx.atomic_load( - bx.backend_type(layout), - source, - parse_const_generic_ordering(ordering), - layout.size, - ); - - return ret_llval(bx, llval); - } - - // The rest falls back to below. - _ => {} + let ty = fn_args.type_at(0); + if matches!(ty.kind(), ty::Int(_)) { + let ordering = fn_args.const_at(1).to_value(); + let ptr = args[0].immediate(); + let val = args[1].immediate(); + bx.atomic_rmw(atom_op, ptr, val, parse_atomic_ordering(ordering)) + } else { + invalid_monomorphization_int_type(ty); + return Ok(()); } - - let Some((instruction, ordering)) = atomic.split_once('_') else { - bx.sess().dcx().emit_fatal(errors::MissingMemoryOrdering); + } + sym::atomic_umax | sym::atomic_umin => { + let atom_op = if name == sym::atomic_umax { + AtomicRmwBinOp::AtomicUMax + } else { + AtomicRmwBinOp::AtomicUMin }; - let parse_ordering = |bx: &Bx, s| match s { - "relaxed" => Relaxed, - "acquire" => Acquire, - "release" => Release, - "acqrel" => AcqRel, - "seqcst" => SeqCst, - _ => bx.sess().dcx().emit_fatal(errors::UnknownAtomicOrdering), + let ty = fn_args.type_at(0); + if matches!(ty.kind(), ty::Uint(_)) { + let ordering = fn_args.const_at(1).to_value(); + let ptr = args[0].immediate(); + let val = args[1].immediate(); + bx.atomic_rmw(atom_op, ptr, val, parse_atomic_ordering(ordering)) + } else { + invalid_monomorphization_int_type(ty); + return Ok(()); + } + } + sym::atomic_xchg + | sym::atomic_xadd + | sym::atomic_xsub + | sym::atomic_and + | sym::atomic_nand + | sym::atomic_or + | sym::atomic_xor => { + let atom_op = match name { + sym::atomic_xchg => AtomicRmwBinOp::AtomicXchg, + sym::atomic_xadd => AtomicRmwBinOp::AtomicAdd, + sym::atomic_xsub => AtomicRmwBinOp::AtomicSub, + sym::atomic_and => AtomicRmwBinOp::AtomicAnd, + sym::atomic_nand => AtomicRmwBinOp::AtomicNand, + sym::atomic_or => AtomicRmwBinOp::AtomicOr, + sym::atomic_xor => AtomicRmwBinOp::AtomicXor, + _ => unreachable!(), }; - match instruction { - "cxchg" | "cxchgweak" => { - let Some((success, failure)) = ordering.split_once('_') else { - bx.sess().dcx().emit_fatal(errors::AtomicCompareExchange); - }; - let ty = fn_args.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() { - let weak = instruction == "cxchgweak"; - let dst = args[0].immediate(); - let cmp = args[1].immediate(); - let src = args[2].immediate(); - let (val, success) = bx.atomic_cmpxchg( - dst, - cmp, - src, - parse_ordering(bx, success), - parse_ordering(bx, failure), - weak, - ); - let val = bx.from_immediate(val); - let success = bx.from_immediate(success); - - let dest = result.project_field(bx, 0); - bx.store_to_place(val, dest.val); - let dest = result.project_field(bx, 1); - bx.store_to_place(success, dest.val); - } else { - invalid_monomorphization(ty); - } - return Ok(()); - } - - "store" => { - let ty = fn_args.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() { - let size = bx.layout_of(ty).size; - let val = args[1].immediate(); - let ptr = args[0].immediate(); - bx.atomic_store(val, ptr, parse_ordering(bx, ordering), size); - } else { - invalid_monomorphization(ty); - } - return Ok(()); - } - - "fence" => { - bx.atomic_fence( - parse_ordering(bx, ordering), - SynchronizationScope::CrossThread, - ); - return Ok(()); - } - - "singlethreadfence" => { - bx.atomic_fence( - parse_ordering(bx, ordering), - SynchronizationScope::SingleThread, - ); - return Ok(()); - } - - // These are all AtomicRMW ops - "max" | "min" => { - let atom_op = if instruction == "max" { - AtomicRmwBinOp::AtomicMax - } else { - AtomicRmwBinOp::AtomicMin - }; - - let ty = fn_args.type_at(0); - if matches!(ty.kind(), ty::Int(_)) { - let ptr = args[0].immediate(); - let val = args[1].immediate(); - bx.atomic_rmw(atom_op, ptr, val, parse_ordering(bx, ordering)) - } else { - invalid_monomorphization(ty); - return Ok(()); - } - } - "umax" | "umin" => { - let atom_op = if instruction == "umax" { - AtomicRmwBinOp::AtomicUMax - } else { - AtomicRmwBinOp::AtomicUMin - }; - - let ty = fn_args.type_at(0); - if matches!(ty.kind(), ty::Uint(_)) { - let ptr = args[0].immediate(); - let val = args[1].immediate(); - bx.atomic_rmw(atom_op, ptr, val, parse_ordering(bx, ordering)) - } else { - invalid_monomorphization(ty); - return Ok(()); - } - } - op => { - let atom_op = match op { - "xchg" => AtomicRmwBinOp::AtomicXchg, - "xadd" => AtomicRmwBinOp::AtomicAdd, - "xsub" => AtomicRmwBinOp::AtomicSub, - "and" => AtomicRmwBinOp::AtomicAnd, - "nand" => AtomicRmwBinOp::AtomicNand, - "or" => AtomicRmwBinOp::AtomicOr, - "xor" => AtomicRmwBinOp::AtomicXor, - _ => bx.sess().dcx().emit_fatal(errors::UnknownAtomicOperation), - }; - - let ty = fn_args.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() { - let ptr = args[0].immediate(); - let val = args[1].immediate(); - bx.atomic_rmw(atom_op, ptr, val, parse_ordering(bx, ordering)) - } else { - invalid_monomorphization(ty); - return Ok(()); - } - } + let ty = fn_args.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() { + let ordering = fn_args.const_at(1).to_value(); + let ptr = args[0].immediate(); + let val = args[1].immediate(); + bx.atomic_rmw(atom_op, ptr, val, parse_atomic_ordering(ordering)) + } else { + invalid_monomorphization_int_type(ty); + return Ok(()); } } + sym::atomic_fence => { + let ordering = fn_args.const_at(0).to_value(); + bx.atomic_fence(parse_atomic_ordering(ordering), SynchronizationScope::CrossThread); + return Ok(()); + } + + sym::atomic_singlethreadfence => { + let ordering = fn_args.const_at(0).to_value(); + bx.atomic_fence( + parse_atomic_ordering(ordering), + SynchronizationScope::SingleThread, + ); + return Ok(()); + } sym::nontemporal_store => { let dst = args[0].deref(bx.cx()); @@ -556,7 +516,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }; - ret_llval(bx, llval) + if result.layout.ty.is_bool() { + let val = bx.from_immediate(llval); + bx.store_to_place(val, result.val); + } else if !result.layout.ty.is_unit() { + bx.store_to_place(llval, result.val); + } + Ok(()) } } diff --git a/compiler/rustc_error_codes/src/error_codes/E0092.md b/compiler/rustc_error_codes/src/error_codes/E0092.md index be459d040c2..9c63798ded7 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0092.md +++ b/compiler/rustc_error_codes/src/error_codes/E0092.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + An undefined atomic operation function was declared. Erroneous code example: -```compile_fail,E0092 +```ignore (no longer emitted) #![feature(intrinsics)] #![allow(internal_features)] @@ -12,13 +14,4 @@ unsafe fn atomic_foo(); // error: unrecognized atomic operation ``` Please check you didn't make a mistake in the function's name. All intrinsic -functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in -`library/core/src/intrinsics.rs` in the Rust source code. Example: - -``` -#![feature(intrinsics)] -#![allow(internal_features)] - -#[rustc_intrinsic] -unsafe fn atomic_fence_seqcst(); // ok! -``` +functions are defined in `library/core/src/intrinsics` in the Rust source code. diff --git a/compiler/rustc_error_codes/src/error_codes/E0093.md b/compiler/rustc_error_codes/src/error_codes/E0093.md index 9929a069927..3552c2db4cc 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0093.md +++ b/compiler/rustc_error_codes/src/error_codes/E0093.md @@ -17,19 +17,4 @@ fn main() { ``` Please check you didn't make a mistake in the function's name. All intrinsic -functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in -`library/core/src/intrinsics.rs` in the Rust source code. Example: - -``` -#![feature(intrinsics)] -#![allow(internal_features)] - -#[rustc_intrinsic] -unsafe fn atomic_fence_seqcst(); // ok! - -fn main() { - unsafe { - atomic_fence_seqcst(); - } -} -``` +functions are defined in `library/core/src/intrinsics` in the Rust source code. diff --git a/compiler/rustc_error_codes/src/error_codes/E0622.md b/compiler/rustc_error_codes/src/error_codes/E0622.md index 9b8131a061e..cc66e067990 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0622.md +++ b/compiler/rustc_error_codes/src/error_codes/E0622.md @@ -4,7 +4,7 @@ An intrinsic was declared without being a function. Erroneous code example: -```no_run +```ignore (no longer emitted) #![feature(intrinsics)] #![allow(internal_features)] @@ -21,7 +21,7 @@ An intrinsic is a function available for use in a given programming language whose implementation is handled specially by the compiler. In order to fix this error, just declare a function. Example: -```no_run +```ignore (no longer emitted) #![feature(intrinsics)] #![allow(internal_features)] diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index a3a0e276f74..4fcd9f8a646 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -565,10 +565,6 @@ hir_analysis_unconstrained_generic_parameter = the {$param_def_kind} `{$param_na hir_analysis_unconstrained_opaque_type = unconstrained opaque type .note = `{$name}` must be used in combination with a concrete type within the same {$what} -hir_analysis_unrecognized_atomic_operation = - unrecognized atomic operation function: `{$op}` - .label = unrecognized atomic operation - hir_analysis_unrecognized_intrinsic_function = unrecognized intrinsic function: `{$name}` .label = unrecognized intrinsic diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 234520c1583..d8080d2537b 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -9,10 +9,7 @@ use rustc_span::def_id::LocalDefId; use rustc_span::{Span, Symbol, sym}; use crate::check::check_function_signature; -use crate::errors::{ - UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction, - WrongNumberOfGenericArgumentsToIntrinsic, -}; +use crate::errors::{UnrecognizedIntrinsicFunction, WrongNumberOfGenericArgumentsToIntrinsic}; fn equate_intrinsic_type<'tcx>( tcx: TyCtxt<'tcx>, @@ -172,7 +169,6 @@ pub(crate) fn check_intrinsic_type( Ty::new_error_with_message(tcx, span, "expected param") } }; - let name_str = intrinsic_name.as_str(); let bound_vars = tcx.mk_bound_variable_kinds(&[ ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon), @@ -198,32 +194,9 @@ pub(crate) fn check_intrinsic_type( (Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty) }; - let (n_tps, n_lts, n_cts, inputs, output, safety) = if name_str.starts_with("atomic_") { - let split: Vec<&str> = name_str.split('_').collect(); - assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format"); - - // Each atomic op has variants with different suffixes (`_seq_cst`, `_acquire`, etc.). Use - // string ops to strip the suffixes, because the variants all get the same treatment here. - let (n_tps, n_cts, inputs, output) = match split[1] { - "cxchg" | "cxchgweak" => ( - 1, - 0, - vec![Ty::new_mut_ptr(tcx, param(0)), param(0), param(0)], - Ty::new_tup(tcx, &[param(0), tcx.types.bool]), - ), - "load" => (1, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), - "store" => (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit), - - "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | "min" | "umax" - | "umin" => (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)), - "fence" | "singlethreadfence" => (0, 0, Vec::new(), tcx.types.unit), - op => { - tcx.dcx().emit_err(UnrecognizedAtomicOperation { span, op }); - return; - } - }; - (n_tps, 0, n_cts, inputs, output, hir::Safety::Unsafe) - } else if intrinsic_name == sym::contract_check_ensures { + let (n_tps, n_lts, n_cts, inputs, output, safety) = if intrinsic_name + == sym::contract_check_ensures + { // contract_check_ensures::(Ret, C) -> Ret // where C: for<'a> Fn(&'a Ret) -> bool, // @@ -694,6 +667,30 @@ pub(crate) fn check_intrinsic_type( sym::simd_shuffle => (3, 0, vec![param(0), param(0), param(1)], param(2)), sym::simd_shuffle_const_generic => (2, 1, vec![param(0), param(0)], param(1)), + sym::atomic_cxchg | sym::atomic_cxchgweak => ( + 1, + 2, + vec![Ty::new_mut_ptr(tcx, param(0)), param(0), param(0)], + Ty::new_tup(tcx, &[param(0), tcx.types.bool]), + ), + sym::atomic_load => (1, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), + sym::atomic_store => { + (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) + } + + sym::atomic_xchg + | sym::atomic_xadd + | sym::atomic_xsub + | sym::atomic_and + | sym::atomic_nand + | sym::atomic_or + | sym::atomic_xor + | sym::atomic_max + | sym::atomic_min + | sym::atomic_umax + | sym::atomic_umin => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)), + sym::atomic_fence | sym::atomic_singlethreadfence => (0, 1, Vec::new(), tcx.types.unit), + other => { tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other }); return; diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 152714b3407..a27d1ed6c53 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -161,15 +161,6 @@ pub(crate) enum AssocItemNotFoundSugg<'a> { }, } -#[derive(Diagnostic)] -#[diag(hir_analysis_unrecognized_atomic_operation, code = E0092)] -pub(crate) struct UnrecognizedAtomicOperation<'a> { - #[primary_span] - #[label] - pub span: Span, - pub op: &'a str, -} - #[derive(Diagnostic)] #[diag(hir_analysis_wrong_number_of_generic_arguments_to_intrinsic, code = E0094)] pub(crate) struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4e842a8f93a..d66f98871b9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -515,8 +515,24 @@ symbols! { async_iterator_poll_next, async_trait_bounds, atomic, + atomic_and, + atomic_cxchg, + atomic_cxchgweak, + atomic_fence, atomic_load, + atomic_max, + atomic_min, atomic_mod, + atomic_nand, + atomic_or, + atomic_singlethreadfence, + atomic_store, + atomic_umax, + atomic_umin, + atomic_xadd, + atomic_xchg, + atomic_xor, + atomic_xsub, atomics, att_syntax, attr, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index bde90464acb..954c3754084 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -84,578 +84,97 @@ pub enum AtomicOrdering { /// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::Relaxed`] as both the success and failure parameters. +/// [`atomic`] types via the `compare_exchange` method. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_relaxed_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::Relaxed`] and [`Ordering::Acquire`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchg_relaxed_acquire(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::Relaxed`] and [`Ordering::SeqCst`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchg_relaxed_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::Acquire`] and [`Ordering::Relaxed`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchg_acquire_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::Acquire`] as both the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchg_acquire_acquire(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::Acquire`] and [`Ordering::SeqCst`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchg_acquire_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::Release`] and [`Ordering::Relaxed`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchg_release_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::Release`] and [`Ordering::Acquire`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchg_release_acquire(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::Release`] and [`Ordering::SeqCst`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchg_release_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::AcqRel`] and [`Ordering::Relaxed`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchg_acqrel_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::AcqRel`] and [`Ordering::Acquire`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchg_acqrel_acquire(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::AcqRel`] and [`Ordering::SeqCst`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchg_acqrel_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::SeqCst`] and [`Ordering::Relaxed`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchg_seqcst_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::SeqCst`] and [`Ordering::Acquire`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchg_seqcst_acquire(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange` method by passing -/// [`Ordering::SeqCst`] as both the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchg_seqcst_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::Relaxed`] as both the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_relaxed_relaxed( - _dst: *mut T, - _old: T, - _src: T, -) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::Relaxed`] and [`Ordering::Acquire`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_relaxed_acquire( - _dst: *mut T, - _old: T, - _src: T, -) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::Relaxed`] and [`Ordering::SeqCst`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_relaxed_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::Acquire`] and [`Ordering::Relaxed`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_acquire_relaxed( - _dst: *mut T, - _old: T, - _src: T, -) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::Acquire`] as both the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_acquire_acquire( - _dst: *mut T, - _old: T, - _src: T, -) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::Acquire`] and [`Ordering::SeqCst`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_acquire_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::Release`] and [`Ordering::Relaxed`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_release_relaxed( - _dst: *mut T, - _old: T, - _src: T, -) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::Release`] and [`Ordering::Acquire`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_release_acquire( - _dst: *mut T, - _old: T, - _src: T, -) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::Release`] and [`Ordering::SeqCst`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_release_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::AcqRel`] and [`Ordering::Relaxed`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_acqrel_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::AcqRel`] and [`Ordering::Acquire`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_acqrel_acquire(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::AcqRel`] and [`Ordering::SeqCst`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_acqrel_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::SeqCst`] and [`Ordering::Relaxed`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_seqcst_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::SeqCst`] and [`Ordering::Acquire`] as the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_seqcst_acquire(dst: *mut T, old: T, src: T) -> (T, bool); -/// Stores a value if the current value is the same as the `old` value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `compare_exchange_weak` method by passing -/// [`Ordering::SeqCst`] as both the success and failure parameters. -/// For example, [`AtomicBool::compare_exchange_weak`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_seqcst_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - -/// Loads the current value of the pointer. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `load` method. For example, [`AtomicBool::load`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_load(src: *const T) -> T; - -/// Stores the value at the specified memory location. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `store` method by passing -/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::store`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_store_seqcst(dst: *mut T, val: T); -/// Stores the value at the specified memory location. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `store` method by passing -/// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::store`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_store_release(dst: *mut T, val: T); -/// Stores the value at the specified memory location. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `store` method by passing -/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::store`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_store_relaxed(dst: *mut T, val: T); - -/// Stores the value at the specified memory location, returning the old value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `swap` method by passing -/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::swap`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xchg_seqcst(dst: *mut T, src: T) -> T; -/// Stores the value at the specified memory location, returning the old value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `swap` method by passing -/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::swap`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xchg_acquire(dst: *mut T, src: T) -> T; -/// Stores the value at the specified memory location, returning the old value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `swap` method by passing -/// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::swap`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xchg_release(dst: *mut T, src: T) -> T; -/// Stores the value at the specified memory location, returning the old value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `swap` method by passing -/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::swap`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xchg_acqrel(dst: *mut T, src: T) -> T; -/// Stores the value at the specified memory location, returning the old value. -/// `T` must be an integer or pointer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `swap` method by passing -/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::swap`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xchg_relaxed(dst: *mut T, src: T) -> T; - -/// Adds to the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_add` method by passing -/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_add`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xadd_seqcst(dst: *mut T, src: T) -> T; -/// Adds to the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_add` method by passing -/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_add`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xadd_acquire(dst: *mut T, src: T) -> T; -/// Adds to the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_add` method by passing -/// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_add`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xadd_release(dst: *mut T, src: T) -> T; -/// Adds to the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_add` method by passing -/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicIsize::fetch_add`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xadd_acqrel(dst: *mut T, src: T) -> T; -/// Adds to the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_add` method by passing -/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicIsize::fetch_add`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xadd_relaxed(dst: *mut T, src: T) -> T; - -/// Subtract from the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_sub` method by passing -/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xsub_seqcst(dst: *mut T, src: T) -> T; -/// Subtract from the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_sub` method by passing -/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xsub_acquire(dst: *mut T, src: T) -> T; -/// Subtract from the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_sub` method by passing -/// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xsub_release(dst: *mut T, src: T) -> T; -/// Subtract from the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. +pub unsafe fn atomic_cxchg< + T: Copy, + const ORD_SUCC: AtomicOrdering, + const ORD_FAIL: AtomicOrdering, +>( + dst: *mut T, + old: T, + src: T, +) -> (T, bool); + +/// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. The comparison may spuriously fail. /// /// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_sub` method by passing -/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. +/// [`atomic`] types via the `compare_exchange_weak` method. +/// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_xsub_acqrel(dst: *mut T, src: T) -> T; -/// Subtract from the current value, returning the previous value. +pub unsafe fn atomic_cxchgweak< + T: Copy, + const ORD_SUCC: AtomicOrdering, + const ORD_FAIL: AtomicOrdering, +>( + _dst: *mut T, + _old: T, + _src: T, +) -> (T, bool); + +/// Loads the current value of the pointer. /// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_sub` method by passing -/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. +/// [`atomic`] types via the `load` method. For example, [`AtomicBool::load`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_xsub_relaxed(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_load(src: *const T) -> T; -/// Bitwise and with the current value, returning the previous value. +/// Stores the value at the specified memory location. /// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_and` method by passing -/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_and`]. +/// [`atomic`] types via the `store` method. For example, [`AtomicBool::store`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_and_seqcst(dst: *mut T, src: T) -> T; -/// Bitwise and with the current value, returning the previous value. +pub unsafe fn atomic_store(dst: *mut T, val: T); + +/// Stores the value at the specified memory location, returning the old value. /// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_and` method by passing -/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_and`]. +/// [`atomic`] types via the `swap` method. For example, [`AtomicBool::swap`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_and_acquire(dst: *mut T, src: T) -> T; -/// Bitwise and with the current value, returning the previous value. +pub unsafe fn atomic_xchg(dst: *mut T, src: T) -> T; + +/// Adds to the current value, returning the previous value. /// `T` must be an integer or pointer type. /// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new /// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_and` method by passing -/// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_and`]. +/// [`atomic`] types via the `fetch_add` method. For example, [`AtomicIsize::fetch_add`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_and_release(dst: *mut T, src: T) -> T; -/// Bitwise and with the current value, returning the previous value. +pub unsafe fn atomic_xadd(dst: *mut T, src: T) -> T; + +/// Subtract from the current value, returning the previous value. /// `T` must be an integer or pointer type. /// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new /// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_and` method by passing -/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_and`]. +/// [`atomic`] types via the `fetch_sub` method. For example, [`AtomicIsize::fetch_sub`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_and_acqrel(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_xsub(dst: *mut T, src: T) -> T; + /// Bitwise and with the current value, returning the previous value. /// `T` must be an integer or pointer type. /// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new /// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_and` method by passing -/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_and`]. +/// [`atomic`] types via the `fetch_and` method. For example, [`AtomicBool::fetch_and`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_and_relaxed(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_and(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. /// `T` must be an integer or pointer type. @@ -663,55 +182,10 @@ pub unsafe fn atomic_and_relaxed(dst: *mut T, src: T) -> T; /// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the -/// [`AtomicBool`] type via the `fetch_nand` method by passing -/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_nand`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_nand_seqcst(dst: *mut T, src: T) -> T; -/// Bitwise nand with the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`AtomicBool`] type via the `fetch_nand` method by passing -/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_nand`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_nand_acquire(dst: *mut T, src: T) -> T; -/// Bitwise nand with the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`AtomicBool`] type via the `fetch_nand` method by passing -/// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_nand`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_nand_release(dst: *mut T, src: T) -> T; -/// Bitwise nand with the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`AtomicBool`] type via the `fetch_nand` method by passing -/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_nand`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_nand_acqrel(dst: *mut T, src: T) -> T; -/// Bitwise nand with the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`AtomicBool`] type via the `fetch_nand` method by passing -/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_nand`]. +/// [`AtomicBool`] type via the `fetch_nand` method. For example, [`AtomicBool::fetch_nand`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_nand_relaxed(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_nand(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. /// `T` must be an integer or pointer type. @@ -719,55 +193,10 @@ pub unsafe fn atomic_nand_relaxed(dst: *mut T, src: T) -> T; /// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_or` method by passing -/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_or`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_or_seqcst(dst: *mut T, src: T) -> T; -/// Bitwise or with the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_or` method by passing -/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_or`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_or_acquire(dst: *mut T, src: T) -> T; -/// Bitwise or with the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_or` method by passing -/// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_or`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_or_release(dst: *mut T, src: T) -> T; -/// Bitwise or with the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_or` method by passing -/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_or`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_or_acqrel(dst: *mut T, src: T) -> T; -/// Bitwise or with the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_or` method by passing -/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_or`]. +/// [`atomic`] types via the `fetch_or` method. For example, [`AtomicBool::fetch_or`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_or_relaxed(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_or(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. /// `T` must be an integer or pointer type. @@ -775,325 +204,62 @@ pub unsafe fn atomic_or_relaxed(dst: *mut T, src: T) -> T; /// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_xor` method by passing -/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_xor`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xor_seqcst(dst: *mut T, src: T) -> T; -/// Bitwise xor with the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_xor` method by passing -/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_xor`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xor_acquire(dst: *mut T, src: T) -> T; -/// Bitwise xor with the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_xor` method by passing -/// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_xor`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xor_release(dst: *mut T, src: T) -> T; -/// Bitwise xor with the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_xor` method by passing -/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_xor`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_xor_acqrel(dst: *mut T, src: T) -> T; -/// Bitwise xor with the current value, returning the previous value. -/// `T` must be an integer or pointer type. -/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new -/// value stored at `*dst` will have the provenance of the old value stored there. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] types via the `fetch_xor` method by passing -/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_xor`]. +/// [`atomic`] types via the `fetch_xor` method. For example, [`AtomicBool::fetch_xor`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_xor_relaxed(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_xor(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. /// `T` must be a signed integer type. /// /// The stabilized version of this intrinsic is available on the -/// [`atomic`] signed integer types via the `fetch_max` method by passing -/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_max`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_max_seqcst(dst: *mut T, src: T) -> T; -/// Maximum with the current value using a signed comparison. -/// `T` must be a signed integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] signed integer types via the `fetch_max` method by passing -/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_max`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_max_acquire(dst: *mut T, src: T) -> T; -/// Maximum with the current value using a signed comparison. -/// `T` must be a signed integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] signed integer types via the `fetch_max` method by passing -/// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_max`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_max_release(dst: *mut T, src: T) -> T; -/// Maximum with the current value using a signed comparison. -/// `T` must be a signed integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] signed integer types via the `fetch_max` method by passing -/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicI32::fetch_max`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_max_acqrel(dst: *mut T, src: T) -> T; -/// Maximum with the current value using a signed comparison. -/// `T` must be a signed integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] signed integer types via the `fetch_max` method by passing -/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicI32::fetch_max`]. +/// [`atomic`] signed integer types via the `fetch_max` method. For example, [`AtomicI32::fetch_max`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_max_relaxed(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_max(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. /// `T` must be a signed integer type. /// /// The stabilized version of this intrinsic is available on the -/// [`atomic`] signed integer types via the `fetch_min` method by passing -/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_min`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_min_seqcst(dst: *mut T, src: T) -> T; -/// Minimum with the current value using a signed comparison. -/// `T` must be a signed integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] signed integer types via the `fetch_min` method by passing -/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_min`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_min_acquire(dst: *mut T, src: T) -> T; -/// Minimum with the current value using a signed comparison. -/// `T` must be a signed integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] signed integer types via the `fetch_min` method by passing -/// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_min`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_min_release(dst: *mut T, src: T) -> T; -/// Minimum with the current value using a signed comparison. -/// `T` must be a signed integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] signed integer types via the `fetch_min` method by passing -/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicI32::fetch_min`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_min_acqrel(dst: *mut T, src: T) -> T; -/// Minimum with the current value using a signed comparison. -/// `T` must be a signed integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] signed integer types via the `fetch_min` method by passing -/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicI32::fetch_min`]. +/// [`atomic`] signed integer types via the `fetch_min` method. For example, [`AtomicI32::fetch_min`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_min_relaxed(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_min(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. /// `T` must be an unsigned integer type. /// /// The stabilized version of this intrinsic is available on the -/// [`atomic`] unsigned integer types via the `fetch_min` method by passing -/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_min`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_umin_seqcst(dst: *mut T, src: T) -> T; -/// Minimum with the current value using an unsigned comparison. -/// `T` must be an unsigned integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] unsigned integer types via the `fetch_min` method by passing -/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_min`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_umin_acquire(dst: *mut T, src: T) -> T; -/// Minimum with the current value using an unsigned comparison. -/// `T` must be an unsigned integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] unsigned integer types via the `fetch_min` method by passing -/// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_min`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_umin_release(dst: *mut T, src: T) -> T; -/// Minimum with the current value using an unsigned comparison. -/// `T` must be an unsigned integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] unsigned integer types via the `fetch_min` method by passing -/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicU32::fetch_min`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_umin_acqrel(dst: *mut T, src: T) -> T; -/// Minimum with the current value using an unsigned comparison. -/// `T` must be an unsigned integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] unsigned integer types via the `fetch_min` method by passing -/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_min`]. +/// [`atomic`] unsigned integer types via the `fetch_min` method. For example, [`AtomicU32::fetch_min`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_umin_relaxed(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_umin(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. /// `T` must be an unsigned integer type. /// /// The stabilized version of this intrinsic is available on the -/// [`atomic`] unsigned integer types via the `fetch_max` method by passing -/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_max`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_umax_seqcst(dst: *mut T, src: T) -> T; -/// Maximum with the current value using an unsigned comparison. -/// `T` must be an unsigned integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] unsigned integer types via the `fetch_max` method by passing -/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_max`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_umax_acquire(dst: *mut T, src: T) -> T; -/// Maximum with the current value using an unsigned comparison. -/// `T` must be an unsigned integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] unsigned integer types via the `fetch_max` method by passing -/// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_max`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_umax_release(dst: *mut T, src: T) -> T; -/// Maximum with the current value using an unsigned comparison. -/// `T` must be an unsigned integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] unsigned integer types via the `fetch_max` method by passing -/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicU32::fetch_max`]. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_umax_acqrel(dst: *mut T, src: T) -> T; -/// Maximum with the current value using an unsigned comparison. -/// `T` must be an unsigned integer type. -/// -/// The stabilized version of this intrinsic is available on the -/// [`atomic`] unsigned integer types via the `fetch_max` method by passing -/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_max`]. +/// [`atomic`] unsigned integer types via the `fetch_max` method. For example, [`AtomicU32::fetch_max`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_umax_relaxed(dst: *mut T, src: T) -> T; +pub unsafe fn atomic_umax(dst: *mut T, src: T) -> T; /// An atomic fence. /// /// The stabilized version of this intrinsic is available in -/// [`atomic::fence`] by passing [`Ordering::SeqCst`] -/// as the `order`. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_fence_seqcst(); -/// An atomic fence. -/// -/// The stabilized version of this intrinsic is available in -/// [`atomic::fence`] by passing [`Ordering::Acquire`] -/// as the `order`. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_fence_acquire(); -/// An atomic fence. -/// -/// The stabilized version of this intrinsic is available in -/// [`atomic::fence`] by passing [`Ordering::Release`] -/// as the `order`. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_fence_release(); -/// An atomic fence. -/// -/// The stabilized version of this intrinsic is available in -/// [`atomic::fence`] by passing [`Ordering::AcqRel`] -/// as the `order`. +/// [`atomic::fence`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_fence_acqrel(); +pub unsafe fn atomic_fence(); -/// A compiler-only memory barrier. -/// -/// Memory accesses will never be reordered across this barrier by the -/// compiler, but no instructions will be emitted for it. This is -/// appropriate for operations on the same thread that may be preempted, -/// such as when interacting with signal handlers. -/// -/// The stabilized version of this intrinsic is available in -/// [`atomic::compiler_fence`] by passing [`Ordering::SeqCst`] -/// as the `order`. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_singlethreadfence_seqcst(); -/// A compiler-only memory barrier. -/// -/// Memory accesses will never be reordered across this barrier by the -/// compiler, but no instructions will be emitted for it. This is -/// appropriate for operations on the same thread that may be preempted, -/// such as when interacting with signal handlers. -/// -/// The stabilized version of this intrinsic is available in -/// [`atomic::compiler_fence`] by passing [`Ordering::Acquire`] -/// as the `order`. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_singlethreadfence_acquire(); -/// A compiler-only memory barrier. -/// -/// Memory accesses will never be reordered across this barrier by the -/// compiler, but no instructions will be emitted for it. This is -/// appropriate for operations on the same thread that may be preempted, -/// such as when interacting with signal handlers. -/// -/// The stabilized version of this intrinsic is available in -/// [`atomic::compiler_fence`] by passing [`Ordering::Release`] -/// as the `order`. -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn atomic_singlethreadfence_release(); -/// A compiler-only memory barrier. -/// -/// Memory accesses will never be reordered across this barrier by the -/// compiler, but no instructions will be emitted for it. This is -/// appropriate for operations on the same thread that may be preempted, -/// such as when interacting with signal handlers. +/// An atomic fence for synchronization within a single thread. /// /// The stabilized version of this intrinsic is available in -/// [`atomic::compiler_fence`] by passing [`Ordering::AcqRel`] -/// as the `order`. +/// [`atomic::compiler_fence`]. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn atomic_singlethreadfence_acqrel(); +pub unsafe fn atomic_singlethreadfence(); /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction /// if supported; otherwise, it is a no-op. diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index ea459f6d92d..453687a949b 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -245,6 +245,7 @@ use self::Ordering::*; use crate::cell::UnsafeCell; use crate::hint::spin_loop; +use crate::intrinsics::AtomicOrdering as AO; use crate::{fmt, intrinsics}; trait Sealed {} @@ -3811,9 +3812,9 @@ unsafe fn atomic_store(dst: *mut T, val: T, order: Ordering) { // SAFETY: the caller must uphold the safety contract for `atomic_store`. unsafe { match order { - Relaxed => intrinsics::atomic_store_relaxed(dst, val), - Release => intrinsics::atomic_store_release(dst, val), - SeqCst => intrinsics::atomic_store_seqcst(dst, val), + Relaxed => intrinsics::atomic_store::(dst, val), + Release => intrinsics::atomic_store::(dst, val), + SeqCst => intrinsics::atomic_store::(dst, val), Acquire => panic!("there is no such thing as an acquire store"), AcqRel => panic!("there is no such thing as an acquire-release store"), } @@ -3823,13 +3824,12 @@ unsafe fn atomic_store(dst: *mut T, val: T, order: Ordering) { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_load(dst: *const T, order: Ordering) -> T { - use intrinsics::AtomicOrdering; // SAFETY: the caller must uphold the safety contract for `atomic_load`. unsafe { match order { - Relaxed => intrinsics::atomic_load::(dst), - Acquire => intrinsics::atomic_load::(dst), - SeqCst => intrinsics::atomic_load::(dst), + Relaxed => intrinsics::atomic_load::(dst), + Acquire => intrinsics::atomic_load::(dst), + SeqCst => intrinsics::atomic_load::(dst), Release => panic!("there is no such thing as a release load"), AcqRel => panic!("there is no such thing as an acquire-release load"), } @@ -3843,11 +3843,11 @@ unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_swap`. unsafe { match order { - Relaxed => intrinsics::atomic_xchg_relaxed(dst, val), - Acquire => intrinsics::atomic_xchg_acquire(dst, val), - Release => intrinsics::atomic_xchg_release(dst, val), - AcqRel => intrinsics::atomic_xchg_acqrel(dst, val), - SeqCst => intrinsics::atomic_xchg_seqcst(dst, val), + Relaxed => intrinsics::atomic_xchg::(dst, val), + Acquire => intrinsics::atomic_xchg::(dst, val), + Release => intrinsics::atomic_xchg::(dst, val), + AcqRel => intrinsics::atomic_xchg::(dst, val), + SeqCst => intrinsics::atomic_xchg::(dst, val), } } } @@ -3860,11 +3860,11 @@ unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_add`. unsafe { match order { - Relaxed => intrinsics::atomic_xadd_relaxed(dst, val), - Acquire => intrinsics::atomic_xadd_acquire(dst, val), - Release => intrinsics::atomic_xadd_release(dst, val), - AcqRel => intrinsics::atomic_xadd_acqrel(dst, val), - SeqCst => intrinsics::atomic_xadd_seqcst(dst, val), + Relaxed => intrinsics::atomic_xadd::(dst, val), + Acquire => intrinsics::atomic_xadd::(dst, val), + Release => intrinsics::atomic_xadd::(dst, val), + AcqRel => intrinsics::atomic_xadd::(dst, val), + SeqCst => intrinsics::atomic_xadd::(dst, val), } } } @@ -3877,11 +3877,11 @@ unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_sub`. unsafe { match order { - Relaxed => intrinsics::atomic_xsub_relaxed(dst, val), - Acquire => intrinsics::atomic_xsub_acquire(dst, val), - Release => intrinsics::atomic_xsub_release(dst, val), - AcqRel => intrinsics::atomic_xsub_acqrel(dst, val), - SeqCst => intrinsics::atomic_xsub_seqcst(dst, val), + Relaxed => intrinsics::atomic_xsub::(dst, val), + Acquire => intrinsics::atomic_xsub::(dst, val), + Release => intrinsics::atomic_xsub::(dst, val), + AcqRel => intrinsics::atomic_xsub::(dst, val), + SeqCst => intrinsics::atomic_xsub::(dst, val), } } } @@ -3902,21 +3902,51 @@ pub unsafe fn atomic_compare_exchange( // SAFETY: the caller must uphold the safety contract for `atomic_compare_exchange`. let (val, ok) = unsafe { match (success, failure) { - (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed_relaxed(dst, old, new), - (Relaxed, Acquire) => intrinsics::atomic_cxchg_relaxed_acquire(dst, old, new), - (Relaxed, SeqCst) => intrinsics::atomic_cxchg_relaxed_seqcst(dst, old, new), - (Acquire, Relaxed) => intrinsics::atomic_cxchg_acquire_relaxed(dst, old, new), - (Acquire, Acquire) => intrinsics::atomic_cxchg_acquire_acquire(dst, old, new), - (Acquire, SeqCst) => intrinsics::atomic_cxchg_acquire_seqcst(dst, old, new), - (Release, Relaxed) => intrinsics::atomic_cxchg_release_relaxed(dst, old, new), - (Release, Acquire) => intrinsics::atomic_cxchg_release_acquire(dst, old, new), - (Release, SeqCst) => intrinsics::atomic_cxchg_release_seqcst(dst, old, new), - (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_relaxed(dst, old, new), - (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel_acquire(dst, old, new), - (AcqRel, SeqCst) => intrinsics::atomic_cxchg_acqrel_seqcst(dst, old, new), - (SeqCst, Relaxed) => intrinsics::atomic_cxchg_seqcst_relaxed(dst, old, new), - (SeqCst, Acquire) => intrinsics::atomic_cxchg_seqcst_acquire(dst, old, new), - (SeqCst, SeqCst) => intrinsics::atomic_cxchg_seqcst_seqcst(dst, old, new), + (Relaxed, Relaxed) => { + intrinsics::atomic_cxchg::(dst, old, new) + } + (Relaxed, Acquire) => { + intrinsics::atomic_cxchg::(dst, old, new) + } + (Relaxed, SeqCst) => { + intrinsics::atomic_cxchg::(dst, old, new) + } + (Acquire, Relaxed) => { + intrinsics::atomic_cxchg::(dst, old, new) + } + (Acquire, Acquire) => { + intrinsics::atomic_cxchg::(dst, old, new) + } + (Acquire, SeqCst) => { + intrinsics::atomic_cxchg::(dst, old, new) + } + (Release, Relaxed) => { + intrinsics::atomic_cxchg::(dst, old, new) + } + (Release, Acquire) => { + intrinsics::atomic_cxchg::(dst, old, new) + } + (Release, SeqCst) => { + intrinsics::atomic_cxchg::(dst, old, new) + } + (AcqRel, Relaxed) => { + intrinsics::atomic_cxchg::(dst, old, new) + } + (AcqRel, Acquire) => { + intrinsics::atomic_cxchg::(dst, old, new) + } + (AcqRel, SeqCst) => { + intrinsics::atomic_cxchg::(dst, old, new) + } + (SeqCst, Relaxed) => { + intrinsics::atomic_cxchg::(dst, old, new) + } + (SeqCst, Acquire) => { + intrinsics::atomic_cxchg::(dst, old, new) + } + (SeqCst, SeqCst) => { + intrinsics::atomic_cxchg::(dst, old, new) + } (_, AcqRel) => panic!("there is no such thing as an acquire-release failure ordering"), (_, Release) => panic!("there is no such thing as a release failure ordering"), } @@ -3937,21 +3967,51 @@ unsafe fn atomic_compare_exchange_weak( // SAFETY: the caller must uphold the safety contract for `atomic_compare_exchange_weak`. let (val, ok) = unsafe { match (success, failure) { - (Relaxed, Relaxed) => intrinsics::atomic_cxchgweak_relaxed_relaxed(dst, old, new), - (Relaxed, Acquire) => intrinsics::atomic_cxchgweak_relaxed_acquire(dst, old, new), - (Relaxed, SeqCst) => intrinsics::atomic_cxchgweak_relaxed_seqcst(dst, old, new), - (Acquire, Relaxed) => intrinsics::atomic_cxchgweak_acquire_relaxed(dst, old, new), - (Acquire, Acquire) => intrinsics::atomic_cxchgweak_acquire_acquire(dst, old, new), - (Acquire, SeqCst) => intrinsics::atomic_cxchgweak_acquire_seqcst(dst, old, new), - (Release, Relaxed) => intrinsics::atomic_cxchgweak_release_relaxed(dst, old, new), - (Release, Acquire) => intrinsics::atomic_cxchgweak_release_acquire(dst, old, new), - (Release, SeqCst) => intrinsics::atomic_cxchgweak_release_seqcst(dst, old, new), - (AcqRel, Relaxed) => intrinsics::atomic_cxchgweak_acqrel_relaxed(dst, old, new), - (AcqRel, Acquire) => intrinsics::atomic_cxchgweak_acqrel_acquire(dst, old, new), - (AcqRel, SeqCst) => intrinsics::atomic_cxchgweak_acqrel_seqcst(dst, old, new), - (SeqCst, Relaxed) => intrinsics::atomic_cxchgweak_seqcst_relaxed(dst, old, new), - (SeqCst, Acquire) => intrinsics::atomic_cxchgweak_seqcst_acquire(dst, old, new), - (SeqCst, SeqCst) => intrinsics::atomic_cxchgweak_seqcst_seqcst(dst, old, new), + (Relaxed, Relaxed) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } + (Relaxed, Acquire) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } + (Relaxed, SeqCst) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } + (Acquire, Relaxed) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } + (Acquire, Acquire) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } + (Acquire, SeqCst) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } + (Release, Relaxed) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } + (Release, Acquire) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } + (Release, SeqCst) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } + (AcqRel, Relaxed) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } + (AcqRel, Acquire) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } + (AcqRel, SeqCst) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } + (SeqCst, Relaxed) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } + (SeqCst, Acquire) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } + (SeqCst, SeqCst) => { + intrinsics::atomic_cxchgweak::(dst, old, new) + } (_, AcqRel) => panic!("there is no such thing as an acquire-release failure ordering"), (_, Release) => panic!("there is no such thing as a release failure ordering"), } @@ -3966,11 +4026,11 @@ unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_and` unsafe { match order { - Relaxed => intrinsics::atomic_and_relaxed(dst, val), - Acquire => intrinsics::atomic_and_acquire(dst, val), - Release => intrinsics::atomic_and_release(dst, val), - AcqRel => intrinsics::atomic_and_acqrel(dst, val), - SeqCst => intrinsics::atomic_and_seqcst(dst, val), + Relaxed => intrinsics::atomic_and::(dst, val), + Acquire => intrinsics::atomic_and::(dst, val), + Release => intrinsics::atomic_and::(dst, val), + AcqRel => intrinsics::atomic_and::(dst, val), + SeqCst => intrinsics::atomic_and::(dst, val), } } } @@ -3982,11 +4042,11 @@ unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_nand` unsafe { match order { - Relaxed => intrinsics::atomic_nand_relaxed(dst, val), - Acquire => intrinsics::atomic_nand_acquire(dst, val), - Release => intrinsics::atomic_nand_release(dst, val), - AcqRel => intrinsics::atomic_nand_acqrel(dst, val), - SeqCst => intrinsics::atomic_nand_seqcst(dst, val), + Relaxed => intrinsics::atomic_nand::(dst, val), + Acquire => intrinsics::atomic_nand::(dst, val), + Release => intrinsics::atomic_nand::(dst, val), + AcqRel => intrinsics::atomic_nand::(dst, val), + SeqCst => intrinsics::atomic_nand::(dst, val), } } } @@ -3998,11 +4058,11 @@ unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_or` unsafe { match order { - SeqCst => intrinsics::atomic_or_seqcst(dst, val), - Acquire => intrinsics::atomic_or_acquire(dst, val), - Release => intrinsics::atomic_or_release(dst, val), - AcqRel => intrinsics::atomic_or_acqrel(dst, val), - Relaxed => intrinsics::atomic_or_relaxed(dst, val), + SeqCst => intrinsics::atomic_or::(dst, val), + Acquire => intrinsics::atomic_or::(dst, val), + Release => intrinsics::atomic_or::(dst, val), + AcqRel => intrinsics::atomic_or::(dst, val), + Relaxed => intrinsics::atomic_or::(dst, val), } } } @@ -4014,16 +4074,16 @@ unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_xor` unsafe { match order { - SeqCst => intrinsics::atomic_xor_seqcst(dst, val), - Acquire => intrinsics::atomic_xor_acquire(dst, val), - Release => intrinsics::atomic_xor_release(dst, val), - AcqRel => intrinsics::atomic_xor_acqrel(dst, val), - Relaxed => intrinsics::atomic_xor_relaxed(dst, val), + SeqCst => intrinsics::atomic_xor::(dst, val), + Acquire => intrinsics::atomic_xor::(dst, val), + Release => intrinsics::atomic_xor::(dst, val), + AcqRel => intrinsics::atomic_xor::(dst, val), + Relaxed => intrinsics::atomic_xor::(dst, val), } } } -/// returns the max value (signed comparison) +/// Updates `*dst` to the max value of `val` and the old value (signed comparison) #[inline] #[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -4031,16 +4091,16 @@ unsafe fn atomic_max(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_max` unsafe { match order { - Relaxed => intrinsics::atomic_max_relaxed(dst, val), - Acquire => intrinsics::atomic_max_acquire(dst, val), - Release => intrinsics::atomic_max_release(dst, val), - AcqRel => intrinsics::atomic_max_acqrel(dst, val), - SeqCst => intrinsics::atomic_max_seqcst(dst, val), + Relaxed => intrinsics::atomic_max::(dst, val), + Acquire => intrinsics::atomic_max::(dst, val), + Release => intrinsics::atomic_max::(dst, val), + AcqRel => intrinsics::atomic_max::(dst, val), + SeqCst => intrinsics::atomic_max::(dst, val), } } } -/// returns the min value (signed comparison) +/// Updates `*dst` to the min value of `val` and the old value (signed comparison) #[inline] #[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -4048,16 +4108,16 @@ unsafe fn atomic_min(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_min` unsafe { match order { - Relaxed => intrinsics::atomic_min_relaxed(dst, val), - Acquire => intrinsics::atomic_min_acquire(dst, val), - Release => intrinsics::atomic_min_release(dst, val), - AcqRel => intrinsics::atomic_min_acqrel(dst, val), - SeqCst => intrinsics::atomic_min_seqcst(dst, val), + Relaxed => intrinsics::atomic_min::(dst, val), + Acquire => intrinsics::atomic_min::(dst, val), + Release => intrinsics::atomic_min::(dst, val), + AcqRel => intrinsics::atomic_min::(dst, val), + SeqCst => intrinsics::atomic_min::(dst, val), } } } -/// returns the max value (unsigned comparison) +/// Updates `*dst` to the max value of `val` and the old value (unsigned comparison) #[inline] #[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -4065,16 +4125,16 @@ unsafe fn atomic_umax(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_umax` unsafe { match order { - Relaxed => intrinsics::atomic_umax_relaxed(dst, val), - Acquire => intrinsics::atomic_umax_acquire(dst, val), - Release => intrinsics::atomic_umax_release(dst, val), - AcqRel => intrinsics::atomic_umax_acqrel(dst, val), - SeqCst => intrinsics::atomic_umax_seqcst(dst, val), + Relaxed => intrinsics::atomic_umax::(dst, val), + Acquire => intrinsics::atomic_umax::(dst, val), + Release => intrinsics::atomic_umax::(dst, val), + AcqRel => intrinsics::atomic_umax::(dst, val), + SeqCst => intrinsics::atomic_umax::(dst, val), } } } -/// returns the min value (unsigned comparison) +/// Updates `*dst` to the min value of `val` and the old value (unsigned comparison) #[inline] #[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -4082,11 +4142,11 @@ unsafe fn atomic_umin(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_umin` unsafe { match order { - Relaxed => intrinsics::atomic_umin_relaxed(dst, val), - Acquire => intrinsics::atomic_umin_acquire(dst, val), - Release => intrinsics::atomic_umin_release(dst, val), - AcqRel => intrinsics::atomic_umin_acqrel(dst, val), - SeqCst => intrinsics::atomic_umin_seqcst(dst, val), + Relaxed => intrinsics::atomic_umin::(dst, val), + Acquire => intrinsics::atomic_umin::(dst, val), + Release => intrinsics::atomic_umin::(dst, val), + AcqRel => intrinsics::atomic_umin::(dst, val), + SeqCst => intrinsics::atomic_umin::(dst, val), } } } @@ -4178,10 +4238,10 @@ pub fn fence(order: Ordering) { // SAFETY: using an atomic fence is safe. unsafe { match order { - Acquire => intrinsics::atomic_fence_acquire(), - Release => intrinsics::atomic_fence_release(), - AcqRel => intrinsics::atomic_fence_acqrel(), - SeqCst => intrinsics::atomic_fence_seqcst(), + Acquire => intrinsics::atomic_fence::<{ AO::Acquire }>(), + Release => intrinsics::atomic_fence::<{ AO::Release }>(), + AcqRel => intrinsics::atomic_fence::<{ AO::AcqRel }>(), + SeqCst => intrinsics::atomic_fence::<{ AO::SeqCst }>(), Relaxed => panic!("there is no such thing as a relaxed fence"), } } @@ -4256,11 +4316,11 @@ pub fn compiler_fence(order: Ordering) { // SAFETY: using an atomic fence is safe. unsafe { match order { - Acquire => intrinsics::atomic_singlethreadfence_acquire(), - Release => intrinsics::atomic_singlethreadfence_release(), - AcqRel => intrinsics::atomic_singlethreadfence_acqrel(), - SeqCst => intrinsics::atomic_singlethreadfence_seqcst(), - Relaxed => panic!("there is no such thing as a relaxed compiler fence"), + Acquire => intrinsics::atomic_singlethreadfence::<{ AO::Acquire }>(), + Release => intrinsics::atomic_singlethreadfence::<{ AO::Release }>(), + AcqRel => intrinsics::atomic_singlethreadfence::<{ AO::AcqRel }>(), + SeqCst => intrinsics::atomic_singlethreadfence::<{ AO::SeqCst }>(), + Relaxed => panic!("there is no such thing as a relaxed fence"), } } } diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 3794b56c089..003ac4f0cd3 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -291,7 +291,7 @@ cfg_if::cfg_if! { } pub(crate) unsafe fn panic(data: Box) -> u32 { - use core::intrinsics::atomic_store_seqcst; + use core::intrinsics::{AtomicOrdering, atomic_store}; // _CxxThrowException executes entirely on this stack frame, so there's no // need to otherwise transfer `data` to the heap. We just pass a stack @@ -325,23 +325,23 @@ pub(crate) unsafe fn panic(data: Box) -> u32 { // In any case, we basically need to do something like this until we can // express more operations in statics (and we may never be able to). unsafe { - atomic_store_seqcst( + atomic_store::<_, { AtomicOrdering::SeqCst }>( (&raw mut THROW_INFO.pmfnUnwind).cast(), ptr_t::new(exception_cleanup as *mut u8).raw(), ); - atomic_store_seqcst( + atomic_store::<_, { AtomicOrdering::SeqCst }>( (&raw mut THROW_INFO.pCatchableTypeArray).cast(), ptr_t::new((&raw mut CATCHABLE_TYPE_ARRAY).cast()).raw(), ); - atomic_store_seqcst( + atomic_store::<_, { AtomicOrdering::SeqCst }>( (&raw mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(), ptr_t::new((&raw mut CATCHABLE_TYPE).cast()).raw(), ); - atomic_store_seqcst( + atomic_store::<_, { AtomicOrdering::SeqCst }>( (&raw mut CATCHABLE_TYPE.pType).cast(), ptr_t::new((&raw mut TYPE_DESCRIPTOR).cast()).raw(), ); - atomic_store_seqcst( + atomic_store::<_, { AtomicOrdering::SeqCst }>( (&raw mut CATCHABLE_TYPE.copyFunction).cast(), ptr_t::new(exception_copy as *mut u8).raw(), ); diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs index a61226eeed9..0a59a707a10 100644 --- a/src/tools/miri/src/intrinsics/atomic.rs +++ b/src/tools/miri/src/intrinsics/atomic.rs @@ -26,108 +26,131 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); - let intrinsic_structure: Vec<_> = intrinsic_name.split('_').collect(); + let get_ord_at = |i: usize| { + let ordering = generic_args.const_at(i).to_value(); + ordering.valtree.unwrap_branch()[0].unwrap_leaf().to_atomic_ordering() + }; - fn read_ord(ord: &str) -> AtomicReadOrd { + fn read_ord(ord: AtomicOrdering) -> AtomicReadOrd { match ord { - "seqcst" => AtomicReadOrd::SeqCst, - "acquire" => AtomicReadOrd::Acquire, - "relaxed" => AtomicReadOrd::Relaxed, - _ => panic!("invalid read ordering `{ord}`"), - } - } - - fn read_ord_const_generic(o: AtomicOrdering) -> AtomicReadOrd { - match o { AtomicOrdering::SeqCst => AtomicReadOrd::SeqCst, AtomicOrdering::Acquire => AtomicReadOrd::Acquire, AtomicOrdering::Relaxed => AtomicReadOrd::Relaxed, - _ => panic!("invalid read ordering `{o:?}`"), + _ => panic!("invalid read ordering `{ord:?}`"), } } - fn write_ord(ord: &str) -> AtomicWriteOrd { + fn write_ord(ord: AtomicOrdering) -> AtomicWriteOrd { match ord { - "seqcst" => AtomicWriteOrd::SeqCst, - "release" => AtomicWriteOrd::Release, - "relaxed" => AtomicWriteOrd::Relaxed, - _ => panic!("invalid write ordering `{ord}`"), + AtomicOrdering::SeqCst => AtomicWriteOrd::SeqCst, + AtomicOrdering::Release => AtomicWriteOrd::Release, + AtomicOrdering::Relaxed => AtomicWriteOrd::Relaxed, + _ => panic!("invalid write ordering `{ord:?}`"), } } - fn rw_ord(ord: &str) -> AtomicRwOrd { + fn rw_ord(ord: AtomicOrdering) -> AtomicRwOrd { match ord { - "seqcst" => AtomicRwOrd::SeqCst, - "acqrel" => AtomicRwOrd::AcqRel, - "acquire" => AtomicRwOrd::Acquire, - "release" => AtomicRwOrd::Release, - "relaxed" => AtomicRwOrd::Relaxed, - _ => panic!("invalid read-write ordering `{ord}`"), + AtomicOrdering::SeqCst => AtomicRwOrd::SeqCst, + AtomicOrdering::AcqRel => AtomicRwOrd::AcqRel, + AtomicOrdering::Acquire => AtomicRwOrd::Acquire, + AtomicOrdering::Release => AtomicRwOrd::Release, + AtomicOrdering::Relaxed => AtomicRwOrd::Relaxed, } } - fn fence_ord(ord: &str) -> AtomicFenceOrd { + fn fence_ord(ord: AtomicOrdering) -> AtomicFenceOrd { match ord { - "seqcst" => AtomicFenceOrd::SeqCst, - "acqrel" => AtomicFenceOrd::AcqRel, - "acquire" => AtomicFenceOrd::Acquire, - "release" => AtomicFenceOrd::Release, - _ => panic!("invalid fence ordering `{ord}`"), + AtomicOrdering::SeqCst => AtomicFenceOrd::SeqCst, + AtomicOrdering::AcqRel => AtomicFenceOrd::AcqRel, + AtomicOrdering::Acquire => AtomicFenceOrd::Acquire, + AtomicOrdering::Release => AtomicFenceOrd::Release, + _ => panic!("invalid fence ordering `{ord:?}`"), } } - match &*intrinsic_structure { - // New-style intrinsics that use const generics - ["load"] => { - let ordering = generic_args.const_at(1).to_value(); - let ordering = - ordering.valtree.unwrap_branch()[0].unwrap_leaf().to_atomic_ordering(); - this.atomic_load(args, dest, read_ord_const_generic(ordering))?; + match intrinsic_name { + "load" => { + let ord = get_ord_at(1); + this.atomic_load(args, dest, read_ord(ord))?; + } + + "store" => { + let ord = get_ord_at(1); + this.atomic_store(args, write_ord(ord))? } - // Old-style intrinsics that have the ordering in the intrinsic name - ["store", ord] => this.atomic_store(args, write_ord(ord))?, - - ["fence", ord] => this.atomic_fence_intrinsic(args, fence_ord(ord))?, - ["singlethreadfence", ord] => this.compiler_fence_intrinsic(args, fence_ord(ord))?, - - ["xchg", ord] => this.atomic_exchange(args, dest, rw_ord(ord))?, - ["cxchg", ord1, ord2] => - this.atomic_compare_exchange(args, dest, rw_ord(ord1), read_ord(ord2))?, - ["cxchgweak", ord1, ord2] => - this.atomic_compare_exchange_weak(args, dest, rw_ord(ord1), read_ord(ord2))?, - - ["or", ord] => - this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), rw_ord(ord))?, - ["xor", ord] => - this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), rw_ord(ord))?, - ["and", ord] => - this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), rw_ord(ord))?, - ["nand", ord] => - this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), rw_ord(ord))?, - ["xadd", ord] => - this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), rw_ord(ord))?, - ["xsub", ord] => - this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), rw_ord(ord))?, - ["min", ord] => { + "fence" => { + let ord = get_ord_at(0); + this.atomic_fence_intrinsic(args, fence_ord(ord))? + } + "singlethreadfence" => { + let ord = get_ord_at(0); + this.compiler_fence_intrinsic(args, fence_ord(ord))?; + } + + "xchg" => { + let ord = get_ord_at(1); + this.atomic_exchange(args, dest, rw_ord(ord))?; + } + "cxchg" => { + let ord1 = get_ord_at(1); + let ord2 = get_ord_at(2); + this.atomic_compare_exchange(args, dest, rw_ord(ord1), read_ord(ord2))?; + } + "cxchgweak" => { + let ord1 = get_ord_at(1); + let ord2 = get_ord_at(2); + this.atomic_compare_exchange_weak(args, dest, rw_ord(ord1), read_ord(ord2))?; + } + + "or" => { + let ord = get_ord_at(1); + this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), rw_ord(ord))?; + } + "xor" => { + let ord = get_ord_at(1); + this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), rw_ord(ord))?; + } + "and" => { + let ord = get_ord_at(1); + this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), rw_ord(ord))?; + } + "nand" => { + let ord = get_ord_at(1); + this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), rw_ord(ord))?; + } + "xadd" => { + let ord = get_ord_at(1); + this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), rw_ord(ord))?; + } + "xsub" => { + let ord = get_ord_at(1); + this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), rw_ord(ord))?; + } + "min" => { + let ord = get_ord_at(1); // Later we will use the type to indicate signed vs unsigned, // so make sure it matches the intrinsic name. assert!(matches!(args[1].layout.ty.kind(), ty::Int(_))); this.atomic_rmw_op(args, dest, AtomicOp::Min, rw_ord(ord))?; } - ["umin", ord] => { + "umin" => { + let ord = get_ord_at(1); // Later we will use the type to indicate signed vs unsigned, // so make sure it matches the intrinsic name. assert!(matches!(args[1].layout.ty.kind(), ty::Uint(_))); this.atomic_rmw_op(args, dest, AtomicOp::Min, rw_ord(ord))?; } - ["max", ord] => { + "max" => { + let ord = get_ord_at(1); // Later we will use the type to indicate signed vs unsigned, // so make sure it matches the intrinsic name. assert!(matches!(args[1].layout.ty.kind(), ty::Int(_))); this.atomic_rmw_op(args, dest, AtomicOp::Max, rw_ord(ord))?; } - ["umax", ord] => { + "umax" => { + let ord = get_ord_at(1); // Later we will use the type to indicate signed vs unsigned, // so make sure it matches the intrinsic name. assert!(matches!(args[1].layout.ty.kind(), ty::Uint(_))); diff --git a/tests/run-make/atomic-lock-free/atomic_lock_free.rs b/tests/run-make/atomic-lock-free/atomic_lock_free.rs index b49c5044f31..e8bbd420cc4 100644 --- a/tests/run-make/atomic-lock-free/atomic_lock_free.rs +++ b/tests/run-make/atomic-lock-free/atomic_lock_free.rs @@ -1,9 +1,20 @@ #![feature(no_core, intrinsics, lang_items)] +#![feature(adt_const_params)] #![crate_type = "rlib"] #![no_core] +pub enum AtomicOrdering { + // These values must match the compiler's `AtomicOrdering` defined in + // `rustc_middle/src/ty/consts/int.rs`! + Relaxed = 0, + Release = 1, + Acquire = 2, + AcqRel = 3, + SeqCst = 4, +} + #[rustc_intrinsic] -unsafe fn atomic_xadd_seqcst(dst: *mut T, src: T) -> T; +unsafe fn atomic_xadd(dst: *mut T, src: T) -> T; #[lang = "sized"] trait Sized {} @@ -11,55 +22,58 @@ trait Sized {} trait Copy {} #[lang = "freeze"] trait Freeze {} +#[lang = "const_param_ty"] +pub trait ConstParamTy {} impl Copy for *mut T {} +impl ConstParamTy for AtomicOrdering {} #[cfg(target_has_atomic = "8")] pub unsafe fn atomic_u8(x: *mut u8) { - atomic_xadd_seqcst(x, 1); - atomic_xadd_seqcst(x, 1); + atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); + atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); } #[cfg(target_has_atomic = "8")] pub unsafe fn atomic_i8(x: *mut i8) { - atomic_xadd_seqcst(x, 1); + atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); } #[cfg(target_has_atomic = "16")] pub unsafe fn atomic_u16(x: *mut u16) { - atomic_xadd_seqcst(x, 1); + atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); } #[cfg(target_has_atomic = "16")] pub unsafe fn atomic_i16(x: *mut i16) { - atomic_xadd_seqcst(x, 1); + atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); } #[cfg(target_has_atomic = "32")] pub unsafe fn atomic_u32(x: *mut u32) { - atomic_xadd_seqcst(x, 1); + atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); } #[cfg(target_has_atomic = "32")] pub unsafe fn atomic_i32(x: *mut i32) { - atomic_xadd_seqcst(x, 1); + atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); } #[cfg(target_has_atomic = "64")] pub unsafe fn atomic_u64(x: *mut u64) { - atomic_xadd_seqcst(x, 1); + atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); } #[cfg(target_has_atomic = "64")] pub unsafe fn atomic_i64(x: *mut i64) { - atomic_xadd_seqcst(x, 1); + atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); } #[cfg(target_has_atomic = "128")] pub unsafe fn atomic_u128(x: *mut u128) { - atomic_xadd_seqcst(x, 1); + atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); } #[cfg(target_has_atomic = "128")] pub unsafe fn atomic_i128(x: *mut i128) { - atomic_xadd_seqcst(x, 1); + atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); } #[cfg(target_has_atomic = "ptr")] pub unsafe fn atomic_usize(x: *mut usize) { - atomic_xadd_seqcst(x, 1); + atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); } #[cfg(target_has_atomic = "ptr")] pub unsafe fn atomic_isize(x: *mut isize) { - atomic_xadd_seqcst(x, 1); + atomic_xadd::<_, { AtomicOrdering::SeqCst }>(x, 1); } diff --git a/tests/ui/error-codes/E0092.rs b/tests/ui/error-codes/E0092.rs deleted file mode 100644 index 19a7c65a48e..00000000000 --- a/tests/ui/error-codes/E0092.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![feature(intrinsics)] - -#[rustc_intrinsic] -unsafe fn atomic_foo(); //~ ERROR E0092 - -fn main() {} diff --git a/tests/ui/error-codes/E0092.stderr b/tests/ui/error-codes/E0092.stderr deleted file mode 100644 index 003c989fd59..00000000000 --- a/tests/ui/error-codes/E0092.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0092]: unrecognized atomic operation function: `foo` - --> $DIR/E0092.rs:4:11 - | -LL | unsafe fn atomic_foo(); - | ^^^^^^^^^^ unrecognized atomic operation - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0092`. diff --git a/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.stderr b/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.stderr index aaaaeece67a..fb05273b6ff 100644 --- a/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.stderr +++ b/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.stderr @@ -7,7 +7,7 @@ LL | #[rustc_intrinsic] = help: add `#![feature(intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0133]: call to unsafe function `atomic_fence` is unsafe and requires unsafe function or block +error[E0133]: call to unsafe function `main::atomic_fence` is unsafe and requires unsafe function or block --> $DIR/feature-gated-feature-in-macro-arg.rs:11:9 | LL | atomic_fence(); diff --git a/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs b/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs index 1014ac6f560..ab4604b77b3 100644 --- a/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs +++ b/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs @@ -1,11 +1,24 @@ -#![feature(intrinsics)] +#![feature(intrinsics, adt_const_params)] pub mod rusti { + use std::marker::ConstParamTy; + + #[derive(Debug, ConstParamTy, PartialEq, Eq)] + pub enum AtomicOrdering { + // These values must match the compiler's `AtomicOrdering` defined in + // `rustc_middle/src/ty/consts/int.rs`! + Relaxed = 0, + Release = 1, + Acquire = 2, + AcqRel = 3, + SeqCst = 4, + } + #[rustc_intrinsic] - pub unsafe fn atomic_xchg_seqcst(dst: *mut T, src: T) -> T; + pub unsafe fn atomic_xchg(dst: *mut T, src: T) -> T; } #[inline(always)] pub fn atomic_xchg_seqcst(dst: *mut isize, src: isize) -> isize { - unsafe { rusti::atomic_xchg_seqcst(dst, src) } + unsafe { rusti::atomic_xchg::<_, { rusti::AtomicOrdering::SeqCst }>(dst, src) } } diff --git a/tests/ui/intrinsics/intrinsic-atomics.rs b/tests/ui/intrinsics/intrinsic-atomics.rs index f96c6dc832e..2275aafff83 100644 --- a/tests/ui/intrinsics/intrinsic-atomics.rs +++ b/tests/ui/intrinsics/intrinsic-atomics.rs @@ -1,50 +1,50 @@ //@ run-pass #![feature(core_intrinsics)] -use std::intrinsics::{self as rusti, AtomicOrdering}; +use std::intrinsics::{self as rusti, AtomicOrdering::*}; pub fn main() { unsafe { let mut x: Box<_> = Box::new(1); - assert_eq!(rusti::atomic_load::<_, { AtomicOrdering::SeqCst }>(&*x), 1); + assert_eq!(rusti::atomic_load::<_, { SeqCst }>(&*x), 1); *x = 5; - assert_eq!(rusti::atomic_load::<_, { AtomicOrdering::Acquire }>(&*x), 5); + assert_eq!(rusti::atomic_load::<_, { Acquire }>(&*x), 5); - rusti::atomic_store_seqcst(&mut *x, 3); + rusti::atomic_store::<_, { SeqCst }>(&mut *x, 3); assert_eq!(*x, 3); - rusti::atomic_store_release(&mut *x, 1); + rusti::atomic_store::<_, { Release }>(&mut *x, 1); assert_eq!(*x, 1); - assert_eq!(rusti::atomic_cxchg_seqcst_seqcst(&mut *x, 1, 2), (1, true)); + assert_eq!(rusti::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(&mut *x, 1, 2), (1, true)); assert_eq!(*x, 2); - assert_eq!(rusti::atomic_cxchg_acquire_acquire(&mut *x, 1, 3), (2, false)); + assert_eq!(rusti::atomic_cxchg::<_, { Acquire }, { Acquire }>(&mut *x, 1, 3), (2, false)); assert_eq!(*x, 2); - assert_eq!(rusti::atomic_cxchg_release_relaxed(&mut *x, 2, 1), (2, true)); + assert_eq!(rusti::atomic_cxchg::<_, { Release }, { Relaxed }>(&mut *x, 2, 1), (2, true)); assert_eq!(*x, 1); - assert_eq!(rusti::atomic_xchg_seqcst(&mut *x, 0), 1); + assert_eq!(rusti::atomic_xchg::<_, { SeqCst }>(&mut *x, 0), 1); assert_eq!(*x, 0); - assert_eq!(rusti::atomic_xchg_acquire(&mut *x, 1), 0); + assert_eq!(rusti::atomic_xchg::<_, { Acquire }>(&mut *x, 1), 0); assert_eq!(*x, 1); - assert_eq!(rusti::atomic_xchg_release(&mut *x, 0), 1); + assert_eq!(rusti::atomic_xchg::<_, { Release }>(&mut *x, 0), 1); assert_eq!(*x, 0); - assert_eq!(rusti::atomic_xadd_seqcst(&mut *x, 1), 0); - assert_eq!(rusti::atomic_xadd_acquire(&mut *x, 1), 1); - assert_eq!(rusti::atomic_xadd_release(&mut *x, 1), 2); + assert_eq!(rusti::atomic_xadd::<_, { SeqCst }>(&mut *x, 1), 0); + assert_eq!(rusti::atomic_xadd::<_, { Acquire }>(&mut *x, 1), 1); + assert_eq!(rusti::atomic_xadd::<_, { Release }>(&mut *x, 1), 2); assert_eq!(*x, 3); - assert_eq!(rusti::atomic_xsub_seqcst(&mut *x, 1), 3); - assert_eq!(rusti::atomic_xsub_acquire(&mut *x, 1), 2); - assert_eq!(rusti::atomic_xsub_release(&mut *x, 1), 1); + assert_eq!(rusti::atomic_xsub::<_, { SeqCst }>(&mut *x, 1), 3); + assert_eq!(rusti::atomic_xsub::<_, { Acquire }>(&mut *x, 1), 2); + assert_eq!(rusti::atomic_xsub::<_, { Release }>(&mut *x, 1), 1); assert_eq!(*x, 0); loop { - let res = rusti::atomic_cxchgweak_seqcst_seqcst(&mut *x, 0, 1); + let res = rusti::atomic_cxchgweak::<_, { SeqCst }, { SeqCst }>(&mut *x, 0, 1); assert_eq!(res.0, 0); if res.1 { break; @@ -53,7 +53,7 @@ pub fn main() { assert_eq!(*x, 1); loop { - let res = rusti::atomic_cxchgweak_acquire_acquire(&mut *x, 1, 2); + let res = rusti::atomic_cxchgweak::<_, { Acquire }, { Acquire }>(&mut *x, 1, 2); assert_eq!(res.0, 1); if res.1 { break; @@ -62,7 +62,7 @@ pub fn main() { assert_eq!(*x, 2); loop { - let res = rusti::atomic_cxchgweak_release_relaxed(&mut *x, 2, 3); + let res = rusti::atomic_cxchgweak::<_, { Release }, { Relaxed }>(&mut *x, 2, 3); assert_eq!(res.0, 2); if res.1 { break; diff --git a/tests/ui/intrinsics/non-integer-atomic.rs b/tests/ui/intrinsics/non-integer-atomic.rs index 5464bf747fa..853c163710f 100644 --- a/tests/ui/intrinsics/non-integer-atomic.rs +++ b/tests/ui/intrinsics/non-integer-atomic.rs @@ -4,7 +4,7 @@ #![allow(warnings)] #![crate_type = "rlib"] -use std::intrinsics::{self, AtomicOrdering}; +use std::intrinsics::{self, AtomicOrdering::*}; #[derive(Copy, Clone)] pub struct Foo(i64); @@ -12,81 +12,81 @@ pub type Bar = &'static dyn Fn(); pub type Quux = [u8; 100]; pub unsafe fn test_bool_load(p: &mut bool, v: bool) { - intrinsics::atomic_load::<_, { AtomicOrdering::SeqCst }>(p); + intrinsics::atomic_load::<_, { SeqCst }>(p); //~^ ERROR `atomic_load` intrinsic: expected basic integer type, found `bool` } pub unsafe fn test_bool_store(p: &mut bool, v: bool) { - intrinsics::atomic_store_seqcst(p, v); - //~^ ERROR `atomic_store_seqcst` intrinsic: expected basic integer type, found `bool` + intrinsics::atomic_store::<_, { SeqCst }>(p, v); + //~^ ERROR `atomic_store` intrinsic: expected basic integer type, found `bool` } pub unsafe fn test_bool_xchg(p: &mut bool, v: bool) { - intrinsics::atomic_xchg_seqcst(p, v); - //~^ ERROR `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `bool` + intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); + //~^ ERROR `atomic_xchg` intrinsic: expected basic integer type, found `bool` } pub unsafe fn test_bool_cxchg(p: &mut bool, v: bool) { - intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); - //~^ ERROR `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `bool` + intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); + //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer type, found `bool` } pub unsafe fn test_Foo_load(p: &mut Foo, v: Foo) { - intrinsics::atomic_load::<_, { AtomicOrdering::SeqCst }>(p); + intrinsics::atomic_load::<_, { SeqCst }>(p); //~^ ERROR `atomic_load` intrinsic: expected basic integer type, found `Foo` } pub unsafe fn test_Foo_store(p: &mut Foo, v: Foo) { - intrinsics::atomic_store_seqcst(p, v); - //~^ ERROR `atomic_store_seqcst` intrinsic: expected basic integer type, found `Foo` + intrinsics::atomic_store::<_, { SeqCst }>(p, v); + //~^ ERROR `atomic_store` intrinsic: expected basic integer type, found `Foo` } pub unsafe fn test_Foo_xchg(p: &mut Foo, v: Foo) { - intrinsics::atomic_xchg_seqcst(p, v); - //~^ ERROR `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `Foo` + intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); + //~^ ERROR `atomic_xchg` intrinsic: expected basic integer type, found `Foo` } pub unsafe fn test_Foo_cxchg(p: &mut Foo, v: Foo) { - intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); - //~^ ERROR `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `Foo` + intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); + //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer type, found `Foo` } pub unsafe fn test_Bar_load(p: &mut Bar, v: Bar) { - intrinsics::atomic_load::<_, { AtomicOrdering::SeqCst }>(p); + intrinsics::atomic_load::<_, { SeqCst }>(p); //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Bar_store(p: &mut Bar, v: Bar) { - intrinsics::atomic_store_seqcst(p, v); + intrinsics::atomic_store::<_, { SeqCst }>(p, v); //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Bar_xchg(p: &mut Bar, v: Bar) { - intrinsics::atomic_xchg_seqcst(p, v); + intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Bar_cxchg(p: &mut Bar, v: Bar) { - intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Quux_load(p: &mut Quux, v: Quux) { - intrinsics::atomic_load::<_, { AtomicOrdering::SeqCst }>(p); + intrinsics::atomic_load::<_, { SeqCst }>(p); //~^ ERROR `atomic_load` intrinsic: expected basic integer type, found `[u8; 100]` } pub unsafe fn test_Quux_store(p: &mut Quux, v: Quux) { - intrinsics::atomic_store_seqcst(p, v); - //~^ ERROR `atomic_store_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` + intrinsics::atomic_store::<_, { SeqCst }>(p, v); + //~^ ERROR `atomic_store` intrinsic: expected basic integer type, found `[u8; 100]` } pub unsafe fn test_Quux_xchg(p: &mut Quux, v: Quux) { - intrinsics::atomic_xchg_seqcst(p, v); - //~^ ERROR `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` + intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); + //~^ ERROR `atomic_xchg` intrinsic: expected basic integer type, found `[u8; 100]` } pub unsafe fn test_Quux_cxchg(p: &mut Quux, v: Quux) { - intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); - //~^ ERROR `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` + intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); + //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer type, found `[u8; 100]` } diff --git a/tests/ui/intrinsics/non-integer-atomic.stderr b/tests/ui/intrinsics/non-integer-atomic.stderr index 58c2dc00c66..e539d99b8ae 100644 --- a/tests/ui/intrinsics/non-integer-atomic.stderr +++ b/tests/ui/intrinsics/non-integer-atomic.stderr @@ -1,98 +1,98 @@ error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `bool` --> $DIR/non-integer-atomic.rs:15:5 | -LL | intrinsics::atomic_load::<_, { AtomicOrdering::SeqCst }>(p); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_load::<_, { SeqCst }>(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store_seqcst` intrinsic: expected basic integer type, found `bool` +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `bool` --> $DIR/non-integer-atomic.rs:20:5 | -LL | intrinsics::atomic_store_seqcst(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `bool` +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `bool` --> $DIR/non-integer-atomic.rs:25:5 | -LL | intrinsics::atomic_xchg_seqcst(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `bool` +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `bool` --> $DIR/non-integer-atomic.rs:30:5 | -LL | intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `Foo` --> $DIR/non-integer-atomic.rs:35:5 | -LL | intrinsics::atomic_load::<_, { AtomicOrdering::SeqCst }>(p); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_load::<_, { SeqCst }>(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store_seqcst` intrinsic: expected basic integer type, found `Foo` +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `Foo` --> $DIR/non-integer-atomic.rs:40:5 | -LL | intrinsics::atomic_store_seqcst(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `Foo` +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `Foo` --> $DIR/non-integer-atomic.rs:45:5 | -LL | intrinsics::atomic_xchg_seqcst(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `Foo` +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `Foo` --> $DIR/non-integer-atomic.rs:50:5 | -LL | intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:55:5 | -LL | intrinsics::atomic_load::<_, { AtomicOrdering::SeqCst }>(p); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_load::<_, { SeqCst }>(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store_seqcst` intrinsic: expected basic integer type, found `&dyn Fn()` +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:60:5 | -LL | intrinsics::atomic_store_seqcst(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `&dyn Fn()` +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:65:5 | -LL | intrinsics::atomic_xchg_seqcst(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `&dyn Fn()` +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:70:5 | -LL | intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `[u8; 100]` --> $DIR/non-integer-atomic.rs:75:5 | -LL | intrinsics::atomic_load::<_, { AtomicOrdering::SeqCst }>(p); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_load::<_, { SeqCst }>(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `[u8; 100]` --> $DIR/non-integer-atomic.rs:80:5 | -LL | intrinsics::atomic_store_seqcst(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `[u8; 100]` --> $DIR/non-integer-atomic.rs:85:5 | -LL | intrinsics::atomic_xchg_seqcst(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `[u8; 100]` --> $DIR/non-integer-atomic.rs:90:5 | -LL | intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 16 previous errors -- cgit 1.4.1-3-g733a5 From 2a3a6150d4078d2ae23c6e6af3dbfaea56bd56c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 May 2025 18:43:16 +0200 Subject: move all intrinsic typeck logic into the one big match --- compiler/rustc_hir_analysis/src/check/intrinsic.rs | 952 ++++++++++----------- 1 file changed, 457 insertions(+), 495 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index d8080d2537b..481cdaa4c6c 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -194,509 +194,471 @@ pub(crate) fn check_intrinsic_type( (Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty) }; - let (n_tps, n_lts, n_cts, inputs, output, safety) = if intrinsic_name - == sym::contract_check_ensures - { - // contract_check_ensures::(Ret, C) -> Ret - // where C: for<'a> Fn(&'a Ret) -> bool, - // - // so: two type params, 0 lifetime param, 0 const params, two inputs, no return - (2, 0, 0, vec![param(0), param(1)], param(1), hir::Safety::Safe) - } else { - let safety = intrinsic_operation_unsafety(tcx, intrinsic_id); - let (n_tps, n_cts, inputs, output) = match intrinsic_name { - sym::abort => (0, 0, vec![], tcx.types.never), - sym::unreachable => (0, 0, vec![], tcx.types.never), - sym::breakpoint => (0, 0, vec![], tcx.types.unit), - sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => { - (1, 0, vec![], tcx.types.usize) - } - sym::size_of_val | sym::min_align_of_val => { - (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize) - } - sym::rustc_peek => (1, 0, vec![param(0)], param(0)), - sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()), - sym::assert_inhabited - | sym::assert_zero_valid - | sym::assert_mem_uninitialized_valid => (1, 0, vec![], tcx.types.unit), - sym::forget => (1, 0, vec![param(0)], tcx.types.unit), - sym::transmute | sym::transmute_unchecked => (2, 0, vec![param(0)], param(1)), - sym::prefetch_read_data - | sym::prefetch_write_data - | sym::prefetch_read_instruction - | sym::prefetch_write_instruction => { - (1, 0, vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.i32], tcx.types.unit) - } - sym::needs_drop => (1, 0, vec![], tcx.types.bool), - - sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)), - sym::type_id => (1, 0, vec![], tcx.types.u128), - sym::offset => (2, 0, vec![param(0), param(1)], param(0)), - sym::arith_offset => ( - 1, - 0, - vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.isize], - Ty::new_imm_ptr(tcx, param(0)), - ), - sym::slice_get_unchecked => (3, 0, vec![param(1), tcx.types.usize], param(0)), - sym::ptr_mask => ( - 1, - 0, - vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.usize], - Ty::new_imm_ptr(tcx, param(0)), - ), + let safety = intrinsic_operation_unsafety(tcx, intrinsic_id); + let n_lts = 0; + let (n_tps, n_cts, inputs, output) = match intrinsic_name { + sym::abort => (0, 0, vec![], tcx.types.never), + sym::unreachable => (0, 0, vec![], tcx.types.never), + sym::breakpoint => (0, 0, vec![], tcx.types.unit), + sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => { + (1, 0, vec![], tcx.types.usize) + } + sym::size_of_val | sym::min_align_of_val => { + (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize) + } + sym::rustc_peek => (1, 0, vec![param(0)], param(0)), + sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()), + sym::assert_inhabited | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid => { + (1, 0, vec![], tcx.types.unit) + } + sym::forget => (1, 0, vec![param(0)], tcx.types.unit), + sym::transmute | sym::transmute_unchecked => (2, 0, vec![param(0)], param(1)), + sym::prefetch_read_data + | sym::prefetch_write_data + | sym::prefetch_read_instruction + | sym::prefetch_write_instruction => { + (1, 0, vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.i32], tcx.types.unit) + } + sym::needs_drop => (1, 0, vec![], tcx.types.bool), + + sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)), + sym::type_id => (1, 0, vec![], tcx.types.u128), + sym::offset => (2, 0, vec![param(0), param(1)], param(0)), + sym::arith_offset => ( + 1, + 0, + vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.isize], + Ty::new_imm_ptr(tcx, param(0)), + ), + sym::slice_get_unchecked => (3, 0, vec![param(1), tcx.types.usize], param(0)), + sym::ptr_mask => ( + 1, + 0, + vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.usize], + Ty::new_imm_ptr(tcx, param(0)), + ), + + sym::copy | sym::copy_nonoverlapping => ( + 1, + 0, + vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_mut_ptr(tcx, param(0)), tcx.types.usize], + tcx.types.unit, + ), + sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => ( + 1, + 0, + vec![Ty::new_mut_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0)), tcx.types.usize], + tcx.types.unit, + ), + sym::compare_bytes => { + let byte_ptr = Ty::new_imm_ptr(tcx, tcx.types.u8); + (0, 0, vec![byte_ptr, byte_ptr, tcx.types.usize], tcx.types.i32) + } + sym::write_bytes | sym::volatile_set_memory => ( + 1, + 0, + vec![Ty::new_mut_ptr(tcx, param(0)), tcx.types.u8, tcx.types.usize], + tcx.types.unit, + ), + + sym::sqrtf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::sqrtf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::sqrtf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::sqrtf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + + sym::powif16 => (0, 0, vec![tcx.types.f16, tcx.types.i32], tcx.types.f16), + sym::powif32 => (0, 0, vec![tcx.types.f32, tcx.types.i32], tcx.types.f32), + sym::powif64 => (0, 0, vec![tcx.types.f64, tcx.types.i32], tcx.types.f64), + sym::powif128 => (0, 0, vec![tcx.types.f128, tcx.types.i32], tcx.types.f128), + + sym::sinf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::sinf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::sinf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::sinf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + + sym::cosf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::cosf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::cosf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::cosf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + + sym::powf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), + sym::powf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::powf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::powf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), + + sym::expf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::expf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::expf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::expf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + + sym::exp2f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::exp2f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::exp2f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::exp2f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + + sym::logf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::logf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::logf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::logf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + + sym::log10f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::log10f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::log10f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::log10f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + + sym::log2f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::log2f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::log2f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::log2f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + + sym::fmaf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16, tcx.types.f16], tcx.types.f16), + sym::fmaf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::fmaf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::fmaf128 => { + (0, 0, vec![tcx.types.f128, tcx.types.f128, tcx.types.f128], tcx.types.f128) + } - sym::copy | sym::copy_nonoverlapping => ( - 1, - 0, - vec![ - Ty::new_imm_ptr(tcx, param(0)), - Ty::new_mut_ptr(tcx, param(0)), - tcx.types.usize, - ], - tcx.types.unit, - ), - sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => ( + sym::fmuladdf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16, tcx.types.f16], tcx.types.f16), + sym::fmuladdf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::fmuladdf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::fmuladdf128 => { + (0, 0, vec![tcx.types.f128, tcx.types.f128, tcx.types.f128], tcx.types.f128) + } + + sym::fabsf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::fabsf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::fabsf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::fabsf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + + sym::minnumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), + sym::minnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::minnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::minnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), + + sym::minimumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), + sym::minimumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::minimumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::minimumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), + + sym::maxnumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), + sym::maxnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::maxnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::maxnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), + + sym::maximumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), + sym::maximumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::maximumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::maximumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), + + sym::copysignf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), + sym::copysignf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), + sym::copysignf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), + sym::copysignf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), + + sym::floorf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::floorf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::floorf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::floorf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + + sym::ceilf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::ceilf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::ceilf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::ceilf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + + sym::truncf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::truncf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::truncf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::truncf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + + sym::round_ties_even_f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::round_ties_even_f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::round_ties_even_f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::round_ties_even_f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + + sym::roundf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::roundf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::roundf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::roundf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + + sym::volatile_load | sym::unaligned_volatile_load => { + (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)) + } + sym::volatile_store | sym::unaligned_volatile_store => { + (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) + } + + sym::ctpop | sym::ctlz | sym::ctlz_nonzero | sym::cttz | sym::cttz_nonzero => { + (1, 0, vec![param(0)], tcx.types.u32) + } + + sym::bswap | sym::bitreverse => (1, 0, vec![param(0)], param(0)), + + sym::three_way_compare => (1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(span)), + + sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { + (1, 0, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool])) + } + + sym::carrying_mul_add => (2, 0, vec![param(0); 4], Ty::new_tup(tcx, &[param(1), param(0)])), + + sym::ptr_guaranteed_cmp => ( + 1, + 0, + vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], + tcx.types.u8, + ), + + sym::const_allocate => { + (0, 0, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8)) + } + sym::const_deallocate => ( + 0, + 0, + vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize], + tcx.types.unit, + ), + + sym::ptr_offset_from => ( + 1, + 0, + vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], + tcx.types.isize, + ), + sym::ptr_offset_from_unsigned => ( + 1, + 0, + vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], + tcx.types.usize, + ), + sym::unchecked_div | sym::unchecked_rem | sym::exact_div | sym::disjoint_bitor => { + (1, 0, vec![param(0), param(0)], param(0)) + } + sym::unchecked_shl | sym::unchecked_shr => (2, 0, vec![param(0), param(1)], param(0)), + sym::rotate_left | sym::rotate_right => (1, 0, vec![param(0), tcx.types.u32], param(0)), + sym::unchecked_add | sym::unchecked_sub | sym::unchecked_mul => { + (1, 0, vec![param(0), param(0)], param(0)) + } + sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => { + (1, 0, vec![param(0), param(0)], param(0)) + } + sym::saturating_add | sym::saturating_sub => (1, 0, vec![param(0), param(0)], param(0)), + sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { + (1, 0, vec![param(0), param(0)], param(0)) + } + sym::fadd_algebraic + | sym::fsub_algebraic + | sym::fmul_algebraic + | sym::fdiv_algebraic + | sym::frem_algebraic => (1, 0, vec![param(0), param(0)], param(0)), + sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)), + + sym::assume => (0, 0, vec![tcx.types.bool], tcx.types.unit), + sym::select_unpredictable => (1, 0, vec![tcx.types.bool, param(0), param(0)], param(0)), + sym::cold_path => (0, 0, vec![], tcx.types.unit), + + sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), + sym::write_via_move => { + (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) + } + + sym::typed_swap_nonoverlapping => { + (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit) + } + + sym::discriminant_value => { + let assoc_items = tcx.associated_item_def_ids( + tcx.require_lang_item(hir::LangItem::DiscriminantKind, span), + ); + let discriminant_def_id = assoc_items[0]; + + let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon }; + ( 1, 0, - vec![ - Ty::new_mut_ptr(tcx, param(0)), - Ty::new_imm_ptr(tcx, param(0)), - tcx.types.usize, - ], + vec![Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0))], + Ty::new_projection_from_args( + tcx, + discriminant_def_id, + tcx.mk_args(&[param(0).into()]), + ), + ) + } + + sym::catch_unwind => { + let mut_u8 = Ty::new_mut_ptr(tcx, tcx.types.u8); + let try_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( + [mut_u8], tcx.types.unit, - ), - sym::compare_bytes => { - let byte_ptr = Ty::new_imm_ptr(tcx, tcx.types.u8); - (0, 0, vec![byte_ptr, byte_ptr, tcx.types.usize], tcx.types.i32) - } - sym::write_bytes | sym::volatile_set_memory => ( - 1, - 0, - vec![Ty::new_mut_ptr(tcx, param(0)), tcx.types.u8, tcx.types.usize], + false, + hir::Safety::Safe, + ExternAbi::Rust, + )); + let catch_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( + [mut_u8, mut_u8], tcx.types.unit, - ), - - sym::sqrtf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::sqrtf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::sqrtf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::sqrtf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::powif16 => (0, 0, vec![tcx.types.f16, tcx.types.i32], tcx.types.f16), - sym::powif32 => (0, 0, vec![tcx.types.f32, tcx.types.i32], tcx.types.f32), - sym::powif64 => (0, 0, vec![tcx.types.f64, tcx.types.i32], tcx.types.f64), - sym::powif128 => (0, 0, vec![tcx.types.f128, tcx.types.i32], tcx.types.f128), - - sym::sinf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::sinf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::sinf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::sinf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::cosf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::cosf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::cosf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::cosf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::powf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), - sym::powf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - sym::powf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - sym::powf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), - - sym::expf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::expf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::expf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::expf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::exp2f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::exp2f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::exp2f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::exp2f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::logf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::logf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::logf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::logf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::log10f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::log10f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::log10f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::log10f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::log2f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::log2f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::log2f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::log2f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::fmaf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16, tcx.types.f16], tcx.types.f16), - sym::fmaf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32), - sym::fmaf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64), - sym::fmaf128 => { - (0, 0, vec![tcx.types.f128, tcx.types.f128, tcx.types.f128], tcx.types.f128) - } - - sym::fmuladdf16 => { - (0, 0, vec![tcx.types.f16, tcx.types.f16, tcx.types.f16], tcx.types.f16) - } - sym::fmuladdf32 => { - (0, 0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32) - } - sym::fmuladdf64 => { - (0, 0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64) - } - sym::fmuladdf128 => { - (0, 0, vec![tcx.types.f128, tcx.types.f128, tcx.types.f128], tcx.types.f128) - } - - sym::fabsf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::fabsf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::fabsf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::fabsf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::minnumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), - sym::minnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - sym::minnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - sym::minnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), - - sym::minimumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), - sym::minimumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - sym::minimumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - sym::minimumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), - - sym::maxnumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), - sym::maxnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - sym::maxnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - sym::maxnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), - - sym::maximumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), - sym::maximumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - sym::maximumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - sym::maximumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), - - sym::copysignf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), - sym::copysignf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - sym::copysignf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - sym::copysignf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), - - sym::floorf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::floorf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::floorf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::floorf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::ceilf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::ceilf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::ceilf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::ceilf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::truncf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::truncf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::truncf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::truncf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::round_ties_even_f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::round_ties_even_f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::round_ties_even_f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::round_ties_even_f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::roundf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::roundf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::roundf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::roundf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::volatile_load | sym::unaligned_volatile_load => { - (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)) - } - sym::volatile_store | sym::unaligned_volatile_store => { - (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) - } - - sym::ctpop | sym::ctlz | sym::ctlz_nonzero | sym::cttz | sym::cttz_nonzero => { - (1, 0, vec![param(0)], tcx.types.u32) - } - - sym::bswap | sym::bitreverse => (1, 0, vec![param(0)], param(0)), - - sym::three_way_compare => (1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(span)), - - sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { - (1, 0, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool])) - } - - sym::carrying_mul_add => { - (2, 0, vec![param(0); 4], Ty::new_tup(tcx, &[param(1), param(0)])) - } - - sym::ptr_guaranteed_cmp => ( - 1, - 0, - vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], - tcx.types.u8, - ), - - sym::const_allocate => { - (0, 0, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8)) - } - sym::const_deallocate => ( + false, + hir::Safety::Safe, + ExternAbi::Rust, + )); + ( 0, 0, - vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize], - tcx.types.unit, - ), + vec![Ty::new_fn_ptr(tcx, try_fn_ty), mut_u8, Ty::new_fn_ptr(tcx, catch_fn_ty)], + tcx.types.i32, + ) + } - sym::ptr_offset_from => ( - 1, - 0, - vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], - tcx.types.isize, - ), - sym::ptr_offset_from_unsigned => ( - 1, - 0, - vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], - tcx.types.usize, - ), - sym::unchecked_div | sym::unchecked_rem | sym::exact_div | sym::disjoint_bitor => { - (1, 0, vec![param(0), param(0)], param(0)) - } - sym::unchecked_shl | sym::unchecked_shr => (2, 0, vec![param(0), param(1)], param(0)), - sym::rotate_left | sym::rotate_right => (1, 0, vec![param(0), tcx.types.u32], param(0)), - sym::unchecked_add | sym::unchecked_sub | sym::unchecked_mul => { - (1, 0, vec![param(0), param(0)], param(0)) - } - sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => { - (1, 0, vec![param(0), param(0)], param(0)) - } - sym::saturating_add | sym::saturating_sub => (1, 0, vec![param(0), param(0)], param(0)), - sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { - (1, 0, vec![param(0), param(0)], param(0)) - } - sym::fadd_algebraic - | sym::fsub_algebraic - | sym::fmul_algebraic - | sym::fdiv_algebraic - | sym::frem_algebraic => (1, 0, vec![param(0), param(0)], param(0)), - sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)), - - sym::assume => (0, 0, vec![tcx.types.bool], tcx.types.unit), - sym::select_unpredictable => (1, 0, vec![tcx.types.bool, param(0), param(0)], param(0)), - sym::cold_path => (0, 0, vec![], tcx.types.unit), - - sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), - sym::write_via_move => { - (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) - } - - sym::typed_swap_nonoverlapping => { - (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit) - } - - sym::discriminant_value => { - let assoc_items = tcx.associated_item_def_ids( - tcx.require_lang_item(hir::LangItem::DiscriminantKind, span), - ); - let discriminant_def_id = assoc_items[0]; - - let br = - ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon }; - ( - 1, - 0, - vec![Ty::new_imm_ref( - tcx, - ty::Region::new_bound(tcx, ty::INNERMOST, br), - param(0), - )], - Ty::new_projection_from_args( - tcx, - discriminant_def_id, - tcx.mk_args(&[param(0).into()]), - ), - ) - } - - sym::catch_unwind => { - let mut_u8 = Ty::new_mut_ptr(tcx, tcx.types.u8); - let try_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( - [mut_u8], - tcx.types.unit, - false, - hir::Safety::Safe, - ExternAbi::Rust, - )); - let catch_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( - [mut_u8, mut_u8], - tcx.types.unit, - false, - hir::Safety::Safe, - ExternAbi::Rust, - )); - ( - 0, - 0, - vec![Ty::new_fn_ptr(tcx, try_fn_ty), mut_u8, Ty::new_fn_ptr(tcx, catch_fn_ty)], - tcx.types.i32, - ) - } - - sym::va_start | sym::va_end => { - (0, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], tcx.types.unit) - } - - sym::va_copy => { - let (va_list_ref_ty, va_list_ty) = mk_va_list_ty(hir::Mutability::Not); - let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty); - (0, 0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.types.unit) - } - - sym::va_arg => (1, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], param(0)), - - sym::nontemporal_store => { - (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) - } - - sym::raw_eq => { - let br = - ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon }; - let param_ty_lhs = - Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0)); - let br = ty::BoundRegion { - var: ty::BoundVar::from_u32(1), - kind: ty::BoundRegionKind::Anon, - }; - let param_ty_rhs = - Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0)); - (1, 0, vec![param_ty_lhs, param_ty_rhs], tcx.types.bool) - } - - sym::black_box => (1, 0, vec![param(0)], param(0)), - - sym::is_val_statically_known => (1, 0, vec![param(0)], tcx.types.bool), - - sym::const_eval_select => (4, 0, vec![param(0), param(1), param(2)], param(3)), - - sym::vtable_size | sym::vtable_align => { - (0, 0, vec![Ty::new_imm_ptr(tcx, tcx.types.unit)], tcx.types.usize) - } - - // This type check is not particularly useful, but the `where` bounds - // on the definition in `core` do the heavy lifting for checking it. - sym::aggregate_raw_ptr => (3, 0, vec![param(1), param(2)], param(0)), - sym::ptr_metadata => (2, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)), - - sym::ub_checks => (0, 0, Vec::new(), tcx.types.bool), - - sym::box_new => (1, 0, vec![param(0)], Ty::new_box(tcx, param(0))), - - // contract_checks() -> bool - sym::contract_checks => (0, 0, Vec::new(), tcx.types.bool), - // contract_check_requires::(C) -> bool, where C: impl Fn() -> bool - sym::contract_check_requires => (1, 0, vec![param(0)], tcx.types.unit), - - sym::simd_eq - | sym::simd_ne - | sym::simd_lt - | sym::simd_le - | sym::simd_gt - | sym::simd_ge => (2, 0, vec![param(0), param(0)], param(1)), - sym::simd_add - | sym::simd_sub - | sym::simd_mul - | sym::simd_rem - | sym::simd_div - | sym::simd_shl - | sym::simd_shr - | sym::simd_and - | sym::simd_or - | sym::simd_xor - | sym::simd_fmin - | sym::simd_fmax - | sym::simd_saturating_add - | sym::simd_saturating_sub => (1, 0, vec![param(0), param(0)], param(0)), - sym::simd_arith_offset => (2, 0, vec![param(0), param(1)], param(0)), - sym::simd_neg - | sym::simd_bswap - | sym::simd_bitreverse - | sym::simd_ctlz - | sym::simd_cttz - | sym::simd_ctpop - | sym::simd_fsqrt - | sym::simd_fsin - | sym::simd_fcos - | sym::simd_fexp - | sym::simd_fexp2 - | sym::simd_flog2 - | sym::simd_flog10 - | sym::simd_flog - | sym::simd_fabs - | sym::simd_ceil - | sym::simd_floor - | sym::simd_round - | sym::simd_trunc => (1, 0, vec![param(0)], param(0)), - sym::simd_fma | sym::simd_relaxed_fma => { - (1, 0, vec![param(0), param(0), param(0)], param(0)) - } - sym::simd_gather => (3, 0, vec![param(0), param(1), param(2)], param(0)), - sym::simd_masked_load => (3, 0, vec![param(0), param(1), param(2)], param(2)), - sym::simd_masked_store => (3, 0, vec![param(0), param(1), param(2)], tcx.types.unit), - sym::simd_scatter => (3, 0, vec![param(0), param(1), param(2)], tcx.types.unit), - sym::simd_insert | sym::simd_insert_dyn => { - (2, 0, vec![param(0), tcx.types.u32, param(1)], param(0)) - } - sym::simd_extract | sym::simd_extract_dyn => { - (2, 0, vec![param(0), tcx.types.u32], param(1)) - } - sym::simd_cast - | sym::simd_as - | sym::simd_cast_ptr - | sym::simd_expose_provenance - | sym::simd_with_exposed_provenance => (2, 0, vec![param(0)], param(1)), - sym::simd_bitmask => (2, 0, vec![param(0)], param(1)), - sym::simd_select | sym::simd_select_bitmask => { - (2, 0, vec![param(0), param(1), param(1)], param(1)) - } - sym::simd_reduce_all | sym::simd_reduce_any => (1, 0, vec![param(0)], tcx.types.bool), - sym::simd_reduce_add_ordered | sym::simd_reduce_mul_ordered => { - (2, 0, vec![param(0), param(1)], param(1)) - } - sym::simd_reduce_add_unordered - | sym::simd_reduce_mul_unordered - | sym::simd_reduce_and - | sym::simd_reduce_or - | sym::simd_reduce_xor - | sym::simd_reduce_min - | sym::simd_reduce_max => (2, 0, vec![param(0)], param(1)), - sym::simd_shuffle => (3, 0, vec![param(0), param(0), param(1)], param(2)), - sym::simd_shuffle_const_generic => (2, 1, vec![param(0), param(0)], param(1)), - - sym::atomic_cxchg | sym::atomic_cxchgweak => ( - 1, - 2, - vec![Ty::new_mut_ptr(tcx, param(0)), param(0), param(0)], - Ty::new_tup(tcx, &[param(0), tcx.types.bool]), - ), - sym::atomic_load => (1, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), - sym::atomic_store => { - (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) - } - - sym::atomic_xchg - | sym::atomic_xadd - | sym::atomic_xsub - | sym::atomic_and - | sym::atomic_nand - | sym::atomic_or - | sym::atomic_xor - | sym::atomic_max - | sym::atomic_min - | sym::atomic_umax - | sym::atomic_umin => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)), - sym::atomic_fence | sym::atomic_singlethreadfence => (0, 1, Vec::new(), tcx.types.unit), - - other => { - tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other }); - return; - } - }; - (n_tps, 0, n_cts, inputs, output, safety) + sym::va_start | sym::va_end => { + (0, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], tcx.types.unit) + } + + sym::va_copy => { + let (va_list_ref_ty, va_list_ty) = mk_va_list_ty(hir::Mutability::Not); + let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty); + (0, 0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.types.unit) + } + + sym::va_arg => (1, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], param(0)), + + sym::nontemporal_store => { + (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) + } + + sym::raw_eq => { + let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon }; + let param_ty_lhs = + Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0)); + let br = + ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BoundRegionKind::Anon }; + let param_ty_rhs = + Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0)); + (1, 0, vec![param_ty_lhs, param_ty_rhs], tcx.types.bool) + } + + sym::black_box => (1, 0, vec![param(0)], param(0)), + + sym::is_val_statically_known => (1, 0, vec![param(0)], tcx.types.bool), + + sym::const_eval_select => (4, 0, vec![param(0), param(1), param(2)], param(3)), + + sym::vtable_size | sym::vtable_align => { + (0, 0, vec![Ty::new_imm_ptr(tcx, tcx.types.unit)], tcx.types.usize) + } + + // This type check is not particularly useful, but the `where` bounds + // on the definition in `core` do the heavy lifting for checking it. + sym::aggregate_raw_ptr => (3, 0, vec![param(1), param(2)], param(0)), + sym::ptr_metadata => (2, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)), + + sym::ub_checks => (0, 0, Vec::new(), tcx.types.bool), + + sym::box_new => (1, 0, vec![param(0)], Ty::new_box(tcx, param(0))), + + // contract_checks() -> bool + sym::contract_checks => (0, 0, Vec::new(), tcx.types.bool), + // contract_check_requires::(C) -> bool, where C: impl Fn() -> bool + sym::contract_check_requires => (1, 0, vec![param(0)], tcx.types.unit), + sym::contract_check_ensures => (2, 0, vec![param(0), param(1)], param(1)), + + sym::simd_eq | sym::simd_ne | sym::simd_lt | sym::simd_le | sym::simd_gt | sym::simd_ge => { + (2, 0, vec![param(0), param(0)], param(1)) + } + sym::simd_add + | sym::simd_sub + | sym::simd_mul + | sym::simd_rem + | sym::simd_div + | sym::simd_shl + | sym::simd_shr + | sym::simd_and + | sym::simd_or + | sym::simd_xor + | sym::simd_fmin + | sym::simd_fmax + | sym::simd_saturating_add + | sym::simd_saturating_sub => (1, 0, vec![param(0), param(0)], param(0)), + sym::simd_arith_offset => (2, 0, vec![param(0), param(1)], param(0)), + sym::simd_neg + | sym::simd_bswap + | sym::simd_bitreverse + | sym::simd_ctlz + | sym::simd_cttz + | sym::simd_ctpop + | sym::simd_fsqrt + | sym::simd_fsin + | sym::simd_fcos + | sym::simd_fexp + | sym::simd_fexp2 + | sym::simd_flog2 + | sym::simd_flog10 + | sym::simd_flog + | sym::simd_fabs + | sym::simd_ceil + | sym::simd_floor + | sym::simd_round + | sym::simd_trunc => (1, 0, vec![param(0)], param(0)), + sym::simd_fma | sym::simd_relaxed_fma => { + (1, 0, vec![param(0), param(0), param(0)], param(0)) + } + sym::simd_gather => (3, 0, vec![param(0), param(1), param(2)], param(0)), + sym::simd_masked_load => (3, 0, vec![param(0), param(1), param(2)], param(2)), + sym::simd_masked_store => (3, 0, vec![param(0), param(1), param(2)], tcx.types.unit), + sym::simd_scatter => (3, 0, vec![param(0), param(1), param(2)], tcx.types.unit), + sym::simd_insert | sym::simd_insert_dyn => { + (2, 0, vec![param(0), tcx.types.u32, param(1)], param(0)) + } + sym::simd_extract | sym::simd_extract_dyn => { + (2, 0, vec![param(0), tcx.types.u32], param(1)) + } + sym::simd_cast + | sym::simd_as + | sym::simd_cast_ptr + | sym::simd_expose_provenance + | sym::simd_with_exposed_provenance => (2, 0, vec![param(0)], param(1)), + sym::simd_bitmask => (2, 0, vec![param(0)], param(1)), + sym::simd_select | sym::simd_select_bitmask => { + (2, 0, vec![param(0), param(1), param(1)], param(1)) + } + sym::simd_reduce_all | sym::simd_reduce_any => (1, 0, vec![param(0)], tcx.types.bool), + sym::simd_reduce_add_ordered | sym::simd_reduce_mul_ordered => { + (2, 0, vec![param(0), param(1)], param(1)) + } + sym::simd_reduce_add_unordered + | sym::simd_reduce_mul_unordered + | sym::simd_reduce_and + | sym::simd_reduce_or + | sym::simd_reduce_xor + | sym::simd_reduce_min + | sym::simd_reduce_max => (2, 0, vec![param(0)], param(1)), + sym::simd_shuffle => (3, 0, vec![param(0), param(0), param(1)], param(2)), + sym::simd_shuffle_const_generic => (2, 1, vec![param(0), param(0)], param(1)), + + sym::atomic_cxchg | sym::atomic_cxchgweak => ( + 1, + 2, + vec![Ty::new_mut_ptr(tcx, param(0)), param(0), param(0)], + Ty::new_tup(tcx, &[param(0), tcx.types.bool]), + ), + sym::atomic_load => (1, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), + sym::atomic_store => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit), + + sym::atomic_xchg + | sym::atomic_xadd + | sym::atomic_xsub + | sym::atomic_and + | sym::atomic_nand + | sym::atomic_or + | sym::atomic_xor + | sym::atomic_max + | sym::atomic_min + | sym::atomic_umax + | sym::atomic_umin => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)), + sym::atomic_fence | sym::atomic_singlethreadfence => (0, 1, Vec::new(), tcx.types.unit), + + other => { + tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other }); + return; + } }; let sig = tcx.mk_fn_sig(inputs, output, false, safety, ExternAbi::Rust); let sig = ty::Binder::bind_with_vars(sig, bound_vars); -- cgit 1.4.1-3-g733a5 From 52824052d7782762056aec11179e08ed015c0dd3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Jun 2025 14:14:09 +0200 Subject: cci_inrinsic tets: do not use atomic intrinsic --- tests/ui/intrinsics/auxiliary/cci_intrinsic.rs | 22 +++++----------------- tests/ui/intrinsics/intrinsic-atomics-cc.rs | 12 ------------ tests/ui/intrinsics/intrinsic-inline-cc.rs | 9 +++++++++ 3 files changed, 14 insertions(+), 29 deletions(-) delete mode 100644 tests/ui/intrinsics/intrinsic-atomics-cc.rs create mode 100644 tests/ui/intrinsics/intrinsic-inline-cc.rs diff --git a/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs b/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs index ab4604b77b3..95fc673f434 100644 --- a/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs +++ b/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs @@ -1,24 +1,12 @@ #![feature(intrinsics, adt_const_params)] -pub mod rusti { - use std::marker::ConstParamTy; - - #[derive(Debug, ConstParamTy, PartialEq, Eq)] - pub enum AtomicOrdering { - // These values must match the compiler's `AtomicOrdering` defined in - // `rustc_middle/src/ty/consts/int.rs`! - Relaxed = 0, - Release = 1, - Acquire = 2, - AcqRel = 3, - SeqCst = 4, - } - +mod rusti { #[rustc_intrinsic] - pub unsafe fn atomic_xchg(dst: *mut T, src: T) -> T; + pub unsafe fn size_of_val(ptr: *const T) -> usize; } +// A monomorphic function, inlined cross-crate, referencing an intrinsic. #[inline(always)] -pub fn atomic_xchg_seqcst(dst: *mut isize, src: isize) -> isize { - unsafe { rusti::atomic_xchg::<_, { rusti::AtomicOrdering::SeqCst }>(dst, src) } +pub fn size_of_val(val: &[u8]) -> usize { + unsafe { rusti::size_of_val(val) } } diff --git a/tests/ui/intrinsics/intrinsic-atomics-cc.rs b/tests/ui/intrinsics/intrinsic-atomics-cc.rs deleted file mode 100644 index 612a21a47cf..00000000000 --- a/tests/ui/intrinsics/intrinsic-atomics-cc.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ run-pass -//@ aux-build:cci_intrinsic.rs - - -extern crate cci_intrinsic; -use cci_intrinsic::atomic_xchg_seqcst; - -pub fn main() { - let mut x = 1; - atomic_xchg_seqcst(&mut x, 5); - assert_eq!(x, 5); -} diff --git a/tests/ui/intrinsics/intrinsic-inline-cc.rs b/tests/ui/intrinsics/intrinsic-inline-cc.rs new file mode 100644 index 00000000000..f2b961a760b --- /dev/null +++ b/tests/ui/intrinsics/intrinsic-inline-cc.rs @@ -0,0 +1,9 @@ +//@ run-pass +//@ aux-build:cci_intrinsic.rs + +extern crate cci_intrinsic; + +pub fn main() { + let val = cci_intrinsic::size_of_val(&[1u8, 2, 3]); + assert_eq!(val, 3); +} -- cgit 1.4.1-3-g733a5 From f598bbd66b8e0cf5ac1adf0ff6147baa7601a731 Mon Sep 17 00:00:00 2001 From: The rustc-dev-guide Cronjob Bot Date: Mon, 9 Jun 2025 04:08:59 +0000 Subject: Preparing for merge from rustc --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 8b48bd518bd..c8721bb3600 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -c68032fd4c442d275f4daa571ba19c076106b490 +c31cccb7b5cc098b1a8c1794ed38d7fdbec0ccb0 -- cgit 1.4.1-3-g733a5